From 9135579f8cc6e590f4373aae288a7eb7c173a567 Mon Sep 17 00:00:00 2001 From: albertmena <12760268+albertmena@users.noreply.github.com> Date: Thu, 7 May 2026 12:02:58 +0200 Subject: [PATCH 01/15] alglib updated version from 8 years old (maybe v3.10) to v4.07 --- core/alglib/alglibinternal.cpp | 37780 ++++--- core/alglib/alglibinternal.h | 3263 +- core/alglib/alglibmisc.cpp | 12721 ++- core/alglib/alglibmisc.h | 2901 +- core/alglib/ap.cpp | 31179 +++-- core/alglib/ap.h | 9273 +- core/alglib/dataanalysis.cpp | 87700 ++++++++------ core/alglib/dataanalysis.h | 18087 +-- core/alglib/diffequations.cpp | 2532 +- core/alglib/diffequations.h | 557 +- core/alglib/fasttransforms.cpp | 8250 +- core/alglib/fasttransforms.h | 1709 +- core/alglib/integration.cpp | 8213 +- core/alglib/integration.h | 1714 +- core/alglib/interpolation.cpp | 105251 ++++++++++++----- core/alglib/interpolation.h | 18246 ++- core/alglib/kernels_avx2.cpp | 2175 + core/alglib/kernels_avx2.h | 201 + core/alglib/kernels_fma.cpp | 1069 + core/alglib/kernels_fma.h | 137 + core/alglib/kernels_sse2.cpp | 735 + core/alglib/kernels_sse2.h | 100 + core/alglib/linalg.cpp | 100409 +++++++++++------ core/alglib/linalg.h | 15345 ++- core/alglib/minlp.cpp | 15593 +++ core/alglib/minlp.h | 2283 + core/alglib/optimization.cpp | 169308 ++++++++++++++++++++++++---- core/alglib/optimization.h | 24504 +++- core/alglib/solvers.cpp | 29318 +++-- core/alglib/solvers.h | 6880 +- core/alglib/specialfunctions.cpp | 20309 ++-- core/alglib/specialfunctions.h | 4281 +- core/alglib/statistics.cpp | 43731 +++---- core/alglib/statistics.h | 3598 +- core/alglib/stdafx.h | 4 +- 35 files changed, 554389 insertions(+), 234967 deletions(-) create mode 100644 core/alglib/kernels_avx2.cpp create mode 100644 core/alglib/kernels_avx2.h create mode 100644 core/alglib/kernels_fma.cpp create mode 100644 core/alglib/kernels_fma.h create mode 100644 core/alglib/kernels_sse2.cpp create mode 100644 core/alglib/kernels_sse2.h create mode 100644 core/alglib/minlp.cpp create mode 100644 core/alglib/minlp.h diff --git a/core/alglib/alglibinternal.cpp b/core/alglib/alglibinternal.cpp index b3bcd5ca..82cc3c02 100644 --- a/core/alglib/alglibinternal.cpp +++ b/core/alglib/alglibinternal.cpp @@ -1,15919 +1,21861 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "alglibinternal.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - - - - -static void tsort_tagsortfastirec(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Integer */ ae_vector* bufb, - ae_int_t i1, - ae_int_t i2, - ae_state *_state); -static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Real */ ae_vector* bufb, - ae_int_t i1, - ae_int_t i2, - ae_state *_state); -static void tsort_tagsortfastrec(/* Real */ ae_vector* a, - /* Real */ ae_vector* bufa, - ae_int_t i1, - ae_int_t i2, - ae_state *_state); - - - - - - - - - - - - - - - - - - - - -static void hsschur_internalauxschur(ae_bool wantt, - ae_bool wantz, - ae_int_t n, - ae_int_t ilo, - ae_int_t ihi, - /* Real */ ae_matrix* h, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - ae_int_t iloz, - ae_int_t ihiz, - /* Real */ ae_matrix* z, - /* Real */ ae_vector* work, - /* Real */ ae_vector* workv3, - /* Real */ ae_vector* workc1, - /* Real */ ae_vector* works1, - ae_int_t* info, - ae_state *_state); -static void hsschur_aux2x2schur(double* a, - double* b, - double* c, - double* d, - double* rt1r, - double* rt1i, - double* rt2r, - double* rt2i, - double* cs, - double* sn, - ae_state *_state); -static double hsschur_extschursign(double a, double b, ae_state *_state); -static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state); - - - - -static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, - ae_complex beta, - double lnmax, - double bnorm, - double maxgrowth, - double* xnorm, - ae_complex* x, - ae_state *_state); - - -static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ ae_vector* weights, - ae_int_t wcount, - /* Real */ ae_vector* hpcbuf, - ae_state *_state); -static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ ae_vector* buf, - ae_int_t wcount, - /* Real */ ae_vector* grad, - ae_state *_state); - - -static void xblas_xsum(/* Real */ ae_vector* w, - double mx, - ae_int_t n, - double* r, - double* rerr, - ae_state *_state); -static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state); - - -static double linmin_ftol = 0.001; -static double linmin_xtol = 100*ae_machineepsilon; -static ae_int_t linmin_maxfev = 20; -static double linmin_stpmin = 1.0E-50; -static double linmin_defstpmax = 1.0E+50; -static double linmin_armijofactor = 1.3; -static void linmin_mcstep(double* stx, - double* fx, - double* dx, - double* sty, - double* fy, - double* dy, - double* stp, - double fp, - double dp, - ae_bool* brackt, - double stmin, - double stmax, - ae_int_t* info, - ae_state *_state); - - -static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state); -static ae_int_t ntheory_modmul(ae_int_t a, - ae_int_t b, - ae_int_t n, - ae_state *_state); -static ae_int_t ntheory_modexp(ae_int_t a, - ae_int_t b, - ae_int_t n, - ae_state *_state); - - -static ae_int_t ftbase_coltype = 0; -static ae_int_t ftbase_coloperandscnt = 1; -static ae_int_t ftbase_coloperandsize = 2; -static ae_int_t ftbase_colmicrovectorsize = 3; -static ae_int_t ftbase_colparam0 = 4; -static ae_int_t ftbase_colparam1 = 5; -static ae_int_t ftbase_colparam2 = 6; -static ae_int_t ftbase_colparam3 = 7; -static ae_int_t ftbase_colscnt = 8; -static ae_int_t ftbase_opend = 0; -static ae_int_t ftbase_opcomplexreffft = 1; -static ae_int_t ftbase_opbluesteinsfft = 2; -static ae_int_t ftbase_opcomplexcodeletfft = 3; -static ae_int_t ftbase_opcomplexcodelettwfft = 4; -static ae_int_t ftbase_opradersfft = 5; -static ae_int_t ftbase_opcomplextranspose = -1; -static ae_int_t ftbase_opcomplexfftfactors = -2; -static ae_int_t ftbase_opstart = -3; -static ae_int_t ftbase_opjmp = -4; -static ae_int_t ftbase_opparallelcall = -5; -static ae_int_t ftbase_maxradix = 6; -static ae_int_t ftbase_updatetw = 16; -static ae_int_t ftbase_recursivethreshold = 1024; -static ae_int_t ftbase_raderthreshold = 19; -static ae_int_t ftbase_ftbasecodeletrecommended = 5; -static double ftbase_ftbaseinefficiencyfactor = 1.3; -static ae_int_t ftbase_ftbasemaxsmoothfactor = 5; -static void ftbase_ftdeterminespacerequirements(ae_int_t n, - ae_int_t* precrsize, - ae_int_t* precisize, - ae_state *_state); -static void ftbase_ftcomplexfftplanrec(ae_int_t n, - ae_int_t k, - ae_bool childplan, - ae_bool topmostplan, - ae_int_t* rowptr, - ae_int_t* bluesteinsize, - ae_int_t* precrptr, - ae_int_t* preciptr, - fasttransformplan* plan, - ae_state *_state); -static void ftbase_ftpushentry(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_state *_state); -static void ftbase_ftpushentry2(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_int_t eparam1, - ae_state *_state); -static void ftbase_ftpushentry4(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_int_t eparam1, - ae_int_t eparam2, - ae_int_t eparam3, - ae_state *_state); -static void ftbase_ftapplysubplan(fasttransformplan* plan, - ae_int_t subplan, - /* Real */ ae_vector* a, - ae_int_t abase, - ae_int_t aoffset, - /* Real */ ae_vector* buf, - ae_int_t repcnt, - ae_state *_state); -static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - /* Real */ ae_vector* buf, - ae_state *_state); -static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - ae_state *_state); -static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - ae_state *_state); -static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* precr, - ae_int_t offs, - ae_state *_state); -static void ftbase_ftbluesteinsfft(fasttransformplan* plan, - /* Real */ ae_vector* a, - ae_int_t abase, - ae_int_t aoffset, - ae_int_t operandscnt, - ae_int_t n, - ae_int_t m, - ae_int_t precoffs, - ae_int_t subplan, - /* Real */ ae_vector* bufa, - /* Real */ ae_vector* bufb, - /* Real */ ae_vector* bufc, - /* Real */ ae_vector* bufd, - ae_state *_state); -static void ftbase_ftprecomputeradersfft(ae_int_t n, - ae_int_t rq, - ae_int_t riq, - /* Real */ ae_vector* precr, - ae_int_t offs, - ae_state *_state); -static void ftbase_ftradersfft(fasttransformplan* plan, - /* Real */ ae_vector* a, - ae_int_t abase, - ae_int_t aoffset, - ae_int_t operandscnt, - ae_int_t n, - ae_int_t subplan, - ae_int_t rq, - ae_int_t riq, - ae_int_t precoffs, - /* Real */ ae_vector* buf, - ae_state *_state); -static void ftbase_ftfactorize(ae_int_t n, - ae_bool isroot, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state); -static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state); -static void ftbase_ffttwcalc(/* Real */ ae_vector* a, - ae_int_t aoffset, - ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static void ftbase_internalcomplexlintranspose(/* Real */ ae_vector* a, - ae_int_t m, - ae_int_t n, - ae_int_t astart, - /* Real */ ae_vector* buf, - ae_state *_state); -static void ftbase_ffticltrec(/* Real */ ae_vector* a, - ae_int_t astart, - ae_int_t astride, - /* Real */ ae_vector* b, - ae_int_t bstart, - ae_int_t bstride, - ae_int_t m, - ae_int_t n, - ae_state *_state); -static void ftbase_fftirltrec(/* Real */ ae_vector* a, - ae_int_t astart, - ae_int_t astride, - /* Real */ ae_vector* b, - ae_int_t bstart, - ae_int_t bstride, - ae_int_t m, - ae_int_t n, - ae_state *_state); -static void ftbase_ftbasefindsmoothrec(ae_int_t n, - ae_int_t seed, - ae_int_t leastfactor, - ae_int_t* best, - ae_state *_state); - - - - - - - - - -/************************************************************************* -This function is used to set error flags during unit tests. When COND -parameter is True, FLAG variable is set to True. When COND is False, -FLAG is unchanged. - -The purpose of this function is to have single point where failures of -unit tests can be detected. - -This function returns value of COND. -*************************************************************************/ -ae_bool seterrorflag(ae_bool* flag, ae_bool cond, ae_state *_state) -{ - ae_bool result; - - - if( cond ) - { - *flag = ae_true; - } - result = cond; - return result; -} - - -/************************************************************************* -Internally calls SetErrorFlag() with condition: - - Abs(Val-RefVal)>Tol*Max(Abs(RefVal),S) - -This function is used to test relative error in Val against RefVal, with -relative error being replaced by absolute when scale of RefVal is less -than S. - -This function returns value of COND. -*************************************************************************/ -ae_bool seterrorflagdiff(ae_bool* flag, - double val, - double refval, - double tol, - double s, - ae_state *_state) -{ - ae_bool result; - - - result = seterrorflag(flag, ae_fp_greater(ae_fabs(val-refval, _state),tol*ae_maxreal(ae_fabs(refval, _state), s, _state)), _state); - return result; -} - - -/************************************************************************* -The function "touches" integer - it is used to avoid compiler messages -about unused variables (in rare cases when we do NOT want to remove these -variables). - - -- ALGLIB -- - Copyright 17.09.2012 by Bochkanov Sergey -*************************************************************************/ -void touchint(ae_int_t* a, ae_state *_state) -{ - - -} - - -/************************************************************************* -The function "touches" real - it is used to avoid compiler messages -about unused variables (in rare cases when we do NOT want to remove these -variables). - - -- ALGLIB -- - Copyright 17.09.2012 by Bochkanov Sergey -*************************************************************************/ -void touchreal(double* a, ae_state *_state) -{ - - -} - - -/************************************************************************* -The function convert integer value to real value. - - -- ALGLIB -- - Copyright 17.09.2012 by Bochkanov Sergey -*************************************************************************/ -double inttoreal(ae_int_t a, ae_state *_state) -{ - double result; - - - result = a; - return result; -} - - -/************************************************************************* -The function calculates binary logarithm. - -NOTE: it costs twice as much as Ln(x) - - -- ALGLIB -- - Copyright 17.09.2012 by Bochkanov Sergey -*************************************************************************/ -double log2(double x, ae_state *_state) -{ - double result; - - - result = ae_log(x, _state)/ae_log(2, _state); - return result; -} - - -/************************************************************************* -This function compares two numbers for approximate equality, with tolerance -to errors as large as max(|a|,|b|)*tol. - - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool approxequalrel(double a, double b, double tol, ae_state *_state) -{ - ae_bool result; - - - result = ae_fp_less_eq(ae_fabs(a-b, _state),ae_maxreal(ae_fabs(a, _state), ae_fabs(b, _state), _state)*tol); - return result; -} - - -/************************************************************************* -This function generates 1-dimensional general interpolation task with -moderate Lipshitz constant (close to 1.0) - -If N=1 then suborutine generates only one point at the middle of [A,B] - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void taskgenint1d(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - double h; - - ae_vector_clear(x); - ae_vector_clear(y); - - ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); - ae_vector_set_length(x, n, _state); - ae_vector_set_length(y, n, _state); - if( n>1 ) - { - x->ptr.p_double[0] = a; - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - h = (b-a)/(n-1); - for(i=1; i<=n-1; i++) - { - if( i!=n-1 ) - { - x->ptr.p_double[i] = a+(i+0.2*(2*ae_randomreal(_state)-1))*h; - } - else - { - x->ptr.p_double[i] = b; - } - y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); - } - } - else - { - x->ptr.p_double[0] = 0.5*(a+b); - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - } -} - - -/************************************************************************* -This function generates 1-dimensional equidistant interpolation task with -moderate Lipshitz constant (close to 1.0) - -If N=1 then suborutine generates only one point at the middle of [A,B] - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void taskgenint1dequidist(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - double h; - - ae_vector_clear(x); - ae_vector_clear(y); - - ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); - ae_vector_set_length(x, n, _state); - ae_vector_set_length(y, n, _state); - if( n>1 ) - { - x->ptr.p_double[0] = a; - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - h = (b-a)/(n-1); - for(i=1; i<=n-1; i++) - { - x->ptr.p_double[i] = a+i*h; - y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*h; - } - } - else - { - x->ptr.p_double[0] = 0.5*(a+b); - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - } -} - - -/************************************************************************* -This function generates 1-dimensional Chebyshev-1 interpolation task with -moderate Lipshitz constant (close to 1.0) - -If N=1 then suborutine generates only one point at the middle of [A,B] - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void taskgenint1dcheb1(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(x); - ae_vector_clear(y); - - ae_assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!", _state); - ae_vector_set_length(x, n, _state); - ae_vector_set_length(y, n, _state); - if( n>1 ) - { - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(2*i+1)/(2*n), _state); - if( i==0 ) - { - y->ptr.p_double[i] = 2*ae_randomreal(_state)-1; - } - else - { - y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); - } - } - } - else - { - x->ptr.p_double[0] = 0.5*(a+b); - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - } -} - - -/************************************************************************* -This function generates 1-dimensional Chebyshev-2 interpolation task with -moderate Lipshitz constant (close to 1.0) - -If N=1 then suborutine generates only one point at the middle of [A,B] - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void taskgenint1dcheb2(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(x); - ae_vector_clear(y); - - ae_assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!", _state); - ae_vector_set_length(x, n, _state); - ae_vector_set_length(y, n, _state); - if( n>1 ) - { - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state); - if( i==0 ) - { - y->ptr.p_double[i] = 2*ae_randomreal(_state)-1; - } - else - { - y->ptr.p_double[i] = y->ptr.p_double[i-1]+(2*ae_randomreal(_state)-1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); - } - } - } - else - { - x->ptr.p_double[0] = 0.5*(a+b); - y->ptr.p_double[0] = 2*ae_randomreal(_state)-1; - } -} - - -/************************************************************************* -This function checks that all values from X[] are distinct. It does more -than just usual floating point comparison: -* first, it calculates max(X) and min(X) -* second, it maps X[] from [min,max] to [1,2] -* only at this stage actual comparison is done - -The meaning of such check is to ensure that all values are "distinct enough" -and will not cause interpolation subroutine to fail. - -NOTE: - X[] must be sorted by ascending (subroutine ASSERT's it) - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool aredistinct(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double a; - double b; - ae_int_t i; - ae_bool nonsorted; - ae_bool result; - - - ae_assert(n>=1, "APSERVAreDistinct: internal error (N<1)", _state); - if( n==1 ) - { - - /* - * everything is alright, it is up to caller to decide whether it - * can interpolate something with just one point - */ - result = ae_true; - return result; - } - a = x->ptr.p_double[0]; - b = x->ptr.p_double[0]; - nonsorted = ae_false; - for(i=1; i<=n-1; i++) - { - a = ae_minreal(a, x->ptr.p_double[i], _state); - b = ae_maxreal(b, x->ptr.p_double[i], _state); - nonsorted = nonsorted||ae_fp_greater_eq(x->ptr.p_double[i-1],x->ptr.p_double[i]); - } - ae_assert(!nonsorted, "APSERVAreDistinct: internal error (not sorted)", _state); - for(i=1; i<=n-1; i++) - { - if( ae_fp_eq((x->ptr.p_double[i]-a)/(b-a)+1,(x->ptr.p_double[i-1]-a)/(b-a)+1) ) - { - result = ae_false; - return result; - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that two boolean values are the same (both are True -or both are False). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state) -{ - ae_bool result; - - - result = (v1&&v2)||(!v1&&!v2); - return result; -} - - -/************************************************************************* -If Length(X)cntcntcnt0&&n>0 ) - { - if( x->rowscolsrows; - n2 = x->cols; - ae_swap_matrices(x, &oldx); - ae_matrix_set_length(x, m, n, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( iptr.pp_double[i][j] = oldx.ptr.pp_double[i][j]; - } - else - { - x->ptr.pp_double[i][j] = 0.0; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Resizes X and: -* preserves old contents of X -* fills new elements by zeros - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void imatrixresize(/* Integer */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix oldx; - ae_int_t i; - ae_int_t j; - ae_int_t m2; - ae_int_t n2; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init(&oldx, 0, 0, DT_INT, _state, ae_true); - - m2 = x->rows; - n2 = x->cols; - ae_swap_matrices(x, &oldx); - ae_matrix_set_length(x, m, n, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( iptr.pp_int[i][j] = oldx.ptr.pp_int[i][j]; - } - else - { - x->ptr.pp_int[i][j] = 0; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function checks that length(X) is at least N and first N values from -X[] are finite - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool isfinitevector(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state); - if( n==0 ) - { - result = ae_true; - return result; - } - if( x->cntptr.p_double[i], _state) ) - { - result = ae_false; - return result; - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that first N values from X[] are finite - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool isfinitecvector(/* Complex */ ae_vector* z, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteCVector: internal error (N<0)", _state); - for(i=0; i<=n-1; i++) - { - if( !ae_isfinite(z->ptr.p_complex[i].x, _state)||!ae_isfinite(z->ptr.p_complex[i].y, _state) ) - { - result = ae_false; - return result; - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that size of X is at least MxN and values from -X[0..M-1,0..N-1] are finite. - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool apservisfinitematrix(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteMatrix: internal error (N<0)", _state); - ae_assert(m>=0, "APSERVIsFiniteMatrix: internal error (M<0)", _state); - if( m==0||n==0 ) - { - result = ae_true; - return result; - } - if( x->rowscolsptr.pp_double[i][j], _state) ) - { - result = ae_false; - return result; - } - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that all values from X[0..M-1,0..N-1] are finite - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteCMatrix: internal error (N<0)", _state); - ae_assert(m>=0, "APSERVIsFiniteCMatrix: internal error (M<0)", _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) - { - result = ae_false; - return result; - } - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that size of X is at least NxN and all values from -upper/lower triangle of X[0..N-1,0..N-1] are finite - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool isfinitertrmatrix(/* Real */ ae_matrix* x, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j1; - ae_int_t j2; - ae_int_t j; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteRTRMatrix: internal error (N<0)", _state); - if( n==0 ) - { - result = ae_true; - return result; - } - if( x->rowscolsptr.pp_double[i][j], _state) ) - { - result = ae_false; - return result; - } - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that all values from upper/lower triangle of -X[0..N-1,0..N-1] are finite - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j1; - ae_int_t j2; - ae_int_t j; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state); - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) - { - result = ae_false; - return result; - } - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function checks that all values from X[0..M-1,0..N-1] are finite or -NaN's. - - -- ALGLIB -- - Copyright 18.06.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool apservisfiniteornanmatrix(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_bool result; - - - ae_assert(n>=0, "APSERVIsFiniteOrNaNMatrix: internal error (N<0)", _state); - ae_assert(m>=0, "APSERVIsFiniteOrNaNMatrix: internal error (M<0)", _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( !(ae_isfinite(x->ptr.pp_double[i][j], _state)||ae_isnan(x->ptr.pp_double[i][j], _state)) ) - { - result = ae_false; - return result; - } - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -Safe sqrt(x^2+y^2) - - -- ALGLIB -- - Copyright by Bochkanov Sergey -*************************************************************************/ -double safepythag2(double x, double y, ae_state *_state) -{ - double w; - double xabs; - double yabs; - double z; - double result; - - - xabs = ae_fabs(x, _state); - yabs = ae_fabs(y, _state); - w = ae_maxreal(xabs, yabs, _state); - z = ae_minreal(xabs, yabs, _state); - if( ae_fp_eq(z,0) ) - { - result = w; - } - else - { - result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state); - } - return result; -} - - -/************************************************************************* -Safe sqrt(x^2+y^2) - - -- ALGLIB -- - Copyright by Bochkanov Sergey -*************************************************************************/ -double safepythag3(double x, double y, double z, ae_state *_state) -{ - double w; - double result; - - - w = ae_maxreal(ae_fabs(x, _state), ae_maxreal(ae_fabs(y, _state), ae_fabs(z, _state), _state), _state); - if( ae_fp_eq(w,0) ) - { - result = 0; - return result; - } - x = x/w; - y = y/w; - z = z/w; - result = w*ae_sqrt(ae_sqr(x, _state)+ae_sqr(y, _state)+ae_sqr(z, _state), _state); - return result; -} - - -/************************************************************************* -Safe division. - -This function attempts to calculate R=X/Y without overflow. - -It returns: -* +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like situation - (no overlfow is generated, R is either NAN, PosINF, NegINF) -* 0, if MinRealNumber0 - (R contains result, may be zero) -* -1, if 00 - */ - if( ae_fp_eq(y,0) ) - { - result = 1; - if( ae_fp_eq(x,0) ) - { - *r = _state->v_nan; - } - if( ae_fp_greater(x,0) ) - { - *r = _state->v_posinf; - } - if( ae_fp_less(x,0) ) - { - *r = _state->v_neginf; - } - return result; - } - if( ae_fp_eq(x,0) ) - { - *r = 0; - result = 0; - return result; - } - - /* - * make Y>0 - */ - if( ae_fp_less(y,0) ) - { - x = -x; - y = -y; - } - - /* - * - */ - if( ae_fp_greater_eq(y,1) ) - { - *r = x/y; - if( ae_fp_less_eq(ae_fabs(*r, _state),ae_minrealnumber) ) - { - result = -1; - *r = 0; - } - else - { - result = 0; - } - } - else - { - if( ae_fp_greater_eq(ae_fabs(x, _state),ae_maxrealnumber*y) ) - { - if( ae_fp_greater(x,0) ) - { - *r = _state->v_posinf; - } - else - { - *r = _state->v_neginf; - } - result = 1; - } - else - { - *r = x/y; - result = 0; - } - } - return result; -} - - -/************************************************************************* -This function calculates "safe" min(X/Y,V) for positive finite X, Y, V. -No overflow is generated in any case. - - -- ALGLIB -- - Copyright by Bochkanov Sergey -*************************************************************************/ -double safeminposrv(double x, double y, double v, ae_state *_state) -{ - double r; - double result; - - - if( ae_fp_greater_eq(y,1) ) - { - - /* - * Y>=1, we can safely divide by Y - */ - r = x/y; - result = v; - if( ae_fp_greater(v,r) ) - { - result = r; - } - else - { - result = v; - } - } - else - { - - /* - * Y<1, we can safely multiply by Y - */ - if( ae_fp_less(x,v*y) ) - { - result = x/y; - } - else - { - result = v; - } - } - return result; -} - - -/************************************************************************* -This function makes periodic mapping of X to [A,B]. - -It accepts X, A, B (A>B). It returns T which lies in [A,B] and integer K, -such that X = T + K*(B-A). - -NOTES: -* K is represented as real value, although actually it is integer -* T is guaranteed to be in [A,B] -* T replaces X - - -- ALGLIB -- - Copyright by Bochkanov Sergey -*************************************************************************/ -void apperiodicmap(double* x, - double a, - double b, - double* k, - ae_state *_state) -{ - - *k = 0; - - ae_assert(ae_fp_less(a,b), "APPeriodicMap: internal error!", _state); - *k = ae_ifloor((*x-a)/(b-a), _state); - *x = *x-*k*(b-a); - while(ae_fp_less(*x,a)) - { - *x = *x+(b-a); - *k = *k-1; - } - while(ae_fp_greater(*x,b)) - { - *x = *x-(b-a); - *k = *k+1; - } - *x = ae_maxreal(*x, a, _state); - *x = ae_minreal(*x, b, _state); -} - - -/************************************************************************* -Returns random normal number using low-quality system-provided generator - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -double randomnormal(ae_state *_state) -{ - double u; - double v; - double s; - double result; - - - for(;;) - { - u = 2*ae_randomreal(_state)-1; - v = 2*ae_randomreal(_state)-1; - s = ae_sqr(u, _state)+ae_sqr(v, _state); - if( ae_fp_greater(s,0)&&ae_fp_less(s,1) ) - { - - /* - * two Sqrt's instead of one to - * avoid overflow when S is too small - */ - s = ae_sqrt(-2*ae_log(s, _state), _state)/ae_sqrt(s, _state); - result = u*s; - return result; - } - } - return result; -} - - -/************************************************************************* -Generates random unit vector using low-quality system-provided generator. -Reallocates array if its size is too short. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) -{ - ae_int_t i; - double v; - double vv; - - - ae_assert(n>0, "RandomUnit: N<=0", _state); - if( x->cntptr.p_double[i] = vv; - v = v+vv*vv; - } - } - while(ae_fp_less_eq(v,0)); - v = 1/ae_sqrt(v, _state); - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = x->ptr.p_double[i]*v; - } -} - - -/************************************************************************* -This function is used to increment value of integer variable -*************************************************************************/ -void inc(ae_int_t* v, ae_state *_state) -{ - - - *v = *v+1; -} - - -/************************************************************************* -This function is used to decrement value of integer variable -*************************************************************************/ -void dec(ae_int_t* v, ae_state *_state) -{ - - - *v = *v-1; -} - - -/************************************************************************* -This function performs two operations: -1. decrements value of integer variable, if it is positive -2. explicitly sets variable to zero if it is non-positive -It is used by some algorithms to decrease value of internal counters. -*************************************************************************/ -void countdown(ae_int_t* v, ae_state *_state) -{ - - - if( *v>0 ) - { - *v = *v-1; - } - else - { - *v = 0; - } -} - - -/************************************************************************* -'bounds' value: maps X to [B1,B2] - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -double boundval(double x, double b1, double b2, ae_state *_state) -{ - double result; - - - if( ae_fp_less_eq(x,b1) ) - { - result = b1; - return result; - } - if( ae_fp_greater_eq(x,b2) ) - { - result = b2; - return result; - } - result = x; - return result; -} - - -/************************************************************************* -Allocation of serializer: complex value -*************************************************************************/ -void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state) -{ - - - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); -} - - -/************************************************************************* -Serialization: complex value -*************************************************************************/ -void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state) -{ - - - ae_serializer_serialize_double(s, v.x, _state); - ae_serializer_serialize_double(s, v.y, _state); -} - - -/************************************************************************* -Unserialization: complex value -*************************************************************************/ -ae_complex unserializecomplex(ae_serializer* s, ae_state *_state) -{ - ae_complex result; - - - ae_serializer_unserialize_double(s, &result.x, _state); - ae_serializer_unserialize_double(s, &result.y, _state); - return result; -} - - -/************************************************************************* -Allocation of serializer: real array -*************************************************************************/ -void allocrealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - - - if( n<0 ) - { - n = v->cnt; - } - ae_serializer_alloc_entry(s); - for(i=0; i<=n-1; i++) - { - ae_serializer_alloc_entry(s); - } -} - - -/************************************************************************* -Serialization: complex value -*************************************************************************/ -void serializerealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - - - if( n<0 ) - { - n = v->cnt; - } - ae_serializer_serialize_int(s, n, _state); - for(i=0; i<=n-1; i++) - { - ae_serializer_serialize_double(s, v->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -Unserialization: complex value -*************************************************************************/ -void unserializerealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double t; - - ae_vector_clear(v); - - ae_serializer_unserialize_int(s, &n, _state); - if( n==0 ) - { - return; - } - ae_vector_set_length(v, n, _state); - for(i=0; i<=n-1; i++) - { - ae_serializer_unserialize_double(s, &t, _state); - v->ptr.p_double[i] = t; - } -} - - -/************************************************************************* -Allocation of serializer: Integer array -*************************************************************************/ -void allocintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - - - if( n<0 ) - { - n = v->cnt; - } - ae_serializer_alloc_entry(s); - for(i=0; i<=n-1; i++) - { - ae_serializer_alloc_entry(s); - } -} - - -/************************************************************************* -Serialization: Integer array -*************************************************************************/ -void serializeintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - - - if( n<0 ) - { - n = v->cnt; - } - ae_serializer_serialize_int(s, n, _state); - for(i=0; i<=n-1; i++) - { - ae_serializer_serialize_int(s, v->ptr.p_int[i], _state); - } -} - - -/************************************************************************* -Unserialization: complex value -*************************************************************************/ -void unserializeintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t t; - - ae_vector_clear(v); - - ae_serializer_unserialize_int(s, &n, _state); - if( n==0 ) - { - return; - } - ae_vector_set_length(v, n, _state); - for(i=0; i<=n-1; i++) - { - ae_serializer_unserialize_int(s, &t, _state); - v->ptr.p_int[i] = t; - } -} - - -/************************************************************************* -Allocation of serializer: real matrix -*************************************************************************/ -void allocrealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_int_t n0, - ae_int_t n1, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - if( n0<0 ) - { - n0 = v->rows; - } - if( n1<0 ) - { - n1 = v->cols; - } - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - for(i=0; i<=n0-1; i++) - { - for(j=0; j<=n1-1; j++) - { - ae_serializer_alloc_entry(s); - } - } -} - - -/************************************************************************* -Serialization: complex value -*************************************************************************/ -void serializerealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_int_t n0, - ae_int_t n1, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - if( n0<0 ) - { - n0 = v->rows; - } - if( n1<0 ) - { - n1 = v->cols; - } - ae_serializer_serialize_int(s, n0, _state); - ae_serializer_serialize_int(s, n1, _state); - for(i=0; i<=n0-1; i++) - { - for(j=0; j<=n1-1; j++) - { - ae_serializer_serialize_double(s, v->ptr.pp_double[i][j], _state); - } - } -} - - -/************************************************************************* -Unserialization: complex value -*************************************************************************/ -void unserializerealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n0; - ae_int_t n1; - double t; - - ae_matrix_clear(v); - - ae_serializer_unserialize_int(s, &n0, _state); - ae_serializer_unserialize_int(s, &n1, _state); - if( n0==0||n1==0 ) - { - return; - } - ae_matrix_set_length(v, n0, n1, _state); - for(i=0; i<=n0-1; i++) - { - for(j=0; j<=n1-1; j++) - { - ae_serializer_unserialize_double(s, &t, _state); - v->ptr.pp_double[i][j] = t; - } - } -} - - -/************************************************************************* -Copy integer array -*************************************************************************/ -void copyintegerarray(/* Integer */ ae_vector* src, - /* Integer */ ae_vector* dst, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(dst); - - if( src->cnt>0 ) - { - ae_vector_set_length(dst, src->cnt, _state); - for(i=0; i<=src->cnt-1; i++) - { - dst->ptr.p_int[i] = src->ptr.p_int[i]; - } - } -} - - -/************************************************************************* -Copy real array -*************************************************************************/ -void copyrealarray(/* Real */ ae_vector* src, - /* Real */ ae_vector* dst, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(dst); - - if( src->cnt>0 ) - { - ae_vector_set_length(dst, src->cnt, _state); - for(i=0; i<=src->cnt-1; i++) - { - dst->ptr.p_double[i] = src->ptr.p_double[i]; - } - } -} - - -/************************************************************************* -Copy real matrix -*************************************************************************/ -void copyrealmatrix(/* Real */ ae_matrix* src, - /* Real */ ae_matrix* dst, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(dst); - - if( src->rows>0&&src->cols>0 ) - { - ae_matrix_set_length(dst, src->rows, src->cols, _state); - for(i=0; i<=src->rows-1; i++) - { - for(j=0; j<=src->cols-1; j++) - { - dst->ptr.pp_double[i][j] = src->ptr.pp_double[i][j]; - } - } - } -} - - -/************************************************************************* -This function searches integer array. Elements in this array are actually -records, each NRec elements wide. Each record has unique header - NHeader -integer values, which identify it. Records are lexicographically sorted by -header. - -Records are identified by their index, not offset (offset = NRec*index). - -This function searches A (records with indices [I0,I1)) for a record with -header B. It returns index of this record (not offset!), or -1 on failure. - - -- ALGLIB -- - Copyright 28.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t recsearch(/* Integer */ ae_vector* a, - ae_int_t nrec, - ae_int_t nheader, - ae_int_t i0, - ae_int_t i1, - /* Integer */ ae_vector* b, - ae_state *_state) -{ - ae_int_t mididx; - ae_int_t cflag; - ae_int_t k; - ae_int_t offs; - ae_int_t result; - - - result = -1; - for(;;) - { - if( i0>=i1 ) - { - break; - } - mididx = (i0+i1)/2; - offs = nrec*mididx; - cflag = 0; - for(k=0; k<=nheader-1; k++) - { - if( a->ptr.p_int[offs+k]ptr.p_int[k] ) - { - cflag = -1; - break; - } - if( a->ptr.p_int[offs+k]>b->ptr.p_int[k] ) - { - cflag = 1; - break; - } - } - if( cflag==0 ) - { - result = mididx; - return result; - } - if( cflag<0 ) - { - i0 = mididx+1; - } - else - { - i1 = mididx; - } - } - return result; -} - - -/************************************************************************* -This function is used in parallel functions for recurrent division of large -task into two smaller tasks. - -It has following properties: -* it works only for TaskSize>=2 (assertion is thrown otherwise) -* for TaskSize=2, it returns Task0=1, Task1=1 -* in case TaskSize is odd, Task0=TaskSize-1, Task1=1 -* in case TaskSize is even, Task0 and Task1 are approximately TaskSize/2 - and both Task0 and Task1 are even, Task0>=Task1 - - -- ALGLIB -- - Copyright 07.04.2013 by Bochkanov Sergey -*************************************************************************/ -void splitlengtheven(ae_int_t tasksize, - ae_int_t* task0, - ae_int_t* task1, - ae_state *_state) -{ - - *task0 = 0; - *task1 = 0; - - ae_assert(tasksize>=2, "SplitLengthEven: TaskSize<2", _state); - if( tasksize==2 ) - { - *task0 = 1; - *task1 = 1; - return; - } - if( tasksize%2==0 ) - { - - /* - * Even division - */ - *task0 = tasksize/2; - *task1 = tasksize/2; - if( *task0%2!=0 ) - { - *task0 = *task0+1; - *task1 = *task1-1; - } - } - else - { - - /* - * Odd task size, split trailing odd part from it. - */ - *task0 = tasksize-1; - *task1 = 1; - } - ae_assert(*task0>=1, "SplitLengthEven: internal error", _state); - ae_assert(*task1>=1, "SplitLengthEven: internal error", _state); -} - - -/************************************************************************* -This function is used in parallel functions for recurrent division of large -task into two smaller tasks. - -It has following properties: -* it works only for TaskSize>=2 and ChunkSize>=2 - (assertion is thrown otherwise) -* Task0+Task1=TaskSize, Task0>0, Task1>0 -* Task0 and Task1 are close to each other -* in case TaskSize>ChunkSize, Task0 is always divisible by ChunkSize - - -- ALGLIB -- - Copyright 07.04.2013 by Bochkanov Sergey -*************************************************************************/ -void splitlength(ae_int_t tasksize, - ae_int_t chunksize, - ae_int_t* task0, - ae_int_t* task1, - ae_state *_state) -{ - - *task0 = 0; - *task1 = 0; - - ae_assert(chunksize>=2, "SplitLength: ChunkSize<2", _state); - ae_assert(tasksize>=2, "SplitLength: TaskSize<2", _state); - *task0 = tasksize/2; - if( *task0>chunksize&&*task0%chunksize!=0 ) - { - *task0 = *task0-*task0%chunksize; - } - *task1 = tasksize-(*task0); - ae_assert(*task0>=1, "SplitLength: internal error", _state); - ae_assert(*task1>=1, "SplitLength: internal error", _state); -} - - -ae_bool _apbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - apbuffers *p = (apbuffers*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->ia0, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ia1, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ia2, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ia3, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ra0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ra1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ra2, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ra3, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _apbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - apbuffers *dst = (apbuffers*)_dst; - apbuffers *src = (apbuffers*)_src; - if( !ae_vector_init_copy(&dst->ia0, &src->ia0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ia1, &src->ia1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ia2, &src->ia2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ia3, &src->ia3, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ra0, &src->ra0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ra1, &src->ra1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ra2, &src->ra2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ra3, &src->ra3, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _apbuffers_clear(void* _p) -{ - apbuffers *p = (apbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->ia0); - ae_vector_clear(&p->ia1); - ae_vector_clear(&p->ia2); - ae_vector_clear(&p->ia3); - ae_vector_clear(&p->ra0); - ae_vector_clear(&p->ra1); - ae_vector_clear(&p->ra2); - ae_vector_clear(&p->ra3); -} - - -void _apbuffers_destroy(void* _p) -{ - apbuffers *p = (apbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->ia0); - ae_vector_destroy(&p->ia1); - ae_vector_destroy(&p->ia2); - ae_vector_destroy(&p->ia3); - ae_vector_destroy(&p->ra0); - ae_vector_destroy(&p->ra1); - ae_vector_destroy(&p->ra2); - ae_vector_destroy(&p->ra3); -} - - -ae_bool _sboolean_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sboolean *p = (sboolean*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _sboolean_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sboolean *dst = (sboolean*)_dst; - sboolean *src = (sboolean*)_src; - dst->val = src->val; - return ae_true; -} - - -void _sboolean_clear(void* _p) -{ - sboolean *p = (sboolean*)_p; - ae_touch_ptr((void*)p); -} - - -void _sboolean_destroy(void* _p) -{ - sboolean *p = (sboolean*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _sbooleanarray_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sbooleanarray *p = (sbooleanarray*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->val, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _sbooleanarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sbooleanarray *dst = (sbooleanarray*)_dst; - sbooleanarray *src = (sbooleanarray*)_src; - if( !ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _sbooleanarray_clear(void* _p) -{ - sbooleanarray *p = (sbooleanarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->val); -} - - -void _sbooleanarray_destroy(void* _p) -{ - sbooleanarray *p = (sbooleanarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->val); -} - - -ae_bool _sinteger_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sinteger *p = (sinteger*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _sinteger_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sinteger *dst = (sinteger*)_dst; - sinteger *src = (sinteger*)_src; - dst->val = src->val; - return ae_true; -} - - -void _sinteger_clear(void* _p) -{ - sinteger *p = (sinteger*)_p; - ae_touch_ptr((void*)p); -} - - -void _sinteger_destroy(void* _p) -{ - sinteger *p = (sinteger*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _sintegerarray_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sintegerarray *p = (sintegerarray*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->val, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _sintegerarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sintegerarray *dst = (sintegerarray*)_dst; - sintegerarray *src = (sintegerarray*)_src; - if( !ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _sintegerarray_clear(void* _p) -{ - sintegerarray *p = (sintegerarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->val); -} - - -void _sintegerarray_destroy(void* _p) -{ - sintegerarray *p = (sintegerarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->val); -} - - -ae_bool _sreal_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sreal *p = (sreal*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _sreal_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sreal *dst = (sreal*)_dst; - sreal *src = (sreal*)_src; - dst->val = src->val; - return ae_true; -} - - -void _sreal_clear(void* _p) -{ - sreal *p = (sreal*)_p; - ae_touch_ptr((void*)p); -} - - -void _sreal_destroy(void* _p) -{ - sreal *p = (sreal*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _srealarray_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - srealarray *p = (srealarray*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->val, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _srealarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - srealarray *dst = (srealarray*)_dst; - srealarray *src = (srealarray*)_src; - if( !ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _srealarray_clear(void* _p) -{ - srealarray *p = (srealarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->val); -} - - -void _srealarray_destroy(void* _p) -{ - srealarray *p = (srealarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->val); -} - - -ae_bool _scomplex_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - scomplex *p = (scomplex*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _scomplex_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - scomplex *dst = (scomplex*)_dst; - scomplex *src = (scomplex*)_src; - dst->val = src->val; - return ae_true; -} - - -void _scomplex_clear(void* _p) -{ - scomplex *p = (scomplex*)_p; - ae_touch_ptr((void*)p); -} - - -void _scomplex_destroy(void* _p) -{ - scomplex *p = (scomplex*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _scomplexarray_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - scomplexarray *p = (scomplexarray*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->val, 0, DT_COMPLEX, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _scomplexarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - scomplexarray *dst = (scomplexarray*)_dst; - scomplexarray *src = (scomplexarray*)_src; - if( !ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _scomplexarray_clear(void* _p) -{ - scomplexarray *p = (scomplexarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->val); -} - - -void _scomplexarray_destroy(void* _p) -{ - scomplexarray *p = (scomplexarray*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->val); -} - - - - -ae_int_t getrdfserializationcode(ae_state *_state) -{ - ae_int_t result; - - - result = 1; - return result; -} - - -ae_int_t getkdtreeserializationcode(ae_state *_state) -{ - ae_int_t result; - - - result = 2; - return result; -} - - -ae_int_t getmlpserializationcode(ae_state *_state) -{ - ae_int_t result; - - - result = 3; - return result; -} - - -ae_int_t getmlpeserializationcode(ae_state *_state) -{ - ae_int_t result; - - - result = 4; - return result; -} - - -ae_int_t getrbfserializationcode(ae_state *_state) -{ - ae_int_t result; - - - result = 5; - return result; -} - - - - -/************************************************************************* -This function sorts array of real keys by ascending. - -Its results are: -* sorted array A -* permutation tables P1, P2 - -Algorithm outputs permutation tables using two formats: -* as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i] contains - value which was moved there from J-th position. -* as a sequence of pairwise permutations. Sorted A[] may be obtained by - swaping A[i] and A[P2[i]] for all i from 0 to N-1. - -INPUT PARAMETERS: - A - unsorted array - N - array size - -OUPUT PARAMETERS: - A - sorted array - P1, P2 - permutation tables, array[N] - -NOTES: - this function assumes that A[] is finite; it doesn't checks that - condition. All other conditions (size of input arrays, etc.) are not - checked too. - - -- ALGLIB -- - Copyright 14.05.2008 by Bochkanov Sergey -*************************************************************************/ -void tagsort(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - ae_state *_state) -{ - ae_frame _frame_block; - apbuffers buf; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(p1); - ae_vector_clear(p2); - _apbuffers_init(&buf, _state, ae_true); - - tagsortbuf(a, n, p1, p2, &buf, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Buffered variant of TagSort, which accepts preallocated output arrays as -well as special structure for buffered allocations. If arrays are too -short, they are reallocated. If they are large enough, no memory -allocation is done. - -It is intended to be used in the performance-critical parts of code, where -additional allocations can lead to severe performance degradation - - -- ALGLIB -- - Copyright 14.05.2008 by Bochkanov Sergey -*************************************************************************/ -void tagsortbuf(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - apbuffers* buf, - ae_state *_state) -{ - ae_int_t i; - ae_int_t lv; - ae_int_t lp; - ae_int_t rv; - ae_int_t rp; - - - - /* - * Special cases - */ - if( n<=0 ) - { - return; - } - if( n==1 ) - { - ivectorsetlengthatleast(p1, 1, _state); - ivectorsetlengthatleast(p2, 1, _state); - p1->ptr.p_int[0] = 0; - p2->ptr.p_int[0] = 0; - return; - } - - /* - * General case, N>1: prepare permutations table P1 - */ - ivectorsetlengthatleast(p1, n, _state); - for(i=0; i<=n-1; i++) - { - p1->ptr.p_int[i] = i; - } - - /* - * General case, N>1: sort, update P1 - */ - rvectorsetlengthatleast(&buf->ra0, n, _state); - ivectorsetlengthatleast(&buf->ia0, n, _state); - tagsortfasti(a, p1, &buf->ra0, &buf->ia0, n, _state); - - /* - * General case, N>1: fill permutations table P2 - * - * To fill P2 we maintain two arrays: - * * PV (Buf.IA0), Position(Value). PV[i] contains position of I-th key at the moment - * * VP (Buf.IA1), Value(Position). VP[i] contains key which has position I at the moment - * - * At each step we making permutation of two items: - * Left, which is given by position/value pair LP/LV - * and Right, which is given by RP/RV - * and updating PV[] and VP[] correspondingly. - */ - ivectorsetlengthatleast(&buf->ia0, n, _state); - ivectorsetlengthatleast(&buf->ia1, n, _state); - ivectorsetlengthatleast(p2, n, _state); - for(i=0; i<=n-1; i++) - { - buf->ia0.ptr.p_int[i] = i; - buf->ia1.ptr.p_int[i] = i; - } - for(i=0; i<=n-1; i++) - { - - /* - * calculate LP, LV, RP, RV - */ - lp = i; - lv = buf->ia1.ptr.p_int[lp]; - rv = p1->ptr.p_int[i]; - rp = buf->ia0.ptr.p_int[rv]; - - /* - * Fill P2 - */ - p2->ptr.p_int[i] = rp; - - /* - * update PV and VP - */ - buf->ia1.ptr.p_int[lp] = rv; - buf->ia1.ptr.p_int[rp] = lv; - buf->ia0.ptr.p_int[lv] = rp; - buf->ia0.ptr.p_int[rv] = lp; - } -} - - -/************************************************************************* -Same as TagSort, but optimized for real keys and integer labels. - -A is sorted, and same permutations are applied to B. - -NOTES: -1. this function assumes that A[] is finite; it doesn't checks that - condition. All other conditions (size of input arrays, etc.) are not - checked too. -2. this function uses two buffers, BufA and BufB, each is N elements large. - They may be preallocated (which will save some time) or not, in which - case function will automatically allocate memory. - - -- ALGLIB -- - Copyright 11.12.2008 by Bochkanov Sergey -*************************************************************************/ -void tagsortfasti(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Integer */ ae_vector* bufb, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_bool isascending; - ae_bool isdescending; - double tmpr; - ae_int_t tmpi; - - - - /* - * Special case - */ - if( n<=1 ) - { - return; - } - - /* - * Test for already sorted set - */ - isascending = ae_true; - isdescending = ae_true; - for(i=1; i<=n-1; i++) - { - isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1]; - isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; - } - if( isascending ) - { - return; - } - if( isdescending ) - { - for(i=0; i<=n-1; i++) - { - j = n-1-i; - if( j<=i ) - { - break; - } - tmpr = a->ptr.p_double[i]; - a->ptr.p_double[i] = a->ptr.p_double[j]; - a->ptr.p_double[j] = tmpr; - tmpi = b->ptr.p_int[i]; - b->ptr.p_int[i] = b->ptr.p_int[j]; - b->ptr.p_int[j] = tmpi; - } - return; - } - - /* - * General case - */ - if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; - isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; - } - if( isascending ) - { - return; - } - if( isdescending ) - { - for(i=0; i<=n-1; i++) - { - j = n-1-i; - if( j<=i ) - { - break; - } - tmpr = a->ptr.p_double[i]; - a->ptr.p_double[i] = a->ptr.p_double[j]; - a->ptr.p_double[j] = tmpr; - tmpr = b->ptr.p_double[i]; - b->ptr.p_double[i] = b->ptr.p_double[j]; - b->ptr.p_double[j] = tmpr; - } - return; - } - - /* - * General case - */ - if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; - isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; - } - if( isascending ) - { - return; - } - if( isdescending ) - { - for(i=0; i<=n-1; i++) - { - j = n-1-i; - if( j<=i ) - { - break; - } - tmpr = a->ptr.p_double[i]; - a->ptr.p_double[i] = a->ptr.p_double[j]; - a->ptr.p_double[j] = tmpr; - } - return; - } - - /* - * General case - */ - if( bufa->cnt1: sort, update B - */ - i = 2; - do - { - t = i; - while(t!=1) - { - k = t/2; - if( a->ptr.p_int[offset+k-1]>=a->ptr.p_int[offset+t-1] ) - { - t = 1; - } - else - { - tmp = a->ptr.p_int[offset+k-1]; - a->ptr.p_int[offset+k-1] = a->ptr.p_int[offset+t-1]; - a->ptr.p_int[offset+t-1] = tmp; - tmpr = b->ptr.p_double[offset+k-1]; - b->ptr.p_double[offset+k-1] = b->ptr.p_double[offset+t-1]; - b->ptr.p_double[offset+t-1] = tmpr; - t = k; - } - } - i = i+1; - } - while(i<=n); - i = n-1; - do - { - tmp = a->ptr.p_int[offset+i]; - a->ptr.p_int[offset+i] = a->ptr.p_int[offset+0]; - a->ptr.p_int[offset+0] = tmp; - tmpr = b->ptr.p_double[offset+i]; - b->ptr.p_double[offset+i] = b->ptr.p_double[offset+0]; - b->ptr.p_double[offset+0] = tmpr; - t = 1; - while(t!=0) - { - k = 2*t; - if( k>i ) - { - t = 0; - } - else - { - if( kptr.p_int[offset+k]>a->ptr.p_int[offset+k-1] ) - { - k = k+1; - } - } - if( a->ptr.p_int[offset+t-1]>=a->ptr.p_int[offset+k-1] ) - { - t = 0; - } - else - { - tmp = a->ptr.p_int[offset+k-1]; - a->ptr.p_int[offset+k-1] = a->ptr.p_int[offset+t-1]; - a->ptr.p_int[offset+t-1] = tmp; - tmpr = b->ptr.p_double[offset+k-1]; - b->ptr.p_double[offset+k-1] = b->ptr.p_double[offset+t-1]; - b->ptr.p_double[offset+t-1] = tmpr; - t = k; - } - } - } - i = i-1; - } - while(i>=1); -} - - -/************************************************************************* -Heap operations: adds element to the heap - -PARAMETERS: - A - heap itself, must be at least array[0..N] - B - array of integer tags, which are updated according to - permutations in the heap - N - size of the heap (without new element). - updated on output - VA - value of the element being added - VB - value of the tag - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void tagheappushi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t* n, - double va, - ae_int_t vb, - ae_state *_state) -{ - ae_int_t j; - ae_int_t k; - double v; - - - if( *n<0 ) - { - return; - } - - /* - * N=0 is a special case - */ - if( *n==0 ) - { - a->ptr.p_double[0] = va; - b->ptr.p_int[0] = vb; - *n = *n+1; - return; - } - - /* - * add current point to the heap - * (add to the bottom, then move up) - * - * we don't write point to the heap - * until its final position is determined - * (it allow us to reduce number of array access operations) - */ - j = *n; - *n = *n+1; - while(j>0) - { - k = (j-1)/2; - v = a->ptr.p_double[k]; - if( ae_fp_less(v,va) ) - { - - /* - * swap with higher element - */ - a->ptr.p_double[j] = v; - b->ptr.p_int[j] = b->ptr.p_int[k]; - j = k; - } - else - { - - /* - * element in its place. terminate. - */ - break; - } - } - a->ptr.p_double[j] = va; - b->ptr.p_int[j] = vb; -} - - -/************************************************************************* -Heap operations: replaces top element with new element -(which is moved down) - -PARAMETERS: - A - heap itself, must be at least array[0..N-1] - B - array of integer tags, which are updated according to - permutations in the heap - N - size of the heap - VA - value of the element which replaces top element - VB - value of the tag - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void tagheapreplacetopi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t n, - double va, - ae_int_t vb, - ae_state *_state) -{ - ae_int_t j; - ae_int_t k1; - ae_int_t k2; - double v; - double v1; - double v2; - - - if( n<1 ) - { - return; - } - - /* - * N=1 is a special case - */ - if( n==1 ) - { - a->ptr.p_double[0] = va; - b->ptr.p_int[0] = vb; - return; - } - - /* - * move down through heap: - * * J - current element - * * K1 - first child (always exists) - * * K2 - second child (may not exists) - * - * we don't write point to the heap - * until its final position is determined - * (it allow us to reduce number of array access operations) - */ - j = 0; - k1 = 1; - k2 = 2; - while(k1=n ) - { - - /* - * only one child. - * - * swap and terminate (because this child - * have no siblings due to heap structure) - */ - v = a->ptr.p_double[k1]; - if( ae_fp_greater(v,va) ) - { - a->ptr.p_double[j] = v; - b->ptr.p_int[j] = b->ptr.p_int[k1]; - j = k1; - } - break; - } - else - { - - /* - * two childs - */ - v1 = a->ptr.p_double[k1]; - v2 = a->ptr.p_double[k2]; - if( ae_fp_greater(v1,v2) ) - { - if( ae_fp_less(va,v1) ) - { - a->ptr.p_double[j] = v1; - b->ptr.p_int[j] = b->ptr.p_int[k1]; - j = k1; - } - else - { - break; - } - } - else - { - if( ae_fp_less(va,v2) ) - { - a->ptr.p_double[j] = v2; - b->ptr.p_int[j] = b->ptr.p_int[k2]; - j = k2; - } - else - { - break; - } - } - k1 = 2*j+1; - k2 = 2*j+2; - } - } - a->ptr.p_double[j] = va; - b->ptr.p_int[j] = vb; -} - - -/************************************************************************* -Heap operations: pops top element from the heap - -PARAMETERS: - A - heap itself, must be at least array[0..N-1] - B - array of integer tags, which are updated according to - permutations in the heap - N - size of the heap, N>=1 - -On output top element is moved to A[N-1], B[N-1], heap is reordered, N is -decreased by 1. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void tagheappopi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t* n, - ae_state *_state) -{ - double va; - ae_int_t vb; - - - if( *n<1 ) - { - return; - } - - /* - * N=1 is a special case - */ - if( *n==1 ) - { - *n = 0; - return; - } - - /* - * swap top element and last element, - * then reorder heap - */ - va = a->ptr.p_double[*n-1]; - vb = b->ptr.p_int[*n-1]; - a->ptr.p_double[*n-1] = a->ptr.p_double[0]; - b->ptr.p_int[*n-1] = b->ptr.p_int[0]; - *n = *n-1; - tagheapreplacetopi(a, b, *n, va, vb, _state); -} - - -/************************************************************************* -Search first element less than T in sorted array. - -PARAMETERS: - A - sorted array by ascending from 0 to N-1 - N - number of elements in array - T - the desired element - -RESULT: - The very first element's index, which isn't less than T. -In the case when there aren't such elements, returns N. -*************************************************************************/ -ae_int_t lowerbound(/* Real */ ae_vector* a, - ae_int_t n, - double t, - ae_state *_state) -{ - ae_int_t l; - ae_int_t half; - ae_int_t first; - ae_int_t middle; - ae_int_t result; - - - l = n; - first = 0; - while(l>0) - { - half = l/2; - middle = first+half; - if( ae_fp_less(a->ptr.p_double[middle],t) ) - { - first = middle+1; - l = l-half-1; - } - else - { - l = half; - } - } - result = first; - return result; -} - - -/************************************************************************* -Search first element more than T in sorted array. - -PARAMETERS: - A - sorted array by ascending from 0 to N-1 - N - number of elements in array - T - the desired element - - RESULT: - The very first element's index, which more than T. -In the case when there aren't such elements, returns N. -*************************************************************************/ -ae_int_t upperbound(/* Real */ ae_vector* a, - ae_int_t n, - double t, - ae_state *_state) -{ - ae_int_t l; - ae_int_t half; - ae_int_t first; - ae_int_t middle; - ae_int_t result; - - - l = n; - first = 0; - while(l>0) - { - half = l/2; - middle = first+half; - if( ae_fp_less(t,a->ptr.p_double[middle]) ) - { - l = half; - } - else - { - first = middle+1; - l = l-half-1; - } - } - result = first; - return result; -} - - -/************************************************************************* -Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), -applies same permutations to B. - - -- ALGLIB -- - Copyright 06.09.2010 by Bochkanov Sergey -*************************************************************************/ -static void tsort_tagsortfastirec(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Integer */ ae_vector* bufb, - ae_int_t i1, - ae_int_t i2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t cntless; - ae_int_t cnteq; - ae_int_t cntgreater; - double tmpr; - ae_int_t tmpi; - double v0; - double v1; - double v2; - double vp; - - - - /* - * Fast exit - */ - if( i2<=i1 ) - { - return; - } - - /* - * Non-recursive sort for small arrays - */ - if( i2-i1<=16 ) - { - for(j=i1+1; j<=i2; j++) - { - - /* - * Search elements [I1..J-1] for place to insert Jth element. - * - * This code stops immediately if we can leave A[J] at J-th position - * (all elements have same value of A[J] larger than any of them) - */ - tmpr = a->ptr.p_double[j]; - tmpi = j; - for(k=j-1; k>=i1; k--) - { - if( a->ptr.p_double[k]<=tmpr ) - { - break; - } - tmpi = k; - } - k = tmpi; - - /* - * Insert Jth element into Kth position - */ - if( k!=j ) - { - tmpr = a->ptr.p_double[j]; - tmpi = b->ptr.p_int[j]; - for(i=j-1; i>=k; i--) - { - a->ptr.p_double[i+1] = a->ptr.p_double[i]; - b->ptr.p_int[i+1] = b->ptr.p_int[i]; - } - a->ptr.p_double[k] = tmpr; - b->ptr.p_int[k] = tmpi; - } - } - return; - } - - /* - * Quicksort: choose pivot - * Here we assume that I2-I1>=2 - */ - v0 = a->ptr.p_double[i1]; - v1 = a->ptr.p_double[i1+(i2-i1)/2]; - v2 = a->ptr.p_double[i2]; - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - if( v1>v2 ) - { - tmpr = v2; - v2 = v1; - v1 = tmpr; - } - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - vp = v1; - - /* - * now pass through A/B and: - * * move elements that are LESS than VP to the left of A/B - * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) - * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order - * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) - * * move elements from the left of BufA/BufB to the end of A/B - */ - cntless = 0; - cnteq = 0; - cntgreater = 0; - for(i=i1; i<=i2; i++) - { - v0 = a->ptr.p_double[i]; - if( v0ptr.p_double[k] = v0; - b->ptr.p_int[k] = b->ptr.p_int[i]; - } - cntless = cntless+1; - continue; - } - if( v0==vp ) - { - - /* - * EQUAL - */ - k = i2-cnteq; - bufa->ptr.p_double[k] = v0; - bufb->ptr.p_int[k] = b->ptr.p_int[i]; - cnteq = cnteq+1; - continue; - } - - /* - * GREATER - */ - k = i1+cntgreater; - bufa->ptr.p_double[k] = v0; - bufb->ptr.p_int[k] = b->ptr.p_int[i]; - cntgreater = cntgreater+1; - } - for(i=0; i<=cnteq-1; i++) - { - j = i1+cntless+cnteq-1-i; - k = i2+i-(cnteq-1); - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - b->ptr.p_int[j] = bufb->ptr.p_int[k]; - } - for(i=0; i<=cntgreater-1; i++) - { - j = i1+cntless+cnteq+i; - k = i1+i; - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - b->ptr.p_int[j] = bufb->ptr.p_int[k]; - } - - /* - * Sort left and right parts of the array (ignoring middle part) - */ - tsort_tagsortfastirec(a, b, bufa, bufb, i1, i1+cntless-1, _state); - tsort_tagsortfastirec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); -} - - -/************************************************************************* -Internal TagSortFastR: sorts A[I1...I2] (both bounds are included), -applies same permutations to B. - - -- ALGLIB -- - Copyright 06.09.2010 by Bochkanov Sergey -*************************************************************************/ -static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Real */ ae_vector* bufb, - ae_int_t i1, - ae_int_t i2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - double tmpr; - double tmpr2; - ae_int_t tmpi; - ae_int_t cntless; - ae_int_t cnteq; - ae_int_t cntgreater; - double v0; - double v1; - double v2; - double vp; - - - - /* - * Fast exit - */ - if( i2<=i1 ) - { - return; - } - - /* - * Non-recursive sort for small arrays - */ - if( i2-i1<=16 ) - { - for(j=i1+1; j<=i2; j++) - { - - /* - * Search elements [I1..J-1] for place to insert Jth element. - * - * This code stops immediately if we can leave A[J] at J-th position - * (all elements have same value of A[J] larger than any of them) - */ - tmpr = a->ptr.p_double[j]; - tmpi = j; - for(k=j-1; k>=i1; k--) - { - if( a->ptr.p_double[k]<=tmpr ) - { - break; - } - tmpi = k; - } - k = tmpi; - - /* - * Insert Jth element into Kth position - */ - if( k!=j ) - { - tmpr = a->ptr.p_double[j]; - tmpr2 = b->ptr.p_double[j]; - for(i=j-1; i>=k; i--) - { - a->ptr.p_double[i+1] = a->ptr.p_double[i]; - b->ptr.p_double[i+1] = b->ptr.p_double[i]; - } - a->ptr.p_double[k] = tmpr; - b->ptr.p_double[k] = tmpr2; - } - } - return; - } - - /* - * Quicksort: choose pivot - * Here we assume that I2-I1>=16 - */ - v0 = a->ptr.p_double[i1]; - v1 = a->ptr.p_double[i1+(i2-i1)/2]; - v2 = a->ptr.p_double[i2]; - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - if( v1>v2 ) - { - tmpr = v2; - v2 = v1; - v1 = tmpr; - } - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - vp = v1; - - /* - * now pass through A/B and: - * * move elements that are LESS than VP to the left of A/B - * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) - * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order - * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) - * * move elements from the left of BufA/BufB to the end of A/B - */ - cntless = 0; - cnteq = 0; - cntgreater = 0; - for(i=i1; i<=i2; i++) - { - v0 = a->ptr.p_double[i]; - if( v0ptr.p_double[k] = v0; - b->ptr.p_double[k] = b->ptr.p_double[i]; - } - cntless = cntless+1; - continue; - } - if( v0==vp ) - { - - /* - * EQUAL - */ - k = i2-cnteq; - bufa->ptr.p_double[k] = v0; - bufb->ptr.p_double[k] = b->ptr.p_double[i]; - cnteq = cnteq+1; - continue; - } - - /* - * GREATER - */ - k = i1+cntgreater; - bufa->ptr.p_double[k] = v0; - bufb->ptr.p_double[k] = b->ptr.p_double[i]; - cntgreater = cntgreater+1; - } - for(i=0; i<=cnteq-1; i++) - { - j = i1+cntless+cnteq-1-i; - k = i2+i-(cnteq-1); - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - b->ptr.p_double[j] = bufb->ptr.p_double[k]; - } - for(i=0; i<=cntgreater-1; i++) - { - j = i1+cntless+cnteq+i; - k = i1+i; - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - b->ptr.p_double[j] = bufb->ptr.p_double[k]; - } - - /* - * Sort left and right parts of the array (ignoring middle part) - */ - tsort_tagsortfastrrec(a, b, bufa, bufb, i1, i1+cntless-1, _state); - tsort_tagsortfastrrec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); -} - - -/************************************************************************* -Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), -applies same permutations to B. - - -- ALGLIB -- - Copyright 06.09.2010 by Bochkanov Sergey -*************************************************************************/ -static void tsort_tagsortfastrec(/* Real */ ae_vector* a, - /* Real */ ae_vector* bufa, - ae_int_t i1, - ae_int_t i2, - ae_state *_state) -{ - ae_int_t cntless; - ae_int_t cnteq; - ae_int_t cntgreater; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double tmpr; - ae_int_t tmpi; - double v0; - double v1; - double v2; - double vp; - - - - /* - * Fast exit - */ - if( i2<=i1 ) - { - return; - } - - /* - * Non-recursive sort for small arrays - */ - if( i2-i1<=16 ) - { - for(j=i1+1; j<=i2; j++) - { - - /* - * Search elements [I1..J-1] for place to insert Jth element. - * - * This code stops immediately if we can leave A[J] at J-th position - * (all elements have same value of A[J] larger than any of them) - */ - tmpr = a->ptr.p_double[j]; - tmpi = j; - for(k=j-1; k>=i1; k--) - { - if( a->ptr.p_double[k]<=tmpr ) - { - break; - } - tmpi = k; - } - k = tmpi; - - /* - * Insert Jth element into Kth position - */ - if( k!=j ) - { - tmpr = a->ptr.p_double[j]; - for(i=j-1; i>=k; i--) - { - a->ptr.p_double[i+1] = a->ptr.p_double[i]; - } - a->ptr.p_double[k] = tmpr; - } - } - return; - } - - /* - * Quicksort: choose pivot - * Here we assume that I2-I1>=16 - */ - v0 = a->ptr.p_double[i1]; - v1 = a->ptr.p_double[i1+(i2-i1)/2]; - v2 = a->ptr.p_double[i2]; - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - if( v1>v2 ) - { - tmpr = v2; - v2 = v1; - v1 = tmpr; - } - if( v0>v1 ) - { - tmpr = v1; - v1 = v0; - v0 = tmpr; - } - vp = v1; - - /* - * now pass through A/B and: - * * move elements that are LESS than VP to the left of A/B - * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) - * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order - * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) - * * move elements from the left of BufA/BufB to the end of A/B - */ - cntless = 0; - cnteq = 0; - cntgreater = 0; - for(i=i1; i<=i2; i++) - { - v0 = a->ptr.p_double[i]; - if( v0ptr.p_double[k] = v0; - } - cntless = cntless+1; - continue; - } - if( v0==vp ) - { - - /* - * EQUAL - */ - k = i2-cnteq; - bufa->ptr.p_double[k] = v0; - cnteq = cnteq+1; - continue; - } - - /* - * GREATER - */ - k = i1+cntgreater; - bufa->ptr.p_double[k] = v0; - cntgreater = cntgreater+1; - } - for(i=0; i<=cnteq-1; i++) - { - j = i1+cntless+cnteq-1-i; - k = i2+i-(cnteq-1); - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - } - for(i=0; i<=cntgreater-1; i++) - { - j = i1+cntless+cnteq+i; - k = i1+i; - a->ptr.p_double[j] = bufa->ptr.p_double[k]; - } - - /* - * Sort left and right parts of the array (ignoring middle part) - */ - tsort_tagsortfastrec(a, bufa, i1, i1+cntless-1, _state); - tsort_tagsortfastrec(a, bufa, i1+cntless+cnteq, i2, _state); -} - - - - -/************************************************************************* -Internal ranking subroutine. - -INPUT PARAMETERS: - X - array to rank - N - array size - IsCentered- whether ranks are centered or not: - * True - ranks are centered in such way that their - sum is zero - * False - ranks are not centered - Buf - temporary buffers - -NOTE: when IsCentered is True and all X[] are equal, this function fills - X by zeros (exact zeros are used, not sum which is only approximately - equal to zero). -*************************************************************************/ -void rankx(/* Real */ ae_vector* x, - ae_int_t n, - ae_bool iscentered, - apbuffers* buf, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - double tmp; - double voffs; - - - - /* - * Prepare - */ - if( n<1 ) - { - return; - } - if( n==1 ) - { - x->ptr.p_double[0] = 0; - return; - } - if( buf->ra1.cntra1, n, _state); - } - if( buf->ia1.cntia1, n, _state); - } - for(i=0; i<=n-1; i++) - { - buf->ra1.ptr.p_double[i] = x->ptr.p_double[i]; - buf->ia1.ptr.p_int[i] = i; - } - tagsortfasti(&buf->ra1, &buf->ia1, &buf->ra2, &buf->ia2, n, _state); - - /* - * Special test for all values being equal - */ - if( ae_fp_eq(buf->ra1.ptr.p_double[0],buf->ra1.ptr.p_double[n-1]) ) - { - if( iscentered ) - { - tmp = 0.0; - } - else - { - tmp = (double)(n-1)/(double)2; - } - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = tmp; - } - return; - } - - /* - * compute tied ranks - */ - i = 0; - while(i<=n-1) - { - j = i+1; - while(j<=n-1) - { - if( ae_fp_neq(buf->ra1.ptr.p_double[j],buf->ra1.ptr.p_double[i]) ) - { - break; - } - j = j+1; - } - for(k=i; k<=j-1; k++) - { - buf->ra1.ptr.p_double[k] = (double)(i+j-1)/(double)2; - } - i = j; - } - - /* - * back to x - */ - if( iscentered ) - { - voffs = (double)(n-1)/(double)2; - } - else - { - voffs = 0.0; - } - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[buf->ia1.ptr.p_int[i]] = buf->ra1.ptr.p_double[i]-voffs; - } -} - - - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixrank1f(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_vector* u, - ae_int_t iu, - /* Complex */ ae_vector* v, - ae_int_t iv, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixrank1f(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_vector* u, - ae_int_t iu, - /* Real */ ae_vector* v, - ae_int_t iv, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixmvf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Complex */ ae_vector* x, - ae_int_t ix, - /* Complex */ ae_vector* y, - ae_int_t iy, - ae_state *_state) -{ - ae_bool result; - - - result = ae_false; - return result; -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixmvf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Real */ ae_vector* x, - ae_int_t ix, - /* Real */ ae_vector* y, - ae_int_t iy, - ae_state *_state) -{ - ae_bool result; - - - result = ae_false; - return result; -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_cmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); -#endif -} - - -/************************************************************************* -Fast kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_ABLAS - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); -#endif -} - - -/************************************************************************* -CMatrixGEMM kernel, basecase code for CMatrixGEMM. - -This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: -* C is MxN general matrix -* op1(A) is MxK matrix -* op2(B) is KxN matrix -* "op" may be identity transformation, transposition, conjugate transposition - -Additional info: -* multiplication result replaces C. If Beta=0, C elements are not used in - calculations (not multiplied by zero - just not referenced) -* if Alpha=0, A is not used (not multiplied by zero - just not referenced) -* if both Beta and Alpha are zero, C is filled by zeros. - -IMPORTANT: - -This function does NOT preallocate output matrix C, it MUST be preallocated -by caller prior to calling this function. In case C does not have enough -space to store result, exception will be generated. - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - OpTypeA - transformation type: - * 0 - no transformation - * 1 - transposition - * 2 - conjugate transposition - B - matrix - IB - submatrix offset - JB - submatrix offset - OpTypeB - transformation type: - * 0 - no transformation - * 1 - transposition - * 2 - conjugate transposition - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void cmatrixgemmk(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_complex v; - ae_complex v00; - ae_complex v01; - ae_complex v10; - ae_complex v11; - double v00x; - double v00y; - double v01x; - double v01y; - double v10x; - double v10y; - double v11x; - double v11y; - double a0x; - double a0y; - double a1x; - double a1y; - double b0x; - double b0y; - double b1x; - double b1y; - ae_int_t idxa0; - ae_int_t idxa1; - ae_int_t idxb0; - ae_int_t idxb1; - ae_int_t i0; - ae_int_t i1; - ae_int_t ik; - ae_int_t j0; - ae_int_t j1; - ae_int_t jk; - ae_int_t t; - ae_int_t offsa; - ae_int_t offsb; - - - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * Try optimized code - */ - if( cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) - { - return; - } - - /* - * if K=0, then C=Beta*C - */ - if( k==0 ) - { - if( ae_c_neq_d(beta,1) ) - { - if( ae_c_neq_d(beta,0) ) - { - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul(beta,c->ptr.pp_complex[ic+i][jc+j]); - } - } - } - else - { - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_d(0); - } - } - } - } - return; - } - - /* - * This phase is not really necessary, but compiler complains - * about "possibly uninitialized variables" - */ - a0x = 0; - a0y = 0; - a1x = 0; - a1y = 0; - b0x = 0; - b0y = 0; - b1x = 0; - b1y = 0; - - /* - * General case - */ - i = 0; - while(iptr.pp_complex[idxa0][offsa].x; - a0y = a->ptr.pp_complex[idxa0][offsa].y; - a1x = a->ptr.pp_complex[idxa1][offsa].x; - a1y = a->ptr.pp_complex[idxa1][offsa].y; - } - if( optypea==1 ) - { - a0x = a->ptr.pp_complex[offsa][idxa0].x; - a0y = a->ptr.pp_complex[offsa][idxa0].y; - a1x = a->ptr.pp_complex[offsa][idxa1].x; - a1y = a->ptr.pp_complex[offsa][idxa1].y; - } - if( optypea==2 ) - { - a0x = a->ptr.pp_complex[offsa][idxa0].x; - a0y = -a->ptr.pp_complex[offsa][idxa0].y; - a1x = a->ptr.pp_complex[offsa][idxa1].x; - a1y = -a->ptr.pp_complex[offsa][idxa1].y; - } - if( optypeb==0 ) - { - b0x = b->ptr.pp_complex[offsb][idxb0].x; - b0y = b->ptr.pp_complex[offsb][idxb0].y; - b1x = b->ptr.pp_complex[offsb][idxb1].x; - b1y = b->ptr.pp_complex[offsb][idxb1].y; - } - if( optypeb==1 ) - { - b0x = b->ptr.pp_complex[idxb0][offsb].x; - b0y = b->ptr.pp_complex[idxb0][offsb].y; - b1x = b->ptr.pp_complex[idxb1][offsb].x; - b1y = b->ptr.pp_complex[idxb1][offsb].y; - } - if( optypeb==2 ) - { - b0x = b->ptr.pp_complex[idxb0][offsb].x; - b0y = -b->ptr.pp_complex[idxb0][offsb].y; - b1x = b->ptr.pp_complex[idxb1][offsb].x; - b1y = -b->ptr.pp_complex[idxb1][offsb].y; - } - v00x = v00x+a0x*b0x-a0y*b0y; - v00y = v00y+a0x*b0y+a0y*b0x; - v01x = v01x+a0x*b1x-a0y*b1y; - v01y = v01y+a0x*b1y+a0y*b1x; - v10x = v10x+a1x*b0x-a1y*b0y; - v10y = v10y+a1x*b0y+a1y*b0x; - v11x = v11x+a1x*b1x-a1y*b1y; - v11y = v11y+a1x*b1y+a1y*b1x; - offsa = offsa+1; - offsb = offsb+1; - } - v00.x = v00x; - v00.y = v00y; - v10.x = v10x; - v10.y = v10y; - v01.x = v01x; - v01.y = v01y; - v11.x = v11x; - v11.y = v11y; - if( ae_c_eq_d(beta,0) ) - { - c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_mul(alpha,v00); - c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_mul(alpha,v01); - c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_mul(alpha,v10); - c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_mul(alpha,v11); - } - else - { - c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+0]),ae_c_mul(alpha,v00)); - c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+1]),ae_c_mul(alpha,v01)); - c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+0]),ae_c_mul(alpha,v10)); - c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+1]),ae_c_mul(alpha,v11)); - } - } - else - { - - /* - * Determine submatrix [I0..I1]x[J0..J1] to process - */ - i0 = i; - i1 = ae_minint(i+1, m-1, _state); - j0 = j; - j1 = ae_minint(j+1, n-1, _state); - - /* - * Process submatrix - */ - for(ik=i0; ik<=i1; ik++) - { - for(jk=j0; jk<=j1; jk++) - { - if( k==0||ae_c_eq_d(alpha,0) ) - { - v = ae_complex_from_d(0); - } - else - { - v = ae_complex_from_d(0.0); - if( optypea==0&&optypeb==0 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ja,ja+k-1)); - } - if( optypea==0&&optypeb==1 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ja,ja+k-1)); - } - if( optypea==0&&optypeb==2 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ja,ja+k-1)); - } - if( optypea==1&&optypeb==0 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); - } - if( optypea==1&&optypeb==1 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); - } - if( optypea==1&&optypeb==2 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); - } - if( optypea==2&&optypeb==0 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); - } - if( optypea==2&&optypeb==1 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); - } - if( optypea==2&&optypeb==2 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); - } - } - if( ae_c_eq_d(beta,0) ) - { - c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_mul(alpha,v); - } - else - { - c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+ik][jc+jk]),ae_c_mul(alpha,v)); - } - } - } - } - j = j+2; - } - i = i+2; - } -} - - -/************************************************************************* -RMatrixGEMM kernel, basecase code for RMatrixGEMM. - -This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: -* C is MxN general matrix -* op1(A) is MxK matrix -* op2(B) is KxN matrix -* "op" may be identity transformation, transposition - -Additional info: -* multiplication result replaces C. If Beta=0, C elements are not used in - calculations (not multiplied by zero - just not referenced) -* if Alpha=0, A is not used (not multiplied by zero - just not referenced) -* if both Beta and Alpha are zero, C is filled by zeros. - -IMPORTANT: - -This function does NOT preallocate output matrix C, it MUST be preallocated -by caller prior to calling this function. In case C does not have enough -space to store result, exception will be generated. - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - OpTypeA - transformation type: - * 0 - no transformation - * 1 - transposition - B - matrix - IB - submatrix offset - JB - submatrix offset - OpTypeB - transformation type: - * 0 - no transformation - * 1 - transposition - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void rmatrixgemmk(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * Try optimized code - */ - if( rmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) - { - return; - } - - /* - * if K=0, then C=Beta*C - */ - if( k==0||ae_fp_eq(alpha,0) ) - { - if( ae_fp_neq(beta,1) ) - { - if( ae_fp_neq(beta,0) ) - { - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]; - } - } - } - else - { - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - c->ptr.pp_double[ic+i][jc+j] = 0; - } - } - } - } - return; - } - - /* - * Call specialized code. - * - * NOTE: specialized code was moved to separate function because of strange - * issues with instructions cache on some systems; Having too long - * functions significantly slows down internal loop of the algorithm. - */ - if( optypea==0&&optypeb==0 ) - { - rmatrixgemmk44v00(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); - } - if( optypea==0&&optypeb!=0 ) - { - rmatrixgemmk44v01(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); - } - if( optypea!=0&&optypeb==0 ) - { - rmatrixgemmk44v10(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); - } - if( optypea!=0&&optypeb!=0 ) - { - rmatrixgemmk44v11(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); - } -} - - -/************************************************************************* -RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation -with OpTypeA=0 and OpTypeB=0. - -Additional info: -* this function requires that Alpha<>0 (assertion is thrown otherwise) - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - B - matrix - IB - submatrix offset - JB - submatrix offset - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void rmatrixgemmk44v00(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - double v00; - double v01; - double v02; - double v03; - double v10; - double v11; - double v12; - double v13; - double v20; - double v21; - double v22; - double v23; - double v30; - double v31; - double v32; - double v33; - double a0; - double a1; - double a2; - double a3; - double b0; - double b1; - double b2; - double b3; - ae_int_t idxa0; - ae_int_t idxa1; - ae_int_t idxa2; - ae_int_t idxa3; - ae_int_t idxb0; - ae_int_t idxb1; - ae_int_t idxb2; - ae_int_t idxb3; - ae_int_t i0; - ae_int_t i1; - ae_int_t ik; - ae_int_t j0; - ae_int_t j1; - ae_int_t jk; - ae_int_t t; - ae_int_t offsa; - ae_int_t offsb; - - - ae_assert(ae_fp_neq(alpha,0), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * A*B - */ - i = 0; - while(iptr.pp_double[idxa0][offsa]; - a1 = a->ptr.pp_double[idxa1][offsa]; - b0 = b->ptr.pp_double[offsb][idxb0]; - b1 = b->ptr.pp_double[offsb][idxb1]; - v00 = v00+a0*b0; - v01 = v01+a0*b1; - v10 = v10+a1*b0; - v11 = v11+a1*b1; - a2 = a->ptr.pp_double[idxa2][offsa]; - a3 = a->ptr.pp_double[idxa3][offsa]; - v20 = v20+a2*b0; - v21 = v21+a2*b1; - v30 = v30+a3*b0; - v31 = v31+a3*b1; - b2 = b->ptr.pp_double[offsb][idxb2]; - b3 = b->ptr.pp_double[offsb][idxb3]; - v22 = v22+a2*b2; - v23 = v23+a2*b3; - v32 = v32+a3*b2; - v33 = v33+a3*b3; - v02 = v02+a0*b2; - v03 = v03+a0*b3; - v12 = v12+a1*b2; - v13 = v13+a1*b3; - offsa = offsa+1; - offsb = offsb+1; - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; - } - else - { - c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; - } - } - else - { - - /* - * Determine submatrix [I0..I1]x[J0..J1] to process - */ - i0 = i; - i1 = ae_minint(i+3, m-1, _state); - j0 = j; - j1 = ae_minint(j+3, n-1, _state); - - /* - * Process submatrix - */ - for(ik=i0; ik<=i1; ik++) - { - for(jk=j0; jk<=j1; jk++) - { - if( k==0||ae_fp_eq(alpha,0) ) - { - v = 0; - } - else - { - v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ja,ja+k-1)); - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; - } - else - { - c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; - } - } - } - } - j = j+4; - } - i = i+4; - } -} - - -/************************************************************************* -RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation -with OpTypeA=0 and OpTypeB=1. - -Additional info: -* this function requires that Alpha<>0 (assertion is thrown otherwise) - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - B - matrix - IB - submatrix offset - JB - submatrix offset - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void rmatrixgemmk44v01(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - double v00; - double v01; - double v02; - double v03; - double v10; - double v11; - double v12; - double v13; - double v20; - double v21; - double v22; - double v23; - double v30; - double v31; - double v32; - double v33; - double a0; - double a1; - double a2; - double a3; - double b0; - double b1; - double b2; - double b3; - ae_int_t idxa0; - ae_int_t idxa1; - ae_int_t idxa2; - ae_int_t idxa3; - ae_int_t idxb0; - ae_int_t idxb1; - ae_int_t idxb2; - ae_int_t idxb3; - ae_int_t i0; - ae_int_t i1; - ae_int_t ik; - ae_int_t j0; - ae_int_t j1; - ae_int_t jk; - ae_int_t t; - ae_int_t offsa; - ae_int_t offsb; - - - ae_assert(ae_fp_neq(alpha,0), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * A*B' - */ - i = 0; - while(iptr.pp_double[idxa0][offsa]; - a1 = a->ptr.pp_double[idxa1][offsa]; - b0 = b->ptr.pp_double[idxb0][offsb]; - b1 = b->ptr.pp_double[idxb1][offsb]; - v00 = v00+a0*b0; - v01 = v01+a0*b1; - v10 = v10+a1*b0; - v11 = v11+a1*b1; - a2 = a->ptr.pp_double[idxa2][offsa]; - a3 = a->ptr.pp_double[idxa3][offsa]; - v20 = v20+a2*b0; - v21 = v21+a2*b1; - v30 = v30+a3*b0; - v31 = v31+a3*b1; - b2 = b->ptr.pp_double[idxb2][offsb]; - b3 = b->ptr.pp_double[idxb3][offsb]; - v22 = v22+a2*b2; - v23 = v23+a2*b3; - v32 = v32+a3*b2; - v33 = v33+a3*b3; - v02 = v02+a0*b2; - v03 = v03+a0*b3; - v12 = v12+a1*b2; - v13 = v13+a1*b3; - offsa = offsa+1; - offsb = offsb+1; - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; - } - else - { - c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; - } - } - else - { - - /* - * Determine submatrix [I0..I1]x[J0..J1] to process - */ - i0 = i; - i1 = ae_minint(i+3, m-1, _state); - j0 = j; - j1 = ae_minint(j+3, n-1, _state); - - /* - * Process submatrix - */ - for(ik=i0; ik<=i1; ik++) - { - for(jk=j0; jk<=j1; jk++) - { - if( k==0||ae_fp_eq(alpha,0) ) - { - v = 0; - } - else - { - v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ja,ja+k-1)); - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; - } - else - { - c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; - } - } - } - } - j = j+4; - } - i = i+4; - } -} - - -/************************************************************************* -RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation -with OpTypeA=1 and OpTypeB=0. - -Additional info: -* this function requires that Alpha<>0 (assertion is thrown otherwise) - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - B - matrix - IB - submatrix offset - JB - submatrix offset - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void rmatrixgemmk44v10(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - double v00; - double v01; - double v02; - double v03; - double v10; - double v11; - double v12; - double v13; - double v20; - double v21; - double v22; - double v23; - double v30; - double v31; - double v32; - double v33; - double a0; - double a1; - double a2; - double a3; - double b0; - double b1; - double b2; - double b3; - ae_int_t idxa0; - ae_int_t idxa1; - ae_int_t idxa2; - ae_int_t idxa3; - ae_int_t idxb0; - ae_int_t idxb1; - ae_int_t idxb2; - ae_int_t idxb3; - ae_int_t i0; - ae_int_t i1; - ae_int_t ik; - ae_int_t j0; - ae_int_t j1; - ae_int_t jk; - ae_int_t t; - ae_int_t offsa; - ae_int_t offsb; - - - ae_assert(ae_fp_neq(alpha,0), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * A'*B - */ - i = 0; - while(iptr.pp_double[offsa][idxa0]; - a1 = a->ptr.pp_double[offsa][idxa1]; - b0 = b->ptr.pp_double[offsb][idxb0]; - b1 = b->ptr.pp_double[offsb][idxb1]; - v00 = v00+a0*b0; - v01 = v01+a0*b1; - v10 = v10+a1*b0; - v11 = v11+a1*b1; - a2 = a->ptr.pp_double[offsa][idxa2]; - a3 = a->ptr.pp_double[offsa][idxa3]; - v20 = v20+a2*b0; - v21 = v21+a2*b1; - v30 = v30+a3*b0; - v31 = v31+a3*b1; - b2 = b->ptr.pp_double[offsb][idxb2]; - b3 = b->ptr.pp_double[offsb][idxb3]; - v22 = v22+a2*b2; - v23 = v23+a2*b3; - v32 = v32+a3*b2; - v33 = v33+a3*b3; - v02 = v02+a0*b2; - v03 = v03+a0*b3; - v12 = v12+a1*b2; - v13 = v13+a1*b3; - offsa = offsa+1; - offsb = offsb+1; - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; - } - else - { - c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; - } - } - else - { - - /* - * Determine submatrix [I0..I1]x[J0..J1] to process - */ - i0 = i; - i1 = ae_minint(i+3, m-1, _state); - j0 = j; - j1 = ae_minint(j+3, n-1, _state); - - /* - * Process submatrix - */ - for(ik=i0; ik<=i1; ik++) - { - for(jk=j0; jk<=j1; jk++) - { - if( k==0||ae_fp_eq(alpha,0) ) - { - v = 0; - } - else - { - v = 0.0; - v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ia,ia+k-1)); - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; - } - else - { - c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; - } - } - } - } - j = j+4; - } - i = i+4; - } -} - - -/************************************************************************* -RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation -with OpTypeA=1 and OpTypeB=1. - -Additional info: -* this function requires that Alpha<>0 (assertion is thrown otherwise) - -INPUT PARAMETERS - M - matrix size, M>0 - N - matrix size, N>0 - K - matrix size, K>0 - Alpha - coefficient - A - matrix - IA - submatrix offset - JA - submatrix offset - B - matrix - IB - submatrix offset - JB - submatrix offset - Beta - coefficient - C - PREALLOCATED output matrix - IC - submatrix offset - JC - submatrix offset - - -- ALGLIB routine -- - 27.03.2013 - Bochkanov Sergey -*************************************************************************/ -void rmatrixgemmk44v11(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - double v00; - double v01; - double v02; - double v03; - double v10; - double v11; - double v12; - double v13; - double v20; - double v21; - double v22; - double v23; - double v30; - double v31; - double v32; - double v33; - double a0; - double a1; - double a2; - double a3; - double b0; - double b1; - double b2; - double b3; - ae_int_t idxa0; - ae_int_t idxa1; - ae_int_t idxa2; - ae_int_t idxa3; - ae_int_t idxb0; - ae_int_t idxb1; - ae_int_t idxb2; - ae_int_t idxb3; - ae_int_t i0; - ae_int_t i1; - ae_int_t ik; - ae_int_t j0; - ae_int_t j1; - ae_int_t jk; - ae_int_t t; - ae_int_t offsa; - ae_int_t offsb; - - - ae_assert(ae_fp_neq(alpha,0), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); - - /* - * if matrix size is zero - */ - if( m==0||n==0 ) - { - return; - } - - /* - * A'*B' - */ - i = 0; - while(iptr.pp_double[offsa][idxa0]; - a1 = a->ptr.pp_double[offsa][idxa1]; - b0 = b->ptr.pp_double[idxb0][offsb]; - b1 = b->ptr.pp_double[idxb1][offsb]; - v00 = v00+a0*b0; - v01 = v01+a0*b1; - v10 = v10+a1*b0; - v11 = v11+a1*b1; - a2 = a->ptr.pp_double[offsa][idxa2]; - a3 = a->ptr.pp_double[offsa][idxa3]; - v20 = v20+a2*b0; - v21 = v21+a2*b1; - v30 = v30+a3*b0; - v31 = v31+a3*b1; - b2 = b->ptr.pp_double[idxb2][offsb]; - b3 = b->ptr.pp_double[idxb3][offsb]; - v22 = v22+a2*b2; - v23 = v23+a2*b3; - v32 = v32+a3*b2; - v33 = v33+a3*b3; - v02 = v02+a0*b2; - v03 = v03+a0*b3; - v12 = v12+a1*b2; - v13 = v13+a1*b3; - offsa = offsa+1; - offsb = offsb+1; - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; - } - else - { - c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; - c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; - c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; - c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; - c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; - c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; - c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; - c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; - c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; - c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; - c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; - c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; - c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; - c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; - c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; - c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; - } - } - else - { - - /* - * Determine submatrix [I0..I1]x[J0..J1] to process - */ - i0 = i; - i1 = ae_minint(i+3, m-1, _state); - j0 = j; - j1 = ae_minint(j+3, n-1, _state); - - /* - * Process submatrix - */ - for(ik=i0; ik<=i1; ik++) - { - for(jk=j0; jk<=j1; jk++) - { - if( k==0||ae_fp_eq(alpha,0) ) - { - v = 0; - } - else - { - v = 0.0; - v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ia,ia+k-1)); - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; - } - else - { - c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; - } - } - } - } - j = j+4; - } - i = i+4; - } -} - - - - -/************************************************************************* -MKL-based kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixsyrkmkl(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_MKL - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixsyrkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); -#endif -} - - -/************************************************************************* -MKL-based kernel - - -- ALGLIB routine -- - 19.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixgemmmkl(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_MKL - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_rmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); -#endif -} - - - - -double vectornorm2(/* Real */ ae_vector* x, - ae_int_t i1, - ae_int_t i2, - ae_state *_state) -{ - ae_int_t n; - ae_int_t ix; - double absxi; - double scl; - double ssq; - double result; - - - n = i2-i1+1; - if( n<1 ) - { - result = 0; - return result; - } - if( n==1 ) - { - result = ae_fabs(x->ptr.p_double[i1], _state); - return result; - } - scl = 0; - ssq = 1; - for(ix=i1; ix<=i2; ix++) - { - if( ae_fp_neq(x->ptr.p_double[ix],0) ) - { - absxi = ae_fabs(x->ptr.p_double[ix], _state); - if( ae_fp_less(scl,absxi) ) - { - ssq = 1+ssq*ae_sqr(scl/absxi, _state); - scl = absxi; - } - else - { - ssq = ssq+ae_sqr(absxi/scl, _state); - } - } - } - result = scl*ae_sqrt(ssq, _state); - return result; -} - - -ae_int_t vectoridxabsmax(/* Real */ ae_vector* x, - ae_int_t i1, - ae_int_t i2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t result; - - - result = i1; - for(i=i1+1; i<=i2; i++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[result], _state)) ) - { - result = i; - } - } - return result; -} - - -ae_int_t columnidxabsmax(/* Real */ ae_matrix* x, - ae_int_t i1, - ae_int_t i2, - ae_int_t j, - ae_state *_state) -{ - ae_int_t i; - ae_int_t result; - - - result = i1; - for(i=i1+1; i<=i2; i++) - { - if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[result][j], _state)) ) - { - result = i; - } - } - return result; -} - - -ae_int_t rowidxabsmax(/* Real */ ae_matrix* x, - ae_int_t j1, - ae_int_t j2, - ae_int_t i, - ae_state *_state) -{ - ae_int_t j; - ae_int_t result; - - - result = j1; - for(j=j1+1; j<=j2; j++) - { - if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[i][result], _state)) ) - { - result = j; - } - } - return result; -} - - -double upperhessenberg1norm(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double result; - - - ae_assert(i2-i1==j2-j1, "UpperHessenberg1Norm: I2-I1<>J2-J1!", _state); - for(j=j1; j<=j2; j++) - { - work->ptr.p_double[j] = 0; - } - for(i=i1; i<=i2; i++) - { - for(j=ae_maxint(j1, j1+i-i1-1, _state); j<=j2; j++) - { - work->ptr.p_double[j] = work->ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); - } - } - result = 0; - for(j=j1; j<=j2; j++) - { - result = ae_maxreal(result, work->ptr.p_double[j], _state); - } - return result; -} - - -void copymatrix(/* Real */ ae_matrix* a, - ae_int_t is1, - ae_int_t is2, - ae_int_t js1, - ae_int_t js2, - /* Real */ ae_matrix* b, - ae_int_t id1, - ae_int_t id2, - ae_int_t jd1, - ae_int_t jd2, - ae_state *_state) -{ - ae_int_t isrc; - ae_int_t idst; - - - if( is1>is2||js1>js2 ) - { - return; - } - ae_assert(is2-is1==id2-id1, "CopyMatrix: different sizes!", _state); - ae_assert(js2-js1==jd2-jd1, "CopyMatrix: different sizes!", _state); - for(isrc=is1; isrc<=is2; isrc++) - { - idst = isrc-is1+id1; - ae_v_move(&b->ptr.pp_double[idst][jd1], 1, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(jd1,jd2)); - } -} - - -void inplacetranspose(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t ips; - ae_int_t jps; - ae_int_t l; - - - if( i1>i2||j1>j2 ) - { - return; - } - ae_assert(i1-i2==j1-j2, "InplaceTranspose error: incorrect array size!", _state); - for(i=i1; i<=i2-1; i++) - { - j = j1+i-i1; - ips = i+1; - jps = j1+ips-i1; - l = i2-i; - ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ips][j], a->stride, ae_v_len(1,l)); - ae_v_move(&a->ptr.pp_double[ips][j], a->stride, &a->ptr.pp_double[i][jps], 1, ae_v_len(ips,i2)); - ae_v_move(&a->ptr.pp_double[i][jps], 1, &work->ptr.p_double[1], 1, ae_v_len(jps,j2)); - } -} - - -void copyandtranspose(/* Real */ ae_matrix* a, - ae_int_t is1, - ae_int_t is2, - ae_int_t js1, - ae_int_t js2, - /* Real */ ae_matrix* b, - ae_int_t id1, - ae_int_t id2, - ae_int_t jd1, - ae_int_t jd2, - ae_state *_state) -{ - ae_int_t isrc; - ae_int_t jdst; - - - if( is1>is2||js1>js2 ) - { - return; - } - ae_assert(is2-is1==jd2-jd1, "CopyAndTranspose: different sizes!", _state); - ae_assert(js2-js1==id2-id1, "CopyAndTranspose: different sizes!", _state); - for(isrc=is1; isrc<=is2; isrc++) - { - jdst = isrc-is1+jd1; - ae_v_move(&b->ptr.pp_double[id1][jdst], b->stride, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(id1,id2)); - } -} - - -void matrixvectormultiply(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - ae_bool trans, - /* Real */ ae_vector* x, - ae_int_t ix1, - ae_int_t ix2, - double alpha, - /* Real */ ae_vector* y, - ae_int_t iy1, - ae_int_t iy2, - double beta, - ae_state *_state) -{ - ae_int_t i; - double v; - - - if( !trans ) - { - - /* - * y := alpha*A*x + beta*y; - */ - if( i1>i2||j1>j2 ) - { - return; - } - ae_assert(j2-j1==ix2-ix1, "MatrixVectorMultiply: A and X dont match!", _state); - ae_assert(i2-i1==iy2-iy1, "MatrixVectorMultiply: A and Y dont match!", _state); - - /* - * beta*y - */ - if( ae_fp_eq(beta,0) ) - { - for(i=iy1; i<=iy2; i++) - { - y->ptr.p_double[i] = 0; - } - } - else - { - ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); - } - - /* - * alpha*A*x - */ - for(i=i1; i<=i2; i++) - { - v = ae_v_dotproduct(&a->ptr.pp_double[i][j1], 1, &x->ptr.p_double[ix1], 1, ae_v_len(j1,j2)); - y->ptr.p_double[iy1+i-i1] = y->ptr.p_double[iy1+i-i1]+alpha*v; - } - } - else - { - - /* - * y := alpha*A'*x + beta*y; - */ - if( i1>i2||j1>j2 ) - { - return; - } - ae_assert(i2-i1==ix2-ix1, "MatrixVectorMultiply: A and X do not match!", _state); - ae_assert(j2-j1==iy2-iy1, "MatrixVectorMultiply: A and Y do not match!", _state); - - /* - * beta*y - */ - if( ae_fp_eq(beta,0) ) - { - for(i=iy1; i<=iy2; i++) - { - y->ptr.p_double[i] = 0; - } - } - else - { - ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); - } - - /* - * alpha*A'*x - */ - for(i=i1; i<=i2; i++) - { - v = alpha*x->ptr.p_double[ix1+i-i1]; - ae_v_addd(&y->ptr.p_double[iy1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(iy1,iy2), v); - } - } -} - - -double pythag2(double x, double y, ae_state *_state) -{ - double w; - double xabs; - double yabs; - double z; - double result; - - - xabs = ae_fabs(x, _state); - yabs = ae_fabs(y, _state); - w = ae_maxreal(xabs, yabs, _state); - z = ae_minreal(xabs, yabs, _state); - if( ae_fp_eq(z,0) ) - { - result = w; - } - else - { - result = w*ae_sqrt(1+ae_sqr(z/w, _state), _state); - } - return result; -} - - -void matrixmatrixmultiply(/* Real */ ae_matrix* a, - ae_int_t ai1, - ae_int_t ai2, - ae_int_t aj1, - ae_int_t aj2, - ae_bool transa, - /* Real */ ae_matrix* b, - ae_int_t bi1, - ae_int_t bi2, - ae_int_t bj1, - ae_int_t bj2, - ae_bool transb, - double alpha, - /* Real */ ae_matrix* c, - ae_int_t ci1, - ae_int_t ci2, - ae_int_t cj1, - ae_int_t cj2, - double beta, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t arows; - ae_int_t acols; - ae_int_t brows; - ae_int_t bcols; - ae_int_t crows; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t l; - ae_int_t r; - double v; - - - - /* - * Setup - */ - if( !transa ) - { - arows = ai2-ai1+1; - acols = aj2-aj1+1; - } - else - { - arows = aj2-aj1+1; - acols = ai2-ai1+1; - } - if( !transb ) - { - brows = bi2-bi1+1; - bcols = bj2-bj1+1; - } - else - { - brows = bj2-bj1+1; - bcols = bi2-bi1+1; - } - ae_assert(acols==brows, "MatrixMatrixMultiply: incorrect matrix sizes!", _state); - if( ((arows<=0||acols<=0)||brows<=0)||bcols<=0 ) - { - return; - } - crows = arows; - - /* - * Test WORK - */ - i = ae_maxint(arows, acols, _state); - i = ae_maxint(brows, i, _state); - i = ae_maxint(i, bcols, _state); - work->ptr.p_double[1] = 0; - work->ptr.p_double[i] = 0; - - /* - * Prepare C - */ - if( ae_fp_eq(beta,0) ) - { - for(i=ci1; i<=ci2; i++) - { - for(j=cj1; j<=cj2; j++) - { - c->ptr.pp_double[i][j] = 0; - } - } - } - else - { - for(i=ci1; i<=ci2; i++) - { - ae_v_muld(&c->ptr.pp_double[i][cj1], 1, ae_v_len(cj1,cj2), beta); - } - } - - /* - * A*B - */ - if( !transa&&!transb ) - { - for(l=ai1; l<=ai2; l++) - { - for(r=bi1; r<=bi2; r++) - { - v = alpha*a->ptr.pp_double[l][aj1+r-bi1]; - k = ci1+l-ai1; - ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); - } - } - return; - } - - /* - * A*B' - */ - if( !transa&&transb ) - { - if( arows*acolsptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); - c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; - } - } - return; - } - else - { - for(l=ai1; l<=ai2; l++) - { - for(r=bi1; r<=bi2; r++) - { - v = ae_v_dotproduct(&a->ptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); - c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; - } - } - return; - } - } - - /* - * A'*B - */ - if( transa&&!transb ) - { - for(l=aj1; l<=aj2; l++) - { - for(r=bi1; r<=bi2; r++) - { - v = alpha*a->ptr.pp_double[ai1+r-bi1][l]; - k = ci1+l-aj1; - ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); - } - } - return; - } - - /* - * A'*B' - */ - if( transa&&transb ) - { - if( arows*acolsptr.p_double[i] = 0.0; - } - for(l=ai1; l<=ai2; l++) - { - v = alpha*b->ptr.pp_double[r][bj1+l-ai1]; - ae_v_addd(&work->ptr.p_double[1], 1, &a->ptr.pp_double[l][aj1], 1, ae_v_len(1,crows), v); - } - ae_v_add(&c->ptr.pp_double[ci1][k], c->stride, &work->ptr.p_double[1], 1, ae_v_len(ci1,ci2)); - } - return; - } - else - { - for(l=aj1; l<=aj2; l++) - { - k = ai2-ai1+1; - ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ai1][l], a->stride, ae_v_len(1,k)); - for(r=bi1; r<=bi2; r++) - { - v = ae_v_dotproduct(&work->ptr.p_double[1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(1,k)); - c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1]+alpha*v; - } - } - return; - } - } -} - - - - -void hermitianmatrixvectormultiply(/* Complex */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Complex */ ae_vector* x, - ae_complex alpha, - /* Complex */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ba1; - ae_int_t by1; - ae_int_t by2; - ae_int_t bx1; - ae_int_t bx2; - ae_int_t n; - ae_complex v; - - - n = i2-i1+1; - if( n<=0 ) - { - return; - } - - /* - * Let A = L + D + U, where - * L is strictly lower triangular (main diagonal is zero) - * D is diagonal - * U is strictly upper triangular (main diagonal is zero) - * - * A*x = L*x + D*x + U*x - * - * Calculate D*x first - */ - for(i=i1; i<=i2; i++) - { - y->ptr.p_complex[i-i1+1] = ae_c_mul(a->ptr.pp_complex[i][i],x->ptr.p_complex[i-i1+1]); - } - - /* - * Add L*x + U*x - */ - if( isupper ) - { - for(i=i1; i<=i2-1; i++) - { - - /* - * Add L*x to the result - */ - v = x->ptr.p_complex[i-i1+1]; - by1 = i-i1+2; - by2 = n; - ba1 = i+1; - ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); - - /* - * Add U*x to the result - */ - bx1 = i-i1+2; - bx2 = n; - ba1 = i+1; - v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); - y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); - } - } - else - { - for(i=i1+1; i<=i2; i++) - { - - /* - * Add L*x to the result - */ - bx1 = 1; - bx2 = i-i1; - ba1 = i1; - v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); - y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); - - /* - * Add U*x to the result - */ - v = x->ptr.p_complex[i-i1+1]; - by1 = 1; - by2 = i-i1; - ba1 = i1; - ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); - } - } - ae_v_cmulc(&y->ptr.p_complex[1], 1, ae_v_len(1,n), alpha); -} - - -void hermitianrank2update(/* Complex */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Complex */ ae_vector* x, - /* Complex */ ae_vector* y, - /* Complex */ ae_vector* t, - ae_complex alpha, - ae_state *_state) -{ - ae_int_t i; - ae_int_t tp1; - ae_int_t tp2; - ae_complex v; - - - if( isupper ) - { - for(i=i1; i<=i2; i++) - { - tp1 = i+1-i1; - tp2 = i2-i1+1; - v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); - ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); - v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); - ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); - ae_v_cadd(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i,i2)); - } - } - else - { - for(i=i1; i<=i2; i++) - { - tp1 = 1; - tp2 = i+1-i1; - v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); - ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); - v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); - ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); - ae_v_cadd(&a->ptr.pp_complex[i][i1], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i1,i)); - } - } -} - - - - -/************************************************************************* -Generation of an elementary reflection transformation - -The subroutine generates elementary reflection H of order N, so that, for -a given X, the following equality holds true: - - ( X(1) ) ( Beta ) -H * ( .. ) = ( 0 ) - ( X(n) ) ( 0 ) - -where - ( V(1) ) -H = 1 - Tau * ( .. ) * ( V(1), ..., V(n) ) - ( V(n) ) - -where the first component of vector V equals 1. - -Input parameters: - X - vector. Array whose index ranges within [1..N]. - N - reflection order. - -Output parameters: - X - components from 2 to N are replaced with vector V. - The first component is replaced with parameter Beta. - Tau - scalar value Tau. If X is a null vector, Tau equals 0, - otherwise 1 <= Tau <= 2. - -This subroutine is the modification of the DLARFG subroutines from -the LAPACK library. - -MODIFICATIONS: - 24.12.2005 sign(Alpha) was replaced with an analogous to the Fortran SIGN code. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void generatereflection(/* Real */ ae_vector* x, - ae_int_t n, - double* tau, - ae_state *_state) -{ - ae_int_t j; - double alpha; - double xnorm; - double v; - double beta; - double mx; - double s; - - *tau = 0; - - if( n<=1 ) - { - *tau = 0; - return; - } - - /* - * Scale if needed (to avoid overflow/underflow during intermediate - * calculations). - */ - mx = 0; - for(j=1; j<=n; j++) - { - mx = ae_maxreal(ae_fabs(x->ptr.p_double[j], _state), mx, _state); - } - s = 1; - if( ae_fp_neq(mx,0) ) - { - if( ae_fp_less_eq(mx,ae_minrealnumber/ae_machineepsilon) ) - { - s = ae_minrealnumber/ae_machineepsilon; - v = 1/s; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); - mx = mx*v; - } - else - { - if( ae_fp_greater_eq(mx,ae_maxrealnumber*ae_machineepsilon) ) - { - s = ae_maxrealnumber*ae_machineepsilon; - v = 1/s; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); - mx = mx*v; - } - } - } - - /* - * XNORM = DNRM2( N-1, X, INCX ) - */ - alpha = x->ptr.p_double[1]; - xnorm = 0; - if( ae_fp_neq(mx,0) ) - { - for(j=2; j<=n; j++) - { - xnorm = xnorm+ae_sqr(x->ptr.p_double[j]/mx, _state); - } - xnorm = ae_sqrt(xnorm, _state)*mx; - } - if( ae_fp_eq(xnorm,0) ) - { - - /* - * H = I - */ - *tau = 0; - x->ptr.p_double[1] = x->ptr.p_double[1]*s; - return; - } - - /* - * general case - */ - mx = ae_maxreal(ae_fabs(alpha, _state), ae_fabs(xnorm, _state), _state); - beta = -mx*ae_sqrt(ae_sqr(alpha/mx, _state)+ae_sqr(xnorm/mx, _state), _state); - if( ae_fp_less(alpha,0) ) - { - beta = -beta; - } - *tau = (beta-alpha)/beta; - v = 1/(alpha-beta); - ae_v_muld(&x->ptr.p_double[2], 1, ae_v_len(2,n), v); - x->ptr.p_double[1] = beta; - - /* - * Scale back outputs - */ - x->ptr.p_double[1] = x->ptr.p_double[1]*s; -} - - -/************************************************************************* -Application of an elementary reflection to a rectangular matrix of size MxN - -The algorithm pre-multiplies the matrix by an elementary reflection transformation -which is given by column V and scalar Tau (see the description of the -GenerateReflection procedure). Not the whole matrix but only a part of it -is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements -of this submatrix are changed. - -Input parameters: - C - matrix to be transformed. - Tau - scalar defining the transformation. - V - column defining the transformation. - Array whose index ranges within [1..M2-M1+1]. - M1, M2 - range of rows to be transformed. - N1, N2 - range of columns to be transformed. - WORK - working array whose indexes goes from N1 to N2. - -Output parameters: - C - the result of multiplying the input matrix C by the - transformation matrix which is given by Tau and V. - If N1>N2 or M1>M2, C is not modified. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void applyreflectionfromtheleft(/* Real */ ae_matrix* c, - double tau, - /* Real */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* work, - ae_state *_state) -{ - double t; - ae_int_t i; - - - if( (ae_fp_eq(tau,0)||n1>n2)||m1>m2 ) - { - return; - } - - /* - * w := C' * v - */ - for(i=n1; i<=n2; i++) - { - work->ptr.p_double[i] = 0; - } - for(i=m1; i<=m2; i++) - { - t = v->ptr.p_double[i+1-m1]; - ae_v_addd(&work->ptr.p_double[n1], 1, &c->ptr.pp_double[i][n1], 1, ae_v_len(n1,n2), t); - } - - /* - * C := C - tau * v * w' - */ - for(i=m1; i<=m2; i++) - { - t = v->ptr.p_double[i-m1+1]*tau; - ae_v_subd(&c->ptr.pp_double[i][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2), t); - } -} - - -/************************************************************************* -Application of an elementary reflection to a rectangular matrix of size MxN - -The algorithm post-multiplies the matrix by an elementary reflection transformation -which is given by column V and scalar Tau (see the description of the -GenerateReflection procedure). Not the whole matrix but only a part of it -is transformed (rows from M1 to M2, columns from N1 to N2). Only the -elements of this submatrix are changed. - -Input parameters: - C - matrix to be transformed. - Tau - scalar defining the transformation. - V - column defining the transformation. - Array whose index ranges within [1..N2-N1+1]. - M1, M2 - range of rows to be transformed. - N1, N2 - range of columns to be transformed. - WORK - working array whose indexes goes from M1 to M2. - -Output parameters: - C - the result of multiplying the input matrix C by the - transformation matrix which is given by Tau and V. - If N1>N2 or M1>M2, C is not modified. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void applyreflectionfromtheright(/* Real */ ae_matrix* c, - double tau, - /* Real */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* work, - ae_state *_state) -{ - double t; - ae_int_t i; - ae_int_t vm; - - - if( (ae_fp_eq(tau,0)||n1>n2)||m1>m2 ) - { - return; - } - vm = n2-n1+1; - for(i=m1; i<=m2; i++) - { - t = ae_v_dotproduct(&c->ptr.pp_double[i][n1], 1, &v->ptr.p_double[1], 1, ae_v_len(n1,n2)); - t = t*tau; - ae_v_subd(&c->ptr.pp_double[i][n1], 1, &v->ptr.p_double[1], 1, ae_v_len(n1,n2), t); - } - - /* - * This line is necessary to avoid spurious compiler warnings - */ - touchint(&vm, _state); -} - - - - -/************************************************************************* -Generation of an elementary complex reflection transformation - -The subroutine generates elementary complex reflection H of order N, so -that, for a given X, the following equality holds true: - - ( X(1) ) ( Beta ) -H' * ( .. ) = ( 0 ), H'*H = I, Beta is a real number - ( X(n) ) ( 0 ) - -where - - ( V(1) ) -H = 1 - Tau * ( .. ) * ( conj(V(1)), ..., conj(V(n)) ) - ( V(n) ) - -where the first component of vector V equals 1. - -Input parameters: - X - vector. Array with elements [1..N]. - N - reflection order. - -Output parameters: - X - components from 2 to N are replaced by vector V. - The first component is replaced with parameter Beta. - Tau - scalar value Tau. - -This subroutine is the modification of CLARFG subroutines from the LAPACK -library. It has similar functionality except for the fact that it doesnÂ’t -handle errors when intermediate results cause an overflow. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void complexgeneratereflection(/* Complex */ ae_vector* x, - ae_int_t n, - ae_complex* tau, - ae_state *_state) -{ - ae_int_t j; - ae_complex alpha; - double alphi; - double alphr; - double beta; - double xnorm; - double mx; - ae_complex t; - double s; - ae_complex v; - - tau->x = 0; - tau->y = 0; - - if( n<=0 ) - { - *tau = ae_complex_from_d(0); - return; - } - - /* - * Scale if needed (to avoid overflow/underflow during intermediate - * calculations). - */ - mx = 0; - for(j=1; j<=n; j++) - { - mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); - } - s = 1; - if( ae_fp_neq(mx,0) ) - { - if( ae_fp_less(mx,1) ) - { - s = ae_sqrt(ae_minrealnumber, _state); - v = ae_complex_from_d(1/s); - ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); - } - else - { - s = ae_sqrt(ae_maxrealnumber, _state); - v = ae_complex_from_d(1/s); - ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); - } - } - - /* - * calculate - */ - alpha = x->ptr.p_complex[1]; - mx = 0; - for(j=2; j<=n; j++) - { - mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); - } - xnorm = 0; - if( ae_fp_neq(mx,0) ) - { - for(j=2; j<=n; j++) - { - t = ae_c_div_d(x->ptr.p_complex[j],mx); - xnorm = xnorm+ae_c_mul(t,ae_c_conj(t, _state)).x; - } - xnorm = ae_sqrt(xnorm, _state)*mx; - } - alphr = alpha.x; - alphi = alpha.y; - if( ae_fp_eq(xnorm,0)&&ae_fp_eq(alphi,0) ) - { - *tau = ae_complex_from_d(0); - x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); - return; - } - mx = ae_maxreal(ae_fabs(alphr, _state), ae_fabs(alphi, _state), _state); - mx = ae_maxreal(mx, ae_fabs(xnorm, _state), _state); - beta = -mx*ae_sqrt(ae_sqr(alphr/mx, _state)+ae_sqr(alphi/mx, _state)+ae_sqr(xnorm/mx, _state), _state); - if( ae_fp_less(alphr,0) ) - { - beta = -beta; - } - tau->x = (beta-alphr)/beta; - tau->y = -alphi/beta; - alpha = ae_c_d_div(1,ae_c_sub_d(alpha,beta)); - if( n>1 ) - { - ae_v_cmulc(&x->ptr.p_complex[2], 1, ae_v_len(2,n), alpha); - } - alpha = ae_complex_from_d(beta); - x->ptr.p_complex[1] = alpha; - - /* - * Scale back - */ - x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); -} - - -/************************************************************************* -Application of an elementary reflection to a rectangular matrix of size MxN - -The algorithm pre-multiplies the matrix by an elementary reflection -transformation which is given by column V and scalar Tau (see the -description of the GenerateReflection). Not the whole matrix but only a -part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only -the elements of this submatrix are changed. - -Note: the matrix is multiplied by H, not by H'. If it is required to -multiply the matrix by H', it is necessary to pass Conj(Tau) instead of Tau. - -Input parameters: - C - matrix to be transformed. - Tau - scalar defining transformation. - V - column defining transformation. - Array whose index ranges within [1..M2-M1+1] - M1, M2 - range of rows to be transformed. - N1, N2 - range of columns to be transformed. - WORK - working array whose index goes from N1 to N2. - -Output parameters: - C - the result of multiplying the input matrix C by the - transformation matrix which is given by Tau and V. - If N1>N2 or M1>M2, C is not modified. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, - ae_complex tau, - /* Complex */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Complex */ ae_vector* work, - ae_state *_state) -{ - ae_complex t; - ae_int_t i; - - - if( (ae_c_eq_d(tau,0)||n1>n2)||m1>m2 ) - { - return; - } - - /* - * w := C^T * conj(v) - */ - for(i=n1; i<=n2; i++) - { - work->ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=m1; i<=m2; i++) - { - t = ae_c_conj(v->ptr.p_complex[i+1-m1], _state); - ae_v_caddc(&work->ptr.p_complex[n1], 1, &c->ptr.pp_complex[i][n1], 1, "N", ae_v_len(n1,n2), t); - } - - /* - * C := C - tau * v * w^T - */ - for(i=m1; i<=m2; i++) - { - t = ae_c_mul(v->ptr.p_complex[i-m1+1],tau); - ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &work->ptr.p_complex[n1], 1, "N", ae_v_len(n1,n2), t); - } -} - - -/************************************************************************* -Application of an elementary reflection to a rectangular matrix of size MxN - -The algorithm post-multiplies the matrix by an elementary reflection -transformation which is given by column V and scalar Tau (see the -description of the GenerateReflection). Not the whole matrix but only a -part of it is transformed (rows from M1 to M2, columns from N1 to N2). -Only the elements of this submatrix are changed. - -Input parameters: - C - matrix to be transformed. - Tau - scalar defining transformation. - V - column defining transformation. - Array whose index ranges within [1..N2-N1+1] - M1, M2 - range of rows to be transformed. - N1, N2 - range of columns to be transformed. - WORK - working array whose index goes from M1 to M2. - -Output parameters: - C - the result of multiplying the input matrix C by the - transformation matrix which is given by Tau and V. - If N1>N2 or M1>M2, C is not modified. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, - ae_complex tau, - /* Complex */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Complex */ ae_vector* work, - ae_state *_state) -{ - ae_complex t; - ae_int_t i; - ae_int_t vm; - - - if( (ae_c_eq_d(tau,0)||n1>n2)||m1>m2 ) - { - return; - } - - /* - * w := C * v - */ - vm = n2-n1+1; - for(i=m1; i<=m2; i++) - { - t = ae_v_cdotproduct(&c->ptr.pp_complex[i][n1], 1, "N", &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2)); - work->ptr.p_complex[i] = t; - } - - /* - * C := C - w * conj(v^T) - */ - ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); - for(i=m1; i<=m2; i++) - { - t = ae_c_mul(work->ptr.p_complex[i],tau); - ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2), t); - } - ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); -} - - - - -void symmetricmatrixvectormultiply(/* Real */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* x, - double alpha, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ba1; - ae_int_t ba2; - ae_int_t by1; - ae_int_t by2; - ae_int_t bx1; - ae_int_t bx2; - ae_int_t n; - double v; - - - n = i2-i1+1; - if( n<=0 ) - { - return; - } - - /* - * Let A = L + D + U, where - * L is strictly lower triangular (main diagonal is zero) - * D is diagonal - * U is strictly upper triangular (main diagonal is zero) - * - * A*x = L*x + D*x + U*x - * - * Calculate D*x first - */ - for(i=i1; i<=i2; i++) - { - y->ptr.p_double[i-i1+1] = a->ptr.pp_double[i][i]*x->ptr.p_double[i-i1+1]; - } - - /* - * Add L*x + U*x - */ - if( isupper ) - { - for(i=i1; i<=i2-1; i++) - { - - /* - * Add L*x to the result - */ - v = x->ptr.p_double[i-i1+1]; - by1 = i-i1+2; - by2 = n; - ba1 = i+1; - ba2 = i2; - ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); - - /* - * Add U*x to the result - */ - bx1 = i-i1+2; - bx2 = n; - ba1 = i+1; - ba2 = i2; - v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); - y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; - } - } - else - { - for(i=i1+1; i<=i2; i++) - { - - /* - * Add L*x to the result - */ - bx1 = 1; - bx2 = i-i1; - ba1 = i1; - ba2 = i-1; - v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); - y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; - - /* - * Add U*x to the result - */ - v = x->ptr.p_double[i-i1+1]; - by1 = 1; - by2 = i-i1; - ba1 = i1; - ba2 = i-1; - ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); - } - } - ae_v_muld(&y->ptr.p_double[1], 1, ae_v_len(1,n), alpha); - touchint(&ba2, _state); -} - - -void symmetricrank2update(/* Real */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* t, - double alpha, - ae_state *_state) -{ - ae_int_t i; - ae_int_t tp1; - ae_int_t tp2; - double v; - - - if( isupper ) - { - for(i=i1; i<=i2; i++) - { - tp1 = i+1-i1; - tp2 = i2-i1+1; - v = x->ptr.p_double[i+1-i1]; - ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); - v = y->ptr.p_double[i+1-i1]; - ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); - ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); - ae_v_add(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i,i2)); - } - } - else - { - for(i=i1; i<=i2; i++) - { - tp1 = 1; - tp2 = i+1-i1; - v = x->ptr.p_double[i+1-i1]; - ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); - v = y->ptr.p_double[i+1-i1]; - ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); - ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); - ae_v_add(&a->ptr.pp_double[i][i1], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i1,i)); - } - } -} - - - - -/************************************************************************* -Application of a sequence of elementary rotations to a matrix - -The algorithm pre-multiplies the matrix by a sequence of rotation -transformations which is given by arrays C and S. Depending on the value -of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) -rows are rotated, or the rows N and N-1, N-2 and N-3 and so on, are rotated. - -Not the whole matrix but only a part of it is transformed (rows from M1 to -M2, columns from N1 to N2). Only the elements of this submatrix are changed. - -Input parameters: - IsForward - the sequence of the rotation application. - M1,M2 - the range of rows to be transformed. - N1, N2 - the range of columns to be transformed. - C,S - transformation coefficients. - Array whose index ranges within [1..M2-M1]. - A - processed matrix. - WORK - working array whose index ranges within [N1..N2]. - -Output parameters: - A - transformed matrix. - -Utility subroutine. -*************************************************************************/ -void applyrotationsfromtheleft(ae_bool isforward, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* c, - /* Real */ ae_vector* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t j; - ae_int_t jp1; - double ctemp; - double stemp; - double temp; - - - if( m1>m2||n1>n2 ) - { - return; - } - - /* - * Form P * A - */ - if( isforward ) - { - if( n1!=n2 ) - { - - /* - * Common case: N1<>N2 - */ - for(j=m1; j<=m2-1; j++) - { - ctemp = c->ptr.p_double[j-m1+1]; - stemp = s->ptr.p_double[j-m1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - jp1 = j+1; - ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); - ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); - ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); - ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); - ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); - } - } - } - else - { - - /* - * Special case: N1=N2 - */ - for(j=m1; j<=m2-1; j++) - { - ctemp = c->ptr.p_double[j-m1+1]; - stemp = s->ptr.p_double[j-m1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - temp = a->ptr.pp_double[j+1][n1]; - a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; - a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; - } - } - } - } - else - { - if( n1!=n2 ) - { - - /* - * Common case: N1<>N2 - */ - for(j=m2-1; j>=m1; j--) - { - ctemp = c->ptr.p_double[j-m1+1]; - stemp = s->ptr.p_double[j-m1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - jp1 = j+1; - ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); - ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); - ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); - ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); - ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); - } - } - } - else - { - - /* - * Special case: N1=N2 - */ - for(j=m2-1; j>=m1; j--) - { - ctemp = c->ptr.p_double[j-m1+1]; - stemp = s->ptr.p_double[j-m1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - temp = a->ptr.pp_double[j+1][n1]; - a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; - a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; - } - } - } - } -} - - -/************************************************************************* -Application of a sequence of elementary rotations to a matrix - -The algorithm post-multiplies the matrix by a sequence of rotation -transformations which is given by arrays C and S. Depending on the value -of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) -rows are rotated, or the rows N and N-1, N-2 and N-3 and so on are rotated. - -Not the whole matrix but only a part of it is transformed (rows from M1 -to M2, columns from N1 to N2). Only the elements of this submatrix are changed. - -Input parameters: - IsForward - the sequence of the rotation application. - M1,M2 - the range of rows to be transformed. - N1, N2 - the range of columns to be transformed. - C,S - transformation coefficients. - Array whose index ranges within [1..N2-N1]. - A - processed matrix. - WORK - working array whose index ranges within [M1..M2]. - -Output parameters: - A - transformed matrix. - -Utility subroutine. -*************************************************************************/ -void applyrotationsfromtheright(ae_bool isforward, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* c, - /* Real */ ae_vector* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t j; - ae_int_t jp1; - double ctemp; - double stemp; - double temp; - - - - /* - * Form A * P' - */ - if( isforward ) - { - if( m1!=m2 ) - { - - /* - * Common case: M1<>M2 - */ - for(j=n1; j<=n2-1; j++) - { - ctemp = c->ptr.p_double[j-n1+1]; - stemp = s->ptr.p_double[j-n1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - jp1 = j+1; - ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); - ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); - ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); - ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); - ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); - } - } - } - else - { - - /* - * Special case: M1=M2 - */ - for(j=n1; j<=n2-1; j++) - { - ctemp = c->ptr.p_double[j-n1+1]; - stemp = s->ptr.p_double[j-n1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - temp = a->ptr.pp_double[m1][j+1]; - a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; - a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; - } - } - } - } - else - { - if( m1!=m2 ) - { - - /* - * Common case: M1<>M2 - */ - for(j=n2-1; j>=n1; j--) - { - ctemp = c->ptr.p_double[j-n1+1]; - stemp = s->ptr.p_double[j-n1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - jp1 = j+1; - ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); - ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); - ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); - ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); - ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); - } - } - } - else - { - - /* - * Special case: M1=M2 - */ - for(j=n2-1; j>=n1; j--) - { - ctemp = c->ptr.p_double[j-n1+1]; - stemp = s->ptr.p_double[j-n1+1]; - if( ae_fp_neq(ctemp,1)||ae_fp_neq(stemp,0) ) - { - temp = a->ptr.pp_double[m1][j+1]; - a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; - a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; - } - } - } - } -} - - -/************************************************************************* -The subroutine generates the elementary rotation, so that: - -[ CS SN ] . [ F ] = [ R ] -[ -SN CS ] [ G ] [ 0 ] - -CS**2 + SN**2 = 1 -*************************************************************************/ -void generaterotation(double f, - double g, - double* cs, - double* sn, - double* r, - ae_state *_state) -{ - double f1; - double g1; - - *cs = 0; - *sn = 0; - *r = 0; - - if( ae_fp_eq(g,0) ) - { - *cs = 1; - *sn = 0; - *r = f; - } - else - { - if( ae_fp_eq(f,0) ) - { - *cs = 0; - *sn = 1; - *r = g; - } - else - { - f1 = f; - g1 = g; - if( ae_fp_greater(ae_fabs(f1, _state),ae_fabs(g1, _state)) ) - { - *r = ae_fabs(f1, _state)*ae_sqrt(1+ae_sqr(g1/f1, _state), _state); - } - else - { - *r = ae_fabs(g1, _state)*ae_sqrt(1+ae_sqr(f1/g1, _state), _state); - } - *cs = f1/(*r); - *sn = g1/(*r); - if( ae_fp_greater(ae_fabs(f, _state),ae_fabs(g, _state))&&ae_fp_less(*cs,0) ) - { - *cs = -*cs; - *sn = -*sn; - *r = -*r; - } - } - } -} - - - - -/************************************************************************* -Subroutine performing the Schur decomposition of a matrix in upper -Hessenberg form using the QR algorithm with multiple shifts. - -The source matrix H is represented as S'*H*S = T, where H - matrix in -upper Hessenberg form, S - orthogonal matrix (Schur vectors), T - upper -quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main -diagonal). - -Input parameters: - H - matrix to be decomposed. - Array whose indexes range within [1..N, 1..N]. - N - size of H, N>=0. - - -Output parameters: - H – contains the matrix T. - Array whose indexes range within [1..N, 1..N]. - All elements below the blocks on the main diagonal are equal - to 0. - S - contains Schur vectors. - Array whose indexes range within [1..N, 1..N]. - -Note 1: - The block structure of matrix T could be easily recognized: since all - the elements below the blocks are zeros, the elements a[i+1,i] which - are equal to 0 show the block border. - -Note 2: - the algorithm performance depends on the value of the internal - parameter NS of InternalSchurDecomposition subroutine which defines - the number of shifts in the QR algorithm (analog of the block width - in block matrix algorithms in linear algebra). If you require maximum - performance on your machine, it is recommended to adjust this - parameter manually. - -Result: - True, if the algorithm has converged and the parameters H and S contain - the result. - False, if the algorithm has not converged. - -Algorithm implemented on the basis of subroutine DHSEQR (LAPACK 3.0 library). -*************************************************************************/ -ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, - ae_int_t n, - /* Real */ ae_matrix* s, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector wi; - ae_vector wr; - ae_int_t info; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(s); - ae_vector_init(&wi, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wr, 0, DT_REAL, _state, ae_true); - - internalschurdecomposition(h, n, 1, 2, &wr, &wi, s, &info, _state); - result = info==0; - ae_frame_leave(_state); - return result; -} - - -void internalschurdecomposition(/* Real */ ae_matrix* h, - ae_int_t n, - ae_int_t tneeded, - ae_int_t zneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* z, - ae_int_t* info, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_int_t i; - ae_int_t i1; - ae_int_t i2; - ae_int_t ierr; - ae_int_t ii; - ae_int_t itemp; - ae_int_t itn; - ae_int_t its; - ae_int_t j; - ae_int_t k; - ae_int_t l; - ae_int_t maxb; - ae_int_t nr; - ae_int_t ns; - ae_int_t nv; - double absw; - double smlnum; - double tau; - double temp; - double tst1; - double ulp; - double unfl; - ae_matrix s; - ae_vector v; - ae_vector vv; - ae_vector workc1; - ae_vector works1; - ae_vector workv3; - ae_vector tmpwr; - ae_vector tmpwi; - ae_bool initz; - ae_bool wantt; - ae_bool wantz; - double cnst; - ae_bool failflag; - ae_int_t p1; - ae_int_t p2; - double vt; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(wr); - ae_vector_clear(wi); - *info = 0; - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&s, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&vv, 0, DT_REAL, _state, ae_true); - ae_vector_init(&workc1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&works1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&workv3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpwr, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpwi, 0, DT_REAL, _state, ae_true); - - - /* - * Set the order of the multi-shift QR algorithm to be used. - * If you want to tune algorithm, change this values - */ - ns = 12; - maxb = 50; - - /* - * Now 2 < NS <= MAXB < NH. - */ - maxb = ae_maxint(3, maxb, _state); - ns = ae_minint(maxb, ns, _state); - - /* - * Initialize - */ - cnst = 1.5; - ae_vector_set_length(&work, ae_maxint(n, 1, _state)+1, _state); - ae_matrix_set_length(&s, ns+1, ns+1, _state); - ae_vector_set_length(&v, ns+1+1, _state); - ae_vector_set_length(&vv, ns+1+1, _state); - ae_vector_set_length(wr, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(wi, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&workc1, 1+1, _state); - ae_vector_set_length(&works1, 1+1, _state); - ae_vector_set_length(&workv3, 3+1, _state); - ae_vector_set_length(&tmpwr, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&tmpwi, ae_maxint(n, 1, _state)+1, _state); - ae_assert(n>=0, "InternalSchurDecomposition: incorrect N!", _state); - ae_assert(tneeded==0||tneeded==1, "InternalSchurDecomposition: incorrect TNeeded!", _state); - ae_assert((zneeded==0||zneeded==1)||zneeded==2, "InternalSchurDecomposition: incorrect ZNeeded!", _state); - wantt = tneeded==1; - initz = zneeded==2; - wantz = zneeded!=0; - *info = 0; - - /* - * Initialize Z, if necessary - */ - if( initz ) - { - ae_matrix_set_length(z, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - for(j=1; j<=n; j++) - { - if( i==j ) - { - z->ptr.pp_double[i][j] = 1; - } - else - { - z->ptr.pp_double[i][j] = 0; - } - } - } - } - - /* - * Quick return if possible - */ - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - wr->ptr.p_double[1] = h->ptr.pp_double[1][1]; - wi->ptr.p_double[1] = 0; - ae_frame_leave(_state); - return; - } - - /* - * Set rows and columns 1 to N to zero below the first - * subdiagonal. - */ - for(j=1; j<=n-2; j++) - { - for(i=j+2; i<=n; i++) - { - h->ptr.pp_double[i][j] = 0; - } - } - - /* - * Test if N is sufficiently small - */ - if( (ns<=2||ns>n)||maxb>=n ) - { - - /* - * Use the standard double-shift algorithm - */ - hsschur_internalauxschur(wantt, wantz, n, 1, n, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); - - /* - * fill entries under diagonal blocks of T with zeros - */ - if( wantt ) - { - j = 1; - while(j<=n) - { - if( ae_fp_eq(wi->ptr.p_double[j],0) ) - { - for(i=j+1; i<=n; i++) - { - h->ptr.pp_double[i][j] = 0; - } - j = j+1; - } - else - { - for(i=j+2; i<=n; i++) - { - h->ptr.pp_double[i][j] = 0; - h->ptr.pp_double[i][j+1] = 0; - } - j = j+2; - } - } - } - ae_frame_leave(_state); - return; - } - unfl = ae_minrealnumber; - ulp = 2*ae_machineepsilon; - smlnum = unfl*(n/ulp); - - /* - * I1 and I2 are the indices of the first row and last column of H - * to which transformations must be applied. If eigenvalues only are - * being computed, I1 and I2 are set inside the main loop. - */ - i1 = 1; - i2 = n; - - /* - * ITN is the total number of multiple-shift QR iterations allowed. - */ - itn = 30*n; - - /* - * The main loop begins here. I is the loop index and decreases from - * IHI to ILO in steps of at most MAXB. Each iteration of the loop - * works with the active submatrix in rows and columns L to I. - * Eigenvalues I+1 to IHI have already converged. Either L = ILO or - * H(L,L-1) is negligible so that the matrix splits. - */ - i = n; - for(;;) - { - l = 1; - if( i<1 ) - { - - /* - * fill entries under diagonal blocks of T with zeros - */ - if( wantt ) - { - j = 1; - while(j<=n) - { - if( ae_fp_eq(wi->ptr.p_double[j],0) ) - { - for(i=j+1; i<=n; i++) - { - h->ptr.pp_double[i][j] = 0; - } - j = j+1; - } - else - { - for(i=j+2; i<=n; i++) - { - h->ptr.pp_double[i][j] = 0; - h->ptr.pp_double[i][j+1] = 0; - } - j = j+2; - } - } - } - - /* - * Exit - */ - ae_frame_leave(_state); - return; - } - - /* - * Perform multiple-shift QR iterations on rows and columns ILO to I - * until a submatrix of order at most MAXB splits off at the bottom - * because a subdiagonal element has become negligible. - */ - failflag = ae_true; - for(its=0; its<=itn; its++) - { - - /* - * Look for a single small subdiagonal element. - */ - for(k=i; k>=l+1; k--) - { - tst1 = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); - if( ae_fp_eq(tst1,0) ) - { - tst1 = upperhessenberg1norm(h, l, i, l, i, &work, _state); - } - if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ae_maxreal(ulp*tst1, smlnum, _state)) ) - { - break; - } - } - l = k; - if( l>1 ) - { - - /* - * H(L,L-1) is negligible. - */ - h->ptr.pp_double[l][l-1] = 0; - } - - /* - * Exit from loop if a submatrix of order <= MAXB has split off. - */ - if( l>=i-maxb+1 ) - { - failflag = ae_false; - break; - } - - /* - * Now the active submatrix is in rows and columns L to I. If - * eigenvalues only are being computed, only the active submatrix - * need be transformed. - */ - if( its==20||its==30 ) - { - - /* - * Exceptional shifts. - */ - for(ii=i-ns+1; ii<=i; ii++) - { - wr->ptr.p_double[ii] = cnst*(ae_fabs(h->ptr.pp_double[ii][ii-1], _state)+ae_fabs(h->ptr.pp_double[ii][ii], _state)); - wi->ptr.p_double[ii] = 0; - } - } - else - { - - /* - * Use eigenvalues of trailing submatrix of order NS as shifts. - */ - copymatrix(h, i-ns+1, i, i-ns+1, i, &s, 1, ns, 1, ns, _state); - hsschur_internalauxschur(ae_false, ae_false, ns, 1, ns, &s, &tmpwr, &tmpwi, 1, ns, z, &work, &workv3, &workc1, &works1, &ierr, _state); - for(p1=1; p1<=ns; p1++) - { - wr->ptr.p_double[i-ns+p1] = tmpwr.ptr.p_double[p1]; - wi->ptr.p_double[i-ns+p1] = tmpwi.ptr.p_double[p1]; - } - if( ierr>0 ) - { - - /* - * If DLAHQR failed to compute all NS eigenvalues, use the - * unconverged diagonal elements as the remaining shifts. - */ - for(ii=1; ii<=ierr; ii++) - { - wr->ptr.p_double[i-ns+ii] = s.ptr.pp_double[ii][ii]; - wi->ptr.p_double[i-ns+ii] = 0; - } - } - } - - /* - * Form the first column of (G-w(1)) (G-w(2)) . . . (G-w(ns)) - * where G is the Hessenberg submatrix H(L:I,L:I) and w is - * the vector of shifts (stored in WR and WI). The result is - * stored in the local array V. - */ - v.ptr.p_double[1] = 1; - for(ii=2; ii<=ns+1; ii++) - { - v.ptr.p_double[ii] = 0; - } - nv = 1; - for(j=i-ns+1; j<=i; j++) - { - if( ae_fp_greater_eq(wi->ptr.p_double[j],0) ) - { - if( ae_fp_eq(wi->ptr.p_double[j],0) ) - { - - /* - * real shift - */ - p1 = nv+1; - ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); - matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &vv, 1, nv, 1.0, &v, 1, nv+1, -wr->ptr.p_double[j], _state); - nv = nv+1; - } - else - { - if( ae_fp_greater(wi->ptr.p_double[j],0) ) - { - - /* - * complex conjugate pair of shifts - */ - p1 = nv+1; - ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); - matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &v, 1, nv, 1.0, &vv, 1, nv+1, -2*wr->ptr.p_double[j], _state); - itemp = vectoridxabsmax(&vv, 1, nv+1, _state); - temp = 1/ae_maxreal(ae_fabs(vv.ptr.p_double[itemp], _state), smlnum, _state); - p1 = nv+1; - ae_v_muld(&vv.ptr.p_double[1], 1, ae_v_len(1,p1), temp); - absw = pythag2(wr->ptr.p_double[j], wi->ptr.p_double[j], _state); - temp = temp*absw*absw; - matrixvectormultiply(h, l, l+nv+1, l, l+nv, ae_false, &vv, 1, nv+1, 1.0, &v, 1, nv+2, temp, _state); - nv = nv+2; - } - } - - /* - * Scale V(1:NV) so that max(abs(V(i))) = 1. If V is zero, - * reset it to the unit vector. - */ - itemp = vectoridxabsmax(&v, 1, nv, _state); - temp = ae_fabs(v.ptr.p_double[itemp], _state); - if( ae_fp_eq(temp,0) ) - { - v.ptr.p_double[1] = 1; - for(ii=2; ii<=nv; ii++) - { - v.ptr.p_double[ii] = 0; - } - } - else - { - temp = ae_maxreal(temp, smlnum, _state); - vt = 1/temp; - ae_v_muld(&v.ptr.p_double[1], 1, ae_v_len(1,nv), vt); - } - } - } - - /* - * Multiple-shift QR step - */ - for(k=l; k<=i-1; k++) - { - - /* - * The first iteration of this loop determines a reflection G - * from the vector V and applies it from left and right to H, - * thus creating a nonzero bulge below the subdiagonal. - * - * Each subsequent iteration determines a reflection G to - * restore the Hessenberg form in the (K-1)th column, and thus - * chases the bulge one step toward the bottom of the active - * submatrix. NR is the order of G. - */ - nr = ae_minint(ns+1, i-k+1, _state); - if( k>l ) - { - p1 = k-1; - p2 = k+nr-1; - ae_v_move(&v.ptr.p_double[1], 1, &h->ptr.pp_double[k][p1], h->stride, ae_v_len(1,nr)); - touchint(&p2, _state); - } - generatereflection(&v, nr, &tau, _state); - if( k>l ) - { - h->ptr.pp_double[k][k-1] = v.ptr.p_double[1]; - for(ii=k+1; ii<=i; ii++) - { - h->ptr.pp_double[ii][k-1] = 0; - } - } - v.ptr.p_double[1] = 1; - - /* - * Apply G from the left to transform the rows of the matrix in - * columns K to I2. - */ - applyreflectionfromtheleft(h, tau, &v, k, k+nr-1, k, i2, &work, _state); - - /* - * Apply G from the right to transform the columns of the - * matrix in rows I1 to min(K+NR,I). - */ - applyreflectionfromtheright(h, tau, &v, i1, ae_minint(k+nr, i, _state), k, k+nr-1, &work, _state); - if( wantz ) - { - - /* - * Accumulate transformations in the matrix Z - */ - applyreflectionfromtheright(z, tau, &v, 1, n, k, k+nr-1, &work, _state); - } - } - } - - /* - * Failure to converge in remaining number of iterations - */ - if( failflag ) - { - *info = i; - ae_frame_leave(_state); - return; - } - - /* - * A submatrix of order <= MAXB in rows and columns L to I has split - * off. Use the double-shift QR algorithm to handle it. - */ - hsschur_internalauxschur(wantt, wantz, n, l, i, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); - if( *info>0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Decrement number of remaining iterations, and return to start of - * the main loop with a new value of I. - */ - itn = itn-its; - i = l-1; - } - ae_frame_leave(_state); -} - - -static void hsschur_internalauxschur(ae_bool wantt, - ae_bool wantz, - ae_int_t n, - ae_int_t ilo, - ae_int_t ihi, - /* Real */ ae_matrix* h, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - ae_int_t iloz, - ae_int_t ihiz, - /* Real */ ae_matrix* z, - /* Real */ ae_vector* work, - /* Real */ ae_vector* workv3, - /* Real */ ae_vector* workc1, - /* Real */ ae_vector* works1, - ae_int_t* info, - ae_state *_state) -{ - ae_int_t i; - ae_int_t i1; - ae_int_t i2; - ae_int_t itn; - ae_int_t its; - ae_int_t j; - ae_int_t k; - ae_int_t l; - ae_int_t m; - ae_int_t nh; - ae_int_t nr; - ae_int_t nz; - double ave; - double cs; - double disc; - double h00; - double h10; - double h11; - double h12; - double h21; - double h22; - double h33; - double h33s; - double h43h34; - double h44; - double h44s; - double s; - double smlnum; - double sn; - double sum; - double t1; - double t2; - double t3; - double tst1; - double unfl; - double v1; - double v2; - double v3; - ae_bool failflag; - double dat1; - double dat2; - ae_int_t p1; - double him1im1; - double him1i; - double hiim1; - double hii; - double wrim1; - double wri; - double wiim1; - double wii; - double ulp; - - *info = 0; - - *info = 0; - dat1 = 0.75; - dat2 = -0.4375; - ulp = ae_machineepsilon; - - /* - * Quick return if possible - */ - if( n==0 ) - { - return; - } - if( ilo==ihi ) - { - wr->ptr.p_double[ilo] = h->ptr.pp_double[ilo][ilo]; - wi->ptr.p_double[ilo] = 0; - return; - } - nh = ihi-ilo+1; - nz = ihiz-iloz+1; - - /* - * Set machine-dependent constants for the stopping criterion. - * If norm(H) <= sqrt(MaxRealNumber), overflow should not occur. - */ - unfl = ae_minrealnumber; - smlnum = unfl*(nh/ulp); - - /* - * I1 and I2 are the indices of the first row and last column of H - * to which transformations must be applied. If eigenvalues only are - * being computed, I1 and I2 are set inside the main loop. - */ - i1 = 1; - i2 = n; - - /* - * ITN is the total number of QR iterations allowed. - */ - itn = 30*nh; - - /* - * The main loop begins here. I is the loop index and decreases from - * IHI to ILO in steps of 1 or 2. Each iteration of the loop works - * with the active submatrix in rows and columns L to I. - * Eigenvalues I+1 to IHI have already converged. Either L = ILO or - * H(L,L-1) is negligible so that the matrix splits. - */ - i = ihi; - for(;;) - { - l = ilo; - if( i=l+1; k--) - { - tst1 = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); - if( ae_fp_eq(tst1,0) ) - { - tst1 = upperhessenberg1norm(h, l, i, l, i, work, _state); - } - if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ae_maxreal(ulp*tst1, smlnum, _state)) ) - { - break; - } - } - l = k; - if( l>ilo ) - { - - /* - * H(L,L-1) is negligible - */ - h->ptr.pp_double[l][l-1] = 0; - } - - /* - * Exit from loop if a submatrix of order 1 or 2 has split off. - */ - if( l>=i-1 ) - { - failflag = ae_false; - break; - } - - /* - * Now the active submatrix is in rows and columns L to I. If - * eigenvalues only are being computed, only the active submatrix - * need be transformed. - */ - if( its==10||its==20 ) - { - - /* - * Exceptional shift. - */ - s = ae_fabs(h->ptr.pp_double[i][i-1], _state)+ae_fabs(h->ptr.pp_double[i-1][i-2], _state); - h44 = dat1*s+h->ptr.pp_double[i][i]; - h33 = h44; - h43h34 = dat2*s*s; - } - else - { - - /* - * Prepare to use Francis' double shift - * (i.e. 2nd degree generalized Rayleigh quotient) - */ - h44 = h->ptr.pp_double[i][i]; - h33 = h->ptr.pp_double[i-1][i-1]; - h43h34 = h->ptr.pp_double[i][i-1]*h->ptr.pp_double[i-1][i]; - s = h->ptr.pp_double[i-1][i-2]*h->ptr.pp_double[i-1][i-2]; - disc = (h33-h44)*0.5; - disc = disc*disc+h43h34; - if( ae_fp_greater(disc,0) ) - { - - /* - * Real roots: use Wilkinson's shift twice - */ - disc = ae_sqrt(disc, _state); - ave = 0.5*(h33+h44); - if( ae_fp_greater(ae_fabs(h33, _state)-ae_fabs(h44, _state),0) ) - { - h33 = h33*h44-h43h34; - h44 = h33/(hsschur_extschursign(disc, ave, _state)+ave); - } - else - { - h44 = hsschur_extschursign(disc, ave, _state)+ave; - } - h33 = h44; - h43h34 = 0; - } - } - - /* - * Look for two consecutive small subdiagonal elements. - */ - for(m=i-2; m>=l; m--) - { - - /* - * Determine the effect of starting the double-shift QR - * iteration at row M, and see if this would make H(M,M-1) - * negligible. - */ - h11 = h->ptr.pp_double[m][m]; - h22 = h->ptr.pp_double[m+1][m+1]; - h21 = h->ptr.pp_double[m+1][m]; - h12 = h->ptr.pp_double[m][m+1]; - h44s = h44-h11; - h33s = h33-h11; - v1 = (h33s*h44s-h43h34)/h21+h12; - v2 = h22-h11-h33s-h44s; - v3 = h->ptr.pp_double[m+2][m+1]; - s = ae_fabs(v1, _state)+ae_fabs(v2, _state)+ae_fabs(v3, _state); - v1 = v1/s; - v2 = v2/s; - v3 = v3/s; - workv3->ptr.p_double[1] = v1; - workv3->ptr.p_double[2] = v2; - workv3->ptr.p_double[3] = v3; - if( m==l ) - { - break; - } - h00 = h->ptr.pp_double[m-1][m-1]; - h10 = h->ptr.pp_double[m][m-1]; - tst1 = ae_fabs(v1, _state)*(ae_fabs(h00, _state)+ae_fabs(h11, _state)+ae_fabs(h22, _state)); - if( ae_fp_less_eq(ae_fabs(h10, _state)*(ae_fabs(v2, _state)+ae_fabs(v3, _state)),ulp*tst1) ) - { - break; - } - } - - /* - * Double-shift QR step - */ - for(k=m; k<=i-1; k++) - { - - /* - * The first iteration of this loop determines a reflection G - * from the vector V and applies it from left and right to H, - * thus creating a nonzero bulge below the subdiagonal. - * - * Each subsequent iteration determines a reflection G to - * restore the Hessenberg form in the (K-1)th column, and thus - * chases the bulge one step toward the bottom of the active - * submatrix. NR is the order of G. - */ - nr = ae_minint(3, i-k+1, _state); - if( k>m ) - { - for(p1=1; p1<=nr; p1++) - { - workv3->ptr.p_double[p1] = h->ptr.pp_double[k+p1-1][k-1]; - } - } - generatereflection(workv3, nr, &t1, _state); - if( k>m ) - { - h->ptr.pp_double[k][k-1] = workv3->ptr.p_double[1]; - h->ptr.pp_double[k+1][k-1] = 0; - if( kptr.pp_double[k+2][k-1] = 0; - } - } - else - { - if( m>l ) - { - h->ptr.pp_double[k][k-1] = -h->ptr.pp_double[k][k-1]; - } - } - v2 = workv3->ptr.p_double[2]; - t2 = t1*v2; - if( nr==3 ) - { - v3 = workv3->ptr.p_double[3]; - t3 = t1*v3; - - /* - * Apply G from the left to transform the rows of the matrix - * in columns K to I2. - */ - for(j=k; j<=i2; j++) - { - sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]+v3*h->ptr.pp_double[k+2][j]; - h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; - h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; - h->ptr.pp_double[k+2][j] = h->ptr.pp_double[k+2][j]-sum*t3; - } - - /* - * Apply G from the right to transform the columns of the - * matrix in rows I1 to min(K+3,I). - */ - for(j=i1; j<=ae_minint(k+3, i, _state); j++) - { - sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]+v3*h->ptr.pp_double[j][k+2]; - h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; - h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; - h->ptr.pp_double[j][k+2] = h->ptr.pp_double[j][k+2]-sum*t3; - } - if( wantz ) - { - - /* - * Accumulate transformations in the matrix Z - */ - for(j=iloz; j<=ihiz; j++) - { - sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]+v3*z->ptr.pp_double[j][k+2]; - z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; - z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; - z->ptr.pp_double[j][k+2] = z->ptr.pp_double[j][k+2]-sum*t3; - } - } - } - else - { - if( nr==2 ) - { - - /* - * Apply G from the left to transform the rows of the matrix - * in columns K to I2. - */ - for(j=k; j<=i2; j++) - { - sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]; - h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; - h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; - } - - /* - * Apply G from the right to transform the columns of the - * matrix in rows I1 to min(K+3,I). - */ - for(j=i1; j<=i; j++) - { - sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]; - h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; - h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; - } - if( wantz ) - { - - /* - * Accumulate transformations in the matrix Z - */ - for(j=iloz; j<=ihiz; j++) - { - sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]; - z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; - z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; - } - } - } - } - } - } - if( failflag ) - { - - /* - * Failure to converge in remaining number of iterations - */ - *info = i; - return; - } - if( l==i ) - { - - /* - * H(I,I-1) is negligible: one eigenvalue has converged. - */ - wr->ptr.p_double[i] = h->ptr.pp_double[i][i]; - wi->ptr.p_double[i] = 0; - } - else - { - if( l==i-1 ) - { - - /* - * H(I-1,I-2) is negligible: a pair of eigenvalues have converged. - * - * Transform the 2-by-2 submatrix to standard Schur form, - * and compute and store the eigenvalues. - */ - him1im1 = h->ptr.pp_double[i-1][i-1]; - him1i = h->ptr.pp_double[i-1][i]; - hiim1 = h->ptr.pp_double[i][i-1]; - hii = h->ptr.pp_double[i][i]; - hsschur_aux2x2schur(&him1im1, &him1i, &hiim1, &hii, &wrim1, &wiim1, &wri, &wii, &cs, &sn, _state); - wr->ptr.p_double[i-1] = wrim1; - wi->ptr.p_double[i-1] = wiim1; - wr->ptr.p_double[i] = wri; - wi->ptr.p_double[i] = wii; - h->ptr.pp_double[i-1][i-1] = him1im1; - h->ptr.pp_double[i-1][i] = him1i; - h->ptr.pp_double[i][i-1] = hiim1; - h->ptr.pp_double[i][i] = hii; - if( wantt ) - { - - /* - * Apply the transformation to the rest of H. - */ - if( i2>i ) - { - workc1->ptr.p_double[1] = cs; - works1->ptr.p_double[1] = sn; - applyrotationsfromtheleft(ae_true, i-1, i, i+1, i2, workc1, works1, h, work, _state); - } - workc1->ptr.p_double[1] = cs; - works1->ptr.p_double[1] = sn; - applyrotationsfromtheright(ae_true, i1, i-2, i-1, i, workc1, works1, h, work, _state); - } - if( wantz ) - { - - /* - * Apply the transformation to Z. - */ - workc1->ptr.p_double[1] = cs; - works1->ptr.p_double[1] = sn; - applyrotationsfromtheright(ae_true, iloz, iloz+nz-1, i-1, i, workc1, works1, z, work, _state); - } - } - } - - /* - * Decrement number of remaining iterations, and return to start of - * the main loop with new value of I. - */ - itn = itn-its; - i = l-1; - } -} - - -static void hsschur_aux2x2schur(double* a, - double* b, - double* c, - double* d, - double* rt1r, - double* rt1i, - double* rt2r, - double* rt2i, - double* cs, - double* sn, - ae_state *_state) -{ - double multpl; - double aa; - double bb; - double bcmax; - double bcmis; - double cc; - double cs1; - double dd; - double eps; - double p; - double sab; - double sac; - double scl; - double sigma; - double sn1; - double tau; - double temp; - double z; - - *rt1r = 0; - *rt1i = 0; - *rt2r = 0; - *rt2i = 0; - *cs = 0; - *sn = 0; - - multpl = 4.0; - eps = ae_machineepsilon; - if( ae_fp_eq(*c,0) ) - { - *cs = 1; - *sn = 0; - } - else - { - if( ae_fp_eq(*b,0) ) - { - - /* - * Swap rows and columns - */ - *cs = 0; - *sn = 1; - temp = *d; - *d = *a; - *a = temp; - *b = -*c; - *c = 0; - } - else - { - if( ae_fp_eq(*a-(*d),0)&&hsschur_extschursigntoone(*b, _state)!=hsschur_extschursigntoone(*c, _state) ) - { - *cs = 1; - *sn = 0; - } - else - { - temp = *a-(*d); - p = 0.5*temp; - bcmax = ae_maxreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state); - bcmis = ae_minreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state)*hsschur_extschursigntoone(*b, _state)*hsschur_extschursigntoone(*c, _state); - scl = ae_maxreal(ae_fabs(p, _state), bcmax, _state); - z = p/scl*p+bcmax/scl*bcmis; - - /* - * If Z is of the order of the machine accuracy, postpone the - * decision on the nature of eigenvalues - */ - if( ae_fp_greater_eq(z,multpl*eps) ) - { - - /* - * Real eigenvalues. Compute A and D. - */ - z = p+hsschur_extschursign(ae_sqrt(scl, _state)*ae_sqrt(z, _state), p, _state); - *a = *d+z; - *d = *d-bcmax/z*bcmis; - - /* - * Compute B and the rotation matrix - */ - tau = pythag2(*c, z, _state); - *cs = z/tau; - *sn = *c/tau; - *b = *b-(*c); - *c = 0; - } - else - { - - /* - * Complex eigenvalues, or real (almost) equal eigenvalues. - * Make diagonal elements equal. - */ - sigma = *b+(*c); - tau = pythag2(sigma, temp, _state); - *cs = ae_sqrt(0.5*(1+ae_fabs(sigma, _state)/tau), _state); - *sn = -p/(tau*(*cs))*hsschur_extschursign(1, sigma, _state); - - /* - * Compute [ AA BB ] = [ A B ] [ CS -SN ] - * [ CC DD ] [ C D ] [ SN CS ] - */ - aa = *a*(*cs)+*b*(*sn); - bb = -*a*(*sn)+*b*(*cs); - cc = *c*(*cs)+*d*(*sn); - dd = -*c*(*sn)+*d*(*cs); - - /* - * Compute [ A B ] = [ CS SN ] [ AA BB ] - * [ C D ] [-SN CS ] [ CC DD ] - */ - *a = aa*(*cs)+cc*(*sn); - *b = bb*(*cs)+dd*(*sn); - *c = -aa*(*sn)+cc*(*cs); - *d = -bb*(*sn)+dd*(*cs); - temp = 0.5*(*a+(*d)); - *a = temp; - *d = temp; - if( ae_fp_neq(*c,0) ) - { - if( ae_fp_neq(*b,0) ) - { - if( hsschur_extschursigntoone(*b, _state)==hsschur_extschursigntoone(*c, _state) ) - { - - /* - * Real eigenvalues: reduce to upper triangular form - */ - sab = ae_sqrt(ae_fabs(*b, _state), _state); - sac = ae_sqrt(ae_fabs(*c, _state), _state); - p = hsschur_extschursign(sab*sac, *c, _state); - tau = 1/ae_sqrt(ae_fabs(*b+(*c), _state), _state); - *a = temp+p; - *d = temp-p; - *b = *b-(*c); - *c = 0; - cs1 = sab*tau; - sn1 = sac*tau; - temp = *cs*cs1-*sn*sn1; - *sn = *cs*sn1+*sn*cs1; - *cs = temp; - } - } - else - { - *b = -*c; - *c = 0; - temp = *cs; - *cs = -*sn; - *sn = temp; - } - } - } - } - } - } - - /* - * Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). - */ - *rt1r = *a; - *rt2r = *d; - if( ae_fp_eq(*c,0) ) - { - *rt1i = 0; - *rt2i = 0; - } - else - { - *rt1i = ae_sqrt(ae_fabs(*b, _state), _state)*ae_sqrt(ae_fabs(*c, _state), _state); - *rt2i = -*rt1i; - } -} - - -static double hsschur_extschursign(double a, double b, ae_state *_state) -{ - double result; - - - if( ae_fp_greater_eq(b,0) ) - { - result = ae_fabs(a, _state); - } - else - { - result = -ae_fabs(a, _state); - } - return result; -} - - -static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state) -{ - ae_int_t result; - - - if( ae_fp_greater_eq(b,0) ) - { - result = 1; - } - else - { - result = -1; - } - return result; -} - - - - -/************************************************************************* -Utility subroutine performing the "safe" solution of system of linear -equations with triangular coefficient matrices. - -The subroutine uses scaling and solves the scaled system A*x=s*b (where s -is a scalar value) instead of A*x=b, choosing s so that x can be -represented by a floating-point number. The closer the system gets to a -singular, the less s is. If the system is singular, s=0 and x contains the -non-trivial solution of equation A*x=0. - -The feature of an algorithm is that it could not cause an overflow or a -division by zero regardless of the matrix used as the input. - -The algorithm can solve systems of equations with upper/lower triangular -matrices, with/without unit diagonal, and systems of type A*x=b or A'*x=b -(where A' is a transposed matrix A). - -Input parameters: - A - system matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - X - right-hand member of a system. - Array whose index ranges within [0..N-1]. - IsUpper - matrix type. If it is True, the system matrix is the upper - triangular and is located in the corresponding part of - matrix A. - Trans - problem type. If it is True, the problem to be solved is - A'*x=b, otherwise it is A*x=b. - Isunit - matrix type. If it is True, the system matrix has a unit - diagonal (the elements on the main diagonal are not used - in the calculation process), otherwise the matrix is considered - to be a general triangular matrix. - -Output parameters: - X - solution. Array whose index ranges within [0..N-1]. - S - scaling factor. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - June 30, 1992 -*************************************************************************/ -void rmatrixtrsafesolve(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* x, - double* s, - ae_bool isupper, - ae_bool istrans, - ae_bool isunit, - ae_state *_state) -{ - ae_frame _frame_block; - ae_bool normin; - ae_vector cnorm; - ae_matrix a1; - ae_vector x1; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *s = 0; - ae_vector_init(&cnorm, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a1, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x1, 0, DT_REAL, _state, ae_true); - - - /* - * From 0-based to 1-based - */ - normin = ae_false; - ae_matrix_set_length(&a1, n+1, n+1, _state); - ae_vector_set_length(&x1, n+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&a1.ptr.pp_double[i][1], 1, &a->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); - } - ae_v_move(&x1.ptr.p_double[1], 1, &x->ptr.p_double[0], 1, ae_v_len(1,n)); - - /* - * Solve 1-based - */ - safesolvetriangular(&a1, n, &x1, s, isupper, istrans, isunit, normin, &cnorm, _state); - - /* - * From 1-based to 0-based - */ - ae_v_move(&x->ptr.p_double[0], 1, &x1.ptr.p_double[1], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Obsolete 1-based subroutine. -See RMatrixTRSafeSolve for 0-based replacement. -*************************************************************************/ -void safesolvetriangular(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* x, - double* s, - ae_bool isupper, - ae_bool istrans, - ae_bool isunit, - ae_bool normin, - /* Real */ ae_vector* cnorm, - ae_state *_state) -{ - ae_int_t i; - ae_int_t imax; - ae_int_t j; - ae_int_t jfirst; - ae_int_t jinc; - ae_int_t jlast; - ae_int_t jm1; - ae_int_t jp1; - ae_int_t ip1; - ae_int_t im1; - ae_int_t k; - ae_int_t flg; - double v; - double vd; - double bignum; - double grow; - double rec; - double smlnum; - double sumj; - double tjj; - double tjjs; - double tmax; - double tscal; - double uscal; - double xbnd; - double xj; - double xmax; - ae_bool notran; - ae_bool upper; - ae_bool nounit; - - *s = 0; - - upper = isupper; - notran = !istrans; - nounit = !isunit; - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - tjjs = 0; - - /* - * Quick return if possible - */ - if( n==0 ) - { - return; - } - - /* - * Determine machine dependent parameters to control overflow. - */ - smlnum = ae_minrealnumber/(ae_machineepsilon*2); - bignum = 1/smlnum; - *s = 1; - if( !normin ) - { - ae_vector_set_length(cnorm, n+1, _state); - - /* - * Compute the 1-norm of each column, not including the diagonal. - */ - if( upper ) - { - - /* - * A is upper triangular. - */ - for(j=1; j<=n; j++) - { - v = 0; - for(k=1; k<=j-1; k++) - { - v = v+ae_fabs(a->ptr.pp_double[k][j], _state); - } - cnorm->ptr.p_double[j] = v; - } - } - else - { - - /* - * A is lower triangular. - */ - for(j=1; j<=n-1; j++) - { - v = 0; - for(k=j+1; k<=n; k++) - { - v = v+ae_fabs(a->ptr.pp_double[k][j], _state); - } - cnorm->ptr.p_double[j] = v; - } - cnorm->ptr.p_double[n] = 0; - } - } - - /* - * Scale the column norms by TSCAL if the maximum element in CNORM is - * greater than BIGNUM. - */ - imax = 1; - for(k=2; k<=n; k++) - { - if( ae_fp_greater(cnorm->ptr.p_double[k],cnorm->ptr.p_double[imax]) ) - { - imax = k; - } - } - tmax = cnorm->ptr.p_double[imax]; - if( ae_fp_less_eq(tmax,bignum) ) - { - tscal = 1; - } - else - { - tscal = 1/(smlnum*tmax); - ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), tscal); - } - - /* - * Compute a bound on the computed solution vector to see if the - * Level 2 BLAS routine DTRSV can be used. - */ - j = 1; - for(k=2; k<=n; k++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[j], _state)) ) - { - j = k; - } - } - xmax = ae_fabs(x->ptr.p_double[j], _state); - xbnd = xmax; - if( notran ) - { - - /* - * Compute the growth in A * x = b. - */ - if( upper ) - { - jfirst = n; - jlast = 1; - jinc = -1; - } - else - { - jfirst = 1; - jlast = n; - jinc = 1; - } - if( ae_fp_neq(tscal,1) ) - { - grow = 0; - } - else - { - if( nounit ) - { - - /* - * A is non-unit triangular. - * - * Compute GROW = 1/G(j) and XBND = 1/M(j). - * Initially, G(0) = max{x(i), i=1,...,n}. - */ - grow = 1/ae_maxreal(xbnd, smlnum, _state); - xbnd = grow; - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Exit the loop if the growth factor is too small. - */ - if( ae_fp_less_eq(grow,smlnum) ) - { - break; - } - - /* - * M(j) = G(j-1) / abs(A(j,j)) - */ - tjj = ae_fabs(a->ptr.pp_double[j][j], _state); - xbnd = ae_minreal(xbnd, ae_minreal(1, tjj, _state)*grow, _state); - if( ae_fp_greater_eq(tjj+cnorm->ptr.p_double[j],smlnum) ) - { - - /* - * G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) - */ - grow = grow*(tjj/(tjj+cnorm->ptr.p_double[j])); - } - else - { - - /* - * G(j) could overflow, set GROW to 0. - */ - grow = 0; - } - if( j==jlast ) - { - grow = xbnd; - } - j = j+jinc; - } - } - else - { - - /* - * A is unit triangular. - * - * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. - */ - grow = ae_minreal(1, 1/ae_maxreal(xbnd, smlnum, _state), _state); - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Exit the loop if the growth factor is too small. - */ - if( ae_fp_less_eq(grow,smlnum) ) - { - break; - } - - /* - * G(j) = G(j-1)*( 1 + CNORM(j) ) - */ - grow = grow*(1/(1+cnorm->ptr.p_double[j])); - j = j+jinc; - } - } - } - } - else - { - - /* - * Compute the growth in A' * x = b. - */ - if( upper ) - { - jfirst = 1; - jlast = n; - jinc = 1; - } - else - { - jfirst = n; - jlast = 1; - jinc = -1; - } - if( ae_fp_neq(tscal,1) ) - { - grow = 0; - } - else - { - if( nounit ) - { - - /* - * A is non-unit triangular. - * - * Compute GROW = 1/G(j) and XBND = 1/M(j). - * Initially, M(0) = max{x(i), i=1,...,n}. - */ - grow = 1/ae_maxreal(xbnd, smlnum, _state); - xbnd = grow; - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Exit the loop if the growth factor is too small. - */ - if( ae_fp_less_eq(grow,smlnum) ) - { - break; - } - - /* - * G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) - */ - xj = 1+cnorm->ptr.p_double[j]; - grow = ae_minreal(grow, xbnd/xj, _state); - - /* - * M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) - */ - tjj = ae_fabs(a->ptr.pp_double[j][j], _state); - if( ae_fp_greater(xj,tjj) ) - { - xbnd = xbnd*(tjj/xj); - } - if( j==jlast ) - { - grow = ae_minreal(grow, xbnd, _state); - } - j = j+jinc; - } - } - else - { - - /* - * A is unit triangular. - * - * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. - */ - grow = ae_minreal(1, 1/ae_maxreal(xbnd, smlnum, _state), _state); - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Exit the loop if the growth factor is too small. - */ - if( ae_fp_less_eq(grow,smlnum) ) - { - break; - } - - /* - * G(j) = ( 1 + CNORM(j) )*G(j-1) - */ - xj = 1+cnorm->ptr.p_double[j]; - grow = grow/xj; - j = j+jinc; - } - } - } - } - if( ae_fp_greater(grow*tscal,smlnum) ) - { - - /* - * Use the Level 2 BLAS solve if the reciprocal of the bound on - * elements of X is not too small. - */ - if( (upper&¬ran)||(!upper&&!notran) ) - { - if( nounit ) - { - vd = a->ptr.pp_double[n][n]; - } - else - { - vd = 1; - } - x->ptr.p_double[n] = x->ptr.p_double[n]/vd; - for(i=n-1; i>=1; i--) - { - ip1 = i+1; - if( upper ) - { - v = ae_v_dotproduct(&a->ptr.pp_double[i][ip1], 1, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); - } - else - { - v = ae_v_dotproduct(&a->ptr.pp_double[ip1][i], a->stride, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); - } - if( nounit ) - { - vd = a->ptr.pp_double[i][i]; - } - else - { - vd = 1; - } - x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; - } - } - else - { - if( nounit ) - { - vd = a->ptr.pp_double[1][1]; - } - else - { - vd = 1; - } - x->ptr.p_double[1] = x->ptr.p_double[1]/vd; - for(i=2; i<=n; i++) - { - im1 = i-1; - if( upper ) - { - v = ae_v_dotproduct(&a->ptr.pp_double[1][i], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); - } - else - { - v = ae_v_dotproduct(&a->ptr.pp_double[i][1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); - } - if( nounit ) - { - vd = a->ptr.pp_double[i][i]; - } - else - { - vd = 1; - } - x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; - } - } - } - else - { - - /* - * Use a Level 1 BLAS solve, scaling intermediate results. - */ - if( ae_fp_greater(xmax,bignum) ) - { - - /* - * Scale X so that its components are less than or equal to - * BIGNUM in absolute value. - */ - *s = bignum/xmax; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), *s); - xmax = bignum; - } - if( notran ) - { - - /* - * Solve A * x = b - */ - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Compute x(j) = b(j) / A(j,j), scaling x if necessary. - */ - xj = ae_fabs(x->ptr.p_double[j], _state); - flg = 0; - if( nounit ) - { - tjjs = a->ptr.pp_double[j][j]*tscal; - } - else - { - tjjs = tscal; - if( ae_fp_eq(tscal,1) ) - { - flg = 100; - } - } - if( flg!=100 ) - { - tjj = ae_fabs(tjjs, _state); - if( ae_fp_greater(tjj,smlnum) ) - { - - /* - * abs(A(j,j)) > SMLNUM: - */ - if( ae_fp_less(tjj,1) ) - { - if( ae_fp_greater(xj,tjj*bignum) ) - { - - /* - * Scale x by 1/b(j). - */ - rec = 1/xj; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - xmax = xmax*rec; - } - } - x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; - xj = ae_fabs(x->ptr.p_double[j], _state); - } - else - { - if( ae_fp_greater(tjj,0) ) - { - - /* - * 0 < abs(A(j,j)) <= SMLNUM: - */ - if( ae_fp_greater(xj,tjj*bignum) ) - { - - /* - * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM - * to avoid overflow when dividing by A(j,j). - */ - rec = tjj*bignum/xj; - if( ae_fp_greater(cnorm->ptr.p_double[j],1) ) - { - - /* - * Scale by 1/CNORM(j) to avoid overflow when - * multiplying x(j) times column j. - */ - rec = rec/cnorm->ptr.p_double[j]; - } - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - xmax = xmax*rec; - } - x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; - xj = ae_fabs(x->ptr.p_double[j], _state); - } - else - { - - /* - * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and - * scale = 0, and compute a solution to A*x = 0. - */ - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = 0; - } - x->ptr.p_double[j] = 1; - xj = 1; - *s = 0; - xmax = 0; - } - } - } - - /* - * Scale x if necessary to avoid overflow when adding a - * multiple of column j of A. - */ - if( ae_fp_greater(xj,1) ) - { - rec = 1/xj; - if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xmax)*rec) ) - { - - /* - * Scale x by 1/(2*abs(x(j))). - */ - rec = rec*0.5; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - } - } - else - { - if( ae_fp_greater(xj*cnorm->ptr.p_double[j],bignum-xmax) ) - { - - /* - * Scale x by 1/2. - */ - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), 0.5); - *s = *s*0.5; - } - } - if( upper ) - { - if( j>1 ) - { - - /* - * Compute the update - * x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) - */ - v = x->ptr.p_double[j]*tscal; - jm1 = j-1; - ae_v_subd(&x->ptr.p_double[1], 1, &a->ptr.pp_double[1][j], a->stride, ae_v_len(1,jm1), v); - i = 1; - for(k=2; k<=j-1; k++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) - { - i = k; - } - } - xmax = ae_fabs(x->ptr.p_double[i], _state); - } - } - else - { - if( jptr.p_double[j]*tscal; - ae_v_subd(&x->ptr.p_double[jp1], 1, &a->ptr.pp_double[jp1][j], a->stride, ae_v_len(jp1,n), v); - i = j+1; - for(k=j+2; k<=n; k++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) - { - i = k; - } - } - xmax = ae_fabs(x->ptr.p_double[i], _state); - } - } - j = j+jinc; - } - } - else - { - - /* - * Solve A' * x = b - */ - j = jfirst; - while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) - { - - /* - * Compute x(j) = b(j) - sum A(k,j)*x(k). - * k<>j - */ - xj = ae_fabs(x->ptr.p_double[j], _state); - uscal = tscal; - rec = 1/ae_maxreal(xmax, 1, _state); - if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xj)*rec) ) - { - - /* - * If x(j) could overflow, scale x by 1/(2*XMAX). - */ - rec = rec*0.5; - if( nounit ) - { - tjjs = a->ptr.pp_double[j][j]*tscal; - } - else - { - tjjs = tscal; - } - tjj = ae_fabs(tjjs, _state); - if( ae_fp_greater(tjj,1) ) - { - - /* - * Divide by A(j,j) when scaling x if A(j,j) > 1. - */ - rec = ae_minreal(1, rec*tjj, _state); - uscal = uscal/tjjs; - } - if( ae_fp_less(rec,1) ) - { - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - xmax = xmax*rec; - } - } - sumj = 0; - if( ae_fp_eq(uscal,1) ) - { - - /* - * If the scaling needed for A in the dot product is 1, - * call DDOT to perform the dot product. - */ - if( upper ) - { - if( j>1 ) - { - jm1 = j-1; - sumj = ae_v_dotproduct(&a->ptr.pp_double[1][j], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,jm1)); - } - else - { - sumj = 0; - } - } - else - { - if( jptr.pp_double[jp1][j], a->stride, &x->ptr.p_double[jp1], 1, ae_v_len(jp1,n)); - } - } - } - else - { - - /* - * Otherwise, use in-line code for the dot product. - */ - if( upper ) - { - for(i=1; i<=j-1; i++) - { - v = a->ptr.pp_double[i][j]*uscal; - sumj = sumj+v*x->ptr.p_double[i]; - } - } - else - { - if( jptr.pp_double[i][j]*uscal; - sumj = sumj+v*x->ptr.p_double[i]; - } - } - } - } - if( ae_fp_eq(uscal,tscal) ) - { - - /* - * Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) - * was not used to scale the dotproduct. - */ - x->ptr.p_double[j] = x->ptr.p_double[j]-sumj; - xj = ae_fabs(x->ptr.p_double[j], _state); - flg = 0; - if( nounit ) - { - tjjs = a->ptr.pp_double[j][j]*tscal; - } - else - { - tjjs = tscal; - if( ae_fp_eq(tscal,1) ) - { - flg = 150; - } - } - - /* - * Compute x(j) = x(j) / A(j,j), scaling if necessary. - */ - if( flg!=150 ) - { - tjj = ae_fabs(tjjs, _state); - if( ae_fp_greater(tjj,smlnum) ) - { - - /* - * abs(A(j,j)) > SMLNUM: - */ - if( ae_fp_less(tjj,1) ) - { - if( ae_fp_greater(xj,tjj*bignum) ) - { - - /* - * Scale X by 1/abs(x(j)). - */ - rec = 1/xj; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - xmax = xmax*rec; - } - } - x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; - } - else - { - if( ae_fp_greater(tjj,0) ) - { - - /* - * 0 < abs(A(j,j)) <= SMLNUM: - */ - if( ae_fp_greater(xj,tjj*bignum) ) - { - - /* - * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. - */ - rec = tjj*bignum/xj; - ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); - *s = *s*rec; - xmax = xmax*rec; - } - x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; - } - else - { - - /* - * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and - * scale = 0, and compute a solution to A'*x = 0. - */ - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = 0; - } - x->ptr.p_double[j] = 1; - *s = 0; - xmax = 0; - } - } - } - } - else - { - - /* - * Compute x(j) := x(j) / A(j,j) - sumj if the dot - * product has already been divided by 1/A(j,j). - */ - x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs-sumj; - } - xmax = ae_maxreal(xmax, ae_fabs(x->ptr.p_double[j], _state), _state); - j = j+jinc; - } - } - *s = *s/tscal; - } - - /* - * Scale the column norms by 1/TSCAL for return. - */ - if( ae_fp_neq(tscal,1) ) - { - v = 1/tscal; - ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), v); - } -} - - - - -/************************************************************************* -Real implementation of CMatrixScaledTRSafeSolve - - -- ALGLIB routine -- - 21.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixscaledtrsafesolve(/* Real */ ae_matrix* a, - double sa, - ae_int_t n, - /* Real */ ae_vector* x, - ae_bool isupper, - ae_int_t trans, - ae_bool isunit, - double maxgrowth, - ae_state *_state) -{ - ae_frame _frame_block; - double lnmax; - double nrmb; - double nrmx; - ae_int_t i; - ae_complex alpha; - ae_complex beta; - double vr; - ae_complex cx; - ae_vector tmp; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "RMatrixTRSafeSolve: incorrect N!", _state); - ae_assert(trans==0||trans==1, "RMatrixTRSafeSolve: incorrect Trans!", _state); - result = ae_true; - lnmax = ae_log(ae_maxrealnumber, _state); - - /* - * Quick return if possible - */ - if( n<=0 ) - { - ae_frame_leave(_state); - return result; - } - - /* - * Load norms: right part and X - */ - nrmb = 0; - for(i=0; i<=n-1; i++) - { - nrmb = ae_maxreal(nrmb, ae_fabs(x->ptr.p_double[i], _state), _state); - } - nrmx = 0; - - /* - * Solve - */ - ae_vector_set_length(&tmp, n, _state); - result = ae_true; - if( isupper&&trans==0 ) - { - - /* - * U*x = b - */ - for(i=n-1; i>=0; i--) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); - } - if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); - vr = ae_v_dotproduct(&tmp.ptr.p_double[i+1], 1, &x->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); - beta = ae_complex_from_d(x->ptr.p_double[i]-vr); - } - else - { - beta = ae_complex_from_d(x->ptr.p_double[i]); - } - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_double[i] = cx.x; - } - ae_frame_leave(_state); - return result; - } - if( !isupper&&trans==0 ) - { - - /* - * L*x = b - */ - for(i=0; i<=n-1; i++) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); - } - if( i>0 ) - { - ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); - vr = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,i-1)); - beta = ae_complex_from_d(x->ptr.p_double[i]-vr); - } - else - { - beta = ae_complex_from_d(x->ptr.p_double[i]); - } - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_double[i] = cx.x; - } - ae_frame_leave(_state); - return result; - } - if( isupper&&trans==1 ) - { - - /* - * U^T*x = b - */ - for(i=0; i<=n-1; i++) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); - } - beta = ae_complex_from_d(x->ptr.p_double[i]); - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_double[i] = cx.x; - - /* - * update the rest of right part - */ - if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); - ae_v_subd(&x->ptr.p_double[i+1], 1, &tmp.ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), vr); - } - } - ae_frame_leave(_state); - return result; - } - if( !isupper&&trans==1 ) - { - - /* - * L^T*x = b - */ - for(i=n-1; i>=0; i--) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); - } - beta = ae_complex_from_d(x->ptr.p_double[i]); - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_double[i] = cx.x; - - /* - * update the rest of right part - */ - if( i>0 ) - { - vr = cx.x; - ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); - ae_v_subd(&x->ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1), vr); - } - } - ae_frame_leave(_state); - return result; - } - result = ae_false; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Internal subroutine for safe solution of - - SA*op(A)=b - -where A is NxN upper/lower triangular/unitriangular matrix, op(A) is -either identity transform, transposition or Hermitian transposition, SA is -a scaling factor such that max(|SA*A[i,j]|) is close to 1.0 in magnutude. - -This subroutine limits relative growth of solution (in inf-norm) by -MaxGrowth, returning False if growth exceeds MaxGrowth. Degenerate or -near-degenerate matrices are handled correctly (False is returned) as long -as MaxGrowth is significantly less than MaxRealNumber/norm(b). - - -- ALGLIB routine -- - 21.01.2010 - Bochkanov Sergey -*************************************************************************/ -ae_bool cmatrixscaledtrsafesolve(/* Complex */ ae_matrix* a, - double sa, - ae_int_t n, - /* Complex */ ae_vector* x, - ae_bool isupper, - ae_int_t trans, - ae_bool isunit, - double maxgrowth, - ae_state *_state) -{ - ae_frame _frame_block; - double lnmax; - double nrmb; - double nrmx; - ae_int_t i; - ae_complex alpha; - ae_complex beta; - ae_complex vc; - ae_vector tmp; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0, "CMatrixTRSafeSolve: incorrect N!", _state); - ae_assert((trans==0||trans==1)||trans==2, "CMatrixTRSafeSolve: incorrect Trans!", _state); - result = ae_true; - lnmax = ae_log(ae_maxrealnumber, _state); - - /* - * Quick return if possible - */ - if( n<=0 ) - { - ae_frame_leave(_state); - return result; - } - - /* - * Load norms: right part and X - */ - nrmb = 0; - for(i=0; i<=n-1; i++) - { - nrmb = ae_maxreal(nrmb, ae_c_abs(x->ptr.p_complex[i], _state), _state); - } - nrmx = 0; - - /* - * Solve - */ - ae_vector_set_length(&tmp, n, _state); - result = ae_true; - if( isupper&&trans==0 ) - { - - /* - * U*x = b - */ - for(i=n-1; i>=0; i--) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); - } - if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); - vc = ae_v_cdotproduct(&tmp.ptr.p_complex[i+1], 1, "N", &x->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); - beta = ae_c_sub(x->ptr.p_complex[i],vc); - } - else - { - beta = x->ptr.p_complex[i]; - } - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - } - ae_frame_leave(_state); - return result; - } - if( !isupper&&trans==0 ) - { - - /* - * L*x = b - */ - for(i=0; i<=n-1; i++) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); - } - if( i>0 ) - { - ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); - vc = ae_v_cdotproduct(&tmp.ptr.p_complex[0], 1, "N", &x->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); - beta = ae_c_sub(x->ptr.p_complex[i],vc); - } - else - { - beta = x->ptr.p_complex[i]; - } - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - } - ae_frame_leave(_state); - return result; - } - if( isupper&&trans==1 ) - { - - /* - * U^T*x = b - */ - for(i=0; i<=n-1; i++) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); - } - beta = x->ptr.p_complex[i]; - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - - /* - * update the rest of right part - */ - if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); - ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); - } - } - ae_frame_leave(_state); - return result; - } - if( !isupper&&trans==1 ) - { - - /* - * L^T*x = b - */ - for(i=n-1; i>=0; i--) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); - } - beta = x->ptr.p_complex[i]; - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - - /* - * update the rest of right part - */ - if( i>0 ) - { - ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); - ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); - } - } - ae_frame_leave(_state); - return result; - } - if( isupper&&trans==2 ) - { - - /* - * U^H*x = b - */ - for(i=0; i<=n-1; i++) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); - } - beta = x->ptr.p_complex[i]; - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - - /* - * update the rest of right part - */ - if( iptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), sa); - ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); - } - } - ae_frame_leave(_state); - return result; - } - if( !isupper&&trans==2 ) - { - - /* - * L^T*x = b - */ - for(i=n-1; i>=0; i--) - { - - /* - * Task is reduced to alpha*x[i] = beta - */ - if( isunit ) - { - alpha = ae_complex_from_d(sa); - } - else - { - alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); - } - beta = x->ptr.p_complex[i]; - - /* - * solve alpha*x[i] = beta - */ - result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - x->ptr.p_complex[i] = vc; - - /* - * update the rest of right part - */ - if( i>0 ) - { - ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), sa); - ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); - } - } - ae_frame_leave(_state); - return result; - } - result = ae_false; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -complex basic solver-updater for reduced linear system - - alpha*x[i] = beta - -solves this equation and updates it in overlfow-safe manner (keeping track -of relative growth of solution). - -Parameters: - Alpha - alpha - Beta - beta - LnMax - precomputed Ln(MaxRealNumber) - BNorm - inf-norm of b (right part of original system) - MaxGrowth- maximum growth of norm(x) relative to norm(b) - XNorm - inf-norm of other components of X (which are already processed) - it is updated by CBasicSolveAndUpdate. - X - solution - - -- ALGLIB routine -- - 26.01.2009 - Bochkanov Sergey -*************************************************************************/ -static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, - ae_complex beta, - double lnmax, - double bnorm, - double maxgrowth, - double* xnorm, - ae_complex* x, - ae_state *_state) -{ - double v; - ae_bool result; - - x->x = 0; - x->y = 0; - - result = ae_false; - if( ae_c_eq_d(alpha,0) ) - { - return result; - } - if( ae_c_neq_d(beta,0) ) - { - - /* - * alpha*x[i]=beta - */ - v = ae_log(ae_c_abs(beta, _state), _state)-ae_log(ae_c_abs(alpha, _state), _state); - if( ae_fp_greater(v,lnmax) ) - { - return result; - } - *x = ae_c_div(beta,alpha); - } - else - { - - /* - * alpha*x[i]=0 - */ - *x = ae_complex_from_d(0); - } - - /* - * update NrmX, test growth limit - */ - *xnorm = ae_maxreal(*xnorm, ae_c_abs(*x, _state), _state); - if( ae_fp_greater(*xnorm,maxgrowth*bnorm) ) - { - return result; - } - result = ae_true; - return result; -} - - - - -/************************************************************************* -Prepares HPC compuations of chunked gradient with HPCChunkedGradient(). -You have to call this function before calling HPCChunkedGradient() for -a new set of weights. You have to call it only once, see example below: - -HOW TO PROCESS DATASET WITH THIS FUNCTION: - Grad:=0 - HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) - foreach chunk-of-dataset do - HPCChunkedGradient(...) - HPCFinalizeChunkedGradient(Buf, Grad) - -*************************************************************************/ -void hpcpreparechunkedgradient(/* Real */ ae_vector* weights, - ae_int_t wcount, - ae_int_t ntotal, - ae_int_t nin, - ae_int_t nout, - mlpbuffers* buf, - ae_state *_state) -{ - ae_int_t i; - ae_int_t batch4size; - ae_int_t chunksize; - - - chunksize = 4; - batch4size = 3*chunksize*ntotal+chunksize*(2*nout+1); - if( buf->xy.rowsxy.colsxy, chunksize, nin+nout, _state); - } - if( buf->xy2.rowsxy2.colsxy2, chunksize, nin+nout, _state); - } - if( buf->xyrow.cntxyrow, nin+nout, _state); - } - if( buf->x.cntx, nin, _state); - } - if( buf->y.cnty, nout, _state); - } - if( buf->desiredy.cntdesiredy, nout, _state); - } - if( buf->batch4buf.cntbatch4buf, batch4size, _state); - } - if( buf->hpcbuf.cnthpcbuf, wcount, _state); - } - if( buf->g.cntg, wcount, _state); - } - if( !hpccores_hpcpreparechunkedgradientx(weights, wcount, &buf->hpcbuf, _state) ) - { - for(i=0; i<=wcount-1; i++) - { - buf->hpcbuf.ptr.p_double[i] = 0.0; - } - } - buf->wcount = wcount; - buf->ntotal = ntotal; - buf->nin = nin; - buf->nout = nout; - buf->chunksize = chunksize; -} - - -/************************************************************************* -Finalizes HPC compuations of chunked gradient with HPCChunkedGradient(). -You have to call this function after calling HPCChunkedGradient() for -a new set of weights. You have to call it only once, see example below: - -HOW TO PROCESS DATASET WITH THIS FUNCTION: - Grad:=0 - HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) - foreach chunk-of-dataset do - HPCChunkedGradient(...) - HPCFinalizeChunkedGradient(Buf, Grad) - -*************************************************************************/ -void hpcfinalizechunkedgradient(mlpbuffers* buf, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_int_t i; - - - if( !hpccores_hpcfinalizechunkedgradientx(&buf->hpcbuf, buf->wcount, grad, _state) ) - { - for(i=0; i<=buf->wcount-1; i++) - { - grad->ptr.p_double[i] = grad->ptr.p_double[i]+buf->hpcbuf.ptr.p_double[i]; - } - } -} - - -/************************************************************************* -Fast kernel for chunked gradient. - -*************************************************************************/ -ae_bool hpcchunkedgradient(/* Real */ ae_vector* weights, - /* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - double* e, - ae_bool naturalerrorfunc, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SSE2 - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_hpcchunkedgradient(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc); -#endif -} - - -/************************************************************************* -Fast kernel for chunked processing. - -*************************************************************************/ -ae_bool hpcchunkedprocess(/* Real */ ae_vector* weights, - /* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SSE2 - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_hpcchunkedprocess(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf); -#endif -} - - -/************************************************************************* -Stub function. - - -- ALGLIB routine -- - 14.06.2013 - Bochkanov Sergey -*************************************************************************/ -static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ ae_vector* weights, - ae_int_t wcount, - /* Real */ ae_vector* hpcbuf, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SSE2 - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_hpcpreparechunkedgradientx(weights, wcount, hpcbuf); -#endif -} - - -/************************************************************************* -Stub function. - - -- ALGLIB routine -- - 14.06.2013 - Bochkanov Sergey -*************************************************************************/ -static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ ae_vector* buf, - ae_int_t wcount, - /* Real */ ae_vector* grad, - ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SSE2 - ae_bool result; - - - result = ae_false; - return result; -#else - return _ialglib_i_hpcfinalizechunkedgradientx(buf, wcount, grad); -#endif -} - - -ae_bool _mlpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpbuffers *p = (mlpbuffers*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->batch4buf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hpcbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->xy2, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->desiredy, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mlpbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpbuffers *dst = (mlpbuffers*)_dst; - mlpbuffers *src = (mlpbuffers*)_src; - dst->chunksize = src->chunksize; - dst->ntotal = src->ntotal; - dst->nin = src->nin; - dst->nout = src->nout; - dst->wcount = src->wcount; - if( !ae_vector_init_copy(&dst->batch4buf, &src->batch4buf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->hpcbuf, &src->hpcbuf, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->xy2, &src->xy2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->desiredy, &src->desiredy, _state, make_automatic) ) - return ae_false; - dst->e = src->e; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mlpbuffers_clear(void* _p) -{ - mlpbuffers *p = (mlpbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->batch4buf); - ae_vector_clear(&p->hpcbuf); - ae_matrix_clear(&p->xy); - ae_matrix_clear(&p->xy2); - ae_vector_clear(&p->xyrow); - ae_vector_clear(&p->x); - ae_vector_clear(&p->y); - ae_vector_clear(&p->desiredy); - ae_vector_clear(&p->g); - ae_vector_clear(&p->tmp0); -} - - -void _mlpbuffers_destroy(void* _p) -{ - mlpbuffers *p = (mlpbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->batch4buf); - ae_vector_destroy(&p->hpcbuf); - ae_matrix_destroy(&p->xy); - ae_matrix_destroy(&p->xy2); - ae_vector_destroy(&p->xyrow); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->y); - ae_vector_destroy(&p->desiredy); - ae_vector_destroy(&p->g); - ae_vector_destroy(&p->tmp0); -} - - - - -/************************************************************************* -More precise dot-product. Absolute error of subroutine result is about -1 ulp of max(MX,V), where: - MX = max( |a[i]*b[i]| ) - V = |(a,b)| - -INPUT PARAMETERS - A - array[0..N-1], vector 1 - B - array[0..N-1], vector 2 - N - vectors length, N<2^29. - Temp - array[0..N-1], pre-allocated temporary storage - -OUTPUT PARAMETERS - R - (A,B) - RErr - estimate of error. This estimate accounts for both errors - during calculation of (A,B) and errors introduced by - rounding of A and B to fit in double (about 1 ulp). - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -void xdot(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* temp, - double* r, - double* rerr, - ae_state *_state) -{ - ae_int_t i; - double mx; - double v; - - *r = 0; - *rerr = 0; - - - /* - * special cases: - * * N=0 - */ - if( n==0 ) - { - *r = 0; - *rerr = 0; - return; - } - mx = 0; - for(i=0; i<=n-1; i++) - { - v = a->ptr.p_double[i]*b->ptr.p_double[i]; - temp->ptr.p_double[i] = v; - mx = ae_maxreal(mx, ae_fabs(v, _state), _state); - } - if( ae_fp_eq(mx,0) ) - { - *r = 0; - *rerr = 0; - return; - } - xblas_xsum(temp, mx, n, r, rerr, _state); -} - - -/************************************************************************* -More precise complex dot-product. Absolute error of subroutine result is -about 1 ulp of max(MX,V), where: - MX = max( |a[i]*b[i]| ) - V = |(a,b)| - -INPUT PARAMETERS - A - array[0..N-1], vector 1 - B - array[0..N-1], vector 2 - N - vectors length, N<2^29. - Temp - array[0..2*N-1], pre-allocated temporary storage - -OUTPUT PARAMETERS - R - (A,B) - RErr - estimate of error. This estimate accounts for both errors - during calculation of (A,B) and errors introduced by - rounding of A and B to fit in double (about 1 ulp). - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void xcdot(/* Complex */ ae_vector* a, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* temp, - ae_complex* r, - double* rerr, - ae_state *_state) -{ - ae_int_t i; - double mx; - double v; - double rerrx; - double rerry; - - r->x = 0; - r->y = 0; - *rerr = 0; - - - /* - * special cases: - * * N=0 - */ - if( n==0 ) - { - *r = ae_complex_from_d(0); - *rerr = 0; - return; - } - - /* - * calculate real part - */ - mx = 0; - for(i=0; i<=n-1; i++) - { - v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].x; - temp->ptr.p_double[2*i+0] = v; - mx = ae_maxreal(mx, ae_fabs(v, _state), _state); - v = -a->ptr.p_complex[i].y*b->ptr.p_complex[i].y; - temp->ptr.p_double[2*i+1] = v; - mx = ae_maxreal(mx, ae_fabs(v, _state), _state); - } - if( ae_fp_eq(mx,0) ) - { - r->x = 0; - rerrx = 0; - } - else - { - xblas_xsum(temp, mx, 2*n, &r->x, &rerrx, _state); - } - - /* - * calculate imaginary part - */ - mx = 0; - for(i=0; i<=n-1; i++) - { - v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].y; - temp->ptr.p_double[2*i+0] = v; - mx = ae_maxreal(mx, ae_fabs(v, _state), _state); - v = a->ptr.p_complex[i].y*b->ptr.p_complex[i].x; - temp->ptr.p_double[2*i+1] = v; - mx = ae_maxreal(mx, ae_fabs(v, _state), _state); - } - if( ae_fp_eq(mx,0) ) - { - r->y = 0; - rerry = 0; - } - else - { - xblas_xsum(temp, mx, 2*n, &r->y, &rerry, _state); - } - - /* - * total error - */ - if( ae_fp_eq(rerrx,0)&&ae_fp_eq(rerry,0) ) - { - *rerr = 0; - } - else - { - *rerr = ae_maxreal(rerrx, rerry, _state)*ae_sqrt(1+ae_sqr(ae_minreal(rerrx, rerry, _state)/ae_maxreal(rerrx, rerry, _state), _state), _state); - } -} - - -/************************************************************************* -Internal subroutine for extra-precise calculation of SUM(w[i]). - -INPUT PARAMETERS: - W - array[0..N-1], values to be added - W is modified during calculations. - MX - max(W[i]) - N - array size - -OUTPUT PARAMETERS: - R - SUM(w[i]) - RErr- error estimate for R - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -static void xblas_xsum(/* Real */ ae_vector* w, - double mx, - ae_int_t n, - double* r, - double* rerr, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t ks; - double v; - double s; - double ln2; - double chunk; - double invchunk; - ae_bool allzeros; - - *r = 0; - *rerr = 0; - - - /* - * special cases: - * * N=0 - * * N is too large to use integer arithmetics - */ - if( n==0 ) - { - *r = 0; - *rerr = 0; - return; - } - if( ae_fp_eq(mx,0) ) - { - *r = 0; - *rerr = 0; - return; - } - ae_assert(n<536870912, "XDot: N is too large!", _state); - - /* - * Prepare - */ - ln2 = ae_log(2, _state); - *rerr = mx*ae_machineepsilon; - - /* - * 1. find S such that 0.5<=S*MX<1 - * 2. multiply W by S, so task is normalized in some sense - * 3. S:=1/S so we can obtain original vector multiplying by S - */ - k = ae_round(ae_log(mx, _state)/ln2, _state); - s = xblas_xfastpow(2, -k, _state); - while(ae_fp_greater_eq(s*mx,1)) - { - s = 0.5*s; - } - while(ae_fp_less(s*mx,0.5)) - { - s = 2*s; - } - ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), s); - s = 1/s; - - /* - * find Chunk=2^M such that N*Chunk<2^29 - * - * we have chosen upper limit (2^29) with enough space left - * to tolerate possible problems with rounding and N's close - * to the limit, so we don't want to be very strict here. - */ - k = ae_trunc(ae_log((double)536870912/(double)n, _state)/ln2, _state); - chunk = xblas_xfastpow(2, k, _state); - if( ae_fp_less(chunk,2) ) - { - chunk = 2; - } - invchunk = 1/chunk; - - /* - * calculate result - */ - *r = 0; - ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), chunk); - for(;;) - { - s = s*invchunk; - allzeros = ae_true; - ks = 0; - for(i=0; i<=n-1; i++) - { - v = w->ptr.p_double[i]; - k = ae_trunc(v, _state); - if( ae_fp_neq(v,k) ) - { - allzeros = ae_false; - } - w->ptr.p_double[i] = chunk*(v-k); - ks = ks+k; - } - *r = *r+s*ks; - v = ae_fabs(*r, _state); - if( allzeros||ae_fp_eq(s*n+mx,mx) ) - { - break; - } - } - - /* - * correct error - */ - *rerr = ae_maxreal(*rerr, ae_fabs(*r, _state)*ae_machineepsilon, _state); -} - - -/************************************************************************* -Fast Pow - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state) -{ - double result; - - - result = 0; - if( n>0 ) - { - if( n%2==0 ) - { - result = ae_sqr(xblas_xfastpow(r, n/2, _state), _state); - } - else - { - result = r*xblas_xfastpow(r, n-1, _state); - } - return result; - } - if( n==0 ) - { - result = 1; - } - if( n<0 ) - { - result = xblas_xfastpow(1/r, -n, _state); - } - return result; -} - - - - -/************************************************************************* -Normalizes direction/step pair: makes |D|=1, scales Stp. -If |D|=0, it returns, leavind D/Stp unchanged. - - -- ALGLIB -- - Copyright 01.04.2010 by Bochkanov Sergey -*************************************************************************/ -void linminnormalized(/* Real */ ae_vector* d, - double* stp, - ae_int_t n, - ae_state *_state) -{ - double mx; - double s; - ae_int_t i; - - - - /* - * first, scale D to avoid underflow/overflow durng squaring - */ - mx = 0; - for(i=0; i<=n-1; i++) - { - mx = ae_maxreal(mx, ae_fabs(d->ptr.p_double[i], _state), _state); - } - if( ae_fp_eq(mx,0) ) - { - return; - } - s = 1/mx; - ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); - *stp = *stp/s; - - /* - * normalize D - */ - s = ae_v_dotproduct(&d->ptr.p_double[0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); - s = 1/ae_sqrt(s, _state); - ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); - *stp = *stp/s; -} - - -/************************************************************************* -THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT -DECREASE CONDITION AND A CURVATURE CONDITION. - -AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH -ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN -SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION - - F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). - -IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE -FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF -UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). - -THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT -DECREASE CONDITION - - F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), - -AND THE CURVATURE CONDITION - - ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). - -IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED -BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. -IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE -ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. -IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. - - -:::::::::::::IMPORTANT NOTES::::::::::::: - -NOTE 1: - -This routine guarantees that it will stop at the last point where function -value was calculated. It won't make several additional function evaluations -after finding good point. So if you store function evaluations requested by -this routine, you can be sure that last one is the point where we've stopped. - -NOTE 2: - -when 0xtrapf = 4.0; - zero = 0; - if( ae_fp_eq(stpmax,0) ) - { - stpmax = linmin_defstpmax; - } - if( ae_fp_less(*stp,linmin_stpmin) ) - { - *stp = linmin_stpmin; - } - if( ae_fp_greater(*stp,stpmax) ) - { - *stp = stpmax; - } - - /* - * Main cycle - */ - for(;;) - { - if( *stage==0 ) - { - - /* - * NEXT - */ - *stage = 2; - continue; - } - if( *stage==2 ) - { - state->infoc = 1; - *info = 0; - - /* - * CHECK THE INPUT PARAMETERS FOR ERRORS. - */ - if( ae_fp_less(stpmax,linmin_stpmin)&&ae_fp_greater(stpmax,0) ) - { - *info = 5; - *stp = 0.0; - return; - } - if( ((((((n<=0||ae_fp_less_eq(*stp,0))||ae_fp_less(linmin_ftol,0))||ae_fp_less(gtol,zero))||ae_fp_less(linmin_xtol,zero))||ae_fp_less(linmin_stpmin,zero))||ae_fp_less(stpmax,linmin_stpmin))||linmin_maxfev<=0 ) - { - *stage = 0; - return; - } - - /* - * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION - * AND CHECK THAT S IS A DESCENT DIRECTION. - */ - v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->dginit = v; - if( ae_fp_greater_eq(state->dginit,0) ) - { - *stage = 0; - return; - } - - /* - * INITIALIZE LOCAL VARIABLES. - */ - state->brackt = ae_false; - state->stage1 = ae_true; - *nfev = 0; - state->finit = *f; - state->dgtest = linmin_ftol*state->dginit; - state->width = stpmax-linmin_stpmin; - state->width1 = state->width/p5; - ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, - * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. - * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, - * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF - * THE INTERVAL OF UNCERTAINTY. - * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, - * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. - */ - state->stx = 0; - state->fx = state->finit; - state->dgx = state->dginit; - state->sty = 0; - state->fy = state->finit; - state->dgy = state->dginit; - - /* - * NEXT - */ - *stage = 3; - continue; - } - if( *stage==3 ) - { - - /* - * START OF ITERATION. - * - * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND - * TO THE PRESENT INTERVAL OF UNCERTAINTY. - */ - if( state->brackt ) - { - if( ae_fp_less(state->stx,state->sty) ) - { - state->stmin = state->stx; - state->stmax = state->sty; - } - else - { - state->stmin = state->sty; - state->stmax = state->stx; - } - } - else - { - state->stmin = state->stx; - state->stmax = *stp+state->xtrapf*(*stp-state->stx); - } - - /* - * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. - */ - if( ae_fp_greater(*stp,stpmax) ) - { - *stp = stpmax; - } - if( ae_fp_less(*stp,linmin_stpmin) ) - { - *stp = linmin_stpmin; - } - - /* - * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET - * STP BE THE LOWEST POINT OBTAINED SO FAR. - */ - if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=linmin_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax)) ) - { - *stp = state->stx; - } - - /* - * EVALUATE THE FUNCTION AND GRADIENT AT STP - * AND COMPUTE THE DIRECTIONAL DERIVATIVE. - */ - ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); - - /* - * NEXT - */ - *stage = 4; - return; - } - if( *stage==4 ) - { - *info = 0; - *nfev = *nfev+1; - v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->dg = v; - state->ftest1 = state->finit+*stp*state->dgtest; - - /* - * TEST FOR CONVERGENCE. - */ - if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) - { - *info = 6; - } - if( (ae_fp_eq(*stp,stpmax)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) - { - *info = 5; - } - if( ae_fp_eq(*stp,linmin_stpmin)&&(ae_fp_greater(*f,state->ftest1)||ae_fp_greater_eq(state->dg,state->dgtest)) ) - { - *info = 4; - } - if( *nfev>=linmin_maxfev ) - { - *info = 3; - } - if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax) ) - { - *info = 2; - } - if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-gtol*state->dginit) ) - { - *info = 1; - } - - /* - * CHECK FOR TERMINATION. - */ - if( *info!=0 ) - { - *stage = 0; - return; - } - - /* - * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED - * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. - */ - if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(linmin_ftol, gtol, _state)*state->dginit) ) - { - state->stage1 = ae_false; - } - - /* - * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF - * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED - * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE - * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN - * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. - */ - if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) - { - - /* - * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. - */ - state->fm = *f-*stp*state->dgtest; - state->fxm = state->fx-state->stx*state->dgtest; - state->fym = state->fy-state->sty*state->dgtest; - state->dgm = state->dg-state->dgtest; - state->dgxm = state->dgx-state->dgtest; - state->dgym = state->dgy-state->dgtest; - - /* - * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY - * AND TO COMPUTE THE NEW STEP. - */ - linmin_mcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); - - /* - * RESET THE FUNCTION AND GRADIENT VALUES FOR F. - */ - state->fx = state->fxm+state->stx*state->dgtest; - state->fy = state->fym+state->sty*state->dgtest; - state->dgx = state->dgxm+state->dgtest; - state->dgy = state->dgym+state->dgtest; - } - else - { - - /* - * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY - * AND TO COMPUTE THE NEW STEP. - */ - linmin_mcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); - } - - /* - * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE - * INTERVAL OF UNCERTAINTY. - */ - if( state->brackt ) - { - if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) - { - *stp = state->stx+p5*(state->sty-state->stx); - } - state->width1 = state->width; - state->width = ae_fabs(state->sty-state->stx, _state); - } - - /* - * NEXT. - */ - *stage = 3; - continue; - } - } -} - - -/************************************************************************* -These functions perform Armijo line search using at most FMAX function -evaluations. It doesn't enforce some kind of " sufficient decrease" -criterion - it just tries different Armijo steps and returns optimum found -so far. - -Optimization is done using F-rcomm interface: -* ArmijoCreate initializes State structure - (reusing previously allocated buffers) -* ArmijoIteration is subsequently called -* ArmijoResults returns results - -INPUT PARAMETERS: - N - problem size - X - array[N], starting point - F - F(X+S*STP) - S - step direction, S>0 - STP - step length - STPMAX - maximum value for STP or zero (if no limit is imposed) - FMAX - maximum number of function evaluations - State - optimization state - - -- ALGLIB -- - Copyright 05.10.2010 by Bochkanov Sergey -*************************************************************************/ -void armijocreate(ae_int_t n, - /* Real */ ae_vector* x, - double f, - /* Real */ ae_vector* s, - double stp, - double stpmax, - ae_int_t fmax, - armijostate* state, - ae_state *_state) -{ - - - if( state->x.cntx, n, _state); - } - if( state->xbase.cntxbase, n, _state); - } - if( state->s.cnts, n, _state); - } - state->stpmax = stpmax; - state->fmax = fmax; - state->stplen = stp; - state->fcur = f; - state->n = n; - ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->s.ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_vector_set_length(&state->rstate.ia, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 0+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -This is rcomm-based search function - - -- ALGLIB -- - Copyright 05.10.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool armijoiteration(armijostate* state, ae_state *_state) -{ - double v; - ae_int_t n; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - v = state->rstate.ra.ptr.p_double[0]; - } - else - { - n = -983; - v = -989; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - - /* - * Routine body - */ - if( (ae_fp_less_eq(state->stplen,0)||ae_fp_less(state->stpmax,0))||state->fmax<2 ) - { - state->info = 0; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) - { - state->info = 4; - result = ae_false; - return result; - } - n = state->n; - state->nfev = 0; - - /* - * We always need F - */ - state->needf = ae_true; - - /* - * Bound StpLen - */ - if( ae_fp_greater(state->stplen,state->stpmax)&&ae_fp_neq(state->stpmax,0) ) - { - state->stplen = state->stpmax; - } - - /* - * Increase length - */ - v = state->stplen*linmin_armijofactor; - if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,0) ) - { - v = state->stpmax; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->nfev = state->nfev+1; - if( ae_fp_greater_eq(state->f,state->fcur) ) - { - goto lbl_4; - } - state->stplen = v; - state->fcur = state->f; -lbl_6: - if( ae_false ) - { - goto lbl_7; - } - - /* - * test stopping conditions - */ - if( state->nfev>=state->fmax ) - { - state->info = 3; - result = ae_false; - return result; - } - if( ae_fp_greater_eq(state->stplen,state->stpmax) ) - { - state->info = 5; - result = ae_false; - return result; - } - - /* - * evaluate F - */ - v = state->stplen*linmin_armijofactor; - if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,0) ) - { - v = state->stpmax; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->nfev = state->nfev+1; - - /* - * make decision - */ - if( ae_fp_less(state->f,state->fcur) ) - { - state->stplen = v; - state->fcur = state->f; - } - else - { - state->info = 1; - result = ae_false; - return result; - } - goto lbl_6; -lbl_7: -lbl_4: - - /* - * Decrease length - */ - v = state->stplen/linmin_armijofactor; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->nfev = state->nfev+1; - if( ae_fp_greater_eq(state->f,state->fcur) ) - { - goto lbl_8; - } - state->stplen = state->stplen/linmin_armijofactor; - state->fcur = state->f; -lbl_10: - if( ae_false ) - { - goto lbl_11; - } - - /* - * test stopping conditions - */ - if( state->nfev>=state->fmax ) - { - state->info = 3; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) - { - state->info = 4; - result = ae_false; - return result; - } - - /* - * evaluate F - */ - v = state->stplen/linmin_armijofactor; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->nfev = state->nfev+1; - - /* - * make decision - */ - if( ae_fp_less(state->f,state->fcur) ) - { - state->stplen = state->stplen/linmin_armijofactor; - state->fcur = state->f; - } - else - { - state->info = 1; - result = ae_false; - return result; - } - goto lbl_10; -lbl_11: -lbl_8: - - /* - * Nothing to be done - */ - state->info = 1; - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ra.ptr.p_double[0] = v; - return result; -} - - -/************************************************************************* -Results of Armijo search - -OUTPUT PARAMETERS: - INFO - on output it is set to one of the return codes: - * 0 improper input params - * 1 optimum step is found with at most FMAX evaluations - * 3 FMAX evaluations were used, - X contains optimum found so far - * 4 step is at lower bound STPMIN - * 5 step is at upper bound - STP - step length (in case of failure it is still returned) - F - function value (in case of failure it is still returned) - - -- ALGLIB -- - Copyright 05.10.2010 by Bochkanov Sergey -*************************************************************************/ -void armijoresults(armijostate* state, - ae_int_t* info, - double* stp, - double* f, - ae_state *_state) -{ - - - *info = state->info; - *stp = state->stplen; - *f = state->fcur; -} - - -static void linmin_mcstep(double* stx, - double* fx, - double* dx, - double* sty, - double* fy, - double* dy, - double* stp, - double fp, - double dp, - ae_bool* brackt, - double stmin, - double stmax, - ae_int_t* info, - ae_state *_state) -{ - ae_bool bound; - double gamma; - double p; - double q; - double r; - double s; - double sgnd; - double stpc; - double stpf; - double stpq; - double theta; - - - *info = 0; - - /* - * CHECK THE INPUT PARAMETERS FOR ERRORS. - */ - if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),0))||ae_fp_less(stmax,stmin) ) - { - return; - } - - /* - * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. - */ - sgnd = dp*(*dx/ae_fabs(*dx, _state)); - - /* - * FIRST CASE. A HIGHER FUNCTION VALUE. - * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER - * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, - * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. - */ - if( ae_fp_greater(fp,*fx) ) - { - *info = 1; - bound = ae_true; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); - if( ae_fp_less(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-(*dx)+theta; - q = gamma-(*dx)+gamma+dp; - r = p/q; - stpc = *stx+r*(*stp-(*stx)); - stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/2*(*stp-(*stx)); - if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpc+(stpq-stpc)/2; - } - *brackt = ae_true; - } - else - { - if( ae_fp_less(sgnd,0) ) - { - - /* - * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF - * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC - * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, - * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. - */ - *info = 2; - bound = ae_false; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); - if( ae_fp_greater(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma-dp+gamma+(*dx); - r = p/q; - stpc = *stp+r*(*stx-(*stp)); - stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); - if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - *brackt = ae_true; - } - else - { - if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) - { - - /* - * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE - * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. - * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY - * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC - * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE - * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO - * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP - * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. - */ - *info = 3; - bound = ae_true; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - - /* - * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND - * TO INFINITY IN THE DIRECTION OF THE STEP. - */ - gamma = s*ae_sqrt(ae_maxreal(0, ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); - if( ae_fp_greater(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma+(*dx-dp)+gamma; - r = p/q; - if( ae_fp_less(r,0)&&ae_fp_neq(gamma,0) ) - { - stpc = *stp+r*(*stx-(*stp)); - } - else - { - if( ae_fp_greater(*stp,*stx) ) - { - stpc = stmax; - } - else - { - stpc = stmin; - } - } - stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); - if( *brackt ) - { - if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - } - else - { - if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - } - } - else - { - - /* - * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE - * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES - * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP - * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. - */ - *info = 4; - bound = ae_false; - if( *brackt ) - { - theta = 3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); - if( ae_fp_greater(*stp,*sty) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma-dp+gamma+(*dy); - r = p/q; - stpc = *stp+r*(*sty-(*stp)); - stpf = stpc; - } - else - { - if( ae_fp_greater(*stp,*stx) ) - { - stpf = stmax; - } - else - { - stpf = stmin; - } - } - } - } - } - - /* - * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT - * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. - */ - if( ae_fp_greater(fp,*fx) ) - { - *sty = *stp; - *fy = fp; - *dy = dp; - } - else - { - if( ae_fp_less(sgnd,0.0) ) - { - *sty = *stx; - *fy = *fx; - *dy = *dx; - } - *stx = *stp; - *fx = fp; - *dx = dp; - } - - /* - * COMPUTE THE NEW STEP AND SAFEGUARD IT. - */ - stpf = ae_minreal(stmax, stpf, _state); - stpf = ae_maxreal(stmin, stpf, _state); - *stp = stpf; - if( *brackt&&bound ) - { - if( ae_fp_greater(*sty,*stx) ) - { - *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); - } - else - { - *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); - } - } -} - - -ae_bool _linminstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - linminstate *p = (linminstate*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _linminstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - linminstate *dst = (linminstate*)_dst; - linminstate *src = (linminstate*)_src; - dst->brackt = src->brackt; - dst->stage1 = src->stage1; - dst->infoc = src->infoc; - dst->dg = src->dg; - dst->dgm = src->dgm; - dst->dginit = src->dginit; - dst->dgtest = src->dgtest; - dst->dgx = src->dgx; - dst->dgxm = src->dgxm; - dst->dgy = src->dgy; - dst->dgym = src->dgym; - dst->finit = src->finit; - dst->ftest1 = src->ftest1; - dst->fm = src->fm; - dst->fx = src->fx; - dst->fxm = src->fxm; - dst->fy = src->fy; - dst->fym = src->fym; - dst->stx = src->stx; - dst->sty = src->sty; - dst->stmin = src->stmin; - dst->stmax = src->stmax; - dst->width = src->width; - dst->width1 = src->width1; - dst->xtrapf = src->xtrapf; - return ae_true; -} - - -void _linminstate_clear(void* _p) -{ - linminstate *p = (linminstate*)_p; - ae_touch_ptr((void*)p); -} - - -void _linminstate_destroy(void* _p) -{ - linminstate *p = (linminstate*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _armijostate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - armijostate *p = (armijostate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _armijostate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - armijostate *dst = (armijostate*)_dst; - armijostate *src = (armijostate*)_src; - dst->needf = src->needf; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - dst->n = src->n; - if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - dst->stplen = src->stplen; - dst->fcur = src->fcur; - dst->stpmax = src->stpmax; - dst->fmax = src->fmax; - dst->nfev = src->nfev; - dst->info = src->info; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _armijostate_clear(void* _p) -{ - armijostate *p = (armijostate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->xbase); - ae_vector_clear(&p->s); - _rcommstate_clear(&p->rstate); -} - - -void _armijostate_destroy(void* _p) -{ - armijostate *p = (armijostate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->xbase); - ae_vector_destroy(&p->s); - _rcommstate_destroy(&p->rstate); -} - - - - -void findprimitiverootandinverse(ae_int_t n, - ae_int_t* proot, - ae_int_t* invproot, - ae_state *_state) -{ - ae_int_t candroot; - ae_int_t phin; - ae_int_t q; - ae_int_t f; - ae_bool allnonone; - ae_int_t x; - ae_int_t lastx; - ae_int_t y; - ae_int_t lasty; - ae_int_t a; - ae_int_t b; - ae_int_t t; - ae_int_t n2; - - *proot = 0; - *invproot = 0; - - ae_assert(n>=3, "FindPrimitiveRootAndInverse: N<3", _state); - *proot = 0; - *invproot = 0; - - /* - * check that N is prime - */ - ae_assert(ntheory_isprime(n, _state), "FindPrimitiveRoot: N is not prime", _state); - - /* - * Because N is prime, Euler totient function is equal to N-1 - */ - phin = n-1; - - /* - * Test different values of PRoot - from 2 to N-1. - * One of these values MUST be primitive root. - * - * For testing we use algorithm from Wiki (Primitive root modulo n): - * * compute phi(N) - * * determine the different prime factors of phi(N), say p1, ..., pk - * * for every element m of Zn*, compute m^(phi(N)/pi) mod N for i=1..k - * using a fast algorithm for modular exponentiation. - * * a number m for which these k results are all different from 1 is a - * primitive root. - */ - for(candroot=2; candroot<=n-1; candroot++) - { - - /* - * We have current candidate root in CandRoot. - * - * Scan different prime factors of PhiN. Here: - * * F is a current candidate factor - * * Q is a current quotient - amount which was left after dividing PhiN - * by all previous factors - * - * For each factor, perform test mentioned above. - */ - q = phin; - f = 2; - allnonone = ae_true; - while(q>1) - { - if( q%f==0 ) - { - t = ntheory_modexp(candroot, phin/f, n, _state); - if( t==1 ) - { - allnonone = ae_false; - break; - } - while(q%f==0) - { - q = q/f; - } - } - f = f+1; - } - if( allnonone ) - { - *proot = candroot; - break; - } - } - ae_assert(*proot>=2, "FindPrimitiveRoot: internal error (root not found)", _state); - - /* - * Use extended Euclidean algorithm to find multiplicative inverse of primitive root - */ - x = 0; - lastx = 1; - y = 1; - lasty = 0; - a = *proot; - b = n; - while(b!=0) - { - q = a/b; - t = a%b; - a = b; - b = t; - t = lastx-q*x; - lastx = x; - x = t; - t = lasty-q*y; - lasty = y; - y = t; - } - while(lastx<0) - { - lastx = lastx+n; - } - *invproot = lastx; - - /* - * Check that it is safe to perform multiplication modulo N. - * Check results for consistency. - */ - n2 = (n-1)*(n-1); - ae_assert(n2/(n-1)==n-1, "FindPrimitiveRoot: internal error", _state); - ae_assert(*proot*(*invproot)/(*proot)==(*invproot), "FindPrimitiveRoot: internal error", _state); - ae_assert(*proot*(*invproot)/(*invproot)==(*proot), "FindPrimitiveRoot: internal error", _state); - ae_assert(*proot*(*invproot)%n==1, "FindPrimitiveRoot: internal error", _state); -} - - -static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state) -{ - ae_int_t p; - ae_bool result; - - - result = ae_false; - p = 2; - while(p*p<=n) - { - if( n%p==0 ) - { - return result; - } - p = p+1; - } - result = ae_true; - return result; -} - - -static ae_int_t ntheory_modmul(ae_int_t a, - ae_int_t b, - ae_int_t n, - ae_state *_state) -{ - ae_int_t t; - double ra; - double rb; - ae_int_t result; - - - ae_assert(a>=0&&a=N", _state); - ae_assert(b>=0&&b=N", _state); - - /* - * Base cases - */ - ra = a; - rb = b; - if( b==0||a==0 ) - { - result = 0; - return result; - } - if( b==1||a==1 ) - { - result = a*b; - return result; - } - if( ae_fp_eq(ra*rb,a*b) ) - { - result = a*b%n; - return result; - } - - /* - * Non-base cases - */ - if( b%2==0 ) - { - - /* - * A*B = (A*(B/2)) * 2 - * - * Product T=A*(B/2) is calculated recursively, product T*2 is - * calculated as follows: - * * result:=T-N - * * result:=result+T - * * if result<0 then result:=result+N - * - * In case integer result overflows, we generate exception - */ - t = ntheory_modmul(a, b/2, n, _state); - result = t-n; - result = result+t; - if( result<0 ) - { - result = result+n; - } - } - else - { - - /* - * A*B = (A*(B div 2)) * 2 + A - * - * Product T=A*(B/2) is calculated recursively, product T*2 is - * calculated as follows: - * * result:=T-N - * * result:=result+T - * * if result<0 then result:=result+N - * - * In case integer result overflows, we generate exception - */ - t = ntheory_modmul(a, b/2, n, _state); - result = t-n; - result = result+t; - if( result<0 ) - { - result = result+n; - } - result = result-n; - result = result+a; - if( result<0 ) - { - result = result+n; - } - } - return result; -} - - -static ae_int_t ntheory_modexp(ae_int_t a, - ae_int_t b, - ae_int_t n, - ae_state *_state) -{ - ae_int_t t; - ae_int_t result; - - - ae_assert(a>=0&&a=N", _state); - ae_assert(b>=0, "ModExp: B<0", _state); - - /* - * Base cases - */ - if( b==0 ) - { - result = 1; - return result; - } - if( b==1 ) - { - result = a; - return result; - } - - /* - * Non-base cases - */ - if( b%2==0 ) - { - t = ntheory_modmul(a, a, n, _state); - result = ntheory_modexp(t, b/2, n, _state); - } - else - { - t = ntheory_modmul(a, a, n, _state); - result = ntheory_modexp(t, b/2, n, _state); - result = ntheory_modmul(result, a, n, _state); - } - return result; -} - - - - -/************************************************************************* -This subroutine generates FFT plan for K complex FFT's with length N each. - -INPUT PARAMETERS: - N - FFT length (in complex numbers), N>=1 - K - number of repetitions, K>=1 - -OUTPUT PARAMETERS: - Plan - plan - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -void ftcomplexfftplan(ae_int_t n, - ae_int_t k, - fasttransformplan* plan, - ae_state *_state) -{ - ae_frame _frame_block; - srealarray bluesteinbuf; - ae_int_t rowptr; - ae_int_t bluesteinsize; - ae_int_t precrptr; - ae_int_t preciptr; - ae_int_t precrsize; - ae_int_t precisize; - - ae_frame_make(_state, &_frame_block); - _fasttransformplan_clear(plan); - _srealarray_init(&bluesteinbuf, _state, ae_true); - - - /* - * Initial check for parameters - */ - ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); - ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); - - /* - * Determine required sizes of precomputed real and integer - * buffers. This stage of code is highly dependent on internals - * of FTComplexFFTPlanRec() and must be kept synchronized with - * possible changes in internals of plan generation function. - * - * Buffer size is determined as follows: - * * N is factorized - * * we factor out anything which is less or equal to MaxRadix - * * prime factor F>RaderThreshold requires 4*FTBaseFindSmooth(2*F-1) - * real entries to store precomputed Quantities for Bluestein's - * transformation - * * prime factor F<=RaderThreshold does NOT require - * precomputed storage - */ - precrsize = 0; - precisize = 0; - ftbase_ftdeterminespacerequirements(n, &precrsize, &precisize, _state); - if( precrsize>0 ) - { - ae_vector_set_length(&plan->precr, precrsize, _state); - } - if( precisize>0 ) - { - ae_vector_set_length(&plan->preci, precisize, _state); - } - - /* - * Generate plan - */ - rowptr = 0; - precrptr = 0; - preciptr = 0; - bluesteinsize = 1; - ae_vector_set_length(&plan->buffer, 2*n*k, _state); - ftbase_ftcomplexfftplanrec(n, k, ae_true, ae_true, &rowptr, &bluesteinsize, &precrptr, &preciptr, plan, _state); - ae_vector_set_length(&bluesteinbuf.val, bluesteinsize, _state); - ae_shared_pool_set_seed(&plan->bluesteinpool, &bluesteinbuf, sizeof(bluesteinbuf), _srealarray_init, _srealarray_init_copy, _srealarray_destroy, _state); - - /* - * Check that actual amount of precomputed space used by transformation - * plan is EXACTLY equal to amount of space allocated by us. - */ - ae_assert(precrptr==precrsize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); - ae_assert(preciptr==precisize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine applies transformation plan to input/output array A. - -INPUT PARAMETERS: - Plan - transformation plan - A - array, must be large enough for plan to work - OffsA - offset of the subarray to process - RepCnt - repetition count (transformation is repeatedly applied - to subsequent subarrays) - -OUTPUT PARAMETERS: - Plan - plan (temporary buffers can be modified, plan itself - is unchanged and can be reused) - A - transformed array - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -void ftapplyplan(fasttransformplan* plan, - /* Real */ ae_vector* a, - ae_int_t offsa, - ae_int_t repcnt, - ae_state *_state) -{ - ae_int_t plansize; - ae_int_t i; - - - plansize = plan->entries.ptr.pp_int[0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[0][ftbase_colmicrovectorsize]; - for(i=0; i<=repcnt-1; i++) - { - ftbase_ftapplysubplan(plan, 0, a, offsa+plansize*i, 0, &plan->buffer, 1, _state); - } -} - - -/************************************************************************* -Returns good factorization N=N1*N2. - -Usually N1<=N2 (but not always - small N's may be exception). -if N1<>1 then N2<>1. - -Factorization is chosen depending on task type and codelets we have. - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -void ftbasefactorize(ae_int_t n, - ae_int_t tasktype, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state) -{ - ae_int_t j; - - *n1 = 0; - *n2 = 0; - - *n1 = 0; - *n2 = 0; - - /* - * try to find good codelet - */ - if( *n1*(*n2)!=n ) - { - for(j=ftbase_ftbasecodeletrecommended; j>=2; j--) - { - if( n%j==0 ) - { - *n1 = j; - *n2 = n/j; - break; - } - } - } - - /* - * try to factorize N - */ - if( *n1*(*n2)!=n ) - { - for(j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) - { - if( n%j==0 ) - { - *n1 = j; - *n2 = n/j; - break; - } - } - } - - /* - * looks like N is prime :( - */ - if( *n1*(*n2)!=n ) - { - *n1 = 1; - *n2 = n; - } - - /* - * normalize - */ - if( *n2==1&&*n1!=1 ) - { - *n2 = *n1; - *n1 = 1; - } -} - - -/************************************************************************* -Is number smooth? - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state) -{ - ae_int_t i; - ae_bool result; - - - for(i=2; i<=ftbase_ftbasemaxsmoothfactor; i++) - { - while(n%i==0) - { - n = n/i; - } - } - result = n==1; - return result; -} - - -/************************************************************************* -Returns smallest smooth (divisible only by 2, 3, 5) number that is greater -than or equal to max(N,2) - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state) -{ - ae_int_t best; - ae_int_t result; - - - best = 2; - while(bestRaderThreshold requires 4*FTBaseFindSmooth(2*F-1) - * real entries to store precomputed Quantities for Bluestein's - * transformation - * * prime factor F<=RaderThreshold requires 2*(F-1)+ESTIMATE(F-1) - * precomputed storage - */ - ncur = n; - for(i=2; i<=ftbase_maxradix; i++) - { - while(ncur%i==0) - { - ncur = ncur/i; - } - } - f = 2; - while(f<=ncur) - { - while(ncur%f==0) - { - if( f>ftbase_raderthreshold ) - { - *precrsize = *precrsize+4*ftbasefindsmooth(2*f-1, _state); - } - else - { - *precrsize = *precrsize+2*(f-1); - ftbase_ftdeterminespacerequirements(f-1, precrsize, precisize, _state); - } - ncur = ncur/f; - } - f = f+1; - } -} - - -/************************************************************************* -Recurrent function called by FTComplexFFTPlan() and other functions. It -recursively builds transformation plan - -INPUT PARAMETERS: - N - FFT length (in complex numbers), N>=1 - K - number of repetitions, K>=1 - ChildPlan - if True, plan generator inserts OpStart/opEnd in the - plan header/footer. - TopmostPlan - if True, plan generator assumes that it is topmost plan: - * it may use global buffer for transpositions - and there is no other plan which executes in parallel - RowPtr - index which points to past-the-last entry generated so far - BluesteinSize- amount of storage (in real numbers) required for Bluestein buffer - PrecRPtr - pointer to unused part of precomputed real buffer (Plan.PrecR): - * when this function stores some data to precomputed buffer, - it advances pointer. - * it is responsibility of the function to assert that - Plan.PrecR has enough space to store data before actually - writing to buffer. - * it is responsibility of the caller to allocate enough - space before calling this function - PrecIPtr - pointer to unused part of precomputed integer buffer (Plan.PrecI): - * when this function stores some data to precomputed buffer, - it advances pointer. - * it is responsibility of the function to assert that - Plan.PrecR has enough space to store data before actually - writing to buffer. - * it is responsibility of the caller to allocate enough - space before calling this function - Plan - plan (generated so far) - -OUTPUT PARAMETERS: - RowPtr - updated pointer (advanced by number of entries generated - by function) - BluesteinSize- updated amount - (may be increased, but may never be decreased) - -NOTE: in case TopmostPlan is True, ChildPlan is also must be True. - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftcomplexfftplanrec(ae_int_t n, - ae_int_t k, - ae_bool childplan, - ae_bool topmostplan, - ae_int_t* rowptr, - ae_int_t* bluesteinsize, - ae_int_t* precrptr, - ae_int_t* preciptr, - fasttransformplan* plan, - ae_state *_state) -{ - ae_frame _frame_block; - srealarray localbuf; - ae_int_t m; - ae_int_t n1; - ae_int_t n2; - ae_int_t gq; - ae_int_t giq; - ae_int_t row0; - ae_int_t row1; - ae_int_t row2; - ae_int_t row3; - - ae_frame_make(_state, &_frame_block); - _srealarray_init(&localbuf, _state, ae_true); - - ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); - ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); - ae_assert(!topmostplan||childplan, "FTComplexFFTPlan: ChildPlan is inconsistent with TopmostPlan", _state); - - /* - * Try to generate "topmost" plan - */ - if( topmostplan&&n>ftbase_recursivethreshold ) - { - ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); - if( n1*n2==0 ) - { - - /* - * Handle prime-factor FFT with Bluestein's FFT. - * Determine size of Bluestein's buffer. - */ - m = ftbasefindsmooth(2*n-1, _state); - *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); - - /* - * Generate plan - */ - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); - row0 = *rowptr; - ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); - ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_true, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - row1 = *rowptr; - plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - - /* - * Fill precomputed buffer - */ - ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); - - /* - * Update pointer to the precomputed area - */ - *precrptr = *precrptr+4*m; - } - else - { - - /* - * Handle composite FFT with recursive Cooley-Tukey which - * uses global buffer instead of local one. - */ - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - row0 = *rowptr; - ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); - row2 = *rowptr; - ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - row1 = *rowptr; - ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; - row3 = *rowptr; - ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; - } - ae_frame_leave(_state); - return; - } - - /* - * Prepare "non-topmost" plan: - * * calculate factorization - * * use local (shared) buffer - * * update buffer size - ANY plan will need at least - * 2*N temporaries, additional requirements can be - * applied later - */ - ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); - - /* - * Handle FFT's with N1*N2=0: either small-N or prime-factor - */ - if( n1*n2==0 ) - { - if( n<=ftbase_maxradix ) - { - - /* - * Small-N FFT - */ - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodeletfft, k, n, 2, 0, _state); - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - ae_frame_leave(_state); - return; - } - if( n<=ftbase_raderthreshold ) - { - - /* - * Handle prime-factor FFT's with Rader's FFT - */ - m = n-1; - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - findprimitiverootandinverse(n, &gq, &giq, _state); - ftbase_ftpushentry4(plan, rowptr, ftbase_opradersfft, k, n, 2, 2, gq, giq, *precrptr, _state); - ftbase_ftprecomputeradersfft(n, gq, giq, &plan->precr, *precrptr, _state); - *precrptr = *precrptr+2*(n-1); - row0 = *rowptr; - ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); - ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - row1 = *rowptr; - plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - } - else - { - - /* - * Handle prime-factor FFT's with Bluestein's FFT - */ - m = ftbasefindsmooth(2*n-1, _state); - *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); - ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); - *precrptr = *precrptr+4*m; - row0 = *rowptr; - ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); - ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - row1 = *rowptr; - plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - } - ae_frame_leave(_state); - return; - } - - /* - * Handle Cooley-Tukey FFT with small N1 - */ - if( n1<=ftbase_maxradix ) - { - - /* - * Specialized transformation for small N1: - * * N2 short inplace FFT's, each N1-point, with integrated twiddle factors - * * N1 long FFT's - * * final transposition - */ - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodelettwfft, k, n1, 2*n2, 0, _state); - ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - ae_frame_leave(_state); - return; - } - - /* - * Handle general Cooley-Tukey FFT, either "flat" or "recursive" - */ - if( n<=ftbase_recursivethreshold ) - { - - /* - * General code for large N1/N2, "flat" version without explicit recurrence - * (nested subplans are inserted directly into the body of the plan) - */ - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - ftbase_ftcomplexfftplanrec(n1, k*n2, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); - ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - } - else - { - - /* - * General code for large N1/N2, "recursive" version - nested subplans - * are separated from the plan body. - * - * Generate parent plan. - */ - if( childplan ) - { - ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); - } - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - row0 = *rowptr; - ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); - row2 = *rowptr; - ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); - ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); - if( childplan ) - { - ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); - } - - /* - * Generate child subplans, insert refence to parent plans - */ - row1 = *rowptr; - ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; - row3 = *rowptr; - ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); - plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function pushes one more entry to the plan. It resizes Entries matrix -if needed. - -INPUT PARAMETERS: - Plan - plan (generated so far) - RowPtr - index which points to past-the-last entry generated so far - EType - entry type - EOpCnt - operands count - EOpSize - operand size - EMcvSize - microvector size - EParam0 - parameter 0 - -OUTPUT PARAMETERS: - Plan - updated plan - RowPtr - updated pointer - -NOTE: Param1 is set to -1. - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftpushentry(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_state *_state) -{ - - - ftbase_ftpushentry2(plan, rowptr, etype, eopcnt, eopsize, emcvsize, eparam0, -1, _state); -} - - -/************************************************************************* -Same as FTPushEntry(), but sets Param0 AND Param1. -This function pushes one more entry to the plan. It resized Entries matrix -if needed. - -INPUT PARAMETERS: - Plan - plan (generated so far) - RowPtr - index which points to past-the-last entry generated so far - EType - entry type - EOpCnt - operands count - EOpSize - operand size - EMcvSize - microvector size - EParam0 - parameter 0 - EParam1 - parameter 1 - -OUTPUT PARAMETERS: - Plan - updated plan - RowPtr - updated pointer - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftpushentry2(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_int_t eparam1, - ae_state *_state) -{ - - - if( *rowptr>=plan->entries.rows ) - { - imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); - } - plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; - plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; - plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; - plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = 0; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = 0; - *rowptr = *rowptr+1; -} - - -/************************************************************************* -Same as FTPushEntry(), but sets Param0, Param1, Param2 and Param3. -This function pushes one more entry to the plan. It resized Entries matrix -if needed. - -INPUT PARAMETERS: - Plan - plan (generated so far) - RowPtr - index which points to past-the-last entry generated so far - EType - entry type - EOpCnt - operands count - EOpSize - operand size - EMcvSize - microvector size - EParam0 - parameter 0 - EParam1 - parameter 1 - EParam2 - parameter 2 - EParam3 - parameter 3 - -OUTPUT PARAMETERS: - Plan - updated plan - RowPtr - updated pointer - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftpushentry4(fasttransformplan* plan, - ae_int_t* rowptr, - ae_int_t etype, - ae_int_t eopcnt, - ae_int_t eopsize, - ae_int_t emcvsize, - ae_int_t eparam0, - ae_int_t eparam1, - ae_int_t eparam2, - ae_int_t eparam3, - ae_state *_state) -{ - - - if( *rowptr>=plan->entries.rows ) - { - imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); - } - plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; - plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; - plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; - plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = eparam2; - plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = eparam3; - *rowptr = *rowptr+1; -} - - -/************************************************************************* -This subroutine applies subplan to input/output array A. - -INPUT PARAMETERS: - Plan - transformation plan - SubPlan - subplan index - A - array, must be large enough for plan to work - ABase - base offset in array A, this value points to start of - subarray whose length is equal to length of the plan - AOffset - offset with respect to ABase, 0<=AOffsetentries.ptr.pp_int[subplan][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect subplan header", _state); - rowidx = subplan+1; - while(plan->entries.ptr.pp_int[rowidx][ftbase_coltype]!=ftbase_opend) - { - operation = plan->entries.ptr.pp_int[rowidx][ftbase_coltype]; - operandscnt = repcnt*plan->entries.ptr.pp_int[rowidx][ftbase_coloperandscnt]; - operandsize = plan->entries.ptr.pp_int[rowidx][ftbase_coloperandsize]; - microvectorsize = plan->entries.ptr.pp_int[rowidx][ftbase_colmicrovectorsize]; - param0 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; - param1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam1]; - touchint(¶m1, _state); - - /* - * Process "jump" operation - */ - if( operation==ftbase_opjmp ) - { - rowidx = rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; - continue; - } - - /* - * Process "parallel call" operation: - * * we perform initial check for consistency between parent and child plans - * * we call FTSplitAndApplyParallelPlan(), which splits parallel plan into - * several parallel tasks - */ - if( operation==ftbase_opparallelcall ) - { - parentsize = operandsize*microvectorsize; - childsize = plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_colmicrovectorsize]; - ae_assert(plan->entries.ptr.pp_int[rowidx+param0][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect child subplan header", _state); - ae_assert(parentsize==childsize, "FTApplySubPlan: incorrect child subplan header", _state); - chunksize = ae_maxint(ftbase_recursivethreshold/childsize, 1, _state); - lastchunksize = operandscnt%chunksize; - if( lastchunksize==0 ) - { - lastchunksize = chunksize; - } - i = 0; - while(ibluesteinpool, &_bufa, _state); - ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufb, _state); - ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufc, _state); - ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufd, _state); - ftbase_ftbluesteinsfft(plan, a, abase, aoffset, operandscnt, operandsize, plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], &bufa->val, &bufb->val, &bufc->val, &bufd->val, _state); - ae_shared_pool_recycle(&plan->bluesteinpool, &_bufa, _state); - ae_shared_pool_recycle(&plan->bluesteinpool, &_bufb, _state); - ae_shared_pool_recycle(&plan->bluesteinpool, &_bufc, _state); - ae_shared_pool_recycle(&plan->bluesteinpool, &_bufd, _state); - rowidx = rowidx+1; - continue; - } - - /* - * Process Rader's FFT - */ - if( operation==ftbase_opradersfft ) - { - ftbase_ftradersfft(plan, a, abase, aoffset, operandscnt, operandsize, rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], plan->entries.ptr.pp_int[rowidx][ftbase_colparam3], buf, _state); - rowidx = rowidx+1; - continue; - } - - /* - * Process "complex twiddle factors" operation - */ - if( operation==ftbase_opcomplexfftfactors ) - { - ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); - n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; - n2 = operandsize/n1; - for(i=0; i<=operandscnt-1; i++) - { - ftbase_ffttwcalc(a, abase+aoffset+i*operandsize*2, n1, n2, _state); - } - rowidx = rowidx+1; - continue; - } - - /* - * Process "complex transposition" operation - */ - if( operation==ftbase_opcomplextranspose ) - { - ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); - n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; - n2 = operandsize/n1; - for(i=0; i<=operandscnt-1; i++) - { - ftbase_internalcomplexlintranspose(a, n1, n2, abase+aoffset+i*operandsize*2, buf, _state); - } - rowidx = rowidx+1; - continue; - } - - /* - * Error - */ - ae_assert(ae_false, "FTApplySubPlan: unexpected plan type", _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine applies complex reference FFT to input/output array A. - -VERY SLOW OPERATION, do not use it in real life plans :) - -INPUT PARAMETERS: - A - array, must be large enough for plan to work - Offs - offset of the subarray to process - OperandsCnt - operands count (see description of FastTransformPlan) - OperandSize - operand size (see description of FastTransformPlan) - MicrovectorSize-microvector size (see description of FastTransformPlan) - Buf - temporary array, must be at least OperandsCnt*OperandSize*MicrovectorSize - -OUTPUT PARAMETERS: - A - transformed array - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - /* Real */ ae_vector* buf, - ae_state *_state) -{ - ae_int_t opidx; - ae_int_t i; - ae_int_t k; - double hre; - double him; - double c; - double s; - double re; - double im; - ae_int_t n; - - - ae_assert(operandscnt>=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); - ae_assert(operandsize>=1, "FTApplyComplexRefFFT: OperandSize<1", _state); - ae_assert(microvectorsize==2, "FTApplyComplexRefFFT: MicrovectorSize<>2", _state); - n = operandsize; - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - for(i=0; i<=n-1; i++) - { - hre = 0; - him = 0; - for(k=0; k<=n-1; k++) - { - re = a->ptr.p_double[offs+opidx*operandsize*2+2*k+0]; - im = a->ptr.p_double[offs+opidx*operandsize*2+2*k+1]; - c = ae_cos(-2*ae_pi*k*i/n, _state); - s = ae_sin(-2*ae_pi*k*i/n, _state); - hre = hre+c*re-s*im; - him = him+c*im+s*re; - } - buf->ptr.p_double[2*i+0] = hre; - buf->ptr.p_double[2*i+1] = him; - } - for(i=0; i<=operandsize*2-1; i++) - { - a->ptr.p_double[offs+opidx*operandsize*2+i] = buf->ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This subroutine applies complex codelet FFT to input/output array A. - -INPUT PARAMETERS: - A - array, must be large enough for plan to work - Offs - offset of the subarray to process - OperandsCnt - operands count (see description of FastTransformPlan) - OperandSize - operand size (see description of FastTransformPlan) - MicrovectorSize-microvector size, must be 2 - -OUTPUT PARAMETERS: - A - transformed array - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - ae_state *_state) -{ - ae_int_t opidx; - ae_int_t n; - ae_int_t aoffset; - double a0x; - double a0y; - double a1x; - double a1y; - double a2x; - double a2y; - double a3x; - double a3y; - double a4x; - double a4y; - double a5x; - double a5y; - double v0; - double v1; - double v2; - double v3; - double t1x; - double t1y; - double t2x; - double t2y; - double t3x; - double t3y; - double t4x; - double t4y; - double t5x; - double t5y; - double m1x; - double m1y; - double m2x; - double m2y; - double m3x; - double m3y; - double m4x; - double m4y; - double m5x; - double m5y; - double s1x; - double s1y; - double s2x; - double s2y; - double s3x; - double s3y; - double s4x; - double s4y; - double s5x; - double s5y; - double c1; - double c2; - double c3; - double c4; - double c5; - double v; - - - ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); - ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); - ae_assert(microvectorsize==2, "FTApplyComplexCodeletFFT: MicrovectorSize<>2", _state); - n = operandsize; - - /* - * Hard-coded transforms for different N's - */ - ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletFFT: N>MaxRadix", _state); - if( n==2 ) - { - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset = offs+opidx*operandsize*2; - a0x = a->ptr.p_double[aoffset+0]; - a0y = a->ptr.p_double[aoffset+1]; - a1x = a->ptr.p_double[aoffset+2]; - a1y = a->ptr.p_double[aoffset+3]; - v0 = a0x+a1x; - v1 = a0y+a1y; - v2 = a0x-a1x; - v3 = a0y-a1y; - a->ptr.p_double[aoffset+0] = v0; - a->ptr.p_double[aoffset+1] = v1; - a->ptr.p_double[aoffset+2] = v2; - a->ptr.p_double[aoffset+3] = v3; - } - return; - } - if( n==3 ) - { - c1 = ae_cos(2*ae_pi/3, _state)-1; - c2 = ae_sin(2*ae_pi/3, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset = offs+opidx*operandsize*2; - a0x = a->ptr.p_double[aoffset+0]; - a0y = a->ptr.p_double[aoffset+1]; - a1x = a->ptr.p_double[aoffset+2]; - a1y = a->ptr.p_double[aoffset+3]; - a2x = a->ptr.p_double[aoffset+4]; - a2y = a->ptr.p_double[aoffset+5]; - t1x = a1x+a2x; - t1y = a1y+a2y; - a0x = a0x+t1x; - a0y = a0y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a1y-a2y); - m2y = c2*(a2x-a1x); - s1x = a0x+m1x; - s1y = a0y+m1y; - a1x = s1x+m2x; - a1y = s1y+m2y; - a2x = s1x-m2x; - a2y = s1y-m2y; - a->ptr.p_double[aoffset+0] = a0x; - a->ptr.p_double[aoffset+1] = a0y; - a->ptr.p_double[aoffset+2] = a1x; - a->ptr.p_double[aoffset+3] = a1y; - a->ptr.p_double[aoffset+4] = a2x; - a->ptr.p_double[aoffset+5] = a2y; - } - return; - } - if( n==4 ) - { - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset = offs+opidx*operandsize*2; - a0x = a->ptr.p_double[aoffset+0]; - a0y = a->ptr.p_double[aoffset+1]; - a1x = a->ptr.p_double[aoffset+2]; - a1y = a->ptr.p_double[aoffset+3]; - a2x = a->ptr.p_double[aoffset+4]; - a2y = a->ptr.p_double[aoffset+5]; - a3x = a->ptr.p_double[aoffset+6]; - a3y = a->ptr.p_double[aoffset+7]; - t1x = a0x+a2x; - t1y = a0y+a2y; - t2x = a1x+a3x; - t2y = a1y+a3y; - m2x = a0x-a2x; - m2y = a0y-a2y; - m3x = a1y-a3y; - m3y = a3x-a1x; - a->ptr.p_double[aoffset+0] = t1x+t2x; - a->ptr.p_double[aoffset+1] = t1y+t2y; - a->ptr.p_double[aoffset+4] = t1x-t2x; - a->ptr.p_double[aoffset+5] = t1y-t2y; - a->ptr.p_double[aoffset+2] = m2x+m3x; - a->ptr.p_double[aoffset+3] = m2y+m3y; - a->ptr.p_double[aoffset+6] = m2x-m3x; - a->ptr.p_double[aoffset+7] = m2y-m3y; - } - return; - } - if( n==5 ) - { - v = 2*ae_pi/5; - c1 = (ae_cos(v, _state)+ae_cos(2*v, _state))/2-1; - c2 = (ae_cos(v, _state)-ae_cos(2*v, _state))/2; - c3 = -ae_sin(v, _state); - c4 = -(ae_sin(v, _state)+ae_sin(2*v, _state)); - c5 = ae_sin(v, _state)-ae_sin(2*v, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset = offs+opidx*operandsize*2; - t1x = a->ptr.p_double[aoffset+2]+a->ptr.p_double[aoffset+8]; - t1y = a->ptr.p_double[aoffset+3]+a->ptr.p_double[aoffset+9]; - t2x = a->ptr.p_double[aoffset+4]+a->ptr.p_double[aoffset+6]; - t2y = a->ptr.p_double[aoffset+5]+a->ptr.p_double[aoffset+7]; - t3x = a->ptr.p_double[aoffset+2]-a->ptr.p_double[aoffset+8]; - t3y = a->ptr.p_double[aoffset+3]-a->ptr.p_double[aoffset+9]; - t4x = a->ptr.p_double[aoffset+6]-a->ptr.p_double[aoffset+4]; - t4y = a->ptr.p_double[aoffset+7]-a->ptr.p_double[aoffset+5]; - t5x = t1x+t2x; - t5y = t1y+t2y; - a->ptr.p_double[aoffset+0] = a->ptr.p_double[aoffset+0]+t5x; - a->ptr.p_double[aoffset+1] = a->ptr.p_double[aoffset+1]+t5y; - m1x = c1*t5x; - m1y = c1*t5y; - m2x = c2*(t1x-t2x); - m2y = c2*(t1y-t2y); - m3x = -c3*(t3y+t4y); - m3y = c3*(t3x+t4x); - m4x = -c4*t4y; - m4y = c4*t4x; - m5x = -c5*t3y; - m5y = c5*t3x; - s3x = m3x-m4x; - s3y = m3y-m4y; - s5x = m3x+m5x; - s5y = m3y+m5y; - s1x = a->ptr.p_double[aoffset+0]+m1x; - s1y = a->ptr.p_double[aoffset+1]+m1y; - s2x = s1x+m2x; - s2y = s1y+m2y; - s4x = s1x-m2x; - s4y = s1y-m2y; - a->ptr.p_double[aoffset+2] = s2x+s3x; - a->ptr.p_double[aoffset+3] = s2y+s3y; - a->ptr.p_double[aoffset+4] = s4x+s5x; - a->ptr.p_double[aoffset+5] = s4y+s5y; - a->ptr.p_double[aoffset+6] = s4x-s5x; - a->ptr.p_double[aoffset+7] = s4y-s5y; - a->ptr.p_double[aoffset+8] = s2x-s3x; - a->ptr.p_double[aoffset+9] = s2y-s3y; - } - return; - } - if( n==6 ) - { - c1 = ae_cos(2*ae_pi/3, _state)-1; - c2 = ae_sin(2*ae_pi/3, _state); - c3 = ae_cos(-ae_pi/3, _state); - c4 = ae_sin(-ae_pi/3, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset = offs+opidx*operandsize*2; - a0x = a->ptr.p_double[aoffset+0]; - a0y = a->ptr.p_double[aoffset+1]; - a1x = a->ptr.p_double[aoffset+2]; - a1y = a->ptr.p_double[aoffset+3]; - a2x = a->ptr.p_double[aoffset+4]; - a2y = a->ptr.p_double[aoffset+5]; - a3x = a->ptr.p_double[aoffset+6]; - a3y = a->ptr.p_double[aoffset+7]; - a4x = a->ptr.p_double[aoffset+8]; - a4y = a->ptr.p_double[aoffset+9]; - a5x = a->ptr.p_double[aoffset+10]; - a5y = a->ptr.p_double[aoffset+11]; - v0 = a0x; - v1 = a0y; - a0x = a0x+a3x; - a0y = a0y+a3y; - a3x = v0-a3x; - a3y = v1-a3y; - v0 = a1x; - v1 = a1y; - a1x = a1x+a4x; - a1y = a1y+a4y; - a4x = v0-a4x; - a4y = v1-a4y; - v0 = a2x; - v1 = a2y; - a2x = a2x+a5x; - a2y = a2y+a5y; - a5x = v0-a5x; - a5y = v1-a5y; - t4x = a4x*c3-a4y*c4; - t4y = a4x*c4+a4y*c3; - a4x = t4x; - a4y = t4y; - t5x = -a5x*c3-a5y*c4; - t5y = a5x*c4-a5y*c3; - a5x = t5x; - a5y = t5y; - t1x = a1x+a2x; - t1y = a1y+a2y; - a0x = a0x+t1x; - a0y = a0y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a1y-a2y); - m2y = c2*(a2x-a1x); - s1x = a0x+m1x; - s1y = a0y+m1y; - a1x = s1x+m2x; - a1y = s1y+m2y; - a2x = s1x-m2x; - a2y = s1y-m2y; - t1x = a4x+a5x; - t1y = a4y+a5y; - a3x = a3x+t1x; - a3y = a3y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a4y-a5y); - m2y = c2*(a5x-a4x); - s1x = a3x+m1x; - s1y = a3y+m1y; - a4x = s1x+m2x; - a4y = s1y+m2y; - a5x = s1x-m2x; - a5y = s1y-m2y; - a->ptr.p_double[aoffset+0] = a0x; - a->ptr.p_double[aoffset+1] = a0y; - a->ptr.p_double[aoffset+2] = a3x; - a->ptr.p_double[aoffset+3] = a3y; - a->ptr.p_double[aoffset+4] = a1x; - a->ptr.p_double[aoffset+5] = a1y; - a->ptr.p_double[aoffset+6] = a4x; - a->ptr.p_double[aoffset+7] = a4y; - a->ptr.p_double[aoffset+8] = a2x; - a->ptr.p_double[aoffset+9] = a2y; - a->ptr.p_double[aoffset+10] = a5x; - a->ptr.p_double[aoffset+11] = a5y; - } - return; - } -} - - -/************************************************************************* -This subroutine applies complex "integrated" codelet FFT to input/output -array A. "Integrated" codelet differs from "normal" one in following ways: -* it can work with MicrovectorSize>1 -* hence, it can be used in Cooley-Tukey FFT without transpositions -* it performs inlined multiplication by twiddle factors of Cooley-Tukey - FFT with N2=MicrovectorSize/2. - -INPUT PARAMETERS: - A - array, must be large enough for plan to work - Offs - offset of the subarray to process - OperandsCnt - operands count (see description of FastTransformPlan) - OperandSize - operand size (see description of FastTransformPlan) - MicrovectorSize-microvector size, must be 1 - -OUTPUT PARAMETERS: - A - transformed array - - -- ALGLIB -- - Copyright 05.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, - ae_int_t offs, - ae_int_t operandscnt, - ae_int_t operandsize, - ae_int_t microvectorsize, - ae_state *_state) -{ - ae_int_t opidx; - ae_int_t mvidx; - ae_int_t n; - ae_int_t m; - ae_int_t aoffset0; - ae_int_t aoffset2; - ae_int_t aoffset4; - ae_int_t aoffset6; - ae_int_t aoffset8; - ae_int_t aoffset10; - double a0x; - double a0y; - double a1x; - double a1y; - double a2x; - double a2y; - double a3x; - double a3y; - double a4x; - double a4y; - double a5x; - double a5y; - double v0; - double v1; - double v2; - double v3; - double q0x; - double q0y; - double t1x; - double t1y; - double t2x; - double t2y; - double t3x; - double t3y; - double t4x; - double t4y; - double t5x; - double t5y; - double m1x; - double m1y; - double m2x; - double m2y; - double m3x; - double m3y; - double m4x; - double m4y; - double m5x; - double m5y; - double s1x; - double s1y; - double s2x; - double s2y; - double s3x; - double s3y; - double s4x; - double s4y; - double s5x; - double s5y; - double c1; - double c2; - double c3; - double c4; - double c5; - double v; - double tw0; - double tw1; - double twx; - double twxm1; - double twy; - double tw2x; - double tw2y; - double tw3x; - double tw3y; - double tw4x; - double tw4y; - double tw5x; - double tw5y; - - - ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); - ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); - ae_assert(microvectorsize>=1, "FTApplyComplexCodeletFFT: MicrovectorSize<>1", _state); - ae_assert(microvectorsize%2==0, "FTApplyComplexCodeletFFT: MicrovectorSize is not even", _state); - n = operandsize; - m = microvectorsize/2; - - /* - * Hard-coded transforms for different N's - */ - ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletTwFFT: N>MaxRadix", _state); - if( n==2 ) - { - v = -2*ae_pi/(n*m); - tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - tw1 = ae_sin(v, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset0 = offs+opidx*operandsize*microvectorsize; - aoffset2 = aoffset0+microvectorsize; - twxm1 = 0.0; - twy = 0.0; - for(mvidx=0; mvidx<=m-1; mvidx++) - { - a0x = a->ptr.p_double[aoffset0]; - a0y = a->ptr.p_double[aoffset0+1]; - a1x = a->ptr.p_double[aoffset2]; - a1y = a->ptr.p_double[aoffset2+1]; - v0 = a0x+a1x; - v1 = a0y+a1y; - v2 = a0x-a1x; - v3 = a0y-a1y; - a->ptr.p_double[aoffset0] = v0; - a->ptr.p_double[aoffset0+1] = v1; - a->ptr.p_double[aoffset2] = v2*(1+twxm1)-v3*twy; - a->ptr.p_double[aoffset2+1] = v3*(1+twxm1)+v2*twy; - aoffset0 = aoffset0+2; - aoffset2 = aoffset2+2; - if( (mvidx+1)%ftbase_updatetw==0 ) - { - v = -2*ae_pi*(mvidx+1)/(n*m); - twxm1 = ae_sin(0.5*v, _state); - twxm1 = -2*twxm1*twxm1; - twy = ae_sin(v, _state); - } - else - { - v = twxm1+tw0+twxm1*tw0-twy*tw1; - twy = twy+tw1+twxm1*tw1+twy*tw0; - twxm1 = v; - } - } - } - return; - } - if( n==3 ) - { - v = -2*ae_pi/(n*m); - tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - tw1 = ae_sin(v, _state); - c1 = ae_cos(2*ae_pi/3, _state)-1; - c2 = ae_sin(2*ae_pi/3, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset0 = offs+opidx*operandsize*microvectorsize; - aoffset2 = aoffset0+microvectorsize; - aoffset4 = aoffset2+microvectorsize; - twx = 1.0; - twxm1 = 0.0; - twy = 0.0; - for(mvidx=0; mvidx<=m-1; mvidx++) - { - a0x = a->ptr.p_double[aoffset0]; - a0y = a->ptr.p_double[aoffset0+1]; - a1x = a->ptr.p_double[aoffset2]; - a1y = a->ptr.p_double[aoffset2+1]; - a2x = a->ptr.p_double[aoffset4]; - a2y = a->ptr.p_double[aoffset4+1]; - t1x = a1x+a2x; - t1y = a1y+a2y; - a0x = a0x+t1x; - a0y = a0y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a1y-a2y); - m2y = c2*(a2x-a1x); - s1x = a0x+m1x; - s1y = a0y+m1y; - a1x = s1x+m2x; - a1y = s1y+m2y; - a2x = s1x-m2x; - a2y = s1y-m2y; - tw2x = twx*twx-twy*twy; - tw2y = 2*twx*twy; - a->ptr.p_double[aoffset0] = a0x; - a->ptr.p_double[aoffset0+1] = a0y; - a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; - a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; - a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; - a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; - aoffset0 = aoffset0+2; - aoffset2 = aoffset2+2; - aoffset4 = aoffset4+2; - if( (mvidx+1)%ftbase_updatetw==0 ) - { - v = -2*ae_pi*(mvidx+1)/(n*m); - twxm1 = ae_sin(0.5*v, _state); - twxm1 = -2*twxm1*twxm1; - twy = ae_sin(v, _state); - twx = twxm1+1; - } - else - { - v = twxm1+tw0+twxm1*tw0-twy*tw1; - twy = twy+tw1+twxm1*tw1+twy*tw0; - twxm1 = v; - twx = v+1; - } - } - } - return; - } - if( n==4 ) - { - v = -2*ae_pi/(n*m); - tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - tw1 = ae_sin(v, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset0 = offs+opidx*operandsize*microvectorsize; - aoffset2 = aoffset0+microvectorsize; - aoffset4 = aoffset2+microvectorsize; - aoffset6 = aoffset4+microvectorsize; - twx = 1.0; - twxm1 = 0.0; - twy = 0.0; - for(mvidx=0; mvidx<=m-1; mvidx++) - { - a0x = a->ptr.p_double[aoffset0]; - a0y = a->ptr.p_double[aoffset0+1]; - a1x = a->ptr.p_double[aoffset2]; - a1y = a->ptr.p_double[aoffset2+1]; - a2x = a->ptr.p_double[aoffset4]; - a2y = a->ptr.p_double[aoffset4+1]; - a3x = a->ptr.p_double[aoffset6]; - a3y = a->ptr.p_double[aoffset6+1]; - t1x = a0x+a2x; - t1y = a0y+a2y; - t2x = a1x+a3x; - t2y = a1y+a3y; - m2x = a0x-a2x; - m2y = a0y-a2y; - m3x = a1y-a3y; - m3y = a3x-a1x; - tw2x = twx*twx-twy*twy; - tw2y = 2*twx*twy; - tw3x = twx*tw2x-twy*tw2y; - tw3y = twx*tw2y+twy*tw2x; - a1x = m2x+m3x; - a1y = m2y+m3y; - a2x = t1x-t2x; - a2y = t1y-t2y; - a3x = m2x-m3x; - a3y = m2y-m3y; - a->ptr.p_double[aoffset0] = t1x+t2x; - a->ptr.p_double[aoffset0+1] = t1y+t2y; - a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; - a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; - a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; - a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; - a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; - a->ptr.p_double[aoffset6+1] = a3y*tw3x+a3x*tw3y; - aoffset0 = aoffset0+2; - aoffset2 = aoffset2+2; - aoffset4 = aoffset4+2; - aoffset6 = aoffset6+2; - if( (mvidx+1)%ftbase_updatetw==0 ) - { - v = -2*ae_pi*(mvidx+1)/(n*m); - twxm1 = ae_sin(0.5*v, _state); - twxm1 = -2*twxm1*twxm1; - twy = ae_sin(v, _state); - twx = twxm1+1; - } - else - { - v = twxm1+tw0+twxm1*tw0-twy*tw1; - twy = twy+tw1+twxm1*tw1+twy*tw0; - twxm1 = v; - twx = v+1; - } - } - } - return; - } - if( n==5 ) - { - v = -2*ae_pi/(n*m); - tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - tw1 = ae_sin(v, _state); - v = 2*ae_pi/5; - c1 = (ae_cos(v, _state)+ae_cos(2*v, _state))/2-1; - c2 = (ae_cos(v, _state)-ae_cos(2*v, _state))/2; - c3 = -ae_sin(v, _state); - c4 = -(ae_sin(v, _state)+ae_sin(2*v, _state)); - c5 = ae_sin(v, _state)-ae_sin(2*v, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset0 = offs+opidx*operandsize*microvectorsize; - aoffset2 = aoffset0+microvectorsize; - aoffset4 = aoffset2+microvectorsize; - aoffset6 = aoffset4+microvectorsize; - aoffset8 = aoffset6+microvectorsize; - twx = 1.0; - twxm1 = 0.0; - twy = 0.0; - for(mvidx=0; mvidx<=m-1; mvidx++) - { - a0x = a->ptr.p_double[aoffset0]; - a0y = a->ptr.p_double[aoffset0+1]; - a1x = a->ptr.p_double[aoffset2]; - a1y = a->ptr.p_double[aoffset2+1]; - a2x = a->ptr.p_double[aoffset4]; - a2y = a->ptr.p_double[aoffset4+1]; - a3x = a->ptr.p_double[aoffset6]; - a3y = a->ptr.p_double[aoffset6+1]; - a4x = a->ptr.p_double[aoffset8]; - a4y = a->ptr.p_double[aoffset8+1]; - t1x = a1x+a4x; - t1y = a1y+a4y; - t2x = a2x+a3x; - t2y = a2y+a3y; - t3x = a1x-a4x; - t3y = a1y-a4y; - t4x = a3x-a2x; - t4y = a3y-a2y; - t5x = t1x+t2x; - t5y = t1y+t2y; - q0x = a0x+t5x; - q0y = a0y+t5y; - m1x = c1*t5x; - m1y = c1*t5y; - m2x = c2*(t1x-t2x); - m2y = c2*(t1y-t2y); - m3x = -c3*(t3y+t4y); - m3y = c3*(t3x+t4x); - m4x = -c4*t4y; - m4y = c4*t4x; - m5x = -c5*t3y; - m5y = c5*t3x; - s3x = m3x-m4x; - s3y = m3y-m4y; - s5x = m3x+m5x; - s5y = m3y+m5y; - s1x = q0x+m1x; - s1y = q0y+m1y; - s2x = s1x+m2x; - s2y = s1y+m2y; - s4x = s1x-m2x; - s4y = s1y-m2y; - tw2x = twx*twx-twy*twy; - tw2y = 2*twx*twy; - tw3x = twx*tw2x-twy*tw2y; - tw3y = twx*tw2y+twy*tw2x; - tw4x = tw2x*tw2x-tw2y*tw2y; - tw4y = tw2x*tw2y+tw2y*tw2x; - a1x = s2x+s3x; - a1y = s2y+s3y; - a2x = s4x+s5x; - a2y = s4y+s5y; - a3x = s4x-s5x; - a3y = s4y-s5y; - a4x = s2x-s3x; - a4y = s2y-s3y; - a->ptr.p_double[aoffset0] = q0x; - a->ptr.p_double[aoffset0+1] = q0y; - a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; - a->ptr.p_double[aoffset2+1] = a1x*twy+a1y*twx; - a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; - a->ptr.p_double[aoffset4+1] = a2x*tw2y+a2y*tw2x; - a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; - a->ptr.p_double[aoffset6+1] = a3x*tw3y+a3y*tw3x; - a->ptr.p_double[aoffset8] = a4x*tw4x-a4y*tw4y; - a->ptr.p_double[aoffset8+1] = a4x*tw4y+a4y*tw4x; - aoffset0 = aoffset0+2; - aoffset2 = aoffset2+2; - aoffset4 = aoffset4+2; - aoffset6 = aoffset6+2; - aoffset8 = aoffset8+2; - if( (mvidx+1)%ftbase_updatetw==0 ) - { - v = -2*ae_pi*(mvidx+1)/(n*m); - twxm1 = ae_sin(0.5*v, _state); - twxm1 = -2*twxm1*twxm1; - twy = ae_sin(v, _state); - twx = twxm1+1; - } - else - { - v = twxm1+tw0+twxm1*tw0-twy*tw1; - twy = twy+tw1+twxm1*tw1+twy*tw0; - twxm1 = v; - twx = v+1; - } - } - } - return; - } - if( n==6 ) - { - c1 = ae_cos(2*ae_pi/3, _state)-1; - c2 = ae_sin(2*ae_pi/3, _state); - c3 = ae_cos(-ae_pi/3, _state); - c4 = ae_sin(-ae_pi/3, _state); - v = -2*ae_pi/(n*m); - tw0 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - tw1 = ae_sin(v, _state); - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - aoffset0 = offs+opidx*operandsize*microvectorsize; - aoffset2 = aoffset0+microvectorsize; - aoffset4 = aoffset2+microvectorsize; - aoffset6 = aoffset4+microvectorsize; - aoffset8 = aoffset6+microvectorsize; - aoffset10 = aoffset8+microvectorsize; - twx = 1.0; - twxm1 = 0.0; - twy = 0.0; - for(mvidx=0; mvidx<=m-1; mvidx++) - { - a0x = a->ptr.p_double[aoffset0+0]; - a0y = a->ptr.p_double[aoffset0+1]; - a1x = a->ptr.p_double[aoffset2+0]; - a1y = a->ptr.p_double[aoffset2+1]; - a2x = a->ptr.p_double[aoffset4+0]; - a2y = a->ptr.p_double[aoffset4+1]; - a3x = a->ptr.p_double[aoffset6+0]; - a3y = a->ptr.p_double[aoffset6+1]; - a4x = a->ptr.p_double[aoffset8+0]; - a4y = a->ptr.p_double[aoffset8+1]; - a5x = a->ptr.p_double[aoffset10+0]; - a5y = a->ptr.p_double[aoffset10+1]; - v0 = a0x; - v1 = a0y; - a0x = a0x+a3x; - a0y = a0y+a3y; - a3x = v0-a3x; - a3y = v1-a3y; - v0 = a1x; - v1 = a1y; - a1x = a1x+a4x; - a1y = a1y+a4y; - a4x = v0-a4x; - a4y = v1-a4y; - v0 = a2x; - v1 = a2y; - a2x = a2x+a5x; - a2y = a2y+a5y; - a5x = v0-a5x; - a5y = v1-a5y; - t4x = a4x*c3-a4y*c4; - t4y = a4x*c4+a4y*c3; - a4x = t4x; - a4y = t4y; - t5x = -a5x*c3-a5y*c4; - t5y = a5x*c4-a5y*c3; - a5x = t5x; - a5y = t5y; - t1x = a1x+a2x; - t1y = a1y+a2y; - a0x = a0x+t1x; - a0y = a0y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a1y-a2y); - m2y = c2*(a2x-a1x); - s1x = a0x+m1x; - s1y = a0y+m1y; - a1x = s1x+m2x; - a1y = s1y+m2y; - a2x = s1x-m2x; - a2y = s1y-m2y; - t1x = a4x+a5x; - t1y = a4y+a5y; - a3x = a3x+t1x; - a3y = a3y+t1y; - m1x = c1*t1x; - m1y = c1*t1y; - m2x = c2*(a4y-a5y); - m2y = c2*(a5x-a4x); - s1x = a3x+m1x; - s1y = a3y+m1y; - a4x = s1x+m2x; - a4y = s1y+m2y; - a5x = s1x-m2x; - a5y = s1y-m2y; - tw2x = twx*twx-twy*twy; - tw2y = 2*twx*twy; - tw3x = twx*tw2x-twy*tw2y; - tw3y = twx*tw2y+twy*tw2x; - tw4x = tw2x*tw2x-tw2y*tw2y; - tw4y = 2*tw2x*tw2y; - tw5x = tw3x*tw2x-tw3y*tw2y; - tw5y = tw3x*tw2y+tw3y*tw2x; - a->ptr.p_double[aoffset0+0] = a0x; - a->ptr.p_double[aoffset0+1] = a0y; - a->ptr.p_double[aoffset2+0] = a3x*twx-a3y*twy; - a->ptr.p_double[aoffset2+1] = a3y*twx+a3x*twy; - a->ptr.p_double[aoffset4+0] = a1x*tw2x-a1y*tw2y; - a->ptr.p_double[aoffset4+1] = a1y*tw2x+a1x*tw2y; - a->ptr.p_double[aoffset6+0] = a4x*tw3x-a4y*tw3y; - a->ptr.p_double[aoffset6+1] = a4y*tw3x+a4x*tw3y; - a->ptr.p_double[aoffset8+0] = a2x*tw4x-a2y*tw4y; - a->ptr.p_double[aoffset8+1] = a2y*tw4x+a2x*tw4y; - a->ptr.p_double[aoffset10+0] = a5x*tw5x-a5y*tw5y; - a->ptr.p_double[aoffset10+1] = a5y*tw5x+a5x*tw5y; - aoffset0 = aoffset0+2; - aoffset2 = aoffset2+2; - aoffset4 = aoffset4+2; - aoffset6 = aoffset6+2; - aoffset8 = aoffset8+2; - aoffset10 = aoffset10+2; - if( (mvidx+1)%ftbase_updatetw==0 ) - { - v = -2*ae_pi*(mvidx+1)/(n*m); - twxm1 = ae_sin(0.5*v, _state); - twxm1 = -2*twxm1*twxm1; - twy = ae_sin(v, _state); - twx = twxm1+1; - } - else - { - v = twxm1+tw0+twxm1*tw0-twy*tw1; - twy = twy+tw1+twxm1*tw1+twy*tw0; - twxm1 = v; - twx = v+1; - } - } - } - return; - } -} - - -/************************************************************************* -This subroutine precomputes data for complex Bluestein's FFT and writes -them to array PrecR[] at specified offset. It is responsibility of the -caller to make sure that PrecR[] is large enough. - -INPUT PARAMETERS: - N - original size of the transform - M - size of the "padded" Bluestein's transform - PrecR - preallocated array - Offs - offset - -OUTPUT PARAMETERS: - PrecR - data at Offs:Offs+4*M-1 are modified: - * PrecR[Offs:Offs+2*M-1] stores Z[k]=exp(i*pi*k^2/N) - * PrecR[Offs+2*M:Offs+4*M-1] stores FFT of the Z - Other parts of PrecR are unchanged. - -NOTE: this function performs internal M-point FFT. It allocates temporary - plan which is destroyed after leaving this function. - - -- ALGLIB -- - Copyright 08.05.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* precr, - ae_int_t offs, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - double bx; - double by; - fasttransformplan plan; - - ae_frame_make(_state, &_frame_block); - _fasttransformplan_init(&plan, _state, ae_true); - - - /* - * Fill first half of PrecR with b[k] = exp(i*pi*k^2/N) - */ - for(i=0; i<=2*m-1; i++) - { - precr->ptr.p_double[offs+i] = 0; - } - for(i=0; i<=n-1; i++) - { - bx = ae_cos(ae_pi/n*i*i, _state); - by = ae_sin(ae_pi/n*i*i, _state); - precr->ptr.p_double[offs+2*i+0] = bx; - precr->ptr.p_double[offs+2*i+1] = by; - precr->ptr.p_double[offs+2*((m-i)%m)+0] = bx; - precr->ptr.p_double[offs+2*((m-i)%m)+1] = by; - } - - /* - * Precomputed FFT - */ - ftcomplexfftplan(m, 1, &plan, _state); - for(i=0; i<=2*m-1; i++) - { - precr->ptr.p_double[offs+2*m+i] = precr->ptr.p_double[offs+i]; - } - ftbase_ftapplysubplan(&plan, 0, precr, offs+2*m, 0, &plan.buffer, 1, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine applies complex Bluestein's FFT to input/output array A. - -INPUT PARAMETERS: - Plan - transformation plan - A - array, must be large enough for plan to work - ABase - base offset in array A, this value points to start of - subarray whose length is equal to length of the plan - AOffset - offset with respect to ABase, 0<=AOffsetptr.p_double[p0+0]; - y = a->ptr.p_double[p0+1]; - bx = plan->precr.ptr.p_double[p1+0]; - by = -plan->precr.ptr.p_double[p1+1]; - bufa->ptr.p_double[2*i+0] = x*bx-y*by; - bufa->ptr.p_double[2*i+1] = x*by+y*bx; - p0 = p0+2; - p1 = p1+2; - } - for(i=2*n; i<=2*m-1; i++) - { - bufa->ptr.p_double[i] = 0; - } - - /* - * Perform convolution of A and Z (using precomputed - * FFT of Z stored in Plan structure). - */ - ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); - p0 = 0; - p1 = precoffs+2*m; - for(i=0; i<=m-1; i++) - { - ax = bufa->ptr.p_double[p0+0]; - ay = bufa->ptr.p_double[p0+1]; - bx = plan->precr.ptr.p_double[p1+0]; - by = plan->precr.ptr.p_double[p1+1]; - bufa->ptr.p_double[p0+0] = ax*bx-ay*by; - bufa->ptr.p_double[p0+1] = -(ax*by+ay*bx); - p0 = p0+2; - p1 = p1+2; - } - ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); - - /* - * Post processing: - * A:=conj(Z)*conj(A)/M - * Here conj(A)/M corresponds to last stage of inverse DFT, - * and conj(Z) comes from Bluestein's FFT algorithm. - */ - p0 = precoffs; - p1 = 0; - p2 = abase+aoffset+op*2*n; - for(i=0; i<=n-1; i++) - { - bx = plan->precr.ptr.p_double[p0+0]; - by = plan->precr.ptr.p_double[p0+1]; - rx = bufa->ptr.p_double[p1+0]/m; - ry = -bufa->ptr.p_double[p1+1]/m; - a->ptr.p_double[p2+0] = rx*bx-ry*(-by); - a->ptr.p_double[p2+1] = rx*(-by)+ry*bx; - p0 = p0+2; - p1 = p1+2; - p2 = p2+2; - } - } -} - - -/************************************************************************* -This subroutine precomputes data for complex Rader's FFT and writes them -to array PrecR[] at specified offset. It is responsibility of the caller -to make sure that PrecR[] is large enough. - -INPUT PARAMETERS: - N - original size of the transform (before reduction to N-1) - RQ - primitive root modulo N - RIQ - inverse of primitive root modulo N - PrecR - preallocated array - Offs - offset - -OUTPUT PARAMETERS: - PrecR - data at Offs:Offs+2*(N-1)-1 store FFT of Rader's factors, - other parts of PrecR are unchanged. - -NOTE: this function performs internal (N-1)-point FFT. It allocates temporary - plan which is destroyed after leaving this function. - - -- ALGLIB -- - Copyright 08.05.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftprecomputeradersfft(ae_int_t n, - ae_int_t rq, - ae_int_t riq, - /* Real */ ae_vector* precr, - ae_int_t offs, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t q; - fasttransformplan plan; - ae_int_t kiq; - double v; - - ae_frame_make(_state, &_frame_block); - _fasttransformplan_init(&plan, _state, ae_true); - - - /* - * Fill PrecR with Rader factors, perform FFT - */ - kiq = 1; - for(q=0; q<=n-2; q++) - { - v = -2*ae_pi*kiq/n; - precr->ptr.p_double[offs+2*q+0] = ae_cos(v, _state); - precr->ptr.p_double[offs+2*q+1] = ae_sin(v, _state); - kiq = kiq*riq%n; - } - ftcomplexfftplan(n-1, 1, &plan, _state); - ftbase_ftapplysubplan(&plan, 0, precr, offs, 0, &plan.buffer, 1, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine applies complex Rader's FFT to input/output array A. - -INPUT PARAMETERS: - A - array, must be large enough for plan to work - ABase - base offset in array A, this value points to start of - subarray whose length is equal to length of the plan - AOffset - offset with respect to ABase, 0<=AOffset=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); - - /* - * Process operands - */ - for(opidx=0; opidx<=operandscnt-1; opidx++) - { - - /* - * fill QA - */ - kq = 1; - p0 = abase+aoffset+opidx*n*2; - p1 = aoffset+opidx*n*2; - rx = a->ptr.p_double[p0+0]; - ry = a->ptr.p_double[p0+1]; - x0 = rx; - y0 = ry; - for(q=0; q<=n-2; q++) - { - ax = a->ptr.p_double[p0+2*kq+0]; - ay = a->ptr.p_double[p0+2*kq+1]; - buf->ptr.p_double[p1+0] = ax; - buf->ptr.p_double[p1+1] = ay; - rx = rx+ax; - ry = ry+ay; - kq = kq*rq%n; - p1 = p1+2; - } - p0 = abase+aoffset+opidx*n*2; - p1 = aoffset+opidx*n*2; - for(q=0; q<=n-2; q++) - { - a->ptr.p_double[p0] = buf->ptr.p_double[p1]; - a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; - p0 = p0+2; - p1 = p1+2; - } - - /* - * Convolution - */ - ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); - p0 = abase+aoffset+opidx*n*2; - p1 = precoffs; - for(i=0; i<=n-2; i++) - { - ax = a->ptr.p_double[p0+0]; - ay = a->ptr.p_double[p0+1]; - bx = plan->precr.ptr.p_double[p1+0]; - by = plan->precr.ptr.p_double[p1+1]; - a->ptr.p_double[p0+0] = ax*bx-ay*by; - a->ptr.p_double[p0+1] = -(ax*by+ay*bx); - p0 = p0+2; - p1 = p1+2; - } - ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); - p0 = abase+aoffset+opidx*n*2; - for(i=0; i<=n-2; i++) - { - a->ptr.p_double[p0+0] = a->ptr.p_double[p0+0]/(n-1); - a->ptr.p_double[p0+1] = -a->ptr.p_double[p0+1]/(n-1); - p0 = p0+2; - } - - /* - * Result - */ - buf->ptr.p_double[aoffset+opidx*n*2+0] = rx; - buf->ptr.p_double[aoffset+opidx*n*2+1] = ry; - kiq = 1; - p0 = aoffset+opidx*n*2; - p1 = abase+aoffset+opidx*n*2; - for(q=0; q<=n-2; q++) - { - buf->ptr.p_double[p0+2*kiq+0] = x0+a->ptr.p_double[p1+0]; - buf->ptr.p_double[p0+2*kiq+1] = y0+a->ptr.p_double[p1+1]; - kiq = kiq*riq%n; - p1 = p1+2; - } - p0 = abase+aoffset+opidx*n*2; - p1 = aoffset+opidx*n*2; - for(q=0; q<=n-1; q++) - { - a->ptr.p_double[p0] = buf->ptr.p_double[p1]; - a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; - p0 = p0+2; - p1 = p1+2; - } - } -} - - -/************************************************************************* -Factorizes task size N into product of two smaller sizes N1 and N2 - -INPUT PARAMETERS: - N - task size, N>0 - IsRoot - whether taks is root task (first one in a sequence) - -OUTPUT PARAMETERS: - N1, N2 - such numbers that: - * for prime N: N1=N2=0 - * for composite N<=MaxRadix: N1=N2=0 - * for composite N>MaxRadix: 1<=N1<=N2, N1*N2=N - - -- ALGLIB -- - Copyright 08.04.2013 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftfactorize(ae_int_t n, - ae_bool isroot, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state) -{ - ae_int_t j; - ae_int_t k; - - *n1 = 0; - *n2 = 0; - - ae_assert(n>0, "FTFactorize: N<=0", _state); - *n1 = 0; - *n2 = 0; - - /* - * Small N - */ - if( n<=ftbase_maxradix ) - { - return; - } - - /* - * Large N, recursive split - */ - if( n>ftbase_recursivethreshold ) - { - k = ae_iceil(ae_sqrt(n, _state), _state)+1; - ae_assert(k*k>=n, "FTFactorize: internal error during recursive factorization", _state); - for(j=k; j>=2; j--) - { - if( n%j==0 ) - { - *n1 = ae_minint(n/j, j, _state); - *n2 = ae_maxint(n/j, j, _state); - return; - } - } - } - - /* - * N>MaxRadix, try to find good codelet - */ - for(j=ftbase_maxradix; j>=2; j--) - { - if( n%j==0 ) - { - *n1 = j; - *n2 = n/j; - break; - } - } - - /* - * In case no good codelet was found, - * try to factorize N into product of ANY primes. - */ - if( *n1*(*n2)!=n ) - { - for(j=2; j<=n-1; j++) - { - if( n%j==0 ) - { - *n1 = j; - *n2 = n/j; - break; - } - if( j*j>n ) - { - break; - } - } - } - - /* - * normalize - */ - if( *n1>(*n2) ) - { - j = *n1; - *n1 = *n2; - *n2 = j; - } -} - - -/************************************************************************* -Returns optimistic estimate of the FFT cost, in UNITs (1 UNIT = 100 KFLOPs) - -INPUT PARAMETERS: - N - task size, N>0 - -RESULU: - cost in UNITs, rounded down to nearest integer - -NOTE: If FFT cost is less than 1 UNIT, it will return 0 as result. - - -- ALGLIB -- - Copyright 08.04.2013 by Bochkanov Sergey -*************************************************************************/ -static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state) -{ - ae_int_t result; - - - ae_assert(n>0, "FTOptimisticEstimate: N<=0", _state); - result = ae_ifloor(1.0E-5*5*n*ae_log(n, _state)/ae_log(2, _state), _state); - return result; -} - - -/************************************************************************* -Twiddle factors calculation - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ffttwcalc(/* Real */ ae_vector* a, - ae_int_t aoffset, - ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j2; - ae_int_t n; - ae_int_t halfn1; - ae_int_t offs; - double x; - double y; - double twxm1; - double twy; - double twbasexm1; - double twbasey; - double twrowxm1; - double twrowy; - double tmpx; - double tmpy; - double v; - ae_int_t updatetw2; - - - - /* - * Multiplication by twiddle factors for complex Cooley-Tukey FFT - * with N factorized as N1*N2. - * - * Naive solution to this problem is given below: - * - * > for K:=1 to N2-1 do - * > for J:=1 to N1-1 do - * > begin - * > Idx:=K*N1+J; - * > X:=A[AOffset+2*Idx+0]; - * > Y:=A[AOffset+2*Idx+1]; - * > TwX:=Cos(-2*Pi()*K*J/(N1*N2)); - * > TwY:=Sin(-2*Pi()*K*J/(N1*N2)); - * > A[AOffset+2*Idx+0]:=X*TwX-Y*TwY; - * > A[AOffset+2*Idx+1]:=X*TwY+Y*TwX; - * > end; - * - * However, there are exist more efficient solutions. - * - * Each pass of the inner cycle corresponds to multiplication of one - * entry of A by W[k,j]=exp(-I*2*pi*k*j/N). This factor can be rewritten - * as exp(-I*2*pi*k/N)^j. So we can replace costly exponentiation by - * repeated multiplication: W[k,j+1]=W[k,j]*exp(-I*2*pi*k/N), with - * second factor being computed once in the beginning of the iteration. - * - * Also, exp(-I*2*pi*k/N) can be represented as exp(-I*2*pi/N)^k, i.e. - * we have W[K+1,1]=W[K,1]*W[1,1]. - * - * In our loop we use following variables: - * * [TwBaseXM1,TwBaseY] = [cos(2*pi/N)-1, sin(2*pi/N)] - * * [TwRowXM1, TwRowY] = [cos(2*pi*I/N)-1, sin(2*pi*I/N)] - * * [TwXM1, TwY] = [cos(2*pi*I*J/N)-1, sin(2*pi*I*J/N)] - * - * Meaning of the variables: - * * [TwXM1,TwY] is current twiddle factor W[I,J] - * * [TwRowXM1, TwRowY] is W[I,1] - * * [TwBaseXM1,TwBaseY] is W[1,1] - * - * During inner loop we multiply current twiddle factor by W[I,1], - * during outer loop we update W[I,1]. - * - */ - ae_assert(ftbase_updatetw>=2, "FFTTwCalc: internal error - UpdateTw<2", _state); - updatetw2 = ftbase_updatetw/2; - halfn1 = n1/2; - n = n1*n2; - v = -2*ae_pi/n; - twbasexm1 = -2*ae_sqr(ae_sin(0.5*v, _state), _state); - twbasey = ae_sin(v, _state); - twrowxm1 = 0; - twrowy = 0; - offs = aoffset; - for(i=0; i<=n2-1; i++) - { - - /* - * Initialize twiddle factor for current row - */ - twxm1 = 0; - twy = 0; - - /* - * N1-point block is separated into 2-point chunks and residual 1-point chunk - * (in case N1 is odd). Unrolled loop is several times faster. - */ - for(j2=0; j2<=halfn1-1; j2++) - { - - /* - * Processing: - * * process first element in a chunk. - * * update twiddle factor (unconditional update) - * * process second element - * * conditional update of the twiddle factor - */ - x = a->ptr.p_double[offs+0]; - y = a->ptr.p_double[offs+1]; - tmpx = x*(1+twxm1)-y*twy; - tmpy = x*twy+y*(1+twxm1); - a->ptr.p_double[offs+0] = tmpx; - a->ptr.p_double[offs+1] = tmpy; - tmpx = (1+twxm1)*twrowxm1-twy*twrowy; - twy = twy+(1+twxm1)*twrowy+twy*twrowxm1; - twxm1 = twxm1+tmpx; - x = a->ptr.p_double[offs+2]; - y = a->ptr.p_double[offs+3]; - tmpx = x*(1+twxm1)-y*twy; - tmpy = x*twy+y*(1+twxm1); - a->ptr.p_double[offs+2] = tmpx; - a->ptr.p_double[offs+3] = tmpy; - offs = offs+4; - if( (j2+1)%updatetw2==0&&j2ptr.p_double[offs+0]; - y = a->ptr.p_double[offs+1]; - tmpx = x*(1+twxm1)-y*twy; - tmpy = x*twy+y*(1+twxm1); - a->ptr.p_double[offs+0] = tmpx; - a->ptr.p_double[offs+1] = tmpy; - offs = offs+2; - } - - /* - * update TwRow: TwRow(new) = TwRow(old)*TwBase - */ - if( iptr.p_double[astart], 1, &buf->ptr.p_double[0], 1, ae_v_len(astart,astart+2*m*n-1)); -} - - -/************************************************************************* -Recurrent subroutine for a InternalComplexLinTranspose - -Write A^T to B, where: -* A is m*n complex matrix stored in array A as pairs of real/image values, - beginning from AStart position, with AStride stride -* B is n*m complex matrix stored in array B as pairs of real/image values, - beginning from BStart position, with BStride stride -stride is measured in complex numbers, i.e. in real/image pairs. - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ffticltrec(/* Real */ ae_vector* a, - ae_int_t astart, - ae_int_t astride, - /* Real */ ae_vector* b, - ae_int_t bstart, - ae_int_t bstride, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t idx1; - ae_int_t idx2; - ae_int_t m2; - ae_int_t m1; - ae_int_t n1; - - - if( m==0||n==0 ) - { - return; - } - if( ae_maxint(m, n, _state)<=8 ) - { - m2 = 2*bstride; - for(i=0; i<=m-1; i++) - { - idx1 = bstart+2*i; - idx2 = astart+2*i*astride; - for(j=0; j<=n-1; j++) - { - b->ptr.p_double[idx1+0] = a->ptr.p_double[idx2+0]; - b->ptr.p_double[idx1+1] = a->ptr.p_double[idx2+1]; - idx1 = idx1+m2; - idx2 = idx2+2; - } - } - return; - } - if( n>m ) - { - - /* - * New partition: - * - * "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) - * ( B2 ) - */ - n1 = n/2; - if( n-n1>=8&&n1%8!=0 ) - { - n1 = n1+(8-n1%8); - } - ae_assert(n-n1>0, "Assertion failed", _state); - ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1, _state); - ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1, _state); - } - else - { - - /* - * New partition: - * - * "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) - * ( A2 ) - */ - m1 = m/2; - if( m-m1>=8&&m1%8!=0 ) - { - m1 = m1+(8-m1%8); - } - ae_assert(m-m1>0, "Assertion failed", _state); - ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n, _state); - ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n, _state); - } -} - - -/************************************************************************* -Recurrent subroutine for a InternalRealLinTranspose - - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_fftirltrec(/* Real */ ae_vector* a, - ae_int_t astart, - ae_int_t astride, - /* Real */ ae_vector* b, - ae_int_t bstart, - ae_int_t bstride, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t idx1; - ae_int_t idx2; - ae_int_t m1; - ae_int_t n1; - - - if( m==0||n==0 ) - { - return; - } - if( ae_maxint(m, n, _state)<=8 ) - { - for(i=0; i<=m-1; i++) - { - idx1 = bstart+i; - idx2 = astart+i*astride; - for(j=0; j<=n-1; j++) - { - b->ptr.p_double[idx1] = a->ptr.p_double[idx2]; - idx1 = idx1+bstride; - idx2 = idx2+1; - } - } - return; - } - if( n>m ) - { - - /* - * New partition: - * - * "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) - * ( B2 ) - */ - n1 = n/2; - if( n-n1>=8&&n1%8!=0 ) - { - n1 = n1+(8-n1%8); - } - ae_assert(n-n1>0, "Assertion failed", _state); - ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m, n1, _state); - ftbase_fftirltrec(a, astart+n1, astride, b, bstart+n1*bstride, bstride, m, n-n1, _state); - } - else - { - - /* - * New partition: - * - * "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) - * ( A2 ) - */ - m1 = m/2; - if( m-m1>=8&&m1%8!=0 ) - { - m1 = m1+(8-m1%8); - } - ae_assert(m-m1>0, "Assertion failed", _state); - ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m1, n, _state); - ftbase_fftirltrec(a, astart+m1*astride, astride, b, bstart+m1, bstride, m-m1, n, _state); - } -} - - -/************************************************************************* -recurrent subroutine for FFTFindSmoothRec - - -- ALGLIB -- - Copyright 01.05.2009 by Bochkanov Sergey -*************************************************************************/ -static void ftbase_ftbasefindsmoothrec(ae_int_t n, - ae_int_t seed, - ae_int_t leastfactor, - ae_int_t* best, - ae_state *_state) -{ - - - ae_assert(ftbase_ftbasemaxsmoothfactor<=5, "FTBaseFindSmoothRec: internal error!", _state); - if( seed>=n ) - { - *best = ae_minint(*best, seed, _state); - return; - } - if( leastfactor<=2 ) - { - ftbase_ftbasefindsmoothrec(n, seed*2, 2, best, _state); - } - if( leastfactor<=3 ) - { - ftbase_ftbasefindsmoothrec(n, seed*3, 3, best, _state); - } - if( leastfactor<=5 ) - { - ftbase_ftbasefindsmoothrec(n, seed*5, 5, best, _state); - } -} - - -ae_bool _fasttransformplan_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - fasttransformplan *p = (fasttransformplan*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->entries, 0, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->buffer, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->precr, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->preci, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->bluesteinpool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _fasttransformplan_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - fasttransformplan *dst = (fasttransformplan*)_dst; - fasttransformplan *src = (fasttransformplan*)_src; - if( !ae_matrix_init_copy(&dst->entries, &src->entries, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->buffer, &src->buffer, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->precr, &src->precr, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->preci, &src->preci, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init_copy(&dst->bluesteinpool, &src->bluesteinpool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _fasttransformplan_clear(void* _p) -{ - fasttransformplan *p = (fasttransformplan*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->entries); - ae_vector_clear(&p->buffer); - ae_vector_clear(&p->precr); - ae_vector_clear(&p->preci); - ae_shared_pool_clear(&p->bluesteinpool); -} - - -void _fasttransformplan_destroy(void* _p) -{ - fasttransformplan *p = (fasttransformplan*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->entries); - ae_vector_destroy(&p->buffer); - ae_vector_destroy(&p->precr); - ae_vector_destroy(&p->preci); - ae_shared_pool_destroy(&p->bluesteinpool); -} - - - - -double nulog1p(double x, ae_state *_state) -{ - double z; - double lp; - double lq; - double result; - - - z = 1.0+x; - if( ae_fp_less(z,0.70710678118654752440)||ae_fp_greater(z,1.41421356237309504880) ) - { - result = ae_log(z, _state); - return result; - } - z = x*x; - lp = 4.5270000862445199635215E-5; - lp = lp*x+4.9854102823193375972212E-1; - lp = lp*x+6.5787325942061044846969E0; - lp = lp*x+2.9911919328553073277375E1; - lp = lp*x+6.0949667980987787057556E1; - lp = lp*x+5.7112963590585538103336E1; - lp = lp*x+2.0039553499201281259648E1; - lq = 1.0000000000000000000000E0; - lq = lq*x+1.5062909083469192043167E1; - lq = lq*x+8.3047565967967209469434E1; - lq = lq*x+2.2176239823732856465394E2; - lq = lq*x+3.0909872225312059774938E2; - lq = lq*x+2.1642788614495947685003E2; - lq = lq*x+6.0118660497603843919306E1; - z = -0.5*z+x*(z*lp/lq); - result = x+z; - return result; -} - - -double nuexpm1(double x, ae_state *_state) -{ - double r; - double xx; - double ep; - double eq; - double result; - - - if( ae_fp_less(x,-0.5)||ae_fp_greater(x,0.5) ) - { - result = ae_exp(x, _state)-1.0; - return result; - } - xx = x*x; - ep = 1.2617719307481059087798E-4; - ep = ep*xx+3.0299440770744196129956E-2; - ep = ep*xx+9.9999999999999999991025E-1; - eq = 3.0019850513866445504159E-6; - eq = eq*xx+2.5244834034968410419224E-3; - eq = eq*xx+2.2726554820815502876593E-1; - eq = eq*xx+2.0000000000000000000897E0; - r = x*ep; - r = r/(eq-r); - result = r+r; - return result; -} - - -double nucosm1(double x, ae_state *_state) -{ - double xx; - double c; - double result; - - - if( ae_fp_less(x,-0.25*ae_pi)||ae_fp_greater(x,0.25*ae_pi) ) - { - result = ae_cos(x, _state)-1; - return result; - } - xx = x*x; - c = 4.7377507964246204691685E-14; - c = c*xx-1.1470284843425359765671E-11; - c = c*xx+2.0876754287081521758361E-9; - c = c*xx-2.7557319214999787979814E-7; - c = c*xx+2.4801587301570552304991E-5; - c = c*xx-1.3888888888888872993737E-3; - c = c*xx+4.1666666666666666609054E-2; - result = -0.5*xx+xx*xx*c; - return result; -} - - - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "alglibinternal.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_APSERV) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_ABLASF) || !defined(AE_PARTIAL_BUILD) +static void ablasf_rincreaserowsfixedcolsminternal(ae_int_t newrows, + /* Real */ ae_matrix* a, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_bool ablasf_rgemm32basecase(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +#endif + + +#endif +#if defined(AE_COMPILE_HBLAS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_CREFLECTIONS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SBLAS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_ABLASPBL) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SCODES) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_TSORT) || !defined(AE_PARTIAL_BUILD) +static void tsort_tagsortfastirec(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Integer */ ae_vector* bufb, + ae_int_t i1, + ae_int_t i2, + ae_state *_state); +static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, + /* Real */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Real */ ae_vector* bufb, + ae_int_t i1, + ae_int_t i2, + ae_state *_state); +static void tsort_tagsortfastrec(/* Real */ ae_vector* a, + /* Real */ ae_vector* bufa, + ae_int_t i1, + ae_int_t i2, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_BLAS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_ROTATIONS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_BASICSTATOPS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_APSTRUCT) || !defined(AE_PARTIAL_BUILD) +static ae_int_t apstruct_knisheadersize = 2; + + +#endif +#if defined(AE_COMPILE_TRLINSOLVE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SAFESOLVE) || !defined(AE_PARTIAL_BUILD) +static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, + ae_complex beta, + double lnmax, + double bnorm, + double maxgrowth, + double* xnorm, + ae_complex* x, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_XBLAS) || !defined(AE_PARTIAL_BUILD) +static void xblas_xsum(/* Real */ ae_vector* w, + double mx, + ae_int_t n, + double* r, + double* rerr, + ae_state *_state); +static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LINMIN) || !defined(AE_PARTIAL_BUILD) +static double linmin_ftol = 0.001; +static double linmin_xtol = (double)100*ae_machineepsilon; +static ae_int_t linmin_maxfev = 20; +static double linmin_stpmin = 1.0E-50; +static double linmin_defstpmax = 1.0E+50; +static double linmin_armijofactor = 1.3; +static void linmin_mcstep(double* stx, + double* fx, + double* dx, + double* sty, + double* fy, + double* dy, + double* stp, + double fp, + double dp, + ae_bool* brackt, + double stmin, + double stmax, + ae_int_t* info, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NEARUNITYUNIT) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_NTHEORY) || !defined(AE_PARTIAL_BUILD) +static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state); +static ae_int_t ntheory_modmul(ae_int_t a, + ae_int_t b, + ae_int_t n, + ae_state *_state); +static ae_int_t ntheory_modexp(ae_int_t a, + ae_int_t b, + ae_int_t n, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_FTBASE) || !defined(AE_PARTIAL_BUILD) +static ae_int_t ftbase_coltype = 0; +static ae_int_t ftbase_coloperandscnt = 1; +static ae_int_t ftbase_coloperandsize = 2; +static ae_int_t ftbase_colmicrovectorsize = 3; +static ae_int_t ftbase_colparam0 = 4; +static ae_int_t ftbase_colparam1 = 5; +static ae_int_t ftbase_colparam2 = 6; +static ae_int_t ftbase_colparam3 = 7; +static ae_int_t ftbase_colscnt = 8; +static ae_int_t ftbase_opend = 0; +static ae_int_t ftbase_opcomplexreffft = 1; +static ae_int_t ftbase_opbluesteinsfft = 2; +static ae_int_t ftbase_opcomplexcodeletfft = 3; +static ae_int_t ftbase_opcomplexcodelettwfft = 4; +static ae_int_t ftbase_opradersfft = 5; +static ae_int_t ftbase_opcomplextranspose = -1; +static ae_int_t ftbase_opcomplexfftfactors = -2; +static ae_int_t ftbase_opstart = -3; +static ae_int_t ftbase_opjmp = -4; +static ae_int_t ftbase_opparallelcall = -5; +static ae_int_t ftbase_maxradix = 6; +static ae_int_t ftbase_updatetw = 16; +static ae_int_t ftbase_recursivethreshold = 1024; +static ae_int_t ftbase_raderthreshold = 19; +static ae_int_t ftbase_ftbasecodeletrecommended = 5; +static double ftbase_ftbaseinefficiencyfactor = 1.3; +static ae_int_t ftbase_ftbasemaxsmoothfactor = 5; +static void ftbase_ftdeterminespacerequirements(ae_int_t n, + ae_int_t* precrsize, + ae_int_t* precisize, + ae_state *_state); +static void ftbase_ftcomplexfftplanrec(ae_int_t n, + ae_int_t k, + ae_bool childplan, + ae_bool topmostplan, + ae_int_t* rowptr, + ae_int_t* bluesteinsize, + ae_int_t* precrptr, + ae_int_t* preciptr, + fasttransformplan* plan, + ae_state *_state); +static void ftbase_ftpushentry(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_state *_state); +static void ftbase_ftpushentry2(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_int_t eparam1, + ae_state *_state); +static void ftbase_ftpushentry4(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_int_t eparam1, + ae_int_t eparam2, + ae_int_t eparam3, + ae_state *_state); +static void ftbase_ftapplysubplan(fasttransformplan* plan, + ae_int_t subplan, + /* Real */ ae_vector* a, + ae_int_t abase, + ae_int_t aoffset, + /* Real */ ae_vector* buf, + ae_int_t repcnt, + ae_state *_state); +static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + /* Real */ ae_vector* buf, + ae_state *_state); +static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + ae_state *_state); +static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + ae_state *_state); +static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* precr, + ae_int_t offs, + ae_state *_state); +static void ftbase_ftbluesteinsfft(fasttransformplan* plan, + /* Real */ ae_vector* a, + ae_int_t abase, + ae_int_t aoffset, + ae_int_t operandscnt, + ae_int_t n, + ae_int_t m, + ae_int_t precoffs, + ae_int_t subplan, + /* Real */ ae_vector* bufa, + /* Real */ ae_vector* bufb, + /* Real */ ae_vector* bufc, + /* Real */ ae_vector* bufd, + ae_state *_state); +static void ftbase_ftprecomputeradersfft(ae_int_t n, + ae_int_t rq, + ae_int_t riq, + /* Real */ ae_vector* precr, + ae_int_t offs, + ae_state *_state); +static void ftbase_ftradersfft(fasttransformplan* plan, + /* Real */ ae_vector* a, + ae_int_t abase, + ae_int_t aoffset, + ae_int_t operandscnt, + ae_int_t n, + ae_int_t subplan, + ae_int_t rq, + ae_int_t riq, + ae_int_t precoffs, + /* Real */ ae_vector* buf, + ae_state *_state); +static void ftbase_ftfactorize(ae_int_t n, + ae_bool isroot, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state); +static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state); +static void ftbase_ffttwcalc(/* Real */ ae_vector* a, + ae_int_t aoffset, + ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static void ftbase_internalcomplexlintranspose(/* Real */ ae_vector* a, + ae_int_t m, + ae_int_t n, + ae_int_t astart, + /* Real */ ae_vector* buf, + ae_state *_state); +static void ftbase_ffticltrec(/* Real */ ae_vector* a, + ae_int_t astart, + ae_int_t astride, + /* Real */ ae_vector* b, + ae_int_t bstart, + ae_int_t bstride, + ae_int_t m, + ae_int_t n, + ae_state *_state); +static void ftbase_ftbasefindsmoothrec(ae_int_t n, + ae_int_t seed, + ae_int_t leastfactor, + ae_int_t* best, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_HPCCORES) || !defined(AE_PARTIAL_BUILD) +static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ const ae_vector* weights, + ae_int_t wcount, + /* Real */ ae_vector* hpcbuf, + ae_state *_state); +static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ const ae_vector* buf, + ae_int_t wcount, + /* Real */ ae_vector* grad, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_ALGLIBBASICS) || !defined(AE_PARTIAL_BUILD) + + +#endif + +#if defined(AE_COMPILE_APSERV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Internally calls SetErrorFlag() with condition: + + Abs(Val-RefVal)>Tol*Max(Abs(RefVal),S) + +This function is used to test relative error in Val against RefVal, with +relative error being replaced by absolute when scale of RefVal is less +than S. + +This function returns value of COND. +*************************************************************************/ +void seterrorflagdiff(ae_bool* flag, + double val, + double refval, + double tol, + double s, + ae_state *_state) +{ + + + ae_set_error_flag(flag, ae_fp_greater(ae_fabs(val-refval, _state),tol*ae_maxreal(ae_fabs(refval, _state), s, _state)), __FILE__, __LINE__, "apserv.ap:206"); +} + + +/************************************************************************* +The function always returns False. +It may be used sometimes to prevent spurious warnings. + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool alwaysfalse(ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +The function "touches" boolean - it is used to avoid compiler messages +about unused variables (in rare cases when we do NOT want to remove these +variables). + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +void touchboolean(ae_bool* a, ae_state *_state) +{ + + +} + + +/************************************************************************* +The function "touches" integer - it is used to avoid compiler messages +about unused variables (in rare cases when we do NOT want to remove these +variables). + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +void touchint(ae_int_t* a, ae_state *_state) +{ + + +} + + +/************************************************************************* +The function "touches" real - it is used to avoid compiler messages +about unused variables (in rare cases when we do NOT want to remove these +variables). + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +void touchreal(double* a, ae_state *_state) +{ + + +} + + +/************************************************************************* +The function performs zero-coalescing on real value. + +NOTE: no check is performed for B<>0 + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +double coalesce(double a, double b, ae_state *_state) +{ + double result; + + + result = a; + if( ae_fp_eq(a,0.0) ) + { + result = b; + } + return result; +} + + +/************************************************************************* +The function performs zero-coalescing on integer value. + +NOTE: no check is performed for B<>0 + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +ae_int_t coalescei(ae_int_t a, ae_int_t b, ae_state *_state) +{ + ae_int_t result; + + + result = a; + if( a==0 ) + { + result = b; + } + return result; +} + + +/************************************************************************* +The function performs zero-coalescing on integer value. + +NOTE: no check is performed for B<>0 + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +ae_int_t icoalesce(ae_int_t a, ae_int_t b, ae_state *_state) +{ + ae_int_t result; + + + result = a; + if( a==0 ) + { + result = b; + } + return result; +} + + +/************************************************************************* +The function convert integer value to real value. + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +double inttoreal(ae_int_t a, ae_state *_state) +{ + double result; + + + result = (double)(a); + return result; +} + + +/************************************************************************* +The function calculates binary logarithm. + +NOTE: it costs twice as much as Ln(x) + + -- ALGLIB -- + Copyright 17.09.2012 by Bochkanov Sergey +*************************************************************************/ +double logbase2(double x, ae_state *_state) +{ + double result; + + + result = ae_log(x, _state)/ae_log((double)(2), _state); + return result; +} + + +/************************************************************************* +This function compares two numbers for approximate equality, with tolerance +to errors as large as tol. + + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool approxequal(double a, double b, double tol, ae_state *_state) +{ + ae_bool result; + + + result = ae_fp_less_eq(ae_fabs(a-b, _state),tol); + return result; +} + + +/************************************************************************* +This function compares two numbers for approximate equality, with tolerance +to errors as large as max(|a|,|b|)*tol. + + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool approxequalrel(double a, double b, double tol, ae_state *_state) +{ + ae_bool result; + + + result = ae_fp_less_eq(ae_fabs(a-b, _state),ae_maxreal(ae_fabs(a, _state), ae_fabs(b, _state), _state)*tol); + return result; +} + + +/************************************************************************* +This function generates 1-dimensional general interpolation task with +moderate Lipshitz constant (close to 1.0) + +If N=1 then suborutine generates only one point at the middle of [A,B] + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void taskgenint1d(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + double h; + + ae_vector_clear(x); + ae_vector_clear(y); + + ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); + ae_vector_set_length(x, n, _state); + ae_vector_set_length(y, n, _state); + if( n>1 ) + { + x->ptr.p_double[0] = a; + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + h = (b-a)/(double)(n-1); + for(i=1; i<=n-1; i++) + { + if( i!=n-1 ) + { + x->ptr.p_double[i] = a+((double)i+0.2*((double)2*ae_randomreal(_state)-(double)1))*h; + } + else + { + x->ptr.p_double[i] = b; + } + y->ptr.p_double[i] = y->ptr.p_double[i-1]+((double)2*ae_randomreal(_state)-(double)1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); + } + } + else + { + x->ptr.p_double[0] = 0.5*(a+b); + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + } +} + + +/************************************************************************* +This function generates 1-dimensional equidistant interpolation task with +moderate Lipshitz constant (close to 1.0) + +If N=1 then suborutine generates only one point at the middle of [A,B] + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void taskgenint1dequidist(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + double h; + + ae_vector_clear(x); + ae_vector_clear(y); + + ae_assert(n>=1, "TaskGenInterpolationEqdist1D: N<1!", _state); + ae_vector_set_length(x, n, _state); + ae_vector_set_length(y, n, _state); + if( n>1 ) + { + x->ptr.p_double[0] = a; + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + h = (b-a)/(double)(n-1); + for(i=1; i<=n-1; i++) + { + x->ptr.p_double[i] = a+(double)i*h; + y->ptr.p_double[i] = y->ptr.p_double[i-1]+((double)2*ae_randomreal(_state)-(double)1)*h; + } + } + else + { + x->ptr.p_double[0] = 0.5*(a+b); + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + } +} + + +/************************************************************************* +This function generates 1-dimensional Chebyshev-1 interpolation task with +moderate Lipshitz constant (close to 1.0) + +If N=1 then suborutine generates only one point at the middle of [A,B] + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void taskgenint1dcheb1(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(x); + ae_vector_clear(y); + + ae_assert(n>=1, "TaskGenInterpolation1DCheb1: N<1!", _state); + ae_vector_set_length(x, n, _state); + ae_vector_set_length(y, n, _state); + if( n>1 ) + { + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(double)(2*i+1)/(double)(2*n), _state); + if( i==0 ) + { + y->ptr.p_double[i] = (double)2*ae_randomreal(_state)-(double)1; + } + else + { + y->ptr.p_double[i] = y->ptr.p_double[i-1]+((double)2*ae_randomreal(_state)-(double)1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); + } + } + } + else + { + x->ptr.p_double[0] = 0.5*(a+b); + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + } +} + + +/************************************************************************* +This function generates 1-dimensional Chebyshev-2 interpolation task with +moderate Lipshitz constant (close to 1.0) + +If N=1 then suborutine generates only one point at the middle of [A,B] + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void taskgenint1dcheb2(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(x); + ae_vector_clear(y); + + ae_assert(n>=1, "TaskGenInterpolation1DCheb2: N<1!", _state); + ae_vector_set_length(x, n, _state); + ae_vector_set_length(y, n, _state); + if( n>1 ) + { + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*(double)i/(double)(n-1), _state); + if( i==0 ) + { + y->ptr.p_double[i] = (double)2*ae_randomreal(_state)-(double)1; + } + else + { + y->ptr.p_double[i] = y->ptr.p_double[i-1]+((double)2*ae_randomreal(_state)-(double)1)*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); + } + } + } + else + { + x->ptr.p_double[0] = 0.5*(a+b); + y->ptr.p_double[0] = (double)2*ae_randomreal(_state)-(double)1; + } +} + + +/************************************************************************* +This function checks that all values from X[] are distinct. It does more +than just usual floating point comparison: +* first, it calculates max(X) and min(X) +* second, it maps X[] from [min,max] to [1,2] +* only at this stage actual comparison is done + +The meaning of such check is to ensure that all values are "distinct enough" +and will not cause interpolation subroutine to fail. + +NOTE: + X[] must be sorted by ascending (subroutine ASSERT's it) + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool aredistinct(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double a; + double b; + ae_int_t i; + ae_bool nonsorted; + ae_bool result; + + + ae_assert(n>=1, "APSERVAreDistinct: internal error (N<1)", _state); + if( n==1 ) + { + + /* + * everything is alright, it is up to caller to decide whether it + * can interpolate something with just one point + */ + result = ae_true; + return result; + } + a = x->ptr.p_double[0]; + b = x->ptr.p_double[0]; + nonsorted = ae_false; + for(i=1; i<=n-1; i++) + { + a = ae_minreal(a, x->ptr.p_double[i], _state); + b = ae_maxreal(b, x->ptr.p_double[i], _state); + nonsorted = nonsorted||ae_fp_greater_eq(x->ptr.p_double[i-1],x->ptr.p_double[i]); + } + ae_assert(!nonsorted, "APSERVAreDistinct: internal error (not sorted)", _state); + for(i=1; i<=n-1; i++) + { + if( ae_fp_eq((x->ptr.p_double[i]-a)/(b-a)+(double)1,(x->ptr.p_double[i-1]-a)/(b-a)+(double)1) ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that two boolean values are the same (both are True +or both are False). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state) +{ + ae_bool result; + + + result = (v1&&v2)||(!v1&&!v2); + return result; +} + + +/************************************************************************* +Resizes X and fills by zeros + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void setlengthzero(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>=0, "SetLengthZero: N<0", _state); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } +} + + +/************************************************************************* +If Length(X)cntcntcnt0&&n>0 ) + { + if( x->rowscols0&&n>0 ) + { + if( x->rowscolscnt>=n ) + { + ae_frame_leave(_state); + return; + } + + /* + * Choose new size + */ + n = ae_maxint(n, ae_round(1.8*(double)x->cnt+(double)1, _state), _state); + + /* + * Grow + */ + n2 = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( iptr.p_bool[i] = oldx.ptr.p_bool[i]; + } + else + { + x->ptr.p_bool[i] = ae_false; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Grows X, i.e. changes its size in such a way that: +a) contents is preserved +b) new size is at least N +c) new size can be larger than N, so subsequent grow() calls can return + without reallocation + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void ivectorgrowto(/* Integer */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t i; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_INT, _state, ae_true); + + + /* + * Enough place + */ + if( x->cnt>=n ) + { + ae_frame_leave(_state); + return; + } + + /* + * Choose new size + */ + n = ae_maxint(n, ae_round(1.8*(double)x->cnt+(double)1, _state), _state); + + /* + * Grow + */ + n2 = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( iptr.p_int[i] = oldx.ptr.p_int[i]; + } + else + { + x->ptr.p_int[i] = 0; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Grows X, i.e. appends rows in such a way that: +a) contents is preserved +b) new row count is at least N +c) new row count can be larger than N, so subsequent grow() calls can return + without reallocation +d) new matrix has at least MinCols columns (if less than specified amount + of columns is present, new columns are added with undefined contents); + MinCols can be 0 or negative value = ignored + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixgrowrowsto(/* Real */ ae_matrix* a, + ae_int_t n, + ae_int_t mincols, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix olda; + ae_int_t i; + ae_int_t j; + ae_int_t n2; + ae_int_t m; + + ae_frame_make(_state, &_frame_block); + memset(&olda, 0, sizeof(olda)); + ae_matrix_init(&olda, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Enough place? + */ + if( a->rows>=n&&a->cols>=mincols ) + { + ae_frame_leave(_state); + return; + } + + /* + * Sizes and metrics + */ + if( a->rowsrows+(double)1, _state), _state); + } + n2 = ae_minint(a->rows, n, _state); + m = a->cols; + + /* + * Grow + */ + ae_swap_matrices(a, &olda); + ae_matrix_set_length(a, n, ae_maxint(m, mincols, _state), _state); + for(i=0; i<=n2-1; i++) + { + for(j=0; j<=m-1; j++) + { + a->ptr.pp_double[i][j] = olda.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Grows X, i.e. appends cols in such a way that: +a) contents is preserved +b) new col count is at least N +c) new col count can be larger than N, so subsequent grow() calls can return + without reallocation +d) new matrix has at least MinRows row (if less than specified amount + of rows is present, new rows are added with undefined contents); + MinRows can be 0 or negative value = ignored + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixgrowcolsto(/* Real */ ae_matrix* a, + ae_int_t n, + ae_int_t minrows, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix olda; + ae_int_t i; + ae_int_t j; + ae_int_t n2; + ae_int_t m; + + ae_frame_make(_state, &_frame_block); + memset(&olda, 0, sizeof(olda)); + ae_matrix_init(&olda, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Enough place? + */ + if( a->cols>=n&&a->rows>=minrows ) + { + ae_frame_leave(_state); + return; + } + + /* + * Sizes and metrics + */ + if( a->colscols+(double)1, _state), _state); + } + n2 = ae_minint(a->cols, n, _state); + m = a->rows; + + /* + * Grow + */ + ae_swap_matrices(a, &olda); + ae_matrix_set_length(a, ae_maxint(m, minrows, _state), n, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n2-1; j++) + { + a->ptr.pp_double[i][j] = olda.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Grows X, i.e. changes its size in such a way that: +a) contents is preserved +b) new size is at least N +c) new size can be larger than N, so subsequent grow() calls can return + without reallocation + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rvectorgrowto(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t i; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_REAL, _state, ae_true); + + + /* + * Enough place + */ + if( x->cnt>=n ) + { + ae_frame_leave(_state); + return; + } + + /* + * Choose new size + */ + n = ae_maxint(n, ae_round(1.8*(double)x->cnt+(double)1, _state), _state); + + /* + * Grow + */ + n2 = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( iptr.p_double[i] = oldx.ptr.p_double[i]; + } + else + { + x->ptr.p_double[i] = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Resizes X and: +* preserves old contents of X +* fills new elements by zeros + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void ivectorresize(/* Integer */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t i; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_INT, _state, ae_true); + + n2 = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( iptr.p_int[i] = oldx.ptr.p_int[i]; + } + else + { + x->ptr.p_int[i] = 0; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Resizes X and: +* preserves old contents of X +* fills new elements by zeros + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rvectorresize(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t i; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_REAL, _state, ae_true); + + n2 = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( iptr.p_double[i] = oldx.ptr.p_double[i]; + } + else + { + x->ptr.p_double[i] = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Resizes X and: +* preserves old contents of X +* fills new elements by zeros + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixresize(/* Real */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix oldx; + ae_int_t i; + ae_int_t j; + ae_int_t m2; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_matrix_init(&oldx, 0, 0, DT_REAL, _state, ae_true); + + m2 = x->rows; + n2 = x->cols; + ae_swap_matrices(x, &oldx); + ae_matrix_set_length(x, m, n, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( iptr.pp_double[i][j] = oldx.ptr.pp_double[i][j]; + } + else + { + x->ptr.pp_double[i][j] = 0.0; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Resizes X and: +* preserves old contents of X +* fills new elements by zeros + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void imatrixresize(/* Integer */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix oldx; + ae_int_t i; + ae_int_t j; + ae_int_t m2; + ae_int_t n2; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_matrix_init(&oldx, 0, 0, DT_INT, _state, ae_true); + + m2 = x->rows; + n2 = x->cols; + ae_swap_matrices(x, &oldx); + ae_matrix_set_length(x, m, n, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( iptr.pp_int[i][j] = oldx.ptr.pp_int[i][j]; + } + else + { + x->ptr.pp_int[i][j] = 0; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +appends element to X + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void ivectorappend(/* Integer */ ae_vector* x, + ae_int_t v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t i; + ae_int_t n; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_INT, _state, ae_true); + + n = x->cnt; + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, n+1, _state); + for(i=0; i<=n-1; i++) + { + x->ptr.p_int[i] = oldx.ptr.p_int[i]; + } + x->ptr.p_int[n] = v; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function checks that length(X) is at least N and first N values from +X[] are finite or NANs + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfiniteornanvector(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state); + if( n==0 ) + { + result = ae_true; + return result; + } + if( x->cntptr.p_double[i]; + } + if( ae_isfinite(v, _state) ) + { + result = ae_true; + return result; + } + + /* + * OK, check that either finite or nan + */ + for(i=0; i<=n-1; i++) + { + if( !ae_isfinite(x->ptr.p_double[i], _state)&&!ae_isnan(x->ptr.p_double[i], _state) ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that first N values from X[] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfinitecvector(/* Complex */ const ae_vector* z, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteCVector: internal error (N<0)", _state); + for(i=0; i<=n-1; i++) + { + if( !ae_isfinite(z->ptr.p_complex[i].x, _state)||!ae_isfinite(z->ptr.p_complex[i].y, _state) ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that size of X is at least MxN and values from +X[0..M-1,0..N-1] are finite. + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool apservisfinitematrix(/* Real */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteMatrix: internal error (N<0)", _state); + ae_assert(m>=0, "APSERVIsFiniteMatrix: internal error (M<0)", _state); + if( m==0||n==0 ) + { + result = ae_true; + return result; + } + if( x->rowscolsptr.pp_double[i][j], _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that all values from X[0..M-1,0..N-1] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool apservisfinitecmatrix(/* Complex */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteCMatrix: internal error (N<0)", _state); + ae_assert(m>=0, "APSERVIsFiniteCMatrix: internal error (M<0)", _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that all values from X[0..M-1,0..N-1] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfinitecmatrix(/* Complex */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "IsFiniteCMatrix: internal error (N<0)", _state); + ae_assert(m>=0, "IsFiniteCMatrix: internal error (M<0)", _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that size of X is at least NxN and all values from +upper/lower triangle of X[0..N-1,0..N-1] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfinitertrmatrix(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j1; + ae_int_t j2; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteRTRMatrix: internal error (N<0)", _state); + if( n==0 ) + { + result = ae_true; + return result; + } + if( x->rowscolsptr.pp_double[i][j], _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that all values from upper/lower triangle of +X[0..N-1,0..N-1] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool apservisfinitectrmatrix(/* Complex */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j1; + ae_int_t j2; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that all values from upper/lower triangle of +X[0..N-1,0..N-1] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfinitectrmatrix(/* Complex */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j1; + ae_int_t j2; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteCTRMatrix: internal error (N<0)", _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( !ae_isfinite(x->ptr.pp_complex[i][j].x, _state)||!ae_isfinite(x->ptr.pp_complex[i][j].y, _state) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function checks that all values from X[0..M-1,0..N-1] are finite or +NaN's. + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool apservisfiniteornanmatrix(/* Real */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteOrNaNMatrix: internal error (N<0)", _state); + ae_assert(m>=0, "APSERVIsFiniteOrNaNMatrix: internal error (M<0)", _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( !(ae_isfinite(x->ptr.pp_double[i][j], _state)||ae_isnan(x->ptr.pp_double[i][j], _state)) ) + { + result = ae_false; + return result; + } + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Safe sqrt(x^2+y^2) + + -- ALGLIB -- + Copyright by Bochkanov Sergey +*************************************************************************/ +double safepythag2(double x, double y, ae_state *_state) +{ + double w; + double xabs; + double yabs; + double z; + double result; + + + xabs = ae_fabs(x, _state); + yabs = ae_fabs(y, _state); + w = ae_maxreal(xabs, yabs, _state); + z = ae_minreal(xabs, yabs, _state); + if( ae_fp_eq(z,(double)(0)) ) + { + result = w; + } + else + { + result = w*ae_sqrt((double)1+ae_sqr(z/w, _state), _state); + } + return result; +} + + +/************************************************************************* +Safe sqrt(x^2+y^2) + + -- ALGLIB -- + Copyright by Bochkanov Sergey +*************************************************************************/ +double safepythag3(double x, double y, double z, ae_state *_state) +{ + double w; + double result; + + + w = ae_maxreal(ae_fabs(x, _state), ae_maxreal(ae_fabs(y, _state), ae_fabs(z, _state), _state), _state); + if( ae_fp_eq(w,(double)(0)) ) + { + result = (double)(0); + return result; + } + x = x/w; + y = y/w; + z = z/w; + result = w*ae_sqrt(ae_sqr(x, _state)+ae_sqr(y, _state)+ae_sqr(z, _state), _state); + return result; +} + + +/************************************************************************* +Safe division. + +This function attempts to calculate R=X/Y without overflow. + +It returns: +* +1, if abs(X/Y)>=MaxRealNumber or undefined - overflow-like situation + (no overlfow is generated, R is either NAN, PosINF, NegINF) +* 0, if MinRealNumber0 + (R contains result, may be zero) +* -1, if 00 + */ + if( ae_fp_eq(y,(double)(0)) ) + { + result = 1; + if( ae_fp_eq(x,(double)(0)) ) + { + *r = _state->v_nan; + } + if( ae_fp_greater(x,(double)(0)) ) + { + *r = _state->v_posinf; + } + if( ae_fp_less(x,(double)(0)) ) + { + *r = _state->v_neginf; + } + return result; + } + if( ae_fp_eq(x,(double)(0)) ) + { + *r = (double)(0); + result = 0; + return result; + } + + /* + * make Y>0 + */ + if( ae_fp_less(y,(double)(0)) ) + { + x = -x; + y = -y; + } + + /* + * + */ + if( ae_fp_greater_eq(y,(double)(1)) ) + { + *r = x/y; + if( ae_fp_less_eq(ae_fabs(*r, _state),ae_minrealnumber) ) + { + result = -1; + *r = (double)(0); + } + else + { + result = 0; + } + } + else + { + if( ae_fp_greater_eq(ae_fabs(x, _state),ae_maxrealnumber*y) ) + { + if( ae_fp_greater(x,(double)(0)) ) + { + *r = _state->v_posinf; + } + else + { + *r = _state->v_neginf; + } + result = 1; + } + else + { + *r = x/y; + result = 0; + } + } + return result; +} + + +/************************************************************************* +This function calculates "safe" min(X/Y,V) for positive finite X, Y, V. +No overflow is generated in any case. + + -- ALGLIB -- + Copyright by Bochkanov Sergey +*************************************************************************/ +double safeminposrv(double x, double y, double v, ae_state *_state) +{ + double r; + double result; + + + if( y>=(double)1 ) + { + + /* + * Y>=1, we can safely divide by Y + */ + r = x/y; + result = v; + if( v>r ) + { + result = r; + } + else + { + result = v; + } + } + else + { + + /* + * Y<1, we can safely multiply by Y + */ + if( xB). It returns T which lies in [A,B] and integer K, +such that X = T + K*(B-A). + +NOTES: +* K is represented as real value, although actually it is integer +* T is guaranteed to be in [A,B] +* T replaces X + + -- ALGLIB -- + Copyright by Bochkanov Sergey +*************************************************************************/ +void apperiodicmap(double* x, + double a, + double b, + double* k, + ae_state *_state) +{ + + *k = 0.0; + + ae_assert(ae_fp_less(a,b), "APPeriodicMap: internal error!", _state); + *k = (double)(ae_ifloor((*x-a)/(b-a), _state)); + *x = *x-*k*(b-a); + while(ae_fp_less(*x,a)) + { + *x = *x+(b-a); + *k = *k-(double)1; + } + while(ae_fp_greater(*x,b)) + { + *x = *x-(b-a); + *k = *k+(double)1; + } + *x = ae_maxreal(*x, a, _state); + *x = ae_minreal(*x, b, _state); +} + + +/************************************************************************* +Returns random normal number using low-quality system-provided generator + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +double randomnormal(ae_state *_state) +{ + double u; + double v; + double s; + double result; + + + for(;;) + { + u = (double)2*ae_randomreal(_state)-(double)1; + v = (double)2*ae_randomreal(_state)-(double)1; + s = ae_sqr(u, _state)+ae_sqr(v, _state); + if( ae_fp_greater(s,(double)(0))&&ae_fp_less(s,(double)(1)) ) + { + + /* + * two Sqrt's instead of one to + * avoid overflow when S is too small + */ + s = ae_sqrt(-(double)2*ae_log(s, _state), _state)/ae_sqrt(s, _state); + result = u*s; + break; + } + } + return result; +} + + +/************************************************************************* +Generates random unit vector using low-quality system-provided generator. +Reallocates array if its size is too short. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) +{ + ae_int_t i; + double v; + double vv; + + + ae_assert(n>0, "RandomUnit: N<=0", _state); + if( x->cntptr.p_double[i] = vv; + v = v+vv*vv; + } + } + while(ae_fp_less_eq(v,(double)(0))); + v = (double)1/ae_sqrt(v, _state); + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*v; + } +} + + +/************************************************************************* +This function is used to swap two integer values +*************************************************************************/ +void swapi(ae_int_t* v0, ae_int_t* v1, ae_state *_state) +{ + ae_int_t v; + + + v = *v0; + *v0 = *v1; + *v1 = v; +} + + +/************************************************************************* +This function is used to swap two real values +*************************************************************************/ +void swapr(double* v0, double* v1, ae_state *_state) +{ + double v; + + + v = *v0; + *v0 = *v1; + *v1 = v; +} + + +/************************************************************************* +This function is used to swap two rows of the matrix; if NCols<0, automatically +determined from the matrix size. +*************************************************************************/ +void swaprows(/* Real */ ae_matrix* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t ncols, + ae_state *_state) +{ + ae_int_t j; + double v; + + + if( i0==i1 ) + { + return; + } + if( ncols<0 ) + { + ncols = a->cols; + } + for(j=0; j<=ncols-1; j++) + { + v = a->ptr.pp_double[i0][j]; + a->ptr.pp_double[i0][j] = a->ptr.pp_double[i1][j]; + a->ptr.pp_double[i1][j] = v; + } +} + + +/************************************************************************* +This function is used to swap two cols of the matrix; if NRows<0, automatically +determined from the matrix size. +*************************************************************************/ +void swapcols(/* Real */ ae_matrix* a, + ae_int_t j0, + ae_int_t j1, + ae_int_t nrows, + ae_state *_state) +{ + ae_int_t i; + double v; + + + if( j0==j1 ) + { + return; + } + if( nrows<0 ) + { + nrows = a->rows; + } + for(i=0; i<=nrows-1; i++) + { + v = a->ptr.pp_double[i][j0]; + a->ptr.pp_double[i][j0] = a->ptr.pp_double[i][j1]; + a->ptr.pp_double[i][j1] = v; + } +} + + +/************************************************************************* +This function is used to swap two "entries" in 1-dimensional array composed +from D-element entries +*************************************************************************/ +void swapentries(/* Real */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t entrywidth, + ae_state *_state) +{ + ae_int_t offs0; + ae_int_t offs1; + ae_int_t j; + double v; + + + if( i0==i1 ) + { + return; + } + offs0 = i0*entrywidth; + offs1 = i1*entrywidth; + for(j=0; j<=entrywidth-1; j++) + { + v = a->ptr.p_double[offs0+j]; + a->ptr.p_double[offs0+j] = a->ptr.p_double[offs1+j]; + a->ptr.p_double[offs1+j] = v; + } +} + + +/************************************************************************* +This function is used to swap two "entries" in 1-dimensional array composed +from D-element entries +*************************************************************************/ +void swapentriesb(/* Boolean */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t entrywidth, + ae_state *_state) +{ + ae_int_t offs0; + ae_int_t offs1; + ae_int_t j; + ae_bool v; + + + if( i0==i1 ) + { + return; + } + offs0 = i0*entrywidth; + offs1 = i1*entrywidth; + for(j=0; j<=entrywidth-1; j++) + { + v = a->ptr.p_bool[offs0+j]; + a->ptr.p_bool[offs0+j] = a->ptr.p_bool[offs1+j]; + a->ptr.p_bool[offs1+j] = v; + } +} + + +/************************************************************************* +This function is used to swap two elements of the vector +*************************************************************************/ +void swapelements(/* Real */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state) +{ + double v; + + + if( i0==i1 ) + { + return; + } + v = a->ptr.p_double[i0]; + a->ptr.p_double[i0] = a->ptr.p_double[i1]; + a->ptr.p_double[i1] = v; +} + + +/************************************************************************* +This function is used to swap two elements of the vector +*************************************************************************/ +void swapelementsi(/* Integer */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state) +{ + ae_int_t v; + + + if( i0==i1 ) + { + return; + } + v = a->ptr.p_int[i0]; + a->ptr.p_int[i0] = a->ptr.p_int[i1]; + a->ptr.p_int[i1] = v; +} + + +/************************************************************************* +This function is used to swap two elements of the vector +*************************************************************************/ +void swapelementsb(/* Boolean */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state) +{ + ae_bool v; + + + if( i0==i1 ) + { + return; + } + v = a->ptr.p_bool[i0]; + a->ptr.p_bool[i0] = a->ptr.p_bool[i1]; + a->ptr.p_bool[i1] = v; +} + + +/************************************************************************* +This function is used to return maximum of three real values +*************************************************************************/ +double maxreal3(double v0, double v1, double v2, ae_state *_state) +{ + double result; + + + result = v0; + if( ae_fp_less(result,v1) ) + { + result = v1; + } + if( ae_fp_less(result,v2) ) + { + result = v2; + } + return result; +} + + +/************************************************************************* +This function is used to increment value of integer variable +*************************************************************************/ +void inc(ae_int_t* v, ae_state *_state) +{ + + + *v = *v+1; +} + + +/************************************************************************* +This function is used to decrement value of integer variable +*************************************************************************/ +void dec(ae_int_t* v, ae_state *_state) +{ + + + *v = *v-1; +} + + +/************************************************************************* +This function is used to increment value of integer variable; name of the +function suggests that increment is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness) +*************************************************************************/ +void threadunsafeinc(ae_int_t* v, ae_state *_state) +{ + + + *v = *v+1; +} + + +/************************************************************************* +This function is used to increment value of integer variable; name of the +function suggests that increment is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness) +*************************************************************************/ +void threadunsafeincby(ae_int_t* v, ae_int_t k, ae_state *_state) +{ + + + *v = *v+k; +} + + +/************************************************************************* +This function is used to set value of an int variable; name of the +function suggests that increment is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness), although the library may try to use safe options, if available. +*************************************************************************/ +void threadunsafeset(ae_int_t* v, ae_int_t x, ae_state *_state) +{ + + + *v = x; +} + + +/************************************************************************* +This function is used to read value of an int variable; name of the +function suggests that read is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness), although the library may try to use safe options, if available. +*************************************************************************/ +ae_int_t threadunsafeget(ae_int_t* v, ae_state *_state) +{ + ae_int_t result; + + + result = *v; + return result; +} + + +/************************************************************************* +This function is used to increment value of a real variable; name of the +function suggests that increment is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness) +*************************************************************************/ +void rthreadunsafeincby(double* v, double x, ae_state *_state) +{ + + + *v = *v+x; +} + + +/************************************************************************* +This function is used to set value of a real variable; name of the +function suggests that increment is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness), although the library may try to use safe options, if available. +*************************************************************************/ +void rthreadunsafeset(double* v, double x, ae_state *_state) +{ + + + *v = x; +} + + +/************************************************************************* +This function is used to read value of a real variable; name of the +function suggests that read is done in multithreaded setting in the +thread-unsafe manner (optional progress reports which do not need guaranteed +correctness), although the library may try to use safe options, if available. +*************************************************************************/ +double rthreadunsafeget(double* v, ae_state *_state) +{ + double result; + + + result = *v; + return result; +} + + +/************************************************************************* +This function performs weak atomic fetch-add. Atomicity is guaranteed on +C# targets and on C++ targets with AE_OS #defined. + +It returns result prior to the addition. +*************************************************************************/ +ae_int_t weakatomicfetchadd(ae_int_t* v, ae_int_t n, ae_state *_state) +{ + ae_int_t provisional; + ae_int_t result; + + + for(;;) + { + provisional = ae_weak_atomic_load_norace(v); + result = ae_weak_atomic_cas(v, provisional, provisional+n); + if( result==provisional ) + { + return result; + } + } + return result; +} + + +/************************************************************************* +This function performs weak atomic spinlock acquisition. The function waits +for the spinlock to become EXPECTED and then assigns NEWVAL. + +Atomicity is guaranteed on C# targets and on C++ targets with AE_OS #defined. +*************************************************************************/ +void weakatomicacquirelock(ae_int_t* v, + ae_int_t expected, + ae_int_t newval, + ae_state *_state) +{ + + + for(;;) + { + while(ae_unsafe_volatile_read(v)!=expected) + { + } + if( ae_weak_atomic_cas(v, expected, newval)==expected ) + { + return; + } + } +} + + +/************************************************************************* +This function performs weak atomic spinlock acquisition. The function waits +for the spinlock to become EXPECTED and then assigns NEWVAL. + +Atomicity is guaranteed on C# targets and on C++ targets with AE_OS #defined. +*************************************************************************/ +void weakatomicacquirelockv(/* Integer */ ae_vector* v, + ae_int_t idx, + ae_int_t expected, + ae_int_t newval, + ae_state *_state) +{ + + + for(;;) + { + while(ae_unsafe_volatile_read(v->ptr.p_int+idx)!=expected) + { + } + if( ae_weak_atomic_cas(v->ptr.p_int+idx, expected, newval)==expected ) + { + return; + } + } +} + + +/************************************************************************* +This function waits for a variable to become equal to EXPECTED. It waits +for at most WAITFOR iterations. + +It returns after the variable has become EXPECTED, or the timer has expired. +It does not return the specific for stopping because it may be possible +that the variable status has changed in the meantime. +*************************************************************************/ +void weakatomicwaitforv(/* Integer */ ae_vector* v, + ae_int_t idx, + ae_int_t expected, + ae_int_t waitfor, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=waitfor-1; i++) + { + if( ae_unsafe_volatile_read(v->ptr.p_int+idx)==expected ) + { + return; + } + } +} + + +/************************************************************************* +This function performs two operations: +1. decrements value of integer variable, if it is positive +2. explicitly sets variable to zero if it is non-positive +It is used by some algorithms to decrease value of internal counters. +*************************************************************************/ +void countdown(ae_int_t* v, ae_state *_state) +{ + + + if( *v>0 ) + { + *v = *v-1; + } + else + { + *v = 0; + } +} + + +/************************************************************************* +This function returns +1 or -1 depending on sign of X. +x=0 results in +1 being returned. +*************************************************************************/ +double possign(double x, ae_state *_state) +{ + double result; + + + if( x>=(double)0 ) + { + result = (double)(1); + } + else + { + result = (double)(-1); + } + return result; +} + + +/************************************************************************* +This function returns +1 or -1 depending on sign of X. +x=0 results in +1 being returned. +*************************************************************************/ +ae_int_t ipossign(double x, ae_state *_state) +{ + ae_int_t result; + + + if( ae_fp_greater_eq(x,(double)(0)) ) + { + result = 1; + } + else + { + result = -1; + } + return result; +} + + +/************************************************************************* +This function returns product of two real numbers. It is convenient when +you have to perform typecast-and-product of two INTEGERS. +*************************************************************************/ +double rmul2(double v0, double v1, ae_state *_state) +{ + double result; + + + result = v0*v1; + return result; +} + + +/************************************************************************* +This function returns product of three real numbers. It is convenient when +you have to perform typecast-and-product of three INTEGERS. +*************************************************************************/ +double rmul3(double v0, double v1, double v2, ae_state *_state) +{ + double result; + + + result = v0*v1*v2; + return result; +} + + +/************************************************************************* +This function returns product of four real numbers. It is convenient when +you have to perform typecast-and-product of four INTEGERS. +*************************************************************************/ +double rmul4(double v0, double v1, double v2, double v3, ae_state *_state) +{ + double result; + + + result = v0*v1*v2*v3; + return result; +} + + +/************************************************************************* +This function returns (A div B) rounded up; it expects that A>0, B>0, but +does not check it. +*************************************************************************/ +ae_int_t idivup(ae_int_t a, ae_int_t b, ae_state *_state) +{ + ae_int_t result; + + + result = a/b; + if( a%b>0 ) + { + result = result+1; + } + return result; +} + + +/************************************************************************* +This function returns min(i0,i1) +*************************************************************************/ +ae_int_t imin2(ae_int_t i0, ae_int_t i1, ae_state *_state) +{ + ae_int_t result; + + + result = i0; + if( i1result ) + { + result = i1; + } + return result; +} + + +/************************************************************************* +This function returns max(i0,i1,i2) +*************************************************************************/ +ae_int_t imax3(ae_int_t i0, ae_int_t i1, ae_int_t i2, ae_state *_state) +{ + ae_int_t result; + + + result = i0; + if( i1>result ) + { + result = i1; + } + if( i2>result ) + { + result = i2; + } + return result; +} + + +/************************************************************************* +This function returns max(i0,i1,i2,i3) +*************************************************************************/ +ae_int_t imax4(ae_int_t i0, + ae_int_t i1, + ae_int_t i2, + ae_int_t i3, + ae_state *_state) +{ + ae_int_t result; + + + result = i0; + if( i1>result ) + { + result = i1; + } + if( i2>result ) + { + result = i2; + } + if( i3>result ) + { + result = i3; + } + return result; +} + + +/************************************************************************* +This function returns max(r0,r1,r2) +*************************************************************************/ +double rmax3(double r0, double r1, double r2, ae_state *_state) +{ + double result; + + + result = r0; + if( r1>result ) + { + result = r1; + } + if( r2>result ) + { + result = r2; + } + return result; +} + + +/************************************************************************* +This function returns min(r0,r1,r2) +*************************************************************************/ +double rmin3(double r0, double r1, double r2, ae_state *_state) +{ + double result; + + + result = r0; + if( r1result ) + { + result = r1; + } + return result; +} + + +/************************************************************************* +This function returns max(|r0|,|r1|,|r2|) +*************************************************************************/ +double rmaxabs3(double r0, double r1, double r2, ae_state *_state) +{ + double result; + + + r0 = ae_fabs(r0, _state); + r1 = ae_fabs(r1, _state); + r2 = ae_fabs(r2, _state); + result = r0; + if( r1>result ) + { + result = r1; + } + if( r2>result ) + { + result = r2; + } + return result; +} + + +/************************************************************************* +'bounds' value: maps X to [B1,B2] + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +double boundval(double x, double b1, double b2, ae_state *_state) +{ + double result; + + + if( ae_fp_less_eq(x,b1) ) + { + result = b1; + return result; + } + if( ae_fp_greater_eq(x,b2) ) + { + result = b2; + return result; + } + result = x; + return result; +} + + +/************************************************************************* +'bounds' value: maps X to [B1,B2] + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +ae_int_t iboundval(ae_int_t x, ae_int_t b1, ae_int_t b2, ae_state *_state) +{ + ae_int_t result; + + + if( x<=b1 ) + { + result = b1; + return result; + } + if( x>=b2 ) + { + result = b2; + return result; + } + result = x; + return result; +} + + +/************************************************************************* +'bounds' value: maps X to [B1,B2] + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +double rboundval(double x, double b1, double b2, ae_state *_state) +{ + double result; + + + if( ae_fp_less_eq(x,b1) ) + { + result = b1; + return result; + } + if( ae_fp_greater_eq(x,b2) ) + { + result = b2; + return result; + } + result = x; + return result; +} + + +/************************************************************************* +Boolean case-2: returns V0 if Cond=True, V1 otherwise +*************************************************************************/ +ae_bool bcase2(ae_bool cond, ae_bool v0, ae_bool v1, ae_state *_state) +{ + ae_bool result; + + + if( cond ) + { + result = v0; + } + else + { + result = v1; + } + return result; +} + + +/************************************************************************* +Real case-2: returns V0 if Cond=True, V1 otherwise +*************************************************************************/ +double rcase2(ae_bool cond, double v0, double v1, ae_state *_state) +{ + double result; + + + if( cond ) + { + result = v0; + } + else + { + result = v1; + } + return result; +} + + +/************************************************************************* +Returns number of non-zeros +*************************************************************************/ +ae_int_t countnz1(/* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t result; + + + result = 0; + for(i=0; i<=n-1; i++) + { + if( !(v->ptr.p_double[i]==(double)0) ) + { + result = result+1; + } + } + return result; +} + + +/************************************************************************* +Returns number of non-zeros +*************************************************************************/ +ae_int_t countnz2(/* Real */ const ae_matrix* v, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t result; + + + result = 0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( !(v->ptr.pp_double[i][j]==(double)0) ) + { + result = result+1; + } + } + } + return result; +} + + +/************************************************************************* +Allocation of serializer: complex value +*************************************************************************/ +void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state) +{ + + + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); +} + + +/************************************************************************* +Serialization: complex value +*************************************************************************/ +void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state) +{ + + + ae_serializer_serialize_double(s, v.x, _state); + ae_serializer_serialize_double(s, v.y, _state); +} + + +/************************************************************************* +Unserialization: complex value +*************************************************************************/ +ae_complex unserializecomplex(ae_serializer* s, ae_state *_state) +{ + ae_complex result; + + + ae_serializer_unserialize_double(s, &result.x, _state); + ae_serializer_unserialize_double(s, &result.y, _state); + return result; +} + + +/************************************************************************* +Allocation of serializer: real array +*************************************************************************/ +void allocrealarray(ae_serializer* s, + /* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_alloc_entry(s); + for(i=0; i<=n-1; i++) + { + ae_serializer_alloc_entry(s); + } +} + + +/************************************************************************* +Allocation of serializer: boolean array +*************************************************************************/ +void allocbooleanarray(ae_serializer* s, + /* Boolean */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_alloc_entry(s); + for(i=0; i<=n-1; i++) + { + ae_serializer_alloc_entry(s); + } +} + + +/************************************************************************* +Serialization: complex value +*************************************************************************/ +void serializerealarray(ae_serializer* s, + /* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_serialize_int(s, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_serialize_double(s, v->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Serialization: boolean array +*************************************************************************/ +void serializebooleanarray(ae_serializer* s, + /* Boolean */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_serialize_int(s, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_serialize_bool(s, v->ptr.p_bool[i], _state); + } +} + + +/************************************************************************* +Unserialization: complex value +*************************************************************************/ +void unserializerealarray(ae_serializer* s, + /* Real */ ae_vector* v, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double t; + + ae_vector_clear(v); + + ae_serializer_unserialize_int(s, &n, _state); + if( n==0 ) + { + return; + } + ae_vector_set_length(v, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_unserialize_double(s, &t, _state); + v->ptr.p_double[i] = t; + } +} + + +/************************************************************************* +Unserialization: boolean value +*************************************************************************/ +void unserializebooleanarray(ae_serializer* s, + /* Boolean */ ae_vector* v, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_bool t; + + ae_vector_clear(v); + + ae_serializer_unserialize_int(s, &n, _state); + if( n==0 ) + { + return; + } + ae_vector_set_length(v, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_unserialize_bool(s, &t, _state); + v->ptr.p_bool[i] = t; + } +} + + +/************************************************************************* +Allocation of serializer: Integer array +*************************************************************************/ +void allocintegerarray(ae_serializer* s, + /* Integer */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_alloc_entry(s); + for(i=0; i<=n-1; i++) + { + ae_serializer_alloc_entry(s); + } +} + + +/************************************************************************* +Serialization: Integer array +*************************************************************************/ +void serializeintegerarray(ae_serializer* s, + /* Integer */ const ae_vector* v, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + if( n<0 ) + { + n = v->cnt; + } + ae_serializer_serialize_int(s, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_serialize_int(s, v->ptr.p_int[i], _state); + } +} + + +/************************************************************************* +Unserialization: complex value +*************************************************************************/ +void unserializeintegerarray(ae_serializer* s, + /* Integer */ ae_vector* v, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t t; + + ae_vector_clear(v); + + ae_serializer_unserialize_int(s, &n, _state); + if( n==0 ) + { + return; + } + ae_vector_set_length(v, n, _state); + for(i=0; i<=n-1; i++) + { + ae_serializer_unserialize_int(s, &t, _state); + v->ptr.p_int[i] = t; + } +} + + +/************************************************************************* +Allocation of serializer: real matrix +*************************************************************************/ +void allocrealmatrix(ae_serializer* s, + /* Real */ const ae_matrix* v, + ae_int_t n0, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( n0<0 ) + { + n0 = v->rows; + } + if( n1<0 ) + { + n1 = v->cols; + } + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + ae_serializer_alloc_entry(s); + } + } +} + + +/************************************************************************* +Serialization: complex value +*************************************************************************/ +void serializerealmatrix(ae_serializer* s, + /* Real */ const ae_matrix* v, + ae_int_t n0, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( n0<0 ) + { + n0 = v->rows; + } + if( n1<0 ) + { + n1 = v->cols; + } + ae_serializer_serialize_int(s, n0, _state); + ae_serializer_serialize_int(s, n1, _state); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + ae_serializer_serialize_double(s, v->ptr.pp_double[i][j], _state); + } + } +} + + +/************************************************************************* +Unserialization: complex value +*************************************************************************/ +void unserializerealmatrix(ae_serializer* s, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n0; + ae_int_t n1; + double t; + + ae_matrix_clear(v); + + ae_serializer_unserialize_int(s, &n0, _state); + ae_serializer_unserialize_int(s, &n1, _state); + if( n0==0||n1==0 ) + { + return; + } + ae_matrix_set_length(v, n0, n1, _state); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + ae_serializer_unserialize_double(s, &t, _state); + v->ptr.pp_double[i][j] = t; + } + } +} + + +/************************************************************************* +Copy boolean array +*************************************************************************/ +void copybooleanarray(/* Boolean */ const ae_vector* src, + /* Boolean */ ae_vector* dst, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(dst); + + if( src->cnt>0 ) + { + ae_vector_set_length(dst, src->cnt, _state); + for(i=0; i<=src->cnt-1; i++) + { + dst->ptr.p_bool[i] = src->ptr.p_bool[i]; + } + } +} + + +/************************************************************************* +Copy integer array +*************************************************************************/ +void copyintegerarray(/* Integer */ const ae_vector* src, + /* Integer */ ae_vector* dst, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(dst); + + if( src->cnt>0 ) + { + ae_vector_set_length(dst, src->cnt, _state); + for(i=0; i<=src->cnt-1; i++) + { + dst->ptr.p_int[i] = src->ptr.p_int[i]; + } + } +} + + +/************************************************************************* +Copy real array +*************************************************************************/ +void copyrealarray(/* Real */ const ae_vector* src, + /* Real */ ae_vector* dst, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(dst); + + if( src->cnt>0 ) + { + ae_vector_set_length(dst, src->cnt, _state); + for(i=0; i<=src->cnt-1; i++) + { + dst->ptr.p_double[i] = src->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Copy real matrix +*************************************************************************/ +void copyrealmatrix(/* Real */ const ae_matrix* src, + /* Real */ ae_matrix* dst, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(dst); + + if( src->rows>0&&src->cols>0 ) + { + ae_matrix_set_length(dst, src->rows, src->cols, _state); + for(i=0; i<=src->rows-1; i++) + { + for(j=0; j<=src->cols-1; j++) + { + dst->ptr.pp_double[i][j] = src->ptr.pp_double[i][j]; + } + } + } +} + + +/************************************************************************* +Clears integer array +*************************************************************************/ +void unsetintegerarray(/* Integer */ ae_vector* a, ae_state *_state) +{ + + ae_vector_clear(a); + + ae_vector_set_length(a, 0, _state); +} + + +/************************************************************************* +Clears real array +*************************************************************************/ +void unsetrealarray(/* Real */ ae_vector* a, ae_state *_state) +{ + + ae_vector_clear(a); + + ae_vector_set_length(a, 0, _state); +} + + +/************************************************************************* +Clears real matrix +*************************************************************************/ +void unsetrealmatrix(/* Real */ ae_matrix* a, ae_state *_state) +{ + + ae_matrix_clear(a); + + ae_matrix_set_length(a, 0, 0, _state); +} + + +/************************************************************************* +This function is used in parallel functions for recurrent division of large +task into two smaller tasks. + +It has following properties: +* it works only for TaskSize>=2 and TaskSize>TileSize (assertion is thrown otherwise) +* Task0+Task1=TaskSize, Task0>0, Task1>0 +* Task0 and Task1 are close to each other +* Task0>=Task1 +* Task0 is always divisible by TileSize + + -- ALGLIB -- + Copyright 07.04.2013 by Bochkanov Sergey +*************************************************************************/ +void tiledsplit(ae_int_t tasksize, + ae_int_t tilesize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state) +{ + ae_int_t cc; + + *task0 = 0; + *task1 = 0; + + ae_assert(tasksize>=2, "TiledSplit: TaskSize<2", _state); + ae_assert(tasksize>tilesize, "TiledSplit: TaskSize<=TileSize", _state); + cc = chunkscount(tasksize, tilesize, _state); + ae_assert(cc>=2, "TiledSplit: integrity check failed", _state); + *task0 = idivup(cc, 2, _state)*tilesize; + *task1 = tasksize-(*task0); + ae_assert(*task0>=1, "TiledSplit: internal error", _state); + ae_assert(*task1>=1, "TiledSplit: internal error", _state); + ae_assert(*task0%tilesize==0, "TiledSplit: internal error", _state); + ae_assert(*task0>=(*task1), "TiledSplit: internal error", _state); +} + + +/************************************************************************* +Binary search in an integer array. If an element is not present, raises an +exception. Returns element position. + +The range [I0,I1) is searched. + + -- ALGLIB -- + Copyright 11.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t ibinarysearchexisting(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state) +{ + ae_int_t ori1; + ae_int_t m; + ae_int_t result; + + + ori1 = i1; + while(i0ptr.p_int[m]ptr.p_int[i0]==v, "iBinarySearchExisting: the element is not found", _state); + result = i0; + return result; +} + + +/************************************************************************* +Linear search in an integer array for a specific element, returns True or +False. Can deal with unsorted arrays. + +The range [I0,I1) is searched. + + -- ALGLIB -- + Copyright 11.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool ilinearsearchispresent(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state) +{ + ae_int_t i; + ae_bool result; + + + result = ae_false; + for(i=i0; i<=i1-1; i++) + { + if( a->ptr.p_int[i]==v ) + { + result = ae_true; + return result; + } + } + return result; +} + + +/************************************************************************* +Binary search in an integer array for a specific element, returns True or +False. Needs array to be sorted by ascending. + +The range [I0,I1) is searched. + + -- ALGLIB -- + Copyright 11.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool ibinarysearchispresent(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state) +{ + ae_int_t ori1; + ae_int_t m; + ae_bool result; + + + ori1 = i1; + while(i0ptr.p_int[m]ptr.p_int[i0]==v; + return result; +} + + +/************************************************************************* +This function searches integer array. Elements in this array are actually +records, each NRec elements wide. Each record has unique header - NHeader +integer values, which identify it. Records are lexicographically sorted by +header. + +Records are identified by their index, not offset (offset = NRec*index). + +This function searches A (records with indices [I0,I1)) for a record with +header B. It returns index of this record (not offset!), or -1 on failure. + + -- ALGLIB -- + Copyright 28.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t recsearch(/* Integer */ const ae_vector* a, + ae_int_t nrec, + ae_int_t nheader, + ae_int_t i0, + ae_int_t i1, + /* Integer */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t mididx; + ae_int_t cflag; + ae_int_t k; + ae_int_t offs; + ae_int_t result; + + + result = -1; + for(;;) + { + if( i0>=i1 ) + { + break; + } + mididx = (i0+i1)/2; + offs = nrec*mididx; + cflag = 0; + for(k=0; k<=nheader-1; k++) + { + if( a->ptr.p_int[offs+k]ptr.p_int[k] ) + { + cflag = -1; + break; + } + if( a->ptr.p_int[offs+k]>b->ptr.p_int[k] ) + { + cflag = 1; + break; + } + } + if( cflag==0 ) + { + result = mididx; + return result; + } + if( cflag<0 ) + { + i0 = mididx+1; + } + else + { + i1 = mididx; + } + } + return result; +} + + +/************************************************************************* +This function is used in parallel functions for recurrent division of large +task into two smaller tasks. + +It has following properties: +* it works only for TaskSize>=2 (assertion is thrown otherwise) +* for TaskSize=2, it returns Task0=1, Task1=1 +* in case TaskSize is odd, Task0=TaskSize-1, Task1=1 +* in case TaskSize is even, Task0 and Task1 are approximately TaskSize/2 + and both Task0 and Task1 are even, Task0>=Task1 + + -- ALGLIB -- + Copyright 07.04.2013 by Bochkanov Sergey +*************************************************************************/ +void splitlengtheven(ae_int_t tasksize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state) +{ + + *task0 = 0; + *task1 = 0; + + ae_assert(tasksize>=2, "SplitLengthEven: TaskSize<2", _state); + if( tasksize==2 ) + { + *task0 = 1; + *task1 = 1; + return; + } + if( tasksize%2==0 ) + { + + /* + * Even division + */ + *task0 = tasksize/2; + *task1 = tasksize/2; + if( *task0%2!=0 ) + { + *task0 = *task0+1; + *task1 = *task1-1; + } + } + else + { + + /* + * Odd task size, split trailing odd part from it. + */ + *task0 = tasksize-1; + *task1 = 1; + } + ae_assert(*task0>=1, "SplitLengthEven: internal error", _state); + ae_assert(*task1>=1, "SplitLengthEven: internal error", _state); +} + + +/************************************************************************* +This function is used to calculate number of chunks (including partial, +non-complete chunks) in some set. It expects that ChunkSize>=1, TaskSize>=0. +Assertion is thrown otherwise. + +Function result is equivalent to Ceil(TaskSize/ChunkSize), but with guarantees +that rounding errors won't ruin results. + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +ae_int_t chunkscount(ae_int_t tasksize, + ae_int_t chunksize, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(tasksize>=0, "ChunksCount: TaskSize<0", _state); + ae_assert(chunksize>=1, "ChunksCount: ChunkSize<1", _state); + result = tasksize/chunksize; + if( tasksize%chunksize!=0 ) + { + result = result+1; + } + return result; +} + + +/************************************************************************* +Returns maximum density for level 2 sparse/dense functions. Density values +below one returned by this function are better to handle via sparse Level 2 +functionality. + + -- ALGLIB routine -- + 10.01.2019 + Bochkanov Sergey +*************************************************************************/ +double sparselevel2density(ae_state *_state) +{ + double result; + + + result = 0.1; + return result; +} + + +/************************************************************************* +Returns A-tile size for a matrix. + +A-tiles are smallest tiles (32x32), suitable for processing by ALGLIB own +implementation of Level 3 linear algebra. + + -- ALGLIB routine -- + 10.01.2019 + Bochkanov Sergey +*************************************************************************/ +ae_int_t matrixtilesizea(ae_state *_state) +{ + ae_int_t result; + + + result = 32; + return result; +} + + +/************************************************************************* +Returns B-tile size for a matrix. + +B-tiles are larger tiles (64x64), suitable for parallel execution or for +processing by vendor's implementation of Level 3 linear algebra. + + -- ALGLIB routine -- + 10.01.2019 + Bochkanov Sergey +*************************************************************************/ +ae_int_t matrixtilesizeb(ae_state *_state) +{ + ae_int_t result; + + + result = 64; + return result; +} + + +/************************************************************************* +This function returns minimum cost of task which is feasible for +multithreaded processing. It returns real number in order to avoid overflow +problems. + + -- ALGLIB -- + Copyright 10.01.2018 by Bochkanov Sergey +*************************************************************************/ +double smpactivationlevel(ae_state *_state) +{ + double nn; + double result; + + + nn = (double)(2*matrixtilesizeb(_state)); + result = ae_maxreal(0.95*(double)2*nn*nn*nn, 1.0E7, _state); + return result; +} + + +/************************************************************************* +This function returns minimum time required to accumulate statistics about +problem solution costs. Algorithms utilizing adaptive parallelism will +wait until information from sufficiently many tasks is accumulated before +deciding on adaptive parallelism status. + +The time is returned in milliseconds + + -- ALGLIB -- + Copyright 10.01.2018 by Bochkanov Sergey +*************************************************************************/ +double adaptiveparallelismtimerequired(ae_state *_state) +{ + double result; + + + result = 25.0; + return result; +} + + +/************************************************************************* +This function returns minimum amount of subproblems required to accumulate +statistics about problem solution costs. Algorithms utilizing adaptive +parallelism will wait until information from sufficiently many tasks is +accumulated before deciding on adaptive parallelism status. + +The time is returned in milliseconds + + -- ALGLIB -- + Copyright 10.01.2018 by Bochkanov Sergey +*************************************************************************/ +double adaptiveparallelismcountrequired(ae_state *_state) +{ + double result; + + + result = 2.0; + return result; +} + + +/************************************************************************* +This function returns minimum time of a subproblem that justifies activation +of a previously inactive parallelism (root problem insertion and worker +queue activation). + +The time is returned in milliseconds + + -- ALGLIB -- + Copyright 10.01.2018 by Bochkanov Sergey +*************************************************************************/ +double workerstartthresholdms(ae_state *_state) +{ + double result; + + + result = 2.0; + return result; +} + + +/************************************************************************* +This function returns minimum cost of task which is feasible for +spawn (given that multithreading is active). + +It returns real number in order to avoid overflow problems. + + -- ALGLIB -- + Copyright 10.01.2018 by Bochkanov Sergey +*************************************************************************/ +double spawnlevel(ae_state *_state) +{ + double nn; + double result; + + + nn = (double)(2*matrixtilesizea(_state)); + result = 0.95*(double)2*nn*nn*nn; + return result; +} + + +/************************************************************************* +--- OBSOLETE FUNCTION, USE TILED SPLIT INSTEAD --- + +This function is used in parallel functions for recurrent division of large +task into two smaller tasks. + +It has following properties: +* it works only for TaskSize>=2 and ChunkSize>=2 + (assertion is thrown otherwise) +* Task0+Task1=TaskSize, Task0>0, Task1>0 +* Task0 and Task1 are close to each other +* in case TaskSize>ChunkSize, Task0 is always divisible by ChunkSize + + -- ALGLIB -- + Copyright 07.04.2013 by Bochkanov Sergey +*************************************************************************/ +void splitlength(ae_int_t tasksize, + ae_int_t chunksize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state) +{ + + *task0 = 0; + *task1 = 0; + + ae_assert(chunksize>=2, "SplitLength: ChunkSize<2", _state); + ae_assert(tasksize>=2, "SplitLength: TaskSize<2", _state); + *task0 = tasksize/2; + if( *task0>chunksize&&*task0%chunksize!=0 ) + { + *task0 = *task0-*task0%chunksize; + } + *task1 = tasksize-(*task0); + ae_assert(*task0>=1, "SplitLength: internal error", _state); + ae_assert(*task1>=1, "SplitLength: internal error", _state); +} + + +/************************************************************************* +Outputs vector A[I0,I1-1] to trace log using either: +a) 6-digit exponential format (no trace flags is set) +b) 15-ditit exponential format ('PREC.E15' trace flag is set) +b) 6-ditit fixed-point format ('PREC.F6' trace flag is set) + +This function checks trace flags every time it is called. +*************************************************************************/ +void tracevectorautoprec(/* Real */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t prectouse; + + + + /* + * Determine precision to use + */ + prectouse = 0; + if( ae_is_trace_enabled("PREC.E15") ) + { + prectouse = 1; + } + if( ae_is_trace_enabled("PREC.F6") ) + { + prectouse = 2; + } + + /* + * Output + */ + ae_trace("[ "); + for(i=i0; i<=i1-1; i++) + { + if( prectouse==0 ) + { + ae_trace("%14.6e", + (double)(a->ptr.p_double[i])); + } + if( prectouse==1 ) + { + ae_trace("%23.15e", + (double)(a->ptr.p_double[i])); + } + if( prectouse==2 ) + { + ae_trace("%13.6f", + (double)(a->ptr.p_double[i])); + } + if( iptr.pp_double[i][j])); + } + if( prectouse==1 ) + { + ae_trace("%23.15e", + (double)(a->ptr.pp_double[i][j])); + } + if( prectouse==2 ) + { + ae_trace("%13.6f", + (double)(a->ptr.pp_double[i][j])); + } + if( jptr.p_double[i]; + if( applyscl ) + { + v = v*scl->ptr.p_double[i]; + } + if( applysft ) + { + v = v+sft->ptr.p_double[i]; + } + if( prectouse==0 ) + { + ae_trace("%14.6e", + (double)(v)); + } + if( prectouse==1 ) + { + ae_trace("%23.15e", + (double)(v)); + } + if( prectouse==2 ) + { + ae_trace("%13.6f", + (double)(v)); + } + if( iptr.pp_double[i][j], _state), _state); + } + if( prectouse==0 ) + { + ae_trace("%14.6e", + (double)(v)); + } + if( prectouse==1 ) + { + ae_trace("%23.15e", + (double)(v)); + } + if( prectouse==2 ) + { + ae_trace("%13.6f", + (double)(v)); + } + if( iptr.p_double[i])); + if( iptr.p_double[i])); + if( iptr.p_double[i])); + } + else + { + ae_trace("%14.6e", + (double)(a->ptr.p_double[i])); + } + if( iptr.pp_double[i][j], _state), _state); + } + ae_trace("%14.6e", + (double)(v)); + if( i" symbols +*************************************************************************/ +void traceangles(ae_int_t cnt, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=cnt-1; i++) + { + ae_trace(">"); + } +} + + +/************************************************************************* +Minimum speedup feasible for multithreading +*************************************************************************/ +double minspeedup(ae_state *_state) +{ + double result; + + + result = 1.5; + return result; +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Maximum concurrency on given system, with given compilation settings +*************************************************************************/ +ae_int_t maxconcurrency(ae_state *_state) +{ + ae_int_t result; + + + result = 1; + return result; +} +#endif + + +/************************************************************************* +Initialize SAvgCounter + +Prior value is a value that is returned when no values are in the buffer +*************************************************************************/ +void savgcounterinit(savgcounter* c, double priorvalue, ae_state *_state) +{ + + + c->rsum = (double)(0); + c->rcnt = (double)(0); + c->prior = priorvalue; +} + + +/************************************************************************* +Enqueue value into SAvgCounter +*************************************************************************/ +void savgcounterenqueue(savgcounter* c, double v, ae_state *_state) +{ + + + c->rsum = c->rsum+v; + c->rcnt = c->rcnt+(double)1; +} + + +/************************************************************************* +Enqueue value into SAvgCounter +*************************************************************************/ +double savgcounterget(const savgcounter* c, ae_state *_state) +{ + double result; + + + if( ae_fp_eq(c->rcnt,(double)(0)) ) + { + result = c->prior; + } + else + { + result = c->rsum/c->rcnt; + } + return result; +} + + +/************************************************************************* +Initialize SQuantileCounter + +Prior value is a value that is returned when no values are in the buffer +*************************************************************************/ +void squantilecounterinit(squantilecounter* c, + double priorvalue, + ae_state *_state) +{ + + + c->cnt = 0; + c->prior = priorvalue; +} + + +/************************************************************************* +Enqueue value into SQuantileCounter +*************************************************************************/ +void squantilecounterenqueue(squantilecounter* c, + double v, + ae_state *_state) +{ + + + if( c->elems.cnt==c->cnt ) + { + rvectorresize(&c->elems, 2*c->cnt+1, _state); + } + c->elems.ptr.p_double[c->cnt] = v; + c->cnt = c->cnt+1; +} + + +/************************************************************************* +Get k-th quantile. Thread-unsafe, modifies internal structures. + +0<=Q<=1. +*************************************************************************/ +double squantilecounterget(squantilecounter* c, + double q, + ae_state *_state) +{ + ae_int_t left; + ae_int_t right; + ae_int_t k; + ae_int_t pivotindex; + double pivotvalue; + ae_int_t storeindex; + ae_int_t i; + double result; + + + ae_assert(ae_fp_greater_eq(q,(double)(0))&&ae_fp_less_eq(q,(double)(1)), "SQuantileCounterGet: incorrect Q", _state); + if( c->cnt==0 ) + { + result = c->prior; + return result; + } + if( c->cnt==1 ) + { + result = c->elems.ptr.p_double[0]; + return result; + } + k = ae_round(q*(double)(c->cnt-1), _state); + left = 0; + right = c->cnt-1; + for(;;) + { + if( left==right ) + { + result = c->elems.ptr.p_double[left]; + break; + } + pivotindex = left+(right-left)/2; + pivotvalue = c->elems.ptr.p_double[pivotindex]; + swapelements(&c->elems, pivotindex, right, _state); + storeindex = left; + for(i=left; i<=right-1; i++) + { + if( ae_fp_less(c->elems.ptr.p_double[i],pivotvalue) ) + { + swapelements(&c->elems, storeindex, i, _state); + storeindex = storeindex+1; + } + } + swapelements(&c->elems, storeindex, right, _state); + pivotindex = storeindex; + if( pivotindex==k ) + { + result = c->elems.ptr.p_double[k]; + break; + } + if( kttotal = 0; + t->isrunning = ae_false; +} + + +/************************************************************************* +Start measurement. + +This function may be slow on some systems because it accesses internal +timer. Depending on the implementation, it may have negligible or significant +cost. +*************************************************************************/ +void stimerstart(stimer* t, ae_state *_state) +{ + + + ae_assert(!t->isrunning, "STimerStart: attempt to start already started timer", _state); + t->isrunning = ae_true; + t->tcurrent = ae_tickcount(); +} + + +/************************************************************************* +Stop measurement, add time to the already accumulated + +This function may be slow on some systems because it accesses internal +timer. Depending on the implementation, it may have negligible or significant +cost. +*************************************************************************/ +void stimerstop(stimer* t, ae_state *_state) +{ + ae_int_t tc; + + + ae_assert(t->isrunning, "STimerStop: attempt to stop already stopped timer", _state); + t->isrunning = ae_false; + tc = ae_tickcount(); + if( tc>=t->tcurrent ) + { + tc = tc-t->tcurrent; + } + else + { + tc = t->tcurrent-tc; + } + t->ttotal = t->ttotal+tc; +} + + +/************************************************************************* +Start measurement if Cond is True; do nothing otherwise. + +Accessing timer can be slow on some systems, thus one should not use timers +too frequently. This function allows to access the timer when Cond is True, +but completely skip timer-related infrastructure and perform a quick exit +when Cond is False. +*************************************************************************/ +void stimerstartcond(stimer* t, ae_bool cond, ae_state *_state) +{ + + + if( !cond ) + { + return; + } + ae_assert(!t->isrunning, "STimerStart: attempt to start already started timer", _state); + t->isrunning = ae_true; + t->tcurrent = ae_tickcount(); +} + + +/************************************************************************* +Stop measurement, add time to the already accumulated, if Cond is True. +Do nothing otherwise. + +Accessing timer can be slow on some systems, thus one should not use timers +too frequently. This function allows to access the timer when Cond is True, +but completely skip timer-related infrastructure and perform a quick exit +when Cond is False. +*************************************************************************/ +void stimerstopcond(stimer* t, ae_bool cond, ae_state *_state) +{ + double tc; + + + if( !cond ) + { + return; + } + ae_assert(t->isrunning, "STimerStop: attempt to stop already stopped timer", _state); + t->isrunning = ae_false; + tc = (double)(ae_tickcount()-t->tcurrent); + if( ae_fp_less(tc,(double)(0)) ) + { + tc = tc+4294967296.0; + } + t->ttotal = t->ttotal+ae_round(tc, _state); +} + + +/************************************************************************* +Retrieve time in milliseconds for the stopped timer, accuracy unknown. +*************************************************************************/ +double stimergetms(const stimer* t, ae_state *_state) +{ + double result; + + + ae_assert(!t->isrunning, "STimerGetMS: attempt to get time from the running timer", _state); + result = (double)(t->ttotal); + return result; +} + + +/************************************************************************* +Retrieve time in milliseconds for the stopped timer, accuracy unknown. + +The result is returned as integer. For small running times (below 1ms or +below accuracy, which may be as large as 20-50ms) it is not rounded to +nearest integer (which is likely to be zero for submillicecond times). + +Instead, a zero or non-zero value is returned. For repeated runs these +values average to the 'true' average of a sequence. +*************************************************************************/ +ae_int_t stimergetmsint(const stimer* t, ae_state *_state) +{ + ae_int_t result; + + + ae_assert(!t->isrunning, "STimerGetMS: attempt to get time from the running timer", _state); + result = t->ttotal; + return result; +} + + +/************************************************************************* +Retrieve time in milliseconds for the running or stopped timer, accuracy unknown +*************************************************************************/ +double stimergetmsrunning(const stimer* t, ae_state *_state) +{ + double tc; + double result; + + + result = (double)(t->ttotal); + if( t->isrunning ) + { + tc = (double)(ae_tickcount()-t->tcurrent); + if( ae_fp_less(tc,(double)(0)) ) + { + tc = tc+4294967296.0; + } + result = result+tc; + } + return result; +} + + +/************************************************************************* +Retrieve time in milliseconds for the running or stopped timer, accuracy unknown +*************************************************************************/ +double stimergetmsrunningandrestart(stimer* t, ae_state *_state) +{ + double result; + + + result = stimergetmsrunning(t, _state); + stimerinit(t, _state); + stimerstart(t, _state); + return result; +} + + +void _apbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + apbuffers *p = (apbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->ba0, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->ia0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ia1, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ia2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ia3, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ra0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ra1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ra2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ra3, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rm0, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rm1, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _apbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + apbuffers *dst = (apbuffers*)_dst; + const apbuffers *src = (const apbuffers*)_src; + ae_vector_init_copy(&dst->ba0, &src->ba0, _state, make_automatic); + ae_vector_init_copy(&dst->ia0, &src->ia0, _state, make_automatic); + ae_vector_init_copy(&dst->ia1, &src->ia1, _state, make_automatic); + ae_vector_init_copy(&dst->ia2, &src->ia2, _state, make_automatic); + ae_vector_init_copy(&dst->ia3, &src->ia3, _state, make_automatic); + ae_vector_init_copy(&dst->ra0, &src->ra0, _state, make_automatic); + ae_vector_init_copy(&dst->ra1, &src->ra1, _state, make_automatic); + ae_vector_init_copy(&dst->ra2, &src->ra2, _state, make_automatic); + ae_vector_init_copy(&dst->ra3, &src->ra3, _state, make_automatic); + ae_matrix_init_copy(&dst->rm0, &src->rm0, _state, make_automatic); + ae_matrix_init_copy(&dst->rm1, &src->rm1, _state, make_automatic); +} + + +void _apbuffers_clear(void* _p) +{ + apbuffers *p = (apbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->ba0); + ae_vector_clear(&p->ia0); + ae_vector_clear(&p->ia1); + ae_vector_clear(&p->ia2); + ae_vector_clear(&p->ia3); + ae_vector_clear(&p->ra0); + ae_vector_clear(&p->ra1); + ae_vector_clear(&p->ra2); + ae_vector_clear(&p->ra3); + ae_matrix_clear(&p->rm0); + ae_matrix_clear(&p->rm1); +} + + +void _apbuffers_destroy(void* _p) +{ + apbuffers *p = (apbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->ba0); + ae_vector_destroy(&p->ia0); + ae_vector_destroy(&p->ia1); + ae_vector_destroy(&p->ia2); + ae_vector_destroy(&p->ia3); + ae_vector_destroy(&p->ra0); + ae_vector_destroy(&p->ra1); + ae_vector_destroy(&p->ra2); + ae_vector_destroy(&p->ra3); + ae_matrix_destroy(&p->rm0); + ae_matrix_destroy(&p->rm1); +} + + +void _sboolean_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sboolean *p = (sboolean*)_p; + ae_touch_ptr((void*)p); +} + + +void _sboolean_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sboolean *dst = (sboolean*)_dst; + const sboolean *src = (const sboolean*)_src; + dst->val = src->val; +} + + +void _sboolean_clear(void* _p) +{ + sboolean *p = (sboolean*)_p; + ae_touch_ptr((void*)p); +} + + +void _sboolean_destroy(void* _p) +{ + sboolean *p = (sboolean*)_p; + ae_touch_ptr((void*)p); +} + + +void _sbooleanarray_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sbooleanarray *p = (sbooleanarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->val, 0, DT_BOOL, _state, make_automatic); +} + + +void _sbooleanarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sbooleanarray *dst = (sbooleanarray*)_dst; + const sbooleanarray *src = (const sbooleanarray*)_src; + ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic); +} + + +void _sbooleanarray_clear(void* _p) +{ + sbooleanarray *p = (sbooleanarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->val); +} + + +void _sbooleanarray_destroy(void* _p) +{ + sbooleanarray *p = (sbooleanarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->val); +} + + +void _sinteger_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sinteger *p = (sinteger*)_p; + ae_touch_ptr((void*)p); +} + + +void _sinteger_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sinteger *dst = (sinteger*)_dst; + const sinteger *src = (const sinteger*)_src; + dst->val = src->val; +} + + +void _sinteger_clear(void* _p) +{ + sinteger *p = (sinteger*)_p; + ae_touch_ptr((void*)p); +} + + +void _sinteger_destroy(void* _p) +{ + sinteger *p = (sinteger*)_p; + ae_touch_ptr((void*)p); +} + + +void _sintegerarray_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sintegerarray *p = (sintegerarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->val, 0, DT_INT, _state, make_automatic); +} + + +void _sintegerarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sintegerarray *dst = (sintegerarray*)_dst; + const sintegerarray *src = (const sintegerarray*)_src; + ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic); +} + + +void _sintegerarray_clear(void* _p) +{ + sintegerarray *p = (sintegerarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->val); +} + + +void _sintegerarray_destroy(void* _p) +{ + sintegerarray *p = (sintegerarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->val); +} + + +void _sreal_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sreal *p = (sreal*)_p; + ae_touch_ptr((void*)p); +} + + +void _sreal_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sreal *dst = (sreal*)_dst; + const sreal *src = (const sreal*)_src; + dst->val = src->val; +} + + +void _sreal_clear(void* _p) +{ + sreal *p = (sreal*)_p; + ae_touch_ptr((void*)p); +} + + +void _sreal_destroy(void* _p) +{ + sreal *p = (sreal*)_p; + ae_touch_ptr((void*)p); +} + + +void _srealarray_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + srealarray *p = (srealarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->val, 0, DT_REAL, _state, make_automatic); +} + + +void _srealarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + srealarray *dst = (srealarray*)_dst; + const srealarray *src = (const srealarray*)_src; + ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic); +} + + +void _srealarray_clear(void* _p) +{ + srealarray *p = (srealarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->val); +} + + +void _srealarray_destroy(void* _p) +{ + srealarray *p = (srealarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->val); +} + + +void _scomplex_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + scomplex *p = (scomplex*)_p; + ae_touch_ptr((void*)p); +} + + +void _scomplex_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + scomplex *dst = (scomplex*)_dst; + const scomplex *src = (const scomplex*)_src; + dst->val = src->val; +} + + +void _scomplex_clear(void* _p) +{ + scomplex *p = (scomplex*)_p; + ae_touch_ptr((void*)p); +} + + +void _scomplex_destroy(void* _p) +{ + scomplex *p = (scomplex*)_p; + ae_touch_ptr((void*)p); +} + + +void _scomplexarray_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + scomplexarray *p = (scomplexarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->val, 0, DT_COMPLEX, _state, make_automatic); +} + + +void _scomplexarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + scomplexarray *dst = (scomplexarray*)_dst; + const scomplexarray *src = (const scomplexarray*)_src; + ae_vector_init_copy(&dst->val, &src->val, _state, make_automatic); +} + + +void _scomplexarray_clear(void* _p) +{ + scomplexarray *p = (scomplexarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->val); +} + + +void _scomplexarray_destroy(void* _p) +{ + scomplexarray *p = (scomplexarray*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->val); +} + + +void _savgcounter_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + savgcounter *p = (savgcounter*)_p; + ae_touch_ptr((void*)p); +} + + +void _savgcounter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + savgcounter *dst = (savgcounter*)_dst; + const savgcounter *src = (const savgcounter*)_src; + dst->rsum = src->rsum; + dst->rcnt = src->rcnt; + dst->prior = src->prior; +} + + +void _savgcounter_clear(void* _p) +{ + savgcounter *p = (savgcounter*)_p; + ae_touch_ptr((void*)p); +} + + +void _savgcounter_destroy(void* _p) +{ + savgcounter *p = (savgcounter*)_p; + ae_touch_ptr((void*)p); +} + + +void _squantilecounter_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + squantilecounter *p = (squantilecounter*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->elems, 0, DT_REAL, _state, make_automatic); +} + + +void _squantilecounter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + squantilecounter *dst = (squantilecounter*)_dst; + const squantilecounter *src = (const squantilecounter*)_src; + dst->cnt = src->cnt; + ae_vector_init_copy(&dst->elems, &src->elems, _state, make_automatic); + dst->prior = src->prior; +} + + +void _squantilecounter_clear(void* _p) +{ + squantilecounter *p = (squantilecounter*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->elems); +} + + +void _squantilecounter_destroy(void* _p) +{ + squantilecounter *p = (squantilecounter*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->elems); +} + + +void _stimer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + stimer *p = (stimer*)_p; + ae_touch_ptr((void*)p); +} + + +void _stimer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + stimer *dst = (stimer*)_dst; + const stimer *src = (const stimer*)_src; + dst->ttotal = src->ttotal; + dst->tcurrent = src->tcurrent; + dst->isrunning = src->isrunning; +} + + +void _stimer_clear(void* _p) +{ + stimer *p = (stimer*)_p; + ae_touch_ptr((void*)p); +} + + +void _stimer_destroy(void* _p) +{ + stimer *p = (stimer*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_ABLASF) || !defined(AE_PARTIAL_BUILD) + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Computes dot product (X,Y) for elements [0,N) of X[] and Y[] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + Y - array[N], vector to process + +RESULT: + (X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[i]*y->ptr.p_double[i]; + } + return result; +} +#endif + + +/************************************************************************* +Computes scaled dot product (S*X,S*Y) for elements [0,N) of X[] and Y[] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + Y - array[N], vector to process + S - array[N], vector to process + +RESULT: + (X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotscl1v(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[i]*s->ptr.p_double[i]*(y->ptr.p_double[i]*s->ptr.p_double[i]); + } + return result; +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Computes dot product (X,A[i]) for elements [0,N) of vector X[] and row A[i,*] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + A - array[?,N], matrix to process + I - row index + +RESULT: + (X,Ai) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_matrix* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + double result; + + + result = (double)(0); + for(j=0; j<=n-1; j++) + { + result = result+x->ptr.p_double[j]*a->ptr.pp_double[i][j]; + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Computes dot product (X,A[i]) for rows A[ia,*] and B[ib,*] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + A - array[?,N], matrix to process + I - row index + +RESULT: + (X,Ai) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_state *_state) +{ + ae_int_t j; + double result; + + + result = (double)(0); + for(j=0; j<=n-1; j++) + { + result = result+a->ptr.pp_double[ia][j]*b->ptr.pp_double[ib][j]; + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Computes dot product (X,X) for elements [0,N) of X[] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +RESULT: + (X,X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotv2(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + result = result+v*v; + } + return result; +} +#endif + + +/************************************************************************* +Computes scaled dot product (S*X,S*X) for elements [0,N) of X[] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + S - array[N], vector to process + +RESULT: + (X,X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotscl1v2(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]*s->ptr.p_double[i]; + result = result+v*v; + } + return result; +} + + +/************************************************************************* +Computes scaled inf-norm of X: max(|x[i]/s[i]|) + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + S - array[N], scales, S[i]<>0 + +RESULT: + (X,X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rsclnrminf(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]/s->ptr.p_double[i]; + result = ae_maxreal(result, ae_fabs(v, _state), _state); + } + return result; +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of Y[] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddv(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+alpha*y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of Y[]*Z[] to X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X + Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace subtraction of Y[]*Z[] from X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X - Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rnegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]-y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs addition of Y[]*Z[] to X[], with result being stored to R[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + R - array[N], vector to process + +RESULT: + R := X + Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rcopymuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + r->ptr.p_double[i] = x->ptr.p_double[i]+y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs subtraction of Y[]*Z[] from X[], with result being stored to R[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + R - array[N], vector to process + +RESULT: + R := X - Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rcopynegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + r->ptr.p_double[i] = x->ptr.p_double[i]-y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of Y[] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - source vector + OffsY - source offset + X - destination vector + OffsX - destination offset + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddvx(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + ae_int_t offsy, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[offsx+i] = x->ptr.p_double[offsx+i]+alpha*y->ptr.p_double[offsy+i]; + } +} +#endif + + +/************************************************************************* +Performs inplace addition of vector Y[] to column X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - vector to add + X - target column ColIdx + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddvc(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t colidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[i][colidx] = x->ptr.pp_double[i][colidx]+alpha*y->ptr.p_double[i]; + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of vector Y[] to row X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - vector to add + X - target row RowIdx + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddvr(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]+alpha*y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise multiplication of vector X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target vector + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise multiplication of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]*y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise multiplication of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*y->ptr.pp_double[rowidx][i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise division of vector X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to divide by + X - target vector + +RESULT: + X := componentwise(X/Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise division of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to divide by + X - target row RowIdx + +RESULT: + X := componentwise(X/Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]/y->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise division of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to divide by + X - target row RowIdx + +RESULT: + X := componentwise(X/Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/y->ptr.pp_double[rowidx][i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of vector X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target vector + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], y->ptr.p_double[i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of row X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = ae_maxreal(x->ptr.pp_double[rowidx][i], y->ptr.p_double[i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of row X[I] and vector Y[] + +INPUT PARAMETERS: + N - vector length + X - matrix, I-th row is source + X - target row RowIdx + +RESULT: + Y := componentwise_max(Y,X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = ae_maxreal(y->ptr.p_double[i], x->ptr.pp_double[rowidx][i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of vector X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target vector + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = ae_minreal(x->ptr.p_double[i], y->ptr.p_double[i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of row X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = ae_minreal(x->ptr.pp_double[rowidx][i], y->ptr.p_double[i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs componentwise max of row X[I] and vector Y[] + +INPUT PARAMETERS: + N - vector length + X - matrix, I-th row is source + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = ae_minreal(y->ptr.p_double[i], x->ptr.pp_double[rowidx][i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of Y[RIdx,...] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[?,N], matrix whose RIdx-th row is added + RIdx - row index + X - array[N], vector to process + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddrv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+alpha*y->ptr.pp_double[ridx][i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace addition of Y[RIdx,...] to X[RIdxDst] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[?,N], matrix whose RIdxSrc-th row is added + RIdxSrc - source row index + X - array[?,N], matrix whose RIdxDst-th row is target + RIdxDst - destination row index + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddrr(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridxsrc, + /* Real */ ae_matrix* x, + ae_int_t ridxdst, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[ridxdst][i] = x->ptr.pp_double[ridxdst][i]+alpha*y->ptr.pp_double[ridxsrc][i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace multiplication of X[] by V + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements 0...N-1 multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*v; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace multiplication of X[] by V + +INPUT PARAMETERS: + N - row length + X - array[?,N], row to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements 0...N-1 of row RowIdx are multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulr(ae_int_t n, + double v, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]*v; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace computation of Sqrt(X) + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + X - elements 0...N-1 replaced by Sqrt(X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsqrtv(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = ae_sqrt(x->ptr.p_double[i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace computation of Sqrt(X[RowIdx,*]) + +INPUT PARAMETERS: + N - vector length + X - array[?,N], matrix to process + +OUTPUT PARAMETERS: + X - elements 0...N-1 replaced by Sqrt(X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsqrtr(ae_int_t n, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = ae_sqrt(x->ptr.pp_double[rowidx][i], _state); + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs inplace multiplication of X[OffsX:OffsX+N-1] by V + +INPUT PARAMETERS: + N - subvector length + X - vector to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements OffsX:OffsX+N-1 multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[offsx+i] = x->ptr.p_double[offsx+i]*v; + } +} +#endif + + +/************************************************************************* +Returns minimum X + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + max(X[i]) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rminv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + if( n<=0 ) + { + result = (double)(0); + return result; + } + result = x->ptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + if( vptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + if( v>result ) + { + result = v; + } + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Returns maximum |X| + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + max(|X[i]|) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxabsv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = ae_fabs(x->ptr.p_double[i], _state); + if( v>result ) + { + result = v; + } + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Returns maximum X + +INPUT PARAMETERS: + N - vector length + X - matrix to process, RowIdx-th row is processed + +OUTPUT PARAMETERS: + max(X[RowIdx,i]) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + if( n<=0 ) + { + result = (double)(0); + return result; + } + result = x->ptr.pp_double[rowidx][0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.pp_double[rowidx][i]; + if( v>result ) + { + result = v; + } + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Returns maximum |X| + +INPUT PARAMETERS: + N - vector length + X - matrix to process, RowIdx-th row is processed + +OUTPUT PARAMETERS: + max(|X[RowIdx,i]|) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxabsr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = ae_fabs(x->ptr.pp_double[rowidx][i], _state); + if( v>result ) + { + result = v; + } + } + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Sets X[OffsX:OffsX+N-1] to V + +INPUT PARAMETERS: + N - subvector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - X[OffsX:OffsX+N-1] is replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + x->ptr.p_double[offsx+j] = v; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void bsetv(ae_int_t n, + ae_bool v, + /* Boolean */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + x->ptr.p_bool[j] = v; + } +} +#endif + + +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void csetv(ae_int_t n, + ae_complex v, + /* Complex */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + x->ptr.p_complex[j].x = v.x; + x->ptr.p_complex[j].y = v.y; + } +} + + +/************************************************************************* +Sets matrix A[] to V + +INPUT PARAMETERS: + M, N - rows/cols count + V - value to set + A - array[M,N] + +OUTPUT PARAMETERS: + A - leading M rows, N cols are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void isetm(ae_int_t m, + ae_int_t n, + ae_int_t v, + /* Integer */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_int[i][j] = v; + } + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Sets matrix A[] to V + +INPUT PARAMETERS: + M, N - rows/cols count + V - value to set + A - array[M,N] + +OUTPUT PARAMETERS: + A - leading M rows, N cols are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetm(ae_int_t m, + ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = v; + } + } +} +#endif + + +/************************************************************************* +Sets vector A[] to V, reallocating A[] if too small. + +INPUT PARAMETERS: + M - rows count + N - cols count + V - value to set + A - possibly preallocated matrix + +OUTPUT PARAMETERS: + A - leading M rows, N cols are replaced by V; the matrix is + reallocated if its rows/cols count is less than M/N. + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void isetallocm(ae_int_t m, + ae_int_t n, + ae_int_t v, + /* Integer */ ae_matrix* a, + ae_state *_state) +{ + + + if( a->rowscolsrowscols=N + + -- ALGLIB -- + Copyright 20.07.2022 by Bochkanov Sergey +*************************************************************************/ +void callocv(ae_int_t n, /* Complex */ ae_vector* x, ae_state *_state) +{ + + + if( x->cnt=N + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void ballocv(ae_int_t n, /* Boolean */ ae_vector* x, ae_state *_state) +{ + + + if( x->cntrowscolscntcntptr.pp_double[i][j] = v; + } +} +#endif + + +/************************************************************************* +Sets col J of A[,] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + A - array[N,N] or larger + J - col index + +OUTPUT PARAMETERS: + A - leading N elements of I-th col are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetc(ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_int_t j, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + a->ptr.pp_double[i][j] = v; + } +} + + +/************************************************************************* +Copies matrix X[] to Y[], resizing Y[] if needed. On resize, dimensions of +Y[] are increased - but not decreased. + +INPUT PARAMETERS: + M - rows count + N - cols count + X - array[M,N], source + Y - possibly preallocated array[M,N] (resized if needed) + +OUTPUT PARAMETERS: + Y - leading [M,N] elements are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopym(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( m==0||n==0 ) + { + return; + } + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + y->ptr.pp_double[i][j] = x->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +Copies matrix X[] to Y[], resizing Y[] if needed. On resize, dimensions of +Y[] are increased - but not decreased. + +INPUT PARAMETERS: + M - rows count + N - cols count + X - array[M,N], source + Y - possibly preallocated array[M,N] (resized if needed) + +OUTPUT PARAMETERS: + Y - leading [M,N] elements are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyallocm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + + + if( m==0||n==0 ) + { + return; + } + if( y->rowscolsrows, _state), ae_maxint(n, y->cols, _state), _state); + } + rcopym(m, n, x, y, _state); +} + + +/************************************************************************* +Copies vector X[] to Y[], resizing Y[] if needed. + +INPUT PARAMETERS: + N - vector length + X - array[N], source + Y - possibly preallocated array[N] (resized if needed) + +OUTPUT PARAMETERS: + Y - leading N elements are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void bcopyallocv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state) +{ + + + if( y->cntColsCnt (including cols(A)>ColsCnt), then the matrix is + completely reallocated, its new size will be at least MxColsCnt, but + likely to be greater than that + + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rgrowrowsfixedcolsm(ae_int_t m, + ae_int_t colscnt, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + + + if( a->cols!=colscnt ) + { + ae_matrix_set_length(a, ae_round(1.25*(double)m+(double)8, _state), colscnt, _state); + return; + } + if( a->rowsColsCnt (including cols(A)>ColsCnt) AND N=0, then the matrix + is completely reallocated, its new size will be at least 1xColsCnt, but + likely to be greater than that +c) if cols(A)<>ColsCnt (including cols(A)>ColsCnt) AND N<>0, an exception + is generated + + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void rappendrowfixedcolsm(ae_int_t n, + ae_int_t colscnt, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + + + if( a->cols!=colscnt ) + { + if( n!=0 ) + { + ae_assert(ae_false, "APSERV: integrity check 3225 failed", _state); + } + ae_matrix_set_length(a, 8, colscnt, _state); + return; + } + if( a->rowsrows==n ) + { + ablasf_rincreaserowsfixedcolsminternal(n+1, a, _state); + return; + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs copying with multiplication of V*X[] to Y[] + +INPUT PARAMETERS: + N - vector length + V - multiplier + X - array[N], source + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - array[N], Y = V*X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopymulv(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = v*x->ptr.p_double[i]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Performs copying with multiplication of V*X[] to Y[I,*] + +INPUT PARAMETERS: + N - vector length + V - multiplier + X - array[N], source + Y - preallocated array[?,N] + RIdx - destination row index + +OUTPUT PARAMETERS: + Y - Y[RIdx,...] = V*X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopymulvr(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t ridx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + y->ptr.pp_double[ridx][i] = v*x->ptr.p_double[i]; + } +} +#endif + + +/************************************************************************* +Performs copying with multiplication of V*X[] to Y[*,J] + +INPUT PARAMETERS: + N - vector length + V - multiplier + X - array[N], source + Y - preallocated array[N,?] + CIdx - destination rocol index + +OUTPUT PARAMETERS: + Y - Y[RIdx,...] = V*X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopymulvc(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t cidx, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + y->ptr.pp_double[i][cidx] = v*x->ptr.p_double[i]; + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies vector X[] to row I of A[,] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + A - preallocated 2D array large enough to store result + I - destination row index + +OUTPUT PARAMETERS: + A - leading N elements of I-th row are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = x->ptr.p_double[j]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies row I of A[,] to vector X[] + +INPUT PARAMETERS: + N - vector length + A - 2D array, source + I - source row index + X - preallocated destination + +OUTPUT PARAMETERS: + X - array[N], destination + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyrv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + x->ptr.p_double[j] = a->ptr.pp_double[i][j]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies row I of A[,] to row K of B[,]. + +A[i,...] and B[k,...] may overlap. + +INPUT PARAMETERS: + N - vector length + A - 2D array, source + I - source row index + B - preallocated destination + K - destination row index + +OUTPUT PARAMETERS: + B - row K overwritten + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_matrix* b, + ae_int_t k, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[k][j] = a->ptr.pp_double[i][j]; + } +} +#endif + + +/************************************************************************* +Copies vector X[] to column J of A[,] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + A - preallocated 2D array large enough to store result + J - destination col index + +OUTPUT PARAMETERS: + A - leading N elements of J-th column are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyvc(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t j, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + a->ptr.pp_double[i][j] = x->ptr.p_double[i]; + } +} + + +/************************************************************************* +Copies column J of A[,] to vector X[] + +INPUT PARAMETERS: + N - vector length + A - source 2D array + J - source col index + +OUTPUT PARAMETERS: + X - preallocated array[N], destination + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopycv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t j, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = a->ptr.pp_double[i][j]; + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Matrix-vector product: y := alpha*op(A)*x + beta*y + +NOTE: this function expects Y to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, x, y. + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + Alpha- coefficient + A - source matrix + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector, has at least N elements + Beta- coefficient + Y - preallocated output array, has at least M elements + +OUTPUT PARAMETERS: + Y - vector which stores result + +HANDLING OF SPECIAL CASES: + * if M=0, then subroutine does nothing. It does not even touch arrays. + * if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. A and X are not referenced + at all. Initial values of Y are ignored (we do not multiply Y by + zero, we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y + * if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by A*x; + initial state of Y is ignored (rewritten by A*x, without initial + multiplication by zeros). + + + -- ALGLIB routine -- + + 01.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t opa, + /* Real */ const ae_vector* x, + double beta, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Properly premultiply Y by Beta. + * + * Quick exit for M=0, N=0 or Alpha=0. + * After this block we have M>0, N>0, Alpha<>0. + */ + if( m<=0 ) + { + return; + } + if( ae_fp_neq(beta,(double)(0)) ) + { + rmulv(m, beta, y, _state); + } + else + { + rsetv(m, 0.0, y, _state); + } + if( n<=0||ae_fp_eq(alpha,0.0) ) + { + return; + } + + /* + * Generic code + */ + if( opa==0 ) + { + + /* + * y += A*x + */ + for(i=0; i<=m-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+a->ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + y->ptr.p_double[i] = alpha*v+y->ptr.p_double[i]; + } + return; + } + if( opa==1 ) + { + + /* + * y += A^T*x + */ + for(i=0; i<=n-1; i++) + { + v = alpha*x->ptr.p_double[i]; + for(j=0; j<=m-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+v*a->ptr.pp_double[i][j]; + } + } + return; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Matrix-vector product: y := alpha*op(A)*x + beta*y + +Here x, y, A are subvectors/submatrices of larger vectors/matrices. + +NOTE: this function expects Y to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, x, y. + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + Alpha- coefficient + A - source matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector, has at least N+IX elements + IX - subvector offset + Beta- coefficient + Y - preallocated output array, has at least M+IY elements + IY - subvector offset + +OUTPUT PARAMETERS: + Y - vector which stores result + +HANDLING OF SPECIAL CASES: + * if M=0, then subroutine does nothing. It does not even touch arrays. + * if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. A and X are not referenced + at all. Initial values of Y are ignored (we do not multiply Y by + zero, we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y + * if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by A*x; + initial state of Y is ignored (rewritten by A*x, without initial + multiplication by zeros). + + + -- ALGLIB routine -- + + 01.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rgemvx(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Properly premultiply Y by Beta. + * + * Quick exit for M=0, N=0 or Alpha=0. + * After this block we have M>0, N>0, Alpha<>0. + */ + if( m<=0 ) + { + return; + } + if( ae_fp_neq(beta,(double)(0)) ) + { + rmulvx(m, beta, y, iy, _state); + } + else + { + rsetvx(m, 0.0, y, iy, _state); + } + if( n<=0||ae_fp_eq(alpha,0.0) ) + { + return; + } + + /* + * Generic code + */ + if( opa==0 ) + { + + /* + * y += A*x + */ + for(i=0; i<=m-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + y->ptr.p_double[iy+i] = alpha*v+y->ptr.p_double[iy+i]; + } + return; + } + if( opa==1 ) + { + + /* + * y += A^T*x + */ + for(i=0; i<=n-1; i++) + { + v = alpha*x->ptr.p_double[ix+i]; + for(j=0; j<=m-1; j++) + { + y->ptr.p_double[iy+j] = y->ptr.p_double[iy+j]+v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Rank-1 correction: A := A + alpha*u*v' + +NOTE: this function expects A to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, u, v. + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target MxN matrix + Alpha- coefficient + U - vector #1 + V - vector #2 + + + -- ALGLIB routine -- + 07.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rger(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double s; + + + if( (m<=0||n<=0)||ae_fp_eq(alpha,(double)(0)) ) + { + return; + } + for(i=0; i<=m-1; i++) + { + s = alpha*u->ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]+s*v->ptr.p_double[j]; + } + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +This subroutine solves linear system op(A)*x=b where: +* A is NxN upper/lower triangular/unitriangular matrix +* X and B are Nx1 vectors +* "op" may be identity transformation or transposition + +Solution replaces X. + +IMPORTANT: * no overflow/underflow/denegeracy tests is performed. + * no integrity checks for operand sizes, out-of-bounds accesses + and so on is performed + +INPUT PARAMETERS + N - matrix size, N>=0 + A - matrix, actial matrix is stored in A[IA:IA+N-1,JA:JA+N-1] + IA - submatrix offset + JA - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - right part, actual vector is stored in X[IX:IX+N-1] + IX - offset + +OUTPUT PARAMETERS + X - solution replaces elements X[IX:IX+N-1] + + -- ALGLIB routine -- + (c) 07.09.2021 Bochkanov Sergey +*************************************************************************/ +void rtrsvx(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + if( n<=0 ) + { + return; + } + if( optype==0&&isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + for(j=i+1; j<=n-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==0&&!isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + for(j=0; j<=i-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==1&&isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==(double)0 ) + { + continue; + } + for(j=i+1; j<=n-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + if( optype==1&&!isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==(double)0 ) + { + continue; + } + for(j=0; j<=i-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + ae_assert(ae_false, "rTRSVX: unexpected operation type", _state); +} +#endif + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixgerf(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double ralpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_rmatrixgerf(m, n, a, ia, ja, ralpha, u, iu, v, iv); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixrank1f(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixrank1f(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixherkf(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_cmatrixherkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsyrkf(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper); +#endif +} + + +/************************************************************************* +Fast kernel + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixgemmf(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_ABLAS + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc); +#endif +} + + +/************************************************************************* +CMatrixGEMM kernel, basecase code for CMatrixGEMM. + +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition, conjugate transposition + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void cmatrixgemmk(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex v; + ae_complex v00; + ae_complex v01; + ae_complex v10; + ae_complex v11; + double v00x; + double v00y; + double v01x; + double v01y; + double v10x; + double v10y; + double v11x; + double v11y; + double a0x; + double a0y; + double a1x; + double a1y; + double b0x; + double b0y; + double b1x; + double b1y; + ae_int_t idxa0; + ae_int_t idxa1; + ae_int_t idxb0; + ae_int_t idxb1; + ae_int_t i0; + ae_int_t i1; + ae_int_t ik; + ae_int_t j0; + ae_int_t j1; + ae_int_t jk; + ae_int_t t; + ae_int_t offsa; + ae_int_t offsb; + + + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * Try optimized code + */ + if( cmatrixgemmf(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) + { + return; + } + + /* + * if K=0 or Alpha=0, then C=Beta*C + */ + if( k==0||ae_c_eq_d(alpha,(double)(0)) ) + { + if( ae_c_neq_d(beta,(double)(1)) ) + { + if( ae_c_neq_d(beta,(double)(0)) ) + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul(beta,c->ptr.pp_complex[ic+i][jc+j]); + } + } + } + else + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_i(0); + } + } + } + } + return; + } + + /* + * This phase is not really necessary, but compiler complains + * about "possibly uninitialized variables" + */ + a0x = (double)(0); + a0y = (double)(0); + a1x = (double)(0); + a1y = (double)(0); + b0x = (double)(0); + b0y = (double)(0); + b1x = (double)(0); + b1y = (double)(0); + + /* + * General case + */ + i = 0; + while(iptr.pp_complex[idxa0][offsa].x; + a0y = a->ptr.pp_complex[idxa0][offsa].y; + a1x = a->ptr.pp_complex[idxa1][offsa].x; + a1y = a->ptr.pp_complex[idxa1][offsa].y; + } + if( optypea==1 ) + { + a0x = a->ptr.pp_complex[offsa][idxa0].x; + a0y = a->ptr.pp_complex[offsa][idxa0].y; + a1x = a->ptr.pp_complex[offsa][idxa1].x; + a1y = a->ptr.pp_complex[offsa][idxa1].y; + } + if( optypea==2 ) + { + a0x = a->ptr.pp_complex[offsa][idxa0].x; + a0y = -a->ptr.pp_complex[offsa][idxa0].y; + a1x = a->ptr.pp_complex[offsa][idxa1].x; + a1y = -a->ptr.pp_complex[offsa][idxa1].y; + } + if( optypeb==0 ) + { + b0x = b->ptr.pp_complex[offsb][idxb0].x; + b0y = b->ptr.pp_complex[offsb][idxb0].y; + b1x = b->ptr.pp_complex[offsb][idxb1].x; + b1y = b->ptr.pp_complex[offsb][idxb1].y; + } + if( optypeb==1 ) + { + b0x = b->ptr.pp_complex[idxb0][offsb].x; + b0y = b->ptr.pp_complex[idxb0][offsb].y; + b1x = b->ptr.pp_complex[idxb1][offsb].x; + b1y = b->ptr.pp_complex[idxb1][offsb].y; + } + if( optypeb==2 ) + { + b0x = b->ptr.pp_complex[idxb0][offsb].x; + b0y = -b->ptr.pp_complex[idxb0][offsb].y; + b1x = b->ptr.pp_complex[idxb1][offsb].x; + b1y = -b->ptr.pp_complex[idxb1][offsb].y; + } + v00x = v00x+a0x*b0x-a0y*b0y; + v00y = v00y+a0x*b0y+a0y*b0x; + v01x = v01x+a0x*b1x-a0y*b1y; + v01y = v01y+a0x*b1y+a0y*b1x; + v10x = v10x+a1x*b0x-a1y*b0y; + v10y = v10y+a1x*b0y+a1y*b0x; + v11x = v11x+a1x*b1x-a1y*b1y; + v11y = v11y+a1x*b1y+a1y*b1x; + offsa = offsa+1; + offsb = offsb+1; + } + v00.x = v00x; + v00.y = v00y; + v10.x = v10x; + v10.y = v10y; + v01.x = v01x; + v01.y = v01y; + v11.x = v11x; + v11.y = v11y; + if( ae_c_eq_d(beta,(double)(0)) ) + { + c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_mul(alpha,v00); + c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_mul(alpha,v01); + c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_mul(alpha,v10); + c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_mul(alpha,v11); + } + else + { + c->ptr.pp_complex[ic+i+0][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+0]),ae_c_mul(alpha,v00)); + c->ptr.pp_complex[ic+i+0][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+0][jc+j+1]),ae_c_mul(alpha,v01)); + c->ptr.pp_complex[ic+i+1][jc+j+0] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+0]),ae_c_mul(alpha,v10)); + c->ptr.pp_complex[ic+i+1][jc+j+1] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+i+1][jc+j+1]),ae_c_mul(alpha,v11)); + } + } + else + { + + /* + * Determine submatrix [I0..I1]x[J0..J1] to process + */ + i0 = i; + i1 = ae_minint(i+1, m-1, _state); + j0 = j; + j1 = ae_minint(j+1, n-1, _state); + + /* + * Process submatrix + */ + for(ik=i0; ik<=i1; ik++) + { + for(jk=j0; jk<=j1; jk++) + { + if( k==0||ae_c_eq_d(alpha,(double)(0)) ) + { + v = ae_complex_from_i(0); + } + else + { + v = ae_complex_from_d(0.0); + if( optypea==0&&optypeb==0 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ja,ja+k-1)); + } + if( optypea==0&&optypeb==1 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ja,ja+k-1)); + } + if( optypea==0&&optypeb==2 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+ik][ja], 1, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ja,ja+k-1)); + } + if( optypea==1&&optypeb==0 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); + } + if( optypea==1&&optypeb==1 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); + } + if( optypea==1&&optypeb==2 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "N", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); + } + if( optypea==2&&optypeb==0 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib][jb+jk], b->stride, "N", ae_v_len(ia,ia+k-1)); + } + if( optypea==2&&optypeb==1 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "N", ae_v_len(ia,ia+k-1)); + } + if( optypea==2&&optypeb==2 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia][ja+ik], a->stride, "Conj", &b->ptr.pp_complex[ib+jk][jb], 1, "Conj", ae_v_len(ia,ia+k-1)); + } + } + if( ae_c_eq_d(beta,(double)(0)) ) + { + c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_mul(alpha,v); + } + else + { + c->ptr.pp_complex[ic+ik][jc+jk] = ae_c_add(ae_c_mul(beta,c->ptr.pp_complex[ic+ik][jc+jk]),ae_c_mul(alpha,v)); + } + } + } + } + j = j+2; + } + i = i+2; + } +} + + +/************************************************************************* +RMatrixGEMM kernel, basecase code for RMatrixGEMM. + +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemmk(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * Try optimized code + */ + if( ablasf_rgemm32basecase(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) + { + return; + } + + /* + * if K=0 or Alpha=0, then C=Beta*C + */ + if( k==0||ae_fp_eq(alpha,(double)(0)) ) + { + if( ae_fp_neq(beta,(double)(1)) ) + { + if( ae_fp_neq(beta,(double)(0)) ) + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]; + } + } + } + else + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + c->ptr.pp_double[ic+i][jc+j] = (double)(0); + } + } + } + } + return; + } + + /* + * Call specialized code. + * + * NOTE: specialized code was moved to separate function because of strange + * issues with instructions cache on some systems; Having too long + * functions significantly slows down internal loop of the algorithm. + */ + if( optypea==0&&optypeb==0 ) + { + rmatrixgemmk44v00(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); + } + if( optypea==0&&optypeb!=0 ) + { + rmatrixgemmk44v01(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); + } + if( optypea!=0&&optypeb==0 ) + { + rmatrixgemmk44v10(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); + } + if( optypea!=0&&optypeb!=0 ) + { + rmatrixgemmk44v11(m, n, k, alpha, a, ia, ja, b, ib, jb, beta, c, ic, jc, _state); + } +} + + +/************************************************************************* +RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation +with OpTypeA=0 and OpTypeB=0. + +Additional info: +* this function requires that Alpha<>0 (assertion is thrown otherwise) + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + B - matrix + IB - submatrix offset + JB - submatrix offset + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemmk44v00(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double v00; + double v01; + double v02; + double v03; + double v10; + double v11; + double v12; + double v13; + double v20; + double v21; + double v22; + double v23; + double v30; + double v31; + double v32; + double v33; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + ae_int_t idxa0; + ae_int_t idxa1; + ae_int_t idxa2; + ae_int_t idxa3; + ae_int_t idxb0; + ae_int_t idxb1; + ae_int_t idxb2; + ae_int_t idxb3; + ae_int_t i0; + ae_int_t i1; + ae_int_t ik; + ae_int_t j0; + ae_int_t j1; + ae_int_t jk; + ae_int_t t; + ae_int_t offsa; + ae_int_t offsb; + + + ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * A*B + */ + i = 0; + while(iptr.pp_double[idxa0][offsa]; + a1 = a->ptr.pp_double[idxa1][offsa]; + b0 = b->ptr.pp_double[offsb][idxb0]; + b1 = b->ptr.pp_double[offsb][idxb1]; + v00 = v00+a0*b0; + v01 = v01+a0*b1; + v10 = v10+a1*b0; + v11 = v11+a1*b1; + a2 = a->ptr.pp_double[idxa2][offsa]; + a3 = a->ptr.pp_double[idxa3][offsa]; + v20 = v20+a2*b0; + v21 = v21+a2*b1; + v30 = v30+a3*b0; + v31 = v31+a3*b1; + b2 = b->ptr.pp_double[offsb][idxb2]; + b3 = b->ptr.pp_double[offsb][idxb3]; + v22 = v22+a2*b2; + v23 = v23+a2*b3; + v32 = v32+a3*b2; + v33 = v33+a3*b3; + v02 = v02+a0*b2; + v03 = v03+a0*b3; + v12 = v12+a1*b2; + v13 = v13+a1*b3; + offsa = offsa+1; + offsb = offsb+1; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; + } + else + { + c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; + } + } + else + { + + /* + * Determine submatrix [I0..I1]x[J0..J1] to process + */ + i0 = i; + i1 = ae_minint(i+3, m-1, _state); + j0 = j; + j1 = ae_minint(j+3, n-1, _state); + + /* + * Process submatrix + */ + for(ik=i0; ik<=i1; ik++) + { + for(jk=j0; jk<=j1; jk++) + { + if( k==0||ae_fp_eq(alpha,(double)(0)) ) + { + v = (double)(0); + } + else + { + v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ja,ja+k-1)); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; + } + else + { + c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; + } + } + } + } + j = j+4; + } + i = i+4; + } +} + + +/************************************************************************* +RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation +with OpTypeA=0 and OpTypeB=1. + +Additional info: +* this function requires that Alpha<>0 (assertion is thrown otherwise) + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + B - matrix + IB - submatrix offset + JB - submatrix offset + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemmk44v01(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double v00; + double v01; + double v02; + double v03; + double v10; + double v11; + double v12; + double v13; + double v20; + double v21; + double v22; + double v23; + double v30; + double v31; + double v32; + double v33; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + ae_int_t idxa0; + ae_int_t idxa1; + ae_int_t idxa2; + ae_int_t idxa3; + ae_int_t idxb0; + ae_int_t idxb1; + ae_int_t idxb2; + ae_int_t idxb3; + ae_int_t i0; + ae_int_t i1; + ae_int_t ik; + ae_int_t j0; + ae_int_t j1; + ae_int_t jk; + ae_int_t t; + ae_int_t offsa; + ae_int_t offsb; + + + ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * A*B' + */ + i = 0; + while(iptr.pp_double[idxa0][offsa]; + a1 = a->ptr.pp_double[idxa1][offsa]; + b0 = b->ptr.pp_double[idxb0][offsb]; + b1 = b->ptr.pp_double[idxb1][offsb]; + v00 = v00+a0*b0; + v01 = v01+a0*b1; + v10 = v10+a1*b0; + v11 = v11+a1*b1; + a2 = a->ptr.pp_double[idxa2][offsa]; + a3 = a->ptr.pp_double[idxa3][offsa]; + v20 = v20+a2*b0; + v21 = v21+a2*b1; + v30 = v30+a3*b0; + v31 = v31+a3*b1; + b2 = b->ptr.pp_double[idxb2][offsb]; + b3 = b->ptr.pp_double[idxb3][offsb]; + v22 = v22+a2*b2; + v23 = v23+a2*b3; + v32 = v32+a3*b2; + v33 = v33+a3*b3; + v02 = v02+a0*b2; + v03 = v03+a0*b3; + v12 = v12+a1*b2; + v13 = v13+a1*b3; + offsa = offsa+1; + offsb = offsb+1; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; + } + else + { + c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; + } + } + else + { + + /* + * Determine submatrix [I0..I1]x[J0..J1] to process + */ + i0 = i; + i1 = ae_minint(i+3, m-1, _state); + j0 = j; + j1 = ae_minint(j+3, n-1, _state); + + /* + * Process submatrix + */ + for(ik=i0; ik<=i1; ik++) + { + for(jk=j0; jk<=j1; jk++) + { + if( k==0||ae_fp_eq(alpha,(double)(0)) ) + { + v = (double)(0); + } + else + { + v = ae_v_dotproduct(&a->ptr.pp_double[ia+ik][ja], 1, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ja,ja+k-1)); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; + } + else + { + c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; + } + } + } + } + j = j+4; + } + i = i+4; + } +} + + +/************************************************************************* +RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation +with OpTypeA=1 and OpTypeB=0. + +Additional info: +* this function requires that Alpha<>0 (assertion is thrown otherwise) + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + B - matrix + IB - submatrix offset + JB - submatrix offset + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemmk44v10(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double v00; + double v01; + double v02; + double v03; + double v10; + double v11; + double v12; + double v13; + double v20; + double v21; + double v22; + double v23; + double v30; + double v31; + double v32; + double v33; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + ae_int_t idxa0; + ae_int_t idxa1; + ae_int_t idxa2; + ae_int_t idxa3; + ae_int_t idxb0; + ae_int_t idxb1; + ae_int_t idxb2; + ae_int_t idxb3; + ae_int_t i0; + ae_int_t i1; + ae_int_t ik; + ae_int_t j0; + ae_int_t j1; + ae_int_t jk; + ae_int_t t; + ae_int_t offsa; + ae_int_t offsb; + + + ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * A'*B + */ + i = 0; + while(iptr.pp_double[offsa][idxa0]; + a1 = a->ptr.pp_double[offsa][idxa1]; + b0 = b->ptr.pp_double[offsb][idxb0]; + b1 = b->ptr.pp_double[offsb][idxb1]; + v00 = v00+a0*b0; + v01 = v01+a0*b1; + v10 = v10+a1*b0; + v11 = v11+a1*b1; + a2 = a->ptr.pp_double[offsa][idxa2]; + a3 = a->ptr.pp_double[offsa][idxa3]; + v20 = v20+a2*b0; + v21 = v21+a2*b1; + v30 = v30+a3*b0; + v31 = v31+a3*b1; + b2 = b->ptr.pp_double[offsb][idxb2]; + b3 = b->ptr.pp_double[offsb][idxb3]; + v22 = v22+a2*b2; + v23 = v23+a2*b3; + v32 = v32+a3*b2; + v33 = v33+a3*b3; + v02 = v02+a0*b2; + v03 = v03+a0*b3; + v12 = v12+a1*b2; + v13 = v13+a1*b3; + offsa = offsa+1; + offsb = offsb+1; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; + } + else + { + c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; + } + } + else + { + + /* + * Determine submatrix [I0..I1]x[J0..J1] to process + */ + i0 = i; + i1 = ae_minint(i+3, m-1, _state); + j0 = j; + j1 = ae_minint(j+3, n-1, _state); + + /* + * Process submatrix + */ + for(ik=i0; ik<=i1; ik++) + { + for(jk=j0; jk<=j1; jk++) + { + if( k==0||ae_fp_eq(alpha,(double)(0)) ) + { + v = (double)(0); + } + else + { + v = 0.0; + v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib][jb+jk], b->stride, ae_v_len(ia,ia+k-1)); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; + } + else + { + c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; + } + } + } + } + j = j+4; + } + i = i+4; + } +} + + +/************************************************************************* +RMatrixGEMM kernel, basecase code for RMatrixGEMM, specialized for sitation +with OpTypeA=1 and OpTypeB=1. + +Additional info: +* this function requires that Alpha<>0 (assertion is thrown otherwise) + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + B - matrix + IB - submatrix offset + JB - submatrix offset + Beta - coefficient + C - PREALLOCATED output matrix + IC - submatrix offset + JC - submatrix offset + + -- ALGLIB routine -- + 27.03.2013 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemmk44v11(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double v00; + double v01; + double v02; + double v03; + double v10; + double v11; + double v12; + double v13; + double v20; + double v21; + double v22; + double v23; + double v30; + double v31; + double v32; + double v33; + double a0; + double a1; + double a2; + double a3; + double b0; + double b1; + double b2; + double b3; + ae_int_t idxa0; + ae_int_t idxa1; + ae_int_t idxa2; + ae_int_t idxa3; + ae_int_t idxb0; + ae_int_t idxb1; + ae_int_t idxb2; + ae_int_t idxb3; + ae_int_t i0; + ae_int_t i1; + ae_int_t ik; + ae_int_t j0; + ae_int_t j1; + ae_int_t jk; + ae_int_t t; + ae_int_t offsa; + ae_int_t offsb; + + + ae_assert(ae_fp_neq(alpha,(double)(0)), "RMatrixGEMMK44V00: internal error (Alpha=0)", _state); + + /* + * if matrix size is zero + */ + if( m==0||n==0 ) + { + return; + } + + /* + * A'*B' + */ + i = 0; + while(iptr.pp_double[offsa][idxa0]; + a1 = a->ptr.pp_double[offsa][idxa1]; + b0 = b->ptr.pp_double[idxb0][offsb]; + b1 = b->ptr.pp_double[idxb1][offsb]; + v00 = v00+a0*b0; + v01 = v01+a0*b1; + v10 = v10+a1*b0; + v11 = v11+a1*b1; + a2 = a->ptr.pp_double[offsa][idxa2]; + a3 = a->ptr.pp_double[offsa][idxa3]; + v20 = v20+a2*b0; + v21 = v21+a2*b1; + v30 = v30+a3*b0; + v31 = v31+a3*b1; + b2 = b->ptr.pp_double[idxb2][offsb]; + b3 = b->ptr.pp_double[idxb3][offsb]; + v22 = v22+a2*b2; + v23 = v23+a2*b3; + v32 = v32+a3*b2; + v33 = v33+a3*b3; + v02 = v02+a0*b2; + v03 = v03+a0*b3; + v12 = v12+a1*b2; + v13 = v13+a1*b3; + offsa = offsa+1; + offsb = offsb+1; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+i+0][jc+j+0] = alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = alpha*v33; + } + else + { + c->ptr.pp_double[ic+i+0][jc+j+0] = beta*c->ptr.pp_double[ic+i+0][jc+j+0]+alpha*v00; + c->ptr.pp_double[ic+i+0][jc+j+1] = beta*c->ptr.pp_double[ic+i+0][jc+j+1]+alpha*v01; + c->ptr.pp_double[ic+i+0][jc+j+2] = beta*c->ptr.pp_double[ic+i+0][jc+j+2]+alpha*v02; + c->ptr.pp_double[ic+i+0][jc+j+3] = beta*c->ptr.pp_double[ic+i+0][jc+j+3]+alpha*v03; + c->ptr.pp_double[ic+i+1][jc+j+0] = beta*c->ptr.pp_double[ic+i+1][jc+j+0]+alpha*v10; + c->ptr.pp_double[ic+i+1][jc+j+1] = beta*c->ptr.pp_double[ic+i+1][jc+j+1]+alpha*v11; + c->ptr.pp_double[ic+i+1][jc+j+2] = beta*c->ptr.pp_double[ic+i+1][jc+j+2]+alpha*v12; + c->ptr.pp_double[ic+i+1][jc+j+3] = beta*c->ptr.pp_double[ic+i+1][jc+j+3]+alpha*v13; + c->ptr.pp_double[ic+i+2][jc+j+0] = beta*c->ptr.pp_double[ic+i+2][jc+j+0]+alpha*v20; + c->ptr.pp_double[ic+i+2][jc+j+1] = beta*c->ptr.pp_double[ic+i+2][jc+j+1]+alpha*v21; + c->ptr.pp_double[ic+i+2][jc+j+2] = beta*c->ptr.pp_double[ic+i+2][jc+j+2]+alpha*v22; + c->ptr.pp_double[ic+i+2][jc+j+3] = beta*c->ptr.pp_double[ic+i+2][jc+j+3]+alpha*v23; + c->ptr.pp_double[ic+i+3][jc+j+0] = beta*c->ptr.pp_double[ic+i+3][jc+j+0]+alpha*v30; + c->ptr.pp_double[ic+i+3][jc+j+1] = beta*c->ptr.pp_double[ic+i+3][jc+j+1]+alpha*v31; + c->ptr.pp_double[ic+i+3][jc+j+2] = beta*c->ptr.pp_double[ic+i+3][jc+j+2]+alpha*v32; + c->ptr.pp_double[ic+i+3][jc+j+3] = beta*c->ptr.pp_double[ic+i+3][jc+j+3]+alpha*v33; + } + } + else + { + + /* + * Determine submatrix [I0..I1]x[J0..J1] to process + */ + i0 = i; + i1 = ae_minint(i+3, m-1, _state); + j0 = j; + j1 = ae_minint(j+3, n-1, _state); + + /* + * Process submatrix + */ + for(ik=i0; ik<=i1; ik++) + { + for(jk=j0; jk<=j1; jk++) + { + if( k==0||ae_fp_eq(alpha,(double)(0)) ) + { + v = (double)(0); + } + else + { + v = 0.0; + v = ae_v_dotproduct(&a->ptr.pp_double[ia][ja+ik], a->stride, &b->ptr.pp_double[ib+jk][jb], 1, ae_v_len(ia,ia+k-1)); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+ik][jc+jk] = alpha*v; + } + else + { + c->ptr.pp_double[ic+ik][jc+jk] = beta*c->ptr.pp_double[ic+ik][jc+jk]+alpha*v; + } + } + } + } + j = j+4; + } + i = i+4; + } +} + + +/************************************************************************* +Internal function which actually works with dynamic arrays. We need it to +be a separate function in order to minimize penalty associated with maintaining +a local dynamically allocated variable. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +static void ablasf_rincreaserowsfixedcolsminternal(ae_int_t newrows, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix olda; + + ae_frame_make(_state, &_frame_block); + memset(&olda, 0, sizeof(olda)); + ae_matrix_init(&olda, 0, 0, DT_REAL, _state, ae_true); + + ae_swap_matrices(a, &olda); + ae_matrix_set_length(a, ae_round(ae_maxreal(1.8*(double)olda.rows+(double)8, 1.25*(double)newrows, _state), _state), olda.cols, _state); + rcopym(olda.rows, olda.cols, &olda, a, _state); + ae_frame_leave(_state); +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Fast kernel (new version with AVX2/SSE2) + + -- ALGLIB routine -- + 19.01.2010 + Bochkanov Sergey +*************************************************************************/ +static ae_bool ablasf_rgemm32basecase(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} +#endif + + +#endif +#if defined(AE_COMPILE_HBLAS) || !defined(AE_PARTIAL_BUILD) + + +void hermitianmatrixvectormultiply(/* Complex */ const ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Complex */ const ae_vector* x, + ae_complex alpha, + /* Complex */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ba1; + ae_int_t by1; + ae_int_t by2; + ae_int_t bx1; + ae_int_t bx2; + ae_int_t n; + ae_complex v; + + + n = i2-i1+1; + if( n<=0 ) + { + return; + } + + /* + * Let A = L + D + U, where + * L is strictly lower triangular (main diagonal is zero) + * D is diagonal + * U is strictly upper triangular (main diagonal is zero) + * + * A*x = L*x + D*x + U*x + * + * Calculate D*x first + */ + for(i=i1; i<=i2; i++) + { + y->ptr.p_complex[i-i1+1] = ae_c_mul(a->ptr.pp_complex[i][i],x->ptr.p_complex[i-i1+1]); + } + + /* + * Add L*x + U*x + */ + if( isupper ) + { + for(i=i1; i<=i2-1; i++) + { + + /* + * Add L*x to the result + */ + v = x->ptr.p_complex[i-i1+1]; + by1 = i-i1+2; + by2 = n; + ba1 = i+1; + ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); + + /* + * Add U*x to the result + */ + bx1 = i-i1+2; + bx2 = n; + ba1 = i+1; + v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); + y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); + } + } + else + { + for(i=i1+1; i<=i2; i++) + { + + /* + * Add L*x to the result + */ + bx1 = 1; + bx2 = i-i1; + ba1 = i1; + v = ae_v_cdotproduct(&x->ptr.p_complex[bx1], 1, "N", &a->ptr.pp_complex[i][ba1], 1, "N", ae_v_len(bx1,bx2)); + y->ptr.p_complex[i-i1+1] = ae_c_add(y->ptr.p_complex[i-i1+1],v); + + /* + * Add U*x to the result + */ + v = x->ptr.p_complex[i-i1+1]; + by1 = 1; + by2 = i-i1; + ba1 = i1; + ae_v_caddc(&y->ptr.p_complex[by1], 1, &a->ptr.pp_complex[i][ba1], 1, "Conj", ae_v_len(by1,by2), v); + } + } + ae_v_cmulc(&y->ptr.p_complex[1], 1, ae_v_len(1,n), alpha); +} + + +void hermitianrank2update(/* Complex */ ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Complex */ const ae_vector* x, + /* Complex */ const ae_vector* y, + /* Complex */ ae_vector* t, + ae_complex alpha, + ae_state *_state) +{ + ae_int_t i; + ae_int_t tp1; + ae_int_t tp2; + ae_complex v; + + + if( isupper ) + { + for(i=i1; i<=i2; i++) + { + tp1 = i+1-i1; + tp2 = i2-i1+1; + v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); + ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); + v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); + ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); + ae_v_cadd(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i,i2)); + } + } + else + { + for(i=i1; i<=i2; i++) + { + tp1 = 1; + tp2 = i+1-i1; + v = ae_c_mul(alpha,x->ptr.p_complex[i+1-i1]); + ae_v_cmovec(&t->ptr.p_complex[tp1], 1, &y->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); + v = ae_c_mul(ae_c_conj(alpha, _state),y->ptr.p_complex[i+1-i1]); + ae_v_caddc(&t->ptr.p_complex[tp1], 1, &x->ptr.p_complex[tp1], 1, "Conj", ae_v_len(tp1,tp2), v); + ae_v_cadd(&a->ptr.pp_complex[i][i1], 1, &t->ptr.p_complex[tp1], 1, "N", ae_v_len(i1,i)); + } + } +} + + +#endif +#if defined(AE_COMPILE_CREFLECTIONS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Generation of an elementary complex reflection transformation + +The subroutine generates elementary complex reflection H of order N, so +that, for a given X, the following equality holds true: + + ( X(1) ) ( Beta ) +H' * ( .. ) = ( 0 ), H'*H = I, Beta is a real number + ( X(n) ) ( 0 ) + +where + + ( V(1) ) +H = 1 - Tau * ( .. ) * ( conj(V(1)), ..., conj(V(n)) ) + ( V(n) ) + +where the first component of vector V equals 1. + +Input parameters: + X - vector. Array with elements [1..N]. + N - reflection order. + +Output parameters: + X - components from 2 to N are replaced by vector V. + The first component is replaced with parameter Beta. + Tau - scalar value Tau. + +This subroutine is the modification of CLARFG subroutines from the LAPACK +library. It has similar functionality except for the fact that it doesn't +handle errors when intermediate results cause an overflow. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void complexgeneratereflection(/* Complex */ ae_vector* x, + ae_int_t n, + ae_complex* tau, + ae_state *_state) +{ + ae_int_t j; + ae_complex alpha; + double alphi; + double alphr; + double beta; + double xnorm; + double mx; + ae_complex t; + double s; + ae_complex v; + + tau->x = 0.0; + tau->y = 0.0; + + if( n<=0 ) + { + *tau = ae_complex_from_i(0); + return; + } + + /* + * Scale if needed (to avoid overflow/underflow during intermediate + * calculations). + */ + mx = (double)(0); + for(j=1; j<=n; j++) + { + mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); + } + s = (double)(1); + if( ae_fp_neq(mx,(double)(0)) ) + { + if( ae_fp_less(mx,(double)(1)) ) + { + s = ae_sqrt(ae_minrealnumber, _state); + v = ae_complex_from_d((double)1/s); + ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); + } + else + { + s = ae_sqrt(ae_maxrealnumber, _state); + v = ae_complex_from_d((double)1/s); + ae_v_cmulc(&x->ptr.p_complex[1], 1, ae_v_len(1,n), v); + } + } + + /* + * calculate + */ + alpha = x->ptr.p_complex[1]; + mx = (double)(0); + for(j=2; j<=n; j++) + { + mx = ae_maxreal(ae_c_abs(x->ptr.p_complex[j], _state), mx, _state); + } + xnorm = (double)(0); + if( ae_fp_neq(mx,(double)(0)) ) + { + for(j=2; j<=n; j++) + { + t = ae_c_div_d(x->ptr.p_complex[j],mx); + xnorm = xnorm+ae_c_mul(t,ae_c_conj(t, _state)).x; + } + xnorm = ae_sqrt(xnorm, _state)*mx; + } + alphr = alpha.x; + alphi = alpha.y; + if( ae_fp_eq(xnorm,(double)(0))&&ae_fp_eq(alphi,(double)(0)) ) + { + *tau = ae_complex_from_i(0); + x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); + return; + } + mx = ae_maxreal(ae_fabs(alphr, _state), ae_fabs(alphi, _state), _state); + mx = ae_maxreal(mx, ae_fabs(xnorm, _state), _state); + beta = -mx*ae_sqrt(ae_sqr(alphr/mx, _state)+ae_sqr(alphi/mx, _state)+ae_sqr(xnorm/mx, _state), _state); + if( ae_fp_less(alphr,(double)(0)) ) + { + beta = -beta; + } + tau->x = (beta-alphr)/beta; + tau->y = -alphi/beta; + alpha = ae_c_d_div((double)(1),ae_c_sub_d(alpha,beta)); + if( n>1 ) + { + ae_v_cmulc(&x->ptr.p_complex[2], 1, ae_v_len(2,n), alpha); + } + alpha = ae_complex_from_d(beta); + x->ptr.p_complex[1] = alpha; + + /* + * Scale back + */ + x->ptr.p_complex[1] = ae_c_mul_d(x->ptr.p_complex[1],s); +} + + +/************************************************************************* +Application of an elementary reflection to a rectangular matrix of size MxN + +The algorithm pre-multiplies the matrix by an elementary reflection +transformation which is given by column V and scalar Tau (see the +description of the GenerateReflection). Not the whole matrix but only a +part of it is transformed (rows from M1 to M2, columns from N1 to N2). Only +the elements of this submatrix are changed. + +Note: the matrix is multiplied by H, not by H'. If it is required to +multiply the matrix by H', it is necessary to pass Conj(Tau) instead of Tau. + +Input parameters: + C - matrix to be transformed. + Tau - scalar defining transformation. + V - column defining transformation. + Array whose index ranges within [1..M2-M1+1] + M1, M2 - range of rows to be transformed. + N1, N2 - range of columns to be transformed. + WORK - working array whose index goes from N1 to N2. + +Output parameters: + C - the result of multiplying the input matrix C by the + transformation matrix which is given by Tau and V. + If N1>N2 or M1>M2, C is not modified. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, + ae_complex tau, + /* Complex */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Complex */ ae_vector* work, + ae_state *_state) +{ + ae_complex t; + ae_int_t i; + + + if( (ae_c_eq_d(tau,(double)(0))||n1>n2)||m1>m2 ) + { + return; + } + + /* + * w := C^T * conj(v) + */ + for(i=n1; i<=n2; i++) + { + work->ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=m1; i<=m2; i++) + { + t = ae_c_conj(v->ptr.p_complex[i+1-m1], _state); + ae_v_caddc(&work->ptr.p_complex[n1], 1, &c->ptr.pp_complex[i][n1], 1, "N", ae_v_len(n1,n2), t); + } + + /* + * C := C - tau * v * w^T + */ + for(i=m1; i<=m2; i++) + { + t = ae_c_mul(v->ptr.p_complex[i-m1+1],tau); + ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &work->ptr.p_complex[n1], 1, "N", ae_v_len(n1,n2), t); + } +} + + +/************************************************************************* +Application of an elementary reflection to a rectangular matrix of size MxN + +The algorithm post-multiplies the matrix by an elementary reflection +transformation which is given by column V and scalar Tau (see the +description of the GenerateReflection). Not the whole matrix but only a +part of it is transformed (rows from M1 to M2, columns from N1 to N2). +Only the elements of this submatrix are changed. + +Input parameters: + C - matrix to be transformed. + Tau - scalar defining transformation. + V - column defining transformation. + Array whose index ranges within [1..N2-N1+1] + M1, M2 - range of rows to be transformed. + N1, N2 - range of columns to be transformed. + WORK - working array whose index goes from M1 to M2. + +Output parameters: + C - the result of multiplying the input matrix C by the + transformation matrix which is given by Tau and V. + If N1>N2 or M1>M2, C is not modified. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, + ae_complex tau, + /* Complex */ ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Complex */ ae_vector* work, + ae_state *_state) +{ + ae_complex t; + ae_int_t i; + ae_int_t vm; + + + if( (ae_c_eq_d(tau,(double)(0))||n1>n2)||m1>m2 ) + { + return; + } + + /* + * w := C * v + */ + vm = n2-n1+1; + for(i=m1; i<=m2; i++) + { + t = ae_v_cdotproduct(&c->ptr.pp_complex[i][n1], 1, "N", &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2)); + work->ptr.p_complex[i] = t; + } + + /* + * C := C - w * conj(v^T) + */ + ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); + for(i=m1; i<=m2; i++) + { + t = ae_c_mul(work->ptr.p_complex[i],tau); + ae_v_csubc(&c->ptr.pp_complex[i][n1], 1, &v->ptr.p_complex[1], 1, "N", ae_v_len(n1,n2), t); + } + ae_v_cmove(&v->ptr.p_complex[1], 1, &v->ptr.p_complex[1], 1, "Conj", ae_v_len(1,vm)); +} + + +#endif +#if defined(AE_COMPILE_SBLAS) || !defined(AE_PARTIAL_BUILD) + + +void symmetricmatrixvectormultiply(/* Real */ const ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ const ae_vector* x, + double alpha, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ba1; + ae_int_t ba2; + ae_int_t by1; + ae_int_t by2; + ae_int_t bx1; + ae_int_t bx2; + ae_int_t n; + double v; + + + n = i2-i1+1; + if( n<=0 ) + { + return; + } + + /* + * Let A = L + D + U, where + * L is strictly lower triangular (main diagonal is zero) + * D is diagonal + * U is strictly upper triangular (main diagonal is zero) + * + * A*x = L*x + D*x + U*x + * + * Calculate D*x first + */ + for(i=i1; i<=i2; i++) + { + y->ptr.p_double[i-i1+1] = a->ptr.pp_double[i][i]*x->ptr.p_double[i-i1+1]; + } + + /* + * Add L*x + U*x + */ + if( isupper ) + { + for(i=i1; i<=i2-1; i++) + { + + /* + * Add L*x to the result + */ + v = x->ptr.p_double[i-i1+1]; + by1 = i-i1+2; + by2 = n; + ba1 = i+1; + ba2 = i2; + ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); + + /* + * Add U*x to the result + */ + bx1 = i-i1+2; + bx2 = n; + ba1 = i+1; + ba2 = i2; + v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); + y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; + } + } + else + { + for(i=i1+1; i<=i2; i++) + { + + /* + * Add L*x to the result + */ + bx1 = 1; + bx2 = i-i1; + ba1 = i1; + ba2 = i-1; + v = ae_v_dotproduct(&x->ptr.p_double[bx1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(bx1,bx2)); + y->ptr.p_double[i-i1+1] = y->ptr.p_double[i-i1+1]+v; + + /* + * Add U*x to the result + */ + v = x->ptr.p_double[i-i1+1]; + by1 = 1; + by2 = i-i1; + ba1 = i1; + ba2 = i-1; + ae_v_addd(&y->ptr.p_double[by1], 1, &a->ptr.pp_double[i][ba1], 1, ae_v_len(by1,by2), v); + } + } + ae_v_muld(&y->ptr.p_double[1], 1, ae_v_len(1,n), alpha); + touchint(&ba2, _state); +} + + +void symmetricrank2update(/* Real */ ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* t, + double alpha, + ae_state *_state) +{ + ae_int_t i; + ae_int_t tp1; + ae_int_t tp2; + double v; + + + if( isupper ) + { + for(i=i1; i<=i2; i++) + { + tp1 = i+1-i1; + tp2 = i2-i1+1; + v = x->ptr.p_double[i+1-i1]; + ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); + v = y->ptr.p_double[i+1-i1]; + ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); + ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); + ae_v_add(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i,i2)); + } + } + else + { + for(i=i1; i<=i2; i++) + { + tp1 = 1; + tp2 = i+1-i1; + v = x->ptr.p_double[i+1-i1]; + ae_v_moved(&t->ptr.p_double[tp1], 1, &y->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); + v = y->ptr.p_double[i+1-i1]; + ae_v_addd(&t->ptr.p_double[tp1], 1, &x->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), v); + ae_v_muld(&t->ptr.p_double[tp1], 1, ae_v_len(tp1,tp2), alpha); + ae_v_add(&a->ptr.pp_double[i][i1], 1, &t->ptr.p_double[tp1], 1, ae_v_len(i1,i)); + } + } +} + + +#endif +#if defined(AE_COMPILE_ABLASPBL) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixgerpbl(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double alpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixrank1pbl(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixrank1pbl(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixmvpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Complex */ const ae_vector* x, + ae_int_t ix, + /* Complex */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixmvpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixgemvpbl(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL kernel + + -- ALGLIB routine -- + 12.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixtrsvpbl(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 01.10.2013 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsyrkpbl(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 01.10.2013 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixherkpbl(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 01.10.2013 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixgemmpbl(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 01.10.2017 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsymvpbl(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixgemmpbl(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixlefttrsmpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixrighttrsmpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixlefttrsmpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixrighttrsmpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: + +if function returned False, CholResult is NOT modified. Not ever referenced! +if function returned True, CholResult is set to status of Cholesky decomposition +(True on succeess). + + -- ALGLIB routine -- + 16.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixcholeskypbl(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool* cholresult, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixplupbl(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: this function needs preallocated output/temporary arrays. + D and E must be at least max(M,N)-wide. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixbdpbl(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + /* Real */ ae_vector* tauq, + /* Real */ ae_vector* taup, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +If ByQ is True, TauP is not used (can be empty array). +If ByQ is False, TauQ is not used (can be empty array). + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixbdmultiplybypbl(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + /* Real */ const ae_vector* taup, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool byq, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Tau must be preallocated array with at least N-1 elements. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixhessenbergpbl(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Q must be preallocated N*N array + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixhessenbergunpackqpbl(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Tau, D, E must be preallocated arrays; + length(E)=length(Tau)=N-1 (or larger) + length(D)=N (or larger) + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixtdpbl(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Q must be preallocated N*N array + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixtdunpackqpbl(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Tau, D, E must be preallocated arrays; + length(E)=length(Tau)=N-1 (or larger) + length(D)=N (or larger) + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool hmatrixtdpbl(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +NOTE: Q must be preallocated N*N array + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool hmatrixtdunpackqpbl(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* tau, + /* Complex */ ae_matrix* q, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +Returns True if PBL was present and handled request (PBL completion code +is returned as separate output parameter). + +D and E are pre-allocated arrays with length N (both of them!). On output, +D constraints singular values, and E is destroyed. + +SVDResult is modified if and only if PBL is present. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixbdsvdpbl(/* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_bool* svdresult, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based DHSEQR kernel. + +Returns True if PBL was present and handled request. + +WR and WI are pre-allocated arrays with length N. +Z is pre-allocated array[N,N]. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixinternalschurdecompositionpbl(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based DTREVC kernel. + +Returns True if PBL was present and handled request. + +NOTE: this function does NOT support HOWMNY=3!!!! + +VL and VR are pre-allocated arrays with length N*N, if required. If particalar +variables is not required, it can be dummy (empty) array. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixinternaltrevcpbl(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +Returns True if PBL was present and handled request (PBL completion code +is returned as separate output parameter). + +D and E are pre-allocated arrays with length N (both of them!). On output, +D constraints eigenvalues, and E is destroyed. + +Z is preallocated array[N,N] for ZNeeded<>0; ignored for ZNeeded=0. + +EVDResult is modified if and only if PBL is present. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixtdevdpbl(/* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_bool* evdresult, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +PBL-based kernel. + +Returns True if PBL was present and handled request (PBL completion code +is returned as separate output parameter). + +D and E are pre-allocated arrays with length N (both of them!). On output, +D constraints eigenvalues, and E is destroyed. + +Z is preallocated array[N,N] for ZNeeded<>0; ignored for ZNeeded=0. + +EVDResult is modified if and only if PBL is present. + + -- ALGLIB routine -- + 20.10.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsegemvcrspbl(ae_int_t opa, + ae_int_t arows, + ae_int_t acols, + double alpha, + /* Real */ const ae_vector* vals, + /* Integer */ const ae_vector* cidx, + /* Integer */ const ae_vector* ridx, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +#endif +#if defined(AE_COMPILE_SCODES) || !defined(AE_PARTIAL_BUILD) + + +ae_int_t getrdfserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 1; + return result; +} + + +ae_int_t getkdtreeserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 2; + return result; +} + + +ae_int_t getmlpserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 3; + return result; +} + + +ae_int_t getmlpeserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 4; + return result; +} + + +ae_int_t getrbfserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 5; + return result; +} + + +ae_int_t getspline2dserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 6; + return result; +} + + +ae_int_t getidwserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 7; + return result; +} + + +ae_int_t getsparsematrixserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 8; + return result; +} + + +ae_int_t getspline2dwithmissingnodesserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 9; + return result; +} + + +ae_int_t getspline1dserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 10; + return result; +} + + +ae_int_t getknnserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 108; + return result; +} + + +ae_int_t getlptestserializationcode(ae_state *_state) +{ + ae_int_t result; + + + result = 200; + return result; +} + + +#endif +#if defined(AE_COMPILE_TSORT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function sorts array of real keys by ascending. + +Its results are: +* sorted array A +* permutation tables P1, P2 + +Algorithm outputs permutation tables using two formats: +* as usual permutation of [0..N-1]. If P1[i]=j, then sorted A[i] contains + value which was moved there from J-th position. +* as a sequence of pairwise permutations. Sorted A[] may be obtained by + swaping A[i] and A[P2[i]] for all i from 0 to N-1. + +INPUT PARAMETERS: + A - unsorted array + N - array size + +OUPUT PARAMETERS: + A - sorted array + P1, P2 - permutation tables, array[N] + +NOTES: + this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. + + -- ALGLIB -- + Copyright 14.05.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsort(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + ae_state *_state) +{ + ae_frame _frame_block; + apbuffers buf; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + ae_vector_clear(p1); + ae_vector_clear(p2); + _apbuffers_init(&buf, _state, ae_true); + + tagsortbuf(a, n, p1, p2, &buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Buffered variant of TagSort, which accepts preallocated output arrays as +well as special structure for buffered allocations. If arrays are too +short, they are reallocated. If they are large enough, no memory +allocation is done. + +It is intended to be used in the performance-critical parts of code, where +additional allocations can lead to severe performance degradation + + -- ALGLIB -- + Copyright 14.05.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsortbuf(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + apbuffers* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t lv; + ae_int_t lp; + ae_int_t rv; + ae_int_t rp; + + + + /* + * Special cases + */ + if( n<=0 ) + { + return; + } + if( n==1 ) + { + ivectorsetlengthatleast(p1, 1, _state); + ivectorsetlengthatleast(p2, 1, _state); + p1->ptr.p_int[0] = 0; + p2->ptr.p_int[0] = 0; + return; + } + + /* + * General case, N>1: prepare permutations table P1 + */ + ivectorsetlengthatleast(p1, n, _state); + for(i=0; i<=n-1; i++) + { + p1->ptr.p_int[i] = i; + } + + /* + * General case, N>1: sort, update P1 + */ + rvectorsetlengthatleast(&buf->ra0, n, _state); + ivectorsetlengthatleast(&buf->ia0, n, _state); + tagsortfasti(a, p1, &buf->ra0, &buf->ia0, n, _state); + + /* + * General case, N>1: fill permutations table P2 + * + * To fill P2 we maintain two arrays: + * * PV (Buf.IA0), Position(Value). PV[i] contains position of I-th key at the moment + * * VP (Buf.IA1), Value(Position). VP[i] contains key which has position I at the moment + * + * At each step we making permutation of two items: + * Left, which is given by position/value pair LP/LV + * and Right, which is given by RP/RV + * and updating PV[] and VP[] correspondingly. + */ + ivectorsetlengthatleast(&buf->ia0, n, _state); + ivectorsetlengthatleast(&buf->ia1, n, _state); + ivectorsetlengthatleast(p2, n, _state); + for(i=0; i<=n-1; i++) + { + buf->ia0.ptr.p_int[i] = i; + buf->ia1.ptr.p_int[i] = i; + } + for(i=0; i<=n-1; i++) + { + + /* + * calculate LP, LV, RP, RV + */ + lp = i; + lv = buf->ia1.ptr.p_int[lp]; + rv = p1->ptr.p_int[i]; + rp = buf->ia0.ptr.p_int[rv]; + + /* + * Fill P2 + */ + p2->ptr.p_int[i] = rp; + + /* + * update PV and VP + */ + buf->ia1.ptr.p_int[lp] = rv; + buf->ia1.ptr.p_int[rp] = lv; + buf->ia0.ptr.p_int[lv] = rp; + buf->ia0.ptr.p_int[rv] = lp; + } +} + + +/************************************************************************* +Same as TagSort, but optimized for real keys and integer labels. + +A is sorted, and same permutations are applied to B. + +NOTES: +1. this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. +2. this function uses two buffers, BufA and BufB, each is N elements large. + They may be preallocated (which will save some time) or not, in which + case function will automatically allocate memory. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsortfasti(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Integer */ ae_vector* bufb, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool isascending; + ae_bool isdescending; + double tmpr; + ae_int_t tmpi; + + + + /* + * Special case + */ + if( n<=1 ) + { + return; + } + + /* + * Test for already sorted set + */ + isascending = ae_true; + isdescending = ae_true; + for(i=1; i<=n-1; i++) + { + isascending = isascending&&a->ptr.p_double[i]>=a->ptr.p_double[i-1]; + isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; + } + if( isascending ) + { + return; + } + if( isdescending ) + { + for(i=0; i<=n-1; i++) + { + j = n-1-i; + if( j<=i ) + { + break; + } + tmpr = a->ptr.p_double[i]; + a->ptr.p_double[i] = a->ptr.p_double[j]; + a->ptr.p_double[j] = tmpr; + tmpi = b->ptr.p_int[i]; + b->ptr.p_int[i] = b->ptr.p_int[j]; + b->ptr.p_int[j] = tmpi; + } + return; + } + + /* + * General case + */ + if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; + isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; + } + if( isascending ) + { + return; + } + if( isdescending ) + { + for(i=0; i<=n-1; i++) + { + j = n-1-i; + if( j<=i ) + { + break; + } + tmpr = a->ptr.p_double[i]; + a->ptr.p_double[i] = a->ptr.p_double[j]; + a->ptr.p_double[j] = tmpr; + tmpr = b->ptr.p_double[i]; + b->ptr.p_double[i] = b->ptr.p_double[j]; + b->ptr.p_double[j] = tmpr; + } + return; + } + + /* + * General case + */ + if( bufa->cntcntptr.p_double[i]>=a->ptr.p_double[i-1]; + isdescending = isdescending&&a->ptr.p_double[i]<=a->ptr.p_double[i-1]; + } + if( isascending ) + { + return; + } + if( isdescending ) + { + for(i=0; i<=n-1; i++) + { + j = n-1-i; + if( j<=i ) + { + break; + } + tmpr = a->ptr.p_double[i]; + a->ptr.p_double[i] = a->ptr.p_double[j]; + a->ptr.p_double[j] = tmpr; + } + return; + } + + /* + * General case + */ + if( bufa->cnt1: sort, update B + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_double[p0]; + at = a->ptr.p_double[p1]; + if( ae_fp_greater_eq(ak,at) ) + { + break; + } + a->ptr.p_double[p0] = at; + a->ptr.p_double[p1] = ak; + tmpi = b->ptr.p_int[p0]; + b->ptr.p_int[p0] = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = tmpi; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmpa = a->ptr.p_double[p1]; + a->ptr.p_double[p1] = a->ptr.p_double[p0]; + a->ptr.p_double[p0] = tmpa; + at = tmpa; + tmpi = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = b->ptr.p_int[p0]; + b->ptr.p_int[p0] = tmpi; + bt = tmpi; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_double[p1]; + if( k+1ptr.p_double[p1+1]; + if( ae_fp_greater(ak1,ak) ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( ae_fp_greater_eq(at,ak) ) + { + break; + } + a->ptr.p_double[p1] = at; + a->ptr.p_double[p0] = ak; + b->ptr.p_int[p0] = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = bt; + t = k; + } + } +} + + +/************************************************************************* +Sorting function optimized for integer keys and integer labels, can be used +to sort middle of the array + +A is sorted, and same permutations are applied to B. + +NOTES: + this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsortmiddleii(/* Integer */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t offset, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + ae_int_t tmp; + ae_int_t tmpi; + ae_int_t p0; + ae_int_t p1; + ae_int_t at; + ae_int_t ak; + ae_int_t ak1; + ae_int_t bt; + + + + /* + * Special cases + */ + if( n<=1 ) + { + return; + } + + /* + * General case, N>1: sort, update B + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_int[p0]; + at = a->ptr.p_int[p1]; + if( ak>=at ) + { + break; + } + a->ptr.p_int[p0] = at; + a->ptr.p_int[p1] = ak; + tmpi = b->ptr.p_int[p0]; + b->ptr.p_int[p0] = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = tmpi; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmp = a->ptr.p_int[p1]; + a->ptr.p_int[p1] = a->ptr.p_int[p0]; + a->ptr.p_int[p0] = tmp; + at = tmp; + tmpi = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = b->ptr.p_int[p0]; + b->ptr.p_int[p0] = tmpi; + bt = tmpi; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_int[p1]; + if( k+1ptr.p_int[p1+1]; + if( ak1>ak ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( at>=ak ) + { + break; + } + a->ptr.p_int[p1] = at; + a->ptr.p_int[p0] = ak; + b->ptr.p_int[p0] = b->ptr.p_int[p1]; + b->ptr.p_int[p1] = bt; + t = k; + } + } +} + + +/************************************************************************* +Sorting function optimized for integer keys and real labels, can be used +to sort middle of the array + +A is sorted, and same permutations are applied to B. + +NOTES: + this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsortmiddlei(/* Integer */ ae_vector* a, + ae_int_t offset, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + ae_int_t tmp; + ae_int_t p0; + ae_int_t p1; + ae_int_t at; + ae_int_t ak; + ae_int_t ak1; + + + + /* + * Special cases + */ + if( n<=1 ) + { + return; + } + + /* + * General case, N>1: sort, update B + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_int[p0]; + at = a->ptr.p_int[p1]; + if( ak>=at ) + { + break; + } + a->ptr.p_int[p0] = at; + a->ptr.p_int[p1] = ak; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmp = a->ptr.p_int[p1]; + a->ptr.p_int[p1] = a->ptr.p_int[p0]; + a->ptr.p_int[p0] = tmp; + at = tmp; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_int[p1]; + if( k+1ptr.p_int[p1+1]; + if( ak1>ak ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( at>=ak ) + { + break; + } + a->ptr.p_int[p1] = at; + a->ptr.p_int[p0] = ak; + t = k; + } + } +} + + +/************************************************************************* +Sorting function optimized for integer values (only keys, no labels), can +be used to sort middle of the array + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void sortmiddlei(/* Integer */ ae_vector* a, + ae_int_t offset, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + ae_int_t tmp; + ae_int_t p0; + ae_int_t p1; + ae_int_t at; + ae_int_t ak; + ae_int_t ak1; + + + + /* + * Special cases + */ + if( n<=1 ) + { + return; + } + + /* + * General case, N>1: sort, update B + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_int[p0]; + at = a->ptr.p_int[p1]; + if( ak>=at ) + { + break; + } + a->ptr.p_int[p0] = at; + a->ptr.p_int[p1] = ak; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmp = a->ptr.p_int[p1]; + a->ptr.p_int[p1] = a->ptr.p_int[p0]; + a->ptr.p_int[p0] = tmp; + at = tmp; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_int[p1]; + if( k+1ptr.p_int[p1+1]; + if( ak1>ak ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( at>=ak ) + { + break; + } + a->ptr.p_int[p1] = at; + a->ptr.p_int[p0] = ak; + t = k; + } + } +} + + +/************************************************************************* +Heap operations: adds element to the heap + +PARAMETERS: + A - heap itself, must be at least array[0..N] + B - array of integer tags, which are updated according to + permutations in the heap + N - size of the heap (without new element). + updated on output + VA - value of the element being added + VB - value of the tag + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void tagheappushi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t* n, + double va, + ae_int_t vb, + ae_state *_state) +{ + ae_int_t j; + ae_int_t k; + double v; + + + if( *n<0 ) + { + return; + } + + /* + * N=0 is a special case + */ + if( *n==0 ) + { + a->ptr.p_double[0] = va; + b->ptr.p_int[0] = vb; + *n = *n+1; + return; + } + + /* + * add current point to the heap + * (add to the bottom, then move up) + * + * we don't write point to the heap + * until its final position is determined + * (it allow us to reduce number of array access operations) + */ + j = *n; + *n = *n+1; + while(j>0) + { + k = (j-1)/2; + v = a->ptr.p_double[k]; + if( vptr.p_double[j] = v; + b->ptr.p_int[j] = b->ptr.p_int[k]; + j = k; + } + else + { + + /* + * element in its place. terminate. + */ + break; + } + } + a->ptr.p_double[j] = va; + b->ptr.p_int[j] = vb; +} + + +/************************************************************************* +Heap operations: replaces top element with new element +(which is moved down) + +PARAMETERS: + A - heap itself, must be at least array[0..N-1] + B - array of integer tags, which are updated according to + permutations in the heap + N - size of the heap + VA - value of the element which replaces top element + VB - value of the tag + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void tagheapreplacetopi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t n, + double va, + ae_int_t vb, + ae_state *_state) +{ + ae_int_t j; + ae_int_t k1; + ae_int_t k2; + double v; + double v1; + double v2; + + + if( n<1 ) + { + return; + } + + /* + * N=1 is a special case + */ + if( n==1 ) + { + a->ptr.p_double[0] = va; + b->ptr.p_int[0] = vb; + return; + } + + /* + * move down through heap: + * * J - current element + * * K1 - first child (always exists) + * * K2 - second child (may not exists) + * + * we don't write point to the heap + * until its final position is determined + * (it allow us to reduce number of array access operations) + */ + j = 0; + k1 = 1; + k2 = 2; + while(k1=n ) + { + + /* + * only one child. + * + * swap and terminate (because this child + * have no siblings due to heap structure) + */ + v = a->ptr.p_double[k1]; + if( v>va ) + { + a->ptr.p_double[j] = v; + b->ptr.p_int[j] = b->ptr.p_int[k1]; + j = k1; + } + break; + } + else + { + + /* + * two childs + */ + v1 = a->ptr.p_double[k1]; + v2 = a->ptr.p_double[k2]; + if( v1>v2 ) + { + if( vaptr.p_double[j] = v1; + b->ptr.p_int[j] = b->ptr.p_int[k1]; + j = k1; + } + else + { + break; + } + } + else + { + if( vaptr.p_double[j] = v2; + b->ptr.p_int[j] = b->ptr.p_int[k2]; + j = k2; + } + else + { + break; + } + } + k1 = 2*j+1; + k2 = 2*j+2; + } + } + a->ptr.p_double[j] = va; + b->ptr.p_int[j] = vb; +} + + +/************************************************************************* +Heap operations: pops top element from the heap + +PARAMETERS: + A - heap itself, must be at least array[0..N-1] + B - array of integer tags, which are updated according to + permutations in the heap + N - size of the heap, N>=1 + +On output top element is moved to A[N-1], B[N-1], heap is reordered, N is +decreased by 1. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void tagheappopi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t* n, + ae_state *_state) +{ + double va; + ae_int_t vb; + + + if( *n<1 ) + { + return; + } + + /* + * N=1 is a special case + */ + if( *n==1 ) + { + *n = 0; + return; + } + + /* + * swap top element and last element, + * then reorder heap + */ + va = a->ptr.p_double[*n-1]; + vb = b->ptr.p_int[*n-1]; + a->ptr.p_double[*n-1] = a->ptr.p_double[0]; + b->ptr.p_int[*n-1] = b->ptr.p_int[0]; + *n = *n-1; + tagheapreplacetopi(a, b, *n, va, vb, _state); +} + + +/************************************************************************* +Search first element less than T in sorted array. + +PARAMETERS: + A - sorted array by ascending from 0 to N-1 + N - number of elements in array + T - the desired element + +RESULT: + The very first element's index, which isn't less than T. +In the case when there aren't such elements, returns N. +*************************************************************************/ +ae_int_t lowerbound(/* Real */ const ae_vector* a, + ae_int_t n, + double t, + ae_state *_state) +{ + ae_int_t l; + ae_int_t half; + ae_int_t first; + ae_int_t middle; + ae_int_t result; + + + l = n; + first = 0; + while(l>0) + { + half = l/2; + middle = first+half; + if( ae_fp_less(a->ptr.p_double[middle],t) ) + { + first = middle+1; + l = l-half-1; + } + else + { + l = half; + } + } + result = first; + return result; +} + + +/************************************************************************* +Search first element more than T in sorted array. + +PARAMETERS: + A - sorted array by ascending from 0 to N-1 + N - number of elements in array + T - the desired element + + RESULT: + The very first element's index, which more than T. +In the case when there aren't such elements, returns N. +*************************************************************************/ +ae_int_t upperbound(/* Real */ const ae_vector* a, + ae_int_t n, + double t, + ae_state *_state) +{ + ae_int_t l; + ae_int_t half; + ae_int_t first; + ae_int_t middle; + ae_int_t result; + + + l = n; + first = 0; + while(l>0) + { + half = l/2; + middle = first+half; + if( ae_fp_less(t,a->ptr.p_double[middle]) ) + { + l = half; + } + else + { + first = middle+1; + l = l-half-1; + } + } + result = first; + return result; +} + + +/************************************************************************* +Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), +applies same permutations to B. + + -- ALGLIB -- + Copyright 06.09.2010 by Bochkanov Sergey +*************************************************************************/ +static void tsort_tagsortfastirec(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Integer */ ae_vector* bufb, + ae_int_t i1, + ae_int_t i2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cntless; + ae_int_t cnteq; + ae_int_t cntgreater; + double tmpr; + ae_int_t tmpi; + double v0; + double v1; + double v2; + double vp; + + + + /* + * Fast exit + */ + if( i2<=i1 ) + { + return; + } + + /* + * Non-recursive sort for small arrays + */ + if( i2-i1<=16 ) + { + for(j=i1+1; j<=i2; j++) + { + + /* + * Search elements [I1..J-1] for place to insert Jth element. + * + * This code stops immediately if we can leave A[J] at J-th position + * (all elements have same value of A[J] larger than any of them) + */ + tmpr = a->ptr.p_double[j]; + tmpi = j; + for(k=j-1; k>=i1; k--) + { + if( a->ptr.p_double[k]<=tmpr ) + { + break; + } + tmpi = k; + } + k = tmpi; + + /* + * Insert Jth element into Kth position + */ + if( k!=j ) + { + tmpr = a->ptr.p_double[j]; + tmpi = b->ptr.p_int[j]; + for(i=j-1; i>=k; i--) + { + a->ptr.p_double[i+1] = a->ptr.p_double[i]; + b->ptr.p_int[i+1] = b->ptr.p_int[i]; + } + a->ptr.p_double[k] = tmpr; + b->ptr.p_int[k] = tmpi; + } + } + return; + } + + /* + * Quicksort: choose pivot + * Here we assume that I2-I1>=2 + */ + v0 = a->ptr.p_double[i1]; + v1 = a->ptr.p_double[i1+(i2-i1)/2]; + v2 = a->ptr.p_double[i2]; + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + if( v1>v2 ) + { + tmpr = v2; + v2 = v1; + v1 = tmpr; + } + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + vp = v1; + + /* + * now pass through A/B and: + * * move elements that are LESS than VP to the left of A/B + * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) + * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order + * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) + * * move elements from the left of BufA/BufB to the end of A/B + */ + cntless = 0; + cnteq = 0; + cntgreater = 0; + for(i=i1; i<=i2; i++) + { + v0 = a->ptr.p_double[i]; + if( v0ptr.p_double[k] = v0; + b->ptr.p_int[k] = b->ptr.p_int[i]; + } + cntless = cntless+1; + continue; + } + if( v0==vp ) + { + + /* + * EQUAL + */ + k = i2-cnteq; + bufa->ptr.p_double[k] = v0; + bufb->ptr.p_int[k] = b->ptr.p_int[i]; + cnteq = cnteq+1; + continue; + } + + /* + * GREATER + */ + k = i1+cntgreater; + bufa->ptr.p_double[k] = v0; + bufb->ptr.p_int[k] = b->ptr.p_int[i]; + cntgreater = cntgreater+1; + } + for(i=0; i<=cnteq-1; i++) + { + j = i1+cntless+cnteq-1-i; + k = i2+i-(cnteq-1); + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + b->ptr.p_int[j] = bufb->ptr.p_int[k]; + } + for(i=0; i<=cntgreater-1; i++) + { + j = i1+cntless+cnteq+i; + k = i1+i; + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + b->ptr.p_int[j] = bufb->ptr.p_int[k]; + } + + /* + * Sort left and right parts of the array (ignoring middle part) + */ + tsort_tagsortfastirec(a, b, bufa, bufb, i1, i1+cntless-1, _state); + tsort_tagsortfastirec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); +} + + +/************************************************************************* +Internal TagSortFastR: sorts A[I1...I2] (both bounds are included), +applies same permutations to B. + + -- ALGLIB -- + Copyright 06.09.2010 by Bochkanov Sergey +*************************************************************************/ +static void tsort_tagsortfastrrec(/* Real */ ae_vector* a, + /* Real */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Real */ ae_vector* bufb, + ae_int_t i1, + ae_int_t i2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double tmpr; + double tmpr2; + ae_int_t tmpi; + ae_int_t cntless; + ae_int_t cnteq; + ae_int_t cntgreater; + double v0; + double v1; + double v2; + double vp; + + + + /* + * Fast exit + */ + if( i2<=i1 ) + { + return; + } + + /* + * Non-recursive sort for small arrays + */ + if( i2-i1<=16 ) + { + for(j=i1+1; j<=i2; j++) + { + + /* + * Search elements [I1..J-1] for place to insert Jth element. + * + * This code stops immediatly if we can leave A[J] at J-th position + * (all elements have same value of A[J] larger than any of them) + */ + tmpr = a->ptr.p_double[j]; + tmpi = j; + for(k=j-1; k>=i1; k--) + { + if( a->ptr.p_double[k]<=tmpr ) + { + break; + } + tmpi = k; + } + k = tmpi; + + /* + * Insert Jth element into Kth position + */ + if( k!=j ) + { + tmpr = a->ptr.p_double[j]; + tmpr2 = b->ptr.p_double[j]; + for(i=j-1; i>=k; i--) + { + a->ptr.p_double[i+1] = a->ptr.p_double[i]; + b->ptr.p_double[i+1] = b->ptr.p_double[i]; + } + a->ptr.p_double[k] = tmpr; + b->ptr.p_double[k] = tmpr2; + } + } + return; + } + + /* + * Quicksort: choose pivot + * Here we assume that I2-I1>=16 + */ + v0 = a->ptr.p_double[i1]; + v1 = a->ptr.p_double[i1+(i2-i1)/2]; + v2 = a->ptr.p_double[i2]; + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + if( v1>v2 ) + { + tmpr = v2; + v2 = v1; + v1 = tmpr; + } + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + vp = v1; + + /* + * now pass through A/B and: + * * move elements that are LESS than VP to the left of A/B + * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) + * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order + * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) + * * move elements from the left of BufA/BufB to the end of A/B + */ + cntless = 0; + cnteq = 0; + cntgreater = 0; + for(i=i1; i<=i2; i++) + { + v0 = a->ptr.p_double[i]; + if( v0ptr.p_double[k] = v0; + b->ptr.p_double[k] = b->ptr.p_double[i]; + } + cntless = cntless+1; + continue; + } + if( v0==vp ) + { + + /* + * EQUAL + */ + k = i2-cnteq; + bufa->ptr.p_double[k] = v0; + bufb->ptr.p_double[k] = b->ptr.p_double[i]; + cnteq = cnteq+1; + continue; + } + + /* + * GREATER + */ + k = i1+cntgreater; + bufa->ptr.p_double[k] = v0; + bufb->ptr.p_double[k] = b->ptr.p_double[i]; + cntgreater = cntgreater+1; + } + for(i=0; i<=cnteq-1; i++) + { + j = i1+cntless+cnteq-1-i; + k = i2+i-(cnteq-1); + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + b->ptr.p_double[j] = bufb->ptr.p_double[k]; + } + for(i=0; i<=cntgreater-1; i++) + { + j = i1+cntless+cnteq+i; + k = i1+i; + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + b->ptr.p_double[j] = bufb->ptr.p_double[k]; + } + + /* + * Sort left and right parts of the array (ignoring middle part) + */ + tsort_tagsortfastrrec(a, b, bufa, bufb, i1, i1+cntless-1, _state); + tsort_tagsortfastrrec(a, b, bufa, bufb, i1+cntless+cnteq, i2, _state); +} + + +/************************************************************************* +Internal TagSortFastI: sorts A[I1...I2] (both bounds are included), +applies same permutations to B. + + -- ALGLIB -- + Copyright 06.09.2010 by Bochkanov Sergey +*************************************************************************/ +static void tsort_tagsortfastrec(/* Real */ ae_vector* a, + /* Real */ ae_vector* bufa, + ae_int_t i1, + ae_int_t i2, + ae_state *_state) +{ + ae_int_t cntless; + ae_int_t cnteq; + ae_int_t cntgreater; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double tmpr; + ae_int_t tmpi; + double v0; + double v1; + double v2; + double vp; + + + + /* + * Fast exit + */ + if( i2<=i1 ) + { + return; + } + + /* + * Non-recursive sort for small arrays + */ + if( i2-i1<=16 ) + { + for(j=i1+1; j<=i2; j++) + { + + /* + * Search elements [I1..J-1] for place to insert Jth element. + * + * This code stops immediatly if we can leave A[J] at J-th position + * (all elements have same value of A[J] larger than any of them) + */ + tmpr = a->ptr.p_double[j]; + tmpi = j; + for(k=j-1; k>=i1; k--) + { + if( a->ptr.p_double[k]<=tmpr ) + { + break; + } + tmpi = k; + } + k = tmpi; + + /* + * Insert Jth element into Kth position + */ + if( k!=j ) + { + tmpr = a->ptr.p_double[j]; + for(i=j-1; i>=k; i--) + { + a->ptr.p_double[i+1] = a->ptr.p_double[i]; + } + a->ptr.p_double[k] = tmpr; + } + } + return; + } + + /* + * Quicksort: choose pivot + * Here we assume that I2-I1>=16 + */ + v0 = a->ptr.p_double[i1]; + v1 = a->ptr.p_double[i1+(i2-i1)/2]; + v2 = a->ptr.p_double[i2]; + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + if( v1>v2 ) + { + tmpr = v2; + v2 = v1; + v1 = tmpr; + } + if( v0>v1 ) + { + tmpr = v1; + v1 = v0; + v0 = tmpr; + } + vp = v1; + + /* + * now pass through A/B and: + * * move elements that are LESS than VP to the left of A/B + * * move elements that are EQUAL to VP to the right of BufA/BufB (in the reverse order) + * * move elements that are GREATER than VP to the left of BufA/BufB (in the normal order + * * move elements from the tail of BufA/BufB to the middle of A/B (restoring normal order) + * * move elements from the left of BufA/BufB to the end of A/B + */ + cntless = 0; + cnteq = 0; + cntgreater = 0; + for(i=i1; i<=i2; i++) + { + v0 = a->ptr.p_double[i]; + if( v0ptr.p_double[k] = v0; + } + cntless = cntless+1; + continue; + } + if( v0==vp ) + { + + /* + * EQUAL + */ + k = i2-cnteq; + bufa->ptr.p_double[k] = v0; + cnteq = cnteq+1; + continue; + } + + /* + * GREATER + */ + k = i1+cntgreater; + bufa->ptr.p_double[k] = v0; + cntgreater = cntgreater+1; + } + for(i=0; i<=cnteq-1; i++) + { + j = i1+cntless+cnteq-1-i; + k = i2+i-(cnteq-1); + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + } + for(i=0; i<=cntgreater-1; i++) + { + j = i1+cntless+cnteq+i; + k = i1+i; + a->ptr.p_double[j] = bufa->ptr.p_double[k]; + } + + /* + * Sort left and right parts of the array (ignoring middle part) + */ + tsort_tagsortfastrec(a, bufa, i1, i1+cntless-1, _state); + tsort_tagsortfastrec(a, bufa, i1+cntless+cnteq, i2, _state); +} + + +#endif +#if defined(AE_COMPILE_BLAS) || !defined(AE_PARTIAL_BUILD) + + +double vectornorm2(/* Real */ const ae_vector* x, + ae_int_t i1, + ae_int_t i2, + ae_state *_state) +{ + ae_int_t n; + ae_int_t ix; + double absxi; + double scl; + double ssq; + double result; + + + n = i2-i1+1; + if( n<1 ) + { + result = (double)(0); + return result; + } + if( n==1 ) + { + result = ae_fabs(x->ptr.p_double[i1], _state); + return result; + } + scl = (double)(0); + ssq = (double)(1); + for(ix=i1; ix<=i2; ix++) + { + if( ae_fp_neq(x->ptr.p_double[ix],(double)(0)) ) + { + absxi = ae_fabs(x->ptr.p_double[ix], _state); + if( ae_fp_less(scl,absxi) ) + { + ssq = (double)1+ssq*ae_sqr(scl/absxi, _state); + scl = absxi; + } + else + { + ssq = ssq+ae_sqr(absxi/scl, _state); + } + } + } + result = scl*ae_sqrt(ssq, _state); + return result; +} + + +ae_int_t vectoridxabsmax(/* Real */ const ae_vector* x, + ae_int_t i1, + ae_int_t i2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t result; + + + result = i1; + for(i=i1+1; i<=i2; i++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[result], _state)) ) + { + result = i; + } + } + return result; +} + + +ae_int_t columnidxabsmax(/* Real */ const ae_matrix* x, + ae_int_t i1, + ae_int_t i2, + ae_int_t j, + ae_state *_state) +{ + ae_int_t i; + ae_int_t result; + + + result = i1; + for(i=i1+1; i<=i2; i++) + { + if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[result][j], _state)) ) + { + result = i; + } + } + return result; +} + + +ae_int_t rowidxabsmax(/* Real */ const ae_matrix* x, + ae_int_t j1, + ae_int_t j2, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + ae_int_t result; + + + result = j1; + for(j=j1+1; j<=j2; j++) + { + if( ae_fp_greater(ae_fabs(x->ptr.pp_double[i][j], _state),ae_fabs(x->ptr.pp_double[i][result], _state)) ) + { + result = j; + } + } + return result; +} + + +double upperhessenberg1norm(/* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double result; + + + ae_assert(i2-i1==j2-j1, "UpperHessenberg1Norm: I2-I1<>J2-J1!", _state); + for(j=j1; j<=j2; j++) + { + work->ptr.p_double[j] = (double)(0); + } + for(i=i1; i<=i2; i++) + { + for(j=ae_maxint(j1, j1+i-i1-1, _state); j<=j2; j++) + { + work->ptr.p_double[j] = work->ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); + } + } + result = (double)(0); + for(j=j1; j<=j2; j++) + { + result = ae_maxreal(result, work->ptr.p_double[j], _state); + } + return result; +} + + +void copymatrix(/* Real */ const ae_matrix* a, + ae_int_t is1, + ae_int_t is2, + ae_int_t js1, + ae_int_t js2, + /* Real */ ae_matrix* b, + ae_int_t id1, + ae_int_t id2, + ae_int_t jd1, + ae_int_t jd2, + ae_state *_state) +{ + ae_int_t isrc; + ae_int_t idst; + + + if( is1>is2||js1>js2 ) + { + return; + } + ae_assert(is2-is1==id2-id1, "CopyMatrix: different sizes!", _state); + ae_assert(js2-js1==jd2-jd1, "CopyMatrix: different sizes!", _state); + for(isrc=is1; isrc<=is2; isrc++) + { + idst = isrc-is1+id1; + ae_v_move(&b->ptr.pp_double[idst][jd1], 1, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(jd1,jd2)); + } +} + + +void inplacetranspose(/* Real */ ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ips; + ae_int_t jps; + ae_int_t l; + + + if( i1>i2||j1>j2 ) + { + return; + } + ae_assert(i1-i2==j1-j2, "InplaceTranspose error: incorrect array size!", _state); + for(i=i1; i<=i2-1; i++) + { + j = j1+i-i1; + ips = i+1; + jps = j1+ips-i1; + l = i2-i; + ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ips][j], a->stride, ae_v_len(1,l)); + ae_v_move(&a->ptr.pp_double[ips][j], a->stride, &a->ptr.pp_double[i][jps], 1, ae_v_len(ips,i2)); + ae_v_move(&a->ptr.pp_double[i][jps], 1, &work->ptr.p_double[1], 1, ae_v_len(jps,j2)); + } +} + + +void copyandtranspose(/* Real */ const ae_matrix* a, + ae_int_t is1, + ae_int_t is2, + ae_int_t js1, + ae_int_t js2, + /* Real */ ae_matrix* b, + ae_int_t id1, + ae_int_t id2, + ae_int_t jd1, + ae_int_t jd2, + ae_state *_state) +{ + ae_int_t isrc; + ae_int_t jdst; + + + if( is1>is2||js1>js2 ) + { + return; + } + ae_assert(is2-is1==jd2-jd1, "CopyAndTranspose: different sizes!", _state); + ae_assert(js2-js1==id2-id1, "CopyAndTranspose: different sizes!", _state); + for(isrc=is1; isrc<=is2; isrc++) + { + jdst = isrc-is1+jd1; + ae_v_move(&b->ptr.pp_double[id1][jdst], b->stride, &a->ptr.pp_double[isrc][js1], 1, ae_v_len(id1,id2)); + } +} + + +void matrixvectormultiply(/* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + ae_bool trans, + /* Real */ const ae_vector* x, + ae_int_t ix1, + ae_int_t ix2, + double alpha, + /* Real */ ae_vector* y, + ae_int_t iy1, + ae_int_t iy2, + double beta, + ae_state *_state) +{ + ae_int_t i; + double v; + + + if( !trans ) + { + + /* + * y := alpha*A*x + beta*y; + */ + if( i1>i2||j1>j2 ) + { + return; + } + ae_assert(j2-j1==ix2-ix1, "MatrixVectorMultiply: A and X dont match!", _state); + ae_assert(i2-i1==iy2-iy1, "MatrixVectorMultiply: A and Y dont match!", _state); + + /* + * beta*y + */ + if( ae_fp_eq(beta,(double)(0)) ) + { + for(i=iy1; i<=iy2; i++) + { + y->ptr.p_double[i] = (double)(0); + } + } + else + { + ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); + } + + /* + * alpha*A*x + */ + for(i=i1; i<=i2; i++) + { + v = ae_v_dotproduct(&a->ptr.pp_double[i][j1], 1, &x->ptr.p_double[ix1], 1, ae_v_len(j1,j2)); + y->ptr.p_double[iy1+i-i1] = y->ptr.p_double[iy1+i-i1]+alpha*v; + } + } + else + { + + /* + * y := alpha*A'*x + beta*y; + */ + if( i1>i2||j1>j2 ) + { + return; + } + ae_assert(i2-i1==ix2-ix1, "MatrixVectorMultiply: A and X dont match!", _state); + ae_assert(j2-j1==iy2-iy1, "MatrixVectorMultiply: A and Y dont match!", _state); + + /* + * beta*y + */ + if( ae_fp_eq(beta,(double)(0)) ) + { + for(i=iy1; i<=iy2; i++) + { + y->ptr.p_double[i] = (double)(0); + } + } + else + { + ae_v_muld(&y->ptr.p_double[iy1], 1, ae_v_len(iy1,iy2), beta); + } + + /* + * alpha*A'*x + */ + for(i=i1; i<=i2; i++) + { + v = alpha*x->ptr.p_double[ix1+i-i1]; + ae_v_addd(&y->ptr.p_double[iy1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(iy1,iy2), v); + } + } +} + + +double pythag2(double x, double y, ae_state *_state) +{ + double w; + double xabs; + double yabs; + double z; + double result; + + + xabs = ae_fabs(x, _state); + yabs = ae_fabs(y, _state); + w = ae_maxreal(xabs, yabs, _state); + z = ae_minreal(xabs, yabs, _state); + if( ae_fp_eq(z,(double)(0)) ) + { + result = w; + } + else + { + result = w*ae_sqrt((double)1+ae_sqr(z/w, _state), _state); + } + return result; +} + + +void matrixmatrixmultiply(/* Real */ const ae_matrix* a, + ae_int_t ai1, + ae_int_t ai2, + ae_int_t aj1, + ae_int_t aj2, + ae_bool transa, + /* Real */ const ae_matrix* b, + ae_int_t bi1, + ae_int_t bi2, + ae_int_t bj1, + ae_int_t bj2, + ae_bool transb, + double alpha, + /* Real */ ae_matrix* c, + ae_int_t ci1, + ae_int_t ci2, + ae_int_t cj1, + ae_int_t cj2, + double beta, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t arows; + ae_int_t acols; + ae_int_t brows; + ae_int_t bcols; + ae_int_t crows; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t l; + ae_int_t r; + double v; + + + + /* + * Setup + */ + if( !transa ) + { + arows = ai2-ai1+1; + acols = aj2-aj1+1; + } + else + { + arows = aj2-aj1+1; + acols = ai2-ai1+1; + } + if( !transb ) + { + brows = bi2-bi1+1; + bcols = bj2-bj1+1; + } + else + { + brows = bj2-bj1+1; + bcols = bi2-bi1+1; + } + ae_assert(acols==brows, "MatrixMatrixMultiply: incorrect matrix sizes!", _state); + if( ((arows<=0||acols<=0)||brows<=0)||bcols<=0 ) + { + return; + } + crows = arows; + + /* + * Test WORK + */ + i = ae_maxint(arows, acols, _state); + i = ae_maxint(brows, i, _state); + i = ae_maxint(i, bcols, _state); + work->ptr.p_double[1] = (double)(0); + work->ptr.p_double[i] = (double)(0); + + /* + * Prepare C + */ + if( ae_fp_eq(beta,(double)(0)) ) + { + for(i=ci1; i<=ci2; i++) + { + for(j=cj1; j<=cj2; j++) + { + c->ptr.pp_double[i][j] = (double)(0); + } + } + } + else + { + for(i=ci1; i<=ci2; i++) + { + ae_v_muld(&c->ptr.pp_double[i][cj1], 1, ae_v_len(cj1,cj2), beta); + } + } + + /* + * A*B + */ + if( !transa&&!transb ) + { + for(l=ai1; l<=ai2; l++) + { + for(r=bi1; r<=bi2; r++) + { + v = alpha*a->ptr.pp_double[l][aj1+r-bi1]; + k = ci1+l-ai1; + ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); + } + } + return; + } + + /* + * A*B' + */ + if( !transa&&transb ) + { + if( arows*acolsptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); + c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; + } + } + return; + } + else + { + for(l=ai1; l<=ai2; l++) + { + for(r=bi1; r<=bi2; r++) + { + v = ae_v_dotproduct(&a->ptr.pp_double[l][aj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(aj1,aj2)); + c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-ai1][cj1+r-bi1]+alpha*v; + } + } + return; + } + } + + /* + * A'*B + */ + if( transa&&!transb ) + { + for(l=aj1; l<=aj2; l++) + { + for(r=bi1; r<=bi2; r++) + { + v = alpha*a->ptr.pp_double[ai1+r-bi1][l]; + k = ci1+l-aj1; + ae_v_addd(&c->ptr.pp_double[k][cj1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(cj1,cj2), v); + } + } + return; + } + + /* + * A'*B' + */ + if( transa&&transb ) + { + if( arows*acolsptr.p_double[i] = 0.0; + } + for(l=ai1; l<=ai2; l++) + { + v = alpha*b->ptr.pp_double[r][bj1+l-ai1]; + ae_v_addd(&work->ptr.p_double[1], 1, &a->ptr.pp_double[l][aj1], 1, ae_v_len(1,crows), v); + } + ae_v_add(&c->ptr.pp_double[ci1][k], c->stride, &work->ptr.p_double[1], 1, ae_v_len(ci1,ci2)); + } + return; + } + else + { + for(l=aj1; l<=aj2; l++) + { + k = ai2-ai1+1; + ae_v_move(&work->ptr.p_double[1], 1, &a->ptr.pp_double[ai1][l], a->stride, ae_v_len(1,k)); + for(r=bi1; r<=bi2; r++) + { + v = ae_v_dotproduct(&work->ptr.p_double[1], 1, &b->ptr.pp_double[r][bj1], 1, ae_v_len(1,k)); + c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1] = c->ptr.pp_double[ci1+l-aj1][cj1+r-bi1]+alpha*v; + } + } + return; + } + } +} + + +#endif +#if defined(AE_COMPILE_ROTATIONS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Application of a sequence of elementary rotations to a matrix + +The algorithm pre-multiplies the matrix by a sequence of rotation +transformations which is given by arrays C and S. Depending on the value +of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) +rows are rotated, or the rows N and N-1, N-2 and N-3 and so on, are rotated. + +Not the whole matrix but only a part of it is transformed (rows from M1 to +M2, columns from N1 to N2). Only the elements of this submatrix are changed. + +Input parameters: + IsForward - the sequence of the rotation application. + M1,M2 - the range of rows to be transformed. + N1, N2 - the range of columns to be transformed. + C,S - transformation coefficients. + Array whose index ranges within [1..M2-M1]. + A - processed matrix. + WORK - working array whose index ranges within [N1..N2]. + +Output parameters: + A - transformed matrix. + +Utility subroutine. +*************************************************************************/ +void applyrotationsfromtheleft(ae_bool isforward, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t j; + ae_int_t jp1; + double ctemp; + double stemp; + double temp; + + + if( m1>m2||n1>n2 ) + { + return; + } + + /* + * Form P * A + */ + if( isforward ) + { + if( n1!=n2 ) + { + + /* + * Common case: N1<>N2 + */ + for(j=m1; j<=m2-1; j++) + { + ctemp = c->ptr.p_double[j-m1+1]; + stemp = s->ptr.p_double[j-m1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + jp1 = j+1; + ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); + ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); + ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); + ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); + ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); + } + } + } + else + { + + /* + * Special case: N1=N2 + */ + for(j=m1; j<=m2-1; j++) + { + ctemp = c->ptr.p_double[j-m1+1]; + stemp = s->ptr.p_double[j-m1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + temp = a->ptr.pp_double[j+1][n1]; + a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; + a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; + } + } + } + } + else + { + if( n1!=n2 ) + { + + /* + * Common case: N1<>N2 + */ + for(j=m2-1; j>=m1; j--) + { + ctemp = c->ptr.p_double[j-m1+1]; + stemp = s->ptr.p_double[j-m1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + jp1 = j+1; + ae_v_moved(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), ctemp); + ae_v_subd(&work->ptr.p_double[n1], 1, &a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), stemp); + ae_v_muld(&a->ptr.pp_double[j][n1], 1, ae_v_len(n1,n2), ctemp); + ae_v_addd(&a->ptr.pp_double[j][n1], 1, &a->ptr.pp_double[jp1][n1], 1, ae_v_len(n1,n2), stemp); + ae_v_move(&a->ptr.pp_double[jp1][n1], 1, &work->ptr.p_double[n1], 1, ae_v_len(n1,n2)); + } + } + } + else + { + + /* + * Special case: N1=N2 + */ + for(j=m2-1; j>=m1; j--) + { + ctemp = c->ptr.p_double[j-m1+1]; + stemp = s->ptr.p_double[j-m1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + temp = a->ptr.pp_double[j+1][n1]; + a->ptr.pp_double[j+1][n1] = ctemp*temp-stemp*a->ptr.pp_double[j][n1]; + a->ptr.pp_double[j][n1] = stemp*temp+ctemp*a->ptr.pp_double[j][n1]; + } + } + } + } +} + + +/************************************************************************* +Application of a sequence of elementary rotations to a matrix + +The algorithm post-multiplies the matrix by a sequence of rotation +transformations which is given by arrays C and S. Depending on the value +of the IsForward parameter either 1 and 2, 3 and 4 and so on (if IsForward=true) +rows are rotated, or the rows N and N-1, N-2 and N-3 and so on are rotated. + +Not the whole matrix but only a part of it is transformed (rows from M1 +to M2, columns from N1 to N2). Only the elements of this submatrix are changed. + +Input parameters: + IsForward - the sequence of the rotation application. + M1,M2 - the range of rows to be transformed. + N1, N2 - the range of columns to be transformed. + C,S - transformation coefficients. + Array whose index ranges within [1..N2-N1]. + A - processed matrix. + WORK - working array whose index ranges within [M1..M2]. + +Output parameters: + A - transformed matrix. + +Utility subroutine. +*************************************************************************/ +void applyrotationsfromtheright(ae_bool isforward, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t j; + ae_int_t jp1; + double ctemp; + double stemp; + double temp; + + + + /* + * Form A * P' + */ + if( isforward ) + { + if( m1!=m2 ) + { + + /* + * Common case: M1<>M2 + */ + for(j=n1; j<=n2-1; j++) + { + ctemp = c->ptr.p_double[j-n1+1]; + stemp = s->ptr.p_double[j-n1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + jp1 = j+1; + ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); + ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); + ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); + ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); + ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); + } + } + } + else + { + + /* + * Special case: M1=M2 + */ + for(j=n1; j<=n2-1; j++) + { + ctemp = c->ptr.p_double[j-n1+1]; + stemp = s->ptr.p_double[j-n1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + temp = a->ptr.pp_double[m1][j+1]; + a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; + a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; + } + } + } + } + else + { + if( m1!=m2 ) + { + + /* + * Common case: M1<>M2 + */ + for(j=n2-1; j>=n1; j--) + { + ctemp = c->ptr.p_double[j-n1+1]; + stemp = s->ptr.p_double[j-n1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + jp1 = j+1; + ae_v_moved(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), ctemp); + ae_v_subd(&work->ptr.p_double[m1], 1, &a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), stemp); + ae_v_muld(&a->ptr.pp_double[m1][j], a->stride, ae_v_len(m1,m2), ctemp); + ae_v_addd(&a->ptr.pp_double[m1][j], a->stride, &a->ptr.pp_double[m1][jp1], a->stride, ae_v_len(m1,m2), stemp); + ae_v_move(&a->ptr.pp_double[m1][jp1], a->stride, &work->ptr.p_double[m1], 1, ae_v_len(m1,m2)); + } + } + } + else + { + + /* + * Special case: M1=M2 + */ + for(j=n2-1; j>=n1; j--) + { + ctemp = c->ptr.p_double[j-n1+1]; + stemp = s->ptr.p_double[j-n1+1]; + if( ae_fp_neq(ctemp,(double)(1))||ae_fp_neq(stemp,(double)(0)) ) + { + temp = a->ptr.pp_double[m1][j+1]; + a->ptr.pp_double[m1][j+1] = ctemp*temp-stemp*a->ptr.pp_double[m1][j]; + a->ptr.pp_double[m1][j] = stemp*temp+ctemp*a->ptr.pp_double[m1][j]; + } + } + } + } +} + + +/************************************************************************* +The subroutine generates the elementary rotation, so that: + +[ CS SN ] . [ F ] = [ R ] +[ -SN CS ] [ G ] [ 0 ] + +CS**2 + SN**2 = 1 +*************************************************************************/ +void generaterotation(double f, + double g, + double* cs, + double* sn, + double* r, + ae_state *_state) +{ + double f1; + double g1; + + *cs = 0.0; + *sn = 0.0; + *r = 0.0; + + if( ae_fp_eq(g,(double)(0)) ) + { + *cs = (double)(1); + *sn = (double)(0); + *r = f; + } + else + { + if( ae_fp_eq(f,(double)(0)) ) + { + *cs = (double)(0); + *sn = (double)(1); + *r = g; + } + else + { + f1 = f; + g1 = g; + if( ae_fp_greater(ae_fabs(f1, _state),ae_fabs(g1, _state)) ) + { + *r = ae_fabs(f1, _state)*ae_sqrt((double)1+ae_sqr(g1/f1, _state), _state); + } + else + { + *r = ae_fabs(g1, _state)*ae_sqrt((double)1+ae_sqr(f1/g1, _state), _state); + } + *cs = f1/(*r); + *sn = g1/(*r); + if( ae_fp_greater(ae_fabs(f, _state),ae_fabs(g, _state))&&ae_fp_less(*cs,(double)(0)) ) + { + *cs = -*cs; + *sn = -*sn; + *r = -*r; + } + } + } +} + + +#endif +#if defined(AE_COMPILE_BASICSTATOPS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Internal tied ranking subroutine. + +INPUT PARAMETERS: + X - array to rank + N - array size + IsCentered- whether ranks are centered or not: + * True - ranks are centered in such way that their + sum is zero + * False - ranks are not centered + Buf - temporary buffers + +NOTE: when IsCentered is True and all X[] are equal, this function fills + X by zeros (exact zeros are used, not sum which is only approximately + equal to zero). +*************************************************************************/ +void rankx(/* Real */ ae_vector* x, + ae_int_t n, + ae_bool iscentered, + apbuffers* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double tmp; + double voffs; + + + + /* + * Prepare + */ + if( n<1 ) + { + return; + } + if( n==1 ) + { + x->ptr.p_double[0] = (double)(0); + return; + } + if( buf->ra1.cntra1, n, _state); + } + if( buf->ia1.cntia1, n, _state); + } + for(i=0; i<=n-1; i++) + { + buf->ra1.ptr.p_double[i] = x->ptr.p_double[i]; + buf->ia1.ptr.p_int[i] = i; + } + tagsortfasti(&buf->ra1, &buf->ia1, &buf->ra2, &buf->ia2, n, _state); + + /* + * Special test for all values being equal + */ + if( ae_fp_eq(buf->ra1.ptr.p_double[0],buf->ra1.ptr.p_double[n-1]) ) + { + if( iscentered ) + { + tmp = 0.0; + } + else + { + tmp = (double)(n-1)/(double)2; + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = tmp; + } + return; + } + + /* + * compute tied ranks + */ + i = 0; + while(i<=n-1) + { + j = i+1; + while(j<=n-1) + { + if( ae_fp_neq(buf->ra1.ptr.p_double[j],buf->ra1.ptr.p_double[i]) ) + { + break; + } + j = j+1; + } + for(k=i; k<=j-1; k++) + { + buf->ra1.ptr.p_double[k] = (double)(i+j-1)/(double)2; + } + i = j; + } + + /* + * back to x + */ + if( iscentered ) + { + voffs = (double)(n-1)/(double)2; + } + else + { + voffs = 0.0; + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[buf->ia1.ptr.p_int[i]] = buf->ra1.ptr.p_double[i]-voffs; + } +} + + +/************************************************************************* +Internal untied ranking subroutine. + +INPUT PARAMETERS: + X - array to rank + N - array size + Buf - temporary buffers + +Returns untied ranks (in case of a tie ranks are resolved arbitrarily). +*************************************************************************/ +void rankxuntied(/* Real */ ae_vector* x, + ae_int_t n, + apbuffers* buf, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * Prepare + */ + if( n<1 ) + { + return; + } + if( n==1 ) + { + x->ptr.p_double[0] = (double)(0); + return; + } + if( buf->ra1.cntra1, n, _state); + } + if( buf->ia1.cntia1, n, _state); + } + for(i=0; i<=n-1; i++) + { + buf->ra1.ptr.p_double[i] = x->ptr.p_double[i]; + buf->ia1.ptr.p_int[i] = i; + } + tagsortfasti(&buf->ra1, &buf->ia1, &buf->ra2, &buf->ia2, n, _state); + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[buf->ia1.ptr.p_int[i]] = (double)(i); + } +} + + +#endif +#if defined(AE_COMPILE_APSTRUCT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initializes n-set by empty structure. + +IMPORTANT: this function need O(N) time for initialization. It is recommended + to reduce its usage as much as possible, and use nisClear() + where possible. + +INPUT PARAMETERS + N - possible set size + +OUTPUT PARAMETERS + SA - empty N-set + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void nisinitemptyslow(ae_int_t n, niset* sa, ae_state *_state) +{ + + + sa->n = n; + sa->nstored = 0; + isetallocv(n, -999999999, &sa->locationof, _state); + isetallocv(n, -999999999, &sa->items, _state); +} + + +/************************************************************************* +Copies n-set to properly initialized target set. The target set has to be +properly initialized, and it can be non-empty. If it is non-empty, its +contents is quickly erased before copying. + +The cost of this function is O(max(SrcSize,DstSize)) + +INPUT PARAMETERS + SSrc - source N-set + SDst - destination N-set (has same size as SSrc) + +OUTPUT PARAMETERS + SDst - copy of SSrc + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void niscopy(const niset* ssrc, niset* sdst, ae_state *_state) +{ + ae_int_t ns; + ae_int_t i; + ae_int_t k; + + + nisclear(sdst, _state); + ns = ssrc->nstored; + for(i=0; i<=ns-1; i++) + { + k = ssrc->items.ptr.p_int[i]; + sdst->items.ptr.p_int[i] = k; + sdst->locationof.ptr.p_int[k] = i; + } + sdst->nstored = ns; +} + + +/************************************************************************* +Add K-th element to the set. The element may already exist in the set. + +INPUT PARAMETERS + SA - set + K - element to add, 0<=Klocationof.ptr.p_int[k]>=0 ) + { + return; + } + ns = sa->nstored; + sa->locationof.ptr.p_int[k] = ns; + sa->items.ptr.p_int[ns] = k; + sa->nstored = ns+1; +} + + +/************************************************************************* +Subtracts K-th set from the source structure + +INPUT PARAMETERS + SA - set + Src, K - source kn-set and set index K + +OUTPUT PARAMETERS + SA - modified SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void nissubtract1(niset* sa, const niset* src, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t loc; + ae_int_t item; + ae_int_t ns; + ae_int_t ss; + + + ns = sa->nstored; + ss = src->nstored; + if( ssitems.ptr.p_int[i]; + loc = sa->locationof.ptr.p_int[j]; + if( loc>=0 ) + { + item = sa->items.ptr.p_int[ns-1]; + sa->items.ptr.p_int[loc] = item; + sa->locationof.ptr.p_int[item] = loc; + sa->locationof.ptr.p_int[j] = -1; + ns = ns-1; + } + } + } + else + { + i = 0; + while(iitems.ptr.p_int[i]; + loc = src->locationof.ptr.p_int[j]; + if( loc>=0 ) + { + item = sa->items.ptr.p_int[ns-1]; + sa->items.ptr.p_int[i] = item; + sa->locationof.ptr.p_int[item] = i; + sa->locationof.ptr.p_int[j] = -1; + ns = ns-1; + } + else + { + i = i+1; + } + } + } + sa->nstored = ns; +} + + +/************************************************************************* +Clears set + +INPUT PARAMETERS + SA - set to be cleared + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void nisclear(niset* sa, ae_state *_state) +{ + ae_int_t i; + ae_int_t ns; + + + ns = sa->nstored; + for(i=0; i<=ns-1; i++) + { + sa->locationof.ptr.p_int[sa->items.ptr.p_int[i]] = -1; + } + sa->nstored = 0; +} + + +/************************************************************************* +Counts set elements + +INPUT PARAMETERS + SA - set + +RESULT + number of elements in SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_int_t niscount(const niset* sa, ae_state *_state) +{ + ae_int_t result; + + + result = sa->nstored; + return result; +} + + +/************************************************************************* +Compare two sets, returns True for equal sets + +INPUT PARAMETERS + S0 - set 0 + S1 - set 1, must have same parameter N as set 0 + +RESULT + True, if sets are equal + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_bool nisequal(const niset* s0, const niset* s1, ae_state *_state) +{ + ae_int_t i; + ae_int_t ns0; + ae_int_t ns1; + ae_bool result; + + + result = ae_false; + if( s0->n!=s1->n ) + { + return result; + } + if( s0->nstored!=s1->nstored ) + { + return result; + } + ns0 = s0->nstored; + ns1 = s1->nstored; + for(i=0; i<=ns0-1; i++) + { + if( s1->locationof.ptr.p_int[s0->items.ptr.p_int[i]]<0 ) + { + return result; + } + } + for(i=0; i<=ns1-1; i++) + { + if( s0->locationof.ptr.p_int[s1->items.ptr.p_int[i]]<0 ) + { + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Prepares iteration over set + +INPUT PARAMETERS + SA - set + +OUTPUT PARAMETERS + SA - SA ready for repeated calls of nisEnumerate() + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void nisstartenumeration(niset* sa, ae_state *_state) +{ + + + sa->iteridx = 0; +} + + +/************************************************************************* +Iterates over the set. Subsequent calls return True and set J to new set +item until iteration stops and False is returned. + +INPUT PARAMETERS + SA - n-set + +OUTPUT PARAMETERS + J - if: + * Result=True - index of element in the set + * Result=False - not set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_bool nisenumerate(niset* sa, ae_int_t* i, ae_state *_state) +{ + ae_int_t k; + ae_bool result; + + *i = 0; + + k = sa->iteridx; + if( k>=sa->nstored ) + { + result = ae_false; + return result; + } + *i = sa->items.ptr.p_int[k]; + sa->iteridx = k+1; + result = ae_true; + return result; +} + + +/************************************************************************* +Compresses internal storage, reclaiming previously dropped blocks. To be +used internally by kn-set modification functions. + +INPUT PARAMETERS + SA - kn-set to compress + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void kniscompressstorage(kniset* sa, ae_state *_state) +{ + ae_int_t i; + ae_int_t blocklen; + ae_int_t setidx; + ae_int_t srcoffs; + ae_int_t dstoffs; + + + ae_assert(sa->storagemode==0, "knisCompressStorage: unexpected storage mode", _state); + srcoffs = 0; + dstoffs = 0; + while(srcoffsdataused) + { + blocklen = sa->data.ptr.p_int[srcoffs+0]; + setidx = sa->data.ptr.p_int[srcoffs+1]; + ae_assert(blocklen>=apstruct_knisheadersize, "knisCompressStorage: integrity check 6385 failed", _state); + if( setidx<0 ) + { + srcoffs = srcoffs+blocklen; + continue; + } + if( srcoffs!=dstoffs ) + { + for(i=0; i<=blocklen-1; i++) + { + sa->data.ptr.p_int[dstoffs+i] = sa->data.ptr.p_int[srcoffs+i]; + } + sa->vbegin.ptr.p_int[setidx] = dstoffs+apstruct_knisheadersize; + } + dstoffs = dstoffs+blocklen; + srcoffs = srcoffs+blocklen; + } + ae_assert(srcoffs==sa->dataused, "knisCompressStorage: integrity check 9464 failed", _state); + sa->dataused = dstoffs; +} + + +/************************************************************************* +Reallocates internal storage for set #SetIdx, increasing its capacity to +NewAllocated exactly. This function may invalidate internal pointers for +ALL sets in the kn-set structure because it may perform storage +compression in order to reclaim previously freed space. + +INPUT PARAMETERS + SA - kn-set structure + SetIdx - set to reallocate + NewAllocated - new size for the set, must be at least equal to already + allocated + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisreallocate(kniset* sa, + ae_int_t setidx, + ae_int_t newallocated, + ae_state *_state) +{ + ae_int_t oldbegin; + ae_int_t oldcnt; + ae_int_t newbegin; + ae_int_t j; + + + ae_assert(sa->storagemode==0, "knisReallocate: unexpected storage mode", _state); + if( sa->data.cntdataused+apstruct_knisheadersize+newallocated ) + { + kniscompressstorage(sa, _state); + if( sa->data.cntdataused+apstruct_knisheadersize+newallocated ) + { + ivectorgrowto(&sa->data, sa->dataused+apstruct_knisheadersize+newallocated, _state); + } + } + oldbegin = sa->vbegin.ptr.p_int[setidx]; + oldcnt = sa->vcnt.ptr.p_int[setidx]; + newbegin = sa->dataused+apstruct_knisheadersize; + sa->vbegin.ptr.p_int[setidx] = newbegin; + sa->vallocated.ptr.p_int[setidx] = newallocated; + sa->data.ptr.p_int[oldbegin-1] = -1; + sa->data.ptr.p_int[newbegin-2] = apstruct_knisheadersize+newallocated; + sa->data.ptr.p_int[newbegin-1] = setidx; + sa->dataused = sa->dataused+sa->data.ptr.p_int[newbegin-2]; + for(j=0; j<=oldcnt-1; j++) + { + sa->data.ptr.p_int[newbegin+j] = sa->data.ptr.p_int[oldbegin+j]; + } +} + + +/************************************************************************* +Initialize kn-set using default unsorted storage mode. Elements within a +subset are unsorted, with possible duplicates. + +INPUT PARAMETERS + K - sets count, K>0 + N - set size, N>=0 + kPrealloc - preallocate place per set (can be zero), >=0 + +OUTPUT PARAMETERS + SA - K sets of N elements, initially empty + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisinitunsorted(ae_int_t k, + ae_int_t n, + ae_int_t kprealloc, + kniset* sa, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(k>0, "knisInitUnsorted: K<=0", _state); + ae_assert(n>=0, "knisInitUnsorted: N<0", _state); + ae_assert(kprealloc>=0, "knisInitUnsorted: kPrealloc<0", _state); + sa->storagemode = 0; + sa->k = k; + sa->n = n; + isetallocv(n, -1, &sa->flagarray, _state); + isetallocv(k, kprealloc, &sa->vallocated, _state); + ivectorsetlengthatleast(&sa->vbegin, k, _state); + sa->vbegin.ptr.p_int[0] = apstruct_knisheadersize; + for(i=1; i<=k-1; i++) + { + sa->vbegin.ptr.p_int[i] = sa->vbegin.ptr.p_int[i-1]+sa->vallocated.ptr.p_int[i-1]+apstruct_knisheadersize; + } + sa->dataused = sa->vbegin.ptr.p_int[k-1]+sa->vallocated.ptr.p_int[k-1]; + ivectorsetlengthatleast(&sa->data, sa->dataused, _state); + for(i=0; i<=k-1; i++) + { + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-2] = apstruct_knisheadersize+sa->vallocated.ptr.p_int[i]; + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-1] = i; + } + isetallocv(k, 0, &sa->vcnt, _state); +} + + +/************************************************************************* +Allows direct access to internal storage of kn-set structure - returns +range of elements SA.Data[idxBegin...idxEnd-1] used to store K-th set + +INPUT PARAMETERS + SA - kn-set + K - set index + +OUTPUT PARAMETERS + idxBegin, + idxEnd - half-range [idxBegin,idxEnd) of SA.Data that stores + K-th set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisdirectaccess(const kniset* sa, + ae_int_t k, + ae_int_t* idxbegin, + ae_int_t* idxend, + ae_state *_state) +{ + + *idxbegin = 0; + *idxend = 0; + + ae_assert(sa->storagemode==0, "knisDirectAccess: unexpected storage mode", _state); + *idxbegin = sa->vbegin.ptr.p_int[k]; + *idxend = *idxbegin+sa->vcnt.ptr.p_int[k]; +} + + +/************************************************************************* +Pops last element from the K-th set. + +INPUT PARAMETERS + SA - kn-set; K-th set must include at least one element, + otherwise an exception is generated + K - set index + +RESULT: + last element in K-th set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_int_t knispoplast(kniset* sa, ae_int_t k, ae_state *_state) +{ + ae_int_t c; + ae_int_t result; + + + ae_assert(sa->storagemode==0, "knisPopLast: unexpected storage mode", _state); + c = sa->vcnt.ptr.p_int[k]; + ae_assert(c>0, "knisDirectAccess: K-th set is empty", _state); + result = sa->data.ptr.p_int[sa->vbegin.ptr.p_int[k]+c-1]; + sa->vcnt.ptr.p_int[k] = c-1; + return result; +} + + +/************************************************************************* +Add K-th element to I-th set. If an element already exists in the target, +a duplicate entry is added. + +INPUT PARAMETERS + SA - kn-set + I - set index + K - element to add + +OUTPUT PARAMETERS + SA - modified SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisaddnewelement(kniset* sa, + ae_int_t i, + ae_int_t k, + ae_state *_state) +{ + ae_int_t cnt; + + + ae_assert(sa->storagemode==0, "knisAddNewElement: unexpected storage mode", _state); + cnt = sa->vcnt.ptr.p_int[i]; + if( cnt==sa->vallocated.ptr.p_int[i] ) + { + knisreallocate(sa, i, 2*sa->vallocated.ptr.p_int[i]+1, _state); + } + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]+cnt] = k; + sa->vcnt.ptr.p_int[i] = cnt+1; +} + + +/************************************************************************* +Clear k-th kn-set in collection. + +Freed memory is NOT reclaimed for future garbage collection. + +INPUT PARAMETERS + SA - kn-set structure + K - set index + +OUTPUT PARAMETERS + SA - K-th set was cleared + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisclearkthnoreclaim(kniset* sa, ae_int_t k, ae_state *_state) +{ + + + ae_assert(sa->storagemode==0, "knisClearKthNoReclaim: unexpected storage mode", _state); + sa->vcnt.ptr.p_int[k] = 0; +} + + +/************************************************************************* +Clear k-th kn-set in collection. + +Freed memory is reclaimed for future garbage collection. This function is +NOT recommended if you intend to add elements to this set in some future, +because every addition will result in reallocation of previously freed +memory. Use knsClearKthNoReclaim(). + +INPUT PARAMETERS + SA - kn-set structure + K - set index + +OUTPUT PARAMETERS + SA - K-th set was cleared + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void knisclearkthreclaim(kniset* sa, ae_int_t k, ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t allocated; + + + ae_assert(sa->storagemode==0, "knisClearKthReclaim: unexpected storage mode", _state); + idxbegin = sa->vbegin.ptr.p_int[k]; + allocated = sa->vallocated.ptr.p_int[k]; + sa->vcnt.ptr.p_int[k] = 0; + if( allocated>=apstruct_knisheadersize ) + { + sa->data.ptr.p_int[idxbegin-2] = 2; + sa->data.ptr.p_int[idxbegin+0] = allocated; + sa->data.ptr.p_int[idxbegin+1] = -1; + sa->vallocated.ptr.p_int[k] = 0; + } +} + + +/************************************************************************* +Counts elements of K-th set of S0 (duplicates are counted as distinct elements). + +INPUT PARAMETERS + S0 - kn-set structure + K - set index in the structure S0 + +RESULT + K-th set element count + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_int_t kniscountkth(const kniset* s0, ae_int_t k, ae_state *_state) +{ + ae_int_t result; + + + ae_assert(s0->storagemode==0, "knisCountKth: unexpected storage mode", _state); + result = s0->vcnt.ptr.p_int[k]; + return result; +} + + +void _niset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + niset *p = (niset*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->items, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->locationof, 0, DT_INT, _state, make_automatic); +} + + +void _niset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + niset *dst = (niset*)_dst; + const niset *src = (const niset*)_src; + dst->n = src->n; + dst->nstored = src->nstored; + ae_vector_init_copy(&dst->items, &src->items, _state, make_automatic); + ae_vector_init_copy(&dst->locationof, &src->locationof, _state, make_automatic); + dst->iteridx = src->iteridx; +} + + +void _niset_clear(void* _p) +{ + niset *p = (niset*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->items); + ae_vector_clear(&p->locationof); +} + + +void _niset_destroy(void* _p) +{ + niset *p = (niset*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->items); + ae_vector_destroy(&p->locationof); +} + + +void _kniset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + kniset *p = (kniset*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->flagarray, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vallocated, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vcnt, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->data, 0, DT_INT, _state, make_automatic); +} + + +void _kniset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + kniset *dst = (kniset*)_dst; + const kniset *src = (const kniset*)_src; + dst->storagemode = src->storagemode; + dst->k = src->k; + dst->n = src->n; + ae_vector_init_copy(&dst->flagarray, &src->flagarray, _state, make_automatic); + ae_vector_init_copy(&dst->vbegin, &src->vbegin, _state, make_automatic); + ae_vector_init_copy(&dst->vallocated, &src->vallocated, _state, make_automatic); + ae_vector_init_copy(&dst->vcnt, &src->vcnt, _state, make_automatic); + ae_vector_init_copy(&dst->data, &src->data, _state, make_automatic); + dst->dataused = src->dataused; + dst->iterrow = src->iterrow; + dst->iteridx = src->iteridx; +} + + +void _kniset_clear(void* _p) +{ + kniset *p = (kniset*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->flagarray); + ae_vector_clear(&p->vbegin); + ae_vector_clear(&p->vallocated); + ae_vector_clear(&p->vcnt); + ae_vector_clear(&p->data); +} + + +void _kniset_destroy(void* _p) +{ + kniset *p = (kniset*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->flagarray); + ae_vector_destroy(&p->vbegin); + ae_vector_destroy(&p->vallocated); + ae_vector_destroy(&p->vcnt); + ae_vector_destroy(&p->data); +} + + +#endif +#if defined(AE_COMPILE_TRLINSOLVE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Utility subroutine performing the "safe" solution of system of linear +equations with triangular coefficient matrices. + +The subroutine uses scaling and solves the scaled system A*x=s*b (where s +is a scalar value) instead of A*x=b, choosing s so that x can be +represented by a floating-point number. The closer the system gets to a +singular, the less s is. If the system is singular, s=0 and x contains the +non-trivial solution of equation A*x=0. + +The feature of an algorithm is that it could not cause an overflow or a +division by zero regardless of the matrix used as the input. + +The algorithm can solve systems of equations with upper/lower triangular +matrices, with/without unit diagonal, and systems of type A*x=b or A'*x=b +(where A' is a transposed matrix A). + +Input parameters: + A - system matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + X - right-hand member of a system. + Array whose index ranges within [0..N-1]. + IsUpper - matrix type. If it is True, the system matrix is the upper + triangular and is located in the corresponding part of + matrix A. + Trans - problem type. If it is True, the problem to be solved is + A'*x=b, otherwise it is A*x=b. + Isunit - matrix type. If it is True, the system matrix has a unit + diagonal (the elements on the main diagonal are not used + in the calculation process), otherwise the matrix is considered + to be a general triangular matrix. + +Output parameters: + X - solution. Array whose index ranges within [0..N-1]. + S - scaling factor. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1992 +*************************************************************************/ +void rmatrixtrsafesolve(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + double* s, + ae_bool isupper, + ae_bool istrans, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_bool normin; + ae_vector cnorm; + ae_matrix a1; + ae_vector x1; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&cnorm, 0, sizeof(cnorm)); + memset(&a1, 0, sizeof(a1)); + memset(&x1, 0, sizeof(x1)); + *s = 0.0; + ae_vector_init(&cnorm, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a1, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x1, 0, DT_REAL, _state, ae_true); + + + /* + * From 0-based to 1-based + */ + normin = ae_false; + ae_matrix_set_length(&a1, n+1, n+1, _state); + ae_vector_set_length(&x1, n+1, _state); + for(i=1; i<=n; i++) + { + ae_v_move(&a1.ptr.pp_double[i][1], 1, &a->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); + } + ae_v_move(&x1.ptr.p_double[1], 1, &x->ptr.p_double[0], 1, ae_v_len(1,n)); + + /* + * Solve 1-based + */ + safesolvetriangular(&a1, n, &x1, s, isupper, istrans, isunit, normin, &cnorm, _state); + + /* + * From 1-based to 0-based + */ + ae_v_move(&x->ptr.p_double[0], 1, &x1.ptr.p_double[1], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Obsolete 1-based subroutine. +See RMatrixTRSafeSolve for 0-based replacement. +*************************************************************************/ +void safesolvetriangular(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + double* s, + ae_bool isupper, + ae_bool istrans, + ae_bool isunit, + ae_bool normin, + /* Real */ ae_vector* cnorm, + ae_state *_state) +{ + ae_int_t i; + ae_int_t imax; + ae_int_t j; + ae_int_t jfirst; + ae_int_t jinc; + ae_int_t jlast; + ae_int_t jm1; + ae_int_t jp1; + ae_int_t ip1; + ae_int_t im1; + ae_int_t k; + ae_int_t flg; + double v; + double vd; + double bignum; + double grow; + double rec; + double smlnum; + double sumj; + double tjj; + double tjjs; + double tmax; + double tscal; + double uscal; + double xbnd; + double xj; + double xmax; + ae_bool notran; + ae_bool upper; + ae_bool nounit; + + *s = 0.0; + + upper = isupper; + notran = !istrans; + nounit = !isunit; + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + tjjs = (double)(0); + + /* + * Quick return if possible + */ + if( n==0 ) + { + return; + } + + /* + * Determine machine dependent parameters to control overflow. + */ + smlnum = ae_minrealnumber/(ae_machineepsilon*(double)2); + bignum = (double)1/smlnum; + *s = (double)(1); + if( !normin ) + { + ae_vector_set_length(cnorm, n+1, _state); + + /* + * Compute the 1-norm of each column, not including the diagonal. + */ + if( upper ) + { + + /* + * A is upper triangular. + */ + for(j=1; j<=n; j++) + { + v = (double)(0); + for(k=1; k<=j-1; k++) + { + v = v+ae_fabs(a->ptr.pp_double[k][j], _state); + } + cnorm->ptr.p_double[j] = v; + } + } + else + { + + /* + * A is lower triangular. + */ + for(j=1; j<=n-1; j++) + { + v = (double)(0); + for(k=j+1; k<=n; k++) + { + v = v+ae_fabs(a->ptr.pp_double[k][j], _state); + } + cnorm->ptr.p_double[j] = v; + } + cnorm->ptr.p_double[n] = (double)(0); + } + } + + /* + * Scale the column norms by TSCAL if the maximum element in CNORM is + * greater than BIGNUM. + */ + imax = 1; + for(k=2; k<=n; k++) + { + if( ae_fp_greater(cnorm->ptr.p_double[k],cnorm->ptr.p_double[imax]) ) + { + imax = k; + } + } + tmax = cnorm->ptr.p_double[imax]; + if( ae_fp_less_eq(tmax,bignum) ) + { + tscal = (double)(1); + } + else + { + tscal = (double)1/(smlnum*tmax); + ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), tscal); + } + + /* + * Compute a bound on the computed solution vector to see if the + * Level 2 BLAS routine DTRSV can be used. + */ + j = 1; + for(k=2; k<=n; k++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[j], _state)) ) + { + j = k; + } + } + xmax = ae_fabs(x->ptr.p_double[j], _state); + xbnd = xmax; + if( notran ) + { + + /* + * Compute the growth in A * x = b. + */ + if( upper ) + { + jfirst = n; + jlast = 1; + jinc = -1; + } + else + { + jfirst = 1; + jlast = n; + jinc = 1; + } + if( ae_fp_neq(tscal,(double)(1)) ) + { + grow = (double)(0); + } + else + { + if( nounit ) + { + + /* + * A is non-unit triangular. + * + * Compute GROW = 1/G(j) and XBND = 1/M(j). + * Initially, G(0) = max{x(i), i=1,...,n}. + */ + grow = (double)1/ae_maxreal(xbnd, smlnum, _state); + xbnd = grow; + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Exit the loop if the growth factor is too small. + */ + if( ae_fp_less_eq(grow,smlnum) ) + { + break; + } + + /* + * M(j) = G(j-1) / abs(A(j,j)) + */ + tjj = ae_fabs(a->ptr.pp_double[j][j], _state); + xbnd = ae_minreal(xbnd, ae_minreal((double)(1), tjj, _state)*grow, _state); + if( ae_fp_greater_eq(tjj+cnorm->ptr.p_double[j],smlnum) ) + { + + /* + * G(j) = G(j-1)*( 1 + CNORM(j) / abs(A(j,j)) ) + */ + grow = grow*(tjj/(tjj+cnorm->ptr.p_double[j])); + } + else + { + + /* + * G(j) could overflow, set GROW to 0. + */ + grow = (double)(0); + } + if( j==jlast ) + { + grow = xbnd; + } + j = j+jinc; + } + } + else + { + + /* + * A is unit triangular. + * + * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + */ + grow = ae_minreal((double)(1), (double)1/ae_maxreal(xbnd, smlnum, _state), _state); + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Exit the loop if the growth factor is too small. + */ + if( ae_fp_less_eq(grow,smlnum) ) + { + break; + } + + /* + * G(j) = G(j-1)*( 1 + CNORM(j) ) + */ + grow = grow*((double)1/((double)1+cnorm->ptr.p_double[j])); + j = j+jinc; + } + } + } + } + else + { + + /* + * Compute the growth in A' * x = b. + */ + if( upper ) + { + jfirst = 1; + jlast = n; + jinc = 1; + } + else + { + jfirst = n; + jlast = 1; + jinc = -1; + } + if( ae_fp_neq(tscal,(double)(1)) ) + { + grow = (double)(0); + } + else + { + if( nounit ) + { + + /* + * A is non-unit triangular. + * + * Compute GROW = 1/G(j) and XBND = 1/M(j). + * Initially, M(0) = max{x(i), i=1,...,n}. + */ + grow = (double)1/ae_maxreal(xbnd, smlnum, _state); + xbnd = grow; + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Exit the loop if the growth factor is too small. + */ + if( ae_fp_less_eq(grow,smlnum) ) + { + break; + } + + /* + * G(j) = max( G(j-1), M(j-1)*( 1 + CNORM(j) ) ) + */ + xj = (double)1+cnorm->ptr.p_double[j]; + grow = ae_minreal(grow, xbnd/xj, _state); + + /* + * M(j) = M(j-1)*( 1 + CNORM(j) ) / abs(A(j,j)) + */ + tjj = ae_fabs(a->ptr.pp_double[j][j], _state); + if( ae_fp_greater(xj,tjj) ) + { + xbnd = xbnd*(tjj/xj); + } + if( j==jlast ) + { + grow = ae_minreal(grow, xbnd, _state); + } + j = j+jinc; + } + } + else + { + + /* + * A is unit triangular. + * + * Compute GROW = 1/G(j), where G(0) = max{x(i), i=1,...,n}. + */ + grow = ae_minreal((double)(1), (double)1/ae_maxreal(xbnd, smlnum, _state), _state); + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Exit the loop if the growth factor is too small. + */ + if( ae_fp_less_eq(grow,smlnum) ) + { + break; + } + + /* + * G(j) = ( 1 + CNORM(j) )*G(j-1) + */ + xj = (double)1+cnorm->ptr.p_double[j]; + grow = grow/xj; + j = j+jinc; + } + } + } + } + if( ae_fp_greater(grow*tscal,smlnum) ) + { + + /* + * Use the Level 2 BLAS solve if the reciprocal of the bound on + * elements of X is not too small. + */ + if( (upper&¬ran)||(!upper&&!notran) ) + { + if( nounit ) + { + vd = a->ptr.pp_double[n][n]; + } + else + { + vd = (double)(1); + } + x->ptr.p_double[n] = x->ptr.p_double[n]/vd; + for(i=n-1; i>=1; i--) + { + ip1 = i+1; + if( upper ) + { + v = ae_v_dotproduct(&a->ptr.pp_double[i][ip1], 1, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); + } + else + { + v = ae_v_dotproduct(&a->ptr.pp_double[ip1][i], a->stride, &x->ptr.p_double[ip1], 1, ae_v_len(ip1,n)); + } + if( nounit ) + { + vd = a->ptr.pp_double[i][i]; + } + else + { + vd = (double)(1); + } + x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; + } + } + else + { + if( nounit ) + { + vd = a->ptr.pp_double[1][1]; + } + else + { + vd = (double)(1); + } + x->ptr.p_double[1] = x->ptr.p_double[1]/vd; + for(i=2; i<=n; i++) + { + im1 = i-1; + if( upper ) + { + v = ae_v_dotproduct(&a->ptr.pp_double[1][i], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); + } + else + { + v = ae_v_dotproduct(&a->ptr.pp_double[i][1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,im1)); + } + if( nounit ) + { + vd = a->ptr.pp_double[i][i]; + } + else + { + vd = (double)(1); + } + x->ptr.p_double[i] = (x->ptr.p_double[i]-v)/vd; + } + } + } + else + { + + /* + * Use a Level 1 BLAS solve, scaling intermediate results. + */ + if( ae_fp_greater(xmax,bignum) ) + { + + /* + * Scale X so that its components are less than or equal to + * BIGNUM in absolute value. + */ + *s = bignum/xmax; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), *s); + xmax = bignum; + } + if( notran ) + { + + /* + * Solve A * x = b + */ + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Compute x(j) = b(j) / A(j,j), scaling x if necessary. + */ + xj = ae_fabs(x->ptr.p_double[j], _state); + flg = 0; + if( nounit ) + { + tjjs = a->ptr.pp_double[j][j]*tscal; + } + else + { + tjjs = tscal; + if( ae_fp_eq(tscal,(double)(1)) ) + { + flg = 100; + } + } + if( flg!=100 ) + { + tjj = ae_fabs(tjjs, _state); + if( ae_fp_greater(tjj,smlnum) ) + { + + /* + * abs(A(j,j)) > SMLNUM: + */ + if( ae_fp_less(tjj,(double)(1)) ) + { + if( ae_fp_greater(xj,tjj*bignum) ) + { + + /* + * Scale x by 1/b(j). + */ + rec = (double)1/xj; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + xmax = xmax*rec; + } + } + x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; + xj = ae_fabs(x->ptr.p_double[j], _state); + } + else + { + if( ae_fp_greater(tjj,(double)(0)) ) + { + + /* + * 0 < abs(A(j,j)) <= SMLNUM: + */ + if( ae_fp_greater(xj,tjj*bignum) ) + { + + /* + * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM + * to avoid overflow when dividing by A(j,j). + */ + rec = tjj*bignum/xj; + if( ae_fp_greater(cnorm->ptr.p_double[j],(double)(1)) ) + { + + /* + * Scale by 1/CNORM(j) to avoid overflow when + * multiplying x(j) times column j. + */ + rec = rec/cnorm->ptr.p_double[j]; + } + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + xmax = xmax*rec; + } + x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; + xj = ae_fabs(x->ptr.p_double[j], _state); + } + else + { + + /* + * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + * scale = 0, and compute a solution to A*x = 0. + */ + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = (double)(0); + } + x->ptr.p_double[j] = (double)(1); + xj = (double)(1); + *s = (double)(0); + xmax = (double)(0); + } + } + } + + /* + * Scale x if necessary to avoid overflow when adding a + * multiple of column j of A. + */ + if( ae_fp_greater(xj,(double)(1)) ) + { + rec = (double)1/xj; + if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xmax)*rec) ) + { + + /* + * Scale x by 1/(2*abs(x(j))). + */ + rec = rec*0.5; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + } + } + else + { + if( ae_fp_greater(xj*cnorm->ptr.p_double[j],bignum-xmax) ) + { + + /* + * Scale x by 1/2. + */ + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), 0.5); + *s = *s*0.5; + } + } + if( upper ) + { + if( j>1 ) + { + + /* + * Compute the update + * x(1:j-1) := x(1:j-1) - x(j) * A(1:j-1,j) + */ + v = x->ptr.p_double[j]*tscal; + jm1 = j-1; + ae_v_subd(&x->ptr.p_double[1], 1, &a->ptr.pp_double[1][j], a->stride, ae_v_len(1,jm1), v); + i = 1; + for(k=2; k<=j-1; k++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) + { + i = k; + } + } + xmax = ae_fabs(x->ptr.p_double[i], _state); + } + } + else + { + if( jptr.p_double[j]*tscal; + ae_v_subd(&x->ptr.p_double[jp1], 1, &a->ptr.pp_double[jp1][j], a->stride, ae_v_len(jp1,n), v); + i = j+1; + for(k=j+2; k<=n; k++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[k], _state),ae_fabs(x->ptr.p_double[i], _state)) ) + { + i = k; + } + } + xmax = ae_fabs(x->ptr.p_double[i], _state); + } + } + j = j+jinc; + } + } + else + { + + /* + * Solve A' * x = b + */ + j = jfirst; + while((jinc>0&&j<=jlast)||(jinc<0&&j>=jlast)) + { + + /* + * Compute x(j) = b(j) - sum A(k,j)*x(k). + * k<>j + */ + xj = ae_fabs(x->ptr.p_double[j], _state); + uscal = tscal; + rec = (double)1/ae_maxreal(xmax, (double)(1), _state); + if( ae_fp_greater(cnorm->ptr.p_double[j],(bignum-xj)*rec) ) + { + + /* + * If x(j) could overflow, scale x by 1/(2*XMAX). + */ + rec = rec*0.5; + if( nounit ) + { + tjjs = a->ptr.pp_double[j][j]*tscal; + } + else + { + tjjs = tscal; + } + tjj = ae_fabs(tjjs, _state); + if( ae_fp_greater(tjj,(double)(1)) ) + { + + /* + * Divide by A(j,j) when scaling x if A(j,j) > 1. + */ + rec = ae_minreal((double)(1), rec*tjj, _state); + uscal = uscal/tjjs; + } + if( ae_fp_less(rec,(double)(1)) ) + { + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + xmax = xmax*rec; + } + } + sumj = (double)(0); + if( ae_fp_eq(uscal,(double)(1)) ) + { + + /* + * If the scaling needed for A in the dot product is 1, + * call DDOT to perform the dot product. + */ + if( upper ) + { + if( j>1 ) + { + jm1 = j-1; + sumj = ae_v_dotproduct(&a->ptr.pp_double[1][j], a->stride, &x->ptr.p_double[1], 1, ae_v_len(1,jm1)); + } + else + { + sumj = (double)(0); + } + } + else + { + if( jptr.pp_double[jp1][j], a->stride, &x->ptr.p_double[jp1], 1, ae_v_len(jp1,n)); + } + } + } + else + { + + /* + * Otherwise, use in-line code for the dot product. + */ + if( upper ) + { + for(i=1; i<=j-1; i++) + { + v = a->ptr.pp_double[i][j]*uscal; + sumj = sumj+v*x->ptr.p_double[i]; + } + } + else + { + if( jptr.pp_double[i][j]*uscal; + sumj = sumj+v*x->ptr.p_double[i]; + } + } + } + } + if( ae_fp_eq(uscal,tscal) ) + { + + /* + * Compute x(j) := ( x(j) - sumj ) / A(j,j) if 1/A(j,j) + * was not used to scale the dotproduct. + */ + x->ptr.p_double[j] = x->ptr.p_double[j]-sumj; + xj = ae_fabs(x->ptr.p_double[j], _state); + flg = 0; + if( nounit ) + { + tjjs = a->ptr.pp_double[j][j]*tscal; + } + else + { + tjjs = tscal; + if( ae_fp_eq(tscal,(double)(1)) ) + { + flg = 150; + } + } + + /* + * Compute x(j) = x(j) / A(j,j), scaling if necessary. + */ + if( flg!=150 ) + { + tjj = ae_fabs(tjjs, _state); + if( ae_fp_greater(tjj,smlnum) ) + { + + /* + * abs(A(j,j)) > SMLNUM: + */ + if( ae_fp_less(tjj,(double)(1)) ) + { + if( ae_fp_greater(xj,tjj*bignum) ) + { + + /* + * Scale X by 1/abs(x(j)). + */ + rec = (double)1/xj; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + xmax = xmax*rec; + } + } + x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; + } + else + { + if( ae_fp_greater(tjj,(double)(0)) ) + { + + /* + * 0 < abs(A(j,j)) <= SMLNUM: + */ + if( ae_fp_greater(xj,tjj*bignum) ) + { + + /* + * Scale x by (1/abs(x(j)))*abs(A(j,j))*BIGNUM. + */ + rec = tjj*bignum/xj; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), rec); + *s = *s*rec; + xmax = xmax*rec; + } + x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs; + } + else + { + + /* + * A(j,j) = 0: Set x(1:n) = 0, x(j) = 1, and + * scale = 0, and compute a solution to A'*x = 0. + */ + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = (double)(0); + } + x->ptr.p_double[j] = (double)(1); + *s = (double)(0); + xmax = (double)(0); + } + } + } + } + else + { + + /* + * Compute x(j) := x(j) / A(j,j) - sumj if the dot + * product has already been divided by 1/A(j,j). + */ + x->ptr.p_double[j] = x->ptr.p_double[j]/tjjs-sumj; + } + xmax = ae_maxreal(xmax, ae_fabs(x->ptr.p_double[j], _state), _state); + j = j+jinc; + } + } + *s = *s/tscal; + } + + /* + * Scale the column norms by 1/TSCAL for return. + */ + if( ae_fp_neq(tscal,(double)(1)) ) + { + v = (double)1/tscal; + ae_v_muld(&cnorm->ptr.p_double[1], 1, ae_v_len(1,n), v); + } +} + + +#endif +#if defined(AE_COMPILE_SAFESOLVE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Real implementation of CMatrixScaledTRSafeSolve + + -- ALGLIB routine -- + 21.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixscaledtrsafesolve(/* Real */ const ae_matrix* a, + double sa, + ae_int_t n, + /* Real */ ae_vector* x, + ae_bool isupper, + ae_int_t trans, + ae_bool isunit, + double maxgrowth, + ae_state *_state) +{ + ae_frame _frame_block; + double lnmax; + double nrmb; + double nrmx; + ae_int_t i; + ae_complex alpha; + ae_complex beta; + double vr; + ae_complex cx; + ae_vector tmp; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixTRSafeSolve: incorrect N!", _state); + ae_assert(trans==0||trans==1, "RMatrixTRSafeSolve: incorrect Trans!", _state); + result = ae_true; + lnmax = ae_log(ae_maxrealnumber, _state); + + /* + * Quick return if possible + */ + if( n<=0 ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Load norms: right part and X + */ + nrmb = (double)(0); + for(i=0; i<=n-1; i++) + { + nrmb = ae_maxreal(nrmb, ae_fabs(x->ptr.p_double[i], _state), _state); + } + nrmx = (double)(0); + + /* + * Solve + */ + ae_vector_set_length(&tmp, n, _state); + result = ae_true; + if( isupper&&trans==0 ) + { + + /* + * U*x = b + */ + for(i=n-1; i>=0; i--) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); + } + if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); + vr = ae_v_dotproduct(&tmp.ptr.p_double[i+1], 1, &x->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + beta = ae_complex_from_d(x->ptr.p_double[i]-vr); + } + else + { + beta = ae_complex_from_d(x->ptr.p_double[i]); + } + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_double[i] = cx.x; + } + ae_frame_leave(_state); + return result; + } + if( !isupper&&trans==0 ) + { + + /* + * L*x = b + */ + for(i=0; i<=n-1; i++) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); + } + if( i>0 ) + { + ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); + vr = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,i-1)); + beta = ae_complex_from_d(x->ptr.p_double[i]-vr); + } + else + { + beta = ae_complex_from_d(x->ptr.p_double[i]); + } + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_double[i] = cx.x; + } + ae_frame_leave(_state); + return result; + } + if( isupper&&trans==1 ) + { + + /* + * U^T*x = b + */ + for(i=0; i<=n-1; i++) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); + } + beta = ae_complex_from_d(x->ptr.p_double[i]); + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_double[i] = cx.x; + + /* + * update the rest of right part + */ + if( iptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sa); + ae_v_subd(&x->ptr.p_double[i+1], 1, &tmp.ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), vr); + } + } + ae_frame_leave(_state); + return result; + } + if( !isupper&&trans==1 ) + { + + /* + * L^T*x = b + */ + for(i=n-1; i>=0; i--) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_complex_from_d(a->ptr.pp_double[i][i]*sa); + } + beta = ae_complex_from_d(x->ptr.p_double[i]); + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &cx, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_double[i] = cx.x; + + /* + * update the rest of right part + */ + if( i>0 ) + { + vr = cx.x; + ae_v_moved(&tmp.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sa); + ae_v_subd(&x->ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1), vr); + } + } + ae_frame_leave(_state); + return result; + } + result = ae_false; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Internal subroutine for safe solution of + + SA*op(A)=b + +where A is NxN upper/lower triangular/unitriangular matrix, op(A) is +either identity transform, transposition or Hermitian transposition, SA is +a scaling factor such that max(|SA*A[i,j]|) is close to 1.0 in magnutude. + +This subroutine limits relative growth of solution (in inf-norm) by +MaxGrowth, returning False if growth exceeds MaxGrowth. Degenerate or +near-degenerate matrices are handled correctly (False is returned) as long +as MaxGrowth is significantly less than MaxRealNumber/norm(b). + + -- ALGLIB routine -- + 21.01.2010 + Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixscaledtrsafesolve(/* Complex */ const ae_matrix* a, + double sa, + ae_int_t n, + /* Complex */ ae_vector* x, + ae_bool isupper, + ae_int_t trans, + ae_bool isunit, + double maxgrowth, + ae_state *_state) +{ + ae_frame _frame_block; + double lnmax; + double nrmb; + double nrmx; + ae_int_t i; + ae_complex alpha; + ae_complex beta; + ae_complex vc; + ae_vector tmp; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixTRSafeSolve: incorrect N!", _state); + ae_assert((trans==0||trans==1)||trans==2, "CMatrixTRSafeSolve: incorrect Trans!", _state); + result = ae_true; + lnmax = ae_log(ae_maxrealnumber, _state); + + /* + * Quick return if possible + */ + if( n<=0 ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Load norms: right part and X + */ + nrmb = (double)(0); + for(i=0; i<=n-1; i++) + { + nrmb = ae_maxreal(nrmb, ae_c_abs(x->ptr.p_complex[i], _state), _state); + } + nrmx = (double)(0); + + /* + * Solve + */ + ae_vector_set_length(&tmp, n, _state); + result = ae_true; + if( isupper&&trans==0 ) + { + + /* + * U*x = b + */ + for(i=n-1; i>=0; i--) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); + } + if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); + vc = ae_v_cdotproduct(&tmp.ptr.p_complex[i+1], 1, "N", &x->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); + beta = ae_c_sub(x->ptr.p_complex[i],vc); + } + else + { + beta = x->ptr.p_complex[i]; + } + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + } + ae_frame_leave(_state); + return result; + } + if( !isupper&&trans==0 ) + { + + /* + * L*x = b + */ + for(i=0; i<=n-1; i++) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); + } + if( i>0 ) + { + ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); + vc = ae_v_cdotproduct(&tmp.ptr.p_complex[0], 1, "N", &x->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); + beta = ae_c_sub(x->ptr.p_complex[i],vc); + } + else + { + beta = x->ptr.p_complex[i]; + } + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + } + ae_frame_leave(_state); + return result; + } + if( isupper&&trans==1 ) + { + + /* + * U^T*x = b + */ + for(i=0; i<=n-1; i++) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); + } + beta = x->ptr.p_complex[i]; + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + + /* + * update the rest of right part + */ + if( iptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sa); + ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); + } + } + ae_frame_leave(_state); + return result; + } + if( !isupper&&trans==1 ) + { + + /* + * L^T*x = b + */ + for(i=n-1; i>=0; i--) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(a->ptr.pp_complex[i][i],sa); + } + beta = x->ptr.p_complex[i]; + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + + /* + * update the rest of right part + */ + if( i>0 ) + { + ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sa); + ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); + } + } + ae_frame_leave(_state); + return result; + } + if( isupper&&trans==2 ) + { + + /* + * U^H*x = b + */ + for(i=0; i<=n-1; i++) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); + } + beta = x->ptr.p_complex[i]; + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + + /* + * update the rest of right part + */ + if( iptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), sa); + ae_v_csubc(&x->ptr.p_complex[i+1], 1, &tmp.ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), vc); + } + } + ae_frame_leave(_state); + return result; + } + if( !isupper&&trans==2 ) + { + + /* + * L^T*x = b + */ + for(i=n-1; i>=0; i--) + { + + /* + * Task is reduced to alpha*x[i] = beta + */ + if( isunit ) + { + alpha = ae_complex_from_d(sa); + } + else + { + alpha = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[i][i], _state),sa); + } + beta = x->ptr.p_complex[i]; + + /* + * solve alpha*x[i] = beta + */ + result = safesolve_cbasicsolveandupdate(alpha, beta, lnmax, nrmb, maxgrowth, &nrmx, &vc, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + x->ptr.p_complex[i] = vc; + + /* + * update the rest of right part + */ + if( i>0 ) + { + ae_v_cmoved(&tmp.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), sa); + ae_v_csubc(&x->ptr.p_complex[0], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), vc); + } + } + ae_frame_leave(_state); + return result; + } + result = ae_false; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +complex basic solver-updater for reduced linear system + + alpha*x[i] = beta + +solves this equation and updates it in overlfow-safe manner (keeping track +of relative growth of solution). + +Parameters: + Alpha - alpha + Beta - beta + LnMax - precomputed Ln(MaxRealNumber) + BNorm - inf-norm of b (right part of original system) + MaxGrowth- maximum growth of norm(x) relative to norm(b) + XNorm - inf-norm of other components of X (which are already processed) + it is updated by CBasicSolveAndUpdate. + X - solution + + -- ALGLIB routine -- + 26.01.2009 + Bochkanov Sergey +*************************************************************************/ +static ae_bool safesolve_cbasicsolveandupdate(ae_complex alpha, + ae_complex beta, + double lnmax, + double bnorm, + double maxgrowth, + double* xnorm, + ae_complex* x, + ae_state *_state) +{ + double v; + ae_bool result; + + x->x = 0.0; + x->y = 0.0; + + result = ae_false; + if( ae_c_eq_d(alpha,(double)(0)) ) + { + return result; + } + if( ae_c_neq_d(beta,(double)(0)) ) + { + + /* + * alpha*x[i]=beta + */ + v = ae_log(ae_c_abs(beta, _state), _state)-ae_log(ae_c_abs(alpha, _state), _state); + if( ae_fp_greater(v,lnmax) ) + { + return result; + } + *x = ae_c_div(beta,alpha); + } + else + { + + /* + * alpha*x[i]=0 + */ + *x = ae_complex_from_i(0); + } + + /* + * update NrmX, test growth limit + */ + *xnorm = ae_maxreal(*xnorm, ae_c_abs(*x, _state), _state); + if( ae_fp_greater(*xnorm,maxgrowth*bnorm) ) + { + return result; + } + result = ae_true; + return result; +} + + +#endif +#if defined(AE_COMPILE_XBLAS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +More precise dot-product. Absolute error of subroutine result is about +1 ulp of max(MX,V), where: + MX = max( |a[i]*b[i]| ) + V = |(a,b)| + +INPUT PARAMETERS + A - array[0..N-1], vector 1 + B - array[0..N-1], vector 2 + N - vectors length, N<2^29. + Temp - array[0..N-1], pre-allocated temporary storage + +OUTPUT PARAMETERS + R - (A,B) + RErr - estimate of error. This estimate accounts for both errors + during calculation of (A,B) and errors introduced by + rounding of A and B to fit in double (about 1 ulp). + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void xdot(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* temp, + double* r, + double* rerr, + ae_state *_state) +{ + ae_int_t i; + double mx; + double v; + + *r = 0.0; + *rerr = 0.0; + + + /* + * special cases: + * * N=0 + */ + if( n==0 ) + { + *r = (double)(0); + *rerr = (double)(0); + return; + } + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + v = a->ptr.p_double[i]*b->ptr.p_double[i]; + temp->ptr.p_double[i] = v; + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + } + if( ae_fp_eq(mx,(double)(0)) ) + { + *r = (double)(0); + *rerr = (double)(0); + return; + } + xblas_xsum(temp, mx, n, r, rerr, _state); +} + + +/************************************************************************* +More precise complex dot-product. Absolute error of subroutine result is +about 1 ulp of max(MX,V), where: + MX = max( |a[i]*b[i]| ) + V = |(a,b)| + +INPUT PARAMETERS + A - array[0..N-1], vector 1 + B - array[0..N-1], vector 2 + N - vectors length, N<2^29. + Temp - array[0..2*N-1], pre-allocated temporary storage + +OUTPUT PARAMETERS + R - (A,B) + RErr - estimate of error. This estimate accounts for both errors + during calculation of (A,B) and errors introduced by + rounding of A and B to fit in double (about 1 ulp). + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void xcdot(/* Complex */ const ae_vector* a, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* temp, + ae_complex* r, + double* rerr, + ae_state *_state) +{ + ae_int_t i; + double mx; + double v; + double rerrx; + double rerry; + + r->x = 0.0; + r->y = 0.0; + *rerr = 0.0; + + + /* + * special cases: + * * N=0 + */ + if( n==0 ) + { + *r = ae_complex_from_i(0); + *rerr = (double)(0); + return; + } + + /* + * calculate real part + */ + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].x; + temp->ptr.p_double[2*i+0] = v; + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + v = -a->ptr.p_complex[i].y*b->ptr.p_complex[i].y; + temp->ptr.p_double[2*i+1] = v; + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + } + if( ae_fp_eq(mx,(double)(0)) ) + { + r->x = (double)(0); + rerrx = (double)(0); + } + else + { + xblas_xsum(temp, mx, 2*n, &r->x, &rerrx, _state); + } + + /* + * calculate imaginary part + */ + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + v = a->ptr.p_complex[i].x*b->ptr.p_complex[i].y; + temp->ptr.p_double[2*i+0] = v; + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + v = a->ptr.p_complex[i].y*b->ptr.p_complex[i].x; + temp->ptr.p_double[2*i+1] = v; + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + } + if( ae_fp_eq(mx,(double)(0)) ) + { + r->y = (double)(0); + rerry = (double)(0); + } + else + { + xblas_xsum(temp, mx, 2*n, &r->y, &rerry, _state); + } + + /* + * total error + */ + if( ae_fp_eq(rerrx,(double)(0))&&ae_fp_eq(rerry,(double)(0)) ) + { + *rerr = (double)(0); + } + else + { + *rerr = ae_maxreal(rerrx, rerry, _state)*ae_sqrt((double)1+ae_sqr(ae_minreal(rerrx, rerry, _state)/ae_maxreal(rerrx, rerry, _state), _state), _state); + } +} + + +/************************************************************************* +Internal subroutine for extra-precise calculation of SUM(w[i]). + +INPUT PARAMETERS: + W - array[0..N-1], values to be added + W is modified during calculations. + MX - max(W[i]) + N - array size + +OUTPUT PARAMETERS: + R - SUM(w[i]) + RErr- error estimate for R + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +static void xblas_xsum(/* Real */ ae_vector* w, + double mx, + ae_int_t n, + double* r, + double* rerr, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t ks; + double v; + double s; + double ln2; + double chunk; + double invchunk; + ae_bool allzeros; + + *r = 0.0; + *rerr = 0.0; + + + /* + * special cases: + * * N=0 + * * N is too large to use integer arithmetics + */ + if( n==0 ) + { + *r = (double)(0); + *rerr = (double)(0); + return; + } + if( ae_fp_eq(mx,(double)(0)) ) + { + *r = (double)(0); + *rerr = (double)(0); + return; + } + ae_assert(n<536870912, "XDot: N is too large!", _state); + + /* + * Prepare + */ + ln2 = ae_log((double)(2), _state); + *rerr = mx*ae_machineepsilon; + + /* + * 1. find S such that 0.5<=S*MX<1 + * 2. multiply W by S, so task is normalized in some sense + * 3. S:=1/S so we can obtain original vector multiplying by S + */ + k = ae_round(ae_log(mx, _state)/ln2, _state); + s = xblas_xfastpow((double)(2), -k, _state); + if( !ae_isfinite(s, _state) ) + { + + /* + * Overflow or underflow during evaluation of S; fallback low-precision code + */ + *r = (double)(0); + *rerr = mx*ae_machineepsilon; + for(i=0; i<=n-1; i++) + { + *r = *r+w->ptr.p_double[i]; + } + return; + } + while(ae_fp_greater_eq(s*mx,(double)(1))) + { + s = 0.5*s; + } + while(ae_fp_less(s*mx,0.5)) + { + s = (double)2*s; + } + ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), s); + s = (double)1/s; + + /* + * find Chunk=2^M such that N*Chunk<2^29 + * + * we have chosen upper limit (2^29) with enough space left + * to tolerate possible problems with rounding and N's close + * to the limit, so we don't want to be very strict here. + */ + k = ae_trunc(ae_log((double)536870912/(double)n, _state)/ln2, _state); + chunk = xblas_xfastpow((double)(2), k, _state); + if( ae_fp_less(chunk,(double)(2)) ) + { + chunk = (double)(2); + } + invchunk = (double)1/chunk; + + /* + * calculate result + */ + *r = (double)(0); + ae_v_muld(&w->ptr.p_double[0], 1, ae_v_len(0,n-1), chunk); + for(;;) + { + s = s*invchunk; + allzeros = ae_true; + ks = 0; + for(i=0; i<=n-1; i++) + { + v = w->ptr.p_double[i]; + k = ae_trunc(v, _state); + if( ae_fp_neq(v,(double)(k)) ) + { + allzeros = ae_false; + } + w->ptr.p_double[i] = chunk*(v-(double)k); + ks = ks+k; + } + *r = *r+s*(double)ks; + if( allzeros||ae_fp_eq(s*(double)n+mx,mx) ) + { + break; + } + } + + /* + * correct error + */ + *rerr = ae_maxreal(*rerr, ae_fabs(*r, _state)*ae_machineepsilon, _state); +} + + +/************************************************************************* +Fast Pow + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +static double xblas_xfastpow(double r, ae_int_t n, ae_state *_state) +{ + double result; + + + result = (double)(0); + if( n>0 ) + { + if( n%2==0 ) + { + result = ae_sqr(xblas_xfastpow(r, n/2, _state), _state); + } + else + { + result = r*xblas_xfastpow(r, n-1, _state); + } + return result; + } + if( n==0 ) + { + result = (double)(1); + } + if( n<0 ) + { + result = xblas_xfastpow((double)1/r, -n, _state); + } + return result; +} + + +#endif +#if defined(AE_COMPILE_LINMIN) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Normalizes direction/step pair: makes |D|=1, scales Stp. +If |D|=0, it returns, leavind D/Stp unchanged. + + -- ALGLIB -- + Copyright 01.04.2010 by Bochkanov Sergey +*************************************************************************/ +void linminnormalized(/* Real */ ae_vector* d, + double* stp, + ae_int_t n, + ae_state *_state) +{ + double mx; + double s; + ae_int_t i; + + + + /* + * first, scale D to avoid underflow/overflow durng squaring + */ + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(d->ptr.p_double[i], _state), _state); + } + if( ae_fp_eq(mx,(double)(0)) ) + { + return; + } + s = (double)1/mx; + ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); + *stp = *stp/s; + + /* + * normalize D + */ + s = ae_v_dotproduct(&d->ptr.p_double[0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); + s = (double)1/ae_sqrt(s, _state); + ae_v_muld(&d->ptr.p_double[0], 1, ae_v_len(0,n-1), s); + *stp = *stp/s; +} + + +/************************************************************************* +THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT +DECREASE CONDITION AND A CURVATURE CONDITION. + +AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH +ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN +SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION + + F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). + +IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE +FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF +UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). + +THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT +DECREASE CONDITION + + F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), + +AND THE CURVATURE CONDITION + + ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). + +IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED +BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. +IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE +ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. +IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. + + +:::::::::::::IMPORTANT NOTES::::::::::::: + +NOTE 1: + +This routine guarantees that it will stop at the last point where function +value was calculated. It won't make several additional function evaluations +after finding good point. So if you store function evaluations requested by +this routine, you can be sure that last one is the point where we've stopped. + +NOTE 2: + +when 0initial_point - after rounding to machine precision + +NOTE 4: + +when non-descent direction is specified, algorithm stops with MCINFO=0, +Stp=0 and initial point at X[]. +::::::::::::::::::::::::::::::::::::::::: + + +PARAMETERS DESCRIPRION + +STAGE IS ZERO ON FIRST CALL, ZERO ON FINAL EXIT + +N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES. + +X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR +THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S. + +F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT +IT CONTAINS THE VALUE OF F AT X + STP*S. + +G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X. +ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S. + +S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION. + +STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE +OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE. + +FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE +SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE +SATISFIED. + +XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE +WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. + +STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND +UPPER BOUNDS FOR THE STEP. + +MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE +NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION. + +INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS: + INFO = 0 IMPROPER INPUT PARAMETERS. + + INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE + DIRECTIONAL DERIVATIVE CONDITION HOLD. + + INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY + IS AT MOST XTOL. + + INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV. + + INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN. + + INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX. + + INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS. + THERE MAY NOT BE A STEP WHICH SATISFIES THE + SUFFICIENT DECREASE AND CURVATURE CONDITIONS. + TOLERANCES MAY BE TOO SMALL. + +NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN. + +WA IS A WORK ARRAY OF LENGTH N. + +ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983 +JORGE J. MORE', DAVID J. THUENTE +*************************************************************************/ +void mcsrch(ae_int_t n, + /* Real */ ae_vector* x, + double* f, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* s, + double* stp, + double stpmax, + double gtol, + ae_int_t* info, + ae_int_t* nfev, + /* Real */ ae_vector* wa, + linminstate* state, + ae_int_t* stage, + ae_state *_state) +{ + ae_int_t i; + double v; + double p5; + double p66; + double zero; + + + + /* + * init + */ + p5 = 0.5; + p66 = 0.66; + state->xtrapf = 4.0; + zero = (double)(0); + if( ae_fp_eq(stpmax,(double)(0)) ) + { + stpmax = linmin_defstpmax; + } + if( ae_fp_less(*stp,linmin_stpmin) ) + { + *stp = linmin_stpmin; + } + if( ae_fp_greater(*stp,stpmax) ) + { + *stp = stpmax; + } + + /* + * Main cycle + */ + for(;;) + { + if( *stage==0 ) + { + + /* + * NEXT + */ + *stage = 2; + continue; + } + if( *stage==2 ) + { + state->infoc = 1; + *info = 0; + + /* + * CHECK THE INPUT PARAMETERS FOR ERRORS. + */ + if( ae_fp_less(stpmax,linmin_stpmin)&&ae_fp_greater(stpmax,(double)(0)) ) + { + *info = 5; + *stp = stpmax; + *stage = 0; + return; + } + if( ((((((n<=0||ae_fp_less_eq(*stp,(double)(0)))||ae_fp_less(linmin_ftol,(double)(0)))||ae_fp_less(gtol,zero))||ae_fp_less(linmin_xtol,zero))||ae_fp_less(linmin_stpmin,zero))||ae_fp_less(stpmax,linmin_stpmin))||linmin_maxfev<=0 ) + { + *stage = 0; + return; + } + + /* + * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION + * AND CHECK THAT S IS A DESCENT DIRECTION. + */ + v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->dginit = v; + if( ae_fp_greater_eq(state->dginit,(double)(0)) ) + { + *stage = 0; + *stp = (double)(0); + return; + } + + /* + * INITIALIZE LOCAL VARIABLES. + */ + state->brackt = ae_false; + state->stage1 = ae_true; + *nfev = 0; + state->finit = *f; + state->dgtest = linmin_ftol*state->dginit; + state->width = stpmax-linmin_stpmin; + state->width1 = state->width/p5; + ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, + * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. + * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, + * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF + * THE INTERVAL OF UNCERTAINTY. + * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, + * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. + */ + state->stx = (double)(0); + state->fx = state->finit; + state->dgx = state->dginit; + state->sty = (double)(0); + state->fy = state->finit; + state->dgy = state->dginit; + + /* + * NEXT + */ + *stage = 3; + continue; + } + if( *stage==3 ) + { + + /* + * START OF ITERATION. + * + * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND + * TO THE PRESENT INTERVAL OF UNCERTAINTY. + */ + if( state->brackt ) + { + if( ae_fp_less(state->stx,state->sty) ) + { + state->stmin = state->stx; + state->stmax = state->sty; + } + else + { + state->stmin = state->sty; + state->stmax = state->stx; + } + } + else + { + state->stmin = state->stx; + state->stmax = *stp+state->xtrapf*(*stp-state->stx); + } + + /* + * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. + */ + if( ae_fp_greater(*stp,stpmax) ) + { + *stp = stpmax; + } + if( ae_fp_less(*stp,linmin_stpmin) ) + { + *stp = linmin_stpmin; + } + + /* + * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET + * STP BE THE LOWEST POINT OBTAINED SO FAR. + */ + if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=linmin_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax)) ) + { + *stp = state->stx; + } + + /* + * EVALUATE THE FUNCTION AND GRADIENT AT STP + * AND COMPUTE THE DIRECTIONAL DERIVATIVE. + */ + ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); + + /* + * NEXT + */ + *stage = 4; + return; + } + if( *stage==4 ) + { + *info = 0; + *nfev = *nfev+1; + v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->dg = v; + state->ftest1 = state->finit+*stp*state->dgtest; + + /* + * TEST FOR CONVERGENCE. + */ + if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) + { + *info = 6; + } + if( ((ae_fp_eq(*stp,stpmax)&&ae_fp_less(*f,state->finit))&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) + { + *info = 5; + } + if( ae_fp_eq(*stp,linmin_stpmin)&&((ae_fp_greater_eq(*f,state->finit)||ae_fp_greater(*f,state->ftest1))||ae_fp_greater_eq(state->dg,state->dgtest)) ) + { + *info = 4; + } + if( *nfev>=linmin_maxfev ) + { + *info = 3; + } + if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,linmin_xtol*state->stmax) ) + { + *info = 2; + } + if( (ae_fp_less(*f,state->finit)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(ae_fabs(state->dg, _state),-gtol*state->dginit) ) + { + *info = 1; + } + + /* + * CHECK FOR TERMINATION. + */ + if( *info!=0 ) + { + + /* + * Check guarantees provided by the function for INFO=1 or INFO=5 + */ + if( *info==1||*info==5 ) + { + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+(wa->ptr.p_double[i]-x->ptr.p_double[i])*(wa->ptr.p_double[i]-x->ptr.p_double[i]); + } + if( ae_fp_greater_eq(*f,state->finit)||ae_fp_eq(v,0.0) ) + { + *info = 6; + } + } + *stage = 0; + return; + } + + /* + * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED + * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. + */ + if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(linmin_ftol, gtol, _state)*state->dginit) ) + { + state->stage1 = ae_false; + } + + /* + * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF + * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED + * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE + * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN + * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. + */ + if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) + { + + /* + * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. + */ + state->fm = *f-*stp*state->dgtest; + state->fxm = state->fx-state->stx*state->dgtest; + state->fym = state->fy-state->sty*state->dgtest; + state->dgm = state->dg-state->dgtest; + state->dgxm = state->dgx-state->dgtest; + state->dgym = state->dgy-state->dgtest; + + /* + * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY + * AND TO COMPUTE THE NEW STEP. + */ + linmin_mcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); + + /* + * RESET THE FUNCTION AND GRADIENT VALUES FOR F. + */ + state->fx = state->fxm+state->stx*state->dgtest; + state->fy = state->fym+state->sty*state->dgtest; + state->dgx = state->dgxm+state->dgtest; + state->dgy = state->dgym+state->dgtest; + } + else + { + + /* + * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY + * AND TO COMPUTE THE NEW STEP. + */ + linmin_mcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); + } + + /* + * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE + * INTERVAL OF UNCERTAINTY. + */ + if( state->brackt ) + { + if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) + { + *stp = state->stx+p5*(state->sty-state->stx); + } + state->width1 = state->width; + state->width = ae_fabs(state->sty-state->stx, _state); + } + + /* + * NEXT. + */ + *stage = 3; + continue; + } + } +} + + +/************************************************************************* +These functions perform Armijo line search using at most FMAX function +evaluations. It doesn't enforce some kind of " sufficient decrease" +criterion - it just tries different Armijo steps and returns optimum found +so far. + +Optimization is done using F-rcomm interface: +* ArmijoCreate initializes State structure + (reusing previously allocated buffers) +* ArmijoIteration is subsequently called +* ArmijoResults returns results + +INPUT PARAMETERS: + N - problem size + X - array[N], starting point + F - F(X+S*STP) + S - step direction, S>0 + STP - step length + STPMAX - maximum value for STP or zero (if no limit is imposed) + FMAX - maximum number of function evaluations + State - optimization state + + -- ALGLIB -- + Copyright 05.10.2010 by Bochkanov Sergey +*************************************************************************/ +void armijocreate(ae_int_t n, + /* Real */ const ae_vector* x, + double f, + /* Real */ const ae_vector* s, + double stp, + double stpmax, + ae_int_t fmax, + armijostate* state, + ae_state *_state) +{ + + + if( state->x.cntx, n, _state); + } + if( state->xbase.cntxbase, n, _state); + } + if( state->s.cnts, n, _state); + } + state->stpmax = stpmax; + state->fmax = fmax; + state->stplen = stp; + state->fcur = f; + state->n = n; + ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->s.ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_vector_set_length(&state->rstate.ia, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This is rcomm-based search function + + -- ALGLIB -- + Copyright 05.10.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool armijoiteration(armijostate* state, ae_state *_state) +{ + double v; + ae_int_t n; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + v = state->rstate.ra.ptr.p_double[0]; + } + else + { + n = 359; + v = -58.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + if( (ae_fp_less_eq(state->stplen,(double)(0))||ae_fp_less(state->stpmax,(double)(0)))||state->fmax<2 ) + { + state->info = 0; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) + { + state->info = 4; + result = ae_false; + return result; + } + n = state->n; + state->nfev = 0; + + /* + * We always need F + */ + state->needf = ae_true; + + /* + * Bound StpLen + */ + if( ae_fp_greater(state->stplen,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) + { + state->stplen = state->stpmax; + } + + /* + * Increase length + */ + v = state->stplen*linmin_armijofactor; + if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) + { + v = state->stpmax; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->nfev = state->nfev+1; + if( ae_fp_greater_eq(state->f,state->fcur) ) + { + goto lbl_4; + } + state->stplen = v; + state->fcur = state->f; +lbl_6: + if( ae_false ) + { + goto lbl_7; + } + + /* + * test stopping conditions + */ + if( state->nfev>=state->fmax ) + { + state->info = 3; + result = ae_false; + return result; + } + if( ae_fp_greater_eq(state->stplen,state->stpmax) ) + { + state->info = 5; + result = ae_false; + return result; + } + + /* + * evaluate F + */ + v = state->stplen*linmin_armijofactor; + if( ae_fp_greater(v,state->stpmax)&&ae_fp_neq(state->stpmax,(double)(0)) ) + { + v = state->stpmax; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->nfev = state->nfev+1; + + /* + * make decision + */ + if( ae_fp_less(state->f,state->fcur) ) + { + state->stplen = v; + state->fcur = state->f; + } + else + { + state->info = 1; + result = ae_false; + return result; + } + goto lbl_6; +lbl_7: +lbl_4: + + /* + * Decrease length + */ + v = state->stplen/linmin_armijofactor; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->nfev = state->nfev+1; + if( ae_fp_greater_eq(state->f,state->fcur) ) + { + goto lbl_8; + } + state->stplen = state->stplen/linmin_armijofactor; + state->fcur = state->f; +lbl_10: + if( ae_false ) + { + goto lbl_11; + } + + /* + * test stopping conditions + */ + if( state->nfev>=state->fmax ) + { + state->info = 3; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->stplen,linmin_stpmin) ) + { + state->info = 4; + result = ae_false; + return result; + } + + /* + * evaluate F + */ + v = state->stplen/linmin_armijofactor; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->s.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->nfev = state->nfev+1; + + /* + * make decision + */ + if( ae_fp_less(state->f,state->fcur) ) + { + state->stplen = state->stplen/linmin_armijofactor; + state->fcur = state->f; + } + else + { + state->info = 1; + result = ae_false; + return result; + } + goto lbl_10; +lbl_11: +lbl_8: + + /* + * Nothing to be done + */ + state->info = 1; + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ra.ptr.p_double[0] = v; + return result; +} + + +/************************************************************************* +Results of Armijo search + +OUTPUT PARAMETERS: + INFO - on output it is set to one of the return codes: + * 0 improper input params + * 1 optimum step is found with at most FMAX evaluations + * 3 FMAX evaluations were used, + X contains optimum found so far + * 4 step is at lower bound STPMIN + * 5 step is at upper bound + STP - step length (in case of failure it is still returned) + F - function value (in case of failure it is still returned) + + -- ALGLIB -- + Copyright 05.10.2010 by Bochkanov Sergey +*************************************************************************/ +void armijoresults(armijostate* state, + ae_int_t* info, + double* stp, + double* f, + ae_state *_state) +{ + + + *info = state->info; + *stp = state->stplen; + *f = state->fcur; +} + + +static void linmin_mcstep(double* stx, + double* fx, + double* dx, + double* sty, + double* fy, + double* dy, + double* stp, + double fp, + double dp, + ae_bool* brackt, + double stmin, + double stmax, + ae_int_t* info, + ae_state *_state) +{ + ae_bool bound; + double gamma; + double p; + double q; + double r; + double s; + double sgnd; + double stpc; + double stpf; + double stpq; + double theta; + + + *info = 0; + + /* + * CHECK THE INPUT PARAMETERS FOR ERRORS. + */ + if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),(double)(0)))||ae_fp_less(stmax,stmin) ) + { + return; + } + + /* + * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. + */ + sgnd = dp*(*dx/ae_fabs(*dx, _state)); + + /* + * FIRST CASE. A HIGHER FUNCTION VALUE. + * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER + * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, + * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. + */ + if( ae_fp_greater(fp,*fx) ) + { + *info = 1; + bound = ae_true; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); + if( ae_fp_less(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-(*dx)+theta; + q = gamma-(*dx)+gamma+dp; + r = p/q; + stpc = *stx+r*(*stp-(*stx)); + stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/(double)2*(*stp-(*stx)); + if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpc+(stpq-stpc)/(double)2; + } + *brackt = ae_true; + } + else + { + if( ae_fp_less(sgnd,(double)(0)) ) + { + + /* + * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF + * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC + * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, + * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. + */ + *info = 2; + bound = ae_false; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); + if( ae_fp_greater(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma-dp+gamma+(*dx); + r = p/q; + stpc = *stp+r*(*stx-(*stp)); + stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); + if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + *brackt = ae_true; + } + else + { + if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) + { + + /* + * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE + * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. + * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY + * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC + * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE + * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO + * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP + * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. + */ + *info = 3; + bound = ae_true; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + + /* + * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND + * TO INFINITY IN THE DIRECTION OF THE STEP. + */ + gamma = s*ae_sqrt(ae_maxreal((double)(0), ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); + if( ae_fp_greater(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma+(*dx-dp)+gamma; + r = p/q; + if( ae_fp_less(r,(double)(0))&&ae_fp_neq(gamma,(double)(0)) ) + { + stpc = *stp+r*(*stx-(*stp)); + } + else + { + if( ae_fp_greater(*stp,*stx) ) + { + stpc = stmax; + } + else + { + stpc = stmin; + } + } + stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); + if( *brackt ) + { + if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + } + else + { + if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + } + } + else + { + + /* + * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE + * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES + * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP + * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. + */ + *info = 4; + bound = ae_false; + if( *brackt ) + { + theta = (double)3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); + if( ae_fp_greater(*stp,*sty) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma-dp+gamma+(*dy); + r = p/q; + stpc = *stp+r*(*sty-(*stp)); + stpf = stpc; + } + else + { + if( ae_fp_greater(*stp,*stx) ) + { + stpf = stmax; + } + else + { + stpf = stmin; + } + } + } + } + } + + /* + * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT + * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. + */ + if( ae_fp_greater(fp,*fx) ) + { + *sty = *stp; + *fy = fp; + *dy = dp; + } + else + { + if( ae_fp_less(sgnd,0.0) ) + { + *sty = *stx; + *fy = *fx; + *dy = *dx; + } + *stx = *stp; + *fx = fp; + *dx = dp; + } + + /* + * COMPUTE THE NEW STEP AND SAFEGUARD IT. + */ + stpf = ae_minreal(stmax, stpf, _state); + stpf = ae_maxreal(stmin, stpf, _state); + *stp = stpf; + if( *brackt&&bound ) + { + if( ae_fp_greater(*sty,*stx) ) + { + *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); + } + else + { + *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); + } + } +} + + +void _linminstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + linminstate *p = (linminstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _linminstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + linminstate *dst = (linminstate*)_dst; + const linminstate *src = (const linminstate*)_src; + dst->brackt = src->brackt; + dst->stage1 = src->stage1; + dst->infoc = src->infoc; + dst->dg = src->dg; + dst->dgm = src->dgm; + dst->dginit = src->dginit; + dst->dgtest = src->dgtest; + dst->dgx = src->dgx; + dst->dgxm = src->dgxm; + dst->dgy = src->dgy; + dst->dgym = src->dgym; + dst->finit = src->finit; + dst->ftest1 = src->ftest1; + dst->fm = src->fm; + dst->fx = src->fx; + dst->fxm = src->fxm; + dst->fy = src->fy; + dst->fym = src->fym; + dst->stx = src->stx; + dst->sty = src->sty; + dst->stmin = src->stmin; + dst->stmax = src->stmax; + dst->width = src->width; + dst->width1 = src->width1; + dst->xtrapf = src->xtrapf; +} + + +void _linminstate_clear(void* _p) +{ + linminstate *p = (linminstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _linminstate_destroy(void* _p) +{ + linminstate *p = (linminstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _armijostate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + armijostate *p = (armijostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _armijostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + armijostate *dst = (armijostate*)_dst; + const armijostate *src = (const armijostate*)_src; + dst->needf = src->needf; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + dst->n = src->n; + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->stplen = src->stplen; + dst->fcur = src->fcur; + dst->stpmax = src->stpmax; + dst->fmax = src->fmax; + dst->nfev = src->nfev; + dst->info = src->info; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _armijostate_clear(void* _p) +{ + armijostate *p = (armijostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->s); + _rcommstate_clear(&p->rstate); +} + + +void _armijostate_destroy(void* _p) +{ + armijostate *p = (armijostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->s); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_NEARUNITYUNIT) || !defined(AE_PARTIAL_BUILD) + + +double nulog1p(double x, ae_state *_state) +{ + double z; + double lp; + double lq; + double result; + + + z = 1.0+x; + if( ae_fp_less(z,0.70710678118654752440)||ae_fp_greater(z,1.41421356237309504880) ) + { + result = ae_log(z, _state); + return result; + } + z = x*x; + lp = 4.5270000862445199635215E-5; + lp = lp*x+4.9854102823193375972212E-1; + lp = lp*x+6.5787325942061044846969E0; + lp = lp*x+2.9911919328553073277375E1; + lp = lp*x+6.0949667980987787057556E1; + lp = lp*x+5.7112963590585538103336E1; + lp = lp*x+2.0039553499201281259648E1; + lq = 1.0000000000000000000000E0; + lq = lq*x+1.5062909083469192043167E1; + lq = lq*x+8.3047565967967209469434E1; + lq = lq*x+2.2176239823732856465394E2; + lq = lq*x+3.0909872225312059774938E2; + lq = lq*x+2.1642788614495947685003E2; + lq = lq*x+6.0118660497603843919306E1; + z = -0.5*z+x*(z*lp/lq); + result = x+z; + return result; +} + + +double nuexpm1(double x, ae_state *_state) +{ + double r; + double xx; + double ep; + double eq; + double result; + + + if( ae_fp_less(x,-0.5)||ae_fp_greater(x,0.5) ) + { + result = ae_exp(x, _state)-1.0; + return result; + } + xx = x*x; + ep = 1.2617719307481059087798E-4; + ep = ep*xx+3.0299440770744196129956E-2; + ep = ep*xx+9.9999999999999999991025E-1; + eq = 3.0019850513866445504159E-6; + eq = eq*xx+2.5244834034968410419224E-3; + eq = eq*xx+2.2726554820815502876593E-1; + eq = eq*xx+2.0000000000000000000897E0; + r = x*ep; + r = r/(eq-r); + result = r+r; + return result; +} + + +double nucosm1(double x, ae_state *_state) +{ + double xx; + double c; + double result; + + + if( ae_fp_less(x,-0.25*ae_pi)||ae_fp_greater(x,0.25*ae_pi) ) + { + result = ae_cos(x, _state)-(double)1; + return result; + } + xx = x*x; + c = 4.7377507964246204691685E-14; + c = c*xx-1.1470284843425359765671E-11; + c = c*xx+2.0876754287081521758361E-9; + c = c*xx-2.7557319214999787979814E-7; + c = c*xx+2.4801587301570552304991E-5; + c = c*xx-1.3888888888888872993737E-3; + c = c*xx+4.1666666666666666609054E-2; + result = -0.5*xx+xx*xx*c; + return result; +} + + +#endif +#if defined(AE_COMPILE_NTHEORY) || !defined(AE_PARTIAL_BUILD) + + +void findprimitiverootandinverse(ae_int_t n, + ae_int_t* proot, + ae_int_t* invproot, + ae_state *_state) +{ + ae_int_t candroot; + ae_int_t phin; + ae_int_t q; + ae_int_t f; + ae_bool allnonone; + ae_int_t x; + ae_int_t lastx; + ae_int_t y; + ae_int_t lasty; + ae_int_t a; + ae_int_t b; + ae_int_t t; + ae_int_t n2; + + *proot = 0; + *invproot = 0; + + ae_assert(n>=3, "FindPrimitiveRootAndInverse: N<3", _state); + *proot = 0; + *invproot = 0; + + /* + * check that N is prime + */ + ae_assert(ntheory_isprime(n, _state), "FindPrimitiveRoot: N is not prime", _state); + + /* + * Because N is prime, Euler totient function is equal to N-1 + */ + phin = n-1; + + /* + * Test different values of PRoot - from 2 to N-1. + * One of these values MUST be primitive root. + * + * For testing we use algorithm from Wiki (Primitive root modulo n): + * * compute phi(N) + * * determine the different prime factors of phi(N), say p1, ..., pk + * * for every element m of Zn*, compute m^(phi(N)/pi) mod N for i=1..k + * using a fast algorithm for modular exponentiation. + * * a number m for which these k results are all different from 1 is a + * primitive root. + */ + for(candroot=2; candroot<=n-1; candroot++) + { + + /* + * We have current candidate root in CandRoot. + * + * Scan different prime factors of PhiN. Here: + * * F is a current candidate factor + * * Q is a current quotient - amount which was left after dividing PhiN + * by all previous factors + * + * For each factor, perform test mentioned above. + */ + q = phin; + f = 2; + allnonone = ae_true; + while(q>1) + { + if( q%f==0 ) + { + t = ntheory_modexp(candroot, phin/f, n, _state); + if( t==1 ) + { + allnonone = ae_false; + break; + } + while(q%f==0) + { + q = q/f; + } + } + f = f+1; + } + if( allnonone ) + { + *proot = candroot; + break; + } + } + ae_assert(*proot>=2, "FindPrimitiveRoot: internal error (root not found)", _state); + + /* + * Use extended Euclidean algorithm to find multiplicative inverse of primitive root + */ + x = 0; + lastx = 1; + y = 1; + lasty = 0; + a = *proot; + b = n; + while(b!=0) + { + q = a/b; + t = a%b; + a = b; + b = t; + t = lastx-q*x; + lastx = x; + x = t; + t = lasty-q*y; + lasty = y; + y = t; + } + while(lastx<0) + { + lastx = lastx+n; + } + *invproot = lastx; + + /* + * Check that it is safe to perform multiplication modulo N. + * Check results for consistency. + */ + n2 = (n-1)*(n-1); + ae_assert(n2/(n-1)==n-1, "FindPrimitiveRoot: internal error", _state); + ae_assert(*proot*(*invproot)/(*proot)==(*invproot), "FindPrimitiveRoot: internal error", _state); + ae_assert(*proot*(*invproot)/(*invproot)==(*proot), "FindPrimitiveRoot: internal error", _state); + ae_assert(*proot*(*invproot)%n==1, "FindPrimitiveRoot: internal error", _state); +} + + +static ae_bool ntheory_isprime(ae_int_t n, ae_state *_state) +{ + ae_int_t p; + ae_bool result; + + + result = ae_false; + p = 2; + while(p*p<=n) + { + if( n%p==0 ) + { + return result; + } + p = p+1; + } + result = ae_true; + return result; +} + + +static ae_int_t ntheory_modmul(ae_int_t a, + ae_int_t b, + ae_int_t n, + ae_state *_state) +{ + ae_int_t t; + double ra; + double rb; + ae_int_t result; + + + ae_assert(a>=0&&a=N", _state); + ae_assert(b>=0&&b=N", _state); + + /* + * Base cases + */ + ra = (double)(a); + rb = (double)(b); + if( b==0||a==0 ) + { + result = 0; + return result; + } + if( b==1||a==1 ) + { + result = a*b; + return result; + } + if( ae_fp_eq(ra*rb,(double)(a*b)) ) + { + result = a*b%n; + return result; + } + + /* + * Non-base cases + */ + if( b%2==0 ) + { + + /* + * A*B = (A*(B/2)) * 2 + * + * Product T=A*(B/2) is calculated recursively, product T*2 is + * calculated as follows: + * * result:=T-N + * * result:=result+T + * * if result<0 then result:=result+N + * + * In case integer result overflows, we generate exception + */ + t = ntheory_modmul(a, b/2, n, _state); + result = t-n; + result = result+t; + if( result<0 ) + { + result = result+n; + } + } + else + { + + /* + * A*B = (A*(B div 2)) * 2 + A + * + * Product T=A*(B/2) is calculated recursively, product T*2 is + * calculated as follows: + * * result:=T-N + * * result:=result+T + * * if result<0 then result:=result+N + * + * In case integer result overflows, we generate exception + */ + t = ntheory_modmul(a, b/2, n, _state); + result = t-n; + result = result+t; + if( result<0 ) + { + result = result+n; + } + result = result-n; + result = result+a; + if( result<0 ) + { + result = result+n; + } + } + return result; +} + + +static ae_int_t ntheory_modexp(ae_int_t a, + ae_int_t b, + ae_int_t n, + ae_state *_state) +{ + ae_int_t t; + ae_int_t result; + + + ae_assert(a>=0&&a=N", _state); + ae_assert(b>=0, "ModExp: B<0", _state); + + /* + * Base cases + */ + if( b==0 ) + { + result = 1; + return result; + } + if( b==1 ) + { + result = a; + return result; + } + + /* + * Non-base cases + */ + if( b%2==0 ) + { + t = ntheory_modmul(a, a, n, _state); + result = ntheory_modexp(t, b/2, n, _state); + } + else + { + t = ntheory_modmul(a, a, n, _state); + result = ntheory_modexp(t, b/2, n, _state); + result = ntheory_modmul(result, a, n, _state); + } + return result; +} + + +#endif +#if defined(AE_COMPILE_FTBASE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine generates FFT plan for K complex FFT's with length N each. + +INPUT PARAMETERS: + N - FFT length (in complex numbers), N>=1 + K - number of repetitions, K>=1 + +OUTPUT PARAMETERS: + Plan - plan + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +void ftcomplexfftplan(ae_int_t n, + ae_int_t k, + fasttransformplan* plan, + ae_state *_state) +{ + ae_frame _frame_block; + srealarray bluesteinbuf; + ae_int_t rowptr; + ae_int_t bluesteinsize; + ae_int_t precrptr; + ae_int_t preciptr; + ae_int_t precrsize; + ae_int_t precisize; + + ae_frame_make(_state, &_frame_block); + memset(&bluesteinbuf, 0, sizeof(bluesteinbuf)); + _fasttransformplan_clear(plan); + _srealarray_init(&bluesteinbuf, _state, ae_true); + + + /* + * Initial check for parameters + */ + ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); + ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); + + /* + * Determine required sizes of precomputed real and integer + * buffers. This stage of code is highly dependent on internals + * of FTComplexFFTPlanRec() and must be kept synchronized with + * possible changes in internals of plan generation function. + * + * Buffer size is determined as follows: + * * N is factorized + * * we factor out anything which is less or equal to MaxRadix + * * prime factor F>RaderThreshold requires 4*FTBaseFindSmooth(2*F-1) + * real entries to store precomputed Quantities for Bluestein's + * transformation + * * prime factor F<=RaderThreshold does NOT require + * precomputed storage + */ + precrsize = 0; + precisize = 0; + ftbase_ftdeterminespacerequirements(n, &precrsize, &precisize, _state); + if( precrsize>0 ) + { + ae_vector_set_length(&plan->precr, precrsize, _state); + } + if( precisize>0 ) + { + ae_vector_set_length(&plan->preci, precisize, _state); + } + + /* + * Generate plan + */ + rowptr = 0; + precrptr = 0; + preciptr = 0; + bluesteinsize = 1; + ae_vector_set_length(&plan->buffer, 2*n*k, _state); + ftbase_ftcomplexfftplanrec(n, k, ae_true, ae_true, &rowptr, &bluesteinsize, &precrptr, &preciptr, plan, _state); + ae_vector_set_length(&bluesteinbuf.val, bluesteinsize, _state); + ae_shared_pool_set_seed(&plan->bluesteinpool, &bluesteinbuf, (ae_int_t)sizeof(bluesteinbuf), (ae_copy_constructor)_srealarray_init_copy, (ae_destructor)_srealarray_destroy, _state); + + /* + * Check that actual amount of precomputed space used by transformation + * plan is EXACTLY equal to amount of space allocated by us. + */ + ae_assert(precrptr==precrsize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); + ae_assert(preciptr==precisize, "FTComplexFFTPlan: internal error (PrecRPtr<>PrecRSize)", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine applies transformation plan to input/output array A. + +INPUT PARAMETERS: + Plan - transformation plan + A - array, must be large enough for plan to work + OffsA - offset of the subarray to process + RepCnt - repetition count (transformation is repeatedly applied + to subsequent subarrays) + +OUTPUT PARAMETERS: + Plan - plan (temporary buffers can be modified, plan itself + is unchanged and can be reused) + A - transformed array + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +void ftapplyplan(fasttransformplan* plan, + /* Real */ ae_vector* a, + ae_int_t offsa, + ae_int_t repcnt, + ae_state *_state) +{ + ae_int_t plansize; + ae_int_t i; + + + plansize = plan->entries.ptr.pp_int[0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[0][ftbase_colmicrovectorsize]; + for(i=0; i<=repcnt-1; i++) + { + ftbase_ftapplysubplan(plan, 0, a, offsa+plansize*i, 0, &plan->buffer, 1, _state); + } +} + + +/************************************************************************* +Returns good factorization N=N1*N2. + +Usually N1<=N2 (but not always - small N's may be exception). +if N1<>1 then N2<>1. + +Factorization is chosen depending on task type and codelets we have. + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +void ftbasefactorize(ae_int_t n, + ae_int_t tasktype, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state) +{ + ae_int_t j; + + *n1 = 0; + *n2 = 0; + + *n1 = 0; + *n2 = 0; + + /* + * try to find good codelet + */ + if( *n1*(*n2)!=n ) + { + for(j=ftbase_ftbasecodeletrecommended; j>=2; j--) + { + if( n%j==0 ) + { + *n1 = j; + *n2 = n/j; + break; + } + } + } + + /* + * try to factorize N + */ + if( *n1*(*n2)!=n ) + { + for(j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) + { + if( n%j==0 ) + { + *n1 = j; + *n2 = n/j; + break; + } + } + } + + /* + * looks like N is prime :( + */ + if( *n1*(*n2)!=n ) + { + *n1 = 1; + *n2 = n; + } + + /* + * normalize + */ + if( *n2==1&&*n1!=1 ) + { + *n2 = *n1; + *n1 = 1; + } +} + + +/************************************************************************* +Is number smooth? + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state) +{ + ae_int_t i; + ae_bool result; + + + for(i=2; i<=ftbase_ftbasemaxsmoothfactor; i++) + { + while(n%i==0) + { + n = n/i; + } + } + result = n==1; + return result; +} + + +/************************************************************************* +Returns smallest smooth (divisible only by 2, 3, 5) number that is greater +than or equal to max(N,2) + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state) +{ + ae_int_t best; + ae_int_t result; + + + best = 2; + while(bestRaderThreshold requires 4*FTBaseFindSmooth(2*F-1) + * real entries to store precomputed Quantities for Bluestein's + * transformation + * * prime factor F<=RaderThreshold requires 2*(F-1)+ESTIMATE(F-1) + * precomputed storage + */ + ncur = n; + for(i=2; i<=ftbase_maxradix; i++) + { + while(ncur%i==0) + { + ncur = ncur/i; + } + } + f = 2; + while(f<=ncur) + { + while(ncur%f==0) + { + if( f>ftbase_raderthreshold ) + { + *precrsize = *precrsize+4*ftbasefindsmooth(2*f-1, _state); + } + else + { + *precrsize = *precrsize+2*(f-1); + ftbase_ftdeterminespacerequirements(f-1, precrsize, precisize, _state); + } + ncur = ncur/f; + } + f = f+1; + } +} + + +/************************************************************************* +Recurrent function called by FTComplexFFTPlan() and other functions. It +recursively builds transformation plan + +INPUT PARAMETERS: + N - FFT length (in complex numbers), N>=1 + K - number of repetitions, K>=1 + ChildPlan - if True, plan generator inserts OpStart/opEnd in the + plan header/footer. + TopmostPlan - if True, plan generator assumes that it is topmost plan: + * it may use global buffer for transpositions + and there is no other plan which executes in parallel + RowPtr - index which points to past-the-last entry generated so far + BluesteinSize- amount of storage (in real numbers) required for Bluestein buffer + PrecRPtr - pointer to unused part of precomputed real buffer (Plan.PrecR): + * when this function stores some data to precomputed buffer, + it advances pointer. + * it is responsibility of the function to assert that + Plan.PrecR has enough space to store data before actually + writing to buffer. + * it is responsibility of the caller to allocate enough + space before calling this function + PrecIPtr - pointer to unused part of precomputed integer buffer (Plan.PrecI): + * when this function stores some data to precomputed buffer, + it advances pointer. + * it is responsibility of the function to assert that + Plan.PrecR has enough space to store data before actually + writing to buffer. + * it is responsibility of the caller to allocate enough + space before calling this function + Plan - plan (generated so far) + +OUTPUT PARAMETERS: + RowPtr - updated pointer (advanced by number of entries generated + by function) + BluesteinSize- updated amount + (may be increased, but may never be decreased) + +NOTE: in case TopmostPlan is True, ChildPlan is also must be True. + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftcomplexfftplanrec(ae_int_t n, + ae_int_t k, + ae_bool childplan, + ae_bool topmostplan, + ae_int_t* rowptr, + ae_int_t* bluesteinsize, + ae_int_t* precrptr, + ae_int_t* preciptr, + fasttransformplan* plan, + ae_state *_state) +{ + ae_frame _frame_block; + srealarray localbuf; + ae_int_t m; + ae_int_t n1; + ae_int_t n2; + ae_int_t gq; + ae_int_t giq; + ae_int_t row0; + ae_int_t row1; + ae_int_t row2; + ae_int_t row3; + + ae_frame_make(_state, &_frame_block); + memset(&localbuf, 0, sizeof(localbuf)); + _srealarray_init(&localbuf, _state, ae_true); + + ae_assert(n>0, "FTComplexFFTPlan: N<=0", _state); + ae_assert(k>0, "FTComplexFFTPlan: K<=0", _state); + ae_assert(!topmostplan||childplan, "FTComplexFFTPlan: ChildPlan is inconsistent with TopmostPlan", _state); + + /* + * Try to generate "topmost" plan + */ + if( topmostplan&&n>ftbase_recursivethreshold ) + { + ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); + if( n1*n2==0 ) + { + + /* + * Handle prime-factor FFT with Bluestein's FFT. + * Determine size of Bluestein's buffer. + */ + m = ftbasefindsmooth(2*n-1, _state); + *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); + + /* + * Generate plan + */ + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); + row0 = *rowptr; + ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); + ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_true, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + row1 = *rowptr; + plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + + /* + * Fill precomputed buffer + */ + ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); + + /* + * Update pointer to the precomputed area + */ + *precrptr = *precrptr+4*m; + } + else + { + + /* + * Handle composite FFT with recursive Cooley-Tukey which + * uses global buffer instead of local one. + */ + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + row0 = *rowptr; + ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); + row2 = *rowptr; + ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + row1 = *rowptr; + ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; + row3 = *rowptr; + ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; + } + ae_frame_leave(_state); + return; + } + + /* + * Prepare "non-topmost" plan: + * * calculate factorization + * * use local (shared) buffer + * * update buffer size - ANY plan will need at least + * 2*N temporaries, additional requirements can be + * applied later + */ + ftbase_ftfactorize(n, ae_false, &n1, &n2, _state); + + /* + * Handle FFT's with N1*N2=0: either small-N or prime-factor + */ + if( n1*n2==0 ) + { + if( n<=ftbase_maxradix ) + { + + /* + * Small-N FFT + */ + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodeletfft, k, n, 2, 0, _state); + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + ae_frame_leave(_state); + return; + } + if( n<=ftbase_raderthreshold ) + { + + /* + * Handle prime-factor FFT's with Rader's FFT + */ + m = n-1; + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + findprimitiverootandinverse(n, &gq, &giq, _state); + ftbase_ftpushentry4(plan, rowptr, ftbase_opradersfft, k, n, 2, 2, gq, giq, *precrptr, _state); + ftbase_ftprecomputeradersfft(n, gq, giq, &plan->precr, *precrptr, _state); + *precrptr = *precrptr+2*(n-1); + row0 = *rowptr; + ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); + ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + row1 = *rowptr; + plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + } + else + { + + /* + * Handle prime-factor FFT's with Bluestein's FFT + */ + m = ftbasefindsmooth(2*n-1, _state); + *bluesteinsize = ae_maxint(2*m, *bluesteinsize, _state); + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + ftbase_ftpushentry4(plan, rowptr, ftbase_opbluesteinsfft, k, n, 2, m, 2, *precrptr, 0, _state); + ftbase_ftprecomputebluesteinsfft(n, m, &plan->precr, *precrptr, _state); + *precrptr = *precrptr+4*m; + row0 = *rowptr; + ftbase_ftpushentry(plan, rowptr, ftbase_opjmp, 0, 0, 0, 0, _state); + ftbase_ftcomplexfftplanrec(m, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + row1 = *rowptr; + plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Handle Cooley-Tukey FFT with small N1 + */ + if( n1<=ftbase_maxradix ) + { + + /* + * Specialized transformation for small N1: + * * N2 short inplace FFT's, each N1-point, with integrated twiddle factors + * * N1 long FFT's + * * final transposition + */ + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexcodelettwfft, k, n1, 2*n2, 0, _state); + ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * Handle general Cooley-Tukey FFT, either "flat" or "recursive" + */ + if( n<=ftbase_recursivethreshold ) + { + + /* + * General code for large N1/N2, "flat" version without explicit recurrence + * (nested subplans are inserted directly into the body of the plan) + */ + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + ftbase_ftcomplexfftplanrec(n1, k*n2, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); + ftbase_ftcomplexfftplanrec(n2, k*n1, ae_false, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + } + else + { + + /* + * General code for large N1/N2, "recursive" version - nested subplans + * are separated from the plan body. + * + * Generate parent plan. + */ + if( childplan ) + { + ftbase_ftpushentry2(plan, rowptr, ftbase_opstart, k, n, 2, -1, ftbase_ftoptimisticestimate(n, _state), _state); + } + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + row0 = *rowptr; + ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n2, n1, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplexfftfactors, k, n, 2, n1, _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n2, _state); + row2 = *rowptr; + ftbase_ftpushentry2(plan, rowptr, ftbase_opparallelcall, k*n1, n2, 2, 0, ftbase_ftoptimisticestimate(n, _state), _state); + ftbase_ftpushentry(plan, rowptr, ftbase_opcomplextranspose, k, n, 2, n1, _state); + if( childplan ) + { + ftbase_ftpushentry(plan, rowptr, ftbase_opend, k, n, 2, 0, _state); + } + + /* + * Generate child subplans, insert refence to parent plans + */ + row1 = *rowptr; + ftbase_ftcomplexfftplanrec(n1, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + plan->entries.ptr.pp_int[row0][ftbase_colparam0] = row1-row0; + row3 = *rowptr; + ftbase_ftcomplexfftplanrec(n2, 1, ae_true, ae_false, rowptr, bluesteinsize, precrptr, preciptr, plan, _state); + plan->entries.ptr.pp_int[row2][ftbase_colparam0] = row3-row2; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function pushes one more entry to the plan. It resizes Entries matrix +if needed. + +INPUT PARAMETERS: + Plan - plan (generated so far) + RowPtr - index which points to past-the-last entry generated so far + EType - entry type + EOpCnt - operands count + EOpSize - operand size + EMcvSize - microvector size + EParam0 - parameter 0 + +OUTPUT PARAMETERS: + Plan - updated plan + RowPtr - updated pointer + +NOTE: Param1 is set to -1. + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftpushentry(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_state *_state) +{ + + + ftbase_ftpushentry2(plan, rowptr, etype, eopcnt, eopsize, emcvsize, eparam0, -1, _state); +} + + +/************************************************************************* +Same as FTPushEntry(), but sets Param0 AND Param1. +This function pushes one more entry to the plan. It resized Entries matrix +if needed. + +INPUT PARAMETERS: + Plan - plan (generated so far) + RowPtr - index which points to past-the-last entry generated so far + EType - entry type + EOpCnt - operands count + EOpSize - operand size + EMcvSize - microvector size + EParam0 - parameter 0 + EParam1 - parameter 1 + +OUTPUT PARAMETERS: + Plan - updated plan + RowPtr - updated pointer + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftpushentry2(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_int_t eparam1, + ae_state *_state) +{ + + + if( *rowptr>=plan->entries.rows ) + { + imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); + } + plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; + plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; + plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; + plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = 0; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = 0; + *rowptr = *rowptr+1; +} + + +/************************************************************************* +Same as FTPushEntry(), but sets Param0, Param1, Param2 and Param3. +This function pushes one more entry to the plan. It resized Entries matrix +if needed. + +INPUT PARAMETERS: + Plan - plan (generated so far) + RowPtr - index which points to past-the-last entry generated so far + EType - entry type + EOpCnt - operands count + EOpSize - operand size + EMcvSize - microvector size + EParam0 - parameter 0 + EParam1 - parameter 1 + EParam2 - parameter 2 + EParam3 - parameter 3 + +OUTPUT PARAMETERS: + Plan - updated plan + RowPtr - updated pointer + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftpushentry4(fasttransformplan* plan, + ae_int_t* rowptr, + ae_int_t etype, + ae_int_t eopcnt, + ae_int_t eopsize, + ae_int_t emcvsize, + ae_int_t eparam0, + ae_int_t eparam1, + ae_int_t eparam2, + ae_int_t eparam3, + ae_state *_state) +{ + + + if( *rowptr>=plan->entries.rows ) + { + imatrixresize(&plan->entries, ae_maxint(2*plan->entries.rows, 1, _state), ftbase_colscnt, _state); + } + plan->entries.ptr.pp_int[*rowptr][ftbase_coltype] = etype; + plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandscnt] = eopcnt; + plan->entries.ptr.pp_int[*rowptr][ftbase_coloperandsize] = eopsize; + plan->entries.ptr.pp_int[*rowptr][ftbase_colmicrovectorsize] = emcvsize; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam0] = eparam0; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam1] = eparam1; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam2] = eparam2; + plan->entries.ptr.pp_int[*rowptr][ftbase_colparam3] = eparam3; + *rowptr = *rowptr+1; +} + + +/************************************************************************* +This subroutine applies subplan to input/output array A. + +INPUT PARAMETERS: + Plan - transformation plan + SubPlan - subplan index + A - array, must be large enough for plan to work + ABase - base offset in array A, this value points to start of + subarray whose length is equal to length of the plan + AOffset - offset with respect to ABase, 0<=AOffsetentries.ptr.pp_int[subplan][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect subplan header", _state); + rowidx = subplan+1; + while(plan->entries.ptr.pp_int[rowidx][ftbase_coltype]!=ftbase_opend) + { + operation = plan->entries.ptr.pp_int[rowidx][ftbase_coltype]; + operandscnt = repcnt*plan->entries.ptr.pp_int[rowidx][ftbase_coloperandscnt]; + operandsize = plan->entries.ptr.pp_int[rowidx][ftbase_coloperandsize]; + microvectorsize = plan->entries.ptr.pp_int[rowidx][ftbase_colmicrovectorsize]; + param0 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; + param1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam1]; + touchint(¶m1, _state); + + /* + * Process "jump" operation + */ + if( operation==ftbase_opjmp ) + { + rowidx = rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; + continue; + } + + /* + * Process "parallel call" operation: + * * we perform initial check for consistency between parent and child plans + * * we call FTSplitAndApplyParallelPlan(), which splits parallel plan into + * several parallel tasks + */ + if( operation==ftbase_opparallelcall ) + { + parentsize = operandsize*microvectorsize; + childsize = plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandscnt]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_coloperandsize]*plan->entries.ptr.pp_int[rowidx+param0][ftbase_colmicrovectorsize]; + ae_assert(plan->entries.ptr.pp_int[rowidx+param0][ftbase_coltype]==ftbase_opstart, "FTApplySubPlan: incorrect child subplan header", _state); + ae_assert(parentsize==childsize, "FTApplySubPlan: incorrect child subplan header", _state); + chunksize = ae_maxint(ftbase_recursivethreshold/childsize, 1, _state); + i = 0; + while(ibluesteinpool, &_bufa, _state); + ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufb, _state); + ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufc, _state); + ae_shared_pool_retrieve(&plan->bluesteinpool, &_bufd, _state); + ftbase_ftbluesteinsfft(plan, a, abase, aoffset, operandscnt, operandsize, plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], &bufa->val, &bufb->val, &bufc->val, &bufd->val, _state); + ae_shared_pool_recycle(&plan->bluesteinpool, &_bufa, _state); + ae_shared_pool_recycle(&plan->bluesteinpool, &_bufb, _state); + ae_shared_pool_recycle(&plan->bluesteinpool, &_bufc, _state); + ae_shared_pool_recycle(&plan->bluesteinpool, &_bufd, _state); + rowidx = rowidx+1; + continue; + } + + /* + * Process Rader's FFT + */ + if( operation==ftbase_opradersfft ) + { + ftbase_ftradersfft(plan, a, abase, aoffset, operandscnt, operandsize, rowidx+plan->entries.ptr.pp_int[rowidx][ftbase_colparam0], plan->entries.ptr.pp_int[rowidx][ftbase_colparam1], plan->entries.ptr.pp_int[rowidx][ftbase_colparam2], plan->entries.ptr.pp_int[rowidx][ftbase_colparam3], buf, _state); + rowidx = rowidx+1; + continue; + } + + /* + * Process "complex twiddle factors" operation + */ + if( operation==ftbase_opcomplexfftfactors ) + { + ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); + n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; + n2 = operandsize/n1; + for(i=0; i<=operandscnt-1; i++) + { + ftbase_ffttwcalc(a, abase+aoffset+i*operandsize*2, n1, n2, _state); + } + rowidx = rowidx+1; + continue; + } + + /* + * Process "complex transposition" operation + */ + if( operation==ftbase_opcomplextranspose ) + { + ae_assert(microvectorsize==2, "FTApplySubPlan: MicrovectorSize<>1", _state); + n1 = plan->entries.ptr.pp_int[rowidx][ftbase_colparam0]; + n2 = operandsize/n1; + for(i=0; i<=operandscnt-1; i++) + { + ftbase_internalcomplexlintranspose(a, n1, n2, abase+aoffset+i*operandsize*2, buf, _state); + } + rowidx = rowidx+1; + continue; + } + + /* + * Error + */ + ae_assert(ae_false, "FTApplySubPlan: unexpected plan type", _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine applies complex reference FFT to input/output array A. + +VERY SLOW OPERATION, do not use it in real life plans :) + +INPUT PARAMETERS: + A - array, must be large enough for plan to work + Offs - offset of the subarray to process + OperandsCnt - operands count (see description of FastTransformPlan) + OperandSize - operand size (see description of FastTransformPlan) + MicrovectorSize-microvector size (see description of FastTransformPlan) + Buf - temporary array, must be at least OperandsCnt*OperandSize*MicrovectorSize + +OUTPUT PARAMETERS: + A - transformed array + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftapplycomplexreffft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + /* Real */ ae_vector* buf, + ae_state *_state) +{ + ae_int_t opidx; + ae_int_t i; + ae_int_t k; + double hre; + double him; + double c; + double s; + double re; + double im; + ae_int_t n; + + + ae_assert(operandscnt>=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); + ae_assert(operandsize>=1, "FTApplyComplexRefFFT: OperandSize<1", _state); + ae_assert(microvectorsize==2, "FTApplyComplexRefFFT: MicrovectorSize<>2", _state); + n = operandsize; + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + for(i=0; i<=n-1; i++) + { + hre = (double)(0); + him = (double)(0); + for(k=0; k<=n-1; k++) + { + re = a->ptr.p_double[offs+opidx*operandsize*2+2*k+0]; + im = a->ptr.p_double[offs+opidx*operandsize*2+2*k+1]; + c = ae_cos(-(double)2*ae_pi*(double)k*(double)i/(double)n, _state); + s = ae_sin(-(double)2*ae_pi*(double)k*(double)i/(double)n, _state); + hre = hre+c*re-s*im; + him = him+c*im+s*re; + } + buf->ptr.p_double[2*i+0] = hre; + buf->ptr.p_double[2*i+1] = him; + } + for(i=0; i<=operandsize*2-1; i++) + { + a->ptr.p_double[offs+opidx*operandsize*2+i] = buf->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This subroutine applies complex codelet FFT to input/output array A. + +INPUT PARAMETERS: + A - array, must be large enough for plan to work + Offs - offset of the subarray to process + OperandsCnt - operands count (see description of FastTransformPlan) + OperandSize - operand size (see description of FastTransformPlan) + MicrovectorSize-microvector size, must be 2 + +OUTPUT PARAMETERS: + A - transformed array + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftapplycomplexcodeletfft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + ae_state *_state) +{ + ae_int_t opidx; + ae_int_t n; + ae_int_t aoffset; + double a0x; + double a0y; + double a1x; + double a1y; + double a2x; + double a2y; + double a3x; + double a3y; + double a4x; + double a4y; + double a5x; + double a5y; + double v0; + double v1; + double v2; + double v3; + double t1x; + double t1y; + double t2x; + double t2y; + double t3x; + double t3y; + double t4x; + double t4y; + double t5x; + double t5y; + double m1x; + double m1y; + double m2x; + double m2y; + double m3x; + double m3y; + double m4x; + double m4y; + double m5x; + double m5y; + double s1x; + double s1y; + double s2x; + double s2y; + double s3x; + double s3y; + double s4x; + double s4y; + double s5x; + double s5y; + double c1; + double c2; + double c3; + double c4; + double c5; + double v; + + + ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); + ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); + ae_assert(microvectorsize==2, "FTApplyComplexCodeletFFT: MicrovectorSize<>2", _state); + n = operandsize; + + /* + * Hard-coded transforms for different N's + */ + ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletFFT: N>MaxRadix", _state); + if( n==2 ) + { + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset = offs+opidx*operandsize*2; + a0x = a->ptr.p_double[aoffset+0]; + a0y = a->ptr.p_double[aoffset+1]; + a1x = a->ptr.p_double[aoffset+2]; + a1y = a->ptr.p_double[aoffset+3]; + v0 = a0x+a1x; + v1 = a0y+a1y; + v2 = a0x-a1x; + v3 = a0y-a1y; + a->ptr.p_double[aoffset+0] = v0; + a->ptr.p_double[aoffset+1] = v1; + a->ptr.p_double[aoffset+2] = v2; + a->ptr.p_double[aoffset+3] = v3; + } + return; + } + if( n==3 ) + { + c1 = ae_cos((double)2*ae_pi/(double)3, _state)-(double)1; + c2 = ae_sin((double)2*ae_pi/(double)3, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset = offs+opidx*operandsize*2; + a0x = a->ptr.p_double[aoffset+0]; + a0y = a->ptr.p_double[aoffset+1]; + a1x = a->ptr.p_double[aoffset+2]; + a1y = a->ptr.p_double[aoffset+3]; + a2x = a->ptr.p_double[aoffset+4]; + a2y = a->ptr.p_double[aoffset+5]; + t1x = a1x+a2x; + t1y = a1y+a2y; + a0x = a0x+t1x; + a0y = a0y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a1y-a2y); + m2y = c2*(a2x-a1x); + s1x = a0x+m1x; + s1y = a0y+m1y; + a1x = s1x+m2x; + a1y = s1y+m2y; + a2x = s1x-m2x; + a2y = s1y-m2y; + a->ptr.p_double[aoffset+0] = a0x; + a->ptr.p_double[aoffset+1] = a0y; + a->ptr.p_double[aoffset+2] = a1x; + a->ptr.p_double[aoffset+3] = a1y; + a->ptr.p_double[aoffset+4] = a2x; + a->ptr.p_double[aoffset+5] = a2y; + } + return; + } + if( n==4 ) + { + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset = offs+opidx*operandsize*2; + a0x = a->ptr.p_double[aoffset+0]; + a0y = a->ptr.p_double[aoffset+1]; + a1x = a->ptr.p_double[aoffset+2]; + a1y = a->ptr.p_double[aoffset+3]; + a2x = a->ptr.p_double[aoffset+4]; + a2y = a->ptr.p_double[aoffset+5]; + a3x = a->ptr.p_double[aoffset+6]; + a3y = a->ptr.p_double[aoffset+7]; + t1x = a0x+a2x; + t1y = a0y+a2y; + t2x = a1x+a3x; + t2y = a1y+a3y; + m2x = a0x-a2x; + m2y = a0y-a2y; + m3x = a1y-a3y; + m3y = a3x-a1x; + a->ptr.p_double[aoffset+0] = t1x+t2x; + a->ptr.p_double[aoffset+1] = t1y+t2y; + a->ptr.p_double[aoffset+4] = t1x-t2x; + a->ptr.p_double[aoffset+5] = t1y-t2y; + a->ptr.p_double[aoffset+2] = m2x+m3x; + a->ptr.p_double[aoffset+3] = m2y+m3y; + a->ptr.p_double[aoffset+6] = m2x-m3x; + a->ptr.p_double[aoffset+7] = m2y-m3y; + } + return; + } + if( n==5 ) + { + v = (double)2*ae_pi/(double)5; + c1 = (ae_cos(v, _state)+ae_cos((double)2*v, _state))/(double)2-(double)1; + c2 = (ae_cos(v, _state)-ae_cos((double)2*v, _state))/(double)2; + c3 = -ae_sin(v, _state); + c4 = -(ae_sin(v, _state)+ae_sin((double)2*v, _state)); + c5 = ae_sin(v, _state)-ae_sin((double)2*v, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset = offs+opidx*operandsize*2; + t1x = a->ptr.p_double[aoffset+2]+a->ptr.p_double[aoffset+8]; + t1y = a->ptr.p_double[aoffset+3]+a->ptr.p_double[aoffset+9]; + t2x = a->ptr.p_double[aoffset+4]+a->ptr.p_double[aoffset+6]; + t2y = a->ptr.p_double[aoffset+5]+a->ptr.p_double[aoffset+7]; + t3x = a->ptr.p_double[aoffset+2]-a->ptr.p_double[aoffset+8]; + t3y = a->ptr.p_double[aoffset+3]-a->ptr.p_double[aoffset+9]; + t4x = a->ptr.p_double[aoffset+6]-a->ptr.p_double[aoffset+4]; + t4y = a->ptr.p_double[aoffset+7]-a->ptr.p_double[aoffset+5]; + t5x = t1x+t2x; + t5y = t1y+t2y; + a->ptr.p_double[aoffset+0] = a->ptr.p_double[aoffset+0]+t5x; + a->ptr.p_double[aoffset+1] = a->ptr.p_double[aoffset+1]+t5y; + m1x = c1*t5x; + m1y = c1*t5y; + m2x = c2*(t1x-t2x); + m2y = c2*(t1y-t2y); + m3x = -c3*(t3y+t4y); + m3y = c3*(t3x+t4x); + m4x = -c4*t4y; + m4y = c4*t4x; + m5x = -c5*t3y; + m5y = c5*t3x; + s3x = m3x-m4x; + s3y = m3y-m4y; + s5x = m3x+m5x; + s5y = m3y+m5y; + s1x = a->ptr.p_double[aoffset+0]+m1x; + s1y = a->ptr.p_double[aoffset+1]+m1y; + s2x = s1x+m2x; + s2y = s1y+m2y; + s4x = s1x-m2x; + s4y = s1y-m2y; + a->ptr.p_double[aoffset+2] = s2x+s3x; + a->ptr.p_double[aoffset+3] = s2y+s3y; + a->ptr.p_double[aoffset+4] = s4x+s5x; + a->ptr.p_double[aoffset+5] = s4y+s5y; + a->ptr.p_double[aoffset+6] = s4x-s5x; + a->ptr.p_double[aoffset+7] = s4y-s5y; + a->ptr.p_double[aoffset+8] = s2x-s3x; + a->ptr.p_double[aoffset+9] = s2y-s3y; + } + return; + } + if( n==6 ) + { + c1 = ae_cos((double)2*ae_pi/(double)3, _state)-(double)1; + c2 = ae_sin((double)2*ae_pi/(double)3, _state); + c3 = ae_cos(-ae_pi/(double)3, _state); + c4 = ae_sin(-ae_pi/(double)3, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset = offs+opidx*operandsize*2; + a0x = a->ptr.p_double[aoffset+0]; + a0y = a->ptr.p_double[aoffset+1]; + a1x = a->ptr.p_double[aoffset+2]; + a1y = a->ptr.p_double[aoffset+3]; + a2x = a->ptr.p_double[aoffset+4]; + a2y = a->ptr.p_double[aoffset+5]; + a3x = a->ptr.p_double[aoffset+6]; + a3y = a->ptr.p_double[aoffset+7]; + a4x = a->ptr.p_double[aoffset+8]; + a4y = a->ptr.p_double[aoffset+9]; + a5x = a->ptr.p_double[aoffset+10]; + a5y = a->ptr.p_double[aoffset+11]; + v0 = a0x; + v1 = a0y; + a0x = a0x+a3x; + a0y = a0y+a3y; + a3x = v0-a3x; + a3y = v1-a3y; + v0 = a1x; + v1 = a1y; + a1x = a1x+a4x; + a1y = a1y+a4y; + a4x = v0-a4x; + a4y = v1-a4y; + v0 = a2x; + v1 = a2y; + a2x = a2x+a5x; + a2y = a2y+a5y; + a5x = v0-a5x; + a5y = v1-a5y; + t4x = a4x*c3-a4y*c4; + t4y = a4x*c4+a4y*c3; + a4x = t4x; + a4y = t4y; + t5x = -a5x*c3-a5y*c4; + t5y = a5x*c4-a5y*c3; + a5x = t5x; + a5y = t5y; + t1x = a1x+a2x; + t1y = a1y+a2y; + a0x = a0x+t1x; + a0y = a0y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a1y-a2y); + m2y = c2*(a2x-a1x); + s1x = a0x+m1x; + s1y = a0y+m1y; + a1x = s1x+m2x; + a1y = s1y+m2y; + a2x = s1x-m2x; + a2y = s1y-m2y; + t1x = a4x+a5x; + t1y = a4y+a5y; + a3x = a3x+t1x; + a3y = a3y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a4y-a5y); + m2y = c2*(a5x-a4x); + s1x = a3x+m1x; + s1y = a3y+m1y; + a4x = s1x+m2x; + a4y = s1y+m2y; + a5x = s1x-m2x; + a5y = s1y-m2y; + a->ptr.p_double[aoffset+0] = a0x; + a->ptr.p_double[aoffset+1] = a0y; + a->ptr.p_double[aoffset+2] = a3x; + a->ptr.p_double[aoffset+3] = a3y; + a->ptr.p_double[aoffset+4] = a1x; + a->ptr.p_double[aoffset+5] = a1y; + a->ptr.p_double[aoffset+6] = a4x; + a->ptr.p_double[aoffset+7] = a4y; + a->ptr.p_double[aoffset+8] = a2x; + a->ptr.p_double[aoffset+9] = a2y; + a->ptr.p_double[aoffset+10] = a5x; + a->ptr.p_double[aoffset+11] = a5y; + } + return; + } +} + + +/************************************************************************* +This subroutine applies complex "integrated" codelet FFT to input/output +array A. "Integrated" codelet differs from "normal" one in following ways: +* it can work with MicrovectorSize>1 +* hence, it can be used in Cooley-Tukey FFT without transpositions +* it performs inlined multiplication by twiddle factors of Cooley-Tukey + FFT with N2=MicrovectorSize/2. + +INPUT PARAMETERS: + A - array, must be large enough for plan to work + Offs - offset of the subarray to process + OperandsCnt - operands count (see description of FastTransformPlan) + OperandSize - operand size (see description of FastTransformPlan) + MicrovectorSize-microvector size, must be 1 + +OUTPUT PARAMETERS: + A - transformed array + + -- ALGLIB -- + Copyright 05.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftapplycomplexcodelettwfft(/* Real */ ae_vector* a, + ae_int_t offs, + ae_int_t operandscnt, + ae_int_t operandsize, + ae_int_t microvectorsize, + ae_state *_state) +{ + ae_int_t opidx; + ae_int_t mvidx; + ae_int_t n; + ae_int_t m; + ae_int_t aoffset0; + ae_int_t aoffset2; + ae_int_t aoffset4; + ae_int_t aoffset6; + ae_int_t aoffset8; + ae_int_t aoffset10; + double a0x; + double a0y; + double a1x; + double a1y; + double a2x; + double a2y; + double a3x; + double a3y; + double a4x; + double a4y; + double a5x; + double a5y; + double v0; + double v1; + double v2; + double v3; + double q0x; + double q0y; + double t1x; + double t1y; + double t2x; + double t2y; + double t3x; + double t3y; + double t4x; + double t4y; + double t5x; + double t5y; + double m1x; + double m1y; + double m2x; + double m2y; + double m3x; + double m3y; + double m4x; + double m4y; + double m5x; + double m5y; + double s1x; + double s1y; + double s2x; + double s2y; + double s3x; + double s3y; + double s4x; + double s4y; + double s5x; + double s5y; + double c1; + double c2; + double c3; + double c4; + double c5; + double v; + double tw0; + double tw1; + double twx; + double twxm1; + double twy; + double tw2x; + double tw2y; + double tw3x; + double tw3y; + double tw4x; + double tw4y; + double tw5x; + double tw5y; + + + ae_assert(operandscnt>=1, "FTApplyComplexCodeletFFT: OperandsCnt<1", _state); + ae_assert(operandsize>=1, "FTApplyComplexCodeletFFT: OperandSize<1", _state); + ae_assert(microvectorsize>=1, "FTApplyComplexCodeletFFT: MicrovectorSize<>1", _state); + ae_assert(microvectorsize%2==0, "FTApplyComplexCodeletFFT: MicrovectorSize is not even", _state); + n = operandsize; + m = microvectorsize/2; + + /* + * Hard-coded transforms for different N's + */ + ae_assert(n<=ftbase_maxradix, "FTApplyComplexCodeletTwFFT: N>MaxRadix", _state); + if( n==2 ) + { + v = -(double)2*ae_pi/(double)(n*m); + tw0 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + tw1 = ae_sin(v, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset0 = offs+opidx*operandsize*microvectorsize; + aoffset2 = aoffset0+microvectorsize; + twxm1 = 0.0; + twy = 0.0; + for(mvidx=0; mvidx<=m-1; mvidx++) + { + a0x = a->ptr.p_double[aoffset0]; + a0y = a->ptr.p_double[aoffset0+1]; + a1x = a->ptr.p_double[aoffset2]; + a1y = a->ptr.p_double[aoffset2+1]; + v0 = a0x+a1x; + v1 = a0y+a1y; + v2 = a0x-a1x; + v3 = a0y-a1y; + a->ptr.p_double[aoffset0] = v0; + a->ptr.p_double[aoffset0+1] = v1; + a->ptr.p_double[aoffset2] = v2*((double)1+twxm1)-v3*twy; + a->ptr.p_double[aoffset2+1] = v3*((double)1+twxm1)+v2*twy; + aoffset0 = aoffset0+2; + aoffset2 = aoffset2+2; + if( (mvidx+1)%ftbase_updatetw==0 ) + { + v = -(double)2*ae_pi*(double)(mvidx+1)/(double)(n*m); + twxm1 = ae_sin(0.5*v, _state); + twxm1 = -(double)2*twxm1*twxm1; + twy = ae_sin(v, _state); + } + else + { + v = twxm1+tw0+twxm1*tw0-twy*tw1; + twy = twy+tw1+twxm1*tw1+twy*tw0; + twxm1 = v; + } + } + } + return; + } + if( n==3 ) + { + v = -(double)2*ae_pi/(double)(n*m); + tw0 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + tw1 = ae_sin(v, _state); + c1 = ae_cos((double)2*ae_pi/(double)3, _state)-(double)1; + c2 = ae_sin((double)2*ae_pi/(double)3, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset0 = offs+opidx*operandsize*microvectorsize; + aoffset2 = aoffset0+microvectorsize; + aoffset4 = aoffset2+microvectorsize; + twx = 1.0; + twxm1 = 0.0; + twy = 0.0; + for(mvidx=0; mvidx<=m-1; mvidx++) + { + a0x = a->ptr.p_double[aoffset0]; + a0y = a->ptr.p_double[aoffset0+1]; + a1x = a->ptr.p_double[aoffset2]; + a1y = a->ptr.p_double[aoffset2+1]; + a2x = a->ptr.p_double[aoffset4]; + a2y = a->ptr.p_double[aoffset4+1]; + t1x = a1x+a2x; + t1y = a1y+a2y; + a0x = a0x+t1x; + a0y = a0y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a1y-a2y); + m2y = c2*(a2x-a1x); + s1x = a0x+m1x; + s1y = a0y+m1y; + a1x = s1x+m2x; + a1y = s1y+m2y; + a2x = s1x-m2x; + a2y = s1y-m2y; + tw2x = twx*twx-twy*twy; + tw2y = (double)2*twx*twy; + a->ptr.p_double[aoffset0] = a0x; + a->ptr.p_double[aoffset0+1] = a0y; + a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; + a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; + a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; + a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; + aoffset0 = aoffset0+2; + aoffset2 = aoffset2+2; + aoffset4 = aoffset4+2; + if( (mvidx+1)%ftbase_updatetw==0 ) + { + v = -(double)2*ae_pi*(double)(mvidx+1)/(double)(n*m); + twxm1 = ae_sin(0.5*v, _state); + twxm1 = -(double)2*twxm1*twxm1; + twy = ae_sin(v, _state); + twx = twxm1+(double)1; + } + else + { + v = twxm1+tw0+twxm1*tw0-twy*tw1; + twy = twy+tw1+twxm1*tw1+twy*tw0; + twxm1 = v; + twx = v+(double)1; + } + } + } + return; + } + if( n==4 ) + { + v = -(double)2*ae_pi/(double)(n*m); + tw0 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + tw1 = ae_sin(v, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset0 = offs+opidx*operandsize*microvectorsize; + aoffset2 = aoffset0+microvectorsize; + aoffset4 = aoffset2+microvectorsize; + aoffset6 = aoffset4+microvectorsize; + twx = 1.0; + twxm1 = 0.0; + twy = 0.0; + for(mvidx=0; mvidx<=m-1; mvidx++) + { + a0x = a->ptr.p_double[aoffset0]; + a0y = a->ptr.p_double[aoffset0+1]; + a1x = a->ptr.p_double[aoffset2]; + a1y = a->ptr.p_double[aoffset2+1]; + a2x = a->ptr.p_double[aoffset4]; + a2y = a->ptr.p_double[aoffset4+1]; + a3x = a->ptr.p_double[aoffset6]; + a3y = a->ptr.p_double[aoffset6+1]; + t1x = a0x+a2x; + t1y = a0y+a2y; + t2x = a1x+a3x; + t2y = a1y+a3y; + m2x = a0x-a2x; + m2y = a0y-a2y; + m3x = a1y-a3y; + m3y = a3x-a1x; + tw2x = twx*twx-twy*twy; + tw2y = (double)2*twx*twy; + tw3x = twx*tw2x-twy*tw2y; + tw3y = twx*tw2y+twy*tw2x; + a1x = m2x+m3x; + a1y = m2y+m3y; + a2x = t1x-t2x; + a2y = t1y-t2y; + a3x = m2x-m3x; + a3y = m2y-m3y; + a->ptr.p_double[aoffset0] = t1x+t2x; + a->ptr.p_double[aoffset0+1] = t1y+t2y; + a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; + a->ptr.p_double[aoffset2+1] = a1y*twx+a1x*twy; + a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; + a->ptr.p_double[aoffset4+1] = a2y*tw2x+a2x*tw2y; + a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; + a->ptr.p_double[aoffset6+1] = a3y*tw3x+a3x*tw3y; + aoffset0 = aoffset0+2; + aoffset2 = aoffset2+2; + aoffset4 = aoffset4+2; + aoffset6 = aoffset6+2; + if( (mvidx+1)%ftbase_updatetw==0 ) + { + v = -(double)2*ae_pi*(double)(mvidx+1)/(double)(n*m); + twxm1 = ae_sin(0.5*v, _state); + twxm1 = -(double)2*twxm1*twxm1; + twy = ae_sin(v, _state); + twx = twxm1+(double)1; + } + else + { + v = twxm1+tw0+twxm1*tw0-twy*tw1; + twy = twy+tw1+twxm1*tw1+twy*tw0; + twxm1 = v; + twx = v+(double)1; + } + } + } + return; + } + if( n==5 ) + { + v = -(double)2*ae_pi/(double)(n*m); + tw0 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + tw1 = ae_sin(v, _state); + v = (double)2*ae_pi/(double)5; + c1 = (ae_cos(v, _state)+ae_cos((double)2*v, _state))/(double)2-(double)1; + c2 = (ae_cos(v, _state)-ae_cos((double)2*v, _state))/(double)2; + c3 = -ae_sin(v, _state); + c4 = -(ae_sin(v, _state)+ae_sin((double)2*v, _state)); + c5 = ae_sin(v, _state)-ae_sin((double)2*v, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset0 = offs+opidx*operandsize*microvectorsize; + aoffset2 = aoffset0+microvectorsize; + aoffset4 = aoffset2+microvectorsize; + aoffset6 = aoffset4+microvectorsize; + aoffset8 = aoffset6+microvectorsize; + twx = 1.0; + twxm1 = 0.0; + twy = 0.0; + for(mvidx=0; mvidx<=m-1; mvidx++) + { + a0x = a->ptr.p_double[aoffset0]; + a0y = a->ptr.p_double[aoffset0+1]; + a1x = a->ptr.p_double[aoffset2]; + a1y = a->ptr.p_double[aoffset2+1]; + a2x = a->ptr.p_double[aoffset4]; + a2y = a->ptr.p_double[aoffset4+1]; + a3x = a->ptr.p_double[aoffset6]; + a3y = a->ptr.p_double[aoffset6+1]; + a4x = a->ptr.p_double[aoffset8]; + a4y = a->ptr.p_double[aoffset8+1]; + t1x = a1x+a4x; + t1y = a1y+a4y; + t2x = a2x+a3x; + t2y = a2y+a3y; + t3x = a1x-a4x; + t3y = a1y-a4y; + t4x = a3x-a2x; + t4y = a3y-a2y; + t5x = t1x+t2x; + t5y = t1y+t2y; + q0x = a0x+t5x; + q0y = a0y+t5y; + m1x = c1*t5x; + m1y = c1*t5y; + m2x = c2*(t1x-t2x); + m2y = c2*(t1y-t2y); + m3x = -c3*(t3y+t4y); + m3y = c3*(t3x+t4x); + m4x = -c4*t4y; + m4y = c4*t4x; + m5x = -c5*t3y; + m5y = c5*t3x; + s3x = m3x-m4x; + s3y = m3y-m4y; + s5x = m3x+m5x; + s5y = m3y+m5y; + s1x = q0x+m1x; + s1y = q0y+m1y; + s2x = s1x+m2x; + s2y = s1y+m2y; + s4x = s1x-m2x; + s4y = s1y-m2y; + tw2x = twx*twx-twy*twy; + tw2y = (double)2*twx*twy; + tw3x = twx*tw2x-twy*tw2y; + tw3y = twx*tw2y+twy*tw2x; + tw4x = tw2x*tw2x-tw2y*tw2y; + tw4y = tw2x*tw2y+tw2y*tw2x; + a1x = s2x+s3x; + a1y = s2y+s3y; + a2x = s4x+s5x; + a2y = s4y+s5y; + a3x = s4x-s5x; + a3y = s4y-s5y; + a4x = s2x-s3x; + a4y = s2y-s3y; + a->ptr.p_double[aoffset0] = q0x; + a->ptr.p_double[aoffset0+1] = q0y; + a->ptr.p_double[aoffset2] = a1x*twx-a1y*twy; + a->ptr.p_double[aoffset2+1] = a1x*twy+a1y*twx; + a->ptr.p_double[aoffset4] = a2x*tw2x-a2y*tw2y; + a->ptr.p_double[aoffset4+1] = a2x*tw2y+a2y*tw2x; + a->ptr.p_double[aoffset6] = a3x*tw3x-a3y*tw3y; + a->ptr.p_double[aoffset6+1] = a3x*tw3y+a3y*tw3x; + a->ptr.p_double[aoffset8] = a4x*tw4x-a4y*tw4y; + a->ptr.p_double[aoffset8+1] = a4x*tw4y+a4y*tw4x; + aoffset0 = aoffset0+2; + aoffset2 = aoffset2+2; + aoffset4 = aoffset4+2; + aoffset6 = aoffset6+2; + aoffset8 = aoffset8+2; + if( (mvidx+1)%ftbase_updatetw==0 ) + { + v = -(double)2*ae_pi*(double)(mvidx+1)/(double)(n*m); + twxm1 = ae_sin(0.5*v, _state); + twxm1 = -(double)2*twxm1*twxm1; + twy = ae_sin(v, _state); + twx = twxm1+(double)1; + } + else + { + v = twxm1+tw0+twxm1*tw0-twy*tw1; + twy = twy+tw1+twxm1*tw1+twy*tw0; + twxm1 = v; + twx = v+(double)1; + } + } + } + return; + } + if( n==6 ) + { + c1 = ae_cos((double)2*ae_pi/(double)3, _state)-(double)1; + c2 = ae_sin((double)2*ae_pi/(double)3, _state); + c3 = ae_cos(-ae_pi/(double)3, _state); + c4 = ae_sin(-ae_pi/(double)3, _state); + v = -(double)2*ae_pi/(double)(n*m); + tw0 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + tw1 = ae_sin(v, _state); + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + aoffset0 = offs+opidx*operandsize*microvectorsize; + aoffset2 = aoffset0+microvectorsize; + aoffset4 = aoffset2+microvectorsize; + aoffset6 = aoffset4+microvectorsize; + aoffset8 = aoffset6+microvectorsize; + aoffset10 = aoffset8+microvectorsize; + twx = 1.0; + twxm1 = 0.0; + twy = 0.0; + for(mvidx=0; mvidx<=m-1; mvidx++) + { + a0x = a->ptr.p_double[aoffset0+0]; + a0y = a->ptr.p_double[aoffset0+1]; + a1x = a->ptr.p_double[aoffset2+0]; + a1y = a->ptr.p_double[aoffset2+1]; + a2x = a->ptr.p_double[aoffset4+0]; + a2y = a->ptr.p_double[aoffset4+1]; + a3x = a->ptr.p_double[aoffset6+0]; + a3y = a->ptr.p_double[aoffset6+1]; + a4x = a->ptr.p_double[aoffset8+0]; + a4y = a->ptr.p_double[aoffset8+1]; + a5x = a->ptr.p_double[aoffset10+0]; + a5y = a->ptr.p_double[aoffset10+1]; + v0 = a0x; + v1 = a0y; + a0x = a0x+a3x; + a0y = a0y+a3y; + a3x = v0-a3x; + a3y = v1-a3y; + v0 = a1x; + v1 = a1y; + a1x = a1x+a4x; + a1y = a1y+a4y; + a4x = v0-a4x; + a4y = v1-a4y; + v0 = a2x; + v1 = a2y; + a2x = a2x+a5x; + a2y = a2y+a5y; + a5x = v0-a5x; + a5y = v1-a5y; + t4x = a4x*c3-a4y*c4; + t4y = a4x*c4+a4y*c3; + a4x = t4x; + a4y = t4y; + t5x = -a5x*c3-a5y*c4; + t5y = a5x*c4-a5y*c3; + a5x = t5x; + a5y = t5y; + t1x = a1x+a2x; + t1y = a1y+a2y; + a0x = a0x+t1x; + a0y = a0y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a1y-a2y); + m2y = c2*(a2x-a1x); + s1x = a0x+m1x; + s1y = a0y+m1y; + a1x = s1x+m2x; + a1y = s1y+m2y; + a2x = s1x-m2x; + a2y = s1y-m2y; + t1x = a4x+a5x; + t1y = a4y+a5y; + a3x = a3x+t1x; + a3y = a3y+t1y; + m1x = c1*t1x; + m1y = c1*t1y; + m2x = c2*(a4y-a5y); + m2y = c2*(a5x-a4x); + s1x = a3x+m1x; + s1y = a3y+m1y; + a4x = s1x+m2x; + a4y = s1y+m2y; + a5x = s1x-m2x; + a5y = s1y-m2y; + tw2x = twx*twx-twy*twy; + tw2y = (double)2*twx*twy; + tw3x = twx*tw2x-twy*tw2y; + tw3y = twx*tw2y+twy*tw2x; + tw4x = tw2x*tw2x-tw2y*tw2y; + tw4y = (double)2*tw2x*tw2y; + tw5x = tw3x*tw2x-tw3y*tw2y; + tw5y = tw3x*tw2y+tw3y*tw2x; + a->ptr.p_double[aoffset0+0] = a0x; + a->ptr.p_double[aoffset0+1] = a0y; + a->ptr.p_double[aoffset2+0] = a3x*twx-a3y*twy; + a->ptr.p_double[aoffset2+1] = a3y*twx+a3x*twy; + a->ptr.p_double[aoffset4+0] = a1x*tw2x-a1y*tw2y; + a->ptr.p_double[aoffset4+1] = a1y*tw2x+a1x*tw2y; + a->ptr.p_double[aoffset6+0] = a4x*tw3x-a4y*tw3y; + a->ptr.p_double[aoffset6+1] = a4y*tw3x+a4x*tw3y; + a->ptr.p_double[aoffset8+0] = a2x*tw4x-a2y*tw4y; + a->ptr.p_double[aoffset8+1] = a2y*tw4x+a2x*tw4y; + a->ptr.p_double[aoffset10+0] = a5x*tw5x-a5y*tw5y; + a->ptr.p_double[aoffset10+1] = a5y*tw5x+a5x*tw5y; + aoffset0 = aoffset0+2; + aoffset2 = aoffset2+2; + aoffset4 = aoffset4+2; + aoffset6 = aoffset6+2; + aoffset8 = aoffset8+2; + aoffset10 = aoffset10+2; + if( (mvidx+1)%ftbase_updatetw==0 ) + { + v = -(double)2*ae_pi*(double)(mvidx+1)/(double)(n*m); + twxm1 = ae_sin(0.5*v, _state); + twxm1 = -(double)2*twxm1*twxm1; + twy = ae_sin(v, _state); + twx = twxm1+(double)1; + } + else + { + v = twxm1+tw0+twxm1*tw0-twy*tw1; + twy = twy+tw1+twxm1*tw1+twy*tw0; + twxm1 = v; + twx = v+(double)1; + } + } + } + return; + } +} + + +/************************************************************************* +This subroutine precomputes data for complex Bluestein's FFT and writes +them to array PrecR[] at specified offset. It is responsibility of the +caller to make sure that PrecR[] is large enough. + +INPUT PARAMETERS: + N - original size of the transform + M - size of the "padded" Bluestein's transform + PrecR - preallocated array + Offs - offset + +OUTPUT PARAMETERS: + PrecR - data at Offs:Offs+4*M-1 are modified: + * PrecR[Offs:Offs+2*M-1] stores Z[k]=exp(i*pi*k^2/N) + * PrecR[Offs+2*M:Offs+4*M-1] stores FFT of the Z + Other parts of PrecR are unchanged. + +NOTE: this function performs internal M-point FFT. It allocates temporary + plan which is destroyed after leaving this function. + + -- ALGLIB -- + Copyright 08.05.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftprecomputebluesteinsfft(ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* precr, + ae_int_t offs, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + double bx; + double by; + fasttransformplan plan; + + ae_frame_make(_state, &_frame_block); + memset(&plan, 0, sizeof(plan)); + _fasttransformplan_init(&plan, _state, ae_true); + + + /* + * Fill first half of PrecR with b[k] = exp(i*pi*k^2/N) + */ + for(i=0; i<=2*m-1; i++) + { + precr->ptr.p_double[offs+i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + bx = ae_cos(ae_pi/(double)n*(double)i*(double)i, _state); + by = ae_sin(ae_pi/(double)n*(double)i*(double)i, _state); + precr->ptr.p_double[offs+2*i+0] = bx; + precr->ptr.p_double[offs+2*i+1] = by; + precr->ptr.p_double[offs+2*((m-i)%m)+0] = bx; + precr->ptr.p_double[offs+2*((m-i)%m)+1] = by; + } + + /* + * Precomputed FFT + */ + ftcomplexfftplan(m, 1, &plan, _state); + for(i=0; i<=2*m-1; i++) + { + precr->ptr.p_double[offs+2*m+i] = precr->ptr.p_double[offs+i]; + } + ftbase_ftapplysubplan(&plan, 0, precr, offs+2*m, 0, &plan.buffer, 1, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine applies complex Bluestein's FFT to input/output array A. + +INPUT PARAMETERS: + Plan - transformation plan + A - array, must be large enough for plan to work + ABase - base offset in array A, this value points to start of + subarray whose length is equal to length of the plan + AOffset - offset with respect to ABase, 0<=AOffsetptr.p_double[p0+0]; + y = a->ptr.p_double[p0+1]; + bx = plan->precr.ptr.p_double[p1+0]; + by = -plan->precr.ptr.p_double[p1+1]; + bufa->ptr.p_double[2*i+0] = x*bx-y*by; + bufa->ptr.p_double[2*i+1] = x*by+y*bx; + p0 = p0+2; + p1 = p1+2; + } + for(i=2*n; i<=2*m-1; i++) + { + bufa->ptr.p_double[i] = (double)(0); + } + + /* + * Perform convolution of A and Z (using precomputed + * FFT of Z stored in Plan structure). + */ + ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); + p0 = 0; + p1 = precoffs+2*m; + for(i=0; i<=m-1; i++) + { + ax = bufa->ptr.p_double[p0+0]; + ay = bufa->ptr.p_double[p0+1]; + bx = plan->precr.ptr.p_double[p1+0]; + by = plan->precr.ptr.p_double[p1+1]; + bufa->ptr.p_double[p0+0] = ax*bx-ay*by; + bufa->ptr.p_double[p0+1] = -(ax*by+ay*bx); + p0 = p0+2; + p1 = p1+2; + } + ftbase_ftapplysubplan(plan, subplan, bufa, 0, 0, bufc, 1, _state); + + /* + * Post processing: + * A:=conj(Z)*conj(A)/M + * Here conj(A)/M corresponds to last stage of inverse DFT, + * and conj(Z) comes from Bluestein's FFT algorithm. + */ + p0 = precoffs; + p1 = 0; + p2 = abase+aoffset+op*2*n; + for(i=0; i<=n-1; i++) + { + bx = plan->precr.ptr.p_double[p0+0]; + by = plan->precr.ptr.p_double[p0+1]; + rx = bufa->ptr.p_double[p1+0]/(double)m; + ry = -bufa->ptr.p_double[p1+1]/(double)m; + a->ptr.p_double[p2+0] = rx*bx-ry*(-by); + a->ptr.p_double[p2+1] = rx*(-by)+ry*bx; + p0 = p0+2; + p1 = p1+2; + p2 = p2+2; + } + } +} + + +/************************************************************************* +This subroutine precomputes data for complex Rader's FFT and writes them +to array PrecR[] at specified offset. It is responsibility of the caller +to make sure that PrecR[] is large enough. + +INPUT PARAMETERS: + N - original size of the transform (before reduction to N-1) + RQ - primitive root modulo N + RIQ - inverse of primitive root modulo N + PrecR - preallocated array + Offs - offset + +OUTPUT PARAMETERS: + PrecR - data at Offs:Offs+2*(N-1)-1 store FFT of Rader's factors, + other parts of PrecR are unchanged. + +NOTE: this function performs internal (N-1)-point FFT. It allocates temporary + plan which is destroyed after leaving this function. + + -- ALGLIB -- + Copyright 08.05.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftprecomputeradersfft(ae_int_t n, + ae_int_t rq, + ae_int_t riq, + /* Real */ ae_vector* precr, + ae_int_t offs, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t q; + fasttransformplan plan; + ae_int_t kiq; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&plan, 0, sizeof(plan)); + _fasttransformplan_init(&plan, _state, ae_true); + + + /* + * Fill PrecR with Rader factors, perform FFT + */ + kiq = 1; + for(q=0; q<=n-2; q++) + { + v = -(double)2*ae_pi*(double)kiq/(double)n; + precr->ptr.p_double[offs+2*q+0] = ae_cos(v, _state); + precr->ptr.p_double[offs+2*q+1] = ae_sin(v, _state); + kiq = kiq*riq%n; + } + ftcomplexfftplan(n-1, 1, &plan, _state); + ftbase_ftapplysubplan(&plan, 0, precr, offs, 0, &plan.buffer, 1, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine applies complex Rader's FFT to input/output array A. + +INPUT PARAMETERS: + A - array, must be large enough for plan to work + ABase - base offset in array A, this value points to start of + subarray whose length is equal to length of the plan + AOffset - offset with respect to ABase, 0<=AOffset=1, "FTApplyComplexRefFFT: OperandsCnt<1", _state); + + /* + * Process operands + */ + for(opidx=0; opidx<=operandscnt-1; opidx++) + { + + /* + * fill QA + */ + kq = 1; + p0 = abase+aoffset+opidx*n*2; + p1 = aoffset+opidx*n*2; + rx = a->ptr.p_double[p0+0]; + ry = a->ptr.p_double[p0+1]; + x0 = rx; + y0 = ry; + for(q=0; q<=n-2; q++) + { + ax = a->ptr.p_double[p0+2*kq+0]; + ay = a->ptr.p_double[p0+2*kq+1]; + buf->ptr.p_double[p1+0] = ax; + buf->ptr.p_double[p1+1] = ay; + rx = rx+ax; + ry = ry+ay; + kq = kq*rq%n; + p1 = p1+2; + } + p0 = abase+aoffset+opidx*n*2; + p1 = aoffset+opidx*n*2; + for(q=0; q<=n-2; q++) + { + a->ptr.p_double[p0] = buf->ptr.p_double[p1]; + a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; + p0 = p0+2; + p1 = p1+2; + } + + /* + * Convolution + */ + ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); + p0 = abase+aoffset+opidx*n*2; + p1 = precoffs; + for(i=0; i<=n-2; i++) + { + ax = a->ptr.p_double[p0+0]; + ay = a->ptr.p_double[p0+1]; + bx = plan->precr.ptr.p_double[p1+0]; + by = plan->precr.ptr.p_double[p1+1]; + a->ptr.p_double[p0+0] = ax*bx-ay*by; + a->ptr.p_double[p0+1] = -(ax*by+ay*bx); + p0 = p0+2; + p1 = p1+2; + } + ftbase_ftapplysubplan(plan, subplan, a, abase, aoffset+opidx*n*2, buf, 1, _state); + p0 = abase+aoffset+opidx*n*2; + for(i=0; i<=n-2; i++) + { + a->ptr.p_double[p0+0] = a->ptr.p_double[p0+0]/(double)(n-1); + a->ptr.p_double[p0+1] = -a->ptr.p_double[p0+1]/(double)(n-1); + p0 = p0+2; + } + + /* + * Result + */ + buf->ptr.p_double[aoffset+opidx*n*2+0] = rx; + buf->ptr.p_double[aoffset+opidx*n*2+1] = ry; + kiq = 1; + p0 = aoffset+opidx*n*2; + p1 = abase+aoffset+opidx*n*2; + for(q=0; q<=n-2; q++) + { + buf->ptr.p_double[p0+2*kiq+0] = x0+a->ptr.p_double[p1+0]; + buf->ptr.p_double[p0+2*kiq+1] = y0+a->ptr.p_double[p1+1]; + kiq = kiq*riq%n; + p1 = p1+2; + } + p0 = abase+aoffset+opidx*n*2; + p1 = aoffset+opidx*n*2; + for(q=0; q<=n-1; q++) + { + a->ptr.p_double[p0] = buf->ptr.p_double[p1]; + a->ptr.p_double[p0+1] = buf->ptr.p_double[p1+1]; + p0 = p0+2; + p1 = p1+2; + } + } +} + + +/************************************************************************* +Factorizes task size N into product of two smaller sizes N1 and N2 + +INPUT PARAMETERS: + N - task size, N>0 + IsRoot - whether taks is root task (first one in a sequence) + +OUTPUT PARAMETERS: + N1, N2 - such numbers that: + * for prime N: N1=N2=0 + * for composite N<=MaxRadix: N1=N2=0 + * for composite N>MaxRadix: 1<=N1<=N2, N1*N2=N + + -- ALGLIB -- + Copyright 08.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftfactorize(ae_int_t n, + ae_bool isroot, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state) +{ + ae_int_t j; + ae_int_t k; + + *n1 = 0; + *n2 = 0; + + ae_assert(n>0, "FTFactorize: N<=0", _state); + *n1 = 0; + *n2 = 0; + + /* + * Small N + */ + if( n<=ftbase_maxradix ) + { + return; + } + + /* + * Large N, recursive split + */ + if( n>ftbase_recursivethreshold ) + { + k = ae_iceil(ae_sqrt((double)(n), _state), _state)+1; + ae_assert(k*k>=n, "FTFactorize: internal error during recursive factorization", _state); + for(j=k; j>=2; j--) + { + if( n%j==0 ) + { + *n1 = ae_minint(n/j, j, _state); + *n2 = ae_maxint(n/j, j, _state); + return; + } + } + } + + /* + * N>MaxRadix, try to find good codelet + */ + for(j=ftbase_maxradix; j>=2; j--) + { + if( n%j==0 ) + { + *n1 = j; + *n2 = n/j; + break; + } + } + + /* + * In case no good codelet was found, + * try to factorize N into product of ANY primes. + */ + if( *n1*(*n2)!=n ) + { + for(j=2; j<=n-1; j++) + { + if( n%j==0 ) + { + *n1 = j; + *n2 = n/j; + break; + } + if( j*j>n ) + { + break; + } + } + } + + /* + * normalize + */ + if( *n1>(*n2) ) + { + j = *n1; + *n1 = *n2; + *n2 = j; + } +} + + +/************************************************************************* +Returns optimistic estimate of the FFT cost, in UNITs (1 UNIT = 100 KFLOPs) + +INPUT PARAMETERS: + N - task size, N>0 + +RESULU: + cost in UNITs, rounded down to nearest integer + +NOTE: If FFT cost is less than 1 UNIT, it will return 0 as result. + + -- ALGLIB -- + Copyright 08.04.2013 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t ftbase_ftoptimisticestimate(ae_int_t n, ae_state *_state) +{ + ae_int_t result; + + + ae_assert(n>0, "FTOptimisticEstimate: N<=0", _state); + result = ae_ifloor(1.0E-5*(double)5*(double)n*ae_log((double)(n), _state)/ae_log((double)(2), _state), _state); + return result; +} + + +/************************************************************************* +Twiddle factors calculation + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ffttwcalc(/* Real */ ae_vector* a, + ae_int_t aoffset, + ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j2; + ae_int_t n; + ae_int_t halfn1; + ae_int_t offs; + double x; + double y; + double twxm1; + double twy; + double twbasexm1; + double twbasey; + double twrowxm1; + double twrowy; + double tmpx; + double tmpy; + double v; + ae_int_t updatetw2; + + + + /* + * Multiplication by twiddle factors for complex Cooley-Tukey FFT + * with N factorized as N1*N2. + * + * Naive solution to this problem is given below: + * + * > for K:=1 to N2-1 do + * > for J:=1 to N1-1 do + * > begin + * > Idx:=K*N1+J; + * > X:=A[AOffset+2*Idx+0]; + * > Y:=A[AOffset+2*Idx+1]; + * > TwX:=Cos(-2*Pi()*K*J/(N1*N2)); + * > TwY:=Sin(-2*Pi()*K*J/(N1*N2)); + * > A[AOffset+2*Idx+0]:=X*TwX-Y*TwY; + * > A[AOffset+2*Idx+1]:=X*TwY+Y*TwX; + * > end; + * + * However, there are exist more efficient solutions. + * + * Each pass of the inner cycle corresponds to multiplication of one + * entry of A by W[k,j]=exp(-I*2*pi*k*j/N). This factor can be rewritten + * as exp(-I*2*pi*k/N)^j. So we can replace costly exponentiation by + * repeated multiplication: W[k,j+1]=W[k,j]*exp(-I*2*pi*k/N), with + * second factor being computed once in the beginning of the iteration. + * + * Also, exp(-I*2*pi*k/N) can be represented as exp(-I*2*pi/N)^k, i.e. + * we have W[K+1,1]=W[K,1]*W[1,1]. + * + * In our loop we use following variables: + * * [TwBaseXM1,TwBaseY] = [cos(2*pi/N)-1, sin(2*pi/N)] + * * [TwRowXM1, TwRowY] = [cos(2*pi*I/N)-1, sin(2*pi*I/N)] + * * [TwXM1, TwY] = [cos(2*pi*I*J/N)-1, sin(2*pi*I*J/N)] + * + * Meaning of the variables: + * * [TwXM1,TwY] is current twiddle factor W[I,J] + * * [TwRowXM1, TwRowY] is W[I,1] + * * [TwBaseXM1,TwBaseY] is W[1,1] + * + * During inner loop we multiply current twiddle factor by W[I,1], + * during outer loop we update W[I,1]. + * + */ + ae_assert(ftbase_updatetw>=2, "FFTTwCalc: internal error - UpdateTw<2", _state); + updatetw2 = ftbase_updatetw/2; + halfn1 = n1/2; + n = n1*n2; + v = -(double)2*ae_pi/(double)n; + twbasexm1 = -(double)2*ae_sqr(ae_sin(0.5*v, _state), _state); + twbasey = ae_sin(v, _state); + twrowxm1 = (double)(0); + twrowy = (double)(0); + offs = aoffset; + for(i=0; i<=n2-1; i++) + { + + /* + * Initialize twiddle factor for current row + */ + twxm1 = (double)(0); + twy = (double)(0); + + /* + * N1-point block is separated into 2-point chunks and residual 1-point chunk + * (in case N1 is odd). Unrolled loop is several times faster. + */ + for(j2=0; j2<=halfn1-1; j2++) + { + + /* + * Processing: + * * process first element in a chunk. + * * update twiddle factor (unconditional update) + * * process second element + * * conditional update of the twiddle factor + */ + x = a->ptr.p_double[offs+0]; + y = a->ptr.p_double[offs+1]; + tmpx = x*((double)1+twxm1)-y*twy; + tmpy = x*twy+y*((double)1+twxm1); + a->ptr.p_double[offs+0] = tmpx; + a->ptr.p_double[offs+1] = tmpy; + tmpx = ((double)1+twxm1)*twrowxm1-twy*twrowy; + twy = twy+((double)1+twxm1)*twrowy+twy*twrowxm1; + twxm1 = twxm1+tmpx; + x = a->ptr.p_double[offs+2]; + y = a->ptr.p_double[offs+3]; + tmpx = x*((double)1+twxm1)-y*twy; + tmpy = x*twy+y*((double)1+twxm1); + a->ptr.p_double[offs+2] = tmpx; + a->ptr.p_double[offs+3] = tmpy; + offs = offs+4; + if( (j2+1)%updatetw2==0&&j2ptr.p_double[offs+0]; + y = a->ptr.p_double[offs+1]; + tmpx = x*((double)1+twxm1)-y*twy; + tmpy = x*twy+y*((double)1+twxm1); + a->ptr.p_double[offs+0] = tmpx; + a->ptr.p_double[offs+1] = tmpy; + offs = offs+2; + } + + /* + * update TwRow: TwRow(new) = TwRow(old)*TwBase + */ + if( iptr.p_double[astart], 1, &buf->ptr.p_double[0], 1, ae_v_len(astart,astart+2*m*n-1)); +} + + +/************************************************************************* +Recurrent subroutine for a InternalComplexLinTranspose + +Write A^T to B, where: +* A is m*n complex matrix stored in array A as pairs of real/image values, + beginning from AStart position, with AStride stride +* B is n*m complex matrix stored in array B as pairs of real/image values, + beginning from BStart position, with BStride stride +stride is measured in complex numbers, i.e. in real/image pairs. + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ffticltrec(/* Real */ ae_vector* a, + ae_int_t astart, + ae_int_t astride, + /* Real */ ae_vector* b, + ae_int_t bstart, + ae_int_t bstride, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t idx1; + ae_int_t idx2; + ae_int_t m2; + ae_int_t m1; + ae_int_t n1; + + + if( m==0||n==0 ) + { + return; + } + if( ae_maxint(m, n, _state)<=8 ) + { + m2 = 2*bstride; + for(i=0; i<=m-1; i++) + { + idx1 = bstart+2*i; + idx2 = astart+2*i*astride; + for(j=0; j<=n-1; j++) + { + b->ptr.p_double[idx1+0] = a->ptr.p_double[idx2+0]; + b->ptr.p_double[idx1+1] = a->ptr.p_double[idx2+1]; + idx1 = idx1+m2; + idx2 = idx2+2; + } + } + return; + } + if( n>m ) + { + + /* + * New partition: + * + * "A^T -> B" becomes "(A1 A2)^T -> ( B1 ) + * ( B2 ) + */ + n1 = n/2; + if( n-n1>=8&&n1%8!=0 ) + { + n1 = n1+(8-n1%8); + } + ae_assert(n-n1>0, "Assertion failed", _state); + ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1, _state); + ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1, _state); + } + else + { + + /* + * New partition: + * + * "A^T -> B" becomes "( A1 )^T -> ( B1 B2 ) + * ( A2 ) + */ + m1 = m/2; + if( m-m1>=8&&m1%8!=0 ) + { + m1 = m1+(8-m1%8); + } + ae_assert(m-m1>0, "Assertion failed", _state); + ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n, _state); + ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n, _state); + } +} + + +/************************************************************************* +recurrent subroutine for FFTFindSmoothRec + + -- ALGLIB -- + Copyright 01.05.2009 by Bochkanov Sergey +*************************************************************************/ +static void ftbase_ftbasefindsmoothrec(ae_int_t n, + ae_int_t seed, + ae_int_t leastfactor, + ae_int_t* best, + ae_state *_state) +{ + + + ae_assert(ftbase_ftbasemaxsmoothfactor<=5, "FTBaseFindSmoothRec: internal error!", _state); + if( seed>=n ) + { + *best = ae_minint(*best, seed, _state); + return; + } + if( leastfactor<=2 ) + { + ftbase_ftbasefindsmoothrec(n, seed*2, 2, best, _state); + } + if( leastfactor<=3 ) + { + ftbase_ftbasefindsmoothrec(n, seed*3, 3, best, _state); + } + if( leastfactor<=5 ) + { + ftbase_ftbasefindsmoothrec(n, seed*5, 5, best, _state); + } +} + + +void _fasttransformplan_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + fasttransformplan *p = (fasttransformplan*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->entries, 0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->buffer, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->precr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->preci, 0, DT_REAL, _state, make_automatic); + ae_shared_pool_init(&p->bluesteinpool, _state, make_automatic); +} + + +void _fasttransformplan_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + fasttransformplan *dst = (fasttransformplan*)_dst; + const fasttransformplan *src = (const fasttransformplan*)_src; + ae_matrix_init_copy(&dst->entries, &src->entries, _state, make_automatic); + ae_vector_init_copy(&dst->buffer, &src->buffer, _state, make_automatic); + ae_vector_init_copy(&dst->precr, &src->precr, _state, make_automatic); + ae_vector_init_copy(&dst->preci, &src->preci, _state, make_automatic); + ae_shared_pool_init_copy(&dst->bluesteinpool, &src->bluesteinpool, _state, make_automatic); +} + + +void _fasttransformplan_clear(void* _p) +{ + fasttransformplan *p = (fasttransformplan*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->entries); + ae_vector_clear(&p->buffer); + ae_vector_clear(&p->precr); + ae_vector_clear(&p->preci); + ae_shared_pool_clear(&p->bluesteinpool); +} + + +void _fasttransformplan_destroy(void* _p) +{ + fasttransformplan *p = (fasttransformplan*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->entries); + ae_vector_destroy(&p->buffer); + ae_vector_destroy(&p->precr); + ae_vector_destroy(&p->preci); + ae_shared_pool_destroy(&p->bluesteinpool); +} + + +#endif +#if defined(AE_COMPILE_HPCCORES) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Prepares HPC compuations of chunked gradient with HPCChunkedGradient(). +You have to call this function before calling HPCChunkedGradient() for +a new set of weights. You have to call it only once, see example below: + +HOW TO PROCESS DATASET WITH THIS FUNCTION: + Grad:=0 + HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) + foreach chunk-of-dataset do + HPCChunkedGradient(...) + HPCFinalizeChunkedGradient(Buf, Grad) + +*************************************************************************/ +void hpcpreparechunkedgradient(/* Real */ const ae_vector* weights, + ae_int_t wcount, + ae_int_t ntotal, + ae_int_t nin, + ae_int_t nout, + mlpbuffers* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t batch4size; + ae_int_t chunksize; + + + chunksize = 4; + batch4size = 3*chunksize*ntotal+chunksize*(2*nout+1); + if( buf->xy.rowsxy.colsxy, chunksize, nin+nout, _state); + } + if( buf->xy2.rowsxy2.colsxy2, chunksize, nin+nout, _state); + } + if( buf->xyrow.cntxyrow, nin+nout, _state); + } + if( buf->x.cntx, nin, _state); + } + if( buf->y.cnty, nout, _state); + } + if( buf->desiredy.cntdesiredy, nout, _state); + } + if( buf->batch4buf.cntbatch4buf, batch4size, _state); + } + if( buf->hpcbuf.cnthpcbuf, wcount, _state); + } + if( buf->g.cntg, wcount, _state); + } + if( !hpccores_hpcpreparechunkedgradientx(weights, wcount, &buf->hpcbuf, _state) ) + { + for(i=0; i<=wcount-1; i++) + { + buf->hpcbuf.ptr.p_double[i] = 0.0; + } + } + buf->wcount = wcount; + buf->ntotal = ntotal; + buf->nin = nin; + buf->nout = nout; + buf->chunksize = chunksize; +} + + +/************************************************************************* +Finalizes HPC compuations of chunked gradient with HPCChunkedGradient(). +You have to call this function after calling HPCChunkedGradient() for +a new set of weights. You have to call it only once, see example below: + +HOW TO PROCESS DATASET WITH THIS FUNCTION: + Grad:=0 + HPCPrepareChunkedGradient(Weights, WCount, NTotal, NOut, Buf) + foreach chunk-of-dataset do + HPCChunkedGradient(...) + HPCFinalizeChunkedGradient(Buf, Grad) + +*************************************************************************/ +void hpcfinalizechunkedgradient(const mlpbuffers* buf, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_int_t i; + + + if( !hpccores_hpcfinalizechunkedgradientx(&buf->hpcbuf, buf->wcount, grad, _state) ) + { + for(i=0; i<=buf->wcount-1; i++) + { + grad->ptr.p_double[i] = grad->ptr.p_double[i]+buf->hpcbuf.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Fast kernel for chunked gradient. + +*************************************************************************/ +ae_bool hpcchunkedgradient(/* Real */ const ae_vector* weights, + /* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + double* e, + ae_bool naturalerrorfunc, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SSE2 + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_hpcchunkedgradient(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc); +#endif +} + + +/************************************************************************* +Fast kernel for chunked processing. + +*************************************************************************/ +ae_bool hpcchunkedprocess(/* Real */ const ae_vector* weights, + /* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SSE2 + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_hpcchunkedprocess(weights, structinfo, columnmeans, columnsigmas, xy, cstart, csize, batch4buf, hpcbuf); +#endif +} + + +/************************************************************************* +Stub function. + + -- ALGLIB routine -- + 14.06.2013 + Bochkanov Sergey +*************************************************************************/ +static ae_bool hpccores_hpcpreparechunkedgradientx(/* Real */ const ae_vector* weights, + ae_int_t wcount, + /* Real */ ae_vector* hpcbuf, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SSE2 + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_hpcpreparechunkedgradientx(weights, wcount, hpcbuf); +#endif +} + + +/************************************************************************* +Stub function. + + -- ALGLIB routine -- + 14.06.2013 + Bochkanov Sergey +*************************************************************************/ +static ae_bool hpccores_hpcfinalizechunkedgradientx(/* Real */ const ae_vector* buf, + ae_int_t wcount, + /* Real */ ae_vector* grad, + ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SSE2 + ae_bool result; + + + result = ae_false; + return result; +#else + return _ialglib_i_hpcfinalizechunkedgradientx(buf, wcount, grad); +#endif +} + + +void _mlpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpbuffers *p = (mlpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->batch4buf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hpcbuf, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xy2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->desiredy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); +} + + +void _mlpbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpbuffers *dst = (mlpbuffers*)_dst; + const mlpbuffers *src = (const mlpbuffers*)_src; + dst->chunksize = src->chunksize; + dst->ntotal = src->ntotal; + dst->nin = src->nin; + dst->nout = src->nout; + dst->wcount = src->wcount; + ae_vector_init_copy(&dst->batch4buf, &src->batch4buf, _state, make_automatic); + ae_vector_init_copy(&dst->hpcbuf, &src->hpcbuf, _state, make_automatic); + ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic); + ae_matrix_init_copy(&dst->xy2, &src->xy2, _state, make_automatic); + ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->desiredy, &src->desiredy, _state, make_automatic); + dst->e = src->e; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); +} + + +void _mlpbuffers_clear(void* _p) +{ + mlpbuffers *p = (mlpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->batch4buf); + ae_vector_clear(&p->hpcbuf); + ae_matrix_clear(&p->xy); + ae_matrix_clear(&p->xy2); + ae_vector_clear(&p->xyrow); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->desiredy); + ae_vector_clear(&p->g); + ae_vector_clear(&p->tmp0); +} + + +void _mlpbuffers_destroy(void* _p) +{ + mlpbuffers *p = (mlpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->batch4buf); + ae_vector_destroy(&p->hpcbuf); + ae_matrix_destroy(&p->xy); + ae_matrix_destroy(&p->xy2); + ae_vector_destroy(&p->xyrow); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->desiredy); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->tmp0); +} + + +#endif +#if defined(AE_COMPILE_ALGLIBBASICS) || !defined(AE_PARTIAL_BUILD) + + +#endif + +} + diff --git a/core/alglib/alglibinternal.h b/core/alglib/alglibinternal.h index a59bf7e2..1eec87c1 100644 --- a/core/alglib/alglibinternal.h +++ b/core/alglib/alglibinternal.h @@ -1,1074 +1,2189 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _alglibinternal_pkg_h -#define _alglibinternal_pkg_h -#include "ap.h" - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_vector ia0; - ae_vector ia1; - ae_vector ia2; - ae_vector ia3; - ae_vector ra0; - ae_vector ra1; - ae_vector ra2; - ae_vector ra3; -} apbuffers; -typedef struct -{ - ae_bool val; -} sboolean; -typedef struct -{ - ae_vector val; -} sbooleanarray; -typedef struct -{ - ae_int_t val; -} sinteger; -typedef struct -{ - ae_vector val; -} sintegerarray; -typedef struct -{ - double val; -} sreal; -typedef struct -{ - ae_vector val; -} srealarray; -typedef struct -{ - ae_complex val; -} scomplex; -typedef struct -{ - ae_vector val; -} scomplexarray; -typedef struct -{ - ae_int_t chunksize; - ae_int_t ntotal; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_vector batch4buf; - ae_vector hpcbuf; - ae_matrix xy; - ae_matrix xy2; - ae_vector xyrow; - ae_vector x; - ae_vector y; - ae_vector desiredy; - double e; - ae_vector g; - ae_vector tmp0; -} mlpbuffers; -typedef struct -{ - ae_bool brackt; - ae_bool stage1; - ae_int_t infoc; - double dg; - double dgm; - double dginit; - double dgtest; - double dgx; - double dgxm; - double dgy; - double dgym; - double finit; - double ftest1; - double fm; - double fx; - double fxm; - double fy; - double fym; - double stx; - double sty; - double stmin; - double stmax; - double width; - double width1; - double xtrapf; -} linminstate; -typedef struct -{ - ae_bool needf; - ae_vector x; - double f; - ae_int_t n; - ae_vector xbase; - ae_vector s; - double stplen; - double fcur; - double stpmax; - ae_int_t fmax; - ae_int_t nfev; - ae_int_t info; - rcommstate rstate; -} armijostate; -typedef struct -{ - ae_matrix entries; - ae_vector buffer; - ae_vector precr; - ae_vector preci; - ae_shared_pool bluesteinpool; -} fasttransformplan; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -ae_bool seterrorflag(ae_bool* flag, ae_bool cond, ae_state *_state); -ae_bool seterrorflagdiff(ae_bool* flag, - double val, - double refval, - double tol, - double s, - ae_state *_state); -void touchint(ae_int_t* a, ae_state *_state); -void touchreal(double* a, ae_state *_state); -double inttoreal(ae_int_t a, ae_state *_state); -double log2(double x, ae_state *_state); -ae_bool approxequalrel(double a, double b, double tol, ae_state *_state); -void taskgenint1d(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void taskgenint1dequidist(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void taskgenint1dcheb1(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void taskgenint1dcheb2(double a, - double b, - ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -ae_bool aredistinct(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state); -void bvectorsetlengthatleast(/* Boolean */ ae_vector* x, - ae_int_t n, - ae_state *_state); -void ivectorsetlengthatleast(/* Integer */ ae_vector* x, - ae_int_t n, - ae_state *_state); -void rvectorsetlengthatleast(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -void rmatrixsetlengthatleast(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void rmatrixresize(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void imatrixresize(/* Integer */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -ae_bool isfinitevector(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -ae_bool isfinitecvector(/* Complex */ ae_vector* z, - ae_int_t n, - ae_state *_state); -ae_bool apservisfinitematrix(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -ae_bool apservisfinitecmatrix(/* Complex */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -ae_bool isfinitertrmatrix(/* Real */ ae_matrix* x, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -ae_bool apservisfinitectrmatrix(/* Complex */ ae_matrix* x, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -ae_bool apservisfiniteornanmatrix(/* Real */ ae_matrix* x, - ae_int_t m, - ae_int_t n, - ae_state *_state); -double safepythag2(double x, double y, ae_state *_state); -double safepythag3(double x, double y, double z, ae_state *_state); -ae_int_t saferdiv(double x, double y, double* r, ae_state *_state); -double safeminposrv(double x, double y, double v, ae_state *_state); -void apperiodicmap(double* x, - double a, - double b, - double* k, - ae_state *_state); -double randomnormal(ae_state *_state); -void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); -void inc(ae_int_t* v, ae_state *_state); -void dec(ae_int_t* v, ae_state *_state); -void countdown(ae_int_t* v, ae_state *_state); -double boundval(double x, double b1, double b2, ae_state *_state); -void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state); -void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state); -ae_complex unserializecomplex(ae_serializer* s, ae_state *_state); -void allocrealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_int_t n, - ae_state *_state); -void serializerealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_int_t n, - ae_state *_state); -void unserializerealarray(ae_serializer* s, - /* Real */ ae_vector* v, - ae_state *_state); -void allocintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_int_t n, - ae_state *_state); -void serializeintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_int_t n, - ae_state *_state); -void unserializeintegerarray(ae_serializer* s, - /* Integer */ ae_vector* v, - ae_state *_state); -void allocrealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_int_t n0, - ae_int_t n1, - ae_state *_state); -void serializerealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_int_t n0, - ae_int_t n1, - ae_state *_state); -void unserializerealmatrix(ae_serializer* s, - /* Real */ ae_matrix* v, - ae_state *_state); -void copyintegerarray(/* Integer */ ae_vector* src, - /* Integer */ ae_vector* dst, - ae_state *_state); -void copyrealarray(/* Real */ ae_vector* src, - /* Real */ ae_vector* dst, - ae_state *_state); -void copyrealmatrix(/* Real */ ae_matrix* src, - /* Real */ ae_matrix* dst, - ae_state *_state); -ae_int_t recsearch(/* Integer */ ae_vector* a, - ae_int_t nrec, - ae_int_t nheader, - ae_int_t i0, - ae_int_t i1, - /* Integer */ ae_vector* b, - ae_state *_state); -void splitlengtheven(ae_int_t tasksize, - ae_int_t* task0, - ae_int_t* task1, - ae_state *_state); -void splitlength(ae_int_t tasksize, - ae_int_t chunksize, - ae_int_t* task0, - ae_int_t* task1, - ae_state *_state); -ae_bool _apbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _apbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _apbuffers_clear(void* _p); -void _apbuffers_destroy(void* _p); -ae_bool _sboolean_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sboolean_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sboolean_clear(void* _p); -void _sboolean_destroy(void* _p); -ae_bool _sbooleanarray_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sbooleanarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sbooleanarray_clear(void* _p); -void _sbooleanarray_destroy(void* _p); -ae_bool _sinteger_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sinteger_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sinteger_clear(void* _p); -void _sinteger_destroy(void* _p); -ae_bool _sintegerarray_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sintegerarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sintegerarray_clear(void* _p); -void _sintegerarray_destroy(void* _p); -ae_bool _sreal_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sreal_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sreal_clear(void* _p); -void _sreal_destroy(void* _p); -ae_bool _srealarray_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _srealarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _srealarray_clear(void* _p); -void _srealarray_destroy(void* _p); -ae_bool _scomplex_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _scomplex_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _scomplex_clear(void* _p); -void _scomplex_destroy(void* _p); -ae_bool _scomplexarray_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _scomplexarray_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _scomplexarray_clear(void* _p); -void _scomplexarray_destroy(void* _p); -ae_int_t getrdfserializationcode(ae_state *_state); -ae_int_t getkdtreeserializationcode(ae_state *_state); -ae_int_t getmlpserializationcode(ae_state *_state); -ae_int_t getmlpeserializationcode(ae_state *_state); -ae_int_t getrbfserializationcode(ae_state *_state); -void tagsort(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - ae_state *_state); -void tagsortbuf(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - apbuffers* buf, - ae_state *_state); -void tagsortfasti(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Integer */ ae_vector* bufb, - ae_int_t n, - ae_state *_state); -void tagsortfastr(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* bufa, - /* Real */ ae_vector* bufb, - ae_int_t n, - ae_state *_state); -void tagsortfast(/* Real */ ae_vector* a, - /* Real */ ae_vector* bufa, - ae_int_t n, - ae_state *_state); -void tagsortmiddleir(/* Integer */ ae_vector* a, - /* Real */ ae_vector* b, - ae_int_t offset, - ae_int_t n, - ae_state *_state); -void tagheappushi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t* n, - double va, - ae_int_t vb, - ae_state *_state); -void tagheapreplacetopi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t n, - double va, - ae_int_t vb, - ae_state *_state); -void tagheappopi(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t* n, - ae_state *_state); -ae_int_t lowerbound(/* Real */ ae_vector* a, - ae_int_t n, - double t, - ae_state *_state); -ae_int_t upperbound(/* Real */ ae_vector* a, - ae_int_t n, - double t, - ae_state *_state); -void rankx(/* Real */ ae_vector* x, - ae_int_t n, - ae_bool iscentered, - apbuffers* buf, - ae_state *_state); -ae_bool cmatrixrank1f(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_vector* u, - ae_int_t iu, - /* Complex */ ae_vector* v, - ae_int_t iv, - ae_state *_state); -ae_bool rmatrixrank1f(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_vector* u, - ae_int_t iu, - /* Real */ ae_vector* v, - ae_int_t iv, - ae_state *_state); -ae_bool cmatrixmvf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Complex */ ae_vector* x, - ae_int_t ix, - /* Complex */ ae_vector* y, - ae_int_t iy, - ae_state *_state); -ae_bool rmatrixmvf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Real */ ae_vector* x, - ae_int_t ix, - /* Real */ ae_vector* y, - ae_int_t iy, - ae_state *_state); -ae_bool cmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -ae_bool cmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -ae_bool rmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -ae_bool rmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -ae_bool cmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -ae_bool rmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -ae_bool rmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -ae_bool cmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void cmatrixgemmk(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void rmatrixgemmk(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void rmatrixgemmk44v00(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void rmatrixgemmk44v01(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void rmatrixgemmk44v10(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void rmatrixgemmk44v11(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -ae_bool rmatrixsyrkmkl(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -ae_bool rmatrixgemmmkl(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -double vectornorm2(/* Real */ ae_vector* x, - ae_int_t i1, - ae_int_t i2, - ae_state *_state); -ae_int_t vectoridxabsmax(/* Real */ ae_vector* x, - ae_int_t i1, - ae_int_t i2, - ae_state *_state); -ae_int_t columnidxabsmax(/* Real */ ae_matrix* x, - ae_int_t i1, - ae_int_t i2, - ae_int_t j, - ae_state *_state); -ae_int_t rowidxabsmax(/* Real */ ae_matrix* x, - ae_int_t j1, - ae_int_t j2, - ae_int_t i, - ae_state *_state); -double upperhessenberg1norm(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - /* Real */ ae_vector* work, - ae_state *_state); -void copymatrix(/* Real */ ae_matrix* a, - ae_int_t is1, - ae_int_t is2, - ae_int_t js1, - ae_int_t js2, - /* Real */ ae_matrix* b, - ae_int_t id1, - ae_int_t id2, - ae_int_t jd1, - ae_int_t jd2, - ae_state *_state); -void inplacetranspose(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - /* Real */ ae_vector* work, - ae_state *_state); -void copyandtranspose(/* Real */ ae_matrix* a, - ae_int_t is1, - ae_int_t is2, - ae_int_t js1, - ae_int_t js2, - /* Real */ ae_matrix* b, - ae_int_t id1, - ae_int_t id2, - ae_int_t jd1, - ae_int_t jd2, - ae_state *_state); -void matrixvectormultiply(/* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t i2, - ae_int_t j1, - ae_int_t j2, - ae_bool trans, - /* Real */ ae_vector* x, - ae_int_t ix1, - ae_int_t ix2, - double alpha, - /* Real */ ae_vector* y, - ae_int_t iy1, - ae_int_t iy2, - double beta, - ae_state *_state); -double pythag2(double x, double y, ae_state *_state); -void matrixmatrixmultiply(/* Real */ ae_matrix* a, - ae_int_t ai1, - ae_int_t ai2, - ae_int_t aj1, - ae_int_t aj2, - ae_bool transa, - /* Real */ ae_matrix* b, - ae_int_t bi1, - ae_int_t bi2, - ae_int_t bj1, - ae_int_t bj2, - ae_bool transb, - double alpha, - /* Real */ ae_matrix* c, - ae_int_t ci1, - ae_int_t ci2, - ae_int_t cj1, - ae_int_t cj2, - double beta, - /* Real */ ae_vector* work, - ae_state *_state); -void hermitianmatrixvectormultiply(/* Complex */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Complex */ ae_vector* x, - ae_complex alpha, - /* Complex */ ae_vector* y, - ae_state *_state); -void hermitianrank2update(/* Complex */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Complex */ ae_vector* x, - /* Complex */ ae_vector* y, - /* Complex */ ae_vector* t, - ae_complex alpha, - ae_state *_state); -void generatereflection(/* Real */ ae_vector* x, - ae_int_t n, - double* tau, - ae_state *_state); -void applyreflectionfromtheleft(/* Real */ ae_matrix* c, - double tau, - /* Real */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* work, - ae_state *_state); -void applyreflectionfromtheright(/* Real */ ae_matrix* c, - double tau, - /* Real */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* work, - ae_state *_state); -void complexgeneratereflection(/* Complex */ ae_vector* x, - ae_int_t n, - ae_complex* tau, - ae_state *_state); -void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, - ae_complex tau, - /* Complex */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Complex */ ae_vector* work, - ae_state *_state); -void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, - ae_complex tau, - /* Complex */ ae_vector* v, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Complex */ ae_vector* work, - ae_state *_state); -void symmetricmatrixvectormultiply(/* Real */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* x, - double alpha, - /* Real */ ae_vector* y, - ae_state *_state); -void symmetricrank2update(/* Real */ ae_matrix* a, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* t, - double alpha, - ae_state *_state); -void applyrotationsfromtheleft(ae_bool isforward, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* c, - /* Real */ ae_vector* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* work, - ae_state *_state); -void applyrotationsfromtheright(ae_bool isforward, - ae_int_t m1, - ae_int_t m2, - ae_int_t n1, - ae_int_t n2, - /* Real */ ae_vector* c, - /* Real */ ae_vector* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* work, - ae_state *_state); -void generaterotation(double f, - double g, - double* cs, - double* sn, - double* r, - ae_state *_state); -ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, - ae_int_t n, - /* Real */ ae_matrix* s, - ae_state *_state); -void internalschurdecomposition(/* Real */ ae_matrix* h, - ae_int_t n, - ae_int_t tneeded, - ae_int_t zneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* z, - ae_int_t* info, - ae_state *_state); -void rmatrixtrsafesolve(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* x, - double* s, - ae_bool isupper, - ae_bool istrans, - ae_bool isunit, - ae_state *_state); -void safesolvetriangular(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* x, - double* s, - ae_bool isupper, - ae_bool istrans, - ae_bool isunit, - ae_bool normin, - /* Real */ ae_vector* cnorm, - ae_state *_state); -ae_bool rmatrixscaledtrsafesolve(/* Real */ ae_matrix* a, - double sa, - ae_int_t n, - /* Real */ ae_vector* x, - ae_bool isupper, - ae_int_t trans, - ae_bool isunit, - double maxgrowth, - ae_state *_state); -ae_bool cmatrixscaledtrsafesolve(/* Complex */ ae_matrix* a, - double sa, - ae_int_t n, - /* Complex */ ae_vector* x, - ae_bool isupper, - ae_int_t trans, - ae_bool isunit, - double maxgrowth, - ae_state *_state); -void hpcpreparechunkedgradient(/* Real */ ae_vector* weights, - ae_int_t wcount, - ae_int_t ntotal, - ae_int_t nin, - ae_int_t nout, - mlpbuffers* buf, - ae_state *_state); -void hpcfinalizechunkedgradient(mlpbuffers* buf, - /* Real */ ae_vector* grad, - ae_state *_state); -ae_bool hpcchunkedgradient(/* Real */ ae_vector* weights, - /* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - double* e, - ae_bool naturalerrorfunc, - ae_state *_state); -ae_bool hpcchunkedprocess(/* Real */ ae_vector* weights, - /* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - ae_state *_state); -ae_bool _mlpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpbuffers_clear(void* _p); -void _mlpbuffers_destroy(void* _p); -void xdot(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* temp, - double* r, - double* rerr, - ae_state *_state); -void xcdot(/* Complex */ ae_vector* a, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* temp, - ae_complex* r, - double* rerr, - ae_state *_state); -void linminnormalized(/* Real */ ae_vector* d, - double* stp, - ae_int_t n, - ae_state *_state); -void mcsrch(ae_int_t n, - /* Real */ ae_vector* x, - double* f, - /* Real */ ae_vector* g, - /* Real */ ae_vector* s, - double* stp, - double stpmax, - double gtol, - ae_int_t* info, - ae_int_t* nfev, - /* Real */ ae_vector* wa, - linminstate* state, - ae_int_t* stage, - ae_state *_state); -void armijocreate(ae_int_t n, - /* Real */ ae_vector* x, - double f, - /* Real */ ae_vector* s, - double stp, - double stpmax, - ae_int_t fmax, - armijostate* state, - ae_state *_state); -ae_bool armijoiteration(armijostate* state, ae_state *_state); -void armijoresults(armijostate* state, - ae_int_t* info, - double* stp, - double* f, - ae_state *_state); -ae_bool _linminstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _linminstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _linminstate_clear(void* _p); -void _linminstate_destroy(void* _p); -ae_bool _armijostate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _armijostate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _armijostate_clear(void* _p); -void _armijostate_destroy(void* _p); -void findprimitiverootandinverse(ae_int_t n, - ae_int_t* proot, - ae_int_t* invproot, - ae_state *_state); -void ftcomplexfftplan(ae_int_t n, - ae_int_t k, - fasttransformplan* plan, - ae_state *_state); -void ftapplyplan(fasttransformplan* plan, - /* Real */ ae_vector* a, - ae_int_t offsa, - ae_int_t repcnt, - ae_state *_state); -void ftbasefactorize(ae_int_t n, - ae_int_t tasktype, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state); -ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state); -ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state); -ae_int_t ftbasefindsmootheven(ae_int_t n, ae_state *_state); -double ftbasegetflopestimate(ae_int_t n, ae_state *_state); -ae_bool _fasttransformplan_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _fasttransformplan_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _fasttransformplan_clear(void* _p); -void _fasttransformplan_destroy(void* _p); -double nulog1p(double x, ae_state *_state); -double nuexpm1(double x, ae_state *_state); -double nucosm1(double x, ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _alglibinternal_pkg_h +#define _alglibinternal_pkg_h +#include "ap.h" + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_APSERV) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector ba0; + ae_vector ia0; + ae_vector ia1; + ae_vector ia2; + ae_vector ia3; + ae_vector ra0; + ae_vector ra1; + ae_vector ra2; + ae_vector ra3; + ae_matrix rm0; + ae_matrix rm1; +} apbuffers; +typedef struct +{ + ae_bool val; +} sboolean; +typedef struct +{ + ae_vector val; +} sbooleanarray; +typedef struct +{ + ae_int_t val; +} sinteger; +typedef struct +{ + ae_vector val; +} sintegerarray; +typedef struct +{ + double val; +} sreal; +typedef struct +{ + ae_vector val; +} srealarray; +typedef struct +{ + ae_complex val; +} scomplex; +typedef struct +{ + ae_vector val; +} scomplexarray; +typedef struct +{ + double rsum; + double rcnt; + double prior; +} savgcounter; +typedef struct +{ + ae_int_t cnt; + ae_vector elems; + double prior; +} squantilecounter; +typedef struct +{ + ae_int_t ttotal; + ae_int_t tcurrent; + ae_bool isrunning; +} stimer; +#endif +#if defined(AE_COMPILE_ABLASF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_HBLAS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CREFLECTIONS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SBLAS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_ABLASPBL) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SCODES) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_TSORT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BLAS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_ROTATIONS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BASICSTATOPS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_APSTRUCT) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t nstored; + ae_vector items; + ae_vector locationof; + ae_int_t iteridx; +} niset; +typedef struct +{ + ae_int_t storagemode; + ae_int_t k; + ae_int_t n; + ae_vector flagarray; + ae_vector vbegin; + ae_vector vallocated; + ae_vector vcnt; + ae_vector data; + ae_int_t dataused; + ae_int_t iterrow; + ae_int_t iteridx; +} kniset; +#endif +#if defined(AE_COMPILE_TRLINSOLVE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SAFESOLVE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_XBLAS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_LINMIN) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool brackt; + ae_bool stage1; + ae_int_t infoc; + double dg; + double dgm; + double dginit; + double dgtest; + double dgx; + double dgxm; + double dgy; + double dgym; + double finit; + double ftest1; + double fm; + double fx; + double fxm; + double fy; + double fym; + double stx; + double sty; + double stmin; + double stmax; + double width; + double width1; + double xtrapf; +} linminstate; +typedef struct +{ + ae_bool needf; + ae_vector x; + double f; + ae_int_t n; + ae_vector xbase; + ae_vector s; + double stplen; + double fcur; + double stpmax; + ae_int_t fmax; + ae_int_t nfev; + ae_int_t info; + rcommstate rstate; +} armijostate; +#endif +#if defined(AE_COMPILE_NEARUNITYUNIT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_NTHEORY) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_FTBASE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_matrix entries; + ae_vector buffer; + ae_vector precr; + ae_vector preci; + ae_shared_pool bluesteinpool; +} fasttransformplan; +#endif +#if defined(AE_COMPILE_HPCCORES) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t chunksize; + ae_int_t ntotal; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_vector batch4buf; + ae_vector hpcbuf; + ae_matrix xy; + ae_matrix xy2; + ae_vector xyrow; + ae_vector x; + ae_vector y; + ae_vector desiredy; + double e; + ae_vector g; + ae_vector tmp0; +} mlpbuffers; +#endif +#if defined(AE_COMPILE_ALGLIBBASICS) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_APSERV) || !defined(AE_PARTIAL_BUILD) +void seterrorflagdiff(ae_bool* flag, + double val, + double refval, + double tol, + double s, + ae_state *_state); +ae_bool alwaysfalse(ae_state *_state); +void touchboolean(ae_bool* a, ae_state *_state); +void touchint(ae_int_t* a, ae_state *_state); +void touchreal(double* a, ae_state *_state); +double coalesce(double a, double b, ae_state *_state); +ae_int_t coalescei(ae_int_t a, ae_int_t b, ae_state *_state); +ae_int_t icoalesce(ae_int_t a, ae_int_t b, ae_state *_state); +double inttoreal(ae_int_t a, ae_state *_state); +double logbase2(double x, ae_state *_state); +ae_bool approxequal(double a, double b, double tol, ae_state *_state); +ae_bool approxequalrel(double a, double b, double tol, ae_state *_state); +void taskgenint1d(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void taskgenint1dequidist(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void taskgenint1dcheb1(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void taskgenint1dcheb2(double a, + double b, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool aredistinct(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +ae_bool aresameboolean(ae_bool v1, ae_bool v2, ae_state *_state); +void setlengthzero(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void bvectorsetlengthatleast(/* Boolean */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void ivectorsetlengthatleast(/* Integer */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void rvectorsetlengthatleast(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void rmatrixsetlengthatleast(/* Real */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void bmatrixsetlengthatleast(/* Boolean */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void bvectorgrowto(/* Boolean */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void ivectorgrowto(/* Integer */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void rmatrixgrowrowsto(/* Real */ ae_matrix* a, + ae_int_t n, + ae_int_t mincols, + ae_state *_state); +void rmatrixgrowcolsto(/* Real */ ae_matrix* a, + ae_int_t n, + ae_int_t minrows, + ae_state *_state); +void rvectorgrowto(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void ivectorresize(/* Integer */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void rvectorresize(/* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void rmatrixresize(/* Real */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void imatrixresize(/* Integer */ ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void ivectorappend(/* Integer */ ae_vector* x, + ae_int_t v, + ae_state *_state); +ae_bool isfiniteornanvector(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +ae_bool isfinitecvector(/* Complex */ const ae_vector* z, + ae_int_t n, + ae_state *_state); +ae_bool apservisfinitematrix(/* Real */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +ae_bool apservisfinitecmatrix(/* Complex */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +ae_bool isfinitecmatrix(/* Complex */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +ae_bool isfinitertrmatrix(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +ae_bool apservisfinitectrmatrix(/* Complex */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +ae_bool isfinitectrmatrix(/* Complex */ const ae_matrix* x, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +ae_bool apservisfiniteornanmatrix(/* Real */ const ae_matrix* x, + ae_int_t m, + ae_int_t n, + ae_state *_state); +double safepythag2(double x, double y, ae_state *_state); +double safepythag3(double x, double y, double z, ae_state *_state); +ae_int_t saferdiv(double x, double y, double* r, ae_state *_state); +double safeminposrv(double x, double y, double v, ae_state *_state); +void apperiodicmap(double* x, + double a, + double b, + double* k, + ae_state *_state); +double randomnormal(ae_state *_state); +void randomunit(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); +void swapi(ae_int_t* v0, ae_int_t* v1, ae_state *_state); +void swapr(double* v0, double* v1, ae_state *_state); +void swaprows(/* Real */ ae_matrix* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t ncols, + ae_state *_state); +void swapcols(/* Real */ ae_matrix* a, + ae_int_t j0, + ae_int_t j1, + ae_int_t nrows, + ae_state *_state); +void swapentries(/* Real */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t entrywidth, + ae_state *_state); +void swapentriesb(/* Boolean */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t entrywidth, + ae_state *_state); +void swapelements(/* Real */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +void swapelementsi(/* Integer */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +void swapelementsb(/* Boolean */ ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +double maxreal3(double v0, double v1, double v2, ae_state *_state); +void inc(ae_int_t* v, ae_state *_state); +void dec(ae_int_t* v, ae_state *_state); +void threadunsafeinc(ae_int_t* v, ae_state *_state); +void threadunsafeincby(ae_int_t* v, ae_int_t k, ae_state *_state); +void threadunsafeset(ae_int_t* v, ae_int_t x, ae_state *_state); +ae_int_t threadunsafeget(ae_int_t* v, ae_state *_state); +void rthreadunsafeincby(double* v, double x, ae_state *_state); +void rthreadunsafeset(double* v, double x, ae_state *_state); +double rthreadunsafeget(double* v, ae_state *_state); +ae_int_t weakatomicfetchadd(ae_int_t* v, ae_int_t n, ae_state *_state); +void weakatomicacquirelock(ae_int_t* v, + ae_int_t expected, + ae_int_t newval, + ae_state *_state); +void weakatomicacquirelockv(/* Integer */ ae_vector* v, + ae_int_t idx, + ae_int_t expected, + ae_int_t newval, + ae_state *_state); +void weakatomicwaitforv(/* Integer */ ae_vector* v, + ae_int_t idx, + ae_int_t expected, + ae_int_t waitfor, + ae_state *_state); +void countdown(ae_int_t* v, ae_state *_state); +double possign(double x, ae_state *_state); +ae_int_t ipossign(double x, ae_state *_state); +double rmul2(double v0, double v1, ae_state *_state); +double rmul3(double v0, double v1, double v2, ae_state *_state); +double rmul4(double v0, double v1, double v2, double v3, ae_state *_state); +ae_int_t idivup(ae_int_t a, ae_int_t b, ae_state *_state); +ae_int_t imin2(ae_int_t i0, ae_int_t i1, ae_state *_state); +ae_int_t imin3(ae_int_t i0, ae_int_t i1, ae_int_t i2, ae_state *_state); +ae_int_t imin4(ae_int_t i0, + ae_int_t i1, + ae_int_t i2, + ae_int_t i3, + ae_state *_state); +ae_int_t imax2(ae_int_t i0, ae_int_t i1, ae_state *_state); +ae_int_t imax3(ae_int_t i0, ae_int_t i1, ae_int_t i2, ae_state *_state); +ae_int_t imax4(ae_int_t i0, + ae_int_t i1, + ae_int_t i2, + ae_int_t i3, + ae_state *_state); +double rmax3(double r0, double r1, double r2, ae_state *_state); +double rmin3(double r0, double r1, double r2, ae_state *_state); +double rmaxabs2(double r0, double r1, ae_state *_state); +double rmaxabs3(double r0, double r1, double r2, ae_state *_state); +double boundval(double x, double b1, double b2, ae_state *_state); +ae_int_t iboundval(ae_int_t x, ae_int_t b1, ae_int_t b2, ae_state *_state); +double rboundval(double x, double b1, double b2, ae_state *_state); +ae_bool bcase2(ae_bool cond, ae_bool v0, ae_bool v1, ae_state *_state); +double rcase2(ae_bool cond, double v0, double v1, ae_state *_state); +ae_int_t countnz1(/* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +ae_int_t countnz2(/* Real */ const ae_matrix* v, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void alloccomplex(ae_serializer* s, ae_complex v, ae_state *_state); +void serializecomplex(ae_serializer* s, ae_complex v, ae_state *_state); +ae_complex unserializecomplex(ae_serializer* s, ae_state *_state); +void allocrealarray(ae_serializer* s, + /* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void allocbooleanarray(ae_serializer* s, + /* Boolean */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void serializerealarray(ae_serializer* s, + /* Real */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void serializebooleanarray(ae_serializer* s, + /* Boolean */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void unserializerealarray(ae_serializer* s, + /* Real */ ae_vector* v, + ae_state *_state); +void unserializebooleanarray(ae_serializer* s, + /* Boolean */ ae_vector* v, + ae_state *_state); +void allocintegerarray(ae_serializer* s, + /* Integer */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void serializeintegerarray(ae_serializer* s, + /* Integer */ const ae_vector* v, + ae_int_t n, + ae_state *_state); +void unserializeintegerarray(ae_serializer* s, + /* Integer */ ae_vector* v, + ae_state *_state); +void allocrealmatrix(ae_serializer* s, + /* Real */ const ae_matrix* v, + ae_int_t n0, + ae_int_t n1, + ae_state *_state); +void serializerealmatrix(ae_serializer* s, + /* Real */ const ae_matrix* v, + ae_int_t n0, + ae_int_t n1, + ae_state *_state); +void unserializerealmatrix(ae_serializer* s, + /* Real */ ae_matrix* v, + ae_state *_state); +void copybooleanarray(/* Boolean */ const ae_vector* src, + /* Boolean */ ae_vector* dst, + ae_state *_state); +void copyintegerarray(/* Integer */ const ae_vector* src, + /* Integer */ ae_vector* dst, + ae_state *_state); +void copyrealarray(/* Real */ const ae_vector* src, + /* Real */ ae_vector* dst, + ae_state *_state); +void copyrealmatrix(/* Real */ const ae_matrix* src, + /* Real */ ae_matrix* dst, + ae_state *_state); +void unsetintegerarray(/* Integer */ ae_vector* a, ae_state *_state); +void unsetrealarray(/* Real */ ae_vector* a, ae_state *_state); +void unsetrealmatrix(/* Real */ ae_matrix* a, ae_state *_state); +void tiledsplit(ae_int_t tasksize, + ae_int_t tilesize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state); +ae_int_t ibinarysearchexisting(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state); +ae_bool ilinearsearchispresent(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state); +ae_bool ibinarysearchispresent(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state); +ae_int_t recsearch(/* Integer */ const ae_vector* a, + ae_int_t nrec, + ae_int_t nheader, + ae_int_t i0, + ae_int_t i1, + /* Integer */ const ae_vector* b, + ae_state *_state); +void splitlengtheven(ae_int_t tasksize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state); +ae_int_t chunkscount(ae_int_t tasksize, + ae_int_t chunksize, + ae_state *_state); +double sparselevel2density(ae_state *_state); +ae_int_t matrixtilesizea(ae_state *_state); +ae_int_t matrixtilesizeb(ae_state *_state); +double smpactivationlevel(ae_state *_state); +double adaptiveparallelismtimerequired(ae_state *_state); +double adaptiveparallelismcountrequired(ae_state *_state); +double workerstartthresholdms(ae_state *_state); +double spawnlevel(ae_state *_state); +void splitlength(ae_int_t tasksize, + ae_int_t chunksize, + ae_int_t* task0, + ae_int_t* task1, + ae_state *_state); +void tracevectorautoprec(/* Real */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +void tracerowautoprec(/* Real */ const ae_matrix* a, + ae_int_t i, + ae_int_t j0, + ae_int_t j1, + ae_state *_state); +void tracevectorunscaledunshiftedautoprec(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* scl, + ae_bool applyscl, + /* Real */ const ae_vector* sft, + ae_bool applysft, + ae_state *_state); +void tracerownrm1autoprec(/* Real */ const ae_matrix* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, + ae_state *_state); +void tracevectore3(/* Real */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +void tracevectore6(/* Real */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_state *_state); +void tracevectore615(/* Real */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_bool usee15, + ae_state *_state); +void tracerownrm1e6(/* Real */ const ae_matrix* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, + ae_state *_state); +void tracespaces(ae_int_t cnt, ae_state *_state); +void traceangles(ae_int_t cnt, ae_state *_state); +double minspeedup(ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +ae_int_t maxconcurrency(ae_state *_state); +#endif +void savgcounterinit(savgcounter* c, double priorvalue, ae_state *_state); +void savgcounterenqueue(savgcounter* c, double v, ae_state *_state); +double savgcounterget(const savgcounter* c, ae_state *_state); +void squantilecounterinit(squantilecounter* c, + double priorvalue, + ae_state *_state); +void squantilecounterenqueue(squantilecounter* c, + double v, + ae_state *_state); +double squantilecounterget(squantilecounter* c, + double q, + ae_state *_state); +void stimerinit(stimer* t, ae_state *_state); +void stimerstart(stimer* t, ae_state *_state); +void stimerstop(stimer* t, ae_state *_state); +void stimerstartcond(stimer* t, ae_bool cond, ae_state *_state); +void stimerstopcond(stimer* t, ae_bool cond, ae_state *_state); +double stimergetms(const stimer* t, ae_state *_state); +ae_int_t stimergetmsint(const stimer* t, ae_state *_state); +double stimergetmsrunning(const stimer* t, ae_state *_state); +double stimergetmsrunningandrestart(stimer* t, ae_state *_state); +void _apbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _apbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _apbuffers_clear(void* _p); +void _apbuffers_destroy(void* _p); +void _sboolean_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sboolean_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sboolean_clear(void* _p); +void _sboolean_destroy(void* _p); +void _sbooleanarray_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sbooleanarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sbooleanarray_clear(void* _p); +void _sbooleanarray_destroy(void* _p); +void _sinteger_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sinteger_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sinteger_clear(void* _p); +void _sinteger_destroy(void* _p); +void _sintegerarray_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sintegerarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sintegerarray_clear(void* _p); +void _sintegerarray_destroy(void* _p); +void _sreal_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sreal_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sreal_clear(void* _p); +void _sreal_destroy(void* _p); +void _srealarray_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _srealarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _srealarray_clear(void* _p); +void _srealarray_destroy(void* _p); +void _scomplex_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _scomplex_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _scomplex_clear(void* _p); +void _scomplex_destroy(void* _p); +void _scomplexarray_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _scomplexarray_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _scomplexarray_clear(void* _p); +void _scomplexarray_destroy(void* _p); +void _savgcounter_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _savgcounter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _savgcounter_clear(void* _p); +void _savgcounter_destroy(void* _p); +void _squantilecounter_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _squantilecounter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _squantilecounter_clear(void* _p); +void _squantilecounter_destroy(void* _p); +void _stimer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _stimer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _stimer_clear(void* _p); +void _stimer_destroy(void* _p); +#endif +#if defined(AE_COMPILE_ABLASF) || !defined(AE_PARTIAL_BUILD) +#ifdef ALGLIB_NO_FAST_KERNELS +double rdotv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_state *_state); +#endif +double rdotscl1v(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* s, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +double rdotvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_matrix* a, + ae_int_t i, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +double rdotrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +double rdotv2(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +#endif +double rdotscl1v2(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* s, + ae_state *_state); +double rsclnrminf(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* s, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void raddv(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rnegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopymuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopynegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void raddvx(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + ae_int_t offsy, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +#endif +void raddvc(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t colidx, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void raddvr(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemulv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemulvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemulrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergedivv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergedivvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergedivrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemaxv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemaxvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergemaxrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergeminv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergeminvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmergeminrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void raddrv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridx, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void raddrr(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridxsrc, + /* Real */ ae_matrix* x, + ae_int_t ridxdst, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmulv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmulr(ae_int_t n, + double v, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rsqrtv(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rsqrtr(ae_int_t n, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rmulvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +#endif +double rminv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +double rmaxv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +double rmaxabsv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +double rmaxr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +double rmaxabsr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rsetvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void bsetv(ae_int_t n, + ae_bool v, + /* Boolean */ ae_vector* x, + ae_state *_state); +#endif +void csetv(ae_int_t n, + ae_complex v, + /* Complex */ ae_vector* x, + ae_state *_state); +void isetm(ae_int_t m, + ae_int_t n, + ae_int_t v, + /* Integer */ ae_matrix* a, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rsetm(ae_int_t m, + ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_state *_state); +#endif +void isetallocm(ae_int_t m, + ae_int_t n, + ae_int_t v, + /* Integer */ ae_matrix* a, + ae_state *_state); +void rsetallocm(ae_int_t m, + ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_state *_state); +void callocv(ae_int_t n, /* Complex */ ae_vector* x, ae_state *_state); +void ballocv(ae_int_t n, /* Boolean */ ae_vector* x, ae_state *_state); +void rallocm(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_state *_state); +void bsetallocv(ae_int_t n, + ae_bool v, + /* Boolean */ ae_vector* x, + ae_state *_state); +void csetallocv(ae_int_t n, + ae_complex v, + /* Complex */ ae_vector* x, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rsetr(ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state); +#endif +void rsetc(ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_int_t j, + ae_state *_state); +void rcopym(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_state *_state); +void rcopyallocm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_state *_state); +void bcopyallocv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state); +void rgrowrowsfixedcolsm(ae_int_t m, + ae_int_t colscnt, + /* Real */ ae_matrix* a, + ae_state *_state); +void rappendrowfixedcolsm(ae_int_t n, + ae_int_t colscnt, + /* Real */ ae_matrix* a, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopymulv(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopymulvr(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t ridx, + ae_state *_state); +#endif +void rcopymulvc(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t cidx, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopyvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopyrv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopyrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_matrix* b, + ae_int_t k, + ae_state *_state); +#endif +void rcopyvc(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t j, + ae_state *_state); +void rcopycv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t j, + /* Real */ ae_vector* x, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t opa, + /* Real */ const ae_vector* x, + double beta, + /* Real */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rgemvx(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rger(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + /* Real */ ae_matrix* a, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rtrsvx(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state); +#endif +ae_bool rmatrixgerf(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double ralpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool cmatrixrank1f(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool rmatrixrank1f(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool cmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool cmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool rmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool rmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool cmatrixherkf(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool rmatrixsyrkf(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool cmatrixgemmf(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void cmatrixgemmk(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void rmatrixgemmk(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void rmatrixgemmk44v00(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void rmatrixgemmk44v01(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void rmatrixgemmk44v10(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +void rmatrixgemmk44v11(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +#endif +#if defined(AE_COMPILE_HBLAS) || !defined(AE_PARTIAL_BUILD) +void hermitianmatrixvectormultiply(/* Complex */ const ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Complex */ const ae_vector* x, + ae_complex alpha, + /* Complex */ ae_vector* y, + ae_state *_state); +void hermitianrank2update(/* Complex */ ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Complex */ const ae_vector* x, + /* Complex */ const ae_vector* y, + /* Complex */ ae_vector* t, + ae_complex alpha, + ae_state *_state); +#endif +#if defined(AE_COMPILE_CREFLECTIONS) || !defined(AE_PARTIAL_BUILD) +void complexgeneratereflection(/* Complex */ ae_vector* x, + ae_int_t n, + ae_complex* tau, + ae_state *_state); +void complexapplyreflectionfromtheleft(/* Complex */ ae_matrix* c, + ae_complex tau, + /* Complex */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Complex */ ae_vector* work, + ae_state *_state); +void complexapplyreflectionfromtheright(/* Complex */ ae_matrix* c, + ae_complex tau, + /* Complex */ ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Complex */ ae_vector* work, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SBLAS) || !defined(AE_PARTIAL_BUILD) +void symmetricmatrixvectormultiply(/* Real */ const ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ const ae_vector* x, + double alpha, + /* Real */ ae_vector* y, + ae_state *_state); +void symmetricrank2update(/* Real */ ae_matrix* a, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* t, + double alpha, + ae_state *_state); +#endif +#if defined(AE_COMPILE_ABLASPBL) || !defined(AE_PARTIAL_BUILD) +ae_bool rmatrixgerpbl(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double alpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool cmatrixrank1pbl(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool rmatrixrank1pbl(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +ae_bool cmatrixmvpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Complex */ const ae_vector* x, + ae_int_t ix, + /* Complex */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +ae_bool rmatrixmvpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +ae_bool rmatrixgemvpbl(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +ae_bool rmatrixtrsvpbl(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state); +ae_bool rmatrixsyrkpbl(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool cmatrixherkpbl(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool rmatrixgemmpbl(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool rmatrixsymvpbl(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +ae_bool cmatrixgemmpbl(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool cmatrixlefttrsmpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool cmatrixrighttrsmpbl(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool rmatrixlefttrsmpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool rmatrixrighttrsmpbl(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool spdmatrixcholeskypbl(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool* cholresult, + ae_state *_state); +ae_bool rmatrixplupbl(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +ae_bool rmatrixbdpbl(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + /* Real */ ae_vector* tauq, + /* Real */ ae_vector* taup, + ae_state *_state); +ae_bool rmatrixbdmultiplybypbl(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + /* Real */ const ae_vector* taup, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool byq, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state); +ae_bool rmatrixhessenbergpbl(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state); +ae_bool rmatrixhessenbergunpackqpbl(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state); +ae_bool smatrixtdpbl(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state); +ae_bool smatrixtdunpackqpbl(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state); +ae_bool hmatrixtdpbl(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state); +ae_bool hmatrixtdunpackqpbl(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* tau, + /* Complex */ ae_matrix* q, + ae_state *_state); +ae_bool rmatrixbdsvdpbl(/* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_bool* svdresult, + ae_state *_state); +ae_bool rmatrixinternalschurdecompositionpbl(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state); +ae_bool rmatrixinternaltrevcpbl(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state); +ae_bool smatrixtdevdpbl(/* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_bool* evdresult, + ae_state *_state); +ae_bool sparsegemvcrspbl(ae_int_t opa, + ae_int_t arows, + ae_int_t acols, + double alpha, + /* Real */ const ae_vector* vals, + /* Integer */ const ae_vector* cidx, + /* Integer */ const ae_vector* ridx, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SCODES) || !defined(AE_PARTIAL_BUILD) +ae_int_t getrdfserializationcode(ae_state *_state); +ae_int_t getkdtreeserializationcode(ae_state *_state); +ae_int_t getmlpserializationcode(ae_state *_state); +ae_int_t getmlpeserializationcode(ae_state *_state); +ae_int_t getrbfserializationcode(ae_state *_state); +ae_int_t getspline2dserializationcode(ae_state *_state); +ae_int_t getidwserializationcode(ae_state *_state); +ae_int_t getsparsematrixserializationcode(ae_state *_state); +ae_int_t getspline2dwithmissingnodesserializationcode(ae_state *_state); +ae_int_t getspline1dserializationcode(ae_state *_state); +ae_int_t getknnserializationcode(ae_state *_state); +ae_int_t getlptestserializationcode(ae_state *_state); +#endif +#if defined(AE_COMPILE_TSORT) || !defined(AE_PARTIAL_BUILD) +void tagsort(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + ae_state *_state); +void tagsortbuf(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + apbuffers* buf, + ae_state *_state); +void tagsortfasti(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Integer */ ae_vector* bufb, + ae_int_t n, + ae_state *_state); +void tagsortfastr(/* Real */ ae_vector* a, + /* Real */ ae_vector* b, + /* Real */ ae_vector* bufa, + /* Real */ ae_vector* bufb, + ae_int_t n, + ae_state *_state); +void tagsortfast(/* Real */ ae_vector* a, + /* Real */ ae_vector* bufa, + ae_int_t n, + ae_state *_state); +void tagsortmiddleri(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +void tagsortmiddleii(/* Integer */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +void tagsortmiddlei(/* Integer */ ae_vector* a, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +void sortmiddlei(/* Integer */ ae_vector* a, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +void tagheappushi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t* n, + double va, + ae_int_t vb, + ae_state *_state); +void tagheapreplacetopi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t n, + double va, + ae_int_t vb, + ae_state *_state); +void tagheappopi(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t* n, + ae_state *_state); +ae_int_t lowerbound(/* Real */ const ae_vector* a, + ae_int_t n, + double t, + ae_state *_state); +ae_int_t upperbound(/* Real */ const ae_vector* a, + ae_int_t n, + double t, + ae_state *_state); +#endif +#if defined(AE_COMPILE_BLAS) || !defined(AE_PARTIAL_BUILD) +double vectornorm2(/* Real */ const ae_vector* x, + ae_int_t i1, + ae_int_t i2, + ae_state *_state); +ae_int_t vectoridxabsmax(/* Real */ const ae_vector* x, + ae_int_t i1, + ae_int_t i2, + ae_state *_state); +ae_int_t columnidxabsmax(/* Real */ const ae_matrix* x, + ae_int_t i1, + ae_int_t i2, + ae_int_t j, + ae_state *_state); +ae_int_t rowidxabsmax(/* Real */ const ae_matrix* x, + ae_int_t j1, + ae_int_t j2, + ae_int_t i, + ae_state *_state); +double upperhessenberg1norm(/* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + /* Real */ ae_vector* work, + ae_state *_state); +void copymatrix(/* Real */ const ae_matrix* a, + ae_int_t is1, + ae_int_t is2, + ae_int_t js1, + ae_int_t js2, + /* Real */ ae_matrix* b, + ae_int_t id1, + ae_int_t id2, + ae_int_t jd1, + ae_int_t jd2, + ae_state *_state); +void inplacetranspose(/* Real */ ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + /* Real */ ae_vector* work, + ae_state *_state); +void copyandtranspose(/* Real */ const ae_matrix* a, + ae_int_t is1, + ae_int_t is2, + ae_int_t js1, + ae_int_t js2, + /* Real */ ae_matrix* b, + ae_int_t id1, + ae_int_t id2, + ae_int_t jd1, + ae_int_t jd2, + ae_state *_state); +void matrixvectormultiply(/* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t i2, + ae_int_t j1, + ae_int_t j2, + ae_bool trans, + /* Real */ const ae_vector* x, + ae_int_t ix1, + ae_int_t ix2, + double alpha, + /* Real */ ae_vector* y, + ae_int_t iy1, + ae_int_t iy2, + double beta, + ae_state *_state); +double pythag2(double x, double y, ae_state *_state); +void matrixmatrixmultiply(/* Real */ const ae_matrix* a, + ae_int_t ai1, + ae_int_t ai2, + ae_int_t aj1, + ae_int_t aj2, + ae_bool transa, + /* Real */ const ae_matrix* b, + ae_int_t bi1, + ae_int_t bi2, + ae_int_t bj1, + ae_int_t bj2, + ae_bool transb, + double alpha, + /* Real */ ae_matrix* c, + ae_int_t ci1, + ae_int_t ci2, + ae_int_t cj1, + ae_int_t cj2, + double beta, + /* Real */ ae_vector* work, + ae_state *_state); +#endif +#if defined(AE_COMPILE_ROTATIONS) || !defined(AE_PARTIAL_BUILD) +void applyrotationsfromtheleft(ae_bool isforward, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* work, + ae_state *_state); +void applyrotationsfromtheright(ae_bool isforward, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* work, + ae_state *_state); +void generaterotation(double f, + double g, + double* cs, + double* sn, + double* r, + ae_state *_state); +#endif +#if defined(AE_COMPILE_BASICSTATOPS) || !defined(AE_PARTIAL_BUILD) +void rankx(/* Real */ ae_vector* x, + ae_int_t n, + ae_bool iscentered, + apbuffers* buf, + ae_state *_state); +void rankxuntied(/* Real */ ae_vector* x, + ae_int_t n, + apbuffers* buf, + ae_state *_state); +#endif +#if defined(AE_COMPILE_APSTRUCT) || !defined(AE_PARTIAL_BUILD) +void nisinitemptyslow(ae_int_t n, niset* sa, ae_state *_state); +void niscopy(const niset* ssrc, niset* sdst, ae_state *_state); +void nisaddelement(niset* sa, ae_int_t k, ae_state *_state); +void nissubtract1(niset* sa, const niset* src, ae_state *_state); +void nisclear(niset* sa, ae_state *_state); +ae_int_t niscount(const niset* sa, ae_state *_state); +ae_bool nisequal(const niset* s0, const niset* s1, ae_state *_state); +void nisstartenumeration(niset* sa, ae_state *_state); +ae_bool nisenumerate(niset* sa, ae_int_t* i, ae_state *_state); +void kniscompressstorage(kniset* sa, ae_state *_state); +void knisreallocate(kniset* sa, + ae_int_t setidx, + ae_int_t newallocated, + ae_state *_state); +void knisinitunsorted(ae_int_t k, + ae_int_t n, + ae_int_t kprealloc, + kniset* sa, + ae_state *_state); +void knisdirectaccess(const kniset* sa, + ae_int_t k, + ae_int_t* idxbegin, + ae_int_t* idxend, + ae_state *_state); +ae_int_t knispoplast(kniset* sa, ae_int_t k, ae_state *_state); +void knisaddnewelement(kniset* sa, + ae_int_t i, + ae_int_t k, + ae_state *_state); +void knisclearkthnoreclaim(kniset* sa, ae_int_t k, ae_state *_state); +void knisclearkthreclaim(kniset* sa, ae_int_t k, ae_state *_state); +ae_int_t kniscountkth(const kniset* s0, ae_int_t k, ae_state *_state); +void _niset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _niset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _niset_clear(void* _p); +void _niset_destroy(void* _p); +void _kniset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _kniset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _kniset_clear(void* _p); +void _kniset_destroy(void* _p); +#endif +#if defined(AE_COMPILE_TRLINSOLVE) || !defined(AE_PARTIAL_BUILD) +void rmatrixtrsafesolve(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + double* s, + ae_bool isupper, + ae_bool istrans, + ae_bool isunit, + ae_state *_state); +void safesolvetriangular(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + double* s, + ae_bool isupper, + ae_bool istrans, + ae_bool isunit, + ae_bool normin, + /* Real */ ae_vector* cnorm, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SAFESOLVE) || !defined(AE_PARTIAL_BUILD) +ae_bool rmatrixscaledtrsafesolve(/* Real */ const ae_matrix* a, + double sa, + ae_int_t n, + /* Real */ ae_vector* x, + ae_bool isupper, + ae_int_t trans, + ae_bool isunit, + double maxgrowth, + ae_state *_state); +ae_bool cmatrixscaledtrsafesolve(/* Complex */ const ae_matrix* a, + double sa, + ae_int_t n, + /* Complex */ ae_vector* x, + ae_bool isupper, + ae_int_t trans, + ae_bool isunit, + double maxgrowth, + ae_state *_state); +#endif +#if defined(AE_COMPILE_XBLAS) || !defined(AE_PARTIAL_BUILD) +void xdot(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* temp, + double* r, + double* rerr, + ae_state *_state); +void xcdot(/* Complex */ const ae_vector* a, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* temp, + ae_complex* r, + double* rerr, + ae_state *_state); +#endif +#if defined(AE_COMPILE_LINMIN) || !defined(AE_PARTIAL_BUILD) +void linminnormalized(/* Real */ ae_vector* d, + double* stp, + ae_int_t n, + ae_state *_state); +void mcsrch(ae_int_t n, + /* Real */ ae_vector* x, + double* f, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* s, + double* stp, + double stpmax, + double gtol, + ae_int_t* info, + ae_int_t* nfev, + /* Real */ ae_vector* wa, + linminstate* state, + ae_int_t* stage, + ae_state *_state); +void armijocreate(ae_int_t n, + /* Real */ const ae_vector* x, + double f, + /* Real */ const ae_vector* s, + double stp, + double stpmax, + ae_int_t fmax, + armijostate* state, + ae_state *_state); +ae_bool armijoiteration(armijostate* state, ae_state *_state); +void armijoresults(armijostate* state, + ae_int_t* info, + double* stp, + double* f, + ae_state *_state); +void _linminstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _linminstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _linminstate_clear(void* _p); +void _linminstate_destroy(void* _p); +void _armijostate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _armijostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _armijostate_clear(void* _p); +void _armijostate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NEARUNITYUNIT) || !defined(AE_PARTIAL_BUILD) +double nulog1p(double x, ae_state *_state); +double nuexpm1(double x, ae_state *_state); +double nucosm1(double x, ae_state *_state); +#endif +#if defined(AE_COMPILE_NTHEORY) || !defined(AE_PARTIAL_BUILD) +void findprimitiverootandinverse(ae_int_t n, + ae_int_t* proot, + ae_int_t* invproot, + ae_state *_state); +#endif +#if defined(AE_COMPILE_FTBASE) || !defined(AE_PARTIAL_BUILD) +void ftcomplexfftplan(ae_int_t n, + ae_int_t k, + fasttransformplan* plan, + ae_state *_state); +void ftapplyplan(fasttransformplan* plan, + /* Real */ ae_vector* a, + ae_int_t offsa, + ae_int_t repcnt, + ae_state *_state); +void ftbasefactorize(ae_int_t n, + ae_int_t tasktype, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state); +ae_bool ftbaseissmooth(ae_int_t n, ae_state *_state); +ae_int_t ftbasefindsmooth(ae_int_t n, ae_state *_state); +ae_int_t ftbasefindsmootheven(ae_int_t n, ae_state *_state); +double ftbasegetflopestimate(ae_int_t n, ae_state *_state); +void _fasttransformplan_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _fasttransformplan_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _fasttransformplan_clear(void* _p); +void _fasttransformplan_destroy(void* _p); +#endif +#if defined(AE_COMPILE_HPCCORES) || !defined(AE_PARTIAL_BUILD) +void hpcpreparechunkedgradient(/* Real */ const ae_vector* weights, + ae_int_t wcount, + ae_int_t ntotal, + ae_int_t nin, + ae_int_t nout, + mlpbuffers* buf, + ae_state *_state); +void hpcfinalizechunkedgradient(const mlpbuffers* buf, + /* Real */ ae_vector* grad, + ae_state *_state); +ae_bool hpcchunkedgradient(/* Real */ const ae_vector* weights, + /* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + double* e, + ae_bool naturalerrorfunc, + ae_state *_state); +ae_bool hpcchunkedprocess(/* Real */ const ae_vector* weights, + /* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + ae_state *_state); +void _mlpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpbuffers_clear(void* _p); +void _mlpbuffers_destroy(void* _p); +#endif +#if defined(AE_COMPILE_ALGLIBBASICS) || !defined(AE_PARTIAL_BUILD) +#endif + +} +#endif + diff --git a/core/alglib/alglibmisc.cpp b/core/alglib/alglibmisc.cpp index cc4e0956..f97edff4 100644 --- a/core/alglib/alglibmisc.cpp +++ b/core/alglib/alglibmisc.cpp @@ -1,3611 +1,9110 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "alglibmisc.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Portable high quality random number generator state. -Initialized with HQRNDRandomize() or HQRNDSeed(). - -Fields: - S1, S2 - seed values - V - precomputed value - MagicV - 'magic' value used to determine whether State structure - was correctly initialized. -*************************************************************************/ -_hqrndstate_owner::_hqrndstate_owner() -{ - p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_hqrndstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_hqrndstate_owner::_hqrndstate_owner(const _hqrndstate_owner &rhs) -{ - p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_hqrndstate_owner& _hqrndstate_owner::operator=(const _hqrndstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_hqrndstate_clear(p_struct); - if( !alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_hqrndstate_owner::~_hqrndstate_owner() -{ - alglib_impl::_hqrndstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -hqrndstate::hqrndstate() : _hqrndstate_owner() -{ -} - -hqrndstate::hqrndstate(const hqrndstate &rhs):_hqrndstate_owner(rhs) -{ -} - -hqrndstate& hqrndstate::operator=(const hqrndstate &rhs) -{ - if( this==&rhs ) - return *this; - _hqrndstate_owner::operator=(rhs); - return *this; -} - -hqrndstate::~hqrndstate() -{ -} - -/************************************************************************* -HQRNDState initialization with random values which come from standard -RNG. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndrandomize(hqrndstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hqrndrandomize(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -HQRNDState initialization with seed values - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hqrndseed(s1, s2, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function generates random real number in (0,1), -not including interval boundaries - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrnduniformr(const hqrndstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hqrnduniformr(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function generates random integer number in [0, N) - -1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() -2. N can be any positive number except for very large numbers: - * close to 2^31 on 32-bit systems - * close to 2^62 on 64-bit systems - An exception will be generated if N is too large. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_int_t hqrnduniformi(const hqrndstate &state, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::hqrnduniformi(const_cast(state.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Random number generator: normal numbers - -This function generates one random number from normal distribution. -Its performance is equal to that of HQRNDNormal2() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrndnormal(const hqrndstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hqrndnormal(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Random number generator: random X and Y such that X^2+Y^2=1 - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndunit2(const hqrndstate &state, double &x, double &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hqrndunit2(const_cast(state.c_ptr()), &x, &y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Random number generator: normal numbers - -This function generates two independent random numbers from normal -distribution. Its performance is equal to that of HQRNDNormal() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndnormal2(const hqrndstate &state, double &x1, double &x2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hqrndnormal2(const_cast(state.c_ptr()), &x1, &x2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Random number generator: exponential distribution - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 11.08.2007 by Bochkanov Sergey -*************************************************************************/ -double hqrndexponential(const hqrndstate &state, const double lambdav) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hqrndexponential(const_cast(state.c_ptr()), lambdav, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function generates random number from discrete distribution given by -finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample - N - number of elements to use, N>=1 - -RESULT - this function returns one of the X[i] for random i=0..N-1 - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrnddiscrete(const hqrndstate &state, const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hqrnddiscrete(const_cast(state.c_ptr()), const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function generates random number from continuous distribution given -by finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample, array[N] (can be larger, in this case only - leading N elements are used). THIS ARRAY MUST BE SORTED BY - ASCENDING. - N - number of elements to use, N>=1 - -RESULT - this function returns random number from continuous distribution which - tries to approximate X as mush as possible. min(X)<=Result<=max(X). - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrndcontinuous(const hqrndstate &state, const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hqrndcontinuous(const_cast(state.c_ptr()), const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_kdtree_owner::_kdtree_owner() -{ - p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_kdtree_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_kdtree_owner::_kdtree_owner(const _kdtree_owner &rhs) -{ - p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_kdtree_owner& _kdtree_owner::operator=(const _kdtree_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_kdtree_clear(p_struct); - if( !alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_kdtree_owner::~_kdtree_owner() -{ - alglib_impl::_kdtree_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::kdtree* _kdtree_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::kdtree* _kdtree_owner::c_ptr() const -{ - return const_cast(p_struct); -} -kdtree::kdtree() : _kdtree_owner() -{ -} - -kdtree::kdtree(const kdtree &rhs):_kdtree_owner(rhs) -{ -} - -kdtree& kdtree::operator=(const kdtree &rhs) -{ - if( this==&rhs ) - return *this; - _kdtree_owner::operator=(rhs); - return *this; -} - -kdtree::~kdtree() -{ -} - - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void kdtreeserialize(kdtree &obj, std::string &s_out) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - alglib_impl::ae_int_t ssize; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_alloc_start(&serializer); - alglib_impl::kdtreealloc(&serializer, obj.c_ptr(), &state); - ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); - s_out.clear(); - s_out.reserve((size_t)(ssize+1)); - alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); - alglib_impl::kdtreeserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - if( s_out.length()>(size_t)ssize ) - throw ap_error("ALGLIB: serialization integrity error"); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void kdtreeunserialize(std::string &s_in, kdtree &obj) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); - alglib_impl::kdtreeunserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values and optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - N - number of points, N>=0. - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreebuild(const_cast(xy.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values and optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - N - number of points, N>=0. - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = xy.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreebuild(const_cast(xy.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values, integer tags and -optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - Tags - tags, array[0..N-1], contains integer tags associated - with points. - N - number of points, N>=0 - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreebuildtagged(const_cast(xy.c_ptr()), const_cast(tags.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values, integer tags and -optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - Tags - tags, array[0..N-1], contains integer tags associated - with points. - N - number of points, N>=0 - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (xy.rows()!=tags.length())) - throw ap_error("Error while calling 'kdtreebuildtagged': looks like one of arguments has wrong size"); - n = xy.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreebuildtagged(const_cast(xy.c_ptr()), const_cast(tags.c_ptr()), n, nx, ny, normtype, const_cast(kdt.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -K-NN query: K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of actual neighbors found (either K or N, if K>N). - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -K-NN query: K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of actual neighbors found (either K or N, if K>N). - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - bool selfmatch; - - selfmatch = true; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -R-NN query: all points within R-sphere centered at X - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - R - radius of sphere (in corresponding norm), R>0 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of neighbors found, >=0 - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -actual results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), r, selfmatch, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -R-NN query: all points within R-sphere centered at X - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - R - radius of sphere (in corresponding norm), R>0 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of neighbors found, >=0 - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -actual results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r) -{ - alglib_impl::ae_state _alglib_env_state; - bool selfmatch; - - selfmatch = true; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), r, selfmatch, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -K-NN query: approximate K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - Eps - approximation factor, Eps>=0. eps-approximate nearest - neighbor is a neighbor whose distance from X is at - most (1+eps) times distance of true nearest neighbor. - -RESULT - number of actual neighbors found (either K or N, if K>N). - -NOTES - significant performance gain may be achieved only when Eps is is on - the order of magnitude of 1 or larger. - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, eps, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -K-NN query: approximate K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - Eps - approximation factor, Eps>=0. eps-approximate nearest - neighbor is a neighbor whose distance from X is at - most (1+eps) times distance of true nearest neighbor. - -RESULT - number of actual neighbors found (either K or N, if K>N). - -NOTES - significant performance gain may be achieved only when Eps is is on - the order of magnitude of 1 or larger. - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps) -{ - alglib_impl::ae_state _alglib_env_state; - bool selfmatch; - - selfmatch = true; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), k, selfmatch, eps, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -X-values from last query - -INPUT PARAMETERS - KDT - KD-tree - X - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - X - rows are filled with X-values - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsx(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -X- and Y-values from last query - -INPUT PARAMETERS - KDT - KD-tree - XY - possibly pre-allocated buffer. If XY is too small to store - result, it is resized. If size(XY) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - XY - rows are filled with points: first NX columns with - X-values, next NY columns - with Y-values. - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsxy(const_cast(kdt.c_ptr()), const_cast(xy.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Tags from last query - -INPUT PARAMETERS - KDT - KD-tree - Tags - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - Tags - filled with tags associated with points, - or, when no tags were supplied, with zeros - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultstags(const_cast(kdt.c_ptr()), const_cast(tags.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Distances from last query - -INPUT PARAMETERS - KDT - KD-tree - R - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - R - filled with distances (in corresponding norm) - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsdistances(const_cast(kdt.c_ptr()), const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -X-values from last query; 'interactive' variant for languages like Python -which support constructs like "X = KDTreeQueryResultsXI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsxi(const_cast(kdt.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -XY-values from last query; 'interactive' variant for languages like Python -which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsxyi(const_cast(kdt.c_ptr()), const_cast(xy.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Tags from last query; 'interactive' variant for languages like Python -which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultstagsi(const_cast(kdt.c_ptr()), const_cast(tags.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Distances from last query; 'interactive' variant for languages like Python -which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" -and interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kdtreequeryresultsdistancesi(const_cast(kdt.c_ptr()), const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static ae_int_t hqrnd_hqrndmax = 2147483561; -static ae_int_t hqrnd_hqrndm1 = 2147483563; -static ae_int_t hqrnd_hqrndm2 = 2147483399; -static ae_int_t hqrnd_hqrndmagic = 1634357784; -static ae_int_t hqrnd_hqrndintegerbase(hqrndstate* state, - ae_state *_state); - - -static ae_int_t nearestneighbor_splitnodesize = 6; -static ae_int_t nearestneighbor_kdtreefirstversion = 0; -static void nearestneighbor_kdtreesplit(kdtree* kdt, - ae_int_t i1, - ae_int_t i2, - ae_int_t d, - double s, - ae_int_t* i3, - ae_state *_state); -static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, - ae_int_t* nodesoffs, - ae_int_t* splitsoffs, - ae_int_t i1, - ae_int_t i2, - ae_int_t maxleafsize, - ae_state *_state); -static void nearestneighbor_kdtreequerynnrec(kdtree* kdt, - ae_int_t offs, - ae_state *_state); -static void nearestneighbor_kdtreeinitbox(kdtree* kdt, - /* Real */ ae_vector* x, - ae_state *_state); -static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, - ae_int_t nx, - ae_int_t ny, - ae_state *_state); -static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_state *_state); -static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_state *_state); - - - - - -/************************************************************************* -HQRNDState initialization with random values which come from standard -RNG. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndrandomize(hqrndstate* state, ae_state *_state) -{ - ae_int_t s0; - ae_int_t s1; - - _hqrndstate_clear(state); - - s0 = ae_randominteger(hqrnd_hqrndm1, _state); - s1 = ae_randominteger(hqrnd_hqrndm2, _state); - hqrndseed(s0, s1, state, _state); -} - - -/************************************************************************* -HQRNDState initialization with seed values - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndseed(ae_int_t s1, - ae_int_t s2, - hqrndstate* state, - ae_state *_state) -{ - - _hqrndstate_clear(state); - - - /* - * Protection against negative seeds: - * - * SEED := -(SEED+1) - * - * We can use just "-SEED" because there exists such integer number N - * that N<0, -N=N<0 too. (This number is equal to 0x800...000). Need - * to handle such seed correctly forces us to use a bit complicated - * formula. - */ - if( s1<0 ) - { - s1 = -(s1+1); - } - if( s2<0 ) - { - s2 = -(s2+1); - } - state->s1 = s1%(hqrnd_hqrndm1-1)+1; - state->s2 = s2%(hqrnd_hqrndm2-1)+1; - state->magicv = hqrnd_hqrndmagic; -} - - -/************************************************************************* -This function generates random real number in (0,1), -not including interval boundaries - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrnduniformr(hqrndstate* state, ae_state *_state) -{ - double result; - - - result = (double)(hqrnd_hqrndintegerbase(state, _state)+1)/(double)(hqrnd_hqrndmax+2); - return result; -} - - -/************************************************************************* -This function generates random integer number in [0, N) - -1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() -2. N can be any positive number except for very large numbers: - * close to 2^31 on 32-bit systems - * close to 2^62 on 64-bit systems - An exception will be generated if N is too large. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state) -{ - ae_int_t maxcnt; - ae_int_t mx; - ae_int_t a; - ae_int_t b; - ae_int_t result; - - - ae_assert(n>0, "HQRNDUniformI: N<=0!", _state); - maxcnt = hqrnd_hqrndmax+1; - - /* - * Two branches: one for N<=MaxCnt, another for N>MaxCnt. - */ - if( n>maxcnt ) - { - - /* - * N>=MaxCnt. - * - * We have two options here: - * a) N is exactly divisible by MaxCnt - * b) N is not divisible by MaxCnt - * - * In both cases we reduce problem on interval spanning [0,N) - * to several subproblems on intervals spanning [0,MaxCnt). - */ - if( n%maxcnt==0 ) - { - - /* - * N is exactly divisible by MaxCnt. - * - * [0,N) range is dividided into N/MaxCnt bins, - * each of them having length equal to MaxCnt. - * - * We generate: - * * random bin number B - * * random offset within bin A - * Both random numbers are generated by recursively - * calling HQRNDUniformI(). - * - * Result is equal to A+MaxCnt*B. - */ - ae_assert(n/maxcnt<=maxcnt, "HQRNDUniformI: N is too large", _state); - a = hqrnduniformi(state, maxcnt, _state); - b = hqrnduniformi(state, n/maxcnt, _state); - result = a+maxcnt*b; - } - else - { - - /* - * N is NOT exactly divisible by MaxCnt. - * - * [0,N) range is dividided into Ceil(N/MaxCnt) bins, - * each of them having length equal to MaxCnt. - * - * We generate: - * * random bin number B in [0, Ceil(N/MaxCnt)-1] - * * random offset within bin A - * * if both of what is below is true - * 1) bin number B is that of the last bin - * 2) A >= N mod MaxCnt - * then we repeat generation of A/B. - * This stage is essential in order to avoid bias in the result. - * * otherwise, we return A*MaxCnt+N - */ - ae_assert(n/maxcnt+1<=maxcnt, "HQRNDUniformI: N is too large", _state); - result = -1; - do - { - a = hqrnduniformi(state, maxcnt, _state); - b = hqrnduniformi(state, n/maxcnt+1, _state); - if( b==n/maxcnt&&a>=n%maxcnt ) - { - continue; - } - result = a+maxcnt*b; - } - while(result<0); - } - } - else - { - - /* - * N<=MaxCnt - * - * Code below is a bit complicated because we can not simply - * return "HQRNDIntegerBase() mod N" - it will be skewed for - * large N's in [0.1*HQRNDMax...HQRNDMax]. - */ - mx = maxcnt-maxcnt%n; - do - { - result = hqrnd_hqrndintegerbase(state, _state); - } - while(result>=mx); - result = result%n; - } - return result; -} - - -/************************************************************************* -Random number generator: normal numbers - -This function generates one random number from normal distribution. -Its performance is equal to that of HQRNDNormal2() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrndnormal(hqrndstate* state, ae_state *_state) -{ - double v1; - double v2; - double result; - - - hqrndnormal2(state, &v1, &v2, _state); - result = v1; - return result; -} - - -/************************************************************************* -Random number generator: random X and Y such that X^2+Y^2=1 - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state) -{ - double v; - double mx; - double mn; - - *x = 0; - *y = 0; - - do - { - hqrndnormal2(state, x, y, _state); - } - while(!(ae_fp_neq(*x,0)||ae_fp_neq(*y,0))); - mx = ae_maxreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); - mn = ae_minreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); - v = mx*ae_sqrt(1+ae_sqr(mn/mx, _state), _state); - *x = *x/v; - *y = *y/v; -} - - -/************************************************************************* -Random number generator: normal numbers - -This function generates two independent random numbers from normal -distribution. Its performance is equal to that of HQRNDNormal() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndnormal2(hqrndstate* state, - double* x1, - double* x2, - ae_state *_state) -{ - double u; - double v; - double s; - - *x1 = 0; - *x2 = 0; - - for(;;) - { - u = 2*hqrnduniformr(state, _state)-1; - v = 2*hqrnduniformr(state, _state)-1; - s = ae_sqr(u, _state)+ae_sqr(v, _state); - if( ae_fp_greater(s,0)&&ae_fp_less(s,1) ) - { - - /* - * two Sqrt's instead of one to - * avoid overflow when S is too small - */ - s = ae_sqrt(-2*ae_log(s, _state), _state)/ae_sqrt(s, _state); - *x1 = u*s; - *x2 = v*s; - return; - } - } -} - - -/************************************************************************* -Random number generator: exponential distribution - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 11.08.2007 by Bochkanov Sergey -*************************************************************************/ -double hqrndexponential(hqrndstate* state, - double lambdav, - ae_state *_state) -{ - double result; - - - ae_assert(ae_fp_greater(lambdav,0), "HQRNDExponential: LambdaV<=0!", _state); - result = -ae_log(hqrnduniformr(state, _state), _state)/lambdav; - return result; -} - - -/************************************************************************* -This function generates random number from discrete distribution given by -finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample - N - number of elements to use, N>=1 - -RESULT - this function returns one of the X[i] for random i=0..N-1 - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrnddiscrete(hqrndstate* state, - /* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double result; - - - ae_assert(n>0, "HQRNDDiscrete: N<=0", _state); - ae_assert(n<=x->cnt, "HQRNDDiscrete: Length(X)ptr.p_double[hqrnduniformi(state, n, _state)]; - return result; -} - - -/************************************************************************* -This function generates random number from continuous distribution given -by finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample, array[N] (can be larger, in this case only - leading N elements are used). THIS ARRAY MUST BE SORTED BY - ASCENDING. - N - number of elements to use, N>=1 - -RESULT - this function returns random number from continuous distribution which - tries to approximate X as mush as possible. min(X)<=Result<=max(X). - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrndcontinuous(hqrndstate* state, - /* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double mx; - double mn; - ae_int_t i; - double result; - - - ae_assert(n>0, "HQRNDContinuous: N<=0", _state); - ae_assert(n<=x->cnt, "HQRNDContinuous: Length(X)ptr.p_double[0]; - return result; - } - i = hqrnduniformi(state, n-1, _state); - mn = x->ptr.p_double[i]; - mx = x->ptr.p_double[i+1]; - ae_assert(ae_fp_greater_eq(mx,mn), "HQRNDDiscrete: X is not sorted by ascending", _state); - if( ae_fp_neq(mx,mn) ) - { - result = (mx-mn)*hqrnduniformr(state, _state)+mn; - } - else - { - result = mn; - } - return result; -} - - -/************************************************************************* -This function returns random integer in [0,HQRNDMax] - -L'Ecuyer, Efficient and portable combined random number generators -*************************************************************************/ -static ae_int_t hqrnd_hqrndintegerbase(hqrndstate* state, - ae_state *_state) -{ - ae_int_t k; - ae_int_t result; - - - ae_assert(state->magicv==hqrnd_hqrndmagic, "HQRNDIntegerBase: State is not correctly initialized!", _state); - k = state->s1/53668; - state->s1 = 40014*(state->s1-k*53668)-k*12211; - if( state->s1<0 ) - { - state->s1 = state->s1+2147483563; - } - k = state->s2/52774; - state->s2 = 40692*(state->s2-k*52774)-k*3791; - if( state->s2<0 ) - { - state->s2 = state->s2+2147483399; - } - - /* - * Result - */ - result = state->s1-state->s2; - if( result<1 ) - { - result = result+2147483562; - } - result = result-1; - return result; -} - - -ae_bool _hqrndstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - hqrndstate *p = (hqrndstate*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _hqrndstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - hqrndstate *dst = (hqrndstate*)_dst; - hqrndstate *src = (hqrndstate*)_src; - dst->s1 = src->s1; - dst->s2 = src->s2; - dst->magicv = src->magicv; - return ae_true; -} - - -void _hqrndstate_clear(void* _p) -{ - hqrndstate *p = (hqrndstate*)_p; - ae_touch_ptr((void*)p); -} - - -void _hqrndstate_destroy(void* _p) -{ - hqrndstate *p = (hqrndstate*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values and optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - N - number of points, N>=0. - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuild(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_int_t normtype, - kdtree* kdt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tags; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _kdtree_clear(kdt); - ae_vector_init(&tags, 0, DT_INT, _state, ae_true); - - ae_assert(n>=0, "KDTreeBuild: N<0", _state); - ae_assert(nx>=1, "KDTreeBuild: NX<1", _state); - ae_assert(ny>=0, "KDTreeBuild: NY<0", _state); - ae_assert(normtype>=0&&normtype<=2, "KDTreeBuild: incorrect NormType", _state); - ae_assert(xy->rows>=n, "KDTreeBuild: rows(X)cols>=nx+ny||n==0, "KDTreeBuild: cols(X)0 ) - { - ae_vector_set_length(&tags, n, _state); - for(i=0; i<=n-1; i++) - { - tags.ptr.p_int[i] = 0; - } - } - kdtreebuildtagged(xy, &tags, n, nx, ny, normtype, kdt, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values, integer tags and -optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - Tags - tags, array[0..N-1], contains integer tags associated - with points. - N - number of points, N>=0 - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuildtagged(/* Real */ ae_matrix* xy, - /* Integer */ ae_vector* tags, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_int_t normtype, - kdtree* kdt, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t maxnodes; - ae_int_t nodesoffs; - ae_int_t splitsoffs; - - _kdtree_clear(kdt); - - ae_assert(n>=0, "KDTreeBuildTagged: N<0", _state); - ae_assert(nx>=1, "KDTreeBuildTagged: NX<1", _state); - ae_assert(ny>=0, "KDTreeBuildTagged: NY<0", _state); - ae_assert(normtype>=0&&normtype<=2, "KDTreeBuildTagged: incorrect NormType", _state); - ae_assert(xy->rows>=n, "KDTreeBuildTagged: rows(X)cols>=nx+ny||n==0, "KDTreeBuildTagged: cols(X)n = n; - kdt->nx = nx; - kdt->ny = ny; - kdt->normtype = normtype; - kdt->kcur = 0; - - /* - * N=0 => quick exit - */ - if( n==0 ) - { - return; - } - - /* - * Allocate - */ - nearestneighbor_kdtreeallocdatasetindependent(kdt, nx, ny, _state); - nearestneighbor_kdtreeallocdatasetdependent(kdt, n, nx, ny, _state); - - /* - * Initial fill - */ - for(i=0; i<=n-1; i++) - { - ae_v_move(&kdt->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); - ae_v_move(&kdt->xy.ptr.pp_double[i][nx], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(nx,2*nx+ny-1)); - kdt->tags.ptr.p_int[i] = tags->ptr.p_int[i]; - } - - /* - * Determine bounding box - */ - ae_v_move(&kdt->boxmin.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); - ae_v_move(&kdt->boxmax.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); - for(i=1; i<=n-1; i++) - { - for(j=0; j<=nx-1; j++) - { - kdt->boxmin.ptr.p_double[j] = ae_minreal(kdt->boxmin.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); - kdt->boxmax.ptr.p_double[j] = ae_maxreal(kdt->boxmax.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); - } - } - - /* - * prepare tree structure - * * MaxNodes=N because we guarantee no trivial splits, i.e. - * every split will generate two non-empty boxes - */ - maxnodes = n; - ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*maxnodes, _state); - ae_vector_set_length(&kdt->splits, 2*maxnodes, _state); - nodesoffs = 0; - splitsoffs = 0; - ae_v_move(&kdt->curboxmin.ptr.p_double[0], 1, &kdt->boxmin.ptr.p_double[0], 1, ae_v_len(0,nx-1)); - ae_v_move(&kdt->curboxmax.ptr.p_double[0], 1, &kdt->boxmax.ptr.p_double[0], 1, ae_v_len(0,nx-1)); - nearestneighbor_kdtreegeneratetreerec(kdt, &nodesoffs, &splitsoffs, 0, n, 8, _state); -} - - -/************************************************************************* -K-NN query: K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of actual neighbors found (either K or N, if K>N). - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryknn(kdtree* kdt, - /* Real */ ae_vector* x, - ae_int_t k, - ae_bool selfmatch, - ae_state *_state) -{ - ae_int_t result; - - - ae_assert(k>=1, "KDTreeQueryKNN: K<1!", _state); - ae_assert(x->cnt>=kdt->nx, "KDTreeQueryKNN: Length(X)nx, _state), "KDTreeQueryKNN: X contains infinite or NaN values!", _state); - result = kdtreequeryaknn(kdt, x, k, selfmatch, 0.0, _state); - return result; -} - - -/************************************************************************* -R-NN query: all points within R-sphere centered at X - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - R - radius of sphere (in corresponding norm), R>0 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of neighbors found, >=0 - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -actual results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryrnn(kdtree* kdt, - /* Real */ ae_vector* x, - double r, - ae_bool selfmatch, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t result; - - - ae_assert(ae_fp_greater(r,0), "KDTreeQueryRNN: incorrect R!", _state); - ae_assert(x->cnt>=kdt->nx, "KDTreeQueryRNN: Length(X)nx, _state), "KDTreeQueryRNN: X contains infinite or NaN values!", _state); - - /* - * Handle special case: KDT.N=0 - */ - if( kdt->n==0 ) - { - kdt->kcur = 0; - result = 0; - return result; - } - - /* - * Prepare parameters - */ - kdt->kneeded = 0; - if( kdt->normtype!=2 ) - { - kdt->rneeded = r; - } - else - { - kdt->rneeded = ae_sqr(r, _state); - } - kdt->selfmatch = selfmatch; - kdt->approxf = 1; - kdt->kcur = 0; - - /* - * calculate distance from point to current bounding box - */ - nearestneighbor_kdtreeinitbox(kdt, x, _state); - - /* - * call recursive search - * results are returned as heap - */ - nearestneighbor_kdtreequerynnrec(kdt, 0, _state); - - /* - * pop from heap to generate ordered representation - * - * last element is not pop'ed because it is already in - * its place - */ - result = kdt->kcur; - j = kdt->kcur; - for(i=kdt->kcur; i>=2; i--) - { - tagheappopi(&kdt->r, &kdt->idx, &j, _state); - } - return result; -} - - -/************************************************************************* -K-NN query: approximate K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - Eps - approximation factor, Eps>=0. eps-approximate nearest - neighbor is a neighbor whose distance from X is at - most (1+eps) times distance of true nearest neighbor. - -RESULT - number of actual neighbors found (either K or N, if K>N). - -NOTES - significant performance gain may be achieved only when Eps is is on - the order of magnitude of 1 or larger. - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryaknn(kdtree* kdt, - /* Real */ ae_vector* x, - ae_int_t k, - ae_bool selfmatch, - double eps, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t result; - - - ae_assert(k>0, "KDTreeQueryAKNN: incorrect K!", _state); - ae_assert(ae_fp_greater_eq(eps,0), "KDTreeQueryAKNN: incorrect Eps!", _state); - ae_assert(x->cnt>=kdt->nx, "KDTreeQueryAKNN: Length(X)nx, _state), "KDTreeQueryAKNN: X contains infinite or NaN values!", _state); - - /* - * Handle special case: KDT.N=0 - */ - if( kdt->n==0 ) - { - kdt->kcur = 0; - result = 0; - return result; - } - - /* - * Prepare parameters - */ - k = ae_minint(k, kdt->n, _state); - kdt->kneeded = k; - kdt->rneeded = 0; - kdt->selfmatch = selfmatch; - if( kdt->normtype==2 ) - { - kdt->approxf = 1/ae_sqr(1+eps, _state); - } - else - { - kdt->approxf = 1/(1+eps); - } - kdt->kcur = 0; - - /* - * calculate distance from point to current bounding box - */ - nearestneighbor_kdtreeinitbox(kdt, x, _state); - - /* - * call recursive search - * results are returned as heap - */ - nearestneighbor_kdtreequerynnrec(kdt, 0, _state); - - /* - * pop from heap to generate ordered representation - * - * last element is non pop'ed because it is already in - * its place - */ - result = kdt->kcur; - j = kdt->kcur; - for(i=kdt->kcur; i>=2; i--) - { - tagheappopi(&kdt->r, &kdt->idx, &j, _state); - } - return result; -} - - -/************************************************************************* -X-values from last query - -INPUT PARAMETERS - KDT - KD-tree - X - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - X - rows are filled with X-values - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsx(kdtree* kdt, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - - if( kdt->kcur==0 ) - { - return; - } - if( x->rowskcur||x->colsnx ) - { - ae_matrix_set_length(x, kdt->kcur, kdt->nx, _state); - } - k = kdt->kcur; - for(i=0; i<=k-1; i++) - { - ae_v_move(&x->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[kdt->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx-1)); - } -} - - -/************************************************************************* -X- and Y-values from last query - -INPUT PARAMETERS - KDT - KD-tree - XY - possibly pre-allocated buffer. If XY is too small to store - result, it is resized. If size(XY) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - XY - rows are filled with points: first NX columns with - X-values, next NY columns - with Y-values. - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxy(kdtree* kdt, - /* Real */ ae_matrix* xy, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - - if( kdt->kcur==0 ) - { - return; - } - if( xy->rowskcur||xy->colsnx+kdt->ny ) - { - ae_matrix_set_length(xy, kdt->kcur, kdt->nx+kdt->ny, _state); - } - k = kdt->kcur; - for(i=0; i<=k-1; i++) - { - ae_v_move(&xy->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[kdt->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx+kdt->ny-1)); - } -} - - -/************************************************************************* -Tags from last query - -INPUT PARAMETERS - KDT - KD-tree - Tags - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - Tags - filled with tags associated with points, - or, when no tags were supplied, with zeros - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstags(kdtree* kdt, - /* Integer */ ae_vector* tags, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - - if( kdt->kcur==0 ) - { - return; - } - if( tags->cntkcur ) - { - ae_vector_set_length(tags, kdt->kcur, _state); - } - k = kdt->kcur; - for(i=0; i<=k-1; i++) - { - tags->ptr.p_int[i] = kdt->tags.ptr.p_int[kdt->idx.ptr.p_int[i]]; - } -} - - -/************************************************************************* -Distances from last query - -INPUT PARAMETERS - KDT - KD-tree - R - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - R - filled with distances (in corresponding norm) - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistances(kdtree* kdt, - /* Real */ ae_vector* r, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - - if( kdt->kcur==0 ) - { - return; - } - if( r->cntkcur ) - { - ae_vector_set_length(r, kdt->kcur, _state); - } - k = kdt->kcur; - - /* - * unload norms - * - * Abs() call is used to handle cases with negative norms - * (generated during KFN requests) - */ - if( kdt->normtype==0 ) - { - for(i=0; i<=k-1; i++) - { - r->ptr.p_double[i] = ae_fabs(kdt->r.ptr.p_double[i], _state); - } - } - if( kdt->normtype==1 ) - { - for(i=0; i<=k-1; i++) - { - r->ptr.p_double[i] = ae_fabs(kdt->r.ptr.p_double[i], _state); - } - } - if( kdt->normtype==2 ) - { - for(i=0; i<=k-1; i++) - { - r->ptr.p_double[i] = ae_sqrt(ae_fabs(kdt->r.ptr.p_double[i], _state), _state); - } - } -} - - -/************************************************************************* -X-values from last query; 'interactive' variant for languages like Python -which support constructs like "X = KDTreeQueryResultsXI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxi(kdtree* kdt, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - - ae_matrix_clear(x); - - kdtreequeryresultsx(kdt, x, _state); -} - - -/************************************************************************* -XY-values from last query; 'interactive' variant for languages like Python -which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxyi(kdtree* kdt, - /* Real */ ae_matrix* xy, - ae_state *_state) -{ - - ae_matrix_clear(xy); - - kdtreequeryresultsxy(kdt, xy, _state); -} - - -/************************************************************************* -Tags from last query; 'interactive' variant for languages like Python -which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstagsi(kdtree* kdt, - /* Integer */ ae_vector* tags, - ae_state *_state) -{ - - ae_vector_clear(tags); - - kdtreequeryresultstags(kdt, tags, _state); -} - - -/************************************************************************* -Distances from last query; 'interactive' variant for languages like Python -which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" -and interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistancesi(kdtree* kdt, - /* Real */ ae_vector* r, - ae_state *_state) -{ - - ae_vector_clear(r); - - kdtreequeryresultsdistances(kdt, r, _state); -} - - -/************************************************************************* -Serializer: allocation - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state) -{ - - - - /* - * Header - */ - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - - /* - * Data - */ - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - allocrealmatrix(s, &tree->xy, -1, -1, _state); - allocintegerarray(s, &tree->tags, -1, _state); - allocrealarray(s, &tree->boxmin, -1, _state); - allocrealarray(s, &tree->boxmax, -1, _state); - allocintegerarray(s, &tree->nodes, -1, _state); - allocrealarray(s, &tree->splits, -1, _state); -} - - -/************************************************************************* -Serializer: serialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state) -{ - - - - /* - * Header - */ - ae_serializer_serialize_int(s, getkdtreeserializationcode(_state), _state); - ae_serializer_serialize_int(s, nearestneighbor_kdtreefirstversion, _state); - - /* - * Data - */ - ae_serializer_serialize_int(s, tree->n, _state); - ae_serializer_serialize_int(s, tree->nx, _state); - ae_serializer_serialize_int(s, tree->ny, _state); - ae_serializer_serialize_int(s, tree->normtype, _state); - serializerealmatrix(s, &tree->xy, -1, -1, _state); - serializeintegerarray(s, &tree->tags, -1, _state); - serializerealarray(s, &tree->boxmin, -1, _state); - serializerealarray(s, &tree->boxmax, -1, _state); - serializeintegerarray(s, &tree->nodes, -1, _state); - serializerealarray(s, &tree->splits, -1, _state); -} - - -/************************************************************************* -Serializer: unserialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state) -{ - ae_int_t i0; - ae_int_t i1; - - _kdtree_clear(tree); - - - /* - * check correctness of header - */ - ae_serializer_unserialize_int(s, &i0, _state); - ae_assert(i0==getkdtreeserializationcode(_state), "KDTreeUnserialize: stream header corrupted", _state); - ae_serializer_unserialize_int(s, &i1, _state); - ae_assert(i1==nearestneighbor_kdtreefirstversion, "KDTreeUnserialize: stream header corrupted", _state); - - /* - * Unserialize data - */ - ae_serializer_unserialize_int(s, &tree->n, _state); - ae_serializer_unserialize_int(s, &tree->nx, _state); - ae_serializer_unserialize_int(s, &tree->ny, _state); - ae_serializer_unserialize_int(s, &tree->normtype, _state); - unserializerealmatrix(s, &tree->xy, _state); - unserializeintegerarray(s, &tree->tags, _state); - unserializerealarray(s, &tree->boxmin, _state); - unserializerealarray(s, &tree->boxmax, _state); - unserializeintegerarray(s, &tree->nodes, _state); - unserializerealarray(s, &tree->splits, _state); - nearestneighbor_kdtreealloctemporaries(tree, tree->n, tree->nx, tree->ny, _state); -} - - -/************************************************************************* -Rearranges nodes [I1,I2) using partition in D-th dimension with S as threshold. -Returns split position I3: [I1,I3) and [I3,I2) are created as result. - -This subroutine doesn't create tree structures, just rearranges nodes. -*************************************************************************/ -static void nearestneighbor_kdtreesplit(kdtree* kdt, - ae_int_t i1, - ae_int_t i2, - ae_int_t d, - double s, - ae_int_t* i3, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t ileft; - ae_int_t iright; - double v; - - *i3 = 0; - - ae_assert(kdt->n>0, "KDTreeSplit: internal error", _state); - - /* - * split XY/Tags in two parts: - * * [ILeft,IRight] is non-processed part of XY/Tags - * - * After cycle is done, we have Ileft=IRight. We deal with - * this element separately. - * - * After this, [I1,ILeft) contains left part, and [ILeft,I2) - * contains right part. - */ - ileft = i1; - iright = i2-1; - while(ileftxy.ptr.pp_double[ileft][d],s) ) - { - - /* - * XY[ILeft] is on its place. - * Advance ILeft. - */ - ileft = ileft+1; - } - else - { - - /* - * XY[ILeft,..] must be at IRight. - * Swap and advance IRight. - */ - for(i=0; i<=2*kdt->nx+kdt->ny-1; i++) - { - v = kdt->xy.ptr.pp_double[ileft][i]; - kdt->xy.ptr.pp_double[ileft][i] = kdt->xy.ptr.pp_double[iright][i]; - kdt->xy.ptr.pp_double[iright][i] = v; - } - j = kdt->tags.ptr.p_int[ileft]; - kdt->tags.ptr.p_int[ileft] = kdt->tags.ptr.p_int[iright]; - kdt->tags.ptr.p_int[iright] = j; - iright = iright-1; - } - } - if( ae_fp_less_eq(kdt->xy.ptr.pp_double[ileft][d],s) ) - { - ileft = ileft+1; - } - else - { - iright = iright-1; - } - *i3 = ileft; -} - - -/************************************************************************* -Recursive kd-tree generation subroutine. - -PARAMETERS - KDT tree - NodesOffs unused part of Nodes[] which must be filled by tree - SplitsOffs unused part of Splits[] - I1, I2 points from [I1,I2) are processed - -NodesOffs[] and SplitsOffs[] must be large enough. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, - ae_int_t* nodesoffs, - ae_int_t* splitsoffs, - ae_int_t i1, - ae_int_t i2, - ae_int_t maxleafsize, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nx; - ae_int_t ny; - ae_int_t i; - ae_int_t j; - ae_int_t oldoffs; - ae_int_t i3; - ae_int_t cntless; - ae_int_t cntgreater; - double minv; - double maxv; - ae_int_t minidx; - ae_int_t maxidx; - ae_int_t d; - double ds; - double s; - double v; - double v0; - double v1; - - - ae_assert(kdt->n>0, "KDTreeGenerateTreeRec: internal error", _state); - ae_assert(i2>i1, "KDTreeGenerateTreeRec: internal error", _state); - - /* - * Generate leaf if needed - */ - if( i2-i1<=maxleafsize ) - { - kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; - kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; - *nodesoffs = *nodesoffs+2; - return; - } - - /* - * Load values for easier access - */ - nx = kdt->nx; - ny = kdt->ny; - - /* - * Select dimension to split: - * * D is a dimension number - * In case bounding box has zero size, we enforce creation of the leaf node. - */ - d = 0; - ds = kdt->curboxmax.ptr.p_double[0]-kdt->curboxmin.ptr.p_double[0]; - for(i=1; i<=nx-1; i++) - { - v = kdt->curboxmax.ptr.p_double[i]-kdt->curboxmin.ptr.p_double[i]; - if( ae_fp_greater(v,ds) ) - { - ds = v; - d = i; - } - } - if( ae_fp_eq(ds,0) ) - { - kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; - kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; - *nodesoffs = *nodesoffs+2; - return; - } - - /* - * Select split position S using sliding midpoint rule, - * rearrange points into [I1,I3) and [I3,I2). - * - * In case all points has same value of D-th component - * (MinV=MaxV) we enforce D-th dimension of bounding - * box to become exactly zero and repeat tree construction. - */ - s = kdt->curboxmin.ptr.p_double[d]+0.5*ds; - ae_v_move(&kdt->buf.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[i1][d], kdt->xy.stride, ae_v_len(0,i2-i1-1)); - n = i2-i1; - cntless = 0; - cntgreater = 0; - minv = kdt->buf.ptr.p_double[0]; - maxv = kdt->buf.ptr.p_double[0]; - minidx = i1; - maxidx = i1; - for(i=0; i<=n-1; i++) - { - v = kdt->buf.ptr.p_double[i]; - if( ae_fp_less(v,minv) ) - { - minv = v; - minidx = i1+i; - } - if( ae_fp_greater(v,maxv) ) - { - maxv = v; - maxidx = i1+i; - } - if( ae_fp_less(v,s) ) - { - cntless = cntless+1; - } - if( ae_fp_greater(v,s) ) - { - cntgreater = cntgreater+1; - } - } - if( ae_fp_eq(minv,maxv) ) - { - - /* - * In case all points has same value of D-th component - * (MinV=MaxV) we enforce D-th dimension of bounding - * box to become exactly zero and repeat tree construction. - */ - v0 = kdt->curboxmin.ptr.p_double[d]; - v1 = kdt->curboxmax.ptr.p_double[d]; - kdt->curboxmin.ptr.p_double[d] = minv; - kdt->curboxmax.ptr.p_double[d] = maxv; - nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i2, maxleafsize, _state); - kdt->curboxmin.ptr.p_double[d] = v0; - kdt->curboxmax.ptr.p_double[d] = v1; - return; - } - if( cntless>0&&cntgreater>0 ) - { - - /* - * normal midpoint split - */ - nearestneighbor_kdtreesplit(kdt, i1, i2, d, s, &i3, _state); - } - else - { - - /* - * sliding midpoint - */ - if( cntless==0 ) - { - - /* - * 1. move split to MinV, - * 2. place one point to the left bin (move to I1), - * others - to the right bin - */ - s = minv; - if( minidx!=i1 ) - { - for(i=0; i<=2*nx+ny-1; i++) - { - v = kdt->xy.ptr.pp_double[minidx][i]; - kdt->xy.ptr.pp_double[minidx][i] = kdt->xy.ptr.pp_double[i1][i]; - kdt->xy.ptr.pp_double[i1][i] = v; - } - j = kdt->tags.ptr.p_int[minidx]; - kdt->tags.ptr.p_int[minidx] = kdt->tags.ptr.p_int[i1]; - kdt->tags.ptr.p_int[i1] = j; - } - i3 = i1+1; - } - else - { - - /* - * 1. move split to MaxV, - * 2. place one point to the right bin (move to I2-1), - * others - to the left bin - */ - s = maxv; - if( maxidx!=i2-1 ) - { - for(i=0; i<=2*nx+ny-1; i++) - { - v = kdt->xy.ptr.pp_double[maxidx][i]; - kdt->xy.ptr.pp_double[maxidx][i] = kdt->xy.ptr.pp_double[i2-1][i]; - kdt->xy.ptr.pp_double[i2-1][i] = v; - } - j = kdt->tags.ptr.p_int[maxidx]; - kdt->tags.ptr.p_int[maxidx] = kdt->tags.ptr.p_int[i2-1]; - kdt->tags.ptr.p_int[i2-1] = j; - } - i3 = i2-1; - } - } - - /* - * Generate 'split' node - */ - kdt->nodes.ptr.p_int[*nodesoffs+0] = 0; - kdt->nodes.ptr.p_int[*nodesoffs+1] = d; - kdt->nodes.ptr.p_int[*nodesoffs+2] = *splitsoffs; - kdt->splits.ptr.p_double[*splitsoffs+0] = s; - oldoffs = *nodesoffs; - *nodesoffs = *nodesoffs+nearestneighbor_splitnodesize; - *splitsoffs = *splitsoffs+1; - - /* - * Recirsive generation: - * * update CurBox - * * call subroutine - * * restore CurBox - */ - kdt->nodes.ptr.p_int[oldoffs+3] = *nodesoffs; - v = kdt->curboxmax.ptr.p_double[d]; - kdt->curboxmax.ptr.p_double[d] = s; - nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i3, maxleafsize, _state); - kdt->curboxmax.ptr.p_double[d] = v; - kdt->nodes.ptr.p_int[oldoffs+4] = *nodesoffs; - v = kdt->curboxmin.ptr.p_double[d]; - kdt->curboxmin.ptr.p_double[d] = s; - nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i3, i2, maxleafsize, _state); - kdt->curboxmin.ptr.p_double[d] = v; -} - - -/************************************************************************* -Recursive subroutine for NN queries. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreequerynnrec(kdtree* kdt, - ae_int_t offs, - ae_state *_state) -{ - double ptdist; - ae_int_t i; - ae_int_t j; - ae_int_t nx; - ae_int_t i1; - ae_int_t i2; - ae_int_t d; - double s; - double v; - double t1; - ae_int_t childbestoffs; - ae_int_t childworstoffs; - ae_int_t childoffs; - double prevdist; - ae_bool todive; - ae_bool bestisleft; - ae_bool updatemin; - - - ae_assert(kdt->n>0, "KDTreeQueryNNRec: internal error", _state); - - /* - * Leaf node. - * Process points. - */ - if( kdt->nodes.ptr.p_int[offs]>0 ) - { - i1 = kdt->nodes.ptr.p_int[offs+1]; - i2 = i1+kdt->nodes.ptr.p_int[offs]; - for(i=i1; i<=i2-1; i++) - { - - /* - * Calculate distance - */ - ptdist = 0; - nx = kdt->nx; - if( kdt->normtype==0 ) - { - for(j=0; j<=nx-1; j++) - { - ptdist = ae_maxreal(ptdist, ae_fabs(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state), _state); - } - } - if( kdt->normtype==1 ) - { - for(j=0; j<=nx-1; j++) - { - ptdist = ptdist+ae_fabs(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state); - } - } - if( kdt->normtype==2 ) - { - for(j=0; j<=nx-1; j++) - { - ptdist = ptdist+ae_sqr(kdt->xy.ptr.pp_double[i][j]-kdt->x.ptr.p_double[j], _state); - } - } - - /* - * Skip points with zero distance if self-matches are turned off - */ - if( ae_fp_eq(ptdist,0)&&!kdt->selfmatch ) - { - continue; - } - - /* - * We CAN'T process point if R-criterion isn't satisfied, - * i.e. (RNeeded<>0) AND (PtDist>R). - */ - if( ae_fp_eq(kdt->rneeded,0)||ae_fp_less_eq(ptdist,kdt->rneeded) ) - { - - /* - * R-criterion is satisfied, we must either: - * * replace worst point, if (KNeeded<>0) AND (KCur=KNeeded) - * (or skip, if worst point is better) - * * add point without replacement otherwise - */ - if( kdt->kcurkneeded||kdt->kneeded==0 ) - { - - /* - * add current point to heap without replacement - */ - tagheappushi(&kdt->r, &kdt->idx, &kdt->kcur, ptdist, i, _state); - } - else - { - - /* - * New points are added or not, depending on their distance. - * If added, they replace element at the top of the heap - */ - if( ae_fp_less(ptdist,kdt->r.ptr.p_double[0]) ) - { - if( kdt->kneeded==1 ) - { - kdt->idx.ptr.p_int[0] = i; - kdt->r.ptr.p_double[0] = ptdist; - } - else - { - tagheapreplacetopi(&kdt->r, &kdt->idx, kdt->kneeded, ptdist, i, _state); - } - } - } - } - } - return; - } - - /* - * Simple split - */ - if( kdt->nodes.ptr.p_int[offs]==0 ) - { - - /* - * Load: - * * D dimension to split - * * S split position - */ - d = kdt->nodes.ptr.p_int[offs+1]; - s = kdt->splits.ptr.p_double[kdt->nodes.ptr.p_int[offs+2]]; - - /* - * Calculate: - * * ChildBestOffs child box with best chances - * * ChildWorstOffs child box with worst chances - */ - if( ae_fp_less_eq(kdt->x.ptr.p_double[d],s) ) - { - childbestoffs = kdt->nodes.ptr.p_int[offs+3]; - childworstoffs = kdt->nodes.ptr.p_int[offs+4]; - bestisleft = ae_true; - } - else - { - childbestoffs = kdt->nodes.ptr.p_int[offs+4]; - childworstoffs = kdt->nodes.ptr.p_int[offs+3]; - bestisleft = ae_false; - } - - /* - * Navigate through childs - */ - for(i=0; i<=1; i++) - { - - /* - * Select child to process: - * * ChildOffs current child offset in Nodes[] - * * UpdateMin whether minimum or maximum value - * of bounding box is changed on update - */ - if( i==0 ) - { - childoffs = childbestoffs; - updatemin = !bestisleft; - } - else - { - updatemin = bestisleft; - childoffs = childworstoffs; - } - - /* - * Update bounding box and current distance - */ - if( updatemin ) - { - prevdist = kdt->curdist; - t1 = kdt->x.ptr.p_double[d]; - v = kdt->curboxmin.ptr.p_double[d]; - if( ae_fp_less_eq(t1,s) ) - { - if( kdt->normtype==0 ) - { - kdt->curdist = ae_maxreal(kdt->curdist, s-t1, _state); - } - if( kdt->normtype==1 ) - { - kdt->curdist = kdt->curdist-ae_maxreal(v-t1, 0, _state)+s-t1; - } - if( kdt->normtype==2 ) - { - kdt->curdist = kdt->curdist-ae_sqr(ae_maxreal(v-t1, 0, _state), _state)+ae_sqr(s-t1, _state); - } - } - kdt->curboxmin.ptr.p_double[d] = s; - } - else - { - prevdist = kdt->curdist; - t1 = kdt->x.ptr.p_double[d]; - v = kdt->curboxmax.ptr.p_double[d]; - if( ae_fp_greater_eq(t1,s) ) - { - if( kdt->normtype==0 ) - { - kdt->curdist = ae_maxreal(kdt->curdist, t1-s, _state); - } - if( kdt->normtype==1 ) - { - kdt->curdist = kdt->curdist-ae_maxreal(t1-v, 0, _state)+t1-s; - } - if( kdt->normtype==2 ) - { - kdt->curdist = kdt->curdist-ae_sqr(ae_maxreal(t1-v, 0, _state), _state)+ae_sqr(t1-s, _state); - } - } - kdt->curboxmax.ptr.p_double[d] = s; - } - - /* - * Decide: to dive into cell or not to dive - */ - if( ae_fp_neq(kdt->rneeded,0)&&ae_fp_greater(kdt->curdist,kdt->rneeded) ) - { - todive = ae_false; - } - else - { - if( kdt->kcurkneeded||kdt->kneeded==0 ) - { - - /* - * KCurcurdist,kdt->r.ptr.p_double[0]*kdt->approxf); - } - } - if( todive ) - { - nearestneighbor_kdtreequerynnrec(kdt, childoffs, _state); - } - - /* - * Restore bounding box and distance - */ - if( updatemin ) - { - kdt->curboxmin.ptr.p_double[d] = v; - } - else - { - kdt->curboxmax.ptr.p_double[d] = v; - } - kdt->curdist = prevdist; - } - return; - } -} - - -/************************************************************************* -Copies X[] to KDT.X[] -Loads distance from X[] to bounding box. -Initializes CurBox[]. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreeinitbox(kdtree* kdt, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t i; - double vx; - double vmin; - double vmax; - - - ae_assert(kdt->n>0, "KDTreeInitBox: internal error", _state); - - /* - * calculate distance from point to current bounding box - */ - kdt->curdist = 0; - if( kdt->normtype==0 ) - { - for(i=0; i<=kdt->nx-1; i++) - { - vx = x->ptr.p_double[i]; - vmin = kdt->boxmin.ptr.p_double[i]; - vmax = kdt->boxmax.ptr.p_double[i]; - kdt->x.ptr.p_double[i] = vx; - kdt->curboxmin.ptr.p_double[i] = vmin; - kdt->curboxmax.ptr.p_double[i] = vmax; - if( ae_fp_less(vx,vmin) ) - { - kdt->curdist = ae_maxreal(kdt->curdist, vmin-vx, _state); - } - else - { - if( ae_fp_greater(vx,vmax) ) - { - kdt->curdist = ae_maxreal(kdt->curdist, vx-vmax, _state); - } - } - } - } - if( kdt->normtype==1 ) - { - for(i=0; i<=kdt->nx-1; i++) - { - vx = x->ptr.p_double[i]; - vmin = kdt->boxmin.ptr.p_double[i]; - vmax = kdt->boxmax.ptr.p_double[i]; - kdt->x.ptr.p_double[i] = vx; - kdt->curboxmin.ptr.p_double[i] = vmin; - kdt->curboxmax.ptr.p_double[i] = vmax; - if( ae_fp_less(vx,vmin) ) - { - kdt->curdist = kdt->curdist+vmin-vx; - } - else - { - if( ae_fp_greater(vx,vmax) ) - { - kdt->curdist = kdt->curdist+vx-vmax; - } - } - } - } - if( kdt->normtype==2 ) - { - for(i=0; i<=kdt->nx-1; i++) - { - vx = x->ptr.p_double[i]; - vmin = kdt->boxmin.ptr.p_double[i]; - vmax = kdt->boxmax.ptr.p_double[i]; - kdt->x.ptr.p_double[i] = vx; - kdt->curboxmin.ptr.p_double[i] = vmin; - kdt->curboxmax.ptr.p_double[i] = vmax; - if( ae_fp_less(vx,vmin) ) - { - kdt->curdist = kdt->curdist+ae_sqr(vmin-vx, _state); - } - else - { - if( ae_fp_greater(vx,vmax) ) - { - kdt->curdist = kdt->curdist+ae_sqr(vx-vmax, _state); - } - } - } - } -} - - -/************************************************************************* -This function allocates all dataset-independent array fields of KDTree, -i.e. such array fields that their dimensions do not depend on dataset -size. - -This function do not sets KDT.NX or KDT.NY - it just allocates arrays - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, - ae_int_t nx, - ae_int_t ny, - ae_state *_state) -{ - - - ae_assert(kdt->n>0, "KDTreeAllocDatasetIndependent: internal error", _state); - ae_vector_set_length(&kdt->x, nx, _state); - ae_vector_set_length(&kdt->boxmin, nx, _state); - ae_vector_set_length(&kdt->boxmax, nx, _state); - ae_vector_set_length(&kdt->curboxmin, nx, _state); - ae_vector_set_length(&kdt->curboxmax, nx, _state); -} - - -/************************************************************************* -This function allocates all dataset-dependent array fields of KDTree, i.e. -such array fields that their dimensions depend on dataset size. - -This function do not sets KDT.N, KDT.NX or KDT.NY - -it just allocates arrays. - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_state *_state) -{ - - - ae_assert(n>0, "KDTreeAllocDatasetDependent: internal error", _state); - ae_matrix_set_length(&kdt->xy, n, 2*nx+ny, _state); - ae_vector_set_length(&kdt->tags, n, _state); - ae_vector_set_length(&kdt->idx, n, _state); - ae_vector_set_length(&kdt->r, n, _state); - ae_vector_set_length(&kdt->x, nx, _state); - ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state); - ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*n, _state); - ae_vector_set_length(&kdt->splits, 2*n, _state); -} - - -/************************************************************************* -This function allocates temporaries. - -This function do not sets KDT.N, KDT.NX or KDT.NY - -it just allocates arrays. - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -static void nearestneighbor_kdtreealloctemporaries(kdtree* kdt, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_state *_state) -{ - - - ae_assert(n>0, "KDTreeAllocTemporaries: internal error", _state); - ae_vector_set_length(&kdt->x, nx, _state); - ae_vector_set_length(&kdt->idx, n, _state); - ae_vector_set_length(&kdt->r, n, _state); - ae_vector_set_length(&kdt->buf, ae_maxint(n, nx, _state), _state); - ae_vector_set_length(&kdt->curboxmin, nx, _state); - ae_vector_set_length(&kdt->curboxmax, nx, _state); -} - - -ae_bool _kdtree_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - kdtree *p = (kdtree*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tags, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->boxmin, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->boxmax, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->nodes, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->splits, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->buf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _kdtree_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - kdtree *dst = (kdtree*)_dst; - kdtree *src = (kdtree*)_src; - dst->n = src->n; - dst->nx = src->nx; - dst->ny = src->ny; - dst->normtype = src->normtype; - if( !ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tags, &src->tags, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->boxmin, &src->boxmin, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->boxmax, &src->boxmax, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->nodes, &src->nodes, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->splits, &src->splits, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->kneeded = src->kneeded; - dst->rneeded = src->rneeded; - dst->selfmatch = src->selfmatch; - dst->approxf = src->approxf; - dst->kcur = src->kcur; - if( !ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->buf, &src->buf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic) ) - return ae_false; - dst->curdist = src->curdist; - dst->debugcounter = src->debugcounter; - return ae_true; -} - - -void _kdtree_clear(void* _p) -{ - kdtree *p = (kdtree*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->xy); - ae_vector_clear(&p->tags); - ae_vector_clear(&p->boxmin); - ae_vector_clear(&p->boxmax); - ae_vector_clear(&p->nodes); - ae_vector_clear(&p->splits); - ae_vector_clear(&p->x); - ae_vector_clear(&p->idx); - ae_vector_clear(&p->r); - ae_vector_clear(&p->buf); - ae_vector_clear(&p->curboxmin); - ae_vector_clear(&p->curboxmax); -} - - -void _kdtree_destroy(void* _p) -{ - kdtree *p = (kdtree*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->xy); - ae_vector_destroy(&p->tags); - ae_vector_destroy(&p->boxmin); - ae_vector_destroy(&p->boxmax); - ae_vector_destroy(&p->nodes); - ae_vector_destroy(&p->splits); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->idx); - ae_vector_destroy(&p->r); - ae_vector_destroy(&p->buf); - ae_vector_destroy(&p->curboxmin); - ae_vector_destroy(&p->curboxmax); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "alglibmisc.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebuginitrecord1(xdebugrecord1 &rec1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebuginitrecord1(rec1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebugupdaterecord1(xdebugrecord1 &rec1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugupdaterecord1(rec1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 1D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb1count(const boolean_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::xdebugb1count(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1not(boolean_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb1not(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1appendcopy(boolean_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb1appendcopy(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered elements set to True. +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1outeven(const ae_int_t n, boolean_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb1outeven(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi1sum(const integer_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::xdebugi1sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1neg(integer_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi1neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1appendcopy(integer_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi1appendcopy(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I, and odd-numbered +ones set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1outeven(const ae_int_t n, integer_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi1outeven(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1sum(const real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::xdebugr1sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1internalcopyandsum(const real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::xdebugr1internalcopyandsum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1neg(real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr1neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1appendcopy(real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr1appendcopy(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I*0.25, +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1outeven(const ae_int_t n, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr1outeven(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +alglib::complex xdebugc1sum(const complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::xdebugc1sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return alglib::complex(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1neg(complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc1neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1appendcopy(complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc1appendcopy(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1outeven(const ae_int_t n, complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc1outeven(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 2D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb2count(const boolean_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::xdebugb2count(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2not(boolean_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb2not(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2transpose(boolean_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb2transpose(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2outsin(const ae_int_t m, const ae_int_t n, boolean_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugb2outsin(m, n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi2sum(const integer_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::xdebugi2sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2neg(integer_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi2neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2transpose(integer_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi2transpose(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2outsin(const ae_int_t m, const ae_int_t n, integer_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugi2outsin(m, n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2sum(const real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::xdebugr2sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of a. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2internalcopyandsum(const real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::xdebugr2internalcopyandsum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2neg(real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr2neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2transpose(real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr2transpose(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2outsin(const ae_int_t m, const ae_int_t n, real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugr2outsin(m, n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +alglib::complex xdebugc2sum(const complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::xdebugc2sum(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return alglib::complex(result); +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2neg(complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc2neg(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2transpose(complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc2transpose(a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2outsincos(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::xdebugc2outsincos(m, n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugmaskedbiasedproductsum(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const real_2d_array &b, const boolean_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::xdebugmaskedbiasedproductsum(m, n, a.c_ptr(), b.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + + +/************************************************************************* +This is a debug class intended for testing ALGLIB interface generator. +Never use it in any real life project. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +_xdebugrecord1_owner::_xdebugrecord1_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_xdebugrecord1_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::xdebugrecord1*)alglib_impl::ae_malloc(sizeof(alglib_impl::xdebugrecord1), &_state); + memset(p_struct, 0, sizeof(alglib_impl::xdebugrecord1)); + alglib_impl::_xdebugrecord1_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_xdebugrecord1_owner::_xdebugrecord1_owner(alglib_impl::xdebugrecord1 *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_xdebugrecord1_owner::_xdebugrecord1_owner(const _xdebugrecord1_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_xdebugrecord1_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: xdebugrecord1 copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::xdebugrecord1*)alglib_impl::ae_malloc(sizeof(alglib_impl::xdebugrecord1), &_state); + memset(p_struct, 0, sizeof(alglib_impl::xdebugrecord1)); + alglib_impl::_xdebugrecord1_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_xdebugrecord1_owner& _xdebugrecord1_owner::operator=(const _xdebugrecord1_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: xdebugrecord1 assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: xdebugrecord1 assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: xdebugrecord1 assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_xdebugrecord1_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::xdebugrecord1)); + alglib_impl::_xdebugrecord1_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_xdebugrecord1_owner::~_xdebugrecord1_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_xdebugrecord1_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::xdebugrecord1* _xdebugrecord1_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::xdebugrecord1* _xdebugrecord1_owner::c_ptr() const +{ + return p_struct; +} +xdebugrecord1::xdebugrecord1() : _xdebugrecord1_owner() ,i(p_struct->i),c(*((alglib::complex*)(&p_struct->c))),a(&p_struct->a) +{ +} + +xdebugrecord1::xdebugrecord1(alglib_impl::xdebugrecord1 *attach_to):_xdebugrecord1_owner(attach_to) ,i(p_struct->i),c(*((alglib::complex*)(&p_struct->c))),a(&p_struct->a) +{ +} + +xdebugrecord1::xdebugrecord1(const xdebugrecord1 &rhs):_xdebugrecord1_owner(rhs) ,i(p_struct->i),c(*((alglib::complex*)(&p_struct->c))),a(&p_struct->a) +{ +} + +xdebugrecord1& xdebugrecord1::operator=(const xdebugrecord1 &rhs) +{ + if( this==&rhs ) + return *this; + _xdebugrecord1_owner::operator=(rhs); + return *this; +} + +xdebugrecord1::~xdebugrecord1() +{ +} +#endif + +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +HQRNDState initialization with random values which come from standard +RNG. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndrandomize(hqrndstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndrandomize(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +HQRNDState initialization with seed values + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndseed(s1, s2, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function generates random real number in (0,1), +not including interval boundaries + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrnduniformr(hqrndstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hqrnduniformr(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function generates random integer number in [0, N) + +1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() +2. N can be any positive number except for very large numbers: + * close to 2^31 on 32-bit systems + * close to 2^62 on 64-bit systems + An exception will be generated if N is too large. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_int_t hqrnduniformi(hqrndstate &state, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::hqrnduniformi(state.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Random number generator: normal numbers + +This function generates one random number from normal distribution. +Its performance is equal to that of HQRNDNormal2() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrndnormal(hqrndstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hqrndnormal(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Random number generator: vector with random entries (normal distribution) + +This function generates N random numbers from normal distribution. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalv(hqrndstate &state, const ae_int_t n, real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndnormalv(state.c_ptr(), n, x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Random number generator: matrix with random entries (normal distribution) + +This function generates MxN random matrix. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalm(hqrndstate &state, const ae_int_t m, const ae_int_t n, real_2d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndnormalm(state.c_ptr(), m, n, x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Random number generator: random X and Y such that X^2+Y^2=1 + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndunit2(hqrndstate &state, double &x, double &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndunit2(state.c_ptr(), &x, &y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Random number generator: normal numbers + +This function generates two independent random numbers from normal +distribution. Its performance is equal to that of HQRNDNormal() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormal2(hqrndstate &state, double &x1, double &x2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hqrndnormal2(state.c_ptr(), &x1, &x2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Random number generator: exponential distribution + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 11.08.2007 by Bochkanov Sergey +*************************************************************************/ +double hqrndexponential(hqrndstate &state, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hqrndexponential(state.c_ptr(), lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function generates random number from discrete distribution given by +finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample + N - number of elements to use, N>=1 + +RESULT + this function returns one of the X[i] for random i=0..N-1 + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrnddiscrete(hqrndstate &state, const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hqrnddiscrete(state.c_ptr(), x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function generates random number from continuous distribution given +by finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample, array[N] (can be larger, in this case only + leading N elements are used). THIS ARRAY MUST BE SORTED BY + ASCENDING. + N - number of elements to use, N>=1 + +RESULT + this function returns random number from continuous distribution which + tries to approximate X as mush as possible. min(X)<=Result<=max(X). + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrndcontinuous(hqrndstate &state, const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hqrndcontinuous(state.c_ptr(), x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + + +/************************************************************************* +Portable high quality random number generator state. +Initialized with HQRNDRandomize() or HQRNDSeed(). + +Fields: + S1, S2 - seed values + V - precomputed value + MagicV - 'magic' value used to determine whether State structure + was correctly initialized. +*************************************************************************/ +_hqrndstate_owner::_hqrndstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_hqrndstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::hqrndstate)); + alglib_impl::_hqrndstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_hqrndstate_owner::_hqrndstate_owner(alglib_impl::hqrndstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_hqrndstate_owner::_hqrndstate_owner(const _hqrndstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_hqrndstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: hqrndstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::hqrndstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::hqrndstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::hqrndstate)); + alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_hqrndstate_owner& _hqrndstate_owner::operator=(const _hqrndstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: hqrndstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: hqrndstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: hqrndstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_hqrndstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::hqrndstate)); + alglib_impl::_hqrndstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_hqrndstate_owner::~_hqrndstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_hqrndstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::hqrndstate* _hqrndstate_owner::c_ptr() const +{ + return p_struct; +} +hqrndstate::hqrndstate() : _hqrndstate_owner() +{ +} + +hqrndstate::hqrndstate(alglib_impl::hqrndstate *attach_to):_hqrndstate_owner(attach_to) +{ +} + +hqrndstate::hqrndstate(const hqrndstate &rhs):_hqrndstate_owner(rhs) +{ +} + +hqrndstate& hqrndstate::operator=(const hqrndstate &rhs) +{ + if( this==&rhs ) + return *this; + _hqrndstate_owner::operator=(rhs); + return *this; +} + +hqrndstate::~hqrndstate() +{ +} +#endif + +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void kdtreeserialize(const kdtree &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::kdtreealloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::kdtreeserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void kdtreeserialize(const kdtree &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::kdtreealloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::kdtreeserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void kdtreeunserialize(const std::string &s_in, kdtree &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::kdtreeunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void kdtreeunserialize(const std::istream &s_in, kdtree &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::kdtreeunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values and optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + N - number of points, N>=0. + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreebuild(xy.c_ptr(), n, nx, ny, normtype, kdt.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values and optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + N - number of points, N>=0. + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreebuild(xy.c_ptr(), n, nx, ny, normtype, kdt.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values, integer tags and +optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + Tags - tags, array[0..N-1], contains integer tags associated + with points. + N - number of points, N>=0 + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreebuildtagged(xy.c_ptr(), tags.c_ptr(), n, nx, ny, normtype, kdt.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values, integer tags and +optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + Tags - tags, array[0..N-1], contains integer tags associated + with points. + N - number of points, N>=0 + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (xy.rows()!=tags.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'kdtreebuildtagged': looks like one of arguments has wrong size"); + n = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreebuildtagged(xy.c_ptr(), tags.c_ptr(), n, nx, ny, normtype, kdt.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel KD-tree requests. + +KD-tree subpackage provides two sets of request functions - ones which use +internal buffer of KD-tree object (these functions are single-threaded +because they use same buffer, which can not shared between threads), and +ones which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + KDT - KD-tree which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: KD-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreecreaterequestbuffer(const kdtree &kdt, kdtreerequestbuffer &buf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreecreaterequestbuffer(kdt.c_ptr(), buf.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +K-NN query: K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(kdt.c_ptr(), x.c_ptr(), k, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +K-NN query: K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreequeryknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryknn(kdt.c_ptr(), x.c_ptr(), k, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +K-NN query: K nearest neighbors, using external thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - kd-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryknn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), k, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +K-NN query: K nearest neighbors, using external thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - kd-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreetsqueryknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryknn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), k, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, ordered by distance +between point and X (by ascending). + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnn(kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(kdt.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, ordered by distance +between point and X (by ascending). + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreequeryrnn(kdtree &kdt, const real_1d_array &x, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnn(kdt.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, no ordering by +distance as undicated by "U" suffix (faster that ordered query, for large +queries - significantly faster). + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + + -- ALGLIB -- + Copyright 01.11.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnnu(kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnnu(kdt.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, no ordering by +distance as undicated by "U" suffix (faster that ordered query, for large +queries - significantly faster). + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + + -- ALGLIB -- + Copyright 01.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreequeryrnnu(kdtree &kdt, const real_1d_array &x, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryrnnu(kdt.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, sorted by distance between point and X (by ascending) + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryrnn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, sorted by distance between point and X (by ascending) + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreetsqueryrnn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryrnn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, no ordering by distance as undicated by "U" suffix +(faster that ordered query, for large queries - significantly faster). + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnnu(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryrnnu(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, no ordering by distance as undicated by "U" suffix +(faster that ordered query, for large queries - significantly faster). + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreetsqueryrnnu(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryrnnu(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), r, selfmatch, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +K-NN query: approximate K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryAKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryaknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(kdt.c_ptr(), x.c_ptr(), k, selfmatch, eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +K-NN query: approximate K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryAKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreequeryaknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequeryaknn(kdt.c_ptr(), x.c_ptr(), k, selfmatch, eps, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +K-NN query: approximate K nearest neighbors, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryaknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryaknn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), k, selfmatch, eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +K-NN query: approximate K nearest neighbors, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +ae_int_t kdtreetsqueryaknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + bool selfmatch; + + selfmatch = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsqueryaknn(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), k, selfmatch, eps, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Box query: all points within user-specified box. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryBox() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() returns zeros for this request + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequerybox(kdtree &kdt, const real_1d_array &boxmin, const real_1d_array &boxmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreequerybox(kdt.c_ptr(), boxmin.c_ptr(), boxmax.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Box query: all points within user-specified box, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "ts" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() returns zeros for this query + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsquerybox(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &boxmin, const real_1d_array &boxmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::kdtreetsquerybox(kdt.c_ptr(), buf.c_ptr(), boxmin.c_ptr(), boxmax.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +X-values from last query. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsx(). + +INPUT PARAMETERS + KDT - KD-tree + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsx(kdt.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +X- and Y-values from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsxy(). + +INPUT PARAMETERS + KDT - KD-tree + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsxy(kdt.c_ptr(), xy.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Tags from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultstags(kdt.c_ptr(), tags.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Distances from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsdistances(kdt.c_ptr(), r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +X-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsx(const kdtree &kdt, const kdtreerequestbuffer &buf, real_2d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreetsqueryresultsx(kdt.c_ptr(), buf.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +X- and Y-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsxy(const kdtree &kdt, const kdtreerequestbuffer &buf, real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreetsqueryresultsxy(kdt.c_ptr(), buf.c_ptr(), xy.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Tags from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultstags(const kdtree &kdt, const kdtreerequestbuffer &buf, integer_1d_array &tags, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreetsqueryresultstags(kdt.c_ptr(), buf.c_ptr(), tags.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Distances from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsdistances(const kdtree &kdt, const kdtreerequestbuffer &buf, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreetsqueryresultsdistances(kdt.c_ptr(), buf.c_ptr(), r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +X-values from last query; 'interactive' variant for languages like Python +which support constructs like "X = KDTreeQueryResultsXI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsxi(kdt.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +XY-values from last query; 'interactive' variant for languages like Python +which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsxyi(kdt.c_ptr(), xy.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Tags from last query; 'interactive' variant for languages like Python +which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultstagsi(kdt.c_ptr(), tags.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Distances from last query; 'interactive' variant for languages like Python +which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" +and interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kdtreequeryresultsdistancesi(kdt.c_ptr(), r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Buffer object which is used to perform nearest neighbor requests in the +multithreaded mode (multiple threads working with same KD-tree object). + +This object should be created with KDTreeCreateRequestBuffer(). +*************************************************************************/ +_kdtreerequestbuffer_owner::_kdtreerequestbuffer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kdtreerequestbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::kdtreerequestbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtreerequestbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kdtreerequestbuffer)); + alglib_impl::_kdtreerequestbuffer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kdtreerequestbuffer_owner::_kdtreerequestbuffer_owner(alglib_impl::kdtreerequestbuffer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_kdtreerequestbuffer_owner::_kdtreerequestbuffer_owner(const _kdtreerequestbuffer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kdtreerequestbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kdtreerequestbuffer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::kdtreerequestbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtreerequestbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kdtreerequestbuffer)); + alglib_impl::_kdtreerequestbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kdtreerequestbuffer_owner& _kdtreerequestbuffer_owner::operator=(const _kdtreerequestbuffer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: kdtreerequestbuffer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kdtreerequestbuffer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: kdtreerequestbuffer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_kdtreerequestbuffer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::kdtreerequestbuffer)); + alglib_impl::_kdtreerequestbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_kdtreerequestbuffer_owner::~_kdtreerequestbuffer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_kdtreerequestbuffer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::kdtreerequestbuffer* _kdtreerequestbuffer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::kdtreerequestbuffer* _kdtreerequestbuffer_owner::c_ptr() const +{ + return p_struct; +} +kdtreerequestbuffer::kdtreerequestbuffer() : _kdtreerequestbuffer_owner() +{ +} + +kdtreerequestbuffer::kdtreerequestbuffer(alglib_impl::kdtreerequestbuffer *attach_to):_kdtreerequestbuffer_owner(attach_to) +{ +} + +kdtreerequestbuffer::kdtreerequestbuffer(const kdtreerequestbuffer &rhs):_kdtreerequestbuffer_owner(rhs) +{ +} + +kdtreerequestbuffer& kdtreerequestbuffer::operator=(const kdtreerequestbuffer &rhs) +{ + if( this==&rhs ) + return *this; + _kdtreerequestbuffer_owner::operator=(rhs); + return *this; +} + +kdtreerequestbuffer::~kdtreerequestbuffer() +{ +} + + + + +/************************************************************************* +KD-tree object. +*************************************************************************/ +_kdtree_owner::_kdtree_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kdtree_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kdtree)); + alglib_impl::_kdtree_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kdtree_owner::_kdtree_owner(alglib_impl::kdtree *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_kdtree_owner::_kdtree_owner(const _kdtree_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kdtree_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kdtree copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::kdtree*)alglib_impl::ae_malloc(sizeof(alglib_impl::kdtree), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kdtree)); + alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kdtree_owner& _kdtree_owner::operator=(const _kdtree_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: kdtree assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kdtree assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: kdtree assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_kdtree_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::kdtree)); + alglib_impl::_kdtree_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_kdtree_owner::~_kdtree_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_kdtree_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::kdtree* _kdtree_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::kdtree* _kdtree_owner::c_ptr() const +{ + return p_struct; +} +kdtree::kdtree() : _kdtree_owner() +{ +} + +kdtree::kdtree(alglib_impl::kdtree *attach_to):_kdtree_owner(attach_to) +{ +} + +kdtree::kdtree(const kdtree &rhs):_kdtree_owner(rhs) +{ +} + +kdtree& kdtree::operator=(const kdtree &rhs) +{ + if( this==&rhs ) + return *this; + _kdtree_owner::operator=(rhs); + return *this; +} + +kdtree::~kdtree() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +static ae_int_t hqrnd_hqrndmax = 2147483561; +static ae_int_t hqrnd_hqrndm1 = 2147483563; +static ae_int_t hqrnd_hqrndm2 = 2147483399; +static ae_int_t hqrnd_hqrndmagic = 1634357784; + + +#endif +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +static ae_int_t nearestneighbor_splitnodesize = 6; +static ae_int_t nearestneighbor_kdtreefirstversion = 0; +static ae_int_t nearestneighbor_tsqueryrnn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_bool orderedbydist, + ae_state *_state); +static void nearestneighbor_kdtreesplit(kdtree* kdt, + ae_int_t i1, + ae_int_t i2, + ae_int_t d, + double s, + ae_int_t* i3, + ae_state *_state); +static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, + ae_int_t* nodesoffs, + ae_int_t* splitsoffs, + ae_int_t i1, + ae_int_t i2, + ae_int_t maxleafsize, + ae_state *_state); +static void nearestneighbor_kdtreequerynnrec(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_int_t offs, + ae_state *_state); +static void nearestneighbor_kdtreequeryboxrec(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_int_t offs, + ae_state *_state); +static void nearestneighbor_kdtreeinitbox(const kdtree* kdt, + /* Real */ const ae_vector* x, + kdtreerequestbuffer* buf, + ae_state *_state); +static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, + ae_int_t nx, + ae_int_t ny, + ae_state *_state); +static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_state *_state); +static void nearestneighbor_checkrequestbufferconsistency(const kdtree* kdt, + const kdtreerequestbuffer* buf, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebuginitrecord1(xdebugrecord1* rec1, ae_state *_state) +{ + + _xdebugrecord1_clear(rec1); + + rec1->i = 1; + rec1->c.x = (double)(1); + rec1->c.y = (double)(1); + ae_vector_set_length(&rec1->a, 2, _state); + rec1->a.ptr.p_double[0] = (double)(2); + rec1->a.ptr.p_double[1] = (double)(3); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebugupdaterecord1(xdebugrecord1* rec1, ae_state *_state) +{ + + + rec1->i = rec1->i+1; + rec1->c.x = rec1->c.x+(double)2; + rec1->c.y = rec1->c.y+(double)3; + rvectorresize(&rec1->a, rec1->a.cnt+1, _state); + rec1->a.ptr.p_double[rec1->a.cnt-1] = rec1->a.ptr.p_double[rec1->a.cnt-2]+(double)3; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 1D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb1count(/* Boolean */ const ae_vector* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t result; + + + result = 0; + for(i=0; i<=a->cnt-1; i++) + { + if( a->ptr.p_bool[i] ) + { + result = result+1; + } + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1not(/* Boolean */ ae_vector* a, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_bool[i] = !a->ptr.p_bool[i]; + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1appendcopy(/* Boolean */ ae_vector* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_vector_init(&b, 0, DT_BOOL, _state, ae_true); + + ae_vector_set_length(&b, a->cnt, _state); + for(i=0; i<=b.cnt-1; i++) + { + b.ptr.p_bool[i] = a->ptr.p_bool[i]; + } + ae_vector_set_length(a, 2*b.cnt, _state); + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_bool[i] = b.ptr.p_bool[i%b.cnt]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered elements set to True. +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1outeven(ae_int_t n, + /* Boolean */ ae_vector* a, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(a); + + ae_vector_set_length(a, n, _state); + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_bool[i] = i%2==0; + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi1sum(/* Integer */ const ae_vector* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t result; + + + result = 0; + for(i=0; i<=a->cnt-1; i++) + { + result = result+a->ptr.p_int[i]; + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1neg(/* Integer */ ae_vector* a, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_int[i] = -a->ptr.p_int[i]; + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1appendcopy(/* Integer */ ae_vector* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_vector_init(&b, 0, DT_INT, _state, ae_true); + + ae_vector_set_length(&b, a->cnt, _state); + for(i=0; i<=b.cnt-1; i++) + { + b.ptr.p_int[i] = a->ptr.p_int[i]; + } + ae_vector_set_length(a, 2*b.cnt, _state); + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_int[i] = b.ptr.p_int[i%b.cnt]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I, and odd-numbered +ones set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1outeven(ae_int_t n, + /* Integer */ ae_vector* a, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(a); + + ae_vector_set_length(a, n, _state); + for(i=0; i<=a->cnt-1; i++) + { + if( i%2==0 ) + { + a->ptr.p_int[i] = i; + } + else + { + a->ptr.p_int[i] = 0; + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1sum(/* Real */ const ae_vector* a, ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=0; i<=a->cnt-1; i++) + { + result = result+a->ptr.p_double[i]; + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1internalcopyandsum(/* Real */ const ae_vector* _a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_int_t i; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_vector_init_copy(&a, _a, _state, ae_true); + + result = (double)(0); + for(i=0; i<=a.cnt-1; i++) + { + result = result+a.ptr.p_double[i]; + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1neg(/* Real */ ae_vector* a, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_double[i] = -a->ptr.p_double[i]; + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1appendcopy(/* Real */ ae_vector* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&b, a->cnt, _state); + for(i=0; i<=b.cnt-1; i++) + { + b.ptr.p_double[i] = a->ptr.p_double[i]; + } + ae_vector_set_length(a, 2*b.cnt, _state); + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_double[i] = b.ptr.p_double[i%b.cnt]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I*0.25, +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1outeven(ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(a); + + ae_vector_set_length(a, n, _state); + for(i=0; i<=a->cnt-1; i++) + { + if( i%2==0 ) + { + a->ptr.p_double[i] = (double)i*0.25; + } + else + { + a->ptr.p_double[i] = (double)(0); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_complex xdebugc1sum(/* Complex */ const ae_vector* a, ae_state *_state) +{ + ae_int_t i; + ae_complex result; + + + result = ae_complex_from_i(0); + for(i=0; i<=a->cnt-1; i++) + { + result = ae_c_add(result,a->ptr.p_complex[i]); + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1neg(/* Complex */ ae_vector* a, ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_complex[i] = ae_c_neg(a->ptr.p_complex[i]); + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1appendcopy(/* Complex */ ae_vector* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); + + ae_vector_set_length(&b, a->cnt, _state); + for(i=0; i<=b.cnt-1; i++) + { + b.ptr.p_complex[i] = a->ptr.p_complex[i]; + } + ae_vector_set_length(a, 2*b.cnt, _state); + for(i=0; i<=a->cnt-1; i++) + { + a->ptr.p_complex[i] = b.ptr.p_complex[i%b.cnt]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1outeven(ae_int_t n, + /* Complex */ ae_vector* a, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(a); + + ae_vector_set_length(a, n, _state); + for(i=0; i<=a->cnt-1; i++) + { + if( i%2==0 ) + { + a->ptr.p_complex[i].x = (double)i*0.250; + a->ptr.p_complex[i].y = (double)i*0.125; + } + else + { + a->ptr.p_complex[i] = ae_complex_from_i(0); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 2D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb2count(/* Boolean */ const ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t result; + + + result = 0; + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + if( a->ptr.pp_bool[i][j] ) + { + result = result+1; + } + } + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2not(/* Boolean */ ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_bool[i][j] = !a->ptr.pp_bool[i][j]; + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2transpose(/* Boolean */ ae_matrix* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_matrix b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_matrix_init(&b, 0, 0, DT_BOOL, _state, ae_true); + + ae_matrix_set_length(&b, a->rows, a->cols, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + b.ptr.pp_bool[i][j] = a->ptr.pp_bool[i][j]; + } + } + ae_matrix_set_length(a, b.cols, b.rows, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + a->ptr.pp_bool[j][i] = b.ptr.pp_bool[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2outsin(ae_int_t m, + ae_int_t n, + /* Boolean */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_matrix_set_length(a, m, n, _state); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_bool[i][j] = ae_fp_greater(ae_sin((double)(3*i+5*j), _state),(double)(0)); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi2sum(/* Integer */ const ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t result; + + + result = 0; + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + result = result+a->ptr.pp_int[i][j]; + } + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2neg(/* Integer */ ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_int[i][j] = -a->ptr.pp_int[i][j]; + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2transpose(/* Integer */ ae_matrix* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_matrix b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_matrix_init(&b, 0, 0, DT_INT, _state, ae_true); + + ae_matrix_set_length(&b, a->rows, a->cols, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + b.ptr.pp_int[i][j] = a->ptr.pp_int[i][j]; + } + } + ae_matrix_set_length(a, b.cols, b.rows, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + a->ptr.pp_int[j][i] = b.ptr.pp_int[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2outsin(ae_int_t m, + ae_int_t n, + /* Integer */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_matrix_set_length(a, m, n, _state); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_int[i][j] = ae_sign(ae_sin((double)(3*i+5*j), _state), _state); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2sum(/* Real */ const ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double result; + + + result = (double)(0); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + result = result+a->ptr.pp_double[i][j]; + } + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of a. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2internalcopyandsum(/* Real */ const ae_matrix* _a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + result = (double)(0); + for(i=0; i<=a.rows-1; i++) + { + for(j=0; j<=a.cols-1; j++) + { + result = result+a.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2neg(/* Real */ ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_double[i][j] = -a->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2transpose(/* Real */ ae_matrix* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_matrix b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_matrix_init(&b, 0, 0, DT_REAL, _state, ae_true); + + ae_matrix_set_length(&b, a->rows, a->cols, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + b.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; + } + } + ae_matrix_set_length(a, b.cols, b.rows, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + a->ptr.pp_double[j][i] = b.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2outsin(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_matrix_set_length(a, m, n, _state); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_double[i][j] = ae_sin((double)(3*i+5*j), _state); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_complex xdebugc2sum(/* Complex */ const ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex result; + + + result = ae_complex_from_i(0); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + result = ae_c_add(result,a->ptr.pp_complex[i][j]); + } + } + return result; +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2neg(/* Complex */ ae_matrix* a, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_complex[i][j] = ae_c_neg(a->ptr.pp_complex[i][j]); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2transpose(/* Complex */ ae_matrix* a, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_matrix b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_matrix_init(&b, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_matrix_set_length(&b, a->rows, a->cols, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + b.ptr.pp_complex[i][j] = a->ptr.pp_complex[i][j]; + } + } + ae_matrix_set_length(a, b.cols, b.rows, _state); + for(i=0; i<=b.rows-1; i++) + { + for(j=0; j<=b.cols-1; j++) + { + a->ptr.pp_complex[j][i] = b.ptr.pp_complex[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2outsincos(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_matrix_set_length(a, m, n, _state); + for(i=0; i<=a->rows-1; i++) + { + for(j=0; j<=a->cols-1; j++) + { + a->ptr.pp_complex[i][j].x = ae_sin((double)(3*i+5*j), _state); + a->ptr.pp_complex[i][j].y = ae_cos((double)(3*i+5*j), _state); + } + } +} + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugmaskedbiasedproductsum(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* b, + /* Boolean */ const ae_matrix* c, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double result; + + + ae_assert(m>=a->rows, "Assertion failed", _state); + ae_assert(m>=b->rows, "Assertion failed", _state); + ae_assert(m>=c->rows, "Assertion failed", _state); + ae_assert(n>=a->cols, "Assertion failed", _state); + ae_assert(n>=b->cols, "Assertion failed", _state); + ae_assert(n>=c->cols, "Assertion failed", _state); + result = 0.0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( c->ptr.pp_bool[i][j] ) + { + result = result+a->ptr.pp_double[i][j]*((double)1+b->ptr.pp_double[i][j]); + } + } + } + return result; +} + + +void _xdebugrecord1_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xdebugrecord1 *p = (xdebugrecord1*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->a, 0, DT_REAL, _state, make_automatic); +} + + +void _xdebugrecord1_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xdebugrecord1 *dst = (xdebugrecord1*)_dst; + const xdebugrecord1 *src = (const xdebugrecord1*)_src; + dst->i = src->i; + dst->c = src->c; + ae_vector_init_copy(&dst->a, &src->a, _state, make_automatic); +} + + +void _xdebugrecord1_clear(void* _p) +{ + xdebugrecord1 *p = (xdebugrecord1*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->a); +} + + +void _xdebugrecord1_destroy(void* _p) +{ + xdebugrecord1 *p = (xdebugrecord1*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->a); +} + + +#endif +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +HQRNDState initialization with random values which come from standard +RNG. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndrandomize(hqrndstate* state, ae_state *_state) +{ + ae_int_t s0; + ae_int_t s1; + + _hqrndstate_clear(state); + + s0 = ae_randominteger(hqrnd_hqrndm1, _state); + s1 = ae_randominteger(hqrnd_hqrndm2, _state); + hqrndseed(s0, s1, state, _state); +} + + +/************************************************************************* +HQRNDState initialization with seed values + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndseed(ae_int_t s1, + ae_int_t s2, + hqrndstate* state, + ae_state *_state) +{ + + _hqrndstate_clear(state); + + + /* + * Protection against negative seeds: + * + * SEED := -(SEED+1) + * + * We can use just "-SEED" because there exists such integer number N + * that N<0, -N=N<0 too. (This number is equal to 0x800...000). Need + * to handle such seed correctly forces us to use a bit complicated + * formula. + */ + if( s1<0 ) + { + s1 = -(s1+1); + } + if( s2<0 ) + { + s2 = -(s2+1); + } + state->s1 = s1%(hqrnd_hqrndm1-1)+1; + state->s2 = s2%(hqrnd_hqrndm2-1)+1; + state->magicv = hqrnd_hqrndmagic; +} + + +/************************************************************************* +This function generates random real number in (0,1), +not including interval boundaries + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrnduniformr(hqrndstate* state, ae_state *_state) +{ + double result; + + + result = (double)(hqrndintegerbase(state, _state)+1)/(double)(hqrnd_hqrndmax+2); + return result; +} + + +/************************************************************************* +This function generates random integer number in [0, N) + +1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() +2. N can be any positive number except for very large numbers: + * close to 2^31 on 32-bit systems + * close to 2^62 on 64-bit systems + An exception will be generated if N is too large. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state) +{ + ae_int_t maxcnt; + ae_int_t mx; + ae_int_t a; + ae_int_t b; + ae_int_t result; + + + ae_assert(n>0, "HQRNDUniformI: N<=0!", _state); + maxcnt = hqrnd_hqrndmax+1; + + /* + * Two branches: one for N<=MaxCnt, another for N>MaxCnt. + */ + if( n>maxcnt ) + { + + /* + * N>=MaxCnt. + * + * We have two options here: + * a) N is exactly divisible by MaxCnt + * b) N is not divisible by MaxCnt + * + * In both cases we reduce problem on interval spanning [0,N) + * to several subproblems on intervals spanning [0,MaxCnt). + */ + if( n%maxcnt==0 ) + { + + /* + * N is exactly divisible by MaxCnt. + * + * [0,N) range is dividided into N/MaxCnt bins, + * each of them having length equal to MaxCnt. + * + * We generate: + * * random bin number B + * * random offset within bin A + * Both random numbers are generated by recursively + * calling HQRNDUniformI(). + * + * Result is equal to A+MaxCnt*B. + */ + ae_assert(n/maxcnt<=maxcnt, "HQRNDUniformI: N is too large", _state); + a = hqrnduniformi(state, maxcnt, _state); + b = hqrnduniformi(state, n/maxcnt, _state); + result = a+maxcnt*b; + } + else + { + + /* + * N is NOT exactly divisible by MaxCnt. + * + * [0,N) range is dividided into Ceil(N/MaxCnt) bins, + * each of them having length equal to MaxCnt. + * + * We generate: + * * random bin number B in [0, Ceil(N/MaxCnt)-1] + * * random offset within bin A + * * if both of what is below is true + * 1) bin number B is that of the last bin + * 2) A >= N mod MaxCnt + * then we repeat generation of A/B. + * This stage is essential in order to avoid bias in the result. + * * otherwise, we return A*MaxCnt+N + */ + ae_assert(n/maxcnt+1<=maxcnt, "HQRNDUniformI: N is too large", _state); + result = -1; + do + { + a = hqrnduniformi(state, maxcnt, _state); + b = hqrnduniformi(state, n/maxcnt+1, _state); + if( b==n/maxcnt&&a>=n%maxcnt ) + { + continue; + } + result = a+maxcnt*b; + } + while(result<0); + } + } + else + { + + /* + * N<=MaxCnt + * + * Code below is a bit complicated because we can not simply + * return "HQRNDIntegerBase() mod N" - it will be skewed for + * large N's in [0.1*HQRNDMax...HQRNDMax]. + */ + mx = maxcnt-maxcnt%n; + do + { + result = hqrndintegerbase(state, _state); + } + while(result>=mx); + result = result%n; + } + return result; +} + + +/************************************************************************* +Random number generator: normal numbers + +This function generates one random number from normal distribution. +Its performance is equal to that of HQRNDNormal2() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrndnormal(hqrndstate* state, ae_state *_state) +{ + double v1; + double v2; + double result; + + + hqrndnormal2(state, &v1, &v2, _state); + result = v1; + return result; +} + + +/************************************************************************* +Random number generator: vector with random entries (normal distribution) + +This function generates N random numbers from normal distribution. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalv(hqrndstate* state, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n2; + double v1; + double v2; + + ae_vector_clear(x); + + n2 = n/2; + rallocv(n, x, _state); + for(i=0; i<=n2-1; i++) + { + hqrndnormal2(state, &v1, &v2, _state); + x->ptr.p_double[2*i+0] = v1; + x->ptr.p_double[2*i+1] = v2; + } + if( n%2!=0 ) + { + hqrndnormal2(state, &v1, &v2, _state); + x->ptr.p_double[n-1] = v1; + } +} + + +/************************************************************************* +Random number generator: matrix with random entries (normal distribution) + +This function generates MxN random matrix. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalm(hqrndstate* state, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n2; + double v1; + double v2; + + ae_matrix_clear(x); + + n2 = n/2; + ae_matrix_set_length(x, m, n, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n2-1; j++) + { + hqrndnormal2(state, &v1, &v2, _state); + x->ptr.pp_double[i][2*j+0] = v1; + x->ptr.pp_double[i][2*j+1] = v2; + } + if( n%2!=0 ) + { + hqrndnormal2(state, &v1, &v2, _state); + x->ptr.pp_double[i][n-1] = v1; + } + } +} + + +/************************************************************************* +Random number generator: random X and Y such that X^2+Y^2=1 + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state) +{ + double v; + double mx; + double mn; + + *x = 0.0; + *y = 0.0; + + do + { + hqrndnormal2(state, x, y, _state); + } + while(!(ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))); + mx = ae_maxreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); + mn = ae_minreal(ae_fabs(*x, _state), ae_fabs(*y, _state), _state); + v = mx*ae_sqrt((double)1+ae_sqr(mn/mx, _state), _state); + *x = *x/v; + *y = *y/v; +} + + +/************************************************************************* +Random number generator: normal numbers + +This function generates two independent random numbers from normal +distribution. Its performance is equal to that of HQRNDNormal() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormal2(hqrndstate* state, + double* x1, + double* x2, + ae_state *_state) +{ + double u; + double v; + double s; + + *x1 = 0.0; + *x2 = 0.0; + + for(;;) + { + u = (double)2*hqrnduniformr(state, _state)-(double)1; + v = (double)2*hqrnduniformr(state, _state)-(double)1; + s = ae_sqr(u, _state)+ae_sqr(v, _state); + if( ae_fp_greater(s,(double)(0))&&ae_fp_less(s,(double)(1)) ) + { + + /* + * two Sqrt's instead of one to + * avoid overflow when S is too small + */ + s = ae_sqrt(-(double)2*ae_log(s, _state), _state)/ae_sqrt(s, _state); + *x1 = u*s; + *x2 = v*s; + return; + } + } +} + + +/************************************************************************* +Random number generator: exponential distribution + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 11.08.2007 by Bochkanov Sergey +*************************************************************************/ +double hqrndexponential(hqrndstate* state, + double lambdav, + ae_state *_state) +{ + double result; + + + ae_assert(ae_fp_greater(lambdav,(double)(0)), "HQRNDExponential: LambdaV<=0!", _state); + result = -ae_log(hqrnduniformr(state, _state), _state)/lambdav; + return result; +} + + +/************************************************************************* +This function returns HQRNDMax + +L'Ecuyer, Efficient and portable combined random number generators +*************************************************************************/ +ae_int_t hqrndgetmax(ae_state *_state) +{ + ae_int_t result; + + + result = hqrnd_hqrndmax; + return result; +} + + +/************************************************************************* +This function returns random integer in [0,HQRNDMax], basecase for other +RNG functions. + +L'Ecuyer, Efficient and portable combined random number generators +*************************************************************************/ +ae_int_t hqrndintegerbase(hqrndstate* state, ae_state *_state) +{ + ae_int_t k; + ae_int_t result; + + + if( state->magicv!=hqrnd_hqrndmagic ) + { + ae_assert(ae_false, "HQRNDIntegerBase: State is not correctly initialized!", _state); + } + k = state->s1/53668; + state->s1 = 40014*(state->s1-k*53668)-k*12211; + if( state->s1<0 ) + { + state->s1 = state->s1+2147483563; + } + k = state->s2/52774; + state->s2 = 40692*(state->s2-k*52774)-k*3791; + if( state->s2<0 ) + { + state->s2 = state->s2+2147483399; + } + + /* + * Result + */ + result = state->s1-state->s2; + if( result<1 ) + { + result = result+2147483562; + } + result = result-1; + return result; +} + + +/************************************************************************* +This function generates random number from discrete distribution given by +finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample + N - number of elements to use, N>=1 + +RESULT + this function returns one of the X[i] for random i=0..N-1 + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrnddiscrete(hqrndstate* state, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double result; + + + ae_assert(n>0, "HQRNDDiscrete: N<=0", _state); + ae_assert(n<=x->cnt, "HQRNDDiscrete: Length(X)ptr.p_double[hqrnduniformi(state, n, _state)]; + return result; +} + + +/************************************************************************* +This function generates random number from continuous distribution given +by finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample, array[N] (can be larger, in this case only + leading N elements are used). THIS ARRAY MUST BE SORTED BY + ASCENDING. + N - number of elements to use, N>=1 + +RESULT + this function returns random number from continuous distribution which + tries to approximate X as mush as possible. min(X)<=Result<=max(X). + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrndcontinuous(hqrndstate* state, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double mx; + double mn; + ae_int_t i; + double result; + + + ae_assert(n>0, "HQRNDContinuous: N<=0", _state); + ae_assert(n<=x->cnt, "HQRNDContinuous: Length(X)ptr.p_double[0]; + return result; + } + i = hqrnduniformi(state, n-1, _state); + mn = x->ptr.p_double[i]; + mx = x->ptr.p_double[i+1]; + ae_assert(ae_fp_greater_eq(mx,mn), "HQRNDDiscrete: X is not sorted by ascending", _state); + if( ae_fp_neq(mx,mn) ) + { + result = (mx-mn)*hqrnduniformr(state, _state)+mn; + } + else + { + result = mn; + } + return result; +} + + +void _hqrndstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + hqrndstate *p = (hqrndstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _hqrndstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + hqrndstate *dst = (hqrndstate*)_dst; + const hqrndstate *src = (const hqrndstate*)_src; + dst->s1 = src->s1; + dst->s2 = src->s2; + dst->magicv = src->magicv; +} + + +void _hqrndstate_clear(void* _p) +{ + hqrndstate *p = (hqrndstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _hqrndstate_destroy(void* _p) +{ + hqrndstate *p = (hqrndstate*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values and optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + N - number of points, N>=0. + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuild(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t normtype, + kdtree* kdt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tags; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&tags, 0, sizeof(tags)); + _kdtree_clear(kdt); + ae_vector_init(&tags, 0, DT_INT, _state, ae_true); + + ae_assert(n>=0, "KDTreeBuild: N<0", _state); + ae_assert(nx>=1, "KDTreeBuild: NX<1", _state); + ae_assert(ny>=0, "KDTreeBuild: NY<0", _state); + ae_assert(normtype>=0&&normtype<=2, "KDTreeBuild: incorrect NormType", _state); + ae_assert(xy->rows>=n, "KDTreeBuild: rows(X)cols>=nx+ny||n==0, "KDTreeBuild: cols(X)0 ) + { + ae_vector_set_length(&tags, n, _state); + for(i=0; i<=n-1; i++) + { + tags.ptr.p_int[i] = 0; + } + } + kdtreebuildtagged(xy, &tags, n, nx, ny, normtype, kdt, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values, integer tags and +optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + Tags - tags, array[0..N-1], contains integer tags associated + with points. + N - number of points, N>=0 + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuildtagged(/* Real */ const ae_matrix* xy, + /* Integer */ const ae_vector* tags, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t normtype, + kdtree* kdt, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nodesoffs; + ae_int_t splitsoffs; + + _kdtree_clear(kdt); + + ae_assert(n>=0, "KDTreeBuildTagged: N<0", _state); + ae_assert(nx>=1, "KDTreeBuildTagged: NX<1", _state); + ae_assert(ny>=0, "KDTreeBuildTagged: NY<0", _state); + ae_assert(normtype>=0&&normtype<=2, "KDTreeBuildTagged: incorrect NormType", _state); + ae_assert(xy->rows>=n, "KDTreeBuildTagged: rows(X)cols>=nx+ny||n==0, "KDTreeBuildTagged: cols(X)n = n; + kdt->nx = nx; + kdt->ny = ny; + kdt->normtype = normtype; + kdt->innerbuf.kcur = 0; + + /* + * N=0 => quick exit + */ + if( n==0 ) + { + return; + } + + /* + * Allocate + */ + nearestneighbor_kdtreeallocdatasetindependent(kdt, nx, ny, _state); + nearestneighbor_kdtreeallocdatasetdependent(kdt, n, nx, ny, _state); + kdtreecreaterequestbuffer(kdt, &kdt->innerbuf, _state); + + /* + * Initial fill + */ + for(i=0; i<=n-1; i++) + { + ae_v_move(&kdt->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); + ae_v_move(&kdt->xy.ptr.pp_double[i][nx], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(nx,2*nx+ny-1)); + kdt->tags.ptr.p_int[i] = tags->ptr.p_int[i]; + } + + /* + * Determine bounding box + */ + ae_v_move(&kdt->boxmin.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); + ae_v_move(&kdt->boxmax.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[0][0], 1, ae_v_len(0,nx-1)); + for(i=1; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + kdt->boxmin.ptr.p_double[j] = ae_minreal(kdt->boxmin.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); + kdt->boxmax.ptr.p_double[j] = ae_maxreal(kdt->boxmax.ptr.p_double[j], kdt->xy.ptr.pp_double[i][j], _state); + } + } + + /* + * Generate tree + */ + nodesoffs = 0; + splitsoffs = 0; + ae_v_move(&kdt->innerbuf.curboxmin.ptr.p_double[0], 1, &kdt->boxmin.ptr.p_double[0], 1, ae_v_len(0,nx-1)); + ae_v_move(&kdt->innerbuf.curboxmax.ptr.p_double[0], 1, &kdt->boxmax.ptr.p_double[0], 1, ae_v_len(0,nx-1)); + nearestneighbor_kdtreegeneratetreerec(kdt, &nodesoffs, &splitsoffs, 0, n, 8, _state); + ivectorresize(&kdt->nodes, nodesoffs, _state); + rvectorresize(&kdt->splits, splitsoffs, _state); +} + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel KD-tree requests. + +KD-tree subpackage provides two sets of request functions - ones which use +internal buffer of KD-tree object (these functions are single-threaded +because they use same buffer, which can not shared between threads), and +ones which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + KDT - KD-tree which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: KD-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreecreaterequestbuffer(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_state *_state) +{ + + _kdtreerequestbuffer_clear(buf); + + ae_vector_set_length(&buf->x, kdt->nx, _state); + ae_vector_set_length(&buf->boxmin, kdt->nx, _state); + ae_vector_set_length(&buf->boxmax, kdt->nx, _state); + ae_vector_set_length(&buf->idx, kdt->n, _state); + ae_vector_set_length(&buf->r, kdt->n, _state); + ae_vector_set_length(&buf->buf, ae_maxint(kdt->n, kdt->nx, _state), _state); + ae_vector_set_length(&buf->curboxmin, kdt->nx, _state); + ae_vector_set_length(&buf->curboxmax, kdt->nx, _state); + buf->kcur = 0; +} + + +/************************************************************************* +K-NN query: K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryknn(kdtree* kdt, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(k>=1, "KDTreeQueryKNN: K<1!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeQueryKNN: Length(X)nx, _state), "KDTreeQueryKNN: X contains infinite or NaN values!", _state); + result = kdtreetsqueryaknn(kdt, &kdt->innerbuf, x, k, selfmatch, 0.0, _state); + return result; +} + + +/************************************************************************* +K-NN query: K nearest neighbors, using external thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - kd-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryknn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(k>=1, "KDTreeTsQueryKNN: K<1!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeTsQueryKNN: Length(X)nx, _state), "KDTreeTsQueryKNN: X contains infinite or NaN values!", _state); + result = kdtreetsqueryaknn(kdt, buf, x, k, selfmatch, 0.0, _state); + return result; +} + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, ordered by distance +between point and X (by ascending). + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnn(kdtree* kdt, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(ae_fp_greater(r,(double)(0)), "KDTreeQueryRNN: incorrect R!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeQueryRNN: Length(X)nx, _state), "KDTreeQueryRNN: X contains infinite or NaN values!", _state); + result = kdtreetsqueryrnn(kdt, &kdt->innerbuf, x, r, selfmatch, _state); + return result; +} + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, no ordering by +distance as undicated by "U" suffix (faster that ordered query, for large +queries - significantly faster). + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + + -- ALGLIB -- + Copyright 01.11.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnnu(kdtree* kdt, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(ae_fp_greater(r,(double)(0)), "KDTreeQueryRNNU: incorrect R!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeQueryRNNU: Length(X)nx, _state), "KDTreeQueryRNNU: X contains infinite or NaN values!", _state); + result = kdtreetsqueryrnnu(kdt, &kdt->innerbuf, x, r, selfmatch, _state); + return result; +} + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, sorted by distance between point and X (by ascending) + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(ae_isfinite(r, _state)&&ae_fp_greater(r,(double)(0)), "KDTreeTsQueryRNN: incorrect R!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeTsQueryRNN: Length(X)nx, _state), "KDTreeTsQueryRNN: X contains infinite or NaN values!", _state); + result = nearestneighbor_tsqueryrnn(kdt, buf, x, r, selfmatch, ae_true, _state); + return result; +} + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, no ordering by distance as undicated by "U" suffix +(faster that ordered query, for large queries - significantly faster). + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnnu(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(ae_isfinite(r, _state)&&ae_fp_greater(r,(double)(0)), "KDTreeTsQueryRNNU: incorrect R!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeTsQueryRNNU: Length(X)nx, _state), "KDTreeTsQueryRNNU: X contains infinite or NaN values!", _state); + result = nearestneighbor_tsqueryrnn(kdt, buf, x, r, selfmatch, ae_false, _state); + return result; +} + + +/************************************************************************* +K-NN query: approximate K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryAKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryaknn(kdtree* kdt, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + double eps, + ae_state *_state) +{ + ae_int_t result; + + + result = kdtreetsqueryaknn(kdt, &kdt->innerbuf, x, k, selfmatch, eps, _state); + return result; +} + + +/************************************************************************* +K-NN query: approximate K nearest neighbors, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryaknn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + double eps, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t result; + + + ae_assert(k>0, "KDTreeTsQueryAKNN: incorrect K!", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "KDTreeTsQueryAKNN: incorrect Eps!", _state); + ae_assert(x->cnt>=kdt->nx, "KDTreeTsQueryAKNN: Length(X)nx, _state), "KDTreeTsQueryAKNN: X contains infinite or NaN values!", _state); + + /* + * Handle special case: KDT.N=0 + */ + if( kdt->n==0 ) + { + buf->kcur = 0; + result = 0; + return result; + } + + /* + * Check consistency of request buffer + */ + nearestneighbor_checkrequestbufferconsistency(kdt, buf, _state); + + /* + * Prepare parameters + */ + k = ae_minint(k, kdt->n, _state); + buf->kneeded = k; + buf->rneeded = (double)(0); + buf->selfmatch = selfmatch; + if( kdt->normtype==2 ) + { + buf->approxf = (double)1/ae_sqr((double)1+eps, _state); + } + else + { + buf->approxf = (double)1/((double)1+eps); + } + buf->kcur = 0; + + /* + * calculate distance from point to current bounding box + */ + nearestneighbor_kdtreeinitbox(kdt, x, buf, _state); + + /* + * call recursive search + * results are returned as heap + */ + nearestneighbor_kdtreequerynnrec(kdt, buf, 0, _state); + + /* + * pop from heap to generate ordered representation + * + * last element is non pop'ed because it is already in + * its place + */ + result = buf->kcur; + j = buf->kcur; + for(i=buf->kcur; i>=2; i--) + { + tagheappopi(&buf->r, &buf->idx, &j, _state); + } + return result; +} + + +/************************************************************************* +Box query: all points within user-specified box. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryBox() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() returns zeros for this request + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequerybox(kdtree* kdt, + /* Real */ const ae_vector* boxmin, + /* Real */ const ae_vector* boxmax, + ae_state *_state) +{ + ae_int_t result; + + + result = kdtreetsquerybox(kdt, &kdt->innerbuf, boxmin, boxmax, _state); + return result; +} + + +/************************************************************************* +Box query: all points within user-specified box, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "ts" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() returns zeros for this query + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsquerybox(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* boxmin, + /* Real */ const ae_vector* boxmax, + ae_state *_state) +{ + ae_int_t j; + ae_int_t result; + + + ae_assert(boxmin->cnt>=kdt->nx, "KDTreeTsQueryBox: Length(BoxMin)cnt>=kdt->nx, "KDTreeTsQueryBox: Length(BoxMax)nx, _state), "KDTreeTsQueryBox: BoxMin contains infinite or NaN values!", _state); + ae_assert(isfinitevector(boxmax, kdt->nx, _state), "KDTreeTsQueryBox: BoxMax contains infinite or NaN values!", _state); + + /* + * Check consistency of request buffer + */ + nearestneighbor_checkrequestbufferconsistency(kdt, buf, _state); + + /* + * Quick exit for degenerate boxes + */ + for(j=0; j<=kdt->nx-1; j++) + { + if( ae_fp_greater(boxmin->ptr.p_double[j],boxmax->ptr.p_double[j]) ) + { + buf->kcur = 0; + result = 0; + return result; + } + } + + /* + * Prepare parameters + */ + for(j=0; j<=kdt->nx-1; j++) + { + buf->boxmin.ptr.p_double[j] = boxmin->ptr.p_double[j]; + buf->boxmax.ptr.p_double[j] = boxmax->ptr.p_double[j]; + buf->curboxmin.ptr.p_double[j] = boxmin->ptr.p_double[j]; + buf->curboxmax.ptr.p_double[j] = boxmax->ptr.p_double[j]; + } + buf->kcur = 0; + + /* + * call recursive search + */ + nearestneighbor_kdtreequeryboxrec(kdt, buf, 0, _state); + result = buf->kcur; + return result; +} + + +/************************************************************************* +X-values from last query. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsx(). + +INPUT PARAMETERS + KDT - KD-tree + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsx(const kdtree* kdt, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + + + kdtreetsqueryresultsx(kdt, &kdt->innerbuf, x, _state); +} + + +/************************************************************************* +X- and Y-values from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsxy(). + +INPUT PARAMETERS + KDT - KD-tree + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxy(const kdtree* kdt, + /* Real */ ae_matrix* xy, + ae_state *_state) +{ + + + kdtreetsqueryresultsxy(kdt, &kdt->innerbuf, xy, _state); +} + + +/************************************************************************* +Tags from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstags(const kdtree* kdt, + /* Integer */ ae_vector* tags, + ae_state *_state) +{ + + + kdtreetsqueryresultstags(kdt, &kdt->innerbuf, tags, _state); +} + + +/************************************************************************* +Distances from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistances(const kdtree* kdt, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + + kdtreetsqueryresultsdistances(kdt, &kdt->innerbuf, r, _state); +} + + +/************************************************************************* +X-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsx(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + if( buf->kcur==0 ) + { + return; + } + if( x->rowskcur||x->colsnx ) + { + ae_matrix_set_length(x, buf->kcur, kdt->nx, _state); + } + k = buf->kcur; + for(i=0; i<=k-1; i++) + { + ae_v_move(&x->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[buf->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx-1)); + } +} + + +/************************************************************************* +X- and Y-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsxy(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_matrix* xy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + if( buf->kcur==0 ) + { + return; + } + if( xy->rowskcur||xy->colsnx+kdt->ny ) + { + ae_matrix_set_length(xy, buf->kcur, kdt->nx+kdt->ny, _state); + } + k = buf->kcur; + for(i=0; i<=k-1; i++) + { + ae_v_move(&xy->ptr.pp_double[i][0], 1, &kdt->xy.ptr.pp_double[buf->idx.ptr.p_int[i]][kdt->nx], 1, ae_v_len(0,kdt->nx+kdt->ny-1)); + } +} + + +/************************************************************************* +Tags from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultstags(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Integer */ ae_vector* tags, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + if( buf->kcur==0 ) + { + return; + } + if( tags->cntkcur ) + { + ae_vector_set_length(tags, buf->kcur, _state); + } + k = buf->kcur; + for(i=0; i<=k-1; i++) + { + tags->ptr.p_int[i] = kdt->tags.ptr.p_int[buf->idx.ptr.p_int[i]]; + } +} + + +/************************************************************************* +Distances from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsdistances(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + if( buf->kcur==0 ) + { + return; + } + if( r->cntkcur ) + { + ae_vector_set_length(r, buf->kcur, _state); + } + k = buf->kcur; + + /* + * unload norms + * + * Abs() call is used to handle cases with negative norms + * (generated during KFN requests) + */ + if( kdt->normtype==0 ) + { + for(i=0; i<=k-1; i++) + { + r->ptr.p_double[i] = ae_fabs(buf->r.ptr.p_double[i], _state); + } + } + if( kdt->normtype==1 ) + { + for(i=0; i<=k-1; i++) + { + r->ptr.p_double[i] = ae_fabs(buf->r.ptr.p_double[i], _state); + } + } + if( kdt->normtype==2 ) + { + for(i=0; i<=k-1; i++) + { + r->ptr.p_double[i] = ae_sqrt(ae_fabs(buf->r.ptr.p_double[i], _state), _state); + } + } +} + + +/************************************************************************* +X-values from last query; 'interactive' variant for languages like Python +which support constructs like "X = KDTreeQueryResultsXI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxi(const kdtree* kdt, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + + ae_matrix_clear(x); + + kdtreequeryresultsx(kdt, x, _state); +} + + +/************************************************************************* +XY-values from last query; 'interactive' variant for languages like Python +which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxyi(const kdtree* kdt, + /* Real */ ae_matrix* xy, + ae_state *_state) +{ + + ae_matrix_clear(xy); + + kdtreequeryresultsxy(kdt, xy, _state); +} + + +/************************************************************************* +Tags from last query; 'interactive' variant for languages like Python +which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstagsi(const kdtree* kdt, + /* Integer */ ae_vector* tags, + ae_state *_state) +{ + + ae_vector_clear(tags); + + kdtreequeryresultstags(kdt, tags, _state); +} + + +/************************************************************************* +Distances from last query; 'interactive' variant for languages like Python +which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" +and interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistancesi(const kdtree* kdt, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + kdtreequeryresultsdistances(kdt, r, _state); +} + + +/************************************************************************* +It is informational function which returns bounding box for entire dataset. +This function is not visible to ALGLIB users, only ALGLIB itself may use +it. + +This function assumes that output buffers are preallocated by caller. + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreeexplorebox(const kdtree* kdt, + /* Real */ ae_vector* boxmin, + /* Real */ ae_vector* boxmax, + ae_state *_state) +{ + ae_int_t i; + + + rvectorsetlengthatleast(boxmin, kdt->nx, _state); + rvectorsetlengthatleast(boxmax, kdt->nx, _state); + for(i=0; i<=kdt->nx-1; i++) + { + boxmin->ptr.p_double[i] = kdt->boxmin.ptr.p_double[i]; + boxmax->ptr.p_double[i] = kdt->boxmax.ptr.p_double[i]; + } +} + + +/************************************************************************* +It is informational function which allows to get information about node +type. Node index is given by integer value, with 0 corresponding to root +node and other node indexes obtained via exploration. + +You should not expect that serialization/unserialization will retain node +indexes. You should keep in mind that future versions of ALGLIB may +introduce new node types. + +OUTPUT VALUES: + NodeType - node type: + * 0 corresponds to leaf node, which can be explored by + kdtreeexploreleaf() function + * 1 corresponds to split node, which can be explored + by kdtreeexploresplit() function + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreeexplorenodetype(const kdtree* kdt, + ae_int_t node, + ae_int_t* nodetype, + ae_state *_state) +{ + + *nodetype = 0; + + ae_assert(node>=0, "KDTreeExploreNodeType: incorrect node", _state); + ae_assert(nodenodes.cnt, "KDTreeExploreNodeType: incorrect node", _state); + if( kdt->nodes.ptr.p_int[node]>0 ) + { + + /* + * Leaf node + */ + *nodetype = 0; + return; + } + if( kdt->nodes.ptr.p_int[node]==0 ) + { + + /* + * Split node + */ + *nodetype = 1; + return; + } + ae_assert(ae_false, "KDTreeExploreNodeType: integrity check failure", _state); +} + + +/************************************************************************* +It is informational function which allows to get information about leaf +node. Node index is given by integer value, with 0 corresponding to root +node and other node indexes obtained via exploration. + +You should not expect that serialization/unserialization will retain node +indexes. You should keep in mind that future versions of ALGLIB may +introduce new node types. + +OUTPUT VALUES: + XT - output buffer is reallocated (if too small) and filled by + XY values + K - number of rows in XY + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreeexploreleaf(const kdtree* kdt, + ae_int_t node, + /* Real */ ae_matrix* xy, + ae_int_t* k, + ae_state *_state) +{ + ae_int_t offs; + ae_int_t i; + ae_int_t j; + + *k = 0; + + ae_assert(node>=0, "KDTreeExploreLeaf: incorrect node index", _state); + ae_assert(node+1nodes.cnt, "KDTreeExploreLeaf: incorrect node index", _state); + ae_assert(kdt->nodes.ptr.p_int[node]>0, "KDTreeExploreLeaf: incorrect node index", _state); + *k = kdt->nodes.ptr.p_int[node]; + offs = kdt->nodes.ptr.p_int[node+1]; + ae_assert(offs>=0, "KDTreeExploreLeaf: integrity error", _state); + ae_assert(offs+(*k)-1xy.rows, "KDTreeExploreLeaf: integrity error", _state); + rmatrixsetlengthatleast(xy, *k, kdt->nx+kdt->ny, _state); + for(i=0; i<=*k-1; i++) + { + for(j=0; j<=kdt->nx+kdt->ny-1; j++) + { + xy->ptr.pp_double[i][j] = kdt->xy.ptr.pp_double[offs+i][kdt->nx+j]; + } + } +} + + +/************************************************************************* +It is informational function which allows to get information about split +node. Node index is given by integer value, with 0 corresponding to root +node and other node indexes obtained via exploration. + +You should not expect that serialization/unserialization will retain node +indexes. You should keep in mind that future versions of ALGLIB may +introduce new node types. + +OUTPUT VALUES: + XT - output buffer is reallocated (if too small) and filled by + XY values + K - number of rows in XY + + // Nodes[idx+1]=dim dimension to split + // Nodes[idx+2]=offs offset of splitting point in Splits[] + // Nodes[idx+3]=left position of left child in Nodes[] + // Nodes[idx+4]=right position of right child in Nodes[] + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreeexploresplit(const kdtree* kdt, + ae_int_t node, + ae_int_t* d, + double* s, + ae_int_t* nodele, + ae_int_t* nodege, + ae_state *_state) +{ + + *d = 0; + *s = 0.0; + *nodele = 0; + *nodege = 0; + + ae_assert(node>=0, "KDTreeExploreSplit: incorrect node index", _state); + ae_assert(node+4nodes.cnt, "KDTreeExploreSplit: incorrect node index", _state); + ae_assert(kdt->nodes.ptr.p_int[node]==0, "KDTreeExploreSplit: incorrect node index", _state); + *d = kdt->nodes.ptr.p_int[node+1]; + *s = kdt->splits.ptr.p_double[kdt->nodes.ptr.p_int[node+2]]; + *nodele = kdt->nodes.ptr.p_int[node+3]; + *nodege = kdt->nodes.ptr.p_int[node+4]; + ae_assert(*d>=0, "KDTreeExploreSplit: integrity failure", _state); + ae_assert(*dnx, "KDTreeExploreSplit: integrity failure", _state); + ae_assert(ae_isfinite(*s, _state), "KDTreeExploreSplit: integrity failure", _state); + ae_assert(*nodele>=0, "KDTreeExploreSplit: integrity failure", _state); + ae_assert(*nodelenodes.cnt, "KDTreeExploreSplit: integrity failure", _state); + ae_assert(*nodege>=0, "KDTreeExploreSplit: integrity failure", _state); + ae_assert(*nodegenodes.cnt, "KDTreeExploreSplit: integrity failure", _state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void kdtreealloc(ae_serializer* s, const kdtree* tree, ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealmatrix(s, &tree->xy, -1, -1, _state); + allocintegerarray(s, &tree->tags, -1, _state); + allocrealarray(s, &tree->boxmin, -1, _state); + allocrealarray(s, &tree->boxmax, -1, _state); + allocintegerarray(s, &tree->nodes, -1, _state); + allocrealarray(s, &tree->splits, -1, _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void kdtreeserialize(ae_serializer* s, + const kdtree* tree, + ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_serialize_int(s, getkdtreeserializationcode(_state), _state); + ae_serializer_serialize_int(s, nearestneighbor_kdtreefirstversion, _state); + + /* + * Data + */ + ae_serializer_serialize_int(s, tree->n, _state); + ae_serializer_serialize_int(s, tree->nx, _state); + ae_serializer_serialize_int(s, tree->ny, _state); + ae_serializer_serialize_int(s, tree->normtype, _state); + serializerealmatrix(s, &tree->xy, -1, -1, _state); + serializeintegerarray(s, &tree->tags, -1, _state); + serializerealarray(s, &tree->boxmin, -1, _state); + serializerealarray(s, &tree->boxmax, -1, _state); + serializeintegerarray(s, &tree->nodes, -1, _state); + serializerealarray(s, &tree->splits, -1, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state) +{ + ae_int_t i0; + ae_int_t i1; + + _kdtree_clear(tree); + + + /* + * check correctness of header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getkdtreeserializationcode(_state), "KDTreeUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_assert(i1==nearestneighbor_kdtreefirstversion, "KDTreeUnserialize: stream header corrupted", _state); + + /* + * Unserialize data + */ + ae_serializer_unserialize_int(s, &tree->n, _state); + ae_serializer_unserialize_int(s, &tree->nx, _state); + ae_serializer_unserialize_int(s, &tree->ny, _state); + ae_serializer_unserialize_int(s, &tree->normtype, _state); + unserializerealmatrix(s, &tree->xy, _state); + unserializeintegerarray(s, &tree->tags, _state); + unserializerealarray(s, &tree->boxmin, _state); + unserializerealarray(s, &tree->boxmax, _state); + unserializeintegerarray(s, &tree->nodes, _state); + unserializerealarray(s, &tree->splits, _state); + kdtreecreaterequestbuffer(tree, &tree->innerbuf, _state); +} + + +/************************************************************************* +This function returns an approximate cost (measured in CPU cycles) of a +R-NN query with some fixed R. + +A VERY CRUDE APPROXIMATION IS RETURNED, ONLY AN ORDER OF MAGNITUDE CORRECT + +This approximation can be used in a multithreaded code which decides whether +it makes sense to activate multithreading or not. + +Internally this function is implemented by performing some small (about 50) +amount of random queries and computing an average number of R-neighbors of +a node. This number is multiplied by log2(NPoints), and then by a crude +estimate of how many CPU cycles is required to perform a split during kd-tree +search. + +This function is deterministic, i.e. it always uses a fixed seed to initialize +its internal RNG. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. + + See kdtreeapproxrnnquerycost() for a thread-safe alternative. + +INPUT PARAMETERS + KDT - KD-tree + R - radius of sphere (in corresponding norm), R>0 + +RESULT + double precision number, approximate query cost + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +double kdtreeapproxrnnquerycost(kdtree* kdt, double r, ae_state *_state) +{ + double result; + + + result = kdtreetsapproxrnnquerycost(kdt, &kdt->innerbuf, r, _state); + return result; +} + + +/************************************************************************* +This function returns an approximate cost (measured in CPU cycles) of a +R-NN query with some fixed R. + +A thread-safe version of kdtreeapproxrnnquerycost() using a request buffer. + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +double kdtreetsapproxrnnquerycost(const kdtree* kdt, + kdtreerequestbuffer* buf, + double r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cnt; + ae_int_t nx; + double log2n; + double avgrnn; + hqrndstate rs; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(ae_isfinite(r, _state)&&ae_fp_greater(r,(double)(0)), "KDTreeApproxRNNQueryCost: incorrect R!", _state); + hqrndseed(46532, 66356, &rs, _state); + nx = kdt->nx; + cnt = ae_minint(50, kdt->n, _state); + log2n = ae_log((double)(1+kdt->n), _state)/ae_log((double)(2), _state); + avgrnn = (double)(0); + rallocv(nx, &buf->xqc, _state); + for(i=0; i<=cnt-1; i++) + { + k = hqrnduniformi(&rs, kdt->n, _state); + for(j=0; j<=nx-1; j++) + { + buf->xqc.ptr.p_double[j] = kdt->xy.ptr.pp_double[k][nx+j]; + } + avgrnn = avgrnn+(double)nearestneighbor_tsqueryrnn(kdt, buf, &buf->xqc, r, ae_true, ae_false, _state)/(double)cnt; + } + result = avgrnn*log2n*(double)15; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, sorted by distance between point and X (by ascending) + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t nearestneighbor_tsqueryrnn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_bool orderedbydist, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t result; + + + + /* + * Handle special case: KDT.N=0 + */ + if( kdt->n==0 ) + { + buf->kcur = 0; + result = 0; + return result; + } + + /* + * Check consistency of request buffer + */ + nearestneighbor_checkrequestbufferconsistency(kdt, buf, _state); + + /* + * Prepare parameters + */ + buf->kneeded = 0; + if( kdt->normtype!=2 ) + { + buf->rneeded = r; + } + else + { + buf->rneeded = ae_sqr(r, _state); + } + buf->selfmatch = selfmatch; + buf->approxf = (double)(1); + buf->kcur = 0; + + /* + * calculate distance from point to current bounding box + */ + nearestneighbor_kdtreeinitbox(kdt, x, buf, _state); + + /* + * call recursive search + * results are returned as heap + */ + nearestneighbor_kdtreequerynnrec(kdt, buf, 0, _state); + result = buf->kcur; + + /* + * pop from heap to generate ordered representation + * + * last element is not pop'ed because it is already in + * its place + */ + if( orderedbydist ) + { + j = buf->kcur; + for(i=buf->kcur; i>=2; i--) + { + tagheappopi(&buf->r, &buf->idx, &j, _state); + } + } + return result; +} + + +/************************************************************************* +Rearranges nodes [I1,I2) using partition in D-th dimension with S as threshold. +Returns split position I3: [I1,I3) and [I3,I2) are created as result. + +This subroutine doesn't create tree structures, just rearranges nodes. +*************************************************************************/ +static void nearestneighbor_kdtreesplit(kdtree* kdt, + ae_int_t i1, + ae_int_t i2, + ae_int_t d, + double s, + ae_int_t* i3, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ileft; + ae_int_t iright; + double v; + + *i3 = 0; + + ae_assert(kdt->n>0, "KDTreeSplit: internal error", _state); + + /* + * split XY/Tags in two parts: + * * [ILeft,IRight] is non-processed part of XY/Tags + * + * After cycle is done, we have Ileft=IRight. We deal with + * this element separately. + * + * After this, [I1,ILeft) contains left part, and [ILeft,I2) + * contains right part. + */ + ileft = i1; + iright = i2-1; + while(ileftxy.ptr.pp_double[ileft][d]<=s ) + { + + /* + * XY[ILeft] is on its place. + * Advance ILeft. + */ + ileft = ileft+1; + } + else + { + + /* + * XY[ILeft,..] must be at IRight. + * Swap and advance IRight. + */ + for(i=0; i<=2*kdt->nx+kdt->ny-1; i++) + { + v = kdt->xy.ptr.pp_double[ileft][i]; + kdt->xy.ptr.pp_double[ileft][i] = kdt->xy.ptr.pp_double[iright][i]; + kdt->xy.ptr.pp_double[iright][i] = v; + } + j = kdt->tags.ptr.p_int[ileft]; + kdt->tags.ptr.p_int[ileft] = kdt->tags.ptr.p_int[iright]; + kdt->tags.ptr.p_int[iright] = j; + iright = iright-1; + } + } + if( kdt->xy.ptr.pp_double[ileft][d]<=s ) + { + ileft = ileft+1; + } + else + { + iright = iright-1; + } + *i3 = ileft; +} + + +/************************************************************************* +Recursive kd-tree generation subroutine. + +PARAMETERS + KDT tree + NodesOffs unused part of Nodes[] which must be filled by tree + SplitsOffs unused part of Splits[] + I1, I2 points from [I1,I2) are processed + +NodesOffs[] and SplitsOffs[] must be large enough. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreegeneratetreerec(kdtree* kdt, + ae_int_t* nodesoffs, + ae_int_t* splitsoffs, + ae_int_t i1, + ae_int_t i2, + ae_int_t maxleafsize, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + ae_int_t oldoffs; + ae_int_t i3; + ae_int_t cntless; + ae_int_t cntgreater; + double minv; + double maxv; + ae_int_t minidx; + ae_int_t maxidx; + ae_int_t d; + double ds; + double s; + double v; + double v0; + double v1; + + + ae_assert(kdt->n>0, "KDTreeGenerateTreeRec: internal error", _state); + ae_assert(i2>i1, "KDTreeGenerateTreeRec: internal error", _state); + + /* + * Generate leaf if needed + */ + if( i2-i1<=maxleafsize ) + { + kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; + kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; + *nodesoffs = *nodesoffs+2; + return; + } + + /* + * Load values for easier access + */ + nx = kdt->nx; + ny = kdt->ny; + + /* + * Select dimension to split: + * * D is a dimension number + * In case bounding box has zero size, we enforce creation of the leaf node. + */ + d = 0; + ds = kdt->innerbuf.curboxmax.ptr.p_double[0]-kdt->innerbuf.curboxmin.ptr.p_double[0]; + for(i=1; i<=nx-1; i++) + { + v = kdt->innerbuf.curboxmax.ptr.p_double[i]-kdt->innerbuf.curboxmin.ptr.p_double[i]; + if( v>ds ) + { + ds = v; + d = i; + } + } + if( ae_fp_eq(ds,(double)(0)) ) + { + kdt->nodes.ptr.p_int[*nodesoffs+0] = i2-i1; + kdt->nodes.ptr.p_int[*nodesoffs+1] = i1; + *nodesoffs = *nodesoffs+2; + return; + } + + /* + * Select split position S using sliding midpoint rule, + * rearrange points into [I1,I3) and [I3,I2). + * + * In case all points has same value of D-th component + * (MinV=MaxV) we enforce D-th dimension of bounding + * box to become exactly zero and repeat tree construction. + */ + s = kdt->innerbuf.curboxmin.ptr.p_double[d]+0.5*ds; + ae_v_move(&kdt->innerbuf.buf.ptr.p_double[0], 1, &kdt->xy.ptr.pp_double[i1][d], kdt->xy.stride, ae_v_len(0,i2-i1-1)); + n = i2-i1; + cntless = 0; + cntgreater = 0; + minv = kdt->innerbuf.buf.ptr.p_double[0]; + maxv = kdt->innerbuf.buf.ptr.p_double[0]; + minidx = i1; + maxidx = i1; + for(i=0; i<=n-1; i++) + { + v = kdt->innerbuf.buf.ptr.p_double[i]; + if( vmaxv ) + { + maxv = v; + maxidx = i1+i; + } + if( vs ) + { + cntgreater = cntgreater+1; + } + } + if( minv==maxv ) + { + + /* + * In case all points has same value of D-th component + * (MinV=MaxV) we enforce D-th dimension of bounding + * box to become exactly zero and repeat tree construction. + */ + v0 = kdt->innerbuf.curboxmin.ptr.p_double[d]; + v1 = kdt->innerbuf.curboxmax.ptr.p_double[d]; + kdt->innerbuf.curboxmin.ptr.p_double[d] = minv; + kdt->innerbuf.curboxmax.ptr.p_double[d] = maxv; + nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i2, maxleafsize, _state); + kdt->innerbuf.curboxmin.ptr.p_double[d] = v0; + kdt->innerbuf.curboxmax.ptr.p_double[d] = v1; + return; + } + if( cntless>0&&cntgreater>0 ) + { + + /* + * normal midpoint split + */ + nearestneighbor_kdtreesplit(kdt, i1, i2, d, s, &i3, _state); + } + else + { + + /* + * sliding midpoint + */ + if( cntless==0 ) + { + + /* + * 1. move split to MinV, + * 2. place one point to the left bin (move to I1), + * others - to the right bin + */ + s = minv; + if( minidx!=i1 ) + { + for(i=0; i<=2*nx+ny-1; i++) + { + v = kdt->xy.ptr.pp_double[minidx][i]; + kdt->xy.ptr.pp_double[minidx][i] = kdt->xy.ptr.pp_double[i1][i]; + kdt->xy.ptr.pp_double[i1][i] = v; + } + j = kdt->tags.ptr.p_int[minidx]; + kdt->tags.ptr.p_int[minidx] = kdt->tags.ptr.p_int[i1]; + kdt->tags.ptr.p_int[i1] = j; + } + i3 = i1+1; + } + else + { + + /* + * 1. move split to MaxV, + * 2. place one point to the right bin (move to I2-1), + * others - to the left bin + */ + s = maxv; + if( maxidx!=i2-1 ) + { + for(i=0; i<=2*nx+ny-1; i++) + { + v = kdt->xy.ptr.pp_double[maxidx][i]; + kdt->xy.ptr.pp_double[maxidx][i] = kdt->xy.ptr.pp_double[i2-1][i]; + kdt->xy.ptr.pp_double[i2-1][i] = v; + } + j = kdt->tags.ptr.p_int[maxidx]; + kdt->tags.ptr.p_int[maxidx] = kdt->tags.ptr.p_int[i2-1]; + kdt->tags.ptr.p_int[i2-1] = j; + } + i3 = i2-1; + } + } + + /* + * Generate 'split' node + */ + kdt->nodes.ptr.p_int[*nodesoffs+0] = 0; + kdt->nodes.ptr.p_int[*nodesoffs+1] = d; + kdt->nodes.ptr.p_int[*nodesoffs+2] = *splitsoffs; + kdt->splits.ptr.p_double[*splitsoffs+0] = s; + oldoffs = *nodesoffs; + *nodesoffs = *nodesoffs+nearestneighbor_splitnodesize; + *splitsoffs = *splitsoffs+1; + + /* + * Recursive generation: + * * update CurBox + * * call subroutine + * * restore CurBox + */ + kdt->nodes.ptr.p_int[oldoffs+3] = *nodesoffs; + v = kdt->innerbuf.curboxmax.ptr.p_double[d]; + kdt->innerbuf.curboxmax.ptr.p_double[d] = s; + nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i1, i3, maxleafsize, _state); + kdt->innerbuf.curboxmax.ptr.p_double[d] = v; + kdt->nodes.ptr.p_int[oldoffs+4] = *nodesoffs; + v = kdt->innerbuf.curboxmin.ptr.p_double[d]; + kdt->innerbuf.curboxmin.ptr.p_double[d] = s; + nearestneighbor_kdtreegeneratetreerec(kdt, nodesoffs, splitsoffs, i3, i2, maxleafsize, _state); + kdt->innerbuf.curboxmin.ptr.p_double[d] = v; + + /* + * Zero-fill unused portions of the node (avoid false warnings by Valgrind + * about attempt to serialize uninitialized values) + */ + ae_assert(nearestneighbor_splitnodesize==6, "KDTreeGenerateTreeRec: node size has unexpectedly changed", _state); + kdt->nodes.ptr.p_int[oldoffs+5] = 0; +} + + +/************************************************************************* +Recursive subroutine for NN queries. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreequerynnrec(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_int_t offs, + ae_state *_state) +{ + double ptdist; + ae_int_t i; + ae_int_t j; + ae_int_t nx; + ae_int_t i1; + ae_int_t i2; + ae_int_t d; + double s; + double v; + double t1; + ae_int_t childbestoffs; + ae_int_t childworstoffs; + ae_int_t childoffs; + double prevdist; + ae_bool todive; + ae_bool bestisleft; + ae_bool updatemin; + + + ae_assert(kdt->n>0, "KDTreeQueryNNRec: internal error", _state); + + /* + * Leaf node. + * Process points. + */ + if( kdt->nodes.ptr.p_int[offs]>0 ) + { + i1 = kdt->nodes.ptr.p_int[offs+1]; + i2 = i1+kdt->nodes.ptr.p_int[offs]; + for(i=i1; i<=i2-1; i++) + { + + /* + * Calculate distance + */ + ptdist = (double)(0); + nx = kdt->nx; + if( kdt->normtype==0 ) + { + for(j=0; j<=nx-1; j++) + { + ptdist = ae_maxreal(ptdist, ae_fabs(kdt->xy.ptr.pp_double[i][j]-buf->x.ptr.p_double[j], _state), _state); + } + } + if( kdt->normtype==1 ) + { + for(j=0; j<=nx-1; j++) + { + ptdist = ptdist+ae_fabs(kdt->xy.ptr.pp_double[i][j]-buf->x.ptr.p_double[j], _state); + } + } + if( kdt->normtype==2 ) + { + for(j=0; j<=nx-1; j++) + { + ptdist = ptdist+ae_sqr(kdt->xy.ptr.pp_double[i][j]-buf->x.ptr.p_double[j], _state); + } + } + + /* + * Skip points with zero distance if self-matches are turned off + */ + if( ptdist==(double)0&&!buf->selfmatch ) + { + continue; + } + + /* + * We CAN'T process point if R-criterion isn't satisfied, + * i.e. (RNeeded<>0) AND (PtDist>R). + */ + if( buf->rneeded==(double)0||ptdist<=buf->rneeded ) + { + + /* + * R-criterion is satisfied, we must either: + * * replace worst point, if (KNeeded<>0) AND (KCur=KNeeded) + * (or skip, if worst point is better) + * * add point without replacement otherwise + */ + if( buf->kcurkneeded||buf->kneeded==0 ) + { + + /* + * add current point to heap without replacement + */ + tagheappushi(&buf->r, &buf->idx, &buf->kcur, ptdist, i, _state); + } + else + { + + /* + * New points are added or not, depending on their distance. + * If added, they replace element at the top of the heap + */ + if( ptdistr.ptr.p_double[0] ) + { + if( buf->kneeded==1 ) + { + buf->idx.ptr.p_int[0] = i; + buf->r.ptr.p_double[0] = ptdist; + } + else + { + tagheapreplacetopi(&buf->r, &buf->idx, buf->kneeded, ptdist, i, _state); + } + } + } + } + } + return; + } + + /* + * Simple split + */ + if( kdt->nodes.ptr.p_int[offs]==0 ) + { + + /* + * Load: + * * D dimension to split + * * S split position + */ + d = kdt->nodes.ptr.p_int[offs+1]; + s = kdt->splits.ptr.p_double[kdt->nodes.ptr.p_int[offs+2]]; + + /* + * Calculate: + * * ChildBestOffs child box with best chances + * * ChildWorstOffs child box with worst chances + */ + if( buf->x.ptr.p_double[d]<=s ) + { + childbestoffs = kdt->nodes.ptr.p_int[offs+3]; + childworstoffs = kdt->nodes.ptr.p_int[offs+4]; + bestisleft = ae_true; + } + else + { + childbestoffs = kdt->nodes.ptr.p_int[offs+4]; + childworstoffs = kdt->nodes.ptr.p_int[offs+3]; + bestisleft = ae_false; + } + + /* + * Navigate through childs + */ + for(i=0; i<=1; i++) + { + + /* + * Select child to process: + * * ChildOffs current child offset in Nodes[] + * * UpdateMin whether minimum or maximum value + * of bounding box is changed on update + */ + if( i==0 ) + { + childoffs = childbestoffs; + updatemin = !bestisleft; + } + else + { + updatemin = bestisleft; + childoffs = childworstoffs; + } + + /* + * Update bounding box and current distance + */ + if( updatemin ) + { + prevdist = buf->curdist; + t1 = buf->x.ptr.p_double[d]; + v = buf->curboxmin.ptr.p_double[d]; + if( t1<=s ) + { + if( kdt->normtype==0 ) + { + buf->curdist = ae_maxreal(buf->curdist, s-t1, _state); + } + if( kdt->normtype==1 ) + { + buf->curdist = buf->curdist-ae_maxreal(v-t1, (double)(0), _state)+s-t1; + } + if( kdt->normtype==2 ) + { + buf->curdist = buf->curdist-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(s-t1, _state); + } + } + buf->curboxmin.ptr.p_double[d] = s; + } + else + { + prevdist = buf->curdist; + t1 = buf->x.ptr.p_double[d]; + v = buf->curboxmax.ptr.p_double[d]; + if( t1>=s ) + { + if( kdt->normtype==0 ) + { + buf->curdist = ae_maxreal(buf->curdist, t1-s, _state); + } + if( kdt->normtype==1 ) + { + buf->curdist = buf->curdist-ae_maxreal(t1-v, (double)(0), _state)+t1-s; + } + if( kdt->normtype==2 ) + { + buf->curdist = buf->curdist-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-s, _state); + } + } + buf->curboxmax.ptr.p_double[d] = s; + } + + /* + * Decide: to dive into cell or not to dive + */ + if( buf->rneeded!=(double)0&&buf->curdist>buf->rneeded ) + { + todive = ae_false; + } + else + { + if( buf->kcurkneeded||buf->kneeded==0 ) + { + + /* + * KCurcurdist<=buf->r.ptr.p_double[0]*buf->approxf; + } + } + if( todive ) + { + nearestneighbor_kdtreequerynnrec(kdt, buf, childoffs, _state); + } + + /* + * Restore bounding box and distance + */ + if( updatemin ) + { + buf->curboxmin.ptr.p_double[d] = v; + } + else + { + buf->curboxmax.ptr.p_double[d] = v; + } + buf->curdist = prevdist; + } + return; + } +} + + +/************************************************************************* +Recursive subroutine for box queries. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreequeryboxrec(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_int_t offs, + ae_state *_state) +{ + ae_bool inbox; + ae_int_t nx; + ae_int_t i1; + ae_int_t i2; + ae_int_t i; + ae_int_t j; + ae_int_t d; + double s; + double v; + + + ae_assert(kdt->n>0, "KDTreeQueryBoxRec: internal error", _state); + nx = kdt->nx; + + /* + * Check that intersection of query box with bounding box is non-empty. + * This check is performed once for Offs=0 (tree root). + */ + if( offs==0 ) + { + for(j=0; j<=nx-1; j++) + { + if( buf->boxmin.ptr.p_double[j]>buf->curboxmax.ptr.p_double[j] ) + { + return; + } + if( buf->boxmax.ptr.p_double[j]curboxmin.ptr.p_double[j] ) + { + return; + } + } + } + + /* + * Leaf node. + * Process points. + */ + if( kdt->nodes.ptr.p_int[offs]>0 ) + { + i1 = kdt->nodes.ptr.p_int[offs+1]; + i2 = i1+kdt->nodes.ptr.p_int[offs]; + for(i=i1; i<=i2-1; i++) + { + + /* + * Check whether point is in box or not + */ + inbox = ae_true; + for(j=0; j<=nx-1; j++) + { + inbox = inbox&&kdt->xy.ptr.pp_double[i][j]>=buf->boxmin.ptr.p_double[j]; + inbox = inbox&&kdt->xy.ptr.pp_double[i][j]<=buf->boxmax.ptr.p_double[j]; + } + if( !inbox ) + { + continue; + } + + /* + * Add point to unordered list + */ + buf->r.ptr.p_double[buf->kcur] = 0.0; + buf->idx.ptr.p_int[buf->kcur] = i; + buf->kcur = buf->kcur+1; + } + return; + } + + /* + * Simple split + */ + if( kdt->nodes.ptr.p_int[offs]==0 ) + { + + /* + * Load: + * * D dimension to split + * * S split position + */ + d = kdt->nodes.ptr.p_int[offs+1]; + s = kdt->splits.ptr.p_double[kdt->nodes.ptr.p_int[offs+2]]; + + /* + * Check lower split (S is upper bound of new bounding box) + */ + if( s>=buf->boxmin.ptr.p_double[d] ) + { + v = buf->curboxmax.ptr.p_double[d]; + buf->curboxmax.ptr.p_double[d] = s; + nearestneighbor_kdtreequeryboxrec(kdt, buf, kdt->nodes.ptr.p_int[offs+3], _state); + buf->curboxmax.ptr.p_double[d] = v; + } + + /* + * Check upper split (S is lower bound of new bounding box) + */ + if( s<=buf->boxmax.ptr.p_double[d] ) + { + v = buf->curboxmin.ptr.p_double[d]; + buf->curboxmin.ptr.p_double[d] = s; + nearestneighbor_kdtreequeryboxrec(kdt, buf, kdt->nodes.ptr.p_int[offs+4], _state); + buf->curboxmin.ptr.p_double[d] = v; + } + return; + } +} + + +/************************************************************************* +Copies X[] to Buf.X[] +Loads distance from X[] to bounding box. +Initializes Buf.CurBox[]. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreeinitbox(const kdtree* kdt, + /* Real */ const ae_vector* x, + kdtreerequestbuffer* buf, + ae_state *_state) +{ + ae_int_t i; + double vx; + double vmin; + double vmax; + + + ae_assert(kdt->n>0, "KDTreeInitBox: internal error", _state); + + /* + * calculate distance from point to current bounding box + */ + buf->curdist = (double)(0); + if( kdt->normtype==0 ) + { + for(i=0; i<=kdt->nx-1; i++) + { + vx = x->ptr.p_double[i]; + vmin = kdt->boxmin.ptr.p_double[i]; + vmax = kdt->boxmax.ptr.p_double[i]; + buf->x.ptr.p_double[i] = vx; + buf->curboxmin.ptr.p_double[i] = vmin; + buf->curboxmax.ptr.p_double[i] = vmax; + if( vxcurdist = ae_maxreal(buf->curdist, vmin-vx, _state); + } + else + { + if( vx>vmax ) + { + buf->curdist = ae_maxreal(buf->curdist, vx-vmax, _state); + } + } + } + } + if( kdt->normtype==1 ) + { + for(i=0; i<=kdt->nx-1; i++) + { + vx = x->ptr.p_double[i]; + vmin = kdt->boxmin.ptr.p_double[i]; + vmax = kdt->boxmax.ptr.p_double[i]; + buf->x.ptr.p_double[i] = vx; + buf->curboxmin.ptr.p_double[i] = vmin; + buf->curboxmax.ptr.p_double[i] = vmax; + if( vxcurdist = buf->curdist+vmin-vx; + } + else + { + if( vx>vmax ) + { + buf->curdist = buf->curdist+vx-vmax; + } + } + } + } + if( kdt->normtype==2 ) + { + for(i=0; i<=kdt->nx-1; i++) + { + vx = x->ptr.p_double[i]; + vmin = kdt->boxmin.ptr.p_double[i]; + vmax = kdt->boxmax.ptr.p_double[i]; + buf->x.ptr.p_double[i] = vx; + buf->curboxmin.ptr.p_double[i] = vmin; + buf->curboxmax.ptr.p_double[i] = vmax; + if( vxcurdist = buf->curdist+ae_sqr(vmin-vx, _state); + } + else + { + if( vx>vmax ) + { + buf->curdist = buf->curdist+ae_sqr(vx-vmax, _state); + } + } + } + } +} + + +/************************************************************************* +This function allocates all dataset-independend array fields of KDTree, +i.e. such array fields that their dimensions do not depend on dataset +size. + +This function do not sets KDT.NX or KDT.NY - it just allocates arrays + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreeallocdatasetindependent(kdtree* kdt, + ae_int_t nx, + ae_int_t ny, + ae_state *_state) +{ + + + ae_assert(kdt->n>0, "KDTreeAllocDatasetIndependent: internal error", _state); + ae_vector_set_length(&kdt->boxmin, nx, _state); + ae_vector_set_length(&kdt->boxmax, nx, _state); +} + + +/************************************************************************* +This function allocates all dataset-dependent array fields of KDTree, i.e. +such array fields that their dimensions depend on dataset size. + +This function do not sets KDT.N, KDT.NX or KDT.NY - +it just allocates arrays. + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_kdtreeallocdatasetdependent(kdtree* kdt, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_state *_state) +{ + + + ae_assert(n>0, "KDTreeAllocDatasetDependent: internal error", _state); + ae_matrix_set_length(&kdt->xy, n, 2*nx+ny, _state); + ae_vector_set_length(&kdt->tags, n, _state); + ae_vector_set_length(&kdt->nodes, nearestneighbor_splitnodesize*2*n, _state); + ae_vector_set_length(&kdt->splits, 2*n, _state); +} + + +/************************************************************************* +This function checks consistency of request buffer structure with +dimensions of kd-tree object. + + -- ALGLIB -- + Copyright 02.04.2016 by Bochkanov Sergey +*************************************************************************/ +static void nearestneighbor_checkrequestbufferconsistency(const kdtree* kdt, + const kdtreerequestbuffer* buf, + ae_state *_state) +{ + + + ae_assert(buf->x.cnt>=kdt->nx, "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); + ae_assert(buf->idx.cnt>=kdt->n, "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); + ae_assert(buf->r.cnt>=kdt->n, "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); + ae_assert(buf->buf.cnt>=ae_maxint(kdt->n, kdt->nx, _state), "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); + ae_assert(buf->curboxmin.cnt>=kdt->nx, "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); + ae_assert(buf->curboxmax.cnt>=kdt->nx, "KDTree: dimensions of kdtreerequestbuffer are inconsistent with kdtree structure", _state); +} + + +void _kdtreerequestbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + kdtreerequestbuffer *p = (kdtreerequestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->boxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->boxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->buf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xqc, 0, DT_REAL, _state, make_automatic); +} + + +void _kdtreerequestbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + kdtreerequestbuffer *dst = (kdtreerequestbuffer*)_dst; + const kdtreerequestbuffer *src = (const kdtreerequestbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->boxmin, &src->boxmin, _state, make_automatic); + ae_vector_init_copy(&dst->boxmax, &src->boxmax, _state, make_automatic); + dst->kneeded = src->kneeded; + dst->rneeded = src->rneeded; + dst->selfmatch = src->selfmatch; + dst->approxf = src->approxf; + dst->kcur = src->kcur; + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->buf, &src->buf, _state, make_automatic); + ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic); + ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic); + dst->curdist = src->curdist; + ae_vector_init_copy(&dst->xqc, &src->xqc, _state, make_automatic); +} + + +void _kdtreerequestbuffer_clear(void* _p) +{ + kdtreerequestbuffer *p = (kdtreerequestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->boxmin); + ae_vector_clear(&p->boxmax); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->r); + ae_vector_clear(&p->buf); + ae_vector_clear(&p->curboxmin); + ae_vector_clear(&p->curboxmax); + ae_vector_clear(&p->xqc); +} + + +void _kdtreerequestbuffer_destroy(void* _p) +{ + kdtreerequestbuffer *p = (kdtreerequestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->boxmin); + ae_vector_destroy(&p->boxmax); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->r); + ae_vector_destroy(&p->buf); + ae_vector_destroy(&p->curboxmin); + ae_vector_destroy(&p->curboxmax); + ae_vector_destroy(&p->xqc); +} + + +void _kdtree_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + kdtree *p = (kdtree*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tags, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->boxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->boxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nodes, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->splits, 0, DT_REAL, _state, make_automatic); + _kdtreerequestbuffer_init(&p->innerbuf, _state, make_automatic); +} + + +void _kdtree_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + kdtree *dst = (kdtree*)_dst; + const kdtree *src = (const kdtree*)_src; + dst->n = src->n; + dst->nx = src->nx; + dst->ny = src->ny; + dst->normtype = src->normtype; + ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic); + ae_vector_init_copy(&dst->tags, &src->tags, _state, make_automatic); + ae_vector_init_copy(&dst->boxmin, &src->boxmin, _state, make_automatic); + ae_vector_init_copy(&dst->boxmax, &src->boxmax, _state, make_automatic); + ae_vector_init_copy(&dst->nodes, &src->nodes, _state, make_automatic); + ae_vector_init_copy(&dst->splits, &src->splits, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->innerbuf, &src->innerbuf, _state, make_automatic); + dst->debugcounter = src->debugcounter; +} + + +void _kdtree_clear(void* _p) +{ + kdtree *p = (kdtree*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->xy); + ae_vector_clear(&p->tags); + ae_vector_clear(&p->boxmin); + ae_vector_clear(&p->boxmax); + ae_vector_clear(&p->nodes); + ae_vector_clear(&p->splits); + _kdtreerequestbuffer_clear(&p->innerbuf); +} + + +void _kdtree_destroy(void* _p) +{ + kdtree *p = (kdtree*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->xy); + ae_vector_destroy(&p->tags); + ae_vector_destroy(&p->boxmin); + ae_vector_destroy(&p->boxmax); + ae_vector_destroy(&p->nodes); + ae_vector_destroy(&p->splits); + _kdtreerequestbuffer_destroy(&p->innerbuf); +} + + +#endif + +} + diff --git a/core/alglib/alglibmisc.h b/core/alglib/alglibmisc.h index 8209ac6e..00536a2b 100644 --- a/core/alglib/alglibmisc.h +++ b/core/alglib/alglibmisc.h @@ -1,769 +1,2132 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _alglibmisc_pkg_h -#define _alglibmisc_pkg_h -#include "ap.h" -#include "alglibinternal.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t magicv; -} hqrndstate; -typedef struct -{ - ae_int_t n; - ae_int_t nx; - ae_int_t ny; - ae_int_t normtype; - ae_matrix xy; - ae_vector tags; - ae_vector boxmin; - ae_vector boxmax; - ae_vector nodes; - ae_vector splits; - ae_vector x; - ae_int_t kneeded; - double rneeded; - ae_bool selfmatch; - double approxf; - ae_int_t kcur; - ae_vector idx; - ae_vector r; - ae_vector buf; - ae_vector curboxmin; - ae_vector curboxmax; - double curdist; - ae_int_t debugcounter; -} kdtree; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - -/************************************************************************* -Portable high quality random number generator state. -Initialized with HQRNDRandomize() or HQRNDSeed(). - -Fields: - S1, S2 - seed values - V - precomputed value - MagicV - 'magic' value used to determine whether State structure - was correctly initialized. -*************************************************************************/ -class _hqrndstate_owner -{ -public: - _hqrndstate_owner(); - _hqrndstate_owner(const _hqrndstate_owner &rhs); - _hqrndstate_owner& operator=(const _hqrndstate_owner &rhs); - virtual ~_hqrndstate_owner(); - alglib_impl::hqrndstate* c_ptr(); - alglib_impl::hqrndstate* c_ptr() const; -protected: - alglib_impl::hqrndstate *p_struct; -}; -class hqrndstate : public _hqrndstate_owner -{ -public: - hqrndstate(); - hqrndstate(const hqrndstate &rhs); - hqrndstate& operator=(const hqrndstate &rhs); - virtual ~hqrndstate(); - -}; - -/************************************************************************* - -*************************************************************************/ -class _kdtree_owner -{ -public: - _kdtree_owner(); - _kdtree_owner(const _kdtree_owner &rhs); - _kdtree_owner& operator=(const _kdtree_owner &rhs); - virtual ~_kdtree_owner(); - alglib_impl::kdtree* c_ptr(); - alglib_impl::kdtree* c_ptr() const; -protected: - alglib_impl::kdtree *p_struct; -}; -class kdtree : public _kdtree_owner -{ -public: - kdtree(); - kdtree(const kdtree &rhs); - kdtree& operator=(const kdtree &rhs); - virtual ~kdtree(); - -}; - -/************************************************************************* -HQRNDState initialization with random values which come from standard -RNG. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndrandomize(hqrndstate &state); - - -/************************************************************************* -HQRNDState initialization with seed values - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state); - - -/************************************************************************* -This function generates random real number in (0,1), -not including interval boundaries - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrnduniformr(const hqrndstate &state); - - -/************************************************************************* -This function generates random integer number in [0, N) - -1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() -2. N can be any positive number except for very large numbers: - * close to 2^31 on 32-bit systems - * close to 2^62 on 64-bit systems - An exception will be generated if N is too large. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -ae_int_t hqrnduniformi(const hqrndstate &state, const ae_int_t n); - - -/************************************************************************* -Random number generator: normal numbers - -This function generates one random number from normal distribution. -Its performance is equal to that of HQRNDNormal2() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double hqrndnormal(const hqrndstate &state); - - -/************************************************************************* -Random number generator: random X and Y such that X^2+Y^2=1 - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndunit2(const hqrndstate &state, double &x, double &y); - - -/************************************************************************* -Random number generator: normal numbers - -This function generates two independent random numbers from normal -distribution. Its performance is equal to that of HQRNDNormal() - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void hqrndnormal2(const hqrndstate &state, double &x1, double &x2); - - -/************************************************************************* -Random number generator: exponential distribution - -State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). - - -- ALGLIB -- - Copyright 11.08.2007 by Bochkanov Sergey -*************************************************************************/ -double hqrndexponential(const hqrndstate &state, const double lambdav); - - -/************************************************************************* -This function generates random number from discrete distribution given by -finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample - N - number of elements to use, N>=1 - -RESULT - this function returns one of the X[i] for random i=0..N-1 - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrnddiscrete(const hqrndstate &state, const real_1d_array &x, const ae_int_t n); - - -/************************************************************************* -This function generates random number from continuous distribution given -by finite sample X. - -INPUT PARAMETERS - State - high quality random number generator, must be - initialized with HQRNDRandomize() or HQRNDSeed(). - X - finite sample, array[N] (can be larger, in this case only - leading N elements are used). THIS ARRAY MUST BE SORTED BY - ASCENDING. - N - number of elements to use, N>=1 - -RESULT - this function returns random number from continuous distribution which - tries to approximate X as mush as possible. min(X)<=Result<=max(X). - - -- ALGLIB -- - Copyright 08.11.2011 by Bochkanov Sergey -*************************************************************************/ -double hqrndcontinuous(const hqrndstate &state, const real_1d_array &x, const ae_int_t n); - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void kdtreeserialize(kdtree &obj, std::string &s_out); - - -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void kdtreeunserialize(std::string &s_in, kdtree &obj); - - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values and optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - N - number of points, N>=0. - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); -void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); - - -/************************************************************************* -KD-tree creation - -This subroutine creates KD-tree from set of X-values, integer tags and -optional Y-values - -INPUT PARAMETERS - XY - dataset, array[0..N-1,0..NX+NY-1]. - one row corresponds to one point. - first NX columns contain X-values, next NY (NY may be zero) - columns may contain associated Y-values - Tags - tags, array[0..N-1], contains integer tags associated - with points. - N - number of points, N>=0 - NX - space dimension, NX>=1. - NY - number of optional Y-values, NY>=0. - NormType- norm type: - * 0 denotes infinity-norm - * 1 denotes 1-norm - * 2 denotes 2-norm (Euclidean norm) - -OUTPUT PARAMETERS - KDT - KD-tree - -NOTES - -1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory - requirements. -2. Although KD-trees may be used with any combination of N and NX, they - are more efficient than brute-force search only when N >> 4^NX. So they - are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another - inefficient case, because simple binary search (without additional - structures) is much more efficient in such tasks than KD-trees. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); -void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt); - - -/************************************************************************* -K-NN query: K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of actual neighbors found (either K or N, if K>N). - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch); -ae_int_t kdtreequeryknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k); - - -/************************************************************************* -R-NN query: all points within R-sphere centered at X - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - R - radius of sphere (in corresponding norm), R>0 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - -RESULT - number of neighbors found, >=0 - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -actual results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch); -ae_int_t kdtreequeryrnn(const kdtree &kdt, const real_1d_array &x, const double r); - - -/************************************************************************* -K-NN query: approximate K nearest neighbors - -INPUT PARAMETERS - KDT - KD-tree - X - point, array[0..NX-1]. - K - number of neighbors to return, K>=1 - SelfMatch - whether self-matches are allowed: - * if True, nearest neighbor may be the point itself - (if it exists in original dataset) - * if False, then only points with non-zero distance - are returned - * if not given, considered True - Eps - approximation factor, Eps>=0. eps-approximate nearest - neighbor is a neighbor whose distance from X is at - most (1+eps) times distance of true nearest neighbor. - -RESULT - number of actual neighbors found (either K or N, if K>N). - -NOTES - significant performance gain may be achieved only when Eps is is on - the order of magnitude of 1 or larger. - -This subroutine performs query and stores its result in the internal -structures of the KD-tree. You can use following subroutines to obtain -these results: -* KDTreeQueryResultsX() to get X-values -* KDTreeQueryResultsXY() to get X- and Y-values -* KDTreeQueryResultsTags() to get tag values -* KDTreeQueryResultsDistances() to get distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps); -ae_int_t kdtreequeryaknn(const kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps); - - -/************************************************************************* -X-values from last query - -INPUT PARAMETERS - KDT - KD-tree - X - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - X - rows are filled with X-values - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x); - - -/************************************************************************* -X- and Y-values from last query - -INPUT PARAMETERS - KDT - KD-tree - XY - possibly pre-allocated buffer. If XY is too small to store - result, it is resized. If size(XY) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - XY - rows are filled with points: first NX columns with - X-values, next NY columns - with Y-values. - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsTags() tag values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy); - - -/************************************************************************* -Tags from last query - -INPUT PARAMETERS - KDT - KD-tree - Tags - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - Tags - filled with tags associated with points, - or, when no tags were supplied, with zeros - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsDistances() distances - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags); - - -/************************************************************************* -Distances from last query - -INPUT PARAMETERS - KDT - KD-tree - R - possibly pre-allocated buffer. If X is too small to store - result, it is resized. If size(X) is enough to store - result, it is left unchanged. - -OUTPUT PARAMETERS - R - filled with distances (in corresponding norm) - -NOTES -1. points are ordered by distance from the query point (first = closest) -2. if XY is larger than required to store result, only leading part will - be overwritten; trailing part will be left unchanged. So if on input - XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get - XY = [[1,2],[C,D]]. This is done purposely to increase performance; if - you want function to resize array according to result size, use - function with same name and suffix 'I'. - -SEE ALSO -* KDTreeQueryResultsX() X-values -* KDTreeQueryResultsXY() X- and Y-values -* KDTreeQueryResultsTags() tag values - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r); - - -/************************************************************************* -X-values from last query; 'interactive' variant for languages like Python -which support constructs like "X = KDTreeQueryResultsXI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x); - - -/************************************************************************* -XY-values from last query; 'interactive' variant for languages like Python -which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy); - - -/************************************************************************* -Tags from last query; 'interactive' variant for languages like Python -which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and -interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags); - - -/************************************************************************* -Distances from last query; 'interactive' variant for languages like Python -which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" -and interactive mode of interpreter. - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void hqrndrandomize(hqrndstate* state, ae_state *_state); -void hqrndseed(ae_int_t s1, - ae_int_t s2, - hqrndstate* state, - ae_state *_state); -double hqrnduniformr(hqrndstate* state, ae_state *_state); -ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state); -double hqrndnormal(hqrndstate* state, ae_state *_state); -void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state); -void hqrndnormal2(hqrndstate* state, - double* x1, - double* x2, - ae_state *_state); -double hqrndexponential(hqrndstate* state, - double lambdav, - ae_state *_state); -double hqrnddiscrete(hqrndstate* state, - /* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -double hqrndcontinuous(hqrndstate* state, - /* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -ae_bool _hqrndstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _hqrndstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _hqrndstate_clear(void* _p); -void _hqrndstate_destroy(void* _p); -void kdtreebuild(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_int_t normtype, - kdtree* kdt, - ae_state *_state); -void kdtreebuildtagged(/* Real */ ae_matrix* xy, - /* Integer */ ae_vector* tags, - ae_int_t n, - ae_int_t nx, - ae_int_t ny, - ae_int_t normtype, - kdtree* kdt, - ae_state *_state); -ae_int_t kdtreequeryknn(kdtree* kdt, - /* Real */ ae_vector* x, - ae_int_t k, - ae_bool selfmatch, - ae_state *_state); -ae_int_t kdtreequeryrnn(kdtree* kdt, - /* Real */ ae_vector* x, - double r, - ae_bool selfmatch, - ae_state *_state); -ae_int_t kdtreequeryaknn(kdtree* kdt, - /* Real */ ae_vector* x, - ae_int_t k, - ae_bool selfmatch, - double eps, - ae_state *_state); -void kdtreequeryresultsx(kdtree* kdt, - /* Real */ ae_matrix* x, - ae_state *_state); -void kdtreequeryresultsxy(kdtree* kdt, - /* Real */ ae_matrix* xy, - ae_state *_state); -void kdtreequeryresultstags(kdtree* kdt, - /* Integer */ ae_vector* tags, - ae_state *_state); -void kdtreequeryresultsdistances(kdtree* kdt, - /* Real */ ae_vector* r, - ae_state *_state); -void kdtreequeryresultsxi(kdtree* kdt, - /* Real */ ae_matrix* x, - ae_state *_state); -void kdtreequeryresultsxyi(kdtree* kdt, - /* Real */ ae_matrix* xy, - ae_state *_state); -void kdtreequeryresultstagsi(kdtree* kdt, - /* Integer */ ae_vector* tags, - ae_state *_state); -void kdtreequeryresultsdistancesi(kdtree* kdt, - /* Real */ ae_vector* r, - ae_state *_state); -void kdtreealloc(ae_serializer* s, kdtree* tree, ae_state *_state); -void kdtreeserialize(ae_serializer* s, kdtree* tree, ae_state *_state); -void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state); -ae_bool _kdtree_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _kdtree_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _kdtree_clear(void* _p); -void _kdtree_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _alglibmisc_pkg_h +#define _alglibmisc_pkg_h +#include "ap.h" +#include "alglibinternal.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t i; + ae_complex c; + ae_vector a; +} xdebugrecord1; +#endif +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t magicv; +} hqrndstate; +#endif +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector x; + ae_vector boxmin; + ae_vector boxmax; + ae_int_t kneeded; + double rneeded; + ae_bool selfmatch; + double approxf; + ae_int_t kcur; + ae_vector idx; + ae_vector r; + ae_vector buf; + ae_vector curboxmin; + ae_vector curboxmax; + double curdist; + ae_vector xqc; +} kdtreerequestbuffer; +typedef struct +{ + ae_int_t n; + ae_int_t nx; + ae_int_t ny; + ae_int_t normtype; + ae_matrix xy; + ae_vector tags; + ae_vector boxmin; + ae_vector boxmax; + ae_vector nodes; + ae_vector splits; + kdtreerequestbuffer innerbuf; + ae_int_t debugcounter; +} kdtree; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) +class _xdebugrecord1_owner; +class xdebugrecord1; + + +/************************************************************************* +This is a debug class intended for testing ALGLIB interface generator. +Never use it in any real life project. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +class _xdebugrecord1_owner +{ +public: + _xdebugrecord1_owner(); + _xdebugrecord1_owner(alglib_impl::xdebugrecord1 *attach_to); + _xdebugrecord1_owner(const _xdebugrecord1_owner &rhs); + _xdebugrecord1_owner& operator=(const _xdebugrecord1_owner &rhs); + virtual ~_xdebugrecord1_owner(); + alglib_impl::xdebugrecord1* c_ptr(); + const alglib_impl::xdebugrecord1* c_ptr() const; +protected: + alglib_impl::xdebugrecord1 *p_struct; + bool is_attached; +}; +class xdebugrecord1 : public _xdebugrecord1_owner +{ +public: + xdebugrecord1(); + xdebugrecord1(alglib_impl::xdebugrecord1 *attach_to); + xdebugrecord1(const xdebugrecord1 &rhs); + xdebugrecord1& operator=(const xdebugrecord1 &rhs); + virtual ~xdebugrecord1(); + ae_int_t &i; + alglib::complex &c; + real_1d_array a; + + +}; +#endif + +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +class _hqrndstate_owner; +class hqrndstate; + + +/************************************************************************* +Portable high quality random number generator state. +Initialized with HQRNDRandomize() or HQRNDSeed(). + +Fields: + S1, S2 - seed values + V - precomputed value + MagicV - 'magic' value used to determine whether State structure + was correctly initialized. +*************************************************************************/ +class _hqrndstate_owner +{ +public: + _hqrndstate_owner(); + _hqrndstate_owner(alglib_impl::hqrndstate *attach_to); + _hqrndstate_owner(const _hqrndstate_owner &rhs); + _hqrndstate_owner& operator=(const _hqrndstate_owner &rhs); + virtual ~_hqrndstate_owner(); + alglib_impl::hqrndstate* c_ptr(); + const alglib_impl::hqrndstate* c_ptr() const; +protected: + alglib_impl::hqrndstate *p_struct; + bool is_attached; +}; +class hqrndstate : public _hqrndstate_owner +{ +public: + hqrndstate(); + hqrndstate(alglib_impl::hqrndstate *attach_to); + hqrndstate(const hqrndstate &rhs); + hqrndstate& operator=(const hqrndstate &rhs); + virtual ~hqrndstate(); + + +}; +#endif + +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +class _kdtreerequestbuffer_owner; +class kdtreerequestbuffer; +class _kdtree_owner; +class kdtree; + + +/************************************************************************* +Buffer object which is used to perform nearest neighbor requests in the +multithreaded mode (multiple threads working with same KD-tree object). + +This object should be created with KDTreeCreateRequestBuffer(). +*************************************************************************/ +class _kdtreerequestbuffer_owner +{ +public: + _kdtreerequestbuffer_owner(); + _kdtreerequestbuffer_owner(alglib_impl::kdtreerequestbuffer *attach_to); + _kdtreerequestbuffer_owner(const _kdtreerequestbuffer_owner &rhs); + _kdtreerequestbuffer_owner& operator=(const _kdtreerequestbuffer_owner &rhs); + virtual ~_kdtreerequestbuffer_owner(); + alglib_impl::kdtreerequestbuffer* c_ptr(); + const alglib_impl::kdtreerequestbuffer* c_ptr() const; +protected: + alglib_impl::kdtreerequestbuffer *p_struct; + bool is_attached; +}; +class kdtreerequestbuffer : public _kdtreerequestbuffer_owner +{ +public: + kdtreerequestbuffer(); + kdtreerequestbuffer(alglib_impl::kdtreerequestbuffer *attach_to); + kdtreerequestbuffer(const kdtreerequestbuffer &rhs); + kdtreerequestbuffer& operator=(const kdtreerequestbuffer &rhs); + virtual ~kdtreerequestbuffer(); + + +}; + + +/************************************************************************* +KD-tree object. +*************************************************************************/ +class _kdtree_owner +{ +public: + _kdtree_owner(); + _kdtree_owner(alglib_impl::kdtree *attach_to); + _kdtree_owner(const _kdtree_owner &rhs); + _kdtree_owner& operator=(const _kdtree_owner &rhs); + virtual ~_kdtree_owner(); + alglib_impl::kdtree* c_ptr(); + const alglib_impl::kdtree* c_ptr() const; +protected: + alglib_impl::kdtree *p_struct; + bool is_attached; +}; +class kdtree : public _kdtree_owner +{ +public: + kdtree(); + kdtree(alglib_impl::kdtree *attach_to); + kdtree(const kdtree &rhs); + kdtree& operator=(const kdtree &rhs); + virtual ~kdtree(); + + +}; +#endif + +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebuginitrecord1(xdebugrecord1 &rec1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Creates and returns XDebugRecord1 structure: +* integer and complex fields of Rec1 are set to 1 and 1+i correspondingly +* array field of Rec1 is set to [2,3] + + -- ALGLIB -- + Copyright 27.05.2014 by Bochkanov Sergey +*************************************************************************/ +void xdebugupdaterecord1(xdebugrecord1 &rec1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 1D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb1count(const boolean_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1not(boolean_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1appendcopy(boolean_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered elements set to True. +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb1outeven(const ae_int_t n, boolean_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi1sum(const integer_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1neg(integer_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1appendcopy(integer_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I, and odd-numbered +ones set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi1outeven(const ae_int_t n, integer_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1sum(const real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr1internalcopyandsum(const real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1neg(real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1appendcopy(real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[I] set to I*0.25, +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr1outeven(const ae_int_t n, real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +alglib::complex xdebugc1sum(const complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -A[I] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1neg(complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Appends copy of array to itself. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1appendcopy(complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate N-element array with even-numbered A[K] set to (x,y) = (K*0.25, K*0.125) +and odd-numbered ones are set to 0. + +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc1outeven(const ae_int_t n, complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Counts number of True values in the boolean 2D array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugb2count(const boolean_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by NOT(a[i]). +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2not(boolean_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2transpose(boolean_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)>0" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugb2outsin(const ae_int_t m, const ae_int_t n, boolean_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +ae_int_t xdebugi2sum(const integer_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2neg(integer_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2transpose(integer_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sign(Sin(3*I+5*J))" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugi2outsin(const ae_int_t m, const ae_int_t n, integer_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2sum(const real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + +Internally it creates a copy of a. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugr2internalcopyandsum(const real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2neg(real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2transpose(real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugr2outsin(const ae_int_t m, const ae_int_t n, real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of elements in the array. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +alglib::complex xdebugc2sum(const complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Replace all values in array by -a[i,j] +Array is passed using "shared" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2neg(complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Transposes array. +Array is passed using "var" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2transpose(complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Generate MxN matrix with elements set to "Sin(3*I+5*J),Cos(3*I+5*J)" +Array is passed using "out" convention. + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +void xdebugc2outsincos(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is debug function intended for testing ALGLIB interface generator. +Never use it in any real life project. + +Returns sum of a[i,j]*(1+b[i,j]) such that c[i,j] is True + + -- ALGLIB -- + Copyright 11.10.2013 by Bochkanov Sergey +*************************************************************************/ +double xdebugmaskedbiasedproductsum(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const real_2d_array &b, const boolean_2d_array &c, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +HQRNDState initialization with random values which come from standard +RNG. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndrandomize(hqrndstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +HQRNDState initialization with seed values + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndseed(const ae_int_t s1, const ae_int_t s2, hqrndstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function generates random real number in (0,1), +not including interval boundaries + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrnduniformr(hqrndstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function generates random integer number in [0, N) + +1. State structure must be initialized with HQRNDRandomize() or HQRNDSeed() +2. N can be any positive number except for very large numbers: + * close to 2^31 on 32-bit systems + * close to 2^62 on 64-bit systems + An exception will be generated if N is too large. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +ae_int_t hqrnduniformi(hqrndstate &state, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: normal numbers + +This function generates one random number from normal distribution. +Its performance is equal to that of HQRNDNormal2() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double hqrndnormal(hqrndstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: vector with random entries (normal distribution) + +This function generates N random numbers from normal distribution. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalv(hqrndstate &state, const ae_int_t n, real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: matrix with random entries (normal distribution) + +This function generates MxN random matrix. + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormalm(hqrndstate &state, const ae_int_t m, const ae_int_t n, real_2d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: random X and Y such that X^2+Y^2=1 + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndunit2(hqrndstate &state, double &x, double &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: normal numbers + +This function generates two independent random numbers from normal +distribution. Its performance is equal to that of HQRNDNormal() + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void hqrndnormal2(hqrndstate &state, double &x1, double &x2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Random number generator: exponential distribution + +State structure must be initialized with HQRNDRandomize() or HQRNDSeed(). + + -- ALGLIB -- + Copyright 11.08.2007 by Bochkanov Sergey +*************************************************************************/ +double hqrndexponential(hqrndstate &state, const double lambdav, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function generates random number from discrete distribution given by +finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample + N - number of elements to use, N>=1 + +RESULT + this function returns one of the X[i] for random i=0..N-1 + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrnddiscrete(hqrndstate &state, const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function generates random number from continuous distribution given +by finite sample X. + +INPUT PARAMETERS + State - high quality random number generator, must be + initialized with HQRNDRandomize() or HQRNDSeed(). + X - finite sample, array[N] (can be larger, in this case only + leading N elements are used). THIS ARRAY MUST BE SORTED BY + ASCENDING. + N - number of elements to use, N>=1 + +RESULT + this function returns random number from continuous distribution which + tries to approximate X as mush as possible. min(X)<=Result<=max(X). + + -- ALGLIB -- + Copyright 08.11.2011 by Bochkanov Sergey +*************************************************************************/ +double hqrndcontinuous(hqrndstate &state, const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void kdtreeserialize(const kdtree &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void kdtreeserialize(const kdtree &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void kdtreeunserialize(const std::string &s_in, kdtree &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void kdtreeunserialize(const std::istream &s_in, kdtree &obj); + + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values and optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + N - number of points, N>=0. + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuild(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams = alglib::xdefault); +void kdtreebuild(const real_2d_array &xy, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +KD-tree creation + +This subroutine creates KD-tree from set of X-values, integer tags and +optional Y-values + +INPUT PARAMETERS + XY - dataset, array[0..N-1,0..NX+NY-1]. + one row corresponds to one point. + first NX columns contain X-values, next NY (NY may be zero) + columns may contain associated Y-values + Tags - tags, array[0..N-1], contains integer tags associated + with points. + N - number of points, N>=0 + NX - space dimension, NX>=1. + NY - number of optional Y-values, NY>=0. + NormType- norm type: + * 0 denotes infinity-norm + * 1 denotes 1-norm + * 2 denotes 2-norm (Euclidean norm) + +OUTPUT PARAMETERS + KDT - KD-tree + +NOTES + +1. KD-tree creation have O(N*logN) complexity and O(N*(2*NX+NY)) memory + requirements. +2. Although KD-trees may be used with any combination of N and NX, they + are more efficient than brute-force search only when N >> 4^NX. So they + are most useful in low-dimensional tasks (NX=2, NX=3). NX=1 is another + inefficient case, because simple binary search (without additional + structures) is much more efficient in such tasks than KD-trees. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t n, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams = alglib::xdefault); +void kdtreebuildtagged(const real_2d_array &xy, const integer_1d_array &tags, const ae_int_t nx, const ae_int_t ny, const ae_int_t normtype, kdtree &kdt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel KD-tree requests. + +KD-tree subpackage provides two sets of request functions - ones which use +internal buffer of KD-tree object (these functions are single-threaded +because they use same buffer, which can not shared between threads), and +ones which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + KDT - KD-tree which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: KD-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +void kdtreecreaterequestbuffer(const kdtree &kdt, kdtreerequestbuffer &buf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +K-NN query: K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreequeryknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +K-NN query: K nearest neighbors, using external thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - kd-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of actual neighbors found (either K or N, if K>N). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreetsqueryknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, ordered by distance +between point and X (by ascending). + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnn(kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreequeryrnn(kdtree &kdt, const real_1d_array &x, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, no ordering by +distance as undicated by "U" suffix (faster that ordered query, for large +queries - significantly faster). + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: kdtreetsqueryrnn() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +actual results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + + -- ALGLIB -- + Copyright 01.11.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryrnnu(kdtree &kdt, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreequeryrnnu(kdtree &kdt, const real_1d_array &x, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, sorted by distance between point and X (by ascending) + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +NOTE: it is also possible to perform undordered queries performed by means + of kdtreequeryrnnu() and kdtreetsqueryrnnu() functions. Such queries + are faster because we do not have to use heap structure for sorting. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreetsqueryrnn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +R-NN query: all points within R-sphere centered at X, using external +thread-local buffer, no ordering by distance as undicated by "U" suffix +(faster that ordered query, for large queries - significantly faster). + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + R - radius of sphere (in corresponding norm), R>0 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + +RESULT + number of neighbors found, >=0 + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +As indicated by "U" suffix, this function returns unordered results. + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryrnnu(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const bool selfmatch, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreetsqueryrnnu(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +K-NN query: approximate K nearest neighbors + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryAKNN() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() to get distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequeryaknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreequeryaknn(kdtree &kdt, const real_1d_array &x, const ae_int_t k, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +K-NN query: approximate K nearest neighbors, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + X - point, array[0..NX-1]. + K - number of neighbors to return, K>=1 + SelfMatch - whether self-matches are allowed: + * if True, nearest neighbor may be the point itself + (if it exists in original dataset) + * if False, then only points with non-zero distance + are returned + * if not given, considered True + Eps - approximation factor, Eps>=0. eps-approximate nearest + neighbor is a neighbor whose distance from X is at + most (1+eps) times distance of true nearest neighbor. + +RESULT + number of actual neighbors found (either K or N, if K>N). + +NOTES + significant performance gain may be achieved only when Eps is is on + the order of magnitude of 1 or larger. + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "buf" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() to get distances + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 18.03.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsqueryaknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const bool selfmatch, const double eps, const xparams _xparams = alglib::xdefault); +ae_int_t kdtreetsqueryaknn(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &x, const ae_int_t k, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Box query: all points within user-specified box. + +IMPORTANT: this function can not be used in multithreaded code because it + uses internal temporary buffer of kd-tree object, which can not + be shared between multiple threads. If you want to perform + parallel requests, use function which uses external request + buffer: KDTreeTsQueryBox() ("Ts" stands for "thread-safe"). + +INPUT PARAMETERS + KDT - KD-tree + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the KD-tree. You can use following subroutines to obtain +these results: +* KDTreeQueryResultsX() to get X-values +* KDTreeQueryResultsXY() to get X- and Y-values +* KDTreeQueryResultsTags() to get tag values +* KDTreeQueryResultsDistances() returns zeros for this request + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreequerybox(kdtree &kdt, const real_1d_array &boxmin, const real_1d_array &boxmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Box query: all points within user-specified box, using thread-local buffer. + +You can call this function from multiple threads for same kd-tree instance, +assuming that different instances of buffer object are passed to different +threads. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure with kdtreecreaterequestbuffer() + function. + BoxMin - lower bounds, array[0..NX-1]. + BoxMax - upper bounds, array[0..NX-1]. + +RESULT + number of actual neighbors found (in [0,N]). + +This subroutine performs query and stores its result in the internal +structures of the buffer object. You can use following subroutines to +obtain these results (pay attention to "ts" in their names): +* KDTreeTsQueryResultsX() to get X-values +* KDTreeTsQueryResultsXY() to get X- and Y-values +* KDTreeTsQueryResultsTags() to get tag values +* KDTreeTsQueryResultsDistances() returns zeros for this query + +NOTE: this particular query returns unordered results, because there is no + meaningful way of ordering points. Furthermore, no 'distance' is + associated with points - it is either INSIDE or OUTSIDE (so request + for distances will return zeros). + +IMPORTANT: kd-tree buffer should be used only with KD-tree object which + was used to initialize buffer. Any attempt to use biffer with + different object is dangerous - you may get integrity check + failure (exception) because sizes of internal arrays do not fit + to dimensions of KD-tree structure. + + -- ALGLIB -- + Copyright 14.05.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t kdtreetsquerybox(const kdtree &kdt, kdtreerequestbuffer &buf, const real_1d_array &boxmin, const real_1d_array &boxmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +X-values from last query. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsx(). + +INPUT PARAMETERS + KDT - KD-tree + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsx(const kdtree &kdt, real_2d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +X- and Y-values from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsxy(). + +INPUT PARAMETERS + KDT - KD-tree + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxy(const kdtree &kdt, real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Tags from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstags(const kdtree &kdt, integer_1d_array &tags, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Distances from last query + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - kdtreetsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistances(const kdtree &kdt, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +X-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + X - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + X - rows are filled with X-values + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsx(const kdtree &kdt, const kdtreerequestbuffer &buf, real_2d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +X- and Y-values from last query associated with kdtreerequestbuffer object. + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + XY - possibly pre-allocated buffer. If XY is too small to store + result, it is resized. If size(XY) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + XY - rows are filled with points: first NX columns with + X-values, next NY columns - with Y-values. + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsTags() tag values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsxy(const kdtree &kdt, const kdtreerequestbuffer &buf, real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Tags from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultstags(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + Tags - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + Tags - filled with tags associated with points, + or, when no tags were supplied, with zeros + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsDistances() distances + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultstags(const kdtree &kdt, const kdtreerequestbuffer &buf, integer_1d_array &tags, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Distances from last query associated with kdtreerequestbuffer object. + +This function retuns results stored in the internal buffer of kd-tree +object. If you performed buffered requests (ones which use instances of +kdtreerequestbuffer class), you should call buffered version of this +function - KDTreeTsqueryresultsdistances(). + +INPUT PARAMETERS + KDT - KD-tree + Buf - request buffer object created for this particular + instance of kd-tree structure. + R - possibly pre-allocated buffer. If X is too small to store + result, it is resized. If size(X) is enough to store + result, it is left unchanged. + +OUTPUT PARAMETERS + R - filled with distances (in corresponding norm) + +NOTES +1. points are ordered by distance from the query point (first = closest) +2. if XY is larger than required to store result, only leading part will + be overwritten; trailing part will be left unchanged. So if on input + XY = [[A,B],[C,D]], and result is [1,2], then on exit we will get + XY = [[1,2],[C,D]]. This is done purposely to increase performance; if + you want function to resize array according to result size, use + function with same name and suffix 'I'. + +SEE ALSO +* KDTreeQueryResultsX() X-values +* KDTreeQueryResultsXY() X- and Y-values +* KDTreeQueryResultsTags() tag values + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreetsqueryresultsdistances(const kdtree &kdt, const kdtreerequestbuffer &buf, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +X-values from last query; 'interactive' variant for languages like Python +which support constructs like "X = KDTreeQueryResultsXI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxi(const kdtree &kdt, real_2d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +XY-values from last query; 'interactive' variant for languages like Python +which support constructs like "XY = KDTreeQueryResultsXYI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsxyi(const kdtree &kdt, real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Tags from last query; 'interactive' variant for languages like Python +which support constructs like "Tags = KDTreeQueryResultsTagsI(KDT)" and +interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultstagsi(const kdtree &kdt, integer_1d_array &tags, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Distances from last query; 'interactive' variant for languages like Python +which support constructs like "R = KDTreeQueryResultsDistancesI(KDT)" +and interactive mode of interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void kdtreequeryresultsdistancesi(const kdtree &kdt, real_1d_array &r, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_XDEBUG) || !defined(AE_PARTIAL_BUILD) +void xdebuginitrecord1(xdebugrecord1* rec1, ae_state *_state); +void xdebugupdaterecord1(xdebugrecord1* rec1, ae_state *_state); +ae_int_t xdebugb1count(/* Boolean */ const ae_vector* a, ae_state *_state); +void xdebugb1not(/* Boolean */ ae_vector* a, ae_state *_state); +void xdebugb1appendcopy(/* Boolean */ ae_vector* a, ae_state *_state); +void xdebugb1outeven(ae_int_t n, + /* Boolean */ ae_vector* a, + ae_state *_state); +ae_int_t xdebugi1sum(/* Integer */ const ae_vector* a, ae_state *_state); +void xdebugi1neg(/* Integer */ ae_vector* a, ae_state *_state); +void xdebugi1appendcopy(/* Integer */ ae_vector* a, ae_state *_state); +void xdebugi1outeven(ae_int_t n, + /* Integer */ ae_vector* a, + ae_state *_state); +double xdebugr1sum(/* Real */ const ae_vector* a, ae_state *_state); +double xdebugr1internalcopyandsum(/* Real */ const ae_vector* _a, + ae_state *_state); +void xdebugr1neg(/* Real */ ae_vector* a, ae_state *_state); +void xdebugr1appendcopy(/* Real */ ae_vector* a, ae_state *_state); +void xdebugr1outeven(ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state); +ae_complex xdebugc1sum(/* Complex */ const ae_vector* a, ae_state *_state); +void xdebugc1neg(/* Complex */ ae_vector* a, ae_state *_state); +void xdebugc1appendcopy(/* Complex */ ae_vector* a, ae_state *_state); +void xdebugc1outeven(ae_int_t n, + /* Complex */ ae_vector* a, + ae_state *_state); +ae_int_t xdebugb2count(/* Boolean */ const ae_matrix* a, ae_state *_state); +void xdebugb2not(/* Boolean */ ae_matrix* a, ae_state *_state); +void xdebugb2transpose(/* Boolean */ ae_matrix* a, ae_state *_state); +void xdebugb2outsin(ae_int_t m, + ae_int_t n, + /* Boolean */ ae_matrix* a, + ae_state *_state); +ae_int_t xdebugi2sum(/* Integer */ const ae_matrix* a, ae_state *_state); +void xdebugi2neg(/* Integer */ ae_matrix* a, ae_state *_state); +void xdebugi2transpose(/* Integer */ ae_matrix* a, ae_state *_state); +void xdebugi2outsin(ae_int_t m, + ae_int_t n, + /* Integer */ ae_matrix* a, + ae_state *_state); +double xdebugr2sum(/* Real */ const ae_matrix* a, ae_state *_state); +double xdebugr2internalcopyandsum(/* Real */ const ae_matrix* _a, + ae_state *_state); +void xdebugr2neg(/* Real */ ae_matrix* a, ae_state *_state); +void xdebugr2transpose(/* Real */ ae_matrix* a, ae_state *_state); +void xdebugr2outsin(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_state *_state); +ae_complex xdebugc2sum(/* Complex */ const ae_matrix* a, ae_state *_state); +void xdebugc2neg(/* Complex */ ae_matrix* a, ae_state *_state); +void xdebugc2transpose(/* Complex */ ae_matrix* a, ae_state *_state); +void xdebugc2outsincos(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_state *_state); +double xdebugmaskedbiasedproductsum(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* b, + /* Boolean */ const ae_matrix* c, + ae_state *_state); +void _xdebugrecord1_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xdebugrecord1_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xdebugrecord1_clear(void* _p); +void _xdebugrecord1_destroy(void* _p); +#endif +#if defined(AE_COMPILE_HQRND) || !defined(AE_PARTIAL_BUILD) +void hqrndrandomize(hqrndstate* state, ae_state *_state); +void hqrndseed(ae_int_t s1, + ae_int_t s2, + hqrndstate* state, + ae_state *_state); +double hqrnduniformr(hqrndstate* state, ae_state *_state); +ae_int_t hqrnduniformi(hqrndstate* state, ae_int_t n, ae_state *_state); +double hqrndnormal(hqrndstate* state, ae_state *_state); +void hqrndnormalv(hqrndstate* state, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); +void hqrndnormalm(hqrndstate* state, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* x, + ae_state *_state); +void hqrndunit2(hqrndstate* state, double* x, double* y, ae_state *_state); +void hqrndnormal2(hqrndstate* state, + double* x1, + double* x2, + ae_state *_state); +double hqrndexponential(hqrndstate* state, + double lambdav, + ae_state *_state); +ae_int_t hqrndgetmax(ae_state *_state); +ae_int_t hqrndintegerbase(hqrndstate* state, ae_state *_state); +double hqrnddiscrete(hqrndstate* state, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +double hqrndcontinuous(hqrndstate* state, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +void _hqrndstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _hqrndstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _hqrndstate_clear(void* _p); +void _hqrndstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NEARESTNEIGHBOR) || !defined(AE_PARTIAL_BUILD) +void kdtreebuild(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t normtype, + kdtree* kdt, + ae_state *_state); +void kdtreebuildtagged(/* Real */ const ae_matrix* xy, + /* Integer */ const ae_vector* tags, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t normtype, + kdtree* kdt, + ae_state *_state); +void kdtreecreaterequestbuffer(const kdtree* kdt, + kdtreerequestbuffer* buf, + ae_state *_state); +ae_int_t kdtreequeryknn(kdtree* kdt, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreetsqueryknn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreequeryrnn(kdtree* kdt, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreequeryrnnu(kdtree* kdt, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreetsqueryrnn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreetsqueryrnnu(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + double r, + ae_bool selfmatch, + ae_state *_state); +ae_int_t kdtreequeryaknn(kdtree* kdt, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + double eps, + ae_state *_state); +ae_int_t kdtreetsqueryaknn(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* x, + ae_int_t k, + ae_bool selfmatch, + double eps, + ae_state *_state); +ae_int_t kdtreequerybox(kdtree* kdt, + /* Real */ const ae_vector* boxmin, + /* Real */ const ae_vector* boxmax, + ae_state *_state); +ae_int_t kdtreetsquerybox(const kdtree* kdt, + kdtreerequestbuffer* buf, + /* Real */ const ae_vector* boxmin, + /* Real */ const ae_vector* boxmax, + ae_state *_state); +void kdtreequeryresultsx(const kdtree* kdt, + /* Real */ ae_matrix* x, + ae_state *_state); +void kdtreequeryresultsxy(const kdtree* kdt, + /* Real */ ae_matrix* xy, + ae_state *_state); +void kdtreequeryresultstags(const kdtree* kdt, + /* Integer */ ae_vector* tags, + ae_state *_state); +void kdtreequeryresultsdistances(const kdtree* kdt, + /* Real */ ae_vector* r, + ae_state *_state); +void kdtreetsqueryresultsx(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_matrix* x, + ae_state *_state); +void kdtreetsqueryresultsxy(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_matrix* xy, + ae_state *_state); +void kdtreetsqueryresultstags(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Integer */ ae_vector* tags, + ae_state *_state); +void kdtreetsqueryresultsdistances(const kdtree* kdt, + const kdtreerequestbuffer* buf, + /* Real */ ae_vector* r, + ae_state *_state); +void kdtreequeryresultsxi(const kdtree* kdt, + /* Real */ ae_matrix* x, + ae_state *_state); +void kdtreequeryresultsxyi(const kdtree* kdt, + /* Real */ ae_matrix* xy, + ae_state *_state); +void kdtreequeryresultstagsi(const kdtree* kdt, + /* Integer */ ae_vector* tags, + ae_state *_state); +void kdtreequeryresultsdistancesi(const kdtree* kdt, + /* Real */ ae_vector* r, + ae_state *_state); +void kdtreeexplorebox(const kdtree* kdt, + /* Real */ ae_vector* boxmin, + /* Real */ ae_vector* boxmax, + ae_state *_state); +void kdtreeexplorenodetype(const kdtree* kdt, + ae_int_t node, + ae_int_t* nodetype, + ae_state *_state); +void kdtreeexploreleaf(const kdtree* kdt, + ae_int_t node, + /* Real */ ae_matrix* xy, + ae_int_t* k, + ae_state *_state); +void kdtreeexploresplit(const kdtree* kdt, + ae_int_t node, + ae_int_t* d, + double* s, + ae_int_t* nodele, + ae_int_t* nodege, + ae_state *_state); +void kdtreealloc(ae_serializer* s, const kdtree* tree, ae_state *_state); +void kdtreeserialize(ae_serializer* s, + const kdtree* tree, + ae_state *_state); +void kdtreeunserialize(ae_serializer* s, kdtree* tree, ae_state *_state); +double kdtreeapproxrnnquerycost(kdtree* kdt, double r, ae_state *_state); +double kdtreetsapproxrnnquerycost(const kdtree* kdt, + kdtreerequestbuffer* buf, + double r, + ae_state *_state); +void _kdtreerequestbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _kdtreerequestbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _kdtreerequestbuffer_clear(void* _p); +void _kdtreerequestbuffer_destroy(void* _p); +void _kdtree_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _kdtree_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _kdtree_clear(void* _p); +void _kdtree_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/ap.cpp b/core/alglib/ap.cpp index 54102f41..e6feeb88 100644 --- a/core/alglib/ap.cpp +++ b/core/alglib/ap.cpp @@ -1,10661 +1,20518 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "ap.h" -#include -#include -using namespace std; - -#if defined(AE_CPU) -#if (AE_CPU==AE_INTEL) - -#if AE_COMPILER==AE_MSVC -#include -#endif - -#endif -#endif - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION IMPLEMENTS BASIC FUNCTIONALITY LIKE -// MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS -// SHARED BETWEEN C++ AND PURE C LIBRARIES -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -/* - * local definitions - */ -#define x_nb 16 -#define AE_DATA_ALIGN 16 -#define AE_PTR_ALIGN sizeof(void*) -#define DYN_BOTTOM ((void*)1) -#define DYN_FRAME ((void*)2) -#define AE_LITTLE_ENDIAN 1 -#define AE_BIG_ENDIAN 2 -#define AE_MIXED_ENDIAN 3 -#define AE_SER_ENTRY_LENGTH 11 -#define AE_SER_ENTRIES_PER_ROW 5 - -#define AE_SM_DEFAULT 0 -#define AE_SM_ALLOC 1 -#define AE_SM_READY2S 2 -#define AE_SM_TO_STRING 10 -#define AE_SM_FROM_STRING 20 -#define AE_SM_TO_CPPSTRING 11 - -#define AE_LOCK_CYCLES 512 -#define AE_LOCK_TESTS_BEFORE_YIELD 16 -#define AE_CRITICAL_ASSERT(x) if( !(x) ) abort() - - -/* - * alloc counter (if used) - */ -#ifdef AE_USE_ALLOC_COUNTER -ae_int64_t _alloc_counter = 0; -#endif -#ifdef AE_DEBUGRNG -static ae_int_t _debug_rng_s0 = 11; -static ae_int_t _debug_rng_s1 = 13; -#endif -#ifdef AE_SMP_DEBUGCOUNTERS -__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_acquisitions = 0; -__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_spinwaits = 0; -__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_yields = 0; -#endif - -/* - * These declarations are used to ensure that - * sizeof(ae_int32_t)==4, sizeof(ae_int64_t)==8, sizeof(ae_int_t)==sizeof(void*). - * they will lead to syntax error otherwise (array size will be negative). - * - * you can remove them, if you want - they are not used anywhere. - * - */ -static char _ae_int32_t_must_be_32_bits_wide[1-2*((int)(sizeof(ae_int32_t))-4)*((int)(sizeof(ae_int32_t))-4)]; -static char _ae_int64_t_must_be_64_bits_wide[1-2*((int)(sizeof(ae_int64_t))-8)*((int)(sizeof(ae_int64_t))-8)]; -static char _ae_int_t_must_be_pointer_sized [1-2*((int)(sizeof(ae_int_t))-(int)sizeof(void*))*((int)(sizeof(ae_int_t))-(int)(sizeof(void*)))]; - -/* - * This variable is used to prevent some tricky optimizations which may degrade multithreaded performance. - * It is touched once in the ae_init_pool() function from smp.c in order to prevent optimizations. - * - */ -static volatile ae_int_t ae_never_change_it = 1; - -ae_int_t ae_misalignment(const void *ptr, size_t alignment) -{ - union _u - { - const void *ptr; - ae_int_t iptr; - } u; - u.ptr = ptr; - return (ae_int_t)(u.iptr%alignment); -} - -void* ae_align(void *ptr, size_t alignment) -{ - char *result = (char*)ptr; - if( (result-(char*)0)%alignment!=0 ) - result += alignment - (result-(char*)0)%alignment; - return result; -} - -void ae_break(ae_state *state, ae_error_type error_type, const char *msg) -{ -#ifndef AE_USE_CPP_ERROR_HANDLING - if( state!=NULL ) - { - if( state->thread_exception_handler!=NULL ) - state->thread_exception_handler(state); - ae_state_clear(state); - state->last_error = error_type; - state->error_msg = msg; - if( state->break_jump!=NULL ) - longjmp(*(state->break_jump), 1); - else - abort(); - } - else - abort(); -#else - if( state!=NULL ) - { - if( state->thread_exception_handler!=NULL ) - state->thread_exception_handler(state); - ae_state_clear(state); - state->last_error = error_type; - state->error_msg = msg; - } - throw error_type; -#endif -} - -void* aligned_malloc(size_t size, size_t alignment) -{ - if( size==0 ) - return NULL; - if( alignment<=1 ) - { - /* no alignment, just call malloc */ - void *block; - void **p; ; - block = malloc(sizeof(void*)+size); - if( block==NULL ) - return NULL; - p = (void**)block; - *p = block; -#ifdef AE_USE_ALLOC_COUNTER - _alloc_counter++; -#endif - return (void*)((char*)block+sizeof(void*)); - } - else - { - /* align */ - void *block; - char *result; - block = malloc(alignment-1+sizeof(void*)+size); - if( block==NULL ) - return NULL; - result = (char*)block+sizeof(void*); - /*if( (result-(char*)0)%alignment!=0 ) - result += alignment - (result-(char*)0)%alignment;*/ - result = (char*)ae_align(result, alignment); - *((void**)(result-sizeof(void*))) = block; -#ifdef AE_USE_ALLOC_COUNTER - _alloc_counter++; -#endif - return result; - } -} - -void aligned_free(void *block) -{ - void *p; - if( block==NULL ) - return; - p = *((void**)((char*)block-sizeof(void*))); - free(p); -#ifdef AE_USE_ALLOC_COUNTER - _alloc_counter--; -#endif -} - -/************************************************************************ -Malloc's memory with automatic alignment. - -Returns NULL when zero size is specified. - -Error handling: -* if state is NULL, returns NULL on allocation error -* if state is not NULL, calls ae_break() on allocation error -************************************************************************/ -void* ae_malloc(size_t size, ae_state *state) -{ - void *result; - if( size==0 ) - return NULL; - result = aligned_malloc(size,AE_DATA_ALIGN); - if( result==NULL && state!=NULL) - { - char buf[256]; - sprintf(buf, "ae_malloc(): out of memory (attempted to allocate %llu bytes)", (unsigned long long)size); - ae_break(state, ERR_OUT_OF_MEMORY, buf); - } - return result; -} - -void ae_free(void *p) -{ - if( p!=NULL ) - aligned_free(p); -} - -/************************************************************************ -Sets pointers to the matrix rows. - -* dst must be correctly initialized matrix -* dst->data.ptr points to the beginning of memory block allocated for - row pointers. -* dst->ptr - undefined (initialized during algorithm processing) -* storage parameter points to the beginning of actual storage -************************************************************************/ -void ae_matrix_update_row_pointers(ae_matrix *dst, void *storage) -{ - char *p_base; - void **pp_ptr; - ae_int_t i; - if( dst->rows>0 && dst->cols>0 ) - { - p_base = (char*)storage; - pp_ptr = (void**)dst->data.ptr; - dst->ptr.pp_void = pp_ptr; - for(i=0; irows; i++, p_base+=dst->stride*ae_sizeof(dst->datatype)) - pp_ptr[i] = p_base; - } - else - dst->ptr.pp_void = NULL; -} - -/************************************************************************ -Returns size of datatype. -Zero for dynamic types like strings or multiple precision types. -************************************************************************/ -ae_int_t ae_sizeof(ae_datatype datatype) -{ - switch(datatype) - { - case DT_BOOL: return (ae_int_t)sizeof(ae_bool); - case DT_INT: return (ae_int_t)sizeof(ae_int_t); - case DT_REAL: return (ae_int_t)sizeof(double); - case DT_COMPLEX: return 2*(ae_int_t)sizeof(double); - default: return 0; - } -} - - -/************************************************************************ -This dummy function is used to prevent compiler messages about unused -locals in automatically generated code. - -It makes nothing - just accepts pointer, "touches" it - and that is all. -It performs several tricky operations without side effects which confuse -compiler so it does not compain about unused locals in THIS function. -************************************************************************/ -void ae_touch_ptr(void *p) -{ - void * volatile fake_variable0 = p; - void * volatile fake_variable1 = fake_variable0; - fake_variable0 = fake_variable1; -} - -/************************************************************************ -This function initializes ALGLIB environment state. - -NOTES: -* stacks contain no frames, so ae_make_frame() must be called before - attaching dynamic blocks. Without it ae_leave_frame() will cycle - forever (which is intended behavior). -************************************************************************/ -void ae_state_init(ae_state *state) -{ - ae_int32_t *vp; - - /* - * p_next points to itself because: - * * correct program should be able to detect end of the list - * by looking at the ptr field. - * * NULL p_next may be used to distinguish automatic blocks - * (in the list) from non-automatic (not in the list) - */ - state->last_block.p_next = &(state->last_block); - state->last_block.deallocator = NULL; - state->last_block.ptr = DYN_BOTTOM; - state->p_top_block = &(state->last_block); -#ifndef AE_USE_CPP_ERROR_HANDLING - state->break_jump = NULL; -#endif - state->error_msg = ""; - - /* - * determine endianness and initialize precomputed IEEE special quantities. - */ - state->endianness = ae_get_endianness(); - if( state->endianness==AE_LITTLE_ENDIAN ) - { - vp = (ae_int32_t*)(&state->v_nan); - vp[0] = 0; - vp[1] = (ae_int32_t)0x7FF80000; - vp = (ae_int32_t*)(&state->v_posinf); - vp[0] = 0; - vp[1] = (ae_int32_t)0x7FF00000; - vp = (ae_int32_t*)(&state->v_neginf); - vp[0] = 0; - vp[1] = (ae_int32_t)0xFFF00000; - } - else if( state->endianness==AE_BIG_ENDIAN ) - { - vp = (ae_int32_t*)(&state->v_nan); - vp[1] = 0; - vp[0] = (ae_int32_t)0x7FF80000; - vp = (ae_int32_t*)(&state->v_posinf); - vp[1] = 0; - vp[0] = (ae_int32_t)0x7FF00000; - vp = (ae_int32_t*)(&state->v_neginf); - vp[1] = 0; - vp[0] = (ae_int32_t)0xFFF00000; - } - else - abort(); - - /* - * set threading information - */ - state->worker_thread = NULL; - state->parent_task = NULL; - state->thread_exception_handler = NULL; -} - - -/************************************************************************ -This function clears ALGLIB environment state. -All dynamic data controlled by state are freed. -************************************************************************/ -void ae_state_clear(ae_state *state) -{ - while( state->p_top_block->ptr!=DYN_BOTTOM ) - ae_frame_leave(state); -} - - -#ifndef AE_USE_CPP_ERROR_HANDLING -/************************************************************************ -This function sets jump buffer for error handling. - -buf may be NULL. -************************************************************************/ -void ae_state_set_break_jump(ae_state *state, jmp_buf *buf) -{ - state->break_jump = buf; -} -#endif - - -/************************************************************************ -This function makes new stack frame. - -This function takes two parameters: environment state and pointer to the -dynamic block which will be used as indicator of the frame beginning. -This dynamic block must be initialized by caller and mustn't be changed/ -deallocated/reused till ae_leave_frame called. It may be global or local -variable (local is even better). -************************************************************************/ -void ae_frame_make(ae_state *state, ae_frame *tmp) -{ - tmp->db_marker.p_next = state->p_top_block; - tmp->db_marker.deallocator = NULL; - tmp->db_marker.ptr = DYN_FRAME; - state->p_top_block = &tmp->db_marker; -} - - -/************************************************************************ -This function leaves current stack frame and deallocates all automatic -dynamic blocks which were attached to this frame. -************************************************************************/ -void ae_frame_leave(ae_state *state) -{ - while( state->p_top_block->ptr!=DYN_FRAME && state->p_top_block->ptr!=DYN_BOTTOM) - { - if( state->p_top_block->ptr!=NULL && state->p_top_block->deallocator!=NULL) - ((ae_deallocator)(state->p_top_block->deallocator))(state->p_top_block->ptr); - state->p_top_block = state->p_top_block->p_next; - } - state->p_top_block = state->p_top_block->p_next; -} - - -/************************************************************************ -This function attaches block to the dynamic block list - -block block -state ALGLIB environment state - -NOTES: -* never call it for special blocks which marks frame boundaries! -************************************************************************/ -void ae_db_attach(ae_dyn_block *block, ae_state *state) -{ - block->p_next = state->p_top_block; - state->p_top_block = block; -} - - -/************************************************************************ -This function malloc's dynamic block: - -block destination block, assumed to be uninitialized -size size (in bytes) -state ALGLIB environment state. May be NULL. -make_automatic if true, vector is added to the dynamic block list - -block is assumed to be uninitialized, its fields are ignored. - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -NOTES: -* never call it for blocks which are already in the list -************************************************************************/ -ae_bool ae_db_malloc(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(size>=0, "ae_db_malloc(): negative size", state); - if( size<0 ) - return ae_false; - - /* alloc */ - block->ptr = ae_malloc((size_t)size, state); - if( block->ptr==NULL && size!=0 ) - return ae_false; - if( make_automatic && state!=NULL ) - ae_db_attach(block, state); - else - block->p_next = NULL; - block->deallocator = ae_free; - return ae_true; -} - - -/************************************************************************ -This function realloc's dynamic block: - -block destination block (initialized) -size new size (in bytes) -state ALGLIB environment state - -block is assumed to be initialized. - -This function: -* deletes old contents -* preserves automatic state - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -NOTES: -* never call it for special blocks which mark frame boundaries! -************************************************************************/ -ae_bool ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(size>=0, "ae_db_realloc(): negative size", state); - if( size<0 ) - return ae_false; - - /* realloc */ - if( block->ptr!=NULL ) - ((ae_deallocator)block->deallocator)(block->ptr); - block->ptr = ae_malloc((size_t)size, state); - if( block->ptr==NULL && size!=0 ) - return ae_false; - block->deallocator = ae_free; - return ae_true; -} - - -/************************************************************************ -This function clears dynamic block (releases all dynamically allocated -memory). Dynamic block may be in automatic management list - in this case -it will NOT be removed from list. - -block destination block (initialized) - -NOTES: -* never call it for special blocks which marks frame boundaries! -************************************************************************/ -void ae_db_free(ae_dyn_block *block) -{ - if( block->ptr!=NULL ) - ((ae_deallocator)block->deallocator)(block->ptr); - block->ptr = NULL; - block->deallocator = ae_free; -} - -/************************************************************************ -This function swaps contents of two dynamic blocks (pointers and -deallocators) leaving other parameters (automatic management settings, -etc.) unchanged. - -NOTES: -* never call it for special blocks which marks frame boundaries! -************************************************************************/ -void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2) -{ - void (*deallocator)(void*) = NULL; - void * volatile ptr; - ptr = block1->ptr; - deallocator = block1->deallocator; - block1->ptr = block2->ptr; - block1->deallocator = block2->deallocator; - block2->ptr = ptr; - block2->deallocator = deallocator; -} - -/************************************************************************ -This function creates ae_vector. - -Vector size may be zero. Vector contents is uninitialized. - -dst destination vector -size vector size, may be zero -datatype guess what... -state ALGLIB environment state -make_automatic if true, vector is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -ae_bool ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state, ae_bool make_automatic) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(size>=0, "ae_vector_init(): negative size", state); - if( size<0 ) - return ae_false; - - /* init */ - dst->cnt = size; - dst->datatype = datatype; - if( !ae_db_malloc(&dst->data, size*ae_sizeof(datatype), state, make_automatic) ) - return ae_false; - dst->ptr.p_ptr = dst->data.ptr; - return ae_true; -} - - -/************************************************************************ -This function creates copy of ae_vector. - -dst destination vector -src well, it is source -state ALGLIB environment state -make_automatic if true, vector is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -ae_bool ae_vector_init_copy(ae_vector *dst, ae_vector *src, ae_state *state, ae_bool make_automatic) -{ - if( !ae_vector_init(dst, src->cnt, src->datatype, state, make_automatic) ) - return ae_false; - if( src->cnt!=0 ) - memcpy(dst->ptr.p_ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); - return ae_true; -} - -/************************************************************************ -This function creates ae_vector from x_vector: - -dst destination vector -src source, vector in x-format -state ALGLIB environment state -make_automatic if true, vector is added to the dynamic block list - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic) -{ - ae_vector_init(dst, (ae_int_t)src->cnt, (ae_datatype)src->datatype, state, make_automatic); - if( src->cnt>0 ) - memcpy(dst->ptr.p_ptr, src->ptr, (size_t)(((ae_int_t)src->cnt)*ae_sizeof((ae_datatype)src->datatype))); -} - - -/************************************************************************ -This function changes length of ae_vector. - -dst destination vector -newsize vector size, may be zero -state ALGLIB environment state - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -NOTES: -* vector must be initialized -* all contents is destroyed during setlength() call -* new size may be zero. -************************************************************************/ -ae_bool ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(newsize>=0, "ae_vector_set_length(): negative size", state); - if( newsize<0 ) - return ae_false; - - /* set length */ - if( dst->cnt==newsize ) - return ae_true; - dst->cnt = newsize; - if( !ae_db_realloc(&dst->data, newsize*ae_sizeof(dst->datatype), state) ) - return ae_false; - dst->ptr.p_ptr = dst->data.ptr; - return ae_true; -} - - -/************************************************************************ -This function provides "CLEAR" functionality for vector (contents is -cleared, but structure still left in valid state). - -The function clears vector contents (releases all dynamically allocated -memory). Vector may be in automatic management list - in this case it -will NOT be removed from list. - -IMPORTANT: this function does NOT invalidates dst; it just releases all -dynamically allocated storage, but dst still may be used after call to -ae_vector_set_length(). - -dst destination vector -************************************************************************/ -void ae_vector_clear(ae_vector *dst) -{ - dst->cnt = 0; - ae_db_free(&dst->data); - dst->ptr.p_ptr = 0; -} - - -/************************************************************************ -This function provides "DESTROY" functionality for vector (contents is -cleared, all internal structures are destroyed). For vectors it is same -as CLEAR. - -dst destination vector -************************************************************************/ -void ae_vector_destroy(ae_vector *dst) -{ - ae_vector_clear(dst); -} - - -/************************************************************************ -This function efficiently swaps contents of two vectors, leaving other -pararemeters (automatic management, etc.) unchanged. -************************************************************************/ -void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2) -{ - ae_int_t cnt; - ae_datatype datatype; - void *p_ptr; - - ae_db_swap(&vec1->data, &vec2->data); - - cnt = vec1->cnt; - datatype = vec1->datatype; - p_ptr = vec1->ptr.p_ptr; - vec1->cnt = vec2->cnt; - vec1->datatype = vec2->datatype; - vec1->ptr.p_ptr = vec2->ptr.p_ptr; - vec2->cnt = cnt; - vec2->datatype = datatype; - vec2->ptr.p_ptr = p_ptr; -} - -/************************************************************************ -This function creates ae_matrix. - -Matrix size may be zero, in such cases both rows and cols are zero. -Matrix contents is uninitialized. - -dst destination natrix -rows rows count -cols cols count -datatype element type -state ALGLIB environment state -make_automatic if true, matrix is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -ae_bool ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state, ae_bool make_automatic) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(rows>=0 && cols>=0, "ae_matrix_init(): negative length", state); - if( rows<0 || cols<0 ) - return ae_false; - - /* if one of rows/cols is zero, another MUST be too */ - if( rows==0 || cols==0 ) - { - rows = 0; - cols = 0; - } - - /* init */ - dst->rows = rows; - dst->cols = cols; - dst->stride = cols; - while( dst->stride*ae_sizeof(datatype)%AE_DATA_ALIGN!=0 ) - dst->stride++; - dst->datatype = datatype; - if( !ae_db_malloc(&dst->data, dst->rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(datatype))+AE_DATA_ALIGN-1, state, make_automatic) ) - return ae_false; - ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+dst->rows*sizeof(void*),AE_DATA_ALIGN)); - return ae_true; -} - - -/************************************************************************ -This function creates copy of ae_matrix. - -dst destination matrix -src well, it is source -state ALGLIB environment state -make_automatic if true, matrix is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -ae_bool ae_matrix_init_copy(ae_matrix *dst, ae_matrix *src, ae_state *state, ae_bool make_automatic) -{ - ae_int_t i; - if( !ae_matrix_init(dst, src->rows, src->cols, src->datatype, state, make_automatic) ) - return ae_false; - if( src->rows!=0 && src->cols!=0 ) - { - if( dst->stride==src->stride ) - memcpy(dst->ptr.pp_void[0], src->ptr.pp_void[0], (size_t)(src->rows*src->stride*ae_sizeof(src->datatype))); - else - for(i=0; irows; i++) - memcpy(dst->ptr.pp_void[i], src->ptr.pp_void[i], (size_t)(dst->cols*ae_sizeof(dst->datatype))); - } - return ae_true; -} - - -void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic) -{ - char *p_src_row; - char *p_dst_row; - ae_int_t row_size; - ae_int_t i; - ae_matrix_init(dst, (ae_int_t)src->rows, (ae_int_t)src->cols, (ae_datatype)src->datatype, state, make_automatic); - if( src->rows!=0 && src->cols!=0 ) - { - p_src_row = (char*)src->ptr; - p_dst_row = (char*)(dst->ptr.pp_void[0]); - row_size = ae_sizeof((ae_datatype)src->datatype)*(ae_int_t)src->cols; - for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof((ae_datatype)src->datatype), p_dst_row+=dst->stride*ae_sizeof((ae_datatype)src->datatype)) - memcpy(p_dst_row, p_src_row, (size_t)(row_size)); - } -} - - -/************************************************************************ -This function changes length of ae_matrix. - -dst destination matrix -rows size, may be zero -cols size, may be zero -state ALGLIB environment state - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -NOTES: -* matrix must be initialized -* all contents is destroyed during setlength() call -* new size may be zero. -************************************************************************/ -ae_bool ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state) -{ - /* ensure that size is >=0 - two ways to exit: 1) through ae_assert, if we have non-NULL state, 2) by returning ae_false */ - if( state!=NULL ) - ae_assert(rows>=0 && cols>=0, "ae_matrix_set_length(): negative length", state); - if( rows<0 || cols<0 ) - return ae_false; - - if( dst->rows==rows && dst->cols==cols ) - return ae_true; - dst->rows = rows; - dst->cols = cols; - dst->stride = cols; - while( dst->stride*ae_sizeof(dst->datatype)%AE_DATA_ALIGN!=0 ) - dst->stride++; - if( !ae_db_realloc(&dst->data, dst->rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(dst->datatype))+AE_DATA_ALIGN-1, state) ) - return ae_false; - ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+dst->rows*sizeof(void*),AE_DATA_ALIGN)); - return ae_true; -} - - -/************************************************************************ -This function provides "CLEAR" functionality for vector (contents is -cleared, but structure still left in valid state). - -The function clears matrix contents (releases all dynamically allocated -memory). Matrix may be in automatic management list - in this case it -will NOT be removed from list. - -IMPORTANT: this function does NOT invalidates dst; it just releases all -dynamically allocated storage, but dst still may be used after call to -ae_matrix_set_length(). - -dst destination matrix -************************************************************************/ -void ae_matrix_clear(ae_matrix *dst) -{ - dst->rows = 0; - dst->cols = 0; - dst->stride = 0; - ae_db_free(&dst->data); - dst->ptr.p_ptr = 0; -} - - -/************************************************************************ -This function provides "DESTROY" functionality for matrix (contents is -cleared, but structure still left in valid state). - -For matrices it is same as CLEAR. - -dst destination matrix -************************************************************************/ -void ae_matrix_destroy(ae_matrix *dst) -{ - ae_matrix_clear(dst); -} - - -/************************************************************************ -This function efficiently swaps contents of two vectors, leaving other -pararemeters (automatic management, etc.) unchanged. -************************************************************************/ -void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2) -{ - ae_int_t rows; - ae_int_t cols; - ae_int_t stride; - ae_datatype datatype; - void *p_ptr; - - ae_db_swap(&mat1->data, &mat2->data); - - rows = mat1->rows; - cols = mat1->cols; - stride = mat1->stride; - datatype = mat1->datatype; - p_ptr = mat1->ptr.p_ptr; - - mat1->rows = mat2->rows; - mat1->cols = mat2->cols; - mat1->stride = mat2->stride; - mat1->datatype = mat2->datatype; - mat1->ptr.p_ptr = mat2->ptr.p_ptr; - - mat2->rows = rows; - mat2->cols = cols; - mat2->stride = stride; - mat2->datatype = datatype; - mat2->ptr.p_ptr = p_ptr; -} - - -/************************************************************************ -This function creates smart pointer structure. - -dst destination smart pointer. - already allocated, but not initialized. -subscriber pointer to pointer which receives updates in the - internal object stored in ae_smart_ptr. Any update to - dst->ptr is translated to subscriber. Can be NULL. -state ALGLIB environment state -make_automatic if true, smart pointer is added to the dynamic block list - -After initialization, smart pointer stores NULL pointer. - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success -************************************************************************/ -ae_bool ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_state *state, ae_bool make_automatic) -{ - dst->subscriber = subscriber; - dst->ptr = NULL; - if( dst->subscriber!=NULL ) - *(dst->subscriber) = dst->ptr; - dst->is_owner = ae_false; - dst->is_dynamic = ae_false; - dst->frame_entry.deallocator = ae_smart_ptr_destroy; - dst->frame_entry.ptr = dst; - if( make_automatic && state!=NULL ) - ae_db_attach(&dst->frame_entry, state); - return ae_true; -} - - -/************************************************************************ -This function clears smart pointer structure. - -dst destination smart pointer. - -After call to this function smart pointer contains NULL reference, which -is propagated to its subscriber (in cases non-NULL subscruber was -specified during pointer creation). -************************************************************************/ -void ae_smart_ptr_clear(void *_dst) -{ - ae_smart_ptr *dst = (ae_smart_ptr*)_dst; - if( dst->is_owner && dst->ptr!=NULL ) - { - dst->destroy(dst->ptr); - if( dst->is_dynamic ) - ae_free(dst->ptr); - } - dst->is_owner = ae_false; - dst->is_dynamic = ae_false; - dst->ptr = NULL; - dst->destroy = NULL; - if( dst->subscriber!=NULL ) - *(dst->subscriber) = NULL; -} - - -/************************************************************************ -This function dstroys smart pointer structure (same as clearing it). - -dst destination smart pointer. -************************************************************************/ -void ae_smart_ptr_destroy(void *_dst) -{ - ae_smart_ptr_clear(_dst); -} - - -/************************************************************************ -This function assigns pointer to ae_smart_ptr structure. - -dst destination smart pointer. -new_ptr new pointer to assign -is_owner whether smart pointer owns new_ptr -is_dynamic whether object is dynamic - clearing such object - requires BOTH calling destructor function AND calling - ae_free() for memory occupied by object. -destroy destructor function - -In case smart pointer already contains non-NULL value and owns this value, -it is freed before assigning new pointer. - -Changes in pointer are propagated to its subscriber (in case non-NULL -subscriber was specified during pointer creation). - -You can specify NULL new_ptr, in which case is_owner/destroy are ignored. -************************************************************************/ -void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, void (*destroy)(void*)) -{ - if( dst->is_owner && dst->ptr!=NULL ) - dst->destroy(dst->ptr); - if( new_ptr!=NULL ) - { - dst->ptr = new_ptr; - dst->is_owner = is_owner; - dst->is_dynamic = is_dynamic; - dst->destroy = destroy; - } - else - { - dst->ptr = NULL; - dst->is_owner = ae_false; - dst->is_dynamic = ae_false; - dst->destroy = NULL; - } - if( dst->subscriber!=NULL ) - *(dst->subscriber) = dst->ptr; -} - - -/************************************************************************ -This function releases pointer owned by ae_smart_ptr structure: -* all internal fields are set to NULL -* destructor function for internal pointer is NOT called even when we own - this pointer. After this call ae_smart_ptr releases ownership of its - pointer and passes it to caller. -* changes in pointer are propagated to its subscriber (in case non-NULL - subscriber was specified during pointer creation). - -dst destination smart pointer. -************************************************************************/ -void ae_smart_ptr_release(ae_smart_ptr *dst) -{ - dst->is_owner = ae_false; - dst->is_dynamic = ae_false; - dst->ptr = NULL; - dst->destroy = NULL; - if( dst->subscriber!=NULL ) - *(dst->subscriber) = NULL; -} - -/************************************************************************ -This function fills x_vector by ae_vector's contents: - -dst destination vector -src source, vector in x-format -state ALGLIB environment state - -NOTES: -* dst is assumed to be initialized. Its contents is freed before copying - data from src (if size / type are different) or overwritten (if - possible given destination size). -************************************************************************/ -void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state) -{ - if( dst->cnt!=src->cnt || dst->datatype!=src->datatype ) - { - if( dst->owner==OWN_AE ) - ae_free(dst->ptr); - dst->ptr = ae_malloc((size_t)(src->cnt*ae_sizeof(src->datatype)), state); - dst->last_action = ACT_NEW_LOCATION; - dst->cnt = src->cnt; - dst->datatype = src->datatype; - dst->owner = OWN_AE; - } - else - dst->last_action = ACT_SAME_LOCATION; - if( src->cnt ) - memcpy(dst->ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); -} - -/************************************************************************ -This function fills x_matrix by ae_matrix's contents: - -dst destination vector -src source, matrix in x-format -state ALGLIB environment state - -NOTES: -* dst is assumed to be initialized. Its contents is freed before copying - data from src (if size / type are different) or overwritten (if - possible given destination size). -************************************************************************/ -void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state) -{ - char *p_src_row; - char *p_dst_row; - ae_int_t i; - ae_int_t row_size; - if( dst->rows!=src->rows || dst->cols!=src->cols || dst->datatype!=src->datatype ) - { - if( dst->owner==OWN_AE ) - ae_free(dst->ptr); - dst->rows = src->rows; - dst->cols = src->cols; - dst->stride = src->cols; - dst->datatype = src->datatype; - dst->ptr = ae_malloc((size_t)(dst->rows*((ae_int_t)dst->stride)*ae_sizeof(src->datatype)), state); - dst->last_action = ACT_NEW_LOCATION; - dst->owner = OWN_AE; - } - else - dst->last_action = ACT_SAME_LOCATION; - if( src->rows!=0 && src->cols!=0 ) - { - p_src_row = (char*)(src->ptr.pp_void[0]); - p_dst_row = (char*)dst->ptr; - row_size = ae_sizeof(src->datatype)*src->cols; - for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof(src->datatype), p_dst_row+=dst->stride*ae_sizeof(src->datatype)) - memcpy(p_dst_row, p_src_row, (size_t)(row_size)); - } -} - -/************************************************************************ -This function attaches x_vector to ae_vector's contents. -Ownership of memory allocated is not changed (it is still managed by -ae_matrix). - -dst destination vector -src source, vector in x-format -state ALGLIB environment state - -NOTES: -* dst is assumed to be initialized. Its contents is freed before - attaching to src. -* this function doesn't need ae_state parameter because it can't fail - (assuming correctly initialized src) -************************************************************************/ -void ae_x_attach_to_vector(x_vector *dst, ae_vector *src) -{ - if( dst->owner==OWN_AE ) - ae_free(dst->ptr); - dst->ptr = src->ptr.p_ptr; - dst->last_action = ACT_NEW_LOCATION; - dst->cnt = src->cnt; - dst->datatype = src->datatype; - dst->owner = OWN_CALLER; -} - -/************************************************************************ -This function attaches x_matrix to ae_matrix's contents. -Ownership of memory allocated is not changed (it is still managed by -ae_matrix). - -dst destination vector -src source, matrix in x-format -state ALGLIB environment state - -NOTES: -* dst is assumed to be initialized. Its contents is freed before - attaching to src. -* this function doesn't need ae_state parameter because it can't fail - (assuming correctly initialized src) -************************************************************************/ -void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src) -{ - if( dst->owner==OWN_AE ) - ae_free(dst->ptr); - dst->rows = src->rows; - dst->cols = src->cols; - dst->stride = src->stride; - dst->datatype = src->datatype; - dst->ptr = &(src->ptr.pp_double[0][0]); - dst->last_action = ACT_NEW_LOCATION; - dst->owner = OWN_CALLER; -} - -/************************************************************************ -This function clears x_vector. It does nothing if vector is not owned by -ALGLIB environment. - -dst vector -************************************************************************/ -void x_vector_clear(x_vector *dst) -{ - if( dst->owner==OWN_AE ) - aligned_free(dst->ptr); - dst->ptr = NULL; - dst->cnt = 0; -} - -/************************************************************************ -Assertion -************************************************************************/ -void ae_assert(ae_bool cond, const char *msg, ae_state *state) -{ - if( !cond ) - ae_break(state, ERR_ASSERTION_FAILED, msg); -} - -/************************************************************************ -CPUID - -Returns information about features CPU and compiler support. - -You must tell ALGLIB what CPU family is used by defining AE_CPU symbol -(without this hint zero will be returned). - -Note: results of this function depend on both CPU and compiler; -if compiler doesn't support SSE intrinsics, function won't set -corresponding flag. -************************************************************************/ -static volatile ae_bool _ae_cpuid_initialized = ae_false; -static volatile ae_bool _ae_cpuid_has_sse2 = ae_false; -ae_int_t ae_cpuid() -{ - /* - * to speed up CPU detection we cache results from previous attempts - * there is no synchronization, but it is still thread safe. - * - * thread safety is guaranteed on all modern architectures which - * have following property: simultaneous writes by different cores - * to the same location will be executed in serial manner. - * - */ - ae_int_t result; - - /* - * if not initialized, determine system properties - */ - if( !_ae_cpuid_initialized ) - { - /* - * SSE2 - */ -#if defined(AE_CPU) -#if (AE_CPU==AE_INTEL) && defined(AE_HAS_SSE2_INTRINSICS) -#if AE_COMPILER==AE_MSVC - { - int CPUInfo[4]; - __cpuid(CPUInfo, 1); - if( (CPUInfo[3]&0x04000000)!=0 ) - _ae_cpuid_has_sse2 = ae_true; - } -#elif AE_COMPILER==AE_GNUC - { - ae_int_t a,b,c,d; - __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); - if( (d&0x04000000)!=0 ) - _ae_cpuid_has_sse2 = ae_true; - } -#elif AE_COMPILER==AE_SUNC - { - ae_int_t a,b,c,d; - __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); - if( (d&0x04000000)!=0 ) - _ae_cpuid_has_sse2 = ae_true; - } -#else -#endif -#endif -#endif - /* - * set initialization flag - */ - _ae_cpuid_initialized = ae_true; - } - - /* - * return - */ - result = 0; - if( _ae_cpuid_has_sse2 ) - result = result|CPU_SSE2; - return result; -} - -/************************************************************************ -Real math functions -************************************************************************/ -ae_bool ae_fp_eq(double v1, double v2) -{ - /* IEEE-strict floating point comparison */ - volatile double x = v1; - volatile double y = v2; - return x==y; -} - -ae_bool ae_fp_neq(double v1, double v2) -{ - /* IEEE-strict floating point comparison */ - return !ae_fp_eq(v1,v2); -} - -ae_bool ae_fp_less(double v1, double v2) -{ - /* IEEE-strict floating point comparison */ - volatile double x = v1; - volatile double y = v2; - return xy; -} - -ae_bool ae_fp_greater_eq(double v1, double v2) -{ - /* IEEE-strict floating point comparison */ - volatile double x = v1; - volatile double y = v2; - return x>=y; -} - -ae_bool ae_isfinite_stateless(double x, ae_int_t endianness) -{ - union _u - { - double a; - ae_int32_t p[2]; - } u; - ae_int32_t high; - u.a = x; - if( endianness==AE_LITTLE_ENDIAN ) - high = u.p[1]; - else - high = u.p[0]; - return (high & (ae_int32_t)0x7FF00000)!=(ae_int32_t)0x7FF00000; -} - -ae_bool ae_isnan_stateless(double x, ae_int_t endianness) -{ - union _u - { - double a; - ae_int32_t p[2]; - } u; - ae_int32_t high, low; - u.a = x; - if( endianness==AE_LITTLE_ENDIAN ) - { - high = u.p[1]; - low = u.p[0]; - } - else - { - high = u.p[0]; - low = u.p[1]; - } - return ((high &0x7FF00000)==0x7FF00000) && (((high &0x000FFFFF)!=0) || (low!=0)); -} - -ae_bool ae_isinf_stateless(double x, ae_int_t endianness) -{ - union _u - { - double a; - ae_int32_t p[2]; - } u; - ae_int32_t high, low; - u.a = x; - if( endianness==AE_LITTLE_ENDIAN ) - { - high = u.p[1]; - low = u.p[0]; - } - else - { - high = u.p[0]; - low = u.p[1]; - } - - /* 31 least significant bits of high are compared */ - return ((high&0x7FFFFFFF)==0x7FF00000) && (low==0); -} - -ae_bool ae_isposinf_stateless(double x, ae_int_t endianness) -{ - union _u - { - double a; - ae_int32_t p[2]; - } u; - ae_int32_t high, low; - u.a = x; - if( endianness==AE_LITTLE_ENDIAN ) - { - high = u.p[1]; - low = u.p[0]; - } - else - { - high = u.p[0]; - low = u.p[1]; - } - - /* all 32 bits of high are compared */ - return (high==(ae_int32_t)0x7FF00000) && (low==0); -} - -ae_bool ae_isneginf_stateless(double x, ae_int_t endianness) -{ - union _u - { - double a; - ae_int32_t p[2]; - } u; - ae_int32_t high, low; - u.a = x; - if( endianness==AE_LITTLE_ENDIAN ) - { - high = u.p[1]; - low = u.p[0]; - } - else - { - high = u.p[0]; - low = u.p[1]; - } - - /* this code is a bit tricky to avoid comparison of high with 0xFFF00000, which may be unsafe with some buggy compilers */ - return ((high&0x7FFFFFFF)==0x7FF00000) && (high!=(ae_int32_t)0x7FF00000) && (low==0); -} - -ae_int_t ae_get_endianness() -{ - union - { - double a; - ae_int32_t p[2]; - } u; - - /* - * determine endianness - * two types are supported: big-endian and little-endian. - * mixed-endian hardware is NOT supported. - * - * 1983 is used as magic number because its non-periodic double - * representation allow us to easily distinguish between upper - * and lower halfs and to detect mixed endian hardware. - * - */ - u.a = 1.0/1983.0; - if( u.p[1]==(ae_int32_t)0x3f408642 ) - return AE_LITTLE_ENDIAN; - if( u.p[0]==(ae_int32_t)0x3f408642 ) - return AE_BIG_ENDIAN; - return AE_MIXED_ENDIAN; -} - -ae_bool ae_isfinite(double x,ae_state *state) -{ - return ae_isfinite_stateless(x, state->endianness); -} - -ae_bool ae_isnan(double x, ae_state *state) -{ - return ae_isnan_stateless(x, state->endianness); -} - -ae_bool ae_isinf(double x, ae_state *state) -{ - return ae_isinf_stateless(x, state->endianness); -} - -ae_bool ae_isposinf(double x,ae_state *state) -{ - return ae_isposinf_stateless(x, state->endianness); -} - -ae_bool ae_isneginf(double x,ae_state *state) -{ - return ae_isneginf_stateless(x, state->endianness); -} - -double ae_fabs(double x, ae_state *state) -{ - return fabs(x); -} - -ae_int_t ae_iabs(ae_int_t x, ae_state *state) -{ - return x>=0 ? x : -x; -} - -double ae_sqr(double x, ae_state *state) -{ - return x*x; -} - -double ae_sqrt(double x, ae_state *state) -{ - return sqrt(x); -} - -ae_int_t ae_sign(double x, ae_state *state) -{ - if( x>0 ) return 1; - if( x<0 ) return -1; - return 0; -} - -ae_int_t ae_round(double x, ae_state *state) -{ - return (ae_int_t)(ae_ifloor(x+0.5,state)); -} - -ae_int_t ae_trunc(double x, ae_state *state) -{ - return (ae_int_t)(x>0 ? ae_ifloor(x,state) : ae_iceil(x,state)); -} - -ae_int_t ae_ifloor(double x, ae_state *state) -{ - return (ae_int_t)(floor(x)); -} - -ae_int_t ae_iceil(double x, ae_state *state) -{ - return (ae_int_t)(ceil(x)); -} - -ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state) -{ - return m1>m2 ? m1 : m2; -} - -ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state) -{ - return m1>m2 ? m2 : m1; -} - -double ae_maxreal(double m1, double m2, ae_state *state) -{ - return m1>m2 ? m1 : m2; -} - -double ae_minreal(double m1, double m2, ae_state *state) -{ - return m1>m2 ? m2 : m1; -} - -#ifdef AE_DEBUGRNG -ae_int_t ae_debugrng() -{ - ae_int_t k; - ae_int_t result; - k = _debug_rng_s0/53668; - _debug_rng_s0 = 40014*(_debug_rng_s0-k*53668)-k*12211; - if( _debug_rng_s0<0 ) - _debug_rng_s0 = _debug_rng_s0+2147483563; - k = _debug_rng_s1/52774; - _debug_rng_s1 = 40692*(_debug_rng_s1-k*52774)-k*3791; - if( _debug_rng_s1<0 ) - _debug_rng_s1 = _debug_rng_s1+2147483399; - result = _debug_rng_s0-_debug_rng_s1; - if( result<1 ) - result = result+2147483562; - return result; -} -#endif - -double ae_randomreal(ae_state *state) -{ -#ifdef AE_DEBUGRNG - return ae_debugrng()/2147483563.0; -#else - int i1 = rand(); - int i2 = rand(); - double mx = (double)(RAND_MAX)+1.0; - volatile double tmp0 = i2/mx; - volatile double tmp1 = i1+tmp0; - return tmp1/mx; -#endif -} - -ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state) -{ -#ifdef AE_DEBUGRNG - return (ae_debugrng()-1)%maxv; -#else - return rand()%maxv; -#endif -} - -double ae_sin(double x, ae_state *state) -{ - return sin(x); -} - -double ae_cos(double x, ae_state *state) -{ - return cos(x); -} - -double ae_tan(double x, ae_state *state) -{ - return tan(x); -} - -double ae_sinh(double x, ae_state *state) -{ - return sinh(x); -} - -double ae_cosh(double x, ae_state *state) -{ - return cosh(x); -} -double ae_tanh(double x, ae_state *state) -{ - return tanh(x); -} - -double ae_asin(double x, ae_state *state) -{ - return asin(x); -} - -double ae_acos(double x, ae_state *state) -{ - return acos(x); -} - -double ae_atan(double x, ae_state *state) -{ - return atan(x); -} - -double ae_atan2(double y, double x, ae_state *state) -{ - return atan2(y,x); -} - -double ae_log(double x, ae_state *state) -{ - return log(x); -} - -double ae_pow(double x, double y, ae_state *state) -{ - return pow(x,y); -} - -double ae_exp(double x, ae_state *state) -{ - return exp(x); -} - -/************************************************************************ -Symmetric/Hermitian properties: check and force -************************************************************************/ -static void x_split_length(ae_int_t n, ae_int_t nb, ae_int_t* n1, ae_int_t* n2) -{ - ae_int_t r; - if( n<=nb ) - { - *n1 = n; - *n2 = 0; - } - else - { - if( n%nb!=0 ) - { - *n2 = n%nb; - *n1 = n-(*n2); - } - else - { - *n2 = n/2; - *n1 = n-(*n2); - if( *n1%nb==0 ) - { - return; - } - r = nb-*n1%nb; - *n1 = *n1+r; - *n2 = *n2-r; - } - } -} -static double x_safepythag2(double x, double y) -{ - double w; - double xabs; - double yabs; - double z; - xabs = fabs(x); - yabs = fabs(y); - w = xabs>yabs ? xabs : yabs; - z = xabsx_nb || len1>x_nb ) - { - ae_int_t n1, n2; - if( len0>len1 ) - { - x_split_length(len0, x_nb, &n1, &n2); - is_symmetric_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); - is_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); - } - else - { - x_split_length(len1, x_nb, &n1, &n2); - is_symmetric_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); - is_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); - } - return; - } - else - { - /* base case */ - double *p1, *p2, *prow, *pcol; - double v; - ae_int_t i, j; - - p1 = (double*)(a->ptr)+offset0*a->stride+offset1; - p2 = (double*)(a->ptr)+offset1*a->stride+offset0; - for(i=0; istride; - for(j=0; jv ? *mx : v; - v = fabs(*prow); - *mx = *mx>v ? *mx : v; - v = fabs(*pcol-*prow); - *err = *err>v ? *err : v; - } - pcol += a->stride; - prow++; - } - } - } -} -/* - * this function checks that diagonal block A0 is symmetric. - * Block A0 is specified by its offset and size. - * - * [ . ] - * [ A0 ] - * A = [ . ] - * [ . ] - * - * this subroutine updates current values of: - * a) mx maximum value of A[i,j] found so far - * b) err componentwise difference between A0 and A0^T - * - */ -static void is_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) -{ - double *p, *prow, *pcol; - double v; - ae_int_t i, j; - - /* try to split problem into two smaller ones */ - if( len>x_nb ) - { - ae_int_t n1, n2; - x_split_length(len, x_nb, &n1, &n2); - is_symmetric_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); - is_symmetric_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); - is_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); - return; - } - - /* base case */ - p = (double*)(a->ptr)+offset*a->stride+offset; - for(i=0; istride; - for(j=0; jstride,prow++) - { - if( !ae_isfinite(*pcol,_state) || !ae_isfinite(*prow,_state) ) - { - *nonfinite = ae_true; - } - else - { - v = fabs(*pcol); - *mx = *mx>v ? *mx : v; - v = fabs(*prow); - *mx = *mx>v ? *mx : v; - v = fabs(*pcol-*prow); - *err = *err>v ? *err : v; - } - } - v = fabs(p[i+i*a->stride]); - *mx = *mx>v ? *mx : v; - } -} -/* - * this function checks difference between offdiagonal blocks BL and BU - * (see below). Block BL is specified by offsets (offset0,offset1) and - * sizes (len0,len1). - * - * [ . ] - * [ A0 BU ] - * A = [ BL A1 ] - * [ . ] - * - * this subroutine updates current values of: - * a) mx maximum value of A[i,j] found so far - * b) err componentwise difference between elements of BL and BU^H - * - */ -static void is_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) -{ - /* try to split problem into two smaller ones */ - if( len0>x_nb || len1>x_nb ) - { - ae_int_t n1, n2; - if( len0>len1 ) - { - x_split_length(len0, x_nb, &n1, &n2); - is_hermitian_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); - is_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); - } - else - { - x_split_length(len1, x_nb, &n1, &n2); - is_hermitian_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); - is_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); - } - return; - } - else - { - /* base case */ - ae_complex *p1, *p2, *prow, *pcol; - double v; - ae_int_t i, j; - - p1 = (ae_complex*)(a->ptr)+offset0*a->stride+offset1; - p2 = (ae_complex*)(a->ptr)+offset1*a->stride+offset0; - for(i=0; istride; - for(j=0; jx, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) - { - *nonfinite = ae_true; - } - else - { - v = x_safepythag2(pcol->x, pcol->y); - *mx = *mx>v ? *mx : v; - v = x_safepythag2(prow->x, prow->y); - *mx = *mx>v ? *mx : v; - v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); - *err = *err>v ? *err : v; - } - pcol += a->stride; - prow++; - } - } - } -} -/* - * this function checks that diagonal block A0 is Hermitian. - * Block A0 is specified by its offset and size. - * - * [ . ] - * [ A0 ] - * A = [ . ] - * [ . ] - * - * this subroutine updates current values of: - * a) mx maximum value of A[i,j] found so far - * b) err componentwise difference between A0 and A0^H - * - */ -static void is_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) -{ - ae_complex *p, *prow, *pcol; - double v; - ae_int_t i, j; - - /* try to split problem into two smaller ones */ - if( len>x_nb ) - { - ae_int_t n1, n2; - x_split_length(len, x_nb, &n1, &n2); - is_hermitian_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); - is_hermitian_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); - is_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); - return; - } - - /* base case */ - p = (ae_complex*)(a->ptr)+offset*a->stride+offset; - for(i=0; istride; - for(j=0; jstride,prow++) - { - if( !ae_isfinite(pcol->x, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) - { - *nonfinite = ae_true; - } - else - { - v = x_safepythag2(pcol->x, pcol->y); - *mx = *mx>v ? *mx : v; - v = x_safepythag2(prow->x, prow->y); - *mx = *mx>v ? *mx : v; - v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); - *err = *err>v ? *err : v; - } - } - if( !ae_isfinite(p[i+i*a->stride].x, _state) || !ae_isfinite(p[i+i*a->stride].y, _state) ) - { - *nonfinite = ae_true; - } - else - { - v = fabs(p[i+i*a->stride].x); - *mx = *mx>v ? *mx : v; - v = fabs(p[i+i*a->stride].y); - *err = *err>v ? *err : v; - } - } -} -/* - * this function copies offdiagonal block BL to its symmetric counterpart - * BU (see below). Block BL is specified by offsets (offset0,offset1) - * and sizes (len0,len1). - * - * [ . ] - * [ A0 BU ] - * A = [ BL A1 ] - * [ . ] - * - */ -static void force_symmetric_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) -{ - /* try to split problem into two smaller ones */ - if( len0>x_nb || len1>x_nb ) - { - ae_int_t n1, n2; - if( len0>len1 ) - { - x_split_length(len0, x_nb, &n1, &n2); - force_symmetric_rec_off_stat(a, offset0, offset1, n1, len1); - force_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1); - } - else - { - x_split_length(len1, x_nb, &n1, &n2); - force_symmetric_rec_off_stat(a, offset0, offset1, len0, n1); - force_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2); - } - return; - } - else - { - /* base case */ - double *p1, *p2, *prow, *pcol; - ae_int_t i, j; - - p1 = (double*)(a->ptr)+offset0*a->stride+offset1; - p2 = (double*)(a->ptr)+offset1*a->stride+offset0; - for(i=0; istride; - for(j=0; jstride; - prow++; - } - } - } -} -/* - * this function copies lower part of diagonal block A0 to its upper part - * Block is specified by offset and size. - * - * [ . ] - * [ A0 ] - * A = [ . ] - * [ . ] - * - */ -static void force_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) -{ - double *p, *prow, *pcol; - ae_int_t i, j; - - /* try to split problem into two smaller ones */ - if( len>x_nb ) - { - ae_int_t n1, n2; - x_split_length(len, x_nb, &n1, &n2); - force_symmetric_rec_diag_stat(a, offset, n1); - force_symmetric_rec_diag_stat(a, offset+n1, n2); - force_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1); - return; - } - - /* base case */ - p = (double*)(a->ptr)+offset*a->stride+offset; - for(i=0; istride; - for(j=0; jstride,prow++) - *pcol = *prow; - } -} -/* - * this function copies Hermitian transpose of offdiagonal block BL to - * its symmetric counterpart BU (see below). Block BL is specified by - * offsets (offset0,offset1) and sizes (len0,len1). - * - * [ . ] - * [ A0 BU ] - * A = [ BL A1 ] - * [ . ] - */ -static void force_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) -{ - /* try to split problem into two smaller ones */ - if( len0>x_nb || len1>x_nb ) - { - ae_int_t n1, n2; - if( len0>len1 ) - { - x_split_length(len0, x_nb, &n1, &n2); - force_hermitian_rec_off_stat(a, offset0, offset1, n1, len1); - force_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1); - } - else - { - x_split_length(len1, x_nb, &n1, &n2); - force_hermitian_rec_off_stat(a, offset0, offset1, len0, n1); - force_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2); - } - return; - } - else - { - /* base case */ - ae_complex *p1, *p2, *prow, *pcol; - ae_int_t i, j; - - p1 = (ae_complex*)(a->ptr)+offset0*a->stride+offset1; - p2 = (ae_complex*)(a->ptr)+offset1*a->stride+offset0; - for(i=0; istride; - for(j=0; jstride; - prow++; - } - } - } -} -/* - * this function copies Hermitian transpose of lower part of - * diagonal block A0 to its upper part Block is specified by offset and size. - * - * [ . ] - * [ A0 ] - * A = [ . ] - * [ . ] - * - */ -static void force_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) -{ - ae_complex *p, *prow, *pcol; - ae_int_t i, j; - - /* try to split problem into two smaller ones */ - if( len>x_nb ) - { - ae_int_t n1, n2; - x_split_length(len, x_nb, &n1, &n2); - force_hermitian_rec_diag_stat(a, offset, n1); - force_hermitian_rec_diag_stat(a, offset+n1, n2); - force_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1); - return; - } - - /* base case */ - p = (ae_complex*)(a->ptr)+offset*a->stride+offset; - for(i=0; istride; - for(j=0; jstride,prow++) - *pcol = *prow; - } -} -ae_bool x_is_symmetric(x_matrix *a) -{ - double mx, err; - ae_bool nonfinite; - ae_state _alglib_env_state; - if( a->datatype!=DT_REAL ) - return ae_false; - if( a->cols!=a->rows ) - return ae_false; - if( a->cols==0 || a->rows==0 ) - return ae_true; - ae_state_init(&_alglib_env_state); - mx = 0; - err = 0; - nonfinite = ae_false; - is_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); - if( nonfinite ) - return ae_false; - if( mx==0 ) - return ae_true; - return err/mx<=1.0E-14; -} -ae_bool x_is_hermitian(x_matrix *a) -{ - double mx, err; - ae_bool nonfinite; - ae_state _alglib_env_state; - if( a->datatype!=DT_COMPLEX ) - return ae_false; - if( a->cols!=a->rows ) - return ae_false; - if( a->cols==0 || a->rows==0 ) - return ae_true; - ae_state_init(&_alglib_env_state); - mx = 0; - err = 0; - nonfinite = ae_false; - is_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); - if( nonfinite ) - return ae_false; - if( mx==0 ) - return ae_true; - return err/mx<=1.0E-14; -} -ae_bool x_force_symmetric(x_matrix *a) -{ - if( a->datatype!=DT_REAL ) - return ae_false; - if( a->cols!=a->rows ) - return ae_false; - if( a->cols==0 || a->rows==0 ) - return ae_true; - force_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows); - return ae_true; -} -ae_bool x_force_hermitian(x_matrix *a) -{ - if( a->datatype!=DT_COMPLEX ) - return ae_false; - if( a->cols!=a->rows ) - return ae_false; - if( a->cols==0 || a->rows==0 ) - return ae_true; - force_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows); - return ae_true; -} - -ae_bool ae_is_symmetric(ae_matrix *a) -{ - x_matrix x; - x.owner = OWN_CALLER; - ae_x_attach_to_matrix(&x, a); - return x_is_symmetric(&x); -} - -ae_bool ae_is_hermitian(ae_matrix *a) -{ - x_matrix x; - x.owner = OWN_CALLER; - ae_x_attach_to_matrix(&x, a); - return x_is_hermitian(&x); -} - -ae_bool ae_force_symmetric(ae_matrix *a) -{ - x_matrix x; - x.owner = OWN_CALLER; - ae_x_attach_to_matrix(&x, a); - return x_force_symmetric(&x); -} - -ae_bool ae_force_hermitian(ae_matrix *a) -{ - x_matrix x; - x.owner = OWN_CALLER; - ae_x_attach_to_matrix(&x, a); - return x_force_hermitian(&x); -} - -/************************************************************************ -This function converts six-bit value (from 0 to 63) to character (only -digits, lowercase and uppercase letters, minus and underscore are used). - -If v is negative or greater than 63, this function returns '?'. -************************************************************************/ -static char _sixbits2char_tbl[64] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', '-', '_' }; - -char ae_sixbits2char(ae_int_t v) -{ - - if( v<0 || v>63 ) - return '?'; - return _sixbits2char_tbl[v]; - - /* v is correct, process it */ - /*if( v<10 ) - return '0'+v; - v -= 10; - if( v<26 ) - return 'A'+v; - v -= 26; - if( v<26 ) - return 'a'+v; - v -= 26; - return v==0 ? '-' : '_';*/ -} - -/************************************************************************ -This function converts character to six-bit value (from 0 to 63). - -This function is inverse of ae_sixbits2char() -If c is not correct character, this function returns -1. -************************************************************************/ -static ae_int_t _ae_char2sixbits_tbl[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 62, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, -1, -1, -1, -1, 63, - -1, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, -1, -1, -1, -1, -1 }; -ae_int_t ae_char2sixbits(char c) -{ - return (c>=0 && c<127) ? _ae_char2sixbits_tbl[(int)c] : -1; -} - -/************************************************************************ -This function converts three bytes (24 bits) to four six-bit values -(24 bits again). - -src pointer to three bytes -dst pointer to four ints -************************************************************************/ -void ae_threebytes2foursixbits(const unsigned char *src, ae_int_t *dst) -{ - dst[0] = src[0] & 0x3F; - dst[1] = (src[0]>>6) | ((src[1]&0x0F)<<2); - dst[2] = (src[1]>>4) | ((src[2]&0x03)<<4); - dst[3] = src[2]>>2; -} - -/************************************************************************ -This function converts four six-bit values (24 bits) to three bytes -(24 bits again). - -src pointer to four ints -dst pointer to three bytes -************************************************************************/ -void ae_foursixbits2threebytes(const ae_int_t *src, unsigned char *dst) -{ - dst[0] = (unsigned char)( src[0] | ((src[1]&0x03)<<6)); - dst[1] = (unsigned char)((src[1]>>2) | ((src[2]&0x0F)<<4)); - dst[2] = (unsigned char)((src[2]>>4) | (src[3]<<2)); -} - -/************************************************************************ -This function serializes boolean value into buffer - -v boolean value to be serialized -buf buffer, at least 12 characters wide - (11 chars for value, one for trailing zero) -state ALGLIB environment state -************************************************************************/ -void ae_bool2str(ae_bool v, char *buf, ae_state *state) -{ - char c = v ? '1' : '0'; - ae_int_t i; - for(i=0; iendianness==AE_BIG_ENDIAN ) - { - for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) - { - unsigned char tc; - tc = u.bytes[i]; - u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i]; - u.bytes[sizeof(ae_int_t)-1-i] = tc; - } - } - - /* - * convert to six-bit representation, output - * - * NOTE: last 12th element of sixbits is always zero, we do not output it - */ - ae_threebytes2foursixbits(u.bytes+0, sixbits+0); - ae_threebytes2foursixbits(u.bytes+3, sixbits+4); - ae_threebytes2foursixbits(u.bytes+6, sixbits+8); - for(i=0; i=AE_SER_ENTRY_LENGTH ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - sixbits[sixbitsread] = d; - sixbitsread++; - buf++; - } - *pasttheend = buf; - if( sixbitsread==0 ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - for(i=sixbitsread; i<12; i++) - sixbits[i] = 0; - ae_foursixbits2threebytes(sixbits+0, u.bytes+0); - ae_foursixbits2threebytes(sixbits+4, u.bytes+3); - ae_foursixbits2threebytes(sixbits+8, u.bytes+6); - if( state->endianness==AE_BIG_ENDIAN ) - { - for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) - { - unsigned char tc; - tc = u.bytes[i]; - u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i]; - u.bytes[sizeof(ae_int_t)-1-i] = tc; - } - } - return u.ival; -} - - -/************************************************************************ -This function serializes double value into buffer - -v double value to be serialized -buf buffer, at least 12 characters wide - (11 chars for value, one for trailing zero) -state ALGLIB environment state -************************************************************************/ -void ae_double2str(double v, char *buf, ae_state *state) -{ - union _u - { - double dval; - unsigned char bytes[9]; - } u; - ae_int_t i; - ae_int_t sixbits[12]; - - /* - * handle special quantities - */ - if( ae_isnan(v, state) ) - { - const char *s = ".nan_______"; - memcpy(buf, s, strlen(s)+1); - return; - } - if( ae_isposinf(v, state) ) - { - const char *s = ".posinf____"; - memcpy(buf, s, strlen(s)+1); - return; - } - if( ae_isneginf(v, state) ) - { - const char *s = ".neginf____"; - memcpy(buf, s, strlen(s)+1); - return; - } - - /* - * process general case: - * 1. copy v to array of chars - * 2. set 9th byte of u.bytes to zero in order to - * simplify conversion to six-bit representation - * 3. convert to little endian (if needed) - * 4. convert to six-bit representation - * (last 12th element of sixbits is always zero, we do not output it) - */ - u.dval = v; - u.bytes[8] = 0; - if( state->endianness==AE_BIG_ENDIAN ) - { - for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) - { - unsigned char tc; - tc = u.bytes[i]; - u.bytes[i] = u.bytes[sizeof(double)-1-i]; - u.bytes[sizeof(double)-1-i] = tc; - } - } - ae_threebytes2foursixbits(u.bytes+0, sixbits+0); - ae_threebytes2foursixbits(u.bytes+3, sixbits+4); - ae_threebytes2foursixbits(u.bytes+6, sixbits+8); - for(i=0; iv_nan; - } - if( strncmp(buf, s_posinf, strlen(s_posinf))==0 ) - { - *pasttheend = buf+strlen(s_posinf); - return state->v_posinf; - } - if( strncmp(buf, s_neginf, strlen(s_neginf))==0 ) - { - *pasttheend = buf+strlen(s_neginf); - return state->v_neginf; - } - ae_break(state, ERR_ASSERTION_FAILED, emsg); - } - - /* - * General case: - * 1. read and decode six-bit digits - * 2. check that all 11 digits were read - * 3. set last 12th digit to zero (needed for simplicity of conversion) - * 4. convert to 8 bytes - * 5. convert to big endian representation, if needed - */ - sixbitsread = 0; - while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 ) - { - ae_int_t d; - d = ae_char2sixbits(*buf); - if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - sixbits[sixbitsread] = d; - sixbitsread++; - buf++; - } - *pasttheend = buf; - if( sixbitsread!=AE_SER_ENTRY_LENGTH ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - sixbits[AE_SER_ENTRY_LENGTH] = 0; - ae_foursixbits2threebytes(sixbits+0, u.bytes+0); - ae_foursixbits2threebytes(sixbits+4, u.bytes+3); - ae_foursixbits2threebytes(sixbits+8, u.bytes+6); - if( state->endianness==AE_BIG_ENDIAN ) - { - for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) - { - unsigned char tc; - tc = u.bytes[i]; - u.bytes[i] = u.bytes[sizeof(double)-1-i]; - u.bytes[sizeof(double)-1-i] = tc; - } - } - return u.dval; -} - - -/************************************************************************ -This function performs given number of spin-wait iterations -************************************************************************/ -void ae_spin_wait(ae_int_t cnt) -{ - /* - * these strange operations with ae_never_change_it are necessary to - * prevent compiler optimization of the loop. - */ - volatile ae_int_t i; - - /* very unlikely because no one will wait for such amount of cycles */ - if( cnt>0x12345678 ) - ae_never_change_it = cnt%10; - - /* spin wait, test condition which will never be true */ - for(i=0; i0 ) - ae_never_change_it--; -} - - -/************************************************************************ -This function causes the calling thread to relinquish the CPU. The thread -is moved to the end of the queue and some other thread gets to run. - -NOTE: this function should NOT be called when AE_OS is AE_UNKNOWN - the - whole program will be abnormally terminated. -************************************************************************/ -void ae_yield() -{ -#if AE_OS==AE_WINDOWS - if( !SwitchToThread() ) - Sleep(0); -#elif AE_OS==AE_POSIX - sched_yield(); -#else - abort(); -#endif -} - -/************************************************************************ -This function initializes ae_lock structure and sets lock in a free mode. -************************************************************************/ -void ae_init_lock(ae_lock *lock) -{ -#if AE_OS==AE_WINDOWS - lock->p_lock = (ae_int_t*)ae_align((void*)(&lock->buf),AE_LOCK_ALIGNMENT); - lock->p_lock[0] = 0; -#elif AE_OS==AE_POSIX - pthread_mutex_init(&lock->mutex, NULL); -#else - lock->is_locked = ae_false; -#endif -} - - -/************************************************************************ -This function acquires lock. In case lock is busy, we perform several -iterations inside tight loop before trying again. -************************************************************************/ -void ae_acquire_lock(ae_lock *lock) -{ -#if AE_OS==AE_WINDOWS - ae_int_t cnt = 0; -#ifdef AE_SMP_DEBUGCOUNTERS - InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_acquisitions); -#endif - for(;;) - { - if( InterlockedCompareExchange((LONG volatile *)lock->p_lock, 1, 0)==0 ) - return; - ae_spin_wait(AE_LOCK_CYCLES); -#ifdef AE_SMP_DEBUGCOUNTERS - InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_spinwaits); -#endif - cnt++; - if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) - { -#ifdef AE_SMP_DEBUGCOUNTERS - InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_yields); -#endif - ae_yield(); - } - } -#elif AE_OS==AE_POSIX - ae_int_t cnt = 0; - for(;;) - { - if( pthread_mutex_trylock(&lock->mutex)==0 ) - return; - ae_spin_wait(AE_LOCK_CYCLES); - cnt++; - if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) - ae_yield(); - } - ; -#else - AE_CRITICAL_ASSERT(!lock->is_locked); - lock->is_locked = ae_true; -#endif -} - - -/************************************************************************ -This function releases lock. -************************************************************************/ -void ae_release_lock(ae_lock *lock) -{ -#if AE_OS==AE_WINDOWS - InterlockedExchange((LONG volatile *)lock->p_lock, 0); -#elif AE_OS==AE_POSIX - pthread_mutex_unlock(&lock->mutex); -#else - lock->is_locked = ae_false; -#endif -} - - -/************************************************************************ -This function frees ae_lock structure. -************************************************************************/ -void ae_free_lock(ae_lock *lock) -{ -#if AE_OS==AE_POSIX - pthread_mutex_destroy(&lock->mutex); -#endif -} - - -/************************************************************************ -This function creates ae_shared_pool structure. - -dst destination shared pool; - already allocated, but not initialized. -state ALGLIB environment state -make_automatic if true, pool is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. -************************************************************************/ -ae_bool ae_shared_pool_init(void *_dst, ae_state *state, ae_bool make_automatic) -{ - ae_shared_pool *dst; - - dst = (ae_shared_pool*)_dst; - - /* init */ - dst->seed_object = NULL; - dst->recycled_objects = NULL; - dst->recycled_entries = NULL; - dst->enumeration_counter = NULL; - dst->size_of_object = 0; - dst->init = NULL; - dst->init_copy = NULL; - dst->destroy = NULL; - dst->frame_entry.deallocator = ae_shared_pool_destroy; - dst->frame_entry.ptr = dst; - if( make_automatic && state!=NULL ) - ae_db_attach(&dst->frame_entry, state); - ae_init_lock(&dst->pool_lock); - return ae_true; -} - - -/************************************************************************ -This function clears all dynamically allocated fields of the pool except -for the lock. It does NOT try to acquire pool_lock. - -NOTE: this function is NOT thread-safe, it is not protected by lock. -************************************************************************/ -static void ae_shared_pool_internalclear(ae_shared_pool *dst) -{ - ae_shared_pool_entry *ptr, *tmp; - - /* destroy seed */ - if( dst->seed_object!=NULL ) - { - dst->destroy((void*)dst->seed_object); - ae_free((void*)dst->seed_object); - dst->seed_object = NULL; - } - - /* destroy recycled objects */ - for(ptr=dst->recycled_objects; ptr!=NULL;) - { - tmp = (ae_shared_pool_entry*)ptr->next_entry; - dst->destroy(ptr->obj); - ae_free(ptr->obj); - ae_free(ptr); - ptr = tmp; - } - dst->recycled_objects = NULL; - - /* destroy recycled entries */ - for(ptr=dst->recycled_entries; ptr!=NULL;) - { - tmp = (ae_shared_pool_entry*)ptr->next_entry; - ae_free(ptr); - ptr = tmp; - } - dst->recycled_entries = NULL; -} - - -/************************************************************************ -This function creates copy of ae_shared_pool. - -dst destination pool, allocated but not initialized -src source pool -state ALGLIB environment state -make_automatic if true, pool is added to the dynamic block list - -Error handling: -* if state is NULL, returns ae_false on allocation error -* if state is not NULL, calls ae_break() on allocation error -* returns ae_true on success - -dst is assumed to be uninitialized, its fields are ignored. - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -ae_bool ae_shared_pool_init_copy(void *_dst, void *_src, ae_state *state, ae_bool make_automatic) -{ - ae_shared_pool *dst, *src; - ae_shared_pool_entry *ptr; - - dst = (ae_shared_pool*)_dst; - src = (ae_shared_pool*)_src; - if( !ae_shared_pool_init(dst, state, make_automatic) ) - return ae_false; - - /* copy non-pointer fields */ - dst->size_of_object = src->size_of_object; - dst->init = src->init; - dst->init_copy = src->init_copy; - dst->destroy = src->destroy; - ae_init_lock(&dst->pool_lock); - - /* copy seed object */ - if( src->seed_object!=NULL ) - { - dst->seed_object = ae_malloc(dst->size_of_object, state); - if( dst->seed_object==NULL ) - return ae_false; - if( !dst->init_copy(dst->seed_object, src->seed_object, state, ae_false) ) - return ae_false; - } - - /* copy recycled objects */ - dst->recycled_objects = NULL; - for(ptr=src->recycled_objects; ptr!=NULL; ptr=(ae_shared_pool_entry*)ptr->next_entry) - { - ae_shared_pool_entry *tmp; - tmp = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); - if( tmp==NULL ) - return ae_false; - tmp->obj = ae_malloc(dst->size_of_object, state); - if( tmp->obj==NULL ) - return ae_false; - if( !dst->init_copy(tmp->obj, ptr->obj, state, ae_false) ) - return ae_false; - tmp->next_entry = dst->recycled_objects; - dst->recycled_objects = tmp; - } - - /* recycled entries are not copied because they do not store any information */ - dst->recycled_entries = NULL; - - /* enumeration counter is reset on copying */ - dst->enumeration_counter = NULL; - - /* initialize frame record */ - dst->frame_entry.deallocator = ae_shared_pool_destroy; - dst->frame_entry.ptr = dst; - - /* return */ - return ae_true; -} - - -/************************************************************************ -This function clears contents of the pool, but pool remain usable. - -IMPORTANT: this function invalidates dst, it can not be used after it is - cleared. - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -void ae_shared_pool_clear(void *_dst) -{ - ae_shared_pool *dst = (ae_shared_pool*)_dst; - - /* clear seed and lists */ - ae_shared_pool_internalclear(dst); - - /* clear fields */ - dst->seed_object = NULL; - dst->recycled_objects = NULL; - dst->recycled_entries = NULL; - dst->enumeration_counter = NULL; - dst->size_of_object = 0; - dst->init = NULL; - dst->init_copy = NULL; - dst->destroy = NULL; -} - - -/************************************************************************ -This function destroys pool (object is left in invalid state, all -dynamically allocated memory is freed). - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -void ae_shared_pool_destroy(void *_dst) -{ - ae_shared_pool *dst = (ae_shared_pool*)_dst; - ae_shared_pool_clear(_dst); - ae_free_lock(&dst->pool_lock); -} - - -/************************************************************************ -This function returns True, if internal seed object was set. It returns -False for un-seeded pool. - -dst destination pool (initialized by constructor function) - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -ae_bool ae_shared_pool_is_initialized(void *_dst) -{ - ae_shared_pool *dst = (ae_shared_pool*)_dst; - return dst->seed_object!=NULL; -} - - -/************************************************************************ -This function sets internal seed object. All objects owned by the pool -(current seed object, recycled objects) are automatically freed. - -dst destination pool (initialized by constructor function) -seed_object new seed object -size_of_object sizeof(), used to allocate memory -init constructor function -init_copy copy constructor -clear destructor function -state ALGLIB environment state - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -void ae_shared_pool_set_seed( - ae_shared_pool *dst, - void *seed_object, - ae_int_t size_of_object, - ae_bool (*init)(void* dst, ae_state* state, ae_bool make_automatic), - ae_bool (*init_copy)(void* dst, void* src, ae_state* state, ae_bool make_automatic), - void (*destroy)(void* ptr), - ae_state *state) -{ - /* destroy internal objects */ - ae_shared_pool_internalclear(dst); - - /* set non-pointer fields */ - dst->size_of_object = size_of_object; - dst->init = init; - dst->init_copy = init_copy; - dst->destroy = destroy; - - /* set seed object */ - dst->seed_object = ae_malloc(size_of_object, state); - ae_assert(dst->seed_object!=NULL, "ALGLIB: unable to allocate memory for ae_shared_pool_set_seed()", state); - ae_assert( - init_copy(dst->seed_object, seed_object, state, ae_false), - "ALGLIB: unable to initialize seed in ae_shared_pool_set_seed()", - state); -} - - -/************************************************************************ -This function retrieves a copy of the seed object from the pool and -stores it to target smart pointer ptr. - -In case target pointer owns non-NULL value, it is deallocated before -storing value retrieved from pool. Target pointer becomes owner of the -value which was retrieved from pool. - -pool pool -pptr pointer to ae_smart_ptr structure -state ALGLIB environment state - -NOTE: this function IS thread-safe. It acquires pool lock during its - operation and can be used simultaneously from several threads. -************************************************************************/ -void ae_shared_pool_retrieve( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state) -{ - void *new_obj; - - /* assert that pool was seeded */ - ae_assert( - pool->seed_object!=NULL, - "ALGLIB: shared pool is not seeded, PoolRetrieve() failed", - state); - - /* acquire lock */ - ae_acquire_lock(&pool->pool_lock); - - /* try to reuse recycled objects */ - if( pool->recycled_objects!=NULL ) - { - void *new_obj; - ae_shared_pool_entry *result; - - /* retrieve entry/object from list of recycled objects */ - result = pool->recycled_objects; - pool->recycled_objects = (ae_shared_pool_entry*)pool->recycled_objects->next_entry; - new_obj = result->obj; - result->obj = NULL; - - /* move entry to list of recycled entries */ - result->next_entry = pool->recycled_entries; - pool->recycled_entries = result; - - /* release lock */ - ae_release_lock(&pool->pool_lock); - - /* assign object to smart pointer */ - ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->destroy); - return; - } - - /* release lock; we do not need it anymore because copy constructor does not modify source variable */ - ae_release_lock(&pool->pool_lock); - - /* create new object from seed */ - new_obj = ae_malloc(pool->size_of_object, state); - ae_assert(new_obj!=NULL, "ALGLIB: unable to allocate memory for ae_shared_pool_retrieve()", state); - ae_assert( - pool->init_copy(new_obj, pool->seed_object, state, ae_false), - "ALGLIB: unable to initialize object in ae_shared_pool_retrieve()", - state); - - /* assign object to smart pointer and return */ - ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->destroy); -} - - -/************************************************************************ -This function recycles object owned by smart pointer by moving it to -internal storage of the shared pool. - -Source pointer must own the object. After function is over, it owns NULL -pointer. - -pool pool -pptr pointer to ae_smart_ptr structure -state ALGLIB environment state - -NOTE: this function IS thread-safe. It acquires pool lock during its - operation and can be used simultaneously from several threads. -************************************************************************/ -void ae_shared_pool_recycle( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state) -{ - ae_shared_pool_entry *new_entry; - - /* assert that pool was seeded */ - ae_assert( - pool->seed_object!=NULL, - "ALGLIB: shared pool is not seeded, PoolRecycle() failed", - state); - - /* assert that pointer non-null and owns the object */ - ae_assert(pptr->is_owner, "ALGLIB: pptr in ae_shared_pool_recycle() does not own its pointer", state); - ae_assert(pptr->ptr!=NULL, "ALGLIB: pptr in ae_shared_pool_recycle() is NULL", state); - - /* acquire lock */ - ae_acquire_lock(&pool->pool_lock); - - /* acquire shared pool entry (reuse one from recycled_entries or malloc new one) */ - if( pool->recycled_entries!=NULL ) - { - /* reuse previously allocated entry */ - new_entry = pool->recycled_entries; - pool->recycled_entries = (ae_shared_pool_entry*)new_entry->next_entry; - } - else - { - /* - * Allocate memory for new entry. - * - * NOTE: we release pool lock during allocation because ae_malloc() may raise - * exception and we do not want our pool to be left in the locked state. - */ - ae_release_lock(&pool->pool_lock); - new_entry = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); - ae_assert(new_entry!=NULL, "ALGLIB: unable to allocate memory in ae_shared_pool_recycle()", state); - ae_acquire_lock(&pool->pool_lock); - } - - /* add object to the list of recycled objects */ - new_entry->obj = pptr->ptr; - new_entry->next_entry = pool->recycled_objects; - pool->recycled_objects = new_entry; - - /* release lock object */ - ae_release_lock(&pool->pool_lock); - - /* release source pointer */ - ae_smart_ptr_release(pptr); -} - - -/************************************************************************ -This function clears internal list of recycled objects, but does not -change seed object managed by the pool. - -pool pool -state ALGLIB environment state - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -void ae_shared_pool_clear_recycled( - ae_shared_pool *pool, - ae_state *state) -{ - ae_shared_pool_entry *ptr, *tmp; - - /* clear recycled objects */ - for(ptr=pool->recycled_objects; ptr!=NULL;) - { - tmp = (ae_shared_pool_entry*)ptr->next_entry; - pool->destroy(ptr->obj); - ae_free(ptr->obj); - ae_free(ptr); - ptr = tmp; - } - pool->recycled_objects = NULL; -} - - -/************************************************************************ -This function allows to enumerate recycled elements of the shared pool. -It stores pointer to the first recycled object in the smart pointer. - -IMPORTANT: -* in case target pointer owns non-NULL value, it is deallocated before - storing value retrieved from pool. -* recycled object IS NOT removed from pool -* target pointer DOES NOT become owner of the new value -* this function IS NOT thread-safe -* you SHOULD NOT modify shared pool during enumeration (although you can - modify state of the objects retrieved from pool) -* in case there is no recycled objects in the pool, NULL is stored to pptr -* in case pool is not seeded, NULL is stored to pptr - -pool pool -pptr pointer to ae_smart_ptr structure -state ALGLIB environment state -************************************************************************/ -void ae_shared_pool_first_recycled( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state) -{ - /* modify internal enumeration counter */ - pool->enumeration_counter = pool->recycled_objects; - - /* exit on empty list */ - if( pool->enumeration_counter==NULL ) - { - ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); - return; - } - - /* assign object to smart pointer */ - ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, pool->destroy); -} - - -/************************************************************************ -This function allows to enumerate recycled elements of the shared pool. -It stores pointer to the next recycled object in the smart pointer. - -IMPORTANT: -* in case target pointer owns non-NULL value, it is deallocated before - storing value retrieved from pool. -* recycled object IS NOT removed from pool -* target pointer DOES NOT become owner of the new value -* this function IS NOT thread-safe -* you SHOULD NOT modify shared pool during enumeration (although you can - modify state of the objects retrieved from pool) -* in case there is no recycled objects left in the pool, NULL is stored. -* in case pool is not seeded, NULL is stored. - -pool pool -pptr pointer to ae_smart_ptr structure -state ALGLIB environment state -************************************************************************/ -void ae_shared_pool_next_recycled( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state) -{ - /* exit on end of list */ - if( pool->enumeration_counter==NULL ) - { - ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); - return; - } - - /* modify internal enumeration counter */ - pool->enumeration_counter = (ae_shared_pool_entry*)pool->enumeration_counter->next_entry; - - /* exit on empty list */ - if( pool->enumeration_counter==NULL ) - { - ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, NULL); - return; - } - - /* assign object to smart pointer */ - ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, pool->destroy); -} - - - -/************************************************************************ -This function clears internal list of recycled objects and seed object. -However, pool still can be used (after initialization with another seed). - -pool pool -state ALGLIB environment state - -NOTE: this function is NOT thread-safe. It does not acquire pool lock, so - you should NOT call it when lock can be used by another thread. -************************************************************************/ -void ae_shared_pool_reset( - ae_shared_pool *pool, - ae_state *state) -{ - /* clear seed and lists */ - ae_shared_pool_internalclear(pool); - - /* clear fields */ - pool->seed_object = NULL; - pool->recycled_objects = NULL; - pool->recycled_entries = NULL; - pool->enumeration_counter = NULL; - pool->size_of_object = 0; - pool->init = NULL; - pool->init_copy = NULL; - pool->destroy = NULL; -} - - -/************************************************************************ -This function initializes serializer -************************************************************************/ -void ae_serializer_init(ae_serializer *serializer) -{ - serializer->mode = AE_SM_DEFAULT; - serializer->entries_needed = 0; - serializer->bytes_asked = 0; -} - -void ae_serializer_clear(ae_serializer *serializer) -{ -} - -void ae_serializer_alloc_start(ae_serializer *serializer) -{ - serializer->entries_needed = 0; - serializer->bytes_asked = 0; - serializer->mode = AE_SM_ALLOC; -} - -void ae_serializer_alloc_entry(ae_serializer *serializer) -{ - serializer->entries_needed++; -} - -ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer) -{ - ae_int_t rows, lastrowsize, result; - - serializer->mode = AE_SM_READY2S; - - /* if no entries needes (degenerate case) */ - if( serializer->entries_needed==0 ) - { - serializer->bytes_asked = 1; - return serializer->bytes_asked; - } - - /* non-degenerate case */ - rows = serializer->entries_needed/AE_SER_ENTRIES_PER_ROW; - lastrowsize = AE_SER_ENTRIES_PER_ROW; - if( serializer->entries_needed%AE_SER_ENTRIES_PER_ROW ) - { - lastrowsize = serializer->entries_needed%AE_SER_ENTRIES_PER_ROW; - rows++; - } - - /* calculate result size */ - result = ((rows-1)*AE_SER_ENTRIES_PER_ROW+lastrowsize)*AE_SER_ENTRY_LENGTH; - result += (rows-1)*(AE_SER_ENTRIES_PER_ROW-1)+(lastrowsize-1); - result += rows*2; - serializer->bytes_asked = result; - return result; -} - -#ifdef AE_USE_CPP_SERIALIZATION -void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf) -{ - serializer->mode = AE_SM_TO_CPPSTRING; - serializer->out_cppstr = buf; - serializer->entries_saved = 0; - serializer->bytes_written = 0; -} -#endif - -#ifdef AE_USE_CPP_SERIALIZATION -void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf) -{ - serializer->mode = AE_SM_FROM_STRING; - serializer->in_str = buf->c_str(); -} -#endif - -void ae_serializer_sstart_str(ae_serializer *serializer, char *buf) -{ - serializer->mode = AE_SM_TO_STRING; - serializer->out_str = buf; - serializer->out_str[0] = 0; - serializer->entries_saved = 0; - serializer->bytes_written = 0; -} - -void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf) -{ - serializer->mode = AE_SM_FROM_STRING; - serializer->in_str = buf; -} - -void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state) -{ - char buf[AE_SER_ENTRY_LENGTH+2+1]; - const char *emsg = "ALGLIB: serialization integrity error"; - ae_int_t bytes_appended; - - /* prepare serialization, check consistency */ - ae_bool2str(v, buf, state); - serializer->entries_saved++; - if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) - strcat(buf, " "); - else - strcat(buf, "\r\n"); - bytes_appended = (ae_int_t)strlen(buf); - if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - serializer->bytes_written += bytes_appended; - - /* append to buffer */ -#ifdef AE_USE_CPP_SERIALIZATION - if( serializer->mode==AE_SM_TO_CPPSTRING ) - { - *(serializer->out_cppstr) += buf; - return; - } -#endif - if( serializer->mode==AE_SM_TO_STRING ) - { - strcat(serializer->out_str, buf); - serializer->out_str += bytes_appended; - return; - } - ae_break(state, ERR_ASSERTION_FAILED, emsg); -} - -void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state) -{ - char buf[AE_SER_ENTRY_LENGTH+2+1]; - const char *emsg = "ALGLIB: serialization integrity error"; - ae_int_t bytes_appended; - - /* prepare serialization, check consistency */ - ae_int2str(v, buf, state); - serializer->entries_saved++; - if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) - strcat(buf, " "); - else - strcat(buf, "\r\n"); - bytes_appended = (ae_int_t)strlen(buf); - if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - serializer->bytes_written += bytes_appended; - - /* append to buffer */ -#ifdef AE_USE_CPP_SERIALIZATION - if( serializer->mode==AE_SM_TO_CPPSTRING ) - { - *(serializer->out_cppstr) += buf; - return; - } -#endif - if( serializer->mode==AE_SM_TO_STRING ) - { - strcat(serializer->out_str, buf); - serializer->out_str += bytes_appended; - return; - } - ae_break(state, ERR_ASSERTION_FAILED, emsg); -} - -void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state) -{ - char buf[AE_SER_ENTRY_LENGTH+2+1]; - const char *emsg = "ALGLIB: serialization integrity error"; - ae_int_t bytes_appended; - - /* prepare serialization, check consistency */ - ae_double2str(v, buf, state); - serializer->entries_saved++; - if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) - strcat(buf, " "); - else - strcat(buf, "\r\n"); - bytes_appended = (ae_int_t)strlen(buf); - if( serializer->bytes_written+bytes_appended > serializer->bytes_asked ) - ae_break(state, ERR_ASSERTION_FAILED, emsg); - serializer->bytes_written += bytes_appended; - - /* append to buffer */ -#ifdef AE_USE_CPP_SERIALIZATION - if( serializer->mode==AE_SM_TO_CPPSTRING ) - { - *(serializer->out_cppstr) += buf; - return; - } -#endif - if( serializer->mode==AE_SM_TO_STRING ) - { - strcat(serializer->out_str, buf); - serializer->out_str += bytes_appended; - return; - } - ae_break(state, ERR_ASSERTION_FAILED, emsg); -} - -void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state) -{ - *v = ae_str2bool(serializer->in_str, state, &serializer->in_str); -} - -void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state) -{ - *v = ae_str2int(serializer->in_str, state, &serializer->in_str); -} - -void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state) -{ - *v = ae_str2double(serializer->in_str, state, &serializer->in_str); -} - -void ae_serializer_stop(ae_serializer *serializer) -{ -} - - -/************************************************************************ -Complex math functions -************************************************************************/ -ae_complex ae_complex_from_d(double v) -{ - ae_complex r; - r.x = v; - r.y = 0.0; - return r; -} - -ae_complex ae_c_neg(ae_complex lhs) -{ - ae_complex result; - result.x = -lhs.x; - result.y = -lhs.y; - return result; -} - -ae_complex ae_c_conj(ae_complex lhs, ae_state *state) -{ - ae_complex result; - result.x = +lhs.x; - result.y = -lhs.y; - return result; -} - -ae_complex ae_c_sqr(ae_complex lhs, ae_state *state) -{ - ae_complex result; - result.x = lhs.x*lhs.x-lhs.y*lhs.y; - result.y = 2*lhs.x*lhs.y; - return result; -} - -double ae_c_abs(ae_complex z, ae_state *state) -{ - double w; - double xabs; - double yabs; - double v; - - xabs = fabs(z.x); - yabs = fabs(z.y); - w = xabs>yabs ? xabs : yabs; - v = xabsx; - v0y = -v0->y; - v1x = v1->x; - v1y = -v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( !bconj0 && bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = v0->y; - v1x = v1->x; - v1y = -v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( bconj0 && !bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = -v0->y; - v1x = v1->x; - v1y = v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( !bconj0 && !bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = v0->y; - v1x = v1->x; - v1y = v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - result.x = rx; - result.y = ry; - return result; -} - -void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - for(i=0; ix = vsrc->x; - vdst->y = -vsrc->y; - } - } - else - { - for(i=0; ix = vsrc->x; - vdst->y = -vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = -vsrc->y; - } - } - } - else - { - /* - * optimized case - */ - if( bconj ) - { - for(i=0; ix = -vsrc->x; - vdst->y = vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = -vsrc->y; - } - } - } -} - -void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = -alpha*vsrc->y; - } - } - else - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = alpha*vsrc->y; - } - } - } - else - { - /* - * optimized case - */ - if( bconj ) - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = -alpha*vsrc->y; - } - } - else - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = alpha*vsrc->y; - } - } - } -} - -void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x+ay*vsrc->y; - vdst->y = -ax*vsrc->y+ay*vsrc->x; - } - } - else - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x-ay*vsrc->y; - vdst->y = ax*vsrc->y+ay*vsrc->x; - } - } - } - else - { - /* - * highly optimized case - */ - if( bconj ) - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x+ay*vsrc->y; - vdst->y = -ax*vsrc->y+ay*vsrc->x; - } - } - else - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x-ay*vsrc->y; - vdst->y = ax*vsrc->y+ay*vsrc->x; - } - } - } -} - -void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - for(i=0; ix += vsrc->x; - vdst->y -= vsrc->y; - } - } - else - { - for(i=0; ix += vsrc->x; - vdst->y += vsrc->y; - } - } - } - else - { - /* - * optimized case - */ - if( bconj ) - { - for(i=0; ix += vsrc->x; - vdst->y -= vsrc->y; - } - } - else - { - for(i=0; ix += vsrc->x; - vdst->y += vsrc->y; - } - } - } -} - -void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - for(i=0; ix += alpha*vsrc->x; - vdst->y -= alpha*vsrc->y; - } - } - else - { - for(i=0; ix += alpha*vsrc->x; - vdst->y += alpha*vsrc->y; - } - } - } - else - { - /* - * optimized case - */ - if( bconj ) - { - for(i=0; ix += alpha*vsrc->x; - vdst->y -= alpha*vsrc->y; - } - } - else - { - for(i=0; ix += alpha*vsrc->x; - vdst->y += alpha*vsrc->y; - } - } - } -} - -void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - double ax = alpha.x, ay = alpha.y; - if( bconj ) - { - for(i=0; ix += ax*vsrc->x+ay*vsrc->y; - vdst->y -= ax*vsrc->y-ay*vsrc->x; - } - } - else - { - for(i=0; ix += ax*vsrc->x-ay*vsrc->y; - vdst->y += ax*vsrc->y+ay*vsrc->x; - } - } - } - else - { - /* - * highly optimized case - */ - double ax = alpha.x, ay = alpha.y; - if( bconj ) - { - for(i=0; ix += ax*vsrc->x+ay*vsrc->y; - vdst->y -= ax*vsrc->y-ay*vsrc->x; - } - } - else - { - for(i=0; ix += ax*vsrc->x-ay*vsrc->y; - vdst->y += ax*vsrc->y+ay*vsrc->x; - } - } - } -} - -void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) -{ - ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - /* - * general unoptimized case - */ - if( bconj ) - { - for(i=0; ix -= vsrc->x; - vdst->y += vsrc->y; - } - } - else - { - for(i=0; ix -= vsrc->x; - vdst->y -= vsrc->y; - } - } - } - else - { - /* - * highly optimized case - */ - if( bconj ) - { - for(i=0; ix -= vsrc->x; - vdst->y += vsrc->y; - } - } - else - { - for(i=0; ix -= vsrc->x; - vdst->y -= vsrc->y; - } - } - } -} - -void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) -{ - ae_v_caddd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); -} - -void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) -{ - alpha.x = -alpha.x; - alpha.y = -alpha.y; - ae_v_caddc(vdst, stride_dst, vsrc, stride_src, conj_src, n, alpha); -} - -void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) -{ - ae_int_t i; - if( stride_dst!=1 ) - { - /* - * general unoptimized case - */ - for(i=0; ix *= alpha; - vdst->y *= alpha; - } - } - else - { - /* - * optimized case - */ - for(i=0; ix *= alpha; - vdst->y *= alpha; - } - } -} - -void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha) -{ - ae_int_t i; - if( stride_dst!=1 ) - { - /* - * general unoptimized case - */ - double ax = alpha.x, ay = alpha.y; - for(i=0; ix, dsty = vdst->y; - vdst->x = ax*dstx-ay*dsty; - vdst->y = ax*dsty+ay*dstx; - } - } - else - { - /* - * highly optimized case - */ - double ax = alpha.x, ay = alpha.y; - for(i=0; ix, dsty = vdst->y; - vdst->x = ax*dstx-ay*dsty; - vdst->y = ax*dsty+ay*dstx; - } - } -} - -/************************************************************************ -Real BLAS operations -************************************************************************/ -double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n) -{ - double result = 0; - ae_int_t i; - if( stride0!=1 || stride1!=1 ) - { - /* - * slow general code - */ - for(i=0; iba, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ia, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ra, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ca, 0, DT_COMPLEX, _state, make_automatic) ) - return ae_false; - return ae_true; -} - -ae_bool _rcommstate_init_copy(rcommstate* dst, rcommstate* src, ae_state *_state, ae_bool make_automatic) -{ - if( !ae_vector_init_copy(&dst->ba, &src->ba, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ia, &src->ia, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ra, &src->ra, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ca, &src->ca, _state, make_automatic) ) - return ae_false; - dst->stage = src->stage; - return ae_true; -} - -void _rcommstate_clear(rcommstate* p) -{ - ae_vector_clear(&p->ba); - ae_vector_clear(&p->ia); - ae_vector_clear(&p->ra); - ae_vector_clear(&p->ca); -} - -void _rcommstate_destroy(rcommstate* p) -{ - _rcommstate_clear(p); -} - -#ifdef AE_DEBUG4WINDOWS -int _tickcount() -{ - return GetTickCount(); -} -#endif - -#ifdef AE_DEBUG4POSIX -#include -int _tickcount() -{ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) ) - return 0; - return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0; -} -#endif - -#ifdef AE_DEBUGRNG -void ae_set_seed(ae_int_t s0, ae_int_t s1) -{ - ae_int_t hqrnd_hqrndm1 = 2147483563; - ae_int_t hqrnd_hqrndm2 = 2147483399; - - while(s0<1) - s0 += hqrnd_hqrndm1-1; - while(s0>hqrnd_hqrndm1-1) - s0 -= hqrnd_hqrndm1-1; - - while(s1<1) - s1 += hqrnd_hqrndm2-1; - while(s1>hqrnd_hqrndm2-1) - s1 -= hqrnd_hqrndm2-1; - - _debug_rng_s0 = s0; - _debug_rng_s1 = s1; -} - -void ae_get_seed(ae_int_t *s0, ae_int_t *s1) -{ - *s0 = _debug_rng_s0; - *s1 = _debug_rng_s1; -} -#endif - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ RELATED FUNCTIONALITY -// -///////////////////////////////////////////////////////////////////////// -/******************************************************************** -Internal forwards -********************************************************************/ -namespace alglib -{ - double get_aenv_nan(); - double get_aenv_posinf(); - double get_aenv_neginf(); - ae_int_t my_stricmp(const char *s1, const char *s2); - char* filter_spaces(const char *s); - void str_vector_create(const char *src, bool match_head_only, std::vector *p_vec); - void str_matrix_create(const char *src, std::vector< std::vector > *p_mat); - - ae_bool parse_bool_delim(const char *s, const char *delim); - ae_int_t parse_int_delim(const char *s, const char *delim); - bool _parse_real_delim(const char *s, const char *delim, double *result, const char **new_s); - double parse_real_delim(const char *s, const char *delim); - alglib::complex parse_complex_delim(const char *s, const char *delim); - - std::string arraytostring(const bool *ptr, ae_int_t n); - std::string arraytostring(const ae_int_t *ptr, ae_int_t n); - std::string arraytostring(const double *ptr, ae_int_t n, int dps); - std::string arraytostring(const alglib::complex *ptr, ae_int_t n, int dps); -} - -/******************************************************************** -Global and local constants -********************************************************************/ -const double alglib::machineepsilon = 5E-16; -const double alglib::maxrealnumber = 1E300; -const double alglib::minrealnumber = 1E-300; -const alglib::ae_int_t alglib::endianness = alglib_impl::ae_get_endianness(); -const double alglib::fp_nan = alglib::get_aenv_nan(); -const double alglib::fp_posinf = alglib::get_aenv_posinf(); -const double alglib::fp_neginf = alglib::get_aenv_neginf(); - - -/******************************************************************** -ap_error -********************************************************************/ -alglib::ap_error::ap_error() -{ -} - -alglib::ap_error::ap_error(const char *s) -{ - msg = s; -} - -void alglib::ap_error::make_assertion(bool bClause) -{ - if(!bClause) - throw ap_error(); -} - -void alglib::ap_error::make_assertion(bool bClause, const char *msg) -{ - if(!bClause) - throw ap_error(msg); -} - - -/******************************************************************** -Complex number with double precision. -********************************************************************/ -alglib::complex::complex():x(0.0),y(0.0) -{ -} - -alglib::complex::complex(const double &_x):x(_x),y(0.0) -{ -} - -alglib::complex::complex(const double &_x, const double &_y):x(_x),y(_y) -{ -} - -alglib::complex::complex(const alglib::complex &z):x(z.x),y(z.y) -{ -} - -alglib::complex& alglib::complex::operator= (const double& v) -{ - x = v; - y = 0.0; - return *this; -} - -alglib::complex& alglib::complex::operator+=(const double& v) -{ - x += v; - return *this; -} - -alglib::complex& alglib::complex::operator-=(const double& v) -{ - x -= v; - return *this; -} - -alglib::complex& alglib::complex::operator*=(const double& v) -{ - x *= v; - y *= v; - return *this; -} - -alglib::complex& alglib::complex::operator/=(const double& v) -{ - x /= v; - y /= v; - return *this; -} - -alglib::complex& alglib::complex::operator= (const alglib::complex& z) -{ - x = z.x; - y = z.y; - return *this; -} - -alglib::complex& alglib::complex::operator+=(const alglib::complex& z) -{ - x += z.x; - y += z.y; - return *this; -} - -alglib::complex& alglib::complex::operator-=(const alglib::complex& z) -{ - x -= z.x; - y -= z.y; - return *this; -} - -alglib::complex& alglib::complex::operator*=(const alglib::complex& z) -{ - double t = x*z.x-y*z.y; - y = x*z.y+y*z.x; - x = t; - return *this; -} - -alglib::complex& alglib::complex::operator/=(const alglib::complex& z) -{ - alglib::complex result; - double e; - double f; - if( fabs(z.y)=0 ? _dps : -_dps; - if( dps<=0 || dps>=20 ) - throw ap_error("complex::tostring(): incorrect dps"); - - // handle IEEE special quantities - if( fp_isnan(x) || fp_isnan(y) ) - return "NAN"; - if( fp_isinf(x) || fp_isinf(y) ) - return "INF"; - - // generate mask - if( sprintf(mask, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask) ) - throw ap_error("complex::tostring(): buffer overflow"); - - // print |x|, |y| and zero with same mask and compare - if( sprintf(buf_x, mask, (double)(fabs(x)))>=(int)sizeof(buf_x) ) - throw ap_error("complex::tostring(): buffer overflow"); - if( sprintf(buf_y, mask, (double)(fabs(y)))>=(int)sizeof(buf_y) ) - throw ap_error("complex::tostring(): buffer overflow"); - if( sprintf(buf_zero, mask, (double)0)>=(int)sizeof(buf_zero) ) - throw ap_error("complex::tostring(): buffer overflow"); - - // different zero/nonzero patterns - if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)!=0 ) - return std::string(x>0 ? "" : "-")+buf_x+(y>0 ? "+" : "-")+buf_y+"i"; - if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)==0 ) - return std::string(x>0 ? "" : "-")+buf_x; - if( strcmp(buf_x,buf_zero)==0 && strcmp(buf_y,buf_zero)!=0 ) - return std::string(y>0 ? "" : "-")+buf_y+"i"; - return std::string("0"); -} - -const bool alglib::operator==(const alglib::complex& lhs, const alglib::complex& rhs) -{ - volatile double x1 = lhs.x; - volatile double x2 = rhs.x; - volatile double y1 = lhs.y; - volatile double y2 = rhs.y; - return x1==x2 && y1==y2; -} - -const bool alglib::operator!=(const alglib::complex& lhs, const alglib::complex& rhs) -{ return !(lhs==rhs); } - -const alglib::complex alglib::operator+(const alglib::complex& lhs) -{ return lhs; } - -const alglib::complex alglib::operator-(const alglib::complex& lhs) -{ return alglib::complex(-lhs.x, -lhs.y); } - -const alglib::complex alglib::operator+(const alglib::complex& lhs, const alglib::complex& rhs) -{ alglib::complex r = lhs; r += rhs; return r; } - -const alglib::complex alglib::operator+(const alglib::complex& lhs, const double& rhs) -{ alglib::complex r = lhs; r += rhs; return r; } - -const alglib::complex alglib::operator+(const double& lhs, const alglib::complex& rhs) -{ alglib::complex r = rhs; r += lhs; return r; } - -const alglib::complex alglib::operator-(const alglib::complex& lhs, const alglib::complex& rhs) -{ alglib::complex r = lhs; r -= rhs; return r; } - -const alglib::complex alglib::operator-(const alglib::complex& lhs, const double& rhs) -{ alglib::complex r = lhs; r -= rhs; return r; } - -const alglib::complex alglib::operator-(const double& lhs, const alglib::complex& rhs) -{ alglib::complex r = lhs; r -= rhs; return r; } - -const alglib::complex alglib::operator*(const alglib::complex& lhs, const alglib::complex& rhs) -{ return alglib::complex(lhs.x*rhs.x - lhs.y*rhs.y, lhs.x*rhs.y + lhs.y*rhs.x); } - -const alglib::complex alglib::operator*(const alglib::complex& lhs, const double& rhs) -{ return alglib::complex(lhs.x*rhs, lhs.y*rhs); } - -const alglib::complex alglib::operator*(const double& lhs, const alglib::complex& rhs) -{ return alglib::complex(lhs*rhs.x, lhs*rhs.y); } - -const alglib::complex alglib::operator/(const alglib::complex& lhs, const alglib::complex& rhs) -{ - alglib::complex result; - double e; - double f; - if( fabs(rhs.y)yabs ? xabs : yabs; - v = xabsx; - v0y = -v0->y; - v1x = v1->x; - v1y = -v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( !bconj0 && bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = v0->y; - v1x = v1->x; - v1y = -v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( bconj0 && !bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = -v0->y; - v1x = v1->x; - v1y = v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - if( !bconj0 && !bconj1 ) - { - double v0x, v0y, v1x, v1y; - for(i=0; ix; - v0y = v0->y; - v1x = v1->x; - v1y = v1->y; - rx += v0x*v1x-v0y*v1y; - ry += v0x*v1y+v0y*v1x; - } - } - return alglib::complex(rx,ry); -} - -alglib::complex alglib::vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N) -{ - return vdotproduct(v1, 1, "N", v2, 1, "N", N); -} - -void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n) -{ - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix = vsrc->x; - vdst->y = -vsrc->y; - } - } - else - { - for(i=0; ix = vsrc->x; - vdst->y = -vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = -vsrc->y; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - for(i=0; ix = -vsrc->x; - vdst->y = vsrc->y; - } - } - else - { - for(i=0; ix = -vsrc->x; - vdst->y = -vsrc->y; - } - } - } -} - -void alglib::vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) -{ - vmoveneg(vdst, 1, vsrc, 1, "N", N); -} - -void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha) -{ - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix = alpha*vsrc->x; - vdst->y = -alpha*vsrc->y; - } - } - else - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = alpha*vsrc->y; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = -alpha*vsrc->y; - } - } - else - { - for(i=0; ix = alpha*vsrc->x; - vdst->y = alpha*vsrc->y; - } - } - } -} - -void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) -{ - vmove(vdst, 1, vsrc, 1, "N", N, alpha); -} - -void alglib::vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) -{ - bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - if( bconj ) - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x+ay*vsrc->y; - vdst->y = -ax*vsrc->y+ay*vsrc->x; - } - } - else - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x-ay*vsrc->y; - vdst->y = ax*vsrc->y+ay*vsrc->x; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x+ay*vsrc->y; - vdst->y = -ax*vsrc->y+ay*vsrc->x; - } - } - else - { - double ax = alpha.x, ay = alpha.y; - for(i=0; ix = ax*vsrc->x-ay*vsrc->y; - vdst->y = ax*vsrc->y+ay*vsrc->x; - } - } - } -} - -void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) -{ - vmove(vdst, 1, vsrc, 1, "N", N, alpha); -} - -void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) -{ - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix += vsrc->x; - vdst->y -= vsrc->y; - } - } - else - { - for(i=0; ix += vsrc->x; - vdst->y += vsrc->y; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - for(i=0; ix += vsrc->x; - vdst->y -= vsrc->y; - } - } - else - { - for(i=0; ix += vsrc->x; - vdst->y += vsrc->y; - } - } - } -} - -void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) -{ - vadd(vdst, 1, vsrc, 1, "N", N); -} - -void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) -{ - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix += alpha*vsrc->x; - vdst->y -= alpha*vsrc->y; - } - } - else - { - for(i=0; ix += alpha*vsrc->x; - vdst->y += alpha*vsrc->y; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - for(i=0; ix += alpha*vsrc->x; - vdst->y -= alpha*vsrc->y; - } - } - else - { - for(i=0; ix += alpha*vsrc->x; - vdst->y += alpha*vsrc->y; - } - } - } -} - -void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) -{ - vadd(vdst, 1, vsrc, 1, "N", N, alpha); -} - -void alglib::vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) -{ - bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - double ax = alpha.x, ay = alpha.y; - if( bconj ) - { - for(i=0; ix += ax*vsrc->x+ay*vsrc->y; - vdst->y -= ax*vsrc->y-ay*vsrc->x; - } - } - else - { - for(i=0; ix += ax*vsrc->x-ay*vsrc->y; - vdst->y += ax*vsrc->y+ay*vsrc->x; - } - } - } - else - { - // - // optimized case - // - double ax = alpha.x, ay = alpha.y; - if( bconj ) - { - for(i=0; ix += ax*vsrc->x+ay*vsrc->y; - vdst->y -= ax*vsrc->y-ay*vsrc->x; - } - } - else - { - for(i=0; ix += ax*vsrc->x-ay*vsrc->y; - vdst->y += ax*vsrc->y+ay*vsrc->x; - } - } - } -} - -void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) -{ - vadd(vdst, 1, vsrc, 1, "N", N, alpha); -} - -void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) -{ - ae_int_t i; - if( stride_dst!=1 || stride_src!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix -= vsrc->x; - vdst->y += vsrc->y; - } - } - else - { - for(i=0; ix -= vsrc->x; - vdst->y -= vsrc->y; - } - } - } - else - { - // - // optimized case - // - if( bconj ) - { - for(i=0; ix -= vsrc->x; - vdst->y += vsrc->y; - } - } - else - { - for(i=0; ix -= vsrc->x; - vdst->y -= vsrc->y; - } - } - } -} - -void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) -{ - vsub(vdst, 1, vsrc, 1, "N", N); -} - -void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) -{ - vadd(vdst, stride_dst, vsrc, stride_src, n, -alpha); -} - -void alglib::vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha) -{ - vadd(vdst, 1, vsrc, 1, N, -alpha); -} - -void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) -{ - vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); -} - -void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, double alpha) -{ - vadd(vdst, 1, vsrc, 1, "N", n, -alpha); -} - -void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) -{ - vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); -} - -void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, alglib::complex alpha) -{ - vadd(vdst, 1, vsrc, 1, "N", n, -alpha); -} -void alglib::vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) -{ - ae_int_t i; - if( stride_dst!=1 ) - { - // - // general unoptimized case - // - for(i=0; ix *= alpha; - vdst->y *= alpha; - } - } - else - { - // - // optimized case - // - for(i=0; ix *= alpha; - vdst->y *= alpha; - } - } -} - -void alglib::vmul(alglib::complex *vdst, ae_int_t N, double alpha) -{ - vmul(vdst, 1, N, alpha); -} - -void alglib::vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha) -{ - ae_int_t i; - if( stride_dst!=1 ) - { - // - // general unoptimized case - // - double ax = alpha.x, ay = alpha.y; - for(i=0; ix, dsty = vdst->y; - vdst->x = ax*dstx-ay*dsty; - vdst->y = ax*dsty+ay*dstx; - } - } - else - { - // - // optimized case - // - double ax = alpha.x, ay = alpha.y; - for(i=0; ix, dsty = vdst->y; - vdst->x = ax*dstx-ay*dsty; - vdst->y = ax*dsty+ay*dstx; - } - } -} - -void alglib::vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha) -{ - vmul(vdst, 1, N, alpha); -} - - -/******************************************************************** -Matrices and vectors -********************************************************************/ -alglib::ae_vector_wrapper::ae_vector_wrapper() -{ - p_vec = NULL; -} - -alglib::ae_vector_wrapper::~ae_vector_wrapper() -{ - if( p_vec==&vec ) - ae_vector_clear(p_vec); -} - -void alglib::ae_vector_wrapper::setlength(ae_int_t iLen) -{ - if( p_vec==NULL ) - throw alglib::ap_error("ALGLIB: setlength() error, p_vec==NULL (array was not correctly initialized)"); - if( p_vec!=&vec ) - throw alglib::ap_error("ALGLIB: setlength() error, p_vec!=&vec (attempt to resize frozen array)"); - if( !ae_vector_set_length(p_vec, iLen, NULL) ) - throw alglib::ap_error("ALGLIB: malloc error"); -} - -alglib::ae_int_t alglib::ae_vector_wrapper::length() const -{ - if( p_vec==NULL ) - return 0; - return p_vec->cnt; -} - -void alglib::ae_vector_wrapper::attach_to(alglib_impl::ae_vector *ptr) -{ - if( ptr==&vec ) - throw alglib::ap_error("ALGLIB: attempt to attach vector to itself"); - if( p_vec==&vec ) - ae_vector_clear(p_vec); - p_vec = ptr; -} - -void alglib::ae_vector_wrapper::allocate_own(ae_int_t size, alglib_impl::ae_datatype datatype) -{ - if( p_vec==&vec ) - ae_vector_clear(p_vec); - p_vec = &vec; - if( !ae_vector_init(p_vec, size, datatype, NULL, false) ) - throw alglib::ap_error("ALGLIB: malloc error"); -} - -const alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() const -{ - return p_vec; -} - -alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() -{ - return p_vec; -} - -void alglib::ae_vector_wrapper::create(const alglib::ae_vector_wrapper &rhs) -{ - if( rhs.p_vec!=NULL ) - { - p_vec = &vec; - if( !ae_vector_init_copy(p_vec, rhs.p_vec, NULL, ae_false) ) - throw alglib::ap_error("ALGLIB: malloc error!"); - } - else - p_vec = NULL; -} - -void alglib::ae_vector_wrapper::create(const char *s, alglib_impl::ae_datatype datatype) -{ - std::vector svec; - size_t i; - char *p = filter_spaces(s); - try - { - str_vector_create(p, true, &svec); - allocate_own((ae_int_t)(svec.size()), datatype); - for(i=0; iptr.p_bool[i] = parse_bool_delim(svec[i],",]"); - if( datatype==alglib_impl::DT_INT ) - p_vec->ptr.p_int[i] = parse_int_delim(svec[i],",]"); - if( datatype==alglib_impl::DT_REAL ) - p_vec->ptr.p_double[i] = parse_real_delim(svec[i],",]"); - if( datatype==alglib_impl::DT_COMPLEX ) - { - alglib::complex t = parse_complex_delim(svec[i],",]"); - p_vec->ptr.p_complex[i].x = t.x; - p_vec->ptr.p_complex[i].y = t.y; - } - } - alglib_impl::ae_free(p); - } - catch(...) - { - alglib_impl::ae_free(p); - throw; - } -} - -void alglib::ae_vector_wrapper::assign(const alglib::ae_vector_wrapper &rhs) -{ - if( this==&rhs ) - return; - if( p_vec==&vec || p_vec==NULL ) - { - // - // Assignment to non-proxy object - // - ae_vector_clear(p_vec); - if( rhs.p_vec!=NULL ) - { - p_vec = &vec; - if( !ae_vector_init_copy(p_vec, rhs.p_vec, NULL, ae_false) ) - throw alglib::ap_error("ALGLIB: malloc error!"); - } - else - p_vec = NULL; - } - else - { - // - // Assignment to proxy object - // - if( rhs.p_vec==NULL ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes do not match)"); - if( rhs.p_vec->datatype!=p_vec->datatype ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (types do not match)"); - if( rhs.p_vec->cnt!=p_vec->cnt ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes do not match)"); - memcpy(p_vec->ptr.p_ptr, rhs.p_vec->ptr.p_ptr, p_vec->cnt*alglib_impl::ae_sizeof(p_vec->datatype)); - } -} - -alglib::boolean_1d_array::boolean_1d_array() -{ - allocate_own(0, alglib_impl::DT_BOOL); -} - -alglib::boolean_1d_array::boolean_1d_array(const char *s) -{ - create(s, alglib_impl::DT_BOOL); -} - -alglib::boolean_1d_array::boolean_1d_array(const alglib::boolean_1d_array &rhs) -{ - create(rhs); -} - -alglib::boolean_1d_array::boolean_1d_array(alglib_impl::ae_vector *p) -{ - p_vec = NULL; - attach_to(p); -} - -const alglib::boolean_1d_array& alglib::boolean_1d_array::operator=(const alglib::boolean_1d_array &rhs) -{ - assign(rhs); - return *this; -} - -alglib::boolean_1d_array::~boolean_1d_array() -{ -} - -const ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) const -{ - return p_vec->ptr.p_bool[i]; -} - -ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) -{ - return p_vec->ptr.p_bool[i]; -} - -const ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) const -{ - return p_vec->ptr.p_bool[i]; -} - -ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) -{ - return p_vec->ptr.p_bool[i]; -} - -void alglib::boolean_1d_array::setcontent(ae_int_t iLen, const bool *pContent ) -{ - ae_int_t i; - setlength(iLen); - for(i=0; iptr.p_bool[i] = pContent[i]; -} - -ae_bool* alglib::boolean_1d_array::getcontent() -{ - return p_vec->ptr.p_bool; -} - -const ae_bool* alglib::boolean_1d_array::getcontent() const -{ - return p_vec->ptr.p_bool; -} - -std::string alglib::boolean_1d_array::tostring() const -{ - if( length()==0 ) - return "[]"; - return arraytostring(&(operator()(0)), length()); -} - -alglib::integer_1d_array::integer_1d_array() -{ - allocate_own(0, alglib_impl::DT_INT); -} - -alglib::integer_1d_array::integer_1d_array(alglib_impl::ae_vector *p) -{ - p_vec = NULL; - attach_to(p); -} - -alglib::integer_1d_array::integer_1d_array(const char *s) -{ - create(s, alglib_impl::DT_INT); -} - -alglib::integer_1d_array::integer_1d_array(const alglib::integer_1d_array &rhs) -{ - create(rhs); -} - -const alglib::integer_1d_array& alglib::integer_1d_array::operator=(const alglib::integer_1d_array &rhs) -{ - assign(rhs); - return *this; -} - -alglib::integer_1d_array::~integer_1d_array() -{ -} - -const alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) const -{ - return p_vec->ptr.p_int[i]; -} - -alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) -{ - return p_vec->ptr.p_int[i]; -} - -const alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) const -{ - return p_vec->ptr.p_int[i]; -} - -alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) -{ - return p_vec->ptr.p_int[i]; -} - -void alglib::integer_1d_array::setcontent(ae_int_t iLen, const ae_int_t *pContent ) -{ - ae_int_t i; - setlength(iLen); - for(i=0; iptr.p_int[i] = pContent[i]; -} - -alglib::ae_int_t* alglib::integer_1d_array::getcontent() -{ - return p_vec->ptr.p_int; -} - -const alglib::ae_int_t* alglib::integer_1d_array::getcontent() const -{ - return p_vec->ptr.p_int; -} - -std::string alglib::integer_1d_array::tostring() const -{ - if( length()==0 ) - return "[]"; - return arraytostring(&operator()(0), length()); -} - -alglib::real_1d_array::real_1d_array() -{ - allocate_own(0, alglib_impl::DT_REAL); -} - -alglib::real_1d_array::real_1d_array(alglib_impl::ae_vector *p) -{ - p_vec = NULL; - attach_to(p); -} - -alglib::real_1d_array::real_1d_array(const char *s) -{ - create(s, alglib_impl::DT_REAL); -} - -alglib::real_1d_array::real_1d_array(const alglib::real_1d_array &rhs) -{ - create(rhs); -} - -const alglib::real_1d_array& alglib::real_1d_array::operator=(const alglib::real_1d_array &rhs) -{ - assign(rhs); - return *this; -} - -alglib::real_1d_array::~real_1d_array() -{ -} - -const double& alglib::real_1d_array::operator()(ae_int_t i) const -{ - return p_vec->ptr.p_double[i]; -} - -double& alglib::real_1d_array::operator()(ae_int_t i) -{ - return p_vec->ptr.p_double[i]; -} - -const double& alglib::real_1d_array::operator[](ae_int_t i) const -{ - return p_vec->ptr.p_double[i]; -} - -double& alglib::real_1d_array::operator[](ae_int_t i) -{ - return p_vec->ptr.p_double[i]; -} - -void alglib::real_1d_array::setcontent(ae_int_t iLen, const double *pContent ) -{ - ae_int_t i; - setlength(iLen); - for(i=0; iptr.p_double[i] = pContent[i]; -} - -double* alglib::real_1d_array::getcontent() -{ - return p_vec->ptr.p_double; -} - -const double* alglib::real_1d_array::getcontent() const -{ - return p_vec->ptr.p_double; -} - -std::string alglib::real_1d_array::tostring(int dps) const -{ - if( length()==0 ) - return "[]"; - return arraytostring(&operator()(0), length(), dps); -} - -alglib::complex_1d_array::complex_1d_array() -{ - allocate_own(0, alglib_impl::DT_COMPLEX); -} - -alglib::complex_1d_array::complex_1d_array(alglib_impl::ae_vector *p) -{ - p_vec = NULL; - attach_to(p); -} - -alglib::complex_1d_array::complex_1d_array(const char *s) -{ - create(s, alglib_impl::DT_COMPLEX); -} - -alglib::complex_1d_array::complex_1d_array(const alglib::complex_1d_array &rhs) -{ - create(rhs); -} - -const alglib::complex_1d_array& alglib::complex_1d_array::operator=(const alglib::complex_1d_array &rhs) -{ - assign(rhs); - return *this; -} - -alglib::complex_1d_array::~complex_1d_array() -{ -} - -const alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) const -{ - return *((const alglib::complex*)(p_vec->ptr.p_complex+i)); -} - -alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) -{ - return *((alglib::complex*)(p_vec->ptr.p_complex+i)); -} - -const alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) const -{ - return *((const alglib::complex*)(p_vec->ptr.p_complex+i)); -} - -alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) -{ - return *((alglib::complex*)(p_vec->ptr.p_complex+i)); -} - -void alglib::complex_1d_array::setcontent(ae_int_t iLen, const alglib::complex *pContent ) -{ - ae_int_t i; - setlength(iLen); - for(i=0; iptr.p_complex[i].x = pContent[i].x; - p_vec->ptr.p_complex[i].y = pContent[i].y; - } -} - - alglib::complex* alglib::complex_1d_array::getcontent() -{ - return (alglib::complex*)p_vec->ptr.p_complex; -} - -const alglib::complex* alglib::complex_1d_array::getcontent() const -{ - return (const alglib::complex*)p_vec->ptr.p_complex; -} - -std::string alglib::complex_1d_array::tostring(int dps) const -{ - if( length()==0 ) - return "[]"; - return arraytostring(&operator()(0), length(), dps); -} - -alglib::ae_matrix_wrapper::ae_matrix_wrapper() -{ - p_mat = NULL; -} - -alglib::ae_matrix_wrapper::~ae_matrix_wrapper() -{ - if( p_mat==&mat ) - ae_matrix_clear(p_mat); -} - -const alglib::ae_matrix_wrapper& alglib::ae_matrix_wrapper::operator=(const alglib::ae_matrix_wrapper &rhs) -{ - assign(rhs); - return *this; -} - -void alglib::ae_matrix_wrapper::create(const ae_matrix_wrapper &rhs) -{ - if( rhs.p_mat!=NULL ) - { - p_mat = &mat; - if( !ae_matrix_init_copy(p_mat, rhs.p_mat, NULL, ae_false) ) - throw alglib::ap_error("ALGLIB: malloc error!"); - } - else - p_mat = NULL; -} - -void alglib::ae_matrix_wrapper::create(const char *s, alglib_impl::ae_datatype datatype) -{ - std::vector< std::vector > smat; - size_t i, j; - char *p = filter_spaces(s); - try - { - str_matrix_create(p, &smat); - if( smat.size()!=0 ) - { - allocate_own((ae_int_t)(smat.size()), (ae_int_t)(smat[0].size()), datatype); - for(i=0; iptr.pp_bool[i][j] = parse_bool_delim(smat[i][j],",]"); - if( datatype==alglib_impl::DT_INT ) - p_mat->ptr.pp_int[i][j] = parse_int_delim(smat[i][j],",]"); - if( datatype==alglib_impl::DT_REAL ) - p_mat->ptr.pp_double[i][j] = parse_real_delim(smat[i][j],",]"); - if( datatype==alglib_impl::DT_COMPLEX ) - { - alglib::complex t = parse_complex_delim(smat[i][j],",]"); - p_mat->ptr.pp_complex[i][j].x = t.x; - p_mat->ptr.pp_complex[i][j].y = t.y; - } - } - } - else - allocate_own(0, 0, datatype); - alglib_impl::ae_free(p); - } - catch(...) - { - alglib_impl::ae_free(p); - throw; - } -} - -void alglib::ae_matrix_wrapper::assign(const alglib::ae_matrix_wrapper &rhs) -{ - if( this==&rhs ) - return; - if( p_mat==&mat || p_mat==NULL ) - { - // - // Assignment to non-proxy object - // - ae_matrix_clear(p_mat); - if( rhs.p_mat!=NULL ) - { - p_mat = &mat; - if( !ae_matrix_init_copy(p_mat, rhs.p_mat, NULL, ae_false) ) - throw alglib::ap_error("ALGLIB: malloc error!"); - } - else - p_mat = NULL; - } - else - { - // - // Assignment to proxy object - // - ae_int_t i; - if( rhs.p_mat==NULL ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes do not match)"); - if( rhs.p_mat->datatype!=p_mat->datatype ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (types do not match)"); - if( rhs.p_mat->rows!=p_mat->rows ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes do not match)"); - if( rhs.p_mat->cols!=p_mat->cols ) - throw alglib::ap_error("ALGLIB: incorrect assignment to array (sizes do not match)"); - for(i=0; irows; i++) - memcpy(p_mat->ptr.pp_void[i], rhs.p_mat->ptr.pp_void[i], p_mat->cols*alglib_impl::ae_sizeof(p_mat->datatype)); - } -} - -void alglib::ae_matrix_wrapper::setlength(ae_int_t rows, ae_int_t cols) -{ - if( p_mat==NULL ) - throw alglib::ap_error("ALGLIB: setlength() error, p_mat==NULL (array was not correctly initialized)"); - if( p_mat!=&mat ) - throw alglib::ap_error("ALGLIB: setlength() error, p_mat!=&mat (attempt to resize frozen array)"); - if( !ae_matrix_set_length(p_mat, rows, cols, NULL) ) - throw alglib::ap_error("ALGLIB: malloc error"); -} - -alglib::ae_int_t alglib::ae_matrix_wrapper::rows() const -{ - if( p_mat==NULL ) - return 0; - return p_mat->rows; -} - -alglib::ae_int_t alglib::ae_matrix_wrapper::cols() const -{ - if( p_mat==NULL ) - return 0; - return p_mat->cols; -} - -bool alglib::ae_matrix_wrapper::isempty() const -{ - return rows()==0 || cols()==0; -} - -alglib::ae_int_t alglib::ae_matrix_wrapper::getstride() const -{ - if( p_mat==NULL ) - return 0; - return p_mat->stride; -} - -void alglib::ae_matrix_wrapper::attach_to(alglib_impl::ae_matrix *ptr) -{ - if( ptr==&mat ) - throw alglib::ap_error("ALGLIB: attempt to attach matrix to itself"); - if( p_mat==&mat ) - ae_matrix_clear(p_mat); - p_mat = ptr; -} - -void alglib::ae_matrix_wrapper::allocate_own(ae_int_t rows, ae_int_t cols, alglib_impl::ae_datatype datatype) -{ - if( p_mat==&mat ) - ae_matrix_clear(p_mat); - p_mat = &mat; - if( !ae_matrix_init(p_mat, rows, cols, datatype, NULL, false) ) - throw alglib::ap_error("ALGLIB: malloc error"); -} - -const alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() const -{ - return p_mat; -} - -alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() -{ - return p_mat; -} - -alglib::boolean_2d_array::boolean_2d_array() -{ - allocate_own(0, 0, alglib_impl::DT_BOOL); -} - -alglib::boolean_2d_array::boolean_2d_array(const alglib::boolean_2d_array &rhs) -{ - create(rhs); -} - -alglib::boolean_2d_array::boolean_2d_array(alglib_impl::ae_matrix *p) -{ - p_mat = NULL; - attach_to(p); -} - -alglib::boolean_2d_array::boolean_2d_array(const char *s) -{ - create(s, alglib_impl::DT_BOOL); -} - -alglib::boolean_2d_array::~boolean_2d_array() -{ -} - -const ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) const -{ - return p_mat->ptr.pp_bool[i][j]; -} - -ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) -{ - return p_mat->ptr.pp_bool[i][j]; -} - -const ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) const -{ - return p_mat->ptr.pp_bool[i]; -} - -ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) -{ - return p_mat->ptr.pp_bool[i]; -} - -void alglib::boolean_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ) -{ - ae_int_t i, j; - setlength(irows, icols); - for(i=0; iptr.pp_bool[i][j] = pContent[i*icols+j]; -} - -std::string alglib::boolean_2d_array::tostring() const -{ - std::string result; - ae_int_t i; - if( isempty() ) - return "[[]]"; - result = "["; - for(i=0; iptr.pp_int[i][j]; -} - -alglib::ae_int_t& alglib::integer_2d_array::operator()(ae_int_t i, ae_int_t j) -{ - return p_mat->ptr.pp_int[i][j]; -} - -const alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) const -{ - return p_mat->ptr.pp_int[i]; -} - -alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) -{ - return p_mat->ptr.pp_int[i]; -} - -void alglib::integer_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ) -{ - ae_int_t i, j; - setlength(irows, icols); - for(i=0; iptr.pp_int[i][j] = pContent[i*icols+j]; -} - -std::string alglib::integer_2d_array::tostring() const -{ - std::string result; - ae_int_t i; - if( isempty() ) - return "[[]]"; - result = "["; - for(i=0; iptr.pp_double[i][j]; -} - -double& alglib::real_2d_array::operator()(ae_int_t i, ae_int_t j) -{ - return p_mat->ptr.pp_double[i][j]; -} - -const double* alglib::real_2d_array::operator[](ae_int_t i) const -{ - return p_mat->ptr.pp_double[i]; -} - -double* alglib::real_2d_array::operator[](ae_int_t i) -{ - return p_mat->ptr.pp_double[i]; -} - -void alglib::real_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const double *pContent ) -{ - ae_int_t i, j; - setlength(irows, icols); - for(i=0; iptr.pp_double[i][j] = pContent[i*icols+j]; -} - -std::string alglib::real_2d_array::tostring(int dps) const -{ - std::string result; - ae_int_t i; - if( isempty() ) - return "[[]]"; - result = "["; - for(i=0; iptr.pp_complex[i]+j)); -} - -alglib::complex& alglib::complex_2d_array::operator()(ae_int_t i, ae_int_t j) -{ - return *((alglib::complex*)(p_mat->ptr.pp_complex[i]+j)); -} - -const alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) const -{ - return (const alglib::complex*)(p_mat->ptr.pp_complex[i]); -} - -alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) -{ - return (alglib::complex*)(p_mat->ptr.pp_complex[i]); -} - -void alglib::complex_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ) -{ - ae_int_t i, j; - setlength(irows, icols); - for(i=0; iptr.pp_complex[i][j].x = pContent[i*icols+j].x; - p_mat->ptr.pp_complex[i][j].y = pContent[i*icols+j].y; - } -} - -std::string alglib::complex_2d_array::tostring(int dps) const -{ - std::string result; - ae_int_t i; - if( isempty() ) - return "[[]]"; - result = "["; - for(i=0; ic2 ) - return +1; - } -} - -char* alglib::filter_spaces(const char *s) -{ - size_t i, n; - char *r; - char *r0; - n = strlen(s); - r = (char*)alglib_impl::ae_malloc(n+1, NULL); - if( r==NULL ) - throw ap_error("malloc error"); - for(i=0,r0=r; i<=n; i++,s++) - if( !isspace(*s) ) - { - *r0 = *s; - r0++; - } - return r; -} - -void alglib::str_vector_create(const char *src, bool match_head_only, std::vector *p_vec) -{ - // - // parse beginning of the string. - // try to handle "[]" string - // - p_vec->clear(); - if( *src!='[' ) - throw alglib::ap_error("Incorrect initializer for vector"); - src++; - if( *src==']' ) - return; - p_vec->push_back(src); - for(;;) - { - if( *src==0 ) - throw alglib::ap_error("Incorrect initializer for vector"); - if( *src==']' ) - { - if( src[1]==0 || !match_head_only) - return; - throw alglib::ap_error("Incorrect initializer for vector"); - } - if( *src==',' ) - { - p_vec->push_back(src+1); - src++; - continue; - } - src++; - } -} - -void alglib::str_matrix_create(const char *src, std::vector< std::vector > *p_mat) -{ - p_mat->clear(); - - // - // Try to handle "[[]]" string - // - if( strcmp(src, "[[]]")==0 ) - return; - - // - // Parse non-empty string - // - if( *src!='[' ) - throw alglib::ap_error("Incorrect initializer for matrix"); - src++; - for(;;) - { - p_mat->push_back(std::vector()); - str_vector_create(src, false, &p_mat->back()); - if( p_mat->back().size()==0 || p_mat->back().size()!=(*p_mat)[0].size() ) - throw alglib::ap_error("Incorrect initializer for matrix"); - src = strchr(src, ']'); - if( src==NULL ) - throw alglib::ap_error("Incorrect initializer for matrix"); - src++; - if( *src==',' ) - { - src++; - continue; - } - if( *src==']' ) - break; - throw alglib::ap_error("Incorrect initializer for matrix"); - } - src++; - if( *src!=0 ) - throw alglib::ap_error("Incorrect initializer for matrix"); -} - -ae_bool alglib::parse_bool_delim(const char *s, const char *delim) -{ - const char *p; - char buf[8]; - - // try to parse false - p = "false"; - memset(buf, 0, sizeof(buf)); - strncpy(buf, s, strlen(p)); - if( my_stricmp(buf, p)==0 ) - { - if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) - throw alglib::ap_error("Cannot parse value"); - return ae_false; - } - - // try to parse true - p = "true"; - memset(buf, 0, sizeof(buf)); - strncpy(buf, s, strlen(p)); - if( my_stricmp(buf, p)==0 ) - { - if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) - throw alglib::ap_error("Cannot parse value"); - return ae_true; - } - - // error - throw alglib::ap_error("Cannot parse value"); -} - -alglib::ae_int_t alglib::parse_int_delim(const char *s, const char *delim) -{ - const char *p; - long long_val; - volatile ae_int_t ae_val; - - p = s; - - // - // check string structure: - // * leading sign - // * at least one digit - // * delimiter - // - if( *s=='-' || *s=='+' ) - s++; - if( *s==0 || strchr("1234567890",*s)==NULL) - throw alglib::ap_error("Cannot parse value"); - while( *s!=0 && strchr("1234567890",*s)!=NULL ) - s++; - if( *s==0 || strchr(delim,*s)==NULL ) - throw alglib::ap_error("Cannot parse value"); - - // convert and ensure that value fits into ae_int_t - s = p; - long_val = atol(s); - ae_val = long_val; - if( ae_val!=long_val ) - throw alglib::ap_error("Cannot parse value"); - return ae_val; -} - -bool alglib::_parse_real_delim(const char *s, const char *delim, double *result, const char **new_s) -{ - const char *p; - char *t; - bool has_digits; - char buf[64]; - int isign; - lconv *loc; - - p = s; - - // - // check string structure and decide what to do - // - isign = 1; - if( *s=='-' || *s=='+' ) - { - isign = *s=='-' ? -1 : +1; - s++; - } - memset(buf, 0, sizeof(buf)); - strncpy(buf, s, 3); - if( my_stricmp(buf,"nan")!=0 && my_stricmp(buf,"inf")!=0 ) - { - // - // [sign] [ddd] [.] [ddd] [e|E[sign]ddd] - // - has_digits = false; - if( *s!=0 && strchr("1234567890",*s)!=NULL ) - { - has_digits = true; - while( *s!=0 && strchr("1234567890",*s)!=NULL ) - s++; - } - if( *s=='.' ) - s++; - if( *s!=0 && strchr("1234567890",*s)!=NULL ) - { - has_digits = true; - while( *s!=0 && strchr("1234567890",*s)!=NULL ) - s++; - } - if (!has_digits ) - return false; - if( *s=='e' || *s=='E' ) - { - s++; - if( *s=='-' || *s=='+' ) - s++; - if( *s==0 || strchr("1234567890",*s)==NULL ) - return false; - while( *s!=0 && strchr("1234567890",*s)!=NULL ) - s++; - } - if( *s==0 || strchr(delim,*s)==NULL ) - return false; - *new_s = s; - - // - // finite value conversion - // - if( *new_s-p>=(int)sizeof(buf) ) - return false; - strncpy(buf, p, (size_t)(*new_s-p)); - buf[*new_s-p] = 0; - loc = localeconv(); - t = strchr(buf,'.'); - if( t!=NULL ) - *t = *loc->decimal_point; - *result = atof(buf); - return true; - } - else - { - // - // check delimiter and update *new_s - // - s += 3; - if( *s==0 || strchr(delim,*s)==NULL ) - return false; - *new_s = s; - - // - // NAN, INF conversion - // - if( my_stricmp(buf,"nan")==0 ) - *result = fp_nan; - if( my_stricmp(buf,"inf")==0 ) - *result = isign>0 ? fp_posinf : fp_neginf; - return true; - } -} - -double alglib::parse_real_delim(const char *s, const char *delim) -{ - double result; - const char *new_s; - if( !_parse_real_delim(s, delim, &result, &new_s) ) - throw alglib::ap_error("Cannot parse value"); - return result; -} - -alglib::complex alglib::parse_complex_delim(const char *s, const char *delim) -{ - double d_result; - const char *new_s; - alglib::complex c_result; - - // parse as real value - if( _parse_real_delim(s, delim, &d_result, &new_s) ) - return d_result; - - // parse as "a+bi" or "a-bi" - if( _parse_real_delim(s, "+-", &c_result.x, &new_s) ) - { - s = new_s; - if( !_parse_real_delim(s, "i", &c_result.y, &new_s) ) - throw alglib::ap_error("Cannot parse value"); - s = new_s+1; - if( *s==0 || strchr(delim,*s)==NULL ) - throw alglib::ap_error("Cannot parse value"); - return c_result; - } - - // parse as complex value "bi+a" or "bi-a" - if( _parse_real_delim(s, "i", &c_result.y, &new_s) ) - { - s = new_s+1; - if( *s==0 ) - throw alglib::ap_error("Cannot parse value"); - if( strchr(delim,*s)!=NULL ) - { - c_result.x = 0; - return c_result; - } - if( strchr("+-",*s)!=NULL ) - { - if( !_parse_real_delim(s, delim, &c_result.x, &new_s) ) - throw alglib::ap_error("Cannot parse value"); - return c_result; - } - throw alglib::ap_error("Cannot parse value"); - } - - // error - throw alglib::ap_error("Cannot parse value"); -} - -std::string alglib::arraytostring(const bool *ptr, ae_int_t n) -{ - std::string result; - ae_int_t i; - result = "["; - for(i=0; i=(int)sizeof(buf) ) - throw ap_error("arraytostring(): buffer overflow"); - result += buf; - } - result += "]"; - return result; -} - -std::string alglib::arraytostring(const double *ptr, ae_int_t n, int _dps) -{ - std::string result; - ae_int_t i; - char buf[67]; - char mask1[64]; - char mask2[66]; - int dps = _dps>=0 ? _dps : -_dps; - result = "["; - if( sprintf(mask1, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask1) ) - throw ap_error("arraytostring(): buffer overflow"); - if( sprintf(mask2, ",%s", mask1)>=(int)sizeof(mask2) ) - throw ap_error("arraytostring(): buffer overflow"); - for(i=0; i=(int)sizeof(buf) ) - throw ap_error("arraytostring(): buffer overflow"); - } - else if( fp_isnan(ptr[i]) ) - strcpy(buf, i==0 ? "NAN" : ",NAN"); - else if( fp_isposinf(ptr[i]) ) - strcpy(buf, i==0 ? "+INF" : ",+INF"); - else if( fp_isneginf(ptr[i]) ) - strcpy(buf, i==0 ? "-INF" : ",-INF"); - result += buf; - } - result += "]"; - return result; -} - -std::string alglib::arraytostring(const alglib::complex *ptr, ae_int_t n, int dps) -{ - std::string result; - ae_int_t i; - result = "["; - for(i=0; i0 ) return 1; - if( x<0 ) return -1; - return 0; -} - -double alglib::randomreal() -{ -#ifdef AE_DEBUGRNG - return alglib_impl::ae_debugrng()/2147483563.0; -#else - int i1 = rand(); - int i2 = rand(); - double mx = (double)(RAND_MAX)+1.0; - volatile double tmp0 = i2/mx; - volatile double tmp1 = i1+tmp0; - return tmp1/mx; -#endif -} - -alglib::ae_int_t alglib::randominteger(alglib::ae_int_t maxv) -{ -#ifdef AE_DEBUGRNG - return ((alglib::ae_int_t)(alglib_impl::ae_debugrng()-1))%maxv; -#else - return ((alglib::ae_int_t)rand())%maxv; -#endif -} - -int alglib::round(double x) -{ return int(floor(x+0.5)); } - -int alglib::trunc(double x) -{ return int(x>0 ? floor(x) : ceil(x)); } - -int alglib::ifloor(double x) -{ return int(floor(x)); } - -int alglib::iceil(double x) -{ return int(ceil(x)); } - -double alglib::pi() -{ return 3.14159265358979323846; } - -double alglib::sqr(double x) -{ return x*x; } - -int alglib::maxint(int m1, int m2) -{ - return m1>m2 ? m1 : m2; -} - -int alglib::minint(int m1, int m2) -{ - return m1>m2 ? m2 : m1; -} - -double alglib::maxreal(double m1, double m2) -{ - return m1>m2 ? m1 : m2; -} - -double alglib::minreal(double m1, double m2) -{ - return m1>m2 ? m2 : m1; -} - -bool alglib::fp_eq(double v1, double v2) -{ - // IEEE-strict floating point comparison - volatile double x = v1; - volatile double y = v2; - return x==y; -} - -bool alglib::fp_neq(double v1, double v2) -{ - // IEEE-strict floating point comparison - return !fp_eq(v1,v2); -} - -bool alglib::fp_less(double v1, double v2) -{ - // IEEE-strict floating point comparison - volatile double x = v1; - volatile double y = v2; - return xy; -} - -bool alglib::fp_greater_eq(double v1, double v2) -{ - // IEEE-strict floating point comparison - volatile double x = v1; - volatile double y = v2; - return x>=y; -} - -bool alglib::fp_isnan(double x) -{ - return alglib_impl::ae_isnan_stateless(x,endianness); -} - -bool alglib::fp_isposinf(double x) -{ - return alglib_impl::ae_isposinf_stateless(x,endianness); -} - -bool alglib::fp_isneginf(double x) -{ - return alglib_impl::ae_isneginf_stateless(x,endianness); -} - -bool alglib::fp_isinf(double x) -{ - return alglib_impl::ae_isinf_stateless(x,endianness); -} - -bool alglib::fp_isfinite(double x) -{ - return alglib_impl::ae_isfinite_stateless(x,endianness); -} - -/******************************************************************** -Dataset functions -********************************************************************/ -/*bool alglib::readstrings(std::string file, std::list *pOutput) -{ - return readstrings(file, pOutput, ""); -} - -bool alglib::readstrings(std::string file, std::list *pOutput, std::string comment) -{ - std::string cmd, s; - FILE *f; - char buf[32768]; - char *str; - - f = fopen(file.c_str(), "rb"); - if( !f ) - return false; - s = ""; - pOutput->clear(); - while(str=fgets(buf, sizeof(buf), f)) - { - // TODO: read file by small chunks, combine in one large string - if( strlen(str)==0 ) - continue; - - // - // trim trailing newline chars - // - char *eos = str+strlen(str)-1; - if( *eos=='\n' ) - { - *eos = 0; - eos--; - } - if( *eos=='\r' ) - { - *eos = 0; - eos--; - } - s = str; - - // - // skip comments - // - if( comment.length()>0 ) - if( strncmp(s.c_str(), comment.c_str(), comment.length())==0 ) - { - s = ""; - continue; - } - - // - // read data - // - if( s.length()<1 ) - { - fclose(f); - throw alglib::ap_error("internal error in read_strings"); - } - pOutput->push_back(s); - } - fclose(f); - return true; -} - -void alglib::explodestring(std::string s, char sep, std::vector *pOutput) -{ - std::string tmp; - int i; - tmp = ""; - pOutput->clear(); - for(i=0; ipush_back(tmp); - tmp = ""; - } - if( tmp.length()!=0 ) - pOutput->push_back(tmp); -} - -std::string alglib::strtolower(const std::string &s) -{ - std::string r = s; - for(int i=0; i Lines; - std::vector Values, RowsArr, ColsArr, VarsArr, HeadArr; - std::list::iterator i; - std::string s; - int TrnFirst, TrnLast, ValFirst, ValLast, TstFirst, TstLast, LinesRead, j; - - // - // Read data - // - if( pdataset==NULL ) - return false; - if( !readstrings(file, &Lines, "//") ) - return false; - i = Lines.begin(); - *pdataset = dataset(); - - // - // Read header - // - if( i==Lines.end() ) - return false; - s = alglib::xtrim(*i); - alglib::explodestring(s, '#', &HeadArr); - if( HeadArr.size()!=2 ) - return false; - - // - // Rows info - // - alglib::explodestring(alglib::xtrim(HeadArr[0]), ' ', &RowsArr); - if( RowsArr.size()==0 || RowsArr.size()>3 ) - return false; - if( RowsArr.size()==1 ) - { - pdataset->totalsize = atol(RowsArr[0].c_str()); - pdataset->trnsize = pdataset->totalsize; - } - if( RowsArr.size()==2 ) - { - pdataset->trnsize = atol(RowsArr[0].c_str()); - pdataset->tstsize = atol(RowsArr[1].c_str()); - pdataset->totalsize = pdataset->trnsize + pdataset->tstsize; - } - if( RowsArr.size()==3 ) - { - pdataset->trnsize = atol(RowsArr[0].c_str()); - pdataset->valsize = atol(RowsArr[1].c_str()); - pdataset->tstsize = atol(RowsArr[2].c_str()); - pdataset->totalsize = pdataset->trnsize + pdataset->valsize + pdataset->tstsize; - } - if( pdataset->totalsize<=0 || pdataset->trnsize<0 || pdataset->valsize<0 || pdataset->tstsize<0 ) - return false; - TrnFirst = 0; - TrnLast = TrnFirst + pdataset->trnsize; - ValFirst = TrnLast; - ValLast = ValFirst + pdataset->valsize; - TstFirst = ValLast; - TstLast = TstFirst + pdataset->tstsize; - - // - // columns - // - alglib::explodestring(alglib::xtrim(HeadArr[1]), ' ', &ColsArr); - if( ColsArr.size()!=1 && ColsArr.size()!=4 ) - return false; - if( ColsArr.size()==1 ) - { - pdataset->nin = atoi(ColsArr[0].c_str()); - if( pdataset->nin<=0 ) - return false; - } - if( ColsArr.size()==4 ) - { - if( alglib::strtolower(ColsArr[0])!="reg" && alglib::strtolower(ColsArr[0])!="cls" ) - return false; - if( ColsArr[2]!="=>" ) - return false; - pdataset->nin = atol(ColsArr[1].c_str()); - if( pdataset->nin<1 ) - return false; - if( alglib::strtolower(ColsArr[0])=="reg" ) - { - pdataset->nclasses = 0; - pdataset->nout = atol(ColsArr[3].c_str()); - if( pdataset->nout<1 ) - return false; - } - else - { - pdataset->nclasses = atol(ColsArr[3].c_str()); - pdataset->nout = 1; - if( pdataset->nclasses<2 ) - return false; - } - } - - // - // initialize arrays - // - pdataset->all.setlength(pdataset->totalsize, pdataset->nin+pdataset->nout); - if( pdataset->trnsize>0 ) pdataset->trn.setlength(pdataset->trnsize, pdataset->nin+pdataset->nout); - if( pdataset->valsize>0 ) pdataset->val.setlength(pdataset->valsize, pdataset->nin+pdataset->nout); - if( pdataset->tstsize>0 ) pdataset->tst.setlength(pdataset->tstsize, pdataset->nin+pdataset->nout); - - // - // read data - // - for(LinesRead=0, i++; i!=Lines.end() && LinesReadtotalsize; i++, LinesRead++) - { - std::string sss = *i; - alglib::explodestring(alglib::xtrim(*i), ' ', &VarsArr); - if( VarsArr.size()!=pdataset->nin+pdataset->nout ) - return false; - int tmpc = alglib::round(atof(VarsArr[pdataset->nin+pdataset->nout-1].c_str())); - if( pdataset->nclasses>0 && (tmpc<0 || tmpc>=pdataset->nclasses) ) - return false; - for(j=0; jnin+pdataset->nout; j++) - { - pdataset->all(LinesRead,j) = atof(VarsArr[j].c_str()); - if( LinesRead>=TrnFirst && LinesReadtrn(LinesRead-TrnFirst,j) = atof(VarsArr[j].c_str()); - if( LinesRead>=ValFirst && LinesReadval(LinesRead-ValFirst,j) = atof(VarsArr[j].c_str()); - if( LinesRead>=TstFirst && LinesReadtst(LinesRead-TstFirst,j) = atof(VarsArr[j].c_str()); - } - } - if( LinesRead!=pdataset->totalsize ) - return false; - return true; -}*/ - -/* -previous variant -bool alglib::opendataset(std::string file, dataset *pdataset) -{ - std::list Lines; - std::vector Values; - std::list::iterator i; - int nCol, nRow, nSplitted; - int nColumns, nRows; - - // - // Read data - // - if( pdataset==NULL ) - return false; - if( !readstrings(file, &Lines, "//") ) - return false; - i = Lines.begin(); - *pdataset = dataset(); - - // - // Read columns info - // - if( i==Lines.end() ) - return false; - if( sscanf(i->c_str(), " columns = %d %d ", &pdataset->nin, &pdataset->nout)!=2 ) - return false; - if( pdataset->nin<=0 || pdataset->nout==0 || pdataset->nout==-1) - return false; - if( pdataset->nout<0 ) - { - pdataset->nclasses = -pdataset->nout; - pdataset->nout = 1; - pdataset->iscls = true; - } - else - { - pdataset->isreg = true; - } - nColumns = pdataset->nin+pdataset->nout; - i++; - - // - // Read rows info - // - if( i==Lines.end() ) - return false; - if( sscanf(i->c_str(), " rows = %d %d %d ", &pdataset->trnsize, &pdataset->valsize, &pdataset->tstsize)!=3 ) - return false; - if( (pdataset->trnsize<0) || (pdataset->valsize<0) || (pdataset->tstsize<0) ) - return false; - if( (pdataset->trnsize==0) && (pdataset->valsize==0) && (pdataset->tstsize==0) ) - return false; - nRows = pdataset->trnsize+pdataset->valsize+pdataset->tstsize; - pdataset->size = nRows; - if( Lines.size()!=nRows+2 ) - return false; - i++; - - // - // Read all cases - // - alglib::real_2d_array &arr = pdataset->all; - arr.setbounds(0, nRows-1, 0, nColumns-1); - for(nRow=0; nRowiscls && ((round(v)<0) || (round(v)>=pdataset->nclasses)) ) - return false; - if( (nCol==nColumns-1) && pdataset->iscls ) - arr(nRow, nCol) = round(v); - else - arr(nRow, nCol) = v; - } - i++; - } - - // - // Split to training, validation and test sets - // - if( pdataset->trnsize>0 ) - pdataset->trn.setbounds(0, pdataset->trnsize-1, 0, nColumns-1); - if( pdataset->valsize>0 ) - pdataset->val.setbounds(0, pdataset->valsize-1, 0, nColumns-1); - if( pdataset->tstsize>0 ) - pdataset->tst.setbounds(0, pdataset->tstsize-1, 0, nColumns-1); - nSplitted=0; - for(nRow=0; nRow<=pdataset->trnsize-1; nRow++, nSplitted++) - for(nCol=0; nCol<=nColumns-1; nCol++) - pdataset->trn(nRow,nCol) = arr(nSplitted,nCol); - for(nRow=0; nRow<=pdataset->valsize-1; nRow++, nSplitted++) - for(nCol=0; nCol<=nColumns-1; nCol++) - pdataset->val(nRow,nCol) = arr(nSplitted,nCol); - for(nRow=0; nRow<=pdataset->tstsize-1; nRow++, nSplitted++) - for(nCol=0; nCol<=nColumns-1; nCol++) - pdataset->tst(nRow,nCol) = arr(nSplitted,nCol); - return true; -}*/ - -alglib::ae_int_t alglib::vlen(ae_int_t n1, ae_int_t n2) -{ - return n2-n1+1; -} - - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTIONS CONTAINS OPTIMIZED LINEAR ALGEBRA CODE -// IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -#define alglib_simd_alignment 16 - -#define alglib_r_block 32 -#define alglib_half_r_block 16 -#define alglib_twice_r_block 64 - -#define alglib_c_block 24 -#define alglib_half_c_block 12 -#define alglib_twice_c_block 48 - - -/******************************************************************** -This subroutine calculates fast 32x32 real matrix-vector product: - - y := beta*y + alpha*A*x - -using either generic C code or native optimizations (if available) - -IMPORTANT: -* A must be stored in row-major order, - stride is alglib_r_block, - aligned on alglib_simd_alignment boundary -* X must be aligned on alglib_simd_alignment boundary -* Y may be non-aligned -********************************************************************/ -void _ialglib_mv_32(const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) -{ - ae_int_t i, k; - const double *pa0, *pa1, *pb; - - pa0 = a; - pa1 = a+alglib_r_block; - pb = x; - for(i=0; i<16; i++) - { - double v0 = 0, v1 = 0; - for(k=0; k<4; k++) - { - v0 += pa0[0]*pb[0]; - v1 += pa1[0]*pb[0]; - v0 += pa0[1]*pb[1]; - v1 += pa1[1]*pb[1]; - v0 += pa0[2]*pb[2]; - v1 += pa1[2]*pb[2]; - v0 += pa0[3]*pb[3]; - v1 += pa1[3]*pb[3]; - v0 += pa0[4]*pb[4]; - v1 += pa1[4]*pb[4]; - v0 += pa0[5]*pb[5]; - v1 += pa1[5]*pb[5]; - v0 += pa0[6]*pb[6]; - v1 += pa1[6]*pb[6]; - v0 += pa0[7]*pb[7]; - v1 += pa1[7]*pb[7]; - pa0 += 8; - pa1 += 8; - pb += 8; - } - y[0] = beta*y[0]+alpha*v0; - y[stride] = beta*y[stride]+alpha*v1; - - /* - * now we've processed rows I and I+1, - * pa0 and pa1 are pointing to rows I+1 and I+2. - * move to I+2 and I+3. - */ - pa0 += alglib_r_block; - pa1 += alglib_r_block; - pb = x; - y+=2*stride; - } -} - - -/************************************************************************* -This function calculates MxN real matrix-vector product: - - y := beta*y + alpha*A*x - -using generic C code. It calls _ialglib_mv_32 if both M=32 and N=32. - -If beta is zero, we do not use previous values of y (they are overwritten -by alpha*A*x without ever being read). If alpha is zero, no matrix-vector -product is calculated (only beta is updated); however, this update is not -efficient and this function should NOT be used for multiplication of -vector and scalar. - -IMPORTANT: -* 0<=M<=alglib_r_block, 0<=N<=alglib_r_block -* A must be stored in row-major order with stride equal to alglib_r_block -*************************************************************************/ -void _ialglib_rmv(ae_int_t m, ae_int_t n, const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) -{ - /* - * Handle special cases: - * - alpha is zero or n is zero - * - m is zero - */ - if( m==0 ) - return; - if( alpha==0.0 || n==0 ) - { - ae_int_t i; - if( beta==0.0 ) - { - for(i=0; ix-beta.y*cy->y)+(alpha.x*v0-alpha.y*v1); - double ty = (beta.x*cy->y+beta.y*cy->x)+(alpha.x*v1+alpha.y*v0); - cy->x = tx; - cy->y = ty; - cy+=stride; - } - else - { - double tx = (beta.x*dy[0]-beta.y*dy[1])+(alpha.x*v0-alpha.y*v1); - double ty = (beta.x*dy[1]+beta.y*dy[0])+(alpha.x*v1+alpha.y*v0); - dy[0] = tx; - dy[1] = ty; - dy += 2*stride; - } - parow += 2*alglib_c_block; - } -} - - -/************************************************************************* -This subroutine calculates fast MxN complex matrix-vector product: - - y := beta*y + alpha*A*x - -using generic C code, where A, x, y, alpha and beta are complex. - -If beta is zero, we do not use previous values of y (they are overwritten -by alpha*A*x without ever being read). However, when alpha is zero, we -still calculate A*x and multiply it by alpha (this distinction can be -important when A or x contain infinities/NANs). - -IMPORTANT: -* 0<=M<=alglib_c_block, 0<=N<=alglib_c_block -* A must be stored in row-major order, as sequence of double precision - pairs. Stride is alglib_c_block (it is measured in pairs of doubles, not - in doubles). -* Y may be referenced by cy (pointer to ae_complex) or - dy (pointer to array of double precision pair) depending on what type of - output you wish. Pass pointer to Y as one of these parameters, - AND SET OTHER PARAMETER TO NULL. -* both A and x must be aligned; y may be non-aligned. - -This function supports SSE2; it can be used when: -1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time) -2. ae_cpuid() result contains CPU_SSE2 (checked at run-time) - -If (1) is failed, this function will be undefined. If (2) is failed, call -to this function will probably crash your system. - -If you want to know whether it is safe to call it, you should check -results of ae_cpuid(). If CPU_SSE2 bit is set, this function is callable -and will do its work. -*************************************************************************/ -#if defined(AE_HAS_SSE2_INTRINSICS) -void _ialglib_cmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x, ae_complex *cy, double *dy, ae_int_t stride, ae_complex alpha, ae_complex beta) -{ - ae_int_t i, j, m2; - const double *pa0, *pa1, *parow, *pb; - __m128d vbeta, vbetax, vbetay; - __m128d valpha, valphax, valphay; - - m2 = m/2; - parow = a; - if( cy!=NULL ) - { - dy = (double*)cy; - cy = NULL; - } - vbeta = _mm_loadh_pd(_mm_load_sd(&beta.x),&beta.y); - vbetax = _mm_unpacklo_pd(vbeta,vbeta); - vbetay = _mm_unpackhi_pd(vbeta,vbeta); - valpha = _mm_loadh_pd(_mm_load_sd(&alpha.x),&alpha.y); - valphax = _mm_unpacklo_pd(valpha,valpha); - valphay = _mm_unpackhi_pd(valpha,valpha); - for(i=0; ix = 0.0; - p->y = 0.0; - } - } - else - { - for(i=0; ix = 0.0; - p->y = 0.0; - } - } -} - - -/******************************************************************** -This subroutine copies unaligned real vector -********************************************************************/ -void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb) -{ - ae_int_t i, n2; - if( stridea==1 && strideb==1 ) - { - n2 = n/2; - for(i=n2; i!=0; i--, a+=2, b+=2) - { - b[0] = a[0]; - b[1] = a[1]; - } - if( n%2!=0 ) - b[0] = a[0]; - } - else - { - for(i=0; ix; - b[1] = a->y; - } - } - else - { - for(i=0; ix; - b[1] = -a->y; - } - } -} - - -/******************************************************************** -This subroutine copies unaligned complex vector (passed as double*) - -1. strideb is stride measured in complex numbers, not doubles -2. conj may be "N" (no conj.) or "C" (conj.) -********************************************************************/ -void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj) -{ - ae_int_t i; - - /* - * more general case - */ - if( conj[0]=='N' || conj[0]=='n' ) - { - for(i=0; ix; - pdst[1] = psrc->y; - } - } - if( op==1 ) - { - for(i=0,psrc=a; ix; - pdst[1] = psrc->y; - } - } - if( op==2 ) - { - for(i=0,psrc=a; ix; - pdst[1] = -psrc->y; - } - } - if( op==3 ) - { - for(i=0,psrc=a; ix; - pdst[1] = -psrc->y; - } - } -} - - -/******************************************************************** -This subroutine copies matrix from aligned contigous storage to -non-aligned non-contigous storage - -A: -* 2*alglib_c_block*alglib_c_block doubles (only MxN submatrix is used) -* aligned -* stride is alglib_c_block -* pointer to double is passed -* may be transformed during copying (as prescribed by op) - -B: -* MxN -* non-aligned -* non-contigous -* pointer to ae_complex is passed - -Transformation types: -* 0 - no transform -* 1 - transposition -* 2 - conjugate transposition -* 3 - conjugate, but no transposition -********************************************************************/ -void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride) -{ - ae_int_t i, j; - const double *psrc; - ae_complex *pdst; - if( op==0 ) - { - for(i=0,psrc=a; ix = psrc[0]; - pdst->y = psrc[1]; - } - } - if( op==1 ) - { - for(i=0,psrc=a; ix = psrc[0]; - pdst->y = psrc[1]; - } - } - if( op==2 ) - { - for(i=0,psrc=a; ix = psrc[0]; - pdst->y = -psrc[1]; - } - } - if( op==3 ) - { - for(i=0,psrc=a; ix = psrc[0]; - pdst->y = -psrc[1]; - } - } -} - - -/******************************************************************** -Real GEMM kernel -********************************************************************/ -ae_bool _ialglib_rmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - double *_a, - ae_int_t _a_stride, - ae_int_t optypea, - double *_b, - ae_int_t _b_stride, - ae_int_t optypeb, - double beta, - double *_c, - ae_int_t _c_stride) -{ - int i; - double *crow; - double _abuf[alglib_r_block+alglib_simd_alignment]; - double _bbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; - double * const abuf = (double * const) ae_align(_abuf,alglib_simd_alignment); - double * const b = (double * const) ae_align(_bbuf,alglib_simd_alignment); - void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; - void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; - - if( m>alglib_r_block || n>alglib_r_block || k>alglib_r_block || m<=0 || n<=0 || k<=0 || alpha==0.0 ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - rmv = &_ialglib_rmv_sse2; - mcopyblock = &_ialglib_mcopyblock_sse2; - } -#endif - - /* - * copy b - */ - if( optypeb==0 ) - mcopyblock(k, n, _b, 1, _b_stride, b); - else - mcopyblock(n, k, _b, 0, _b_stride, b); - - /* - * multiply B by A (from the right, by rows) - * and store result in C - */ - crow = _c; - if( optypea==0 ) - { - const double *arow = _a; - for(i=0; ialglib_c_block || n>alglib_c_block || k>alglib_c_block ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - cmv = &_ialglib_cmv_sse2; - } -#endif - - /* - * copy b - */ - brows = optypeb==0 ? k : n; - bcols = optypeb==0 ? n : k; - if( optypeb==0 ) - _ialglib_mcopyblock_complex(brows, bcols, _b, 1, _b_stride, b); - if( optypeb==1 ) - _ialglib_mcopyblock_complex(brows, bcols, _b, 0, _b_stride, b); - if( optypeb==2 ) - _ialglib_mcopyblock_complex(brows, bcols, _b, 3, _b_stride, b); - - /* - * multiply B by A (from the right, by rows) - * and store result in C - */ - arow = _a; - crow = _c; - for(i=0; ialglib_c_block || n>alglib_c_block ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - cmv = &_ialglib_cmv_sse2; - } -#endif - - /* - * Prepare - */ - _ialglib_mcopyblock_complex(n, n, _a, optype, _a_stride, abuf); - _ialglib_mcopyblock_complex(m, n, _x, 0, _x_stride, xbuf); - if( isunit ) - for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) - { - ae_complex tmp_c; - ae_complex beta; - ae_complex alpha; - tmp_c.x = pdiag[0]; - tmp_c.y = pdiag[1]; - beta = ae_c_d_div(1.0, tmp_c); - alpha.x = -beta.x; - alpha.y = -beta.y; - _ialglib_vcopy_dcomplex(n-1-i, pdiag+2*alglib_c_block, alglib_c_block, tmpbuf, 1, "No conj"); - cmv(m, n-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); - } - _ialglib_mcopyunblock_complex(m, n, xbuf, 0, _x, _x_stride); - } - return ae_true; -} - - -/******************************************************************** -real TRSM kernel -********************************************************************/ -ae_bool _ialglib_rmatrixrighttrsm(ae_int_t m, - ae_int_t n, - double *_a, - ae_int_t _a_stride, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - double *_x, - ae_int_t _x_stride) -{ - /* - * local buffers - */ - double *pdiag; - ae_int_t i; - double _loc_abuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; - double _loc_xbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; - double _loc_tmpbuf[alglib_r_block+alglib_simd_alignment]; - double * const abuf = (double * const) ae_align(_loc_abuf, alglib_simd_alignment); - double * const xbuf = (double * const) ae_align(_loc_xbuf, alglib_simd_alignment); - double * const tmpbuf = (double * const) ae_align(_loc_tmpbuf,alglib_simd_alignment); - ae_bool uppera; - void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; - void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; - - if( m>alglib_r_block || n>alglib_r_block ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - rmv = &_ialglib_rmv_sse2; - mcopyblock = &_ialglib_mcopyblock_sse2; - } -#endif - - /* - * Prepare - */ - mcopyblock(n, n, _a, optype, _a_stride, abuf); - mcopyblock(m, n, _x, 0, _x_stride, xbuf); - if( isunit ) - for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) - { - double beta = 1.0/(*pdiag); - double alpha = -beta; - _ialglib_vcopy(n-1-i, pdiag+alglib_r_block, alglib_r_block, tmpbuf+i+1, 1); - rmv(m, n-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); - } - _ialglib_mcopyunblock(m, n, xbuf, 0, _x, _x_stride); - } - return ae_true; -} - - -/******************************************************************** -complex TRSM kernel -********************************************************************/ -ae_bool _ialglib_cmatrixlefttrsm(ae_int_t m, - ae_int_t n, - ae_complex *_a, - ae_int_t _a_stride, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_complex *_x, - ae_int_t _x_stride) -{ - /* - * local buffers - */ - double *pdiag, *arow; - ae_int_t i; - double _loc_abuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; - double _loc_xbuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; - double _loc_tmpbuf[2*alglib_c_block+alglib_simd_alignment]; - double * const abuf = (double * const) ae_align(_loc_abuf, alglib_simd_alignment); - double * const xbuf = (double * const) ae_align(_loc_xbuf, alglib_simd_alignment); - double * const tmpbuf = (double * const) ae_align(_loc_tmpbuf,alglib_simd_alignment); - ae_bool uppera; - void (*cmv)(ae_int_t, ae_int_t, const double *, const double *, ae_complex *, double *, ae_int_t, ae_complex, ae_complex) = &_ialglib_cmv; - - if( m>alglib_c_block || n>alglib_c_block ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - cmv = &_ialglib_cmv_sse2; - } -#endif - - /* - * Prepare - * Transpose X (so we may use mv, which calculates A*x, but not x*A) - */ - _ialglib_mcopyblock_complex(m, m, _a, optype, _a_stride, abuf); - _ialglib_mcopyblock_complex(m, n, _x, 1, _x_stride, xbuf); - if( isunit ) - for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) - { - ae_complex tmp_c; - ae_complex beta; - ae_complex alpha; - tmp_c.x = pdiag[0]; - tmp_c.y = pdiag[1]; - beta = ae_c_d_div(1.0, tmp_c); - alpha.x = -beta.x; - alpha.y = -beta.y; - _ialglib_vcopy_dcomplex(m-1-i, pdiag+2, 1, tmpbuf, 1, "No conj"); - cmv(n, m-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); - } - _ialglib_mcopyunblock_complex(m, n, xbuf, 1, _x, _x_stride); - } - else - { for(i=0,pdiag=abuf,arow=abuf; ialglib_r_block || n>alglib_r_block ) - return ae_false; - - /* - * Check for SSE2 support - */ -#ifdef AE_HAS_SSE2_INTRINSICS - if( ae_cpuid() & CPU_SSE2 ) - { - rmv = &_ialglib_rmv_sse2; - mcopyblock = &_ialglib_mcopyblock_sse2; - } -#endif - - /* - * Prepare - * Transpose X (so we may use mv, which calculates A*x, but not x*A) - */ - mcopyblock(m, m, _a, optype, _a_stride, abuf); - mcopyblock(m, n, _x, 1, _x_stride, xbuf); - if( isunit ) - for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) - { - double beta = 1.0/(*pdiag); - double alpha = -beta; - _ialglib_vcopy(m-1-i, pdiag+1, 1, tmpbuf+i+1, 1); - rmv(n, m-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); - } - _ialglib_mcopyunblock(m, n, xbuf, 1, _x, _x_stride); - } - else - { for(i=0,pdiag=abuf,arow=abuf; ialglib_c_block || k>alglib_c_block ) - return ae_false; - if( n==0 ) - return ae_true; - - /* - * copy A and C, task is transformed to "A*A^H"-form. - * if beta==0, then C is filled by zeros (and not referenced) - * - * alpha==0 or k==0 are correctly processed (A is not referenced) - */ - c_alpha.x = alpha; - c_alpha.y = 0; - c_beta.x = beta; - c_beta.y = 0; - if( alpha==0 ) - k = 0; - if( k>0 ) - { - if( optypea==0 ) - _ialglib_mcopyblock_complex(n, k, _a, 3, _a_stride, abuf); - else - _ialglib_mcopyblock_complex(k, n, _a, 1, _a_stride, abuf); - } - _ialglib_mcopyblock_complex(n, n, _c, 0, _c_stride, cbuf); - if( beta==0 ) - { - for(i=0,crow=cbuf; ialglib_r_block || k>alglib_r_block ) - return ae_false; - if( n==0 ) - return ae_true; - - /* - * copy A and C, task is transformed to "A*A^T"-form. - * if beta==0, then C is filled by zeros (and not referenced) - * - * alpha==0 or k==0 are correctly processed (A is not referenced) - */ - if( alpha==0 ) - k = 0; - if( k>0 ) - { - if( optypea==0 ) - _ialglib_mcopyblock(n, k, _a, 0, _a_stride, abuf); - else - _ialglib_mcopyblock(k, n, _a, 1, _a_stride, abuf); - } - _ialglib_mcopyblock(n, n, _c, 0, _c_stride, cbuf); - if( beta==0 ) - { - for(i=0,crow=cbuf; iptr.pp_double[ia]+ja, _a->stride, optypea, _b->ptr.pp_double[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_double[ic]+jc, _c->stride); -} - -ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - ae_matrix *_a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - ae_matrix *_b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - ae_matrix *_c, - ae_int_t ic, - ae_int_t jc) -{ - return _ialglib_cmatrixgemm(m, n, k, alpha, _a->ptr.pp_complex[ia]+ja, _a->stride, optypea, _b->ptr.pp_complex[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_complex[ic]+jc, _c->stride); -} - -ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2) -{ - return _ialglib_cmatrixrighttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); -} - -ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2) -{ - return _ialglib_rmatrixrighttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); -} - -ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2) -{ - return _ialglib_cmatrixlefttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); -} - -ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2) -{ - return _ialglib_rmatrixlefttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); -} - -ae_bool _ialglib_i_cmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper) -{ - return _ialglib_cmatrixsyrk(n, k, alpha, &a->ptr.pp_complex[ia][ja], a->stride, optypea, beta, &c->ptr.pp_complex[ic][jc], c->stride, isupper); -} - -ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper) -{ - return _ialglib_rmatrixsyrk(n, k, alpha, &a->ptr.pp_double[ia][ja], a->stride, optypea, beta, &c->ptr.pp_double[ic][jc], c->stride, isupper); -} - -ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_vector *u, - ae_int_t uoffs, - ae_vector *v, - ae_int_t voffs) -{ - return _ialglib_cmatrixrank1(m, n, &a->ptr.pp_complex[ia][ja], a->stride, &u->ptr.p_complex[uoffs], &v->ptr.p_complex[voffs]); -} - -ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_vector *u, - ae_int_t uoffs, - ae_vector *v, - ae_int_t voffs) -{ - return _ialglib_rmatrixrank1(m, n, &a->ptr.pp_double[ia][ja], a->stride, &u->ptr.p_double[uoffs], &v->ptr.p_double[voffs]); -} - - - - -/******************************************************************** -This function reads rectangular matrix A given by two column pointers -col0 and col1 and stride src_stride and moves it into contiguous row- -by-row storage given by dst. - -It can handle following special cases: -* col1==NULL in this case second column of A is filled by zeros -********************************************************************/ -void _ialglib_pack_n2( - double *col0, - double *col1, - ae_int_t n, - ae_int_t src_stride, - double *dst) -{ - ae_int_t n2, j, stride2; - - /* - * handle special case - */ - if( col1==NULL ) - { - for(j=0; j>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" + +// +// if AE_OS==AE_LINUX (will be redefined to AE_POSIX in ap.h), +// set _GNU_SOURCE flag BEFORE any #includes to get affinity +// management functions +// +#if (AE_OS==AE_LINUX) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif + +// +// Must be defined before we include ap.h +// +#define _ALGLIB_IMPL_DEFINES +#define _ALGLIB_INTEGRITY_CHECKS_ONCE + +#include "ap.h" +#include +#include +#include + +#if defined(AE_CPU) +#if (AE_CPU==AE_INTEL) + +#if AE_COMPILER==AE_MSVC +#include +#endif + +#endif +#endif + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION IMPLEMENTS BASIC FUNCTIONALITY LIKE +// MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS +// SHARED BETWEEN C++ AND PURE C LIBRARIES +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +/* + * OS-specific includes + */ +#ifdef AE_USE_CPP +} +#endif +#if AE_OS==AE_WINDOWS || defined(AE_DEBUG4WINDOWS) +#include +#include +#elif AE_OS==AE_POSIX || defined(AE_DEBUG4POSIX) +#include +#include +#include +#include +#include +#else +#include +#endif + +/* Entropy source */ +#if ALGLIB_ENTROPY_SRC==ALGLIB_ENTROPY_SRC_OPENSSL +#include +#define ALGLIB_OPENSSL_RAND_MAX 0x7FFFFFFF +#endif + +/* Debugging helpers for Windows */ +#ifdef AE_DEBUG4WINDOWS +#include +#include +#endif +#ifdef AE_USE_CPP +namespace alglib_impl +{ +#endif + +/* + * local definitions + */ +#define x_nb 16 +#define AE_DATA_ALIGN 64 +#define AE_PTR_ALIGN sizeof(void*) +#define DYN_BOTTOM ((void*)1) +#define DYN_FRAME ((void*)2) +#define AE_LITTLE_ENDIAN 1 +#define AE_BIG_ENDIAN 2 +#define AE_MIXED_ENDIAN 3 +#define AE_SER_ENTRY_LENGTH 11 +#define AE_SER_ENTRIES_PER_ROW 5 + +#define AE_SM_DEFAULT 0 +#define AE_SM_ALLOC 1 +#define AE_SM_READY2S 2 +#define AE_SM_TO_STRING 10 +#define AE_SM_TO_CPPSTRING 11 +#define AE_SM_TO_STREAM 12 +#define AE_SM_FROM_STRING 20 +#define AE_SM_FROM_STREAM 22 + +#define AE_LOCK_CYCLES 512 +#define AE_LOCK_TESTS_BEFORE_YIELD 16 +#define AE_CRITICAL_ASSERT(x) if( !(x) ) abort() + +/* IDs for set_dbg_value */ +#define _ALGLIB_USE_ALLOC_COUNTER 0 +#define _ALGLIB_USE_DBG_COUNTERS 1 +#define _ALGLIB_USE_VENDOR_KERNELS 100 +#define _ALGLIB_VENDOR_MEMSTAT 101 + +#define _ALGLIB_DEBUG_WORKSTEALING 200 +#define _ALGLIB_WSDBG_NCORES 201 +#define _ALGLIB_WSDBG_PUSHROOT_OK 202 +#define _ALGLIB_WSDBG_PUSHROOT_FAILED 203 + +#define _ALGLIB_SET_GLOBAL_FLAGS 1001 +#define _ALGLIB_SET_NWORKERS 1002 + +/* IDs for get_dbg_value */ +#define _ALGLIB_GET_ALLOC_COUNTER 0 +#define _ALGLIB_GET_CUMULATIVE_ALLOC_SIZE 1 +#define _ALGLIB_GET_CUMULATIVE_ALLOC_COUNT 2 + +#define _ALGLIB_GET_CORES_COUNT 1000 +#define _ALGLIB_GET_GLOBAL_FLAGS 1001 +#define _ALGLIB_GET_NWORKERS 1002 +#define _ALGLIB_GET_CORES_TO_USE 1003 + +#if defined(ALGLIB_REDZONE) +#define _ALGLIB_REDZONE_VAL 0x3c +#endif + +/************************************************************************* +Lock. + +This is internal structure which implements lock functionality. +*************************************************************************/ +typedef struct +{ +#if AE_OS==AE_WINDOWS + volatile ae_int_t * volatile p_lock; + char buf[sizeof(ae_int_t)+AE_LOCK_ALIGNMENT]; +#elif AE_OS==AE_POSIX + pthread_mutex_t mutex; +#else + ae_bool is_locked; +#endif +} _lock; + + + + +/* + * Error tracking facilities; this fields are modified every time ae_set_error_flag() + * is called with non-zero cond. Thread unsafe access, but it does not matter actually. + */ +static const char * sef_file = ""; +static int sef_line = 0; +static const char * sef_xdesc = ""; + +/* + * Global flags, split into several char-sized variables in order + * to avoid problem with non-atomic reads/writes (single-byte ops + * are atomic on all modern architectures); + * + * Following variables are included: + * * threading-related settings + */ +ae_uint64_t _alglib_global_flags = 0x0; + +#if defined(_ALGLIB_HAS_THREADLOCAL) +/* + * Current callback worker index (index of a parallel thread performing batch callback evaluation). + * Zero + */ +_ALGLIB_THREADLOCAL static ae_int_t _cbck_worker_idx = 0; +#endif + +/* + * DESCRIPTION: recommended number of active workers: + * * positive value >=1 is used to specify exact number of active workers + * * 0 means that ALL available cores are used + * * negative value means that all cores EXCEPT for cores_to_use will be used + * (say, -1 means that all cores except for one will be used). At least one + * core will be used in this case, even if you assign -9999999 to this field. + * + * Default value = 0 (fully parallel execution) when AE_NWORKERS is not defined + * = 0 for manually defined number of cores (AE_NWORKERS is defined) + * PROTECTION: not needed; runtime modification is possible, but we do not need exact + * synchronization. + */ +#if defined(AE_NWORKERS) && (AE_NWORKERS<=0) +#error AE_NWORKERS must be positive number or not defined at all. +#endif +#if defined(AE_NWORKERS) +ae_int_t _alglib_cores_to_use = 0; +#else +ae_int_t _alglib_cores_to_use = 0; +#endif + +/* + * Debug counters + */ +ae_int_t _alloc_counter = 0; +ae_int_t _alloc_counter_total = 0; +ae_bool _use_alloc_counter = ae_false; + +ae_int_t _dbg_alloc_total = 0; +ae_bool _use_dbg_counters = ae_false; + +ae_bool _use_vendor_kernels = ae_true; + +ae_bool debug_workstealing = ae_false; /* debug workstealing environment? False by default */ +ae_int_t dbgws_pushroot_ok = 0; +ae_int_t dbgws_pushroot_failed = 0; + +#ifdef AE_SMP_DEBUGCOUNTERS +__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_acquisitions = 0; +__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_spinwaits = 0; +__declspec(align(AE_LOCK_ALIGNMENT)) volatile ae_int64_t _ae_dbg_lock_yields = 0; +#endif + +/* + * Allocation debugging + */ +ae_bool _force_malloc_failure = ae_false; +ae_int_t _malloc_failure_after = 0; + + +/* + * Trace-related declarations: + * alglib_trace_type - trace output type + * alglib_trace_file - file descriptor (to be used by ALGLIB code which + * sends messages to trace log + * alglib_fclose_trace - whether we have to call fclose() when disabling or + * changing trace output + * alglib_trace_tags - string buffer used to store tags + two additional + * characters (leading and trailing commas) + null + * terminator + */ +#define ALGLIB_TRACE_NONE 0 +#define ALGLIB_TRACE_FILE 1 +#define ALGLIB_TRACE_TAGS_LEN 2048 +#define ALGLIB_TRACE_BUFFER_LEN (ALGLIB_TRACE_TAGS_LEN+2+1) +static ae_int_t alglib_trace_type = ALGLIB_TRACE_NONE; +FILE *alglib_trace_file = NULL; +static ae_bool alglib_fclose_trace = ae_false; +static char alglib_trace_tags[ALGLIB_TRACE_BUFFER_LEN]; + +/* + * Fields for memory allocation over static array + */ +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC +#if AE_THREADING!=AE_SERIAL_UNSAFE +#error Basis static malloc is thread-unsafe; define AE_THREADING=AE_SERIAL_UNSAFE to prove that you know it +#endif +static ae_int_t sm_page_size = 0; +static ae_int_t sm_page_cnt = 0; +static ae_int_t *sm_page_tbl = NULL; +static unsigned char *sm_mem = NULL; +#endif + +/* + * These declarations are used to ensure that + * sizeof(ae_bool)=1, sizeof(ae_int32_t)==4, sizeof(ae_int64_t)==8, sizeof(ae_int_t)==sizeof(void*). + * they will lead to syntax error otherwise (array size will be negative). + * + * you can remove them, if you want - they are not used anywhere. + * + */ +static char _ae_bool_must_be_8_bits_wide [1-2*((int)(sizeof(ae_bool))-1)*((int)(sizeof(ae_bool))-1)]; +static char _ae_int32_t_must_be_32_bits_wide[1-2*((int)(sizeof(ae_int32_t))-4)*((int)(sizeof(ae_int32_t))-4)]; +static char _ae_int64_t_must_be_64_bits_wide[1-2*((int)(sizeof(ae_int64_t))-8)*((int)(sizeof(ae_int64_t))-8)]; +static char _ae_uint64_t_must_be_64_bits_wide[1-2*((int)(sizeof(ae_uint64_t))-8)*((int)(sizeof(ae_uint64_t))-8)]; +static char _ae_int_t_must_be_pointer_sized [1-2*((int)(sizeof(ae_int_t))-(int)sizeof(void*))*((int)(sizeof(ae_int_t))-(int)(sizeof(void*)))]; +#if defined(ALGLIB_REDZONE) +static char _ae_redzone_must_be_multiple_of_64[1-2*(((ALGLIB_REDZONE)<(AE_DATA_ALIGN)) ? 1 : 0)-2*(((ALGLIB_REDZONE)%(AE_DATA_ALIGN)) ? 1 : 0)]; +#endif + +/* + * This variable is used to prevent some tricky optimizations which may degrade multithreaded performance. + * It is touched once in the ae_init_pool() function from smp.c in order to prevent optimizations. + * + */ +static volatile ae_int_t ae_never_change_it = 1; + +/************************************************************************* +This function should never be called. It is here to prevent spurious +compiler warnings about unused variables (in fact: used). +*************************************************************************/ +void ae_never_call_it() +{ + ae_touch_ptr((void*)_ae_bool_must_be_8_bits_wide); + ae_touch_ptr((void*)_ae_int32_t_must_be_32_bits_wide); + ae_touch_ptr((void*)_ae_int64_t_must_be_64_bits_wide); + ae_touch_ptr((void*)_ae_uint64_t_must_be_64_bits_wide); + ae_touch_ptr((void*)_ae_int_t_must_be_pointer_sized); +} + + +/************************************************************************* +RNG wrappers +*************************************************************************/ +ae_int_t ae_rand() +{ +#if (defined(ALGLIB_ENTROPY_SRC) && ALGLIB_ENTROPY_SRC==ALGLIB_ENTROPY_SRC_STDRAND) || !defined(ALGLIB_ENTROPY_SRC) + return (ae_int_t)rand(); +#elif ALGLIB_ENTROPY_SRC==ALGLIB_ENTROPY_SRC_OPENSSL + ae_int32_t random_number; + unsigned char buf[sizeof(random_number)]; + if( !RAND_bytes(buf,sizeof(random_number)) ) + { + /* openSSL random number generator failed, default to standard random generator */ + return (ae_int_t)rand(); + } + memmove(&random_number, buf, sizeof(random_number)); + if( random_number<0 ) + random_number = -(random_number+1); + return (ae_int_t)random_number; +#else +#error ALGLIB_ENTROPY_SRC is defined, but its value is not recognized +#endif +} + +ae_int_t ae_rand_max() +{ +#if (defined(ALGLIB_ENTROPY_SRC) && ALGLIB_ENTROPY_SRC==ALGLIB_ENTROPY_SRC_STDRAND) || !defined(ALGLIB_ENTROPY_SRC) + return (ae_int_t)RAND_MAX; +#elif ALGLIB_ENTROPY_SRC==ALGLIB_ENTROPY_SRC_OPENSSL + return (ae_int_t)ALGLIB_OPENSSL_RAND_MAX; +#else +#error ALGLIB_ENTROPY_SRC is defined, but its value is not recognized +#endif +} + +/************************************************************************* +Standard function wrappers for better GLIBC portability +*************************************************************************/ +#if defined(X_FOR_LINUX_X64) || defined(X_FOR_LINUX_ARM64) +#if defined(X_FOR_LINUX_X64) +__asm__(".symver exp,exp@GLIBC_2.2.5"); +__asm__(".symver log,log@GLIBC_2.2.5"); +__asm__(".symver pow,pow@GLIBC_2.2.5"); +#endif +#if defined(X_FOR_LINUX_ARM64) +__asm__(".symver exp,exp@GLIBC_2.17"); +__asm__(".symver log,log@GLIBC_2.17"); +__asm__(".symver pow,pow@GLIBC_2.17"); +#endif + +double __wrap_exp(double x) +{ + return exp(x); +} + +double __wrap_log(double x) +{ + return log(x); +} + +double __wrap_pow(double x, double y) +{ + return pow(x, y); +} +#endif + +void ae_set_dbg_flag(ae_int64_t flag_id, ae_int64_t flag_val) +{ + if( flag_id==_ALGLIB_USE_ALLOC_COUNTER ) + { + _use_alloc_counter = flag_val!=0; + return; + } + if( flag_id==_ALGLIB_USE_DBG_COUNTERS ) + { + _use_dbg_counters = flag_val!=0; + return; + } + if( flag_id==_ALGLIB_USE_VENDOR_KERNELS ) + { + _use_vendor_kernels = flag_val!=0; + return; + } + if( flag_id==_ALGLIB_DEBUG_WORKSTEALING ) + { + debug_workstealing = flag_val!=0; + return; + } + if( flag_id==_ALGLIB_SET_GLOBAL_FLAGS ) + { + ae_set_global_flags((ae_uint64_t)flag_val); + return; + } + if( flag_id==_ALGLIB_SET_NWORKERS ) + { + _alglib_cores_to_use = (ae_int_t)flag_val; + return; + } +} + +ae_int64_t ae_get_dbg_value(ae_int64_t id) +{ + if( id==_ALGLIB_GET_ALLOC_COUNTER ) + return (ae_int64_t)_alloc_counter; + if( id==_ALGLIB_GET_CUMULATIVE_ALLOC_SIZE ) + return (ae_int64_t)_dbg_alloc_total; + if( id==_ALGLIB_GET_CUMULATIVE_ALLOC_COUNT ) + return (ae_int64_t)_alloc_counter_total; + + if( id==_ALGLIB_VENDOR_MEMSTAT ) + { +#if defined(_ALGLIB_USE_PBL) + return (ae_int64_t)ae_pbl_memstat(); +#else + return (ae_int64_t)0; +#endif + } + + /* workstealing counters */ + if( id==_ALGLIB_WSDBG_NCORES ) +#if defined(AE_SMP) + return (ae_int64_t)ae_cores_count(); +#else + return (ae_int64_t)0; +#endif + if( id==_ALGLIB_WSDBG_PUSHROOT_OK ) + return (ae_int64_t)dbgws_pushroot_ok; + if( id==_ALGLIB_WSDBG_PUSHROOT_FAILED ) + return (ae_int64_t)dbgws_pushroot_failed; + + if( id==_ALGLIB_GET_CORES_COUNT ) +#if defined(AE_SMP) + return (ae_int64_t)ae_cores_count(); +#else + return (ae_int64_t)0; +#endif + if( id==_ALGLIB_GET_GLOBAL_FLAGS ) + return (ae_int64_t)ae_get_global_flags(); + if( id==_ALGLIB_GET_NWORKERS ) + return (ae_int64_t)_alglib_cores_to_use; + if( id==_ALGLIB_GET_CORES_TO_USE ) +#if defined(AE_SMP) + return (ae_int64_t)ae_get_cores_to_use_positive(); +#else + return (ae_int64_t)1; +#endif + + /* unknown value */ + return (ae_int64_t)0; +} + +/************************************************************************ +This function sets default (global) threading model: +* serial execution +* multithreading, if cores_to_use allows it +* serial callbacks +* parallel callbacks +and vendor backend settings + +************************************************************************/ +void ae_set_global_flags(ae_uint64_t flg_value) +{ + AE_CRITICAL_ASSERT((flg_value&_ALGLIB_FLG_THREADING_MASK_WRK)==_ALGLIB_FLG_THREADING_SERIAL || + (flg_value&_ALGLIB_FLG_THREADING_MASK_WRK)==_ALGLIB_FLG_THREADING_PARALLEL || + (flg_value&_ALGLIB_FLG_THREADING_MASK_WRK)==_ALGLIB_FLG_USE_GLOBAL); + AE_CRITICAL_ASSERT((flg_value&_ALGLIB_FLG_THREADING_MASK_CBK)==_ALGLIB_FLG_THREADING_SERIAL_CALLBACKS || + (flg_value&_ALGLIB_FLG_THREADING_MASK_CBK)==_ALGLIB_FLG_THREADING_PARALLEL_CALLBACKS || + (flg_value&_ALGLIB_FLG_THREADING_MASK_CBK)==_ALGLIB_FLG_USE_GLOBAL); + AE_CRITICAL_ASSERT((flg_value&_ALGLIB_FLG_BACKEND_MASK_LINALG)==_ALGLIB_FLG_BACKEND_LINALG || + (flg_value&_ALGLIB_FLG_BACKEND_MASK_LINALG)==_ALGLIB_FLG_BACKEND_NOLINALG || + (flg_value&_ALGLIB_FLG_BACKEND_MASK_LINALG)==_ALGLIB_FLG_USE_GLOBAL); + AE_CRITICAL_ASSERT((flg_value&_ALGLIB_FLG_BACKEND_MASK_DSS)==_ALGLIB_FLG_BACKEND_DSS || + (flg_value&_ALGLIB_FLG_BACKEND_MASK_DSS)==_ALGLIB_FLG_BACKEND_NODSS || + (flg_value&_ALGLIB_FLG_BACKEND_MASK_DSS)==_ALGLIB_FLG_USE_GLOBAL); + ae_really_weak_store_u64(&_alglib_global_flags, flg_value); +} + + +/************************************************************************ +This function returns index of a current worker thread that calls user +callback during parallel numerical differentiation or batch evaluation: + +* a value between 0 and max-1 is returned when callback parallelism is + enabled (here max depends on the current smp configuration) and when + this function is called from a user callback + +* 0 is returned when callback parallelism is NOT enabled, or when called + from outside of a callback. + +This function is available only in C11/C++11 or later because it relies +on availability of a portable _Thread_local/thread_local specifier. +************************************************************************/ +#if defined(_ALGLIB_HAS_THREADLOCAL) +ae_int_t ae_get_callback_worker_idx() +{ + return _cbck_worker_idx; +} +#endif + + +/************************************************************************ +This function sets index of a current worker thread that calls user +callback during parallel numerical differentiation or batch evaluation. + +It should be called by the worker once before calling a user callback. + +This function is available only in C11/C++11 or later because it relies +on availability of a portable _Thread_local/thread_local specifier. +************************************************************************/ +#if defined(_ALGLIB_HAS_THREADLOCAL) +void ae_set_callback_worker_idx(ae_int_t idx) +{ + _cbck_worker_idx = idx; +} +#endif + +/************************************************************************ +This function gets default (global) threading model and performance +backend configuration + +************************************************************************/ +ae_uint64_t ae_get_global_flags() +{ + return _alglib_global_flags; +} + +/************************************************************************ +This function returns number of processors configured in the system +using GetSystemInfo() or sysconf(_SC_NPROCESSORS_ONLN). The value returned +is cached, so that subsequent calls do not have syscall overhead. + +When no AE_OS is #defined, returns 1. +************************************************************************/ +static ae_int_t nprocessors_last = 0; +ae_int_t get_nprocessors_cached() +{ + ae_int_t result = ae_weak_atomic_load_norace(&nprocessors_last); + ae_int_t prev_result = result; + if( result==0 ) + { + #if AE_OS==AE_WINDOWS + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + result = sysInfo.dwNumberOfProcessors; + #elif AE_OS==AE_POSIX + long r = sysconf(_SC_NPROCESSORS_ONLN); + result = r<0 ? 1 : r; + #else + result = 1; + #endif + } + if( prev_result==0 ) + ae_weak_store_release(&nprocessors_last, result); + return result; +} + +void ae_set_error_flag(ae_bool *p_flag, ae_bool cond, const char *filename, int lineno, const char *xdesc) +{ + if( cond ) + { + *p_flag = ae_true; + sef_file = filename; + sef_line = lineno; + sef_xdesc= xdesc; +#ifdef ALGLIB_ABORT_ON_ERROR_FLAG + printf("[ALGLIB] aborting on ae_set_error_flag(cond=true)\n"); + printf("[ALGLIB] %s:%d\n", filename, lineno); + printf("[ALGLIB] %s\n", xdesc); + fflush(stdout); + if( alglib_trace_file!=NULL ) fflush(alglib_trace_file); + abort(); +#endif + } +} + +/************************************************************************ +This function returns file name for the last call of ae_set_error_flag() +with non-zero cond parameter. +************************************************************************/ +const char * ae_get_last_error_file() +{ + return sef_file; +} + +/************************************************************************ +This function returns line number for the last call of ae_set_error_flag() +with non-zero cond parameter. +************************************************************************/ +int ae_get_last_error_line() +{ + return sef_line; +} + +/************************************************************************ +This function returns extra description for the last call of ae_set_error_flag() +with non-zero cond parameter. +************************************************************************/ +const char * ae_get_last_error_xdesc() +{ + return sef_xdesc; +} + +ae_int_t ae_misalignment(const void *ptr, size_t alignment) +{ + union _u + { + const void *ptr; + ae_int_t iptr; + } u; + u.ptr = ptr; + return u.iptr%(ae_int_t)alignment; +} + +void* ae_align(void *ptr, size_t alignment) +{ + char *result = (char*)ptr; + if( ((size_t)(result-(char*)0))%alignment!=0 ) + result += alignment - ((size_t)(result-(char*)0))%alignment; + return result; +} + +/************************************************************************ +This function maps nworkers number (which can be positive, zero or +negative with 0 meaning "all cores", -1 meaning "all cores -1" and so on) +to "effective", strictly positive workers count. + +This function is intended to be used by debugging/testing code which +tests different number of worker threads. It is NOT aligned in any way +with ALGLIB multithreading framework (i.e. it can return non-zero worker +count even for single-threaded GPLed ALGLIB). +************************************************************************/ +ae_int_t ae_get_effective_workers(ae_int_t nworkers) +{ + ae_int_t ncores; + + /* determine cores count */ +#if defined(AE_NWORKERS) + ncores = AE_NWORKERS; +#else + ncores = get_nprocessors_cached(); +#endif + AE_CRITICAL_ASSERT(ncores>=1); + + /* map nworkers to its effective value */ + if( nworkers>=1 ) + return nworkers>ncores ? ncores : nworkers; + return ncores+nworkers>=1 ? ncores+nworkers : 1; +} + +/************************************************************************* +This function belongs to the family of "optional atomics", i.e. atomic +functions which either perform atomic changes - or do nothing at all, if +current compiler settings do not allow us to generate atomic code. + +All "optional atomics" are synchronized, i.e. either all of them work - or +no one of the works. + +This particular function performs atomic addition on pointer-sized value, +which must be pointer-size aligned. + +NOTE: this function is not intended to be extremely high performance one, + so use it only when necessary. +*************************************************************************/ +void ae_optional_atomic_add_i(ae_int_t *p, ae_int_t v) +{ + AE_CRITICAL_ASSERT(ae_misalignment(p,sizeof(void*))==0); +#if AE_OS==AE_WINDOWS + for(;;) + { + /* perform conversion between ae_int_t* and void** + without compiler warnings about indirection levels */ + union _u + { + PVOID volatile * volatile ptr; + volatile ae_int_t * volatile iptr; + } u; + u.iptr = p; + + /* atomic read for initial value */ + PVOID v0 = InterlockedCompareExchangePointer(u.ptr, NULL, NULL); + + /* increment cached value and store */ + if( InterlockedCompareExchangePointer(u.ptr, (PVOID)(((char*)v0)+v), v0)==v0 ) + break; + } +#elif defined(__clang__) || ((AE_COMPILER==AE_GNUC)&&(__GNUC__*100+__GNUC__>=470)) + __atomic_fetch_add(p, v, __ATOMIC_RELAXED); +#else +#endif +} + +/************************************************************************* +This function belongs to the family of "optional atomics", i.e. atomic +functions which either perform atomic changes - or do nothing at all, if +current compiler settings do not allow us to generate atomic code. + +All "optional atomics" are synchronized, i.e. either all of them work - or +no one of the works. + +This particular function performs atomic subtraction on pointer-sized +value, which must be pointer-size aligned. + +NOTE: this function is not intended to be extremely high performance one, + so use it only when necessary. +*************************************************************************/ +void ae_optional_atomic_sub_i(ae_int_t *p, ae_int_t v) +{ + AE_CRITICAL_ASSERT(ae_misalignment(p,sizeof(void*))==0); +#if AE_OS==AE_WINDOWS + for(;;) + { + /* perform conversion between ae_int_t* and void** + without compiler warnings about indirection levels */ + union _u + { + PVOID volatile * volatile ptr; + volatile ae_int_t * volatile iptr; + } u; + u.iptr = p; + + /* atomic read for initial value, convert it to 1-byte pointer */ + PVOID v0 = InterlockedCompareExchangePointer(u.ptr, NULL, NULL); + + /* increment cached value and store */ + if( InterlockedCompareExchangePointer(u.ptr, (PVOID)(((char*)v0)-v), v0)==v0 ) + break; + } +#elif defined(__clang__) || ((AE_COMPILER==AE_GNUC) && (__GNUC__*100+__GNUC__>=470)) + __atomic_fetch_sub(p, v, __ATOMIC_RELAXED); +#else +#endif +} + +/************************************************************************* +Issues weak memory fence + +"weak" means that the memfence is issued for AE_OS #defined, but not +guaranteed to be issued for OS-agnostic mode. +*************************************************************************/ +void ae_mfence_lockless() +{ +#if (AE_OS==AE_POSIX) || (AE_OS==AE_LINUX) + #if defined(__clang__) + __atomic_thread_fence(__ATOMIC_SEQ_CST); + #elif defined(__GNUC__) + #if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=7) + __atomic_thread_fence(__ATOMIC_SEQ_CST); + #else + __sync_synchronize(); + #endif + #else + #error ae_weak_mfence() on POSIX/LINUX is implemented only for GNUC-compatible compilers + #endif +#elif AE_OS==AE_WINDOWS + MemoryBarrier(); +#elif AE_OS==AE_UNKNOWN + // do nothing +#else +#error Unexpected OS for ae_weak_mfence() +#endif +} + +/************************************************************************* +Performs weak atomic write (having no syncronization semantics) +to a properly aligned ae_uint64_t. + +"really weak" means that the atomicity is guaranteed only for 64-bit platforms +and properly aligned 64-bit integers. + +Simultaneous 64-bit writes executed on 32-bit platforms are NOT guaranteed +to be done tear-free. This, this function shall not be used in critical +synchronization primitives. Using it to store global flags is considered +acceptable. +*************************************************************************/ +void ae_really_weak_store_u64(ae_uint64_t *p, ae_uint64_t v) +{ + *p = v; +} + + +/************************************************************************* +Performs weak atomic write RELEASE semantics to the properly aligned ae_int_t. + +"weak" means that the atomicity and interlocked properties are guaranteed +for AE_OS #defined, but not guaranteed for OS-agnostic mode. +*************************************************************************/ +void ae_weak_store_release(ae_int_t *p, ae_int_t v) +{ +#if defined(_ALGLIB_TSAN) + /* use compare-and-swap in order to help ThreadSanitizer infer synchronization status of the function */ + ae_int_t prev; + ae_int_t cur = ae_weak_atomic_cas(p, 0, 0); + do + { + prev = cur; + cur = ae_weak_atomic_cas(p, prev, v); + } + while( cur!=prev ); +#elif AE_CPU==AE_INTEL + /* x64 platform provides strong ordering guarantees */ + *((volatile ae_int_t *)p) = v; + +#elif defined(__clang__) + /* CLang has atomics */ + __atomic_store(p, &v, __ATOMIC_RELEASE); + +#elif defined(__GNUC__) + /* GNU compilers also have nice intrinsics, but we provide special fallback for older generations */ + #if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=7) + __atomic_store(p, &v, __ATOMIC_RELEASE); + #else + for(ae_int_t prev=*p;;) + { + ae_int_t cur = __sync_val_compare_and_swap(p,prev,v); + if( cur==prev ) + break; + prev = cur; + } + #endif + +#elif (AE_OS==AE_POSIX) || (AE_OS==AE_LINUX) + /* Non-GNU POSIX/LINUX */ + ae_mfence_lockless(); + *((volatile ae_int_t *)p) = v; + +#elif AE_OS==AE_WINDOWS + /* generic Windows platform can be x64 or ARM with weaker memory model */ + ae_mfence_lockless(); + *((volatile ae_int_t *)p) = v; + +#elif AE_OS==AE_UNKNOWN + ae_mfence_lockless(); + *((volatile ae_int_t *)p) = v; + +#else + #error Unexpected OS for ae_weak_store_release() + +#endif +} + + +/************************************************************************* +Performs weak atomic load from the properly aligned ae_int_t. + +"weak" means that the atomicity is guaranteed for AE_OS #defined, but not +guaranteed for OS-agnostic mode. + +The operation is generally equivalent to conventional load, however it is +marked as a safe one for TSAN. The primary purpose is to provide loads that +do not raise warnings about races. +*************************************************************************/ +ae_int_t ae_weak_atomic_load_norace(ae_int_t *p) +{ +#if defined(_ALGLIB_TSAN) + /* use compare-and-swap in order to help ThreadSanitizer infer synchronization status of the function */ + return ae_weak_atomic_cas(p, 0, 0); +#else + return *p; +#endif +} + + +/************************************************************************* +Performs weak atomic load from the properly aligned void*. + +"weak" means that the atomicity is guaranteed for AE_OS #defined, but not +guaranteed for OS-agnostic mode. + +The operation is generally equivalent to conventional load, however it is +marked as a safe one for TSAN. The primary purpose is to provide loads that +do not raise warnings about races. +*************************************************************************/ +void* ae_weak_atomic_load_norace_ptr(void **p) +{ +#if defined(_ALGLIB_TSAN) + /* use compare-and-swap in order to help ThreadSanitizer infer synchronization status of the function */ + return ae_weak_atomic_cas_ptr(p, NULL, NULL); +#else + return *p; +#endif +} + +/************************************************************************* +Performs weak atomic compare-and-swap from the properly aligned ae_int_t. +Returns the value stored in *p prior to the comparison. + +"weak" means that the atomicity is guaranteed for AE_OS #defined, but not +guaranteed for OS-agnostic mode. +*************************************************************************/ +ae_int_t ae_weak_atomic_cas(ae_int_t *p, ae_int_t expect, ae_int_t store) +{ +#if (AE_OS==AE_POSIX) || (AE_OS==AE_LINUX) + #if defined(__clang__) + if( __atomic_compare_exchange(p, &expect, &store, 0x0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) + return expect; + return expect; + #elif defined(__GNUC__) + #if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=7) + if( __atomic_compare_exchange(p, &expect, &store, 0x0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) + return expect; + return expect; + #else + return __sync_val_compare_and_swap(p, expect, store); + #endif + #else + #error ae_weak_atomic_cas() on POSIX/LINUX is implemented only for GNUC-compatible compilers + return 0x0; /* avoid spurious compiler warnings */ + #endif + +#elif AE_OS==AE_WINDOWS + void *p_expect, *p_store, *p_result; + ae_int_t result; + memmove(&p_expect, &expect, sizeof(expect)); + memmove(&p_store, &store, sizeof(store)); + p_result = InterlockedCompareExchangePointer((PVOID*)p, p_store, p_expect); + memmove(&result, &p_result, sizeof(result)); + return result; + +#elif AE_OS==AE_UNKNOWN + ae_int_t v = *((volatile ae_int_t *)p); + if( v==expect ) + *((volatile ae_int_t *)p) = store; + return v; + +#else + #error Unexpected OS for ae_weak_atomic_cas() + return 0x0; /* avoid spurious compiler warnings */ + +#endif +} + +/************************************************************************* +Performs weak atomic compare-and-swap from the properly aligned void*. +Returns the value stored in *p prior to the comparison. + +"weak" means that the atomicity is guaranteed for AE_OS #defined, but not +guaranteed for OS-agnostic mode. +*************************************************************************/ +void* ae_weak_atomic_cas_ptr(void **p, void *expect, void *store) +{ +#if (AE_OS==AE_POSIX) || (AE_OS==AE_LINUX) + #if defined(__clang__) + if( __atomic_compare_exchange(p, &expect, &store, 0x0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) + return expect; + return expect; + #elif defined(__GNUC__) + #if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=7) + if( __atomic_compare_exchange(p, &expect, &store, 0x0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) + return expect; + return expect; + #else + return __sync_val_compare_and_swap(p, expect, store); + #endif + #else + #error ae_weak_atomic_cas() on POSIX/LINUX is implemented only for GNUC-compatible compilers + return 0x0; /* avoid spurious compiler warnings */ + #endif + +#elif AE_OS==AE_WINDOWS + return InterlockedCompareExchangePointer(p, store, expect); + +#elif AE_OS==AE_UNKNOWN + void* v = *p; + if( v==expect ) + *p = store; + return v; + +#else + #error Unexpected OS for ae_weak_atomic_cas() + return 0x0; /* avoid spurious compiler warnings */ + +#endif +} + +/************************************************************************* +Performs weak check of the lock status. + +When TSan is NOT used, basically it is just an unsafe-volatile read from +the variable and comparison with the val_to_check. No atomicity, no lock +acquisition, nothing. + +When TSan is used, this function serves as a hint in order to establish a +happens-before relationship. +*************************************************************************/ +ae_bool ae_weak_atomic_check_lock(ae_int_t *p, ae_int_t val_to_check) +{ +#if defined(_ALGLIB_TSAN) + /* use compare-and-swap in order to help ThreadSanitizer infer synchronization status of the function */ + return ae_weak_atomic_cas(p, val_to_check, val_to_check)==val_to_check; +#else + return ae_unsafe_volatile_read(p)==val_to_check; +#endif +} + +/************************************************************************* +Performs weak atomic release of a spinlock implemented as a properly +aligned ae_int_t. + +"weak" means that the atomicity is guaranteed for AE_OS #defined, but not +guaranteed for OS-agnostic mode. + +The spinlock must be equal to EXPECT prior to calling this function. After +the call it will be equal to STORE. Depending on the situation, this function +may be implemented either as a simple RELEASE-STORE assignment, or as a +COMPARE-AND-SWAP with P/EXPECTED/STORE. +*************************************************************************/ +void ae_weak_atomic_release_lock(ae_int_t *p, ae_int_t expect, ae_int_t store) +{ +#if defined(_ALGLIB_TSAN) + /* use compare-and-swap in order to help ThreadSanitizer infer synchronization status of the function */ + ae_weak_atomic_cas(p, expect, store); +#else + ae_weak_store_release(p, store); +#endif +} + +ae_int_t ae_unsafe_volatile_read(const ae_int_t *p) +{ + return *((volatile const ae_int_t *)p); +} + +void ae_unsafe_write(ae_int_t *dst, ae_int_t v) +{ + *dst = v; +} + +/************************************************************************* +This function cleans up automatically managed memory before caller terminates +ALGLIB executing by ae_break() or by simply stopping calling callback. + +For state!=NULL it calls thread_exception_handler() and the ae_state_clear(). +For state==NULL it does nothing. +*************************************************************************/ +void ae_clean_up_before_breaking(ae_state *state) +{ + if( state!=NULL ) + { + if( state->thread_exception_handler!=NULL ) + state->thread_exception_handler(state); + ae_state_clear(state); + } +} + +/************************************************************************* +This function abnormally aborts program, using one of several ways: + +* for state!=NULL and state->break_jump being initialized with call to + ae_state_set_break_jump() - it performs longjmp() to return site. +* otherwise, abort() is called + +In all cases, for state!=NULL function sets state->last_error and +state->error_msg fields. It also clears state with ae_state_clear(). + +If state is not NULL and state->thread_exception_handler is set, it is +called prior to handling error and clearing state. +*************************************************************************/ +void ae_break(ae_state *state, ae_error_type error_type, const char *msg) +{ + if( state!=NULL ) + { + if( alglib_trace_type!=ALGLIB_TRACE_NONE ) + ae_trace("---!!! CRITICAL ERROR !!!--- exception with message '%s' was generated\n", msg!=NULL ? msg : ""); + ae_clean_up_before_breaking(state); + state->last_error = error_type; + state->error_msg = msg; + if( state->break_jump!=NULL ) + longjmp(*(state->break_jump), 1); + else + abort(); + } + else + abort(); +} + +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC +void set_memory_pool(void *ptr, size_t size) +{ + /* + * Integrity checks + */ + AE_CRITICAL_ASSERT(sm_page_size==0); + AE_CRITICAL_ASSERT(sm_page_cnt==0); + AE_CRITICAL_ASSERT(sm_page_tbl==NULL); + AE_CRITICAL_ASSERT(sm_mem==NULL); + AE_CRITICAL_ASSERT(size>0); + + /* + * Align pointer + */ + size -= ae_misalignment(ptr, sizeof(ae_int_t)); + ptr = ae_align(ptr, sizeof(ae_int_t)); + + /* + * Calculate page size and page count, prepare pointers to page table and memory + */ + sm_page_size = 256; + AE_CRITICAL_ASSERT(size>=(sm_page_size+sizeof(ae_int_t))+sm_page_size); /* we expect to have memory for at least one page + table entry + alignment */ + sm_page_cnt = (size-sm_page_size)/(sm_page_size+sizeof(ae_int_t)); + AE_CRITICAL_ASSERT(sm_page_cnt>0); + sm_page_tbl = (ae_int_t*)ptr; + sm_mem = (unsigned char*)ae_align(sm_page_tbl+sm_page_cnt, sm_page_size); + + /* + * Mark all pages as free + */ + memset(sm_page_tbl, 0, sm_page_cnt*sizeof(ae_int_t)); +} + +void* ae_static_malloc(size_t size, size_t alignment) +{ + int rq_pages, i, j, cur_len; + + AE_CRITICAL_ASSERT(size>=0); + AE_CRITICAL_ASSERT(sm_page_size>0); + AE_CRITICAL_ASSERT(sm_page_cnt>0); + AE_CRITICAL_ASSERT(sm_page_tbl!=NULL); + AE_CRITICAL_ASSERT(sm_mem!=NULL); + + if( size==(size_t)0 ) + return NULL; + if( _force_malloc_failure ) + return NULL; + + /* check that page alignment and requested alignment match each other */ + if( alignment==0 ) + alignment = AE_DATA_ALIGN; + AE_CRITICAL_ASSERT(alignment<=sm_page_size); + AE_CRITICAL_ASSERT((sm_page_size%alignment)==0); + + /* search long enough sequence of pages */ + rq_pages = size/sm_page_size; + if( size%sm_page_size ) + rq_pages++; + cur_len = 0; + for(i=0; i0); + cur_len=0; + i += sm_page_tbl[i]; + continue; + } + + /* found it? */ + if( cur_len>=rq_pages ) + { + /* update counters (if flag is set) */ + if( _use_alloc_counter ) + { + ae_optional_atomic_add_i(&_alloc_counter, 1); + ae_optional_atomic_add_i(&_alloc_counter_total, 1); + } + if( _use_dbg_counters ) + ae_optional_atomic_add_i(&_dbg_alloc_total, size); + + /* mark pages and return */ + for(j=0; j=0); + AE_CRITICAL_ASSERT((page_idx%sm_page_size)==0); + page_idx = page_idx/sm_page_size; + AE_CRITICAL_ASSERT(page_idx=1); + for(i=0; i0); + AE_CRITICAL_ASSERT(sm_page_cnt>0); + AE_CRITICAL_ASSERT(sm_page_tbl!=NULL); + AE_CRITICAL_ASSERT(sm_mem!=NULL); + + /* scan page table */ + *bytes_used = 0; + *bytes_free = 0; + for(i=0; i0); + *bytes_used += sm_page_tbl[i]; + i += sm_page_tbl[i]; + } + } + *bytes_used *= sm_page_size; + *bytes_free *= sm_page_size; +} +#endif + +void* aligned_malloc(size_t size, size_t alignment) +{ +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC + return ae_static_malloc(size, alignment); +#else + char *result = NULL; + void *block; + size_t alloc_size; +#if defined(ALGLIB_REDZONE) + char *redzone0; + char *redzone1; +#endif + + if( size==(size_t)0 ) + return NULL; + if( _force_malloc_failure ) + return NULL; + if( _malloc_failure_after>0 && _alloc_counter_total>=_malloc_failure_after ) + return NULL; + + /* + * Allocate, handling case with alignment=1 specially (no padding is added) + * + */ + if( alignment==0 ) + alignment = AE_DATA_ALIGN; + alloc_size = 2*sizeof(void*)+size; + if( alignment>1 ) + alloc_size += alignment-1; +#if defined(ALGLIB_REDZONE) + alloc_size += 2*(ALGLIB_REDZONE); +#endif + block = malloc(alloc_size); + if( block==NULL ) + return NULL; + result = (char*)block+2*sizeof(void*); + result = (char*)ae_align(result, alignment); + *((void**)(result-sizeof(void*))) = block; +#if defined(ALGLIB_REDZONE) + redzone0 = result; + result = redzone0+(ALGLIB_REDZONE); + redzone1 = result+size; + ae_assert(ae_misalignment(result,alignment)==0, "ALGLIB: improperly configured red zone size - is not multiple of the current alignment", NULL); + *((void**)(redzone0-2*sizeof(void*))) = redzone1; + memset(redzone0, _ALGLIB_REDZONE_VAL, ALGLIB_REDZONE); + memset(redzone1, _ALGLIB_REDZONE_VAL, ALGLIB_REDZONE); +#endif + + /* update counters (if flag is set) */ + if( _use_alloc_counter ) + { + ae_optional_atomic_add_i(&_alloc_counter, 1); + ae_optional_atomic_add_i(&_alloc_counter_total, 1); + } + if( _use_dbg_counters ) + ae_optional_atomic_add_i(&_dbg_alloc_total, (ae_int_t)size); + + /* return */ + return (void*)result; +#endif +} + +void* aligned_extract_ptr(void *block) +{ +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC + return NULL; +#else + char *ptr; + if( block==NULL ) + return NULL; + ptr = (char*)block; +#if defined(ALGLIB_REDZONE) + ptr -= (ALGLIB_REDZONE); +#endif + ptr -= sizeof(void*); + return *((void**)ptr); +#endif +} + +void aligned_free(void *block) +{ +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC + ae_static_free(block); +#else + /* + * Handle NULL input + */ + if( block==NULL ) + return; + + /* + * If red zone is activated, check it before deallocation + */ +#if defined(ALGLIB_REDZONE) + { + char *redzone0 = (char*)block-(ALGLIB_REDZONE); + char *redzone1 = (char*)(*((void**)(redzone0-2*sizeof(void*)))); + ae_int_t i; + for(i=0; i<(ALGLIB_REDZONE); i++) + { + if( redzone0[i]!=_ALGLIB_REDZONE_VAL ) + { + const char *msg = "ALGLIB: red zone corruption is detected (write prior to the block beginning?)"; + fprintf(stderr, "%s\n", msg); + ae_assert(ae_false, msg, NULL); + } + if( redzone1[i]!=_ALGLIB_REDZONE_VAL ) + { + const char *msg = "ALGLIB: red zone corruption is detected (write past the end of the block?)"; + fprintf(stderr, "%s\n", msg); + ae_assert(ae_false, msg, NULL); + } + } + } +#endif + + /* + * Free the memory and optionally update allocation counters + */ + free(aligned_extract_ptr(block)); + if( _use_alloc_counter ) + ae_optional_atomic_sub_i(&_alloc_counter, 1); +#endif +} + +void* eternal_malloc(size_t size) +{ + if( size==(size_t)0 ) + return NULL; + if( _force_malloc_failure ) + return NULL; + return malloc(size); +} + +/************************************************************************ +Allocate memory with automatic alignment. + +Returns NULL when zero size is specified. + +Error handling: +* if state is NULL, returns NULL on allocation error +* if state is not NULL, calls ae_break() on allocation error +************************************************************************/ +void* ae_malloc(size_t size, ae_state *state) +{ + void *result; + if( size==(size_t)0 ) + return NULL; + result = aligned_malloc(size,AE_DATA_ALIGN); + if( result==NULL && state!=NULL) + ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); + return result; +} + +/************************************************************************ +Allocate memory with automatic alignment and zero-fill. + +Returns NULL when zero size is specified. + +Error handling: +* if state is NULL, returns NULL on allocation error +* if state is not NULL, calls ae_break() on allocation error +************************************************************************/ +void* ae_malloc_zero(size_t size, ae_state *state) +{ + void *result = ae_malloc(size, state); + if( result!=NULL ) + memset(result, 0, size); + return result; +} + +void ae_free(void *p) +{ + if( p!=NULL ) + aligned_free(p); +} + +/************************************************************************ +Sets pointers to the matrix rows. + +* dst must be correctly initialized matrix +* dst->data.ptr points to the beginning of memory block allocated for + row pointers. +* dst->ptr - undefined (initialized during algorithm processing) +* storage parameter points to the beginning of actual storage +************************************************************************/ +void ae_matrix_update_row_pointers(ae_matrix *dst, void *storage) +{ + char *p_base; + void **pp_ptr; + ae_int_t i; + if( dst->rows>0 && dst->cols>0 ) + { + p_base = (char*)storage; + pp_ptr = (void**)dst->data.ptr; + dst->ptr.pp_void = pp_ptr; + for(i=0; irows; i++, p_base+=dst->stride*ae_sizeof(dst->datatype)) + pp_ptr[i] = p_base; + } + else + dst->ptr.pp_void = NULL; +} + +/************************************************************************ +Returns size of datatype. +Zero for dynamic types like strings or multiple precision types. +************************************************************************/ +ae_int_t ae_sizeof(ae_datatype datatype) +{ + switch(datatype) + { + case DT_BOOL: return (ae_int_t)sizeof(ae_bool); + case DT_INT: return (ae_int_t)sizeof(ae_int_t); + case DT_REAL: return (ae_int_t)sizeof(double); + case DT_COMPLEX: return 2*(ae_int_t)sizeof(double); + default: return 0; + } +} + +/************************************************************************ +Checks that n bytes pointed by ptr are zero. + +This function is used in the constructors to check that instance fields +on entry are correctly initialized by zeros. +************************************************************************/ +ae_bool ae_check_zeros(const void *ptr, ae_int_t n) +{ + ae_int_t nu, nr, i; + unsigned long long c = (unsigned long long)0x0; + + /* + * determine leading and trailing lengths + */ + nu = n/(ae_int_t)sizeof(unsigned long long); + nr = n%(ae_int_t)sizeof(unsigned long long); + + /* + * handle leading nu long long elements + */ + if( nu>0 ) + { + const unsigned long long *p_ull; + p_ull = (const unsigned long long *)ptr; + for(i=0; i0 ) + { + const unsigned char *p_uc; + p_uc = ((const unsigned char *)ptr)+nu*(ae_int_t)sizeof(unsigned long long); + for(i=0; iflags = (ae_uint64_t)0x0; + + /* + * p_next points to itself because: + * * correct program should be able to detect end of the list + * by looking at the ptr field. + * * NULL p_next may be used to distinguish automatic blocks + * (in the list) from non-automatic (not in the list) + */ + state->last_block.p_next = &(state->last_block); + state->last_block.deallocator = NULL; + state->last_block.ptr = DYN_BOTTOM; + state->p_top_block = &(state->last_block); + state->break_jump = NULL; + state->error_msg = ""; + + /* + * determine endianness and initialize precomputed IEEE special quantities. + */ + state->endianness = ae_get_endianness(); + if( state->endianness==AE_LITTLE_ENDIAN ) + { + vp = (ae_int32_t*)(&state->v_nan); + vp[0] = 0; + vp[1] = (ae_int32_t)0x7FF80000; + vp = (ae_int32_t*)(&state->v_posinf); + vp[0] = 0; + vp[1] = (ae_int32_t)0x7FF00000; + vp = (ae_int32_t*)(&state->v_neginf); + vp[0] = 0; + vp[1] = (ae_int32_t)0xFFF00000; + } + else if( state->endianness==AE_BIG_ENDIAN ) + { + vp = (ae_int32_t*)(&state->v_nan); + vp[1] = 0; + vp[0] = (ae_int32_t)0x7FF80000; + vp = (ae_int32_t*)(&state->v_posinf); + vp[1] = 0; + vp[0] = (ae_int32_t)0x7FF00000; + vp = (ae_int32_t*)(&state->v_neginf); + vp[1] = 0; + vp[0] = (ae_int32_t)0xFFF00000; + } + else + abort(); + + /* + * set threading information + */ + state->worker_thread = NULL; + state->parent_task = NULL; + state->thread_exception_handler = NULL; +} + + +/************************************************************************ +This function clears ALGLIB environment state. +All dynamic data controlled by state are freed. +************************************************************************/ +void ae_state_clear(ae_state *state) +{ + while( state->p_top_block->ptr!=DYN_BOTTOM ) + ae_frame_leave(state); +} + + +/************************************************************************ +This function sets jump buffer for error handling. + +buf may be NULL. +************************************************************************/ +void ae_state_set_break_jump(ae_state *state, jmp_buf *buf) +{ + state->break_jump = buf; +} + + +/************************************************************************ +This function sets flags member of the ae_state structure +************************************************************************/ +void ae_state_set_flags(ae_state *state, ae_uint64_t flags) +{ + state->flags = flags; +} + +/************************************************************************ +This function returns effective flags subject to combination of state-local +and global flags. +************************************************************************/ +ae_uint64_t ae_get_effective_flags(ae_state *state) +{ + ae_uint64_t result = 0x0; + result |= (((state->flags&_ALGLIB_FLG_THREADING_MASK_WRK )==_ALGLIB_FLG_USE_GLOBAL) ? _alglib_global_flags : state->flags)&_ALGLIB_FLG_THREADING_MASK_WRK; + result |= (((state->flags&_ALGLIB_FLG_THREADING_MASK_CBK )==_ALGLIB_FLG_USE_GLOBAL) ? _alglib_global_flags : state->flags)&_ALGLIB_FLG_THREADING_MASK_CBK; + result |= (((state->flags&_ALGLIB_FLG_BACKEND_MASK_LINALG)==_ALGLIB_FLG_USE_GLOBAL) ? _alglib_global_flags : state->flags)&_ALGLIB_FLG_BACKEND_MASK_LINALG; + result |= (((state->flags&_ALGLIB_FLG_BACKEND_MASK_DSS )==_ALGLIB_FLG_USE_GLOBAL) ? _alglib_global_flags : state->flags)&_ALGLIB_FLG_BACKEND_MASK_DSS; + result |= state->worker_thread!=NULL ? _ALGLIB_FLG_WORKER_THREAD : 0x0; + return result; +} + + +/************************************************************************ +This function makes new stack frame. + +This function takes two parameters: environment state and pointer to the +dynamic block which will be used as indicator of the frame beginning. +This dynamic block must be initialized by caller and mustn't be changed/ +deallocated/reused till ae_leave_frame called. It may be global or local +variable (local is even better). +************************************************************************/ +void ae_frame_make(ae_state *state, ae_frame *tmp) +{ + tmp->db_marker.p_next = state->p_top_block; + tmp->db_marker.deallocator = NULL; + tmp->db_marker.ptr = DYN_FRAME; + state->p_top_block = &tmp->db_marker; +} + + +/************************************************************************ +This function leaves current stack frame and deallocates all automatic +dynamic blocks which were attached to this frame. +************************************************************************/ +void ae_frame_leave(ae_state *state) +{ + while( state->p_top_block->ptr!=DYN_FRAME && state->p_top_block->ptr!=DYN_BOTTOM) + { + if( state->p_top_block->ptr!=NULL && state->p_top_block->deallocator!=NULL) + (state->p_top_block->deallocator)(state->p_top_block->ptr); + state->p_top_block = state->p_top_block->p_next; + } + state->p_top_block = state->p_top_block->p_next; +} + + +/************************************************************************ +This function attaches block to the dynamic block list + +block block +state ALGLIB environment state + +This function does NOT generate exceptions. + +NOTES: +* never call it for special blocks which marks frame boundaries! +************************************************************************/ +void ae_db_attach(ae_dyn_block *block, ae_state *state) +{ + block->p_next = state->p_top_block; + state->p_top_block = block; +} + + +/************************************************************************ +This function initializes dynamic block: + +block destination block, MUST be zero-filled on entry +size size (in bytes), >=0. +state ALGLIB environment state, non-NULL +make_automatic if true, vector is added to the dynamic block list + +block is assumed to be uninitialized, its fields are ignored. You may +call this function with zero size in order to register block in the +dynamic list. + +Error handling: calls ae_break() on allocation error. Block is left in +valid state (empty, but valid). + +NOTES: +* never call it for blocks which are already in the list; use ae_db_realloc + for already allocated blocks. + +NOTE: no memory allocation is performed for initialization with size=0 +************************************************************************/ +void ae_db_init(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(block,(ae_int_t)sizeof(*block))); + + /* + * NOTE: these strange dances around block->ptr are necessary + * in order to correctly handle possible exceptions during + * memory allocation. + */ + if( size<0 ) + ae_assert(ae_false, "ae_db_init(): negative size", state); + block->ptr = NULL; + block->valgrind_hint = NULL; + if( make_automatic ) + ae_db_attach(block, state); + else + block->p_next = NULL; + if( size!=0 ) + { + block->ptr = ae_malloc((size_t)size, state); + block->valgrind_hint = aligned_extract_ptr(block->ptr); + } + block->deallocator = ae_free; +} + + +/************************************************************************ +This function realloc's dynamic block: + +block destination block (initialized) +size new size (in bytes) +state ALGLIB environment state + +block is assumed to be initialized. + +This function: +* deletes old contents +* preserves automatic state + +Error handling: calls ae_break() on allocation error. Block is left in +valid state - empty, but valid. + +NOTES: +* never call it for special blocks which mark frame boundaries! +************************************************************************/ +void ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state) +{ + AE_CRITICAL_ASSERT(state!=NULL); + + /* + * NOTE: these strange dances around block->ptr are necessary + * in order to correctly handle possible exceptions during + * memory allocation. + */ + ae_assert(size>=0, "ae_db_realloc(): negative size", state); + if( block->ptr!=NULL ) + { + ((ae_destructor)block->deallocator)(block->ptr); + block->ptr = NULL; + block->valgrind_hint = NULL; + } + block->ptr = ae_malloc((size_t)size, state); + block->valgrind_hint = aligned_extract_ptr(block->ptr); + block->deallocator = ae_free; +} + + +/************************************************************************ +This function clears dynamic block (releases all dynamically allocated +memory). Dynamic block may be in automatic management list - in this case +it will NOT be removed from list. + +block destination block (initialized) + +NOTES: +* never call it for special blocks which marks frame boundaries! +************************************************************************/ +void ae_db_free(ae_dyn_block *block) +{ + if( block->ptr!=NULL ) + ((ae_destructor)block->deallocator)(block->ptr); + block->ptr = NULL; + block->valgrind_hint = NULL; + block->deallocator = ae_free; +} + +/************************************************************************ +This function swaps contents of two dynamic blocks (pointers and +deallocators) leaving other parameters (automatic management settings, +etc.) unchanged. + +NOTES: +* never call it for special blocks which marks frame boundaries! +************************************************************************/ +void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2) +{ + void (*deallocator)(void*) = NULL; + void * volatile ptr; + void * valgrind_hint; + + ptr = block1->ptr; + valgrind_hint = block1->valgrind_hint; + deallocator = block1->deallocator; + + block1->ptr = block2->ptr; + block1->valgrind_hint = block2->valgrind_hint; + block1->deallocator = block2->deallocator; + + block2->ptr = ptr; + block2->valgrind_hint = valgrind_hint; + block2->deallocator = deallocator; +} + +/************************************************************************* +This function creates ae_vector. +Vector size may be zero. Vector contents is uninitialized. + +dst destination vector, MUST be zero-filled (we check it + and call abort() if *dst is non-zero; the rationale is + that we can not correctly handle errors in constructors + without zero-filling). +size vector size, may be zero +datatype guess what... +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +NOTE: no memory allocation is performed for initialization with size=0 +*************************************************************************/ +void ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state, ae_bool make_automatic) +{ + /* + * Integrity checks + */ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + ae_assert(size>=0, "ae_vector_init(): negative size", state); + + /* prepare for possible errors during allocation */ + dst->cnt = 0; + dst->ptr.p_ptr = NULL; + + /* init */ + ae_db_init(&dst->data, size*ae_sizeof(datatype), state, make_automatic); + dst->cnt = size; + dst->datatype = datatype; + dst->ptr.p_ptr = dst->data.ptr; + dst->is_attached = ae_false; +} + + +/************************************************************************ +This function creates copy of ae_vector. New copy of the data is created, +which is managed and owned by newly initialized vector. + +dst destination vector, MUST be zero-filled (we check it + and call abort() if *dst is non-zero; the rationale is + that we can not correctly handle errors in constructors + without zero-filling). +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_vector_init_copy(ae_vector *dst, const ae_vector *src, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + + ae_vector_init(dst, src->cnt, src->datatype, state, make_automatic); + if( src->cnt!=0 ) + memmove(dst->ptr.p_ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); +} + +/************************************************************************ +This function initializes ae_vector using X-structure as source. New copy +of data is created, which is owned/managed by ae_vector structure. Both +structures (source and destination) remain completely independent after +this call. + +dst destination vector, MUST be zero-filled (we check it + and call abort() if *dst is non-zero; the rationale is + that we can not correctly handle errors in constructors + without zero-filling). +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + + ae_vector_init(dst, (ae_int_t)src->cnt, (ae_datatype)src->datatype, state, make_automatic); + if( src->cnt>0 ) + memmove(dst->ptr.p_ptr, src->x_ptr.p_ptr, (size_t)(((ae_int_t)src->cnt)*ae_sizeof((ae_datatype)src->datatype))); +} + +/************************************************************************ +This function initializes ae_vector using X-structure as a source. +Depending on the action parameter, the following actions can be +performed: + +* action=INIT_ATTACH_OR_COPY -> depending on alignment of src->x_ptr, + dst is either attached to src (if src is properly aligned) or a new + copy of the data is created in dst. + +dst destination vector, MUST be zero-filled (we check it + and call abort() if *dst is non-zero; the rationale is + that we can not correctly handle errors in constructors + without zero-filling). +src well, it is source. Can be zero-length, but datatype must + be initialize in any case. +action the following values are allowed: + * INIT_ATTACH_OR_COPY +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_vector_init_from_x2(ae_vector *dst, x_vector *src, ae_int_t action, ae_state *state, ae_bool make_automatic) +{ + volatile ae_int_t cnt; + + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(action==INIT_ATTACH_OR_COPY); + + /* integrity check */ + cnt = (ae_int_t)src->cnt; + ae_assert(cnt==src->cnt, "ae_vector_init_from_x2(): 32/64 overflow", state); + ae_assert(cnt>=0, "ae_vector_init_from_x2(): negative length", state); + + /* proceed */ + if( action==INIT_ATTACH_OR_COPY ) + { + /* handle empty inputs */ + if( src->cnt==0 ) + { + ae_vector_init(dst, 0, (ae_datatype)src->datatype, state, make_automatic); + return; + } + + /* the input is non-empty; is it aligned? */ + if( ae_misalignment(src->x_ptr.p_ptr, AE_DATA_ALIGN)!=0 ) + { + /* the input is misaligned, create a copy */ + ae_vector_init(dst, (ae_int_t)src->cnt, (ae_datatype)src->datatype, state, make_automatic); + memmove(dst->ptr.p_ptr, src->x_ptr.p_ptr, (size_t)(((ae_int_t)src->cnt)*ae_sizeof((ae_datatype)src->datatype))); + } + else + { + /* the input is aligned, we can attach */ + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + ae_db_init(&dst->data, 0, state, make_automatic); /* zero-size init in order to correctly register in the frame */ + dst->datatype = (ae_datatype)src->datatype; + dst->cnt = cnt; + dst->ptr.p_ptr = src->x_ptr.p_ptr; + dst->is_attached = ae_true; + } + return; + } +} + +/************************************************************************ +This function initializes ae_vector using X-structure as source. + +New vector is attached to source: +* DST shares memory with SRC +* both DST and SRC are writable - all writes to DST change elements of + SRC and vice versa. +* DST can be reallocated with ae_vector_set_length(), in this case SRC + remains untouched +* SRC, however, CAN NOT BE REALLOCATED AS LONG AS DST EXISTS + +NOTE: is_attached field is set to ae_true in order to indicate that + vector does not own its memory. + +dst destination vector +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_vector_init_attach_to_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic) +{ + volatile ae_int_t cnt; + + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + cnt = (ae_int_t)src->cnt; + + /* ensure that size is correct */ + ae_assert(cnt==src->cnt, "ae_vector_init_attach_to_x(): 32/64 overflow", state); + ae_assert(cnt>=0, "ae_vector_init_attach_to_x(): negative length", state); + + /* prepare for possible errors during allocation */ + dst->cnt = 0; + dst->ptr.p_ptr = NULL; + dst->datatype = (ae_datatype)src->datatype; + + /* zero-size init in order to correctly register in the frame */ + ae_db_init(&dst->data, 0, state, make_automatic); + + /* init */ + dst->cnt = cnt; + dst->ptr.p_ptr = src->x_ptr.p_ptr; + dst->is_attached = ae_true; +} + +/************************************************************************ +This function changes length of ae_vector. + +dst destination vector +newsize vector size, may be zero +state ALGLIB environment state, can not be NULL + +Error handling: calls ae_break() on allocation error + +NOTES: +* vector must be initialized +* all contents is destroyed during setlength() call +* new size may be zero. +************************************************************************/ +void ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state) +{ + AE_CRITICAL_ASSERT(state!=NULL); + ae_assert(newsize>=0, "ae_vector_set_length(): negative size", state); + if( dst->cnt==newsize ) + return; + + /* realloc, being ready for exception during reallocation (cnt=ptr=0 on entry) */ + dst->cnt = 0; + dst->ptr.p_ptr = NULL; + ae_db_realloc(&dst->data, newsize*ae_sizeof(dst->datatype), state); + dst->cnt = newsize; + dst->ptr.p_ptr = dst->data.ptr; +} + +/************************************************************************ +This function resized ae_vector, preserving previously existing elements. +Values of elements added during vector growth is undefined. + +dst destination vector +newsize vector size, may be zero +state ALGLIB environment state, can not be NULL + +Error handling: calls ae_break() on allocation error + +NOTES: +* vector must be initialized +* new size may be zero. +************************************************************************/ +void ae_vector_resize(ae_vector *dst, ae_int_t newsize, ae_state *state) +{ + ae_vector tmp; + ae_int_t bytes_total; + + memset(&tmp, 0, sizeof(tmp)); + ae_vector_init(&tmp, newsize, dst->datatype, state, ae_false); + bytes_total = (dst->cntcnt : newsize)*ae_sizeof(dst->datatype); + if( bytes_total>0 ) + memmove(tmp.ptr.p_ptr, dst->ptr.p_ptr, (size_t)bytes_total); + ae_swap_vectors(dst, &tmp); + ae_vector_clear(&tmp); +} + + +/************************************************************************ +This function provides "CLEAR" functionality for vector (contents is +cleared, but structure still left in valid state). + +The function clears vector contents (releases all dynamically allocated +memory). Vector may be in automatic management list - in this case it +will NOT be removed from list. + +IMPORTANT: this function does NOT invalidates dst; it just releases all +dynamically allocated storage, but dst still may be used after call to +ae_vector_set_length(). + +dst destination vector +************************************************************************/ +void ae_vector_clear(ae_vector *dst) +{ + dst->cnt = 0; + ae_db_free(&dst->data); + dst->ptr.p_ptr = 0; + dst->is_attached = ae_false; +} + + +/************************************************************************ +This function provides "DESTROY" functionality for vector (contents is +cleared, all internal structures are destroyed). For vectors it is same +as CLEAR. + +dst destination vector +************************************************************************/ +void ae_vector_destroy(ae_vector *dst) +{ + ae_vector_clear(dst); +} + + +/************************************************************************ +This function efficiently swaps contents of two vectors, leaving other +pararemeters (automatic management, etc.) unchanged. +************************************************************************/ +void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2) +{ + ae_int_t cnt; + ae_datatype datatype; + void *p_ptr; + + ae_assert(!vec1->is_attached, "ALGLIB: internal error, attempt to swap vectors attached to X-object", NULL); + ae_assert(!vec2->is_attached, "ALGLIB: internal error, attempt to swap vectors attached to X-object", NULL); + + ae_db_swap(&vec1->data, &vec2->data); + + cnt = vec1->cnt; + datatype = vec1->datatype; + p_ptr = vec1->ptr.p_ptr; + vec1->cnt = vec2->cnt; + vec1->datatype = vec2->datatype; + vec1->ptr.p_ptr = vec2->ptr.p_ptr; + vec2->cnt = cnt; + vec2->datatype = datatype; + vec2->ptr.p_ptr = p_ptr; +} + +/************************************************************************ +This function creates ae_matrix. + +Matrix size may be zero, in such cases both rows and cols are zero. +Matrix contents is uninitialized. + +dst destination matrix, must be zero-filled +rows rows count +cols cols count +datatype element type +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, matrix will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. + +NOTE: no memory allocation is performed for initialization with rows=cols=0 +************************************************************************/ +void ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + ae_assert(rows>=0 && cols>=0, "ae_matrix_init(): negative length", state); + + /* if one of rows/cols is zero, another MUST be too; perform quick exit */ + if( rows==0 || cols==0 ) + { + dst->rows = 0; + dst->cols = 0; + dst->is_attached = ae_false; + dst->ptr.pp_void = NULL; + dst->stride = 0; + dst->datatype = datatype; + ae_db_init(&dst->data, 0, state, make_automatic); + return; + } + + /* init, being ready for exception during allocation (rows=cols=ptr=NULL on entry) */ + dst->is_attached = ae_false; + dst->rows = 0; + dst->cols = 0; + dst->ptr.pp_void = NULL; + dst->stride = cols; + while( dst->stride*ae_sizeof(datatype)%AE_DATA_ALIGN!=0 ) + dst->stride++; + dst->datatype = datatype; + ae_db_init(&dst->data, rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(datatype))+AE_DATA_ALIGN-1, state, make_automatic); + dst->rows = rows; + dst->cols = cols; + ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+rows*(ae_int_t)sizeof(void*),AE_DATA_ALIGN)); +} + + +/************************************************************************ +This function creates copy of ae_matrix. A new copy of the data is created. + +dst destination matrix, must be zero-filled +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, matrix will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_matrix_init_copy(ae_matrix *dst, const ae_matrix *src, ae_state *state, ae_bool make_automatic) +{ + ae_int_t i; + ae_matrix_init(dst, src->rows, src->cols, src->datatype, state, make_automatic); + if( src->rows!=0 && src->cols!=0 ) + { + if( dst->stride==src->stride ) + memmove(dst->ptr.pp_void[0], src->ptr.pp_void[0], (size_t)(src->rows*src->stride*ae_sizeof(src->datatype))); + else + for(i=0; irows; i++) + memmove(dst->ptr.pp_void[i], src->ptr.pp_void[i], (size_t)(dst->cols*ae_sizeof(dst->datatype))); + } +} + + +/************************************************************************ +This function initializes ae_matrix using X-structure as source. New copy +of data is created, which is owned/managed by ae_matrix structure. Both +structures (source and destination) remain completely independent after +this call. + +dst destination matrix, must be zero-filled +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, matrix will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic) +{ + char *p_src_row; + char *p_dst_row; + ae_int_t row_size; + ae_int_t i; + AE_CRITICAL_ASSERT(state!=NULL); + ae_matrix_init(dst, (ae_int_t)src->rows, (ae_int_t)src->cols, (ae_datatype)src->datatype, state, make_automatic); + if( src->rows!=0 && src->cols!=0 ) + { + p_src_row = (char*)src->x_ptr.p_ptr; + p_dst_row = (char*)(dst->ptr.pp_void[0]); + row_size = ae_sizeof((ae_datatype)src->datatype)*(ae_int_t)src->cols; + for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof((ae_datatype)src->datatype), p_dst_row+=dst->stride*ae_sizeof((ae_datatype)src->datatype)) + memmove(p_dst_row, p_src_row, (size_t)(row_size)); + } +} + + +/************************************************************************ +This function initializes ae_matrix using X-structure as a source. +Depending on the action parameter, the following actions can be +performed: + +* action=INIT_ATTACH_OR_COPY -> depending on alignment of src->x_ptr and + on the row stride (is it aligned too or not) dst is either attached to + src (if src is properly aligned) or a new copy of the data is created + in dst. + +dst destination matrix, MUST be zero-filled (we check it + and call abort() if *dst is non-zero; the rationale is + that we can not correctly handle errors in constructors + without zero-filling). +src well, it is source. Can be zero-length, but datatype must + be initialize in any case. +action the following values are allowed: + * INIT_ATTACH_OR_COPY +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, matrix will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_matrix_init_from_x2(ae_matrix *dst, x_matrix *src, ae_int_t action, ae_state *state, ae_bool make_automatic) +{ + volatile ae_int_t rows, cols, stride; + char *p_src_row; + char *p_dst_row; + ae_int_t row_size, src_stride_bytes; + ae_int_t i; + + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(action==INIT_ATTACH_OR_COPY); + + /* integrity check */ + rows = (ae_int_t)src->rows; + cols = (ae_int_t)src->cols; + stride = (ae_int_t)src->stride; + ae_assert(rows==src->rows, "ae_matrix_init_from_x2(): 32/64 overflow", state); + ae_assert(cols==src->cols, "ae_matrix_init_from_x2(): 32/64 overflow", state); + ae_assert(stride==src->stride, "ae_matrix_init_from_x2(): 32/64 overflow", state); + ae_assert(rows>=0 && cols>=0, "ae_matrix_init_from_x2(): negative length", state); + + /* attach or copy, depending on alignment */ + if( action==INIT_ATTACH_OR_COPY ) + { + /* handle empty inputs */ + if( src->rows==0 || src->cols==0 ) + { + ae_matrix_init(dst, 0, 0, (ae_datatype)src->datatype, state, make_automatic); + return; + } + + /* the input is non-empty; is it aligned? */ + src_stride_bytes = stride*ae_sizeof((ae_datatype)src->datatype); + if( ae_misalignment(src->x_ptr.p_ptr, AE_DATA_ALIGN)!=0 || src_stride_bytes%AE_DATA_ALIGN!=0 ) + { + /* the input is not properly aligned, create a copy */ + ae_int_t dst_stride_bytes; + ae_matrix_init(dst, (ae_int_t)src->rows, (ae_int_t)src->cols, (ae_datatype)src->datatype, state, make_automatic); + dst_stride_bytes = dst->stride*ae_sizeof((ae_datatype)src->datatype); + p_src_row = (char*)src->x_ptr.p_ptr; + p_dst_row = (char*)(dst->ptr.pp_void[0]); + row_size = ae_sizeof((ae_datatype)src->datatype)*(ae_int_t)src->cols; + for(i=0; irows; i++, p_src_row+=src_stride_bytes, p_dst_row+=dst_stride_bytes) + memmove(p_dst_row, p_src_row, (size_t)(row_size)); + } + else + { + char *p_row; + void **pp_ptr; + + /* the input is aligned, attach */ + ae_db_init(&dst->data, rows*(ae_int_t)sizeof(void*), state, make_automatic); + dst->is_attached = ae_true; + dst->rows = rows; + dst->cols = cols; + dst->stride = stride; + dst->datatype = (ae_datatype)src->datatype; + p_row = (char*)src->x_ptr.p_ptr; + pp_ptr = (void**)dst->data.ptr; + dst->ptr.pp_void = pp_ptr; + for(i=0; irows; i++, p_row+=src_stride_bytes) + pp_ptr[i] = p_row; + } + + /* done */ + return; + } +} + +/************************************************************************ +This function initializes ae_matrix using X-structure as source. + +New matrix is attached to source: +* DST shares memory with SRC +* both DST and SRC are writable - all writes to DST change elements of + SRC and vice versa. +* DST can be reallocated with ae_matrix_set_length(), in this case SRC + remains untouched +* SRC, however, CAN NOT BE REALLOCATED AS LONG AS DST EXISTS + +dst destination matrix, must be zero-filled +src well, it is source +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, matrix will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_matrix_init_attach_to_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic) +{ + ae_int_t rows, cols; + + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + rows = (ae_int_t)src->rows; + cols = (ae_int_t)src->cols; + + /* check that X-source is densely packed */ + ae_assert(src->cols==src->stride, "ae_matrix_init_attach_to_x(): unsupported stride", state); + + /* ensure that size is correct */ + ae_assert(rows==src->rows, "ae_matrix_init_attach_to_x(): 32/64 overflow", state); + ae_assert(cols==src->cols, "ae_matrix_init_attach_to_x(): 32/64 overflow", state); + ae_assert(rows>=0 && cols>=0, "ae_matrix_init_attach_to_x(): negative length", state); + + /* if one of rows/cols is zero, another MUST be too */ + if( rows==0 || cols==0 ) + { + rows = 0; + cols = 0; + } + + /* init, being ready for allocation error */ + dst->is_attached = ae_true; + dst->rows = 0; + dst->cols = 0; + dst->stride = cols; + dst->datatype = (ae_datatype)src->datatype; + dst->ptr.pp_void = NULL; + ae_db_init(&dst->data, rows*(ae_int_t)sizeof(void*), state, make_automatic); + dst->rows = rows; + dst->cols = cols; + if( dst->rows>0 && dst->cols>0 ) + { + ae_int_t i, rowsize; + char *p_row; + void **pp_ptr; + + p_row = (char*)src->x_ptr.p_ptr; + rowsize = dst->stride*ae_sizeof(dst->datatype); + pp_ptr = (void**)dst->data.ptr; + dst->ptr.pp_void = pp_ptr; + for(i=0; irows; i++, p_row+=rowsize) + pp_ptr[i] = p_row; + } +} + + +/************************************************************************ +This function changes length of ae_matrix. + +dst destination matrix +rows size, may be zero +cols size, may be zero +state ALGLIB environment state + +Error handling: +* if state is NULL, returns ae_false on allocation error +* if state is not NULL, calls ae_break() on allocation error +* returns ae_true on success + +NOTES: +* matrix must be initialized +* all contents is destroyed during setlength() call +* new size may be zero. +************************************************************************/ +void ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state) +{ + AE_CRITICAL_ASSERT(state!=NULL); + ae_assert(rows>=0 && cols>=0, "ae_matrix_set_length(): negative length", state); + if( dst->rows==rows && dst->cols==cols ) + return; + + /* prepare stride */ + dst->stride = cols; + while( dst->stride*ae_sizeof(dst->datatype)%AE_DATA_ALIGN!=0 ) + dst->stride++; + + /* realloc, being ready for an exception during reallocation (rows=cols=0 on entry) */ + dst->rows = 0; + dst->cols = 0; + dst->ptr.pp_void = NULL; + ae_db_realloc(&dst->data, rows*((ae_int_t)sizeof(void*)+dst->stride*ae_sizeof(dst->datatype))+AE_DATA_ALIGN-1, state); + dst->rows = rows; + dst->cols = cols; + + /* update pointers to rows */ + ae_matrix_update_row_pointers(dst, ae_align((char*)dst->data.ptr+dst->rows*(ae_int_t)sizeof(void*),AE_DATA_ALIGN)); +} + + +/************************************************************************ +This function provides "CLEAR" functionality for vector (contents is +cleared, but structure still left in valid state). + +The function clears matrix contents (releases all dynamically allocated +memory). Matrix may be in automatic management list - in this case it +will NOT be removed from list. + +IMPORTANT: this function does NOT invalidates dst; it just releases all +dynamically allocated storage, but dst still may be used after call to +ae_matrix_set_length(). + +dst destination matrix +************************************************************************/ +void ae_matrix_clear(ae_matrix *dst) +{ + dst->rows = 0; + dst->cols = 0; + dst->stride = 0; + ae_db_free(&dst->data); + dst->ptr.p_ptr = 0; + dst->is_attached = ae_false; +} + + +/************************************************************************ +This function provides "DESTROY" functionality for matrix (contents is +cleared, but structure still left in valid state). + +For matrices it is same as CLEAR. + +dst destination matrix +************************************************************************/ +void ae_matrix_destroy(ae_matrix *dst) +{ + ae_matrix_clear(dst); +} + + +/************************************************************************ +This function efficiently swaps contents of two vectors, leaving other +pararemeters (automatic management, etc.) unchanged. +************************************************************************/ +void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2) +{ + ae_int_t rows; + ae_int_t cols; + ae_int_t stride; + ae_datatype datatype; + void *p_ptr; + + ae_assert(!mat1->is_attached, "ALGLIB: internal error, attempt to swap matrices attached to X-object", NULL); + ae_assert(!mat2->is_attached, "ALGLIB: internal error, attempt to swap matrices attached to X-object", NULL); + + ae_db_swap(&mat1->data, &mat2->data); + + rows = mat1->rows; + cols = mat1->cols; + stride = mat1->stride; + datatype = mat1->datatype; + p_ptr = mat1->ptr.p_ptr; + + mat1->rows = mat2->rows; + mat1->cols = mat2->cols; + mat1->stride = mat2->stride; + mat1->datatype = mat2->datatype; + mat1->ptr.p_ptr = mat2->ptr.p_ptr; + + mat2->rows = rows; + mat2->cols = cols; + mat2->stride = stride; + mat2->datatype = datatype; + mat2->ptr.p_ptr = p_ptr; +} + + +/************************************************************************ +This function creates smart pointer structure. + +dst destination smart pointer, must be zero-filled +subscriber pointer to pointer which receives updates in the + internal object stored in ae_smart_ptr. Any update to + dst->ptr is translated to subscriber. Can be NULL. +exclusive if exclusive, the structure can receive ownership but + can not transfer ownership; any attempt to request release/transfer + will result in an exception. The pointer can be free, though. +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, pointer will be registered in the current frame + of the state structure; + +Error handling: +* on failure calls ae_break() with NULL state pointer. Usually it results + in abort() call. + +After initialization, smart pointer stores NULL pointer. +************************************************************************/ +void ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_bool exclusive, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + dst->subscriber = subscriber; + dst->ptr = NULL; + if( dst->subscriber!=NULL ) + *(dst->subscriber) = dst->ptr; + dst->is_owner = ae_false; + dst->is_dynamic = ae_false; + dst->exclusive = exclusive; + dst->size_of_object = 0; + dst->copy_constructor = NULL; + dst->destructor = NULL; + dst->frame_entry.deallocator = ae_smart_ptr_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); +} + + +/************************************************************************ +This function clears smart pointer structure. + +dst destination smart pointer. + +After call to this function smart pointer contains NULL reference, which +is propagated to its subscriber (in cases non-NULL subscruber was +specified during pointer creation). +************************************************************************/ +void ae_smart_ptr_clear(void *_dst) +{ + ae_smart_ptr *dst = (ae_smart_ptr*)_dst; + if( dst->is_owner && dst->ptr!=NULL ) + { + dst->destructor(dst->ptr); + if( dst->is_dynamic ) + ae_free(dst->ptr); + } + dst->is_owner = ae_false; + dst->is_dynamic = ae_false; + dst->ptr = NULL; + dst->size_of_object = 0; + dst->copy_constructor = NULL; + dst->destructor = NULL; + if( dst->subscriber!=NULL ) + *(dst->subscriber) = NULL; +} + + +/************************************************************************ +This function dstroys smart pointer structure (same as clearing it). + +dst destination smart pointer. +************************************************************************/ +void ae_smart_ptr_destroy(void *_dst) +{ + ae_smart_ptr_clear(_dst); +} + + +/************************************************************************ +This function assigns pointer to ae_smart_ptr structure. + +dst destination smart pointer. +new_ptr new pointer to assign +is_owner whether smart pointer owns new_ptr; if dst is in an exclusive + mode, is_owner must be true +is_dynamic whether object is dynamic - clearing such object + requires BOTH calling destructor function AND calling + ae_free() for memory occupied by object. +obj_size in-memory size of the object. Ignored for is_owner==false. +cc copy constructor, can not be NULL for new_ptr!=NULL +dd destructor function; can be NULL for is_owner==ae_false. + +In case smart pointer already contains non-NULL value and owns this value, +it is freed before assigning new pointer. + +Changes in pointer are propagated to its subscriber (in case non-NULL +subscriber was specified during pointer creation). + +You can specify NULL new_ptr, in which case is_owner/destroy/exclusive are ignored. +************************************************************************/ +void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, ae_int_t obj_size, ae_copy_constructor cc, ae_destructor dd) +{ + ae_assert(new_ptr==NULL || !is_owner || cc!=NULL, "ae_smart_ptr_assign: new_ptr!=NULL, is_owner, but copy constructor is NULL", NULL); + ae_assert(new_ptr==NULL || !is_owner || dd!=NULL, "ae_smart_ptr_assign: new_ptr!=NULL, is_owner, but destructor is NULL", NULL); + ae_assert(new_ptr==NULL || !is_owner || obj_size>0, "ae_smart_ptr_assign: new_ptr!=NULL, is_owner, but object size is zero", NULL); + ae_assert(!dst->exclusive || (is_owner || new_ptr==NULL), "ae_smart_ptr_assign: destination is in exclusive mode, but is_owner is false", NULL); + + if( dst->is_owner && dst->ptr!=NULL ) + { + dst->destructor(dst->ptr); + if( dst->is_dynamic ) + ae_free(dst->ptr); + } + if( new_ptr!=NULL ) + { + dst->ptr = new_ptr; + dst->is_owner = is_owner; + dst->is_dynamic = is_dynamic; + dst->size_of_object = is_owner ? obj_size : 0; + dst->copy_constructor = cc; + dst->destructor = dd; + } + else + { + dst->ptr = NULL; + dst->is_owner = ae_false; + dst->is_dynamic = ae_false; + dst->size_of_object = 0; + dst->copy_constructor = NULL; + dst->destructor = NULL; + } + if( dst->subscriber!=NULL ) + *(dst->subscriber) = dst->ptr; +} + + +/************************************************************************ +This function releases pointer owned by ae_smart_ptr structure: +* all internal fields are set to NULL +* destructor function for internal pointer is NOT called even when we own + this pointer. After this call ae_smart_ptr releases ownership of its + pointer and passes it to caller. +* changes in pointer are propagated to its subscriber (in case non-NULL + subscriber was specified during pointer creation). + +dst destination smart pointer. +************************************************************************/ +void ae_smart_ptr_release(ae_smart_ptr *dst) +{ + ae_assert(!dst->exclusive, "ae_smart_ptr_release: pointer is in exclusive mode, unable to release", NULL); + dst->is_owner = ae_false; + dst->is_dynamic = ae_false; + dst->ptr = NULL; + dst->size_of_object = 0; + dst->copy_constructor = NULL; + dst->destructor = NULL; + if( dst->subscriber!=NULL ) + *(dst->subscriber) = NULL; +} + + +/************************************************************************ +This function creates an empty opaque object structure. + +dst destination opaque object, must be zero-filled +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, pointer will be registered in the current frame + of the state structure; + +Error handling: +* on failure calls ae_break() with NULL state pointer. Usually it results + in abort() call. + +After initialization, opaque object is empty (stores NULL pointer) +************************************************************************/ +void ae_opaque_object_init(ae_opaque_object *dst, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + dst->ptr = NULL; + dst->obj_type = 0; + dst->obj_size = 0; + dst->opaque_copy_constructor = NULL; + dst->destructor = NULL; + dst->frame_entry.deallocator = ae_opaque_object_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); +} + + +/************************************************************************ +This function creates a deep copy of the opaque object (if possible). + +Depending on object type, its copy constructor may either: +* perform an actual deep copy +* allocate a new object with a special 'dummy' state + +dst destination opaque object, must be zero-filled +src opaque object +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, array will be registered in the current frame + of the state structure; +************************************************************************/ +void ae_opaque_object_init_copy(ae_opaque_object *dst, const ae_opaque_object *src, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,sizeof(*dst))); + + /* initialize array; we know that empty array has NULL internal pointers */ + ae_opaque_object_init(dst, state, make_automatic); + + /* copy fields */ + dst->obj_type = src->obj_type; + dst->obj_size = src->obj_size; + if( dst->obj_type!=0 ) + { + AE_CRITICAL_ASSERT(dst->obj_size>0); + dst->opaque_copy_constructor = src->opaque_copy_constructor; + dst->destructor = src->destructor; + dst->ptr = aligned_malloc(dst->obj_size,0); + dst->opaque_copy_constructor(dst->ptr, src->ptr, state); + } + else + { + AE_CRITICAL_ASSERT(dst->obj_size==0); + AE_CRITICAL_ASSERT(src->opaque_copy_constructor==NULL); + AE_CRITICAL_ASSERT(src->destructor==NULL); + } +} + + +/************************************************************************ +This function clears opaque object structure. + +dst destination pointer. + +After call to this function destination contains NULL reference, with +existing opaque instance being properly uninitialized +************************************************************************/ +void ae_opaque_object_clear(void *_dst) /* accepts ae_opaque_object* */ +{ + ae_opaque_object *dst = (ae_opaque_object*)_dst; + if( dst->obj_type!=0 ) + { + dst->destructor(dst->ptr); + aligned_free(dst->ptr); + } + dst->ptr = NULL; + dst->obj_type = 0; + dst->obj_size = 0; + dst->opaque_copy_constructor = NULL; + dst->destructor = NULL; +} + + +/************************************************************************ +This function dstroys smart pointer structure (same as clearing it). + +dst destination smart pointer. +************************************************************************/ +void ae_opaque_object_destroy(void *_dst) +{ + ae_opaque_object_clear(_dst); +} + + +/************************************************************************ +This function creates array of objects. + +dst preallocated destination, must be zero-filled +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, pointer will be registered in the current frame + of the state structure; + +Error handling: +* on failure calls ae_break() with NULL state pointer. Usually it results + in abort() call. + +After initialization, smart pointer stores NULL pointer. +************************************************************************/ +void ae_obj_array_init(ae_obj_array *dst, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,sizeof(*dst))); + + /* first, attach to frame, just to be sure that we will clean everything if we generate exception during init */ + dst->frame_entry.deallocator = (ae_destructor)ae_obj_array_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); + + /* initialize */ + dst->cnt = 0; + dst->capacity = 0; + dst->fixed_capacity = ae_false; + dst->pp_obj_ptr = NULL; + dst->pp_obj_sizes = NULL; + dst->pp_copy = NULL; + dst->pp_destroy = NULL; + ae_init_lock(&dst->array_lock, state, ae_false); +} + + +/************************************************************************ +This function creates a deep copy of ae_obj_array, with independent copies +of all objects owned by the array being created. + +dst destination array, must be zero-filled +src source array +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, array will be registered in the current frame + of the state structure; + +NOTE: this function is NOT thread-safe. It does not acquire array lock, so + you should NOT call it when array can be used by another thread. +************************************************************************/ +void ae_obj_array_init_copy(ae_obj_array *dst, const ae_obj_array *src, ae_state *state, ae_bool make_automatic) +{ + ae_int_t i; + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,sizeof(*dst))); + + /* initialize array; we know that empty array has NULL internal pointers */ + ae_obj_array_init(dst, state, make_automatic); + AE_CRITICAL_ASSERT(dst->capacity==0); + AE_CRITICAL_ASSERT(dst->pp_obj_ptr==NULL); + AE_CRITICAL_ASSERT(dst->pp_obj_sizes==NULL); + AE_CRITICAL_ASSERT(dst->pp_copy==NULL); + AE_CRITICAL_ASSERT(dst->pp_destroy==NULL); + + /* copy fields */ + dst->cnt = src->cnt; + dst->capacity = src->capacity; + dst->fixed_capacity = src->fixed_capacity; + AE_CRITICAL_ASSERT(src->cnt <= src->capacity); + + /* copy data */ + if( dst->capacity>0 ) + { + dst->pp_obj_ptr = (void**)ae_malloc_zero((size_t)dst->capacity*sizeof(void*), state); + dst->pp_obj_sizes = (ae_int_t*)ae_malloc_zero((size_t)dst->capacity*sizeof(ae_int_t), state); + dst->pp_copy = (ae_copy_constructor*)ae_malloc_zero((size_t)dst->capacity*sizeof(ae_copy_constructor), state); + dst->pp_destroy = (ae_destructor*)ae_malloc_zero((size_t)dst->capacity*sizeof(ae_destructor), state); + for(i=0; icnt; i++) + { + dst->pp_destroy[i] = src->pp_destroy[i]; + dst->pp_copy[i] = src->pp_copy[i]; + dst->pp_obj_sizes[i] = src->pp_obj_sizes[i]; + dst->pp_obj_ptr[i] = ae_malloc_zero((size_t)dst->pp_obj_sizes[i], state); + (dst->pp_copy[i])(dst->pp_obj_ptr[i], src->pp_obj_ptr[i], state, ae_false); + } + } +} + + +/************************************************************************ +This function clears dynamic objects array. + +dst destination array. + +After call to this function all objects managed by array are destroyed and +their memory is freed. Array capacity does not change. + +NOTE: this function is thread-unsafe. + +************************************************************************/ +void ae_obj_array_clear(ae_obj_array *dst) +{ + ae_int_t i; + for(i=0; icnt; i++) + if( dst->pp_obj_ptr[i]!=NULL ) + { + (dst->pp_destroy[i])(dst->pp_obj_ptr[i]); + ae_free(dst->pp_obj_ptr[i]); + dst->pp_obj_ptr[i] = NULL; + dst->pp_obj_sizes[i] = 0; + dst->pp_copy[i] = NULL; + dst->pp_destroy[i] = NULL; + } + dst->cnt = 0; +} + +/************************************************************************ +This function destroys dynamic objects array by clearing it first, then +deallocating internal dynamically allocated structures. + +dst destination instance. +************************************************************************/ +void ae_obj_array_destroy(ae_obj_array *dst) +{ + ae_obj_array_clear(dst); + if( dst->pp_obj_ptr!=NULL ) + ae_free(dst->pp_obj_ptr); + if( dst->pp_obj_sizes!=NULL ) + ae_free(dst->pp_obj_sizes); + if( dst->pp_copy!=NULL ) + ae_free(dst->pp_copy); + if( dst->pp_destroy!=NULL ) + ae_free(dst->pp_destroy); + ae_free_lock(&dst->array_lock); +} + +/************************************************************************ +This function returns array length. + +It is thread-safe, i.e. it can be combined with functions adding elements +to the array. If this function is called when another thread adds an +element to the array, this function will either: +* return old array size +* return new array size, but ONLY after new element is added to the array + +dst destination instance. + +Result: + array length +************************************************************************/ +ae_int_t ae_obj_array_get_length(const ae_obj_array *dst) +{ + return ae_unsafe_volatile_read(&dst->cnt); +} + +/************************************************************************ +Internal function which modifies array capacity, ignoring fixed_capacity +flag. + +Returns ae_false on memory reallocation failure, ae_true otherwise. +************************************************************************/ +static ae_bool _ae_obj_array_set_capacity(ae_obj_array *arr, ae_int_t new_capacity, ae_state *state) +{ + void **new_pp_obj_ptr; + ae_int_t *new_pp_obj_sizes; + ae_copy_constructor *new_pp_copy; + ae_destructor *new_pp_destroy; + + /* integrity checks */ + ae_assert(arr->cnt<=new_capacity, "_ae_obj_array_set_capacity: new capacity is less than present size", state); + + /* quick exit */ + if( arr->cnt==new_capacity ) + return ae_true; + + /* increase capacity */ + arr->capacity = new_capacity; + + /* allocate new memory, check correctness */ + new_pp_obj_ptr = (void**)ae_malloc((size_t)arr->capacity*sizeof(void*), NULL); + new_pp_obj_sizes = (ae_int_t*)ae_malloc((size_t)arr->capacity*sizeof(ae_int_t), NULL); + new_pp_copy = (ae_copy_constructor*)ae_malloc((size_t)arr->capacity*sizeof(ae_copy_constructor), NULL); + new_pp_destroy = (ae_destructor*)ae_malloc((size_t)arr->capacity*sizeof(ae_destructor), NULL); + if( new_pp_obj_ptr==NULL || new_pp_obj_sizes==NULL || new_pp_copy==NULL || new_pp_destroy==NULL ) + { + /* malloc error: free all newly allocated memory, return */ + ae_free(new_pp_obj_ptr); + ae_free(new_pp_obj_sizes); + ae_free(new_pp_copy); + ae_free(new_pp_destroy); + return ae_false; + } + + /* move data */ + memmove(new_pp_obj_ptr, arr->pp_obj_ptr, (size_t)arr->cnt*sizeof(void*)); + memmove(new_pp_obj_sizes, arr->pp_obj_sizes, (size_t)arr->cnt*sizeof(ae_int_t)); + memmove(new_pp_copy, arr->pp_copy, (size_t)arr->cnt*sizeof(ae_copy_constructor)); + memmove(new_pp_destroy, arr->pp_destroy, (size_t)arr->cnt*sizeof(ae_destructor)); + + /* free old memory, swap pointers */ + ae_free(arr->pp_obj_ptr); + ae_free(arr->pp_obj_sizes); + ae_free(arr->pp_copy); + ae_free(arr->pp_destroy); + arr->pp_obj_ptr = new_pp_obj_ptr; + arr->pp_obj_sizes = new_pp_obj_sizes; + arr->pp_copy = new_pp_copy; + arr->pp_destroy = new_pp_destroy; + + /* done */ + return ae_true; +} + +/************************************************************************ +This function sets array into special fixed capacity mode which allows +concurrent appends, writes and reads to be performed. + +arr array, can be in any mode - dynamic or fixed capacity +new_capacity new capacity, must be at least equal to current length. + +On output: +* array capacity increased to new_capacity exactly +* all present elements are retained +* if array size already exceeds new_capacity, an exception is generated +************************************************************************/ +void ae_obj_array_fixed_capacity(ae_obj_array *arr, ae_int_t new_capacity, ae_state *state) +{ + ae_assert(arr->cnt<=new_capacity, "ae_obj_array_fixed_capacity: new capacity is less than present size", state); + + if( !_ae_obj_array_set_capacity(arr, new_capacity, state) ) + ae_assert(ae_false, "ae_obj_array_fixed_capacity: memory error during reallocation", state); + arr->fixed_capacity = ae_true; +} + +/************************************************************************ +This function retrieves element from the array and assigns it to the smart +pointer PTR. + +arr array. +idx element index +ptr smart pointer structure + +On output: +* pointer with index idx is assigned to PTR +* PTR does NOT own new pointer +* if, prior to calling this function, PTR owns some pointer, it will be + properly deallocated +* out-of-bounds access will result in exception being generated +************************************************************************/ +void ae_obj_array_get(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state) +{ + if( idx<0 || idx>=ae_unsafe_volatile_read(&arr->cnt) ) + ae_assert(ae_false, "ObjArray: out of bounds read access was performed", state); + ae_smart_ptr_assign(ptr, arr->pp_obj_ptr[idx], ae_false, ae_false, 0, NULL, NULL); +} + +/************************************************************************ +This function retrieves element from the array and assigns it to the smart +pointer PTR, passing ownership. Then the idx-th element of the original +array is set to NULL. + +arr array. +idx element index +ptr smart pointer structure + +On output: +* pointer with index idx is assigned to PTR +* PTR owns the new pointer +* if, prior to calling this function, PTR owns some pointer, it will be + properly deallocated +* out-of-bounds access will result in exception being generated +************************************************************************/ +void ae_obj_array_extract_transfer(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state) +{ + if( idx<0 || idx>=ae_unsafe_volatile_read(&arr->cnt) ) + ae_assert(ae_false, "ObjArray: out of bounds ae_obj_array_extract_transfer() was performed", state); + ae_smart_ptr_assign(ptr, arr->pp_obj_ptr[idx], ae_true, ae_true, arr->pp_obj_sizes[idx], arr->pp_copy[idx], arr->pp_destroy[idx]); + arr->pp_obj_ptr[idx] = NULL; + arr->pp_obj_sizes[idx] = 0; + arr->pp_copy[idx] = NULL; + arr->pp_destroy[idx] = NULL; +} + +/************************************************************************ +This function retrieves the last element from the array and assigns it to +the smart pointer PTR, passing ownership. Then the last element of the +original array is removed (array size is decreased by 1). + +arr array. +ptr smart pointer structure + +On output: +* pointer with index cnt-1 is assigned to PTR +* PTR owns the new pointer +* if, prior to calling this function, PTR owns some pointer, it will be + properly deallocated +* calling for an empty array will result in exception being generated + +The function is not thread-safe. +************************************************************************/ +void ae_obj_array_pop_transfer(ae_obj_array *arr, ae_smart_ptr *ptr, ae_state *state) +{ + ae_int_t idx = ae_unsafe_volatile_read(&arr->cnt)-1; + if( idx<0 ) + ae_assert(ae_false, "ObjArray: ae_obj_array_pop_transfer() was called for an empty array", state); + ae_smart_ptr_assign(ptr, arr->pp_obj_ptr[idx], ae_true, ae_true, arr->pp_obj_sizes[idx], arr->pp_copy[idx], arr->pp_destroy[idx]); + arr->pp_obj_ptr[idx] = NULL; + arr->pp_obj_sizes[idx] = 0; + arr->pp_copy[idx] = NULL; + arr->pp_destroy[idx] = NULL; + arr->cnt = idx; +} + +/************************************************************************ +This function swaps elements idx and idx2 of the array. + +arr array. +idx element index +idx2 element index + +On output: +* out-of-bounds access will result in exception being generated +************************************************************************/ +void ae_obj_array_swap(ae_obj_array *arr, ae_int_t idx, ae_int_t idx2, ae_state *state) +{ + ae_int_t cnt = ae_unsafe_volatile_read(&arr->cnt); + void *t_obj; + ae_int_t t_size; + ae_copy_constructor t_copy; + ae_destructor t_dstr; + if( idx<0 || idx>=cnt ) + ae_assert(ae_false, "ObjArray: out of bounds ae_obj_array_swap() was performed", state); + if( idx2<0 || idx2>=cnt ) + ae_assert(ae_false, "ObjArray: out of bounds ae_obj_array_swap() was performed", state); + + t_obj = arr->pp_obj_ptr[idx]; + arr->pp_obj_ptr[idx] = arr->pp_obj_ptr[idx2]; + arr->pp_obj_ptr[idx2] = t_obj; + + t_size = arr->pp_obj_sizes[idx]; + arr->pp_obj_sizes[idx] = arr->pp_obj_sizes[idx2]; + arr->pp_obj_sizes[idx2] = t_size; + + t_copy = arr->pp_copy[idx]; + arr->pp_copy[idx] = arr->pp_copy[idx2]; + arr->pp_copy[idx2] = t_copy; + + t_dstr = arr->pp_destroy[idx]; + arr->pp_destroy[idx] = arr->pp_destroy[idx2]; + arr->pp_destroy[idx2] = t_dstr; +} + +/************************************************************************ +This function sets idx-th element of arr to the pointer contained in ptr. + +Notes: +* array size must be at least idx+1, an exception will be generated + otherwise +* ptr can be NULL +* non-NULL ptr MUST own its value prior to calling this function, and it + will transfer ownership to arr after the call (although it will still + point to the object) +* non-NULL ptr must point to dynamically allocated object (on-stack + objects are not supported) +* out-of-bounds access will result in exception being generated +* this function does NOT change array size and capacity + +This function is partially thread-safe: it is safe as long as array +capacity is not changed by concurrently called functions. + +arr array. +idx element index +ptr smart pointer structure + +************************************************************************/ +void ae_obj_array_set_transfer(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state) +{ + /* initial integrity checks */ + if( idx<0 || idx>=ae_unsafe_volatile_read(&arr->cnt) ) + ae_assert(ae_false, "ae_obj_array_set_transfer: out of bounds idx", state); + ae_assert(ptr->ptr==NULL || ptr->is_owner, "ae_obj_array_set_transfer: ptr does not own its pointer", state); + ae_assert(ptr->ptr==NULL || ptr->is_dynamic, "ae_obj_array_set_transfer: ptr does not point to dynamic object", state); + + /* clean up existing pointer at location idx, if needed */ + if( arr->pp_obj_ptr[idx]!=NULL ) + { + (arr->pp_destroy[idx])(arr->pp_obj_ptr[idx]); + ae_free(arr->pp_obj_ptr[idx]); + arr->pp_obj_ptr[idx] = NULL; + arr->pp_obj_sizes[idx] = 0; + arr->pp_copy[idx] = NULL; + arr->pp_destroy[idx] = NULL; + } + + /* if ptr is non-NULL, transfer it to array */ + if( ptr->ptr!=NULL ) + { + /* move to array */ + arr->pp_obj_ptr[idx] = ptr->ptr; + arr->pp_obj_sizes[idx] = ptr->size_of_object; + arr->pp_copy[idx] = ptr->copy_constructor; + arr->pp_destroy[idx] = ptr->destructor; + + /* release ownership */ + ptr->is_owner = ae_false; + ptr->is_dynamic = ae_false; + ptr->size_of_object = 0; + ptr->copy_constructor = NULL; + ptr->destructor = NULL; + } +} + + +/************************************************************************ +This function atomically appends pointer to arr, increasing array length +by 1 and returns index of the element being added. + +arr array. +ptr smart pointer structure + +Notes: +* if array has fixed capacity and its size is already at its limit, an + exception will be generated +* ptr can be NULL +* non-NULL ptr MUST own its value prior to calling this function, and it + will transfer ownership to arr after the call (although it will still + point to the object) +* non-NULL ptr must point to the dynamically allocated object (on-stack + objects are not supported) + +This function is partially thread-safe: +* parallel threads can concurrently append elements using this function +* for fixed-capacity arrays it is possible to combine appends with reads, + e.g. to use ae_obj_array_get() +************************************************************************/ +ae_int_t ae_obj_array_append_transfer(ae_obj_array *arr, ae_smart_ptr *ptr, ae_state *state) +{ + ae_int_t result, cnt; + + /* initial integrity checks */ + ae_assert(ptr->ptr==NULL || ptr->is_owner, "ae_obj_array_append_transfer: ptr does not own its pointer", state); + ae_assert(ptr->ptr==NULL || ptr->is_dynamic, "ae_obj_array_append_transfer: ptr does not point to dynamic object", state); + + /* get the primary lock */ + ae_acquire_lock(&arr->array_lock); + + /* fetch array size using 'unsafe read' in order to prevent spurious reports by TSan */ + cnt = ae_unsafe_volatile_read(&arr->cnt); + + /* array integrity check */ + if(arr->fixed_capacity && cnt>=arr->capacity ) + { + /* release lock and throw exception */ + ae_release_lock(&arr->array_lock); + ae_assert(ae_false, "ae_obj_array_append_transfer: unable to append, all capacity is used up", state); + } + + /* reallocate if needed */ + if( cnt==arr->capacity ) + { + /* one more integrity check */ + AE_CRITICAL_ASSERT(!arr->fixed_capacity); + + /* increase capacity */ + if( !_ae_obj_array_set_capacity(arr, 2*arr->capacity+8, state) ) + { + /* malloc error: release lock and throw exception */ + ae_release_lock(&arr->array_lock); + ae_assert(ae_false, "ae_obj_array_append_transfer: malloc error", state); + } + } + + /* append ptr */ + if( ptr->ptr!=NULL ) + { + /* move to array */ + arr->pp_obj_ptr[cnt] = ptr->ptr; + arr->pp_obj_sizes[cnt] = ptr->size_of_object; + arr->pp_copy[cnt] = ptr->copy_constructor; + arr->pp_destroy[cnt] = ptr->destructor; + + /* release ownership */ + ptr->is_owner = ae_false; + ptr->is_dynamic = ae_false; + ptr->size_of_object = 0; + ptr->copy_constructor = NULL; + ptr->destructor = NULL; + } + else + { + /* set to NULL */ + arr->pp_obj_ptr[cnt] = NULL; + arr->pp_obj_sizes[cnt] = 0; + arr->pp_copy[cnt] = NULL; + arr->pp_destroy[cnt] = NULL; + } + + /* issue memory fence (necessary for correct ae_obj_array_get_length) and increase array size */ + ae_mfence_lockless(); + result = cnt; + ae_unsafe_write(&arr->cnt, cnt+1); + + /* release primary lock */ + ae_release_lock(&arr->array_lock); + + /* done */ + return result; +} + +/************************************************************************ +This function copies contents of ae_vector (SRC) to x_vector (DST). + +This function should not be called for DST which is attached to SRC +(opposite situation, when SRC is attached to DST, is possible). + +Depending on situation, following actions are performed +* for SRC attached to DST, this function performs no actions (no need to + do anything) +* for independent vectors of different sizes it allocates storage in DST + and copy contents of SRC to DST. DST->last_action field is set to + ACT_NEW_LOCATION, and DST->owner is set to ACT_XFREE_ON_REALLOC . +* for independent vectors of same sizes it does not perform memory + (re)allocation. It just copies SRC to already existing place. + DST->last_action is set to ACT_SAME_LOCATION (unless it was + ACT_NEW_LOCATION), DST->owner is unmodified. + +dst destination vector +src source, vector in x-format +state ALGLIB environment state + +NOTES: +* dst is assumed to be initialized. Its contents is freed before copying + data from src (if size / type are different) or overwritten (if + possible given destination size). +************************************************************************/ +void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state) +{ + if( src->ptr.p_ptr == dst->x_ptr.p_ptr ) + { + /* src->ptr points to the beginning of dst, attached matrices, no need to copy */ + return; + } + if( dst->cnt!=src->cnt || dst->datatype!=src->datatype ) + { + if( dst->owner==ACT_XFREE_ON_REALLOC ) + ae_free(dst->x_ptr.p_ptr); + dst->x_ptr.p_ptr = ae_malloc((size_t)(src->cnt*ae_sizeof(src->datatype)), state); + if( src->cnt!=0 && dst->x_ptr.p_ptr==NULL ) + ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); + dst->last_action = ACT_NEW_LOCATION; + dst->cnt = src->cnt; + dst->datatype = src->datatype; + dst->owner = ACT_XFREE_ON_REALLOC; + } + else + { + if( dst->last_action==ACT_UNCHANGED ) + dst->last_action = ACT_SAME_LOCATION; + else if( dst->last_action==ACT_SAME_LOCATION ) + dst->last_action = ACT_SAME_LOCATION; + else if( dst->last_action==ACT_NEW_LOCATION ) + dst->last_action = ACT_NEW_LOCATION; + else + ae_assert(ae_false, "ALGLIB: internal error in ae_x_set_vector()", state); + } + if( src->cnt ) + memmove(dst->x_ptr.p_ptr, src->ptr.p_ptr, (size_t)(src->cnt*ae_sizeof(src->datatype))); +} + +/************************************************************************ +This function copies contents of ae_matrix to x_matrix. + +This function should not be called for DST which is attached to SRC +(opposite situation, when SRC is attached to DST, is possible). + +Depending on situation, following actions are performed +* for SRC attached to DST, this function performs no actions (no need to + do anything) +* for independent matrices of different sizes it allocates storage in DST + and copy contents of SRC to DST. DST->last_action field is set to + ACT_NEW_LOCATION, and DST->owner is set to ACT_XFREE_ON_REALLOC. +* for independent matrices of same sizes it does not perform memory + (re)allocation. It just copies SRC to already existing place. + DST->last_action is set to ACT_SAME_LOCATION (unless it was + ACT_NEW_LOCATION), DST->owner is unmodified. + +dst destination vector +src source, matrix in x-format +state ALGLIB environment state + +NOTES: +* dst is assumed to be initialized. Its contents is freed before copying + data from src (if size / type are different) or overwritten (if + possible given destination size). +************************************************************************/ +void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state) +{ + char *p_src_row; + char *p_dst_row; + ae_int_t i; + ae_int_t row_size; + if( src->ptr.pp_void!=NULL && src->ptr.pp_void[0] == dst->x_ptr.p_ptr ) + { + /* src->ptr points to the beginning of dst, attached matrices, no need to copy */ + return; + } + if( dst->rows!=src->rows || dst->cols!=src->cols || dst->datatype!=src->datatype ) + { + if( dst->owner==ACT_XFREE_ON_REALLOC ) + ae_free(dst->x_ptr.p_ptr); + dst->rows = src->rows; + dst->cols = src->cols; + dst->stride = src->cols; + dst->datatype = src->datatype; + dst->x_ptr.p_ptr = ae_malloc((size_t)(dst->rows*((ae_int_t)dst->stride)*ae_sizeof(src->datatype)), state); + if( dst->rows!=0 && dst->stride!=0 && dst->x_ptr.p_ptr==NULL ) + ae_break(state, ERR_OUT_OF_MEMORY, "ae_malloc(): out of memory"); + dst->last_action = ACT_NEW_LOCATION; + dst->owner = ACT_XFREE_ON_REALLOC; + } + else + { + if( dst->last_action==ACT_UNCHANGED ) + dst->last_action = ACT_SAME_LOCATION; + else if( dst->last_action==ACT_SAME_LOCATION ) + dst->last_action = ACT_SAME_LOCATION; + else if( dst->last_action==ACT_NEW_LOCATION ) + dst->last_action = ACT_NEW_LOCATION; + else + ae_assert(ae_false, "ALGLIB: internal error in ae_x_set_vector()", state); + } + if( src->rows!=0 && src->cols!=0 ) + { + p_src_row = (char*)(src->ptr.pp_void[0]); + p_dst_row = (char*)dst->x_ptr.p_ptr; + row_size = ae_sizeof(src->datatype)*src->cols; + for(i=0; irows; i++, p_src_row+=src->stride*ae_sizeof(src->datatype), p_dst_row+=dst->stride*ae_sizeof(src->datatype)) + memmove(p_dst_row, p_src_row, (size_t)(row_size)); + } +} + +/************************************************************************ +This function attaches x_vector to ae_vector's contents. +Ownership of memory allocated is not changed (it is still managed by +ae_matrix). + +dst destination vector +src source, vector in x-format +state ALGLIB environment state + +NOTES: +* dst is assumed to be initialized. Its contents is freed before + attaching to src. +* this function doesn't need ae_state parameter because it can't fail + (assuming correctly initialized src) +************************************************************************/ +void ae_x_attach_to_vector(x_vector *dst, ae_vector *src) +{ + if( dst->owner==ACT_XFREE_ON_REALLOC ) + ae_free(dst->x_ptr.p_ptr); + dst->x_ptr.p_ptr = src->ptr.p_ptr; + dst->last_action = ACT_NEW_LOCATION; + dst->cnt = src->cnt; + dst->datatype = src->datatype; + dst->owner = ACT_DROP_ON_REALLOC; +} + +/************************************************************************ +This function attaches x_matrix to ae_matrix's contents. +Ownership of memory allocated is not changed (it is still managed by +ae_matrix). + +dst destination vector +src source, matrix in x-format +state ALGLIB environment state + +NOTES: +* dst is assumed to be initialized. Its contents is freed before + attaching to src. +* this function doesn't need ae_state parameter because it can't fail + (assuming correctly initialized src) +************************************************************************/ +void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src) +{ + if( dst->owner==ACT_XFREE_ON_REALLOC ) + ae_free(dst->x_ptr.p_ptr); + dst->rows = src->rows; + dst->cols = src->cols; + dst->stride = src->stride; + dst->datatype = src->datatype; + dst->x_ptr.p_ptr = (src->rows!=0 && src->cols!=0) ? &(src->ptr.pp_double[0][0]) : NULL; + dst->last_action = ACT_NEW_LOCATION; + dst->owner = ACT_DROP_ON_REALLOC; +} + +/************************************************************************ +This function clears x_vector. It does nothing if vector is not owned by +ALGLIB environment. + +dst vector +************************************************************************/ +void x_vector_clear(x_vector *dst) +{ + if( dst->owner==ACT_XFREE_ON_REALLOC ) + aligned_free(dst->x_ptr.p_ptr); + dst->x_ptr.p_ptr = NULL; + dst->cnt = 0; +} + +/************************************************************************ +Assertion + +For non-NULL state it allows to gracefully leave ALGLIB session, +removing all frames and deallocating registered dynamic data structure. + +For NULL state it just abort()'s program. + +IMPORTANT: this function ALWAYS evaluates its argument. It can not be + replaced by macro which does nothing. So, you may place actual + function calls at cond, and these will always be performed. +************************************************************************/ +void ae_assert(ae_bool cond, const char *msg, ae_state *state) +{ + if( !cond ) + ae_break(state, ERR_ASSERTION_FAILED, msg); +} + +/************************************************************************ +CPUID + +Returns information about features CPU and compiler support. + +You must tell ALGLIB what CPU family is used by defining AE_CPU symbol +(without this hint zero will be returned). + +Note: results of this function depend on both CPU and compiler; +if compiler doesn't support SSE intrinsics, function won't set +corresponding flag. +************************************************************************/ +static volatile ae_bool _ae_cpuid_initialized = ae_false; +static volatile ae_bool _ae_cpuid_has_sse2 = ae_false; +static volatile ae_bool _ae_cpuid_has_avx2 = ae_false; +static volatile ae_bool _ae_cpuid_has_fma = ae_false; +ae_int_t ae_cpuid() +{ + /* + * to speed up CPU detection we cache results from previous attempts + * there is no synchronization, but it is still thread safe. + * + * thread safety is guaranteed on all modern architectures which + * have following property: simultaneous writes by different cores + * to the same location will be executed in serial manner. + * + */ + ae_int_t result; + + /* + * if not initialized, determine system properties + */ + if( !_ae_cpuid_initialized ) + { + /* + * SSE2 + */ +#if defined(AE_CPU) +#if (AE_CPU==AE_INTEL) +#if AE_COMPILER==AE_MSVC + { + /* SSE2 support */ + #if defined(_ALGLIB_HAS_SSE2_INTRINSICS) + int CPUInfo[4]; + __cpuid(CPUInfo, 1); + if( (CPUInfo[3]&0x04000000)!=0 ) + _ae_cpuid_has_sse2 = ae_true; + #endif + + /* check OS support for XSAVE XGETBV */ + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) + __cpuid(CPUInfo, 1); + if( (CPUInfo[2]&(0x1<<27))!=0 ) + if( (_xgetbv(0)&0x6)==0x6 ) + { + /* AVX2 support */ + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) && (_MSC_VER>=1600) + if( _ae_cpuid_has_sse2 ) + { + __cpuidex(CPUInfo, 7, 0); + if( (CPUInfo[1]&(0x1<<5))!=0 ) + _ae_cpuid_has_avx2 = ae_true; + } + #endif + + /* FMA support */ + #if defined(_ALGLIB_HAS_FMA_INTRINSICS) && (_MSC_VER>=1600) + if( _ae_cpuid_has_avx2 ) + { + __cpuid(CPUInfo, 1); + if( (CPUInfo[2]&(0x1<<12))!=0 ) + _ae_cpuid_has_fma = ae_true; + } + #endif + } + #endif + } +#elif AE_COMPILER==AE_GNUC + { + ae_int_t a,b,c,d; + + /* SSE2 support */ + #if defined(_ALGLIB_HAS_SSE2_INTRINSICS) + __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); + if( (d&0x04000000)!=0 ) + _ae_cpuid_has_sse2 = ae_true; + #endif + + /* check OS support for XSAVE XGETBV */ + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) + __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); + if( (c&(0x1<<27))!=0 ) + { + __asm__ volatile ("xgetbv" : "=a" (a), "=d" (d) : "c" (0)); + if( (a&0x6)==0x6 ) + { + /* AVX2 support */ + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) + if( _ae_cpuid_has_sse2 ) + { + __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (7), "c" (0) ); + if( (b&(0x1<<5))!=0 ) + _ae_cpuid_has_avx2 = ae_true; + } + #endif + + /* FMA support */ + #if defined(_ALGLIB_HAS_FMA_INTRINSICS) + if( _ae_cpuid_has_avx2 ) + { + __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1) ); + if( (c&(0x1<<12))!=0 ) + _ae_cpuid_has_fma = ae_true; + } + #endif + } + } + #endif + } +#elif AE_COMPILER==AE_SUNC + { + ae_int_t a,b,c,d; + __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); + if( (d&0x04000000)!=0 ) + _ae_cpuid_has_sse2 = ae_true; + } +#else +#endif +#endif +#endif + /* + * Perform one more CPUID call to generate memory fence + */ +#if AE_CPU==AE_INTEL +#if AE_COMPILER==AE_MSVC + { int CPUInfo[4]; __cpuid(CPUInfo, 1); } +#elif AE_COMPILER==AE_GNUC + { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); } +#elif AE_COMPILER==AE_SUNC + { ae_int_t a,b,c,d; __asm__ __volatile__ ("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (1)); } +#else +#endif +#endif + + /* + * set initialization flag + */ + _ae_cpuid_initialized = ae_true; + } + + /* + * return + */ + result = 0; + if( _ae_cpuid_has_sse2 ) + result = result|CPU_SSE2; + if( _ae_cpuid_has_avx2 ) + result = result|CPU_AVX2; + if( _ae_cpuid_has_fma ) + result = result|CPU_FMA; + return result; +} + +/************************************************************************ +Activates tracing to file + +IMPORTANT: this function is NOT thread-safe! Calling it from multiple + threads will result in undefined behavior. Calling it when + some thread calls ALGLIB functions may result in undefined + behavior. +************************************************************************/ +void ae_trace_file(const char *tags, const char *filename) +{ + /* + * clean up previous call + */ + if( alglib_fclose_trace ) + { + if( alglib_trace_file!=NULL ) + fclose(alglib_trace_file); + alglib_trace_file = NULL; + alglib_fclose_trace = ae_false; + } + + /* + * store ",tags," to buffer. Leading and trailing commas allow us + * to perform checks for various tags by simply calling strstr(). + */ + memset(alglib_trace_tags, 0, ALGLIB_TRACE_BUFFER_LEN); + strcat(alglib_trace_tags, ","); + strncat(alglib_trace_tags, tags, ALGLIB_TRACE_TAGS_LEN); + strcat(alglib_trace_tags, ","); + for(int i=0; alglib_trace_tags[i]!=0; i++) + alglib_trace_tags[i] = (char)tolower((int)alglib_trace_tags[i]); + + /* + * set up trace + */ + alglib_trace_type = ALGLIB_TRACE_FILE; + alglib_trace_file = fopen(filename, "ab"); + alglib_fclose_trace = ae_true; +} + +/************************************************************************ +Activates tracing to stdout + +IMPORTANT: this function is NOT thread-safe! Calling it from multiple + threads will result in undefined behavior. Calling it when + some thread calls ALGLIB functions may result in undefined + behavior. +************************************************************************/ +void ae_trace_stdout(const char *tags) +{ + /* + * clean up previous call + */ + if( alglib_fclose_trace ) + { + if( alglib_trace_file!=NULL ) + fclose(alglib_trace_file); + alglib_trace_file = NULL; + alglib_fclose_trace = ae_false; + } + + /* + * store ",tags," to buffer. Leading and trailing commas allow us + * to perform checks for various tags by simply calling strstr(). + */ + memset(alglib_trace_tags, 0, ALGLIB_TRACE_BUFFER_LEN); + strcat(alglib_trace_tags, ","); + strncat(alglib_trace_tags, tags, ALGLIB_TRACE_TAGS_LEN); + strcat(alglib_trace_tags, ","); + for(int i=0; alglib_trace_tags[i]!=0; i++) + alglib_trace_tags[i] = (char)tolower((int)alglib_trace_tags[i]); + + /* + * set up trace + */ + alglib_trace_type = ALGLIB_TRACE_FILE; + alglib_trace_file = stdout; + alglib_fclose_trace = ae_false; +} + +/************************************************************************ +Disables tracing +************************************************************************/ +void ae_trace_disable() +{ + alglib_trace_type = ALGLIB_TRACE_NONE; + if( alglib_fclose_trace ) + fclose(alglib_trace_file); + alglib_trace_file = NULL; + alglib_fclose_trace = ae_false; +} + +/************************************************************************ +Checks whether specific kind of tracing is enabled +************************************************************************/ +ae_bool ae_is_trace_enabled(const char *tag) +{ + char buf[ALGLIB_TRACE_BUFFER_LEN]; + + /* check global trace status */ + if( alglib_trace_type==ALGLIB_TRACE_NONE || alglib_trace_file==NULL ) + return ae_false; + + /* copy tag to buffer, lowercase it */ + memset(buf, 0, ALGLIB_TRACE_BUFFER_LEN); + strcat(buf, ","); + strncat(buf, tag, ALGLIB_TRACE_TAGS_LEN); + strcat(buf, "?"); + for(int i=0; buf[i]!=0; i++) + buf[i] = (char)tolower((int)buf[i]); + + /* contains tag (followed by comma, which means exact match) */ + buf[strlen(buf)-1] = ','; + if( strstr(alglib_trace_tags,buf)!=NULL ) + return ae_true; + + /* contains tag (followed by dot, which means match with child) */ + buf[strlen(buf)-1] = '.'; + if( strstr(alglib_trace_tags,buf)!=NULL ) + return ae_true; + + /* nothing */ + return ae_false; +} + +void ae_trace(const char * printf_fmt, ...) +{ + /* check global trace status */ + if( alglib_trace_type==ALGLIB_TRACE_FILE && alglib_trace_file!=NULL ) + { + va_list args; + + /* fprintf() */ + va_start(args, printf_fmt); + vfprintf(alglib_trace_file, printf_fmt, args); + va_end(args); + + /* flush output */ + fflush(alglib_trace_file); + } +} + +ae_int_t ae_tickcount() +{ +#if AE_OS==AE_WINDOWS || defined(AE_DEBUG4WINDOWS) + #if defined(_WIN32_WINNT) && (_WIN32_WINNT>=0x0600) + return (ae_int_t)GetTickCount64(); + #else + return (ae_int_t)GetTickCount(); + #endif +#elif AE_OS==AE_POSIX || defined(AE_DEBUG4POSIX) + struct timeval now; + ae_int64_t r, v; + gettimeofday(&now, NULL); + v = (ae_int64_t)now.tv_sec; + r = v*1000; + v = (ae_int64_t)(now.tv_usec/(suseconds_t)1000); + r = r+v; + return (ae_int_t)r; + /*struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) ) + return 0; + return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0;*/ +#else + ae_int64_t t = time(NULL); + return (ae_int_t)(t*1000); +#endif +} + + +/************************************************************************ +Real math functions +************************************************************************/ +ae_bool ae_fp_eq(double v1, double v2) +{ + /* IEEE-strict floating point comparison */ + volatile double x = v1; + volatile double y = v2; + return x==y; +} + +ae_bool ae_fp_neq(double v1, double v2) +{ + /* IEEE-strict floating point comparison */ + return !ae_fp_eq(v1,v2); +} + +ae_bool ae_fp_less(double v1, double v2) +{ + /* IEEE-strict floating point comparison */ + volatile double x = v1; + volatile double y = v2; + return xy; +} + +ae_bool ae_fp_greater_eq(double v1, double v2) +{ + /* IEEE-strict floating point comparison */ + volatile double x = v1; + volatile double y = v2; + return x>=y; +} + +ae_bool ae_isfinite_stateless(double x, ae_int_t endianness) +{ + union _u + { + double a; + ae_int32_t p[2]; + } u; + ae_int32_t high; + u.a = x; + if( endianness==AE_LITTLE_ENDIAN ) + high = u.p[1]; + else + high = u.p[0]; + return (high & (ae_int32_t)0x7FF00000)!=(ae_int32_t)0x7FF00000; +} + +ae_bool ae_isnan_stateless(double x, ae_int_t endianness) +{ + union _u + { + double a; + ae_int32_t p[2]; + } u; + ae_int32_t high, low; + u.a = x; + if( endianness==AE_LITTLE_ENDIAN ) + { + high = u.p[1]; + low = u.p[0]; + } + else + { + high = u.p[0]; + low = u.p[1]; + } + return ((high &0x7FF00000)==0x7FF00000) && (((high &0x000FFFFF)!=0) || (low!=0)); +} + +ae_bool ae_isinf_stateless(double x, ae_int_t endianness) +{ + union _u + { + double a; + ae_int32_t p[2]; + } u; + ae_int32_t high, low; + u.a = x; + if( endianness==AE_LITTLE_ENDIAN ) + { + high = u.p[1]; + low = u.p[0]; + } + else + { + high = u.p[0]; + low = u.p[1]; + } + + /* 31 least significant bits of high are compared */ + return ((high&0x7FFFFFFF)==0x7FF00000) && (low==0); +} + +ae_bool ae_isposinf_stateless(double x, ae_int_t endianness) +{ + union _u + { + double a; + ae_int32_t p[2]; + } u; + ae_int32_t high, low; + u.a = x; + if( endianness==AE_LITTLE_ENDIAN ) + { + high = u.p[1]; + low = u.p[0]; + } + else + { + high = u.p[0]; + low = u.p[1]; + } + + /* all 32 bits of high are compared */ + return (high==(ae_int32_t)0x7FF00000) && (low==0); +} + +ae_bool ae_isneginf_stateless(double x, ae_int_t endianness) +{ + union _u + { + double a; + ae_int32_t p[2]; + } u; + ae_int32_t high, low; + u.a = x; + if( endianness==AE_LITTLE_ENDIAN ) + { + high = u.p[1]; + low = u.p[0]; + } + else + { + high = u.p[0]; + low = u.p[1]; + } + + /* this code is a bit tricky to avoid comparison of high with 0xFFF00000, which may be unsafe with some buggy compilers */ + return ((high&0x7FFFFFFF)==0x7FF00000) && (high!=(ae_int32_t)0x7FF00000) && (low==0); +} + +ae_int_t ae_get_endianness() +{ + union + { + double a; + ae_int32_t p[2]; + } u; + + /* + * determine endianness + * two types are supported: big-endian and little-endian. + * mixed-endian hardware is NOT supported. + * + * 1983 is used as magic number because its non-periodic double + * representation allow us to easily distinguish between upper + * and lower halfs and to detect mixed endian hardware. + * + */ + u.a = 1.0/1983.0; + if( u.p[1]==(ae_int32_t)0x3f408642 ) + return AE_LITTLE_ENDIAN; + if( u.p[0]==(ae_int32_t)0x3f408642 ) + return AE_BIG_ENDIAN; + return AE_MIXED_ENDIAN; +} + +ae_bool ae_isfinite(double x,ae_state *state) +{ + return ae_isfinite_stateless(x, state->endianness); +} + +ae_bool ae_isnan(double x, ae_state *state) +{ + return ae_isnan_stateless(x, state->endianness); +} + +ae_bool ae_isinf(double x, ae_state *state) +{ + return ae_isinf_stateless(x, state->endianness); +} + +ae_bool ae_isposinf(double x,ae_state *state) +{ + return ae_isposinf_stateless(x, state->endianness); +} + +ae_bool ae_isneginf(double x,ae_state *state) +{ + return ae_isneginf_stateless(x, state->endianness); +} + +double ae_fabs(double x, ae_state *state) +{ + return fabs(x); +} + +ae_int_t ae_iabs(ae_int_t x, ae_state *state) +{ + return x>=0 ? x : -x; +} + +double ae_sqr(double x, ae_state *state) +{ + return x*x; +} + +double ae_sqrt(double x, ae_state *state) +{ + return sqrt(x); +} + +ae_int_t ae_sign(double x, ae_state *state) +{ + if( x>0.0 ) return 1; + if( x<0.0 ) return -1; + return 0; +} + +ae_int_t ae_round(double x, ae_state *state) +{ + return (ae_int_t)(ae_ifloor(x+0.5,state)); +} + +ae_int_t ae_trunc(double x, ae_state *state) +{ + return (ae_int_t)(x>0.0 ? ae_ifloor(x,state) : ae_iceil(x,state)); +} + +ae_int_t ae_ifloor(double x, ae_state *state) +{ + return (ae_int_t)(floor(x)); +} + +ae_int_t ae_iceil(double x, ae_state *state) +{ + return (ae_int_t)(ceil(x)); +} + +ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state) +{ + return m1>m2 ? m1 : m2; +} + +ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state) +{ + return m1>m2 ? m2 : m1; +} + +double ae_maxreal(double m1, double m2, ae_state *state) +{ + return m1>m2 ? m1 : m2; +} + +double ae_minreal(double m1, double m2, ae_state *state) +{ + return m1>m2 ? m2 : m1; +} + +double ae_randomreal(ae_state *state) +{ + double i1 = (double)ae_rand(); + double i2 = (double)ae_rand(); + double mx = (double)ae_rand_max()+1.0; + volatile double tmp0 = i2/mx; + volatile double tmp1 = i1+tmp0; + return tmp1/mx; +} + +ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state) +{ + return ae_rand()%maxv; +} + +double ae_sin(double x, ae_state *state) +{ + return sin(x); +} + +double ae_cos(double x, ae_state *state) +{ + return cos(x); +} + +double ae_tan(double x, ae_state *state) +{ + return tan(x); +} + +double ae_sinh(double x, ae_state *state) +{ + return sinh(x); +} + +double ae_cosh(double x, ae_state *state) +{ + return cosh(x); +} +double ae_tanh(double x, ae_state *state) +{ + return tanh(x); +} + +double ae_asin(double x, ae_state *state) +{ + return asin(x); +} + +double ae_acos(double x, ae_state *state) +{ + return acos(x); +} + +double ae_atan(double x, ae_state *state) +{ + return atan(x); +} + +double ae_atan2(double y, double x, ae_state *state) +{ + return atan2(y,x); +} + +double ae_log(double x, ae_state *state) +{ + return log(x); +} + +double ae_pow(double x, double y, ae_state *state) +{ + return pow(x,y); +} + +double ae_exp(double x, ae_state *state) +{ + return exp(x); +} + +/************************************************************************ +Symmetric/Hermitian properties: check and force +************************************************************************/ +static void x_split_length(ae_int_t n, ae_int_t nb, ae_int_t* n1, ae_int_t* n2) +{ + ae_int_t r; + if( n<=nb ) + { + *n1 = n; + *n2 = 0; + } + else + { + if( n%nb!=0 ) + { + *n2 = n%nb; + *n1 = n-(*n2); + } + else + { + *n2 = n/2; + *n1 = n-(*n2); + if( *n1%nb==0 ) + { + return; + } + r = nb-*n1%nb; + *n1 = *n1+r; + *n2 = *n2-r; + } + } +} +static double x_safepythag2(double x, double y) +{ + double w; + double xabs; + double yabs; + double z; + xabs = fabs(x); + yabs = fabs(y); + w = xabs>yabs ? xabs : yabs; + z = xabsx_nb || len1>x_nb ) + { + ae_int_t n1, n2; + if( len0>len1 ) + { + x_split_length(len0, x_nb, &n1, &n2); + is_symmetric_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); + is_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); + } + else + { + x_split_length(len1, x_nb, &n1, &n2); + is_symmetric_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); + is_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); + } + return; + } + else + { + /* base case */ + double *p1, *p2, *prow, *pcol; + double v; + ae_int_t i, j; + + p1 = (double*)(a->x_ptr.p_ptr)+offset0*a->stride+offset1; + p2 = (double*)(a->x_ptr.p_ptr)+offset1*a->stride+offset0; + for(i=0; istride; + for(j=0; jv ? *mx : v; + v = fabs(*prow); + *mx = *mx>v ? *mx : v; + v = fabs(*pcol-*prow); + *err = *err>v ? *err : v; + } + pcol += a->stride; + prow++; + } + } + } +} +/* + * this function checks that diagonal block A0 is symmetric. + * Block A0 is specified by its offset and size. + * + * [ . ] + * [ A0 ] + * A = [ . ] + * [ . ] + * + * this subroutine updates current values of: + * a) mx maximum value of A[i,j] found so far + * b) err componentwise difference between A0 and A0^T + * + */ +static void is_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) +{ + double *p, *prow, *pcol; + double v; + ae_int_t i, j; + + /* try to split problem into two smaller ones */ + if( len>x_nb ) + { + ae_int_t n1, n2; + x_split_length(len, x_nb, &n1, &n2); + is_symmetric_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); + is_symmetric_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); + is_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); + return; + } + + /* base case */ + p = (double*)(a->x_ptr.p_ptr)+offset*a->stride+offset; + for(i=0; istride; + for(j=0; jstride,prow++) + { + if( !ae_isfinite(*pcol,_state) || !ae_isfinite(*prow,_state) ) + { + *nonfinite = ae_true; + } + else + { + v = fabs(*pcol); + *mx = *mx>v ? *mx : v; + v = fabs(*prow); + *mx = *mx>v ? *mx : v; + v = fabs(*pcol-*prow); + *err = *err>v ? *err : v; + } + } + v = fabs(p[i+i*a->stride]); + *mx = *mx>v ? *mx : v; + } +} +/* + * this function checks difference between offdiagonal blocks BL and BU + * (see below). Block BL is specified by offsets (offset0,offset1) and + * sizes (len0,len1). + * + * [ . ] + * [ A0 BU ] + * A = [ BL A1 ] + * [ . ] + * + * this subroutine updates current values of: + * a) mx maximum value of A[i,j] found so far + * b) err componentwise difference between elements of BL and BU^H + * + */ +static void is_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) +{ + /* try to split problem into two smaller ones */ + if( len0>x_nb || len1>x_nb ) + { + ae_int_t n1, n2; + if( len0>len1 ) + { + x_split_length(len0, x_nb, &n1, &n2); + is_hermitian_rec_off_stat(a, offset0, offset1, n1, len1, nonfinite, mx, err, _state); + is_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1, nonfinite, mx, err, _state); + } + else + { + x_split_length(len1, x_nb, &n1, &n2); + is_hermitian_rec_off_stat(a, offset0, offset1, len0, n1, nonfinite, mx, err, _state); + is_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2, nonfinite, mx, err, _state); + } + return; + } + else + { + /* base case */ + ae_complex *p1, *p2, *prow, *pcol; + double v; + ae_int_t i, j; + + p1 = (ae_complex*)(a->x_ptr.p_ptr)+offset0*a->stride+offset1; + p2 = (ae_complex*)(a->x_ptr.p_ptr)+offset1*a->stride+offset0; + for(i=0; istride; + for(j=0; jx, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) + { + *nonfinite = ae_true; + } + else + { + v = x_safepythag2(pcol->x, pcol->y); + *mx = *mx>v ? *mx : v; + v = x_safepythag2(prow->x, prow->y); + *mx = *mx>v ? *mx : v; + v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); + *err = *err>v ? *err : v; + } + pcol += a->stride; + prow++; + } + } + } +} +/* + * this function checks that diagonal block A0 is Hermitian. + * Block A0 is specified by its offset and size. + * + * [ . ] + * [ A0 ] + * A = [ . ] + * [ . ] + * + * this subroutine updates current values of: + * a) mx maximum value of A[i,j] found so far + * b) err componentwise difference between A0 and A0^H + * + */ +static void is_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len, ae_bool *nonfinite, double *mx, double *err, ae_state *_state) +{ + ae_complex *p, *prow, *pcol; + double v; + ae_int_t i, j; + + /* try to split problem into two smaller ones */ + if( len>x_nb ) + { + ae_int_t n1, n2; + x_split_length(len, x_nb, &n1, &n2); + is_hermitian_rec_diag_stat(a, offset, n1, nonfinite, mx, err, _state); + is_hermitian_rec_diag_stat(a, offset+n1, n2, nonfinite, mx, err, _state); + is_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1, nonfinite, mx, err, _state); + return; + } + + /* base case */ + p = (ae_complex*)(a->x_ptr.p_ptr)+offset*a->stride+offset; + for(i=0; istride; + for(j=0; jstride,prow++) + { + if( !ae_isfinite(pcol->x, _state) || !ae_isfinite(pcol->y, _state) || !ae_isfinite(prow->x, _state) || !ae_isfinite(prow->y, _state) ) + { + *nonfinite = ae_true; + } + else + { + v = x_safepythag2(pcol->x, pcol->y); + *mx = *mx>v ? *mx : v; + v = x_safepythag2(prow->x, prow->y); + *mx = *mx>v ? *mx : v; + v = x_safepythag2(pcol->x-prow->x, pcol->y+prow->y); + *err = *err>v ? *err : v; + } + } + if( !ae_isfinite(p[i+i*a->stride].x, _state) || !ae_isfinite(p[i+i*a->stride].y, _state) ) + { + *nonfinite = ae_true; + } + else + { + v = fabs(p[i+i*a->stride].x); + *mx = *mx>v ? *mx : v; + v = fabs(p[i+i*a->stride].y); + *err = *err>v ? *err : v; + } + } +} +/* + * this function copies offdiagonal block BL to its symmetric counterpart + * BU (see below). Block BL is specified by offsets (offset0,offset1) + * and sizes (len0,len1). + * + * [ . ] + * [ A0 BU ] + * A = [ BL A1 ] + * [ . ] + * + */ +static void force_symmetric_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) +{ + /* try to split problem into two smaller ones */ + if( len0>x_nb || len1>x_nb ) + { + ae_int_t n1, n2; + if( len0>len1 ) + { + x_split_length(len0, x_nb, &n1, &n2); + force_symmetric_rec_off_stat(a, offset0, offset1, n1, len1); + force_symmetric_rec_off_stat(a, offset0+n1, offset1, n2, len1); + } + else + { + x_split_length(len1, x_nb, &n1, &n2); + force_symmetric_rec_off_stat(a, offset0, offset1, len0, n1); + force_symmetric_rec_off_stat(a, offset0, offset1+n1, len0, n2); + } + return; + } + else + { + /* base case */ + double *p1, *p2, *prow, *pcol; + ae_int_t i, j; + + p1 = (double*)(a->x_ptr.p_ptr)+offset0*a->stride+offset1; + p2 = (double*)(a->x_ptr.p_ptr)+offset1*a->stride+offset0; + for(i=0; istride; + for(j=0; jstride; + prow++; + } + } + } +} +/* + * this function copies lower part of diagonal block A0 to its upper part + * Block is specified by offset and size. + * + * [ . ] + * [ A0 ] + * A = [ . ] + * [ . ] + * + */ +static void force_symmetric_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) +{ + double *p, *prow, *pcol; + ae_int_t i, j; + + /* try to split problem into two smaller ones */ + if( len>x_nb ) + { + ae_int_t n1, n2; + x_split_length(len, x_nb, &n1, &n2); + force_symmetric_rec_diag_stat(a, offset, n1); + force_symmetric_rec_diag_stat(a, offset+n1, n2); + force_symmetric_rec_off_stat(a, offset+n1, offset, n2, n1); + return; + } + + /* base case */ + p = (double*)(a->x_ptr.p_ptr)+offset*a->stride+offset; + for(i=0; istride; + for(j=0; jstride,prow++) + *pcol = *prow; + } +} +/* + * this function copies Hermitian transpose of offdiagonal block BL to + * its symmetric counterpart BU (see below). Block BL is specified by + * offsets (offset0,offset1) and sizes (len0,len1). + * + * [ . ] + * [ A0 BU ] + * A = [ BL A1 ] + * [ . ] + */ +static void force_hermitian_rec_off_stat(x_matrix *a, ae_int_t offset0, ae_int_t offset1, ae_int_t len0, ae_int_t len1) +{ + /* try to split problem into two smaller ones */ + if( len0>x_nb || len1>x_nb ) + { + ae_int_t n1, n2; + if( len0>len1 ) + { + x_split_length(len0, x_nb, &n1, &n2); + force_hermitian_rec_off_stat(a, offset0, offset1, n1, len1); + force_hermitian_rec_off_stat(a, offset0+n1, offset1, n2, len1); + } + else + { + x_split_length(len1, x_nb, &n1, &n2); + force_hermitian_rec_off_stat(a, offset0, offset1, len0, n1); + force_hermitian_rec_off_stat(a, offset0, offset1+n1, len0, n2); + } + return; + } + else + { + /* base case */ + ae_complex *p1, *p2, *prow, *pcol; + ae_int_t i, j; + + p1 = (ae_complex*)(a->x_ptr.p_ptr)+offset0*a->stride+offset1; + p2 = (ae_complex*)(a->x_ptr.p_ptr)+offset1*a->stride+offset0; + for(i=0; istride; + for(j=0; jstride; + prow++; + } + } + } +} +/* + * this function copies Hermitian transpose of lower part of + * diagonal block A0 to its upper part Block is specified by offset and size. + * + * [ . ] + * [ A0 ] + * A = [ . ] + * [ . ] + * + */ +static void force_hermitian_rec_diag_stat(x_matrix *a, ae_int_t offset, ae_int_t len) +{ + ae_complex *p, *prow, *pcol; + ae_int_t i, j; + + /* try to split problem into two smaller ones */ + if( len>x_nb ) + { + ae_int_t n1, n2; + x_split_length(len, x_nb, &n1, &n2); + force_hermitian_rec_diag_stat(a, offset, n1); + force_hermitian_rec_diag_stat(a, offset+n1, n2); + force_hermitian_rec_off_stat(a, offset+n1, offset, n2, n1); + return; + } + + /* base case */ + p = (ae_complex*)(a->x_ptr.p_ptr)+offset*a->stride+offset; + for(i=0; istride; + for(j=0; jstride,prow++) + *pcol = *prow; + } +} +ae_bool x_is_symmetric(x_matrix *a) +{ + double mx, err; + ae_bool nonfinite; + ae_state _alglib_env_state; + if( a->datatype!=DT_REAL ) + return ae_false; + if( a->cols!=a->rows ) + return ae_false; + if( a->cols==0 || a->rows==0 ) + return ae_true; + ae_state_init(&_alglib_env_state); + mx = 0.0; + err = 0.0; + nonfinite = ae_false; + is_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); + if( nonfinite ) + return ae_false; + if( mx==0.0 ) + return ae_true; + return err/mx<=1.0E-14; +} +ae_bool x_is_hermitian(x_matrix *a) +{ + double mx, err; + ae_bool nonfinite; + ae_state _alglib_env_state; + if( a->datatype!=DT_COMPLEX ) + return ae_false; + if( a->cols!=a->rows ) + return ae_false; + if( a->cols==0 || a->rows==0 ) + return ae_true; + ae_state_init(&_alglib_env_state); + mx = 0.0; + err = 0.0; + nonfinite = ae_false; + is_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows, &nonfinite, &mx, &err, &_alglib_env_state); + if( nonfinite ) + return ae_false; + if( mx==0.0 ) + return ae_true; + return err/mx<=1.0E-14; +} +ae_bool x_force_symmetric(x_matrix *a) +{ + if( a->datatype!=DT_REAL ) + return ae_false; + if( a->cols!=a->rows ) + return ae_false; + if( a->cols==0 || a->rows==0 ) + return ae_true; + force_symmetric_rec_diag_stat(a, 0, (ae_int_t)a->rows); + return ae_true; +} +ae_bool x_force_hermitian(x_matrix *a) +{ + if( a->datatype!=DT_COMPLEX ) + return ae_false; + if( a->cols!=a->rows ) + return ae_false; + if( a->cols==0 || a->rows==0 ) + return ae_true; + force_hermitian_rec_diag_stat(a, 0, (ae_int_t)a->rows); + return ae_true; +} + +ae_bool ae_is_symmetric(ae_matrix *a) // candidates for removal!!!!!!!!!!! +{ + x_matrix x; + x.owner = ACT_DROP_ON_REALLOC; + ae_x_attach_to_matrix(&x, a); + return x_is_symmetric(&x); +} + +ae_bool ae_is_hermitian(ae_matrix *a) // candidates for removal!!!!!!!!!! +{ + x_matrix x; + x.owner = ACT_DROP_ON_REALLOC; + ae_x_attach_to_matrix(&x, a); + return x_is_hermitian(&x); +} + +ae_bool ae_force_symmetric(ae_matrix *a) // candidates for removal!!!!!!!!!! +{ + x_matrix x; + x.owner = ACT_DROP_ON_REALLOC; + ae_x_attach_to_matrix(&x, a); + return x_force_symmetric(&x); +} + +ae_bool ae_force_hermitian(ae_matrix *a) // candidates for removal!!!!!!!!!! +{ + x_matrix x; + x.owner = ACT_DROP_ON_REALLOC; + ae_x_attach_to_matrix(&x, a); + return x_force_hermitian(&x); +} + +/************************************************************************ +This function converts six-bit value (from 0 to 63) to character (only +digits, lowercase and uppercase letters, minus and underscore are used). + +If v is negative or greater than 63, this function returns '?'. +************************************************************************/ +static char _sixbits2char_tbl[64] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '-', '_' }; + +char ae_sixbits2char(ae_int_t v) +{ + + if( v<0 || v>63 ) + return '?'; + return _sixbits2char_tbl[v]; + + /* v is correct, process it */ + /*if( v<10 ) + return '0'+v; + v -= 10; + if( v<26 ) + return 'A'+v; + v -= 26; + if( v<26 ) + return 'a'+v; + v -= 26; + return v==0 ? '-' : '_';*/ +} + +/************************************************************************ +This function converts character to six-bit value (from 0 to 63). + +This function is inverse of ae_sixbits2char() +If c is not correct character, this function returns -1. +************************************************************************/ +static ae_int_t _ae_char2sixbits_tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 62, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, -1, -1, -1, -1, 63, + -1, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, -1, -1, -1, -1, -1 }; +ae_int_t ae_char2sixbits(char c) +{ + return (c>=0 && c<127) ? _ae_char2sixbits_tbl[(int)c] : -1; +} + +/************************************************************************ +This function converts three bytes (24 bits) to four six-bit values +(24 bits again). + +src pointer to three bytes +dst pointer to four ints +************************************************************************/ +void ae_threebytes2foursixbits(const unsigned char *src, ae_int_t *dst) +{ + dst[0] = src[0] & 0x3F; + dst[1] = (src[0]>>6) | ((src[1]&0x0F)<<2); + dst[2] = (src[1]>>4) | ((src[2]&0x03)<<4); + dst[3] = src[2]>>2; +} + +/************************************************************************ +This function converts four six-bit values (24 bits) to three bytes +(24 bits again). + +src pointer to four ints +dst pointer to three bytes +************************************************************************/ +void ae_foursixbits2threebytes(const ae_int_t *src, unsigned char *dst) +{ + dst[0] = (unsigned char)( src[0] | ((src[1]&0x03)<<6)); + dst[1] = (unsigned char)((src[1]>>2) | ((src[2]&0x0F)<<4)); + dst[2] = (unsigned char)((src[2]>>4) | (src[3]<<2)); +} + +/************************************************************************ +This function serializes boolean value into buffer + +v boolean value to be serialized +buf buffer, at least 12 characters wide + (11 chars for value, one for trailing zero) +state ALGLIB environment state +************************************************************************/ +void ae_bool2str(ae_bool v, char *buf, ae_state *state) +{ + char c = v ? '1' : '0'; + ae_int_t i; + for(i=0; iendianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) + { + unsigned char tc; + tc = u.bytes[i]; + u.bytes[i] = u.bytes[(ae_int_t)sizeof(ae_int_t)-1-i]; + u.bytes[(ae_int_t)sizeof(ae_int_t)-1-i] = tc; + } + } + + /* + * convert to six-bit representation, output + * + * NOTE: last 12th element of sixbits is always zero, we do not output it + */ + ae_threebytes2foursixbits(u.bytes+0, sixbits+0); + ae_threebytes2foursixbits(u.bytes+3, sixbits+4); + ae_threebytes2foursixbits(u.bytes+6, sixbits+8); + for(i=0; iendianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) + { + unsigned char tc; + tc = bytes[i]; + bytes[i] = bytes[(ae_int_t)sizeof(ae_int_t)-1-i]; + bytes[(ae_int_t)sizeof(ae_int_t)-1-i] = tc; + } + } + + /* + * convert to six-bit representation, output + * + * NOTE: last 12th element of sixbits is always zero, we do not output it + */ + ae_threebytes2foursixbits(bytes+0, sixbits+0); + ae_threebytes2foursixbits(bytes+3, sixbits+4); + ae_threebytes2foursixbits(bytes+6, sixbits+8); + for(i=0; i=AE_SER_ENTRY_LENGTH ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + sixbits[sixbitsread] = d; + sixbitsread++; + buf++; + } + *pasttheend = buf; + if( sixbitsread==0 ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + for(i=sixbitsread; i<12; i++) + sixbits[i] = 0; + ae_foursixbits2threebytes(sixbits+0, u.bytes+0); + ae_foursixbits2threebytes(sixbits+4, u.bytes+3); + ae_foursixbits2threebytes(sixbits+8, u.bytes+6); + if( state->endianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) + { + unsigned char tc; + tc = u.bytes[i]; + u.bytes[i] = u.bytes[sizeof(ae_int_t)-1-i]; + u.bytes[sizeof(ae_int_t)-1-i] = tc; + } + } + return u.ival; +} + +/************************************************************************ +This function unserializes 64-bit integer value from string + +buf buffer which contains value; leading spaces/tabs/newlines are + ignored, traling spaces/tabs/newlines are treated as end of + the boolean value. +state ALGLIB environment state + +This function raises an error in case unexpected symbol is found +************************************************************************/ +ae_int64_t ae_str2int64(const char *buf, ae_state *state, const char **pasttheend) +{ + const char *emsg = "ALGLIB: unable to read integer value from stream"; + ae_int_t sixbits[12]; + ae_int_t sixbitsread, i; + unsigned char bytes[9]; + ae_int64_t result; + + /* + * 1. skip leading spaces + * 2. read and decode six-bit digits + * 3. set trailing digits to zeros + * 4. convert to little endian 64-bit integer representation + * 5. convert to big endian representation, if needed + */ + while( *buf==' ' || *buf=='\t' || *buf=='\n' || *buf=='\r' ) + buf++; + sixbitsread = 0; + while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 ) + { + ae_int_t d; + d = ae_char2sixbits(*buf); + if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + sixbits[sixbitsread] = d; + sixbitsread++; + buf++; + } + *pasttheend = buf; + if( sixbitsread==0 ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + for(i=sixbitsread; i<12; i++) + sixbits[i] = 0; + ae_foursixbits2threebytes(sixbits+0, bytes+0); + ae_foursixbits2threebytes(sixbits+4, bytes+3); + ae_foursixbits2threebytes(sixbits+8, bytes+6); + if( state->endianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(ae_int_t)/2); i++) + { + unsigned char tc; + tc = bytes[i]; + bytes[i] = bytes[sizeof(ae_int_t)-1-i]; + bytes[sizeof(ae_int_t)-1-i] = tc; + } + } + memmove(&result, bytes, sizeof(result)); + return result; +} + + +/************************************************************************ +This function serializes double value into buffer + +v double value to be serialized +buf buffer, at least 12 characters wide + (11 chars for value, one for trailing zero) +state ALGLIB environment state +************************************************************************/ +void ae_double2str(double v, char *buf, ae_state *state) +{ + union _u + { + double dval; + unsigned char bytes[9]; + } u; + ae_int_t i; + ae_int_t sixbits[12]; + + /* + * handle special quantities + */ + if( ae_isnan(v, state) ) + { + const char *s = ".nan_______"; + memmove(buf, s, strlen(s)+1); + return; + } + if( ae_isposinf(v, state) ) + { + const char *s = ".posinf____"; + memmove(buf, s, strlen(s)+1); + return; + } + if( ae_isneginf(v, state) ) + { + const char *s = ".neginf____"; + memmove(buf, s, strlen(s)+1); + return; + } + + /* + * process general case: + * 1. copy v to array of chars + * 2. set 9th byte of u.bytes to zero in order to + * simplify conversion to six-bit representation + * 3. convert to little endian (if needed) + * 4. convert to six-bit representation + * (last 12th element of sixbits is always zero, we do not output it) + */ + u.dval = v; + u.bytes[8] = (unsigned char)0; + if( state->endianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) + { + unsigned char tc; + tc = u.bytes[i]; + u.bytes[i] = u.bytes[sizeof(double)-1-i]; + u.bytes[sizeof(double)-1-i] = tc; + } + } + ae_threebytes2foursixbits(u.bytes+0, sixbits+0); + ae_threebytes2foursixbits(u.bytes+3, sixbits+4); + ae_threebytes2foursixbits(u.bytes+6, sixbits+8); + for(i=0; iv_nan; + } + if( strncmp(buf, s_posinf, strlen(s_posinf))==0 ) + { + *pasttheend = buf+strlen(s_posinf); + return state->v_posinf; + } + if( strncmp(buf, s_neginf, strlen(s_neginf))==0 ) + { + *pasttheend = buf+strlen(s_neginf); + return state->v_neginf; + } + ae_break(state, ERR_ASSERTION_FAILED, emsg); + } + + /* + * General case: + * 1. read and decode six-bit digits + * 2. check that all 11 digits were read + * 3. set last 12th digit to zero (needed for simplicity of conversion) + * 4. convert to 8 bytes + * 5. convert to big endian representation, if needed + */ + sixbitsread = 0; + while( *buf!=' ' && *buf!='\t' && *buf!='\n' && *buf!='\r' && *buf!=0 ) + { + ae_int_t d; + d = ae_char2sixbits(*buf); + if( d<0 || sixbitsread>=AE_SER_ENTRY_LENGTH ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + sixbits[sixbitsread] = d; + sixbitsread++; + buf++; + } + *pasttheend = buf; + if( sixbitsread!=AE_SER_ENTRY_LENGTH ) + ae_break(state, ERR_ASSERTION_FAILED, emsg); + sixbits[AE_SER_ENTRY_LENGTH] = 0; + ae_foursixbits2threebytes(sixbits+0, u.bytes+0); + ae_foursixbits2threebytes(sixbits+4, u.bytes+3); + ae_foursixbits2threebytes(sixbits+8, u.bytes+6); + if( state->endianness==AE_BIG_ENDIAN ) + { + for(i=0; i<(ae_int_t)(sizeof(double)/2); i++) + { + unsigned char tc; + tc = u.bytes[i]; + u.bytes[i] = u.bytes[(ae_int_t)sizeof(double)-1-i]; + u.bytes[(ae_int_t)sizeof(double)-1-i] = tc; + } + } + return u.dval; +} + + +/************************************************************************ +This function performs given number of spin-wait iterations +************************************************************************/ +void ae_spin_wait(ae_int_t cnt) +{ + /* + * these strange operations with ae_never_change_it are necessary to + * prevent compiler optimization of the loop. + */ + volatile ae_int_t i; + + /* very unlikely because no one will wait for such amount of cycles */ + if( cnt>0x12345678 ) + ae_never_change_it = cnt%10; + + /* spin wait, test condition which will never be true */ + for(i=0; i1 ) + ae_never_change_it--; +} + + +/************************************************************************ +This function causes the calling thread to relinquish the CPU. The thread +is moved to the end of the queue and some other thread gets to run. + +NOTE: this function should NOT be called when AE_OS is AE_UNKNOWN - the + whole program will be abnormally terminated. +************************************************************************/ +void ae_yield() +{ +#if 0 +#if (AE_CPU==AE_INTEL) && defined(AE_HAS_SSE2_INTRINSICS) + _mm_pause(); +#else + #if AE_OS==AE_WINDOWS + #if defined(_WIN32_WINNT) && (_WIN32_WINNT>=0x0501) + if( !SwitchToThread() ) + Sleep(0); + #else + Sleep(0); + #endif + #elif AE_OS==AE_POSIX + sched_yield(); + #else + abort(); + #endif +#endif +#endif +} + +/************************************************************************ +This function initializes _lock structure which is internally used by +ae_lock high-level structure. + +_lock structure is statically allocated, no malloc() calls is performed +during its allocation. However, you have to call _ae_free_lock_raw() in +order to deallocate this lock properly. +************************************************************************/ +void _ae_init_lock_raw(_lock *p) +{ +#if AE_OS==AE_WINDOWS + p->p_lock = (ae_int_t*)ae_align((void*)(&p->buf),AE_LOCK_ALIGNMENT); + p->p_lock[0] = 0; +#elif AE_OS==AE_POSIX + pthread_mutex_init(&p->mutex, NULL); +#else + p->is_locked = ae_false; +#endif +} + + +/************************************************************************ +This function acquires _lock structure. + +It is low-level workhorse utilized by ae_acquire_lock(). +************************************************************************/ +void _ae_acquire_lock_raw(_lock *p) +{ +#if AE_OS==AE_WINDOWS + ae_int_t cnt = 0; +#ifdef AE_SMP_DEBUGCOUNTERS + InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_acquisitions); +#endif + for(;;) + { + if( InterlockedCompareExchange((LONG volatile *)p->p_lock, 1, 0)==0 ) + return; + ae_spin_wait(AE_LOCK_CYCLES); +#ifdef AE_SMP_DEBUGCOUNTERS + InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_spinwaits); +#endif + cnt++; + if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) + { +#ifdef AE_SMP_DEBUGCOUNTERS + InterlockedIncrement((LONG volatile *)&_ae_dbg_lock_yields); +#endif + ae_yield(); + } + } +#elif AE_OS==AE_POSIX + ae_int_t cnt = 0; + for(;;) + { + if( pthread_mutex_trylock(&p->mutex)==0 ) + return; + ae_spin_wait(AE_LOCK_CYCLES); + cnt++; + if( cnt%AE_LOCK_TESTS_BEFORE_YIELD==0 ) + ae_yield(); + } + ; +#else + AE_CRITICAL_ASSERT(!p->is_locked); + p->is_locked = ae_true; +#endif +} + + +/************************************************************************ +This function releases _lock structure. + +It is low-level lock function which is used by ae_release_lock. +************************************************************************/ +void _ae_release_lock_raw(_lock *p) +{ +#if AE_OS==AE_WINDOWS + InterlockedExchange((LONG volatile *)p->p_lock, 0); +#elif AE_OS==AE_POSIX + pthread_mutex_unlock(&p->mutex); +#else + p->is_locked = ae_false; +#endif +} + + +/************************************************************************ +This function frees _lock structure. +************************************************************************/ +void _ae_free_lock_raw(_lock *p) +{ +#if AE_OS==AE_POSIX + pthread_mutex_destroy(&p->mutex); +#endif +} + + +/************************************************************************ +This function initializes ae_lock structure. + +INPUT PARAMETERS: + lock - pointer to lock structure, must be zero-filled + state - pointer to state structure, used for exception + handling and management of automatic objects. + make_automatic - if true, lock object is added to automatic + memory management list. + +NOTE: as a special exception, this function allows you to specify NULL + state pointer. In this case all exception arising during construction + are handled as critical failures, with abort() being called. + make_automatic must be false on such calls. +************************************************************************/ +void ae_init_lock(ae_lock *lock, ae_state *state, ae_bool make_automatic) +{ + _lock *p; + AE_CRITICAL_ASSERT(ae_check_zeros(lock,(ae_int_t)sizeof(*lock))); + if(state==NULL) + { + ae_state _tmp_state; + AE_CRITICAL_ASSERT(!make_automatic); + ae_state_init(&_tmp_state); + ae_init_lock(lock, &_tmp_state, ae_false); + ae_state_clear(&_tmp_state); + return; + } + lock->eternal = ae_false; + ae_db_init(&lock->db, (ae_int_t)sizeof(_lock), state, make_automatic); + lock->lock_ptr = lock->db.ptr; + p = (_lock*)lock->lock_ptr; + _ae_init_lock_raw(p); +} + +/************************************************************************ +This function initializes "eternal" ae_lock structure which is expected +to persist until the end of the execution of the program. Eternal locks +can not be deallocated (cleared) and do not increase debug allocation +counters. Errors during allocation of eternal locks are considered +critical exceptions and handled by calling abort(). + +INPUT PARAMETERS: + lock - pointer to lock structure, must be zero-filled + state - pointer to state structure, used for exception + handling and management of automatic objects; + non-NULL. + make_automatic - if true, lock object is added to automatic + memory management list. +************************************************************************/ +void ae_init_lock_eternal(ae_lock *lock) +{ + _lock *p; + AE_CRITICAL_ASSERT(ae_check_zeros(lock,(ae_int_t)sizeof(*lock))); + lock->eternal = ae_true; + lock->lock_ptr = eternal_malloc(sizeof(_lock)); + p = (_lock*)lock->lock_ptr; + _ae_init_lock_raw(p); +} + + +/************************************************************************ +This function acquires lock. In case lock is busy, we perform several +iterations inside tight loop before trying again. +************************************************************************/ +void ae_acquire_lock(ae_lock *lock) +{ + _lock *p; + p = (_lock*)lock->lock_ptr; + _ae_acquire_lock_raw(p); +} + + +/************************************************************************ +This function releases lock. +************************************************************************/ +void ae_release_lock(ae_lock *lock) +{ + _lock *p; + p = (_lock*)lock->lock_ptr; + _ae_release_lock_raw(p); +} + + +/************************************************************************ +This function frees ae_lock structure. +************************************************************************/ +void ae_free_lock(ae_lock *lock) +{ + _lock *p; + AE_CRITICAL_ASSERT(!lock->eternal); + p = (_lock*)lock->lock_ptr; + if( p!=NULL ) + _ae_free_lock_raw(p); + ae_db_free(&lock->db); +} + + +/************************************************************************ +This function creates ae_shared_pool structure. + +dst destination shared pool, must be zero-filled + already allocated, but not initialized. +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +Error handling: +* on failure calls ae_break() with NULL state pointer. Usually it results + in abort() call. + +dst is assumed to be uninitialized, its fields are ignored. +************************************************************************/ +void ae_shared_pool_init(void *_dst, ae_state *state, ae_bool make_automatic) +{ + ae_shared_pool *dst; + + AE_CRITICAL_ASSERT(state!=NULL); + dst = (ae_shared_pool*)_dst; + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + /* attach to frame first, just to be sure that if we fail within malloc, we will be able to clean up the object */ + dst->frame_entry.deallocator = ae_shared_pool_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); + + /* init */ + dst->seed_object = NULL; + dst->recycled_objects = NULL; + dst->recycled_entries = NULL; + dst->enumeration_counter = NULL; + dst->size_of_object = 0; + dst->init_copy = NULL; + dst->destroy = NULL; + ae_init_lock(&dst->pool_lock, state, ae_false); +} + + +/************************************************************************ +This function clears all dynamically allocated fields of the pool except +for the lock. It does NOT try to acquire pool_lock. + +NOTE: this function is NOT thread-safe, it is not protected by lock. +************************************************************************/ +static void ae_shared_pool_internalclear(ae_shared_pool *dst) +{ + ae_shared_pool_entry *ptr, *tmp; + + /* destroy seed */ + if( dst->seed_object!=NULL ) + { + dst->destroy((void*)dst->seed_object); + ae_free((void*)dst->seed_object); + dst->seed_object = NULL; + } + + /* destroy recycled objects */ + for(ptr=dst->recycled_objects; ptr!=NULL;) + { + tmp = (ae_shared_pool_entry*)ptr->next_entry; + dst->destroy(ptr->obj); + ae_free(ptr->obj); + ae_free(ptr); + ptr = tmp; + } + dst->recycled_objects = NULL; + + /* destroy recycled entries */ + for(ptr=dst->recycled_entries; ptr!=NULL;) + { + tmp = (ae_shared_pool_entry*)ptr->next_entry; + ae_free(ptr); + ptr = tmp; + } + dst->recycled_entries = NULL; +} + + +/************************************************************************ +This function creates copy of ae_shared_pool. + +dst destination pool, must be zero-filled +src source pool +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_shared_pool_init_copy(void *_dst, const void *_src, ae_state *state, ae_bool make_automatic) +{ + ae_shared_pool *dst; + const ae_shared_pool *src; + ae_shared_pool_entry *ptr; + + /* state!=NULL, allocation errors result in exception */ + /* AE_CRITICAL_ASSERT(state!=NULL); */ + + dst = (ae_shared_pool*)_dst; + src = (const ae_shared_pool*)_src; + ae_shared_pool_init(dst, state, make_automatic); + + /* copy non-pointer fields */ + dst->size_of_object = src->size_of_object; + dst->init_copy = src->init_copy; + dst->destroy = src->destroy; + + /* copy seed object */ + if( src->seed_object!=NULL ) + { + dst->seed_object = ae_malloc((size_t)dst->size_of_object, state); + memset(dst->seed_object, 0, (size_t)dst->size_of_object); + dst->init_copy(dst->seed_object, src->seed_object, state, ae_false); + } + + /* copy recycled objects */ + dst->recycled_objects = NULL; + for(ptr=src->recycled_objects; ptr!=NULL; ptr=(ae_shared_pool_entry*)ptr->next_entry) + { + ae_shared_pool_entry *tmp; + + /* allocate entry, immediately add to the recycled list + (we do not want to lose it in case of future malloc failures) */ + tmp = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); + memset(tmp, 0, sizeof(*tmp)); + tmp->next_entry = dst->recycled_objects; + dst->recycled_objects = tmp; + + /* prepare place for object, init_copy() it */ + tmp->obj = ae_malloc((size_t)dst->size_of_object, state); + memset(tmp->obj, 0, (size_t)dst->size_of_object); + dst->init_copy(tmp->obj, ptr->obj, state, ae_false); + } + + /* recycled entries are not copied because they do not store any information */ + dst->recycled_entries = NULL; + + /* enumeration counter is reset on copying */ + dst->enumeration_counter = NULL; + + /* initialize frame record */ + dst->frame_entry.deallocator = ae_shared_pool_destroy; + dst->frame_entry.ptr = dst; +} + + +/************************************************************************ +This function performs destruction of the pool object. + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when pool can be used by another thread. +************************************************************************/ +void ae_shared_pool_clear(void *_dst) +{ + ae_shared_pool *dst = (ae_shared_pool*)_dst; + + /* clear seed and lists */ + ae_shared_pool_internalclear(dst); + + /* clear fields */ + dst->seed_object = NULL; + dst->recycled_objects = NULL; + dst->recycled_entries = NULL; + dst->enumeration_counter = NULL; + dst->size_of_object = 0; + dst->init_copy = NULL; + dst->destroy = NULL; +} + +void ae_shared_pool_destroy(void *_dst) +{ + ae_shared_pool *dst = (ae_shared_pool*)_dst; + ae_shared_pool_clear(_dst); + ae_free_lock(&dst->pool_lock); +} + + +/************************************************************************ +This function returns True, if internal seed object was set. It returns +False for un-seeded pool. + +dst destination pool (initialized by constructor function) + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +ae_bool ae_shared_pool_is_initialized(void *_dst) +{ + ae_shared_pool *dst = (ae_shared_pool*)_dst; + return dst->seed_object!=NULL; +} + + +/************************************************************************ +This function sets internal seed object. All objects owned by the pool +(current seed object, recycled objects) are automatically freed. + +dst destination pool (initialized by constructor function) +seed_object new seed object +size_of_object sizeof(), used to allocate memory +constructor constructor function +copy_constructor copy constructor +destructor destructor function +state ALGLIB environment state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_shared_pool_set_seed( + ae_shared_pool *dst, + const void *seed_object, + ae_int_t size_of_object, + ae_copy_constructor copy_constructor, + ae_destructor destructor, + ae_state *state) +{ + /* state!=NULL, allocation errors result in exception */ + AE_CRITICAL_ASSERT(state!=NULL); + + /* destroy internal objects */ + ae_shared_pool_internalclear(dst); + + /* set non-pointer fields */ + dst->size_of_object = size_of_object; + dst->init_copy = copy_constructor; + dst->destroy = destructor; + + /* set seed object */ + dst->seed_object = ae_malloc((size_t)size_of_object, state); + memset(dst->seed_object, 0, (size_t)size_of_object); + copy_constructor(dst->seed_object, seed_object, state, ae_false); +} + + +/************************************************************************ +This function sets internal seed object, if pool is uninitialized or is +initialized by an object of another type. Otherwise, the pool is left +intact. + +Upon initialization all objects owned by the pool (current seed object, +recycled objects) are automatically freed. + +dst destination pool (initialized by constructor function) +seed_object new seed object +size_of_object sizeof(), used to allocate memory +constructor constructor function +copy_constructor copy constructor +destructor destructor function +state ALGLIB environment state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_shared_pool_set_seed_if_different( + ae_shared_pool *dst, + const void *seed_object, + ae_int_t size_of_object, + ae_copy_constructor copy_constructor, + ae_destructor destructor, + ae_state *state) +{ + if( dst->seed_object==NULL || dst->size_of_object!=size_of_object || dst->init_copy!=copy_constructor || dst->destroy!=destructor ) + ae_shared_pool_set_seed(dst, seed_object, size_of_object, copy_constructor, destructor, state); +} + + +/************************************************************************ +This function retrieves a copy of the seed object from the pool and +stores it to target smart pointer ptr. + +In case target pointer owns non-NULL value, it is deallocated before +storing value retrieved from pool. Target pointer becomes owner of the +value which was retrieved from pool. + +pool pool +pptr pointer to ae_smart_ptr structure +state ALGLIB environment state + +NOTE: this function IS thread-safe. It acquires pool lock during its + operation and can be used simultaneously from several threads. +************************************************************************/ +void ae_shared_pool_retrieve( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state) +{ + void *new_obj; + + /* state!=NULL, allocation errors are handled by throwing exception from ae_malloc() */ + AE_CRITICAL_ASSERT(state!=NULL); + + /* assert that pool was seeded */ + ae_assert( + pool->seed_object!=NULL, + "ALGLIB: shared pool is not seeded, PoolRetrieve() failed", + state); + + /* acquire lock */ + ae_acquire_lock(&pool->pool_lock); + + /* try to reuse recycled objects */ + if( pool->recycled_objects!=NULL ) + { + ae_shared_pool_entry *result; + + /* retrieve entry/object from list of recycled objects */ + result = pool->recycled_objects; + pool->recycled_objects = (ae_shared_pool_entry*)pool->recycled_objects->next_entry; + new_obj = result->obj; + result->obj = NULL; + + /* move entry to list of recycled entries */ + result->next_entry = pool->recycled_entries; + pool->recycled_entries = result; + + /* release lock */ + ae_release_lock(&pool->pool_lock); + + /* assign object to smart pointer */ + ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->size_of_object, pool->init_copy, pool->destroy); + return; + } + + /* release lock; we do not need it anymore because copy constructor does not modify source variable */ + ae_release_lock(&pool->pool_lock); + + /* create new object from seed, immediately assign object to smart pointer + (do not want to lose it in case of future failures) */ + new_obj = ae_malloc((size_t)pool->size_of_object, state); + memset(new_obj, 0, (size_t)pool->size_of_object); + ae_smart_ptr_assign(pptr, new_obj, ae_true, ae_true, pool->size_of_object, pool->init_copy, pool->destroy); + + /* perform actual copying; before this line smartptr points to zero-filled instance */ + pool->init_copy(new_obj, pool->seed_object, state, ae_false); +} + + +/************************************************************************ +This function recycles object owned by smart pointer by moving it to +internal storage of the shared pool. + +Source pointer must own the object. After function is over, it owns NULL +pointer. + +pool pool +pptr pointer to ae_smart_ptr structure +state ALGLIB environment state + +NOTE: this function IS thread-safe. It acquires pool lock during its + operation and can be used simultaneously from several threads. +************************************************************************/ +void ae_shared_pool_recycle( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state) +{ + ae_shared_pool_entry *new_entry; + + /* state!=NULL, allocation errors are handled by throwing exception from ae_malloc() */ + AE_CRITICAL_ASSERT(state!=NULL); + + /* assert that pool was seeded */ + ae_assert( + pool->seed_object!=NULL, + "ALGLIB: shared pool is not seeded, PoolRecycle() failed", + state); + + /* assert that pointer non-null and owns the object */ + ae_assert(pptr->is_owner, "ALGLIB: pptr in ae_shared_pool_recycle() does not own its pointer", state); + ae_assert(pptr->ptr!=NULL, "ALGLIB: pptr in ae_shared_pool_recycle() is NULL", state); + + /* acquire lock */ + ae_acquire_lock(&pool->pool_lock); + + /* acquire shared pool entry (reuse one from recycled_entries or allocate new one) */ + if( pool->recycled_entries!=NULL ) + { + /* reuse previously allocated entry */ + new_entry = pool->recycled_entries; + pool->recycled_entries = (ae_shared_pool_entry*)new_entry->next_entry; + } + else + { + /* + * Allocate memory for new entry. + * + * NOTE: we release pool lock during allocation because ae_malloc() may raise + * exception and we do not want our pool to be left in the locked state. + */ + ae_release_lock(&pool->pool_lock); + new_entry = (ae_shared_pool_entry*)ae_malloc(sizeof(ae_shared_pool_entry), state); + ae_acquire_lock(&pool->pool_lock); + } + + /* add object to the list of recycled objects */ + new_entry->obj = pptr->ptr; + new_entry->next_entry = pool->recycled_objects; + pool->recycled_objects = new_entry; + + /* release lock object */ + ae_release_lock(&pool->pool_lock); + + /* release source pointer */ + ae_smart_ptr_release(pptr); +} + + +/************************************************************************ +This function clears internal list of recycled objects, but does not +change seed object managed by the pool. + +pool pool +state ALGLIB environment state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_shared_pool_clear_recycled( + ae_shared_pool *pool, + ae_state *state) +{ + ae_shared_pool_entry *ptr, *tmp; + + /* + * acquire pool lock, extract list of recycled objects and immediately release lock + * it is unlikely to happen, but if we crash during memory deallocation, it is better + * to have pool lock released at this moment. + */ + ae_acquire_lock(&pool->pool_lock); + ptr=pool->recycled_objects; + pool->recycled_objects = NULL; + ae_release_lock(&pool->pool_lock); + + /* clear recycled objects */ + while( ptr!=NULL ) + { + tmp = (ae_shared_pool_entry*)ptr->next_entry; + pool->destroy(ptr->obj); + ae_free(ptr->obj); + ae_free(ptr); + ptr = tmp; + } +} + + +/************************************************************************ +This function allows to enumerate recycled elements of the shared pool. +It stores pointer to the first recycled object in the smart pointer. + +IMPORTANT: +* in case target pointer owns non-NULL value, it is deallocated before + storing value retrieved from pool. +* recycled object IS NOT removed from pool +* target pointer DOES NOT become owner of the new value +* this function IS NOT thread-safe +* you SHOULD NOT modify shared pool during enumeration (although you can + modify state of the objects retrieved from pool) +* in case there is no recycled objects in the pool, NULL is stored to pptr +* in case pool is not seeded, NULL is stored to pptr + +pool pool +pptr pointer to ae_smart_ptr structure +state ALGLIB environment state +************************************************************************/ +void ae_shared_pool_first_recycled( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state) +{ + /* modify internal enumeration counter */ + pool->enumeration_counter = pool->recycled_objects; + + /* exit on empty list */ + if( pool->enumeration_counter==NULL ) + { + ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, 0, NULL, NULL); + return; + } + + /* assign object to smart pointer */ + ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, 0, NULL, NULL); +} + + +/************************************************************************ +This function allows to enumerate recycled elements of the shared pool. +It stores pointer to the next recycled object in the smart pointer. + +IMPORTANT: +* in case target pointer owns non-NULL value, it is deallocated before + storing value retrieved from pool. +* recycled object IS NOT removed from pool +* target pointer DOES NOT become owner of the new value +* this function IS NOT thread-safe +* you SHOULD NOT modify shared pool during enumeration (although you can + modify state of the objects retrieved from pool) +* in case there is no recycled objects left in the pool, NULL is stored. +* in case pool is not seeded, NULL is stored. + +pool pool +pptr pointer to ae_smart_ptr structure +state ALGLIB environment state +************************************************************************/ +void ae_shared_pool_next_recycled( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state) +{ + /* exit on end of list */ + if( pool->enumeration_counter==NULL ) + { + ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, 0, NULL, NULL); + return; + } + + /* modify internal enumeration counter */ + pool->enumeration_counter = (ae_shared_pool_entry*)pool->enumeration_counter->next_entry; + + /* exit on empty list */ + if( pool->enumeration_counter==NULL ) + { + ae_smart_ptr_assign(pptr, NULL, ae_false, ae_false, 0, NULL, NULL); + return; + } + + /* assign object to smart pointer */ + ae_smart_ptr_assign(pptr, pool->enumeration_counter->obj, ae_false, ae_false, 0, NULL, NULL); +} + + + +/************************************************************************ +This function clears internal list of recycled objects and seed object. +However, pool still can be used (after initialization with another seed). + +pool pool +state ALGLIB environment state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_shared_pool_reset( + ae_shared_pool *pool, + ae_state *state) +{ + /* clear seed and lists */ + ae_shared_pool_internalclear(pool); + + /* clear fields */ + pool->seed_object = NULL; + pool->recycled_objects = NULL; + pool->recycled_entries = NULL; + pool->enumeration_counter = NULL; + pool->size_of_object = 0; + pool->init_copy = NULL; + pool->destroy = NULL; +} + + +/************************************************************************ +This function initializes nx-pool: + +dst destination shared pool, must be zero-filled + already allocated, but not initialized. +datatype is a type of array elements +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +The newly initialized pool has N set to zero. + +Error handling: +* on failure calls ae_break() with NULL state pointer. Usually it results + in abort() call. +************************************************************************/ +void ae_nxpool_init(ae_nxpool *dst, ae_datatype datatype, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + /* attach to frame first, just to be sure that if we fail within malloc, we will be able to clean up the object */ + dst->frame_entry.deallocator = (ae_destructor)ae_nxpool_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); + + /* init */ + ae_db_init(&dst->storage, 0, state, ae_false); + dst->datatype = datatype; + dst->array_size = 0; + dst->capacity = 0; + dst->nstored = 0; + ae_init_lock(&dst->pool_lock, state, ae_false); +} + + +/************************************************************************ +This function creates copy of ae_nxpool. + +dst destination pool, must be zero-filled +src source pool +state pointer to current state structure. Can not be NULL. + used for exception handling (say, allocation error results + in longjmp call). +make_automatic if true, vector will be registered in the current frame + of the state structure; + +dst is assumed to be uninitialized, its fields are ignored. + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_nxpool_init_copy(ae_nxpool *dst, const ae_nxpool *src, ae_state *state, ae_bool make_automatic) +{ + AE_CRITICAL_ASSERT(state!=NULL); + AE_CRITICAL_ASSERT(ae_check_zeros(dst,(ae_int_t)sizeof(*dst))); + + /* attach to frame first, just to be sure that if we fail within malloc, we will be able to clean up the object */ + dst->frame_entry.deallocator = (ae_destructor)ae_nxpool_destroy; + dst->frame_entry.ptr = dst; + if( make_automatic ) + ae_db_attach(&dst->frame_entry, state); + + /* init */ + dst->datatype = src->datatype; + dst->array_size = src->array_size; + dst->capacity = src->capacity; + dst->nstored = src->nstored; + ae_db_init(&dst->storage, dst->capacity*sizeof(ae_dyn_block), state, ae_false); + memset(dst->storage.ptr, 0, dst->capacity*sizeof(ae_dyn_block)); + ae_init_lock(&dst->pool_lock, state, ae_false); + + /* copy data */ + for(ae_int_t i=0; instored; i++) + { + ae_int_t arr_bytes = ae_sizeof(dst->datatype)*dst->array_size; + ae_dyn_block *dst_blk = ((ae_dyn_block*)dst->storage.ptr)+i; + ae_dyn_block *src_blk = ((ae_dyn_block*)src->storage.ptr)+i; + ae_db_init(dst_blk, arr_bytes, state, ae_false); + memmove(dst_blk->ptr, src_blk->ptr, arr_bytes); + } +} + +/************************************************************************ +This function clears the pool object, leaving it in the usable state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when pool can be used by another thread. +************************************************************************/ +void ae_nxpool_clear(ae_nxpool *pool) +{ + for(ae_int_t i=0; instored; i++) + ae_db_free(((ae_dyn_block*)pool->storage.ptr)+i); + pool->array_size = 0; + pool->nstored = 0; +} + +/************************************************************************ +This function destroys the pool object, deallocating all internally allocated +memory and leaving it in the unusable state + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when pool can be used by another thread. +************************************************************************/ +void ae_nxpool_destroy(ae_nxpool *pool) +{ + ae_nxpool_clear(pool); + ae_db_free(&pool->storage); + ae_free_lock(&pool->pool_lock); +} + + +/************************************************************************ +This function configures the pool to work with N-sized arrays. All arrays +that are stored in the pool are freed, unless new N is equal to the old +one. + +pool pool +size new array size, N>=0 + +NOTE: this function is NOT thread-safe. It does not acquire pool lock, so + you should NOT call it when lock can be used by another thread. +************************************************************************/ +void ae_nxpool_alloc(ae_nxpool *pool, ae_int_t size, ae_state *state) +{ + /* integrity checks */ + ae_assert(size>=0, "ae_nxpool_alloc: size<0", state); + + /* quick exit if nothing have to be done */ + if( size==pool->array_size ) + return; + + /* update pool settings */ + pool->array_size = size; + + /* remove all currently allocated arrays from the pool */ + for(ae_int_t i=0; instored; i++) + ae_db_free(((ae_dyn_block*)pool->storage.ptr)+i); + pool->nstored = 0; +} + + +/************************************************************************ +This function retrieves array from the pool, either one stored in the +pool, or a completely new one (if the pool is empty). + +pool pool +dst array instance; on entry must have zero length and + exactly the same datatype as the pool + +NOTE: this function IS thread-safe. It acquires pool lock during its + operation and can be used simultaneously from several threads. +************************************************************************/ +void ae_nxpool_retrieve(ae_nxpool *pool, ae_vector *dst, ae_state *state) +{ + /* integrity checks */ + ae_assert(pool->datatype==dst->datatype, "ae_nxpool_retrieve: destination array type does not match", state); + ae_assert(dst->cnt==0, "ae_nxpool_retrieve: destination array has non-zero length", state); + + /* acquire lock */ + ae_acquire_lock(&pool->pool_lock); + + /* quick exit if the pool is empty */ + if( pool->nstored==0 ) + { + ae_release_lock(&pool->pool_lock); + ae_vector_set_length(dst, pool->array_size, state); + return; + } + + /* retrieve from the pool */ + ae_db_swap(&dst->data, ((ae_dyn_block*)pool->storage.ptr)+pool->nstored-1); + dst->ptr.p_ptr = dst->data.ptr; + dst->cnt = pool->array_size; + pool->nstored = pool->nstored-1; + + /* release lock */ + ae_release_lock(&pool->pool_lock); +} + + +/************************************************************************ +This function recycles array into the pool, either one previously +retrieved from the pool, or one allocated somewhere else, but having +exactly the same size and elements type. + +pool pool +src array instance; on entry must have length=N and + exactly the same datatype as the pool. On exit it's + length is set to zero. + +NOTE: this function IS thread-safe. It acquires pool lock during its + operation and can be used simultaneously from several threads. +************************************************************************/ +void ae_nxpool_recycle(ae_nxpool *pool, ae_vector *src, ae_state *state) +{ + /* integrity checks */ + ae_assert(pool->datatype==src->datatype, "ae_nxpool_recycle: source array type does not match", state); + ae_assert(src->cnt==pool->array_size, "ae_nxpool_recycle: source array has non-matching length", state); + + /* acquire lock */ + ae_acquire_lock(&pool->pool_lock); + + /* if full, reallocate storage using temporary dynamic block */ + if( pool->nstored==pool->capacity ) + { + ae_int_t new_capacity = 2*pool->capacity+5; + ae_dyn_block tmp_blk; + memset(&tmp_blk, 0, sizeof(tmp_blk)); + ae_db_init(&tmp_blk, 0, state, ae_false); + ae_db_swap(&tmp_blk, &pool->storage); + ae_db_realloc(&pool->storage, new_capacity*sizeof(tmp_blk), state); + memset(pool->storage.ptr, 0, new_capacity*sizeof(tmp_blk)); + for(ae_int_t i=0; istorage.ptr)+i, 0, state, ae_false); + for(ae_int_t i=0; icapacity; i++) + ae_db_swap(((ae_dyn_block*)pool->storage.ptr)+i, ((ae_dyn_block*)tmp_blk.ptr)+i); + ae_db_free(&tmp_blk); + pool->capacity = new_capacity; + } + + /* store */ + ae_db_swap(&src->data, ((ae_dyn_block*)pool->storage.ptr)+pool->nstored); + src->ptr.p_ptr = src->data.ptr; + src->cnt = 0; + pool->nstored = pool->nstored+1; + + /* release lock */ + ae_release_lock(&pool->pool_lock); +} + + +/************************************************************************ +This function initializes serializer +************************************************************************/ +void ae_serializer_init(ae_serializer *serializer) +{ + serializer->mode = AE_SM_DEFAULT; + serializer->entries_needed = 0; + serializer->bytes_asked = 0; +} + +void ae_serializer_clear(ae_serializer *serializer) +{ +} + +void ae_serializer_alloc_start(ae_serializer *serializer) +{ + serializer->entries_needed = 0; + serializer->bytes_asked = 0; + serializer->mode = AE_SM_ALLOC; +} + +void ae_serializer_alloc_entry(ae_serializer *serializer) +{ + serializer->entries_needed++; +} + +void ae_serializer_alloc_byte_array(ae_serializer *serializer, const ae_vector *bytes) +{ + ae_int_t n; + n = bytes->cnt; + n = n/8 + (n%8>0 ? 1 : 0); + serializer->entries_needed += 1+n; +} + +/************************************************************************ +After allocation phase is done, this function returns required size of +the output string buffer (including trailing zero symbol). Actual size of +the data being stored can be a few characters smaller than requested. +************************************************************************/ +ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer) +{ + ae_int_t rows, lastrowsize, result; + + serializer->mode = AE_SM_READY2S; + + /* if no entries needes (degenerate case) */ + if( serializer->entries_needed==0 ) + { + serializer->bytes_asked = 4; /* a pair of chars for \r\n, one for dot, one for trailing zero */ + return serializer->bytes_asked; + } + + /* non-degenerate case */ + rows = serializer->entries_needed/AE_SER_ENTRIES_PER_ROW; + lastrowsize = AE_SER_ENTRIES_PER_ROW; + if( serializer->entries_needed%AE_SER_ENTRIES_PER_ROW ) + { + lastrowsize = serializer->entries_needed%AE_SER_ENTRIES_PER_ROW; + rows++; + } + + /* calculate result size */ + result = ((rows-1)*AE_SER_ENTRIES_PER_ROW+lastrowsize)*AE_SER_ENTRY_LENGTH; /* data size */ + result += (rows-1)*(AE_SER_ENTRIES_PER_ROW-1)+(lastrowsize-1); /* space symbols */ + result += rows*2; /* newline symbols */ + result += 1; /* trailing dot */ + result += 1; /* trailing zero */ + serializer->bytes_asked = result; + return result; +} + +#ifdef AE_USE_CPP_SERIALIZATION +void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf) +{ + serializer->mode = AE_SM_TO_CPPSTRING; + serializer->out_cppstr = buf; + serializer->entries_saved = 0; + serializer->bytes_written = 0; +} + +void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf) +{ + serializer->mode = AE_SM_FROM_STRING; + serializer->in_str = buf->c_str(); +} + +static char cpp_writer(const char *p_string, ae_int_t aux) +{ + std::ostream *stream = reinterpret_cast(aux); + stream->write(p_string, (std::streamsize)strlen(p_string)); + return stream->bad() ? 1 : 0; +} + +static char cpp_reader(ae_int_t aux, ae_int_t cnt, char *p_buf) +{ + std::istream *stream = reinterpret_cast(aux); + int c; + if( cnt<=0 ) + return 1; /* unexpected cnt */ + for(;;) + { + c = stream->get(); + if( c<0 || c>255 ) + return 1; /* failure! */ + if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) + break; + } + p_buf[0] = (char)c; + for(int k=1; kget(); + if( c<0 || c>255 || c==' ' || c=='\t' || c=='\n' || c=='\r' ) + return 1; /* failure! */ + p_buf[k] = (char)c; + } + p_buf[cnt] = 0; + return 0; /* success */ +} + +void ae_serializer_sstart_stream(ae_serializer *serializer, std::ostream *stream) +{ + serializer->mode = AE_SM_TO_STREAM; + serializer->stream_writer = cpp_writer; + serializer->stream_aux = reinterpret_cast(stream); + serializer->entries_saved = 0; + serializer->bytes_written = 0; +} + +void ae_serializer_ustart_stream(ae_serializer *serializer, const std::istream *stream) +{ + serializer->mode = AE_SM_FROM_STREAM; + serializer->stream_reader = cpp_reader; + serializer->stream_aux = reinterpret_cast(stream); +} +#endif + +void ae_serializer_sstart_str(ae_serializer *serializer, char *buf) +{ + serializer->mode = AE_SM_TO_STRING; + serializer->out_str = buf; + serializer->out_str[0] = 0; + serializer->entries_saved = 0; + serializer->bytes_written = 0; +} + +void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf) +{ + serializer->mode = AE_SM_FROM_STRING; + serializer->in_str = buf; +} + +void ae_serializer_sstart_stream(ae_serializer *serializer, ae_stream_writer writer, ae_int_t aux) +{ + serializer->mode = AE_SM_TO_STREAM; + serializer->stream_writer = writer; + serializer->stream_aux = aux; + serializer->entries_saved = 0; + serializer->bytes_written = 0; +} + +void ae_serializer_ustart_stream(ae_serializer *serializer, ae_stream_reader reader, ae_int_t aux) +{ + serializer->mode = AE_SM_FROM_STREAM; + serializer->stream_reader = reader; + serializer->stream_aux = aux; +} + +void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state) +{ + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *emsg = "ALGLIB: serialization integrity error"; + ae_int_t bytes_appended; + + /* prepare serialization, check consistency */ + ae_bool2str(v, buf, state); + serializer->entries_saved++; + if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) + strcat(buf, " "); + else + strcat(buf, "\r\n"); + bytes_appended = (ae_int_t)strlen(buf); + ae_assert(serializer->bytes_written+bytes_appendedbytes_asked, emsg, state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written += bytes_appended; + + /* append to buffer */ +#ifdef AE_USE_CPP_SERIALIZATION + if( serializer->mode==AE_SM_TO_CPPSTRING ) + { + *(serializer->out_cppstr) += buf; + return; + } +#endif + if( serializer->mode==AE_SM_TO_STRING ) + { + strcat(serializer->out_str, buf); + serializer->out_str += bytes_appended; + return; + } + if( serializer->mode==AE_SM_TO_STREAM ) + { + ae_assert(serializer->stream_writer(buf, serializer->stream_aux)==0, "serializer: error writing to stream", state); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, emsg); +} + +void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state) +{ + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *emsg = "ALGLIB: serialization integrity error"; + ae_int_t bytes_appended; + + /* prepare serialization, check consistency */ + ae_int2str(v, buf, state); + serializer->entries_saved++; + if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) + strcat(buf, " "); + else + strcat(buf, "\r\n"); + bytes_appended = (ae_int_t)strlen(buf); + ae_assert(serializer->bytes_written+bytes_appendedbytes_asked, emsg, state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written += bytes_appended; + + /* append to buffer */ +#ifdef AE_USE_CPP_SERIALIZATION + if( serializer->mode==AE_SM_TO_CPPSTRING ) + { + *(serializer->out_cppstr) += buf; + return; + } +#endif + if( serializer->mode==AE_SM_TO_STRING ) + { + strcat(serializer->out_str, buf); + serializer->out_str += bytes_appended; + return; + } + if( serializer->mode==AE_SM_TO_STREAM ) + { + ae_assert(serializer->stream_writer(buf, serializer->stream_aux)==0, "serializer: error writing to stream", state); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, emsg); +} + +void ae_serializer_serialize_int64(ae_serializer *serializer, ae_int64_t v, ae_state *state) +{ + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *emsg = "ALGLIB: serialization integrity error"; + ae_int_t bytes_appended; + + /* prepare serialization, check consistency */ + ae_int642str(v, buf, state); + serializer->entries_saved++; + if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) + strcat(buf, " "); + else + strcat(buf, "\r\n"); + bytes_appended = (ae_int_t)strlen(buf); + ae_assert(serializer->bytes_written+bytes_appendedbytes_asked, emsg, state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written += bytes_appended; + + /* append to buffer */ +#ifdef AE_USE_CPP_SERIALIZATION + if( serializer->mode==AE_SM_TO_CPPSTRING ) + { + *(serializer->out_cppstr) += buf; + return; + } +#endif + if( serializer->mode==AE_SM_TO_STRING ) + { + strcat(serializer->out_str, buf); + serializer->out_str += bytes_appended; + return; + } + if( serializer->mode==AE_SM_TO_STREAM ) + { + ae_assert(serializer->stream_writer(buf, serializer->stream_aux)==0, "serializer: error writing to stream", state); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, emsg); +} + +void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state) +{ + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *emsg = "ALGLIB: serialization integrity error"; + ae_int_t bytes_appended; + + /* prepare serialization, check consistency */ + ae_double2str(v, buf, state); + serializer->entries_saved++; + if( serializer->entries_saved%AE_SER_ENTRIES_PER_ROW ) + strcat(buf, " "); + else + strcat(buf, "\r\n"); + bytes_appended = (ae_int_t)strlen(buf); + ae_assert(serializer->bytes_written+bytes_appendedbytes_asked, emsg, state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written += bytes_appended; + + /* append to buffer */ +#ifdef AE_USE_CPP_SERIALIZATION + if( serializer->mode==AE_SM_TO_CPPSTRING ) + { + *(serializer->out_cppstr) += buf; + return; + } +#endif + if( serializer->mode==AE_SM_TO_STRING ) + { + strcat(serializer->out_str, buf); + serializer->out_str += bytes_appended; + return; + } + if( serializer->mode==AE_SM_TO_STREAM ) + { + ae_assert(serializer->stream_writer(buf, serializer->stream_aux)==0, "serializer: error writing to stream", state); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, emsg); +} + +void ae_serializer_serialize_byte_array(ae_serializer *serializer, const ae_vector *bytes, ae_state *state) +{ + ae_int_t chunk_size, entries_count; + + chunk_size = 8; + + /* save array length */ + ae_serializer_serialize_int(serializer, bytes->cnt, state); + + /* determine entries count */ + entries_count = bytes->cnt/chunk_size + (bytes->cnt%chunk_size>0 ? 1 : 0); + for(ae_int_t eidx=0; eidxcnt - eidx*chunk_size; + elen = elen>chunk_size ? chunk_size : elen; + memset(&tmpi, 0, sizeof(tmpi)); + memmove(&tmpi, bytes->ptr.p_ubyte + eidx*chunk_size, (size_t)elen); + ae_serializer_serialize_int64(serializer, tmpi, state); + } +} + +void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state) +{ + if( serializer->mode==AE_SM_FROM_STRING ) + { + *v = ae_str2bool(serializer->in_str, state, &serializer->in_str); + return; + } + if( serializer->mode==AE_SM_FROM_STREAM ) + { + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *p = buf; + ae_assert(serializer->stream_reader(serializer->stream_aux, AE_SER_ENTRY_LENGTH, buf)==0, "serializer: error reading from stream", state); + *v = ae_str2bool(buf, state, &p); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, "ae_serializer: integrity check failed"); +} + +void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state) +{ + if( serializer->mode==AE_SM_FROM_STRING ) + { + *v = ae_str2int(serializer->in_str, state, &serializer->in_str); + return; + } + if( serializer->mode==AE_SM_FROM_STREAM ) + { + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *p = buf; + ae_assert(serializer->stream_reader(serializer->stream_aux, AE_SER_ENTRY_LENGTH, buf)==0, "serializer: error reading from stream", state); + *v = ae_str2int(buf, state, &p); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, "ae_serializer: integrity check failed"); +} + +void ae_serializer_unserialize_int64(ae_serializer *serializer, ae_int64_t *v, ae_state *state) +{ + if( serializer->mode==AE_SM_FROM_STRING ) + { + *v = ae_str2int64(serializer->in_str, state, &serializer->in_str); + return; + } + if( serializer->mode==AE_SM_FROM_STREAM ) + { + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *p = buf; + ae_assert(serializer->stream_reader(serializer->stream_aux, AE_SER_ENTRY_LENGTH, buf)==0, "serializer: error reading from stream", state); + *v = ae_str2int64(buf, state, &p); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, "ae_serializer: integrity check failed"); +} + +void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state) +{ + if( serializer->mode==AE_SM_FROM_STRING ) + { + *v = ae_str2double(serializer->in_str, state, &serializer->in_str); + return; + } + if( serializer->mode==AE_SM_FROM_STREAM ) + { + char buf[AE_SER_ENTRY_LENGTH+2+1]; + const char *p = buf; + ae_assert(serializer->stream_reader(serializer->stream_aux, AE_SER_ENTRY_LENGTH, buf)==0, "serializer: error reading from stream", state); + *v = ae_str2double(buf, state, &p); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, "ae_serializer: integrity check failed"); +} + +void ae_serializer_unserialize_byte_array(ae_serializer *serializer, ae_vector *bytes, ae_state *state) +{ + ae_int_t chunk_size, n, entries_count; + + chunk_size = 8; + + /* read array length, allocate output */ + ae_serializer_unserialize_int(serializer, &n, state); + ae_vector_set_length(bytes, n, state); + + /* determine entries count, read entries */ + entries_count = n/chunk_size + (n%chunk_size>0 ? 1 : 0); + for(ae_int_t eidx=0; eidxchunk_size ? chunk_size : elen; + ae_serializer_unserialize_int64(serializer, &tmp64, state); + memmove(bytes->ptr.p_ubyte+eidx*chunk_size, &tmp64, (size_t)elen); + } +} + +void ae_serializer_stop(ae_serializer *serializer, ae_state *state) +{ +#ifdef AE_USE_CPP_SERIALIZATION + if( serializer->mode==AE_SM_TO_CPPSTRING ) + { + ae_assert(serializer->bytes_written+1bytes_asked, "ae_serializer: integrity check failed", state);/* strict "less" because we need space for trailing zero */ + serializer->bytes_written++; + *(serializer->out_cppstr) += "."; + return; + } +#endif + if( serializer->mode==AE_SM_TO_STRING ) + { + ae_assert(serializer->bytes_written+1bytes_asked, "ae_serializer: integrity check failed", state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written++; + strcat(serializer->out_str, "."); + serializer->out_str += 1; + return; + } + if( serializer->mode==AE_SM_TO_STREAM ) + { + ae_assert(serializer->bytes_written+1bytes_asked, "ae_serializer: integrity check failed", state); /* strict "less" because we need space for trailing zero */ + serializer->bytes_written++; + ae_assert(serializer->stream_writer(".", serializer->stream_aux)==0, "ae_serializer: error writing to stream", state); + return; + } + if( serializer->mode==AE_SM_FROM_STRING ) + { + /* + * because input string may be from pre-3.11 serializer, + * which does not include trailing dot, we do not test + * string for presence of "." symbol. Anyway, because string + * is not stream, we do not have to read ALL trailing symbols. + */ + return; + } + if( serializer->mode==AE_SM_FROM_STREAM ) + { + /* + * Read trailing dot, perform integrity check + */ + char buf[2]; + ae_assert(serializer->stream_reader(serializer->stream_aux, 1, buf)==0, "ae_serializer: error reading from stream", state); + ae_assert(buf[0]=='.', "ae_serializer: trailing . is not found in the stream", state); + return; + } + ae_break(state, ERR_ASSERTION_FAILED, "ae_serializer: integrity check failed"); +} + + +/************************************************************************ +Complex math functions +************************************************************************/ +ae_complex ae_complex_from_i(ae_int_t v) +{ + ae_complex r; + r.x = (double)v; + r.y = 0.0; + return r; +} + +ae_complex ae_complex_from_d(double v) +{ + ae_complex r; + r.x = v; + r.y = 0.0; + return r; +} + +ae_complex ae_c_neg(ae_complex lhs) +{ + ae_complex result; + result.x = -lhs.x; + result.y = -lhs.y; + return result; +} + +ae_complex ae_c_conj(ae_complex lhs, ae_state *state) +{ + ae_complex result; + result.x = +lhs.x; + result.y = -lhs.y; + return result; +} + +ae_complex ae_c_sqr(ae_complex lhs, ae_state *state) +{ + ae_complex result; + result.x = lhs.x*lhs.x-lhs.y*lhs.y; + result.y = 2.0*lhs.x*lhs.y; + return result; +} + +double ae_c_abs(ae_complex z, ae_state *state) +{ + double w; + double xabs; + double yabs; + double v; + + xabs = fabs(z.x); + yabs = fabs(z.y); + w = xabs>yabs ? xabs : yabs; + v = xabsx; + v0y = -v0->y; + v1x = v1->x; + v1y = -v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( !bconj0 && bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = v0->y; + v1x = v1->x; + v1y = -v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( bconj0 && !bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = -v0->y; + v1x = v1->x; + v1y = v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( !bconj0 && !bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = v0->y; + v1x = v1->x; + v1y = v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + result.x = rx; + result.y = ry; + return result; +} + +void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + for(i=0; ix = vsrc->x; + vdst->y = -vsrc->y; + } + } + else + { + for(i=0; ix = vsrc->x; + vdst->y = -vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = -vsrc->y; + } + } + } + else + { + /* + * optimized case + */ + if( bconj ) + { + for(i=0; ix = -vsrc->x; + vdst->y = vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = -vsrc->y; + } + } + } +} + +void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = -alpha*vsrc->y; + } + } + else + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = alpha*vsrc->y; + } + } + } + else + { + /* + * optimized case + */ + if( bconj ) + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = -alpha*vsrc->y; + } + } + else + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = alpha*vsrc->y; + } + } + } +} + +void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x+ay*vsrc->y; + vdst->y = -ax*vsrc->y+ay*vsrc->x; + } + } + else + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x-ay*vsrc->y; + vdst->y = ax*vsrc->y+ay*vsrc->x; + } + } + } + else + { + /* + * highly optimized case + */ + if( bconj ) + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x+ay*vsrc->y; + vdst->y = -ax*vsrc->y+ay*vsrc->x; + } + } + else + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x-ay*vsrc->y; + vdst->y = ax*vsrc->y+ay*vsrc->x; + } + } + } +} + +void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + for(i=0; ix += vsrc->x; + vdst->y -= vsrc->y; + } + } + else + { + for(i=0; ix += vsrc->x; + vdst->y += vsrc->y; + } + } + } + else + { + /* + * optimized case + */ + if( bconj ) + { + for(i=0; ix += vsrc->x; + vdst->y -= vsrc->y; + } + } + else + { + for(i=0; ix += vsrc->x; + vdst->y += vsrc->y; + } + } + } +} + +void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + for(i=0; ix += alpha*vsrc->x; + vdst->y -= alpha*vsrc->y; + } + } + else + { + for(i=0; ix += alpha*vsrc->x; + vdst->y += alpha*vsrc->y; + } + } + } + else + { + /* + * optimized case + */ + if( bconj ) + { + for(i=0; ix += alpha*vsrc->x; + vdst->y -= alpha*vsrc->y; + } + } + else + { + for(i=0; ix += alpha*vsrc->x; + vdst->y += alpha*vsrc->y; + } + } + } +} + +void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + double ax = alpha.x, ay = alpha.y; + if( bconj ) + { + for(i=0; ix += ax*vsrc->x+ay*vsrc->y; + vdst->y -= ax*vsrc->y-ay*vsrc->x; + } + } + else + { + for(i=0; ix += ax*vsrc->x-ay*vsrc->y; + vdst->y += ax*vsrc->y+ay*vsrc->x; + } + } + } + else + { + /* + * highly optimized case + */ + double ax = alpha.x, ay = alpha.y; + if( bconj ) + { + for(i=0; ix += ax*vsrc->x+ay*vsrc->y; + vdst->y -= ax*vsrc->y-ay*vsrc->x; + } + } + else + { + for(i=0; ix += ax*vsrc->x-ay*vsrc->y; + vdst->y += ax*vsrc->y+ay*vsrc->x; + } + } + } +} + +void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n) +{ + ae_bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + /* + * general unoptimized case + */ + if( bconj ) + { + for(i=0; ix -= vsrc->x; + vdst->y += vsrc->y; + } + } + else + { + for(i=0; ix -= vsrc->x; + vdst->y -= vsrc->y; + } + } + } + else + { + /* + * highly optimized case + */ + if( bconj ) + { + for(i=0; ix -= vsrc->x; + vdst->y += vsrc->y; + } + } + else + { + for(i=0; ix -= vsrc->x; + vdst->y -= vsrc->y; + } + } + } +} + +void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) +{ + ae_v_caddd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); +} + +void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha) +{ + alpha.x = -alpha.x; + alpha.y = -alpha.y; + ae_v_caddc(vdst, stride_dst, vsrc, stride_src, conj_src, n, alpha); +} + +void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) +{ + ae_int_t i; + if( stride_dst!=1 ) + { + /* + * general unoptimized case + */ + for(i=0; ix *= alpha; + vdst->y *= alpha; + } + } + else + { + /* + * optimized case + */ + for(i=0; ix *= alpha; + vdst->y *= alpha; + } + } +} + +void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha) +{ + ae_int_t i; + if( stride_dst!=1 ) + { + /* + * general unoptimized case + */ + double ax = alpha.x, ay = alpha.y; + for(i=0; ix, dsty = vdst->y; + vdst->x = ax*dstx-ay*dsty; + vdst->y = ax*dsty+ay*dstx; + } + } + else + { + /* + * highly optimized case + */ + double ax = alpha.x, ay = alpha.y; + for(i=0; ix, dsty = vdst->y; + vdst->x = ax*dstx-ay*dsty; + vdst->y = ax*dsty+ay*dstx; + } + } +} + +/************************************************************************ +Real BLAS operations +************************************************************************/ +double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n) +{ + double result = 0.0; + ae_int_t i; + if( stride0!=1 || stride1!=1 ) + { + /* + * slow general code + */ + for(i=0; iba, 0, sizeof(p->ba)); + memset(&p->ia, 0, sizeof(p->ia)); + memset(&p->ra, 0, sizeof(p->ra)); + memset(&p->ca, 0, sizeof(p->ca)); + + /* initialization */ + ae_vector_init(&p->ba, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->ia, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ra, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ca, 0, DT_COMPLEX, _state, make_automatic); +} + +void _rcommstate_init_copy(rcommstate* dst, const rcommstate* src, ae_state *_state, ae_bool make_automatic) +{ + /* initial zero-filling */ + memset(&dst->ba, 0, sizeof(dst->ba)); + memset(&dst->ia, 0, sizeof(dst->ia)); + memset(&dst->ra, 0, sizeof(dst->ra)); + memset(&dst->ca, 0, sizeof(dst->ca)); + + /* initialization */ + ae_vector_init_copy(&dst->ba, &src->ba, _state, make_automatic); + ae_vector_init_copy(&dst->ia, &src->ia, _state, make_automatic); + ae_vector_init_copy(&dst->ra, &src->ra, _state, make_automatic); + ae_vector_init_copy(&dst->ca, &src->ca, _state, make_automatic); + dst->stage = src->stage; +} + +void _rcommstate_clear(rcommstate* p) +{ + ae_vector_clear(&p->ba); + ae_vector_clear(&p->ia); + ae_vector_clear(&p->ra); + ae_vector_clear(&p->ca); +} + +void _rcommstate_destroy(rcommstate* p) +{ + _rcommstate_clear(p); +} + +#if !defined(ALGLIB_NO_FAST_KERNELS) +/************************************************************************* +Maximum concurrency on given system, with given compilation settings +*************************************************************************/ +ae_int_t maxconcurrency(ae_state *_state) +{ + return get_nprocessors_cached(); +} +#endif + + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ RELATED FUNCTIONALITY +// +///////////////////////////////////////////////////////////////////////// +#if !defined(AE_NO_EXCEPTIONS) +#define _ALGLIB_ASSERT_THROW_OR_BREAK(cond,msg) if( !(cond) ) throw alglib::ap_error(msg) +#else +#define _ALGLIB_ASSERT_THROW_OR_BREAK(cond,msg) AE_CRITICAL_ASSERT(!(cond)) +#endif + +/******************************************************************** +Internal forwards +********************************************************************/ +namespace alglib +{ + double get_aenv_nan(); + double get_aenv_posinf(); + double get_aenv_neginf(); + ae_int_t my_stricmp(const char *s1, const char *s2); + char* filter_spaces(const char *s); + void str_vector_create(const char *src, bool match_head_only, std::vector *p_vec); + void str_matrix_create(const char *src, std::vector< std::vector > *p_mat); + + ae_bool parse_bool_delim(const char *s, const char *delim); + ae_int_t parse_int_delim(const char *s, const char *delim); + bool _parse_real_delim(const char *s, const char *delim, double *result, const char **new_s); + double parse_real_delim(const char *s, const char *delim); + alglib::complex parse_complex_delim(const char *s, const char *delim); + + std::string arraytostring(const bool *ptr, ae_int_t n); + std::string arraytostring(const ae_int_t *ptr, ae_int_t n); + std::string arraytostring(const double *ptr, ae_int_t n, int dps); + std::string arraytostring(const alglib::complex *ptr, ae_int_t n, int dps); +} + +/******************************************************************** +Global and local constants/variables +********************************************************************/ +const double alglib::machineepsilon = 5E-16; +const double alglib::maxrealnumber = 1E300; +const double alglib::minrealnumber = 1E-300; +const alglib::ae_int_t alglib::endianness = alglib_impl::ae_get_endianness(); +const double alglib::fp_nan = alglib::get_aenv_nan(); +const double alglib::fp_posinf = alglib::get_aenv_posinf(); +const double alglib::fp_neginf = alglib::get_aenv_neginf(); +#if defined(AE_NO_EXCEPTIONS) +static const char *_alglib_last_error = NULL; +#endif +static const alglib_impl::ae_uint64_t _i64_xdefault = 0x0; +static const alglib_impl::ae_uint64_t _i64_xserial = _ALGLIB_FLG_THREADING_SERIAL; +static const alglib_impl::ae_uint64_t _i64_xparallel = _ALGLIB_FLG_THREADING_PARALLEL; +static const alglib_impl::ae_uint64_t _i64_xserial_callbacks = _ALGLIB_FLG_THREADING_SERIAL_CALLBACKS; +static const alglib_impl::ae_uint64_t _i64_xparallel_callbacks = _ALGLIB_FLG_THREADING_PARALLEL_CALLBACKS; +static const alglib_impl::ae_uint64_t _i64_xbackend_linalg = _ALGLIB_FLG_BACKEND_LINALG; +static const alglib_impl::ae_uint64_t _i64_xno_backend_linalg = _ALGLIB_FLG_BACKEND_NOLINALG; +static const alglib_impl::ae_uint64_t _i64_xbackend_dss = _ALGLIB_FLG_BACKEND_DSS; +static const alglib_impl::ae_uint64_t _i64_xno_backend_dss = _ALGLIB_FLG_BACKEND_NODSS; +const alglib::xparams &alglib::xdefault = *((const alglib::xparams *)(&_i64_xdefault)); +const alglib::xparams &alglib::serial = *((const alglib::xparams *)(&_i64_xserial)); +const alglib::xparams &alglib::parallel = *((const alglib::xparams *)(&_i64_xparallel)); +const alglib::xparams &alglib::serial_callbacks = *((const alglib::xparams *)(&_i64_xserial_callbacks)); +const alglib::xparams &alglib::parallel_callbacks = *((const alglib::xparams *)(&_i64_xparallel_callbacks)); +const alglib::xparams &alglib::backend_linalg = *((const alglib::xparams *)(&_i64_xbackend_linalg)); +const alglib::xparams &alglib::no_backend_linalg = *((const alglib::xparams *)(&_i64_xno_backend_linalg)); +const alglib::xparams &alglib::backend_dss = *((const alglib::xparams *)(&_i64_xbackend_dss)); +const alglib::xparams &alglib::no_backend_dss = *((const alglib::xparams *)(&_i64_xno_backend_dss)); + + + + +/******************************************************************** +Exception handling +********************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +alglib::ap_error::ap_error() +{ +} + +alglib::ap_error::ap_error(const char *s) +{ + msg = s; +} + +alglib::ap_error::ap_error(const std::string &s) +{ + msg = s; +} + +void alglib::ap_error::make_assertion(bool bClause) +{ + if(!bClause) + _ALGLIB_CPP_EXCEPTION(""); +} + +void alglib::ap_error::make_assertion(bool bClause, const char *p_msg) +{ + if(!bClause) + _ALGLIB_CPP_EXCEPTION(p_msg); +} +#else +void alglib::set_error_flag(const char *s) +{ + if( s==NULL ) + s = "ALGLIB: unknown error"; + _alglib_last_error = s; +} + +bool alglib::get_error_flag(const char **p_msg) +{ + if( _alglib_last_error==NULL ) + return false; + if( p_msg!=NULL ) + *p_msg = _alglib_last_error; + return true; +} + +void alglib::clear_error_flag() +{ + _alglib_last_error = NULL; +} +#endif + +/******************************************************************** +Complex number with double precision. +********************************************************************/ +alglib::complex::complex():x(0.0),y(0.0) +{ +} + +alglib::complex::complex(const double &_x):x(_x),y(0.0) +{ +} + +alglib::complex::complex(const double &_x, const double &_y):x(_x),y(_y) +{ +} + +alglib::complex::complex(const alglib::complex &z):x(z.x),y(z.y) +{ +} + +alglib::complex& alglib::complex::operator= (const double& v) +{ + x = v; + y = 0.0; + return *this; +} + +alglib::complex& alglib::complex::operator+=(const double& v) +{ + x += v; + return *this; +} + +alglib::complex& alglib::complex::operator-=(const double& v) +{ + x -= v; + return *this; +} + +alglib::complex& alglib::complex::operator*=(const double& v) +{ + x *= v; + y *= v; + return *this; +} + +alglib::complex& alglib::complex::operator/=(const double& v) +{ + x /= v; + y /= v; + return *this; +} + +alglib::complex& alglib::complex::operator= (const alglib::complex& z) +{ + x = z.x; + y = z.y; + return *this; +} + +alglib::complex& alglib::complex::operator+=(const alglib::complex& z) +{ + x += z.x; + y += z.y; + return *this; +} + +alglib::complex& alglib::complex::operator-=(const alglib::complex& z) +{ + x -= z.x; + y -= z.y; + return *this; +} + +alglib::complex& alglib::complex::operator*=(const alglib::complex& z) +{ + double t = x*z.x-y*z.y; + y = x*z.y+y*z.x; + x = t; + return *this; +} + +alglib::complex& alglib::complex::operator/=(const alglib::complex& z) +{ + alglib::complex result; + double e; + double f; + if( fabs(z.y)=0 ? _dps : -_dps; + if( dps<=0 || dps>=20 ) + _ALGLIB_CPP_EXCEPTION("complex::tostring(): incorrect dps"); + + // handle IEEE special quantities + if( fp_isnan(x) || fp_isnan(y) ) + return "NAN"; + if( fp_isinf(x) || fp_isinf(y) ) + return "INF"; + + // generate mask + if( sprintf(mask, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask) ) + _ALGLIB_CPP_EXCEPTION("complex::tostring(): buffer overflow"); + + // print |x|, |y| and zero with same mask and compare + if( sprintf(buf_x, mask, (double)(fabs(x)))>=(int)sizeof(buf_x) ) + _ALGLIB_CPP_EXCEPTION("complex::tostring(): buffer overflow"); + if( sprintf(buf_y, mask, (double)(fabs(y)))>=(int)sizeof(buf_y) ) + _ALGLIB_CPP_EXCEPTION("complex::tostring(): buffer overflow"); + if( sprintf(buf_zero, mask, (double)0)>=(int)sizeof(buf_zero) ) + _ALGLIB_CPP_EXCEPTION("complex::tostring(): buffer overflow"); + + // different zero/nonzero patterns + if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)!=0 ) + return std::string(x>0.0 ? "" : "-")+buf_x+(y>0.0 ? "+" : "-")+buf_y+"i"; + if( strcmp(buf_x,buf_zero)!=0 && strcmp(buf_y,buf_zero)==0 ) + return std::string(x>0.0 ? "" : "-")+buf_x; + if( strcmp(buf_x,buf_zero)==0 && strcmp(buf_y,buf_zero)!=0 ) + return std::string(y>0.0 ? "" : "-")+buf_y+"i"; + return std::string("0"); +} +#endif + +bool alglib::operator==(const alglib::complex& lhs, const alglib::complex& rhs) +{ + volatile double x1 = lhs.x; + volatile double x2 = rhs.x; + volatile double y1 = lhs.y; + volatile double y2 = rhs.y; + return x1==x2 && y1==y2; +} + +bool alglib::operator!=(const alglib::complex& lhs, const alglib::complex& rhs) +{ return !(lhs==rhs); } + +const alglib::complex alglib::operator+(const alglib::complex& lhs) +{ return lhs; } + +const alglib::complex alglib::operator-(const alglib::complex& lhs) +{ return alglib::complex(-lhs.x, -lhs.y); } + +const alglib::complex alglib::operator+(const alglib::complex& lhs, const alglib::complex& rhs) +{ alglib::complex r = lhs; r += rhs; return r; } + +const alglib::complex alglib::operator+(const alglib::complex& lhs, const double& rhs) +{ alglib::complex r = lhs; r += rhs; return r; } + +const alglib::complex alglib::operator+(const double& lhs, const alglib::complex& rhs) +{ alglib::complex r = rhs; r += lhs; return r; } + +const alglib::complex alglib::operator-(const alglib::complex& lhs, const alglib::complex& rhs) +{ alglib::complex r = lhs; r -= rhs; return r; } + +const alglib::complex alglib::operator-(const alglib::complex& lhs, const double& rhs) +{ alglib::complex r = lhs; r -= rhs; return r; } + +const alglib::complex alglib::operator-(const double& lhs, const alglib::complex& rhs) +{ alglib::complex r = lhs; r -= rhs; return r; } + +const alglib::complex alglib::operator*(const alglib::complex& lhs, const alglib::complex& rhs) +{ return alglib::complex(lhs.x*rhs.x - lhs.y*rhs.y, lhs.x*rhs.y + lhs.y*rhs.x); } + +const alglib::complex alglib::operator*(const alglib::complex& lhs, const double& rhs) +{ return alglib::complex(lhs.x*rhs, lhs.y*rhs); } + +const alglib::complex alglib::operator*(const double& lhs, const alglib::complex& rhs) +{ return alglib::complex(lhs*rhs.x, lhs*rhs.y); } + +const alglib::complex alglib::operator/(const alglib::complex& lhs, const alglib::complex& rhs) +{ + alglib::complex result; + double e; + double f; + if( fabs(rhs.y)yabs ? xabs : yabs; + v = xabs=1 ? r : 1; +} + +#if defined(_ALGLIB_HAS_THREADLOCAL) +alglib::ae_int_t alglib::getcallbackworkeridx() +{ + return alglib_impl::ae_get_callback_worker_idx(); +} +#endif + +alglib::ae_int_t alglib::_ae_cores_count() +{ +#ifdef AE_HPC + return alglib_impl::ae_cores_count(); +#else + return 1; +#endif +} + +void alglib::_ae_set_global_threading(alglib_impl::ae_uint64_t flg_value) +{ +#ifdef AE_HPC + alglib_impl::ae_set_global_threading(flg_value); +#endif +} + +alglib_impl::ae_uint64_t alglib::_ae_get_global_threading() +{ +#ifdef AE_HPC + return alglib_impl::ae_get_global_flags(); +#else + return _ALGLIB_FLG_THREADING_SERIAL; +#endif +} + + +/******************************************************************** +Level 1 BLAS functions +********************************************************************/ +double alglib::vdotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n) +{ + double result = 0.0; + ae_int_t i; + if( stride0!=1 || stride1!=1 ) + { + // + // slow general code + // + for(i=0; ix; + v0y = -v0->y; + v1x = v1->x; + v1y = -v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( !bconj0 && bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = v0->y; + v1x = v1->x; + v1y = -v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( bconj0 && !bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = -v0->y; + v1x = v1->x; + v1y = v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + if( !bconj0 && !bconj1 ) + { + double v0x, v0y, v1x, v1y; + for(i=0; ix; + v0y = v0->y; + v1x = v1->x; + v1y = v1->y; + rx += v0x*v1x-v0y*v1y; + ry += v0x*v1y+v0y*v1x; + } + } + return alglib::complex(rx,ry); +} + +alglib::complex alglib::vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N) +{ + return vdotproduct(v1, 1, "N", v2, 1, "N", N); +} + +void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n) +{ + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix = vsrc->x; + vdst->y = -vsrc->y; + } + } + else + { + for(i=0; ix = vsrc->x; + vdst->y = -vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = -vsrc->y; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + for(i=0; ix = -vsrc->x; + vdst->y = vsrc->y; + } + } + else + { + for(i=0; ix = -vsrc->x; + vdst->y = -vsrc->y; + } + } + } +} + +void alglib::vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) +{ + vmoveneg(vdst, 1, vsrc, 1, "N", N); +} + +void alglib::vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha) +{ + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix = alpha*vsrc->x; + vdst->y = -alpha*vsrc->y; + } + } + else + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = alpha*vsrc->y; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = -alpha*vsrc->y; + } + } + else + { + for(i=0; ix = alpha*vsrc->x; + vdst->y = alpha*vsrc->y; + } + } + } +} + +void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) +{ + vmove(vdst, 1, vsrc, 1, "N", N, alpha); +} + +void alglib::vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) +{ + bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + if( bconj ) + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x+ay*vsrc->y; + vdst->y = -ax*vsrc->y+ay*vsrc->x; + } + } + else + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x-ay*vsrc->y; + vdst->y = ax*vsrc->y+ay*vsrc->x; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x+ay*vsrc->y; + vdst->y = -ax*vsrc->y+ay*vsrc->x; + } + } + else + { + double ax = alpha.x, ay = alpha.y; + for(i=0; ix = ax*vsrc->x-ay*vsrc->y; + vdst->y = ax*vsrc->y+ay*vsrc->x; + } + } + } +} + +void alglib::vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) +{ + vmove(vdst, 1, vsrc, 1, "N", N, alpha); +} + +void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) +{ + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix += vsrc->x; + vdst->y -= vsrc->y; + } + } + else + { + for(i=0; ix += vsrc->x; + vdst->y += vsrc->y; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + for(i=0; ix += vsrc->x; + vdst->y -= vsrc->y; + } + } + else + { + for(i=0; ix += vsrc->x; + vdst->y += vsrc->y; + } + } + } +} + +void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) +{ + vadd(vdst, 1, vsrc, 1, "N", N); +} + +void alglib::vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) +{ + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix += alpha*vsrc->x; + vdst->y -= alpha*vsrc->y; + } + } + else + { + for(i=0; ix += alpha*vsrc->x; + vdst->y += alpha*vsrc->y; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + for(i=0; ix += alpha*vsrc->x; + vdst->y -= alpha*vsrc->y; + } + } + else + { + for(i=0; ix += alpha*vsrc->x; + vdst->y += alpha*vsrc->y; + } + } + } +} + +void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha) +{ + vadd(vdst, 1, vsrc, 1, "N", N, alpha); +} + +void alglib::vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) +{ + bool bconj = !((conj_src[0]=='N') || (conj_src[0]=='n')); + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + double ax = alpha.x, ay = alpha.y; + if( bconj ) + { + for(i=0; ix += ax*vsrc->x+ay*vsrc->y; + vdst->y -= ax*vsrc->y-ay*vsrc->x; + } + } + else + { + for(i=0; ix += ax*vsrc->x-ay*vsrc->y; + vdst->y += ax*vsrc->y+ay*vsrc->x; + } + } + } + else + { + // + // optimized case + // + double ax = alpha.x, ay = alpha.y; + if( bconj ) + { + for(i=0; ix += ax*vsrc->x+ay*vsrc->y; + vdst->y -= ax*vsrc->y-ay*vsrc->x; + } + } + else + { + for(i=0; ix += ax*vsrc->x-ay*vsrc->y; + vdst->y += ax*vsrc->y+ay*vsrc->x; + } + } + } +} + +void alglib::vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha) +{ + vadd(vdst, 1, vsrc, 1, "N", N, alpha); +} + +void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n) +{ + ae_int_t i; + if( stride_dst!=1 || stride_src!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix -= vsrc->x; + vdst->y += vsrc->y; + } + } + else + { + for(i=0; ix -= vsrc->x; + vdst->y -= vsrc->y; + } + } + } + else + { + // + // optimized case + // + if( bconj ) + { + for(i=0; ix -= vsrc->x; + vdst->y += vsrc->y; + } + } + else + { + for(i=0; ix -= vsrc->x; + vdst->y -= vsrc->y; + } + } + } +} + +void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N) +{ + vsub(vdst, 1, vsrc, 1, "N", N); +} + +void alglib::vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha) +{ + vadd(vdst, stride_dst, vsrc, stride_src, n, -alpha); +} + +void alglib::vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha) +{ + vadd(vdst, 1, vsrc, 1, N, -alpha); +} + +void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha) +{ + vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); +} + +void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, double alpha) +{ + vadd(vdst, 1, vsrc, 1, "N", n, -alpha); +} + +void alglib::vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha) +{ + vadd(vdst, stride_dst, vsrc, stride_src, conj_src, n, -alpha); +} + +void alglib::vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t n, alglib::complex alpha) +{ + vadd(vdst, 1, vsrc, 1, "N", n, -alpha); +} +void alglib::vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha) +{ + ae_int_t i; + if( stride_dst!=1 ) + { + // + // general unoptimized case + // + for(i=0; ix *= alpha; + vdst->y *= alpha; + } + } + else + { + // + // optimized case + // + for(i=0; ix *= alpha; + vdst->y *= alpha; + } + } +} + +void alglib::vmul(alglib::complex *vdst, ae_int_t N, double alpha) +{ + vmul(vdst, 1, N, alpha); +} + +void alglib::vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha) +{ + ae_int_t i; + if( stride_dst!=1 ) + { + // + // general unoptimized case + // + double ax = alpha.x, ay = alpha.y; + for(i=0; ix, dsty = vdst->y; + vdst->x = ax*dstx-ay*dsty; + vdst->y = ax*dsty+ay*dstx; + } + } + else + { + // + // optimized case + // + double ax = alpha.x, ay = alpha.y; + for(i=0; ix, dsty = vdst->y; + vdst->x = ax*dstx-ay*dsty; + vdst->y = ax*dsty+ay*dstx; + } + } +} + +void alglib::vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha) +{ + vmul(vdst, 1, N, alpha); +} + +alglib::ae_int_t alglib::vlen(ae_int_t n1, ae_int_t n2) +{ + return n2-n1+1; +} + + +/******************************************************************** +Matrices and vectors +********************************************************************/ +alglib::ae_vector_wrapper::ae_vector_wrapper(alglib_impl::ae_vector *e_ptr, alglib_impl::ae_datatype datatype) +{ + if( e_ptr==NULL || e_ptr->datatype!=datatype ) + { + const char *msg = "ALGLIB: ae_vector_wrapper datatype check failed"; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(msg); + return; +#endif + } + ptr = e_ptr; + is_frozen_proxy = true; +} + +alglib::ae_vector_wrapper::ae_vector_wrapper(alglib_impl::ae_datatype datatype) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ptr = &inner_vec; + is_frozen_proxy = false; + memset(ptr, 0, sizeof(*ptr)); + ae_vector_init(ptr, 0, datatype, &_state, ae_false); + ae_state_clear(&_state); +} + +alglib::ae_vector_wrapper::ae_vector_wrapper(const ae_vector_wrapper &rhs, alglib_impl::ae_datatype datatype) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(rhs.ptr!=NULL, "ALGLIB: ae_vector_wrapper source is not initialized", &_state); + alglib_impl::ae_assert(rhs.ptr->datatype==datatype, "ALGLIB: ae_vector_wrapper datatype check failed", &_state); + ptr = &inner_vec; + is_frozen_proxy = false; + memset(ptr, 0, sizeof(*ptr)); + ae_vector_init_copy(ptr, rhs.ptr, &_state, ae_false); + ae_state_clear(&_state); +} + +alglib::ae_vector_wrapper::~ae_vector_wrapper() +{ + if( ptr==&inner_vec ) + ae_vector_clear(ptr); +} + +void alglib::ae_vector_wrapper::setlength(ae_int_t iLen) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(ptr!=NULL, "ALGLIB: setlength() error, ptr==NULL (array was not correctly initialized)", &_state); + alglib_impl::ae_assert(!is_frozen_proxy, "ALGLIB: setlength() error, ptr is frozen proxy array", &_state); + alglib_impl::ae_vector_set_length(ptr, iLen, &_state); + alglib_impl::ae_state_clear(&_state); +} + +alglib::ae_int_t alglib::ae_vector_wrapper::length() const +{ + if( ptr==NULL ) + return 0; + return ptr->cnt; +} + +void alglib::ae_vector_wrapper::attach_to(alglib_impl::x_vector *new_ptr, alglib_impl::ae_state *_state) +{ + if( ptr==&inner_vec ) + ae_vector_clear(ptr); + ptr = &inner_vec; + memset(ptr, 0, sizeof(*ptr)); + ae_vector_init_attach_to_x(ptr, new_ptr, _state, ae_false); + is_frozen_proxy = true; +} + +const alglib::ae_vector_wrapper& alglib::ae_vector_wrapper::assign(const alglib::ae_vector_wrapper &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + if( this==&rhs ) + return *this; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ae_assert(ptr!=NULL, "ALGLIB: incorrect assignment (uninitialized destination)", &_state); + ae_assert(rhs.ptr!=NULL, "ALGLIB: incorrect assignment (uninitialized source)", &_state); + ae_assert(rhs.ptr->datatype==ptr->datatype, "ALGLIB: incorrect assignment to array (types do not match)", &_state); + if( is_frozen_proxy ) + ae_assert(rhs.ptr->cnt==ptr->cnt, "ALGLIB: incorrect assignment to proxy array (sizes do not match)", &_state); + if( rhs.ptr->cnt!=ptr->cnt ) + ae_vector_set_length(ptr, rhs.ptr->cnt, &_state); + memcpy(ptr->ptr.p_ptr, rhs.ptr->ptr.p_ptr, (size_t)(ptr->cnt*alglib_impl::ae_sizeof(ptr->datatype))); + alglib_impl::ae_state_clear(&_state); + return *this; +} + +const alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() const +{ + return ptr; +} + +alglib_impl::ae_vector* alglib::ae_vector_wrapper::c_ptr() +{ + return ptr; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::ae_vector_wrapper::ae_vector_wrapper(const char *s, alglib_impl::ae_datatype datatype) +{ + std::vector svec; + size_t i; + char *p = filter_spaces(s); + if( p==NULL ) + _ALGLIB_CPP_EXCEPTION("ALGLIB: allocation error"); + try + { + str_vector_create(p, true, &svec); + { + jmp_buf _break_jump; + alglib_impl::ae_state _state; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ptr = &inner_vec; + is_frozen_proxy = false; + memset(ptr, 0, sizeof(*ptr)); + ae_vector_init(ptr, (ae_int_t)(svec.size()), datatype, &_state, ae_false); + ae_state_clear(&_state); + } + for(i=(size_t)0; iptr.p_bool[i] = parse_bool_delim(svec[i],",]"); + if( datatype==alglib_impl::DT_INT ) + ptr->ptr.p_int[i] = parse_int_delim(svec[i],",]"); + if( datatype==alglib_impl::DT_REAL ) + ptr->ptr.p_double[i] = parse_real_delim(svec[i],",]"); + if( datatype==alglib_impl::DT_COMPLEX ) + { + alglib::complex t = parse_complex_delim(svec[i],",]"); + ptr->ptr.p_complex[i].x = t.x; + ptr->ptr.p_complex[i].y = t.y; + } + } + alglib_impl::ae_free(p); + } + catch(...) + { + alglib_impl::ae_free(p); + throw; + } +} +#endif + +alglib::boolean_1d_array::boolean_1d_array():ae_vector_wrapper(alglib_impl::DT_BOOL) +{ +} + +alglib::boolean_1d_array::boolean_1d_array(const alglib::boolean_1d_array &rhs):ae_vector_wrapper(rhs,alglib_impl::DT_BOOL) +{ +} + +alglib::boolean_1d_array::boolean_1d_array(alglib_impl::ae_vector *p):ae_vector_wrapper(p,alglib_impl::DT_BOOL) +{ +} + +const alglib::boolean_1d_array& alglib::boolean_1d_array::operator=(const alglib::boolean_1d_array &rhs) +{ + assign(rhs); + return *this; +} + +alglib::boolean_1d_array::~boolean_1d_array() +{ +} + +const ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) const +{ + return ptr->ptr.p_bool[i]; +} + +ae_bool& alglib::boolean_1d_array::operator()(ae_int_t i) +{ + return ptr->ptr.p_bool[i]; +} + +const ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.p_bool[i]; +} + +ae_bool& alglib::boolean_1d_array::operator[](ae_int_t i) +{ + return ptr->ptr.p_bool[i]; +} + +void alglib::boolean_1d_array::setcontent(ae_int_t iLen, const bool *pContent ) +{ + ae_int_t i; + + // setlength, with exception-free error handling fallback code + setlength(iLen); + if( ptr==NULL || ptr->cnt!=iLen ) + return; + + // copy + for(i=0; iptr.p_bool[i] = pContent[i]; +} + +ae_bool* alglib::boolean_1d_array::getcontent() +{ + return ptr->ptr.p_bool; +} + +const ae_bool* alglib::boolean_1d_array::getcontent() const +{ + return ptr->ptr.p_bool; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::boolean_1d_array::boolean_1d_array(const char *s):ae_vector_wrapper(s, alglib_impl::DT_BOOL) +{ +} + +std::string alglib::boolean_1d_array::tostring() const +{ + if( length()==0 ) + return "[]"; + return arraytostring(&(operator()(0)), length()); +} +#endif + +alglib::integer_1d_array::integer_1d_array():ae_vector_wrapper(alglib_impl::DT_INT) +{ +} + +alglib::integer_1d_array::integer_1d_array(alglib_impl::ae_vector *p):ae_vector_wrapper(p,alglib_impl::DT_INT) +{ +} + +alglib::integer_1d_array::integer_1d_array(const alglib::integer_1d_array &rhs):ae_vector_wrapper(rhs,alglib_impl::DT_INT) +{ +} + +const alglib::integer_1d_array& alglib::integer_1d_array::operator=(const alglib::integer_1d_array &rhs) +{ + assign(rhs); + return *this; +} + +alglib::integer_1d_array::~integer_1d_array() +{ +} + +const alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) const +{ + return ptr->ptr.p_int[i]; +} + +alglib::ae_int_t& alglib::integer_1d_array::operator()(ae_int_t i) +{ + return ptr->ptr.p_int[i]; +} + +const alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.p_int[i]; +} + +alglib::ae_int_t& alglib::integer_1d_array::operator[](ae_int_t i) +{ + return ptr->ptr.p_int[i]; +} + +void alglib::integer_1d_array::setcontent(ae_int_t iLen, const ae_int_t *pContent ) +{ + ae_int_t i; + + // setlength(), handle possible exception-free errors + setlength(iLen); + if( ptr==NULL || ptr->cnt!=iLen ) + return; + + // copy + for(i=0; iptr.p_int[i] = pContent[i]; +} + +alglib::ae_int_t* alglib::integer_1d_array::getcontent() +{ + return ptr->ptr.p_int; +} + +const alglib::ae_int_t* alglib::integer_1d_array::getcontent() const +{ + return ptr->ptr.p_int; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::integer_1d_array::integer_1d_array(const char *s):ae_vector_wrapper(s, alglib_impl::DT_INT) +{ +} + +std::string alglib::integer_1d_array::tostring() const +{ + if( length()==0 ) + return "[]"; + return arraytostring(&operator()(0), length()); +} +#endif + +alglib::real_1d_array::real_1d_array():ae_vector_wrapper(alglib_impl::DT_REAL) +{ +} + +alglib::real_1d_array::real_1d_array(alglib_impl::ae_vector *p):ae_vector_wrapper(p,alglib_impl::DT_REAL) +{ +} + +alglib::real_1d_array::real_1d_array(const alglib::real_1d_array &rhs):ae_vector_wrapper(rhs,alglib_impl::DT_REAL) +{ +} + +const alglib::real_1d_array& alglib::real_1d_array::operator=(const alglib::real_1d_array &rhs) +{ + assign(rhs); + return *this; +} + +alglib::real_1d_array::~real_1d_array() +{ +} + +const double& alglib::real_1d_array::operator()(ae_int_t i) const +{ + return ptr->ptr.p_double[i]; +} + +double& alglib::real_1d_array::operator()(ae_int_t i) +{ + return ptr->ptr.p_double[i]; +} + +const double& alglib::real_1d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.p_double[i]; +} + +double& alglib::real_1d_array::operator[](ae_int_t i) +{ + return ptr->ptr.p_double[i]; +} + +void alglib::real_1d_array::setcontent(ae_int_t iLen, const double *pContent ) +{ + ae_int_t i; + + // setlength(), handle possible exception-free errors + setlength(iLen); + if( ptr==NULL || ptr->cnt!=iLen ) + return; + + // copy + for(i=0; iptr.p_double[i] = pContent[i]; +} + +void alglib::real_1d_array::attach_to_ptr(ae_int_t iLen, double *pContent ) // TODO: convert to constructor!!!!!!! +{ + alglib_impl::x_vector x; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(!is_frozen_proxy, "ALGLIB: unable to attach proxy object to something else", &_state); + alglib_impl::ae_assert(iLen>0, "ALGLIB: non-positive length for attach_to_ptr()", &_state); + x.cnt = iLen; + x.datatype = alglib_impl::DT_REAL; + x.owner = alglib_impl::ACT_DROP_ON_REALLOC; + x.last_action = alglib_impl::ACT_UNCHANGED; + x.x_ptr.p_ptr = pContent; + attach_to(&x, &_state); + ae_state_clear(&_state); +} + +double* alglib::real_1d_array::getcontent() +{ + return ptr->ptr.p_double; +} + +const double* alglib::real_1d_array::getcontent() const +{ + return ptr->ptr.p_double; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::real_1d_array::real_1d_array(const char *s):ae_vector_wrapper(s, alglib_impl::DT_REAL) +{ +} + +std::string alglib::real_1d_array::tostring(int dps) const +{ + if( length()==0 ) + return "[]"; + return arraytostring(&operator()(0), length(), dps); +} +#endif + +alglib::complex_1d_array::complex_1d_array():ae_vector_wrapper(alglib_impl::DT_COMPLEX) +{ +} + +alglib::complex_1d_array::complex_1d_array(alglib_impl::ae_vector *p):ae_vector_wrapper(p,alglib_impl::DT_COMPLEX) +{ +} + +alglib::complex_1d_array::complex_1d_array(const alglib::complex_1d_array &rhs):ae_vector_wrapper(rhs,alglib_impl::DT_COMPLEX) +{ +} + +const alglib::complex_1d_array& alglib::complex_1d_array::operator=(const alglib::complex_1d_array &rhs) +{ + assign(rhs); + return *this; +} + +alglib::complex_1d_array::~complex_1d_array() +{ +} + +const alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) const +{ + return *((const alglib::complex*)(ptr->ptr.p_complex+i)); +} + +alglib::complex& alglib::complex_1d_array::operator()(ae_int_t i) +{ + return *((alglib::complex*)(ptr->ptr.p_complex+i)); +} + +const alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) const +{ + return *((const alglib::complex*)(ptr->ptr.p_complex+i)); +} + +alglib::complex& alglib::complex_1d_array::operator[](ae_int_t i) +{ + return *((alglib::complex*)(ptr->ptr.p_complex+i)); +} + +void alglib::complex_1d_array::setcontent(ae_int_t iLen, const alglib::complex *pContent ) +{ + ae_int_t i; + + // setlength(), handle possible exception-free errors + setlength(iLen); + if( ptr==NULL || ptr->cnt!=iLen ) + return; + + // copy + for(i=0; iptr.p_complex[i].x = pContent[i].x; + ptr->ptr.p_complex[i].y = pContent[i].y; + } +} + + alglib::complex* alglib::complex_1d_array::getcontent() +{ + return (alglib::complex*)ptr->ptr.p_complex; +} + +const alglib::complex* alglib::complex_1d_array::getcontent() const +{ + return (const alglib::complex*)ptr->ptr.p_complex; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::complex_1d_array::complex_1d_array(const char *s):ae_vector_wrapper(s, alglib_impl::DT_COMPLEX) +{ +} + +std::string alglib::complex_1d_array::tostring(int dps) const +{ + if( length()==0 ) + return "[]"; + return arraytostring(&operator()(0), length(), dps); +} +#endif + +alglib::ae_matrix_wrapper::ae_matrix_wrapper(alglib_impl::ae_matrix *e_ptr, alglib_impl::ae_datatype datatype) +{ + if( e_ptr->datatype!=datatype ) + { + const char *msg = "ALGLIB: ae_vector_wrapper datatype check failed"; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(msg); + return; +#endif + } + ptr = e_ptr; + is_frozen_proxy = true; +} + +alglib::ae_matrix_wrapper::ae_matrix_wrapper(alglib_impl::ae_datatype datatype) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ptr = &inner_mat; + is_frozen_proxy = false; + memset(ptr, 0, sizeof(*ptr)); + ae_matrix_init(ptr, 0, 0, datatype, &_state, ae_false); + ae_state_clear(&_state); + +} + +alglib::ae_matrix_wrapper::ae_matrix_wrapper(const ae_matrix_wrapper &rhs, alglib_impl::ae_datatype datatype) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + is_frozen_proxy = false; + ptr = NULL; + if( rhs.ptr!=NULL ) + { + alglib_impl::ae_assert(rhs.ptr->datatype==datatype, "ALGLIB: ae_matrix_wrapper datatype check failed", &_state); + ptr = &inner_mat; + memset(ptr, 0, sizeof(*ptr)); + ae_matrix_init_copy(ptr, rhs.ptr, &_state, ae_false); + } + ae_state_clear(&_state); +} + +alglib::ae_matrix_wrapper::~ae_matrix_wrapper() +{ + if( ptr==&inner_mat ) + ae_matrix_clear(ptr); +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::ae_matrix_wrapper::ae_matrix_wrapper(const char *s, alglib_impl::ae_datatype datatype) +{ + std::vector< std::vector > smat; + size_t i, j; + char *p = filter_spaces(s); + if( p==NULL ) + _ALGLIB_CPP_EXCEPTION("ALGLIB: allocation error"); + try + { + str_matrix_create(p, &smat); + { + jmp_buf _break_jump; + alglib_impl::ae_state _state; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ptr = &inner_mat; + is_frozen_proxy = false; + memset(ptr, 0, sizeof(*ptr)); + if( smat.size()!=0 ) + ae_matrix_init(ptr, (ae_int_t)(smat.size()), (ae_int_t)(smat[0].size()), datatype, &_state, ae_false); + else + ae_matrix_init(ptr, 0, 0, datatype, &_state, ae_false); + ae_state_clear(&_state); + } + for(i=0; iptr.pp_bool[i][j] = parse_bool_delim(smat[i][j],",]"); + if( datatype==alglib_impl::DT_INT ) + ptr->ptr.pp_int[i][j] = parse_int_delim(smat[i][j],",]"); + if( datatype==alglib_impl::DT_REAL ) + ptr->ptr.pp_double[i][j] = parse_real_delim(smat[i][j],",]"); + if( datatype==alglib_impl::DT_COMPLEX ) + { + alglib::complex t = parse_complex_delim(smat[i][j],",]"); + ptr->ptr.pp_complex[i][j].x = t.x; + ptr->ptr.pp_complex[i][j].y = t.y; + } + } + alglib_impl::ae_free(p); + } + catch(...) + { + alglib_impl::ae_free(p); + throw; + } +} +#endif + +void alglib::ae_matrix_wrapper::setlength(ae_int_t rows, ae_int_t cols) // TODO: automatic allocation of NULL ptr!!!!! +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(ptr!=NULL, "ALGLIB: setlength() error, p_mat==NULL (array was not correctly initialized)", &_state); + alglib_impl::ae_assert(!is_frozen_proxy, "ALGLIB: setlength() error, attempt to resize proxy array", &_state); + alglib_impl::ae_matrix_set_length(ptr, rows, cols, &_state); + alglib_impl::ae_state_clear(&_state); +} + +alglib::ae_int_t alglib::ae_matrix_wrapper::rows() const +{ + if( ptr==NULL ) + return 0; + return ptr->rows; +} + +alglib::ae_int_t alglib::ae_matrix_wrapper::cols() const +{ + if( ptr==NULL ) + return 0; + return ptr->cols; +} + +bool alglib::ae_matrix_wrapper::isempty() const +{ + return rows()==0 || cols()==0; +} + +alglib::ae_int_t alglib::ae_matrix_wrapper::getstride() const +{ + if( ptr==NULL ) + return 0; + return ptr->stride; +} + +void alglib::ae_matrix_wrapper::attach_to(alglib_impl::x_matrix *new_ptr, alglib_impl::ae_state *_state) +{ + if( ptr==&inner_mat ) + ae_matrix_clear(ptr); + ptr = &inner_mat; + memset(ptr, 0, sizeof(*ptr)); + ae_matrix_init_attach_to_x(ptr, new_ptr, _state, ae_false); + is_frozen_proxy = true; +} + +const alglib::ae_matrix_wrapper& alglib::ae_matrix_wrapper::assign(const alglib::ae_matrix_wrapper &rhs) +{ + ae_int_t i; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + if( this==&rhs ) + return *this; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + ae_assert(ptr!=NULL, "ALGLIB: incorrect assignment to matrix (uninitialized destination)", &_state); + ae_assert(rhs.ptr!=NULL, "ALGLIB: incorrect assignment to array (uninitialized source)", &_state); + ae_assert(rhs.ptr->datatype==ptr->datatype, "ALGLIB: incorrect assignment to array (types dont match)", &_state); + if( is_frozen_proxy ) + { + ae_assert(rhs.ptr->rows==ptr->rows, "ALGLIB: incorrect assignment to proxy array (sizes dont match)", &_state); + ae_assert(rhs.ptr->cols==ptr->cols, "ALGLIB: incorrect assignment to proxy array (sizes dont match)", &_state); + } + if( (rhs.ptr->rows!=ptr->rows) || (rhs.ptr->cols!=ptr->cols) ) + ae_matrix_set_length(ptr, rhs.ptr->rows, rhs.ptr->cols, &_state); + for(i=0; irows; i++) + memcpy(ptr->ptr.pp_void[i], rhs.ptr->ptr.pp_void[i], (size_t)(ptr->cols*alglib_impl::ae_sizeof(ptr->datatype))); + alglib_impl::ae_state_clear(&_state); + return *this; +} + +const alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() const +{ + return ptr; +} + +alglib_impl::ae_matrix* alglib::ae_matrix_wrapper::c_ptr() +{ + return ptr; +} + +alglib::boolean_2d_array::boolean_2d_array():ae_matrix_wrapper(alglib_impl::DT_BOOL) +{ +} + +alglib::boolean_2d_array::boolean_2d_array(const alglib::boolean_2d_array &rhs):ae_matrix_wrapper(rhs,alglib_impl::DT_BOOL) +{ +} + +alglib::boolean_2d_array::boolean_2d_array(alglib_impl::ae_matrix *p):ae_matrix_wrapper(p,alglib_impl::DT_BOOL) +{ +} + +alglib::boolean_2d_array::~boolean_2d_array() +{ +} + +const alglib::boolean_2d_array& alglib::boolean_2d_array::operator=(const alglib::boolean_2d_array &rhs) +{ + assign(rhs); + return *this; +} + +const ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) const +{ + return ptr->ptr.pp_bool[i][j]; +} + +ae_bool& alglib::boolean_2d_array::operator()(ae_int_t i, ae_int_t j) +{ + return ptr->ptr.pp_bool[i][j]; +} + +const ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.pp_bool[i]; +} + +ae_bool* alglib::boolean_2d_array::operator[](ae_int_t i) +{ + return ptr->ptr.pp_bool[i]; +} + +void alglib::boolean_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ) +{ + ae_int_t i, j; + + // setlength(), handle possible exception-free errors + setlength(irows, icols); + if( ptr==NULL || ptr->rows!=irows || ptr->cols!=icols ) + return; + + // copy + for(i=0; iptr.pp_bool[i][j] = pContent[i*icols+j]; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::boolean_2d_array::boolean_2d_array(const char *s):ae_matrix_wrapper(s, alglib_impl::DT_BOOL) +{ +} + +std::string alglib::boolean_2d_array::tostring() const +{ + std::string result; + ae_int_t i; + if( isempty() ) + return "[[]]"; + result = "["; + for(i=0; iptr.pp_int[i][j]; +} + +alglib::ae_int_t& alglib::integer_2d_array::operator()(ae_int_t i, ae_int_t j) +{ + return ptr->ptr.pp_int[i][j]; +} + +const alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.pp_int[i]; +} + +alglib::ae_int_t* alglib::integer_2d_array::operator[](ae_int_t i) +{ + return ptr->ptr.pp_int[i]; +} + +void alglib::integer_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ) +{ + ae_int_t i, j; + + // setlength(), handle possible exception-free errors + setlength(irows, icols); + if( ptr==NULL || ptr->rows!=irows || ptr->cols!=icols ) + return; + + // copy + for(i=0; iptr.pp_int[i][j] = pContent[i*icols+j]; +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::integer_2d_array::integer_2d_array(const char *s):ae_matrix_wrapper(s, alglib_impl::DT_INT) +{ +} + +std::string alglib::integer_2d_array::tostring() const +{ + std::string result; + ae_int_t i; + if( isempty() ) + return "[[]]"; + result = "["; + for(i=0; iptr.pp_double[i][j]; +} + +double& alglib::real_2d_array::operator()(ae_int_t i, ae_int_t j) +{ + return ptr->ptr.pp_double[i][j]; +} + +const double* alglib::real_2d_array::operator[](ae_int_t i) const +{ + return ptr->ptr.pp_double[i]; +} + +double* alglib::real_2d_array::operator[](ae_int_t i) +{ + return ptr->ptr.pp_double[i]; +} + +void alglib::real_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const double *pContent ) +{ + ae_int_t i, j; + + // setlength(), handle possible exception-free errors + setlength(irows, icols); + if( ptr==NULL || ptr->rows!=irows || ptr->cols!=icols ) + return; + + // copy + for(i=0; iptr.pp_double[i][j] = pContent[i*icols+j]; +} + +void alglib::real_2d_array::attach_to_ptr(ae_int_t irows, ae_int_t icols, double *pContent ) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + alglib_impl::x_matrix x; + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + ptr = NULL; + is_frozen_proxy = false; + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(!is_frozen_proxy, "ALGLIB: unable to attach proxy object to something else", &_state); + alglib_impl::ae_assert(irows>0&&icols>0, "ALGLIB: non-positive length for attach_to_ptr()", &_state); + x.rows = irows; + x.cols = icols; + x.stride = icols; + x.datatype = alglib_impl::DT_REAL; + x.owner = alglib_impl::ACT_DROP_ON_REALLOC; + x.last_action = alglib_impl::ACT_UNCHANGED; + x.x_ptr.p_ptr = pContent; + attach_to(&x, &_state); + ae_state_clear(&_state); +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::real_2d_array::real_2d_array(const char *s):ae_matrix_wrapper(s, alglib_impl::DT_REAL) +{ +} + +std::string alglib::real_2d_array::tostring(int dps) const +{ + std::string result; + ae_int_t i; + if( isempty() ) + return "[[]]"; + result = "["; + for(i=0; iptr.pp_complex[i]+j)); +} + +alglib::complex& alglib::complex_2d_array::operator()(ae_int_t i, ae_int_t j) +{ + return *((alglib::complex*)(ptr->ptr.pp_complex[i]+j)); +} + +const alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) const +{ + return (const alglib::complex*)(ptr->ptr.pp_complex[i]); +} + +alglib::complex* alglib::complex_2d_array::operator[](ae_int_t i) +{ + return (alglib::complex*)(ptr->ptr.pp_complex[i]); +} + +void alglib::complex_2d_array::setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ) +{ + ae_int_t i, j; + + // setlength(), handle possible exception-free errors + setlength(irows, icols); + if( ptr==NULL || ptr->rows!=irows || ptr->cols!=icols ) + return; + + // copy + for(i=0; iptr.pp_complex[i][j].x = pContent[i*icols+j].x; + ptr->ptr.pp_complex[i][j].y = pContent[i*icols+j].y; + } +} + +#if !defined(AE_NO_EXCEPTIONS) +alglib::complex_2d_array::complex_2d_array(const char *s):ae_matrix_wrapper(s, alglib_impl::DT_COMPLEX) +{ +} + +std::string alglib::complex_2d_array::tostring(int dps) const +{ + std::string result; + ae_int_t i; + if( isempty() ) + return "[[]]"; + result = "["; + for(i=0; ic2 ) + return +1; + } +} + +#if !defined(AE_NO_EXCEPTIONS) +// +// This function filters out all spaces from the string. +// It returns string allocated with ae_malloc(). +// On allocaction failure returns NULL. +// +char* alglib::filter_spaces(const char *s) +{ + size_t i, n; + char *r; + char *r0; + n = strlen(s); + r = (char*)alglib_impl::ae_malloc(n+1,NULL); + if( r==NULL ) + return r; + for(i=0,r0=r; i<=n; i++,s++) + if( !isspace((int)(*s)) ) + { + *r0 = *s; + r0++; + } + return r; +} + +void alglib::str_vector_create(const char *src, bool match_head_only, std::vector *p_vec) +{ + // + // parse beginning of the string. + // try to handle "[]" string + // + p_vec->clear(); + if( *src!='[' ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for vector"); + src++; + if( *src==']' ) + return; + p_vec->push_back(src); + for(;;) + { + if( *src==0 ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for vector"); + if( *src==']' ) + { + if( src[1]==0 || !match_head_only) + return; + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for vector"); + } + if( *src==',' ) + { + p_vec->push_back(src+1); + src++; + continue; + } + src++; + } +} + +void alglib::str_matrix_create(const char *src, std::vector< std::vector > *p_mat) +{ + p_mat->clear(); + + // + // Try to handle "[[]]" string + // + if( strcmp(src, "[[]]")==0 ) + return; + + // + // Parse non-empty string + // + if( *src!='[' ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for matrix"); + src++; + for(;;) + { + p_mat->push_back(std::vector()); + str_vector_create(src, false, &p_mat->back()); + if( p_mat->back().size()==(size_t)0 || p_mat->back().size()!=(*p_mat)[0].size() ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for matrix"); + src = strchr(src, ']'); + if( src==NULL ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for matrix"); + src++; + if( *src==',' ) + { + src++; + continue; + } + if( *src==']' ) + break; + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for matrix"); + } + src++; + if( *src!=0 ) + _ALGLIB_CPP_EXCEPTION("Incorrect initializer for matrix"); +} + +ae_bool alglib::parse_bool_delim(const char *s, const char *delim) +{ + const char *p; + char buf[8]; + + // try to parse false + p = "false"; + memset(buf, 0, sizeof(buf)); + strncpy(buf, s, strlen(p)); + if( my_stricmp(buf, p)==0 ) + { + if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return ae_false; + } + + // try to parse true + p = "true"; + memset(buf, 0, sizeof(buf)); + strncpy(buf, s, strlen(p)); + if( my_stricmp(buf, p)==0 ) + { + if( s[strlen(p)]==0 || strchr(delim,s[strlen(p)])==NULL ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return ae_true; + } + + // error + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); +} + +alglib::ae_int_t alglib::parse_int_delim(const char *s, const char *delim) +{ + const char *p; + long long_val; + volatile ae_int_t ae_val; + + p = s; + + // + // check string structure: + // * leading sign + // * at least one digit + // * delimiter + // + if( *s=='-' || *s=='+' ) + s++; + if( *s==0 || strchr("1234567890",*s)==NULL) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + while( *s!=0 && strchr("1234567890",*s)!=NULL ) + s++; + if( *s==0 || strchr(delim,*s)==NULL ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + + // convert and ensure that value fits into ae_int_t + s = p; + long_val = atol(s); + ae_val = long_val; + if( ae_val!=long_val ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return ae_val; +} + +bool alglib::_parse_real_delim(const char *s, const char *delim, double *result, const char **new_s) +{ + const char *p; + char *t; + bool has_digits; + char buf[64]; + int isign; + lconv *loc; + + p = s; + + // + // check string structure and decide what to do + // + isign = 1; + if( *s=='-' || *s=='+' ) + { + isign = *s=='-' ? -1 : +1; + s++; + } + memset(buf, 0, sizeof(buf)); + strncpy(buf, s, (size_t)3); + if( my_stricmp(buf,"nan")!=0 && my_stricmp(buf,"inf")!=0 ) + { + // + // [sign] [ddd] [.] [ddd] [e|E[sign]ddd] + // + has_digits = false; + if( *s!=0 && strchr("1234567890",*s)!=NULL ) + { + has_digits = true; + while( *s!=0 && strchr("1234567890",*s)!=NULL ) + s++; + } + if( *s=='.' ) + s++; + if( *s!=0 && strchr("1234567890",*s)!=NULL ) + { + has_digits = true; + while( *s!=0 && strchr("1234567890",*s)!=NULL ) + s++; + } + if (!has_digits ) + return false; + if( *s=='e' || *s=='E' ) + { + s++; + if( *s=='-' || *s=='+' ) + s++; + if( *s==0 || strchr("1234567890",*s)==NULL ) + return false; + while( *s!=0 && strchr("1234567890",*s)!=NULL ) + s++; + } + if( *s==0 || strchr(delim,*s)==NULL ) + return false; + *new_s = s; + + // + // finite value conversion + // + if( (size_t)(*new_s-p)>=sizeof(buf) ) + return false; + strncpy(buf, p, (size_t)(*new_s-p)); + buf[*new_s-p] = 0; + loc = localeconv(); + t = strchr(buf,'.'); + if( t!=NULL ) + *t = *loc->decimal_point; + *result = atof(buf); + return true; + } + else + { + // + // check delimiter and update *new_s + // + s += 3; + if( *s==0 || strchr(delim,*s)==NULL ) + return false; + *new_s = s; + + // + // NAN, INF conversion + // + if( my_stricmp(buf,"nan")==0 ) + *result = fp_nan; + if( my_stricmp(buf,"inf")==0 ) + *result = isign>0 ? fp_posinf : fp_neginf; + return true; + } +} + +double alglib::parse_real_delim(const char *s, const char *delim) +{ + double result; + const char *new_s; + if( !_parse_real_delim(s, delim, &result, &new_s) ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return result; +} + +alglib::complex alglib::parse_complex_delim(const char *s, const char *delim) +{ + double d_result; + const char *new_s; + alglib::complex c_result; + + // parse as real value + if( _parse_real_delim(s, delim, &d_result, &new_s) ) + return d_result; + + // parse as "a+bi" or "a-bi" + if( _parse_real_delim(s, "+-", &c_result.x, &new_s) ) + { + s = new_s; + if( !_parse_real_delim(s, "i", &c_result.y, &new_s) ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + s = new_s+1; + if( *s==0 || strchr(delim,*s)==NULL ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return c_result; + } + + // parse as complex value "bi+a" or "bi-a" + if( _parse_real_delim(s, "i", &c_result.y, &new_s) ) + { + s = new_s+1; + if( *s==0 ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + if( strchr(delim,*s)!=NULL ) + { + c_result.x = 0.0; + return c_result; + } + if( strchr("+-",*s)!=NULL ) + { + if( !_parse_real_delim(s, delim, &c_result.x, &new_s) ) + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + return c_result; + } + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); + } + + // error + _ALGLIB_CPP_EXCEPTION("Cannot parse value"); +} + +std::string alglib::arraytostring(const bool *ptr, ae_int_t n) +{ + std::string result; + ae_int_t i; + result = "["; + for(i=0; i=(int)sizeof(buf) ) + _ALGLIB_CPP_EXCEPTION("arraytostring(): buffer overflow"); + result += buf; + } + result += "]"; + return result; +} + +std::string alglib::arraytostring(const double *ptr, ae_int_t n, int _dps) +{ + std::string result; + ae_int_t i; + char buf[64]; + char mask1[64]; + char mask2[80]; + int dps = _dps>=0 ? _dps : -_dps; + dps = dps<=50 ? dps : 50; + result = "["; + if( sprintf(mask1, "%%.%d%s", dps, _dps>=0 ? "f" : "e")>=(int)sizeof(mask1) ) + _ALGLIB_CPP_EXCEPTION("arraytostring(): buffer overflow"); + if( sprintf(mask2, ",%s", mask1)>=(int)sizeof(mask2) ) + _ALGLIB_CPP_EXCEPTION("arraytostring(): buffer overflow"); + for(i=0; i=(int)sizeof(buf) ) + _ALGLIB_CPP_EXCEPTION("arraytostring(): buffer overflow"); + } + else if( fp_isnan(ptr[i]) ) + strcpy(buf, i==0 ? "NAN" : ",NAN"); + else if( fp_isposinf(ptr[i]) ) + strcpy(buf, i==0 ? "+INF" : ",+INF"); + else if( fp_isneginf(ptr[i]) ) + strcpy(buf, i==0 ? "-INF" : ",-INF"); + result += buf; + } + result += "]"; + return result; +} + +std::string alglib::arraytostring(const alglib::complex *ptr, ae_int_t n, int dps) +{ + std::string result; + ae_int_t i; + result = "["; + for(i=0; i0.0 ) return 1; + if( x<0.0 ) return -1; + return 0; +} + +double alglib::randomreal() +{ + double i1 = (double)alglib_impl::ae_rand(); + double i2 = (double)alglib_impl::ae_rand(); + double mx = (double)alglib_impl::ae_rand_max()+1.0; + volatile double tmp0 = i2/mx; + volatile double tmp1 = i1+tmp0; + return tmp1/mx; +} + +alglib::ae_int_t alglib::randominteger(alglib::ae_int_t maxv) +{ + return alglib_impl::ae_rand()%maxv; +} + +int alglib::round(double x) +{ return int(floor(x+0.5)); } + +int alglib::trunc(double x) +{ return int(x>0.0 ? floor(x) : ceil(x)); } + +int alglib::ifloor(double x) +{ return int(floor(x)); } + +int alglib::iceil(double x) +{ return int(ceil(x)); } + +double alglib::pi() +{ return 3.14159265358979323846; } + +double alglib::sqr(double x) +{ return x*x; } + +int alglib::maxint(int m1, int m2) +{ + return m1>m2 ? m1 : m2; +} + +int alglib::minint(int m1, int m2) +{ + return m1>m2 ? m2 : m1; +} + +double alglib::maxreal(double m1, double m2) +{ + return m1>m2 ? m1 : m2; +} + +double alglib::minreal(double m1, double m2) +{ + return m1>m2 ? m2 : m1; +} + +bool alglib::fp_eq(double v1, double v2) +{ + // IEEE-strict floating point comparison + volatile double x = v1; + volatile double y = v2; + return x==y; +} + +bool alglib::fp_neq(double v1, double v2) +{ + // IEEE-strict floating point comparison + return !fp_eq(v1,v2); +} + +bool alglib::fp_less(double v1, double v2) +{ + // IEEE-strict floating point comparison + volatile double x = v1; + volatile double y = v2; + return xy; +} + +bool alglib::fp_greater_eq(double v1, double v2) +{ + // IEEE-strict floating point comparison + volatile double x = v1; + volatile double y = v2; + return x>=y; +} + +bool alglib::fp_isnan(double x) +{ + return alglib_impl::ae_isnan_stateless(x,endianness); +} + +bool alglib::fp_isposinf(double x) +{ + return alglib_impl::ae_isposinf_stateless(x,endianness); +} + +bool alglib::fp_isneginf(double x) +{ + return alglib_impl::ae_isneginf_stateless(x,endianness); +} + +bool alglib::fp_isinf(double x) +{ + return alglib_impl::ae_isinf_stateless(x,endianness); +} + +bool alglib::fp_isfinite(double x) +{ + return alglib_impl::ae_isfinite_stateless(x,endianness); +} + +/******************************************************************** +CSV functions +********************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void alglib::read_csv(const char *filename, char separator, int flags, alglib::real_2d_array &out) +{ + int flag; + + // + // Parameters + // + bool skip_first_row = (flags&CSV_SKIP_HEADERS)!=0; + + // + // Prepare empty output array + // + out.setlength(0,0); + + // + // Open file, determine size, read contents + // + FILE *f_in = fopen(filename, "rb"); + if( f_in==NULL ) + _ALGLIB_CPP_EXCEPTION("read_csv: unable to open input file"); + flag = fseek(f_in, 0, SEEK_END); + AE_CRITICAL_ASSERT(flag==0); + long int _filesize = ftell(f_in); + AE_CRITICAL_ASSERT(_filesize>=0); + if( _filesize==0 ) + { + // empty file, return empty array, success + fclose(f_in); + return; + } + size_t filesize = (size_t)_filesize; + std::vector v_buf; + v_buf.resize(filesize+2, 0); + char *p_buf = &v_buf[0]; + flag = fseek(f_in, 0, SEEK_SET); + AE_CRITICAL_ASSERT(flag==0); + size_t bytes_read = fread ((void*)p_buf, 1, filesize, f_in); + AE_CRITICAL_ASSERT(bytes_read==filesize); + fclose(f_in); + + // + // Normalize file contents: + // * replace 0x0 by spaces + // * remove trailing spaces and newlines + // * append trailing '\n' and '\0' characters + // Return if file contains only spaces/newlines. + // + for(size_t i=0; i0; ) + { + char c = p_buf[filesize-1]; + if( c==' ' || c=='\t' || c=='\n' || c=='\r' ) + { + filesize--; + continue; + } + break; + } + if( filesize==0 ) + return; + p_buf[filesize+0] = '\n'; + p_buf[filesize+1] = '\0'; + filesize+=2; + + // + // Scan dataset. + // + size_t rows_count = 0, cols_count = 0, max_length = 0; + std::vector offsets, lengths; + for(size_t row_start=0; p_buf[row_start]!=0x0; ) + { + // determine row length + size_t row_length; + for(row_length=0; p_buf[row_start+row_length]!='\n'; row_length++); + + // determine cols count, perform integrity check + size_t cur_cols_cnt=1; + for(size_t idx=0; idx0 && cols_count!=cur_cols_cnt ) + _ALGLIB_CPP_EXCEPTION("read_csv: non-rectangular contents, rows have different sizes"); + cols_count = cur_cols_cnt; + + // store offsets and lengths of the fields + size_t cur_offs = 0; + for(size_t idx=0; idxmax_length ? idx-cur_offs : max_length; + cur_offs = idx+1; + } + + // advance row start + rows_count++; + row_start = row_start+row_length+1; + } + AE_CRITICAL_ASSERT(rows_count>=1); + AE_CRITICAL_ASSERT(cols_count>=1); + AE_CRITICAL_ASSERT(cols_count*rows_count==offsets.size()); + AE_CRITICAL_ASSERT(cols_count*rows_count==lengths.size()); + if( rows_count==1 && skip_first_row ) // empty output, return + return; + + // + // Convert + // + size_t row0 = skip_first_row ? (size_t)1 : (size_t)0; + size_t row1 = rows_count; + lconv *loc = localeconv(); + out.setlength((ae_int_t)(row1-row0), (ae_int_t)cols_count); + for(size_t ridx=row0; ridxdecimal_point; + out[ridx-row0][cidx] = atof(p_field); + } +} +#endif + + +/******************************************************************** +Trace functions +********************************************************************/ +void alglib::trace_file(std::string tags, std::string filename) +{ + alglib_impl::ae_trace_file(tags.c_str(), filename.c_str()); +} + +void alglib::trace_disable() +{ + alglib_impl::ae_trace_disable(); +} + +/******************************************************************** +V2 reverse communication protocol +********************************************************************/ +alglib_impl::rcommv2_buffers::rcommv2_buffers(const alglib_impl::rcommv2_request &rq) +{ + tmpX.setlength(rq.vars); + if( rq.dim>0 ) + tmpC.setlength(rq.dim); + tmpF.setlength(rq.funcs); + tmpG.setlength(rq.vars); + tmpJ.setlength(rq.funcs, rq.vars); + alglib::sparsecreatecrsempty(rq.vars, tmpS); +} + +alglib_impl::rcommv2_callbacks::rcommv2_callbacks(): + func(NULL),grad(NULL),fvec(NULL),jac(NULL),sjac(NULL), + func_p(NULL),grad_p(NULL),fvec_p(NULL),jac_p(NULL),sjac_p(NULL) +{ +} + +void alglib_impl::process_v2request_1(rcommv2_request &request, ae_int_t query_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers, rcommv2_request::query_order order, alglib_impl::sparsematrix *dst_jacobian) +{ + // + // Query and reply + // + const double *query_data = request.query_data + query_idx*(request.vars+request.dim); + double *reply_fi = request.reply_fi + query_idx*request.funcs; + _ALGLIB_ASSERT_THROW_OR_BREAK(order==rcommv2_request::query_sequential || order==rcommv2_request::query_justone, "ALGLIB: integrity check 1741 failed"); + _ALGLIB_ASSERT_THROW_OR_BREAK(dst_jacobian->matrixtype==1 || dst_jacobian->matrixtype==-10083, "ALGLIB: integrity check 1826 failed"); + _ALGLIB_ASSERT_THROW_OR_BREAK(dst_jacobian->n==request.vars, "ALGLIB: integrity check 1827 failed"); + if( order==rcommv2_request::query_sequential ) + _ALGLIB_ASSERT_THROW_OR_BREAK(dst_jacobian->m==query_idx*request.funcs, "ALGLIB: integrity check 1828 failed"); + if( order==rcommv2_request::query_justone ) + _ALGLIB_ASSERT_THROW_OR_BREAK(dst_jacobian->m==0, "ALGLIB: integrity check 2341 failed"); + + // + // Copy inputs to buffers, prepare tmpS and call the callback + // + alglib_impl::ae_state _state; + alglib_impl::ae_state_init(&_state); + memmove(buffers.tmpX.c_ptr()->ptr.p_double, query_data, request.vars*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+request.vars, request.dim*sizeof(double)); + alglib_impl::sparsecreatecrsemptybuf(request.vars, buffers.tmpS.c_ptr(), &_state); + if( callbacks.sjac!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.sjac(buffers.tmpX, buffers.tmpF, buffers.tmpS, request.ptr); + _ALGLIB_ASSERT_THROW_OR_BREAK(buffers.tmpS.c_ptr()->matrixtype==1, "ALGLIB: sparse Jacobian returned by the user callback is not a CRS matrix"); + _ALGLIB_ASSERT_THROW_OR_BREAK(buffers.tmpS.c_ptr()->m==request.funcs && buffers.tmpS.c_ptr()->n==request.vars, "ALGLIB: sparse Jacobian returned by the user callback has incorrect size"); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + alglib_impl::sparseappendmatrix(dst_jacobian, buffers.tmpS.c_ptr(), &_state); + ae_state_clear(&_state); + return; + } + if( callbacks.sjac_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.sjac_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, buffers.tmpS, request.ptr); + _ALGLIB_ASSERT_THROW_OR_BREAK(buffers.tmpS.c_ptr()->m==request.funcs && buffers.tmpS.c_ptr()->n==request.vars, "ALGLIB: sparse Jacobian returned by user callback has incorrect size"); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + alglib_impl::sparseappendmatrix(dst_jacobian, buffers.tmpS.c_ptr(), &_state); + ae_state_clear(&_state); + return; + } + ae_state_clear(&_state); + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); +} + +void alglib_impl::process_v2request_2(rcommv2_request &request, ae_int_t query_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers) +{ + // + // Query and reply + // + const double *query_data = request.query_data + query_idx*(request.vars+request.dim); + double *reply_fi = request.reply_fi + query_idx*request.funcs; + double *reply_dj = request.reply_dj + query_idx*request.funcs*request.vars; + + // + // Copy inputs to buffers + // + memmove(buffers.tmpX.c_ptr()->ptr.p_double, query_data, request.vars*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+request.vars, request.dim*sizeof(double)); + + // + // Callback + // + if( callbacks.grad!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.grad(buffers.tmpX, *reply_fi, buffers.tmpG, request.ptr); + memmove(reply_dj, buffers.tmpG.c_ptr()->ptr.p_double, request.vars*sizeof(double)); + return; + } + if( callbacks.grad_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.grad_p(buffers.tmpX, buffers.tmpC, *reply_fi, buffers.tmpG, request.ptr); + memmove(reply_dj, buffers.tmpG.c_ptr()->ptr.p_double, request.vars*sizeof(double)); + return; + } + if( callbacks.jac!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.jac(buffers.tmpX, buffers.tmpF, buffers.tmpJ, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + for(ae_int_t ridx=0; ridxptr.pp_double[ridx], request.vars*sizeof(double)); + return; + } + if( callbacks.jac_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.jac_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, buffers.tmpJ, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + for(ae_int_t ridx=0; ridxptr.pp_double[ridx], request.vars*sizeof(double)); + return; + } + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); +} + +void alglib_impl::process_v2request_3phase0(rcommv2_request &request, ae_int_t job_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers) +{ + // + // Phase 0: compute target at the origin and compute parts of the numerical differentiation formula that do NOT depend + // on the value at origin. + // + // This job can be completely parallelized without synchronization. + // + if( job_idxptr.p_double, query_data, n*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+n, request.dim*sizeof(double)); + + // + // compute gradient using numerical differentiation formula provided by the optimizer + // + double xprev = buffers.tmpX[var_idx]; + for(alglib_impl::ae_int_t t=0; t0 && m==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, buffers.tmpF[0], request.ptr); + } + else if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + } + else if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + } + else + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); + buffers.tmpX[var_idx] = xprev; + for(alglib_impl::ae_int_t t=0; tptr.p_double, query_data, request.vars*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+request.vars, request.dim*sizeof(double)); + + // + // Callback + // + if( callbacks.func!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func(buffers.tmpX, *reply_fi, request.ptr); + return; + } + if( callbacks.func_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, *reply_fi, request.ptr); + return; + } + if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); + } +} + +void alglib_impl::process_v2request_3phase1(rcommv2_request &request) +{ + // + // Phase 1: compute parts of the numerical differentiation formula that DO depend on the value at origin. + // + // This phase does not need parallelism because all what we need is to add request.size*request.vars precomputed values. + // + for(ae_int_t query_idx=0; query_idxptr.p_double, query_data, n*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+n, request.dim*sizeof(double)); + + // + // compute gradient using numerical differentiation formula provided by the optimizer + // + double xprev = buffers.tmpX[var_idx]; + for(alglib_impl::ae_int_t t=0; t0 && m==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, buffers.tmpF[0], request.ptr); + } + else if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + } + else if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + } + else + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); + buffers.tmpX[var_idx] = xprev; + for(alglib_impl::ae_int_t t=0; t1 references value at the origin"); + wait_for_value_at_origin = true; + } + + // + // The second term in a triple + // + if( formula_data[idx*3+1]!=query_data[var_idx] ) + { + buffers.tmpX[var_idx] = formula_data[idx*3+1]; + if( callbacks.func!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0 && m==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func(buffers.tmpX, buffers.tmpF[0], request.ptr); + } + else if( callbacks.func_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0 && m==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, buffers.tmpF[0], request.ptr); + } + else if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + } + else if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + } + else + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); + buffers.tmpX[var_idx] = xprev; + for(alglib_impl::ae_int_t t=0; t1 references value at the origin"); + wait_for_value_at_origin = true; + } + + // + // Multiplier + // + if( wait_for_value_at_origin ) + break; + for(alglib_impl::ae_int_t t=0; tptr.p_double, query_data, request.vars*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+request.vars, request.dim*sizeof(double)); + + // + // Callback + // + if( callbacks.func!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func(buffers.tmpX, *reply_fi, request.ptr); + return; + } + if( callbacks.func_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, *reply_fi, request.ptr); + return; + } + if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); + } +} + +void alglib_impl::process_v2request_5phase1(rcommv2_request &request) +{ + // + // Phase 1: compute parts of the numerical differentiation formula that DO depend on the value at origin. + // + // This phase does not need parallelism because all what we need is to add request.size*request.vars precomputed values. + // + for(ae_int_t query_idx=0; query_idx1 references value at the origin"); + uses_value_at_origin = true; + for(alglib_impl::ae_int_t t=0; t1 references value at the origin"); + uses_value_at_origin = true; + for(alglib_impl::ae_int_t t=0; t1 references value at the origin"); + for(alglib_impl::ae_int_t t=0; tptr.p_double, query_data, request.vars*sizeof(double)); + if( request.dim>0 ) + memmove(buffers.tmpC.c_ptr()->ptr.p_double, query_data+request.vars, request.dim*sizeof(double)); + + // + // Callback + // + if( callbacks.func!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func(buffers.tmpX, *reply_fi, request.ptr); + return; + } + if( callbacks.func_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0 && request.funcs==1, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.func_p(buffers.tmpX, buffers.tmpC, *reply_fi, request.ptr); + return; + } + if( callbacks.fvec!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim==0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec(buffers.tmpX, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + if( callbacks.fvec_p!=NULL ) + { + _ALGLIB_ASSERT_THROW_OR_BREAK(request.dim>0, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; incompatible callback for optimizer request"); + callbacks.fvec_p(buffers.tmpX, buffers.tmpC, buffers.tmpF, request.ptr); + memmove(reply_fi, buffers.tmpF.c_ptr()->ptr.p_double, request.funcs*sizeof(double)); + return; + } + _ALGLIB_ASSERT_THROW_OR_BREAK(ae_false, std::string("ALGLIB: integrity check in '")+request.subpackage+"' subpackage failed; no callback for optimizer request"); +} + + + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTIONS CONTAINS OPTIMIZED LINEAR ALGEBRA CODE +// IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES +// +///////////////////////////////////////////////////////////////////////// +#if defined(_ALGLIB_HAS_SSE2_INTRINSICS) +#include "kernels_sse2.h" +#endif +#if defined(_ALGLIB_HAS_AVX2_INTRINSICS) +#include "kernels_avx2.h" +#endif +#if defined(_ALGLIB_HAS_FMA_INTRINSICS) +#include "kernels_fma.h" +#endif +namespace alglib_impl +{ +#define alglib_simd_alignment 16 + +#define alglib_r_block 32 +#define alglib_half_r_block 16 +#define alglib_twice_r_block 64 + +#define alglib_c_block 16 +#define alglib_half_c_block 8 +#define alglib_twice_c_block 32 + + + + +/******************************************************************** +This subroutine calculates fast 32x32 real matrix-vector product: + + y := beta*y + alpha*A*x + +using either generic C code or native optimizations (if available) + +IMPORTANT: +* A must be stored in row-major order, + stride is alglib_r_block, + aligned on alglib_simd_alignment boundary +* X must be aligned on alglib_simd_alignment boundary +* Y may be non-aligned +********************************************************************/ +void _ialglib_mv_32(const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) +{ + ae_int_t i, k; + const double *pa0, *pa1, *pb; + + pa0 = a; + pa1 = a+alglib_r_block; + pb = x; + for(i=0; i<16; i++) + { + double v0 = 0.0, v1 = 0.0; + for(k=0; k<4; k++) + { + v0 += pa0[0]*pb[0]; + v1 += pa1[0]*pb[0]; + v0 += pa0[1]*pb[1]; + v1 += pa1[1]*pb[1]; + v0 += pa0[2]*pb[2]; + v1 += pa1[2]*pb[2]; + v0 += pa0[3]*pb[3]; + v1 += pa1[3]*pb[3]; + v0 += pa0[4]*pb[4]; + v1 += pa1[4]*pb[4]; + v0 += pa0[5]*pb[5]; + v1 += pa1[5]*pb[5]; + v0 += pa0[6]*pb[6]; + v1 += pa1[6]*pb[6]; + v0 += pa0[7]*pb[7]; + v1 += pa1[7]*pb[7]; + pa0 += 8; + pa1 += 8; + pb += 8; + } + y[0] = beta*y[0]+alpha*v0; + y[stride] = beta*y[stride]+alpha*v1; + + /* + * now we've processed rows I and I+1, + * pa0 and pa1 are pointing to rows I+1 and I+2. + * move to I+2 and I+3. + */ + pa0 += alglib_r_block; + pa1 += alglib_r_block; + pb = x; + y+=2*stride; + } +} + + +/************************************************************************* +This function calculates MxN real matrix-vector product: + + y := beta*y + alpha*A*x + +using generic C code. It calls _ialglib_mv_32 if both M=32 and N=32. + +If beta is zero, we do not use previous values of y (they are overwritten +by alpha*A*x without ever being read). If alpha is zero, no matrix-vector +product is calculated (only beta is updated); however, this update is not +efficient and this function should NOT be used for multiplication of +vector and scalar. + +IMPORTANT: +* 0<=M<=alglib_r_block, 0<=N<=alglib_r_block +* A must be stored in row-major order with stride equal to alglib_r_block +*************************************************************************/ +void _ialglib_rmv(ae_int_t m, ae_int_t n, const double *a, const double *x, double *y, ae_int_t stride, double alpha, double beta) +{ + /* + * Handle special cases: + * - alpha is zero or n is zero + * - m is zero + */ + if( m==0 ) + return; + if( alpha==0.0 || n==0 ) + { + ae_int_t i; + if( beta==0.0 ) + { + for(i=0; ix-beta.y*cy->y)+(alpha.x*v0-alpha.y*v1); + double ty = (beta.x*cy->y+beta.y*cy->x)+(alpha.x*v1+alpha.y*v0); + cy->x = tx; + cy->y = ty; + cy+=stride; + } + else + { + double tx = (beta.x*dy[0]-beta.y*dy[1])+(alpha.x*v0-alpha.y*v1); + double ty = (beta.x*dy[1]+beta.y*dy[0])+(alpha.x*v1+alpha.y*v0); + dy[0] = tx; + dy[1] = ty; + dy += 2*stride; + } + parow += 2*alglib_c_block; + } +} + + +/************************************************************************* +This subroutine calculates fast MxN complex matrix-vector product: + + y := beta*y + alpha*A*x + +using generic C code, where A, x, y, alpha and beta are complex. + +If beta is zero, we do not use previous values of y (they are overwritten +by alpha*A*x without ever being read). However, when alpha is zero, we +still calculate A*x and multiply it by alpha (this distinction can be +important when A or x contain infinities/NANs). + +IMPORTANT: +* 0<=M<=alglib_c_block, 0<=N<=alglib_c_block +* A must be stored in row-major order, as sequence of double precision + pairs. Stride is alglib_c_block (it is measured in pairs of doubles, not + in doubles). +* Y may be referenced by cy (pointer to ae_complex) or + dy (pointer to array of double precision pair) depending on what type of + output you wish. Pass pointer to Y as one of these parameters, + AND SET OTHER PARAMETER TO NULL. +* both A and x must be aligned; y may be non-aligned. + +This function supports SSE2; it can be used when: +1. AE_HAS_SSE2_INTRINSICS was defined (checked at compile-time) +2. ae_cpuid() result contains CPU_SSE2 (checked at run-time) + +If (1) is failed, this function will be undefined. If (2) is failed, call +to this function will probably crash your system. + +If you want to know whether it is safe to call it, you should check +results of ae_cpuid(). If CPU_SSE2 bit is set, this function is callable +and will do its work. +*************************************************************************/ +#if defined(AE_HAS_SSE2_INTRINSICS) +void _ialglib_cmv_sse2(ae_int_t m, ae_int_t n, const double *a, const double *x, ae_complex *cy, double *dy, ae_int_t stride, ae_complex alpha, ae_complex beta) +{ + ae_int_t i, j, m2; + const double *pa0, *pa1, *parow, *pb; + __m128d vbeta, vbetax, vbetay; + __m128d valpha, valphax, valphay; + + m2 = m/2; + parow = a; + if( cy!=NULL ) + { + dy = (double*)cy; + cy = NULL; + } + vbeta = _mm_loadh_pd(_mm_load_sd(&beta.x),&beta.y); + vbetax = _mm_unpacklo_pd(vbeta,vbeta); + vbetay = _mm_unpackhi_pd(vbeta,vbeta); + valpha = _mm_loadh_pd(_mm_load_sd(&alpha.x),&alpha.y); + valphax = _mm_unpacklo_pd(valpha,valpha); + valphay = _mm_unpackhi_pd(valpha,valpha); + for(i=0; ix = 0.0; + p->y = 0.0; + } + } + else + { + for(i=0; ix = 0.0; + p->y = 0.0; + } + } +} + + +/******************************************************************** +This subroutine copies unaligned real vector +********************************************************************/ +void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb) +{ + ae_int_t i, n2; + if( stridea==1 && strideb==1 ) + { + n2 = n/2; + for(i=n2; i!=0; i--, a+=2, b+=2) + { + b[0] = a[0]; + b[1] = a[1]; + } + if( n%2!=0 ) + b[0] = a[0]; + } + else + { + for(i=0; ix; + b[1] = a->y; + } + } + else + { + for(i=0; ix; + b[1] = -a->y; + } + } +} + + +/******************************************************************** +This subroutine copies unaligned complex vector (passed as double*) + +1. strideb is stride measured in complex numbers, not doubles +2. conj may be "N" (no conj.) or "C" (conj.) +********************************************************************/ +void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj) +{ + ae_int_t i; + + /* + * more general case + */ + if( conj[0]=='N' || conj[0]=='n' ) + { + for(i=0; ix; + pdst[1] = psrc->y; + } + } + if( op==1 ) + { + for(i=0,psrc=a; ix; + pdst[1] = psrc->y; + } + } + if( op==2 ) + { + for(i=0,psrc=a; ix; + pdst[1] = -psrc->y; + } + } + if( op==3 ) + { + for(i=0,psrc=a; ix; + pdst[1] = -psrc->y; + } + } +} + + +/******************************************************************** +This subroutine copies matrix from aligned contigous storage to +non-aligned non-contigous storage + +A: +* 2*alglib_c_block*alglib_c_block doubles (only MxN submatrix is used) +* aligned +* stride is alglib_c_block +* pointer to double is passed +* may be transformed during copying (as prescribed by op) + +B: +* MxN +* non-aligned +* non-contigous +* pointer to ae_complex is passed + +Transformation types: +* 0 - no transform +* 1 - transposition +* 2 - conjugate transposition +* 3 - conjugate, but no transposition +********************************************************************/ +void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride) +{ + ae_int_t i, j; + const double *psrc; + ae_complex *pdst; + if( op==0 ) + { + for(i=0,psrc=a; ix = psrc[0]; + pdst->y = psrc[1]; + } + } + if( op==1 ) + { + for(i=0,psrc=a; ix = psrc[0]; + pdst->y = psrc[1]; + } + } + if( op==2 ) + { + for(i=0,psrc=a; ix = psrc[0]; + pdst->y = -psrc[1]; + } + } + if( op==3 ) + { + for(i=0,psrc=a; ix = psrc[0]; + pdst->y = -psrc[1]; + } + } +} + + +/******************************************************************** +Real GEMM kernel +********************************************************************/ +ae_bool _ialglib_rmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + const double *_a, + ae_int_t _a_stride, + ae_int_t optypea, + const double *_b, + ae_int_t _b_stride, + ae_int_t optypeb, + double beta, + double *_c, + ae_int_t _c_stride) +{ + int i; + double *crow; + double _abuf[alglib_r_block+alglib_simd_alignment]; + double _bbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; + double * const abuf = (double * ) ae_align(_abuf,alglib_simd_alignment); + double * const b = (double * ) ae_align(_bbuf,alglib_simd_alignment); + void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; + void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; + + if( m>alglib_r_block || n>alglib_r_block || k>alglib_r_block || m<=0 || n<=0 || k<=0 || alpha==0.0 ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + rmv = &_ialglib_rmv_sse2; + mcopyblock = &_ialglib_mcopyblock_sse2; + } +#endif + + /* + * copy b + */ + if( optypeb==0 ) + mcopyblock(k, n, _b, 1, _b_stride, b); + else + mcopyblock(n, k, _b, 0, _b_stride, b); + + /* + * multiply B by A (from the right, by rows) + * and store result in C + */ + crow = _c; + if( optypea==0 ) + { + const double *arow = _a; + for(i=0; ialglib_c_block || n>alglib_c_block || k>alglib_c_block ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + cmv = &_ialglib_cmv_sse2; + } +#endif + + /* + * copy b + */ + brows = optypeb==0 ? k : n; + bcols = optypeb==0 ? n : k; + if( optypeb==0 ) + _ialglib_mcopyblock_complex(brows, bcols, _b, 1, _b_stride, b); + if( optypeb==1 ) + _ialglib_mcopyblock_complex(brows, bcols, _b, 0, _b_stride, b); + if( optypeb==2 ) + _ialglib_mcopyblock_complex(brows, bcols, _b, 3, _b_stride, b); + + /* + * multiply B by A (from the right, by rows) + * and store result in C + */ + arow = _a; + crow = _c; + for(i=0; ialglib_c_block || n>alglib_c_block ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + cmv = &_ialglib_cmv_sse2; + } +#endif + + /* + * Prepare + */ + _ialglib_mcopyblock_complex(n, n, _a, optype, _a_stride, abuf); + _ialglib_mcopyblock_complex(m, n, _x, 0, _x_stride, xbuf); + if( isunit ) + for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) + { + ae_complex tmp_c; + ae_complex beta; + ae_complex alpha; + tmp_c.x = pdiag[0]; + tmp_c.y = pdiag[1]; + beta = ae_c_d_div(1.0, tmp_c); + alpha.x = -beta.x; + alpha.y = -beta.y; + _ialglib_vcopy_dcomplex(n-1-i, pdiag+2*alglib_c_block, alglib_c_block, tmpbuf, 1, "No conj"); + cmv(m, n-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); + } + _ialglib_mcopyunblock_complex(m, n, xbuf, 0, _x, _x_stride); + } + return ae_true; +} + + +/******************************************************************** +real TRSM kernel +********************************************************************/ +ae_bool _ialglib_rmatrixrighttrsm(ae_int_t m, + ae_int_t n, + const double *_a, + ae_int_t _a_stride, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + double *_x, + ae_int_t _x_stride) +{ + /* + * local buffers + */ + double *pdiag; + ae_int_t i; + double _loc_abuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; + double _loc_xbuf[alglib_r_block*alglib_r_block+alglib_simd_alignment]; + double _loc_tmpbuf[alglib_r_block+alglib_simd_alignment]; + double * const abuf = (double *) ae_align(_loc_abuf, alglib_simd_alignment); + double * const xbuf = (double *) ae_align(_loc_xbuf, alglib_simd_alignment); + double * const tmpbuf = (double *) ae_align(_loc_tmpbuf,alglib_simd_alignment); + ae_bool uppera; + void (*rmv)(ae_int_t, ae_int_t, const double *, const double *, double *, ae_int_t, double, double) = &_ialglib_rmv; + void (*mcopyblock)(ae_int_t, ae_int_t, const double *, ae_int_t, ae_int_t, double *) = &_ialglib_mcopyblock; + + if( m>alglib_r_block || n>alglib_r_block ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + rmv = &_ialglib_rmv_sse2; + mcopyblock = &_ialglib_mcopyblock_sse2; + } +#endif + + /* + * Prepare + */ + mcopyblock(n, n, _a, optype, _a_stride, abuf); + mcopyblock(m, n, _x, 0, _x_stride, xbuf); + if( isunit ) + for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) + { + double beta = 1.0/(*pdiag); + double alpha = -beta; + _ialglib_vcopy(n-1-i, pdiag+alglib_r_block, alglib_r_block, tmpbuf+i+1, 1); + rmv(m, n-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); + } + _ialglib_mcopyunblock(m, n, xbuf, 0, _x, _x_stride); + } + return ae_true; +} + + +/******************************************************************** +complex TRSM kernel +********************************************************************/ +ae_bool _ialglib_cmatrixlefttrsm(ae_int_t m, + ae_int_t n, + const ae_complex *_a, + ae_int_t _a_stride, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_complex *_x, + ae_int_t _x_stride) +{ + /* + * local buffers + */ + double *pdiag, *arow; + ae_int_t i; + double _loc_abuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; + double _loc_xbuf[2*alglib_c_block*alglib_c_block+alglib_simd_alignment]; + double _loc_tmpbuf[2*alglib_c_block+alglib_simd_alignment]; + double * const abuf = (double *) ae_align(_loc_abuf, alglib_simd_alignment); + double * const xbuf = (double *) ae_align(_loc_xbuf, alglib_simd_alignment); + double * const tmpbuf = (double *) ae_align(_loc_tmpbuf,alglib_simd_alignment); + ae_bool uppera; + void (*cmv)(ae_int_t, ae_int_t, const double *, const double *, ae_complex *, double *, ae_int_t, ae_complex, ae_complex) = &_ialglib_cmv; + + if( m>alglib_c_block || n>alglib_c_block ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + cmv = &_ialglib_cmv_sse2; + } +#endif + + /* + * Prepare + * Transpose X (so we may use mv, which calculates A*x, but not x*A) + */ + _ialglib_mcopyblock_complex(m, m, _a, optype, _a_stride, abuf); + _ialglib_mcopyblock_complex(m, n, _x, 1, _x_stride, xbuf); + if( isunit ) + for(i=0,pdiag=abuf; i=0; i--,pdiag-=2*(alglib_c_block+1)) + { + ae_complex tmp_c; + ae_complex beta; + ae_complex alpha; + tmp_c.x = pdiag[0]; + tmp_c.y = pdiag[1]; + beta = ae_c_d_div(1.0, tmp_c); + alpha.x = -beta.x; + alpha.y = -beta.y; + _ialglib_vcopy_dcomplex(m-1-i, pdiag+2, 1, tmpbuf, 1, "No conj"); + cmv(n, m-1-i, xbuf+2*(i+1), tmpbuf, NULL, xbuf+2*i, alglib_c_block, alpha, beta); + } + _ialglib_mcopyunblock_complex(m, n, xbuf, 1, _x, _x_stride); + } + else + { for(i=0,pdiag=abuf,arow=abuf; ialglib_r_block || n>alglib_r_block ) + return ae_false; + + /* + * Check for SSE2 support + */ +#ifdef AE_HAS_SSE2_INTRINSICS + if( ae_cpuid() & CPU_SSE2 ) + { + rmv = &_ialglib_rmv_sse2; + mcopyblock = &_ialglib_mcopyblock_sse2; + } +#endif + + /* + * Prepare + * Transpose X (so we may use mv, which calculates A*x, but not x*A) + */ + mcopyblock(m, m, _a, optype, _a_stride, abuf); + mcopyblock(m, n, _x, 1, _x_stride, xbuf); + if( isunit ) + for(i=0,pdiag=abuf; i=0; i--,pdiag-=alglib_r_block+1) + { + double beta = 1.0/(*pdiag); + double alpha = -beta; + _ialglib_vcopy(m-1-i, pdiag+1, 1, tmpbuf+i+1, 1); + rmv(n, m-1-i, xbuf+i+1, tmpbuf+i+1, xbuf+i, alglib_r_block, alpha, beta); + } + _ialglib_mcopyunblock(m, n, xbuf, 1, _x, _x_stride); + } + else + { for(i=0,pdiag=abuf,arow=abuf; ialglib_c_block || k>alglib_c_block ) + return ae_false; + if( n==0 ) + return ae_true; + + /* + * copy A and C, task is transformed to "A*A^H"-form. + * if beta==0, then C is filled by zeros (and not referenced) + * + * alpha==0 or k==0 are correctly processed (A is not referenced) + */ + c_alpha.x = alpha; + c_alpha.y = 0.0; + c_beta.x = beta; + c_beta.y = 0.0; + if( alpha==0.0 ) + k = 0; + if( k>0 ) + { + if( optypea==0 ) + _ialglib_mcopyblock_complex(n, k, _a, 3, _a_stride, abuf); + else + _ialglib_mcopyblock_complex(k, n, _a, 1, _a_stride, abuf); + } + _ialglib_mcopyblock_complex(n, n, _c, 0, _c_stride, cbuf); + if( beta==0.0 ) + { + for(i=0,crow=cbuf; ialglib_r_block || k>alglib_r_block ) + return ae_false; + if( n==0 ) + return ae_true; + + /* + * copy A and C, task is transformed to "A*A^T"-form. + * if beta==0, then C is filled by zeros (and not referenced) + * + * alpha==0 or k==0 are correctly processed (A is not referenced) + */ + if( alpha==0.0 ) + k = 0; + if( k>0 ) + { + if( optypea==0 ) + _ialglib_mcopyblock(n, k, _a, 0, _a_stride, abuf); + else + _ialglib_mcopyblock(k, n, _a, 1, _a_stride, abuf); + } + _ialglib_mcopyblock(n, n, _c, 0, _c_stride, cbuf); + if( beta==0.0 ) + { + for(i=0,crow=cbuf; iptr.pp_double[ia]+ja, _a->stride, optypea, _b->ptr.pp_double[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_double[ic]+jc, _c->stride); +} + +ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + const ae_matrix *_a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + const ae_matrix *_b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + ae_matrix *_c, + ae_int_t ic, + ae_int_t jc) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( (alpha.x==0.0 && alpha.y==0.0) || k==0 || n==0 || m==0 ) + return ae_false; + + /* handle with optimized ALGLIB kernel */ + return _ialglib_cmatrixgemm(m, n, k, alpha, _a->ptr.pp_complex[ia]+ja, _a->stride, optypea, _b->ptr.pp_complex[ib]+jb, _b->stride, optypeb, beta, _c->ptr.pp_complex[ic]+jc, _c->stride); +} + +ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( m==0 || n==0) + return ae_false; + + /* handle with optimized ALGLIB kernel */ + return _ialglib_cmatrixrighttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); +} + +ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( m==0 || n==0) + return ae_false; + + /* handle with optimized ALGLIB kernel */ + return _ialglib_rmatrixrighttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); +} + +ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( m==0 || n==0) + return ae_false; + + /* handle with optimized ALGLIB kernel */ + return _ialglib_cmatrixlefttrsm(m, n, &a->ptr.pp_complex[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_complex[i2][j2], x->stride); +} + +ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( m==0 || n==0) + return ae_false; + + /* handle with optimized ALGLIB kernel */ + return _ialglib_rmatrixlefttrsm(m, n, &a->ptr.pp_double[i1][j1], a->stride, isupper, isunit, optype, &x->ptr.pp_double[i2][j2], x->stride); +} + +ae_bool _ialglib_i_cmatrixherkf(ae_int_t n, + ae_int_t k, + double alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( alpha==0.0 || k==0 || n==0) + return ae_false; + + /* ALGLIB kernel */ + return _ialglib_cmatrixherk(n, k, alpha, &a->ptr.pp_complex[ia][ja], a->stride, optypea, beta, &c->ptr.pp_complex[ic][jc], c->stride, isupper); +} + +ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, + ae_int_t k, + double alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper) +{ + /* handle degenerate cases like zero matrices by ALGLIB - greatly simplifies passing data to ALGLIB kernel */ + if( alpha==0.0 || k==0 || n==0) + return ae_false; + + /* ALGLIB kernel */ + return _ialglib_rmatrixsyrk(n, k, alpha, &a->ptr.pp_double[ia][ja], a->stride, optypea, beta, &c->ptr.pp_double[ic][jc], c->stride, isupper); +} + +ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs) +{ + return _ialglib_cmatrixrank1(m, n, &a->ptr.pp_complex[ia][ja], a->stride, &u->ptr.p_complex[uoffs], &v->ptr.p_complex[voffs]); +} + +ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs) +{ + return _ialglib_rmatrixrank1(m, n, &a->ptr.pp_double[ia][ja], a->stride, &u->ptr.p_double[uoffs], &v->ptr.p_double[voffs]); +} + +ae_bool _ialglib_i_rmatrixgerf(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + double alpha, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs) +{ + return _ialglib_rmatrixger(m, n, &a->ptr.pp_double[ia][ja], a->stride, alpha, &u->ptr.p_double[uoffs], &v->ptr.p_double[voffs]); +} + + + + +/******************************************************************** +This function reads rectangular matrix A given by two column pointers +col0 and col1 and stride src_stride and moves it into contiguous row- +by-row storage given by dst. + +It can handle following special cases: +* col1==NULL in this case second column of A is filled by zeros +********************************************************************/ +void _ialglib_pack_n2( + double *col0, + double *col1, + ae_int_t n, + ae_int_t src_stride, + double *dst) +{ + ae_int_t n2, j, stride2; + + /* + * handle special case + */ + if( col1==NULL ) + { + for(j=0; j=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(rdotv,(n,x->ptr.p_double,y->ptr.p_double,_state)) /* use _ALGLIB_KERNEL_VOID_ for a kernel that does not return result */ + + /* + * Original generic C implementation + */ + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[i]*y->ptr.p_double[i]; + } + return result; +} + + + +/************************************************************************* +Computes dot product (X,A[i]) for elements [0,N) of vector X[] and row A[i,*] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + A - array[?,N], matrix to process + I - row index + +RESULT: + (X,Ai) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_matrix* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(rdotv,(n,x->ptr.p_double,a->ptr.pp_double[i],_state)) + + result = (double)(0); + for(j=0; j<=n-1; j++) + { + result = result+x->ptr.p_double[j]*a->ptr.pp_double[i][j]; + } + return result; +} + + +/************************************************************************* +Computes dot product (X,A[i]) for rows A[ia,*] and B[ib,*] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + A - array[?,N], matrix to process + I - row index + +RESULT: + (X,Ai) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_state *_state) +{ + ae_int_t j; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(rdotv,(n,a->ptr.pp_double[ia],b->ptr.pp_double[ib],_state)) + + result = (double)(0); + for(j=0; j<=n-1; j++) + { + result = result+a->ptr.pp_double[ia][j]*b->ptr.pp_double[ib][j]; + } + return result; +} + + +/************************************************************************* +Computes dot product (X,X) for elements [0,N) of X[] + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +RESULT: + (X,X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rdotv2(ae_int_t n, /* Real */ const ae_vector* x, ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(rdotv2,(n,x->ptr.p_double,_state)) + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + result = result+v*v; + } + return result; +} + + +/************************************************************************* +Copies vector X[] to Y[] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - leading N elements are replaced by X + + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopyv, + (n,x->ptr.p_double,y->ptr.p_double,_state)) + + + for(j=0; j<=n-1; j++) + { + y->ptr.p_double[j] = x->ptr.p_double[j]; + } +} + +/************************************************************************* +Copies vector X[] to row I of A[,] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + A - preallocated 2D array large enough to store result + I - destination row index + +OUTPUT PARAMETERS: + A - leading N elements of I-th row are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopyv, + (n, x->ptr.p_double, a->ptr.pp_double[i], _state)) + + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = x->ptr.p_double[j]; + } +} + + +/************************************************************************* +Copies row I of A[,] to vector X[] + +INPUT PARAMETERS: + N - vector length + A - 2D array, source + I - source row index + X - preallocated destination + +OUTPUT PARAMETERS: + X - array[N], destination + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyrv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopyv, + (n, a->ptr.pp_double[i], x->ptr.p_double, _state)) + + for(j=0; j<=n-1; j++) + { + x->ptr.p_double[j] = a->ptr.pp_double[i][j]; + } +} + + +/************************************************************************* +Copies row I of A[,] to row K of B[,]. + +A[i,...] and B[k,...] may overlap. + +INPUT PARAMETERS: + N - vector length + A - 2D array, source + I - source row index + B - preallocated destination + K - destination row index + +OUTPUT PARAMETERS: + B - row K overwritten + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_matrix* b, + ae_int_t k, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopyv, + (n, a->ptr.pp_double[i], b->ptr.pp_double[k], _state)) + + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[k][j] = a->ptr.pp_double[i][j]; + } +} + +/************************************************************************* +Performs copying with multiplication of V*X[] to Y[] + +INPUT PARAMETERS: + N - vector length + V - multiplier + X - array[N], source + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - array[N], Y = V*X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopymulv(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopymulv, + (n,v,x->ptr.p_double,y->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = v*x->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs copying with multiplication of V*X[] to Y[I,*] + +INPUT PARAMETERS: + N - vector length + V - multiplier + X - array[N], source + Y - preallocated array[?,N] + RIdx - destination row index + +OUTPUT PARAMETERS: + Y - Y[RIdx,...] = V*X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopymulvr(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t ridx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopymulv, + (n,v,x->ptr.p_double,y->ptr.pp_double[ridx],_state)) + + for(i=0; i<=n-1; i++) + { + y->ptr.pp_double[ridx][i] = v*x->ptr.p_double[i]; + } +} + +/************************************************************************* +Copies vector X[] to Y[] + +INPUT PARAMETERS: + N - vector length + X - source array + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - X copied to Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void icopyv(ae_int_t n, + /* Integer */ const ae_vector* x, + /* Integer */ ae_vector* y, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(icopyv, + (n, x->ptr.p_int, y->ptr.p_int, _state)) + + for(j=0; j<=n-1; j++) + { + y->ptr.p_int[j] = x->ptr.p_int[j]; + } +} + +/************************************************************************* +Copies vector X[] to Y[] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - leading N elements are replaced by X + + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void bcopyv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1*8 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(bcopyv, + (n, x->ptr.p_bool, y->ptr.p_bool, _state)) + + for(j=0; j<=n-1; j++) + { + y->ptr.p_bool[j] = x->ptr.p_bool[j]; + } +} + + +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rsetv, + (n, v, x->ptr.p_double, _state)) + + for(j=0; j<=n-1; j++) + { + x->ptr.p_double[j] = v; + } +} + +/************************************************************************* +Sets row I of A[,] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + A - array[N,N] or larger + I - row index + +OUTPUT PARAMETERS: + A - leading N elements of I-th row are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetr(ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rsetv, + (n, v, a->ptr.pp_double[i], _state)) + + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = v; + } +} + + +/************************************************************************* +Sets X[OffsX:OffsX+N-1] to V + +INPUT PARAMETERS: + N - subvector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - X[OffsX:OffsX+N-1] is replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rsetvx, + (n, v, x->ptr.p_double+offsx, _state)) + + for(j=0; j<=n-1; j++) + { + x->ptr.p_double[offsx+j] = v; + } +} + + +/************************************************************************* +Sets matrix A[] to V + +INPUT PARAMETERS: + M, N - rows/cols count + V - value to set + A - array[M,N] + +OUTPUT PARAMETERS: + A - leading M rows, N cols are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +static void rsetm_simd(const ae_int_t n, const double v, double *pDest, ae_state *_state) +{ + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rsetv, (n, v, pDest, _state)); + + ae_int_t j; + for(j=0; j<=n-1; j++) { + pDest[j] = v; + } +} + +void rsetm(ae_int_t m, + ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n >=_ABLASF_KERNEL_SIZE1 ) { + for(i=0; iptr.pp_double[i], _state); + } + return; + } + + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = v; + } + } +} + + +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void isetv(ae_int_t n, + ae_int_t v, + /* Integer */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(isetv, + (n, v, x->ptr.p_int, _state)) + + for(j=0; j<=n-1; j++) + { + x->ptr.p_int[j] = v; + } +} + +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void bsetv(ae_int_t n, + ae_bool v, + /* Boolean */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1*8 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(bsetv, + (n, v, x->ptr.p_bool, _state)) + + for(j=0; j<=n-1; j++) + { + x->ptr.p_bool[j] = v; + } +} + + +/************************************************************************* +Performs inplace multiplication of X[] by V + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements 0...N-1 multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmulv, + (n,v,x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*v; + } +} + + +/************************************************************************* +Performs inplace multiplication of X[] by V + +INPUT PARAMETERS: + N - row length + X - array[?,N], row to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements 0...N-1 of row RowIdx are multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulr(ae_int_t n, + double v, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmulv, + (n, v, x->ptr.pp_double[rowidx], _state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]*v; + } +} + + +/************************************************************************* +Performs inplace computation of Sqrt(X) + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + X - elements 0...N-1 replaced by Sqrt(X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsqrtv(ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_AVX2(rsqrtv, + (n,x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + x->ptr.p_double[i] = sqrt(x->ptr.p_double[i]); +} + + +/************************************************************************* +Performs inplace computation of Sqrt(X[RowIdx,*]) + +INPUT PARAMETERS: + N - vector length + X - array[?,N], matrix to process + +OUTPUT PARAMETERS: + X - elements 0...N-1 replaced by Sqrt(X) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsqrtr(ae_int_t n, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_AVX2(rsqrtv, + (n, x->ptr.pp_double[rowidx], _state)) + + for(i=0; i<=n-1; i++) + x->ptr.pp_double[rowidx][i] = sqrt(x->ptr.pp_double[rowidx][i]); +} + + +/************************************************************************* +Performs inplace multiplication of X[OffsX:OffsX+N-1] by V + +INPUT PARAMETERS: + N - subvector length + X - vector to process + V - multiplier + +OUTPUT PARAMETERS: + X - elements OffsX:OffsX+N-1 multiplied by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmulvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmulvx, + (n, v, x->ptr.p_double+offsx, _state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[offsx+i] = x->ptr.p_double[offsx+i]*v; + } +} + + +/************************************************************************* +Performs inplace addition of Y[] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddv(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(raddv, + (n,alpha,y->ptr.p_double,x->ptr.p_double,_state)) + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+alpha*y->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs inplace addition of vector Y[] to row X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - vector to add + X - target row RowIdx + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddvr(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(raddv, + (n,alpha,y->ptr.p_double,x->ptr.pp_double[rowidx],_state)) + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]+alpha*y->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs inplace addition of Y[RIdx,...] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[?,N], matrix whose RIdx-th row is added + RIdx - row index + X - array[N], vector to process + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddrv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(raddv, + (n,alpha,y->ptr.pp_double[ridx],x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+alpha*y->ptr.pp_double[ridx][i]; + } +} + + +/************************************************************************* +Performs inplace addition of Y[RIdx,...] to X[RIdxDst] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - array[?,N], matrix whose RIdxSrc-th row is added + RIdxSrc - source row index + X - array[?,N], matrix whose RIdxDst-th row is target + RIdxDst - destination row index + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddrr(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridxsrc, + /* Real */ ae_matrix* x, + ae_int_t ridxdst, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(raddv, + (n,alpha,y->ptr.pp_double[ridxsrc],x->ptr.pp_double[ridxdst],_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[ridxdst][i] = x->ptr.pp_double[ridxdst][i]+alpha*y->ptr.pp_double[ridxsrc][i]; + } +} + + +/************************************************************************* +Performs inplace addition of Y[] to X[] + +INPUT PARAMETERS: + N - vector length + Alpha - multiplier + Y - source vector + OffsY - source offset + X - destination vector + OffsX - destination offset + +RESULT: + X := X + alpha*Y + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void raddvx(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + ae_int_t offsy, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(raddvx, + (n, alpha, y->ptr.p_double+offsy, x->ptr.p_double+offsx, _state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[offsx+i] = x->ptr.p_double[offsx+i]+alpha*y->ptr.p_double[offsy+i]; + } +} + + +/************************************************************************* +Performs inplace addition of Y[]*Z[] to X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X + Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_FMA(rmuladdv, (n, y->ptr.p_double, z->ptr.p_double, x->ptr.p_double, _state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs inplace subtraction of Y[]*Z[] from X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + +RESULT: + X := X - Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rnegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_FMA(rnegmuladdv, (n, y->ptr.p_double, z->ptr.p_double, x->ptr.p_double, _state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] -= y->ptr.p_double[i]*z->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs addition of Y[]*Z[] to X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + R - array[N], vector to process + +RESULT: + R := X + Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rcopymuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_FMA(rcopymuladdv, (n, y->ptr.p_double, z->ptr.p_double, x->ptr.p_double, r->ptr.p_double, _state)) + + for(i=0; i<=n-1; i++) + r->ptr.p_double[i] = x->ptr.p_double[i]+y->ptr.p_double[i]*z->ptr.p_double[i]; +} + + +/************************************************************************* +Performs subtraction of Y[]*Z[] from X[] + +INPUT PARAMETERS: + N - vector length + Y - array[N], vector to process + Z - array[N], vector to process + X - array[N], vector to process + R - array[N], vector to process + +RESULT: + R := X - Y*Z + + -- ALGLIB -- + Copyright 29.10.2021 by Bochkanov Sergey +*************************************************************************/ +void rcopynegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_FMA(rcopynegmuladdv, (n, y->ptr.p_double, z->ptr.p_double, x->ptr.p_double, r->ptr.p_double, _state)) + + for(i=0; i<=n-1; i++) + r->ptr.p_double[i] = x->ptr.p_double[i]-y->ptr.p_double[i]*z->ptr.p_double[i]; +} + + +/************************************************************************* +Performs componentwise multiplication of vector X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target vector + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemulv, + (n,y->ptr.p_double,x->ptr.p_double,_state)) + + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*y->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs componentwise multiplication of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemulv, + (n,y->ptr.p_double,x->ptr.pp_double[rowidx],_state)) + + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = x->ptr.pp_double[rowidx][i]*y->ptr.p_double[i]; + } +} + + +/************************************************************************* +Performs componentwise multiplication of row X[] by vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise(X*Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemulrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemulv, + (n,y->ptr.pp_double[rowidx],x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*y->ptr.pp_double[rowidx][i]; + } +} + + + + +/************************************************************************* +Performs componentwise division of vector X[] by vector Y[] + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_AVX2(rmergedivv, + (n,y->ptr.p_double,x->ptr.p_double,_state)) + + + for(i=0; i<=n-1; i++) + x->ptr.p_double[i] /= y->ptr.p_double[i]; +} + + +/************************************************************************* +Performs componentwise division of row X[] by vector Y[] + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_AVX2(rmergedivv, + (n,y->ptr.p_double,x->ptr.pp_double[rowidx],_state)) + + + for(i=0; i<=n-1; i++) + x->ptr.pp_double[rowidx][i] /= y->ptr.p_double[i]; +} + + +/************************************************************************* +Performs componentwise division of row X[] by vector Y[] + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergedivrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_AVX2(rmergedivv, + (n,y->ptr.pp_double[rowidx],x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + x->ptr.p_double[i] /= y->ptr.pp_double[rowidx][i]; +} + +/************************************************************************* +Performs componentwise max of vector X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target vector + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemaxv, + (n,y->ptr.p_double,x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], y->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Performs componentwise max of row X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemaxv, + (n,y->ptr.p_double,x->ptr.pp_double[rowidx],_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = ae_maxreal(x->ptr.pp_double[rowidx][i], y->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Performs componentwise max of row X[I] and vector Y[] + +INPUT PARAMETERS: + N - vector length + X - matrix, I-th row is source + rowidx - target row RowIdx + +RESULT: + Y := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergemaxrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergemaxv, + (n,x->ptr.pp_double[rowidx],y->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = ae_maxreal(y->ptr.p_double[i], x->ptr.pp_double[rowidx][i], _state); + } +} + +/************************************************************************* +Performs componentwise min of vector X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - source vector + X - target vector + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergeminv, + (n,y->ptr.p_double,x->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = ae_minreal(x->ptr.p_double[i], y->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Performs componentwise max of row X[] and vector Y[] + +INPUT PARAMETERS: + N - vector length + Y - vector to multiply by + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergeminv, + (n,y->ptr.p_double,x->ptr.pp_double[rowidx],_state)) + + for(i=0; i<=n-1; i++) + { + x->ptr.pp_double[rowidx][i] = ae_minreal(x->ptr.pp_double[rowidx][i], y->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Performs componentwise max of row X[I] and vector Y[] + +INPUT PARAMETERS: + N - vector length + X - matrix, I-th row is source + X - target row RowIdx + +RESULT: + X := componentwise_max(X,Y) + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rmergeminrv(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rmergeminv, + (n,x->ptr.pp_double[rowidx],y->ptr.p_double,_state)) + + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = ae_minreal(y->ptr.p_double[i], x->ptr.pp_double[rowidx][i], _state); + } +} +/************************************************************************* +Returns maximum X + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + max(X[i]) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxv(ae_int_t n, /* Real */ const ae_vector* x, ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2(rmaxv, (n, x->ptr.p_double, _state)); + + if(n == 0) + return 0.0; + result = x->ptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + if( v>result ) + { + result = v; + } + } + return result; +} + +/************************************************************************* +Returns maximum X + +INPUT PARAMETERS: + N - vector length + X - matrix to process, RowIdx-th row is processed + +OUTPUT PARAMETERS: + max(X[RowIdx,i]) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2(rmaxv,(n, x->ptr.pp_double[rowidx], _state)) + + if(n == 0) + return 0.0; + result = x->ptr.pp_double[rowidx][0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.pp_double[rowidx][i]; + if( v>result ) + { + result = v; + } + } + return result; +} + +/************************************************************************* +Returns maximum |X| + +INPUT PARAMETERS: + N - vector length + X - array[N], vector to process + +OUTPUT PARAMETERS: + max(|X[i]|) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxabsv(ae_int_t n, /* Real */ const ae_vector* x, ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2(rmaxabsv, (n, x->ptr.p_double, _state)) + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = ae_fabs(x->ptr.p_double[i], _state); + if( v>result ) + { + result = v; + } + } + return result; +} + + +/************************************************************************* +Returns maximum |X| + +INPUT PARAMETERS: + N - vector length + X - matrix to process, RowIdx-th row is processed + +OUTPUT PARAMETERS: + max(|X[RowIdx,i]|) + zero for N=0 + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +double rmaxabsr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_RETURN_SSE2_AVX2(rmaxabsv,(n, x->ptr.pp_double[rowidx], _state)) + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = ae_fabs(x->ptr.pp_double[rowidx][i], _state); + if( v>result ) + { + result = v; + } + } + return result; +} + +/************************************************************************* +Copies vector X[] to Y[], extended version + +INPUT PARAMETERS: + N - vector length + X - source array + OffsX - source offset + Y - preallocated array[N] + OffsY - destination offset + +OUTPUT PARAMETERS: + Y - N elements starting from OffsY are replaced by X[OffsX:OffsX+N-1] + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyvx(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t offsx, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(rcopyvx,(n, x->ptr.p_double+offsx, y->ptr.p_double+offsy, _state)) + + for(j=0; j<=n-1; j++) + { + y->ptr.p_double[offsy+j] = x->ptr.p_double[offsx+j]; + } +} + +/************************************************************************* +Copies vector X[] to Y[], extended version + +INPUT PARAMETERS: + N - vector length + X - source array + OffsX - source offset + Y - preallocated array[N] + OffsY - destination offset + +OUTPUT PARAMETERS: + Y - N elements starting from OffsY are replaced by X[OffsX:OffsX+N-1] + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void icopyvx(ae_int_t n, + /* Integer */ const ae_vector* x, + ae_int_t offsx, + /* Integer */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t j; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + if( n>=_ABLASF_KERNEL_SIZE1 ) + _ALGLIB_KERNEL_VOID_SSE2_AVX2(icopyvx,(n, x->ptr.p_int+offsx, y->ptr.p_int+offsy, _state)) + + for(j=0; j<=n-1; j++) + { + y->ptr.p_int[offsy+j] = x->ptr.p_int[offsx+j]; + } +} + +/************************************************************************* +Matrix-vector product: y := alpha*op(A)*x + beta*y + +NOTE: this function expects Y to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, x, y. + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + Alpha- coefficient + A - source matrix + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector, has at least N elements + Beta- coefficient + Y - preallocated output array, has at least M elements + +OUTPUT PARAMETERS: + Y - vector which stores result + +HANDLING OF SPECIAL CASES: + * if M=0, then subroutine does nothing. It does not even touch arrays. + * if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. A and X are not referenced + at all. Initial values of Y are ignored (we do not multiply Y by + zero, we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y + * if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by A*x; + initial state of Y is ignored (rewritten by A*x, without initial + multiplication by zeros). + + + -- ALGLIB routine -- + + 01.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t opa, + /* Real */ const ae_vector* x, + double beta, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Properly premultiply Y by Beta. + * + * Quick exit for M=0, N=0 or Alpha=0. + * After this block we have M>0, N>0, Alpha<>0. + */ + if( m<=0 ) + { + return; + } + if( ae_fp_neq(beta,(double)(0)) ) + { + rmulv(m, beta, y, _state); + } + else + { + rsetv(m, 0.0, y, _state); + } + if( n<=0||ae_fp_eq(alpha,0.0) ) + { + return; + } + + /* + * Straight or transposed? + */ + if( opa==0 ) + { + /* + * Try SIMD code + */ + if( n>=_ABLASF_KERNEL_SIZE2 ) + _ALGLIB_KERNEL_VOID_AVX2_FMA(rgemv_straight, (m, n, alpha, a, + x->ptr.p_double, y->ptr.p_double, _state)) + + /* + * Generic C version: y += A*x + */ + for(i=0; i<=m-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+a->ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + y->ptr.p_double[i] = alpha*v+y->ptr.p_double[i]; + } + return; + } + if( opa==1 ) + { + /* + * Try SIMD code + */ + if( m>=_ABLASF_KERNEL_SIZE2 ) + _ALGLIB_KERNEL_VOID_AVX2_FMA(rgemv_transposed, (m, n, alpha, a, + x->ptr.p_double, y->ptr.p_double, _state)) + + + /* + * Generic C version: y += A^T*x + */ + for(i=0; i<=n-1; i++) + { + v = alpha*x->ptr.p_double[i]; + for(j=0; j<=m-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+v*a->ptr.pp_double[i][j]; + } + } + return; + } +} + + +/************************************************************************* +Matrix-vector product: y := alpha*op(A)*x + beta*y + +Here x, y, A are subvectors/submatrices of larger vectors/matrices. + +NOTE: this function expects Y to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, x, y. + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + Alpha- coefficient + A - source matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector, has at least N+IX elements + IX - subvector offset + Beta- coefficient + Y - preallocated output array, has at least M+IY elements + IY - subvector offset + +OUTPUT PARAMETERS: + Y - vector which stores result + +HANDLING OF SPECIAL CASES: + * if M=0, then subroutine does nothing. It does not even touch arrays. + * if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. A and X are not referenced + at all. Initial values of Y are ignored (we do not multiply Y by + zero, we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y + * if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by A*x; + initial state of Y is ignored (rewritten by A*x, without initial + multiplication by zeros). + + + -- ALGLIB routine -- + + 01.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rgemvx(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Properly premultiply Y by Beta. + * + * Quick exit for M=0, N=0 or Alpha=0. + * After this block we have M>0, N>0, Alpha<>0. + */ + if( m<=0 ) + { + return; + } + if( ae_fp_neq(beta,(double)(0)) ) + { + rmulvx(m, beta, y, iy, _state); + } + else + { + rsetvx(m, 0.0, y, iy, _state); + } + if( n<=0||ae_fp_eq(alpha,0.0) ) + { + return; + } + + /* + * Straight or transposed? + */ + if( opa==0 ) + { + /* + * Try SIMD code + */ + if( n>=_ABLASF_KERNEL_SIZE2 ) + _ALGLIB_KERNEL_VOID_AVX2_FMA(rgemvx_straight, (m, n, alpha, a, ia, ja, + x->ptr.p_double + ix, y->ptr.p_double + iy, _state)) + + + /* + * Generic C code: y += A*x + */ + for(i=0; i<=m-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + y->ptr.p_double[iy+i] = alpha*v+y->ptr.p_double[iy+i]; + } + return; + } + if( opa==1 ) + { + /* + * Try SIMD code + */ + if( m>=_ABLASF_KERNEL_SIZE2 ) + _ALGLIB_KERNEL_VOID_AVX2_FMA(rgemvx_transposed, (m, n, alpha, a, ia, ja, + x->ptr.p_double+ix, y->ptr.p_double+iy, _state)) + + /* + * Generic C code: y += A^T*x + */ + for(i=0; i<=n-1; i++) + { + v = alpha*x->ptr.p_double[ix+i]; + for(j=0; j<=m-1; j++) + { + y->ptr.p_double[iy+j] = y->ptr.p_double[iy+j]+v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } +} + + +/************************************************************************* +Rank-1 correction: A := A + alpha*u*v' + +NOTE: this function expects A to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, u, v. + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target MxN matrix + Alpha- coefficient + U - vector #1 + V - vector #2 + + + -- ALGLIB routine -- + 07.09.2021 + Bochkanov Sergey +*************************************************************************/ +void rger(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double s; + + + if( (m<=0||n<=0)||ae_fp_eq(alpha,(double)(0)) ) + { + return; + } + for(i=0; i<=m-1; i++) + { + s = alpha*u->ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]+s*v->ptr.p_double[j]; + } + } +} + + +/************************************************************************* +This subroutine solves linear system op(A)*x=b where: +* A is NxN upper/lower triangular/unitriangular matrix +* X and B are Nx1 vectors +* "op" may be identity transformation or transposition + +Solution replaces X. + +IMPORTANT: * no overflow/underflow/denegeracy tests is performed. + * no integrity checks for operand sizes, out-of-bounds accesses + and so on is performed + +INPUT PARAMETERS + N - matrix size, N>=0 + A - matrix, actial matrix is stored in A[IA:IA+N-1,JA:JA+N-1] + IA - submatrix offset + JA - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - right part, actual vector is stored in X[IX:IX+N-1] + IX - offset + +OUTPUT PARAMETERS + X - solution replaces elements X[IX:IX+N-1] + + -- ALGLIB routine -- + (c) 07.09.2021 Bochkanov Sergey +*************************************************************************/ +void rtrsvx(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + if( n<=0 ) + { + return; + } + if( optype==0&&isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + for(j=i+1; j<=n-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==0&&!isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + for(j=0; j<=i-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==1&&isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==0.0 ) + { + continue; + } + for(j=i+1; j<=n-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + if( optype==1&&!isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==0.0 ) + { + continue; + } + for(j=0; j<=i-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + ae_assert(ae_false, "rTRSVX: unexpected operation type", _state); +} + +/************************************************************************* +Fast rGEMM kernel with AVX2/FMA support + + -- ALGLIB routine -- + 19.09.2021 + Bochkanov Sergey +*************************************************************************/ +ae_bool ablasf_rgemm32basecase( + ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* _a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* _b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* _c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ +#if !defined(_ALGLIB_HAS_AVX2_INTRINSICS) + return ae_false; +#else + const ae_int_t block_size = _ABLASF_BLOCK_SIZE; + const ae_int_t micro_size = _ABLASF_MICRO_SIZE; + ae_int_t out0, out1; + double *c; + ae_int_t stride_c; + ae_int_t cpu_id = ae_cpuid(); + ae_int_t (*ablasf_packblk)(const double*, ae_int_t, ae_int_t, ae_int_t, ae_int_t, double*, ae_int_t, ae_int_t) = (k==32 && block_size==32) ? ablasf_packblkh32_avx2 : ablasf_packblkh_avx2; + void (*ablasf_dotblk)(const double *, const double *, ae_int_t, ae_int_t, ae_int_t, double *, ae_int_t) = ablasf_dotblkh_avx2; + void (*ablasf_daxpby)(ae_int_t, double, const double *, double, double*) = ablasf_daxpby_avx2; + + /* + * Determine CPU and kernel support + */ + if( m>block_size || n>block_size || k>block_size || m==0 || n==0 || !(cpu_id&CPU_AVX2) ) + return ae_false; +#if defined(_ALGLIB_HAS_FMA_INTRINSICS) + if( cpu_id&CPU_FMA ) + ablasf_dotblk = ablasf_dotblkh_fma; +#endif + + /* + * Prepare C + */ + c = _c->ptr.pp_double[ic]+jc; + stride_c = _c->stride; + + /* + * Do we have alpha*A*B ? + */ + if( alpha!=0 && k>0 ) + { + /* + * Prepare structures + */ + ae_int_t base0, base1, offs0; + double *a = _a->ptr.pp_double[ia]+ja; + double *b = _b->ptr.pp_double[ib]+jb; + ae_int_t stride_a = _a->stride; + ae_int_t stride_b = _b->stride; + double _blka[_ABLASF_BLOCK_SIZE*_ABLASF_MICRO_SIZE+_ALGLIB_SIMD_ALIGNMENT_DOUBLES]; + double _blkb_long[_ABLASF_BLOCK_SIZE*_ABLASF_BLOCK_SIZE+_ALGLIB_SIMD_ALIGNMENT_DOUBLES]; + double _blkc[_ABLASF_MICRO_SIZE*_ABLASF_BLOCK_SIZE+_ALGLIB_SIMD_ALIGNMENT_DOUBLES]; + double *blka = (double*)ae_align(_blka, _ALGLIB_SIMD_ALIGNMENT_BYTES); + double *storageb_long = (double*)ae_align(_blkb_long,_ALGLIB_SIMD_ALIGNMENT_BYTES); + double *blkc = (double*)ae_align(_blkc, _ALGLIB_SIMD_ALIGNMENT_BYTES); + + /* + * Pack transform(B) into precomputed block form + */ + for(base1=0; base1ptr.p_double[cols0]; + double *p_mat_row = rowstorage->ptr.p_double+offss+1*1; + double *p_simd_buf = simdbuf->ptr.p_double; + ae_int_t *p_rowidx = superrowidx->ptr.p_int+rbase; + if( simdwidth==4 ) + { + for(k=0; kptr.p_int[rbase+k]; + baseoffs = offss+(k+blocksize)*sstride; + v = simdbuf->ptr.p_double[i*simdwidth]; + for(j=0; j<=blocksize-1; j++) + { + v = v-rowstorage->ptr.p_double[baseoffs+j]*x->ptr.p_double[cols0+j]; + } + simdbuf->ptr.p_double[i*simdwidth] = v; + } +} + + +/************************************************************************* +Fast kernels for small supernodal updates: special 4x4x4x4 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs AxBxCx4 update, i.e.: +* S is a tHeight*A matrix with row stride equal to 4 (usually it means that + it has 3 or 4 columns) +* U is a uHeight*B matrix +* Uc' is a B*C matrix, with C<=A +* scatter() scatters rows and columns of U*Uc' + +Return value: +* True if update was applied +* False if kernel refused to perform an update (quick exit for unsupported + combinations of input sizes) + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool spchol_updatekernelabc4_dispatcher(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t urank, + ae_int_t urowstride, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + _ALGLIB_KERNELSAVE_RETURN_AVX2_FMA(spchol_updatekernelabc4,(rowstorage, offss, twidth, offsu, uheight, urank, urowstride, uwidth, diagd, offsd, raw2smap, superrowidx, urbase, _state)) + + /* + * Generic code + */ + ae_int_t k; + ae_int_t targetrow; + ae_int_t targetcol; + ae_int_t offsk; + double d0; + double d1; + double d2; + double d3; + double u00; + double u01; + double u02; + double u03; + double u10; + double u11; + double u12; + double u13; + double u20; + double u21; + double u22; + double u23; + double u30; + double u31; + double u32; + double u33; + double uk0; + double uk1; + double uk2; + double uk3; + ae_int_t srccol0; + ae_int_t srccol1; + ae_int_t srccol2; + ae_int_t srccol3; + ae_bool result; + + + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + result = ae_false; + if( twidth<3||twidth>4 ) + { + return result; + } + if( uwidth<1||uwidth>4 ) + { + return result; + } + if( urank>4 ) + { + return result; + } + + /* + * Determine source columns for target columns, -1 if target column + * is not updated. + */ + srccol0 = -1; + srccol1 = -1; + srccol2 = -1; + srccol3 = -1; + for(k=0; k<=uwidth-1; k++) + { + targetcol = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]; + if( targetcol==0 ) + { + srccol0 = k; + } + if( targetcol==1 ) + { + srccol1 = k; + } + if( targetcol==2 ) + { + srccol2 = k; + } + if( targetcol==3 ) + { + srccol3 = k; + } + } + + /* + * Load update matrix into aligned/rearranged 4x4 storage + */ + d0 = (double)(0); + d1 = (double)(0); + d2 = (double)(0); + d3 = (double)(0); + u00 = (double)(0); + u01 = (double)(0); + u02 = (double)(0); + u03 = (double)(0); + u10 = (double)(0); + u11 = (double)(0); + u12 = (double)(0); + u13 = (double)(0); + u20 = (double)(0); + u21 = (double)(0); + u22 = (double)(0); + u23 = (double)(0); + u30 = (double)(0); + u31 = (double)(0); + u32 = (double)(0); + u33 = (double)(0); + if( urank>=1 ) + { + d0 = diagd->ptr.p_double[offsd+0]; + } + if( urank>=2 ) + { + d1 = diagd->ptr.p_double[offsd+1]; + } + if( urank>=3 ) + { + d2 = diagd->ptr.p_double[offsd+2]; + } + if( urank>=4 ) + { + d3 = diagd->ptr.p_double[offsd+3]; + } + if( srccol0>=0 ) + { + if( urank>=1 ) + { + u00 = d0*rowstorage->ptr.p_double[offsu+srccol0*urowstride+0]; + } + if( urank>=2 ) + { + u01 = d1*rowstorage->ptr.p_double[offsu+srccol0*urowstride+1]; + } + if( urank>=3 ) + { + u02 = d2*rowstorage->ptr.p_double[offsu+srccol0*urowstride+2]; + } + if( urank>=4 ) + { + u03 = d3*rowstorage->ptr.p_double[offsu+srccol0*urowstride+3]; + } + } + if( srccol1>=0 ) + { + if( urank>=1 ) + { + u10 = d0*rowstorage->ptr.p_double[offsu+srccol1*urowstride+0]; + } + if( urank>=2 ) + { + u11 = d1*rowstorage->ptr.p_double[offsu+srccol1*urowstride+1]; + } + if( urank>=3 ) + { + u12 = d2*rowstorage->ptr.p_double[offsu+srccol1*urowstride+2]; + } + if( urank>=4 ) + { + u13 = d3*rowstorage->ptr.p_double[offsu+srccol1*urowstride+3]; + } + } + if( srccol2>=0 ) + { + if( urank>=1 ) + { + u20 = d0*rowstorage->ptr.p_double[offsu+srccol2*urowstride+0]; + } + if( urank>=2 ) + { + u21 = d1*rowstorage->ptr.p_double[offsu+srccol2*urowstride+1]; + } + if( urank>=3 ) + { + u22 = d2*rowstorage->ptr.p_double[offsu+srccol2*urowstride+2]; + } + if( urank>=4 ) + { + u23 = d3*rowstorage->ptr.p_double[offsu+srccol2*urowstride+3]; + } + } + if( srccol3>=0 ) + { + if( urank>=1 ) + { + u30 = d0*rowstorage->ptr.p_double[offsu+srccol3*urowstride+0]; + } + if( urank>=2 ) + { + u31 = d1*rowstorage->ptr.p_double[offsu+srccol3*urowstride+1]; + } + if( urank>=3 ) + { + u32 = d2*rowstorage->ptr.p_double[offsu+srccol3*urowstride+2]; + } + if( urank>=4 ) + { + u33 = d3*rowstorage->ptr.p_double[offsu+srccol3*urowstride+3]; + } + } + + /* + * Run update + */ + if( urank==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0; + } + } + if( urank==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1; + } + } + if( urank==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2; + } + } + if( urank==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + uk3 = rowstorage->ptr.p_double[offsk+3]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2-u03*uk3; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2-u13*uk3; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2-u23*uk3; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2-u33*uk3; + } + } + result = ae_true; + return result; +} +ae_bool (*spchol_updatekernelabc4)(ae_vector*,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,const ae_vector*,ae_int_t,const ae_vector*,const ae_vector*,ae_int_t,ae_state*) = spchol_updatekernelabc4_dispatcher; + +/************************************************************************* +Fast kernels for small supernodal updates: special 4x4x4x4 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs 4x4x4x4 update, i.e.: +* S is a tHeight*4 matrix +* U is a uHeight*4 matrix +* Uc' is a 4*4 matrix +* scatter() scatters rows of U*Uc', but does not scatter columns (they are + densely packed). + +Return value: +* True if update was applied +* False if kernel refused to perform an update. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool spchol_updatekernel4444(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + ae_int_t offsk; + double d0; + double d1; + double d2; + double d3; + double u00; + double u01; + double u02; + double u03; + double u10; + double u11; + double u12; + double u13; + double u20; + double u21; + double u22; + double u23; + double u30; + double u31; + double u32; + double u33; + double uk0; + double uk1; + double uk2; + double uk3; + ae_bool result; + + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + _ALGLIB_KERNEL_RETURN_AVX2_FMA(spchol_updatekernel4444,(rowstorage->ptr.p_double, offss, sheight, offsu, uheight, diagd->ptr.p_double, offsd, raw2smap->ptr.p_int, superrowidx->ptr.p_int, urbase, _state)) + + /* + * Generic C fallback code + */ + d0 = diagd->ptr.p_double[offsd+0]; + d1 = diagd->ptr.p_double[offsd+1]; + d2 = diagd->ptr.p_double[offsd+2]; + d3 = diagd->ptr.p_double[offsd+3]; + u00 = d0*rowstorage->ptr.p_double[offsu+0*4+0]; + u01 = d1*rowstorage->ptr.p_double[offsu+0*4+1]; + u02 = d2*rowstorage->ptr.p_double[offsu+0*4+2]; + u03 = d3*rowstorage->ptr.p_double[offsu+0*4+3]; + u10 = d0*rowstorage->ptr.p_double[offsu+1*4+0]; + u11 = d1*rowstorage->ptr.p_double[offsu+1*4+1]; + u12 = d2*rowstorage->ptr.p_double[offsu+1*4+2]; + u13 = d3*rowstorage->ptr.p_double[offsu+1*4+3]; + u20 = d0*rowstorage->ptr.p_double[offsu+2*4+0]; + u21 = d1*rowstorage->ptr.p_double[offsu+2*4+1]; + u22 = d2*rowstorage->ptr.p_double[offsu+2*4+2]; + u23 = d3*rowstorage->ptr.p_double[offsu+2*4+3]; + u30 = d0*rowstorage->ptr.p_double[offsu+3*4+0]; + u31 = d1*rowstorage->ptr.p_double[offsu+3*4+1]; + u32 = d2*rowstorage->ptr.p_double[offsu+3*4+2]; + u33 = d3*rowstorage->ptr.p_double[offsu+3*4+3]; + if( sheight==uheight ) + { + /* + * No row scatter, the most efficient code + */ + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+k*4; + offsk = offsu+k*4; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + uk3 = rowstorage->ptr.p_double[offsk+3]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2-u03*uk3; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2-u13*uk3; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2-u23*uk3; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2-u33*uk3; + } + } + else + { + /* + * Row scatter is performed, less efficient code using double mapping to determine target row index + */ + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*4; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + uk3 = rowstorage->ptr.p_double[offsk+3]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2-u03*uk3; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2-u13*uk3; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2-u23*uk3; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2-u33*uk3; + } + } + result = ae_true; + return result; +} + +ae_bool rbfv3farfields_bhpaneleval1fastkernel(double d0, + double d1, + double d2, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state) +{ + /* + * Only panelp=15 is supported + */ + if( panelp!=15 ) + return ae_false; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + _ALGLIB_KERNEL_RETURN_AVX2(rbfv3farfields_bhpaneleval1fastkernel16,(d0,d1,d2,pnma->ptr.p_double,pnmb->ptr.p_double,pmmcdiag->ptr.p_double,ynma->ptr.p_double,tblrmodmn->ptr.p_double,f,invpowrpplus1,_state)) + + /* + * No fast kernels, no generic C implementation + */ + return ae_false; +} + +ae_bool rbfv3farfields_bhpanelevalfastkernel(double d0, + double d1, + double d2, + ae_int_t ny, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + /* Real */ ae_vector* f, + double* invpowrpplus1, + ae_state *_state) +{ + /* + * Only panelp=15 is supported + */ + if( panelp!=15 ) + return ae_false; + + /* + * Try fast kernels. + * On success this macro will return, on failure to find kernel it will pass execution to the generic C implementation + */ + _ALGLIB_KERNEL_RETURN_AVX2(rbfv3farfields_bhpanelevalfastkernel16,(d0,d1,d2,ny,pnma->ptr.p_double,pnmb->ptr.p_double,pmmcdiag->ptr.p_double,ynma->ptr.p_double,tblrmodmn->ptr.p_double,f->ptr.p_double,invpowrpplus1,_state)) + + /* + * No fast kernels, no generic C implementation + */ + return ae_false; +} + +/* ALGLIB_NO_FAST_KERNELS */ +#endif + + +} + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS PARALLEL SUBROUTINES +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ + + + +ae_int_t ae_cores_count() +{ + return 0; +} + + +} + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS CORE FUNCTIONS TRANSLATED FROM ALGOPASCAL +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ + + +/************************************************************************* +This function checks that length(X) is at least N and first N values from +X[] are finite + + -- ALGLIB -- + Copyright 18.06.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool isfinitevector(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_bool result; + + + ae_assert(n>=0, "APSERVIsFiniteVector: internal error (N<0)", _state); + if( n==0 ) + { + result = ae_true; + return result; + } + if( x->cntptr.p_double[i]; + } + result = ae_isfinite(v, _state); + return result; +} + + +/************************************************************************* +Integer case-2: returns V0 if Cond=True, V1 otherwise +*************************************************************************/ +ae_int_t icase2(ae_bool cond, ae_int_t v0, ae_int_t v1, ae_state *_state) +{ + ae_int_t result; + + + if( cond ) + { + result = v0; + } + else + { + result = v1; + } + return result; +} + + +/************************************************************************* +Binary search in an integer array. If an element is present twice or more, +returns the leftmost one. If the element is not present, returns position +where this element can be inserted. + +The range [I0,I1) is searched. + + -- ALGLIB -- + Copyright 11.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t ibinarysearchlft(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state) +{ + ae_int_t m; + ae_int_t result; + + + while(i0ptr.p_int[m]ptr.p_double[j] = v; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Sets vector X[] to V + +INPUT PARAMETERS: + N - vector length + V - value to set + X - array[N] + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void isetv(ae_int_t n, + ae_int_t v, + /* Integer */ ae_vector* x, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + x->ptr.p_int[j] = v; + } +} +#endif + + +/************************************************************************* +Sets vector X[] to V, reallocating X[] if too small + +INPUT PARAMETERS: + N - vector length + V - value to set + X - possibly preallocated array + +OUTPUT PARAMETERS: + X - leading N elements are replaced by V; array is reallocated + if its length is less than N. + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rsetallocv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state) +{ + + + if( x->cnt=N + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rallocv(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state) +{ + + + if( x->cnt=N + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void iallocv(ae_int_t n, /* Integer */ ae_vector* x, ae_state *_state) +{ + + + if( x->cntcntptr.p_double[j] = x->ptr.p_double[j]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies vector X[] to Y[] + +INPUT PARAMETERS: + N - vector length + X - array[N], source + Y - preallocated array[N] + +OUTPUT PARAMETERS: + Y - leading N elements are replaced by X + + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void bcopyv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + y->ptr.p_bool[j] = x->ptr.p_bool[j]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies vector X[] to Y[], extended version + +INPUT PARAMETERS: + N - vector length + X - source array + OffsX - source offset + Y - preallocated array[N] + OffsY - destination offset + +OUTPUT PARAMETERS: + Y - N elements starting from OffsY are replaced by X[OffsX:OffsX+N-1] + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyvx(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t offsx, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + y->ptr.p_double[offsy+j] = x->ptr.p_double[offsx+j]; + } +} +#endif + + +/************************************************************************* +Copies vector X[] to Y[], resizing Y[] if needed. + +INPUT PARAMETERS: + N - vector length + X - array[N], source + Y - possibly preallocated array[N] (resized if needed) + +OUTPUT PARAMETERS: + Y - leading N elements are replaced by X + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rcopyallocv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + if( y->cntcntptr.p_int[j] = x->ptr.p_int[j]; + } +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Copies vector X[] to Y[], extended version + +INPUT PARAMETERS: + N - vector length + X - source array + OffsX - source offset + Y - preallocated array[N] + OffsY - destination offset + +OUTPUT PARAMETERS: + Y - N elements starting from OffsY are replaced by X[OffsX:OffsX+N-1] + +NOTE: destination and source should NOT overlap + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void icopyvx(ae_int_t n, + /* Integer */ const ae_vector* x, + ae_int_t offsx, + /* Integer */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t j; + + + for(j=0; j<=n-1; j++) + { + y->ptr.p_int[offsy+j] = x->ptr.p_int[offsx+j]; + } +} +#endif + + +/************************************************************************* +Grows X, i.e. changes its size in such a way that: +a) contents is preserved +b) new size is at least N +c) actual size can be larger than N, so subsequent grow() calls can return + without reallocation + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void igrowv(ae_int_t newn, /* Integer */ ae_vector* x, ae_state *_state) +{ + + + + /* + * If no growth is required, exit. Call worker function otherwise. + * + * The idea is that we call function which works with dynamic arrays + * (and utilizes stack unwinding) only when absolutely necessary. + */ + if( x->cnt>=newn ) + { + return; + } + ablasf_igrowvinternal(newn, x, _state); +} + + +/************************************************************************* +Grows X, i.e. changes its size in such a way that: +a) contents is preserved +b) new size is at least N +c) actual size can be larger than N, so subsequent grow() calls can return + without reallocation + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void bgrowv(ae_int_t newn, /* Boolean */ ae_vector* x, ae_state *_state) +{ + + + + /* + * If no growth is required, exit. Call worker function otherwise. + * + * The idea is that we call function which works with dynamic arrays + * (and utilizes stack unwinding) only when absolutely necessary. + */ + if( x->cnt>=newn ) + { + return; + } + ablasf_bgrowvinternal(newn, x, _state); +} + + +/************************************************************************* +Grows X, i.e. changes its size in such a way that: +a) contents is preserved +b) new size is at least N +c) actual size can be larger than N, so subsequent grow() calls can return + without reallocation + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void rgrowv(ae_int_t newn, /* Real */ ae_vector* x, ae_state *_state) +{ + + + + /* + * If no growth is required, exit. Call worker function otherwise. + * + * The idea is that we call function which works with dynamic arrays + * (and utilizes stack unwinding) only when absolutely necessary. + */ + if( x->cnt>=newn ) + { + return; + } + ablasf_rgrowvinternal(newn, x, _state); +} + + +/************************************************************************* +Grows X by calling rGrowV() and sets the element X[NewN-1] to the specified +value + + -- ALGLIB -- + Copyright 07.09.2024 by Bochkanov Sergey +*************************************************************************/ +void rgrowappendv(ae_int_t newn, + /* Real */ ae_vector* x, + double v, + ae_state *_state) +{ + + + rgrowv(newn, x, _state); + x->ptr.p_double[newn-1] = v; +} + + +/************************************************************************* +Grows X by calling iGrowV() and sets the element X[NewN-1] to the specified +value + + -- ALGLIB -- + Copyright 07.09.2024 by Bochkanov Sergey +*************************************************************************/ +void igrowappendv(ae_int_t newn, + /* Integer */ ae_vector* x, + ae_int_t v, + ae_state *_state) +{ + + + igrowv(newn, x, _state); + x->ptr.p_int[newn-1] = v; +} + + +/************************************************************************* +Grows X by calling bGrowV() and sets the element X[NewN-1] to the specified +value + + -- ALGLIB -- + Copyright 07.09.2024 by Bochkanov Sergey +*************************************************************************/ +void bgrowappendv(ae_int_t newn, + /* Boolean */ ae_vector* x, + ae_bool v, + ae_state *_state) +{ + + + bgrowv(newn, x, _state); + x->ptr.p_bool[newn-1] = v; +} + + +/************************************************************************* +Internal function that actually works with dynamic arrays. + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void ablasf_igrowvinternal(ae_int_t newn, + /* Integer */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t oldn; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_INT, _state, ae_true); + + if( x->cnt>=newn ) + { + ae_frame_leave(_state); + return; + } + oldn = x->cnt; + newn = ae_maxint(newn, ae_round(1.8*(double)oldn+(double)1, _state), _state); + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, newn, _state); + icopyv(oldn, &oldx, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal function that actually works with dynamic arrays. + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void ablasf_bgrowvinternal(ae_int_t newn, + /* Boolean */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t oldn; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_BOOL, _state, ae_true); + + if( x->cnt>=newn ) + { + ae_frame_leave(_state); + return; + } + oldn = x->cnt; + newn = ae_maxint(newn, ae_round(1.8*(double)oldn+(double)1, _state), _state); + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, newn, _state); + bcopyv(oldn, &oldx, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal function which actually works with dynamic arrays + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void ablasf_rgrowvinternal(ae_int_t newn, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldx; + ae_int_t oldn; + + ae_frame_make(_state, &_frame_block); + memset(&oldx, 0, sizeof(oldx)); + ae_vector_init(&oldx, 0, DT_REAL, _state, ae_true); + + if( x->cnt>=newn ) + { + ae_frame_leave(_state); + return; + } + oldn = x->cnt; + newn = ae_maxint(newn, ae_round(1.8*(double)oldn+(double)1, _state), _state); + ae_swap_vectors(x, &oldx); + ae_vector_set_length(x, newn, _state); + rcopyv(oldn, &oldx, x, _state); + ae_frame_leave(_state); +} + + + + +/************************************************************************* +Sorting function optimized for integer keys and real labels, can be used +to sort middle of the array + +A is sorted, and same permutations are applied to B. + +NOTES: + this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void tagsortmiddleir(/* Integer */ ae_vector* a, + /* Real */ ae_vector* b, + ae_int_t offset, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + ae_int_t tmp; + double tmpr; + ae_int_t p0; + ae_int_t p1; + ae_int_t at; + ae_int_t ak; + ae_int_t ak1; + double bt; + ae_bool isascending; + + + + /* + * Special cases + */ + if( n<=1 ) + { + return; + } + isascending = ae_true; + for(i=1; i<=n-1; i++) + { + isascending = isascending&&a->ptr.p_int[offset+i]>=a->ptr.p_int[offset+i-1]; + } + if( isascending ) + { + return; + } + + /* + * General case, N>1: sort, update B + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_int[p0]; + at = a->ptr.p_int[p1]; + if( ak>=at ) + { + break; + } + a->ptr.p_int[p0] = at; + a->ptr.p_int[p1] = ak; + tmpr = b->ptr.p_double[p0]; + b->ptr.p_double[p0] = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = tmpr; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmp = a->ptr.p_int[p1]; + a->ptr.p_int[p1] = a->ptr.p_int[p0]; + a->ptr.p_int[p0] = tmp; + at = tmp; + tmpr = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = b->ptr.p_double[p0]; + b->ptr.p_double[p0] = tmpr; + bt = tmpr; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_int[p1]; + if( k+1ptr.p_int[p1+1]; + if( ak1>ak ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( at>=ak ) + { + break; + } + a->ptr.p_int[p1] = at; + a->ptr.p_int[p0] = ak; + b->ptr.p_double[p0] = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = bt; + t = k; + } + } +} + + +/************************************************************************* +Sorting function optimized for integer keys and real labels, can be used +to sort middle of the array + +A is sorted, and same permutations are applied to B and C. + +Elements beyond [offs:offs+N-1] are not modified or referenced. + +NOTES: + this function assumes that A[] is finite; it doesn't checks that + condition. All other conditions (size of input arrays, etc.) are not + checked too. + + -- ALGLIB -- + Copyright 11.12.2024 by Bochkanov Sergey +*************************************************************************/ +void tagsortmiddleirr(/* Integer */ ae_vector* a, + /* Real */ ae_vector* b, + /* Real */ ae_vector* c, + ae_int_t offset, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + ae_int_t tmp; + double tmpr; + double tmpr2; + ae_int_t p0; + ae_int_t p1; + ae_int_t at; + ae_int_t ak; + ae_int_t ak1; + double bt; + double ct; + + + + /* + * Special cases + */ + if( n<=1 ) + { + return; + } + + /* + * General case, N>1: sort, update B and C + */ + for(i=2; i<=n; i++) + { + t = i; + while(t!=1) + { + k = t/2; + p0 = offset+k-1; + p1 = offset+t-1; + ak = a->ptr.p_int[p0]; + at = a->ptr.p_int[p1]; + if( ak>=at ) + { + break; + } + a->ptr.p_int[p0] = at; + a->ptr.p_int[p1] = ak; + tmpr = b->ptr.p_double[p0]; + b->ptr.p_double[p0] = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = tmpr; + tmpr2 = c->ptr.p_double[p0]; + c->ptr.p_double[p0] = c->ptr.p_double[p1]; + c->ptr.p_double[p1] = tmpr2; + t = k; + } + } + for(i=n-1; i>=1; i--) + { + p0 = offset+0; + p1 = offset+i; + tmp = a->ptr.p_int[p1]; + a->ptr.p_int[p1] = a->ptr.p_int[p0]; + a->ptr.p_int[p0] = tmp; + at = tmp; + tmpr = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = b->ptr.p_double[p0]; + b->ptr.p_double[p0] = tmpr; + bt = tmpr; + tmpr2 = c->ptr.p_double[p1]; + c->ptr.p_double[p1] = c->ptr.p_double[p0]; + c->ptr.p_double[p0] = tmpr2; + ct = tmpr2; + t = 0; + for(;;) + { + k = 2*t+1; + if( k+1>i ) + { + break; + } + p0 = offset+t; + p1 = offset+k; + ak = a->ptr.p_int[p1]; + if( k+1ptr.p_int[p1+1]; + if( ak1>ak ) + { + ak = ak1; + p1 = p1+1; + k = k+1; + } + } + if( at>=ak ) + { + break; + } + a->ptr.p_int[p1] = at; + a->ptr.p_int[p0] = ak; + b->ptr.p_double[p0] = b->ptr.p_double[p1]; + b->ptr.p_double[p1] = bt; + c->ptr.p_double[p0] = c->ptr.p_double[p1]; + c->ptr.p_double[p1] = ct; + t = k; + } + } +} + + + + +void _sparsematrix_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sparsematrix *p = (sparsematrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->vals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->didx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->uidx, 0, DT_INT, _state, make_automatic); +} + + +void _sparsematrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sparsematrix *dst = (sparsematrix*)_dst; + const sparsematrix *src = (const sparsematrix*)_src; + ae_vector_init_copy(&dst->vals, &src->vals, _state, make_automatic); + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->ridx, &src->ridx, _state, make_automatic); + ae_vector_init_copy(&dst->didx, &src->didx, _state, make_automatic); + ae_vector_init_copy(&dst->uidx, &src->uidx, _state, make_automatic); + dst->matrixtype = src->matrixtype; + dst->m = src->m; + dst->n = src->n; + dst->nfree = src->nfree; + dst->ninitialized = src->ninitialized; + dst->tablesize = src->tablesize; +} + + +void _sparsematrix_clear(void* _p) +{ + sparsematrix *p = (sparsematrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->vals); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->ridx); + ae_vector_clear(&p->didx); + ae_vector_clear(&p->uidx); +} + + +void _sparsematrix_destroy(void* _p) +{ + sparsematrix *p = (sparsematrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->vals); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->ridx); + ae_vector_destroy(&p->didx); + ae_vector_destroy(&p->uidx); +} + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. + +The empty matrix is a degenerate 0*N-dimensional matrix which can be used +ONLY for: +* appending rows with sparseappendcompressedrow() +* appending non-degenerate CRS matrices with sparseappendmatrix() +Before the first row is appended, the matrix is in a special intermediate +state. After the first append it becomes a standard CRS matrix. + +The main purpose of this function is to simplify step-by-step initialization +of CRS matrices. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSEmptyBuf function. + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsempty(ae_int_t n, sparsematrix* s, ae_state *_state) +{ + + _sparsematrix_clear(s); + + ae_assert(n>0, "SparseCreateCRSEmpty: N<=0", _state); + sparsecreatecrsemptybuf(n, s, _state); +} + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. It +is a buffered version of the function which reuses previosly allocated +space as much as possible. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsemptybuf(ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + + + ae_assert(n>0, "SparseCreateCRSEmptyBuf: N<=0", _state); + s->matrixtype = -10083; + s->ninitialized = 0; + s->m = 0; + s->n = n; + isetallocv(1, 0, &s->ridx, _state); +} + + +/************************************************************************* +This function creates a sparse CRS-based matrix from subset of rows of +another CRS-based matrix. Memory already present in Dst is reused as much +as possible. + +INPUT PARAMETERS: + Src - sparse M*N matrix in CRS format. + R0, R1 - half-range of rows to use, [R0,R1) + +OUTPUT PARAMETERS: + Dst - (R1-R0)*N matrix in the CRS format, subset of Src + + -- ALGLIB PROJECT -- + Copyright 2024.03.23 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromcrsrangebuf(const sparsematrix* src, + ae_int_t r0, + ae_int_t r1, + sparsematrix* dst, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + + + ae_assert(src->matrixtype==1, "SparseCreateCRSFromCRSRangeBuf: Src must be CRS-based matrix", _state); + ae_assert(src->ninitialized==src->ridx.ptr.p_int[src->m], "SparseCreateCRSFromCRSRangeBuf: Src is not completely initialized", _state); + ae_assert(r0=0&&r0m, "SparseCreateCRSFromCRSRangeBuf: half-range [R0,R1) is not a subset of [0,Src.M)", _state); + + /* + * Append the source + */ + m = r1-r0; + igrowv(m, &dst->didx, _state); + igrowv(m, &dst->uidx, _state); + igrowv(m+1, &dst->ridx, _state); + igrowv(src->ridx.ptr.p_int[r1]-src->ridx.ptr.p_int[r0], &dst->idx, _state); + rgrowv(src->ridx.ptr.p_int[r1]-src->ridx.ptr.p_int[r0], &dst->vals, _state); + icopyvx(src->ridx.ptr.p_int[r1]-src->ridx.ptr.p_int[r0], &src->idx, src->ridx.ptr.p_int[r0], &dst->idx, 0, _state); + rcopyvx(src->ridx.ptr.p_int[r1]-src->ridx.ptr.p_int[r0], &src->vals, src->ridx.ptr.p_int[r0], &dst->vals, 0, _state); + dst->ridx.ptr.p_int[0] = 0; + for(i=0; i<=m-1; i++) + { + dst->ridx.ptr.p_int[i+1] = dst->ridx.ptr.p_int[i]+(src->ridx.ptr.p_int[r0+i+1]-src->ridx.ptr.p_int[r0+i]); + dst->didx.ptr.p_int[i] = ibinarysearchlft(&dst->idx, dst->ridx.ptr.p_int[i], dst->ridx.ptr.p_int[i+1], i, _state); + dst->uidx.ptr.p_int[i] = dst->didx.ptr.p_int[i]+icase2(dst->didx.ptr.p_int[i]ridx.ptr.p_int[i+1]&&dst->idx.ptr.p_int[dst->didx.ptr.p_int[i]]==i, 1, 0, _state); + } + + /* + * Finalize the destination matrix + */ + dst->matrixtype = 1; + dst->n = src->n; + dst->m = m; + dst->ninitialized = dst->ridx.ptr.p_int[m]; +} + + +/************************************************************************* +This function copies S0 to S1. +Memory already allocated in S1 is reused as much as possible. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopybuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + + s1->matrixtype = s0->matrixtype; + s1->m = s0->m; + s1->n = s0->n; + s1->nfree = s0->nfree; + s1->ninitialized = s0->ninitialized; + s1->tablesize = s0->tablesize; + + /* + * Initialization for arrays + */ + icopyallocv(s0->ridx.cnt, &s0->ridx, &s1->ridx, _state); + icopyallocv(s0->idx.cnt, &s0->idx, &s1->idx, _state); + rcopyallocv(s0->vals.cnt, &s0->vals, &s1->vals, _state); + + /* + * Initalization for CRS-parameters + */ + icopyallocv(s0->didx.cnt, &s0->didx, &s1->didx, _state); + icopyallocv(s0->uidx.cnt, &s0->uidx, &s1->uidx, _state); +} + + +/************************************************************************* +Procedure for initialization 'S.DIdx' and 'S.UIdx' + + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseinitduidx(sparsematrix* s, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t lt; + ae_int_t rt; + + + ae_assert(s->matrixtype==1, "SparseInitDUIdx: internal error, incorrect matrix type", _state); + iallocv(s->m, &s->didx, _state); + iallocv(s->m, &s->uidx, _state); + for(i=0; i<=s->m-1; i++) + { + s->uidx.ptr.p_int[i] = -1; + s->didx.ptr.p_int[i] = -1; + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(j=lt; j<=rt-1; j++) + { + k = s->idx.ptr.p_int[j]; + if( k==i ) + { + s->didx.ptr.p_int[i] = j; + } + else + { + if( k>i&&s->uidx.ptr.p_int[i]==-1 ) + { + s->uidx.ptr.p_int[i] = j; + break; + } + } + } + if( s->uidx.ptr.p_int[i]==-1 ) + { + s->uidx.ptr.p_int[i] = s->ridx.ptr.p_int[i+1]; + } + if( s->didx.ptr.p_int[i]==-1 ) + { + s->didx.ptr.p_int[i] = s->uidx.ptr.p_int[i]; + } + } +} + + +/************************************************************************* +This function appends from below a sparse CRS-based matrix to another +sparse CRS-based matrix. The matrix being appended must be completely +initialized CRS matrix. + +INPUT PARAMETERS: + SDst - sparse X*N matrix in CRS format, including one created + with sparsecreatecrsempty (in the latter case, X=0). + SSrc - sparse M*N matrix in the CRS format + +OUTPUT PARAMETERS: + SDst - (X+M)*N matrix in the CRS format, SSrc appended from + below + +NOTE: this function has amortized O(MSrc+NZCnt) cost, where NZCnt is a + total number of nonzero elements in SSrc. + + -- ALGLIB PROJECT -- + Copyright 2024.03.23 by Bochkanov Sergey +*************************************************************************/ +void sparseappendmatrix(sparsematrix* sdst, + const sparsematrix* ssrc, + ae_state *_state) +{ + ae_int_t msrc; + ae_int_t mdst; + ae_int_t i; + + + ae_assert(sdst->matrixtype==1||sdst->matrixtype==-10083, "SparseAppendMatrix: SDst must be CRS-based matrix", _state); + ae_assert(sdst->ninitialized==sdst->ridx.ptr.p_int[sdst->m], "SparseAppendMatrix: SDst is not completely initialized", _state); + ae_assert(ssrc->matrixtype==1, "SparseAppendMatrix: SSrc must be CRS-based matrix", _state); + ae_assert(ssrc->ninitialized==ssrc->ridx.ptr.p_int[ssrc->m], "SparseAppendMatrix: SSrc is not completely initialized", _state); + + /* + * Append the source + */ + mdst = sdst->m; + msrc = ssrc->m; + igrowv(mdst+msrc, &sdst->didx, _state); + igrowv(mdst+msrc, &sdst->uidx, _state); + igrowv(mdst+msrc+1, &sdst->ridx, _state); + igrowv(sdst->ridx.ptr.p_int[mdst]+ssrc->ridx.ptr.p_int[msrc], &sdst->idx, _state); + rgrowv(sdst->ridx.ptr.p_int[mdst]+ssrc->ridx.ptr.p_int[msrc], &sdst->vals, _state); + icopyvx(ssrc->ridx.ptr.p_int[msrc], &ssrc->idx, 0, &sdst->idx, sdst->ridx.ptr.p_int[mdst], _state); + rcopyvx(ssrc->ridx.ptr.p_int[msrc], &ssrc->vals, 0, &sdst->vals, sdst->ridx.ptr.p_int[mdst], _state); + for(i=0; i<=msrc-1; i++) + { + sdst->ridx.ptr.p_int[mdst+i+1] = sdst->ridx.ptr.p_int[mdst+i]+(ssrc->ridx.ptr.p_int[i+1]-ssrc->ridx.ptr.p_int[i]); + sdst->didx.ptr.p_int[mdst+i] = ibinarysearchlft(&sdst->idx, sdst->ridx.ptr.p_int[mdst+i], sdst->ridx.ptr.p_int[mdst+i+1], mdst+i, _state); + sdst->uidx.ptr.p_int[mdst+i] = sdst->didx.ptr.p_int[mdst+i]+icase2(sdst->didx.ptr.p_int[mdst+i]ridx.ptr.p_int[mdst+i+1]&&sdst->idx.ptr.p_int[sdst->didx.ptr.p_int[mdst+i]]==mdst+i, 1, 0, _state); + } + + /* + * Finalize the destination matrix + */ + sdst->matrixtype = 1; + sdst->m = mdst+msrc; + sdst->ninitialized = sdst->ridx.ptr.p_int[mdst+msrc]; +} + + +/************************************************************************* +This function converts matrix to CRS format. + +Some algorithms (linear algebra ones, for example) require matrices in +CRS format. This function allows to perform in-place conversion. + +INPUT PARAMETERS + S - sparse M*N matrix in any format + +OUTPUT PARAMETERS + S - matrix in CRS format + +NOTE: this function has no effect when called with matrix which is + already in CRS mode. + +NOTE: this function allocates temporary memory to store a copy of the + matrix. If you perform a lot of repeated conversions, we recommend + you to use SparseCopyToCRSBuf() function, which can reuse + previously allocated memory. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseconverttocrs(sparsematrix* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_vector tvals; + ae_vector tidx; + ae_vector temp; + ae_vector tridx; + ae_int_t nonne; + ae_int_t k; + ae_int_t offs0; + ae_int_t offs1; + + ae_frame_make(_state, &_frame_block); + memset(&tvals, 0, sizeof(tvals)); + memset(&tidx, 0, sizeof(tidx)); + memset(&temp, 0, sizeof(temp)); + memset(&tridx, 0, sizeof(tridx)); + ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&temp, 0, DT_INT, _state, ae_true); + ae_vector_init(&tridx, 0, DT_INT, _state, ae_true); + + m = s->m; + if( s->matrixtype==0 ) + { + + /* + * From Hash-table to CRS. + * First, create local copy of the hash table. + */ + s->matrixtype = 1; + k = s->tablesize; + ae_swap_vectors(&s->vals, &tvals); + ae_swap_vectors(&s->idx, &tidx); + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + nonne = 0; + isetallocv(s->m+1, 0, &s->ridx, _state); + for(i=0; i<=k-1; i++) + { + if( tidx.ptr.p_int[2*i]>=0 ) + { + s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1] = s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1]+1; + nonne = nonne+1; + } + } + for(i=0; i<=s->m-1; i++) + { + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; + } + s->ninitialized = s->ridx.ptr.p_int[s->m]; + + /* + * Allocate memory and move elements to Vals/Idx. + * Initially, elements are sorted by rows, but unsorted within row. + * After initial insertion we sort elements within row. + */ + ae_vector_set_length(&temp, s->m, _state); + for(i=0; i<=s->m-1; i++) + { + temp.ptr.p_int[i] = 0; + } + rallocv(nonne, &s->vals, _state); + iallocv(nonne, &s->idx, _state); + for(i=0; i<=k-1; i++) + { + if( tidx.ptr.p_int[2*i]>=0 ) + { + s->vals.ptr.p_double[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tvals.ptr.p_double[i]; + s->idx.ptr.p_int[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tidx.ptr.p_int[2*i+1]; + temp.ptr.p_int[tidx.ptr.p_int[2*i]] = temp.ptr.p_int[tidx.ptr.p_int[2*i]]+1; + } + } + for(i=0; i<=s->m-1; i++) + { + tagsortmiddleir(&s->idx, &s->vals, s->ridx.ptr.p_int[i], s->ridx.ptr.p_int[i+1]-s->ridx.ptr.p_int[i], _state); + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s, _state); + ae_frame_leave(_state); + return; + } + if( s->matrixtype==1 ) + { + + /* + * Already CRS + */ + ae_frame_leave(_state); + return; + } + if( s->matrixtype==2 ) + { + ae_assert(s->m==s->n, "SparseConvertToCRS: non-square SKS matrices are not supported", _state); + + /* + * From SKS to CRS. + * + * First, create local copy of the SKS matrix (Vals, + * Idx, RIdx are stored; DIdx/UIdx for some time are + * left in the SparseMatrix structure). + */ + s->matrixtype = 1; + ae_swap_vectors(&s->vals, &tvals); + ae_swap_vectors(&s->idx, &tidx); + ae_swap_vectors(&s->ridx, &tridx); + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + iallocv(m+1, &s->ridx, _state); + s->ridx.ptr.p_int[0] = 0; + for(i=1; i<=m; i++) + { + s->ridx.ptr.p_int[i] = 1; + } + nonne = 0; + for(i=0; i<=m-1; i++) + { + s->ridx.ptr.p_int[i+1] = s->didx.ptr.p_int[i]+s->ridx.ptr.p_int[i+1]; + for(j=i-s->uidx.ptr.p_int[i]; j<=i-1; j++) + { + s->ridx.ptr.p_int[j+1] = s->ridx.ptr.p_int[j+1]+1; + } + nonne = nonne+s->didx.ptr.p_int[i]+1+s->uidx.ptr.p_int[i]; + } + for(i=0; i<=s->m-1; i++) + { + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; + } + s->ninitialized = s->ridx.ptr.p_int[s->m]; + + /* + * Allocate memory and move elements to Vals/Idx. + * Initially, elements are sorted by rows, and are sorted within row too. + * No additional post-sorting is required. + */ + isetallocv(m, 0, &temp, _state); + rallocv(nonne, &s->vals, _state); + iallocv(nonne, &s->idx, _state); + for(i=0; i<=m-1; i++) + { + + /* + * copy subdiagonal and diagonal parts of I-th block + */ + offs0 = tridx.ptr.p_int[i]; + offs1 = s->ridx.ptr.p_int[i]+temp.ptr.p_int[i]; + k = s->didx.ptr.p_int[i]+1; + for(j=0; j<=k-1; j++) + { + s->vals.ptr.p_double[offs1+j] = tvals.ptr.p_double[offs0+j]; + s->idx.ptr.p_int[offs1+j] = i-s->didx.ptr.p_int[i]+j; + } + temp.ptr.p_int[i] = temp.ptr.p_int[i]+s->didx.ptr.p_int[i]+1; + + /* + * Copy superdiagonal part of I-th block + */ + offs0 = tridx.ptr.p_int[i]+s->didx.ptr.p_int[i]+1; + k = s->uidx.ptr.p_int[i]; + for(j=0; j<=k-1; j++) + { + offs1 = s->ridx.ptr.p_int[i-k+j]+temp.ptr.p_int[i-k+j]; + s->vals.ptr.p_double[offs1] = tvals.ptr.p_double[offs0+j]; + s->idx.ptr.p_int[offs1] = i; + temp.ptr.p_int[i-k+j] = temp.ptr.p_int[i-k+j]+1; + } + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s, _state); + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "SparseConvertToCRS: invalid matrix type", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs out-of-place conversion to CRS format. S0 is +copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to +maximum extent possible. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + S1 - matrix which may contain some pre-allocated memory, or + can be just uninitialized structure. + +OUTPUT PARAMETERS + S1 - sparse matrix in CRS format. + +NOTE: if S0 is stored as CRS, it is just copied without conversion. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytocrsbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector temp; + ae_int_t nonne; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs0; + ae_int_t offs1; + ae_int_t m; + + ae_frame_make(_state, &_frame_block); + memset(&temp, 0, sizeof(temp)); + ae_vector_init(&temp, 0, DT_INT, _state, ae_true); + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToCRSBuf: invalid matrix type", _state); + m = s0->m; + if( s0->matrixtype==0 ) + { + + /* + * Convert from hash-table to CRS + * Done like ConvertToCRS function + */ + s1->matrixtype = 1; + s1->m = s0->m; + s1->n = s0->n; + s1->nfree = s0->nfree; + nonne = 0; + k = s0->tablesize; + isetallocv(s1->m+1, 0, &s1->ridx, _state); + isetallocv(s1->m, 0, &temp, _state); + + /* + * Number of elements per row + */ + for(i=0; i<=k-1; i++) + { + if( s0->idx.ptr.p_int[2*i]>=0 ) + { + s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1] = s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1]+1; + nonne = nonne+1; + } + } + + /* + * Fill RIdx (offsets of rows) + */ + for(i=0; i<=s1->m-1; i++) + { + s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; + } + + /* + * Allocate memory + */ + rallocv(nonne, &s1->vals, _state); + iallocv(nonne, &s1->idx, _state); + for(i=0; i<=k-1; i++) + { + if( s0->idx.ptr.p_int[2*i]>=0 ) + { + s1->vals.ptr.p_double[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->vals.ptr.p_double[i]; + s1->idx.ptr.p_int[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->idx.ptr.p_int[2*i+1]; + temp.ptr.p_int[s0->idx.ptr.p_int[2*i]] = temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]+1; + } + } + + /* + * Set NInitialized + */ + s1->ninitialized = s1->ridx.ptr.p_int[s1->m]; + + /* + * Sorting of elements + */ + for(i=0; i<=s1->m-1; i++) + { + tagsortmiddleir(&s1->idx, &s1->vals, s1->ridx.ptr.p_int[i], s1->ridx.ptr.p_int[i+1]-s1->ridx.ptr.p_int[i], _state); + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s1, _state); + ae_frame_leave(_state); + return; + } + if( s0->matrixtype==1 ) + { + + /* + * Already CRS, just copy + */ + sparsecopybuf(s0, s1, _state); + ae_frame_leave(_state); + return; + } + if( s0->matrixtype==2 ) + { + ae_assert(s0->m==s0->n, "SparseCopyToCRS: non-square SKS matrices are not supported", _state); + + /* + * From SKS to CRS. + */ + s1->m = s0->m; + s1->n = s0->n; + s1->matrixtype = 1; + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + iallocv(m+1, &s1->ridx, _state); + s1->ridx.ptr.p_int[0] = 0; + for(i=1; i<=m; i++) + { + s1->ridx.ptr.p_int[i] = 1; + } + nonne = 0; + for(i=0; i<=m-1; i++) + { + s1->ridx.ptr.p_int[i+1] = s0->didx.ptr.p_int[i]+s1->ridx.ptr.p_int[i+1]; + for(j=i-s0->uidx.ptr.p_int[i]; j<=i-1; j++) + { + s1->ridx.ptr.p_int[j+1] = s1->ridx.ptr.p_int[j+1]+1; + } + nonne = nonne+s0->didx.ptr.p_int[i]+1+s0->uidx.ptr.p_int[i]; + } + for(i=0; i<=m-1; i++) + { + s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; + } + s1->ninitialized = s1->ridx.ptr.p_int[m]; + + /* + * Allocate memory and move elements to Vals/Idx. + * Initially, elements are sorted by rows, and are sorted within row too. + * No additional post-sorting is required. + */ + ae_vector_set_length(&temp, m, _state); + for(i=0; i<=m-1; i++) + { + temp.ptr.p_int[i] = 0; + } + rallocv(nonne, &s1->vals, _state); + iallocv(nonne, &s1->idx, _state); + for(i=0; i<=m-1; i++) + { + + /* + * copy subdiagonal and diagonal parts of I-th block + */ + offs0 = s0->ridx.ptr.p_int[i]; + offs1 = s1->ridx.ptr.p_int[i]+temp.ptr.p_int[i]; + k = s0->didx.ptr.p_int[i]+1; + for(j=0; j<=k-1; j++) + { + s1->vals.ptr.p_double[offs1+j] = s0->vals.ptr.p_double[offs0+j]; + s1->idx.ptr.p_int[offs1+j] = i-s0->didx.ptr.p_int[i]+j; + } + temp.ptr.p_int[i] = temp.ptr.p_int[i]+s0->didx.ptr.p_int[i]+1; + + /* + * Copy superdiagonal part of I-th block + */ + offs0 = s0->ridx.ptr.p_int[i]+s0->didx.ptr.p_int[i]+1; + k = s0->uidx.ptr.p_int[i]; + for(j=0; j<=k-1; j++) + { + offs1 = s1->ridx.ptr.p_int[i-k+j]+temp.ptr.p_int[i-k+j]; + s1->vals.ptr.p_double[offs1] = s0->vals.ptr.p_double[offs0+j]; + s1->idx.ptr.p_int[offs1] = i; + temp.ptr.p_int[i-k+j] = temp.ptr.p_int[i-k+j]+1; + } + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s1, _state); + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "SparseCopyToCRSBuf: unexpected matrix type", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function checks matrix storage format and returns True when matrix is +stored using CRS representation. + +INPUT PARAMETERS: + S - sparse matrix. + +RESULT: + True if matrix type is CRS + False if matrix type is not CRS + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool sparseiscrs(const sparsematrix* s, ae_state *_state) +{ + ae_bool result; + + + ae_assert((((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2)||s->matrixtype==-10081)||s->matrixtype==-10082, "SparseIsCRS: invalid matrix type", _state); + result = s->matrixtype==1; + return result; +} + + +/************************************************************************* +The function returns number of rows of a sparse matrix. + +RESULT: number of rows of a sparse matrix. + + -- ALGLIB PROJECT -- + Copyright 23.08.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetnrows(const sparsematrix* s, ae_state *_state) +{ + ae_int_t result; + + + result = s->m; + return result; +} + + +/************************************************************************* +The function returns number of columns of a sparse matrix. + +RESULT: number of columns of a sparse matrix. + + -- ALGLIB PROJECT -- + Copyright 23.08.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetncols(const sparsematrix* s, ae_state *_state) +{ + ae_int_t result; + + + result = s->n; + return result; +} + + + + +void _xquadraticconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xquadraticconstraint *p = (xquadraticconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->varidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->lowerq, _state, make_automatic); +} + + +void _xquadraticconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xquadraticconstraint *dst = (xquadraticconstraint*)_dst; + const xquadraticconstraint *src = (const xquadraticconstraint*)_src; + dst->nvars = src->nvars; + ae_vector_init_copy(&dst->varidx, &src->varidx, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + _sparsematrix_init_copy(&dst->lowerq, &src->lowerq, _state, make_automatic); + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; +} + + +void _xquadraticconstraint_clear(void* _p) +{ + xquadraticconstraint *p = (xquadraticconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->varidx); + ae_vector_clear(&p->b); + _sparsematrix_clear(&p->lowerq); +} + + +void _xquadraticconstraint_destroy(void* _p) +{ + xquadraticconstraint *p = (xquadraticconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->varidx); + ae_vector_destroy(&p->b); + _sparsematrix_destroy(&p->lowerq); +} + + +void _xquadraticconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xquadraticconstraints *p = (xquadraticconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_init(&p->constraints, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); +} + + +void _xquadraticconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xquadraticconstraints *dst = (xquadraticconstraints*)_dst; + const xquadraticconstraints *src = (const xquadraticconstraints*)_src; + dst->n = src->n; + ae_obj_array_init_copy(&dst->constraints, &src->constraints, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); +} + + +void _xquadraticconstraints_clear(void* _p) +{ + xquadraticconstraints *p = (xquadraticconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_clear(&p->constraints); + ae_vector_clear(&p->tmpi); +} + + +void _xquadraticconstraints_destroy(void* _p) +{ + xquadraticconstraints *p = (xquadraticconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_destroy(&p->constraints); + ae_vector_destroy(&p->tmpi); +} + + +void _xconicconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xconicconstraint *p = (xconicconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->varidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->diaga, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->shftc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alphapow, 0, DT_REAL, _state, make_automatic); +} + + +void _xconicconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xconicconstraint *dst = (xconicconstraint*)_dst; + const xconicconstraint *src = (const xconicconstraint*)_src; + dst->conetype = src->conetype; + dst->nvars = src->nvars; + dst->kpow = src->kpow; + ae_vector_init_copy(&dst->varidx, &src->varidx, _state, make_automatic); + ae_vector_init_copy(&dst->diaga, &src->diaga, _state, make_automatic); + ae_vector_init_copy(&dst->shftc, &src->shftc, _state, make_automatic); + ae_vector_init_copy(&dst->alphapow, &src->alphapow, _state, make_automatic); + dst->applyorigin = src->applyorigin; +} + + +void _xconicconstraint_clear(void* _p) +{ + xconicconstraint *p = (xconicconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->varidx); + ae_vector_clear(&p->diaga); + ae_vector_clear(&p->shftc); + ae_vector_clear(&p->alphapow); +} + + +void _xconicconstraint_destroy(void* _p) +{ + xconicconstraint *p = (xconicconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->varidx); + ae_vector_destroy(&p->diaga); + ae_vector_destroy(&p->shftc); + ae_vector_destroy(&p->alphapow); +} + + +void _xconicconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xconicconstraints *p = (xconicconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_init(&p->constraints, _state, make_automatic); +} + + +void _xconicconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xconicconstraints *dst = (xconicconstraints*)_dst; + const xconicconstraints *src = (const xconicconstraints*)_src; + dst->n = src->n; + ae_obj_array_init_copy(&dst->constraints, &src->constraints, _state, make_automatic); +} + + +void _xconicconstraints_clear(void* _p) +{ + xconicconstraints *p = (xconicconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_clear(&p->constraints); +} + + +void _xconicconstraints_destroy(void* _p) +{ + xconicconstraints *p = (xconicconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_destroy(&p->constraints); +} + + +void _qpxproblem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + qpxproblem *p = (qpxproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->solx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xorigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->q, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->a, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + _xquadraticconstraints_init(&p->qc, _state, make_automatic); + _sparsematrix_init(&p->dummysparse, _state, make_automatic); +} + + +void _qpxproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + qpxproblem *dst = (qpxproblem*)_dst; + const qpxproblem *src = (const qpxproblem*)_src; + dst->n = src->n; + dst->hasknowntarget = src->hasknowntarget; + dst->targetf = src->targetf; + dst->hasinitialpoint = src->hasinitialpoint; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->hasknownsolution = src->hasknownsolution; + ae_vector_init_copy(&dst->solx, &src->solx, _state, make_automatic); + dst->hasscale = src->hasscale; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->hasorigin = src->hasorigin; + ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + dst->hasq = src->hasq; + _sparsematrix_init_copy(&dst->q, &src->q, _state, make_automatic); + dst->isupperq = src->isupperq; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->mlc = src->mlc; + _sparsematrix_init_copy(&dst->a, &src->a, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + dst->mqc = src->mqc; + _xquadraticconstraints_init_copy(&dst->qc, &src->qc, _state, make_automatic); + dst->mcc = src->mcc; + _sparsematrix_init_copy(&dst->dummysparse, &src->dummysparse, _state, make_automatic); +} + + +void _qpxproblem_clear(void* _p) +{ + qpxproblem *p = (qpxproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->solx); + ae_vector_clear(&p->s); + ae_vector_clear(&p->xorigin); + ae_vector_clear(&p->c); + _sparsematrix_clear(&p->q); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + _sparsematrix_clear(&p->a); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + _xquadraticconstraints_clear(&p->qc); + _sparsematrix_clear(&p->dummysparse); +} + + +void _qpxproblem_destroy(void* _p) +{ + qpxproblem *p = (qpxproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->solx); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->xorigin); + ae_vector_destroy(&p->c); + _sparsematrix_destroy(&p->q); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + _sparsematrix_destroy(&p->a); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + _xquadraticconstraints_destroy(&p->qc); + _sparsematrix_destroy(&p->dummysparse); +} + + +/************************************************************************* +Initialize QPX problem. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemcreate(ae_int_t n, qpxproblem* p, ae_state *_state) +{ + + _qpxproblem_clear(p); + + ae_assert(n>=1, "QPXProblemCreate: N<1", _state); + p->n = n; + p->hasinitialpoint = ae_false; + p->hasknowntarget = ae_false; + p->hasknownsolution = ae_false; + p->hasscale = ae_false; + p->hasorigin = ae_false; + p->hasq = ae_false; + rsetallocv(n, 0.0, &p->c, _state); + rsetallocv(n, _state->v_neginf, &p->bndl, _state); + rsetallocv(n, _state->v_posinf, &p->bndu, _state); + p->mlc = 0; + p->mqc = 0; + p->mcc = 0; + xqcinit(n, &p->qc, _state); +} + + +/************************************************************************* +Set initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetinitialpoint(qpxproblem* p, + /* Real */ const ae_vector* x0, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(x0->cnt>=p->n, "QPXProblemSetInitialPoint: len(X0)n-1; i++) + { + ae_assert(ae_isfinite(x0->ptr.p_double[i], _state), "QPXProblemSetInitialPoint: X0 contains INF/NAN", _state); + } + p->hasinitialpoint = ae_true; + rcopyallocv(p->n, x0, &p->x0, _state); +} + + +/************************************************************************* +Set scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetscale(qpxproblem* p, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=p->n, "QPXProblemSetScale: len(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "QPXProblemSetScale: S contains INF/NAN", _state); + } + p->hasscale = ae_true; + rcopyallocv(p->n, s, &p->s, _state); +} + + +/************************************************************************* +Set origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetorigin(qpxproblem* p, + /* Real */ const ae_vector* xorigin, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(xorigin->cnt>=p->n, "QPXProblemSetOrigin: len(XOrigin)n-1; i++) + { + ae_assert(ae_isfinite(xorigin->ptr.p_double[i], _state), "QPXProblemSetOrigin: C contains INF/NAN", _state); + } + p->hasorigin = ae_true; + rcopyallocv(p->n, xorigin, &p->xorigin, _state); +} + + +/************************************************************************* +Set linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlinearterm(qpxproblem* p, + /* Real */ const ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(c->cnt>=p->n, "QPXProblemSetLinearTerm: len(C)n-1; i++) + { + ae_assert(ae_isfinite(c->ptr.p_double[i], _state), "QPXProblemSetLinearTerm: C contains INF/NAN", _state); + } + rcopyv(p->n, c, &p->c, _state); +} + + +/************************************************************************* +Set quadratic term; Q can be in any sparse matrix format. + +Only one triangle (lower or upper) is referenced by this function. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetquadraticterm(qpxproblem* p, + const sparsematrix* q, + ae_bool isupper, + ae_state *_state) +{ + + + ae_assert(sparseiscrs(q, _state), "QPXProblemSetQuadraticTerm: Q is non-CRS matrix", _state); + p->hasq = ae_true; + p->isupperq = isupper; + sparsecopytocrsbuf(q, &p->q, _state); +} + + +/************************************************************************* +Set box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetbc(qpxproblem* p, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(bndl->cnt>=p->n, "QPXProblemSetBC: len(BndL)cnt>=p->n, "QPXProblemSetBC: len(BndU)n-1; i++) + { + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "QPXProblemSetBC: BndL contains positive infinity", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "QPXProblemSetBC: BndL contains negative infinity", _state); + p->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + p->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } +} + + +/************************************************************************* +Set linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlc2(qpxproblem* p, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t m, + ae_state *_state) +{ + + + if( m<=0 ) + { + p->mlc = 0; + return; + } + ae_assert(sparsegetnrows(a, _state)==m, "QPXProblemSetLC2: rows(A)<>M", _state); + ae_assert(sparsegetncols(a, _state)==p->n, "QPXProblemSetLC2: rows(A)<>M", _state); + p->mlc = m; + sparsecopytocrsbuf(a, &p->a, _state); + rcopyallocv(m, al, &p->al, _state); + rcopyallocv(m, au, &p->au, _state); +} + + +/************************************************************************* +Append two-sided quadratic constraint, same format as minqpaddqc2() + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemaddqc2(qpxproblem* p, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + + + ae_assert(sparsegetnrows(q, _state)==p->n&&sparsegetncols(q, _state)==p->n, "QPXProblemAddQC2: rows(Q)<>N or cols(Q)<>N", _state); + ae_assert(b->cnt>=p->n, "QPXProblemAddQC2: Length(B)n, _state), "QPXProblemAddQC2: B contains infinite or NaN values!", _state); + ae_assert(ae_isfinite(cl, _state)||ae_isneginf(cl, _state), "QPXProblemAddQC2: AL is NAN or +INF", _state); + ae_assert(ae_isfinite(cu, _state)||ae_isposinf(cu, _state), "QPXProblemAddQC2: AU is NAN or -INF", _state); + if( !sparseiscrs(q, _state) ) + { + sparsecopytocrsbuf(q, &p->dummysparse, _state); + xqcaddqc2(&p->qc, &p->dummysparse, isupper, b, cl, cu, applyorigin, _state); + } + else + { + xqcaddqc2(&p->qc, q, isupper, b, cl, cu, applyorigin, _state); + } + p->mqc = p->mqc+1; +} + + +/************************************************************************* +Initialize quadratic constraints structure +*************************************************************************/ +void xqcinit(ae_int_t n, xquadraticconstraints* state, ae_state *_state) +{ + + + ae_assert(n>=1, "xqcInit: N<1", _state); + state->n = n; + ae_obj_array_clear(&state->constraints); +} + + +/************************************************************************* +Clear quadratic constraints structure +*************************************************************************/ +void xqcclear(xquadraticconstraints* state, ae_state *_state) +{ + + + ae_obj_array_clear(&state->constraints); +} + + +/************************************************************************* +Update N, only larger values are possible +*************************************************************************/ +void xqcupdaten(xquadraticconstraints* state, + ae_int_t newn, + ae_state *_state) +{ + + + ae_assert(newn>=state->n, "xqcUpdateN: newNn = newn; +} + + +/************************************************************************* +Append quadratic constraint given by a sparse quadratic matrix +*************************************************************************/ +void xqcaddqc2(xquadraticconstraints* xqc, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t n; + ae_int_t isrc; + double vq; + xquadraticconstraint *c; + ae_smart_ptr _c; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + ae_assert(ae_isfinite(cl, _state)||ae_isneginf(cl, _state), "xqcAppendDense: CL is not finite or -INF", _state); + ae_assert(ae_isfinite(cu, _state)||ae_isposinf(cu, _state), "xqcAppendDense: CU is not finite or +INF", _state); + n = xqc->n; + c = (xquadraticconstraint*)ae_malloc(sizeof(xquadraticconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xquadraticconstraint)); + _xquadraticconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xquadraticconstraint), _xquadraticconstraint_init_copy, _xquadraticconstraint_destroy); + isetallocv(n, 0, &xqc->tmpi, _state); + for(i=0; i<=n-1; i++) + { + if( b->ptr.p_double[i]!=0.0 ) + { + xqc->tmpi.ptr.p_int[i] = 1; + } + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = q->didx.ptr.p_int[i]; + j1 = q->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = q->ridx.ptr.p_int[i]; + j1 = q->uidx.ptr.p_int[i]-1; + } + for(jj=j0; jj<=j1; jj++) + { + if( q->vals.ptr.p_double[jj]!=0.0 ) + { + xqc->tmpi.ptr.p_int[i] = 1; + xqc->tmpi.ptr.p_int[q->idx.ptr.p_int[jj]] = 1; + } + } + } + c->nvars = 0; + for(i=0; i<=n-1; i++) + { + if( xqc->tmpi.ptr.p_int[i]!=0 ) + { + igrowv(c->nvars+1, &c->varidx, _state); + c->varidx.ptr.p_int[c->nvars] = i; + c->nvars = c->nvars+1; + } + } + c->applyorigin = applyorigin; + c->cl = cl; + c->cu = cu; + if( c->nvars>0 ) + { + isetallocv(n, -999999999, &xqc->tmpi, _state); + for(i=0; i<=c->nvars-1; i++) + { + xqc->tmpi.ptr.p_int[c->varidx.ptr.p_int[i]] = i; + } + rallocv(c->nvars, &c->b, _state); + for(i=0; i<=c->nvars-1; i++) + { + c->b.ptr.p_double[i] = b->ptr.p_double[c->varidx.ptr.p_int[i]]; + } + c->lowerq.matrixtype = 1; + c->lowerq.m = c->nvars; + c->lowerq.n = c->nvars; + iallocv(c->nvars, &c->lowerq.uidx, _state); + isetallocv(c->nvars, 1, &c->lowerq.didx, _state); + iallocv(c->nvars+1, &c->lowerq.ridx, _state); + if( isupper ) + { + for(i=0; i<=c->nvars-1; i++) + { + isrc = c->varidx.ptr.p_int[i]; + j0 = q->uidx.ptr.p_int[isrc]; + j1 = q->ridx.ptr.p_int[isrc+1]-1; + for(jj=j0; jj<=j1; jj++) + { + vq = q->vals.ptr.p_double[jj]; + if( vq==0.0 ) + { + continue; + } + j = xqc->tmpi.ptr.p_int[q->idx.ptr.p_int[jj]]; + c->lowerq.didx.ptr.p_int[j] = c->lowerq.didx.ptr.p_int[j]+1; + } + } + c->lowerq.ridx.ptr.p_int[0] = 0; + for(i=0; i<=c->nvars-1; i++) + { + c->lowerq.ridx.ptr.p_int[i+1] = c->lowerq.ridx.ptr.p_int[i]+c->lowerq.didx.ptr.p_int[i]; + } + iallocv(c->lowerq.ridx.ptr.p_int[c->nvars], &c->lowerq.idx, _state); + rallocv(c->lowerq.ridx.ptr.p_int[c->nvars], &c->lowerq.vals, _state); + icopyv(c->nvars, &c->lowerq.ridx, &c->lowerq.didx, _state); + for(i=0; i<=c->nvars-1; i++) + { + isrc = c->varidx.ptr.p_int[i]; + vq = (double)(0); + if( q->didx.ptr.p_int[isrc]!=q->uidx.ptr.p_int[isrc] ) + { + vq = q->vals.ptr.p_double[q->didx.ptr.p_int[isrc]]; + } + offs = c->lowerq.didx.ptr.p_int[i]; + c->lowerq.idx.ptr.p_int[offs] = i; + c->lowerq.vals.ptr.p_double[offs] = vq; + c->lowerq.didx.ptr.p_int[i] = offs+1; + j0 = q->uidx.ptr.p_int[isrc]; + j1 = q->ridx.ptr.p_int[isrc+1]-1; + for(jj=j0; jj<=j1; jj++) + { + vq = q->vals.ptr.p_double[jj]; + if( vq==0.0 ) + { + continue; + } + j = xqc->tmpi.ptr.p_int[q->idx.ptr.p_int[jj]]; + offs = c->lowerq.didx.ptr.p_int[j]; + c->lowerq.idx.ptr.p_int[offs] = i; + c->lowerq.vals.ptr.p_double[offs] = vq; + c->lowerq.didx.ptr.p_int[j] = offs+1; + } + } + for(i=0; i<=c->nvars-1; i++) + { + if( c->lowerq.didx.ptr.p_int[i]!=c->lowerq.ridx.ptr.p_int[i+1] ) + { + ae_assert(ae_false, "OPTSERV: integrity check 5050 failed", _state); + } + } + for(i=0; i<=c->nvars-1; i++) + { + c->lowerq.didx.ptr.p_int[i] = c->lowerq.ridx.ptr.p_int[i+1]-1; + c->lowerq.uidx.ptr.p_int[i] = c->lowerq.ridx.ptr.p_int[i+1]; + } + c->lowerq.ninitialized = c->lowerq.ridx.ptr.p_int[c->nvars]; + } + else + { + c->lowerq.ridx.ptr.p_int[0] = 0; + for(i=0; i<=c->nvars-1; i++) + { + isrc = c->varidx.ptr.p_int[i]; + offs = c->lowerq.ridx.ptr.p_int[i]; + igrowv(offs+c->nvars, &c->lowerq.idx, _state); + rgrowv(offs+c->nvars, &c->lowerq.vals, _state); + j0 = q->ridx.ptr.p_int[isrc]; + j1 = q->didx.ptr.p_int[isrc]-1; + for(jj=j0; jj<=j1; jj++) + { + vq = q->vals.ptr.p_double[jj]; + if( vq==0.0 ) + { + continue; + } + c->lowerq.idx.ptr.p_int[offs] = xqc->tmpi.ptr.p_int[q->idx.ptr.p_int[jj]]; + c->lowerq.vals.ptr.p_double[offs] = vq; + offs = offs+1; + } + if( q->didx.ptr.p_int[isrc]!=q->uidx.ptr.p_int[isrc] ) + { + c->lowerq.idx.ptr.p_int[offs] = i; + c->lowerq.vals.ptr.p_double[offs] = q->vals.ptr.p_double[q->didx.ptr.p_int[isrc]]; + offs = offs+1; + } + else + { + c->lowerq.idx.ptr.p_int[offs] = i; + c->lowerq.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + c->lowerq.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=c->nvars-1; i++) + { + c->lowerq.didx.ptr.p_int[i] = c->lowerq.ridx.ptr.p_int[i+1]-1; + c->lowerq.uidx.ptr.p_int[i] = c->lowerq.ridx.ptr.p_int[i+1]; + } + c->lowerq.ninitialized = c->lowerq.ridx.ptr.p_int[c->nvars]; + } + } + ae_obj_array_append_transfer(&xqc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + + + +/************************************************************************* +Initialize conic constraints structure +*************************************************************************/ +void xccinit(ae_int_t n, xconicconstraints* state, ae_state *_state) +{ + + + ae_assert(n>=1, "qccInit: N<1", _state); + state->n = n; + ae_obj_array_clear(&state->constraints); +} + + +/************************************************************************* +Update N, only larger values are possible +*************************************************************************/ +void xccupdaten(xconicconstraints* state, ae_int_t newn, ae_state *_state) +{ + + + ae_assert(newn>=state->n, "xccUpdateN: newNn = newn; +} + + + +} +namespace alglib +{ + +} + diff --git a/core/alglib/ap.h b/core/alglib/ap.h index 29727f36..509d8479 100644 --- a/core/alglib/ap.h +++ b/core/alglib/ap.h @@ -1,1575 +1,7698 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _ap_h -#define _ap_h - -#include -#include -#include -#include -#include -#include - -#ifdef __BORLANDC__ -#include -#include -#else -#include -#include -#endif - -#define AE_USE_CPP -/* Definitions */ -#define AE_UNKNOWN 0 -#define AE_MSVC 1 -#define AE_GNUC 2 -#define AE_SUNC 3 -#define AE_INTEL 1 -#define AE_SPARC 2 -#define AE_WINDOWS 1 -#define AE_POSIX 2 -#define AE_LOCK_ALIGNMENT 16 - -/* in case no OS is defined, use AE_UNKNOWN */ -#ifndef AE_OS -#define AE_OS AE_UNKNOWN -#endif - -/* automatically determine compiler */ -#define AE_COMPILER AE_UNKNOWN -#ifdef __GNUC__ -#undef AE_COMPILER -#define AE_COMPILER AE_GNUC -#endif -#if defined(__SUNPRO_C)||defined(__SUNPRO_CC) -#undef AE_COMPILER -#define AE_COMPILER AE_SUNC -#endif -#ifdef _MSC_VER -#undef AE_COMPILER -#define AE_COMPILER AE_MSVC -#endif - -/* now we are ready to include headers */ -#include -#include -#include -#include -#include -#include - -#if AE_OS==AE_WINDOWS -#include -#include -#elif AE_OS==AE_POSIX -#include -#include -#include -#include -#endif - -#if defined(AE_HAVE_STDINT) -#include -#endif - -/* - * SSE2 intrinsics - * - * Preprocessor directives below: - * - include headers for SSE2 intrinsics - * - define AE_HAS_SSE2_INTRINSICS definition - * - * These actions are performed when we have: - * - x86 architecture definition (AE_CPU==AE_INTEL) - * - compiler which supports intrinsics - * - * Presence of AE_HAS_SSE2_INTRINSICS does NOT mean that our CPU - * actually supports SSE2 - such things should be determined at runtime - * with ae_cpuid() call. It means that we are working under Intel and - * out compiler can issue SSE2-capable code. - * - */ -#if defined(AE_CPU) -#if AE_CPU==AE_INTEL -#if AE_COMPILER==AE_MSVC -#include -#define AE_HAS_SSE2_INTRINSICS -#endif -#if AE_COMPILER==AE_GNUC -#include -#define AE_HAS_SSE2_INTRINSICS -#endif -#if AE_COMPILER==AE_SUNC -#include -#include -#define AE_HAS_SSE2_INTRINSICS -#endif -#endif -#endif - -/* Debugging helpers for Windows */ -#ifdef AE_DEBUG4WINDOWS -#include -#include -#endif - - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS DECLARATIONS FOR BASIC FUNCTIONALITY -// LIKE MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS SHARED -// BETWEEN C++ AND PURE C LIBRARIES -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - -/* if we work under C++ environment, define several conditions */ -#ifdef AE_USE_CPP -#define AE_USE_CPP_BOOL -#define AE_USE_CPP_ERROR_HANDLING -#define AE_USE_CPP_SERIALIZATION -#endif - -/* - * define ae_int32_t, ae_int64_t, ae_int_t, ae_bool, ae_complex, ae_error_type and ae_datatype - */ - -#if defined(AE_INT32_T) -typedef AE_INT32_T ae_int32_t; -#endif -#if defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) -typedef int32_t ae_int32_t; -#endif -#if !defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) -#if AE_COMPILER==AE_MSVC -typedef _int32 ae_int32_t; -#endif -#if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) -typedef int ae_int32_t; -#endif -#endif - -#if defined(AE_INT64_T) -typedef AE_INT64_T ae_int64_t; -#endif -#if defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) -typedef int64_t ae_int64_t; -#endif -#if !defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) -#if AE_COMPILER==AE_MSVC -typedef _int64 ae_int64_t; -#endif -#if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) -typedef signed long long ae_int64_t; -#endif -#endif - -#if !defined(AE_INT_T) -typedef ptrdiff_t ae_int_t; -#endif - -#if !defined(AE_USE_CPP_BOOL) -#define ae_bool char -#define ae_true 1 -#define ae_false 0 -#else -#define ae_bool bool -#define ae_true true -#define ae_false false -#endif - -typedef struct { double x, y; } ae_complex; - -typedef enum -{ - ERR_OK = 0, - ERR_OUT_OF_MEMORY = 1, - ERR_XARRAY_TOO_LARGE = 2, - ERR_ASSERTION_FAILED = 3 -} ae_error_type; - -typedef ae_int_t ae_datatype; - -/* - * other definitions - */ -enum { OWN_CALLER=1, OWN_AE=2 }; -enum { ACT_UNCHANGED=1, ACT_SAME_LOCATION=2, ACT_NEW_LOCATION=3 }; -enum { DT_BOOL=1, DT_INT=2, DT_REAL=3, DT_COMPLEX=4 }; -enum { CPU_SSE2=1 }; - -/************************************************************************ -x-string (zero-terminated): - owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). - If vector is owned by caller, X-interface will just set - ptr to NULL before realloc(). If it is owned by X, it - will call ae_free/x_free/aligned_free family functions. - - last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION - contents is either: unchanged, stored at the same location, - stored at the new location. - this field is set on return from X. - - ptr pointer to the actual data - -Members of this structure are ae_int64_t to avoid alignment problems. -************************************************************************/ -typedef struct -{ - ae_int64_t owner; - ae_int64_t last_action; - char *ptr; -} x_string; - -/************************************************************************ -x-vector: - cnt number of elements - - datatype one of the DT_XXXX values - - owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). - If vector is owned by caller, X-interface will just set - ptr to NULL before realloc(). If it is owned by X, it - will call ae_free/x_free/aligned_free family functions. - - last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION - contents is either: unchanged, stored at the same location, - stored at the new location. - this field is set on return from X interface and may be - used by caller as hint when deciding what to do with data - (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array - reallocation or copying is required). - - ptr pointer to the actual data - -Members of this structure are ae_int64_t to avoid alignment problems. -************************************************************************/ -typedef struct -{ - ae_int64_t cnt; - ae_int64_t datatype; - ae_int64_t owner; - ae_int64_t last_action; - void *ptr; -} x_vector; - - -/************************************************************************ -x-matrix: - rows number of rows. may be zero only when cols is zero too. - - cols number of columns. may be zero only when rows is zero too. - - stride stride, i.e. distance between first elements of rows (in bytes) - - datatype one of the DT_XXXX values - - owner OWN_CALLER or OWN_AE. Determines what to do on realloc(). - If vector is owned by caller, X-interface will just set - ptr to NULL before realloc(). If it is owned by X, it - will call ae_free/x_free/aligned_free family functions. - - last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION - contents is either: unchanged, stored at the same location, - stored at the new location. - this field is set on return from X interface and may be - used by caller as hint when deciding what to do with data - (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array - reallocation or copying is required). - - ptr pointer to the actual data, stored rowwise - -Members of this structure are ae_int64_t to avoid alignment problems. -************************************************************************/ -typedef struct -{ - ae_int64_t rows; - ae_int64_t cols; - ae_int64_t stride; - ae_int64_t datatype; - ae_int64_t owner; - ae_int64_t last_action; - void *ptr; -} x_matrix; - - -/************************************************************************ -dynamic block which may be automatically deallocated during stack unwinding - -p_next next block in the stack unwinding list. - NULL means that this block is not in the list -deallocator deallocator function which should be used to deallocate block. - NULL for "special" blocks (frame/stack boundaries) -ptr pointer which should be passed to the deallocator. - may be null (for zero-size block), DYN_BOTTOM or DYN_FRAME - for "special" blocks (frame/stack boundaries). - -************************************************************************/ -typedef struct ae_dyn_block -{ - struct ae_dyn_block * volatile p_next; - /* void *deallocator; */ - void (*deallocator)(void*); - void * volatile ptr; -} ae_dyn_block; - -/************************************************************************ -frame marker -************************************************************************/ -typedef struct ae_frame -{ - ae_dyn_block db_marker; -} ae_frame; - -/************************************************************************ -ALGLIB environment state -************************************************************************/ -typedef struct ae_state -{ - /* - * endianness type: AE_LITTLE_ENDIAN or AE_BIG_ENDIAN - */ - ae_int_t endianness; - - /* - * double value for NAN - */ - double v_nan; - - /* - * double value for +INF - */ - double v_posinf; - - /* - * double value for -INF - */ - double v_neginf; - - /* - * pointer to the top block in a stack of frames - * which hold dynamically allocated objects - */ - ae_dyn_block * volatile p_top_block; - ae_dyn_block last_block; - - /* - * jmp_buf for cases when C-style exception handling is used - */ -#ifndef AE_USE_CPP_ERROR_HANDLING - jmp_buf * volatile break_jump; -#endif - - /* - * ae_error_type of the last error (filled when exception is thrown) - */ - ae_error_type volatile last_error; - - /* - * human-readable message (filled when exception is thrown) - */ - const char* volatile error_msg; - - /* - * threading information: - * a) current thread pool - * b) current worker thread - * c) parent task (one we are solving right now) - * d) thread exception handler (function which must be called - * by ae_assert before raising exception). - * - * NOTE: we use void* to store pointers in order to avoid explicit dependency on smp.h - */ - void *worker_thread; - void *parent_task; - void (*thread_exception_handler)(void*); - -} ae_state; - -/************************************************************************ -Serializer -************************************************************************/ -typedef struct -{ - ae_int_t mode; - ae_int_t entries_needed; - ae_int_t entries_saved; - ae_int_t bytes_asked; - ae_int_t bytes_written; - -#ifdef AE_USE_CPP_SERIALIZATION - std::string *out_cppstr; -#endif - char *out_str; - const char *in_str; -} ae_serializer; - -typedef void(*ae_deallocator)(void*); - -typedef struct ae_vector -{ - ae_int_t cnt; - ae_datatype datatype; - ae_dyn_block data; - union - { - void *p_ptr; - ae_bool *p_bool; - ae_int_t *p_int; - double *p_double; - ae_complex *p_complex; - } ptr; -} ae_vector; - -typedef struct ae_matrix -{ - ae_int_t rows; - ae_int_t cols; - ae_int_t stride; - ae_datatype datatype; - ae_dyn_block data; - union - { - void *p_ptr; - void **pp_void; - ae_bool **pp_bool; - ae_int_t **pp_int; - double **pp_double; - ae_complex **pp_complex; - } ptr; -} ae_matrix; - -typedef struct ae_smart_ptr -{ - /* pointer to subscriber; all changes in ptr are translated to subscriber */ - void **subscriber; - - /* pointer to object */ - void *ptr; - - /* whether smart pointer owns ptr */ - ae_bool is_owner; - - /* whether object pointed by ptr is dynamic - clearing such object requires BOTH - calling destructor function AND calling ae_free for memory occupied by object. */ - ae_bool is_dynamic; - - /* destructor function for pointer; clears all dynamically allocated memory */ - void (*destroy)(void*); - - /* frame entry; used to ensure automatic deallocation of smart pointer in case of exception/exit */ - ae_dyn_block frame_entry; -} ae_smart_ptr; - - -/************************************************************************* -Lock. - -This structure provides OS-independent non-reentrant lock: -* under Windows/Posix systems it uses system-provided locks -* under Boost it uses OS-independent lock provided by Boost package -* when no OS is defined, it uses "fake lock" (just stub which is not thread-safe): - a) "fake lock" can be in locked or free mode - b) "fake lock" can be used only from one thread - one which created lock - c) when thread acquires free lock, it immediately returns - d) when thread acquires busy lock, program is terminated - (because lock is already acquired and no one else can free it) -*************************************************************************/ -typedef struct -{ -#if AE_OS==AE_WINDOWS - volatile ae_int_t * volatile p_lock; - char buf[sizeof(ae_int_t)+AE_LOCK_ALIGNMENT]; -#elif AE_OS==AE_POSIX - pthread_mutex_t mutex; -#else - ae_bool is_locked; -#endif -} ae_lock; - - -/************************************************************************* -Shared pool: data structure used to provide thread-safe access to pool of -temporary variables. -*************************************************************************/ -typedef struct ae_shared_pool_entry -{ - void * volatile obj; - void * volatile next_entry; -} ae_shared_pool_entry; - -typedef struct ae_shared_pool -{ - /* lock object which protects pool */ - ae_lock pool_lock; - - /* seed object (used to create new instances of temporaries) */ - void * volatile seed_object; - - /* - * list of recycled OBJECTS: - * 1. entries in this list store pointers to recycled objects - * 2. every time we retrieve object, we retrieve first entry from this list, - * move it to recycled_entries and return its obj field to caller/ - */ - ae_shared_pool_entry * volatile recycled_objects; - - /* - * list of recycled ENTRIES: - * 1. this list holds entries which are not used to store recycled objects; - * every time recycled object is retrieved, its entry is moved to this list. - * 2. every time object is recycled, we try to fetch entry for him from this list - * before allocating it with malloc() - */ - ae_shared_pool_entry * volatile recycled_entries; - - /* enumeration pointer, points to current recycled object*/ - ae_shared_pool_entry * volatile enumeration_counter; - - /* size of object; this field is used when we call malloc() for new objects */ - ae_int_t size_of_object; - - /* initializer function; accepts pointer to malloc'ed object, initializes its fields */ - ae_bool (*init)(void* dst, ae_state* state, ae_bool make_automatic); - - /* copy constructor; accepts pointer to malloc'ed, but not initialized object */ - ae_bool (*init_copy)(void* dst, void* src, ae_state* state, ae_bool make_automatic); - - /* destructor function; */ - void (*destroy)(void* ptr); - - /* frame entry; contains pointer to the pool object itself */ - ae_dyn_block frame_entry; -} ae_shared_pool; - -ae_int_t ae_misalignment(const void *ptr, size_t alignment); -void* ae_align(void *ptr, size_t alignment); -void* aligned_malloc(size_t size, size_t alignment); -void aligned_free(void *block); - -void* ae_malloc(size_t size, ae_state *state); -void ae_free(void *p); -ae_int_t ae_sizeof(ae_datatype datatype); -void ae_touch_ptr(void *p); - -void ae_state_init(ae_state *state); -void ae_state_clear(ae_state *state); -#ifndef AE_USE_CPP_ERROR_HANDLING -void ae_state_set_break_jump(ae_state *state, jmp_buf *buf); -#endif -void ae_break(ae_state *state, ae_error_type error_type, const char *msg); - -void ae_frame_make(ae_state *state, ae_frame *tmp); -void ae_frame_leave(ae_state *state); - -void ae_db_attach(ae_dyn_block *block, ae_state *state); -ae_bool ae_db_malloc(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic); -ae_bool ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state); -void ae_db_free(ae_dyn_block *block); -void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2); - -ae_bool ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state, ae_bool make_automatic); -ae_bool ae_vector_init_copy(ae_vector *dst, ae_vector *src, ae_state *state, ae_bool make_automatic); -void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic); -ae_bool ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state); -void ae_vector_clear(ae_vector *dst); -void ae_vector_destroy(ae_vector *dst); -void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2); - -ae_bool ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state, ae_bool make_automatic); -ae_bool ae_matrix_init_copy(ae_matrix *dst, ae_matrix *src, ae_state *state, ae_bool make_automatic); -void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic); -ae_bool ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state); -void ae_matrix_clear(ae_matrix *dst); -void ae_matrix_destroy(ae_matrix *dst); -void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2); - -ae_bool ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_state *state, ae_bool make_automatic); -void ae_smart_ptr_clear(void *_dst); /* accepts ae_smart_ptr* */ -void ae_smart_ptr_destroy(void *_dst); -void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, void (*destroy)(void*)); -void ae_smart_ptr_release(ae_smart_ptr *dst); - -void ae_yield(); -void ae_init_lock(ae_lock *lock); -void ae_acquire_lock(ae_lock *lock); -void ae_release_lock(ae_lock *lock); -void ae_free_lock(ae_lock *lock); - -ae_bool ae_shared_pool_init(void *_dst, ae_state *state, ae_bool make_automatic); -ae_bool ae_shared_pool_init_copy(void *_dst, void *_src, ae_state *state, ae_bool make_automatic); -void ae_shared_pool_clear(void *dst); -void ae_shared_pool_destroy(void *dst); -ae_bool ae_shared_pool_is_initialized(void *_dst); -void ae_shared_pool_set_seed( - ae_shared_pool *dst, - void *seed_object, - ae_int_t size_of_object, - ae_bool (*init)(void* dst, ae_state* state, ae_bool make_automatic), - ae_bool (*init_copy)(void* dst, void* src, ae_state* state, ae_bool make_automatic), - void (*destroy)(void* ptr), - ae_state *state); -void ae_shared_pool_retrieve( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state); -void ae_shared_pool_recycle( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state); -void ae_shared_pool_clear_recycled( - ae_shared_pool *pool, - ae_state *state); -void ae_shared_pool_first_recycled( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state); -void ae_shared_pool_next_recycled( - ae_shared_pool *pool, - ae_smart_ptr *pptr, - ae_state *state); -void ae_shared_pool_reset( - ae_shared_pool *pool, - ae_state *state); - -void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state); -void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state); -void ae_x_attach_to_vector(x_vector *dst, ae_vector *src); -void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src); - -void x_vector_clear(x_vector *dst); - -ae_bool x_is_symmetric(x_matrix *a); -ae_bool x_is_hermitian(x_matrix *a); -ae_bool x_force_symmetric(x_matrix *a); -ae_bool x_force_hermitian(x_matrix *a); -ae_bool ae_is_symmetric(ae_matrix *a); -ae_bool ae_is_hermitian(ae_matrix *a); -ae_bool ae_force_symmetric(ae_matrix *a); -ae_bool ae_force_hermitian(ae_matrix *a); - -void ae_serializer_init(ae_serializer *serializer); -void ae_serializer_clear(ae_serializer *serializer); - -void ae_serializer_alloc_start(ae_serializer *serializer); -void ae_serializer_alloc_entry(ae_serializer *serializer); -ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer); - -#ifdef AE_USE_CPP_SERIALIZATION -void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf); -void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf); -#endif -void ae_serializer_sstart_str(ae_serializer *serializer, char *buf); -void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf); - -void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state); -void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state); -void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state); -void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state); -void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state); -void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state); - -void ae_serializer_stop(ae_serializer *serializer); - -/************************************************************************ -Service functions -************************************************************************/ -void ae_assert(ae_bool cond, const char *msg, ae_state *state); -ae_int_t ae_cpuid(); - -/************************************************************************ -Real math functions: -* IEEE-compliant floating point comparisons -* standard functions -************************************************************************/ -ae_bool ae_fp_eq(double v1, double v2); -ae_bool ae_fp_neq(double v1, double v2); -ae_bool ae_fp_less(double v1, double v2); -ae_bool ae_fp_less_eq(double v1, double v2); -ae_bool ae_fp_greater(double v1, double v2); -ae_bool ae_fp_greater_eq(double v1, double v2); - -ae_bool ae_isfinite_stateless(double x, ae_int_t endianness); -ae_bool ae_isnan_stateless(double x, ae_int_t endianness); -ae_bool ae_isinf_stateless(double x, ae_int_t endianness); -ae_bool ae_isposinf_stateless(double x, ae_int_t endianness); -ae_bool ae_isneginf_stateless(double x, ae_int_t endianness); - -ae_int_t ae_get_endianness(); - -ae_bool ae_isfinite(double x,ae_state *state); -ae_bool ae_isnan(double x, ae_state *state); -ae_bool ae_isinf(double x, ae_state *state); -ae_bool ae_isposinf(double x,ae_state *state); -ae_bool ae_isneginf(double x,ae_state *state); - -double ae_fabs(double x, ae_state *state); -ae_int_t ae_iabs(ae_int_t x, ae_state *state); -double ae_sqr(double x, ae_state *state); -double ae_sqrt(double x, ae_state *state); - -ae_int_t ae_sign(double x, ae_state *state); -ae_int_t ae_round(double x, ae_state *state); -ae_int_t ae_trunc(double x, ae_state *state); -ae_int_t ae_ifloor(double x, ae_state *state); -ae_int_t ae_iceil(double x, ae_state *state); - -ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state); -ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state); -double ae_maxreal(double m1, double m2, ae_state *state); -double ae_minreal(double m1, double m2, ae_state *state); -double ae_randomreal(ae_state *state); -ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state); - -double ae_sin(double x, ae_state *state); -double ae_cos(double x, ae_state *state); -double ae_tan(double x, ae_state *state); -double ae_sinh(double x, ae_state *state); -double ae_cosh(double x, ae_state *state); -double ae_tanh(double x, ae_state *state); -double ae_asin(double x, ae_state *state); -double ae_acos(double x, ae_state *state); -double ae_atan(double x, ae_state *state); -double ae_atan2(double y, double x, ae_state *state); - -double ae_log(double x, ae_state *state); -double ae_pow(double x, double y, ae_state *state); -double ae_exp(double x, ae_state *state); - -/************************************************************************ -Complex math functions: -* basic arithmetic operations -* standard functions -************************************************************************/ -ae_complex ae_complex_from_d(double v); - -ae_complex ae_c_neg(ae_complex lhs); -ae_bool ae_c_eq(ae_complex lhs, ae_complex rhs); -ae_bool ae_c_neq(ae_complex lhs, ae_complex rhs); -ae_complex ae_c_add(ae_complex lhs, ae_complex rhs); -ae_complex ae_c_mul(ae_complex lhs, ae_complex rhs); -ae_complex ae_c_sub(ae_complex lhs, ae_complex rhs); -ae_complex ae_c_div(ae_complex lhs, ae_complex rhs); -ae_bool ae_c_eq_d(ae_complex lhs, double rhs); -ae_bool ae_c_neq_d(ae_complex lhs, double rhs); -ae_complex ae_c_add_d(ae_complex lhs, double rhs); -ae_complex ae_c_mul_d(ae_complex lhs, double rhs); -ae_complex ae_c_sub_d(ae_complex lhs, double rhs); -ae_complex ae_c_d_sub(double lhs, ae_complex rhs); -ae_complex ae_c_div_d(ae_complex lhs, double rhs); -ae_complex ae_c_d_div(double lhs, ae_complex rhs); - -ae_complex ae_c_conj(ae_complex lhs, ae_state *state); -ae_complex ae_c_sqr(ae_complex lhs, ae_state *state); -double ae_c_abs(ae_complex z, ae_state *state); - -/************************************************************************ -Complex BLAS operations -************************************************************************/ -ae_complex ae_v_cdotproduct(const ae_complex *v0, ae_int_t stride0, const char *conj0, const ae_complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); -void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void ae_v_cmoveneg(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); -void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); -void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); -void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); -void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha); - -/************************************************************************ -Real BLAS operations -************************************************************************/ -double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); -void ae_v_move(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); -void ae_v_moveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); -void ae_v_moved(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void ae_v_add(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); -void ae_v_addd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void ae_v_sub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); -void ae_v_subd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void ae_v_muld(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); - -/************************************************************************ -Other functions -************************************************************************/ -ae_int_t ae_v_len(ae_int_t a, ae_int_t b); - -/* -extern const double ae_machineepsilon; -extern const double ae_maxrealnumber; -extern const double ae_minrealnumber; -extern const double ae_pi; -*/ -#define ae_machineepsilon 5E-16 -#define ae_maxrealnumber 1E300 -#define ae_minrealnumber 1E-300 -#define ae_pi 3.1415926535897932384626433832795 - - -/************************************************************************ -RComm functions -************************************************************************/ -typedef struct rcommstate -{ - int stage; - ae_vector ia; - ae_vector ba; - ae_vector ra; - ae_vector ca; -} rcommstate; -ae_bool _rcommstate_init(rcommstate* p, ae_state *_state, ae_bool make_automatic); -ae_bool _rcommstate_init_copy(rcommstate* dst, rcommstate* src, ae_state *_state, ae_bool make_automatic); -void _rcommstate_clear(rcommstate* p); -void _rcommstate_destroy(rcommstate* p); - -#ifdef AE_USE_ALLOC_COUNTER -extern ae_int64_t _alloc_counter; -#endif - - -/************************************************************************ -debug functions (must be turned on by preprocessor definitions): -* tickcount(), which is wrapper around GetTickCount() -* flushconsole(), fluches console -* ae_debugrng(), returns random number generated with high-quality random numbers generator -* ae_set_seed(), sets seed of the debug RNG (NON-THREAD-SAFE!!!) -* ae_get_seed(), returns two seed values of the debug RNG (NON-THREAD-SAFE!!!) -************************************************************************/ -#ifdef AE_DEBUG4WINDOWS -#define flushconsole(s) fflush(stdout) -#define tickcount(s) _tickcount() -int _tickcount(); -#endif -#ifdef AE_DEBUG4POSIX -#define flushconsole(s) fflush(stdout) -#define tickcount(s) _tickcount() -int _tickcount(); -#endif -#ifdef AE_DEBUGRNG -ae_int_t ae_debugrng(); -void ae_set_seed(ae_int_t s0, ae_int_t s1); -void ae_get_seed(ae_int_t *s0, ae_int_t *s1); -#endif - - -} - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS DECLARATIONS FOR C++ RELATED FUNCTIONALITY -// -///////////////////////////////////////////////////////////////////////// - -namespace alglib -{ - -typedef alglib_impl::ae_int_t ae_int_t; - -/******************************************************************** -Class forwards -********************************************************************/ -class complex; - -ae_int_t vlen(ae_int_t n1, ae_int_t n2); - -/******************************************************************** -Exception class. -********************************************************************/ -class ap_error -{ -public: - std::string msg; - - ap_error(); - ap_error(const char *s); - static void make_assertion(bool bClause); - static void make_assertion(bool bClause, const char *msg); -private: -}; - -/******************************************************************** -Complex number with double precision. -********************************************************************/ -class complex -{ -public: - complex(); - complex(const double &_x); - complex(const double &_x, const double &_y); - complex(const complex &z); - - complex& operator= (const double& v); - complex& operator+=(const double& v); - complex& operator-=(const double& v); - complex& operator*=(const double& v); - complex& operator/=(const double& v); - - complex& operator= (const complex& z); - complex& operator+=(const complex& z); - complex& operator-=(const complex& z); - complex& operator*=(const complex& z); - complex& operator/=(const complex& z); - - alglib_impl::ae_complex* c_ptr(); - const alglib_impl::ae_complex* c_ptr() const; - - std::string tostring(int dps) const; - - double x, y; -}; - -const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); -const bool operator==(const alglib::complex& lhs, const alglib::complex& rhs); -const bool operator!=(const alglib::complex& lhs, const alglib::complex& rhs); -const alglib::complex operator+(const alglib::complex& lhs); -const alglib::complex operator-(const alglib::complex& lhs); -const alglib::complex operator+(const alglib::complex& lhs, const alglib::complex& rhs); -const alglib::complex operator+(const alglib::complex& lhs, const double& rhs); -const alglib::complex operator+(const double& lhs, const alglib::complex& rhs); -const alglib::complex operator-(const alglib::complex& lhs, const alglib::complex& rhs); -const alglib::complex operator-(const alglib::complex& lhs, const double& rhs); -const alglib::complex operator-(const double& lhs, const alglib::complex& rhs); -const alglib::complex operator*(const alglib::complex& lhs, const alglib::complex& rhs); -const alglib::complex operator*(const alglib::complex& lhs, const double& rhs); -const alglib::complex operator*(const double& lhs, const alglib::complex& rhs); -const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); -const alglib::complex operator/(const double& lhs, const alglib::complex& rhs); -const alglib::complex operator/(const alglib::complex& lhs, const double& rhs); -double abscomplex(const alglib::complex &z); -alglib::complex conj(const alglib::complex &z); -alglib::complex csqr(const alglib::complex &z); -void setnworkers(alglib::ae_int_t nworkers); - -/******************************************************************** -Level 1 BLAS functions - -NOTES: -* destination and source should NOT overlap -* stride is assumed to be positive, but it is not - assert'ed within function -* conj_src parameter specifies whether complex source is conjugated - before processing or not. Pass string which starts with 'N' or 'n' - ("No conj", for example) to use unmodified parameter. All other - values will result in conjugation of input, but it is recommended - to use "Conj" in such cases. -********************************************************************/ -double vdotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); -double vdotproduct(const double *v1, const double *v2, ae_int_t N); - -alglib::complex vdotproduct(const alglib::complex *v0, ae_int_t stride0, const char *conj0, const alglib::complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); -alglib::complex vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N); - -void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); -void vmove(double *vdst, const double* vsrc, ae_int_t N); - -void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void vmove(alglib::complex *vdst, const alglib::complex* vsrc, ae_int_t N); - -void vmoveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); -void vmoveneg(double *vdst, const double *vsrc, ae_int_t N); - -void vmoveneg(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); - -void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void vmove(double *vdst, const double *vsrc, ae_int_t N, double alpha); - -void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); - -void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); -void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); - -void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); -void vadd(double *vdst, const double *vsrc, ae_int_t N); - -void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); - -void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void vadd(double *vdst, const double *vsrc, ae_int_t N, double alpha); - -void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); - -void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); -void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); - -void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); -void vsub(double *vdst, const double *vsrc, ae_int_t N); - -void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); -void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); - -void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); -void vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha); - -void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); -void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); - -void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); -void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); - -void vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); -void vmul(double *vdst, ae_int_t N, double alpha); - -void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); -void vmul(alglib::complex *vdst, ae_int_t N, double alpha); - -void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha); -void vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha); - - - -/******************************************************************** -string conversion functions !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -********************************************************************/ - -/******************************************************************** -1- and 2-dimensional arrays -********************************************************************/ -class ae_vector_wrapper -{ -public: - ae_vector_wrapper(); - virtual ~ae_vector_wrapper(); - - void setlength(ae_int_t iLen); - ae_int_t length() const; - - void attach_to(alglib_impl::ae_vector *ptr); - void allocate_own(ae_int_t size, alglib_impl::ae_datatype datatype); - const alglib_impl::ae_vector* c_ptr() const; - alglib_impl::ae_vector* c_ptr(); -private: - ae_vector_wrapper(const ae_vector_wrapper &rhs); - const ae_vector_wrapper& operator=(const ae_vector_wrapper &rhs); -protected: - // - // Copies source vector RHS into current object. - // - // Current object is considered empty (this function should be - // called from copy constructor). - // - void create(const ae_vector_wrapper &rhs); - - // - // Copies array given by string into current object. Additional - // parameter DATATYPE contains information about type of the data - // in S and type of the array to create. - // - // Current object is considered empty (this function should be - // called from copy constructor). - // - void create(const char *s, alglib_impl::ae_datatype datatype); - - // - // Assigns RHS to current object. - // - // It has several branches depending on target object status: - // * in case it is proxy object, data are copied into memory pointed by - // proxy. Function checks that source has exactly same size as target - // (exception is thrown on failure). - // * in case it is non-proxy object, data allocated by object are cleared - // and a copy of RHS is created in target. - // - // NOTE: this function correctly handles assignments of the object to itself. - // - void assign(const ae_vector_wrapper &rhs); - - alglib_impl::ae_vector *p_vec; - alglib_impl::ae_vector vec; -}; - -class boolean_1d_array : public ae_vector_wrapper -{ -public: - boolean_1d_array(); - boolean_1d_array(const char *s); - boolean_1d_array(const boolean_1d_array &rhs); - boolean_1d_array(alglib_impl::ae_vector *p); - const boolean_1d_array& operator=(const boolean_1d_array &rhs); - virtual ~boolean_1d_array() ; - - const ae_bool& operator()(ae_int_t i) const; - ae_bool& operator()(ae_int_t i); - - const ae_bool& operator[](ae_int_t i) const; - ae_bool& operator[](ae_int_t i); - - void setcontent(ae_int_t iLen, const bool *pContent ); - ae_bool* getcontent(); - const ae_bool* getcontent() const; - - std::string tostring() const; -}; - -class integer_1d_array : public ae_vector_wrapper -{ -public: - integer_1d_array(); - integer_1d_array(const char *s); - integer_1d_array(const integer_1d_array &rhs); - integer_1d_array(alglib_impl::ae_vector *p); - const integer_1d_array& operator=(const integer_1d_array &rhs); - virtual ~integer_1d_array(); - - const ae_int_t& operator()(ae_int_t i) const; - ae_int_t& operator()(ae_int_t i); - - const ae_int_t& operator[](ae_int_t i) const; - ae_int_t& operator[](ae_int_t i); - - void setcontent(ae_int_t iLen, const ae_int_t *pContent ); - - ae_int_t* getcontent(); - const ae_int_t* getcontent() const; - - std::string tostring() const; -}; - -class real_1d_array : public ae_vector_wrapper -{ -public: - real_1d_array(); - real_1d_array(const char *s); - real_1d_array(const real_1d_array &rhs); - real_1d_array(alglib_impl::ae_vector *p); - const real_1d_array& operator=(const real_1d_array &rhs); - virtual ~real_1d_array(); - - const double& operator()(ae_int_t i) const; - double& operator()(ae_int_t i); - - const double& operator[](ae_int_t i) const; - double& operator[](ae_int_t i); - - void setcontent(ae_int_t iLen, const double *pContent ); - double* getcontent(); - const double* getcontent() const; - - std::string tostring(int dps) const; -}; - -class complex_1d_array : public ae_vector_wrapper -{ -public: - complex_1d_array(); - complex_1d_array(const char *s); - complex_1d_array(const complex_1d_array &rhs); - complex_1d_array(alglib_impl::ae_vector *p); - const complex_1d_array& operator=(const complex_1d_array &rhs); - virtual ~complex_1d_array(); - - const alglib::complex& operator()(ae_int_t i) const; - alglib::complex& operator()(ae_int_t i); - - const alglib::complex& operator[](ae_int_t i) const; - alglib::complex& operator[](ae_int_t i); - - void setcontent(ae_int_t iLen, const alglib::complex *pContent ); - alglib::complex* getcontent(); - const alglib::complex* getcontent() const; - - std::string tostring(int dps) const; -}; - -class ae_matrix_wrapper -{ -public: - ae_matrix_wrapper(); - virtual ~ae_matrix_wrapper(); - const ae_matrix_wrapper& operator=(const ae_matrix_wrapper &rhs); - - void setlength(ae_int_t rows, ae_int_t cols); - ae_int_t rows() const; - ae_int_t cols() const; - bool isempty() const; - ae_int_t getstride() const; - - void attach_to(alglib_impl::ae_matrix *ptr); - void allocate_own(ae_int_t rows, ae_int_t cols, alglib_impl::ae_datatype datatype); - const alglib_impl::ae_matrix* c_ptr() const; - alglib_impl::ae_matrix* c_ptr(); -private: - ae_matrix_wrapper(const ae_matrix_wrapper &rhs); -protected: - // - // Copies source matrix RHS into current object. - // - // Current object is considered empty (this function should be - // called from copy constructor). - // - void create(const ae_matrix_wrapper &rhs); - - // - // Copies array given by string into current object. Additional - // parameter DATATYPE contains information about type of the data - // in S and type of the array to create. - // - // Current object is considered empty (this function should be - // called from copy constructor). - // - void create(const char *s, alglib_impl::ae_datatype datatype); - - // - // Assigns RHS to current object. - // - // It has several branches depending on target object status: - // * in case it is proxy object, data are copied into memory pointed by - // proxy. Function checks that source has exactly same size as target - // (exception is thrown on failure). - // * in case it is non-proxy object, data allocated by object are cleared - // and a copy of RHS is created in target. - // - // NOTE: this function correctly handles assignments of the object to itself. - // - void assign(const ae_matrix_wrapper &rhs); - - alglib_impl::ae_matrix *p_mat; - alglib_impl::ae_matrix mat; -}; - -class boolean_2d_array : public ae_matrix_wrapper -{ -public: - boolean_2d_array(); - boolean_2d_array(const boolean_2d_array &rhs); - boolean_2d_array(alglib_impl::ae_matrix *p); - boolean_2d_array(const char *s); - virtual ~boolean_2d_array(); - - const ae_bool& operator()(ae_int_t i, ae_int_t j) const; - ae_bool& operator()(ae_int_t i, ae_int_t j); - - const ae_bool* operator[](ae_int_t i) const; - ae_bool* operator[](ae_int_t i); - - void setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ); - - std::string tostring() const ; -}; - -class integer_2d_array : public ae_matrix_wrapper -{ -public: - integer_2d_array(); - integer_2d_array(const integer_2d_array &rhs); - integer_2d_array(alglib_impl::ae_matrix *p); - integer_2d_array(const char *s); - virtual ~integer_2d_array(); - - const ae_int_t& operator()(ae_int_t i, ae_int_t j) const; - ae_int_t& operator()(ae_int_t i, ae_int_t j); - - const ae_int_t* operator[](ae_int_t i) const; - ae_int_t* operator[](ae_int_t i); - - void setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ); - - std::string tostring() const; -}; - -class real_2d_array : public ae_matrix_wrapper -{ -public: - real_2d_array(); - real_2d_array(const real_2d_array &rhs); - real_2d_array(alglib_impl::ae_matrix *p); - real_2d_array(const char *s); - virtual ~real_2d_array(); - - const double& operator()(ae_int_t i, ae_int_t j) const; - double& operator()(ae_int_t i, ae_int_t j); - - const double* operator[](ae_int_t i) const; - double* operator[](ae_int_t i); - - void setcontent(ae_int_t irows, ae_int_t icols, const double *pContent ); - - std::string tostring(int dps) const; -}; - -class complex_2d_array : public ae_matrix_wrapper -{ -public: - complex_2d_array(); - complex_2d_array(const complex_2d_array &rhs); - complex_2d_array(alglib_impl::ae_matrix *p); - complex_2d_array(const char *s); - virtual ~complex_2d_array(); - - const alglib::complex& operator()(ae_int_t i, ae_int_t j) const; - alglib::complex& operator()(ae_int_t i, ae_int_t j); - - const alglib::complex* operator[](ae_int_t i) const; - alglib::complex* operator[](ae_int_t i); - - void setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ); - - std::string tostring(int dps) const; -}; - - - -/******************************************************************** -dataset information. - -can store regression dataset, classification dataset, or non-labeled -task: -* nout==0 means non-labeled task (clustering, for example) -* nout>0 && nclasses==0 means regression task -* nout>0 && nclasses>0 means classification task -********************************************************************/ -/*class dataset -{ -public: - dataset():nin(0), nout(0), nclasses(0), trnsize(0), valsize(0), tstsize(0), totalsize(0){}; - - int nin, nout, nclasses; - - int trnsize; - int valsize; - int tstsize; - int totalsize; - - alglib::real_2d_array trn; - alglib::real_2d_array val; - alglib::real_2d_array tst; - alglib::real_2d_array all; -}; - -bool opendataset(std::string file, dataset *pdataset); - -// -// internal functions -// -std::string strtolower(const std::string &s); -bool readstrings(std::string file, std::list *pOutput); -bool readstrings(std::string file, std::list *pOutput, std::string comment); -void explodestring(std::string s, char sep, std::vector *pOutput); -std::string xtrim(std::string s);*/ - -/******************************************************************** -Constants and functions introduced for compatibility with AlgoPascal -********************************************************************/ -extern const double machineepsilon; -extern const double maxrealnumber; -extern const double minrealnumber; -extern const double fp_nan; -extern const double fp_posinf; -extern const double fp_neginf; -extern const ae_int_t endianness; - -int sign(double x); -double randomreal(); -ae_int_t randominteger(ae_int_t maxv); -int round(double x); -int trunc(double x); -int ifloor(double x); -int iceil(double x); -double pi(); -double sqr(double x); -int maxint(int m1, int m2); -int minint(int m1, int m2); -double maxreal(double m1, double m2); -double minreal(double m1, double m2); - -bool fp_eq(double v1, double v2); -bool fp_neq(double v1, double v2); -bool fp_less(double v1, double v2); -bool fp_less_eq(double v1, double v2); -bool fp_greater(double v1, double v2); -bool fp_greater_eq(double v1, double v2); - -bool fp_isnan(double x); -bool fp_isposinf(double x); -bool fp_isneginf(double x); -bool fp_isinf(double x); -bool fp_isfinite(double x); - - -}//namespace alglib - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTIONS CONTAINS DECLARATIONS FOR OPTIMIZED LINEAR ALGEBRA CODES -// IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES -// -///////////////////////////////////////////////////////////////////////// - -namespace alglib_impl -{ -#define ALGLIB_INTERCEPTS_ABLAS -void _ialglib_vzero(ae_int_t n, double *p, ae_int_t stride); -void _ialglib_vzero_complex(ae_int_t n, ae_complex *p, ae_int_t stride); -void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb); -void _ialglib_vcopy_complex(ae_int_t n, const ae_complex *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); -void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); -void _ialglib_mcopyblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_int_t stride, double *b); -void _ialglib_mcopyunblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, double *b, ae_int_t stride); -void _ialglib_mcopyblock_complex(ae_int_t m, ae_int_t n, const ae_complex *a, ae_int_t op, ae_int_t stride, double *b); -void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride); - -ae_bool _ialglib_i_rmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - ae_matrix *b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc); -ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - ae_matrix *b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc); -ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2); -ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2); -ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2); -ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - ae_matrix *x, - ae_int_t i2, - ae_int_t j2); -ae_bool _ialglib_i_cmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper); -ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, - ae_int_t k, - double alpha, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - ae_matrix *c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper); -ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_vector *u, - ae_int_t uoffs, - ae_vector *v, - ae_int_t voffs); -ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, - ae_int_t n, - ae_matrix *a, - ae_int_t ia, - ae_int_t ja, - ae_vector *u, - ae_int_t uoffs, - ae_vector *v, - ae_int_t voffs); - - - -} - - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS PARALLEL SUBROUTINES -// -///////////////////////////////////////////////////////////////////////// - -namespace alglib_impl -{ - -} - - -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _ap_h +#define _ap_h + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__CODEGEARC__) +#include +#include +#elif defined(__BORLANDC__) +#include +#include +#else +#include +#include +#endif + +#define AE_USE_CPP +/* Definitions */ +#define AE_UNKNOWN 0 +#define AE_INTEL 1 +#define AE_SPARC 2 +#define AE_AARCH64 3 + +/* OS definitions */ +#define AE_WINDOWS 1 +#define AE_POSIX 2 +#define AE_LINUX 304 +#if !defined(AE_OS) +#define AE_OS AE_UNKNOWN +#endif +#if AE_OS==AE_LINUX +#undef AE_OS +#define AE_OS AE_POSIX +#define _ALGLIB_USE_LINUX_EXTENSIONS +#endif + +/* return types for worker functions for different OS types*/ +#if AE_OS==AE_WINDOWS +#define _ALGLIB_THREAD_RETURN_TYPE DWORD WINAPI +#define _ALGLIB_THREAD_RETURN return 0 +#elif AE_OS==AE_POSIX +#define _ALGLIB_THREAD_RETURN_TYPE void* +#define _ALGLIB_THREAD_RETURN return NULL +#else +#define _ALGLIB_THREAD_RETURN_TYPE void +#define _ALGLIB_THREAD_RETURN return +#endif + +/* threading models for AE_THREADING */ +#define AE_PARALLEL 100 +#define AE_SERIAL 101 +#define AE_SERIAL_UNSAFE 102 +#if !defined(AE_THREADING) +#define AE_THREADING AE_PARALLEL +#endif + +/* which entropy source to use */ +#define ALGLIB_ENTROPY_SRC_STDRAND 0 +#define ALGLIB_ENTROPY_SRC_OPENSSL 1 + +/* malloc types for AE_MALLOC */ +#define AE_STDLIB_MALLOC 200 +#define AE_BASIC_STATIC_MALLOC 201 +#if !defined(AE_MALLOC) +#define AE_MALLOC AE_STDLIB_MALLOC +#endif + +#define AE_LOCK_ALIGNMENT 16 + +/* automatically determine compiler */ +#define AE_MSVC 1 +#define AE_GNUC 2 +#define AE_SUNC 3 +#define AE_COMPILER AE_UNKNOWN +#ifdef __GNUC__ +#undef AE_COMPILER +#define AE_COMPILER AE_GNUC +#endif +#if defined(__SUNPRO_C)||defined(__SUNPRO_CC) +#undef AE_COMPILER +#define AE_COMPILER AE_SUNC +#endif +#ifdef _MSC_VER + #undef AE_COMPILER + #define AE_COMPILER AE_MSVC + #if (_MSC_VER<1600) + #if !defined(AE_NO_AVX2) + #define AE_NO_AVX2 + #endif + #if !defined(AE_NO_FMA) + #define AE_NO_FMA + #endif + #endif +#endif + +/* compiler-specific definitions */ +#if AE_COMPILER==AE_MSVC +#define ALIGNED __declspec(align(8)) +#elif AE_COMPILER==AE_GNUC +#define ALIGNED __attribute__((aligned(8))) +#else +#define ALIGNED +#endif + +/* determine thread_local support */ +#if defined(__cplusplus) && (__cplusplus >=201103L) +#define _ALGLIB_HAS_THREADLOCAL +#define _ALGLIB_THREADLOCAL thread_local +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__>=201112L) +#define _ALGLIB_HAS_THREADLOCAL +#define _ALGLIB_THREADLOCAL _Thread_local +#endif + +/* state flags */ +#define _ALGLIB_FLG_THREADING_MASK_WRK 0x7ULL +#define _ALGLIB_FLG_THREADING_MASK_CBK (0x7ULL<<3) +#define _ALGLIB_FLG_BACKEND_MASK_LINALG (0x3ULL<<6) +#define _ALGLIB_FLG_BACKEND_MASK_DSS (0x3ULL<<8) +#define _ALGLIB_FLG_USE_GLOBAL 0x0ULL + +#define _ALGLIB_FLG_THREADING_MASK_ALL (_ALGLIB_FLG_THREADING_MASK_WRK|_ALGLIB_FLG_THREADING_MASK_CBK) +#define _ALGLIB_FLG_THREADING_SERIAL 0x1ULL +#define _ALGLIB_FLG_THREADING_PARALLEL 0x2ULL +#define _ALGLIB_FLG_THREADING_SERIAL_CALLBACKS (0x1ULL<<3) +#define _ALGLIB_FLG_THREADING_PARALLEL_CALLBACKS (0x2ULL<<3) + +#define _ALGLIB_FLG_BACKEND_LINALG (0x1ULL<<6) +#define _ALGLIB_FLG_BACKEND_NOLINALG (0x2ULL<<6) + +#define _ALGLIB_FLG_BACKEND_DSS (0x1ULL<<8) +#define _ALGLIB_FLG_BACKEND_NODSS (0x2ULL<<8) + +#define _ALGLIB_FLG_BACKEND_USE_ALL (_ALGLIB_FLG_BACKEND_LINALG|_ALGLIB_FLG_BACKEND_DSS) + +#define _ALGLIB_FLG_WORKER_THREAD (0x1ULL<<63) + + +/* now we are ready to include headers */ +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(AE_HAVE_STDINT) +#include +#endif + +/* + * CPU-specific definitions + * + */ +#if defined(AE_CPU) && (AE_CPU==AE_INTEL) + /* + * Intel SIMD intrinsics + * + * Preprocessor directives below: + * - include headers for SSE2/AVX2/AVX2+FMA3 intrinsics + * - defines _ALGLIB_HAS_SSE2_INTRINSICS, _ALGLIB_HAS_AVX2_INTRINSICS and _ALGLIB_HAS_FMA_INTRINSICS definitions + * + * These actions are performed when we have: + * - x86 architecture definition (AE_CPU==AE_INTEL) + * - compiler which supports intrinsics + * + * Presence of _ALGLIB_HAS_???_INTRINSICS does NOT mean that our CPU + * actually supports these intrinsics - such things should be determined + * at runtime with ae_cpuid() call. It means that we are working under + * Intel and out compiler can issue SIMD-capable code. + * + */ + #if AE_COMPILER==AE_MSVC + /* + * MSVC is detected. + * We assume that compiler supports all instruction sets + * unless something is explicitly turned off. + */ + #if !defined(AE_NO_SSE2) + #include + #define AE_HAS_SSE2_INTRINSICS + #define _ALGLIB_HAS_SSE2_INTRINSICS + #if !defined(AE_NO_AVX2) + #include + #define _ALGLIB_HAS_AVX2_INTRINSICS + #if !defined(AE_NO_FMA) + #define _ALGLIB_HAS_FMA_INTRINSICS + #endif + #endif + #endif + #elif AE_COMPILER==AE_GNUC + /* + * GCC/CLANG/ICC is detected. + * We assume that compiler supports all instruction sets + * unless something is explicitly turned off. + */ + #if !defined(AE_NO_SSE2) + #include + #define AE_HAS_SSE2_INTRINSICS + #define _ALGLIB_HAS_SSE2_INTRINSICS + #if !defined(AE_NO_AVX2) + #include + #define _ALGLIB_HAS_AVX2_INTRINSICS + #if !defined(AE_NO_FMA) + #define _ALGLIB_HAS_FMA_INTRINSICS + #endif + #endif + #endif + #elif AE_COMPILER==AE_SUNC + /* + * Sun studio + */ + #include + #include + #define AE_HAS_SSE2_INTRINSICS + #define _ALGLIB_HAS_SSE2_INTRINSICS + #include + #define _ALGLIB_HAS_AVX2_INTRINSICS + #define _ALGLIB_HAS_FMA_INTRINSICS + #else + /* + * Unknown compiler + */ + #if !defined(AE_NO_SSE2) + #include + #define AE_HAS_SSE2_INTRINSICS + #define _ALGLIB_HAS_SSE2_INTRINSICS + #if !defined(AE_NO_AVX2) + #define _ALGLIB_HAS_AVX2_INTRINSICS + #if !defined(AE_NO_FMA) + #define _ALGLIB_HAS_FMA_INTRINSICS + #endif + #endif + #endif + #endif + + /* + * Intel integrity checks + */ + #if defined(_ALGLIB_INTEGRITY_CHECKS_ONCE) + #if defined(_ALGLIB_FAIL_WITHOUT_FMA_INTRINSICS) && !defined(_ALGLIB_HAS_FMA_INTRINSICS) +#error ALGLIB was requested to fail without FMA intrinsics + #endif + #endif +#elif defined(AE_CPU) && (AE_CPU==AE_AARCH64) + /* + * AArch64 (ARM V8+) definitions + */ +#endif + + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS DECLARATIONS FOR BASIC FUNCTIONALITY +// LIKE MEMORY MANAGEMENT FOR VECTORS/MATRICES WHICH IS SHARED +// BETWEEN C++ AND PURE C LIBRARIES +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ + +/* if we work under C++ environment, define several conditions */ +#ifdef AE_USE_CPP +#define AE_USE_CPP_BOOL +#define AE_USE_CPP_SERIALIZATION +#include +#endif + +/* + * define ae_int32_t, ae_int64_t, ae_int_t, ae_bool, ae_complex, ae_error_type and ae_datatype + */ + +#if defined(AE_INT32_T) +typedef AE_INT32_T ae_int32_t; +#endif +#if defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) +typedef int32_t ae_int32_t; +#endif +#if !defined(AE_HAVE_STDINT) && !defined(AE_INT32_T) +#if AE_COMPILER==AE_MSVC +typedef __int32 ae_int32_t; +#endif +#if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) +typedef int ae_int32_t; +#endif +#endif + +#if defined(AE_INT64_T) +typedef AE_INT64_T ae_int64_t; +#endif +#if defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) +typedef int64_t ae_int64_t; +#endif +#if !defined(AE_HAVE_STDINT) && !defined(AE_INT64_T) +#if AE_COMPILER==AE_MSVC +typedef __int64 ae_int64_t; +#endif +#if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) +typedef signed long long ae_int64_t; +#endif +#endif + +#if defined(AE_UINT64_T) +typedef AE_UINT64_T ae_uint64_t; +#endif +#if defined(AE_HAVE_STDINT) && !defined(AE_UINT64_T) +typedef uint64_t ae_uint64_t; +#endif +#if !defined(AE_HAVE_STDINT) && !defined(AE_UINT64_T) +#if AE_COMPILER==AE_MSVC +typedef unsigned __int64 ae_uint64_t; +#endif +#if (AE_COMPILER==AE_GNUC) || (AE_COMPILER==AE_SUNC) || (AE_COMPILER==AE_UNKNOWN) +typedef unsigned long long ae_uint64_t; +#endif +#endif + +#if !defined(AE_INT_T) +typedef ptrdiff_t ae_int_t; +#endif + +#if !defined(AE_USE_CPP_BOOL) +#define ae_bool char +#define ae_true 1 +#define ae_false 0 +#else +#define ae_bool bool +#define ae_true true +#define ae_false false +#endif + +typedef struct { double x, y; } ae_complex; + +typedef enum +{ + ERR_OK = 0, + ERR_OUT_OF_MEMORY = 1, + ERR_XARRAY_TOO_LARGE = 2, + ERR_ASSERTION_FAILED = 3 +} ae_error_type; + +typedef ae_int_t ae_datatype; + +/* + * other definitions + */ +enum { INIT_ATTACH_OR_COPY=1 }; +enum { ACT_DROP_ON_REALLOC=1, ACT_XFREE_ON_REALLOC=2 }; +enum { ACT_UNCHANGED=1, ACT_SAME_LOCATION=2, ACT_NEW_LOCATION=3 }; +enum { DT_BOOL=1, DT_BYTE=1, DT_INT=2, DT_REAL=3, DT_COMPLEX=4 }; +enum { CPU_SSE2=0x1, CPU_AVX2=0x2, CPU_FMA=0x4 }; +typedef void(*ae_destructor)(void*); + +/************************************************************************ +x-string (zero-terminated): + owner ACT_DROP_ON_REALLOC or ACT_XFREE_ON_REALLOC. Determines what to do on realloc(). + If vector is owned by caller, X-interface will just set + ptr to NULL before realloc(). If it is owned by X, it + will call ae_free/x_free/aligned_free family functions. + + last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION + contents is either: unchanged, stored at the same location, + stored at the new location. + this field is set on return from X. + + ptr pointer to the actual data + +Members of this structure are ae_int64_t to avoid alignment problems. +************************************************************************/ +typedef struct +{ + ALIGNED ae_int64_t owner; + ALIGNED ae_int64_t last_action; + ALIGNED char *ptr; +} x_string; + +/************************************************************************ +x-vector: + cnt number of elements + + datatype one of the DT_XXXX values + + owner ACT_DROP_ON_REALLOC or ACT_XFREE_ON_REALLOC. Determines what to do on realloc(). + If vector is owned by caller, X-interface will just set + ptr to NULL before realloc(). If it is owned by X, it + will call ae_free/x_free/aligned_free family functions. + + last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION + contents is either: unchanged, stored at the same location, + stored at the new location. + this field is set on return from X interface and may be + used by caller as hint when deciding what to do with data + (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array + reallocation or copying is required). + + ptr pointer to the actual data + +Members of this structure are ae_int64_t to avoid alignment problems. +************************************************************************/ +typedef struct +{ + ae_int64_t cnt; + ae_int64_t datatype; + ae_int64_t owner; + ae_int64_t last_action; + union + { + void *p_ptr; + ae_int64_t portable_alignment_enforcer; + } x_ptr; +} x_vector; + + +/************************************************************************ +x-matrix: + rows number of rows. may be zero only when cols is zero too. + + cols number of columns. may be zero only when rows is zero too. + + stride stride, i.e. distance between first elements of rows (in bytes) + + datatype one of the DT_XXXX values + + owner ACT_DROP_ON_REALLOC or ACT_XFREE_ON_REALLOC. Determines what to do on realloc(). + If vector is owned by caller, X-interface will just set + ptr to NULL before realloc(). If it is owned by X, it + will call ae_free/x_free/aligned_free family functions. + + last_action ACT_UNCHANGED, ACT_SAME_LOCATION, ACT_NEW_LOCATION + contents is either: unchanged, stored at the same location, + stored at the new location. + this field is set on return from X interface and may be + used by caller as hint when deciding what to do with data + (if it was ACT_UNCHANGED or ACT_SAME_LOCATION, no array + reallocation or copying is required). + + ptr pointer to the actual data, stored rowwise + +Members of this structure are ae_int64_t to avoid alignment problems. +************************************************************************/ +typedef struct +{ + ae_int64_t rows; + ae_int64_t cols; + ae_int64_t stride; + ae_int64_t datatype; + ae_int64_t owner; + ae_int64_t last_action; + union + { + void *p_ptr; + ae_int64_t portable_alignment_enforcer; + } x_ptr; +} x_matrix; + + +/************************************************************************ +dynamic block which may be automatically deallocated during stack unwinding + +p_next next block in the stack unwinding list. + NULL means that this block is not in the list +deallocator deallocator function which should be used to deallocate block. + NULL for "special" blocks (frame/stack boundaries) +ptr pointer which should be passed to the deallocator. + may be null (for zero-size block), DYN_BOTTOM or DYN_FRAME + for "special" blocks (frame/stack boundaries). + +valgrind_hint is a special field which stores a special hint pointer for + Valgrind and other similar memory checking tools. ALGLIB + manually aligns pointers obtained via malloc, so ptr usually + points to location past the beginning of the actuallly + allocated memory. In such cases memory testing tools may + report "(possibly) lost" memory. + + This "hint" field stores pointer actually returned by + malloc (or NULL, if for some reason we do not support + this feature). This field is used merely as a hint for + Valgrind - it should NOT be used for anything else. + +************************************************************************/ +typedef struct ae_dyn_block +{ + struct ae_dyn_block * volatile p_next; + ae_destructor deallocator; + void * volatile ptr; + void* valgrind_hint; +} ae_dyn_block; + + +/************************************************************************ +frame marker +************************************************************************/ +typedef struct ae_frame +{ + ae_dyn_block db_marker; +} ae_frame; + +/************************************************************************ +ALGLIB environment state +************************************************************************/ +typedef struct ae_state +{ + /* + * endianness type: AE_LITTLE_ENDIAN or AE_BIG_ENDIAN + */ + ae_int_t endianness; + + /* + * double value for NAN + */ + double v_nan; + + /* + * double value for +INF + */ + double v_posinf; + + /* + * double value for -INF + */ + double v_neginf; + + /* + * pointer to the top block in a stack of frames + * which hold dynamically allocated objects + */ + ae_dyn_block * volatile p_top_block; + ae_dyn_block last_block; + + /* + * jmp_buf pointer for internal C-style exception handling + */ + jmp_buf * volatile break_jump; + + /* + * ae_error_type of the last error (filled when exception is thrown) + */ + ae_error_type volatile last_error; + + /* + * human-readable message (filled when exception is thrown) + */ + const char* volatile error_msg; + + /* + * Flags: call-local settings for ALGLIB + */ + ae_uint64_t flags; + + /* + * threading information: + * a) current thread pool + * b) current worker thread + * c) parent task (one we are solving right now) + * d) thread exception handler (function which must be called + * by ae_assert before raising exception). + * + * NOTE: we use void* to store pointers in order to avoid explicit dependency on smp.h + */ + void *worker_thread; + void *parent_task; + void (*thread_exception_handler)(void*); + +} ae_state; + +typedef void(*ae_constructor)(void*,ae_state*,ae_bool); +typedef void(*ae_copy_constructor)(void*,const void*,ae_state*,ae_bool); +typedef void(*ae_opaque_copy_constructor)(void*,const void*,ae_state*); + + +/************************************************************************ +Serializer: + +* ae_stream_writer type is a function pointer for stream writer method; + this pointer is used by X-core for out-of-core serialization (say, to + serialize ALGLIB structure directly to managed C# stream). + + This function accepts two parameters: pointer to ANSI (7-bit) string + and pointer-sized integer passed to serializer during initialization. + String being passed is a part of the data stream; aux paramerer may be + arbitrary value intended to be used by actual implementation of stream + writer. String parameter may include spaces and linefeed symbols, it + should be written to stream as is. + + Return value must be zero for success or non-zero for failure. + +* ae_stream_reader type is a function pointer for stream reader method; + this pointer is used by X-core for out-of-core unserialization (say, to + unserialize ALGLIB structure directly from managed C# stream). + + This function accepts three parameters: pointer-sized integer passed to + serializer during initialization; number of symbols to read from + stream; pointer to buffer used to store next token read from stream + (ANSI encoding is used, buffer is large enough to store all symbols and + trailing zero symbol). + + Number of symbols to read is always positive. + + After being called by X-core, this function must: + * skip all space and linefeed characters from the current position at + the stream and until first non-space non-linefeed character is found + * read exactly cnt symbols from stream to buffer; check that all + symbols being read are non-space non-linefeed ones + * append trailing zero symbol to buffer + * return value must be zero on success, non-zero if even one of the + conditions above fails. When reader returns non-zero value, contents + of buf is not used. +************************************************************************/ +typedef char(*ae_stream_writer)(const char *p_string, ae_int_t aux); +typedef char(*ae_stream_reader)(ae_int_t aux, ae_int_t cnt, char *p_buf); + +typedef struct +{ + ae_int_t mode; + ae_int_t entries_needed; + ae_int_t entries_saved; + ae_int_t bytes_asked; + ae_int_t bytes_written; + +#ifdef AE_USE_CPP_SERIALIZATION + std::string *out_cppstr; +#endif + char *out_str; /* pointer to the current position at the output buffer; advanced with each write operation */ + const char *in_str; /* pointer to the current position at the input buffer; advanced with each read operation */ + ae_int_t stream_aux; + ae_stream_writer stream_writer; + ae_stream_reader stream_reader; +} ae_serializer; + + +typedef struct ae_vector +{ + /* + * Number of elements in array, cnt>=0 + */ + ae_int_t cnt; + + /* + * Either DT_BOOL/DT_BYTE, DT_INT, DT_REAL or DT_COMPLEX + */ + ae_datatype datatype; + + /* + * If ptr points to memory owned and managed by ae_vector itself, + * this field is ae_false. If vector was attached to x_vector structure + * with ae_vector_init_attach_to_x(), this field is ae_true. + */ + ae_bool is_attached; + + /* + * ae_dyn_block structure which manages data in ptr. This structure + * is responsible for automatic deletion of object when its frame + * is destroyed. + */ + ae_dyn_block data; + + /* + * Pointer to data. + * User usually works with this field. + */ + union + { + void *p_ptr; + ae_bool *p_bool; + unsigned char *p_ubyte; + ae_int_t *p_int; + double *p_double; + ae_complex *p_complex; + } ptr; +} ae_vector; + +typedef struct ae_matrix +{ + ae_int_t rows; + ae_int_t cols; + ae_int_t stride; + ae_datatype datatype; + + /* + * If ptr points to memory owned and managed by ae_vector itself, + * this field is ae_false. If vector was attached to x_vector structure + * with ae_vector_init_attach_to_x(), this field is ae_true. + */ + ae_bool is_attached; + + ae_dyn_block data; + union + { + void *p_ptr; + void **pp_void; + ae_bool **pp_bool; + ae_int_t **pp_int; + double **pp_double; + ae_complex **pp_complex; + } ptr; +} ae_matrix; + +typedef struct ae_smart_ptr +{ + /* pointer to subscriber; all changes in ptr are translated to subscriber */ + void **subscriber; + + /* pointer to object */ + void *ptr; + + /* whether smart pointer owns ptr */ + ae_bool is_owner; + + /* whether ownership can be released or not; + if exclusive, any attempt to transfer ownership will result in an exception; + the pointer can be free, though + */ + ae_bool exclusive; + + /* whether object pointed by ptr is dynamic - clearing such object requires BOTH + calling destructor function AND calling ae_free for memory occupied by object. */ + ae_bool is_dynamic; + + /* size of object; this field is used when we pass the object to ae_obj_array; it is zero for non-owned pointers */ + ae_int_t size_of_object; + + /* copy constructor for the pointer */ + ae_copy_constructor copy_constructor; + + /* destructor function for pointer; clears all dynamically allocated memory */ + ae_destructor destructor; + + /* frame entry; used to ensure automatic deallocation of smart pointer in case of exception/exit */ + ae_dyn_block frame_entry; +} ae_smart_ptr; + +typedef struct ae_opaque_object +{ + /* opaque object pointer; NULL for uninitialized */ + void *ptr; + + /* opaque object type, an integer constant, used to perform integrity checks by consumers; zero for uninitialized */ + ae_int_t obj_type; + + /* opaque object size, >0 for initialized, zero for uninitialized */ + ae_int_t obj_size; + + /* copy constructor for the pointer */ + ae_opaque_copy_constructor opaque_copy_constructor; + + /* destructor function for pointer; clears all dynamically allocated memory */ + ae_destructor destructor; + + /* frame entry; used to ensure automatic deallocation of object in case of exception/exit */ + ae_dyn_block frame_entry; +} ae_opaque_object; + +static const ae_int_t _ALGLIB_PBL_DSS = 1; + + +/************************************************************************* +Lock. + +This structure provides OS-independent non-reentrant lock: +* under Windows/Posix systems it uses system-provided locks +* under Boost it uses OS-independent lock provided by Boost package +* when no OS is defined, it uses "fake lock" (just stub which is not thread-safe): + a) "fake lock" can be in locked or free mode + b) "fake lock" can be used only from one thread - one which created lock + c) when thread acquires free lock, it immediately returns + d) when thread acquires busy lock, program is terminated + (because lock is already acquired and no one else can free it) +*************************************************************************/ +typedef struct +{ + /* + * Pointer to _lock structure. This pointer has type void* in order to + * make header file OS-independent (lock declaration depends on OS). + */ + void *lock_ptr; + + /* + * For eternal=false this field manages pointer to _lock structure. + * + * ae_dyn_block structure is responsible for automatic deletion of + * the memory allocated for the pointer when its frame is destroyed. + */ + ae_dyn_block db; + + /* + * Whether we have eternal lock object (used by thread pool) or + * transient lock. Eternal locks are allocated without using ae_dyn_block + * structure and do not allow deallocation. + */ + ae_bool eternal; +} ae_lock; + +typedef struct ae_obj_array +{ + /* elements count */ + ae_int_t cnt; + + /* storage size */ + ae_int_t capacity; + + /* whether capacity can be automatically increased or not */ + ae_bool fixed_capacity; + + /* pointers to objects */ + void **pp_obj_ptr; + + /* pointers to object sizes */ + ae_int_t *pp_obj_sizes; + + /* pointers to deallocators */ + ae_copy_constructor *pp_copy; + + /* pointers to destructors */ + ae_destructor *pp_destroy; + + /* primary synchronization lock, used for thread-safe appends */ + ae_lock array_lock; + + /* frame entry; used to ensure automatic deallocation of array and its elements in case of exception/exit */ + ae_dyn_block frame_entry; +} ae_obj_array; + +typedef struct ae_nxpool +{ + /* array type */ + ae_datatype datatype; + + /* array size */ + ae_int_t array_size; + + /* current storage capacity (total dynamic blocks count) */ + ae_int_t capacity; + + /* number of dynamic blocks storing arrays (first elements of storage[]) */ + ae_int_t nstored; + + /* array storage */ + ae_dyn_block storage; + + /* primary synchronization lock, used for thread-safe operations */ + ae_lock pool_lock; + + /* frame entry; used to ensure automatic deallocation of the pool and its elements in case of exception/exit */ + ae_dyn_block frame_entry; +} ae_nxpool; + +/************************************************************************* +Shared pool: data structure used to provide thread-safe access to pool of +temporary variables. +*************************************************************************/ +typedef struct ae_shared_pool_entry +{ + void * volatile obj; + void * volatile next_entry; +} ae_shared_pool_entry; + +typedef struct ae_shared_pool +{ + /* lock object which protects pool */ + ae_lock pool_lock; + + /* seed object (used to create new instances of temporaries) */ + void * volatile seed_object; + + /* + * list of recycled OBJECTS: + * 1. entries in this list store pointers to recycled objects + * 2. every time we retrieve object, we retrieve first entry from this list, + * move it to recycled_entries and return its obj field to caller/ + */ + ae_shared_pool_entry * volatile recycled_objects; + + /* + * list of recycled ENTRIES: + * 1. this list holds entries which are not used to store recycled objects; + * every time recycled object is retrieved, its entry is moved to this list. + * 2. every time object is recycled, we try to fetch entry for him from this list + * before allocating it with malloc() + */ + ae_shared_pool_entry * volatile recycled_entries; + + /* enumeration pointer, points to current recycled object*/ + ae_shared_pool_entry * volatile enumeration_counter; + + /* size of object; this field is used when we call malloc() for new objects */ + ae_int_t size_of_object; + + /* copy constructor; accepts pointer to malloc'ed, but not initialized object */ + ae_copy_constructor init_copy; + + /* destructor function; */ + ae_destructor destroy; + + /* frame entry; contains pointer to the pool object itself */ + ae_dyn_block frame_entry; +} ae_shared_pool; + +void ae_never_call_it(); +void ae_set_dbg_flag(ae_int64_t flag_id, ae_int64_t flag_val); +ae_int64_t ae_get_dbg_value(ae_int64_t id); + +/************************************************************************ +Threading-related functions +************************************************************************/ +void ae_set_global_flags(ae_uint64_t flg_value); +ae_uint64_t ae_get_global_flags(); +#if defined(_ALGLIB_HAS_THREADLOCAL) +ae_int_t ae_get_callback_worker_idx(); +void ae_set_callback_worker_idx(ae_int_t idx); +#endif +ae_int_t get_nprocessors_cached(); + +static void ae_set_global_threading(ae_uint64_t flg_value) { ae_set_global_flags(flg_value); } + +/************************************************************************ +Debugging and tracing functions +************************************************************************/ +void ae_set_error_flag(ae_bool *p_flag, ae_bool cond, const char *filename, int lineno, const char *xdesc); +const char * ae_get_last_error_file(); +int ae_get_last_error_line(); +const char * ae_get_last_error_xdesc(); + +void ae_trace_file(const char *tags, const char *filename); +void ae_trace_stdout(const char *tags); +void ae_trace_disable(); +ae_bool ae_is_trace_enabled(const char *tag); +void ae_trace(const char * printf_fmt, ...); + +ae_int_t ae_tickcount(); + + +/************************************************************************ +... +************************************************************************/ +ae_int_t ae_misalignment(const void *ptr, size_t alignment); +void* ae_align(void *ptr, size_t alignment); +ae_int_t ae_get_effective_workers(ae_int_t nworkers); +void ae_optional_atomic_add_i(ae_int_t *p, ae_int_t v); +void ae_optional_atomic_sub_i(ae_int_t *p, ae_int_t v); +void ae_mfence_lockless(); +void ae_really_weak_store_u64(ae_uint64_t *p, ae_uint64_t v); +void ae_weak_store_release(ae_int_t *p, ae_int_t v); +ae_int_t ae_weak_atomic_load_norace(ae_int_t *p); +void* ae_weak_atomic_load_norace_ptr(void **p); +ae_int_t ae_weak_atomic_cas(ae_int_t *p, ae_int_t expect, ae_int_t store); +void* ae_weak_atomic_cas_ptr(void **p, void *expect, void *store); +ae_bool ae_weak_atomic_check_lock(ae_int_t *p, ae_int_t val_to_check); +void ae_weak_atomic_release_lock(ae_int_t *p, ae_int_t expect, ae_int_t store); + +/************************************************************************* +These functions perform thread-unsafe operations with integers. + +Basically they just read/write a value. Their existence allows us +to let ThreadSanitizer ignore reads/writes that lead to benign race conditions. +*************************************************************************/ +ae_int_t ae_unsafe_volatile_read(const ae_int_t *p); +void ae_unsafe_write(ae_int_t *dst, ae_int_t v); + +void* aligned_malloc(size_t size, size_t alignment); +void* aligned_extract_ptr(void *block); +void aligned_free(void *block); +void* eternal_malloc(size_t size); +#if AE_MALLOC==AE_BASIC_STATIC_MALLOC +void set_memory_pool(void *ptr, size_t size); +void memory_pool_stats(ae_int_t *bytes_used, ae_int_t *bytes_free); +#endif + +void* ae_malloc(size_t size, ae_state *state); +void ae_free(void *p); +ae_int_t ae_sizeof(ae_datatype datatype); +ae_bool ae_check_zeros(const void *ptr, ae_int_t n); +void ae_touch_ptr(void *p); + +ae_int_t ae_rand(); +ae_int_t ae_rand_max(); + +void ae_state_init(ae_state *state); +void ae_state_clear(ae_state *state); +void ae_state_set_break_jump(ae_state *state, jmp_buf *buf); +void ae_state_set_flags(ae_state *state, ae_uint64_t flags); +ae_uint64_t ae_get_effective_flags(ae_state *state); +void ae_clean_up_before_breaking(ae_state *state); +void ae_break(ae_state *state, ae_error_type error_type, const char *msg); + +void ae_frame_make(ae_state *state, ae_frame *tmp); +void ae_frame_leave(ae_state *state); + +void ae_db_attach(ae_dyn_block *block, ae_state *state); +void ae_db_init(ae_dyn_block *block, ae_int_t size, ae_state *state, ae_bool make_automatic); +void ae_db_realloc(ae_dyn_block *block, ae_int_t size, ae_state *state); +void ae_db_free(ae_dyn_block *block); +void ae_db_swap(ae_dyn_block *block1, ae_dyn_block *block2); + +void ae_vector_init(ae_vector *dst, ae_int_t size, ae_datatype datatype, ae_state *state, ae_bool make_automatic); +void ae_vector_init_copy(ae_vector *dst, const ae_vector *src, ae_state *state, ae_bool make_automatic); +void ae_vector_init_from_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic); +void ae_vector_init_from_x2(ae_vector *dst, x_vector *src, ae_int_t action, ae_state *state, ae_bool make_automatic); +void ae_vector_init_attach_to_x(ae_vector *dst, x_vector *src, ae_state *state, ae_bool make_automatic); +void ae_vector_set_length(ae_vector *dst, ae_int_t newsize, ae_state *state); +void ae_vector_resize(ae_vector *dst, ae_int_t newsize, ae_state *state); +void ae_vector_clear(ae_vector *dst); +void ae_vector_destroy(ae_vector *dst); +void ae_swap_vectors(ae_vector *vec1, ae_vector *vec2); + +void ae_matrix_init(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_datatype datatype, ae_state *state, ae_bool make_automatic); +void ae_matrix_init_copy(ae_matrix *dst, const ae_matrix *src, ae_state *state, ae_bool make_automatic); +void ae_matrix_init_from_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic); +void ae_matrix_init_from_x2(ae_matrix *dst, x_matrix *src, ae_int_t action, ae_state *state, ae_bool make_automatic); +void ae_matrix_init_attach_to_x(ae_matrix *dst, x_matrix *src, ae_state *state, ae_bool make_automatic); +void ae_matrix_set_length(ae_matrix *dst, ae_int_t rows, ae_int_t cols, ae_state *state); +void ae_matrix_clear(ae_matrix *dst); +void ae_matrix_destroy(ae_matrix *dst); +void ae_swap_matrices(ae_matrix *mat1, ae_matrix *mat2); + +void ae_smart_ptr_init(ae_smart_ptr *dst, void **subscriber, ae_bool exclusive, ae_state *state, ae_bool make_automatic); +void ae_smart_ptr_clear(void *_dst); /* accepts ae_smart_ptr* */ +void ae_smart_ptr_destroy(void *_dst); +void ae_smart_ptr_assign(ae_smart_ptr *dst, void *new_ptr, ae_bool is_owner, ae_bool is_dynamic, ae_int_t obj_size, ae_copy_constructor cc, ae_destructor dd); +void ae_smart_ptr_release(ae_smart_ptr *dst); + +void ae_opaque_object_init(ae_opaque_object *dst, ae_state *state, ae_bool make_automatic); +void ae_opaque_object_init_copy(ae_opaque_object *dst, const ae_opaque_object *src, ae_state *state, ae_bool make_automatic); +void ae_opaque_object_clear(void *_dst); /* accepts ae_opaque_object* */ +void ae_opaque_object_destroy(void *_dst); + +void ae_obj_array_init(ae_obj_array *dst, ae_state *state, ae_bool make_automatic); +void ae_obj_array_init_copy(ae_obj_array *dst, const ae_obj_array *src, ae_state *state, ae_bool make_automatic); +void ae_obj_array_clear(ae_obj_array *dst); +void ae_obj_array_destroy(ae_obj_array *dst); +ae_int_t ae_obj_array_get_length(const ae_obj_array *dst); +void ae_obj_array_fixed_capacity(ae_obj_array *arr, ae_int_t idx, ae_state *state); +void ae_obj_array_get(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state); +void ae_obj_array_extract_transfer(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state); +void ae_obj_array_pop_transfer(ae_obj_array *arr, ae_smart_ptr *ptr, ae_state *state); +void ae_obj_array_swap(ae_obj_array *arr, ae_int_t idx, ae_int_t idx2, ae_state *state); +void ae_obj_array_set_transfer(ae_obj_array *arr, ae_int_t idx, ae_smart_ptr *ptr, ae_state *state); +ae_int_t ae_obj_array_append_transfer(ae_obj_array *arr, ae_smart_ptr *ptr, ae_state *state); + +void ae_yield(); +void ae_init_lock(ae_lock *lock, ae_state *state, ae_bool make_automatic); +void ae_init_lock_eternal(ae_lock *lock); +void ae_acquire_lock(ae_lock *lock); +void ae_release_lock(ae_lock *lock); +void ae_free_lock(ae_lock *lock); + +void ae_shared_pool_init(void *_dst, ae_state *state, ae_bool make_automatic); +void ae_shared_pool_init_copy(void *_dst, const void *_src, ae_state *state, ae_bool make_automatic); +void ae_shared_pool_clear(void *dst); +void ae_shared_pool_destroy(void *dst); +ae_bool ae_shared_pool_is_initialized(void *_dst); +void ae_shared_pool_set_seed( + ae_shared_pool *dst, + const void *seed_object, + ae_int_t size_of_object, + ae_copy_constructor copy_constructor, + ae_destructor destructor, + ae_state *state); +void ae_shared_pool_set_seed_if_different( + ae_shared_pool *dst, + const void *seed_object, + ae_int_t size_of_object, + ae_copy_constructor copy_constructor, + ae_destructor destructor, + ae_state *state); +void ae_shared_pool_retrieve( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state); +void ae_shared_pool_recycle( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state); +void ae_shared_pool_clear_recycled( + ae_shared_pool *pool, + ae_state *state); +void ae_shared_pool_first_recycled( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state); +void ae_shared_pool_next_recycled( + ae_shared_pool *pool, + ae_smart_ptr *pptr, + ae_state *state); +void ae_shared_pool_reset( + ae_shared_pool *pool, + ae_state *state); + +void ae_nxpool_init(ae_nxpool *dst, ae_datatype datatype, ae_state *state, ae_bool make_automatic); +void ae_nxpool_init_copy(ae_nxpool *dst, const ae_nxpool *src, ae_state *state, ae_bool make_automatic); +void ae_nxpool_clear(ae_nxpool *dst); +void ae_nxpool_destroy(ae_nxpool *dst); +void ae_nxpool_alloc(ae_nxpool *pool, ae_int_t size, ae_state *state); +void ae_nxpool_retrieve(ae_nxpool *pool, ae_vector *dst, ae_state *state); +void ae_nxpool_recycle(ae_nxpool *pool, ae_vector *dst, ae_state *state); + +void ae_x_set_vector(x_vector *dst, ae_vector *src, ae_state *state); +void ae_x_set_matrix(x_matrix *dst, ae_matrix *src, ae_state *state); +void ae_x_attach_to_vector(x_vector *dst, ae_vector *src); +void ae_x_attach_to_matrix(x_matrix *dst, ae_matrix *src); + +void x_vector_clear(x_vector *dst); + +ae_bool x_is_symmetric(x_matrix *a); +ae_bool x_is_hermitian(x_matrix *a); +ae_bool x_force_symmetric(x_matrix *a); +ae_bool x_force_hermitian(x_matrix *a); +ae_bool ae_is_symmetric(ae_matrix *a); +ae_bool ae_is_hermitian(ae_matrix *a); +ae_bool ae_force_symmetric(ae_matrix *a); +ae_bool ae_force_hermitian(ae_matrix *a); + +void ae_serializer_init(ae_serializer *serializer); +void ae_serializer_clear(ae_serializer *serializer); + +void ae_serializer_alloc_start(ae_serializer *serializer); +void ae_serializer_alloc_entry(ae_serializer *serializer); +void ae_serializer_alloc_byte_array(ae_serializer *serializer, const ae_vector *bytes); +ae_int_t ae_serializer_get_alloc_size(ae_serializer *serializer); + +#ifdef AE_USE_CPP_SERIALIZATION +void ae_serializer_sstart_str(ae_serializer *serializer, std::string *buf); +void ae_serializer_ustart_str(ae_serializer *serializer, const std::string *buf); +void ae_serializer_sstart_stream(ae_serializer *serializer, std::ostream *stream); +void ae_serializer_ustart_stream(ae_serializer *serializer, const std::istream *stream); +#endif +void ae_serializer_sstart_str(ae_serializer *serializer, char *buf); +void ae_serializer_ustart_str(ae_serializer *serializer, const char *buf); +void ae_serializer_sstart_stream(ae_serializer *serializer, ae_stream_writer writer, ae_int_t aux); +void ae_serializer_ustart_stream(ae_serializer *serializer, ae_stream_reader reader, ae_int_t aux); + +void ae_serializer_serialize_bool(ae_serializer *serializer, ae_bool v, ae_state *state); +void ae_serializer_serialize_int(ae_serializer *serializer, ae_int_t v, ae_state *state); +void ae_serializer_serialize_int64(ae_serializer *serializer, ae_int64_t v, ae_state *state); +void ae_serializer_serialize_double(ae_serializer *serializer, double v, ae_state *state); +void ae_serializer_serialize_byte_array(ae_serializer *serializer, const ae_vector *bytes, ae_state *state); +void ae_serializer_unserialize_bool(ae_serializer *serializer, ae_bool *v, ae_state *state); +void ae_serializer_unserialize_int(ae_serializer *serializer, ae_int_t *v, ae_state *state); +void ae_serializer_unserialize_int64(ae_serializer *serializer, ae_int64_t *v, ae_state *state); +void ae_serializer_unserialize_double(ae_serializer *serializer, double *v, ae_state *state); +void ae_serializer_unserialize_byte_array(ae_serializer *serializer, ae_vector *bytes, ae_state *state); + +void ae_serializer_stop(ae_serializer *serializer, ae_state *state); + +/************************************************************************ +Service functions +************************************************************************/ +void ae_assert(ae_bool cond, const char *msg, ae_state *state); +ae_int_t ae_cpuid(); + +/************************************************************************ +Real math functions: +* IEEE-compliant floating point comparisons +* standard functions +************************************************************************/ +ae_bool ae_fp_eq(double v1, double v2); +ae_bool ae_fp_neq(double v1, double v2); +ae_bool ae_fp_less(double v1, double v2); +ae_bool ae_fp_less_eq(double v1, double v2); +ae_bool ae_fp_greater(double v1, double v2); +ae_bool ae_fp_greater_eq(double v1, double v2); + +ae_bool ae_isfinite_stateless(double x, ae_int_t endianness); +ae_bool ae_isnan_stateless(double x, ae_int_t endianness); +ae_bool ae_isinf_stateless(double x, ae_int_t endianness); +ae_bool ae_isposinf_stateless(double x, ae_int_t endianness); +ae_bool ae_isneginf_stateless(double x, ae_int_t endianness); + +ae_int_t ae_get_endianness(); + +ae_bool ae_isfinite(double x,ae_state *state); +ae_bool ae_isnan(double x, ae_state *state); +ae_bool ae_isinf(double x, ae_state *state); +ae_bool ae_isposinf(double x,ae_state *state); +ae_bool ae_isneginf(double x,ae_state *state); + +double ae_fabs(double x, ae_state *state); +ae_int_t ae_iabs(ae_int_t x, ae_state *state); +double ae_sqr(double x, ae_state *state); +double ae_sqrt(double x, ae_state *state); + +ae_int_t ae_sign(double x, ae_state *state); +ae_int_t ae_round(double x, ae_state *state); +ae_int_t ae_trunc(double x, ae_state *state); +ae_int_t ae_ifloor(double x, ae_state *state); +ae_int_t ae_iceil(double x, ae_state *state); + +ae_int_t ae_maxint(ae_int_t m1, ae_int_t m2, ae_state *state); +ae_int_t ae_minint(ae_int_t m1, ae_int_t m2, ae_state *state); +double ae_maxreal(double m1, double m2, ae_state *state); +double ae_minreal(double m1, double m2, ae_state *state); +double ae_randomreal(ae_state *state); +ae_int_t ae_randominteger(ae_int_t maxv, ae_state *state); + +double ae_sin(double x, ae_state *state); +double ae_cos(double x, ae_state *state); +double ae_tan(double x, ae_state *state); +double ae_sinh(double x, ae_state *state); +double ae_cosh(double x, ae_state *state); +double ae_tanh(double x, ae_state *state); +double ae_asin(double x, ae_state *state); +double ae_acos(double x, ae_state *state); +double ae_atan(double x, ae_state *state); +double ae_atan2(double y, double x, ae_state *state); + +double ae_log(double x, ae_state *state); +double ae_pow(double x, double y, ae_state *state); +double ae_exp(double x, ae_state *state); + +/************************************************************************ +Complex math functions: +* basic arithmetic operations +* standard functions +************************************************************************/ +ae_complex ae_complex_from_i(ae_int_t v); +ae_complex ae_complex_from_d(double v); + +ae_complex ae_c_neg(ae_complex lhs); +ae_bool ae_c_eq(ae_complex lhs, ae_complex rhs); +ae_bool ae_c_neq(ae_complex lhs, ae_complex rhs); +ae_complex ae_c_add(ae_complex lhs, ae_complex rhs); +ae_complex ae_c_mul(ae_complex lhs, ae_complex rhs); +ae_complex ae_c_sub(ae_complex lhs, ae_complex rhs); +ae_complex ae_c_div(ae_complex lhs, ae_complex rhs); +ae_bool ae_c_eq_d(ae_complex lhs, double rhs); +ae_bool ae_c_neq_d(ae_complex lhs, double rhs); +ae_complex ae_c_add_d(ae_complex lhs, double rhs); +ae_complex ae_c_mul_d(ae_complex lhs, double rhs); +ae_complex ae_c_sub_d(ae_complex lhs, double rhs); +ae_complex ae_c_d_sub(double lhs, ae_complex rhs); +ae_complex ae_c_div_d(ae_complex lhs, double rhs); +ae_complex ae_c_d_div(double lhs, ae_complex rhs); + +ae_complex ae_c_conj(ae_complex lhs, ae_state *state); +ae_complex ae_c_sqr(ae_complex lhs, ae_state *state); +double ae_c_abs(ae_complex z, ae_state *state); + +/************************************************************************ +Complex BLAS operations +************************************************************************/ +ae_complex ae_v_cdotproduct(const ae_complex *v0, ae_int_t stride0, const char *conj0, const ae_complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); +void ae_v_cmove(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void ae_v_cmoveneg(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void ae_v_cmoved(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void ae_v_cmovec(ae_complex *vdst, ae_int_t stride_dst, const ae_complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); +void ae_v_cadd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void ae_v_caddd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void ae_v_caddc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); +void ae_v_csub(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void ae_v_csubd(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void ae_v_csubc(ae_complex *vdst, ae_int_t stride_dst, const ae_complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, ae_complex alpha); +void ae_v_cmuld(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); +void ae_v_cmulc(ae_complex *vdst, ae_int_t stride_dst, ae_int_t n, ae_complex alpha); + +/************************************************************************ +Real BLAS operations +************************************************************************/ +double ae_v_dotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); +void ae_v_move(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); +void ae_v_moveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); +void ae_v_moved(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void ae_v_add(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); +void ae_v_addd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void ae_v_sub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); +void ae_v_subd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void ae_v_muld(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); + +/************************************************************************ +Other functions +************************************************************************/ +ae_int_t ae_v_len(ae_int_t a, ae_int_t b); + +/* +extern const double ae_machineepsilon; +extern const double ae_maxrealnumber; +extern const double ae_minrealnumber; +extern const double ae_pi; +*/ +#define ae_machineepsilon 5E-16 +#define ae_maxrealnumber 1E300 +#define ae_minrealnumber 1E-300 +#define ae_pi 3.1415926535897932384626433832795 + + +/************************************************************************ +RComm functions +************************************************************************/ +typedef struct rcommstate +{ + int stage; + ae_vector ia; + ae_vector ba; + ae_vector ra; + ae_vector ca; +} rcommstate; +void _rcommstate_init(rcommstate* p, ae_state *_state, ae_bool make_automatic); +void _rcommstate_init_copy(rcommstate* dst, const rcommstate* src, ae_state *_state, ae_bool make_automatic); +void _rcommstate_clear(rcommstate* p); +void _rcommstate_destroy(rcommstate* p); + + +/************************************************************************ +Allocation counters, inactive by default. +Turned on when needed for debugging purposes. + +_alloc_counter is incremented by 1 on malloc(), decremented on free(). +_alloc_counter_total is only incremented by 1. +************************************************************************/ +extern ae_int_t _alloc_counter; +extern ae_int_t _alloc_counter_total; +extern ae_bool _use_alloc_counter; + + +/************************************************************************ +Malloc debugging: + +* _force_malloc_failure - set this flag to ae_true in order to enforce + failure of ALGLIB malloc(). Useful to debug handling of errors during + memory allocation. As long as this flag is set, ALGLIB malloc will fail. +* _malloc_failure_after - set it to non-zero value in order to enforce + malloc failure as soon as _alloc_counter_total increases above value of + this variable. This value has no effect if _use_alloc_counter is not + set. +************************************************************************/ +extern ae_bool _force_malloc_failure; +extern ae_int_t _malloc_failure_after; + + +/************************************************************************ +Trace file descriptor (to be used by ALGLIB code which sends messages to +trace log) +************************************************************************/ +extern FILE *alglib_trace_file; + + +/************************************************************************ +debug functions (must be turned on by preprocessor definitions): +* flushconsole(), fluches console +* ae_debugrng(), returns random number generated with high-quality random numbers generator +* ae_set_seed(), sets seed of the debug RNG (NON-THREAD-SAFE!!!) +* ae_get_seed(), returns two seed values of the debug RNG (NON-THREAD-SAFE!!!) +************************************************************************/ +#define ae_flushconsole() fflush(stdout) + +/************************************************************************ +Internal macros, defined only when _ALGLIB_IMPL_DEFINES is defined before +inclusion of this header file +************************************************************************/ +#if defined(_ALGLIB_IMPL_DEFINES) + #define _ALGLIB_SIMD_ALIGNMENT_DOUBLES 8 + #define _ALGLIB_SIMD_ALIGNMENT_BYTES (_ALGLIB_SIMD_ALIGNMENT_DOUBLES*8) + + /* + * Updates CPU dispatcher entry with a pointer to the appropriate function; + * does not use atomics when it is safe to do (aligned stores on x64). + * + * Crashes when the very basic assumptions about alignment are violated. + */ + #if AE_CPU==AE_INTEL && !defined(_ALGLIB_TSAN) + #define _ALGLIB_ATOMIC_SAVE_FPTR(ptr_name, func_name) \ + { \ + if( (sizeof(ptr_name)!=sizeof(void*)) || (ae_misalignment(&ptr_name,sizeof(void*))!=0) ) \ + { fprintf(stderr, "ALGLIB: critical error during _ALGLIB_ATOMIC_SAVE_FPTR() for %s()\n", #ptr_name); fflush(stderr); abort(); } \ + ptr_name = func_name; \ + } + #else + #define _ALGLIB_ATOMIC_SAVE_FPTR(ptr_name, func_name) + #endif + + /* + * SIMD kernel dispatchers + */ + #if defined(_ALGLIB_HAS_SSE2_INTRINSICS) + #define _ALGLIB_KKK_VOID_SSE2(fname,params) if( cached_cpuid&CPU_SSE2 ) { fname##_sse2 params; return; } + #define _ALGLIB_KKK_RETURN_SSE2(fname,params) if( cached_cpuid&CPU_SSE2 ) { return fname##_sse2 params; } + #else + #define _ALGLIB_KKK_VOID_SSE2(fname,params) + #define _ALGLIB_KKK_RETURN_SSE2(fname,params) + #endif + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) + #define _ALGLIB_KKK_VOID_AVX2(fname,params) if( cached_cpuid&CPU_AVX2 ) { fname##_avx2 params; return; } + #define _ALGLIB_KKK_RETURN_AVX2(fname,params) if( cached_cpuid&CPU_AVX2 ) { return fname##_avx2 params; } + #define _ALGLIB_KSV_VOID_AVX2(fname,params) if( cached_cpuid&CPU_AVX2 ) { _ALGLIB_ATOMIC_SAVE_FPTR(fname, fname##_avx2); fname##_avx2 params; return; } + #define _ALGLIB_KSV_RETURN_AVX2(fname,params) if( cached_cpuid&CPU_AVX2 ) { _ALGLIB_ATOMIC_SAVE_FPTR(fname, fname##_avx2); return fname##_avx2 params; } + #else + #define _ALGLIB_KKK_VOID_AVX2(fname,params) + #define _ALGLIB_KKK_RETURN_AVX2(fname,params) + #define _ALGLIB_KSV_VOID_AVX2(fname,params) + #define _ALGLIB_KSV_RETURN_AVX2(fname,params) + #endif + #if defined(_ALGLIB_HAS_FMA_INTRINSICS) + #define _ALGLIB_KKK_VOID_FMA(fname,params) if( cached_cpuid&CPU_FMA ) { fname##_fma params; return; } + #define _ALGLIB_KKK_RETURN_FMA(fname,params) if( cached_cpuid&CPU_FMA ) { return fname##_fma params; } + #define _ALGLIB_KSV_VOID_FMA(fname,params) if( cached_cpuid&CPU_FMA ) { _ALGLIB_ATOMIC_SAVE_FPTR(fname, fname##_fma); fname##_fma params; return; } + #define _ALGLIB_KSV_RETURN_FMA(fname,params) if( cached_cpuid&CPU_FMA ) { _ALGLIB_ATOMIC_SAVE_FPTR(fname, fname##_fma); return fname##_fma params; } + #else + #define _ALGLIB_KKK_VOID_FMA(fname,params) + #define _ALGLIB_KKK_RETURN_FMA(fname,params) + #define _ALGLIB_KSV_VOID_FMA(fname,params) + #define _ALGLIB_KSV_RETURN_FMA(fname,params) + #endif + + #if defined(_ALGLIB_HAS_SSE2_INTRINSICS) || defined(_ALGLIB_HAS_AVX2_INTRINSICS) + #define _ALGLIB_KERNEL_VOID_SSE2_AVX2(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_VOID_AVX2(fname,params)\ + _ALGLIB_KKK_VOID_SSE2(fname,params)\ + } + #define _ALGLIB_KERNEL_RETURN_SSE2_AVX2(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_RETURN_AVX2(fname,params)\ + _ALGLIB_KKK_RETURN_SSE2(fname,params)\ + } + #else + #define _ALGLIB_KERNEL_VOID_SSE2_AVX2(fname,params) {} + #define _ALGLIB_KERNEL_RETURN_SSE2_AVX2(fname,params) {} + #endif + + #if defined(_ALGLIB_HAS_SSE2_INTRINSICS) || defined(_ALGLIB_HAS_AVX2_INTRINSICS) || defined(_ALGLIB_HAS_FMA_INTRINSICS) + #define _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_VOID_FMA(fname,params)\ + _ALGLIB_KKK_VOID_AVX2(fname,params)\ + _ALGLIB_KKK_VOID_SSE2(fname,params)\ + } + #define _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_RETURN_FMA(fname,params)\ + _ALGLIB_KKK_RETURN_AVX2(fname,params)\ + _ALGLIB_KKK_RETURN_SSE2(fname,params)\ + } + #else + #define _ALGLIB_KERNEL_VOID_SSE2_AVX2_FMA(fname,params) {} + #define _ALGLIB_KERNEL_RETURN_SSE2_AVX2_FMA(fname,params) {} + #endif + + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) || defined(_ALGLIB_HAS_FMA_INTRINSICS) + #define _ALGLIB_KERNEL_VOID_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_VOID_FMA(fname,params)\ + _ALGLIB_KKK_VOID_AVX2(fname,params)\ + } + #define _ALGLIB_KERNEL_RETURN_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_RETURN_FMA(fname,params)\ + _ALGLIB_KKK_RETURN_AVX2(fname,params)\ + } + #define _ALGLIB_KERNELSAVE_VOID_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KSV_VOID_FMA(fname,params)\ + _ALGLIB_KSV_VOID_AVX2(fname,params)\ + } + #define _ALGLIB_KERNELSAVE_RETURN_AVX2_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KSV_RETURN_FMA(fname,params)\ + _ALGLIB_KSV_RETURN_AVX2(fname,params)\ + } + #else + #define _ALGLIB_KERNEL_VOID_AVX2_FMA(fname,params) {} + #define _ALGLIB_KERNEL_RETURN_AVX2_FMA(fname,params) {} + #define _ALGLIB_KERNELSAVE_VOID_AVX2_FMA(fname,params) {} + #define _ALGLIB_KERNELSAVE_RETURN_AVX2_FMA(fname,params) {} + #endif + + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) + #define _ALGLIB_KERNEL_VOID_AVX2(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_VOID_AVX2(fname,params)\ + } + #define _ALGLIB_KERNEL_RETURN_AVX2(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_RETURN_AVX2(fname,params)\ + } + #else + #define _ALGLIB_KERNEL_VOID_AVX2(fname,params) {} + #define _ALGLIB_KERNEL_RETURN_AVX2(fname,params) {} + #endif + + #if defined(_ALGLIB_HAS_FMA_INTRINSICS) + #define _ALGLIB_KERNEL_VOID_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_VOID_FMA(fname,params)\ + } + #define _ALGLIB_KERNEL_RETURN_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KKK_RETURN_FMA(fname,params)\ + } + #define _ALGLIB_KERNELSAVE_VOID_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KSV_VOID_FMA(fname,params)\ + } + #define _ALGLIB_KERNELSAVE_RETURN_FMA(fname,params) \ + {\ + ae_int_t cached_cpuid = ae_cpuid();\ + _ALGLIB_KSV_RETURN_FMA(fname,params)\ + } + #else + #define _ALGLIB_KERNEL_VOID_FMA(fname,params) {} + #define _ALGLIB_KERNEL_RETURN_FMA(fname,params) {} + #define _ALGLIB_KERNELSAVE_VOID_FMA(fname,params) {} + #define _ALGLIB_KERNELSAVE_RETURN_FMA(fname,params) {} + #endif + + #ifdef FP_FAST_FMA + #define APPROX_FMA(x, y, z) fma((x), (y), (z)) + #else + #define APPROX_FMA(x, y, z) ((x)*(y) + (z)) + #endif + +#endif + +/************************************************************************ +APSERV overrides +************************************************************************/ +#if !defined(ALGLIB_NO_FAST_KERNELS) +/************************************************************************* +Maximum concurrency on given system, with given compilation settings +*************************************************************************/ +ae_int_t maxconcurrency(ae_state *_state); +#endif + + +ae_bool isfinitevector(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +ae_int_t icase2(ae_bool cond, ae_int_t v0, ae_int_t v1, ae_state *_state); +ae_int_t ibinarysearchlft(/* Integer */ const ae_vector* a, + ae_int_t i0, + ae_int_t i1, + ae_int_t v, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rsetv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void isetv(ae_int_t n, + ae_int_t v, + /* Integer */ ae_vector* x, + ae_state *_state); +#endif +void rsetallocv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state); +void rallocv(ae_int_t n, /* Real */ ae_vector* x, ae_state *_state); +void iallocv(ae_int_t n, /* Integer */ ae_vector* x, ae_state *_state); +void isetallocv(ae_int_t n, + ae_int_t v, + /* Integer */ ae_vector* x, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopyv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void bcopyv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void rcopyvx(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t offsx, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); +#endif +void rcopyallocv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void icopyallocv(ae_int_t n, + /* Integer */ const ae_vector* x, + /* Integer */ ae_vector* y, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +void icopyv(ae_int_t n, + /* Integer */ const ae_vector* x, + /* Integer */ ae_vector* y, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +void icopyvx(ae_int_t n, + /* Integer */ const ae_vector* x, + ae_int_t offsx, + /* Integer */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); +#endif +void igrowv(ae_int_t newn, /* Integer */ ae_vector* x, ae_state *_state); +void bgrowv(ae_int_t newn, /* Boolean */ ae_vector* x, ae_state *_state); +void rgrowv(ae_int_t newn, /* Real */ ae_vector* x, ae_state *_state); +void rgrowappendv(ae_int_t newn, + /* Real */ ae_vector* x, + double v, + ae_state *_state); +void igrowappendv(ae_int_t newn, + /* Integer */ ae_vector* x, + ae_int_t v, + ae_state *_state); +void bgrowappendv(ae_int_t newn, + /* Boolean */ ae_vector* x, + ae_bool v, + ae_state *_state); +void ablasf_igrowvinternal(ae_int_t newn, + /* Integer */ ae_vector* x, + ae_state *_state); +void ablasf_bgrowvinternal(ae_int_t newn, + /* Boolean */ ae_vector* x, + ae_state *_state); +void ablasf_rgrowvinternal(ae_int_t newn, + /* Real */ ae_vector* x, + ae_state *_state); +void tagsortmiddleir(/* Integer */ ae_vector* a, + /* Real */ ae_vector* b, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +void tagsortmiddleirr(/* Integer */ ae_vector* a, + /* Real */ ae_vector* b, + /* Real */ ae_vector* c, + ae_int_t offset, + ae_int_t n, + ae_state *_state); +typedef struct +{ + ae_vector vals; + ae_vector idx; + ae_vector ridx; + ae_vector didx; + ae_vector uidx; + ae_int_t matrixtype; + ae_int_t m; + ae_int_t n; + ae_int_t nfree; + ae_int_t ninitialized; + ae_int_t tablesize; +} sparsematrix; +void _sparsematrix_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sparsematrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sparsematrix_clear(void* _p); +void _sparsematrix_destroy(void* _p); +void sparsecreatecrsempty(ae_int_t n, sparsematrix* s, ae_state *_state); +void sparsecreatecrsemptybuf(ae_int_t n, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsfromcrsrangebuf(const sparsematrix* src, + ae_int_t r0, + ae_int_t r1, + sparsematrix* dst, + ae_state *_state); +void sparsecopybuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparseinitduidx(sparsematrix* s, ae_state *_state); +void sparseappendmatrix(sparsematrix* sdst, + const sparsematrix* ssrc, + ae_state *_state); +void sparseconverttocrs(sparsematrix* s, ae_state *_state); +void sparsecopytocrsbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +ae_bool sparseiscrs(const sparsematrix* s, ae_state *_state); +ae_int_t sparsegetnrows(const sparsematrix* s, ae_state *_state); +ae_int_t sparsegetncols(const sparsematrix* s, ae_state *_state); +typedef struct +{ + ae_int_t nvars; + ae_vector varidx; + ae_vector b; + sparsematrix lowerq; + double cl; + double cu; + ae_bool applyorigin; +} xquadraticconstraint; +typedef struct +{ + ae_int_t n; + ae_obj_array constraints; + ae_vector tmpi; +} xquadraticconstraints; +typedef struct +{ + ae_int_t conetype; + ae_int_t nvars; + ae_int_t kpow; + ae_vector varidx; + ae_vector diaga; + ae_vector shftc; + ae_vector alphapow; + ae_bool applyorigin; +} xconicconstraint; +typedef struct +{ + ae_int_t n; + ae_obj_array constraints; +} xconicconstraints; +typedef struct +{ + ae_int_t n; + ae_bool hasknowntarget; + double targetf; + ae_bool hasinitialpoint; + ae_vector x0; + ae_bool hasknownsolution; + ae_vector solx; + ae_bool hasscale; + ae_vector s; + ae_bool hasorigin; + ae_vector xorigin; + ae_vector c; + ae_bool hasq; + sparsematrix q; + ae_bool isupperq; + ae_vector bndl; + ae_vector bndu; + ae_int_t mlc; + sparsematrix a; + ae_vector al; + ae_vector au; + ae_int_t mqc; + xquadraticconstraints qc; + ae_int_t mcc; + sparsematrix dummysparse; +} qpxproblem; +void _xquadraticconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xquadraticconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xquadraticconstraint_clear(void* _p); +void _xquadraticconstraint_destroy(void* _p); +void _xquadraticconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xquadraticconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xquadraticconstraints_clear(void* _p); +void _xquadraticconstraints_destroy(void* _p); +void _xconicconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xconicconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xconicconstraint_clear(void* _p); +void _xconicconstraint_destroy(void* _p); +void _xconicconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xconicconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xconicconstraints_clear(void* _p); +void _xconicconstraints_destroy(void* _p); +void _qpxproblem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _qpxproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _qpxproblem_clear(void* _p); +void _qpxproblem_destroy(void* _p); +void qpxproblemcreate(ae_int_t n, qpxproblem* p, ae_state *_state); +void qpxproblemsetinitialpoint(qpxproblem* p, + /* Real */ const ae_vector* x0, + ae_state *_state); +void qpxproblemsetscale(qpxproblem* p, + /* Real */ const ae_vector* s, + ae_state *_state); +void qpxproblemsetorigin(qpxproblem* p, + /* Real */ const ae_vector* xorigin, + ae_state *_state); +void qpxproblemsetlinearterm(qpxproblem* p, + /* Real */ const ae_vector* c, + ae_state *_state); +void qpxproblemsetquadraticterm(qpxproblem* p, + const sparsematrix* q, + ae_bool isupper, + ae_state *_state); +void qpxproblemsetbc(qpxproblem* p, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void qpxproblemsetlc2(qpxproblem* p, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t m, + ae_state *_state); +void qpxproblemaddqc2(qpxproblem* p, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +void xqcinit(ae_int_t n, xquadraticconstraints* state, ae_state *_state); +void xqcclear(xquadraticconstraints* state, ae_state *_state); +void xqcupdaten(xquadraticconstraints* state, + ae_int_t newn, + ae_state *_state); +void xqcaddqc2(xquadraticconstraints* xqc, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +void xccinit(ae_int_t n, xconicconstraints* state, ae_state *_state); +void xccupdaten(xconicconstraints* state, ae_int_t newn, ae_state *_state); + +} + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS DECLARATIONS FOR C++ RELATED FUNCTIONALITY +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ +/******************************************************************** +Int type redefinition in alglib namespace +********************************************************************/ +typedef alglib_impl::ae_int_t ae_int_t; + +/******************************************************************** +xparams type and several predefined constants +********************************************************************/ +struct xparams +{ + alglib_impl::ae_uint64_t flags; + + xparams operator|(const xparams &rhs) + { + xparams r = *this; + r.flags |= rhs.flags; + return r; + } +}; + +extern const xparams &xdefault; +extern const xparams &serial; +extern const xparams ∥ +extern const xparams &serial_callbacks; +extern const xparams ¶llel_callbacks; +extern const xparams &backend_linalg; +extern const xparams &no_backend_linalg; +extern const xparams &backend_dss; +extern const xparams &no_backend_dss; + +/******************************************************************** +Class forwards +********************************************************************/ +class complex; +class real_1d_array; +class integer_1d_array; + +ae_int_t vlen(ae_int_t n1, ae_int_t n2); + +} + +namespace alglib +{ + +class _sparsematrix_owner; +class sparsematrix; + + + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. + +The empty matrix is a degenerate 0*N-dimensional matrix which can be used +ONLY for: +* appending rows with sparseappendcompressedrow() +* appending non-degenerate CRS matrices with sparseappendmatrix() +Before the first row is appended, the matrix is in a special intermediate +state. After the first append it becomes a standard CRS matrix. + +The main purpose of this function is to simplify step-by-step initialization +of CRS matrices. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSEmptyBuf function. + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsempty(const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. It +is a buffered version of the function which reuses previosly allocated +space as much as possible. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsemptybuf(const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function creates a sparse CRS-based matrix from subset of rows of +another CRS-based matrix. Memory already present in Dst is reused as much +as possible. + +INPUT PARAMETERS: + Src - sparse M*N matrix in CRS format. + R0, R1 - half-range of rows to use, [R0,R1) + +OUTPUT PARAMETERS: + Dst - (R1-R0)*N matrix in the CRS format, subset of Src + + -- ALGLIB PROJECT -- + Copyright 2024.03.23 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromcrsrangebuf(const sparsematrix &src, const ae_int_t r0, const ae_int_t r1, sparsematrix &dst, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function copies S0 to S1. +Memory already allocated in S1 is reused as much as possible. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopybuf(const sparsematrix &s0, sparsematrix &s1, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function appends from below a sparse CRS-based matrix to another +sparse CRS-based matrix. The matrix being appended must be completely +initialized CRS matrix. + +INPUT PARAMETERS: + SDst - sparse X*N matrix in CRS format, including one created + with sparsecreatecrsempty (in the latter case, X=0). + SSrc - sparse M*N matrix in the CRS format + +OUTPUT PARAMETERS: + SDst - (X+M)*N matrix in the CRS format, SSrc appended from + below + +NOTE: this function has amortized O(MSrc+NZCnt) cost, where NZCnt is a + total number of nonzero elements in SSrc. + + -- ALGLIB PROJECT -- + Copyright 2024.03.23 by Bochkanov Sergey +*************************************************************************/ +void sparseappendmatrix(sparsematrix &sdst, const sparsematrix &ssrc, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function converts matrix to CRS format. + +Some algorithms (linear algebra ones, for example) require matrices in +CRS format. This function allows to perform in-place conversion. + +INPUT PARAMETERS + S - sparse M*N matrix in any format + +OUTPUT PARAMETERS + S - matrix in CRS format + +NOTE: this function has no effect when called with matrix which is + already in CRS mode. + +NOTE: this function allocates temporary memory to store a copy of the + matrix. If you perform a lot of repeated conversions, we recommend + you to use SparseCopyToCRSBuf() function, which can reuse + previously allocated memory. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseconverttocrs(sparsematrix &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function performs out-of-place conversion to CRS format. S0 is +copied to S1 and converted on-the-fly. Memory allocated in S1 is reused to +maximum extent possible. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + S1 - matrix which may contain some pre-allocated memory, or + can be just uninitialized structure. + +OUTPUT PARAMETERS + S1 - sparse matrix in CRS format. + +NOTE: if S0 is stored as CRS, it is just copied without conversion. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytocrsbuf(const sparsematrix &s0, sparsematrix &s1, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +This function checks matrix storage format and returns True when matrix is +stored using CRS representation. + +INPUT PARAMETERS: + S - sparse matrix. + +RESULT: + True if matrix type is CRS + False if matrix type is not CRS + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +bool sparseiscrs(const sparsematrix &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +The function returns number of rows of a sparse matrix. + +RESULT: number of rows of a sparse matrix. + + -- ALGLIB PROJECT -- + Copyright 23.08.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetnrows(const sparsematrix &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +The function returns number of columns of a sparse matrix. + +RESULT: number of columns of a sparse matrix. + + -- ALGLIB PROJECT -- + Copyright 23.08.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetncols(const sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse matrix structure. + +You should use ALGLIB functions to work with sparse matrix. Never try to +access its fields directly! + +NOTES ON THE SPARSE STORAGE FORMATS + +Sparse matrices can be stored using several formats: +* Hash-Table representation +* Compressed Row Storage (CRS) +* Skyline matrix storage (SKS) + +Each of the formats has benefits and drawbacks: +* Hash-table is good for dynamic operations (insertion of new elements), + but does not support linear algebra operations +* CRS is good for operations like matrix-vector or matrix-matrix products, + but its initialization is less convenient - you have to tell row sizes + at the initialization, and you have to fill matrix only row by row, + from left to right. +* SKS is a special format which is used to store triangular factors from + Cholesky factorization. It does not support dynamic modification, and + support for linear algebra operations is very limited. + +Tables below outline information about these two formats: + + OPERATIONS WITH MATRIX HASH CRS SKS + creation + + + + SparseGet + + + + SparseExists + + + + SparseRewriteExisting + + + + SparseSet + + + + SparseAdd + + SparseGetRow + + + SparseGetCompressedRow + + + SparseAppendCompressedRow + + sparse-dense linear algebra + + +*************************************************************************/ +class _sparsematrix_owner +{ +public: + _sparsematrix_owner(); + _sparsematrix_owner(alglib_impl::sparsematrix *attach_to); + _sparsematrix_owner(const _sparsematrix_owner &rhs); + _sparsematrix_owner& operator=(const _sparsematrix_owner &rhs); + virtual ~_sparsematrix_owner(); + alglib_impl::sparsematrix* c_ptr(); + const alglib_impl::sparsematrix* c_ptr() const; +protected: + alglib_impl::sparsematrix *p_struct; + bool is_attached; +}; +class sparsematrix : public _sparsematrix_owner +{ +public: + sparsematrix(); + sparsematrix(alglib_impl::sparsematrix *attach_to); + sparsematrix(const sparsematrix &rhs); + sparsematrix& operator=(const sparsematrix &rhs); + virtual ~sparsematrix(); + + +}; + +class _qpxproblem_owner; +class qpxproblem; + + + + +/************************************************************************* +Initialize QPX problem. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemcreate(const ae_int_t n, qpxproblem &p, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetinitialpoint(qpxproblem &p, const real_1d_array &x0, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetscale(qpxproblem &p, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetorigin(qpxproblem &p, const real_1d_array &xorigin, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlinearterm(qpxproblem &p, const real_1d_array &c, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set quadratic term; Q can be in any sparse matrix format. + +Only one triangle (lower or upper) is referenced by this function. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetquadraticterm(qpxproblem &p, const sparsematrix &q, const bool isupper, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetbc(qpxproblem &p, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Set linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlc2(qpxproblem &p, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t m, const xparams _xparams = alglib::xdefault); + + + + +/************************************************************************* +Append two-sided quadratic constraint, same format as minqpaddqc2() + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemaddqc2(qpxproblem &p, const sparsematrix &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +A general QP problem (a linear/quadratic target subject to a mix of box, +linear, quadratic and conic constraints). + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +class _qpxproblem_owner +{ +public: + _qpxproblem_owner(); + _qpxproblem_owner(alglib_impl::qpxproblem *attach_to); + _qpxproblem_owner(const _qpxproblem_owner &rhs); + _qpxproblem_owner& operator=(const _qpxproblem_owner &rhs); + virtual ~_qpxproblem_owner(); + alglib_impl::qpxproblem* c_ptr(); + const alglib_impl::qpxproblem* c_ptr() const; +protected: + alglib_impl::qpxproblem *p_struct; + bool is_attached; +}; +class qpxproblem : public _qpxproblem_owner +{ +public: + qpxproblem(); + qpxproblem(alglib_impl::qpxproblem *attach_to); + qpxproblem(const qpxproblem &rhs); + qpxproblem& operator=(const qpxproblem &rhs); + virtual ~qpxproblem(); + + +}; + +} + +namespace alglib +{ + +/******************************************************************** +Exception class. +********************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +class ap_error +{ +public: + std::string msg; + + ap_error(); + ap_error(const char *s); + ap_error(const std::string &s); + static void make_assertion(bool bClause); + static void make_assertion(bool bClause, const char *p_msg); +private: +}; +#endif + +/******************************************************************** +Complex number with double precision. +********************************************************************/ +class complex +{ +public: + complex(); + complex(const double &_x); + complex(const double &_x, const double &_y); + complex(const complex &z); + complex(const alglib_impl::ae_complex &z):x(z.x),y(z.y){}; + + complex& operator= (const double& v); + complex& operator+=(const double& v); + complex& operator-=(const double& v); + complex& operator*=(const double& v); + complex& operator/=(const double& v); + + complex& operator= (const complex& z); + complex& operator+=(const complex& z); + complex& operator-=(const complex& z); + complex& operator*=(const complex& z); + complex& operator/=(const complex& z); + + alglib_impl::ae_complex* c_ptr(); + const alglib_impl::ae_complex* c_ptr() const; + +#if !defined(AE_NO_EXCEPTIONS) + std::string tostring(int dps) const; +#endif + + double x, y; +}; + +const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); +bool operator==(const alglib::complex& lhs, const alglib::complex& rhs); +bool operator!=(const alglib::complex& lhs, const alglib::complex& rhs); +const alglib::complex operator+(const alglib::complex& lhs); +const alglib::complex operator-(const alglib::complex& lhs); +const alglib::complex operator+(const alglib::complex& lhs, const alglib::complex& rhs); +const alglib::complex operator+(const alglib::complex& lhs, const double& rhs); +const alglib::complex operator+(const double& lhs, const alglib::complex& rhs); +const alglib::complex operator-(const alglib::complex& lhs, const alglib::complex& rhs); +const alglib::complex operator-(const alglib::complex& lhs, const double& rhs); +const alglib::complex operator-(const double& lhs, const alglib::complex& rhs); +const alglib::complex operator*(const alglib::complex& lhs, const alglib::complex& rhs); +const alglib::complex operator*(const alglib::complex& lhs, const double& rhs); +const alglib::complex operator*(const double& lhs, const alglib::complex& rhs); +const alglib::complex operator/(const alglib::complex& lhs, const alglib::complex& rhs); +const alglib::complex operator/(const double& lhs, const alglib::complex& rhs); +const alglib::complex operator/(const alglib::complex& lhs, const double& rhs); +double abscomplex(const alglib::complex &z); +alglib::complex conj(const alglib::complex &z); +alglib::complex csqr(const alglib::complex &z); + +/******************************************************************** +Level 1 BLAS functions + +NOTES: +* destination and source should NOT overlap +* stride is assumed to be positive, but it is not + assert'ed within function +* conj_src parameter specifies whether complex source is conjugated + before processing or not. Pass string which starts with 'N' or 'n' + ("No conj", for example) to use unmodified parameter. All other + values will result in conjugation of input, but it is recommended + to use "Conj" in such cases. +********************************************************************/ +double vdotproduct(const double *v0, ae_int_t stride0, const double *v1, ae_int_t stride1, ae_int_t n); +double vdotproduct(const double *v1, const double *v2, ae_int_t N); + +alglib::complex vdotproduct(const alglib::complex *v0, ae_int_t stride0, const char *conj0, const alglib::complex *v1, ae_int_t stride1, const char *conj1, ae_int_t n); +alglib::complex vdotproduct(const alglib::complex *v1, const alglib::complex *v2, ae_int_t N); + +void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); +void vmove(double *vdst, const double* vsrc, ae_int_t N); + +void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void vmove(alglib::complex *vdst, const alglib::complex* vsrc, ae_int_t N); + +void vmoveneg(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n); +void vmoveneg(double *vdst, const double *vsrc, ae_int_t N); + +void vmoveneg(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void vmoveneg(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); + +void vmove(double *vdst, ae_int_t stride_dst, const double* vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void vmove(double *vdst, const double *vsrc, ae_int_t N, double alpha); + +void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); + +void vmove(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex* vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); +void vmove(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); + +void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); +void vadd(double *vdst, const double *vsrc, ae_int_t N); + +void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); + +void vadd(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void vadd(double *vdst, const double *vsrc, ae_int_t N, double alpha); + +void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); + +void vadd(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); +void vadd(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); + +void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n); +void vsub(double *vdst, const double *vsrc, ae_int_t N); + +void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n); +void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N); + +void vsub(double *vdst, ae_int_t stride_dst, const double *vsrc, ae_int_t stride_src, ae_int_t n, double alpha); +void vsub(double *vdst, const double *vsrc, ae_int_t N, double alpha); + +void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, double alpha); +void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, double alpha); + +void vsub(alglib::complex *vdst, ae_int_t stride_dst, const alglib::complex *vsrc, ae_int_t stride_src, const char *conj_src, ae_int_t n, alglib::complex alpha); +void vsub(alglib::complex *vdst, const alglib::complex *vsrc, ae_int_t N, alglib::complex alpha); + +void vmul(double *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); +void vmul(double *vdst, ae_int_t N, double alpha); + +void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, double alpha); +void vmul(alglib::complex *vdst, ae_int_t N, double alpha); + +void vmul(alglib::complex *vdst, ae_int_t stride_dst, ae_int_t n, alglib::complex alpha); +void vmul(alglib::complex *vdst, ae_int_t N, alglib::complex alpha); + + +/******************************************************************** +Threading functions +********************************************************************/ +// nworkers can be 1, 2, ... ; or 0 for auto; or -1/-2/... for all except for one/two/... +void setnworkers(alglib::ae_int_t nworkers); + +// a function that sets global flags that control threading and vendor backends usage +void setglobalflags(const xparams settings); + +// an older version of setglobalflags() +void setglobalthreading(const xparams settings); + +// returns current value, as set by setnworkers (can be 0, +1, +2, -1, -2, etc.) +alglib::ae_int_t getnworkers(); + +// returns maximum number of worker threads allowed (either cores count or AE_NWORKERS if defined), >=1 +alglib::ae_int_t getmaxnworkers(); + +// +// Get index of a worker thread that computes current callback; returns a +// value in [0,getmaxnworkers()-1], zero is returned when called outside of parallel callback +// context. +// +// NOTE: this function is unavailable when compiled with C++ standard set +// to anything earlier than C++11. +// +#if defined(_ALGLIB_HAS_THREADLOCAL) +alglib::ae_int_t getcallbackworkeridx(); +#endif + +/******************************************************************** +internal functions used by test_x.cpp, interfaces for functions present +in commercial ALGLIB but lacking in free edition. +********************************************************************/ +ae_int_t _ae_cores_count(); +void _ae_set_global_threading(alglib_impl::ae_uint64_t flg_value); +alglib_impl::ae_uint64_t _ae_get_global_threading(); + +/******************************************************************** +1- and 2-dimensional arrays +********************************************************************/ +class ae_vector_wrapper +{ +public: + // + // Creates object attached to external ae_vector structure. + // + // NOTE: this function also checks that source ae_vector* has + // required datatype. An exception is generated otherwise. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + // + ae_vector_wrapper(alglib_impl::ae_vector *e_ptr, alglib_impl::ae_datatype datatype); + + // + // Creates zero-size vector of specific datatype + // + ae_vector_wrapper(alglib_impl::ae_datatype datatype); + + // + // Creates a copy of another vector (can be reference to one of the derived classes) + // + // NOTE: this function also checks that source ae_vector* has + // required datatype. An exception is generated otherwise. + // + ae_vector_wrapper(const ae_vector_wrapper &rhs, alglib_impl::ae_datatype datatype); + + // + // Well, it is destructor... + // + virtual ~ae_vector_wrapper(); + + // + // For wrapper object allocated with allocate_own() this function + // changes length, completely dropping previous contents. + // + // It does not work (throws exception) for frozen proxy objects. + // + void setlength(ae_int_t iLen); + + // + // Element count + // + ae_int_t length() const; + + // + // Access to internal C-structure used by C-core. + // Not intended for external use. + // + const alglib_impl::ae_vector* c_ptr() const; + alglib_impl::ae_vector* c_ptr(); +private: + ae_vector_wrapper(); + ae_vector_wrapper(const ae_vector_wrapper &rhs); + const ae_vector_wrapper& operator=(const ae_vector_wrapper &rhs); +protected: +#if !defined(AE_NO_EXCEPTIONS) + // + // Copies array given by string into current object. Additional + // parameter DATATYPE contains information about type of the data + // in S and type of the array to create. + // + // NOTE: this function is not supported in exception-free mode. + // + ae_vector_wrapper(const char *s, alglib_impl::ae_datatype datatype); +#endif + + // + // This function attaches wrapper object to external x_vector structure; + // "frozen proxy" mode is activated (you can read/write, but can not reallocate + // and do not own memory of the vector). + // + // NOTE: initial state of wrapper object is assumed to be initialized; + // all previously allocated memory is properly deallocated. + // + // NOTE: x_vector structure pointed by new_ptr is used only once; after + // we fetch pointer to memory and its size, this structure is ignored + // and not referenced anymore. So, you can pass pointers to temporary + // x-structures which are deallocated immediately after you call attach_to() + // + // NOTE: state structure is used for error reporting purposes (longjmp on errors). + // + void attach_to(alglib_impl::x_vector *new_ptr, alglib_impl::ae_state *_state); + + // + // Assigns RHS to current object. Returns *this. + // + // It has several branches depending on target object status: + // * in case it is proxy object, data are copied into memory pointed by + // proxy. Function checks that source has exactly same size as target + // (exception is thrown on failure). + // * in case it is non-proxy object, data allocated by object are cleared + // and a copy of RHS is created in target. + // + // NOTE: this function correctly handles assignments of the object to itself. + // + const ae_vector_wrapper& assign(const ae_vector_wrapper &rhs); + + // + // Pointer to ae_vector structure: + // * ptr==&inner_vec means that wrapper object owns ae_vector structure and + // is responsible for proper deallocation of its memory + // * ptr!=&inner_vec means that wrapper object works with someone's other + // ae_vector record and is not responsible for its memory; in this case + // inner_vec is assumed to be uninitialized. + // + alglib_impl::ae_vector *ptr; + + // + // Inner ae_vector record. + // Ignored for ptr!=&inner_rec. + // + alglib_impl::ae_vector inner_vec; + + // + // Whether this wrapper object is frozen proxy (you may read array, may + // modify its value, but can not deallocate its memory or resize it) or not. + // + // If is_frozen_proxy==true and if: + // * ptr==&inner_vec, it means that wrapper works with its own ae_vector + // structure, but this structure points to externally allocated memory. + // This memory is NOT owned by ae_vector object. + // * ptr!=&inner_vec, it means that wrapper works with externally allocated + // and managed ae_vector structure. Both memory pointed by ae_vector and + // ae_vector structure itself are not owned by wrapper object. + // + bool is_frozen_proxy; +}; + +class boolean_1d_array : public ae_vector_wrapper +{ +public: + boolean_1d_array(); + boolean_1d_array(const boolean_1d_array &rhs); + + // + // Attach vector to an instance of ae_vector, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + boolean_1d_array(alglib_impl::ae_vector *p); + const boolean_1d_array& operator=(const boolean_1d_array &rhs); + virtual ~boolean_1d_array() ; + + const ae_bool& operator()(ae_int_t i) const; + ae_bool& operator()(ae_int_t i); + + const ae_bool& operator[](ae_int_t i) const; + ae_bool& operator[](ae_int_t i); + + // + // This function allocates array[iLen] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t iLen, const bool *pContent ); + + // + // This function returns pointer to internal memory + // + ae_bool* getcontent(); + const ae_bool* getcontent() const; + +#if !defined(AE_NO_EXCEPTIONS) + boolean_1d_array(const char *s); + std::string tostring() const; +#endif +}; + +class integer_1d_array : public ae_vector_wrapper +{ +public: + integer_1d_array(); + integer_1d_array(const integer_1d_array &rhs); + + // + // Attach vector to an instance of ae_vector, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + integer_1d_array(alglib_impl::ae_vector *p); + const integer_1d_array& operator=(const integer_1d_array &rhs); + virtual ~integer_1d_array(); + + const ae_int_t& operator()(ae_int_t i) const; + ae_int_t& operator()(ae_int_t i); + + const ae_int_t& operator[](ae_int_t i) const; + ae_int_t& operator[](ae_int_t i); + + // + // This function allocates array[iLen] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t iLen, const ae_int_t *pContent ); + + // + // This function returns pointer to internal memory + // + ae_int_t* getcontent(); + const ae_int_t* getcontent() const; + +#if !defined(AE_NO_EXCEPTIONS) + integer_1d_array(const char *s); + std::string tostring() const; +#endif +}; + +class real_1d_array : public ae_vector_wrapper +{ +public: + real_1d_array(); + real_1d_array(const real_1d_array &rhs); + + // + // Attach vector to an instance of ae_vector, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + real_1d_array(alglib_impl::ae_vector *p); + const real_1d_array& operator=(const real_1d_array &rhs); + virtual ~real_1d_array(); + + const double& operator()(ae_int_t i) const; + double& operator()(ae_int_t i); + + const double& operator[](ae_int_t i) const; + double& operator[](ae_int_t i); + + // + // This function allocates array[iLen] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t iLen, const double *pContent); + + // + // This function attaches array to memory pointed by pContent. + // No own memory is allocated, no copying of data is performed, + // so pContent pointer should be valid as long as we work with + // array. + // + // After you attach array object to external memory, it becomes + // "frozen": it is possible to read/write array elements, but + // it is not allowed to resize it (no setlength() calls). + // + void attach_to_ptr(ae_int_t iLen, double *pContent); + + // + // This function returns pointer to internal memory + // + double* getcontent(); + const double* getcontent() const; + +#if !defined(AE_NO_EXCEPTIONS) + real_1d_array(const char *s); + std::string tostring(int dps) const; +#endif +}; + +class complex_1d_array : public ae_vector_wrapper +{ +public: + complex_1d_array(); + complex_1d_array(const complex_1d_array &rhs); + + // + // Attach vector to an instance of ae_vector, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + complex_1d_array(alglib_impl::ae_vector *p); + const complex_1d_array& operator=(const complex_1d_array &rhs); + virtual ~complex_1d_array(); + + const alglib::complex& operator()(ae_int_t i) const; + alglib::complex& operator()(ae_int_t i); + + const alglib::complex& operator[](ae_int_t i) const; + alglib::complex& operator[](ae_int_t i); + + // + // This function allocates array[iLen] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t iLen, const alglib::complex *pContent ); + alglib::complex* getcontent(); + const alglib::complex* getcontent() const; + +#if !defined(AE_NO_EXCEPTIONS) + complex_1d_array(const char *s); + std::string tostring(int dps) const; +#endif +}; + +class ae_matrix_wrapper +{ +public: + // + // Creates object attached to external ae_vector structure, with additional + // check for matching datatypes (e_ptr->datatype==datatype is required). + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + // + ae_matrix_wrapper(alglib_impl::ae_matrix *e_ptr, alglib_impl::ae_datatype datatype); + + // + // Creates zero-sized matrix of specified datatype. + // + ae_matrix_wrapper(alglib_impl::ae_datatype datatype); + + // + // Creates copy of rhs, with additional check for matching datatypes + // (rhs.datatype==datatype is required). + // + ae_matrix_wrapper(const ae_matrix_wrapper &rhs, alglib_impl::ae_datatype datatype); + + // + // Destructor + // + virtual ~ae_matrix_wrapper(); + + + void setlength(ae_int_t rows, ae_int_t cols); + ae_int_t rows() const; + ae_int_t cols() const; + bool isempty() const; + ae_int_t getstride() const; + + const alglib_impl::ae_matrix* c_ptr() const; + alglib_impl::ae_matrix* c_ptr(); +private: + ae_matrix_wrapper(); + ae_matrix_wrapper(const ae_matrix_wrapper &rhs); + const ae_matrix_wrapper& operator=(const ae_matrix_wrapper &rhs); +protected: +#if !defined(AE_NO_EXCEPTIONS) + // + // Copies array given by string into current object. Additional + // parameter DATATYPE contains information about type of the data + // in S and type of the array to create. + // + // Current object is considered empty (this function should be + // called from copy constructor). + // + ae_matrix_wrapper(const char *s, alglib_impl::ae_datatype datatype); +#endif + + // + // This function attaches wrapper object to external x_vector structure; + // "frozen proxy" mode is activated (you can read/write, but can not reallocate + // and do not own memory of the vector). + // + // NOTE: initial state of wrapper object is assumed to be initialized; + // all previously allocated memory is properly deallocated. + // + // NOTE: x_vector structure pointed by new_ptr is used only once; after + // we fetch pointer to memory and its size, this structure is ignored + // and not referenced anymore. So, you can pass pointers to temporary + // x-structures which are deallocated immediately after you call attach_to() + // + // NOTE: state structure is used for error-handling (a longjmp is performed + // on allocation error). All previously allocated memory is correctly + // freed on error. + // + void attach_to(alglib_impl::x_matrix *new_ptr, alglib_impl::ae_state *_state); + + // + // This function initializes matrix and allocates own memory storage. + // + // NOTE: initial state of wrapper object is assumed to be uninitialized; + // if ptr!=NULL on entry, it is considered critical error (abort is called). + // + void init(ae_int_t rows, ae_int_t cols, alglib_impl::ae_datatype datatype, alglib_impl::ae_state *_state); + + // + // Assigns RHS to current object. + // + // It has several branches depending on target object status: + // * in case it is proxy object, data are copied into memory pointed by + // proxy. Function checks that source has exactly same size as target + // (exception is thrown on failure). + // * in case it is non-proxy object, data allocated by object are cleared + // and a copy of RHS is created in target. + // + // NOTE: this function correctly handles assignments of the object to itself. + // + const ae_matrix_wrapper & assign(const ae_matrix_wrapper &rhs); + + + // + // Pointer to ae_matrix structure: + // * ptr==&inner_mat means that wrapper object owns ae_matrix structure and + // is responsible for proper deallocation of its memory + // * ptr!=&inner_mat means that wrapper object works with someone's other + // ae_matrix record and is not responsible for its memory; in this case + // inner_mat is assumed to be uninitialized. + // + alglib_impl::ae_matrix *ptr; + + // + // Inner ae_matrix record. + // Ignored for ptr!=&inner_mat. + // + alglib_impl::ae_matrix inner_mat; + + // + // Whether this wrapper object is frozen proxy (you may read array, may + // modify its value, but can not deallocate its memory or resize it) or not. + // + // If is_frozen_proxy==true and if: + // * ptr==&inner_vec, it means that wrapper works with its own ae_vector + // structure, but this structure points to externally allocated memory. + // This memory is NOT owned by ae_vector object. + // * ptr!=&inner_vec, it means that wrapper works with externally allocated + // and managed ae_vector structure. Both memory pointed by ae_vector and + // ae_vector structure itself are not owned by wrapper object. + // + bool is_frozen_proxy; +}; + +class boolean_2d_array : public ae_matrix_wrapper +{ +public: + boolean_2d_array(); + boolean_2d_array(const boolean_2d_array &rhs); + + // + // Attach matrix to an instance of ae_matrix, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + boolean_2d_array(alglib_impl::ae_matrix *p); + virtual ~boolean_2d_array(); + + const boolean_2d_array& operator=(const boolean_2d_array &rhs); + + const ae_bool& operator()(ae_int_t i, ae_int_t j) const; + ae_bool& operator()(ae_int_t i, ae_int_t j); + + const ae_bool* operator[](ae_int_t i) const; + ae_bool* operator[](ae_int_t i); + + // + // This function allocates array[irows,icols] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t irows, ae_int_t icols, const bool *pContent ); + +#if !defined(AE_NO_EXCEPTIONS) + boolean_2d_array(const char *s); + std::string tostring() const ; +#endif +}; + +class integer_2d_array : public ae_matrix_wrapper +{ +public: + integer_2d_array(); + integer_2d_array(const integer_2d_array &rhs); + + // + // Attach matrix to an instance of ae_matrix, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + integer_2d_array(alglib_impl::ae_matrix *p); + virtual ~integer_2d_array(); + + const integer_2d_array& operator=(const integer_2d_array &rhs); + + const ae_int_t& operator()(ae_int_t i, ae_int_t j) const; + ae_int_t& operator()(ae_int_t i, ae_int_t j); + + const ae_int_t* operator[](ae_int_t i) const; + ae_int_t* operator[](ae_int_t i); + + // + // This function allocates array[irows,icols] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t irows, ae_int_t icols, const ae_int_t *pContent ); + + +#if !defined(AE_NO_EXCEPTIONS) + integer_2d_array(const char *s); + std::string tostring() const; +#endif +}; + +class real_2d_array : public ae_matrix_wrapper +{ +public: + real_2d_array(); + real_2d_array(const real_2d_array &rhs); + + // + // Attach matrix to an instance of ae_matrix, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + real_2d_array(alglib_impl::ae_matrix *p); + virtual ~real_2d_array(); + + const real_2d_array& operator=(const real_2d_array &rhs); + + const double& operator()(ae_int_t i, ae_int_t j) const; + double& operator()(ae_int_t i, ae_int_t j); + + const double* operator[](ae_int_t i) const; + double* operator[](ae_int_t i); + + // + // This function allocates array[irows,icols] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t irows, ae_int_t icols, const double *pContent); + + // + // This function attaches array to memory pointed by pContent: + // * only minor amount of own memory is allocated - O(irows) bytes to + // store precomputed pointers; but no costly copying of O(rows*cols) + // data is performed. + // * pContent pointer should be valid as long as we work with array + // + // After you attach array object to external memory, it becomes + // "frozen": it is possible to read/write array elements, but + // it is not allowed to resize it (no setlength() calls). + // + void attach_to_ptr(ae_int_t irows, ae_int_t icols, double *pContent); + +#if !defined(AE_NO_EXCEPTIONS) + real_2d_array(const char *s); + std::string tostring(int dps) const; +#endif +}; + +class complex_2d_array : public ae_matrix_wrapper +{ +public: + complex_2d_array(); + complex_2d_array(const complex_2d_array &rhs); + + // + // Attach matrix to an instance of ae_matrix, acting as a proxy for the object. + // + // When created in this mode, instance does not perform any dynamic allocations and does not + // need non-trivial destruction. + // + complex_2d_array(alglib_impl::ae_matrix *p); + + // + virtual ~complex_2d_array(); + + const complex_2d_array& operator=(const complex_2d_array &rhs); + + const alglib::complex& operator()(ae_int_t i, ae_int_t j) const; + alglib::complex& operator()(ae_int_t i, ae_int_t j); + + const alglib::complex* operator[](ae_int_t i) const; + alglib::complex* operator[](ae_int_t i); + + // + // This function allocates array[irows,icols] and copies data + // pointed by pContent to its memory. Completely independent + // copy of data is created. + // + void setcontent(ae_int_t irows, ae_int_t icols, const alglib::complex *pContent ); + +#if !defined(AE_NO_EXCEPTIONS) + complex_2d_array(const char *s); + std::string tostring(int dps) const; +#endif +}; + + +/******************************************************************** +CSV operations: reading CSV file to real matrix. + +This function reads CSV file and stores its contents to double +precision 2D array. Format of the data file must conform to RFC 4180 +specification, with additional notes: +* file size should be less than 2GB +* ASCI encoding, UTF-8 without BOM (in header names) are supported +* any character (comma/tab/space) may be used as field separator, as + long as it is distinct from one used for decimal point +* multiple subsequent field separators (say, two spaces) are treated + as MULTIPLE separators, not one big separator +* both comma and full stop may be used as decimal point. Parser will + automatically determine specific character being used. Both fixed + and exponential number formats are allowed. Thousand separators + are NOT allowed. +* line may end with \n (Unix style) or \r\n (Windows style), parser + will automatically adapt to chosen convention +* escaped fields (ones in double quotes) are not supported + +INPUT PARAMETERS: + filename relative/absolute path + separator character used to separate fields. May be ' ', + ',', '\t'. Other separators are possible too. + flags several values combined with bitwise OR: + * alglib::CSV_SKIP_HEADERS - if present, first row + contains headers and will be skipped. Its + contents is used to determine fields count, and + that's all. + If no flags are specified, default value 0x0 (or + alglib::CSV_DEFAULT, which is same) should be used. + +OUTPUT PARAMETERS: + out 2D matrix, CSV file parsed with atof() + +HANDLING OF SPECIAL CASES: +* file does not exist - alglib::ap_error exception is thrown +* empty file - empty array is returned (no exception) +* skip_first_row=true, only one row in file - empty array is returned +* field contents is not recognized by atof() - field value is replaced + by 0.0 +********************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void read_csv(const char *filename, char separator, int flags, alglib::real_2d_array &out); +#endif + + +/******************************************************************** +This function activates trace output, with trace log being saved to +file (appended to the end). + +Tracing allows us to study behavior of ALGLIB solvers and to debug +their failures: +* tracing is limited by one/several ALGLIB parts specified by means + of trace tags, like "SLP" (for SLP solver) or "OPTGUARD" (OptGuard + integrity checker). +* some ALGLIB solvers support hierarchies of trace tags which activate + different kinds of tracing. Say, "SLP" defines some basic tracing, + but "SLP.PROBING" defines more detailed and costly tracing. +* generally, "TRACETAG.SUBTAG" also implicitly activates logging + which is activated by "TRACETAG" +* you may define multiple trace tags by separating them with commas, + like "SLP,OPTGUARD,SLP.PROBING" +* trace tags are case-insensitive +* spaces/tabs are NOT allowed in the tags string + +Trace log is saved to file "filename", which is opened in the append +mode. If no file with such name can be opened, tracing won't be +performed (but no exception will be generated). +********************************************************************/ +void trace_file(std::string tags, std::string filename); + + +/******************************************************************** +This function disables tracing. +********************************************************************/ +void trace_disable(); + + +/******************************************************************** +Constants and functions introduced for compatibility with AlgoPascal +********************************************************************/ +extern const double machineepsilon; +extern const double maxrealnumber; +extern const double minrealnumber; +extern const double fp_nan; +extern const double fp_posinf; +extern const double fp_neginf; +extern const ae_int_t endianness; +static const int CSV_DEFAULT = 0x0; +static const int CSV_SKIP_HEADERS = 0x1; + +int sign(double x); +double randomreal(); +ae_int_t randominteger(ae_int_t maxv); +int round(double x); +int trunc(double x); +int ifloor(double x); +int iceil(double x); +double pi(); +double sqr(double x); +int maxint(int m1, int m2); +int minint(int m1, int m2); +double maxreal(double m1, double m2); +double minreal(double m1, double m2); + +bool fp_eq(double v1, double v2); +bool fp_neq(double v1, double v2); +bool fp_less(double v1, double v2); +bool fp_less_eq(double v1, double v2); +bool fp_greater(double v1, double v2); +bool fp_greater_eq(double v1, double v2); + +bool fp_isnan(double x); +bool fp_isposinf(double x); +bool fp_isneginf(double x); +bool fp_isinf(double x); +bool fp_isfinite(double x); + +/******************************************************************** +Exception handling macros +********************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +/////////////////////////////////////// +// exception-based code +////////////////////////////// +#define _ALGLIB_CPP_EXCEPTION(msg) throw alglib::ap_error(msg) +#define _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN try{ +#define _ALGLIB_CALLBACK_EXCEPTION_GUARD_END }catch(...){ ae_clean_up_before_breaking(&_alglib_env_state); throw; } + +#else + +/////////////////////////////////////// +// Exception-free version +////////////////////////////// +#if AE_OS!=AE_UNKNOWN +#error Exception-free mode can not be combined with AE_OS definition +#endif +#if AE_THREADING!=AE_SERIAL_UNSAFE +#error Exception-free mode is thread-unsafe; define AE_THREADING=AE_SERIAL_UNSAFE to prove that you know it +#endif +#define _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN +#define _ALGLIB_CALLBACK_EXCEPTION_GUARD_END +#define _ALGLIB_SET_ERROR_FLAG(s) set_error_flag(s) + +// sets eror flag and (optionally) sets error message +void set_error_flag(const char *s = NULL); + +// returns error flag and optionally returns error message (loaded to *p_msg); +// if error flag is not set (or p_msg is NULL) *p_msg is not changed. +bool get_error_flag(const char **p_msg = NULL); + +// clears error flag (it is not cleared until explicit call to this function) +void clear_error_flag(); +#endif + +}//namespace alglib + +namespace alglib_impl +{ + +/******************************************************************** +V2 reverse communication protocol +********************************************************************/ +class rcommv2_request; + +class rcommv2_buffers +{ +public: + // + // Initialize locals by attaching to buffers provided according to the V2 protocol; + // + // This constructor guarantees that no dynamic allocations needing non-trivial destruction will be performed. + // + rcommv2_buffers(ae_vector *t_x, ae_vector *t_c, ae_vector *t_f, ae_vector *t_g, ae_matrix *t_j, alglib_impl::sparsematrix *t_s):tmpX(t_x),tmpC(t_c),tmpF(t_f),tmpG(t_g),tmpJ(t_j),tmpS(t_s){} + + // initialize locals by allocating our own temporary storage + rcommv2_buffers(const rcommv2_request &rq); + + alglib::real_1d_array tmpX, tmpC, tmpF, tmpG; + alglib::real_2d_array tmpJ; + alglib::sparsematrix tmpS; +}; + +class rcommv2_callbacks +{ +public: + rcommv2_callbacks(); + + void (*func )(const alglib::real_1d_array &vars, double &func, void *ptr); + void (*grad )(const alglib::real_1d_array &vars, double &func, alglib::real_1d_array &grad, void *ptr); + void (*fvec )(const alglib::real_1d_array &vars, alglib::real_1d_array &fi, void *ptr); + void (*jac )(const alglib::real_1d_array &vars, alglib::real_1d_array &fi, alglib::real_2d_array &jac, void *ptr); + void (*sjac )(const alglib::real_1d_array &vars, alglib::real_1d_array &fi, alglib::sparsematrix &jac, void *ptr); + void (*func_p)(const alglib::real_1d_array &vars, const alglib::real_1d_array &point, double &func, void *ptr); + void (*grad_p)(const alglib::real_1d_array &vars, const alglib::real_1d_array &point, double &func, alglib::real_1d_array &grad, void *ptr); + void (*fvec_p)(const alglib::real_1d_array &vars, const alglib::real_1d_array &point, alglib::real_1d_array &fi, void *ptr); + void (*jac_p)(const alglib::real_1d_array &vars, const alglib::real_1d_array &point, alglib::real_1d_array &fi, alglib::real_2d_array &jac, void *ptr); + void (*sjac_p)(const alglib::real_1d_array &vars, const alglib::real_1d_array &point, alglib::real_1d_array &fi, alglib::sparsematrix &jac, void *ptr); +}; + +class rcommv2_request +{ +public: + enum query_order { query_sequential, query_justone }; + + // + // This constructor guarantees that no dynamic allocations needing non-trivial destruction will be performed. + // + rcommv2_request(ae_int_t &_rq, + ae_int_t &_sz, + ae_int_t &_fn, + ae_int_t &_vc, + ae_int_t &_di, + ae_int_t &_fs, + double *&_qd, + double *&_rf, + double *&_rj, + alglib_impl::sparsematrix &rs, + void *_ptr, + const char *_sp):subpackage(_sp),ptr(_ptr),query_data(_qd),request(_rq),size(_sz),funcs(_fn),vars(_vc),dim(_di),formulasize(_fs),reply_fi(_rf),reply_dj(_rj),reply_sj(rs){} + // + // Subpackage name + // + const char *subpackage; + + // + // Parameter to user callback + // + void *ptr; + + // + // Query + // + double* &query_data; + + // + // Params + // + ae_int_t &request, &size, &funcs, &vars, &dim, &formulasize; + + // + // Reply + // + double *&reply_fi, *&reply_dj; + alglib_impl::sparsematrix &reply_sj; +}; + +void process_v2request_1(rcommv2_request &request, ae_int_t query_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers, rcommv2_request::query_order order, alglib_impl::sparsematrix *dst_jacobian); +void process_v2request_2(rcommv2_request &request, ae_int_t query_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers); +void process_v2request_3phase0(rcommv2_request &request, ae_int_t job_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers); +void process_v2request_3phase1(rcommv2_request &request); +void process_v2request_4(rcommv2_request &request, ae_int_t query_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers); +void process_v2request_5phase0(rcommv2_request &request, ae_int_t job_idx, rcommv2_callbacks &callbacks, rcommv2_buffers &buffers); +void process_v2request_5phase1(rcommv2_request &request); + +} //namespace alglib_impl + + + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTIONS CONTAINS DECLARATIONS FOR OPTIMIZED LINEAR ALGEBRA CODES +// IT IS SHARED BETWEEN C++ AND PURE C LIBRARIES +// +///////////////////////////////////////////////////////////////////////// + + + +namespace alglib_impl +{ +#define ALGLIB_INTERCEPTS_ABLAS +void _ialglib_vzero(ae_int_t n, double *p, ae_int_t stride); +void _ialglib_vzero_complex(ae_int_t n, ae_complex *p, ae_int_t stride); +void _ialglib_vcopy(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb); +void _ialglib_vcopy_complex(ae_int_t n, const ae_complex *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); +void _ialglib_vcopy_dcomplex(ae_int_t n, const double *a, ae_int_t stridea, double *b, ae_int_t strideb, const char *conj); +void _ialglib_mcopyblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_int_t stride, double *b); +void _ialglib_mcopyunblock(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, double *b, ae_int_t stride); +void _ialglib_mcopyblock_complex(ae_int_t m, ae_int_t n, const ae_complex *a, ae_int_t op, ae_int_t stride, double *b); +void _ialglib_mcopyunblock_complex(ae_int_t m, ae_int_t n, const double *a, ae_int_t op, ae_complex* b, ae_int_t stride); + +ae_bool _ialglib_i_rmatrixgemmf(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + const ae_matrix *b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc); +ae_bool _ialglib_i_cmatrixgemmf(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + const ae_matrix *b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc); +ae_bool _ialglib_i_cmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2); +ae_bool _ialglib_i_rmatrixrighttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2); +ae_bool _ialglib_i_cmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2); +ae_bool _ialglib_i_rmatrixlefttrsmf(ae_int_t m, + ae_int_t n, + const ae_matrix *a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + ae_matrix *x, + ae_int_t i2, + ae_int_t j2); +ae_bool _ialglib_i_cmatrixherkf(ae_int_t n, + ae_int_t k, + double alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper); +ae_bool _ialglib_i_rmatrixsyrkf(ae_int_t n, + ae_int_t k, + double alpha, + const ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + ae_matrix *c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper); +ae_bool _ialglib_i_cmatrixrank1f(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs); +ae_bool _ialglib_i_rmatrixrank1f(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs); +ae_bool _ialglib_i_rmatrixgerf(ae_int_t m, + ae_int_t n, + ae_matrix *a, + ae_int_t ia, + ae_int_t ja, + double alpha, + const ae_vector *u, + ae_int_t uoffs, + const ae_vector *v, + ae_int_t voffs); + + + +#if !defined(ALGLIB_NO_FAST_KERNELS) + +#if defined(_ALGLIB_IMPL_DEFINES) + /* + * Arrays shorter than that will be processed with generic C implementation + */ + #if !defined(_ABLASF_KERNEL_SIZE1) + #define _ABLASF_KERNEL_SIZE1 16 + #endif + #if !defined(_ABLASF_KERNEL_SIZE2) + #define _ABLASF_KERNEL_SIZE2 16 + #endif + #define _ABLASF_BLOCK_SIZE 32 + #define _ABLASF_MICRO_SIZE 2 + #if defined(_ALGLIB_HAS_AVX2_INTRINSICS) || defined(_ALGLIB_HAS_FMA_INTRINSICS) + #define ULOAD256PD(x) _mm256_loadu_pd((const double*)(&x)) + #endif +#endif + +/* + * ABLASF kernels + */ +double rdotv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_state *_state); +double rdotvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_matrix* a, + ae_int_t i, + ae_state *_state); +double rdotrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_state *_state); +double rdotv2(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +void rcopyv(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rcopyvr(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state); +void rcopyrv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_vector* x, + ae_state *_state); +void rcopyrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i, + /* Real */ ae_matrix* b, + ae_int_t k, + ae_state *_state); +void rcopymulv(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rcopymulvr(ae_int_t n, + double v, + /* Real */ const ae_vector* x, + /* Real */ ae_matrix* y, + ae_int_t ridx, + ae_state *_state); +void icopyv(ae_int_t n, + /* Integer */ const ae_vector* x, + /* Integer */ ae_vector* y, + ae_state *_state); +void bcopyv(ae_int_t n, + /* Boolean */ const ae_vector* x, + /* Boolean */ ae_vector* y, + ae_state *_state); +void rsetv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state); +void rsetr(ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_int_t i, + ae_state *_state); +void rsetvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +void rsetm(ae_int_t m, + ae_int_t n, + double v, + /* Real */ ae_matrix* a, + ae_state *_state); +void isetv(ae_int_t n, + ae_int_t v, + /* Integer */ ae_vector* x, + ae_state *_state); +void bsetv(ae_int_t n, + ae_bool v, + /* Boolean */ ae_vector* x, + ae_state *_state); +void rmulv(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_state *_state); +void rmulr(ae_int_t n, + double v, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rsqrtv(ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); +void rsqrtr(ae_int_t n, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rmulvx(ae_int_t n, + double v, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +void raddv(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +void raddvr(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void raddrv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridx, + /* Real */ ae_vector* x, + ae_state *_state); +void raddrr(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* y, + ae_int_t ridxsrc, + /* Real */ ae_matrix* x, + ae_int_t ridxdst, + ae_state *_state); +void raddvx(ae_int_t n, + double alpha, + /* Real */ const ae_vector* y, + ae_int_t offsy, + /* Real */ ae_vector* x, + ae_int_t offsx, + ae_state *_state); +void rmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state); +void rnegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ ae_vector* x, + ae_state *_state); +void rcopymuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state); +void rcopynegmuladdv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* z, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + ae_state *_state); +void rmergemulv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergemulvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rmergemulrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergedivv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergedivvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rmergedivrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergemaxv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergemaxvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rmergemaxrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergeminv(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* x, + ae_state *_state); +void rmergeminvr(ae_int_t n, + /* Real */ const ae_vector* y, + /* Real */ ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rmergeminrv(ae_int_t n, + /* Real */ const ae_matrix* y, + ae_int_t rowidx, + /* Real */ ae_vector* x, + ae_state *_state); +double rmaxv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +double rmaxr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +double rmaxabsv(ae_int_t n, + /* Real */ const ae_vector* x, + ae_state *_state); +double rmaxabsr(ae_int_t n, + /* Real */ const ae_matrix* x, + ae_int_t rowidx, + ae_state *_state); +void rcopyvx(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t offsx, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); +void icopyvx(ae_int_t n, + /* Integer */ const ae_vector* x, + ae_int_t offsx, + /* Integer */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); + +void rgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t opa, + /* Real */ const ae_vector* x, + double beta, + /* Real */ ae_vector* y, + ae_state *_state); +void rgemvx(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +void rger(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + /* Real */ ae_matrix* a, + ae_state *_state); +void rtrsvx(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state); + +ae_bool ablasf_rgemm32basecase( + ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); + +/* + * Sparse supernodal Cholesky kernels + */ +ae_int_t spchol_spsymmgetmaxsimd(ae_state *_state); +void spchol_propagatefwd(/* Real */ const ae_vector* x, + ae_int_t cols0, + ae_int_t blocksize, + /* Integer */ const ae_vector* superrowidx, + ae_int_t rbase, + ae_int_t offdiagsize, + /* Real */ const ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sstride, + /* Real */ ae_vector* simdbuf, + ae_int_t simdwidth, + ae_state *_state); +extern ae_bool (*spchol_updatekernelabc4)(ae_vector*,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,ae_int_t,const ae_vector*,ae_int_t,const ae_vector*,const ae_vector*,ae_int_t,ae_state*); +ae_bool spchol_updatekernel4444(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state); + +/* + * Far field expansions for RBFs + */ +ae_bool rbfv3farfields_bhpaneleval1fastkernel(double d0, + double d1, + double d2, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state); +ae_bool rbfv3farfields_bhpanelevalfastkernel(double d0, + double d1, + double d2, + ae_int_t ny, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + /* Real */ ae_vector* f, + double* invpowrpplus1, + ae_state *_state); + +/* ALGLIB_NO_FAST_KERNELS */ +#endif + +} + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS PARALLEL SUBROUTINES +// +///////////////////////////////////////////////////////////////////////// + + +namespace alglib_impl +{ + +ae_int_t ae_cores_count(); + + +} + + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS DEFINITIONS FOR PARTIAL COMPILATION +// +///////////////////////////////////////////////////////////////////////// +#ifdef AE_COMPILE_APSERV +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_ABLASF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_XDEBUG +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_HQRND +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#endif + +#ifdef AE_COMPILE_HBLAS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_CREFLECTIONS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_SBLAS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_ABLASPBL +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_ABLAS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#endif + +#ifdef AE_COMPILE_ORTFAC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#endif + +#ifdef AE_COMPILE_MATGEN +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_SCODES +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_TSORT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#endif + +#ifdef AE_COMPILE_SPARSE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#endif + +#ifdef AE_COMPILE_BLAS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_ROTATIONS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_HSSCHUR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_BLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLAS +#endif + +#ifdef AE_COMPILE_BASICSTATOPS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#endif + +#ifdef AE_COMPILE_EVD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#endif + +#ifdef AE_COMPILE_DLU +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#endif + +#ifdef AE_COMPILE_SPTRF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#endif + +#ifdef AE_COMPILE_APSTRUCT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#endif + +#ifdef AE_COMPILE_AMDORDERING +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#endif + +#ifdef AE_COMPILE_SPCHOL +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#endif + +#ifdef AE_COMPILE_TRFAC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#endif + +#ifdef AE_COMPILE_POLYNOMIALSOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_TRFAC +#endif + +#ifdef AE_COMPILE_BDSVD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLAS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_SVD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#endif + +#ifdef AE_COMPILE_TRLINSOLVE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_SAFESOLVE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_RCOND +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#endif + +#ifdef AE_COMPILE_XBLAS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_DIRECTDENSESOLVERS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#endif + +#ifdef AE_COMPILE_FBLS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#endif + +#ifdef AE_COMPILE_ITERATIVESPARSE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_MATGEN +#endif + +#ifdef AE_COMPILE_LINCG +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#endif + +#ifdef AE_COMPILE_NORMESTIMATOR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#endif + +#ifdef AE_COMPILE_LINLSQR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#endif + +#ifdef AE_COMPILE_DIRECTSPARSESOLVERS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ITERATIVESPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_TRFAC +#define AE_COMPILE_NORMESTIMATOR +#endif + +#ifdef AE_COMPILE_LINMIN +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_NLEQ +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#endif + +#ifdef AE_COMPILE_OPTGUARDAPI +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_OPTS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#endif + +#ifdef AE_COMPILE_MATINV +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#endif + +#ifdef AE_COMPILE_OPTSERV +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#endif + +#ifdef AE_COMPILE_MINLBFGS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#endif + +#ifdef AE_COMPILE_CQMODELS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#endif + +#ifdef AE_COMPILE_LPQPSERV +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#endif + +#ifdef AE_COMPILE_SNNLS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#endif + +#ifdef AE_COMPILE_SACTIVESETS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_QQPSOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_FBLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#endif + +#ifdef AE_COMPILE_QPDENSEAULSOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#endif + +#ifdef AE_COMPILE_VIPMSOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_IPM2SOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_ECQPSOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_GIPM +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_GQPIPM +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_GIPM +#endif + +#ifdef AE_COMPILE_LPQPPRESOLVE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_MINQP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#endif + +#ifdef AE_COMPILE_NLCFSQP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#endif + +#ifdef AE_COMPILE_MINLM +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_LINMIN +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#endif + +#ifdef AE_COMPILE_NLCAUL +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_MINCG +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_DFGENMOD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCFSQP +#endif + +#ifdef AE_COMPILE_NLCSQP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#endif + +#ifdef AE_COMPILE_SSGD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_DIFFEVO +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#endif + +#ifdef AE_COMPILE_MINDF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SSGD +#define AE_COMPILE_DIFFEVO +#endif + +#ifdef AE_COMPILE_REVISEDDUALSIMPLEX +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPPRESOLVE +#endif + +#ifdef AE_COMPILE_LPSOLVERS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_REVISEDDUALSIMPLEX +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#endif + +#ifdef AE_COMPILE_NLS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_DFGENMOD +#endif + +#ifdef AE_COMPILE_GIPM2 +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_NLCGIPM2 +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_GIPM2 +#endif + +#ifdef AE_COMPILE_MINBLEIC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#endif + +#ifdef AE_COMPILE_MINNLC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#endif + +#ifdef AE_COMPILE_MONBI +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#endif + +#ifdef AE_COMPILE_MINMO +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#define AE_COMPILE_MONBI +#endif + +#ifdef AE_COMPILE_MINNS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#endif + +#ifdef AE_COMPILE_MINCOMP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#endif + +#ifdef AE_COMPILE_MINBC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#endif + +#ifdef AE_COMPILE_NEARESTNEIGHBOR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_ODESOLVER +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_INVERSEUPDATE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_SCHUR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#endif + +#ifdef AE_COMPILE_SPDGEVD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_SBLAS +#define AE_COMPILE_BLAS +#define AE_COMPILE_HBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#endif + +#ifdef AE_COMPILE_MATDET +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#endif + +#ifdef AE_COMPILE_GAMMAFUNC +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_GQ +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_GAMMAFUNC +#endif + +#ifdef AE_COMPILE_GKQ +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_GQ +#endif + +#ifdef AE_COMPILE_AUTOGK +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_GQ +#define AE_COMPILE_GKQ +#endif + +#ifdef AE_COMPILE_NORMALDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_IBETAF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#endif + +#ifdef AE_COMPILE_STUDENTTDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#endif + +#ifdef AE_COMPILE_BASESTAT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#endif + +#ifdef AE_COMPILE_CORRELATIONTESTS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#define AE_COMPILE_STUDENTTDISTR +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#endif + +#ifdef AE_COMPILE_JARQUEBERA +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_FDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#endif + +#ifdef AE_COMPILE_IGAMMAF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#endif + +#ifdef AE_COMPILE_CHISQUAREDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IGAMMAF +#endif + +#ifdef AE_COMPILE_VARIANCETESTS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#define AE_COMPILE_FDISTR +#define AE_COMPILE_IGAMMAF +#define AE_COMPILE_CHISQUAREDISTR +#endif + +#ifdef AE_COMPILE_WSR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#endif + +#ifdef AE_COMPILE_STUDENTTTESTS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#define AE_COMPILE_STUDENTTDISTR +#endif + +#ifdef AE_COMPILE_NEARUNITYUNIT +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_BINOMIALDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#define AE_COMPILE_NEARUNITYUNIT +#endif + +#ifdef AE_COMPILE_STEST +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IBETAF +#define AE_COMPILE_NEARUNITYUNIT +#define AE_COMPILE_BINOMIALDISTR +#endif + +#ifdef AE_COMPILE_NTHEORY +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_FTBASE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_NTHEORY +#endif + +#ifdef AE_COMPILE_FFT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_NTHEORY +#define AE_COMPILE_FTBASE +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_MCMC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_IBETAF +#define AE_COMPILE_STUDENTTDISTR +#define AE_COMPILE_STUDENTTTESTS +#define AE_COMPILE_NEARUNITYUNIT +#define AE_COMPILE_BINOMIALDISTR +#define AE_COMPILE_STEST +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_NTHEORY +#define AE_COMPILE_FTBASE +#define AE_COMPILE_FFT +#endif + +#ifdef AE_COMPILE_MANNWHITNEYU +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#endif + +#ifdef AE_COMPILE_RATINT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#endif + +#ifdef AE_COMPILE_IDW +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#endif + +#ifdef AE_COMPILE_INTFITSERV +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#endif + +#ifdef AE_COMPILE_POLINT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_RATINT +#endif + +#ifdef AE_COMPILE_SPLINE1D +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#endif + +#ifdef AE_COMPILE_LSFIT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_RATINT +#define AE_COMPILE_POLINT +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#endif + +#ifdef AE_COMPILE_FITSPHERE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#endif + +#ifdef AE_COMPILE_PARAMETRIC +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_GQ +#define AE_COMPILE_GKQ +#define AE_COMPILE_AUTOGK +#endif + +#ifdef AE_COMPILE_RBFV1 +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_RATINT +#define AE_COMPILE_POLINT +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#define AE_COMPILE_LSFIT +#endif + +#ifdef AE_COMPILE_RBFV3FARFIELDS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#endif + +#ifdef AE_COMPILE_RBFV3 +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_FBLS +#define AE_COMPILE_ITERATIVESPARSE +#define AE_COMPILE_RBFV3FARFIELDS +#endif + +#ifdef AE_COMPILE_SPLINE2D +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASF +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_FBLS +#define AE_COMPILE_SPLINE1D +#endif + +#ifdef AE_COMPILE_RBFV2 +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_RATINT +#define AE_COMPILE_POLINT +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#define AE_COMPILE_LSFIT +#endif + +#ifdef AE_COMPILE_SPLINE3D +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#endif + +#ifdef AE_COMPILE_INTCOMP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_LINMIN +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#define AE_COMPILE_FITSPHERE +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_RATINT +#define AE_COMPILE_POLINT +#define AE_COMPILE_LSFIT +#endif + +#ifdef AE_COMPILE_RBF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_SCODES +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_SPARSE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_RATINT +#define AE_COMPILE_POLINT +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_FBLS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_SPLINE1D +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MINQP +#define AE_COMPILE_MINLM +#define AE_COMPILE_LSFIT +#define AE_COMPILE_RBFV1 +#define AE_COMPILE_RBFV2 +#define AE_COMPILE_ITERATIVESPARSE +#define AE_COMPILE_RBFV3FARFIELDS +#define AE_COMPILE_RBFV3 +#endif + +#ifdef AE_COMPILE_FHT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_NTHEORY +#define AE_COMPILE_FTBASE +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_FFT +#endif + +#ifdef AE_COMPILE_CONV +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_NTHEORY +#define AE_COMPILE_FTBASE +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_FFT +#endif + +#ifdef AE_COMPILE_CORR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_NTHEORY +#define AE_COMPILE_FTBASE +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_FFT +#define AE_COMPILE_CONV +#endif + +#ifdef AE_COMPILE_EXPINTEGRALS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_JACOBIANELLIPTIC +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_TRIGINTEGRALS +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_CHEBYSHEV +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_POISSONDISTR +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IGAMMAF +#endif + +#ifdef AE_COMPILE_BETAF +#define AE_PARTIAL_BUILD +#define AE_COMPILE_GAMMAFUNC +#endif + +#ifdef AE_COMPILE_FRESNEL +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_PSIF +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_AIRYF +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_DAWSON +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_HERMITE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_LEGENDRE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_BESSEL +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_LAGUERRE +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_ELLIPTIC +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_PCA +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_BASESTAT +#endif + +#ifdef AE_COMPILE_BDSS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#endif + +#ifdef AE_COMPILE_HPCCORES +#define AE_PARTIAL_BUILD +#endif + +#ifdef AE_COMPILE_MLPBASE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#define AE_COMPILE_HPCCORES +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#endif + +#ifdef AE_COMPILE_MLPE +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#define AE_COMPILE_HPCCORES +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_MLPBASE +#endif + +#ifdef AE_COMPILE_CLUSTERING +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_BLAS +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_BASESTAT +#endif + +#ifdef AE_COMPILE_DFOREST +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#endif + +#ifdef AE_COMPILE_LINREG +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IGAMMAF +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#endif + +#ifdef AE_COMPILE_FILTERS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_GAMMAFUNC +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NORMALDISTR +#define AE_COMPILE_IGAMMAF +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_LINREG +#endif + +#ifdef AE_COMPILE_SSA +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#endif + +#ifdef AE_COMPILE_LDA +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_MATGEN +#define AE_COMPILE_SCODES +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#endif + +#ifdef AE_COMPILE_MCPD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#endif + +#ifdef AE_COMPILE_LOGIT +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#define AE_COMPILE_HPCCORES +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_MLPBASE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#endif + +#ifdef AE_COMPILE_KNN +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_NEARESTNEIGHBOR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#endif + +#ifdef AE_COMPILE_MLPTRAIN +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_BDSS +#define AE_COMPILE_HPCCORES +#define AE_COMPILE_SCODES +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_SPARSE +#define AE_COMPILE_MLPBASE +#define AE_COMPILE_MLPE +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#endif + +#ifdef AE_COMPILE_DATACOMP +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_ABLASF +#define AE_COMPILE_TSORT +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLAS +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_BLAS +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_BASESTAT +#define AE_COMPILE_CLUSTERING +#endif + +#ifdef AE_COMPILE_BBGD +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_HBLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_MATGEN +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#endif + +#ifdef AE_COMPILE_MIRBFVNS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_LINMIN +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_FBLS +#define AE_COMPILE_SNNLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_BBGD +#endif + +#ifdef AE_COMPILE_MINLPSOLVERS +#define AE_PARTIAL_BUILD +#define AE_COMPILE_APSERV +#define AE_COMPILE_SCODES +#define AE_COMPILE_ABLASPBL +#define AE_COMPILE_ABLASF +#define AE_COMPILE_XDEBUG +#define AE_COMPILE_HQRND +#define AE_COMPILE_TSORT +#define AE_COMPILE_SPARSE +#define AE_COMPILE_ABLAS +#define AE_COMPILE_CREFLECTIONS +#define AE_COMPILE_MATGEN +#define AE_COMPILE_DLU +#define AE_COMPILE_SPTRF +#define AE_COMPILE_APSTRUCT +#define AE_COMPILE_AMDORDERING +#define AE_COMPILE_SPCHOL +#define AE_COMPILE_ROTATIONS +#define AE_COMPILE_TRFAC +#define AE_COMPILE_HBLAS +#define AE_COMPILE_SBLAS +#define AE_COMPILE_ORTFAC +#define AE_COMPILE_BLAS +#define AE_COMPILE_BDSVD +#define AE_COMPILE_SVD +#define AE_COMPILE_HSSCHUR +#define AE_COMPILE_BASICSTATOPS +#define AE_COMPILE_EVD +#define AE_COMPILE_TRLINSOLVE +#define AE_COMPILE_SAFESOLVE +#define AE_COMPILE_RCOND +#define AE_COMPILE_MATINV +#define AE_COMPILE_XBLAS +#define AE_COMPILE_DIRECTDENSESOLVERS +#define AE_COMPILE_LINMIN +#define AE_COMPILE_OPTGUARDAPI +#define AE_COMPILE_OPTS +#define AE_COMPILE_OPTSERV +#define AE_COMPILE_FBLS +#define AE_COMPILE_MINLBFGS +#define AE_COMPILE_CQMODELS +#define AE_COMPILE_LPQPSERV +#define AE_COMPILE_IPM2SOLVER +#define AE_COMPILE_GIPM2 +#define AE_COMPILE_NLCGIPM2 +#define AE_COMPILE_SNNLS +#define AE_COMPILE_SACTIVESETS +#define AE_COMPILE_MINBLEIC +#define AE_COMPILE_VIPMSOLVER +#define AE_COMPILE_NLCSQP +#define AE_COMPILE_NLCFSQP +#define AE_COMPILE_NLCAUL +#define AE_COMPILE_DFGENMOD +#define AE_COMPILE_MINNLC +#define AE_COMPILE_BBGD +#define AE_COMPILE_LPQPPRESOLVE +#define AE_COMPILE_MIRBFVNS +#define AE_COMPILE_NORMESTIMATOR +#define AE_COMPILE_LINLSQR +#define AE_COMPILE_QQPSOLVER +#define AE_COMPILE_QPDENSEAULSOLVER +#define AE_COMPILE_ECQPSOLVER +#define AE_COMPILE_GIPM +#define AE_COMPILE_GQPIPM +#define AE_COMPILE_MINQP +#define AE_COMPILE_INTFITSERV +#define AE_COMPILE_SPLINE1D +#endif + +#ifdef AE_COMPILE_ALGLIBBASICS +#define AE_PARTIAL_BUILD +#endif + + + +#endif + diff --git a/core/alglib/dataanalysis.cpp b/core/alglib/dataanalysis.cpp index 79c433df..2d09ea3d 100644 --- a/core/alglib/dataanalysis.cpp +++ b/core/alglib/dataanalysis.cpp @@ -1,35078 +1,52622 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "dataanalysis.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Optimal binary classification - -Algorithms finds optimal (=with minimal cross-entropy) binary partition. -Internal subroutine. - -INPUT PARAMETERS: - A - array[0..N-1], variable - C - array[0..N-1], class numbers (0 or 1). - N - array size - -OUTPUT PARAMETERS: - Info - completion code: - * -3, all values of A[] are same (partition is impossible) - * -2, one of C[] is incorrect (<0, >1) - * -1, incorrect pararemets were passed (N<=0). - * 1, OK - Threshold- partiton boundary. Left part contains values which are - strictly less than Threshold. Right part contains values - which are greater than or equal to Threshold. - PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) - CVE - cross-validation estimate of cross-entropy - - -- ALGLIB -- - Copyright 22.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dsoptimalsplit2(const_cast(a.c_ptr()), const_cast(c.c_ptr()), n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Optimal partition, internal subroutine. Fast version. - -Accepts: - A array[0..N-1] array of attributes array[0..N-1] - C array[0..N-1] array of class labels - TiesBuf array[0..N] temporaries (ties) - CntBuf array[0..2*NC-1] temporaries (counts) - Alpha centering factor (0<=alpha<=1, recommended value - 0.05) - BufR array[0..N-1] temporaries - BufI array[0..N-1] temporaries - -Output: - Info error code (">0"=OK, "<0"=bad) - RMS training set RMS error - CVRMS leave-one-out RMS error - -Note: - content of all arrays is changed by subroutine; - it doesn't allocate temporaries. - - -- ALGLIB -- - Copyright 11.12.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dsoptimalsplit2fast(const_cast(a.c_ptr()), const_cast(c.c_ptr()), const_cast(tiesbuf.c_ptr()), const_cast(cntbuf.c_ptr()), const_cast(bufr.c_ptr()), const_cast(bufi.c_ptr()), n, nc, alpha, &info, &threshold, &rms, &cvrms, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This structure is a clusterization engine. - -You should not try to access its fields directly. -Use ALGLIB functions in order to work with this object. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -_clusterizerstate_owner::_clusterizerstate_owner() -{ - p_struct = (alglib_impl::clusterizerstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::clusterizerstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_clusterizerstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_clusterizerstate_owner::_clusterizerstate_owner(const _clusterizerstate_owner &rhs) -{ - p_struct = (alglib_impl::clusterizerstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::clusterizerstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_clusterizerstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_clusterizerstate_owner& _clusterizerstate_owner::operator=(const _clusterizerstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_clusterizerstate_clear(p_struct); - if( !alglib_impl::_clusterizerstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_clusterizerstate_owner::~_clusterizerstate_owner() -{ - alglib_impl::_clusterizerstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -clusterizerstate::clusterizerstate() : _clusterizerstate_owner() -{ -} - -clusterizerstate::clusterizerstate(const clusterizerstate &rhs):_clusterizerstate_owner(rhs) -{ -} - -clusterizerstate& clusterizerstate::operator=(const clusterizerstate &rhs) -{ - if( this==&rhs ) - return *this; - _clusterizerstate_owner::operator=(rhs); - return *this; -} - -clusterizerstate::~clusterizerstate() -{ -} - - -/************************************************************************* -This structure is used to store results of the agglomerative hierarchical -clustering (AHC). - -Following information is returned: - -* NPoints contains number of points in the original dataset - -* Z contains information about merges performed (see below). Z contains - indexes from the original (unsorted) dataset and it can be used when you - need to know what points were merged. However, it is not convenient when - you want to build a dendrograd (see below). - -* if you want to build dendrogram, you can use Z, but it is not good - option, because Z contains indexes from unsorted dataset. Dendrogram - built from such dataset is likely to have intersections. So, you have to - reorder you points before building dendrogram. - Permutation which reorders point is returned in P. Another representation - of merges, which is more convenient for dendorgram construction, is - returned in PM. - -* more information on format of Z, P and PM can be found below and in the - examples from ALGLIB Reference Manual. - -FORMAL DESCRIPTION OF FIELDS: - NPoints number of points - Z array[NPoints-1,2], contains indexes of clusters - linked in pairs to form clustering tree. I-th row - corresponds to I-th merge: - * Z[I,0] - index of the first cluster to merge - * Z[I,1] - index of the second cluster to merge - * Z[I,0](rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_ahcreport_owner& _ahcreport_owner::operator=(const _ahcreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_ahcreport_clear(p_struct); - if( !alglib_impl::_ahcreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_ahcreport_owner::~_ahcreport_owner() -{ - alglib_impl::_ahcreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::ahcreport* _ahcreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::ahcreport* _ahcreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -ahcreport::ahcreport() : _ahcreport_owner() ,npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) -{ -} - -ahcreport::ahcreport(const ahcreport &rhs):_ahcreport_owner(rhs) ,npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) -{ -} - -ahcreport& ahcreport::operator=(const ahcreport &rhs) -{ - if( this==&rhs ) - return *this; - _ahcreport_owner::operator=(rhs); - return *this; -} - -ahcreport::~ahcreport() -{ -} - - -/************************************************************************* -This structure is used to store results of the k-means++ clustering -algorithm. - -Following information is always returned: -* NPoints contains number of points in the original dataset -* TerminationType contains completion code, negative on failure, positive - on success -* K contains number of clusters - -For positive TerminationType we return: -* NFeatures contains number of variables in the original dataset -* C, which contains centers found by algorithm -* CIdx, which maps points of the original dataset to clusters - -FORMAL DESCRIPTION OF FIELDS: - NPoints number of points, >=0 - NFeatures number of variables, >=1 - TerminationType completion code: - * -5 if distance type is anything different from - Euclidean metric - * -3 for degenerate dataset: a) less than K distinct - points, b) K=0 for non-empty dataset. - * +1 for successful completion - K number of clusters - C array[K,NFeatures], rows of the array store centers - CIdx array[NPoints], which contains cluster indexes - - -- ALGLIB -- - Copyright 27.11.2012 by Bochkanov Sergey -*************************************************************************/ -_kmeansreport_owner::_kmeansreport_owner() -{ - p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_kmeansreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_kmeansreport_owner::_kmeansreport_owner(const _kmeansreport_owner &rhs) -{ - p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_kmeansreport_owner& _kmeansreport_owner::operator=(const _kmeansreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_kmeansreport_clear(p_struct); - if( !alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_kmeansreport_owner::~_kmeansreport_owner() -{ - alglib_impl::_kmeansreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -kmeansreport::kmeansreport() : _kmeansreport_owner() ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) -{ -} - -kmeansreport::kmeansreport(const kmeansreport &rhs):_kmeansreport_owner(rhs) ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) -{ -} - -kmeansreport& kmeansreport::operator=(const kmeansreport &rhs) -{ - if( this==&rhs ) - return *this; - _kmeansreport_owner::operator=(rhs); - return *this; -} - -kmeansreport::~kmeansreport() -{ -} - -/************************************************************************* -This function initializes clusterizer object. Newly initialized object is -empty, i.e. it does not contain dataset. You should use it as follows: -1. creation -2. dataset is added with ClusterizerSetPoints() -3. additional parameters are set -3. clusterization is performed with one of the clustering functions - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizercreate(clusterizerstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizercreate(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset to the clusterizer structure. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -NOTE 1: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - -NOTE 2: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric - * k-means++ clustering algorithm may be used only with Euclidean - distance function - Thus, list of specific clustering algorithms you may use depends - on distance function you specify when you set your dataset. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, nfeatures, disttype, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset to the clusterizer structure. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -NOTE 1: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - -NOTE 2: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric - * k-means++ clustering algorithm may be used only with Euclidean - distance function - Thus, list of specific clustering algorithms you may use depends - on distance function you specify when you set your dataset. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - ae_int_t nfeatures; - - npoints = xy.rows(); - nfeatures = xy.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, nfeatures, disttype, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset given by distance matrix to the clusterizer -structure. It is important that dataset is not given explicitly - only -distance matrix is given. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - D - array[NPoints,NPoints], distance matrix given by its upper - or lower triangle (main diagonal is ignored because its - entries are expected to be zero). - NPoints - number of points - IsUpper - whether upper or lower triangle of D is given. - -NOTE 1: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric, including one which is given by - distance matrix - * k-means++ clustering algorithm may be used only with Euclidean - distance function and explicitly given points - it can not be - used with dataset given by distance matrix - Thus, if you call this function, you will be unable to use k-means - clustering algorithm to process your problem. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetdistances(const_cast(s.c_ptr()), const_cast(d.c_ptr()), npoints, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset given by distance matrix to the clusterizer -structure. It is important that dataset is not given explicitly - only -distance matrix is given. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - D - array[NPoints,NPoints], distance matrix given by its upper - or lower triangle (main diagonal is ignored because its - entries are expected to be zero). - NPoints - number of points - IsUpper - whether upper or lower triangle of D is given. - -NOTE 1: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric, including one which is given by - distance matrix - * k-means++ clustering algorithm may be used only with Euclidean - distance function and explicitly given points - it can not be - used with dataset given by distance matrix - Thus, if you call this function, you will be unable to use k-means - clustering algorithm to process your problem. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - if( (d.rows()!=d.cols())) - throw ap_error("Error while calling 'clusterizersetdistances': looks like one of arguments has wrong size"); - npoints = d.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetdistances(const_cast(s.c_ptr()), const_cast(d.c_ptr()), npoints, isupper, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets agglomerative hierarchical clustering algorithm - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Algo - algorithm type: - * 0 complete linkage (default algorithm) - * 1 single linkage - * 2 unweighted average linkage - * 3 weighted average linkage - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetahcalgo(const clusterizerstate &s, const ae_int_t algo) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetahcalgo(const_cast(s.c_ptr()), algo, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets k-means++ properties : number of restarts and maximum -number of iterations per one run. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Restarts- restarts count, >=1. - k-means++ algorithm performs several restarts and chooses - best set of centers (one with minimum squared distance). - MaxIts - maximum number of k-means iterations performed during one - run. >=0, zero value means that algorithm performs unlimited - number of iterations. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetkmeanslimits(const clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizersetkmeanslimits(const_cast(s.c_ptr()), restarts, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function performs agglomerative hierarchical clustering - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - -OUTPUT PARAMETERS: - Rep - clustering results; see description of AHCReport - structure for more information. - -NOTE 1: hierarchical clustering algorithms require large amounts of memory. - In particular, this implementation needs sizeof(double)*NPoints^2 - bytes, which are used to store distance matrix. In case we work - with user-supplied matrix, this amount is multiplied by 2 (we have - to store original matrix and to work with its copy). - - For example, problem with 10000 points would require 800M of RAM, - even when working in a 1-dimensional space. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunahc(const clusterizerstate &s, ahcreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizerrunahc(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_clusterizerrunahc(const clusterizerstate &s, ahcreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_clusterizerrunahc(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function performs clustering by k-means++ algorithm. - -You may change algorithm properties like number of restarts or iterations -limit by calling ClusterizerSetKMeansLimits() functions. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - K - number of clusters, K>=0. - K can be zero only when algorithm is called for empty - dataset, in this case completion code is set to - success (+1). - If K=0 and dataset size is non-zero, we can not - meaningfully assign points to some center (there are no - centers because K=0) and return -3 as completion code - (failure). - -OUTPUT PARAMETERS: - Rep - clustering results; see description of KMeansReport - structure for more information. - -NOTE 1: k-means clustering can be performed only for datasets with - Euclidean distance function. Algorithm will return negative - completion code in Rep.TerminationType in case dataset was added - to clusterizer with DistType other than Euclidean (or dataset was - specified by distance matrix instead of explicitly given points). - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizerrunkmeans(const_cast(s.c_ptr()), k, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns distance matrix for dataset - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -OUTPUT PARAMETERS: - D - array[NPoints,NPoints], distance matrix - (full matrix is returned, with lower and upper triangles) - -NOTES: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::clusterizergetdistances(const_cast(xy.c_ptr()), npoints, nfeatures, disttype, const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_clusterizergetdistances(const_cast(xy.c_ptr()), npoints, nfeatures, disttype, const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function takes as input clusterization report Rep, desired clusters -count K, and builds top K clusters from hierarchical clusterization tree. -It returns assignment of points to clusters (array of cluster indexes). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - K - desired number of clusters, 1<=K<=NPoints. - K can be zero only when NPoints=0. - -OUTPUT PARAMETERS: - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I](rep.c_ptr()), k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function accepts AHC report Rep, desired minimum intercluster -distance and returns top clusters from hierarchical clusterization tree -which are separated by distance R or HIGHER. - -It returns assignment of points to clusters (array of cluster indexes). - -There is one more function with similar name - ClusterizerSeparatedByCorr, -which returns clusters with intercluster correlation equal to R or LOWER -(note: higher for distance, lower for correlation). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - R - desired minimum intercluster distance, R>=0 - -OUTPUT PARAMETERS: - K - number of clusters, 1<=K<=NPoints - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I](rep.c_ptr()), r, &k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function accepts AHC report Rep, desired maximum intercluster -correlation and returns top clusters from hierarchical clusterization tree -which are separated by correlation R or LOWER. - -It returns assignment of points to clusters (array of cluster indexes). - -There is one more function with similar name - ClusterizerSeparatedByDist, -which returns clusters with intercluster distance equal to R or HIGHER -(note: higher for distance, lower for correlation). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - R - desired maximum intercluster correlation, -1<=R<=+1 - -OUTPUT PARAMETERS: - K - number of clusters, 1<=K<=NPoints - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I](rep.c_ptr()), r, &k, const_cast(cidx.c_ptr()), const_cast(cz.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -k-means++ clusterization. -Backward compatibility function, we recommend to use CLUSTERING subpackage -as better replacement. - - -- ALGLIB -- - Copyright 21.03.2009 by Bochkanov Sergey -*************************************************************************/ -void kmeansgenerate(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t k, const ae_int_t restarts, ae_int_t &info, real_2d_array &c, integer_1d_array &xyc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::kmeansgenerate(const_cast(xy.c_ptr()), npoints, nvars, k, restarts, &info, const_cast(c.c_ptr()), const_cast(xyc.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_decisionforest_owner::_decisionforest_owner() -{ - p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_decisionforest_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_decisionforest_owner::_decisionforest_owner(const _decisionforest_owner &rhs) -{ - p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_decisionforest_owner& _decisionforest_owner::operator=(const _decisionforest_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_decisionforest_clear(p_struct); - if( !alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_decisionforest_owner::~_decisionforest_owner() -{ - alglib_impl::_decisionforest_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::decisionforest* _decisionforest_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::decisionforest* _decisionforest_owner::c_ptr() const -{ - return const_cast(p_struct); -} -decisionforest::decisionforest() : _decisionforest_owner() -{ -} - -decisionforest::decisionforest(const decisionforest &rhs):_decisionforest_owner(rhs) -{ -} - -decisionforest& decisionforest::operator=(const decisionforest &rhs) -{ - if( this==&rhs ) - return *this; - _decisionforest_owner::operator=(rhs); - return *this; -} - -decisionforest::~decisionforest() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_dfreport_owner::_dfreport_owner() -{ - p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_dfreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_dfreport_owner::_dfreport_owner(const _dfreport_owner &rhs) -{ - p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_dfreport_owner& _dfreport_owner::operator=(const _dfreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_dfreport_clear(p_struct); - if( !alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_dfreport_owner::~_dfreport_owner() -{ - alglib_impl::_dfreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::dfreport* _dfreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::dfreport* _dfreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -dfreport::dfreport() : _dfreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror) -{ -} - -dfreport::dfreport(const dfreport &rhs):_dfreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror) -{ -} - -dfreport& dfreport::operator=(const dfreport &rhs) -{ - if( this==&rhs ) - return *this; - _dfreport_owner::operator=(rhs); - return *this; -} - -dfreport::~dfreport() -{ -} - - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void dfserialize(decisionforest &obj, std::string &s_out) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - alglib_impl::ae_int_t ssize; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_alloc_start(&serializer); - alglib_impl::dfalloc(&serializer, obj.c_ptr(), &state); - ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); - s_out.clear(); - s_out.reserve((size_t)(ssize+1)); - alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); - alglib_impl::dfserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - if( s_out.length()>(size_t)ssize ) - throw ap_error("ALGLIB: serialization integrity error"); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void dfunserialize(std::string &s_in, decisionforest &obj) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); - alglib_impl::dfunserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} - -/************************************************************************* -This subroutine builds random decision forest. - -INPUT PARAMETERS: - XY - training set - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dfbuildrandomdecisionforest(const_cast(xy.c_ptr()), npoints, nvars, nclasses, ntrees, r, &info, const_cast(df.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds random decision forest. -This function gives ability to tune number of variables used when choosing -best split. - -INPUT PARAMETERS: - XY - training set - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - NRndVars - number of variables used when choosing best split - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dfbuildrandomdecisionforestx1(const_cast(xy.c_ptr()), npoints, nvars, nclasses, ntrees, nrndvars, r, &info, const_cast(df.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - DF - decision forest model - X - input vector, array[0..NVars-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also DFProcessI. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dfprocess(const_cast(df.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -'interactive' variant of DFProcess for languages like Python which support -constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::dfprocessi(const_cast(df.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dfrelclserror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dfavgce(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for - classification task, RMS error means error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dfrmserror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dfavgerror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average relative error when estimating - posterior probability of belonging to the correct class. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dfavgrelerror(const_cast(df.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_linearmodel_owner::_linearmodel_owner() -{ - p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linearmodel_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linearmodel_owner::_linearmodel_owner(const _linearmodel_owner &rhs) -{ - p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linearmodel_owner& _linearmodel_owner::operator=(const _linearmodel_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_linearmodel_clear(p_struct); - if( !alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_linearmodel_owner::~_linearmodel_owner() -{ - alglib_impl::_linearmodel_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::linearmodel* _linearmodel_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::linearmodel* _linearmodel_owner::c_ptr() const -{ - return const_cast(p_struct); -} -linearmodel::linearmodel() : _linearmodel_owner() -{ -} - -linearmodel::linearmodel(const linearmodel &rhs):_linearmodel_owner(rhs) -{ -} - -linearmodel& linearmodel::operator=(const linearmodel &rhs) -{ - if( this==&rhs ) - return *this; - _linearmodel_owner::operator=(rhs); - return *this; -} - -linearmodel::~linearmodel() -{ -} - - -/************************************************************************* -LRReport structure contains additional information about linear model: -* C - covariation matrix, array[0..NVars,0..NVars]. - C[i,j] = Cov(A[i],A[j]) -* RMSError - root mean square error on a training set -* AvgError - average error on a training set -* AvgRelError - average relative error on a training set (excluding - observations with zero function value). -* CVRMSError - leave-one-out cross-validation estimate of - generalization error. Calculated using fast algorithm - with O(NVars*NPoints) complexity. -* CVAvgError - cross-validation estimate of average error -* CVAvgRelError - cross-validation estimate of average relative error - -All other fields of the structure are intended for internal use and should -not be used outside ALGLIB. -*************************************************************************/ -_lrreport_owner::_lrreport_owner() -{ - p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lrreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lrreport_owner::_lrreport_owner(const _lrreport_owner &rhs) -{ - p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lrreport_owner& _lrreport_owner::operator=(const _lrreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_lrreport_clear(p_struct); - if( !alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_lrreport_owner::~_lrreport_owner() -{ - alglib_impl::_lrreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::lrreport* _lrreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::lrreport* _lrreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -lrreport::lrreport() : _lrreport_owner() ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) -{ -} - -lrreport::lrreport(const lrreport &rhs):_lrreport_owner(rhs) ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) -{ -} - -lrreport& lrreport::operator=(const lrreport &rhs) -{ - if( this==&rhs ) - return *this; - _lrreport_owner::operator=(rhs); - return *this; -} - -lrreport::~lrreport() -{ -} - -/************************************************************************* -Linear regression - -Subroutine builds model: - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) - -and model found in ALGLIB format, covariation matrix, training set errors -(rms, average, average relative) and leave-one-out cross-validation -estimate of the generalization error. CV estimate calculated using fast -algorithm with O(NPoints*NVars) complexity. - -When covariation matrix is calculated standard deviations of function -values are assumed to be equal to RMS error on the training set. - -INPUT PARAMETERS: - XY - training set, array [0..NPoints-1,0..NVars]: - * NVars columns - independent variables - * last column - dependent variable - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPoints(xy.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Linear regression - -Variant of LRBuild which uses vector of standatd deviations (errors in -function values). - -INPUT PARAMETERS: - XY - training set, array [0..NPoints-1,0..NVars]: - * NVars columns - independent variables - * last column - dependent variable - S - standard deviations (errors in function values) - array[0..NPoints-1], S[i]>0. - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPoints(xy.c_ptr()), const_cast(s.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like LRBuildS, but builds model - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] - -i.e. with zero constant term. - - -- ALGLIB -- - Copyright 30.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, linearmodel &lm, lrreport &ar) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lrbuildzs(const_cast(xy.c_ptr()), const_cast(s.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like LRBuild but builds model - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] - -i.e. with zero constant term. - - -- ALGLIB -- - Copyright 30.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lrbuildz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, linearmodel &lm, lrreport &ar) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lrbuildz(const_cast(xy.c_ptr()), npoints, nvars, &info, const_cast(lm.c_ptr()), const_cast(ar.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacks coefficients of linear model. - -INPUT PARAMETERS: - LM - linear model in ALGLIB format - -OUTPUT PARAMETERS: - V - coefficients, array[0..NVars] - constant term (intercept) is stored in the V[NVars]. - NVars - number of independent variables (one less than number - of coefficients) - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -void lrunpack(const linearmodel &lm, real_1d_array &v, ae_int_t &nvars) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lrunpack(const_cast(lm.c_ptr()), const_cast(v.c_ptr()), &nvars, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack -reversed). - -INPUT PARAMETERS: - V - coefficients, array[0..NVars] - NVars - number of independent variables - -OUTPUT PAREMETERS: - LM - linear model. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -void lrpack(const real_1d_array &v, const ae_int_t nvars, linearmodel &lm) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lrpack(const_cast(v.c_ptr()), nvars, const_cast(lm.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - LM - linear model - X - input vector, array[0..NVars-1]. - -Result: - value of linear model regression estimate - - -- ALGLIB -- - Copyright 03.09.2008 by Bochkanov Sergey -*************************************************************************/ -double lrprocess(const linearmodel &lm, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::lrprocess(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lrrmserror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::lrrmserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - average error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lravgerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::lravgerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - average relative error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lravgrelerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::lravgrelerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: simple moving averages (unsymmetric). - -This filter replaces array by results of SMA(K) filter. SMA(K) is defined -as filter which averages at most K previous points (previous - not points -AROUND central point) - or less, in case of the first K-1 points. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::filtersma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: simple moving averages (unsymmetric). - -This filter replaces array by results of SMA(K) filter. SMA(K) is defined -as filter which averages at most K previous points (previous - not points -AROUND central point) - or less, in case of the first K-1 points. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filtersma(real_1d_array &x, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::filtersma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: exponential moving averages. - -This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is -defined as filter which replaces X[] by S[]: - S[0] = X[0] - S[t] = alpha*X[t] + (1-alpha)*S[t-1] - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - alpha - 0(x.c_ptr()), n, alpha, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: exponential moving averages. - -This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is -defined as filter which replaces X[] by S[]: - S[0] = X[0] - S[t] = alpha*X[t] + (1-alpha)*S[t-1] - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - alpha - 0(x.c_ptr()), n, alpha, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: linear regression moving averages. - -This filter replaces array by results of LRMA(K) filter. - -LRMA(K) is defined as filter which, for each data point, builds linear -regression model using K prevous points (point itself is included in -these K points) and calculates value of this linear model at the point in -question. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::filterlrma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Filters: linear regression moving averages. - -This filter replaces array by results of LRMA(K) filter. - -LRMA(K) is defined as filter which, for each data point, builds linear -regression model using K prevous points (point itself is included in -these K points) and calculates value of this linear model at the point in -question. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filterlrma(real_1d_array &x, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::filterlrma(const_cast(x.c_ptr()), n, k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiclass Fisher LDA - -Subroutine finds coefficients of linear combination which optimally separates -training set on classes. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - linear combination coefficients, array[0..NVars-1] - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fisherlda(const_cast(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -N-dimensional multiclass Fisher LDA - -Subroutine finds coefficients of linear combinations which optimally separates -training set on classes. It returns N-dimensional basis whose vector are sorted -by quality of training set separation (in descending order). - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - basis, array[0..NVars-1,0..NVars-1] - columns of matrix stores basis vectors, sorted by - quality of training set separation (in descending order) - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fisherldan(const_cast(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Model's errors: - * RelCLSError - fraction of misclassified cases. - * AvgCE - acerage cross-entropy - * RMSError - root-mean-square error - * AvgError - average error - * AvgRelError - average relative error - -NOTE 1: RelCLSError/AvgCE are zero on regression problems. - -NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain - errors in prediction of posterior probabilities -*************************************************************************/ -_modelerrors_owner::_modelerrors_owner() -{ - p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_modelerrors_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_modelerrors_owner::_modelerrors_owner(const _modelerrors_owner &rhs) -{ - p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_modelerrors_owner& _modelerrors_owner::operator=(const _modelerrors_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_modelerrors_clear(p_struct); - if( !alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_modelerrors_owner::~_modelerrors_owner() -{ - alglib_impl::_modelerrors_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::modelerrors* _modelerrors_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::modelerrors* _modelerrors_owner::c_ptr() const -{ - return const_cast(p_struct); -} -modelerrors::modelerrors() : _modelerrors_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) -{ -} - -modelerrors::modelerrors(const modelerrors &rhs):_modelerrors_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) -{ -} - -modelerrors& modelerrors::operator=(const modelerrors &rhs) -{ - if( this==&rhs ) - return *this; - _modelerrors_owner::operator=(rhs); - return *this; -} - -modelerrors::~modelerrors() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_multilayerperceptron_owner::_multilayerperceptron_owner() -{ - p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_multilayerperceptron_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_multilayerperceptron_owner::_multilayerperceptron_owner(const _multilayerperceptron_owner &rhs) -{ - p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_multilayerperceptron_owner& _multilayerperceptron_owner::operator=(const _multilayerperceptron_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_multilayerperceptron_clear(p_struct); - if( !alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_multilayerperceptron_owner::~_multilayerperceptron_owner() -{ - alglib_impl::_multilayerperceptron_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() const -{ - return const_cast(p_struct); -} -multilayerperceptron::multilayerperceptron() : _multilayerperceptron_owner() -{ -} - -multilayerperceptron::multilayerperceptron(const multilayerperceptron &rhs):_multilayerperceptron_owner(rhs) -{ -} - -multilayerperceptron& multilayerperceptron::operator=(const multilayerperceptron &rhs) -{ - if( this==&rhs ) - return *this; - _multilayerperceptron_owner::operator=(rhs); - return *this; -} - -multilayerperceptron::~multilayerperceptron() -{ -} - - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void mlpserialize(multilayerperceptron &obj, std::string &s_out) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - alglib_impl::ae_int_t ssize; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_alloc_start(&serializer); - alglib_impl::mlpalloc(&serializer, obj.c_ptr(), &state); - ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); - s_out.clear(); - s_out.reserve((size_t)(ssize+1)); - alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); - alglib_impl::mlpserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - if( s_out.length()>(size_t)ssize ) - throw ap_error("ALGLIB: serialization integrity error"); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void mlpunserialize(std::string &s_in, multilayerperceptron &obj) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); - alglib_impl::mlpunserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers, with linear output layer. Network weights are filled with small -random values. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreate0(nin, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreate0, but with one hidden layer (NHid neurons) with -non-linear activation function. Output layer is linear. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreate1(nin, nhid, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) -with non-linear activation function. Output layer is linear. - $ALL - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreate2(nin, nhid1, nhid2, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. - -Activation function of the output layer takes values: - - (B, +INF), if D>=0 - -or - - (-INF, B), if D<0. - - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreateb0(nin, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateB0 but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreateb1(nin, nhid, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateB0 but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreateb2(nin, nhid1, nhid2, nout, b, d, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. Activation function of the output layer takes values [A,B]. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreater0(nin, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateR0, but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreater1(nin, nhid, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateR0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreater2(nin, nhid1, nhid2, nout, a, b, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creates classifier network with NIn inputs and NOut possible classes. -Network contains no hidden layers and linear output layer with SOFTMAX- -normalization (so outputs sums up to 1.0 and converge to posterior -probabilities). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreatec0(nin, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateC0, but with one non-linear hidden layer. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreatec1(nin, nhid, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Same as MLPCreateC0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreatec2(nin, nhid1, nhid2, nout, const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Randomization of neural network weights - - -- ALGLIB -- - Copyright 06.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlprandomize(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlprandomize(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Randomization of neural network weights and standartisator - - -- ALGLIB -- - Copyright 10.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlprandomizefull(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlprandomizefull(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns information about initialized network: number of inputs, outputs, -weights. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpproperties(const_cast(network.c_ptr()), &nin, &nout, &wcount, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns number of inputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetinputscount(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpgetinputscount(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns number of outputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetoutputscount(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpgetoutputscount(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns number of weights. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetweightscount(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpgetweightscount(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -bool mlpissoftmax(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::mlpissoftmax(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns total number of layers (including input, hidden and -output layers). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayerscount(const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpgetlayerscount(const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns size of K-th layer. - -K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. - -Size of the output layer is always equal to the number of outputs, although -when we have softmax-normalized network, last neuron doesn't have any -connections - it is just zero. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpgetlayersize(const_cast(network.c_ptr()), k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgetinputscaling(const_cast(network.c_ptr()), i, &mean, &sigma, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. In case we have SOFTMAX-normalized network, -we return (Mean,Sigma)=(0.0,1.0). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgetoutputscaling(const_cast(network.c_ptr()), i, &mean, &sigma, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - -OUTPUT PARAMETERS: - FKind - activation function type (used by MLPActivationFunction()) - this value is zero for input or linear neurons - Threshold - also called offset, bias - zero for input neurons - -NOTE: this function throws exception if layer or neuron with given index -do not exists. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgetneuroninfo(const_cast(network.c_ptr()), k, i, &fkind, &threshold, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - -RESULT: - connection weight (zero for non-existent connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. returns zero if neurons exist, but there is no connection between them - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -double mlpgetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpgetweight(const_cast(network.c_ptr()), k0, i0, k1, i1, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -NTE: I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network. This function sets Mean and Sigma. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetinputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetinputscaling(const_cast(network.c_ptr()), i, mean, sigma, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -OUTPUT PARAMETERS: - -NOTE: I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. This function sets Sigma/Mean. In case we -have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything -other than(0.0,1.0) - this function will throw exception. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetoutputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetoutputscaling(const_cast(network.c_ptr()), i, mean, sigma, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function modifies information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - FKind - activation function type (used by MLPActivationFunction()) - this value must be zero for input neurons - (you can not set activation function for input neurons) - Threshold - also called offset, bias - this value must be zero for input neurons - (you can not set threshold for input neurons) - -NOTES: -1. this function throws exception if layer or neuron with given index do - not exists. -2. this function also throws exception when you try to set non-linear - activation function for input neurons (any kind of network) or for output - neurons of classifier network. -3. this function throws exception when you try to set non-zero threshold for - input neurons (any kind of network). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetneuroninfo(const_cast(network.c_ptr()), k, i, fkind, threshold, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function modifies information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - W - connection weight (must be zero for non-existent - connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. throws exception if you try to set non-zero weight for non-existent - connection - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetweight(const_cast(network.c_ptr()), k0, i0, k1, i1, w, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Neural network activation function - -INPUT PARAMETERS: - NET - neuron input - K - function index (zero for linear function) - -OUTPUT PARAMETERS: - F - function - DF - its derivative - D2F - its second derivative - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpactivationfunction(net, k, &f, &df, &d2f, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Network - neural network - X - input vector, array[0..NIn-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also MLPProcessI - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpprocess(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpprocess(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -'interactive' variant of MLPProcess for languages like Python which -support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 21.09.2010 by Bochkanov Sergey -*************************************************************************/ -void mlpprocessi(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpprocessi(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlperror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Error of the neural network on dataset given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0 - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlperrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Natural error function for neural network, internal subroutine. - -NOTE: this function is single-threaded. Unlike other error function, it -receives no speed-up from being executed in SMP mode. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperrorn(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperrorn(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Classification error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - classification error (number of misclassified cases) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mlpclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -ae_int_t smp_mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::_pexec_mlpclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Relative classification error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 25.12.2008 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlprelclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlprelclserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Relative classification error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. Sparse matrix must use CRS format - for storage. - NPoints - points count, >=0. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlprelclserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlprelclserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 08.01.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgce(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgce(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set given by -sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 9.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgcesparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgcesparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set given. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlprmserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlprmserror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlprmserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlprmserrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average absolute error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average absolute error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average relative error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgrelerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgrelerror(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average relative error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpavgrelerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlpavgrelerrorsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Gradient calculation - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgrad(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgrad(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(desiredy.c_ptr()), &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Gradient calculation (natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradn(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradn(const_cast(network.c_ptr()), const_cast(x.c_ptr()), const_cast(desiredy.c_ptr()), &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpgradbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs given by sparse -matrices - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs. - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradbatchsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpgradbatchsparse(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch gradient calculation for a subset of dataset - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradbatchsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpgradbatchsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs for a subset of -dataset given by set of indexes. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse - function. - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradbatchsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpgradbatchsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(idx.c_ptr()), subsetsize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs -(natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - set of inputs/outputs; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradnbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpgradnbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch Hessian calculation (natural error function) using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessiannbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlphessiannbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), const_cast(h.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Batch Hessian calculation using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessianbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlphessianbatch(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), ssize, &e, const_cast(grad.c_ptr()), const_cast(h.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of all types of errors. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpallerrorssubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpallerrorssubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of all types of errors on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset given by sparse matrix; - one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpallerrorssparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpallerrorssparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperrorsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlperrorsubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Error of the neural network on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - SetSize - real size of XY, SetSize>=0; - it is used when SubsetSize<0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperrorsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -double smp_mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::_pexec_mlperrorsparsesubset(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), setsize, const_cast(subset.c_ptr()), subsetsize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_logitmodel_owner::_logitmodel_owner() -{ - p_struct = (alglib_impl::logitmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::logitmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_logitmodel_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_logitmodel_owner::_logitmodel_owner(const _logitmodel_owner &rhs) -{ - p_struct = (alglib_impl::logitmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::logitmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_logitmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_logitmodel_owner& _logitmodel_owner::operator=(const _logitmodel_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_logitmodel_clear(p_struct); - if( !alglib_impl::_logitmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_logitmodel_owner::~_logitmodel_owner() -{ - alglib_impl::_logitmodel_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::logitmodel* _logitmodel_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::logitmodel* _logitmodel_owner::c_ptr() const -{ - return const_cast(p_struct); -} -logitmodel::logitmodel() : _logitmodel_owner() -{ -} - -logitmodel::logitmodel(const logitmodel &rhs):_logitmodel_owner(rhs) -{ -} - -logitmodel& logitmodel::operator=(const logitmodel &rhs) -{ - if( this==&rhs ) - return *this; - _logitmodel_owner::operator=(rhs); - return *this; -} - -logitmodel::~logitmodel() -{ -} - - -/************************************************************************* -MNLReport structure contains information about training process: -* NGrad - number of gradient calculations -* NHess - number of Hessian calculations -*************************************************************************/ -_mnlreport_owner::_mnlreport_owner() -{ - p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mnlreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mnlreport_owner::_mnlreport_owner(const _mnlreport_owner &rhs) -{ - p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mnlreport_owner& _mnlreport_owner::operator=(const _mnlreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mnlreport_clear(p_struct); - if( !alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mnlreport_owner::~_mnlreport_owner() -{ - alglib_impl::_mnlreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mnlreport* _mnlreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mnlreport* _mnlreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mnlreport::mnlreport() : _mnlreport_owner() ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) -{ -} - -mnlreport::mnlreport(const mnlreport &rhs):_mnlreport_owner(rhs) ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) -{ -} - -mnlreport& mnlreport::operator=(const mnlreport &rhs) -{ - if( this==&rhs ) - return *this; - _mnlreport_owner::operator=(rhs); - return *this; -} - -mnlreport::~mnlreport() -{ -} - -/************************************************************************* -This subroutine trains logit model. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars] - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints(xy.c_ptr()), npoints, nvars, nclasses, &info, const_cast(lm.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - LM - logit model, passed by non-constant reference - (some fields of structure are used as temporaries - when calculating model output). - X - input vector, array[0..NVars-1]. - Y - (possibly) preallocated buffer; if size of Y is less than - NClasses, it will be reallocated.If it is large enough, it - is NOT reallocated, so we can save some time on reallocation. - -OUTPUT PARAMETERS: - Y - result, array[0..NClasses-1] - Vector of posterior probabilities for classification task. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlprocess(const logitmodel &lm, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mnlprocess(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -'interactive' variant of MNLProcess for languages like Python which -support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlprocessi(const logitmodel &lm, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mnlprocessi(const_cast(lm.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacks coefficients of logit model. Logit model have form: - - P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) - S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when i(lm.c_ptr()), const_cast(a.c_ptr()), &nvars, &nclasses, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -"Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack -reversed). - -INPUT PARAMETERS: - A - model (see MNLUnpack) - NVars - number of independent variables - NClasses - number of classes - -OUTPUT PARAMETERS: - LM - logit model. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlpack(const real_2d_array &a, const ae_int_t nvars, const ae_int_t nclasses, logitmodel &lm) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mnlpack(const_cast(a.c_ptr()), nvars, nclasses, const_cast(lm.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*ln(2)). - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgce(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mnlavgce(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlrelclserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mnlrelclserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - root mean square error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlrmserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mnlrmserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - average error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgerror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mnlavgerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - average relative error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgrelerror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t ssize) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mnlavgrelerror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), ssize, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Classification error on test set = MNLRelClsError*NPoints - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mnlclserror(const logitmodel &lm, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::mnlclserror(const_cast(lm.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This structure is a MCPD (Markov Chains for Population Data) solver. - -You should use ALGLIB functions in order to work with this object. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -_mcpdstate_owner::_mcpdstate_owner() -{ - p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mcpdstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mcpdstate_owner::_mcpdstate_owner(const _mcpdstate_owner &rhs) -{ - p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mcpdstate_owner& _mcpdstate_owner::operator=(const _mcpdstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mcpdstate_clear(p_struct); - if( !alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mcpdstate_owner::~_mcpdstate_owner() -{ - alglib_impl::_mcpdstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mcpdstate::mcpdstate() : _mcpdstate_owner() -{ -} - -mcpdstate::mcpdstate(const mcpdstate &rhs):_mcpdstate_owner(rhs) -{ -} - -mcpdstate& mcpdstate::operator=(const mcpdstate &rhs) -{ - if( this==&rhs ) - return *this; - _mcpdstate_owner::operator=(rhs); - return *this; -} - -mcpdstate::~mcpdstate() -{ -} - - -/************************************************************************* -This structure is a MCPD training report: - InnerIterationsCount - number of inner iterations of the - underlying optimization algorithm - OuterIterationsCount - number of outer iterations of the - underlying optimization algorithm - NFEV - number of merit function evaluations - TerminationType - termination type - (same as for MinBLEIC optimizer, positive - values denote success, negative ones - - failure) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -_mcpdreport_owner::_mcpdreport_owner() -{ - p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mcpdreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mcpdreport_owner::_mcpdreport_owner(const _mcpdreport_owner &rhs) -{ - p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mcpdreport_owner& _mcpdreport_owner::operator=(const _mcpdreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mcpdreport_clear(p_struct); - if( !alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mcpdreport_owner::~_mcpdreport_owner() -{ - alglib_impl::_mcpdreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mcpdreport::mcpdreport() : _mcpdreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) -{ -} - -mcpdreport::mcpdreport(const mcpdreport &rhs):_mcpdreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) -{ -} - -mcpdreport& mcpdreport::operator=(const mcpdreport &rhs) -{ - if( this==&rhs ) - return *this; - _mcpdreport_owner::operator=(rhs); - return *this; -} - -mcpdreport::~mcpdreport() -{ -} - -/************************************************************************* -DESCRIPTION: - -This function creates MCPD (Markov Chains for Population Data) solver. - -This solver can be used to find transition matrix P for N-dimensional -prediction problem where transition from X[i] to X[i+1] is modelled as - X[i+1] = P*X[i] -where X[i] and X[i+1] are N-dimensional population vectors (components of -each X are non-negative), and P is a N*N transition matrix (elements of P -are non-negative, each column sums to 1.0). - -Such models arise when when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is constant, i.e. there is no new individuals and no one - leaves population -* you want to model transitions of individuals from one state into another - -USAGE: - -Here we give very brief outline of the MCPD. We strongly recommend you to -read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on data analysis which is available at http://www.alglib.net/dataanalysis/ - -1. User initializes algorithm state with MCPDCreate() call - -2. User adds one or more tracks - sequences of states which describe - evolution of a system being modelled from different starting conditions - -3. User may add optional boundary, equality and/or linear constraints on - the coefficients of P by calling one of the following functions: - * MCPDSetEC() to set equality constraints - * MCPDSetBC() to set bound constraints - * MCPDSetLC() to set linear constraints - -4. Optionally, user may set custom weights for prediction errors (by - default, algorithm assigns non-equal, automatically chosen weights for - errors in the prediction of different components of X). It can be done - with a call of MCPDSetPredictionWeights() function. - -5. User calls MCPDSolve() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -6. User calls MCPDResults() to get solution - -INPUT PARAMETERS: - N - problem dimension, N>=1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreate(const ae_int_t n, mcpdstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdcreate(n, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "entry" state and is treated -in a special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -Such conditions basically mean that row of P which corresponds to "entry" -state is zero. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - at every moment of time there is some - (unpredictable) amount of "new" individuals, which can transit into one - of the states at the next turn, but still no one leaves population -* you want to model transitions of individuals from one state into another -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdcreateentry(n, entrystate, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "exit" state and is treated -in a special way: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that column of P which corresponds to -"exit" state is zero. Multiplication by such P may decrease sum of vector -components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - individuals can move into "exit" state - and leave population at the next turn, but there are no new individuals -* amount of individuals which leave population can be predicted -* you want to model transitions of individuals from one state into another - (including transitions into the "exit" state) - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdcreateexit(n, exitstate, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-Exit-states" model, i.e. model where transition from X[i] to -X[i+1] is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -one selected component of X[] is called "entry" state and is treated in a -special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -and another one component of X[] is called "exit" state and is treated in -a special way too: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that: - row of P which corresponds to "entry" state is zero - column of P which corresponds to "exit" state is zero -Multiplication by such P may decrease sum of vector components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant -* at every moment of time there is some (unpredictable) amount of "new" - individuals, which can transit into one of the states at the next turn -* some individuals can move (predictably) into "exit" state and leave - population at the next turn -* you want to model transitions of individuals from one state into another, - including transitions from the "entry" state and into the "exit" state. -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdcreateentryexit(n, entrystate, exitstate, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add a track - sequence of system states at the -different moments of its evolution. - -You may add one or several tracks to the MCPD solver. In case you have -several tracks, they won't overwrite each other. For example, if you pass -two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then -solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, -t=B+1 to t=B+2, t=B+2 to t=B+3. But it WON'T mix these two tracks - i.e. it -won't try to model transition from t=A+3 to t=B+1. - -INPUT PARAMETERS: - S - solver - XY - track, array[K,N]: - * I-th row is a state at t=I - * elements of XY must be non-negative (exception will be - thrown on negative elements) - K - number of points in a track - * if given, only leading K rows of XY are used - * if not given, automatically determined from size of XY - -NOTES: - -1. Track may contain either proportional or population data: - * with proportional data all rows of XY must sum to 1.0, i.e. we have - proportions instead of absolute population values - * with population data rows of XY contain population counts and generally - do not sum to 1.0 (although they still must be non-negative) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdaddtrack(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add a track - sequence of system states at the -different moments of its evolution. - -You may add one or several tracks to the MCPD solver. In case you have -several tracks, they won't overwrite each other. For example, if you pass -two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then -solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, -t=B+1 to t=B+2, t=B+2 to t=B+3. But it WON'T mix these two tracks - i.e. it -won't try to model transition from t=A+3 to t=B+1. - -INPUT PARAMETERS: - S - solver - XY - track, array[K,N]: - * I-th row is a state at t=I - * elements of XY must be non-negative (exception will be - thrown on negative elements) - K - number of points in a track - * if given, only leading K rows of XY are used - * if not given, automatically determined from size of XY - -NOTES: - -1. Track may contain either proportional or population data: - * with proportional data all rows of XY must sum to 1.0, i.e. we have - proportions instead of absolute population values - * with population data rows of XY contain population counts and generally - do not sum to 1.0 (although they still must be non-negative) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t k; - - k = xy.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdaddtrack(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place equality constraints on arbitrary -subset of elements of P. Set of constraints is specified by EC, which may -contain either NAN's or finite numbers from [0,1]. NAN denotes absence of -constraint, finite number denotes equality constraint on specific element -of P. - -You can also use MCPDAddEC() function which allows to ADD equality -constraint for one element of P without changing constraints for other -elements. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - EC - equality constraints, array[N,N]. Elements of EC can be - either NAN's or finite numbers from [0,1]. NAN denotes - absence of constraints, while finite value denotes - equality constraint on the corresponding element of P. - -NOTES: - -1. infinite values of EC will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetec(const mcpdstate &s, const real_2d_array &ec) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsetec(const_cast(s.c_ptr()), const_cast(ec.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD equality constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetEC() function which allows you to specify -arbitrary set of equality constraints in one call. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - I - row index of element being constrained - J - column index of element being constrained - C - value (constraint for P[I,J]). Can be either NAN (no - constraint) or finite value from [0,1]. - -NOTES: - -1. infinite values of C will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddec(const mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdaddec(const_cast(s.c_ptr()), i, j, c, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add bound constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place bound constraints on arbitrary -subset of elements of P. Set of constraints is specified by BndL/BndU -matrices, which may contain arbitrary combination of finite numbers or -infinities (like -INF(s.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to add bound constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD bound constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetBC() function which allows to place bound -constraints on arbitrary subset of elements of P. Set of constraints is -specified by BndL/BndU matrices, which may contain arbitrary combination -of finite numbers or infinities (like -INF(s.c_ptr()), i, j, bndl, bndu, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to set linear equality/inequality constraints on the -elements of the transition matrix P. - -This function can be used to set one or several general linear constraints -on the elements of P. Two types of constraints are supported: -* equality constraints -* inequality constraints (both less-or-equal and greater-or-equal) - -Coefficients of constraints are specified by matrix C (one of the -parameters). One row of C corresponds to one constraint. Because -transition matrix P has N*N elements, we need N*N columns to store all -coefficients (they are stored row by row), and one more column to store -right part - hence C has N*N+1 columns. Constraint kind is stored in the -CT array. - -Thus, I-th linear constraint is - P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + - + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + - + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] -where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). - -Your constraint may involve only some subset of P (less than N*N elements). -For example it can be something like - P[0,0] + P[0,1] = 0.5 -In this case you still should pass matrix with N*N+1 columns, but all its -elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. - -INPUT PARAMETERS: - S - solver - C - array[K,N*N+1] - coefficients of constraints - (see above for complete description) - CT - array[K] - constraint types - (see above for complete description) - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsetlc(const_cast(s.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to set linear equality/inequality constraints on the -elements of the transition matrix P. - -This function can be used to set one or several general linear constraints -on the elements of P. Two types of constraints are supported: -* equality constraints -* inequality constraints (both less-or-equal and greater-or-equal) - -Coefficients of constraints are specified by matrix C (one of the -parameters). One row of C corresponds to one constraint. Because -transition matrix P has N*N elements, we need N*N columns to store all -coefficients (they are stored row by row), and one more column to store -right part - hence C has N*N+1 columns. Constraint kind is stored in the -CT array. - -Thus, I-th linear constraint is - P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + - + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + - + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] -where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). - -Your constraint may involve only some subset of P (less than N*N elements). -For example it can be something like - P[0,0] + P[0,1] = 0.5 -In this case you still should pass matrix with N*N+1 columns, but all its -elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. - -INPUT PARAMETERS: - S - solver - C - array[K,N*N+1] - coefficients of constraints - (see above for complete description) - CT - array[K] - constraint types - (see above for complete description) - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t k; - if( (c.rows()!=ct.length())) - throw ap_error("Error while calling 'mcpdsetlc': looks like one of arguments has wrong size"); - k = c.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsetlc(const_cast(s.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function allows to tune amount of Tikhonov regularization being -applied to your problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change coefficient r. You can also change -prior values with MCPDSetPrior() function. - -INPUT PARAMETERS: - S - solver - V - regularization coefficient, finite non-negative value. It - is not recommended to specify zero value unless you are - pretty sure that you want it. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsettikhonovregularizer(const mcpdstate &s, const double v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsettikhonovregularizer(const_cast(s.c_ptr()), v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function allows to set prior values used for regularization of your -problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change prior values prior_P. You can also -change r with MCPDSetTikhonovRegularizer() function. - -INPUT PARAMETERS: - S - solver - PP - array[N,N], matrix of prior values: - 1. elements must be real numbers from [0,1] - 2. columns must sum to 1.0. - First property is checked (exception is thrown otherwise), - while second one is not checked/enforced. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetprior(const mcpdstate &s, const real_2d_array &pp) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsetprior(const_cast(s.c_ptr()), const_cast(pp.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to change prediction weights - -MCPD solver scales prediction errors as follows - Error(P) = ||W*(y-P*x)||^2 -where - x is a system state at time t - y is a system state at time t+1 - P is a transition matrix - W is a diagonal scaling matrix - -By default, weights are chosen in order to minimize relative prediction -error instead of absolute one. For example, if one component of state is -about 0.5 in magnitude and another one is about 0.05, then algorithm will -make corresponding weights equal to 2.0 and 20.0. - -INPUT PARAMETERS: - S - solver - PW - array[N], weights: - * must be non-negative values (exception will be thrown otherwise) - * zero values will be replaced by automatically chosen values - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetpredictionweights(const mcpdstate &s, const real_1d_array &pw) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsetpredictionweights(const_cast(s.c_ptr()), const_cast(pw.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to start solution of the MCPD problem. - -After return from this function, you can use MCPDResults() to get solution -and completion code. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsolve(const mcpdstate &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdsolve(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -MCPD results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - P - array[N,N], transition matrix - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one. Speaking short, positive values denote - success, negative ones are failures. - More information about fields of this structure can be - found in the comments on MCPDReport datatype. - - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mcpdresults(const_cast(s.c_ptr()), const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Neural networks ensemble -*************************************************************************/ -_mlpensemble_owner::_mlpensemble_owner() -{ - p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpensemble_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpensemble_owner::_mlpensemble_owner(const _mlpensemble_owner &rhs) -{ - p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpensemble_owner& _mlpensemble_owner::operator=(const _mlpensemble_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mlpensemble_clear(p_struct); - if( !alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mlpensemble_owner::~_mlpensemble_owner() -{ - alglib_impl::_mlpensemble_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mlpensemble::mlpensemble() : _mlpensemble_owner() -{ -} - -mlpensemble::mlpensemble(const mlpensemble &rhs):_mlpensemble_owner(rhs) -{ -} - -mlpensemble& mlpensemble::operator=(const mlpensemble &rhs) -{ - if( this==&rhs ) - return *this; - _mlpensemble_owner::operator=(rhs); - return *this; -} - -mlpensemble::~mlpensemble() -{ -} - - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void mlpeserialize(mlpensemble &obj, std::string &s_out) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - alglib_impl::ae_int_t ssize; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_alloc_start(&serializer); - alglib_impl::mlpealloc(&serializer, obj.c_ptr(), &state); - ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); - s_out.clear(); - s_out.reserve((size_t)(ssize+1)); - alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); - alglib_impl::mlpeserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - if( s_out.length()>(size_t)ssize ) - throw ap_error("ALGLIB: serialization integrity error"); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void mlpeunserialize(std::string &s_in, mlpensemble &obj) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); - alglib_impl::mlpeunserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} - -/************************************************************************* -Like MLPCreate0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreate0(nin, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreate1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreate1(nin, nhid, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreate2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreate2(nin, nhid1, nhid2, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateB0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreateb0(nin, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateB1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreateb1(nin, nhid, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateB2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreateb2(nin, nhid1, nhid2, nout, b, d, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateR0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreater0(nin, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateR1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreater1(nin, nhid, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateR2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreater2(nin, nhid1, nhid2, nout, a, b, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateC0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreatec0(nin, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateC1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreatec1(nin, nhid, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Like MLPCreateC2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreatec2(nin, nhid1, nhid2, nout, ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creates ensemble from network. Only network geometry is copied. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpecreatefromnetwork(const_cast(network.c_ptr()), ensemblesize, const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Randomization of MLP ensemble - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlperandomize(const mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlperandomize(const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Return ensemble properties (number of inputs and outputs). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpeproperties(const_cast(ensemble.c_ptr()), &nin, &nout, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Return normalization type (whether ensemble is SOFTMAX-normalized or not). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -bool mlpeissoftmax(const mlpensemble &ensemble) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::mlpeissoftmax(const_cast(ensemble.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Ensemble- neural networks ensemble - X - input vector, array[0..NIn-1]. - Y - (possibly) preallocated buffer; if size of Y is less than - NOut, it will be reallocated. If it is large enough, it - is NOT reallocated, so we can save some time on reallocation. - - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocess(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpeprocess(const_cast(ensemble.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -'interactive' variant of MLPEProcess for languages like Python which -support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocessi(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpeprocessi(const_cast(ensemble.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Works both for classifier betwork and for regression networks which -are used as classifiers. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlperelclserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlperelclserror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if ensemble solves regression task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgce(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpeavgce(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for classification task -RMS error means error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpermserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpermserror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpeavgerror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average relative error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgrelerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::mlpeavgrelerror(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Training report: - * RelCLSError - fraction of misclassified cases. - * AvgCE - acerage cross-entropy - * RMSError - root-mean-square error - * AvgError - average error - * AvgRelError - average relative error - * NGrad - number of gradient calculations - * NHess - number of Hessian calculations - * NCholesky - number of Cholesky decompositions - -NOTE 1: RelCLSError/AvgCE are zero on regression problems. - -NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain - errors in prediction of posterior probabilities -*************************************************************************/ -_mlpreport_owner::_mlpreport_owner() -{ - p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpreport_owner::_mlpreport_owner(const _mlpreport_owner &rhs) -{ - p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpreport_owner& _mlpreport_owner::operator=(const _mlpreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mlpreport_clear(p_struct); - if( !alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mlpreport_owner::~_mlpreport_owner() -{ - alglib_impl::_mlpreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mlpreport* _mlpreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mlpreport* _mlpreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mlpreport::mlpreport() : _mlpreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) -{ -} - -mlpreport::mlpreport(const mlpreport &rhs):_mlpreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) -{ -} - -mlpreport& mlpreport::operator=(const mlpreport &rhs) -{ - if( this==&rhs ) - return *this; - _mlpreport_owner::operator=(rhs); - return *this; -} - -mlpreport::~mlpreport() -{ -} - - -/************************************************************************* -Cross-validation estimates of generalization error -*************************************************************************/ -_mlpcvreport_owner::_mlpcvreport_owner() -{ - p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpcvreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpcvreport_owner::_mlpcvreport_owner(const _mlpcvreport_owner &rhs) -{ - p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlpcvreport_owner& _mlpcvreport_owner::operator=(const _mlpcvreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mlpcvreport_clear(p_struct); - if( !alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mlpcvreport_owner::~_mlpcvreport_owner() -{ - alglib_impl::_mlpcvreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mlpcvreport::mlpcvreport() : _mlpcvreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) -{ -} - -mlpcvreport::mlpcvreport(const mlpcvreport &rhs):_mlpcvreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) -{ -} - -mlpcvreport& mlpcvreport::operator=(const mlpcvreport &rhs) -{ - if( this==&rhs ) - return *this; - _mlpcvreport_owner::operator=(rhs); - return *this; -} - -mlpcvreport::~mlpcvreport() -{ -} - - -/************************************************************************* -Trainer object for neural network. - -You should not try to access fields of this object directly - use ALGLIB -functions to work with this object. -*************************************************************************/ -_mlptrainer_owner::_mlptrainer_owner() -{ - p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlptrainer_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlptrainer_owner::_mlptrainer_owner(const _mlptrainer_owner &rhs) -{ - p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mlptrainer_owner& _mlptrainer_owner::operator=(const _mlptrainer_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mlptrainer_clear(p_struct); - if( !alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mlptrainer_owner::~_mlptrainer_owner() -{ - alglib_impl::_mlptrainer_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mlptrainer::mlptrainer() : _mlptrainer_owner() -{ -} - -mlptrainer::mlptrainer(const mlptrainer &rhs):_mlptrainer_owner(rhs) -{ -} - -mlptrainer& mlptrainer::operator=(const mlptrainer &rhs) -{ - if( this==&rhs ) - return *this; - _mlptrainer_owner::operator=(rhs); - return *this; -} - -mlptrainer::~mlptrainer() -{ -} - -/************************************************************************* -Neural network training using modified Levenberg-Marquardt with exact -Hessian calculation and regularization. Subroutine trains neural network -with restarts from random positions. Algorithm is well suited for small -and medium scale problems (hundreds of weights). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -9, if internal matrix inverse subroutine failed - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlptrainlm(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Neural network training using L-BFGS algorithm with regularization. -Subroutine trains neural network with restarts from random positions. -Algorithm is well suited for problems of any dimensionality (memory -requirements and step complexity are linear by weights number). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - MaxIts - stopping criterion. Algorithm stops after MaxIts - iterations (NOT gradient calculations). Zero MaxIts - means stopping when step is sufficiently small. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlptrainlbfgs(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Neural network training using early stopping (base algorithm - L-BFGS with -regularization). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - TrnXY - training set - TrnSize - training set size, TrnSize>0 - ValXY - validation set - ValSize - validation set size, ValSize>0 - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts, either: - * strictly positive number - algorithm make specified - number of restarts from random position. - * -1, in which case algorithm makes exactly one run - from the initial state of the network (no randomization). - If you don't know what Restarts to choose, choose one - one the following: - * -1 (deterministic start) - * +1 (one random restart) - * +5 (moderate amount of random restarts) - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1, ...). - * 2, task has been solved, stopping criterion met - - sufficiently small step size. Not expected (we - use EARLY stopping) but possible and not an - error. - * 6, task has been solved, stopping criterion met - - increasing of validation set error. - Rep - training report - -NOTE: - -Algorithm stops if validation set error increases for a long enough or -step size is small enought (there are task where validation set may -decrease for eternity). In any case solution returned corresponds to the -minimum of validation set error. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptraines(const multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlptraines(const_cast(network.c_ptr()), const_cast(trnxy.c_ptr()), trnsize, const_cast(valxy.c_ptr()), valsize, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - L-BFGS. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpkfoldcvlbfgs(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, foldscount, &info, const_cast(rep.c_ptr()), const_cast(cvrep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - Levenberg-Marquardt. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpkfoldcvlm(const_cast(network.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, foldscount, &info, const_cast(rep.c_ptr()), const_cast(cvrep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function estimates generalization error using cross-validation on the -current dataset with current training settings. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * FoldsCount cross-validation rounds (always) - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. Network is not changed during cross- - validation and is not trained - it is used only as - representative of its architecture. I.e., we estimate - generalization properties of ARCHITECTURE, not some - specific network. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that for each cross-validation - round specified number of random restarts is - performed, with best network being chosen after - training. - * NRestarts=0 is same as NRestarts=1 - FoldsCount - number of folds in k-fold cross-validation: - * 2<=FoldsCount<=size of dataset - * recommended value: 10. - * values larger than dataset size will be silently - truncated down to dataset size - -OUTPUT PARAMETERS: - Rep - structure which contains cross-validation estimates: - * Rep.RelCLSError - fraction of misclassified cases. - * Rep.AvgCE - acerage cross-entropy - * Rep.RMSError - root-mean-square error - * Rep.AvgError - average error - * Rep.AvgRelError - average relative error - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or subset with only one point was given, zeros are returned as - estimates. - -NOTE: this method performs FoldsCount cross-validation rounds, each one - with NRestarts random starts. Thus, FoldsCount*NRestarts networks - are trained in total. - -NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. - -NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError - contain errors in prediction of posterior probabilities. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpkfoldcv(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, foldscount, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlpkfoldcv(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, foldscount, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creation of the network trainer object for regression networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NOut - number of outputs, NOut>=1 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any regression - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreatetrainer(nin, nout, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Creation of the network trainer object for classification networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any classification - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpcreatetrainercls(nin, nclasses, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user. - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. - NPoints - points count, >=0. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdataset(const mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetdataset(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user (sparse matrix is used to store dataset). - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Any sparse storage format can be used: - Hash-table, CRS... - NPoints - points count, >=0 - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetsparsedataset(const mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetsparsedataset(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), npoints, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets weight decay coefficient which is used for training. - -INPUT PARAMETERS: - S - trainer object - Decay - weight decay coefficient, >=0. Weight decay term - 'Decay*||Weights||^2' is added to error function. If - you don't know what Decay to choose, use 1.0E-3. - Weight decay can be set to zero, in this case network - is trained without weight decay. - -NOTE: by default network uses some small nonzero value for weight decay. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdecay(const mlptrainer &s, const double decay) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetdecay(const_cast(s.c_ptr()), decay, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping criteria for the optimizer. - -INPUT PARAMETERS: - S - trainer object - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - WStep>=0. - MaxIts - stopping criterion. Algorithm stops after MaxIts - epochs (full passes over entire dataset). Zero MaxIts - means stopping when step is sufficiently small. - MaxIts>=0. - -NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also - used when MLPSetCond() is called with WStep=0 and MaxIts=0. - -NOTE: these stopping criteria are used for all kinds of neural training - - from "conventional" networks to early stopping ensembles. When used - for "conventional" networks, they are used as the only stopping - criteria. When combined with early stopping, they used as ADDITIONAL - stopping criteria which can terminate early stopping algorithm. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetcond(const mlptrainer &s, const double wstep, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetcond(const_cast(s.c_ptr()), wstep, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets training algorithm: batch training using L-BFGS will be -used. - -This algorithm: -* the most robust for small-scale problems, but may be too slow for large - scale ones. -* perfoms full pass through the dataset before performing step -* uses conditions specified by MLPSetCond() for stopping -* is default one used by trainer object - -INPUT PARAMETERS: - S - trainer object - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetalgobatch(const mlptrainer &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpsetalgobatch(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function trains neural network passed to this function, using current -dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) -and current training settings. Training from NRestarts random starting -positions is performed, best network is chosen. - -Training is performed using current training algorithm. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed, best network is chosen after - training - * NRestarts=0 means that current state of the network - is used for training. - -OUTPUT PARAMETERS: - Network - trained network - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - network is filled by zero values. Same behavior for functions - MLPStartTraining and MLPContinueTraining. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlptrainnetwork(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlptrainnetwork(const_cast(s.c_ptr()), const_cast(network.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -After call to this function trainer object remembers network and is ready -to train it. However, no training is performed until first call to -MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() -will advance training progress one iteration further. - -EXAMPLE: - > - > ...initialize network and trainer object.... - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > ...visualize training progress... - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - RandomStart - randomize network before training or not: - * True means that network is randomized and its - initial state (one which was passed to the trainer - object) is lost. - * False means that training is started from the - current state of the network - -OUTPUT PARAMETERS: - Network - neural network which is ready to training (weights are - initialized, preprocessor is initialized using current - training set) - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpstarttraining(const mlptrainer &s, const multilayerperceptron &network, const bool randomstart) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpstarttraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), randomstart, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -This function performs one more iteration of the training and returns -either True (training continues) or False (training stopped). In case True -was returned, Network weights are updated according to the current state -of the optimization progress. In case False was returned, no additional -updates is performed (previous update of the network weights moved us to -the final point, and no additional updates is needed). - -EXAMPLE: - > - > [initialize network and trainer object] - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > [visualize training progress] - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network structure, which is used to store - current state of the training process. - -OUTPUT PARAMETERS: - Network - weights of the neural network are rewritten by the - current approximation. - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - -NOTE: It is expected that Network is the same one which was passed to - MLPStartTraining() function. However, THIS function checks only - following: - * that number of network inputs is consistent with trainer object - settings - * that number of network outputs/classes is consistent with trainer - object settings - * that number of network weights is the same as number of weights in - the network passed to MLPStartTraining() function - Exception is thrown when these conditions are violated. - - It is also expected that you do not change state of the network on - your own - the only party who has right to change network during its - training is a trainer object. Any attempt to interfere with trainer - may lead to unpredictable results. - - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -bool mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::mlpcontinuetraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -bool smp_mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::_pexec_mlpcontinuetraining(const_cast(s.c_ptr()), const_cast(network.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -Modified Levenberg-Marquardt algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglm(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpebagginglm(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), const_cast(ooberrors.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -L-BFGS algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglbfgs(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpebagginglbfgs(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, wstep, maxits, &info, const_cast(rep.c_ptr()), const_cast(ooberrors.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Training neural networks ensemble using early stopping. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 6, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpetraines(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlpetraines(const_cast(ensemble.c_ptr()), const_cast(xy.c_ptr()), npoints, decay, restarts, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function trains neural network ensemble passed to this function using -current dataset and early stopping training algorithm. Each early stopping -round performs NRestarts random restarts (thus, EnsembleSize*NRestarts -training rounds is performed in total). - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * EnsembleSize training sessions performed for each of ensemble - ! members (always parallelized) - ! * NRestarts training sessions performed within each of training - ! sessions (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object; - Ensemble - neural network ensemble. It must have same number of - inputs and outputs/classes as was specified during - creation of the trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed during each ES round; - * NRestarts=0 is silently replaced by 1. - -OUTPUT PARAMETERS: - Ensemble - trained ensemble; - Rep - it contains all type of errors. - -NOTE: this training method uses BOTH early stopping and weight decay! So, - you should select weight decay before starting training just as you - select it before training "conventional" networks. - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or single-point dataset was passed, ensemble is filled by zero - values. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 22.08.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mlptrainensemblees(const_cast(s.c_ptr()), const_cast(ensemble.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_mlptrainensemblees(const_cast(s.c_ptr()), const_cast(ensemble.c_ptr()), nrestarts, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Principal components analysis - -Subroutine builds orthogonal basis where first axis corresponds to -direction with maximum variance, second axis maximizes variance in subspace -orthogonal to first axis and so on. - -It should be noted that, unlike LDA, PCA does not use class labels. - -INPUT PARAMETERS: - X - dataset, array[0..NPoints-1,0..NVars-1]. - matrix contains ONLY INDEPENDENT VARIABLES. - NPoints - dataset size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - -ÂÛÕÎÄÍÛÅ ÏÀÐÀÌÅÒÐÛ: - Info - return code: - * -4, if SVD subroutine haven't converged - * -1, if wrong parameters has been passed (NPoints<0, - NVars<1) - * 1, if task is solved - S2 - array[0..NVars-1]. variance values corresponding - to basis vectors. - V - array[0..NVars-1,0..NVars-1] - matrix, whose columns store basis vectors. - - -- ALGLIB -- - Copyright 25.08.2008 by Bochkanov Sergey -*************************************************************************/ -void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, real_1d_array &s2, real_2d_array &v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pcabuildbasis(const_cast(x.c_ptr()), npoints, nvars, &info, const_cast(s2.c_ptr()), const_cast(v.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static double bdss_xlny(double x, double y, ae_state *_state); -static double bdss_getcv(/* Integer */ ae_vector* cnt, - ae_int_t nc, - ae_state *_state); -static void bdss_tieaddc(/* Integer */ ae_vector* c, - /* Integer */ ae_vector* ties, - ae_int_t ntie, - ae_int_t nc, - /* Integer */ ae_vector* cnt, - ae_state *_state); -static void bdss_tiesubc(/* Integer */ ae_vector* c, - /* Integer */ ae_vector* ties, - ae_int_t ntie, - ae_int_t nc, - /* Integer */ ae_vector* cnt, - ae_state *_state); - - -static ae_int_t clustering_parallelcomplexity = 200000; -static ae_bool clustering_selectcenterpp(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - /* Real */ ae_matrix* centers, - /* Boolean */ ae_vector* busycenters, - ae_int_t ccnt, - /* Real */ ae_vector* d2, - /* Real */ ae_vector* p, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void clustering_clusterizerrunahcinternal(clusterizerstate* s, - /* Real */ ae_matrix* d, - ahcreport* rep, - ae_state *_state); -static void clustering_evaluatedistancematrixrec(/* Real */ ae_matrix* xy, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, - ae_int_t i0, - ae_int_t i1, - ae_int_t j0, - ae_int_t j1, - ae_state *_state); - - - - -static ae_int_t dforest_innernodewidth = 3; -static ae_int_t dforest_leafnodewidth = 2; -static ae_int_t dforest_dfusestrongsplits = 1; -static ae_int_t dforest_dfuseevs = 2; -static ae_int_t dforest_dffirstversion = 0; -static ae_int_t dforest_dfclserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -static void dforest_dfprocessinternal(decisionforest* df, - ae_int_t offs, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -static void dforest_dfbuildtree(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t nfeatures, - ae_int_t nvarsinpool, - ae_int_t flags, - dfinternalbuffers* bufs, - hqrndstate* rs, - ae_state *_state); -static void dforest_dfbuildtreerec(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t nfeatures, - ae_int_t nvarsinpool, - ae_int_t flags, - ae_int_t* numprocessed, - ae_int_t idx1, - ae_int_t idx2, - dfinternalbuffers* bufs, - hqrndstate* rs, - ae_state *_state); -static void dforest_dfsplitc(/* Real */ ae_vector* x, - /* Integer */ ae_vector* c, - /* Integer */ ae_vector* cntbuf, - ae_int_t n, - ae_int_t nc, - ae_int_t flags, - ae_int_t* info, - double* threshold, - double* e, - /* Real */ ae_vector* sortrbuf, - /* Integer */ ae_vector* sortibuf, - ae_state *_state); -static void dforest_dfsplitr(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t flags, - ae_int_t* info, - double* threshold, - double* e, - /* Real */ ae_vector* sortrbuf, - /* Real */ ae_vector* sortrbuf2, - ae_state *_state); - - -static ae_int_t linreg_lrvnum = 5; -static void linreg_lrinternal(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state); - - - - - - -static ae_int_t mlpbase_mlpvnum = 7; -static ae_int_t mlpbase_mlpfirstversion = 0; -static ae_int_t mlpbase_nfieldwidth = 4; -static ae_int_t mlpbase_hlconnfieldwidth = 5; -static ae_int_t mlpbase_hlnfieldwidth = 4; -static ae_int_t mlpbase_gradbasecasecost = 50000; -static ae_int_t mlpbase_microbatchsize = 64; -static void mlpbase_addinputlayer(ae_int_t ncount, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state); -static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state); -static void mlpbase_addactivationlayer(ae_int_t functype, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state); -static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state); -static void mlpbase_hladdinputlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t nin, - ae_state *_state); -static void mlpbase_hladdoutputlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t* weightsidx, - ae_int_t k, - ae_int_t nprev, - ae_int_t nout, - ae_bool iscls, - ae_bool islinearout, - ae_state *_state); -static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t* weightsidx, - ae_int_t k, - ae_int_t nprev, - ae_int_t ncur, - ae_state *_state); -static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, - ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_bool iscls, - ae_bool islinearout, - ae_state *_state); -static void mlpbase_mlpcreate(ae_int_t nin, - ae_int_t nout, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t layerscount, - ae_bool isclsnet, - multilayerperceptron* network, - ae_state *_state); -static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_bool naturalerr, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state); -static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, - /* Real */ ae_vector* neurons, - /* Real */ ae_vector* weights, - /* Real */ ae_vector* derror, - /* Real */ ae_vector* grad, - ae_bool naturalerrorfunc, - ae_state *_state); -static void mlpbase_mlpchunkedgradient(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - double* e, - ae_bool naturalerrorfunc, - ae_state *_state); -static void mlpbase_mlpchunkedprocess(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - ae_state *_state); -static double mlpbase_safecrossentropy(double t, - double z, - ae_state *_state); -static void mlpbase_randomizebackwardpass(multilayerperceptron* network, - ae_int_t neuronidx, - double v, - ae_state *_state); - - -static double logit_xtol = 100*ae_machineepsilon; -static double logit_ftol = 0.0001; -static double logit_gtol = 0.3; -static ae_int_t logit_maxfev = 20; -static double logit_stpmin = 1.0E-2; -static double logit_stpmax = 1.0E5; -static ae_int_t logit_logitvnum = 6; -static void logit_mnliexp(/* Real */ ae_vector* w, - /* Real */ ae_vector* x, - ae_state *_state); -static void logit_mnlallerrors(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double* relcls, - double* avgce, - double* rms, - double* avg, - double* avgrel, - ae_state *_state); -static void logit_mnlmcsrch(ae_int_t n, - /* Real */ ae_vector* x, - double* f, - /* Real */ ae_vector* g, - /* Real */ ae_vector* s, - double* stp, - ae_int_t* info, - ae_int_t* nfev, - /* Real */ ae_vector* wa, - logitmcstate* state, - ae_int_t* stage, - ae_state *_state); -static void logit_mnlmcstep(double* stx, - double* fx, - double* dx, - double* sty, - double* fy, - double* dy, - double* stp, - double fp, - double dp, - ae_bool* brackt, - double stmin, - double stmax, - ae_int_t* info, - ae_state *_state); - - -static double mcpd_xtol = 1.0E-8; -static void mcpd_mcpdinit(ae_int_t n, - ae_int_t entrystate, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state); - - -static ae_int_t mlpe_mlpefirstversion = 1; - - -static double mlptrain_mindecay = 0.001; -static ae_int_t mlptrain_defaultlbfgsfactor = 6; -static void mlptrain_mlpkfoldcvgeneral(multilayerperceptron* n, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t foldscount, - ae_bool lmalgorithm, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state); -static void mlptrain_mlpkfoldsplit(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nclasses, - ae_int_t foldscount, - ae_bool stratifiedsplits, - /* Integer */ ae_vector* folds, - ae_state *_state); -static void mlptrain_mthreadcv(mlptrainer* s, - ae_int_t rowsize, - ae_int_t nrestarts, - /* Integer */ ae_vector* folds, - ae_int_t fold, - ae_int_t dfold, - /* Real */ ae_matrix* cvy, - ae_shared_pool* pooldatacv, - ae_state *_state); -static void mlptrain_mlptrainnetworkx(mlptrainer* s, - ae_int_t nrestarts, - ae_int_t algokind, - /* Integer */ ae_vector* trnsubset, - ae_int_t trnsubsetsize, - /* Integer */ ae_vector* valsubset, - ae_int_t valsubsetsize, - multilayerperceptron* network, - mlpreport* rep, - ae_bool isrootcall, - ae_shared_pool* sessions, - ae_state *_state); -static void mlptrain_mlptrainensemblex(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t idx0, - ae_int_t idx1, - ae_int_t nrestarts, - ae_int_t trainingmethod, - sinteger* ngrad, - ae_bool isrootcall, - ae_shared_pool* esessions, - ae_state *_state); -static void mlptrain_mlpstarttrainingx(mlptrainer* s, - ae_bool randomstart, - ae_int_t algokind, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - smlptrnsession* session, - ae_state *_state); -static ae_bool mlptrain_mlpcontinuetrainingx(mlptrainer* s, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_int_t* ngradbatch, - smlptrnsession* session, - ae_state *_state); -static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_bool lmalgorithm, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state); -static void mlptrain_initmlptrnsession(multilayerperceptron* networktrained, - ae_bool randomizenetwork, - mlptrainer* trainer, - smlptrnsession* session, - ae_state *_state); -static void mlptrain_initmlptrnsessions(multilayerperceptron* networktrained, - ae_bool randomizenetwork, - mlptrainer* trainer, - ae_shared_pool* sessions, - ae_state *_state); -static void mlptrain_initmlpetrnsession(multilayerperceptron* individualnetwork, - mlptrainer* trainer, - mlpetrnsession* session, - ae_state *_state); -static void mlptrain_initmlpetrnsessions(multilayerperceptron* individualnetwork, - mlptrainer* trainer, - ae_shared_pool* sessions, - ae_state *_state); - - - - - - - -/************************************************************************* -This set of routines (DSErrAllocate, DSErrAccumulate, DSErrFinish) -calculates different error functions (classification error, cross-entropy, -rms, avg, avg.rel errors). - -1. DSErrAllocate prepares buffer. -2. DSErrAccumulate accumulates individual errors: - * Y contains predicted output (posterior probabilities for classification) - * DesiredY contains desired output (class number for classification) -3. DSErrFinish outputs results: - * Buf[0] contains relative classification error (zero for regression tasks) - * Buf[1] contains avg. cross-entropy (zero for regression tasks) - * Buf[2] contains rms error (regression, classification) - * Buf[3] contains average error (regression, classification) - * Buf[4] contains average relative error (regression, classification) - -NOTES(1): - "NClasses>0" means that we have classification task. - "NClasses<0" means regression task with -NClasses real outputs. - -NOTES(2): - rms. avg, avg.rel errors for classification tasks are interpreted as - errors in posterior probabilities with respect to probabilities given - by training/test set. - - -- ALGLIB -- - Copyright 11.01.2009 by Bochkanov Sergey -*************************************************************************/ -void dserrallocate(ae_int_t nclasses, - /* Real */ ae_vector* buf, - ae_state *_state) -{ - - ae_vector_clear(buf); - - ae_vector_set_length(buf, 7+1, _state); - buf->ptr.p_double[0] = 0; - buf->ptr.p_double[1] = 0; - buf->ptr.p_double[2] = 0; - buf->ptr.p_double[3] = 0; - buf->ptr.p_double[4] = 0; - buf->ptr.p_double[5] = nclasses; - buf->ptr.p_double[6] = 0; - buf->ptr.p_double[7] = 0; -} - - -/************************************************************************* -See DSErrAllocate for comments on this routine. - - -- ALGLIB -- - Copyright 11.01.2009 by Bochkanov Sergey -*************************************************************************/ -void dserraccumulate(/* Real */ ae_vector* buf, - /* Real */ ae_vector* y, - /* Real */ ae_vector* desiredy, - ae_state *_state) -{ - ae_int_t nclasses; - ae_int_t nout; - ae_int_t offs; - ae_int_t mmax; - ae_int_t rmax; - ae_int_t j; - double v; - double ev; - - - offs = 5; - nclasses = ae_round(buf->ptr.p_double[offs], _state); - if( nclasses>0 ) - { - - /* - * Classification - */ - rmax = ae_round(desiredy->ptr.p_double[0], _state); - mmax = 0; - for(j=1; j<=nclasses-1; j++) - { - if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) - { - mmax = j; - } - } - if( mmax!=rmax ) - { - buf->ptr.p_double[0] = buf->ptr.p_double[0]+1; - } - if( ae_fp_greater(y->ptr.p_double[rmax],0) ) - { - buf->ptr.p_double[1] = buf->ptr.p_double[1]-ae_log(y->ptr.p_double[rmax], _state); - } - else - { - buf->ptr.p_double[1] = buf->ptr.p_double[1]+ae_log(ae_maxrealnumber, _state); - } - for(j=0; j<=nclasses-1; j++) - { - v = y->ptr.p_double[j]; - if( j==rmax ) - { - ev = 1; - } - else - { - ev = 0; - } - buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); - buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); - if( ae_fp_neq(ev,0) ) - { - buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); - buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+1; - } - } - buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+1; - } - else - { - - /* - * Regression - */ - nout = -nclasses; - rmax = 0; - for(j=1; j<=nout-1; j++) - { - if( ae_fp_greater(desiredy->ptr.p_double[j],desiredy->ptr.p_double[rmax]) ) - { - rmax = j; - } - } - mmax = 0; - for(j=1; j<=nout-1; j++) - { - if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) - { - mmax = j; - } - } - if( mmax!=rmax ) - { - buf->ptr.p_double[0] = buf->ptr.p_double[0]+1; - } - for(j=0; j<=nout-1; j++) - { - v = y->ptr.p_double[j]; - ev = desiredy->ptr.p_double[j]; - buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); - buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); - if( ae_fp_neq(ev,0) ) - { - buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); - buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+1; - } - } - buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+1; - } -} - - -/************************************************************************* -See DSErrAllocate for comments on this routine. - - -- ALGLIB -- - Copyright 11.01.2009 by Bochkanov Sergey -*************************************************************************/ -void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state) -{ - ae_int_t nout; - ae_int_t offs; - - - offs = 5; - nout = ae_iabs(ae_round(buf->ptr.p_double[offs], _state), _state); - if( ae_fp_neq(buf->ptr.p_double[offs+1],0) ) - { - buf->ptr.p_double[0] = buf->ptr.p_double[0]/buf->ptr.p_double[offs+1]; - buf->ptr.p_double[1] = buf->ptr.p_double[1]/buf->ptr.p_double[offs+1]; - buf->ptr.p_double[2] = ae_sqrt(buf->ptr.p_double[2]/(nout*buf->ptr.p_double[offs+1]), _state); - buf->ptr.p_double[3] = buf->ptr.p_double[3]/(nout*buf->ptr.p_double[offs+1]); - } - if( ae_fp_neq(buf->ptr.p_double[offs+2],0) ) - { - buf->ptr.p_double[4] = buf->ptr.p_double[4]/buf->ptr.p_double[offs+2]; - } -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 19.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsnormalize(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* means, - /* Real */ ae_vector* sigmas, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector tmp; - double mean; - double variance; - double skewness; - double kurtosis; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(means); - ae_vector_clear(sigmas); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * Test parameters - */ - if( npoints<=0||nvars<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Standartization - */ - ae_vector_set_length(means, nvars-1+1, _state); - ae_vector_set_length(sigmas, nvars-1+1, _state); - ae_vector_set_length(&tmp, npoints-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); - samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); - means->ptr.p_double[j] = mean; - sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); - if( ae_fp_eq(sigmas->ptr.p_double[j],0) ) - { - sigmas->ptr.p_double[j] = 1; - } - for(i=0; i<=npoints-1; i++) - { - xy->ptr.pp_double[i][j] = (xy->ptr.pp_double[i][j]-means->ptr.p_double[j])/sigmas->ptr.p_double[j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 19.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsnormalizec(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* means, - /* Real */ ae_vector* sigmas, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t j; - ae_vector tmp; - double mean; - double variance; - double skewness; - double kurtosis; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(means); - ae_vector_clear(sigmas); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * Test parameters - */ - if( npoints<=0||nvars<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Standartization - */ - ae_vector_set_length(means, nvars-1+1, _state); - ae_vector_set_length(sigmas, nvars-1+1, _state); - ae_vector_set_length(&tmp, npoints-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); - samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); - means->ptr.p_double[j] = mean; - sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); - if( ae_fp_eq(sigmas->ptr.p_double[j],0) ) - { - sigmas->ptr.p_double[j] = 1; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 19.05.2008 by Bochkanov Sergey -*************************************************************************/ -double dsgetmeanmindistance(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector tmp; - ae_vector tmp2; - double v; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); - - - /* - * Test parameters - */ - if( npoints<=0||nvars<1 ) - { - result = 0; - ae_frame_leave(_state); - return result; - } - - /* - * Process - */ - ae_vector_set_length(&tmp, npoints-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - tmp.ptr.p_double[i] = ae_maxrealnumber; - } - ae_vector_set_length(&tmp2, nvars-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - for(j=i+1; j<=npoints-1; j++) - { - ae_v_move(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - v = ae_sqrt(v, _state); - tmp.ptr.p_double[i] = ae_minreal(tmp.ptr.p_double[i], v, _state); - tmp.ptr.p_double[j] = ae_minreal(tmp.ptr.p_double[j], v, _state); - } - } - result = 0; - for(i=0; i<=npoints-1; i++) - { - result = result+tmp.ptr.p_double[i]/npoints; - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 19.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dstie(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* ties, - ae_int_t* tiecount, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(ties); - *tiecount = 0; - ae_vector_clear(p1); - ae_vector_clear(p2); - ae_vector_init(&tmp, 0, DT_INT, _state, ae_true); - - - /* - * Special case - */ - if( n<=0 ) - { - *tiecount = 0; - ae_frame_leave(_state); - return; - } - - /* - * Sort A - */ - tagsort(a, n, p1, p2, _state); - - /* - * Process ties - */ - *tiecount = 1; - for(i=1; i<=n-1; i++) - { - if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) - { - *tiecount = *tiecount+1; - } - } - ae_vector_set_length(ties, *tiecount+1, _state); - ties->ptr.p_int[0] = 0; - k = 1; - for(i=1; i<=n-1; i++) - { - if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) - { - ties->ptr.p_int[k] = i; - k = k+1; - } - } - ties->ptr.p_int[*tiecount] = n; - ae_frame_leave(_state); -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 11.12.2008 by Bochkanov Sergey -*************************************************************************/ -void dstiefasti(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t n, - /* Integer */ ae_vector* ties, - ae_int_t* tiecount, - /* Real */ ae_vector* bufr, - /* Integer */ ae_vector* bufi, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - *tiecount = 0; - ae_vector_init(&tmp, 0, DT_INT, _state, ae_true); - - - /* - * Special case - */ - if( n<=0 ) - { - *tiecount = 0; - ae_frame_leave(_state); - return; - } - - /* - * Sort A - */ - tagsortfasti(a, b, bufr, bufi, n, _state); - - /* - * Process ties - */ - ties->ptr.p_int[0] = 0; - k = 1; - for(i=1; i<=n-1; i++) - { - if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) - { - ties->ptr.p_int[k] = i; - k = k+1; - } - } - ties->ptr.p_int[k] = n; - *tiecount = k; - ae_frame_leave(_state); -} - - -/************************************************************************* -Optimal binary classification - -Algorithms finds optimal (=with minimal cross-entropy) binary partition. -Internal subroutine. - -INPUT PARAMETERS: - A - array[0..N-1], variable - C - array[0..N-1], class numbers (0 or 1). - N - array size - -OUTPUT PARAMETERS: - Info - completion code: - * -3, all values of A[] are same (partition is impossible) - * -2, one of C[] is incorrect (<0, >1) - * -1, incorrect pararemets were passed (N<=0). - * 1, OK - Threshold- partiton boundary. Left part contains values which are - strictly less than Threshold. Right part contains values - which are greater than or equal to Threshold. - PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) - CVE - cross-validation estimate of cross-entropy - - -- ALGLIB -- - Copyright 22.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t* info, - double* threshold, - double* pal, - double* pbl, - double* par, - double* pbr, - double* cve, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _a; - ae_vector _c; - ae_int_t i; - ae_int_t t; - double s; - ae_vector ties; - ae_int_t tiecount; - ae_vector p1; - ae_vector p2; - ae_int_t k; - ae_int_t koptimal; - double pak; - double pbk; - double cvoptimal; - double cv; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init_copy(&_c, c, _state, ae_true); - c = &_c; - *info = 0; - *threshold = 0; - *pal = 0; - *pbl = 0; - *par = 0; - *pbr = 0; - *cve = 0; - ae_vector_init(&ties, 0, DT_INT, _state, ae_true); - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * Test for errors in inputs - */ - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - if( c->ptr.p_int[i]!=0&&c->ptr.p_int[i]!=1 ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Tie - */ - dstie(a, n, &ties, &tiecount, &p1, &p2, _state); - for(i=0; i<=n-1; i++) - { - if( p2.ptr.p_int[i]!=i ) - { - t = c->ptr.p_int[i]; - c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; - c->ptr.p_int[p2.ptr.p_int[i]] = t; - } - } - - /* - * Special case: number of ties is 1. - * - * NOTE: we assume that P[i,j] equals to 0 or 1, - * intermediate values are not allowed. - */ - if( tiecount==1 ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * General case, number of ties > 1 - * - * NOTE: we assume that P[i,j] equals to 0 or 1, - * intermediate values are not allowed. - */ - *pal = 0; - *pbl = 0; - *par = 0; - *pbr = 0; - for(i=0; i<=n-1; i++) - { - if( c->ptr.p_int[i]==0 ) - { - *par = *par+1; - } - if( c->ptr.p_int[i]==1 ) - { - *pbr = *pbr+1; - } - } - koptimal = -1; - cvoptimal = ae_maxrealnumber; - for(k=0; k<=tiecount-2; k++) - { - - /* - * first, obtain information about K-th tie which is - * moved from R-part to L-part - */ - pak = 0; - pbk = 0; - for(i=ties.ptr.p_int[k]; i<=ties.ptr.p_int[k+1]-1; i++) - { - if( c->ptr.p_int[i]==0 ) - { - pak = pak+1; - } - if( c->ptr.p_int[i]==1 ) - { - pbk = pbk+1; - } - } - - /* - * Calculate cross-validation CE - */ - cv = 0; - cv = cv-bdss_xlny(*pal+pak, (*pal+pak)/(*pal+pak+(*pbl)+pbk+1), _state); - cv = cv-bdss_xlny(*pbl+pbk, (*pbl+pbk)/(*pal+pak+1+(*pbl)+pbk), _state); - cv = cv-bdss_xlny(*par-pak, (*par-pak)/(*par-pak+(*pbr)-pbk+1), _state); - cv = cv-bdss_xlny(*pbr-pbk, (*pbr-pbk)/(*par-pak+1+(*pbr)-pbk), _state); - - /* - * Compare with best - */ - if( ae_fp_less(cv,cvoptimal) ) - { - cvoptimal = cv; - koptimal = k; - } - - /* - * update - */ - *pal = *pal+pak; - *pbl = *pbl+pbk; - *par = *par-pak; - *pbr = *pbr-pbk; - } - *cve = cvoptimal; - *threshold = 0.5*(a->ptr.p_double[ties.ptr.p_int[koptimal]]+a->ptr.p_double[ties.ptr.p_int[koptimal+1]]); - *pal = 0; - *pbl = 0; - *par = 0; - *pbr = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_less(a->ptr.p_double[i],*threshold) ) - { - if( c->ptr.p_int[i]==0 ) - { - *pal = *pal+1; - } - else - { - *pbl = *pbl+1; - } - } - else - { - if( c->ptr.p_int[i]==0 ) - { - *par = *par+1; - } - else - { - *pbr = *pbr+1; - } - } - } - s = *pal+(*pbl); - *pal = *pal/s; - *pbl = *pbl/s; - s = *par+(*pbr); - *par = *par/s; - *pbr = *pbr/s; - ae_frame_leave(_state); -} - - -/************************************************************************* -Optimal partition, internal subroutine. Fast version. - -Accepts: - A array[0..N-1] array of attributes array[0..N-1] - C array[0..N-1] array of class labels - TiesBuf array[0..N] temporaries (ties) - CntBuf array[0..2*NC-1] temporaries (counts) - Alpha centering factor (0<=alpha<=1, recommended value - 0.05) - BufR array[0..N-1] temporaries - BufI array[0..N-1] temporaries - -Output: - Info error code (">0"=OK, "<0"=bad) - RMS training set RMS error - CVRMS leave-one-out RMS error - -Note: - content of all arrays is changed by subroutine; - it doesn't allocate temporaries. - - -- ALGLIB -- - Copyright 11.12.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2fast(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - /* Integer */ ae_vector* tiesbuf, - /* Integer */ ae_vector* cntbuf, - /* Real */ ae_vector* bufr, - /* Integer */ ae_vector* bufi, - ae_int_t n, - ae_int_t nc, - double alpha, - ae_int_t* info, - double* threshold, - double* rms, - double* cvrms, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t cl; - ae_int_t tiecount; - double cbest; - double cc; - ae_int_t koptimal; - ae_int_t sl; - ae_int_t sr; - double v; - double w; - double x; - - *info = 0; - *threshold = 0; - *rms = 0; - *cvrms = 0; - - - /* - * Test for errors in inputs - */ - if( n<=0||nc<2 ) - { - *info = -1; - return; - } - for(i=0; i<=n-1; i++) - { - if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) - { - *info = -2; - return; - } - } - *info = 1; - - /* - * Tie - */ - dstiefasti(a, c, n, tiesbuf, &tiecount, bufr, bufi, _state); - - /* - * Special case: number of ties is 1. - */ - if( tiecount==1 ) - { - *info = -3; - return; - } - - /* - * General case, number of ties > 1 - */ - for(i=0; i<=2*nc-1; i++) - { - cntbuf->ptr.p_int[i] = 0; - } - for(i=0; i<=n-1; i++) - { - cntbuf->ptr.p_int[nc+c->ptr.p_int[i]] = cntbuf->ptr.p_int[nc+c->ptr.p_int[i]]+1; - } - koptimal = -1; - *threshold = a->ptr.p_double[n-1]; - cbest = ae_maxrealnumber; - sl = 0; - sr = n; - for(k=0; k<=tiecount-2; k++) - { - - /* - * first, move Kth tie from right to left - */ - for(i=tiesbuf->ptr.p_int[k]; i<=tiesbuf->ptr.p_int[k+1]-1; i++) - { - cl = c->ptr.p_int[i]; - cntbuf->ptr.p_int[cl] = cntbuf->ptr.p_int[cl]+1; - cntbuf->ptr.p_int[nc+cl] = cntbuf->ptr.p_int[nc+cl]-1; - } - sl = sl+(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); - sr = sr-(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); - - /* - * Calculate RMS error - */ - v = 0; - for(i=0; i<=nc-1; i++) - { - w = cntbuf->ptr.p_int[i]; - v = v+w*ae_sqr(w/sl-1, _state); - v = v+(sl-w)*ae_sqr(w/sl, _state); - w = cntbuf->ptr.p_int[nc+i]; - v = v+w*ae_sqr(w/sr-1, _state); - v = v+(sr-w)*ae_sqr(w/sr, _state); - } - v = ae_sqrt(v/(nc*n), _state); - - /* - * Compare with best - */ - x = (double)(2*sl)/(double)(sl+sr)-1; - cc = v*(1-alpha+alpha*ae_sqr(x, _state)); - if( ae_fp_less(cc,cbest) ) - { - - /* - * store split - */ - *rms = v; - koptimal = k; - cbest = cc; - - /* - * calculate CVRMS error - */ - *cvrms = 0; - for(i=0; i<=nc-1; i++) - { - if( sl>1 ) - { - w = cntbuf->ptr.p_int[i]; - *cvrms = *cvrms+w*ae_sqr((w-1)/(sl-1)-1, _state); - *cvrms = *cvrms+(sl-w)*ae_sqr(w/(sl-1), _state); - } - else - { - w = cntbuf->ptr.p_int[i]; - *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-1, _state); - *cvrms = *cvrms+(sl-w)*ae_sqr((double)1/(double)nc, _state); - } - if( sr>1 ) - { - w = cntbuf->ptr.p_int[nc+i]; - *cvrms = *cvrms+w*ae_sqr((w-1)/(sr-1)-1, _state); - *cvrms = *cvrms+(sr-w)*ae_sqr(w/(sr-1), _state); - } - else - { - w = cntbuf->ptr.p_int[nc+i]; - *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-1, _state); - *cvrms = *cvrms+(sr-w)*ae_sqr((double)1/(double)nc, _state); - } - } - *cvrms = ae_sqrt(*cvrms/(nc*n), _state); - } - } - - /* - * Calculate threshold. - * Code is a bit complicated because there can be such - * numbers that 0.5(A+B) equals to A or B (if A-B=epsilon) - */ - *threshold = 0.5*(a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]+a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]); - if( ae_fp_less_eq(*threshold,a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]) ) - { - *threshold = a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]; - } -} - - -/************************************************************************* -Automatic non-optimal discretization, internal subroutine. - - -- ALGLIB -- - Copyright 22.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dssplitk(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t nc, - ae_int_t kmax, - ae_int_t* info, - /* Real */ ae_vector* thresholds, - ae_int_t* ni, - double* cve, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _a; - ae_vector _c; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t k; - ae_vector ties; - ae_int_t tiecount; - ae_vector p1; - ae_vector p2; - ae_vector cnt; - double v2; - ae_int_t bestk; - double bestcve; - ae_vector bestsizes; - double curcve; - ae_vector cursizes; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init_copy(&_c, c, _state, ae_true); - c = &_c; - *info = 0; - ae_vector_clear(thresholds); - *ni = 0; - *cve = 0; - ae_vector_init(&ties, 0, DT_INT, _state, ae_true); - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - ae_vector_init(&cnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&bestsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(&cursizes, 0, DT_INT, _state, ae_true); - - - /* - * Test for errors in inputs - */ - if( (n<=0||nc<2)||kmax<2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Tie - */ - dstie(a, n, &ties, &tiecount, &p1, &p2, _state); - for(i=0; i<=n-1; i++) - { - if( p2.ptr.p_int[i]!=i ) - { - k = c->ptr.p_int[i]; - c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; - c->ptr.p_int[p2.ptr.p_int[i]] = k; - } - } - - /* - * Special cases - */ - if( tiecount==1 ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * General case: - * 0. allocate arrays - */ - kmax = ae_minint(kmax, tiecount, _state); - ae_vector_set_length(&bestsizes, kmax-1+1, _state); - ae_vector_set_length(&cursizes, kmax-1+1, _state); - ae_vector_set_length(&cnt, nc-1+1, _state); - - /* - * General case: - * 1. prepare "weak" solution (two subintervals, divided at median) - */ - v2 = ae_maxrealnumber; - j = -1; - for(i=1; i<=tiecount-1; i++) - { - if( ae_fp_less(ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state),v2) ) - { - v2 = ae_fabs(ties.ptr.p_int[i]-0.5*n, _state); - j = i; - } - } - ae_assert(j>0, "DSSplitK: internal error #1!", _state); - bestk = 2; - bestsizes.ptr.p_int[0] = ties.ptr.p_int[j]; - bestsizes.ptr.p_int[1] = n-j; - bestcve = 0; - for(i=0; i<=nc-1; i++) - { - cnt.ptr.p_int[i] = 0; - } - for(i=0; i<=j-1; i++) - { - bdss_tieaddc(c, &ties, i, nc, &cnt, _state); - } - bestcve = bestcve+bdss_getcv(&cnt, nc, _state); - for(i=0; i<=nc-1; i++) - { - cnt.ptr.p_int[i] = 0; - } - for(i=j; i<=tiecount-1; i++) - { - bdss_tieaddc(c, &ties, i, nc, &cnt, _state); - } - bestcve = bestcve+bdss_getcv(&cnt, nc, _state); - - /* - * General case: - * 2. Use greedy algorithm to find sub-optimal split in O(KMax*N) time - */ - for(k=2; k<=kmax; k++) - { - - /* - * Prepare greedy K-interval split - */ - for(i=0; i<=k-1; i++) - { - cursizes.ptr.p_int[i] = 0; - } - i = 0; - j = 0; - while(j<=tiecount-1&&i<=k-1) - { - - /* - * Rule: I-th bin is empty, fill it - */ - if( cursizes.ptr.p_int[i]==0 ) - { - cursizes.ptr.p_int[i] = ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; - j = j+1; - continue; - } - - /* - * Rule: (K-1-I) bins left, (K-1-I) ties left (1 tie per bin); next bin - */ - if( tiecount-j==k-1-i ) - { - i = i+1; - continue; - } - - /* - * Rule: last bin, always place in current - */ - if( i==k-1 ) - { - cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; - j = j+1; - continue; - } - - /* - * Place J-th tie in I-th bin, or leave for I+1-th bin. - */ - if( ae_fp_less(ae_fabs(cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]-(double)n/(double)k, _state),ae_fabs(cursizes.ptr.p_int[i]-(double)n/(double)k, _state)) ) - { - cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; - j = j+1; - } - else - { - i = i+1; - } - } - ae_assert(cursizes.ptr.p_int[k-1]!=0&&j==tiecount, "DSSplitK: internal error #1", _state); - - /* - * Calculate CVE - */ - curcve = 0; - j = 0; - for(i=0; i<=k-1; i++) - { - for(j1=0; j1<=nc-1; j1++) - { - cnt.ptr.p_int[j1] = 0; - } - for(j1=j; j1<=j+cursizes.ptr.p_int[i]-1; j1++) - { - cnt.ptr.p_int[c->ptr.p_int[j1]] = cnt.ptr.p_int[c->ptr.p_int[j1]]+1; - } - curcve = curcve+bdss_getcv(&cnt, nc, _state); - j = j+cursizes.ptr.p_int[i]; - } - - /* - * Choose best variant - */ - if( ae_fp_less(curcve,bestcve) ) - { - for(i=0; i<=k-1; i++) - { - bestsizes.ptr.p_int[i] = cursizes.ptr.p_int[i]; - } - bestcve = curcve; - bestk = k; - } - } - - /* - * Transform from sizes to thresholds - */ - *cve = bestcve; - *ni = bestk; - ae_vector_set_length(thresholds, *ni-2+1, _state); - j = bestsizes.ptr.p_int[0]; - for(i=1; i<=bestk-1; i++) - { - thresholds->ptr.p_double[i-1] = 0.5*(a->ptr.p_double[j-1]+a->ptr.p_double[j]); - j = j+bestsizes.ptr.p_int[i]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Automatic optimal discretization, internal subroutine. - - -- ALGLIB -- - Copyright 22.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplitk(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t nc, - ae_int_t kmax, - ae_int_t* info, - /* Real */ ae_vector* thresholds, - ae_int_t* ni, - double* cve, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _a; - ae_vector _c; - ae_int_t i; - ae_int_t j; - ae_int_t s; - ae_int_t jl; - ae_int_t jr; - double v2; - ae_vector ties; - ae_int_t tiecount; - ae_vector p1; - ae_vector p2; - double cvtemp; - ae_vector cnt; - ae_vector cnt2; - ae_matrix cv; - ae_matrix splits; - ae_int_t k; - ae_int_t koptimal; - double cvoptimal; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init_copy(&_c, c, _state, ae_true); - c = &_c; - *info = 0; - ae_vector_clear(thresholds); - *ni = 0; - *cve = 0; - ae_vector_init(&ties, 0, DT_INT, _state, ae_true); - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - ae_vector_init(&cnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&cnt2, 0, DT_INT, _state, ae_true); - ae_matrix_init(&cv, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&splits, 0, 0, DT_INT, _state, ae_true); - - - /* - * Test for errors in inputs - */ - if( (n<=0||nc<2)||kmax<2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Tie - */ - dstie(a, n, &ties, &tiecount, &p1, &p2, _state); - for(i=0; i<=n-1; i++) - { - if( p2.ptr.p_int[i]!=i ) - { - k = c->ptr.p_int[i]; - c->ptr.p_int[i] = c->ptr.p_int[p2.ptr.p_int[i]]; - c->ptr.p_int[p2.ptr.p_int[i]] = k; - } - } - - /* - * Special cases - */ - if( tiecount==1 ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * General case - * Use dynamic programming to find best split in O(KMax*NC*TieCount^2) time - */ - kmax = ae_minint(kmax, tiecount, _state); - ae_matrix_set_length(&cv, kmax-1+1, tiecount-1+1, _state); - ae_matrix_set_length(&splits, kmax-1+1, tiecount-1+1, _state); - ae_vector_set_length(&cnt, nc-1+1, _state); - ae_vector_set_length(&cnt2, nc-1+1, _state); - for(j=0; j<=nc-1; j++) - { - cnt.ptr.p_int[j] = 0; - } - for(j=0; j<=tiecount-1; j++) - { - bdss_tieaddc(c, &ties, j, nc, &cnt, _state); - splits.ptr.pp_int[0][j] = 0; - cv.ptr.pp_double[0][j] = bdss_getcv(&cnt, nc, _state); - } - for(k=1; k<=kmax-1; k++) - { - for(j=0; j<=nc-1; j++) - { - cnt.ptr.p_int[j] = 0; - } - - /* - * Subtask size J in [K..TieCount-1]: - * optimal K-splitting on ties from 0-th to J-th. - */ - for(j=k; j<=tiecount-1; j++) - { - - /* - * Update Cnt - let it contain classes of ties from K-th to J-th - */ - bdss_tieaddc(c, &ties, j, nc, &cnt, _state); - - /* - * Search for optimal split point S in [K..J] - */ - for(i=0; i<=nc-1; i++) - { - cnt2.ptr.p_int[i] = cnt.ptr.p_int[i]; - } - cv.ptr.pp_double[k][j] = cv.ptr.pp_double[k-1][j-1]+bdss_getcv(&cnt2, nc, _state); - splits.ptr.pp_int[k][j] = j; - for(s=k+1; s<=j; s++) - { - - /* - * Update Cnt2 - let it contain classes of ties from S-th to J-th - */ - bdss_tiesubc(c, &ties, s-1, nc, &cnt2, _state); - - /* - * Calculate CVE - */ - cvtemp = cv.ptr.pp_double[k-1][s-1]+bdss_getcv(&cnt2, nc, _state); - if( ae_fp_less(cvtemp,cv.ptr.pp_double[k][j]) ) - { - cv.ptr.pp_double[k][j] = cvtemp; - splits.ptr.pp_int[k][j] = s; - } - } - } - } - - /* - * Choose best partition, output result - */ - koptimal = -1; - cvoptimal = ae_maxrealnumber; - for(k=0; k<=kmax-1; k++) - { - if( ae_fp_less(cv.ptr.pp_double[k][tiecount-1],cvoptimal) ) - { - cvoptimal = cv.ptr.pp_double[k][tiecount-1]; - koptimal = k; - } - } - ae_assert(koptimal>=0, "DSOptimalSplitK: internal error #1!", _state); - if( koptimal==0 ) - { - - /* - * Special case: best partition is one big interval. - * Even 2-partition is not better. - * This is possible when dealing with "weak" predictor variables. - * - * Make binary split as close to the median as possible. - */ - v2 = ae_maxrealnumber; - j = -1; - for(i=1; i<=tiecount-1; i++) - { - if( ae_fp_less(ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state),v2) ) - { - v2 = ae_fabs(ties.ptr.p_int[i]-0.5*(n-1), _state); - j = i; - } - } - ae_assert(j>0, "DSOptimalSplitK: internal error #2!", _state); - ae_vector_set_length(thresholds, 0+1, _state); - thresholds->ptr.p_double[0] = 0.5*(a->ptr.p_double[ties.ptr.p_int[j-1]]+a->ptr.p_double[ties.ptr.p_int[j]]); - *ni = 2; - *cve = 0; - for(i=0; i<=nc-1; i++) - { - cnt.ptr.p_int[i] = 0; - } - for(i=0; i<=j-1; i++) - { - bdss_tieaddc(c, &ties, i, nc, &cnt, _state); - } - *cve = *cve+bdss_getcv(&cnt, nc, _state); - for(i=0; i<=nc-1; i++) - { - cnt.ptr.p_int[i] = 0; - } - for(i=j; i<=tiecount-1; i++) - { - bdss_tieaddc(c, &ties, i, nc, &cnt, _state); - } - *cve = *cve+bdss_getcv(&cnt, nc, _state); - } - else - { - - /* - * General case: 2 or more intervals - * - * NOTE: we initialize both JL and JR (left and right bounds), - * although algorithm needs only JL. - */ - ae_vector_set_length(thresholds, koptimal-1+1, _state); - *ni = koptimal+1; - *cve = cv.ptr.pp_double[koptimal][tiecount-1]; - jl = splits.ptr.pp_int[koptimal][tiecount-1]; - jr = tiecount-1; - for(k=koptimal; k>=1; k--) - { - thresholds->ptr.p_double[k-1] = 0.5*(a->ptr.p_double[ties.ptr.p_int[jl-1]]+a->ptr.p_double[ties.ptr.p_int[jl]]); - jr = jl-1; - jl = splits.ptr.pp_int[k-1][jl-1]; - } - touchint(&jr, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal function -*************************************************************************/ -static double bdss_xlny(double x, double y, ae_state *_state) -{ - double result; - - - if( ae_fp_eq(x,0) ) - { - result = 0; - } - else - { - result = x*ae_log(y, _state); - } - return result; -} - - -/************************************************************************* -Internal function, -returns number of samples of class I in Cnt[I] -*************************************************************************/ -static double bdss_getcv(/* Integer */ ae_vector* cnt, - ae_int_t nc, - ae_state *_state) -{ - ae_int_t i; - double s; - double result; - - - s = 0; - for(i=0; i<=nc-1; i++) - { - s = s+cnt->ptr.p_int[i]; - } - result = 0; - for(i=0; i<=nc-1; i++) - { - result = result-bdss_xlny(cnt->ptr.p_int[i], cnt->ptr.p_int[i]/(s+nc-1), _state); - } - return result; -} - - -/************************************************************************* -Internal function, adds number of samples of class I in tie NTie to Cnt[I] -*************************************************************************/ -static void bdss_tieaddc(/* Integer */ ae_vector* c, - /* Integer */ ae_vector* ties, - ae_int_t ntie, - ae_int_t nc, - /* Integer */ ae_vector* cnt, - ae_state *_state) -{ - ae_int_t i; - - - for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) - { - cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]+1; - } -} - - -/************************************************************************* -Internal function, subtracts number of samples of class I in tie NTie to Cnt[I] -*************************************************************************/ -static void bdss_tiesubc(/* Integer */ ae_vector* c, - /* Integer */ ae_vector* ties, - ae_int_t ntie, - ae_int_t nc, - /* Integer */ ae_vector* cnt, - ae_state *_state) -{ - ae_int_t i; - - - for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) - { - cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]-1; - } -} - - -ae_bool _cvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - cvreport *p = (cvreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _cvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - cvreport *dst = (cvreport*)_dst; - cvreport *src = (cvreport*)_src; - dst->relclserror = src->relclserror; - dst->avgce = src->avgce; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - return ae_true; -} - - -void _cvreport_clear(void* _p) -{ - cvreport *p = (cvreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _cvreport_destroy(void* _p) -{ - cvreport *p = (cvreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -This function initializes clusterizer object. Newly initialized object is -empty, i.e. it does not contain dataset. You should use it as follows: -1. creation -2. dataset is added with ClusterizerSetPoints() -3. additional parameters are set -3. clusterization is performed with one of the clustering functions - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizercreate(clusterizerstate* s, ae_state *_state) -{ - - _clusterizerstate_clear(s); - - s->npoints = 0; - s->nfeatures = 0; - s->disttype = 2; - s->ahcalgo = 0; - s->kmeansrestarts = 1; - s->kmeansmaxits = 0; -} - - -/************************************************************************* -This function adds dataset to the clusterizer structure. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -NOTE 1: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - -NOTE 2: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric - * k-means++ clustering algorithm may be used only with Euclidean - distance function - Thus, list of specific clustering algorithms you may use depends - on distance function you specify when you set your dataset. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetpoints(clusterizerstate* s, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerSetPoints: incorrect DistType", _state); - ae_assert(npoints>=0, "ClusterizerSetPoints: NPoints<0", _state); - ae_assert(nfeatures>=1, "ClusterizerSetPoints: NFeatures<1", _state); - ae_assert(xy->rows>=npoints, "ClusterizerSetPoints: Rows(XY)cols>=nfeatures, "ClusterizerSetPoints: Cols(XY)npoints = npoints; - s->nfeatures = nfeatures; - s->disttype = disttype; - rmatrixsetlengthatleast(&s->xy, npoints, nfeatures, _state); - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&s->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); - } -} - - -/************************************************************************* -This function adds dataset given by distance matrix to the clusterizer -structure. It is important that dataset is not given explicitly - only -distance matrix is given. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - D - array[NPoints,NPoints], distance matrix given by its upper - or lower triangle (main diagonal is ignored because its - entries are expected to be zero). - NPoints - number of points - IsUpper - whether upper or lower triangle of D is given. - -NOTE 1: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric, including one which is given by - distance matrix - * k-means++ clustering algorithm may be used only with Euclidean - distance function and explicitly given points - it can not be - used with dataset given by distance matrix - Thus, if you call this function, you will be unable to use k-means - clustering algorithm to process your problem. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetdistances(clusterizerstate* s, - /* Real */ ae_matrix* d, - ae_int_t npoints, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t j0; - ae_int_t j1; - - - ae_assert(npoints>=0, "ClusterizerSetDistances: NPoints<0", _state); - ae_assert(d->rows>=npoints, "ClusterizerSetDistances: Rows(D)cols>=npoints, "ClusterizerSetDistances: Cols(D)npoints = npoints; - s->nfeatures = 0; - s->disttype = -1; - rmatrixsetlengthatleast(&s->d, npoints, npoints, _state); - for(i=0; i<=npoints-1; i++) - { - if( isupper ) - { - j0 = i+1; - j1 = npoints-1; - } - else - { - j0 = 0; - j1 = i-1; - } - for(j=j0; j<=j1; j++) - { - ae_assert(ae_isfinite(d->ptr.pp_double[i][j], _state)&&ae_fp_greater_eq(d->ptr.pp_double[i][j],0), "ClusterizerSetDistances: D contains infinite, NAN or negative elements", _state); - s->d.ptr.pp_double[i][j] = d->ptr.pp_double[i][j]; - s->d.ptr.pp_double[j][i] = d->ptr.pp_double[i][j]; - } - s->d.ptr.pp_double[i][i] = 0; - } -} - - -/************************************************************************* -This function sets agglomerative hierarchical clustering algorithm - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Algo - algorithm type: - * 0 complete linkage (default algorithm) - * 1 single linkage - * 2 unweighted average linkage - * 3 weighted average linkage - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetahcalgo(clusterizerstate* s, - ae_int_t algo, - ae_state *_state) -{ - - - ae_assert(((algo==0||algo==1)||algo==2)||algo==3, "ClusterizerSetHCAlgo: incorrect algorithm type", _state); - s->ahcalgo = algo; -} - - -/************************************************************************* -This function sets k-means++ properties : number of restarts and maximum -number of iterations per one run. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Restarts- restarts count, >=1. - k-means++ algorithm performs several restarts and chooses - best set of centers (one with minimum squared distance). - MaxIts - maximum number of k-means iterations performed during one - run. >=0, zero value means that algorithm performs unlimited - number of iterations. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetkmeanslimits(clusterizerstate* s, - ae_int_t restarts, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(restarts>=1, "ClusterizerSetKMeansLimits: Restarts<=0", _state); - ae_assert(maxits>=0, "ClusterizerSetKMeansLimits: MaxIts<0", _state); - s->kmeansrestarts = restarts; - s->kmeansmaxits = maxits; -} - - -/************************************************************************* -This function performs agglomerative hierarchical clustering - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - -OUTPUT PARAMETERS: - Rep - clustering results; see description of AHCReport - structure for more information. - -NOTE 1: hierarchical clustering algorithms require large amounts of memory. - In particular, this implementation needs sizeof(double)*NPoints^2 - bytes, which are used to store distance matrix. In case we work - with user-supplied matrix, this amount is multiplied by 2 (we have - to store original matrix and to work with its copy). - - For example, problem with 10000 points would require 800M of RAM, - even when working in a 1-dimensional space. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunahc(clusterizerstate* s, - ahcreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t npoints; - ae_int_t nfeatures; - ae_matrix d; - - ae_frame_make(_state, &_frame_block); - _ahcreport_clear(rep); - ae_matrix_init(&d, 0, 0, DT_REAL, _state, ae_true); - - npoints = s->npoints; - nfeatures = s->nfeatures; - - /* - * Fill Rep.NPoints, quick exit when NPoints<=1 - */ - rep->npoints = npoints; - if( npoints==0 ) - { - ae_vector_set_length(&rep->p, 0, _state); - ae_matrix_set_length(&rep->z, 0, 0, _state); - ae_matrix_set_length(&rep->pz, 0, 0, _state); - ae_matrix_set_length(&rep->pm, 0, 0, _state); - ae_vector_set_length(&rep->mergedist, 0, _state); - ae_frame_leave(_state); - return; - } - if( npoints==1 ) - { - ae_vector_set_length(&rep->p, 1, _state); - ae_matrix_set_length(&rep->z, 0, 0, _state); - ae_matrix_set_length(&rep->pz, 0, 0, _state); - ae_matrix_set_length(&rep->pm, 0, 0, _state); - ae_vector_set_length(&rep->mergedist, 0, _state); - rep->p.ptr.p_int[0] = 0; - ae_frame_leave(_state); - return; - } - - /* - * More than one point - */ - if( s->disttype==-1 ) - { - - /* - * Run clusterizer with user-supplied distance matrix - */ - clustering_clusterizerrunahcinternal(s, &s->d, rep, _state); - ae_frame_leave(_state); - return; - } - else - { - - /* - * Build distance matrix D. - */ - clusterizergetdistances(&s->xy, npoints, nfeatures, s->disttype, &d, _state); - - /* - * Run clusterizer - */ - clustering_clusterizerrunahcinternal(s, &d, rep, _state); - ae_frame_leave(_state); - return; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_clusterizerrunahc(clusterizerstate* s, - ahcreport* rep, ae_state *_state) -{ - clusterizerrunahc(s,rep, _state); -} - - -/************************************************************************* -This function performs clustering by k-means++ algorithm. - -You may change algorithm properties like number of restarts or iterations -limit by calling ClusterizerSetKMeansLimits() functions. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - K - number of clusters, K>=0. - K can be zero only when algorithm is called for empty - dataset, in this case completion code is set to - success (+1). - If K=0 and dataset size is non-zero, we can not - meaningfully assign points to some center (there are no - centers because K=0) and return -3 as completion code - (failure). - -OUTPUT PARAMETERS: - Rep - clustering results; see description of KMeansReport - structure for more information. - -NOTE 1: k-means clustering can be performed only for datasets with - Euclidean distance function. Algorithm will return negative - completion code in Rep.TerminationType in case dataset was added - to clusterizer with DistType other than Euclidean (or dataset was - specified by distance matrix instead of explicitly given points). - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunkmeans(clusterizerstate* s, - ae_int_t k, - kmeansreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix dummy; - - ae_frame_make(_state, &_frame_block); - _kmeansreport_clear(rep); - ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(k>=0, "ClusterizerRunKMeans: K<0", _state); - - /* - * Incorrect distance type - */ - if( s->disttype!=2 ) - { - rep->npoints = s->npoints; - rep->terminationtype = -5; - rep->k = k; - ae_frame_leave(_state); - return; - } - - /* - * K>NPoints or (K=0 and NPoints>0) - */ - if( k>s->npoints||(k==0&&s->npoints>0) ) - { - rep->npoints = s->npoints; - rep->terminationtype = -3; - rep->k = k; - ae_frame_leave(_state); - return; - } - - /* - * No points - */ - if( s->npoints==0 ) - { - rep->npoints = 0; - rep->terminationtype = 1; - rep->k = k; - ae_frame_leave(_state); - return; - } - - /* - * Normal case: - * 1<=K<=NPoints, Euclidean distance - */ - rep->npoints = s->npoints; - rep->nfeatures = s->nfeatures; - rep->k = k; - rep->npoints = s->npoints; - rep->nfeatures = s->nfeatures; - kmeansgenerateinternal(&s->xy, s->npoints, s->nfeatures, k, s->kmeansmaxits, s->kmeansrestarts, &rep->terminationtype, &dummy, ae_false, &rep->c, ae_true, &rep->cidx, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function returns distance matrix for dataset - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -OUTPUT PARAMETERS: - D - array[NPoints,NPoints], distance matrix - (full matrix is returned, with lower and upper triangles) - -NOTES: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizergetdistances(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double vv; - double vr; - ae_matrix tmpxy; - ae_vector tmpx; - ae_vector tmpy; - ae_vector diagbuf; - apbuffers buf; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(d); - ae_matrix_init(&tmpxy, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&diagbuf, 0, DT_REAL, _state, ae_true); - _apbuffers_init(&buf, _state, ae_true); - - ae_assert(nfeatures>=1, "ClusterizerGetDistances: NFeatures<1", _state); - ae_assert(npoints>=0, "ClusterizerGetDistances: NPoints<1", _state); - ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerGetDistances: incorrect DistType", _state); - ae_assert(xy->rows>=npoints, "ClusterizerGetDistances: Rows(XY)cols>=nfeatures, "ClusterizerGetDistances: Cols(XY)ptr.pp_double[0][0] = 0; - ae_frame_leave(_state); - return; - } - - /* - * Build distance matrix D. - */ - if( disttype==0||disttype==1 ) - { - - /* - * Chebyshev or city-block distances: - * * recursively calculate upper triangle (with main diagonal) - * * copy it to the bottom part of the matrix - */ - ae_matrix_set_length(d, npoints, npoints, _state); - clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, 0, npoints, 0, npoints, _state); - rmatrixenforcesymmetricity(d, npoints, ae_true, _state); - ae_frame_leave(_state); - return; - } - if( disttype==2 ) - { - - /* - * Euclidean distance - * - * NOTE: parallelization is done within RMatrixSYRK - */ - ae_matrix_set_length(d, npoints, npoints, _state); - ae_matrix_set_length(&tmpxy, npoints, nfeatures, _state); - ae_vector_set_length(&tmpx, nfeatures, _state); - ae_vector_set_length(&diagbuf, npoints, _state); - for(j=0; j<=nfeatures-1; j++) - { - tmpx.ptr.p_double[j] = 0.0; - } - v = (double)1/(double)npoints; - for(i=0; i<=npoints-1; i++) - { - ae_v_addd(&tmpx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1), v); - } - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&tmpxy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); - ae_v_sub(&tmpxy.ptr.pp_double[i][0], 1, &tmpx.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); - } - rmatrixsyrk(npoints, nfeatures, 1.0, &tmpxy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); - for(i=0; i<=npoints-1; i++) - { - diagbuf.ptr.p_double[i] = d->ptr.pp_double[i][i]; - } - for(i=0; i<=npoints-1; i++) - { - d->ptr.pp_double[i][i] = 0.0; - for(j=i+1; j<=npoints-1; j++) - { - v = ae_sqrt(ae_maxreal(diagbuf.ptr.p_double[i]+diagbuf.ptr.p_double[j]-2*d->ptr.pp_double[i][j], 0.0, _state), _state); - d->ptr.pp_double[i][j] = v; - } - } - rmatrixenforcesymmetricity(d, npoints, ae_true, _state); - ae_frame_leave(_state); - return; - } - if( disttype==10||disttype==11 ) - { - - /* - * Absolute/nonabsolute Pearson correlation distance - * - * NOTE: parallelization is done within PearsonCorrM, which calls RMatrixSYRK internally - */ - ae_matrix_set_length(d, npoints, npoints, _state); - ae_vector_set_length(&diagbuf, npoints, _state); - ae_matrix_set_length(&tmpxy, npoints, nfeatures, _state); - for(i=0; i<=npoints-1; i++) - { - v = 0.0; - for(j=0; j<=nfeatures-1; j++) - { - v = v+xy->ptr.pp_double[i][j]; - } - v = v/nfeatures; - for(j=0; j<=nfeatures-1; j++) - { - tmpxy.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]-v; - } - } - rmatrixsyrk(npoints, nfeatures, 1.0, &tmpxy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); - for(i=0; i<=npoints-1; i++) - { - diagbuf.ptr.p_double[i] = d->ptr.pp_double[i][i]; - } - for(i=0; i<=npoints-1; i++) - { - d->ptr.pp_double[i][i] = 0.0; - for(j=i+1; j<=npoints-1; j++) - { - v = d->ptr.pp_double[i][j]/ae_sqrt(diagbuf.ptr.p_double[i]*diagbuf.ptr.p_double[j], _state); - if( disttype==10 ) - { - v = 1-v; - } - else - { - v = 1-ae_fabs(v, _state); - } - v = ae_maxreal(v, 0.0, _state); - d->ptr.pp_double[i][j] = v; - } - } - rmatrixenforcesymmetricity(d, npoints, ae_true, _state); - ae_frame_leave(_state); - return; - } - if( disttype==12||disttype==13 ) - { - - /* - * Absolute/nonabsolute uncentered Pearson correlation distance - * - * NOTE: parallelization is done within RMatrixSYRK - */ - ae_matrix_set_length(d, npoints, npoints, _state); - ae_vector_set_length(&diagbuf, npoints, _state); - rmatrixsyrk(npoints, nfeatures, 1.0, xy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); - for(i=0; i<=npoints-1; i++) - { - diagbuf.ptr.p_double[i] = d->ptr.pp_double[i][i]; - } - for(i=0; i<=npoints-1; i++) - { - d->ptr.pp_double[i][i] = 0.0; - for(j=i+1; j<=npoints-1; j++) - { - v = d->ptr.pp_double[i][j]/ae_sqrt(diagbuf.ptr.p_double[i]*diagbuf.ptr.p_double[j], _state); - if( disttype==13 ) - { - v = ae_fabs(v, _state); - } - v = ae_minreal(v, 1.0, _state); - d->ptr.pp_double[i][j] = 1-v; - } - } - rmatrixenforcesymmetricity(d, npoints, ae_true, _state); - ae_frame_leave(_state); - return; - } - if( disttype==20||disttype==21 ) - { - - /* - * Spearman rank correlation - * - * NOTE: parallelization of correlation matrix is done within - * PearsonCorrM, which calls RMatrixSYRK internally - */ - ae_matrix_set_length(d, npoints, npoints, _state); - ae_vector_set_length(&diagbuf, npoints, _state); - ae_matrix_set_length(&tmpxy, npoints, nfeatures, _state); - rmatrixcopy(npoints, nfeatures, xy, 0, 0, &tmpxy, 0, 0, _state); - rankdatacentered(&tmpxy, npoints, nfeatures, _state); - rmatrixsyrk(npoints, nfeatures, 1.0, &tmpxy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); - for(i=0; i<=npoints-1; i++) - { - if( ae_fp_greater(d->ptr.pp_double[i][i],0) ) - { - diagbuf.ptr.p_double[i] = 1/ae_sqrt(d->ptr.pp_double[i][i], _state); - } - else - { - diagbuf.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=npoints-1; i++) - { - v = diagbuf.ptr.p_double[i]; - d->ptr.pp_double[i][i] = 0.0; - for(j=i+1; j<=npoints-1; j++) - { - vv = d->ptr.pp_double[i][j]*v*diagbuf.ptr.p_double[j]; - if( disttype==20 ) - { - vr = 1-vv; - } - else - { - vr = 1-ae_fabs(vv, _state); - } - if( ae_fp_less(vr,0) ) - { - vr = 0.0; - } - d->ptr.pp_double[i][j] = vr; - } - } - rmatrixenforcesymmetricity(d, npoints, ae_true, _state); - ae_frame_leave(_state); - return; - } - ae_assert(ae_false, "Assertion failed", _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_clusterizergetdistances(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, ae_state *_state) -{ - clusterizergetdistances(xy,npoints,nfeatures,disttype,d, _state); -} - - -/************************************************************************* -This function takes as input clusterization report Rep, desired clusters -count K, and builds top K clusters from hierarchical clusterization tree. -It returns assignment of points to clusters (array of cluster indexes). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - K - desired number of clusters, 1<=K<=NPoints. - K can be zero only when NPoints=0. - -OUTPUT PARAMETERS: - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I]npoints; - ae_assert(npoints>=0, "ClusterizerGetKClusters: internal error in Rep integrity", _state); - ae_assert(k>=0, "ClusterizerGetKClusters: K<=0", _state); - ae_assert(k<=npoints, "ClusterizerGetKClusters: K>NPoints", _state); - ae_assert(k>0||npoints==0, "ClusterizerGetKClusters: K<=0", _state); - ae_assert(npoints==rep->npoints, "ClusterizerGetKClusters: NPoints<>Rep.NPoints", _state); - - /* - * Quick exit - */ - if( npoints==0 ) - { - ae_frame_leave(_state); - return; - } - if( npoints==1 ) - { - ae_vector_set_length(cz, 1, _state); - ae_vector_set_length(cidx, 1, _state); - cz->ptr.p_int[0] = 0; - cidx->ptr.p_int[0] = 0; - ae_frame_leave(_state); - return; - } - - /* - * Replay merges, from top to bottom, - * keep track of clusters being present at the moment - */ - ae_vector_set_length(&presentclusters, 2*npoints-1, _state); - ae_vector_set_length(&tmpidx, npoints, _state); - for(i=0; i<=2*npoints-3; i++) - { - presentclusters.ptr.p_bool[i] = ae_false; - } - presentclusters.ptr.p_bool[2*npoints-2] = ae_true; - for(i=0; i<=npoints-1; i++) - { - tmpidx.ptr.p_int[i] = 2*npoints-2; - } - for(mergeidx=npoints-2; mergeidx>=npoints-k; mergeidx--) - { - - /* - * Update information about clusters being present at the moment - */ - presentclusters.ptr.p_bool[npoints+mergeidx] = ae_false; - presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][0]] = ae_true; - presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][1]] = ae_true; - - /* - * Update TmpIdx according to the current state of the dataset - * - * NOTE: TmpIdx contains cluster indexes from [0..2*NPoints-2]; - * we will convert them to [0..K-1] later. - */ - i0 = rep->pm.ptr.pp_int[mergeidx][0]; - i1 = rep->pm.ptr.pp_int[mergeidx][1]; - t = rep->z.ptr.pp_int[mergeidx][0]; - for(i=i0; i<=i1; i++) - { - tmpidx.ptr.p_int[i] = t; - } - i0 = rep->pm.ptr.pp_int[mergeidx][2]; - i1 = rep->pm.ptr.pp_int[mergeidx][3]; - t = rep->z.ptr.pp_int[mergeidx][1]; - for(i=i0; i<=i1; i++) - { - tmpidx.ptr.p_int[i] = t; - } - } - - /* - * Fill CZ - array which allows us to convert cluster indexes - * from one system to another. - */ - ae_vector_set_length(cz, k, _state); - ae_vector_set_length(&clusterindexes, 2*npoints-1, _state); - t = 0; - for(i=0; i<=2*npoints-2; i++) - { - if( presentclusters.ptr.p_bool[i] ) - { - cz->ptr.p_int[t] = i; - clusterindexes.ptr.p_int[i] = t; - t = t+1; - } - } - ae_assert(t==k, "ClusterizerGetKClusters: internal error", _state); - - /* - * Convert indexes stored in CIdx - */ - ae_vector_set_length(cidx, npoints, _state); - for(i=0; i<=npoints-1; i++) - { - cidx->ptr.p_int[i] = clusterindexes.ptr.p_int[tmpidx.ptr.p_int[rep->p.ptr.p_int[i]]]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function accepts AHC report Rep, desired minimum intercluster -distance and returns top clusters from hierarchical clusterization tree -which are separated by distance R or HIGHER. - -It returns assignment of points to clusters (array of cluster indexes). - -There is one more function with similar name - ClusterizerSeparatedByCorr, -which returns clusters with intercluster correlation equal to R or LOWER -(note: higher for distance, lower for correlation). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - R - desired minimum intercluster distance, R>=0 - -OUTPUT PARAMETERS: - K - number of clusters, 1<=K<=NPoints - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],r)) - { - *k = *k+1; - } - clusterizergetkclusters(rep, *k, cidx, cz, _state); -} - - -/************************************************************************* -This function accepts AHC report Rep, desired maximum intercluster -correlation and returns top clusters from hierarchical clusterization tree -which are separated by correlation R or LOWER. - -It returns assignment of points to clusters (array of cluster indexes). - -There is one more function with similar name - ClusterizerSeparatedByDist, -which returns clusters with intercluster distance equal to R or HIGHER -(note: higher for distance, lower for correlation). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - R - desired maximum intercluster correlation, -1<=R<=+1 - -OUTPUT PARAMETERS: - K - number of clusters, 1<=K<=NPoints - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],1-r)) - { - *k = *k+1; - } - clusterizergetkclusters(rep, *k, cidx, cz, _state); -} - - -/************************************************************************* -K-means++ clusterization - -INPUT PARAMETERS: - XY - dataset, array [0..NPoints-1,0..NVars-1]. - NPoints - dataset size, NPoints>=K - NVars - number of variables, NVars>=1 - K - desired number of clusters, K>=1 - Restarts - number of restarts, Restarts>=1 - -OUTPUT PARAMETERS: - Info - return code: - * -3, if task is degenerate (number of distinct points is - less than K) - * -1, if incorrect NPoints/NFeatures/K/Restarts was passed - * 1, if subroutine finished successfully - CCol - array[0..NVars-1,0..K-1].matrix whose columns store - cluster's centers - NeedCCol - True in case caller requires to store result in CCol - CRow - array[0..K-1,0..NVars-1], same as CCol, but centers are - stored in rows - NeedCRow - True in case caller requires to store result in CCol - XYC - array[NPoints], which contains cluster indexes - - -- ALGLIB -- - Copyright 21.03.2009 by Bochkanov Sergey -*************************************************************************/ -void kmeansgenerateinternal(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t k, - ae_int_t maxits, - ae_int_t restarts, - ae_int_t* info, - /* Real */ ae_matrix* ccol, - ae_bool needccol, - /* Real */ ae_matrix* crow, - ae_bool needcrow, - /* Integer */ ae_vector* xyc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_matrix ct; - ae_matrix ctbest; - ae_vector xycbest; - double e; - double eprev; - double ebest; - ae_vector x; - ae_vector tmp; - ae_vector d2; - ae_vector p; - ae_vector csizes; - ae_vector cbusy; - double v; - ae_int_t cclosest; - double dclosest; - ae_vector work; - ae_bool waschanges; - ae_bool zerosizeclusters; - ae_int_t pass; - ae_int_t itcnt; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_matrix_clear(ccol); - ae_matrix_clear(crow); - ae_vector_clear(xyc); - ae_matrix_init(&ct, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ctbest, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xycbest, 0, DT_INT, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_REAL, _state, ae_true); - ae_vector_init(&csizes, 0, DT_INT, _state, ae_true); - ae_vector_init(&cbusy, 0, DT_BOOL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&rs, _state, ae_true); - - - /* - * Test parameters - */ - if( ((npointsptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - cbusy.ptr.p_bool[0] = ae_true; - for(i=1; i<=k-1; i++) - { - cbusy.ptr.p_bool[i] = ae_false; - } - if( !clustering_selectcenterpp(xy, npoints, nvars, &ct, &cbusy, k, &d2, &p, &tmp, _state) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Update centers: - * 2. update center positions - */ - for(i=0; i<=npoints-1; i++) - { - xyc->ptr.p_int[i] = -1; - } - eprev = ae_maxrealnumber; - itcnt = 0; - e = 0; - while(maxits==0||itcntptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tmp.ptr.p_double[0], 1, &ct.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - if( ae_fp_less(v,dclosest) ) - { - cclosest = j; - dclosest = v; - } - } - if( xyc->ptr.p_int[i]!=cclosest ) - { - waschanges = ae_true; - } - xyc->ptr.p_int[i] = cclosest; - } - - /* - * Update centers - */ - for(j=0; j<=k-1; j++) - { - csizes.ptr.p_int[j] = 0; - } - for(i=0; i<=k-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - ct.ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=npoints-1; i++) - { - csizes.ptr.p_int[xyc->ptr.p_int[i]] = csizes.ptr.p_int[xyc->ptr.p_int[i]]+1; - ae_v_add(&ct.ptr.pp_double[xyc->ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - } - zerosizeclusters = ae_false; - for(j=0; j<=k-1; j++) - { - if( csizes.ptr.p_int[j]!=0 ) - { - v = (double)1/(double)csizes.ptr.p_int[j]; - ae_v_muld(&ct.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), v); - } - cbusy.ptr.p_bool[j] = csizes.ptr.p_int[j]!=0; - zerosizeclusters = zerosizeclusters||csizes.ptr.p_int[j]==0; - } - if( zerosizeclusters ) - { - - /* - * Some clusters have zero size - rare, but possible. - * We'll choose new centers for such clusters using k-means++ rule - * and restart algorithm - */ - if( !clustering_selectcenterpp(xy, npoints, nvars, &ct, &cbusy, k, &d2, &p, &tmp, _state) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - continue; - } - - /* - * Stop if one of two conditions is met: - * 1. nothing has changed during iteration - * 2. energy function increased - */ - e = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tmp.ptr.p_double[0], 1, &ct.ptr.pp_double[xyc->ptr.p_int[i]][0], 1, ae_v_len(0,nvars-1)); - v = ae_v_dotproduct(&tmp.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - e = e+v; - } - if( !waschanges||ae_fp_greater_eq(e,eprev) ) - { - break; - } - - /* - * Update EPrev - */ - eprev = e; - } - - /* - * 3. Calculate E, compare with best centers found so far - */ - if( ae_fp_less(e,ebest) ) - { - - /* - * store partition. - */ - ebest = e; - copymatrix(&ct, 0, k-1, 0, nvars-1, &ctbest, 0, k-1, 0, nvars-1, _state); - for(i=0; i<=npoints-1; i++) - { - xycbest.ptr.p_int[i] = xyc->ptr.p_int[i]; - } - } - } - - /* - * Copy and transpose - */ - if( needccol ) - { - ae_matrix_set_length(ccol, nvars, k, _state); - copyandtranspose(&ctbest, 0, k-1, 0, nvars-1, ccol, 0, nvars-1, 0, k-1, _state); - } - if( needcrow ) - { - ae_matrix_set_length(crow, k, nvars, _state); - rmatrixcopy(k, nvars, &ctbest, 0, 0, crow, 0, 0, _state); - } - for(i=0; i<=npoints-1; i++) - { - xyc->ptr.p_int[i] = xycbest.ptr.p_int[i]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Select center for a new cluster using k-means++ rule -*************************************************************************/ -static ae_bool clustering_selectcenterpp(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - /* Real */ ae_matrix* centers, - /* Boolean */ ae_vector* busycenters, - ae_int_t ccnt, - /* Real */ ae_vector* d2, - /* Real */ ae_vector* p, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t cc; - double v; - double s; - ae_bool result; - - - result = ae_true; - for(cc=0; cc<=ccnt-1; cc++) - { - if( !busycenters->ptr.p_bool[cc] ) - { - - /* - * fill D2 - */ - for(i=0; i<=npoints-1; i++) - { - d2->ptr.p_double[i] = ae_maxrealnumber; - for(j=0; j<=ccnt-1; j++) - { - if( busycenters->ptr.p_bool[j] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tmp->ptr.p_double[0], 1, ¢ers->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - v = ae_v_dotproduct(&tmp->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - if( ae_fp_less(v,d2->ptr.p_double[i]) ) - { - d2->ptr.p_double[i] = v; - } - } - } - } - - /* - * calculate P (non-cumulative) - */ - s = 0; - for(i=0; i<=npoints-1; i++) - { - s = s+d2->ptr.p_double[i]; - } - if( ae_fp_eq(s,0) ) - { - result = ae_false; - return result; - } - s = 1/s; - ae_v_moved(&p->ptr.p_double[0], 1, &d2->ptr.p_double[0], 1, ae_v_len(0,npoints-1), s); - - /* - * choose one of points with probability P - * random number within (0,1) is generated and - * inverse empirical CDF is used to randomly choose a point. - */ - s = 0; - v = ae_randomreal(_state); - for(i=0; i<=npoints-1; i++) - { - s = s+p->ptr.p_double[i]; - if( ae_fp_less_eq(v,s)||i==npoints-1 ) - { - ae_v_move(¢ers->ptr.pp_double[cc][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - busycenters->ptr.p_bool[cc] = ae_true; - break; - } - } - } - } - return result; -} - - -/************************************************************************* -This function performs agglomerative hierarchical clustering using -precomputed distance matrix. Internal function, should not be called -directly. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - D - distance matrix, array[S.NFeatures,S.NFeatures] - Contents of the matrix is destroyed during - algorithm operation. - -OUTPUT PARAMETERS: - Rep - clustering results; see description of AHCReport - structure for more information. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -static void clustering_clusterizerrunahcinternal(clusterizerstate* s, - /* Real */ ae_matrix* d, - ahcreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - ae_int_t mergeidx; - ae_int_t c0; - ae_int_t c1; - ae_int_t s0; - ae_int_t s1; - ae_int_t ar; - ae_int_t br; - ae_int_t npoints; - ae_vector cidx; - ae_vector csizes; - ae_vector nnidx; - ae_matrix cinfo; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&cidx, 0, DT_INT, _state, ae_true); - ae_vector_init(&csizes, 0, DT_INT, _state, ae_true); - ae_vector_init(&nnidx, 0, DT_INT, _state, ae_true); - ae_matrix_init(&cinfo, 0, 0, DT_INT, _state, ae_true); - - npoints = s->npoints; - - /* - * Fill Rep.NPoints, quick exit when NPoints<=1 - */ - rep->npoints = npoints; - if( npoints==0 ) - { - ae_vector_set_length(&rep->p, 0, _state); - ae_matrix_set_length(&rep->z, 0, 0, _state); - ae_matrix_set_length(&rep->pz, 0, 0, _state); - ae_matrix_set_length(&rep->pm, 0, 0, _state); - ae_vector_set_length(&rep->mergedist, 0, _state); - ae_frame_leave(_state); - return; - } - if( npoints==1 ) - { - ae_vector_set_length(&rep->p, 1, _state); - ae_matrix_set_length(&rep->z, 0, 0, _state); - ae_matrix_set_length(&rep->pz, 0, 0, _state); - ae_matrix_set_length(&rep->pm, 0, 0, _state); - ae_vector_set_length(&rep->mergedist, 0, _state); - rep->p.ptr.p_int[0] = 0; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&rep->z, npoints-1, 2, _state); - ae_vector_set_length(&rep->mergedist, npoints-1, _state); - - /* - * Build list of nearest neighbors - */ - ae_vector_set_length(&nnidx, npoints, _state); - for(i=0; i<=npoints-1; i++) - { - - /* - * Calculate index of the nearest neighbor - */ - k = -1; - v = ae_maxrealnumber; - for(j=0; j<=npoints-1; j++) - { - if( j!=i&&ae_fp_less(d->ptr.pp_double[i][j],v) ) - { - k = j; - v = d->ptr.pp_double[i][j]; - } - } - ae_assert(ae_fp_less(v,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); - nnidx.ptr.p_int[i] = k; - } - - /* - * Distance matrix is built, perform merges. - * - * NOTE 1: CIdx is array[NPoints] which maps rows/columns of the - * distance matrix D to indexes of clusters. Values of CIdx - * from [0,NPoints) denote single-point clusters, and values - * from [NPoints,2*NPoints-1) denote ones obtained by merging - * smaller clusters. Negative calues correspond to absent clusters. - * - * Initially it contains [0...NPoints-1], after each merge - * one element of CIdx (one with index C0) is replaced by - * NPoints+MergeIdx, and another one with index C1 is - * rewritten by -1. - * - * NOTE 2: CSizes is array[NPoints] which stores sizes of clusters. - * - */ - ae_vector_set_length(&cidx, npoints, _state); - ae_vector_set_length(&csizes, npoints, _state); - for(i=0; i<=npoints-1; i++) - { - cidx.ptr.p_int[i] = i; - csizes.ptr.p_int[i] = 1; - } - for(mergeidx=0; mergeidx<=npoints-2; mergeidx++) - { - - /* - * Select pair of clusters (C0,C1) with CIdx[C0]=0 ) - { - if( ae_fp_less(d->ptr.pp_double[i][nnidx.ptr.p_int[i]],v) ) - { - c0 = i; - c1 = nnidx.ptr.p_int[i]; - v = d->ptr.pp_double[i][nnidx.ptr.p_int[i]]; - } - } - } - ae_assert(ae_fp_less(v,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); - if( cidx.ptr.p_int[c0]>cidx.ptr.p_int[c1] ) - { - i = c1; - c1 = c0; - c0 = i; - } - - /* - * Fill one row of Rep.Z and one element of Rep.MergeDist - */ - rep->z.ptr.pp_int[mergeidx][0] = cidx.ptr.p_int[c0]; - rep->z.ptr.pp_int[mergeidx][1] = cidx.ptr.p_int[c1]; - rep->mergedist.ptr.p_double[mergeidx] = v; - - /* - * Update distance matrix: - * * row/column C0 are updated by distances to the new cluster - * * row/column C1 are considered empty (we can fill them by zeros, - * but do not want to spend time - we just ignore them) - * - * NOTE: it is important to update distance matrix BEFORE CIdx/CSizes - * are updated. - */ - ae_assert(((s->ahcalgo==0||s->ahcalgo==1)||s->ahcalgo==2)||s->ahcalgo==3, "ClusterizerRunAHC: internal error", _state); - for(i=0; i<=npoints-1; i++) - { - if( i!=c0&&i!=c1 ) - { - if( s->ahcalgo==0 ) - { - d->ptr.pp_double[i][c0] = ae_maxreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); - } - if( s->ahcalgo==1 ) - { - d->ptr.pp_double[i][c0] = ae_minreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); - } - if( s->ahcalgo==2 ) - { - d->ptr.pp_double[i][c0] = (csizes.ptr.p_int[c0]*d->ptr.pp_double[i][c0]+csizes.ptr.p_int[c1]*d->ptr.pp_double[i][c1])/(csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]); - } - if( s->ahcalgo==3 ) - { - d->ptr.pp_double[i][c0] = (d->ptr.pp_double[i][c0]+d->ptr.pp_double[i][c1])/2; - } - d->ptr.pp_double[c0][i] = d->ptr.pp_double[i][c0]; - } - } - - /* - * Update CIdx and CSizes - */ - cidx.ptr.p_int[c0] = npoints+mergeidx; - cidx.ptr.p_int[c1] = -1; - csizes.ptr.p_int[c0] = csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]; - csizes.ptr.p_int[c1] = 0; - - /* - * Update nearest neighbors array: - * * update nearest neighbors of everything except for C0/C1 - * * update neighbors of C0/C1 - */ - for(i=0; i<=npoints-1; i++) - { - if( (cidx.ptr.p_int[i]>=0&&i!=c0)&&(nnidx.ptr.p_int[i]==c0||nnidx.ptr.p_int[i]==c1) ) - { - - /* - * I-th cluster which is distinct from C0/C1 has former C0/C1 cluster as its nearest - * neighbor. We handle this issue depending on specific AHC algorithm being used. - */ - if( s->ahcalgo==1 ) - { - - /* - * Single linkage. Merging of two clusters together - * does NOT change distances between new cluster and - * other clusters. - * - * The only thing we have to do is to update nearest neighbor index - */ - nnidx.ptr.p_int[i] = c0; - } - else - { - - /* - * Something other than single linkage. We have to re-examine - * all the row to find nearest neighbor. - */ - k = -1; - v = ae_maxrealnumber; - for(j=0; j<=npoints-1; j++) - { - if( (cidx.ptr.p_int[j]>=0&&j!=i)&&ae_fp_less(d->ptr.pp_double[i][j],v) ) - { - k = j; - v = d->ptr.pp_double[i][j]; - } - } - ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); - nnidx.ptr.p_int[i] = k; - } - } - } - k = -1; - v = ae_maxrealnumber; - for(j=0; j<=npoints-1; j++) - { - if( (cidx.ptr.p_int[j]>=0&&j!=c0)&&ae_fp_less(d->ptr.pp_double[c0][j],v) ) - { - k = j; - v = d->ptr.pp_double[c0][j]; - } - } - ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); - nnidx.ptr.p_int[c0] = k; - } - - /* - * Calculate Rep.P and Rep.PM. - * - * In order to do that, we fill CInfo matrix - (2*NPoints-1)*3 matrix, - * with I-th row containing: - * * CInfo[I,0] - size of I-th cluster - * * CInfo[I,1] - beginning of I-th cluster - * * CInfo[I,2] - end of I-th cluster - * * CInfo[I,3] - height of I-th cluster - * - * We perform it as follows: - * * first NPoints clusters have unit size (CInfo[I,0]=1) and zero - * height (CInfo[I,3]=0) - * * we replay NPoints-1 merges from first to last and fill sizes of - * corresponding clusters (new size is a sum of sizes of clusters - * being merged) and height (new height is max(heights)+1). - * * now we ready to determine locations of clusters. Last cluster - * spans entire dataset, we know it. We replay merges from last to - * first, during each merge we already know location of the merge - * result, and we can position first cluster to the left part of - * the result, and second cluster to the right part. - */ - ae_vector_set_length(&rep->p, npoints, _state); - ae_matrix_set_length(&rep->pm, npoints-1, 6, _state); - ae_matrix_set_length(&cinfo, 2*npoints-1, 4, _state); - for(i=0; i<=npoints-1; i++) - { - cinfo.ptr.pp_int[i][0] = 1; - cinfo.ptr.pp_int[i][3] = 0; - } - for(i=0; i<=npoints-2; i++) - { - cinfo.ptr.pp_int[npoints+i][0] = cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][0]+cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][0]; - cinfo.ptr.pp_int[npoints+i][3] = ae_maxint(cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][3], cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][3], _state)+1; - } - cinfo.ptr.pp_int[2*npoints-2][1] = 0; - cinfo.ptr.pp_int[2*npoints-2][2] = npoints-1; - for(i=npoints-2; i>=0; i--) - { - - /* - * We merge C0 which spans [A0,B0] and C1 (spans [A1,B1]), - * with unknown A0, B0, A1, B1. However, we know that result - * is CR, which spans [AR,BR] with known AR/BR, and we know - * sizes of C0, C1, CR (denotes as S0, S1, SR). - */ - c0 = rep->z.ptr.pp_int[i][0]; - c1 = rep->z.ptr.pp_int[i][1]; - s0 = cinfo.ptr.pp_int[c0][0]; - s1 = cinfo.ptr.pp_int[c1][0]; - ar = cinfo.ptr.pp_int[npoints+i][1]; - br = cinfo.ptr.pp_int[npoints+i][2]; - cinfo.ptr.pp_int[c0][1] = ar; - cinfo.ptr.pp_int[c0][2] = ar+s0-1; - cinfo.ptr.pp_int[c1][1] = br-(s1-1); - cinfo.ptr.pp_int[c1][2] = br; - rep->pm.ptr.pp_int[i][0] = cinfo.ptr.pp_int[c0][1]; - rep->pm.ptr.pp_int[i][1] = cinfo.ptr.pp_int[c0][2]; - rep->pm.ptr.pp_int[i][2] = cinfo.ptr.pp_int[c1][1]; - rep->pm.ptr.pp_int[i][3] = cinfo.ptr.pp_int[c1][2]; - rep->pm.ptr.pp_int[i][4] = cinfo.ptr.pp_int[c0][3]; - rep->pm.ptr.pp_int[i][5] = cinfo.ptr.pp_int[c1][3]; - } - for(i=0; i<=npoints-1; i++) - { - ae_assert(cinfo.ptr.pp_int[i][1]==cinfo.ptr.pp_int[i][2], "Assertion failed", _state); - rep->p.ptr.p_int[i] = cinfo.ptr.pp_int[i][1]; - } - - /* - * Calculate Rep.PZ - */ - ae_matrix_set_length(&rep->pz, npoints-1, 2, _state); - for(i=0; i<=npoints-2; i++) - { - rep->pz.ptr.pp_int[i][0] = rep->z.ptr.pp_int[i][0]; - rep->pz.ptr.pp_int[i][1] = rep->z.ptr.pp_int[i][1]; - if( rep->pz.ptr.pp_int[i][0]pz.ptr.pp_int[i][0] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][0]]; - } - if( rep->pz.ptr.pp_int[i][1]pz.ptr.pp_int[i][1] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][1]]; - } - } - ae_frame_leave(_state); -} - - -static void clustering_evaluatedistancematrixrec(/* Real */ ae_matrix* xy, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, - ae_int_t i0, - ae_int_t i1, - ae_int_t j0, - ae_int_t j1, - ae_state *_state) -{ - double rcomplexity; - ae_int_t len0; - ae_int_t len1; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - double vv; - - - ae_assert(disttype==0||disttype==1, "EvaluateDistanceMatrixRec: incorrect DistType", _state); - - /* - * Normalize J0/J1: - * * J0:=max(J0,I0) - we ignore lower triangle - * * J1:=max(J1,J0) - normalize J1 - */ - j0 = ae_maxint(j0, i0, _state); - j1 = ae_maxint(j1, j0, _state); - if( j1<=j0||i1<=i0 ) - { - return; - } - - /* - * Try to process in parallel. Two condtions must hold in order to - * activate parallel processing: - * 1. I1-I0>2 or J1-J0>2 - * 2. (I1-I0)*(J1-J0)*NFeatures>=ParallelComplexity - * - * NOTE: all quantities are converted to reals in order to avoid - * integer overflow during multiplication - * - * NOTE: strict inequality in (1) is necessary to reduce task to 2x2 - * basecases. In future versions we will be able to handle such - * basecases more efficiently than 1x1 cases. - */ - rcomplexity = i1-i0; - rcomplexity = rcomplexity*(j1-j0); - rcomplexity = rcomplexity*nfeatures; - if( ae_fp_greater_eq(rcomplexity,clustering_parallelcomplexity)&&(i1-i0>2||j1-j0>2) ) - { - - /* - * Recursive division along largest of dimensions - */ - if( i1-i0>j1-j0 ) - { - splitlengtheven(i1-i0, &len0, &len1, _state); - clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i0+len0, j0, j1, _state); - clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0+len0, i1, j0, j1, _state); - } - else - { - splitlengtheven(j1-j0, &len0, &len1, _state); - clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0, j0+len0, _state); - clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0+len0, j1, _state); - } - return; - } - - /* - * Sequential processing - */ - for(i=i0; i<=i1-1; i++) - { - for(j=j0; j<=j1-1; j++) - { - if( j>=i ) - { - v = 0.0; - if( disttype==0 ) - { - for(k=0; k<=nfeatures-1; k++) - { - vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; - if( ae_fp_less(vv,0) ) - { - vv = -vv; - } - if( ae_fp_greater(vv,v) ) - { - v = vv; - } - } - } - if( disttype==1 ) - { - for(k=0; k<=nfeatures-1; k++) - { - vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; - if( ae_fp_less(vv,0) ) - { - vv = -vv; - } - v = v+vv; - } - } - d->ptr.pp_double[i][j] = v; - } - } - } -} - - -ae_bool _clusterizerstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - clusterizerstate *p = (clusterizerstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->d, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _clusterizerstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - clusterizerstate *dst = (clusterizerstate*)_dst; - clusterizerstate *src = (clusterizerstate*)_src; - dst->npoints = src->npoints; - dst->nfeatures = src->nfeatures; - dst->disttype = src->disttype; - if( !ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - dst->ahcalgo = src->ahcalgo; - dst->kmeansrestarts = src->kmeansrestarts; - dst->kmeansmaxits = src->kmeansmaxits; - return ae_true; -} - - -void _clusterizerstate_clear(void* _p) -{ - clusterizerstate *p = (clusterizerstate*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->xy); - ae_matrix_clear(&p->d); -} - - -void _clusterizerstate_destroy(void* _p) -{ - clusterizerstate *p = (clusterizerstate*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->xy); - ae_matrix_destroy(&p->d); -} - - -ae_bool _ahcreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - ahcreport *p = (ahcreport*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->p, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->z, 0, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->pz, 0, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->pm, 0, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mergedist, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _ahcreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - ahcreport *dst = (ahcreport*)_dst; - ahcreport *src = (ahcreport*)_src; - dst->npoints = src->npoints; - if( !ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->z, &src->z, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->pz, &src->pz, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->pm, &src->pm, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mergedist, &src->mergedist, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _ahcreport_clear(void* _p) -{ - ahcreport *p = (ahcreport*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->p); - ae_matrix_clear(&p->z); - ae_matrix_clear(&p->pz); - ae_matrix_clear(&p->pm); - ae_vector_clear(&p->mergedist); -} - - -void _ahcreport_destroy(void* _p) -{ - ahcreport *p = (ahcreport*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->p); - ae_matrix_destroy(&p->z); - ae_matrix_destroy(&p->pz); - ae_matrix_destroy(&p->pm); - ae_vector_destroy(&p->mergedist); -} - - -ae_bool _kmeansreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - kmeansreport *p = (kmeansreport*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cidx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _kmeansreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - kmeansreport *dst = (kmeansreport*)_dst; - kmeansreport *src = (kmeansreport*)_src; - dst->npoints = src->npoints; - dst->nfeatures = src->nfeatures; - dst->terminationtype = src->terminationtype; - dst->k = src->k; - if( !ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cidx, &src->cidx, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _kmeansreport_clear(void* _p) -{ - kmeansreport *p = (kmeansreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->c); - ae_vector_clear(&p->cidx); -} - - -void _kmeansreport_destroy(void* _p) -{ - kmeansreport *p = (kmeansreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->c); - ae_vector_destroy(&p->cidx); -} - - - - -/************************************************************************* -k-means++ clusterization. -Backward compatibility function, we recommend to use CLUSTERING subpackage -as better replacement. - - -- ALGLIB -- - Copyright 21.03.2009 by Bochkanov Sergey -*************************************************************************/ -void kmeansgenerate(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t k, - ae_int_t restarts, - ae_int_t* info, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* xyc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix dummy; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_matrix_clear(c); - ae_vector_clear(xyc); - ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); - - kmeansgenerateinternal(xy, npoints, nvars, k, 0, restarts, info, c, ae_true, &dummy, ae_false, xyc, _state); - ae_frame_leave(_state); -} - - - - -/************************************************************************* -This subroutine builds random decision forest. - -INPUT PARAMETERS: - XY - training set - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforest(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - double r, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state) -{ - ae_int_t samplesize; - - *info = 0; - _decisionforest_clear(df); - _dfreport_clear(rep); - - if( ae_fp_less_eq(r,0)||ae_fp_greater(r,1) ) - { - *info = -1; - return; - } - samplesize = ae_maxint(ae_round(r*npoints, _state), 1, _state); - dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, ae_maxint(nvars/2, 1, _state), dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); -} - - -/************************************************************************* -This subroutine builds random decision forest. -This function gives ability to tune number of variables used when choosing -best split. - -INPUT PARAMETERS: - XY - training set - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - NRndVars - number of variables used when choosing best split - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforestx1(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - ae_int_t nrndvars, - double r, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state) -{ - ae_int_t samplesize; - - *info = 0; - _decisionforest_clear(df); - _dfreport_clear(rep); - - if( ae_fp_less_eq(r,0)||ae_fp_greater(r,1) ) - { - *info = -1; - return; - } - if( nrndvars<=0||nrndvars>nvars ) - { - *info = -1; - return; - } - samplesize = ae_maxint(ae_round(r*npoints, _state), 1, _state); - dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, nrndvars, dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); -} - - -void dfbuildinternal(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - ae_int_t samplesize, - ae_int_t nfeatures, - ae_int_t flags, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t tmpi; - ae_int_t lasttreeoffs; - ae_int_t offs; - ae_int_t ooboffs; - ae_int_t treesize; - ae_int_t nvarsinpool; - ae_bool useevs; - dfinternalbuffers bufs; - ae_vector permbuf; - ae_vector oobbuf; - ae_vector oobcntbuf; - ae_matrix xys; - ae_vector x; - ae_vector y; - ae_int_t oobcnt; - ae_int_t oobrelcnt; - double v; - double vmin; - double vmax; - ae_bool bflag; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _decisionforest_clear(df); - _dfreport_clear(rep); - _dfinternalbuffers_init(&bufs, _state, ae_true); - ae_vector_init(&permbuf, 0, DT_INT, _state, ae_true); - ae_vector_init(&oobbuf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&oobcntbuf, 0, DT_INT, _state, ae_true); - ae_matrix_init(&xys, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&rs, _state, ae_true); - - - /* - * Test for inputs - */ - if( (((((npoints<1||samplesize<1)||samplesize>npoints)||nvars<1)||nclasses<1)||ntrees<1)||nfeatures<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( nclasses>1 ) - { - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - *info = 1; - - /* - * Flags - */ - useevs = flags/dforest_dfuseevs%2!=0; - - /* - * Allocate data, prepare header - */ - treesize = 1+dforest_innernodewidth*(samplesize-1)+dforest_leafnodewidth*samplesize; - ae_vector_set_length(&permbuf, npoints-1+1, _state); - ae_vector_set_length(&bufs.treebuf, treesize-1+1, _state); - ae_vector_set_length(&bufs.idxbuf, npoints-1+1, _state); - ae_vector_set_length(&bufs.tmpbufr, npoints-1+1, _state); - ae_vector_set_length(&bufs.tmpbufr2, npoints-1+1, _state); - ae_vector_set_length(&bufs.tmpbufi, npoints-1+1, _state); - ae_vector_set_length(&bufs.sortrbuf, npoints, _state); - ae_vector_set_length(&bufs.sortrbuf2, npoints, _state); - ae_vector_set_length(&bufs.sortibuf, npoints, _state); - ae_vector_set_length(&bufs.varpool, nvars-1+1, _state); - ae_vector_set_length(&bufs.evsbin, nvars-1+1, _state); - ae_vector_set_length(&bufs.evssplits, nvars-1+1, _state); - ae_vector_set_length(&bufs.classibuf, 2*nclasses-1+1, _state); - ae_vector_set_length(&oobbuf, nclasses*npoints-1+1, _state); - ae_vector_set_length(&oobcntbuf, npoints-1+1, _state); - ae_vector_set_length(&df->trees, ntrees*treesize-1+1, _state); - ae_matrix_set_length(&xys, samplesize-1+1, nvars+1, _state); - ae_vector_set_length(&x, nvars-1+1, _state); - ae_vector_set_length(&y, nclasses-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - permbuf.ptr.p_int[i] = i; - } - for(i=0; i<=npoints*nclasses-1; i++) - { - oobbuf.ptr.p_double[i] = 0; - } - for(i=0; i<=npoints-1; i++) - { - oobcntbuf.ptr.p_int[i] = 0; - } - - /* - * Prepare variable pool and EVS (extended variable selection/splitting) buffers - * (whether EVS is turned on or not): - * 1. detect binary variables and pre-calculate splits for them - * 2. detect variables with non-distinct values and exclude them from pool - */ - for(i=0; i<=nvars-1; i++) - { - bufs.varpool.ptr.p_int[i] = i; - } - nvarsinpool = nvars; - if( useevs ) - { - for(j=0; j<=nvars-1; j++) - { - vmin = xy->ptr.pp_double[0][j]; - vmax = vmin; - for(i=0; i<=npoints-1; i++) - { - v = xy->ptr.pp_double[i][j]; - vmin = ae_minreal(vmin, v, _state); - vmax = ae_maxreal(vmax, v, _state); - } - if( ae_fp_eq(vmin,vmax) ) - { - - /* - * exclude variable from pool - */ - bufs.varpool.ptr.p_int[j] = bufs.varpool.ptr.p_int[nvarsinpool-1]; - bufs.varpool.ptr.p_int[nvarsinpool-1] = -1; - nvarsinpool = nvarsinpool-1; - continue; - } - bflag = ae_false; - for(i=0; i<=npoints-1; i++) - { - v = xy->ptr.pp_double[i][j]; - if( ae_fp_neq(v,vmin)&&ae_fp_neq(v,vmax) ) - { - bflag = ae_true; - break; - } - } - if( bflag ) - { - - /* - * non-binary variable - */ - bufs.evsbin.ptr.p_bool[j] = ae_false; - } - else - { - - /* - * Prepare - */ - bufs.evsbin.ptr.p_bool[j] = ae_true; - bufs.evssplits.ptr.p_double[j] = 0.5*(vmin+vmax); - if( ae_fp_less_eq(bufs.evssplits.ptr.p_double[j],vmin) ) - { - bufs.evssplits.ptr.p_double[j] = vmax; - } - } - } - } - - /* - * RANDOM FOREST FORMAT - * W[0] - size of array - * W[1] - version number - * W[2] - NVars - * W[3] - NClasses (1 for regression) - * W[4] - NTrees - * W[5] - trees offset - * - * - * TREE FORMAT - * W[Offs] - size of sub-array - * node info: - * W[K+0] - variable number (-1 for leaf mode) - * W[K+1] - threshold (class/value for leaf node) - * W[K+2] - ">=" branch index (absent for leaf node) - * - */ - df->nvars = nvars; - df->nclasses = nclasses; - df->ntrees = ntrees; - - /* - * Build forest - */ - hqrndrandomize(&rs, _state); - offs = 0; - for(i=0; i<=ntrees-1; i++) - { - - /* - * Prepare sample - */ - for(k=0; k<=samplesize-1; k++) - { - j = k+hqrnduniformi(&rs, npoints-k, _state); - tmpi = permbuf.ptr.p_int[k]; - permbuf.ptr.p_int[k] = permbuf.ptr.p_int[j]; - permbuf.ptr.p_int[j] = tmpi; - j = permbuf.ptr.p_int[k]; - ae_v_move(&xys.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars)); - } - - /* - * build tree, copy - */ - dforest_dfbuildtree(&xys, samplesize, nvars, nclasses, nfeatures, nvarsinpool, flags, &bufs, &rs, _state); - j = ae_round(bufs.treebuf.ptr.p_double[0], _state); - ae_v_move(&df->trees.ptr.p_double[offs], 1, &bufs.treebuf.ptr.p_double[0], 1, ae_v_len(offs,offs+j-1)); - lasttreeoffs = offs; - offs = offs+j; - - /* - * OOB estimates - */ - for(k=samplesize; k<=npoints-1; k++) - { - for(j=0; j<=nclasses-1; j++) - { - y.ptr.p_double[j] = 0; - } - j = permbuf.ptr.p_int[k]; - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - dforest_dfprocessinternal(df, lasttreeoffs, &x, &y, _state); - ae_v_add(&oobbuf.ptr.p_double[j*nclasses], 1, &y.ptr.p_double[0], 1, ae_v_len(j*nclasses,(j+1)*nclasses-1)); - oobcntbuf.ptr.p_int[j] = oobcntbuf.ptr.p_int[j]+1; - } - } - df->bufsize = offs; - - /* - * Normalize OOB results - */ - for(i=0; i<=npoints-1; i++) - { - if( oobcntbuf.ptr.p_int[i]!=0 ) - { - v = (double)1/(double)oobcntbuf.ptr.p_int[i]; - ae_v_muld(&oobbuf.ptr.p_double[i*nclasses], 1, ae_v_len(i*nclasses,i*nclasses+nclasses-1), v); - } - } - - /* - * Calculate training set estimates - */ - rep->relclserror = dfrelclserror(df, xy, npoints, _state); - rep->avgce = dfavgce(df, xy, npoints, _state); - rep->rmserror = dfrmserror(df, xy, npoints, _state); - rep->avgerror = dfavgerror(df, xy, npoints, _state); - rep->avgrelerror = dfavgrelerror(df, xy, npoints, _state); - - /* - * Calculate OOB estimates. - */ - rep->oobrelclserror = 0; - rep->oobavgce = 0; - rep->oobrmserror = 0; - rep->oobavgerror = 0; - rep->oobavgrelerror = 0; - oobcnt = 0; - oobrelcnt = 0; - for(i=0; i<=npoints-1; i++) - { - if( oobcntbuf.ptr.p_int[i]!=0 ) - { - ooboffs = i*nclasses; - if( nclasses>1 ) - { - - /* - * classification-specific code - */ - k = ae_round(xy->ptr.pp_double[i][nvars], _state); - tmpi = 0; - for(j=1; j<=nclasses-1; j++) - { - if( ae_fp_greater(oobbuf.ptr.p_double[ooboffs+j],oobbuf.ptr.p_double[ooboffs+tmpi]) ) - { - tmpi = j; - } - } - if( tmpi!=k ) - { - rep->oobrelclserror = rep->oobrelclserror+1; - } - if( ae_fp_neq(oobbuf.ptr.p_double[ooboffs+k],0) ) - { - rep->oobavgce = rep->oobavgce-ae_log(oobbuf.ptr.p_double[ooboffs+k], _state); - } - else - { - rep->oobavgce = rep->oobavgce-ae_log(ae_minrealnumber, _state); - } - for(j=0; j<=nclasses-1; j++) - { - if( j==k ) - { - rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs+j]-1, _state); - rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j]-1, _state); - rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j]-1, _state); - oobrelcnt = oobrelcnt+1; - } - else - { - rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs+j], _state); - rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs+j], _state); - } - } - } - else - { - - /* - * regression-specific code - */ - rep->oobrmserror = rep->oobrmserror+ae_sqr(oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars], _state); - rep->oobavgerror = rep->oobavgerror+ae_fabs(oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars], _state); - if( ae_fp_neq(xy->ptr.pp_double[i][nvars],0) ) - { - rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs((oobbuf.ptr.p_double[ooboffs]-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); - oobrelcnt = oobrelcnt+1; - } - } - - /* - * update OOB estimates count. - */ - oobcnt = oobcnt+1; - } - } - if( oobcnt>0 ) - { - rep->oobrelclserror = rep->oobrelclserror/oobcnt; - rep->oobavgce = rep->oobavgce/oobcnt; - rep->oobrmserror = ae_sqrt(rep->oobrmserror/(oobcnt*nclasses), _state); - rep->oobavgerror = rep->oobavgerror/(oobcnt*nclasses); - if( oobrelcnt>0 ) - { - rep->oobavgrelerror = rep->oobavgrelerror/oobrelcnt; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - DF - decision forest model - X - input vector, array[0..NVars-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also DFProcessI. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfprocess(decisionforest* df, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t offs; - ae_int_t i; - double v; - - - - /* - * Proceed - */ - if( y->cntnclasses ) - { - ae_vector_set_length(y, df->nclasses, _state); - } - offs = 0; - for(i=0; i<=df->nclasses-1; i++) - { - y->ptr.p_double[i] = 0; - } - for(i=0; i<=df->ntrees-1; i++) - { - - /* - * Process basic tree - */ - dforest_dfprocessinternal(df, offs, x, y, _state); - - /* - * Next tree - */ - offs = offs+ae_round(df->trees.ptr.p_double[offs], _state); - } - v = (double)1/(double)df->ntrees; - ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,df->nclasses-1), v); -} - - -/************************************************************************* -'interactive' variant of DFProcess for languages like Python which support -constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void dfprocessi(decisionforest* df, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - ae_vector_clear(y); - - dfprocess(df, x, y, _state); -} - - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrelclserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - result = (double)dforest_dfclserror(df, xy, npoints, _state)/(double)npoints; - return result; -} - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgce(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t tmpi; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&x, df->nvars-1+1, _state); - ae_vector_set_length(&y, df->nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); - dfprocess(df, &x, &y, _state); - if( df->nclasses>1 ) - { - - /* - * classification-specific code - */ - k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); - tmpi = 0; - for(j=1; j<=df->nclasses-1; j++) - { - if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) - { - tmpi = j; - } - } - if( ae_fp_neq(y.ptr.p_double[k],0) ) - { - result = result-ae_log(y.ptr.p_double[k], _state); - } - else - { - result = result-ae_log(ae_minrealnumber, _state); - } - } - } - result = result/npoints; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for - classification task, RMS error means error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrmserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t tmpi; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&x, df->nvars-1+1, _state); - ae_vector_set_length(&y, df->nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); - dfprocess(df, &x, &y, _state); - if( df->nclasses>1 ) - { - - /* - * classification-specific code - */ - k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); - tmpi = 0; - for(j=1; j<=df->nclasses-1; j++) - { - if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) - { - tmpi = j; - } - } - for(j=0; j<=df->nclasses-1; j++) - { - if( j==k ) - { - result = result+ae_sqr(y.ptr.p_double[j]-1, _state); - } - else - { - result = result+ae_sqr(y.ptr.p_double[j], _state); - } - } - } - else - { - - /* - * regression-specific code - */ - result = result+ae_sqr(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); - } - } - result = ae_sqrt(result/(npoints*df->nclasses), _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgerror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&x, df->nvars-1+1, _state); - ae_vector_set_length(&y, df->nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); - dfprocess(df, &x, &y, _state); - if( df->nclasses>1 ) - { - - /* - * classification-specific code - */ - k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); - for(j=0; j<=df->nclasses-1; j++) - { - if( j==k ) - { - result = result+ae_fabs(y.ptr.p_double[j]-1, _state); - } - else - { - result = result+ae_fabs(y.ptr.p_double[j], _state); - } - } - } - else - { - - /* - * regression-specific code - */ - result = result+ae_fabs(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); - } - } - result = result/(npoints*df->nclasses); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average relative error when estimating - posterior probability of belonging to the correct class. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgrelerror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_int_t relcnt; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&x, df->nvars-1+1, _state); - ae_vector_set_length(&y, df->nclasses-1+1, _state); - result = 0; - relcnt = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); - dfprocess(df, &x, &y, _state); - if( df->nclasses>1 ) - { - - /* - * classification-specific code - */ - k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); - for(j=0; j<=df->nclasses-1; j++) - { - if( j==k ) - { - result = result+ae_fabs(y.ptr.p_double[j]-1, _state); - relcnt = relcnt+1; - } - } - } - else - { - - /* - * regression-specific code - */ - if( ae_fp_neq(xy->ptr.pp_double[i][df->nvars],0) ) - { - result = result+ae_fabs((y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars])/xy->ptr.pp_double[i][df->nvars], _state); - relcnt = relcnt+1; - } - } - } - if( relcnt>0 ) - { - result = result/relcnt; - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Copying of DecisionForest strucure - -INPUT PARAMETERS: - DF1 - original - -OUTPUT PARAMETERS: - DF2 - copy - - -- ALGLIB -- - Copyright 13.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfcopy(decisionforest* df1, decisionforest* df2, ae_state *_state) -{ - - _decisionforest_clear(df2); - - df2->nvars = df1->nvars; - df2->nclasses = df1->nclasses; - df2->ntrees = df1->ntrees; - df2->bufsize = df1->bufsize; - ae_vector_set_length(&df2->trees, df1->bufsize-1+1, _state); - ae_v_move(&df2->trees.ptr.p_double[0], 1, &df1->trees.ptr.p_double[0], 1, ae_v_len(0,df1->bufsize-1)); -} - - -/************************************************************************* -Serializer: allocation - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void dfalloc(ae_serializer* s, decisionforest* forest, ae_state *_state) -{ - - - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - allocrealarray(s, &forest->trees, forest->bufsize, _state); -} - - -/************************************************************************* -Serializer: serialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void dfserialize(ae_serializer* s, - decisionforest* forest, - ae_state *_state) -{ - - - ae_serializer_serialize_int(s, getrdfserializationcode(_state), _state); - ae_serializer_serialize_int(s, dforest_dffirstversion, _state); - ae_serializer_serialize_int(s, forest->nvars, _state); - ae_serializer_serialize_int(s, forest->nclasses, _state); - ae_serializer_serialize_int(s, forest->ntrees, _state); - ae_serializer_serialize_int(s, forest->bufsize, _state); - serializerealarray(s, &forest->trees, forest->bufsize, _state); -} - - -/************************************************************************* -Serializer: unserialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void dfunserialize(ae_serializer* s, - decisionforest* forest, - ae_state *_state) -{ - ae_int_t i0; - ae_int_t i1; - - _decisionforest_clear(forest); - - - /* - * check correctness of header - */ - ae_serializer_unserialize_int(s, &i0, _state); - ae_assert(i0==getrdfserializationcode(_state), "DFUnserialize: stream header corrupted", _state); - ae_serializer_unserialize_int(s, &i1, _state); - ae_assert(i1==dforest_dffirstversion, "DFUnserialize: stream header corrupted", _state); - - /* - * Unserialize data - */ - ae_serializer_unserialize_int(s, &forest->nvars, _state); - ae_serializer_unserialize_int(s, &forest->nclasses, _state); - ae_serializer_unserialize_int(s, &forest->ntrees, _state); - ae_serializer_unserialize_int(s, &forest->bufsize, _state); - unserializerealarray(s, &forest->trees, _state); -} - - -/************************************************************************* -Classification error -*************************************************************************/ -static ae_int_t dforest_dfclserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t tmpi; - ae_int_t result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - if( df->nclasses<=1 ) - { - result = 0; - ae_frame_leave(_state); - return result; - } - ae_vector_set_length(&x, df->nvars-1+1, _state); - ae_vector_set_length(&y, df->nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); - dfprocess(df, &x, &y, _state); - k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); - tmpi = 0; - for(j=1; j<=df->nclasses-1; j++) - { - if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) - { - tmpi = j; - } - } - if( tmpi!=k ) - { - result = result+1; - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Internal subroutine for processing one decision tree starting at Offs -*************************************************************************/ -static void dforest_dfprocessinternal(decisionforest* df, - ae_int_t offs, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t k; - ae_int_t idx; - - - - /* - * Set pointer to the root - */ - k = offs+1; - - /* - * Navigate through the tree - */ - for(;;) - { - if( ae_fp_eq(df->trees.ptr.p_double[k],-1) ) - { - if( df->nclasses==1 ) - { - y->ptr.p_double[0] = y->ptr.p_double[0]+df->trees.ptr.p_double[k+1]; - } - else - { - idx = ae_round(df->trees.ptr.p_double[k+1], _state); - y->ptr.p_double[idx] = y->ptr.p_double[idx]+1; - } - break; - } - if( ae_fp_less(x->ptr.p_double[ae_round(df->trees.ptr.p_double[k], _state)],df->trees.ptr.p_double[k+1]) ) - { - k = k+dforest_innernodewidth; - } - else - { - k = offs+ae_round(df->trees.ptr.p_double[k+2], _state); - } - } -} - - -/************************************************************************* -Builds one decision tree. Just a wrapper for the DFBuildTreeRec. -*************************************************************************/ -static void dforest_dfbuildtree(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t nfeatures, - ae_int_t nvarsinpool, - ae_int_t flags, - dfinternalbuffers* bufs, - hqrndstate* rs, - ae_state *_state) -{ - ae_int_t numprocessed; - ae_int_t i; - - - ae_assert(npoints>0, "Assertion failed", _state); - - /* - * Prepare IdxBuf. It stores indices of the training set elements. - * When training set is being split, contents of IdxBuf is - * correspondingly reordered so we can know which elements belong - * to which branch of decision tree. - */ - for(i=0; i<=npoints-1; i++) - { - bufs->idxbuf.ptr.p_int[i] = i; - } - - /* - * Recursive procedure - */ - numprocessed = 1; - dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, &numprocessed, 0, npoints-1, bufs, rs, _state); - bufs->treebuf.ptr.p_double[0] = numprocessed; -} - - -/************************************************************************* -Builds one decision tree (internal recursive subroutine) - -Parameters: - TreeBuf - large enough array, at least TreeSize - IdxBuf - at least NPoints elements - TmpBufR - at least NPoints - TmpBufR2 - at least NPoints - TmpBufI - at least NPoints - TmpBufI2 - at least NPoints+1 -*************************************************************************/ -static void dforest_dfbuildtreerec(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t nfeatures, - ae_int_t nvarsinpool, - ae_int_t flags, - ae_int_t* numprocessed, - ae_int_t idx1, - ae_int_t idx2, - dfinternalbuffers* bufs, - hqrndstate* rs, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_bool bflag; - ae_int_t i1; - ae_int_t i2; - ae_int_t info; - double sl; - double sr; - double w; - ae_int_t idxbest; - double ebest; - double tbest; - ae_int_t varcur; - double s; - double v; - double v1; - double v2; - double threshold; - ae_int_t oldnp; - double currms; - ae_bool useevs; - - - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - tbest = 0; - - /* - * Prepare - */ - ae_assert(npoints>0, "Assertion failed", _state); - ae_assert(idx2>=idx1, "Assertion failed", _state); - useevs = flags/dforest_dfuseevs%2!=0; - - /* - * Leaf node - */ - if( idx2==idx1 ) - { - bufs->treebuf.ptr.p_double[*numprocessed] = -1; - bufs->treebuf.ptr.p_double[*numprocessed+1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[idx1]][nvars]; - *numprocessed = *numprocessed+dforest_leafnodewidth; - return; - } - - /* - * Non-leaf node. - * Select random variable, prepare split: - * 1. prepare default solution - no splitting, class at random - * 2. investigate possible splits, compare with default/best - */ - idxbest = -1; - if( nclasses>1 ) - { - - /* - * default solution for classification - */ - for(i=0; i<=nclasses-1; i++) - { - bufs->classibuf.ptr.p_int[i] = 0; - } - s = idx2-idx1+1; - for(i=idx1; i<=idx2; i++) - { - j = ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars], _state); - bufs->classibuf.ptr.p_int[j] = bufs->classibuf.ptr.p_int[j]+1; - } - ebest = 0; - for(i=0; i<=nclasses-1; i++) - { - ebest = ebest+bufs->classibuf.ptr.p_int[i]*ae_sqr(1-bufs->classibuf.ptr.p_int[i]/s, _state)+(s-bufs->classibuf.ptr.p_int[i])*ae_sqr(bufs->classibuf.ptr.p_int[i]/s, _state); - } - ebest = ae_sqrt(ebest/(nclasses*(idx2-idx1+1)), _state); - } - else - { - - /* - * default solution for regression - */ - v = 0; - for(i=idx1; i<=idx2; i++) - { - v = v+xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]; - } - v = v/(idx2-idx1+1); - ebest = 0; - for(i=idx1; i<=idx2; i++) - { - ebest = ebest+ae_sqr(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]-v, _state); - } - ebest = ae_sqrt(ebest/(idx2-idx1+1), _state); - } - i = 0; - while(i<=ae_minint(nfeatures, nvarsinpool, _state)-1) - { - - /* - * select variables from pool - */ - j = i+hqrnduniformi(rs, nvarsinpool-i, _state); - k = bufs->varpool.ptr.p_int[i]; - bufs->varpool.ptr.p_int[i] = bufs->varpool.ptr.p_int[j]; - bufs->varpool.ptr.p_int[j] = k; - varcur = bufs->varpool.ptr.p_int[i]; - - /* - * load variable values to working array - * - * apply EVS preprocessing: if all variable values are same, - * variable is excluded from pool. - * - * This is necessary for binary pre-splits (see later) to work. - */ - for(j=idx1; j<=idx2; j++) - { - bufs->tmpbufr.ptr.p_double[j-idx1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][varcur]; - } - if( useevs ) - { - bflag = ae_false; - v = bufs->tmpbufr.ptr.p_double[0]; - for(j=0; j<=idx2-idx1; j++) - { - if( ae_fp_neq(bufs->tmpbufr.ptr.p_double[j],v) ) - { - bflag = ae_true; - break; - } - } - if( !bflag ) - { - - /* - * exclude variable from pool, - * go to the next iteration. - * I is not increased. - */ - k = bufs->varpool.ptr.p_int[i]; - bufs->varpool.ptr.p_int[i] = bufs->varpool.ptr.p_int[nvarsinpool-1]; - bufs->varpool.ptr.p_int[nvarsinpool-1] = k; - nvarsinpool = nvarsinpool-1; - continue; - } - } - - /* - * load labels to working array - */ - if( nclasses>1 ) - { - for(j=idx1; j<=idx2; j++) - { - bufs->tmpbufi.ptr.p_int[j-idx1] = ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][nvars], _state); - } - } - else - { - for(j=idx1; j<=idx2; j++) - { - bufs->tmpbufr2.ptr.p_double[j-idx1] = xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[j]][nvars]; - } - } - - /* - * calculate split - */ - if( useevs&&bufs->evsbin.ptr.p_bool[varcur] ) - { - - /* - * Pre-calculated splits for binary variables. - * Threshold is already known, just calculate RMS error - */ - threshold = bufs->evssplits.ptr.p_double[varcur]; - if( nclasses>1 ) - { - - /* - * classification-specific code - */ - for(j=0; j<=2*nclasses-1; j++) - { - bufs->classibuf.ptr.p_int[j] = 0; - } - sl = 0; - sr = 0; - for(j=0; j<=idx2-idx1; j++) - { - k = bufs->tmpbufi.ptr.p_int[j]; - if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) - { - bufs->classibuf.ptr.p_int[k] = bufs->classibuf.ptr.p_int[k]+1; - sl = sl+1; - } - else - { - bufs->classibuf.ptr.p_int[k+nclasses] = bufs->classibuf.ptr.p_int[k+nclasses]+1; - sr = sr+1; - } - } - ae_assert(ae_fp_neq(sl,0)&&ae_fp_neq(sr,0), "DFBuildTreeRec: something strange!", _state); - currms = 0; - for(j=0; j<=nclasses-1; j++) - { - w = bufs->classibuf.ptr.p_int[j]; - currms = currms+w*ae_sqr(w/sl-1, _state); - currms = currms+(sl-w)*ae_sqr(w/sl, _state); - w = bufs->classibuf.ptr.p_int[nclasses+j]; - currms = currms+w*ae_sqr(w/sr-1, _state); - currms = currms+(sr-w)*ae_sqr(w/sr, _state); - } - currms = ae_sqrt(currms/(nclasses*(idx2-idx1+1)), _state); - } - else - { - - /* - * regression-specific code - */ - sl = 0; - sr = 0; - v1 = 0; - v2 = 0; - for(j=0; j<=idx2-idx1; j++) - { - if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) - { - v1 = v1+bufs->tmpbufr2.ptr.p_double[j]; - sl = sl+1; - } - else - { - v2 = v2+bufs->tmpbufr2.ptr.p_double[j]; - sr = sr+1; - } - } - ae_assert(ae_fp_neq(sl,0)&&ae_fp_neq(sr,0), "DFBuildTreeRec: something strange!", _state); - v1 = v1/sl; - v2 = v2/sr; - currms = 0; - for(j=0; j<=idx2-idx1; j++) - { - if( ae_fp_less(bufs->tmpbufr.ptr.p_double[j],threshold) ) - { - currms = currms+ae_sqr(v1-bufs->tmpbufr2.ptr.p_double[j], _state); - } - else - { - currms = currms+ae_sqr(v2-bufs->tmpbufr2.ptr.p_double[j], _state); - } - } - currms = ae_sqrt(currms/(idx2-idx1+1), _state); - } - info = 1; - } - else - { - - /* - * Generic splits - */ - if( nclasses>1 ) - { - dforest_dfsplitc(&bufs->tmpbufr, &bufs->tmpbufi, &bufs->classibuf, idx2-idx1+1, nclasses, dforest_dfusestrongsplits, &info, &threshold, &currms, &bufs->sortrbuf, &bufs->sortibuf, _state); - } - else - { - dforest_dfsplitr(&bufs->tmpbufr, &bufs->tmpbufr2, idx2-idx1+1, dforest_dfusestrongsplits, &info, &threshold, &currms, &bufs->sortrbuf, &bufs->sortrbuf2, _state); - } - } - if( info>0 ) - { - if( ae_fp_less_eq(currms,ebest) ) - { - ebest = currms; - idxbest = varcur; - tbest = threshold; - } - } - - /* - * Next iteration - */ - i = i+1; - } - - /* - * to split or not to split - */ - if( idxbest<0 ) - { - - /* - * All values are same, cannot split. - */ - bufs->treebuf.ptr.p_double[*numprocessed] = -1; - if( nclasses>1 ) - { - - /* - * Select random class label (randomness allows us to - * approximate distribution of the classes) - */ - bufs->treebuf.ptr.p_double[*numprocessed+1] = ae_round(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[idx1+hqrnduniformi(rs, idx2-idx1+1, _state)]][nvars], _state); - } - else - { - - /* - * Select average (for regression task). - */ - v = 0; - for(i=idx1; i<=idx2; i++) - { - v = v+xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i]][nvars]/(idx2-idx1+1); - } - bufs->treebuf.ptr.p_double[*numprocessed+1] = v; - } - *numprocessed = *numprocessed+dforest_leafnodewidth; - } - else - { - - /* - * we can split - */ - bufs->treebuf.ptr.p_double[*numprocessed] = idxbest; - bufs->treebuf.ptr.p_double[*numprocessed+1] = tbest; - i1 = idx1; - i2 = idx2; - while(i1<=i2) - { - - /* - * Reorder indices so that left partition is in [Idx1..I1-1], - * and right partition is in [I2+1..Idx2] - */ - if( ae_fp_less(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i1]][idxbest],tbest) ) - { - i1 = i1+1; - continue; - } - if( ae_fp_greater_eq(xy->ptr.pp_double[bufs->idxbuf.ptr.p_int[i2]][idxbest],tbest) ) - { - i2 = i2-1; - continue; - } - j = bufs->idxbuf.ptr.p_int[i1]; - bufs->idxbuf.ptr.p_int[i1] = bufs->idxbuf.ptr.p_int[i2]; - bufs->idxbuf.ptr.p_int[i2] = j; - i1 = i1+1; - i2 = i2-1; - } - oldnp = *numprocessed; - *numprocessed = *numprocessed+dforest_innernodewidth; - dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, numprocessed, idx1, i1-1, bufs, rs, _state); - bufs->treebuf.ptr.p_double[oldnp+2] = *numprocessed; - dforest_dfbuildtreerec(xy, npoints, nvars, nclasses, nfeatures, nvarsinpool, flags, numprocessed, i2+1, idx2, bufs, rs, _state); - } -} - - -/************************************************************************* -Makes split on attribute -*************************************************************************/ -static void dforest_dfsplitc(/* Real */ ae_vector* x, - /* Integer */ ae_vector* c, - /* Integer */ ae_vector* cntbuf, - ae_int_t n, - ae_int_t nc, - ae_int_t flags, - ae_int_t* info, - double* threshold, - double* e, - /* Real */ ae_vector* sortrbuf, - /* Integer */ ae_vector* sortibuf, - ae_state *_state) -{ - ae_int_t i; - ae_int_t neq; - ae_int_t nless; - ae_int_t ngreater; - ae_int_t q; - ae_int_t qmin; - ae_int_t qmax; - ae_int_t qcnt; - double cursplit; - ae_int_t nleft; - double v; - double cure; - double w; - double sl; - double sr; - - *info = 0; - *threshold = 0; - *e = 0; - - tagsortfasti(x, c, sortrbuf, sortibuf, n, _state); - *e = ae_maxrealnumber; - *threshold = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); - *info = -3; - if( flags/dforest_dfusestrongsplits%2==0 ) - { - - /* - * weak splits, split at half - */ - qcnt = 2; - qmin = 1; - qmax = 1; - } - else - { - - /* - * strong splits: choose best quartile - */ - qcnt = 4; - qmin = 1; - qmax = 3; - } - for(q=qmin; q<=qmax; q++) - { - cursplit = x->ptr.p_double[n*q/qcnt]; - neq = 0; - nless = 0; - ngreater = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_less(x->ptr.p_double[i],cursplit) ) - { - nless = nless+1; - } - if( ae_fp_eq(x->ptr.p_double[i],cursplit) ) - { - neq = neq+1; - } - if( ae_fp_greater(x->ptr.p_double[i],cursplit) ) - { - ngreater = ngreater+1; - } - } - ae_assert(neq!=0, "DFSplitR: NEq=0, something strange!!!", _state); - if( nless!=0||ngreater!=0 ) - { - - /* - * set threshold between two partitions, with - * some tweaking to avoid problems with floating point - * arithmetics. - * - * The problem is that when you calculates C = 0.5*(A+B) there - * can be no C which lies strictly between A and B (for example, - * there is no floating point number which is - * greater than 1 and less than 1+eps). In such situations - * we choose right side as threshold (remember that - * points which lie on threshold falls to the right side). - */ - if( nlessptr.p_double[nless+neq-1]+x->ptr.p_double[nless+neq]); - nleft = nless+neq; - if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless+neq-1]) ) - { - cursplit = x->ptr.p_double[nless+neq]; - } - } - else - { - cursplit = 0.5*(x->ptr.p_double[nless-1]+x->ptr.p_double[nless]); - nleft = nless; - if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless-1]) ) - { - cursplit = x->ptr.p_double[nless]; - } - } - *info = 1; - cure = 0; - for(i=0; i<=2*nc-1; i++) - { - cntbuf->ptr.p_int[i] = 0; - } - for(i=0; i<=nleft-1; i++) - { - cntbuf->ptr.p_int[c->ptr.p_int[i]] = cntbuf->ptr.p_int[c->ptr.p_int[i]]+1; - } - for(i=nleft; i<=n-1; i++) - { - cntbuf->ptr.p_int[nc+c->ptr.p_int[i]] = cntbuf->ptr.p_int[nc+c->ptr.p_int[i]]+1; - } - sl = nleft; - sr = n-nleft; - v = 0; - for(i=0; i<=nc-1; i++) - { - w = cntbuf->ptr.p_int[i]; - v = v+w*ae_sqr(w/sl-1, _state); - v = v+(sl-w)*ae_sqr(w/sl, _state); - w = cntbuf->ptr.p_int[nc+i]; - v = v+w*ae_sqr(w/sr-1, _state); - v = v+(sr-w)*ae_sqr(w/sr, _state); - } - cure = ae_sqrt(v/(nc*n), _state); - if( ae_fp_less(cure,*e) ) - { - *threshold = cursplit; - *e = cure; - } - } - } -} - - -/************************************************************************* -Makes split on attribute -*************************************************************************/ -static void dforest_dfsplitr(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t flags, - ae_int_t* info, - double* threshold, - double* e, - /* Real */ ae_vector* sortrbuf, - /* Real */ ae_vector* sortrbuf2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t neq; - ae_int_t nless; - ae_int_t ngreater; - ae_int_t q; - ae_int_t qmin; - ae_int_t qmax; - ae_int_t qcnt; - double cursplit; - ae_int_t nleft; - double v; - double cure; - - *info = 0; - *threshold = 0; - *e = 0; - - tagsortfastr(x, y, sortrbuf, sortrbuf2, n, _state); - *e = ae_maxrealnumber; - *threshold = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); - *info = -3; - if( flags/dforest_dfusestrongsplits%2==0 ) - { - - /* - * weak splits, split at half - */ - qcnt = 2; - qmin = 1; - qmax = 1; - } - else - { - - /* - * strong splits: choose best quartile - */ - qcnt = 4; - qmin = 1; - qmax = 3; - } - for(q=qmin; q<=qmax; q++) - { - cursplit = x->ptr.p_double[n*q/qcnt]; - neq = 0; - nless = 0; - ngreater = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_less(x->ptr.p_double[i],cursplit) ) - { - nless = nless+1; - } - if( ae_fp_eq(x->ptr.p_double[i],cursplit) ) - { - neq = neq+1; - } - if( ae_fp_greater(x->ptr.p_double[i],cursplit) ) - { - ngreater = ngreater+1; - } - } - ae_assert(neq!=0, "DFSplitR: NEq=0, something strange!!!", _state); - if( nless!=0||ngreater!=0 ) - { - - /* - * set threshold between two partitions, with - * some tweaking to avoid problems with floating point - * arithmetics. - * - * The problem is that when you calculates C = 0.5*(A+B) there - * can be no C which lies strictly between A and B (for example, - * there is no floating point number which is - * greater than 1 and less than 1+eps). In such situations - * we choose right side as threshold (remember that - * points which lie on threshold falls to the right side). - */ - if( nlessptr.p_double[nless+neq-1]+x->ptr.p_double[nless+neq]); - nleft = nless+neq; - if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless+neq-1]) ) - { - cursplit = x->ptr.p_double[nless+neq]; - } - } - else - { - cursplit = 0.5*(x->ptr.p_double[nless-1]+x->ptr.p_double[nless]); - nleft = nless; - if( ae_fp_less_eq(cursplit,x->ptr.p_double[nless-1]) ) - { - cursplit = x->ptr.p_double[nless]; - } - } - *info = 1; - cure = 0; - v = 0; - for(i=0; i<=nleft-1; i++) - { - v = v+y->ptr.p_double[i]; - } - v = v/nleft; - for(i=0; i<=nleft-1; i++) - { - cure = cure+ae_sqr(y->ptr.p_double[i]-v, _state); - } - v = 0; - for(i=nleft; i<=n-1; i++) - { - v = v+y->ptr.p_double[i]; - } - v = v/(n-nleft); - for(i=nleft; i<=n-1; i++) - { - cure = cure+ae_sqr(y->ptr.p_double[i]-v, _state); - } - cure = ae_sqrt(cure/n, _state); - if( ae_fp_less(cure,*e) ) - { - *threshold = cursplit; - *e = cure; - } - } - } -} - - -ae_bool _decisionforest_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - decisionforest *p = (decisionforest*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->trees, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _decisionforest_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - decisionforest *dst = (decisionforest*)_dst; - decisionforest *src = (decisionforest*)_src; - dst->nvars = src->nvars; - dst->nclasses = src->nclasses; - dst->ntrees = src->ntrees; - dst->bufsize = src->bufsize; - if( !ae_vector_init_copy(&dst->trees, &src->trees, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _decisionforest_clear(void* _p) -{ - decisionforest *p = (decisionforest*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->trees); -} - - -void _decisionforest_destroy(void* _p) -{ - decisionforest *p = (decisionforest*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->trees); -} - - -ae_bool _dfreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - dfreport *p = (dfreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _dfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - dfreport *dst = (dfreport*)_dst; - dfreport *src = (dfreport*)_src; - dst->relclserror = src->relclserror; - dst->avgce = src->avgce; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->oobrelclserror = src->oobrelclserror; - dst->oobavgce = src->oobavgce; - dst->oobrmserror = src->oobrmserror; - dst->oobavgerror = src->oobavgerror; - dst->oobavgrelerror = src->oobavgrelerror; - return ae_true; -} - - -void _dfreport_clear(void* _p) -{ - dfreport *p = (dfreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _dfreport_destroy(void* _p) -{ - dfreport *p = (dfreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _dfinternalbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - dfinternalbuffers *p = (dfinternalbuffers*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->treebuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->idxbuf, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpbufr, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpbufr2, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpbufi, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->classibuf, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->sortrbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->sortrbuf2, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->sortibuf, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->varpool, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->evsbin, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->evssplits, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _dfinternalbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - dfinternalbuffers *dst = (dfinternalbuffers*)_dst; - dfinternalbuffers *src = (dfinternalbuffers*)_src; - if( !ae_vector_init_copy(&dst->treebuf, &src->treebuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->idxbuf, &src->idxbuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpbufr, &src->tmpbufr, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpbufr2, &src->tmpbufr2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpbufi, &src->tmpbufi, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->classibuf, &src->classibuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->sortrbuf, &src->sortrbuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->sortrbuf2, &src->sortrbuf2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->sortibuf, &src->sortibuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->varpool, &src->varpool, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->evsbin, &src->evsbin, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->evssplits, &src->evssplits, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _dfinternalbuffers_clear(void* _p) -{ - dfinternalbuffers *p = (dfinternalbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->treebuf); - ae_vector_clear(&p->idxbuf); - ae_vector_clear(&p->tmpbufr); - ae_vector_clear(&p->tmpbufr2); - ae_vector_clear(&p->tmpbufi); - ae_vector_clear(&p->classibuf); - ae_vector_clear(&p->sortrbuf); - ae_vector_clear(&p->sortrbuf2); - ae_vector_clear(&p->sortibuf); - ae_vector_clear(&p->varpool); - ae_vector_clear(&p->evsbin); - ae_vector_clear(&p->evssplits); -} - - -void _dfinternalbuffers_destroy(void* _p) -{ - dfinternalbuffers *p = (dfinternalbuffers*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->treebuf); - ae_vector_destroy(&p->idxbuf); - ae_vector_destroy(&p->tmpbufr); - ae_vector_destroy(&p->tmpbufr2); - ae_vector_destroy(&p->tmpbufi); - ae_vector_destroy(&p->classibuf); - ae_vector_destroy(&p->sortrbuf); - ae_vector_destroy(&p->sortrbuf2); - ae_vector_destroy(&p->sortibuf); - ae_vector_destroy(&p->varpool); - ae_vector_destroy(&p->evsbin); - ae_vector_destroy(&p->evssplits); -} - - - - -/************************************************************************* -Linear regression - -Subroutine builds model: - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) - -and model found in ALGLIB format, covariation matrix, training set errors -(rms, average, average relative) and leave-one-out cross-validation -estimate of the generalization error. CV estimate calculated using fast -algorithm with O(NPoints*NVars) complexity. - -When covariation matrix is calculated standard deviations of function -values are assumed to be equal to RMS error on the training set. - -INPUT PARAMETERS: - XY - training set, array [0..NPoints-1,0..NVars]: - * NVars columns - independent variables - * last column - dependent variable - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPointsrmserror, _state)*npoints/(npoints-nvars-1); - for(i=0; i<=nvars; i++) - { - ae_v_muld(&ar->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Linear regression - -Variant of LRBuild which uses vector of standatd deviations (errors in -function values). - -INPUT PARAMETERS: - XY - training set, array [0..NPoints-1,0..NVars]: - * NVars columns - independent variables - * last column - dependent variable - S - standard deviations (errors in function values) - array[0..NPoints-1], S[i]>0. - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPointsptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - xyi.ptr.pp_double[i][nvars] = 1; - xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; - } - - /* - * Standartization - */ - ae_vector_set_length(&x, npoints-1+1, _state); - ae_vector_set_length(&means, nvars-1+1, _state); - ae_vector_set_length(&sigmas, nvars-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); - samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); - means.ptr.p_double[j] = mean; - sigmas.ptr.p_double[j] = ae_sqrt(variance, _state); - if( ae_fp_eq(sigmas.ptr.p_double[j],0) ) - { - sigmas.ptr.p_double[j] = 1; - } - for(i=0; i<=npoints-1; i++) - { - xyi.ptr.pp_double[i][j] = (xyi.ptr.pp_double[i][j]-means.ptr.p_double[j])/sigmas.ptr.p_double[j]; - } - } - - /* - * Internal processing - */ - linreg_lrinternal(&xyi, s, npoints, nvars+1, info, lm, ar, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Un-standartization - */ - offs = ae_round(lm->w.ptr.p_double[3], _state); - for(j=0; j<=nvars-1; j++) - { - - /* - * Constant term is updated (and its covariance too, - * since it gets some variance from J-th component) - */ - lm->w.ptr.p_double[offs+nvars] = lm->w.ptr.p_double[offs+nvars]-lm->w.ptr.p_double[offs+j]*means.ptr.p_double[j]/sigmas.ptr.p_double[j]; - v = means.ptr.p_double[j]/sigmas.ptr.p_double[j]; - ae_v_subd(&ar->c.ptr.pp_double[nvars][0], 1, &ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); - ae_v_subd(&ar->c.ptr.pp_double[0][nvars], ar->c.stride, &ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); - - /* - * J-th term is updated - */ - lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/sigmas.ptr.p_double[j]; - v = 1/sigmas.ptr.p_double[j]; - ae_v_muld(&ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); - ae_v_muld(&ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Like LRBuildS, but builds model - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] - -i.e. with zero constant term. - - -- ALGLIB -- - Copyright 30.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lrbuildzs(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix xyi; - ae_vector x; - ae_vector c; - ae_int_t i; - ae_int_t j; - double v; - ae_int_t offs; - double mean; - double variance; - double skewness; - double kurtosis; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _linearmodel_clear(lm); - _lrreport_clear(ar); - ae_matrix_init(&xyi, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_REAL, _state, ae_true); - - - /* - * Test parameters - */ - if( npoints<=nvars+1||nvars<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - - /* - * Copy data, add one more column (constant term) - */ - ae_matrix_set_length(&xyi, npoints-1+1, nvars+1+1, _state); - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&xyi.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - xyi.ptr.pp_double[i][nvars] = 0; - xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; - } - - /* - * Standartization: unusual scaling - */ - ae_vector_set_length(&x, npoints-1+1, _state); - ae_vector_set_length(&c, nvars-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); - samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); - if( ae_fp_greater(ae_fabs(mean, _state),ae_sqrt(variance, _state)) ) - { - - /* - * variation is relatively small, it is better to - * bring mean value to 1 - */ - c.ptr.p_double[j] = mean; - } - else - { - - /* - * variation is large, it is better to bring variance to 1 - */ - if( ae_fp_eq(variance,0) ) - { - variance = 1; - } - c.ptr.p_double[j] = ae_sqrt(variance, _state); - } - for(i=0; i<=npoints-1; i++) - { - xyi.ptr.pp_double[i][j] = xyi.ptr.pp_double[i][j]/c.ptr.p_double[j]; - } - } - - /* - * Internal processing - */ - linreg_lrinternal(&xyi, s, npoints, nvars+1, info, lm, ar, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Un-standartization - */ - offs = ae_round(lm->w.ptr.p_double[3], _state); - for(j=0; j<=nvars-1; j++) - { - - /* - * J-th term is updated - */ - lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/c.ptr.p_double[j]; - v = 1/c.ptr.p_double[j]; - ae_v_muld(&ar->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); - ae_v_muld(&ar->c.ptr.pp_double[0][j], ar->c.stride, ae_v_len(0,nvars), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Like LRBuild but builds model - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] - -i.e. with zero constant term. - - -- ALGLIB -- - Copyright 30.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lrbuildz(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector s; - ae_int_t i; - double sigma2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _linearmodel_clear(lm); - _lrreport_clear(ar); - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - - if( npoints<=nvars+1||nvars<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&s, npoints-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - s.ptr.p_double[i] = 1; - } - lrbuildzs(xy, &s, npoints, nvars, info, lm, ar, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - sigma2 = ae_sqr(ar->rmserror, _state)*npoints/(npoints-nvars-1); - for(i=0; i<=nvars; i++) - { - ae_v_muld(&ar->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacks coefficients of linear model. - -INPUT PARAMETERS: - LM - linear model in ALGLIB format - -OUTPUT PARAMETERS: - V - coefficients, array[0..NVars] - constant term (intercept) is stored in the V[NVars]. - NVars - number of independent variables (one less than number - of coefficients) - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -void lrunpack(linearmodel* lm, - /* Real */ ae_vector* v, - ae_int_t* nvars, - ae_state *_state) -{ - ae_int_t offs; - - ae_vector_clear(v); - *nvars = 0; - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); - *nvars = ae_round(lm->w.ptr.p_double[2], _state); - offs = ae_round(lm->w.ptr.p_double[3], _state); - ae_vector_set_length(v, *nvars+1, _state); - ae_v_move(&v->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,*nvars)); -} - - -/************************************************************************* -"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack -reversed). - -INPUT PARAMETERS: - V - coefficients, array[0..NVars] - NVars - number of independent variables - -OUTPUT PAREMETERS: - LM - linear model. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -void lrpack(/* Real */ ae_vector* v, - ae_int_t nvars, - linearmodel* lm, - ae_state *_state) -{ - ae_int_t offs; - - _linearmodel_clear(lm); - - ae_vector_set_length(&lm->w, 4+nvars+1, _state); - offs = 4; - lm->w.ptr.p_double[0] = 4+nvars+1; - lm->w.ptr.p_double[1] = linreg_lrvnum; - lm->w.ptr.p_double[2] = nvars; - lm->w.ptr.p_double[3] = offs; - ae_v_move(&lm->w.ptr.p_double[offs], 1, &v->ptr.p_double[0], 1, ae_v_len(offs,offs+nvars)); -} - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - LM - linear model - X - input vector, array[0..NVars-1]. - -Result: - value of linear model regression estimate - - -- ALGLIB -- - Copyright 03.09.2008 by Bochkanov Sergey -*************************************************************************/ -double lrprocess(linearmodel* lm, - /* Real */ ae_vector* x, - ae_state *_state) -{ - double v; - ae_int_t offs; - ae_int_t nvars; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - offs = ae_round(lm->w.ptr.p_double[3], _state); - v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); - result = v+lm->w.ptr.p_double[offs+nvars]; - return result; -} - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lrrmserror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_int_t i; - double v; - ae_int_t offs; - ae_int_t nvars; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - offs = ae_round(lm->w.ptr.p_double[3], _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); - v = v+lm->w.ptr.p_double[offs+nvars]; - result = result+ae_sqr(v-xy->ptr.pp_double[i][nvars], _state); - } - result = ae_sqrt(result/npoints, _state); - return result; -} - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - average error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lravgerror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_int_t i; - double v; - ae_int_t offs; - ae_int_t nvars; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - offs = ae_round(lm->w.ptr.p_double[3], _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); - v = v+lm->w.ptr.p_double[offs+nvars]; - result = result+ae_fabs(v-xy->ptr.pp_double[i][nvars], _state); - } - result = result/npoints; - return result; -} - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - linear model - XY - test set - NPoints - test set size - -RESULT: - average relative error. - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double lravgrelerror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - double v; - ae_int_t offs; - ae_int_t nvars; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - offs = ae_round(lm->w.ptr.p_double[3], _state); - result = 0; - k = 0; - for(i=0; i<=npoints-1; i++) - { - if( ae_fp_neq(xy->ptr.pp_double[i][nvars],0) ) - { - v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); - v = v+lm->w.ptr.p_double[offs+nvars]; - result = result+ae_fabs((v-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); - k = k+1; - } - } - if( k!=0 ) - { - result = result/k; - } - return result; -} - - -/************************************************************************* -Copying of LinearModel strucure - -INPUT PARAMETERS: - LM1 - original - -OUTPUT PARAMETERS: - LM2 - copy - - -- ALGLIB -- - Copyright 15.03.2009 by Bochkanov Sergey -*************************************************************************/ -void lrcopy(linearmodel* lm1, linearmodel* lm2, ae_state *_state) -{ - ae_int_t k; - - _linearmodel_clear(lm2); - - k = ae_round(lm1->w.ptr.p_double[0], _state); - ae_vector_set_length(&lm2->w, k-1+1, _state); - ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); -} - - -void lrlines(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t n, - ae_int_t* info, - double* a, - double* b, - double* vara, - double* varb, - double* covab, - double* corrab, - double* p, - ae_state *_state) -{ - ae_int_t i; - double ss; - double sx; - double sxx; - double sy; - double stt; - double e1; - double e2; - double t; - double chi2; - - *info = 0; - *a = 0; - *b = 0; - *vara = 0; - *varb = 0; - *covab = 0; - *corrab = 0; - *p = 0; - - if( n<2 ) - { - *info = -1; - return; - } - for(i=0; i<=n-1; i++) - { - if( ae_fp_less_eq(s->ptr.p_double[i],0) ) - { - *info = -2; - return; - } - } - *info = 1; - - /* - * Calculate S, SX, SY, SXX - */ - ss = 0; - sx = 0; - sy = 0; - sxx = 0; - for(i=0; i<=n-1; i++) - { - t = ae_sqr(s->ptr.p_double[i], _state); - ss = ss+1/t; - sx = sx+xy->ptr.pp_double[i][0]/t; - sy = sy+xy->ptr.pp_double[i][1]/t; - sxx = sxx+ae_sqr(xy->ptr.pp_double[i][0], _state)/t; - } - - /* - * Test for condition number - */ - t = ae_sqrt(4*ae_sqr(sx, _state)+ae_sqr(ss-sxx, _state), _state); - e1 = 0.5*(ss+sxx+t); - e2 = 0.5*(ss+sxx-t); - if( ae_fp_less_eq(ae_minreal(e1, e2, _state),1000*ae_machineepsilon*ae_maxreal(e1, e2, _state)) ) - { - *info = -3; - return; - } - - /* - * Calculate A, B - */ - *a = 0; - *b = 0; - stt = 0; - for(i=0; i<=n-1; i++) - { - t = (xy->ptr.pp_double[i][0]-sx/ss)/s->ptr.p_double[i]; - *b = *b+t*xy->ptr.pp_double[i][1]/s->ptr.p_double[i]; - stt = stt+ae_sqr(t, _state); - } - *b = *b/stt; - *a = (sy-sx*(*b))/ss; - - /* - * Calculate goodness-of-fit - */ - if( n>2 ) - { - chi2 = 0; - for(i=0; i<=n-1; i++) - { - chi2 = chi2+ae_sqr((xy->ptr.pp_double[i][1]-(*a)-*b*xy->ptr.pp_double[i][0])/s->ptr.p_double[i], _state); - } - *p = incompletegammac((double)(n-2)/(double)2, chi2/2, _state); - } - else - { - *p = 1; - } - - /* - * Calculate other parameters - */ - *vara = (1+ae_sqr(sx, _state)/(ss*stt))/ss; - *varb = 1/stt; - *covab = -sx/(ss*stt); - *corrab = *covab/ae_sqrt(*vara*(*varb), _state); -} - - -void lrline(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t* info, - double* a, - double* b, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector s; - ae_int_t i; - double vara; - double varb; - double covab; - double corrab; - double p; - - ae_frame_make(_state, &_frame_block); - *info = 0; - *a = 0; - *b = 0; - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - - if( n<2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&s, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - s.ptr.p_double[i] = 1; - } - lrlines(xy, &s, n, info, a, b, &vara, &varb, &covab, &corrab, &p, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal linear regression subroutine -*************************************************************************/ -static void linreg_lrinternal(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix a; - ae_matrix u; - ae_matrix vt; - ae_matrix vm; - ae_matrix xym; - ae_vector b; - ae_vector sv; - ae_vector t; - ae_vector svi; - ae_vector work; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t ncv; - ae_int_t na; - ae_int_t nacv; - double r; - double p; - double epstol; - lrreport ar2; - ae_int_t offs; - linearmodel tlm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _linearmodel_clear(lm); - _lrreport_clear(ar); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xym, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&svi, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - _lrreport_init(&ar2, _state, ae_true); - _linearmodel_init(&tlm, _state, ae_true); - - epstol = 1000; - - /* - * Check for errors in data - */ - if( npointsptr.p_double[i],0) ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Create design matrix - */ - ae_matrix_set_length(&a, npoints-1+1, nvars-1+1, _state); - ae_vector_set_length(&b, npoints-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - r = 1/s->ptr.p_double[i]; - ae_v_moved(&a.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); - b.ptr.p_double[i] = xy->ptr.pp_double[i][nvars]/s->ptr.p_double[i]; - } - - /* - * Allocate W: - * W[0] array size - * W[1] version number, 0 - * W[2] NVars (minus 1, to be compatible with external representation) - * W[3] coefficients offset - */ - ae_vector_set_length(&lm->w, 4+nvars-1+1, _state); - offs = 4; - lm->w.ptr.p_double[0] = 4+nvars; - lm->w.ptr.p_double[1] = linreg_lrvnum; - lm->w.ptr.p_double[2] = nvars-1; - lm->w.ptr.p_double[3] = offs; - - /* - * Solve problem using SVD: - * - * 0. check for degeneracy (different types) - * 1. A = U*diag(sv)*V' - * 2. T = b'*U - * 3. w = SUM((T[i]/sv[i])*V[..,i]) - * 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M) - * - * see $15.4 of "Numerical Recipes in C" for more information - */ - ae_vector_set_length(&t, nvars-1+1, _state); - ae_vector_set_length(&svi, nvars-1+1, _state); - ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); - ae_matrix_set_length(&vm, nvars-1+1, nvars-1+1, _state); - if( !rmatrixsvd(&a, npoints, nvars, 1, 1, 2, &sv, &u, &vt, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - if( ae_fp_less_eq(sv.ptr.p_double[0],0) ) - { - - /* - * Degenerate case: zero design matrix. - */ - for(i=offs; i<=offs+nvars-1; i++) - { - lm->w.ptr.p_double[i] = 0; - } - ar->rmserror = lrrmserror(lm, xy, npoints, _state); - ar->avgerror = lravgerror(lm, xy, npoints, _state); - ar->avgrelerror = lravgrelerror(lm, xy, npoints, _state); - ar->cvrmserror = ar->rmserror; - ar->cvavgerror = ar->avgerror; - ar->cvavgrelerror = ar->avgrelerror; - ar->ncvdefects = 0; - ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); - ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - ar->c.ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - if( ae_fp_less_eq(sv.ptr.p_double[nvars-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) - { - - /* - * Degenerate case, non-zero design matrix. - * - * We can leave it and solve task in SVD least squares fashion. - * Solution and covariance matrix will be obtained correctly, - * but CV error estimates - will not. It is better to reduce - * it to non-degenerate task and to obtain correct CV estimates. - */ - for(k=nvars; k>=1; k--) - { - if( ae_fp_greater(sv.ptr.p_double[k-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) - { - - /* - * Reduce - */ - ae_matrix_set_length(&xym, npoints-1+1, k+1, _state); - for(i=0; i<=npoints-1; i++) - { - for(j=0; j<=k-1; j++) - { - r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - xym.ptr.pp_double[i][j] = r; - } - xym.ptr.pp_double[i][k] = xy->ptr.pp_double[i][nvars]; - } - - /* - * Solve - */ - linreg_lrinternal(&xym, s, npoints, k, info, &tlm, &ar2, _state); - if( *info!=1 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Convert back to un-reduced format - */ - for(j=0; j<=nvars-1; j++) - { - lm->w.ptr.p_double[offs+j] = 0; - } - for(j=0; j<=k-1; j++) - { - r = tlm.w.ptr.p_double[offs+j]; - ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(offs,offs+nvars-1), r); - } - ar->rmserror = ar2.rmserror; - ar->avgerror = ar2.avgerror; - ar->avgrelerror = ar2.avgrelerror; - ar->cvrmserror = ar2.cvrmserror; - ar->cvavgerror = ar2.cvavgerror; - ar->cvavgrelerror = ar2.cvavgrelerror; - ar->ncvdefects = ar2.ncvdefects; - ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); - for(j=0; j<=ar->ncvdefects-1; j++) - { - ar->cvdefects.ptr.p_int[j] = ar2.cvdefects.ptr.p_int[j]; - } - ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); - ae_vector_set_length(&work, nvars+1, _state); - matrixmatrixmultiply(&ar2.c, 0, k-1, 0, k-1, ae_false, &vt, 0, k-1, 0, nvars-1, ae_false, 1.0, &vm, 0, k-1, 0, nvars-1, 0.0, &work, _state); - matrixmatrixmultiply(&vt, 0, k-1, 0, nvars-1, ae_true, &vm, 0, k-1, 0, nvars-1, ae_false, 1.0, &ar->c, 0, nvars-1, 0, nvars-1, 0.0, &work, _state); - ae_frame_leave(_state); - return; - } - } - *info = -255; - ae_frame_leave(_state); - return; - } - for(i=0; i<=nvars-1; i++) - { - if( ae_fp_greater(sv.ptr.p_double[i],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) - { - svi.ptr.p_double[i] = 1/sv.ptr.p_double[i]; - } - else - { - svi.ptr.p_double[i] = 0; - } - } - for(i=0; i<=nvars-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=npoints-1; i++) - { - r = b.ptr.p_double[i]; - ae_v_addd(&t.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); - } - for(i=0; i<=nvars-1; i++) - { - lm->w.ptr.p_double[offs+i] = 0; - } - for(i=0; i<=nvars-1; i++) - { - r = t.ptr.p_double[i]*svi.ptr.p_double[i]; - ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(offs,offs+nvars-1), r); - } - for(j=0; j<=nvars-1; j++) - { - r = svi.ptr.p_double[j]; - ae_v_moved(&vm.ptr.pp_double[0][j], vm.stride, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), r); - } - for(i=0; i<=nvars-1; i++) - { - for(j=i; j<=nvars-1; j++) - { - r = ae_v_dotproduct(&vm.ptr.pp_double[i][0], 1, &vm.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); - ar->c.ptr.pp_double[i][j] = r; - ar->c.ptr.pp_double[j][i] = r; - } - } - - /* - * Leave-1-out cross-validation error. - * - * NOTATIONS: - * A design matrix - * A*x = b original linear least squares task - * U*S*V' SVD of A - * ai i-th row of the A - * bi i-th element of the b - * xf solution of the original LLS task - * - * Cross-validation error of i-th element from a sample is - * calculated using following formula: - * - * ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) - * - * This formula can be derived from normal equations of the - * original task - * - * (A'*A)x = A'*b (2) - * - * by applying modification (zeroing out i-th row of A) to (2): - * - * (A-ai)'*(A-ai) = (A-ai)'*b - * - * and using Sherman-Morrison formula for updating matrix inverse - * - * NOTE 1: b is not zeroed out since it is much simpler and - * does not influence final result. - * - * NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. - * Formula (1) can't be applied for such cases and they are skipped - * from CV calculation (which distorts resulting CV estimate). - * But from the properties of U we can conclude that there can - * be no more than NVars such vectors. Usually - * NVars << NPoints, so in a normal case it only slightly - * influences result. - */ - ncv = 0; - na = 0; - nacv = 0; - ar->rmserror = 0; - ar->avgerror = 0; - ar->avgrelerror = 0; - ar->cvrmserror = 0; - ar->cvavgerror = 0; - ar->cvavgrelerror = 0; - ar->ncvdefects = 0; - ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - - /* - * Error on a training set - */ - r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); - ar->rmserror = ar->rmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); - ar->avgerror = ar->avgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); - if( ae_fp_neq(xy->ptr.pp_double[i][nvars],0) ) - { - ar->avgrelerror = ar->avgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); - na = na+1; - } - - /* - * Error using fast leave-one-out cross-validation - */ - p = ae_v_dotproduct(&u.ptr.pp_double[i][0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - if( ae_fp_greater(p,1-epstol*ae_machineepsilon) ) - { - ar->cvdefects.ptr.p_int[ar->ncvdefects] = i; - ar->ncvdefects = ar->ncvdefects+1; - continue; - } - r = s->ptr.p_double[i]*(r/s->ptr.p_double[i]-b.ptr.p_double[i]*p)/(1-p); - ar->cvrmserror = ar->cvrmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); - ar->cvavgerror = ar->cvavgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); - if( ae_fp_neq(xy->ptr.pp_double[i][nvars],0) ) - { - ar->cvavgrelerror = ar->cvavgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); - nacv = nacv+1; - } - ncv = ncv+1; - } - if( ncv==0 ) - { - - /* - * Something strange: ALL ui are degenerate. - * Unexpected... - */ - *info = -255; - ae_frame_leave(_state); - return; - } - ar->rmserror = ae_sqrt(ar->rmserror/npoints, _state); - ar->avgerror = ar->avgerror/npoints; - if( na!=0 ) - { - ar->avgrelerror = ar->avgrelerror/na; - } - ar->cvrmserror = ae_sqrt(ar->cvrmserror/ncv, _state); - ar->cvavgerror = ar->cvavgerror/ncv; - if( nacv!=0 ) - { - ar->cvavgrelerror = ar->cvavgrelerror/nacv; - } - ae_frame_leave(_state); -} - - -ae_bool _linearmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - linearmodel *p = (linearmodel*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _linearmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - linearmodel *dst = (linearmodel*)_dst; - linearmodel *src = (linearmodel*)_src; - if( !ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _linearmodel_clear(void* _p) -{ - linearmodel *p = (linearmodel*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->w); -} - - -void _linearmodel_destroy(void* _p) -{ - linearmodel *p = (linearmodel*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->w); -} - - -ae_bool _lrreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - lrreport *p = (lrreport*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cvdefects, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _lrreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - lrreport *dst = (lrreport*)_dst; - lrreport *src = (lrreport*)_src; - if( !ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic) ) - return ae_false; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->cvrmserror = src->cvrmserror; - dst->cvavgerror = src->cvavgerror; - dst->cvavgrelerror = src->cvavgrelerror; - dst->ncvdefects = src->ncvdefects; - if( !ae_vector_init_copy(&dst->cvdefects, &src->cvdefects, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _lrreport_clear(void* _p) -{ - lrreport *p = (lrreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->c); - ae_vector_clear(&p->cvdefects); -} - - -void _lrreport_destroy(void* _p) -{ - lrreport *p = (lrreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->c); - ae_vector_destroy(&p->cvdefects); -} - - - - -/************************************************************************* -Filters: simple moving averages (unsymmetric). - -This filter replaces array by results of SMA(K) filter. SMA(K) is defined -as filter which averages at most K previous points (previous - not points -AROUND central point) - or less, in case of the first K-1 points. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filtersma(/* Real */ ae_vector* x, - ae_int_t n, - ae_int_t k, - ae_state *_state) -{ - ae_int_t i; - double runningsum; - double termsinsum; - ae_int_t zeroprefix; - double v; - - - ae_assert(n>=0, "FilterSMA: N<0", _state); - ae_assert(x->cnt>=n, "FilterSMA: Length(X)=1, "FilterSMA: K<1", _state); - - /* - * Quick exit, if necessary - */ - if( n<=1||k==1 ) - { - return; - } - - /* - * Prepare variables (see below for explanation) - */ - runningsum = 0.0; - termsinsum = 0; - for(i=ae_maxint(n-k, 0, _state); i<=n-1; i++) - { - runningsum = runningsum+x->ptr.p_double[i]; - termsinsum = termsinsum+1; - } - i = ae_maxint(n-k, 0, _state); - zeroprefix = 0; - while(i<=n-1&&ae_fp_eq(x->ptr.p_double[i],0)) - { - zeroprefix = zeroprefix+1; - i = i+1; - } - - /* - * General case: we assume that N>1 and K>1 - * - * Make one pass through all elements. At the beginning of - * the iteration we have: - * * I element being processed - * * RunningSum current value of the running sum - * (including I-th element) - * * TermsInSum number of terms in sum, 0<=TermsInSum<=K - * * ZeroPrefix length of the sequence of zero elements - * which starts at X[I-K+1] and continues towards X[I]. - * Equal to zero in case X[I-K+1] is non-zero. - * This value is used to make RunningSum exactly zero - * when it follows from the problem properties. - */ - for(i=n-1; i>=0; i--) - { - - /* - * Store new value of X[i], save old value in V - */ - v = x->ptr.p_double[i]; - x->ptr.p_double[i] = runningsum/termsinsum; - - /* - * Update RunningSum and TermsInSum - */ - if( i-k>=0 ) - { - runningsum = runningsum-v+x->ptr.p_double[i-k]; - } - else - { - runningsum = runningsum-v; - termsinsum = termsinsum-1; - } - - /* - * Update ZeroPrefix. - * In case we have ZeroPrefix=TermsInSum, - * RunningSum is reset to zero. - */ - if( i-k>=0 ) - { - if( ae_fp_neq(x->ptr.p_double[i-k],0) ) - { - zeroprefix = 0; - } - else - { - zeroprefix = ae_minint(zeroprefix+1, k, _state); - } - } - else - { - zeroprefix = ae_minint(zeroprefix, i+1, _state); - } - if( ae_fp_eq(zeroprefix,termsinsum) ) - { - runningsum = 0; - } - } -} - - -/************************************************************************* -Filters: exponential moving averages. - -This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is -defined as filter which replaces X[] by S[]: - S[0] = X[0] - S[t] = alpha*X[t] + (1-alpha)*S[t-1] - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - alpha - 0=0, "FilterEMA: N<0", _state); - ae_assert(x->cnt>=n, "FilterEMA: Length(X)1", _state); - - /* - * Quick exit, if necessary - */ - if( n<=1||ae_fp_eq(alpha,1) ) - { - return; - } - - /* - * Process - */ - for(i=1; i<=n-1; i++) - { - x->ptr.p_double[i] = alpha*x->ptr.p_double[i]+(1-alpha)*x->ptr.p_double[i-1]; - } -} - - -/************************************************************************* -Filters: linear regression moving averages. - -This filter replaces array by results of LRMA(K) filter. - -LRMA(K) is defined as filter which, for each data point, builds linear -regression model using K prevous points (point itself is included in -these K points) and calculates value of this linear model at the point in -question. - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filterlrma(/* Real */ ae_vector* x, - ae_int_t n, - ae_int_t k, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t m; - ae_matrix xy; - ae_vector s; - ae_int_t info; - double a; - double b; - double vara; - double varb; - double covab; - double corrab; - double p; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init(&xy, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "FilterLRMA: N<0", _state); - ae_assert(x->cnt>=n, "FilterLRMA: Length(X)=1, "FilterLRMA: K<1", _state); - - /* - * Quick exit, if necessary: - * * either N is equal to 1 (nothing to average) - * * or K is 1 (only point itself is used) or 2 (model is too simple, - * we will always get identity transformation) - */ - if( n<=1||k<=2 ) - { - ae_frame_leave(_state); - return; - } - - /* - * General case: K>2, N>1. - * We do not process points with I<2 because first two points (I=0 and I=1) will be - * left unmodified by LRMA filter in any case. - */ - ae_matrix_set_length(&xy, k, 2, _state); - ae_vector_set_length(&s, k, _state); - for(i=0; i<=k-1; i++) - { - xy.ptr.pp_double[i][0] = i; - s.ptr.p_double[i] = 1.0; - } - for(i=n-1; i>=2; i--) - { - m = ae_minint(i+1, k, _state); - ae_v_move(&xy.ptr.pp_double[0][1], xy.stride, &x->ptr.p_double[i-m+1], 1, ae_v_len(0,m-1)); - lrlines(&xy, &s, m, &info, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); - ae_assert(info==1, "FilterLRMA: internal error", _state); - x->ptr.p_double[i] = a+b*(m-1); - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Multiclass Fisher LDA - -Subroutine finds coefficients of linear combination which optimally separates -training set on classes. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - linear combination coefficients, array[0..NVars-1] - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherlda(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t* info, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix w2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(w); - ae_matrix_init(&w2, 0, 0, DT_REAL, _state, ae_true); - - fisherldan(xy, npoints, nvars, nclasses, info, &w2, _state); - if( *info>0 ) - { - ae_vector_set_length(w, nvars-1+1, _state); - ae_v_move(&w->ptr.p_double[0], 1, &w2.ptr.pp_double[0][0], w2.stride, ae_v_len(0,nvars-1)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -N-dimensional multiclass Fisher LDA - -Subroutine finds coefficients of linear combinations which optimally separates -training set on classes. It returns N-dimensional basis whose vector are sorted -by quality of training set separation (in descending order). - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - basis, array[0..NVars-1,0..NVars-1] - columns of matrix stores basis vectors, sorted by - quality of training set separation (in descending order) - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherldan(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t* info, - /* Real */ ae_matrix* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t m; - double v; - ae_vector c; - ae_vector mu; - ae_matrix muc; - ae_vector nc; - ae_matrix sw; - ae_matrix st; - ae_matrix z; - ae_matrix z2; - ae_matrix tm; - ae_matrix sbroot; - ae_matrix a; - ae_matrix xyproj; - ae_matrix wproj; - ae_vector tf; - ae_vector d; - ae_vector d2; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_matrix_clear(w); - ae_vector_init(&c, 0, DT_INT, _state, ae_true); - ae_vector_init(&mu, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&muc, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&nc, 0, DT_INT, _state, ae_true); - ae_matrix_init(&sw, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&st, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&sbroot, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xyproj, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&wproj, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - - /* - * Test data - */ - if( (npoints<0||nvars<1)||nclasses<2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Special case: NPoints<=1 - * Degenerate task. - */ - if( npoints<=1 ) - { - *info = 2; - ae_matrix_set_length(w, nvars-1+1, nvars-1+1, _state); - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - if( i==j ) - { - w->ptr.pp_double[i][j] = 1; - } - else - { - w->ptr.pp_double[i][j] = 0; - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * Prepare temporaries - */ - ae_vector_set_length(&tf, nvars-1+1, _state); - ae_vector_set_length(&work, ae_maxint(nvars, npoints, _state)+1, _state); - - /* - * Convert class labels from reals to integers (just for convenience) - */ - ae_vector_set_length(&c, npoints-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - c.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nvars], _state); - } - - /* - * Calculate class sizes and means - */ - ae_vector_set_length(&mu, nvars-1+1, _state); - ae_matrix_set_length(&muc, nclasses-1+1, nvars-1+1, _state); - ae_vector_set_length(&nc, nclasses-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - mu.ptr.p_double[j] = 0; - } - for(i=0; i<=nclasses-1; i++) - { - nc.ptr.p_int[i] = 0; - for(j=0; j<=nvars-1; j++) - { - muc.ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=npoints-1; i++) - { - ae_v_add(&mu.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_add(&muc.ptr.pp_double[c.ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - nc.ptr.p_int[c.ptr.p_int[i]] = nc.ptr.p_int[c.ptr.p_int[i]]+1; - } - for(i=0; i<=nclasses-1; i++) - { - v = (double)1/(double)nc.ptr.p_int[i]; - ae_v_muld(&muc.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); - } - v = (double)1/(double)npoints; - ae_v_muld(&mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1), v); - - /* - * Create ST matrix - */ - ae_matrix_set_length(&st, nvars-1+1, nvars-1+1, _state); - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - st.ptr.pp_double[i][j] = 0; - } - } - for(k=0; k<=npoints-1; k++) - { - ae_v_move(&tf.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tf.ptr.p_double[0], 1, &mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - for(i=0; i<=nvars-1; i++) - { - v = tf.ptr.p_double[i]; - ae_v_addd(&st.ptr.pp_double[i][0], 1, &tf.ptr.p_double[0], 1, ae_v_len(0,nvars-1), v); - } - } - - /* - * Create SW matrix - */ - ae_matrix_set_length(&sw, nvars-1+1, nvars-1+1, _state); - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - sw.ptr.pp_double[i][j] = 0; - } - } - for(k=0; k<=npoints-1; k++) - { - ae_v_move(&tf.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&tf.ptr.p_double[0], 1, &muc.ptr.pp_double[c.ptr.p_int[k]][0], 1, ae_v_len(0,nvars-1)); - for(i=0; i<=nvars-1; i++) - { - v = tf.ptr.p_double[i]; - ae_v_addd(&sw.ptr.pp_double[i][0], 1, &tf.ptr.p_double[0], 1, ae_v_len(0,nvars-1), v); - } - } - - /* - * Maximize ratio J=(w'*ST*w)/(w'*SW*w). - * - * First, make transition from w to v such that w'*ST*w becomes v'*v: - * v = root(ST)*w = R*w - * R = root(D)*Z' - * w = (root(ST)^-1)*v = RI*v - * RI = Z*inv(root(D)) - * J = (v'*v)/(v'*(RI'*SW*RI)*v) - * ST = Z*D*Z' - * - * so we have - * - * J = (v'*v) / (v'*(inv(root(D))*Z'*SW*Z*inv(root(D)))*v) = - * = (v'*v) / (v'*A*v) - */ - if( !smatrixevd(&st, nvars, 1, ae_true, &d, &z, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(w, nvars-1+1, nvars-1+1, _state); - if( ae_fp_less_eq(d.ptr.p_double[nvars-1],0)||ae_fp_less_eq(d.ptr.p_double[0],1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) - { - - /* - * Special case: D[NVars-1]<=0 - * Degenerate task (all variables takes the same value). - */ - if( ae_fp_less_eq(d.ptr.p_double[nvars-1],0) ) - { - *info = 2; - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - if( i==j ) - { - w->ptr.pp_double[i][j] = 1; - } - else - { - w->ptr.pp_double[i][j] = 0; - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * Special case: degenerate ST matrix, multicollinearity found. - * Since we know ST eigenvalues/vectors we can translate task to - * non-degenerate form. - * - * Let WG is orthogonal basis of the non zero variance subspace - * of the ST and let WZ is orthogonal basis of the zero variance - * subspace. - * - * Projection on WG allows us to use LDA on reduced M-dimensional - * subspace, N-M vectors of WZ allows us to update reduced LDA - * factors to full N-dimensional subspace. - */ - m = 0; - for(k=0; k<=nvars-1; k++) - { - if( ae_fp_less_eq(d.ptr.p_double[k],1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) - { - m = k+1; - } - } - ae_assert(m!=0, "FisherLDAN: internal error #1", _state); - ae_matrix_set_length(&xyproj, npoints-1+1, nvars-m+1, _state); - matrixmatrixmultiply(xy, 0, npoints-1, 0, nvars-1, ae_false, &z, 0, nvars-1, m, nvars-1, ae_false, 1.0, &xyproj, 0, npoints-1, 0, nvars-m-1, 0.0, &work, _state); - for(i=0; i<=npoints-1; i++) - { - xyproj.ptr.pp_double[i][nvars-m] = xy->ptr.pp_double[i][nvars]; - } - fisherldan(&xyproj, npoints, nvars-m, nclasses, info, &wproj, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - matrixmatrixmultiply(&z, 0, nvars-1, m, nvars-1, ae_false, &wproj, 0, nvars-m-1, 0, nvars-m-1, ae_false, 1.0, w, 0, nvars-1, 0, nvars-m-1, 0.0, &work, _state); - for(k=nvars-m; k<=nvars-1; k++) - { - ae_v_move(&w->ptr.pp_double[0][k], w->stride, &z.ptr.pp_double[0][k-(nvars-m)], z.stride, ae_v_len(0,nvars-1)); - } - *info = 2; - } - else - { - - /* - * General case: no multicollinearity - */ - ae_matrix_set_length(&tm, nvars-1+1, nvars-1+1, _state); - ae_matrix_set_length(&a, nvars-1+1, nvars-1+1, _state); - matrixmatrixmultiply(&sw, 0, nvars-1, 0, nvars-1, ae_false, &z, 0, nvars-1, 0, nvars-1, ae_false, 1.0, &tm, 0, nvars-1, 0, nvars-1, 0.0, &work, _state); - matrixmatrixmultiply(&z, 0, nvars-1, 0, nvars-1, ae_true, &tm, 0, nvars-1, 0, nvars-1, ae_false, 1.0, &a, 0, nvars-1, 0, nvars-1, 0.0, &work, _state); - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]/ae_sqrt(d.ptr.p_double[i]*d.ptr.p_double[j], _state); - } - } - if( !smatrixevd(&a, nvars, 1, ae_true, &d2, &z2, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - for(k=0; k<=nvars-1; k++) - { - for(i=0; i<=nvars-1; i++) - { - tf.ptr.p_double[i] = z2.ptr.pp_double[i][k]/ae_sqrt(d.ptr.p_double[i], _state); - } - for(i=0; i<=nvars-1; i++) - { - v = ae_v_dotproduct(&z.ptr.pp_double[i][0], 1, &tf.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - w->ptr.pp_double[i][k] = v; - } - } - } - - /* - * Post-processing: - * * normalization - * * converting to non-negative form, if possible - */ - for(k=0; k<=nvars-1; k++) - { - v = ae_v_dotproduct(&w->ptr.pp_double[0][k], w->stride, &w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1)); - v = 1/ae_sqrt(v, _state); - ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), v); - v = 0; - for(i=0; i<=nvars-1; i++) - { - v = v+w->ptr.pp_double[i][k]; - } - if( ae_fp_less(v,0) ) - { - ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), -1); - } - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -This function returns number of weights updates which is required for -gradient calculation problem to be splitted. -*************************************************************************/ -ae_int_t mlpgradsplitcost(ae_state *_state) -{ - ae_int_t result; - - - result = mlpbase_gradbasecasecost; - return result; -} - - -/************************************************************************* -This function returns number of elements in subset of dataset which is -required for gradient calculation problem to be splitted. -*************************************************************************/ -ae_int_t mlpgradsplitsize(ae_state *_state) -{ - ae_int_t result; - - - result = mlpbase_microbatchsize; - return result; -} - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers, with linear output layer. Network weights are filled with small -random values. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate0(ae_int_t nin, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreate0, but with one hidden layer (NHid neurons) with -non-linear activation function. Output layer is linear. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) -with non-linear activation function. Output layer is linear. - $ALL - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. - -Activation function of the output layer takes values: - - (B, +INF), if D>=0 - -or - - (-INF, B), if D<0. - - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb0(ae_int_t nin, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3; - if( ae_fp_greater_eq(d,0) ) - { - d = 1; - } - else - { - d = -1; - } - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); - - /* - * Turn on ouputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = b; - network->columnsigmas.ptr.p_double[i] = d; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateB0 but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3; - if( ae_fp_greater_eq(d,0) ) - { - d = 1; - } - else - { - d = -1; - } - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); - - /* - * Turn on ouputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = b; - network->columnsigmas.ptr.p_double[i] = d; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateB0 but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3+3; - if( ae_fp_greater_eq(d,0) ) - { - d = 1; - } - else - { - d = -1; - } - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); - - /* - * Turn on ouputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = b; - network->columnsigmas.ptr.p_double[i] = d; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. Activation function of the output layer takes values [A,B]. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater0(ae_int_t nin, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); - - /* - * Turn on outputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = 0.5*(a+b); - network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateR0, but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); - - /* - * Turn on outputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = 0.5*(a+b); - network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateR0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - layerscount = 1+3+3+3; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); - - /* - * Turn on outputs shift/scaling. - */ - for(i=nin; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = 0.5*(a+b); - network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Creates classifier network with NIn inputs and NOut possible classes. -Network contains no hidden layers and linear output layer with SOFTMAX- -normalization (so outputs sums up to 1.0 and converge to posterior -probabilities). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec0(ae_int_t nin, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - ae_assert(nout>=2, "MLPCreateC0: NOut<2!", _state); - layerscount = 1+2+1; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); - mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_true, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateC0, but with one non-linear hidden layer. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - ae_assert(nout>=2, "MLPCreateC1: NOut<2!", _state); - layerscount = 1+3+2+1; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_true, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Same as MLPCreateC0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector lsizes; - ae_vector ltypes; - ae_vector lconnfirst; - ae_vector lconnlast; - ae_int_t layerscount; - ae_int_t lastproc; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); - ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); - - ae_assert(nout>=2, "MLPCreateC2: NOut<2!", _state); - layerscount = 1+3+3+2+1; - - /* - * Allocate arrays - */ - ae_vector_set_length(&lsizes, layerscount-1+1, _state); - ae_vector_set_length(<ypes, layerscount-1+1, _state); - ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); - ae_vector_set_length(&lconnlast, layerscount-1+1, _state); - - /* - * Layers - */ - mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); - - /* - * Create - */ - mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); - mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_true, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Copying of neural network - -INPUT PARAMETERS: - Network1 - original - -OUTPUT PARAMETERS: - Network2 - copy - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcopy(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state) -{ - - _multilayerperceptron_clear(network2); - - mlpcopyshared(network1, network2, _state); -} - - -/************************************************************************* -Copying of neural network (second parameter is passed as shared object). - -INPUT PARAMETERS: - Network1 - original - -OUTPUT PARAMETERS: - Network2 - copy - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcopyshared(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t wcount; - ae_int_t i; - mlpbuffers buf; - smlpgrad sgrad; - - ae_frame_make(_state, &_frame_block); - _mlpbuffers_init(&buf, _state, ae_true); - _smlpgrad_init(&sgrad, _state, ae_true); - - - /* - * Copy scalar and array fields - */ - network2->hlnetworktype = network1->hlnetworktype; - network2->hlnormtype = network1->hlnormtype; - copyintegerarray(&network1->hllayersizes, &network2->hllayersizes, _state); - copyintegerarray(&network1->hlconnections, &network2->hlconnections, _state); - copyintegerarray(&network1->hlneurons, &network2->hlneurons, _state); - copyintegerarray(&network1->structinfo, &network2->structinfo, _state); - copyrealarray(&network1->weights, &network2->weights, _state); - copyrealarray(&network1->columnmeans, &network2->columnmeans, _state); - copyrealarray(&network1->columnsigmas, &network2->columnsigmas, _state); - copyrealarray(&network1->neurons, &network2->neurons, _state); - copyrealarray(&network1->dfdnet, &network2->dfdnet, _state); - copyrealarray(&network1->derror, &network2->derror, _state); - copyrealarray(&network1->x, &network2->x, _state); - copyrealarray(&network1->y, &network2->y, _state); - copyrealarray(&network1->nwbuf, &network2->nwbuf, _state); - copyintegerarray(&network1->integerbuf, &network2->integerbuf, _state); - - /* - * copy buffers - */ - wcount = mlpgetweightscount(network1, _state); - ae_shared_pool_set_seed(&network2->buf, &buf, sizeof(buf), _mlpbuffers_init, _mlpbuffers_init_copy, _mlpbuffers_destroy, _state); - ae_vector_set_length(&sgrad.g, wcount, _state); - sgrad.f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad.g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_set_seed(&network2->gradbuf, &sgrad, sizeof(sgrad), _smlpgrad_init, _smlpgrad_init_copy, _smlpgrad_destroy, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function compares architectures of neural networks. Only geometries -are compared, weights and other parameters are not tested. - - -- ALGLIB -- - Copyright 20.06.2013 by Bochkanov Sergey -*************************************************************************/ -ae_bool mlpsamearchitecture(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ninfo; - ae_bool result; - - - ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network1 is uninitialized", _state); - ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network2 is uninitialized", _state); - result = ae_false; - if( network1->structinfo.ptr.p_int[0]!=network2->structinfo.ptr.p_int[0] ) - { - return result; - } - ninfo = network1->structinfo.ptr.p_int[0]; - for(i=0; i<=ninfo-1; i++) - { - if( network1->structinfo.ptr.p_int[i]!=network2->structinfo.ptr.p_int[i] ) - { - return result; - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function copies tunable parameters (weights/means/sigmas) from one -network to another with same architecture. It performs some rudimentary -checks that architectures are same, and throws exception if check fails. - -It is intended for fast copying of states between two network which are -known to have same geometry. - -INPUT PARAMETERS: - Network1 - source, must be correctly initialized - Network2 - target, must have same architecture - -OUTPUT PARAMETERS: - Network2 - network state is copied from source to target - - -- ALGLIB -- - Copyright 20.06.2013 by Bochkanov Sergey -*************************************************************************/ -void mlpcopytunableparameters(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ninfo; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - - - ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 is uninitialized", _state); - ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network2 is uninitialized", _state); - ae_assert(network1->structinfo.ptr.p_int[0]==network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); - ninfo = network1->structinfo.ptr.p_int[0]; - for(i=0; i<=ninfo-1; i++) - { - ae_assert(network1->structinfo.ptr.p_int[i]==network2->structinfo.ptr.p_int[i], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); - } - mlpproperties(network1, &nin, &nout, &wcount, _state); - for(i=0; i<=wcount-1; i++) - { - network2->weights.ptr.p_double[i] = network1->weights.ptr.p_double[i]; - } - if( mlpissoftmax(network1, _state) ) - { - for(i=0; i<=nin-1; i++) - { - network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; - network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; - } - } - else - { - for(i=0; i<=nin+nout-1; i++) - { - network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; - network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This function exports tunable parameters (weights/means/sigmas) from -network to contiguous array. Nothing is guaranteed about array format, the -only thing you can count for is that MLPImportTunableParameters() will be -able to parse it. - -It is intended for fast copying of states between network and backup array - -INPUT PARAMETERS: - Network - source, must be correctly initialized - P - array to use. If its size is enough to store data, it - is reused. - -OUTPUT PARAMETERS: - P - array which stores network parameters, resized if needed - PCount - number of parameters stored in array. - - -- ALGLIB -- - Copyright 20.06.2013 by Bochkanov Sergey -*************************************************************************/ -void mlpexporttunableparameters(multilayerperceptron* network, - /* Real */ ae_vector* p, - ae_int_t* pcount, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - - *pcount = 0; - - ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPExportTunableParameters: Network is uninitialized", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - if( mlpissoftmax(network, _state) ) - { - *pcount = wcount+2*nin; - rvectorsetlengthatleast(p, *pcount, _state); - k = 0; - for(i=0; i<=wcount-1; i++) - { - p->ptr.p_double[k] = network->weights.ptr.p_double[i]; - k = k+1; - } - for(i=0; i<=nin-1; i++) - { - p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; - k = k+1; - p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; - k = k+1; - } - } - else - { - *pcount = wcount+2*(nin+nout); - rvectorsetlengthatleast(p, *pcount, _state); - k = 0; - for(i=0; i<=wcount-1; i++) - { - p->ptr.p_double[k] = network->weights.ptr.p_double[i]; - k = k+1; - } - for(i=0; i<=nin+nout-1; i++) - { - p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; - k = k+1; - p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; - k = k+1; - } - } -} - - -/************************************************************************* -This function imports tunable parameters (weights/means/sigmas) which -were exported by MLPExportTunableParameters(). - -It is intended for fast copying of states between network and backup array - -INPUT PARAMETERS: - Network - target: - * must be correctly initialized - * must have same geometry as network used to export params - P - array with parameters - - -- ALGLIB -- - Copyright 20.06.2013 by Bochkanov Sergey -*************************************************************************/ -void mlpimporttunableparameters(multilayerperceptron* network, - /* Real */ ae_vector* p, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - - - ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPImportTunableParameters: Network is uninitialized", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - if( mlpissoftmax(network, _state) ) - { - k = 0; - for(i=0; i<=wcount-1; i++) - { - network->weights.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - } - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - } - } - else - { - k = 0; - for(i=0; i<=wcount-1; i++) - { - network->weights.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - } - for(i=0; i<=nin+nout-1; i++) - { - network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; - k = k+1; - } - } -} - - -/************************************************************************* -Serialization of MultiLayerPerceptron strucure - -INPUT PARAMETERS: - Network - original - -OUTPUT PARAMETERS: - RA - array of real numbers which stores network, - array[0..RLen-1] - RLen - RA length - - -- ALGLIB -- - Copyright 29.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpserializeold(multilayerperceptron* network, - /* Real */ ae_vector* ra, - ae_int_t* rlen, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ssize; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t sigmalen; - ae_int_t offs; - - ae_vector_clear(ra); - *rlen = 0; - - - /* - * Unload info - */ - ssize = network->structinfo.ptr.p_int[0]; - nin = network->structinfo.ptr.p_int[1]; - nout = network->structinfo.ptr.p_int[2]; - wcount = network->structinfo.ptr.p_int[4]; - if( mlpissoftmax(network, _state) ) - { - sigmalen = nin; - } - else - { - sigmalen = nin+nout; - } - - /* - * RA format: - * LEN DESRC. - * 1 RLen - * 1 version (MLPVNum) - * 1 StructInfo size - * SSize StructInfo - * WCount Weights - * SigmaLen ColumnMeans - * SigmaLen ColumnSigmas - */ - *rlen = 3+ssize+wcount+2*sigmalen; - ae_vector_set_length(ra, *rlen-1+1, _state); - ra->ptr.p_double[0] = *rlen; - ra->ptr.p_double[1] = mlpbase_mlpvnum; - ra->ptr.p_double[2] = ssize; - offs = 3; - for(i=0; i<=ssize-1; i++) - { - ra->ptr.p_double[offs+i] = network->structinfo.ptr.p_int[i]; - } - offs = offs+ssize; - ae_v_move(&ra->ptr.p_double[offs], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); - offs = offs+wcount; - ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); - offs = offs+sigmalen; - ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); - offs = offs+sigmalen; -} - - -/************************************************************************* -Unserialization of MultiLayerPerceptron strucure - -INPUT PARAMETERS: - RA - real array which stores network - -OUTPUT PARAMETERS: - Network - restored network - - -- ALGLIB -- - Copyright 29.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpunserializeold(/* Real */ ae_vector* ra, - multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ssize; - ae_int_t ntotal; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t sigmalen; - ae_int_t offs; - - _multilayerperceptron_clear(network); - - ae_assert(ae_round(ra->ptr.p_double[1], _state)==mlpbase_mlpvnum, "MLPUnserialize: incorrect array!", _state); - - /* - * Unload StructInfo from IA - */ - offs = 3; - ssize = ae_round(ra->ptr.p_double[2], _state); - ae_vector_set_length(&network->structinfo, ssize-1+1, _state); - for(i=0; i<=ssize-1; i++) - { - network->structinfo.ptr.p_int[i] = ae_round(ra->ptr.p_double[offs+i], _state); - } - offs = offs+ssize; - - /* - * Unload info from StructInfo - */ - ssize = network->structinfo.ptr.p_int[0]; - nin = network->structinfo.ptr.p_int[1]; - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - wcount = network->structinfo.ptr.p_int[4]; - if( network->structinfo.ptr.p_int[6]==0 ) - { - sigmalen = nin+nout; - } - else - { - sigmalen = nin; - } - - /* - * Allocate space for other fields - */ - ae_vector_set_length(&network->weights, wcount-1+1, _state); - ae_vector_set_length(&network->columnmeans, sigmalen-1+1, _state); - ae_vector_set_length(&network->columnsigmas, sigmalen-1+1, _state); - ae_vector_set_length(&network->neurons, ntotal-1+1, _state); - ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); - ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); - ae_vector_set_length(&network->x, nin-1+1, _state); - ae_vector_set_length(&network->y, nout-1+1, _state); - ae_vector_set_length(&network->derror, ntotal-1+1, _state); - - /* - * Copy parameters from RA - */ - ae_v_move(&network->weights.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,wcount-1)); - offs = offs+wcount; - ae_v_move(&network->columnmeans.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); - offs = offs+sigmalen; - ae_v_move(&network->columnsigmas.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); - offs = offs+sigmalen; -} - - -/************************************************************************* -Randomization of neural network weights - - -- ALGLIB -- - Copyright 06.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlprandomize(multilayerperceptron* network, ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - hqrndstate r; - ae_int_t entrysize; - ae_int_t entryoffs; - ae_int_t neuronidx; - ae_int_t neurontype; - double vmean; - double vvar; - ae_int_t i; - ae_int_t n1; - ae_int_t n2; - double desiredsigma; - ae_int_t montecarlocnt; - double ef; - double ef2; - double v; - double wscale; - - ae_frame_make(_state, &_frame_block); - _hqrndstate_init(&r, _state, ae_true); - - hqrndrandomize(&r, _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - desiredsigma = 0.5; - montecarlocnt = 20; - - /* - * Stage 1: - * * Network.Weights is filled by standard deviation of weights - * * default values: sigma=1 - */ - for(i=0; i<=wcount-1; i++) - { - network->weights.ptr.p_double[i] = 1.0; - } - - /* - * Stage 2: - * * assume that input neurons have zero mean and unit standard deviation - * * assume that constant neurons have zero standard deviation - * * perform forward pass along neurons - * * for each non-input non-constant neuron: - * * calculate mean and standard deviation of neuron's output - * assuming that we know means/deviations of neurons which feed it - * and assuming that weights has unit variance and zero mean. - * * for each nonlinear neuron additionally we perform backward pass: - * * scale variances of weights which feed it in such way that neuron's - * input has unit standard deviation - * - * NOTE: this algorithm assumes that each connection feeds at most one - * non-linear neuron. This assumption can be incorrect in upcoming - * architectures with strong neurons. However, algorithm should - * work smoothly even in this case. - * - * During this stage we use Network.RndBuf, which is grouped into NTotal - * entries, each of them having following format: - * - * Buf[Offset+0] mean value of neuron's output - * Buf[Offset+1] standard deviation of neuron's output - * - * - */ - entrysize = 2; - rvectorsetlengthatleast(&network->rndbuf, entrysize*ntotal, _state); - for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) - { - neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; - entryoffs = entrysize*neuronidx; - if( neurontype==-2 ) - { - - /* - * Input neuron: zero mean, unit variance. - */ - network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; - network->rndbuf.ptr.p_double[entryoffs+1] = 1.0; - continue; - } - if( neurontype==-3 ) - { - - /* - * "-1" neuron: mean=-1, zero variance. - */ - network->rndbuf.ptr.p_double[entryoffs+0] = -1.0; - network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; - continue; - } - if( neurontype==-4 ) - { - - /* - * "0" neuron: mean=0, zero variance. - */ - network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; - network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; - continue; - } - if( neurontype==0 ) - { - - /* - * Adaptive summator neuron: - * * calculate its mean and variance. - * * we assume that weights of this neuron have unit variance and zero mean. - * * thus, neuron's output is always have zero mean - * * as for variance, it is a bit more interesting: - * * let n[i] is i-th input neuron - * * let w[i] is i-th weight - * * we assume that n[i] and w[i] are independently distributed - * * Var(n0*w0+n1*w1+...) = Var(n0*w0)+Var(n1*w1)+... - * * Var(X*Y) = mean(X)^2*Var(Y) + mean(Y)^2*Var(X) + Var(X)*Var(Y) - * * mean(w[i])=0, var(w[i])=1 - * * Var(n[i]*w[i]) = mean(n[i])^2 + Var(n[i]) - */ - n1 = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; - n2 = n1+network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+1]-1; - vmean = 0.0; - vvar = 0.0; - for(i=n1; i<=n2; i++) - { - vvar = vvar+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+0], _state)+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); - } - network->rndbuf.ptr.p_double[entryoffs+0] = vmean; - network->rndbuf.ptr.p_double[entryoffs+1] = ae_sqrt(vvar, _state); - continue; - } - if( neurontype==-5 ) - { - - /* - * Linear activation function - */ - i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; - vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; - vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); - if( ae_fp_greater(vvar,0) ) - { - wscale = desiredsigma/ae_sqrt(vvar, _state); - } - else - { - wscale = 1.0; - } - mlpbase_randomizebackwardpass(network, i, wscale, _state); - network->rndbuf.ptr.p_double[entryoffs+0] = vmean*wscale; - network->rndbuf.ptr.p_double[entryoffs+1] = desiredsigma; - continue; - } - if( neurontype>0 ) - { - - /* - * Nonlinear activation function: - * * scale its inputs - * * estimate mean/sigma of its output using Monte-Carlo method - * (we simulate different inputs with unit deviation and - * sample activation function output on such inputs) - */ - i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; - vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; - vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); - if( ae_fp_greater(vvar,0) ) - { - wscale = desiredsigma/ae_sqrt(vvar, _state); - } - else - { - wscale = 1.0; - } - mlpbase_randomizebackwardpass(network, i, wscale, _state); - ef = 0.0; - ef2 = 0.0; - vmean = vmean*wscale; - for(i=0; i<=montecarlocnt-1; i++) - { - v = vmean+desiredsigma*hqrndnormal(&r, _state); - ef = ef+v; - ef2 = ef2+v*v; - } - ef = ef/montecarlocnt; - ef2 = ef2/montecarlocnt; - network->rndbuf.ptr.p_double[entryoffs+0] = ef; - network->rndbuf.ptr.p_double[entryoffs+1] = ae_maxreal(ef2-ef*ef, 0.0, _state); - continue; - } - ae_assert(ae_false, "MLPRandomize: unexpected neuron type", _state); - } - - /* - * Stage 3: generate weights. - */ - for(i=0; i<=wcount-1; i++) - { - network->weights.ptr.p_double[i] = network->weights.ptr.p_double[i]*hqrndnormal(&r, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Randomization of neural network weights and standartisator - - -- ALGLIB -- - Copyright 10.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlprandomizefull(multilayerperceptron* network, ae_state *_state) -{ - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t offs; - ae_int_t ntype; - - - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Process network - */ - mlprandomize(network, _state); - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = ae_randomreal(_state)-0.5; - network->columnsigmas.ptr.p_double[i] = ae_randomreal(_state)+0.5; - } - if( !mlpissoftmax(network, _state) ) - { - for(i=0; i<=nout-1; i++) - { - offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; - ntype = network->structinfo.ptr.p_int[offs+0]; - if( ntype==0 ) - { - - /* - * Shifts are changed only for linear outputs neurons - */ - network->columnmeans.ptr.p_double[nin+i] = 2*ae_randomreal(_state)-1; - } - if( ntype==0||ntype==3 ) - { - - /* - * Scales are changed only for linear or bounded outputs neurons. - * Note that scale randomization preserves sign. - */ - network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*(1.5*ae_randomreal(_state)+0.5); - } - } - } -} - - -/************************************************************************* -Internal subroutine. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpinitpreprocessor(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t jmax; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t offs; - ae_int_t ntype; - ae_vector means; - ae_vector sigmas; - double s; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&means, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); - - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Means/Sigmas - */ - if( mlpissoftmax(network, _state) ) - { - jmax = nin-1; - } - else - { - jmax = nin+nout-1; - } - ae_vector_set_length(&means, jmax+1, _state); - ae_vector_set_length(&sigmas, jmax+1, _state); - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = 0; - sigmas.ptr.p_double[i] = 0; - } - for(i=0; i<=ssize-1; i++) - { - for(j=0; j<=jmax; j++) - { - means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[i][j]; - } - } - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = means.ptr.p_double[i]/ssize; - } - for(i=0; i<=ssize-1; i++) - { - for(j=0; j<=jmax; j++) - { - sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[i][j]-means.ptr.p_double[j], _state); - } - } - for(i=0; i<=jmax; i++) - { - sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/ssize, _state); - } - - /* - * Inputs - */ - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; - network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],0) ) - { - network->columnsigmas.ptr.p_double[i] = 1; - } - } - - /* - * Outputs - */ - if( !mlpissoftmax(network, _state) ) - { - for(i=0; i<=nout-1; i++) - { - offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; - ntype = network->structinfo.ptr.p_int[offs+0]; - - /* - * Linear outputs - */ - if( ntype==0 ) - { - network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; - network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - - /* - * Bounded outputs (half-interval) - */ - if( ntype==3 ) - { - s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; - if( ae_fp_eq(s,0) ) - { - s = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state); - } - if( ae_fp_eq(s,0) ) - { - s = 1.0; - } - network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. -Initialization for preprocessor based on a sample. - -INPUT - Network - initialized neural network; - XY - sample, given by sparse matrix; - SSize - sample size. - -OUTPUT - Network - neural network with initialised preprocessor. - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpinitpreprocessorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t jmax; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t offs; - ae_int_t ntype; - ae_vector means; - ae_vector sigmas; - double s; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&means, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); - - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Means/Sigmas - */ - if( mlpissoftmax(network, _state) ) - { - jmax = nin-1; - } - else - { - jmax = nin+nout-1; - } - ae_vector_set_length(&means, jmax+1, _state); - ae_vector_set_length(&sigmas, jmax+1, _state); - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = 0; - sigmas.ptr.p_double[i] = 0; - } - for(i=0; i<=ssize-1; i++) - { - sparsegetrow(xy, i, &network->xyrow, _state); - for(j=0; j<=jmax; j++) - { - means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; - } - } - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = means.ptr.p_double[i]/ssize; - } - for(i=0; i<=ssize-1; i++) - { - sparsegetrow(xy, i, &network->xyrow, _state); - for(j=0; j<=jmax; j++) - { - sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); - } - } - for(i=0; i<=jmax; i++) - { - sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/ssize, _state); - } - - /* - * Inputs - */ - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; - network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],0) ) - { - network->columnsigmas.ptr.p_double[i] = 1; - } - } - - /* - * Outputs - */ - if( !mlpissoftmax(network, _state) ) - { - for(i=0; i<=nout-1; i++) - { - offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; - ntype = network->structinfo.ptr.p_int[offs+0]; - - /* - * Linear outputs - */ - if( ntype==0 ) - { - network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; - network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - - /* - * Bounded outputs (half-interval) - */ - if( ntype==3 ) - { - s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; - if( ae_fp_eq(s,0) ) - { - s = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state); - } - if( ae_fp_eq(s,0) ) - { - s = 1.0; - } - network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. -Initialization for preprocessor based on a subsample. - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array. - -OUTPUT: - Network - neural network with initialised preprocessor. - -NOTE: when SubsetSize<0 is used full dataset by call MLPInitPreprocessor - function. - - -- ALGLIB -- - Copyright 23.08.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpinitpreprocessorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t jmax; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t offs; - ae_int_t ntype; - ae_vector means; - ae_vector sigmas; - double s; - ae_int_t npoints; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&means, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); - - ae_assert(setsize>=0, "MLPInitPreprocessorSubset: SetSize<0", _state); - if( subsetsize<0 ) - { - mlpinitpreprocessor(network, xy, setsize, _state); - ae_frame_leave(_state); - return; - } - ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSubset: SubsetSize>Length(Idx)", _state); - npoints = setsize; - for(i=0; i<=subsetsize-1; i++) - { - ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]<0)", _state); - ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); - } - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Means/Sigmas - */ - if( mlpissoftmax(network, _state) ) - { - jmax = nin-1; - } - else - { - jmax = nin+nout-1; - } - ae_vector_set_length(&means, jmax+1, _state); - ae_vector_set_length(&sigmas, jmax+1, _state); - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = 0; - sigmas.ptr.p_double[i] = 0; - } - for(i=0; i<=subsetsize-1; i++) - { - for(j=0; j<=jmax; j++) - { - means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[idx->ptr.p_int[i]][j]; - } - } - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = means.ptr.p_double[i]/subsetsize; - } - for(i=0; i<=subsetsize-1; i++) - { - for(j=0; j<=jmax; j++) - { - sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[idx->ptr.p_int[i]][j]-means.ptr.p_double[j], _state); - } - } - for(i=0; i<=jmax; i++) - { - sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/subsetsize, _state); - } - - /* - * Inputs - */ - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; - network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],0) ) - { - network->columnsigmas.ptr.p_double[i] = 1; - } - } - - /* - * Outputs - */ - if( !mlpissoftmax(network, _state) ) - { - for(i=0; i<=nout-1; i++) - { - offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; - ntype = network->structinfo.ptr.p_int[offs+0]; - - /* - * Linear outputs - */ - if( ntype==0 ) - { - network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; - network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - - /* - * Bounded outputs (half-interval) - */ - if( ntype==3 ) - { - s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; - if( ae_fp_eq(s,0) ) - { - s = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state); - } - if( ae_fp_eq(s,0) ) - { - s = 1.0; - } - network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. -Initialization for preprocessor based on a subsample. - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset, given by sparse matrix; - one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array. - -OUTPUT: - Network - neural network with initialised preprocessor. - -NOTE: when SubsetSize<0 is used full dataset by call - MLPInitPreprocessorSparse function. - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t jmax; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t offs; - ae_int_t ntype; - ae_vector means; - ae_vector sigmas; - double s; - ae_int_t npoints; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&means, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); - - ae_assert(setsize>=0, "MLPInitPreprocessorSparseSubset: SetSize<0", _state); - if( subsetsize<0 ) - { - mlpinitpreprocessorsparse(network, xy, setsize, _state); - ae_frame_leave(_state); - return; - } - ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSparseSubset: SubsetSize>Length(Idx)", _state); - npoints = setsize; - for(i=0; i<=subsetsize-1; i++) - { - ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); - ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); - } - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Means/Sigmas - */ - if( mlpissoftmax(network, _state) ) - { - jmax = nin-1; - } - else - { - jmax = nin+nout-1; - } - ae_vector_set_length(&means, jmax+1, _state); - ae_vector_set_length(&sigmas, jmax+1, _state); - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = 0; - sigmas.ptr.p_double[i] = 0; - } - for(i=0; i<=subsetsize-1; i++) - { - sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); - for(j=0; j<=jmax; j++) - { - means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; - } - } - for(i=0; i<=jmax; i++) - { - means.ptr.p_double[i] = means.ptr.p_double[i]/subsetsize; - } - for(i=0; i<=subsetsize-1; i++) - { - sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); - for(j=0; j<=jmax; j++) - { - sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); - } - } - for(i=0; i<=jmax; i++) - { - sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/subsetsize, _state); - } - - /* - * Inputs - */ - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; - network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],0) ) - { - network->columnsigmas.ptr.p_double[i] = 1; - } - } - - /* - * Outputs - */ - if( !mlpissoftmax(network, _state) ) - { - for(i=0; i<=nout-1; i++) - { - offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; - ntype = network->structinfo.ptr.p_int[offs+0]; - - /* - * Linear outputs - */ - if( ntype==0 ) - { - network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; - network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - - /* - * Bounded outputs (half-interval) - */ - if( ntype==3 ) - { - s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; - if( ae_fp_eq(s,0) ) - { - s = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state); - } - if( ae_fp_eq(s,0) ) - { - s = 1.0; - } - network->columnsigmas.ptr.p_double[nin+i] = ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); - if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],0) ) - { - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns information about initialized network: number of inputs, outputs, -weights. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpproperties(multilayerperceptron* network, - ae_int_t* nin, - ae_int_t* nout, - ae_int_t* wcount, - ae_state *_state) -{ - - *nin = 0; - *nout = 0; - *wcount = 0; - - *nin = network->structinfo.ptr.p_int[1]; - *nout = network->structinfo.ptr.p_int[2]; - *wcount = network->structinfo.ptr.p_int[4]; -} - - -/************************************************************************* -Returns number of "internal", low-level neurons in the network (one which -is stored in StructInfo). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpntotal(multilayerperceptron* network, ae_state *_state) -{ - ae_int_t result; - - - result = network->structinfo.ptr.p_int[3]; - return result; -} - - -/************************************************************************* -Returns number of inputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetinputscount(multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t result; - - - result = network->structinfo.ptr.p_int[1]; - return result; -} - - -/************************************************************************* -Returns number of outputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetoutputscount(multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t result; - - - result = network->structinfo.ptr.p_int[2]; - return result; -} - - -/************************************************************************* -Returns number of weights. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetweightscount(multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t result; - - - result = network->structinfo.ptr.p_int[4]; - return result; -} - - -/************************************************************************* -Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -ae_bool mlpissoftmax(multilayerperceptron* network, ae_state *_state) -{ - ae_bool result; - - - result = network->structinfo.ptr.p_int[6]==1; - return result; -} - - -/************************************************************************* -This function returns total number of layers (including input, hidden and -output layers). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayerscount(multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t result; - - - result = network->hllayersizes.cnt; - return result; -} - - -/************************************************************************* -This function returns size of K-th layer. - -K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. - -Size of the output layer is always equal to the number of outputs, although -when we have softmax-normalized network, last neuron doesn't have any -connections - it is just zero. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayersize(multilayerperceptron* network, - ae_int_t k, - ae_state *_state) -{ - ae_int_t result; - - - ae_assert(k>=0&&khllayersizes.cnt, "MLPGetLayerSize: incorrect layer index", _state); - result = network->hllayersizes.ptr.p_int[k]; - return result; -} - - -/************************************************************************* -This function returns offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetinputscaling(multilayerperceptron* network, - ae_int_t i, - double* mean, - double* sigma, - ae_state *_state) -{ - - *mean = 0; - *sigma = 0; - - ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPGetInputScaling: incorrect (nonexistent) I", _state); - *mean = network->columnmeans.ptr.p_double[i]; - *sigma = network->columnsigmas.ptr.p_double[i]; - if( ae_fp_eq(*sigma,0) ) - { - *sigma = 1; - } -} - - -/************************************************************************* -This function returns offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. In case we have SOFTMAX-normalized network, -we return (Mean,Sigma)=(0.0,1.0). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetoutputscaling(multilayerperceptron* network, - ae_int_t i, - double* mean, - double* sigma, - ae_state *_state) -{ - - *mean = 0; - *sigma = 0; - - ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPGetOutputScaling: incorrect (nonexistent) I", _state); - if( network->structinfo.ptr.p_int[6]==1 ) - { - *mean = 0; - *sigma = 1; - } - else - { - *mean = network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; - *sigma = network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; - } -} - - -/************************************************************************* -This function returns information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - -OUTPUT PARAMETERS: - FKind - activation function type (used by MLPActivationFunction()) - this value is zero for input or linear neurons - Threshold - also called offset, bias - zero for input neurons - -NOTE: this function throws exception if layer or neuron with given index -do not exists. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetneuroninfo(multilayerperceptron* network, - ae_int_t k, - ae_int_t i, - ae_int_t* fkind, - double* threshold, - ae_state *_state) -{ - ae_int_t ncnt; - ae_int_t istart; - ae_int_t highlevelidx; - ae_int_t activationoffset; - - *fkind = 0; - *threshold = 0; - - ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; - istart = network->structinfo.ptr.p_int[5]; - - /* - * search - */ - network->integerbuf.ptr.p_int[0] = k; - network->integerbuf.ptr.p_int[1] = i; - highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, &network->integerbuf, _state); - ae_assert(highlevelidx>=0, "MLPGetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); - - /* - * 1. find offset of the activation function record in the - */ - if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) - { - activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; - *fkind = network->structinfo.ptr.p_int[activationoffset+0]; - } - else - { - *fkind = 0; - } - if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) - { - *threshold = network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]]; - } - else - { - *threshold = 0; - } -} - - -/************************************************************************* -This function returns information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - -RESULT: - connection weight (zero for non-existent connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. returns zero if neurons exist, but there is no connection between them - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -double mlpgetweight(multilayerperceptron* network, - ae_int_t k0, - ae_int_t i0, - ae_int_t k1, - ae_int_t i1, - ae_state *_state) -{ - ae_int_t ccnt; - ae_int_t highlevelidx; - double result; - - - ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; - - /* - * check params - */ - ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K0", _state); - ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPGetWeight: incorrect (nonexistent) I0", _state); - ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K1", _state); - ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPGetWeight: incorrect (nonexistent) I1", _state); - - /* - * search - */ - network->integerbuf.ptr.p_int[0] = k0; - network->integerbuf.ptr.p_int[1] = i0; - network->integerbuf.ptr.p_int[2] = k1; - network->integerbuf.ptr.p_int[3] = i1; - highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, &network->integerbuf, _state); - if( highlevelidx>=0 ) - { - result = network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]]; - } - else - { - result = 0; - } - return result; -} - - -/************************************************************************* -This function sets offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -NTE: I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network. This function sets Mean and Sigma. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetinputscaling(multilayerperceptron* network, - ae_int_t i, - double mean, - double sigma, - ae_state *_state) -{ - - - ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPSetInputScaling: incorrect (nonexistent) I", _state); - ae_assert(ae_isfinite(mean, _state), "MLPSetInputScaling: infinite or NAN Mean", _state); - ae_assert(ae_isfinite(sigma, _state), "MLPSetInputScaling: infinite or NAN Sigma", _state); - if( ae_fp_eq(sigma,0) ) - { - sigma = 1; - } - network->columnmeans.ptr.p_double[i] = mean; - network->columnsigmas.ptr.p_double[i] = sigma; -} - - -/************************************************************************* -This function sets offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -OUTPUT PARAMETERS: - -NOTE: I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. This function sets Sigma/Mean. In case we -have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything -other than(0.0,1.0) - this function will throw exception. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetoutputscaling(multilayerperceptron* network, - ae_int_t i, - double mean, - double sigma, - ae_state *_state) -{ - - - ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPSetOutputScaling: incorrect (nonexistent) I", _state); - ae_assert(ae_isfinite(mean, _state), "MLPSetOutputScaling: infinite or NAN Mean", _state); - ae_assert(ae_isfinite(sigma, _state), "MLPSetOutputScaling: infinite or NAN Sigma", _state); - if( network->structinfo.ptr.p_int[6]==1 ) - { - ae_assert(ae_fp_eq(mean,0), "MLPSetOutputScaling: you can not set non-zero Mean term for classifier network", _state); - ae_assert(ae_fp_eq(sigma,1), "MLPSetOutputScaling: you can not set non-unit Sigma term for classifier network", _state); - } - else - { - if( ae_fp_eq(sigma,0) ) - { - sigma = 1; - } - network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = mean; - network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = sigma; - } -} - - -/************************************************************************* -This function modifies information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - FKind - activation function type (used by MLPActivationFunction()) - this value must be zero for input neurons - (you can not set activation function for input neurons) - Threshold - also called offset, bias - this value must be zero for input neurons - (you can not set threshold for input neurons) - -NOTES: -1. this function throws exception if layer or neuron with given index do - not exists. -2. this function also throws exception when you try to set non-linear - activation function for input neurons (any kind of network) or for output - neurons of classifier network. -3. this function throws exception when you try to set non-zero threshold for - input neurons (any kind of network). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetneuroninfo(multilayerperceptron* network, - ae_int_t k, - ae_int_t i, - ae_int_t fkind, - double threshold, - ae_state *_state) -{ - ae_int_t ncnt; - ae_int_t istart; - ae_int_t highlevelidx; - ae_int_t activationoffset; - - - ae_assert(ae_isfinite(threshold, _state), "MLPSetNeuronInfo: infinite or NAN Threshold", _state); - - /* - * convenience vars - */ - ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; - istart = network->structinfo.ptr.p_int[5]; - - /* - * search - */ - network->integerbuf.ptr.p_int[0] = k; - network->integerbuf.ptr.p_int[1] = i; - highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, &network->integerbuf, _state); - ae_assert(highlevelidx>=0, "MLPSetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); - - /* - * activation function - */ - if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) - { - activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; - network->structinfo.ptr.p_int[activationoffset+0] = fkind; - } - else - { - ae_assert(fkind==0, "MLPSetNeuronInfo: you try to set activation function for neuron which can not have one", _state); - } - - /* - * Threshold - */ - if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) - { - network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]] = threshold; - } - else - { - ae_assert(ae_fp_eq(threshold,0), "MLPSetNeuronInfo: you try to set non-zero threshold for neuron which can not have one", _state); - } -} - - -/************************************************************************* -This function modifies information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - W - connection weight (must be zero for non-existent - connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. throws exception if you try to set non-zero weight for non-existent - connection - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetweight(multilayerperceptron* network, - ae_int_t k0, - ae_int_t i0, - ae_int_t k1, - ae_int_t i1, - double w, - ae_state *_state) -{ - ae_int_t ccnt; - ae_int_t highlevelidx; - - - ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; - - /* - * check params - */ - ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K0", _state); - ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPSetWeight: incorrect (nonexistent) I0", _state); - ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K1", _state); - ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPSetWeight: incorrect (nonexistent) I1", _state); - ae_assert(ae_isfinite(w, _state), "MLPSetWeight: infinite or NAN weight", _state); - - /* - * search - */ - network->integerbuf.ptr.p_int[0] = k0; - network->integerbuf.ptr.p_int[1] = i0; - network->integerbuf.ptr.p_int[2] = k1; - network->integerbuf.ptr.p_int[3] = i1; - highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, &network->integerbuf, _state); - if( highlevelidx>=0 ) - { - network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]] = w; - } - else - { - ae_assert(ae_fp_eq(w,0), "MLPSetWeight: you try to set non-zero weight for non-existent connection", _state); - } -} - - -/************************************************************************* -Neural network activation function - -INPUT PARAMETERS: - NET - neuron input - K - function index (zero for linear function) - -OUTPUT PARAMETERS: - F - function - DF - its derivative - D2F - its second derivative - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpactivationfunction(double net, - ae_int_t k, - double* f, - double* df, - double* d2f, - ae_state *_state) -{ - double net2; - double arg; - double root; - double r; - - *f = 0; - *df = 0; - *d2f = 0; - - if( k==0||k==-5 ) - { - *f = net; - *df = 1; - *d2f = 0; - return; - } - if( k==1 ) - { - - /* - * TanH activation function - */ - if( ae_fp_less(ae_fabs(net, _state),100) ) - { - *f = ae_tanh(net, _state); - } - else - { - *f = ae_sign(net, _state); - } - *df = 1-*f*(*f); - *d2f = -2*(*f)*(*df); - return; - } - if( k==3 ) - { - - /* - * EX activation function - */ - if( ae_fp_greater_eq(net,0) ) - { - net2 = net*net; - arg = net2+1; - root = ae_sqrt(arg, _state); - *f = net+root; - r = net/root; - *df = 1+r; - *d2f = (root-net*r)/arg; - } - else - { - *f = ae_exp(net, _state); - *df = *f; - *d2f = *f; - } - return; - } - if( k==2 ) - { - *f = ae_exp(-ae_sqr(net, _state), _state); - *df = -2*net*(*f); - *d2f = -2*(*f+*df*net); - return; - } - *f = 0; - *df = 0; - *d2f = 0; -} - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Network - neural network - X - input vector, array[0..NIn-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also MLPProcessI - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpprocess(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - - if( y->cntstructinfo.ptr.p_int[2] ) - { - ae_vector_set_length(y, network->structinfo.ptr.p_int[2], _state); - } - mlpinternalprocessvector(&network->structinfo, &network->weights, &network->columnmeans, &network->columnsigmas, &network->neurons, &network->dfdnet, x, y, _state); -} - - -/************************************************************************* -'interactive' variant of MLPProcess for languages like Python which -support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 21.09.2010 by Bochkanov Sergey -*************************************************************************/ -void mlpprocessi(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - ae_vector_clear(y); - - mlpprocess(network, x, y, _state); -} - - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPError: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = ae_sqr(network->err.rmserror, _state)*npoints*mlpgetoutputscount(network, _state)/2; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlperror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlperror(network,xy,npoints, _state); -} - - -/************************************************************************* -Error of the neural network on dataset given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0 - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPErrorSparse: XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPErrorSparse: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparse: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparse: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = ae_sqr(network->err.rmserror, _state)*npoints*mlpgetoutputscount(network, _state)/2; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlperrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlperrorsparse(network,xy,npoints, _state); -} - - -/************************************************************************* -Natural error function for neural network, internal subroutine. - -NOTE: this function is single-threaded. Unlike other error function, it -receives no speed-up from being executed in SMP mode. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperrorn(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - double e; - double result; - - - mlpproperties(network, &nin, &nout, &wcount, _state); - result = 0; - for(i=0; i<=ssize-1; i++) - { - - /* - * Process vector - */ - ae_v_move(&network->x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); - mlpprocess(network, &network->x, &network->y, _state); - - /* - * Update error function - */ - if( network->structinfo.ptr.p_int[6]==0 ) - { - - /* - * Least squares error function - */ - ae_v_sub(&network->y.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1)); - e = ae_v_dotproduct(&network->y.ptr.p_double[0], 1, &network->y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); - result = result+e/2; - } - else - { - - /* - * Cross-entropy error function - */ - k = ae_round(xy->ptr.pp_double[i][nin], _state); - if( k>=0&&ky.ptr.p_double[k], _state); - } - } - } - return result; -} - - -/************************************************************************* -Classification error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - classification error (number of misclassified cases) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_int_t result; - - - ae_assert(xy->rows>=npoints, "MLPClsError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPClsError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPClsError: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = ae_round(npoints*network->err.relclserror, _state); - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -ae_int_t _pexec_mlpclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpclserror(network,xy,npoints, _state); -} - - -/************************************************************************* -Relative classification error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 25.12.2008 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPRelClsError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRelClsError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsError: XY has less than NIn+NOut columns", _state); - } - } - if( npoints>0 ) - { - result = (double)mlpclserror(network, xy, npoints, _state)/(double)npoints; - } - else - { - result = 0.0; - } - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlprelclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlprelclserror(network,xy,npoints, _state); -} - - -/************************************************************************* -Relative classification error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. Sparse matrix must use CRS format - for storage. - NPoints - points count, >=0. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPRelClsErrorSparse: sparse matrix XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRelClsErrorSparse: sparse matrix XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.relclserror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlprelclserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlprelclserrorsparse(network,xy,npoints, _state); -} - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 08.01.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpavgce(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPAvgCE: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgCE: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCE: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgce; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgce(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgce(network,xy,npoints, _state); -} - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set given by -sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 9.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgcesparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPAvgCESparse: sparse matrix XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgCESparse: sparse matrix XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgCESparse: sparse matrix XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCESparse: sparse matrix XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgce; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgcesparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgcesparse(network,xy,npoints, _state); -} - - -/************************************************************************* -RMS error on the test set given. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlprmserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPRMSError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRMSError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSError: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.rmserror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlprmserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlprmserror(network,xy,npoints, _state); -} - - -/************************************************************************* -RMS error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprmserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPRMSErrorSparse: sparse matrix XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRMSErrorSparse: sparse matrix XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRMSErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.rmserror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlprmserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlprmserrorsparse(network,xy,npoints, _state); -} - - -/************************************************************************* -Average absolute error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPAvgError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgError: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgerror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgerror(network,xy,npoints, _state); -} - - -/************************************************************************* -Average absolute error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPAvgErrorSparse: XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgErrorSparse: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgErrorSparse: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgErrorSparse: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgerror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgerrorsparse(network,xy,npoints, _state); -} - - -/************************************************************************* -Average relative error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(xy->rows>=npoints, "MLPAvgRelError: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgRelError: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelError: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgrelerror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgrelerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgrelerror(network,xy,npoints, _state); -} - - -/************************************************************************* -Average relative error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPAvgRelErrorSparse: XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgRelErrorSparse: XY has less than NPoints rows", _state); - if( npoints>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgRelErrorSparse: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelErrorSparse: XY has less than NIn+NOut columns", _state); - } - } - mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); - result = network->err.avgrelerror; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlpavgrelerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state) -{ - return mlpavgrelerrorsparse(network,xy,npoints, _state); -} - - -/************************************************************************* -Gradient calculation - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgrad(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* desiredy, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_int_t i; - ae_int_t nout; - ae_int_t ntotal; - - *e = 0; - - - /* - * Alloc - */ - rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); - - /* - * Prepare dError/dOut, internal structures - */ - mlpprocess(network, x, &network->y, _state); - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - *e = 0; - for(i=0; i<=ntotal-1; i++) - { - network->derror.ptr.p_double[i] = 0; - } - for(i=0; i<=nout-1; i++) - { - network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; - *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/2; - } - - /* - * gradient - */ - mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_false, _state); -} - - -/************************************************************************* -Gradient calculation (natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradn(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* desiredy, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - double s; - ae_int_t i; - ae_int_t nout; - ae_int_t ntotal; - - *e = 0; - - - /* - * Alloc - */ - rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); - - /* - * Prepare dError/dOut, internal structures - */ - mlpprocess(network, x, &network->y, _state); - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - for(i=0; i<=ntotal-1; i++) - { - network->derror.ptr.p_double[i] = 0; - } - *e = 0; - if( network->structinfo.ptr.p_int[6]==0 ) - { - - /* - * Regression network, least squares - */ - for(i=0; i<=nout-1; i++) - { - network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; - *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/2; - } - } - else - { - - /* - * Classification network, cross-entropy - */ - s = 0; - for(i=0; i<=nout-1; i++) - { - s = s+desiredy->ptr.p_double[i]; - } - for(i=0; i<=nout-1; i++) - { - network->derror.ptr.p_double[ntotal-nout+i] = s*network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; - *e = *e+mlpbase_safecrossentropy(desiredy->ptr.p_double[i], network->y.ptr.p_double[i], _state); - } - } - - /* - * gradient - */ - mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_true, _state); -} - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t subset0; - ae_int_t subset1; - ae_int_t subsettype; - smlpgrad *sgrad; - ae_smart_ptr _sgrad; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state, ae_true); - - ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); - subset0 = 0; - subset1 = ssize; - subsettype = 0; - mlpproperties(network, &nin, &nout, &wcount, _state); - rvectorsetlengthatleast(grad, wcount, _state); - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - sgrad->f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad->g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - mlpgradbatchx(network, xy, &network->dummysxy, ssize, 0, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); - *e = 0.0; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = 0.0; - } - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - *e = *e+sgrad->f; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpgradbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state) -{ - mlpgradbatch(network,xy,ssize,e,grad, _state); -} - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs given by sparse -matrices - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs. - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t subset0; - ae_int_t subset1; - ae_int_t subsettype; - smlpgrad *sgrad; - ae_smart_ptr _sgrad; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state, ae_true); - - ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); - ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparse: sparse matrix XY must be in CRS format.", _state); - subset0 = 0; - subset1 = ssize; - subsettype = 0; - mlpproperties(network, &nin, &nout, &wcount, _state); - rvectorsetlengthatleast(grad, wcount, _state); - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - sgrad->f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad->g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - mlpgradbatchx(network, &network->dummydxy, xy, ssize, 1, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); - *e = 0.0; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = 0.0; - } - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - *e = *e+sgrad->f; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpgradbatchsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state) -{ - mlpgradbatchsparse(network,xy,ssize,e,grad, _state); -} - - -/************************************************************************* -Batch gradient calculation for a subset of dataset - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t npoints; - ae_int_t subset0; - ae_int_t subset1; - ae_int_t subsettype; - smlpgrad *sgrad; - ae_smart_ptr _sgrad; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state, ae_true); - - ae_assert(setsize>=0, "MLPGradBatchSubset: SetSize<0", _state); - ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSubset: SubsetSize>Length(Idx)", _state); - npoints = setsize; - if( subsetsize<0 ) - { - subset0 = 0; - subset1 = setsize; - subsettype = 0; - } - else - { - subset0 = 0; - subset1 = subsetsize; - subsettype = 1; - for(i=0; i<=subsetsize-1; i++) - { - ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]<0)", _state); - ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); - } - } - mlpproperties(network, &nin, &nout, &wcount, _state); - rvectorsetlengthatleast(grad, wcount, _state); - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - sgrad->f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad->g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - mlpgradbatchx(network, xy, &network->dummysxy, setsize, 0, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); - *e = 0.0; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = 0.0; - } - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - *e = *e+sgrad->f; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpgradbatchsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state) -{ - mlpgradbatchsubset(network,xy,setsize,idx,subsetsize,e,grad, _state); -} - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs for a subset of -dataset given by set of indexes. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse - function. - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t npoints; - ae_int_t subset0; - ae_int_t subset1; - ae_int_t subsettype; - smlpgrad *sgrad; - ae_smart_ptr _sgrad; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state, ae_true); - - ae_assert(setsize>=0, "MLPGradBatchSparseSubset: SetSize<0", _state); - ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSparseSubset: SubsetSize>Length(Idx)", _state); - ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparseSubset: sparse matrix XY must be in CRS format.", _state); - npoints = setsize; - if( subsetsize<0 ) - { - subset0 = 0; - subset1 = setsize; - subsettype = 0; - } - else - { - subset0 = 0; - subset1 = subsetsize; - subsettype = 1; - for(i=0; i<=subsetsize-1; i++) - { - ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); - ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); - } - } - mlpproperties(network, &nin, &nout, &wcount, _state); - rvectorsetlengthatleast(grad, wcount, _state); - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - sgrad->f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad->g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - mlpgradbatchx(network, &network->dummydxy, xy, setsize, 1, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); - *e = 0.0; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = 0.0; - } - ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); - while(sgrad!=NULL) - { - *e = *e+sgrad->f; - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; - } - ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpgradbatchsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state) -{ - mlpgradbatchsparsesubset(network,xy,setsize,idx,subsetsize,e,grad, _state); -} - - -void mlpgradbatchx(multilayerperceptron* network, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - ae_shared_pool* gradbuf, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t rowsize; - ae_int_t srcidx; - ae_int_t cstart; - ae_int_t csize; - ae_int_t j; - double problemcost; - mlpbuffers *buf2; - ae_smart_ptr _buf2; - ae_int_t len0; - ae_int_t len1; - mlpbuffers *pbuf; - ae_smart_ptr _pbuf; - smlpgrad *sgrad; - ae_smart_ptr _sgrad; - - ae_frame_make(_state, &_frame_block); - ae_smart_ptr_init(&_buf2, (void**)&buf2, _state, ae_true); - ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true); - ae_smart_ptr_init(&_sgrad, (void**)&sgrad, _state, ae_true); - - ae_assert(datasetsize>=0, "MLPGradBatchX: SetSize<0", _state); - ae_assert(datasettype==0||datasettype==1, "MLPGradBatchX: DatasetType is incorrect", _state); - ae_assert(subsettype==0||subsettype==1, "MLPGradBatchX: SubsetType is incorrect", _state); - - /* - * Determine network and dataset properties - */ - mlpproperties(network, &nin, &nout, &wcount, _state); - if( mlpissoftmax(network, _state) ) - { - rowsize = nin+1; - } - else - { - rowsize = nin+nout; - } - - /* - * Split problem. - * - * Splitting problem allows us to reduce effect of single-precision - * arithmetics (SSE-optimized version of MLPChunkedGradient uses single - * precision internally, but converts them to double precision after - * results are exported from HPC buffer to network). Small batches are - * calculated in single precision, results are aggregated in double - * precision, and it allows us to avoid accumulation of errors when - * we process very large batches (tens of thousands of items). - * - * NOTE: it is important to use real arithmetics for ProblemCost - * because ProblemCost may be larger than MAXINT. - */ - problemcost = subset1-subset0; - problemcost = problemcost*wcount; - if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(problemcost,mlpbase_gradbasecasecost) ) - { - splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); - mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, gradbuf, _state); - mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, gradbuf, _state); - ae_frame_leave(_state); - return; - } - - /* - * Chunked processing - */ - ae_shared_pool_retrieve(gradbuf, &_sgrad, _state); - ae_shared_pool_retrieve(buf, &_pbuf, _state); - hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); - cstart = subset0; - while(cstartchunksize, _state)-cstart; - for(j=0; j<=csize-1; j++) - { - srcidx = -1; - if( subsettype==0 ) - { - srcidx = cstart+j; - } - if( subsettype==1 ) - { - srcidx = idx->ptr.p_int[cstart+j]; - } - ae_assert(srcidx>=0, "MLPGradBatchX: internal error", _state); - if( datasettype==0 ) - { - ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); - } - if( datasettype==1 ) - { - sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); - ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); - } - } - - /* - * Process chunk and advance line pointer - */ - mlpbase_mlpchunkedgradient(network, &pbuf->xy, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, &sgrad->f, ae_false, _state); - cstart = cstart+pbuf->chunksize; - } - hpcfinalizechunkedgradient(pbuf, &sgrad->g, _state); - ae_shared_pool_recycle(buf, &_pbuf, _state); - ae_shared_pool_recycle(gradbuf, &_sgrad, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs -(natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - set of inputs/outputs; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradnbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - mlpbuffers *pbuf; - ae_smart_ptr _pbuf; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true); - - - /* - * Alloc - */ - mlpproperties(network, &nin, &nout, &wcount, _state); - ae_shared_pool_retrieve(&network->buf, &_pbuf, _state); - hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); - rvectorsetlengthatleast(grad, wcount, _state); - for(i=0; i<=wcount-1; i++) - { - grad->ptr.p_double[i] = 0; - } - *e = 0; - i = 0; - while(i<=ssize-1) - { - mlpbase_mlpchunkedgradient(network, xy, i, ae_minint(ssize, i+pbuf->chunksize, _state)-i, &pbuf->batch4buf, &pbuf->hpcbuf, e, ae_true, _state); - i = i+pbuf->chunksize; - } - hpcfinalizechunkedgradient(pbuf, grad, _state); - ae_shared_pool_recycle(&network->buf, &_pbuf, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Batch Hessian calculation (natural error function) using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessiannbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state) -{ - - *e = 0; - - mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_true, e, grad, h, _state); -} - - -/************************************************************************* -Batch Hessian calculation using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessianbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state) -{ - - *e = 0; - - mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_false, e, grad, h, _state); -} - - -/************************************************************************* -Internal subroutine, shouldn't be called by user. -*************************************************************************/ -void mlpinternalprocessvector(/* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* weights, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_vector* neurons, - /* Real */ ae_vector* dfdnet, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n1; - ae_int_t n2; - ae_int_t w1; - ae_int_t w2; - ae_int_t ntotal; - ae_int_t nin; - ae_int_t nout; - ae_int_t istart; - ae_int_t offs; - double net; - double f; - double df; - double d2f; - double mx; - ae_bool perr; - - - - /* - * Read network geometry - */ - nin = structinfo->ptr.p_int[1]; - nout = structinfo->ptr.p_int[2]; - ntotal = structinfo->ptr.p_int[3]; - istart = structinfo->ptr.p_int[5]; - - /* - * Inputs standartisation and putting in the network - */ - for(i=0; i<=nin-1; i++) - { - if( ae_fp_neq(columnsigmas->ptr.p_double[i],0) ) - { - neurons->ptr.p_double[i] = (x->ptr.p_double[i]-columnmeans->ptr.p_double[i])/columnsigmas->ptr.p_double[i]; - } - else - { - neurons->ptr.p_double[i] = x->ptr.p_double[i]-columnmeans->ptr.p_double[i]; - } - } - - /* - * Process network - */ - for(i=0; i<=ntotal-1; i++) - { - offs = istart+i*mlpbase_nfieldwidth; - if( structinfo->ptr.p_int[offs+0]>0||structinfo->ptr.p_int[offs+0]==-5 ) - { - - /* - * Activation function - */ - mlpactivationfunction(neurons->ptr.p_double[structinfo->ptr.p_int[offs+2]], structinfo->ptr.p_int[offs+0], &f, &df, &d2f, _state); - neurons->ptr.p_double[i] = f; - dfdnet->ptr.p_double[i] = df; - continue; - } - if( structinfo->ptr.p_int[offs+0]==0 ) - { - - /* - * Adaptive summator - */ - n1 = structinfo->ptr.p_int[offs+2]; - n2 = n1+structinfo->ptr.p_int[offs+1]-1; - w1 = structinfo->ptr.p_int[offs+3]; - w2 = w1+structinfo->ptr.p_int[offs+1]-1; - net = ae_v_dotproduct(&weights->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2)); - neurons->ptr.p_double[i] = net; - dfdnet->ptr.p_double[i] = 1.0; - touchint(&n2, _state); - continue; - } - if( structinfo->ptr.p_int[offs+0]<0 ) - { - perr = ae_true; - if( structinfo->ptr.p_int[offs+0]==-2 ) - { - - /* - * input neuron, left unchanged - */ - perr = ae_false; - } - if( structinfo->ptr.p_int[offs+0]==-3 ) - { - - /* - * "-1" neuron - */ - neurons->ptr.p_double[i] = -1; - perr = ae_false; - } - if( structinfo->ptr.p_int[offs+0]==-4 ) - { - - /* - * "0" neuron - */ - neurons->ptr.p_double[i] = 0; - perr = ae_false; - } - ae_assert(!perr, "MLPInternalProcessVector: internal error - unknown neuron type!", _state); - continue; - } - } - - /* - * Extract result - */ - ae_v_move(&y->ptr.p_double[0], 1, &neurons->ptr.p_double[ntotal-nout], 1, ae_v_len(0,nout-1)); - - /* - * Softmax post-processing or standardisation if needed - */ - ae_assert(structinfo->ptr.p_int[6]==0||structinfo->ptr.p_int[6]==1, "MLPInternalProcessVector: unknown normalization type!", _state); - if( structinfo->ptr.p_int[6]==1 ) - { - - /* - * Softmax - */ - mx = y->ptr.p_double[0]; - for(i=1; i<=nout-1; i++) - { - mx = ae_maxreal(mx, y->ptr.p_double[i], _state); - } - net = 0; - for(i=0; i<=nout-1; i++) - { - y->ptr.p_double[i] = ae_exp(y->ptr.p_double[i]-mx, _state); - net = net+y->ptr.p_double[i]; - } - for(i=0; i<=nout-1; i++) - { - y->ptr.p_double[i] = y->ptr.p_double[i]/net; - } - } - else - { - - /* - * Standardisation - */ - for(i=0; i<=nout-1; i++) - { - y->ptr.p_double[i] = y->ptr.p_double[i]*columnsigmas->ptr.p_double[nin+i]+columnmeans->ptr.p_double[nin+i]; - } - } -} - - -/************************************************************************* -Serializer: allocation - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpalloc(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t fkind; - double threshold; - double v0; - double v1; - ae_int_t nin; - ae_int_t nout; - - - nin = network->hllayersizes.ptr.p_int[0]; - nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - allocintegerarray(s, &network->hllayersizes, -1, _state); - for(i=1; i<=network->hllayersizes.cnt-1; i++) - { - for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) - { - mlpgetneuroninfo(network, i, j, &fkind, &threshold, _state); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) - { - ae_serializer_alloc_entry(s); - } - } - } - for(j=0; j<=nin-1; j++) - { - mlpgetinputscaling(network, j, &v0, &v1, _state); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - } - for(j=0; j<=nout-1; j++) - { - mlpgetoutputscaling(network, j, &v0, &v1, _state); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - } -} - - -/************************************************************************* -Serializer: serialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpserialize(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t fkind; - double threshold; - double v0; - double v1; - ae_int_t nin; - ae_int_t nout; - - - nin = network->hllayersizes.ptr.p_int[0]; - nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; - ae_serializer_serialize_int(s, getmlpserializationcode(_state), _state); - ae_serializer_serialize_int(s, mlpbase_mlpfirstversion, _state); - ae_serializer_serialize_bool(s, mlpissoftmax(network, _state), _state); - serializeintegerarray(s, &network->hllayersizes, -1, _state); - for(i=1; i<=network->hllayersizes.cnt-1; i++) - { - for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) - { - mlpgetneuroninfo(network, i, j, &fkind, &threshold, _state); - ae_serializer_serialize_int(s, fkind, _state); - ae_serializer_serialize_double(s, threshold, _state); - for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) - { - ae_serializer_serialize_double(s, mlpgetweight(network, i-1, k, i, j, _state), _state); - } - } - } - for(j=0; j<=nin-1; j++) - { - mlpgetinputscaling(network, j, &v0, &v1, _state); - ae_serializer_serialize_double(s, v0, _state); - ae_serializer_serialize_double(s, v1, _state); - } - for(j=0; j<=nout-1; j++) - { - mlpgetoutputscaling(network, j, &v0, &v1, _state); - ae_serializer_serialize_double(s, v0, _state); - ae_serializer_serialize_double(s, v1, _state); - } -} - - -/************************************************************************* -Serializer: unserialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpunserialize(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i0; - ae_int_t i1; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t fkind; - double threshold; - double v0; - double v1; - ae_int_t nin; - ae_int_t nout; - ae_bool issoftmax; - ae_vector layersizes; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&layersizes, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of header - */ - ae_serializer_unserialize_int(s, &i0, _state); - ae_assert(i0==getmlpserializationcode(_state), "MLPUnserialize: stream header corrupted", _state); - ae_serializer_unserialize_int(s, &i1, _state); - ae_assert(i1==mlpbase_mlpfirstversion, "MLPUnserialize: stream header corrupted", _state); - - /* - * Create network - */ - ae_serializer_unserialize_bool(s, &issoftmax, _state); - unserializeintegerarray(s, &layersizes, _state); - ae_assert((layersizes.cnt==2||layersizes.cnt==3)||layersizes.cnt==4, "MLPUnserialize: too many hidden layers!", _state); - nin = layersizes.ptr.p_int[0]; - nout = layersizes.ptr.p_int[layersizes.cnt-1]; - if( layersizes.cnt==2 ) - { - if( issoftmax ) - { - mlpcreatec0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); - } - else - { - mlpcreate0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); - } - } - if( layersizes.cnt==3 ) - { - if( issoftmax ) - { - mlpcreatec1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); - } - else - { - mlpcreate1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); - } - } - if( layersizes.cnt==4 ) - { - if( issoftmax ) - { - mlpcreatec2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); - } - else - { - mlpcreate2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); - } - } - - /* - * Load neurons and weights - */ - for(i=1; i<=layersizes.cnt-1; i++) - { - for(j=0; j<=layersizes.ptr.p_int[i]-1; j++) - { - ae_serializer_unserialize_int(s, &fkind, _state); - ae_serializer_unserialize_double(s, &threshold, _state); - mlpsetneuroninfo(network, i, j, fkind, threshold, _state); - for(k=0; k<=layersizes.ptr.p_int[i-1]-1; k++) - { - ae_serializer_unserialize_double(s, &v0, _state); - mlpsetweight(network, i-1, k, i, j, v0, _state); - } - } - } - - /* - * Load standartizator - */ - for(j=0; j<=nin-1; j++) - { - ae_serializer_unserialize_double(s, &v0, _state); - ae_serializer_unserialize_double(s, &v1, _state); - mlpsetinputscaling(network, j, v0, v1, _state); - } - for(j=0; j<=nout-1; j++) - { - ae_serializer_unserialize_double(s, &v0, _state); - ae_serializer_unserialize_double(s, &v1, _state); - mlpsetoutputscaling(network, j, v0, v1, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Calculation of all types of errors. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, - ae_state *_state) -{ - ae_int_t idx0; - ae_int_t idx1; - ae_int_t idxtype; - - _modelerrors_clear(rep); - - ae_assert(xy->rows>=setsize, "MLPAllErrorsSubset: XY has less than SetSize rows", _state); - if( setsize>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSubset: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSubset: XY has less than NIn+NOut columns", _state); - } - } - if( subsetsize>=0 ) - { - idx0 = 0; - idx1 = subsetsize; - idxtype = 1; - } - else - { - idx0 = 0; - idx1 = setsize; - idxtype = 0; - } - mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, rep, _state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpallerrorssubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, ae_state *_state) -{ - mlpallerrorssubset(network,xy,setsize,subset,subsetsize,rep, _state); -} - - -/************************************************************************* -Calculation of all types of errors on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset given by sparse matrix; - one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, - ae_state *_state) -{ - ae_int_t idx0; - ae_int_t idx1; - ae_int_t idxtype; - - _modelerrors_clear(rep); - - ae_assert(sparseiscrs(xy, _state), "MLPAllErrorsSparseSubset: XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPAllErrorsSparseSubset: XY has less than SetSize rows", _state); - if( setsize>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSparseSubset: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSparseSubset: XY has less than NIn+NOut columns", _state); - } - } - if( subsetsize>=0 ) - { - idx0 = 0; - idx1 = subsetsize; - idxtype = 1; - } - else - { - idx0 = 0; - idx1 = setsize; - idxtype = 0; - } - mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, rep, _state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpallerrorssparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, ae_state *_state) -{ - mlpallerrorssparsesubset(network,xy,setsize,subset,subsetsize,rep, _state); -} - - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_state *_state) -{ - ae_int_t idx0; - ae_int_t idx1; - ae_int_t idxtype; - double result; - - - ae_assert(xy->rows>=setsize, "MLPErrorSubset: XY has less than SetSize rows", _state); - if( setsize>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPErrorSubset: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSubset: XY has less than NIn+NOut columns", _state); - } - } - if( subsetsize>=0 ) - { - idx0 = 0; - idx1 = subsetsize; - idxtype = 1; - } - else - { - idx0 = 0; - idx1 = setsize; - idxtype = 0; - } - mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); - result = ae_sqr(network->err.rmserror, _state)*(idx1-idx0)*mlpgetoutputscount(network, _state)/2; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlperrorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, ae_state *_state) -{ - return mlperrorsubset(network,xy,setsize,subset,subsetsize, _state); -} - - -/************************************************************************* -Error of the neural network on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - SetSize - real size of XY, SetSize>=0; - it is used when SubsetSize<0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_state *_state) -{ - ae_int_t idx0; - ae_int_t idx1; - ae_int_t idxtype; - double result; - - - ae_assert(sparseiscrs(xy, _state), "MLPErrorSparseSubset: XY is not in CRS format.", _state); - ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPErrorSparseSubset: XY has less than SetSize rows", _state); - if( setsize>0 ) - { - if( mlpissoftmax(network, _state) ) - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparseSubset: XY has less than NIn+1 columns", _state); - } - else - { - ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparseSubset: XY has less than NIn+NOut columns", _state); - } - } - if( subsetsize>=0 ) - { - idx0 = 0; - idx1 = subsetsize; - idxtype = 1; - } - else - { - idx0 = 0; - idx1 = setsize; - idxtype = 0; - } - mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); - result = ae_sqr(network->err.rmserror, _state)*(idx1-idx0)*mlpgetoutputscount(network, _state)/2; - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -double _pexec_mlperrorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, ae_state *_state) -{ - return mlperrorsparsesubset(network,xy,setsize,subset,subsetsize, _state); -} - - -void mlpallerrorsx(multilayerperceptron* network, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - modelerrors* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t rowsize; - ae_bool iscls; - ae_int_t srcidx; - ae_int_t cstart; - ae_int_t csize; - ae_int_t j; - mlpbuffers *pbuf; - ae_smart_ptr _pbuf; - ae_int_t len0; - ae_int_t len1; - modelerrors rep0; - modelerrors rep1; - - ae_frame_make(_state, &_frame_block); - ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true); - _modelerrors_init(&rep0, _state, ae_true); - _modelerrors_init(&rep1, _state, ae_true); - - ae_assert(datasetsize>=0, "MLPAllErrorsX: SetSize<0", _state); - ae_assert(datasettype==0||datasettype==1, "MLPAllErrorsX: DatasetType is incorrect", _state); - ae_assert(subsettype==0||subsettype==1, "MLPAllErrorsX: SubsetType is incorrect", _state); - - /* - * Determine network properties - */ - mlpproperties(network, &nin, &nout, &wcount, _state); - iscls = mlpissoftmax(network, _state); - - /* - * Split problem. - * - * Splitting problem allows us to reduce effect of single-precision - * arithmetics (SSE-optimized version of MLPChunkedProcess uses single - * precision internally, but converts them to double precision after - * results are exported from HPC buffer to network). Small batches are - * calculated in single precision, results are aggregated in double - * precision, and it allows us to avoid accumulation of errors when - * we process very large batches (tens of thousands of items). - * - * NOTE: it is important to use real arithmetics for ProblemCost - * because ProblemCost may be larger than MAXINT. - */ - if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(inttoreal(subset1-subset0, _state)*inttoreal(wcount, _state),mlpbase_gradbasecasecost) ) - { - splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); - mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, &rep0, _state); - mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, &rep1, _state); - rep->relclserror = (len0*rep0.relclserror+len1*rep1.relclserror)/(len0+len1); - rep->avgce = (len0*rep0.avgce+len1*rep1.avgce)/(len0+len1); - rep->rmserror = ae_sqrt((len0*ae_sqr(rep0.rmserror, _state)+len1*ae_sqr(rep1.rmserror, _state))/(len0+len1), _state); - rep->avgerror = (len0*rep0.avgerror+len1*rep1.avgerror)/(len0+len1); - rep->avgrelerror = (len0*rep0.avgrelerror+len1*rep1.avgrelerror)/(len0+len1); - ae_frame_leave(_state); - return; - } - - /* - * Retrieve and prepare - */ - ae_shared_pool_retrieve(buf, &_pbuf, _state); - if( iscls ) - { - rowsize = nin+1; - dserrallocate(nout, &pbuf->tmp0, _state); - } - else - { - rowsize = nin+nout; - dserrallocate(-nout, &pbuf->tmp0, _state); - } - - /* - * Processing - */ - hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); - cstart = subset0; - while(cstartchunksize, _state)-cstart; - for(j=0; j<=csize-1; j++) - { - srcidx = -1; - if( subsettype==0 ) - { - srcidx = cstart+j; - } - if( subsettype==1 ) - { - srcidx = idx->ptr.p_int[cstart+j]; - } - ae_assert(srcidx>=0, "MLPAllErrorsX: internal error", _state); - if( datasettype==0 ) - { - ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); - } - if( datasettype==1 ) - { - sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); - ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); - } - } - - /* - * Unpack XY and process (temporary code, to be replaced by chunked processing) - */ - for(j=0; j<=csize-1; j++) - { - ae_v_move(&pbuf->xy2.ptr.pp_double[j][0], 1, &pbuf->xy.ptr.pp_double[j][0], 1, ae_v_len(0,rowsize-1)); - } - mlpbase_mlpchunkedprocess(network, &pbuf->xy2, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, _state); - for(j=0; j<=csize-1; j++) - { - ae_v_move(&pbuf->x.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][0], 1, ae_v_len(0,nin-1)); - ae_v_move(&pbuf->y.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); - if( iscls ) - { - pbuf->desiredy.ptr.p_double[0] = pbuf->xy.ptr.pp_double[j][nin]; - } - else - { - ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &pbuf->xy.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); - } - dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); - } - - /* - * Process chunk and advance line pointer - */ - cstart = cstart+pbuf->chunksize; - } - dserrfinish(&pbuf->tmp0, _state); - rep->relclserror = pbuf->tmp0.ptr.p_double[0]; - rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log(2, _state); - rep->rmserror = pbuf->tmp0.ptr.p_double[2]; - rep->avgerror = pbuf->tmp0.ptr.p_double[3]; - rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; - - /* - * Recycle - */ - ae_shared_pool_recycle(buf, &_pbuf, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine: adding new input layer to network -*************************************************************************/ -static void mlpbase_addinputlayer(ae_int_t ncount, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state) -{ - - - lsizes->ptr.p_int[0] = ncount; - ltypes->ptr.p_int[0] = -2; - lconnfirst->ptr.p_int[0] = 0; - lconnlast->ptr.p_int[0] = 0; - *lastproc = 0; -} - - -/************************************************************************* -Internal subroutine: adding new summator layer to network -*************************************************************************/ -static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state) -{ - - - lsizes->ptr.p_int[*lastproc+1] = 1; - ltypes->ptr.p_int[*lastproc+1] = -3; - lconnfirst->ptr.p_int[*lastproc+1] = 0; - lconnlast->ptr.p_int[*lastproc+1] = 0; - lsizes->ptr.p_int[*lastproc+2] = ncount; - ltypes->ptr.p_int[*lastproc+2] = 0; - lconnfirst->ptr.p_int[*lastproc+2] = *lastproc; - lconnlast->ptr.p_int[*lastproc+2] = *lastproc+1; - *lastproc = *lastproc+2; -} - - -/************************************************************************* -Internal subroutine: adding new summator layer to network -*************************************************************************/ -static void mlpbase_addactivationlayer(ae_int_t functype, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state) -{ - - - ae_assert(functype>0||functype==-5, "AddActivationLayer: incorrect function type", _state); - lsizes->ptr.p_int[*lastproc+1] = lsizes->ptr.p_int[*lastproc]; - ltypes->ptr.p_int[*lastproc+1] = functype; - lconnfirst->ptr.p_int[*lastproc+1] = *lastproc; - lconnlast->ptr.p_int[*lastproc+1] = *lastproc; - *lastproc = *lastproc+1; -} - - -/************************************************************************* -Internal subroutine: adding new zero layer to network -*************************************************************************/ -static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t* lastproc, - ae_state *_state) -{ - - - lsizes->ptr.p_int[*lastproc+1] = 1; - ltypes->ptr.p_int[*lastproc+1] = -4; - lconnfirst->ptr.p_int[*lastproc+1] = 0; - lconnlast->ptr.p_int[*lastproc+1] = 0; - *lastproc = *lastproc+1; -} - - -/************************************************************************* -This routine adds input layer to the high-level description of the network. - -It modifies Network.HLConnections and Network.HLNeurons and assumes that -these arrays have enough place to store data. It accepts following -parameters: - Network - network - ConnIdx - index of the first free entry in the HLConnections - NeuroIdx - index of the first free entry in the HLNeurons - StructInfoIdx- index of the first entry in the low level description - of the current layer (in the StructInfo array) - NIn - number of inputs - -It modified Network and indices. -*************************************************************************/ -static void mlpbase_hladdinputlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t nin, - ae_state *_state) -{ - ae_int_t i; - ae_int_t offs; - - - offs = mlpbase_hlnfieldwidth*(*neuroidx); - for(i=0; i<=nin-1; i++) - { - network->hlneurons.ptr.p_int[offs+0] = 0; - network->hlneurons.ptr.p_int[offs+1] = i; - network->hlneurons.ptr.p_int[offs+2] = -1; - network->hlneurons.ptr.p_int[offs+3] = -1; - offs = offs+mlpbase_hlnfieldwidth; - } - *neuroidx = *neuroidx+nin; - *structinfoidx = *structinfoidx+nin; -} - - -/************************************************************************* -This routine adds output layer to the high-level description of -the network. - -It modifies Network.HLConnections and Network.HLNeurons and assumes that -these arrays have enough place to store data. It accepts following -parameters: - Network - network - ConnIdx - index of the first free entry in the HLConnections - NeuroIdx - index of the first free entry in the HLNeurons - StructInfoIdx- index of the first entry in the low level description - of the current layer (in the StructInfo array) - WeightsIdx - index of the first entry in the Weights array which - corresponds to the current layer - K - current layer index - NPrev - number of neurons in the previous layer - NOut - number of outputs - IsCls - is it classifier network? - IsLinear - is it network with linear output? - -It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. -*************************************************************************/ -static void mlpbase_hladdoutputlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t* weightsidx, - ae_int_t k, - ae_int_t nprev, - ae_int_t nout, - ae_bool iscls, - ae_bool islinearout, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t neurooffs; - ae_int_t connoffs; - - - ae_assert((iscls&&islinearout)||!iscls, "HLAddOutputLayer: internal error", _state); - neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); - connoffs = mlpbase_hlconnfieldwidth*(*connidx); - if( !iscls ) - { - - /* - * Regression network - */ - for(i=0; i<=nout-1; i++) - { - network->hlneurons.ptr.p_int[neurooffs+0] = k; - network->hlneurons.ptr.p_int[neurooffs+1] = i; - network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+nout+i; - network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; - neurooffs = neurooffs+mlpbase_hlnfieldwidth; - } - for(i=0; i<=nprev-1; i++) - { - for(j=0; j<=nout-1; j++) - { - network->hlconnections.ptr.p_int[connoffs+0] = k-1; - network->hlconnections.ptr.p_int[connoffs+1] = i; - network->hlconnections.ptr.p_int[connoffs+2] = k; - network->hlconnections.ptr.p_int[connoffs+3] = j; - network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); - connoffs = connoffs+mlpbase_hlconnfieldwidth; - } - } - *connidx = *connidx+nprev*nout; - *neuroidx = *neuroidx+nout; - *structinfoidx = *structinfoidx+2*nout+1; - *weightsidx = *weightsidx+nout*(nprev+1); - } - else - { - - /* - * Classification network - */ - for(i=0; i<=nout-2; i++) - { - network->hlneurons.ptr.p_int[neurooffs+0] = k; - network->hlneurons.ptr.p_int[neurooffs+1] = i; - network->hlneurons.ptr.p_int[neurooffs+2] = -1; - network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; - neurooffs = neurooffs+mlpbase_hlnfieldwidth; - } - network->hlneurons.ptr.p_int[neurooffs+0] = k; - network->hlneurons.ptr.p_int[neurooffs+1] = i; - network->hlneurons.ptr.p_int[neurooffs+2] = -1; - network->hlneurons.ptr.p_int[neurooffs+3] = -1; - for(i=0; i<=nprev-1; i++) - { - for(j=0; j<=nout-2; j++) - { - network->hlconnections.ptr.p_int[connoffs+0] = k-1; - network->hlconnections.ptr.p_int[connoffs+1] = i; - network->hlconnections.ptr.p_int[connoffs+2] = k; - network->hlconnections.ptr.p_int[connoffs+3] = j; - network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); - connoffs = connoffs+mlpbase_hlconnfieldwidth; - } - } - *connidx = *connidx+nprev*(nout-1); - *neuroidx = *neuroidx+nout; - *structinfoidx = *structinfoidx+nout+2; - *weightsidx = *weightsidx+(nout-1)*(nprev+1); - } -} - - -/************************************************************************* -This routine adds hidden layer to the high-level description of -the network. - -It modifies Network.HLConnections and Network.HLNeurons and assumes that -these arrays have enough place to store data. It accepts following -parameters: - Network - network - ConnIdx - index of the first free entry in the HLConnections - NeuroIdx - index of the first free entry in the HLNeurons - StructInfoIdx- index of the first entry in the low level description - of the current layer (in the StructInfo array) - WeightsIdx - index of the first entry in the Weights array which - corresponds to the current layer - K - current layer index - NPrev - number of neurons in the previous layer - NCur - number of neurons in the current layer - -It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. -*************************************************************************/ -static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, - ae_int_t* connidx, - ae_int_t* neuroidx, - ae_int_t* structinfoidx, - ae_int_t* weightsidx, - ae_int_t k, - ae_int_t nprev, - ae_int_t ncur, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t neurooffs; - ae_int_t connoffs; - - - neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); - connoffs = mlpbase_hlconnfieldwidth*(*connidx); - for(i=0; i<=ncur-1; i++) - { - network->hlneurons.ptr.p_int[neurooffs+0] = k; - network->hlneurons.ptr.p_int[neurooffs+1] = i; - network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+ncur+i; - network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; - neurooffs = neurooffs+mlpbase_hlnfieldwidth; - } - for(i=0; i<=nprev-1; i++) - { - for(j=0; j<=ncur-1; j++) - { - network->hlconnections.ptr.p_int[connoffs+0] = k-1; - network->hlconnections.ptr.p_int[connoffs+1] = i; - network->hlconnections.ptr.p_int[connoffs+2] = k; - network->hlconnections.ptr.p_int[connoffs+3] = j; - network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); - connoffs = connoffs+mlpbase_hlconnfieldwidth; - } - } - *connidx = *connidx+nprev*ncur; - *neuroidx = *neuroidx+ncur; - *structinfoidx = *structinfoidx+2*ncur+1; - *weightsidx = *weightsidx+ncur*(nprev+1); -} - - -/************************************************************************* -This function fills high level information about network created using -internal MLPCreate() function. - -This function does NOT examine StructInfo for low level information, it -just expects that network has following structure: - - input neuron \ - ... | input layer - input neuron / - - "-1" neuron \ - biased summator | - ... | - biased summator | hidden layer(s), if there are exists any - activation function | - ... | - activation function / - - "-1" neuron \ - biased summator | output layer: - ... | - biased summator | * we have NOut summators/activators for regression networks - activation function | * we have only NOut-1 summators and no activators for classifiers - ... | * we have "0" neuron only when we have classifier - activation function | - "0" neuron / - - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, - ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_bool iscls, - ae_bool islinearout, - ae_state *_state) -{ - ae_int_t idxweights; - ae_int_t idxstruct; - ae_int_t idxneuro; - ae_int_t idxconn; - - - ae_assert((iscls&&islinearout)||!iscls, "FillHighLevelInformation: internal error", _state); - - /* - * Preparations common to all types of networks - */ - idxweights = 0; - idxneuro = 0; - idxstruct = 0; - idxconn = 0; - network->hlnetworktype = 0; - - /* - * network without hidden layers - */ - if( nhid1==0 ) - { - ae_vector_set_length(&network->hllayersizes, 2, _state); - network->hllayersizes.ptr.p_int[0] = nin; - network->hllayersizes.ptr.p_int[1] = nout; - if( !iscls ) - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*nout, _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); - network->hlnormtype = 0; - } - else - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*(nout-1), _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); - network->hlnormtype = 1; - } - mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); - mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nout, iscls, islinearout, _state); - return; - } - - /* - * network with one hidden layers - */ - if( nhid2==0 ) - { - ae_vector_set_length(&network->hllayersizes, 3, _state); - network->hllayersizes.ptr.p_int[0] = nin; - network->hllayersizes.ptr.p_int[1] = nhid1; - network->hllayersizes.ptr.p_int[2] = nout; - if( !iscls ) - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nout), _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); - network->hlnormtype = 0; - } - else - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*(nout-1)), _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); - network->hlnormtype = 1; - } - mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); - mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); - mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nout, iscls, islinearout, _state); - return; - } - - /* - * Two hidden layers - */ - ae_vector_set_length(&network->hllayersizes, 4, _state); - network->hllayersizes.ptr.p_int[0] = nin; - network->hllayersizes.ptr.p_int[1] = nhid1; - network->hllayersizes.ptr.p_int[2] = nhid2; - network->hllayersizes.ptr.p_int[3] = nout; - if( !iscls ) - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*nout), _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); - network->hlnormtype = 0; - } - else - { - ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*(nout-1)), _state); - ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); - network->hlnormtype = 1; - } - mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); - mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); - mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nhid2, _state); - mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 3, nhid2, nout, iscls, islinearout, _state); -} - - -/************************************************************************* -Internal subroutine. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -static void mlpbase_mlpcreate(ae_int_t nin, - ae_int_t nout, - /* Integer */ ae_vector* lsizes, - /* Integer */ ae_vector* ltypes, - /* Integer */ ae_vector* lconnfirst, - /* Integer */ ae_vector* lconnlast, - ae_int_t layerscount, - ae_bool isclsnet, - multilayerperceptron* network, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t ssize; - ae_int_t ntotal; - ae_int_t wcount; - ae_int_t offs; - ae_int_t nprocessed; - ae_int_t wallocated; - ae_vector localtemp; - ae_vector lnfirst; - ae_vector lnsyn; - mlpbuffers buf; - smlpgrad sgrad; - - ae_frame_make(_state, &_frame_block); - _multilayerperceptron_clear(network); - ae_vector_init(&localtemp, 0, DT_INT, _state, ae_true); - ae_vector_init(&lnfirst, 0, DT_INT, _state, ae_true); - ae_vector_init(&lnsyn, 0, DT_INT, _state, ae_true); - _mlpbuffers_init(&buf, _state, ae_true); - _smlpgrad_init(&sgrad, _state, ae_true); - - - /* - * Check - */ - ae_assert(layerscount>0, "MLPCreate: wrong parameters!", _state); - ae_assert(ltypes->ptr.p_int[0]==-2, "MLPCreate: wrong LTypes[0] (must be -2)!", _state); - for(i=0; i<=layerscount-1; i++) - { - ae_assert(lsizes->ptr.p_int[i]>0, "MLPCreate: wrong LSizes!", _state); - ae_assert(lconnfirst->ptr.p_int[i]>=0&&(lconnfirst->ptr.p_int[i]ptr.p_int[i]>=lconnfirst->ptr.p_int[i]&&(lconnlast->ptr.p_int[i]ptr.p_int[i]>=0||ltypes->ptr.p_int[i]==-5 ) - { - lnsyn.ptr.p_int[i] = 0; - for(j=lconnfirst->ptr.p_int[i]; j<=lconnlast->ptr.p_int[i]; j++) - { - lnsyn.ptr.p_int[i] = lnsyn.ptr.p_int[i]+lsizes->ptr.p_int[j]; - } - } - else - { - if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) - { - lnsyn.ptr.p_int[i] = 0; - } - } - ae_assert(lnsyn.ptr.p_int[i]>=0, "MLPCreate: internal error #0!", _state); - - /* - * Other info - */ - lnfirst.ptr.p_int[i] = ntotal; - ntotal = ntotal+lsizes->ptr.p_int[i]; - if( ltypes->ptr.p_int[i]==0 ) - { - wcount = wcount+lnsyn.ptr.p_int[i]*lsizes->ptr.p_int[i]; - } - } - ssize = 7+ntotal*mlpbase_nfieldwidth; - - /* - * Allocate - */ - ae_vector_set_length(&network->structinfo, ssize-1+1, _state); - ae_vector_set_length(&network->weights, wcount-1+1, _state); - if( isclsnet ) - { - ae_vector_set_length(&network->columnmeans, nin-1+1, _state); - ae_vector_set_length(&network->columnsigmas, nin-1+1, _state); - } - else - { - ae_vector_set_length(&network->columnmeans, nin+nout-1+1, _state); - ae_vector_set_length(&network->columnsigmas, nin+nout-1+1, _state); - } - ae_vector_set_length(&network->neurons, ntotal-1+1, _state); - ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); - ae_vector_set_length(&network->integerbuf, 3+1, _state); - ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); - ae_vector_set_length(&network->x, nin-1+1, _state); - ae_vector_set_length(&network->y, nout-1+1, _state); - ae_vector_set_length(&network->derror, ntotal-1+1, _state); - - /* - * Fill structure: global info - */ - network->structinfo.ptr.p_int[0] = ssize; - network->structinfo.ptr.p_int[1] = nin; - network->structinfo.ptr.p_int[2] = nout; - network->structinfo.ptr.p_int[3] = ntotal; - network->structinfo.ptr.p_int[4] = wcount; - network->structinfo.ptr.p_int[5] = 7; - if( isclsnet ) - { - network->structinfo.ptr.p_int[6] = 1; - } - else - { - network->structinfo.ptr.p_int[6] = 0; - } - - /* - * Fill structure: neuron connections - */ - nprocessed = 0; - wallocated = 0; - for(i=0; i<=layerscount-1; i++) - { - for(j=0; j<=lsizes->ptr.p_int[i]-1; j++) - { - offs = network->structinfo.ptr.p_int[5]+nprocessed*mlpbase_nfieldwidth; - network->structinfo.ptr.p_int[offs+0] = ltypes->ptr.p_int[i]; - if( ltypes->ptr.p_int[i]==0 ) - { - - /* - * Adaptive summator: - * * connections with weights to previous neurons - */ - network->structinfo.ptr.p_int[offs+1] = lnsyn.ptr.p_int[i]; - network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]; - network->structinfo.ptr.p_int[offs+3] = wallocated; - wallocated = wallocated+lnsyn.ptr.p_int[i]; - nprocessed = nprocessed+1; - } - if( ltypes->ptr.p_int[i]>0||ltypes->ptr.p_int[i]==-5 ) - { - - /* - * Activation layer: - * * each neuron connected to one (only one) of previous neurons. - * * no weights - */ - network->structinfo.ptr.p_int[offs+1] = 1; - network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]+j; - network->structinfo.ptr.p_int[offs+3] = -1; - nprocessed = nprocessed+1; - } - if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) - { - nprocessed = nprocessed+1; - } - } - } - ae_assert(wallocated==wcount, "MLPCreate: internal error #1!", _state); - ae_assert(nprocessed==ntotal, "MLPCreate: internal error #2!", _state); - - /* - * Fill weights by small random values - * Initialize means and sigmas - */ - for(i=0; i<=nin-1; i++) - { - network->columnmeans.ptr.p_double[i] = 0; - network->columnsigmas.ptr.p_double[i] = 1; - } - if( !isclsnet ) - { - for(i=0; i<=nout-1; i++) - { - network->columnmeans.ptr.p_double[nin+i] = 0; - network->columnsigmas.ptr.p_double[nin+i] = 1; - } - } - mlprandomize(network, _state); - - /* - * Seed buffers - */ - ae_shared_pool_set_seed(&network->buf, &buf, sizeof(buf), _mlpbuffers_init, _mlpbuffers_init_copy, _mlpbuffers_destroy, _state); - ae_vector_set_length(&sgrad.g, wcount, _state); - sgrad.f = 0.0; - for(i=0; i<=wcount-1; i++) - { - sgrad.g.ptr.p_double[i] = 0.0; - } - ae_shared_pool_set_seed(&network->gradbuf, &sgrad, sizeof(sgrad), _smlpgrad_init, _smlpgrad_init_copy, _smlpgrad_destroy, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine for Hessian calculation. - -WARNING! Unspeakable math far beyong human capabilities :) -*************************************************************************/ -static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_bool naturalerr, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t kl; - ae_int_t offs; - ae_int_t n1; - ae_int_t n2; - ae_int_t w1; - ae_int_t w2; - double s; - double t; - double v; - double et; - ae_bool bflag; - double f; - double df; - double d2f; - double deidyj; - double mx; - double q; - double z; - double s2; - double expi; - double expj; - ae_vector x; - ae_vector desiredy; - ae_vector gt; - ae_vector zeros; - ae_matrix rx; - ae_matrix ry; - ae_matrix rdx; - ae_matrix rdy; - - ae_frame_make(_state, &_frame_block); - *e = 0; - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&desiredy, 0, DT_REAL, _state, ae_true); - ae_vector_init(>, 0, DT_REAL, _state, ae_true); - ae_vector_init(&zeros, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&rx, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ry, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&rdx, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&rdy, 0, 0, DT_REAL, _state, ae_true); - - mlpproperties(network, &nin, &nout, &wcount, _state); - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Prepare - */ - ae_vector_set_length(&x, nin-1+1, _state); - ae_vector_set_length(&desiredy, nout-1+1, _state); - ae_vector_set_length(&zeros, wcount-1+1, _state); - ae_vector_set_length(>, wcount-1+1, _state); - ae_matrix_set_length(&rx, ntotal+nout-1+1, wcount-1+1, _state); - ae_matrix_set_length(&ry, ntotal+nout-1+1, wcount-1+1, _state); - ae_matrix_set_length(&rdx, ntotal+nout-1+1, wcount-1+1, _state); - ae_matrix_set_length(&rdy, ntotal+nout-1+1, wcount-1+1, _state); - *e = 0; - for(i=0; i<=wcount-1; i++) - { - zeros.ptr.p_double[i] = 0; - } - ae_v_move(&grad->ptr.p_double[0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - for(i=0; i<=wcount-1; i++) - { - ae_v_move(&h->ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - } - - /* - * Process - */ - for(k=0; k<=ssize-1; k++) - { - - /* - * Process vector with MLPGradN. - * Now Neurons, DFDNET and DError contains results of the last run. - */ - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nin-1)); - if( mlpissoftmax(network, _state) ) - { - - /* - * class labels outputs - */ - kl = ae_round(xy->ptr.pp_double[k][nin], _state); - for(i=0; i<=nout-1; i++) - { - if( i==kl ) - { - desiredy.ptr.p_double[i] = 1; - } - else - { - desiredy.ptr.p_double[i] = 0; - } - } - } - else - { - - /* - * real outputs - */ - ae_v_move(&desiredy.ptr.p_double[0], 1, &xy->ptr.pp_double[k][nin], 1, ae_v_len(0,nout-1)); - } - if( naturalerr ) - { - mlpgradn(network, &x, &desiredy, &et, >, _state); - } - else - { - mlpgrad(network, &x, &desiredy, &et, >, _state); - } - - /* - * grad, error - */ - *e = *e+et; - ae_v_add(&grad->ptr.p_double[0], 1, >.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - - /* - * Hessian. - * Forward pass of the R-algorithm - */ - for(i=0; i<=ntotal-1; i++) - { - offs = istart+i*mlpbase_nfieldwidth; - ae_v_move(&rx.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ae_v_move(&ry.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) - { - - /* - * Activation function - */ - n1 = network->structinfo.ptr.p_int[offs+2]; - ae_v_move(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); - v = network->dfdnet.ptr.p_double[i]; - ae_v_moved(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); - continue; - } - if( network->structinfo.ptr.p_int[offs+0]==0 ) - { - - /* - * Adaptive summator - */ - n1 = network->structinfo.ptr.p_int[offs+2]; - n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; - w1 = network->structinfo.ptr.p_int[offs+3]; - w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; - for(j=n1; j<=n2; j++) - { - v = network->weights.ptr.p_double[w1+j-n1]; - ae_v_addd(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[j][0], 1, ae_v_len(0,wcount-1), v); - rx.ptr.pp_double[i][w1+j-n1] = rx.ptr.pp_double[i][w1+j-n1]+network->neurons.ptr.p_double[j]; - } - ae_v_move(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); - continue; - } - if( network->structinfo.ptr.p_int[offs+0]<0 ) - { - bflag = ae_true; - if( network->structinfo.ptr.p_int[offs+0]==-2 ) - { - - /* - * input neuron, left unchanged - */ - bflag = ae_false; - } - if( network->structinfo.ptr.p_int[offs+0]==-3 ) - { - - /* - * "-1" neuron, left unchanged - */ - bflag = ae_false; - } - if( network->structinfo.ptr.p_int[offs+0]==-4 ) - { - - /* - * "0" neuron, left unchanged - */ - bflag = ae_false; - } - ae_assert(!bflag, "MLPHessianNBatch: internal error - unknown neuron type!", _state); - continue; - } - } - - /* - * Hessian. Backward pass of the R-algorithm. - * - * Stage 1. Initialize RDY - */ - for(i=0; i<=ntotal+nout-1; i++) - { - ae_v_move(&rdy.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - } - if( network->structinfo.ptr.p_int[6]==0 ) - { - - /* - * Standardisation. - * - * In context of the Hessian calculation standardisation - * is considered as additional layer with weightless - * activation function: - * - * F(NET) := Sigma*NET - * - * So we add one more layer to forward pass, and - * make forward/backward pass through this layer. - */ - for(i=0; i<=nout-1; i++) - { - n1 = ntotal-nout+i; - n2 = ntotal+i; - - /* - * Forward pass from N1 to N2 - */ - ae_v_move(&rx.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); - v = network->columnsigmas.ptr.p_double[nin+i]; - ae_v_moved(&ry.ptr.pp_double[n2][0], 1, &rx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), v); - - /* - * Initialization of RDY - */ - ae_v_move(&rdy.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); - - /* - * Backward pass from N2 to N1: - * 1. Calculate R(dE/dX). - * 2. No R(dE/dWij) is needed since weight of activation neuron - * is fixed to 1. So we can update R(dE/dY) for - * the connected neuron (note that Vij=0, Wij=1) - */ - df = network->columnsigmas.ptr.p_double[nin+i]; - ae_v_moved(&rdx.ptr.pp_double[n2][0], 1, &rdy.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), df); - ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); - } - } - else - { - - /* - * Softmax. - * - * Initialize RDY using generalized expression for ei'(yi) - * (see expression (9) from p. 5 of "Fast Exact Multiplication by the Hessian"). - * - * When we are working with softmax network, generalized - * expression for ei'(yi) is used because softmax - * normalization leads to ei, which depends on all y's - */ - if( naturalerr ) - { - - /* - * softmax + cross-entropy. - * We have: - * - * S = sum(exp(yk)), - * ei = sum(trn)*exp(yi)/S-trn_i - * - * j=i: d(ei)/d(yj) = T*exp(yi)*(S-exp(yi))/S^2 - * j<>i: d(ei)/d(yj) = -T*exp(yi)*exp(yj)/S^2 - */ - t = 0; - for(i=0; i<=nout-1; i++) - { - t = t+desiredy.ptr.p_double[i]; - } - mx = network->neurons.ptr.p_double[ntotal-nout]; - for(i=0; i<=nout-1; i++) - { - mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); - } - s = 0; - for(i=0; i<=nout-1; i++) - { - network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); - s = s+network->nwbuf.ptr.p_double[i]; - } - for(i=0; i<=nout-1; i++) - { - for(j=0; j<=nout-1; j++) - { - if( j==i ) - { - deidyj = t*network->nwbuf.ptr.p_double[i]*(s-network->nwbuf.ptr.p_double[i])/ae_sqr(s, _state); - ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+i][0], 1, ae_v_len(0,wcount-1), deidyj); - } - else - { - deidyj = -t*network->nwbuf.ptr.p_double[i]*network->nwbuf.ptr.p_double[j]/ae_sqr(s, _state); - ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); - } - } - } - } - else - { - - /* - * For a softmax + squared error we have expression - * far beyond human imagination so we don't even try - * to comment on it. Just enjoy the code... - * - * P.S. That's why "natural error" is called "natural" - - * compact beautiful expressions, fast code.... - */ - mx = network->neurons.ptr.p_double[ntotal-nout]; - for(i=0; i<=nout-1; i++) - { - mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); - } - s = 0; - s2 = 0; - for(i=0; i<=nout-1; i++) - { - network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); - s = s+network->nwbuf.ptr.p_double[i]; - s2 = s2+ae_sqr(network->nwbuf.ptr.p_double[i], _state); - } - q = 0; - for(i=0; i<=nout-1; i++) - { - q = q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*network->nwbuf.ptr.p_double[i]; - } - for(i=0; i<=nout-1; i++) - { - z = -q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*s; - expi = network->nwbuf.ptr.p_double[i]; - for(j=0; j<=nout-1; j++) - { - expj = network->nwbuf.ptr.p_double[j]; - if( j==i ) - { - deidyj = expi/ae_sqr(s, _state)*((z+expi)*(s-2*expi)/s+expi*s2/ae_sqr(s, _state)); - } - else - { - deidyj = expi*expj/ae_sqr(s, _state)*(s2/ae_sqr(s, _state)-2*z/s-(expi+expj)/s+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])-(network->y.ptr.p_double[j]-desiredy.ptr.p_double[j])); - } - ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); - } - } - } - } - - /* - * Hessian. Backward pass of the R-algorithm - * - * Stage 2. Process. - */ - for(i=ntotal-1; i>=0; i--) - { - - /* - * Possible variants: - * 1. Activation function - * 2. Adaptive summator - * 3. Special neuron - */ - offs = istart+i*mlpbase_nfieldwidth; - if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) - { - n1 = network->structinfo.ptr.p_int[offs+2]; - - /* - * First, calculate R(dE/dX). - */ - mlpactivationfunction(network->neurons.ptr.p_double[n1], network->structinfo.ptr.p_int[offs+0], &f, &df, &d2f, _state); - v = d2f*network->derror.ptr.p_double[i]; - ae_v_moved(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), df); - ae_v_addd(&rdx.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); - - /* - * No R(dE/dWij) is needed since weight of activation neuron - * is fixed to 1. - * - * So we can update R(dE/dY) for the connected neuron. - * (note that Vij=0, Wij=1) - */ - ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); - continue; - } - if( network->structinfo.ptr.p_int[offs+0]==0 ) - { - - /* - * Adaptive summator - */ - n1 = network->structinfo.ptr.p_int[offs+2]; - n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; - w1 = network->structinfo.ptr.p_int[offs+3]; - w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; - - /* - * First, calculate R(dE/dX). - */ - ae_v_move(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); - - /* - * Then, calculate R(dE/dWij) - */ - for(j=w1; j<=w2; j++) - { - v = network->neurons.ptr.p_double[n1+j-w1]; - ae_v_addd(&h->ptr.pp_double[j][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); - v = network->derror.ptr.p_double[i]; - ae_v_addd(&h->ptr.pp_double[j][0], 1, &ry.ptr.pp_double[n1+j-w1][0], 1, ae_v_len(0,wcount-1), v); - } - - /* - * And finally, update R(dE/dY) for connected neurons. - */ - for(j=w1; j<=w2; j++) - { - v = network->weights.ptr.p_double[j]; - ae_v_addd(&rdy.ptr.pp_double[n1+j-w1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); - rdy.ptr.pp_double[n1+j-w1][j] = rdy.ptr.pp_double[n1+j-w1][j]+network->derror.ptr.p_double[i]; - } - continue; - } - if( network->structinfo.ptr.p_int[offs+0]<0 ) - { - bflag = ae_false; - if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) - { - - /* - * Special neuron type, no back-propagation required - */ - bflag = ae_true; - } - ae_assert(bflag, "MLPHessianNBatch: unknown neuron type!", _state); - continue; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine - -Network must be processed by MLPProcess on X -*************************************************************************/ -static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, - /* Real */ ae_vector* neurons, - /* Real */ ae_vector* weights, - /* Real */ ae_vector* derror, - /* Real */ ae_vector* grad, - ae_bool naturalerrorfunc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n1; - ae_int_t n2; - ae_int_t w1; - ae_int_t w2; - ae_int_t ntotal; - ae_int_t istart; - ae_int_t nin; - ae_int_t nout; - ae_int_t offs; - double dedf; - double dfdnet; - double v; - double fown; - double deown; - double net; - double mx; - ae_bool bflag; - - - - /* - * Read network geometry - */ - nin = network->structinfo.ptr.p_int[1]; - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - - /* - * Pre-processing of dError/dOut: - * from dError/dOut(normalized) to dError/dOut(non-normalized) - */ - ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPInternalCalculateGradient: unknown normalization type!", _state); - if( network->structinfo.ptr.p_int[6]==1 ) - { - - /* - * Softmax - */ - if( !naturalerrorfunc ) - { - mx = network->neurons.ptr.p_double[ntotal-nout]; - for(i=0; i<=nout-1; i++) - { - mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); - } - net = 0; - for(i=0; i<=nout-1; i++) - { - network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); - net = net+network->nwbuf.ptr.p_double[i]; - } - v = ae_v_dotproduct(&network->derror.ptr.p_double[ntotal-nout], 1, &network->nwbuf.ptr.p_double[0], 1, ae_v_len(ntotal-nout,ntotal-1)); - for(i=0; i<=nout-1; i++) - { - fown = network->nwbuf.ptr.p_double[i]; - deown = network->derror.ptr.p_double[ntotal-nout+i]; - network->nwbuf.ptr.p_double[nout+i] = (-v+deown*fown+deown*(net-fown))*fown/ae_sqr(net, _state); - } - for(i=0; i<=nout-1; i++) - { - network->derror.ptr.p_double[ntotal-nout+i] = network->nwbuf.ptr.p_double[nout+i]; - } - } - } - else - { - - /* - * Un-standardisation - */ - for(i=0; i<=nout-1; i++) - { - network->derror.ptr.p_double[ntotal-nout+i] = network->derror.ptr.p_double[ntotal-nout+i]*network->columnsigmas.ptr.p_double[nin+i]; - } - } - - /* - * Backpropagation - */ - for(i=ntotal-1; i>=0; i--) - { - - /* - * Extract info - */ - offs = istart+i*mlpbase_nfieldwidth; - if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) - { - - /* - * Activation function - */ - dedf = network->derror.ptr.p_double[i]; - dfdnet = network->dfdnet.ptr.p_double[i]; - derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]] = derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]]+dedf*dfdnet; - continue; - } - if( network->structinfo.ptr.p_int[offs+0]==0 ) - { - - /* - * Adaptive summator - */ - n1 = network->structinfo.ptr.p_int[offs+2]; - n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; - w1 = network->structinfo.ptr.p_int[offs+3]; - w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; - dedf = network->derror.ptr.p_double[i]; - dfdnet = 1.0; - v = dedf*dfdnet; - ae_v_moved(&grad->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2), v); - ae_v_addd(&derror->ptr.p_double[n1], 1, &weights->ptr.p_double[w1], 1, ae_v_len(n1,n2), v); - continue; - } - if( network->structinfo.ptr.p_int[offs+0]<0 ) - { - bflag = ae_false; - if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) - { - - /* - * Special neuron type, no back-propagation required - */ - bflag = ae_true; - } - ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); - continue; - } - } -} - - -static void mlpbase_mlpchunkedgradient(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - double* e, - ae_bool naturalerrorfunc, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t kl; - ae_int_t ntotal; - ae_int_t nin; - ae_int_t nout; - ae_int_t offs; - double f; - double df; - double d2f; - double v; - double vv; - double s; - double fown; - double deown; - ae_bool bflag; - ae_int_t istart; - ae_int_t entrysize; - ae_int_t dfoffs; - ae_int_t derroroffs; - ae_int_t entryoffs; - ae_int_t neuronidx; - ae_int_t srcentryoffs; - ae_int_t srcneuronidx; - ae_int_t srcweightidx; - ae_int_t neurontype; - ae_int_t nweights; - ae_int_t offs0; - ae_int_t offs1; - ae_int_t offs2; - double v0; - double v1; - double v2; - double v3; - double s0; - double s1; - double s2; - double s3; - ae_int_t chunksize; - - - chunksize = 4; - ae_assert(csize<=chunksize, "MLPChunkedGradient: internal error (CSize>ChunkSize)", _state); - - /* - * Try to use HPC core, if possible - */ - if( hpcchunkedgradient(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc, _state) ) - { - return; - } - - /* - * Read network geometry, prepare data - */ - nin = network->structinfo.ptr.p_int[1]; - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - entrysize = 12; - dfoffs = 4; - derroroffs = 8; - - /* - * Fill Batch4Buf by zeros. - * - * THIS STAGE IS VERY IMPORTANT! - * - * We fill all components of entry - neuron values, dF/dNET, dError/dF. - * It allows us to easily handle situations when CSizeptr.p_double[i] = 0; - } - - /* - * Forward pass: - * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],0) ) - { - batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; - } - else - { - batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; - } - } - } - for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) - { - entryoffs = entrysize*neuronidx; - offs = istart+neuronidx*mlpbase_nfieldwidth; - neurontype = network->structinfo.ptr.p_int[offs+0]; - if( neurontype>0||neurontype==-5 ) - { - - /* - * "activation function" neuron, which takes value of neuron SrcNeuronIdx - * and applies activation function to it. - * - * This neuron has no weights and no tunable parameters. - */ - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+0] = f; - batch4buf->ptr.p_double[entryoffs+0+dfoffs] = df; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+1] = f; - batch4buf->ptr.p_double[entryoffs+1+dfoffs] = df; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+2] = f; - batch4buf->ptr.p_double[entryoffs+2+dfoffs] = df; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+3] = f; - batch4buf->ptr.p_double[entryoffs+3+dfoffs] = df; - continue; - } - if( neurontype==0 ) - { - - /* - * "adaptive summator" neuron, whose output is a weighted sum of inputs. - * It has weights, but has no activation function. - */ - nweights = network->structinfo.ptr.p_int[offs+1]; - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - srcweightidx = network->structinfo.ptr.p_int[offs+3]; - v0 = 0; - v1 = 0; - v2 = 0; - v3 = 0; - for(j=0; j<=nweights-1; j++) - { - v = network->weights.ptr.p_double[srcweightidx]; - srcweightidx = srcweightidx+1; - v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; - v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; - v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; - v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; - srcentryoffs = srcentryoffs+entrysize; - } - batch4buf->ptr.p_double[entryoffs+0] = v0; - batch4buf->ptr.p_double[entryoffs+1] = v1; - batch4buf->ptr.p_double[entryoffs+2] = v2; - batch4buf->ptr.p_double[entryoffs+3] = v3; - batch4buf->ptr.p_double[entryoffs+0+dfoffs] = 1; - batch4buf->ptr.p_double[entryoffs+1+dfoffs] = 1; - batch4buf->ptr.p_double[entryoffs+2+dfoffs] = 1; - batch4buf->ptr.p_double[entryoffs+3+dfoffs] = 1; - continue; - } - if( neurontype<0 ) - { - bflag = ae_false; - if( neurontype==-2 ) - { - - /* - * Input neuron, left unchanged - */ - bflag = ae_true; - } - if( neurontype==-3 ) - { - - /* - * "-1" neuron - */ - batch4buf->ptr.p_double[entryoffs+0] = -1; - batch4buf->ptr.p_double[entryoffs+1] = -1; - batch4buf->ptr.p_double[entryoffs+2] = -1; - batch4buf->ptr.p_double[entryoffs+3] = -1; - batch4buf->ptr.p_double[entryoffs+0+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+1+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+2+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+3+dfoffs] = 0; - bflag = ae_true; - } - if( neurontype==-4 ) - { - - /* - * "0" neuron - */ - batch4buf->ptr.p_double[entryoffs+0] = 0; - batch4buf->ptr.p_double[entryoffs+1] = 0; - batch4buf->ptr.p_double[entryoffs+2] = 0; - batch4buf->ptr.p_double[entryoffs+3] = 0; - batch4buf->ptr.p_double[entryoffs+0+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+1+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+2+dfoffs] = 0; - batch4buf->ptr.p_double[entryoffs+3+dfoffs] = 0; - bflag = ae_true; - } - ae_assert(bflag, "MLPChunkedGradient: internal error - unknown neuron type!", _state); - continue; - } - } - - /* - * Intermediate phase between forward and backward passes. - * - * For regression networks: - * * forward pass is completely done (no additional post-processing is - * needed). - * * before starting backward pass, we have to calculate dError/dOut - * for output neurons. We also update error at this phase. - * - * For classification networks: - * * in addition to forward pass we apply SOFTMAX normalization to - * output neurons. - * * after applying normalization, we have to calculate dError/dOut, - * which is calculated in two steps: - * * first, we calculate derivative of error with respect to SOFTMAX - * normalized outputs (normalized dError) - * * then, we calculate derivative of error with respect to values - * of outputs BEFORE normalization was applied to them - */ - ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedGradient: unknown normalization type!", _state); - if( network->structinfo.ptr.p_int[6]==1 ) - { - - /* - * SOFTMAX-normalized network. - * - * First, calculate (V0,V1,V2,V3) - component-wise maximum - * of output neurons. This vector of maximum values will be - * used for normalization of outputs prior to calculating - * exponentials. - * - * NOTE: the only purpose of this stage is to prevent overflow - * during calculation of exponentials. With this stage - * we make sure that all exponentials are calculated - * with non-positive argument. If you load (0,0,0,0) to - * (V0,V1,V2,V3), your program will continue working - - * although with less robustness. - */ - entryoffs = entrysize*(ntotal-nout); - v0 = batch4buf->ptr.p_double[entryoffs+0]; - v1 = batch4buf->ptr.p_double[entryoffs+1]; - v2 = batch4buf->ptr.p_double[entryoffs+2]; - v3 = batch4buf->ptr.p_double[entryoffs+3]; - entryoffs = entryoffs+entrysize; - for(i=1; i<=nout-1; i++) - { - v = batch4buf->ptr.p_double[entryoffs+0]; - if( v>v0 ) - { - v0 = v; - } - v = batch4buf->ptr.p_double[entryoffs+1]; - if( v>v1 ) - { - v1 = v; - } - v = batch4buf->ptr.p_double[entryoffs+2]; - if( v>v2 ) - { - v2 = v; - } - v = batch4buf->ptr.p_double[entryoffs+3]; - if( v>v3 ) - { - v3 = v; - } - entryoffs = entryoffs+entrysize; - } - - /* - * Then, calculate exponentials and place them to part of the - * array which is located past the last entry. We also - * calculate sum of exponentials which will be stored past the - * exponentials. - */ - entryoffs = entrysize*(ntotal-nout); - offs0 = entrysize*ntotal; - s0 = 0; - s1 = 0; - s2 = 0; - s3 = 0; - for(i=0; i<=nout-1; i++) - { - v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); - s0 = s0+v; - batch4buf->ptr.p_double[offs0+0] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); - s1 = s1+v; - batch4buf->ptr.p_double[offs0+1] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); - s2 = s2+v; - batch4buf->ptr.p_double[offs0+2] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); - s3 = s3+v; - batch4buf->ptr.p_double[offs0+3] = v; - entryoffs = entryoffs+entrysize; - offs0 = offs0+chunksize; - } - offs0 = entrysize*ntotal+2*nout*chunksize; - batch4buf->ptr.p_double[offs0+0] = s0; - batch4buf->ptr.p_double[offs0+1] = s1; - batch4buf->ptr.p_double[offs0+2] = s2; - batch4buf->ptr.p_double[offs0+3] = s3; - - /* - * Now we have: - * * Batch4Buf[0...EntrySize*NTotal-1] stores: - * * NTotal*ChunkSize neuron output values (SOFTMAX normalization - * was not applied to these values), - * * NTotal*ChunkSize values of dF/dNET (derivative of neuron - * output with respect to its input) - * * NTotal*ChunkSize zeros in the elements which correspond to - * dError/dOut (derivative of error with respect to neuron output). - * * Batch4Buf[EntrySize*NTotal...EntrySize*NTotal+ChunkSize*NOut-1] - - * stores exponentials of last NOut neurons. - * * Batch4Buf[EntrySize*NTotal+ChunkSize*NOut-1...EntrySize*NTotal+ChunkSize*2*NOut-1] - * - can be used for temporary calculations - * * Batch4Buf[EntrySize*NTotal+ChunkSize*2*NOut...EntrySize*NTotal+ChunkSize*2*NOut+ChunkSize-1] - * - stores sum-of-exponentials - * - * Block below calculates derivatives of error function with respect - * to non-SOFTMAX-normalized output values of last NOut neurons. - * - * It is quite complicated; we do not describe algebra behind it, - * but if you want you may check it yourself :) - */ - if( naturalerrorfunc ) - { - - /* - * Calculate derivative of error with respect to values of - * output neurons PRIOR TO SOFTMAX NORMALIZATION. Because we - * use natural error function (cross-entropy), we can do so - * very easy. - */ - offs0 = entrysize*ntotal+2*nout*chunksize; - for(k=0; k<=csize-1; k++) - { - s = batch4buf->ptr.p_double[offs0+k]; - kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); - offs1 = (ntotal-nout)*entrysize+derroroffs+k; - offs2 = entrysize*ntotal+k; - for(i=0; i<=nout-1; i++) - { - if( i==kl ) - { - v = 1; - } - else - { - v = 0; - } - vv = batch4buf->ptr.p_double[offs2]; - batch4buf->ptr.p_double[offs1] = vv/s-v; - *e = *e+mlpbase_safecrossentropy(v, vv/s, _state); - offs1 = offs1+entrysize; - offs2 = offs2+chunksize; - } - } - } - else - { - - /* - * SOFTMAX normalization makes things very difficult. - * Sorry, we do not dare to describe this esoteric math - * in details. - */ - offs0 = entrysize*ntotal+chunksize*2*nout; - for(k=0; k<=csize-1; k++) - { - s = batch4buf->ptr.p_double[offs0+k]; - kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); - vv = 0; - offs1 = entrysize*ntotal+k; - offs2 = entrysize*ntotal+nout*chunksize+k; - for(i=0; i<=nout-1; i++) - { - fown = batch4buf->ptr.p_double[offs1]; - if( i==kl ) - { - deown = fown/s-1; - } - else - { - deown = fown/s; - } - batch4buf->ptr.p_double[offs2] = deown; - vv = vv+deown*fown; - *e = *e+deown*deown/2; - offs1 = offs1+chunksize; - offs2 = offs2+chunksize; - } - offs1 = entrysize*ntotal+k; - offs2 = entrysize*ntotal+nout*chunksize+k; - for(i=0; i<=nout-1; i++) - { - fown = batch4buf->ptr.p_double[offs1]; - deown = batch4buf->ptr.p_double[offs2]; - batch4buf->ptr.p_double[(ntotal-nout+i)*entrysize+derroroffs+k] = (-vv+deown*fown+deown*(s-fown))*fown/ae_sqr(s, _state); - offs1 = offs1+chunksize; - offs2 = offs2+chunksize; - } - } - } - } - else - { - - /* - * Regression network with sum-of-squares function. - * - * For each NOut of last neurons: - * * calculate difference between actual and desired output - * * calculate dError/dOut for this neuron (proportional to difference) - * * store in in last 4 components of entry (these values are used - * to start backpropagation) - * * update error - */ - for(i=0; i<=nout-1; i++) - { - v0 = network->columnsigmas.ptr.p_double[nin+i]; - v1 = network->columnmeans.ptr.p_double[nin+i]; - entryoffs = entrysize*(ntotal-nout+i); - offs0 = entryoffs; - offs1 = entryoffs+derroroffs; - for(j=0; j<=csize-1; j++) - { - v = batch4buf->ptr.p_double[offs0+j]*v0+v1-xy->ptr.pp_double[cstart+j][nin+i]; - batch4buf->ptr.p_double[offs1+j] = v*v0; - *e = *e+v*v/2; - } - } - } - - /* - * Backpropagation - */ - for(neuronidx=ntotal-1; neuronidx>=0; neuronidx--) - { - entryoffs = entrysize*neuronidx; - offs = istart+neuronidx*mlpbase_nfieldwidth; - neurontype = network->structinfo.ptr.p_int[offs+0]; - if( neurontype>0||neurontype==-5 ) - { - - /* - * Activation function - */ - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - offs0 = srcentryoffs+derroroffs; - offs1 = entryoffs+derroroffs; - offs2 = entryoffs+dfoffs; - batch4buf->ptr.p_double[offs0+0] = batch4buf->ptr.p_double[offs0+0]+batch4buf->ptr.p_double[offs1+0]*batch4buf->ptr.p_double[offs2+0]; - batch4buf->ptr.p_double[offs0+1] = batch4buf->ptr.p_double[offs0+1]+batch4buf->ptr.p_double[offs1+1]*batch4buf->ptr.p_double[offs2+1]; - batch4buf->ptr.p_double[offs0+2] = batch4buf->ptr.p_double[offs0+2]+batch4buf->ptr.p_double[offs1+2]*batch4buf->ptr.p_double[offs2+2]; - batch4buf->ptr.p_double[offs0+3] = batch4buf->ptr.p_double[offs0+3]+batch4buf->ptr.p_double[offs1+3]*batch4buf->ptr.p_double[offs2+3]; - continue; - } - if( neurontype==0 ) - { - - /* - * Adaptive summator - */ - nweights = network->structinfo.ptr.p_int[offs+1]; - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - srcweightidx = network->structinfo.ptr.p_int[offs+3]; - v0 = batch4buf->ptr.p_double[entryoffs+derroroffs+0]; - v1 = batch4buf->ptr.p_double[entryoffs+derroroffs+1]; - v2 = batch4buf->ptr.p_double[entryoffs+derroroffs+2]; - v3 = batch4buf->ptr.p_double[entryoffs+derroroffs+3]; - for(j=0; j<=nweights-1; j++) - { - offs0 = srcentryoffs; - offs1 = srcentryoffs+derroroffs; - v = network->weights.ptr.p_double[srcweightidx]; - hpcbuf->ptr.p_double[srcweightidx] = hpcbuf->ptr.p_double[srcweightidx]+batch4buf->ptr.p_double[offs0+0]*v0+batch4buf->ptr.p_double[offs0+1]*v1+batch4buf->ptr.p_double[offs0+2]*v2+batch4buf->ptr.p_double[offs0+3]*v3; - batch4buf->ptr.p_double[offs1+0] = batch4buf->ptr.p_double[offs1+0]+v*v0; - batch4buf->ptr.p_double[offs1+1] = batch4buf->ptr.p_double[offs1+1]+v*v1; - batch4buf->ptr.p_double[offs1+2] = batch4buf->ptr.p_double[offs1+2]+v*v2; - batch4buf->ptr.p_double[offs1+3] = batch4buf->ptr.p_double[offs1+3]+v*v3; - srcentryoffs = srcentryoffs+entrysize; - srcweightidx = srcweightidx+1; - } - continue; - } - if( neurontype<0 ) - { - bflag = ae_false; - if( (neurontype==-2||neurontype==-3)||neurontype==-4 ) - { - - /* - * Special neuron type, no back-propagation required - */ - bflag = ae_true; - } - ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); - continue; - } - } -} - - -static void mlpbase_mlpchunkedprocess(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t cstart, - ae_int_t csize, - /* Real */ ae_vector* batch4buf, - /* Real */ ae_vector* hpcbuf, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t ntotal; - ae_int_t nin; - ae_int_t nout; - ae_int_t offs; - double f; - double df; - double d2f; - double v; - ae_bool bflag; - ae_int_t istart; - ae_int_t entrysize; - ae_int_t entryoffs; - ae_int_t neuronidx; - ae_int_t srcentryoffs; - ae_int_t srcneuronidx; - ae_int_t srcweightidx; - ae_int_t neurontype; - ae_int_t nweights; - ae_int_t offs0; - double v0; - double v1; - double v2; - double v3; - double s0; - double s1; - double s2; - double s3; - ae_int_t chunksize; - - - chunksize = 4; - ae_assert(csize<=chunksize, "MLPChunkedProcess: internal error (CSize>ChunkSize)", _state); - - /* - * Try to use HPC core, if possible - */ - if( hpcchunkedprocess(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, _state) ) - { - return; - } - - /* - * Read network geometry, prepare data - */ - nin = network->structinfo.ptr.p_int[1]; - nout = network->structinfo.ptr.p_int[2]; - ntotal = network->structinfo.ptr.p_int[3]; - istart = network->structinfo.ptr.p_int[5]; - entrysize = 4; - - /* - * Fill Batch4Buf by zeros. - * - * THIS STAGE IS VERY IMPORTANT! - * - * We fill all components of entry - neuron values, dF/dNET, dError/dF. - * It allows us to easily handle situations when CSizeptr.p_double[i] = 0; - } - - /* - * Forward pass: - * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],0) ) - { - batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; - } - else - { - batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; - } - } - } - for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) - { - entryoffs = entrysize*neuronidx; - offs = istart+neuronidx*mlpbase_nfieldwidth; - neurontype = network->structinfo.ptr.p_int[offs+0]; - if( neurontype>0||neurontype==-5 ) - { - - /* - * "activation function" neuron, which takes value of neuron SrcNeuronIdx - * and applies activation function to it. - * - * This neuron has no weights and no tunable parameters. - */ - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+0] = f; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+1] = f; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+2] = f; - mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); - batch4buf->ptr.p_double[entryoffs+3] = f; - continue; - } - if( neurontype==0 ) - { - - /* - * "adaptive summator" neuron, whose output is a weighted sum of inputs. - * It has weights, but has no activation function. - */ - nweights = network->structinfo.ptr.p_int[offs+1]; - srcneuronidx = network->structinfo.ptr.p_int[offs+2]; - srcentryoffs = entrysize*srcneuronidx; - srcweightidx = network->structinfo.ptr.p_int[offs+3]; - v0 = 0; - v1 = 0; - v2 = 0; - v3 = 0; - for(j=0; j<=nweights-1; j++) - { - v = network->weights.ptr.p_double[srcweightidx]; - srcweightidx = srcweightidx+1; - v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; - v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; - v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; - v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; - srcentryoffs = srcentryoffs+entrysize; - } - batch4buf->ptr.p_double[entryoffs+0] = v0; - batch4buf->ptr.p_double[entryoffs+1] = v1; - batch4buf->ptr.p_double[entryoffs+2] = v2; - batch4buf->ptr.p_double[entryoffs+3] = v3; - continue; - } - if( neurontype<0 ) - { - bflag = ae_false; - if( neurontype==-2 ) - { - - /* - * Input neuron, left unchanged - */ - bflag = ae_true; - } - if( neurontype==-3 ) - { - - /* - * "-1" neuron - */ - batch4buf->ptr.p_double[entryoffs+0] = -1; - batch4buf->ptr.p_double[entryoffs+1] = -1; - batch4buf->ptr.p_double[entryoffs+2] = -1; - batch4buf->ptr.p_double[entryoffs+3] = -1; - bflag = ae_true; - } - if( neurontype==-4 ) - { - - /* - * "0" neuron - */ - batch4buf->ptr.p_double[entryoffs+0] = 0; - batch4buf->ptr.p_double[entryoffs+1] = 0; - batch4buf->ptr.p_double[entryoffs+2] = 0; - batch4buf->ptr.p_double[entryoffs+3] = 0; - bflag = ae_true; - } - ae_assert(bflag, "MLPChunkedProcess: internal error - unknown neuron type!", _state); - continue; - } - } - - /* - * SOFTMAX normalization or scaling. - */ - ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedProcess: unknown normalization type!", _state); - if( network->structinfo.ptr.p_int[6]==1 ) - { - - /* - * SOFTMAX-normalized network. - * - * First, calculate (V0,V1,V2,V3) - component-wise maximum - * of output neurons. This vector of maximum values will be - * used for normalization of outputs prior to calculating - * exponentials. - * - * NOTE: the only purpose of this stage is to prevent overflow - * during calculation of exponentials. With this stage - * we make sure that all exponentials are calculated - * with non-positive argument. If you load (0,0,0,0) to - * (V0,V1,V2,V3), your program will continue working - - * although with less robustness. - */ - entryoffs = entrysize*(ntotal-nout); - v0 = batch4buf->ptr.p_double[entryoffs+0]; - v1 = batch4buf->ptr.p_double[entryoffs+1]; - v2 = batch4buf->ptr.p_double[entryoffs+2]; - v3 = batch4buf->ptr.p_double[entryoffs+3]; - entryoffs = entryoffs+entrysize; - for(i=1; i<=nout-1; i++) - { - v = batch4buf->ptr.p_double[entryoffs+0]; - if( v>v0 ) - { - v0 = v; - } - v = batch4buf->ptr.p_double[entryoffs+1]; - if( v>v1 ) - { - v1 = v; - } - v = batch4buf->ptr.p_double[entryoffs+2]; - if( v>v2 ) - { - v2 = v; - } - v = batch4buf->ptr.p_double[entryoffs+3]; - if( v>v3 ) - { - v3 = v; - } - entryoffs = entryoffs+entrysize; - } - - /* - * Then, calculate exponentials and place them to part of the - * array which is located past the last entry. We also - * calculate sum of exponentials. - */ - entryoffs = entrysize*(ntotal-nout); - offs0 = entrysize*ntotal; - s0 = 0; - s1 = 0; - s2 = 0; - s3 = 0; - for(i=0; i<=nout-1; i++) - { - v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); - s0 = s0+v; - batch4buf->ptr.p_double[offs0+0] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); - s1 = s1+v; - batch4buf->ptr.p_double[offs0+1] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); - s2 = s2+v; - batch4buf->ptr.p_double[offs0+2] = v; - v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); - s3 = s3+v; - batch4buf->ptr.p_double[offs0+3] = v; - entryoffs = entryoffs+entrysize; - offs0 = offs0+chunksize; - } - - /* - * Write SOFTMAX-normalized values to the output array. - */ - offs0 = entrysize*ntotal; - for(i=0; i<=nout-1; i++) - { - if( csize>0 ) - { - xy->ptr.pp_double[cstart+0][nin+i] = batch4buf->ptr.p_double[offs0+0]/s0; - } - if( csize>1 ) - { - xy->ptr.pp_double[cstart+1][nin+i] = batch4buf->ptr.p_double[offs0+1]/s1; - } - if( csize>2 ) - { - xy->ptr.pp_double[cstart+2][nin+i] = batch4buf->ptr.p_double[offs0+2]/s2; - } - if( csize>3 ) - { - xy->ptr.pp_double[cstart+3][nin+i] = batch4buf->ptr.p_double[offs0+3]/s3; - } - offs0 = offs0+chunksize; - } - } - else - { - - /* - * Regression network with sum-of-squares function. - * - * For each NOut of last neurons: - * * calculate difference between actual and desired output - * * calculate dError/dOut for this neuron (proportional to difference) - * * store in in last 4 components of entry (these values are used - * to start backpropagation) - * * update error - */ - for(i=0; i<=nout-1; i++) - { - v0 = network->columnsigmas.ptr.p_double[nin+i]; - v1 = network->columnmeans.ptr.p_double[nin+i]; - entryoffs = entrysize*(ntotal-nout+i); - for(j=0; j<=csize-1; j++) - { - xy->ptr.pp_double[cstart+j][nin+i] = batch4buf->ptr.p_double[entryoffs+j]*v0+v1; - } - } - } -} - - -/************************************************************************* -Returns T*Ln(T/Z), guarded against overflow/underflow. -Internal subroutine. -*************************************************************************/ -static double mlpbase_safecrossentropy(double t, - double z, - ae_state *_state) -{ - double r; - double result; - - - if( ae_fp_eq(t,0) ) - { - result = 0; - } - else - { - if( ae_fp_greater(ae_fabs(z, _state),1) ) - { - - /* - * Shouldn't be the case with softmax, - * but we just want to be sure. - */ - if( ae_fp_eq(t/z,0) ) - { - r = ae_minrealnumber; - } - else - { - r = t/z; - } - } - else - { - - /* - * Normal case - */ - if( ae_fp_eq(z,0)||ae_fp_greater_eq(ae_fabs(t, _state),ae_maxrealnumber*ae_fabs(z, _state)) ) - { - r = ae_maxrealnumber; - } - else - { - r = t/z; - } - } - result = t*ae_log(r, _state); - } - return result; -} - - -/************************************************************************* -This function performs backward pass of neural network randimization: -* it assumes that Network.Weights stores standard deviation of weights - (weights are not generated yet, only their deviations are present) -* it sets deviations of weights which feed NeuronIdx-th neuron to specified value -* it recursively passes to deeper neuron and modifies their weights -* it stops after encountering nonlinear neurons, linear activation function, - input neurons, "0" and "-1" neurons - - -- ALGLIB -- - Copyright 27.06.2013 by Bochkanov Sergey -*************************************************************************/ -static void mlpbase_randomizebackwardpass(multilayerperceptron* network, - ae_int_t neuronidx, - double v, - ae_state *_state) -{ - ae_int_t istart; - ae_int_t neurontype; - ae_int_t n1; - ae_int_t n2; - ae_int_t w1; - ae_int_t w2; - ae_int_t offs; - ae_int_t i; - - - istart = network->structinfo.ptr.p_int[5]; - neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; - if( neurontype==-2 ) - { - - /* - * Input neuron - stop - */ - return; - } - if( neurontype==-3 ) - { - - /* - * "-1" neuron: stop - */ - return; - } - if( neurontype==-4 ) - { - - /* - * "0" neuron: stop - */ - return; - } - if( neurontype==0 ) - { - - /* - * Adaptive summator neuron: - * * modify deviations of its weights - * * recursively call this function for its inputs - */ - offs = istart+neuronidx*mlpbase_nfieldwidth; - n1 = network->structinfo.ptr.p_int[offs+2]; - n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; - w1 = network->structinfo.ptr.p_int[offs+3]; - w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; - for(i=w1; i<=w2; i++) - { - network->weights.ptr.p_double[i] = v; - } - for(i=n1; i<=n2; i++) - { - mlpbase_randomizebackwardpass(network, i, v, _state); - } - return; - } - if( neurontype==-5 ) - { - - /* - * Linear activation function: stop - */ - return; - } - if( neurontype>0 ) - { - - /* - * Nonlinear activation function: stop - */ - return; - } - ae_assert(ae_false, "RandomizeBackwardPass: unexpected neuron type", _state); -} - - -ae_bool _modelerrors_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - modelerrors *p = (modelerrors*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _modelerrors_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - modelerrors *dst = (modelerrors*)_dst; - modelerrors *src = (modelerrors*)_src; - dst->relclserror = src->relclserror; - dst->avgce = src->avgce; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - return ae_true; -} - - -void _modelerrors_clear(void* _p) -{ - modelerrors *p = (modelerrors*)_p; - ae_touch_ptr((void*)p); -} - - -void _modelerrors_destroy(void* _p) -{ - modelerrors *p = (modelerrors*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _smlpgrad_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - smlpgrad *p = (smlpgrad*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _smlpgrad_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - smlpgrad *dst = (smlpgrad*)_dst; - smlpgrad *src = (smlpgrad*)_src; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _smlpgrad_clear(void* _p) -{ - smlpgrad *p = (smlpgrad*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->g); -} - - -void _smlpgrad_destroy(void* _p) -{ - smlpgrad *p = (smlpgrad*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->g); -} - - -ae_bool _multilayerperceptron_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - multilayerperceptron *p = (multilayerperceptron*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->hllayersizes, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hlconnections, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hlneurons, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->structinfo, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->weights, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->columnmeans, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->neurons, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dfdnet, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->derror, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->nwbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->integerbuf, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !_modelerrors_init(&p->err, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rndbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->buf, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->gradbuf, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->dummydxy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init(&p->dummysxy, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dummyidx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->dummypool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _multilayerperceptron_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - multilayerperceptron *dst = (multilayerperceptron*)_dst; - multilayerperceptron *src = (multilayerperceptron*)_src; - dst->hlnetworktype = src->hlnetworktype; - dst->hlnormtype = src->hlnormtype; - if( !ae_vector_init_copy(&dst->hllayersizes, &src->hllayersizes, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->hlconnections, &src->hlconnections, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->hlneurons, &src->hlneurons, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->structinfo, &src->structinfo, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->weights, &src->weights, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->neurons, &src->neurons, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dfdnet, &src->dfdnet, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->derror, &src->derror, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->nwbuf, &src->nwbuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->integerbuf, &src->integerbuf, _state, make_automatic) ) - return ae_false; - if( !_modelerrors_init_copy(&dst->err, &src->err, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rndbuf, &src->rndbuf, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init_copy(&dst->buf, &src->buf, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init_copy(&dst->gradbuf, &src->gradbuf, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->dummydxy, &src->dummydxy, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init_copy(&dst->dummysxy, &src->dummysxy, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dummyidx, &src->dummyidx, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init_copy(&dst->dummypool, &src->dummypool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _multilayerperceptron_clear(void* _p) -{ - multilayerperceptron *p = (multilayerperceptron*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->hllayersizes); - ae_vector_clear(&p->hlconnections); - ae_vector_clear(&p->hlneurons); - ae_vector_clear(&p->structinfo); - ae_vector_clear(&p->weights); - ae_vector_clear(&p->columnmeans); - ae_vector_clear(&p->columnsigmas); - ae_vector_clear(&p->neurons); - ae_vector_clear(&p->dfdnet); - ae_vector_clear(&p->derror); - ae_vector_clear(&p->x); - ae_vector_clear(&p->y); - ae_matrix_clear(&p->xy); - ae_vector_clear(&p->xyrow); - ae_vector_clear(&p->nwbuf); - ae_vector_clear(&p->integerbuf); - _modelerrors_clear(&p->err); - ae_vector_clear(&p->rndbuf); - ae_shared_pool_clear(&p->buf); - ae_shared_pool_clear(&p->gradbuf); - ae_matrix_clear(&p->dummydxy); - _sparsematrix_clear(&p->dummysxy); - ae_vector_clear(&p->dummyidx); - ae_shared_pool_clear(&p->dummypool); -} - - -void _multilayerperceptron_destroy(void* _p) -{ - multilayerperceptron *p = (multilayerperceptron*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->hllayersizes); - ae_vector_destroy(&p->hlconnections); - ae_vector_destroy(&p->hlneurons); - ae_vector_destroy(&p->structinfo); - ae_vector_destroy(&p->weights); - ae_vector_destroy(&p->columnmeans); - ae_vector_destroy(&p->columnsigmas); - ae_vector_destroy(&p->neurons); - ae_vector_destroy(&p->dfdnet); - ae_vector_destroy(&p->derror); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->y); - ae_matrix_destroy(&p->xy); - ae_vector_destroy(&p->xyrow); - ae_vector_destroy(&p->nwbuf); - ae_vector_destroy(&p->integerbuf); - _modelerrors_destroy(&p->err); - ae_vector_destroy(&p->rndbuf); - ae_shared_pool_destroy(&p->buf); - ae_shared_pool_destroy(&p->gradbuf); - ae_matrix_destroy(&p->dummydxy); - _sparsematrix_destroy(&p->dummysxy); - ae_vector_destroy(&p->dummyidx); - ae_shared_pool_destroy(&p->dummypool); -} - - - - -/************************************************************************* -This subroutine trains logit model. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars] - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPointsptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * Initialize data - */ - rep->ngrad = 0; - rep->nhess = 0; - - /* - * Allocate array - */ - offs = 5; - ssize = 5+(nvars+1)*(nclasses-1)+nclasses; - ae_vector_set_length(&lm->w, ssize-1+1, _state); - lm->w.ptr.p_double[0] = ssize; - lm->w.ptr.p_double[1] = logit_logitvnum; - lm->w.ptr.p_double[2] = nvars; - lm->w.ptr.p_double[3] = nclasses; - lm->w.ptr.p_double[4] = offs; - - /* - * Degenerate case: all outputs are equal - */ - allsame = ae_true; - for(i=1; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nvars], _state)!=ae_round(xy->ptr.pp_double[i-1][nvars], _state) ) - { - allsame = ae_false; - } - } - if( allsame ) - { - for(i=0; i<=(nvars+1)*(nclasses-1)-1; i++) - { - lm->w.ptr.p_double[offs+i] = 0; - } - v = -2*ae_log(ae_minrealnumber, _state); - k = ae_round(xy->ptr.pp_double[0][nvars], _state); - if( k==nclasses-1 ) - { - for(i=0; i<=nclasses-2; i++) - { - lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = -v; - } - } - else - { - for(i=0; i<=nclasses-2; i++) - { - if( i==k ) - { - lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = v; - } - else - { - lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = 0; - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * General case. - * Prepare task and network. Allocate space. - */ - mlpcreatec0(nvars, nclasses, &network, _state); - mlpinitpreprocessor(&network, xy, npoints, _state); - mlpproperties(&network, &nin, &nout, &wcount, _state); - for(i=0; i<=wcount-1; i++) - { - network.weights.ptr.p_double[i] = (2*ae_randomreal(_state)-1)/nvars; - } - ae_vector_set_length(&g, wcount-1+1, _state); - ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); - ae_vector_set_length(&wbase, wcount-1+1, _state); - ae_vector_set_length(&wdir, wcount-1+1, _state); - ae_vector_set_length(&work, wcount-1+1, _state); - - /* - * First stage: optimize in gradient direction. - */ - for(k=0; k<=wcount/3+10; k++) - { - - /* - * Calculate gradient in starting point - */ - mlpgradnbatch(&network, xy, npoints, &e, &g, _state); - v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - rep->ngrad = rep->ngrad+1; - - /* - * Setup optimization scheme - */ - ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - wstep = ae_sqrt(v, _state); - v = 1/ae_sqrt(v, _state); - ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); - mcstage = 0; - logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); - while(mcstage!=0) - { - mlpgradnbatch(&network, xy, npoints, &e, &g, _state); - v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - rep->ngrad = rep->ngrad+1; - logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); - } - } - - /* - * Second stage: use Hessian when we are close to the minimum - */ - for(;;) - { - - /* - * Calculate and update E/G/H - */ - mlphessiannbatch(&network, xy, npoints, &e, &g, &h, _state); - v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - for(k=0; k<=wcount-1; k++) - { - h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; - } - rep->nhess = rep->nhess+1; - - /* - * Select step direction - * NOTE: it is important to use lower-triangle Cholesky - * factorization since it is much faster than higher-triangle version. - */ - spd = spdmatrixcholesky(&h, wcount, ae_false, _state); - spdmatrixcholeskysolve(&h, wcount, ae_false, &g, &solverinfo, &solverrep, &wdir, _state); - spd = solverinfo>0; - if( spd ) - { - - /* - * H is positive definite. - * Step in Newton direction. - */ - ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1); - spd = ae_true; - } - else - { - - /* - * H is indefinite. - * Step in gradient direction. - */ - ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - spd = ae_false; - } - - /* - * Optimize in WDir direction - */ - v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - wstep = ae_sqrt(v, _state); - v = 1/ae_sqrt(v, _state); - ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); - mcstage = 0; - logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); - while(mcstage!=0) - { - mlpgradnbatch(&network, xy, npoints, &e, &g, _state); - v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - rep->ngrad = rep->ngrad+1; - logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); - } - if( spd&&((mcinfo==2||mcinfo==4)||mcinfo==6) ) - { - break; - } - } - - /* - * Convert from NN format to MNL format - */ - ae_v_move(&lm->w.ptr.p_double[offs], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); - for(k=0; k<=nvars-1; k++) - { - for(i=0; i<=nclasses-2; i++) - { - s = network.columnsigmas.ptr.p_double[k]; - if( ae_fp_eq(s,0) ) - { - s = 1; - } - j = offs+(nvars+1)*i; - v = lm->w.ptr.p_double[j+k]; - lm->w.ptr.p_double[j+k] = v/s; - lm->w.ptr.p_double[j+nvars] = lm->w.ptr.p_double[j+nvars]+v*network.columnmeans.ptr.p_double[k]/s; - } - } - for(k=0; k<=nclasses-2; k++) - { - lm->w.ptr.p_double[offs+(nvars+1)*k+nvars] = -lm->w.ptr.p_double[offs+(nvars+1)*k+nvars]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - LM - logit model, passed by non-constant reference - (some fields of structure are used as temporaries - when calculating model output). - X - input vector, array[0..NVars-1]. - Y - (possibly) preallocated buffer; if size of Y is less than - NClasses, it will be reallocated.If it is large enough, it - is NOT reallocated, so we can save some time on reallocation. - -OUTPUT PARAMETERS: - Y - result, array[0..NClasses-1] - Vector of posterior probabilities for classification task. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlprocess(logitmodel* lm, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t offs; - ae_int_t i; - ae_int_t i1; - double s; - - - ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],logit_logitvnum), "MNLProcess: unexpected model version", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - nclasses = ae_round(lm->w.ptr.p_double[3], _state); - offs = ae_round(lm->w.ptr.p_double[4], _state); - logit_mnliexp(&lm->w, x, _state); - s = 0; - i1 = offs+(nvars+1)*(nclasses-1); - for(i=i1; i<=i1+nclasses-1; i++) - { - s = s+lm->w.ptr.p_double[i]; - } - if( y->cntptr.p_double[i] = lm->w.ptr.p_double[i1+i]/s; - } -} - - -/************************************************************************* -'interactive' variant of MNLProcess for languages like Python which -support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlprocessi(logitmodel* lm, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - ae_vector_clear(y); - - mnlprocess(lm, x, y, _state); -} - - -/************************************************************************* -Unpacks coefficients of logit model. Logit model have form: - - P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) - S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when iw.ptr.p_double[1],logit_logitvnum), "MNLUnpack: unexpected model version", _state); - *nvars = ae_round(lm->w.ptr.p_double[2], _state); - *nclasses = ae_round(lm->w.ptr.p_double[3], _state); - offs = ae_round(lm->w.ptr.p_double[4], _state); - ae_matrix_set_length(a, *nclasses-2+1, *nvars+1, _state); - for(i=0; i<=*nclasses-2; i++) - { - ae_v_move(&a->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs+i*(*nvars+1)], 1, ae_v_len(0,*nvars)); - } -} - - -/************************************************************************* -"Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack -reversed). - -INPUT PARAMETERS: - A - model (see MNLUnpack) - NVars - number of independent variables - NClasses - number of classes - -OUTPUT PARAMETERS: - LM - logit model. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -void mnlpack(/* Real */ ae_matrix* a, - ae_int_t nvars, - ae_int_t nclasses, - logitmodel* lm, - ae_state *_state) -{ - ae_int_t offs; - ae_int_t i; - ae_int_t ssize; - - _logitmodel_clear(lm); - - offs = 5; - ssize = 5+(nvars+1)*(nclasses-1)+nclasses; - ae_vector_set_length(&lm->w, ssize-1+1, _state); - lm->w.ptr.p_double[0] = ssize; - lm->w.ptr.p_double[1] = logit_logitvnum; - lm->w.ptr.p_double[2] = nvars; - lm->w.ptr.p_double[3] = nclasses; - lm->w.ptr.p_double[4] = offs; - for(i=0; i<=nclasses-2; i++) - { - ae_v_move(&lm->w.ptr.p_double[offs+i*(nvars+1)], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars)); - } -} - - -/************************************************************************* -Copying of LogitModel strucure - -INPUT PARAMETERS: - LM1 - original - -OUTPUT PARAMETERS: - LM2 - copy - - -- ALGLIB -- - Copyright 15.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mnlcopy(logitmodel* lm1, logitmodel* lm2, ae_state *_state) -{ - ae_int_t k; - - _logitmodel_clear(lm2); - - k = ae_round(lm1->w.ptr.p_double[0], _state); - ae_vector_set_length(&lm2->w, k-1+1, _state); - ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); -} - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*ln(2)). - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgce(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t i; - ae_vector workx; - ae_vector worky; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&worky, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],logit_logitvnum), "MNLClsError: unexpected model version", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - nclasses = ae_round(lm->w.ptr.p_double[3], _state); - ae_vector_set_length(&workx, nvars-1+1, _state); - ae_vector_set_length(&worky, nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - ae_assert(ae_round(xy->ptr.pp_double[i][nvars], _state)>=0&&ae_round(xy->ptr.pp_double[i][nvars], _state)ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - mnlprocess(lm, &workx, &worky, _state); - if( ae_fp_greater(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)],0) ) - { - result = result-ae_log(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)], _state); - } - else - { - result = result-ae_log(ae_minrealnumber, _state); - } - } - result = result/(npoints*ae_log(2, _state)); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlrelclserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double result; - - - result = (double)mnlclserror(lm, xy, npoints, _state)/(double)npoints; - return result; -} - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - root mean square error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlrmserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double relcls; - double avgce; - double rms; - double avg; - double avgrel; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); - logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); - result = rms; - return result; -} - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - average error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgerror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double relcls; - double avgce; - double rms; - double avg; - double avgrel; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); - logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); - result = avg; - return result; -} - - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - LM - logit model - XY - test set - NPoints - test set size - -RESULT: - average relative error (error when estimating posterior probabilities). - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -double mnlavgrelerror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state) -{ - double relcls; - double avgce; - double rms; - double avg; - double avgrel; - double result; - - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); - logit_mnlallerrors(lm, xy, ssize, &relcls, &avgce, &rms, &avg, &avgrel, _state); - result = avgrel; - return result; -} - - -/************************************************************************* -Classification error on test set = MNLRelClsError*NPoints - - -- ALGLIB -- - Copyright 10.09.2008 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mnlclserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t i; - ae_int_t j; - ae_vector workx; - ae_vector worky; - ae_int_t nmax; - ae_int_t result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&worky, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],logit_logitvnum), "MNLClsError: unexpected model version", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - nclasses = ae_round(lm->w.ptr.p_double[3], _state); - ae_vector_set_length(&workx, nvars-1+1, _state); - ae_vector_set_length(&worky, nclasses-1+1, _state); - result = 0; - for(i=0; i<=npoints-1; i++) - { - - /* - * Process - */ - ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - mnlprocess(lm, &workx, &worky, _state); - - /* - * Logit version of the answer - */ - nmax = 0; - for(j=0; j<=nclasses-1; j++) - { - if( ae_fp_greater(worky.ptr.p_double[j],worky.ptr.p_double[nmax]) ) - { - nmax = j; - } - } - - /* - * compare - */ - if( nmax!=ae_round(xy->ptr.pp_double[i][nvars], _state) ) - { - result = result+1; - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Internal subroutine. Places exponents of the anti-overflow shifted -internal linear outputs into the service part of the W array. -*************************************************************************/ -static void logit_mnliexp(/* Real */ ae_vector* w, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t offs; - ae_int_t i; - ae_int_t i1; - double v; - double mx; - - - ae_assert(ae_fp_eq(w->ptr.p_double[1],logit_logitvnum), "LOGIT: unexpected model version", _state); - nvars = ae_round(w->ptr.p_double[2], _state); - nclasses = ae_round(w->ptr.p_double[3], _state); - offs = ae_round(w->ptr.p_double[4], _state); - i1 = offs+(nvars+1)*(nclasses-1); - for(i=0; i<=nclasses-2; i++) - { - v = ae_v_dotproduct(&w->ptr.p_double[offs+i*(nvars+1)], 1, &x->ptr.p_double[0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars-1)); - w->ptr.p_double[i1+i] = v+w->ptr.p_double[offs+i*(nvars+1)+nvars]; - } - w->ptr.p_double[i1+nclasses-1] = 0; - mx = 0; - for(i=i1; i<=i1+nclasses-1; i++) - { - mx = ae_maxreal(mx, w->ptr.p_double[i], _state); - } - for(i=i1; i<=i1+nclasses-1; i++) - { - w->ptr.p_double[i] = ae_exp(w->ptr.p_double[i]-mx, _state); - } -} - - -/************************************************************************* -Calculation of all types of errors - - -- ALGLIB -- - Copyright 30.08.2008 by Bochkanov Sergey -*************************************************************************/ -static void logit_mnlallerrors(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double* relcls, - double* avgce, - double* rms, - double* avg, - double* avgrel, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t i; - ae_vector buf; - ae_vector workx; - ae_vector y; - ae_vector dy; - - ae_frame_make(_state, &_frame_block); - *relcls = 0; - *avgce = 0; - *rms = 0; - *avg = 0; - *avgrel = 0; - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNL unit: Incorrect MNL version!", _state); - nvars = ae_round(lm->w.ptr.p_double[2], _state); - nclasses = ae_round(lm->w.ptr.p_double[3], _state); - ae_vector_set_length(&workx, nvars-1+1, _state); - ae_vector_set_length(&y, nclasses-1+1, _state); - ae_vector_set_length(&dy, 0+1, _state); - dserrallocate(nclasses, &buf, _state); - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - mnlprocess(lm, &workx, &y, _state); - dy.ptr.p_double[0] = xy->ptr.pp_double[i][nvars]; - dserraccumulate(&buf, &y, &dy, _state); - } - dserrfinish(&buf, _state); - *relcls = buf.ptr.p_double[0]; - *avgce = buf.ptr.p_double[1]; - *rms = buf.ptr.p_double[2]; - *avg = buf.ptr.p_double[3]; - *avgrel = buf.ptr.p_double[4]; - ae_frame_leave(_state); -} - - -/************************************************************************* -THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT -DECREASE CONDITION AND A CURVATURE CONDITION. - -AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH -ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN -SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION - - F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). - -IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE -FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF -UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). - -THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT -DECREASE CONDITION - - F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), - -AND THE CURVATURE CONDITION - - ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). - -IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED -BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. -IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE -ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. -IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. - -PARAMETERS DESCRIPRION - -N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES. - -X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR -THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S. - -F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT -IT CONTAINS THE VALUE OF F AT X + STP*S. - -G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X. -ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S. - -S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION. - -STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE -OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE. - -FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE -SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE -SATISFIED. - -XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE -WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. - -STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND -UPPER BOUNDS FOR THE STEP. - -MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE -NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION. - -INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS: - INFO = 0 IMPROPER INPUT PARAMETERS. - - INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE - DIRECTIONAL DERIVATIVE CONDITION HOLD. - - INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY - IS AT MOST XTOL. - - INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV. - - INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN. - - INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX. - - INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS. - THERE MAY NOT BE A STEP WHICH SATISFIES THE - SUFFICIENT DECREASE AND CURVATURE CONDITIONS. - TOLERANCES MAY BE TOO SMALL. - -NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN. - -WA IS A WORK ARRAY OF LENGTH N. - -ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983 -JORGE J. MORE', DAVID J. THUENTE -*************************************************************************/ -static void logit_mnlmcsrch(ae_int_t n, - /* Real */ ae_vector* x, - double* f, - /* Real */ ae_vector* g, - /* Real */ ae_vector* s, - double* stp, - ae_int_t* info, - ae_int_t* nfev, - /* Real */ ae_vector* wa, - logitmcstate* state, - ae_int_t* stage, - ae_state *_state) -{ - double v; - double p5; - double p66; - double zero; - - - - /* - * init - */ - p5 = 0.5; - p66 = 0.66; - state->xtrapf = 4.0; - zero = 0; - - /* - * Main cycle - */ - for(;;) - { - if( *stage==0 ) - { - - /* - * NEXT - */ - *stage = 2; - continue; - } - if( *stage==2 ) - { - state->infoc = 1; - *info = 0; - - /* - * CHECK THE INPUT PARAMETERS FOR ERRORS. - */ - if( ((((((n<=0||ae_fp_less_eq(*stp,0))||ae_fp_less(logit_ftol,0))||ae_fp_less(logit_gtol,zero))||ae_fp_less(logit_xtol,zero))||ae_fp_less(logit_stpmin,zero))||ae_fp_less(logit_stpmax,logit_stpmin))||logit_maxfev<=0 ) - { - *stage = 0; - return; - } - - /* - * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION - * AND CHECK THAT S IS A DESCENT DIRECTION. - */ - v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->dginit = v; - if( ae_fp_greater_eq(state->dginit,0) ) - { - *stage = 0; - return; - } - - /* - * INITIALIZE LOCAL VARIABLES. - */ - state->brackt = ae_false; - state->stage1 = ae_true; - *nfev = 0; - state->finit = *f; - state->dgtest = logit_ftol*state->dginit; - state->width = logit_stpmax-logit_stpmin; - state->width1 = state->width/p5; - ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, - * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. - * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, - * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF - * THE INTERVAL OF UNCERTAINTY. - * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, - * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. - */ - state->stx = 0; - state->fx = state->finit; - state->dgx = state->dginit; - state->sty = 0; - state->fy = state->finit; - state->dgy = state->dginit; - - /* - * NEXT - */ - *stage = 3; - continue; - } - if( *stage==3 ) - { - - /* - * START OF ITERATION. - * - * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND - * TO THE PRESENT INTERVAL OF UNCERTAINTY. - */ - if( state->brackt ) - { - if( ae_fp_less(state->stx,state->sty) ) - { - state->stmin = state->stx; - state->stmax = state->sty; - } - else - { - state->stmin = state->sty; - state->stmax = state->stx; - } - } - else - { - state->stmin = state->stx; - state->stmax = *stp+state->xtrapf*(*stp-state->stx); - } - - /* - * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. - */ - if( ae_fp_greater(*stp,logit_stpmax) ) - { - *stp = logit_stpmax; - } - if( ae_fp_less(*stp,logit_stpmin) ) - { - *stp = logit_stpmin; - } - - /* - * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET - * STP BE THE LOWEST POINT OBTAINED SO FAR. - */ - if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=logit_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax)) ) - { - *stp = state->stx; - } - - /* - * EVALUATE THE FUNCTION AND GRADIENT AT STP - * AND COMPUTE THE DIRECTIONAL DERIVATIVE. - */ - ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); - - /* - * NEXT - */ - *stage = 4; - return; - } - if( *stage==4 ) - { - *info = 0; - *nfev = *nfev+1; - v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->dg = v; - state->ftest1 = state->finit+*stp*state->dgtest; - - /* - * TEST FOR CONVERGENCE. - */ - if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) - { - *info = 6; - } - if( (ae_fp_eq(*stp,logit_stpmax)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) - { - *info = 5; - } - if( ae_fp_eq(*stp,logit_stpmin)&&(ae_fp_greater(*f,state->ftest1)||ae_fp_greater_eq(state->dg,state->dgtest)) ) - { - *info = 4; - } - if( *nfev>=logit_maxfev ) - { - *info = 3; - } - if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax) ) - { - *info = 2; - } - if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-logit_gtol*state->dginit) ) - { - *info = 1; - } - - /* - * CHECK FOR TERMINATION. - */ - if( *info!=0 ) - { - *stage = 0; - return; - } - - /* - * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED - * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. - */ - if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(logit_ftol, logit_gtol, _state)*state->dginit) ) - { - state->stage1 = ae_false; - } - - /* - * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF - * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED - * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE - * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN - * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. - */ - if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) - { - - /* - * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. - */ - state->fm = *f-*stp*state->dgtest; - state->fxm = state->fx-state->stx*state->dgtest; - state->fym = state->fy-state->sty*state->dgtest; - state->dgm = state->dg-state->dgtest; - state->dgxm = state->dgx-state->dgtest; - state->dgym = state->dgy-state->dgtest; - - /* - * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY - * AND TO COMPUTE THE NEW STEP. - */ - logit_mnlmcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); - - /* - * RESET THE FUNCTION AND GRADIENT VALUES FOR F. - */ - state->fx = state->fxm+state->stx*state->dgtest; - state->fy = state->fym+state->sty*state->dgtest; - state->dgx = state->dgxm+state->dgtest; - state->dgy = state->dgym+state->dgtest; - } - else - { - - /* - * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY - * AND TO COMPUTE THE NEW STEP. - */ - logit_mnlmcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); - } - - /* - * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE - * INTERVAL OF UNCERTAINTY. - */ - if( state->brackt ) - { - if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) - { - *stp = state->stx+p5*(state->sty-state->stx); - } - state->width1 = state->width; - state->width = ae_fabs(state->sty-state->stx, _state); - } - - /* - * NEXT. - */ - *stage = 3; - continue; - } - } -} - - -static void logit_mnlmcstep(double* stx, - double* fx, - double* dx, - double* sty, - double* fy, - double* dy, - double* stp, - double fp, - double dp, - ae_bool* brackt, - double stmin, - double stmax, - ae_int_t* info, - ae_state *_state) -{ - ae_bool bound; - double gamma; - double p; - double q; - double r; - double s; - double sgnd; - double stpc; - double stpf; - double stpq; - double theta; - - - *info = 0; - - /* - * CHECK THE INPUT PARAMETERS FOR ERRORS. - */ - if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),0))||ae_fp_less(stmax,stmin) ) - { - return; - } - - /* - * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. - */ - sgnd = dp*(*dx/ae_fabs(*dx, _state)); - - /* - * FIRST CASE. A HIGHER FUNCTION VALUE. - * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER - * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, - * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. - */ - if( ae_fp_greater(fp,*fx) ) - { - *info = 1; - bound = ae_true; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); - if( ae_fp_less(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-(*dx)+theta; - q = gamma-(*dx)+gamma+dp; - r = p/q; - stpc = *stx+r*(*stp-(*stx)); - stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/2*(*stp-(*stx)); - if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpc+(stpq-stpc)/2; - } - *brackt = ae_true; - } - else - { - if( ae_fp_less(sgnd,0) ) - { - - /* - * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF - * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC - * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, - * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. - */ - *info = 2; - bound = ae_false; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); - if( ae_fp_greater(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma-dp+gamma+(*dx); - r = p/q; - stpc = *stp+r*(*stx-(*stp)); - stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); - if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - *brackt = ae_true; - } - else - { - if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) - { - - /* - * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE - * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. - * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY - * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC - * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE - * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO - * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP - * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. - */ - *info = 3; - bound = ae_true; - theta = 3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); - - /* - * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND - * TO INFINITY IN THE DIRECTION OF THE STEP. - */ - gamma = s*ae_sqrt(ae_maxreal(0, ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); - if( ae_fp_greater(*stp,*stx) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma+(*dx-dp)+gamma; - r = p/q; - if( ae_fp_less(r,0)&&ae_fp_neq(gamma,0) ) - { - stpc = *stp+r*(*stx-(*stp)); - } - else - { - if( ae_fp_greater(*stp,*stx) ) - { - stpc = stmax; - } - else - { - stpc = stmin; - } - } - stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); - if( *brackt ) - { - if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - } - else - { - if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) - { - stpf = stpc; - } - else - { - stpf = stpq; - } - } - } - else - { - - /* - * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE - * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES - * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP - * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. - */ - *info = 4; - bound = ae_false; - if( *brackt ) - { - theta = 3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; - s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); - gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); - if( ae_fp_greater(*stp,*sty) ) - { - gamma = -gamma; - } - p = gamma-dp+theta; - q = gamma-dp+gamma+(*dy); - r = p/q; - stpc = *stp+r*(*sty-(*stp)); - stpf = stpc; - } - else - { - if( ae_fp_greater(*stp,*stx) ) - { - stpf = stmax; - } - else - { - stpf = stmin; - } - } - } - } - } - - /* - * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT - * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. - */ - if( ae_fp_greater(fp,*fx) ) - { - *sty = *stp; - *fy = fp; - *dy = dp; - } - else - { - if( ae_fp_less(sgnd,0.0) ) - { - *sty = *stx; - *fy = *fx; - *dy = *dx; - } - *stx = *stp; - *fx = fp; - *dx = dp; - } - - /* - * COMPUTE THE NEW STEP AND SAFEGUARD IT. - */ - stpf = ae_minreal(stmax, stpf, _state); - stpf = ae_maxreal(stmin, stpf, _state); - *stp = stpf; - if( *brackt&&bound ) - { - if( ae_fp_greater(*sty,*stx) ) - { - *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); - } - else - { - *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); - } - } -} - - -ae_bool _logitmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - logitmodel *p = (logitmodel*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _logitmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - logitmodel *dst = (logitmodel*)_dst; - logitmodel *src = (logitmodel*)_src; - if( !ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _logitmodel_clear(void* _p) -{ - logitmodel *p = (logitmodel*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->w); -} - - -void _logitmodel_destroy(void* _p) -{ - logitmodel *p = (logitmodel*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->w); -} - - -ae_bool _logitmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - logitmcstate *p = (logitmcstate*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _logitmcstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - logitmcstate *dst = (logitmcstate*)_dst; - logitmcstate *src = (logitmcstate*)_src; - dst->brackt = src->brackt; - dst->stage1 = src->stage1; - dst->infoc = src->infoc; - dst->dg = src->dg; - dst->dgm = src->dgm; - dst->dginit = src->dginit; - dst->dgtest = src->dgtest; - dst->dgx = src->dgx; - dst->dgxm = src->dgxm; - dst->dgy = src->dgy; - dst->dgym = src->dgym; - dst->finit = src->finit; - dst->ftest1 = src->ftest1; - dst->fm = src->fm; - dst->fx = src->fx; - dst->fxm = src->fxm; - dst->fy = src->fy; - dst->fym = src->fym; - dst->stx = src->stx; - dst->sty = src->sty; - dst->stmin = src->stmin; - dst->stmax = src->stmax; - dst->width = src->width; - dst->width1 = src->width1; - dst->xtrapf = src->xtrapf; - return ae_true; -} - - -void _logitmcstate_clear(void* _p) -{ - logitmcstate *p = (logitmcstate*)_p; - ae_touch_ptr((void*)p); -} - - -void _logitmcstate_destroy(void* _p) -{ - logitmcstate *p = (logitmcstate*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _mnlreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mnlreport *p = (mnlreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _mnlreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mnlreport *dst = (mnlreport*)_dst; - mnlreport *src = (mnlreport*)_src; - dst->ngrad = src->ngrad; - dst->nhess = src->nhess; - return ae_true; -} - - -void _mnlreport_clear(void* _p) -{ - mnlreport *p = (mnlreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _mnlreport_destroy(void* _p) -{ - mnlreport *p = (mnlreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -DESCRIPTION: - -This function creates MCPD (Markov Chains for Population Data) solver. - -This solver can be used to find transition matrix P for N-dimensional -prediction problem where transition from X[i] to X[i+1] is modelled as - X[i+1] = P*X[i] -where X[i] and X[i+1] are N-dimensional population vectors (components of -each X are non-negative), and P is a N*N transition matrix (elements of P -are non-negative, each column sums to 1.0). - -Such models arise when when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is constant, i.e. there is no new individuals and no one - leaves population -* you want to model transitions of individuals from one state into another - -USAGE: - -Here we give very brief outline of the MCPD. We strongly recommend you to -read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on data analysis which is available at http://www.alglib.net/dataanalysis/ - -1. User initializes algorithm state with MCPDCreate() call - -2. User adds one or more tracks - sequences of states which describe - evolution of a system being modelled from different starting conditions - -3. User may add optional boundary, equality and/or linear constraints on - the coefficients of P by calling one of the following functions: - * MCPDSetEC() to set equality constraints - * MCPDSetBC() to set bound constraints - * MCPDSetLC() to set linear constraints - -4. Optionally, user may set custom weights for prediction errors (by - default, algorithm assigns non-equal, automatically chosen weights for - errors in the prediction of different components of X). It can be done - with a call of MCPDSetPredictionWeights() function. - -5. User calls MCPDSolve() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -6. User calls MCPDResults() to get solution - -INPUT PARAMETERS: - N - problem dimension, N>=1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state) -{ - - _mcpdstate_clear(s); - - ae_assert(n>=1, "MCPDCreate: N<1", _state); - mcpd_mcpdinit(n, -1, -1, s, _state); -} - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "entry" state and is treated -in a special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -Such conditions basically mean that row of P which corresponds to "entry" -state is zero. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - at every moment of time there is some - (unpredictable) amount of "new" individuals, which can transit into one - of the states at the next turn, but still no one leaves population -* you want to model transitions of individuals from one state into another -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentry(ae_int_t n, - ae_int_t entrystate, - mcpdstate* s, - ae_state *_state) -{ - - _mcpdstate_clear(s); - - ae_assert(n>=2, "MCPDCreateEntry: N<2", _state); - ae_assert(entrystate>=0, "MCPDCreateEntry: EntryState<0", _state); - ae_assert(entrystate=N", _state); - mcpd_mcpdinit(n, entrystate, -1, s, _state); -} - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "exit" state and is treated -in a special way: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that column of P which corresponds to -"exit" state is zero. Multiplication by such P may decrease sum of vector -components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - individuals can move into "exit" state - and leave population at the next turn, but there are no new individuals -* amount of individuals which leave population can be predicted -* you want to model transitions of individuals from one state into another - (including transitions into the "exit" state) - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateexit(ae_int_t n, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state) -{ - - _mcpdstate_clear(s); - - ae_assert(n>=2, "MCPDCreateExit: N<2", _state); - ae_assert(exitstate>=0, "MCPDCreateExit: ExitState<0", _state); - ae_assert(exitstate=N", _state); - mcpd_mcpdinit(n, -1, exitstate, s, _state); -} - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-Exit-states" model, i.e. model where transition from X[i] to -X[i+1] is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -one selected component of X[] is called "entry" state and is treated in a -special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -and another one component of X[] is called "exit" state and is treated in -a special way too: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that: - row of P which corresponds to "entry" state is zero - column of P which corresponds to "exit" state is zero -Multiplication by such P may decrease sum of vector components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant -* at every moment of time there is some (unpredictable) amount of "new" - individuals, which can transit into one of the states at the next turn -* some individuals can move (predictably) into "exit" state and leave - population at the next turn -* you want to model transitions of individuals from one state into another, - including transitions from the "entry" state and into the "exit" state. -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentryexit(ae_int_t n, - ae_int_t entrystate, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state) -{ - - _mcpdstate_clear(s); - - ae_assert(n>=2, "MCPDCreateEntryExit: N<2", _state); - ae_assert(entrystate>=0, "MCPDCreateEntryExit: EntryState<0", _state); - ae_assert(entrystate=N", _state); - ae_assert(exitstate>=0, "MCPDCreateEntryExit: ExitState<0", _state); - ae_assert(exitstate=N", _state); - ae_assert(entrystate!=exitstate, "MCPDCreateEntryExit: EntryState=ExitState", _state); - mcpd_mcpdinit(n, entrystate, exitstate, s, _state); -} - - -/************************************************************************* -This function is used to add a track - sequence of system states at the -different moments of its evolution. - -You may add one or several tracks to the MCPD solver. In case you have -several tracks, they won't overwrite each other. For example, if you pass -two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then -solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, -t=B+1 to t=B+2, t=B+2 to t=B+3. But it WON'T mix these two tracks - i.e. it -won't try to model transition from t=A+3 to t=B+1. - -INPUT PARAMETERS: - S - solver - XY - track, array[K,N]: - * I-th row is a state at t=I - * elements of XY must be non-negative (exception will be - thrown on negative elements) - K - number of points in a track - * if given, only leading K rows of XY are used - * if not given, automatically determined from size of XY - -NOTES: - -1. Track may contain either proportional or population data: - * with proportional data all rows of XY must sum to 1.0, i.e. we have - proportions instead of absolute population values - * with population data rows of XY contain population counts and generally - do not sum to 1.0 (although they still must be non-negative) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddtrack(mcpdstate* s, - /* Real */ ae_matrix* xy, - ae_int_t k, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - double s0; - double s1; - - - n = s->n; - ae_assert(k>=0, "MCPDAddTrack: K<0", _state); - ae_assert(xy->cols>=n, "MCPDAddTrack: Cols(XY)rows>=k, "MCPDAddTrack: Rows(XY)ptr.pp_double[i][j],0), "MCPDAddTrack: XY contains negative elements", _state); - } - } - if( k<2 ) - { - return; - } - if( s->data.rowsnpairs+k-1 ) - { - rmatrixresize(&s->data, ae_maxint(2*s->data.rows, s->npairs+k-1, _state), 2*n, _state); - } - for(i=0; i<=k-2; i++) - { - s0 = 0; - s1 = 0; - for(j=0; j<=n-1; j++) - { - if( s->states.ptr.p_int[j]>=0 ) - { - s0 = s0+xy->ptr.pp_double[i][j]; - } - if( s->states.ptr.p_int[j]<=0 ) - { - s1 = s1+xy->ptr.pp_double[i+1][j]; - } - } - if( ae_fp_greater(s0,0)&&ae_fp_greater(s1,0) ) - { - for(j=0; j<=n-1; j++) - { - if( s->states.ptr.p_int[j]>=0 ) - { - s->data.ptr.pp_double[s->npairs][j] = xy->ptr.pp_double[i][j]/s0; - } - else - { - s->data.ptr.pp_double[s->npairs][j] = 0.0; - } - if( s->states.ptr.p_int[j]<=0 ) - { - s->data.ptr.pp_double[s->npairs][n+j] = xy->ptr.pp_double[i+1][j]/s1; - } - else - { - s->data.ptr.pp_double[s->npairs][n+j] = 0.0; - } - } - s->npairs = s->npairs+1; - } - } -} - - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place equality constraints on arbitrary -subset of elements of P. Set of constraints is specified by EC, which may -contain either NAN's or finite numbers from [0,1]. NAN denotes absence of -constraint, finite number denotes equality constraint on specific element -of P. - -You can also use MCPDAddEC() function which allows to ADD equality -constraint for one element of P without changing constraints for other -elements. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - EC - equality constraints, array[N,N]. Elements of EC can be - either NAN's or finite numbers from [0,1]. NAN denotes - absence of constraints, while finite value denotes - equality constraint on the corresponding element of P. - -NOTES: - -1. infinite values of EC will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetec(mcpdstate* s, - /* Real */ ae_matrix* ec, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - - - n = s->n; - ae_assert(ec->cols>=n, "MCPDSetEC: Cols(EC)rows>=n, "MCPDSetEC: Rows(EC)ptr.pp_double[i][j], _state)||ae_isnan(ec->ptr.pp_double[i][j], _state), "MCPDSetEC: EC containts infinite elements", _state); - s->ec.ptr.pp_double[i][j] = ec->ptr.pp_double[i][j]; - } - } -} - - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD equality constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetEC() function which allows you to specify -arbitrary set of equality constraints in one call. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - I - row index of element being constrained - J - column index of element being constrained - C - value (constraint for P[I,J]). Can be either NAN (no - constraint) or finite value from [0,1]. - -NOTES: - -1. infinite values of C will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddec(mcpdstate* s, - ae_int_t i, - ae_int_t j, - double c, - ae_state *_state) -{ - - - ae_assert(i>=0, "MCPDAddEC: I<0", _state); - ae_assert(in, "MCPDAddEC: I>=N", _state); - ae_assert(j>=0, "MCPDAddEC: J<0", _state); - ae_assert(jn, "MCPDAddEC: J>=N", _state); - ae_assert(ae_isnan(c, _state)||ae_isfinite(c, _state), "MCPDAddEC: C is not finite number or NAN", _state); - s->ec.ptr.pp_double[i][j] = c; -} - - -/************************************************************************* -This function is used to add bound constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place bound constraints on arbitrary -subset of elements of P. Set of constraints is specified by BndL/BndU -matrices, which may contain arbitrary combination of finite numbers or -infinities (like -INFn; - ae_assert(bndl->cols>=n, "MCPDSetBC: Cols(BndL)rows>=n, "MCPDSetBC: Rows(BndL)cols>=n, "MCPDSetBC: Cols(BndU)rows>=n, "MCPDSetBC: Rows(BndU)ptr.pp_double[i][j], _state)||ae_isneginf(bndl->ptr.pp_double[i][j], _state), "MCPDSetBC: BndL containts NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.pp_double[i][j], _state)||ae_isposinf(bndu->ptr.pp_double[i][j], _state), "MCPDSetBC: BndU containts NAN or -INF", _state); - s->bndl.ptr.pp_double[i][j] = bndl->ptr.pp_double[i][j]; - s->bndu.ptr.pp_double[i][j] = bndu->ptr.pp_double[i][j]; - } - } -} - - -/************************************************************************* -This function is used to add bound constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD bound constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetBC() function which allows to place bound -constraints on arbitrary subset of elements of P. Set of constraints is -specified by BndL/BndU matrices, which may contain arbitrary combination -of finite numbers or infinities (like -INF=0, "MCPDAddBC: I<0", _state); - ae_assert(in, "MCPDAddBC: I>=N", _state); - ae_assert(j>=0, "MCPDAddBC: J<0", _state); - ae_assert(jn, "MCPDAddBC: J>=N", _state); - ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MCPDAddBC: BndL is NAN or +INF", _state); - ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MCPDAddBC: BndU is NAN or -INF", _state); - s->bndl.ptr.pp_double[i][j] = bndl; - s->bndu.ptr.pp_double[i][j] = bndu; -} - - -/************************************************************************* -This function is used to set linear equality/inequality constraints on the -elements of the transition matrix P. - -This function can be used to set one or several general linear constraints -on the elements of P. Two types of constraints are supported: -* equality constraints -* inequality constraints (both less-or-equal and greater-or-equal) - -Coefficients of constraints are specified by matrix C (one of the -parameters). One row of C corresponds to one constraint. Because -transition matrix P has N*N elements, we need N*N columns to store all -coefficients (they are stored row by row), and one more column to store -right part - hence C has N*N+1 columns. Constraint kind is stored in the -CT array. - -Thus, I-th linear constraint is - P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + - + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + - + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] -where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). - -Your constraint may involve only some subset of P (less than N*N elements). -For example it can be something like - P[0,0] + P[0,1] = 0.5 -In this case you still should pass matrix with N*N+1 columns, but all its -elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. - -INPUT PARAMETERS: - S - solver - C - array[K,N*N+1] - coefficients of constraints - (see above for complete description) - CT - array[K] - constraint types - (see above for complete description) - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetlc(mcpdstate* s, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - - - n = s->n; - ae_assert(c->cols>=n*n+1, "MCPDSetLC: Cols(C)rows>=k, "MCPDSetLC: Rows(C)cnt>=k, "MCPDSetLC: Len(CT)c, k, n*n+1, _state); - ivectorsetlengthatleast(&s->ct, k, _state); - for(i=0; i<=k-1; i++) - { - for(j=0; j<=n*n; j++) - { - s->c.ptr.pp_double[i][j] = c->ptr.pp_double[i][j]; - } - s->ct.ptr.p_int[i] = ct->ptr.p_int[i]; - } - s->ccnt = k; -} - - -/************************************************************************* -This function allows to tune amount of Tikhonov regularization being -applied to your problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change coefficient r. You can also change -prior values with MCPDSetPrior() function. - -INPUT PARAMETERS: - S - solver - V - regularization coefficient, finite non-negative value. It - is not recommended to specify zero value unless you are - pretty sure that you want it. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state) -{ - - - ae_assert(ae_isfinite(v, _state), "MCPDSetTikhonovRegularizer: V is infinite or NAN", _state); - ae_assert(ae_fp_greater_eq(v,0.0), "MCPDSetTikhonovRegularizer: V is less than zero", _state); - s->regterm = v; -} - - -/************************************************************************* -This function allows to set prior values used for regularization of your -problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change prior values prior_P. You can also -change r with MCPDSetTikhonovRegularizer() function. - -INPUT PARAMETERS: - S - solver - PP - array[N,N], matrix of prior values: - 1. elements must be real numbers from [0,1] - 2. columns must sum to 1.0. - First property is checked (exception is thrown otherwise), - while second one is not checked/enforced. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetprior(mcpdstate* s, - /* Real */ ae_matrix* pp, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _pp; - ae_int_t i; - ae_int_t j; - ae_int_t n; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_pp, pp, _state, ae_true); - pp = &_pp; - - n = s->n; - ae_assert(pp->cols>=n, "MCPDSetPrior: Cols(PP)rows>=n, "MCPDSetPrior: Rows(PP)ptr.pp_double[i][j], _state), "MCPDSetPrior: PP containts infinite elements", _state); - ae_assert(ae_fp_greater_eq(pp->ptr.pp_double[i][j],0.0)&&ae_fp_less_eq(pp->ptr.pp_double[i][j],1.0), "MCPDSetPrior: PP[i,j] is less than 0.0 or greater than 1.0", _state); - s->priorp.ptr.pp_double[i][j] = pp->ptr.pp_double[i][j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function is used to change prediction weights - -MCPD solver scales prediction errors as follows - Error(P) = ||W*(y-P*x)||^2 -where - x is a system state at time t - y is a system state at time t+1 - P is a transition matrix - W is a diagonal scaling matrix - -By default, weights are chosen in order to minimize relative prediction -error instead of absolute one. For example, if one component of state is -about 0.5 in magnitude and another one is about 0.05, then algorithm will -make corresponding weights equal to 2.0 and 20.0. - -INPUT PARAMETERS: - S - solver - PW - array[N], weights: - * must be non-negative values (exception will be thrown otherwise) - * zero values will be replaced by automatically chosen values - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetpredictionweights(mcpdstate* s, - /* Real */ ae_vector* pw, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - - - n = s->n; - ae_assert(pw->cnt>=n, "MCPDSetPredictionWeights: Length(PW)ptr.p_double[i], _state), "MCPDSetPredictionWeights: PW containts infinite or NAN elements", _state); - ae_assert(ae_fp_greater_eq(pw->ptr.p_double[i],0), "MCPDSetPredictionWeights: PW containts negative elements", _state); - s->pw.ptr.p_double[i] = pw->ptr.p_double[i]; - } -} - - -/************************************************************************* -This function is used to start solution of the MCPD problem. - -After return from this function, you can use MCPDResults() to get solution -and completion code. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsolve(mcpdstate* s, ae_state *_state) -{ - ae_int_t n; - ae_int_t npairs; - ae_int_t ccnt; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t k2; - double v; - double vv; - - - n = s->n; - npairs = s->npairs; - - /* - * init fields of S - */ - s->repterminationtype = 0; - s->repinneriterationscount = 0; - s->repouteriterationscount = 0; - s->repnfev = 0; - for(k=0; k<=n-1; k++) - { - for(k2=0; k2<=n-1; k2++) - { - s->p.ptr.pp_double[k][k2] = _state->v_nan; - } - } - - /* - * Generate "effective" weights for prediction and calculate preconditioner - */ - for(i=0; i<=n-1; i++) - { - if( ae_fp_eq(s->pw.ptr.p_double[i],0) ) - { - v = 0; - k = 0; - for(j=0; j<=npairs-1; j++) - { - if( ae_fp_neq(s->data.ptr.pp_double[j][n+i],0) ) - { - v = v+s->data.ptr.pp_double[j][n+i]; - k = k+1; - } - } - if( k!=0 ) - { - s->effectivew.ptr.p_double[i] = k/v; - } - else - { - s->effectivew.ptr.p_double[i] = 1.0; - } - } - else - { - s->effectivew.ptr.p_double[i] = s->pw.ptr.p_double[i]; - } - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->h.ptr.p_double[i*n+j] = 2*s->regterm; - } - } - for(k=0; k<=npairs-1; k++) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->h.ptr.p_double[i*n+j] = s->h.ptr.p_double[i*n+j]+2*ae_sqr(s->effectivew.ptr.p_double[i], _state)*ae_sqr(s->data.ptr.pp_double[k][j], _state); - } - } - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( ae_fp_eq(s->h.ptr.p_double[i*n+j],0) ) - { - s->h.ptr.p_double[i*n+j] = 1; - } - } - } - - /* - * Generate "effective" BndL/BndU - */ - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - - /* - * Set default boundary constraints. - * Lower bound is always zero, upper bound is calculated - * with respect to entry/exit states. - */ - s->effectivebndl.ptr.p_double[i*n+j] = 0.0; - if( s->states.ptr.p_int[i]>0||s->states.ptr.p_int[j]<0 ) - { - s->effectivebndu.ptr.p_double[i*n+j] = 0.0; - } - else - { - s->effectivebndu.ptr.p_double[i*n+j] = 1.0; - } - - /* - * Calculate intersection of the default and user-specified bound constraints. - * This code checks consistency of such combination. - */ - if( ae_isfinite(s->bndl.ptr.pp_double[i][j], _state)&&ae_fp_greater(s->bndl.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j]) ) - { - s->effectivebndl.ptr.p_double[i*n+j] = s->bndl.ptr.pp_double[i][j]; - } - if( ae_isfinite(s->bndu.ptr.pp_double[i][j], _state)&&ae_fp_less(s->bndu.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) - { - s->effectivebndu.ptr.p_double[i*n+j] = s->bndu.ptr.pp_double[i][j]; - } - if( ae_fp_greater(s->effectivebndl.ptr.p_double[i*n+j],s->effectivebndu.ptr.p_double[i*n+j]) ) - { - s->repterminationtype = -3; - return; - } - - /* - * Calculate intersection of the effective bound constraints - * and user-specified equality constraints. - * This code checks consistency of such combination. - */ - if( ae_isfinite(s->ec.ptr.pp_double[i][j], _state) ) - { - if( ae_fp_less(s->ec.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j])||ae_fp_greater(s->ec.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) - { - s->repterminationtype = -3; - return; - } - s->effectivebndl.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; - s->effectivebndu.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; - } - } - } - - /* - * Generate linear constraints: - * * "default" sums-to-one constraints (not generated for "exit" states) - */ - rmatrixsetlengthatleast(&s->effectivec, s->ccnt+n, n*n+1, _state); - ivectorsetlengthatleast(&s->effectivect, s->ccnt+n, _state); - ccnt = s->ccnt; - for(i=0; i<=s->ccnt-1; i++) - { - for(j=0; j<=n*n; j++) - { - s->effectivec.ptr.pp_double[i][j] = s->c.ptr.pp_double[i][j]; - } - s->effectivect.ptr.p_int[i] = s->ct.ptr.p_int[i]; - } - for(i=0; i<=n-1; i++) - { - if( s->states.ptr.p_int[i]>=0 ) - { - for(k=0; k<=n*n-1; k++) - { - s->effectivec.ptr.pp_double[ccnt][k] = 0; - } - for(k=0; k<=n-1; k++) - { - s->effectivec.ptr.pp_double[ccnt][k*n+i] = 1; - } - s->effectivec.ptr.pp_double[ccnt][n*n] = 1.0; - s->effectivect.ptr.p_int[ccnt] = 0; - ccnt = ccnt+1; - } - } - - /* - * create optimizer - */ - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->tmpp.ptr.p_double[i*n+j] = (double)1/(double)n; - } - } - minbleicrestartfrom(&s->bs, &s->tmpp, _state); - minbleicsetbc(&s->bs, &s->effectivebndl, &s->effectivebndu, _state); - minbleicsetlc(&s->bs, &s->effectivec, &s->effectivect, ccnt, _state); - minbleicsetcond(&s->bs, 0.0, 0.0, mcpd_xtol, 0, _state); - minbleicsetprecdiag(&s->bs, &s->h, _state); - - /* - * solve problem - */ - while(minbleiciteration(&s->bs, _state)) - { - ae_assert(s->bs.needfg, "MCPDSolve: internal error", _state); - if( s->bs.needfg ) - { - - /* - * Calculate regularization term - */ - s->bs.f = 0.0; - vv = s->regterm; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->bs.f = s->bs.f+vv*ae_sqr(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j], _state); - s->bs.g.ptr.p_double[i*n+j] = 2*vv*(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j]); - } - } - - /* - * calculate prediction error/gradient for K-th pair - */ - for(k=0; k<=npairs-1; k++) - { - for(i=0; i<=n-1; i++) - { - v = ae_v_dotproduct(&s->bs.x.ptr.p_double[i*n], 1, &s->data.ptr.pp_double[k][0], 1, ae_v_len(i*n,i*n+n-1)); - vv = s->effectivew.ptr.p_double[i]; - s->bs.f = s->bs.f+ae_sqr(vv*(v-s->data.ptr.pp_double[k][n+i]), _state); - for(j=0; j<=n-1; j++) - { - s->bs.g.ptr.p_double[i*n+j] = s->bs.g.ptr.p_double[i*n+j]+2*vv*vv*(v-s->data.ptr.pp_double[k][n+i])*s->data.ptr.pp_double[k][j]; - } - } - } - - /* - * continue - */ - continue; - } - } - minbleicresultsbuf(&s->bs, &s->tmpp, &s->br, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->p.ptr.pp_double[i][j] = s->tmpp.ptr.p_double[i*n+j]; - } - } - s->repterminationtype = s->br.terminationtype; - s->repinneriterationscount = s->br.inneriterationscount; - s->repouteriterationscount = s->br.outeriterationscount; - s->repnfev = s->br.nfev; -} - - -/************************************************************************* -MCPD results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - P - array[N,N], transition matrix - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one. Speaking short, positive values denote - success, negative ones are failures. - More information about fields of this structure can be - found in the comments on MCPDReport datatype. - - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdresults(mcpdstate* s, - /* Real */ ae_matrix* p, - mcpdreport* rep, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(p); - _mcpdreport_clear(rep); - - ae_matrix_set_length(p, s->n, s->n, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=s->n-1; j++) - { - p->ptr.pp_double[i][j] = s->p.ptr.pp_double[i][j]; - } - } - rep->terminationtype = s->repterminationtype; - rep->inneriterationscount = s->repinneriterationscount; - rep->outeriterationscount = s->repouteriterationscount; - rep->nfev = s->repnfev; -} - - -/************************************************************************* -Internal initialization function - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -static void mcpd_mcpdinit(ae_int_t n, - ae_int_t entrystate, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - ae_assert(n>=1, "MCPDCreate: N<1", _state); - s->n = n; - ae_vector_set_length(&s->states, n, _state); - for(i=0; i<=n-1; i++) - { - s->states.ptr.p_int[i] = 0; - } - if( entrystate>=0 ) - { - s->states.ptr.p_int[entrystate] = 1; - } - if( exitstate>=0 ) - { - s->states.ptr.p_int[exitstate] = -1; - } - s->npairs = 0; - s->regterm = 1.0E-8; - s->ccnt = 0; - ae_matrix_set_length(&s->p, n, n, _state); - ae_matrix_set_length(&s->ec, n, n, _state); - ae_matrix_set_length(&s->bndl, n, n, _state); - ae_matrix_set_length(&s->bndu, n, n, _state); - ae_vector_set_length(&s->pw, n, _state); - ae_matrix_set_length(&s->priorp, n, n, _state); - ae_vector_set_length(&s->tmpp, n*n, _state); - ae_vector_set_length(&s->effectivew, n, _state); - ae_vector_set_length(&s->effectivebndl, n*n, _state); - ae_vector_set_length(&s->effectivebndu, n*n, _state); - ae_vector_set_length(&s->h, n*n, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->p.ptr.pp_double[i][j] = 0.0; - s->priorp.ptr.pp_double[i][j] = 0.0; - s->bndl.ptr.pp_double[i][j] = _state->v_neginf; - s->bndu.ptr.pp_double[i][j] = _state->v_posinf; - s->ec.ptr.pp_double[i][j] = _state->v_nan; - } - s->pw.ptr.p_double[i] = 0.0; - s->priorp.ptr.pp_double[i][i] = 1.0; - } - ae_matrix_set_length(&s->data, 1, 2*n, _state); - for(i=0; i<=2*n-1; i++) - { - s->data.ptr.pp_double[0][i] = 0.0; - } - for(i=0; i<=n*n-1; i++) - { - s->tmpp.ptr.p_double[i] = 0.0; - } - minbleiccreate(n*n, &s->tmpp, &s->bs, _state); -} - - -ae_bool _mcpdstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mcpdstate *p = (mcpdstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->states, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->data, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->ec, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->bndl, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->bndu, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ct, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->pw, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->priorp, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_minbleicstate_init(&p->bs, _state, make_automatic) ) - return ae_false; - if( !_minbleicreport_init(&p->br, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->effectivew, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->effectivebndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->effectivebndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->effectivec, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->effectivect, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->h, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->p, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mcpdstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mcpdstate *dst = (mcpdstate*)_dst; - mcpdstate *src = (mcpdstate*)_src; - dst->n = src->n; - if( !ae_vector_init_copy(&dst->states, &src->states, _state, make_automatic) ) - return ae_false; - dst->npairs = src->npairs; - if( !ae_matrix_init_copy(&dst->data, &src->data, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->ec, &src->ec, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ct, &src->ct, _state, make_automatic) ) - return ae_false; - dst->ccnt = src->ccnt; - if( !ae_vector_init_copy(&dst->pw, &src->pw, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->priorp, &src->priorp, _state, make_automatic) ) - return ae_false; - dst->regterm = src->regterm; - if( !_minbleicstate_init_copy(&dst->bs, &src->bs, _state, make_automatic) ) - return ae_false; - dst->repinneriterationscount = src->repinneriterationscount; - dst->repouteriterationscount = src->repouteriterationscount; - dst->repnfev = src->repnfev; - dst->repterminationtype = src->repterminationtype; - if( !_minbleicreport_init_copy(&dst->br, &src->br, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpp, &src->tmpp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->effectivew, &src->effectivew, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->effectivebndl, &src->effectivebndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->effectivebndu, &src->effectivebndu, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->effectivec, &src->effectivec, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->effectivect, &src->effectivect, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->h, &src->h, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->p, &src->p, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mcpdstate_clear(void* _p) -{ - mcpdstate *p = (mcpdstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->states); - ae_matrix_clear(&p->data); - ae_matrix_clear(&p->ec); - ae_matrix_clear(&p->bndl); - ae_matrix_clear(&p->bndu); - ae_matrix_clear(&p->c); - ae_vector_clear(&p->ct); - ae_vector_clear(&p->pw); - ae_matrix_clear(&p->priorp); - _minbleicstate_clear(&p->bs); - _minbleicreport_clear(&p->br); - ae_vector_clear(&p->tmpp); - ae_vector_clear(&p->effectivew); - ae_vector_clear(&p->effectivebndl); - ae_vector_clear(&p->effectivebndu); - ae_matrix_clear(&p->effectivec); - ae_vector_clear(&p->effectivect); - ae_vector_clear(&p->h); - ae_matrix_clear(&p->p); -} - - -void _mcpdstate_destroy(void* _p) -{ - mcpdstate *p = (mcpdstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->states); - ae_matrix_destroy(&p->data); - ae_matrix_destroy(&p->ec); - ae_matrix_destroy(&p->bndl); - ae_matrix_destroy(&p->bndu); - ae_matrix_destroy(&p->c); - ae_vector_destroy(&p->ct); - ae_vector_destroy(&p->pw); - ae_matrix_destroy(&p->priorp); - _minbleicstate_destroy(&p->bs); - _minbleicreport_destroy(&p->br); - ae_vector_destroy(&p->tmpp); - ae_vector_destroy(&p->effectivew); - ae_vector_destroy(&p->effectivebndl); - ae_vector_destroy(&p->effectivebndu); - ae_matrix_destroy(&p->effectivec); - ae_vector_destroy(&p->effectivect); - ae_vector_destroy(&p->h); - ae_matrix_destroy(&p->p); -} - - -ae_bool _mcpdreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mcpdreport *p = (mcpdreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _mcpdreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mcpdreport *dst = (mcpdreport*)_dst; - mcpdreport *src = (mcpdreport*)_src; - dst->inneriterationscount = src->inneriterationscount; - dst->outeriterationscount = src->outeriterationscount; - dst->nfev = src->nfev; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _mcpdreport_clear(void* _p) -{ - mcpdreport *p = (mcpdreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _mcpdreport_destroy(void* _p) -{ - mcpdreport *p = (mcpdreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -Like MLPCreate0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate0(ae_int_t nin, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreate0(nin, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreate1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreate1(nin, nhid, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreate2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreate2(nin, nhid1, nhid2, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateB0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb0(ae_int_t nin, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreateb0(nin, nout, b, d, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateB1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreateb1(nin, nhid, nout, b, d, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateB2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreateb2(nin, nhid1, nhid2, nout, b, d, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateR0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater0(ae_int_t nin, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreater0(nin, nout, a, b, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateR1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreater1(nin, nhid, nout, a, b, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateR2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreater2(nin, nhid1, nhid2, nout, a, b, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateC0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec0(ae_int_t nin, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreatec0(nin, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateC1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreatec1(nin, nhid, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Like MLPCreateC2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_frame _frame_block; - multilayerperceptron net; - - ae_frame_make(_state, &_frame_block); - _mlpensemble_clear(ensemble); - _multilayerperceptron_init(&net, _state, ae_true); - - mlpcreatec2(nin, nhid1, nhid2, nout, &net, _state); - mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Creates ensemble from network. Only network geometry is copied. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatefromnetwork(multilayerperceptron* network, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_int_t i; - ae_int_t ccount; - ae_int_t wcount; - - _mlpensemble_clear(ensemble); - - ae_assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!", _state); - - /* - * Copy network - */ - mlpcopy(network, &ensemble->network, _state); - - /* - * network properties - */ - if( mlpissoftmax(network, _state) ) - { - ccount = mlpgetinputscount(&ensemble->network, _state); - } - else - { - ccount = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); - } - wcount = mlpgetweightscount(&ensemble->network, _state); - ensemble->ensemblesize = ensemblesize; - - /* - * weights, means, sigmas - */ - ae_vector_set_length(&ensemble->weights, ensemblesize*wcount, _state); - ae_vector_set_length(&ensemble->columnmeans, ensemblesize*ccount, _state); - ae_vector_set_length(&ensemble->columnsigmas, ensemblesize*ccount, _state); - for(i=0; i<=ensemblesize*wcount-1; i++) - { - ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; - } - for(i=0; i<=ensemblesize-1; i++) - { - ae_v_move(&ensemble->columnmeans.ptr.p_double[i*ccount], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); - ae_v_move(&ensemble->columnsigmas.ptr.p_double[i*ccount], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); - } - - /* - * temporaries, internal buffers - */ - ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); -} - - -/************************************************************************* -Copying of MLPEnsemble strucure - -INPUT PARAMETERS: - Ensemble1 - original - -OUTPUT PARAMETERS: - Ensemble2 - copy - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecopy(mlpensemble* ensemble1, - mlpensemble* ensemble2, - ae_state *_state) -{ - ae_int_t ccount; - ae_int_t wcount; - - _mlpensemble_clear(ensemble2); - - - /* - * Unload info - */ - if( mlpissoftmax(&ensemble1->network, _state) ) - { - ccount = mlpgetinputscount(&ensemble1->network, _state); - } - else - { - ccount = mlpgetinputscount(&ensemble1->network, _state)+mlpgetoutputscount(&ensemble1->network, _state); - } - wcount = mlpgetweightscount(&ensemble1->network, _state); - - /* - * Allocate space - */ - ae_vector_set_length(&ensemble2->weights, ensemble1->ensemblesize*wcount, _state); - ae_vector_set_length(&ensemble2->columnmeans, ensemble1->ensemblesize*ccount, _state); - ae_vector_set_length(&ensemble2->columnsigmas, ensemble1->ensemblesize*ccount, _state); - ae_vector_set_length(&ensemble2->y, mlpgetoutputscount(&ensemble1->network, _state), _state); - - /* - * Copy - */ - ensemble2->ensemblesize = ensemble1->ensemblesize; - ae_v_move(&ensemble2->weights.ptr.p_double[0], 1, &ensemble1->weights.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*wcount-1)); - ae_v_move(&ensemble2->columnmeans.ptr.p_double[0], 1, &ensemble1->columnmeans.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); - ae_v_move(&ensemble2->columnsigmas.ptr.p_double[0], 1, &ensemble1->columnsigmas.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); - mlpcopy(&ensemble1->network, &ensemble2->network, _state); -} - - -/************************************************************************* -Randomization of MLP ensemble - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlperandomize(mlpensemble* ensemble, ae_state *_state) -{ - ae_int_t i; - ae_int_t wcount; - - - wcount = mlpgetweightscount(&ensemble->network, _state); - for(i=0; i<=ensemble->ensemblesize*wcount-1; i++) - { - ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; - } -} - - -/************************************************************************* -Return ensemble properties (number of inputs and outputs). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeproperties(mlpensemble* ensemble, - ae_int_t* nin, - ae_int_t* nout, - ae_state *_state) -{ - - *nin = 0; - *nout = 0; - - *nin = mlpgetinputscount(&ensemble->network, _state); - *nout = mlpgetoutputscount(&ensemble->network, _state); -} - - -/************************************************************************* -Return normalization type (whether ensemble is SOFTMAX-normalized or not). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool mlpeissoftmax(mlpensemble* ensemble, ae_state *_state) -{ - ae_bool result; - - - result = mlpissoftmax(&ensemble->network, _state); - return result; -} - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Ensemble- neural networks ensemble - X - input vector, array[0..NIn-1]. - Y - (possibly) preallocated buffer; if size of Y is less than - NOut, it will be reallocated. If it is large enough, it - is NOT reallocated, so we can save some time on reallocation. - - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocess(mlpensemble* ensemble, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t es; - ae_int_t wc; - ae_int_t cc; - double v; - ae_int_t nout; - - - if( y->cntnetwork, _state) ) - { - ae_vector_set_length(y, mlpgetoutputscount(&ensemble->network, _state), _state); - } - es = ensemble->ensemblesize; - wc = mlpgetweightscount(&ensemble->network, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - cc = mlpgetinputscount(&ensemble->network, _state); - } - else - { - cc = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); - } - v = (double)1/(double)es; - nout = mlpgetoutputscount(&ensemble->network, _state); - for(i=0; i<=nout-1; i++) - { - y->ptr.p_double[i] = 0; - } - for(i=0; i<=es-1; i++) - { - ae_v_move(&ensemble->network.weights.ptr.p_double[0], 1, &ensemble->weights.ptr.p_double[i*wc], 1, ae_v_len(0,wc-1)); - ae_v_move(&ensemble->network.columnmeans.ptr.p_double[0], 1, &ensemble->columnmeans.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); - ae_v_move(&ensemble->network.columnsigmas.ptr.p_double[0], 1, &ensemble->columnsigmas.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); - mlpprocess(&ensemble->network, x, &ensemble->y, _state); - ae_v_addd(&y->ptr.p_double[0], 1, &ensemble->y.ptr.p_double[0], 1, ae_v_len(0,nout-1), v); - } -} - - -/************************************************************************* -'interactive' variant of MLPEProcess for languages like Python which -support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocessi(mlpensemble* ensemble, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - ae_vector_clear(y); - - mlpeprocess(ensemble, x, y, _state); -} - - -/************************************************************************* -Calculation of all types of errors - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeallerrorsx(mlpensemble* ensemble, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - modelerrors* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t nin; - ae_int_t nout; - ae_bool iscls; - ae_int_t srcidx; - mlpbuffers *pbuf; - ae_smart_ptr _pbuf; - modelerrors rep0; - modelerrors rep1; - - ae_frame_make(_state, &_frame_block); - ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true); - _modelerrors_init(&rep0, _state, ae_true); - _modelerrors_init(&rep1, _state, ae_true); - - - /* - * Get network information - */ - nin = mlpgetinputscount(&ensemble->network, _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - iscls = mlpissoftmax(&ensemble->network, _state); - - /* - * Retrieve buffer, prepare, process data, recycle buffer - */ - ae_shared_pool_retrieve(buf, &_pbuf, _state); - if( iscls ) - { - dserrallocate(nout, &pbuf->tmp0, _state); - } - else - { - dserrallocate(-nout, &pbuf->tmp0, _state); - } - rvectorsetlengthatleast(&pbuf->x, nin, _state); - rvectorsetlengthatleast(&pbuf->y, nout, _state); - rvectorsetlengthatleast(&pbuf->desiredy, nout, _state); - for(i=subset0; i<=subset1-1; i++) - { - srcidx = -1; - if( subsettype==0 ) - { - srcidx = i; - } - if( subsettype==1 ) - { - srcidx = idx->ptr.p_int[i]; - } - ae_assert(srcidx>=0, "MLPEAllErrorsX: internal error", _state); - if( datasettype==0 ) - { - ae_v_move(&pbuf->x.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,nin-1)); - } - if( datasettype==1 ) - { - sparsegetrow(sparsexy, srcidx, &pbuf->x, _state); - } - mlpeprocess(ensemble, &pbuf->x, &pbuf->y, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - if( datasettype==0 ) - { - pbuf->desiredy.ptr.p_double[0] = densexy->ptr.pp_double[srcidx][nin]; - } - if( datasettype==1 ) - { - pbuf->desiredy.ptr.p_double[0] = sparseget(sparsexy, srcidx, nin, _state); - } - } - else - { - if( datasettype==0 ) - { - ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][nin], 1, ae_v_len(0,nout-1)); - } - if( datasettype==1 ) - { - for(j=0; j<=nout-1; j++) - { - pbuf->desiredy.ptr.p_double[j] = sparseget(sparsexy, srcidx, nin+j, _state); - } - } - } - dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); - } - dserrfinish(&pbuf->tmp0, _state); - rep->relclserror = pbuf->tmp0.ptr.p_double[0]; - rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log(2, _state); - rep->rmserror = pbuf->tmp0.ptr.p_double[2]; - rep->avgerror = pbuf->tmp0.ptr.p_double[3]; - rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; - ae_shared_pool_recycle(buf, &_pbuf, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Calculation of all types of errors on dataset given by sparse matrix - - -- ALGLIB -- - Copyright 10.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpeallerrorssparse(mlpensemble* ensemble, - sparsematrix* xy, - ae_int_t npoints, - double* relcls, - double* avgce, - double* rms, - double* avg, - double* avgrel, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector buf; - ae_vector workx; - ae_vector y; - ae_vector dy; - ae_int_t nin; - ae_int_t nout; - - ae_frame_make(_state, &_frame_block); - *relcls = 0; - *avgce = 0; - *rms = 0; - *avg = 0; - *avgrel = 0; - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); - - nin = mlpgetinputscount(&ensemble->network, _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - ae_vector_set_length(&dy, 1, _state); - dserrallocate(nout, &buf, _state); - } - else - { - ae_vector_set_length(&dy, nout, _state); - dserrallocate(-nout, &buf, _state); - } - for(i=0; i<=npoints-1; i++) - { - sparsegetrow(xy, i, &workx, _state); - mlpeprocess(ensemble, &workx, &y, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - dy.ptr.p_double[0] = workx.ptr.p_double[nin]; - } - else - { - ae_v_move(&dy.ptr.p_double[0], 1, &workx.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); - } - dserraccumulate(&buf, &y, &dy, _state); - } - dserrfinish(&buf, _state); - *relcls = buf.ptr.p_double[0]; - *avgce = buf.ptr.p_double[1]; - *rms = buf.ptr.p_double[2]; - *avg = buf.ptr.p_double[3]; - *avgrel = buf.ptr.p_double[4]; - ae_frame_leave(_state); -} - - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Works both for classifier betwork and for regression networks which -are used as classifiers. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlperelclserror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors rep; - double result; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&rep, _state, ae_true); - - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); - result = rep.relclserror; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if ensemble solves regression task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgce(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors rep; - double result; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&rep, _state, ae_true); - - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); - result = rep.avgce; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for classification task -RMS error means error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpermserror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors rep; - double result; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&rep, _state, ae_true); - - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); - result = rep.rmserror; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgerror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors rep; - double result; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&rep, _state, ae_true); - - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); - result = rep.avgerror; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average relative error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgrelerror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors rep; - double result; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&rep, _state, ae_true); - - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); - result = rep.avgrelerror; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Serializer: allocation - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpealloc(ae_serializer* s, mlpensemble* ensemble, ae_state *_state) -{ - - - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - allocrealarray(s, &ensemble->weights, -1, _state); - allocrealarray(s, &ensemble->columnmeans, -1, _state); - allocrealarray(s, &ensemble->columnsigmas, -1, _state); - mlpalloc(s, &ensemble->network, _state); -} - - -/************************************************************************* -Serializer: serialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpeserialize(ae_serializer* s, - mlpensemble* ensemble, - ae_state *_state) -{ - - - ae_serializer_serialize_int(s, getmlpeserializationcode(_state), _state); - ae_serializer_serialize_int(s, mlpe_mlpefirstversion, _state); - ae_serializer_serialize_int(s, ensemble->ensemblesize, _state); - serializerealarray(s, &ensemble->weights, -1, _state); - serializerealarray(s, &ensemble->columnmeans, -1, _state); - serializerealarray(s, &ensemble->columnsigmas, -1, _state); - mlpserialize(s, &ensemble->network, _state); -} - - -/************************************************************************* -Serializer: unserialization - - -- ALGLIB -- - Copyright 14.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpeunserialize(ae_serializer* s, - mlpensemble* ensemble, - ae_state *_state) -{ - ae_int_t i0; - ae_int_t i1; - - _mlpensemble_clear(ensemble); - - - /* - * check correctness of header - */ - ae_serializer_unserialize_int(s, &i0, _state); - ae_assert(i0==getmlpeserializationcode(_state), "MLPEUnserialize: stream header corrupted", _state); - ae_serializer_unserialize_int(s, &i1, _state); - ae_assert(i1==mlpe_mlpefirstversion, "MLPEUnserialize: stream header corrupted", _state); - - /* - * Create network - */ - ae_serializer_unserialize_int(s, &ensemble->ensemblesize, _state); - unserializerealarray(s, &ensemble->weights, _state); - unserializerealarray(s, &ensemble->columnmeans, _state); - unserializerealarray(s, &ensemble->columnsigmas, _state); - mlpunserialize(s, &ensemble->network, _state); - - /* - * Allocate termoraries - */ - ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); -} - - -ae_bool _mlpensemble_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpensemble *p = (mlpensemble*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->weights, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->columnmeans, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_multilayerperceptron_init(&p->network, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mlpensemble_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpensemble *dst = (mlpensemble*)_dst; - mlpensemble *src = (mlpensemble*)_src; - dst->ensemblesize = src->ensemblesize; - if( !ae_vector_init_copy(&dst->weights, &src->weights, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state, make_automatic) ) - return ae_false; - if( !_multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mlpensemble_clear(void* _p) -{ - mlpensemble *p = (mlpensemble*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->weights); - ae_vector_clear(&p->columnmeans); - ae_vector_clear(&p->columnsigmas); - _multilayerperceptron_clear(&p->network); - ae_vector_clear(&p->y); -} - - -void _mlpensemble_destroy(void* _p) -{ - mlpensemble *p = (mlpensemble*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->weights); - ae_vector_destroy(&p->columnmeans); - ae_vector_destroy(&p->columnsigmas); - _multilayerperceptron_destroy(&p->network); - ae_vector_destroy(&p->y); -} - - - - -/************************************************************************* -Neural network training using modified Levenberg-Marquardt with exact -Hessian calculation and regularization. Subroutine trains neural network -with restarts from random positions. Algorithm is well suited for small -and medium scale problems (hundreds of weights). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -9, if internal matrix inverse subroutine failed - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlm(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - double lmsteptol; - ae_int_t i; - ae_int_t k; - double v; - double e; - double enew; - double xnorm2; - double stepnorm; - ae_vector g; - ae_vector d; - ae_matrix h; - ae_matrix hmod; - ae_matrix z; - ae_bool spd; - double nu; - double lambdav; - double lambdaup; - double lambdadown; - minlbfgsreport internalrep; - minlbfgsstate state; - ae_vector x; - ae_vector y; - ae_vector wbase; - ae_vector wdir; - ae_vector wt; - ae_vector wx; - ae_int_t pass; - ae_vector wbest; - double ebest; - ae_int_t invinfo; - matinvreport invrep; - ae_int_t solverinfo; - densesolverreport solverrep; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - ae_vector_init(&g, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&h, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&hmod, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); - _minlbfgsreport_init(&internalrep, _state, ae_true); - _minlbfgsstate_init(&state, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wbase, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wdir, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); - _matinvreport_init(&invrep, _state, ae_true); - _densesolverreport_init(&solverrep, _state, ae_true); - - mlpproperties(network, &nin, &nout, &wcount, _state); - lambdaup = 10; - lambdadown = 0.3; - lmsteptol = 0.001; - - /* - * Test for inputs - */ - if( npoints<=0||restarts<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( mlpissoftmax(network, _state) ) - { - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - decay = ae_maxreal(decay, mlptrain_mindecay, _state); - *info = 2; - - /* - * Initialize data - */ - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - - /* - * General case. - * Prepare task and network. Allocate space. - */ - mlpinitpreprocessor(network, xy, npoints, _state); - ae_vector_set_length(&g, wcount-1+1, _state); - ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); - ae_matrix_set_length(&hmod, wcount-1+1, wcount-1+1, _state); - ae_vector_set_length(&wbase, wcount-1+1, _state); - ae_vector_set_length(&wdir, wcount-1+1, _state); - ae_vector_set_length(&wbest, wcount-1+1, _state); - ae_vector_set_length(&wt, wcount-1+1, _state); - ae_vector_set_length(&wx, wcount-1+1, _state); - ebest = ae_maxrealnumber; - - /* - * Multiple passes - */ - for(pass=1; pass<=restarts; pass++) - { - - /* - * Initialize weights - */ - mlprandomize(network, _state); - - /* - * First stage of the hybrid algorithm: LBFGS - */ - ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - minlbfgscreate(wcount, ae_minint(wcount, 5, _state), &wbase, &state, _state); - minlbfgssetcond(&state, 0, 0, 0, ae_maxint(25, wcount, _state), _state); - while(minlbfgsiteration(&state, _state)) - { - - /* - * gradient - */ - ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - mlpgradbatch(network, xy, npoints, &state.f, &state.g, _state); - - /* - * weight decay - */ - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - state.f = state.f+0.5*decay*v; - ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - - /* - * next iteration - */ - rep->ngrad = rep->ngrad+1; - } - minlbfgsresults(&state, &wbase, &internalrep, _state); - ae_v_move(&network->weights.ptr.p_double[0], 1, &wbase.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - - /* - * Second stage of the hybrid algorithm: LM - * - * Initialize H with identity matrix, - * G with gradient, - * E with regularized error. - */ - mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - for(k=0; k<=wcount-1; k++) - { - h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; - } - rep->nhess = rep->nhess+1; - lambdav = 0.001; - nu = 2; - for(;;) - { - - /* - * 1. HMod = H+lambda*I - * 2. Try to solve (H+Lambda*I)*dx = -g. - * Increase lambda if left part is not positive definite. - */ - for(i=0; i<=wcount-1; i++) - { - ae_v_move(&hmod.ptr.pp_double[i][0], 1, &h.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); - hmod.ptr.pp_double[i][i] = hmod.ptr.pp_double[i][i]+lambdav; - } - spd = spdmatrixcholesky(&hmod, wcount, ae_true, _state); - rep->ncholesky = rep->ncholesky+1; - if( !spd ) - { - lambdav = lambdav*lambdaup*nu; - nu = nu*2; - continue; - } - spdmatrixcholeskysolve(&hmod, wcount, ae_true, &g, &solverinfo, &solverrep, &wdir, _state); - if( solverinfo<0 ) - { - lambdav = lambdav*lambdaup*nu; - nu = nu*2; - continue; - } - ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1); - - /* - * Lambda found. - * 1. Save old w in WBase - * 1. Test some stopping criterions - * 2. If error(w+wdir)>error(w), increase lambda - */ - ae_v_add(&network->weights.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - xnorm2 = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - stepnorm = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - stepnorm = ae_sqrt(stepnorm, _state); - enew = mlperror(network, xy, npoints, _state)+0.5*decay*xnorm2; - if( ae_fp_less(stepnorm,lmsteptol*(1+ae_sqrt(xnorm2, _state))) ) - { - break; - } - if( ae_fp_greater(enew,e) ) - { - lambdav = lambdav*lambdaup*nu; - nu = nu*2; - continue; - } - - /* - * Optimize using inv(cholesky(H)) as preconditioner - */ - rmatrixtrinverse(&hmod, wcount, ae_true, ae_false, &invinfo, &invrep, _state); - if( invinfo<=0 ) - { - - /* - * if matrix can't be inverted then exit with errors - * TODO: make WCount steps in direction suggested by HMod - */ - *info = -9; - ae_frame_leave(_state); - return; - } - ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - for(i=0; i<=wcount-1; i++) - { - wt.ptr.p_double[i] = 0; - } - minlbfgscreatex(wcount, wcount, &wt, 1, 0.0, &state, _state); - minlbfgssetcond(&state, 0, 0, 0, 5, _state); - while(minlbfgsiteration(&state, _state)) - { - - /* - * gradient - */ - for(i=0; i<=wcount-1; i++) - { - v = ae_v_dotproduct(&state.x.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); - network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; - } - mlpgradbatch(network, xy, npoints, &state.f, &g, _state); - for(i=0; i<=wcount-1; i++) - { - state.g.ptr.p_double[i] = 0; - } - for(i=0; i<=wcount-1; i++) - { - v = g.ptr.p_double[i]; - ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); - } - - /* - * weight decay - * grad(x'*x) = A'*(x0+A*t) - */ - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - state.f = state.f+0.5*decay*v; - for(i=0; i<=wcount-1; i++) - { - v = decay*network->weights.ptr.p_double[i]; - ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); - } - - /* - * next iteration - */ - rep->ngrad = rep->ngrad+1; - } - minlbfgsresults(&state, &wt, &internalrep, _state); - - /* - * Accept new position. - * Calculate Hessian - */ - for(i=0; i<=wcount-1; i++) - { - v = ae_v_dotproduct(&wt.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); - network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; - } - mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = e+0.5*decay*v; - ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - for(k=0; k<=wcount-1; k++) - { - h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; - } - rep->nhess = rep->nhess+1; - - /* - * Update lambda - */ - lambdav = lambdav*lambdadown; - nu = 2; - } - - /* - * update WBest - */ - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = 0.5*decay*v+mlperror(network, xy, npoints, _state); - if( ae_fp_less(e,ebest) ) - { - ebest = e; - ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - } - } - - /* - * copy WBest to output - */ - ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Neural network training using L-BFGS algorithm with regularization. -Subroutine trains neural network with restarts from random positions. -Algorithm is well suited for problems of any dimensionality (memory -requirements and step complexity are linear by weights number). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - MaxIts - stopping criterion. Algorithm stops after MaxIts - iterations (NOT gradient calculations). Zero MaxIts - means stopping when step is sufficiently small. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlbfgs(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t pass; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_vector w; - ae_vector wbest; - double e; - double v; - double ebest; - minlbfgsreport internalrep; - minlbfgsstate state; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); - _minlbfgsreport_init(&internalrep, _state, ae_true); - _minlbfgsstate_init(&state, _state, ae_true); - - - /* - * Test inputs, parse flags, read network geometry - */ - if( ae_fp_eq(wstep,0)&&maxits==0 ) - { - *info = -8; - ae_frame_leave(_state); - return; - } - if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,0))||maxits<0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - mlpproperties(network, &nin, &nout, &wcount, _state); - if( mlpissoftmax(network, _state) ) - { - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - decay = ae_maxreal(decay, mlptrain_mindecay, _state); - *info = 2; - - /* - * Prepare - */ - mlpinitpreprocessor(network, xy, npoints, _state); - ae_vector_set_length(&w, wcount-1+1, _state); - ae_vector_set_length(&wbest, wcount-1+1, _state); - ebest = ae_maxrealnumber; - - /* - * Multiple starts - */ - rep->ncholesky = 0; - rep->nhess = 0; - rep->ngrad = 0; - for(pass=1; pass<=restarts; pass++) - { - - /* - * Process - */ - mlprandomize(network, _state); - ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); - minlbfgssetcond(&state, 0.0, 0.0, wstep, maxits, _state); - while(minlbfgsiteration(&state, _state)) - { - ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - mlpgradnbatch(network, xy, npoints, &state.f, &state.g, _state); - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - state.f = state.f+0.5*decay*v; - ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - rep->ngrad = rep->ngrad+1; - } - minlbfgsresults(&state, &w, &internalrep, _state); - ae_v_move(&network->weights.ptr.p_double[0], 1, &w.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - - /* - * Compare with best - */ - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = mlperrorn(network, xy, npoints, _state)+0.5*decay*v; - if( ae_fp_less(e,ebest) ) - { - ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ebest = e; - } - } - - /* - * The best network - */ - ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Neural network training using early stopping (base algorithm - L-BFGS with -regularization). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - TrnXY - training set - TrnSize - training set size, TrnSize>0 - ValXY - validation set - ValSize - validation set size, ValSize>0 - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts, either: - * strictly positive number - algorithm make specified - number of restarts from random position. - * -1, in which case algorithm makes exactly one run - from the initial state of the network (no randomization). - If you don't know what Restarts to choose, choose one - one the following: - * -1 (deterministic start) - * +1 (one random restart) - * +5 (moderate amount of random restarts) - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1, ...). - * 2, task has been solved, stopping criterion met - - sufficiently small step size. Not expected (we - use EARLY stopping) but possible and not an - error. - * 6, task has been solved, stopping criterion met - - increasing of validation set error. - Rep - training report - -NOTE: - -Algorithm stops if validation set error increases for a long enough or -step size is small enought (there are task where validation set may -decrease for eternity). In any case solution returned corresponds to the -minimum of validation set error. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptraines(multilayerperceptron* network, - /* Real */ ae_matrix* trnxy, - ae_int_t trnsize, - /* Real */ ae_matrix* valxy, - ae_int_t valsize, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t pass; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_vector w; - ae_vector wbest; - double e; - double v; - double ebest; - ae_vector wfinal; - double efinal; - ae_int_t itcnt; - ae_int_t itbest; - minlbfgsreport internalrep; - minlbfgsstate state; - double wstep; - ae_bool needrandomization; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wfinal, 0, DT_REAL, _state, ae_true); - _minlbfgsreport_init(&internalrep, _state, ae_true); - _minlbfgsstate_init(&state, _state, ae_true); - - wstep = 0.001; - - /* - * Test inputs, parse flags, read network geometry - */ - if( ((trnsize<=0||valsize<=0)||(restarts<1&&restarts!=-1))||ae_fp_less(decay,0) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( restarts==-1 ) - { - needrandomization = ae_false; - restarts = 1; - } - else - { - needrandomization = ae_true; - } - mlpproperties(network, &nin, &nout, &wcount, _state); - if( mlpissoftmax(network, _state) ) - { - for(i=0; i<=trnsize-1; i++) - { - if( ae_round(trnxy->ptr.pp_double[i][nin], _state)<0||ae_round(trnxy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - for(i=0; i<=valsize-1; i++) - { - if( ae_round(valxy->ptr.pp_double[i][nin], _state)<0||ae_round(valxy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - *info = 2; - - /* - * Prepare - */ - mlpinitpreprocessor(network, trnxy, trnsize, _state); - ae_vector_set_length(&w, wcount-1+1, _state); - ae_vector_set_length(&wbest, wcount-1+1, _state); - ae_vector_set_length(&wfinal, wcount-1+1, _state); - efinal = ae_maxrealnumber; - for(i=0; i<=wcount-1; i++) - { - wfinal.ptr.p_double[i] = 0; - } - - /* - * Multiple starts - */ - rep->ncholesky = 0; - rep->nhess = 0; - rep->ngrad = 0; - for(pass=1; pass<=restarts; pass++) - { - - /* - * Process - */ - if( needrandomization ) - { - mlprandomize(network, _state); - } - ebest = mlperror(network, valxy, valsize, _state); - ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - itbest = 0; - itcnt = 0; - ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); - minlbfgssetcond(&state, 0.0, 0.0, wstep, 0, _state); - minlbfgssetxrep(&state, ae_true, _state); - while(minlbfgsiteration(&state, _state)) - { - - /* - * Calculate gradient - */ - if( state.needfg ) - { - ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - mlpgradnbatch(network, trnxy, trnsize, &state.f, &state.g, _state); - v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - state.f = state.f+0.5*decay*v; - ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - rep->ngrad = rep->ngrad+1; - } - - /* - * Validation set - */ - if( state.xupdated ) - { - ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - e = mlperror(network, valxy, valsize, _state); - if( ae_fp_less(e,ebest) ) - { - ebest = e; - ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - itbest = itcnt; - } - if( itcnt>30&&ae_fp_greater(itcnt,1.5*itbest) ) - { - *info = 6; - break; - } - itcnt = itcnt+1; - } - } - minlbfgsresults(&state, &w, &internalrep, _state); - - /* - * Compare with final answer - */ - if( ae_fp_less(ebest,efinal) ) - { - ae_v_move(&wfinal.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - efinal = ebest; - } - } - - /* - * The best network - */ - ae_v_move(&network->weights.ptr.p_double[0], 1, &wfinal.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - L-BFGS. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlbfgs(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t foldscount, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state) -{ - - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(cvrep); - - mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_false, wstep, maxits, info, rep, cvrep, _state); -} - - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - Levenberg-Marquardt. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlm(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t foldscount, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state) -{ - - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(cvrep); - - mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_true, 0.0, 0, info, rep, cvrep, _state); -} - - -/************************************************************************* -This function estimates generalization error using cross-validation on the -current dataset with current training settings. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * FoldsCount cross-validation rounds (always) - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. Network is not changed during cross- - validation and is not trained - it is used only as - representative of its architecture. I.e., we estimate - generalization properties of ARCHITECTURE, not some - specific network. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that for each cross-validation - round specified number of random restarts is - performed, with best network being chosen after - training. - * NRestarts=0 is same as NRestarts=1 - FoldsCount - number of folds in k-fold cross-validation: - * 2<=FoldsCount<=size of dataset - * recommended value: 10. - * values larger than dataset size will be silently - truncated down to dataset size - -OUTPUT PARAMETERS: - Rep - structure which contains cross-validation estimates: - * Rep.RelCLSError - fraction of misclassified cases. - * Rep.AvgCE - acerage cross-entropy - * Rep.RMSError - root-mean-square error - * Rep.AvgError - average error - * Rep.AvgRelError - average relative error - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or subset with only one point was given, zeros are returned as - estimates. - -NOTE: this method performs FoldsCount cross-validation rounds, each one - with NRestarts random starts. Thus, FoldsCount*NRestarts networks - are trained in total. - -NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. - -NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError - contain errors in prediction of posterior probabilities. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcv(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - ae_int_t foldscount, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_shared_pool pooldatacv; - mlpparallelizationcv datacv; - mlpparallelizationcv *sdatacv; - ae_smart_ptr _sdatacv; - ae_matrix cvy; - ae_vector folds; - ae_vector buf; - ae_vector dy; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t rowsize; - ae_int_t ntype; - ae_int_t ttype; - ae_int_t i; - ae_int_t j; - ae_int_t k; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - _mlpreport_clear(rep); - ae_shared_pool_init(&pooldatacv, _state, ae_true); - _mlpparallelizationcv_init(&datacv, _state, ae_true); - ae_smart_ptr_init(&_sdatacv, (void**)&sdatacv, _state, ae_true); - ae_matrix_init(&cvy, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&folds, 0, DT_INT, _state, ae_true); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&rs, _state, ae_true); - - if( !mlpissoftmax(network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - ae_assert(ntype==ttype, "MLPKFoldCV: type of input network is not similar to network type in trainer object", _state); - ae_assert(s->npoints>=0, "MLPKFoldCV: possible trainer S is not initialized(S.NPoints<0)", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPKFoldCV: number of inputs in trainer is not equal to number of inputs in network", _state); - ae_assert(s->nout==nout, "MLPKFoldCV: number of outputs in trainer is not equal to number of outputs in network", _state); - ae_assert(nrestarts>=0, "MLPKFoldCV: NRestarts<0", _state); - ae_assert(foldscount>=2, "MLPKFoldCV: FoldsCount<2", _state); - if( foldscount>s->npoints ) - { - foldscount = s->npoints; - } - rep->relclserror = 0; - rep->avgce = 0; - rep->rmserror = 0; - rep->avgerror = 0; - rep->avgrelerror = 0; - hqrndrandomize(&rs, _state); - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - if( s->npoints==0||s->npoints==1 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Read network geometry, test parameters - */ - if( s->rcpar ) - { - rowsize = nin+nout; - ae_vector_set_length(&dy, nout, _state); - dserrallocate(-nout, &buf, _state); - } - else - { - rowsize = nin+1; - ae_vector_set_length(&dy, 1, _state); - dserrallocate(nout, &buf, _state); - } - - /* - * Folds - */ - ae_vector_set_length(&folds, s->npoints, _state); - for(i=0; i<=s->npoints-1; i++) - { - folds.ptr.p_int[i] = i*foldscount/s->npoints; - } - for(i=0; i<=s->npoints-2; i++) - { - j = i+hqrnduniformi(&rs, s->npoints-i, _state); - if( j!=i ) - { - k = folds.ptr.p_int[i]; - folds.ptr.p_int[i] = folds.ptr.p_int[j]; - folds.ptr.p_int[j] = k; - } - } - ae_matrix_set_length(&cvy, s->npoints, nout, _state); - - /* - * Initialize SEED-value for shared pool - */ - datacv.ngrad = 0; - mlpcopy(network, &datacv.network, _state); - ae_vector_set_length(&datacv.subset, s->npoints, _state); - ae_vector_set_length(&datacv.xyrow, rowsize, _state); - ae_vector_set_length(&datacv.y, nout, _state); - - /* - * Create shared pool - */ - ae_shared_pool_set_seed(&pooldatacv, &datacv, sizeof(datacv), _mlpparallelizationcv_init, _mlpparallelizationcv_init_copy, _mlpparallelizationcv_destroy, _state); - - /* - * Parallelization - */ - mlptrain_mthreadcv(s, rowsize, nrestarts, &folds, 0, foldscount, &cvy, &pooldatacv, _state); - - /* - * Calculate value for NGrad - */ - ae_shared_pool_first_recycled(&pooldatacv, &_sdatacv, _state); - while(sdatacv!=NULL) - { - rep->ngrad = rep->ngrad+sdatacv->ngrad; - ae_shared_pool_next_recycled(&pooldatacv, &_sdatacv, _state); - } - - /* - * Connect of results and calculate cross-validation error - */ - for(i=0; i<=s->npoints-1; i++) - { - if( s->datatype==0 ) - { - ae_v_move(&datacv.xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); - } - if( s->datatype==1 ) - { - sparsegetrow(&s->sparsexy, i, &datacv.xyrow, _state); - } - ae_v_move(&datacv.y.ptr.p_double[0], 1, &cvy.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1)); - if( s->rcpar ) - { - ae_v_move(&dy.ptr.p_double[0], 1, &datacv.xyrow.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); - } - else - { - dy.ptr.p_double[0] = datacv.xyrow.ptr.p_double[nin]; - } - dserraccumulate(&buf, &datacv.y, &dy, _state); - } - dserrfinish(&buf, _state); - rep->relclserror = buf.ptr.p_double[0]; - rep->avgce = buf.ptr.p_double[1]; - rep->rmserror = buf.ptr.p_double[2]; - rep->avgerror = buf.ptr.p_double[3]; - rep->avgrelerror = buf.ptr.p_double[4]; - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlpkfoldcv(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - ae_int_t foldscount, - mlpreport* rep, ae_state *_state) -{ - mlpkfoldcv(s,network,nrestarts,foldscount,rep, _state); -} - - -/************************************************************************* -Creation of the network trainer object for regression networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NOut - number of outputs, NOut>=1 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any regression - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainer(ae_int_t nin, - ae_int_t nout, - mlptrainer* s, - ae_state *_state) -{ - - _mlptrainer_clear(s); - - ae_assert(nin>=1, "MLPCreateTrainer: NIn<1.", _state); - ae_assert(nout>=1, "MLPCreateTrainer: NOut<1.", _state); - s->nin = nin; - s->nout = nout; - s->rcpar = ae_true; - s->lbfgsfactor = mlptrain_defaultlbfgsfactor; - s->decay = 1.0E-6; - mlpsetcond(s, 0, 0, _state); - s->datatype = 0; - s->npoints = 0; - mlpsetalgobatch(s, _state); -} - - -/************************************************************************* -Creation of the network trainer object for classification networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any classification - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainercls(ae_int_t nin, - ae_int_t nclasses, - mlptrainer* s, - ae_state *_state) -{ - - _mlptrainer_clear(s); - - ae_assert(nin>=1, "MLPCreateTrainerCls: NIn<1.", _state); - ae_assert(nclasses>=2, "MLPCreateTrainerCls: NClasses<2.", _state); - s->nin = nin; - s->nout = nclasses; - s->rcpar = ae_false; - s->lbfgsfactor = mlptrain_defaultlbfgsfactor; - s->decay = 1.0E-6; - mlpsetcond(s, 0, 0, _state); - s->datatype = 0; - s->npoints = 0; - mlpsetalgobatch(s, _state); -} - - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user. - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. - NPoints - points count, >=0. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdataset(mlptrainer* s, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - ae_int_t ndim; - ae_int_t i; - ae_int_t j; - - - ae_assert(s->nin>=1, "MLPSetDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); - ae_assert(npoints>=0, "MLPSetDataset: NPoint<0", _state); - ae_assert(npoints<=xy->rows, "MLPSetDataset: invalid size of matrix XY(NPoint more then rows of matrix XY)", _state); - s->datatype = 0; - s->npoints = npoints; - if( npoints==0 ) - { - return; - } - if( s->rcpar ) - { - ae_assert(s->nout>=1, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); - ndim = s->nin+s->nout; - ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); - ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); - } - else - { - ae_assert(s->nout>=2, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); - ndim = s->nin+1; - ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); - ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); - for(i=0; i<=npoints-1; i++) - { - ae_assert(ae_round(xy->ptr.pp_double[i][s->nin], _state)>=0&&ae_round(xy->ptr.pp_double[i][s->nin], _state)nout, "MLPSetDataset: invalid parameter XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); - } - } - rmatrixsetlengthatleast(&s->densexy, npoints, ndim, _state); - for(i=0; i<=npoints-1; i++) - { - for(j=0; j<=ndim-1; j++) - { - s->densexy.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; - } - } -} - - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user (sparse matrix is used to store dataset). - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Any sparse storage format can be used: - Hash-table, CRS... - NPoints - points count, >=0 - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetsparsedataset(mlptrainer* s, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state) -{ - double v; - ae_int_t t0; - ae_int_t t1; - ae_int_t i; - ae_int_t j; - - - - /* - * Check correctness of the data - */ - ae_assert(s->nin>0, "MLPSetSparseDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); - ae_assert(npoints>=0, "MLPSetSparseDataset: NPoint<0", _state); - ae_assert(npoints<=sparsegetnrows(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(NPoint more then rows of matrix XY)", _state); - if( npoints>0 ) - { - t0 = 0; - t1 = 0; - if( s->rcpar ) - { - ae_assert(s->nout>=1, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); - ae_assert(s->nin+s->nout<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); - while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) - { - if( inin+s->nout ) - { - ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); - } - } - } - else - { - ae_assert(s->nout>=2, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); - ae_assert(s->nin+1<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); - while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) - { - if( inin ) - { - if( j!=s->nin ) - { - ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); - } - else - { - ae_assert((ae_isfinite(v, _state)&&ae_round(v, _state)>=0)&&ae_round(v, _state)nout, "MLPSetSparseDataset: invalid sparse matrix XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); - } - } - } - } - } - - /* - * Set dataset - */ - s->datatype = 1; - s->npoints = npoints; - sparsecopytocrs(xy, &s->sparsexy, _state); -} - - -/************************************************************************* -This function sets weight decay coefficient which is used for training. - -INPUT PARAMETERS: - S - trainer object - Decay - weight decay coefficient, >=0. Weight decay term - 'Decay*||Weights||^2' is added to error function. If - you don't know what Decay to choose, use 1.0E-3. - Weight decay can be set to zero, in this case network - is trained without weight decay. - -NOTE: by default network uses some small nonzero value for weight decay. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state) -{ - - - ae_assert(ae_isfinite(decay, _state), "MLPSetDecay: parameter Decay contains Infinite or NaN.", _state); - ae_assert(ae_fp_greater_eq(decay,0), "MLPSetDecay: Decay<0.", _state); - s->decay = decay; -} - - -/************************************************************************* -This function sets stopping criteria for the optimizer. - -INPUT PARAMETERS: - S - trainer object - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - WStep>=0. - MaxIts - stopping criterion. Algorithm stops after MaxIts - epochs (full passes over entire dataset). Zero MaxIts - means stopping when step is sufficiently small. - MaxIts>=0. - -NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also - used when MLPSetCond() is called with WStep=0 and MaxIts=0. - -NOTE: these stopping criteria are used for all kinds of neural training - - from "conventional" networks to early stopping ensembles. When used - for "conventional" networks, they are used as the only stopping - criteria. When combined with early stopping, they used as ADDITIONAL - stopping criteria which can terminate early stopping algorithm. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetcond(mlptrainer* s, - double wstep, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(wstep, _state), "MLPSetCond: parameter WStep contains Infinite or NaN.", _state); - ae_assert(ae_fp_greater_eq(wstep,0), "MLPSetCond: WStep<0.", _state); - ae_assert(maxits>=0, "MLPSetCond: MaxIts<0.", _state); - if( ae_fp_neq(wstep,0)||maxits!=0 ) - { - s->wstep = wstep; - s->maxits = maxits; - } - else - { - s->wstep = 0.005; - s->maxits = 0; - } -} - - -/************************************************************************* -This function sets training algorithm: batch training using L-BFGS will be -used. - -This algorithm: -* the most robust for small-scale problems, but may be too slow for large - scale ones. -* perfoms full pass through the dataset before performing step -* uses conditions specified by MLPSetCond() for stopping -* is default one used by trainer object - -INPUT PARAMETERS: - S - trainer object - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetalgobatch(mlptrainer* s, ae_state *_state) -{ - - - s->algokind = 0; -} - - -/************************************************************************* -This function trains neural network passed to this function, using current -dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) -and current training settings. Training from NRestarts random starting -positions is performed, best network is chosen. - -Training is performed using current training algorithm. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed, best network is chosen after - training - * NRestarts=0 means that current state of the network - is used for training. - -OUTPUT PARAMETERS: - Network - trained network - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - network is filled by zero values. Same behavior for functions - MLPStartTraining and MLPContinueTraining. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainnetwork(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntype; - ae_int_t ttype; - ae_shared_pool trnpool; - - ae_frame_make(_state, &_frame_block); - _mlpreport_clear(rep); - ae_shared_pool_init(&trnpool, _state, ae_true); - - ae_assert(s->npoints>=0, "MLPTrainNetwork: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - if( !mlpissoftmax(network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - ae_assert(ntype==ttype, "MLPTrainNetwork: type of input network is not similar to network type in trainer object", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPTrainNetwork: number of inputs in trainer is not equal to number of inputs in network", _state); - ae_assert(s->nout==nout, "MLPTrainNetwork: number of outputs in trainer is not equal to number of outputs in network", _state); - ae_assert(nrestarts>=0, "MLPTrainNetwork: NRestarts<0.", _state); - - /* - * Train - */ - mlptrain_mlptrainnetworkx(s, nrestarts, -1, &s->subset, -1, &s->subset, 0, network, rep, ae_true, &trnpool, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlptrainnetwork(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - mlpreport* rep, ae_state *_state) -{ - mlptrainnetwork(s,network,nrestarts,rep, _state); -} - - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -After call to this function trainer object remembers network and is ready -to train it. However, no training is performed until first call to -MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() -will advance training progress one iteration further. - -EXAMPLE: - > - > ...initialize network and trainer object.... - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > ...visualize training progress... - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - RandomStart - randomize network before training or not: - * True means that network is randomized and its - initial state (one which was passed to the trainer - object) is lost. - * False means that training is started from the - current state of the network - -OUTPUT PARAMETERS: - Network - neural network which is ready to training (weights are - initialized, preprocessor is initialized using current - training set) - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpstarttraining(mlptrainer* s, - multilayerperceptron* network, - ae_bool randomstart, - ae_state *_state) -{ - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntype; - ae_int_t ttype; - - - ae_assert(s->npoints>=0, "MLPStartTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - if( !mlpissoftmax(network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - ae_assert(ntype==ttype, "MLPStartTraining: type of input network is not similar to network type in trainer object", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPStartTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); - ae_assert(s->nout==nout, "MLPStartTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); - - /* - * Initialize temporaries - */ - mlptrain_initmlptrnsession(network, randomstart, s, &s->session, _state); - - /* - * Train network - */ - mlptrain_mlpstarttrainingx(s, randomstart, -1, &s->subset, -1, &s->session, _state); - - /* - * Update network - */ - mlpcopytunableparameters(&s->session.network, network, _state); -} - - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -This function performs one more iteration of the training and returns -either True (training continues) or False (training stopped). In case True -was returned, Network weights are updated according to the current state -of the optimization progress. In case False was returned, no additional -updates is performed (previous update of the network weights moved us to -the final point, and no additional updates is needed). - -EXAMPLE: - > - > [initialize network and trainer object] - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > [visualize training progress] - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network structure, which is used to store - current state of the training process. - -OUTPUT PARAMETERS: - Network - weights of the neural network are rewritten by the - current approximation. - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - -NOTE: It is expected that Network is the same one which was passed to - MLPStartTraining() function. However, THIS function checks only - following: - * that number of network inputs is consistent with trainer object - settings - * that number of network outputs/classes is consistent with trainer - object settings - * that number of network weights is the same as number of weights in - the network passed to MLPStartTraining() function - Exception is thrown when these conditions are violated. - - It is also expected that you do not change state of the network on - your own - the only party who has right to change network during its - training is a trainer object. Any attempt to interfere with trainer - may lead to unpredictable results. - - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool mlpcontinuetraining(mlptrainer* s, - multilayerperceptron* network, - ae_state *_state) -{ - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntype; - ae_int_t ttype; - ae_bool result; - - - ae_assert(s->npoints>=0, "MLPContinueTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - if( !mlpissoftmax(network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - ae_assert(ntype==ttype, "MLPContinueTraining: type of input network is not similar to network type in trainer object.", _state); - mlpproperties(network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPContinueTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); - ae_assert(s->nout==nout, "MLPContinueTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); - result = mlptrain_mlpcontinuetrainingx(s, &s->subset, -1, &s->ngradbatch, &s->session, _state); - if( result ) - { - ae_v_move(&network->weights.ptr.p_double[0], 1, &s->session.network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - } - return result; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -ae_bool _pexec_mlpcontinuetraining(mlptrainer* s, - multilayerperceptron* network, ae_state *_state) -{ - return mlpcontinuetraining(s,network, _state); -} - - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -Modified Levenberg-Marquardt algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglm(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state) -{ - - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(ooberrors); - - mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, 0.0, 0, ae_true, info, rep, ooberrors, _state); -} - - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -L-BFGS algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglbfgs(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state) -{ - - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(ooberrors); - - mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, wstep, maxits, ae_false, info, rep, ooberrors, _state); -} - - -/************************************************************************* -Training neural networks ensemble using early stopping. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 6, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpetraines(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - ae_int_t ccount; - ae_int_t pcount; - ae_matrix trnxy; - ae_matrix valxy; - ae_int_t trnsize; - ae_int_t valsize; - ae_int_t tmpinfo; - mlpreport tmprep; - modelerrors moderr; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - ae_matrix_init(&trnxy, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&valxy, 0, 0, DT_REAL, _state, ae_true); - _mlpreport_init(&tmprep, _state, ae_true); - _modelerrors_init(&moderr, _state, ae_true); - - nin = mlpgetinputscount(&ensemble->network, _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - wcount = mlpgetweightscount(&ensemble->network, _state); - if( (npoints<2||restarts<1)||ae_fp_less(decay,0) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( mlpissoftmax(&ensemble->network, _state) ) - { - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - *info = 6; - - /* - * allocate - */ - if( mlpissoftmax(&ensemble->network, _state) ) - { - ccount = nin+1; - pcount = nin; - } - else - { - ccount = nin+nout; - pcount = nin+nout; - } - ae_matrix_set_length(&trnxy, npoints, ccount, _state); - ae_matrix_set_length(&valxy, npoints, ccount, _state); - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - - /* - * train networks - */ - for(k=0; k<=ensemble->ensemblesize-1; k++) - { - - /* - * Split set - */ - do - { - trnsize = 0; - valsize = 0; - for(i=0; i<=npoints-1; i++) - { - if( ae_fp_less(ae_randomreal(_state),0.66) ) - { - - /* - * Assign sample to training set - */ - ae_v_move(&trnxy.ptr.pp_double[trnsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); - trnsize = trnsize+1; - } - else - { - - /* - * Assign sample to validation set - */ - ae_v_move(&valxy.ptr.pp_double[valsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); - valsize = valsize+1; - } - } - } - while(!(trnsize!=0&&valsize!=0)); - - /* - * Train - */ - mlptraines(&ensemble->network, &trnxy, trnsize, &valxy, valsize, decay, restarts, &tmpinfo, &tmprep, _state); - if( tmpinfo<0 ) - { - *info = tmpinfo; - ae_frame_leave(_state); - return; - } - - /* - * save results - */ - ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); - ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); - ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); - rep->ngrad = rep->ngrad+tmprep.ngrad; - rep->nhess = rep->nhess+tmprep.nhess; - rep->ncholesky = rep->ncholesky+tmprep.ncholesky; - } - mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &moderr, _state); - rep->relclserror = moderr.relclserror; - rep->avgce = moderr.avgce; - rep->rmserror = moderr.rmserror; - rep->avgerror = moderr.avgerror; - rep->avgrelerror = moderr.avgrelerror; - ae_frame_leave(_state); -} - - -/************************************************************************* -This function trains neural network ensemble passed to this function using -current dataset and early stopping training algorithm. Each early stopping -round performs NRestarts random restarts (thus, EnsembleSize*NRestarts -training rounds is performed in total). - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * EnsembleSize training sessions performed for each of ensemble - ! members (always parallelized) - ! * NRestarts training sessions performed within each of training - ! sessions (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object; - Ensemble - neural network ensemble. It must have same number of - inputs and outputs/classes as was specified during - creation of the trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed during each ES round; - * NRestarts=0 is silently replaced by 1. - -OUTPUT PARAMETERS: - Ensemble - trained ensemble; - Rep - it contains all type of errors. - -NOTE: this training method uses BOTH early stopping and weight decay! So, - you should select weight decay before starting training just as you - select it before training "conventional" networks. - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or single-point dataset was passed, ensemble is filled by zero - values. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 22.08.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainensemblees(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t nrestarts, - mlpreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t ntype; - ae_int_t ttype; - ae_shared_pool esessions; - sinteger sgrad; - modelerrors tmprep; - - ae_frame_make(_state, &_frame_block); - _mlpreport_clear(rep); - ae_shared_pool_init(&esessions, _state, ae_true); - _sinteger_init(&sgrad, _state, ae_true); - _modelerrors_init(&tmprep, _state, ae_true); - - ae_assert(s->npoints>=0, "MLPTrainEnsembleES: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - if( !mlpeissoftmax(ensemble, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - ae_assert(ntype==ttype, "MLPTrainEnsembleES: internal error - type of input network is not similar to network type in trainer object", _state); - nin = mlpgetinputscount(&ensemble->network, _state); - ae_assert(s->nin==nin, "MLPTrainEnsembleES: number of inputs in trainer is not equal to number of inputs in ensemble network", _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - ae_assert(s->nout==nout, "MLPTrainEnsembleES: number of outputs in trainer is not equal to number of outputs in ensemble network", _state); - ae_assert(nrestarts>=0, "MLPTrainEnsembleES: NRestarts<0.", _state); - - /* - * Initialize parameter Rep - */ - rep->relclserror = 0; - rep->avgce = 0; - rep->rmserror = 0; - rep->avgerror = 0; - rep->avgrelerror = 0; - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - - /* - * Allocate - */ - ivectorsetlengthatleast(&s->subset, s->npoints, _state); - ivectorsetlengthatleast(&s->valsubset, s->npoints, _state); - - /* - * Start training - * - * NOTE: ESessions is not initialized because MLPTrainEnsembleX - * needs uninitialized pool. - */ - sgrad.val = 0; - mlptrain_mlptrainensemblex(s, ensemble, 0, ensemble->ensemblesize, nrestarts, 0, &sgrad, ae_true, &esessions, _state); - rep->ngrad = sgrad.val; - - /* - * Calculate errors. - */ - if( s->datatype==0 ) - { - mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 0, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); - } - if( s->datatype==1 ) - { - mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 1, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); - } - rep->relclserror = tmprep.relclserror; - rep->avgce = tmprep.avgce; - rep->rmserror = tmprep.rmserror; - rep->avgerror = tmprep.avgerror; - rep->avgrelerror = tmprep.avgrelerror; - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_mlptrainensemblees(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t nrestarts, - mlpreport* rep, ae_state *_state) -{ - mlptrainensemblees(s,ensemble,nrestarts,rep, _state); -} - - -/************************************************************************* -Internal cross-validation subroutine -*************************************************************************/ -static void mlptrain_mlpkfoldcvgeneral(multilayerperceptron* n, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t foldscount, - ae_bool lmalgorithm, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t fold; - ae_int_t j; - ae_int_t k; - multilayerperceptron network; - ae_int_t nin; - ae_int_t nout; - ae_int_t rowlen; - ae_int_t wcount; - ae_int_t nclasses; - ae_int_t tssize; - ae_int_t cvssize; - ae_matrix cvset; - ae_matrix testset; - ae_vector folds; - ae_int_t relcnt; - mlpreport internalrep; - ae_vector x; - ae_vector y; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(cvrep); - _multilayerperceptron_init(&network, _state, ae_true); - ae_matrix_init(&cvset, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&testset, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&folds, 0, DT_INT, _state, ae_true); - _mlpreport_init(&internalrep, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - - /* - * Read network geometry, test parameters - */ - mlpproperties(n, &nin, &nout, &wcount, _state); - if( mlpissoftmax(n, _state) ) - { - nclasses = nout; - rowlen = nin+1; - } - else - { - nclasses = -nout; - rowlen = nin+nout; - } - if( (npoints<=0||foldscount<2)||foldscount>npoints ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - mlpcopy(n, &network, _state); - - /* - * K-fold out cross-validation. - * First, estimate generalization error - */ - ae_matrix_set_length(&testset, npoints-1+1, rowlen-1+1, _state); - ae_matrix_set_length(&cvset, npoints-1+1, rowlen-1+1, _state); - ae_vector_set_length(&x, nin-1+1, _state); - ae_vector_set_length(&y, nout-1+1, _state); - mlptrain_mlpkfoldsplit(xy, npoints, nclasses, foldscount, ae_false, &folds, _state); - cvrep->relclserror = 0; - cvrep->avgce = 0; - cvrep->rmserror = 0; - cvrep->avgerror = 0; - cvrep->avgrelerror = 0; - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - relcnt = 0; - for(fold=0; fold<=foldscount-1; fold++) - { - - /* - * Separate set - */ - tssize = 0; - cvssize = 0; - for(i=0; i<=npoints-1; i++) - { - if( folds.ptr.p_int[i]==fold ) - { - ae_v_move(&testset.ptr.pp_double[tssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); - tssize = tssize+1; - } - else - { - ae_v_move(&cvset.ptr.pp_double[cvssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); - cvssize = cvssize+1; - } - } - - /* - * Train on CV training set - */ - if( lmalgorithm ) - { - mlptrainlm(&network, &cvset, cvssize, decay, restarts, info, &internalrep, _state); - } - else - { - mlptrainlbfgs(&network, &cvset, cvssize, decay, restarts, wstep, maxits, info, &internalrep, _state); - } - if( *info<0 ) - { - cvrep->relclserror = 0; - cvrep->avgce = 0; - cvrep->rmserror = 0; - cvrep->avgerror = 0; - cvrep->avgrelerror = 0; - ae_frame_leave(_state); - return; - } - rep->ngrad = rep->ngrad+internalrep.ngrad; - rep->nhess = rep->nhess+internalrep.nhess; - rep->ncholesky = rep->ncholesky+internalrep.ncholesky; - - /* - * Estimate error using CV test set - */ - if( mlpissoftmax(&network, _state) ) - { - - /* - * classification-only code - */ - cvrep->relclserror = cvrep->relclserror+mlpclserror(&network, &testset, tssize, _state); - cvrep->avgce = cvrep->avgce+mlperrorn(&network, &testset, tssize, _state); - } - for(i=0; i<=tssize-1; i++) - { - ae_v_move(&x.ptr.p_double[0], 1, &testset.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); - mlpprocess(&network, &x, &y, _state); - if( mlpissoftmax(&network, _state) ) - { - - /* - * Classification-specific code - */ - k = ae_round(testset.ptr.pp_double[i][nin], _state); - for(j=0; j<=nout-1; j++) - { - if( j==k ) - { - cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-1, _state); - cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-1, _state); - cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs(y.ptr.p_double[j]-1, _state); - relcnt = relcnt+1; - } - else - { - cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j], _state); - cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j], _state); - } - } - } - else - { - - /* - * Regression-specific code - */ - for(j=0; j<=nout-1; j++) - { - cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); - cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); - if( ae_fp_neq(testset.ptr.pp_double[i][nin+j],0) ) - { - cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs((y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j])/testset.ptr.pp_double[i][nin+j], _state); - relcnt = relcnt+1; - } - } - } - } - } - if( mlpissoftmax(&network, _state) ) - { - cvrep->relclserror = cvrep->relclserror/npoints; - cvrep->avgce = cvrep->avgce/(ae_log(2, _state)*npoints); - } - cvrep->rmserror = ae_sqrt(cvrep->rmserror/(npoints*nout), _state); - cvrep->avgerror = cvrep->avgerror/(npoints*nout); - if( relcnt>0 ) - { - cvrep->avgrelerror = cvrep->avgrelerror/relcnt; - } - *info = 1; - ae_frame_leave(_state); -} - - -/************************************************************************* -Subroutine prepares K-fold split of the training set. - -NOTES: - "NClasses>0" means that we have classification task. - "NClasses<0" means regression task with -NClasses real outputs. -*************************************************************************/ -static void mlptrain_mlpkfoldsplit(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nclasses, - ae_int_t foldscount, - ae_bool stratifiedsplits, - /* Integer */ ae_vector* folds, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(folds); - _hqrndstate_init(&rs, _state, ae_true); - - - /* - * test parameters - */ - ae_assert(npoints>0, "MLPKFoldSplit: wrong NPoints!", _state); - ae_assert(nclasses>1||nclasses<0, "MLPKFoldSplit: wrong NClasses!", _state); - ae_assert(foldscount>=2&&foldscount<=npoints, "MLPKFoldSplit: wrong FoldsCount!", _state); - ae_assert(!stratifiedsplits, "MLPKFoldSplit: stratified splits are not supported!", _state); - - /* - * Folds - */ - hqrndrandomize(&rs, _state); - ae_vector_set_length(folds, npoints-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - folds->ptr.p_int[i] = i*foldscount/npoints; - } - for(i=0; i<=npoints-2; i++) - { - j = i+hqrnduniformi(&rs, npoints-i, _state); - if( j!=i ) - { - k = folds->ptr.p_int[i]; - folds->ptr.p_int[i] = folds->ptr.p_int[j]; - folds->ptr.p_int[j] = k; - } - } - ae_frame_leave(_state); -} - - -static void mlptrain_mthreadcv(mlptrainer* s, - ae_int_t rowsize, - ae_int_t nrestarts, - /* Integer */ ae_vector* folds, - ae_int_t fold, - ae_int_t dfold, - /* Real */ ae_matrix* cvy, - ae_shared_pool* pooldatacv, - ae_state *_state) -{ - ae_frame _frame_block; - mlpparallelizationcv *datacv; - ae_smart_ptr _datacv; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_smart_ptr_init(&_datacv, (void**)&datacv, _state, ae_true); - - if( fold==dfold-1 ) - { - - /* - * Separate set - */ - ae_shared_pool_retrieve(pooldatacv, &_datacv, _state); - datacv->subsetsize = 0; - for(i=0; i<=s->npoints-1; i++) - { - if( folds->ptr.p_int[i]!=fold ) - { - datacv->subset.ptr.p_int[datacv->subsetsize] = i; - datacv->subsetsize = datacv->subsetsize+1; - } - } - - /* - * Train on CV training set - */ - mlptrain_mlptrainnetworkx(s, nrestarts, -1, &datacv->subset, datacv->subsetsize, &datacv->subset, 0, &datacv->network, &datacv->rep, ae_true, &datacv->trnpool, _state); - datacv->ngrad = datacv->ngrad+datacv->rep.ngrad; - - /* - * Estimate error using CV test set - */ - for(i=0; i<=s->npoints-1; i++) - { - if( folds->ptr.p_int[i]==fold ) - { - if( s->datatype==0 ) - { - ae_v_move(&datacv->xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); - } - if( s->datatype==1 ) - { - sparsegetrow(&s->sparsexy, i, &datacv->xyrow, _state); - } - mlpprocess(&datacv->network, &datacv->xyrow, &datacv->y, _state); - ae_v_move(&cvy->ptr.pp_double[i][0], 1, &datacv->y.ptr.p_double[0], 1, ae_v_len(0,s->nout-1)); - } - } - ae_shared_pool_recycle(pooldatacv, &_datacv, _state); - } - else - { - ae_assert(foldDFold-1).", _state); - mlptrain_mthreadcv(s, rowsize, nrestarts, folds, fold, (fold+dfold)/2, cvy, pooldatacv, _state); - mlptrain_mthreadcv(s, rowsize, nrestarts, folds, (fold+dfold)/2, dfold, cvy, pooldatacv, _state); - } - ae_frame_leave(_state); -} - - -static void mlptrain_mlptrainnetworkx(mlptrainer* s, - ae_int_t nrestarts, - ae_int_t algokind, - /* Integer */ ae_vector* trnsubset, - ae_int_t trnsubsetsize, - /* Integer */ ae_vector* valsubset, - ae_int_t valsubsetsize, - multilayerperceptron* network, - mlpreport* rep, - ae_bool isrootcall, - ae_shared_pool* sessions, - ae_state *_state) -{ - ae_frame _frame_block; - modelerrors modrep; - double eval; - double ebest; - ae_int_t ngradbatch; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t pcount; - ae_int_t itbest; - ae_int_t itcnt; - ae_int_t ntype; - ae_int_t ttype; - ae_bool rndstart; - ae_int_t i; - ae_int_t nr0; - ae_int_t nr1; - mlpreport rep0; - mlpreport rep1; - ae_bool randomizenetwork; - double bestrmserror; - smlptrnsession *psession; - ae_smart_ptr _psession; - - ae_frame_make(_state, &_frame_block); - _modelerrors_init(&modrep, _state, ae_true); - _mlpreport_init(&rep0, _state, ae_true); - _mlpreport_init(&rep1, _state, ae_true); - ae_smart_ptr_init(&_psession, (void**)&psession, _state, ae_true); - - mlpproperties(network, &nin, &nout, &wcount, _state); - - /* - * Process root call - */ - if( isrootcall ) - { - - /* - * Check correctness of parameters - */ - ae_assert(algokind==0||algokind==-1, "MLPTrainNetworkX: unexpected AlgoKind", _state); - ae_assert(s->npoints>=0, "MLPTrainNetworkX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - if( !mlpissoftmax(network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - ae_assert(ntype==ttype, "MLPTrainNetworkX: internal error - type of the training network is not similar to network type in trainer object", _state); - ae_assert(s->nin==nin, "MLPTrainNetworkX: internal error - number of inputs in trainer is not equal to number of inputs in the training network.", _state); - ae_assert(s->nout==nout, "MLPTrainNetworkX: internal error - number of outputs in trainer is not equal to number of outputs in the training network.", _state); - ae_assert(nrestarts>=0, "MLPTrainNetworkX: internal error - NRestarts<0.", _state); - ae_assert(trnsubset->cnt>=trnsubsetsize, "MLPTrainNetworkX: internal error - parameter TrnSubsetSize more than input subset size(Length(TrnSubset)ptr.p_int[i]>=0&&trnsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter TrnSubset contains incorrect index(TrnSubset[I]<0 or TrnSubset[I]>S.NPoints-1)", _state); - } - ae_assert(valsubset->cnt>=valsubsetsize, "MLPTrainNetworkX: internal error - parameter ValSubsetSize more than input subset size(Length(ValSubset)ptr.p_int[i]>=0&&valsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter ValSubset contains incorrect index(ValSubset[I]<0 or ValSubset[I]>S.NPoints-1)", _state); - } - - /* - * Train - */ - randomizenetwork = nrestarts>0; - mlptrain_initmlptrnsessions(network, randomizenetwork, s, sessions, _state); - mlptrain_mlptrainnetworkx(s, nrestarts, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, rep, ae_false, sessions, _state); - - /* - * Choose best network - */ - bestrmserror = ae_maxrealnumber; - ae_shared_pool_first_recycled(sessions, &_psession, _state); - while(psession!=NULL) - { - if( ae_fp_less(psession->bestrmserror,bestrmserror) ) - { - mlpimporttunableparameters(network, &psession->bestparameters, _state); - bestrmserror = psession->bestrmserror; - } - ae_shared_pool_next_recycled(sessions, &_psession, _state); - } - - /* - * Calculate errors - */ - if( s->datatype==0 ) - { - mlpallerrorssubset(network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); - } - if( s->datatype==1 ) - { - mlpallerrorssparsesubset(network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); - } - rep->relclserror = modrep.relclserror; - rep->avgce = modrep.avgce; - rep->rmserror = modrep.rmserror; - rep->avgerror = modrep.avgerror; - rep->avgrelerror = modrep.avgrelerror; - - /* - * Done - */ - ae_frame_leave(_state); - return; - } - - /* - * Split problem, if we have more than 1 restart - */ - if( nrestarts>=2 ) - { - - /* - * Divide problem with NRestarts into two: NR0 and NR1. - */ - nr0 = nrestarts/2; - nr1 = nrestarts-nr0; - mlptrain_mlptrainnetworkx(s, nr0, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep0, ae_false, sessions, _state); - mlptrain_mlptrainnetworkx(s, nr1, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep1, ae_false, sessions, _state); - - /* - * Aggregate results - */ - rep->ngrad = rep0.ngrad+rep1.ngrad; - rep->nhess = rep0.nhess+rep1.nhess; - rep->ncholesky = rep0.ncholesky+rep1.ncholesky; - - /* - * Done :) - */ - ae_frame_leave(_state); - return; - } - - /* - * Execution with NRestarts=1 or NRestarts=0: - * * NRestarts=1 means that network is restarted from random position - * * NRestarts=0 means that network is not randomized - */ - ae_assert(nrestarts==0||nrestarts==1, "MLPTrainNetworkX: internal error", _state); - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - ae_shared_pool_retrieve(sessions, &_psession, _state); - if( ((s->datatype==0||s->datatype==1)&&s->npoints>0)&&trnsubsetsize!=0 ) - { - - /* - * Train network using combination of early stopping and step-size - * and step-count based criteria. Network state with best value of - * validation set error is stored in WBuf0. When validation set is - * zero, most recent state of network is stored. - */ - rndstart = nrestarts!=0; - ngradbatch = 0; - eval = 0; - ebest = 0; - itbest = 0; - itcnt = 0; - mlptrain_mlpstarttrainingx(s, rndstart, algokind, trnsubset, trnsubsetsize, psession, _state); - if( s->datatype==0 ) - { - ebest = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); - } - if( s->datatype==1 ) - { - ebest = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); - } - ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - while(mlptrain_mlpcontinuetrainingx(s, trnsubset, trnsubsetsize, &ngradbatch, psession, _state)) - { - if( s->datatype==0 ) - { - eval = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); - } - if( s->datatype==1 ) - { - eval = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); - } - if( ae_fp_less_eq(eval,ebest)||valsubsetsize==0 ) - { - ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - ebest = eval; - itbest = itcnt; - } - if( itcnt>30&&ae_fp_greater(itcnt,1.5*itbest) ) - { - break; - } - itcnt = itcnt+1; - } - ae_v_move(&psession->network.weights.ptr.p_double[0], 1, &psession->wbuf0.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - rep->ngrad = ngradbatch; - } - else - { - for(i=0; i<=wcount-1; i++) - { - psession->network.weights.ptr.p_double[i] = 0; - } - } - - /* - * Evaluate network performance and update PSession.BestParameters/BestRMSError - * (if needed). - */ - if( s->datatype==0 ) - { - mlpallerrorssubset(&psession->network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); - } - if( s->datatype==1 ) - { - mlpallerrorssparsesubset(&psession->network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); - } - if( ae_fp_less(modrep.rmserror,psession->bestrmserror) ) - { - mlpexporttunableparameters(&psession->network, &psession->bestparameters, &pcount, _state); - psession->bestrmserror = modrep.rmserror; - } - - /* - * Move session back to pool - */ - ae_shared_pool_recycle(sessions, &_psession, _state); - ae_frame_leave(_state); -} - - -static void mlptrain_mlptrainensemblex(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t idx0, - ae_int_t idx1, - ae_int_t nrestarts, - ae_int_t trainingmethod, - sinteger* ngrad, - ae_bool isrootcall, - ae_shared_pool* esessions, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t pcount; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t trnsubsetsize; - ae_int_t valsubsetsize; - ae_int_t k0; - sinteger ngrad0; - sinteger ngrad1; - mlpetrnsession *psession; - ae_smart_ptr _psession; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - _sinteger_init(&ngrad0, _state, ae_true); - _sinteger_init(&ngrad1, _state, ae_true); - ae_smart_ptr_init(&_psession, (void**)&psession, _state, ae_true); - _hqrndstate_init(&rs, _state, ae_true); - - nin = mlpgetinputscount(&ensemble->network, _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - wcount = mlpgetweightscount(&ensemble->network, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - pcount = nin; - } - else - { - pcount = nin+nout; - } - if( nrestarts<=0 ) - { - nrestarts = 1; - } - - /* - * Handle degenerate case - */ - if( s->npoints<2 ) - { - for(i=idx0; i<=idx1-1; i++) - { - for(j=0; j<=wcount-1; j++) - { - ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; - } - for(j=0; j<=pcount-1; j++) - { - ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; - ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 1.0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Process root call - */ - if( isrootcall ) - { - - /* - * Prepare: - * * prepare MLPETrnSessions - * * fill ensemble by zeros (helps to detect errors) - */ - mlptrain_initmlpetrnsessions(&ensemble->network, s, esessions, _state); - for(i=idx0; i<=idx1-1; i++) - { - for(j=0; j<=wcount-1; j++) - { - ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; - } - for(j=0; j<=pcount-1; j++) - { - ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; - ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 0.0; - } - } - - /* - * Train in non-root mode and exit - */ - mlptrain_mlptrainensemblex(s, ensemble, idx0, idx1, nrestarts, trainingmethod, ngrad, ae_false, esessions, _state); - ae_frame_leave(_state); - return; - } - - /* - * Split problem - */ - if( idx1-idx0>=2 ) - { - k0 = (idx1-idx0)/2; - ngrad0.val = 0; - ngrad1.val = 0; - mlptrain_mlptrainensemblex(s, ensemble, idx0, idx0+k0, nrestarts, trainingmethod, &ngrad0, ae_false, esessions, _state); - mlptrain_mlptrainensemblex(s, ensemble, idx0+k0, idx1, nrestarts, trainingmethod, &ngrad1, ae_false, esessions, _state); - ngrad->val = ngrad0.val+ngrad1.val; - ae_frame_leave(_state); - return; - } - - /* - * Retrieve and prepare session - */ - ae_shared_pool_retrieve(esessions, &_psession, _state); - - /* - * Train - */ - hqrndrandomize(&rs, _state); - for(k=idx0; k<=idx1-1; k++) - { - - /* - * Split set - */ - trnsubsetsize = 0; - valsubsetsize = 0; - if( trainingmethod==0 ) - { - do - { - trnsubsetsize = 0; - valsubsetsize = 0; - for(i=0; i<=s->npoints-1; i++) - { - if( ae_fp_less(ae_randomreal(_state),0.66) ) - { - - /* - * Assign sample to training set - */ - psession->trnsubset.ptr.p_int[trnsubsetsize] = i; - trnsubsetsize = trnsubsetsize+1; - } - else - { - - /* - * Assign sample to validation set - */ - psession->valsubset.ptr.p_int[valsubsetsize] = i; - valsubsetsize = valsubsetsize+1; - } - } - } - while(!(trnsubsetsize!=0&&valsubsetsize!=0)); - } - if( trainingmethod==1 ) - { - valsubsetsize = 0; - trnsubsetsize = s->npoints; - for(i=0; i<=s->npoints-1; i++) - { - psession->trnsubset.ptr.p_int[i] = hqrnduniformi(&rs, s->npoints, _state); - } - } - - /* - * Train - */ - mlptrain_mlptrainnetworkx(s, nrestarts, -1, &psession->trnsubset, trnsubsetsize, &psession->valsubset, valsubsetsize, &psession->network, &psession->mlprep, ae_true, &psession->mlpsessions, _state); - ngrad->val = ngrad->val+psession->mlprep.ngrad; - - /* - * Save results - */ - ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); - ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &psession->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); - ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &psession->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); - } - - /* - * Recycle session - */ - ae_shared_pool_recycle(esessions, &_psession, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTrainingX call, -and then user subsequently calls MLPContinueTrainingX to perform one more -iteration of the training. - -After call to this function trainer object remembers network and is ready -to train it. However, no training is performed until first call to -MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() -will advance traing progress one iteration further. - - - -- ALGLIB -- - Copyright 13.08.2012 by Bochkanov Sergey -*************************************************************************/ -static void mlptrain_mlpstarttrainingx(mlptrainer* s, - ae_bool randomstart, - ae_int_t algokind, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - smlptrnsession* session, - ae_state *_state) -{ - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t ntype; - ae_int_t ttype; - ae_int_t i; - - - - /* - * Check parameters - */ - ae_assert(s->npoints>=0, "MLPStartTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); - ae_assert(algokind==0||algokind==-1, "MLPStartTrainingX: unexpected AlgoKind", _state); - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - if( !mlpissoftmax(&session->network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - ae_assert(ntype==ttype, "MLPStartTrainingX: internal error - type of the resulting network is not similar to network type in trainer object", _state); - mlpproperties(&session->network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPStartTrainingX: number of inputs in trainer is not equal to number of inputs in the network.", _state); - ae_assert(s->nout==nout, "MLPStartTrainingX: number of outputs in trainer is not equal to number of outputs in the network.", _state); - ae_assert(subset->cnt>=subsetsize, "MLPStartTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPStartTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1)", _state); - } - - /* - * Prepare session - */ - minlbfgssetcond(&session->optimizer, 0.0, 0.0, s->wstep, s->maxits, _state); - if( s->npoints>0&&subsetsize!=0 ) - { - if( randomstart ) - { - mlprandomize(&session->network, _state); - } - minlbfgsrestartfrom(&session->optimizer, &session->network.weights, _state); - } - else - { - for(i=0; i<=wcount-1; i++) - { - session->network.weights.ptr.p_double[i] = 0; - } - } - if( algokind==-1 ) - { - session->algoused = s->algokind; - if( s->algokind==1 ) - { - session->minibatchsize = s->minibatchsize; - } - } - else - { - session->algoused = 0; - } - hqrndrandomize(&session->generator, _state); - ae_vector_set_length(&session->rstate.ia, 15+1, _state); - ae_vector_set_length(&session->rstate.ra, 1+1, _state); - session->rstate.stage = -1; -} - - -/************************************************************************* -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTrainingX call, -and then user subsequently calls MLPContinueTrainingX to perform one more -iteration of the training. - -This function performs one more iteration of the training and returns -either True (training continues) or False (training stopped). In case True -was returned, Network weights are updated according to the current state -of the optimization progress. In case False was returned, no additional -updates is performed (previous update of the network weights moved us to -the final point, and no additional updates is needed). - -EXAMPLE: - > - > [initialize network and trainer object] - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > [visualize training progress] - > - - - -- ALGLIB -- - Copyright 13.08.2012 by Bochkanov Sergey -*************************************************************************/ -static ae_bool mlptrain_mlpcontinuetrainingx(mlptrainer* s, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_int_t* ngradbatch, - smlptrnsession* session, - ae_state *_state) -{ - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t twcount; - ae_int_t ntype; - ae_int_t ttype; - double decay; - double v; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t trnsetsize; - ae_int_t epoch; - ae_int_t minibatchcount; - ae_int_t minibatchidx; - ae_int_t cursize; - ae_int_t idx0; - ae_int_t idx1; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( session->rstate.stage>=0 ) - { - nin = session->rstate.ia.ptr.p_int[0]; - nout = session->rstate.ia.ptr.p_int[1]; - wcount = session->rstate.ia.ptr.p_int[2]; - twcount = session->rstate.ia.ptr.p_int[3]; - ntype = session->rstate.ia.ptr.p_int[4]; - ttype = session->rstate.ia.ptr.p_int[5]; - i = session->rstate.ia.ptr.p_int[6]; - j = session->rstate.ia.ptr.p_int[7]; - k = session->rstate.ia.ptr.p_int[8]; - trnsetsize = session->rstate.ia.ptr.p_int[9]; - epoch = session->rstate.ia.ptr.p_int[10]; - minibatchcount = session->rstate.ia.ptr.p_int[11]; - minibatchidx = session->rstate.ia.ptr.p_int[12]; - cursize = session->rstate.ia.ptr.p_int[13]; - idx0 = session->rstate.ia.ptr.p_int[14]; - idx1 = session->rstate.ia.ptr.p_int[15]; - decay = session->rstate.ra.ptr.p_double[0]; - v = session->rstate.ra.ptr.p_double[1]; - } - else - { - nin = -983; - nout = -989; - wcount = -834; - twcount = 900; - ntype = -287; - ttype = 364; - i = 214; - j = -338; - k = -686; - trnsetsize = 912; - epoch = 585; - minibatchcount = 497; - minibatchidx = -271; - cursize = -581; - idx0 = 745; - idx1 = -533; - decay = -77; - v = 678; - } - if( session->rstate.stage==0 ) - { - goto lbl_0; - } - - /* - * Routine body - */ - - /* - * Check correctness of inputs - */ - ae_assert(s->npoints>=0, "MLPContinueTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0).", _state); - if( s->rcpar ) - { - ttype = 0; - } - else - { - ttype = 1; - } - if( !mlpissoftmax(&session->network, _state) ) - { - ntype = 0; - } - else - { - ntype = 1; - } - ae_assert(ntype==ttype, "MLPContinueTrainingX: internal error - type of the resulting network is not similar to network type in trainer object.", _state); - mlpproperties(&session->network, &nin, &nout, &wcount, _state); - ae_assert(s->nin==nin, "MLPContinueTrainingX: internal error - number of inputs in trainer is not equal to number of inputs in the network.", _state); - ae_assert(s->nout==nout, "MLPContinueTrainingX: internal error - number of outputs in trainer is not equal to number of outputs in the network.", _state); - ae_assert(subset->cnt>=subsetsize, "MLPContinueTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPContinueTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1).", _state); - } - - /* - * Quick exit on empty training set - */ - if( s->npoints==0||subsetsize==0 ) - { - result = ae_false; - return result; - } - - /* - * Minibatch training - */ - if( session->algoused==1 ) - { - ae_assert(ae_false, "MINIBATCH TRAINING IS NOT IMPLEMENTED YET", _state); - } - - /* - * Last option: full batch training - */ - decay = s->decay; -lbl_1: - if( !minlbfgsiteration(&session->optimizer, _state) ) - { - goto lbl_2; - } - if( !session->optimizer.xupdated ) - { - goto lbl_3; - } - ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - session->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: -lbl_3: - ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - if( s->datatype==0 ) - { - mlpgradbatchsubset(&session->network, &s->densexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); - } - if( s->datatype==1 ) - { - mlpgradbatchsparsesubset(&session->network, &s->sparsexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); - } - - /* - * Increment number of operations performed on batch gradient - */ - *ngradbatch = *ngradbatch+1; - v = ae_v_dotproduct(&session->network.weights.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); - session->optimizer.f = session->optimizer.f+0.5*decay*v; - ae_v_addd(&session->optimizer.g.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); - goto lbl_1; -lbl_2: - minlbfgsresultsbuf(&session->optimizer, &session->network.weights, &session->optimizerrep, _state); - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - session->rstate.ia.ptr.p_int[0] = nin; - session->rstate.ia.ptr.p_int[1] = nout; - session->rstate.ia.ptr.p_int[2] = wcount; - session->rstate.ia.ptr.p_int[3] = twcount; - session->rstate.ia.ptr.p_int[4] = ntype; - session->rstate.ia.ptr.p_int[5] = ttype; - session->rstate.ia.ptr.p_int[6] = i; - session->rstate.ia.ptr.p_int[7] = j; - session->rstate.ia.ptr.p_int[8] = k; - session->rstate.ia.ptr.p_int[9] = trnsetsize; - session->rstate.ia.ptr.p_int[10] = epoch; - session->rstate.ia.ptr.p_int[11] = minibatchcount; - session->rstate.ia.ptr.p_int[12] = minibatchidx; - session->rstate.ia.ptr.p_int[13] = cursize; - session->rstate.ia.ptr.p_int[14] = idx0; - session->rstate.ia.ptr.p_int[15] = idx1; - session->rstate.ra.ptr.p_double[0] = decay; - session->rstate.ra.ptr.p_double[1] = v; - return result; -} - - -/************************************************************************* -Internal bagging subroutine. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_bool lmalgorithm, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix xys; - ae_vector s; - ae_matrix oobbuf; - ae_vector oobcntbuf; - ae_vector x; - ae_vector y; - ae_vector dy; - ae_vector dsbuf; - ae_int_t ccnt; - ae_int_t pcnt; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - mlpreport tmprep; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _mlpreport_clear(rep); - _mlpcvreport_clear(ooberrors); - ae_matrix_init(&xys, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&s, 0, DT_BOOL, _state, ae_true); - ae_matrix_init(&oobbuf, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&oobcntbuf, 0, DT_INT, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dsbuf, 0, DT_REAL, _state, ae_true); - _mlpreport_init(&tmprep, _state, ae_true); - _hqrndstate_init(&rs, _state, ae_true); - - nin = mlpgetinputscount(&ensemble->network, _state); - nout = mlpgetoutputscount(&ensemble->network, _state); - wcount = mlpgetweightscount(&ensemble->network, _state); - - /* - * Test for inputs - */ - if( (!lmalgorithm&&ae_fp_eq(wstep,0))&&maxits==0 ) - { - *info = -8; - ae_frame_leave(_state); - return; - } - if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,0))||maxits<0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( mlpissoftmax(&ensemble->network, _state) ) - { - for(i=0; i<=npoints-1; i++) - { - if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - } - - /* - * allocate temporaries - */ - *info = 2; - rep->ngrad = 0; - rep->nhess = 0; - rep->ncholesky = 0; - ooberrors->relclserror = 0; - ooberrors->avgce = 0; - ooberrors->rmserror = 0; - ooberrors->avgerror = 0; - ooberrors->avgrelerror = 0; - if( mlpissoftmax(&ensemble->network, _state) ) - { - ccnt = nin+1; - pcnt = nin; - } - else - { - ccnt = nin+nout; - pcnt = nin+nout; - } - ae_matrix_set_length(&xys, npoints, ccnt, _state); - ae_vector_set_length(&s, npoints, _state); - ae_matrix_set_length(&oobbuf, npoints, nout, _state); - ae_vector_set_length(&oobcntbuf, npoints, _state); - ae_vector_set_length(&x, nin, _state); - ae_vector_set_length(&y, nout, _state); - if( mlpissoftmax(&ensemble->network, _state) ) - { - ae_vector_set_length(&dy, 1, _state); - } - else - { - ae_vector_set_length(&dy, nout, _state); - } - for(i=0; i<=npoints-1; i++) - { - for(j=0; j<=nout-1; j++) - { - oobbuf.ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=npoints-1; i++) - { - oobcntbuf.ptr.p_int[i] = 0; - } - - /* - * main bagging cycle - */ - hqrndrandomize(&rs, _state); - for(k=0; k<=ensemble->ensemblesize-1; k++) - { - - /* - * prepare dataset - */ - for(i=0; i<=npoints-1; i++) - { - s.ptr.p_bool[i] = ae_false; - } - for(i=0; i<=npoints-1; i++) - { - j = hqrnduniformi(&rs, npoints, _state); - s.ptr.p_bool[j] = ae_true; - ae_v_move(&xys.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,ccnt-1)); - } - - /* - * train - */ - if( lmalgorithm ) - { - mlptrainlm(&ensemble->network, &xys, npoints, decay, restarts, info, &tmprep, _state); - } - else - { - mlptrainlbfgs(&ensemble->network, &xys, npoints, decay, restarts, wstep, maxits, info, &tmprep, _state); - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * save results - */ - rep->ngrad = rep->ngrad+tmprep.ngrad; - rep->nhess = rep->nhess+tmprep.nhess; - rep->ncholesky = rep->ncholesky+tmprep.ncholesky; - ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); - ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcnt], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); - ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcnt], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); - - /* - * OOB estimates - */ - for(i=0; i<=npoints-1; i++) - { - if( !s.ptr.p_bool[i] ) - { - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); - mlpprocess(&ensemble->network, &x, &y, _state); - ae_v_add(&oobbuf.ptr.pp_double[i][0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); - oobcntbuf.ptr.p_int[i] = oobcntbuf.ptr.p_int[i]+1; - } - } - } - - /* - * OOB estimates - */ - if( mlpissoftmax(&ensemble->network, _state) ) - { - dserrallocate(nout, &dsbuf, _state); - } - else - { - dserrallocate(-nout, &dsbuf, _state); - } - for(i=0; i<=npoints-1; i++) - { - if( oobcntbuf.ptr.p_int[i]!=0 ) - { - v = (double)1/(double)oobcntbuf.ptr.p_int[i]; - ae_v_moved(&y.ptr.p_double[0], 1, &oobbuf.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1), v); - if( mlpissoftmax(&ensemble->network, _state) ) - { - dy.ptr.p_double[0] = xy->ptr.pp_double[i][nin]; - } - else - { - ae_v_moved(&dy.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1), v); - } - dserraccumulate(&dsbuf, &y, &dy, _state); - } - } - dserrfinish(&dsbuf, _state); - ooberrors->relclserror = dsbuf.ptr.p_double[0]; - ooberrors->avgce = dsbuf.ptr.p_double[1]; - ooberrors->rmserror = dsbuf.ptr.p_double[2]; - ooberrors->avgerror = dsbuf.ptr.p_double[3]; - ooberrors->avgrelerror = dsbuf.ptr.p_double[4]; - ae_frame_leave(_state); -} - - -/************************************************************************* -This function initializes temporaries needed for training session. - - - -- ALGLIB -- - Copyright 01.07.2013 by Bochkanov Sergey -*************************************************************************/ -static void mlptrain_initmlptrnsession(multilayerperceptron* networktrained, - ae_bool randomizenetwork, - mlptrainer* trainer, - smlptrnsession* session, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t nin; - ae_int_t nout; - ae_int_t wcount; - ae_int_t pcount; - ae_vector dummysubset; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); - - - /* - * Prepare network: - * * copy input network to Session.Network - * * re-initialize preprocessor and weights if RandomizeNetwork=True - */ - mlpcopy(networktrained, &session->network, _state); - if( randomizenetwork ) - { - ae_assert(trainer->datatype==0||trainer->datatype==1, "InitTemporaries: unexpected Trainer.DataType", _state); - if( trainer->datatype==0 ) - { - mlpinitpreprocessorsubset(&session->network, &trainer->densexy, trainer->npoints, &dummysubset, -1, _state); - } - if( trainer->datatype==1 ) - { - mlpinitpreprocessorsparsesubset(&session->network, &trainer->sparsexy, trainer->npoints, &dummysubset, -1, _state); - } - mlprandomize(&session->network, _state); - session->randomizenetwork = ae_true; - } - else - { - session->randomizenetwork = ae_false; - } - - /* - * Determine network geometry and initialize optimizer - */ - mlpproperties(&session->network, &nin, &nout, &wcount, _state); - minlbfgscreate(wcount, ae_minint(wcount, trainer->lbfgsfactor, _state), &session->network.weights, &session->optimizer, _state); - minlbfgssetxrep(&session->optimizer, ae_true, _state); - - /* - * Create buffers - */ - ae_vector_set_length(&session->wbuf0, wcount, _state); - ae_vector_set_length(&session->wbuf1, wcount, _state); - - /* - * Initialize session result - */ - mlpexporttunableparameters(&session->network, &session->bestparameters, &pcount, _state); - session->bestrmserror = ae_maxrealnumber; - ae_frame_leave(_state); -} - - -/************************************************************************* -This function initializes temporaries needed for training session. - -*************************************************************************/ -static void mlptrain_initmlptrnsessions(multilayerperceptron* networktrained, - ae_bool randomizenetwork, - mlptrainer* trainer, - ae_shared_pool* sessions, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector dummysubset; - smlptrnsession t; - smlptrnsession *p; - ae_smart_ptr _p; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); - _smlptrnsession_init(&t, _state, ae_true); - ae_smart_ptr_init(&_p, (void**)&p, _state, ae_true); - - if( ae_shared_pool_is_initialized(sessions) ) - { - - /* - * Pool was already initialized. - * Clear sessions stored in the pool. - */ - ae_shared_pool_first_recycled(sessions, &_p, _state); - while(p!=NULL) - { - ae_assert(mlpsamearchitecture(&p->network, networktrained, _state), "InitMLPTrnSessions: internal consistency error", _state); - p->bestrmserror = ae_maxrealnumber; - ae_shared_pool_next_recycled(sessions, &_p, _state); - } - } - else - { - - /* - * Prepare session and seed pool - */ - mlptrain_initmlptrnsession(networktrained, randomizenetwork, trainer, &t, _state); - ae_shared_pool_set_seed(sessions, &t, sizeof(t), _smlptrnsession_init, _smlptrnsession_init_copy, _smlptrnsession_destroy, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function initializes temporaries needed for ensemble training. - -*************************************************************************/ -static void mlptrain_initmlpetrnsession(multilayerperceptron* individualnetwork, - mlptrainer* trainer, - mlpetrnsession* session, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector dummysubset; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); - - - /* - * Prepare network: - * * copy input network to Session.Network - * * re-initialize preprocessor and weights if RandomizeNetwork=True - */ - mlpcopy(individualnetwork, &session->network, _state); - mlptrain_initmlptrnsessions(individualnetwork, ae_true, trainer, &session->mlpsessions, _state); - ivectorsetlengthatleast(&session->trnsubset, trainer->npoints, _state); - ivectorsetlengthatleast(&session->valsubset, trainer->npoints, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function initializes temporaries needed for training session. - -*************************************************************************/ -static void mlptrain_initmlpetrnsessions(multilayerperceptron* individualnetwork, - mlptrainer* trainer, - ae_shared_pool* sessions, - ae_state *_state) -{ - ae_frame _frame_block; - mlpetrnsession t; - - ae_frame_make(_state, &_frame_block); - _mlpetrnsession_init(&t, _state, ae_true); - - if( !ae_shared_pool_is_initialized(sessions) ) - { - mlptrain_initmlpetrnsession(individualnetwork, trainer, &t, _state); - ae_shared_pool_set_seed(sessions, &t, sizeof(t), _mlpetrnsession_init, _mlpetrnsession_init_copy, _mlpetrnsession_destroy, _state); - } - ae_frame_leave(_state); -} - - -ae_bool _mlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpreport *p = (mlpreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _mlpreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpreport *dst = (mlpreport*)_dst; - mlpreport *src = (mlpreport*)_src; - dst->relclserror = src->relclserror; - dst->avgce = src->avgce; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->ngrad = src->ngrad; - dst->nhess = src->nhess; - dst->ncholesky = src->ncholesky; - return ae_true; -} - - -void _mlpreport_clear(void* _p) -{ - mlpreport *p = (mlpreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _mlpreport_destroy(void* _p) -{ - mlpreport *p = (mlpreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _mlpcvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpcvreport *p = (mlpcvreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _mlpcvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpcvreport *dst = (mlpcvreport*)_dst; - mlpcvreport *src = (mlpcvreport*)_src; - dst->relclserror = src->relclserror; - dst->avgce = src->avgce; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - return ae_true; -} - - -void _mlpcvreport_clear(void* _p) -{ - mlpcvreport *p = (mlpcvreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _mlpcvreport_destroy(void* _p) -{ - mlpcvreport *p = (mlpcvreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _smlptrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - smlptrnsession *p = (smlptrnsession*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->bestparameters, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_multilayerperceptron_init(&p->network, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsstate_init(&p->optimizer, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsreport_init(&p->optimizerrep, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wbuf0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wbuf1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->allminibatches, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->currentminibatch, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !_hqrndstate_init(&p->generator, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _smlptrnsession_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - smlptrnsession *dst = (smlptrnsession*)_dst; - smlptrnsession *src = (smlptrnsession*)_src; - if( !ae_vector_init_copy(&dst->bestparameters, &src->bestparameters, _state, make_automatic) ) - return ae_false; - dst->bestrmserror = src->bestrmserror; - dst->randomizenetwork = src->randomizenetwork; - if( !_multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsstate_init_copy(&dst->optimizer, &src->optimizer, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsreport_init_copy(&dst->optimizerrep, &src->optimizerrep, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wbuf0, &src->wbuf0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wbuf1, &src->wbuf1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->allminibatches, &src->allminibatches, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->currentminibatch, &src->currentminibatch, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->algoused = src->algoused; - dst->minibatchsize = src->minibatchsize; - if( !_hqrndstate_init_copy(&dst->generator, &src->generator, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _smlptrnsession_clear(void* _p) -{ - smlptrnsession *p = (smlptrnsession*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->bestparameters); - _multilayerperceptron_clear(&p->network); - _minlbfgsstate_clear(&p->optimizer); - _minlbfgsreport_clear(&p->optimizerrep); - ae_vector_clear(&p->wbuf0); - ae_vector_clear(&p->wbuf1); - ae_vector_clear(&p->allminibatches); - ae_vector_clear(&p->currentminibatch); - _rcommstate_clear(&p->rstate); - _hqrndstate_clear(&p->generator); -} - - -void _smlptrnsession_destroy(void* _p) -{ - smlptrnsession *p = (smlptrnsession*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->bestparameters); - _multilayerperceptron_destroy(&p->network); - _minlbfgsstate_destroy(&p->optimizer); - _minlbfgsreport_destroy(&p->optimizerrep); - ae_vector_destroy(&p->wbuf0); - ae_vector_destroy(&p->wbuf1); - ae_vector_destroy(&p->allminibatches); - ae_vector_destroy(&p->currentminibatch); - _rcommstate_destroy(&p->rstate); - _hqrndstate_destroy(&p->generator); -} - - -ae_bool _mlpetrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpetrnsession *p = (mlpetrnsession*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->trnsubset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->valsubset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->mlpsessions, _state, make_automatic) ) - return ae_false; - if( !_mlpreport_init(&p->mlprep, _state, make_automatic) ) - return ae_false; - if( !_multilayerperceptron_init(&p->network, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mlpetrnsession_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpetrnsession *dst = (mlpetrnsession*)_dst; - mlpetrnsession *src = (mlpetrnsession*)_src; - if( !ae_vector_init_copy(&dst->trnsubset, &src->trnsubset, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init_copy(&dst->mlpsessions, &src->mlpsessions, _state, make_automatic) ) - return ae_false; - if( !_mlpreport_init_copy(&dst->mlprep, &src->mlprep, _state, make_automatic) ) - return ae_false; - if( !_multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mlpetrnsession_clear(void* _p) -{ - mlpetrnsession *p = (mlpetrnsession*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->trnsubset); - ae_vector_clear(&p->valsubset); - ae_shared_pool_clear(&p->mlpsessions); - _mlpreport_clear(&p->mlprep); - _multilayerperceptron_clear(&p->network); -} - - -void _mlpetrnsession_destroy(void* _p) -{ - mlpetrnsession *p = (mlpetrnsession*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->trnsubset); - ae_vector_destroy(&p->valsubset); - ae_shared_pool_destroy(&p->mlpsessions); - _mlpreport_destroy(&p->mlprep); - _multilayerperceptron_destroy(&p->network); -} - - -ae_bool _mlptrainer_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlptrainer *p = (mlptrainer*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->densexy, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init(&p->sparsexy, _state, make_automatic) ) - return ae_false; - if( !_smlptrnsession_init(&p->session, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->subset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->valsubset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mlptrainer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlptrainer *dst = (mlptrainer*)_dst; - mlptrainer *src = (mlptrainer*)_src; - dst->nin = src->nin; - dst->nout = src->nout; - dst->rcpar = src->rcpar; - dst->lbfgsfactor = src->lbfgsfactor; - dst->decay = src->decay; - dst->wstep = src->wstep; - dst->maxits = src->maxits; - dst->datatype = src->datatype; - dst->npoints = src->npoints; - if( !ae_matrix_init_copy(&dst->densexy, &src->densexy, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init_copy(&dst->sparsexy, &src->sparsexy, _state, make_automatic) ) - return ae_false; - if( !_smlptrnsession_init_copy(&dst->session, &src->session, _state, make_automatic) ) - return ae_false; - dst->ngradbatch = src->ngradbatch; - if( !ae_vector_init_copy(&dst->subset, &src->subset, _state, make_automatic) ) - return ae_false; - dst->subsetsize = src->subsetsize; - if( !ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state, make_automatic) ) - return ae_false; - dst->valsubsetsize = src->valsubsetsize; - dst->algokind = src->algokind; - dst->minibatchsize = src->minibatchsize; - return ae_true; -} - - -void _mlptrainer_clear(void* _p) -{ - mlptrainer *p = (mlptrainer*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->densexy); - _sparsematrix_clear(&p->sparsexy); - _smlptrnsession_clear(&p->session); - ae_vector_clear(&p->subset); - ae_vector_clear(&p->valsubset); -} - - -void _mlptrainer_destroy(void* _p) -{ - mlptrainer *p = (mlptrainer*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->densexy); - _sparsematrix_destroy(&p->sparsexy); - _smlptrnsession_destroy(&p->session); - ae_vector_destroy(&p->subset); - ae_vector_destroy(&p->valsubset); -} - - -ae_bool _mlpparallelizationcv_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mlpparallelizationcv *p = (mlpparallelizationcv*)_p; - ae_touch_ptr((void*)p); - if( !_multilayerperceptron_init(&p->network, _state, make_automatic) ) - return ae_false; - if( !_mlpreport_init(&p->rep, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->subset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_shared_pool_init(&p->trnpool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mlpparallelizationcv_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mlpparallelizationcv *dst = (mlpparallelizationcv*)_dst; - mlpparallelizationcv *src = (mlpparallelizationcv*)_src; - if( !_multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic) ) - return ae_false; - if( !_mlpreport_init_copy(&dst->rep, &src->rep, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->subset, &src->subset, _state, make_automatic) ) - return ae_false; - dst->subsetsize = src->subsetsize; - if( !ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - dst->ngrad = src->ngrad; - if( !ae_shared_pool_init_copy(&dst->trnpool, &src->trnpool, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mlpparallelizationcv_clear(void* _p) -{ - mlpparallelizationcv *p = (mlpparallelizationcv*)_p; - ae_touch_ptr((void*)p); - _multilayerperceptron_clear(&p->network); - _mlpreport_clear(&p->rep); - ae_vector_clear(&p->subset); - ae_vector_clear(&p->xyrow); - ae_vector_clear(&p->y); - ae_shared_pool_clear(&p->trnpool); -} - - -void _mlpparallelizationcv_destroy(void* _p) -{ - mlpparallelizationcv *p = (mlpparallelizationcv*)_p; - ae_touch_ptr((void*)p); - _multilayerperceptron_destroy(&p->network); - _mlpreport_destroy(&p->rep); - ae_vector_destroy(&p->subset); - ae_vector_destroy(&p->xyrow); - ae_vector_destroy(&p->y); - ae_shared_pool_destroy(&p->trnpool); -} - - - - -/************************************************************************* -Principal components analysis - -Subroutine builds orthogonal basis where first axis corresponds to -direction with maximum variance, second axis maximizes variance in subspace -orthogonal to first axis and so on. - -It should be noted that, unlike LDA, PCA does not use class labels. - -INPUT PARAMETERS: - X - dataset, array[0..NPoints-1,0..NVars-1]. - matrix contains ONLY INDEPENDENT VARIABLES. - NPoints - dataset size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - -ÂÛÕÎÄÍÛÅ ÏÀÐÀÌÅÒÐÛ: - Info - return code: - * -4, if SVD subroutine haven't converged - * -1, if wrong parameters has been passed (NPoints<0, - NVars<1) - * 1, if task is solved - S2 - array[0..NVars-1]. variance values corresponding - to basis vectors. - V - array[0..NVars-1,0..NVars-1] - matrix, whose columns store basis vectors. - - -- ALGLIB -- - Copyright 25.08.2008 by Bochkanov Sergey -*************************************************************************/ -void pcabuildbasis(/* Real */ ae_matrix* x, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* s2, - /* Real */ ae_matrix* v, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix a; - ae_matrix u; - ae_matrix vt; - ae_vector m; - ae_vector t; - ae_int_t i; - ae_int_t j; - double mean; - double variance; - double skewness; - double kurtosis; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(s2); - ae_matrix_clear(v); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&m, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - - /* - * Check input data - */ - if( npoints<0||nvars<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Special case: NPoints=0 - */ - if( npoints==0 ) - { - ae_vector_set_length(s2, nvars-1+1, _state); - ae_matrix_set_length(v, nvars-1+1, nvars-1+1, _state); - for(i=0; i<=nvars-1; i++) - { - s2->ptr.p_double[i] = 0; - } - for(i=0; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - if( i==j ) - { - v->ptr.pp_double[i][j] = 1; - } - else - { - v->ptr.pp_double[i][j] = 0; - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * Calculate means - */ - ae_vector_set_length(&m, nvars-1+1, _state); - ae_vector_set_length(&t, npoints-1+1, _state); - for(j=0; j<=nvars-1; j++) - { - ae_v_move(&t.ptr.p_double[0], 1, &x->ptr.pp_double[0][j], x->stride, ae_v_len(0,npoints-1)); - samplemoments(&t, npoints, &mean, &variance, &skewness, &kurtosis, _state); - m.ptr.p_double[j] = mean; - } - - /* - * Center, apply SVD, prepare output - */ - ae_matrix_set_length(&a, ae_maxint(npoints, nvars, _state)-1+1, nvars-1+1, _state); - for(i=0; i<=npoints-1; i++) - { - ae_v_move(&a.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); - ae_v_sub(&a.ptr.pp_double[i][0], 1, &m.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); - } - for(i=npoints; i<=nvars-1; i++) - { - for(j=0; j<=nvars-1; j++) - { - a.ptr.pp_double[i][j] = 0; - } - } - if( !rmatrixsvd(&a, ae_maxint(npoints, nvars, _state), nvars, 0, 1, 2, s2, &u, &vt, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - if( npoints!=1 ) - { - for(i=0; i<=nvars-1; i++) - { - s2->ptr.p_double[i] = ae_sqr(s2->ptr.p_double[i], _state)/(npoints-1); - } - } - ae_matrix_set_length(v, nvars-1+1, nvars-1+1, _state); - copyandtranspose(&vt, 0, nvars-1, 0, nvars-1, v, 0, nvars-1, 0, nvars-1, _state); - ae_frame_leave(_state); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "dataanalysis.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Principal components analysis + +This function builds orthogonal basis where first axis corresponds to +direction with maximum variance, second axis maximizes variance in the +subspace orthogonal to first axis and so on. + +This function builds FULL basis, i.e. returns N vectors corresponding to +ALL directions, no matter how informative. If you need just a few (say, +10 or 50) of the most important directions, you may find it faster to use +one of the reduced versions: +* pcatruncatedsubspace() - for subspace iteration based method + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[NPoints,NVars]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + +OUTPUT PARAMETERS: + S2 - array[NVars]. variance values corresponding + to basis vectors. + V - array[NVars,NVars] + matrix, whose columns store basis vectors. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 25.08.2008 by Bochkanov Sergey +*************************************************************************/ +void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, real_1d_array &s2, real_2d_array &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pcabuildbasis(x.c_ptr(), npoints, nvars, s2.c_ptr(), v.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Principal components analysis + +This function builds orthogonal basis where first axis corresponds to +direction with maximum variance, second axis maximizes variance in the +subspace orthogonal to first axis and so on. + +This function builds FULL basis, i.e. returns N vectors corresponding to +ALL directions, no matter how informative. If you need just a few (say, +10 or 50) of the most important directions, you may find it faster to use +one of the reduced versions: +* pcatruncatedsubspace() - for subspace iteration based method + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[NPoints,NVars]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + +OUTPUT PARAMETERS: + S2 - array[NVars]. variance values corresponding + to basis vectors. + V - array[NVars,NVars] + matrix, whose columns store basis vectors. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 25.08.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void pcabuildbasis(const real_2d_array &x, real_1d_array &s2, real_2d_array &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + + npoints = x.rows(); + nvars = x.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pcabuildbasis(x.c_ptr(), npoints, nvars, s2.c_ptr(), v.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Principal components analysis + +This function performs truncated PCA, i.e. returns just a few most important +directions. + +Internally it uses iterative eigensolver which is very efficient when only +a minor fraction of full basis is required. Thus, if you need full basis, +it is better to use pcabuildbasis() function. + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[0..NPoints-1,0..NVars-1]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<1) + * -1, incorrect pararemets were passed (N<=0). + * 1, OK + Threshold- partiton boundary. Left part contains values which are + strictly less than Threshold. Right part contains values + which are greater than or equal to Threshold. + PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) + CVE - cross-validation estimate of cross-entropy + + -- ALGLIB -- + Copyright 22.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dsoptimalsplit2(a.c_ptr(), c.c_ptr(), n, &info, &threshold, &pal, &pbl, &par, &pbr, &cve, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Optimal partition, internal subroutine. Fast version. + +Accepts: + A array[0..N-1] array of attributes array[0..N-1] + C array[0..N-1] array of class labels + TiesBuf array[0..N] temporaries (ties) + CntBuf array[0..2*NC-1] temporaries (counts) + Alpha centering factor (0<=alpha<=1, recommended value - 0.05) + BufR array[0..N-1] temporaries + BufI array[0..N-1] temporaries + +Output: + Info error code (">0"=OK, "<0"=bad) + RMS training set RMS error + CVRMS leave-one-out RMS error + +Note: + content of all arrays is changed by subroutine; + it doesn't allocate temporaries. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dsoptimalsplit2fast(a.c_ptr(), c.c_ptr(), tiesbuf.c_ptr(), cntbuf.c_ptr(), bufr.c_ptr(), bufi.c_ptr(), n, nc, alpha, &info, &threshold, &rms, &cvrms, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void mlpserialize(const multilayerperceptron &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::mlpalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::mlpserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void mlpserialize(const multilayerperceptron &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::mlpalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::mlpserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void mlpunserialize(const std::string &s_in, multilayerperceptron &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::mlpunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void mlpunserialize(const std::istream &s_in, multilayerperceptron &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::mlpunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers, with linear output layer. Network weights are filled with small +random values. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreate0(nin, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreate0, but with one hidden layer (NHid neurons) with +non-linear activation function. Output layer is linear. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreate1(nin, nhid, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) +with non-linear activation function. Output layer is linear. + $ALL + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreate2(nin, nhid1, nhid2, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. + +Activation function of the output layer takes values: + + (B, +INF), if D>=0 + +or + + (-INF, B), if D<0. + + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreateb0(nin, nout, b, d, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateB0 but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreateb1(nin, nhid, nout, b, d, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateB0 but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreateb2(nin, nhid1, nhid2, nout, b, d, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. Activation function of the output layer takes values [A,B]. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreater0(nin, nout, a, b, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateR0, but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreater1(nin, nhid, nout, a, b, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateR0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreater2(nin, nhid1, nhid2, nout, a, b, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creates classifier network with NIn inputs and NOut possible classes. +Network contains no hidden layers and linear output layer with SOFTMAX- +normalization (so outputs sums up to 1.0 and converge to posterior +probabilities). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreatec0(nin, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateC0, but with one non-linear hidden layer. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreatec1(nin, nhid, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as MLPCreateC0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreatec2(nin, nhid1, nhid2, nout, network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Copying of neural network + +INPUT PARAMETERS: + Network1 - original + +OUTPUT PARAMETERS: + Network2 - copy + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcopy(const multilayerperceptron &network1, multilayerperceptron &network2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcopy(network1.c_ptr(), network2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function copies tunable parameters (weights/means/sigmas) from one +network to another with same architecture. It performs some rudimentary +checks that architectures are same, and throws exception if check fails. + +It is intended for fast copying of states between two network which are +known to have same geometry. + +INPUT PARAMETERS: + Network1 - source, must be correctly initialized + Network2 - target, must have same architecture + +OUTPUT PARAMETERS: + Network2 - network state is copied from source to target + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +void mlpcopytunableparameters(const multilayerperceptron &network1, multilayerperceptron &network2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcopytunableparameters(network1.c_ptr(), network2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Randomization of neural network weights + + -- ALGLIB -- + Copyright 06.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlprandomize(multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlprandomize(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Randomization of neural network weights and standartisator + + -- ALGLIB -- + Copyright 10.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlprandomizefull(multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlprandomizefull(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Internal subroutine. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessor(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpinitpreprocessor(network.c_ptr(), xy.c_ptr(), ssize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns information about initialized network: number of inputs, outputs, +weights. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpproperties(network.c_ptr(), &nin, &nout, &wcount, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns number of inputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetinputscount(const multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpgetinputscount(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Returns number of outputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetoutputscount(const multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpgetoutputscount(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Returns number of weights. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetweightscount(const multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpgetweightscount(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +bool mlpissoftmax(const multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mlpissoftmax(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +This function returns total number of layers (including input, hidden and +output layers). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayerscount(const multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpgetlayerscount(network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function returns size of K-th layer. + +K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. + +Size of the output layer is always equal to the number of outputs, although +when we have softmax-normalized network, last neuron doesn't have any +connections - it is just zero. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpgetlayersize(network.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function returns offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgetinputscaling(network.c_ptr(), i, &mean, &sigma, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. In case we have SOFTMAX-normalized network, +we return (Mean,Sigma)=(0.0,1.0). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgetoutputscaling(network.c_ptr(), i, &mean, &sigma, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + +OUTPUT PARAMETERS: + FKind - activation function type (used by MLPActivationFunction()) + this value is zero for input or linear neurons + Threshold - also called offset, bias + zero for input neurons + +NOTE: this function throws exception if layer or neuron with given index +do not exists. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetneuroninfo(multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgetneuroninfo(network.c_ptr(), k, i, &fkind, &threshold, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + +RESULT: + connection weight (zero for non-existent connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. returns zero if neurons exist, but there is no connection between them + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +double mlpgetweight(multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpgetweight(network.c_ptr(), k0, i0, k1, i1, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function sets offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +NTE: I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network. This function sets Mean and Sigma. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetinputscaling(multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetinputscaling(network.c_ptr(), i, mean, sigma, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +OUTPUT PARAMETERS: + +NOTE: I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. This function sets Sigma/Mean. In case we +have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything +other than(0.0,1.0) - this function will throw exception. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetoutputscaling(multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetoutputscaling(network.c_ptr(), i, mean, sigma, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function modifies information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + FKind - activation function type (used by MLPActivationFunction()) + this value must be zero for input neurons + (you can not set activation function for input neurons) + Threshold - also called offset, bias + this value must be zero for input neurons + (you can not set threshold for input neurons) + +NOTES: +1. this function throws exception if layer or neuron with given index do + not exists. +2. this function also throws exception when you try to set non-linear + activation function for input neurons (any kind of network) or for output + neurons of classifier network. +3. this function throws exception when you try to set non-zero threshold for + input neurons (any kind of network). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetneuroninfo(multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetneuroninfo(network.c_ptr(), k, i, fkind, threshold, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function modifies information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + W - connection weight (must be zero for non-existent + connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. throws exception if you try to set non-zero weight for non-existent + connection + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetweight(multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetweight(network.c_ptr(), k0, i0, k1, i1, w, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Neural network activation function + +INPUT PARAMETERS: + NET - neuron input + K - function index (zero for linear function) + +OUTPUT PARAMETERS: + F - function + DF - its derivative + D2F - its second derivative + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpactivationfunction(net, k, &f, &df, &d2f, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Network - neural network + X - input vector, array[0..NIn-1]. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also MLPProcessI + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpprocess(multilayerperceptron &network, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpprocess(network.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +'interactive' variant of MLPProcess for languages like Python which +support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 21.09.2010 by Bochkanov Sergey +*************************************************************************/ +void mlpprocessi(multilayerperceptron &network, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpprocessi(network.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Error of the neural network on dataset given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0 + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperrorsparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Natural error function for neural network, internal subroutine. + +NOTE: this function is single-threaded. Unlike other error function, it +receives no speed-up from being executed in SMP mode. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperrorn(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperrorn(network.c_ptr(), xy.c_ptr(), ssize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Classification error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + classification error (number of misclassified cases) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpclserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::mlpclserror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Relative classification error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 25.12.2008 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlprelclserror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Relative classification error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. Sparse matrix must use CRS format + for storage. + NPoints - points count, >=0. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlprelclserrorsparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 08.01.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpavgce(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgce(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set given by +sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 9.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgcesparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgcesparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set given. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlprmserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlprmserror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprmserrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlprmserrorsparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average absolute error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgerror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average absolute error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgerrorsparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average relative error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgrelerror(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average relative error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpavgrelerrorsparse(network.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Gradient calculation + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgrad(multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgrad(network.c_ptr(), x.c_ptr(), desiredy.c_ptr(), &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Gradient calculation (natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradn(multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradn(network.c_ptr(), x.c_ptr(), desiredy.c_ptr(), &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradbatch(network.c_ptr(), xy.c_ptr(), ssize, &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs given by sparse +matrices + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs. + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradbatchsparse(network.c_ptr(), xy.c_ptr(), ssize, &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch gradient calculation for a subset of dataset + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradbatchsubset(network.c_ptr(), xy.c_ptr(), setsize, idx.c_ptr(), subsetsize, &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs for a subset of +dataset given by set of indexes. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + +NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse + function. + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradbatchsparsesubset(network.c_ptr(), xy.c_ptr(), setsize, idx.c_ptr(), subsetsize, &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs +(natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - set of inputs/outputs; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradnbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpgradnbatch(network.c_ptr(), xy.c_ptr(), ssize, &e, grad.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch Hessian calculation (natural error function) using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessiannbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlphessiannbatch(network.c_ptr(), xy.c_ptr(), ssize, &e, grad.c_ptr(), h.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Batch Hessian calculation using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessianbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlphessianbatch(network.c_ptr(), xy.c_ptr(), ssize, &e, grad.c_ptr(), h.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpallerrorssubset(network.c_ptr(), xy.c_ptr(), setsize, subset.c_ptr(), subsetsize, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset given by sparse matrix; + one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpallerrorssparsesubset(network.c_ptr(), xy.c_ptr(), setsize, subset.c_ptr(), subsetsize, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Error of the neural network on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperrorsubset(network.c_ptr(), xy.c_ptr(), setsize, subset.c_ptr(), subsetsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Error of the neural network on subset of sparse dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + SetSize - real size of XY, SetSize>=0; + it is used when SubsetSize<0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperrorsparsesubset(network.c_ptr(), xy.c_ptr(), setsize, subset.c_ptr(), subsetsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + + +/************************************************************************* +Model's errors: + * RelCLSError - fraction of misclassified cases. + * AvgCE - acerage cross-entropy + * RMSError - root-mean-square error + * AvgError - average error + * AvgRelError - average relative error + +NOTE 1: RelCLSError/AvgCE are zero on regression problems. + +NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain + errors in prediction of posterior probabilities +*************************************************************************/ +_modelerrors_owner::_modelerrors_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_modelerrors_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), &_state); + memset(p_struct, 0, sizeof(alglib_impl::modelerrors)); + alglib_impl::_modelerrors_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_modelerrors_owner::_modelerrors_owner(alglib_impl::modelerrors *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_modelerrors_owner::_modelerrors_owner(const _modelerrors_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_modelerrors_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: modelerrors copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::modelerrors*)alglib_impl::ae_malloc(sizeof(alglib_impl::modelerrors), &_state); + memset(p_struct, 0, sizeof(alglib_impl::modelerrors)); + alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_modelerrors_owner& _modelerrors_owner::operator=(const _modelerrors_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: modelerrors assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: modelerrors assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: modelerrors assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_modelerrors_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::modelerrors)); + alglib_impl::_modelerrors_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_modelerrors_owner::~_modelerrors_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_modelerrors_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::modelerrors* _modelerrors_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::modelerrors* _modelerrors_owner::c_ptr() const +{ + return p_struct; +} +modelerrors::modelerrors() : _modelerrors_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +modelerrors::modelerrors(alglib_impl::modelerrors *attach_to):_modelerrors_owner(attach_to) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +modelerrors::modelerrors(const modelerrors &rhs):_modelerrors_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +modelerrors& modelerrors::operator=(const modelerrors &rhs) +{ + if( this==&rhs ) + return *this; + _modelerrors_owner::operator=(rhs); + return *this; +} + +modelerrors::~modelerrors() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_multilayerperceptron_owner::_multilayerperceptron_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_multilayerperceptron_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), &_state); + memset(p_struct, 0, sizeof(alglib_impl::multilayerperceptron)); + alglib_impl::_multilayerperceptron_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_multilayerperceptron_owner::_multilayerperceptron_owner(alglib_impl::multilayerperceptron *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_multilayerperceptron_owner::_multilayerperceptron_owner(const _multilayerperceptron_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_multilayerperceptron_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: multilayerperceptron copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::multilayerperceptron*)alglib_impl::ae_malloc(sizeof(alglib_impl::multilayerperceptron), &_state); + memset(p_struct, 0, sizeof(alglib_impl::multilayerperceptron)); + alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_multilayerperceptron_owner& _multilayerperceptron_owner::operator=(const _multilayerperceptron_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: multilayerperceptron assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: multilayerperceptron assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: multilayerperceptron assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_multilayerperceptron_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::multilayerperceptron)); + alglib_impl::_multilayerperceptron_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_multilayerperceptron_owner::~_multilayerperceptron_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_multilayerperceptron_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::multilayerperceptron* _multilayerperceptron_owner::c_ptr() const +{ + return p_struct; +} +multilayerperceptron::multilayerperceptron() : _multilayerperceptron_owner() +{ +} + +multilayerperceptron::multilayerperceptron(alglib_impl::multilayerperceptron *attach_to):_multilayerperceptron_owner(attach_to) +{ +} + +multilayerperceptron::multilayerperceptron(const multilayerperceptron &rhs):_multilayerperceptron_owner(rhs) +{ +} + +multilayerperceptron& multilayerperceptron::operator=(const multilayerperceptron &rhs) +{ + if( this==&rhs ) + return *this; + _multilayerperceptron_owner::operator=(rhs); + return *this; +} + +multilayerperceptron::~multilayerperceptron() +{ +} +#endif + +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void mlpeserialize(const mlpensemble &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::mlpealloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::mlpeserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void mlpeserialize(const mlpensemble &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::mlpealloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::mlpeserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void mlpeunserialize(const std::string &s_in, mlpensemble &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::mlpeunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void mlpeunserialize(const std::istream &s_in, mlpensemble &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::mlpeunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +Like MLPCreate0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreate0(nin, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreate1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreate1(nin, nhid, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreate2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreate2(nin, nhid1, nhid2, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateB0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreateb0(nin, nout, b, d, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateB1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreateb1(nin, nhid, nout, b, d, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateB2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreateb2(nin, nhid1, nhid2, nout, b, d, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateR0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreater0(nin, nout, a, b, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateR1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreater1(nin, nhid, nout, a, b, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateR2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreater2(nin, nhid1, nhid2, nout, a, b, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateC0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreatec0(nin, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateC1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreatec1(nin, nhid, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like MLPCreateC2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreatec2(nin, nhid1, nhid2, nout, ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creates ensemble from network. Only network geometry is copied. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpecreatefromnetwork(network.c_ptr(), ensemblesize, ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Randomization of MLP ensemble + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlperandomize(mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlperandomize(ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Return ensemble properties (number of inputs and outputs). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpeproperties(ensemble.c_ptr(), &nin, &nout, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Return normalization type (whether ensemble is SOFTMAX-normalized or not). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +bool mlpeissoftmax(const mlpensemble &ensemble, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mlpeissoftmax(ensemble.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Ensemble- neural networks ensemble + X - input vector, array[0..NIn-1]. + Y - (possibly) preallocated buffer; if size of Y is less than + NOut, it will be reallocated. If it is large enough, it + is NOT reallocated, so we can save some time on reallocation. + + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocess(mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpeprocess(ensemble.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +'interactive' variant of MLPEProcess for languages like Python which +support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocessi(mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpeprocessi(ensemble.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Works both for classifier betwork and for regression networks which +are used as classifiers. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlperelclserror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlperelclserror(ensemble.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if ensemble solves regression task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgce(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpeavgce(ensemble.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for classification task +RMS error means error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpermserror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpermserror(ensemble.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgerror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpeavgerror(ensemble.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average relative error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgrelerror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::mlpeavgrelerror(ensemble.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + + +/************************************************************************* +Neural networks ensemble +*************************************************************************/ +_mlpensemble_owner::_mlpensemble_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpensemble_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpensemble)); + alglib_impl::_mlpensemble_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpensemble_owner::_mlpensemble_owner(alglib_impl::mlpensemble *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mlpensemble_owner::_mlpensemble_owner(const _mlpensemble_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpensemble_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpensemble copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mlpensemble*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpensemble), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpensemble)); + alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpensemble_owner& _mlpensemble_owner::operator=(const _mlpensemble_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mlpensemble assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpensemble assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mlpensemble assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mlpensemble_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mlpensemble)); + alglib_impl::_mlpensemble_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mlpensemble_owner::~_mlpensemble_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mlpensemble_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mlpensemble* _mlpensemble_owner::c_ptr() const +{ + return p_struct; +} +mlpensemble::mlpensemble() : _mlpensemble_owner() +{ +} + +mlpensemble::mlpensemble(alglib_impl::mlpensemble *attach_to):_mlpensemble_owner(attach_to) +{ +} + +mlpensemble::mlpensemble(const mlpensemble &rhs):_mlpensemble_owner(rhs) +{ +} + +mlpensemble& mlpensemble::operator=(const mlpensemble &rhs) +{ + if( this==&rhs ) + return *this; + _mlpensemble_owner::operator=(rhs); + return *this; +} + +mlpensemble::~mlpensemble() +{ +} +#endif + +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes clusterizer object. Newly initialized object is +empty, i.e. it does not contain dataset. You should use it as follows: +1. creation +2. dataset is added with ClusterizerSetPoints() +3. additional parameters are set +3. clusterization is performed with one of the clustering functions + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizercreate(clusterizerstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizercreate(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset to the clusterizer structure. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm), non-squared + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +NOTE 1: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + +NOTE 2: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric + * k-means++ clustering algorithm may be used only with Euclidean + distance function + Thus, list of specific clustering algorithms you may use depends + on distance function you specify when you set your dataset. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetpoints(clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetpoints(s.c_ptr(), xy.c_ptr(), npoints, nfeatures, disttype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset to the clusterizer structure. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm), non-squared + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +NOTE 1: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + +NOTE 2: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric + * k-means++ clustering algorithm may be used only with Euclidean + distance function + Thus, list of specific clustering algorithms you may use depends + on distance function you specify when you set your dataset. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void clusterizersetpoints(clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nfeatures; + + npoints = xy.rows(); + nfeatures = xy.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetpoints(s.c_ptr(), xy.c_ptr(), npoints, nfeatures, disttype, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function adds dataset given by distance matrix to the clusterizer +structure. It is important that dataset is not given explicitly - only +distance matrix is given. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + D - array[NPoints,NPoints], distance matrix given by its upper + or lower triangle (main diagonal is ignored because its + entries are expected to be zero). + NPoints - number of points + IsUpper - whether upper or lower triangle of D is given. + +NOTE 1: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric, including one which is given by + distance matrix + * k-means++ clustering algorithm may be used only with Euclidean + distance function and explicitly given points - it can not be + used with dataset given by distance matrix + Thus, if you call this function, you will be unable to use k-means + clustering algorithm to process your problem. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetdistances(clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetdistances(s.c_ptr(), d.c_ptr(), npoints, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset given by distance matrix to the clusterizer +structure. It is important that dataset is not given explicitly - only +distance matrix is given. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + D - array[NPoints,NPoints], distance matrix given by its upper + or lower triangle (main diagonal is ignored because its + entries are expected to be zero). + NPoints - number of points + IsUpper - whether upper or lower triangle of D is given. + +NOTE 1: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric, including one which is given by + distance matrix + * k-means++ clustering algorithm may be used only with Euclidean + distance function and explicitly given points - it can not be + used with dataset given by distance matrix + Thus, if you call this function, you will be unable to use k-means + clustering algorithm to process your problem. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void clusterizersetdistances(clusterizerstate &s, const real_2d_array &d, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + if( (d.rows()!=d.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'clusterizersetdistances': looks like one of arguments has wrong size"); + npoints = d.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetdistances(s.c_ptr(), d.c_ptr(), npoints, isupper, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets agglomerative hierarchical clustering algorithm + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Algo - algorithm type: + * 0 complete linkage (default algorithm) + * 1 single linkage + * 2 unweighted average linkage + * 3 weighted average linkage + * 4 Ward's method + +NOTE: Ward's method works correctly only with Euclidean distance, that's + why algorithm will return negative termination code (failure) for + any other distance type. + + It is possible, however, to use this method with user-supplied + distance matrix. It is your responsibility to pass one which was + calculated with Euclidean distance function. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetahcalgo(clusterizerstate &s, const ae_int_t algo, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetahcalgo(s.c_ptr(), algo, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets k-means properties: number of restarts and maximum +number of iterations per one run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Restarts- restarts count, >=1. + k-means++ algorithm performs several restarts and chooses + best set of centers (one with minimum squared distance). + MaxIts - maximum number of k-means iterations performed during one + run. >=0, zero value means that algorithm performs unlimited + number of iterations. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeanslimits(clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetkmeanslimits(s.c_ptr(), restarts, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets k-means initialization algorithm. Several different +algorithms can be chosen, including k-means++. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + InitAlgo- initialization algorithm: + * 0 automatic selection ( different versions of ALGLIB + may select different algorithms) + * 1 random initialization + * 2 k-means++ initialization (best quality of initial + centers, but long non-parallelizable initialization + phase with bad cache locality) + * 3 "fast-greedy" algorithm with efficient, easy to + parallelize initialization. Quality of initial centers + is somewhat worse than that of k-means++. This + algorithm is a default one in the current version of + ALGLIB. + *-1 "debug" algorithm which always selects first K rows + of dataset; this algorithm is used for debug purposes + only. Do not use it in the industrial code! + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeansinit(clusterizerstate &s, const ae_int_t initalgo, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetkmeansinit(s.c_ptr(), initalgo, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets seed which is used to initialize internal RNG. By +default, deterministic seed is used - same for each run of clusterizer. If +you specify non-deterministic seed value, then some algorithms which +depend on random initialization (in current version: k-means) may return +slightly different results after each run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetseed(clusterizerstate &s, const ae_int_t seed, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizersetseed(s.c_ptr(), seed, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function performs agglomerative hierarchical clustering + +NOTE: Agglomerative hierarchical clustering algorithm has two phases: + distance matrix calculation and clustering itself. Only first phase + (distance matrix calculation) is accelerated by SIMD and SMP. Thus, + acceleration is significant only for medium or high-dimensional + problems. + + Although activating multithreading gives some speedup over single- + threaded execution, you should not expect nearly-linear scaling + with respect to cores count. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + +OUTPUT PARAMETERS: + Rep - clustering results; see description of AHCReport + structure for more information. + +NOTE 1: hierarchical clustering algorithms require large amounts of memory. + In particular, this implementation needs sizeof(double)*NPoints^2 + bytes, which are used to store distance matrix. In case we work + with user-supplied matrix, this amount is multiplied by 2 (we have + to store original matrix and to work with its copy). + + For example, problem with 10000 points would require 800M of RAM, + even when working in a 1-dimensional space. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunahc(clusterizerstate &s, ahcreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizerrunahc(s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function performs clustering by k-means++ algorithm. + +You may change algorithm properties by calling: +* ClusterizerSetKMeansLimits() to change number of restarts or iterations +* ClusterizerSetKMeansInit() to change initialization algorithm + +By default, one restart and unlimited number of iterations are used. +Initialization algorithm is chosen automatically. + +NOTE: k-means clustering algorithm has two phases: selection of initial + centers and clustering itself. ALGLIB parallelizes both phases. + Parallel version is optimized for the following scenario: medium or + high-dimensional problem (8 or more dimensions) with large number of + points and clusters. However, some speed-up can be obtained even + when assumptions above are violated. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + K - number of clusters, K>=0. + K can be zero only when algorithm is called for empty + dataset, in this case completion code is set to + success (+1). + If K=0 and dataset size is non-zero, we can not + meaningfully assign points to some center (there are no + centers because K=0) and return -3 as completion code + (failure). + +OUTPUT PARAMETERS: + Rep - clustering results; see description of KMeansReport + structure for more information. + +NOTE 1: k-means clustering can be performed only for datasets with + Euclidean distance function. Algorithm will return negative + completion code in Rep.TerminationType in case dataset was added + to clusterizer with DistType other than Euclidean (or dataset was + specified by distance matrix instead of explicitly given points). + +NOTE 2: by default, k-means uses non-deterministic seed to initialize RNG + which is used to select initial centers. As result, each run of + algorithm may return different values. If you need deterministic + behavior, use ClusterizerSetSeed() function. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunkmeans(clusterizerstate &s, const ae_int_t k, kmeansreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizerrunkmeans(s.c_ptr(), k, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns distance matrix for dataset + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm, non-squared) + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +OUTPUT PARAMETERS: + D - array[NPoints,NPoints], distance matrix + (full matrix is returned, with lower and upper triangles) + +NOTE: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::clusterizergetdistances(xy.c_ptr(), npoints, nfeatures, disttype, d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function takes as input clusterization report Rep, desired clusters +count K, and builds top K clusters from hierarchical clusterization tree. +It returns assignment of points to clusters (array of cluster indexes). + +INPUT PARAMETERS: + Rep - report from ClusterizerRunAHC() performed on XY + K - desired number of clusters, 1<=K<=NPoints. + K can be zero only when NPoints=0. + +OUTPUT PARAMETERS: + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]=0 + +OUTPUT PARAMETERS: + K - number of clusters, 1<=K<=NPoints + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I](rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_clusterizerstate_owner& _clusterizerstate_owner::operator=(const _clusterizerstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: clusterizerstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: clusterizerstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: clusterizerstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_clusterizerstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::clusterizerstate)); + alglib_impl::_clusterizerstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_clusterizerstate_owner::~_clusterizerstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_clusterizerstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::clusterizerstate* _clusterizerstate_owner::c_ptr() const +{ + return p_struct; +} +clusterizerstate::clusterizerstate() : _clusterizerstate_owner() +{ +} + +clusterizerstate::clusterizerstate(alglib_impl::clusterizerstate *attach_to):_clusterizerstate_owner(attach_to) +{ +} + +clusterizerstate::clusterizerstate(const clusterizerstate &rhs):_clusterizerstate_owner(rhs) +{ +} + +clusterizerstate& clusterizerstate::operator=(const clusterizerstate &rhs) +{ + if( this==&rhs ) + return *this; + _clusterizerstate_owner::operator=(rhs); + return *this; +} + +clusterizerstate::~clusterizerstate() +{ +} + + + + +/************************************************************************* +This structure is used to store results of the agglomerative hierarchical +clustering (AHC). + +Following information is returned: + +* TerminationType - completion code: + * 1 for successful completion of algorithm + * -5 inappropriate combination of clustering algorithm and distance + function was used. As for now, it is possible only when Ward's + method is called for dataset with non-Euclidean distance function. + In case negative completion code is returned, other fields of report + structure are invalid and should not be used. + +* NPoints contains number of points in the original dataset + +* Z contains information about merges performed (see below). Z contains + indexes from the original (unsorted) dataset and it can be used when you + need to know what points were merged. However, it is not convenient when + you want to build a dendrograd (see below). + +* if you want to build dendrogram, you can use Z, but it is not good + option, because Z contains indexes from unsorted dataset. Dendrogram + built from such dataset is likely to have intersections. So, you have to + reorder you points before building dendrogram. + Permutation which reorders point is returned in P. Another representation + of merges, which is more convenient for dendorgram construction, is + returned in PM. + +* more information on format of Z, P and PM can be found below and in the + examples from ALGLIB Reference Manual. + +FORMAL DESCRIPTION OF FIELDS: + NPoints number of points + Z array[NPoints-1,2], contains indexes of clusters + linked in pairs to form clustering tree. I-th row + corresponds to I-th merge: + * Z[I,0] - index of the first cluster to merge + * Z[I,1] - index of the second cluster to merge + * Z[I,0](rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_ahcreport_owner& _ahcreport_owner::operator=(const _ahcreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: ahcreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: ahcreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: ahcreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_ahcreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::ahcreport)); + alglib_impl::_ahcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_ahcreport_owner::~_ahcreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_ahcreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::ahcreport* _ahcreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::ahcreport* _ahcreport_owner::c_ptr() const +{ + return p_struct; +} +ahcreport::ahcreport() : _ahcreport_owner() ,terminationtype(p_struct->terminationtype),npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) +{ +} + +ahcreport::ahcreport(alglib_impl::ahcreport *attach_to):_ahcreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) +{ +} + +ahcreport::ahcreport(const ahcreport &rhs):_ahcreport_owner(rhs) ,terminationtype(p_struct->terminationtype),npoints(p_struct->npoints),p(&p_struct->p),z(&p_struct->z),pz(&p_struct->pz),pm(&p_struct->pm),mergedist(&p_struct->mergedist) +{ +} + +ahcreport& ahcreport::operator=(const ahcreport &rhs) +{ + if( this==&rhs ) + return *this; + _ahcreport_owner::operator=(rhs); + return *this; +} + +ahcreport::~ahcreport() +{ +} + + + + +/************************************************************************* +This structure is used to store results of the k-means clustering +algorithm. + +Following information is always returned: +* NPoints contains number of points in the original dataset +* TerminationType contains completion code, negative on failure, positive + on success +* K contains number of clusters + +For positive TerminationType we return: +* NFeatures contains number of variables in the original dataset +* C, which contains centers found by algorithm +* CIdx, which maps points of the original dataset to clusters + +FORMAL DESCRIPTION OF FIELDS: + NPoints number of points, >=0 + NFeatures number of variables, >=1 + TerminationType completion code: + * -5 if distance type is anything different from + Euclidean metric + * -3 for degenerate dataset: a) less than K distinct + points, b) K=0 for non-empty dataset. + * +1 for successful completion + K number of clusters + C array[K,NFeatures], rows of the array store centers + CIdx array[NPoints], which contains cluster indexes + IterationsCount actual number of iterations performed by clusterizer. + If algorithm performed more than one random restart, + total number of iterations is returned. + Energy merit function, "energy", sum of squared deviations + from cluster centers + + -- ALGLIB -- + Copyright 27.11.2012 by Bochkanov Sergey +*************************************************************************/ +_kmeansreport_owner::_kmeansreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kmeansreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kmeansreport)); + alglib_impl::_kmeansreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kmeansreport_owner::_kmeansreport_owner(alglib_impl::kmeansreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_kmeansreport_owner::_kmeansreport_owner(const _kmeansreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_kmeansreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kmeansreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::kmeansreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::kmeansreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::kmeansreport)); + alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_kmeansreport_owner& _kmeansreport_owner::operator=(const _kmeansreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: kmeansreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: kmeansreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: kmeansreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_kmeansreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::kmeansreport)); + alglib_impl::_kmeansreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_kmeansreport_owner::~_kmeansreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_kmeansreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::kmeansreport* _kmeansreport_owner::c_ptr() const +{ + return p_struct; +} +kmeansreport::kmeansreport() : _kmeansreport_owner() ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),iterationscount(p_struct->iterationscount),energy(p_struct->energy),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) +{ +} + +kmeansreport::kmeansreport(alglib_impl::kmeansreport *attach_to):_kmeansreport_owner(attach_to) ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),iterationscount(p_struct->iterationscount),energy(p_struct->energy),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) +{ +} + +kmeansreport::kmeansreport(const kmeansreport &rhs):_kmeansreport_owner(rhs) ,npoints(p_struct->npoints),nfeatures(p_struct->nfeatures),terminationtype(p_struct->terminationtype),iterationscount(p_struct->iterationscount),energy(p_struct->energy),k(p_struct->k),c(&p_struct->c),cidx(&p_struct->cidx) +{ +} + +kmeansreport& kmeansreport::operator=(const kmeansreport &rhs) +{ + if( this==&rhs ) + return *this; + _kmeansreport_owner::operator=(rhs); + return *this; +} + +kmeansreport::~kmeansreport() +{ +} +#endif + +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void dfserialize(const decisionforest &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::dfalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::dfserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void dfserialize(const decisionforest &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::dfalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::dfserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void dfunserialize(const std::string &s_in, decisionforest &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::dfunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void dfunserialize(const std::istream &s_in, decisionforest &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::dfunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel inference requests. + +DF subpackage provides two sets of computing functions - ones which use +internal buffer of DF model (these functions are single-threaded because +they use same buffer, which can not shared between threads), and ones +which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + Model - DF model which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with model which was used to + initialize buffer. Any attempt to use buffer with different + object is dangerous - you may get integrity check failure + (exception) because sizes of internal arrays do not fit to + dimensions of the model structure. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void dfcreatebuffer(const decisionforest &model, decisionforestbuffer &buf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfcreatebuffer(model.c_ptr(), buf.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine creates DecisionForestBuilder object which is used to +train decision forests. + +By default, new builder stores empty dataset and some reasonable default +settings. At the very least, you should specify dataset prior to building +decision forest. You can also tweak settings of the forest construction +algorithm (recommended, although default setting should work well). + +Following actions are mandatory: +* calling dfbuildersetdataset() to specify dataset +* calling dfbuilderbuildrandomforest() to build decision forest using + current dataset and default settings + +Additionally, you may call: +* dfbuildersetrndvars() or dfbuildersetrndvarsratio() to specify number of + variables randomly chosen for each split +* dfbuildersetsubsampleratio() to specify fraction of the dataset randomly + subsampled to build each tree +* dfbuildersetseed() to control random seed chosen for tree construction + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildercreate(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildercreate(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the forest construction algorithm will be invoked. + +INPUT PARAMETERS: + S - decision forest builder object + XY - array[NPoints,NVars+1] (minimum size; actual size can + be larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * last column store class number (in 0...NClasses-1) + or real value of the dependent variable + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - indicates type of the problem being solved: + * NClasses>=2 means that classification problem is + solved (last column of the dataset stores class + number) + * NClasses=1 means that regression problem is solved + (last column of the dataset stores variable value) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetdataset(decisionforestbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetdataset(s.c_ptr(), xy.c_ptr(), npoints, nvars, nclasses, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets number of variables (in [1,NVars] range) used by +decision forest construction algorithm. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + RndVars - number of randomly selected variables; values outside + of [1,NVars] range are silently clipped. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvars(decisionforestbuilder &s, const ae_int_t rndvars, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetrndvars(s.c_ptr(), rndvars, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets number of variables used by decision forest construction +algorithm as a fraction of total variable count (0,1) range. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + F - round(NVars*F) variables are selected + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsratio(decisionforestbuilder &s, const double f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetrndvarsratio(s.c_ptr(), f, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells decision forest builder to automatically choose number +of variables used by decision forest construction algorithm. Roughly +sqrt(NVars) variables will be used. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsauto(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetrndvarsauto(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets size of dataset subsample generated the decision forest +construction algorithm. Size is specified as a fraction of total dataset +size. + +The default option is to use 50% of the dataset for training, 50% for the +OOB estimates. You can decrease fraction F down to 10%, 1% or even below +in order to reduce overfitting. + +INPUT PARAMETERS: + S - decision forest builder object + F - fraction of the dataset to use, in (0,1] range. Values + outside of this range will be silently clipped. At + least one element is always selected for the training + set. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetsubsampleratio(decisionforestbuilder &s, const double f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetsubsampleratio(s.c_ptr(), f, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets seed used by internal RNG for random subsampling and +random selection of variable subsets. + +By default random seed is used, i.e. every time you build decision forest, +we seed generator with new value obtained from system-wide RNG. Thus, +decision forest builder returns non-deterministic results. You can change +such behavior by specyfing fixed positive seed value. + +INPUT PARAMETERS: + S - decision forest builder object + SeedVal - seed value: + * positive values are used for seeding RNG with fixed + seed, i.e. subsequent runs on same data will return + same decision forests + * non-positive seed means that random seed is used + for every run of builder, i.e. subsequent runs on + same datasets will return slightly different + decision forests + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetseed(decisionforestbuilder &s, const ae_int_t seedval, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetseed(s.c_ptr(), seedval, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets random decision forest construction algorithm. + +As for now, only one decision forest construction algorithm is supported - +a dense "baseline" RDF algorithm. + +INPUT PARAMETERS: + S - decision forest builder object + AlgoType - algorithm type: + * 0 = baseline dense RDF + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfalgo(decisionforestbuilder &s, const ae_int_t algotype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetrdfalgo(s.c_ptr(), algotype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets split selection algorithm used by decision forest +classifier. You may choose several algorithms, with different speed and +quality of the results. + +INPUT PARAMETERS: + S - decision forest builder object + SplitStrength- split type: + * 0 = split at the random position, fastest one + * 1 = split at the middle of the range + * 2 = strong split at the best point of the range (default) + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfsplitstrength(decisionforestbuilder &s, const ae_int_t splitstrength, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetrdfsplitstrength(s.c_ptr(), splitstrength, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells decision forest construction algorithm to use +Gini impurity based variable importance estimation (also known as MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on training sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and beautifully normalized (sum to +one) but have following downsides: +* They ALWAYS sum to 1.0, even if output is completely unpredictable. I.e. + MDI allows to order variables by importance, but does not tell us about + "absolute" importances of variables +* there exist some bias towards continuous and high-cardinality categorical + variables + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancetrngini(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetimportancetrngini(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells decision forest construction algorithm to use +out-of-bag version of Gini variable importance estimation (also known as +OOB-MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on out-of-bag sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and resistant to overfitting issues +(thanks to the out-of-bag estimates used). However, OOB Gini rating has +following downsides: +* there exist some bias towards continuous and high-cardinality categorical + variables +* Gini rating allows us to order variables by importance, but it is hard + to define importance of the variable by itself. + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportanceoobgini(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetimportanceoobgini(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells decision forest construction algorithm to use +permutation variable importance estimator (also known as MDA). + +This version of importance estimation algorithm analyzes mean increase in +out-of-bag sum of squared residuals after random permutation of J-th +variable. The result is divided by error computed with all variables being +perturbed in order to produce R-squared-like estimate in [0,1] range. + +Such estimate is slower to calculate than Gini-based rating because it +needs multiple inference runs for each of variables being studied. + +ALGLIB uses parallelized and highly optimized algorithm which analyzes +path through the decision tree and allows to handle most perturbations +in O(1) time; nevertheless, requesting MDA importances may increase forest +construction time from 10% to 200% (or more, if you have thousands of +variables). + +However, MDA rating has following benefits over Gini-based ones: +* no bias towards specific variable types +* ability to directly evaluate "absolute" importance of some variable at + "0 to 1" scale (contrary to Gini-based rating, which returns comparative + importances). + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancepermutation(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetimportancepermutation(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells decision forest construction algorithm to skip +variable importance estimation. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will result in forest being built + without variable importance estimation. + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancenone(decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildersetimportancenone(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is an alias for dfbuilderpeekprogress(), left in ALGLIB for +backward compatibility reasons. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuildergetprogress(const decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfbuildergetprogress(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function is used to peek into decision forest construction process +from some other thread and get current progress indicator. + +It returns value in [0,1]. + +INPUT PARAMETERS: + S - decision forest builder object used to build forest + in some other thread + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuilderpeekprogress(const decisionforestbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfbuilderpeekprogress(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine builds decision forest according to current settings using +dataset internally stored in the builder object. Dense algorithm is used. + +NOTE: this function uses dense algorithm for forest construction + independently from the dataset format (dense or sparse). + +NOTE: forest built with this function is stored in-memory using 64-bit + data structures for offsets/indexes/split values. It is possible to + convert forest into more memory-efficient compressed binary + representation. Depending on the problem properties, 3.7x-5.7x + compression factors are possible. + + The downsides of compression are (a) slight reduction in the model + accuracy and (b) ~1.5x reduction in the inference speed (due to + increased complexity of the storage format). + + See comments on dfbinarycompression() for more info. + +Default settings are used by the algorithm; you can tweak them with the +help of the following functions: +* dfbuildersetrfactor() - to control a fraction of the dataset used for + subsampling +* dfbuildersetrandomvars() - to control number of variables randomly chosen + for decision rule creation + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - decision forest builder object + NTrees - NTrees>=1, number of trees to train + +OUTPUT PARAMETERS: + DF - decision forest. You can compress this forest to more + compact 16-bit representation with dfbinarycompression() + Rep - report, see below for information on its fields. + +=== report information produced by forest construction function ========== + +Decision forest training report includes following information: +* training set errors +* out-of-bag estimates of errors +* variable importance ratings + +Following fields are used to store information: +* training set errors are stored in rep.relclserror, rep.avgce, rep.rmserror, + rep.avgerror and rep.avgrelerror +* out-of-bag estimates of errors are stored in rep.oobrelclserror, rep.oobavgce, + rep.oobrmserror, rep.oobavgerror and rep.oobavgrelerror + +Variable importance reports, if requested by dfbuildersetimportancegini(), +dfbuildersetimportancetrngini() or dfbuildersetimportancepermutation() +call, are stored in: +* rep.varimportances field stores importance ratings +* rep.topvars stores variable indexes ordered from the most important to + less important ones + +You can find more information about report fields in: +* comments on dfreport structure +* comments on dfbuildersetimportancegini function +* comments on dfbuildersetimportancetrngini function +* comments on dfbuildersetimportancepermutation function + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuilderbuildrandomforest(decisionforestbuilder &s, const ae_int_t ntrees, decisionforest &df, dfreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuilderbuildrandomforest(s.c_ptr(), ntrees, df.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function performs binary compression of the decision forest. + +Original decision forest produced by the forest builder is stored using +64-bit representation for all numbers - offsets, variable indexes, split +points. + +It is possible to significantly reduce model size by means of: +* using compressed dynamic encoding for integers (offsets and variable + indexes), which uses just 1 byte to store small ints (less than 128), + just 2 bytes for larger values (less than 128^2) and so on +* storing floating point numbers using 8-bit exponent and 16-bit mantissa + +As result, model needs significantly less memory (compression factor +depends on variable and class counts). In particular: +* NVars<128 and NClasses<128 result in 4.4x-5.7x model size reduction +* NVars<16384 and NClasses<128 result in 3.7x-4.5x model size reduction + +Such storage format performs lossless compression of all integers, but +compression of floating point values (split values) is lossy, with roughly +0.01% relative error introduced during rounding. Thus, we recommend you to +re-evaluate model accuracy after compression. + +Another downside of compression is ~1.5x reduction in the inference +speed due to necessity of dynamic decompression of the compressed model. + +INPUT PARAMETERS: + DF - decision forest built by forest builder + +OUTPUT PARAMETERS: + DF - replaced by compressed forest + +RESULT: + compression factor (in-RAM size of the compressed model vs than of the + uncompressed one), positive number larger than 1.0 + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +double dfbinarycompression(decisionforest &df, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfbinarycompression(df.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inference using decision forest + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + +INPUT PARAMETERS: + DF - decision forest model + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfprocess(df.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +'interactive' variant of DFProcess for languages like Python which support +constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfprocessi(df.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for dfprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - DF model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double dfprocess0(decisionforest &model, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfprocess0(model.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling dfprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - decision forest model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t dfclassify(decisionforest &model, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::dfclassify(model.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Inference using decision forest + +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same DF model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + DF - decision forest model + Buf - buffer object, must be allocated specifically for this + model with dfcreatebuffer(). + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dftsprocess(const decisionforest &df, decisionforestbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dftsprocess(df.c_ptr(), buf.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfrelclserror(df.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfavgce(df.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for + classification task, RMS error means error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfrmserror(df.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfavgerror(df.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average relative error when estimating + posterior probability of belonging to the correct class. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dfavgrelerror(df.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildrandomdecisionforest(xy.c_ptr(), npoints, nvars, nclasses, ntrees, r, &info, df.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::dfbuildrandomdecisionforestx1(xy.c_ptr(), npoints, nvars, nclasses, ntrees, nrndvars, r, &info, df.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +A random forest (decision forest) builder object. + +Used to store dataset and specify decision forest training algorithm settings. +*************************************************************************/ +_decisionforestbuilder_owner::_decisionforestbuilder_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforestbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::decisionforestbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforestbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuilder)); + alglib_impl::_decisionforestbuilder_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforestbuilder_owner::_decisionforestbuilder_owner(alglib_impl::decisionforestbuilder *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_decisionforestbuilder_owner::_decisionforestbuilder_owner(const _decisionforestbuilder_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforestbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforestbuilder copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::decisionforestbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforestbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuilder)); + alglib_impl::_decisionforestbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforestbuilder_owner& _decisionforestbuilder_owner::operator=(const _decisionforestbuilder_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: decisionforestbuilder assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforestbuilder assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: decisionforestbuilder assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_decisionforestbuilder_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuilder)); + alglib_impl::_decisionforestbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_decisionforestbuilder_owner::~_decisionforestbuilder_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_decisionforestbuilder_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::decisionforestbuilder* _decisionforestbuilder_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::decisionforestbuilder* _decisionforestbuilder_owner::c_ptr() const +{ + return p_struct; +} +decisionforestbuilder::decisionforestbuilder() : _decisionforestbuilder_owner() +{ +} + +decisionforestbuilder::decisionforestbuilder(alglib_impl::decisionforestbuilder *attach_to):_decisionforestbuilder_owner(attach_to) +{ +} + +decisionforestbuilder::decisionforestbuilder(const decisionforestbuilder &rhs):_decisionforestbuilder_owner(rhs) +{ +} + +decisionforestbuilder& decisionforestbuilder::operator=(const decisionforestbuilder &rhs) +{ + if( this==&rhs ) + return *this; + _decisionforestbuilder_owner::operator=(rhs); + return *this; +} + +decisionforestbuilder::~decisionforestbuilder() +{ +} + + + + +/************************************************************************* +Buffer object which is used to perform various requests (usually model +inference) in the multithreaded mode (multiple threads working with same +DF object). + +This object should be created with DFCreateBuffer(). +*************************************************************************/ +_decisionforestbuffer_owner::_decisionforestbuffer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforestbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::decisionforestbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforestbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuffer)); + alglib_impl::_decisionforestbuffer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforestbuffer_owner::_decisionforestbuffer_owner(alglib_impl::decisionforestbuffer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_decisionforestbuffer_owner::_decisionforestbuffer_owner(const _decisionforestbuffer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforestbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforestbuffer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::decisionforestbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforestbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuffer)); + alglib_impl::_decisionforestbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforestbuffer_owner& _decisionforestbuffer_owner::operator=(const _decisionforestbuffer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: decisionforestbuffer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforestbuffer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: decisionforestbuffer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_decisionforestbuffer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::decisionforestbuffer)); + alglib_impl::_decisionforestbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_decisionforestbuffer_owner::~_decisionforestbuffer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_decisionforestbuffer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::decisionforestbuffer* _decisionforestbuffer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::decisionforestbuffer* _decisionforestbuffer_owner::c_ptr() const +{ + return p_struct; +} +decisionforestbuffer::decisionforestbuffer() : _decisionforestbuffer_owner() +{ +} + +decisionforestbuffer::decisionforestbuffer(alglib_impl::decisionforestbuffer *attach_to):_decisionforestbuffer_owner(attach_to) +{ +} + +decisionforestbuffer::decisionforestbuffer(const decisionforestbuffer &rhs):_decisionforestbuffer_owner(rhs) +{ +} + +decisionforestbuffer& decisionforestbuffer::operator=(const decisionforestbuffer &rhs) +{ + if( this==&rhs ) + return *this; + _decisionforestbuffer_owner::operator=(rhs); + return *this; +} + +decisionforestbuffer::~decisionforestbuffer() +{ +} + + + + +/************************************************************************* +Decision forest (random forest) model. +*************************************************************************/ +_decisionforest_owner::_decisionforest_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforest_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforest)); + alglib_impl::_decisionforest_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforest_owner::_decisionforest_owner(alglib_impl::decisionforest *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_decisionforest_owner::_decisionforest_owner(const _decisionforest_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_decisionforest_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforest copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::decisionforest*)alglib_impl::ae_malloc(sizeof(alglib_impl::decisionforest), &_state); + memset(p_struct, 0, sizeof(alglib_impl::decisionforest)); + alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_decisionforest_owner& _decisionforest_owner::operator=(const _decisionforest_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: decisionforest assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: decisionforest assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: decisionforest assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_decisionforest_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::decisionforest)); + alglib_impl::_decisionforest_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_decisionforest_owner::~_decisionforest_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_decisionforest_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::decisionforest* _decisionforest_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::decisionforest* _decisionforest_owner::c_ptr() const +{ + return p_struct; +} +decisionforest::decisionforest() : _decisionforest_owner() +{ +} + +decisionforest::decisionforest(alglib_impl::decisionforest *attach_to):_decisionforest_owner(attach_to) +{ +} + +decisionforest::decisionforest(const decisionforest &rhs):_decisionforest_owner(rhs) +{ +} + +decisionforest& decisionforest::operator=(const decisionforest &rhs) +{ + if( this==&rhs ) + return *this; + _decisionforest_owner::operator=(rhs); + return *this; +} + +decisionforest::~decisionforest() +{ +} + + + + +/************************************************************************* +Decision forest training report. + +=== training/oob errors ================================================== + +Following fields store training set errors: +* relclserror - fraction of misclassified cases, [0,1] +* avgce - average cross-entropy in bits per symbol +* rmserror - root-mean-square error +* avgerror - average error +* avgrelerror - average relative error + +Out-of-bag estimates are stored in fields with same names, but "oob" prefix. + +For classification problems: +* RMS, AVG and AVGREL errors are calculated for posterior probabilities + +For regression problems: +* RELCLS and AVGCE errors are zero + +=== variable importance ================================================== + +Following fields are used to store variable importance information: + +* topvars - variables ordered from the most important to + less important ones (according to current + choice of importance raiting). + For example, topvars[0] contains index of the + most important variable, and topvars[0:2] are + indexes of 3 most important ones and so on. + +* varimportances - array[nvars], ratings (the larger, the more + important the variable is, always in [0,1] + range). + By default, filled by zeros (no importance + ratings are provided unless you explicitly + request them). + Zero rating means that variable is not important, + however you will rarely encounter such a thing, + in many cases unimportant variables produce + nearly-zero (but nonzero) ratings. + +Variable importance report must be EXPLICITLY requested by calling: +* dfbuildersetimportancegini() function, if you need out-of-bag Gini-based + importance rating also known as MDI (fast to calculate, resistant to + overfitting issues, but has some bias towards continuous and + high-cardinality categorical variables) +* dfbuildersetimportancetrngini() function, if you need training set Gini- + -based importance rating (what other packages typically report). +* dfbuildersetimportancepermutation() function, if you need permutation- + based importance rating also known as MDA (slower to calculate, but less + biased) +* dfbuildersetimportancenone() function, if you do not need importance + ratings - ratings will be zero, topvars[] will be [0,1,2,...] + +Different importance ratings (Gini or permutation) produce non-comparable +values. Although in all cases rating values lie in [0,1] range, there are +exist differences: +* informally speaking, Gini importance rating tends to divide "unit amount + of importance" between several important variables, i.e. it produces + estimates which roughly sum to 1.0 (or less than 1.0, if your task can + not be solved exactly). If all variables are equally important, they + will have same rating, roughly 1/NVars, even if every variable is + critically important. +* from the other side, permutation importance tells us what percentage of + the model predictive power will be ruined by permuting this specific + variable. It does not produce estimates which sum to one. Critically + important variable will have rating close to 1.0, and you may have + multiple variables with such a rating. + +More information on variable importance ratings can be found in comments +on the dfbuildersetimportancegini() and dfbuildersetimportancepermutation() +functions. +*************************************************************************/ +_dfreport_owner::_dfreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_dfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::dfreport)); + alglib_impl::_dfreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_dfreport_owner::_dfreport_owner(alglib_impl::dfreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_dfreport_owner::_dfreport_owner(const _dfreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_dfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: dfreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::dfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::dfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::dfreport)); + alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_dfreport_owner& _dfreport_owner::operator=(const _dfreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: dfreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: dfreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: dfreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_dfreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::dfreport)); + alglib_impl::_dfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_dfreport_owner::~_dfreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_dfreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::dfreport* _dfreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::dfreport* _dfreport_owner::c_ptr() const +{ + return p_struct; +} +dfreport::dfreport() : _dfreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror),topvars(&p_struct->topvars),varimportances(&p_struct->varimportances) +{ +} + +dfreport::dfreport(alglib_impl::dfreport *attach_to):_dfreport_owner(attach_to) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror),topvars(&p_struct->topvars),varimportances(&p_struct->varimportances) +{ +} + +dfreport::dfreport(const dfreport &rhs):_dfreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),oobrelclserror(p_struct->oobrelclserror),oobavgce(p_struct->oobavgce),oobrmserror(p_struct->oobrmserror),oobavgerror(p_struct->oobavgerror),oobavgrelerror(p_struct->oobavgrelerror),topvars(&p_struct->topvars),varimportances(&p_struct->varimportances) +{ +} + +dfreport& dfreport::operator=(const dfreport &rhs) +{ + if( this==&rhs ) + return *this; + _dfreport_owner::operator=(rhs); + return *this; +} + +dfreport::~dfreport() +{ +} +#endif + +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Linear regression + +Subroutine builds model: + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) + +and model found in ALGLIB format, covariation matrix, training set errors +(rms, average, average relative) and leave-one-out cross-validation +estimate of the generalization error. CV estimate calculated using fast +algorithm with O(NPoints*NVars) complexity. + +When covariation matrix is calculated standard deviations of function +values are assumed to be equal to RMS error on the training set. + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + NPoints - training set size, NPoints>NVars+1. An exception is + generated otherwise. + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuild(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuild(xy.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Linear regression + +Subroutine builds model: + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) + +and model found in ALGLIB format, covariation matrix, training set errors +(rms, average, average relative) and leave-one-out cross-validation +estimate of the generalization error. CV estimate calculated using fast +algorithm with O(NPoints*NVars) complexity. + +When covariation matrix is calculated standard deviations of function +values are assumed to be equal to RMS error on the training set. + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + NPoints - training set size, NPoints>NVars+1. An exception is + generated otherwise. + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lrbuild(const real_2d_array &xy, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuild(xy.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Linear regression + +Variant of LRBuild which uses vector of standatd deviations (errors in +function values). + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + S - standard deviations (errors in function values) + array[NPoints], S[i]>0. + NPoints - training set size, NPoints>NVars+1 + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuilds(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuilds(xy.c_ptr(), s.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Linear regression + +Variant of LRBuild which uses vector of standatd deviations (errors in +function values). + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + S - standard deviations (errors in function values) + array[NPoints], S[i]>0. + NPoints - training set size, NPoints>NVars+1 + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lrbuilds(const real_2d_array &xy, const real_1d_array &s, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + if( (xy.rows()!=s.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lrbuilds': looks like one of arguments has wrong size"); + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuilds(xy.c_ptr(), s.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Like LRBuildS, but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuildzs(xy.c_ptr(), s.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like LRBuildS, but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + if( (xy.rows()!=s.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lrbuildzs': looks like one of arguments has wrong size"); + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuildzs(xy.c_ptr(), s.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Like LRBuild but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuildz(xy.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Like LRBuild but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lrbuildz(const real_2d_array &xy, linearmodel &lm, lrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrbuildz(xy.c_ptr(), npoints, nvars, lm.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Unpacks coefficients of linear model. + +INPUT PARAMETERS: + LM - linear model in ALGLIB format + +OUTPUT PARAMETERS: + V - coefficients, array[0..NVars] + constant term (intercept) is stored in the V[NVars]. + NVars - number of independent variables (one less than number + of coefficients) + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrunpack(const linearmodel &lm, real_1d_array &v, ae_int_t &nvars, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrunpack(lm.c_ptr(), v.c_ptr(), &nvars, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack +reversed). + +INPUT PARAMETERS: + V - coefficients, array[0..NVars] + NVars - number of independent variables + +OUTPUT PAREMETERS: + LM - linear model. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrpack(const real_1d_array &v, const ae_int_t nvars, linearmodel &lm, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrpack(v.c_ptr(), nvars, lm.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack +reversed). + +INPUT PARAMETERS: + V - coefficients, array[0..NVars] + NVars - number of independent variables + +OUTPUT PAREMETERS: + LM - linear model. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lrpack(const real_1d_array &v, linearmodel &lm, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nvars; + + nvars = v.length()+1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lrpack(v.c_ptr(), nvars, lm.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + LM - linear model + X - input vector, array[0..NVars-1]. + +Result: + value of linear model regression estimate + + -- ALGLIB -- + Copyright 03.09.2008 by Bochkanov Sergey +*************************************************************************/ +double lrprocess(const linearmodel &lm, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lrprocess(lm.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lrrmserror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lrrmserror(lm.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lravgerror(lm.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average relative error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgrelerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lravgrelerror(lm.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + + +/************************************************************************* + +*************************************************************************/ +_linearmodel_owner::_linearmodel_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linearmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linearmodel)); + alglib_impl::_linearmodel_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linearmodel_owner::_linearmodel_owner(alglib_impl::linearmodel *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_linearmodel_owner::_linearmodel_owner(const _linearmodel_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linearmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linearmodel copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::linearmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::linearmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linearmodel)); + alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linearmodel_owner& _linearmodel_owner::operator=(const _linearmodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: linearmodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linearmodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: linearmodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_linearmodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::linearmodel)); + alglib_impl::_linearmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_linearmodel_owner::~_linearmodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_linearmodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::linearmodel* _linearmodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::linearmodel* _linearmodel_owner::c_ptr() const +{ + return p_struct; +} +linearmodel::linearmodel() : _linearmodel_owner() +{ +} + +linearmodel::linearmodel(alglib_impl::linearmodel *attach_to):_linearmodel_owner(attach_to) +{ +} + +linearmodel::linearmodel(const linearmodel &rhs):_linearmodel_owner(rhs) +{ +} + +linearmodel& linearmodel::operator=(const linearmodel &rhs) +{ + if( this==&rhs ) + return *this; + _linearmodel_owner::operator=(rhs); + return *this; +} + +linearmodel::~linearmodel() +{ +} + + + + +/************************************************************************* +LRReport structure contains additional information about linear model: +* C - covariation matrix, array[0..NVars,0..NVars]. + C[i,j] = Cov(A[i],A[j]) +* RMSError - root mean square error on a training set +* AvgError - average error on a training set +* AvgRelError - average relative error on a training set (excluding + observations with zero function value). +* CVRMSError - leave-one-out cross-validation estimate of + generalization error. Calculated using fast algorithm + with O(NVars*NPoints) complexity. +* CVAvgError - cross-validation estimate of average error +* CVAvgRelError - cross-validation estimate of average relative error + +All other fields of the structure are intended for internal use and should +not be used outside ALGLIB. +*************************************************************************/ +_lrreport_owner::_lrreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lrreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lrreport)); + alglib_impl::_lrreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lrreport_owner::_lrreport_owner(alglib_impl::lrreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lrreport_owner::_lrreport_owner(const _lrreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lrreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lrreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lrreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lrreport)); + alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lrreport_owner& _lrreport_owner::operator=(const _lrreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lrreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lrreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lrreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lrreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lrreport)); + alglib_impl::_lrreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lrreport_owner::~_lrreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lrreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lrreport* _lrreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lrreport* _lrreport_owner::c_ptr() const +{ + return p_struct; +} +lrreport::lrreport() : _lrreport_owner() ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) +{ +} + +lrreport::lrreport(alglib_impl::lrreport *attach_to):_lrreport_owner(attach_to) ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) +{ +} + +lrreport::lrreport(const lrreport &rhs):_lrreport_owner(rhs) ,c(&p_struct->c),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),cvrmserror(p_struct->cvrmserror),cvavgerror(p_struct->cvavgerror),cvavgrelerror(p_struct->cvavgrelerror),ncvdefects(p_struct->ncvdefects),cvdefects(&p_struct->cvdefects) +{ +} + +lrreport& lrreport::operator=(const lrreport &rhs) +{ + if( this==&rhs ) + return *this; + _lrreport_owner::operator=(rhs); + return *this; +} + +lrreport::~lrreport() +{ +} +#endif + +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Filters: simple moving averages (unsymmetric). + +This filter replaces array by results of SMA(K) filter. SMA(K) is defined +as filter which averages at most K previous points (previous - not points +AROUND central point) - or less, in case of the first K-1 points. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with SMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::filtersma(x.c_ptr(), n, k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Filters: simple moving averages (unsymmetric). + +This filter replaces array by results of SMA(K) filter. SMA(K) is defined +as filter which averages at most K previous points (previous - not points +AROUND central point) - or less, in case of the first K-1 points. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with SMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void filtersma(real_1d_array &x, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::filtersma(x.c_ptr(), n, k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Filters: exponential moving averages. + +This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is +defined as filter which replaces X[] by S[]: + S[0] = X[0] + S[t] = alpha*X[t] + (1-alpha)*S[t-1] + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + alpha - 0=0 + alpha - 0=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with LRMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::filterlrma(x.c_ptr(), n, k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Filters: linear regression moving averages. + +This filter replaces array by results of LRMA(K) filter. + +LRMA(K) is defined as filter which, for each data point, builds linear +regression model using K prevous points (point itself is included in +these K points) and calculates value of this linear model at the point in +question. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with LRMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void filterlrma(real_1d_array &x, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::filterlrma(x.c_ptr(), n, k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +#endif + +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function creates SSA model object. Right after creation model is in +"dummy" mode - you can add data, but analyzing/prediction will return +just zeros (it assumes that basis is empty). + +HOW TO USE SSA MODEL: + +1. create model with ssacreate() +2. add data with one/many ssaaddsequence() calls +3. choose SSA algorithm with one of ssasetalgo...() functions: + * ssasetalgotopkdirect() for direct one-run analysis + * ssasetalgotopkrealtime() for algorithm optimized for many subsequent + runs with warm-start capabilities + * ssasetalgoprecomputed() for user-supplied basis +4. set window width with ssasetwindow() +5. perform one of the analysis-related activities: + a) call ssagetbasis() to get basis + b) call ssaanalyzelast() ssaanalyzesequence() or ssaanalyzelastwindow() + to perform analysis (trend/noise separation) + c) call one of the forecasting functions (ssaforecastlast() or + ssaforecastsequence()) to perform prediction; alternatively, you can + extract linear recurrence coefficients with ssagetlrr(). + SSA analysis will be performed during first call to analysis-related + function. SSA model is smart enough to track all changes in the dataset + and model settings, to cache previously computed basis and to + re-evaluate basis only when necessary. + +Additionally, if your setting involves constant stream of incoming data, +you can perform quick update already calculated model with one of the +incremental append-and-update functions: ssaappendpointandupdate() or +ssaappendsequenceandupdate(). + +NOTE: steps (2), (3), (4) can be performed in arbitrary order. + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - structure which stores model state + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacreate(ssamodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssacreate(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets window width for SSA model. You should call it before +analysis phase. Default window width is 1 (not for real use). + +Special notes: +* this function call can be performed at any moment before first call to + analysis-related functions +* changing window width invalidates internally stored basis; if you change + window width AFTER you call analysis-related function, next analysis + phase will require re-calculation of the basis according to current + algorithm. +* calling this function with exactly same window width as current one has + no effect +* if you specify window width larger than any data sequence stored in the + model, analysis will return zero basis. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + WindowWidth - >=1, new window width + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetwindow(ssamodel &s, const ae_int_t windowwidth, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetwindow(s.c_ptr(), windowwidth, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets seed which is used to initialize internal RNG when +we make pseudorandom decisions on model updates. + +By default, deterministic seed is used - which results in same sequence of +pseudorandom decisions every time you run SSA model. If you specify non- +deterministic seed value, then SSA model may return slightly different +results after each run. + +This function can be useful when you have several SSA models updated with +sseappendpointandupdate() called with 01 means that delayed power-up is performed + + -- ALGLIB -- + Copyright 03.11.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetpoweruplength(ssamodel &s, const ae_int_t pwlen, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetpoweruplength(s.c_ptr(), pwlen, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets memory limit of SSA analysis. + +Straightforward SSA with sequence length T and window width W needs O(T*W) +memory. It is possible to reduce memory consumption by splitting task into +smaller chunks. + +Thus function allows you to specify approximate memory limit (measured in +double precision numbers used for buffers). Actual memory consumption will +be comparable to the number specified by you. + +Default memory limit is 50.000.000 (400Mbytes) in current version. + +INPUT PARAMETERS: + S - SSA model + MemLimit- memory limit, >=0. Zero value means no limit. + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetmemorylimit(ssamodel &s, const ae_int_t memlimit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetmemorylimit(s.c_ptr(), memlimit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds data sequence to SSA model. Only single-dimensional +sequences are supported. + +What is a sequences? Following definitions/requirements apply: +* a sequence is an array of values measured in subsequent, equally + separated time moments (ticks). +* you may have many sequences in your dataset; say, one sequence may + correspond to one trading session. +* sequence length should be larger than current window length (shorter + sequences will be ignored during analysis). +* analysis is performed within a sequence; different sequences are NOT + stacked together to produce one large contiguous stream of data. +* analysis is performed for all sequences at once, i.e. same set of basis + vectors is computed for all sequences + +INCREMENTAL ANALYSIS + +This function is non intended for incremental updates of previously found +SSA basis. Calling it invalidates all previous analysis results (basis is +reset and will be recalculated from zero during next analysis). + +If you want to perform incremental/real-time SSA, consider using +following functions: +* ssaappendpointandupdate() for appending one point +* ssaappendsequenceandupdate() for appending new sequence + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - array[N], data, can be larger (additional values + are ignored) + N - data length, can be automatically determined from + the array length. N>=0. + +OUTPUT PARAMETERS: + S - SSA model, updated + +NOTE: you can clear dataset with ssacleardata() + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaaddsequence(ssamodel &s, const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaaddsequence(s.c_ptr(), x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds data sequence to SSA model. Only single-dimensional +sequences are supported. + +What is a sequences? Following definitions/requirements apply: +* a sequence is an array of values measured in subsequent, equally + separated time moments (ticks). +* you may have many sequences in your dataset; say, one sequence may + correspond to one trading session. +* sequence length should be larger than current window length (shorter + sequences will be ignored during analysis). +* analysis is performed within a sequence; different sequences are NOT + stacked together to produce one large contiguous stream of data. +* analysis is performed for all sequences at once, i.e. same set of basis + vectors is computed for all sequences + +INCREMENTAL ANALYSIS + +This function is non intended for incremental updates of previously found +SSA basis. Calling it invalidates all previous analysis results (basis is +reset and will be recalculated from zero during next analysis). + +If you want to perform incremental/real-time SSA, consider using +following functions: +* ssaappendpointandupdate() for appending one point +* ssaappendsequenceandupdate() for appending new sequence + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - array[N], data, can be larger (additional values + are ignored) + N - data length, can be automatically determined from + the array length. N>=0. + +OUTPUT PARAMETERS: + S - SSA model, updated + +NOTE: you can clear dataset with ssacleardata() + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void ssaaddsequence(ssamodel &s, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaaddsequence(s.c_ptr(), x.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function appends single point to last data sequence stored in the SSA +model and tries to update model in the incremental manner (if possible +with current algorithm). + +If you want to add more than one point at once: +* if you want to add M points to the same sequence, perform M-1 calls with + UpdateIts parameter set to 0.0, and last call with non-zero UpdateIts. +* if you want to add new sequence, use ssaappendsequenceandupdate() + +Running time of this function does NOT depend on dataset size, only on +window width and number of singular vectors. Depending on algorithm being +used, incremental update has complexity: +* for top-K real time - O(UpdateIts*K*Width^2), with fractional UpdateIts +* for top-K direct - O(Width^3) for any non-zero UpdateIts +* for precomputed basis - O(1), no update is performed + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - new point + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=1, number of ticks in the sequence + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=1, number of ticks in the sequence + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=1 + NBasis - number of basis vectors, 1<=NBasis<=WindowWidth + +OUTPUT PARAMETERS: + S - updated model + +NOTE: calling this function invalidates basis in all cases. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgoprecomputed(ssamodel &s, const real_2d_array &a, const ae_int_t windowwidth, const ae_int_t nbasis, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetalgoprecomputed(s.c_ptr(), a.c_ptr(), windowwidth, nbasis, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets SSA algorithm to "precomputed vectors" algorithm. + +This algorithm uses precomputed set of orthonormal (orthogonal AND +normalized) basis vectors supplied by user. Thus, basis calculation phase +is not performed - we already have our basis - and only analysis/ +forecasting phase requires actual calculations. + +This algorithm may handle "append" requests which add just one/few ticks +to the end of the last sequence in O(1) time. + +NOTE: this algorithm accepts both basis and window width, because these + two parameters are naturally aligned. Calling this function sets + window width; if you call ssasetwindow() with other window width, + then during analysis stage algorithm will detect conflict and reset + to zero basis. + +INPUT PARAMETERS: + S - SSA model + A - array[WindowWidth,NBasis], orthonormalized basis; + this function does NOT control orthogonality and + does NOT perform any kind of renormalization. It + is your responsibility to provide it with correct + basis. + WindowWidth - window width, >=1 + NBasis - number of basis vectors, 1<=NBasis<=WindowWidth + +OUTPUT PARAMETERS: + S - updated model + +NOTE: calling this function invalidates basis in all cases. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void ssasetalgoprecomputed(ssamodel &s, const real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t windowwidth; + ae_int_t nbasis; + + windowwidth = a.rows(); + nbasis = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetalgoprecomputed(s.c_ptr(), a.c_ptr(), windowwidth, nbasis, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets SSA algorithm to "direct top-K" algorithm. + +"Direct top-K" algorithm performs full SVD of the N*WINDOW trajectory +matrix (hence its name - direct solver is used), then extracts top K +components. Overall running time is O(N*WINDOW^2), where N is a number of +ticks in the dataset, WINDOW is window width. + +This algorithm may handle "append" requests which add just one/few ticks +to the end of the last sequence in O(WINDOW^3) time, which is ~N/WINDOW +times faster than re-computing everything from scratch. + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkdirect(ssamodel &s, const ae_int_t topk, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetalgotopkdirect(s.c_ptr(), topk, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets SSA algorithm to "top-K real time algorithm". This algo +extracts K components with largest singular values. + +It is real-time version of top-K algorithm which is optimized for +incremental processing and fast start-up. Internally it uses subspace +eigensolver for truncated SVD. It results in ability to perform quick +updates of the basis when only a few points/sequences is added to dataset. + +Performance profile of the algorithm is given below: +* O(K*WindowWidth^2) running time for incremental update of the dataset + with one of the "append-and-update" functions (ssaappendpointandupdate() + or ssaappendsequenceandupdate()). +* O(N*WindowWidth^2) running time for initial basis evaluation (N=size of + dataset) +* ability to split costly initialization across several incremental + updates of the basis (so called "Power-Up" functionality, activated by + ssasetpoweruplength() function) + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + +NOTE: this algorithm is optimized for large-scale tasks with large + datasets. On toy problems with just 5-10 points it can return basis + which is slightly different from that returned by direct algorithm + (ssasetalgotopkdirect() function). However, the difference becomes + negligible as dataset grows. + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkrealtime(ssamodel &s, const ae_int_t topk, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssasetalgotopkrealtime(s.c_ptr(), topk, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function clears all data stored in the model and invalidates all +basis components found so far. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacleardata(ssamodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssacleardata(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function executes SSA on internally stored dataset and returns basis +found by current method. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth,NBasis], basis; vectors are + stored in matrix columns, by descreasing variance + SV - array[NBasis]: + * zeros - for model initialized with SSASetAlgoPrecomputed() + * singular values - for other algorithms + WindowWidth - current window + NBasis - basis size + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns basis with +just one zero vector. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetbasis(ssamodel &s, real_2d_array &a, real_1d_array &sv, ae_int_t &windowwidth, ae_int_t &nbasis, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssagetbasis(s.c_ptr(), a.c_ptr(), sv.c_ptr(), &windowwidth, &nbasis, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns linear recurrence relation (LRR) coefficients found +by current SSA algorithm. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth-1]. Coefficients of the + linear recurrence of the form: + X[W-1] = X[W-2]*A[W-2] + X[W-3]*A[W-3] + ... + X[0]*A[0]. + Empty array for WindowWidth=1. + WindowWidth - current window width + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns zeros. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetlrr(ssamodel &s, real_1d_array &a, ae_int_t &windowwidth, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssagetlrr(s.c_ptr(), a.c_ptr(), &windowwidth, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function executes SSA on internally stored dataset and returns +analysis for the last window of the last sequence. Such analysis is +an lightweight alternative for full scale reconstruction (see below). + +Typical use case for this function is real-time setting, when you are +interested in quick-and-dirty (very quick and very dirty) processing of +just a few last ticks of the trend. + +IMPORTANT: full scale SSA involves analysis of the ENTIRE dataset, + with reconstruction being done for all positions of sliding + window with subsequent hankelization (diagonal averaging) of + the resulting matrix. + + Such analysis requires O((DataLen-Window)*Window*NBasis) FLOPs + and can be quite costly. However, it has nice noise-canceling + effects due to averaging. + + This function performs REDUCED analysis of the last window. It + is much faster - just O(Window*NBasis), but its results are + DIFFERENT from that of ssaanalyzelast(). In particular, first + few points of the trend are much more prone to noise. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + Trend - array[WindowSize], reconstructed trend line + Noise - array[WindowSize], the rest of the signal; + it holds that ActualData = Trend+Noise. + NTicks - current WindowSize + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, WindowWidth ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelastwindow(ssamodel &s, real_1d_array &trend, real_1d_array &noise, ae_int_t &nticks, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaanalyzelastwindow(s.c_ptr(), trend.c_ptr(), noise.c_ptr(), &nticks, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the last NTicks of the last sequence + +If you want to analyze some other sequence, use ssaanalyzesequence(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +IMPORTANT: due to averaging this function returns different results for + different values of NTicks. It is expected and not a bug. + + For example: + * Trend[NTicks-1] is always same because it is not averaged in + any case (same applies to Trend[0]). + * Trend[NTicks-2] has different values for NTicks=WindowWidth + and NTicks=WindowWidth+1 because former case means that no + averaging is performed, and latter case means that averaging + using two sliding windows is performed. Larger values of + NTicks produce same results as NTicks=WindowWidth+1. + * ...and so on... + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks<=WindowWidth is handled + by analyzing last window and returning NTicks + last ticks. + * special case NTicks>LastSequenceLen is handled + by prepending result with NTicks-LastSequenceLen + zeros. + +OUTPUT PARAMETERS: + Trend - array[NTicks], reconstructed trend line + Noise - array[NTicks], the rest of the signal; + it holds that ActualData = Trend+Noise. + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, NTicks ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelast(ssamodel &s, const ae_int_t nticks, real_1d_array &trend, real_1d_array &noise, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaanalyzelast(s.c_ptr(), nticks, trend.c_ptr(), noise.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the sequence being passed to this function + +If you want to analyze last sequence stored in the model, use +ssaanalyzelast(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], can be larger (only NTicks leading + elements will be used) + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks=1. + * special case of NTicks=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastlast(ssamodel &s, const ae_int_t nticks, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastlast(s.c_ptr(), nticks, trend.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from the WindowWidth last elements of the + sequence. This stage is optional, you can turn it off if you pass + data which are already processed with SSA. Of course, you can turn it + off even for raw data, but it is not recommended - noise suppression is + very important for correct prediction. +* then, we apply LRR for last WindowWidth-1 elements of the extracted + trend. + +This function has following running time: +* O(NBasis*WindowWidth) for trend extraction phase +* O(WindowWidth*NTicks) for forecast phase + +NOTE: this algorithm performs prediction using only one - last - sliding + window. Predictions produced by such approach are smooth + continuations of the reconstructed trend line, but they can be + easily corrupted by noise. If you need noise-resistant prediction, + use ssaforecastavgsequence() function, which averages predictions + built using several sliding windows. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not; + if you do not know what to specify, pass True. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastsequence(ssamodel &s, const real_1d_array &data, const ae_int_t datalen, const ae_int_t forecastlen, const bool applysmoothing, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastsequence(s.c_ptr(), data.c_ptr(), datalen, forecastlen, applysmoothing, trend.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from the WindowWidth last elements of the + sequence. This stage is optional, you can turn it off if you pass + data which are already processed with SSA. Of course, you can turn it + off even for raw data, but it is not recommended - noise suppression is + very important for correct prediction. +* then, we apply LRR for last WindowWidth-1 elements of the extracted + trend. + +This function has following running time: +* O(NBasis*WindowWidth) for trend extraction phase +* O(WindowWidth*NTicks) for forecast phase + +NOTE: this algorithm performs prediction using only one - last - sliding + window. Predictions produced by such approach are smooth + continuations of the reconstructed trend line, but they can be + easily corrupted by noise. If you need noise-resistant prediction, + use ssaforecastavgsequence() function, which averages predictions + built using several sliding windows. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not; + if you do not know what to specify, pass True. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void ssaforecastsequence(ssamodel &s, const real_1d_array &data, const ae_int_t forecastlen, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t datalen; + bool applysmoothing; + + datalen = data.length(); + applysmoothing = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastsequence(s.c_ptr(), data.c_ptr(), datalen, forecastlen, applysmoothing, trend.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function builds SSA basis and performs forecasting for a specified +number of ticks, returning value of trend. + +Forecast is performed as follows: +* SSA trend extraction is applied to last M sliding windows of the + internally stored dataset +* for each of M sliding windows, M predictions are built +* average value of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase (always performed) +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: noise reduction is ALWAYS applied by this algorithm; if you want to + apply recurrence relation to raw unprocessed data, use another + function - ssaforecastsequence() which allows to turn on and off + noise reduction phase. + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + NTicks - number of ticks to forecast, NTicks>=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavglast(ssamodel &s, const ae_int_t m, const ae_int_t nticks, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastavglast(s.c_ptr(), m, nticks, trend.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from M last sliding windows of the sequence. + This stage is optional, you can turn it off if you pass data which + are already processed with SSA. Of course, you can turn it off even + for raw data, but it is not recommended - noise suppression is very + important for correct prediction. +* then, we apply LRR independently for M sliding windows +* average of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not. + if you do not know what to specify, pass true. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavgsequence(ssamodel &s, const real_1d_array &data, const ae_int_t datalen, const ae_int_t m, const ae_int_t forecastlen, const bool applysmoothing, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastavgsequence(s.c_ptr(), data.c_ptr(), datalen, m, forecastlen, applysmoothing, trend.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from M last sliding windows of the sequence. + This stage is optional, you can turn it off if you pass data which + are already processed with SSA. Of course, you can turn it off even + for raw data, but it is not recommended - noise suppression is very + important for correct prediction. +* then, we apply LRR independently for M sliding windows +* average of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not. + if you do not know what to specify, pass true. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void ssaforecastavgsequence(ssamodel &s, const real_1d_array &data, const ae_int_t m, const ae_int_t forecastlen, real_1d_array &trend, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t datalen; + bool applysmoothing; + + datalen = data.length(); + applysmoothing = true; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ssaforecastavgsequence(s.c_ptr(), data.c_ptr(), datalen, m, forecastlen, applysmoothing, trend.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + + +/************************************************************************* +This object stores state of the SSA model. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_ssamodel_owner::_ssamodel_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_ssamodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::ssamodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::ssamodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::ssamodel)); + alglib_impl::_ssamodel_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_ssamodel_owner::_ssamodel_owner(alglib_impl::ssamodel *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_ssamodel_owner::_ssamodel_owner(const _ssamodel_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_ssamodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: ssamodel copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::ssamodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::ssamodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::ssamodel)); + alglib_impl::_ssamodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_ssamodel_owner& _ssamodel_owner::operator=(const _ssamodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: ssamodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: ssamodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: ssamodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_ssamodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::ssamodel)); + alglib_impl::_ssamodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_ssamodel_owner::~_ssamodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_ssamodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::ssamodel* _ssamodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::ssamodel* _ssamodel_owner::c_ptr() const +{ + return p_struct; +} +ssamodel::ssamodel() : _ssamodel_owner() +{ +} + +ssamodel::ssamodel(alglib_impl::ssamodel *attach_to):_ssamodel_owner(attach_to) +{ +} + +ssamodel::ssamodel(const ssamodel &rhs):_ssamodel_owner(rhs) +{ +} + +ssamodel& ssamodel::operator=(const ssamodel &rhs) +{ + if( this==&rhs ) + return *this; + _ssamodel_owner::operator=(rhs); + return *this; +} + +ssamodel::~ssamodel() +{ +} +#endif + +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Multiclass Fisher LDA + +The function finds coefficients of a linear combination which optimally +separates training set. Most suited for 2-class problems, see fisherldan() +for an variant that returns N-dimensional basis. + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - linear combination coefficients, array[NVars] + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fisherlda(xy.c_ptr(), npoints, nvars, nclasses, w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiclass Fisher LDA + +The function finds coefficients of a linear combination which optimally +separates training set. Most suited for 2-class problems, see fisherldan() +for an variant that returns N-dimensional basis. + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - linear combination coefficients, array[NVars] + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fisherlda(const real_2d_array &xy, const ae_int_t nclasses, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fisherlda(xy.c_ptr(), npoints, nvars, nclasses, w.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +N-dimensional multiclass Fisher LDA + +Subroutine finds coefficients of linear combinations which optimally separates +training set on classes. It returns N-dimensional basis whose vector are sorted +by quality of training set separation (in descending order). + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - basis, array[NVars,NVars] + columns of matrix stores basis vectors, sorted by + quality of training set separation (in descending order) + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, real_2d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fisherldan(xy.c_ptr(), npoints, nvars, nclasses, w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +N-dimensional multiclass Fisher LDA + +Subroutine finds coefficients of linear combinations which optimally separates +training set on classes. It returns N-dimensional basis whose vector are sorted +by quality of training set separation (in descending order). + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - basis, array[NVars,NVars] + columns of matrix stores basis vectors, sorted by + quality of training set separation (in descending order) + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fisherldan(const real_2d_array &xy, const ae_int_t nclasses, real_2d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nvars; + + npoints = xy.rows(); + nvars = xy.cols()-1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fisherldan(xy.c_ptr(), npoints, nvars, nclasses, w.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +#endif + +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +DESCRIPTION: + +This function creates MCPD (Markov Chains for Population Data) solver. + +This solver can be used to find transition matrix P for N-dimensional +prediction problem where transition from X[i] to X[i+1] is modelled as + X[i+1] = P*X[i] +where X[i] and X[i+1] are N-dimensional population vectors (components of +each X are non-negative), and P is a N*N transition matrix (elements of P +are non-negative, each column sums to 1.0). + +Such models arise when when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is constant, i.e. there is no new individuals and no one + leaves population +* you want to model transitions of individuals from one state into another + +USAGE: + +Here we give very brief outline of the MCPD. We strongly recommend you to +read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on data analysis which is available at http://www.alglib.net/dataanalysis/ + +1. User initializes algorithm state with MCPDCreate() call + +2. User adds one or more tracks - sequences of states which describe + evolution of a system being modelled from different starting conditions + +3. User may add optional boundary, equality and/or linear constraints on + the coefficients of P by calling one of the following functions: + * MCPDSetEC() to set equality constraints + * MCPDSetBC() to set bound constraints + * MCPDSetLC() to set linear constraints + +4. Optionally, user may set custom weights for prediction errors (by + default, algorithm assigns non-equal, automatically chosen weights for + errors in the prediction of different components of X). It can be done + with a call of MCPDSetPredictionWeights() function. + +5. User calls MCPDSolve() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +6. User calls MCPDResults() to get solution + +INPUT PARAMETERS: + N - problem dimension, N>=1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreate(const ae_int_t n, mcpdstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdcreate(n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "entry" state and is treated +in a special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +Such conditions basically mean that row of P which corresponds to "entry" +state is zero. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - at every moment of time there is some + (unpredictable) amount of "new" individuals, which can transit into one + of the states at the next turn, but still no one leaves population +* you want to model transitions of individuals from one state into another +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdcreateentry(n, entrystate, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "exit" state and is treated +in a special way: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that column of P which corresponds to +"exit" state is zero. Multiplication by such P may decrease sum of vector +components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - individuals can move into "exit" state + and leave population at the next turn, but there are no new individuals +* amount of individuals which leave population can be predicted +* you want to model transitions of individuals from one state into another + (including transitions into the "exit" state) + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdcreateexit(n, exitstate, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-Exit-states" model, i.e. model where transition from X[i] to +X[i+1] is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +one selected component of X[] is called "entry" state and is treated in a +special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +and another one component of X[] is called "exit" state and is treated in +a special way too: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that: + row of P which corresponds to "entry" state is zero + column of P which corresponds to "exit" state is zero +Multiplication by such P may decrease sum of vector components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant +* at every moment of time there is some (unpredictable) amount of "new" + individuals, which can transit into one of the states at the next turn +* some individuals can move (predictably) into "exit" state and leave + population at the next turn +* you want to model transitions of individuals from one state into another, + including transitions from the "entry" state and into the "exit" state. +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdcreateentryexit(n, entrystate, exitstate, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to add a track - sequence of system states at the +different moments of its evolution. + +You may add one or several tracks to the MCPD solver. In case you have +several tracks, they won't overwrite each other. For example, if you pass +two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then +solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, +t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it +wont try to model transition from t=A+3 to t=B+1. + +INPUT PARAMETERS: + S - solver + XY - track, array[K,N]: + * I-th row is a state at t=I + * elements of XY must be non-negative (exception will be + thrown on negative elements) + K - number of points in a track + * if given, only leading K rows of XY are used + * if not given, automatically determined from size of XY + +NOTES: + +1. Track may contain either proportional or population data: + * with proportional data all rows of XY must sum to 1.0, i.e. we have + proportions instead of absolute population values + * with population data rows of XY contain population counts and generally + do not sum to 1.0 (although they still must be non-negative) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddtrack(mcpdstate &s, const real_2d_array &xy, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdaddtrack(s.c_ptr(), xy.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to add a track - sequence of system states at the +different moments of its evolution. + +You may add one or several tracks to the MCPD solver. In case you have +several tracks, they won't overwrite each other. For example, if you pass +two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then +solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, +t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it +wont try to model transition from t=A+3 to t=B+1. + +INPUT PARAMETERS: + S - solver + XY - track, array[K,N]: + * I-th row is a state at t=I + * elements of XY must be non-negative (exception will be + thrown on negative elements) + K - number of points in a track + * if given, only leading K rows of XY are used + * if not given, automatically determined from size of XY + +NOTES: + +1. Track may contain either proportional or population data: + * with proportional data all rows of XY must sum to 1.0, i.e. we have + proportions instead of absolute population values + * with population data rows of XY contain population counts and generally + do not sum to 1.0 (although they still must be non-negative) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcpdaddtrack(mcpdstate &s, const real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + + k = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdaddtrack(s.c_ptr(), xy.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place equality constraints on arbitrary +subset of elements of P. Set of constraints is specified by EC, which may +contain either NAN's or finite numbers from [0,1]. NAN denotes absence of +constraint, finite number denotes equality constraint on specific element +of P. + +You can also use MCPDAddEC() function which allows to ADD equality +constraint for one element of P without changing constraints for other +elements. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + EC - equality constraints, array[N,N]. Elements of EC can be + either NAN's or finite numbers from [0,1]. NAN denotes + absence of constraints, while finite value denotes + equality constraint on the corresponding element of P. + +NOTES: + +1. infinite values of EC will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetec(mcpdstate &s, const real_2d_array &ec, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsetec(s.c_ptr(), ec.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD equality constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetEC() function which allows you to specify +arbitrary set of equality constraints in one call. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + I - row index of element being constrained + J - column index of element being constrained + C - value (constraint for P[I,J]). Can be either NAN (no + constraint) or finite value from [0,1]. + +NOTES: + +1. infinite values of C will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddec(mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdaddec(s.c_ptr(), i, j, c, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to add bound constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place bound constraints on arbitrary +subset of elements of P. Set of constraints is specified by BndL/BndU +matrices, which may contain arbitrary combination of finite numbers or +infinities (like -INF=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD bound constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetBC() function which allows to place bound +constraints on arbitrary subset of elements of P. Set of constraints is +specified by BndL/BndU matrices, which may contain arbitrary combination +of finite numbers or infinities (like -INF=" (CT[i]>0). + +Your constraint may involve only some subset of P (less than N*N elements). +For example it can be something like + P[0,0] + P[0,1] = 0.5 +In this case you still should pass matrix with N*N+1 columns, but all its +elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. + +INPUT PARAMETERS: + S - solver + C - array[K,N*N+1] - coefficients of constraints + (see above for complete description) + CT - array[K] - constraint types + (see above for complete description) + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetlc(mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsetlc(s.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to set linear equality/inequality constraints on the +elements of the transition matrix P. + +This function can be used to set one or several general linear constraints +on the elements of P. Two types of constraints are supported: +* equality constraints +* inequality constraints (both less-or-equal and greater-or-equal) + +Coefficients of constraints are specified by matrix C (one of the +parameters). One row of C corresponds to one constraint. Because +transition matrix P has N*N elements, we need N*N columns to store all +coefficients (they are stored row by row), and one more column to store +right part - hence C has N*N+1 columns. Constraint kind is stored in the +CT array. + +Thus, I-th linear constraint is + P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] +where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). + +Your constraint may involve only some subset of P (less than N*N elements). +For example it can be something like + P[0,0] + P[0,1] = 0.5 +In this case you still should pass matrix with N*N+1 columns, but all its +elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. + +INPUT PARAMETERS: + S - solver + C - array[K,N*N+1] - coefficients of constraints + (see above for complete description) + CT - array[K] - constraint types + (see above for complete description) + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcpdsetlc(mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'mcpdsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsetlc(s.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function allows to tune amount of Tikhonov regularization being +applied to your problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change coefficient r. You can also change +prior values with MCPDSetPrior() function. + +INPUT PARAMETERS: + S - solver + V - regularization coefficient, finite non-negative value. It + is not recommended to specify zero value unless you are + pretty sure that you want it. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsettikhonovregularizer(mcpdstate &s, const double v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsettikhonovregularizer(s.c_ptr(), v, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function allows to set prior values used for regularization of your +problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change prior values prior_P. You can also +change r with MCPDSetTikhonovRegularizer() function. + +INPUT PARAMETERS: + S - solver + PP - array[N,N], matrix of prior values: + 1. elements must be real numbers from [0,1] + 2. columns must sum to 1.0. + First property is checked (exception is thrown otherwise), + while second one is not checked/enforced. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetprior(mcpdstate &s, const real_2d_array &pp, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsetprior(s.c_ptr(), pp.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to change prediction weights + +MCPD solver scales prediction errors as follows + Error(P) = ||W*(y-P*x)||^2 +where + x is a system state at time t + y is a system state at time t+1 + P is a transition matrix + W is a diagonal scaling matrix + +By default, weights are chosen in order to minimize relative prediction +error instead of absolute one. For example, if one component of state is +about 0.5 in magnitude and another one is about 0.05, then algorithm will +make corresponding weights equal to 2.0 and 20.0. + +INPUT PARAMETERS: + S - solver + PW - array[N], weights: + * must be non-negative values (exception will be thrown otherwise) + * zero values will be replaced by automatically chosen values + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetpredictionweights(mcpdstate &s, const real_1d_array &pw, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsetpredictionweights(s.c_ptr(), pw.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to start solution of the MCPD problem. + +After return from this function, you can use MCPDResults() to get solution +and completion code. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsolve(mcpdstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdsolve(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +MCPD results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - array[N,N], transition matrix + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one. Speaking short, positive values denote + success, negative ones are failures. + More information about fields of this structure can be + found in the comments on MCPDReport datatype. + + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcpdresults(s.c_ptr(), p.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This structure is a MCPD (Markov Chains for Population Data) solver. + +You should use ALGLIB functions in order to work with this object. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +_mcpdstate_owner::_mcpdstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcpdstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcpdstate)); + alglib_impl::_mcpdstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcpdstate_owner::_mcpdstate_owner(alglib_impl::mcpdstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mcpdstate_owner::_mcpdstate_owner(const _mcpdstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcpdstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcpdstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mcpdstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcpdstate)); + alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcpdstate_owner& _mcpdstate_owner::operator=(const _mcpdstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mcpdstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcpdstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mcpdstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mcpdstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mcpdstate)); + alglib_impl::_mcpdstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mcpdstate_owner::~_mcpdstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mcpdstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mcpdstate* _mcpdstate_owner::c_ptr() const +{ + return p_struct; +} +mcpdstate::mcpdstate() : _mcpdstate_owner() +{ +} + +mcpdstate::mcpdstate(alglib_impl::mcpdstate *attach_to):_mcpdstate_owner(attach_to) +{ +} + +mcpdstate::mcpdstate(const mcpdstate &rhs):_mcpdstate_owner(rhs) +{ +} + +mcpdstate& mcpdstate::operator=(const mcpdstate &rhs) +{ + if( this==&rhs ) + return *this; + _mcpdstate_owner::operator=(rhs); + return *this; +} + +mcpdstate::~mcpdstate() +{ +} + + + + +/************************************************************************* +This structure is a MCPD training report: + InnerIterationsCount - number of inner iterations of the + underlying optimization algorithm + OuterIterationsCount - number of outer iterations of the + underlying optimization algorithm + NFEV - number of merit function evaluations + TerminationType - termination type + (same as for MinBLEIC optimizer, positive + values denote success, negative ones - + failure) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +_mcpdreport_owner::_mcpdreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcpdreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcpdreport)); + alglib_impl::_mcpdreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcpdreport_owner::_mcpdreport_owner(alglib_impl::mcpdreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mcpdreport_owner::_mcpdreport_owner(const _mcpdreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcpdreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcpdreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mcpdreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcpdreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcpdreport)); + alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcpdreport_owner& _mcpdreport_owner::operator=(const _mcpdreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mcpdreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcpdreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mcpdreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mcpdreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mcpdreport)); + alglib_impl::_mcpdreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mcpdreport_owner::~_mcpdreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mcpdreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mcpdreport* _mcpdreport_owner::c_ptr() const +{ + return p_struct; +} +mcpdreport::mcpdreport() : _mcpdreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mcpdreport::mcpdreport(alglib_impl::mcpdreport *attach_to):_mcpdreport_owner(attach_to) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mcpdreport::mcpdreport(const mcpdreport &rhs):_mcpdreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mcpdreport& mcpdreport::operator=(const mcpdreport &rhs) +{ + if( this==&rhs ) + return *this; + _mcpdreport_owner::operator=(rhs); + return *this; +} + +mcpdreport::~mcpdreport() +{ +} +#endif + +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine trains logit model. + +INPUT PARAMETERS: + XY - training set, array[0..NPoints-1,0..NVars] + First NVars columns store values of independent + variables, next column stores number of class (from 0 + to NClasses-1) which dataset element belongs to. Fractional + values are rounded to nearest integer. + NPoints - training set size, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_logitmodel_owner& _logitmodel_owner::operator=(const _logitmodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: logitmodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: logitmodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: logitmodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_logitmodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::logitmodel)); + alglib_impl::_logitmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_logitmodel_owner::~_logitmodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_logitmodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::logitmodel* _logitmodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::logitmodel* _logitmodel_owner::c_ptr() const +{ + return p_struct; +} +logitmodel::logitmodel() : _logitmodel_owner() +{ +} + +logitmodel::logitmodel(alglib_impl::logitmodel *attach_to):_logitmodel_owner(attach_to) +{ +} + +logitmodel::logitmodel(const logitmodel &rhs):_logitmodel_owner(rhs) +{ +} + +logitmodel& logitmodel::operator=(const logitmodel &rhs) +{ + if( this==&rhs ) + return *this; + _logitmodel_owner::operator=(rhs); + return *this; +} + +logitmodel::~logitmodel() +{ +} + + + + +/************************************************************************* +MNLReport structure contains information about training process: +* NGrad - number of gradient calculations +* NHess - number of Hessian calculations +*************************************************************************/ +_mnlreport_owner::_mnlreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mnlreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mnlreport)); + alglib_impl::_mnlreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mnlreport_owner::_mnlreport_owner(alglib_impl::mnlreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mnlreport_owner::_mnlreport_owner(const _mnlreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mnlreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mnlreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mnlreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mnlreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mnlreport)); + alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mnlreport_owner& _mnlreport_owner::operator=(const _mnlreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mnlreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mnlreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mnlreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mnlreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mnlreport)); + alglib_impl::_mnlreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mnlreport_owner::~_mnlreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mnlreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mnlreport* _mnlreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mnlreport* _mnlreport_owner::c_ptr() const +{ + return p_struct; +} +mnlreport::mnlreport() : _mnlreport_owner() ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) +{ +} + +mnlreport::mnlreport(alglib_impl::mnlreport *attach_to):_mnlreport_owner(attach_to) ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) +{ +} + +mnlreport::mnlreport(const mnlreport &rhs):_mnlreport_owner(rhs) ,ngrad(p_struct->ngrad),nhess(p_struct->nhess) +{ +} + +mnlreport& mnlreport::operator=(const mnlreport &rhs) +{ + if( this==&rhs ) + return *this; + _mnlreport_owner::operator=(rhs); + return *this; +} + +mnlreport::~mnlreport() +{ +} +#endif + +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void knnserialize(const knnmodel &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::knnalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::knnserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void knnserialize(const knnmodel &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::knnalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::knnserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void knnunserialize(const std::string &s_in, knnmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::knnunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void knnunserialize(const std::istream &s_in, knnmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::knnunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel KNN requests. + +KNN subpackage provides two sets of computing functions - ones which use +internal buffer of KNN model (these functions are single-threaded because +they use same buffer, which can not shared between threads), and ones +which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + Model - KNN model which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with model which was used to + initialize buffer. Any attempt to use buffer with different + object is dangerous - you may get integrity check failure + (exception) because sizes of internal arrays do not fit to + dimensions of the model structure. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knncreatebuffer(const knnmodel &model, knnbuffer &buf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knncreatebuffer(model.c_ptr(), buf.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine creates KNNBuilder object which is used to train KNN models. + +By default, new builder stores empty dataset and some reasonable default +settings. At the very least, you should specify dataset prior to building +KNN model. You can also tweak settings of the model construction algorithm +(recommended, although default settings should work well). + +Following actions are mandatory: +* calling knnbuildersetdataset() to specify dataset +* calling knnbuilderbuildknnmodel() to build KNN model using current + dataset and default settings + +Additionally, you may call: +* knnbuildersetnorm() to change norm being used + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildercreate(knnbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnbuildercreate(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Specifies regression problem (one or more continuous output variables are +predicted). There also exists "classification" version of this function. + +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the KNN construction algorithm will be invoked. + +INPUT PARAMETERS: + S - KNN builder object + XY - array[NPoints,NVars+NOut] (note: actual size can be + larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * next NOut elements store values of the dependent + variables + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NOut - number of dependent variables, NOut>=1 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetreg(knnbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nout, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnbuildersetdatasetreg(s.c_ptr(), xy.c_ptr(), npoints, nvars, nout, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Specifies classification problem (two or more classes are predicted). +There also exists "regression" version of this function. + +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the KNN construction algorithm will be invoked. + +INPUT PARAMETERS: + S - KNN builder object + XY - array[NPoints,NVars+1] (note: actual size can be + larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * next element stores class index, in [0,NClasses) + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetcls(knnbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnbuildersetdatasetcls(s.c_ptr(), xy.c_ptr(), npoints, nvars, nclasses, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets norm type used for neighbor search. + +INPUT PARAMETERS: + S - decision forest builder object + NormType - norm type: + * 0 inf-norm + * 1 1-norm + * 2 Euclidean norm (default) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetnorm(knnbuilder &s, const ae_int_t nrmtype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnbuildersetnorm(s.c_ptr(), nrmtype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds KNN model according to current settings, using +dataset internally stored in the builder object. + +The model being built performs inference using Eps-approximate K nearest +neighbors search algorithm, with: +* K=1, Eps=0 corresponding to the "nearest neighbor algorithm" +* K>1, Eps=0 corresponding to the "K nearest neighbors algorithm" +* K>=1, Eps>0 corresponding to "approximate nearest neighbors algorithm" + +An approximate KNN is a good option for high-dimensional datasets (exact +KNN works slowly when dimensions count grows). + +An ALGLIB implementation of kd-trees is used to perform k-nn searches. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - KNN builder object + K - number of neighbors to search for, K>=1 + Eps - approximation factor: + * Eps=0 means that exact kNN search is performed + * Eps>0 means that (1+Eps)-approximate search is performed + +OUTPUT PARAMETERS: + Model - KNN model + Rep - report + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuilderbuildknnmodel(knnbuilder &s, const ae_int_t k, const double eps, knnmodel &model, knnreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnbuilderbuildknnmodel(s.c_ptr(), k, eps, model.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Changing search settings of KNN model. + +K and EPS parameters of KNN (AKNN) search are specified during model +construction. However, plain KNN algorithm with Euclidean distance allows +you to change them at any moment. + +NOTE: future versions of KNN model may support advanced versions of KNN, + such as NCA or LMNN. It is possible that such algorithms won't allow + you to change search settings on the fly. If you call this function + for an algorithm which does not support on-the-fly changes, it will + throw an exception. + +INPUT PARAMETERS: + Model - KNN model + K - K>=1, neighbors count + EPS - accuracy of the EPS-approximate NN search. Set to 0.0, if + you want to perform "classic" KNN search. Specify larger + values if you need to speed-up high-dimensional KNN + queries. + +OUTPUT PARAMETERS: + nothing on success, exception on failure + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnrewritekeps(knnmodel &model, const ae_int_t k, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnrewritekeps(model.c_ptr(), k, eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inference using KNN model. + +See also knnprocess0(), knnprocessi() and knnclassify() for options with a +bit more convenient interface. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + Y - possible preallocated buffer. Reused if long enough. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocess(knnmodel &model, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnprocess(model.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for knnprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnprocess0(knnmodel &model, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnprocess0(model.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling knnprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t knnclassify(knnmodel &model, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::knnclassify(model.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +'interactive' variant of knnprocess() for languages like Python which +support constructs like "y = knnprocessi(model,x)" and interactive mode of +the interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocessi(knnmodel &model, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnprocessi(model.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same KNN model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + Model - KNN model + Buf - buffer object, must be allocated specifically for this + model with knncreatebuffer(). + X - input vector, array[NVars] + +OUTPUT PARAMETERS: + Y - result, array[NOut]. Regression estimate when solving + regression task, vector of posterior probabilities for + a classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knntsprocess(const knnmodel &model, knnbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knntsprocess(model.c_ptr(), buf.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrelclserror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnrelclserror(model.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/NPoints. + Zero if model solves regression task. + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgce(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnavgce(model.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +RMS error on the test set. + +Its meaning for regression task is obvious. As for classification problems, +RMS error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrmserror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnrmserror(model.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgerror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnavgerror(model.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Average relative error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average relative error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average relative error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgrelerror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::knnavgrelerror(model.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculates all kinds of errors for the model in one call. + +INPUT PARAMETERS: + Model - KNN model + XY - test set: + * one row per point + * first NVars columns store independent variables + * depending on problem type: + * next column stores class number in [0,NClasses) - for + classification problems + * next NOut columns store dependent variables - for + regression problems + NPoints - test set size, NPoints>=0 + +OUTPUT PARAMETERS: + Rep - following fields are loaded with errors for both regression + and classification models: + * rep.rmserror - RMS error for the output + * rep.avgerror - average error + * rep.avgrelerror - average relative error + following fields are set only for classification models, + zero for regression ones: + * relclserror - relative classification error, in [0,1] + * avgce - average cross-entropy in bits per dataset entry + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnallerrors(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, knnreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::knnallerrors(model.c_ptr(), xy.c_ptr(), npoints, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Buffer object which is used to perform various requests (usually model +inference) in the multithreaded mode (multiple threads working with same +KNN object). + +This object should be created with KNNCreateBuffer(). +*************************************************************************/ +_knnbuffer_owner::_knnbuffer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::knnbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnbuffer)); + alglib_impl::_knnbuffer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnbuffer_owner::_knnbuffer_owner(alglib_impl::knnbuffer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_knnbuffer_owner::_knnbuffer_owner(const _knnbuffer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnbuffer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::knnbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnbuffer)); + alglib_impl::_knnbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnbuffer_owner& _knnbuffer_owner::operator=(const _knnbuffer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: knnbuffer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnbuffer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: knnbuffer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_knnbuffer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::knnbuffer)); + alglib_impl::_knnbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_knnbuffer_owner::~_knnbuffer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_knnbuffer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::knnbuffer* _knnbuffer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::knnbuffer* _knnbuffer_owner::c_ptr() const +{ + return p_struct; +} +knnbuffer::knnbuffer() : _knnbuffer_owner() +{ +} + +knnbuffer::knnbuffer(alglib_impl::knnbuffer *attach_to):_knnbuffer_owner(attach_to) +{ +} + +knnbuffer::knnbuffer(const knnbuffer &rhs):_knnbuffer_owner(rhs) +{ +} + +knnbuffer& knnbuffer::operator=(const knnbuffer &rhs) +{ + if( this==&rhs ) + return *this; + _knnbuffer_owner::operator=(rhs); + return *this; +} + +knnbuffer::~knnbuffer() +{ +} + + + + +/************************************************************************* +A KNN builder object; this object encapsulates dataset and all related +settings, it is used to create an actual instance of KNN model. +*************************************************************************/ +_knnbuilder_owner::_knnbuilder_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::knnbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnbuilder)); + alglib_impl::_knnbuilder_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnbuilder_owner::_knnbuilder_owner(alglib_impl::knnbuilder *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_knnbuilder_owner::_knnbuilder_owner(const _knnbuilder_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnbuilder copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::knnbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnbuilder)); + alglib_impl::_knnbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnbuilder_owner& _knnbuilder_owner::operator=(const _knnbuilder_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: knnbuilder assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnbuilder assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: knnbuilder assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_knnbuilder_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::knnbuilder)); + alglib_impl::_knnbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_knnbuilder_owner::~_knnbuilder_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_knnbuilder_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::knnbuilder* _knnbuilder_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::knnbuilder* _knnbuilder_owner::c_ptr() const +{ + return p_struct; +} +knnbuilder::knnbuilder() : _knnbuilder_owner() +{ +} + +knnbuilder::knnbuilder(alglib_impl::knnbuilder *attach_to):_knnbuilder_owner(attach_to) +{ +} + +knnbuilder::knnbuilder(const knnbuilder &rhs):_knnbuilder_owner(rhs) +{ +} + +knnbuilder& knnbuilder::operator=(const knnbuilder &rhs) +{ + if( this==&rhs ) + return *this; + _knnbuilder_owner::operator=(rhs); + return *this; +} + +knnbuilder::~knnbuilder() +{ +} + + + + +/************************************************************************* +KNN model, can be used for classification or regression +*************************************************************************/ +_knnmodel_owner::_knnmodel_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::knnmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnmodel)); + alglib_impl::_knnmodel_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnmodel_owner::_knnmodel_owner(alglib_impl::knnmodel *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_knnmodel_owner::_knnmodel_owner(const _knnmodel_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnmodel copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::knnmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnmodel)); + alglib_impl::_knnmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnmodel_owner& _knnmodel_owner::operator=(const _knnmodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: knnmodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnmodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: knnmodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_knnmodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::knnmodel)); + alglib_impl::_knnmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_knnmodel_owner::~_knnmodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_knnmodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::knnmodel* _knnmodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::knnmodel* _knnmodel_owner::c_ptr() const +{ + return p_struct; +} +knnmodel::knnmodel() : _knnmodel_owner() +{ +} + +knnmodel::knnmodel(alglib_impl::knnmodel *attach_to):_knnmodel_owner(attach_to) +{ +} + +knnmodel::knnmodel(const knnmodel &rhs):_knnmodel_owner(rhs) +{ +} + +knnmodel& knnmodel::operator=(const knnmodel &rhs) +{ + if( this==&rhs ) + return *this; + _knnmodel_owner::operator=(rhs); + return *this; +} + +knnmodel::~knnmodel() +{ +} + + + + +/************************************************************************* +KNN training report. + +Following fields store training set errors: +* relclserror - fraction of misclassified cases, [0,1] +* avgce - average cross-entropy in bits per symbol +* rmserror - root-mean-square error +* avgerror - average error +* avgrelerror - average relative error + +For classification problems: +* RMS, AVG and AVGREL errors are calculated for posterior probabilities + +For regression problems: +* RELCLS and AVGCE errors are zero +*************************************************************************/ +_knnreport_owner::_knnreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::knnreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnreport)); + alglib_impl::_knnreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnreport_owner::_knnreport_owner(alglib_impl::knnreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_knnreport_owner::_knnreport_owner(const _knnreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_knnreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::knnreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::knnreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::knnreport)); + alglib_impl::_knnreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_knnreport_owner& _knnreport_owner::operator=(const _knnreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: knnreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: knnreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: knnreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_knnreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::knnreport)); + alglib_impl::_knnreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_knnreport_owner::~_knnreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_knnreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::knnreport* _knnreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::knnreport* _knnreport_owner::c_ptr() const +{ + return p_struct; +} +knnreport::knnreport() : _knnreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +knnreport::knnreport(alglib_impl::knnreport *attach_to):_knnreport_owner(attach_to) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +knnreport::knnreport(const knnreport &rhs):_knnreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +knnreport& knnreport::operator=(const knnreport &rhs) +{ + if( this==&rhs ) + return *this; + _knnreport_owner::operator=(rhs); + return *this; +} + +knnreport::~knnreport() +{ +} +#endif + +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Neural network training using modified Levenberg-Marquardt with exact +Hessian calculation and regularization. Subroutine trains neural network +with restarts from random positions. Algorithm is well suited for small +and medium scale problems (hundreds of weights). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -9, if internal matrix inverse subroutine failed + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlm(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlptrainlm(network.c_ptr(), xy.c_ptr(), npoints, decay, restarts, &info, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Neural network training using L-BFGS algorithm with regularization. +Subroutine trains neural network with restarts from random positions. +Algorithm is well suited for problems of any dimensionality (memory +requirements and step complexity are linear by weights number). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + MaxIts - stopping criterion. Algorithm stops after MaxIts + iterations (NOT gradient calculations). Zero MaxIts + means stopping when step is sufficiently small. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlbfgs(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlptrainlbfgs(network.c_ptr(), xy.c_ptr(), npoints, decay, restarts, wstep, maxits, &info, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Neural network training using early stopping (base algorithm - L-BFGS with +regularization). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + TrnXY - training set + TrnSize - training set size, TrnSize>0 + ValXY - validation set + ValSize - validation set size, ValSize>0 + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts, either: + * strictly positive number - algorithm make specified + number of restarts from random position. + * -1, in which case algorithm makes exactly one run + from the initial state of the network (no randomization). + If you don't know what Restarts to choose, choose one + one the following: + * -1 (deterministic start) + * +1 (one random restart) + * +5 (moderate amount of random restarts) + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1, ...). + * 2, task has been solved, stopping criterion met - + sufficiently small step size. Not expected (we + use EARLY stopping) but possible and not an + error. + * 6, task has been solved, stopping criterion met - + increasing of validation set error. + Rep - training report + +NOTE: + +Algorithm stops if validation set error increases for a long enough or +step size is small enought (there are task where validation set may +decrease for eternity). In any case solution returned corresponds to the +minimum of validation set error. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptraines(multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlptraines(network.c_ptr(), trnxy.c_ptr(), trnsize, valxy.c_ptr(), valsize, decay, restarts, &info, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - L-BFGS. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpkfoldcvlbfgs(network.c_ptr(), xy.c_ptr(), npoints, decay, restarts, wstep, maxits, foldscount, &info, rep.c_ptr(), cvrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - Levenberg-Marquardt. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpkfoldcvlm(network.c_ptr(), xy.c_ptr(), npoints, decay, restarts, foldscount, &info, rep.c_ptr(), cvrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function estimates generalization error using cross-validation on the +current dataset with current training settings. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. Network is not changed during cross- + validation and is not trained - it is used only as + representative of its architecture. I.e., we estimate + generalization properties of ARCHITECTURE, not some + specific network. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that for each cross-validation + round specified number of random restarts is + performed, with best network being chosen after + training. + * NRestarts=0 is same as NRestarts=1 + FoldsCount - number of folds in k-fold cross-validation: + * 2<=FoldsCount<=size of dataset + * recommended value: 10. + * values larger than dataset size will be silently + truncated down to dataset size + +OUTPUT PARAMETERS: + Rep - structure which contains cross-validation estimates: + * Rep.RelCLSError - fraction of misclassified cases. + * Rep.AvgCE - acerage cross-entropy + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average error + * Rep.AvgRelError - average relative error + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or subset with only one point was given, zeros are returned as + estimates. + +NOTE: this method performs FoldsCount cross-validation rounds, each one + with NRestarts random starts. Thus, FoldsCount*NRestarts networks + are trained in total. + +NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. + +NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError + contain errors in prediction of posterior probabilities. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcv(mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpkfoldcv(s.c_ptr(), network.c_ptr(), nrestarts, foldscount, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creation of the network trainer object for regression networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NOut - number of outputs, NOut>=1 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any regression + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreatetrainer(nin, nout, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Creation of the network trainer object for classification networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any classification + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpcreatetrainercls(nin, nclasses, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user. + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. + NPoints - points count, >=0. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdataset(mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetdataset(s.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user (sparse matrix is used to store dataset). + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Any sparse storage format can be used: + Hash-table, CRS... + NPoints - points count, >=0 + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetsparsedataset(mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetsparsedataset(s.c_ptr(), xy.c_ptr(), npoints, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets weight decay coefficient which is used for training. + +INPUT PARAMETERS: + S - trainer object + Decay - weight decay coefficient, >=0. Weight decay term + 'Decay*||Weights||^2' is added to error function. If + you don't know what Decay to choose, use 1.0E-3. + Weight decay can be set to zero, in this case network + is trained without weight decay. + +NOTE: by default network uses some small nonzero value for weight decay. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdecay(mlptrainer &s, const double decay, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetdecay(s.c_ptr(), decay, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping criteria for the optimizer. + +INPUT PARAMETERS: + S - trainer object + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + WStep>=0. + MaxIts - stopping criterion. Algorithm stops after MaxIts + epochs (full passes over entire dataset). Zero MaxIts + means stopping when step is sufficiently small. + MaxIts>=0. + +NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also + used when MLPSetCond() is called with WStep=0 and MaxIts=0. + +NOTE: these stopping criteria are used for all kinds of neural training - + from "conventional" networks to early stopping ensembles. When used + for "conventional" networks, they are used as the only stopping + criteria. When combined with early stopping, they used as ADDITIONAL + stopping criteria which can terminate early stopping algorithm. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetcond(mlptrainer &s, const double wstep, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetcond(s.c_ptr(), wstep, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets training algorithm: batch training using L-BFGS will be +used. + +This algorithm: +* the most robust for small-scale problems, but may be too slow for large + scale ones. +* perfoms full pass through the dataset before performing step +* uses conditions specified by MLPSetCond() for stopping +* is default one used by trainer object + +INPUT PARAMETERS: + S - trainer object + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetalgobatch(mlptrainer &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpsetalgobatch(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function trains neural network passed to this function, using current +dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) +and current training settings. Training from NRestarts random starting +positions is performed, best network is chosen. + +Training is performed using current training algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed, best network is chosen after + training + * NRestarts=0 means that current state of the network + is used for training. + +OUTPUT PARAMETERS: + Network - trained network + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + network is filled by zero values. Same behavior for functions + MLPStartTraining and MLPContinueTraining. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainnetwork(mlptrainer &s, multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlptrainnetwork(s.c_ptr(), network.c_ptr(), nrestarts, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +After call to this function trainer object remembers network and is ready +to train it. However, no training is performed until first call to +MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() +will advance training progress one iteration further. + +EXAMPLE: + > + > ...initialize network and trainer object.... + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > ...visualize training progress... + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + RandomStart - randomize network before training or not: + * True means that network is randomized and its + initial state (one which was passed to the trainer + object) is lost. + * False means that training is started from the + current state of the network + +OUTPUT PARAMETERS: + Network - neural network which is ready to training (weights are + initialized, preprocessor is initialized using current + training set) + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpstarttraining(mlptrainer &s, multilayerperceptron &network, const bool randomstart, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpstarttraining(s.c_ptr(), network.c_ptr(), randomstart, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +This function performs one more iteration of the training and returns +either True (training continues) or False (training stopped). In case True +was returned, Network weights are updated according to the current state +of the optimization progress. In case False was returned, no additional +updates is performed (previous update of the network weights moved us to +the final point, and no additional updates is needed). + +EXAMPLE: + > + > [initialize network and trainer object] + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > [visualize training progress] + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network structure, which is used to store + current state of the training process. + +OUTPUT PARAMETERS: + Network - weights of the neural network are rewritten by the + current approximation. + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + +NOTE: It is expected that Network is the same one which was passed to + MLPStartTraining() function. However, THIS function checks only + following: + * that number of network inputs is consistent with trainer object + settings + * that number of network outputs/classes is consistent with trainer + object settings + * that number of network weights is the same as number of weights in + the network passed to MLPStartTraining() function + Exception is thrown when these conditions are violated. + + It is also expected that you do not change state of the network on + your own - the only party who has right to change network during its + training is a trainer object. Any attempt to interfere with trainer + may lead to unpredictable results. + + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +bool mlpcontinuetraining(mlptrainer &s, multilayerperceptron &network, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mlpcontinuetraining(s.c_ptr(), network.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +Modified Levenberg-Marquardt algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglm(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpebagginglm(ensemble.c_ptr(), xy.c_ptr(), npoints, decay, restarts, &info, rep.c_ptr(), ooberrors.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +L-BFGS algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglbfgs(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpebagginglbfgs(ensemble.c_ptr(), xy.c_ptr(), npoints, decay, restarts, wstep, maxits, &info, rep.c_ptr(), ooberrors.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Training neural networks ensemble using early stopping. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 6, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpetraines(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlpetraines(ensemble.c_ptr(), xy.c_ptr(), npoints, decay, restarts, &info, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function trains neural network ensemble passed to this function using +current dataset and early stopping training algorithm. Each early stopping +round performs NRestarts random restarts (thus, EnsembleSize*NRestarts +training rounds is performed in total). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object; + Ensemble - neural network ensemble. It must have same number of + inputs and outputs/classes as was specified during + creation of the trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed during each ES round; + * NRestarts=0 is silently replaced by 1. + +OUTPUT PARAMETERS: + Ensemble - trained ensemble; + Rep - it contains all type of errors. + +NOTE: this training method uses BOTH early stopping and weight decay! So, + you should select weight decay before starting training just as you + select it before training "conventional" networks. + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or single-point dataset was passed, ensemble is filled by zero + values. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 22.08.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainensemblees(mlptrainer &s, mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mlptrainensemblees(s.c_ptr(), ensemble.c_ptr(), nrestarts, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Training report: + * RelCLSError - fraction of misclassified cases. + * AvgCE - acerage cross-entropy + * RMSError - root-mean-square error + * AvgError - average error + * AvgRelError - average relative error + * NGrad - number of gradient calculations + * NHess - number of Hessian calculations + * NCholesky - number of Cholesky decompositions + +NOTE 1: RelCLSError/AvgCE are zero on regression problems. + +NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain + errors in prediction of posterior probabilities +*************************************************************************/ +_mlpreport_owner::_mlpreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpreport)); + alglib_impl::_mlpreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpreport_owner::_mlpreport_owner(alglib_impl::mlpreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mlpreport_owner::_mlpreport_owner(const _mlpreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpreport)); + alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpreport_owner& _mlpreport_owner::operator=(const _mlpreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mlpreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mlpreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mlpreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mlpreport)); + alglib_impl::_mlpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mlpreport_owner::~_mlpreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mlpreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mlpreport* _mlpreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mlpreport* _mlpreport_owner::c_ptr() const +{ + return p_struct; +} +mlpreport::mlpreport() : _mlpreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +mlpreport::mlpreport(alglib_impl::mlpreport *attach_to):_mlpreport_owner(attach_to) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +mlpreport::mlpreport(const mlpreport &rhs):_mlpreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +mlpreport& mlpreport::operator=(const mlpreport &rhs) +{ + if( this==&rhs ) + return *this; + _mlpreport_owner::operator=(rhs); + return *this; +} + +mlpreport::~mlpreport() +{ +} + + + + +/************************************************************************* +Cross-validation estimates of generalization error +*************************************************************************/ +_mlpcvreport_owner::_mlpcvreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpcvreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpcvreport)); + alglib_impl::_mlpcvreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpcvreport_owner::_mlpcvreport_owner(alglib_impl::mlpcvreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mlpcvreport_owner::_mlpcvreport_owner(const _mlpcvreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlpcvreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpcvreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mlpcvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlpcvreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlpcvreport)); + alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlpcvreport_owner& _mlpcvreport_owner::operator=(const _mlpcvreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mlpcvreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlpcvreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mlpcvreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mlpcvreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mlpcvreport)); + alglib_impl::_mlpcvreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mlpcvreport_owner::~_mlpcvreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mlpcvreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mlpcvreport* _mlpcvreport_owner::c_ptr() const +{ + return p_struct; +} +mlpcvreport::mlpcvreport() : _mlpcvreport_owner() ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +mlpcvreport::mlpcvreport(alglib_impl::mlpcvreport *attach_to):_mlpcvreport_owner(attach_to) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +mlpcvreport::mlpcvreport(const mlpcvreport &rhs):_mlpcvreport_owner(rhs) ,relclserror(p_struct->relclserror),avgce(p_struct->avgce),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror) +{ +} + +mlpcvreport& mlpcvreport::operator=(const mlpcvreport &rhs) +{ + if( this==&rhs ) + return *this; + _mlpcvreport_owner::operator=(rhs); + return *this; +} + +mlpcvreport::~mlpcvreport() +{ +} + + + + +/************************************************************************* +Trainer object for neural network. + +You should not try to access fields of this object directly - use ALGLIB +functions to work with this object. +*************************************************************************/ +_mlptrainer_owner::_mlptrainer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlptrainer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlptrainer)); + alglib_impl::_mlptrainer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlptrainer_owner::_mlptrainer_owner(alglib_impl::mlptrainer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mlptrainer_owner::_mlptrainer_owner(const _mlptrainer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mlptrainer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlptrainer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mlptrainer*)alglib_impl::ae_malloc(sizeof(alglib_impl::mlptrainer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mlptrainer)); + alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mlptrainer_owner& _mlptrainer_owner::operator=(const _mlptrainer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mlptrainer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mlptrainer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mlptrainer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mlptrainer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mlptrainer)); + alglib_impl::_mlptrainer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mlptrainer_owner::~_mlptrainer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mlptrainer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mlptrainer* _mlptrainer_owner::c_ptr() const +{ + return p_struct; +} +mlptrainer::mlptrainer() : _mlptrainer_owner() +{ +} + +mlptrainer::mlptrainer(alglib_impl::mlptrainer *attach_to):_mlptrainer_owner(attach_to) +{ +} + +mlptrainer::mlptrainer(const mlptrainer &rhs):_mlptrainer_owner(rhs) +{ +} + +mlptrainer& mlptrainer::operator=(const mlptrainer &rhs) +{ + if( this==&rhs ) + return *this; + _mlptrainer_owner::operator=(rhs); + return *this; +} + +mlptrainer::~mlptrainer() +{ +} +#endif + +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +k-means++ clusterization. +Backward compatibility function, we recommend to use CLUSTERING subpackage +as better replacement. + + -- ALGLIB -- + Copyright 21.03.2009 by Bochkanov Sergey +*************************************************************************/ +void kmeansgenerate(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t k, const ae_int_t restarts, ae_int_t &info, real_2d_array &c, integer_1d_array &xyc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::kmeansgenerate(xy.c_ptr(), npoints, nvars, k, restarts, &info, c.c_ptr(), xyc.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_BDSS) || !defined(AE_PARTIAL_BUILD) +static double bdss_xlny(double x, double y, ae_state *_state); +static double bdss_getcv(/* Integer */ const ae_vector* cnt, + ae_int_t nc, + ae_state *_state); +static void bdss_tieaddc(/* Integer */ const ae_vector* c, + /* Integer */ const ae_vector* ties, + ae_int_t ntie, + ae_int_t nc, + /* Integer */ ae_vector* cnt, + ae_state *_state); +static void bdss_tiesubc(/* Integer */ const ae_vector* c, + /* Integer */ const ae_vector* ties, + ae_int_t ntie, + ae_int_t nc, + /* Integer */ ae_vector* cnt, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +static ae_int_t mlpbase_mlpvnum = 7; +static ae_int_t mlpbase_mlpfirstversion = 0; +static ae_int_t mlpbase_nfieldwidth = 4; +static ae_int_t mlpbase_hlconnfieldwidth = 5; +static ae_int_t mlpbase_hlnfieldwidth = 4; +static ae_int_t mlpbase_gradbasecasecost = 50000; +static ae_int_t mlpbase_microbatchsize = 64; +static void mlpbase_addinputlayer(ae_int_t ncount, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state); +static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state); +static void mlpbase_addactivationlayer(ae_int_t functype, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state); +static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state); +static void mlpbase_hladdinputlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t nin, + ae_state *_state); +static void mlpbase_hladdoutputlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t* weightsidx, + ae_int_t k, + ae_int_t nprev, + ae_int_t nout, + ae_bool iscls, + ae_bool islinearout, + ae_state *_state); +static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t* weightsidx, + ae_int_t k, + ae_int_t nprev, + ae_int_t ncur, + ae_state *_state); +static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, + ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_bool iscls, + ae_bool islinearout, + ae_state *_state); +static void mlpbase_mlpcreate(ae_int_t nin, + ae_int_t nout, + /* Integer */ const ae_vector* lsizes, + /* Integer */ const ae_vector* ltypes, + /* Integer */ const ae_vector* lconnfirst, + /* Integer */ const ae_vector* lconnlast, + ae_int_t layerscount, + ae_bool isclsnet, + multilayerperceptron* network, + ae_state *_state); +static void mlpbase_mlpgetneuroninfox(const multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + /* Integer */ ae_vector* integerbuf, + ae_int_t* fkind, + double* threshold, + ae_state *_state); +static double mlpbase_mlpgetweightx(const multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + /* Integer */ ae_vector* integerbuf, + ae_state *_state); +static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_bool naturalerr, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state); +static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, + /* Real */ const ae_vector* neurons, + /* Real */ const ae_vector* weights, + /* Real */ ae_vector* derror, + /* Real */ ae_vector* grad, + ae_bool naturalerrorfunc, + ae_state *_state); +static void mlpbase_mlpchunkedgradient(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + double* e, + ae_bool naturalerrorfunc, + ae_state *_state); +static void mlpbase_mlpchunkedprocess(const multilayerperceptron* network, + /* Real */ ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + ae_state *_state); +static double mlpbase_safecrossentropy(double t, + double z, + ae_state *_state); +static void mlpbase_randomizebackwardpass(multilayerperceptron* network, + ae_int_t neuronidx, + double v, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +static ae_int_t mlpe_mlpefirstversion = 1; + + +#endif +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +static ae_int_t clustering_kmeansblocksize = 32; +static ae_int_t clustering_kmeansparalleldim = 8; +static ae_int_t clustering_kmeansparallelk = 4; +static double clustering_complexitymultiplier = 1.0; +static void clustering_selectinitialcenters(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t initalgo, + hqrndstate* rs, + ae_int_t k, + /* Real */ ae_matrix* ct, + apbuffers* initbuf, + ae_shared_pool* updatepool, + ae_state *_state); +static ae_bool clustering_fixcenters(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + /* Real */ ae_matrix* ct, + ae_int_t k, + apbuffers* initbuf, + ae_shared_pool* updatepool, + ae_state *_state); +static void clustering_clusterizerrunahcinternal(clusterizerstate* s, + /* Real */ ae_matrix* d, + ahcreport* rep, + ae_state *_state); +static void clustering_evaluatedistancematrixrec(/* Real */ const ae_matrix* xy, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, + ae_state *_state); +ae_bool _trypexec_clustering_evaluatedistancematrixrec(/* Real */ const ae_matrix* xy, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) +static ae_int_t dforest_innernodewidth = 3; +static ae_int_t dforest_leafnodewidth = 2; +static ae_int_t dforest_dfusestrongsplits = 1; +static ae_int_t dforest_dfuseevs = 2; +static ae_int_t dforest_dfuncompressedv0 = 0; +static ae_int_t dforest_dfcompressedv0 = 1; +static ae_int_t dforest_needtrngini = 1; +static ae_int_t dforest_needoobgini = 2; +static ae_int_t dforest_needpermutation = 3; +static ae_int_t dforest_permutationimportancebatchsize = 512; +static void dforest_buildrandomtree(decisionforestbuilder* s, + ae_int_t treeidx0, + ae_int_t treeidx1, + ae_state *_state); +ae_bool _trypexec_dforest_buildrandomtree(decisionforestbuilder* s, + ae_int_t treeidx0, + ae_int_t treeidx1, ae_state *_state); +static void dforest_buildrandomtreerec(const decisionforestbuilder* s, + dfworkbuf* workbuf, + ae_int_t workingset, + ae_int_t varstoselect, + /* Real */ ae_vector* treebuf, + dfvotebuf* votebuf, + hqrndstate* rs, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t oobidx0, + ae_int_t oobidx1, + double meanloss, + double topmostmeanloss, + ae_int_t* treesize, + ae_state *_state); +static void dforest_estimatevariableimportance(decisionforestbuilder* s, + ae_int_t sessionseed, + const decisionforest* df, + ae_int_t ntrees, + dfreport* rep, + ae_state *_state); +ae_bool _trypexec_dforest_estimatevariableimportance(decisionforestbuilder* s, + ae_int_t sessionseed, + const decisionforest* df, + ae_int_t ntrees, + dfreport* rep, ae_state *_state); +static void dforest_estimatepermutationimportances(decisionforestbuilder* s, + const decisionforest* df, + ae_int_t ntrees, + ae_shared_pool* permpool, + ae_int_t idx0, + ae_int_t idx1, + ae_state *_state); +ae_bool _trypexec_dforest_estimatepermutationimportances(decisionforestbuilder* s, + const decisionforest* df, + ae_int_t ntrees, + ae_shared_pool* permpool, + ae_int_t idx0, + ae_int_t idx1, ae_state *_state); +static void dforest_cleanreport(const decisionforestbuilder* s, + dfreport* rep, + ae_state *_state); +static double dforest_meannrms2(ae_int_t nclasses, + /* Integer */ const ae_vector* trnlabelsi, + /* Real */ const ae_vector* trnlabelsr, + ae_int_t trnidx0, + ae_int_t trnidx1, + /* Integer */ const ae_vector* tstlabelsi, + /* Real */ const ae_vector* tstlabelsr, + ae_int_t tstidx0, + ae_int_t tstidx1, + /* Integer */ ae_vector* tmpi, + ae_state *_state); +static void dforest_choosecurrentsplitdense(const decisionforestbuilder* s, + dfworkbuf* workbuf, + ae_int_t* varsinpool, + ae_int_t varstoselect, + hqrndstate* rs, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t* varbest, + double* splitbest, + ae_state *_state); +static void dforest_evaluatedensesplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + hqrndstate* rs, + ae_int_t splitvar, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t* info, + double* split, + double* rms, + ae_state *_state); +static void dforest_classifiersplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* c, + ae_int_t n, + hqrndstate* rs, + ae_int_t* info, + double* threshold, + double* e, + /* Real */ ae_vector* sortrbuf, + /* Integer */ ae_vector* sortibuf, + ae_state *_state); +static void dforest_regressionsplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_int_t n, + ae_int_t* info, + double* threshold, + double* e, + /* Real */ ae_vector* sortrbuf, + /* Real */ ae_vector* sortrbuf2, + ae_state *_state); +static double dforest_getsplit(const decisionforestbuilder* s, + double a, + double b, + hqrndstate* rs, + ae_state *_state); +static void dforest_outputleaf(const decisionforestbuilder* s, + dfworkbuf* workbuf, + /* Real */ ae_vector* treebuf, + dfvotebuf* votebuf, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t oobidx0, + ae_int_t oobidx1, + ae_int_t* treesize, + double leafval, + ae_state *_state); +static void dforest_analyzeandpreprocessdataset(decisionforestbuilder* s, + ae_state *_state); +static void dforest_mergetrees(decisionforestbuilder* s, + decisionforest* df, + ae_state *_state); +static void dforest_processvotingresults(decisionforestbuilder* s, + ae_int_t ntrees, + dfvotebuf* buf, + dfreport* rep, + ae_state *_state); +static double dforest_binarycompression(decisionforest* df, + ae_bool usemantissa8, + ae_state *_state); +static ae_int_t dforest_computecompressedsizerec(const decisionforest* df, + ae_bool usemantissa8, + ae_int_t treeroot, + ae_int_t treepos, + /* Integer */ ae_vector* compressedsizes, + ae_bool savecompressedsizes, + ae_state *_state); +static void dforest_compressrec(const decisionforest* df, + ae_bool usemantissa8, + ae_int_t treeroot, + ae_int_t treepos, + /* Integer */ const ae_vector* compressedsizes, + ae_vector* buf, + ae_int_t* dstoffs, + ae_state *_state); +static ae_int_t dforest_computecompresseduintsize(ae_int_t v, + ae_state *_state); +static void dforest_streamuint(ae_vector* buf, + ae_int_t* offs, + ae_int_t v, + ae_state *_state); +static ae_int_t dforest_unstreamuint(const ae_vector* buf, + ae_int_t* offs, + ae_state *_state); +static void dforest_streamfloat(ae_vector* buf, + ae_bool usemantissa8, + ae_int_t* offs, + double v, + ae_state *_state); +static double dforest_unstreamfloat(const ae_vector* buf, + ae_bool usemantissa8, + ae_int_t* offs, + ae_state *_state); +static ae_int_t dforest_dfclserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +static void dforest_dfprocessinternaluncompressed(const decisionforest* df, + ae_int_t subtreeroot, + ae_int_t nodeoffs, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static void dforest_dfprocessinternalcompressed(const decisionforest* df, + ae_int_t offs, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static double dforest_xfastpow(double r, ae_int_t n, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +static ae_int_t linreg_lrvnum = 5; +static void linreg_lrinternal(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* ar, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +static ae_bool ssa_hassomethingtoanalyze(const ssamodel* s, + ae_state *_state); +static ae_bool ssa_issequencebigenough(const ssamodel* s, + ae_int_t i, + ae_state *_state); +static void ssa_updatebasis(ssamodel* s, + ae_int_t appendlen, + double updateits, + ae_state *_state); +static void ssa_analyzesequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t i0, + ae_int_t i1, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_int_t offs, + ae_state *_state); +static void ssa_forecastavgsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t i0, + ae_int_t i1, + ae_int_t m, + ae_int_t forecastlen, + ae_bool smooth, + /* Real */ ae_vector* trend, + ae_int_t offs, + ae_state *_state); +static void ssa_realtimedequeue(ssamodel* s, + double beta, + ae_int_t cnt, + ae_state *_state); +static void ssa_updatexxtprepare(ssamodel* s, + ae_int_t updatesize, + ae_int_t windowwidth, + ae_int_t memorylimit, + ae_state *_state); +static void ssa_updatexxtsend(ssamodel* s, + /* Real */ const ae_vector* u, + ae_int_t i0, + /* Real */ ae_matrix* xxt, + ae_state *_state); +static void ssa_updatexxtfinalize(ssamodel* s, + /* Real */ ae_matrix* xxt, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +static double mcpd_xtol = 1.0E-8; +static void mcpd_mcpdinit(ae_int_t n, + ae_int_t entrystate, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +static double logit_xtol = (double)100*ae_machineepsilon; +static double logit_ftol = 0.0001; +static double logit_gtol = 0.3; +static ae_int_t logit_maxfev = 20; +static double logit_stpmin = 1.0E-2; +static double logit_stpmax = 1.0E5; +static ae_int_t logit_logitvnum = 6; +static void logit_mnliexp(/* Real */ ae_vector* w, + /* Real */ const ae_vector* x, + ae_state *_state); +static void logit_mnlallerrors(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double* relcls, + double* avgce, + double* rms, + double* avg, + double* avgrel, + ae_state *_state); +static void logit_mnlmcsrch(ae_int_t n, + /* Real */ ae_vector* x, + double* f, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* s, + double* stp, + ae_int_t* info, + ae_int_t* nfev, + /* Real */ ae_vector* wa, + logitmcstate* state, + ae_int_t* stage, + ae_state *_state); +static void logit_mnlmcstep(double* stx, + double* fx, + double* dx, + double* sty, + double* fy, + double* dy, + double* stp, + double fp, + double dp, + ae_bool* brackt, + double stmin, + double stmax, + ae_int_t* info, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) +static ae_int_t knn_knnfirstversion = 0; +static void knn_clearreport(knnreport* rep, ae_state *_state); +static void knn_processinternal(const knnmodel* model, + knnbuffer* buf, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +static double mlptrain_mindecay = 0.001; +static ae_int_t mlptrain_defaultlbfgsfactor = 6; +static void mlptrain_mlpkfoldcvgeneral(const multilayerperceptron* n, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t foldscount, + ae_bool lmalgorithm, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state); +static void mlptrain_mlpkfoldsplit(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nclasses, + ae_int_t foldscount, + ae_bool stratifiedsplits, + /* Integer */ ae_vector* folds, + ae_state *_state); +static void mlptrain_mthreadcv(mlptrainer* s, + ae_int_t rowsize, + ae_int_t nrestarts, + /* Integer */ const ae_vector* folds, + ae_int_t fold, + ae_int_t dfold, + /* Real */ ae_matrix* cvy, + ae_shared_pool* pooldatacv, + ae_int_t wcount, + ae_state *_state); +ae_bool _trypexec_mlptrain_mthreadcv(mlptrainer* s, + ae_int_t rowsize, + ae_int_t nrestarts, + /* Integer */ const ae_vector* folds, + ae_int_t fold, + ae_int_t dfold, + /* Real */ ae_matrix* cvy, + ae_shared_pool* pooldatacv, + ae_int_t wcount, ae_state *_state); +static void mlptrain_mlptrainnetworkx(const mlptrainer* s, + ae_int_t nrestarts, + ae_int_t algokind, + /* Integer */ const ae_vector* trnsubset, + ae_int_t trnsubsetsize, + /* Integer */ const ae_vector* valsubset, + ae_int_t valsubsetsize, + multilayerperceptron* network, + mlpreport* rep, + ae_bool isrootcall, + ae_shared_pool* sessions, + ae_state *_state); +ae_bool _trypexec_mlptrain_mlptrainnetworkx(const mlptrainer* s, + ae_int_t nrestarts, + ae_int_t algokind, + /* Integer */ const ae_vector* trnsubset, + ae_int_t trnsubsetsize, + /* Integer */ const ae_vector* valsubset, + ae_int_t valsubsetsize, + multilayerperceptron* network, + mlpreport* rep, + ae_bool isrootcall, + ae_shared_pool* sessions, ae_state *_state); +static void mlptrain_mlptrainensemblex(const mlptrainer* s, + mlpensemble* ensemble, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nrestarts, + ae_int_t trainingmethod, + sinteger* ngrad, + ae_bool isrootcall, + ae_shared_pool* esessions, + ae_state *_state); +ae_bool _trypexec_mlptrain_mlptrainensemblex(const mlptrainer* s, + mlpensemble* ensemble, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nrestarts, + ae_int_t trainingmethod, + sinteger* ngrad, + ae_bool isrootcall, + ae_shared_pool* esessions, ae_state *_state); +static void mlptrain_mlpstarttrainingx(const mlptrainer* s, + ae_bool randomstart, + ae_int_t algokind, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + smlptrnsession* session, + ae_state *_state); +static ae_bool mlptrain_mlpcontinuetrainingx(const mlptrainer* s, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_int_t* ngradbatch, + smlptrnsession* session, + ae_state *_state); +static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_bool lmalgorithm, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state); +static void mlptrain_initmlptrnsession(const multilayerperceptron* networktrained, + ae_bool randomizenetwork, + const mlptrainer* trainer, + smlptrnsession* session, + ae_state *_state); +static void mlptrain_initmlptrnsessions(const multilayerperceptron* networktrained, + ae_bool randomizenetwork, + const mlptrainer* trainer, + ae_shared_pool* sessions, + ae_state *_state); +static void mlptrain_initmlpetrnsession(const multilayerperceptron* individualnetwork, + const mlptrainer* trainer, + mlpetrnsession* session, + ae_state *_state); +static void mlptrain_initmlpetrnsessions(const multilayerperceptron* individualnetwork, + const mlptrainer* trainer, + ae_shared_pool* sessions, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) + + +#endif + +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Principal components analysis + +This function builds orthogonal basis where first axis corresponds to +direction with maximum variance, second axis maximizes variance in the +subspace orthogonal to first axis and so on. + +This function builds FULL basis, i.e. returns N vectors corresponding to +ALL directions, no matter how informative. If you need just a few (say, +10 or 50) of the most important directions, you may find it faster to use +one of the reduced versions: +* pcatruncatedsubspace() - for subspace iteration based method + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[NPoints,NVars]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + +OUTPUT PARAMETERS: + S2 - array[NVars]. variance values corresponding + to basis vectors. + V - array[NVars,NVars] + matrix, whose columns store basis vectors. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 25.08.2008 by Bochkanov Sergey +*************************************************************************/ +void pcabuildbasis(/* Real */ const ae_matrix* x, + ae_int_t npoints, + ae_int_t nvars, + /* Real */ ae_vector* s2, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix u; + ae_matrix vt; + ae_vector m; + ae_vector t; + ae_int_t i; + ae_int_t j; + double mean; + double variance; + double skewness; + double kurtosis; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + memset(&m, 0, sizeof(m)); + memset(&t, 0, sizeof(t)); + ae_vector_clear(s2); + ae_matrix_clear(v); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&m, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + + /* + * Check input data + */ + ae_assert(npoints>=0, "PCABuildBasis: NPoints<0", _state); + ae_assert(nvars>=1, "PCABuildBasis: NVars<1", _state); + ae_assert(x->rows>=npoints, "PCABuildBasis: rows(X)cols>=nvars||npoints==0, "PCABuildBasis: cols(X)ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + if( i==j ) + { + v->ptr.pp_double[i][j] = (double)(1); + } + else + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * Calculate means + */ + ae_vector_set_length(&m, nvars, _state); + ae_vector_set_length(&t, npoints, _state); + for(j=0; j<=nvars-1; j++) + { + ae_v_move(&t.ptr.p_double[0], 1, &x->ptr.pp_double[0][j], x->stride, ae_v_len(0,npoints-1)); + samplemoments(&t, npoints, &mean, &variance, &skewness, &kurtosis, _state); + m.ptr.p_double[j] = mean; + } + + /* + * Center, apply SVD, prepare output + */ + ae_matrix_set_length(&a, ae_maxint(npoints, nvars, _state), nvars, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&a.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + ae_v_sub(&a.ptr.pp_double[i][0], 1, &m.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + } + for(i=npoints; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + } + if( !rmatrixsvd(&a, ae_maxint(npoints, nvars, _state), nvars, 0, 1, 2, s2, &u, &vt, _state) ) + { + ae_assert(ae_false, "PCABuildBasis: internal SVD solver failure", _state); + ae_frame_leave(_state); + return; + } + if( npoints!=1 ) + { + for(i=0; i<=nvars-1; i++) + { + s2->ptr.p_double[i] = ae_sqr(s2->ptr.p_double[i], _state)/(double)(npoints-1); + } + } + ae_matrix_set_length(v, nvars, nvars, _state); + copyandtranspose(&vt, 0, nvars-1, 0, nvars-1, v, 0, nvars-1, 0, nvars-1, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Principal components analysis + +This function performs truncated PCA, i.e. returns just a few most important +directions. + +Internally it uses iterative eigensolver which is very efficient when only +a minor fraction of full basis is required. Thus, if you need full basis, +it is better to use pcabuildbasis() function. + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[0..NPoints-1,0..NVars-1]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<=0, "PCATruncatedSubspace: npoints<0", _state); + ae_assert(nvars>=1, "PCATruncatedSubspace: nvars<1", _state); + ae_assert(nneeded>0, "PCATruncatedSubspace: nneeded<1", _state); + ae_assert(nneeded<=nvars, "PCATruncatedSubspace: nneeded>nvars", _state); + ae_assert(maxits>=0, "PCATruncatedSubspace: maxits<0", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "PCATruncatedSubspace: eps<0 or is not finite", _state); + ae_assert(x->rows>=npoints, "PCATruncatedSubspace: rows(x)cols>=nvars||npoints==0, "PCATruncatedSubspace: cols(x)ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nneeded-1; j++) + { + if( i==j ) + { + v->ptr.pp_double[i][j] = (double)(1); + } + else + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * Center matrix + */ + ae_vector_set_length(&means, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + means.ptr.p_double[i] = (double)(0); + } + vv = (double)1/(double)npoints; + for(i=0; i<=npoints-1; i++) + { + ae_v_addd(&means.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), vv); + } + ae_matrix_set_length(&a, npoints, nvars, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&a.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + ae_v_sub(&a.ptr.pp_double[i][0], 1, &means.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + } + + /* + * Find eigenvalues with subspace iteration solver + */ + eigsubspacecreate(nvars, nneeded, &solver, _state); + eigsubspacesetcond(&solver, eps, maxits, _state); + eigsubspaceoocstart(&solver, 0, _state); + while(eigsubspaceooccontinue(&solver, _state)) + { + ae_assert(solver.requesttype==0, "PCATruncatedSubspace: integrity check failed", _state); + k = solver.requestsize; + rmatrixsetlengthatleast(&b, npoints, k, _state); + rmatrixgemm(npoints, k, nvars, 1.0, &a, 0, 0, 0, &solver.x, 0, 0, 0, 0.0, &b, 0, 0, _state); + rmatrixgemm(nvars, k, npoints, 1.0, &a, 0, 0, 1, &b, 0, 0, 0, 0.0, &solver.ax, 0, 0, _state); + } + eigsubspaceoocstop(&solver, s2, v, &rep, _state); + if( npoints!=1 ) + { + for(i=0; i<=nneeded-1; i++) + { + s2->ptr.p_double[i] = s2->ptr.p_double[i]/(double)(npoints-1); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Sparse truncated principal components analysis + +This function performs sparse truncated PCA, i.e. returns just a few most +important principal components for a sparse input X. + +Internally it uses iterative eigensolver which is very efficient when only +a minor fraction of full basis is required. + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - sparse dataset, sparse npoints*nvars matrix. It is + recommended to use CRS sparse storage format; non-CRS + input will be internally converted to CRS. + Matrix contains ONLY INDEPENDENT VARIABLES, and must + be EXACTLY npoints*nvars. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<=0, "PCATruncatedSubspaceSparse: npoints<0", _state); + ae_assert(nvars>=1, "PCATruncatedSubspaceSparse: nvars<1", _state); + ae_assert(nneeded>0, "PCATruncatedSubspaceSparse: nneeded<1", _state); + ae_assert(nneeded<=nvars, "PCATruncatedSubspaceSparse: nneeded>nvars", _state); + ae_assert(maxits>=0, "PCATruncatedSubspaceSparse: maxits<0", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "PCATruncatedSubspaceSparse: eps<0 or is not finite", _state); + if( npoints>0 ) + { + ae_assert(sparsegetnrows(x, _state)==npoints, "PCATruncatedSubspaceSparse: rows(x)!=npoints", _state); + ae_assert(sparsegetncols(x, _state)==nvars, "PCATruncatedSubspaceSparse: cols(x)!=nvars", _state); + } + + /* + * Special case: NPoints=0 + */ + if( npoints==0 ) + { + ae_vector_set_length(s2, nneeded, _state); + ae_matrix_set_length(v, nvars, nneeded, _state); + for(i=0; i<=nvars-1; i++) + { + s2->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nneeded-1; j++) + { + if( i==j ) + { + v->ptr.pp_double[i][j] = (double)(1); + } + else + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * If input data are not in CRS format, perform conversion to CRS + */ + if( !sparseiscrs(x, _state) ) + { + sparsecopytocrs(x, &xcrs, _state); + pcatruncatedsubspacesparse(&xcrs, npoints, nvars, nneeded, eps, maxits, s2, v, _state); + ae_frame_leave(_state); + return; + } + + /* + * Initialize parameters, prepare buffers + */ + ae_vector_set_length(&b1, npoints, _state); + ae_vector_set_length(&z1, nvars, _state); + if( ae_fp_eq(eps,(double)(0))&&maxits==0 ) + { + eps = 1.0E-6; + } + if( maxits==0 ) + { + maxits = 50+2*nvars; + } + + /* + * Calculate mean values + */ + vv = (double)1/(double)npoints; + for(i=0; i<=npoints-1; i++) + { + b1.ptr.p_double[i] = vv; + } + sparsemtv(x, &b1, &means, _state); + + /* + * Find eigenvalues with subspace iteration solver + */ + eigsubspacecreate(nvars, nneeded, &solver, _state); + eigsubspacesetcond(&solver, eps, maxits, _state); + eigsubspaceoocstart(&solver, 0, _state); + while(eigsubspaceooccontinue(&solver, _state)) + { + ae_assert(solver.requesttype==0, "PCATruncatedSubspace: integrity check failed", _state); + for(k=0; k<=solver.requestsize-1; k++) + { + + /* + * Calculate B1=(X-meansX)*Zk + */ + ae_v_move(&z1.ptr.p_double[0], 1, &solver.x.ptr.pp_double[0][k], solver.x.stride, ae_v_len(0,nvars-1)); + sparsemv(x, &z1, &b1, _state); + vv = ae_v_dotproduct(&solver.x.ptr.pp_double[0][k], solver.x.stride, &means.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + for(i=0; i<=npoints-1; i++) + { + b1.ptr.p_double[i] = b1.ptr.p_double[i]-vv; + } + + /* + * Calculate (X-meansX)^T*B1 + */ + sparsemtv(x, &b1, &c1, _state); + vv = (double)(0); + for(i=0; i<=npoints-1; i++) + { + vv = vv+b1.ptr.p_double[i]; + } + for(j=0; j<=nvars-1; j++) + { + solver.ax.ptr.pp_double[j][k] = c1.ptr.p_double[j]-vv*means.ptr.p_double[j]; + } + } + } + eigsubspaceoocstop(&solver, s2, v, &rep, _state); + if( npoints!=1 ) + { + for(i=0; i<=nneeded-1; i++) + { + s2->ptr.p_double[i] = s2->ptr.p_double[i]/(double)(npoints-1); + } + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_BDSS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This set of routines (DSErrAllocate, DSErrAccumulate, DSErrFinish) +calculates different error functions (classification error, cross-entropy, +rms, avg, avg.rel errors). + +1. DSErrAllocate prepares buffer. +2. DSErrAccumulate accumulates individual errors: + * Y contains predicted output (posterior probabilities for classification) + * DesiredY contains desired output (class number for classification) +3. DSErrFinish outputs results: + * Buf[0] contains relative classification error (zero for regression tasks) + * Buf[1] contains avg. cross-entropy (zero for regression tasks) + * Buf[2] contains rms error (regression, classification) + * Buf[3] contains average error (regression, classification) + * Buf[4] contains average relative error (regression, classification) + +NOTES(1): + "NClasses>0" means that we have classification task. + "NClasses<0" means regression task with -NClasses real outputs. + +NOTES(2): + rms. avg, avg.rel errors for classification tasks are interpreted as + errors in posterior probabilities with respect to probabilities given + by training/test set. + + -- ALGLIB -- + Copyright 11.01.2009 by Bochkanov Sergey +*************************************************************************/ +void dserrallocate(ae_int_t nclasses, + /* Real */ ae_vector* buf, + ae_state *_state) +{ + + ae_vector_clear(buf); + + ae_vector_set_length(buf, 7+1, _state); + buf->ptr.p_double[0] = (double)(0); + buf->ptr.p_double[1] = (double)(0); + buf->ptr.p_double[2] = (double)(0); + buf->ptr.p_double[3] = (double)(0); + buf->ptr.p_double[4] = (double)(0); + buf->ptr.p_double[5] = (double)(nclasses); + buf->ptr.p_double[6] = (double)(0); + buf->ptr.p_double[7] = (double)(0); +} + + +/************************************************************************* +See DSErrAllocate for comments on this routine. + + -- ALGLIB -- + Copyright 11.01.2009 by Bochkanov Sergey +*************************************************************************/ +void dserraccumulate(/* Real */ ae_vector* buf, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* desiredy, + ae_state *_state) +{ + ae_int_t nclasses; + ae_int_t nout; + ae_int_t offs; + ae_int_t mmax; + ae_int_t rmax; + ae_int_t j; + double v; + double ev; + + + offs = 5; + nclasses = ae_round(buf->ptr.p_double[offs], _state); + if( nclasses>0 ) + { + + /* + * Classification + */ + rmax = ae_round(desiredy->ptr.p_double[0], _state); + mmax = 0; + for(j=1; j<=nclasses-1; j++) + { + if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) + { + mmax = j; + } + } + if( mmax!=rmax ) + { + buf->ptr.p_double[0] = buf->ptr.p_double[0]+(double)1; + } + if( ae_fp_greater(y->ptr.p_double[rmax],(double)(0)) ) + { + buf->ptr.p_double[1] = buf->ptr.p_double[1]-ae_log(y->ptr.p_double[rmax], _state); + } + else + { + buf->ptr.p_double[1] = buf->ptr.p_double[1]+ae_log(ae_maxrealnumber, _state); + } + for(j=0; j<=nclasses-1; j++) + { + v = y->ptr.p_double[j]; + if( j==rmax ) + { + ev = (double)(1); + } + else + { + ev = (double)(0); + } + buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); + buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); + if( ae_fp_neq(ev,(double)(0)) ) + { + buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); + buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+(double)1; + } + } + buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+(double)1; + } + else + { + + /* + * Regression + */ + nout = -nclasses; + rmax = 0; + for(j=1; j<=nout-1; j++) + { + if( ae_fp_greater(desiredy->ptr.p_double[j],desiredy->ptr.p_double[rmax]) ) + { + rmax = j; + } + } + mmax = 0; + for(j=1; j<=nout-1; j++) + { + if( ae_fp_greater(y->ptr.p_double[j],y->ptr.p_double[mmax]) ) + { + mmax = j; + } + } + if( mmax!=rmax ) + { + buf->ptr.p_double[0] = buf->ptr.p_double[0]+(double)1; + } + for(j=0; j<=nout-1; j++) + { + v = y->ptr.p_double[j]; + ev = desiredy->ptr.p_double[j]; + buf->ptr.p_double[2] = buf->ptr.p_double[2]+ae_sqr(v-ev, _state); + buf->ptr.p_double[3] = buf->ptr.p_double[3]+ae_fabs(v-ev, _state); + if( ae_fp_neq(ev,(double)(0)) ) + { + buf->ptr.p_double[4] = buf->ptr.p_double[4]+ae_fabs((v-ev)/ev, _state); + buf->ptr.p_double[offs+2] = buf->ptr.p_double[offs+2]+(double)1; + } + } + buf->ptr.p_double[offs+1] = buf->ptr.p_double[offs+1]+(double)1; + } +} + + +/************************************************************************* +See DSErrAllocate for comments on this routine. + + -- ALGLIB -- + Copyright 11.01.2009 by Bochkanov Sergey +*************************************************************************/ +void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state) +{ + ae_int_t nout; + ae_int_t offs; + + + offs = 5; + nout = ae_iabs(ae_round(buf->ptr.p_double[offs], _state), _state); + if( ae_fp_neq(buf->ptr.p_double[offs+1],(double)(0)) ) + { + buf->ptr.p_double[0] = buf->ptr.p_double[0]/buf->ptr.p_double[offs+1]; + buf->ptr.p_double[1] = buf->ptr.p_double[1]/buf->ptr.p_double[offs+1]; + buf->ptr.p_double[2] = ae_sqrt(buf->ptr.p_double[2]/((double)nout*buf->ptr.p_double[offs+1]), _state); + buf->ptr.p_double[3] = buf->ptr.p_double[3]/((double)nout*buf->ptr.p_double[offs+1]); + } + if( ae_fp_neq(buf->ptr.p_double[offs+2],(double)(0)) ) + { + buf->ptr.p_double[4] = buf->ptr.p_double[4]/buf->ptr.p_double[offs+2]; + } +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 19.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsnormalize(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t* info, + /* Real */ ae_vector* means, + /* Real */ ae_vector* sigmas, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + double mean; + double variance; + double skewness; + double kurtosis; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + *info = 0; + ae_vector_clear(means); + ae_vector_clear(sigmas); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * Test parameters + */ + if( npoints<=0||nvars<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * Standartization + */ + ae_vector_set_length(means, nvars-1+1, _state); + ae_vector_set_length(sigmas, nvars-1+1, _state); + ae_vector_set_length(&tmp, npoints-1+1, _state); + for(j=0; j<=nvars-1; j++) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); + samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); + means->ptr.p_double[j] = mean; + sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); + if( ae_fp_eq(sigmas->ptr.p_double[j],(double)(0)) ) + { + sigmas->ptr.p_double[j] = (double)(1); + } + for(i=0; i<=npoints-1; i++) + { + xy->ptr.pp_double[i][j] = (xy->ptr.pp_double[i][j]-means->ptr.p_double[j])/sigmas->ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 19.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsnormalizec(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t* info, + /* Real */ ae_vector* means, + /* Real */ ae_vector* sigmas, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t j; + ae_vector tmp; + double mean; + double variance; + double skewness; + double kurtosis; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + *info = 0; + ae_vector_clear(means); + ae_vector_clear(sigmas); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * Test parameters + */ + if( npoints<=0||nvars<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * Standartization + */ + ae_vector_set_length(means, nvars-1+1, _state); + ae_vector_set_length(sigmas, nvars-1+1, _state); + ae_vector_set_length(&tmp, npoints-1+1, _state); + for(j=0; j<=nvars-1; j++) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); + samplemoments(&tmp, npoints, &mean, &variance, &skewness, &kurtosis, _state); + means->ptr.p_double[j] = mean; + sigmas->ptr.p_double[j] = ae_sqrt(variance, _state); + if( ae_fp_eq(sigmas->ptr.p_double[j],(double)(0)) ) + { + sigmas->ptr.p_double[j] = (double)(1); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 19.05.2008 by Bochkanov Sergey +*************************************************************************/ +double dsgetmeanmindistance(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + ae_vector tmp2; + double v; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + memset(&tmp2, 0, sizeof(tmp2)); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + + + /* + * Test parameters + */ + if( npoints<=0||nvars<1 ) + { + result = (double)(0); + ae_frame_leave(_state); + return result; + } + + /* + * Process + */ + ae_vector_set_length(&tmp, npoints-1+1, _state); + for(i=0; i<=npoints-1; i++) + { + tmp.ptr.p_double[i] = ae_maxrealnumber; + } + ae_vector_set_length(&tmp2, nvars-1+1, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=i+1; j<=npoints-1; j++) + { + ae_v_move(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + ae_v_sub(&tmp2.ptr.p_double[0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); + v = ae_v_dotproduct(&tmp2.ptr.p_double[0], 1, &tmp2.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + v = ae_sqrt(v, _state); + tmp.ptr.p_double[i] = ae_minreal(tmp.ptr.p_double[i], v, _state); + tmp.ptr.p_double[j] = ae_minreal(tmp.ptr.p_double[j], v, _state); + } + } + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + result = result+tmp.ptr.p_double[i]/(double)npoints; + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 19.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dstie(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* ties, + ae_int_t* tiecount, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_clear(ties); + *tiecount = 0; + ae_vector_clear(p1); + ae_vector_clear(p2); + ae_vector_init(&tmp, 0, DT_INT, _state, ae_true); + + + /* + * Special case + */ + if( n<=0 ) + { + *tiecount = 0; + ae_frame_leave(_state); + return; + } + + /* + * Sort A + */ + tagsort(a, n, p1, p2, _state); + + /* + * Process ties + */ + *tiecount = 1; + for(i=1; i<=n-1; i++) + { + if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) + { + *tiecount = *tiecount+1; + } + } + ae_vector_set_length(ties, *tiecount+1, _state); + ties->ptr.p_int[0] = 0; + k = 1; + for(i=1; i<=n-1; i++) + { + if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) + { + ties->ptr.p_int[k] = i; + k = k+1; + } + } + ties->ptr.p_int[*tiecount] = n; + ae_frame_leave(_state); +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void dstiefasti(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t n, + /* Integer */ ae_vector* ties, + ae_int_t* tiecount, + /* Real */ ae_vector* bufr, + /* Integer */ ae_vector* bufi, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + *tiecount = 0; + ae_vector_init(&tmp, 0, DT_INT, _state, ae_true); + + + /* + * Special case + */ + if( n<=0 ) + { + *tiecount = 0; + ae_frame_leave(_state); + return; + } + + /* + * Sort A + */ + tagsortfasti(a, b, bufr, bufi, n, _state); + + /* + * Process ties + */ + ties->ptr.p_int[0] = 0; + k = 1; + for(i=1; i<=n-1; i++) + { + if( ae_fp_neq(a->ptr.p_double[i],a->ptr.p_double[i-1]) ) + { + ties->ptr.p_int[k] = i; + k = k+1; + } + } + ties->ptr.p_int[k] = n; + *tiecount = k; + ae_frame_leave(_state); +} + + +/************************************************************************* +Optimal binary classification + +Algorithms finds optimal (=with minimal cross-entropy) binary partition. +Internal subroutine. + +INPUT PARAMETERS: + A - array[0..N-1], variable + C - array[0..N-1], class numbers (0 or 1). + N - array size + +OUTPUT PARAMETERS: + Info - completetion code: + * -3, all values of A[] are same (partition is impossible) + * -2, one of C[] is incorrect (<0, >1) + * -1, incorrect pararemets were passed (N<=0). + * 1, OK + Threshold- partiton boundary. Left part contains values which are + strictly less than Threshold. Right part contains values + which are greater than or equal to Threshold. + PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) + CVE - cross-validation estimate of cross-entropy + + -- ALGLIB -- + Copyright 22.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t* info, + double* threshold, + double* pal, + double* pbl, + double* par, + double* pbr, + double* cve, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector c; + ae_int_t i; + ae_int_t t; + double s; + ae_vector ties; + ae_int_t tiecount; + ae_vector p1; + ae_vector p2; + ae_int_t k; + ae_int_t koptimal; + double pak; + double pbk; + double cvoptimal; + double cv; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&c, 0, sizeof(c)); + memset(&ties, 0, sizeof(ties)); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + ae_vector_init_copy(&a, _a, _state, ae_true); + ae_vector_init_copy(&c, _c, _state, ae_true); + *info = 0; + *threshold = 0.0; + *pal = 0.0; + *pbl = 0.0; + *par = 0.0; + *pbr = 0.0; + *cve = 0.0; + ae_vector_init(&ties, 0, DT_INT, _state, ae_true); + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * Test for errors in inputs + */ + if( n<=0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( c.ptr.p_int[i]!=0&&c.ptr.p_int[i]!=1 ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + *info = 1; + + /* + * Tie + */ + dstie(&a, n, &ties, &tiecount, &p1, &p2, _state); + for(i=0; i<=n-1; i++) + { + if( p2.ptr.p_int[i]!=i ) + { + t = c.ptr.p_int[i]; + c.ptr.p_int[i] = c.ptr.p_int[p2.ptr.p_int[i]]; + c.ptr.p_int[p2.ptr.p_int[i]] = t; + } + } + + /* + * Special case: number of ties is 1. + * + * NOTE: we assume that P[i,j] equals to 0 or 1, + * intermediate values are not allowed. + */ + if( tiecount==1 ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * General case, number of ties > 1 + * + * NOTE: we assume that P[i,j] equals to 0 or 1, + * intermediate values are not allowed. + */ + *pal = (double)(0); + *pbl = (double)(0); + *par = (double)(0); + *pbr = (double)(0); + for(i=0; i<=n-1; i++) + { + if( c.ptr.p_int[i]==0 ) + { + *par = *par+(double)1; + } + if( c.ptr.p_int[i]==1 ) + { + *pbr = *pbr+(double)1; + } + } + koptimal = -1; + cvoptimal = ae_maxrealnumber; + for(k=0; k<=tiecount-2; k++) + { + + /* + * first, obtain information about K-th tie which is + * moved from R-part to L-part + */ + pak = (double)(0); + pbk = (double)(0); + for(i=ties.ptr.p_int[k]; i<=ties.ptr.p_int[k+1]-1; i++) + { + if( c.ptr.p_int[i]==0 ) + { + pak = pak+(double)1; + } + if( c.ptr.p_int[i]==1 ) + { + pbk = pbk+(double)1; + } + } + + /* + * Calculate cross-validation CE + */ + cv = (double)(0); + cv = cv-bdss_xlny(*pal+pak, (*pal+pak)/(*pal+pak+(*pbl)+pbk+(double)1), _state); + cv = cv-bdss_xlny(*pbl+pbk, (*pbl+pbk)/(*pal+pak+(double)1+(*pbl)+pbk), _state); + cv = cv-bdss_xlny(*par-pak, (*par-pak)/(*par-pak+(*pbr)-pbk+(double)1), _state); + cv = cv-bdss_xlny(*pbr-pbk, (*pbr-pbk)/(*par-pak+(double)1+(*pbr)-pbk), _state); + + /* + * Compare with best + */ + if( ae_fp_less(cv,cvoptimal) ) + { + cvoptimal = cv; + koptimal = k; + } + + /* + * update + */ + *pal = *pal+pak; + *pbl = *pbl+pbk; + *par = *par-pak; + *pbr = *pbr-pbk; + } + *cve = cvoptimal; + *threshold = 0.5*(a.ptr.p_double[ties.ptr.p_int[koptimal]]+a.ptr.p_double[ties.ptr.p_int[koptimal+1]]); + *pal = (double)(0); + *pbl = (double)(0); + *par = (double)(0); + *pbr = (double)(0); + for(i=0; i<=n-1; i++) + { + if( ae_fp_less(a.ptr.p_double[i],*threshold) ) + { + if( c.ptr.p_int[i]==0 ) + { + *pal = *pal+(double)1; + } + else + { + *pbl = *pbl+(double)1; + } + } + else + { + if( c.ptr.p_int[i]==0 ) + { + *par = *par+(double)1; + } + else + { + *pbr = *pbr+(double)1; + } + } + } + s = *pal+(*pbl); + *pal = *pal/s; + *pbl = *pbl/s; + s = *par+(*pbr); + *par = *par/s; + *pbr = *pbr/s; + ae_frame_leave(_state); +} + + +/************************************************************************* +Optimal partition, internal subroutine. Fast version. + +Accepts: + A array[0..N-1] array of attributes array[0..N-1] + C array[0..N-1] array of class labels + TiesBuf array[0..N] temporaries (ties) + CntBuf array[0..2*NC-1] temporaries (counts) + Alpha centering factor (0<=alpha<=1, recommended value - 0.05) + BufR array[0..N-1] temporaries + BufI array[0..N-1] temporaries + +Output: + Info error code (">0"=OK, "<0"=bad) + RMS training set RMS error + CVRMS leave-one-out RMS error + +Note: + content of all arrays is changed by subroutine; + it doesn't allocate temporaries. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2fast(/* Real */ ae_vector* a, + /* Integer */ ae_vector* c, + /* Integer */ ae_vector* tiesbuf, + /* Integer */ ae_vector* cntbuf, + /* Real */ ae_vector* bufr, + /* Integer */ ae_vector* bufi, + ae_int_t n, + ae_int_t nc, + double alpha, + ae_int_t* info, + double* threshold, + double* rms, + double* cvrms, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t cl; + ae_int_t tiecount; + double cbest; + double cc; + ae_int_t koptimal; + ae_int_t sl; + ae_int_t sr; + double v; + double w; + double x; + + *info = 0; + *threshold = 0.0; + *rms = 0.0; + *cvrms = 0.0; + + + /* + * Test for errors in inputs + */ + if( n<=0||nc<2 ) + { + *info = -1; + return; + } + for(i=0; i<=n-1; i++) + { + if( c->ptr.p_int[i]<0||c->ptr.p_int[i]>=nc ) + { + *info = -2; + return; + } + } + *info = 1; + + /* + * Tie + */ + dstiefasti(a, c, n, tiesbuf, &tiecount, bufr, bufi, _state); + + /* + * Special case: number of ties is 1. + */ + if( tiecount==1 ) + { + *info = -3; + return; + } + + /* + * General case, number of ties > 1 + */ + for(i=0; i<=2*nc-1; i++) + { + cntbuf->ptr.p_int[i] = 0; + } + for(i=0; i<=n-1; i++) + { + cntbuf->ptr.p_int[nc+c->ptr.p_int[i]] = cntbuf->ptr.p_int[nc+c->ptr.p_int[i]]+1; + } + koptimal = -1; + *threshold = a->ptr.p_double[n-1]; + cbest = ae_maxrealnumber; + sl = 0; + sr = n; + for(k=0; k<=tiecount-2; k++) + { + + /* + * first, move Kth tie from right to left + */ + for(i=tiesbuf->ptr.p_int[k]; i<=tiesbuf->ptr.p_int[k+1]-1; i++) + { + cl = c->ptr.p_int[i]; + cntbuf->ptr.p_int[cl] = cntbuf->ptr.p_int[cl]+1; + cntbuf->ptr.p_int[nc+cl] = cntbuf->ptr.p_int[nc+cl]-1; + } + sl = sl+(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); + sr = sr-(tiesbuf->ptr.p_int[k+1]-tiesbuf->ptr.p_int[k]); + + /* + * Calculate RMS error + */ + v = (double)(0); + for(i=0; i<=nc-1; i++) + { + w = (double)(cntbuf->ptr.p_int[i]); + v = v+w*ae_sqr(w/(double)sl-(double)1, _state); + v = v+((double)sl-w)*ae_sqr(w/(double)sl, _state); + w = (double)(cntbuf->ptr.p_int[nc+i]); + v = v+w*ae_sqr(w/(double)sr-(double)1, _state); + v = v+((double)sr-w)*ae_sqr(w/(double)sr, _state); + } + v = ae_sqrt(v/(double)(nc*n), _state); + + /* + * Compare with best + */ + x = (double)(2*sl)/(double)(sl+sr)-(double)1; + cc = v*((double)1-alpha+alpha*ae_sqr(x, _state)); + if( ae_fp_less(cc,cbest) ) + { + + /* + * store split + */ + *rms = v; + koptimal = k; + cbest = cc; + + /* + * calculate CVRMS error + */ + *cvrms = (double)(0); + for(i=0; i<=nc-1; i++) + { + if( sl>1 ) + { + w = (double)(cntbuf->ptr.p_int[i]); + *cvrms = *cvrms+w*ae_sqr((w-(double)1)/(double)(sl-1)-(double)1, _state); + *cvrms = *cvrms+((double)sl-w)*ae_sqr(w/(double)(sl-1), _state); + } + else + { + w = (double)(cntbuf->ptr.p_int[i]); + *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-(double)1, _state); + *cvrms = *cvrms+((double)sl-w)*ae_sqr((double)1/(double)nc, _state); + } + if( sr>1 ) + { + w = (double)(cntbuf->ptr.p_int[nc+i]); + *cvrms = *cvrms+w*ae_sqr((w-(double)1)/(double)(sr-1)-(double)1, _state); + *cvrms = *cvrms+((double)sr-w)*ae_sqr(w/(double)(sr-1), _state); + } + else + { + w = (double)(cntbuf->ptr.p_int[nc+i]); + *cvrms = *cvrms+w*ae_sqr((double)1/(double)nc-(double)1, _state); + *cvrms = *cvrms+((double)sr-w)*ae_sqr((double)1/(double)nc, _state); + } + } + *cvrms = ae_sqrt(*cvrms/(double)(nc*n), _state); + } + } + + /* + * Calculate threshold. + * Code is a bit complicated because there can be such + * numbers that 0.5(A+B) equals to A or B (if A-B=epsilon) + */ + *threshold = 0.5*(a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]+a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]); + if( ae_fp_less_eq(*threshold,a->ptr.p_double[tiesbuf->ptr.p_int[koptimal]]) ) + { + *threshold = a->ptr.p_double[tiesbuf->ptr.p_int[koptimal+1]]; + } +} + + +/************************************************************************* +Automatic non-optimal discretization, internal subroutine. + + -- ALGLIB -- + Copyright 22.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dssplitk(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t nc, + ae_int_t kmax, + ae_int_t* info, + /* Real */ ae_vector* thresholds, + ae_int_t* ni, + double* cve, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector c; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t k; + ae_vector ties; + ae_int_t tiecount; + ae_vector p1; + ae_vector p2; + ae_vector cnt; + double v2; + ae_int_t bestk; + double bestcve; + ae_vector bestsizes; + double curcve; + ae_vector cursizes; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&c, 0, sizeof(c)); + memset(&ties, 0, sizeof(ties)); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + memset(&cnt, 0, sizeof(cnt)); + memset(&bestsizes, 0, sizeof(bestsizes)); + memset(&cursizes, 0, sizeof(cursizes)); + ae_vector_init_copy(&a, _a, _state, ae_true); + ae_vector_init_copy(&c, _c, _state, ae_true); + *info = 0; + ae_vector_clear(thresholds); + *ni = 0; + *cve = 0.0; + ae_vector_init(&ties, 0, DT_INT, _state, ae_true); + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + ae_vector_init(&cnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&bestsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(&cursizes, 0, DT_INT, _state, ae_true); + + + /* + * Test for errors in inputs + */ + if( (n<=0||nc<2)||kmax<2 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( c.ptr.p_int[i]<0||c.ptr.p_int[i]>=nc ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + *info = 1; + + /* + * Tie + */ + dstie(&a, n, &ties, &tiecount, &p1, &p2, _state); + for(i=0; i<=n-1; i++) + { + if( p2.ptr.p_int[i]!=i ) + { + k = c.ptr.p_int[i]; + c.ptr.p_int[i] = c.ptr.p_int[p2.ptr.p_int[i]]; + c.ptr.p_int[p2.ptr.p_int[i]] = k; + } + } + + /* + * Special cases + */ + if( tiecount==1 ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * General case: + * 0. allocate arrays + */ + kmax = ae_minint(kmax, tiecount, _state); + ae_vector_set_length(&bestsizes, kmax-1+1, _state); + ae_vector_set_length(&cursizes, kmax-1+1, _state); + ae_vector_set_length(&cnt, nc-1+1, _state); + + /* + * General case: + * 1. prepare "weak" solution (two subintervals, divided at median) + */ + v2 = ae_maxrealnumber; + j = -1; + for(i=1; i<=tiecount-1; i++) + { + if( ae_fp_less(ae_fabs((double)ties.ptr.p_int[i]-0.5*(double)(n-1), _state),v2) ) + { + v2 = ae_fabs((double)ties.ptr.p_int[i]-0.5*(double)n, _state); + j = i; + } + } + ae_assert(j>0, "DSSplitK: internal error #1!", _state); + bestk = 2; + bestsizes.ptr.p_int[0] = ties.ptr.p_int[j]; + bestsizes.ptr.p_int[1] = n-j; + bestcve = (double)(0); + for(i=0; i<=nc-1; i++) + { + cnt.ptr.p_int[i] = 0; + } + for(i=0; i<=j-1; i++) + { + bdss_tieaddc(&c, &ties, i, nc, &cnt, _state); + } + bestcve = bestcve+bdss_getcv(&cnt, nc, _state); + for(i=0; i<=nc-1; i++) + { + cnt.ptr.p_int[i] = 0; + } + for(i=j; i<=tiecount-1; i++) + { + bdss_tieaddc(&c, &ties, i, nc, &cnt, _state); + } + bestcve = bestcve+bdss_getcv(&cnt, nc, _state); + + /* + * General case: + * 2. Use greedy algorithm to find sub-optimal split in O(KMax*N) time + */ + for(k=2; k<=kmax; k++) + { + + /* + * Prepare greedy K-interval split + */ + for(i=0; i<=k-1; i++) + { + cursizes.ptr.p_int[i] = 0; + } + i = 0; + j = 0; + while(j<=tiecount-1&&i<=k-1) + { + + /* + * Rule: I-th bin is empty, fill it + */ + if( cursizes.ptr.p_int[i]==0 ) + { + cursizes.ptr.p_int[i] = ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; + j = j+1; + continue; + } + + /* + * Rule: (K-1-I) bins left, (K-1-I) ties left (1 tie per bin); next bin + */ + if( tiecount-j==k-1-i ) + { + i = i+1; + continue; + } + + /* + * Rule: last bin, always place in current + */ + if( i==k-1 ) + { + cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; + j = j+1; + continue; + } + + /* + * Place J-th tie in I-th bin, or leave for I+1-th bin. + */ + if( ae_fp_less(ae_fabs((double)(cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j])-(double)n/(double)k, _state),ae_fabs((double)cursizes.ptr.p_int[i]-(double)n/(double)k, _state)) ) + { + cursizes.ptr.p_int[i] = cursizes.ptr.p_int[i]+ties.ptr.p_int[j+1]-ties.ptr.p_int[j]; + j = j+1; + } + else + { + i = i+1; + } + } + ae_assert(cursizes.ptr.p_int[k-1]!=0&&j==tiecount, "DSSplitK: internal error #1", _state); + + /* + * Calculate CVE + */ + curcve = (double)(0); + j = 0; + for(i=0; i<=k-1; i++) + { + for(j1=0; j1<=nc-1; j1++) + { + cnt.ptr.p_int[j1] = 0; + } + for(j1=j; j1<=j+cursizes.ptr.p_int[i]-1; j1++) + { + cnt.ptr.p_int[c.ptr.p_int[j1]] = cnt.ptr.p_int[c.ptr.p_int[j1]]+1; + } + curcve = curcve+bdss_getcv(&cnt, nc, _state); + j = j+cursizes.ptr.p_int[i]; + } + + /* + * Choose best variant + */ + if( ae_fp_less(curcve,bestcve) ) + { + for(i=0; i<=k-1; i++) + { + bestsizes.ptr.p_int[i] = cursizes.ptr.p_int[i]; + } + bestcve = curcve; + bestk = k; + } + } + + /* + * Transform from sizes to thresholds + */ + *cve = bestcve; + *ni = bestk; + ae_vector_set_length(thresholds, *ni-2+1, _state); + j = bestsizes.ptr.p_int[0]; + for(i=1; i<=bestk-1; i++) + { + thresholds->ptr.p_double[i-1] = 0.5*(a.ptr.p_double[j-1]+a.ptr.p_double[j]); + j = j+bestsizes.ptr.p_int[i]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Automatic optimal discretization, internal subroutine. + + -- ALGLIB -- + Copyright 22.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplitk(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t nc, + ae_int_t kmax, + ae_int_t* info, + /* Real */ ae_vector* thresholds, + ae_int_t* ni, + double* cve, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector c; + ae_int_t i; + ae_int_t j; + ae_int_t s; + ae_int_t jl; + ae_int_t jr; + double v2; + ae_vector ties; + ae_int_t tiecount; + ae_vector p1; + ae_vector p2; + double cvtemp; + ae_vector cnt; + ae_vector cnt2; + ae_matrix cv; + ae_matrix splits; + ae_int_t k; + ae_int_t koptimal; + double cvoptimal; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&c, 0, sizeof(c)); + memset(&ties, 0, sizeof(ties)); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + memset(&cnt, 0, sizeof(cnt)); + memset(&cnt2, 0, sizeof(cnt2)); + memset(&cv, 0, sizeof(cv)); + memset(&splits, 0, sizeof(splits)); + ae_vector_init_copy(&a, _a, _state, ae_true); + ae_vector_init_copy(&c, _c, _state, ae_true); + *info = 0; + ae_vector_clear(thresholds); + *ni = 0; + *cve = 0.0; + ae_vector_init(&ties, 0, DT_INT, _state, ae_true); + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + ae_vector_init(&cnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&cnt2, 0, DT_INT, _state, ae_true); + ae_matrix_init(&cv, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&splits, 0, 0, DT_INT, _state, ae_true); + + + /* + * Test for errors in inputs + */ + if( (n<=0||nc<2)||kmax<2 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( c.ptr.p_int[i]<0||c.ptr.p_int[i]>=nc ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + *info = 1; + + /* + * Tie + */ + dstie(&a, n, &ties, &tiecount, &p1, &p2, _state); + for(i=0; i<=n-1; i++) + { + if( p2.ptr.p_int[i]!=i ) + { + k = c.ptr.p_int[i]; + c.ptr.p_int[i] = c.ptr.p_int[p2.ptr.p_int[i]]; + c.ptr.p_int[p2.ptr.p_int[i]] = k; + } + } + + /* + * Special cases + */ + if( tiecount==1 ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * General case + * Use dynamic programming to find best split in O(KMax*NC*TieCount^2) time + */ + kmax = ae_minint(kmax, tiecount, _state); + ae_matrix_set_length(&cv, kmax-1+1, tiecount-1+1, _state); + ae_matrix_set_length(&splits, kmax-1+1, tiecount-1+1, _state); + ae_vector_set_length(&cnt, nc-1+1, _state); + ae_vector_set_length(&cnt2, nc-1+1, _state); + for(j=0; j<=nc-1; j++) + { + cnt.ptr.p_int[j] = 0; + } + for(j=0; j<=tiecount-1; j++) + { + bdss_tieaddc(&c, &ties, j, nc, &cnt, _state); + splits.ptr.pp_int[0][j] = 0; + cv.ptr.pp_double[0][j] = bdss_getcv(&cnt, nc, _state); + } + for(k=1; k<=kmax-1; k++) + { + for(j=0; j<=nc-1; j++) + { + cnt.ptr.p_int[j] = 0; + } + + /* + * Subtask size J in [K..TieCount-1]: + * optimal K-splitting on ties from 0-th to J-th. + */ + for(j=k; j<=tiecount-1; j++) + { + + /* + * Update Cnt - let it contain classes of ties from K-th to J-th + */ + bdss_tieaddc(&c, &ties, j, nc, &cnt, _state); + + /* + * Search for optimal split point S in [K..J] + */ + for(i=0; i<=nc-1; i++) + { + cnt2.ptr.p_int[i] = cnt.ptr.p_int[i]; + } + cv.ptr.pp_double[k][j] = cv.ptr.pp_double[k-1][j-1]+bdss_getcv(&cnt2, nc, _state); + splits.ptr.pp_int[k][j] = j; + for(s=k+1; s<=j; s++) + { + + /* + * Update Cnt2 - let it contain classes of ties from S-th to J-th + */ + bdss_tiesubc(&c, &ties, s-1, nc, &cnt2, _state); + + /* + * Calculate CVE + */ + cvtemp = cv.ptr.pp_double[k-1][s-1]+bdss_getcv(&cnt2, nc, _state); + if( ae_fp_less(cvtemp,cv.ptr.pp_double[k][j]) ) + { + cv.ptr.pp_double[k][j] = cvtemp; + splits.ptr.pp_int[k][j] = s; + } + } + } + } + + /* + * Choose best partition, output result + */ + koptimal = -1; + cvoptimal = ae_maxrealnumber; + for(k=0; k<=kmax-1; k++) + { + if( ae_fp_less(cv.ptr.pp_double[k][tiecount-1],cvoptimal) ) + { + cvoptimal = cv.ptr.pp_double[k][tiecount-1]; + koptimal = k; + } + } + ae_assert(koptimal>=0, "DSOptimalSplitK: internal error #1!", _state); + if( koptimal==0 ) + { + + /* + * Special case: best partition is one big interval. + * Even 2-partition is not better. + * This is possible when dealing with "weak" predictor variables. + * + * Make binary split as close to the median as possible. + */ + v2 = ae_maxrealnumber; + j = -1; + for(i=1; i<=tiecount-1; i++) + { + if( ae_fp_less(ae_fabs((double)ties.ptr.p_int[i]-0.5*(double)(n-1), _state),v2) ) + { + v2 = ae_fabs((double)ties.ptr.p_int[i]-0.5*(double)(n-1), _state); + j = i; + } + } + ae_assert(j>0, "DSOptimalSplitK: internal error #2!", _state); + ae_vector_set_length(thresholds, 0+1, _state); + thresholds->ptr.p_double[0] = 0.5*(a.ptr.p_double[ties.ptr.p_int[j-1]]+a.ptr.p_double[ties.ptr.p_int[j]]); + *ni = 2; + *cve = (double)(0); + for(i=0; i<=nc-1; i++) + { + cnt.ptr.p_int[i] = 0; + } + for(i=0; i<=j-1; i++) + { + bdss_tieaddc(&c, &ties, i, nc, &cnt, _state); + } + *cve = *cve+bdss_getcv(&cnt, nc, _state); + for(i=0; i<=nc-1; i++) + { + cnt.ptr.p_int[i] = 0; + } + for(i=j; i<=tiecount-1; i++) + { + bdss_tieaddc(&c, &ties, i, nc, &cnt, _state); + } + *cve = *cve+bdss_getcv(&cnt, nc, _state); + } + else + { + + /* + * General case: 2 or more intervals + * + * NOTE: we initialize both JL and JR (left and right bounds), + * altough algorithm needs only JL. + */ + ae_vector_set_length(thresholds, koptimal-1+1, _state); + *ni = koptimal+1; + *cve = cv.ptr.pp_double[koptimal][tiecount-1]; + jl = splits.ptr.pp_int[koptimal][tiecount-1]; + jr = tiecount-1; + for(k=koptimal; k>=1; k--) + { + thresholds->ptr.p_double[k-1] = 0.5*(a.ptr.p_double[ties.ptr.p_int[jl-1]]+a.ptr.p_double[ties.ptr.p_int[jl]]); + jr = jl-1; + jl = splits.ptr.pp_int[k-1][jl-1]; + } + touchint(&jr, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal function +*************************************************************************/ +static double bdss_xlny(double x, double y, ae_state *_state) +{ + double result; + + + if( ae_fp_eq(x,(double)(0)) ) + { + result = (double)(0); + } + else + { + result = x*ae_log(y, _state); + } + return result; +} + + +/************************************************************************* +Internal function, +returns number of samples of class I in Cnt[I] +*************************************************************************/ +static double bdss_getcv(/* Integer */ const ae_vector* cnt, + ae_int_t nc, + ae_state *_state) +{ + ae_int_t i; + double s; + double result; + + + s = (double)(0); + for(i=0; i<=nc-1; i++) + { + s = s+(double)cnt->ptr.p_int[i]; + } + result = (double)(0); + for(i=0; i<=nc-1; i++) + { + result = result-bdss_xlny((double)(cnt->ptr.p_int[i]), (double)cnt->ptr.p_int[i]/(s+(double)nc-(double)1), _state); + } + return result; +} + + +/************************************************************************* +Internal function, adds number of samples of class I in tie NTie to Cnt[I] +*************************************************************************/ +static void bdss_tieaddc(/* Integer */ const ae_vector* c, + /* Integer */ const ae_vector* ties, + ae_int_t ntie, + ae_int_t nc, + /* Integer */ ae_vector* cnt, + ae_state *_state) +{ + ae_int_t i; + + + for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) + { + cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]+1; + } +} + + +/************************************************************************* +Internal function, subtracts number of samples of class I in tie NTie to Cnt[I] +*************************************************************************/ +static void bdss_tiesubc(/* Integer */ const ae_vector* c, + /* Integer */ const ae_vector* ties, + ae_int_t ntie, + ae_int_t nc, + /* Integer */ ae_vector* cnt, + ae_state *_state) +{ + ae_int_t i; + + + for(i=ties->ptr.p_int[ntie]; i<=ties->ptr.p_int[ntie+1]-1; i++) + { + cnt->ptr.p_int[c->ptr.p_int[i]] = cnt->ptr.p_int[c->ptr.p_int[i]]-1; + } +} + + +void _cvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + cvreport *p = (cvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _cvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + cvreport *dst = (cvreport*)_dst; + const cvreport *src = (const cvreport*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; +} + + +void _cvreport_clear(void* _p) +{ + cvreport *p = (cvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _cvreport_destroy(void* _p) +{ + cvreport *p = (cvreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function returns number of weights updates which is required for +gradient calculation problem to be splitted. +*************************************************************************/ +ae_int_t mlpgradsplitcost(ae_state *_state) +{ + ae_int_t result; + + + result = mlpbase_gradbasecasecost; + return result; +} + + +/************************************************************************* +This function returns number of elements in subset of dataset which is +required for gradient calculation problem to be splitted. +*************************************************************************/ +ae_int_t mlpgradsplitsize(ae_state *_state) +{ + ae_int_t result; + + + result = mlpbase_microbatchsize; + return result; +} + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers, with linear output layer. Network weights are filled with small +random values. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate0(ae_int_t nin, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreate0, but with one hidden layer (NHid neurons) with +non-linear activation function. Output layer is linear. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) +with non-linear activation function. Output layer is linear. + $ALL + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(-5, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. + +Activation function of the output layer takes values: + + (B, +INF), if D>=0 + +or + + (-INF, B), if D<0. + + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb0(ae_int_t nin, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3; + if( ae_fp_greater_eq(d,(double)(0)) ) + { + d = (double)(1); + } + else + { + d = (double)(-1); + } + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); + + /* + * Turn on ouputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = b; + network->columnsigmas.ptr.p_double[i] = d; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateB0 but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3; + if( ae_fp_greater_eq(d,(double)(0)) ) + { + d = (double)(1); + } + else + { + d = (double)(-1); + } + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); + + /* + * Turn on ouputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = b; + network->columnsigmas.ptr.p_double[i] = d; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateB0 but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3+3; + if( ae_fp_greater_eq(d,(double)(0)) ) + { + d = (double)(1); + } + else + { + d = (double)(-1); + } + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(3, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); + + /* + * Turn on ouputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = b; + network->columnsigmas.ptr.p_double[i] = d; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. Activation function of the output layer takes values [A,B]. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater0(ae_int_t nin, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_false, ae_false, _state); + + /* + * Turn on outputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = 0.5*(a+b); + network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateR0, but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_false, ae_false, _state); + + /* + * Turn on outputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = 0.5*(a+b); + network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateR0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + layerscount = 1+3+3+3; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_false, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_false, ae_false, _state); + + /* + * Turn on outputs shift/scaling. + */ + for(i=nin; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = 0.5*(a+b); + network->columnsigmas.ptr.p_double[i] = 0.5*(a-b); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Creates classifier network with NIn inputs and NOut possible classes. +Network contains no hidden layers and linear output layer with SOFTMAX- +normalization (so outputs sums up to 1.0 and converge to posterior +probabilities). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec0(ae_int_t nin, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + ae_assert(nout>=2, "MLPCreateC0: NOut<2!", _state); + layerscount = 1+2+1; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); + mlpbase_fillhighlevelinformation(network, nin, 0, 0, nout, ae_true, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateC0, but with one non-linear hidden layer. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + ae_assert(nout>=2, "MLPCreateC1: NOut<2!", _state); + layerscount = 1+3+2+1; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid, 0, nout, ae_true, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Same as MLPCreateC0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector lsizes; + ae_vector ltypes; + ae_vector lconnfirst; + ae_vector lconnlast; + ae_int_t layerscount; + ae_int_t lastproc; + + ae_frame_make(_state, &_frame_block); + memset(&lsizes, 0, sizeof(lsizes)); + memset(<ypes, 0, sizeof(ltypes)); + memset(&lconnfirst, 0, sizeof(lconnfirst)); + memset(&lconnlast, 0, sizeof(lconnlast)); + _multilayerperceptron_clear(network); + ae_vector_init(&lsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(<ypes, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lconnlast, 0, DT_INT, _state, ae_true); + + ae_assert(nout>=2, "MLPCreateC2: NOut<2!", _state); + layerscount = 1+3+3+2+1; + + /* + * Allocate arrays + */ + ae_vector_set_length(&lsizes, layerscount-1+1, _state); + ae_vector_set_length(<ypes, layerscount-1+1, _state); + ae_vector_set_length(&lconnfirst, layerscount-1+1, _state); + ae_vector_set_length(&lconnlast, layerscount-1+1, _state); + + /* + * Layers + */ + mlpbase_addinputlayer(nin, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nhid2, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addactivationlayer(1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addbiasedsummatorlayer(nout-1, &lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + mlpbase_addzerolayer(&lsizes, <ypes, &lconnfirst, &lconnlast, &lastproc, _state); + + /* + * Create + */ + mlpbase_mlpcreate(nin, nout, &lsizes, <ypes, &lconnfirst, &lconnlast, layerscount, ae_true, network, _state); + mlpbase_fillhighlevelinformation(network, nin, nhid1, nhid2, nout, ae_true, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Copying of neural network + +INPUT PARAMETERS: + Network1 - original + +OUTPUT PARAMETERS: + Network2 - copy + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcopy(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state) +{ + + _multilayerperceptron_clear(network2); + + mlpcopyshared(network1, network2, _state); +} + + +/************************************************************************* +Copying of neural network (second parameter is passed as shared object). + +INPUT PARAMETERS: + Network1 - original + +OUTPUT PARAMETERS: + Network2 - copy + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcopyshared(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t wcount; + ae_int_t i; + mlpbuffers buf; + smlpgrad sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&sgrad, 0, sizeof(sgrad)); + _mlpbuffers_init(&buf, _state, ae_true); + _smlpgrad_init(&sgrad, _state, ae_true); + + + /* + * Copy scalar and array fields + */ + network2->hlnetworktype = network1->hlnetworktype; + network2->hlnormtype = network1->hlnormtype; + copyintegerarray(&network1->hllayersizes, &network2->hllayersizes, _state); + copyintegerarray(&network1->hlconnections, &network2->hlconnections, _state); + copyintegerarray(&network1->hlneurons, &network2->hlneurons, _state); + copyintegerarray(&network1->structinfo, &network2->structinfo, _state); + copyrealarray(&network1->weights, &network2->weights, _state); + copyrealarray(&network1->columnmeans, &network2->columnmeans, _state); + copyrealarray(&network1->columnsigmas, &network2->columnsigmas, _state); + copyrealarray(&network1->neurons, &network2->neurons, _state); + copyrealarray(&network1->dfdnet, &network2->dfdnet, _state); + copyrealarray(&network1->derror, &network2->derror, _state); + copyrealarray(&network1->x, &network2->x, _state); + copyrealarray(&network1->y, &network2->y, _state); + copyrealarray(&network1->nwbuf, &network2->nwbuf, _state); + copyintegerarray(&network1->integerbuf, &network2->integerbuf, _state); + + /* + * copy buffers + */ + wcount = mlpgetweightscount(network1, _state); + ae_shared_pool_set_seed(&network2->buf, &buf, (ae_int_t)sizeof(buf), (ae_copy_constructor)_mlpbuffers_init_copy, (ae_destructor)_mlpbuffers_destroy, _state); + ae_vector_set_length(&sgrad.g, wcount, _state); + sgrad.f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad.g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_set_seed(&network2->gradbuf, &sgrad, (ae_int_t)sizeof(sgrad), (ae_copy_constructor)_smlpgrad_init_copy, (ae_destructor)_smlpgrad_destroy, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function compares architectures of neural networks. Only geometries +are compared, weights and other parameters are not tested. + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +ae_bool mlpsamearchitecture(const multilayerperceptron* network1, + const multilayerperceptron* network2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ninfo; + ae_bool result; + + + ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network1 is uninitialized", _state); + ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPSameArchitecture: Network2 is uninitialized", _state); + result = ae_false; + if( network1->structinfo.ptr.p_int[0]!=network2->structinfo.ptr.p_int[0] ) + { + return result; + } + ninfo = network1->structinfo.ptr.p_int[0]; + for(i=0; i<=ninfo-1; i++) + { + if( network1->structinfo.ptr.p_int[i]!=network2->structinfo.ptr.p_int[i] ) + { + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function copies tunable parameters (weights/means/sigmas) from one +network to another with same architecture. It performs some rudimentary +checks that architectures are same, and throws exception if check fails. + +It is intended for fast copying of states between two network which are +known to have same geometry. + +INPUT PARAMETERS: + Network1 - source, must be correctly initialized + Network2 - target, must have same architecture + +OUTPUT PARAMETERS: + Network2 - network state is copied from source to target + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +void mlpcopytunableparameters(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ninfo; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + + + ae_assert(network1->structinfo.cnt>0&&network1->structinfo.cnt>=network1->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 is uninitialized", _state); + ae_assert(network2->structinfo.cnt>0&&network2->structinfo.cnt>=network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network2 is uninitialized", _state); + ae_assert(network1->structinfo.ptr.p_int[0]==network2->structinfo.ptr.p_int[0], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); + ninfo = network1->structinfo.ptr.p_int[0]; + for(i=0; i<=ninfo-1; i++) + { + ae_assert(network1->structinfo.ptr.p_int[i]==network2->structinfo.ptr.p_int[i], "MLPCopyTunableParameters: Network1 geometry differs from that of Network2", _state); + } + mlpproperties(network1, &nin, &nout, &wcount, _state); + for(i=0; i<=wcount-1; i++) + { + network2->weights.ptr.p_double[i] = network1->weights.ptr.p_double[i]; + } + if( mlpissoftmax(network1, _state) ) + { + for(i=0; i<=nin-1; i++) + { + network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; + network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; + } + } + else + { + for(i=0; i<=nin+nout-1; i++) + { + network2->columnmeans.ptr.p_double[i] = network1->columnmeans.ptr.p_double[i]; + network2->columnsigmas.ptr.p_double[i] = network1->columnsigmas.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function exports tunable parameters (weights/means/sigmas) from +network to contiguous array. Nothing is guaranteed about array format, the +only thing you can count for is that MLPImportTunableParameters() will be +able to parse it. + +It is intended for fast copying of states between network and backup array + +INPUT PARAMETERS: + Network - source, must be correctly initialized + P - array to use. If its size is enough to store data, it + is reused. + +OUTPUT PARAMETERS: + P - array which stores network parameters, resized if needed + PCount - number of parameters stored in array. + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +void mlpexporttunableparameters(const multilayerperceptron* network, + /* Real */ ae_vector* p, + ae_int_t* pcount, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + + *pcount = 0; + + ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPExportTunableParameters: Network is uninitialized", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + if( mlpissoftmax(network, _state) ) + { + *pcount = wcount+2*nin; + rvectorsetlengthatleast(p, *pcount, _state); + k = 0; + for(i=0; i<=wcount-1; i++) + { + p->ptr.p_double[k] = network->weights.ptr.p_double[i]; + k = k+1; + } + for(i=0; i<=nin-1; i++) + { + p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; + k = k+1; + p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; + k = k+1; + } + } + else + { + *pcount = wcount+2*(nin+nout); + rvectorsetlengthatleast(p, *pcount, _state); + k = 0; + for(i=0; i<=wcount-1; i++) + { + p->ptr.p_double[k] = network->weights.ptr.p_double[i]; + k = k+1; + } + for(i=0; i<=nin+nout-1; i++) + { + p->ptr.p_double[k] = network->columnmeans.ptr.p_double[i]; + k = k+1; + p->ptr.p_double[k] = network->columnsigmas.ptr.p_double[i]; + k = k+1; + } + } +} + + +/************************************************************************* +This function imports tunable parameters (weights/means/sigmas) which +were exported by MLPExportTunableParameters(). + +It is intended for fast copying of states between network and backup array + +INPUT PARAMETERS: + Network - target: + * must be correctly initialized + * must have same geometry as network used to export params + P - array with parameters + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +void mlpimporttunableparameters(multilayerperceptron* network, + /* Real */ ae_vector* p, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + + + ae_assert(network->structinfo.cnt>0&&network->structinfo.cnt>=network->structinfo.ptr.p_int[0], "MLPImportTunableParameters: Network is uninitialized", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + if( mlpissoftmax(network, _state) ) + { + k = 0; + for(i=0; i<=wcount-1; i++) + { + network->weights.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + } + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + } + } + else + { + k = 0; + for(i=0; i<=wcount-1; i++) + { + network->weights.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + } + for(i=0; i<=nin+nout-1; i++) + { + network->columnmeans.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + network->columnsigmas.ptr.p_double[i] = p->ptr.p_double[k]; + k = k+1; + } + } +} + + +/************************************************************************* +Serialization of MultiLayerPerceptron strucure + +INPUT PARAMETERS: + Network - original + +OUTPUT PARAMETERS: + RA - array of real numbers which stores network, + array[0..RLen-1] + RLen - RA lenght + + -- ALGLIB -- + Copyright 29.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpserializeold(const multilayerperceptron* network, + /* Real */ ae_vector* ra, + ae_int_t* rlen, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ssize; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t sigmalen; + ae_int_t offs; + + ae_vector_clear(ra); + *rlen = 0; + + + /* + * Unload info + */ + ssize = network->structinfo.ptr.p_int[0]; + nin = network->structinfo.ptr.p_int[1]; + nout = network->structinfo.ptr.p_int[2]; + wcount = network->structinfo.ptr.p_int[4]; + if( mlpissoftmax(network, _state) ) + { + sigmalen = nin; + } + else + { + sigmalen = nin+nout; + } + + /* + * RA format: + * LEN DESRC. + * 1 RLen + * 1 version (MLPVNum) + * 1 StructInfo size + * SSize StructInfo + * WCount Weights + * SigmaLen ColumnMeans + * SigmaLen ColumnSigmas + */ + *rlen = 3+ssize+wcount+2*sigmalen; + ae_vector_set_length(ra, *rlen-1+1, _state); + ra->ptr.p_double[0] = (double)(*rlen); + ra->ptr.p_double[1] = (double)(mlpbase_mlpvnum); + ra->ptr.p_double[2] = (double)(ssize); + offs = 3; + for(i=0; i<=ssize-1; i++) + { + ra->ptr.p_double[offs+i] = (double)(network->structinfo.ptr.p_int[i]); + } + offs = offs+ssize; + ae_v_move(&ra->ptr.p_double[offs], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); + offs = offs+wcount; + ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); + offs = offs+sigmalen; + ae_v_move(&ra->ptr.p_double[offs], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(offs,offs+sigmalen-1)); + offs = offs+sigmalen; +} + + +/************************************************************************* +Unserialization of MultiLayerPerceptron strucure + +INPUT PARAMETERS: + RA - real array which stores network + +OUTPUT PARAMETERS: + Network - restored network + + -- ALGLIB -- + Copyright 29.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpunserializeold(/* Real */ const ae_vector* ra, + multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ssize; + ae_int_t ntotal; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t sigmalen; + ae_int_t offs; + + _multilayerperceptron_clear(network); + + ae_assert(ae_round(ra->ptr.p_double[1], _state)==mlpbase_mlpvnum, "MLPUnserialize: incorrect array!", _state); + + /* + * Unload StructInfo from IA + */ + offs = 3; + ssize = ae_round(ra->ptr.p_double[2], _state); + ae_vector_set_length(&network->structinfo, ssize-1+1, _state); + for(i=0; i<=ssize-1; i++) + { + network->structinfo.ptr.p_int[i] = ae_round(ra->ptr.p_double[offs+i], _state); + } + offs = offs+ssize; + + /* + * Unload info from StructInfo + */ + ssize = network->structinfo.ptr.p_int[0]; + nin = network->structinfo.ptr.p_int[1]; + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + wcount = network->structinfo.ptr.p_int[4]; + if( network->structinfo.ptr.p_int[6]==0 ) + { + sigmalen = nin+nout; + } + else + { + sigmalen = nin; + } + + /* + * Allocate space for other fields + */ + ae_vector_set_length(&network->weights, wcount-1+1, _state); + ae_vector_set_length(&network->columnmeans, sigmalen-1+1, _state); + ae_vector_set_length(&network->columnsigmas, sigmalen-1+1, _state); + ae_vector_set_length(&network->neurons, ntotal-1+1, _state); + ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); + ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); + ae_vector_set_length(&network->x, nin-1+1, _state); + ae_vector_set_length(&network->y, nout-1+1, _state); + ae_vector_set_length(&network->derror, ntotal-1+1, _state); + + /* + * Copy parameters from RA + */ + ae_v_move(&network->weights.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,wcount-1)); + offs = offs+wcount; + ae_v_move(&network->columnmeans.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); + offs = offs+sigmalen; + ae_v_move(&network->columnsigmas.ptr.p_double[0], 1, &ra->ptr.p_double[offs], 1, ae_v_len(0,sigmalen-1)); + offs = offs+sigmalen; +} + + +/************************************************************************* +Randomization of neural network weights + + -- ALGLIB -- + Copyright 06.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlprandomize(multilayerperceptron* network, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + hqrndstate r; + ae_int_t entrysize; + ae_int_t entryoffs; + ae_int_t neuronidx; + ae_int_t neurontype; + double vmean; + double vvar; + ae_int_t i; + ae_int_t n1; + ae_int_t n2; + double desiredsigma; + ae_int_t montecarlocnt; + double ef; + double ef2; + double v; + double wscale; + + ae_frame_make(_state, &_frame_block); + memset(&r, 0, sizeof(r)); + _hqrndstate_init(&r, _state, ae_true); + + hqrndrandomize(&r, _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + desiredsigma = 0.5; + montecarlocnt = 20; + + /* + * Stage 1: + * * Network.Weights is filled by standard deviation of weights + * * default values: sigma=1 + */ + for(i=0; i<=wcount-1; i++) + { + network->weights.ptr.p_double[i] = 1.0; + } + + /* + * Stage 2: + * * assume that input neurons have zero mean and unit standard deviation + * * assume that constant neurons have zero standard deviation + * * perform forward pass along neurons + * * for each non-input non-constant neuron: + * * calculate mean and standard deviation of neuron's output + * assuming that we know means/deviations of neurons which feed it + * and assuming that weights has unit variance and zero mean. + * * for each nonlinear neuron additionally we perform backward pass: + * * scale variances of weights which feed it in such way that neuron's + * input has unit standard deviation + * + * NOTE: this algorithm assumes that each connection feeds at most one + * non-linear neuron. This assumption can be incorrect in upcoming + * architectures with strong neurons. However, algorithm should + * work smoothly even in this case. + * + * During this stage we use Network.RndBuf, which is grouped into NTotal + * entries, each of them having following format: + * + * Buf[Offset+0] mean value of neuron's output + * Buf[Offset+1] standard deviation of neuron's output + * + * + */ + entrysize = 2; + rvectorsetlengthatleast(&network->rndbuf, entrysize*ntotal, _state); + for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) + { + neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; + entryoffs = entrysize*neuronidx; + if( neurontype==-2 ) + { + + /* + * Input neuron: zero mean, unit variance. + */ + network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; + network->rndbuf.ptr.p_double[entryoffs+1] = 1.0; + continue; + } + if( neurontype==-3 ) + { + + /* + * "-1" neuron: mean=-1, zero variance. + */ + network->rndbuf.ptr.p_double[entryoffs+0] = -1.0; + network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; + continue; + } + if( neurontype==-4 ) + { + + /* + * "0" neuron: mean=0, zero variance. + */ + network->rndbuf.ptr.p_double[entryoffs+0] = 0.0; + network->rndbuf.ptr.p_double[entryoffs+1] = 0.0; + continue; + } + if( neurontype==0 ) + { + + /* + * Adaptive summator neuron: + * * calculate its mean and variance. + * * we assume that weights of this neuron have unit variance and zero mean. + * * thus, neuron's output is always have zero mean + * * as for variance, it is a bit more interesting: + * * let n[i] is i-th input neuron + * * let w[i] is i-th weight + * * we assume that n[i] and w[i] are independently distributed + * * Var(n0*w0+n1*w1+...) = Var(n0*w0)+Var(n1*w1)+... + * * Var(X*Y) = mean(X)^2*Var(Y) + mean(Y)^2*Var(X) + Var(X)*Var(Y) + * * mean(w[i])=0, var(w[i])=1 + * * Var(n[i]*w[i]) = mean(n[i])^2 + Var(n[i]) + */ + n1 = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; + n2 = n1+network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+1]-1; + vmean = 0.0; + vvar = 0.0; + for(i=n1; i<=n2; i++) + { + vvar = vvar+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+0], _state)+ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); + } + network->rndbuf.ptr.p_double[entryoffs+0] = vmean; + network->rndbuf.ptr.p_double[entryoffs+1] = ae_sqrt(vvar, _state); + continue; + } + if( neurontype==-5 ) + { + + /* + * Linear activation function + */ + i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; + vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; + vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); + if( ae_fp_greater(vvar,(double)(0)) ) + { + wscale = desiredsigma/ae_sqrt(vvar, _state); + } + else + { + wscale = 1.0; + } + mlpbase_randomizebackwardpass(network, i, wscale, _state); + network->rndbuf.ptr.p_double[entryoffs+0] = vmean*wscale; + network->rndbuf.ptr.p_double[entryoffs+1] = desiredsigma; + continue; + } + if( neurontype>0 ) + { + + /* + * Nonlinear activation function: + * * scale its inputs + * * estimate mean/sigma of its output using Monte-Carlo method + * (we simulate different inputs with unit deviation and + * sample activation function output on such inputs) + */ + i = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+2]; + vmean = network->rndbuf.ptr.p_double[entrysize*i+0]; + vvar = ae_sqr(network->rndbuf.ptr.p_double[entrysize*i+1], _state); + if( ae_fp_greater(vvar,(double)(0)) ) + { + wscale = desiredsigma/ae_sqrt(vvar, _state); + } + else + { + wscale = 1.0; + } + mlpbase_randomizebackwardpass(network, i, wscale, _state); + ef = 0.0; + ef2 = 0.0; + vmean = vmean*wscale; + for(i=0; i<=montecarlocnt-1; i++) + { + v = vmean+desiredsigma*hqrndnormal(&r, _state); + ef = ef+v; + ef2 = ef2+v*v; + } + ef = ef/(double)montecarlocnt; + ef2 = ef2/(double)montecarlocnt; + network->rndbuf.ptr.p_double[entryoffs+0] = ef; + network->rndbuf.ptr.p_double[entryoffs+1] = ae_maxreal(ef2-ef*ef, 0.0, _state); + continue; + } + ae_assert(ae_false, "MLPRandomize: unexpected neuron type", _state); + } + + /* + * Stage 3: generate weights. + */ + for(i=0; i<=wcount-1; i++) + { + network->weights.ptr.p_double[i] = network->weights.ptr.p_double[i]*hqrndnormal(&r, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Randomization of neural network weights and standartisator + + -- ALGLIB -- + Copyright 10.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlprandomizefull(multilayerperceptron* network, ae_state *_state) +{ + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t offs; + ae_int_t ntype; + + + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Process network + */ + mlprandomize(network, _state); + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = ae_randomreal(_state)-0.5; + network->columnsigmas.ptr.p_double[i] = ae_randomreal(_state)+0.5; + } + if( !mlpissoftmax(network, _state) ) + { + for(i=0; i<=nout-1; i++) + { + offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; + ntype = network->structinfo.ptr.p_int[offs+0]; + if( ntype==0 ) + { + + /* + * Shifts are changed only for linear outputs neurons + */ + network->columnmeans.ptr.p_double[nin+i] = (double)2*ae_randomreal(_state)-(double)1; + } + if( ntype==0||ntype==3 ) + { + + /* + * Scales are changed only for linear or bounded outputs neurons. + * Note that scale randomization preserves sign. + */ + network->columnsigmas.ptr.p_double[nin+i] = (double)ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*(1.5*ae_randomreal(_state)+0.5); + } + } + } +} + + +/************************************************************************* +Internal subroutine. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessor(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t jmax; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t offs; + ae_int_t ntype; + ae_vector means; + ae_vector sigmas; + double s; + + ae_frame_make(_state, &_frame_block); + memset(&means, 0, sizeof(means)); + memset(&sigmas, 0, sizeof(sigmas)); + ae_vector_init(&means, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); + + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Means/Sigmas + */ + if( mlpissoftmax(network, _state) ) + { + jmax = nin-1; + } + else + { + jmax = nin+nout-1; + } + ae_vector_set_length(&means, jmax+1, _state); + ae_vector_set_length(&sigmas, jmax+1, _state); + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = (double)(0); + sigmas.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=ssize-1; i++) + { + for(j=0; j<=jmax; j++) + { + means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[i][j]; + } + } + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = means.ptr.p_double[i]/(double)ssize; + } + for(i=0; i<=ssize-1; i++) + { + for(j=0; j<=jmax; j++) + { + sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[i][j]-means.ptr.p_double[j], _state); + } + } + for(i=0; i<=jmax; i++) + { + sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/(double)ssize, _state); + } + + /* + * Inputs + */ + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; + network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[i] = (double)(1); + } + } + + /* + * Outputs + */ + if( !mlpissoftmax(network, _state) ) + { + for(i=0; i<=nout-1; i++) + { + offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; + ntype = network->structinfo.ptr.p_int[offs+0]; + + /* + * Linear outputs + */ + if( ntype==0 ) + { + network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; + network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + + /* + * Bounded outputs (half-interval) + */ + if( ntype==3 ) + { + s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = 1.0; + } + network->columnsigmas.ptr.p_double[nin+i] = (double)ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Initialization for preprocessor based on a sample. + +INPUT + Network - initialized neural network; + XY - sample, given by sparse matrix; + SSize - sample size. + +OUTPUT + Network - neural network with initialised preprocessor. + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t ssize, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t jmax; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t offs; + ae_int_t ntype; + ae_vector means; + ae_vector sigmas; + double s; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&means, 0, sizeof(means)); + memset(&sigmas, 0, sizeof(sigmas)); + ae_vector_init(&means, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); + + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Means/Sigmas + */ + if( mlpissoftmax(network, _state) ) + { + jmax = nin-1; + } + else + { + jmax = nin+nout-1; + } + ae_vector_set_length(&means, jmax+1, _state); + ae_vector_set_length(&sigmas, jmax+1, _state); + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = (double)(0); + sigmas.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=ssize-1; i++) + { + sparsegetrow(xy, i, &network->xyrow, _state); + for(j=0; j<=jmax; j++) + { + means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; + } + } + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = means.ptr.p_double[i]/(double)ssize; + } + for(i=0; i<=ssize-1; i++) + { + sparsegetrow(xy, i, &network->xyrow, _state); + for(j=0; j<=jmax; j++) + { + sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); + } + } + for(i=0; i<=jmax; i++) + { + sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/(double)ssize, _state); + } + + /* + * Inputs + */ + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; + network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[i] = (double)(1); + } + } + + /* + * Outputs + */ + if( !mlpissoftmax(network, _state) ) + { + for(i=0; i<=nout-1; i++) + { + offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; + ntype = network->structinfo.ptr.p_int[offs+0]; + + /* + * Linear outputs + */ + if( ntype==0 ) + { + network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; + network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + + /* + * Bounded outputs (half-interval) + */ + if( ntype==3 ) + { + s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = 1.0; + } + network->columnsigmas.ptr.p_double[nin+i] = (double)ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Initialization for preprocessor based on a subsample. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array. + +OUTPUT: + Network - neural network with initialised preprocessor. + +NOTE: when SubsetSize<0 is used full dataset by call MLPInitPreprocessor + function. + + -- ALGLIB -- + Copyright 23.08.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessorsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t jmax; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t offs; + ae_int_t ntype; + ae_vector means; + ae_vector sigmas; + double s; + ae_int_t npoints; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&means, 0, sizeof(means)); + memset(&sigmas, 0, sizeof(sigmas)); + ae_vector_init(&means, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); + + ae_assert(setsize>=0, "MLPInitPreprocessorSubset: SetSize<0", _state); + if( subsetsize<0 ) + { + mlpinitpreprocessor(network, xy, setsize, _state); + ae_frame_leave(_state); + return; + } + ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSubset: SubsetSize>Length(Idx)", _state); + npoints = setsize; + for(i=0; i<=subsetsize-1; i++) + { + ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]<0)", _state); + ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); + } + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Means/Sigmas + */ + if( mlpissoftmax(network, _state) ) + { + jmax = nin-1; + } + else + { + jmax = nin+nout-1; + } + ae_vector_set_length(&means, jmax+1, _state); + ae_vector_set_length(&sigmas, jmax+1, _state); + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = (double)(0); + sigmas.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=subsetsize-1; i++) + { + for(j=0; j<=jmax; j++) + { + means.ptr.p_double[j] = means.ptr.p_double[j]+xy->ptr.pp_double[idx->ptr.p_int[i]][j]; + } + } + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = means.ptr.p_double[i]/(double)subsetsize; + } + for(i=0; i<=subsetsize-1; i++) + { + for(j=0; j<=jmax; j++) + { + sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(xy->ptr.pp_double[idx->ptr.p_int[i]][j]-means.ptr.p_double[j], _state); + } + } + for(i=0; i<=jmax; i++) + { + sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/(double)subsetsize, _state); + } + + /* + * Inputs + */ + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; + network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[i] = (double)(1); + } + } + + /* + * Outputs + */ + if( !mlpissoftmax(network, _state) ) + { + for(i=0; i<=nout-1; i++) + { + offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; + ntype = network->structinfo.ptr.p_int[offs+0]; + + /* + * Linear outputs + */ + if( ntype==0 ) + { + network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; + network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + + /* + * Bounded outputs (half-interval) + */ + if( ntype==3 ) + { + s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = 1.0; + } + network->columnsigmas.ptr.p_double[nin+i] = (double)ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Initialization for preprocessor based on a subsample. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset, given by sparse matrix; + one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array. + +OUTPUT: + Network - neural network with initialised preprocessor. + +NOTE: when SubsetSize<0 is used full dataset by call + MLPInitPreprocessorSparse function. + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t jmax; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t offs; + ae_int_t ntype; + ae_vector means; + ae_vector sigmas; + double s; + ae_int_t npoints; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&means, 0, sizeof(means)); + memset(&sigmas, 0, sizeof(sigmas)); + ae_vector_init(&means, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); + + ae_assert(setsize>=0, "MLPInitPreprocessorSparseSubset: SetSize<0", _state); + if( subsetsize<0 ) + { + mlpinitpreprocessorsparse(network, xy, setsize, _state); + ae_frame_leave(_state); + return; + } + ae_assert(subsetsize<=idx->cnt, "MLPInitPreprocessorSparseSubset: SubsetSize>Length(Idx)", _state); + npoints = setsize; + for(i=0; i<=subsetsize-1; i++) + { + ae_assert(idx->ptr.p_int[i]>=0, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); + ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPInitPreprocessorSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); + } + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Means/Sigmas + */ + if( mlpissoftmax(network, _state) ) + { + jmax = nin-1; + } + else + { + jmax = nin+nout-1; + } + ae_vector_set_length(&means, jmax+1, _state); + ae_vector_set_length(&sigmas, jmax+1, _state); + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = (double)(0); + sigmas.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=subsetsize-1; i++) + { + sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); + for(j=0; j<=jmax; j++) + { + means.ptr.p_double[j] = means.ptr.p_double[j]+network->xyrow.ptr.p_double[j]; + } + } + for(i=0; i<=jmax; i++) + { + means.ptr.p_double[i] = means.ptr.p_double[i]/(double)subsetsize; + } + for(i=0; i<=subsetsize-1; i++) + { + sparsegetrow(xy, idx->ptr.p_int[i], &network->xyrow, _state); + for(j=0; j<=jmax; j++) + { + sigmas.ptr.p_double[j] = sigmas.ptr.p_double[j]+ae_sqr(network->xyrow.ptr.p_double[j]-means.ptr.p_double[j], _state); + } + } + for(i=0; i<=jmax; i++) + { + sigmas.ptr.p_double[i] = ae_sqrt(sigmas.ptr.p_double[i]/(double)subsetsize, _state); + } + + /* + * Inputs + */ + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = means.ptr.p_double[i]; + network->columnsigmas.ptr.p_double[i] = sigmas.ptr.p_double[i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[i] = (double)(1); + } + } + + /* + * Outputs + */ + if( !mlpissoftmax(network, _state) ) + { + for(i=0; i<=nout-1; i++) + { + offs = istart+(ntotal-nout+i)*mlpbase_nfieldwidth; + ntype = network->structinfo.ptr.p_int[offs+0]; + + /* + * Linear outputs + */ + if( ntype==0 ) + { + network->columnmeans.ptr.p_double[nin+i] = means.ptr.p_double[nin+i]; + network->columnsigmas.ptr.p_double[nin+i] = sigmas.ptr.p_double[nin+i]; + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + + /* + * Bounded outputs (half-interval) + */ + if( ntype==3 ) + { + s = means.ptr.p_double[nin+i]-network->columnmeans.ptr.p_double[nin+i]; + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)); + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = 1.0; + } + network->columnsigmas.ptr.p_double[nin+i] = (double)ae_sign(network->columnsigmas.ptr.p_double[nin+i], _state)*ae_fabs(s, _state); + if( ae_fp_eq(network->columnsigmas.ptr.p_double[nin+i],(double)(0)) ) + { + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns information about initialized network: number of inputs, outputs, +weights. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpproperties(const multilayerperceptron* network, + ae_int_t* nin, + ae_int_t* nout, + ae_int_t* wcount, + ae_state *_state) +{ + + *nin = 0; + *nout = 0; + *wcount = 0; + + *nin = network->structinfo.ptr.p_int[1]; + *nout = network->structinfo.ptr.p_int[2]; + *wcount = network->structinfo.ptr.p_int[4]; +} + + +/************************************************************************* +Returns number of "internal", low-level neurons in the network (one which +is stored in StructInfo). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpntotal(const multilayerperceptron* network, ae_state *_state) +{ + ae_int_t result; + + + result = network->structinfo.ptr.p_int[3]; + return result; +} + + +/************************************************************************* +Returns number of inputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetinputscount(const multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t result; + + + result = network->structinfo.ptr.p_int[1]; + return result; +} + + +/************************************************************************* +Returns number of outputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetoutputscount(const multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t result; + + + result = network->structinfo.ptr.p_int[2]; + return result; +} + + +/************************************************************************* +Returns number of weights. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetweightscount(const multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t result; + + + result = network->structinfo.ptr.p_int[4]; + return result; +} + + +/************************************************************************* +Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +ae_bool mlpissoftmax(const multilayerperceptron* network, + ae_state *_state) +{ + ae_bool result; + + + result = network->structinfo.ptr.p_int[6]==1; + return result; +} + + +/************************************************************************* +This function returns total number of layers (including input, hidden and +output layers). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayerscount(const multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t result; + + + result = network->hllayersizes.cnt; + return result; +} + + +/************************************************************************* +This function returns size of K-th layer. + +K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. + +Size of the output layer is always equal to the number of outputs, although +when we have softmax-normalized network, last neuron doesn't have any +connections - it is just zero. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayersize(const multilayerperceptron* network, + ae_int_t k, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(k>=0&&khllayersizes.cnt, "MLPGetLayerSize: incorrect layer index", _state); + result = network->hllayersizes.ptr.p_int[k]; + return result; +} + + +/************************************************************************* +This function returns offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetinputscaling(const multilayerperceptron* network, + ae_int_t i, + double* mean, + double* sigma, + ae_state *_state) +{ + + *mean = 0.0; + *sigma = 0.0; + + ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPGetInputScaling: incorrect (nonexistent) I", _state); + *mean = network->columnmeans.ptr.p_double[i]; + *sigma = network->columnsigmas.ptr.p_double[i]; + if( ae_fp_eq(*sigma,(double)(0)) ) + { + *sigma = (double)(1); + } +} + + +/************************************************************************* +This function returns offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. In case we have SOFTMAX-normalized network, +we return (Mean,Sigma)=(0.0,1.0). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetoutputscaling(const multilayerperceptron* network, + ae_int_t i, + double* mean, + double* sigma, + ae_state *_state) +{ + + *mean = 0.0; + *sigma = 0.0; + + ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPGetOutputScaling: incorrect (nonexistent) I", _state); + if( network->structinfo.ptr.p_int[6]==1 ) + { + *mean = (double)(0); + *sigma = (double)(1); + } + else + { + *mean = network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; + *sigma = network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i]; + } +} + + +/************************************************************************* +This function returns information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + +OUTPUT PARAMETERS: + FKind - activation function type (used by MLPActivationFunction()) + this value is zero for input or linear neurons + Threshold - also called offset, bias + zero for input neurons + +NOTE: this function throws exception if layer or neuron with given index +do not exists. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetneuroninfo(multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + ae_int_t* fkind, + double* threshold, + ae_state *_state) +{ + + *fkind = 0; + *threshold = 0.0; + + mlpbase_mlpgetneuroninfox(network, k, i, &network->integerbuf, fkind, threshold, _state); +} + + +/************************************************************************* +This function returns information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + +RESULT: + connection weight (zero for non-existent connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. returns zero if neurons exist, but there is no connection between them + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +double mlpgetweight(multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + ae_state *_state) +{ + double result; + + + result = mlpbase_mlpgetweightx(network, k0, i0, k1, i1, &network->integerbuf, _state); + return result; +} + + +/************************************************************************* +This function sets offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +NTE: I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network. This function sets Mean and Sigma. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetinputscaling(multilayerperceptron* network, + ae_int_t i, + double mean, + double sigma, + ae_state *_state) +{ + + + ae_assert(i>=0&&ihllayersizes.ptr.p_int[0], "MLPSetInputScaling: incorrect (nonexistent) I", _state); + ae_assert(ae_isfinite(mean, _state), "MLPSetInputScaling: infinite or NAN Mean", _state); + ae_assert(ae_isfinite(sigma, _state), "MLPSetInputScaling: infinite or NAN Sigma", _state); + if( ae_fp_eq(sigma,(double)(0)) ) + { + sigma = (double)(1); + } + network->columnmeans.ptr.p_double[i] = mean; + network->columnsigmas.ptr.p_double[i] = sigma; +} + + +/************************************************************************* +This function sets offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +OUTPUT PARAMETERS: + +NOTE: I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. This function sets Sigma/Mean. In case we +have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything +other than(0.0,1.0) - this function will throw exception. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetoutputscaling(multilayerperceptron* network, + ae_int_t i, + double mean, + double sigma, + ae_state *_state) +{ + + + ae_assert(i>=0&&ihllayersizes.ptr.p_int[network->hllayersizes.cnt-1], "MLPSetOutputScaling: incorrect (nonexistent) I", _state); + ae_assert(ae_isfinite(mean, _state), "MLPSetOutputScaling: infinite or NAN Mean", _state); + ae_assert(ae_isfinite(sigma, _state), "MLPSetOutputScaling: infinite or NAN Sigma", _state); + if( network->structinfo.ptr.p_int[6]==1 ) + { + ae_assert(ae_fp_eq(mean,(double)(0)), "MLPSetOutputScaling: you can not set non-zero Mean term for classifier network", _state); + ae_assert(ae_fp_eq(sigma,(double)(1)), "MLPSetOutputScaling: you can not set non-unit Sigma term for classifier network", _state); + } + else + { + if( ae_fp_eq(sigma,(double)(0)) ) + { + sigma = (double)(1); + } + network->columnmeans.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = mean; + network->columnsigmas.ptr.p_double[network->hllayersizes.ptr.p_int[0]+i] = sigma; + } +} + + +/************************************************************************* +This function modifies information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + FKind - activation function type (used by MLPActivationFunction()) + this value must be zero for input neurons + (you can not set activation function for input neurons) + Threshold - also called offset, bias + this value must be zero for input neurons + (you can not set threshold for input neurons) + +NOTES: +1. this function throws exception if layer or neuron with given index do + not exists. +2. this function also throws exception when you try to set non-linear + activation function for input neurons (any kind of network) or for output + neurons of classifier network. +3. this function throws exception when you try to set non-zero threshold for + input neurons (any kind of network). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetneuroninfo(multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + ae_int_t fkind, + double threshold, + ae_state *_state) +{ + ae_int_t ncnt; + ae_int_t istart; + ae_int_t highlevelidx; + ae_int_t activationoffset; + + + ae_assert(ae_isfinite(threshold, _state), "MLPSetNeuronInfo: infinite or NAN Threshold", _state); + + /* + * convenience vars + */ + ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; + istart = network->structinfo.ptr.p_int[5]; + + /* + * search + */ + network->integerbuf.ptr.p_int[0] = k; + network->integerbuf.ptr.p_int[1] = i; + highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, &network->integerbuf, _state); + ae_assert(highlevelidx>=0, "MLPSetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); + + /* + * activation function + */ + if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) + { + activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; + network->structinfo.ptr.p_int[activationoffset+0] = fkind; + } + else + { + ae_assert(fkind==0, "MLPSetNeuronInfo: you try to set activation function for neuron which can not have one", _state); + } + + /* + * Threshold + */ + if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) + { + network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]] = threshold; + } + else + { + ae_assert(ae_fp_eq(threshold,(double)(0)), "MLPSetNeuronInfo: you try to set non-zero threshold for neuron which can not have one", _state); + } +} + + +/************************************************************************* +This function modifies information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + W - connection weight (must be zero for non-existent + connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. throws exception if you try to set non-zero weight for non-existent + connection + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetweight(multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + double w, + ae_state *_state) +{ + ae_int_t ccnt; + ae_int_t highlevelidx; + + + ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; + + /* + * check params + */ + ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K0", _state); + ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPSetWeight: incorrect (nonexistent) I0", _state); + ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPSetWeight: incorrect (nonexistent) K1", _state); + ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPSetWeight: incorrect (nonexistent) I1", _state); + ae_assert(ae_isfinite(w, _state), "MLPSetWeight: infinite or NAN weight", _state); + + /* + * search + */ + network->integerbuf.ptr.p_int[0] = k0; + network->integerbuf.ptr.p_int[1] = i0; + network->integerbuf.ptr.p_int[2] = k1; + network->integerbuf.ptr.p_int[3] = i1; + highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, &network->integerbuf, _state); + if( highlevelidx>=0 ) + { + network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]] = w; + } + else + { + ae_assert(ae_fp_eq(w,(double)(0)), "MLPSetWeight: you try to set non-zero weight for non-existent connection", _state); + } +} + + +/************************************************************************* +Neural network activation function + +INPUT PARAMETERS: + NET - neuron input + K - function index (zero for linear function) + +OUTPUT PARAMETERS: + F - function + DF - its derivative + D2F - its second derivative + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpactivationfunction(double net, + ae_int_t k, + double* f, + double* df, + double* d2f, + ae_state *_state) +{ + double net2; + double arg; + double root; + double r; + + *f = 0.0; + *df = 0.0; + *d2f = 0.0; + + if( k==0||k==-5 ) + { + *f = net; + *df = (double)(1); + *d2f = (double)(0); + return; + } + if( k==1 ) + { + + /* + * TanH activation function + */ + if( ae_fp_less(ae_fabs(net, _state),(double)(100)) ) + { + *f = ae_tanh(net, _state); + } + else + { + *f = (double)(ae_sign(net, _state)); + } + *df = (double)1-*f*(*f); + *d2f = -(double)2*(*f)*(*df); + return; + } + if( k==3 ) + { + + /* + * EX activation function + */ + if( ae_fp_greater_eq(net,(double)(0)) ) + { + net2 = net*net; + arg = net2+(double)1; + root = ae_sqrt(arg, _state); + *f = net+root; + r = net/root; + *df = (double)1+r; + *d2f = (root-net*r)/arg; + } + else + { + *f = ae_exp(net, _state); + *df = *f; + *d2f = *f; + } + return; + } + if( k==2 ) + { + *f = ae_exp(-ae_sqr(net, _state), _state); + *df = -(double)2*net*(*f); + *d2f = -(double)2*(*f+*df*net); + return; + } + *f = (double)(0); + *df = (double)(0); + *d2f = (double)(0); +} + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Network - neural network + X - input vector, array[0..NIn-1]. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also MLPProcessI + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpprocess(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + if( y->cntstructinfo.ptr.p_int[2] ) + { + ae_vector_set_length(y, network->structinfo.ptr.p_int[2], _state); + } + mlpinternalprocessvector(&network->structinfo, &network->weights, &network->columnmeans, &network->columnsigmas, &network->neurons, &network->dfdnet, x, y, _state); +} + + +/************************************************************************* +'interactive' variant of MLPProcess for languages like Python which +support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 21.09.2010 by Bochkanov Sergey +*************************************************************************/ +void mlpprocessi(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + mlpprocess(network, x, y, _state); +} + + +/************************************************************************* +Error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPError: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = ae_sqr(network->err.rmserror, _state)*(double)npoints*(double)mlpgetoutputscount(network, _state)/(double)2; + return result; +} + + +/************************************************************************* +Error of the neural network on dataset given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0 + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPErrorSparse: XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPErrorSparse: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparse: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparse: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = ae_sqr(network->err.rmserror, _state)*(double)npoints*(double)mlpgetoutputscount(network, _state)/(double)2; + return result; +} + + +/************************************************************************* +Natural error function for neural network, internal subroutine. + +NOTE: this function is single-threaded. Unlike other error function, it +receives no speed-up from being executed in SMP mode. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperrorn(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + double e; + double result; + + + mlpproperties(network, &nin, &nout, &wcount, _state); + result = (double)(0); + for(i=0; i<=ssize-1; i++) + { + + /* + * Process vector + */ + ae_v_move(&network->x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); + mlpprocess(network, &network->x, &network->y, _state); + + /* + * Update error function + */ + if( network->structinfo.ptr.p_int[6]==0 ) + { + + /* + * Least squares error function + */ + ae_v_sub(&network->y.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1)); + e = ae_v_dotproduct(&network->y.ptr.p_double[0], 1, &network->y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); + result = result+e/(double)2; + } + else + { + + /* + * Cross-entropy error function + */ + k = ae_round(xy->ptr.pp_double[i][nin], _state); + if( k>=0&&ky.ptr.p_double[k], _state); + } + } + } + return result; +} + + +/************************************************************************* +Classification error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + classification error (number of misclassified cases) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpclserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(xy->rows>=npoints, "MLPClsError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPClsError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPClsError: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = ae_round((double)npoints*network->err.relclserror, _state); + return result; +} + + +/************************************************************************* +Relative classification error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 25.12.2008 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPRelClsError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRelClsError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsError: XY has less than NIn+NOut columns", _state); + } + } + if( npoints>0 ) + { + result = (double)mlpclserror(network, xy, npoints, _state)/(double)npoints; + } + else + { + result = 0.0; + } + return result; +} + + +/************************************************************************* +Relative classification error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. Sparse matrix must use CRS format + for storage. + NPoints - points count, >=0. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPRelClsErrorSparse: sparse matrix XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRelClsErrorSparse: sparse matrix XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRelClsErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.relclserror; + return result; +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 08.01.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpavgce(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPAvgCE: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgCE: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCE: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgce; + return result; +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set given by +sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 9.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgcesparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPAvgCESparse: sparse matrix XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgCESparse: sparse matrix XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgCESparse: sparse matrix XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgCESparse: sparse matrix XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgce; + return result; +} + + +/************************************************************************* +RMS error on the test set given. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlprmserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPRMSError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPRMSError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSError: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.rmserror; + return result; +} + + +/************************************************************************* +RMS error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprmserrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPRMSErrorSparse: sparse matrix XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPRMSErrorSparse: sparse matrix XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPRMSErrorSparse: sparse matrix XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPRMSErrorSparse: sparse matrix XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.rmserror; + return result; +} + + +/************************************************************************* +Average absolute error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPAvgError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgError: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgerror; + return result; +} + + +/************************************************************************* +Average absolute error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPAvgErrorSparse: XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgErrorSparse: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgErrorSparse: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgErrorSparse: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgerror; + return result; +} + + +/************************************************************************* +Average relative error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(xy->rows>=npoints, "MLPAvgRelError: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAvgRelError: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelError: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, xy, &network->dummysxy, npoints, 0, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgrelerror; + return result; +} + + +/************************************************************************* +Average relative error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPAvgRelErrorSparse: XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=npoints, "MLPAvgRelErrorSparse: XY has less than NPoints rows", _state); + if( npoints>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAvgRelErrorSparse: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAvgRelErrorSparse: XY has less than NIn+NOut columns", _state); + } + } + mlpallerrorsx(network, &network->dummydxy, xy, npoints, 1, &network->dummyidx, 0, npoints, 0, &network->buf, &network->err, _state); + result = network->err.avgrelerror; + return result; +} + + +/************************************************************************* +Gradient calculation + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgrad(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* desiredy, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nout; + ae_int_t ntotal; + + *e = 0.0; + + + /* + * Alloc + */ + rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); + + /* + * Prepare dError/dOut, internal structures + */ + mlpprocess(network, x, &network->y, _state); + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + *e = (double)(0); + for(i=0; i<=ntotal-1; i++) + { + network->derror.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nout-1; i++) + { + network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; + *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/(double)2; + } + + /* + * gradient + */ + mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_false, _state); +} + + +/************************************************************************* +Gradient calculation (natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradn(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* desiredy, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + double s; + ae_int_t i; + ae_int_t nout; + ae_int_t ntotal; + + *e = 0.0; + + + /* + * Alloc + */ + rvectorsetlengthatleast(grad, network->structinfo.ptr.p_int[4], _state); + + /* + * Prepare dError/dOut, internal structures + */ + mlpprocess(network, x, &network->y, _state); + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + for(i=0; i<=ntotal-1; i++) + { + network->derror.ptr.p_double[i] = (double)(0); + } + *e = (double)(0); + if( network->structinfo.ptr.p_int[6]==0 ) + { + + /* + * Regression network, least squares + */ + for(i=0; i<=nout-1; i++) + { + network->derror.ptr.p_double[ntotal-nout+i] = network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; + *e = *e+ae_sqr(network->y.ptr.p_double[i]-desiredy->ptr.p_double[i], _state)/(double)2; + } + } + else + { + + /* + * Classification network, cross-entropy + */ + s = (double)(0); + for(i=0; i<=nout-1; i++) + { + s = s+desiredy->ptr.p_double[i]; + } + for(i=0; i<=nout-1; i++) + { + network->derror.ptr.p_double[ntotal-nout+i] = s*network->y.ptr.p_double[i]-desiredy->ptr.p_double[i]; + *e = *e+mlpbase_safecrossentropy(desiredy->ptr.p_double[i], network->y.ptr.p_double[i], _state); + } + } + + /* + * gradient + */ + mlpbase_mlpinternalcalculategradient(network, &network->neurons, &network->weights, &network->derror, grad, ae_true, _state); +} + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t subset0; + ae_int_t subset1; + ae_int_t subsettype; + smlpgrad *sgrad; + ae_smart_ptr _sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&_sgrad, 0, sizeof(_sgrad)); + *e = 0.0; + ae_smart_ptr_init(&_sgrad, (void**)&sgrad, ae_false, _state, ae_true); + + ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); + subset0 = 0; + subset1 = ssize; + subsettype = 0; + mlpproperties(network, &nin, &nout, &wcount, _state); + rvectorsetlengthatleast(grad, wcount, _state); + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + sgrad->f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad->g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + mlpgradbatchx(network, xy, &network->dummysxy, ssize, 0, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); + *e = 0.0; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = 0.0; + } + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + *e = *e+sgrad->f; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs given by sparse +matrices + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs. + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t subset0; + ae_int_t subset1; + ae_int_t subsettype; + smlpgrad *sgrad; + ae_smart_ptr _sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&_sgrad, 0, sizeof(_sgrad)); + *e = 0.0; + ae_smart_ptr_init(&_sgrad, (void**)&sgrad, ae_false, _state, ae_true); + + ae_assert(ssize>=0, "MLPGradBatchSparse: SSize<0", _state); + ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparse: sparse matrix XY must be in CRS format.", _state); + subset0 = 0; + subset1 = ssize; + subsettype = 0; + mlpproperties(network, &nin, &nout, &wcount, _state); + rvectorsetlengthatleast(grad, wcount, _state); + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + sgrad->f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad->g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + mlpgradbatchx(network, &network->dummydxy, xy, ssize, 1, &network->dummyidx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); + *e = 0.0; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = 0.0; + } + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + *e = *e+sgrad->f; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Batch gradient calculation for a subset of dataset + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t npoints; + ae_int_t subset0; + ae_int_t subset1; + ae_int_t subsettype; + smlpgrad *sgrad; + ae_smart_ptr _sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&_sgrad, 0, sizeof(_sgrad)); + *e = 0.0; + ae_smart_ptr_init(&_sgrad, (void**)&sgrad, ae_false, _state, ae_true); + + ae_assert(setsize>=0, "MLPGradBatchSubset: SetSize<0", _state); + ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSubset: SubsetSize>Length(Idx)", _state); + npoints = setsize; + if( subsetsize<0 ) + { + subset0 = 0; + subset1 = setsize; + subsettype = 0; + } + else + { + subset0 = 0; + subset1 = subsetsize; + subsettype = 1; + for(i=0; i<=subsetsize-1; i++) + { + ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]<0)", _state); + ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); + } + } + mlpproperties(network, &nin, &nout, &wcount, _state); + rvectorsetlengthatleast(grad, wcount, _state); + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + sgrad->f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad->g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + mlpgradbatchx(network, xy, &network->dummysxy, setsize, 0, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); + *e = 0.0; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = 0.0; + } + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + *e = *e+sgrad->f; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs for a subset of +dataset given by set of indexes. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + +NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse + function. + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t npoints; + ae_int_t subset0; + ae_int_t subset1; + ae_int_t subsettype; + smlpgrad *sgrad; + ae_smart_ptr _sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&_sgrad, 0, sizeof(_sgrad)); + *e = 0.0; + ae_smart_ptr_init(&_sgrad, (void**)&sgrad, ae_false, _state, ae_true); + + ae_assert(setsize>=0, "MLPGradBatchSparseSubset: SetSize<0", _state); + ae_assert(subsetsize<=idx->cnt, "MLPGradBatchSparseSubset: SubsetSize>Length(Idx)", _state); + ae_assert(sparseiscrs(xy, _state), "MLPGradBatchSparseSubset: sparse matrix XY must be in CRS format.", _state); + npoints = setsize; + if( subsetsize<0 ) + { + subset0 = 0; + subset1 = setsize; + subsettype = 0; + } + else + { + subset0 = 0; + subset1 = subsetsize; + subsettype = 1; + for(i=0; i<=subsetsize-1; i++) + { + ae_assert(idx->ptr.p_int[i]>=0, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]<0)", _state); + ae_assert(idx->ptr.p_int[i]<=npoints-1, "MLPGradBatchSparseSubset: incorrect index of XY row(Idx[I]>Rows(XY)-1)", _state); + } + } + mlpproperties(network, &nin, &nout, &wcount, _state); + rvectorsetlengthatleast(grad, wcount, _state); + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + sgrad->f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad->g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + mlpgradbatchx(network, &network->dummydxy, xy, setsize, 1, idx, subset0, subset1, subsettype, &network->buf, &network->gradbuf, _state); + *e = 0.0; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = 0.0; + } + ae_shared_pool_first_recycled(&network->gradbuf, &_sgrad, _state); + while(sgrad!=NULL) + { + *e = *e+sgrad->f; + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = grad->ptr.p_double[i]+sgrad->g.ptr.p_double[i]; + } + ae_shared_pool_next_recycled(&network->gradbuf, &_sgrad, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal function which actually calculates batch gradient for a subset or +full dataset, which can be represented in different formats. + +THIS FUNCTION IS NOT INTENDED TO BE USED BY ALGLIB USERS! + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + ae_shared_pool* gradbuf, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t rowsize; + ae_int_t srcidx; + ae_int_t cstart; + ae_int_t csize; + ae_int_t j; + double problemcost; + mlpbuffers *buf2; + ae_smart_ptr _buf2; + ae_int_t len0; + ae_int_t len1; + mlpbuffers *pbuf; + ae_smart_ptr _pbuf; + smlpgrad *sgrad; + ae_smart_ptr _sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&_buf2, 0, sizeof(_buf2)); + memset(&_pbuf, 0, sizeof(_pbuf)); + memset(&_sgrad, 0, sizeof(_sgrad)); + ae_smart_ptr_init(&_buf2, (void**)&buf2, ae_false, _state, ae_true); + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + ae_smart_ptr_init(&_sgrad, (void**)&sgrad, ae_false, _state, ae_true); + + ae_assert(datasetsize>=0, "MLPGradBatchX: SetSize<0", _state); + ae_assert(datasettype==0||datasettype==1, "MLPGradBatchX: DatasetType is incorrect", _state); + ae_assert(subsettype==0||subsettype==1, "MLPGradBatchX: SubsetType is incorrect", _state); + + /* + * Determine network and dataset properties + */ + mlpproperties(network, &nin, &nout, &wcount, _state); + if( mlpissoftmax(network, _state) ) + { + rowsize = nin+1; + } + else + { + rowsize = nin+nout; + } + + /* + * Split problem. + * + * Splitting problem allows us to reduce effect of single-precision + * arithmetics (SSE-optimized version of MLPChunkedGradient uses single + * precision internally, but converts them to double precision after + * results are exported from HPC buffer to network). Small batches are + * calculated in single precision, results are aggregated in double + * precision, and it allows us to avoid accumulation of errors when + * we process very large batches (tens of thousands of items). + * + * NOTE: it is important to use real arithmetics for ProblemCost + * because ProblemCost may be larger than MAXINT. + */ + problemcost = (double)(subset1-subset0); + problemcost = problemcost*(double)wcount*(double)2; + if( ae_fp_greater_eq(problemcost,smpactivationlevel(_state))&&subset1-subset0>=2*mlpbase_microbatchsize ) + { + if( _trypexec_mlpgradbatchx(network,densexy,sparsexy,datasetsize,datasettype,idx,subset0,subset1,subsettype,buf,gradbuf, _state) ) + { + ae_frame_leave(_state); + return; + } + } + if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(problemcost,spawnlevel(_state)) ) + { + splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); + mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, gradbuf, _state); + mlpgradbatchx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, gradbuf, _state); + ae_frame_leave(_state); + return; + } + + /* + * Chunked processing + */ + ae_shared_pool_retrieve(gradbuf, &_sgrad, _state); + ae_shared_pool_retrieve(buf, &_pbuf, _state); + hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); + cstart = subset0; + while(cstartchunksize, _state)-cstart; + for(j=0; j<=csize-1; j++) + { + srcidx = -1; + if( subsettype==0 ) + { + srcidx = cstart+j; + } + if( subsettype==1 ) + { + srcidx = idx->ptr.p_int[cstart+j]; + } + ae_assert(srcidx>=0, "MLPGradBatchX: internal error", _state); + if( datasettype==0 ) + { + ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); + } + if( datasettype==1 ) + { + sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); + ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); + } + } + + /* + * Process chunk and advance line pointer + */ + mlpbase_mlpchunkedgradient(network, &pbuf->xy, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, &sgrad->f, ae_false, _state); + cstart = cstart+pbuf->chunksize; + } + hpcfinalizechunkedgradient(pbuf, &sgrad->g, _state); + ae_shared_pool_recycle(buf, &_pbuf, _state); + ae_shared_pool_recycle(gradbuf, &_sgrad, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mlpgradbatchx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + ae_shared_pool* gradbuf, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs +(natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - set of inputs/outputs; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradnbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + mlpbuffers *pbuf; + ae_smart_ptr _pbuf; + + ae_frame_make(_state, &_frame_block); + memset(&_pbuf, 0, sizeof(_pbuf)); + *e = 0.0; + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + + + /* + * Alloc + */ + mlpproperties(network, &nin, &nout, &wcount, _state); + ae_shared_pool_retrieve(&network->buf, &_pbuf, _state); + hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); + rvectorsetlengthatleast(grad, wcount, _state); + for(i=0; i<=wcount-1; i++) + { + grad->ptr.p_double[i] = (double)(0); + } + *e = (double)(0); + i = 0; + while(i<=ssize-1) + { + mlpbase_mlpchunkedgradient(network, xy, i, ae_minint(ssize, i+pbuf->chunksize, _state)-i, &pbuf->batch4buf, &pbuf->hpcbuf, e, ae_true, _state); + i = i+pbuf->chunksize; + } + hpcfinalizechunkedgradient(pbuf, grad, _state); + ae_shared_pool_recycle(&network->buf, &_pbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Batch Hessian calculation (natural error function) using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessiannbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + + *e = 0.0; + + mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_true, e, grad, h, _state); +} + + +/************************************************************************* +Batch Hessian calculation using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessianbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + + *e = 0.0; + + mlpbase_mlphessianbatchinternal(network, xy, ssize, ae_false, e, grad, h, _state); +} + + +/************************************************************************* +Internal subroutine, shouldn't be called by user. +*************************************************************************/ +void mlpinternalprocessvector(/* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* weights, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ ae_vector* neurons, + /* Real */ ae_vector* dfdnet, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n1; + ae_int_t n2; + ae_int_t w1; + ae_int_t w2; + ae_int_t ntotal; + ae_int_t nin; + ae_int_t nout; + ae_int_t istart; + ae_int_t offs; + double net; + double f; + double df; + double d2f; + double mx; + ae_bool perr; + + + + /* + * Read network geometry + */ + nin = structinfo->ptr.p_int[1]; + nout = structinfo->ptr.p_int[2]; + ntotal = structinfo->ptr.p_int[3]; + istart = structinfo->ptr.p_int[5]; + + /* + * Inputs standartisation and putting in the network + */ + for(i=0; i<=nin-1; i++) + { + if( ae_fp_neq(columnsigmas->ptr.p_double[i],(double)(0)) ) + { + neurons->ptr.p_double[i] = (x->ptr.p_double[i]-columnmeans->ptr.p_double[i])/columnsigmas->ptr.p_double[i]; + } + else + { + neurons->ptr.p_double[i] = x->ptr.p_double[i]-columnmeans->ptr.p_double[i]; + } + } + + /* + * Process network + */ + for(i=0; i<=ntotal-1; i++) + { + offs = istart+i*mlpbase_nfieldwidth; + if( structinfo->ptr.p_int[offs+0]>0||structinfo->ptr.p_int[offs+0]==-5 ) + { + + /* + * Activation function + */ + mlpactivationfunction(neurons->ptr.p_double[structinfo->ptr.p_int[offs+2]], structinfo->ptr.p_int[offs+0], &f, &df, &d2f, _state); + neurons->ptr.p_double[i] = f; + dfdnet->ptr.p_double[i] = df; + continue; + } + if( structinfo->ptr.p_int[offs+0]==0 ) + { + + /* + * Adaptive summator + */ + n1 = structinfo->ptr.p_int[offs+2]; + n2 = n1+structinfo->ptr.p_int[offs+1]-1; + w1 = structinfo->ptr.p_int[offs+3]; + w2 = w1+structinfo->ptr.p_int[offs+1]-1; + net = ae_v_dotproduct(&weights->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2)); + neurons->ptr.p_double[i] = net; + dfdnet->ptr.p_double[i] = 1.0; + touchint(&n2, _state); + continue; + } + if( structinfo->ptr.p_int[offs+0]<0 ) + { + perr = ae_true; + if( structinfo->ptr.p_int[offs+0]==-2 ) + { + + /* + * input neuron, left unchanged + */ + perr = ae_false; + } + if( structinfo->ptr.p_int[offs+0]==-3 ) + { + + /* + * "-1" neuron + */ + neurons->ptr.p_double[i] = (double)(-1); + perr = ae_false; + } + if( structinfo->ptr.p_int[offs+0]==-4 ) + { + + /* + * "0" neuron + */ + neurons->ptr.p_double[i] = (double)(0); + perr = ae_false; + } + ae_assert(!perr, "MLPInternalProcessVector: internal error - unknown neuron type!", _state); + continue; + } + } + + /* + * Extract result + */ + ae_v_move(&y->ptr.p_double[0], 1, &neurons->ptr.p_double[ntotal-nout], 1, ae_v_len(0,nout-1)); + + /* + * Softmax post-processing or standardisation if needed + */ + ae_assert(structinfo->ptr.p_int[6]==0||structinfo->ptr.p_int[6]==1, "MLPInternalProcessVector: unknown normalization type!", _state); + if( structinfo->ptr.p_int[6]==1 ) + { + + /* + * Softmax + */ + mx = y->ptr.p_double[0]; + for(i=1; i<=nout-1; i++) + { + mx = ae_maxreal(mx, y->ptr.p_double[i], _state); + } + net = (double)(0); + for(i=0; i<=nout-1; i++) + { + y->ptr.p_double[i] = ae_exp(y->ptr.p_double[i]-mx, _state); + net = net+y->ptr.p_double[i]; + } + for(i=0; i<=nout-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]/net; + } + } + else + { + + /* + * Standardisation + */ + for(i=0; i<=nout-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]*columnsigmas->ptr.p_double[nin+i]+columnmeans->ptr.p_double[nin+i]; + } + } +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpalloc(ae_serializer* s, + const multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t fkind; + double threshold; + double v0; + double v1; + ae_int_t nin; + ae_int_t nout; + ae_vector integerbuf; + + ae_frame_make(_state, &_frame_block); + memset(&integerbuf, 0, sizeof(integerbuf)); + ae_vector_init(&integerbuf, 0, DT_INT, _state, ae_true); + + nin = network->hllayersizes.ptr.p_int[0]; + nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocintegerarray(s, &network->hllayersizes, -1, _state); + for(i=1; i<=network->hllayersizes.cnt-1; i++) + { + for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) + { + mlpbase_mlpgetneuroninfox(network, i, j, &integerbuf, &fkind, &threshold, _state); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) + { + ae_serializer_alloc_entry(s); + } + } + } + for(j=0; j<=nin-1; j++) + { + mlpgetinputscaling(network, j, &v0, &v1, _state); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + } + for(j=0; j<=nout-1; j++) + { + mlpgetoutputscaling(network, j, &v0, &v1, _state); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpserialize(ae_serializer* s, + const multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t fkind; + double threshold; + double v0; + double v1; + ae_int_t nin; + ae_int_t nout; + ae_vector integerbuf; + + ae_frame_make(_state, &_frame_block); + memset(&integerbuf, 0, sizeof(integerbuf)); + ae_vector_init(&integerbuf, 0, DT_INT, _state, ae_true); + + nin = network->hllayersizes.ptr.p_int[0]; + nout = network->hllayersizes.ptr.p_int[network->hllayersizes.cnt-1]; + ae_serializer_serialize_int(s, getmlpserializationcode(_state), _state); + ae_serializer_serialize_int(s, mlpbase_mlpfirstversion, _state); + ae_serializer_serialize_bool(s, mlpissoftmax(network, _state), _state); + serializeintegerarray(s, &network->hllayersizes, -1, _state); + for(i=1; i<=network->hllayersizes.cnt-1; i++) + { + for(j=0; j<=network->hllayersizes.ptr.p_int[i]-1; j++) + { + mlpbase_mlpgetneuroninfox(network, i, j, &integerbuf, &fkind, &threshold, _state); + ae_serializer_serialize_int(s, fkind, _state); + ae_serializer_serialize_double(s, threshold, _state); + for(k=0; k<=network->hllayersizes.ptr.p_int[i-1]-1; k++) + { + ae_serializer_serialize_double(s, mlpbase_mlpgetweightx(network, i-1, k, i, j, &integerbuf, _state), _state); + } + } + } + for(j=0; j<=nin-1; j++) + { + mlpgetinputscaling(network, j, &v0, &v1, _state); + ae_serializer_serialize_double(s, v0, _state); + ae_serializer_serialize_double(s, v1, _state); + } + for(j=0; j<=nout-1; j++) + { + mlpgetoutputscaling(network, j, &v0, &v1, _state); + ae_serializer_serialize_double(s, v0, _state); + ae_serializer_serialize_double(s, v1, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpunserialize(ae_serializer* s, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i0; + ae_int_t i1; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t fkind; + double threshold; + double v0; + double v1; + ae_int_t nin; + ae_int_t nout; + ae_bool issoftmax; + ae_vector layersizes; + + ae_frame_make(_state, &_frame_block); + memset(&layersizes, 0, sizeof(layersizes)); + _multilayerperceptron_clear(network); + ae_vector_init(&layersizes, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getmlpserializationcode(_state), "MLPUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_assert(i1==mlpbase_mlpfirstversion, "MLPUnserialize: stream header corrupted", _state); + + /* + * Create network + */ + ae_serializer_unserialize_bool(s, &issoftmax, _state); + unserializeintegerarray(s, &layersizes, _state); + ae_assert((layersizes.cnt==2||layersizes.cnt==3)||layersizes.cnt==4, "MLPUnserialize: too many hidden layers!", _state); + nin = layersizes.ptr.p_int[0]; + nout = layersizes.ptr.p_int[layersizes.cnt-1]; + if( layersizes.cnt==2 ) + { + if( issoftmax ) + { + mlpcreatec0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); + } + else + { + mlpcreate0(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], network, _state); + } + } + if( layersizes.cnt==3 ) + { + if( issoftmax ) + { + mlpcreatec1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); + } + else + { + mlpcreate1(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], network, _state); + } + } + if( layersizes.cnt==4 ) + { + if( issoftmax ) + { + mlpcreatec2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); + } + else + { + mlpcreate2(layersizes.ptr.p_int[0], layersizes.ptr.p_int[1], layersizes.ptr.p_int[2], layersizes.ptr.p_int[3], network, _state); + } + } + + /* + * Load neurons and weights + */ + for(i=1; i<=layersizes.cnt-1; i++) + { + for(j=0; j<=layersizes.ptr.p_int[i]-1; j++) + { + ae_serializer_unserialize_int(s, &fkind, _state); + ae_serializer_unserialize_double(s, &threshold, _state); + mlpsetneuroninfo(network, i, j, fkind, threshold, _state); + for(k=0; k<=layersizes.ptr.p_int[i-1]-1; k++) + { + ae_serializer_unserialize_double(s, &v0, _state); + mlpsetweight(network, i-1, k, i, j, v0, _state); + } + } + } + + /* + * Load standartizator + */ + for(j=0; j<=nin-1; j++) + { + ae_serializer_unserialize_double(s, &v0, _state); + ae_serializer_unserialize_double(s, &v1, _state); + mlpsetinputscaling(network, j, v0, v1, _state); + } + for(j=0; j<=nout-1; j++) + { + ae_serializer_unserialize_double(s, &v0, _state); + ae_serializer_unserialize_double(s, &v1, _state); + mlpsetoutputscaling(network, j, v0, v1, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + modelerrors* rep, + ae_state *_state) +{ + ae_int_t idx0; + ae_int_t idx1; + ae_int_t idxtype; + + _modelerrors_clear(rep); + + ae_assert(xy->rows>=setsize, "MLPAllErrorsSubset: XY has less than SetSize rows", _state); + if( setsize>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSubset: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSubset: XY has less than NIn+NOut columns", _state); + } + } + if( subsetsize>=0 ) + { + idx0 = 0; + idx1 = subsetsize; + idxtype = 1; + } + else + { + idx0 = 0; + idx1 = setsize; + idxtype = 0; + } + mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, rep, _state); +} + + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset given by sparse matrix; + one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + modelerrors* rep, + ae_state *_state) +{ + ae_int_t idx0; + ae_int_t idx1; + ae_int_t idxtype; + + _modelerrors_clear(rep); + + ae_assert(sparseiscrs(xy, _state), "MLPAllErrorsSparseSubset: XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPAllErrorsSparseSubset: XY has less than SetSize rows", _state); + if( setsize>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPAllErrorsSparseSubset: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPAllErrorsSparseSubset: XY has less than NIn+NOut columns", _state); + } + } + if( subsetsize>=0 ) + { + idx0 = 0; + idx1 = subsetsize; + idxtype = 1; + } + else + { + idx0 = 0; + idx1 = setsize; + idxtype = 0; + } + mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, rep, _state); +} + + +/************************************************************************* +Error of the neural network on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_state *_state) +{ + ae_int_t idx0; + ae_int_t idx1; + ae_int_t idxtype; + double result; + + + ae_assert(xy->rows>=setsize, "MLPErrorSubset: XY has less than SetSize rows", _state); + if( setsize>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+1, "MLPErrorSubset: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(xy->cols>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSubset: XY has less than NIn+NOut columns", _state); + } + } + if( subsetsize>=0 ) + { + idx0 = 0; + idx1 = subsetsize; + idxtype = 1; + } + else + { + idx0 = 0; + idx1 = setsize; + idxtype = 0; + } + mlpallerrorsx(network, xy, &network->dummysxy, setsize, 0, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); + result = ae_sqr(network->err.rmserror, _state)*(double)(idx1-idx0)*(double)mlpgetoutputscount(network, _state)/(double)2; + return result; +} + + +/************************************************************************* +Error of the neural network on subset of sparse dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + SetSize - real size of XY, SetSize>=0; + it is used when SubsetSize<0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_state *_state) +{ + ae_int_t idx0; + ae_int_t idx1; + ae_int_t idxtype; + double result; + + + ae_assert(sparseiscrs(xy, _state), "MLPErrorSparseSubset: XY is not in CRS format.", _state); + ae_assert(sparsegetnrows(xy, _state)>=setsize, "MLPErrorSparseSubset: XY has less than SetSize rows", _state); + if( setsize>0 ) + { + if( mlpissoftmax(network, _state) ) + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+1, "MLPErrorSparseSubset: XY has less than NIn+1 columns", _state); + } + else + { + ae_assert(sparsegetncols(xy, _state)>=mlpgetinputscount(network, _state)+mlpgetoutputscount(network, _state), "MLPErrorSparseSubset: XY has less than NIn+NOut columns", _state); + } + } + if( subsetsize>=0 ) + { + idx0 = 0; + idx1 = subsetsize; + idxtype = 1; + } + else + { + idx0 = 0; + idx1 = setsize; + idxtype = 0; + } + mlpallerrorsx(network, &network->dummydxy, xy, setsize, 1, subset, idx0, idx1, idxtype, &network->buf, &network->err, _state); + result = ae_sqr(network->err.rmserror, _state)*(double)(idx1-idx0)*(double)mlpgetoutputscount(network, _state)/(double)2; + return result; +} + + +/************************************************************************* +Calculation of all types of errors at once for a subset or full dataset, +which can be represented in different formats. + +THIS INTERNAL FUNCTION IS NOT INTENDED TO BE USED BY ALGLIB USERS! + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorsx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t rowsize; + ae_bool iscls; + ae_int_t srcidx; + ae_int_t cstart; + ae_int_t csize; + ae_int_t j; + mlpbuffers *pbuf; + ae_smart_ptr _pbuf; + ae_int_t len0; + ae_int_t len1; + modelerrors rep0; + modelerrors rep1; + double problemcost; + + ae_frame_make(_state, &_frame_block); + memset(&_pbuf, 0, sizeof(_pbuf)); + memset(&rep0, 0, sizeof(rep0)); + memset(&rep1, 0, sizeof(rep1)); + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + _modelerrors_init(&rep0, _state, ae_true); + _modelerrors_init(&rep1, _state, ae_true); + + ae_assert(datasetsize>=0, "MLPAllErrorsX: SetSize<0", _state); + ae_assert(datasettype==0||datasettype==1, "MLPAllErrorsX: DatasetType is incorrect", _state); + ae_assert(subsettype==0||subsettype==1, "MLPAllErrorsX: SubsetType is incorrect", _state); + + /* + * Determine network properties + */ + mlpproperties(network, &nin, &nout, &wcount, _state); + iscls = mlpissoftmax(network, _state); + + /* + * Split problem. + * + * Splitting problem allows us to reduce effect of single-precision + * arithmetics (SSE-optimized version of MLPChunkedProcess uses single + * precision internally, but converts them to double precision after + * results are exported from HPC buffer to network). Small batches are + * calculated in single precision, results are aggregated in double + * precision, and it allows us to avoid accumulation of errors when + * we process very large batches (tens of thousands of items). + * + * NOTE: it is important to use real arithmetics for ProblemCost + * because ProblemCost may be larger than MAXINT. + */ + problemcost = (double)(subset1-subset0); + problemcost = problemcost*(double)wcount*(double)2; + if( ae_fp_greater_eq(problemcost,smpactivationlevel(_state))&&subset1-subset0>=2*mlpbase_microbatchsize ) + { + if( _trypexec_mlpallerrorsx(network,densexy,sparsexy,datasetsize,datasettype,idx,subset0,subset1,subsettype,buf,rep, _state) ) + { + ae_frame_leave(_state); + return; + } + } + if( subset1-subset0>=2*mlpbase_microbatchsize&&ae_fp_greater(problemcost,spawnlevel(_state)) ) + { + splitlength(subset1-subset0, mlpbase_microbatchsize, &len0, &len1, _state); + mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0, subset0+len0, subsettype, buf, &rep0, _state); + mlpallerrorsx(network, densexy, sparsexy, datasetsize, datasettype, idx, subset0+len0, subset1, subsettype, buf, &rep1, _state); + rep->relclserror = ((double)len0*rep0.relclserror+(double)len1*rep1.relclserror)/(double)(len0+len1); + rep->avgce = ((double)len0*rep0.avgce+(double)len1*rep1.avgce)/(double)(len0+len1); + rep->rmserror = ae_sqrt(((double)len0*ae_sqr(rep0.rmserror, _state)+(double)len1*ae_sqr(rep1.rmserror, _state))/(double)(len0+len1), _state); + rep->avgerror = ((double)len0*rep0.avgerror+(double)len1*rep1.avgerror)/(double)(len0+len1); + rep->avgrelerror = ((double)len0*rep0.avgrelerror+(double)len1*rep1.avgrelerror)/(double)(len0+len1); + ae_frame_leave(_state); + return; + } + + /* + * Retrieve and prepare + */ + ae_shared_pool_retrieve(buf, &_pbuf, _state); + if( iscls ) + { + rowsize = nin+1; + dserrallocate(nout, &pbuf->tmp0, _state); + } + else + { + rowsize = nin+nout; + dserrallocate(-nout, &pbuf->tmp0, _state); + } + + /* + * Processing + */ + hpcpreparechunkedgradient(&network->weights, wcount, mlpntotal(network, _state), nin, nout, pbuf, _state); + cstart = subset0; + while(cstartchunksize, _state)-cstart; + for(j=0; j<=csize-1; j++) + { + srcidx = -1; + if( subsettype==0 ) + { + srcidx = cstart+j; + } + if( subsettype==1 ) + { + srcidx = idx->ptr.p_int[cstart+j]; + } + ae_assert(srcidx>=0, "MLPAllErrorsX: internal error", _state); + if( datasettype==0 ) + { + ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,rowsize-1)); + } + if( datasettype==1 ) + { + sparsegetrow(sparsexy, srcidx, &pbuf->xyrow, _state); + ae_v_move(&pbuf->xy.ptr.pp_double[j][0], 1, &pbuf->xyrow.ptr.p_double[0], 1, ae_v_len(0,rowsize-1)); + } + } + + /* + * Unpack XY and process (temporary code, to be replaced by chunked processing) + */ + for(j=0; j<=csize-1; j++) + { + ae_v_move(&pbuf->xy2.ptr.pp_double[j][0], 1, &pbuf->xy.ptr.pp_double[j][0], 1, ae_v_len(0,rowsize-1)); + } + mlpbase_mlpchunkedprocess(network, &pbuf->xy2, 0, csize, &pbuf->batch4buf, &pbuf->hpcbuf, _state); + for(j=0; j<=csize-1; j++) + { + ae_v_move(&pbuf->x.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][0], 1, ae_v_len(0,nin-1)); + ae_v_move(&pbuf->y.ptr.p_double[0], 1, &pbuf->xy2.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); + if( iscls ) + { + pbuf->desiredy.ptr.p_double[0] = pbuf->xy.ptr.pp_double[j][nin]; + } + else + { + ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &pbuf->xy.ptr.pp_double[j][nin], 1, ae_v_len(0,nout-1)); + } + dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); + } + + /* + * Process chunk and advance line pointer + */ + cstart = cstart+pbuf->chunksize; + } + dserrfinish(&pbuf->tmp0, _state); + rep->relclserror = pbuf->tmp0.ptr.p_double[0]; + rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log((double)(2), _state); + rep->rmserror = pbuf->tmp0.ptr.p_double[2]; + rep->avgerror = pbuf->tmp0.ptr.p_double[3]; + rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; + + /* + * Recycle + */ + ae_shared_pool_recycle(buf, &_pbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mlpallerrorsx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Internal subroutine: adding new input layer to network +*************************************************************************/ +static void mlpbase_addinputlayer(ae_int_t ncount, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state) +{ + + + lsizes->ptr.p_int[0] = ncount; + ltypes->ptr.p_int[0] = -2; + lconnfirst->ptr.p_int[0] = 0; + lconnlast->ptr.p_int[0] = 0; + *lastproc = 0; +} + + +/************************************************************************* +Internal subroutine: adding new summator layer to network +*************************************************************************/ +static void mlpbase_addbiasedsummatorlayer(ae_int_t ncount, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state) +{ + + + lsizes->ptr.p_int[*lastproc+1] = 1; + ltypes->ptr.p_int[*lastproc+1] = -3; + lconnfirst->ptr.p_int[*lastproc+1] = 0; + lconnlast->ptr.p_int[*lastproc+1] = 0; + lsizes->ptr.p_int[*lastproc+2] = ncount; + ltypes->ptr.p_int[*lastproc+2] = 0; + lconnfirst->ptr.p_int[*lastproc+2] = *lastproc; + lconnlast->ptr.p_int[*lastproc+2] = *lastproc+1; + *lastproc = *lastproc+2; +} + + +/************************************************************************* +Internal subroutine: adding new summator layer to network +*************************************************************************/ +static void mlpbase_addactivationlayer(ae_int_t functype, + /* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state) +{ + + + ae_assert(functype>0||functype==-5, "AddActivationLayer: incorrect function type", _state); + lsizes->ptr.p_int[*lastproc+1] = lsizes->ptr.p_int[*lastproc]; + ltypes->ptr.p_int[*lastproc+1] = functype; + lconnfirst->ptr.p_int[*lastproc+1] = *lastproc; + lconnlast->ptr.p_int[*lastproc+1] = *lastproc; + *lastproc = *lastproc+1; +} + + +/************************************************************************* +Internal subroutine: adding new zero layer to network +*************************************************************************/ +static void mlpbase_addzerolayer(/* Integer */ ae_vector* lsizes, + /* Integer */ ae_vector* ltypes, + /* Integer */ ae_vector* lconnfirst, + /* Integer */ ae_vector* lconnlast, + ae_int_t* lastproc, + ae_state *_state) +{ + + + lsizes->ptr.p_int[*lastproc+1] = 1; + ltypes->ptr.p_int[*lastproc+1] = -4; + lconnfirst->ptr.p_int[*lastproc+1] = 0; + lconnlast->ptr.p_int[*lastproc+1] = 0; + *lastproc = *lastproc+1; +} + + +/************************************************************************* +This routine adds input layer to the high-level description of the network. + +It modifies Network.HLConnections and Network.HLNeurons and assumes that +these arrays have enough place to store data. It accepts following +parameters: + Network - network + ConnIdx - index of the first free entry in the HLConnections + NeuroIdx - index of the first free entry in the HLNeurons + StructInfoIdx- index of the first entry in the low level description + of the current layer (in the StructInfo array) + NIn - number of inputs + +It modified Network and indices. +*************************************************************************/ +static void mlpbase_hladdinputlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t nin, + ae_state *_state) +{ + ae_int_t i; + ae_int_t offs; + + + offs = mlpbase_hlnfieldwidth*(*neuroidx); + for(i=0; i<=nin-1; i++) + { + network->hlneurons.ptr.p_int[offs+0] = 0; + network->hlneurons.ptr.p_int[offs+1] = i; + network->hlneurons.ptr.p_int[offs+2] = -1; + network->hlneurons.ptr.p_int[offs+3] = -1; + offs = offs+mlpbase_hlnfieldwidth; + } + *neuroidx = *neuroidx+nin; + *structinfoidx = *structinfoidx+nin; +} + + +/************************************************************************* +This routine adds output layer to the high-level description of +the network. + +It modifies Network.HLConnections and Network.HLNeurons and assumes that +these arrays have enough place to store data. It accepts following +parameters: + Network - network + ConnIdx - index of the first free entry in the HLConnections + NeuroIdx - index of the first free entry in the HLNeurons + StructInfoIdx- index of the first entry in the low level description + of the current layer (in the StructInfo array) + WeightsIdx - index of the first entry in the Weights array which + corresponds to the current layer + K - current layer index + NPrev - number of neurons in the previous layer + NOut - number of outputs + IsCls - is it classifier network? + IsLinear - is it network with linear output? + +It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. +*************************************************************************/ +static void mlpbase_hladdoutputlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t* weightsidx, + ae_int_t k, + ae_int_t nprev, + ae_int_t nout, + ae_bool iscls, + ae_bool islinearout, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t neurooffs; + ae_int_t connoffs; + + + ae_assert((iscls&&islinearout)||!iscls, "HLAddOutputLayer: internal error", _state); + neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); + connoffs = mlpbase_hlconnfieldwidth*(*connidx); + if( !iscls ) + { + + /* + * Regression network + */ + for(i=0; i<=nout-1; i++) + { + network->hlneurons.ptr.p_int[neurooffs+0] = k; + network->hlneurons.ptr.p_int[neurooffs+1] = i; + network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+nout+i; + network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; + neurooffs = neurooffs+mlpbase_hlnfieldwidth; + } + for(i=0; i<=nprev-1; i++) + { + for(j=0; j<=nout-1; j++) + { + network->hlconnections.ptr.p_int[connoffs+0] = k-1; + network->hlconnections.ptr.p_int[connoffs+1] = i; + network->hlconnections.ptr.p_int[connoffs+2] = k; + network->hlconnections.ptr.p_int[connoffs+3] = j; + network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); + connoffs = connoffs+mlpbase_hlconnfieldwidth; + } + } + *connidx = *connidx+nprev*nout; + *neuroidx = *neuroidx+nout; + *structinfoidx = *structinfoidx+2*nout+1; + *weightsidx = *weightsidx+nout*(nprev+1); + } + else + { + + /* + * Classification network + */ + for(i=0; i<=nout-2; i++) + { + network->hlneurons.ptr.p_int[neurooffs+0] = k; + network->hlneurons.ptr.p_int[neurooffs+1] = i; + network->hlneurons.ptr.p_int[neurooffs+2] = -1; + network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; + neurooffs = neurooffs+mlpbase_hlnfieldwidth; + } + network->hlneurons.ptr.p_int[neurooffs+0] = k; + network->hlneurons.ptr.p_int[neurooffs+1] = i; + network->hlneurons.ptr.p_int[neurooffs+2] = -1; + network->hlneurons.ptr.p_int[neurooffs+3] = -1; + for(i=0; i<=nprev-1; i++) + { + for(j=0; j<=nout-2; j++) + { + network->hlconnections.ptr.p_int[connoffs+0] = k-1; + network->hlconnections.ptr.p_int[connoffs+1] = i; + network->hlconnections.ptr.p_int[connoffs+2] = k; + network->hlconnections.ptr.p_int[connoffs+3] = j; + network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); + connoffs = connoffs+mlpbase_hlconnfieldwidth; + } + } + *connidx = *connidx+nprev*(nout-1); + *neuroidx = *neuroidx+nout; + *structinfoidx = *structinfoidx+nout+2; + *weightsidx = *weightsidx+(nout-1)*(nprev+1); + } +} + + +/************************************************************************* +This routine adds hidden layer to the high-level description of +the network. + +It modifies Network.HLConnections and Network.HLNeurons and assumes that +these arrays have enough place to store data. It accepts following +parameters: + Network - network + ConnIdx - index of the first free entry in the HLConnections + NeuroIdx - index of the first free entry in the HLNeurons + StructInfoIdx- index of the first entry in the low level description + of the current layer (in the StructInfo array) + WeightsIdx - index of the first entry in the Weights array which + corresponds to the current layer + K - current layer index + NPrev - number of neurons in the previous layer + NCur - number of neurons in the current layer + +It modified Network and ConnIdx/NeuroIdx/StructInfoIdx/WeightsIdx. +*************************************************************************/ +static void mlpbase_hladdhiddenlayer(multilayerperceptron* network, + ae_int_t* connidx, + ae_int_t* neuroidx, + ae_int_t* structinfoidx, + ae_int_t* weightsidx, + ae_int_t k, + ae_int_t nprev, + ae_int_t ncur, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t neurooffs; + ae_int_t connoffs; + + + neurooffs = mlpbase_hlnfieldwidth*(*neuroidx); + connoffs = mlpbase_hlconnfieldwidth*(*connidx); + for(i=0; i<=ncur-1; i++) + { + network->hlneurons.ptr.p_int[neurooffs+0] = k; + network->hlneurons.ptr.p_int[neurooffs+1] = i; + network->hlneurons.ptr.p_int[neurooffs+2] = *structinfoidx+1+ncur+i; + network->hlneurons.ptr.p_int[neurooffs+3] = *weightsidx+nprev+(nprev+1)*i; + neurooffs = neurooffs+mlpbase_hlnfieldwidth; + } + for(i=0; i<=nprev-1; i++) + { + for(j=0; j<=ncur-1; j++) + { + network->hlconnections.ptr.p_int[connoffs+0] = k-1; + network->hlconnections.ptr.p_int[connoffs+1] = i; + network->hlconnections.ptr.p_int[connoffs+2] = k; + network->hlconnections.ptr.p_int[connoffs+3] = j; + network->hlconnections.ptr.p_int[connoffs+4] = *weightsidx+i+j*(nprev+1); + connoffs = connoffs+mlpbase_hlconnfieldwidth; + } + } + *connidx = *connidx+nprev*ncur; + *neuroidx = *neuroidx+ncur; + *structinfoidx = *structinfoidx+2*ncur+1; + *weightsidx = *weightsidx+ncur*(nprev+1); +} + + +/************************************************************************* +This function fills high level information about network created using +internal MLPCreate() function. + +This function does NOT examine StructInfo for low level information, it +just expects that network has following structure: + + input neuron \ + ... | input layer + input neuron / + + "-1" neuron \ + biased summator | + ... | + biased summator | hidden layer(s), if there are exists any + activation function | + ... | + activation function / + + "-1" neuron \ + biased summator | output layer: + ... | + biased summator | * we have NOut summators/activators for regression networks + activation function | * we have only NOut-1 summators and no activators for classifiers + ... | * we have "0" neuron only when we have classifier + activation function | + "0" neuron / + + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +static void mlpbase_fillhighlevelinformation(multilayerperceptron* network, + ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_bool iscls, + ae_bool islinearout, + ae_state *_state) +{ + ae_int_t idxweights; + ae_int_t idxstruct; + ae_int_t idxneuro; + ae_int_t idxconn; + + + ae_assert((iscls&&islinearout)||!iscls, "FillHighLevelInformation: internal error", _state); + + /* + * Preparations common to all types of networks + */ + idxweights = 0; + idxneuro = 0; + idxstruct = 0; + idxconn = 0; + network->hlnetworktype = 0; + + /* + * network without hidden layers + */ + if( nhid1==0 ) + { + ae_vector_set_length(&network->hllayersizes, 2, _state); + network->hllayersizes.ptr.p_int[0] = nin; + network->hllayersizes.ptr.p_int[1] = nout; + if( !iscls ) + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*nout, _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); + network->hlnormtype = 0; + } + else + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*nin*(nout-1), _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nout), _state); + network->hlnormtype = 1; + } + mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); + mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nout, iscls, islinearout, _state); + return; + } + + /* + * network with one hidden layers + */ + if( nhid2==0 ) + { + ae_vector_set_length(&network->hllayersizes, 3, _state); + network->hllayersizes.ptr.p_int[0] = nin; + network->hllayersizes.ptr.p_int[1] = nhid1; + network->hllayersizes.ptr.p_int[2] = nout; + if( !iscls ) + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nout), _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); + network->hlnormtype = 0; + } + else + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*(nout-1)), _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nout), _state); + network->hlnormtype = 1; + } + mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); + mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); + mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nout, iscls, islinearout, _state); + return; + } + + /* + * Two hidden layers + */ + ae_vector_set_length(&network->hllayersizes, 4, _state); + network->hllayersizes.ptr.p_int[0] = nin; + network->hllayersizes.ptr.p_int[1] = nhid1; + network->hllayersizes.ptr.p_int[2] = nhid2; + network->hllayersizes.ptr.p_int[3] = nout; + if( !iscls ) + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*nout), _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); + network->hlnormtype = 0; + } + else + { + ae_vector_set_length(&network->hlconnections, mlpbase_hlconnfieldwidth*(nin*nhid1+nhid1*nhid2+nhid2*(nout-1)), _state); + ae_vector_set_length(&network->hlneurons, mlpbase_hlnfieldwidth*(nin+nhid1+nhid2+nout), _state); + network->hlnormtype = 1; + } + mlpbase_hladdinputlayer(network, &idxconn, &idxneuro, &idxstruct, nin, _state); + mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 1, nin, nhid1, _state); + mlpbase_hladdhiddenlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 2, nhid1, nhid2, _state); + mlpbase_hladdoutputlayer(network, &idxconn, &idxneuro, &idxstruct, &idxweights, 3, nhid2, nout, iscls, islinearout, _state); +} + + +/************************************************************************* +Internal subroutine. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +static void mlpbase_mlpcreate(ae_int_t nin, + ae_int_t nout, + /* Integer */ const ae_vector* lsizes, + /* Integer */ const ae_vector* ltypes, + /* Integer */ const ae_vector* lconnfirst, + /* Integer */ const ae_vector* lconnlast, + ae_int_t layerscount, + ae_bool isclsnet, + multilayerperceptron* network, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t ssize; + ae_int_t ntotal; + ae_int_t wcount; + ae_int_t offs; + ae_int_t nprocessed; + ae_int_t wallocated; + ae_vector localtemp; + ae_vector lnfirst; + ae_vector lnsyn; + mlpbuffers buf; + smlpgrad sgrad; + + ae_frame_make(_state, &_frame_block); + memset(&localtemp, 0, sizeof(localtemp)); + memset(&lnfirst, 0, sizeof(lnfirst)); + memset(&lnsyn, 0, sizeof(lnsyn)); + memset(&buf, 0, sizeof(buf)); + memset(&sgrad, 0, sizeof(sgrad)); + _multilayerperceptron_clear(network); + ae_vector_init(&localtemp, 0, DT_INT, _state, ae_true); + ae_vector_init(&lnfirst, 0, DT_INT, _state, ae_true); + ae_vector_init(&lnsyn, 0, DT_INT, _state, ae_true); + _mlpbuffers_init(&buf, _state, ae_true); + _smlpgrad_init(&sgrad, _state, ae_true); + + + /* + * Check + */ + ae_assert(layerscount>0, "MLPCreate: wrong parameters!", _state); + ae_assert(ltypes->ptr.p_int[0]==-2, "MLPCreate: wrong LTypes[0] (must be -2)!", _state); + for(i=0; i<=layerscount-1; i++) + { + ae_assert(lsizes->ptr.p_int[i]>0, "MLPCreate: wrong LSizes!", _state); + ae_assert(lconnfirst->ptr.p_int[i]>=0&&(lconnfirst->ptr.p_int[i]ptr.p_int[i]>=lconnfirst->ptr.p_int[i]&&(lconnlast->ptr.p_int[i]ptr.p_int[i]>=0||ltypes->ptr.p_int[i]==-5 ) + { + lnsyn.ptr.p_int[i] = 0; + for(j=lconnfirst->ptr.p_int[i]; j<=lconnlast->ptr.p_int[i]; j++) + { + lnsyn.ptr.p_int[i] = lnsyn.ptr.p_int[i]+lsizes->ptr.p_int[j]; + } + } + else + { + if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) + { + lnsyn.ptr.p_int[i] = 0; + } + } + ae_assert(lnsyn.ptr.p_int[i]>=0, "MLPCreate: internal error #0!", _state); + + /* + * Other info + */ + lnfirst.ptr.p_int[i] = ntotal; + ntotal = ntotal+lsizes->ptr.p_int[i]; + if( ltypes->ptr.p_int[i]==0 ) + { + wcount = wcount+lnsyn.ptr.p_int[i]*lsizes->ptr.p_int[i]; + } + } + ssize = 7+ntotal*mlpbase_nfieldwidth; + + /* + * Allocate + */ + ae_vector_set_length(&network->structinfo, ssize-1+1, _state); + ae_vector_set_length(&network->weights, wcount-1+1, _state); + if( isclsnet ) + { + ae_vector_set_length(&network->columnmeans, nin-1+1, _state); + ae_vector_set_length(&network->columnsigmas, nin-1+1, _state); + } + else + { + ae_vector_set_length(&network->columnmeans, nin+nout-1+1, _state); + ae_vector_set_length(&network->columnsigmas, nin+nout-1+1, _state); + } + ae_vector_set_length(&network->neurons, ntotal-1+1, _state); + ae_vector_set_length(&network->nwbuf, ae_maxint(wcount, 2*nout, _state)-1+1, _state); + ae_vector_set_length(&network->integerbuf, 3+1, _state); + ae_vector_set_length(&network->dfdnet, ntotal-1+1, _state); + ae_vector_set_length(&network->x, nin-1+1, _state); + ae_vector_set_length(&network->y, nout-1+1, _state); + ae_vector_set_length(&network->derror, ntotal-1+1, _state); + + /* + * Fill structure: + * * first, fill by dummy values to avoid spurious reports by Valgrind + * * then fill global info header + */ + for(i=0; i<=ssize-1; i++) + { + network->structinfo.ptr.p_int[i] = -999999; + } + network->structinfo.ptr.p_int[0] = ssize; + network->structinfo.ptr.p_int[1] = nin; + network->structinfo.ptr.p_int[2] = nout; + network->structinfo.ptr.p_int[3] = ntotal; + network->structinfo.ptr.p_int[4] = wcount; + network->structinfo.ptr.p_int[5] = 7; + if( isclsnet ) + { + network->structinfo.ptr.p_int[6] = 1; + } + else + { + network->structinfo.ptr.p_int[6] = 0; + } + + /* + * Fill structure: neuron connections + */ + nprocessed = 0; + wallocated = 0; + for(i=0; i<=layerscount-1; i++) + { + for(j=0; j<=lsizes->ptr.p_int[i]-1; j++) + { + offs = network->structinfo.ptr.p_int[5]+nprocessed*mlpbase_nfieldwidth; + network->structinfo.ptr.p_int[offs+0] = ltypes->ptr.p_int[i]; + if( ltypes->ptr.p_int[i]==0 ) + { + + /* + * Adaptive summator: + * * connections with weights to previous neurons + */ + network->structinfo.ptr.p_int[offs+1] = lnsyn.ptr.p_int[i]; + network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]; + network->structinfo.ptr.p_int[offs+3] = wallocated; + wallocated = wallocated+lnsyn.ptr.p_int[i]; + nprocessed = nprocessed+1; + } + if( ltypes->ptr.p_int[i]>0||ltypes->ptr.p_int[i]==-5 ) + { + + /* + * Activation layer: + * * each neuron connected to one (only one) of previous neurons. + * * no weights + */ + network->structinfo.ptr.p_int[offs+1] = 1; + network->structinfo.ptr.p_int[offs+2] = lnfirst.ptr.p_int[lconnfirst->ptr.p_int[i]]+j; + network->structinfo.ptr.p_int[offs+3] = -1; + nprocessed = nprocessed+1; + } + if( (ltypes->ptr.p_int[i]==-2||ltypes->ptr.p_int[i]==-3)||ltypes->ptr.p_int[i]==-4 ) + { + nprocessed = nprocessed+1; + } + } + } + ae_assert(wallocated==wcount, "MLPCreate: internal error #1!", _state); + ae_assert(nprocessed==ntotal, "MLPCreate: internal error #2!", _state); + + /* + * Fill weights by small random values + * Initialize means and sigmas + */ + for(i=0; i<=nin-1; i++) + { + network->columnmeans.ptr.p_double[i] = (double)(0); + network->columnsigmas.ptr.p_double[i] = (double)(1); + } + if( !isclsnet ) + { + for(i=0; i<=nout-1; i++) + { + network->columnmeans.ptr.p_double[nin+i] = (double)(0); + network->columnsigmas.ptr.p_double[nin+i] = (double)(1); + } + } + mlprandomize(network, _state); + + /* + * Seed buffers + */ + ae_shared_pool_set_seed(&network->buf, &buf, (ae_int_t)sizeof(buf), (ae_copy_constructor)_mlpbuffers_init_copy, (ae_destructor)_mlpbuffers_destroy, _state); + ae_vector_set_length(&sgrad.g, wcount, _state); + sgrad.f = 0.0; + for(i=0; i<=wcount-1; i++) + { + sgrad.g.ptr.p_double[i] = 0.0; + } + ae_shared_pool_set_seed(&network->gradbuf, &sgrad, (ae_int_t)sizeof(sgrad), (ae_copy_constructor)_smlpgrad_init_copy, (ae_destructor)_smlpgrad_destroy, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function returns information about Ith neuron of Kth layer. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +static void mlpbase_mlpgetneuroninfox(const multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + /* Integer */ ae_vector* integerbuf, + ae_int_t* fkind, + double* threshold, + ae_state *_state) +{ + ae_int_t ncnt; + ae_int_t istart; + ae_int_t highlevelidx; + ae_int_t activationoffset; + + *fkind = 0; + *threshold = 0.0; + + iallocv(2, integerbuf, _state); + ncnt = network->hlneurons.cnt/mlpbase_hlnfieldwidth; + istart = network->structinfo.ptr.p_int[5]; + + /* + * search + */ + integerbuf->ptr.p_int[0] = k; + integerbuf->ptr.p_int[1] = i; + highlevelidx = recsearch(&network->hlneurons, mlpbase_hlnfieldwidth, 2, 0, ncnt, integerbuf, _state); + ae_assert(highlevelidx>=0, "MLPGetNeuronInfo: incorrect (nonexistent) layer or neuron index", _state); + + /* + * 1. find offset of the activation function record in the + */ + if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]>=0 ) + { + activationoffset = istart+network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+2]*mlpbase_nfieldwidth; + *fkind = network->structinfo.ptr.p_int[activationoffset+0]; + } + else + { + *fkind = 0; + } + if( network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]>=0 ) + { + *threshold = network->weights.ptr.p_double[network->hlneurons.ptr.p_int[highlevelidx*mlpbase_hlnfieldwidth+3]]; + } + else + { + *threshold = (double)(0); + } +} + + +/************************************************************************* +This function returns information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + +RESULT: + connection weight (zero for non-existent connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. returns zero if neurons exist, but there is no connection between them + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +static double mlpbase_mlpgetweightx(const multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + /* Integer */ ae_vector* integerbuf, + ae_state *_state) +{ + ae_int_t ccnt; + ae_int_t highlevelidx; + double result; + + + iallocv(4, integerbuf, _state); + ccnt = network->hlconnections.cnt/mlpbase_hlconnfieldwidth; + + /* + * check params + */ + ae_assert(k0>=0&&k0hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K0", _state); + ae_assert(i0>=0&&i0hllayersizes.ptr.p_int[k0], "MLPGetWeight: incorrect (nonexistent) I0", _state); + ae_assert(k1>=0&&k1hllayersizes.cnt, "MLPGetWeight: incorrect (nonexistent) K1", _state); + ae_assert(i1>=0&&i1hllayersizes.ptr.p_int[k1], "MLPGetWeight: incorrect (nonexistent) I1", _state); + + /* + * search + */ + integerbuf->ptr.p_int[0] = k0; + integerbuf->ptr.p_int[1] = i0; + integerbuf->ptr.p_int[2] = k1; + integerbuf->ptr.p_int[3] = i1; + highlevelidx = recsearch(&network->hlconnections, mlpbase_hlconnfieldwidth, 4, 0, ccnt, integerbuf, _state); + if( highlevelidx>=0 ) + { + result = network->weights.ptr.p_double[network->hlconnections.ptr.p_int[highlevelidx*mlpbase_hlconnfieldwidth+4]]; + } + else + { + result = (double)(0); + } + return result; +} + + +/************************************************************************* +Internal subroutine for Hessian calculation. + +WARNING! Unspeakable math far beyong human capabilities :) +*************************************************************************/ +static void mlpbase_mlphessianbatchinternal(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_bool naturalerr, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t kl; + ae_int_t offs; + ae_int_t n1; + ae_int_t n2; + ae_int_t w1; + ae_int_t w2; + double s; + double t; + double v; + double et; + ae_bool bflag; + double f; + double df; + double d2f; + double deidyj; + double mx; + double q; + double z; + double s2; + double expi; + double expj; + ae_vector x; + ae_vector desiredy; + ae_vector gt; + ae_vector zeros; + ae_matrix rx; + ae_matrix ry; + ae_matrix rdx; + ae_matrix rdy; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&desiredy, 0, sizeof(desiredy)); + memset(>, 0, sizeof(gt)); + memset(&zeros, 0, sizeof(zeros)); + memset(&rx, 0, sizeof(rx)); + memset(&ry, 0, sizeof(ry)); + memset(&rdx, 0, sizeof(rdx)); + memset(&rdy, 0, sizeof(rdy)); + *e = 0.0; + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&desiredy, 0, DT_REAL, _state, ae_true); + ae_vector_init(>, 0, DT_REAL, _state, ae_true); + ae_vector_init(&zeros, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&rx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ry, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&rdx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&rdy, 0, 0, DT_REAL, _state, ae_true); + + mlpproperties(network, &nin, &nout, &wcount, _state); + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Prepare + */ + ae_vector_set_length(&x, nin-1+1, _state); + ae_vector_set_length(&desiredy, nout-1+1, _state); + ae_vector_set_length(&zeros, wcount-1+1, _state); + ae_vector_set_length(>, wcount-1+1, _state); + ae_matrix_set_length(&rx, ntotal+nout-1+1, wcount-1+1, _state); + ae_matrix_set_length(&ry, ntotal+nout-1+1, wcount-1+1, _state); + ae_matrix_set_length(&rdx, ntotal+nout-1+1, wcount-1+1, _state); + ae_matrix_set_length(&rdy, ntotal+nout-1+1, wcount-1+1, _state); + *e = (double)(0); + for(i=0; i<=wcount-1; i++) + { + zeros.ptr.p_double[i] = (double)(0); + } + ae_v_move(&grad->ptr.p_double[0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + for(i=0; i<=wcount-1; i++) + { + ae_v_move(&h->ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + } + + /* + * Process + */ + for(k=0; k<=ssize-1; k++) + { + + /* + * Process vector with MLPGradN. + * Now Neurons, DFDNET and DError contains results of the last run. + */ + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nin-1)); + if( mlpissoftmax(network, _state) ) + { + + /* + * class labels outputs + */ + kl = ae_round(xy->ptr.pp_double[k][nin], _state); + for(i=0; i<=nout-1; i++) + { + if( i==kl ) + { + desiredy.ptr.p_double[i] = (double)(1); + } + else + { + desiredy.ptr.p_double[i] = (double)(0); + } + } + } + else + { + + /* + * real outputs + */ + ae_v_move(&desiredy.ptr.p_double[0], 1, &xy->ptr.pp_double[k][nin], 1, ae_v_len(0,nout-1)); + } + if( naturalerr ) + { + mlpgradn(network, &x, &desiredy, &et, >, _state); + } + else + { + mlpgrad(network, &x, &desiredy, &et, >, _state); + } + + /* + * grad, error + */ + *e = *e+et; + ae_v_add(&grad->ptr.p_double[0], 1, >.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + + /* + * Hessian. + * Forward pass of the R-algorithm + */ + for(i=0; i<=ntotal-1; i++) + { + offs = istart+i*mlpbase_nfieldwidth; + ae_v_move(&rx.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ae_v_move(&ry.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) + { + + /* + * Activation function + */ + n1 = network->structinfo.ptr.p_int[offs+2]; + ae_v_move(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); + v = network->dfdnet.ptr.p_double[i]; + ae_v_moved(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); + continue; + } + if( network->structinfo.ptr.p_int[offs+0]==0 ) + { + + /* + * Adaptive summator + */ + n1 = network->structinfo.ptr.p_int[offs+2]; + n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; + w1 = network->structinfo.ptr.p_int[offs+3]; + w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; + for(j=n1; j<=n2; j++) + { + v = network->weights.ptr.p_double[w1+j-n1]; + ae_v_addd(&rx.ptr.pp_double[i][0], 1, &ry.ptr.pp_double[j][0], 1, ae_v_len(0,wcount-1), v); + rx.ptr.pp_double[i][w1+j-n1] = rx.ptr.pp_double[i][w1+j-n1]+network->neurons.ptr.p_double[j]; + } + ae_v_move(&ry.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); + continue; + } + if( network->structinfo.ptr.p_int[offs+0]<0 ) + { + bflag = ae_true; + if( network->structinfo.ptr.p_int[offs+0]==-2 ) + { + + /* + * input neuron, left unchanged + */ + bflag = ae_false; + } + if( network->structinfo.ptr.p_int[offs+0]==-3 ) + { + + /* + * "-1" neuron, left unchanged + */ + bflag = ae_false; + } + if( network->structinfo.ptr.p_int[offs+0]==-4 ) + { + + /* + * "0" neuron, left unchanged + */ + bflag = ae_false; + } + ae_assert(!bflag, "MLPHessianNBatch: internal error - unknown neuron type!", _state); + continue; + } + } + + /* + * Hessian. Backward pass of the R-algorithm. + * + * Stage 1. Initialize RDY + */ + for(i=0; i<=ntotal+nout-1; i++) + { + ae_v_move(&rdy.ptr.pp_double[i][0], 1, &zeros.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + } + if( network->structinfo.ptr.p_int[6]==0 ) + { + + /* + * Standardisation. + * + * In context of the Hessian calculation standardisation + * is considered as additional layer with weightless + * activation function: + * + * F(NET) := Sigma*NET + * + * So we add one more layer to forward pass, and + * make forward/backward pass through this layer. + */ + for(i=0; i<=nout-1; i++) + { + n1 = ntotal-nout+i; + n2 = ntotal+i; + + /* + * Forward pass from N1 to N2 + */ + ae_v_move(&rx.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n1][0], 1, ae_v_len(0,wcount-1)); + v = network->columnsigmas.ptr.p_double[nin+i]; + ae_v_moved(&ry.ptr.pp_double[n2][0], 1, &rx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), v); + + /* + * Initialization of RDY + */ + ae_v_move(&rdy.ptr.pp_double[n2][0], 1, &ry.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); + + /* + * Backward pass from N2 to N1: + * 1. Calculate R(dE/dX). + * 2. No R(dE/dWij) is needed since weight of activation neuron + * is fixed to 1. So we can update R(dE/dY) for + * the connected neuron (note that Vij=0, Wij=1) + */ + df = network->columnsigmas.ptr.p_double[nin+i]; + ae_v_moved(&rdx.ptr.pp_double[n2][0], 1, &rdy.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1), df); + ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[n2][0], 1, ae_v_len(0,wcount-1)); + } + } + else + { + + /* + * Softmax. + * + * Initialize RDY using generalized expression for ei'(yi) + * (see expression (9) from p. 5 of "Fast Exact Multiplication by the Hessian"). + * + * When we are working with softmax network, generalized + * expression for ei'(yi) is used because softmax + * normalization leads to ei, which depends on all y's + */ + if( naturalerr ) + { + + /* + * softmax + cross-entropy. + * We have: + * + * S = sum(exp(yk)), + * ei = sum(trn)*exp(yi)/S-trn_i + * + * j=i: d(ei)/d(yj) = T*exp(yi)*(S-exp(yi))/S^2 + * j<>i: d(ei)/d(yj) = -T*exp(yi)*exp(yj)/S^2 + */ + t = (double)(0); + for(i=0; i<=nout-1; i++) + { + t = t+desiredy.ptr.p_double[i]; + } + mx = network->neurons.ptr.p_double[ntotal-nout]; + for(i=0; i<=nout-1; i++) + { + mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); + } + s = (double)(0); + for(i=0; i<=nout-1; i++) + { + network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); + s = s+network->nwbuf.ptr.p_double[i]; + } + for(i=0; i<=nout-1; i++) + { + for(j=0; j<=nout-1; j++) + { + if( j==i ) + { + deidyj = t*network->nwbuf.ptr.p_double[i]*(s-network->nwbuf.ptr.p_double[i])/ae_sqr(s, _state); + ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+i][0], 1, ae_v_len(0,wcount-1), deidyj); + } + else + { + deidyj = -t*network->nwbuf.ptr.p_double[i]*network->nwbuf.ptr.p_double[j]/ae_sqr(s, _state); + ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); + } + } + } + } + else + { + + /* + * For a softmax + squared error we have expression + * far beyond human imagination so we dont even try + * to comment on it. Just enjoy the code... + * + * P.S. That's why "natural error" is called "natural" - + * compact beatiful expressions, fast code.... + */ + mx = network->neurons.ptr.p_double[ntotal-nout]; + for(i=0; i<=nout-1; i++) + { + mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); + } + s = (double)(0); + s2 = (double)(0); + for(i=0; i<=nout-1; i++) + { + network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); + s = s+network->nwbuf.ptr.p_double[i]; + s2 = s2+ae_sqr(network->nwbuf.ptr.p_double[i], _state); + } + q = (double)(0); + for(i=0; i<=nout-1; i++) + { + q = q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*network->nwbuf.ptr.p_double[i]; + } + for(i=0; i<=nout-1; i++) + { + z = -q+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])*s; + expi = network->nwbuf.ptr.p_double[i]; + for(j=0; j<=nout-1; j++) + { + expj = network->nwbuf.ptr.p_double[j]; + if( j==i ) + { + deidyj = expi/ae_sqr(s, _state)*((z+expi)*(s-(double)2*expi)/s+expi*s2/ae_sqr(s, _state)); + } + else + { + deidyj = expi*expj/ae_sqr(s, _state)*(s2/ae_sqr(s, _state)-(double)2*z/s-(expi+expj)/s+(network->y.ptr.p_double[i]-desiredy.ptr.p_double[i])-(network->y.ptr.p_double[j]-desiredy.ptr.p_double[j])); + } + ae_v_addd(&rdy.ptr.pp_double[ntotal-nout+i][0], 1, &ry.ptr.pp_double[ntotal-nout+j][0], 1, ae_v_len(0,wcount-1), deidyj); + } + } + } + } + + /* + * Hessian. Backward pass of the R-algorithm + * + * Stage 2. Process. + */ + for(i=ntotal-1; i>=0; i--) + { + + /* + * Possible variants: + * 1. Activation function + * 2. Adaptive summator + * 3. Special neuron + */ + offs = istart+i*mlpbase_nfieldwidth; + if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) + { + n1 = network->structinfo.ptr.p_int[offs+2]; + + /* + * First, calculate R(dE/dX). + */ + mlpactivationfunction(network->neurons.ptr.p_double[n1], network->structinfo.ptr.p_int[offs+0], &f, &df, &d2f, _state); + v = d2f*network->derror.ptr.p_double[i]; + ae_v_moved(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), df); + ae_v_addd(&rdx.ptr.pp_double[i][0], 1, &rx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); + + /* + * No R(dE/dWij) is needed since weight of activation neuron + * is fixed to 1. + * + * So we can update R(dE/dY) for the connected neuron. + * (note that Vij=0, Wij=1) + */ + ae_v_add(&rdy.ptr.pp_double[n1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); + continue; + } + if( network->structinfo.ptr.p_int[offs+0]==0 ) + { + + /* + * Adaptive summator + */ + n1 = network->structinfo.ptr.p_int[offs+2]; + n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; + w1 = network->structinfo.ptr.p_int[offs+3]; + w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; + + /* + * First, calculate R(dE/dX). + */ + ae_v_move(&rdx.ptr.pp_double[i][0], 1, &rdy.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); + + /* + * Then, calculate R(dE/dWij) + */ + for(j=w1; j<=w2; j++) + { + v = network->neurons.ptr.p_double[n1+j-w1]; + ae_v_addd(&h->ptr.pp_double[j][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); + v = network->derror.ptr.p_double[i]; + ae_v_addd(&h->ptr.pp_double[j][0], 1, &ry.ptr.pp_double[n1+j-w1][0], 1, ae_v_len(0,wcount-1), v); + } + + /* + * And finally, update R(dE/dY) for connected neurons. + */ + for(j=w1; j<=w2; j++) + { + v = network->weights.ptr.p_double[j]; + ae_v_addd(&rdy.ptr.pp_double[n1+j-w1][0], 1, &rdx.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1), v); + rdy.ptr.pp_double[n1+j-w1][j] = rdy.ptr.pp_double[n1+j-w1][j]+network->derror.ptr.p_double[i]; + } + continue; + } + if( network->structinfo.ptr.p_int[offs+0]<0 ) + { + bflag = ae_false; + if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) + { + + /* + * Special neuron type, no back-propagation required + */ + bflag = ae_true; + } + ae_assert(bflag, "MLPHessianNBatch: unknown neuron type!", _state); + continue; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine + +Network must be processed by MLPProcess on X +*************************************************************************/ +static void mlpbase_mlpinternalcalculategradient(multilayerperceptron* network, + /* Real */ const ae_vector* neurons, + /* Real */ const ae_vector* weights, + /* Real */ ae_vector* derror, + /* Real */ ae_vector* grad, + ae_bool naturalerrorfunc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n1; + ae_int_t n2; + ae_int_t w1; + ae_int_t w2; + ae_int_t ntotal; + ae_int_t istart; + ae_int_t nin; + ae_int_t nout; + ae_int_t offs; + double dedf; + double dfdnet; + double v; + double fown; + double deown; + double net; + double mx; + ae_bool bflag; + + + + /* + * Read network geometry + */ + nin = network->structinfo.ptr.p_int[1]; + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + + /* + * Pre-processing of dError/dOut: + * from dError/dOut(normalized) to dError/dOut(non-normalized) + */ + ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPInternalCalculateGradient: unknown normalization type!", _state); + if( network->structinfo.ptr.p_int[6]==1 ) + { + + /* + * Softmax + */ + if( !naturalerrorfunc ) + { + mx = network->neurons.ptr.p_double[ntotal-nout]; + for(i=0; i<=nout-1; i++) + { + mx = ae_maxreal(mx, network->neurons.ptr.p_double[ntotal-nout+i], _state); + } + net = (double)(0); + for(i=0; i<=nout-1; i++) + { + network->nwbuf.ptr.p_double[i] = ae_exp(network->neurons.ptr.p_double[ntotal-nout+i]-mx, _state); + net = net+network->nwbuf.ptr.p_double[i]; + } + v = ae_v_dotproduct(&network->derror.ptr.p_double[ntotal-nout], 1, &network->nwbuf.ptr.p_double[0], 1, ae_v_len(ntotal-nout,ntotal-1)); + for(i=0; i<=nout-1; i++) + { + fown = network->nwbuf.ptr.p_double[i]; + deown = network->derror.ptr.p_double[ntotal-nout+i]; + network->nwbuf.ptr.p_double[nout+i] = (-v+deown*fown+deown*(net-fown))*fown/ae_sqr(net, _state); + } + for(i=0; i<=nout-1; i++) + { + network->derror.ptr.p_double[ntotal-nout+i] = network->nwbuf.ptr.p_double[nout+i]; + } + } + } + else + { + + /* + * Un-standardisation + */ + for(i=0; i<=nout-1; i++) + { + network->derror.ptr.p_double[ntotal-nout+i] = network->derror.ptr.p_double[ntotal-nout+i]*network->columnsigmas.ptr.p_double[nin+i]; + } + } + + /* + * Backpropagation + */ + for(i=ntotal-1; i>=0; i--) + { + + /* + * Extract info + */ + offs = istart+i*mlpbase_nfieldwidth; + if( network->structinfo.ptr.p_int[offs+0]>0||network->structinfo.ptr.p_int[offs+0]==-5 ) + { + + /* + * Activation function + */ + dedf = network->derror.ptr.p_double[i]; + dfdnet = network->dfdnet.ptr.p_double[i]; + derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]] = derror->ptr.p_double[network->structinfo.ptr.p_int[offs+2]]+dedf*dfdnet; + continue; + } + if( network->structinfo.ptr.p_int[offs+0]==0 ) + { + + /* + * Adaptive summator + */ + n1 = network->structinfo.ptr.p_int[offs+2]; + n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; + w1 = network->structinfo.ptr.p_int[offs+3]; + w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; + dedf = network->derror.ptr.p_double[i]; + dfdnet = 1.0; + v = dedf*dfdnet; + ae_v_moved(&grad->ptr.p_double[w1], 1, &neurons->ptr.p_double[n1], 1, ae_v_len(w1,w2), v); + ae_v_addd(&derror->ptr.p_double[n1], 1, &weights->ptr.p_double[w1], 1, ae_v_len(n1,n2), v); + continue; + } + if( network->structinfo.ptr.p_int[offs+0]<0 ) + { + bflag = ae_false; + if( (network->structinfo.ptr.p_int[offs+0]==-2||network->structinfo.ptr.p_int[offs+0]==-3)||network->structinfo.ptr.p_int[offs+0]==-4 ) + { + + /* + * Special neuron type, no back-propagation required + */ + bflag = ae_true; + } + ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); + continue; + } + } +} + + +static void mlpbase_mlpchunkedgradient(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + double* e, + ae_bool naturalerrorfunc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t kl; + ae_int_t ntotal; + ae_int_t nin; + ae_int_t nout; + ae_int_t offs; + double f; + double df; + double d2f; + double v; + double vv; + double s; + double fown; + double deown; + ae_bool bflag; + ae_int_t istart; + ae_int_t entrysize; + ae_int_t dfoffs; + ae_int_t derroroffs; + ae_int_t entryoffs; + ae_int_t neuronidx; + ae_int_t srcentryoffs; + ae_int_t srcneuronidx; + ae_int_t srcweightidx; + ae_int_t neurontype; + ae_int_t nweights; + ae_int_t offs0; + ae_int_t offs1; + ae_int_t offs2; + double v0; + double v1; + double v2; + double v3; + double s0; + double s1; + double s2; + double s3; + ae_int_t chunksize; + + + chunksize = 4; + ae_assert(csize<=chunksize, "MLPChunkedGradient: internal error (CSize>ChunkSize)", _state); + + /* + * Try to use HPC core, if possible + */ + if( hpcchunkedgradient(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, e, naturalerrorfunc, _state) ) + { + return; + } + + /* + * Read network geometry, prepare data + */ + nin = network->structinfo.ptr.p_int[1]; + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + entrysize = 12; + dfoffs = 4; + derroroffs = 8; + + /* + * Fill Batch4Buf by zeros. + * + * THIS STAGE IS VERY IMPORTANT! + * + * We fill all components of entry - neuron values, dF/dNET, dError/dF. + * It allows us to easily handle situations when CSizeptr.p_double[i] = (double)(0); + } + + /* + * Forward pass: + * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],(double)(0)) ) + { + batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; + } + else + { + batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; + } + } + } + for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) + { + entryoffs = entrysize*neuronidx; + offs = istart+neuronidx*mlpbase_nfieldwidth; + neurontype = network->structinfo.ptr.p_int[offs+0]; + if( neurontype>0||neurontype==-5 ) + { + + /* + * "activation function" neuron, which takes value of neuron SrcNeuronIdx + * and applies activation function to it. + * + * This neuron has no weights and no tunable parameters. + */ + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+0] = f; + batch4buf->ptr.p_double[entryoffs+0+dfoffs] = df; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+1] = f; + batch4buf->ptr.p_double[entryoffs+1+dfoffs] = df; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+2] = f; + batch4buf->ptr.p_double[entryoffs+2+dfoffs] = df; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+3] = f; + batch4buf->ptr.p_double[entryoffs+3+dfoffs] = df; + continue; + } + if( neurontype==0 ) + { + + /* + * "adaptive summator" neuron, whose output is a weighted sum of inputs. + * It has weights, but has no activation function. + */ + nweights = network->structinfo.ptr.p_int[offs+1]; + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + srcweightidx = network->structinfo.ptr.p_int[offs+3]; + v0 = (double)(0); + v1 = (double)(0); + v2 = (double)(0); + v3 = (double)(0); + for(j=0; j<=nweights-1; j++) + { + v = network->weights.ptr.p_double[srcweightidx]; + srcweightidx = srcweightidx+1; + v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; + v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; + v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; + v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; + srcentryoffs = srcentryoffs+entrysize; + } + batch4buf->ptr.p_double[entryoffs+0] = v0; + batch4buf->ptr.p_double[entryoffs+1] = v1; + batch4buf->ptr.p_double[entryoffs+2] = v2; + batch4buf->ptr.p_double[entryoffs+3] = v3; + batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(1); + batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(1); + batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(1); + batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(1); + continue; + } + if( neurontype<0 ) + { + bflag = ae_false; + if( neurontype==-2 ) + { + + /* + * Input neuron, left unchanged + */ + bflag = ae_true; + } + if( neurontype==-3 ) + { + + /* + * "-1" neuron + */ + batch4buf->ptr.p_double[entryoffs+0] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+1] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+2] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+3] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(0); + bflag = ae_true; + } + if( neurontype==-4 ) + { + + /* + * "0" neuron + */ + batch4buf->ptr.p_double[entryoffs+0] = (double)(0); + batch4buf->ptr.p_double[entryoffs+1] = (double)(0); + batch4buf->ptr.p_double[entryoffs+2] = (double)(0); + batch4buf->ptr.p_double[entryoffs+3] = (double)(0); + batch4buf->ptr.p_double[entryoffs+0+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+1+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+2+dfoffs] = (double)(0); + batch4buf->ptr.p_double[entryoffs+3+dfoffs] = (double)(0); + bflag = ae_true; + } + ae_assert(bflag, "MLPChunkedGradient: internal error - unknown neuron type!", _state); + continue; + } + } + + /* + * Intermediate phase between forward and backward passes. + * + * For regression networks: + * * forward pass is completely done (no additional post-processing is + * needed). + * * before starting backward pass, we have to calculate dError/dOut + * for output neurons. We also update error at this phase. + * + * For classification networks: + * * in addition to forward pass we apply SOFTMAX normalization to + * output neurons. + * * after applying normalization, we have to calculate dError/dOut, + * which is calculated in two steps: + * * first, we calculate derivative of error with respect to SOFTMAX + * normalized outputs (normalized dError) + * * then, we calculate derivative of error with respect to values + * of outputs BEFORE normalization was applied to them + */ + ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedGradient: unknown normalization type!", _state); + if( network->structinfo.ptr.p_int[6]==1 ) + { + + /* + * SOFTMAX-normalized network. + * + * First, calculate (V0,V1,V2,V3) - component-wise maximum + * of output neurons. This vector of maximum values will be + * used for normalization of outputs prior to calculating + * exponentials. + * + * NOTE: the only purpose of this stage is to prevent overflow + * during calculation of exponentials. With this stage + * we make sure that all exponentials are calculated + * with non-positive argument. If you load (0,0,0,0) to + * (V0,V1,V2,V3), your program will continue working - + * although with less robustness. + */ + entryoffs = entrysize*(ntotal-nout); + v0 = batch4buf->ptr.p_double[entryoffs+0]; + v1 = batch4buf->ptr.p_double[entryoffs+1]; + v2 = batch4buf->ptr.p_double[entryoffs+2]; + v3 = batch4buf->ptr.p_double[entryoffs+3]; + entryoffs = entryoffs+entrysize; + for(i=1; i<=nout-1; i++) + { + v = batch4buf->ptr.p_double[entryoffs+0]; + if( v>v0 ) + { + v0 = v; + } + v = batch4buf->ptr.p_double[entryoffs+1]; + if( v>v1 ) + { + v1 = v; + } + v = batch4buf->ptr.p_double[entryoffs+2]; + if( v>v2 ) + { + v2 = v; + } + v = batch4buf->ptr.p_double[entryoffs+3]; + if( v>v3 ) + { + v3 = v; + } + entryoffs = entryoffs+entrysize; + } + + /* + * Then, calculate exponentials and place them to part of the + * array which is located past the last entry. We also + * calculate sum of exponentials which will be stored past the + * exponentials. + */ + entryoffs = entrysize*(ntotal-nout); + offs0 = entrysize*ntotal; + s0 = (double)(0); + s1 = (double)(0); + s2 = (double)(0); + s3 = (double)(0); + for(i=0; i<=nout-1; i++) + { + v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); + s0 = s0+v; + batch4buf->ptr.p_double[offs0+0] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); + s1 = s1+v; + batch4buf->ptr.p_double[offs0+1] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); + s2 = s2+v; + batch4buf->ptr.p_double[offs0+2] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); + s3 = s3+v; + batch4buf->ptr.p_double[offs0+3] = v; + entryoffs = entryoffs+entrysize; + offs0 = offs0+chunksize; + } + offs0 = entrysize*ntotal+2*nout*chunksize; + batch4buf->ptr.p_double[offs0+0] = s0; + batch4buf->ptr.p_double[offs0+1] = s1; + batch4buf->ptr.p_double[offs0+2] = s2; + batch4buf->ptr.p_double[offs0+3] = s3; + + /* + * Now we have: + * * Batch4Buf[0...EntrySize*NTotal-1] stores: + * * NTotal*ChunkSize neuron output values (SOFTMAX normalization + * was not applied to these values), + * * NTotal*ChunkSize values of dF/dNET (derivative of neuron + * output with respect to its input) + * * NTotal*ChunkSize zeros in the elements which correspond to + * dError/dOut (derivative of error with respect to neuron output). + * * Batch4Buf[EntrySize*NTotal...EntrySize*NTotal+ChunkSize*NOut-1] - + * stores exponentials of last NOut neurons. + * * Batch4Buf[EntrySize*NTotal+ChunkSize*NOut-1...EntrySize*NTotal+ChunkSize*2*NOut-1] + * - can be used for temporary calculations + * * Batch4Buf[EntrySize*NTotal+ChunkSize*2*NOut...EntrySize*NTotal+ChunkSize*2*NOut+ChunkSize-1] + * - stores sum-of-exponentials + * + * Block below calculates derivatives of error function with respect + * to non-SOFTMAX-normalized output values of last NOut neurons. + * + * It is quite complicated; we do not describe algebra behind it, + * but if you want you may check it yourself :) + */ + if( naturalerrorfunc ) + { + + /* + * Calculate derivative of error with respect to values of + * output neurons PRIOR TO SOFTMAX NORMALIZATION. Because we + * use natural error function (cross-entropy), we can do so + * very easy. + */ + offs0 = entrysize*ntotal+2*nout*chunksize; + for(k=0; k<=csize-1; k++) + { + s = batch4buf->ptr.p_double[offs0+k]; + kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); + offs1 = (ntotal-nout)*entrysize+derroroffs+k; + offs2 = entrysize*ntotal+k; + for(i=0; i<=nout-1; i++) + { + if( i==kl ) + { + v = (double)(1); + } + else + { + v = (double)(0); + } + vv = batch4buf->ptr.p_double[offs2]; + batch4buf->ptr.p_double[offs1] = vv/s-v; + *e = *e+mlpbase_safecrossentropy(v, vv/s, _state); + offs1 = offs1+entrysize; + offs2 = offs2+chunksize; + } + } + } + else + { + + /* + * SOFTMAX normalization makes things very difficult. + * Sorry, we do not dare to describe this esoteric math + * in details. + */ + offs0 = entrysize*ntotal+chunksize*2*nout; + for(k=0; k<=csize-1; k++) + { + s = batch4buf->ptr.p_double[offs0+k]; + kl = ae_round(xy->ptr.pp_double[cstart+k][nin], _state); + vv = (double)(0); + offs1 = entrysize*ntotal+k; + offs2 = entrysize*ntotal+nout*chunksize+k; + for(i=0; i<=nout-1; i++) + { + fown = batch4buf->ptr.p_double[offs1]; + if( i==kl ) + { + deown = fown/s-(double)1; + } + else + { + deown = fown/s; + } + batch4buf->ptr.p_double[offs2] = deown; + vv = vv+deown*fown; + *e = *e+deown*deown/(double)2; + offs1 = offs1+chunksize; + offs2 = offs2+chunksize; + } + offs1 = entrysize*ntotal+k; + offs2 = entrysize*ntotal+nout*chunksize+k; + for(i=0; i<=nout-1; i++) + { + fown = batch4buf->ptr.p_double[offs1]; + deown = batch4buf->ptr.p_double[offs2]; + batch4buf->ptr.p_double[(ntotal-nout+i)*entrysize+derroroffs+k] = (-vv+deown*fown+deown*(s-fown))*fown/ae_sqr(s, _state); + offs1 = offs1+chunksize; + offs2 = offs2+chunksize; + } + } + } + } + else + { + + /* + * Regression network with sum-of-squares function. + * + * For each NOut of last neurons: + * * calculate difference between actual and desired output + * * calculate dError/dOut for this neuron (proportional to difference) + * * store in in last 4 components of entry (these values are used + * to start backpropagation) + * * update error + */ + for(i=0; i<=nout-1; i++) + { + v0 = network->columnsigmas.ptr.p_double[nin+i]; + v1 = network->columnmeans.ptr.p_double[nin+i]; + entryoffs = entrysize*(ntotal-nout+i); + offs0 = entryoffs; + offs1 = entryoffs+derroroffs; + for(j=0; j<=csize-1; j++) + { + v = batch4buf->ptr.p_double[offs0+j]*v0+v1-xy->ptr.pp_double[cstart+j][nin+i]; + batch4buf->ptr.p_double[offs1+j] = v*v0; + *e = *e+v*v/(double)2; + } + } + } + + /* + * Backpropagation + */ + for(neuronidx=ntotal-1; neuronidx>=0; neuronidx--) + { + entryoffs = entrysize*neuronidx; + offs = istart+neuronidx*mlpbase_nfieldwidth; + neurontype = network->structinfo.ptr.p_int[offs+0]; + if( neurontype>0||neurontype==-5 ) + { + + /* + * Activation function + */ + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + offs0 = srcentryoffs+derroroffs; + offs1 = entryoffs+derroroffs; + offs2 = entryoffs+dfoffs; + batch4buf->ptr.p_double[offs0+0] = batch4buf->ptr.p_double[offs0+0]+batch4buf->ptr.p_double[offs1+0]*batch4buf->ptr.p_double[offs2+0]; + batch4buf->ptr.p_double[offs0+1] = batch4buf->ptr.p_double[offs0+1]+batch4buf->ptr.p_double[offs1+1]*batch4buf->ptr.p_double[offs2+1]; + batch4buf->ptr.p_double[offs0+2] = batch4buf->ptr.p_double[offs0+2]+batch4buf->ptr.p_double[offs1+2]*batch4buf->ptr.p_double[offs2+2]; + batch4buf->ptr.p_double[offs0+3] = batch4buf->ptr.p_double[offs0+3]+batch4buf->ptr.p_double[offs1+3]*batch4buf->ptr.p_double[offs2+3]; + continue; + } + if( neurontype==0 ) + { + + /* + * Adaptive summator + */ + nweights = network->structinfo.ptr.p_int[offs+1]; + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + srcweightidx = network->structinfo.ptr.p_int[offs+3]; + v0 = batch4buf->ptr.p_double[entryoffs+derroroffs+0]; + v1 = batch4buf->ptr.p_double[entryoffs+derroroffs+1]; + v2 = batch4buf->ptr.p_double[entryoffs+derroroffs+2]; + v3 = batch4buf->ptr.p_double[entryoffs+derroroffs+3]; + for(j=0; j<=nweights-1; j++) + { + offs0 = srcentryoffs; + offs1 = srcentryoffs+derroroffs; + v = network->weights.ptr.p_double[srcweightidx]; + hpcbuf->ptr.p_double[srcweightidx] = hpcbuf->ptr.p_double[srcweightidx]+batch4buf->ptr.p_double[offs0+0]*v0+batch4buf->ptr.p_double[offs0+1]*v1+batch4buf->ptr.p_double[offs0+2]*v2+batch4buf->ptr.p_double[offs0+3]*v3; + batch4buf->ptr.p_double[offs1+0] = batch4buf->ptr.p_double[offs1+0]+v*v0; + batch4buf->ptr.p_double[offs1+1] = batch4buf->ptr.p_double[offs1+1]+v*v1; + batch4buf->ptr.p_double[offs1+2] = batch4buf->ptr.p_double[offs1+2]+v*v2; + batch4buf->ptr.p_double[offs1+3] = batch4buf->ptr.p_double[offs1+3]+v*v3; + srcentryoffs = srcentryoffs+entrysize; + srcweightidx = srcweightidx+1; + } + continue; + } + if( neurontype<0 ) + { + bflag = ae_false; + if( (neurontype==-2||neurontype==-3)||neurontype==-4 ) + { + + /* + * Special neuron type, no back-propagation required + */ + bflag = ae_true; + } + ae_assert(bflag, "MLPInternalCalculateGradient: unknown neuron type!", _state); + continue; + } + } +} + + +static void mlpbase_mlpchunkedprocess(const multilayerperceptron* network, + /* Real */ ae_matrix* xy, + ae_int_t cstart, + ae_int_t csize, + /* Real */ ae_vector* batch4buf, + /* Real */ ae_vector* hpcbuf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ntotal; + ae_int_t nin; + ae_int_t nout; + ae_int_t offs; + double f; + double df; + double d2f; + double v; + ae_bool bflag; + ae_int_t istart; + ae_int_t entrysize; + ae_int_t entryoffs; + ae_int_t neuronidx; + ae_int_t srcentryoffs; + ae_int_t srcneuronidx; + ae_int_t srcweightidx; + ae_int_t neurontype; + ae_int_t nweights; + ae_int_t offs0; + double v0; + double v1; + double v2; + double v3; + double s0; + double s1; + double s2; + double s3; + ae_int_t chunksize; + + + chunksize = 4; + ae_assert(csize<=chunksize, "MLPChunkedProcess: internal error (CSize>ChunkSize)", _state); + + /* + * Try to use HPC core, if possible + */ + if( hpcchunkedprocess(&network->weights, &network->structinfo, &network->columnmeans, &network->columnsigmas, xy, cstart, csize, batch4buf, hpcbuf, _state) ) + { + return; + } + + /* + * Read network geometry, prepare data + */ + nin = network->structinfo.ptr.p_int[1]; + nout = network->structinfo.ptr.p_int[2]; + ntotal = network->structinfo.ptr.p_int[3]; + istart = network->structinfo.ptr.p_int[5]; + entrysize = 4; + + /* + * Fill Batch4Buf by zeros. + * + * THIS STAGE IS VERY IMPORTANT! + * + * We fill all components of entry - neuron values, dF/dNET, dError/dF. + * It allows us to easily handle situations when CSizeptr.p_double[i] = (double)(0); + } + + /* + * Forward pass: + * 1. Load data into Batch4Buf. If CSizecolumnsigmas.ptr.p_double[i],(double)(0)) ) + { + batch4buf->ptr.p_double[entryoffs+j] = (xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i])/network->columnsigmas.ptr.p_double[i]; + } + else + { + batch4buf->ptr.p_double[entryoffs+j] = xy->ptr.pp_double[cstart+j][i]-network->columnmeans.ptr.p_double[i]; + } + } + } + for(neuronidx=0; neuronidx<=ntotal-1; neuronidx++) + { + entryoffs = entrysize*neuronidx; + offs = istart+neuronidx*mlpbase_nfieldwidth; + neurontype = network->structinfo.ptr.p_int[offs+0]; + if( neurontype>0||neurontype==-5 ) + { + + /* + * "activation function" neuron, which takes value of neuron SrcNeuronIdx + * and applies activation function to it. + * + * This neuron has no weights and no tunable parameters. + */ + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+0], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+0] = f; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+1], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+1] = f; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+2], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+2] = f; + mlpactivationfunction(batch4buf->ptr.p_double[srcentryoffs+3], neurontype, &f, &df, &d2f, _state); + batch4buf->ptr.p_double[entryoffs+3] = f; + continue; + } + if( neurontype==0 ) + { + + /* + * "adaptive summator" neuron, whose output is a weighted sum of inputs. + * It has weights, but has no activation function. + */ + nweights = network->structinfo.ptr.p_int[offs+1]; + srcneuronidx = network->structinfo.ptr.p_int[offs+2]; + srcentryoffs = entrysize*srcneuronidx; + srcweightidx = network->structinfo.ptr.p_int[offs+3]; + v0 = (double)(0); + v1 = (double)(0); + v2 = (double)(0); + v3 = (double)(0); + for(j=0; j<=nweights-1; j++) + { + v = network->weights.ptr.p_double[srcweightidx]; + srcweightidx = srcweightidx+1; + v0 = v0+v*batch4buf->ptr.p_double[srcentryoffs+0]; + v1 = v1+v*batch4buf->ptr.p_double[srcentryoffs+1]; + v2 = v2+v*batch4buf->ptr.p_double[srcentryoffs+2]; + v3 = v3+v*batch4buf->ptr.p_double[srcentryoffs+3]; + srcentryoffs = srcentryoffs+entrysize; + } + batch4buf->ptr.p_double[entryoffs+0] = v0; + batch4buf->ptr.p_double[entryoffs+1] = v1; + batch4buf->ptr.p_double[entryoffs+2] = v2; + batch4buf->ptr.p_double[entryoffs+3] = v3; + continue; + } + if( neurontype<0 ) + { + bflag = ae_false; + if( neurontype==-2 ) + { + + /* + * Input neuron, left unchanged + */ + bflag = ae_true; + } + if( neurontype==-3 ) + { + + /* + * "-1" neuron + */ + batch4buf->ptr.p_double[entryoffs+0] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+1] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+2] = (double)(-1); + batch4buf->ptr.p_double[entryoffs+3] = (double)(-1); + bflag = ae_true; + } + if( neurontype==-4 ) + { + + /* + * "0" neuron + */ + batch4buf->ptr.p_double[entryoffs+0] = (double)(0); + batch4buf->ptr.p_double[entryoffs+1] = (double)(0); + batch4buf->ptr.p_double[entryoffs+2] = (double)(0); + batch4buf->ptr.p_double[entryoffs+3] = (double)(0); + bflag = ae_true; + } + ae_assert(bflag, "MLPChunkedProcess: internal error - unknown neuron type!", _state); + continue; + } + } + + /* + * SOFTMAX normalization or scaling. + */ + ae_assert(network->structinfo.ptr.p_int[6]==0||network->structinfo.ptr.p_int[6]==1, "MLPChunkedProcess: unknown normalization type!", _state); + if( network->structinfo.ptr.p_int[6]==1 ) + { + + /* + * SOFTMAX-normalized network. + * + * First, calculate (V0,V1,V2,V3) - component-wise maximum + * of output neurons. This vector of maximum values will be + * used for normalization of outputs prior to calculating + * exponentials. + * + * NOTE: the only purpose of this stage is to prevent overflow + * during calculation of exponentials. With this stage + * we make sure that all exponentials are calculated + * with non-positive argument. If you load (0,0,0,0) to + * (V0,V1,V2,V3), your program will continue working - + * although with less robustness. + */ + entryoffs = entrysize*(ntotal-nout); + v0 = batch4buf->ptr.p_double[entryoffs+0]; + v1 = batch4buf->ptr.p_double[entryoffs+1]; + v2 = batch4buf->ptr.p_double[entryoffs+2]; + v3 = batch4buf->ptr.p_double[entryoffs+3]; + entryoffs = entryoffs+entrysize; + for(i=1; i<=nout-1; i++) + { + v = batch4buf->ptr.p_double[entryoffs+0]; + if( v>v0 ) + { + v0 = v; + } + v = batch4buf->ptr.p_double[entryoffs+1]; + if( v>v1 ) + { + v1 = v; + } + v = batch4buf->ptr.p_double[entryoffs+2]; + if( v>v2 ) + { + v2 = v; + } + v = batch4buf->ptr.p_double[entryoffs+3]; + if( v>v3 ) + { + v3 = v; + } + entryoffs = entryoffs+entrysize; + } + + /* + * Then, calculate exponentials and place them to part of the + * array which is located past the last entry. We also + * calculate sum of exponentials. + */ + entryoffs = entrysize*(ntotal-nout); + offs0 = entrysize*ntotal; + s0 = (double)(0); + s1 = (double)(0); + s2 = (double)(0); + s3 = (double)(0); + for(i=0; i<=nout-1; i++) + { + v = ae_exp(batch4buf->ptr.p_double[entryoffs+0]-v0, _state); + s0 = s0+v; + batch4buf->ptr.p_double[offs0+0] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+1]-v1, _state); + s1 = s1+v; + batch4buf->ptr.p_double[offs0+1] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+2]-v2, _state); + s2 = s2+v; + batch4buf->ptr.p_double[offs0+2] = v; + v = ae_exp(batch4buf->ptr.p_double[entryoffs+3]-v3, _state); + s3 = s3+v; + batch4buf->ptr.p_double[offs0+3] = v; + entryoffs = entryoffs+entrysize; + offs0 = offs0+chunksize; + } + + /* + * Write SOFTMAX-normalized values to the output array. + */ + offs0 = entrysize*ntotal; + for(i=0; i<=nout-1; i++) + { + if( csize>0 ) + { + xy->ptr.pp_double[cstart+0][nin+i] = batch4buf->ptr.p_double[offs0+0]/s0; + } + if( csize>1 ) + { + xy->ptr.pp_double[cstart+1][nin+i] = batch4buf->ptr.p_double[offs0+1]/s1; + } + if( csize>2 ) + { + xy->ptr.pp_double[cstart+2][nin+i] = batch4buf->ptr.p_double[offs0+2]/s2; + } + if( csize>3 ) + { + xy->ptr.pp_double[cstart+3][nin+i] = batch4buf->ptr.p_double[offs0+3]/s3; + } + offs0 = offs0+chunksize; + } + } + else + { + + /* + * Regression network with sum-of-squares function. + * + * For each NOut of last neurons: + * * calculate difference between actual and desired output + * * calculate dError/dOut for this neuron (proportional to difference) + * * store in in last 4 components of entry (these values are used + * to start backpropagation) + * * update error + */ + for(i=0; i<=nout-1; i++) + { + v0 = network->columnsigmas.ptr.p_double[nin+i]; + v1 = network->columnmeans.ptr.p_double[nin+i]; + entryoffs = entrysize*(ntotal-nout+i); + for(j=0; j<=csize-1; j++) + { + xy->ptr.pp_double[cstart+j][nin+i] = batch4buf->ptr.p_double[entryoffs+j]*v0+v1; + } + } + } +} + + +/************************************************************************* +Returns T*Ln(T/Z), guarded against overflow/underflow. +Internal subroutine. +*************************************************************************/ +static double mlpbase_safecrossentropy(double t, + double z, + ae_state *_state) +{ + double r; + double result; + + + if( ae_fp_eq(t,(double)(0)) ) + { + result = (double)(0); + } + else + { + if( ae_fp_greater(ae_fabs(z, _state),(double)(1)) ) + { + + /* + * Shouldn't be the case with softmax, + * but we just want to be sure. + */ + if( ae_fp_eq(t/z,(double)(0)) ) + { + r = ae_minrealnumber; + } + else + { + r = t/z; + } + } + else + { + + /* + * Normal case + */ + if( ae_fp_eq(z,(double)(0))||ae_fp_greater_eq(ae_fabs(t, _state),ae_maxrealnumber*ae_fabs(z, _state)) ) + { + r = ae_maxrealnumber; + } + else + { + r = t/z; + } + } + result = t*ae_log(r, _state); + } + return result; +} + + +/************************************************************************* +This function performs backward pass of neural network randimization: +* it assumes that Network.Weights stores standard deviation of weights + (weights are not generated yet, only their deviations are present) +* it sets deviations of weights which feed NeuronIdx-th neuron to specified value +* it recursively passes to deeper neuron and modifies their weights +* it stops after encountering nonlinear neurons, linear activation function, + input neurons, "0" and "-1" neurons + + -- ALGLIB -- + Copyright 27.06.2013 by Bochkanov Sergey +*************************************************************************/ +static void mlpbase_randomizebackwardpass(multilayerperceptron* network, + ae_int_t neuronidx, + double v, + ae_state *_state) +{ + ae_int_t istart; + ae_int_t neurontype; + ae_int_t n1; + ae_int_t n2; + ae_int_t w1; + ae_int_t w2; + ae_int_t offs; + ae_int_t i; + + + istart = network->structinfo.ptr.p_int[5]; + neurontype = network->structinfo.ptr.p_int[istart+neuronidx*mlpbase_nfieldwidth+0]; + if( neurontype==-2 ) + { + + /* + * Input neuron - stop + */ + return; + } + if( neurontype==-3 ) + { + + /* + * "-1" neuron: stop + */ + return; + } + if( neurontype==-4 ) + { + + /* + * "0" neuron: stop + */ + return; + } + if( neurontype==0 ) + { + + /* + * Adaptive summator neuron: + * * modify deviations of its weights + * * recursively call this function for its inputs + */ + offs = istart+neuronidx*mlpbase_nfieldwidth; + n1 = network->structinfo.ptr.p_int[offs+2]; + n2 = n1+network->structinfo.ptr.p_int[offs+1]-1; + w1 = network->structinfo.ptr.p_int[offs+3]; + w2 = w1+network->structinfo.ptr.p_int[offs+1]-1; + for(i=w1; i<=w2; i++) + { + network->weights.ptr.p_double[i] = v; + } + for(i=n1; i<=n2; i++) + { + mlpbase_randomizebackwardpass(network, i, v, _state); + } + return; + } + if( neurontype==-5 ) + { + + /* + * Linear activation function: stop + */ + return; + } + if( neurontype>0 ) + { + + /* + * Nonlinear activation function: stop + */ + return; + } + ae_assert(ae_false, "RandomizeBackwardPass: unexpected neuron type", _state); +} + + +void _modelerrors_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + modelerrors *p = (modelerrors*)_p; + ae_touch_ptr((void*)p); +} + + +void _modelerrors_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + modelerrors *dst = (modelerrors*)_dst; + const modelerrors *src = (const modelerrors*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; +} + + +void _modelerrors_clear(void* _p) +{ + modelerrors *p = (modelerrors*)_p; + ae_touch_ptr((void*)p); +} + + +void _modelerrors_destroy(void* _p) +{ + modelerrors *p = (modelerrors*)_p; + ae_touch_ptr((void*)p); +} + + +void _smlpgrad_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + smlpgrad *p = (smlpgrad*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); +} + + +void _smlpgrad_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + smlpgrad *dst = (smlpgrad*)_dst; + const smlpgrad *src = (const smlpgrad*)_src; + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); +} + + +void _smlpgrad_clear(void* _p) +{ + smlpgrad *p = (smlpgrad*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->g); +} + + +void _smlpgrad_destroy(void* _p) +{ + smlpgrad *p = (smlpgrad*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->g); +} + + +void _multilayerperceptron_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + multilayerperceptron *p = (multilayerperceptron*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->hllayersizes, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->hlconnections, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->hlneurons, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->structinfo, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->weights, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->columnmeans, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->neurons, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dfdnet, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->derror, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nwbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->integerbuf, 0, DT_INT, _state, make_automatic); + _modelerrors_init(&p->err, _state, make_automatic); + ae_vector_init(&p->rndbuf, 0, DT_REAL, _state, make_automatic); + ae_shared_pool_init(&p->buf, _state, make_automatic); + ae_shared_pool_init(&p->gradbuf, _state, make_automatic); + ae_matrix_init(&p->dummydxy, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->dummysxy, _state, make_automatic); + ae_vector_init(&p->dummyidx, 0, DT_INT, _state, make_automatic); + ae_shared_pool_init(&p->dummypool, _state, make_automatic); +} + + +void _multilayerperceptron_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + multilayerperceptron *dst = (multilayerperceptron*)_dst; + const multilayerperceptron *src = (const multilayerperceptron*)_src; + dst->hlnetworktype = src->hlnetworktype; + dst->hlnormtype = src->hlnormtype; + ae_vector_init_copy(&dst->hllayersizes, &src->hllayersizes, _state, make_automatic); + ae_vector_init_copy(&dst->hlconnections, &src->hlconnections, _state, make_automatic); + ae_vector_init_copy(&dst->hlneurons, &src->hlneurons, _state, make_automatic); + ae_vector_init_copy(&dst->structinfo, &src->structinfo, _state, make_automatic); + ae_vector_init_copy(&dst->weights, &src->weights, _state, make_automatic); + ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state, make_automatic); + ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state, make_automatic); + ae_vector_init_copy(&dst->neurons, &src->neurons, _state, make_automatic); + ae_vector_init_copy(&dst->dfdnet, &src->dfdnet, _state, make_automatic); + ae_vector_init_copy(&dst->derror, &src->derror, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic); + ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic); + ae_vector_init_copy(&dst->nwbuf, &src->nwbuf, _state, make_automatic); + ae_vector_init_copy(&dst->integerbuf, &src->integerbuf, _state, make_automatic); + _modelerrors_init_copy(&dst->err, &src->err, _state, make_automatic); + ae_vector_init_copy(&dst->rndbuf, &src->rndbuf, _state, make_automatic); + ae_shared_pool_init_copy(&dst->buf, &src->buf, _state, make_automatic); + ae_shared_pool_init_copy(&dst->gradbuf, &src->gradbuf, _state, make_automatic); + ae_matrix_init_copy(&dst->dummydxy, &src->dummydxy, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysxy, &src->dummysxy, _state, make_automatic); + ae_vector_init_copy(&dst->dummyidx, &src->dummyidx, _state, make_automatic); + ae_shared_pool_init_copy(&dst->dummypool, &src->dummypool, _state, make_automatic); +} + + +void _multilayerperceptron_clear(void* _p) +{ + multilayerperceptron *p = (multilayerperceptron*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->hllayersizes); + ae_vector_clear(&p->hlconnections); + ae_vector_clear(&p->hlneurons); + ae_vector_clear(&p->structinfo); + ae_vector_clear(&p->weights); + ae_vector_clear(&p->columnmeans); + ae_vector_clear(&p->columnsigmas); + ae_vector_clear(&p->neurons); + ae_vector_clear(&p->dfdnet); + ae_vector_clear(&p->derror); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_matrix_clear(&p->xy); + ae_vector_clear(&p->xyrow); + ae_vector_clear(&p->nwbuf); + ae_vector_clear(&p->integerbuf); + _modelerrors_clear(&p->err); + ae_vector_clear(&p->rndbuf); + ae_shared_pool_clear(&p->buf); + ae_shared_pool_clear(&p->gradbuf); + ae_matrix_clear(&p->dummydxy); + _sparsematrix_clear(&p->dummysxy); + ae_vector_clear(&p->dummyidx); + ae_shared_pool_clear(&p->dummypool); +} + + +void _multilayerperceptron_destroy(void* _p) +{ + multilayerperceptron *p = (multilayerperceptron*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->hllayersizes); + ae_vector_destroy(&p->hlconnections); + ae_vector_destroy(&p->hlneurons); + ae_vector_destroy(&p->structinfo); + ae_vector_destroy(&p->weights); + ae_vector_destroy(&p->columnmeans); + ae_vector_destroy(&p->columnsigmas); + ae_vector_destroy(&p->neurons); + ae_vector_destroy(&p->dfdnet); + ae_vector_destroy(&p->derror); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_matrix_destroy(&p->xy); + ae_vector_destroy(&p->xyrow); + ae_vector_destroy(&p->nwbuf); + ae_vector_destroy(&p->integerbuf); + _modelerrors_destroy(&p->err); + ae_vector_destroy(&p->rndbuf); + ae_shared_pool_destroy(&p->buf); + ae_shared_pool_destroy(&p->gradbuf); + ae_matrix_destroy(&p->dummydxy); + _sparsematrix_destroy(&p->dummysxy); + ae_vector_destroy(&p->dummyidx); + ae_shared_pool_destroy(&p->dummypool); +} + + +#endif +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Like MLPCreate0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate0(ae_int_t nin, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreate0(nin, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreate1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreate1(nin, nhid, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreate2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreate2(nin, nhid1, nhid2, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateB0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb0(ae_int_t nin, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreateb0(nin, nout, b, d, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateB1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreateb1(nin, nhid, nout, b, d, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateB2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreateb2(nin, nhid1, nhid2, nout, b, d, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateR0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater0(ae_int_t nin, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreater0(nin, nout, a, b, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateR1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreater1(nin, nhid, nout, a, b, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateR2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreater2(nin, nhid1, nhid2, nout, a, b, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateC0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec0(ae_int_t nin, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreatec0(nin, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateC1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreatec1(nin, nhid, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Like MLPCreateC2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_frame _frame_block; + multilayerperceptron net; + + ae_frame_make(_state, &_frame_block); + memset(&net, 0, sizeof(net)); + _mlpensemble_clear(ensemble); + _multilayerperceptron_init(&net, _state, ae_true); + + mlpcreatec2(nin, nhid1, nhid2, nout, &net, _state); + mlpecreatefromnetwork(&net, ensemblesize, ensemble, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Creates ensemble from network. Only network geometry is copied. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatefromnetwork(const multilayerperceptron* network, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ccount; + ae_int_t wcount; + + _mlpensemble_clear(ensemble); + + ae_assert(ensemblesize>0, "MLPECreate: incorrect ensemble size!", _state); + + /* + * Copy network + */ + mlpcopy(network, &ensemble->network, _state); + + /* + * network properties + */ + if( mlpissoftmax(network, _state) ) + { + ccount = mlpgetinputscount(&ensemble->network, _state); + } + else + { + ccount = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); + } + wcount = mlpgetweightscount(&ensemble->network, _state); + ensemble->ensemblesize = ensemblesize; + + /* + * weights, means, sigmas + */ + ae_vector_set_length(&ensemble->weights, ensemblesize*wcount, _state); + ae_vector_set_length(&ensemble->columnmeans, ensemblesize*ccount, _state); + ae_vector_set_length(&ensemble->columnsigmas, ensemblesize*ccount, _state); + for(i=0; i<=ensemblesize*wcount-1; i++) + { + ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; + } + for(i=0; i<=ensemblesize-1; i++) + { + ae_v_move(&ensemble->columnmeans.ptr.p_double[i*ccount], 1, &network->columnmeans.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); + ae_v_move(&ensemble->columnsigmas.ptr.p_double[i*ccount], 1, &network->columnsigmas.ptr.p_double[0], 1, ae_v_len(i*ccount,(i+1)*ccount-1)); + } + + /* + * temporaries, internal buffers + */ + ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); +} + + +/************************************************************************* +Copying of MLPEnsemble strucure + +INPUT PARAMETERS: + Ensemble1 - original + +OUTPUT PARAMETERS: + Ensemble2 - copy + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecopy(const mlpensemble* ensemble1, + mlpensemble* ensemble2, + ae_state *_state) +{ + ae_int_t ccount; + ae_int_t wcount; + + _mlpensemble_clear(ensemble2); + + + /* + * Unload info + */ + if( mlpissoftmax(&ensemble1->network, _state) ) + { + ccount = mlpgetinputscount(&ensemble1->network, _state); + } + else + { + ccount = mlpgetinputscount(&ensemble1->network, _state)+mlpgetoutputscount(&ensemble1->network, _state); + } + wcount = mlpgetweightscount(&ensemble1->network, _state); + + /* + * Allocate space + */ + ae_vector_set_length(&ensemble2->weights, ensemble1->ensemblesize*wcount, _state); + ae_vector_set_length(&ensemble2->columnmeans, ensemble1->ensemblesize*ccount, _state); + ae_vector_set_length(&ensemble2->columnsigmas, ensemble1->ensemblesize*ccount, _state); + ae_vector_set_length(&ensemble2->y, mlpgetoutputscount(&ensemble1->network, _state), _state); + + /* + * Copy + */ + ensemble2->ensemblesize = ensemble1->ensemblesize; + ae_v_move(&ensemble2->weights.ptr.p_double[0], 1, &ensemble1->weights.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*wcount-1)); + ae_v_move(&ensemble2->columnmeans.ptr.p_double[0], 1, &ensemble1->columnmeans.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); + ae_v_move(&ensemble2->columnsigmas.ptr.p_double[0], 1, &ensemble1->columnsigmas.ptr.p_double[0], 1, ae_v_len(0,ensemble1->ensemblesize*ccount-1)); + mlpcopy(&ensemble1->network, &ensemble2->network, _state); +} + + +/************************************************************************* +Randomization of MLP ensemble + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlperandomize(mlpensemble* ensemble, ae_state *_state) +{ + ae_int_t i; + ae_int_t wcount; + + + wcount = mlpgetweightscount(&ensemble->network, _state); + for(i=0; i<=ensemble->ensemblesize*wcount-1; i++) + { + ensemble->weights.ptr.p_double[i] = ae_randomreal(_state)-0.5; + } +} + + +/************************************************************************* +Return ensemble properties (number of inputs and outputs). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeproperties(const mlpensemble* ensemble, + ae_int_t* nin, + ae_int_t* nout, + ae_state *_state) +{ + + *nin = 0; + *nout = 0; + + *nin = mlpgetinputscount(&ensemble->network, _state); + *nout = mlpgetoutputscount(&ensemble->network, _state); +} + + +/************************************************************************* +Return normalization type (whether ensemble is SOFTMAX-normalized or not). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool mlpeissoftmax(const mlpensemble* ensemble, ae_state *_state) +{ + ae_bool result; + + + result = mlpissoftmax(&ensemble->network, _state); + return result; +} + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Ensemble- neural networks ensemble + X - input vector, array[0..NIn-1]. + Y - (possibly) preallocated buffer; if size of Y is less than + NOut, it will be reallocated. If it is large enough, it + is NOT reallocated, so we can save some time on reallocation. + + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocess(mlpensemble* ensemble, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t es; + ae_int_t wc; + ae_int_t cc; + double v; + ae_int_t nout; + + + if( y->cntnetwork, _state) ) + { + ae_vector_set_length(y, mlpgetoutputscount(&ensemble->network, _state), _state); + } + es = ensemble->ensemblesize; + wc = mlpgetweightscount(&ensemble->network, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + cc = mlpgetinputscount(&ensemble->network, _state); + } + else + { + cc = mlpgetinputscount(&ensemble->network, _state)+mlpgetoutputscount(&ensemble->network, _state); + } + v = (double)1/(double)es; + nout = mlpgetoutputscount(&ensemble->network, _state); + for(i=0; i<=nout-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=es-1; i++) + { + ae_v_move(&ensemble->network.weights.ptr.p_double[0], 1, &ensemble->weights.ptr.p_double[i*wc], 1, ae_v_len(0,wc-1)); + ae_v_move(&ensemble->network.columnmeans.ptr.p_double[0], 1, &ensemble->columnmeans.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); + ae_v_move(&ensemble->network.columnsigmas.ptr.p_double[0], 1, &ensemble->columnsigmas.ptr.p_double[i*cc], 1, ae_v_len(0,cc-1)); + mlpprocess(&ensemble->network, x, &ensemble->y, _state); + ae_v_addd(&y->ptr.p_double[0], 1, &ensemble->y.ptr.p_double[0], 1, ae_v_len(0,nout-1), v); + } +} + + +/************************************************************************* +'interactive' variant of MLPEProcess for languages like Python which +support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocessi(mlpensemble* ensemble, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + mlpeprocess(ensemble, x, y, _state); +} + + +/************************************************************************* +Calculation of all types of errors + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeallerrorsx(mlpensemble* ensemble, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t nin; + ae_int_t nout; + ae_bool iscls; + ae_int_t srcidx; + mlpbuffers *pbuf; + ae_smart_ptr _pbuf; + modelerrors rep0; + modelerrors rep1; + + ae_frame_make(_state, &_frame_block); + memset(&_pbuf, 0, sizeof(_pbuf)); + memset(&rep0, 0, sizeof(rep0)); + memset(&rep1, 0, sizeof(rep1)); + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + _modelerrors_init(&rep0, _state, ae_true); + _modelerrors_init(&rep1, _state, ae_true); + + + /* + * Get network information + */ + nin = mlpgetinputscount(&ensemble->network, _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + iscls = mlpissoftmax(&ensemble->network, _state); + + /* + * Retrieve buffer, prepare, process data, recycle buffer + */ + ae_shared_pool_retrieve(buf, &_pbuf, _state); + if( iscls ) + { + dserrallocate(nout, &pbuf->tmp0, _state); + } + else + { + dserrallocate(-nout, &pbuf->tmp0, _state); + } + rvectorsetlengthatleast(&pbuf->x, nin, _state); + rvectorsetlengthatleast(&pbuf->y, nout, _state); + rvectorsetlengthatleast(&pbuf->desiredy, nout, _state); + for(i=subset0; i<=subset1-1; i++) + { + srcidx = -1; + if( subsettype==0 ) + { + srcidx = i; + } + if( subsettype==1 ) + { + srcidx = idx->ptr.p_int[i]; + } + ae_assert(srcidx>=0, "MLPEAllErrorsX: internal error", _state); + if( datasettype==0 ) + { + ae_v_move(&pbuf->x.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][0], 1, ae_v_len(0,nin-1)); + } + if( datasettype==1 ) + { + sparsegetrow(sparsexy, srcidx, &pbuf->x, _state); + } + mlpeprocess(ensemble, &pbuf->x, &pbuf->y, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + if( datasettype==0 ) + { + pbuf->desiredy.ptr.p_double[0] = densexy->ptr.pp_double[srcidx][nin]; + } + if( datasettype==1 ) + { + pbuf->desiredy.ptr.p_double[0] = sparseget(sparsexy, srcidx, nin, _state); + } + } + else + { + if( datasettype==0 ) + { + ae_v_move(&pbuf->desiredy.ptr.p_double[0], 1, &densexy->ptr.pp_double[srcidx][nin], 1, ae_v_len(0,nout-1)); + } + if( datasettype==1 ) + { + for(j=0; j<=nout-1; j++) + { + pbuf->desiredy.ptr.p_double[j] = sparseget(sparsexy, srcidx, nin+j, _state); + } + } + } + dserraccumulate(&pbuf->tmp0, &pbuf->y, &pbuf->desiredy, _state); + } + dserrfinish(&pbuf->tmp0, _state); + rep->relclserror = pbuf->tmp0.ptr.p_double[0]; + rep->avgce = pbuf->tmp0.ptr.p_double[1]/ae_log((double)(2), _state); + rep->rmserror = pbuf->tmp0.ptr.p_double[2]; + rep->avgerror = pbuf->tmp0.ptr.p_double[3]; + rep->avgrelerror = pbuf->tmp0.ptr.p_double[4]; + ae_shared_pool_recycle(buf, &_pbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Calculation of all types of errors on dataset given by sparse matrix + + -- ALGLIB -- + Copyright 10.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpeallerrorssparse(mlpensemble* ensemble, + const sparsematrix* xy, + ae_int_t npoints, + double* relcls, + double* avgce, + double* rms, + double* avg, + double* avgrel, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector buf; + ae_vector workx; + ae_vector y; + ae_vector dy; + ae_int_t nin; + ae_int_t nout; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&workx, 0, sizeof(workx)); + memset(&y, 0, sizeof(y)); + memset(&dy, 0, sizeof(dy)); + *relcls = 0.0; + *avgce = 0.0; + *rms = 0.0; + *avg = 0.0; + *avgrel = 0.0; + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); + + nin = mlpgetinputscount(&ensemble->network, _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + ae_vector_set_length(&dy, 1, _state); + dserrallocate(nout, &buf, _state); + } + else + { + ae_vector_set_length(&dy, nout, _state); + dserrallocate(-nout, &buf, _state); + } + for(i=0; i<=npoints-1; i++) + { + sparsegetrow(xy, i, &workx, _state); + mlpeprocess(ensemble, &workx, &y, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + dy.ptr.p_double[0] = workx.ptr.p_double[nin]; + } + else + { + ae_v_move(&dy.ptr.p_double[0], 1, &workx.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); + } + dserraccumulate(&buf, &y, &dy, _state); + } + dserrfinish(&buf, _state); + *relcls = buf.ptr.p_double[0]; + *avgce = buf.ptr.p_double[1]; + *rms = buf.ptr.p_double[2]; + *avg = buf.ptr.p_double[3]; + *avgrel = buf.ptr.p_double[4]; + ae_frame_leave(_state); +} + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Works both for classifier betwork and for regression networks which +are used as classifiers. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlperelclserror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _modelerrors_init(&rep, _state, ae_true); + + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); + result = rep.relclserror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if ensemble solves regression task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgce(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _modelerrors_init(&rep, _state, ae_true); + + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); + result = rep.avgce; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for classification task +RMS error means error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpermserror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _modelerrors_init(&rep, _state, ae_true); + + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); + result = rep.rmserror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgerror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _modelerrors_init(&rep, _state, ae_true); + + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); + result = rep.avgerror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average relative error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgrelerror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _modelerrors_init(&rep, _state, ae_true); + + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &rep, _state); + result = rep.avgrelerror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpealloc(ae_serializer* s, + const mlpensemble* ensemble, + ae_state *_state) +{ + + + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &ensemble->weights, -1, _state); + allocrealarray(s, &ensemble->columnmeans, -1, _state); + allocrealarray(s, &ensemble->columnsigmas, -1, _state); + mlpalloc(s, &ensemble->network, _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpeserialize(ae_serializer* s, + const mlpensemble* ensemble, + ae_state *_state) +{ + + + ae_serializer_serialize_int(s, getmlpeserializationcode(_state), _state); + ae_serializer_serialize_int(s, mlpe_mlpefirstversion, _state); + ae_serializer_serialize_int(s, ensemble->ensemblesize, _state); + serializerealarray(s, &ensemble->weights, -1, _state); + serializerealarray(s, &ensemble->columnmeans, -1, _state); + serializerealarray(s, &ensemble->columnsigmas, -1, _state); + mlpserialize(s, &ensemble->network, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpeunserialize(ae_serializer* s, + mlpensemble* ensemble, + ae_state *_state) +{ + ae_int_t i0; + ae_int_t i1; + + _mlpensemble_clear(ensemble); + + + /* + * check correctness of header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getmlpeserializationcode(_state), "MLPEUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_assert(i1==mlpe_mlpefirstversion, "MLPEUnserialize: stream header corrupted", _state); + + /* + * Create network + */ + ae_serializer_unserialize_int(s, &ensemble->ensemblesize, _state); + unserializerealarray(s, &ensemble->weights, _state); + unserializerealarray(s, &ensemble->columnmeans, _state); + unserializerealarray(s, &ensemble->columnsigmas, _state); + mlpunserialize(s, &ensemble->network, _state); + + /* + * Allocate termoraries + */ + ae_vector_set_length(&ensemble->y, mlpgetoutputscount(&ensemble->network, _state), _state); +} + + +void _mlpensemble_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpensemble *p = (mlpensemble*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->weights, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->columnmeans, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->columnsigmas, 0, DT_REAL, _state, make_automatic); + _multilayerperceptron_init(&p->network, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); +} + + +void _mlpensemble_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpensemble *dst = (mlpensemble*)_dst; + const mlpensemble *src = (const mlpensemble*)_src; + dst->ensemblesize = src->ensemblesize; + ae_vector_init_copy(&dst->weights, &src->weights, _state, make_automatic); + ae_vector_init_copy(&dst->columnmeans, &src->columnmeans, _state, make_automatic); + ae_vector_init_copy(&dst->columnsigmas, &src->columnsigmas, _state, make_automatic); + _multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); +} + + +void _mlpensemble_clear(void* _p) +{ + mlpensemble *p = (mlpensemble*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->weights); + ae_vector_clear(&p->columnmeans); + ae_vector_clear(&p->columnsigmas); + _multilayerperceptron_clear(&p->network); + ae_vector_clear(&p->y); +} + + +void _mlpensemble_destroy(void* _p) +{ + mlpensemble *p = (mlpensemble*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->weights); + ae_vector_destroy(&p->columnmeans); + ae_vector_destroy(&p->columnsigmas); + _multilayerperceptron_destroy(&p->network); + ae_vector_destroy(&p->y); +} + + +#endif +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes clusterizer object. Newly initialized object is +empty, i.e. it does not contain dataset. You should use it as follows: +1. creation +2. dataset is added with ClusterizerSetPoints() +3. additional parameters are set +3. clusterization is performed with one of the clustering functions + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizercreate(clusterizerstate* s, ae_state *_state) +{ + + _clusterizerstate_clear(s); + + s->npoints = 0; + s->nfeatures = 0; + s->disttype = 2; + s->ahcalgo = 0; + s->kmeansrestarts = 1; + s->kmeansmaxits = 0; + s->kmeansinitalgo = 0; + s->kmeansdbgnoits = ae_false; + s->seed = 1; + kmeansinitbuf(&s->kmeanstmp, _state); +} + + +/************************************************************************* +This function adds dataset to the clusterizer structure. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm), non-squared + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +NOTE 1: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + +NOTE 2: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric + * k-means++ clustering algorithm may be used only with Euclidean + distance function + Thus, list of specific clustering algorithms you may use depends + on distance function you specify when you set your dataset. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetpoints(clusterizerstate* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_int_t disttype, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerSetPoints: incorrect DistType", _state); + ae_assert(npoints>=0, "ClusterizerSetPoints: NPoints<0", _state); + ae_assert(nfeatures>=1, "ClusterizerSetPoints: NFeatures<1", _state); + ae_assert(xy->rows>=npoints, "ClusterizerSetPoints: Rows(XY)cols>=nfeatures, "ClusterizerSetPoints: Cols(XY)npoints = npoints; + s->nfeatures = nfeatures; + s->disttype = disttype; + rmatrixsetlengthatleast(&s->xy, npoints, nfeatures, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&s->xy.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); + } +} + + +/************************************************************************* +This function adds dataset given by distance matrix to the clusterizer +structure. It is important that dataset is not given explicitly - only +distance matrix is given. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + D - array[NPoints,NPoints], distance matrix given by its upper + or lower triangle (main diagonal is ignored because its + entries are expected to be zero). + NPoints - number of points + IsUpper - whether upper or lower triangle of D is given. + +NOTE 1: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric, including one which is given by + distance matrix + * k-means++ clustering algorithm may be used only with Euclidean + distance function and explicitly given points - it can not be + used with dataset given by distance matrix + Thus, if you call this function, you will be unable to use k-means + clustering algorithm to process your problem. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetdistances(clusterizerstate* s, + /* Real */ const ae_matrix* d, + ae_int_t npoints, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + + + ae_assert(npoints>=0, "ClusterizerSetDistances: NPoints<0", _state); + ae_assert(d->rows>=npoints, "ClusterizerSetDistances: Rows(D)cols>=npoints, "ClusterizerSetDistances: Cols(D)npoints = npoints; + s->nfeatures = 0; + s->disttype = -1; + rmatrixsetlengthatleast(&s->d, npoints, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + if( isupper ) + { + j0 = i+1; + j1 = npoints-1; + } + else + { + j0 = 0; + j1 = i-1; + } + for(j=j0; j<=j1; j++) + { + ae_assert(ae_isfinite(d->ptr.pp_double[i][j], _state)&&ae_fp_greater_eq(d->ptr.pp_double[i][j],(double)(0)), "ClusterizerSetDistances: D contains infinite, NAN or negative elements", _state); + s->d.ptr.pp_double[i][j] = d->ptr.pp_double[i][j]; + s->d.ptr.pp_double[j][i] = d->ptr.pp_double[i][j]; + } + s->d.ptr.pp_double[i][i] = (double)(0); + } +} + + +/************************************************************************* +This function sets agglomerative hierarchical clustering algorithm + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Algo - algorithm type: + * 0 complete linkage (default algorithm) + * 1 single linkage + * 2 unweighted average linkage + * 3 weighted average linkage + * 4 Ward's method + +NOTE: Ward's method works correctly only with Euclidean distance, that's + why algorithm will return negative termination code (failure) for + any other distance type. + + It is possible, however, to use this method with user-supplied + distance matrix. It is your responsibility to pass one which was + calculated with Euclidean distance function. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetahcalgo(clusterizerstate* s, + ae_int_t algo, + ae_state *_state) +{ + + + ae_assert((((algo==0||algo==1)||algo==2)||algo==3)||algo==4, "ClusterizerSetHCAlgo: incorrect algorithm type", _state); + s->ahcalgo = algo; +} + + +/************************************************************************* +This function sets k-means properties: number of restarts and maximum +number of iterations per one run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Restarts- restarts count, >=1. + k-means++ algorithm performs several restarts and chooses + best set of centers (one with minimum squared distance). + MaxIts - maximum number of k-means iterations performed during one + run. >=0, zero value means that algorithm performs unlimited + number of iterations. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeanslimits(clusterizerstate* s, + ae_int_t restarts, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(restarts>=1, "ClusterizerSetKMeansLimits: Restarts<=0", _state); + ae_assert(maxits>=0, "ClusterizerSetKMeansLimits: MaxIts<0", _state); + s->kmeansrestarts = restarts; + s->kmeansmaxits = maxits; +} + + +/************************************************************************* +This function sets k-means initialization algorithm. Several different +algorithms can be chosen, including k-means++. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + InitAlgo- initialization algorithm: + * 0 automatic selection ( different versions of ALGLIB + may select different algorithms) + * 1 random initialization + * 2 k-means++ initialization (best quality of initial + centers, but long non-parallelizable initialization + phase with bad cache locality) + * 3 "fast-greedy" algorithm with efficient, easy to + parallelize initialization. Quality of initial centers + is somewhat worse than that of k-means++. This + algorithm is a default one in the current version of + ALGLIB. + *-1 "debug" algorithm which always selects first K rows + of dataset; this algorithm is used for debug purposes + only. Do not use it in the industrial code! + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeansinit(clusterizerstate* s, + ae_int_t initalgo, + ae_state *_state) +{ + + + ae_assert(initalgo>=-1&&initalgo<=3, "ClusterizerSetKMeansInit: InitAlgo is incorrect", _state); + s->kmeansinitalgo = initalgo; +} + + +/************************************************************************* +This function sets seed which is used to initialize internal RNG. By +default, deterministic seed is used - same for each run of clusterizer. If +you specify non-deterministic seed value, then some algorithms which +depend on random initialization (in current version: k-means) may return +slightly different results after each run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetseed(clusterizerstate* s, + ae_int_t seed, + ae_state *_state) +{ + + + s->seed = seed; +} + + +/************************************************************************* +This function performs agglomerative hierarchical clustering + +NOTE: Agglomerative hierarchical clustering algorithm has two phases: + distance matrix calculation and clustering itself. Only first phase + (distance matrix calculation) is accelerated by SIMD and SMP. Thus, + acceleration is significant only for medium or high-dimensional + problems. + + Although activating multithreading gives some speedup over single- + threaded execution, you should not expect nearly-linear scaling + with respect to cores count. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + +OUTPUT PARAMETERS: + Rep - clustering results; see description of AHCReport + structure for more information. + +NOTE 1: hierarchical clustering algorithms require large amounts of memory. + In particular, this implementation needs sizeof(double)*NPoints^2 + bytes, which are used to store distance matrix. In case we work + with user-supplied matrix, this amount is multiplied by 2 (we have + to store original matrix and to work with its copy). + + For example, problem with 10000 points would require 800M of RAM, + even when working in a 1-dimensional space. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunahc(clusterizerstate* s, + ahcreport* rep, + ae_state *_state) +{ + ae_int_t npoints; + ae_int_t nfeatures; + + _ahcreport_clear(rep); + + npoints = s->npoints; + nfeatures = s->nfeatures; + + /* + * Fill Rep.NPoints, quick exit when NPoints<=1 + */ + rep->npoints = npoints; + if( npoints==0 ) + { + ae_vector_set_length(&rep->p, 0, _state); + ae_matrix_set_length(&rep->z, 0, 0, _state); + ae_matrix_set_length(&rep->pz, 0, 0, _state); + ae_matrix_set_length(&rep->pm, 0, 0, _state); + ae_vector_set_length(&rep->mergedist, 0, _state); + rep->terminationtype = 1; + return; + } + if( npoints==1 ) + { + ae_vector_set_length(&rep->p, 1, _state); + ae_matrix_set_length(&rep->z, 0, 0, _state); + ae_matrix_set_length(&rep->pz, 0, 0, _state); + ae_matrix_set_length(&rep->pm, 0, 0, _state); + ae_vector_set_length(&rep->mergedist, 0, _state); + rep->p.ptr.p_int[0] = 0; + rep->terminationtype = 1; + return; + } + + /* + * More than one point + */ + if( s->disttype==-1 ) + { + + /* + * Run clusterizer with user-supplied distance matrix + */ + clustering_clusterizerrunahcinternal(s, &s->d, rep, _state); + return; + } + else + { + + /* + * Check combination of AHC algo and distance type + */ + if( s->ahcalgo==4&&s->disttype!=2 ) + { + rep->terminationtype = -5; + return; + } + + /* + * Build distance matrix D. + */ + clusterizergetdistancesbuf(&s->distbuf, &s->xy, npoints, nfeatures, s->disttype, &s->tmpd, _state); + + /* + * Run clusterizer + */ + clustering_clusterizerrunahcinternal(s, &s->tmpd, rep, _state); + return; + } +} + + +/************************************************************************* +This function performs clustering by k-means++ algorithm. + +You may change algorithm properties by calling: +* ClusterizerSetKMeansLimits() to change number of restarts or iterations +* ClusterizerSetKMeansInit() to change initialization algorithm + +By default, one restart and unlimited number of iterations are used. +Initialization algorithm is chosen automatically. + +NOTE: k-means clustering algorithm has two phases: selection of initial + centers and clustering itself. ALGLIB parallelizes both phases. + Parallel version is optimized for the following scenario: medium or + high-dimensional problem (8 or more dimensions) with large number of + points and clusters. However, some speed-up can be obtained even + when assumptions above are violated. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + K - number of clusters, K>=0. + K can be zero only when algorithm is called for empty + dataset, in this case completion code is set to + success (+1). + If K=0 and dataset size is non-zero, we can not + meaningfully assign points to some center (there are no + centers because K=0) and return -3 as completion code + (failure). + +OUTPUT PARAMETERS: + Rep - clustering results; see description of KMeansReport + structure for more information. + +NOTE 1: k-means clustering can be performed only for datasets with + Euclidean distance function. Algorithm will return negative + completion code in Rep.TerminationType in case dataset was added + to clusterizer with DistType other than Euclidean (or dataset was + specified by distance matrix instead of explicitly given points). + +NOTE 2: by default, k-means uses non-deterministic seed to initialize RNG + which is used to select initial centers. As result, each run of + algorithm may return different values. If you need deterministic + behavior, use ClusterizerSetSeed() function. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunkmeans(clusterizerstate* s, + ae_int_t k, + kmeansreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix dummy; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + _kmeansreport_clear(rep); + ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(k>=0, "ClusterizerRunKMeans: K<0", _state); + + /* + * Incorrect distance type + */ + if( s->disttype!=2 ) + { + rep->npoints = s->npoints; + rep->terminationtype = -5; + rep->k = k; + rep->iterationscount = 0; + rep->energy = 0.0; + ae_frame_leave(_state); + return; + } + + /* + * K>NPoints or (K=0 and NPoints>0) + */ + if( k>s->npoints||(k==0&&s->npoints>0) ) + { + rep->npoints = s->npoints; + rep->terminationtype = -3; + rep->k = k; + rep->iterationscount = 0; + rep->energy = 0.0; + ae_frame_leave(_state); + return; + } + + /* + * No points + */ + if( s->npoints==0 ) + { + rep->npoints = 0; + rep->terminationtype = 1; + rep->k = k; + rep->iterationscount = 0; + rep->energy = 0.0; + ae_frame_leave(_state); + return; + } + + /* + * Normal case: + * 1<=K<=NPoints, Euclidean distance + */ + rep->npoints = s->npoints; + rep->nfeatures = s->nfeatures; + rep->k = k; + rep->npoints = s->npoints; + rep->nfeatures = s->nfeatures; + kmeansgenerateinternal(&s->xy, s->npoints, s->nfeatures, k, s->kmeansinitalgo, s->seed, s->kmeansmaxits, s->kmeansrestarts, s->kmeansdbgnoits, &rep->terminationtype, &rep->iterationscount, &dummy, ae_false, &rep->c, ae_true, &rep->cidx, &rep->energy, &s->kmeanstmp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function returns distance matrix for dataset + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm, non-squared) + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +OUTPUT PARAMETERS: + D - array[NPoints,NPoints], distance matrix + (full matrix is returned, with lower and upper triangles) + +NOTE: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizergetdistances(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_state *_state) +{ + ae_frame _frame_block; + apbuffers buf; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + ae_matrix_clear(d); + _apbuffers_init(&buf, _state, ae_true); + + ae_assert(nfeatures>=1, "ClusterizerGetDistances: NFeatures<1", _state); + ae_assert(npoints>=0, "ClusterizerGetDistances: NPoints<1", _state); + ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerGetDistances: incorrect DistType", _state); + ae_assert(xy->rows>=npoints, "ClusterizerGetDistances: Rows(XY)cols>=nfeatures, "ClusterizerGetDistances: Cols(XY)=1, "ClusterizerGetDistancesBuf: NFeatures<1", _state); + ae_assert(npoints>=0, "ClusterizerGetDistancesBuf: NPoints<1", _state); + ae_assert((((((((disttype==0||disttype==1)||disttype==2)||disttype==10)||disttype==11)||disttype==12)||disttype==13)||disttype==20)||disttype==21, "ClusterizerGetDistancesBuf: incorrect DistType", _state); + ae_assert(xy->rows>=npoints, "ClusterizerGetDistancesBuf: Rows(XY)cols>=nfeatures, "ClusterizerGetDistancesBuf: Cols(XY)ptr.pp_double[0][0] = (double)(0); + return; + } + + /* + * Build distance matrix D. + */ + if( disttype==0||disttype==1 ) + { + + /* + * Chebyshev or city-block distances: + * * recursively calculate upper triangle (with main diagonal) + * * copy it to the bottom part of the matrix + */ + rmatrixsetlengthatleast(d, npoints, npoints, _state); + clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, 0, npoints, 0, npoints, _state); + rmatrixenforcesymmetricity(d, npoints, ae_true, _state); + return; + } + if( disttype==2 ) + { + + /* + * Euclidean distance + * + * NOTE: parallelization is done within RMatrixSYRK + */ + rmatrixsetlengthatleast(d, npoints, npoints, _state); + rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); + rvectorsetlengthatleast(&buf->ra1, nfeatures, _state); + rvectorsetlengthatleast(&buf->ra0, npoints, _state); + for(j=0; j<=nfeatures-1; j++) + { + buf->ra1.ptr.p_double[j] = 0.0; + } + v = (double)1/(double)npoints; + for(i=0; i<=npoints-1; i++) + { + ae_v_addd(&buf->ra1.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1), v); + } + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&buf->rm0.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); + ae_v_sub(&buf->rm0.ptr.pp_double[i][0], 1, &buf->ra1.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); + } + rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); + for(i=0; i<=npoints-1; i++) + { + buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; + } + for(i=0; i<=npoints-1; i++) + { + d->ptr.pp_double[i][i] = 0.0; + for(j=i+1; j<=npoints-1; j++) + { + v = ae_sqrt(ae_maxreal(buf->ra0.ptr.p_double[i]+buf->ra0.ptr.p_double[j]-(double)2*d->ptr.pp_double[i][j], 0.0, _state), _state); + d->ptr.pp_double[i][j] = v; + } + } + rmatrixenforcesymmetricity(d, npoints, ae_true, _state); + return; + } + if( disttype==10||disttype==11 ) + { + + /* + * Absolute/nonabsolute Pearson correlation distance + * + * NOTE: parallelization is done within PearsonCorrM, which calls RMatrixSYRK internally + */ + rmatrixsetlengthatleast(d, npoints, npoints, _state); + rvectorsetlengthatleast(&buf->ra0, npoints, _state); + rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); + for(i=0; i<=npoints-1; i++) + { + v = 0.0; + for(j=0; j<=nfeatures-1; j++) + { + v = v+xy->ptr.pp_double[i][j]; + } + v = v/(double)nfeatures; + for(j=0; j<=nfeatures-1; j++) + { + buf->rm0.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]-v; + } + } + rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); + for(i=0; i<=npoints-1; i++) + { + buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; + } + for(i=0; i<=npoints-1; i++) + { + d->ptr.pp_double[i][i] = 0.0; + for(j=i+1; j<=npoints-1; j++) + { + v = d->ptr.pp_double[i][j]/ae_sqrt(buf->ra0.ptr.p_double[i]*buf->ra0.ptr.p_double[j], _state); + if( disttype==10 ) + { + v = (double)1-v; + } + else + { + v = (double)1-ae_fabs(v, _state); + } + v = ae_maxreal(v, 0.0, _state); + d->ptr.pp_double[i][j] = v; + } + } + rmatrixenforcesymmetricity(d, npoints, ae_true, _state); + return; + } + if( disttype==12||disttype==13 ) + { + + /* + * Absolute/nonabsolute uncentered Pearson correlation distance + * + * NOTE: parallelization is done within RMatrixSYRK + */ + rmatrixsetlengthatleast(d, npoints, npoints, _state); + rvectorsetlengthatleast(&buf->ra0, npoints, _state); + rmatrixsyrk(npoints, nfeatures, 1.0, xy, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); + for(i=0; i<=npoints-1; i++) + { + buf->ra0.ptr.p_double[i] = d->ptr.pp_double[i][i]; + } + for(i=0; i<=npoints-1; i++) + { + d->ptr.pp_double[i][i] = 0.0; + for(j=i+1; j<=npoints-1; j++) + { + v = d->ptr.pp_double[i][j]/ae_sqrt(buf->ra0.ptr.p_double[i]*buf->ra0.ptr.p_double[j], _state); + if( disttype==13 ) + { + v = ae_fabs(v, _state); + } + v = ae_minreal(v, 1.0, _state); + d->ptr.pp_double[i][j] = (double)1-v; + } + } + rmatrixenforcesymmetricity(d, npoints, ae_true, _state); + return; + } + if( disttype==20||disttype==21 ) + { + + /* + * Spearman rank correlation + * + * NOTE: parallelization of correlation matrix is done within + * PearsonCorrM, which calls RMatrixSYRK internally + */ + rmatrixsetlengthatleast(d, npoints, npoints, _state); + rvectorsetlengthatleast(&buf->ra0, npoints, _state); + rmatrixsetlengthatleast(&buf->rm0, npoints, nfeatures, _state); + rmatrixcopy(npoints, nfeatures, xy, 0, 0, &buf->rm0, 0, 0, _state); + rankdatacentered(&buf->rm0, npoints, nfeatures, _state); + rmatrixsyrk(npoints, nfeatures, 1.0, &buf->rm0, 0, 0, 0, 0.0, d, 0, 0, ae_true, _state); + for(i=0; i<=npoints-1; i++) + { + if( ae_fp_greater(d->ptr.pp_double[i][i],(double)(0)) ) + { + buf->ra0.ptr.p_double[i] = (double)1/ae_sqrt(d->ptr.pp_double[i][i], _state); + } + else + { + buf->ra0.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=npoints-1; i++) + { + v = buf->ra0.ptr.p_double[i]; + d->ptr.pp_double[i][i] = 0.0; + for(j=i+1; j<=npoints-1; j++) + { + vv = d->ptr.pp_double[i][j]*v*buf->ra0.ptr.p_double[j]; + if( disttype==20 ) + { + vr = (double)1-vv; + } + else + { + vr = (double)1-ae_fabs(vv, _state); + } + if( ae_fp_less(vr,(double)(0)) ) + { + vr = 0.0; + } + d->ptr.pp_double[i][j] = vr; + } + } + rmatrixenforcesymmetricity(d, npoints, ae_true, _state); + return; + } + ae_assert(ae_false, "Assertion failed", _state); +} + + +/************************************************************************* +This function takes as input clusterization report Rep, desired clusters +count K, and builds top K clusters from hierarchical clusterization tree. +It returns assignment of points to clusters (array of cluster indexes). + +INPUT PARAMETERS: + Rep - report from ClusterizerRunAHC() performed on XY + K - desired number of clusters, 1<=K<=NPoints. + K can be zero only when NPoints=0. + +OUTPUT PARAMETERS: + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]npoints; + ae_assert(npoints>=0, "ClusterizerGetKClusters: internal error in Rep integrity", _state); + ae_assert(k>=0, "ClusterizerGetKClusters: K<=0", _state); + ae_assert(k<=npoints, "ClusterizerGetKClusters: K>NPoints", _state); + ae_assert(k>0||npoints==0, "ClusterizerGetKClusters: K<=0", _state); + ae_assert(npoints==rep->npoints, "ClusterizerGetKClusters: NPoints<>Rep.NPoints", _state); + + /* + * Quick exit + */ + if( npoints==0 ) + { + ae_frame_leave(_state); + return; + } + if( npoints==1 ) + { + ae_vector_set_length(cz, 1, _state); + ae_vector_set_length(cidx, 1, _state); + cz->ptr.p_int[0] = 0; + cidx->ptr.p_int[0] = 0; + ae_frame_leave(_state); + return; + } + + /* + * Replay merges, from top to bottom, + * keep track of clusters being present at the moment + */ + ae_vector_set_length(&presentclusters, 2*npoints-1, _state); + ae_vector_set_length(&tmpidx, npoints, _state); + for(i=0; i<=2*npoints-3; i++) + { + presentclusters.ptr.p_bool[i] = ae_false; + } + presentclusters.ptr.p_bool[2*npoints-2] = ae_true; + for(i=0; i<=npoints-1; i++) + { + tmpidx.ptr.p_int[i] = 2*npoints-2; + } + for(mergeidx=npoints-2; mergeidx>=npoints-k; mergeidx--) + { + + /* + * Update information about clusters being present at the moment + */ + presentclusters.ptr.p_bool[npoints+mergeidx] = ae_false; + presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][0]] = ae_true; + presentclusters.ptr.p_bool[rep->z.ptr.pp_int[mergeidx][1]] = ae_true; + + /* + * Update TmpIdx according to the current state of the dataset + * + * NOTE: TmpIdx contains cluster indexes from [0..2*NPoints-2]; + * we will convert them to [0..K-1] later. + */ + i0 = rep->pm.ptr.pp_int[mergeidx][0]; + i1 = rep->pm.ptr.pp_int[mergeidx][1]; + t = rep->z.ptr.pp_int[mergeidx][0]; + for(i=i0; i<=i1; i++) + { + tmpidx.ptr.p_int[i] = t; + } + i0 = rep->pm.ptr.pp_int[mergeidx][2]; + i1 = rep->pm.ptr.pp_int[mergeidx][3]; + t = rep->z.ptr.pp_int[mergeidx][1]; + for(i=i0; i<=i1; i++) + { + tmpidx.ptr.p_int[i] = t; + } + } + + /* + * Fill CZ - array which allows us to convert cluster indexes + * from one system to another. + */ + ae_vector_set_length(cz, k, _state); + ae_vector_set_length(&clusterindexes, 2*npoints-1, _state); + t = 0; + for(i=0; i<=2*npoints-2; i++) + { + if( presentclusters.ptr.p_bool[i] ) + { + cz->ptr.p_int[t] = i; + clusterindexes.ptr.p_int[i] = t; + t = t+1; + } + } + ae_assert(t==k, "ClusterizerGetKClusters: internal error", _state); + + /* + * Convert indexes stored in CIdx + */ + ae_vector_set_length(cidx, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + cidx->ptr.p_int[i] = clusterindexes.ptr.p_int[tmpidx.ptr.p_int[rep->p.ptr.p_int[i]]]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function accepts AHC report Rep, desired minimum intercluster +distance and returns top clusters from hierarchical clusterization tree +which are separated by distance R or HIGHER. + +It returns assignment of points to clusters (array of cluster indexes). + +There is one more function with similar name - ClusterizerSeparatedByCorr, +which returns clusters with intercluster correlation equal to R or LOWER +(note: higher for distance, lower for correlation). + +INPUT PARAMETERS: + Rep - report from ClusterizerRunAHC() performed on XY + R - desired minimum intercluster distance, R>=0 + +OUTPUT PARAMETERS: + K - number of clusters, 1<=K<=NPoints + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],r)) + { + *k = *k+1; + } + clusterizergetkclusters(rep, *k, cidx, cz, _state); +} + + +/************************************************************************* +This function accepts AHC report Rep, desired maximum intercluster +correlation and returns top clusters from hierarchical clusterization tree +which are separated by correlation R or LOWER. + +It returns assignment of points to clusters (array of cluster indexes). + +There is one more function with similar name - ClusterizerSeparatedByDist, +which returns clusters with intercluster distance equal to R or HIGHER +(note: higher for distance, lower for correlation). + +INPUT PARAMETERS: + Rep - report from ClusterizerRunAHC() performed on XY + R - desired maximum intercluster correlation, -1<=R<=+1 + +OUTPUT PARAMETERS: + K - number of clusters, 1<=K<=NPoints + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]npoints&&ae_fp_greater_eq(rep->mergedist.ptr.p_double[rep->npoints-1-(*k)],(double)1-r)) + { + *k = *k+1; + } + clusterizergetkclusters(rep, *k, cidx, cz, _state); +} + + +/************************************************************************* +K-means++ initialization + +INPUT PARAMETERS: + Buf - special reusable structure which stores previously allocated + memory, intended to avoid memory fragmentation when solving + multiple subsequent problems. Must be initialized prior to + usage. + +OUTPUT PARAMETERS: + Buf - initialized structure + + -- ALGLIB -- + Copyright 24.07.2015 by Bochkanov Sergey +*************************************************************************/ +void kmeansinitbuf(kmeansbuffers* buf, ae_state *_state) +{ + ae_frame _frame_block; + apbuffers updateseed; + + ae_frame_make(_state, &_frame_block); + memset(&updateseed, 0, sizeof(updateseed)); + _apbuffers_init(&updateseed, _state, ae_true); + + ae_shared_pool_set_seed(&buf->updatepool, &updateseed, (ae_int_t)sizeof(updateseed), (ae_copy_constructor)_apbuffers_init_copy, (ae_destructor)_apbuffers_destroy, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +K-means++ clusterization + +INPUT PARAMETERS: + XY - dataset, array [0..NPoints-1,0..NVars-1]. + NPoints - dataset size, NPoints>=K + NVars - number of variables, NVars>=1 + K - desired number of clusters, K>=1 + InitAlgo - initialization algorithm: + * 0 - automatic selection of best algorithm + * 1 - random selection of centers + * 2 - k-means++ + * 3 - fast-greedy init + *-1 - first K rows of dataset are used + (special debug algorithm) + Seed - seed value for internal RNG: + * positive value is used to initialize RNG in order to + induce deterministic behavior of algorithm + * zero or negative value means that random seed is + generated + MaxIts - iterations limit or zero for no limit + Restarts - number of restarts, Restarts>=1 + KMeansDbgNoIts- debug flag; if set, Lloyd's iteration is not performed, + only initialization phase. + Buf - special reusable structure which stores previously allocated + memory, intended to avoid memory fragmentation when solving + multiple subsequent problems: + * MUST BE INITIALIZED WITH KMeansInitBuffers() CALL BEFORE + FIRST PASS TO THIS FUNCTION! + * subsequent passes must be made without re-initialization + +OUTPUT PARAMETERS: + Info - return code: + * -3, if task is degenerate (number of distinct points is + less than K) + * -1, if incorrect NPoints/NFeatures/K/Restarts was passed + * 1, if subroutine finished successfully + IterationsCount- actual number of iterations performed by clusterizer + CCol - array[0..NVars-1,0..K-1].matrix whose columns store + cluster's centers + NeedCCol - True in case caller requires to store result in CCol + CRow - array[0..K-1,0..NVars-1], same as CCol, but centers are + stored in rows + NeedCRow - True in case caller requires to store result in CCol + XYC - array[NPoints], which contains cluster indexes + Energy - merit function of clusterization + + -- ALGLIB -- + Copyright 21.03.2009 by Bochkanov Sergey +*************************************************************************/ +void kmeansgenerateinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t k, + ae_int_t initalgo, + ae_int_t seed, + ae_int_t maxits, + ae_int_t restarts, + ae_bool kmeansdbgnoits, + ae_int_t* info, + ae_int_t* iterationscount, + /* Real */ ae_matrix* ccol, + ae_bool needccol, + /* Real */ ae_matrix* crow, + ae_bool needcrow, + /* Integer */ ae_vector* xyc, + double* energy, + kmeansbuffers* buf, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t i1; + double e; + double eprev; + double v; + double vv; + ae_bool waschanges; + ae_bool zerosizeclusters; + ae_int_t pass; + ae_int_t itcnt; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + *info = 0; + *iterationscount = 0; + ae_matrix_clear(ccol); + ae_matrix_clear(crow); + ae_vector_clear(xyc); + *energy = 0.0; + _hqrndstate_init(&rs, _state, ae_true); + + + /* + * Test parameters + */ + if( ((npointsct, k, nvars, _state); + rmatrixsetlengthatleast(&buf->ctbest, k, nvars, _state); + ivectorsetlengthatleast(&buf->xycprev, npoints, _state); + ivectorsetlengthatleast(&buf->xycbest, npoints, _state); + rvectorsetlengthatleast(&buf->d2, npoints, _state); + ivectorsetlengthatleast(&buf->csizes, k, _state); + *energy = ae_maxrealnumber; + for(pass=1; pass<=restarts; pass++) + { + + /* + * Select initial centers. + * + * Note that for performance reasons centers are stored in ROWS of CT, not + * in columns. We'll transpose CT in the end and store it in the C. + * + * Also note that SelectInitialCenters() may return degenerate set of centers + * (some of them have no corresponding points in dataset, some are non-distinct). + * Algorithm below is robust enough to deal with such set. + */ + clustering_selectinitialcenters(xy, npoints, nvars, initalgo, &rs, k, &buf->ct, &buf->initbuf, &buf->updatepool, _state); + + /* + * Lloyd's iteration + */ + if( !kmeansdbgnoits ) + { + + /* + * Perform iteration as usual, in normal mode + */ + for(i=0; i<=npoints-1; i++) + { + xyc->ptr.p_int[i] = -1; + } + eprev = ae_maxrealnumber; + e = ae_maxrealnumber; + itcnt = 0; + while(maxits==0||itcntxycprev.ptr.p_int[i] = xyc->ptr.p_int[i]; + } + kmeansupdatedistances(xy, 0, npoints, nvars, &buf->ct, 0, k, xyc, &buf->d2, &buf->updatepool, _state); + waschanges = ae_false; + for(i=0; i<=npoints-1; i++) + { + waschanges = waschanges||xyc->ptr.p_int[i]!=buf->xycprev.ptr.p_int[i]; + } + + /* + * Update centers + */ + for(j=0; j<=k-1; j++) + { + buf->csizes.ptr.p_int[j] = 0; + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + buf->ct.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=npoints-1; i++) + { + buf->csizes.ptr.p_int[xyc->ptr.p_int[i]] = buf->csizes.ptr.p_int[xyc->ptr.p_int[i]]+1; + ae_v_add(&buf->ct.ptr.pp_double[xyc->ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + } + zerosizeclusters = ae_false; + for(j=0; j<=k-1; j++) + { + if( buf->csizes.ptr.p_int[j]!=0 ) + { + v = (double)1/(double)buf->csizes.ptr.p_int[j]; + ae_v_muld(&buf->ct.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), v); + } + zerosizeclusters = zerosizeclusters||buf->csizes.ptr.p_int[j]==0; + } + if( zerosizeclusters ) + { + + /* + * Some clusters have zero size - rare, but possible. + * We'll choose new centers for such clusters using k-means++ rule + * and restart algorithm, decrementing iteration counter + * in order to allow one more iteration (this one was useless + * and should not be counted). + */ + if( !clustering_fixcenters(xy, npoints, nvars, &buf->ct, k, &buf->initbuf, &buf->updatepool, _state) ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + itcnt = itcnt-1; + continue; + } + + /* + * Stop if one of two conditions is met: + * 1. nothing has changed during iteration + * 2. energy function increased after recalculation on new centers + */ + e = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = 0.0; + i1 = xyc->ptr.p_int[i]; + for(j=0; j<=nvars-1; j++) + { + vv = xy->ptr.pp_double[i][j]-buf->ct.ptr.pp_double[i1][j]; + v = v+vv*vv; + } + e = e+v; + } + if( !waschanges||ae_fp_greater_eq(e,eprev) ) + { + break; + } + + /* + * Update EPrev + */ + eprev = e; + } + } + else + { + + /* + * Debug mode: no Lloyd's iteration. + * We just calculate potential E. + */ + kmeansupdatedistances(xy, 0, npoints, nvars, &buf->ct, 0, k, xyc, &buf->d2, &buf->updatepool, _state); + e = (double)(0); + for(i=0; i<=npoints-1; i++) + { + e = e+buf->d2.ptr.p_double[i]; + } + } + + /* + * Compare E with best centers found so far + */ + if( ae_fp_less(e,*energy) ) + { + + /* + * store partition. + */ + *energy = e; + copymatrix(&buf->ct, 0, k-1, 0, nvars-1, &buf->ctbest, 0, k-1, 0, nvars-1, _state); + for(i=0; i<=npoints-1; i++) + { + buf->xycbest.ptr.p_int[i] = xyc->ptr.p_int[i]; + } + } + } + + /* + * Copy and transpose + */ + if( needccol ) + { + ae_matrix_set_length(ccol, nvars, k, _state); + copyandtranspose(&buf->ctbest, 0, k-1, 0, nvars-1, ccol, 0, nvars-1, 0, k-1, _state); + } + if( needcrow ) + { + ae_matrix_set_length(crow, k, nvars, _state); + rmatrixcopy(k, nvars, &buf->ctbest, 0, 0, crow, 0, 0, _state); + } + for(i=0; i<=npoints-1; i++) + { + xyc->ptr.p_int[i] = buf->xycbest.ptr.p_int[i]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This procedure recalculates distances from points to centers and assigns +each point to closest center. + +INPUT PARAMETERS: + XY - dataset, array [0..NPoints-1,0..NVars-1]. + Idx0,Idx1 - define range of dataset [Idx0,Idx1) to process; + right boundary is not included. + NVars - number of variables, NVars>=1 + CT - matrix of centers, centers are stored in rows + CIdx0,CIdx1 - define range of centers [CIdx0,CIdx1) to process; + right boundary is not included. + XYC - preallocated output buffer, + XYDist2 - preallocated output buffer + Tmp - temporary buffer, automatically reallocated if needed + BufferPool - shared pool seeded with instance of APBuffers structure + (seed instance can be unitialized). It is recommended + to use this pool only with KMeansUpdateDistances() + function. + +OUTPUT PARAMETERS: + XYC - new assignment of points to centers are stored + in [Idx0,Idx1) + XYDist2 - squared distances from points to their centers are + stored in [Idx0,Idx1) + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +void kmeansupdatedistances(/* Real */ const ae_matrix* xy, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nvars, + /* Real */ const ae_matrix* ct, + ae_int_t cidx0, + ae_int_t cidx1, + /* Integer */ ae_vector* xyc, + /* Real */ ae_vector* xydist2, + ae_shared_pool* bufferpool, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t i0; + ae_int_t i1; + ae_int_t j; + ae_int_t cclosest; + double dclosest; + double vv; + apbuffers *buf; + ae_smart_ptr _buf; + double rcomplexity; + ae_int_t task0; + ae_int_t task1; + ae_int_t pblkcnt; + ae_int_t cblkcnt; + ae_int_t vblkcnt; + ae_int_t pblk; + ae_int_t cblk; + ae_int_t vblk; + ae_int_t p0; + ae_int_t p1; + ae_int_t c0; + ae_int_t c1; + ae_int_t v0; + ae_int_t v1; + double v00; + double v01; + double v10; + double v11; + double vp0; + double vp1; + double vc0; + double vc1; + ae_int_t pcnt; + ae_int_t pcntpadded; + ae_int_t ccnt; + ae_int_t ccntpadded; + ae_int_t offs0; + ae_int_t offs00; + ae_int_t offs01; + ae_int_t offs10; + ae_int_t offs11; + ae_int_t vcnt; + ae_int_t stride; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + + /* + * Quick exit for special cases + */ + if( idx1<=idx0 ) + { + ae_frame_leave(_state); + return; + } + if( cidx1<=cidx0 ) + { + ae_frame_leave(_state); + return; + } + if( nvars<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Try to recursively divide/process dataset + * + * NOTE: real arithmetics is used to avoid integer overflow on large problem sizes + */ + rcomplexity = (double)2*rmul3((double)(idx1-idx0), (double)(cidx1-cidx0), (double)(nvars), _state); + if( ae_fp_greater_eq(rcomplexity,smpactivationlevel(_state))&&idx1-idx0>=2*clustering_kmeansblocksize ) + { + if( _trypexec_kmeansupdatedistances(xy,idx0,idx1,nvars,ct,cidx0,cidx1,xyc,xydist2,bufferpool, _state) ) + { + ae_frame_leave(_state); + return; + } + } + if( ((ae_fp_greater_eq(rcomplexity,spawnlevel(_state))&&idx1-idx0>=2*clustering_kmeansblocksize)&&nvars>=clustering_kmeansparalleldim)&&cidx1-cidx0>=clustering_kmeansparallelk ) + { + splitlength(idx1-idx0, clustering_kmeansblocksize, &task0, &task1, _state); + kmeansupdatedistances(xy, idx0, idx0+task0, nvars, ct, cidx0, cidx1, xyc, xydist2, bufferpool, _state); + kmeansupdatedistances(xy, idx0+task0, idx1, nvars, ct, cidx0, cidx1, xyc, xydist2, bufferpool, _state); + ae_frame_leave(_state); + return; + } + + /* + * Dataset chunk is selected. + * + * Process it with blocked algorithm: + * * iterate over points, process them in KMeansBlockSize-ed chunks + * * for each chunk of dataset, iterate over centers, process them in KMeansBlockSize-ed chunks + * * for each chunk of dataset/centerset, iterate over variables, process them in KMeansBlockSize-ed chunks + */ + ae_assert(clustering_kmeansblocksize%2==0, "KMeansUpdateDistances: internal error", _state); + ae_shared_pool_retrieve(bufferpool, &_buf, _state); + rvectorsetlengthatleast(&buf->ra0, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); + rvectorsetlengthatleast(&buf->ra1, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); + rvectorsetlengthatleast(&buf->ra2, clustering_kmeansblocksize*clustering_kmeansblocksize, _state); + rvectorsetlengthatleast(&buf->ra3, clustering_kmeansblocksize, _state); + ivectorsetlengthatleast(&buf->ia3, clustering_kmeansblocksize, _state); + pblkcnt = chunkscount(idx1-idx0, clustering_kmeansblocksize, _state); + cblkcnt = chunkscount(cidx1-cidx0, clustering_kmeansblocksize, _state); + vblkcnt = chunkscount(nvars, clustering_kmeansblocksize, _state); + for(pblk=0; pblk<=pblkcnt-1; pblk++) + { + + /* + * Process PBlk-th chunk of dataset. + */ + p0 = idx0+pblk*clustering_kmeansblocksize; + p1 = ae_minint(p0+clustering_kmeansblocksize, idx1, _state); + + /* + * Prepare RA3[]/IA3[] for storage of best distances and best cluster numbers. + */ + for(i=0; i<=clustering_kmeansblocksize-1; i++) + { + buf->ra3.ptr.p_double[i] = ae_maxrealnumber; + buf->ia3.ptr.p_int[i] = -1; + } + + /* + * Iterare over chunks of centerset. + */ + for(cblk=0; cblk<=cblkcnt-1; cblk++) + { + + /* + * Process CBlk-th chunk of centerset + */ + c0 = cidx0+cblk*clustering_kmeansblocksize; + c1 = ae_minint(c0+clustering_kmeansblocksize, cidx1, _state); + + /* + * At this point we have to calculate a set of pairwise distances + * between points [P0,P1) and centers [C0,C1) and select best center + * for each point. It can also be done with blocked algorithm + * (blocking for variables). + * + * Following arrays are used: + * * RA0[] - matrix of distances, padded by zeros for even size, + * rows are stored with stride KMeansBlockSize. + * * RA1[] - matrix of points (variables corresponding to current + * block are extracted), padded by zeros for even size, + * rows are stored with stride KMeansBlockSize. + * * RA2[] - matrix of centers (variables corresponding to current + * block are extracted), padded by zeros for even size, + * rows are stored with stride KMeansBlockSize. + * + */ + pcnt = p1-p0; + pcntpadded = pcnt+pcnt%2; + ccnt = c1-c0; + ccntpadded = ccnt+ccnt%2; + stride = clustering_kmeansblocksize; + ae_assert(pcntpadded<=clustering_kmeansblocksize, "KMeansUpdateDistances: integrity error", _state); + ae_assert(ccntpadded<=clustering_kmeansblocksize, "KMeansUpdateDistances: integrity error", _state); + for(i=0; i<=pcntpadded-1; i++) + { + for(j=0; j<=ccntpadded-1; j++) + { + buf->ra0.ptr.p_double[i*stride+j] = 0.0; + } + } + for(vblk=0; vblk<=vblkcnt-1; vblk++) + { + + /* + * Fetch VBlk-th block of variables to arrays RA1 (points) and RA2 (centers). + * Pad points and centers with zeros. + */ + v0 = vblk*clustering_kmeansblocksize; + v1 = ae_minint(v0+clustering_kmeansblocksize, nvars, _state); + vcnt = v1-v0; + for(i=0; i<=pcnt-1; i++) + { + for(j=0; j<=vcnt-1; j++) + { + buf->ra1.ptr.p_double[i*stride+j] = xy->ptr.pp_double[p0+i][v0+j]; + } + } + for(i=pcnt; i<=pcntpadded-1; i++) + { + for(j=0; j<=vcnt-1; j++) + { + buf->ra1.ptr.p_double[i*stride+j] = 0.0; + } + } + for(i=0; i<=ccnt-1; i++) + { + for(j=0; j<=vcnt-1; j++) + { + buf->ra2.ptr.p_double[i*stride+j] = ct->ptr.pp_double[c0+i][v0+j]; + } + } + for(i=ccnt; i<=ccntpadded-1; i++) + { + for(j=0; j<=vcnt-1; j++) + { + buf->ra2.ptr.p_double[i*stride+j] = 0.0; + } + } + + /* + * Update distance matrix with sums-of-squared-differences of RA1 and RA2 + */ + i0 = 0; + while(i0ra0.ptr.p_double[offs0]; + v01 = buf->ra0.ptr.p_double[offs0+1]; + v10 = buf->ra0.ptr.p_double[offs0+stride]; + v11 = buf->ra0.ptr.p_double[offs0+stride+1]; + offs00 = i0*stride; + offs01 = offs00+stride; + offs10 = i1*stride; + offs11 = offs10+stride; + for(j=0; j<=vcnt-1; j++) + { + vp0 = buf->ra1.ptr.p_double[offs00+j]; + vp1 = buf->ra1.ptr.p_double[offs01+j]; + vc0 = buf->ra2.ptr.p_double[offs10+j]; + vc1 = buf->ra2.ptr.p_double[offs11+j]; + vv = vp0-vc0; + v00 = v00+vv*vv; + vv = vp0-vc1; + v01 = v01+vv*vv; + vv = vp1-vc0; + v10 = v10+vv*vv; + vv = vp1-vc1; + v11 = v11+vv*vv; + } + offs0 = i0*stride+i1; + buf->ra0.ptr.p_double[offs0] = v00; + buf->ra0.ptr.p_double[offs0+1] = v01; + buf->ra0.ptr.p_double[offs0+stride] = v10; + buf->ra0.ptr.p_double[offs0+stride+1] = v11; + i1 = i1+2; + } + i0 = i0+2; + } + } + for(i=0; i<=pcnt-1; i++) + { + cclosest = buf->ia3.ptr.p_int[i]; + dclosest = buf->ra3.ptr.p_double[i]; + for(j=0; j<=ccnt-1; j++) + { + if( ae_fp_less(buf->ra0.ptr.p_double[i*stride+j],dclosest) ) + { + dclosest = buf->ra0.ptr.p_double[i*stride+j]; + cclosest = c0+j; + } + } + buf->ia3.ptr.p_int[i] = cclosest; + buf->ra3.ptr.p_double[i] = dclosest; + } + } + + /* + * Store best centers to XYC[] + */ + for(i=p0; i<=p1-1; i++) + { + xyc->ptr.p_int[i] = buf->ia3.ptr.p_int[i-p0]; + xydist2->ptr.p_double[i] = buf->ra3.ptr.p_double[i-p0]; + } + } + ae_shared_pool_recycle(bufferpool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_kmeansupdatedistances(/* Real */ const ae_matrix* xy, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nvars, + /* Real */ const ae_matrix* ct, + ae_int_t cidx0, + ae_int_t cidx1, + /* Integer */ ae_vector* xyc, + /* Real */ ae_vector* xydist2, + ae_shared_pool* bufferpool, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function selects initial centers according to specified initialization +algorithm. + +IMPORTANT: this function provides no guarantees regarding selection of + DIFFERENT centers. Centers returned by this function may + include duplicates (say, when random sampling is used). It is + also possible that some centers are empty. + Algorithm which uses this function must be able to deal with it. + Say, you may want to use FixCenters() in order to fix empty centers. + +INPUT PARAMETERS: + XY - dataset, array [0..NPoints-1,0..NVars-1]. + NPoints - points count + NVars - number of variables, NVars>=1 + InitAlgo - initialization algorithm: + * 0 - automatic selection of best algorithm + * 1 - random selection + * 2 - k-means++ + * 3 - fast-greedy init + *-1 - first K rows of dataset are used (debug algorithm) + RS - RNG used to select centers + K - number of centers, K>=1 + CT - possibly preallocated output buffer, resized if needed + InitBuf - internal buffer, possibly unitialized instance of + APBuffers. It is recommended to use this instance only + with SelectInitialCenters() and FixCenters() functions, + because these functions may allocate really large storage. + UpdatePool - shared pool seeded with instance of APBuffers structure + (seed instance can be unitialized). Used internally with + KMeansUpdateDistances() function. It is recommended + to use this pool ONLY with KMeansUpdateDistances() + function. + +OUTPUT PARAMETERS: + CT - set of K clusters, one per row + +RESULT: + True on success, False on failure (impossible to create K independent clusters) + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +static void clustering_selectinitialcenters(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t initalgo, + hqrndstate* rs, + ae_int_t k, + /* Real */ ae_matrix* ct, + apbuffers* initbuf, + ae_shared_pool* updatepool, + ae_state *_state) +{ + ae_int_t cidx; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double s; + ae_int_t lastnz; + ae_int_t ptidx; + ae_int_t samplesize; + ae_int_t samplescntnew; + ae_int_t samplescntall; + double samplescale; + + + + /* + * Check parameters + */ + ae_assert(npoints>0, "SelectInitialCenters: internal error", _state); + ae_assert(nvars>0, "SelectInitialCenters: internal error", _state); + ae_assert(k>0, "SelectInitialCenters: internal error", _state); + if( initalgo==0 ) + { + initalgo = 3; + } + rmatrixsetlengthatleast(ct, k, nvars, _state); + + /* + * Random initialization + */ + if( initalgo==-1 ) + { + for(i=0; i<=k-1; i++) + { + ae_v_move(&ct->ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i%npoints][0], 1, ae_v_len(0,nvars-1)); + } + return; + } + + /* + * Random initialization + */ + if( initalgo==1 ) + { + for(i=0; i<=k-1; i++) + { + j = hqrnduniformi(rs, npoints, _state); + ae_v_move(&ct->ptr.pp_double[i][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); + } + return; + } + + /* + * k-means++ initialization + */ + if( initalgo==2 ) + { + + /* + * Prepare distances array. + * Select initial center at random. + */ + rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; + } + ptidx = hqrnduniformi(rs, npoints, _state); + ae_v_move(&ct->ptr.pp_double[0][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + + /* + * For each newly added center repeat: + * * reevaluate distances from points to best centers + * * sample points with probability dependent on distance + * * add new center + */ + for(cidx=0; cidx<=k-2; cidx++) + { + + /* + * Reevaluate distances + */ + s = 0.0; + for(i=0; i<=npoints-1; i++) + { + v = 0.0; + for(j=0; j<=nvars-1; j++) + { + vv = xy->ptr.pp_double[i][j]-ct->ptr.pp_double[cidx][j]; + v = v+vv*vv; + } + if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) + { + initbuf->ra0.ptr.p_double[i] = v; + } + s = s+initbuf->ra0.ptr.p_double[i]; + } + + /* + * If all distances are zero, it means that we can not find enough + * distinct points. In this case we just select non-distinct center + * at random and continue iterations. This issue will be handled + * later in the FixCenters() function. + */ + if( ae_fp_eq(s,0.0) ) + { + ptidx = hqrnduniformi(rs, npoints, _state); + ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + continue; + } + + /* + * Select point as center using its distance. + * We also handle situation when because of rounding errors + * no point was selected - in this case, last non-zero one + * will be used. + */ + v = hqrnduniformr(rs, _state); + vv = 0.0; + lastnz = -1; + ptidx = -1; + for(i=0; i<=npoints-1; i++) + { + if( ae_fp_eq(initbuf->ra0.ptr.p_double[i],0.0) ) + { + continue; + } + lastnz = i; + vv = vv+initbuf->ra0.ptr.p_double[i]; + if( ae_fp_less_eq(v,vv/s) ) + { + ptidx = i; + break; + } + } + ae_assert(lastnz>=0, "SelectInitialCenters: integrity error", _state); + if( ptidx<0 ) + { + ptidx = lastnz; + } + ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + } + return; + } + + /* + * "Fast-greedy" algorithm based on "Scalable k-means++". + * + * We perform several rounds, within each round we sample about 0.5*K points + * (not exactly 0.5*K) until we have 2*K points sampled. Before each round + * we calculate distances from dataset points to closest points sampled so far. + * We sample dataset points independently using distance xtimes 0.5*K divided by total + * as probability (similar to k-means++, but each point is sampled independently; + * after each round we have roughtly 0.5*K points added to sample). + * + * After sampling is done, we run "greedy" version of k-means++ on this subsample + * which selects most distant point on every round. + */ + if( initalgo==3 ) + { + + /* + * Prepare arrays. + * Select initial center at random, add it to "new" part of sample, + * which is stored at the beginning of the array + */ + samplesize = 2*k; + samplescale = 0.5*(double)k; + rmatrixsetlengthatleast(&initbuf->rm0, samplesize, nvars, _state); + ptidx = hqrnduniformi(rs, npoints, _state); + ae_v_move(&initbuf->rm0.ptr.pp_double[0][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + samplescntnew = 1; + samplescntall = 1; + rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); + rvectorsetlengthatleast(&initbuf->ra1, npoints, _state); + ivectorsetlengthatleast(&initbuf->ia1, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; + } + + /* + * Repeat until samples count is 2*K + */ + while(samplescntallrm0, samplescntall-samplescntnew, samplescntall, &initbuf->ia1, &initbuf->ra1, updatepool, _state); + samplescntnew = 0; + + /* + * Merge new distances with old ones. + * Calculate sum of distances, if sum is exactly zero - fill sample + * by randomly selected points and terminate. + */ + s = 0.0; + for(i=0; i<=npoints-1; i++) + { + initbuf->ra0.ptr.p_double[i] = ae_minreal(initbuf->ra0.ptr.p_double[i], initbuf->ra1.ptr.p_double[i], _state); + s = s+initbuf->ra0.ptr.p_double[i]; + } + if( ae_fp_eq(s,0.0) ) + { + while(samplescntallrm0.ptr.pp_double[samplescntall][0], 1, &xy->ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + inc(&samplescntall, _state); + inc(&samplescntnew, _state); + } + break; + } + + /* + * Sample points independently. + */ + for(i=0; i<=npoints-1; i++) + { + if( samplescntall==samplesize ) + { + break; + } + if( ae_fp_eq(initbuf->ra0.ptr.p_double[i],0.0) ) + { + continue; + } + if( ae_fp_less_eq(hqrnduniformr(rs, _state),samplescale*initbuf->ra0.ptr.p_double[i]/s) ) + { + ae_v_move(&initbuf->rm0.ptr.pp_double[samplescntall][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + inc(&samplescntall, _state); + inc(&samplescntnew, _state); + } + } + } + + /* + * Run greedy version of k-means on sampled points + */ + rvectorsetlengthatleast(&initbuf->ra0, samplescntall, _state); + for(i=0; i<=samplescntall-1; i++) + { + initbuf->ra0.ptr.p_double[i] = ae_maxrealnumber; + } + ptidx = hqrnduniformi(rs, samplescntall, _state); + ae_v_move(&ct->ptr.pp_double[0][0], 1, &initbuf->rm0.ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + for(cidx=0; cidx<=k-2; cidx++) + { + + /* + * Reevaluate distances + */ + for(i=0; i<=samplescntall-1; i++) + { + v = 0.0; + for(j=0; j<=nvars-1; j++) + { + vv = initbuf->rm0.ptr.pp_double[i][j]-ct->ptr.pp_double[cidx][j]; + v = v+vv*vv; + } + if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) + { + initbuf->ra0.ptr.p_double[i] = v; + } + } + + /* + * Select point as center in greedy manner - most distant + * point is selected. + */ + ptidx = 0; + for(i=0; i<=samplescntall-1; i++) + { + if( ae_fp_greater(initbuf->ra0.ptr.p_double[i],initbuf->ra0.ptr.p_double[ptidx]) ) + { + ptidx = i; + } + } + ae_v_move(&ct->ptr.pp_double[cidx+1][0], 1, &initbuf->rm0.ptr.pp_double[ptidx][0], 1, ae_v_len(0,nvars-1)); + } + return; + } + + /* + * Internal error + */ + ae_assert(ae_false, "SelectInitialCenters: internal error", _state); +} + + +/************************************************************************* +This function "fixes" centers, i.e. replaces ones which have no neighbor +points by new centers which have at least one neighbor. If it is impossible +to fix centers (not enough distinct points in the dataset), this function +returns False. + +INPUT PARAMETERS: + XY - dataset, array [0..NPoints-1,0..NVars-1]. + NPoints - points count, >=1 + NVars - number of variables, NVars>=1 + CT - centers + K - number of centers, K>=1 + InitBuf - internal buffer, possibly unitialized instance of + APBuffers. It is recommended to use this instance only + with SelectInitialCenters() and FixCenters() functions, + because these functions may allocate really large storage. + UpdatePool - shared pool seeded with instance of APBuffers structure + (seed instance can be unitialized). Used internally with + KMeansUpdateDistances() function. It is recommended + to use this pool ONLY with KMeansUpdateDistances() + function. + +OUTPUT PARAMETERS: + CT - set of K centers, one per row + +RESULT: + True on success, False on failure (impossible to create K independent clusters) + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +static ae_bool clustering_fixcenters(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + /* Real */ ae_matrix* ct, + ae_int_t k, + apbuffers* initbuf, + ae_shared_pool* updatepool, + ae_state *_state) +{ + ae_int_t fixiteration; + ae_int_t centertofix; + ae_int_t i; + ae_int_t j; + ae_int_t pdistant; + double ddistant; + double v; + ae_bool result; + + + ae_assert(npoints>=1, "FixCenters: internal error", _state); + ae_assert(nvars>=1, "FixCenters: internal error", _state); + ae_assert(k>=1, "FixCenters: internal error", _state); + + /* + * Calculate distances from points to best centers (RA0) + * and best center indexes (IA0) + */ + ivectorsetlengthatleast(&initbuf->ia0, npoints, _state); + rvectorsetlengthatleast(&initbuf->ra0, npoints, _state); + kmeansupdatedistances(xy, 0, npoints, nvars, ct, 0, k, &initbuf->ia0, &initbuf->ra0, updatepool, _state); + + /* + * Repeat loop: + * * find first center which has no corresponding point + * * set it to the most distant (from the rest of the centerset) point + * * recalculate distances, update IA0/RA0 + * * repeat + * + * Loop is repeated for at most 2*K iterations. It is stopped once we have + * no "empty" clusters. + */ + bvectorsetlengthatleast(&initbuf->ba0, k, _state); + for(fixiteration=0; fixiteration<=2*k; fixiteration++) + { + + /* + * Select center to fix (one which is not mentioned in IA0), + * terminate if there is no such center. + * BA0[] stores True for centers which have at least one point. + */ + for(i=0; i<=k-1; i++) + { + initbuf->ba0.ptr.p_bool[i] = ae_false; + } + for(i=0; i<=npoints-1; i++) + { + initbuf->ba0.ptr.p_bool[initbuf->ia0.ptr.p_int[i]] = ae_true; + } + centertofix = -1; + for(i=0; i<=k-1; i++) + { + if( !initbuf->ba0.ptr.p_bool[i] ) + { + centertofix = i; + break; + } + } + if( centertofix<0 ) + { + result = ae_true; + return result; + } + + /* + * Replace center to fix by the most distant point. + * Update IA0/RA0 + */ + pdistant = 0; + ddistant = initbuf->ra0.ptr.p_double[pdistant]; + for(i=0; i<=npoints-1; i++) + { + if( ae_fp_greater(initbuf->ra0.ptr.p_double[i],ddistant) ) + { + ddistant = initbuf->ra0.ptr.p_double[i]; + pdistant = i; + } + } + if( ae_fp_eq(ddistant,0.0) ) + { + break; + } + ae_v_move(&ct->ptr.pp_double[centertofix][0], 1, &xy->ptr.pp_double[pdistant][0], 1, ae_v_len(0,nvars-1)); + for(i=0; i<=npoints-1; i++) + { + v = 0.0; + for(j=0; j<=nvars-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-ct->ptr.pp_double[centertofix][j], _state); + } + if( ae_fp_less(v,initbuf->ra0.ptr.p_double[i]) ) + { + initbuf->ra0.ptr.p_double[i] = v; + initbuf->ia0.ptr.p_int[i] = centertofix; + } + } + } + result = ae_false; + return result; +} + + +/************************************************************************* +This function performs agglomerative hierarchical clustering using +precomputed distance matrix. Internal function, should not be called +directly. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + D - distance matrix, array[S.NFeatures,S.NFeatures] + Contents of the matrix is destroyed during + algorithm operation. + +OUTPUT PARAMETERS: + Rep - clustering results; see description of AHCReport + structure for more information. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +static void clustering_clusterizerrunahcinternal(clusterizerstate* s, + /* Real */ ae_matrix* d, + ahcreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_int_t mergeidx; + ae_int_t c0; + ae_int_t c1; + ae_int_t s0; + ae_int_t s1; + ae_int_t ar; + ae_int_t br; + ae_int_t npoints; + ae_vector cidx; + ae_vector csizes; + ae_vector nnidx; + ae_matrix cinfo; + ae_int_t n0; + ae_int_t n1; + ae_int_t ni; + double d01; + + ae_frame_make(_state, &_frame_block); + memset(&cidx, 0, sizeof(cidx)); + memset(&csizes, 0, sizeof(csizes)); + memset(&nnidx, 0, sizeof(nnidx)); + memset(&cinfo, 0, sizeof(cinfo)); + ae_vector_init(&cidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&csizes, 0, DT_INT, _state, ae_true); + ae_vector_init(&nnidx, 0, DT_INT, _state, ae_true); + ae_matrix_init(&cinfo, 0, 0, DT_INT, _state, ae_true); + + npoints = s->npoints; + + /* + * Fill Rep.NPoints, quick exit when NPoints<=1 + */ + rep->npoints = npoints; + if( npoints==0 ) + { + ae_vector_set_length(&rep->p, 0, _state); + ae_matrix_set_length(&rep->z, 0, 0, _state); + ae_matrix_set_length(&rep->pz, 0, 0, _state); + ae_matrix_set_length(&rep->pm, 0, 0, _state); + ae_vector_set_length(&rep->mergedist, 0, _state); + rep->terminationtype = 1; + ae_frame_leave(_state); + return; + } + if( npoints==1 ) + { + ae_vector_set_length(&rep->p, 1, _state); + ae_matrix_set_length(&rep->z, 0, 0, _state); + ae_matrix_set_length(&rep->pz, 0, 0, _state); + ae_matrix_set_length(&rep->pm, 0, 0, _state); + ae_vector_set_length(&rep->mergedist, 0, _state); + rep->p.ptr.p_int[0] = 0; + rep->terminationtype = 1; + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(&rep->z, npoints-1, 2, _state); + ae_vector_set_length(&rep->mergedist, npoints-1, _state); + rep->terminationtype = 1; + + /* + * Build list of nearest neighbors + */ + ae_vector_set_length(&nnidx, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + + /* + * Calculate index of the nearest neighbor + */ + k = -1; + v = ae_maxrealnumber; + for(j=0; j<=npoints-1; j++) + { + if( j!=i&&ae_fp_less(d->ptr.pp_double[i][j],v) ) + { + k = j; + v = d->ptr.pp_double[i][j]; + } + } + ae_assert(ae_fp_less(v,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); + nnidx.ptr.p_int[i] = k; + } + + /* + * For AHCAlgo=4 (Ward's method) replace distances by their squares times 0.5 + */ + if( s->ahcalgo==4 ) + { + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=npoints-1; j++) + { + d->ptr.pp_double[i][j] = 0.5*d->ptr.pp_double[i][j]*d->ptr.pp_double[i][j]; + } + } + } + + /* + * Distance matrix is built, perform merges. + * + * NOTE 1: CIdx is array[NPoints] which maps rows/columns of the + * distance matrix D to indexes of clusters. Values of CIdx + * from [0,NPoints) denote single-point clusters, and values + * from [NPoints,2*NPoints-1) denote ones obtained by merging + * smaller clusters. Negative calues correspond to absent clusters. + * + * Initially it contains [0...NPoints-1], after each merge + * one element of CIdx (one with index C0) is replaced by + * NPoints+MergeIdx, and another one with index C1 is + * rewritten by -1. + * + * NOTE 2: CSizes is array[NPoints] which stores sizes of clusters. + * + */ + ae_vector_set_length(&cidx, npoints, _state); + ae_vector_set_length(&csizes, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + cidx.ptr.p_int[i] = i; + csizes.ptr.p_int[i] = 1; + } + for(mergeidx=0; mergeidx<=npoints-2; mergeidx++) + { + + /* + * Select pair of clusters (C0,C1) with CIdx[C0]=0 ) + { + if( ae_fp_less(d->ptr.pp_double[i][nnidx.ptr.p_int[i]],d01) ) + { + c0 = i; + c1 = nnidx.ptr.p_int[i]; + d01 = d->ptr.pp_double[i][nnidx.ptr.p_int[i]]; + } + } + } + ae_assert(ae_fp_less(d01,ae_maxrealnumber), "ClusterizerRunAHC: internal error", _state); + if( cidx.ptr.p_int[c0]>cidx.ptr.p_int[c1] ) + { + i = c1; + c1 = c0; + c0 = i; + } + + /* + * Fill one row of Rep.Z and one element of Rep.MergeDist + */ + rep->z.ptr.pp_int[mergeidx][0] = cidx.ptr.p_int[c0]; + rep->z.ptr.pp_int[mergeidx][1] = cidx.ptr.p_int[c1]; + rep->mergedist.ptr.p_double[mergeidx] = d01; + + /* + * Update distance matrix: + * * row/column C0 are updated by distances to the new cluster + * * row/column C1 are considered empty (we can fill them by zeros, + * but do not want to spend time - we just ignore them) + * + * NOTE: it is important to update distance matrix BEFORE CIdx/CSizes + * are updated. + */ + ae_assert((((s->ahcalgo==0||s->ahcalgo==1)||s->ahcalgo==2)||s->ahcalgo==3)||s->ahcalgo==4, "ClusterizerRunAHC: internal error", _state); + for(i=0; i<=npoints-1; i++) + { + if( i!=c0&&i!=c1 ) + { + n0 = csizes.ptr.p_int[c0]; + n1 = csizes.ptr.p_int[c1]; + ni = csizes.ptr.p_int[i]; + if( s->ahcalgo==0 ) + { + d->ptr.pp_double[i][c0] = ae_maxreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); + } + if( s->ahcalgo==1 ) + { + d->ptr.pp_double[i][c0] = ae_minreal(d->ptr.pp_double[i][c0], d->ptr.pp_double[i][c1], _state); + } + if( s->ahcalgo==2 ) + { + d->ptr.pp_double[i][c0] = ((double)csizes.ptr.p_int[c0]*d->ptr.pp_double[i][c0]+(double)csizes.ptr.p_int[c1]*d->ptr.pp_double[i][c1])/(double)(csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]); + } + if( s->ahcalgo==3 ) + { + d->ptr.pp_double[i][c0] = (d->ptr.pp_double[i][c0]+d->ptr.pp_double[i][c1])/(double)2; + } + if( s->ahcalgo==4 ) + { + d->ptr.pp_double[i][c0] = ((double)(n0+ni)*d->ptr.pp_double[i][c0]+(double)(n1+ni)*d->ptr.pp_double[i][c1]-(double)ni*d01)/(double)(n0+n1+ni); + } + d->ptr.pp_double[c0][i] = d->ptr.pp_double[i][c0]; + } + } + + /* + * Update CIdx and CSizes + */ + cidx.ptr.p_int[c0] = npoints+mergeidx; + cidx.ptr.p_int[c1] = -1; + csizes.ptr.p_int[c0] = csizes.ptr.p_int[c0]+csizes.ptr.p_int[c1]; + csizes.ptr.p_int[c1] = 0; + + /* + * Update nearest neighbors array: + * * update nearest neighbors of everything except for C0/C1 + * * update neighbors of C0/C1 + */ + for(i=0; i<=npoints-1; i++) + { + if( (cidx.ptr.p_int[i]>=0&&i!=c0)&&(nnidx.ptr.p_int[i]==c0||nnidx.ptr.p_int[i]==c1) ) + { + + /* + * I-th cluster which is distinct from C0/C1 has former C0/C1 cluster as its nearest + * neighbor. We handle this issue depending on specific AHC algorithm being used. + */ + if( s->ahcalgo==1 ) + { + + /* + * Single linkage. Merging of two clusters together + * does NOT change distances between new cluster and + * other clusters. + * + * The only thing we have to do is to update nearest neighbor index + */ + nnidx.ptr.p_int[i] = c0; + } + else + { + + /* + * Something other than single linkage. We have to re-examine + * all the row to find nearest neighbor. + */ + k = -1; + v = ae_maxrealnumber; + for(j=0; j<=npoints-1; j++) + { + if( (cidx.ptr.p_int[j]>=0&&j!=i)&&ae_fp_less(d->ptr.pp_double[i][j],v) ) + { + k = j; + v = d->ptr.pp_double[i][j]; + } + } + ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); + nnidx.ptr.p_int[i] = k; + } + } + } + k = -1; + v = ae_maxrealnumber; + for(j=0; j<=npoints-1; j++) + { + if( (cidx.ptr.p_int[j]>=0&&j!=c0)&&ae_fp_less(d->ptr.pp_double[c0][j],v) ) + { + k = j; + v = d->ptr.pp_double[c0][j]; + } + } + ae_assert(ae_fp_less(v,ae_maxrealnumber)||mergeidx==npoints-2, "ClusterizerRunAHC: internal error", _state); + nnidx.ptr.p_int[c0] = k; + } + + /* + * Calculate Rep.P and Rep.PM. + * + * In order to do that, we fill CInfo matrix - (2*NPoints-1)*3 matrix, + * with I-th row containing: + * * CInfo[I,0] - size of I-th cluster + * * CInfo[I,1] - beginning of I-th cluster + * * CInfo[I,2] - end of I-th cluster + * * CInfo[I,3] - height of I-th cluster + * + * We perform it as follows: + * * first NPoints clusters have unit size (CInfo[I,0]=1) and zero + * height (CInfo[I,3]=0) + * * we replay NPoints-1 merges from first to last and fill sizes of + * corresponding clusters (new size is a sum of sizes of clusters + * being merged) and height (new height is max(heights)+1). + * * now we ready to determine locations of clusters. Last cluster + * spans entire dataset, we know it. We replay merges from last to + * first, during each merge we already know location of the merge + * result, and we can position first cluster to the left part of + * the result, and second cluster to the right part. + */ + ae_vector_set_length(&rep->p, npoints, _state); + ae_matrix_set_length(&rep->pm, npoints-1, 6, _state); + ae_matrix_set_length(&cinfo, 2*npoints-1, 4, _state); + for(i=0; i<=npoints-1; i++) + { + cinfo.ptr.pp_int[i][0] = 1; + cinfo.ptr.pp_int[i][3] = 0; + } + for(i=0; i<=npoints-2; i++) + { + cinfo.ptr.pp_int[npoints+i][0] = cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][0]+cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][0]; + cinfo.ptr.pp_int[npoints+i][3] = ae_maxint(cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][0]][3], cinfo.ptr.pp_int[rep->z.ptr.pp_int[i][1]][3], _state)+1; + } + cinfo.ptr.pp_int[2*npoints-2][1] = 0; + cinfo.ptr.pp_int[2*npoints-2][2] = npoints-1; + for(i=npoints-2; i>=0; i--) + { + + /* + * We merge C0 which spans [A0,B0] and C1 (spans [A1,B1]), + * with unknown A0, B0, A1, B1. However, we know that result + * is CR, which spans [AR,BR] with known AR/BR, and we know + * sizes of C0, C1, CR (denotes as S0, S1, SR). + */ + c0 = rep->z.ptr.pp_int[i][0]; + c1 = rep->z.ptr.pp_int[i][1]; + s0 = cinfo.ptr.pp_int[c0][0]; + s1 = cinfo.ptr.pp_int[c1][0]; + ar = cinfo.ptr.pp_int[npoints+i][1]; + br = cinfo.ptr.pp_int[npoints+i][2]; + cinfo.ptr.pp_int[c0][1] = ar; + cinfo.ptr.pp_int[c0][2] = ar+s0-1; + cinfo.ptr.pp_int[c1][1] = br-(s1-1); + cinfo.ptr.pp_int[c1][2] = br; + rep->pm.ptr.pp_int[i][0] = cinfo.ptr.pp_int[c0][1]; + rep->pm.ptr.pp_int[i][1] = cinfo.ptr.pp_int[c0][2]; + rep->pm.ptr.pp_int[i][2] = cinfo.ptr.pp_int[c1][1]; + rep->pm.ptr.pp_int[i][3] = cinfo.ptr.pp_int[c1][2]; + rep->pm.ptr.pp_int[i][4] = cinfo.ptr.pp_int[c0][3]; + rep->pm.ptr.pp_int[i][5] = cinfo.ptr.pp_int[c1][3]; + } + for(i=0; i<=npoints-1; i++) + { + ae_assert(cinfo.ptr.pp_int[i][1]==cinfo.ptr.pp_int[i][2], "Assertion failed", _state); + rep->p.ptr.p_int[i] = cinfo.ptr.pp_int[i][1]; + } + + /* + * Calculate Rep.PZ + */ + ae_matrix_set_length(&rep->pz, npoints-1, 2, _state); + for(i=0; i<=npoints-2; i++) + { + rep->pz.ptr.pp_int[i][0] = rep->z.ptr.pp_int[i][0]; + rep->pz.ptr.pp_int[i][1] = rep->z.ptr.pp_int[i][1]; + if( rep->pz.ptr.pp_int[i][0]pz.ptr.pp_int[i][0] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][0]]; + } + if( rep->pz.ptr.pp_int[i][1]pz.ptr.pp_int[i][1] = rep->p.ptr.p_int[rep->pz.ptr.pp_int[i][1]]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function recursively evaluates distance matrix for SOME (not all!) +distance types. + +INPUT PARAMETERS: + XY - array[?,NFeatures], dataset + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + D - preallocated output matrix + I0,I1 - half interval of rows to calculate: [I0,I1) is processed + J0,J1 - half interval of cols to calculate: [J0,J1) is processed + +OUTPUT PARAMETERS: + D - array[NPoints,NPoints], distance matrix + upper triangle and main diagonal are initialized with + data. + +NOTE: intersection of [I0,I1) and [J0,J1) may completely lie in upper + triangle, only partially intersect with it, or have zero intersection. + In any case, only intersection of submatrix given by [I0,I1)*[J0,J1) + with upper triangle of the matrix is evaluated. + + Say, for 4x4 distance matrix A: + * [0,2)*[0,2) will result in evaluation of A00, A01, A11 + * [2,4)*[2,4) will result in evaluation of A22, A23, A32, A33 + * [2,4)*[0,2) will result in evaluation of empty set of elements + + + -- ALGLIB -- + Copyright 07.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void clustering_evaluatedistancematrixrec(/* Real */ const ae_matrix* xy, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, + ae_state *_state) +{ + double rcomplexity; + ae_int_t len0; + ae_int_t len1; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + + + ae_assert(disttype==0||disttype==1, "EvaluateDistanceMatrixRec: incorrect DistType", _state); + + /* + * Normalize J0/J1: + * * J0:=max(J0,I0) - we ignore lower triangle + * * J1:=max(J1,J0) - normalize J1 + */ + j0 = ae_maxint(j0, i0, _state); + j1 = ae_maxint(j1, j0, _state); + if( j1<=j0||i1<=i0 ) + { + return; + } + rcomplexity = clustering_complexitymultiplier*rmul3((double)(i1-i0), (double)(j1-j0), (double)(nfeatures), _state); + if( (i1-i0>2||j1-j0>2)&&ae_fp_greater_eq(rcomplexity,smpactivationlevel(_state)) ) + { + if( _trypexec_clustering_evaluatedistancematrixrec(xy,nfeatures,disttype,d,i0,i1,j0,j1, _state) ) + { + return; + } + } + + /* + * Try to process in parallel. Two condtions must hold in order to + * activate parallel processing: + * 1. I1-I0>2 or J1-J0>2 + * 2. (I1-I0)*(J1-J0)*NFeatures>=ParallelComplexity + * + * NOTE: all quantities are converted to reals in order to avoid + * integer overflow during multiplication + * + * NOTE: strict inequality in (1) is necessary to reduce task to 2x2 + * basecases. In future versions we will be able to handle such + * basecases more efficiently than 1x1 cases. + */ + if( ae_fp_greater_eq(rcomplexity,spawnlevel(_state))&&(i1-i0>2||j1-j0>2) ) + { + + /* + * Recursive division along largest of dimensions + */ + if( i1-i0>j1-j0 ) + { + splitlengtheven(i1-i0, &len0, &len1, _state); + clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i0+len0, j0, j1, _state); + clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0+len0, i1, j0, j1, _state); + } + else + { + splitlengtheven(j1-j0, &len0, &len1, _state); + clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0, j0+len0, _state); + clustering_evaluatedistancematrixrec(xy, nfeatures, disttype, d, i0, i1, j0+len0, j1, _state); + } + return; + } + + /* + * Sequential processing + */ + for(i=i0; i<=i1-1; i++) + { + for(j=j0; j<=j1-1; j++) + { + if( j>=i ) + { + v = 0.0; + if( disttype==0 ) + { + for(k=0; k<=nfeatures-1; k++) + { + vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; + if( ae_fp_less(vv,(double)(0)) ) + { + vv = -vv; + } + if( ae_fp_greater(vv,v) ) + { + v = vv; + } + } + } + if( disttype==1 ) + { + for(k=0; k<=nfeatures-1; k++) + { + vv = xy->ptr.pp_double[i][k]-xy->ptr.pp_double[j][k]; + if( ae_fp_less(vv,(double)(0)) ) + { + vv = -vv; + } + v = v+vv; + } + } + d->ptr.pp_double[i][j] = v; + } + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_clustering_evaluatedistancematrixrec(/* Real */ const ae_matrix* xy, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_int_t i0, + ae_int_t i1, + ae_int_t j0, + ae_int_t j1, + ae_state *_state) +{ + return ae_false; +} + + +void _kmeansbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + kmeansbuffers *p = (kmeansbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->ct, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ctbest, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xycbest, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xycprev, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->d2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->csizes, 0, DT_INT, _state, make_automatic); + _apbuffers_init(&p->initbuf, _state, make_automatic); + ae_shared_pool_init(&p->updatepool, _state, make_automatic); +} + + +void _kmeansbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + kmeansbuffers *dst = (kmeansbuffers*)_dst; + const kmeansbuffers *src = (const kmeansbuffers*)_src; + ae_matrix_init_copy(&dst->ct, &src->ct, _state, make_automatic); + ae_matrix_init_copy(&dst->ctbest, &src->ctbest, _state, make_automatic); + ae_vector_init_copy(&dst->xycbest, &src->xycbest, _state, make_automatic); + ae_vector_init_copy(&dst->xycprev, &src->xycprev, _state, make_automatic); + ae_vector_init_copy(&dst->d2, &src->d2, _state, make_automatic); + ae_vector_init_copy(&dst->csizes, &src->csizes, _state, make_automatic); + _apbuffers_init_copy(&dst->initbuf, &src->initbuf, _state, make_automatic); + ae_shared_pool_init_copy(&dst->updatepool, &src->updatepool, _state, make_automatic); +} + + +void _kmeansbuffers_clear(void* _p) +{ + kmeansbuffers *p = (kmeansbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->ct); + ae_matrix_clear(&p->ctbest); + ae_vector_clear(&p->xycbest); + ae_vector_clear(&p->xycprev); + ae_vector_clear(&p->d2); + ae_vector_clear(&p->csizes); + _apbuffers_clear(&p->initbuf); + ae_shared_pool_clear(&p->updatepool); +} + + +void _kmeansbuffers_destroy(void* _p) +{ + kmeansbuffers *p = (kmeansbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->ct); + ae_matrix_destroy(&p->ctbest); + ae_vector_destroy(&p->xycbest); + ae_vector_destroy(&p->xycprev); + ae_vector_destroy(&p->d2); + ae_vector_destroy(&p->csizes); + _apbuffers_destroy(&p->initbuf); + ae_shared_pool_destroy(&p->updatepool); +} + + +void _clusterizerstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + clusterizerstate *p = (clusterizerstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->d, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpd, 0, 0, DT_REAL, _state, make_automatic); + _apbuffers_init(&p->distbuf, _state, make_automatic); + _kmeansbuffers_init(&p->kmeanstmp, _state, make_automatic); +} + + +void _clusterizerstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + clusterizerstate *dst = (clusterizerstate*)_dst; + const clusterizerstate *src = (const clusterizerstate*)_src; + dst->npoints = src->npoints; + dst->nfeatures = src->nfeatures; + dst->disttype = src->disttype; + ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic); + ae_matrix_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->ahcalgo = src->ahcalgo; + dst->kmeansrestarts = src->kmeansrestarts; + dst->kmeansmaxits = src->kmeansmaxits; + dst->kmeansinitalgo = src->kmeansinitalgo; + dst->kmeansdbgnoits = src->kmeansdbgnoits; + dst->seed = src->seed; + ae_matrix_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic); + _apbuffers_init_copy(&dst->distbuf, &src->distbuf, _state, make_automatic); + _kmeansbuffers_init_copy(&dst->kmeanstmp, &src->kmeanstmp, _state, make_automatic); +} + + +void _clusterizerstate_clear(void* _p) +{ + clusterizerstate *p = (clusterizerstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->xy); + ae_matrix_clear(&p->d); + ae_matrix_clear(&p->tmpd); + _apbuffers_clear(&p->distbuf); + _kmeansbuffers_clear(&p->kmeanstmp); +} + + +void _clusterizerstate_destroy(void* _p) +{ + clusterizerstate *p = (clusterizerstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->xy); + ae_matrix_destroy(&p->d); + ae_matrix_destroy(&p->tmpd); + _apbuffers_destroy(&p->distbuf); + _kmeansbuffers_destroy(&p->kmeanstmp); +} + + +void _ahcreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ahcreport *p = (ahcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->p, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->z, 0, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->pz, 0, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->pm, 0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->mergedist, 0, DT_REAL, _state, make_automatic); +} + + +void _ahcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ahcreport *dst = (ahcreport*)_dst; + const ahcreport *src = (const ahcreport*)_src; + dst->terminationtype = src->terminationtype; + dst->npoints = src->npoints; + ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic); + ae_matrix_init_copy(&dst->z, &src->z, _state, make_automatic); + ae_matrix_init_copy(&dst->pz, &src->pz, _state, make_automatic); + ae_matrix_init_copy(&dst->pm, &src->pm, _state, make_automatic); + ae_vector_init_copy(&dst->mergedist, &src->mergedist, _state, make_automatic); +} + + +void _ahcreport_clear(void* _p) +{ + ahcreport *p = (ahcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->p); + ae_matrix_clear(&p->z); + ae_matrix_clear(&p->pz); + ae_matrix_clear(&p->pm); + ae_vector_clear(&p->mergedist); +} + + +void _ahcreport_destroy(void* _p) +{ + ahcreport *p = (ahcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->p); + ae_matrix_destroy(&p->z); + ae_matrix_destroy(&p->pz); + ae_matrix_destroy(&p->pm); + ae_vector_destroy(&p->mergedist); +} + + +void _kmeansreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + kmeansreport *p = (kmeansreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cidx, 0, DT_INT, _state, make_automatic); +} + + +void _kmeansreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + kmeansreport *dst = (kmeansreport*)_dst; + const kmeansreport *src = (const kmeansreport*)_src; + dst->npoints = src->npoints; + dst->nfeatures = src->nfeatures; + dst->terminationtype = src->terminationtype; + dst->iterationscount = src->iterationscount; + dst->energy = src->energy; + dst->k = src->k; + ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->cidx, &src->cidx, _state, make_automatic); +} + + +void _kmeansreport_clear(void* _p) +{ + kmeansreport *p = (kmeansreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->c); + ae_vector_clear(&p->cidx); +} + + +void _kmeansreport_destroy(void* _p) +{ + kmeansreport *p = (kmeansreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->c); + ae_vector_destroy(&p->cidx); +} + + +#endif +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel inference requests. + +DF subpackage provides two sets of computing functions - ones which use +internal buffer of DF model (these functions are single-threaded because +they use same buffer, which can not shared between threads), and ones +which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + Model - DF model which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with model which was used to + initialize buffer. Any attempt to use buffer with different + object is dangerous - you may get integrity check failure + (exception) because sizes of internal arrays do not fit to + dimensions of the model structure. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void dfcreatebuffer(const decisionforest* model, + decisionforestbuffer* buf, + ae_state *_state) +{ + + _decisionforestbuffer_clear(buf); + + ae_vector_set_length(&buf->x, model->nvars, _state); + ae_vector_set_length(&buf->y, model->nclasses, _state); +} + + +/************************************************************************* +This subroutine creates DecisionForestBuilder object which is used to +train decision forests. + +By default, new builder stores empty dataset and some reasonable default +settings. At the very least, you should specify dataset prior to building +decision forest. You can also tweak settings of the forest construction +algorithm (recommended, although default setting should work well). + +Following actions are mandatory: +* calling dfbuildersetdataset() to specify dataset +* calling dfbuilderbuildrandomforest() to build decision forest using + current dataset and default settings + +Additionally, you may call: +* dfbuildersetrndvars() or dfbuildersetrndvarsratio() to specify number of + variables randomly chosen for each split +* dfbuildersetsubsampleratio() to specify fraction of the dataset randomly + subsampled to build each tree +* dfbuildersetseed() to control random seed chosen for tree construction + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildercreate(decisionforestbuilder* s, ae_state *_state) +{ + + _decisionforestbuilder_clear(s); + + + /* + * Empty dataset + */ + s->dstype = -1; + s->npoints = 0; + s->nvars = 0; + s->nclasses = 1; + + /* + * Default training settings + */ + s->rdfalgo = 0; + s->rdfratio = 0.5; + s->rdfvars = 0.0; + s->rdfglobalseed = 0; + s->rdfsplitstrength = 2; + s->rdfimportance = 0; + + /* + * Other fields + */ + s->rdfprogress = 0; + s->rdftotal = 1; +} + + +/************************************************************************* +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the forest construction algorithm will be invoked. + +INPUT PARAMETERS: + S - decision forest builder object + XY - array[NPoints,NVars+1] (minimum size; actual size can + be larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * last column store class number (in 0...NClasses-1) + or real value of the dependent variable + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - indicates type of the problem being solved: + * NClasses>=2 means that classification problem is + solved (last column of the dataset stores class + number) + * NClasses=1 means that regression problem is solved + (last column of the dataset stores variable value) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetdataset(decisionforestbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + + /* + * Check parameters + */ + ae_assert(npoints>=1, "dfbuildersetdataset: npoints<1", _state); + ae_assert(nvars>=1, "dfbuildersetdataset: nvars<1", _state); + ae_assert(nclasses>=1, "dfbuildersetdataset: nclasses<1", _state); + ae_assert(xy->rows>=npoints, "dfbuildersetdataset: rows(xy)cols>=nvars+1, "dfbuildersetdataset: cols(xy)1 ) + { + for(i=0; i<=npoints-1; i++) + { + j = ae_round(xy->ptr.pp_double[i][nvars], _state); + ae_assert(j>=0&&jdstype = 0; + s->npoints = npoints; + s->nvars = nvars; + s->nclasses = nclasses; + rvectorsetlengthatleast(&s->dsdata, npoints*nvars, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + s->dsdata.ptr.p_double[j*npoints+i] = xy->ptr.pp_double[i][j]; + } + } + if( nclasses>1 ) + { + ivectorsetlengthatleast(&s->dsival, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + s->dsival.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nvars], _state); + } + } + else + { + rvectorsetlengthatleast(&s->dsrval, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + s->dsrval.ptr.p_double[i] = xy->ptr.pp_double[i][nvars]; + } + } +} + + +/************************************************************************* +This function sets number of variables (in [1,NVars] range) used by +decision forest construction algorithm. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + RndVars - number of randomly selected variables; values outside + of [1,NVars] range are silently clipped. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvars(decisionforestbuilder* s, + ae_int_t rndvars, + ae_state *_state) +{ + + + s->rdfvars = (double)(ae_maxint(rndvars, 1, _state)); +} + + +/************************************************************************* +This function sets number of variables used by decision forest construction +algorithm as a fraction of total variable count (0,1) range. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + F - round(NVars*F) variables are selected + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsratio(decisionforestbuilder* s, + double f, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(f, _state), "dfbuildersetrndvarsratio: F is INF or NAN", _state); + s->rdfvars = -ae_maxreal(f, ae_machineepsilon, _state); +} + + +/************************************************************************* +This function tells decision forest builder to automatically choose number +of variables used by decision forest construction algorithm. Roughly +sqrt(NVars) variables will be used. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsauto(decisionforestbuilder* s, ae_state *_state) +{ + + + s->rdfvars = (double)(0); +} + + +/************************************************************************* +This function sets size of dataset subsample generated the decision forest +construction algorithm. Size is specified as a fraction of total dataset +size. + +The default option is to use 50% of the dataset for training, 50% for the +OOB estimates. You can decrease fraction F down to 10%, 1% or even below +in order to reduce overfitting. + +INPUT PARAMETERS: + S - decision forest builder object + F - fraction of the dataset to use, in (0,1] range. Values + outside of this range will be silently clipped. At + least one element is always selected for the training + set. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetsubsampleratio(decisionforestbuilder* s, + double f, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(f, _state), "dfbuildersetrndvarsfraction: F is INF or NAN", _state); + s->rdfratio = ae_maxreal(f, ae_machineepsilon, _state); +} + + +/************************************************************************* +This function sets seed used by internal RNG for random subsampling and +random selection of variable subsets. + +By default random seed is used, i.e. every time you build decision forest, +we seed generator with new value obtained from system-wide RNG. Thus, +decision forest builder returns non-deterministic results. You can change +such behavior by specyfing fixed positive seed value. + +INPUT PARAMETERS: + S - decision forest builder object + SeedVal - seed value: + * positive values are used for seeding RNG with fixed + seed, i.e. subsequent runs on same data will return + same decision forests + * non-positive seed means that random seed is used + for every run of builder, i.e. subsequent runs on + same datasets will return slightly different + decision forests + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetseed(decisionforestbuilder* s, + ae_int_t seedval, + ae_state *_state) +{ + + + s->rdfglobalseed = seedval; +} + + +/************************************************************************* +This function sets random decision forest construction algorithm. + +As for now, only one decision forest construction algorithm is supported - +a dense "baseline" RDF algorithm. + +INPUT PARAMETERS: + S - decision forest builder object + AlgoType - algorithm type: + * 0 = baseline dense RDF + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfalgo(decisionforestbuilder* s, + ae_int_t algotype, + ae_state *_state) +{ + + + ae_assert(algotype==0, "dfbuildersetrdfalgo: unexpected algotype", _state); + s->rdfalgo = algotype; +} + + +/************************************************************************* +This function sets split selection algorithm used by decision forest +classifier. You may choose several algorithms, with different speed and +quality of the results. + +INPUT PARAMETERS: + S - decision forest builder object + SplitStrength- split type: + * 0 = split at the random position, fastest one + * 1 = split at the middle of the range + * 2 = strong split at the best point of the range (default) + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfsplitstrength(decisionforestbuilder* s, + ae_int_t splitstrength, + ae_state *_state) +{ + + + ae_assert((splitstrength==0||splitstrength==1)||splitstrength==2, "dfbuildersetrdfsplitstrength: unexpected split type", _state); + s->rdfsplitstrength = splitstrength; +} + + +/************************************************************************* +This function tells decision forest construction algorithm to use +Gini impurity based variable importance estimation (also known as MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on training sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and beautifully normalized (sum to +one) but have following downsides: +* They ALWAYS sum to 1.0, even if output is completely unpredictable. I.e. + MDI allows to order variables by importance, but does not tell us about + "absolute" importances of variables +* there exist some bias towards continuous and high-cardinality categorical + variables + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancetrngini(decisionforestbuilder* s, + ae_state *_state) +{ + + + s->rdfimportance = dforest_needtrngini; +} + + +/************************************************************************* +This function tells decision forest construction algorithm to use +out-of-bag version of Gini variable importance estimation (also known as +OOB-MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on out-of-bag sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and resistant to overfitting issues +(thanks to the out-of-bag estimates used). However, OOB Gini rating has +following downsides: +* there exist some bias towards continuous and high-cardinality categorical + variables +* Gini rating allows us to order variables by importance, but it is hard + to define importance of the variable by itself. + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportanceoobgini(decisionforestbuilder* s, + ae_state *_state) +{ + + + s->rdfimportance = dforest_needoobgini; +} + + +/************************************************************************* +This function tells decision forest construction algorithm to use +permutation variable importance estimator (also known as MDA). + +This version of importance estimation algorithm analyzes mean increase in +out-of-bag sum of squared residuals after random permutation of J-th +variable. The result is divided by error computed with all variables being +perturbed in order to produce R-squared-like estimate in [0,1] range. + +Such estimate is slower to calculate than Gini-based rating because it +needs multiple inference runs for each of variables being studied. + +ALGLIB uses parallelized and highly optimized algorithm which analyzes +path through the decision tree and allows to handle most perturbations +in O(1) time; nevertheless, requesting MDA importances may increase forest +construction time from 10% to 200% (or more, if you have thousands of +variables). + +However, MDA rating has following benefits over Gini-based ones: +* no bias towards specific variable types +* ability to directly evaluate "absolute" importance of some variable at + "0 to 1" scale (contrary to Gini-based rating, which returns comparative + importances). + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancepermutation(decisionforestbuilder* s, + ae_state *_state) +{ + + + s->rdfimportance = dforest_needpermutation; +} + + +/************************************************************************* +This function tells decision forest construction algorithm to skip +variable importance estimation. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will result in forest being built + without variable importance estimation. + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancenone(decisionforestbuilder* s, + ae_state *_state) +{ + + + s->rdfimportance = 0; +} + + +/************************************************************************* +This function is an alias for dfbuilderpeekprogress(), left in ALGLIB for +backward compatibility reasons. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuildergetprogress(const decisionforestbuilder* s, + ae_state *_state) +{ + double result; + + + result = dfbuilderpeekprogress(s, _state); + return result; +} + + +/************************************************************************* +This function is used to peek into decision forest construction process +from some other thread and get current progress indicator. + +It returns value in [0,1]. + +INPUT PARAMETERS: + S - decision forest builder object used to build forest + in some other thread + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuilderpeekprogress(const decisionforestbuilder* s, + ae_state *_state) +{ + double result; + + + result = (double)s->rdfprogress/ae_maxreal((double)(s->rdftotal), (double)(1), _state); + result = ae_maxreal(result, (double)(0), _state); + result = ae_minreal(result, (double)(1), _state); + return result; +} + + +/************************************************************************* +This subroutine builds decision forest according to current settings using +dataset internally stored in the builder object. Dense algorithm is used. + +NOTE: this function uses dense algorithm for forest construction + independently from the dataset format (dense or sparse). + +NOTE: forest built with this function is stored in-memory using 64-bit + data structures for offsets/indexes/split values. It is possible to + convert forest into more memory-efficient compressed binary + representation. Depending on the problem properties, 3.7x-5.7x + compression factors are possible. + + The downsides of compression are (a) slight reduction in the model + accuracy and (b) ~1.5x reduction in the inference speed (due to + increased complexity of the storage format). + + See comments on dfbinarycompression() for more info. + +Default settings are used by the algorithm; you can tweak them with the +help of the following functions: +* dfbuildersetrfactor() - to control a fraction of the dataset used for + subsampling +* dfbuildersetrandomvars() - to control number of variables randomly chosen + for decision rule creation + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - decision forest builder object + NTrees - NTrees>=1, number of trees to train + +OUTPUT PARAMETERS: + DF - decision forest. You can compress this forest to more + compact 16-bit representation with dfbinarycompression() + Rep - report, see below for information on its fields. + +=== report information produced by forest construction function ========== + +Decision forest training report includes following information: +* training set errors +* out-of-bag estimates of errors +* variable importance ratings + +Following fields are used to store information: +* training set errors are stored in rep.relclserror, rep.avgce, rep.rmserror, + rep.avgerror and rep.avgrelerror +* out-of-bag estimates of errors are stored in rep.oobrelclserror, rep.oobavgce, + rep.oobrmserror, rep.oobavgerror and rep.oobavgrelerror + +Variable importance reports, if requested by dfbuildersetimportancegini(), +dfbuildersetimportancetrngini() or dfbuildersetimportancepermutation() +call, are stored in: +* rep.varimportances field stores importance ratings +* rep.topvars stores variable indexes ordered from the most important to + less important ones + +You can find more information about report fields in: +* comments on dfreport structure +* comments on dfbuildersetimportancegini function +* comments on dfbuildersetimportancetrngini function +* comments on dfbuildersetimportancepermutation function + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuilderbuildrandomforest(decisionforestbuilder* s, + ae_int_t ntrees, + decisionforest* df, + dfreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t npoints; + ae_int_t trnsize; + ae_int_t maxtreesize; + ae_int_t sessionseed; + dfworkbuf workbufseed; + dfvotebuf votebufseed; + dftreebuf treebufseed; + + ae_frame_make(_state, &_frame_block); + memset(&workbufseed, 0, sizeof(workbufseed)); + memset(&votebufseed, 0, sizeof(votebufseed)); + memset(&treebufseed, 0, sizeof(treebufseed)); + _decisionforest_clear(df); + _dfreport_clear(rep); + _dfworkbuf_init(&workbufseed, _state, ae_true); + _dfvotebuf_init(&votebufseed, _state, ae_true); + _dftreebuf_init(&treebufseed, _state, ae_true); + + ae_assert(ntrees>=1, "DFBuilderBuildRandomForest: ntrees<1", _state); + dforest_cleanreport(s, rep, _state); + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + + /* + * Set up progress counter + */ + s->rdfprogress = 0; + s->rdftotal = ntrees*npoints; + if( s->rdfimportance==dforest_needpermutation ) + { + s->rdftotal = s->rdftotal+ntrees*npoints; + } + + /* + * Quick exit for empty dataset + */ + if( s->dstype==-1||npoints==0 ) + { + ae_assert(dforest_leafnodewidth==2, "DFBuilderBuildRandomForest: integrity check failed", _state); + df->forestformat = dforest_dfuncompressedv0; + df->nvars = s->nvars; + df->nclasses = s->nclasses; + df->ntrees = 1; + df->bufsize = 1+dforest_leafnodewidth; + ae_vector_set_length(&df->trees, 1+dforest_leafnodewidth, _state); + df->trees.ptr.p_double[0] = (double)(1+dforest_leafnodewidth); + df->trees.ptr.p_double[1] = (double)(-1); + df->trees.ptr.p_double[2] = 0.0; + dfcreatebuffer(df, &df->buffer, _state); + ae_frame_leave(_state); + return; + } + ae_assert(npoints>0, "DFBuilderBuildRandomForest: integrity check failed", _state); + + /* + * Analyze dataset statistics, perform preprocessing + */ + dforest_analyzeandpreprocessdataset(s, _state); + + /* + * Prepare "work", "vote" and "tree" pools and other settings + */ + trnsize = ae_round((double)npoints*s->rdfratio, _state); + trnsize = ae_maxint(trnsize, 1, _state); + trnsize = ae_minint(trnsize, npoints, _state); + maxtreesize = 1+dforest_innernodewidth*(trnsize-1)+dforest_leafnodewidth*trnsize; + ae_vector_set_length(&workbufseed.varpool, nvars, _state); + ae_vector_set_length(&workbufseed.trnset, trnsize, _state); + ae_vector_set_length(&workbufseed.oobset, npoints-trnsize, _state); + ae_vector_set_length(&workbufseed.tmp0i, npoints, _state); + ae_vector_set_length(&workbufseed.tmp1i, npoints, _state); + ae_vector_set_length(&workbufseed.tmp0r, npoints, _state); + ae_vector_set_length(&workbufseed.tmp1r, npoints, _state); + ae_vector_set_length(&workbufseed.tmp2r, npoints, _state); + ae_vector_set_length(&workbufseed.tmp3r, npoints, _state); + ae_vector_set_length(&workbufseed.trnlabelsi, npoints, _state); + ae_vector_set_length(&workbufseed.trnlabelsr, npoints, _state); + ae_vector_set_length(&workbufseed.ooblabelsi, npoints, _state); + ae_vector_set_length(&workbufseed.ooblabelsr, npoints, _state); + ae_vector_set_length(&workbufseed.curvals, npoints, _state); + ae_vector_set_length(&workbufseed.bestvals, npoints, _state); + ae_vector_set_length(&workbufseed.classpriors, nclasses, _state); + ae_vector_set_length(&workbufseed.classtotals0, nclasses, _state); + ae_vector_set_length(&workbufseed.classtotals1, nclasses, _state); + ae_vector_set_length(&workbufseed.classtotals01, 2*nclasses, _state); + ae_vector_set_length(&workbufseed.treebuf, maxtreesize, _state); + workbufseed.trnsize = trnsize; + workbufseed.oobsize = npoints-trnsize; + ae_vector_set_length(&votebufseed.trntotals, npoints*nclasses, _state); + ae_vector_set_length(&votebufseed.oobtotals, npoints*nclasses, _state); + for(i=0; i<=npoints*nclasses-1; i++) + { + votebufseed.trntotals.ptr.p_double[i] = (double)(0); + votebufseed.oobtotals.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&votebufseed.trncounts, npoints, _state); + ae_vector_set_length(&votebufseed.oobcounts, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + votebufseed.trncounts.ptr.p_int[i] = 0; + votebufseed.oobcounts.ptr.p_int[i] = 0; + } + ae_vector_set_length(&votebufseed.giniimportances, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + votebufseed.giniimportances.ptr.p_double[i] = 0.0; + } + treebufseed.treeidx = -1; + ae_shared_pool_set_seed(&s->workpool, &workbufseed, (ae_int_t)sizeof(workbufseed), (ae_copy_constructor)_dfworkbuf_init_copy, (ae_destructor)_dfworkbuf_destroy, _state); + ae_shared_pool_set_seed(&s->votepool, &votebufseed, (ae_int_t)sizeof(votebufseed), (ae_copy_constructor)_dfvotebuf_init_copy, (ae_destructor)_dfvotebuf_destroy, _state); + ae_shared_pool_set_seed(&s->treepool, &treebufseed, (ae_int_t)sizeof(treebufseed), (ae_copy_constructor)_dftreebuf_init_copy, (ae_destructor)_dftreebuf_destroy, _state); + ae_shared_pool_set_seed(&s->treefactory, &treebufseed, (ae_int_t)sizeof(treebufseed), (ae_copy_constructor)_dftreebuf_init_copy, (ae_destructor)_dftreebuf_destroy, _state); + + /* + * Select session seed (individual trees are constructed using + * combination of session and local seeds). + */ + sessionseed = s->rdfglobalseed; + if( s->rdfglobalseed<=0 ) + { + sessionseed = ae_randominteger(30000, _state); + } + + /* + * Prepare In-and-Out-of-Bag matrix, if needed + */ + s->neediobmatrix = s->rdfimportance==dforest_needpermutation; + if( s->neediobmatrix ) + { + + /* + * Prepare default state of In-and-Out-of-Bag matrix + */ + bmatrixsetlengthatleast(&s->iobmatrix, ntrees, npoints, _state); + for(i=0; i<=ntrees-1; i++) + { + for(j=0; j<=npoints-1; j++) + { + s->iobmatrix.ptr.pp_bool[i][j] = ae_false; + } + } + } + + /* + * Build trees (in parallel, if possible) + */ + dforest_buildrandomtree(s, 0, ntrees, _state); + + /* + * Merge trees and output result + */ + dforest_mergetrees(s, df, _state); + + /* + * Process voting results and output training set and OOB errors. + * Finalize tree construction. + */ + dforest_processvotingresults(s, ntrees, &votebufseed, rep, _state); + dfcreatebuffer(df, &df->buffer, _state); + + /* + * Perform variable importance estimation + */ + dforest_estimatevariableimportance(s, sessionseed, df, ntrees, rep, _state); + + /* + * Update progress counter + */ + s->rdfprogress = s->rdftotal; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs binary compression of the decision forest. + +Original decision forest produced by the forest builder is stored using +64-bit representation for all numbers - offsets, variable indexes, split +points. + +It is possible to significantly reduce model size by means of: +* using compressed dynamic encoding for integers (offsets and variable + indexes), which uses just 1 byte to store small ints (less than 128), + just 2 bytes for larger values (less than 128^2) and so on +* storing floating point numbers using 8-bit exponent and 16-bit mantissa + +As result, model needs significantly less memory (compression factor +depends on variable and class counts). In particular: +* NVars<128 and NClasses<128 result in 4.4x-5.7x model size reduction +* NVars<16384 and NClasses<128 result in 3.7x-4.5x model size reduction + +Such storage format performs lossless compression of all integers, but +compression of floating point values (split values) is lossy, with roughly +0.01% relative error introduced during rounding. Thus, we recommend you to +re-evaluate model accuracy after compression. + +Another downside of compression is ~1.5x reduction in the inference +speed due to necessity of dynamic decompression of the compressed model. + +INPUT PARAMETERS: + DF - decision forest built by forest builder + +OUTPUT PARAMETERS: + DF - replaced by compressed forest + +RESULT: + compression factor (in-RAM size of the compressed model vs than of the + uncompressed one), positive number larger than 1.0 + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +double dfbinarycompression(decisionforest* df, ae_state *_state) +{ + double result; + + + result = dforest_binarycompression(df, ae_false, _state); + return result; +} + + +/************************************************************************* +This is a 8-bit version of dfbinarycompression. +Not recommended for external use because it is too lossy. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +double dfbinarycompression8(decisionforest* df, ae_state *_state) +{ + double result; + + + result = dforest_binarycompression(df, ae_true, _state); + return result; +} + + +/************************************************************************* +Inference using decision forest + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + +INPUT PARAMETERS: + DF - decision forest model + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfprocess(const decisionforest* df, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t offs; + ae_int_t i; + double v; + ae_int_t treesize; + ae_bool processed; + + + + /* + * Process + * + * Although comments above warn you about thread-unsafety of this + * function, it is de facto thread-safe. However, thread safety is + * an accidental side-effect of the specific inference algorithm + * being used. It may disappear in the future versions of the DF + * models, so you should NOT rely on it. + */ + if( y->cntnclasses ) + { + ae_vector_set_length(y, df->nclasses, _state); + } + for(i=0; i<=df->nclasses-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + processed = ae_false; + if( df->forestformat==dforest_dfuncompressedv0 ) + { + + /* + * Process trees stored in uncompressed format + */ + offs = 0; + for(i=0; i<=df->ntrees-1; i++) + { + dforest_dfprocessinternaluncompressed(df, offs, offs+1, x, y, _state); + offs = offs+ae_round(df->trees.ptr.p_double[offs], _state); + } + processed = ae_true; + } + if( df->forestformat==dforest_dfcompressedv0 ) + { + + /* + * Process trees stored in compressed format + */ + offs = 0; + for(i=0; i<=df->ntrees-1; i++) + { + treesize = dforest_unstreamuint(&df->trees8, &offs, _state); + dforest_dfprocessinternalcompressed(df, offs, x, y, _state); + offs = offs+treesize; + } + processed = ae_true; + } + ae_assert(processed, "DFProcess: integrity check failed (unexpected format?)", _state); + v = (double)1/(double)df->ntrees; + ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,df->nclasses-1), v); +} + + +/************************************************************************* +'interactive' variant of DFProcess for languages like Python which support +constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void dfprocessi(const decisionforest* df, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + dfprocess(df, x, y, _state); +} + + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for dfprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - DF model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double dfprocess0(decisionforest* model, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nvars; + double result; + + + nvars = model->nvars; + for(i=0; i<=nvars-1; i++) + { + model->buffer.x.ptr.p_double[i] = x->ptr.p_double[i]; + } + dfprocess(model, &model->buffer.x, &model->buffer.y, _state); + result = model->buffer.y.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling dfprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - decision forest model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t dfclassify(decisionforest* model, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nvars; + ae_int_t nout; + ae_int_t result; + + + if( model->nclasses<2 ) + { + result = -1; + return result; + } + nvars = model->nvars; + nout = model->nclasses; + for(i=0; i<=nvars-1; i++) + { + model->buffer.x.ptr.p_double[i] = x->ptr.p_double[i]; + } + dfprocess(model, &model->buffer.x, &model->buffer.y, _state); + result = 0; + for(i=1; i<=nout-1; i++) + { + if( model->buffer.y.ptr.p_double[i]>model->buffer.y.ptr.p_double[result] ) + { + result = i; + } + } + return result; +} + + +/************************************************************************* +Inference using decision forest + +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same DF model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + DF - decision forest model + Buf - buffer object, must be allocated specifically for this + model with dfcreatebuffer(). + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dftsprocess(const decisionforest* df, + decisionforestbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + + /* + * Although docs warn you about thread-unsafety of the dfprocess() + * function, it is de facto thread-safe. However, thread safety is + * an accidental side-effect of the specific inference algorithm + * being used. It may disappear in the future versions of the DF + * models, so you should NOT rely on it. + */ + dfprocess(df, x, y, _state); +} + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrelclserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + result = (double)dforest_dfclserror(df, xy, npoints, _state)/(double)npoints; + return result; +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgce(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t tmpi; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&x, df->nvars-1+1, _state); + ae_vector_set_length(&y, df->nclasses-1+1, _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); + dfprocess(df, &x, &y, _state); + if( df->nclasses>1 ) + { + + /* + * classification-specific code + */ + k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); + tmpi = 0; + for(j=1; j<=df->nclasses-1; j++) + { + if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) + { + tmpi = j; + } + } + if( ae_fp_neq(y.ptr.p_double[k],(double)(0)) ) + { + result = result-ae_log(y.ptr.p_double[k], _state); + } + else + { + result = result-ae_log(ae_minrealnumber, _state); + } + } + } + result = result/(double)npoints; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for + classification task, RMS error means error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrmserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t tmpi; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&x, df->nvars-1+1, _state); + ae_vector_set_length(&y, df->nclasses-1+1, _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); + dfprocess(df, &x, &y, _state); + if( df->nclasses>1 ) + { + + /* + * classification-specific code + */ + k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); + tmpi = 0; + for(j=1; j<=df->nclasses-1; j++) + { + if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) + { + tmpi = j; + } + } + for(j=0; j<=df->nclasses-1; j++) + { + if( j==k ) + { + result = result+ae_sqr(y.ptr.p_double[j]-(double)1, _state); + } + else + { + result = result+ae_sqr(y.ptr.p_double[j], _state); + } + } + } + else + { + + /* + * regression-specific code + */ + result = result+ae_sqr(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); + } + } + result = ae_sqrt(result/(double)(npoints*df->nclasses), _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgerror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&x, df->nvars-1+1, _state); + ae_vector_set_length(&y, df->nclasses-1+1, _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); + dfprocess(df, &x, &y, _state); + if( df->nclasses>1 ) + { + + /* + * classification-specific code + */ + k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); + for(j=0; j<=df->nclasses-1; j++) + { + if( j==k ) + { + result = result+ae_fabs(y.ptr.p_double[j]-(double)1, _state); + } + else + { + result = result+ae_fabs(y.ptr.p_double[j], _state); + } + } + } + else + { + + /* + * regression-specific code + */ + result = result+ae_fabs(y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars], _state); + } + } + result = result/(double)(npoints*df->nclasses); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average relative error when estimating + posterior probability of belonging to the correct class. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgrelerror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t relcnt; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&x, df->nvars-1+1, _state); + ae_vector_set_length(&y, df->nclasses-1+1, _state); + result = (double)(0); + relcnt = 0; + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); + dfprocess(df, &x, &y, _state); + if( df->nclasses>1 ) + { + + /* + * classification-specific code + */ + k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); + for(j=0; j<=df->nclasses-1; j++) + { + if( j==k ) + { + result = result+ae_fabs(y.ptr.p_double[j]-(double)1, _state); + relcnt = relcnt+1; + } + } + } + else + { + + /* + * regression-specific code + */ + if( ae_fp_neq(xy->ptr.pp_double[i][df->nvars],(double)(0)) ) + { + result = result+ae_fabs((y.ptr.p_double[0]-xy->ptr.pp_double[i][df->nvars])/xy->ptr.pp_double[i][df->nvars], _state); + relcnt = relcnt+1; + } + } + } + if( relcnt>0 ) + { + result = result/(double)relcnt; + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Copying of DecisionForest strucure + +INPUT PARAMETERS: + DF1 - original + +OUTPUT PARAMETERS: + DF2 - copy + + -- ALGLIB -- + Copyright 13.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfcopy(const decisionforest* df1, + decisionforest* df2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t bufsize; + + _decisionforest_clear(df2); + + if( df1->forestformat==dforest_dfuncompressedv0 ) + { + df2->forestformat = df1->forestformat; + df2->nvars = df1->nvars; + df2->nclasses = df1->nclasses; + df2->ntrees = df1->ntrees; + df2->bufsize = df1->bufsize; + ae_vector_set_length(&df2->trees, df1->bufsize, _state); + ae_v_move(&df2->trees.ptr.p_double[0], 1, &df1->trees.ptr.p_double[0], 1, ae_v_len(0,df1->bufsize-1)); + dfcreatebuffer(df2, &df2->buffer, _state); + return; + } + if( df1->forestformat==dforest_dfcompressedv0 ) + { + df2->forestformat = df1->forestformat; + df2->usemantissa8 = df1->usemantissa8; + df2->nvars = df1->nvars; + df2->nclasses = df1->nclasses; + df2->ntrees = df1->ntrees; + bufsize = df1->trees8.cnt; + ae_vector_set_length(&(df2->trees8), bufsize, _state); + for(i=0; i<=bufsize-1; i++) + { + df2->trees8.ptr.p_ubyte[i] = (unsigned char)(df1->trees8.ptr.p_ubyte[i]); + } + dfcreatebuffer(df2, &df2->buffer, _state); + return; + } + ae_assert(ae_false, "DFCopy: unexpected forest format", _state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void dfalloc(ae_serializer* s, + const decisionforest* forest, + ae_state *_state) +{ + + + if( forest->forestformat==dforest_dfuncompressedv0 ) + { + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &forest->trees, forest->bufsize, _state); + return; + } + if( forest->forestformat==dforest_dfcompressedv0 ) + { + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_byte_array(s, &forest->trees8); + return; + } + ae_assert(ae_false, "DFAlloc: unexpected forest format", _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void dfserialize(ae_serializer* s, + const decisionforest* forest, + ae_state *_state) +{ + + + if( forest->forestformat==dforest_dfuncompressedv0 ) + { + ae_serializer_serialize_int(s, getrdfserializationcode(_state), _state); + ae_serializer_serialize_int(s, dforest_dfuncompressedv0, _state); + ae_serializer_serialize_int(s, forest->nvars, _state); + ae_serializer_serialize_int(s, forest->nclasses, _state); + ae_serializer_serialize_int(s, forest->ntrees, _state); + ae_serializer_serialize_int(s, forest->bufsize, _state); + serializerealarray(s, &forest->trees, forest->bufsize, _state); + return; + } + if( forest->forestformat==dforest_dfcompressedv0 ) + { + ae_serializer_serialize_int(s, getrdfserializationcode(_state), _state); + ae_serializer_serialize_int(s, forest->forestformat, _state); + ae_serializer_serialize_bool(s, forest->usemantissa8, _state); + ae_serializer_serialize_int(s, forest->nvars, _state); + ae_serializer_serialize_int(s, forest->nclasses, _state); + ae_serializer_serialize_int(s, forest->ntrees, _state); + ae_serializer_serialize_byte_array(s, &forest->trees8, _state); + return; + } + ae_assert(ae_false, "DFSerialize: unexpected forest format", _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 14.03.2011 by Bochkanov Sergey +*************************************************************************/ +void dfunserialize(ae_serializer* s, + decisionforest* forest, + ae_state *_state) +{ + ae_int_t i0; + ae_int_t forestformat; + ae_bool processed; + + _decisionforest_clear(forest); + + + /* + * check correctness of header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getrdfserializationcode(_state), "DFUnserialize: stream header corrupted", _state); + + /* + * Read forest + */ + ae_serializer_unserialize_int(s, &forestformat, _state); + processed = ae_false; + if( forestformat==dforest_dfuncompressedv0 ) + { + + /* + * Unserialize data + */ + forest->forestformat = forestformat; + ae_serializer_unserialize_int(s, &forest->nvars, _state); + ae_serializer_unserialize_int(s, &forest->nclasses, _state); + ae_serializer_unserialize_int(s, &forest->ntrees, _state); + ae_serializer_unserialize_int(s, &forest->bufsize, _state); + unserializerealarray(s, &forest->trees, _state); + processed = ae_true; + } + if( forestformat==dforest_dfcompressedv0 ) + { + + /* + * Unserialize data + */ + forest->forestformat = forestformat; + ae_serializer_unserialize_bool(s, &forest->usemantissa8, _state); + ae_serializer_unserialize_int(s, &forest->nvars, _state); + ae_serializer_unserialize_int(s, &forest->nclasses, _state); + ae_serializer_unserialize_int(s, &forest->ntrees, _state); + ae_serializer_unserialize_byte_array(s, &forest->trees8, _state); + processed = ae_true; + } + ae_assert(processed, "DFUnserialize: unexpected forest format", _state); + + /* + * Prepare buffer + */ + dfcreatebuffer(forest, &forest->buffer, _state); +} + + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforest(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + double r, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state) +{ + ae_int_t samplesize; + + *info = 0; + _decisionforest_clear(df); + _dfreport_clear(rep); + + if( ae_fp_less_eq(r,(double)(0))||ae_fp_greater(r,(double)(1)) ) + { + *info = -1; + return; + } + samplesize = ae_maxint(ae_round(r*(double)npoints, _state), 1, _state); + dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, ae_maxint(nvars/2, 1, _state), dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); +} + + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforestx1(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + ae_int_t nrndvars, + double r, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state) +{ + ae_int_t samplesize; + + *info = 0; + _decisionforest_clear(df); + _dfreport_clear(rep); + + if( ae_fp_less_eq(r,(double)(0))||ae_fp_greater(r,(double)(1)) ) + { + *info = -1; + return; + } + if( nrndvars<=0||nrndvars>nvars ) + { + *info = -1; + return; + } + samplesize = ae_maxint(ae_round(r*(double)npoints, _state), 1, _state); + dfbuildinternal(xy, npoints, nvars, nclasses, ntrees, samplesize, nrndvars, dforest_dfusestrongsplits+dforest_dfuseevs, info, df, rep, _state); +} + + +void dfbuildinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + ae_int_t samplesize, + ae_int_t nfeatures, + ae_int_t flags, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + decisionforestbuilder builder; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&builder, 0, sizeof(builder)); + *info = 0; + _decisionforest_clear(df); + _dfreport_clear(rep); + _decisionforestbuilder_init(&builder, _state, ae_true); + + + /* + * Test for inputs + */ + if( (((((npoints<1||samplesize<1)||samplesize>npoints)||nvars<1)||nclasses<1)||ntrees<1)||nfeatures<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( nclasses>1 ) + { + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + *info = 1; + dfbuildercreate(&builder, _state); + dfbuildersetdataset(&builder, xy, npoints, nvars, nclasses, _state); + dfbuildersetsubsampleratio(&builder, (double)samplesize/(double)npoints, _state); + dfbuildersetrndvars(&builder, nfeatures, _state); + dfbuilderbuildrandomforest(&builder, ntrees, df, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Builds a range of random trees [TreeIdx0,TreeIdx1) using decision forest +algorithm. Tree index is used to seed per-tree RNG. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_buildrandomtree(decisionforestbuilder* s, + ae_int_t treeidx0, + ae_int_t treeidx1, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t treeidx; + ae_int_t i; + ae_int_t j; + ae_int_t npoints; + ae_int_t nvars; + ae_int_t nclasses; + hqrndstate rs; + dfworkbuf *workbuf; + ae_smart_ptr _workbuf; + dfvotebuf *votebuf; + ae_smart_ptr _votebuf; + dftreebuf *treebuf; + ae_smart_ptr _treebuf; + ae_int_t treesize; + ae_int_t varstoselect; + ae_int_t workingsetsize; + double meanloss; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + memset(&_workbuf, 0, sizeof(_workbuf)); + memset(&_votebuf, 0, sizeof(_votebuf)); + memset(&_treebuf, 0, sizeof(_treebuf)); + _hqrndstate_init(&rs, _state, ae_true); + ae_smart_ptr_init(&_workbuf, (void**)&workbuf, ae_false, _state, ae_true); + ae_smart_ptr_init(&_votebuf, (void**)&votebuf, ae_false, _state, ae_true); + ae_smart_ptr_init(&_treebuf, (void**)&treebuf, ae_false, _state, ae_true); + + + /* + * Perform parallelization + */ + if( treeidx1-treeidx0>1 ) + { + if( _trypexec_dforest_buildrandomtree(s,treeidx0,treeidx1, _state) ) + { + ae_frame_leave(_state); + return; + } + j = (treeidx1-treeidx0)/2; + dforest_buildrandomtree(s, treeidx0, treeidx0+j, _state); + dforest_buildrandomtree(s, treeidx0+j, treeidx1, _state); + ae_frame_leave(_state); + return; + } + else + { + ae_assert(treeidx1-treeidx0==1, "RDF: integrity check failed", _state); + treeidx = treeidx0; + } + + /* + * Prepare + */ + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + if( s->rdfglobalseed>0 ) + { + hqrndseed(s->rdfglobalseed, 1+treeidx, &rs, _state); + } + else + { + hqrndseed(ae_randominteger(30000, _state), 1+treeidx, &rs, _state); + } + + /* + * Retrieve buffers. + */ + ae_shared_pool_retrieve(&s->workpool, &_workbuf, _state); + ae_shared_pool_retrieve(&s->votepool, &_votebuf, _state); + + /* + * Prepare everything for tree construction. + */ + ae_assert(workbuf->trnsize>=1, "DForest: integrity check failed (34636)", _state); + ae_assert(workbuf->oobsize>=0, "DForest: integrity check failed (45745)", _state); + ae_assert(workbuf->trnsize+workbuf->oobsize==npoints, "DForest: integrity check failed (89415)", _state); + workingsetsize = -1; + workbuf->varpoolsize = 0; + for(i=0; i<=nvars-1; i++) + { + if( ae_fp_neq(s->dsmin.ptr.p_double[i],s->dsmax.ptr.p_double[i]) ) + { + workbuf->varpool.ptr.p_int[workbuf->varpoolsize] = i; + inc(&workbuf->varpoolsize, _state); + } + } + workingsetsize = workbuf->varpoolsize; + ae_assert(workingsetsize>=0, "DForest: integrity check failed (73f5)", _state); + for(i=0; i<=npoints-1; i++) + { + workbuf->tmp0i.ptr.p_int[i] = i; + } + for(i=0; i<=workbuf->trnsize-1; i++) + { + j = hqrnduniformi(&rs, npoints-i, _state); + swapelementsi(&workbuf->tmp0i, i, i+j, _state); + workbuf->trnset.ptr.p_int[i] = workbuf->tmp0i.ptr.p_int[i]; + if( nclasses>1 ) + { + workbuf->trnlabelsi.ptr.p_int[i] = s->dsival.ptr.p_int[workbuf->tmp0i.ptr.p_int[i]]; + } + else + { + workbuf->trnlabelsr.ptr.p_double[i] = s->dsrval.ptr.p_double[workbuf->tmp0i.ptr.p_int[i]]; + } + if( s->neediobmatrix ) + { + s->iobmatrix.ptr.pp_bool[treeidx][workbuf->trnset.ptr.p_int[i]] = ae_true; + } + } + for(i=0; i<=workbuf->oobsize-1; i++) + { + j = workbuf->tmp0i.ptr.p_int[workbuf->trnsize+i]; + workbuf->oobset.ptr.p_int[i] = j; + if( nclasses>1 ) + { + workbuf->ooblabelsi.ptr.p_int[i] = s->dsival.ptr.p_int[j]; + } + else + { + workbuf->ooblabelsr.ptr.p_double[i] = s->dsrval.ptr.p_double[j]; + } + } + varstoselect = ae_round(ae_sqrt((double)(nvars), _state), _state); + if( ae_fp_greater(s->rdfvars,(double)(0)) ) + { + varstoselect = ae_round(s->rdfvars, _state); + } + if( ae_fp_less(s->rdfvars,(double)(0)) ) + { + varstoselect = ae_round(-(double)nvars*s->rdfvars, _state); + } + varstoselect = ae_maxint(varstoselect, 1, _state); + varstoselect = ae_minint(varstoselect, nvars, _state); + + /* + * Perform recurrent construction + */ + if( s->rdfimportance==dforest_needtrngini ) + { + meanloss = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, 0, workbuf->trnsize, &workbuf->trnlabelsi, &workbuf->trnlabelsr, 0, workbuf->trnsize, &workbuf->tmpnrms2, _state); + } + else + { + meanloss = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, 0, workbuf->trnsize, &workbuf->ooblabelsi, &workbuf->ooblabelsr, 0, workbuf->oobsize, &workbuf->tmpnrms2, _state); + } + treesize = 1; + dforest_buildrandomtreerec(s, workbuf, workingsetsize, varstoselect, &workbuf->treebuf, votebuf, &rs, 0, workbuf->trnsize, 0, workbuf->oobsize, meanloss, meanloss, &treesize, _state); + workbuf->treebuf.ptr.p_double[0] = (double)(treesize); + + /* + * Store tree + */ + ae_shared_pool_retrieve(&s->treefactory, &_treebuf, _state); + ae_vector_set_length(&treebuf->treebuf, treesize, _state); + for(i=0; i<=treesize-1; i++) + { + treebuf->treebuf.ptr.p_double[i] = workbuf->treebuf.ptr.p_double[i]; + } + treebuf->treeidx = treeidx; + ae_shared_pool_recycle(&s->treepool, &_treebuf, _state); + + /* + * Return other buffers to appropriate pools + */ + ae_shared_pool_recycle(&s->workpool, &_workbuf, _state); + ae_shared_pool_recycle(&s->votepool, &_votebuf, _state); + + /* + * Update progress indicator + */ + threadunsafeincby(&s->rdfprogress, npoints, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_dforest_buildrandomtree(decisionforestbuilder* s, + ae_int_t treeidx0, + ae_int_t treeidx1, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Recurrent tree construction function using caller-allocated buffers and +caller-initialized RNG. + +Following iterms are processed: +* items [Idx0,Idx1) of WorkBuf.TrnSet +* items [OOBIdx0, OOBIdx1) of WorkBuf.OOBSet + +TreeSize on input must be 1 (header element of the tree), on output it +contains size of the tree. + +OOBLoss on input must contain value of MeanNRMS2(...) computed for entire +dataset. + +Variables from #0 to #WorkingSet-1 from WorkBuf.VarPool are used (for +block algorithm: blocks, not vars) + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_buildrandomtreerec(const decisionforestbuilder* s, + dfworkbuf* workbuf, + ae_int_t workingset, + ae_int_t varstoselect, + /* Real */ ae_vector* treebuf, + dfvotebuf* votebuf, + hqrndstate* rs, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t oobidx0, + ae_int_t oobidx1, + double meanloss, + double topmostmeanloss, + ae_int_t* treesize, + ae_state *_state) +{ + ae_int_t npoints; + ae_int_t nclasses; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + double v; + ae_bool labelsaresame; + ae_int_t offs; + ae_int_t varbest; + double splitbest; + ae_int_t i1; + ae_int_t i2; + ae_int_t idxtrn; + ae_int_t idxoob; + double meanloss0; + double meanloss1; + + + ae_assert(s->dstype==0, "not supported skbdgfsi!", _state); + ae_assert(idx0npoints; + nclasses = s->nclasses; + + /* + * Check labels: all same or not? + */ + if( nclasses>1 ) + { + labelsaresame = ae_true; + for(i=0; i<=nclasses-1; i++) + { + workbuf->classpriors.ptr.p_int[i] = 0; + } + j0 = workbuf->trnlabelsi.ptr.p_int[idx0]; + for(i=idx0; i<=idx1-1; i++) + { + j = workbuf->trnlabelsi.ptr.p_int[i]; + workbuf->classpriors.ptr.p_int[j] = workbuf->classpriors.ptr.p_int[j]+1; + labelsaresame = labelsaresame&&j0==j; + } + } + else + { + labelsaresame = ae_false; + } + + /* + * Leaf node + */ + if( idx1-idx0==1||labelsaresame ) + { + if( nclasses==1 ) + { + dforest_outputleaf(s, workbuf, treebuf, votebuf, idx0, idx1, oobidx0, oobidx1, treesize, workbuf->trnlabelsr.ptr.p_double[idx0], _state); + } + else + { + dforest_outputleaf(s, workbuf, treebuf, votebuf, idx0, idx1, oobidx0, oobidx1, treesize, (double)(workbuf->trnlabelsi.ptr.p_int[idx0]), _state); + } + return; + } + + /* + * Non-leaf node. + * Investigate possible splits. + */ + ae_assert(s->rdfalgo==0, "BuildRandomForest: unexpected algo", _state); + dforest_choosecurrentsplitdense(s, workbuf, &workingset, varstoselect, rs, idx0, idx1, &varbest, &splitbest, _state); + if( varbest<0 ) + { + + /* + * No good split was found; make leaf (label is randomly chosen) and exit. + */ + if( nclasses>1 ) + { + v = (double)(workbuf->trnlabelsi.ptr.p_int[idx0+hqrnduniformi(rs, idx1-idx0, _state)]); + } + else + { + v = workbuf->trnlabelsr.ptr.p_double[idx0+hqrnduniformi(rs, idx1-idx0, _state)]; + } + dforest_outputleaf(s, workbuf, treebuf, votebuf, idx0, idx1, oobidx0, oobidx1, treesize, v, _state); + return; + } + + /* + * Good split WAS found, we can perform it: + * * first, we split training set + * * then, we similarly split OOB set + */ + ae_assert(s->dstype==0, "not supported 54bfdh", _state); + offs = npoints*varbest; + i1 = idx0; + i2 = idx1-1; + while(i1<=i2) + { + + /* + * Reorder indexes so that left partition is in [Idx0..I1), + * and right partition is in [I2+1..Idx1) + */ + if( workbuf->bestvals.ptr.p_double[i1]bestvals.ptr.p_double[i2]>=splitbest ) + { + i2 = i2-1; + continue; + } + j = workbuf->trnset.ptr.p_int[i1]; + workbuf->trnset.ptr.p_int[i1] = workbuf->trnset.ptr.p_int[i2]; + workbuf->trnset.ptr.p_int[i2] = j; + if( nclasses>1 ) + { + j = workbuf->trnlabelsi.ptr.p_int[i1]; + workbuf->trnlabelsi.ptr.p_int[i1] = workbuf->trnlabelsi.ptr.p_int[i2]; + workbuf->trnlabelsi.ptr.p_int[i2] = j; + } + else + { + v = workbuf->trnlabelsr.ptr.p_double[i1]; + workbuf->trnlabelsr.ptr.p_double[i1] = workbuf->trnlabelsr.ptr.p_double[i2]; + workbuf->trnlabelsr.ptr.p_double[i2] = v; + } + i1 = i1+1; + i2 = i2-1; + } + ae_assert(i1==i2+1, "BuildRandomTreeRec: integrity check failed (45rds3)", _state); + idxtrn = i1; + if( oobidx0dsdata.ptr.p_double[offs+workbuf->oobset.ptr.p_int[i1]]dsdata.ptr.p_double[offs+workbuf->oobset.ptr.p_int[i2]]>=splitbest ) + { + i2 = i2-1; + continue; + } + j = workbuf->oobset.ptr.p_int[i1]; + workbuf->oobset.ptr.p_int[i1] = workbuf->oobset.ptr.p_int[i2]; + workbuf->oobset.ptr.p_int[i2] = j; + if( nclasses>1 ) + { + j = workbuf->ooblabelsi.ptr.p_int[i1]; + workbuf->ooblabelsi.ptr.p_int[i1] = workbuf->ooblabelsi.ptr.p_int[i2]; + workbuf->ooblabelsi.ptr.p_int[i2] = j; + } + else + { + v = workbuf->ooblabelsr.ptr.p_double[i1]; + workbuf->ooblabelsr.ptr.p_double[i1] = workbuf->ooblabelsr.ptr.p_double[i2]; + workbuf->ooblabelsr.ptr.p_double[i2] = v; + } + i1 = i1+1; + i2 = i2-1; + } + ae_assert(i1==i2+1, "BuildRandomTreeRec: integrity check failed (643fs3)", _state); + idxoob = i1; + } + else + { + idxoob = oobidx0; + } + + /* + * Compute estimates of NRMS2 loss over TRN or OOB subsets, update Gini importances + */ + if( s->rdfimportance==dforest_needtrngini ) + { + meanloss0 = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idx0, idxtrn, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idx0, idxtrn, &workbuf->tmpnrms2, _state); + meanloss1 = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idxtrn, idx1, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idxtrn, idx1, &workbuf->tmpnrms2, _state); + } + else + { + meanloss0 = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idx0, idxtrn, &workbuf->ooblabelsi, &workbuf->ooblabelsr, oobidx0, idxoob, &workbuf->tmpnrms2, _state); + meanloss1 = dforest_meannrms2(nclasses, &workbuf->trnlabelsi, &workbuf->trnlabelsr, idxtrn, idx1, &workbuf->ooblabelsi, &workbuf->ooblabelsr, idxoob, oobidx1, &workbuf->tmpnrms2, _state); + } + votebuf->giniimportances.ptr.p_double[varbest] = votebuf->giniimportances.ptr.p_double[varbest]+(meanloss-(meanloss0+meanloss1))/(topmostmeanloss+1.0e-20); + + /* + * Generate tree node and subtrees (recursively) + */ + treebuf->ptr.p_double[*treesize] = (double)(varbest); + treebuf->ptr.p_double[*treesize+1] = splitbest; + i = *treesize; + *treesize = *treesize+dforest_innernodewidth; + dforest_buildrandomtreerec(s, workbuf, workingset, varstoselect, treebuf, votebuf, rs, idx0, idxtrn, oobidx0, idxoob, meanloss0, topmostmeanloss, treesize, _state); + treebuf->ptr.p_double[i+2] = (double)(*treesize); + dforest_buildrandomtreerec(s, workbuf, workingset, varstoselect, treebuf, votebuf, rs, idxtrn, idx1, idxoob, oobidx1, meanloss1, topmostmeanloss, treesize, _state); +} + + +/************************************************************************* +Estimates permutation variable importance ratings for a range of dataset +points. + +Initial call to this function should span entire range of the dataset, +[Idx0,Idx1)=[0,NPoints), because function performs initialization of some +internal structures when called with these arguments. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_estimatevariableimportance(decisionforestbuilder* s, + ae_int_t sessionseed, + const decisionforest* df, + ae_int_t ntrees, + dfreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t npoints; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t nperm; + ae_int_t i; + ae_int_t j; + ae_int_t k; + dfvotebuf *vote; + ae_smart_ptr _vote; + ae_vector tmpr0; + ae_vector tmpr1; + ae_vector tmpi0; + ae_vector losses; + dfpermimpbuf permseed; + dfpermimpbuf *permresult; + ae_smart_ptr _permresult; + ae_shared_pool permpool; + double nopermloss; + double totalpermloss; + hqrndstate varimprs; + + ae_frame_make(_state, &_frame_block); + memset(&_vote, 0, sizeof(_vote)); + memset(&tmpr0, 0, sizeof(tmpr0)); + memset(&tmpr1, 0, sizeof(tmpr1)); + memset(&tmpi0, 0, sizeof(tmpi0)); + memset(&losses, 0, sizeof(losses)); + memset(&permseed, 0, sizeof(permseed)); + memset(&_permresult, 0, sizeof(_permresult)); + memset(&permpool, 0, sizeof(permpool)); + memset(&varimprs, 0, sizeof(varimprs)); + ae_smart_ptr_init(&_vote, (void**)&vote, ae_false, _state, ae_true); + ae_vector_init(&tmpr0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpr1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpi0, 0, DT_INT, _state, ae_true); + ae_vector_init(&losses, 0, DT_REAL, _state, ae_true); + _dfpermimpbuf_init(&permseed, _state, ae_true); + ae_smart_ptr_init(&_permresult, (void**)&permresult, ae_false, _state, ae_true); + ae_shared_pool_init(&permpool, _state, ae_true); + _hqrndstate_init(&varimprs, _state, ae_true); + + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + + /* + * No importance rating + */ + if( s->rdfimportance==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Gini importance + */ + if( s->rdfimportance==dforest_needtrngini||s->rdfimportance==dforest_needoobgini ) + { + + /* + * Merge OOB Gini importances computed during tree generation + */ + ae_shared_pool_first_recycled(&s->votepool, &_vote, _state); + while(vote!=NULL) + { + for(i=0; i<=nvars-1; i++) + { + rep->varimportances.ptr.p_double[i] = rep->varimportances.ptr.p_double[i]+vote->giniimportances.ptr.p_double[i]/(double)ntrees; + } + ae_shared_pool_next_recycled(&s->votepool, &_vote, _state); + } + for(i=0; i<=nvars-1; i++) + { + rep->varimportances.ptr.p_double[i] = boundval(rep->varimportances.ptr.p_double[i], (double)(0), (double)(1), _state); + } + + /* + * Compute topvars[] array + */ + ae_vector_set_length(&tmpr0, nvars, _state); + for(j=0; j<=nvars-1; j++) + { + tmpr0.ptr.p_double[j] = -rep->varimportances.ptr.p_double[j]; + rep->topvars.ptr.p_int[j] = j; + } + tagsortfasti(&tmpr0, &rep->topvars, &tmpr1, &tmpi0, nvars, _state); + ae_frame_leave(_state); + return; + } + + /* + * Permutation importance + */ + if( s->rdfimportance==dforest_needpermutation ) + { + ae_assert(df->forestformat==dforest_dfuncompressedv0, "EstimateVariableImportance: integrity check failed (ff)", _state); + ae_assert(s->iobmatrix.rows>=ntrees&&s->iobmatrix.cols>=npoints, "EstimateVariableImportance: integrity check failed (IOB)", _state); + + /* + * Generate packed representation of the shuffle which is applied to all variables + * + * Ideally we want to apply different permutations to different variables, + * i.e. we have to generate and store NPoints*NVars random numbers. + * However due to performance and memory restrictions we prefer to use compact + * representation: + * * we store one "reference" permutation P_ref in VarImpShuffle2[0:NPoints-1] + * * a permutation P_j applied to variable J is obtained by circularly shifting + * elements in P_ref by VarImpShuffle2[NPoints+J] + */ + hqrndseed(sessionseed, 1117, &varimprs, _state); + ivectorsetlengthatleast(&s->varimpshuffle2, npoints+nvars, _state); + for(i=0; i<=npoints-1; i++) + { + s->varimpshuffle2.ptr.p_int[i] = i; + } + for(i=0; i<=npoints-2; i++) + { + j = i+hqrnduniformi(&varimprs, npoints-i, _state); + k = s->varimpshuffle2.ptr.p_int[i]; + s->varimpshuffle2.ptr.p_int[i] = s->varimpshuffle2.ptr.p_int[j]; + s->varimpshuffle2.ptr.p_int[j] = k; + } + for(i=0; i<=nvars-1; i++) + { + s->varimpshuffle2.ptr.p_int[npoints+i] = hqrnduniformi(&varimprs, npoints, _state); + } + + /* + * Prepare buffer object, seed pool + */ + nperm = nvars+2; + ae_vector_set_length(&permseed.losses, nperm, _state); + for(j=0; j<=nperm-1; j++) + { + permseed.losses.ptr.p_double[j] = (double)(0); + } + ae_vector_set_length(&permseed.yv, nperm*nclasses, _state); + ae_vector_set_length(&permseed.xraw, nvars, _state); + ae_vector_set_length(&permseed.xdist, nvars, _state); + ae_vector_set_length(&permseed.xcur, nvars, _state); + ae_vector_set_length(&permseed.targety, nclasses, _state); + ae_vector_set_length(&permseed.startnodes, nvars, _state); + ae_vector_set_length(&permseed.y, nclasses, _state); + ae_shared_pool_set_seed(&permpool, &permseed, (ae_int_t)sizeof(permseed), (ae_copy_constructor)_dfpermimpbuf_init_copy, (ae_destructor)_dfpermimpbuf_destroy, _state); + + /* + * Recursively split subset and process (using parallel capabilities, if possible) + */ + dforest_estimatepermutationimportances(s, df, ntrees, &permpool, 0, npoints, _state); + + /* + * Merge results + */ + ae_vector_set_length(&losses, nperm, _state); + for(j=0; j<=nperm-1; j++) + { + losses.ptr.p_double[j] = 1.0e-20; + } + ae_shared_pool_first_recycled(&permpool, &_permresult, _state); + while(permresult!=NULL) + { + for(j=0; j<=nperm-1; j++) + { + losses.ptr.p_double[j] = losses.ptr.p_double[j]+permresult->losses.ptr.p_double[j]; + } + ae_shared_pool_next_recycled(&permpool, &_permresult, _state); + } + + /* + * Compute importances + */ + nopermloss = losses.ptr.p_double[nvars+1]; + totalpermloss = losses.ptr.p_double[nvars]; + for(i=0; i<=nvars-1; i++) + { + rep->varimportances.ptr.p_double[i] = (double)1-nopermloss/totalpermloss-((double)1-losses.ptr.p_double[i]/totalpermloss); + rep->varimportances.ptr.p_double[i] = boundval(rep->varimportances.ptr.p_double[i], (double)(0), (double)(1), _state); + } + + /* + * Compute topvars[] array + */ + ae_vector_set_length(&tmpr0, nvars, _state); + for(j=0; j<=nvars-1; j++) + { + tmpr0.ptr.p_double[j] = -rep->varimportances.ptr.p_double[j]; + rep->topvars.ptr.p_int[j] = j; + } + tagsortfasti(&tmpr0, &rep->topvars, &tmpr1, &tmpi0, nvars, _state); + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "EstimateVariableImportance: unexpected importance type", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_dforest_estimatevariableimportance(decisionforestbuilder* s, + ae_int_t sessionseed, + const decisionforest* df, + ae_int_t ntrees, + dfreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Estimates permutation variable importance ratings for a range of dataset +points. + +Initial call to this function should span entire range of the dataset, +[Idx0,Idx1)=[0,NPoints), because function performs initialization of some +internal structures when called with these arguments. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_estimatepermutationimportances(decisionforestbuilder* s, + const decisionforest* df, + ae_int_t ntrees, + ae_shared_pool* permpool, + ae_int_t idx0, + ae_int_t idx1, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t npoints; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t nperm; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_int_t treeroot; + ae_int_t nodeoffs; + double prediction; + ae_int_t varidx; + ae_int_t oobcounts; + ae_int_t srcidx; + dfpermimpbuf *permimpbuf; + ae_smart_ptr _permimpbuf; + + ae_frame_make(_state, &_frame_block); + memset(&_permimpbuf, 0, sizeof(_permimpbuf)); + ae_smart_ptr_init(&_permimpbuf, (void**)&permimpbuf, ae_false, _state, ae_true); + + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + ae_assert(df->forestformat==dforest_dfuncompressedv0, "EstimateVariableImportance: integrity check failed (ff)", _state); + ae_assert((idx0>=0&&idx0<=idx1)&&idx1<=npoints, "EstimateVariableImportance: integrity check failed (idx)", _state); + ae_assert(s->iobmatrix.rows>=ntrees&&s->iobmatrix.cols>=npoints, "EstimateVariableImportance: integrity check failed (IOB)", _state); + + /* + * Perform parallelization if batch is too large + */ + if( idx1-idx0>dforest_permutationimportancebatchsize ) + { + if( _trypexec_dforest_estimatepermutationimportances(s,df,ntrees,permpool,idx0,idx1, _state) ) + { + ae_frame_leave(_state); + return; + } + j = (idx1-idx0)/2; + dforest_estimatepermutationimportances(s, df, ntrees, permpool, idx0, idx0+j, _state); + dforest_estimatepermutationimportances(s, df, ntrees, permpool, idx0+j, idx1, _state); + ae_frame_leave(_state); + return; + } + + /* + * Retrieve buffer object from pool + */ + ae_shared_pool_retrieve(permpool, &_permimpbuf, _state); + + /* + * Process range of points [idx0,idx1) + */ + nperm = nvars+2; + for(i=idx0; i<=idx1-1; i++) + { + ae_assert(s->dstype==0, "EstimateVariableImportance: unexpected dataset type", _state); + for(j=0; j<=nvars-1; j++) + { + permimpbuf->xraw.ptr.p_double[j] = s->dsdata.ptr.p_double[j*npoints+i]; + srcidx = s->varimpshuffle2.ptr.p_int[(i+s->varimpshuffle2.ptr.p_int[npoints+j])%npoints]; + permimpbuf->xdist.ptr.p_double[j] = s->dsdata.ptr.p_double[j*npoints+srcidx]; + } + if( nclasses>1 ) + { + for(j=0; j<=nclasses-1; j++) + { + permimpbuf->targety.ptr.p_double[j] = (double)(0); + } + permimpbuf->targety.ptr.p_double[s->dsival.ptr.p_int[i]] = (double)(1); + } + else + { + permimpbuf->targety.ptr.p_double[0] = s->dsrval.ptr.p_double[i]; + } + + /* + * Process all trees, for each tree compute NPerm losses corresponding + * to various permutations of variable values + */ + for(j=0; j<=nperm*nclasses-1; j++) + { + permimpbuf->yv.ptr.p_double[j] = (double)(0); + } + oobcounts = 0; + treeroot = 0; + for(k=0; k<=ntrees-1; k++) + { + if( !s->iobmatrix.ptr.pp_bool[k][i] ) + { + + /* + * Process original (unperturbed) point and analyze path from the + * tree root to the final leaf. Output prediction to RawPrediction. + * + * Additionally, for each variable in [0,NVars-1] save offset of + * the first split on this variable. It allows us to quickly compute + * tree decision when perturbation does not change decision path. + */ + ae_assert(df->forestformat==dforest_dfuncompressedv0, "EstimateVariableImportance: integrity check failed (ff)", _state); + nodeoffs = treeroot+1; + for(j=0; j<=nvars-1; j++) + { + permimpbuf->startnodes.ptr.p_int[j] = -1; + } + prediction = (double)(0); + for(;;) + { + if( ae_fp_eq(df->trees.ptr.p_double[nodeoffs],(double)(-1)) ) + { + prediction = df->trees.ptr.p_double[nodeoffs+1]; + break; + } + j = ae_round(df->trees.ptr.p_double[nodeoffs], _state); + if( permimpbuf->startnodes.ptr.p_int[j]<0 ) + { + permimpbuf->startnodes.ptr.p_int[j] = nodeoffs; + } + if( permimpbuf->xraw.ptr.p_double[j]trees.ptr.p_double[nodeoffs+1] ) + { + nodeoffs = nodeoffs+dforest_innernodewidth; + } + else + { + nodeoffs = treeroot+ae_round(df->trees.ptr.p_double[nodeoffs+2], _state); + } + } + + /* + * Save loss for unperturbed point + */ + varidx = nvars+1; + if( nclasses>1 ) + { + j = ae_round(prediction, _state); + permimpbuf->yv.ptr.p_double[varidx*nclasses+j] = permimpbuf->yv.ptr.p_double[varidx*nclasses+j]+(double)1; + } + else + { + permimpbuf->yv.ptr.p_double[varidx] = permimpbuf->yv.ptr.p_double[varidx]+prediction; + } + + /* + * Save loss for all variables being perturbed (XDist). + * This loss is used as a reference loss when we compute R-squared. + */ + varidx = nvars; + for(j=0; j<=nclasses-1; j++) + { + permimpbuf->y.ptr.p_double[j] = (double)(0); + } + dforest_dfprocessinternaluncompressed(df, treeroot, treeroot+1, &permimpbuf->xdist, &permimpbuf->y, _state); + for(j=0; j<=nclasses-1; j++) + { + permimpbuf->yv.ptr.p_double[varidx*nclasses+j] = permimpbuf->yv.ptr.p_double[varidx*nclasses+j]+permimpbuf->y.ptr.p_double[j]; + } + + /* + * Compute losses for variable #VarIdx being perturbed. Quite an often decision + * process does not actually depend on the variable #VarIdx (path from the tree + * root does not include splits on this variable). In such cases we perform + * quick exit from the loop with precomputed value. + */ + for(j=0; j<=nvars-1; j++) + { + permimpbuf->xcur.ptr.p_double[j] = permimpbuf->xraw.ptr.p_double[j]; + } + for(varidx=0; varidx<=nvars-1; varidx++) + { + if( permimpbuf->startnodes.ptr.p_int[varidx]>=0 ) + { + + /* + * Path from tree root to the final leaf involves split on variable #VarIdx. + * Restart computation from the position first split on #VarIdx. + */ + ae_assert(df->forestformat==dforest_dfuncompressedv0, "EstimateVariableImportance: integrity check failed (ff)", _state); + permimpbuf->xcur.ptr.p_double[varidx] = permimpbuf->xdist.ptr.p_double[varidx]; + nodeoffs = permimpbuf->startnodes.ptr.p_int[varidx]; + for(;;) + { + if( ae_fp_eq(df->trees.ptr.p_double[nodeoffs],(double)(-1)) ) + { + if( nclasses>1 ) + { + j = ae_round(df->trees.ptr.p_double[nodeoffs+1], _state); + permimpbuf->yv.ptr.p_double[varidx*nclasses+j] = permimpbuf->yv.ptr.p_double[varidx*nclasses+j]+(double)1; + } + else + { + permimpbuf->yv.ptr.p_double[varidx] = permimpbuf->yv.ptr.p_double[varidx]+df->trees.ptr.p_double[nodeoffs+1]; + } + break; + } + j = ae_round(df->trees.ptr.p_double[nodeoffs], _state); + if( permimpbuf->xcur.ptr.p_double[j]trees.ptr.p_double[nodeoffs+1] ) + { + nodeoffs = nodeoffs+dforest_innernodewidth; + } + else + { + nodeoffs = treeroot+ae_round(df->trees.ptr.p_double[nodeoffs+2], _state); + } + } + permimpbuf->xcur.ptr.p_double[varidx] = permimpbuf->xraw.ptr.p_double[varidx]; + } + else + { + + /* + * Path from tree root to the final leaf does NOT involve split on variable #VarIdx. + * Permutation does not change tree output, reuse already computed value. + */ + if( nclasses>1 ) + { + j = ae_round(prediction, _state); + permimpbuf->yv.ptr.p_double[varidx*nclasses+j] = permimpbuf->yv.ptr.p_double[varidx*nclasses+j]+(double)1; + } + else + { + permimpbuf->yv.ptr.p_double[varidx] = permimpbuf->yv.ptr.p_double[varidx]+prediction; + } + } + } + + /* + * update OOB counter + */ + inc(&oobcounts, _state); + } + treeroot = treeroot+ae_round(df->trees.ptr.p_double[treeroot], _state); + } + + /* + * Now YV[] stores NPerm versions of the forest output for various permutations of variable values. + * Update losses. + */ + for(j=0; j<=nperm-1; j++) + { + for(k=0; k<=nclasses-1; k++) + { + permimpbuf->yv.ptr.p_double[j*nclasses+k] = permimpbuf->yv.ptr.p_double[j*nclasses+k]/coalesce((double)(oobcounts), (double)(1), _state); + } + v = (double)(0); + for(k=0; k<=nclasses-1; k++) + { + v = v+ae_sqr(permimpbuf->yv.ptr.p_double[j*nclasses+k]-permimpbuf->targety.ptr.p_double[k], _state); + } + permimpbuf->losses.ptr.p_double[j] = permimpbuf->losses.ptr.p_double[j]+v; + } + + /* + * Update progress indicator + */ + threadunsafeincby(&s->rdfprogress, ntrees, _state); + } + + /* + * Recycle buffer object with updated Losses[] field + */ + ae_shared_pool_recycle(permpool, &_permimpbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_dforest_estimatepermutationimportances(decisionforestbuilder* s, + const decisionforest* df, + ae_int_t ntrees, + ae_shared_pool* permpool, + ae_int_t idx0, + ae_int_t idx1, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Sets report fields to their default values + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_cleanreport(const decisionforestbuilder* s, + dfreport* rep, + ae_state *_state) +{ + ae_int_t i; + + + rep->relclserror = (double)(0); + rep->avgce = (double)(0); + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->oobrelclserror = (double)(0); + rep->oobavgce = (double)(0); + rep->oobrmserror = (double)(0); + rep->oobavgerror = (double)(0); + rep->oobavgrelerror = (double)(0); + ae_vector_set_length(&rep->topvars, s->nvars, _state); + ae_vector_set_length(&rep->varimportances, s->nvars, _state); + for(i=0; i<=s->nvars-1; i++) + { + rep->topvars.ptr.p_int[i] = i; + rep->varimportances.ptr.p_double[i] = (double)(0); + } +} + + +/************************************************************************* +This function returns NRMS2 loss (sum of squared residuals) for a constant- +output model: +* model output is a mean over TRN set being passed (for classification + problems - NClasses-dimensional vector of class probabilities) +* model is evaluated over TST set being passed, with L2 loss being returned + +Input parameters: + NClasses - ">1" for classification, "=1" for regression + TrnLabelsI - training set labels, class indexes (for NClasses>1) + TrnLabelsR - training set output values (for NClasses=1) + TrnIdx0, TrnIdx1 - a range [Idx0,Idx1) of elements in LabelsI/R is considered + TstLabelsI - training set labels, class indexes (for NClasses>1) + TstLabelsR - training set output values (for NClasses=1) + TstIdx0, TstIdx1 - a range [Idx0,Idx1) of elements in LabelsI/R is considered + TmpI - temporary array, reallocated as needed + +Result: + sum of squared residuals; + for NClasses>=2 it coincides with Gini impurity times (Idx1-Idx0) + +Following fields of WorkBuf are used as temporaries: +* TmpMeanNRMS2 + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static double dforest_meannrms2(ae_int_t nclasses, + /* Integer */ const ae_vector* trnlabelsi, + /* Real */ const ae_vector* trnlabelsr, + ae_int_t trnidx0, + ae_int_t trnidx1, + /* Integer */ const ae_vector* tstlabelsi, + /* Real */ const ae_vector* tstlabelsr, + ae_int_t tstidx0, + ae_int_t tstidx1, + /* Integer */ ae_vector* tmpi, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t ntrn; + ae_int_t ntst; + double v; + double vv; + double invntrn; + double pitrn; + double nitst; + double result; + + + ae_assert(trnidx0<=trnidx1, "MeanNRMS2: integrity check failed (8754)", _state); + ae_assert(tstidx0<=tstidx1, "MeanNRMS2: integrity check failed (8754)", _state); + result = (double)(0); + ntrn = trnidx1-trnidx0; + ntst = tstidx1-tstidx0; + if( ntrn==0||ntst==0 ) + { + return result; + } + invntrn = 1.0/(double)ntrn; + if( nclasses>1 ) + { + + /* + * Classification problem + */ + ivectorsetlengthatleast(tmpi, 2*nclasses, _state); + for(i=0; i<=2*nclasses-1; i++) + { + tmpi->ptr.p_int[i] = 0; + } + for(i=trnidx0; i<=trnidx1-1; i++) + { + k = trnlabelsi->ptr.p_int[i]; + tmpi->ptr.p_int[k] = tmpi->ptr.p_int[k]+1; + } + for(i=tstidx0; i<=tstidx1-1; i++) + { + k = tstlabelsi->ptr.p_int[i]; + tmpi->ptr.p_int[k+nclasses] = tmpi->ptr.p_int[k+nclasses]+1; + } + for(i=0; i<=nclasses-1; i++) + { + pitrn = (double)tmpi->ptr.p_int[i]*invntrn; + nitst = (double)(tmpi->ptr.p_int[i+nclasses]); + result = result+nitst*((double)1-pitrn)*((double)1-pitrn); + result = result+((double)ntst-nitst)*pitrn*pitrn; + } + } + else + { + + /* + * regression-specific code + */ + v = (double)(0); + for(i=trnidx0; i<=trnidx1-1; i++) + { + v = v+trnlabelsr->ptr.p_double[i]; + } + v = v*invntrn; + for(i=tstidx0; i<=tstidx1-1; i++) + { + vv = tstlabelsr->ptr.p_double[i]-v; + result = result+vv*vv; + } + } + return result; +} + + +/************************************************************************* +This function is a part of the recurrent tree construction function; it +selects variable for splitting according to current tree construction +algorithm. + +Note: modifies VarsInPool, may decrease it if some variables become non-informative +and leave the pool. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_choosecurrentsplitdense(const decisionforestbuilder* s, + dfworkbuf* workbuf, + ae_int_t* varsinpool, + ae_int_t varstoselect, + hqrndstate* rs, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t* varbest, + double* splitbest, + ae_state *_state) +{ + ae_int_t npoints; + double errbest; + ae_int_t varstried; + ae_int_t varcur; + ae_bool valuesaresame; + ae_int_t offs; + double split; + ae_int_t i; + double v; + double v0; + double currms; + ae_int_t info; + + *varbest = 0; + *splitbest = 0.0; + + ae_assert(s->dstype==0, "sparsity is not supported 4terg!", _state); + ae_assert(s->rdfalgo==0, "BuildRandomTreeRec: integrity check failed (1657)", _state); + ae_assert(idx0npoints; + + /* + * Select split according to dense direct RDF algorithm + */ + *varbest = -1; + errbest = ae_maxrealnumber; + *splitbest = (double)(0); + varstried = 0; + while(varstried<=ae_minint(varstoselect, *varsinpool, _state)-1) + { + + /* + * select variables from pool + */ + swapelementsi(&workbuf->varpool, varstried, varstried+hqrnduniformi(rs, *varsinpool-varstried, _state), _state); + varcur = workbuf->varpool.ptr.p_int[varstried]; + + /* + * Load variable values to working array. + * If all variable values are same, variable is excluded from pool and we re-run variable selection. + */ + valuesaresame = ae_true; + ae_assert(s->dstype==0, "not supported segsv34fs", _state); + offs = npoints*varcur; + v0 = s->dsdata.ptr.p_double[offs+workbuf->trnset.ptr.p_int[idx0]]; + for(i=idx0; i<=idx1-1; i++) + { + v = s->dsdata.ptr.p_double[offs+workbuf->trnset.ptr.p_int[i]]; + workbuf->curvals.ptr.p_double[i] = v; + valuesaresame = valuesaresame&&v==v0; + } + if( valuesaresame ) + { + + /* + * Variable does not change across current subset. + * Exclude variable from pool, go to the next iteration. + * VarsTried is not increased. + * + * NOTE: it is essential that updated VarsInPool is passed + * down to children but not up to caller - it is + * possible that one level higher this variable is + * not-fixed. + */ + swapelementsi(&workbuf->varpool, varstried, *varsinpool-1, _state); + *varsinpool = *varsinpool-1; + continue; + } + + /* + * Now we are ready to infer the split + */ + dforest_evaluatedensesplit(s, workbuf, rs, varcur, idx0, idx1, &info, &split, &currms, _state); + if( info>0&&(*varbest<0||ae_fp_less_eq(currms,errbest)) ) + { + errbest = currms; + *varbest = varcur; + *splitbest = split; + for(i=idx0; i<=idx1-1; i++) + { + workbuf->bestvals.ptr.p_double[i] = workbuf->curvals.ptr.p_double[i]; + } + } + + /* + * Next iteration + */ + varstried = varstried+1; + } +} + + +/************************************************************************* +This function performs split on some specific dense variable whose values +are stored in WorkBuf.CurVals[Idx0,Idx1) and labels are stored in +WorkBuf.TrnLabelsR/I[Idx0,Idx1). + +It returns split value and associated RMS error. It is responsibility of +the caller to make sure that variable has at least two distinct values, +i.e. it is possible to make a split. + +Precomputed values of following fields of WorkBuf are used: +* ClassPriors + +Following fields of WorkBuf are used as temporaries: +* ClassTotals0,1,01 +* Tmp0I, Tmp1I, Tmp0R, Tmp1R, Tmp2R, Tmp3R + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_evaluatedensesplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + hqrndstate* rs, + ae_int_t splitvar, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t* info, + double* split, + double* rms, + ae_state *_state) +{ + ae_int_t nclasses; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + double v; + double v0; + double v1; + double v2; + ae_int_t sl; + ae_int_t sr; + + *info = 0; + *split = 0.0; + *rms = 0.0; + + ae_assert(idx0nclasses; + if( s->dsbinary.ptr.p_bool[splitvar] ) + { + + /* + * Try simple binary split, if possible + * Split can be inferred from minimum/maximum values, just calculate RMS error + */ + *info = 1; + *split = dforest_getsplit(s, s->dsmin.ptr.p_double[splitvar], s->dsmax.ptr.p_double[splitvar], rs, _state); + if( nclasses>1 ) + { + + /* + * Classification problem + */ + for(j=0; j<=nclasses-1; j++) + { + workbuf->classtotals0.ptr.p_int[j] = 0; + } + sl = 0; + for(i=idx0; i<=idx1-1; i++) + { + if( workbuf->curvals.ptr.p_double[i]<*split ) + { + j = workbuf->trnlabelsi.ptr.p_int[i]; + workbuf->classtotals0.ptr.p_int[j] = workbuf->classtotals0.ptr.p_int[j]+1; + sl = sl+1; + } + } + sr = idx1-idx0-sl; + ae_assert(sl!=0&&sr!=0, "BuildRandomTreeRec: something strange, impossible failure!", _state); + v0 = (double)1/(double)sl; + v1 = (double)1/(double)sr; + *rms = (double)(0); + for(j=0; j<=nclasses-1; j++) + { + k0 = workbuf->classtotals0.ptr.p_int[j]; + k1 = workbuf->classpriors.ptr.p_int[j]-k0; + *rms = *rms+(double)k0*((double)1-v0*(double)k0)+(double)k1*((double)1-v1*(double)k1); + } + *rms = ae_sqrt(*rms/(double)(nclasses*(idx1-idx0+1)), _state); + } + else + { + + /* + * regression-specific code + */ + sl = 0; + sr = 0; + v1 = (double)(0); + v2 = (double)(0); + for(j=idx0; j<=idx1-1; j++) + { + if( workbuf->curvals.ptr.p_double[j]<*split ) + { + v1 = v1+workbuf->trnlabelsr.ptr.p_double[j]; + sl = sl+1; + } + else + { + v2 = v2+workbuf->trnlabelsr.ptr.p_double[j]; + sr = sr+1; + } + } + ae_assert(sl!=0&&sr!=0, "BuildRandomTreeRec: something strange, impossible failure!", _state); + v1 = v1/(double)sl; + v2 = v2/(double)sr; + *rms = (double)(0); + for(j=0; j<=idx1-idx0-1; j++) + { + v = workbuf->trnlabelsr.ptr.p_double[idx0+j]; + if( workbuf->curvals.ptr.p_double[j]<*split ) + { + v = v-v1; + } + else + { + v = v-v2; + } + *rms = *rms+v*v; + } + *rms = ae_sqrt(*rms/(double)(idx1-idx0+1), _state); + } + } + else + { + + /* + * General split + */ + *info = 0; + if( nclasses>1 ) + { + for(i=0; i<=idx1-idx0-1; i++) + { + workbuf->tmp0r.ptr.p_double[i] = workbuf->curvals.ptr.p_double[idx0+i]; + workbuf->tmp0i.ptr.p_int[i] = workbuf->trnlabelsi.ptr.p_int[idx0+i]; + } + dforest_classifiersplit(s, workbuf, &workbuf->tmp0r, &workbuf->tmp0i, idx1-idx0, rs, info, split, rms, &workbuf->tmp1r, &workbuf->tmp1i, _state); + } + else + { + for(i=0; i<=idx1-idx0-1; i++) + { + workbuf->tmp0r.ptr.p_double[i] = workbuf->curvals.ptr.p_double[idx0+i]; + workbuf->tmp1r.ptr.p_double[i] = workbuf->trnlabelsr.ptr.p_double[idx0+i]; + } + dforest_regressionsplit(s, workbuf, &workbuf->tmp0r, &workbuf->tmp1r, idx1-idx0, info, split, rms, &workbuf->tmp2r, &workbuf->tmp3r, _state); + } + } +} + + +/************************************************************************* +Classifier split +*************************************************************************/ +static void dforest_classifiersplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* c, + ae_int_t n, + hqrndstate* rs, + ae_int_t* info, + double* threshold, + double* e, + /* Real */ ae_vector* sortrbuf, + /* Integer */ ae_vector* sortibuf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t n0; + ae_int_t n0prev; + double v; + ae_int_t advanceby; + double rms; + ae_int_t k0; + ae_int_t k1; + double v0; + double v1; + ae_int_t nclasses; + double vmin; + double vmax; + + *info = 0; + *threshold = 0.0; + *e = 0.0; + + ae_assert((s->rdfsplitstrength==0||s->rdfsplitstrength==1)||s->rdfsplitstrength==2, "RDF: unexpected split type at ClassifierSplit()", _state); + nclasses = s->nclasses; + advanceby = 1; + if( n>=20 ) + { + advanceby = ae_maxint(2, ae_round((double)n*0.05, _state), _state); + } + *info = -1; + *threshold = (double)(0); + *e = ae_maxrealnumber; + + /* + * Random split + */ + if( s->rdfsplitstrength==0 ) + { + + /* + * Evaluate minimum, maximum and randomly selected values + */ + vmin = x->ptr.p_double[0]; + vmax = x->ptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + if( vvmax ) + { + vmax = v; + } + } + if( ae_fp_eq(vmin,vmax) ) + { + return; + } + v = x->ptr.p_double[hqrnduniformi(rs, n, _state)]; + if( ae_fp_eq(v,vmin) ) + { + v = vmax; + } + + /* + * Calculate RMS error associated with the split + */ + for(i=0; i<=nclasses-1; i++) + { + workbuf->classtotals0.ptr.p_int[i] = 0; + } + n0 = 0; + for(i=0; i<=n-1; i++) + { + if( x->ptr.p_double[i]ptr.p_int[i]; + workbuf->classtotals0.ptr.p_int[k] = workbuf->classtotals0.ptr.p_int[k]+1; + n0 = n0+1; + } + } + ae_assert(n0>0&&n0classtotals0.ptr.p_int[j]; + k1 = workbuf->classpriors.ptr.p_int[j]-k0; + rms = rms+(double)k0*((double)1-v0*(double)k0)+(double)k1*((double)1-v1*(double)k1); + } + *threshold = v; + *info = 1; + *e = rms; + return; + } + + /* + * Stronger splits which require us to sort the data + * Quick check for degeneracy + */ + tagsortfasti(x, c, sortrbuf, sortibuf, n, _state); + v = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); + if( !(ae_fp_less(x->ptr.p_double[0],v)&&ae_fp_less(v,x->ptr.p_double[n-1])) ) + { + return; + } + + /* + * Split at the middle + */ + if( s->rdfsplitstrength==1 ) + { + + /* + * Select split position + */ + vmin = x->ptr.p_double[0]; + vmax = x->ptr.p_double[n-1]; + v = x->ptr.p_double[n/2]; + if( ae_fp_eq(v,vmin) ) + { + v = vmin+0.001*(vmax-vmin); + } + if( ae_fp_eq(v,vmin) ) + { + v = vmax; + } + + /* + * Calculate RMS error associated with the split + */ + for(i=0; i<=nclasses-1; i++) + { + workbuf->classtotals0.ptr.p_int[i] = 0; + } + n0 = 0; + for(i=0; i<=n-1; i++) + { + if( x->ptr.p_double[i]ptr.p_int[i]; + workbuf->classtotals0.ptr.p_int[k] = workbuf->classtotals0.ptr.p_int[k]+1; + n0 = n0+1; + } + } + ae_assert(n0>0&&n0classtotals0.ptr.p_int[j]; + k1 = workbuf->classpriors.ptr.p_int[j]-k0; + rms = rms+(double)k0*((double)1-v0*(double)k0)+(double)k1*((double)1-v1*(double)k1); + } + *threshold = v; + *info = 1; + *e = rms; + return; + } + + /* + * Strong split + */ + if( s->rdfsplitstrength==2 ) + { + + /* + * Prepare initial split. + * Evaluate current split, prepare next one, repeat. + */ + for(i=0; i<=nclasses-1; i++) + { + workbuf->classtotals0.ptr.p_int[i] = 0; + } + n0 = 1; + while(n0ptr.p_double[n0]==x->ptr.p_double[n0-1]) + { + n0 = n0+1; + } + ae_assert(n0ptr.p_int[i]; + workbuf->classtotals0.ptr.p_int[k] = workbuf->classtotals0.ptr.p_int[k]+1; + } + *info = -1; + *threshold = x->ptr.p_double[n-1]; + *e = ae_maxrealnumber; + while(n0classtotals0.ptr.p_int[j]; + k1 = workbuf->classpriors.ptr.p_int[j]-k0; + rms = rms+(double)k0*((double)1-v0*(double)k0)+(double)k1*((double)1-v1*(double)k1); + } + if( *info<0||rms<*e ) + { + *info = 1; + *e = rms; + *threshold = 0.5*(x->ptr.p_double[n0-1]+x->ptr.p_double[n0]); + if( *threshold<=x->ptr.p_double[n0-1] ) + { + *threshold = x->ptr.p_double[n0]; + } + } + + /* + * Advance + */ + n0prev = n0; + while(n0ptr.p_double[n0]; + while(n0ptr.p_double[n0]==v) + { + k = c->ptr.p_int[n0]; + workbuf->classtotals0.ptr.p_int[k] = workbuf->classtotals0.ptr.p_int[k]+1; + n0 = n0+1; + } + } + } + if( *info>0 ) + { + *e = ae_sqrt(*e/(double)(nclasses*n), _state); + } + return; + } + ae_assert(ae_false, "RDF: ClassifierSplit(), critical error", _state); +} + + +/************************************************************************* +Regression model split +*************************************************************************/ +static void dforest_regressionsplit(const decisionforestbuilder* s, + dfworkbuf* workbuf, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_int_t n, + ae_int_t* info, + double* threshold, + double* e, + /* Real */ ae_vector* sortrbuf, + /* Real */ ae_vector* sortrbuf2, + ae_state *_state) +{ + ae_int_t i; + double vmin; + double vmax; + double bnd01; + double bnd12; + double bnd23; + ae_int_t total0; + ae_int_t total1; + ae_int_t total2; + ae_int_t total3; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t cnt2; + ae_int_t cnt3; + ae_int_t n0; + ae_int_t advanceby; + double v; + double v0; + double v1; + double rms; + ae_int_t n0prev; + ae_int_t k0; + ae_int_t k1; + + *info = 0; + *threshold = 0.0; + *e = 0.0; + + advanceby = 1; + if( n>=20 ) + { + advanceby = ae_maxint(2, ae_round((double)n*0.05, _state), _state); + } + + /* + * Sort data + * Quick check for degeneracy + */ + tagsortfastr(x, y, sortrbuf, sortrbuf2, n, _state); + v = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[n-1]); + if( !(ae_fp_less(x->ptr.p_double[0],v)&&ae_fp_less(v,x->ptr.p_double[n-1])) ) + { + *info = -1; + *threshold = x->ptr.p_double[n-1]; + *e = ae_maxrealnumber; + return; + } + + /* + * Prepare initial split. + * Evaluate current split, prepare next one, repeat. + */ + vmin = y->ptr.p_double[0]; + vmax = y->ptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + v = y->ptr.p_double[i]; + if( vvmax ) + { + vmax = v; + } + } + bnd12 = 0.5*(vmin+vmax); + bnd01 = 0.5*(vmin+bnd12); + bnd23 = 0.5*(vmax+bnd12); + total0 = 0; + total1 = 0; + total2 = 0; + total3 = 0; + for(i=0; i<=n-1; i++) + { + v = y->ptr.p_double[i]; + if( vptr.p_double[n0]==x->ptr.p_double[n0-1]) + { + n0 = n0+1; + } + ae_assert(n0ptr.p_double[i]; + if( vptr.p_double[n-1]; + *e = ae_maxrealnumber; + while(n0ptr.p_double[n0-1]+x->ptr.p_double[n0]); + if( *threshold<=x->ptr.p_double[n0-1] ) + { + *threshold = x->ptr.p_double[n0]; + } + } + + /* + * Advance + */ + n0prev = n0; + while(n0ptr.p_double[n0]; + while(n0ptr.p_double[n0]==v0) + { + v = y->ptr.p_double[n0]; + if( v0 ) + { + *e = ae_sqrt(*e/(double)(4*n), _state); + } +} + + +/************************************************************************* +Returns split: either deterministic split at the middle of [A,B], or randomly +chosen split. + +It is guaranteed that Anclasses; + if( nclasses==1 ) + { + + /* + * Store split to the tree + */ + treebuf->ptr.p_double[*treesize] = (double)(-1); + treebuf->ptr.p_double[*treesize+1] = leafval; + + /* + * Update training and OOB voting stats + */ + for(i=idx0; i<=idx1-1; i++) + { + j = workbuf->trnset.ptr.p_int[i]; + votebuf->trntotals.ptr.p_double[j] = votebuf->trntotals.ptr.p_double[j]+leafval; + votebuf->trncounts.ptr.p_int[j] = votebuf->trncounts.ptr.p_int[j]+1; + } + for(i=oobidx0; i<=oobidx1-1; i++) + { + j = workbuf->oobset.ptr.p_int[i]; + votebuf->oobtotals.ptr.p_double[j] = votebuf->oobtotals.ptr.p_double[j]+leafval; + votebuf->oobcounts.ptr.p_int[j] = votebuf->oobcounts.ptr.p_int[j]+1; + } + } + else + { + + /* + * Store split to the tree + */ + treebuf->ptr.p_double[*treesize] = (double)(-1); + treebuf->ptr.p_double[*treesize+1] = leafval; + + /* + * Update training and OOB voting stats + */ + leafvali = ae_round(leafval, _state); + for(i=idx0; i<=idx1-1; i++) + { + j = workbuf->trnset.ptr.p_int[i]; + votebuf->trntotals.ptr.p_double[j*nclasses+leafvali] = votebuf->trntotals.ptr.p_double[j*nclasses+leafvali]+(double)1; + votebuf->trncounts.ptr.p_int[j] = votebuf->trncounts.ptr.p_int[j]+1; + } + for(i=oobidx0; i<=oobidx1-1; i++) + { + j = workbuf->oobset.ptr.p_int[i]; + votebuf->oobtotals.ptr.p_double[j*nclasses+leafvali] = votebuf->oobtotals.ptr.p_double[j*nclasses+leafvali]+(double)1; + votebuf->oobcounts.ptr.p_int[j] = votebuf->oobcounts.ptr.p_int[j]+1; + } + } + *treesize = *treesize+dforest_leafnodewidth; +} + + +/************************************************************************* +This function performs generic and algorithm-specific preprocessing of the +dataset + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_analyzeandpreprocessdataset(decisionforestbuilder* s, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t npoints; + ae_int_t i; + ae_int_t j; + ae_bool isbinary; + double v; + double v0; + double v1; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(s->dstype==0, "no sparsity", _state); + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + + /* + * seed local RNG + */ + if( s->rdfglobalseed>0 ) + { + hqrndseed(s->rdfglobalseed, 3532, &rs, _state); + } + else + { + hqrndseed(ae_randominteger(30000, _state), 3532, &rs, _state); + } + + /* + * Generic processing + */ + ae_assert(npoints>=1, "BuildRandomForest: integrity check failed", _state); + rvectorsetlengthatleast(&s->dsmin, nvars, _state); + rvectorsetlengthatleast(&s->dsmax, nvars, _state); + bvectorsetlengthatleast(&s->dsbinary, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + v0 = s->dsdata.ptr.p_double[i*npoints+0]; + v1 = s->dsdata.ptr.p_double[i*npoints+0]; + for(j=1; j<=npoints-1; j++) + { + v = s->dsdata.ptr.p_double[i*npoints+j]; + if( vv1 ) + { + v1 = v; + } + } + s->dsmin.ptr.p_double[i] = v0; + s->dsmax.ptr.p_double[i] = v1; + ae_assert(ae_fp_less_eq(v0,v1), "BuildRandomForest: strange integrity check failure", _state); + isbinary = ae_true; + for(j=0; j<=npoints-1; j++) + { + v = s->dsdata.ptr.p_double[i*npoints+j]; + isbinary = isbinary&&(v==v0||v==v1); + } + s->dsbinary.ptr.p_bool[i] = isbinary; + } + if( nclasses==1 ) + { + s->dsravg = (double)(0); + for(i=0; i<=npoints-1; i++) + { + s->dsravg = s->dsravg+s->dsrval.ptr.p_double[i]; + } + s->dsravg = s->dsravg/(double)npoints; + } + else + { + ivectorsetlengthatleast(&s->dsctotals, nclasses, _state); + for(i=0; i<=nclasses-1; i++) + { + s->dsctotals.ptr.p_int[i] = 0; + } + for(i=0; i<=npoints-1; i++) + { + s->dsctotals.ptr.p_int[s->dsival.ptr.p_int[i]] = s->dsctotals.ptr.p_int[s->dsival.ptr.p_int[i]]+1; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function merges together trees generated during training and outputs +it to the decision forest. + +INPUT PARAMETERS: + S - decision forest builder object + NTrees - NTrees>=1, number of trees to train + +OUTPUT PARAMETERS: + DF - decision forest + Rep - report + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_mergetrees(decisionforestbuilder* s, + decisionforest* df, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t cursize; + ae_int_t offs; + dftreebuf *tree; + ae_smart_ptr _tree; + ae_vector treesizes; + ae_vector treeoffsets; + + ae_frame_make(_state, &_frame_block); + memset(&_tree, 0, sizeof(_tree)); + memset(&treesizes, 0, sizeof(treesizes)); + memset(&treeoffsets, 0, sizeof(treeoffsets)); + ae_smart_ptr_init(&_tree, (void**)&tree, ae_false, _state, ae_true); + ae_vector_init(&treesizes, 0, DT_INT, _state, ae_true); + ae_vector_init(&treeoffsets, 0, DT_INT, _state, ae_true); + + df->forestformat = dforest_dfuncompressedv0; + df->nvars = s->nvars; + df->nclasses = s->nclasses; + df->bufsize = 0; + df->ntrees = 0; + + /* + * Determine trees count + */ + ae_shared_pool_first_recycled(&s->treepool, &_tree, _state); + while(tree!=NULL) + { + df->ntrees = df->ntrees+1; + ae_shared_pool_next_recycled(&s->treepool, &_tree, _state); + } + ae_assert(df->ntrees>0, "MergeTrees: integrity check failed, zero trees count", _state); + + /* + * Determine individual tree sizes and total buffer size + */ + ae_vector_set_length(&treesizes, df->ntrees, _state); + for(i=0; i<=df->ntrees-1; i++) + { + treesizes.ptr.p_int[i] = -1; + } + ae_shared_pool_first_recycled(&s->treepool, &_tree, _state); + while(tree!=NULL) + { + ae_assert(tree->treeidx>=0&&tree->treeidxntrees, "MergeTrees: integrity check failed (wrong TreeIdx)", _state); + ae_assert(treesizes.ptr.p_int[tree->treeidx]<0, "MergeTrees: integrity check failed (duplicate TreeIdx)", _state); + df->bufsize = df->bufsize+ae_round(tree->treebuf.ptr.p_double[0], _state); + treesizes.ptr.p_int[tree->treeidx] = ae_round(tree->treebuf.ptr.p_double[0], _state); + ae_shared_pool_next_recycled(&s->treepool, &_tree, _state); + } + for(i=0; i<=df->ntrees-1; i++) + { + ae_assert(treesizes.ptr.p_int[i]>0, "MergeTrees: integrity check failed (wrong TreeSize)", _state); + } + + /* + * Determine offsets for individual trees in output buffer + */ + ae_vector_set_length(&treeoffsets, df->ntrees, _state); + treeoffsets.ptr.p_int[0] = 0; + for(i=1; i<=df->ntrees-1; i++) + { + treeoffsets.ptr.p_int[i] = treeoffsets.ptr.p_int[i-1]+treesizes.ptr.p_int[i-1]; + } + + /* + * Output trees + * + * NOTE: since ALGLIB 3.16.0 trees are sorted by tree index prior to + * output (necessary for variable importance estimation), that's + * why we need array of tree offsets + */ + ae_vector_set_length(&df->trees, df->bufsize, _state); + ae_shared_pool_first_recycled(&s->treepool, &_tree, _state); + while(tree!=NULL) + { + cursize = ae_round(tree->treebuf.ptr.p_double[0], _state); + offs = treeoffsets.ptr.p_int[tree->treeidx]; + for(i=0; i<=cursize-1; i++) + { + df->trees.ptr.p_double[offs+i] = tree->treebuf.ptr.p_double[i]; + } + ae_shared_pool_next_recycled(&s->treepool, &_tree, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function post-processes voting array and calculates TRN and OOB errors. + +INPUT PARAMETERS: + S - decision forest builder object + NTrees - number of trees in the forest + Buf - possibly preallocated vote buffer, its contents is + overwritten by this function + +OUTPUT PARAMETERS: + Rep - report fields corresponding to errors are updated + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +static void dforest_processvotingresults(decisionforestbuilder* s, + ae_int_t ntrees, + dfvotebuf* buf, + dfreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + dfvotebuf *vote; + ae_smart_ptr _vote; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t npoints; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k1; + double v; + ae_int_t avgrelcnt; + ae_int_t oobavgrelcnt; + + ae_frame_make(_state, &_frame_block); + memset(&_vote, 0, sizeof(_vote)); + ae_smart_ptr_init(&_vote, (void**)&vote, ae_false, _state, ae_true); + + npoints = s->npoints; + nvars = s->nvars; + nclasses = s->nclasses; + ae_assert(npoints>0, "DFOREST: integrity check failed", _state); + ae_assert(nvars>0, "DFOREST: integrity check failed", _state); + ae_assert(nclasses>0, "DFOREST: integrity check failed", _state); + + /* + * Prepare vote buffer + */ + rvectorsetlengthatleast(&buf->trntotals, npoints*nclasses, _state); + rvectorsetlengthatleast(&buf->oobtotals, npoints*nclasses, _state); + for(i=0; i<=npoints*nclasses-1; i++) + { + buf->trntotals.ptr.p_double[i] = (double)(0); + buf->oobtotals.ptr.p_double[i] = (double)(0); + } + ivectorsetlengthatleast(&buf->trncounts, npoints, _state); + ivectorsetlengthatleast(&buf->oobcounts, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + buf->trncounts.ptr.p_int[i] = 0; + buf->oobcounts.ptr.p_int[i] = 0; + } + + /* + * Merge voting arrays + */ + ae_shared_pool_first_recycled(&s->votepool, &_vote, _state); + while(vote!=NULL) + { + for(i=0; i<=npoints*nclasses-1; i++) + { + buf->trntotals.ptr.p_double[i] = buf->trntotals.ptr.p_double[i]+vote->trntotals.ptr.p_double[i]+vote->oobtotals.ptr.p_double[i]; + buf->oobtotals.ptr.p_double[i] = buf->oobtotals.ptr.p_double[i]+vote->oobtotals.ptr.p_double[i]; + } + for(i=0; i<=npoints-1; i++) + { + buf->trncounts.ptr.p_int[i] = buf->trncounts.ptr.p_int[i]+vote->trncounts.ptr.p_int[i]+vote->oobcounts.ptr.p_int[i]; + buf->oobcounts.ptr.p_int[i] = buf->oobcounts.ptr.p_int[i]+vote->oobcounts.ptr.p_int[i]; + } + ae_shared_pool_next_recycled(&s->votepool, &_vote, _state); + } + for(i=0; i<=npoints-1; i++) + { + v = (double)1/coalesce((double)(buf->trncounts.ptr.p_int[i]), (double)(1), _state); + for(j=0; j<=nclasses-1; j++) + { + buf->trntotals.ptr.p_double[i*nclasses+j] = buf->trntotals.ptr.p_double[i*nclasses+j]*v; + } + v = (double)1/coalesce((double)(buf->oobcounts.ptr.p_int[i]), (double)(1), _state); + for(j=0; j<=nclasses-1; j++) + { + buf->oobtotals.ptr.p_double[i*nclasses+j] = buf->oobtotals.ptr.p_double[i*nclasses+j]*v; + } + } + + /* + * Use aggregated voting data to output error metrics + */ + avgrelcnt = 0; + oobavgrelcnt = 0; + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->relclserror = (double)(0); + rep->avgce = (double)(0); + rep->oobrmserror = (double)(0); + rep->oobavgerror = (double)(0); + rep->oobavgrelerror = (double)(0); + rep->oobrelclserror = (double)(0); + rep->oobavgce = (double)(0); + for(i=0; i<=npoints-1; i++) + { + if( nclasses>1 ) + { + + /* + * classification-specific code + */ + k = s->dsival.ptr.p_int[i]; + for(j=0; j<=nclasses-1; j++) + { + v = buf->trntotals.ptr.p_double[i*nclasses+j]; + if( j==k ) + { + rep->avgce = rep->avgce-ae_log(coalesce(v, ae_minrealnumber, _state), _state); + rep->rmserror = rep->rmserror+ae_sqr(v-(double)1, _state); + rep->avgerror = rep->avgerror+ae_fabs(v-(double)1, _state); + rep->avgrelerror = rep->avgrelerror+ae_fabs(v-(double)1, _state); + inc(&avgrelcnt, _state); + } + else + { + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + } + v = buf->oobtotals.ptr.p_double[i*nclasses+j]; + if( j==k ) + { + rep->oobavgce = rep->oobavgce-ae_log(coalesce(v, ae_minrealnumber, _state), _state); + rep->oobrmserror = rep->oobrmserror+ae_sqr(v-(double)1, _state); + rep->oobavgerror = rep->oobavgerror+ae_fabs(v-(double)1, _state); + rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs(v-(double)1, _state); + inc(&oobavgrelcnt, _state); + } + else + { + rep->oobrmserror = rep->oobrmserror+ae_sqr(v, _state); + rep->oobavgerror = rep->oobavgerror+ae_fabs(v, _state); + } + } + + /* + * Classification errors are handled separately + */ + k1 = 0; + for(j=1; j<=nclasses-1; j++) + { + if( buf->trntotals.ptr.p_double[i*nclasses+j]>buf->trntotals.ptr.p_double[i*nclasses+k1] ) + { + k1 = j; + } + } + if( k1!=k ) + { + rep->relclserror = rep->relclserror+(double)1; + } + k1 = 0; + for(j=1; j<=nclasses-1; j++) + { + if( buf->oobtotals.ptr.p_double[i*nclasses+j]>buf->oobtotals.ptr.p_double[i*nclasses+k1] ) + { + k1 = j; + } + } + if( k1!=k ) + { + rep->oobrelclserror = rep->oobrelclserror+(double)1; + } + } + else + { + + /* + * regression-specific code + */ + v = buf->trntotals.ptr.p_double[i]-s->dsrval.ptr.p_double[i]; + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + if( ae_fp_neq(s->dsrval.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(v/s->dsrval.ptr.p_double[i], _state); + avgrelcnt = avgrelcnt+1; + } + v = buf->oobtotals.ptr.p_double[i]-s->dsrval.ptr.p_double[i]; + rep->oobrmserror = rep->oobrmserror+ae_sqr(v, _state); + rep->oobavgerror = rep->oobavgerror+ae_fabs(v, _state); + if( ae_fp_neq(s->dsrval.ptr.p_double[i],(double)(0)) ) + { + rep->oobavgrelerror = rep->oobavgrelerror+ae_fabs(v/s->dsrval.ptr.p_double[i], _state); + oobavgrelcnt = oobavgrelcnt+1; + } + } + } + rep->relclserror = rep->relclserror/(double)npoints; + rep->rmserror = ae_sqrt(rep->rmserror/(double)(npoints*nclasses), _state); + rep->avgerror = rep->avgerror/(double)(npoints*nclasses); + rep->avgrelerror = rep->avgrelerror/coalesce((double)(avgrelcnt), (double)(1), _state); + rep->oobrelclserror = rep->oobrelclserror/(double)npoints; + rep->oobrmserror = ae_sqrt(rep->oobrmserror/(double)(npoints*nclasses), _state); + rep->oobavgerror = rep->oobavgerror/(double)(npoints*nclasses); + rep->oobavgrelerror = rep->oobavgrelerror/coalesce((double)(oobavgrelcnt), (double)(1), _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs binary compression of decision forest, using either +8-bit mantissa (a bit more compact representation) or 16-bit mantissa for +splits and regression outputs. + +Forest is compressed in-place. + +Return value is a compression factor. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static double dforest_binarycompression(decisionforest* df, + ae_bool usemantissa8, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t size8; + ae_int_t size8i; + ae_int_t offssrc; + ae_int_t offsdst; + ae_int_t i; + ae_vector dummyi; + ae_int_t maxrawtreesize; + ae_vector compressedsizes; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&dummyi, 0, sizeof(dummyi)); + memset(&compressedsizes, 0, sizeof(compressedsizes)); + ae_vector_init(&dummyi, 0, DT_INT, _state, ae_true); + ae_vector_init(&compressedsizes, 0, DT_INT, _state, ae_true); + + + /* + * Quick exit if already compressed + */ + if( df->forestformat==dforest_dfcompressedv0 ) + { + result = (double)(1); + ae_frame_leave(_state); + return result; + } + + /* + * Check that source format is supported + */ + ae_assert(df->forestformat==dforest_dfuncompressedv0, "BinaryCompression: unexpected forest format", _state); + + /* + * Compute sizes of uncompressed and compressed trees. + */ + size8 = 0; + offssrc = 0; + maxrawtreesize = 0; + for(i=0; i<=df->ntrees-1; i++) + { + size8i = dforest_computecompressedsizerec(df, usemantissa8, offssrc, offssrc+1, &dummyi, ae_false, _state); + size8 = size8+dforest_computecompresseduintsize(size8i, _state)+size8i; + maxrawtreesize = ae_maxint(maxrawtreesize, ae_round(df->trees.ptr.p_double[offssrc], _state), _state); + offssrc = offssrc+ae_round(df->trees.ptr.p_double[offssrc], _state); + } + result = (double)(8*df->trees.cnt)/(double)(size8+1); + + /* + * Allocate memory and perform compression + */ + ae_vector_set_length(&(df->trees8), size8, _state); + ae_vector_set_length(&compressedsizes, maxrawtreesize, _state); + offssrc = 0; + offsdst = 0; + for(i=0; i<=df->ntrees-1; i++) + { + + /* + * Call compressed size evaluator one more time, now saving subtree sizes into temporary array + */ + size8i = dforest_computecompressedsizerec(df, usemantissa8, offssrc, offssrc+1, &compressedsizes, ae_true, _state); + + /* + * Output tree header (length in bytes) + */ + dforest_streamuint(&df->trees8, &offsdst, size8i, _state); + + /* + * Compress recursively + */ + dforest_compressrec(df, usemantissa8, offssrc, offssrc+1, &compressedsizes, &df->trees8, &offsdst, _state); + + /* + * Next tree + */ + offssrc = offssrc+ae_round(df->trees.ptr.p_double[offssrc], _state); + } + ae_assert(offsdst==size8, "BinaryCompression: integrity check failed (stream length)", _state); + + /* + * Finalize forest conversion, clear previously allocated memory + */ + df->forestformat = dforest_dfcompressedv0; + df->usemantissa8 = usemantissa8; + ae_vector_set_length(&df->trees, 0, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function returns exact number of bytes required to store compressed +version of the tree starting at location TreeBase. + +PARAMETERS: + DF - decision forest + UseMantissa8 - whether 8-bit or 16-bit mantissas are used to store + floating point numbers + TreeRoot - root of the specific tree being stored (offset in DF.Trees) + TreePos - position within tree (first location in the tree + is TreeRoot+1) + CompressedSizes - not referenced if SaveCompressedSizes is False; + otherwise, values computed by this function for + specific values of TreePos are stored to + CompressedSizes[TreePos-TreeRoot] (other elements + of the array are not referenced). + This array must be preallocated by caller. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t dforest_computecompressedsizerec(const decisionforest* df, + ae_bool usemantissa8, + ae_int_t treeroot, + ae_int_t treepos, + /* Integer */ ae_vector* compressedsizes, + ae_bool savecompressedsizes, + ae_state *_state) +{ + ae_int_t jmponbranch; + ae_int_t child0size; + ae_int_t child1size; + ae_int_t fpwidth; + ae_int_t result; + + + if( usemantissa8 ) + { + fpwidth = 2; + } + else + { + fpwidth = 3; + } + + /* + * Leaf or split? + */ + if( ae_fp_eq(df->trees.ptr.p_double[treepos],(double)(-1)) ) + { + + /* + * Leaf + */ + result = dforest_computecompresseduintsize(2*df->nvars, _state); + if( df->nclasses==1 ) + { + result = result+fpwidth; + } + else + { + result = result+dforest_computecompresseduintsize(ae_round(df->trees.ptr.p_double[treepos+1], _state), _state); + } + } + else + { + + /* + * Split + */ + jmponbranch = ae_round(df->trees.ptr.p_double[treepos+2], _state); + child0size = dforest_computecompressedsizerec(df, usemantissa8, treeroot, treepos+dforest_innernodewidth, compressedsizes, savecompressedsizes, _state); + child1size = dforest_computecompressedsizerec(df, usemantissa8, treeroot, treeroot+jmponbranch, compressedsizes, savecompressedsizes, _state); + if( child0size<=child1size ) + { + + /* + * Child #0 comes first because it is shorter + */ + result = dforest_computecompresseduintsize(ae_round(df->trees.ptr.p_double[treepos], _state), _state); + result = result+fpwidth; + result = result+dforest_computecompresseduintsize(child0size, _state); + } + else + { + + /* + * Child #1 comes first because it is shorter + */ + result = dforest_computecompresseduintsize(ae_round(df->trees.ptr.p_double[treepos], _state)+df->nvars, _state); + result = result+fpwidth; + result = result+dforest_computecompresseduintsize(child1size, _state); + } + result = result+child0size+child1size; + } + + /* + * Do we have to save compressed sizes? + */ + if( savecompressedsizes ) + { + ae_assert(treepos-treerootcnt, "ComputeCompressedSizeRec: integrity check failed", _state); + compressedsizes->ptr.p_int[treepos-treeroot] = result; + } + return result; +} + + +/************************************************************************* +This function returns exact number of bytes required to store compressed +version of the tree starting at location TreeBase. + +PARAMETERS: + DF - decision forest + UseMantissa8 - whether 8-bit or 16-bit mantissas are used to store + floating point numbers + TreeRoot - root of the specific tree being stored (offset in DF.Trees) + TreePos - position within tree (first location in the tree + is TreeRoot+1) + CompressedSizes - not referenced if SaveCompressedSizes is False; + otherwise, values computed by this function for + specific values of TreePos are stored to + CompressedSizes[TreePos-TreeRoot] (other elements + of the array are not referenced). + This array must be preallocated by caller. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static void dforest_compressrec(const decisionforest* df, + ae_bool usemantissa8, + ae_int_t treeroot, + ae_int_t treepos, + /* Integer */ const ae_vector* compressedsizes, + ae_vector* buf, + ae_int_t* dstoffs, + ae_state *_state) +{ + ae_int_t jmponbranch; + ae_int_t child0size; + ae_int_t child1size; + ae_int_t varidx; + double leafval; + double splitval; + ae_int_t dstoffsold; + + + dstoffsold = *dstoffs; + + /* + * Leaf or split? + */ + varidx = ae_round(df->trees.ptr.p_double[treepos], _state); + if( varidx==-1 ) + { + + /* + * Leaf node: + * * stream special value which denotes leaf (2*NVars) + * * then, stream scalar value (floating point) or class number (unsigned integer) + */ + leafval = df->trees.ptr.p_double[treepos+1]; + dforest_streamuint(buf, dstoffs, 2*df->nvars, _state); + if( df->nclasses==1 ) + { + dforest_streamfloat(buf, usemantissa8, dstoffs, leafval, _state); + } + else + { + dforest_streamuint(buf, dstoffs, ae_round(leafval, _state), _state); + } + } + else + { + + /* + * Split node: + * * fetch compressed sizes of child nodes, decide which child goes first + */ + jmponbranch = ae_round(df->trees.ptr.p_double[treepos+2], _state); + splitval = df->trees.ptr.p_double[treepos+1]; + child0size = compressedsizes->ptr.p_int[treepos+dforest_innernodewidth-treeroot]; + child1size = compressedsizes->ptr.p_int[treeroot+jmponbranch-treeroot]; + if( child0size<=child1size ) + { + + /* + * Child #0 comes first because it is shorter: + * * stream variable index used for splitting; + * value in [0,NVars) range indicates that split is + * "if VAR=VAL then BRANCH0 else BRANCH1" + * * stream value used for splitting + * * stream children #0 and #1 + */ + dforest_streamuint(buf, dstoffs, varidx+df->nvars, _state); + dforest_streamfloat(buf, usemantissa8, dstoffs, splitval, _state); + dforest_streamuint(buf, dstoffs, child1size, _state); + dforest_compressrec(df, usemantissa8, treeroot, treeroot+jmponbranch, compressedsizes, buf, dstoffs, _state); + dforest_compressrec(df, usemantissa8, treeroot, treepos+dforest_innernodewidth, compressedsizes, buf, dstoffs, _state); + } + } + + /* + * Integrity check at the end + */ + ae_assert(*dstoffs-dstoffsold==compressedsizes->ptr.p_int[treepos-treeroot], "CompressRec: integrity check failed (compressed size at leaf)", _state); +} + + +/************************************************************************* +This function returns exact number of bytes required to store compressed +unsigned integer number (negative arguments result in assertion being +generated). + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t dforest_computecompresseduintsize(ae_int_t v, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(v>=0, "Assertion failed", _state); + result = 1; + while(v>=128) + { + v = v/128; + result = result+1; + } + return result; +} + + +/************************************************************************* +This function stores compressed unsigned integer number (negative arguments +result in assertion being generated) to byte array at location Offs and +increments Offs by number of bytes being stored. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static void dforest_streamuint(ae_vector* buf, + ae_int_t* offs, + ae_int_t v, + ae_state *_state) +{ + ae_int_t v0; + + + ae_assert(v>=0, "Assertion failed", _state); + for(;;) + { + + /* + * Save 7 least significant bits of V, use 8th bit as a flag which + * tells us whether subsequent 7-bit packages will be sent. + */ + v0 = v%128; + if( v>=128 ) + { + v0 = v0+128; + } + buf->ptr.p_ubyte[*(offs)] = (unsigned char)(v0); + *offs = *offs+1; + v = v/128; + if( v==0 ) + { + break; + } + } +} + + +/************************************************************************* +This function reads compressed unsigned integer number from byte array +starting at location Offs and increments Offs by number of bytes being +read. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t dforest_unstreamuint(const ae_vector* buf, + ae_int_t* offs, + ae_state *_state) +{ + ae_int_t v0; + ae_int_t p; + ae_int_t result; + + + result = 0; + p = 1; + for(;;) + { + + /* + * Rad 7 bits of V, use 8th bit as a flag which tells us whether + * subsequent 7-bit packages will be received. + */ + v0 = buf->ptr.p_ubyte[*(offs)]; + *offs = *offs+1; + result = result+v0%128*p; + if( v0<128 ) + { + break; + } + p = p*128; + } + return result; +} + + +/************************************************************************* +This function stores compressed floating point number to byte array at +location Offs and increments Offs by number of bytes being stored. + +Either 8-bit mantissa or 16-bit mantissa is used. The exponent is always +7 bits of exponent + sign. Values which do not fit into exponent range are +truncated to fit. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static void dforest_streamfloat(ae_vector* buf, + ae_bool usemantissa8, + ae_int_t* offs, + double v, + ae_state *_state) +{ + ae_int_t signbit; + ae_int_t e; + ae_int_t m; + double twopow30; + double twopowm30; + double twopow10; + double twopowm10; + + + ae_assert(ae_isfinite(v, _state), "StreamFloat: V is not finite number", _state); + + /* + * Special case: zero + */ + if( v==0.0 ) + { + if( usemantissa8 ) + { + buf->ptr.p_ubyte[*offs+0] = (unsigned char)(0); + buf->ptr.p_ubyte[*offs+1] = (unsigned char)(0); + *offs = *offs+2; + } + else + { + buf->ptr.p_ubyte[*offs+0] = (unsigned char)(0); + buf->ptr.p_ubyte[*offs+1] = (unsigned char)(0); + buf->ptr.p_ubyte[*offs+2] = (unsigned char)(0); + *offs = *offs+3; + } + return; + } + + /* + * Handle sign + */ + signbit = 0; + if( v<0.0 ) + { + v = -v; + signbit = 128; + } + + /* + * Compute exponent + */ + twopow30 = (double)(1073741824); + twopow10 = (double)(1024); + twopowm30 = 1.0/twopow30; + twopowm10 = 1.0/twopow10; + e = 0; + while(v>=twopow30) + { + v = v*twopowm30; + e = e+30; + } + while(v>=twopow10) + { + v = v*twopowm10; + e = e+10; + } + while(v>=1.0) + { + v = v*0.5; + e = e+1; + } + while(v=0.5&&v<1.0, "StreamFloat: integrity check failed", _state); + + /* + * Handle exponent underflow/overflow + */ + if( e<-63 ) + { + signbit = 0; + e = 0; + v = (double)(0); + } + if( e>63 ) + { + e = 63; + v = 1.0; + } + + /* + * Save to stream + */ + if( usemantissa8 ) + { + m = ae_round(v*(double)256, _state); + if( m==256 ) + { + m = m/2; + e = ae_minint(e+1, 63, _state); + } + buf->ptr.p_ubyte[*offs+0] = (unsigned char)(e+64+signbit); + buf->ptr.p_ubyte[*offs+1] = (unsigned char)(m); + *offs = *offs+2; + } + else + { + m = ae_round(v*(double)65536, _state); + if( m==65536 ) + { + m = m/2; + e = ae_minint(e+1, 63, _state); + } + buf->ptr.p_ubyte[*offs+0] = (unsigned char)(e+64+signbit); + buf->ptr.p_ubyte[*offs+1] = (unsigned char)(m%256); + buf->ptr.p_ubyte[*offs+2] = (unsigned char)(m/256); + *offs = *offs+3; + } +} + + +/************************************************************************* +This function reads compressed floating point number from the byte array +starting from location Offs and increments Offs by number of bytes being +read. + +Either 8-bit mantissa or 16-bit mantissa is used. The exponent is always +7 bits of exponent + sign. Values which do not fit into exponent range are +truncated to fit. + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +static double dforest_unstreamfloat(const ae_vector* buf, + ae_bool usemantissa8, + ae_int_t* offs, + ae_state *_state) +{ + ae_int_t e; + double v; + double inv256; + double result; + + + + /* + * Read from stream + */ + inv256 = 1.0/256.0; + if( usemantissa8 ) + { + e = buf->ptr.p_ubyte[*offs+0]; + v = (double)buf->ptr.p_ubyte[*offs+1]*inv256; + *offs = *offs+2; + } + else + { + e = buf->ptr.p_ubyte[*offs+0]; + v = ((double)buf->ptr.p_ubyte[*offs+1]*inv256+(double)buf->ptr.p_ubyte[*offs+2])*inv256; + *offs = *offs+3; + } + + /* + * Decode + */ + if( e>128 ) + { + v = -v; + e = e-128; + } + e = e-64; + result = dforest_xfastpow((double)(2), e, _state)*v; + return result; +} + + +/************************************************************************* +Classification error +*************************************************************************/ +static ae_int_t dforest_dfclserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t tmpi; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + if( df->nclasses<=1 ) + { + result = 0; + ae_frame_leave(_state); + return result; + } + ae_vector_set_length(&x, df->nvars-1+1, _state); + ae_vector_set_length(&y, df->nclasses-1+1, _state); + result = 0; + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,df->nvars-1)); + dfprocess(df, &x, &y, _state); + k = ae_round(xy->ptr.pp_double[i][df->nvars], _state); + tmpi = 0; + for(j=1; j<=df->nclasses-1; j++) + { + if( ae_fp_greater(y.ptr.p_double[j],y.ptr.p_double[tmpi]) ) + { + tmpi = j; + } + } + if( tmpi!=k ) + { + result = result+1; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Internal subroutine for processing one decision tree stored in uncompressed +format starting at SubtreeRoot (this index points to the header of the tree, +not its first node). First node being processed is located at NodeOffs. +*************************************************************************/ +static void dforest_dfprocessinternaluncompressed(const decisionforest* df, + ae_int_t subtreeroot, + ae_int_t nodeoffs, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t idx; + + + ae_assert(df->forestformat==dforest_dfuncompressedv0, "DFProcessInternal: unexpected forest format", _state); + + /* + * Navigate through the tree + */ + for(;;) + { + if( ae_fp_eq(df->trees.ptr.p_double[nodeoffs],(double)(-1)) ) + { + if( df->nclasses==1 ) + { + y->ptr.p_double[0] = y->ptr.p_double[0]+df->trees.ptr.p_double[nodeoffs+1]; + } + else + { + idx = ae_round(df->trees.ptr.p_double[nodeoffs+1], _state); + y->ptr.p_double[idx] = y->ptr.p_double[idx]+(double)1; + } + break; + } + if( x->ptr.p_double[ae_round(df->trees.ptr.p_double[nodeoffs], _state)]trees.ptr.p_double[nodeoffs+1] ) + { + nodeoffs = nodeoffs+dforest_innernodewidth; + } + else + { + nodeoffs = subtreeroot+ae_round(df->trees.ptr.p_double[nodeoffs+2], _state); + } + } +} + + +/************************************************************************* +Internal subroutine for processing one decision tree stored in compressed +format starting at Offs (this index points to the first node of the tree, +right past the header field). +*************************************************************************/ +static void dforest_dfprocessinternalcompressed(const decisionforest* df, + ae_int_t offs, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t leafindicator; + ae_int_t varidx; + double splitval; + ae_int_t jmplen; + double leafval; + ae_int_t leafcls; + + + ae_assert(df->forestformat==dforest_dfcompressedv0, "DFProcessInternal: unexpected forest format", _state); + + /* + * Navigate through the tree + */ + leafindicator = 2*df->nvars; + for(;;) + { + + /* + * Read variable idx + */ + varidx = dforest_unstreamuint(&df->trees8, &offs, _state); + + /* + * Is it leaf? + */ + if( varidx==leafindicator ) + { + if( df->nclasses==1 ) + { + + /* + * Regression forest + */ + leafval = dforest_unstreamfloat(&df->trees8, df->usemantissa8, &offs, _state); + y->ptr.p_double[0] = y->ptr.p_double[0]+leafval; + } + else + { + + /* + * Classification forest + */ + leafcls = dforest_unstreamuint(&df->trees8, &offs, _state); + y->ptr.p_double[leafcls] = y->ptr.p_double[leafcls]+(double)1; + } + break; + } + + /* + * Process node + */ + splitval = dforest_unstreamfloat(&df->trees8, df->usemantissa8, &offs, _state); + jmplen = dforest_unstreamuint(&df->trees8, &offs, _state); + if( varidxnvars ) + { + + /* + * The split rule is "if VARptr.p_double[varidx]>=splitval ) + { + offs = offs+jmplen; + } + } + else + { + + /* + * The split rule is "if VAR>=VAL then BRANCH0 else BRANCH1" + */ + varidx = varidx-df->nvars; + if( x->ptr.p_double[varidx]0 ) + { + if( n%2==0 ) + { + result = dforest_xfastpow(r, n/2, _state); + result = result*result; + } + else + { + result = r*dforest_xfastpow(r, n-1, _state); + } + return result; + } + if( n==0 ) + { + result = (double)(1); + } + if( n<0 ) + { + result = dforest_xfastpow((double)1/r, -n, _state); + } + return result; +} + + +void _decisionforestbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + decisionforestbuilder *p = (decisionforestbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->dsdata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsrval, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsival, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->dsmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsbinary, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->dsctotals, 0, DT_INT, _state, make_automatic); + ae_shared_pool_init(&p->workpool, _state, make_automatic); + ae_shared_pool_init(&p->votepool, _state, make_automatic); + ae_shared_pool_init(&p->treepool, _state, make_automatic); + ae_shared_pool_init(&p->treefactory, _state, make_automatic); + ae_matrix_init(&p->iobmatrix, 0, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->varimpshuffle2, 0, DT_INT, _state, make_automatic); +} + + +void _decisionforestbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + decisionforestbuilder *dst = (decisionforestbuilder*)_dst; + const decisionforestbuilder *src = (const decisionforestbuilder*)_src; + dst->dstype = src->dstype; + dst->npoints = src->npoints; + dst->nvars = src->nvars; + dst->nclasses = src->nclasses; + ae_vector_init_copy(&dst->dsdata, &src->dsdata, _state, make_automatic); + ae_vector_init_copy(&dst->dsrval, &src->dsrval, _state, make_automatic); + ae_vector_init_copy(&dst->dsival, &src->dsival, _state, make_automatic); + dst->rdfalgo = src->rdfalgo; + dst->rdfratio = src->rdfratio; + dst->rdfvars = src->rdfvars; + dst->rdfglobalseed = src->rdfglobalseed; + dst->rdfsplitstrength = src->rdfsplitstrength; + dst->rdfimportance = src->rdfimportance; + ae_vector_init_copy(&dst->dsmin, &src->dsmin, _state, make_automatic); + ae_vector_init_copy(&dst->dsmax, &src->dsmax, _state, make_automatic); + ae_vector_init_copy(&dst->dsbinary, &src->dsbinary, _state, make_automatic); + dst->dsravg = src->dsravg; + ae_vector_init_copy(&dst->dsctotals, &src->dsctotals, _state, make_automatic); + dst->rdfprogress = src->rdfprogress; + dst->rdftotal = src->rdftotal; + ae_shared_pool_init_copy(&dst->workpool, &src->workpool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->votepool, &src->votepool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->treepool, &src->treepool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->treefactory, &src->treefactory, _state, make_automatic); + dst->neediobmatrix = src->neediobmatrix; + ae_matrix_init_copy(&dst->iobmatrix, &src->iobmatrix, _state, make_automatic); + ae_vector_init_copy(&dst->varimpshuffle2, &src->varimpshuffle2, _state, make_automatic); +} + + +void _decisionforestbuilder_clear(void* _p) +{ + decisionforestbuilder *p = (decisionforestbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->dsdata); + ae_vector_clear(&p->dsrval); + ae_vector_clear(&p->dsival); + ae_vector_clear(&p->dsmin); + ae_vector_clear(&p->dsmax); + ae_vector_clear(&p->dsbinary); + ae_vector_clear(&p->dsctotals); + ae_shared_pool_clear(&p->workpool); + ae_shared_pool_clear(&p->votepool); + ae_shared_pool_clear(&p->treepool); + ae_shared_pool_clear(&p->treefactory); + ae_matrix_clear(&p->iobmatrix); + ae_vector_clear(&p->varimpshuffle2); +} + + +void _decisionforestbuilder_destroy(void* _p) +{ + decisionforestbuilder *p = (decisionforestbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->dsdata); + ae_vector_destroy(&p->dsrval); + ae_vector_destroy(&p->dsival); + ae_vector_destroy(&p->dsmin); + ae_vector_destroy(&p->dsmax); + ae_vector_destroy(&p->dsbinary); + ae_vector_destroy(&p->dsctotals); + ae_shared_pool_destroy(&p->workpool); + ae_shared_pool_destroy(&p->votepool); + ae_shared_pool_destroy(&p->treepool); + ae_shared_pool_destroy(&p->treefactory); + ae_matrix_destroy(&p->iobmatrix); + ae_vector_destroy(&p->varimpshuffle2); +} + + +void _dfworkbuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfworkbuf *p = (dfworkbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->classpriors, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->varpool, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->trnset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->trnlabelsr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->trnlabelsi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->oobset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ooblabelsr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ooblabelsi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->treebuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curvals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bestvals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0i, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp1i, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp0r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp3r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpnrms2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->classtotals0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->classtotals1, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->classtotals01, 0, DT_INT, _state, make_automatic); +} + + +void _dfworkbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfworkbuf *dst = (dfworkbuf*)_dst; + const dfworkbuf *src = (const dfworkbuf*)_src; + ae_vector_init_copy(&dst->classpriors, &src->classpriors, _state, make_automatic); + ae_vector_init_copy(&dst->varpool, &src->varpool, _state, make_automatic); + dst->varpoolsize = src->varpoolsize; + ae_vector_init_copy(&dst->trnset, &src->trnset, _state, make_automatic); + dst->trnsize = src->trnsize; + ae_vector_init_copy(&dst->trnlabelsr, &src->trnlabelsr, _state, make_automatic); + ae_vector_init_copy(&dst->trnlabelsi, &src->trnlabelsi, _state, make_automatic); + ae_vector_init_copy(&dst->oobset, &src->oobset, _state, make_automatic); + dst->oobsize = src->oobsize; + ae_vector_init_copy(&dst->ooblabelsr, &src->ooblabelsr, _state, make_automatic); + ae_vector_init_copy(&dst->ooblabelsi, &src->ooblabelsi, _state, make_automatic); + ae_vector_init_copy(&dst->treebuf, &src->treebuf, _state, make_automatic); + ae_vector_init_copy(&dst->curvals, &src->curvals, _state, make_automatic); + ae_vector_init_copy(&dst->bestvals, &src->bestvals, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0i, &src->tmp0i, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1i, &src->tmp1i, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0r, &src->tmp0r, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1r, &src->tmp1r, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2r, &src->tmp2r, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3r, &src->tmp3r, _state, make_automatic); + ae_vector_init_copy(&dst->tmpnrms2, &src->tmpnrms2, _state, make_automatic); + ae_vector_init_copy(&dst->classtotals0, &src->classtotals0, _state, make_automatic); + ae_vector_init_copy(&dst->classtotals1, &src->classtotals1, _state, make_automatic); + ae_vector_init_copy(&dst->classtotals01, &src->classtotals01, _state, make_automatic); +} + + +void _dfworkbuf_clear(void* _p) +{ + dfworkbuf *p = (dfworkbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->classpriors); + ae_vector_clear(&p->varpool); + ae_vector_clear(&p->trnset); + ae_vector_clear(&p->trnlabelsr); + ae_vector_clear(&p->trnlabelsi); + ae_vector_clear(&p->oobset); + ae_vector_clear(&p->ooblabelsr); + ae_vector_clear(&p->ooblabelsi); + ae_vector_clear(&p->treebuf); + ae_vector_clear(&p->curvals); + ae_vector_clear(&p->bestvals); + ae_vector_clear(&p->tmp0i); + ae_vector_clear(&p->tmp1i); + ae_vector_clear(&p->tmp0r); + ae_vector_clear(&p->tmp1r); + ae_vector_clear(&p->tmp2r); + ae_vector_clear(&p->tmp3r); + ae_vector_clear(&p->tmpnrms2); + ae_vector_clear(&p->classtotals0); + ae_vector_clear(&p->classtotals1); + ae_vector_clear(&p->classtotals01); +} + + +void _dfworkbuf_destroy(void* _p) +{ + dfworkbuf *p = (dfworkbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->classpriors); + ae_vector_destroy(&p->varpool); + ae_vector_destroy(&p->trnset); + ae_vector_destroy(&p->trnlabelsr); + ae_vector_destroy(&p->trnlabelsi); + ae_vector_destroy(&p->oobset); + ae_vector_destroy(&p->ooblabelsr); + ae_vector_destroy(&p->ooblabelsi); + ae_vector_destroy(&p->treebuf); + ae_vector_destroy(&p->curvals); + ae_vector_destroy(&p->bestvals); + ae_vector_destroy(&p->tmp0i); + ae_vector_destroy(&p->tmp1i); + ae_vector_destroy(&p->tmp0r); + ae_vector_destroy(&p->tmp1r); + ae_vector_destroy(&p->tmp2r); + ae_vector_destroy(&p->tmp3r); + ae_vector_destroy(&p->tmpnrms2); + ae_vector_destroy(&p->classtotals0); + ae_vector_destroy(&p->classtotals1); + ae_vector_destroy(&p->classtotals01); +} + + +void _dfvotebuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfvotebuf *p = (dfvotebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->trntotals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->oobtotals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->trncounts, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->oobcounts, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->giniimportances, 0, DT_REAL, _state, make_automatic); +} + + +void _dfvotebuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfvotebuf *dst = (dfvotebuf*)_dst; + const dfvotebuf *src = (const dfvotebuf*)_src; + ae_vector_init_copy(&dst->trntotals, &src->trntotals, _state, make_automatic); + ae_vector_init_copy(&dst->oobtotals, &src->oobtotals, _state, make_automatic); + ae_vector_init_copy(&dst->trncounts, &src->trncounts, _state, make_automatic); + ae_vector_init_copy(&dst->oobcounts, &src->oobcounts, _state, make_automatic); + ae_vector_init_copy(&dst->giniimportances, &src->giniimportances, _state, make_automatic); +} + + +void _dfvotebuf_clear(void* _p) +{ + dfvotebuf *p = (dfvotebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->trntotals); + ae_vector_clear(&p->oobtotals); + ae_vector_clear(&p->trncounts); + ae_vector_clear(&p->oobcounts); + ae_vector_clear(&p->giniimportances); +} + + +void _dfvotebuf_destroy(void* _p) +{ + dfvotebuf *p = (dfvotebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->trntotals); + ae_vector_destroy(&p->oobtotals); + ae_vector_destroy(&p->trncounts); + ae_vector_destroy(&p->oobcounts); + ae_vector_destroy(&p->giniimportances); +} + + +void _dfpermimpbuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfpermimpbuf *p = (dfpermimpbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->losses, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xraw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xdist, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->targety, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->startnodes, 0, DT_INT, _state, make_automatic); +} + + +void _dfpermimpbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfpermimpbuf *dst = (dfpermimpbuf*)_dst; + const dfpermimpbuf *src = (const dfpermimpbuf*)_src; + ae_vector_init_copy(&dst->losses, &src->losses, _state, make_automatic); + ae_vector_init_copy(&dst->xraw, &src->xraw, _state, make_automatic); + ae_vector_init_copy(&dst->xdist, &src->xdist, _state, make_automatic); + ae_vector_init_copy(&dst->xcur, &src->xcur, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->yv, &src->yv, _state, make_automatic); + ae_vector_init_copy(&dst->targety, &src->targety, _state, make_automatic); + ae_vector_init_copy(&dst->startnodes, &src->startnodes, _state, make_automatic); +} + + +void _dfpermimpbuf_clear(void* _p) +{ + dfpermimpbuf *p = (dfpermimpbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->losses); + ae_vector_clear(&p->xraw); + ae_vector_clear(&p->xdist); + ae_vector_clear(&p->xcur); + ae_vector_clear(&p->y); + ae_vector_clear(&p->yv); + ae_vector_clear(&p->targety); + ae_vector_clear(&p->startnodes); +} + + +void _dfpermimpbuf_destroy(void* _p) +{ + dfpermimpbuf *p = (dfpermimpbuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->losses); + ae_vector_destroy(&p->xraw); + ae_vector_destroy(&p->xdist); + ae_vector_destroy(&p->xcur); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->yv); + ae_vector_destroy(&p->targety); + ae_vector_destroy(&p->startnodes); +} + + +void _dftreebuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dftreebuf *p = (dftreebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->treebuf, 0, DT_REAL, _state, make_automatic); +} + + +void _dftreebuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dftreebuf *dst = (dftreebuf*)_dst; + const dftreebuf *src = (const dftreebuf*)_src; + ae_vector_init_copy(&dst->treebuf, &src->treebuf, _state, make_automatic); + dst->treeidx = src->treeidx; +} + + +void _dftreebuf_clear(void* _p) +{ + dftreebuf *p = (dftreebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->treebuf); +} + + +void _dftreebuf_destroy(void* _p) +{ + dftreebuf *p = (dftreebuf*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->treebuf); +} + + +void _decisionforestbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + decisionforestbuffer *p = (decisionforestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); +} + + +void _decisionforestbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + decisionforestbuffer *dst = (decisionforestbuffer*)_dst; + const decisionforestbuffer *src = (const decisionforestbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); +} + + +void _decisionforestbuffer_clear(void* _p) +{ + decisionforestbuffer *p = (decisionforestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); +} + + +void _decisionforestbuffer_destroy(void* _p) +{ + decisionforestbuffer *p = (decisionforestbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); +} + + +void _decisionforest_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + decisionforest *p = (decisionforest*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->trees, 0, DT_REAL, _state, make_automatic); + _decisionforestbuffer_init(&p->buffer, _state, make_automatic); + ae_vector_init(&p->trees8, 0, DT_BYTE, _state, make_automatic); +} + + +void _decisionforest_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + decisionforest *dst = (decisionforest*)_dst; + const decisionforest *src = (const decisionforest*)_src; + dst->forestformat = src->forestformat; + dst->usemantissa8 = src->usemantissa8; + dst->nvars = src->nvars; + dst->nclasses = src->nclasses; + dst->ntrees = src->ntrees; + dst->bufsize = src->bufsize; + ae_vector_init_copy(&dst->trees, &src->trees, _state, make_automatic); + _decisionforestbuffer_init_copy(&dst->buffer, &src->buffer, _state, make_automatic); + ae_vector_init_copy(&dst->trees8, &src->trees8, _state, make_automatic); +} + + +void _decisionforest_clear(void* _p) +{ + decisionforest *p = (decisionforest*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->trees); + _decisionforestbuffer_clear(&p->buffer); + ae_vector_clear(&p->trees8); +} + + +void _decisionforest_destroy(void* _p) +{ + decisionforest *p = (decisionforest*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->trees); + _decisionforestbuffer_destroy(&p->buffer); + ae_vector_destroy(&p->trees8); +} + + +void _dfreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfreport *p = (dfreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->topvars, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->varimportances, 0, DT_REAL, _state, make_automatic); +} + + +void _dfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfreport *dst = (dfreport*)_dst; + const dfreport *src = (const dfreport*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->oobrelclserror = src->oobrelclserror; + dst->oobavgce = src->oobavgce; + dst->oobrmserror = src->oobrmserror; + dst->oobavgerror = src->oobavgerror; + dst->oobavgrelerror = src->oobavgrelerror; + ae_vector_init_copy(&dst->topvars, &src->topvars, _state, make_automatic); + ae_vector_init_copy(&dst->varimportances, &src->varimportances, _state, make_automatic); +} + + +void _dfreport_clear(void* _p) +{ + dfreport *p = (dfreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->topvars); + ae_vector_clear(&p->varimportances); +} + + +void _dfreport_destroy(void* _p) +{ + dfreport *p = (dfreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->topvars); + ae_vector_destroy(&p->varimportances); +} + + +void _dfinternalbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfinternalbuffers *p = (dfinternalbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->treebuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idxbuf, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpbufr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpbufr2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpbufi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->classibuf, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sortrbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sortrbuf2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sortibuf, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->varpool, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->evsbin, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->evssplits, 0, DT_REAL, _state, make_automatic); +} + + +void _dfinternalbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfinternalbuffers *dst = (dfinternalbuffers*)_dst; + const dfinternalbuffers *src = (const dfinternalbuffers*)_src; + ae_vector_init_copy(&dst->treebuf, &src->treebuf, _state, make_automatic); + ae_vector_init_copy(&dst->idxbuf, &src->idxbuf, _state, make_automatic); + ae_vector_init_copy(&dst->tmpbufr, &src->tmpbufr, _state, make_automatic); + ae_vector_init_copy(&dst->tmpbufr2, &src->tmpbufr2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpbufi, &src->tmpbufi, _state, make_automatic); + ae_vector_init_copy(&dst->classibuf, &src->classibuf, _state, make_automatic); + ae_vector_init_copy(&dst->sortrbuf, &src->sortrbuf, _state, make_automatic); + ae_vector_init_copy(&dst->sortrbuf2, &src->sortrbuf2, _state, make_automatic); + ae_vector_init_copy(&dst->sortibuf, &src->sortibuf, _state, make_automatic); + ae_vector_init_copy(&dst->varpool, &src->varpool, _state, make_automatic); + ae_vector_init_copy(&dst->evsbin, &src->evsbin, _state, make_automatic); + ae_vector_init_copy(&dst->evssplits, &src->evssplits, _state, make_automatic); +} + + +void _dfinternalbuffers_clear(void* _p) +{ + dfinternalbuffers *p = (dfinternalbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->treebuf); + ae_vector_clear(&p->idxbuf); + ae_vector_clear(&p->tmpbufr); + ae_vector_clear(&p->tmpbufr2); + ae_vector_clear(&p->tmpbufi); + ae_vector_clear(&p->classibuf); + ae_vector_clear(&p->sortrbuf); + ae_vector_clear(&p->sortrbuf2); + ae_vector_clear(&p->sortibuf); + ae_vector_clear(&p->varpool); + ae_vector_clear(&p->evsbin); + ae_vector_clear(&p->evssplits); +} + + +void _dfinternalbuffers_destroy(void* _p) +{ + dfinternalbuffers *p = (dfinternalbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->treebuf); + ae_vector_destroy(&p->idxbuf); + ae_vector_destroy(&p->tmpbufr); + ae_vector_destroy(&p->tmpbufr2); + ae_vector_destroy(&p->tmpbufi); + ae_vector_destroy(&p->classibuf); + ae_vector_destroy(&p->sortrbuf); + ae_vector_destroy(&p->sortrbuf2); + ae_vector_destroy(&p->sortibuf); + ae_vector_destroy(&p->varpool); + ae_vector_destroy(&p->evsbin); + ae_vector_destroy(&p->evssplits); +} + + +#endif +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Linear regression + +Subroutine builds model: + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) + +and model found in ALGLIB format, covariation matrix, training set errors +(rms, average, average relative) and leave-one-out cross-validation +estimate of the generalization error. CV estimate calculated using fast +algorithm with O(NPoints*NVars) complexity. + +When covariation matrix is calculated standard deviations of function +values are assumed to be equal to RMS error on the training set. + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + NPoints - training set size, NPoints>NVars+1. An exception is + generated otherwise. + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuild(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector s; + ae_int_t i; + double sigma2; + + ae_frame_make(_state, &_frame_block); + memset(&s, 0, sizeof(s)); + _linearmodel_clear(lm); + _lrreport_clear(rep); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + + ae_assert(nvars>=1, "LRBuild: NVars<1", _state); + ae_assert(npoints>nvars+1, "LRBuild: NPoints is less than NVars+1", _state); + ae_assert(xy->rows>=npoints, "LRBuild: rows(XY)cols>=nvars+1, "LRBuild: cols(XY)rmserror, _state)*(double)npoints/(double)(npoints-nvars-1); + for(i=0; i<=nvars; i++) + { + ae_v_muld(&rep->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Linear regression + +Variant of LRBuild which uses vector of standatd deviations (errors in +function values). + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + S - standard deviations (errors in function values) + array[NPoints], S[i]>0. + NPoints - training set size, NPoints>NVars+1 + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuilds(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xyi; + ae_vector x; + ae_vector means; + ae_vector sigmas; + ae_int_t i; + ae_int_t j; + double v; + ae_int_t offs; + double mean; + double variance; + double skewness; + double kurtosis; + + ae_frame_make(_state, &_frame_block); + memset(&xyi, 0, sizeof(xyi)); + memset(&x, 0, sizeof(x)); + memset(&means, 0, sizeof(means)); + memset(&sigmas, 0, sizeof(sigmas)); + _linearmodel_clear(lm); + _lrreport_clear(rep); + ae_matrix_init(&xyi, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&means, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sigmas, 0, DT_REAL, _state, ae_true); + + ae_assert(nvars>=1, "LRBuildS: NVars<1", _state); + ae_assert(npoints>nvars+1, "LRBuildS: NPoints is less than NVars+1", _state); + ae_assert(xy->rows>=npoints, "LRBuildS: rows(XY)cols>=nvars+1, "LRBuildS: cols(XY)cnt>=npoints, "LRBuildS: length(S)ptr.p_double[i],(double)(0)), "LRBuildS: S[I]<=0", _state); + } + + /* + * Copy data, add one more column (constant term) + */ + ae_matrix_set_length(&xyi, npoints-1+1, nvars+1+1, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&xyi.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + xyi.ptr.pp_double[i][nvars] = (double)(1); + xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; + } + + /* + * Standartization + */ + ae_vector_set_length(&x, npoints-1+1, _state); + ae_vector_set_length(&means, nvars-1+1, _state); + ae_vector_set_length(&sigmas, nvars-1+1, _state); + for(j=0; j<=nvars-1; j++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); + samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); + means.ptr.p_double[j] = mean; + sigmas.ptr.p_double[j] = ae_sqrt(variance, _state); + if( ae_fp_eq(sigmas.ptr.p_double[j],(double)(0)) ) + { + sigmas.ptr.p_double[j] = (double)(1); + } + for(i=0; i<=npoints-1; i++) + { + xyi.ptr.pp_double[i][j] = (xyi.ptr.pp_double[i][j]-means.ptr.p_double[j])/sigmas.ptr.p_double[j]; + } + } + + /* + * Internal processing + */ + linreg_lrinternal(&xyi, s, npoints, nvars+1, lm, rep, _state); + + /* + * Un-standartization + */ + offs = ae_round(lm->w.ptr.p_double[3], _state); + for(j=0; j<=nvars-1; j++) + { + + /* + * Constant term is updated (and its covariance too, + * since it gets some variance from J-th component) + */ + lm->w.ptr.p_double[offs+nvars] = lm->w.ptr.p_double[offs+nvars]-lm->w.ptr.p_double[offs+j]*means.ptr.p_double[j]/sigmas.ptr.p_double[j]; + v = means.ptr.p_double[j]/sigmas.ptr.p_double[j]; + ae_v_subd(&rep->c.ptr.pp_double[nvars][0], 1, &rep->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); + ae_v_subd(&rep->c.ptr.pp_double[0][nvars], rep->c.stride, &rep->c.ptr.pp_double[0][j], rep->c.stride, ae_v_len(0,nvars), v); + + /* + * J-th term is updated + */ + lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/sigmas.ptr.p_double[j]; + v = (double)1/sigmas.ptr.p_double[j]; + ae_v_muld(&rep->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); + ae_v_muld(&rep->c.ptr.pp_double[0][j], rep->c.stride, ae_v_len(0,nvars), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Like LRBuildS, but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildzs(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xyi; + ae_vector x; + ae_vector c; + ae_int_t i; + ae_int_t j; + double v; + ae_int_t offs; + double mean; + double variance; + double skewness; + double kurtosis; + + ae_frame_make(_state, &_frame_block); + memset(&xyi, 0, sizeof(xyi)); + memset(&x, 0, sizeof(x)); + memset(&c, 0, sizeof(c)); + _linearmodel_clear(lm); + _lrreport_clear(rep); + ae_matrix_init(&xyi, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + + ae_assert(nvars>=1, "LRBuildZS: NVars<1", _state); + ae_assert(npoints>nvars+1, "LRBuildZS: NPoints is less than NVars+1", _state); + ae_assert(xy->rows>=npoints, "LRBuildZS: rows(XY)cols>=nvars+1, "LRBuildZS: cols(XY)cnt>=npoints, "LRBuildZS: length(S)ptr.p_double[i],(double)(0)), "LRBuildZS: S[I]<=0", _state); + } + + /* + * Copy data, add one more column (constant term) + */ + ae_matrix_set_length(&xyi, npoints-1+1, nvars+1+1, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&xyi.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + xyi.ptr.pp_double[i][nvars] = (double)(0); + xyi.ptr.pp_double[i][nvars+1] = xy->ptr.pp_double[i][nvars]; + } + + /* + * Standartization: unusual scaling + */ + ae_vector_set_length(&x, npoints-1+1, _state); + ae_vector_set_length(&c, nvars-1+1, _state); + for(j=0; j<=nvars-1; j++) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[0][j], xy->stride, ae_v_len(0,npoints-1)); + samplemoments(&x, npoints, &mean, &variance, &skewness, &kurtosis, _state); + if( ae_fp_greater(ae_fabs(mean, _state),ae_sqrt(variance, _state)) ) + { + + /* + * variation is relatively small, it is better to + * bring mean value to 1 + */ + c.ptr.p_double[j] = mean; + } + else + { + + /* + * variation is large, it is better to bring variance to 1 + */ + if( ae_fp_eq(variance,(double)(0)) ) + { + variance = (double)(1); + } + c.ptr.p_double[j] = ae_sqrt(variance, _state); + } + for(i=0; i<=npoints-1; i++) + { + xyi.ptr.pp_double[i][j] = xyi.ptr.pp_double[i][j]/c.ptr.p_double[j]; + } + } + + /* + * Internal processing + */ + linreg_lrinternal(&xyi, s, npoints, nvars+1, lm, rep, _state); + + /* + * Un-standartization + */ + offs = ae_round(lm->w.ptr.p_double[3], _state); + for(j=0; j<=nvars-1; j++) + { + + /* + * J-th term is updated + */ + lm->w.ptr.p_double[offs+j] = lm->w.ptr.p_double[offs+j]/c.ptr.p_double[j]; + v = (double)1/c.ptr.p_double[j]; + ae_v_muld(&rep->c.ptr.pp_double[j][0], 1, ae_v_len(0,nvars), v); + ae_v_muld(&rep->c.ptr.pp_double[0][j], rep->c.stride, ae_v_len(0,nvars), v); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Like LRBuild but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildz(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector s; + ae_int_t i; + double sigma2; + + ae_frame_make(_state, &_frame_block); + memset(&s, 0, sizeof(s)); + _linearmodel_clear(lm); + _lrreport_clear(rep); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + + ae_assert(nvars>=1, "LRBuildZ: NVars<1", _state); + ae_assert(npoints>nvars+1, "LRBuildZ: NPoints is less than NVars+1", _state); + ae_assert(xy->rows>=npoints, "LRBuildZ: rows(XY)cols>=nvars+1, "LRBuildZ: cols(XY)rmserror, _state)*(double)npoints/(double)(npoints-nvars-1); + for(i=0; i<=nvars; i++) + { + ae_v_muld(&rep->c.ptr.pp_double[i][0], 1, ae_v_len(0,nvars), sigma2); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacks coefficients of linear model. + +INPUT PARAMETERS: + LM - linear model in ALGLIB format + +OUTPUT PARAMETERS: + V - coefficients, array[0..NVars] + constant term (intercept) is stored in the V[NVars]. + NVars - number of independent variables (one less than number + of coefficients) + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrunpack(const linearmodel* lm, + /* Real */ ae_vector* v, + ae_int_t* nvars, + ae_state *_state) +{ + ae_int_t offs; + + ae_vector_clear(v); + *nvars = 0; + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); + *nvars = ae_round(lm->w.ptr.p_double[2], _state); + offs = ae_round(lm->w.ptr.p_double[3], _state); + ae_vector_set_length(v, *nvars+1, _state); + ae_v_move(&v->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,*nvars)); +} + + +/************************************************************************* +"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack +reversed). + +INPUT PARAMETERS: + V - coefficients, array[0..NVars] + NVars - number of independent variables + +OUTPUT PAREMETERS: + LM - linear model. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrpack(/* Real */ const ae_vector* v, + ae_int_t nvars, + linearmodel* lm, + ae_state *_state) +{ + ae_int_t offs; + + _linearmodel_clear(lm); + + ae_assert(v->cnt>=nvars+1, "LRPack: length(V)w, 4+nvars+1, _state); + offs = 4; + lm->w.ptr.p_double[0] = (double)(4+nvars+1); + lm->w.ptr.p_double[1] = (double)(linreg_lrvnum); + lm->w.ptr.p_double[2] = (double)(nvars); + lm->w.ptr.p_double[3] = (double)(offs); + ae_v_move(&lm->w.ptr.p_double[offs], 1, &v->ptr.p_double[0], 1, ae_v_len(offs,offs+nvars)); +} + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + LM - linear model + X - input vector, array[0..NVars-1]. + +Result: + value of linear model regression estimate + + -- ALGLIB -- + Copyright 03.09.2008 by Bochkanov Sergey +*************************************************************************/ +double lrprocess(const linearmodel* lm, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + double v; + ae_int_t offs; + ae_int_t nvars; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + offs = ae_round(lm->w.ptr.p_double[3], _state); + v = ae_v_dotproduct(&x->ptr.p_double[0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); + result = v+lm->w.ptr.p_double[offs+nvars]; + return result; +} + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lrrmserror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_int_t offs; + ae_int_t nvars; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + offs = ae_round(lm->w.ptr.p_double[3], _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); + v = v+lm->w.ptr.p_double[offs+nvars]; + result = result+ae_sqr(v-xy->ptr.pp_double[i][nvars], _state); + } + result = ae_sqrt(result/(double)npoints, _state); + return result; +} + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgerror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_int_t offs; + ae_int_t nvars; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + offs = ae_round(lm->w.ptr.p_double[3], _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); + v = v+lm->w.ptr.p_double[offs+nvars]; + result = result+ae_fabs(v-xy->ptr.pp_double[i][nvars], _state); + } + result = result/(double)npoints; + return result; +} + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average relative error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgrelerror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double v; + ae_int_t offs; + ae_int_t nvars; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==linreg_lrvnum, "LINREG: Incorrect LINREG version!", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + offs = ae_round(lm->w.ptr.p_double[3], _state); + result = (double)(0); + k = 0; + for(i=0; i<=npoints-1; i++) + { + if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) + { + v = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); + v = v+lm->w.ptr.p_double[offs+nvars]; + result = result+ae_fabs((v-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); + k = k+1; + } + } + if( k!=0 ) + { + result = result/(double)k; + } + return result; +} + + +/************************************************************************* +Copying of LinearModel strucure + +INPUT PARAMETERS: + LM1 - original + +OUTPUT PARAMETERS: + LM2 - copy + + -- ALGLIB -- + Copyright 15.03.2009 by Bochkanov Sergey +*************************************************************************/ +void lrcopy(const linearmodel* lm1, linearmodel* lm2, ae_state *_state) +{ + ae_int_t k; + + _linearmodel_clear(lm2); + + k = ae_round(lm1->w.ptr.p_double[0], _state); + ae_vector_set_length(&lm2->w, k-1+1, _state); + ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); +} + + +void lrlines(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t n, + double* a, + double* b, + double* vara, + double* varb, + double* covab, + double* corrab, + double* p, + ae_state *_state) +{ + ae_int_t i; + double ss; + double sx; + double sxx; + double sy; + double stt; + double e1; + double e2; + double t; + double chi2; + + *a = 0.0; + *b = 0.0; + *vara = 0.0; + *varb = 0.0; + *covab = 0.0; + *corrab = 0.0; + *p = 0.0; + + if( n<2 ) + { + ae_assert(ae_false, "LINREG: 7129", _state); + return; + } + for(i=0; i<=n-1; i++) + { + if( ae_fp_less_eq(s->ptr.p_double[i],(double)(0)) ) + { + ae_assert(ae_false, "LINREG: 7729", _state); + return; + } + } + + /* + * Calculate S, SX, SY, SXX + */ + ss = (double)(0); + sx = (double)(0); + sy = (double)(0); + sxx = (double)(0); + for(i=0; i<=n-1; i++) + { + t = ae_sqr(s->ptr.p_double[i], _state); + ss = ss+(double)1/t; + sx = sx+xy->ptr.pp_double[i][0]/t; + sy = sy+xy->ptr.pp_double[i][1]/t; + sxx = sxx+ae_sqr(xy->ptr.pp_double[i][0], _state)/t; + } + + /* + * Test for condition number + */ + t = ae_sqrt((double)4*ae_sqr(sx, _state)+ae_sqr(ss-sxx, _state), _state); + e1 = 0.5*(ss+sxx+t); + e2 = 0.5*(ss+sxx-t); + if( ae_fp_less_eq(ae_minreal(e1, e2, _state),(double)1000*ae_machineepsilon*ae_maxreal(e1, e2, _state)) ) + { + ae_assert(ae_false, "LINREG: 4929", _state); + return; + } + + /* + * Calculate A, B + */ + *a = (double)(0); + *b = (double)(0); + stt = (double)(0); + for(i=0; i<=n-1; i++) + { + t = (xy->ptr.pp_double[i][0]-sx/ss)/s->ptr.p_double[i]; + *b = *b+t*xy->ptr.pp_double[i][1]/s->ptr.p_double[i]; + stt = stt+ae_sqr(t, _state); + } + *b = *b/stt; + *a = (sy-sx*(*b))/ss; + + /* + * Calculate goodness-of-fit + */ + if( n>2 ) + { + chi2 = (double)(0); + for(i=0; i<=n-1; i++) + { + chi2 = chi2+ae_sqr((xy->ptr.pp_double[i][1]-(*a)-*b*xy->ptr.pp_double[i][0])/s->ptr.p_double[i], _state); + } + *p = incompletegammac((double)(n-2)/(double)2, chi2/(double)2, _state); + } + else + { + *p = (double)(1); + } + + /* + * Calculate other parameters + */ + *vara = ((double)1+ae_sqr(sx, _state)/(ss*stt))/ss; + *varb = (double)1/stt; + *covab = -sx/(ss*stt); + *corrab = *covab/ae_sqrt(*vara*(*varb), _state); +} + + +void lrline(/* Real */ const ae_matrix* xy, + ae_int_t n, + double* a, + double* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector s; + ae_int_t i; + double vara; + double varb; + double covab; + double corrab; + double p; + + ae_frame_make(_state, &_frame_block); + memset(&s, 0, sizeof(s)); + *a = 0.0; + *b = 0.0; + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + + if( n<2 ) + { + ae_assert(ae_false, "LINREG: 3329", _state); + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&s, n-1+1, _state); + for(i=0; i<=n-1; i++) + { + s.ptr.p_double[i] = (double)(1); + } + lrlines(xy, &s, n, a, b, &vara, &varb, &covab, &corrab, &p, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal linear regression subroutine +*************************************************************************/ +static void linreg_lrinternal(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* ar, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix u; + ae_matrix vt; + ae_matrix vm; + ae_matrix xym; + ae_vector b; + ae_vector sv; + ae_vector t; + ae_vector svi; + ae_vector work; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t ncv; + ae_int_t na; + ae_int_t nacv; + double r; + double p; + double epstol; + lrreport ar2; + ae_int_t offs; + linearmodel tlm; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + memset(&vm, 0, sizeof(vm)); + memset(&xym, 0, sizeof(xym)); + memset(&b, 0, sizeof(b)); + memset(&sv, 0, sizeof(sv)); + memset(&t, 0, sizeof(t)); + memset(&svi, 0, sizeof(svi)); + memset(&work, 0, sizeof(work)); + memset(&ar2, 0, sizeof(ar2)); + memset(&tlm, 0, sizeof(tlm)); + _linearmodel_clear(lm); + _lrreport_clear(ar); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xym, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&svi, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + _lrreport_init(&ar2, _state, ae_true); + _linearmodel_init(&tlm, _state, ae_true); + + epstol = (double)(1000); + + /* + * Check for errors in data + */ + ae_assert(!(npointsptr.p_double[i],(double)(0)), "LINREG: integrity check 3057 failed", _state); + } + + /* + * Create design matrix + */ + ae_matrix_set_length(&a, npoints-1+1, nvars-1+1, _state); + ae_vector_set_length(&b, npoints-1+1, _state); + for(i=0; i<=npoints-1; i++) + { + r = (double)1/s->ptr.p_double[i]; + ae_v_moved(&a.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); + b.ptr.p_double[i] = xy->ptr.pp_double[i][nvars]/s->ptr.p_double[i]; + } + + /* + * Allocate W: + * W[0] array size + * W[1] version number, 0 + * W[2] NVars (minus 1, to be compatible with external representation) + * W[3] coefficients offset + */ + ae_vector_set_length(&lm->w, 4+nvars-1+1, _state); + offs = 4; + lm->w.ptr.p_double[0] = (double)(4+nvars); + lm->w.ptr.p_double[1] = (double)(linreg_lrvnum); + lm->w.ptr.p_double[2] = (double)(nvars-1); + lm->w.ptr.p_double[3] = (double)(offs); + + /* + * Solve problem using SVD: + * + * 0. check for degeneracy (different types) + * 1. A = U*diag(sv)*V' + * 2. T = b'*U + * 3. w = SUM((T[i]/sv[i])*V[..,i]) + * 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M) + * + * see $15.4 of "Numerical Recipes in C" for more information + */ + ae_vector_set_length(&t, nvars-1+1, _state); + ae_vector_set_length(&svi, nvars-1+1, _state); + ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); + ae_matrix_set_length(&vm, nvars-1+1, nvars-1+1, _state); + if( !rmatrixsvd(&a, npoints, nvars, 1, 1, 2, &sv, &u, &vt, _state) ) + { + ae_assert(ae_false, "LINREG: SVD solver failed", _state); + } + if( ae_fp_less_eq(sv.ptr.p_double[0],(double)(0)) ) + { + + /* + * Degenerate case: zero design matrix. + */ + for(i=offs; i<=offs+nvars-1; i++) + { + lm->w.ptr.p_double[i] = (double)(0); + } + ar->rmserror = lrrmserror(lm, xy, npoints, _state); + ar->avgerror = lravgerror(lm, xy, npoints, _state); + ar->avgrelerror = lravgrelerror(lm, xy, npoints, _state); + ar->cvrmserror = ar->rmserror; + ar->cvavgerror = ar->avgerror; + ar->cvavgrelerror = ar->avgrelerror; + ar->ncvdefects = 0; + ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); + for(i=0; i<=nvars-1; i++) + { + ar->cvdefects.ptr.p_int[i] = -1; + } + ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + ar->c.ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + if( ae_fp_less_eq(sv.ptr.p_double[nvars-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) + { + + /* + * Degenerate case, non-zero design matrix. + * + * We can leave it and solve task in SVD least squares fashion. + * Solution and covariance matrix will be obtained correctly, + * but CV error estimates - will not. It is better to reduce + * it to non-degenerate task and to obtain correct CV estimates. + */ + for(k=nvars; k>=1; k--) + { + if( ae_fp_greater(sv.ptr.p_double[k-1],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) + { + + /* + * Reduce + */ + ae_matrix_set_length(&xym, npoints-1+1, k+1, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=k-1; j++) + { + r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); + xym.ptr.pp_double[i][j] = r; + } + xym.ptr.pp_double[i][k] = xy->ptr.pp_double[i][nvars]; + } + + /* + * Solve + */ + linreg_lrinternal(&xym, s, npoints, k, &tlm, &ar2, _state); + + /* + * Convert back to un-reduced format + */ + for(j=0; j<=nvars-1; j++) + { + lm->w.ptr.p_double[offs+j] = (double)(0); + } + for(j=0; j<=k-1; j++) + { + r = tlm.w.ptr.p_double[offs+j]; + ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[j][0], 1, ae_v_len(offs,offs+nvars-1), r); + } + ar->rmserror = ar2.rmserror; + ar->avgerror = ar2.avgerror; + ar->avgrelerror = ar2.avgrelerror; + ar->cvrmserror = ar2.cvrmserror; + ar->cvavgerror = ar2.cvavgerror; + ar->cvavgrelerror = ar2.cvavgrelerror; + ar->ncvdefects = ar2.ncvdefects; + ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); + for(j=0; j<=ar->ncvdefects-1; j++) + { + ar->cvdefects.ptr.p_int[j] = ar2.cvdefects.ptr.p_int[j]; + } + for(j=ar->ncvdefects; j<=nvars-1; j++) + { + ar->cvdefects.ptr.p_int[j] = -1; + } + ae_matrix_set_length(&ar->c, nvars-1+1, nvars-1+1, _state); + ae_vector_set_length(&work, nvars+1, _state); + matrixmatrixmultiply(&ar2.c, 0, k-1, 0, k-1, ae_false, &vt, 0, k-1, 0, nvars-1, ae_false, 1.0, &vm, 0, k-1, 0, nvars-1, 0.0, &work, _state); + matrixmatrixmultiply(&vt, 0, k-1, 0, nvars-1, ae_true, &vm, 0, k-1, 0, nvars-1, ae_false, 1.0, &ar->c, 0, nvars-1, 0, nvars-1, 0.0, &work, _state); + ae_frame_leave(_state); + return; + } + } + ae_assert(ae_false, "LINREG: integrity check 7801 failed", _state); + } + for(i=0; i<=nvars-1; i++) + { + if( ae_fp_greater(sv.ptr.p_double[i],epstol*ae_machineepsilon*sv.ptr.p_double[0]) ) + { + svi.ptr.p_double[i] = (double)1/sv.ptr.p_double[i]; + } + else + { + svi.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=nvars-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=npoints-1; i++) + { + r = b.ptr.p_double[i]; + ae_v_addd(&t.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), r); + } + for(i=0; i<=nvars-1; i++) + { + lm->w.ptr.p_double[offs+i] = (double)(0); + } + for(i=0; i<=nvars-1; i++) + { + r = t.ptr.p_double[i]*svi.ptr.p_double[i]; + ae_v_addd(&lm->w.ptr.p_double[offs], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(offs,offs+nvars-1), r); + } + for(j=0; j<=nvars-1; j++) + { + r = svi.ptr.p_double[j]; + ae_v_moved(&vm.ptr.pp_double[0][j], vm.stride, &vt.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1), r); + } + for(i=0; i<=nvars-1; i++) + { + for(j=i; j<=nvars-1; j++) + { + r = ae_v_dotproduct(&vm.ptr.pp_double[i][0], 1, &vm.ptr.pp_double[j][0], 1, ae_v_len(0,nvars-1)); + ar->c.ptr.pp_double[i][j] = r; + ar->c.ptr.pp_double[j][i] = r; + } + } + + /* + * Leave-1-out cross-validation error. + * + * NOTATIONS: + * A design matrix + * A*x = b original linear least squares task + * U*S*V' SVD of A + * ai i-th row of the A + * bi i-th element of the b + * xf solution of the original LLS task + * + * Cross-validation error of i-th element from a sample is + * calculated using following formula: + * + * ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) + * + * This formula can be derived from normal equations of the + * original task + * + * (A'*A)x = A'*b (2) + * + * by applying modification (zeroing out i-th row of A) to (2): + * + * (A-ai)'*(A-ai) = (A-ai)'*b + * + * and using Sherman-Morrison formula for updating matrix inverse + * + * NOTE 1: b is not zeroed out since it is much simpler and + * does not influence final result. + * + * NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. + * Formula (1) can't be applied for such cases and they are skipped + * from CV calculation (which distorts resulting CV estimate). + * But from the properties of U we can conclude that there can + * be no more than NVars such vectors. Usually + * NVars << NPoints, so in a normal case it only slightly + * influences result. + */ + ncv = 0; + na = 0; + nacv = 0; + ar->rmserror = (double)(0); + ar->avgerror = (double)(0); + ar->avgrelerror = (double)(0); + ar->cvrmserror = (double)(0); + ar->cvavgerror = (double)(0); + ar->cvavgrelerror = (double)(0); + ar->ncvdefects = 0; + ae_vector_set_length(&ar->cvdefects, nvars-1+1, _state); + for(i=0; i<=nvars-1; i++) + { + ar->cvdefects.ptr.p_int[i] = -1; + } + for(i=0; i<=npoints-1; i++) + { + + /* + * Error on a training set + */ + r = ae_v_dotproduct(&xy->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs], 1, ae_v_len(0,nvars-1)); + ar->rmserror = ar->rmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); + ar->avgerror = ar->avgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); + if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) + { + ar->avgrelerror = ar->avgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); + na = na+1; + } + + /* + * Error using fast leave-one-out cross-validation + */ + p = ae_v_dotproduct(&u.ptr.pp_double[i][0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + if( ae_fp_greater(p,(double)1-epstol*ae_machineepsilon) ) + { + ar->cvdefects.ptr.p_int[ar->ncvdefects] = i; + ar->ncvdefects = ar->ncvdefects+1; + continue; + } + r = s->ptr.p_double[i]*(r/s->ptr.p_double[i]-b.ptr.p_double[i]*p)/((double)1-p); + ar->cvrmserror = ar->cvrmserror+ae_sqr(r-xy->ptr.pp_double[i][nvars], _state); + ar->cvavgerror = ar->cvavgerror+ae_fabs(r-xy->ptr.pp_double[i][nvars], _state); + if( ae_fp_neq(xy->ptr.pp_double[i][nvars],(double)(0)) ) + { + ar->cvavgrelerror = ar->cvavgrelerror+ae_fabs((r-xy->ptr.pp_double[i][nvars])/xy->ptr.pp_double[i][nvars], _state); + nacv = nacv+1; + } + ncv = ncv+1; + } + if( ncv==0 ) + { + + /* + * Something strange: ALL ui are degenerate. + * Unexpected... + */ + ae_assert(ae_false, "LINREG: integrity check 0301 failed", _state); + } + ar->rmserror = ae_sqrt(ar->rmserror/(double)npoints, _state); + ar->avgerror = ar->avgerror/(double)npoints; + if( na!=0 ) + { + ar->avgrelerror = ar->avgrelerror/(double)na; + } + ar->cvrmserror = ae_sqrt(ar->cvrmserror/(double)ncv, _state); + ar->cvavgerror = ar->cvavgerror/(double)ncv; + if( nacv!=0 ) + { + ar->cvavgrelerror = ar->cvavgrelerror/(double)nacv; + } + ae_frame_leave(_state); +} + + +void _linearmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + linearmodel *p = (linearmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic); +} + + +void _linearmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + linearmodel *dst = (linearmodel*)_dst; + const linearmodel *src = (const linearmodel*)_src; + ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic); +} + + +void _linearmodel_clear(void* _p) +{ + linearmodel *p = (linearmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->w); +} + + +void _linearmodel_destroy(void* _p) +{ + linearmodel *p = (linearmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->w); +} + + +void _lrreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lrreport *p = (lrreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cvdefects, 0, DT_INT, _state, make_automatic); +} + + +void _lrreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lrreport *dst = (lrreport*)_dst; + const lrreport *src = (const lrreport*)_src; + ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic); + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->cvrmserror = src->cvrmserror; + dst->cvavgerror = src->cvavgerror; + dst->cvavgrelerror = src->cvavgrelerror; + dst->ncvdefects = src->ncvdefects; + ae_vector_init_copy(&dst->cvdefects, &src->cvdefects, _state, make_automatic); +} + + +void _lrreport_clear(void* _p) +{ + lrreport *p = (lrreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->c); + ae_vector_clear(&p->cvdefects); +} + + +void _lrreport_destroy(void* _p) +{ + lrreport *p = (lrreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->c); + ae_vector_destroy(&p->cvdefects); +} + + +#endif +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Filters: simple moving averages (unsymmetric). + +This filter replaces array by results of SMA(K) filter. SMA(K) is defined +as filter which averages at most K previous points (previous - not points +AROUND central point) - or less, in case of the first K-1 points. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with SMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filtersma(/* Real */ ae_vector* x, + ae_int_t n, + ae_int_t k, + ae_state *_state) +{ + ae_int_t i; + double runningsum; + double termsinsum; + ae_int_t zeroprefix; + double v; + + + ae_assert(n>=0, "FilterSMA: N<0", _state); + ae_assert(x->cnt>=n, "FilterSMA: Length(X)=1, "FilterSMA: K<1", _state); + + /* + * Quick exit, if necessary + */ + if( n<=1||k==1 ) + { + return; + } + + /* + * Prepare variables (see below for explanation) + */ + runningsum = 0.0; + termsinsum = (double)(0); + for(i=ae_maxint(n-k, 0, _state); i<=n-1; i++) + { + runningsum = runningsum+x->ptr.p_double[i]; + termsinsum = termsinsum+(double)1; + } + i = ae_maxint(n-k, 0, _state); + zeroprefix = 0; + while(i<=n-1&&ae_fp_eq(x->ptr.p_double[i],(double)(0))) + { + zeroprefix = zeroprefix+1; + i = i+1; + } + + /* + * General case: we assume that N>1 and K>1 + * + * Make one pass through all elements. At the beginning of + * the iteration we have: + * * I element being processed + * * RunningSum current value of the running sum + * (including I-th element) + * * TermsInSum number of terms in sum, 0<=TermsInSum<=K + * * ZeroPrefix length of the sequence of zero elements + * which starts at X[I-K+1] and continues towards X[I]. + * Equal to zero in case X[I-K+1] is non-zero. + * This value is used to make RunningSum exactly zero + * when it follows from the problem properties. + */ + for(i=n-1; i>=0; i--) + { + + /* + * Store new value of X[i], save old value in V + */ + v = x->ptr.p_double[i]; + x->ptr.p_double[i] = runningsum/termsinsum; + + /* + * Update RunningSum and TermsInSum + */ + if( i-k>=0 ) + { + runningsum = runningsum-v+x->ptr.p_double[i-k]; + } + else + { + runningsum = runningsum-v; + termsinsum = termsinsum-(double)1; + } + + /* + * Update ZeroPrefix. + * In case we have ZeroPrefix=TermsInSum, + * RunningSum is reset to zero. + */ + if( i-k>=0 ) + { + if( ae_fp_neq(x->ptr.p_double[i-k],(double)(0)) ) + { + zeroprefix = 0; + } + else + { + zeroprefix = ae_minint(zeroprefix+1, k, _state); + } + } + else + { + zeroprefix = ae_minint(zeroprefix, i+1, _state); + } + if( ae_fp_eq((double)(zeroprefix),termsinsum) ) + { + runningsum = (double)(0); + } + } +} + + +/************************************************************************* +Filters: exponential moving averages. + +This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is +defined as filter which replaces X[] by S[]: + S[0] = X[0] + S[t] = alpha*X[t] + (1-alpha)*S[t-1] + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + alpha - 0=0, "FilterEMA: N<0", _state); + ae_assert(x->cnt>=n, "FilterEMA: Length(X)1", _state); + + /* + * Quick exit, if necessary + */ + if( n<=1||ae_fp_eq(alpha,(double)(1)) ) + { + return; + } + + /* + * Process + */ + for(i=1; i<=n-1; i++) + { + x->ptr.p_double[i] = alpha*x->ptr.p_double[i]+((double)1-alpha)*x->ptr.p_double[i-1]; + } +} + + +/************************************************************************* +Filters: linear regression moving averages. + +This filter replaces array by results of LRMA(K) filter. + +LRMA(K) is defined as filter which, for each data point, builds linear +regression model using K prevous points (point itself is included in +these K points) and calculates value of this linear model at the point in +question. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with LRMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filterlrma(/* Real */ ae_vector* x, + ae_int_t n, + ae_int_t k, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t m; + ae_matrix xy; + ae_vector s; + double a; + double b; + double vara; + double varb; + double covab; + double corrab; + double p; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&s, 0, sizeof(s)); + ae_matrix_init(&xy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "FilterLRMA: N<0", _state); + ae_assert(x->cnt>=n, "FilterLRMA: Length(X)=1, "FilterLRMA: K<1", _state); + + /* + * Quick exit, if necessary: + * * either N is equal to 1 (nothing to average) + * * or K is 1 (only point itself is used) or 2 (model is too simple, + * we will always get identity transformation) + */ + if( n<=1||k<=2 ) + { + ae_frame_leave(_state); + return; + } + + /* + * General case: K>2, N>1. + * We do not process points with I<2 because first two points (I=0 and I=1) will be + * left unmodified by LRMA filter in any case. + */ + ae_matrix_set_length(&xy, k, 2, _state); + ae_vector_set_length(&s, k, _state); + for(i=0; i<=k-1; i++) + { + xy.ptr.pp_double[i][0] = (double)(i); + s.ptr.p_double[i] = 1.0; + } + for(i=n-1; i>=2; i--) + { + m = ae_minint(i+1, k, _state); + ae_v_move(&xy.ptr.pp_double[0][1], xy.stride, &x->ptr.p_double[i-m+1], 1, ae_v_len(0,m-1)); + lrlines(&xy, &s, m, &a, &b, &vara, &varb, &covab, &corrab, &p, _state); + x->ptr.p_double[i] = a+b*(double)(m-1); + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates SSA model object. Right after creation model is in +"dummy" mode - you can add data, but analyzing/prediction will return +just zeros (it assumes that basis is empty). + +HOW TO USE SSA MODEL: + +1. create model with ssacreate() +2. add data with one/many ssaaddsequence() calls +3. choose SSA algorithm with one of ssasetalgo...() functions: + * ssasetalgotopkdirect() for direct one-run analysis + * ssasetalgotopkrealtime() for algorithm optimized for many subsequent + runs with warm-start capabilities + * ssasetalgoprecomputed() for user-supplied basis +4. set window width with ssasetwindow() +5. perform one of the analysis-related activities: + a) call ssagetbasis() to get basis + b) call ssaanalyzelast() ssaanalyzesequence() or ssaanalyzelastwindow() + to perform analysis (trend/noise separation) + c) call one of the forecasting functions (ssaforecastlast() or + ssaforecastsequence()) to perform prediction; alternatively, you can + extract linear recurrence coefficients with ssagetlrr(). + SSA analysis will be performed during first call to analysis-related + function. SSA model is smart enough to track all changes in the dataset + and model settings, to cache previously computed basis and to + re-evaluate basis only when necessary. + +Additionally, if your setting involves constant stream of incoming data, +you can perform quick update already calculated model with one of the +incremental append-and-update functions: ssaappendpointandupdate() or +ssaappendsequenceandupdate(). + +NOTE: steps (2), (3), (4) can be performed in arbitrary order. + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - structure which stores model state + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacreate(ssamodel* s, ae_state *_state) +{ + + _ssamodel_clear(s); + + + /* + * Model data, algorithms and settings + */ + s->nsequences = 0; + ae_vector_set_length(&s->sequenceidx, 1, _state); + s->sequenceidx.ptr.p_int[0] = 0; + s->algotype = 0; + s->windowwidth = 1; + s->rtpowerup = 1; + s->arebasisandsolvervalid = ae_false; + s->rngseed = 1; + s->defaultsubspaceits = 10; + s->memorylimit = 50000000; + + /* + * Debug counters + */ + s->dbgcntevd = 0; +} + + +/************************************************************************* +This function sets window width for SSA model. You should call it before +analysis phase. Default window width is 1 (not for real use). + +Special notes: +* this function call can be performed at any moment before first call to + analysis-related functions +* changing window width invalidates internally stored basis; if you change + window width AFTER you call analysis-related function, next analysis + phase will require re-calculation of the basis according to current + algorithm. +* calling this function with exactly same window width as current one has + no effect +* if you specify window width larger than any data sequence stored in the + model, analysis will return zero basis. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + WindowWidth - >=1, new window width + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetwindow(ssamodel* s, ae_int_t windowwidth, ae_state *_state) +{ + + + ae_assert(windowwidth>=1, "SSASetWindow: WindowWidth<1", _state); + if( windowwidth==s->windowwidth ) + { + return; + } + s->windowwidth = windowwidth; + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function sets seed which is used to initialize internal RNG when +we make pseudorandom decisions on model updates. + +By default, deterministic seed is used - which results in same sequence of +pseudorandom decisions every time you run SSA model. If you specify non- +deterministic seed value, then SSA model may return slightly different +results after each run. + +This function can be useful when you have several SSA models updated with +sseappendpointandupdate() called with 0rngseed = seed; +} + + +/************************************************************************* +This function sets length of power-up cycle for real-time algorithm. + +By default, this algorithm performs costly O(N*WindowWidth^2) init phase +followed by full run of truncated EVD. However, if you are ready to +live with a bit lower-quality basis during first few iterations, you can +split this O(N*WindowWidth^2) initialization between several subsequent +append-and-update rounds. It results in better latency of the algorithm. + +This function invalidates basis/solver, next analysis call will result in +full recalculation of everything. + +INPUT PARAMETERS: + S - SSA model + PWLen - length of the power-up stage: + * 0 means that no power-up is requested + * 1 is the same as 0 + * >1 means that delayed power-up is performed + + -- ALGLIB -- + Copyright 03.11.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetpoweruplength(ssamodel* s, ae_int_t pwlen, ae_state *_state) +{ + + + ae_assert(pwlen>=0, "SSASetPowerUpLength: PWLen<0", _state); + s->rtpowerup = ae_maxint(pwlen, 1, _state); + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function sets memory limit of SSA analysis. + +Straightforward SSA with sequence length T and window width W needs O(T*W) +memory. It is possible to reduce memory consumption by splitting task into +smaller chunks. + +Thus function allows you to specify approximate memory limit (measured in +double precision numbers used for buffers). Actual memory consumption will +be comparable to the number specified by you. + +Default memory limit is 50.000.000 (400Mbytes) in current version. + +INPUT PARAMETERS: + S - SSA model + MemLimit- memory limit, >=0. Zero value means no limit. + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetmemorylimit(ssamodel* s, ae_int_t memlimit, ae_state *_state) +{ + + + if( memlimit<0 ) + { + memlimit = 0; + } + s->memorylimit = memlimit; +} + + +/************************************************************************* +This function adds data sequence to SSA model. Only single-dimensional +sequences are supported. + +What is a sequences? Following definitions/requirements apply: +* a sequence is an array of values measured in subsequent, equally + separated time moments (ticks). +* you may have many sequences in your dataset; say, one sequence may + correspond to one trading session. +* sequence length should be larger than current window length (shorter + sequences will be ignored during analysis). +* analysis is performed within a sequence; different sequences are NOT + stacked together to produce one large contiguous stream of data. +* analysis is performed for all sequences at once, i.e. same set of basis + vectors is computed for all sequences + +INCREMENTAL ANALYSIS + +This function is non intended for incremental updates of previously found +SSA basis. Calling it invalidates all previous analysis results (basis is +reset and will be recalculated from zero during next analysis). + +If you want to perform incremental/real-time SSA, consider using +following functions: +* ssaappendpointandupdate() for appending one point +* ssaappendsequenceandupdate() for appending new sequence + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - array[N], data, can be larger (additional values + are ignored) + N - data length, can be automatically determined from + the array length. N>=0. + +OUTPUT PARAMETERS: + S - SSA model, updated + +NOTE: you can clear dataset with ssacleardata() + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaaddsequence(ssamodel* s, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t offs; + + + ae_assert(n>=0, "SSAAddSequence: N<0", _state); + ae_assert(x->cnt>=n, "SSAAddSequence: X is too short", _state); + ae_assert(isfinitevector(x, n, _state), "SSAAddSequence: X contains infinities NANs", _state); + + /* + * Invalidate model + */ + s->arebasisandsolvervalid = ae_false; + + /* + * Add sequence + */ + ivectorgrowto(&s->sequenceidx, s->nsequences+2, _state); + s->sequenceidx.ptr.p_int[s->nsequences+1] = s->sequenceidx.ptr.p_int[s->nsequences]+n; + rvectorgrowto(&s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences+1], _state); + offs = s->sequenceidx.ptr.p_int[s->nsequences]; + for(i=0; i<=n-1; i++) + { + s->sequencedata.ptr.p_double[offs+i] = x->ptr.p_double[i]; + } + inc(&s->nsequences, _state); +} + + +/************************************************************************* +This function appends single point to last data sequence stored in the SSA +model and tries to update model in the incremental manner (if possible +with current algorithm). + +If you want to add more than one point at once: +* if you want to add M points to the same sequence, perform M-1 calls with + UpdateIts parameter set to 0.0, and last call with non-zero UpdateIts. +* if you want to add new sequence, use ssaappendsequenceandupdate() + +Running time of this function does NOT depend on dataset size, only on +window width and number of singular vectors. Depending on algorithm being +used, incremental update has complexity: +* for top-K real time - O(UpdateIts*K*Width^2), with fractional UpdateIts +* for top-K direct - O(Width^3) for any non-zero UpdateIts +* for precomputed basis - O(1), no update is performed + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - new point + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0nsequences>0, "SSAAppendPointAndUpdate: dataset is empty, no sequence to modify", _state); + + /* + * Append point to dataset + */ + rvectorgrowto(&s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]+1, _state); + s->sequencedata.ptr.p_double[s->sequenceidx.ptr.p_int[s->nsequences]] = x; + s->sequenceidx.ptr.p_int[s->nsequences] = s->sequenceidx.ptr.p_int[s->nsequences]+1; + + /* + * Do we have something to analyze? If no, invalidate basis + * (just to be sure) and exit. + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + s->arebasisandsolvervalid = ae_false; + return; + } + + /* + * Well, we have data to analyze and algorithm set, but basis is + * invalid. Let's calculate it from scratch and exit. + */ + if( !s->arebasisandsolvervalid ) + { + ssa_updatebasis(s, 0, 0.0, _state); + return; + } + + /* + * Update already computed basis + */ + ssa_updatebasis(s, 1, updateits, _state); +} + + +/************************************************************************* +This function appends new sequence to dataset stored in the SSA model and +tries to update model in the incremental manner (if possible with current +algorithm). + +Notes: +* if you want to add M sequences at once, perform M-1 calls with UpdateIts + parameter set to 0.0, and last call with non-zero UpdateIts. +* if you want to add just one point, use ssaappendpointandupdate() + +Running time of this function does NOT depend on dataset size, only on +sequence length, window width and number of singular vectors. Depending on +algorithm being used, incremental update has complexity: +* for top-K real time - O(UpdateIts*K*Width^2+(NTicks-Width)*Width^2) +* for top-K direct - O(Width^3+(NTicks-Width)*Width^2) +* for precomputed basis - O(1), no update is performed + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - new sequence, array[NTicks] or larget + NTicks - >=1, number of ticks in the sequence + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=0, "SSAAppendSequenceAndUpdate: NTicks<0", _state); + ae_assert(x->cnt>=nticks, "SSAAppendSequenceAndUpdate: X is too short", _state); + ae_assert(isfinitevector(x, nticks, _state), "SSAAppendSequenceAndUpdate: X contains infinities NANs", _state); + + /* + * Add sequence + */ + ivectorgrowto(&s->sequenceidx, s->nsequences+2, _state); + s->sequenceidx.ptr.p_int[s->nsequences+1] = s->sequenceidx.ptr.p_int[s->nsequences]+nticks; + rvectorgrowto(&s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences+1], _state); + offs = s->sequenceidx.ptr.p_int[s->nsequences]; + for(i=0; i<=nticks-1; i++) + { + s->sequencedata.ptr.p_double[offs+i] = x->ptr.p_double[i]; + } + inc(&s->nsequences, _state); + + /* + * Do we have something to analyze? If no, invalidate basis + * (just to be sure) and exit. + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + s->arebasisandsolvervalid = ae_false; + return; + } + + /* + * Well, we have data to analyze and algorithm set, but basis is + * invalid. Let's calculate it from scratch and exit. + */ + if( !s->arebasisandsolvervalid ) + { + ssa_updatebasis(s, 0, 0.0, _state); + return; + } + + /* + * Update already computed basis + */ + if( nticks>=s->windowwidth ) + { + ssa_updatebasis(s, nticks-s->windowwidth+1, updateits, _state); + } +} + + +/************************************************************************* +This function sets SSA algorithm to "precomputed vectors" algorithm. + +This algorithm uses precomputed set of orthonormal (orthogonal AND +normalized) basis vectors supplied by user. Thus, basis calculation phase +is not performed - we already have our basis - and only analysis/ +forecasting phase requires actual calculations. + +This algorithm may handle "append" requests which add just one/few ticks +to the end of the last sequence in O(1) time. + +NOTE: this algorithm accepts both basis and window width, because these + two parameters are naturally aligned. Calling this function sets + window width; if you call ssasetwindow() with other window width, + then during analysis stage algorithm will detect conflict and reset + to zero basis. + +INPUT PARAMETERS: + S - SSA model + A - array[WindowWidth,NBasis], orthonormalized basis; + this function does NOT control orthogonality and + does NOT perform any kind of renormalization. It + is your responsibility to provide it with correct + basis. + WindowWidth - window width, >=1 + NBasis - number of basis vectors, 1<=NBasis<=WindowWidth + +OUTPUT PARAMETERS: + S - updated model + +NOTE: calling this function invalidates basis in all cases. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgoprecomputed(ssamodel* s, + /* Real */ const ae_matrix* a, + ae_int_t windowwidth, + ae_int_t nbasis, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(windowwidth>=1, "SSASetAlgoPrecomputed: WindowWidth<1", _state); + ae_assert(nbasis>=1, "SSASetAlgoPrecomputed: NBasis<1", _state); + ae_assert(nbasis<=windowwidth, "SSASetAlgoPrecomputed: NBasis>WindowWidth", _state); + ae_assert(a->rows>=windowwidth, "SSASetAlgoPrecomputed: Rows(A)cols>=nbasis, "SSASetAlgoPrecomputed: Rows(A)algotype = 1; + s->precomputedwidth = windowwidth; + s->precomputednbasis = nbasis; + s->windowwidth = windowwidth; + rmatrixsetlengthatleast(&s->precomputedbasis, windowwidth, nbasis, _state); + for(i=0; i<=windowwidth-1; i++) + { + for(j=0; j<=nbasis-1; j++) + { + s->precomputedbasis.ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; + } + } + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function sets SSA algorithm to "direct top-K" algorithm. + +"Direct top-K" algorithm performs full SVD of the N*WINDOW trajectory +matrix (hence its name - direct solver is used), then extracts top K +components. Overall running time is O(N*WINDOW^2), where N is a number of +ticks in the dataset, WINDOW is window width. + +This algorithm may handle "append" requests which add just one/few ticks +to the end of the last sequence in O(WINDOW^3) time, which is ~N/WINDOW +times faster than re-computing everything from scratch. + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkdirect(ssamodel* s, ae_int_t topk, ae_state *_state) +{ + + + ae_assert(topk>=1, "SSASetAlgoTopKDirect: TopK<1", _state); + + /* + * Ignore calls which change nothing + */ + if( s->algotype==2&&s->topk==topk ) + { + return; + } + + /* + * Update settings, invalidate model + */ + s->algotype = 2; + s->topk = topk; + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function sets SSA algorithm to "top-K real time algorithm". This algo +extracts K components with largest singular values. + +It is real-time version of top-K algorithm which is optimized for +incremental processing and fast start-up. Internally it uses subspace +eigensolver for truncated SVD. It results in ability to perform quick +updates of the basis when only a few points/sequences is added to dataset. + +Performance profile of the algorithm is given below: +* O(K*WindowWidth^2) running time for incremental update of the dataset + with one of the "append-and-update" functions (ssaappendpointandupdate() + or ssaappendsequenceandupdate()). +* O(N*WindowWidth^2) running time for initial basis evaluation (N=size of + dataset) +* ability to split costly initialization across several incremental + updates of the basis (so called "Power-Up" functionality, activated by + ssasetpoweruplength() function) + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + +NOTE: this algorithm is optimized for large-scale tasks with large + datasets. On toy problems with just 5-10 points it can return basis + which is slightly different from that returned by direct algorithm + (ssasetalgotopkdirect() function). However, the difference becomes + negligible as dataset grows. + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkrealtime(ssamodel* s, ae_int_t topk, ae_state *_state) +{ + + + ae_assert(topk>=1, "SSASetAlgoTopKRealTime: TopK<1", _state); + + /* + * Ignore calls which change nothing + */ + if( s->algotype==3&&s->topk==topk ) + { + return; + } + + /* + * Update settings, invalidate model + */ + s->algotype = 3; + s->topk = topk; + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function clears all data stored in the model and invalidates all +basis components found so far. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacleardata(ssamodel* s, ae_state *_state) +{ + + + s->nsequences = 0; + s->arebasisandsolvervalid = ae_false; +} + + +/************************************************************************* +This function executes SSA on internally stored dataset and returns basis +found by current method. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth,NBasis], basis; vectors are + stored in matrix columns, by descreasing variance + SV - array[NBasis]: + * zeros - for model initialized with SSASetAlgoPrecomputed() + * singular values - for other algorithms + WindowWidth - current window + NBasis - basis size + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns basis with +just one zero vector. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetbasis(ssamodel* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* sv, + ae_int_t* windowwidth, + ae_int_t* nbasis, + ae_state *_state) +{ + ae_int_t i; + + ae_matrix_clear(a); + ae_vector_clear(sv); + *windowwidth = 0; + *nbasis = 0; + + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + *windowwidth = s->windowwidth; + *nbasis = 1; + ae_matrix_set_length(a, *windowwidth, 1, _state); + for(i=0; i<=*windowwidth-1; i++) + { + a->ptr.pp_double[i][0] = 0.0; + } + ae_vector_set_length(sv, 1, _state); + sv->ptr.p_double[0] = 0.0; + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + + /* + * Output + */ + ae_assert(s->nbasis>0, "SSAGetBasis: integrity check failed", _state); + ae_assert(s->windowwidth>0, "SSAGetBasis: integrity check failed", _state); + *nbasis = s->nbasis; + *windowwidth = s->windowwidth; + ae_matrix_set_length(a, *windowwidth, *nbasis, _state); + rmatrixcopy(*windowwidth, *nbasis, &s->basis, 0, 0, a, 0, 0, _state); + ae_vector_set_length(sv, *nbasis, _state); + for(i=0; i<=*nbasis-1; i++) + { + sv->ptr.p_double[i] = s->sv.ptr.p_double[i]; + } +} + + +/************************************************************************* +This function returns linear recurrence relation (LRR) coefficients found +by current SSA algorithm. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth-1]. Coefficients of the + linear recurrence of the form: + X[W-1] = X[W-2]*A[W-2] + X[W-3]*A[W-3] + ... + X[0]*A[0]. + Empty array for WindowWidth=1. + WindowWidth - current window width + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns zeros. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetlrr(ssamodel* s, + /* Real */ ae_vector* a, + ae_int_t* windowwidth, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(a); + *windowwidth = 0; + + ae_assert(s->windowwidth>0, "SSAGetLRR: integrity check failed", _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + *windowwidth = s->windowwidth; + ae_vector_set_length(a, *windowwidth-1, _state); + for(i=0; i<=*windowwidth-2; i++) + { + a->ptr.p_double[i] = 0.0; + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + + /* + * Output + */ + *windowwidth = s->windowwidth; + ae_vector_set_length(a, *windowwidth-1, _state); + for(i=0; i<=*windowwidth-2; i++) + { + a->ptr.p_double[i] = s->forecasta.ptr.p_double[i]; + } +} + + +/************************************************************************* +This function executes SSA on internally stored dataset and returns +analysis for the last window of the last sequence. Such analysis is +an lightweight alternative for full scale reconstruction (see below). + +Typical use case for this function is real-time setting, when you are +interested in quick-and-dirty (very quick and very dirty) processing of +just a few last ticks of the trend. + +IMPORTANT: full scale SSA involves analysis of the ENTIRE dataset, + with reconstruction being done for all positions of sliding + window with subsequent hankelization (diagonal averaging) of + the resulting matrix. + + Such analysis requires O((DataLen-Window)*Window*NBasis) FLOPs + and can be quite costly. However, it has nice noise-canceling + effects due to averaging. + + This function performs REDUCED analysis of the last window. It + is much faster - just O(Window*NBasis), but its results are + DIFFERENT from that of ssaanalyzelast(). In particular, first + few points of the trend are much more prone to noise. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + Trend - array[WindowSize], reconstructed trend line + Noise - array[WindowSize], the rest of the signal; + it holds that ActualData = Trend+Noise. + NTicks - current WindowSize + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, WindowWidth ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelastwindow(ssamodel* s, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_int_t* nticks, + ae_state *_state) +{ + ae_int_t i; + ae_int_t offs; + ae_int_t cnt; + + ae_vector_clear(trend); + ae_vector_clear(noise); + *nticks = 0; + + + /* + * Init + */ + *nticks = s->windowwidth; + ae_vector_set_length(trend, s->windowwidth, _state); + ae_vector_set_length(noise, s->windowwidth, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state)||!ssa_issequencebigenough(s, -1, _state) ) + { + for(i=0; i<=*nticks-1; i++) + { + trend->ptr.p_double[i] = (double)(0); + noise->ptr.p_double[i] = (double)(0); + } + if( s->nsequences>=1 ) + { + cnt = ae_minint(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1], *nticks, _state); + offs = s->sequenceidx.ptr.p_int[s->nsequences]-cnt; + for(i=0; i<=cnt-1; i++) + { + noise->ptr.p_double[*nticks-cnt+i] = s->sequencedata.ptr.p_double[offs+i]; + } + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + + /* + * Perform analysis of the last window + */ + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->windowwidth>=0, "SSAAnalyzeLastWindow: integrity check failed", _state); + rvectorsetlengthatleast(&s->tmp0, s->nbasis, _state); + rmatrixgemv(s->nbasis, s->windowwidth, 1.0, &s->basist, 0, 0, 0, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]-s->windowwidth, 0.0, &s->tmp0, 0, _state); + rmatrixgemv(s->windowwidth, s->nbasis, 1.0, &s->basis, 0, 0, 0, &s->tmp0, 0, 0.0, trend, 0, _state); + offs = s->sequenceidx.ptr.p_int[s->nsequences]-s->windowwidth; + cnt = s->windowwidth; + for(i=0; i<=cnt-1; i++) + { + noise->ptr.p_double[i] = s->sequencedata.ptr.p_double[offs+i]-trend->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the last NTicks of the last sequence + +If you want to analyze some other sequence, use ssaanalyzesequence(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +IMPORTANT: due to averaging this function returns different results for + different values of NTicks. It is expected and not a bug. + + For example: + * Trend[NTicks-1] is always same because it is not averaged in + any case (same applies to Trend[0]). + * Trend[NTicks-2] has different values for NTicks=WindowWidth + and NTicks=WindowWidth+1 because former case means that no + averaging is performed, and latter case means that averaging + using two sliding windows is performed. Larger values of + NTicks produce same results as NTicks=WindowWidth+1. + * ...and so on... + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks<=WindowWidth is handled + by analyzing last window and returning NTicks + last ticks. + * special case NTicks>LastSequenceLen is handled + by prepending result with NTicks-LastSequenceLen + zeros. + +OUTPUT PARAMETERS: + Trend - array[NTicks], reconstructed trend line + Noise - array[NTicks], the rest of the signal; + it holds that ActualData = Trend+Noise. + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, NTicks ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelast(ssamodel* s, + ae_int_t nticks, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_state *_state) +{ + ae_int_t i; + ae_int_t offs; + ae_int_t cnt; + ae_int_t cntzeros; + + ae_vector_clear(trend); + ae_vector_clear(noise); + + ae_assert(nticks>=1, "SSAAnalyzeLast: NTicks<1", _state); + + /* + * Init + */ + ae_vector_set_length(trend, nticks, _state); + ae_vector_set_length(noise, nticks, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state)||!ssa_issequencebigenough(s, -1, _state) ) + { + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = (double)(0); + noise->ptr.p_double[i] = (double)(0); + } + if( s->nsequences>=1 ) + { + cnt = ae_minint(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1], nticks, _state); + offs = s->sequenceidx.ptr.p_int[s->nsequences]-cnt; + for(i=0; i<=cnt-1; i++) + { + noise->ptr.p_double[nticks-cnt+i] = s->sequencedata.ptr.p_double[offs+i]; + } + } + return; + } + + /* + * Fast exit: NTicks<=WindowWidth, just last window is analyzed + */ + if( nticks<=s->windowwidth ) + { + ssaanalyzelastwindow(s, &s->alongtrend, &s->alongnoise, &cnt, _state); + offs = s->windowwidth-nticks; + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = s->alongtrend.ptr.p_double[offs+i]; + noise->ptr.p_double[i] = s->alongnoise.ptr.p_double[offs+i]; + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + + /* + * Perform analysis: + * * prepend max(NTicks-LastSequenceLength,0) zeros to the beginning + * of array + * * analyze the rest with AnalyzeSequence() which assumes that we + * already have basis + */ + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>=s->windowwidth, "SSAAnalyzeLast: integrity check failed / 23vd4", _state); + cntzeros = ae_maxint(nticks-(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]), 0, _state); + for(i=0; i<=cntzeros-1; i++) + { + trend->ptr.p_double[i] = 0.0; + noise->ptr.p_double[i] = 0.0; + } + cnt = ae_minint(nticks, s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1], _state); + ssa_analyzesequence(s, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]-cnt, s->sequenceidx.ptr.p_int[s->nsequences], trend, noise, cntzeros, _state); +} + + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the sequence being passed to this function + +If you want to analyze last sequence stored in the model, use +ssaanalyzelast(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], can be larger (only NTicks leading + elements will be used) + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks=1, "SSAAnalyzeSequence: NTicks<1", _state); + ae_assert(data->cnt>=nticks, "SSAAnalyzeSequence: Data is too short", _state); + ae_assert(isfinitevector(data, nticks, _state), "SSAAnalyzeSequence: Data contains infinities NANs", _state); + + /* + * Init + */ + ae_vector_set_length(trend, nticks, _state); + ae_vector_set_length(noise, nticks, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state)||ntickswindowwidth ) + { + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = (double)(0); + noise->ptr.p_double[i] = data->ptr.p_double[i]; + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + + /* + * Perform analysis + */ + ssa_analyzesequence(s, data, 0, nticks, trend, noise, 0, _state); +} + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a specified +number of ticks, returning value of trend. + +Forecast is performed as follows: +* SSA trend extraction is applied to last WindowWidth elements of the + internally stored dataset; this step is basically a noise reduction. +* linear recurrence relation is applied to extracted trend + +This function has following running time: +* O(NBasis*WindowWidth) for trend extraction phase (always performed) +* O(WindowWidth*NTicks) for forecast phase + +NOTE: noise reduction is ALWAYS applied by this algorithm; if you want to + apply recurrence relation to raw unprocessed data, use another + function - ssaforecastsequence() which allows to turn on and off + noise reduction phase. + +NOTE: this algorithm performs prediction using only one - last - sliding + window. Predictions produced by such approach are smooth + continuations of the reconstructed trend line, but they can be + easily corrupted by noise. If you need noise-resistant prediction, + use ssaforecastavglast() function, which averages predictions built + using several sliding windows. + +INPUT PARAMETERS: + S - SSA model + NTicks - number of ticks to forecast, NTicks>=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastlast(ssamodel* s, + ae_int_t nticks, + /* Real */ ae_vector* trend, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t winw; + + ae_vector_clear(trend); + + ae_assert(nticks>=1, "SSAForecast: NTicks<1", _state); + + /* + * Init + */ + winw = s->windowwidth; + ae_vector_set_length(trend, nticks, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = (double)(0); + } + return; + } + ae_assert(s->nsequences>0, "SSAForecastLast: integrity check failed", _state); + if( s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]ptr.p_double[i] = (double)(0); + } + return; + } + if( winw==1 ) + { + ae_assert(s->nsequences>0, "SSAForecast: integrity check failed / 2355", _state); + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>0, "SSAForecast: integrity check failed", _state); + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = s->sequencedata.ptr.p_double[s->sequenceidx.ptr.p_int[s->nsequences]-1]; + } + return; + } + + /* + * Update basis and recurrent relation. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + ae_assert(s->nbasis<=winw&&s->nbasis>0, "SSAForecast: integrity check failed / 4f5et", _state); + if( s->nbasis==winw ) + { + + /* + * Handle degenerate situation with basis whose size + * is equal to window length. + */ + ae_assert(s->nsequences>0, "SSAForecast: integrity check failed / 2355", _state); + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>0, "SSAForecast: integrity check failed", _state); + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = s->sequencedata.ptr.p_double[s->sequenceidx.ptr.p_int[s->nsequences]-1]; + } + return; + } + + /* + * Apply recurrent formula for SSA forecasting: + * * first, perform smoothing of the last window + * * second, perform analysis phase + */ + ae_assert(s->nsequences>0, "SSAForecastLast: integrity check failed", _state); + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>=s->windowwidth, "SSAForecastLast: integrity check failed", _state); + rvectorsetlengthatleast(&s->tmp0, s->nbasis, _state); + rvectorsetlengthatleast(&s->fctrend, s->windowwidth, _state); + rmatrixgemv(s->nbasis, s->windowwidth, 1.0, &s->basist, 0, 0, 0, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]-s->windowwidth, 0.0, &s->tmp0, 0, _state); + rmatrixgemv(s->windowwidth, s->nbasis, 1.0, &s->basis, 0, 0, 0, &s->tmp0, 0, 0.0, &s->fctrend, 0, _state); + rvectorsetlengthatleast(&s->tmp1, winw-1, _state); + for(i=1; i<=winw-1; i++) + { + s->tmp1.ptr.p_double[i-1] = s->fctrend.ptr.p_double[i]; + } + for(i=0; i<=nticks-1; i++) + { + v = s->forecasta.ptr.p_double[0]*s->tmp1.ptr.p_double[0]; + for(j=1; j<=winw-2; j++) + { + v = v+s->forecasta.ptr.p_double[j]*s->tmp1.ptr.p_double[j]; + s->tmp1.ptr.p_double[j-1] = s->tmp1.ptr.p_double[j]; + } + trend->ptr.p_double[i] = v; + s->tmp1.ptr.p_double[winw-2] = v; + } +} + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from the WindowWidth last elements of the + sequence. This stage is optional, you can turn it off if you pass + data which are already processed with SSA. Of course, you can turn it + off even for raw data, but it is not recommended - noise suppression is + very important for correct prediction. +* then, we apply LRR for last WindowWidth-1 elements of the extracted + trend. + +This function has following running time: +* O(NBasis*WindowWidth) for trend extraction phase +* O(WindowWidth*NTicks) for forecast phase + +NOTE: this algorithm performs prediction using only one - last - sliding + window. Predictions produced by such approach are smooth + continuations of the reconstructed trend line, but they can be + easily corrupted by noise. If you need noise-resistant prediction, + use ssaforecastavgsequence() function, which averages predictions + built using several sliding windows. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not; + if you do not know what to specify, pass True. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t datalen, + ae_int_t forecastlen, + ae_bool applysmoothing, + /* Real */ ae_vector* trend, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t winw; + + ae_vector_clear(trend); + + ae_assert(datalen>=1, "SSAForecastSequence: DataLen<1", _state); + ae_assert(data->cnt>=datalen, "SSAForecastSequence: Data is too short", _state); + ae_assert(isfinitevector(data, datalen, _state), "SSAForecastSequence: Data contains infinities NANs", _state); + ae_assert(forecastlen>=1, "SSAForecastSequence: ForecastLen<1", _state); + + /* + * Init + */ + winw = s->windowwidth; + ae_vector_set_length(trend, forecastlen, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state)||datalenptr.p_double[i] = (double)(0); + } + return; + } + if( winw==1 ) + { + for(i=0; i<=forecastlen-1; i++) + { + trend->ptr.p_double[i] = data->ptr.p_double[datalen-1]; + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + ae_assert(s->nbasis<=winw&&s->nbasis>0, "SSAForecast: integrity check failed / 4f5et", _state); + if( s->nbasis==winw ) + { + + /* + * Handle degenerate situation with basis whose size + * is equal to window length. + */ + for(i=0; i<=forecastlen-1; i++) + { + trend->ptr.p_double[i] = data->ptr.p_double[datalen-1]; + } + return; + } + + /* + * Perform trend extraction + */ + rvectorsetlengthatleast(&s->fctrend, s->windowwidth, _state); + if( applysmoothing ) + { + ae_assert(datalen>=winw, "SSAForecastSequence: integrity check failed", _state); + rvectorsetlengthatleast(&s->tmp0, s->nbasis, _state); + rmatrixgemv(s->nbasis, winw, 1.0, &s->basist, 0, 0, 0, data, datalen-winw, 0.0, &s->tmp0, 0, _state); + rmatrixgemv(winw, s->nbasis, 1.0, &s->basis, 0, 0, 0, &s->tmp0, 0, 0.0, &s->fctrend, 0, _state); + } + else + { + for(i=0; i<=winw-1; i++) + { + s->fctrend.ptr.p_double[i] = data->ptr.p_double[datalen+i-winw]; + } + } + + /* + * Apply recurrent formula for SSA forecasting + */ + rvectorsetlengthatleast(&s->tmp1, winw-1, _state); + for(i=1; i<=winw-1; i++) + { + s->tmp1.ptr.p_double[i-1] = s->fctrend.ptr.p_double[i]; + } + for(i=0; i<=forecastlen-1; i++) + { + v = s->forecasta.ptr.p_double[0]*s->tmp1.ptr.p_double[0]; + for(j=1; j<=winw-2; j++) + { + v = v+s->forecasta.ptr.p_double[j]*s->tmp1.ptr.p_double[j]; + s->tmp1.ptr.p_double[j-1] = s->tmp1.ptr.p_double[j]; + } + trend->ptr.p_double[i] = v; + s->tmp1.ptr.p_double[winw-2] = v; + } +} + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a specified +number of ticks, returning value of trend. + +Forecast is performed as follows: +* SSA trend extraction is applied to last M sliding windows of the + internally stored dataset +* for each of M sliding windows, M predictions are built +* average value of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase (always performed) +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: noise reduction is ALWAYS applied by this algorithm; if you want to + apply recurrence relation to raw unprocessed data, use another + function - ssaforecastsequence() which allows to turn on and off + noise reduction phase. + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + NTicks - number of ticks to forecast, NTicks>=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavglast(ssamodel* s, + ae_int_t m, + ae_int_t nticks, + /* Real */ ae_vector* trend, + ae_state *_state) +{ + ae_int_t i; + ae_int_t winw; + + ae_vector_clear(trend); + + ae_assert(nticks>=1, "SSAForecastAvgLast: NTicks<1", _state); + ae_assert(m>=1, "SSAForecastAvgLast: M<1", _state); + + /* + * Init + */ + winw = s->windowwidth; + ae_vector_set_length(trend, nticks, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state) ) + { + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = (double)(0); + } + return; + } + ae_assert(s->nsequences>0, "SSAForecastAvgLast: integrity check failed", _state); + if( s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]ptr.p_double[i] = (double)(0); + } + return; + } + if( winw==1 ) + { + ae_assert(s->nsequences>0, "SSAForecastAvgLast: integrity check failed / 2355", _state); + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>0, "SSAForecastAvgLast: integrity check failed", _state); + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = s->sequencedata.ptr.p_double[s->sequenceidx.ptr.p_int[s->nsequences]-1]; + } + return; + } + + /* + * Update basis and recurrent relation. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + ae_assert(s->nbasis<=winw&&s->nbasis>0, "SSAForecastAvgLast: integrity check failed / 4f5et", _state); + if( s->nbasis==winw ) + { + + /* + * Handle degenerate situation with basis whose size + * is equal to window length. + */ + ae_assert(s->nsequences>0, "SSAForecastAvgLast: integrity check failed / 2355", _state); + ae_assert(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]>0, "SSAForecastAvgLast: integrity check failed", _state); + for(i=0; i<=nticks-1; i++) + { + trend->ptr.p_double[i] = s->sequencedata.ptr.p_double[s->sequenceidx.ptr.p_int[s->nsequences]-1]; + } + return; + } + + /* + * Decrease M if we have less than M sliding windows. + * Forecast. + */ + m = ae_minint(m, s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]-winw+1, _state); + ae_assert(m>=1, "SSAForecastAvgLast: integrity check failed", _state); + ssa_forecastavgsequence(s, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences-1], s->sequenceidx.ptr.p_int[s->nsequences], m, nticks, ae_true, trend, 0, _state); +} + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from M last sliding windows of the sequence. + This stage is optional, you can turn it off if you pass data which + are already processed with SSA. Of course, you can turn it off even + for raw data, but it is not recommended - noise suppression is very + important for correct prediction. +* then, we apply LRR independently for M sliding windows +* average of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not. + if you do not know what to specify, pass true. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavgsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t datalen, + ae_int_t m, + ae_int_t forecastlen, + ae_bool applysmoothing, + /* Real */ ae_vector* trend, + ae_state *_state) +{ + ae_int_t i; + ae_int_t winw; + + ae_vector_clear(trend); + + ae_assert(datalen>=1, "SSAForecastAvgSequence: DataLen<1", _state); + ae_assert(m>=1, "SSAForecastAvgSequence: M<1", _state); + ae_assert(data->cnt>=datalen, "SSAForecastAvgSequence: Data is too short", _state); + ae_assert(isfinitevector(data, datalen, _state), "SSAForecastAvgSequence: Data contains infinities NANs", _state); + ae_assert(forecastlen>=1, "SSAForecastAvgSequence: ForecastLen<1", _state); + + /* + * Init + */ + winw = s->windowwidth; + ae_vector_set_length(trend, forecastlen, _state); + + /* + * Is it degenerate case? + */ + if( !ssa_hassomethingtoanalyze(s, _state)||datalenptr.p_double[i] = (double)(0); + } + return; + } + if( winw==1 ) + { + for(i=0; i<=forecastlen-1; i++) + { + trend->ptr.p_double[i] = data->ptr.p_double[datalen-1]; + } + return; + } + + /* + * Update basis. + * + * It will take care of basis validity flags. AppendLen=0 which means + * that we perform initial basis evaluation. + */ + ssa_updatebasis(s, 0, 0.0, _state); + ae_assert(s->nbasis<=winw&&s->nbasis>0, "SSAForecast: integrity check failed / 4f5et", _state); + if( s->nbasis==winw ) + { + + /* + * Handle degenerate situation with basis whose size + * is equal to window length. + */ + for(i=0; i<=forecastlen-1; i++) + { + trend->ptr.p_double[i] = data->ptr.p_double[datalen-1]; + } + return; + } + + /* + * Decrease M if we have less than M sliding windows. + * Forecast. + */ + m = ae_minint(m, datalen-winw+1, _state); + ae_assert(m>=1, "SSAForecastAvgLast: integrity check failed", _state); + ssa_forecastavgsequence(s, data, 0, datalen, m, forecastlen, applysmoothing, trend, 0, _state); +} + + +/************************************************************************* +This function evaluates current model and tells whether we have some data +which can be analyzed by current algorithm, or not. + +No analysis can be done in the following degenerate cases: +* dataset is empty +* all sequences are shorter than the window length +* no algorithm is specified + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +static ae_bool ssa_hassomethingtoanalyze(const ssamodel* s, + ae_state *_state) +{ + ae_int_t i; + ae_bool allsmaller; + ae_bool isdegenerate; + ae_bool result; + + + isdegenerate = ae_false; + isdegenerate = isdegenerate||s->algotype==0; + isdegenerate = isdegenerate||s->nsequences==0; + allsmaller = ae_true; + for(i=0; i<=s->nsequences-1; i++) + { + allsmaller = allsmaller&&s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]windowwidth; + } + isdegenerate = isdegenerate||allsmaller; + result = !isdegenerate; + return result; +} + + +/************************************************************************* +This function checks whether I-th sequence is big enough for analysis or not. + +I=-1 is used to denote last sequence (for NSequences=0) + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +static ae_bool ssa_issequencebigenough(const ssamodel* s, + ae_int_t i, + ae_state *_state) +{ + ae_bool result; + + + ae_assert(i>=-1&&insequences, "Assertion failed", _state); + result = ae_false; + if( s->nsequences==0 ) + { + return result; + } + if( i<0 ) + { + i = s->nsequences-1; + } + result = s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]>=s->windowwidth; + return result; +} + + +/************************************************************************* +This function performs basis update. Either full update (recalculated from +the very beginning) or partial update (handles append to the end of the +dataset). + +With AppendLen=0 this function behaves as follows: +* if AreBasisAndSolverValid=False, then solver object is created from + scratch, initial calculations are performed according to specific SSA + algorithm being chosen. Basis/Solver validity flag is set to True, then + we immediately return. +* if AreBasisAndSolverValid=True, then nothing is done - we immediately + return. + +With AppendLen>0 this function behaves as follows: +* if AreBasisAndSolverValid=False, then exception is generated; you can + append points only to fully constructed basis. Call this function with + zero AppendLen BEFORE append, then perform append, then call it one more + time with non-zero AppendLen. +* if AreBasisAndSolverValid=True, then basis is incrementally updated. It + also updates recurrence relation used for prediction. It is expected that + either AppendLen=1, or AppendLen=length(last_sequence). Basis update is + performed with probability UpdateIts (larger-than-one values mean that + some amount of iterations is always performed). + + +In any case, after calling this function we either: +* have an exception +* have completely valid basis + +IMPORTANT: this function expects that we do NOT call it for degenerate tasks + (no data). So, call it after check with HasSomethingToAnalyze() + returned True. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_updatebasis(ssamodel* s, + ae_int_t appendlen, + double updateits, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t srcoffs; + ae_int_t dstoffs; + ae_int_t winw; + ae_int_t windowstotal; + ae_int_t requesttype; + ae_int_t requestsize; + double v; + ae_bool degeneraterecurrence; + double nu2; + ae_int_t subspaceits; + ae_bool needevd; + + + winw = s->windowwidth; + + /* + * Critical checks + */ + ae_assert(appendlen>=0, "SSA: incorrect parameters passed to UpdateBasis(), integrity check failed", _state); + ae_assert(!(!s->arebasisandsolvervalid&&appendlen!=0), "SSA: incorrect parameters passed to UpdateBasis(), integrity check failed", _state); + ae_assert(!(appendlen==0&&ae_fp_greater(updateits,0.0)), "SSA: incorrect parameters passed to UpdateBasis(), integrity check failed", _state); + + /* + * Everything is OK, nothing to do + */ + if( s->arebasisandsolvervalid&&appendlen==0 ) + { + return; + } + + /* + * Seed RNG with fixed or random seed. + * + * RNG used when pseudorandomly deciding whether + * to re-evaluate basis or not. Sandom seed is + * important when we have several simultaneously + * calculated SSA models - we do not want them + * to be re-evaluated in same moments). + */ + if( !s->arebasisandsolvervalid ) + { + if( s->rngseed>0 ) + { + hqrndseed(s->rngseed, s->rngseed+235, &s->rs, _state); + } + else + { + hqrndrandomize(&s->rs, _state); + } + } + + /* + * Compute XXT for algorithms which need it + */ + if( !s->arebasisandsolvervalid ) + { + ae_assert(appendlen==0, "SSA: integrity check failed / 34cx6", _state); + if( s->algotype==2 ) + { + + /* + * Compute X*X^T for direct algorithm. + * Quite straightforward, no subtle optimizations. + */ + rmatrixsetlengthatleast(&s->xxt, winw, winw, _state); + windowstotal = 0; + for(i=0; i<=s->nsequences-1; i++) + { + windowstotal = windowstotal+ae_maxint(s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]-winw+1, 0, _state); + } + ae_assert(windowstotal>0, "SSA: integrity check in UpdateBasis() failed / 76t34", _state); + for(i=0; i<=winw-1; i++) + { + for(j=0; j<=winw-1; j++) + { + s->xxt.ptr.pp_double[i][j] = (double)(0); + } + } + ssa_updatexxtprepare(s, windowstotal, winw, s->memorylimit, _state); + for(i=0; i<=s->nsequences-1; i++) + { + for(j=0; j<=ae_maxint(s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]-winw+1, 0, _state)-1; j++) + { + ssa_updatexxtsend(s, &s->sequencedata, s->sequenceidx.ptr.p_int[i]+j, &s->xxt, _state); + } + } + ssa_updatexxtfinalize(s, &s->xxt, _state); + } + if( s->algotype==3 ) + { + + /* + * Compute X*X^T for real-time algorithm: + * * prepare queue of windows to merge into XXT + * * shuffle queue in order to avoid time-related biases in algorithm + * * dequeue first chunk + */ + rmatrixsetlengthatleast(&s->xxt, winw, winw, _state); + windowstotal = 0; + for(i=0; i<=s->nsequences-1; i++) + { + windowstotal = windowstotal+ae_maxint(s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]-winw+1, 0, _state); + } + ae_assert(windowstotal>0, "SSA: integrity check in UpdateBasis() failed / 76t34", _state); + ivectorsetlengthatleast(&s->rtqueue, windowstotal, _state); + dstoffs = 0; + for(i=0; i<=s->nsequences-1; i++) + { + for(j=0; j<=ae_maxint(s->sequenceidx.ptr.p_int[i+1]-s->sequenceidx.ptr.p_int[i]-winw+1, 0, _state)-1; j++) + { + srcoffs = s->sequenceidx.ptr.p_int[i]+j; + s->rtqueue.ptr.p_int[dstoffs] = srcoffs; + inc(&dstoffs, _state); + } + } + ae_assert(dstoffs==windowstotal, "SSA: integrity check in UpdateBasis() failed / fh45f", _state); + if( s->rtpowerup>1 ) + { + + /* + * Shuffle queue, it helps to avoid time-related bias in algorithm + */ + for(i=0; i<=windowstotal-1; i++) + { + j = i+hqrnduniformi(&s->rs, windowstotal-i, _state); + swapelementsi(&s->rtqueue, i, j, _state); + } + } + s->rtqueuecnt = windowstotal; + s->rtqueuechunk = 1; + s->rtqueuechunk = ae_maxint(s->rtqueuechunk, s->rtqueuecnt/s->rtpowerup, _state); + s->rtqueuechunk = ae_maxint(s->rtqueuechunk, 2*s->topk, _state); + ssa_realtimedequeue(s, 0.0, ae_minint(s->rtqueuechunk, s->rtqueuecnt, _state), _state); + } + } + + /* + * Handle possible updates for XXT: + * * check that append involves either last point of last sequence, + * or entire last sequence + * * if last sequence is shorter than window width, perform quick exit - + * we have nothing to update - no windows to insert into XXT + * * update XXT + */ + if( appendlen>0 ) + { + ae_assert(s->arebasisandsolvervalid, "SSA: integrity check failed / 5gvz3", _state); + ae_assert(s->nsequences>=1, "SSA: integrity check failed / 658ev", _state); + ae_assert(appendlen==1||appendlen==s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]-winw+1, "SSA: integrity check failed / sd3g7", _state); + if( s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]algotype==2||s->algotype==3 ) + { + if( appendlen>1 ) + { + + /* + * Long append, use GEMM for updates + */ + ssa_updatexxtprepare(s, appendlen, winw, s->memorylimit, _state); + for(j=0; j<=ae_maxint(s->sequenceidx.ptr.p_int[s->nsequences]-s->sequenceidx.ptr.p_int[s->nsequences-1]-winw+1, 0, _state)-1; j++) + { + ssa_updatexxtsend(s, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences-1]+j, &s->xxt, _state); + } + ssa_updatexxtfinalize(s, &s->xxt, _state); + } + else + { + + /* + * Just one element is added, use rank-1 update + */ + rmatrixger(winw, winw, &s->xxt, 0, 0, 1.0, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]-winw, &s->sequencedata, s->sequenceidx.ptr.p_int[s->nsequences]-winw, _state); + } + } + } + + /* + * Now, perform basis calculation - either full recalculation (AppendLen=0) + * or quick update (AppendLen>0). + */ + if( s->algotype==1 ) + { + + /* + * Precomputed basis + */ + if( winw!=s->precomputedwidth ) + { + + /* + * Window width has changed, reset basis to zeros + */ + s->nbasis = 1; + rmatrixsetlengthatleast(&s->basis, winw, 1, _state); + rvectorsetlengthatleast(&s->sv, 1, _state); + for(i=0; i<=winw-1; i++) + { + s->basis.ptr.pp_double[i][0] = 0.0; + } + s->sv.ptr.p_double[0] = 0.0; + } + else + { + + /* + * OK, use precomputed basis + */ + s->nbasis = s->precomputednbasis; + rmatrixsetlengthatleast(&s->basis, winw, s->nbasis, _state); + rvectorsetlengthatleast(&s->sv, s->nbasis, _state); + for(j=0; j<=s->nbasis-1; j++) + { + s->sv.ptr.p_double[j] = 0.0; + for(i=0; i<=winw-1; i++) + { + s->basis.ptr.pp_double[i][j] = s->precomputedbasis.ptr.pp_double[i][j]; + } + } + } + rmatrixsetlengthatleast(&s->basist, s->nbasis, winw, _state); + rmatrixtranspose(winw, s->nbasis, &s->basis, 0, 0, &s->basist, 0, 0, _state); + } + else + { + if( s->algotype==2 ) + { + + /* + * Direct top-K algorithm + * + * Calculate eigenvectors with SMatrixEVD(), reorder by descending + * of magnitudes. + * + * Update is performed for invalid basis or for non-zero UpdateIts. + */ + needevd = !s->arebasisandsolvervalid; + needevd = needevd||ae_fp_greater_eq(updateits,(double)(1)); + needevd = needevd||ae_fp_less(hqrnduniformr(&s->rs, _state),updateits-(double)ae_ifloor(updateits, _state)); + if( needevd ) + { + inc(&s->dbgcntevd, _state); + s->nbasis = ae_minint(winw, s->topk, _state); + if( !smatrixevd(&s->xxt, winw, 1, ae_true, &s->sv, &s->basis, _state) ) + { + ae_assert(ae_false, "SSA: SMatrixEVD failed", _state); + } + for(i=0; i<=winw-1; i++) + { + k = winw-1-i; + if( i>=k ) + { + break; + } + v = s->sv.ptr.p_double[i]; + s->sv.ptr.p_double[i] = s->sv.ptr.p_double[k]; + s->sv.ptr.p_double[k] = v; + for(j=0; j<=winw-1; j++) + { + v = s->basis.ptr.pp_double[j][i]; + s->basis.ptr.pp_double[j][i] = s->basis.ptr.pp_double[j][k]; + s->basis.ptr.pp_double[j][k] = v; + } + } + for(i=0; i<=s->nbasis-1; i++) + { + s->sv.ptr.p_double[i] = ae_sqrt(ae_maxreal(s->sv.ptr.p_double[i], 0.0, _state), _state); + } + rmatrixsetlengthatleast(&s->basist, s->nbasis, winw, _state); + rmatrixtranspose(winw, s->nbasis, &s->basis, 0, 0, &s->basist, 0, 0, _state); + } + } + else + { + if( s->algotype==3 ) + { + + /* + * Real-time top-K. + * + * Determine actual number of basis components, prepare subspace + * solver (either create from scratch or reuse). + * + * Update is always performed for invalid basis; for a valid basis + * it is performed with probability UpdateIts. + */ + if( s->rtpowerup==1 ) + { + subspaceits = s->defaultsubspaceits; + } + else + { + subspaceits = 3; + } + if( appendlen>0 ) + { + ae_assert(s->arebasisandsolvervalid, "SSA: integrity check in UpdateBasis() failed / srg6f", _state); + ae_assert(ae_fp_greater_eq(updateits,(double)(0)), "SSA: integrity check in UpdateBasis() failed / srg4f", _state); + subspaceits = ae_ifloor(updateits, _state); + if( ae_fp_less(hqrnduniformr(&s->rs, _state),updateits-(double)ae_ifloor(updateits, _state)) ) + { + inc(&subspaceits, _state); + } + ae_assert(subspaceits>=0, "SSA: integrity check in UpdateBasis() failed / srg9f", _state); + } + + /* + * Dequeue pending dataset and merge it into XXT. + * + * Dequeuing is done only for appends, and only when we have + * non-empty queue. + */ + if( appendlen>0&&s->rtqueuecnt>0 ) + { + ssa_realtimedequeue(s, 1.0, ae_minint(s->rtqueuechunk, s->rtqueuecnt, _state), _state); + } + + /* + * Now, proceed to solver + */ + if( subspaceits>0 ) + { + if( appendlen==0 ) + { + s->nbasis = ae_minint(winw, s->topk, _state); + eigsubspacecreatebuf(winw, s->nbasis, &s->solver, _state); + } + else + { + eigsubspacesetwarmstart(&s->solver, ae_true, _state); + } + eigsubspacesetcond(&s->solver, 0.0, subspaceits, _state); + + /* + * Perform initial basis estimation + */ + inc(&s->dbgcntevd, _state); + eigsubspaceoocstart(&s->solver, 0, _state); + while(eigsubspaceooccontinue(&s->solver, _state)) + { + eigsubspaceoocgetrequestinfo(&s->solver, &requesttype, &requestsize, _state); + ae_assert(requesttype==0, "SSA: integrity check in UpdateBasis() failed / 346372", _state); + rmatrixgemm(winw, requestsize, winw, 1.0, &s->xxt, 0, 0, 0, &s->solver.x, 0, 0, 0, 0.0, &s->solver.ax, 0, 0, _state); + } + eigsubspaceoocstop(&s->solver, &s->sv, &s->basis, &s->solverrep, _state); + for(i=0; i<=s->nbasis-1; i++) + { + s->sv.ptr.p_double[i] = ae_sqrt(ae_maxreal(s->sv.ptr.p_double[i], 0.0, _state), _state); + } + rmatrixsetlengthatleast(&s->basist, s->nbasis, winw, _state); + rmatrixtranspose(winw, s->nbasis, &s->basis, 0, 0, &s->basist, 0, 0, _state); + } + } + else + { + ae_assert(ae_false, "SSA: integrity check in UpdateBasis() failed / dfgs34", _state); + } + } + } + + /* + * Update recurrent relation + */ + rvectorsetlengthatleast(&s->forecasta, ae_maxint(winw-1, 1, _state), _state); + degeneraterecurrence = ae_false; + if( winw>1 ) + { + + /* + * Non-degenerate case + */ + rvectorsetlengthatleast(&s->tmp0, s->nbasis, _state); + nu2 = 0.0; + for(i=0; i<=s->nbasis-1; i++) + { + v = s->basist.ptr.pp_double[i][winw-1]; + s->tmp0.ptr.p_double[i] = v; + nu2 = nu2+v*v; + } + if( ae_fp_less(nu2,(double)1-(double)1000*ae_machineepsilon) ) + { + rmatrixgemv(winw-1, s->nbasis, (double)1/((double)1-nu2), &s->basist, 0, 0, 1, &s->tmp0, 0, 0.0, &s->forecasta, 0, _state); + } + else + { + degeneraterecurrence = ae_true; + } + } + else + { + degeneraterecurrence = ae_true; + } + if( degeneraterecurrence ) + { + for(i=0; i<=ae_maxint(winw-1, 1, _state)-1; i++) + { + s->forecasta.ptr.p_double[i] = 0.0; + } + s->forecasta.ptr.p_double[ae_maxint(winw-1, 1, _state)-1] = 1.0; + } + + /* + * Set validity flag + */ + s->arebasisandsolvervalid = ae_true; +} + + +/************************************************************************* +This function performs analysis using current basis. It assumes and checks +that validity flag AreBasisAndSolverValid is set. + +INPUT PARAMETERS: + S - model + Data - array which holds data in elements [I0,I1): + * right bound is not included. + * I1-I0>=WindowWidth (assertion is performed). + Trend - preallocated output array, large enough + Noise - preallocated output array, large enough + Offs - offset in Trend/Noise where result is stored; + I1-I0 elements are written starting at offset + Offs. + +OUTPUT PARAMETERS: + Trend, Noise - processing results + + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_analyzesequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t i0, + ae_int_t i1, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_int_t offs, + ae_state *_state) +{ + ae_int_t winw; + ae_int_t nwindows; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cnt; + ae_int_t batchstart; + ae_int_t batchlimit; + ae_int_t batchsize; + + + ae_assert(s->arebasisandsolvervalid, "AnalyzeSequence: integrity check failed / d84sz0", _state); + ae_assert(i1-i0>=s->windowwidth, "AnalyzeSequence: integrity check failed / d84sz1", _state); + ae_assert(s->nbasis>=1, "AnalyzeSequence: integrity check failed / d84sz2", _state); + nwindows = i1-i0-s->windowwidth+1; + winw = s->windowwidth; + batchlimit = ae_maxint(nwindows, 1, _state); + if( s->memorylimit>0 ) + { + batchlimit = ae_minint(batchlimit, ae_maxint(s->memorylimit/winw, 4*winw, _state), _state); + } + + /* + * Zero-initialize trend and counts + */ + cnt = i1-i0; + ivectorsetlengthatleast(&s->aseqcounts, cnt, _state); + for(i=0; i<=cnt-1; i++) + { + s->aseqcounts.ptr.p_int[i] = 0; + trend->ptr.p_double[offs+i] = 0.0; + } + + /* + * Reset temporaries if algorithm settings changed since last round + */ + if( s->aseqtrajectory.cols!=winw ) + { + ae_matrix_set_length(&s->aseqtrajectory, 0, 0, _state); + } + if( s->aseqtbproduct.cols!=s->nbasis ) + { + ae_matrix_set_length(&s->aseqtbproduct, 0, 0, _state); + } + + /* + * Perform batch processing + */ + rmatrixsetlengthatleast(&s->aseqtrajectory, batchlimit, winw, _state); + rmatrixsetlengthatleast(&s->aseqtbproduct, batchlimit, s->nbasis, _state); + batchsize = 0; + batchstart = offs; + for(i=0; i<=nwindows-1; i++) + { + + /* + * Enqueue next row of trajectory matrix + */ + if( batchsize==0 ) + { + batchstart = i; + } + for(j=0; j<=winw-1; j++) + { + s->aseqtrajectory.ptr.pp_double[batchsize][j] = data->ptr.p_double[i0+i+j]; + } + inc(&batchsize, _state); + + /* + * Process batch + */ + if( batchsize==batchlimit||i==nwindows-1 ) + { + + /* + * Project onto basis + */ + rmatrixgemm(batchsize, s->nbasis, winw, 1.0, &s->aseqtrajectory, 0, 0, 0, &s->basist, 0, 0, 1, 0.0, &s->aseqtbproduct, 0, 0, _state); + rmatrixgemm(batchsize, winw, s->nbasis, 1.0, &s->aseqtbproduct, 0, 0, 0, &s->basist, 0, 0, 0, 0.0, &s->aseqtrajectory, 0, 0, _state); + + /* + * Hankelize + */ + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=winw-1; j++) + { + trend->ptr.p_double[offs+batchstart+k+j] = trend->ptr.p_double[offs+batchstart+k+j]+s->aseqtrajectory.ptr.pp_double[k][j]; + s->aseqcounts.ptr.p_int[batchstart+k+j] = s->aseqcounts.ptr.p_int[batchstart+k+j]+1; + } + } + + /* + * Reset batch size + */ + batchsize = 0; + } + } + for(i=0; i<=cnt-1; i++) + { + trend->ptr.p_double[offs+i] = trend->ptr.p_double[offs+i]/(double)s->aseqcounts.ptr.p_int[i]; + } + + /* + * Output noise + */ + for(i=0; i<=cnt-1; i++) + { + noise->ptr.p_double[offs+i] = data->ptr.p_double[i0+i]-trend->ptr.p_double[offs+i]; + } +} + + +/************************************************************************* +This function performs averaged forecasting. It assumes that basis is +already built, everything is valid and checked. See comments on similar +public functions to find out more about averaged predictions. + +INPUT PARAMETERS: + S - model + Data - array which holds data in elements [I0,I1): + * right bound is not included. + * I1-I0>=WindowWidth (assertion is performed). + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + ForecastLen - number of ticks to predict, ForecastLen>=1 + Trend - preallocated output array, large enough + Offs - offset in Trend where result is stored; + I1-I0 elements are written starting at offset + Offs. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_forecastavgsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t i0, + ae_int_t i1, + ae_int_t m, + ae_int_t forecastlen, + ae_bool smooth, + /* Real */ ae_vector* trend, + ae_int_t offs, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t winw; + + + ae_assert(s->arebasisandsolvervalid, "ForecastAvgSequence: integrity check failed / d84sz0", _state); + ae_assert(i1-i0-s->windowwidth+1>=m, "ForecastAvgSequence: integrity check failed / d84sz1", _state); + ae_assert(s->nbasis>=1, "ForecastAvgSequence: integrity check failed / d84sz2", _state); + ae_assert(s->windowwidth>=2, "ForecastAvgSequence: integrity check failed / 5tgdg5", _state); + ae_assert(s->windowwidth>s->nbasis, "ForecastAvgSequence: integrity check failed / d5g56w", _state); + winw = s->windowwidth; + + /* + * Prepare M synchronized predictions for the last known tick + * (last one is an actual value of the trend, previous M-1 predictions + * are predictions from differently positioned sliding windows). + */ + rmatrixsetlengthatleast(&s->fctrendm, m, winw, _state); + rvectorsetlengthatleast(&s->tmp0, ae_maxint(m, s->nbasis, _state), _state); + rvectorsetlengthatleast(&s->tmp1, winw, _state); + for(k=0; k<=m-1; k++) + { + + /* + * Perform prediction for rows [0,K-1] + */ + rmatrixgemv(k, winw-1, 1.0, &s->fctrendm, 0, 1, 0, &s->forecasta, 0, 0.0, &s->tmp0, 0, _state); + for(i=0; i<=k-1; i++) + { + for(j=1; j<=winw-1; j++) + { + s->fctrendm.ptr.pp_double[i][j-1] = s->fctrendm.ptr.pp_double[i][j]; + } + s->fctrendm.ptr.pp_double[i][winw-1] = s->tmp0.ptr.p_double[i]; + } + + /* + * Perform trend extraction for row K, add it to dataset + */ + if( smooth ) + { + rmatrixgemv(s->nbasis, winw, 1.0, &s->basist, 0, 0, 0, data, i1-winw-(m-1-k), 0.0, &s->tmp0, 0, _state); + rmatrixgemv(s->windowwidth, s->nbasis, 1.0, &s->basis, 0, 0, 0, &s->tmp0, 0, 0.0, &s->tmp1, 0, _state); + for(j=0; j<=winw-1; j++) + { + s->fctrendm.ptr.pp_double[k][j] = s->tmp1.ptr.p_double[j]; + } + } + else + { + for(j=0; j<=winw-1; j++) + { + s->fctrendm.ptr.pp_double[k][j] = data->ptr.p_double[i1-winw-(m-1-k)+j]; + } + } + } + + /* + * Now we have M synchronized predictions of the sequence state at the last + * know moment (last "prediction" is just a copy of the trend). Let's start + * batch prediction! + */ + for(k=0; k<=forecastlen-1; k++) + { + rmatrixgemv(m, winw-1, 1.0, &s->fctrendm, 0, 1, 0, &s->forecasta, 0, 0.0, &s->tmp0, 0, _state); + trend->ptr.p_double[offs+k] = 0.0; + for(i=0; i<=m-1; i++) + { + for(j=1; j<=winw-1; j++) + { + s->fctrendm.ptr.pp_double[i][j-1] = s->fctrendm.ptr.pp_double[i][j]; + } + s->fctrendm.ptr.pp_double[i][winw-1] = s->tmp0.ptr.p_double[i]; + trend->ptr.p_double[offs+k] = trend->ptr.p_double[offs+k]+s->tmp0.ptr.p_double[i]; + } + trend->ptr.p_double[offs+k] = trend->ptr.p_double[offs+k]/(double)m; + } +} + + +/************************************************************************* +This function extracts updates from real-time queue and applies them to +the S.XXT matrix. XXT is premultiplied by Beta, which can be 0.0 for +initial creation, 1.0 for subsequent updates, or even within (0,1) for some +kind of updates with decay. + +INPUT PARAMETERS: + S - model + Beta - >=0, coefficient to premultiply XXT + Cnt - 00, "SSA: RealTimeDequeue() integrity check failed / 43tdv", _state); + ae_assert(ae_isfinite(beta, _state)&&ae_fp_greater_eq(beta,(double)(0)), "SSA: RealTimeDequeue() integrity check failed / 5gdg6", _state); + ae_assert(cnt<=s->rtqueuecnt, "SSA: RealTimeDequeue() integrity check failed / 547yh", _state); + ae_assert(s->xxt.cols>=s->windowwidth, "SSA: RealTimeDequeue() integrity check failed / 54bf4", _state); + ae_assert(s->xxt.rows>=s->windowwidth, "SSA: RealTimeDequeue() integrity check failed / 9gdfn", _state); + winw = s->windowwidth; + + /* + * Premultiply XXT by Beta + */ + if( ae_fp_neq(beta,(double)(0)) ) + { + for(i=0; i<=winw-1; i++) + { + for(j=0; j<=winw-1; j++) + { + s->xxt.ptr.pp_double[i][j] = s->xxt.ptr.pp_double[i][j]*beta; + } + } + } + else + { + for(i=0; i<=winw-1; i++) + { + for(j=0; j<=winw-1; j++) + { + s->xxt.ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * Dequeue + */ + ssa_updatexxtprepare(s, cnt, winw, s->memorylimit, _state); + for(i=0; i<=cnt-1; i++) + { + ssa_updatexxtsend(s, &s->sequencedata, s->rtqueue.ptr.p_int[s->rtqueuecnt-1], &s->xxt, _state); + dec(&s->rtqueuecnt, _state); + } + ssa_updatexxtfinalize(s, &s->xxt, _state); +} + + +/************************************************************************* +This function prepares batch buffer for XXT update. The idea is that we +send a stream of "XXT += u*u'" updates, and we want to package them into +one big matrix update U*U', applied with SYRK() kernel, but U can consume +too much memory, so we want to transparently divide it into few smaller +chunks. + +This set of functions solves this problem: +* UpdateXXTPrepare() prepares temporary buffers +* UpdateXXTSend() sends next u to the buffer, possibly initiating next SYRK() +* UpdateXXTFinalize() performs last SYRK() update + +INPUT PARAMETERS: + S - model, only fields with UX prefix are used + UpdateSize - number of updates + WindowWidth - window width, >0 + MemoryLimit - memory limit, non-positive value means no limit + +OUTPUT PARAMETERS: + S - UX temporaries updated + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_updatexxtprepare(ssamodel* s, + ae_int_t updatesize, + ae_int_t windowwidth, + ae_int_t memorylimit, + ae_state *_state) +{ + + + ae_assert(windowwidth>0, "UpdateXXTPrepare: WinW<=0", _state); + s->uxbatchlimit = ae_maxint(updatesize, 1, _state); + if( memorylimit>0 ) + { + s->uxbatchlimit = ae_minint(s->uxbatchlimit, ae_maxint(memorylimit/windowwidth, 4*windowwidth, _state), _state); + } + s->uxbatchwidth = windowwidth; + s->uxbatchsize = 0; + if( s->uxbatch.cols!=windowwidth ) + { + ae_matrix_set_length(&s->uxbatch, 0, 0, _state); + } + rmatrixsetlengthatleast(&s->uxbatch, s->uxbatchlimit, windowwidth, _state); +} + + +/************************************************************************* +This function sends update u*u' to the batch buffer. + +INPUT PARAMETERS: + S - model, only fields with UX prefix are used + U - WindowWidth-sized update, starts at I0 + I0 - starting position for update + +OUTPUT PARAMETERS: + S - UX temporaries updated + XXT - array[WindowWidth,WindowWidth], in the middle + of update. All intermediate updates are + applied to the upper triangle. + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_updatexxtsend(ssamodel* s, + /* Real */ const ae_vector* u, + ae_int_t i0, + /* Real */ ae_matrix* xxt, + ae_state *_state) +{ + + + ae_assert(i0+s->uxbatchwidth-1cnt, "UpdateXXTSend: incorrect U size", _state); + ae_assert(s->uxbatchsize>=0, "UpdateXXTSend: integrity check failure", _state); + ae_assert(s->uxbatchsize<=s->uxbatchlimit, "UpdateXXTSend: integrity check failure", _state); + ae_assert(s->uxbatchlimit>=1, "UpdateXXTSend: integrity check failure", _state); + + /* + * Send pending batch if full + */ + if( s->uxbatchsize==s->uxbatchlimit ) + { + rmatrixsyrk(s->uxbatchwidth, s->uxbatchsize, 1.0, &s->uxbatch, 0, 0, 2, 1.0, xxt, 0, 0, ae_true, _state); + s->uxbatchsize = 0; + } + + /* + * Append update to batch + */ + ae_v_move(&s->uxbatch.ptr.pp_double[s->uxbatchsize][0], 1, &u->ptr.p_double[i0], 1, ae_v_len(0,s->uxbatchwidth-1)); + inc(&s->uxbatchsize, _state); +} + + +/************************************************************************* +This function finalizes batch buffer. Call it after the last update. + +INPUT PARAMETERS: + S - model, only fields with UX prefix are used + +OUTPUT PARAMETERS: + S - UX temporaries updated + XXT - array[WindowWidth,WindowWidth], updated with + all previous updates, both triangles of the + symmetric matrix are present. + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +static void ssa_updatexxtfinalize(ssamodel* s, + /* Real */ ae_matrix* xxt, + ae_state *_state) +{ + + + ae_assert(s->uxbatchsize>=0, "UpdateXXTFinalize: integrity check failure", _state); + ae_assert(s->uxbatchsize<=s->uxbatchlimit, "UpdateXXTFinalize: integrity check failure", _state); + ae_assert(s->uxbatchlimit>=1, "UpdateXXTFinalize: integrity check failure", _state); + if( s->uxbatchsize>0 ) + { + rmatrixsyrk(s->uxbatchwidth, s->uxbatchsize, 1.0, &s->uxbatch, 0, 0, 2, 1.0, &s->xxt, 0, 0, ae_true, _state); + s->uxbatchsize = 0; + } + rmatrixenforcesymmetricity(&s->xxt, s->uxbatchwidth, ae_true, _state); +} + + +void _ssamodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ssamodel *p = (ssamodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->sequenceidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sequencedata, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->precomputedbasis, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->basis, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->basist, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->forecasta, 0, DT_REAL, _state, make_automatic); + _eigsubspacestate_init(&p->solver, _state, make_automatic); + ae_matrix_init(&p->xxt, 0, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->rs, _state, make_automatic); + ae_vector_init(&p->rtqueue, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + _eigsubspacereport_init(&p->solverrep, _state, make_automatic); + ae_vector_init(&p->alongtrend, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alongnoise, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->aseqtrajectory, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->aseqtbproduct, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->aseqcounts, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->fctrend, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fcnoise, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->fctrendm, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->uxbatch, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _ssamodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ssamodel *dst = (ssamodel*)_dst; + const ssamodel *src = (const ssamodel*)_src; + dst->nsequences = src->nsequences; + ae_vector_init_copy(&dst->sequenceidx, &src->sequenceidx, _state, make_automatic); + ae_vector_init_copy(&dst->sequencedata, &src->sequencedata, _state, make_automatic); + dst->algotype = src->algotype; + dst->windowwidth = src->windowwidth; + dst->rtpowerup = src->rtpowerup; + dst->topk = src->topk; + dst->precomputedwidth = src->precomputedwidth; + dst->precomputednbasis = src->precomputednbasis; + ae_matrix_init_copy(&dst->precomputedbasis, &src->precomputedbasis, _state, make_automatic); + dst->defaultsubspaceits = src->defaultsubspaceits; + dst->memorylimit = src->memorylimit; + dst->arebasisandsolvervalid = src->arebasisandsolvervalid; + ae_matrix_init_copy(&dst->basis, &src->basis, _state, make_automatic); + ae_matrix_init_copy(&dst->basist, &src->basist, _state, make_automatic); + ae_vector_init_copy(&dst->sv, &src->sv, _state, make_automatic); + ae_vector_init_copy(&dst->forecasta, &src->forecasta, _state, make_automatic); + dst->nbasis = src->nbasis; + _eigsubspacestate_init_copy(&dst->solver, &src->solver, _state, make_automatic); + ae_matrix_init_copy(&dst->xxt, &src->xxt, _state, make_automatic); + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + dst->rngseed = src->rngseed; + ae_vector_init_copy(&dst->rtqueue, &src->rtqueue, _state, make_automatic); + dst->rtqueuecnt = src->rtqueuecnt; + dst->rtqueuechunk = src->rtqueuechunk; + dst->dbgcntevd = src->dbgcntevd; + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + _eigsubspacereport_init_copy(&dst->solverrep, &src->solverrep, _state, make_automatic); + ae_vector_init_copy(&dst->alongtrend, &src->alongtrend, _state, make_automatic); + ae_vector_init_copy(&dst->alongnoise, &src->alongnoise, _state, make_automatic); + ae_matrix_init_copy(&dst->aseqtrajectory, &src->aseqtrajectory, _state, make_automatic); + ae_matrix_init_copy(&dst->aseqtbproduct, &src->aseqtbproduct, _state, make_automatic); + ae_vector_init_copy(&dst->aseqcounts, &src->aseqcounts, _state, make_automatic); + ae_vector_init_copy(&dst->fctrend, &src->fctrend, _state, make_automatic); + ae_vector_init_copy(&dst->fcnoise, &src->fcnoise, _state, make_automatic); + ae_matrix_init_copy(&dst->fctrendm, &src->fctrendm, _state, make_automatic); + ae_matrix_init_copy(&dst->uxbatch, &src->uxbatch, _state, make_automatic); + dst->uxbatchwidth = src->uxbatchwidth; + dst->uxbatchsize = src->uxbatchsize; + dst->uxbatchlimit = src->uxbatchlimit; +} + + +void _ssamodel_clear(void* _p) +{ + ssamodel *p = (ssamodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->sequenceidx); + ae_vector_clear(&p->sequencedata); + ae_matrix_clear(&p->precomputedbasis); + ae_matrix_clear(&p->basis); + ae_matrix_clear(&p->basist); + ae_vector_clear(&p->sv); + ae_vector_clear(&p->forecasta); + _eigsubspacestate_clear(&p->solver); + ae_matrix_clear(&p->xxt); + _hqrndstate_clear(&p->rs); + ae_vector_clear(&p->rtqueue); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + _eigsubspacereport_clear(&p->solverrep); + ae_vector_clear(&p->alongtrend); + ae_vector_clear(&p->alongnoise); + ae_matrix_clear(&p->aseqtrajectory); + ae_matrix_clear(&p->aseqtbproduct); + ae_vector_clear(&p->aseqcounts); + ae_vector_clear(&p->fctrend); + ae_vector_clear(&p->fcnoise); + ae_matrix_clear(&p->fctrendm); + ae_matrix_clear(&p->uxbatch); +} + + +void _ssamodel_destroy(void* _p) +{ + ssamodel *p = (ssamodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->sequenceidx); + ae_vector_destroy(&p->sequencedata); + ae_matrix_destroy(&p->precomputedbasis); + ae_matrix_destroy(&p->basis); + ae_matrix_destroy(&p->basist); + ae_vector_destroy(&p->sv); + ae_vector_destroy(&p->forecasta); + _eigsubspacestate_destroy(&p->solver); + ae_matrix_destroy(&p->xxt); + _hqrndstate_destroy(&p->rs); + ae_vector_destroy(&p->rtqueue); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + _eigsubspacereport_destroy(&p->solverrep); + ae_vector_destroy(&p->alongtrend); + ae_vector_destroy(&p->alongnoise); + ae_matrix_destroy(&p->aseqtrajectory); + ae_matrix_destroy(&p->aseqtbproduct); + ae_vector_destroy(&p->aseqcounts); + ae_vector_destroy(&p->fctrend); + ae_vector_destroy(&p->fcnoise); + ae_matrix_destroy(&p->fctrendm); + ae_matrix_destroy(&p->uxbatch); +} + + +#endif +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Multiclass Fisher LDA + +The function finds coefficients of a linear combination which optimally +separates training set. Most suited for 2-class problems, see fisherldan() +for an variant that returns N-dimensional basis. + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - linear combination coefficients, array[NVars] + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherlda(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix w2; + + ae_frame_make(_state, &_frame_block); + memset(&w2, 0, sizeof(w2)); + ae_vector_clear(w); + ae_matrix_init(&w2, 0, 0, DT_REAL, _state, ae_true); + + fisherldan(xy, npoints, nvars, nclasses, &w2, _state); + ae_vector_set_length(w, nvars, _state); + ae_v_move(&w->ptr.p_double[0], 1, &w2.ptr.pp_double[0][0], w2.stride, ae_v_len(0,nvars-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +N-dimensional multiclass Fisher LDA + +Subroutine finds coefficients of linear combinations which optimally separates +training set on classes. It returns N-dimensional basis whose vector are sorted +by quality of training set separation (in descending order). + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - basis, array[NVars,NVars] + columns of matrix stores basis vectors, sorted by + quality of training set separation (in descending order) + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherldan(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + /* Real */ ae_matrix* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t m; + double v; + ae_vector c; + ae_vector mu; + ae_matrix muc; + ae_vector nc; + ae_matrix sw; + ae_matrix st; + ae_matrix z; + ae_matrix z2; + ae_matrix tm; + ae_matrix sbroot; + ae_matrix a; + ae_matrix xyc; + ae_matrix xyproj; + ae_matrix wproj; + ae_vector tf; + ae_vector d; + ae_vector d2; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&mu, 0, sizeof(mu)); + memset(&muc, 0, sizeof(muc)); + memset(&nc, 0, sizeof(nc)); + memset(&sw, 0, sizeof(sw)); + memset(&st, 0, sizeof(st)); + memset(&z, 0, sizeof(z)); + memset(&z2, 0, sizeof(z2)); + memset(&tm, 0, sizeof(tm)); + memset(&sbroot, 0, sizeof(sbroot)); + memset(&a, 0, sizeof(a)); + memset(&xyc, 0, sizeof(xyc)); + memset(&xyproj, 0, sizeof(xyproj)); + memset(&wproj, 0, sizeof(wproj)); + memset(&tf, 0, sizeof(tf)); + memset(&d, 0, sizeof(d)); + memset(&d2, 0, sizeof(d2)); + memset(&work, 0, sizeof(work)); + ae_matrix_clear(w); + ae_vector_init(&c, 0, DT_INT, _state, ae_true); + ae_vector_init(&mu, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&muc, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&nc, 0, DT_INT, _state, ae_true); + ae_matrix_init(&sw, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&st, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&sbroot, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xyc, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xyproj, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&wproj, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + + /* + * Test data + */ + ae_assert(!(npoints<0), "FisherLDAN: NPoints<0", _state); + ae_assert(!(nvars<1), "FisherLDAN: NVars<1", _state); + ae_assert(!(nclasses<2), "FisherLDAN: NClasses<2", _state); + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) + { + ae_assert(ae_false, "FisherLDAN: class index is <0 or >NClasses-1", _state); + } + } + + /* + * Special case: NPoints<=1 + * Degenerate task. + */ + if( npoints<=1 ) + { + ae_matrix_set_length(w, nvars, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + if( i==j ) + { + w->ptr.pp_double[i][j] = (double)(1); + } + else + { + w->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * Prepare temporaries + */ + ae_vector_set_length(&tf, nvars, _state); + ae_vector_set_length(&work, ae_maxint(nvars, npoints, _state)+1, _state); + ae_matrix_set_length(&xyc, npoints, nvars, _state); + + /* + * Convert class labels from reals to integers (just for convenience) + */ + ae_vector_set_length(&c, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + c.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nvars], _state); + } + + /* + * Calculate class sizes, class means + */ + ae_vector_set_length(&mu, nvars, _state); + ae_matrix_set_length(&muc, nclasses, nvars, _state); + ae_vector_set_length(&nc, nclasses, _state); + for(j=0; j<=nvars-1; j++) + { + mu.ptr.p_double[j] = (double)(0); + } + for(i=0; i<=nclasses-1; i++) + { + nc.ptr.p_int[i] = 0; + for(j=0; j<=nvars-1; j++) + { + muc.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=npoints-1; i++) + { + ae_v_add(&mu.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + ae_v_add(&muc.ptr.pp_double[c.ptr.p_int[i]][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + nc.ptr.p_int[c.ptr.p_int[i]] = nc.ptr.p_int[c.ptr.p_int[i]]+1; + } + for(i=0; i<=nclasses-1; i++) + { + v = (double)1/(double)nc.ptr.p_int[i]; + ae_v_muld(&muc.ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); + } + v = (double)1/(double)npoints; + ae_v_muld(&mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1), v); + + /* + * Create ST matrix + */ + ae_matrix_set_length(&st, nvars, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + st.ptr.pp_double[i][j] = (double)(0); + } + } + for(k=0; k<=npoints-1; k++) + { + ae_v_move(&xyc.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); + ae_v_sub(&xyc.ptr.pp_double[k][0], 1, &mu.ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + } + rmatrixgemm(nvars, nvars, npoints, 1.0, &xyc, 0, 0, 1, &xyc, 0, 0, 0, 0.0, &st, 0, 0, _state); + + /* + * Create SW matrix + */ + ae_matrix_set_length(&sw, nvars, nvars, _state); + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + sw.ptr.pp_double[i][j] = (double)(0); + } + } + for(k=0; k<=npoints-1; k++) + { + ae_v_move(&xyc.ptr.pp_double[k][0], 1, &xy->ptr.pp_double[k][0], 1, ae_v_len(0,nvars-1)); + ae_v_sub(&xyc.ptr.pp_double[k][0], 1, &muc.ptr.pp_double[c.ptr.p_int[k]][0], 1, ae_v_len(0,nvars-1)); + } + rmatrixgemm(nvars, nvars, npoints, 1.0, &xyc, 0, 0, 1, &xyc, 0, 0, 0, 0.0, &sw, 0, 0, _state); + + /* + * Maximize ratio J=(w'*ST*w)/(w'*SW*w). + * + * First, make transition from w to v such that w'*ST*w becomes v'*v: + * v = root(ST)*w = R*w + * R = root(D)*Z' + * w = (root(ST)^-1)*v = RI*v + * RI = Z*inv(root(D)) + * J = (v'*v)/(v'*(RI'*SW*RI)*v) + * ST = Z*D*Z' + * + * so we have + * + * J = (v'*v) / (v'*(inv(root(D))*Z'*SW*Z*inv(root(D)))*v) = + * = (v'*v) / (v'*A*v) + */ + if( !smatrixevd(&st, nvars, 1, ae_true, &d, &z, _state) ) + { + ae_assert(ae_false, "FisherLDAN: EVD solver failure", _state); + } + ae_matrix_set_length(w, nvars, nvars, _state); + if( ae_fp_less_eq(d.ptr.p_double[nvars-1],(double)(0))||ae_fp_less_eq(d.ptr.p_double[0],(double)1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) + { + + /* + * Special case: D[NVars-1]<=0 + * Degenerate task (all variables takes the same value). + */ + if( ae_fp_less_eq(d.ptr.p_double[nvars-1],(double)(0)) ) + { + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + if( i==j ) + { + w->ptr.pp_double[i][j] = (double)(1); + } + else + { + w->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * Special case: degenerate ST matrix, multicollinearity found. + * Since we know ST eigenvalues/vectors we can translate task to + * non-degenerate form. + * + * Let WG is orthogonal basis of the non zero variance subspace + * of the ST and let WZ is orthogonal basis of the zero variance + * subspace. + * + * Projection on WG allows us to use LDA on reduced M-dimensional + * subspace, N-M vectors of WZ allows us to update reduced LDA + * factors to full N-dimensional subspace. + */ + m = 0; + for(k=0; k<=nvars-1; k++) + { + if( ae_fp_less_eq(d.ptr.p_double[k],(double)1000*ae_machineepsilon*d.ptr.p_double[nvars-1]) ) + { + m = k+1; + } + } + ae_assert(m!=0, "FisherLDAN: internal error #1", _state); + ae_matrix_set_length(&xyproj, npoints, nvars-m+1, _state); + rmatrixgemm(npoints, nvars-m, nvars, 1.0, xy, 0, 0, 0, &z, 0, m, 0, 0.0, &xyproj, 0, 0, _state); + for(i=0; i<=npoints-1; i++) + { + xyproj.ptr.pp_double[i][nvars-m] = xy->ptr.pp_double[i][nvars]; + } + fisherldan(&xyproj, npoints, nvars-m, nclasses, &wproj, _state); + rmatrixgemm(nvars, nvars-m, nvars-m, 1.0, &z, 0, m, 0, &wproj, 0, 0, 0, 0.0, w, 0, 0, _state); + for(k=nvars-m; k<=nvars-1; k++) + { + ae_v_move(&w->ptr.pp_double[0][k], w->stride, &z.ptr.pp_double[0][k-(nvars-m)], z.stride, ae_v_len(0,nvars-1)); + } + } + else + { + + /* + * General case: no multicollinearity + */ + ae_matrix_set_length(&tm, nvars, nvars, _state); + ae_matrix_set_length(&a, nvars, nvars, _state); + rmatrixgemm(nvars, nvars, nvars, 1.0, &sw, 0, 0, 0, &z, 0, 0, 0, 0.0, &tm, 0, 0, _state); + rmatrixgemm(nvars, nvars, nvars, 1.0, &z, 0, 0, 1, &tm, 0, 0, 0, 0.0, &a, 0, 0, _state); + for(i=0; i<=nvars-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + a.ptr.pp_double[i][j] = a.ptr.pp_double[i][j]/ae_sqrt(d.ptr.p_double[i]*d.ptr.p_double[j], _state); + } + } + if( !smatrixevd(&a, nvars, 1, ae_true, &d2, &z2, _state) ) + { + ae_assert(ae_false, "FisherLDAN: EVD solver failure", _state); + } + for(i=0; i<=nvars-1; i++) + { + for(k=0; k<=nvars-1; k++) + { + z2.ptr.pp_double[i][k] = z2.ptr.pp_double[i][k]/ae_sqrt(d.ptr.p_double[i], _state); + } + } + rmatrixgemm(nvars, nvars, nvars, 1.0, &z, 0, 0, 0, &z2, 0, 0, 0, 0.0, w, 0, 0, _state); + } + + /* + * Post-processing: + * * normalization + * * converting to non-negative form, if possible + */ + for(k=0; k<=nvars-1; k++) + { + v = ae_v_dotproduct(&w->ptr.pp_double[0][k], w->stride, &w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1)); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), v); + v = (double)(0); + for(i=0; i<=nvars-1; i++) + { + v = v+w->ptr.pp_double[i][k]; + } + if( ae_fp_less(v,(double)(0)) ) + { + ae_v_muld(&w->ptr.pp_double[0][k], w->stride, ae_v_len(0,nvars-1), -1.0); + } + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +DESCRIPTION: + +This function creates MCPD (Markov Chains for Population Data) solver. + +This solver can be used to find transition matrix P for N-dimensional +prediction problem where transition from X[i] to X[i+1] is modelled as + X[i+1] = P*X[i] +where X[i] and X[i+1] are N-dimensional population vectors (components of +each X are non-negative), and P is a N*N transition matrix (elements of P +are non-negative, each column sums to 1.0). + +Such models arise when when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is constant, i.e. there is no new individuals and no one + leaves population +* you want to model transitions of individuals from one state into another + +USAGE: + +Here we give very brief outline of the MCPD. We strongly recommend you to +read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on data analysis which is available at http://www.alglib.net/dataanalysis/ + +1. User initializes algorithm state with MCPDCreate() call + +2. User adds one or more tracks - sequences of states which describe + evolution of a system being modelled from different starting conditions + +3. User may add optional boundary, equality and/or linear constraints on + the coefficients of P by calling one of the following functions: + * MCPDSetEC() to set equality constraints + * MCPDSetBC() to set bound constraints + * MCPDSetLC() to set linear constraints + +4. Optionally, user may set custom weights for prediction errors (by + default, algorithm assigns non-equal, automatically chosen weights for + errors in the prediction of different components of X). It can be done + with a call of MCPDSetPredictionWeights() function. + +5. User calls MCPDSolve() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +6. User calls MCPDResults() to get solution + +INPUT PARAMETERS: + N - problem dimension, N>=1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state) +{ + + _mcpdstate_clear(s); + + ae_assert(n>=1, "MCPDCreate: N<1", _state); + mcpd_mcpdinit(n, -1, -1, s, _state); +} + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "entry" state and is treated +in a special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +Such conditions basically mean that row of P which corresponds to "entry" +state is zero. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - at every moment of time there is some + (unpredictable) amount of "new" individuals, which can transit into one + of the states at the next turn, but still no one leaves population +* you want to model transitions of individuals from one state into another +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentry(ae_int_t n, + ae_int_t entrystate, + mcpdstate* s, + ae_state *_state) +{ + + _mcpdstate_clear(s); + + ae_assert(n>=2, "MCPDCreateEntry: N<2", _state); + ae_assert(entrystate>=0, "MCPDCreateEntry: EntryState<0", _state); + ae_assert(entrystate=N", _state); + mcpd_mcpdinit(n, entrystate, -1, s, _state); +} + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "exit" state and is treated +in a special way: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that column of P which corresponds to +"exit" state is zero. Multiplication by such P may decrease sum of vector +components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - individuals can move into "exit" state + and leave population at the next turn, but there are no new individuals +* amount of individuals which leave population can be predicted +* you want to model transitions of individuals from one state into another + (including transitions into the "exit" state) + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateexit(ae_int_t n, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state) +{ + + _mcpdstate_clear(s); + + ae_assert(n>=2, "MCPDCreateExit: N<2", _state); + ae_assert(exitstate>=0, "MCPDCreateExit: ExitState<0", _state); + ae_assert(exitstate=N", _state); + mcpd_mcpdinit(n, -1, exitstate, s, _state); +} + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-Exit-states" model, i.e. model where transition from X[i] to +X[i+1] is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +one selected component of X[] is called "entry" state and is treated in a +special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +and another one component of X[] is called "exit" state and is treated in +a special way too: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that: + row of P which corresponds to "entry" state is zero + column of P which corresponds to "exit" state is zero +Multiplication by such P may decrease sum of vector components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant +* at every moment of time there is some (unpredictable) amount of "new" + individuals, which can transit into one of the states at the next turn +* some individuals can move (predictably) into "exit" state and leave + population at the next turn +* you want to model transitions of individuals from one state into another, + including transitions from the "entry" state and into the "exit" state. +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentryexit(ae_int_t n, + ae_int_t entrystate, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state) +{ + + _mcpdstate_clear(s); + + ae_assert(n>=2, "MCPDCreateEntryExit: N<2", _state); + ae_assert(entrystate>=0, "MCPDCreateEntryExit: EntryState<0", _state); + ae_assert(entrystate=N", _state); + ae_assert(exitstate>=0, "MCPDCreateEntryExit: ExitState<0", _state); + ae_assert(exitstate=N", _state); + ae_assert(entrystate!=exitstate, "MCPDCreateEntryExit: EntryState=ExitState", _state); + mcpd_mcpdinit(n, entrystate, exitstate, s, _state); +} + + +/************************************************************************* +This function is used to add a track - sequence of system states at the +different moments of its evolution. + +You may add one or several tracks to the MCPD solver. In case you have +several tracks, they won't overwrite each other. For example, if you pass +two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then +solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, +t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it +wont try to model transition from t=A+3 to t=B+1. + +INPUT PARAMETERS: + S - solver + XY - track, array[K,N]: + * I-th row is a state at t=I + * elements of XY must be non-negative (exception will be + thrown on negative elements) + K - number of points in a track + * if given, only leading K rows of XY are used + * if not given, automatically determined from size of XY + +NOTES: + +1. Track may contain either proportional or population data: + * with proportional data all rows of XY must sum to 1.0, i.e. we have + proportions instead of absolute population values + * with population data rows of XY contain population counts and generally + do not sum to 1.0 (although they still must be non-negative) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddtrack(mcpdstate* s, + /* Real */ const ae_matrix* xy, + ae_int_t k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + double s0; + double s1; + + + n = s->n; + ae_assert(k>=0, "MCPDAddTrack: K<0", _state); + ae_assert(xy->cols>=n, "MCPDAddTrack: Cols(XY)rows>=k, "MCPDAddTrack: Rows(XY)ptr.pp_double[i][j],(double)(0)), "MCPDAddTrack: XY contains negative elements", _state); + } + } + if( k<2 ) + { + return; + } + if( s->data.rowsnpairs+k-1 ) + { + rmatrixresize(&s->data, ae_maxint(2*s->data.rows, s->npairs+k-1, _state), 2*n, _state); + } + for(i=0; i<=k-2; i++) + { + s0 = (double)(0); + s1 = (double)(0); + for(j=0; j<=n-1; j++) + { + if( s->states.ptr.p_int[j]>=0 ) + { + s0 = s0+xy->ptr.pp_double[i][j]; + } + if( s->states.ptr.p_int[j]<=0 ) + { + s1 = s1+xy->ptr.pp_double[i+1][j]; + } + } + if( ae_fp_greater(s0,(double)(0))&&ae_fp_greater(s1,(double)(0)) ) + { + for(j=0; j<=n-1; j++) + { + if( s->states.ptr.p_int[j]>=0 ) + { + s->data.ptr.pp_double[s->npairs][j] = xy->ptr.pp_double[i][j]/s0; + } + else + { + s->data.ptr.pp_double[s->npairs][j] = 0.0; + } + if( s->states.ptr.p_int[j]<=0 ) + { + s->data.ptr.pp_double[s->npairs][n+j] = xy->ptr.pp_double[i+1][j]/s1; + } + else + { + s->data.ptr.pp_double[s->npairs][n+j] = 0.0; + } + } + s->npairs = s->npairs+1; + } + } +} + + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place equality constraints on arbitrary +subset of elements of P. Set of constraints is specified by EC, which may +contain either NAN's or finite numbers from [0,1]. NAN denotes absence of +constraint, finite number denotes equality constraint on specific element +of P. + +You can also use MCPDAddEC() function which allows to ADD equality +constraint for one element of P without changing constraints for other +elements. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + EC - equality constraints, array[N,N]. Elements of EC can be + either NAN's or finite numbers from [0,1]. NAN denotes + absence of constraints, while finite value denotes + equality constraint on the corresponding element of P. + +NOTES: + +1. infinite values of EC will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetec(mcpdstate* s, + /* Real */ const ae_matrix* ec, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + + n = s->n; + ae_assert(ec->cols>=n, "MCPDSetEC: Cols(EC)rows>=n, "MCPDSetEC: Rows(EC)ptr.pp_double[i][j], _state)||ae_isnan(ec->ptr.pp_double[i][j], _state), "MCPDSetEC: EC containts infinite elements", _state); + s->ec.ptr.pp_double[i][j] = ec->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD equality constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetEC() function which allows you to specify +arbitrary set of equality constraints in one call. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + I - row index of element being constrained + J - column index of element being constrained + C - value (constraint for P[I,J]). Can be either NAN (no + constraint) or finite value from [0,1]. + +NOTES: + +1. infinite values of C will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddec(mcpdstate* s, + ae_int_t i, + ae_int_t j, + double c, + ae_state *_state) +{ + + + ae_assert(i>=0, "MCPDAddEC: I<0", _state); + ae_assert(in, "MCPDAddEC: I>=N", _state); + ae_assert(j>=0, "MCPDAddEC: J<0", _state); + ae_assert(jn, "MCPDAddEC: J>=N", _state); + ae_assert(ae_isnan(c, _state)||ae_isfinite(c, _state), "MCPDAddEC: C is not finite number or NAN", _state); + s->ec.ptr.pp_double[i][j] = c; +} + + +/************************************************************************* +This function is used to add bound constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place bound constraints on arbitrary +subset of elements of P. Set of constraints is specified by BndL/BndU +matrices, which may contain arbitrary combination of finite numbers or +infinities (like -INFn; + ae_assert(bndl->cols>=n, "MCPDSetBC: Cols(BndL)rows>=n, "MCPDSetBC: Rows(BndL)cols>=n, "MCPDSetBC: Cols(BndU)rows>=n, "MCPDSetBC: Rows(BndU)ptr.pp_double[i][j], _state)||ae_isneginf(bndl->ptr.pp_double[i][j], _state), "MCPDSetBC: BndL containts NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.pp_double[i][j], _state)||ae_isposinf(bndu->ptr.pp_double[i][j], _state), "MCPDSetBC: BndU containts NAN or -INF", _state); + s->bndl.ptr.pp_double[i][j] = bndl->ptr.pp_double[i][j]; + s->bndu.ptr.pp_double[i][j] = bndu->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function is used to add bound constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD bound constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetBC() function which allows to place bound +constraints on arbitrary subset of elements of P. Set of constraints is +specified by BndL/BndU matrices, which may contain arbitrary combination +of finite numbers or infinities (like -INF=0, "MCPDAddBC: I<0", _state); + ae_assert(in, "MCPDAddBC: I>=N", _state); + ae_assert(j>=0, "MCPDAddBC: J<0", _state); + ae_assert(jn, "MCPDAddBC: J>=N", _state); + ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MCPDAddBC: BndL is NAN or +INF", _state); + ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MCPDAddBC: BndU is NAN or -INF", _state); + s->bndl.ptr.pp_double[i][j] = bndl; + s->bndu.ptr.pp_double[i][j] = bndu; +} + + +/************************************************************************* +This function is used to set linear equality/inequality constraints on the +elements of the transition matrix P. + +This function can be used to set one or several general linear constraints +on the elements of P. Two types of constraints are supported: +* equality constraints +* inequality constraints (both less-or-equal and greater-or-equal) + +Coefficients of constraints are specified by matrix C (one of the +parameters). One row of C corresponds to one constraint. Because +transition matrix P has N*N elements, we need N*N columns to store all +coefficients (they are stored row by row), and one more column to store +right part - hence C has N*N+1 columns. Constraint kind is stored in the +CT array. + +Thus, I-th linear constraint is + P[0,0]*C[I,0] + P[0,1]*C[I,1] + .. + P[0,N-1]*C[I,N-1] + + + P[1,0]*C[I,N] + P[1,1]*C[I,N+1] + ... + + + P[N-1,N-1]*C[I,N*N-1] ?=? C[I,N*N] +where ?=? can be either "=" (CT[i]=0), "<=" (CT[i]<0) or ">=" (CT[i]>0). + +Your constraint may involve only some subset of P (less than N*N elements). +For example it can be something like + P[0,0] + P[0,1] = 0.5 +In this case you still should pass matrix with N*N+1 columns, but all its +elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. + +INPUT PARAMETERS: + S - solver + C - array[K,N*N+1] - coefficients of constraints + (see above for complete description) + CT - array[K] - constraint types + (see above for complete description) + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetlc(mcpdstate* s, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + + n = s->n; + ae_assert(c->cols>=n*n+1, "MCPDSetLC: Cols(C)rows>=k, "MCPDSetLC: Rows(C)cnt>=k, "MCPDSetLC: Len(CT)c, k, n*n+1, _state); + ivectorsetlengthatleast(&s->ct, k, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n*n; j++) + { + s->c.ptr.pp_double[i][j] = c->ptr.pp_double[i][j]; + } + s->ct.ptr.p_int[i] = ct->ptr.p_int[i]; + } + s->ccnt = k; +} + + +/************************************************************************* +This function allows to tune amount of Tikhonov regularization being +applied to your problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change coefficient r. You can also change +prior values with MCPDSetPrior() function. + +INPUT PARAMETERS: + S - solver + V - regularization coefficient, finite non-negative value. It + is not recommended to specify zero value unless you are + pretty sure that you want it. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state) +{ + + + ae_assert(ae_isfinite(v, _state), "MCPDSetTikhonovRegularizer: V is infinite or NAN", _state); + ae_assert(ae_fp_greater_eq(v,0.0), "MCPDSetTikhonovRegularizer: V is less than zero", _state); + s->regterm = v; +} + + +/************************************************************************* +This function allows to set prior values used for regularization of your +problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change prior values prior_P. You can also +change r with MCPDSetTikhonovRegularizer() function. + +INPUT PARAMETERS: + S - solver + PP - array[N,N], matrix of prior values: + 1. elements must be real numbers from [0,1] + 2. columns must sum to 1.0. + First property is checked (exception is thrown otherwise), + while second one is not checked/enforced. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetprior(mcpdstate* s, + /* Real */ const ae_matrix* _pp, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix pp; + ae_int_t i; + ae_int_t j; + ae_int_t n; + + ae_frame_make(_state, &_frame_block); + memset(&pp, 0, sizeof(pp)); + ae_matrix_init_copy(&pp, _pp, _state, ae_true); + + n = s->n; + ae_assert(pp.cols>=n, "MCPDSetPrior: Cols(PP)=n, "MCPDSetPrior: Rows(PP)priorp.ptr.pp_double[i][j] = pp.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function is used to change prediction weights + +MCPD solver scales prediction errors as follows + Error(P) = ||W*(y-P*x)||^2 +where + x is a system state at time t + y is a system state at time t+1 + P is a transition matrix + W is a diagonal scaling matrix + +By default, weights are chosen in order to minimize relative prediction +error instead of absolute one. For example, if one component of state is +about 0.5 in magnitude and another one is about 0.05, then algorithm will +make corresponding weights equal to 2.0 and 20.0. + +INPUT PARAMETERS: + S - solver + PW - array[N], weights: + * must be non-negative values (exception will be thrown otherwise) + * zero values will be replaced by automatically chosen values + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetpredictionweights(mcpdstate* s, + /* Real */ const ae_vector* pw, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = s->n; + ae_assert(pw->cnt>=n, "MCPDSetPredictionWeights: Length(PW)ptr.p_double[i], _state), "MCPDSetPredictionWeights: PW containts infinite or NAN elements", _state); + ae_assert(ae_fp_greater_eq(pw->ptr.p_double[i],(double)(0)), "MCPDSetPredictionWeights: PW containts negative elements", _state); + s->pw.ptr.p_double[i] = pw->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function is used to start solution of the MCPD problem. + +After return from this function, you can use MCPDResults() to get solution +and completion code. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsolve(mcpdstate* s, ae_state *_state) +{ + ae_int_t n; + ae_int_t npairs; + ae_int_t ccnt; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k2; + double v; + double vv; + + + n = s->n; + npairs = s->npairs; + + /* + * init fields of S + */ + s->repterminationtype = 0; + s->repinneriterationscount = 0; + s->repouteriterationscount = 0; + s->repnfev = 0; + for(k=0; k<=n-1; k++) + { + for(k2=0; k2<=n-1; k2++) + { + s->p.ptr.pp_double[k][k2] = _state->v_nan; + } + } + + /* + * Generate "effective" weights for prediction and calculate preconditioner + */ + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(s->pw.ptr.p_double[i],(double)(0)) ) + { + v = (double)(0); + k = 0; + for(j=0; j<=npairs-1; j++) + { + if( ae_fp_neq(s->data.ptr.pp_double[j][n+i],(double)(0)) ) + { + v = v+s->data.ptr.pp_double[j][n+i]; + k = k+1; + } + } + if( k!=0 ) + { + s->effectivew.ptr.p_double[i] = (double)k/v; + } + else + { + s->effectivew.ptr.p_double[i] = 1.0; + } + } + else + { + s->effectivew.ptr.p_double[i] = s->pw.ptr.p_double[i]; + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->h.ptr.p_double[i*n+j] = (double)2*s->regterm; + } + } + for(k=0; k<=npairs-1; k++) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->h.ptr.p_double[i*n+j] = s->h.ptr.p_double[i*n+j]+(double)2*ae_sqr(s->effectivew.ptr.p_double[i], _state)*ae_sqr(s->data.ptr.pp_double[k][j], _state); + } + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( ae_fp_eq(s->h.ptr.p_double[i*n+j],(double)(0)) ) + { + s->h.ptr.p_double[i*n+j] = (double)(1); + } + } + } + + /* + * Generate "effective" BndL/BndU + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + + /* + * Set default boundary constraints. + * Lower bound is always zero, upper bound is calculated + * with respect to entry/exit states. + */ + s->effectivebndl.ptr.p_double[i*n+j] = 0.0; + if( s->states.ptr.p_int[i]>0||s->states.ptr.p_int[j]<0 ) + { + s->effectivebndu.ptr.p_double[i*n+j] = 0.0; + } + else + { + s->effectivebndu.ptr.p_double[i*n+j] = 1.0; + } + + /* + * Calculate intersection of the default and user-specified bound constraints. + * This code checks consistency of such combination. + */ + if( ae_isfinite(s->bndl.ptr.pp_double[i][j], _state)&&ae_fp_greater(s->bndl.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j]) ) + { + s->effectivebndl.ptr.p_double[i*n+j] = s->bndl.ptr.pp_double[i][j]; + } + if( ae_isfinite(s->bndu.ptr.pp_double[i][j], _state)&&ae_fp_less(s->bndu.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) + { + s->effectivebndu.ptr.p_double[i*n+j] = s->bndu.ptr.pp_double[i][j]; + } + if( ae_fp_greater(s->effectivebndl.ptr.p_double[i*n+j],s->effectivebndu.ptr.p_double[i*n+j]) ) + { + s->repterminationtype = -3; + return; + } + + /* + * Calculate intersection of the effective bound constraints + * and user-specified equality constraints. + * This code checks consistency of such combination. + */ + if( ae_isfinite(s->ec.ptr.pp_double[i][j], _state) ) + { + if( ae_fp_less(s->ec.ptr.pp_double[i][j],s->effectivebndl.ptr.p_double[i*n+j])||ae_fp_greater(s->ec.ptr.pp_double[i][j],s->effectivebndu.ptr.p_double[i*n+j]) ) + { + s->repterminationtype = -3; + return; + } + s->effectivebndl.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; + s->effectivebndu.ptr.p_double[i*n+j] = s->ec.ptr.pp_double[i][j]; + } + } + } + + /* + * Generate linear constraints: + * * "default" sums-to-one constraints (not generated for "exit" states) + */ + rmatrixsetlengthatleast(&s->effectivec, s->ccnt+n, n*n+1, _state); + ivectorsetlengthatleast(&s->effectivect, s->ccnt+n, _state); + ccnt = s->ccnt; + for(i=0; i<=s->ccnt-1; i++) + { + for(j=0; j<=n*n; j++) + { + s->effectivec.ptr.pp_double[i][j] = s->c.ptr.pp_double[i][j]; + } + s->effectivect.ptr.p_int[i] = s->ct.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + if( s->states.ptr.p_int[i]>=0 ) + { + for(k=0; k<=n*n-1; k++) + { + s->effectivec.ptr.pp_double[ccnt][k] = (double)(0); + } + for(k=0; k<=n-1; k++) + { + s->effectivec.ptr.pp_double[ccnt][k*n+i] = (double)(1); + } + s->effectivec.ptr.pp_double[ccnt][n*n] = 1.0; + s->effectivect.ptr.p_int[ccnt] = 0; + ccnt = ccnt+1; + } + } + + /* + * create optimizer + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->tmpp.ptr.p_double[i*n+j] = (double)1/(double)n; + } + } + minbleicrestartfrom(&s->bs, &s->tmpp, _state); + minbleicsetbc(&s->bs, &s->effectivebndl, &s->effectivebndu, _state); + minbleicsetlc(&s->bs, &s->effectivec, &s->effectivect, ccnt, _state); + minbleicsetcond(&s->bs, 0.0, 0.0, mcpd_xtol, 0, _state); + minbleicsetprecdiag(&s->bs, &s->h, _state); + + /* + * solve problem + */ + while(minbleiciteration(&s->bs, _state)) + { + ae_assert(s->bs.needfg, "MCPDSolve: internal error", _state); + if( s->bs.needfg ) + { + + /* + * Calculate regularization term + */ + s->bs.f = 0.0; + vv = s->regterm; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->bs.f = s->bs.f+vv*ae_sqr(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j], _state); + s->bs.g.ptr.p_double[i*n+j] = (double)2*vv*(s->bs.x.ptr.p_double[i*n+j]-s->priorp.ptr.pp_double[i][j]); + } + } + + /* + * calculate prediction error/gradient for K-th pair + */ + for(k=0; k<=npairs-1; k++) + { + for(i=0; i<=n-1; i++) + { + v = ae_v_dotproduct(&s->bs.x.ptr.p_double[i*n], 1, &s->data.ptr.pp_double[k][0], 1, ae_v_len(i*n,i*n+n-1)); + vv = s->effectivew.ptr.p_double[i]; + s->bs.f = s->bs.f+ae_sqr(vv*(v-s->data.ptr.pp_double[k][n+i]), _state); + for(j=0; j<=n-1; j++) + { + s->bs.g.ptr.p_double[i*n+j] = s->bs.g.ptr.p_double[i*n+j]+(double)2*vv*vv*(v-s->data.ptr.pp_double[k][n+i])*s->data.ptr.pp_double[k][j]; + } + } + } + + /* + * continue + */ + continue; + } + } + minbleicresultsbuf(&s->bs, &s->tmpp, &s->br, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->p.ptr.pp_double[i][j] = s->tmpp.ptr.p_double[i*n+j]; + } + } + s->repterminationtype = s->br.terminationtype; + s->repinneriterationscount = s->br.inneriterationscount; + s->repouteriterationscount = s->br.outeriterationscount; + s->repnfev = s->br.nfev; +} + + +/************************************************************************* +MCPD results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - array[N,N], transition matrix + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one. Speaking short, positive values denote + success, negative ones are failures. + More information about fields of this structure can be + found in the comments on MCPDReport datatype. + + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdresults(const mcpdstate* s, + /* Real */ ae_matrix* p, + mcpdreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(p); + _mcpdreport_clear(rep); + + ae_matrix_set_length(p, s->n, s->n, _state); + for(i=0; i<=s->n-1; i++) + { + for(j=0; j<=s->n-1; j++) + { + p->ptr.pp_double[i][j] = s->p.ptr.pp_double[i][j]; + } + } + rep->terminationtype = s->repterminationtype; + rep->inneriterationscount = s->repinneriterationscount; + rep->outeriterationscount = s->repouteriterationscount; + rep->nfev = s->repnfev; +} + + +/************************************************************************* +Internal initialization function + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +static void mcpd_mcpdinit(ae_int_t n, + ae_int_t entrystate, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(n>=1, "MCPDCreate: N<1", _state); + s->n = n; + ae_vector_set_length(&s->states, n, _state); + for(i=0; i<=n-1; i++) + { + s->states.ptr.p_int[i] = 0; + } + if( entrystate>=0 ) + { + s->states.ptr.p_int[entrystate] = 1; + } + if( exitstate>=0 ) + { + s->states.ptr.p_int[exitstate] = -1; + } + s->npairs = 0; + s->regterm = 1.0E-8; + s->ccnt = 0; + ae_matrix_set_length(&s->p, n, n, _state); + ae_matrix_set_length(&s->ec, n, n, _state); + ae_matrix_set_length(&s->bndl, n, n, _state); + ae_matrix_set_length(&s->bndu, n, n, _state); + ae_vector_set_length(&s->pw, n, _state); + ae_matrix_set_length(&s->priorp, n, n, _state); + ae_vector_set_length(&s->tmpp, n*n, _state); + ae_vector_set_length(&s->effectivew, n, _state); + ae_vector_set_length(&s->effectivebndl, n*n, _state); + ae_vector_set_length(&s->effectivebndu, n*n, _state); + ae_vector_set_length(&s->h, n*n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->p.ptr.pp_double[i][j] = 0.0; + s->priorp.ptr.pp_double[i][j] = 0.0; + s->bndl.ptr.pp_double[i][j] = _state->v_neginf; + s->bndu.ptr.pp_double[i][j] = _state->v_posinf; + s->ec.ptr.pp_double[i][j] = _state->v_nan; + } + s->pw.ptr.p_double[i] = 0.0; + s->priorp.ptr.pp_double[i][i] = 1.0; + } + ae_matrix_set_length(&s->data, 1, 2*n, _state); + for(i=0; i<=2*n-1; i++) + { + s->data.ptr.pp_double[0][i] = 0.0; + } + for(i=0; i<=n*n-1; i++) + { + s->tmpp.ptr.p_double[i] = 0.0; + } + minbleiccreate(n*n, &s->tmpp, &s->bs, _state); +} + + +void _mcpdstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mcpdstate *p = (mcpdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->states, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->data, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ec, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bndl, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bndu, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ct, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->pw, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->priorp, 0, 0, DT_REAL, _state, make_automatic); + _minbleicstate_init(&p->bs, _state, make_automatic); + _minbleicreport_init(&p->br, _state, make_automatic); + ae_vector_init(&p->tmpp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effectivew, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effectivebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effectivebndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->effectivec, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effectivect, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->h, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->p, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _mcpdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mcpdstate *dst = (mcpdstate*)_dst; + const mcpdstate *src = (const mcpdstate*)_src; + dst->n = src->n; + ae_vector_init_copy(&dst->states, &src->states, _state, make_automatic); + dst->npairs = src->npairs; + ae_matrix_init_copy(&dst->data, &src->data, _state, make_automatic); + ae_matrix_init_copy(&dst->ec, &src->ec, _state, make_automatic); + ae_matrix_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_matrix_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->ct, &src->ct, _state, make_automatic); + dst->ccnt = src->ccnt; + ae_vector_init_copy(&dst->pw, &src->pw, _state, make_automatic); + ae_matrix_init_copy(&dst->priorp, &src->priorp, _state, make_automatic); + dst->regterm = src->regterm; + _minbleicstate_init_copy(&dst->bs, &src->bs, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + _minbleicreport_init_copy(&dst->br, &src->br, _state, make_automatic); + ae_vector_init_copy(&dst->tmpp, &src->tmpp, _state, make_automatic); + ae_vector_init_copy(&dst->effectivew, &src->effectivew, _state, make_automatic); + ae_vector_init_copy(&dst->effectivebndl, &src->effectivebndl, _state, make_automatic); + ae_vector_init_copy(&dst->effectivebndu, &src->effectivebndu, _state, make_automatic); + ae_matrix_init_copy(&dst->effectivec, &src->effectivec, _state, make_automatic); + ae_vector_init_copy(&dst->effectivect, &src->effectivect, _state, make_automatic); + ae_vector_init_copy(&dst->h, &src->h, _state, make_automatic); + ae_matrix_init_copy(&dst->p, &src->p, _state, make_automatic); +} + + +void _mcpdstate_clear(void* _p) +{ + mcpdstate *p = (mcpdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->states); + ae_matrix_clear(&p->data); + ae_matrix_clear(&p->ec); + ae_matrix_clear(&p->bndl); + ae_matrix_clear(&p->bndu); + ae_matrix_clear(&p->c); + ae_vector_clear(&p->ct); + ae_vector_clear(&p->pw); + ae_matrix_clear(&p->priorp); + _minbleicstate_clear(&p->bs); + _minbleicreport_clear(&p->br); + ae_vector_clear(&p->tmpp); + ae_vector_clear(&p->effectivew); + ae_vector_clear(&p->effectivebndl); + ae_vector_clear(&p->effectivebndu); + ae_matrix_clear(&p->effectivec); + ae_vector_clear(&p->effectivect); + ae_vector_clear(&p->h); + ae_matrix_clear(&p->p); +} + + +void _mcpdstate_destroy(void* _p) +{ + mcpdstate *p = (mcpdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->states); + ae_matrix_destroy(&p->data); + ae_matrix_destroy(&p->ec); + ae_matrix_destroy(&p->bndl); + ae_matrix_destroy(&p->bndu); + ae_matrix_destroy(&p->c); + ae_vector_destroy(&p->ct); + ae_vector_destroy(&p->pw); + ae_matrix_destroy(&p->priorp); + _minbleicstate_destroy(&p->bs); + _minbleicreport_destroy(&p->br); + ae_vector_destroy(&p->tmpp); + ae_vector_destroy(&p->effectivew); + ae_vector_destroy(&p->effectivebndl); + ae_vector_destroy(&p->effectivebndu); + ae_matrix_destroy(&p->effectivec); + ae_vector_destroy(&p->effectivect); + ae_vector_destroy(&p->h); + ae_matrix_destroy(&p->p); +} + + +void _mcpdreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mcpdreport *p = (mcpdreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mcpdreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mcpdreport *dst = (mcpdreport*)_dst; + const mcpdreport *src = (const mcpdreport*)_src; + dst->inneriterationscount = src->inneriterationscount; + dst->outeriterationscount = src->outeriterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; +} + + +void _mcpdreport_clear(void* _p) +{ + mcpdreport *p = (mcpdreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mcpdreport_destroy(void* _p) +{ + mcpdreport *p = (mcpdreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine trains logit model. + +INPUT PARAMETERS: + XY - training set, array[0..NPoints-1,0..NVars] + First NVars columns store values of independent + variables, next column stores number of class (from 0 + to NClasses-1) which dataset element belongs to. Fractional + values are rounded to nearest integer. + NPoints - training set size, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPointsptr.pp_double[i][nvars], _state)<0||ae_round(xy->ptr.pp_double[i][nvars], _state)>=nclasses ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + *info = 1; + + /* + * Initialize data + */ + rep->ngrad = 0; + rep->nhess = 0; + + /* + * Allocate array + */ + offs = 5; + ssize = 5+(nvars+1)*(nclasses-1)+nclasses; + ae_vector_set_length(&lm->w, ssize-1+1, _state); + lm->w.ptr.p_double[0] = (double)(ssize); + lm->w.ptr.p_double[1] = (double)(logit_logitvnum); + lm->w.ptr.p_double[2] = (double)(nvars); + lm->w.ptr.p_double[3] = (double)(nclasses); + lm->w.ptr.p_double[4] = (double)(offs); + + /* + * Degenerate case: all outputs are equal + */ + allsame = ae_true; + for(i=1; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nvars], _state)!=ae_round(xy->ptr.pp_double[i-1][nvars], _state) ) + { + allsame = ae_false; + } + } + if( allsame ) + { + for(i=0; i<=(nvars+1)*(nclasses-1)-1; i++) + { + lm->w.ptr.p_double[offs+i] = (double)(0); + } + v = -(double)2*ae_log(ae_minrealnumber, _state); + k = ae_round(xy->ptr.pp_double[0][nvars], _state); + if( k==nclasses-1 ) + { + for(i=0; i<=nclasses-2; i++) + { + lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = -v; + } + } + else + { + for(i=0; i<=nclasses-2; i++) + { + if( i==k ) + { + lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = v; + } + else + { + lm->w.ptr.p_double[offs+i*(nvars+1)+nvars] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * General case. + * Prepare task and network. Allocate space. + */ + mlpcreatec0(nvars, nclasses, &network, _state); + mlpinitpreprocessor(&network, xy, npoints, _state); + mlpproperties(&network, &nin, &nout, &wcount, _state); + for(i=0; i<=wcount-1; i++) + { + network.weights.ptr.p_double[i] = ((double)2*ae_randomreal(_state)-(double)1)/(double)nvars; + } + ae_vector_set_length(&g, wcount-1+1, _state); + ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); + ae_vector_set_length(&wbase, wcount-1+1, _state); + ae_vector_set_length(&wdir, wcount-1+1, _state); + ae_vector_set_length(&work, wcount-1+1, _state); + + /* + * First stage: optimize in gradient direction. + */ + for(k=0; k<=wcount/3+10; k++) + { + + /* + * Calculate gradient in starting point + */ + mlpgradnbatch(&network, xy, npoints, &e, &g, _state); + v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + rep->ngrad = rep->ngrad+1; + + /* + * Setup optimization scheme + */ + ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + wstep = ae_sqrt(v, _state); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); + mcstage = 0; + logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); + while(mcstage!=0) + { + mlpgradnbatch(&network, xy, npoints, &e, &g, _state); + v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + rep->ngrad = rep->ngrad+1; + logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); + } + } + + /* + * Second stage: use Hessian when we are close to the minimum + */ + for(;;) + { + + /* + * Calculate and update E/G/H + */ + mlphessiannbatch(&network, xy, npoints, &e, &g, &h, _state); + v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + for(k=0; k<=wcount-1; k++) + { + h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; + } + rep->nhess = rep->nhess+1; + + /* + * Select step direction + * NOTE: it is important to use lower-triangle Cholesky + * factorization since it is much faster than higher-triangle version. + */ + spd = spdmatrixcholesky(&h, wcount, ae_false, _state); + spdmatrixcholeskysolve(&h, wcount, ae_false, &g, &wdir, &solverrep, _state); + spd = solverrep.terminationtype>0; + if( spd ) + { + + /* + * H is positive definite. + * Step in Newton direction. + */ + ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1.0); + spd = ae_true; + } + else + { + + /* + * H is indefinite. + * Step in gradient direction. + */ + ae_v_moveneg(&wdir.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + spd = ae_false; + } + + /* + * Optimize in WDir direction + */ + v = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + wstep = ae_sqrt(v, _state); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), v); + mcstage = 0; + logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); + while(mcstage!=0) + { + mlpgradnbatch(&network, xy, npoints, &e, &g, _state); + v = ae_v_dotproduct(&network.weights.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + rep->ngrad = rep->ngrad+1; + logit_mnlmcsrch(wcount, &network.weights, &e, &g, &wdir, &wstep, &mcinfo, &mcnfev, &work, &mcstate, &mcstage, _state); + } + if( spd&&((mcinfo==2||mcinfo==4)||mcinfo==6) ) + { + break; + } + } + + /* + * Convert from NN format to MNL format + */ + ae_v_move(&lm->w.ptr.p_double[offs], 1, &network.weights.ptr.p_double[0], 1, ae_v_len(offs,offs+wcount-1)); + for(k=0; k<=nvars-1; k++) + { + for(i=0; i<=nclasses-2; i++) + { + s = network.columnsigmas.ptr.p_double[k]; + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(1); + } + j = offs+(nvars+1)*i; + v = lm->w.ptr.p_double[j+k]; + lm->w.ptr.p_double[j+k] = v/s; + lm->w.ptr.p_double[j+nvars] = lm->w.ptr.p_double[j+nvars]+v*network.columnmeans.ptr.p_double[k]/s; + } + } + for(k=0; k<=nclasses-2; k++) + { + lm->w.ptr.p_double[offs+(nvars+1)*k+nvars] = -lm->w.ptr.p_double[offs+(nvars+1)*k+nvars]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + LM - logit model, passed by non-constant reference + (some fields of structure are used as temporaries + when calculating model output). + X - input vector, array[0..NVars-1]. + Y - (possibly) preallocated buffer; if size of Y is less than + NClasses, it will be reallocated.If it is large enough, it + is NOT reallocated, so we can save some time on reallocation. + +OUTPUT PARAMETERS: + Y - result, array[0..NClasses-1] + Vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +void mnlprocess(logitmodel* lm, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t offs; + ae_int_t i; + ae_int_t i1; + double s; + + + ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLProcess: unexpected model version", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + nclasses = ae_round(lm->w.ptr.p_double[3], _state); + offs = ae_round(lm->w.ptr.p_double[4], _state); + logit_mnliexp(&lm->w, x, _state); + s = (double)(0); + i1 = offs+(nvars+1)*(nclasses-1); + for(i=i1; i<=i1+nclasses-1; i++) + { + s = s+lm->w.ptr.p_double[i]; + } + if( y->cntptr.p_double[i] = lm->w.ptr.p_double[i1+i]/s; + } +} + + +/************************************************************************* +'interactive' variant of MNLProcess for languages like Python which +support constructs like "Y = MNLProcess(LM,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +void mnlprocessi(logitmodel* lm, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + mnlprocess(lm, x, y, _state); +} + + +/************************************************************************* +Unpacks coefficients of logit model. Logit model have form: + + P(class=i) = S(i) / (S(0) + S(1) + ... +S(M-1)) + S(i) = Exp(A[i,0]*X[0] + ... + A[i,N-1]*X[N-1] + A[i,N]), when iw.ptr.p_double[1],(double)(logit_logitvnum)), "MNLUnpack: unexpected model version", _state); + *nvars = ae_round(lm->w.ptr.p_double[2], _state); + *nclasses = ae_round(lm->w.ptr.p_double[3], _state); + offs = ae_round(lm->w.ptr.p_double[4], _state); + ae_matrix_set_length(a, *nclasses-2+1, *nvars+1, _state); + for(i=0; i<=*nclasses-2; i++) + { + ae_v_move(&a->ptr.pp_double[i][0], 1, &lm->w.ptr.p_double[offs+i*(*nvars+1)], 1, ae_v_len(0,*nvars)); + } +} + + +/************************************************************************* +"Packs" coefficients and creates logit model in ALGLIB format (MNLUnpack +reversed). + +INPUT PARAMETERS: + A - model (see MNLUnpack) + NVars - number of independent variables + NClasses - number of classes + +OUTPUT PARAMETERS: + LM - logit model. + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +void mnlpack(/* Real */ const ae_matrix* a, + ae_int_t nvars, + ae_int_t nclasses, + logitmodel* lm, + ae_state *_state) +{ + ae_int_t offs; + ae_int_t i; + ae_int_t ssize; + + _logitmodel_clear(lm); + + offs = 5; + ssize = 5+(nvars+1)*(nclasses-1)+nclasses; + ae_vector_set_length(&lm->w, ssize-1+1, _state); + lm->w.ptr.p_double[0] = (double)(ssize); + lm->w.ptr.p_double[1] = (double)(logit_logitvnum); + lm->w.ptr.p_double[2] = (double)(nvars); + lm->w.ptr.p_double[3] = (double)(nclasses); + lm->w.ptr.p_double[4] = (double)(offs); + for(i=0; i<=nclasses-2; i++) + { + ae_v_move(&lm->w.ptr.p_double[offs+i*(nvars+1)], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars)); + } +} + + +/************************************************************************* +Copying of LogitModel strucure + +INPUT PARAMETERS: + LM1 - original + +OUTPUT PARAMETERS: + LM2 - copy + + -- ALGLIB -- + Copyright 15.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mnlcopy(const logitmodel* lm1, logitmodel* lm2, ae_state *_state) +{ + ae_int_t k; + + _logitmodel_clear(lm2); + + k = ae_round(lm1->w.ptr.p_double[0], _state); + ae_vector_set_length(&lm2->w, k-1+1, _state); + ae_v_move(&lm2->w.ptr.p_double[0], 1, &lm1->w.ptr.p_double[0], 1, ae_v_len(0,k-1)); +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + LM - logit model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*ln(2)). + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +double mnlavgce(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t i; + ae_vector workx; + ae_vector worky; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&workx, 0, sizeof(workx)); + memset(&worky, 0, sizeof(worky)); + ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&worky, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLClsError: unexpected model version", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + nclasses = ae_round(lm->w.ptr.p_double[3], _state); + ae_vector_set_length(&workx, nvars-1+1, _state); + ae_vector_set_length(&worky, nclasses-1+1, _state); + result = (double)(0); + for(i=0; i<=npoints-1; i++) + { + ae_assert(ae_round(xy->ptr.pp_double[i][nvars], _state)>=0&&ae_round(xy->ptr.pp_double[i][nvars], _state)ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + mnlprocess(lm, &workx, &worky, _state); + if( ae_fp_greater(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)],(double)(0)) ) + { + result = result-ae_log(worky.ptr.p_double[ae_round(xy->ptr.pp_double[i][nvars], _state)], _state); + } + else + { + result = result-ae_log(ae_minrealnumber, _state); + } + } + result = result/((double)npoints*ae_log((double)(2), _state)); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + LM - logit model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +double mnlrelclserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double result; + + + result = (double)mnlclserror(lm, xy, npoints, _state)/(double)npoints; + return result; +} + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - logit model + XY - test set + NPoints - test set size + +RESULT: + root mean square error (error when estimating posterior probabilities). + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double mnlrmserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double relcls; + double avgce; + double rms; + double avg; + double avgrel; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); + logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); + result = rms; + return result; +} + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + LM - logit model + XY - test set + NPoints - test set size + +RESULT: + average error (error when estimating posterior probabilities). + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double mnlavgerror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double relcls; + double avgce; + double rms; + double avg; + double avgrel; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); + logit_mnlallerrors(lm, xy, npoints, &relcls, &avgce, &rms, &avg, &avgrel, _state); + result = avg; + return result; +} + + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + LM - logit model + XY - test set + NPoints - test set size + +RESULT: + average relative error (error when estimating posterior probabilities). + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double mnlavgrelerror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state) +{ + double relcls; + double avgce; + double rms; + double avg; + double avgrel; + double result; + + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNLRMSError: Incorrect MNL version!", _state); + logit_mnlallerrors(lm, xy, ssize, &relcls, &avgce, &rms, &avg, &avgrel, _state); + result = avgrel; + return result; +} + + +/************************************************************************* +Classification error on test set = MNLRelClsError*NPoints + + -- ALGLIB -- + Copyright 10.09.2008 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mnlclserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t i; + ae_int_t j; + ae_vector workx; + ae_vector worky; + ae_int_t nmax; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&workx, 0, sizeof(workx)); + memset(&worky, 0, sizeof(worky)); + ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&worky, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_eq(lm->w.ptr.p_double[1],(double)(logit_logitvnum)), "MNLClsError: unexpected model version", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + nclasses = ae_round(lm->w.ptr.p_double[3], _state); + ae_vector_set_length(&workx, nvars-1+1, _state); + ae_vector_set_length(&worky, nclasses-1+1, _state); + result = 0; + for(i=0; i<=npoints-1; i++) + { + + /* + * Process + */ + ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + mnlprocess(lm, &workx, &worky, _state); + + /* + * Logit version of the answer + */ + nmax = 0; + for(j=0; j<=nclasses-1; j++) + { + if( ae_fp_greater(worky.ptr.p_double[j],worky.ptr.p_double[nmax]) ) + { + nmax = j; + } + } + + /* + * compare + */ + if( nmax!=ae_round(xy->ptr.pp_double[i][nvars], _state) ) + { + result = result+1; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Internal subroutine. Places exponents of the anti-overflow shifted +internal linear outputs into the service part of the W array. +*************************************************************************/ +static void logit_mnliexp(/* Real */ ae_vector* w, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t offs; + ae_int_t i; + ae_int_t i1; + double v; + double mx; + + + ae_assert(ae_fp_eq(w->ptr.p_double[1],(double)(logit_logitvnum)), "LOGIT: unexpected model version", _state); + nvars = ae_round(w->ptr.p_double[2], _state); + nclasses = ae_round(w->ptr.p_double[3], _state); + offs = ae_round(w->ptr.p_double[4], _state); + i1 = offs+(nvars+1)*(nclasses-1); + for(i=0; i<=nclasses-2; i++) + { + v = ae_v_dotproduct(&w->ptr.p_double[offs+i*(nvars+1)], 1, &x->ptr.p_double[0], 1, ae_v_len(offs+i*(nvars+1),offs+i*(nvars+1)+nvars-1)); + w->ptr.p_double[i1+i] = v+w->ptr.p_double[offs+i*(nvars+1)+nvars]; + } + w->ptr.p_double[i1+nclasses-1] = (double)(0); + mx = (double)(0); + for(i=i1; i<=i1+nclasses-1; i++) + { + mx = ae_maxreal(mx, w->ptr.p_double[i], _state); + } + for(i=i1; i<=i1+nclasses-1; i++) + { + w->ptr.p_double[i] = ae_exp(w->ptr.p_double[i]-mx, _state); + } +} + + +/************************************************************************* +Calculation of all types of errors + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +static void logit_mnlallerrors(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double* relcls, + double* avgce, + double* rms, + double* avg, + double* avgrel, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t i; + ae_vector buf; + ae_vector workx; + ae_vector y; + ae_vector dy; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&workx, 0, sizeof(workx)); + memset(&y, 0, sizeof(y)); + memset(&dy, 0, sizeof(dy)); + *relcls = 0.0; + *avgce = 0.0; + *rms = 0.0; + *avg = 0.0; + *avgrel = 0.0; + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&workx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_round(lm->w.ptr.p_double[1], _state)==logit_logitvnum, "MNL unit: Incorrect MNL version!", _state); + nvars = ae_round(lm->w.ptr.p_double[2], _state); + nclasses = ae_round(lm->w.ptr.p_double[3], _state); + ae_vector_set_length(&workx, nvars-1+1, _state); + ae_vector_set_length(&y, nclasses-1+1, _state); + ae_vector_set_length(&dy, 0+1, _state); + dserrallocate(nclasses, &buf, _state); + for(i=0; i<=npoints-1; i++) + { + ae_v_move(&workx.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1)); + mnlprocess(lm, &workx, &y, _state); + dy.ptr.p_double[0] = xy->ptr.pp_double[i][nvars]; + dserraccumulate(&buf, &y, &dy, _state); + } + dserrfinish(&buf, _state); + *relcls = buf.ptr.p_double[0]; + *avgce = buf.ptr.p_double[1]; + *rms = buf.ptr.p_double[2]; + *avg = buf.ptr.p_double[3]; + *avgrel = buf.ptr.p_double[4]; + ae_frame_leave(_state); +} + + +/************************************************************************* +THE PURPOSE OF MCSRCH IS TO FIND A STEP WHICH SATISFIES A SUFFICIENT +DECREASE CONDITION AND A CURVATURE CONDITION. + +AT EACH STAGE THE SUBROUTINE UPDATES AN INTERVAL OF UNCERTAINTY WITH +ENDPOINTS STX AND STY. THE INTERVAL OF UNCERTAINTY IS INITIALLY CHOSEN +SO THAT IT CONTAINS A MINIMIZER OF THE MODIFIED FUNCTION + + F(X+STP*S) - F(X) - FTOL*STP*(GRADF(X)'S). + +IF A STEP IS OBTAINED FOR WHICH THE MODIFIED FUNCTION HAS A NONPOSITIVE +FUNCTION VALUE AND NONNEGATIVE DERIVATIVE, THEN THE INTERVAL OF +UNCERTAINTY IS CHOSEN SO THAT IT CONTAINS A MINIMIZER OF F(X+STP*S). + +THE ALGORITHM IS DESIGNED TO FIND A STEP WHICH SATISFIES THE SUFFICIENT +DECREASE CONDITION + + F(X+STP*S) .LE. F(X) + FTOL*STP*(GRADF(X)'S), + +AND THE CURVATURE CONDITION + + ABS(GRADF(X+STP*S)'S)) .LE. GTOL*ABS(GRADF(X)'S). + +IF FTOL IS LESS THAN GTOL AND IF, FOR EXAMPLE, THE FUNCTION IS BOUNDED +BELOW, THEN THERE IS ALWAYS A STEP WHICH SATISFIES BOTH CONDITIONS. +IF NO STEP CAN BE FOUND WHICH SATISFIES BOTH CONDITIONS, THEN THE +ALGORITHM USUALLY STOPS WHEN ROUNDING ERRORS PREVENT FURTHER PROGRESS. +IN THIS CASE STP ONLY SATISFIES THE SUFFICIENT DECREASE CONDITION. + +PARAMETERS DESCRIPRION + +N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER OF VARIABLES. + +X IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE BASE POINT FOR +THE LINE SEARCH. ON OUTPUT IT CONTAINS X+STP*S. + +F IS A VARIABLE. ON INPUT IT MUST CONTAIN THE VALUE OF F AT X. ON OUTPUT +IT CONTAINS THE VALUE OF F AT X + STP*S. + +G IS AN ARRAY OF LENGTH N. ON INPUT IT MUST CONTAIN THE GRADIENT OF F AT X. +ON OUTPUT IT CONTAINS THE GRADIENT OF F AT X + STP*S. + +S IS AN INPUT ARRAY OF LENGTH N WHICH SPECIFIES THE SEARCH DIRECTION. + +STP IS A NONNEGATIVE VARIABLE. ON INPUT STP CONTAINS AN INITIAL ESTIMATE +OF A SATISFACTORY STEP. ON OUTPUT STP CONTAINS THE FINAL ESTIMATE. + +FTOL AND GTOL ARE NONNEGATIVE INPUT VARIABLES. TERMINATION OCCURS WHEN THE +SUFFICIENT DECREASE CONDITION AND THE DIRECTIONAL DERIVATIVE CONDITION ARE +SATISFIED. + +XTOL IS A NONNEGATIVE INPUT VARIABLE. TERMINATION OCCURS WHEN THE RELATIVE +WIDTH OF THE INTERVAL OF UNCERTAINTY IS AT MOST XTOL. + +STPMIN AND STPMAX ARE NONNEGATIVE INPUT VARIABLES WHICH SPECIFY LOWER AND +UPPER BOUNDS FOR THE STEP. + +MAXFEV IS A POSITIVE INTEGER INPUT VARIABLE. TERMINATION OCCURS WHEN THE +NUMBER OF CALLS TO FCN IS AT LEAST MAXFEV BY THE END OF AN ITERATION. + +INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS: + INFO = 0 IMPROPER INPUT PARAMETERS. + + INFO = 1 THE SUFFICIENT DECREASE CONDITION AND THE + DIRECTIONAL DERIVATIVE CONDITION HOLD. + + INFO = 2 RELATIVE WIDTH OF THE INTERVAL OF UNCERTAINTY + IS AT MOST XTOL. + + INFO = 3 NUMBER OF CALLS TO FCN HAS REACHED MAXFEV. + + INFO = 4 THE STEP IS AT THE LOWER BOUND STPMIN. + + INFO = 5 THE STEP IS AT THE UPPER BOUND STPMAX. + + INFO = 6 ROUNDING ERRORS PREVENT FURTHER PROGRESS. + THERE MAY NOT BE A STEP WHICH SATISFIES THE + SUFFICIENT DECREASE AND CURVATURE CONDITIONS. + TOLERANCES MAY BE TOO SMALL. + +NFEV IS AN INTEGER OUTPUT VARIABLE SET TO THE NUMBER OF CALLS TO FCN. + +WA IS A WORK ARRAY OF LENGTH N. + +ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1983 +JORGE J. MORE', DAVID J. THUENTE +*************************************************************************/ +static void logit_mnlmcsrch(ae_int_t n, + /* Real */ ae_vector* x, + double* f, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* s, + double* stp, + ae_int_t* info, + ae_int_t* nfev, + /* Real */ ae_vector* wa, + logitmcstate* state, + ae_int_t* stage, + ae_state *_state) +{ + double v; + double p5; + double p66; + double zero; + + + + /* + * init + */ + p5 = 0.5; + p66 = 0.66; + state->xtrapf = 4.0; + zero = (double)(0); + + /* + * Main cycle + */ + for(;;) + { + if( *stage==0 ) + { + + /* + * NEXT + */ + *stage = 2; + continue; + } + if( *stage==2 ) + { + state->infoc = 1; + *info = 0; + + /* + * CHECK THE INPUT PARAMETERS FOR ERRORS. + */ + if( ((((((n<=0||ae_fp_less_eq(*stp,(double)(0)))||ae_fp_less(logit_ftol,(double)(0)))||ae_fp_less(logit_gtol,zero))||ae_fp_less(logit_xtol,zero))||ae_fp_less(logit_stpmin,zero))||ae_fp_less(logit_stpmax,logit_stpmin))||logit_maxfev<=0 ) + { + *stage = 0; + return; + } + + /* + * COMPUTE THE INITIAL GRADIENT IN THE SEARCH DIRECTION + * AND CHECK THAT S IS A DESCENT DIRECTION. + */ + v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->dginit = v; + if( ae_fp_greater_eq(state->dginit,(double)(0)) ) + { + *stage = 0; + return; + } + + /* + * INITIALIZE LOCAL VARIABLES. + */ + state->brackt = ae_false; + state->stage1 = ae_true; + *nfev = 0; + state->finit = *f; + state->dgtest = logit_ftol*state->dginit; + state->width = logit_stpmax-logit_stpmin; + state->width1 = state->width/p5; + ae_v_move(&wa->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * THE VARIABLES STX, FX, DGX CONTAIN THE VALUES OF THE STEP, + * FUNCTION, AND DIRECTIONAL DERIVATIVE AT THE BEST STEP. + * THE VARIABLES STY, FY, DGY CONTAIN THE VALUE OF THE STEP, + * FUNCTION, AND DERIVATIVE AT THE OTHER ENDPOINT OF + * THE INTERVAL OF UNCERTAINTY. + * THE VARIABLES STP, F, DG CONTAIN THE VALUES OF THE STEP, + * FUNCTION, AND DERIVATIVE AT THE CURRENT STEP. + */ + state->stx = (double)(0); + state->fx = state->finit; + state->dgx = state->dginit; + state->sty = (double)(0); + state->fy = state->finit; + state->dgy = state->dginit; + + /* + * NEXT + */ + *stage = 3; + continue; + } + if( *stage==3 ) + { + + /* + * START OF ITERATION. + * + * SET THE MINIMUM AND MAXIMUM STEPS TO CORRESPOND + * TO THE PRESENT INTERVAL OF UNCERTAINTY. + */ + if( state->brackt ) + { + if( ae_fp_less(state->stx,state->sty) ) + { + state->stmin = state->stx; + state->stmax = state->sty; + } + else + { + state->stmin = state->sty; + state->stmax = state->stx; + } + } + else + { + state->stmin = state->stx; + state->stmax = *stp+state->xtrapf*(*stp-state->stx); + } + + /* + * FORCE THE STEP TO BE WITHIN THE BOUNDS STPMAX AND STPMIN. + */ + if( ae_fp_greater(*stp,logit_stpmax) ) + { + *stp = logit_stpmax; + } + if( ae_fp_less(*stp,logit_stpmin) ) + { + *stp = logit_stpmin; + } + + /* + * IF AN UNUSUAL TERMINATION IS TO OCCUR THEN LET + * STP BE THE LOWEST POINT OBTAINED SO FAR. + */ + if( (((state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||*nfev>=logit_maxfev-1)||state->infoc==0)||(state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax)) ) + { + *stp = state->stx; + } + + /* + * EVALUATE THE FUNCTION AND GRADIENT AT STP + * AND COMPUTE THE DIRECTIONAL DERIVATIVE. + */ + ae_v_move(&x->ptr.p_double[0], 1, &wa->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&x->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1), *stp); + + /* + * NEXT + */ + *stage = 4; + return; + } + if( *stage==4 ) + { + *info = 0; + *nfev = *nfev+1; + v = ae_v_dotproduct(&g->ptr.p_double[0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->dg = v; + state->ftest1 = state->finit+*stp*state->dgtest; + + /* + * TEST FOR CONVERGENCE. + */ + if( (state->brackt&&(ae_fp_less_eq(*stp,state->stmin)||ae_fp_greater_eq(*stp,state->stmax)))||state->infoc==0 ) + { + *info = 6; + } + if( (ae_fp_eq(*stp,logit_stpmax)&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_less_eq(state->dg,state->dgtest) ) + { + *info = 5; + } + if( ae_fp_eq(*stp,logit_stpmin)&&(ae_fp_greater(*f,state->ftest1)||ae_fp_greater_eq(state->dg,state->dgtest)) ) + { + *info = 4; + } + if( *nfev>=logit_maxfev ) + { + *info = 3; + } + if( state->brackt&&ae_fp_less_eq(state->stmax-state->stmin,logit_xtol*state->stmax) ) + { + *info = 2; + } + if( ae_fp_less_eq(*f,state->ftest1)&&ae_fp_less_eq(ae_fabs(state->dg, _state),-logit_gtol*state->dginit) ) + { + *info = 1; + } + + /* + * CHECK FOR TERMINATION. + */ + if( *info!=0 ) + { + *stage = 0; + return; + } + + /* + * IN THE FIRST STAGE WE SEEK A STEP FOR WHICH THE MODIFIED + * FUNCTION HAS A NONPOSITIVE VALUE AND NONNEGATIVE DERIVATIVE. + */ + if( (state->stage1&&ae_fp_less_eq(*f,state->ftest1))&&ae_fp_greater_eq(state->dg,ae_minreal(logit_ftol, logit_gtol, _state)*state->dginit) ) + { + state->stage1 = ae_false; + } + + /* + * A MODIFIED FUNCTION IS USED TO PREDICT THE STEP ONLY IF + * WE HAVE NOT OBTAINED A STEP FOR WHICH THE MODIFIED + * FUNCTION HAS A NONPOSITIVE FUNCTION VALUE AND NONNEGATIVE + * DERIVATIVE, AND IF A LOWER FUNCTION VALUE HAS BEEN + * OBTAINED BUT THE DECREASE IS NOT SUFFICIENT. + */ + if( (state->stage1&&ae_fp_less_eq(*f,state->fx))&&ae_fp_greater(*f,state->ftest1) ) + { + + /* + * DEFINE THE MODIFIED FUNCTION AND DERIVATIVE VALUES. + */ + state->fm = *f-*stp*state->dgtest; + state->fxm = state->fx-state->stx*state->dgtest; + state->fym = state->fy-state->sty*state->dgtest; + state->dgm = state->dg-state->dgtest; + state->dgxm = state->dgx-state->dgtest; + state->dgym = state->dgy-state->dgtest; + + /* + * CALL CSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY + * AND TO COMPUTE THE NEW STEP. + */ + logit_mnlmcstep(&state->stx, &state->fxm, &state->dgxm, &state->sty, &state->fym, &state->dgym, stp, state->fm, state->dgm, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); + + /* + * RESET THE FUNCTION AND GRADIENT VALUES FOR F. + */ + state->fx = state->fxm+state->stx*state->dgtest; + state->fy = state->fym+state->sty*state->dgtest; + state->dgx = state->dgxm+state->dgtest; + state->dgy = state->dgym+state->dgtest; + } + else + { + + /* + * CALL MCSTEP TO UPDATE THE INTERVAL OF UNCERTAINTY + * AND TO COMPUTE THE NEW STEP. + */ + logit_mnlmcstep(&state->stx, &state->fx, &state->dgx, &state->sty, &state->fy, &state->dgy, stp, *f, state->dg, &state->brackt, state->stmin, state->stmax, &state->infoc, _state); + } + + /* + * FORCE A SUFFICIENT DECREASE IN THE SIZE OF THE + * INTERVAL OF UNCERTAINTY. + */ + if( state->brackt ) + { + if( ae_fp_greater_eq(ae_fabs(state->sty-state->stx, _state),p66*state->width1) ) + { + *stp = state->stx+p5*(state->sty-state->stx); + } + state->width1 = state->width; + state->width = ae_fabs(state->sty-state->stx, _state); + } + + /* + * NEXT. + */ + *stage = 3; + continue; + } + } +} + + +static void logit_mnlmcstep(double* stx, + double* fx, + double* dx, + double* sty, + double* fy, + double* dy, + double* stp, + double fp, + double dp, + ae_bool* brackt, + double stmin, + double stmax, + ae_int_t* info, + ae_state *_state) +{ + ae_bool bound; + double gamma; + double p; + double q; + double r; + double s; + double sgnd; + double stpc; + double stpf; + double stpq; + double theta; + + + *info = 0; + + /* + * CHECK THE INPUT PARAMETERS FOR ERRORS. + */ + if( ((*brackt&&(ae_fp_less_eq(*stp,ae_minreal(*stx, *sty, _state))||ae_fp_greater_eq(*stp,ae_maxreal(*stx, *sty, _state))))||ae_fp_greater_eq(*dx*(*stp-(*stx)),(double)(0)))||ae_fp_less(stmax,stmin) ) + { + return; + } + + /* + * DETERMINE IF THE DERIVATIVES HAVE OPPOSITE SIGN. + */ + sgnd = dp*(*dx/ae_fabs(*dx, _state)); + + /* + * FIRST CASE. A HIGHER FUNCTION VALUE. + * THE MINIMUM IS BRACKETED. IF THE CUBIC STEP IS CLOSER + * TO STX THAN THE QUADRATIC STEP, THE CUBIC STEP IS TAKEN, + * ELSE THE AVERAGE OF THE CUBIC AND QUADRATIC STEPS IS TAKEN. + */ + if( ae_fp_greater(fp,*fx) ) + { + *info = 1; + bound = ae_true; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); + if( ae_fp_less(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-(*dx)+theta; + q = gamma-(*dx)+gamma+dp; + r = p/q; + stpc = *stx+r*(*stp-(*stx)); + stpq = *stx+*dx/((*fx-fp)/(*stp-(*stx))+(*dx))/(double)2*(*stp-(*stx)); + if( ae_fp_less(ae_fabs(stpc-(*stx), _state),ae_fabs(stpq-(*stx), _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpc+(stpq-stpc)/(double)2; + } + *brackt = ae_true; + } + else + { + if( ae_fp_less(sgnd,(double)(0)) ) + { + + /* + * SECOND CASE. A LOWER FUNCTION VALUE AND DERIVATIVES OF + * OPPOSITE SIGN. THE MINIMUM IS BRACKETED. IF THE CUBIC + * STEP IS CLOSER TO STX THAN THE QUADRATIC (SECANT) STEP, + * THE CUBIC STEP IS TAKEN, ELSE THE QUADRATIC STEP IS TAKEN. + */ + *info = 2; + bound = ae_false; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state); + if( ae_fp_greater(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma-dp+gamma+(*dx); + r = p/q; + stpc = *stp+r*(*stx-(*stp)); + stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); + if( ae_fp_greater(ae_fabs(stpc-(*stp), _state),ae_fabs(stpq-(*stp), _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + *brackt = ae_true; + } + else + { + if( ae_fp_less(ae_fabs(dp, _state),ae_fabs(*dx, _state)) ) + { + + /* + * THIRD CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE + * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DECREASES. + * THE CUBIC STEP IS ONLY USED IF THE CUBIC TENDS TO INFINITY + * IN THE DIRECTION OF THE STEP OR IF THE MINIMUM OF THE CUBIC + * IS BEYOND STP. OTHERWISE THE CUBIC STEP IS DEFINED TO BE + * EITHER STPMIN OR STPMAX. THE QUADRATIC (SECANT) STEP IS ALSO + * COMPUTED AND IF THE MINIMUM IS BRACKETED THEN THE THE STEP + * CLOSEST TO STX IS TAKEN, ELSE THE STEP FARTHEST AWAY IS TAKEN. + */ + *info = 3; + bound = ae_true; + theta = (double)3*(*fx-fp)/(*stp-(*stx))+(*dx)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dx, _state), ae_fabs(dp, _state), _state), _state); + + /* + * THE CASE GAMMA = 0 ONLY ARISES IF THE CUBIC DOES NOT TEND + * TO INFINITY IN THE DIRECTION OF THE STEP. + */ + gamma = s*ae_sqrt(ae_maxreal((double)(0), ae_sqr(theta/s, _state)-*dx/s*(dp/s), _state), _state); + if( ae_fp_greater(*stp,*stx) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma+(*dx-dp)+gamma; + r = p/q; + if( ae_fp_less(r,(double)(0))&&ae_fp_neq(gamma,(double)(0)) ) + { + stpc = *stp+r*(*stx-(*stp)); + } + else + { + if( ae_fp_greater(*stp,*stx) ) + { + stpc = stmax; + } + else + { + stpc = stmin; + } + } + stpq = *stp+dp/(dp-(*dx))*(*stx-(*stp)); + if( *brackt ) + { + if( ae_fp_less(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + } + else + { + if( ae_fp_greater(ae_fabs(*stp-stpc, _state),ae_fabs(*stp-stpq, _state)) ) + { + stpf = stpc; + } + else + { + stpf = stpq; + } + } + } + else + { + + /* + * FOURTH CASE. A LOWER FUNCTION VALUE, DERIVATIVES OF THE + * SAME SIGN, AND THE MAGNITUDE OF THE DERIVATIVE DOES + * NOT DECREASE. IF THE MINIMUM IS NOT BRACKETED, THE STEP + * IS EITHER STPMIN OR STPMAX, ELSE THE CUBIC STEP IS TAKEN. + */ + *info = 4; + bound = ae_false; + if( *brackt ) + { + theta = (double)3*(fp-(*fy))/(*sty-(*stp))+(*dy)+dp; + s = ae_maxreal(ae_fabs(theta, _state), ae_maxreal(ae_fabs(*dy, _state), ae_fabs(dp, _state), _state), _state); + gamma = s*ae_sqrt(ae_sqr(theta/s, _state)-*dy/s*(dp/s), _state); + if( ae_fp_greater(*stp,*sty) ) + { + gamma = -gamma; + } + p = gamma-dp+theta; + q = gamma-dp+gamma+(*dy); + r = p/q; + stpc = *stp+r*(*sty-(*stp)); + stpf = stpc; + } + else + { + if( ae_fp_greater(*stp,*stx) ) + { + stpf = stmax; + } + else + { + stpf = stmin; + } + } + } + } + } + + /* + * UPDATE THE INTERVAL OF UNCERTAINTY. THIS UPDATE DOES NOT + * DEPEND ON THE NEW STEP OR THE CASE ANALYSIS ABOVE. + */ + if( ae_fp_greater(fp,*fx) ) + { + *sty = *stp; + *fy = fp; + *dy = dp; + } + else + { + if( ae_fp_less(sgnd,0.0) ) + { + *sty = *stx; + *fy = *fx; + *dy = *dx; + } + *stx = *stp; + *fx = fp; + *dx = dp; + } + + /* + * COMPUTE THE NEW STEP AND SAFEGUARD IT. + */ + stpf = ae_minreal(stmax, stpf, _state); + stpf = ae_maxreal(stmin, stpf, _state); + *stp = stpf; + if( *brackt&&bound ) + { + if( ae_fp_greater(*sty,*stx) ) + { + *stp = ae_minreal(*stx+0.66*(*sty-(*stx)), *stp, _state); + } + else + { + *stp = ae_maxreal(*stx+0.66*(*sty-(*stx)), *stp, _state); + } + } +} + + +void _logitmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + logitmodel *p = (logitmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic); +} + + +void _logitmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + logitmodel *dst = (logitmodel*)_dst; + const logitmodel *src = (const logitmodel*)_src; + ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic); +} + + +void _logitmodel_clear(void* _p) +{ + logitmodel *p = (logitmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->w); +} + + +void _logitmodel_destroy(void* _p) +{ + logitmodel *p = (logitmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->w); +} + + +void _logitmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + logitmcstate *p = (logitmcstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _logitmcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + logitmcstate *dst = (logitmcstate*)_dst; + const logitmcstate *src = (const logitmcstate*)_src; + dst->brackt = src->brackt; + dst->stage1 = src->stage1; + dst->infoc = src->infoc; + dst->dg = src->dg; + dst->dgm = src->dgm; + dst->dginit = src->dginit; + dst->dgtest = src->dgtest; + dst->dgx = src->dgx; + dst->dgxm = src->dgxm; + dst->dgy = src->dgy; + dst->dgym = src->dgym; + dst->finit = src->finit; + dst->ftest1 = src->ftest1; + dst->fm = src->fm; + dst->fx = src->fx; + dst->fxm = src->fxm; + dst->fy = src->fy; + dst->fym = src->fym; + dst->stx = src->stx; + dst->sty = src->sty; + dst->stmin = src->stmin; + dst->stmax = src->stmax; + dst->width = src->width; + dst->width1 = src->width1; + dst->xtrapf = src->xtrapf; +} + + +void _logitmcstate_clear(void* _p) +{ + logitmcstate *p = (logitmcstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _logitmcstate_destroy(void* _p) +{ + logitmcstate *p = (logitmcstate*)_p; + ae_touch_ptr((void*)p); +} + + +void _mnlreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mnlreport *p = (mnlreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mnlreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mnlreport *dst = (mnlreport*)_dst; + const mnlreport *src = (const mnlreport*)_src; + dst->ngrad = src->ngrad; + dst->nhess = src->nhess; +} + + +void _mnlreport_clear(void* _p) +{ + mnlreport *p = (mnlreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mnlreport_destroy(void* _p) +{ + mnlreport *p = (mnlreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel KNN requests. + +KNN subpackage provides two sets of computing functions - ones which use +internal buffer of KNN model (these functions are single-threaded because +they use same buffer, which can not shared between threads), and ones +which use external buffer. + +This function is used to initialize external buffer. + +INPUT PARAMETERS + Model - KNN model which is associated with newly created buffer + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with model which was used to + initialize buffer. Any attempt to use buffer with different + object is dangerous - you may get integrity check failure + (exception) because sizes of internal arrays do not fit to + dimensions of the model structure. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knncreatebuffer(const knnmodel* model, + knnbuffer* buf, + ae_state *_state) +{ + + _knnbuffer_clear(buf); + + if( !model->isdummy ) + { + kdtreecreaterequestbuffer(&model->tree, &buf->treebuf, _state); + } + ae_vector_set_length(&buf->x, model->nvars, _state); + ae_vector_set_length(&buf->y, model->nout, _state); +} + + +/************************************************************************* +This subroutine creates KNNBuilder object which is used to train KNN models. + +By default, new builder stores empty dataset and some reasonable default +settings. At the very least, you should specify dataset prior to building +KNN model. You can also tweak settings of the model construction algorithm +(recommended, although default settings should work well). + +Following actions are mandatory: +* calling knnbuildersetdataset() to specify dataset +* calling knnbuilderbuildknnmodel() to build KNN model using current + dataset and default settings + +Additionally, you may call: +* knnbuildersetnorm() to change norm being used + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildercreate(knnbuilder* s, ae_state *_state) +{ + + _knnbuilder_clear(s); + + + /* + * Empty dataset + */ + s->dstype = -1; + s->npoints = 0; + s->nvars = 0; + s->iscls = ae_false; + s->nout = 1; + + /* + * Default training settings + */ + s->knnnrm = 2; +} + + +/************************************************************************* +Specifies regression problem (one or more continuous output variables are +predicted). There also exists "classification" version of this function. + +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the KNN construction algorithm will be invoked. + +INPUT PARAMETERS: + S - KNN builder object + XY - array[NPoints,NVars+NOut] (note: actual size can be + larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * next NOut elements store values of the dependent + variables + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NOut - number of dependent variables, NOut>=1 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetreg(knnbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nout, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + + /* + * Check parameters + */ + ae_assert(npoints>=1, "knnbuildersetdatasetreg: npoints<1", _state); + ae_assert(nvars>=1, "knnbuildersetdatasetreg: nvars<1", _state); + ae_assert(nout>=1, "knnbuildersetdatasetreg: nout<1", _state); + ae_assert(xy->rows>=npoints, "knnbuildersetdatasetreg: rows(xy)cols>=nvars+nout, "knnbuildersetdatasetreg: cols(xy)dstype = 0; + s->iscls = ae_false; + s->npoints = npoints; + s->nvars = nvars; + s->nout = nout; + rmatrixsetlengthatleast(&s->dsdata, npoints, nvars, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + s->dsdata.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; + } + } + rvectorsetlengthatleast(&s->dsrval, npoints*nout, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nout-1; j++) + { + s->dsrval.ptr.p_double[i*nout+j] = xy->ptr.pp_double[i][nvars+j]; + } + } +} + + +/************************************************************************* +Specifies classification problem (two or more classes are predicted). +There also exists "regression" version of this function. + +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the KNN construction algorithm will be invoked. + +INPUT PARAMETERS: + S - KNN builder object + XY - array[NPoints,NVars+1] (note: actual size can be + larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * next element stores class index, in [0,NClasses) + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetcls(knnbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + + /* + * Check parameters + */ + ae_assert(npoints>=1, "knnbuildersetdatasetcls: npoints<1", _state); + ae_assert(nvars>=1, "knnbuildersetdatasetcls: nvars<1", _state); + ae_assert(nclasses>=2, "knnbuildersetdatasetcls: nclasses<2", _state); + ae_assert(xy->rows>=npoints, "knnbuildersetdatasetcls: rows(xy)cols>=nvars+1, "knnbuildersetdatasetcls: cols(xy)ptr.pp_double[i][nvars], _state); + ae_assert(j>=0&&jiscls = ae_true; + s->dstype = 0; + s->npoints = npoints; + s->nvars = nvars; + s->nout = nclasses; + rmatrixsetlengthatleast(&s->dsdata, npoints, nvars, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + s->dsdata.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; + } + } + ivectorsetlengthatleast(&s->dsival, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + s->dsival.ptr.p_int[i] = ae_round(xy->ptr.pp_double[i][nvars], _state); + } +} + + +/************************************************************************* +This function sets norm type used for neighbor search. + +INPUT PARAMETERS: + S - decision forest builder object + NormType - norm type: + * 0 inf-norm + * 1 1-norm + * 2 Euclidean norm (default) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetnorm(knnbuilder* s, ae_int_t nrmtype, ae_state *_state) +{ + + + ae_assert((nrmtype==0||nrmtype==1)||nrmtype==2, "knnbuildersetnorm: unexpected norm type", _state); + s->knnnrm = nrmtype; +} + + +/************************************************************************* +This subroutine builds KNN model according to current settings, using +dataset internally stored in the builder object. + +The model being built performs inference using Eps-approximate K nearest +neighbors search algorithm, with: +* K=1, Eps=0 corresponding to the "nearest neighbor algorithm" +* K>1, Eps=0 corresponding to the "K nearest neighbors algorithm" +* K>=1, Eps>0 corresponding to "approximate nearest neighbors algorithm" + +An approximate KNN is a good option for high-dimensional datasets (exact +KNN works slowly when dimensions count grows). + +An ALGLIB implementation of kd-trees is used to perform k-nn searches. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - KNN builder object + K - number of neighbors to search for, K>=1 + Eps - approximation factor: + * Eps=0 means that exact kNN search is performed + * Eps>0 means that (1+Eps)-approximate search is performed + +OUTPUT PARAMETERS: + Model - KNN model + Rep - report + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuilderbuildknnmodel(knnbuilder* s, + ae_int_t k, + double eps, + knnmodel* model, + knnreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t nvars; + ae_int_t nout; + ae_int_t npoints; + ae_bool iscls; + ae_matrix xy; + ae_vector tags; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&tags, 0, sizeof(tags)); + _knnmodel_clear(model); + _knnreport_clear(rep); + ae_matrix_init(&xy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tags, 0, DT_INT, _state, ae_true); + + npoints = s->npoints; + nvars = s->nvars; + nout = s->nout; + iscls = s->iscls; + + /* + * Check settings + */ + ae_assert(k>=1, "knnbuilderbuildknnmodel: k<1", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "knnbuilderbuildknnmodel: eps<0", _state); + + /* + * Prepare output + */ + knn_clearreport(rep, _state); + model->nvars = nvars; + model->nout = nout; + model->iscls = iscls; + model->k = k; + model->eps = eps; + model->isdummy = ae_false; + + /* + * Quick exit for empty dataset + */ + if( s->dstype==-1 ) + { + model->isdummy = ae_true; + ae_frame_leave(_state); + return; + } + + /* + * Build kd-tree + */ + if( iscls ) + { + ae_matrix_set_length(&xy, npoints, nvars+1, _state); + ae_vector_set_length(&tags, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + xy.ptr.pp_double[i][j] = s->dsdata.ptr.pp_double[i][j]; + } + xy.ptr.pp_double[i][nvars] = (double)(s->dsival.ptr.p_int[i]); + tags.ptr.p_int[i] = s->dsival.ptr.p_int[i]; + } + kdtreebuildtagged(&xy, &tags, npoints, nvars, 0, s->knnnrm, &model->tree, _state); + } + else + { + ae_matrix_set_length(&xy, npoints, nvars+nout, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + xy.ptr.pp_double[i][j] = s->dsdata.ptr.pp_double[i][j]; + } + for(j=0; j<=nout-1; j++) + { + xy.ptr.pp_double[i][nvars+j] = s->dsrval.ptr.p_double[i*nout+j]; + } + } + kdtreebuild(&xy, npoints, nvars, nout, s->knnnrm, &model->tree, _state); + } + + /* + * Build buffer + */ + knncreatebuffer(model, &model->buffer, _state); + + /* + * Report + */ + knnallerrors(model, &xy, npoints, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Changing search settings of KNN model. + +K and EPS parameters of KNN (AKNN) search are specified during model +construction. However, plain KNN algorithm with Euclidean distance allows +you to change them at any moment. + +NOTE: future versions of KNN model may support advanced versions of KNN, + such as NCA or LMNN. It is possible that such algorithms won't allow + you to change search settings on the fly. If you call this function + for an algorithm which does not support on-the-fly changes, it will + throw an exception. + +INPUT PARAMETERS: + Model - KNN model + K - K>=1, neighbors count + EPS - accuracy of the EPS-approximate NN search. Set to 0.0, if + you want to perform "classic" KNN search. Specify larger + values if you need to speed-up high-dimensional KNN + queries. + +OUTPUT PARAMETERS: + nothing on success, exception on failure + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnrewritekeps(knnmodel* model, + ae_int_t k, + double eps, + ae_state *_state) +{ + + + ae_assert(k>=1, "knnrewritekeps: k<1", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "knnrewritekeps: eps<0", _state); + model->k = k; + model->eps = eps; +} + + +/************************************************************************* +Inference using KNN model. + +See also knnprocess0(), knnprocessi() and knnclassify() for options with a +bit more convenient interface. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + Y - possible preallocated buffer. Reused if long enough. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocess(knnmodel* model, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + knntsprocess(model, &model->buffer, x, y, _state); +} + + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for knnprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnprocess0(knnmodel* model, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nvars; + double result; + + + nvars = model->nvars; + for(i=0; i<=nvars-1; i++) + { + model->buffer.x.ptr.p_double[i] = x->ptr.p_double[i]; + } + knn_processinternal(model, &model->buffer, _state); + result = model->buffer.y.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling knnprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t knnclassify(knnmodel* model, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nvars; + ae_int_t nout; + ae_int_t result; + + + if( !model->iscls ) + { + result = -1; + return result; + } + nvars = model->nvars; + nout = model->nout; + for(i=0; i<=nvars-1; i++) + { + model->buffer.x.ptr.p_double[i] = x->ptr.p_double[i]; + } + knn_processinternal(model, &model->buffer, _state); + result = 0; + for(i=1; i<=nout-1; i++) + { + if( model->buffer.y.ptr.p_double[i]>model->buffer.y.ptr.p_double[result] ) + { + result = i; + } + } + return result; +} + + +/************************************************************************* +'interactive' variant of knnprocess() for languages like Python which +support constructs like "y = knnprocessi(model,x)" and interactive mode of +the interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocessi(knnmodel* model, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + knnprocess(model, x, y, _state); +} + + +/************************************************************************* +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same KNN model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + Model - KNN model + Buf - buffer object, must be allocated specifically for this + model with knncreatebuffer(). + X - input vector, array[NVars] + +OUTPUT PARAMETERS: + Y - result, array[NOut]. Regression estimate when solving + regression task, vector of posterior probabilities for + a classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knntsprocess(const knnmodel* model, + knnbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nvars; + ae_int_t nout; + + + nvars = model->nvars; + nout = model->nout; + for(i=0; i<=nvars-1; i++) + { + buf->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + knn_processinternal(model, buf, _state); + if( y->cntptr.p_double[i] = buf->y.ptr.p_double[i]; + } +} + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrelclserror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + knnreport rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _knnreport_init(&rep, _state, ae_true); + + knnallerrors(model, xy, npoints, &rep, _state); + result = rep.relclserror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/NPoints. + Zero if model solves regression task. + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgce(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + knnreport rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _knnreport_init(&rep, _state, ae_true); + + knnallerrors(model, xy, npoints, &rep, _state); + result = rep.avgce; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +RMS error on the test set. + +Its meaning for regression task is obvious. As for classification problems, +RMS error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrmserror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + knnreport rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _knnreport_init(&rep, _state, ae_true); + + knnallerrors(model, xy, npoints, &rep, _state); + result = rep.rmserror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgerror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + knnreport rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _knnreport_init(&rep, _state, ae_true); + + knnallerrors(model, xy, npoints, &rep, _state); + result = rep.avgerror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Average relative error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average relative error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average relative error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgrelerror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_frame _frame_block; + knnreport rep; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + _knnreport_init(&rep, _state, ae_true); + + knnallerrors(model, xy, npoints, &rep, _state); + result = rep.avgrelerror; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Calculates all kinds of errors for the model in one call. + +INPUT PARAMETERS: + Model - KNN model + XY - test set: + * one row per point + * first NVars columns store independent variables + * depending on problem type: + * next column stores class number in [0,NClasses) - for + classification problems + * next NOut columns store dependent variables - for + regression problems + NPoints - test set size, NPoints>=0 + +OUTPUT PARAMETERS: + Rep - following fields are loaded with errors for both regression + and classification models: + * rep.rmserror - RMS error for the output + * rep.avgerror - average error + * rep.avgrelerror - average relative error + following fields are set only for classification models, + zero for regression ones: + * relclserror - relative classification error, in [0,1] + * avgce - average cross-entropy in bits per dataset entry + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnallerrors(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + knnreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + knnbuffer buf; + ae_vector desiredy; + ae_vector errbuf; + ae_int_t nvars; + ae_int_t nout; + ae_int_t ny; + ae_bool iscls; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&desiredy, 0, sizeof(desiredy)); + memset(&errbuf, 0, sizeof(errbuf)); + _knnreport_clear(rep); + _knnbuffer_init(&buf, _state, ae_true); + ae_vector_init(&desiredy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&errbuf, 0, DT_REAL, _state, ae_true); + + nvars = model->nvars; + nout = model->nout; + iscls = model->iscls; + if( iscls ) + { + ny = 1; + } + else + { + ny = nout; + } + + /* + * Check input + */ + ae_assert(npoints>=0, "knnallerrors: npoints<0", _state); + ae_assert(xy->rows>=npoints, "knnallerrors: rows(xy)cols>=nvars+ny, "knnallerrors: cols(xy)isdummy||npoints==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Process using local buffer + */ + knncreatebuffer(model, &buf, _state); + if( iscls ) + { + dserrallocate(nout, &errbuf, _state); + } + else + { + dserrallocate(-nout, &errbuf, _state); + } + ae_vector_set_length(&desiredy, ny, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + buf.x.ptr.p_double[j] = xy->ptr.pp_double[i][j]; + } + if( iscls ) + { + j = ae_round(xy->ptr.pp_double[i][nvars], _state); + ae_assert(j>=0&&jptr.pp_double[i][nvars+j]; + } + } + knn_processinternal(model, &buf, _state); + dserraccumulate(&errbuf, &buf.y, &desiredy, _state); + } + dserrfinish(&errbuf, _state); + + /* + * Extract results + */ + if( iscls ) + { + rep->relclserror = errbuf.ptr.p_double[0]; + rep->avgce = errbuf.ptr.p_double[1]; + } + rep->rmserror = errbuf.ptr.p_double[2]; + rep->avgerror = errbuf.ptr.p_double[3]; + rep->avgrelerror = errbuf.ptr.p_double[4]; + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnalloc(ae_serializer* s, const knnmodel* model, ae_state *_state) +{ + + + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + if( !model->isdummy ) + { + kdtreealloc(s, &model->tree, _state); + } +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnserialize(ae_serializer* s, + const knnmodel* model, + ae_state *_state) +{ + + + ae_serializer_serialize_int(s, getknnserializationcode(_state), _state); + ae_serializer_serialize_int(s, knn_knnfirstversion, _state); + ae_serializer_serialize_int(s, model->nvars, _state); + ae_serializer_serialize_int(s, model->nout, _state); + ae_serializer_serialize_int(s, model->k, _state); + ae_serializer_serialize_double(s, model->eps, _state); + ae_serializer_serialize_bool(s, model->iscls, _state); + ae_serializer_serialize_bool(s, model->isdummy, _state); + if( !model->isdummy ) + { + kdtreeserialize(s, &model->tree, _state); + } +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnunserialize(ae_serializer* s, knnmodel* model, ae_state *_state) +{ + ae_int_t i0; + ae_int_t i1; + + _knnmodel_clear(model); + + + /* + * check correctness of header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getknnserializationcode(_state), "KNNUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_assert(i1==knn_knnfirstversion, "KNNUnserialize: stream header corrupted", _state); + + /* + * Unserialize data + */ + ae_serializer_unserialize_int(s, &model->nvars, _state); + ae_serializer_unserialize_int(s, &model->nout, _state); + ae_serializer_unserialize_int(s, &model->k, _state); + ae_serializer_unserialize_double(s, &model->eps, _state); + ae_serializer_unserialize_bool(s, &model->iscls, _state); + ae_serializer_unserialize_bool(s, &model->isdummy, _state); + if( !model->isdummy ) + { + kdtreeunserialize(s, &model->tree, _state); + } + + /* + * Prepare local buffer + */ + knncreatebuffer(model, &model->buffer, _state); +} + + +/************************************************************************* +Sets report fields to their default values + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +static void knn_clearreport(knnreport* rep, ae_state *_state) +{ + + + rep->relclserror = (double)(0); + rep->avgce = (double)(0); + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); +} + + +/************************************************************************* +This function processes buf.X and stores result to buf.Y + +INPUT PARAMETERS + Model - KNN model + Buf - processing buffer. + + +IMPORTANT: buffer object should be used only with model which was used to + initialize buffer. Any attempt to use buffer with different + object is dangerous - you may get integrity check failure + (exception) because sizes of internal arrays do not fit to + dimensions of the model structure. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +static void knn_processinternal(const knnmodel* model, + knnbuffer* buf, + ae_state *_state) +{ + ae_int_t nvars; + ae_int_t nout; + ae_bool iscls; + ae_int_t nncnt; + ae_int_t i; + ae_int_t j; + double v; + + + nvars = model->nvars; + nout = model->nout; + iscls = model->iscls; + + /* + * Quick exit if needed + */ + if( model->isdummy ) + { + for(i=0; i<=nout-1; i++) + { + buf->y.ptr.p_double[i] = (double)(0); + } + return; + } + + /* + * Perform request, average results + */ + for(i=0; i<=nout-1; i++) + { + buf->y.ptr.p_double[i] = (double)(0); + } + nncnt = kdtreetsqueryaknn(&model->tree, &buf->treebuf, &buf->x, model->k, ae_true, model->eps, _state); + v = (double)1/coalesce((double)(nncnt), (double)(1), _state); + if( iscls ) + { + kdtreetsqueryresultstags(&model->tree, &buf->treebuf, &buf->tags, _state); + for(i=0; i<=nncnt-1; i++) + { + j = buf->tags.ptr.p_int[i]; + buf->y.ptr.p_double[j] = buf->y.ptr.p_double[j]+v; + } + } + else + { + kdtreetsqueryresultsxy(&model->tree, &buf->treebuf, &buf->xy, _state); + for(i=0; i<=nncnt-1; i++) + { + for(j=0; j<=nout-1; j++) + { + buf->y.ptr.p_double[j] = buf->y.ptr.p_double[j]+v*buf->xy.ptr.pp_double[i][nvars+j]; + } + } + } +} + + +void _knnbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + knnbuffer *p = (knnbuffer*)_p; + ae_touch_ptr((void*)p); + _kdtreerequestbuffer_init(&p->treebuf, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tags, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->xy, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _knnbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + knnbuffer *dst = (knnbuffer*)_dst; + const knnbuffer *src = (const knnbuffer*)_src; + _kdtreerequestbuffer_init_copy(&dst->treebuf, &src->treebuf, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->tags, &src->tags, _state, make_automatic); + ae_matrix_init_copy(&dst->xy, &src->xy, _state, make_automatic); +} + + +void _knnbuffer_clear(void* _p) +{ + knnbuffer *p = (knnbuffer*)_p; + ae_touch_ptr((void*)p); + _kdtreerequestbuffer_clear(&p->treebuf); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->tags); + ae_matrix_clear(&p->xy); +} + + +void _knnbuffer_destroy(void* _p) +{ + knnbuffer *p = (knnbuffer*)_p; + ae_touch_ptr((void*)p); + _kdtreerequestbuffer_destroy(&p->treebuf); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->tags); + ae_matrix_destroy(&p->xy); +} + + +void _knnbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + knnbuilder *p = (knnbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->dsdata, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsrval, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dsival, 0, DT_INT, _state, make_automatic); +} + + +void _knnbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + knnbuilder *dst = (knnbuilder*)_dst; + const knnbuilder *src = (const knnbuilder*)_src; + dst->dstype = src->dstype; + dst->npoints = src->npoints; + dst->nvars = src->nvars; + dst->iscls = src->iscls; + dst->nout = src->nout; + ae_matrix_init_copy(&dst->dsdata, &src->dsdata, _state, make_automatic); + ae_vector_init_copy(&dst->dsrval, &src->dsrval, _state, make_automatic); + ae_vector_init_copy(&dst->dsival, &src->dsival, _state, make_automatic); + dst->knnnrm = src->knnnrm; +} + + +void _knnbuilder_clear(void* _p) +{ + knnbuilder *p = (knnbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->dsdata); + ae_vector_clear(&p->dsrval); + ae_vector_clear(&p->dsival); +} + + +void _knnbuilder_destroy(void* _p) +{ + knnbuilder *p = (knnbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->dsdata); + ae_vector_destroy(&p->dsrval); + ae_vector_destroy(&p->dsival); +} + + +void _knnmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + knnmodel *p = (knnmodel*)_p; + ae_touch_ptr((void*)p); + _kdtree_init(&p->tree, _state, make_automatic); + _knnbuffer_init(&p->buffer, _state, make_automatic); +} + + +void _knnmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + knnmodel *dst = (knnmodel*)_dst; + const knnmodel *src = (const knnmodel*)_src; + dst->nvars = src->nvars; + dst->nout = src->nout; + dst->k = src->k; + dst->eps = src->eps; + dst->iscls = src->iscls; + dst->isdummy = src->isdummy; + _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic); + _knnbuffer_init_copy(&dst->buffer, &src->buffer, _state, make_automatic); +} + + +void _knnmodel_clear(void* _p) +{ + knnmodel *p = (knnmodel*)_p; + ae_touch_ptr((void*)p); + _kdtree_clear(&p->tree); + _knnbuffer_clear(&p->buffer); +} + + +void _knnmodel_destroy(void* _p) +{ + knnmodel *p = (knnmodel*)_p; + ae_touch_ptr((void*)p); + _kdtree_destroy(&p->tree); + _knnbuffer_destroy(&p->buffer); +} + + +void _knnreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + knnreport *p = (knnreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _knnreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + knnreport *dst = (knnreport*)_dst; + const knnreport *src = (const knnreport*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; +} + + +void _knnreport_clear(void* _p) +{ + knnreport *p = (knnreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _knnreport_destroy(void* _p) +{ + knnreport *p = (knnreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Neural network training using modified Levenberg-Marquardt with exact +Hessian calculation and regularization. Subroutine trains neural network +with restarts from random positions. Algorithm is well suited for small +and medium scale problems (hundreds of weights). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -9, if internal matrix inverse subroutine failed + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlm(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + double lmsteptol; + ae_int_t i; + ae_int_t k; + double v; + double e; + double enew; + double xnorm2; + double stepnorm; + ae_vector g; + ae_vector d; + ae_matrix h; + ae_matrix hmod; + ae_matrix z; + ae_bool spd; + double nu; + double lambdav; + double lambdaup; + double lambdadown; + minlbfgsreport internalrep; + minlbfgsstate state; + ae_vector x; + ae_vector y; + ae_vector wbase; + ae_vector wdir; + ae_vector wt; + ae_vector wx; + ae_int_t pass; + ae_vector wbest; + double ebest; + matinvreport invrep; + densesolverreport solverrep; + + ae_frame_make(_state, &_frame_block); + memset(&g, 0, sizeof(g)); + memset(&d, 0, sizeof(d)); + memset(&h, 0, sizeof(h)); + memset(&hmod, 0, sizeof(hmod)); + memset(&z, 0, sizeof(z)); + memset(&internalrep, 0, sizeof(internalrep)); + memset(&state, 0, sizeof(state)); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&wbase, 0, sizeof(wbase)); + memset(&wdir, 0, sizeof(wdir)); + memset(&wt, 0, sizeof(wt)); + memset(&wx, 0, sizeof(wx)); + memset(&wbest, 0, sizeof(wbest)); + memset(&invrep, 0, sizeof(invrep)); + memset(&solverrep, 0, sizeof(solverrep)); + *info = 0; + _mlpreport_clear(rep); + ae_vector_init(&g, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&h, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&hmod, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + _minlbfgsreport_init(&internalrep, _state, ae_true); + _minlbfgsstate_init(&state, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wbase, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wdir, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); + _matinvreport_init(&invrep, _state, ae_true); + _densesolverreport_init(&solverrep, _state, ae_true); + + mlpproperties(network, &nin, &nout, &wcount, _state); + lambdaup = (double)(10); + lambdadown = 0.3; + lmsteptol = 0.001; + + /* + * Test for inputs + */ + if( npoints<=0||restarts<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( mlpissoftmax(network, _state) ) + { + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + decay = ae_maxreal(decay, mlptrain_mindecay, _state); + *info = 2; + + /* + * Initialize data + */ + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + + /* + * General case. + * Prepare task and network. Allocate space. + */ + mlpinitpreprocessor(network, xy, npoints, _state); + ae_vector_set_length(&g, wcount-1+1, _state); + ae_matrix_set_length(&h, wcount-1+1, wcount-1+1, _state); + ae_matrix_set_length(&hmod, wcount-1+1, wcount-1+1, _state); + ae_vector_set_length(&wbase, wcount-1+1, _state); + ae_vector_set_length(&wdir, wcount-1+1, _state); + ae_vector_set_length(&wbest, wcount-1+1, _state); + ae_vector_set_length(&wt, wcount-1+1, _state); + ae_vector_set_length(&wx, wcount-1+1, _state); + ebest = ae_maxrealnumber; + + /* + * Multiple passes + */ + for(pass=1; pass<=restarts; pass++) + { + + /* + * Initialize weights + */ + mlprandomize(network, _state); + + /* + * First stage of the hybrid algorithm: LBFGS + */ + ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + minlbfgscreate(wcount, ae_minint(wcount, 5, _state), &wbase, &state, _state); + minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), ae_maxint(25, wcount, _state), _state); + while(minlbfgsiteration(&state, _state)) + { + + /* + * gradient + */ + ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + mlpgradbatch(network, xy, npoints, &state.f, &state.g, _state); + + /* + * weight decay + */ + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + state.f = state.f+0.5*decay*v; + ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + + /* + * next iteration + */ + rep->ngrad = rep->ngrad+1; + } + minlbfgsresults(&state, &wbase, &internalrep, _state); + ae_v_move(&network->weights.ptr.p_double[0], 1, &wbase.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + + /* + * Second stage of the hybrid algorithm: LM + * + * Initialize H with identity matrix, + * G with gradient, + * E with regularized error. + */ + mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + for(k=0; k<=wcount-1; k++) + { + h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; + } + rep->nhess = rep->nhess+1; + lambdav = 0.001; + nu = (double)(2); + for(;;) + { + + /* + * 1. HMod = H+lambda*I + * 2. Try to solve (H+Lambda*I)*dx = -g. + * Increase lambda if left part is not positive definite. + */ + for(i=0; i<=wcount-1; i++) + { + ae_v_move(&hmod.ptr.pp_double[i][0], 1, &h.ptr.pp_double[i][0], 1, ae_v_len(0,wcount-1)); + hmod.ptr.pp_double[i][i] = hmod.ptr.pp_double[i][i]+lambdav; + } + spd = spdmatrixcholesky(&hmod, wcount, ae_true, _state); + rep->ncholesky = rep->ncholesky+1; + if( !spd ) + { + lambdav = lambdav*lambdaup*nu; + nu = nu*(double)2; + continue; + } + spdmatrixcholeskysolve(&hmod, wcount, ae_true, &g, &wdir, &solverrep, _state); + if( solverrep.terminationtype<0 ) + { + lambdav = lambdav*lambdaup*nu; + nu = nu*(double)2; + continue; + } + ae_v_muld(&wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1), -1.0); + + /* + * Lambda found. + * 1. Save old w in WBase + * 1. Test some stopping criterions + * 2. If error(w+wdir)>error(w), increase lambda + */ + ae_v_add(&network->weights.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + xnorm2 = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + stepnorm = ae_v_dotproduct(&wdir.ptr.p_double[0], 1, &wdir.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + stepnorm = ae_sqrt(stepnorm, _state); + enew = mlperror(network, xy, npoints, _state)+0.5*decay*xnorm2; + if( ae_fp_less(stepnorm,lmsteptol*((double)1+ae_sqrt(xnorm2, _state))) ) + { + break; + } + if( ae_fp_greater(enew,e) ) + { + lambdav = lambdav*lambdaup*nu; + nu = nu*(double)2; + continue; + } + + /* + * Optimize using inv(cholesky(H)) as preconditioner + */ + rmatrixtrinverse(&hmod, wcount, ae_true, ae_false, &invrep, _state); + if( invrep.terminationtype<=0 ) + { + + /* + * if matrix can't be inverted then exit with errors + * TODO: make WCount steps in direction suggested by HMod + */ + *info = -9; + ae_frame_leave(_state); + return; + } + ae_v_move(&wbase.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + for(i=0; i<=wcount-1; i++) + { + wt.ptr.p_double[i] = (double)(0); + } + minlbfgscreatex(wcount, wcount, &wt, 1, 0.0, &state, _state); + minlbfgssetcond(&state, (double)(0), (double)(0), (double)(0), 5, _state); + while(minlbfgsiteration(&state, _state)) + { + + /* + * gradient + */ + for(i=0; i<=wcount-1; i++) + { + v = ae_v_dotproduct(&state.x.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); + network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; + } + mlpgradbatch(network, xy, npoints, &state.f, &g, _state); + for(i=0; i<=wcount-1; i++) + { + state.g.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=wcount-1; i++) + { + v = g.ptr.p_double[i]; + ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); + } + + /* + * weight decay + * grad(x'*x) = A'*(x0+A*t) + */ + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + state.f = state.f+0.5*decay*v; + for(i=0; i<=wcount-1; i++) + { + v = decay*network->weights.ptr.p_double[i]; + ae_v_addd(&state.g.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1), v); + } + + /* + * next iteration + */ + rep->ngrad = rep->ngrad+1; + } + minlbfgsresults(&state, &wt, &internalrep, _state); + + /* + * Accept new position. + * Calculate Hessian + */ + for(i=0; i<=wcount-1; i++) + { + v = ae_v_dotproduct(&wt.ptr.p_double[i], 1, &hmod.ptr.pp_double[i][i], 1, ae_v_len(i,wcount-1)); + network->weights.ptr.p_double[i] = wbase.ptr.p_double[i]+v; + } + mlphessianbatch(network, xy, npoints, &e, &g, &h, _state); + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = e+0.5*decay*v; + ae_v_addd(&g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + for(k=0; k<=wcount-1; k++) + { + h.ptr.pp_double[k][k] = h.ptr.pp_double[k][k]+decay; + } + rep->nhess = rep->nhess+1; + + /* + * Update lambda + */ + lambdav = lambdav*lambdadown; + nu = (double)(2); + } + + /* + * update WBest + */ + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = 0.5*decay*v+mlperror(network, xy, npoints, _state); + if( ae_fp_less(e,ebest) ) + { + ebest = e; + ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + } + } + + /* + * copy WBest to output + */ + ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Neural network training using L-BFGS algorithm with regularization. +Subroutine trains neural network with restarts from random positions. +Algorithm is well suited for problems of any dimensionality (memory +requirements and step complexity are linear by weights number). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + MaxIts - stopping criterion. Algorithm stops after MaxIts + iterations (NOT gradient calculations). Zero MaxIts + means stopping when step is sufficiently small. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlbfgs(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t pass; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_vector w; + ae_vector wbest; + double e; + double v; + double ebest; + minlbfgsreport internalrep; + minlbfgsstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&wbest, 0, sizeof(wbest)); + memset(&internalrep, 0, sizeof(internalrep)); + memset(&state, 0, sizeof(state)); + *info = 0; + _mlpreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); + _minlbfgsreport_init(&internalrep, _state, ae_true); + _minlbfgsstate_init(&state, _state, ae_true); + + + /* + * Test inputs, parse flags, read network geometry + */ + if( ae_fp_eq(wstep,(double)(0))&&maxits==0 ) + { + *info = -8; + ae_frame_leave(_state); + return; + } + if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,(double)(0)))||maxits<0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + mlpproperties(network, &nin, &nout, &wcount, _state); + if( mlpissoftmax(network, _state) ) + { + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + decay = ae_maxreal(decay, mlptrain_mindecay, _state); + *info = 2; + + /* + * Prepare + */ + mlpinitpreprocessor(network, xy, npoints, _state); + ae_vector_set_length(&w, wcount-1+1, _state); + ae_vector_set_length(&wbest, wcount-1+1, _state); + ebest = ae_maxrealnumber; + + /* + * Multiple starts + */ + rep->ncholesky = 0; + rep->nhess = 0; + rep->ngrad = 0; + for(pass=1; pass<=restarts; pass++) + { + + /* + * Process + */ + mlprandomize(network, _state); + ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); + minlbfgssetcond(&state, 0.0, 0.0, wstep, maxits, _state); + while(minlbfgsiteration(&state, _state)) + { + ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + mlpgradnbatch(network, xy, npoints, &state.f, &state.g, _state); + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + state.f = state.f+0.5*decay*v; + ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + rep->ngrad = rep->ngrad+1; + } + minlbfgsresults(&state, &w, &internalrep, _state); + ae_v_move(&network->weights.ptr.p_double[0], 1, &w.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + + /* + * Compare with best + */ + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = mlperrorn(network, xy, npoints, _state)+0.5*decay*v; + if( ae_fp_less(e,ebest) ) + { + ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ebest = e; + } + } + + /* + * The best network + */ + ae_v_move(&network->weights.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Neural network training using early stopping (base algorithm - L-BFGS with +regularization). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + TrnXY - training set + TrnSize - training set size, TrnSize>0 + ValXY - validation set + ValSize - validation set size, ValSize>0 + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts, either: + * strictly positive number - algorithm make specified + number of restarts from random position. + * -1, in which case algorithm makes exactly one run + from the initial state of the network (no randomization). + If you don't know what Restarts to choose, choose one + one the following: + * -1 (deterministic start) + * +1 (one random restart) + * +5 (moderate amount of random restarts) + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1, ...). + * 2, task has been solved, stopping criterion met - + sufficiently small step size. Not expected (we + use EARLY stopping) but possible and not an + error. + * 6, task has been solved, stopping criterion met - + increasing of validation set error. + Rep - training report + +NOTE: + +Algorithm stops if validation set error increases for a long enough or +step size is small enought (there are task where validation set may +decrease for eternity). In any case solution returned corresponds to the +minimum of validation set error. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptraines(multilayerperceptron* network, + /* Real */ const ae_matrix* trnxy, + ae_int_t trnsize, + /* Real */ const ae_matrix* valxy, + ae_int_t valsize, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t pass; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_vector w; + ae_vector wbest; + double e; + double v; + double ebest; + ae_vector wfinal; + double efinal; + ae_int_t itcnt; + ae_int_t itbest; + minlbfgsreport internalrep; + minlbfgsstate state; + double wstep; + ae_bool needrandomization; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&wbest, 0, sizeof(wbest)); + memset(&wfinal, 0, sizeof(wfinal)); + memset(&internalrep, 0, sizeof(internalrep)); + memset(&state, 0, sizeof(state)); + *info = 0; + _mlpreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wbest, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wfinal, 0, DT_REAL, _state, ae_true); + _minlbfgsreport_init(&internalrep, _state, ae_true); + _minlbfgsstate_init(&state, _state, ae_true); + + wstep = 0.001; + + /* + * Test inputs, parse flags, read network geometry + */ + if( ((trnsize<=0||valsize<=0)||(restarts<1&&restarts!=-1))||ae_fp_less(decay,(double)(0)) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( restarts==-1 ) + { + needrandomization = ae_false; + restarts = 1; + } + else + { + needrandomization = ae_true; + } + mlpproperties(network, &nin, &nout, &wcount, _state); + if( mlpissoftmax(network, _state) ) + { + for(i=0; i<=trnsize-1; i++) + { + if( ae_round(trnxy->ptr.pp_double[i][nin], _state)<0||ae_round(trnxy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + for(i=0; i<=valsize-1; i++) + { + if( ae_round(valxy->ptr.pp_double[i][nin], _state)<0||ae_round(valxy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + *info = 2; + + /* + * Prepare + */ + mlpinitpreprocessor(network, trnxy, trnsize, _state); + ae_vector_set_length(&w, wcount-1+1, _state); + ae_vector_set_length(&wbest, wcount-1+1, _state); + ae_vector_set_length(&wfinal, wcount-1+1, _state); + efinal = ae_maxrealnumber; + for(i=0; i<=wcount-1; i++) + { + wfinal.ptr.p_double[i] = (double)(0); + } + + /* + * Multiple starts + */ + rep->ncholesky = 0; + rep->nhess = 0; + rep->ngrad = 0; + for(pass=1; pass<=restarts; pass++) + { + + /* + * Process + */ + if( needrandomization ) + { + mlprandomize(network, _state); + } + ebest = mlperror(network, valxy, valsize, _state); + ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + itbest = 0; + itcnt = 0; + ae_v_move(&w.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + minlbfgscreate(wcount, ae_minint(wcount, 10, _state), &w, &state, _state); + minlbfgssetcond(&state, 0.0, 0.0, wstep, 0, _state); + minlbfgssetxrep(&state, ae_true, _state); + while(minlbfgsiteration(&state, _state)) + { + + /* + * Calculate gradient + */ + if( state.needfg ) + { + ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + mlpgradnbatch(network, trnxy, trnsize, &state.f, &state.g, _state); + v = ae_v_dotproduct(&network->weights.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + state.f = state.f+0.5*decay*v; + ae_v_addd(&state.g.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + rep->ngrad = rep->ngrad+1; + } + + /* + * Validation set + */ + if( state.xupdated ) + { + ae_v_move(&network->weights.ptr.p_double[0], 1, &state.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + e = mlperror(network, valxy, valsize, _state); + if( ae_fp_less(e,ebest) ) + { + ebest = e; + ae_v_move(&wbest.ptr.p_double[0], 1, &network->weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + itbest = itcnt; + } + if( itcnt>30&&ae_fp_greater((double)(itcnt),1.5*(double)itbest) ) + { + *info = 6; + break; + } + itcnt = itcnt+1; + } + } + minlbfgsresults(&state, &w, &internalrep, _state); + + /* + * Compare with final answer + */ + if( ae_fp_less(ebest,efinal) ) + { + ae_v_move(&wfinal.ptr.p_double[0], 1, &wbest.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + efinal = ebest; + } + } + + /* + * The best network + */ + ae_v_move(&network->weights.ptr.p_double[0], 1, &wfinal.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - L-BFGS. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlbfgs(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t foldscount, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state) +{ + + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(cvrep); + + mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_false, wstep, maxits, info, rep, cvrep, _state); +} + + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - Levenberg-Marquardt. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlm(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t foldscount, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state) +{ + + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(cvrep); + + mlptrain_mlpkfoldcvgeneral(network, xy, npoints, decay, restarts, foldscount, ae_true, 0.0, 0, info, rep, cvrep, _state); +} + + +/************************************************************************* +This function estimates generalization error using cross-validation on the +current dataset with current training settings. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. Network is not changed during cross- + validation and is not trained - it is used only as + representative of its architecture. I.e., we estimate + generalization properties of ARCHITECTURE, not some + specific network. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that for each cross-validation + round specified number of random restarts is + performed, with best network being chosen after + training. + * NRestarts=0 is same as NRestarts=1 + FoldsCount - number of folds in k-fold cross-validation: + * 2<=FoldsCount<=size of dataset + * recommended value: 10. + * values larger than dataset size will be silently + truncated down to dataset size + +OUTPUT PARAMETERS: + Rep - structure which contains cross-validation estimates: + * Rep.RelCLSError - fraction of misclassified cases. + * Rep.AvgCE - acerage cross-entropy + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average error + * Rep.AvgRelError - average relative error + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or subset with only one point was given, zeros are returned as + estimates. + +NOTE: this method performs FoldsCount cross-validation rounds, each one + with NRestarts random starts. Thus, FoldsCount*NRestarts networks + are trained in total. + +NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. + +NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError + contain errors in prediction of posterior probabilities. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcv(mlptrainer* s, + const multilayerperceptron* network, + ae_int_t nrestarts, + ae_int_t foldscount, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_shared_pool pooldatacv; + mlpparallelizationcv datacv; + mlpparallelizationcv *sdatacv; + ae_smart_ptr _sdatacv; + ae_matrix cvy; + ae_vector folds; + ae_vector buf; + ae_vector dy; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t rowsize; + ae_int_t ntype; + ae_int_t ttype; + ae_int_t i; + ae_int_t j; + ae_int_t k; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&pooldatacv, 0, sizeof(pooldatacv)); + memset(&datacv, 0, sizeof(datacv)); + memset(&_sdatacv, 0, sizeof(_sdatacv)); + memset(&cvy, 0, sizeof(cvy)); + memset(&folds, 0, sizeof(folds)); + memset(&buf, 0, sizeof(buf)); + memset(&dy, 0, sizeof(dy)); + memset(&rs, 0, sizeof(rs)); + _mlpreport_clear(rep); + ae_shared_pool_init(&pooldatacv, _state, ae_true); + _mlpparallelizationcv_init(&datacv, _state, ae_true); + ae_smart_ptr_init(&_sdatacv, (void**)&sdatacv, ae_false, _state, ae_true); + ae_matrix_init(&cvy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&folds, 0, DT_INT, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + + if( !mlpissoftmax(network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + ae_assert(ntype==ttype, "MLPKFoldCV: type of input network is not similar to network type in trainer object", _state); + ae_assert(s->npoints>=0, "MLPKFoldCV: possible trainer S is not initialized(S.NPoints<0)", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPKFoldCV: number of inputs in trainer is not equal to number of inputs in network", _state); + ae_assert(s->nout==nout, "MLPKFoldCV: number of outputs in trainer is not equal to number of outputs in network", _state); + ae_assert(nrestarts>=0, "MLPKFoldCV: NRestarts<0", _state); + ae_assert(foldscount>=2, "MLPKFoldCV: FoldsCount<2", _state); + if( foldscount>s->npoints ) + { + foldscount = s->npoints; + } + rep->relclserror = (double)(0); + rep->avgce = (double)(0); + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + hqrndrandomize(&rs, _state); + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + if( s->npoints==0||s->npoints==1 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Read network geometry, test parameters + */ + if( s->rcpar ) + { + rowsize = nin+nout; + ae_vector_set_length(&dy, nout, _state); + dserrallocate(-nout, &buf, _state); + } + else + { + rowsize = nin+1; + ae_vector_set_length(&dy, 1, _state); + dserrallocate(nout, &buf, _state); + } + + /* + * Folds + */ + ae_vector_set_length(&folds, s->npoints, _state); + for(i=0; i<=s->npoints-1; i++) + { + folds.ptr.p_int[i] = i*foldscount/s->npoints; + } + for(i=0; i<=s->npoints-2; i++) + { + j = i+hqrnduniformi(&rs, s->npoints-i, _state); + if( j!=i ) + { + k = folds.ptr.p_int[i]; + folds.ptr.p_int[i] = folds.ptr.p_int[j]; + folds.ptr.p_int[j] = k; + } + } + ae_matrix_set_length(&cvy, s->npoints, nout, _state); + + /* + * Initialize SEED-value for shared pool + */ + datacv.ngrad = 0; + mlpcopy(network, &datacv.network, _state); + ae_vector_set_length(&datacv.subset, s->npoints, _state); + ae_vector_set_length(&datacv.xyrow, rowsize, _state); + ae_vector_set_length(&datacv.y, nout, _state); + + /* + * Create shared pool + */ + ae_shared_pool_set_seed(&pooldatacv, &datacv, (ae_int_t)sizeof(datacv), (ae_copy_constructor)_mlpparallelizationcv_init_copy, (ae_destructor)_mlpparallelizationcv_destroy, _state); + + /* + * Parallelization + */ + mlptrain_mthreadcv(s, rowsize, nrestarts, &folds, 0, foldscount, &cvy, &pooldatacv, wcount, _state); + + /* + * Calculate value for NGrad + */ + ae_shared_pool_first_recycled(&pooldatacv, &_sdatacv, _state); + while(sdatacv!=NULL) + { + rep->ngrad = rep->ngrad+sdatacv->ngrad; + ae_shared_pool_next_recycled(&pooldatacv, &_sdatacv, _state); + } + + /* + * Connect of results and calculate cross-validation error + */ + for(i=0; i<=s->npoints-1; i++) + { + if( s->datatype==0 ) + { + ae_v_move(&datacv.xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); + } + if( s->datatype==1 ) + { + sparsegetrow(&s->sparsexy, i, &datacv.xyrow, _state); + } + ae_v_move(&datacv.y.ptr.p_double[0], 1, &cvy.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1)); + if( s->rcpar ) + { + ae_v_move(&dy.ptr.p_double[0], 1, &datacv.xyrow.ptr.p_double[nin], 1, ae_v_len(0,nout-1)); + } + else + { + dy.ptr.p_double[0] = datacv.xyrow.ptr.p_double[nin]; + } + dserraccumulate(&buf, &datacv.y, &dy, _state); + } + dserrfinish(&buf, _state); + rep->relclserror = buf.ptr.p_double[0]; + rep->avgce = buf.ptr.p_double[1]; + rep->rmserror = buf.ptr.p_double[2]; + rep->avgerror = buf.ptr.p_double[3]; + rep->avgrelerror = buf.ptr.p_double[4]; + ae_frame_leave(_state); +} + + +/************************************************************************* +Creation of the network trainer object for regression networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NOut - number of outputs, NOut>=1 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any regression + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainer(ae_int_t nin, + ae_int_t nout, + mlptrainer* s, + ae_state *_state) +{ + + _mlptrainer_clear(s); + + ae_assert(nin>=1, "MLPCreateTrainer: NIn<1.", _state); + ae_assert(nout>=1, "MLPCreateTrainer: NOut<1.", _state); + s->nin = nin; + s->nout = nout; + s->rcpar = ae_true; + s->lbfgsfactor = mlptrain_defaultlbfgsfactor; + s->decay = 1.0E-6; + mlpsetcond(s, (double)(0), 0, _state); + s->datatype = 0; + s->npoints = 0; + mlpsetalgobatch(s, _state); +} + + +/************************************************************************* +Creation of the network trainer object for classification networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any classification + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainercls(ae_int_t nin, + ae_int_t nclasses, + mlptrainer* s, + ae_state *_state) +{ + + _mlptrainer_clear(s); + + ae_assert(nin>=1, "MLPCreateTrainerCls: NIn<1.", _state); + ae_assert(nclasses>=2, "MLPCreateTrainerCls: NClasses<2.", _state); + s->nin = nin; + s->nout = nclasses; + s->rcpar = ae_false; + s->lbfgsfactor = mlptrain_defaultlbfgsfactor; + s->decay = 1.0E-6; + mlpsetcond(s, (double)(0), 0, _state); + s->datatype = 0; + s->npoints = 0; + mlpsetalgobatch(s, _state); +} + + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user. + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. + NPoints - points count, >=0. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdataset(mlptrainer* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + ae_int_t ndim; + ae_int_t i; + ae_int_t j; + + + ae_assert(s->nin>=1, "MLPSetDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); + ae_assert(npoints>=0, "MLPSetDataset: NPoint<0", _state); + ae_assert(npoints<=xy->rows, "MLPSetDataset: invalid size of matrix XY(NPoint more then rows of matrix XY)", _state); + s->datatype = 0; + s->npoints = npoints; + if( npoints==0 ) + { + return; + } + if( s->rcpar ) + { + ae_assert(s->nout>=1, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); + ndim = s->nin+s->nout; + ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); + ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); + } + else + { + ae_assert(s->nout>=2, "MLPSetDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); + ndim = s->nin+1; + ae_assert(ndim<=xy->cols, "MLPSetDataset: invalid size of matrix XY(too few columns in matrix XY).", _state); + ae_assert(apservisfinitematrix(xy, npoints, ndim, _state), "MLPSetDataset: parameter XY contains Infinite or NaN.", _state); + for(i=0; i<=npoints-1; i++) + { + ae_assert(ae_round(xy->ptr.pp_double[i][s->nin], _state)>=0&&ae_round(xy->ptr.pp_double[i][s->nin], _state)nout, "MLPSetDataset: invalid parameter XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); + } + } + rmatrixsetlengthatleast(&s->densexy, npoints, ndim, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=ndim-1; j++) + { + s->densexy.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user (sparse matrix is used to store dataset). + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Any sparse storage format can be used: + Hash-table, CRS... + NPoints - points count, >=0 + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetsparsedataset(mlptrainer* s, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state) +{ + double v; + ae_int_t t0; + ae_int_t t1; + ae_int_t i; + ae_int_t j; + + + + /* + * Check correctness of the data + */ + ae_assert(s->nin>0, "MLPSetSparseDataset: possible parameter S is not initialized or spoiled(S.NIn<=0).", _state); + ae_assert(npoints>=0, "MLPSetSparseDataset: NPoint<0", _state); + ae_assert(npoints<=sparsegetnrows(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(NPoint more then rows of matrix XY)", _state); + if( npoints>0 ) + { + t0 = 0; + t1 = 0; + if( s->rcpar ) + { + ae_assert(s->nout>=1, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NOut<1 for regression).", _state); + ae_assert(s->nin+s->nout<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); + while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) + { + if( inin+s->nout ) + { + ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); + } + } + } + else + { + ae_assert(s->nout>=2, "MLPSetSparseDataset: possible parameter S is not initialized or is spoiled(NClasses<2 for classifier).", _state); + ae_assert(s->nin+1<=sparsegetncols(xy, _state), "MLPSetSparseDataset: invalid size of sparse matrix XY(too few columns in sparse matrix XY).", _state); + while(sparseenumerate(xy, &t0, &t1, &i, &j, &v, _state)) + { + if( inin ) + { + if( j!=s->nin ) + { + ae_assert(ae_isfinite(v, _state), "MLPSetSparseDataset: sparse matrix XY contains Infinite or NaN.", _state); + } + else + { + ae_assert((ae_isfinite(v, _state)&&ae_round(v, _state)>=0)&&ae_round(v, _state)nout, "MLPSetSparseDataset: invalid sparse matrix XY(in classifier used nonexistent class number: either XY[.,NIn]<0 or XY[.,NIn]>=NClasses).", _state); + } + } + } + } + } + + /* + * Set dataset + */ + s->datatype = 1; + s->npoints = npoints; + sparsecopytocrs(xy, &s->sparsexy, _state); +} + + +/************************************************************************* +This function sets weight decay coefficient which is used for training. + +INPUT PARAMETERS: + S - trainer object + Decay - weight decay coefficient, >=0. Weight decay term + 'Decay*||Weights||^2' is added to error function. If + you don't know what Decay to choose, use 1.0E-3. + Weight decay can be set to zero, in this case network + is trained without weight decay. + +NOTE: by default network uses some small nonzero value for weight decay. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state) +{ + + + ae_assert(ae_isfinite(decay, _state), "MLPSetDecay: parameter Decay contains Infinite or NaN.", _state); + ae_assert(ae_fp_greater_eq(decay,(double)(0)), "MLPSetDecay: Decay<0.", _state); + s->decay = decay; +} + + +/************************************************************************* +This function sets stopping criteria for the optimizer. + +INPUT PARAMETERS: + S - trainer object + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + WStep>=0. + MaxIts - stopping criterion. Algorithm stops after MaxIts + epochs (full passes over entire dataset). Zero MaxIts + means stopping when step is sufficiently small. + MaxIts>=0. + +NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also + used when MLPSetCond() is called with WStep=0 and MaxIts=0. + +NOTE: these stopping criteria are used for all kinds of neural training - + from "conventional" networks to early stopping ensembles. When used + for "conventional" networks, they are used as the only stopping + criteria. When combined with early stopping, they used as ADDITIONAL + stopping criteria which can terminate early stopping algorithm. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetcond(mlptrainer* s, + double wstep, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(wstep, _state), "MLPSetCond: parameter WStep contains Infinite or NaN.", _state); + ae_assert(ae_fp_greater_eq(wstep,(double)(0)), "MLPSetCond: WStep<0.", _state); + ae_assert(maxits>=0, "MLPSetCond: MaxIts<0.", _state); + if( ae_fp_neq(wstep,(double)(0))||maxits!=0 ) + { + s->wstep = wstep; + s->maxits = maxits; + } + else + { + s->wstep = 0.005; + s->maxits = 0; + } +} + + +/************************************************************************* +This function sets training algorithm: batch training using L-BFGS will be +used. + +This algorithm: +* the most robust for small-scale problems, but may be too slow for large + scale ones. +* perfoms full pass through the dataset before performing step +* uses conditions specified by MLPSetCond() for stopping +* is default one used by trainer object + +INPUT PARAMETERS: + S - trainer object + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetalgobatch(mlptrainer* s, ae_state *_state) +{ + + + s->algokind = 0; +} + + +/************************************************************************* +This function trains neural network passed to this function, using current +dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) +and current training settings. Training from NRestarts random starting +positions is performed, best network is chosen. + +Training is performed using current training algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed, best network is chosen after + training + * NRestarts=0 means that current state of the network + is used for training. + +OUTPUT PARAMETERS: + Network - trained network + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + network is filled by zero values. Same behavior for functions + MLPStartTraining and MLPContinueTraining. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainnetwork(mlptrainer* s, + multilayerperceptron* network, + ae_int_t nrestarts, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntype; + ae_int_t ttype; + ae_shared_pool trnpool; + + ae_frame_make(_state, &_frame_block); + memset(&trnpool, 0, sizeof(trnpool)); + _mlpreport_clear(rep); + ae_shared_pool_init(&trnpool, _state, ae_true); + + ae_assert(s->npoints>=0, "MLPTrainNetwork: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + if( !mlpissoftmax(network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + ae_assert(ntype==ttype, "MLPTrainNetwork: type of input network is not similar to network type in trainer object", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPTrainNetwork: number of inputs in trainer is not equal to number of inputs in network", _state); + ae_assert(s->nout==nout, "MLPTrainNetwork: number of outputs in trainer is not equal to number of outputs in network", _state); + ae_assert(nrestarts>=0, "MLPTrainNetwork: NRestarts<0.", _state); + + /* + * Train + */ + mlptrain_mlptrainnetworkx(s, nrestarts, -1, &s->subset, -1, &s->subset, 0, network, rep, ae_true, &trnpool, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +After call to this function trainer object remembers network and is ready +to train it. However, no training is performed until first call to +MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() +will advance training progress one iteration further. + +EXAMPLE: + > + > ...initialize network and trainer object.... + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > ...visualize training progress... + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + RandomStart - randomize network before training or not: + * True means that network is randomized and its + initial state (one which was passed to the trainer + object) is lost. + * False means that training is started from the + current state of the network + +OUTPUT PARAMETERS: + Network - neural network which is ready to training (weights are + initialized, preprocessor is initialized using current + training set) + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpstarttraining(mlptrainer* s, + multilayerperceptron* network, + ae_bool randomstart, + ae_state *_state) +{ + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntype; + ae_int_t ttype; + + + ae_assert(s->npoints>=0, "MLPStartTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + if( !mlpissoftmax(network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + ae_assert(ntype==ttype, "MLPStartTraining: type of input network is not similar to network type in trainer object", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPStartTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); + ae_assert(s->nout==nout, "MLPStartTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); + + /* + * Initialize temporaries + */ + mlptrain_initmlptrnsession(network, randomstart, s, &s->session, _state); + + /* + * Train network + */ + mlptrain_mlpstarttrainingx(s, randomstart, -1, &s->subset, -1, &s->session, _state); + + /* + * Update network + */ + mlpcopytunableparameters(&s->session.network, network, _state); +} + + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +This function performs one more iteration of the training and returns +either True (training continues) or False (training stopped). In case True +was returned, Network weights are updated according to the current state +of the optimization progress. In case False was returned, no additional +updates is performed (previous update of the network weights moved us to +the final point, and no additional updates is needed). + +EXAMPLE: + > + > [initialize network and trainer object] + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > [visualize training progress] + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network structure, which is used to store + current state of the training process. + +OUTPUT PARAMETERS: + Network - weights of the neural network are rewritten by the + current approximation. + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + +NOTE: It is expected that Network is the same one which was passed to + MLPStartTraining() function. However, THIS function checks only + following: + * that number of network inputs is consistent with trainer object + settings + * that number of network outputs/classes is consistent with trainer + object settings + * that number of network weights is the same as number of weights in + the network passed to MLPStartTraining() function + Exception is thrown when these conditions are violated. + + It is also expected that you do not change state of the network on + your own - the only party who has right to change network during its + training is a trainer object. Any attempt to interfere with trainer + may lead to unpredictable results. + + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool mlpcontinuetraining(mlptrainer* s, + multilayerperceptron* network, + ae_state *_state) +{ + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntype; + ae_int_t ttype; + ae_bool result; + + + ae_assert(s->npoints>=0, "MLPContinueTraining: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + if( !mlpissoftmax(network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + ae_assert(ntype==ttype, "MLPContinueTraining: type of input network is not similar to network type in trainer object.", _state); + mlpproperties(network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPContinueTraining: number of inputs in trainer is not equal to number of inputs in the network.", _state); + ae_assert(s->nout==nout, "MLPContinueTraining: number of outputs in trainer is not equal to number of outputs in the network.", _state); + result = mlptrain_mlpcontinuetrainingx(s, &s->subset, -1, &s->ngradbatch, &s->session, _state); + if( result ) + { + ae_v_move(&network->weights.ptr.p_double[0], 1, &s->session.network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + } + return result; +} + + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +Modified Levenberg-Marquardt algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglm(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state) +{ + + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(ooberrors); + + mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, 0.0, 0, ae_true, info, rep, ooberrors, _state); +} + + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +L-BFGS algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglbfgs(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state) +{ + + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(ooberrors); + + mlptrain_mlpebagginginternal(ensemble, xy, npoints, decay, restarts, wstep, maxits, ae_false, info, rep, ooberrors, _state); +} + + +/************************************************************************* +Training neural networks ensemble using early stopping. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 6, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpetraines(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_int_t ccount; + ae_int_t pcount; + ae_matrix trnxy; + ae_matrix valxy; + ae_int_t trnsize; + ae_int_t valsize; + ae_int_t tmpinfo; + mlpreport tmprep; + modelerrors moderr; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + + ae_frame_make(_state, &_frame_block); + memset(&trnxy, 0, sizeof(trnxy)); + memset(&valxy, 0, sizeof(valxy)); + memset(&tmprep, 0, sizeof(tmprep)); + memset(&moderr, 0, sizeof(moderr)); + *info = 0; + _mlpreport_clear(rep); + ae_matrix_init(&trnxy, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&valxy, 0, 0, DT_REAL, _state, ae_true); + _mlpreport_init(&tmprep, _state, ae_true); + _modelerrors_init(&moderr, _state, ae_true); + + nin = mlpgetinputscount(&ensemble->network, _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + wcount = mlpgetweightscount(&ensemble->network, _state); + if( (npoints<2||restarts<1)||ae_fp_less(decay,(double)(0)) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( mlpissoftmax(&ensemble->network, _state) ) + { + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + *info = 6; + + /* + * allocate + */ + if( mlpissoftmax(&ensemble->network, _state) ) + { + ccount = nin+1; + pcount = nin; + } + else + { + ccount = nin+nout; + pcount = nin+nout; + } + ae_matrix_set_length(&trnxy, npoints, ccount, _state); + ae_matrix_set_length(&valxy, npoints, ccount, _state); + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + + /* + * train networks + */ + for(k=0; k<=ensemble->ensemblesize-1; k++) + { + + /* + * Split set + */ + do + { + trnsize = 0; + valsize = 0; + for(i=0; i<=npoints-1; i++) + { + if( ae_fp_less(ae_randomreal(_state),0.66) ) + { + + /* + * Assign sample to training set + */ + ae_v_move(&trnxy.ptr.pp_double[trnsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); + trnsize = trnsize+1; + } + else + { + + /* + * Assign sample to validation set + */ + ae_v_move(&valxy.ptr.pp_double[valsize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,ccount-1)); + valsize = valsize+1; + } + } + } + while(!(trnsize!=0&&valsize!=0)); + + /* + * Train + */ + mlptraines(&ensemble->network, &trnxy, trnsize, &valxy, valsize, decay, restarts, &tmpinfo, &tmprep, _state); + if( tmpinfo<0 ) + { + *info = tmpinfo; + ae_frame_leave(_state); + return; + } + + /* + * save results + */ + ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); + ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); + ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); + rep->ngrad = rep->ngrad+tmprep.ngrad; + rep->nhess = rep->nhess+tmprep.nhess; + rep->ncholesky = rep->ncholesky+tmprep.ncholesky; + } + mlpeallerrorsx(ensemble, xy, &ensemble->network.dummysxy, npoints, 0, &ensemble->network.dummyidx, 0, npoints, 0, &ensemble->network.buf, &moderr, _state); + rep->relclserror = moderr.relclserror; + rep->avgce = moderr.avgce; + rep->rmserror = moderr.rmserror; + rep->avgerror = moderr.avgerror; + rep->avgrelerror = moderr.avgrelerror; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function trains neural network ensemble passed to this function using +current dataset and early stopping training algorithm. Each early stopping +round performs NRestarts random restarts (thus, EnsembleSize*NRestarts +training rounds is performed in total). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object; + Ensemble - neural network ensemble. It must have same number of + inputs and outputs/classes as was specified during + creation of the trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed during each ES round; + * NRestarts=0 is silently replaced by 1. + +OUTPUT PARAMETERS: + Ensemble - trained ensemble; + Rep - it contains all type of errors. + +NOTE: this training method uses BOTH early stopping and weight decay! So, + you should select weight decay before starting training just as you + select it before training "conventional" networks. + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or single-point dataset was passed, ensemble is filled by zero + values. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 22.08.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainensemblees(mlptrainer* s, + mlpensemble* ensemble, + ae_int_t nrestarts, + mlpreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t ntype; + ae_int_t ttype; + ae_shared_pool esessions; + sinteger sgrad; + modelerrors tmprep; + + ae_frame_make(_state, &_frame_block); + memset(&esessions, 0, sizeof(esessions)); + memset(&sgrad, 0, sizeof(sgrad)); + memset(&tmprep, 0, sizeof(tmprep)); + _mlpreport_clear(rep); + ae_shared_pool_init(&esessions, _state, ae_true); + _sinteger_init(&sgrad, _state, ae_true); + _modelerrors_init(&tmprep, _state, ae_true); + + ae_assert(s->npoints>=0, "MLPTrainEnsembleES: parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + if( !mlpeissoftmax(ensemble, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + ae_assert(ntype==ttype, "MLPTrainEnsembleES: internal error - type of input network is not similar to network type in trainer object", _state); + nin = mlpgetinputscount(&ensemble->network, _state); + ae_assert(s->nin==nin, "MLPTrainEnsembleES: number of inputs in trainer is not equal to number of inputs in ensemble network", _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + ae_assert(s->nout==nout, "MLPTrainEnsembleES: number of outputs in trainer is not equal to number of outputs in ensemble network", _state); + ae_assert(nrestarts>=0, "MLPTrainEnsembleES: NRestarts<0.", _state); + + /* + * Initialize parameter Rep + */ + rep->relclserror = (double)(0); + rep->avgce = (double)(0); + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + + /* + * Allocate + */ + ivectorsetlengthatleast(&s->subset, s->npoints, _state); + ivectorsetlengthatleast(&s->valsubset, s->npoints, _state); + + /* + * Start training + * + * NOTE: ESessions is not initialized because MLPTrainEnsembleX + * needs uninitialized pool. + */ + sgrad.val = 0; + mlptrain_mlptrainensemblex(s, ensemble, 0, ensemble->ensemblesize, nrestarts, 0, &sgrad, ae_true, &esessions, _state); + rep->ngrad = sgrad.val; + + /* + * Calculate errors. + */ + if( s->datatype==0 ) + { + mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 0, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); + } + if( s->datatype==1 ) + { + mlpeallerrorsx(ensemble, &s->densexy, &s->sparsexy, s->npoints, 1, &ensemble->network.dummyidx, 0, s->npoints, 0, &ensemble->network.buf, &tmprep, _state); + } + rep->relclserror = tmprep.relclserror; + rep->avgce = tmprep.avgce; + rep->rmserror = tmprep.rmserror; + rep->avgerror = tmprep.avgerror; + rep->avgrelerror = tmprep.avgrelerror; + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal cross-validation subroutine +*************************************************************************/ +static void mlptrain_mlpkfoldcvgeneral(const multilayerperceptron* n, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t foldscount, + ae_bool lmalgorithm, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t fold; + ae_int_t j; + ae_int_t k; + multilayerperceptron network; + ae_int_t nin; + ae_int_t nout; + ae_int_t rowlen; + ae_int_t wcount; + ae_int_t nclasses; + ae_int_t tssize; + ae_int_t cvssize; + ae_matrix cvset; + ae_matrix testset; + ae_vector folds; + ae_int_t relcnt; + mlpreport internalrep; + ae_vector x; + ae_vector y; + + ae_frame_make(_state, &_frame_block); + memset(&network, 0, sizeof(network)); + memset(&cvset, 0, sizeof(cvset)); + memset(&testset, 0, sizeof(testset)); + memset(&folds, 0, sizeof(folds)); + memset(&internalrep, 0, sizeof(internalrep)); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(cvrep); + _multilayerperceptron_init(&network, _state, ae_true); + ae_matrix_init(&cvset, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&testset, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&folds, 0, DT_INT, _state, ae_true); + _mlpreport_init(&internalrep, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + + /* + * Read network geometry, test parameters + */ + mlpproperties(n, &nin, &nout, &wcount, _state); + if( mlpissoftmax(n, _state) ) + { + nclasses = nout; + rowlen = nin+1; + } + else + { + nclasses = -nout; + rowlen = nin+nout; + } + if( (npoints<=0||foldscount<2)||foldscount>npoints ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + mlpcopy(n, &network, _state); + + /* + * K-fold out cross-validation. + * First, estimate generalization error + */ + ae_matrix_set_length(&testset, npoints-1+1, rowlen-1+1, _state); + ae_matrix_set_length(&cvset, npoints-1+1, rowlen-1+1, _state); + ae_vector_set_length(&x, nin-1+1, _state); + ae_vector_set_length(&y, nout-1+1, _state); + mlptrain_mlpkfoldsplit(xy, npoints, nclasses, foldscount, ae_false, &folds, _state); + cvrep->relclserror = (double)(0); + cvrep->avgce = (double)(0); + cvrep->rmserror = (double)(0); + cvrep->avgerror = (double)(0); + cvrep->avgrelerror = (double)(0); + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + relcnt = 0; + for(fold=0; fold<=foldscount-1; fold++) + { + + /* + * Separate set + */ + tssize = 0; + cvssize = 0; + for(i=0; i<=npoints-1; i++) + { + if( folds.ptr.p_int[i]==fold ) + { + ae_v_move(&testset.ptr.pp_double[tssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); + tssize = tssize+1; + } + else + { + ae_v_move(&cvset.ptr.pp_double[cvssize][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,rowlen-1)); + cvssize = cvssize+1; + } + } + + /* + * Train on CV training set + */ + if( lmalgorithm ) + { + mlptrainlm(&network, &cvset, cvssize, decay, restarts, info, &internalrep, _state); + } + else + { + mlptrainlbfgs(&network, &cvset, cvssize, decay, restarts, wstep, maxits, info, &internalrep, _state); + } + if( *info<0 ) + { + cvrep->relclserror = (double)(0); + cvrep->avgce = (double)(0); + cvrep->rmserror = (double)(0); + cvrep->avgerror = (double)(0); + cvrep->avgrelerror = (double)(0); + ae_frame_leave(_state); + return; + } + rep->ngrad = rep->ngrad+internalrep.ngrad; + rep->nhess = rep->nhess+internalrep.nhess; + rep->ncholesky = rep->ncholesky+internalrep.ncholesky; + + /* + * Estimate error using CV test set + */ + if( mlpissoftmax(&network, _state) ) + { + + /* + * classification-only code + */ + cvrep->relclserror = cvrep->relclserror+(double)mlpclserror(&network, &testset, tssize, _state); + cvrep->avgce = cvrep->avgce+mlperrorn(&network, &testset, tssize, _state); + } + for(i=0; i<=tssize-1; i++) + { + ae_v_move(&x.ptr.p_double[0], 1, &testset.ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); + mlpprocess(&network, &x, &y, _state); + if( mlpissoftmax(&network, _state) ) + { + + /* + * Classification-specific code + */ + k = ae_round(testset.ptr.pp_double[i][nin], _state); + for(j=0; j<=nout-1; j++) + { + if( j==k ) + { + cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-(double)1, _state); + cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-(double)1, _state); + cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs(y.ptr.p_double[j]-(double)1, _state); + relcnt = relcnt+1; + } + else + { + cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j], _state); + cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j], _state); + } + } + } + else + { + + /* + * Regression-specific code + */ + for(j=0; j<=nout-1; j++) + { + cvrep->rmserror = cvrep->rmserror+ae_sqr(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); + cvrep->avgerror = cvrep->avgerror+ae_fabs(y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j], _state); + if( ae_fp_neq(testset.ptr.pp_double[i][nin+j],(double)(0)) ) + { + cvrep->avgrelerror = cvrep->avgrelerror+ae_fabs((y.ptr.p_double[j]-testset.ptr.pp_double[i][nin+j])/testset.ptr.pp_double[i][nin+j], _state); + relcnt = relcnt+1; + } + } + } + } + } + if( mlpissoftmax(&network, _state) ) + { + cvrep->relclserror = cvrep->relclserror/(double)npoints; + cvrep->avgce = cvrep->avgce/(ae_log((double)(2), _state)*(double)npoints); + } + cvrep->rmserror = ae_sqrt(cvrep->rmserror/(double)(npoints*nout), _state); + cvrep->avgerror = cvrep->avgerror/(double)(npoints*nout); + if( relcnt>0 ) + { + cvrep->avgrelerror = cvrep->avgrelerror/(double)relcnt; + } + *info = 1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Subroutine prepares K-fold split of the training set. + +NOTES: + "NClasses>0" means that we have classification task. + "NClasses<0" means regression task with -NClasses real outputs. +*************************************************************************/ +static void mlptrain_mlpkfoldsplit(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nclasses, + ae_int_t foldscount, + ae_bool stratifiedsplits, + /* Integer */ ae_vector* folds, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_vector_clear(folds); + _hqrndstate_init(&rs, _state, ae_true); + + + /* + * test parameters + */ + ae_assert(npoints>0, "MLPKFoldSplit: wrong NPoints!", _state); + ae_assert(nclasses>1||nclasses<0, "MLPKFoldSplit: wrong NClasses!", _state); + ae_assert(foldscount>=2&&foldscount<=npoints, "MLPKFoldSplit: wrong FoldsCount!", _state); + ae_assert(!stratifiedsplits, "MLPKFoldSplit: stratified splits are not supported!", _state); + + /* + * Folds + */ + hqrndrandomize(&rs, _state); + ae_vector_set_length(folds, npoints-1+1, _state); + for(i=0; i<=npoints-1; i++) + { + folds->ptr.p_int[i] = i*foldscount/npoints; + } + for(i=0; i<=npoints-2; i++) + { + j = i+hqrnduniformi(&rs, npoints-i, _state); + if( j!=i ) + { + k = folds->ptr.p_int[i]; + folds->ptr.p_int[i] = folds->ptr.p_int[j]; + folds->ptr.p_int[j] = k; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine for parallelization function MLPFoldCV. + + +INPUT PARAMETERS: + S - trainer object; + RowSize - row size(eitherNIn+NOut or NIn+1); + NRestarts - number of restarts(>=0); + Folds - cross-validation set; + Fold - the number of first cross-validation(>=0); + DFold - the number of second cross-validation(>=Fold+1); + CVY - parameter which stores the result is returned by network, + training on I-th cross-validation set. + It has to be preallocated. + PoolDataCV- parameter for parallelization. + WCount - number of weights in network, used to make decisions on + parallelization. + +NOTE: There are no checks on the parameters correctness. + + -- ALGLIB -- + Copyright 25.09.2012 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_mthreadcv(mlptrainer* s, + ae_int_t rowsize, + ae_int_t nrestarts, + /* Integer */ const ae_vector* folds, + ae_int_t fold, + ae_int_t dfold, + /* Real */ ae_matrix* cvy, + ae_shared_pool* pooldatacv, + ae_int_t wcount, + ae_state *_state) +{ + ae_frame _frame_block; + mlpparallelizationcv *datacv; + ae_smart_ptr _datacv; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&_datacv, 0, sizeof(_datacv)); + ae_smart_ptr_init(&_datacv, (void**)&datacv, ae_false, _state, ae_true); + + if( fold==dfold-1 ) + { + + /* + * Separate set + */ + ae_shared_pool_retrieve(pooldatacv, &_datacv, _state); + datacv->subsetsize = 0; + for(i=0; i<=s->npoints-1; i++) + { + if( folds->ptr.p_int[i]!=fold ) + { + datacv->subset.ptr.p_int[datacv->subsetsize] = i; + datacv->subsetsize = datacv->subsetsize+1; + } + } + + /* + * Train on CV training set + */ + mlptrain_mlptrainnetworkx(s, nrestarts, -1, &datacv->subset, datacv->subsetsize, &datacv->subset, 0, &datacv->network, &datacv->rep, ae_true, &datacv->trnpool, _state); + datacv->ngrad = datacv->ngrad+datacv->rep.ngrad; + + /* + * Estimate error using CV test set + */ + for(i=0; i<=s->npoints-1; i++) + { + if( folds->ptr.p_int[i]==fold ) + { + if( s->datatype==0 ) + { + ae_v_move(&datacv->xyrow.ptr.p_double[0], 1, &s->densexy.ptr.pp_double[i][0], 1, ae_v_len(0,rowsize-1)); + } + if( s->datatype==1 ) + { + sparsegetrow(&s->sparsexy, i, &datacv->xyrow, _state); + } + mlpprocess(&datacv->network, &datacv->xyrow, &datacv->y, _state); + ae_v_move(&cvy->ptr.pp_double[i][0], 1, &datacv->y.ptr.p_double[0], 1, ae_v_len(0,s->nout-1)); + } + } + ae_shared_pool_recycle(pooldatacv, &_datacv, _state); + } + else + { + ae_assert(foldDFold-1).", _state); + + /* + * We expect that minimum number of iterations before convergence is 100. + * Hence is our approach to evaluation of task complexity. + */ + if( ae_fp_greater_eq((double)ae_maxint(nrestarts, 1, _state)*rmul3((double)(2*wcount), (double)(s->npoints), (double)(100), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_mlptrain_mthreadcv(s,rowsize,nrestarts,folds,fold,dfold,cvy,pooldatacv,wcount, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Split task + */ + mlptrain_mthreadcv(s, rowsize, nrestarts, folds, fold, (fold+dfold)/2, cvy, pooldatacv, wcount, _state); + mlptrain_mthreadcv(s, rowsize, nrestarts, folds, (fold+dfold)/2, dfold, cvy, pooldatacv, wcount, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mlptrain_mthreadcv(mlptrainer* s, + ae_int_t rowsize, + ae_int_t nrestarts, + /* Integer */ const ae_vector* folds, + ae_int_t fold, + ae_int_t dfold, + /* Real */ ae_matrix* cvy, + ae_shared_pool* pooldatacv, + ae_int_t wcount, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function trains neural network passed to this function, using current +dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) +and current training settings. Training from NRestarts random starting +positions is performed, best network is chosen. + +This function is inteded to be used internally. It may be used in several +settings: +* training with ValSubsetSize=0, corresponds to "normal" training with + termination criteria based on S.MaxIts (steps count) and S.WStep (step + size). Training sample is given by TrnSubset/TrnSubsetSize. +* training with ValSubsetSize>0, corresponds to early stopping training + with additional MaxIts/WStep stopping criteria. Training sample is given + by TrnSubset/TrnSubsetSize, validation sample is given by ValSubset/ + ValSubsetSize. + + -- ALGLIB -- + Copyright 13.08.2012 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_mlptrainnetworkx(const mlptrainer* s, + ae_int_t nrestarts, + ae_int_t algokind, + /* Integer */ const ae_vector* trnsubset, + ae_int_t trnsubsetsize, + /* Integer */ const ae_vector* valsubset, + ae_int_t valsubsetsize, + multilayerperceptron* network, + mlpreport* rep, + ae_bool isrootcall, + ae_shared_pool* sessions, + ae_state *_state) +{ + ae_frame _frame_block; + modelerrors modrep; + double eval; + double ebest; + ae_int_t ngradbatch; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t pcount; + ae_int_t itbest; + ae_int_t itcnt; + ae_int_t ntype; + ae_int_t ttype; + ae_bool rndstart; + ae_int_t i; + ae_int_t nr0; + ae_int_t nr1; + mlpreport rep0; + mlpreport rep1; + ae_bool randomizenetwork; + double bestrmserror; + smlptrnsession *psession; + ae_smart_ptr _psession; + + ae_frame_make(_state, &_frame_block); + memset(&modrep, 0, sizeof(modrep)); + memset(&rep0, 0, sizeof(rep0)); + memset(&rep1, 0, sizeof(rep1)); + memset(&_psession, 0, sizeof(_psession)); + _modelerrors_init(&modrep, _state, ae_true); + _mlpreport_init(&rep0, _state, ae_true); + _mlpreport_init(&rep1, _state, ae_true); + ae_smart_ptr_init(&_psession, (void**)&psession, ae_false, _state, ae_true); + + mlpproperties(network, &nin, &nout, &wcount, _state); + + /* + * Process root call + */ + if( isrootcall ) + { + + /* + * Try parallelization + * We expect that minimum number of iterations before convergence is 100. + * Hence is our approach to evaluation of task complexity. + */ + if( ae_fp_greater_eq((double)ae_maxint(nrestarts, 1, _state)*rmul3((double)(2*wcount), (double)(s->npoints), (double)(100), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_mlptrain_mlptrainnetworkx(s,nrestarts,algokind,trnsubset,trnsubsetsize,valsubset,valsubsetsize,network,rep,isrootcall,sessions, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Check correctness of parameters + */ + ae_assert(algokind==0||algokind==-1, "MLPTrainNetworkX: unexpected AlgoKind", _state); + ae_assert(s->npoints>=0, "MLPTrainNetworkX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + if( !mlpissoftmax(network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + ae_assert(ntype==ttype, "MLPTrainNetworkX: internal error - type of the training network is not similar to network type in trainer object", _state); + ae_assert(s->nin==nin, "MLPTrainNetworkX: internal error - number of inputs in trainer is not equal to number of inputs in the training network.", _state); + ae_assert(s->nout==nout, "MLPTrainNetworkX: internal error - number of outputs in trainer is not equal to number of outputs in the training network.", _state); + ae_assert(nrestarts>=0, "MLPTrainNetworkX: internal error - NRestarts<0.", _state); + ae_assert(trnsubset->cnt>=trnsubsetsize, "MLPTrainNetworkX: internal error - parameter TrnSubsetSize more than input subset size(Length(TrnSubset)ptr.p_int[i]>=0&&trnsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter TrnSubset contains incorrect index(TrnSubset[I]<0 or TrnSubset[I]>S.NPoints-1)", _state); + } + ae_assert(valsubset->cnt>=valsubsetsize, "MLPTrainNetworkX: internal error - parameter ValSubsetSize more than input subset size(Length(ValSubset)ptr.p_int[i]>=0&&valsubset->ptr.p_int[i]<=s->npoints-1, "MLPTrainNetworkX: internal error - parameter ValSubset contains incorrect index(ValSubset[I]<0 or ValSubset[I]>S.NPoints-1)", _state); + } + + /* + * Train + */ + randomizenetwork = nrestarts>0; + mlptrain_initmlptrnsessions(network, randomizenetwork, s, sessions, _state); + mlptrain_mlptrainnetworkx(s, nrestarts, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, rep, ae_false, sessions, _state); + + /* + * Choose best network + */ + bestrmserror = ae_maxrealnumber; + ae_shared_pool_first_recycled(sessions, &_psession, _state); + while(psession!=NULL) + { + if( ae_fp_less(psession->bestrmserror,bestrmserror) ) + { + mlpimporttunableparameters(network, &psession->bestparameters, _state); + bestrmserror = psession->bestrmserror; + } + ae_shared_pool_next_recycled(sessions, &_psession, _state); + } + + /* + * Calculate errors + */ + if( s->datatype==0 ) + { + mlpallerrorssubset(network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); + } + if( s->datatype==1 ) + { + mlpallerrorssparsesubset(network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); + } + rep->relclserror = modrep.relclserror; + rep->avgce = modrep.avgce; + rep->rmserror = modrep.rmserror; + rep->avgerror = modrep.avgerror; + rep->avgrelerror = modrep.avgrelerror; + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * Split problem, if we have more than 1 restart + */ + if( nrestarts>=2 ) + { + + /* + * Divide problem with NRestarts into two: NR0 and NR1. + */ + nr0 = nrestarts/2; + nr1 = nrestarts-nr0; + mlptrain_mlptrainnetworkx(s, nr0, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep0, ae_false, sessions, _state); + mlptrain_mlptrainnetworkx(s, nr1, algokind, trnsubset, trnsubsetsize, valsubset, valsubsetsize, network, &rep1, ae_false, sessions, _state); + + /* + * Aggregate results + */ + rep->ngrad = rep0.ngrad+rep1.ngrad; + rep->nhess = rep0.nhess+rep1.nhess; + rep->ncholesky = rep0.ncholesky+rep1.ncholesky; + + /* + * Done :) + */ + ae_frame_leave(_state); + return; + } + + /* + * Execution with NRestarts=1 or NRestarts=0: + * * NRestarts=1 means that network is restarted from random position + * * NRestarts=0 means that network is not randomized + */ + ae_assert(nrestarts==0||nrestarts==1, "MLPTrainNetworkX: internal error", _state); + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + ae_shared_pool_retrieve(sessions, &_psession, _state); + if( ((s->datatype==0||s->datatype==1)&&s->npoints>0)&&trnsubsetsize!=0 ) + { + + /* + * Train network using combination of early stopping and step-size + * and step-count based criteria. Network state with best value of + * validation set error is stored in WBuf0. When validation set is + * zero, most recent state of network is stored. + */ + rndstart = nrestarts!=0; + ngradbatch = 0; + eval = (double)(0); + ebest = (double)(0); + itbest = 0; + itcnt = 0; + mlptrain_mlpstarttrainingx(s, rndstart, algokind, trnsubset, trnsubsetsize, psession, _state); + if( s->datatype==0 ) + { + ebest = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); + } + if( s->datatype==1 ) + { + ebest = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); + } + ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + while(mlptrain_mlpcontinuetrainingx(s, trnsubset, trnsubsetsize, &ngradbatch, psession, _state)) + { + if( s->datatype==0 ) + { + eval = mlperrorsubset(&psession->network, &s->densexy, s->npoints, valsubset, valsubsetsize, _state); + } + if( s->datatype==1 ) + { + eval = mlperrorsparsesubset(&psession->network, &s->sparsexy, s->npoints, valsubset, valsubsetsize, _state); + } + if( ae_fp_less_eq(eval,ebest)||valsubsetsize==0 ) + { + ae_v_move(&psession->wbuf0.ptr.p_double[0], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + ebest = eval; + itbest = itcnt; + } + if( itcnt>30&&ae_fp_greater((double)(itcnt),1.5*(double)itbest) ) + { + break; + } + itcnt = itcnt+1; + } + ae_v_move(&psession->network.weights.ptr.p_double[0], 1, &psession->wbuf0.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + rep->ngrad = ngradbatch; + } + else + { + for(i=0; i<=wcount-1; i++) + { + psession->network.weights.ptr.p_double[i] = (double)(0); + } + } + + /* + * Evaluate network performance and update PSession.BestParameters/BestRMSError + * (if needed). + */ + if( s->datatype==0 ) + { + mlpallerrorssubset(&psession->network, &s->densexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); + } + if( s->datatype==1 ) + { + mlpallerrorssparsesubset(&psession->network, &s->sparsexy, s->npoints, trnsubset, trnsubsetsize, &modrep, _state); + } + if( ae_fp_less(modrep.rmserror,psession->bestrmserror) ) + { + mlpexporttunableparameters(&psession->network, &psession->bestparameters, &pcount, _state); + psession->bestrmserror = modrep.rmserror; + } + + /* + * Move session back to pool + */ + ae_shared_pool_recycle(sessions, &_psession, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mlptrain_mlptrainnetworkx(const mlptrainer* s, + ae_int_t nrestarts, + ae_int_t algokind, + /* Integer */ const ae_vector* trnsubset, + ae_int_t trnsubsetsize, + /* Integer */ const ae_vector* valsubset, + ae_int_t valsubsetsize, + multilayerperceptron* network, + mlpreport* rep, + ae_bool isrootcall, + ae_shared_pool* sessions, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function trains neural network ensemble passed to this function using +current dataset and early stopping training algorithm. Each early stopping +round performs NRestarts random restarts (thus, EnsembleSize*NRestarts +training rounds is performed in total). + + + -- ALGLIB -- + Copyright 22.08.2012 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_mlptrainensemblex(const mlptrainer* s, + mlpensemble* ensemble, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nrestarts, + ae_int_t trainingmethod, + sinteger* ngrad, + ae_bool isrootcall, + ae_shared_pool* esessions, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t pcount; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t trnsubsetsize; + ae_int_t valsubsetsize; + ae_int_t k0; + sinteger ngrad0; + sinteger ngrad1; + mlpetrnsession *psession; + ae_smart_ptr _psession; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&ngrad0, 0, sizeof(ngrad0)); + memset(&ngrad1, 0, sizeof(ngrad1)); + memset(&_psession, 0, sizeof(_psession)); + memset(&rs, 0, sizeof(rs)); + _sinteger_init(&ngrad0, _state, ae_true); + _sinteger_init(&ngrad1, _state, ae_true); + ae_smart_ptr_init(&_psession, (void**)&psession, ae_false, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + + nin = mlpgetinputscount(&ensemble->network, _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + wcount = mlpgetweightscount(&ensemble->network, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + pcount = nin; + } + else + { + pcount = nin+nout; + } + if( nrestarts<=0 ) + { + nrestarts = 1; + } + + /* + * Handle degenerate case + */ + if( s->npoints<2 ) + { + for(i=idx0; i<=idx1-1; i++) + { + for(j=0; j<=wcount-1; j++) + { + ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; + } + for(j=0; j<=pcount-1; j++) + { + ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; + ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 1.0; + } + } + ae_frame_leave(_state); + return; + } + + /* + * Process root call + */ + if( isrootcall ) + { + + /* + * Try parallelization + * We expect that minimum number of iterations before convergence is 100. + * Hence is our approach to evaluation of task complexity. + */ + if( ae_fp_greater_eq((double)(ae_maxint(nrestarts, 1, _state)*(idx1-idx0))*rmul3((double)(2*wcount), (double)(s->npoints), (double)(100), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_mlptrain_mlptrainensemblex(s,ensemble,idx0,idx1,nrestarts,trainingmethod,ngrad,isrootcall,esessions, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Prepare: + * * prepare MLPETrnSessions + * * fill ensemble by zeros (helps to detect errors) + */ + mlptrain_initmlpetrnsessions(&ensemble->network, s, esessions, _state); + for(i=idx0; i<=idx1-1; i++) + { + for(j=0; j<=wcount-1; j++) + { + ensemble->weights.ptr.p_double[i*wcount+j] = 0.0; + } + for(j=0; j<=pcount-1; j++) + { + ensemble->columnmeans.ptr.p_double[i*pcount+j] = 0.0; + ensemble->columnsigmas.ptr.p_double[i*pcount+j] = 0.0; + } + } + + /* + * Train in non-root mode and exit + */ + mlptrain_mlptrainensemblex(s, ensemble, idx0, idx1, nrestarts, trainingmethod, ngrad, ae_false, esessions, _state); + ae_frame_leave(_state); + return; + } + + /* + * Split problem + */ + if( idx1-idx0>=2 ) + { + k0 = (idx1-idx0)/2; + ngrad0.val = 0; + ngrad1.val = 0; + mlptrain_mlptrainensemblex(s, ensemble, idx0, idx0+k0, nrestarts, trainingmethod, &ngrad0, ae_false, esessions, _state); + mlptrain_mlptrainensemblex(s, ensemble, idx0+k0, idx1, nrestarts, trainingmethod, &ngrad1, ae_false, esessions, _state); + ngrad->val = ngrad0.val+ngrad1.val; + ae_frame_leave(_state); + return; + } + + /* + * Retrieve and prepare session + */ + ae_shared_pool_retrieve(esessions, &_psession, _state); + + /* + * Train + */ + hqrndrandomize(&rs, _state); + for(k=idx0; k<=idx1-1; k++) + { + + /* + * Split set + */ + trnsubsetsize = 0; + valsubsetsize = 0; + if( trainingmethod==0 ) + { + do + { + trnsubsetsize = 0; + valsubsetsize = 0; + for(i=0; i<=s->npoints-1; i++) + { + if( ae_fp_less(ae_randomreal(_state),0.66) ) + { + + /* + * Assign sample to training set + */ + psession->trnsubset.ptr.p_int[trnsubsetsize] = i; + trnsubsetsize = trnsubsetsize+1; + } + else + { + + /* + * Assign sample to validation set + */ + psession->valsubset.ptr.p_int[valsubsetsize] = i; + valsubsetsize = valsubsetsize+1; + } + } + } + while(!(trnsubsetsize!=0&&valsubsetsize!=0)); + } + if( trainingmethod==1 ) + { + valsubsetsize = 0; + trnsubsetsize = s->npoints; + for(i=0; i<=s->npoints-1; i++) + { + psession->trnsubset.ptr.p_int[i] = hqrnduniformi(&rs, s->npoints, _state); + } + } + + /* + * Train + */ + mlptrain_mlptrainnetworkx(s, nrestarts, -1, &psession->trnsubset, trnsubsetsize, &psession->valsubset, valsubsetsize, &psession->network, &psession->mlprep, ae_true, &psession->mlpsessions, _state); + ngrad->val = ngrad->val+psession->mlprep.ngrad; + + /* + * Save results + */ + ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &psession->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); + ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcount], 1, &psession->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); + ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcount], 1, &psession->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcount,(k+1)*pcount-1)); + } + + /* + * Recycle session + */ + ae_shared_pool_recycle(esessions, &_psession, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mlptrain_mlptrainensemblex(const mlptrainer* s, + mlpensemble* ensemble, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nrestarts, + ae_int_t trainingmethod, + sinteger* ngrad, + ae_bool isrootcall, + ae_shared_pool* esessions, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTrainingX call, +and then user subsequently calls MLPContinueTrainingX to perform one more +iteration of the training. + +After call to this function trainer object remembers network and is ready +to train it. However, no training is performed until first call to +MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() +will advance traing progress one iteration further. + + + -- ALGLIB -- + Copyright 13.08.2012 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_mlpstarttrainingx(const mlptrainer* s, + ae_bool randomstart, + ae_int_t algokind, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + smlptrnsession* session, + ae_state *_state) +{ + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t ntype; + ae_int_t ttype; + ae_int_t i; + + + + /* + * Check parameters + */ + ae_assert(s->npoints>=0, "MLPStartTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0)", _state); + ae_assert(algokind==0||algokind==-1, "MLPStartTrainingX: unexpected AlgoKind", _state); + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + if( !mlpissoftmax(&session->network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + ae_assert(ntype==ttype, "MLPStartTrainingX: internal error - type of the resulting network is not similar to network type in trainer object", _state); + mlpproperties(&session->network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPStartTrainingX: number of inputs in trainer is not equal to number of inputs in the network.", _state); + ae_assert(s->nout==nout, "MLPStartTrainingX: number of outputs in trainer is not equal to number of outputs in the network.", _state); + ae_assert(subset->cnt>=subsetsize, "MLPStartTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPStartTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1)", _state); + } + + /* + * Prepare session + */ + minlbfgssetcond(&session->optimizer, 0.0, 0.0, s->wstep, s->maxits, _state); + if( s->npoints>0&&subsetsize!=0 ) + { + if( randomstart ) + { + mlprandomize(&session->network, _state); + } + minlbfgsrestartfrom(&session->optimizer, &session->network.weights, _state); + } + else + { + for(i=0; i<=wcount-1; i++) + { + session->network.weights.ptr.p_double[i] = (double)(0); + } + } + if( algokind==-1 ) + { + session->algoused = s->algokind; + if( s->algokind==1 ) + { + session->minibatchsize = s->minibatchsize; + } + } + else + { + session->algoused = 0; + } + hqrndrandomize(&session->generator, _state); + ae_vector_set_length(&session->rstate.ia, 15+1, _state); + ae_vector_set_length(&session->rstate.ra, 1+1, _state); + session->rstate.stage = -1; +} + + +/************************************************************************* +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTrainingX call, +and then user subsequently calls MLPContinueTrainingX to perform one more +iteration of the training. + +This function performs one more iteration of the training and returns +either True (training continues) or False (training stopped). In case True +was returned, Network weights are updated according to the current state +of the optimization progress. In case False was returned, no additional +updates is performed (previous update of the network weights moved us to +the final point, and no additional updates is needed). + +EXAMPLE: + > + > [initialize network and trainer object] + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > [visualize training progress] + > + + + -- ALGLIB -- + Copyright 13.08.2012 by Bochkanov Sergey +*************************************************************************/ +static ae_bool mlptrain_mlpcontinuetrainingx(const mlptrainer* s, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_int_t* ngradbatch, + smlptrnsession* session, + ae_state *_state) +{ + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t twcount; + ae_int_t ntype; + ae_int_t ttype; + double decay; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t trnsetsize; + ae_int_t epoch; + ae_int_t minibatchcount; + ae_int_t minibatchidx; + ae_int_t cursize; + ae_int_t idx0; + ae_int_t idx1; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( session->rstate.stage>=0 ) + { + nin = session->rstate.ia.ptr.p_int[0]; + nout = session->rstate.ia.ptr.p_int[1]; + wcount = session->rstate.ia.ptr.p_int[2]; + twcount = session->rstate.ia.ptr.p_int[3]; + ntype = session->rstate.ia.ptr.p_int[4]; + ttype = session->rstate.ia.ptr.p_int[5]; + i = session->rstate.ia.ptr.p_int[6]; + j = session->rstate.ia.ptr.p_int[7]; + k = session->rstate.ia.ptr.p_int[8]; + trnsetsize = session->rstate.ia.ptr.p_int[9]; + epoch = session->rstate.ia.ptr.p_int[10]; + minibatchcount = session->rstate.ia.ptr.p_int[11]; + minibatchidx = session->rstate.ia.ptr.p_int[12]; + cursize = session->rstate.ia.ptr.p_int[13]; + idx0 = session->rstate.ia.ptr.p_int[14]; + idx1 = session->rstate.ia.ptr.p_int[15]; + decay = session->rstate.ra.ptr.p_double[0]; + v = session->rstate.ra.ptr.p_double[1]; + } + else + { + nin = 359; + nout = -58; + wcount = -919; + twcount = -909; + ntype = 81; + ttype = 255; + i = 74; + j = -788; + k = 809; + trnsetsize = 205; + epoch = -838; + minibatchcount = 939; + minibatchidx = -526; + cursize = 763; + idx0 = -541; + idx1 = -698; + decay = -900.0; + v = -318.0; + } + if( session->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + + /* + * Check correctness of inputs + */ + ae_assert(s->npoints>=0, "MLPContinueTrainingX: internal error - parameter S is not initialized or is spoiled(S.NPoints<0).", _state); + if( s->rcpar ) + { + ttype = 0; + } + else + { + ttype = 1; + } + if( !mlpissoftmax(&session->network, _state) ) + { + ntype = 0; + } + else + { + ntype = 1; + } + ae_assert(ntype==ttype, "MLPContinueTrainingX: internal error - type of the resulting network is not similar to network type in trainer object.", _state); + mlpproperties(&session->network, &nin, &nout, &wcount, _state); + ae_assert(s->nin==nin, "MLPContinueTrainingX: internal error - number of inputs in trainer is not equal to number of inputs in the network.", _state); + ae_assert(s->nout==nout, "MLPContinueTrainingX: internal error - number of outputs in trainer is not equal to number of outputs in the network.", _state); + ae_assert(subset->cnt>=subsetsize, "MLPContinueTrainingX: internal error - parameter SubsetSize more than input subset size(Length(Subset)ptr.p_int[i]>=0&&subset->ptr.p_int[i]<=s->npoints-1, "MLPContinueTrainingX: internal error - parameter Subset contains incorrect index(Subset[I]<0 or Subset[I]>S.NPoints-1).", _state); + } + + /* + * Quick exit on empty training set + */ + if( s->npoints==0||subsetsize==0 ) + { + result = ae_false; + return result; + } + + /* + * Minibatch training + */ + if( session->algoused==1 ) + { + ae_assert(ae_false, "MINIBATCH TRAINING IS NOT IMPLEMENTED YET", _state); + } + + /* + * Last option: full batch training + */ + decay = s->decay; +lbl_1: + if( !minlbfgsiteration(&session->optimizer, _state) ) + { + goto lbl_2; + } + if( !session->optimizer.xupdated ) + { + goto lbl_3; + } + ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + session->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: +lbl_3: + ae_v_move(&session->network.weights.ptr.p_double[0], 1, &session->optimizer.x.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + if( s->datatype==0 ) + { + mlpgradbatchsubset(&session->network, &s->densexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); + } + if( s->datatype==1 ) + { + mlpgradbatchsparsesubset(&session->network, &s->sparsexy, s->npoints, subset, subsetsize, &session->optimizer.f, &session->optimizer.g, _state); + } + + /* + * Increment number of operations performed on batch gradient + */ + *ngradbatch = *ngradbatch+1; + v = ae_v_dotproduct(&session->network.weights.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1)); + session->optimizer.f = session->optimizer.f+0.5*decay*v; + ae_v_addd(&session->optimizer.g.ptr.p_double[0], 1, &session->network.weights.ptr.p_double[0], 1, ae_v_len(0,wcount-1), decay); + goto lbl_1; +lbl_2: + minlbfgsresultsbuf(&session->optimizer, &session->network.weights, &session->optimizerrep, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + session->rstate.ia.ptr.p_int[0] = nin; + session->rstate.ia.ptr.p_int[1] = nout; + session->rstate.ia.ptr.p_int[2] = wcount; + session->rstate.ia.ptr.p_int[3] = twcount; + session->rstate.ia.ptr.p_int[4] = ntype; + session->rstate.ia.ptr.p_int[5] = ttype; + session->rstate.ia.ptr.p_int[6] = i; + session->rstate.ia.ptr.p_int[7] = j; + session->rstate.ia.ptr.p_int[8] = k; + session->rstate.ia.ptr.p_int[9] = trnsetsize; + session->rstate.ia.ptr.p_int[10] = epoch; + session->rstate.ia.ptr.p_int[11] = minibatchcount; + session->rstate.ia.ptr.p_int[12] = minibatchidx; + session->rstate.ia.ptr.p_int[13] = cursize; + session->rstate.ia.ptr.p_int[14] = idx0; + session->rstate.ia.ptr.p_int[15] = idx1; + session->rstate.ra.ptr.p_double[0] = decay; + session->rstate.ra.ptr.p_double[1] = v; + return result; +} + + +/************************************************************************* +Internal bagging subroutine. + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_mlpebagginginternal(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_bool lmalgorithm, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xys; + ae_vector s; + ae_matrix oobbuf; + ae_vector oobcntbuf; + ae_vector x; + ae_vector y; + ae_vector dy; + ae_vector dsbuf; + ae_int_t ccnt; + ae_int_t pcnt; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + mlpreport tmprep; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&xys, 0, sizeof(xys)); + memset(&s, 0, sizeof(s)); + memset(&oobbuf, 0, sizeof(oobbuf)); + memset(&oobcntbuf, 0, sizeof(oobcntbuf)); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&dy, 0, sizeof(dy)); + memset(&dsbuf, 0, sizeof(dsbuf)); + memset(&tmprep, 0, sizeof(tmprep)); + memset(&rs, 0, sizeof(rs)); + *info = 0; + _mlpreport_clear(rep); + _mlpcvreport_clear(ooberrors); + ae_matrix_init(&xys, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_BOOL, _state, ae_true); + ae_matrix_init(&oobbuf, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&oobcntbuf, 0, DT_INT, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dsbuf, 0, DT_REAL, _state, ae_true); + _mlpreport_init(&tmprep, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + + nin = mlpgetinputscount(&ensemble->network, _state); + nout = mlpgetoutputscount(&ensemble->network, _state); + wcount = mlpgetweightscount(&ensemble->network, _state); + + /* + * Test for inputs + */ + if( (!lmalgorithm&&ae_fp_eq(wstep,(double)(0)))&&maxits==0 ) + { + *info = -8; + ae_frame_leave(_state); + return; + } + if( ((npoints<=0||restarts<1)||ae_fp_less(wstep,(double)(0)))||maxits<0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( mlpissoftmax(&ensemble->network, _state) ) + { + for(i=0; i<=npoints-1; i++) + { + if( ae_round(xy->ptr.pp_double[i][nin], _state)<0||ae_round(xy->ptr.pp_double[i][nin], _state)>=nout ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + } + + /* + * allocate temporaries + */ + *info = 2; + rep->ngrad = 0; + rep->nhess = 0; + rep->ncholesky = 0; + ooberrors->relclserror = (double)(0); + ooberrors->avgce = (double)(0); + ooberrors->rmserror = (double)(0); + ooberrors->avgerror = (double)(0); + ooberrors->avgrelerror = (double)(0); + if( mlpissoftmax(&ensemble->network, _state) ) + { + ccnt = nin+1; + pcnt = nin; + } + else + { + ccnt = nin+nout; + pcnt = nin+nout; + } + ae_matrix_set_length(&xys, npoints, ccnt, _state); + ae_vector_set_length(&s, npoints, _state); + ae_matrix_set_length(&oobbuf, npoints, nout, _state); + ae_vector_set_length(&oobcntbuf, npoints, _state); + ae_vector_set_length(&x, nin, _state); + ae_vector_set_length(&y, nout, _state); + if( mlpissoftmax(&ensemble->network, _state) ) + { + ae_vector_set_length(&dy, 1, _state); + } + else + { + ae_vector_set_length(&dy, nout, _state); + } + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nout-1; j++) + { + oobbuf.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=npoints-1; i++) + { + oobcntbuf.ptr.p_int[i] = 0; + } + + /* + * main bagging cycle + */ + hqrndrandomize(&rs, _state); + for(k=0; k<=ensemble->ensemblesize-1; k++) + { + + /* + * prepare dataset + */ + for(i=0; i<=npoints-1; i++) + { + s.ptr.p_bool[i] = ae_false; + } + for(i=0; i<=npoints-1; i++) + { + j = hqrnduniformi(&rs, npoints, _state); + s.ptr.p_bool[j] = ae_true; + ae_v_move(&xys.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[j][0], 1, ae_v_len(0,ccnt-1)); + } + + /* + * train + */ + if( lmalgorithm ) + { + mlptrainlm(&ensemble->network, &xys, npoints, decay, restarts, info, &tmprep, _state); + } + else + { + mlptrainlbfgs(&ensemble->network, &xys, npoints, decay, restarts, wstep, maxits, info, &tmprep, _state); + } + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * save results + */ + rep->ngrad = rep->ngrad+tmprep.ngrad; + rep->nhess = rep->nhess+tmprep.nhess; + rep->ncholesky = rep->ncholesky+tmprep.ncholesky; + ae_v_move(&ensemble->weights.ptr.p_double[k*wcount], 1, &ensemble->network.weights.ptr.p_double[0], 1, ae_v_len(k*wcount,(k+1)*wcount-1)); + ae_v_move(&ensemble->columnmeans.ptr.p_double[k*pcnt], 1, &ensemble->network.columnmeans.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); + ae_v_move(&ensemble->columnsigmas.ptr.p_double[k*pcnt], 1, &ensemble->network.columnsigmas.ptr.p_double[0], 1, ae_v_len(k*pcnt,(k+1)*pcnt-1)); + + /* + * OOB estimates + */ + for(i=0; i<=npoints-1; i++) + { + if( !s.ptr.p_bool[i] ) + { + ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nin-1)); + mlpprocess(&ensemble->network, &x, &y, _state); + ae_v_add(&oobbuf.ptr.pp_double[i][0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,nout-1)); + oobcntbuf.ptr.p_int[i] = oobcntbuf.ptr.p_int[i]+1; + } + } + } + + /* + * OOB estimates + */ + if( mlpissoftmax(&ensemble->network, _state) ) + { + dserrallocate(nout, &dsbuf, _state); + } + else + { + dserrallocate(-nout, &dsbuf, _state); + } + for(i=0; i<=npoints-1; i++) + { + if( oobcntbuf.ptr.p_int[i]!=0 ) + { + v = (double)1/(double)oobcntbuf.ptr.p_int[i]; + ae_v_moved(&y.ptr.p_double[0], 1, &oobbuf.ptr.pp_double[i][0], 1, ae_v_len(0,nout-1), v); + if( mlpissoftmax(&ensemble->network, _state) ) + { + dy.ptr.p_double[0] = xy->ptr.pp_double[i][nin]; + } + else + { + ae_v_moved(&dy.ptr.p_double[0], 1, &xy->ptr.pp_double[i][nin], 1, ae_v_len(0,nout-1), v); + } + dserraccumulate(&dsbuf, &y, &dy, _state); + } + } + dserrfinish(&dsbuf, _state); + ooberrors->relclserror = dsbuf.ptr.p_double[0]; + ooberrors->avgce = dsbuf.ptr.p_double[1]; + ooberrors->rmserror = dsbuf.ptr.p_double[2]; + ooberrors->avgerror = dsbuf.ptr.p_double[3]; + ooberrors->avgrelerror = dsbuf.ptr.p_double[4]; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function initializes temporaries needed for training session. + + + -- ALGLIB -- + Copyright 01.07.2013 by Bochkanov Sergey +*************************************************************************/ +static void mlptrain_initmlptrnsession(const multilayerperceptron* networktrained, + ae_bool randomizenetwork, + const mlptrainer* trainer, + smlptrnsession* session, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nin; + ae_int_t nout; + ae_int_t wcount; + ae_int_t pcount; + ae_vector dummysubset; + + ae_frame_make(_state, &_frame_block); + memset(&dummysubset, 0, sizeof(dummysubset)); + ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); + + + /* + * Prepare network: + * * copy input network to Session.Network + * * re-initialize preprocessor and weights if RandomizeNetwork=True + */ + mlpcopy(networktrained, &session->network, _state); + if( randomizenetwork ) + { + ae_assert(trainer->datatype==0||trainer->datatype==1, "InitTemporaries: unexpected Trainer.DataType", _state); + if( trainer->datatype==0 ) + { + mlpinitpreprocessorsubset(&session->network, &trainer->densexy, trainer->npoints, &dummysubset, -1, _state); + } + if( trainer->datatype==1 ) + { + mlpinitpreprocessorsparsesubset(&session->network, &trainer->sparsexy, trainer->npoints, &dummysubset, -1, _state); + } + mlprandomize(&session->network, _state); + session->randomizenetwork = ae_true; + } + else + { + session->randomizenetwork = ae_false; + } + + /* + * Determine network geometry and initialize optimizer + */ + mlpproperties(&session->network, &nin, &nout, &wcount, _state); + minlbfgscreate(wcount, ae_minint(wcount, trainer->lbfgsfactor, _state), &session->network.weights, &session->optimizer, _state); + minlbfgssetxrep(&session->optimizer, ae_true, _state); + + /* + * Create buffers + */ + ae_vector_set_length(&session->wbuf0, wcount, _state); + ae_vector_set_length(&session->wbuf1, wcount, _state); + + /* + * Initialize session result + */ + mlpexporttunableparameters(&session->network, &session->bestparameters, &pcount, _state); + session->bestrmserror = ae_maxrealnumber; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function initializes temporaries needed for training session. + +*************************************************************************/ +static void mlptrain_initmlptrnsessions(const multilayerperceptron* networktrained, + ae_bool randomizenetwork, + const mlptrainer* trainer, + ae_shared_pool* sessions, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector dummysubset; + smlptrnsession t; + smlptrnsession *p; + ae_smart_ptr _p; + + ae_frame_make(_state, &_frame_block); + memset(&dummysubset, 0, sizeof(dummysubset)); + memset(&t, 0, sizeof(t)); + memset(&_p, 0, sizeof(_p)); + ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); + _smlptrnsession_init(&t, _state, ae_true); + ae_smart_ptr_init(&_p, (void**)&p, ae_false, _state, ae_true); + + if( ae_shared_pool_is_initialized(sessions) ) + { + + /* + * Pool was already initialized. + * Clear sessions stored in the pool. + */ + ae_shared_pool_first_recycled(sessions, &_p, _state); + while(p!=NULL) + { + ae_assert(mlpsamearchitecture(&p->network, networktrained, _state), "InitMLPTrnSessions: internal consistency error", _state); + p->bestrmserror = ae_maxrealnumber; + ae_shared_pool_next_recycled(sessions, &_p, _state); + } + } + else + { + + /* + * Prepare session and seed pool + */ + mlptrain_initmlptrnsession(networktrained, randomizenetwork, trainer, &t, _state); + ae_shared_pool_set_seed(sessions, &t, (ae_int_t)sizeof(t), (ae_copy_constructor)_smlptrnsession_init_copy, (ae_destructor)_smlptrnsession_destroy, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function initializes temporaries needed for ensemble training. + +*************************************************************************/ +static void mlptrain_initmlpetrnsession(const multilayerperceptron* individualnetwork, + const mlptrainer* trainer, + mlpetrnsession* session, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector dummysubset; + + ae_frame_make(_state, &_frame_block); + memset(&dummysubset, 0, sizeof(dummysubset)); + ae_vector_init(&dummysubset, 0, DT_INT, _state, ae_true); + + + /* + * Prepare network: + * * copy input network to Session.Network + * * re-initialize preprocessor and weights if RandomizeNetwork=True + */ + mlpcopy(individualnetwork, &session->network, _state); + mlptrain_initmlptrnsessions(individualnetwork, ae_true, trainer, &session->mlpsessions, _state); + ivectorsetlengthatleast(&session->trnsubset, trainer->npoints, _state); + ivectorsetlengthatleast(&session->valsubset, trainer->npoints, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function initializes temporaries needed for training session. + +*************************************************************************/ +static void mlptrain_initmlpetrnsessions(const multilayerperceptron* individualnetwork, + const mlptrainer* trainer, + ae_shared_pool* sessions, + ae_state *_state) +{ + ae_frame _frame_block; + mlpetrnsession t; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + _mlpetrnsession_init(&t, _state, ae_true); + + if( !ae_shared_pool_is_initialized(sessions) ) + { + mlptrain_initmlpetrnsession(individualnetwork, trainer, &t, _state); + ae_shared_pool_set_seed(sessions, &t, (ae_int_t)sizeof(t), (ae_copy_constructor)_mlpetrnsession_init_copy, (ae_destructor)_mlpetrnsession_destroy, _state); + } + ae_frame_leave(_state); +} + + +void _mlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpreport *p = (mlpreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mlpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpreport *dst = (mlpreport*)_dst; + const mlpreport *src = (const mlpreport*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->ngrad = src->ngrad; + dst->nhess = src->nhess; + dst->ncholesky = src->ncholesky; +} + + +void _mlpreport_clear(void* _p) +{ + mlpreport *p = (mlpreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mlpreport_destroy(void* _p) +{ + mlpreport *p = (mlpreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mlpcvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpcvreport *p = (mlpcvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mlpcvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpcvreport *dst = (mlpcvreport*)_dst; + const mlpcvreport *src = (const mlpcvreport*)_src; + dst->relclserror = src->relclserror; + dst->avgce = src->avgce; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; +} + + +void _mlpcvreport_clear(void* _p) +{ + mlpcvreport *p = (mlpcvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mlpcvreport_destroy(void* _p) +{ + mlpcvreport *p = (mlpcvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _smlptrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + smlptrnsession *p = (smlptrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->bestparameters, 0, DT_REAL, _state, make_automatic); + _multilayerperceptron_init(&p->network, _state, make_automatic); + _minlbfgsstate_init(&p->optimizer, _state, make_automatic); + _minlbfgsreport_init(&p->optimizerrep, _state, make_automatic); + ae_vector_init(&p->wbuf0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wbuf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->allminibatches, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->currentminibatch, 0, DT_INT, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _hqrndstate_init(&p->generator, _state, make_automatic); +} + + +void _smlptrnsession_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + smlptrnsession *dst = (smlptrnsession*)_dst; + const smlptrnsession *src = (const smlptrnsession*)_src; + ae_vector_init_copy(&dst->bestparameters, &src->bestparameters, _state, make_automatic); + dst->bestrmserror = src->bestrmserror; + dst->randomizenetwork = src->randomizenetwork; + _multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic); + _minlbfgsstate_init_copy(&dst->optimizer, &src->optimizer, _state, make_automatic); + _minlbfgsreport_init_copy(&dst->optimizerrep, &src->optimizerrep, _state, make_automatic); + ae_vector_init_copy(&dst->wbuf0, &src->wbuf0, _state, make_automatic); + ae_vector_init_copy(&dst->wbuf1, &src->wbuf1, _state, make_automatic); + ae_vector_init_copy(&dst->allminibatches, &src->allminibatches, _state, make_automatic); + ae_vector_init_copy(&dst->currentminibatch, &src->currentminibatch, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->algoused = src->algoused; + dst->minibatchsize = src->minibatchsize; + _hqrndstate_init_copy(&dst->generator, &src->generator, _state, make_automatic); +} + + +void _smlptrnsession_clear(void* _p) +{ + smlptrnsession *p = (smlptrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->bestparameters); + _multilayerperceptron_clear(&p->network); + _minlbfgsstate_clear(&p->optimizer); + _minlbfgsreport_clear(&p->optimizerrep); + ae_vector_clear(&p->wbuf0); + ae_vector_clear(&p->wbuf1); + ae_vector_clear(&p->allminibatches); + ae_vector_clear(&p->currentminibatch); + _rcommstate_clear(&p->rstate); + _hqrndstate_clear(&p->generator); +} + + +void _smlptrnsession_destroy(void* _p) +{ + smlptrnsession *p = (smlptrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->bestparameters); + _multilayerperceptron_destroy(&p->network); + _minlbfgsstate_destroy(&p->optimizer); + _minlbfgsreport_destroy(&p->optimizerrep); + ae_vector_destroy(&p->wbuf0); + ae_vector_destroy(&p->wbuf1); + ae_vector_destroy(&p->allminibatches); + ae_vector_destroy(&p->currentminibatch); + _rcommstate_destroy(&p->rstate); + _hqrndstate_destroy(&p->generator); +} + + +void _mlpetrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpetrnsession *p = (mlpetrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->trnsubset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->valsubset, 0, DT_INT, _state, make_automatic); + ae_shared_pool_init(&p->mlpsessions, _state, make_automatic); + _mlpreport_init(&p->mlprep, _state, make_automatic); + _multilayerperceptron_init(&p->network, _state, make_automatic); +} + + +void _mlpetrnsession_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpetrnsession *dst = (mlpetrnsession*)_dst; + const mlpetrnsession *src = (const mlpetrnsession*)_src; + ae_vector_init_copy(&dst->trnsubset, &src->trnsubset, _state, make_automatic); + ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state, make_automatic); + ae_shared_pool_init_copy(&dst->mlpsessions, &src->mlpsessions, _state, make_automatic); + _mlpreport_init_copy(&dst->mlprep, &src->mlprep, _state, make_automatic); + _multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic); +} + + +void _mlpetrnsession_clear(void* _p) +{ + mlpetrnsession *p = (mlpetrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->trnsubset); + ae_vector_clear(&p->valsubset); + ae_shared_pool_clear(&p->mlpsessions); + _mlpreport_clear(&p->mlprep); + _multilayerperceptron_clear(&p->network); +} + + +void _mlpetrnsession_destroy(void* _p) +{ + mlpetrnsession *p = (mlpetrnsession*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->trnsubset); + ae_vector_destroy(&p->valsubset); + ae_shared_pool_destroy(&p->mlpsessions); + _mlpreport_destroy(&p->mlprep); + _multilayerperceptron_destroy(&p->network); +} + + +void _mlptrainer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlptrainer *p = (mlptrainer*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->densexy, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsexy, _state, make_automatic); + _smlptrnsession_init(&p->session, _state, make_automatic); + ae_vector_init(&p->subset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->valsubset, 0, DT_INT, _state, make_automatic); +} + + +void _mlptrainer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlptrainer *dst = (mlptrainer*)_dst; + const mlptrainer *src = (const mlptrainer*)_src; + dst->nin = src->nin; + dst->nout = src->nout; + dst->rcpar = src->rcpar; + dst->lbfgsfactor = src->lbfgsfactor; + dst->decay = src->decay; + dst->wstep = src->wstep; + dst->maxits = src->maxits; + dst->datatype = src->datatype; + dst->npoints = src->npoints; + ae_matrix_init_copy(&dst->densexy, &src->densexy, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsexy, &src->sparsexy, _state, make_automatic); + _smlptrnsession_init_copy(&dst->session, &src->session, _state, make_automatic); + dst->ngradbatch = src->ngradbatch; + ae_vector_init_copy(&dst->subset, &src->subset, _state, make_automatic); + dst->subsetsize = src->subsetsize; + ae_vector_init_copy(&dst->valsubset, &src->valsubset, _state, make_automatic); + dst->valsubsetsize = src->valsubsetsize; + dst->algokind = src->algokind; + dst->minibatchsize = src->minibatchsize; +} + + +void _mlptrainer_clear(void* _p) +{ + mlptrainer *p = (mlptrainer*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->densexy); + _sparsematrix_clear(&p->sparsexy); + _smlptrnsession_clear(&p->session); + ae_vector_clear(&p->subset); + ae_vector_clear(&p->valsubset); +} + + +void _mlptrainer_destroy(void* _p) +{ + mlptrainer *p = (mlptrainer*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->densexy); + _sparsematrix_destroy(&p->sparsexy); + _smlptrnsession_destroy(&p->session); + ae_vector_destroy(&p->subset); + ae_vector_destroy(&p->valsubset); +} + + +void _mlpparallelizationcv_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mlpparallelizationcv *p = (mlpparallelizationcv*)_p; + ae_touch_ptr((void*)p); + _multilayerperceptron_init(&p->network, _state, make_automatic); + _mlpreport_init(&p->rep, _state, make_automatic); + ae_vector_init(&p->subset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xyrow, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_shared_pool_init(&p->trnpool, _state, make_automatic); +} + + +void _mlpparallelizationcv_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mlpparallelizationcv *dst = (mlpparallelizationcv*)_dst; + const mlpparallelizationcv *src = (const mlpparallelizationcv*)_src; + _multilayerperceptron_init_copy(&dst->network, &src->network, _state, make_automatic); + _mlpreport_init_copy(&dst->rep, &src->rep, _state, make_automatic); + ae_vector_init_copy(&dst->subset, &src->subset, _state, make_automatic); + dst->subsetsize = src->subsetsize; + ae_vector_init_copy(&dst->xyrow, &src->xyrow, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + dst->ngrad = src->ngrad; + ae_shared_pool_init_copy(&dst->trnpool, &src->trnpool, _state, make_automatic); +} + + +void _mlpparallelizationcv_clear(void* _p) +{ + mlpparallelizationcv *p = (mlpparallelizationcv*)_p; + ae_touch_ptr((void*)p); + _multilayerperceptron_clear(&p->network); + _mlpreport_clear(&p->rep); + ae_vector_clear(&p->subset); + ae_vector_clear(&p->xyrow); + ae_vector_clear(&p->y); + ae_shared_pool_clear(&p->trnpool); +} + + +void _mlpparallelizationcv_destroy(void* _p) +{ + mlpparallelizationcv *p = (mlpparallelizationcv*)_p; + ae_touch_ptr((void*)p); + _multilayerperceptron_destroy(&p->network); + _mlpreport_destroy(&p->rep); + ae_vector_destroy(&p->subset); + ae_vector_destroy(&p->xyrow); + ae_vector_destroy(&p->y); + ae_shared_pool_destroy(&p->trnpool); +} + + +#endif +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +k-means++ clusterization. +Backward compatibility function, we recommend to use CLUSTERING subpackage +as better replacement. + + -- ALGLIB -- + Copyright 21.03.2009 by Bochkanov Sergey +*************************************************************************/ +void kmeansgenerate(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t k, + ae_int_t restarts, + ae_int_t* info, + /* Real */ ae_matrix* c, + /* Integer */ ae_vector* xyc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix dummy; + ae_int_t itscnt; + double e; + kmeansbuffers buf; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + memset(&buf, 0, sizeof(buf)); + *info = 0; + ae_matrix_clear(c); + ae_vector_clear(xyc); + ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); + _kmeansbuffers_init(&buf, _state, ae_true); + + kmeansinitbuf(&buf, _state); + kmeansgenerateinternal(xy, npoints, nvars, k, 0, 1, 0, restarts, ae_false, info, &itscnt, c, ae_true, &dummy, ae_false, xyc, &e, &buf, _state); + ae_frame_leave(_state); +} + + +#endif + +} + diff --git a/core/alglib/dataanalysis.h b/core/alglib/dataanalysis.h index 69d985ce..33f29f80 100644 --- a/core/alglib/dataanalysis.h +++ b/core/alglib/dataanalysis.h @@ -1,7394 +1,10693 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _dataanalysis_pkg_h -#define _dataanalysis_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "linalg.h" -#include "statistics.h" -#include "alglibmisc.h" -#include "specialfunctions.h" -#include "solvers.h" -#include "optimization.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - double relclserror; - double avgce; - double rmserror; - double avgerror; - double avgrelerror; -} cvreport; -typedef struct -{ - ae_int_t npoints; - ae_int_t nfeatures; - ae_int_t disttype; - ae_matrix xy; - ae_matrix d; - ae_int_t ahcalgo; - ae_int_t kmeansrestarts; - ae_int_t kmeansmaxits; -} clusterizerstate; -typedef struct -{ - ae_int_t npoints; - ae_vector p; - ae_matrix z; - ae_matrix pz; - ae_matrix pm; - ae_vector mergedist; -} ahcreport; -typedef struct -{ - ae_int_t npoints; - ae_int_t nfeatures; - ae_int_t terminationtype; - ae_int_t k; - ae_matrix c; - ae_vector cidx; -} kmeansreport; -typedef struct -{ - ae_int_t nvars; - ae_int_t nclasses; - ae_int_t ntrees; - ae_int_t bufsize; - ae_vector trees; -} decisionforest; -typedef struct -{ - double relclserror; - double avgce; - double rmserror; - double avgerror; - double avgrelerror; - double oobrelclserror; - double oobavgce; - double oobrmserror; - double oobavgerror; - double oobavgrelerror; -} dfreport; -typedef struct -{ - ae_vector treebuf; - ae_vector idxbuf; - ae_vector tmpbufr; - ae_vector tmpbufr2; - ae_vector tmpbufi; - ae_vector classibuf; - ae_vector sortrbuf; - ae_vector sortrbuf2; - ae_vector sortibuf; - ae_vector varpool; - ae_vector evsbin; - ae_vector evssplits; -} dfinternalbuffers; -typedef struct -{ - ae_vector w; -} linearmodel; -typedef struct -{ - ae_matrix c; - double rmserror; - double avgerror; - double avgrelerror; - double cvrmserror; - double cvavgerror; - double cvavgrelerror; - ae_int_t ncvdefects; - ae_vector cvdefects; -} lrreport; -typedef struct -{ - double relclserror; - double avgce; - double rmserror; - double avgerror; - double avgrelerror; -} modelerrors; -typedef struct -{ - double f; - ae_vector g; -} smlpgrad; -typedef struct -{ - ae_int_t hlnetworktype; - ae_int_t hlnormtype; - ae_vector hllayersizes; - ae_vector hlconnections; - ae_vector hlneurons; - ae_vector structinfo; - ae_vector weights; - ae_vector columnmeans; - ae_vector columnsigmas; - ae_vector neurons; - ae_vector dfdnet; - ae_vector derror; - ae_vector x; - ae_vector y; - ae_matrix xy; - ae_vector xyrow; - ae_vector nwbuf; - ae_vector integerbuf; - modelerrors err; - ae_vector rndbuf; - ae_shared_pool buf; - ae_shared_pool gradbuf; - ae_matrix dummydxy; - sparsematrix dummysxy; - ae_vector dummyidx; - ae_shared_pool dummypool; -} multilayerperceptron; -typedef struct -{ - ae_vector w; -} logitmodel; -typedef struct -{ - ae_bool brackt; - ae_bool stage1; - ae_int_t infoc; - double dg; - double dgm; - double dginit; - double dgtest; - double dgx; - double dgxm; - double dgy; - double dgym; - double finit; - double ftest1; - double fm; - double fx; - double fxm; - double fy; - double fym; - double stx; - double sty; - double stmin; - double stmax; - double width; - double width1; - double xtrapf; -} logitmcstate; -typedef struct -{ - ae_int_t ngrad; - ae_int_t nhess; -} mnlreport; -typedef struct -{ - ae_int_t n; - ae_vector states; - ae_int_t npairs; - ae_matrix data; - ae_matrix ec; - ae_matrix bndl; - ae_matrix bndu; - ae_matrix c; - ae_vector ct; - ae_int_t ccnt; - ae_vector pw; - ae_matrix priorp; - double regterm; - minbleicstate bs; - ae_int_t repinneriterationscount; - ae_int_t repouteriterationscount; - ae_int_t repnfev; - ae_int_t repterminationtype; - minbleicreport br; - ae_vector tmpp; - ae_vector effectivew; - ae_vector effectivebndl; - ae_vector effectivebndu; - ae_matrix effectivec; - ae_vector effectivect; - ae_vector h; - ae_matrix p; -} mcpdstate; -typedef struct -{ - ae_int_t inneriterationscount; - ae_int_t outeriterationscount; - ae_int_t nfev; - ae_int_t terminationtype; -} mcpdreport; -typedef struct -{ - ae_int_t ensemblesize; - ae_vector weights; - ae_vector columnmeans; - ae_vector columnsigmas; - multilayerperceptron network; - ae_vector y; -} mlpensemble; -typedef struct -{ - double relclserror; - double avgce; - double rmserror; - double avgerror; - double avgrelerror; - ae_int_t ngrad; - ae_int_t nhess; - ae_int_t ncholesky; -} mlpreport; -typedef struct -{ - double relclserror; - double avgce; - double rmserror; - double avgerror; - double avgrelerror; -} mlpcvreport; -typedef struct -{ - ae_vector bestparameters; - double bestrmserror; - ae_bool randomizenetwork; - multilayerperceptron network; - minlbfgsstate optimizer; - minlbfgsreport optimizerrep; - ae_vector wbuf0; - ae_vector wbuf1; - ae_vector allminibatches; - ae_vector currentminibatch; - rcommstate rstate; - ae_int_t algoused; - ae_int_t minibatchsize; - hqrndstate generator; -} smlptrnsession; -typedef struct -{ - ae_vector trnsubset; - ae_vector valsubset; - ae_shared_pool mlpsessions; - mlpreport mlprep; - multilayerperceptron network; -} mlpetrnsession; -typedef struct -{ - ae_int_t nin; - ae_int_t nout; - ae_bool rcpar; - ae_int_t lbfgsfactor; - double decay; - double wstep; - ae_int_t maxits; - ae_int_t datatype; - ae_int_t npoints; - ae_matrix densexy; - sparsematrix sparsexy; - smlptrnsession session; - ae_int_t ngradbatch; - ae_vector subset; - ae_int_t subsetsize; - ae_vector valsubset; - ae_int_t valsubsetsize; - ae_int_t algokind; - ae_int_t minibatchsize; -} mlptrainer; -typedef struct -{ - multilayerperceptron network; - mlpreport rep; - ae_vector subset; - ae_int_t subsetsize; - ae_vector xyrow; - ae_vector y; - ae_int_t ngrad; - ae_shared_pool trnpool; -} mlpparallelizationcv; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - - -/************************************************************************* -This structure is a clusterization engine. - -You should not try to access its fields directly. -Use ALGLIB functions in order to work with this object. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -class _clusterizerstate_owner -{ -public: - _clusterizerstate_owner(); - _clusterizerstate_owner(const _clusterizerstate_owner &rhs); - _clusterizerstate_owner& operator=(const _clusterizerstate_owner &rhs); - virtual ~_clusterizerstate_owner(); - alglib_impl::clusterizerstate* c_ptr(); - alglib_impl::clusterizerstate* c_ptr() const; -protected: - alglib_impl::clusterizerstate *p_struct; -}; -class clusterizerstate : public _clusterizerstate_owner -{ -public: - clusterizerstate(); - clusterizerstate(const clusterizerstate &rhs); - clusterizerstate& operator=(const clusterizerstate &rhs); - virtual ~clusterizerstate(); - -}; - - -/************************************************************************* -This structure is used to store results of the agglomerative hierarchical -clustering (AHC). - -Following information is returned: - -* NPoints contains number of points in the original dataset - -* Z contains information about merges performed (see below). Z contains - indexes from the original (unsorted) dataset and it can be used when you - need to know what points were merged. However, it is not convenient when - you want to build a dendrograd (see below). - -* if you want to build dendrogram, you can use Z, but it is not good - option, because Z contains indexes from unsorted dataset. Dendrogram - built from such dataset is likely to have intersections. So, you have to - reorder you points before building dendrogram. - Permutation which reorders point is returned in P. Another representation - of merges, which is more convenient for dendorgram construction, is - returned in PM. - -* more information on format of Z, P and PM can be found below and in the - examples from ALGLIB Reference Manual. - -FORMAL DESCRIPTION OF FIELDS: - NPoints number of points - Z array[NPoints-1,2], contains indexes of clusters - linked in pairs to form clustering tree. I-th row - corresponds to I-th merge: - * Z[I,0] - index of the first cluster to merge - * Z[I,1] - index of the second cluster to merge - * Z[I,0]=0 - NFeatures number of variables, >=1 - TerminationType completion code: - * -5 if distance type is anything different from - Euclidean metric - * -3 for degenerate dataset: a) less than K distinct - points, b) K=0 for non-empty dataset. - * +1 for successful completion - K number of clusters - C array[K,NFeatures], rows of the array store centers - CIdx array[NPoints], which contains cluster indexes - - -- ALGLIB -- - Copyright 27.11.2012 by Bochkanov Sergey -*************************************************************************/ -class _kmeansreport_owner -{ -public: - _kmeansreport_owner(); - _kmeansreport_owner(const _kmeansreport_owner &rhs); - _kmeansreport_owner& operator=(const _kmeansreport_owner &rhs); - virtual ~_kmeansreport_owner(); - alglib_impl::kmeansreport* c_ptr(); - alglib_impl::kmeansreport* c_ptr() const; -protected: - alglib_impl::kmeansreport *p_struct; -}; -class kmeansreport : public _kmeansreport_owner -{ -public: - kmeansreport(); - kmeansreport(const kmeansreport &rhs); - kmeansreport& operator=(const kmeansreport &rhs); - virtual ~kmeansreport(); - ae_int_t &npoints; - ae_int_t &nfeatures; - ae_int_t &terminationtype; - ae_int_t &k; - real_2d_array c; - integer_1d_array cidx; - -}; - - - -/************************************************************************* - -*************************************************************************/ -class _decisionforest_owner -{ -public: - _decisionforest_owner(); - _decisionforest_owner(const _decisionforest_owner &rhs); - _decisionforest_owner& operator=(const _decisionforest_owner &rhs); - virtual ~_decisionforest_owner(); - alglib_impl::decisionforest* c_ptr(); - alglib_impl::decisionforest* c_ptr() const; -protected: - alglib_impl::decisionforest *p_struct; -}; -class decisionforest : public _decisionforest_owner -{ -public: - decisionforest(); - decisionforest(const decisionforest &rhs); - decisionforest& operator=(const decisionforest &rhs); - virtual ~decisionforest(); - -}; - - -/************************************************************************* - -*************************************************************************/ -class _dfreport_owner -{ -public: - _dfreport_owner(); - _dfreport_owner(const _dfreport_owner &rhs); - _dfreport_owner& operator=(const _dfreport_owner &rhs); - virtual ~_dfreport_owner(); - alglib_impl::dfreport* c_ptr(); - alglib_impl::dfreport* c_ptr() const; -protected: - alglib_impl::dfreport *p_struct; -}; -class dfreport : public _dfreport_owner -{ -public: - dfreport(); - dfreport(const dfreport &rhs); - dfreport& operator=(const dfreport &rhs); - virtual ~dfreport(); - double &relclserror; - double &avgce; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &oobrelclserror; - double &oobavgce; - double &oobrmserror; - double &oobavgerror; - double &oobavgrelerror; - -}; - -/************************************************************************* - -*************************************************************************/ -class _linearmodel_owner -{ -public: - _linearmodel_owner(); - _linearmodel_owner(const _linearmodel_owner &rhs); - _linearmodel_owner& operator=(const _linearmodel_owner &rhs); - virtual ~_linearmodel_owner(); - alglib_impl::linearmodel* c_ptr(); - alglib_impl::linearmodel* c_ptr() const; -protected: - alglib_impl::linearmodel *p_struct; -}; -class linearmodel : public _linearmodel_owner -{ -public: - linearmodel(); - linearmodel(const linearmodel &rhs); - linearmodel& operator=(const linearmodel &rhs); - virtual ~linearmodel(); - -}; - - -/************************************************************************* -LRReport structure contains additional information about linear model: -* C - covariation matrix, array[0..NVars,0..NVars]. - C[i,j] = Cov(A[i],A[j]) -* RMSError - root mean square error on a training set -* AvgError - average error on a training set -* AvgRelError - average relative error on a training set (excluding - observations with zero function value). -* CVRMSError - leave-one-out cross-validation estimate of - generalization error. Calculated using fast algorithm - with O(NVars*NPoints) complexity. -* CVAvgError - cross-validation estimate of average error -* CVAvgRelError - cross-validation estimate of average relative error - -All other fields of the structure are intended for internal use and should -not be used outside ALGLIB. -*************************************************************************/ -class _lrreport_owner -{ -public: - _lrreport_owner(); - _lrreport_owner(const _lrreport_owner &rhs); - _lrreport_owner& operator=(const _lrreport_owner &rhs); - virtual ~_lrreport_owner(); - alglib_impl::lrreport* c_ptr(); - alglib_impl::lrreport* c_ptr() const; -protected: - alglib_impl::lrreport *p_struct; -}; -class lrreport : public _lrreport_owner -{ -public: - lrreport(); - lrreport(const lrreport &rhs); - lrreport& operator=(const lrreport &rhs); - virtual ~lrreport(); - real_2d_array c; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &cvrmserror; - double &cvavgerror; - double &cvavgrelerror; - ae_int_t &ncvdefects; - integer_1d_array cvdefects; - -}; - - - - - -/************************************************************************* -Model's errors: - * RelCLSError - fraction of misclassified cases. - * AvgCE - acerage cross-entropy - * RMSError - root-mean-square error - * AvgError - average error - * AvgRelError - average relative error - -NOTE 1: RelCLSError/AvgCE are zero on regression problems. - -NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain - errors in prediction of posterior probabilities -*************************************************************************/ -class _modelerrors_owner -{ -public: - _modelerrors_owner(); - _modelerrors_owner(const _modelerrors_owner &rhs); - _modelerrors_owner& operator=(const _modelerrors_owner &rhs); - virtual ~_modelerrors_owner(); - alglib_impl::modelerrors* c_ptr(); - alglib_impl::modelerrors* c_ptr() const; -protected: - alglib_impl::modelerrors *p_struct; -}; -class modelerrors : public _modelerrors_owner -{ -public: - modelerrors(); - modelerrors(const modelerrors &rhs); - modelerrors& operator=(const modelerrors &rhs); - virtual ~modelerrors(); - double &relclserror; - double &avgce; - double &rmserror; - double &avgerror; - double &avgrelerror; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _multilayerperceptron_owner -{ -public: - _multilayerperceptron_owner(); - _multilayerperceptron_owner(const _multilayerperceptron_owner &rhs); - _multilayerperceptron_owner& operator=(const _multilayerperceptron_owner &rhs); - virtual ~_multilayerperceptron_owner(); - alglib_impl::multilayerperceptron* c_ptr(); - alglib_impl::multilayerperceptron* c_ptr() const; -protected: - alglib_impl::multilayerperceptron *p_struct; -}; -class multilayerperceptron : public _multilayerperceptron_owner -{ -public: - multilayerperceptron(); - multilayerperceptron(const multilayerperceptron &rhs); - multilayerperceptron& operator=(const multilayerperceptron &rhs); - virtual ~multilayerperceptron(); - -}; - -/************************************************************************* - -*************************************************************************/ -class _logitmodel_owner -{ -public: - _logitmodel_owner(); - _logitmodel_owner(const _logitmodel_owner &rhs); - _logitmodel_owner& operator=(const _logitmodel_owner &rhs); - virtual ~_logitmodel_owner(); - alglib_impl::logitmodel* c_ptr(); - alglib_impl::logitmodel* c_ptr() const; -protected: - alglib_impl::logitmodel *p_struct; -}; -class logitmodel : public _logitmodel_owner -{ -public: - logitmodel(); - logitmodel(const logitmodel &rhs); - logitmodel& operator=(const logitmodel &rhs); - virtual ~logitmodel(); - -}; - - -/************************************************************************* -MNLReport structure contains information about training process: -* NGrad - number of gradient calculations -* NHess - number of Hessian calculations -*************************************************************************/ -class _mnlreport_owner -{ -public: - _mnlreport_owner(); - _mnlreport_owner(const _mnlreport_owner &rhs); - _mnlreport_owner& operator=(const _mnlreport_owner &rhs); - virtual ~_mnlreport_owner(); - alglib_impl::mnlreport* c_ptr(); - alglib_impl::mnlreport* c_ptr() const; -protected: - alglib_impl::mnlreport *p_struct; -}; -class mnlreport : public _mnlreport_owner -{ -public: - mnlreport(); - mnlreport(const mnlreport &rhs); - mnlreport& operator=(const mnlreport &rhs); - virtual ~mnlreport(); - ae_int_t &ngrad; - ae_int_t &nhess; - -}; - -/************************************************************************* -This structure is a MCPD (Markov Chains for Population Data) solver. - -You should use ALGLIB functions in order to work with this object. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -class _mcpdstate_owner -{ -public: - _mcpdstate_owner(); - _mcpdstate_owner(const _mcpdstate_owner &rhs); - _mcpdstate_owner& operator=(const _mcpdstate_owner &rhs); - virtual ~_mcpdstate_owner(); - alglib_impl::mcpdstate* c_ptr(); - alglib_impl::mcpdstate* c_ptr() const; -protected: - alglib_impl::mcpdstate *p_struct; -}; -class mcpdstate : public _mcpdstate_owner -{ -public: - mcpdstate(); - mcpdstate(const mcpdstate &rhs); - mcpdstate& operator=(const mcpdstate &rhs); - virtual ~mcpdstate(); - -}; - - -/************************************************************************* -This structure is a MCPD training report: - InnerIterationsCount - number of inner iterations of the - underlying optimization algorithm - OuterIterationsCount - number of outer iterations of the - underlying optimization algorithm - NFEV - number of merit function evaluations - TerminationType - termination type - (same as for MinBLEIC optimizer, positive - values denote success, negative ones - - failure) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -class _mcpdreport_owner -{ -public: - _mcpdreport_owner(); - _mcpdreport_owner(const _mcpdreport_owner &rhs); - _mcpdreport_owner& operator=(const _mcpdreport_owner &rhs); - virtual ~_mcpdreport_owner(); - alglib_impl::mcpdreport* c_ptr(); - alglib_impl::mcpdreport* c_ptr() const; -protected: - alglib_impl::mcpdreport *p_struct; -}; -class mcpdreport : public _mcpdreport_owner -{ -public: - mcpdreport(); - mcpdreport(const mcpdreport &rhs); - mcpdreport& operator=(const mcpdreport &rhs); - virtual ~mcpdreport(); - ae_int_t &inneriterationscount; - ae_int_t &outeriterationscount; - ae_int_t &nfev; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -Neural networks ensemble -*************************************************************************/ -class _mlpensemble_owner -{ -public: - _mlpensemble_owner(); - _mlpensemble_owner(const _mlpensemble_owner &rhs); - _mlpensemble_owner& operator=(const _mlpensemble_owner &rhs); - virtual ~_mlpensemble_owner(); - alglib_impl::mlpensemble* c_ptr(); - alglib_impl::mlpensemble* c_ptr() const; -protected: - alglib_impl::mlpensemble *p_struct; -}; -class mlpensemble : public _mlpensemble_owner -{ -public: - mlpensemble(); - mlpensemble(const mlpensemble &rhs); - mlpensemble& operator=(const mlpensemble &rhs); - virtual ~mlpensemble(); - -}; - -/************************************************************************* -Training report: - * RelCLSError - fraction of misclassified cases. - * AvgCE - acerage cross-entropy - * RMSError - root-mean-square error - * AvgError - average error - * AvgRelError - average relative error - * NGrad - number of gradient calculations - * NHess - number of Hessian calculations - * NCholesky - number of Cholesky decompositions - -NOTE 1: RelCLSError/AvgCE are zero on regression problems. - -NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain - errors in prediction of posterior probabilities -*************************************************************************/ -class _mlpreport_owner -{ -public: - _mlpreport_owner(); - _mlpreport_owner(const _mlpreport_owner &rhs); - _mlpreport_owner& operator=(const _mlpreport_owner &rhs); - virtual ~_mlpreport_owner(); - alglib_impl::mlpreport* c_ptr(); - alglib_impl::mlpreport* c_ptr() const; -protected: - alglib_impl::mlpreport *p_struct; -}; -class mlpreport : public _mlpreport_owner -{ -public: - mlpreport(); - mlpreport(const mlpreport &rhs); - mlpreport& operator=(const mlpreport &rhs); - virtual ~mlpreport(); - double &relclserror; - double &avgce; - double &rmserror; - double &avgerror; - double &avgrelerror; - ae_int_t &ngrad; - ae_int_t &nhess; - ae_int_t &ncholesky; - -}; - - -/************************************************************************* -Cross-validation estimates of generalization error -*************************************************************************/ -class _mlpcvreport_owner -{ -public: - _mlpcvreport_owner(); - _mlpcvreport_owner(const _mlpcvreport_owner &rhs); - _mlpcvreport_owner& operator=(const _mlpcvreport_owner &rhs); - virtual ~_mlpcvreport_owner(); - alglib_impl::mlpcvreport* c_ptr(); - alglib_impl::mlpcvreport* c_ptr() const; -protected: - alglib_impl::mlpcvreport *p_struct; -}; -class mlpcvreport : public _mlpcvreport_owner -{ -public: - mlpcvreport(); - mlpcvreport(const mlpcvreport &rhs); - mlpcvreport& operator=(const mlpcvreport &rhs); - virtual ~mlpcvreport(); - double &relclserror; - double &avgce; - double &rmserror; - double &avgerror; - double &avgrelerror; - -}; - - -/************************************************************************* -Trainer object for neural network. - -You should not try to access fields of this object directly - use ALGLIB -functions to work with this object. -*************************************************************************/ -class _mlptrainer_owner -{ -public: - _mlptrainer_owner(); - _mlptrainer_owner(const _mlptrainer_owner &rhs); - _mlptrainer_owner& operator=(const _mlptrainer_owner &rhs); - virtual ~_mlptrainer_owner(); - alglib_impl::mlptrainer* c_ptr(); - alglib_impl::mlptrainer* c_ptr() const; -protected: - alglib_impl::mlptrainer *p_struct; -}; -class mlptrainer : public _mlptrainer_owner -{ -public: - mlptrainer(); - mlptrainer(const mlptrainer &rhs); - mlptrainer& operator=(const mlptrainer &rhs); - virtual ~mlptrainer(); - -}; - -/************************************************************************* -Optimal binary classification - -Algorithms finds optimal (=with minimal cross-entropy) binary partition. -Internal subroutine. - -INPUT PARAMETERS: - A - array[0..N-1], variable - C - array[0..N-1], class numbers (0 or 1). - N - array size - -OUTPUT PARAMETERS: - Info - completion code: - * -3, all values of A[] are same (partition is impossible) - * -2, one of C[] is incorrect (<0, >1) - * -1, incorrect pararemets were passed (N<=0). - * 1, OK - Threshold- partiton boundary. Left part contains values which are - strictly less than Threshold. Right part contains values - which are greater than or equal to Threshold. - PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) - CVE - cross-validation estimate of cross-entropy - - -- ALGLIB -- - Copyright 22.05.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve); - - -/************************************************************************* -Optimal partition, internal subroutine. Fast version. - -Accepts: - A array[0..N-1] array of attributes array[0..N-1] - C array[0..N-1] array of class labels - TiesBuf array[0..N] temporaries (ties) - CntBuf array[0..2*NC-1] temporaries (counts) - Alpha centering factor (0<=alpha<=1, recommended value - 0.05) - BufR array[0..N-1] temporaries - BufI array[0..N-1] temporaries - -Output: - Info error code (">0"=OK, "<0"=bad) - RMS training set RMS error - CVRMS leave-one-out RMS error - -Note: - content of all arrays is changed by subroutine; - it doesn't allocate temporaries. - - -- ALGLIB -- - Copyright 11.12.2008 by Bochkanov Sergey -*************************************************************************/ -void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms); - -/************************************************************************* -This function initializes clusterizer object. Newly initialized object is -empty, i.e. it does not contain dataset. You should use it as follows: -1. creation -2. dataset is added with ClusterizerSetPoints() -3. additional parameters are set -3. clusterization is performed with one of the clustering functions - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizercreate(clusterizerstate &s); - - -/************************************************************************* -This function adds dataset to the clusterizer structure. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -NOTE 1: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - -NOTE 2: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric - * k-means++ clustering algorithm may be used only with Euclidean - distance function - Thus, list of specific clustering algorithms you may use depends - on distance function you specify when you set your dataset. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype); -void clusterizersetpoints(const clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype); - - -/************************************************************************* -This function adds dataset given by distance matrix to the clusterizer -structure. It is important that dataset is not given explicitly - only -distance matrix is given. - -This function overrides all previous calls of ClusterizerSetPoints() or -ClusterizerSetDistances(). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - D - array[NPoints,NPoints], distance matrix given by its upper - or lower triangle (main diagonal is ignored because its - entries are expected to be zero). - NPoints - number of points - IsUpper - whether upper or lower triangle of D is given. - -NOTE 1: different clustering algorithms have different limitations: - * agglomerative hierarchical clustering algorithms may be used with - any kind of distance metric, including one which is given by - distance matrix - * k-means++ clustering algorithm may be used only with Euclidean - distance function and explicitly given points - it can not be - used with dataset given by distance matrix - Thus, if you call this function, you will be unable to use k-means - clustering algorithm to process your problem. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper); -void clusterizersetdistances(const clusterizerstate &s, const real_2d_array &d, const bool isupper); - - -/************************************************************************* -This function sets agglomerative hierarchical clustering algorithm - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Algo - algorithm type: - * 0 complete linkage (default algorithm) - * 1 single linkage - * 2 unweighted average linkage - * 3 weighted average linkage - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetahcalgo(const clusterizerstate &s, const ae_int_t algo); - - -/************************************************************************* -This function sets k-means++ properties : number of restarts and maximum -number of iterations per one run. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - Restarts- restarts count, >=1. - k-means++ algorithm performs several restarts and chooses - best set of centers (one with minimum squared distance). - MaxIts - maximum number of k-means iterations performed during one - run. >=0, zero value means that algorithm performs unlimited - number of iterations. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizersetkmeanslimits(const clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits); - - -/************************************************************************* -This function performs agglomerative hierarchical clustering - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - -OUTPUT PARAMETERS: - Rep - clustering results; see description of AHCReport - structure for more information. - -NOTE 1: hierarchical clustering algorithms require large amounts of memory. - In particular, this implementation needs sizeof(double)*NPoints^2 - bytes, which are used to store distance matrix. In case we work - with user-supplied matrix, this amount is multiplied by 2 (we have - to store original matrix and to work with its copy). - - For example, problem with 10000 points would require 800M of RAM, - even when working in a 1-dimensional space. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunahc(const clusterizerstate &s, ahcreport &rep); -void smp_clusterizerrunahc(const clusterizerstate &s, ahcreport &rep); - - -/************************************************************************* -This function performs clustering by k-means++ algorithm. - -You may change algorithm properties like number of restarts or iterations -limit by calling ClusterizerSetKMeansLimits() functions. - -INPUT PARAMETERS: - S - clusterizer state, initialized by ClusterizerCreate() - K - number of clusters, K>=0. - K can be zero only when algorithm is called for empty - dataset, in this case completion code is set to - success (+1). - If K=0 and dataset size is non-zero, we can not - meaningfully assign points to some center (there are no - centers because K=0) and return -3 as completion code - (failure). - -OUTPUT PARAMETERS: - Rep - clustering results; see description of KMeansReport - structure for more information. - -NOTE 1: k-means clustering can be performed only for datasets with - Euclidean distance function. Algorithm will return negative - completion code in Rep.TerminationType in case dataset was added - to clusterizer with DistType other than Euclidean (or dataset was - specified by distance matrix instead of explicitly given points). - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizerrunkmeans(const clusterizerstate &s, const ae_int_t k, kmeansreport &rep); - - -/************************************************************************* -This function returns distance matrix for dataset - -FOR USERS OF SMP EDITION: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Multicore version is pretty efficient on large - ! problems which need more than 1.000.000 operations to be solved, - ! gives moderate speed-up in mid-range (from 100.000 to 1.000.000 CPU - ! cycles), but gives no speed-up for small problems (less than 100.000 - ! operations). - -INPUT PARAMETERS: - XY - array[NPoints,NFeatures], dataset - NPoints - number of points, >=0 - NFeatures- number of features, >=1 - DistType- distance function: - * 0 Chebyshev distance (L-inf norm) - * 1 city block distance (L1 norm) - * 2 Euclidean distance (L2 norm) - * 10 Pearson correlation: - dist(a,b) = 1-corr(a,b) - * 11 Absolute Pearson correlation: - dist(a,b) = 1-|corr(a,b)| - * 12 Uncentered Pearson correlation (cosine of the angle): - dist(a,b) = a'*b/(|a|*|b|) - * 13 Absolute uncentered Pearson correlation - dist(a,b) = |a'*b|/(|a|*|b|) - * 20 Spearman rank correlation: - dist(a,b) = 1-rankcorr(a,b) - * 21 Absolute Spearman rank correlation - dist(a,b) = 1-|rankcorr(a,b)| - -OUTPUT PARAMETERS: - D - array[NPoints,NPoints], distance matrix - (full matrix is returned, with lower and upper triangles) - -NOTES: different distance functions have different performance penalty: - * Euclidean or Pearson correlation distances are the fastest ones - * Spearman correlation distance function is a bit slower - * city block and Chebyshev distances are order of magnitude slower - - The reason behing difference in performance is that correlation-based - distance functions are computed using optimized linear algebra kernels, - while Chebyshev and city block distance functions are computed using - simple nested loops with two branches at each iteration. - - -- ALGLIB -- - Copyright 10.07.2012 by Bochkanov Sergey -*************************************************************************/ -void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d); -void smp_clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d); - - -/************************************************************************* -This function takes as input clusterization report Rep, desired clusters -count K, and builds top K clusters from hierarchical clusterization tree. -It returns assignment of points to clusters (array of cluster indexes). - -INPUT PARAMETERS: - Rep - report from ClusterizerRunAHC() performed on XY - K - desired number of clusters, 1<=K<=NPoints. - K can be zero only when NPoints=0. - -OUTPUT PARAMETERS: - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I]=0 - -OUTPUT PARAMETERS: - K - number of clusters, 1<=K<=NPoints - CIdx - array[NPoints], I-th element contains cluster index (from - 0 to K-1) for I-th point of the dataset. - CZ - array[K]. This array allows to convert cluster indexes - returned by this function to indexes used by Rep.Z. J-th - cluster returned by this function corresponds to CZ[J]-th - cluster stored in Rep.Z/PZ/PM. - It is guaranteed that CZ[I]=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep); - - -/************************************************************************* -This subroutine builds random decision forest. -This function gives ability to tune number of variables used when choosing -best split. - -INPUT PARAMETERS: - XY - training set - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - task type: - * NClasses=1 - regression task with one - dependent variable - * NClasses>1 - classification task with - NClasses classes. - NTrees - number of trees in a forest, NTrees>=1. - recommended values: 50-100. - NRndVars - number of variables used when choosing best split - R - percent of a training set used to build - individual trees. 01). - * 1, if task has been solved - DF - model built - Rep - training report, contains error on a training set - and out-of-bag estimates of generalization error. - - -- ALGLIB -- - Copyright 19.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep); - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - DF - decision forest model - X - input vector, array[0..NVars-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also DFProcessI. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -'interactive' variant of DFProcess for languages like Python which support -constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 28.02.2010 by Bochkanov Sergey -*************************************************************************/ -void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if model solves regression task. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for - classification task, RMS error means error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average error when estimating posterior - probabilities. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - DF - decision forest model - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for - classification task, it means average relative error when estimating - posterior probability of belonging to the correct class. - - -- ALGLIB -- - Copyright 16.02.2009 by Bochkanov Sergey -*************************************************************************/ -double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints); - -/************************************************************************* -Linear regression - -Subroutine builds model: - - Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) - -and model found in ALGLIB format, covariation matrix, training set errors -(rms, average, average relative) and leave-one-out cross-validation -estimate of the generalization error. CV estimate calculated using fast -algorithm with O(NPoints*NVars) complexity. - -When covariation matrix is calculated standard deviations of function -values are assumed to be equal to RMS error on the training set. - -INPUT PARAMETERS: - XY - training set, array [0..NPoints-1,0..NVars]: - * NVars columns - independent variables - * last column - dependent variable - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPoints0. - NPoints - training set size, NPoints>NVars+1 - NVars - number of independent variables - -OUTPUT PARAMETERS: - Info - return code: - * -255, in case of unknown internal error - * -4, if internal SVD subroutine haven't converged - * -1, if incorrect parameters was passed (NPoints=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k); -void filtersma(real_1d_array &x, const ae_int_t k); - - -/************************************************************************* -Filters: exponential moving averages. - -This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is -defined as filter which replaces X[] by S[]: - S[0] = X[0] - S[t] = alpha*X[t] + (1-alpha)*S[t-1] - -INPUT PARAMETERS: - X - array[N], array to process. It can be larger than N, - in this case only first N points are processed. - N - points count, N>=0 - alpha - 0=0 - K - K>=1 (K can be larger than N , such cases will be - correctly handled). Window width. K=1 corresponds to - identity transformation (nothing changes). - -OUTPUT PARAMETERS: - X - array, whose first N elements were processed with SMA(K) - -NOTE 1: this function uses efficient in-place algorithm which does not - allocate temporary arrays. - -NOTE 2: this algorithm makes only one pass through array and uses running - sum to speed-up calculation of the averages. Additional measures - are taken to ensure that running sum on a long sequence of zero - elements will be correctly reset to zero even in the presence of - round-off error. - -NOTE 3: this is unsymmetric version of the algorithm, which does NOT - averages points after the current one. Only X[i], X[i-1], ... are - used when calculating new value of X[i]. We should also note that - this algorithm uses BOTH previous points and current one, i.e. - new value of X[i] depends on BOTH previous point and X[i] itself. - - -- ALGLIB -- - Copyright 25.10.2011 by Bochkanov Sergey -*************************************************************************/ -void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k); -void filterlrma(real_1d_array &x, const ae_int_t k); - -/************************************************************************* -Multiclass Fisher LDA - -Subroutine finds coefficients of linear combination which optimally separates -training set on classes. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - linear combination coefficients, array[0..NVars-1] - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_1d_array &w); - - -/************************************************************************* -N-dimensional multiclass Fisher LDA - -Subroutine finds coefficients of linear combinations which optimally separates -training set on classes. It returns N-dimensional basis whose vector are sorted -by quality of training set separation (in descending order). - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars]. - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - - -OUTPUT PARAMETERS: - Info - return code: - * -4, if internal EVD subroutine hasn't converged - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed (NPoints<0, - NVars<1, NClasses<2) - * 1, if task has been solved - * 2, if there was a multicollinearity in training set, - but task has been solved. - W - basis, array[0..NVars-1,0..NVars-1] - columns of matrix stores basis vectors, sorted by - quality of training set separation (in descending order) - - -- ALGLIB -- - Copyright 31.05.2008 by Bochkanov Sergey -*************************************************************************/ -void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, ae_int_t &info, real_2d_array &w); - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void mlpserialize(multilayerperceptron &obj, std::string &s_out); - - -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void mlpunserialize(std::string &s_in, multilayerperceptron &obj); - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers, with linear output layer. Network weights are filled with small -random values. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreate0, but with one hidden layer (NHid neurons) with -non-linear activation function. Output layer is linear. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) -with non-linear activation function. Output layer is linear. - $ALL - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. - -Activation function of the output layer takes values: - - (B, +INF), if D>=0 - -or - - (-INF, B), if D<0. - - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateB0 but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateB0 but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network); - - -/************************************************************************* -Creates neural network with NIn inputs, NOut outputs, without hidden -layers with non-linear output layer. Network weights are filled with small -random values. Activation function of the output layer takes values [A,B]. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateR0, but with non-linear hidden layer. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateR0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 30.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network); - - -/************************************************************************* -Creates classifier network with NIn inputs and NOut possible classes. -Network contains no hidden layers and linear output layer with SOFTMAX- -normalization (so outputs sums up to 1.0 and converge to posterior -probabilities). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateC0, but with one non-linear hidden layer. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Same as MLPCreateC0, but with two non-linear hidden layers. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network); - - -/************************************************************************* -Randomization of neural network weights - - -- ALGLIB -- - Copyright 06.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlprandomize(const multilayerperceptron &network); - - -/************************************************************************* -Randomization of neural network weights and standartisator - - -- ALGLIB -- - Copyright 10.03.2008 by Bochkanov Sergey -*************************************************************************/ -void mlprandomizefull(const multilayerperceptron &network); - - -/************************************************************************* -Returns information about initialized network: number of inputs, outputs, -weights. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount); - - -/************************************************************************* -Returns number of inputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetinputscount(const multilayerperceptron &network); - - -/************************************************************************* -Returns number of outputs. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetoutputscount(const multilayerperceptron &network); - - -/************************************************************************* -Returns number of weights. - - -- ALGLIB -- - Copyright 19.10.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetweightscount(const multilayerperceptron &network); - - -/************************************************************************* -Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -bool mlpissoftmax(const multilayerperceptron &network); - - -/************************************************************************* -This function returns total number of layers (including input, hidden and -output layers). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayerscount(const multilayerperceptron &network); - - -/************************************************************************* -This function returns size of K-th layer. - -K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. - -Size of the output layer is always equal to the number of outputs, although -when we have softmax-normalized network, last neuron doesn't have any -connections - it is just zero. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k); - - -/************************************************************************* -This function returns offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma); - - -/************************************************************************* -This function returns offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - -OUTPUT PARAMETERS: - Mean - mean term - Sigma - sigma term, guaranteed to be nonzero. - -I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. In case we have SOFTMAX-normalized network, -we return (Mean,Sigma)=(0.0,1.0). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma); - - -/************************************************************************* -This function returns information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - -OUTPUT PARAMETERS: - FKind - activation function type (used by MLPActivationFunction()) - this value is zero for input or linear neurons - Threshold - also called offset, bias - zero for input neurons - -NOTE: this function throws exception if layer or neuron with given index -do not exists. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpgetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold); - - -/************************************************************************* -This function returns information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - -RESULT: - connection weight (zero for non-existent connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. returns zero if neurons exist, but there is no connection between them - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -double mlpgetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1); - - -/************************************************************************* -This function sets offset/scaling coefficients for I-th input of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -NTE: I-th input is passed through linear transformation - IN[i] = (IN[i]-Mean)/Sigma -before feeding to the network. This function sets Mean and Sigma. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetinputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma); - - -/************************************************************************* -This function sets offset/scaling coefficients for I-th output of the -network. - -INPUT PARAMETERS: - Network - network - I - input index - Mean - mean term - Sigma - sigma term (if zero, will be replaced by 1.0) - -OUTPUT PARAMETERS: - -NOTE: I-th output is passed through linear transformation - OUT[i] = OUT[i]*Sigma+Mean -before returning it to user. This function sets Sigma/Mean. In case we -have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything -other than(0.0,1.0) - this function will throw exception. - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetoutputscaling(const multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma); - - -/************************************************************************* -This function modifies information about Ith neuron of Kth layer - -INPUT PARAMETERS: - Network - network - K - layer index - I - neuron index (within layer) - FKind - activation function type (used by MLPActivationFunction()) - this value must be zero for input neurons - (you can not set activation function for input neurons) - Threshold - also called offset, bias - this value must be zero for input neurons - (you can not set threshold for input neurons) - -NOTES: -1. this function throws exception if layer or neuron with given index do - not exists. -2. this function also throws exception when you try to set non-linear - activation function for input neurons (any kind of network) or for output - neurons of classifier network. -3. this function throws exception when you try to set non-zero threshold for - input neurons (any kind of network). - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetneuroninfo(const multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold); - - -/************************************************************************* -This function modifies information about connection from I0-th neuron of -K0-th layer to I1-th neuron of K1-th layer. - -INPUT PARAMETERS: - Network - network - K0 - layer index - I0 - neuron index (within layer) - K1 - layer index - I1 - neuron index (within layer) - W - connection weight (must be zero for non-existent - connections) - -This function: -1. throws exception if layer or neuron with given index do not exists. -2. throws exception if you try to set non-zero weight for non-existent - connection - - -- ALGLIB -- - Copyright 25.03.2011 by Bochkanov Sergey -*************************************************************************/ -void mlpsetweight(const multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w); - - -/************************************************************************* -Neural network activation function - -INPUT PARAMETERS: - NET - neuron input - K - function index (zero for linear function) - -OUTPUT PARAMETERS: - F - function - DF - its derivative - D2F - its second derivative - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f); - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Network - neural network - X - input vector, array[0..NIn-1]. - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - -See also MLPProcessI - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpprocess(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -'interactive' variant of MLPProcess for languages like Python which -support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 21.09.2010 by Bochkanov Sergey -*************************************************************************/ -void mlpprocessi(const multilayerperceptron &network, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlperror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Error of the neural network on dataset given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x, depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0 - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlperrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -Natural error function for neural network, internal subroutine. - -NOTE: this function is single-threaded. Unlike other error function, it -receives no speed-up from being executed in SMP mode. - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlperrorn(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize); - - -/************************************************************************* -Classification error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: - classification error (number of misclassified cases) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -ae_int_t mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -ae_int_t smp_mlpclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Relative classification error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 25.12.2008 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlprelclserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Relative classification error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. Sparse matrix must use CRS format - for storage. - NPoints - points count, >=0. - -RESULT: -Percent of incorrectly classified cases. Works both for classifier -networks and general purpose networks used as classifiers. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlprelclserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 08.01.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlpavgce(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set given by -sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -CrossEntropy/(NPoints*LN(2)). -Zero if network solves regression task. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 9.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlpavgcesparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -RMS error on the test set given. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -double mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlprmserror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -RMS error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Root mean square error. Its meaning for regression task is obvious. As for -classification task, RMS error means error when estimating posterior -probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlprmserrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -Average absolute error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlpavgerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average absolute error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average error when estimating posterior probabilities. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlpavgerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -Average relative error on the test set. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - NPoints - points count. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 11.03.2008 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); -double smp_mlpavgrelerror(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average relative error on the test set given by sparse matrix. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - NPoints - points count, >=0. - -RESULT: -Its meaning for regression task is obvious. As for classification task, it -means average relative error when estimating posterior probability of -belonging to the correct class. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 09.08.2012 by Bochkanov Sergey -*************************************************************************/ -double mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); -double smp_mlpavgrelerrorsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -Gradient calculation - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgrad(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad); - - -/************************************************************************* -Gradient calculation (natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - X - input vector, length of array must be at least NIn - DesiredY- desired outputs, length of array must be at least NOut - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradn(const multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); -void smp_mlpgradbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs given by sparse -matrices - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs. - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad); -void smp_mlpgradbatchsparse(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch gradient calculation for a subset of dataset - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in dense format; one sample = one row: - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); -void smp_mlpgradbatchsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs for a subset of -dataset given by set of indexes. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset in sparse format; one sample = one row: - * MATRIX MUST BE STORED IN CRS FORMAT - * first NIn columns contain inputs, - * for regression problem, next NOut columns store - desired outputs. - * for classification problem, next column (just one!) - stores class number. - SetSize - real size of XY, SetSize>=0; - Idx - subset of SubsetSize elements, array[SubsetSize]: - * Idx[I] stores row index in the original dataset which is - given by XY. Gradient is calculated with respect to rows - whose indexes are stored in Idx[]. - * Idx[] must store correct indexes; this function throws - an exception in case incorrect index (less than 0 or - larger than rows(XY)) is given - * Idx[] may store indexes in any order and even with - repetitions. - SubsetSize- number of elements in Idx[] array: - * positive value means that subset given by Idx[] is processed - * zero value results in zero gradient - * negative value means that full dataset is processed - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) - Grad - gradient of E with respect to weights of network, - array[WCount] - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse - function. - - -- ALGLIB -- - Copyright 26.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); -void smp_mlpgradbatchsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch gradient calculation for a set of inputs/outputs -(natural error function is used) - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - set of inputs/outputs; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SSize - number of elements in XY - Grad - possibly preallocated array. If size of array is smaller - than WCount, it will be reallocated. It is recommended to - reuse previously allocated array to reduce allocation - overhead. - -OUTPUT PARAMETERS: - E - error function, sum-of-squares for regression networks, - cross-entropy for classification networks. - Grad - gradient of E with respect to weights of network, array[WCount] - - -- ALGLIB -- - Copyright 04.11.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpgradnbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad); - - -/************************************************************************* -Batch Hessian calculation (natural error function) using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessiannbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h); - - -/************************************************************************* -Batch Hessian calculation using R-algorithm. -Internal subroutine. - - -- ALGLIB -- - Copyright 26.01.2008 by Bochkanov Sergey. - - Hessian calculation based on R-algorithm described in - "Fast Exact Multiplication by the Hessian", - B. A. Pearlmutter, - Neural Computation, 1994. -*************************************************************************/ -void mlphessianbatch(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h); - - -/************************************************************************* -Calculation of all types of errors. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset; one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); -void smp_mlpallerrorssubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); - - -/************************************************************************* -Calculation of all types of errors on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - network initialized with one of the network creation funcs - XY - original dataset given by sparse matrix; - one sample = one row; - first NIn columns contain inputs, - next NOut columns - desired outputs. - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -OUTPUT PARAMETERS: - Rep - it contains all type of errors. - -NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatch function. - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); -void smp_mlpallerrorssparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep); - - -/************************************************************************* -Error of the neural network on dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format; - SetSize - real size of XY, SetSize>=0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); -double smp_mlperrorsubset(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); - - -/************************************************************************* -Error of the neural network on sparse dataset. - - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support - ! - ! First improvement gives close-to-linear speedup on multicore systems. - ! Second improvement gives constant speedup (2-3x depending on your CPU) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - - -INPUT PARAMETERS: - Network - neural network; - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Sparse matrix must use CRS format for - storage. - SetSize - real size of XY, SetSize>=0; - it is used when SubsetSize<0; - Subset - subset of SubsetSize elements, array[SubsetSize]; - SubsetSize- number of elements in Subset[] array. - -RESULT: - sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -dataset format is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 04.09.2012 by Bochkanov Sergey -*************************************************************************/ -double mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); -double smp_mlperrorsparsesubset(const multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize); - -/************************************************************************* -This subroutine trains logit model. - -INPUT PARAMETERS: - XY - training set, array[0..NPoints-1,0..NVars] - First NVars columns store values of independent - variables, next column stores number of class (from 0 - to NClasses-1) which dataset element belongs to. Fractional - values are rounded to nearest integer. - NPoints - training set size, NPoints>=1 - NVars - number of independent variables, NVars>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints=1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreate(const ae_int_t n, mcpdstate &s); - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "entry" state and is treated -in a special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -Such conditions basically mean that row of P which corresponds to "entry" -state is zero. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - at every moment of time there is some - (unpredictable) amount of "new" individuals, which can transit into one - of the states at the next turn, but still no one leaves population -* you want to model transitions of individuals from one state into another -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s); - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] -is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -and one selected component of X[] is called "exit" state and is treated -in a special way: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that column of P which corresponds to -"exit" state is zero. Multiplication by such P may decrease sum of vector -components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant - individuals can move into "exit" state - and leave population at the next turn, but there are no new individuals -* amount of individuals which leave population can be predicted -* you want to model transitions of individuals from one state into another - (including transitions into the "exit" state) - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s); - - -/************************************************************************* -DESCRIPTION: - -This function is a specialized version of MCPDCreate() function, and we -recommend you to read comments for this function for general information -about MCPD solver. - -This function creates MCPD (Markov Chains for Population Data) solver -for "Entry-Exit-states" model, i.e. model where transition from X[i] to -X[i+1] is modelled as - X[i+1] = P*X[i] -where - X[i] and X[i+1] are N-dimensional state vectors - P is a N*N transition matrix -one selected component of X[] is called "entry" state and is treated in a -special way: - system state always transits from "entry" state to some another state - system state can not transit from any state into "entry" state -and another one component of X[] is called "exit" state and is treated in -a special way too: - system state can transit from any state into "exit" state - system state can not transit from "exit" state into any other state - transition operator discards "exit" state (makes it zero at each turn) -Such conditions basically mean that: - row of P which corresponds to "entry" state is zero - column of P which corresponds to "exit" state is zero -Multiplication by such P may decrease sum of vector components. - -Such models arise when: -* there is some population of individuals -* individuals can have different states -* individuals can transit from one state to another -* population size is NOT constant -* at every moment of time there is some (unpredictable) amount of "new" - individuals, which can transit into one of the states at the next turn -* some individuals can move (predictably) into "exit" state and leave - population at the next turn -* you want to model transitions of individuals from one state into another, - including transitions from the "entry" state and into the "exit" state. -* but you do NOT want to predict amount of "new" individuals because it - does not depends on individuals already present (hence system can not - transit INTO entry state - it can only transit FROM it). - -This model is discussed in more details in the ALGLIB User Guide (see -http://www.alglib.net/dataanalysis/ for more data). - -INPUT PARAMETERS: - N - problem dimension, N>=2 - EntryState- index of entry state, in 0..N-1 - ExitState- index of exit state, in 0..N-1 - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s); - - -/************************************************************************* -This function is used to add a track - sequence of system states at the -different moments of its evolution. - -You may add one or several tracks to the MCPD solver. In case you have -several tracks, they won't overwrite each other. For example, if you pass -two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then -solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, -t=B+1 to t=B+2, t=B+2 to t=B+3. But it WON'T mix these two tracks - i.e. it -won't try to model transition from t=A+3 to t=B+1. - -INPUT PARAMETERS: - S - solver - XY - track, array[K,N]: - * I-th row is a state at t=I - * elements of XY must be non-negative (exception will be - thrown on negative elements) - K - number of points in a track - * if given, only leading K rows of XY are used - * if not given, automatically determined from size of XY - -NOTES: - -1. Track may contain either proportional or population data: - * with proportional data all rows of XY must sum to 1.0, i.e. we have - proportions instead of absolute population values - * with population data rows of XY contain population counts and generally - do not sum to 1.0 (although they still must be non-negative) - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy, const ae_int_t k); -void mcpdaddtrack(const mcpdstate &s, const real_2d_array &xy); - - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place equality constraints on arbitrary -subset of elements of P. Set of constraints is specified by EC, which may -contain either NAN's or finite numbers from [0,1]. NAN denotes absence of -constraint, finite number denotes equality constraint on specific element -of P. - -You can also use MCPDAddEC() function which allows to ADD equality -constraint for one element of P without changing constraints for other -elements. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - EC - equality constraints, array[N,N]. Elements of EC can be - either NAN's or finite numbers from [0,1]. NAN denotes - absence of constraints, while finite value denotes - equality constraint on the corresponding element of P. - -NOTES: - -1. infinite values of EC will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetec(const mcpdstate &s, const real_2d_array &ec); - - -/************************************************************************* -This function is used to add equality constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD equality constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetEC() function which allows you to specify -arbitrary set of equality constraints in one call. - -These functions (MCPDSetEC and MCPDAddEC) interact as follows: -* there is internal matrix of equality constraints which is stored in the - MCPD solver -* MCPDSetEC() replaces this matrix by another one (SET) -* MCPDAddEC() modifies one element of this matrix and leaves other ones - unchanged (ADD) -* thus MCPDAddEC() call preserves all modifications done by previous - calls, while MCPDSetEC() completely discards all changes done to the - equality constraints. - -INPUT PARAMETERS: - S - solver - I - row index of element being constrained - J - column index of element being constrained - C - value (constraint for P[I,J]). Can be either NAN (no - constraint) or finite value from [0,1]. - -NOTES: - -1. infinite values of C will lead to exception being thrown. Values less -than 0.0 or greater than 1.0 will lead to error code being returned after -call to MCPDSolve(). - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdaddec(const mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c); - - -/************************************************************************* -This function is used to add bound constraints on the elements of the -transition matrix P. - -MCPD solver has four types of constraints which can be placed on P: -* user-specified equality constraints (optional) -* user-specified bound constraints (optional) -* user-specified general linear constraints (optional) -* basic constraints (always present): - * non-negativity: P[i,j]>=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to place bound constraints on arbitrary -subset of elements of P. Set of constraints is specified by BndL/BndU -matrices, which may contain arbitrary combination of finite numbers or -infinities (like -INF=0 - * consistency: every column of P sums to 1.0 - -Final constraints which are passed to the underlying optimizer are -calculated as intersection of all present constraints. For example, you -may specify boundary constraint on P[0,0] and equality one: - 0.1<=P[0,0]<=0.9 - P[0,0]=0.5 -Such combination of constraints will be silently reduced to their -intersection, which is P[0,0]=0.5. - -This function can be used to ADD bound constraint for one element of P -without changing constraints for other elements. - -You can also use MCPDSetBC() function which allows to place bound -constraints on arbitrary subset of elements of P. Set of constraints is -specified by BndL/BndU matrices, which may contain arbitrary combination -of finite numbers or infinities (like -INF=" (CT[i]>0). - -Your constraint may involve only some subset of P (less than N*N elements). -For example it can be something like - P[0,0] + P[0,1] = 0.5 -In this case you still should pass matrix with N*N+1 columns, but all its -elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. - -INPUT PARAMETERS: - S - solver - C - array[K,N*N+1] - coefficients of constraints - (see above for complete description) - CT - array[K] - constraint types - (see above for complete description) - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); -void mcpdsetlc(const mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct); - - -/************************************************************************* -This function allows to tune amount of Tikhonov regularization being -applied to your problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change coefficient r. You can also change -prior values with MCPDSetPrior() function. - -INPUT PARAMETERS: - S - solver - V - regularization coefficient, finite non-negative value. It - is not recommended to specify zero value unless you are - pretty sure that you want it. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsettikhonovregularizer(const mcpdstate &s, const double v); - - -/************************************************************************* -This function allows to set prior values used for regularization of your -problem. - -By default, regularizing term is equal to r*||P-prior_P||^2, where r is a -small non-zero value, P is transition matrix, prior_P is identity matrix, -||X||^2 is a sum of squared elements of X. - -This function allows you to change prior values prior_P. You can also -change r with MCPDSetTikhonovRegularizer() function. - -INPUT PARAMETERS: - S - solver - PP - array[N,N], matrix of prior values: - 1. elements must be real numbers from [0,1] - 2. columns must sum to 1.0. - First property is checked (exception is thrown otherwise), - while second one is not checked/enforced. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetprior(const mcpdstate &s, const real_2d_array &pp); - - -/************************************************************************* -This function is used to change prediction weights - -MCPD solver scales prediction errors as follows - Error(P) = ||W*(y-P*x)||^2 -where - x is a system state at time t - y is a system state at time t+1 - P is a transition matrix - W is a diagonal scaling matrix - -By default, weights are chosen in order to minimize relative prediction -error instead of absolute one. For example, if one component of state is -about 0.5 in magnitude and another one is about 0.05, then algorithm will -make corresponding weights equal to 2.0 and 20.0. - -INPUT PARAMETERS: - S - solver - PW - array[N], weights: - * must be non-negative values (exception will be thrown otherwise) - * zero values will be replaced by automatically chosen values - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsetpredictionweights(const mcpdstate &s, const real_1d_array &pw); - - -/************************************************************************* -This function is used to start solution of the MCPD problem. - -After return from this function, you can use MCPDResults() to get solution -and completion code. - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdsolve(const mcpdstate &s); - - -/************************************************************************* -MCPD results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - P - array[N,N], transition matrix - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one. Speaking short, positive values denote - success, negative ones are failures. - More information about fields of this structure can be - found in the comments on MCPDReport datatype. - - - -- ALGLIB -- - Copyright 23.05.2010 by Bochkanov Sergey -*************************************************************************/ -void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep); - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void mlpeserialize(mlpensemble &obj, std::string &s_out); - - -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void mlpeunserialize(std::string &s_in, mlpensemble &obj); - - -/************************************************************************* -Like MLPCreate0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreate1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreate2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateB0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateB1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateB2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateR0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateR1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateR2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateC0, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateC1, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Like MLPCreateC2, but for ensembles. - - -- ALGLIB -- - Copyright 18.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Creates ensemble from network. Only network geometry is copied. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble); - - -/************************************************************************* -Randomization of MLP ensemble - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlperandomize(const mlpensemble &ensemble); - - -/************************************************************************* -Return ensemble properties (number of inputs and outputs). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout); - - -/************************************************************************* -Return normalization type (whether ensemble is SOFTMAX-normalized or not). - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -bool mlpeissoftmax(const mlpensemble &ensemble); - - -/************************************************************************* -Procesing - -INPUT PARAMETERS: - Ensemble- neural networks ensemble - X - input vector, array[0..NIn-1]. - Y - (possibly) preallocated buffer; if size of Y is less than - NOut, it will be reallocated. If it is large enough, it - is NOT reallocated, so we can save some time on reallocation. - - -OUTPUT PARAMETERS: - Y - result. Regression estimate when solving regression task, - vector of posterior probabilities for classification task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocess(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -'interactive' variant of MLPEProcess for languages like Python which -support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the -interpreter - -This function allocates new array on each call, so it is significantly -slower than its 'non-interactive' counterpart, but it is more convenient -when you call it from command line. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpeprocessi(const mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -Relative classification error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - percent of incorrectly classified cases. - Works both for classifier betwork and for regression networks which -are used as classifiers. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlperelclserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average cross-entropy (in bits per element) on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - CrossEntropy/(NPoints*LN(2)). - Zero if ensemble solves regression task. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgce(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -RMS error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - root mean square error. - Its meaning for regression task is obvious. As for classification task -RMS error means error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpermserror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -Average relative error on the test set - -INPUT PARAMETERS: - Ensemble- ensemble - XY - test set - NPoints - test set size - -RESULT: - Its meaning for regression task is obvious. As for classification task -it means average relative error when estimating posterior probabilities. - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -double mlpeavgrelerror(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints); - -/************************************************************************* -Neural network training using modified Levenberg-Marquardt with exact -Hessian calculation and regularization. Subroutine trains neural network -with restarts from random positions. Algorithm is well suited for small -and medium scale problems (hundreds of weights). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -9, if internal matrix inverse subroutine failed - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); - - -/************************************************************************* -Neural network training using L-BFGS algorithm with regularization. -Subroutine trains neural network with restarts from random positions. -Algorithm is well suited for problems of any dimensionality (memory -requirements and step complexity are linear by weights number). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts from random position, >0. - If you don't know what Restarts to choose, use 2. - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - MaxIts - stopping criterion. Algorithm stops after MaxIts - iterations (NOT gradient calculations). Zero MaxIts - means stopping when step is sufficiently small. - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlptrainlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep); - - -/************************************************************************* -Neural network training using early stopping (base algorithm - L-BFGS with -regularization). - -INPUT PARAMETERS: - Network - neural network with initialized geometry - TrnXY - training set - TrnSize - training set size, TrnSize>0 - ValXY - validation set - ValSize - validation set size, ValSize>0 - Decay - weight decay constant, >=0.001 - Decay term 'Decay*||Weights||^2' is added to error - function. - If you don't know what Decay to choose, use 0.001. - Restarts - number of restarts, either: - * strictly positive number - algorithm make specified - number of restarts from random position. - * -1, in which case algorithm makes exactly one run - from the initial state of the network (no randomization). - If you don't know what Restarts to choose, choose one - one the following: - * -1 (deterministic start) - * +1 (one random restart) - * +5 (moderate amount of random restarts) - -OUTPUT PARAMETERS: - Network - trained neural network. - Info - return code: - * -2, if there is a point with class number - outside of [0..NOut-1]. - * -1, if wrong parameters specified - (NPoints<0, Restarts<1, ...). - * 2, task has been solved, stopping criterion met - - sufficiently small step size. Not expected (we - use EARLY stopping) but possible and not an - error. - * 6, task has been solved, stopping criterion met - - increasing of validation set error. - Rep - training report - -NOTE: - -Algorithm stops if validation set error increases for a long enough or -step size is small enought (there are task where validation set may -decrease for eternity). In any case solution returned corresponds to the -minimum of validation set error. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlptraines(const multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); - - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - L-BFGS. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep); - - -/************************************************************************* -Cross-validation estimate of generalization error. - -Base algorithm - Levenberg-Marquardt. - -INPUT PARAMETERS: - Network - neural network with initialized geometry. Network is - not changed during cross-validation - it is used only - as a representative of its architecture. - XY - training set. - SSize - training set size - Decay - weight decay, same as in MLPTrainLBFGS - Restarts - number of restarts, >0. - restarts are counted for each partition separately, so - total number of restarts will be Restarts*FoldsCount. - FoldsCount - number of folds in k-fold cross-validation, - 2<=FoldsCount<=SSize. - recommended value: 10. - -OUTPUT PARAMETERS: - Info - return code, same as in MLPTrainLBFGS - Rep - report, same as in MLPTrainLM/MLPTrainLBFGS - CVRep - generalization error estimates - - -- ALGLIB -- - Copyright 09.12.2007 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep); - - -/************************************************************************* -This function estimates generalization error using cross-validation on the -current dataset with current training settings. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * FoldsCount cross-validation rounds (always) - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. Network is not changed during cross- - validation and is not trained - it is used only as - representative of its architecture. I.e., we estimate - generalization properties of ARCHITECTURE, not some - specific network. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that for each cross-validation - round specified number of random restarts is - performed, with best network being chosen after - training. - * NRestarts=0 is same as NRestarts=1 - FoldsCount - number of folds in k-fold cross-validation: - * 2<=FoldsCount<=size of dataset - * recommended value: 10. - * values larger than dataset size will be silently - truncated down to dataset size - -OUTPUT PARAMETERS: - Rep - structure which contains cross-validation estimates: - * Rep.RelCLSError - fraction of misclassified cases. - * Rep.AvgCE - acerage cross-entropy - * Rep.RMSError - root-mean-square error - * Rep.AvgError - average error - * Rep.AvgRelError - average relative error - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or subset with only one point was given, zeros are returned as - estimates. - -NOTE: this method performs FoldsCount cross-validation rounds, each one - with NRestarts random starts. Thus, FoldsCount*NRestarts networks - are trained in total. - -NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. - -NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError - contain errors in prediction of posterior probabilities. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep); -void smp_mlpkfoldcv(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep); - - -/************************************************************************* -Creation of the network trainer object for regression networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NOut - number of outputs, NOut>=1 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any regression - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s); - - -/************************************************************************* -Creation of the network trainer object for classification networks - -INPUT PARAMETERS: - NIn - number of inputs, NIn>=1 - NClasses - number of classes, NClasses>=2 - -OUTPUT PARAMETERS: - S - neural network trainer object. - This structure can be used to train any classification - network with NIn inputs and NOut outputs. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s); - - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user. - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. - NPoints - points count, >=0. - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdataset(const mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints); - - -/************************************************************************* -This function sets "current dataset" of the trainer object to one passed -by user (sparse matrix is used to store dataset). - -INPUT PARAMETERS: - S - trainer object - XY - training set, see below for information on the - training set format. This function checks correctness - of the dataset (no NANs/INFs, class numbers are - correct) and throws exception when incorrect dataset - is passed. Any sparse storage format can be used: - Hash-table, CRS... - NPoints - points count, >=0 - -DATASET FORMAT: - -This function uses two different dataset formats - one for regression -networks, another one for classification networks. - -For regression networks with NIn inputs and NOut outputs following dataset -format is used: -* dataset is given by NPoints*(NIn+NOut) matrix -* each row corresponds to one example -* first NIn columns are inputs, next NOut columns are outputs - -For classification networks with NIn inputs and NClasses clases following -datasetformat is used: -* dataset is given by NPoints*(NIn+1) matrix -* each row corresponds to one example -* first NIn columns are inputs, last column stores class number (from 0 to - NClasses-1). - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetsparsedataset(const mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints); - - -/************************************************************************* -This function sets weight decay coefficient which is used for training. - -INPUT PARAMETERS: - S - trainer object - Decay - weight decay coefficient, >=0. Weight decay term - 'Decay*||Weights||^2' is added to error function. If - you don't know what Decay to choose, use 1.0E-3. - Weight decay can be set to zero, in this case network - is trained without weight decay. - -NOTE: by default network uses some small nonzero value for weight decay. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetdecay(const mlptrainer &s, const double decay); - - -/************************************************************************* -This function sets stopping criteria for the optimizer. - -INPUT PARAMETERS: - S - trainer object - WStep - stopping criterion. Algorithm stops if step size is - less than WStep. Recommended value - 0.01. Zero step - size means stopping after MaxIts iterations. - WStep>=0. - MaxIts - stopping criterion. Algorithm stops after MaxIts - epochs (full passes over entire dataset). Zero MaxIts - means stopping when step is sufficiently small. - MaxIts>=0. - -NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also - used when MLPSetCond() is called with WStep=0 and MaxIts=0. - -NOTE: these stopping criteria are used for all kinds of neural training - - from "conventional" networks to early stopping ensembles. When used - for "conventional" networks, they are used as the only stopping - criteria. When combined with early stopping, they used as ADDITIONAL - stopping criteria which can terminate early stopping algorithm. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetcond(const mlptrainer &s, const double wstep, const ae_int_t maxits); - - -/************************************************************************* -This function sets training algorithm: batch training using L-BFGS will be -used. - -This algorithm: -* the most robust for small-scale problems, but may be too slow for large - scale ones. -* perfoms full pass through the dataset before performing step -* uses conditions specified by MLPSetCond() for stopping -* is default one used by trainer object - -INPUT PARAMETERS: - S - trainer object - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpsetalgobatch(const mlptrainer &s); - - -/************************************************************************* -This function trains neural network passed to this function, using current -dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) -and current training settings. Training from NRestarts random starting -positions is performed, best network is chosen. - -Training is performed using current training algorithm. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * NRestarts training sessions performed within each of - ! cross-validation rounds (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed, best network is chosen after - training - * NRestarts=0 means that current state of the network - is used for training. - -OUTPUT PARAMETERS: - Network - trained network - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - network is filled by zero values. Same behavior for functions - MLPStartTraining and MLPContinueTraining. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep); -void smp_mlptrainnetwork(const mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep); - - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -After call to this function trainer object remembers network and is ready -to train it. However, no training is performed until first call to -MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() -will advance training progress one iteration further. - -EXAMPLE: - > - > ...initialize network and trainer object.... - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > ...visualize training progress... - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network. It must have same number of inputs and - output/classes as was specified during creation of the - trainer object. - RandomStart - randomize network before training or not: - * True means that network is randomized and its - initial state (one which was passed to the trainer - object) is lost. - * False means that training is started from the - current state of the network - -OUTPUT PARAMETERS: - Network - neural network which is ready to training (weights are - initialized, preprocessor is initialized using current - training set) - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -void mlpstarttraining(const mlptrainer &s, const multilayerperceptron &network, const bool randomstart); - - -/************************************************************************* -IMPORTANT: this is an "expert" version of the MLPTrain() function. We do - not recommend you to use it unless you are pretty sure that you - need ability to monitor training progress. - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -This function performs step-by-step training of the neural network. Here -"step-by-step" means that training starts with MLPStartTraining() call, -and then user subsequently calls MLPContinueTraining() to perform one more -iteration of the training. - -This function performs one more iteration of the training and returns -either True (training continues) or False (training stopped). In case True -was returned, Network weights are updated according to the current state -of the optimization progress. In case False was returned, no additional -updates is performed (previous update of the network weights moved us to -the final point, and no additional updates is needed). - -EXAMPLE: - > - > [initialize network and trainer object] - > - > MLPStartTraining(Trainer, Network, True) - > while MLPContinueTraining(Trainer, Network) do - > [visualize training progress] - > - -INPUT PARAMETERS: - S - trainer object - Network - neural network structure, which is used to store - current state of the training process. - -OUTPUT PARAMETERS: - Network - weights of the neural network are rewritten by the - current approximation. - -NOTE: this method uses sum-of-squares error function for training. - -NOTE: it is expected that trainer object settings are NOT changed during - step-by-step training, i.e. no one changes stopping criteria or - training set during training. It is possible and there is no defense - against such actions, but algorithm behavior in such cases is - undefined and can be unpredictable. - -NOTE: It is expected that Network is the same one which was passed to - MLPStartTraining() function. However, THIS function checks only - following: - * that number of network inputs is consistent with trainer object - settings - * that number of network outputs/classes is consistent with trainer - object settings - * that number of network weights is the same as number of weights in - the network passed to MLPStartTraining() function - Exception is thrown when these conditions are violated. - - It is also expected that you do not change state of the network on - your own - the only party who has right to change network during its - training is a trainer object. Any attempt to interfere with trainer - may lead to unpredictable results. - - - -- ALGLIB -- - Copyright 23.07.2012 by Bochkanov Sergey -*************************************************************************/ -bool mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network); -bool smp_mlpcontinuetraining(const mlptrainer &s, const multilayerperceptron &network); - - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -Modified Levenberg-Marquardt algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglm(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors); - - -/************************************************************************* -Training neural networks ensemble using bootstrap aggregating (bagging). -L-BFGS algorithm is used as base training method. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - WStep - stopping criterion, same as in MLPTrainLBFGS - MaxIts - stopping criterion, same as in MLPTrainLBFGS - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -8, if both WStep=0 and MaxIts=0 - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 2, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 17.02.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpebagginglbfgs(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors); - - -/************************************************************************* -Training neural networks ensemble using early stopping. - -INPUT PARAMETERS: - Ensemble - model with initialized geometry - XY - training set - NPoints - training set size - Decay - weight decay coefficient, >=0.001 - Restarts - restarts, >0. - -OUTPUT PARAMETERS: - Ensemble - trained model - Info - return code: - * -2, if there is a point with class number - outside of [0..NClasses-1]. - * -1, if incorrect parameters was passed - (NPoints<0, Restarts<1). - * 6, if task has been solved. - Rep - training report. - OOBErrors - out-of-bag generalization error estimate - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void mlpetraines(const mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep); - - -/************************************************************************* -This function trains neural network ensemble passed to this function using -current dataset and early stopping training algorithm. Each early stopping -round performs NRestarts random restarts (thus, EnsembleSize*NRestarts -training rounds is performed in total). - -FOR USERS OF COMMERCIAL EDITION: - - ! Commercial version of ALGLIB includes two important improvements of - ! this function: - ! * multicore support (C++ and C# computational cores) - ! * SSE support (C++ computational core) - ! - ! Second improvement gives constant speedup (2-3X). First improvement - ! gives close-to-linear speedup on multicore systems. Following - ! operations can be executed in parallel: - ! * EnsembleSize training sessions performed for each of ensemble - ! members (always parallelized) - ! * NRestarts training sessions performed within each of training - ! sessions (if NRestarts>1) - ! * gradient calculation over large dataset (if dataset is large enough) - ! - ! In order to use multicore features you have to: - ! * use commercial version of ALGLIB - ! * call this function with "smp_" prefix, which indicates that - ! multicore code will be used (for multicore support) - ! - ! In order to use SSE features you have to: - ! * use commercial version of ALGLIB on Intel processors - ! * use C++ computational core - ! - ! This note is given for users of commercial edition; if you use GPL - ! edition, you still will be able to call smp-version of this function, - ! but all computations will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - -INPUT PARAMETERS: - S - trainer object; - Ensemble - neural network ensemble. It must have same number of - inputs and outputs/classes as was specified during - creation of the trainer object. - NRestarts - number of restarts, >=0: - * NRestarts>0 means that specified number of random - restarts are performed during each ES round; - * NRestarts=0 is silently replaced by 1. - -OUTPUT PARAMETERS: - Ensemble - trained ensemble; - Rep - it contains all type of errors. - -NOTE: this training method uses BOTH early stopping and weight decay! So, - you should select weight decay before starting training just as you - select it before training "conventional" networks. - -NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), - or single-point dataset was passed, ensemble is filled by zero - values. - -NOTE: this method uses sum-of-squares error function for training. - - -- ALGLIB -- - Copyright 22.08.2012 by Bochkanov Sergey -*************************************************************************/ -void mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep); -void smp_mlptrainensemblees(const mlptrainer &s, const mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep); - -/************************************************************************* -Principal components analysis - -Subroutine builds orthogonal basis where first axis corresponds to -direction with maximum variance, second axis maximizes variance in subspace -orthogonal to first axis and so on. - -It should be noted that, unlike LDA, PCA does not use class labels. - -INPUT PARAMETERS: - X - dataset, array[0..NPoints-1,0..NVars-1]. - matrix contains ONLY INDEPENDENT VARIABLES. - NPoints - dataset size, NPoints>=0 - NVars - number of independent variables, NVars>=1 - -ÂÛÕÎÄÍÛÅ ÏÀÐÀÌÅÒÐÛ: - Info - return code: - * -4, if SVD subroutine haven't converged - * -1, if wrong parameters has been passed (NPoints<0, - NVars<1) - * 1, if task is solved - S2 - array[0..NVars-1]. variance values corresponding - to basis vectors. - V - array[0..NVars-1,0..NVars-1] - matrix, whose columns store basis vectors. - - -- ALGLIB -- - Copyright 25.08.2008 by Bochkanov Sergey -*************************************************************************/ -void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, ae_int_t &info, real_1d_array &s2, real_2d_array &v); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void dserrallocate(ae_int_t nclasses, - /* Real */ ae_vector* buf, - ae_state *_state); -void dserraccumulate(/* Real */ ae_vector* buf, - /* Real */ ae_vector* y, - /* Real */ ae_vector* desiredy, - ae_state *_state); -void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state); -void dsnormalize(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* means, - /* Real */ ae_vector* sigmas, - ae_state *_state); -void dsnormalizec(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* means, - /* Real */ ae_vector* sigmas, - ae_state *_state); -double dsgetmeanmindistance(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_state *_state); -void dstie(/* Real */ ae_vector* a, - ae_int_t n, - /* Integer */ ae_vector* ties, - ae_int_t* tiecount, - /* Integer */ ae_vector* p1, - /* Integer */ ae_vector* p2, - ae_state *_state); -void dstiefasti(/* Real */ ae_vector* a, - /* Integer */ ae_vector* b, - ae_int_t n, - /* Integer */ ae_vector* ties, - ae_int_t* tiecount, - /* Real */ ae_vector* bufr, - /* Integer */ ae_vector* bufi, - ae_state *_state); -void dsoptimalsplit2(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t* info, - double* threshold, - double* pal, - double* pbl, - double* par, - double* pbr, - double* cve, - ae_state *_state); -void dsoptimalsplit2fast(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - /* Integer */ ae_vector* tiesbuf, - /* Integer */ ae_vector* cntbuf, - /* Real */ ae_vector* bufr, - /* Integer */ ae_vector* bufi, - ae_int_t n, - ae_int_t nc, - double alpha, - ae_int_t* info, - double* threshold, - double* rms, - double* cvrms, - ae_state *_state); -void dssplitk(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t nc, - ae_int_t kmax, - ae_int_t* info, - /* Real */ ae_vector* thresholds, - ae_int_t* ni, - double* cve, - ae_state *_state); -void dsoptimalsplitk(/* Real */ ae_vector* a, - /* Integer */ ae_vector* c, - ae_int_t n, - ae_int_t nc, - ae_int_t kmax, - ae_int_t* info, - /* Real */ ae_vector* thresholds, - ae_int_t* ni, - double* cve, - ae_state *_state); -ae_bool _cvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _cvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _cvreport_clear(void* _p); -void _cvreport_destroy(void* _p); -void clusterizercreate(clusterizerstate* s, ae_state *_state); -void clusterizersetpoints(clusterizerstate* s, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - ae_state *_state); -void clusterizersetdistances(clusterizerstate* s, - /* Real */ ae_matrix* d, - ae_int_t npoints, - ae_bool isupper, - ae_state *_state); -void clusterizersetahcalgo(clusterizerstate* s, - ae_int_t algo, - ae_state *_state); -void clusterizersetkmeanslimits(clusterizerstate* s, - ae_int_t restarts, - ae_int_t maxits, - ae_state *_state); -void clusterizerrunahc(clusterizerstate* s, - ahcreport* rep, - ae_state *_state); -void _pexec_clusterizerrunahc(clusterizerstate* s, - ahcreport* rep, ae_state *_state); -void clusterizerrunkmeans(clusterizerstate* s, - ae_int_t k, - kmeansreport* rep, - ae_state *_state); -void clusterizergetdistances(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, - ae_state *_state); -void _pexec_clusterizergetdistances(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_int_t disttype, - /* Real */ ae_matrix* d, ae_state *_state); -void clusterizergetkclusters(ahcreport* rep, - ae_int_t k, - /* Integer */ ae_vector* cidx, - /* Integer */ ae_vector* cz, - ae_state *_state); -void clusterizerseparatedbydist(ahcreport* rep, - double r, - ae_int_t* k, - /* Integer */ ae_vector* cidx, - /* Integer */ ae_vector* cz, - ae_state *_state); -void clusterizerseparatedbycorr(ahcreport* rep, - double r, - ae_int_t* k, - /* Integer */ ae_vector* cidx, - /* Integer */ ae_vector* cz, - ae_state *_state); -void kmeansgenerateinternal(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t k, - ae_int_t maxits, - ae_int_t restarts, - ae_int_t* info, - /* Real */ ae_matrix* ccol, - ae_bool needccol, - /* Real */ ae_matrix* crow, - ae_bool needcrow, - /* Integer */ ae_vector* xyc, - ae_state *_state); -ae_bool _clusterizerstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _clusterizerstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _clusterizerstate_clear(void* _p); -void _clusterizerstate_destroy(void* _p); -ae_bool _ahcreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _ahcreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _ahcreport_clear(void* _p); -void _ahcreport_destroy(void* _p); -ae_bool _kmeansreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _kmeansreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _kmeansreport_clear(void* _p); -void _kmeansreport_destroy(void* _p); -void kmeansgenerate(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t k, - ae_int_t restarts, - ae_int_t* info, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* xyc, - ae_state *_state); -void dfbuildrandomdecisionforest(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - double r, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state); -void dfbuildrandomdecisionforestx1(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - ae_int_t nrndvars, - double r, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state); -void dfbuildinternal(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t ntrees, - ae_int_t samplesize, - ae_int_t nfeatures, - ae_int_t flags, - ae_int_t* info, - decisionforest* df, - dfreport* rep, - ae_state *_state); -void dfprocess(decisionforest* df, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void dfprocessi(decisionforest* df, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -double dfrelclserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double dfavgce(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double dfrmserror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double dfavgerror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double dfavgrelerror(decisionforest* df, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -void dfcopy(decisionforest* df1, decisionforest* df2, ae_state *_state); -void dfalloc(ae_serializer* s, decisionforest* forest, ae_state *_state); -void dfserialize(ae_serializer* s, - decisionforest* forest, - ae_state *_state); -void dfunserialize(ae_serializer* s, - decisionforest* forest, - ae_state *_state); -ae_bool _decisionforest_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _decisionforest_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _decisionforest_clear(void* _p); -void _decisionforest_destroy(void* _p); -ae_bool _dfreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _dfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _dfreport_clear(void* _p); -void _dfreport_destroy(void* _p); -ae_bool _dfinternalbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _dfinternalbuffers_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _dfinternalbuffers_clear(void* _p); -void _dfinternalbuffers_destroy(void* _p); -void lrbuild(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state); -void lrbuilds(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state); -void lrbuildzs(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state); -void lrbuildz(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - linearmodel* lm, - lrreport* ar, - ae_state *_state); -void lrunpack(linearmodel* lm, - /* Real */ ae_vector* v, - ae_int_t* nvars, - ae_state *_state); -void lrpack(/* Real */ ae_vector* v, - ae_int_t nvars, - linearmodel* lm, - ae_state *_state); -double lrprocess(linearmodel* lm, - /* Real */ ae_vector* x, - ae_state *_state); -double lrrmserror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double lravgerror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double lravgrelerror(linearmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -void lrcopy(linearmodel* lm1, linearmodel* lm2, ae_state *_state); -void lrlines(/* Real */ ae_matrix* xy, - /* Real */ ae_vector* s, - ae_int_t n, - ae_int_t* info, - double* a, - double* b, - double* vara, - double* varb, - double* covab, - double* corrab, - double* p, - ae_state *_state); -void lrline(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t* info, - double* a, - double* b, - ae_state *_state); -ae_bool _linearmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _linearmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _linearmodel_clear(void* _p); -void _linearmodel_destroy(void* _p); -ae_bool _lrreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _lrreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _lrreport_clear(void* _p); -void _lrreport_destroy(void* _p); -void filtersma(/* Real */ ae_vector* x, - ae_int_t n, - ae_int_t k, - ae_state *_state); -void filterema(/* Real */ ae_vector* x, - ae_int_t n, - double alpha, - ae_state *_state); -void filterlrma(/* Real */ ae_vector* x, - ae_int_t n, - ae_int_t k, - ae_state *_state); -void fisherlda(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t* info, - /* Real */ ae_vector* w, - ae_state *_state); -void fisherldan(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t* info, - /* Real */ ae_matrix* w, - ae_state *_state); -ae_int_t mlpgradsplitcost(ae_state *_state); -ae_int_t mlpgradsplitsize(ae_state *_state); -void mlpcreate0(ae_int_t nin, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcreate1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcreate2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcreateb0(ae_int_t nin, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state); -void mlpcreateb1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state); -void mlpcreateb2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double b, - double d, - multilayerperceptron* network, - ae_state *_state); -void mlpcreater0(ae_int_t nin, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state); -void mlpcreater1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state); -void mlpcreater2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double a, - double b, - multilayerperceptron* network, - ae_state *_state); -void mlpcreatec0(ae_int_t nin, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcreatec1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcreatec2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - multilayerperceptron* network, - ae_state *_state); -void mlpcopy(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state); -void mlpcopyshared(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state); -ae_bool mlpsamearchitecture(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state); -void mlpcopytunableparameters(multilayerperceptron* network1, - multilayerperceptron* network2, - ae_state *_state); -void mlpexporttunableparameters(multilayerperceptron* network, - /* Real */ ae_vector* p, - ae_int_t* pcount, - ae_state *_state); -void mlpimporttunableparameters(multilayerperceptron* network, - /* Real */ ae_vector* p, - ae_state *_state); -void mlpserializeold(multilayerperceptron* network, - /* Real */ ae_vector* ra, - ae_int_t* rlen, - ae_state *_state); -void mlpunserializeold(/* Real */ ae_vector* ra, - multilayerperceptron* network, - ae_state *_state); -void mlprandomize(multilayerperceptron* network, ae_state *_state); -void mlprandomizefull(multilayerperceptron* network, ae_state *_state); -void mlpinitpreprocessor(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state); -void mlpinitpreprocessorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - ae_state *_state); -void mlpinitpreprocessorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - ae_state *_state); -void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - ae_state *_state); -void mlpproperties(multilayerperceptron* network, - ae_int_t* nin, - ae_int_t* nout, - ae_int_t* wcount, - ae_state *_state); -ae_int_t mlpntotal(multilayerperceptron* network, ae_state *_state); -ae_int_t mlpgetinputscount(multilayerperceptron* network, - ae_state *_state); -ae_int_t mlpgetoutputscount(multilayerperceptron* network, - ae_state *_state); -ae_int_t mlpgetweightscount(multilayerperceptron* network, - ae_state *_state); -ae_bool mlpissoftmax(multilayerperceptron* network, ae_state *_state); -ae_int_t mlpgetlayerscount(multilayerperceptron* network, - ae_state *_state); -ae_int_t mlpgetlayersize(multilayerperceptron* network, - ae_int_t k, - ae_state *_state); -void mlpgetinputscaling(multilayerperceptron* network, - ae_int_t i, - double* mean, - double* sigma, - ae_state *_state); -void mlpgetoutputscaling(multilayerperceptron* network, - ae_int_t i, - double* mean, - double* sigma, - ae_state *_state); -void mlpgetneuroninfo(multilayerperceptron* network, - ae_int_t k, - ae_int_t i, - ae_int_t* fkind, - double* threshold, - ae_state *_state); -double mlpgetweight(multilayerperceptron* network, - ae_int_t k0, - ae_int_t i0, - ae_int_t k1, - ae_int_t i1, - ae_state *_state); -void mlpsetinputscaling(multilayerperceptron* network, - ae_int_t i, - double mean, - double sigma, - ae_state *_state); -void mlpsetoutputscaling(multilayerperceptron* network, - ae_int_t i, - double mean, - double sigma, - ae_state *_state); -void mlpsetneuroninfo(multilayerperceptron* network, - ae_int_t k, - ae_int_t i, - ae_int_t fkind, - double threshold, - ae_state *_state); -void mlpsetweight(multilayerperceptron* network, - ae_int_t k0, - ae_int_t i0, - ae_int_t k1, - ae_int_t i1, - double w, - ae_state *_state); -void mlpactivationfunction(double net, - ae_int_t k, - double* f, - double* df, - double* d2f, - ae_state *_state); -void mlpprocess(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mlpprocessi(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -double mlperror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlperror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlperrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlperrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -double mlperrorn(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state); -ae_int_t mlpclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -ae_int_t _pexec_mlpclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlprelclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlprelclserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlprelclserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlprelclserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgce(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgce(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgcesparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgcesparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -double mlprmserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlprmserror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlprmserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlprmserrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgrelerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgrelerror(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, ae_state *_state); -double mlpavgrelerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -double _pexec_mlpavgrelerrorsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t npoints, ae_state *_state); -void mlpgrad(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* desiredy, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void mlpgradn(multilayerperceptron* network, - /* Real */ ae_vector* x, - /* Real */ ae_vector* desiredy, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void mlpgradbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void _pexec_mlpgradbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state); -void mlpgradbatchsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void _pexec_mlpgradbatchsparse(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state); -void mlpgradbatchsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void _pexec_mlpgradbatchsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state); -void mlpgradbatchsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void _pexec_mlpgradbatchsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* idx, - ae_int_t subsetsize, - double* e, - /* Real */ ae_vector* grad, ae_state *_state); -void mlpgradbatchx(multilayerperceptron* network, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - ae_shared_pool* gradbuf, - ae_state *_state); -void mlpgradnbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - ae_state *_state); -void mlphessiannbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state); -void mlphessianbatch(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - double* e, - /* Real */ ae_vector* grad, - /* Real */ ae_matrix* h, - ae_state *_state); -void mlpinternalprocessvector(/* Integer */ ae_vector* structinfo, - /* Real */ ae_vector* weights, - /* Real */ ae_vector* columnmeans, - /* Real */ ae_vector* columnsigmas, - /* Real */ ae_vector* neurons, - /* Real */ ae_vector* dfdnet, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mlpalloc(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state); -void mlpserialize(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state); -void mlpunserialize(ae_serializer* s, - multilayerperceptron* network, - ae_state *_state); -void mlpallerrorssubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, - ae_state *_state); -void _pexec_mlpallerrorssubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, ae_state *_state); -void mlpallerrorssparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, - ae_state *_state); -void _pexec_mlpallerrorssparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - modelerrors* rep, ae_state *_state); -double mlperrorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_state *_state); -double _pexec_mlperrorsubset(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, ae_state *_state); -double mlperrorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, - ae_state *_state); -double _pexec_mlperrorsparsesubset(multilayerperceptron* network, - sparsematrix* xy, - ae_int_t setsize, - /* Integer */ ae_vector* subset, - ae_int_t subsetsize, ae_state *_state); -void mlpallerrorsx(multilayerperceptron* network, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - modelerrors* rep, - ae_state *_state); -ae_bool _modelerrors_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _modelerrors_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _modelerrors_clear(void* _p); -void _modelerrors_destroy(void* _p); -ae_bool _smlpgrad_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _smlpgrad_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _smlpgrad_clear(void* _p); -void _smlpgrad_destroy(void* _p); -ae_bool _multilayerperceptron_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _multilayerperceptron_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _multilayerperceptron_clear(void* _p); -void _multilayerperceptron_destroy(void* _p); -void mnltrainh(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t nclasses, - ae_int_t* info, - logitmodel* lm, - mnlreport* rep, - ae_state *_state); -void mnlprocess(logitmodel* lm, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mnlprocessi(logitmodel* lm, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mnlunpack(logitmodel* lm, - /* Real */ ae_matrix* a, - ae_int_t* nvars, - ae_int_t* nclasses, - ae_state *_state); -void mnlpack(/* Real */ ae_matrix* a, - ae_int_t nvars, - ae_int_t nclasses, - logitmodel* lm, - ae_state *_state); -void mnlcopy(logitmodel* lm1, logitmodel* lm2, ae_state *_state); -double mnlavgce(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mnlrelclserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mnlrmserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mnlavgerror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mnlavgrelerror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t ssize, - ae_state *_state); -ae_int_t mnlclserror(logitmodel* lm, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -ae_bool _logitmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _logitmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _logitmodel_clear(void* _p); -void _logitmodel_destroy(void* _p); -ae_bool _logitmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _logitmcstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _logitmcstate_clear(void* _p); -void _logitmcstate_destroy(void* _p); -ae_bool _mnlreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mnlreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mnlreport_clear(void* _p); -void _mnlreport_destroy(void* _p); -void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state); -void mcpdcreateentry(ae_int_t n, - ae_int_t entrystate, - mcpdstate* s, - ae_state *_state); -void mcpdcreateexit(ae_int_t n, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state); -void mcpdcreateentryexit(ae_int_t n, - ae_int_t entrystate, - ae_int_t exitstate, - mcpdstate* s, - ae_state *_state); -void mcpdaddtrack(mcpdstate* s, - /* Real */ ae_matrix* xy, - ae_int_t k, - ae_state *_state); -void mcpdsetec(mcpdstate* s, - /* Real */ ae_matrix* ec, - ae_state *_state); -void mcpdaddec(mcpdstate* s, - ae_int_t i, - ae_int_t j, - double c, - ae_state *_state); -void mcpdsetbc(mcpdstate* s, - /* Real */ ae_matrix* bndl, - /* Real */ ae_matrix* bndu, - ae_state *_state); -void mcpdaddbc(mcpdstate* s, - ae_int_t i, - ae_int_t j, - double bndl, - double bndu, - ae_state *_state); -void mcpdsetlc(mcpdstate* s, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state); -void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state); -void mcpdsetprior(mcpdstate* s, - /* Real */ ae_matrix* pp, - ae_state *_state); -void mcpdsetpredictionweights(mcpdstate* s, - /* Real */ ae_vector* pw, - ae_state *_state); -void mcpdsolve(mcpdstate* s, ae_state *_state); -void mcpdresults(mcpdstate* s, - /* Real */ ae_matrix* p, - mcpdreport* rep, - ae_state *_state); -ae_bool _mcpdstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mcpdstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mcpdstate_clear(void* _p); -void _mcpdstate_destroy(void* _p); -ae_bool _mcpdreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mcpdreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mcpdreport_clear(void* _p); -void _mcpdreport_destroy(void* _p); -void mlpecreate0(ae_int_t nin, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreate1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreate2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreateb0(ae_int_t nin, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreateb1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreateb2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double b, - double d, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreater0(ae_int_t nin, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreater1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreater2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - double a, - double b, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreatec0(ae_int_t nin, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreatec1(ae_int_t nin, - ae_int_t nhid, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreatec2(ae_int_t nin, - ae_int_t nhid1, - ae_int_t nhid2, - ae_int_t nout, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecreatefromnetwork(multilayerperceptron* network, - ae_int_t ensemblesize, - mlpensemble* ensemble, - ae_state *_state); -void mlpecopy(mlpensemble* ensemble1, - mlpensemble* ensemble2, - ae_state *_state); -void mlperandomize(mlpensemble* ensemble, ae_state *_state); -void mlpeproperties(mlpensemble* ensemble, - ae_int_t* nin, - ae_int_t* nout, - ae_state *_state); -ae_bool mlpeissoftmax(mlpensemble* ensemble, ae_state *_state); -void mlpeprocess(mlpensemble* ensemble, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mlpeprocessi(mlpensemble* ensemble, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void mlpeallerrorsx(mlpensemble* ensemble, - /* Real */ ae_matrix* densexy, - sparsematrix* sparsexy, - ae_int_t datasetsize, - ae_int_t datasettype, - /* Integer */ ae_vector* idx, - ae_int_t subset0, - ae_int_t subset1, - ae_int_t subsettype, - ae_shared_pool* buf, - modelerrors* rep, - ae_state *_state); -void mlpeallerrorssparse(mlpensemble* ensemble, - sparsematrix* xy, - ae_int_t npoints, - double* relcls, - double* avgce, - double* rms, - double* avg, - double* avgrel, - ae_state *_state); -double mlperelclserror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mlpeavgce(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mlpermserror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mlpeavgerror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -double mlpeavgrelerror(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -void mlpealloc(ae_serializer* s, mlpensemble* ensemble, ae_state *_state); -void mlpeserialize(ae_serializer* s, - mlpensemble* ensemble, - ae_state *_state); -void mlpeunserialize(ae_serializer* s, - mlpensemble* ensemble, - ae_state *_state); -ae_bool _mlpensemble_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpensemble_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpensemble_clear(void* _p); -void _mlpensemble_destroy(void* _p); -void mlptrainlm(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state); -void mlptrainlbfgs(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - ae_state *_state); -void mlptraines(multilayerperceptron* network, - /* Real */ ae_matrix* trnxy, - ae_int_t trnsize, - /* Real */ ae_matrix* valxy, - ae_int_t valsize, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state); -void mlpkfoldcvlbfgs(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t foldscount, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state); -void mlpkfoldcvlm(multilayerperceptron* network, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t foldscount, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* cvrep, - ae_state *_state); -void mlpkfoldcv(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - ae_int_t foldscount, - mlpreport* rep, - ae_state *_state); -void _pexec_mlpkfoldcv(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - ae_int_t foldscount, - mlpreport* rep, ae_state *_state); -void mlpcreatetrainer(ae_int_t nin, - ae_int_t nout, - mlptrainer* s, - ae_state *_state); -void mlpcreatetrainercls(ae_int_t nin, - ae_int_t nclasses, - mlptrainer* s, - ae_state *_state); -void mlpsetdataset(mlptrainer* s, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_state *_state); -void mlpsetsparsedataset(mlptrainer* s, - sparsematrix* xy, - ae_int_t npoints, - ae_state *_state); -void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state); -void mlpsetcond(mlptrainer* s, - double wstep, - ae_int_t maxits, - ae_state *_state); -void mlpsetalgobatch(mlptrainer* s, ae_state *_state); -void mlptrainnetwork(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - mlpreport* rep, - ae_state *_state); -void _pexec_mlptrainnetwork(mlptrainer* s, - multilayerperceptron* network, - ae_int_t nrestarts, - mlpreport* rep, ae_state *_state); -void mlpstarttraining(mlptrainer* s, - multilayerperceptron* network, - ae_bool randomstart, - ae_state *_state); -ae_bool mlpcontinuetraining(mlptrainer* s, - multilayerperceptron* network, - ae_state *_state); -ae_bool _pexec_mlpcontinuetraining(mlptrainer* s, - multilayerperceptron* network, ae_state *_state); -void mlpebagginglm(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state); -void mlpebagginglbfgs(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - double wstep, - ae_int_t maxits, - ae_int_t* info, - mlpreport* rep, - mlpcvreport* ooberrors, - ae_state *_state); -void mlpetraines(mlpensemble* ensemble, - /* Real */ ae_matrix* xy, - ae_int_t npoints, - double decay, - ae_int_t restarts, - ae_int_t* info, - mlpreport* rep, - ae_state *_state); -void mlptrainensemblees(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t nrestarts, - mlpreport* rep, - ae_state *_state); -void _pexec_mlptrainensemblees(mlptrainer* s, - mlpensemble* ensemble, - ae_int_t nrestarts, - mlpreport* rep, ae_state *_state); -ae_bool _mlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpreport_clear(void* _p); -void _mlpreport_destroy(void* _p); -ae_bool _mlpcvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpcvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpcvreport_clear(void* _p); -void _mlpcvreport_destroy(void* _p); -ae_bool _smlptrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _smlptrnsession_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _smlptrnsession_clear(void* _p); -void _smlptrnsession_destroy(void* _p); -ae_bool _mlpetrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpetrnsession_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpetrnsession_clear(void* _p); -void _mlpetrnsession_destroy(void* _p); -ae_bool _mlptrainer_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlptrainer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlptrainer_clear(void* _p); -void _mlptrainer_destroy(void* _p); -ae_bool _mlpparallelizationcv_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mlpparallelizationcv_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mlpparallelizationcv_clear(void* _p); -void _mlpparallelizationcv_destroy(void* _p); -void pcabuildbasis(/* Real */ ae_matrix* x, - ae_int_t npoints, - ae_int_t nvars, - ae_int_t* info, - /* Real */ ae_vector* s2, - /* Real */ ae_matrix* v, - ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _dataanalysis_pkg_h +#define _dataanalysis_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "statistics.h" +#include "specialfunctions.h" +#include "optimization.h" +#include "solvers.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BDSS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; +} cvreport; +#endif +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; +} modelerrors; +typedef struct +{ + double f; + ae_vector g; +} smlpgrad; +typedef struct +{ + ae_int_t hlnetworktype; + ae_int_t hlnormtype; + ae_vector hllayersizes; + ae_vector hlconnections; + ae_vector hlneurons; + ae_vector structinfo; + ae_vector weights; + ae_vector columnmeans; + ae_vector columnsigmas; + ae_vector neurons; + ae_vector dfdnet; + ae_vector derror; + ae_vector x; + ae_vector y; + ae_matrix xy; + ae_vector xyrow; + ae_vector nwbuf; + ae_vector integerbuf; + modelerrors err; + ae_vector rndbuf; + ae_shared_pool buf; + ae_shared_pool gradbuf; + ae_matrix dummydxy; + sparsematrix dummysxy; + ae_vector dummyidx; + ae_shared_pool dummypool; +} multilayerperceptron; +#endif +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t ensemblesize; + ae_vector weights; + ae_vector columnmeans; + ae_vector columnsigmas; + multilayerperceptron network; + ae_vector y; +} mlpensemble; +#endif +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_matrix ct; + ae_matrix ctbest; + ae_vector xycbest; + ae_vector xycprev; + ae_vector d2; + ae_vector csizes; + apbuffers initbuf; + ae_shared_pool updatepool; +} kmeansbuffers; +typedef struct +{ + ae_int_t npoints; + ae_int_t nfeatures; + ae_int_t disttype; + ae_matrix xy; + ae_matrix d; + ae_int_t ahcalgo; + ae_int_t kmeansrestarts; + ae_int_t kmeansmaxits; + ae_int_t kmeansinitalgo; + ae_bool kmeansdbgnoits; + ae_int_t seed; + ae_matrix tmpd; + apbuffers distbuf; + kmeansbuffers kmeanstmp; +} clusterizerstate; +typedef struct +{ + ae_int_t terminationtype; + ae_int_t npoints; + ae_vector p; + ae_matrix z; + ae_matrix pz; + ae_matrix pm; + ae_vector mergedist; +} ahcreport; +typedef struct +{ + ae_int_t npoints; + ae_int_t nfeatures; + ae_int_t terminationtype; + ae_int_t iterationscount; + double energy; + ae_int_t k; + ae_matrix c; + ae_vector cidx; +} kmeansreport; +#endif +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t dstype; + ae_int_t npoints; + ae_int_t nvars; + ae_int_t nclasses; + ae_vector dsdata; + ae_vector dsrval; + ae_vector dsival; + ae_int_t rdfalgo; + double rdfratio; + double rdfvars; + ae_int_t rdfglobalseed; + ae_int_t rdfsplitstrength; + ae_int_t rdfimportance; + ae_vector dsmin; + ae_vector dsmax; + ae_vector dsbinary; + double dsravg; + ae_vector dsctotals; + ae_int_t rdfprogress; + ae_int_t rdftotal; + ae_shared_pool workpool; + ae_shared_pool votepool; + ae_shared_pool treepool; + ae_shared_pool treefactory; + ae_bool neediobmatrix; + ae_matrix iobmatrix; + ae_vector varimpshuffle2; +} decisionforestbuilder; +typedef struct +{ + ae_vector classpriors; + ae_vector varpool; + ae_int_t varpoolsize; + ae_vector trnset; + ae_int_t trnsize; + ae_vector trnlabelsr; + ae_vector trnlabelsi; + ae_vector oobset; + ae_int_t oobsize; + ae_vector ooblabelsr; + ae_vector ooblabelsi; + ae_vector treebuf; + ae_vector curvals; + ae_vector bestvals; + ae_vector tmp0i; + ae_vector tmp1i; + ae_vector tmp0r; + ae_vector tmp1r; + ae_vector tmp2r; + ae_vector tmp3r; + ae_vector tmpnrms2; + ae_vector classtotals0; + ae_vector classtotals1; + ae_vector classtotals01; +} dfworkbuf; +typedef struct +{ + ae_vector trntotals; + ae_vector oobtotals; + ae_vector trncounts; + ae_vector oobcounts; + ae_vector giniimportances; +} dfvotebuf; +typedef struct +{ + ae_vector losses; + ae_vector xraw; + ae_vector xdist; + ae_vector xcur; + ae_vector y; + ae_vector yv; + ae_vector targety; + ae_vector startnodes; +} dfpermimpbuf; +typedef struct +{ + ae_vector treebuf; + ae_int_t treeidx; +} dftreebuf; +typedef struct +{ + ae_vector x; + ae_vector y; +} decisionforestbuffer; +typedef struct +{ + ae_int_t forestformat; + ae_bool usemantissa8; + ae_int_t nvars; + ae_int_t nclasses; + ae_int_t ntrees; + ae_int_t bufsize; + ae_vector trees; + decisionforestbuffer buffer; + ae_vector trees8; +} decisionforest; +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; + double oobrelclserror; + double oobavgce; + double oobrmserror; + double oobavgerror; + double oobavgrelerror; + ae_vector topvars; + ae_vector varimportances; +} dfreport; +typedef struct +{ + ae_vector treebuf; + ae_vector idxbuf; + ae_vector tmpbufr; + ae_vector tmpbufr2; + ae_vector tmpbufi; + ae_vector classibuf; + ae_vector sortrbuf; + ae_vector sortrbuf2; + ae_vector sortibuf; + ae_vector varpool; + ae_vector evsbin; + ae_vector evssplits; +} dfinternalbuffers; +#endif +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector w; +} linearmodel; +typedef struct +{ + ae_matrix c; + double rmserror; + double avgerror; + double avgrelerror; + double cvrmserror; + double cvavgerror; + double cvavgrelerror; + ae_int_t ncvdefects; + ae_vector cvdefects; +} lrreport; +#endif +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t nsequences; + ae_vector sequenceidx; + ae_vector sequencedata; + ae_int_t algotype; + ae_int_t windowwidth; + ae_int_t rtpowerup; + ae_int_t topk; + ae_int_t precomputedwidth; + ae_int_t precomputednbasis; + ae_matrix precomputedbasis; + ae_int_t defaultsubspaceits; + ae_int_t memorylimit; + ae_bool arebasisandsolvervalid; + ae_matrix basis; + ae_matrix basist; + ae_vector sv; + ae_vector forecasta; + ae_int_t nbasis; + eigsubspacestate solver; + ae_matrix xxt; + hqrndstate rs; + ae_int_t rngseed; + ae_vector rtqueue; + ae_int_t rtqueuecnt; + ae_int_t rtqueuechunk; + ae_int_t dbgcntevd; + ae_vector tmp0; + ae_vector tmp1; + eigsubspacereport solverrep; + ae_vector alongtrend; + ae_vector alongnoise; + ae_matrix aseqtrajectory; + ae_matrix aseqtbproduct; + ae_vector aseqcounts; + ae_vector fctrend; + ae_vector fcnoise; + ae_matrix fctrendm; + ae_matrix uxbatch; + ae_int_t uxbatchwidth; + ae_int_t uxbatchsize; + ae_int_t uxbatchlimit; +} ssamodel; +#endif +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_vector states; + ae_int_t npairs; + ae_matrix data; + ae_matrix ec; + ae_matrix bndl; + ae_matrix bndu; + ae_matrix c; + ae_vector ct; + ae_int_t ccnt; + ae_vector pw; + ae_matrix priorp; + double regterm; + minbleicstate bs; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + minbleicreport br; + ae_vector tmpp; + ae_vector effectivew; + ae_vector effectivebndl; + ae_vector effectivebndu; + ae_matrix effectivec; + ae_vector effectivect; + ae_vector h; + ae_matrix p; +} mcpdstate; +typedef struct +{ + ae_int_t inneriterationscount; + ae_int_t outeriterationscount; + ae_int_t nfev; + ae_int_t terminationtype; +} mcpdreport; +#endif +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector w; +} logitmodel; +typedef struct +{ + ae_bool brackt; + ae_bool stage1; + ae_int_t infoc; + double dg; + double dgm; + double dginit; + double dgtest; + double dgx; + double dgxm; + double dgy; + double dgym; + double finit; + double ftest1; + double fm; + double fx; + double fxm; + double fy; + double fym; + double stx; + double sty; + double stmin; + double stmax; + double width; + double width1; + double xtrapf; +} logitmcstate; +typedef struct +{ + ae_int_t ngrad; + ae_int_t nhess; +} mnlreport; +#endif +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + kdtreerequestbuffer treebuf; + ae_vector x; + ae_vector y; + ae_vector tags; + ae_matrix xy; +} knnbuffer; +typedef struct +{ + ae_int_t dstype; + ae_int_t npoints; + ae_int_t nvars; + ae_bool iscls; + ae_int_t nout; + ae_matrix dsdata; + ae_vector dsrval; + ae_vector dsival; + ae_int_t knnnrm; +} knnbuilder; +typedef struct +{ + ae_int_t nvars; + ae_int_t nout; + ae_int_t k; + double eps; + ae_bool iscls; + ae_bool isdummy; + kdtree tree; + knnbuffer buffer; +} knnmodel; +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; +} knnreport; +#endif +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; + ae_int_t ngrad; + ae_int_t nhess; + ae_int_t ncholesky; +} mlpreport; +typedef struct +{ + double relclserror; + double avgce; + double rmserror; + double avgerror; + double avgrelerror; +} mlpcvreport; +typedef struct +{ + ae_vector bestparameters; + double bestrmserror; + ae_bool randomizenetwork; + multilayerperceptron network; + minlbfgsstate optimizer; + minlbfgsreport optimizerrep; + ae_vector wbuf0; + ae_vector wbuf1; + ae_vector allminibatches; + ae_vector currentminibatch; + rcommstate rstate; + ae_int_t algoused; + ae_int_t minibatchsize; + hqrndstate generator; +} smlptrnsession; +typedef struct +{ + ae_vector trnsubset; + ae_vector valsubset; + ae_shared_pool mlpsessions; + mlpreport mlprep; + multilayerperceptron network; +} mlpetrnsession; +typedef struct +{ + ae_int_t nin; + ae_int_t nout; + ae_bool rcpar; + ae_int_t lbfgsfactor; + double decay; + double wstep; + ae_int_t maxits; + ae_int_t datatype; + ae_int_t npoints; + ae_matrix densexy; + sparsematrix sparsexy; + smlptrnsession session; + ae_int_t ngradbatch; + ae_vector subset; + ae_int_t subsetsize; + ae_vector valsubset; + ae_int_t valsubsetsize; + ae_int_t algokind; + ae_int_t minibatchsize; +} mlptrainer; +typedef struct +{ + multilayerperceptron network; + mlpreport rep; + ae_vector subset; + ae_int_t subsetsize; + ae_vector xyrow; + ae_vector y; + ae_int_t ngrad; + ae_shared_pool trnpool; +} mlpparallelizationcv; +#endif +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_BDSS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +class _modelerrors_owner; +class modelerrors; +class _multilayerperceptron_owner; +class multilayerperceptron; + + +/************************************************************************* +Model's errors: + * RelCLSError - fraction of misclassified cases. + * AvgCE - acerage cross-entropy + * RMSError - root-mean-square error + * AvgError - average error + * AvgRelError - average relative error + +NOTE 1: RelCLSError/AvgCE are zero on regression problems. + +NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain + errors in prediction of posterior probabilities +*************************************************************************/ +class _modelerrors_owner +{ +public: + _modelerrors_owner(); + _modelerrors_owner(alglib_impl::modelerrors *attach_to); + _modelerrors_owner(const _modelerrors_owner &rhs); + _modelerrors_owner& operator=(const _modelerrors_owner &rhs); + virtual ~_modelerrors_owner(); + alglib_impl::modelerrors* c_ptr(); + const alglib_impl::modelerrors* c_ptr() const; +protected: + alglib_impl::modelerrors *p_struct; + bool is_attached; +}; +class modelerrors : public _modelerrors_owner +{ +public: + modelerrors(); + modelerrors(alglib_impl::modelerrors *attach_to); + modelerrors(const modelerrors &rhs); + modelerrors& operator=(const modelerrors &rhs); + virtual ~modelerrors(); + double &relclserror; + double &avgce; + double &rmserror; + double &avgerror; + double &avgrelerror; + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _multilayerperceptron_owner +{ +public: + _multilayerperceptron_owner(); + _multilayerperceptron_owner(alglib_impl::multilayerperceptron *attach_to); + _multilayerperceptron_owner(const _multilayerperceptron_owner &rhs); + _multilayerperceptron_owner& operator=(const _multilayerperceptron_owner &rhs); + virtual ~_multilayerperceptron_owner(); + alglib_impl::multilayerperceptron* c_ptr(); + const alglib_impl::multilayerperceptron* c_ptr() const; +protected: + alglib_impl::multilayerperceptron *p_struct; + bool is_attached; +}; +class multilayerperceptron : public _multilayerperceptron_owner +{ +public: + multilayerperceptron(); + multilayerperceptron(alglib_impl::multilayerperceptron *attach_to); + multilayerperceptron(const multilayerperceptron &rhs); + multilayerperceptron& operator=(const multilayerperceptron &rhs); + virtual ~multilayerperceptron(); + + +}; +#endif + +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +class _mlpensemble_owner; +class mlpensemble; + + +/************************************************************************* +Neural networks ensemble +*************************************************************************/ +class _mlpensemble_owner +{ +public: + _mlpensemble_owner(); + _mlpensemble_owner(alglib_impl::mlpensemble *attach_to); + _mlpensemble_owner(const _mlpensemble_owner &rhs); + _mlpensemble_owner& operator=(const _mlpensemble_owner &rhs); + virtual ~_mlpensemble_owner(); + alglib_impl::mlpensemble* c_ptr(); + const alglib_impl::mlpensemble* c_ptr() const; +protected: + alglib_impl::mlpensemble *p_struct; + bool is_attached; +}; +class mlpensemble : public _mlpensemble_owner +{ +public: + mlpensemble(); + mlpensemble(alglib_impl::mlpensemble *attach_to); + mlpensemble(const mlpensemble &rhs); + mlpensemble& operator=(const mlpensemble &rhs); + virtual ~mlpensemble(); + + +}; +#endif + +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +class _clusterizerstate_owner; +class clusterizerstate; +class _ahcreport_owner; +class ahcreport; +class _kmeansreport_owner; +class kmeansreport; + + +/************************************************************************* +This structure is a clusterization engine. + +You should not try to access its fields directly. +Use ALGLIB functions in order to work with this object. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +class _clusterizerstate_owner +{ +public: + _clusterizerstate_owner(); + _clusterizerstate_owner(alglib_impl::clusterizerstate *attach_to); + _clusterizerstate_owner(const _clusterizerstate_owner &rhs); + _clusterizerstate_owner& operator=(const _clusterizerstate_owner &rhs); + virtual ~_clusterizerstate_owner(); + alglib_impl::clusterizerstate* c_ptr(); + const alglib_impl::clusterizerstate* c_ptr() const; +protected: + alglib_impl::clusterizerstate *p_struct; + bool is_attached; +}; +class clusterizerstate : public _clusterizerstate_owner +{ +public: + clusterizerstate(); + clusterizerstate(alglib_impl::clusterizerstate *attach_to); + clusterizerstate(const clusterizerstate &rhs); + clusterizerstate& operator=(const clusterizerstate &rhs); + virtual ~clusterizerstate(); + + +}; + + +/************************************************************************* +This structure is used to store results of the agglomerative hierarchical +clustering (AHC). + +Following information is returned: + +* TerminationType - completion code: + * 1 for successful completion of algorithm + * -5 inappropriate combination of clustering algorithm and distance + function was used. As for now, it is possible only when Ward's + method is called for dataset with non-Euclidean distance function. + In case negative completion code is returned, other fields of report + structure are invalid and should not be used. + +* NPoints contains number of points in the original dataset + +* Z contains information about merges performed (see below). Z contains + indexes from the original (unsorted) dataset and it can be used when you + need to know what points were merged. However, it is not convenient when + you want to build a dendrograd (see below). + +* if you want to build dendrogram, you can use Z, but it is not good + option, because Z contains indexes from unsorted dataset. Dendrogram + built from such dataset is likely to have intersections. So, you have to + reorder you points before building dendrogram. + Permutation which reorders point is returned in P. Another representation + of merges, which is more convenient for dendorgram construction, is + returned in PM. + +* more information on format of Z, P and PM can be found below and in the + examples from ALGLIB Reference Manual. + +FORMAL DESCRIPTION OF FIELDS: + NPoints number of points + Z array[NPoints-1,2], contains indexes of clusters + linked in pairs to form clustering tree. I-th row + corresponds to I-th merge: + * Z[I,0] - index of the first cluster to merge + * Z[I,1] - index of the second cluster to merge + * Z[I,0]=0 + NFeatures number of variables, >=1 + TerminationType completion code: + * -5 if distance type is anything different from + Euclidean metric + * -3 for degenerate dataset: a) less than K distinct + points, b) K=0 for non-empty dataset. + * +1 for successful completion + K number of clusters + C array[K,NFeatures], rows of the array store centers + CIdx array[NPoints], which contains cluster indexes + IterationsCount actual number of iterations performed by clusterizer. + If algorithm performed more than one random restart, + total number of iterations is returned. + Energy merit function, "energy", sum of squared deviations + from cluster centers + + -- ALGLIB -- + Copyright 27.11.2012 by Bochkanov Sergey +*************************************************************************/ +class _kmeansreport_owner +{ +public: + _kmeansreport_owner(); + _kmeansreport_owner(alglib_impl::kmeansreport *attach_to); + _kmeansreport_owner(const _kmeansreport_owner &rhs); + _kmeansreport_owner& operator=(const _kmeansreport_owner &rhs); + virtual ~_kmeansreport_owner(); + alglib_impl::kmeansreport* c_ptr(); + const alglib_impl::kmeansreport* c_ptr() const; +protected: + alglib_impl::kmeansreport *p_struct; + bool is_attached; +}; +class kmeansreport : public _kmeansreport_owner +{ +public: + kmeansreport(); + kmeansreport(alglib_impl::kmeansreport *attach_to); + kmeansreport(const kmeansreport &rhs); + kmeansreport& operator=(const kmeansreport &rhs); + virtual ~kmeansreport(); + ae_int_t &npoints; + ae_int_t &nfeatures; + ae_int_t &terminationtype; + ae_int_t &iterationscount; + double &energy; + ae_int_t &k; + real_2d_array c; + integer_1d_array cidx; + + +}; +#endif + +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) +class _decisionforestbuilder_owner; +class decisionforestbuilder; +class _decisionforestbuffer_owner; +class decisionforestbuffer; +class _decisionforest_owner; +class decisionforest; +class _dfreport_owner; +class dfreport; + + +/************************************************************************* +A random forest (decision forest) builder object. + +Used to store dataset and specify decision forest training algorithm settings. +*************************************************************************/ +class _decisionforestbuilder_owner +{ +public: + _decisionforestbuilder_owner(); + _decisionforestbuilder_owner(alglib_impl::decisionforestbuilder *attach_to); + _decisionforestbuilder_owner(const _decisionforestbuilder_owner &rhs); + _decisionforestbuilder_owner& operator=(const _decisionforestbuilder_owner &rhs); + virtual ~_decisionforestbuilder_owner(); + alglib_impl::decisionforestbuilder* c_ptr(); + const alglib_impl::decisionforestbuilder* c_ptr() const; +protected: + alglib_impl::decisionforestbuilder *p_struct; + bool is_attached; +}; +class decisionforestbuilder : public _decisionforestbuilder_owner +{ +public: + decisionforestbuilder(); + decisionforestbuilder(alglib_impl::decisionforestbuilder *attach_to); + decisionforestbuilder(const decisionforestbuilder &rhs); + decisionforestbuilder& operator=(const decisionforestbuilder &rhs); + virtual ~decisionforestbuilder(); + + +}; + + +/************************************************************************* +Buffer object which is used to perform various requests (usually model +inference) in the multithreaded mode (multiple threads working with same +DF object). + +This object should be created with DFCreateBuffer(). +*************************************************************************/ +class _decisionforestbuffer_owner +{ +public: + _decisionforestbuffer_owner(); + _decisionforestbuffer_owner(alglib_impl::decisionforestbuffer *attach_to); + _decisionforestbuffer_owner(const _decisionforestbuffer_owner &rhs); + _decisionforestbuffer_owner& operator=(const _decisionforestbuffer_owner &rhs); + virtual ~_decisionforestbuffer_owner(); + alglib_impl::decisionforestbuffer* c_ptr(); + const alglib_impl::decisionforestbuffer* c_ptr() const; +protected: + alglib_impl::decisionforestbuffer *p_struct; + bool is_attached; +}; +class decisionforestbuffer : public _decisionforestbuffer_owner +{ +public: + decisionforestbuffer(); + decisionforestbuffer(alglib_impl::decisionforestbuffer *attach_to); + decisionforestbuffer(const decisionforestbuffer &rhs); + decisionforestbuffer& operator=(const decisionforestbuffer &rhs); + virtual ~decisionforestbuffer(); + + +}; + + +/************************************************************************* +Decision forest (random forest) model. +*************************************************************************/ +class _decisionforest_owner +{ +public: + _decisionforest_owner(); + _decisionforest_owner(alglib_impl::decisionforest *attach_to); + _decisionforest_owner(const _decisionforest_owner &rhs); + _decisionforest_owner& operator=(const _decisionforest_owner &rhs); + virtual ~_decisionforest_owner(); + alglib_impl::decisionforest* c_ptr(); + const alglib_impl::decisionforest* c_ptr() const; +protected: + alglib_impl::decisionforest *p_struct; + bool is_attached; +}; +class decisionforest : public _decisionforest_owner +{ +public: + decisionforest(); + decisionforest(alglib_impl::decisionforest *attach_to); + decisionforest(const decisionforest &rhs); + decisionforest& operator=(const decisionforest &rhs); + virtual ~decisionforest(); + + +}; + + +/************************************************************************* +Decision forest training report. + +=== training/oob errors ================================================== + +Following fields store training set errors: +* relclserror - fraction of misclassified cases, [0,1] +* avgce - average cross-entropy in bits per symbol +* rmserror - root-mean-square error +* avgerror - average error +* avgrelerror - average relative error + +Out-of-bag estimates are stored in fields with same names, but "oob" prefix. + +For classification problems: +* RMS, AVG and AVGREL errors are calculated for posterior probabilities + +For regression problems: +* RELCLS and AVGCE errors are zero + +=== variable importance ================================================== + +Following fields are used to store variable importance information: + +* topvars - variables ordered from the most important to + less important ones (according to current + choice of importance raiting). + For example, topvars[0] contains index of the + most important variable, and topvars[0:2] are + indexes of 3 most important ones and so on. + +* varimportances - array[nvars], ratings (the larger, the more + important the variable is, always in [0,1] + range). + By default, filled by zeros (no importance + ratings are provided unless you explicitly + request them). + Zero rating means that variable is not important, + however you will rarely encounter such a thing, + in many cases unimportant variables produce + nearly-zero (but nonzero) ratings. + +Variable importance report must be EXPLICITLY requested by calling: +* dfbuildersetimportancegini() function, if you need out-of-bag Gini-based + importance rating also known as MDI (fast to calculate, resistant to + overfitting issues, but has some bias towards continuous and + high-cardinality categorical variables) +* dfbuildersetimportancetrngini() function, if you need training set Gini- + -based importance rating (what other packages typically report). +* dfbuildersetimportancepermutation() function, if you need permutation- + based importance rating also known as MDA (slower to calculate, but less + biased) +* dfbuildersetimportancenone() function, if you do not need importance + ratings - ratings will be zero, topvars[] will be [0,1,2,...] + +Different importance ratings (Gini or permutation) produce non-comparable +values. Although in all cases rating values lie in [0,1] range, there are +exist differences: +* informally speaking, Gini importance rating tends to divide "unit amount + of importance" between several important variables, i.e. it produces + estimates which roughly sum to 1.0 (or less than 1.0, if your task can + not be solved exactly). If all variables are equally important, they + will have same rating, roughly 1/NVars, even if every variable is + critically important. +* from the other side, permutation importance tells us what percentage of + the model predictive power will be ruined by permuting this specific + variable. It does not produce estimates which sum to one. Critically + important variable will have rating close to 1.0, and you may have + multiple variables with such a rating. + +More information on variable importance ratings can be found in comments +on the dfbuildersetimportancegini() and dfbuildersetimportancepermutation() +functions. +*************************************************************************/ +class _dfreport_owner +{ +public: + _dfreport_owner(); + _dfreport_owner(alglib_impl::dfreport *attach_to); + _dfreport_owner(const _dfreport_owner &rhs); + _dfreport_owner& operator=(const _dfreport_owner &rhs); + virtual ~_dfreport_owner(); + alglib_impl::dfreport* c_ptr(); + const alglib_impl::dfreport* c_ptr() const; +protected: + alglib_impl::dfreport *p_struct; + bool is_attached; +}; +class dfreport : public _dfreport_owner +{ +public: + dfreport(); + dfreport(alglib_impl::dfreport *attach_to); + dfreport(const dfreport &rhs); + dfreport& operator=(const dfreport &rhs); + virtual ~dfreport(); + double &relclserror; + double &avgce; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &oobrelclserror; + double &oobavgce; + double &oobrmserror; + double &oobavgerror; + double &oobavgrelerror; + integer_1d_array topvars; + real_1d_array varimportances; + + +}; +#endif + +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +class _linearmodel_owner; +class linearmodel; +class _lrreport_owner; +class lrreport; + + +/************************************************************************* + +*************************************************************************/ +class _linearmodel_owner +{ +public: + _linearmodel_owner(); + _linearmodel_owner(alglib_impl::linearmodel *attach_to); + _linearmodel_owner(const _linearmodel_owner &rhs); + _linearmodel_owner& operator=(const _linearmodel_owner &rhs); + virtual ~_linearmodel_owner(); + alglib_impl::linearmodel* c_ptr(); + const alglib_impl::linearmodel* c_ptr() const; +protected: + alglib_impl::linearmodel *p_struct; + bool is_attached; +}; +class linearmodel : public _linearmodel_owner +{ +public: + linearmodel(); + linearmodel(alglib_impl::linearmodel *attach_to); + linearmodel(const linearmodel &rhs); + linearmodel& operator=(const linearmodel &rhs); + virtual ~linearmodel(); + + +}; + + +/************************************************************************* +LRReport structure contains additional information about linear model: +* C - covariation matrix, array[0..NVars,0..NVars]. + C[i,j] = Cov(A[i],A[j]) +* RMSError - root mean square error on a training set +* AvgError - average error on a training set +* AvgRelError - average relative error on a training set (excluding + observations with zero function value). +* CVRMSError - leave-one-out cross-validation estimate of + generalization error. Calculated using fast algorithm + with O(NVars*NPoints) complexity. +* CVAvgError - cross-validation estimate of average error +* CVAvgRelError - cross-validation estimate of average relative error + +All other fields of the structure are intended for internal use and should +not be used outside ALGLIB. +*************************************************************************/ +class _lrreport_owner +{ +public: + _lrreport_owner(); + _lrreport_owner(alglib_impl::lrreport *attach_to); + _lrreport_owner(const _lrreport_owner &rhs); + _lrreport_owner& operator=(const _lrreport_owner &rhs); + virtual ~_lrreport_owner(); + alglib_impl::lrreport* c_ptr(); + const alglib_impl::lrreport* c_ptr() const; +protected: + alglib_impl::lrreport *p_struct; + bool is_attached; +}; +class lrreport : public _lrreport_owner +{ +public: + lrreport(); + lrreport(alglib_impl::lrreport *attach_to); + lrreport(const lrreport &rhs); + lrreport& operator=(const lrreport &rhs); + virtual ~lrreport(); + real_2d_array c; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &cvrmserror; + double &cvavgerror; + double &cvavgrelerror; + ae_int_t &ncvdefects; + integer_1d_array cvdefects; + + +}; +#endif + +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +class _ssamodel_owner; +class ssamodel; + + +/************************************************************************* +This object stores state of the SSA model. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _ssamodel_owner +{ +public: + _ssamodel_owner(); + _ssamodel_owner(alglib_impl::ssamodel *attach_to); + _ssamodel_owner(const _ssamodel_owner &rhs); + _ssamodel_owner& operator=(const _ssamodel_owner &rhs); + virtual ~_ssamodel_owner(); + alglib_impl::ssamodel* c_ptr(); + const alglib_impl::ssamodel* c_ptr() const; +protected: + alglib_impl::ssamodel *p_struct; + bool is_attached; +}; +class ssamodel : public _ssamodel_owner +{ +public: + ssamodel(); + ssamodel(alglib_impl::ssamodel *attach_to); + ssamodel(const ssamodel &rhs); + ssamodel& operator=(const ssamodel &rhs); + virtual ~ssamodel(); + + +}; +#endif + +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +class _mcpdstate_owner; +class mcpdstate; +class _mcpdreport_owner; +class mcpdreport; + + +/************************************************************************* +This structure is a MCPD (Markov Chains for Population Data) solver. + +You should use ALGLIB functions in order to work with this object. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +class _mcpdstate_owner +{ +public: + _mcpdstate_owner(); + _mcpdstate_owner(alglib_impl::mcpdstate *attach_to); + _mcpdstate_owner(const _mcpdstate_owner &rhs); + _mcpdstate_owner& operator=(const _mcpdstate_owner &rhs); + virtual ~_mcpdstate_owner(); + alglib_impl::mcpdstate* c_ptr(); + const alglib_impl::mcpdstate* c_ptr() const; +protected: + alglib_impl::mcpdstate *p_struct; + bool is_attached; +}; +class mcpdstate : public _mcpdstate_owner +{ +public: + mcpdstate(); + mcpdstate(alglib_impl::mcpdstate *attach_to); + mcpdstate(const mcpdstate &rhs); + mcpdstate& operator=(const mcpdstate &rhs); + virtual ~mcpdstate(); + + +}; + + +/************************************************************************* +This structure is a MCPD training report: + InnerIterationsCount - number of inner iterations of the + underlying optimization algorithm + OuterIterationsCount - number of outer iterations of the + underlying optimization algorithm + NFEV - number of merit function evaluations + TerminationType - termination type + (same as for MinBLEIC optimizer, positive + values denote success, negative ones - + failure) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +class _mcpdreport_owner +{ +public: + _mcpdreport_owner(); + _mcpdreport_owner(alglib_impl::mcpdreport *attach_to); + _mcpdreport_owner(const _mcpdreport_owner &rhs); + _mcpdreport_owner& operator=(const _mcpdreport_owner &rhs); + virtual ~_mcpdreport_owner(); + alglib_impl::mcpdreport* c_ptr(); + const alglib_impl::mcpdreport* c_ptr() const; +protected: + alglib_impl::mcpdreport *p_struct; + bool is_attached; +}; +class mcpdreport : public _mcpdreport_owner +{ +public: + mcpdreport(); + mcpdreport(alglib_impl::mcpdreport *attach_to); + mcpdreport(const mcpdreport &rhs); + mcpdreport& operator=(const mcpdreport &rhs); + virtual ~mcpdreport(); + ae_int_t &inneriterationscount; + ae_int_t &outeriterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +class _logitmodel_owner; +class logitmodel; +class _mnlreport_owner; +class mnlreport; + + +/************************************************************************* + +*************************************************************************/ +class _logitmodel_owner +{ +public: + _logitmodel_owner(); + _logitmodel_owner(alglib_impl::logitmodel *attach_to); + _logitmodel_owner(const _logitmodel_owner &rhs); + _logitmodel_owner& operator=(const _logitmodel_owner &rhs); + virtual ~_logitmodel_owner(); + alglib_impl::logitmodel* c_ptr(); + const alglib_impl::logitmodel* c_ptr() const; +protected: + alglib_impl::logitmodel *p_struct; + bool is_attached; +}; +class logitmodel : public _logitmodel_owner +{ +public: + logitmodel(); + logitmodel(alglib_impl::logitmodel *attach_to); + logitmodel(const logitmodel &rhs); + logitmodel& operator=(const logitmodel &rhs); + virtual ~logitmodel(); + + +}; + + +/************************************************************************* +MNLReport structure contains information about training process: +* NGrad - number of gradient calculations +* NHess - number of Hessian calculations +*************************************************************************/ +class _mnlreport_owner +{ +public: + _mnlreport_owner(); + _mnlreport_owner(alglib_impl::mnlreport *attach_to); + _mnlreport_owner(const _mnlreport_owner &rhs); + _mnlreport_owner& operator=(const _mnlreport_owner &rhs); + virtual ~_mnlreport_owner(); + alglib_impl::mnlreport* c_ptr(); + const alglib_impl::mnlreport* c_ptr() const; +protected: + alglib_impl::mnlreport *p_struct; + bool is_attached; +}; +class mnlreport : public _mnlreport_owner +{ +public: + mnlreport(); + mnlreport(alglib_impl::mnlreport *attach_to); + mnlreport(const mnlreport &rhs); + mnlreport& operator=(const mnlreport &rhs); + virtual ~mnlreport(); + ae_int_t &ngrad; + ae_int_t &nhess; + + +}; +#endif + +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) +class _knnbuffer_owner; +class knnbuffer; +class _knnbuilder_owner; +class knnbuilder; +class _knnmodel_owner; +class knnmodel; +class _knnreport_owner; +class knnreport; + + +/************************************************************************* +Buffer object which is used to perform various requests (usually model +inference) in the multithreaded mode (multiple threads working with same +KNN object). + +This object should be created with KNNCreateBuffer(). +*************************************************************************/ +class _knnbuffer_owner +{ +public: + _knnbuffer_owner(); + _knnbuffer_owner(alglib_impl::knnbuffer *attach_to); + _knnbuffer_owner(const _knnbuffer_owner &rhs); + _knnbuffer_owner& operator=(const _knnbuffer_owner &rhs); + virtual ~_knnbuffer_owner(); + alglib_impl::knnbuffer* c_ptr(); + const alglib_impl::knnbuffer* c_ptr() const; +protected: + alglib_impl::knnbuffer *p_struct; + bool is_attached; +}; +class knnbuffer : public _knnbuffer_owner +{ +public: + knnbuffer(); + knnbuffer(alglib_impl::knnbuffer *attach_to); + knnbuffer(const knnbuffer &rhs); + knnbuffer& operator=(const knnbuffer &rhs); + virtual ~knnbuffer(); + + +}; + + +/************************************************************************* +A KNN builder object; this object encapsulates dataset and all related +settings, it is used to create an actual instance of KNN model. +*************************************************************************/ +class _knnbuilder_owner +{ +public: + _knnbuilder_owner(); + _knnbuilder_owner(alglib_impl::knnbuilder *attach_to); + _knnbuilder_owner(const _knnbuilder_owner &rhs); + _knnbuilder_owner& operator=(const _knnbuilder_owner &rhs); + virtual ~_knnbuilder_owner(); + alglib_impl::knnbuilder* c_ptr(); + const alglib_impl::knnbuilder* c_ptr() const; +protected: + alglib_impl::knnbuilder *p_struct; + bool is_attached; +}; +class knnbuilder : public _knnbuilder_owner +{ +public: + knnbuilder(); + knnbuilder(alglib_impl::knnbuilder *attach_to); + knnbuilder(const knnbuilder &rhs); + knnbuilder& operator=(const knnbuilder &rhs); + virtual ~knnbuilder(); + + +}; + + +/************************************************************************* +KNN model, can be used for classification or regression +*************************************************************************/ +class _knnmodel_owner +{ +public: + _knnmodel_owner(); + _knnmodel_owner(alglib_impl::knnmodel *attach_to); + _knnmodel_owner(const _knnmodel_owner &rhs); + _knnmodel_owner& operator=(const _knnmodel_owner &rhs); + virtual ~_knnmodel_owner(); + alglib_impl::knnmodel* c_ptr(); + const alglib_impl::knnmodel* c_ptr() const; +protected: + alglib_impl::knnmodel *p_struct; + bool is_attached; +}; +class knnmodel : public _knnmodel_owner +{ +public: + knnmodel(); + knnmodel(alglib_impl::knnmodel *attach_to); + knnmodel(const knnmodel &rhs); + knnmodel& operator=(const knnmodel &rhs); + virtual ~knnmodel(); + + +}; + + +/************************************************************************* +KNN training report. + +Following fields store training set errors: +* relclserror - fraction of misclassified cases, [0,1] +* avgce - average cross-entropy in bits per symbol +* rmserror - root-mean-square error +* avgerror - average error +* avgrelerror - average relative error + +For classification problems: +* RMS, AVG and AVGREL errors are calculated for posterior probabilities + +For regression problems: +* RELCLS and AVGCE errors are zero +*************************************************************************/ +class _knnreport_owner +{ +public: + _knnreport_owner(); + _knnreport_owner(alglib_impl::knnreport *attach_to); + _knnreport_owner(const _knnreport_owner &rhs); + _knnreport_owner& operator=(const _knnreport_owner &rhs); + virtual ~_knnreport_owner(); + alglib_impl::knnreport* c_ptr(); + const alglib_impl::knnreport* c_ptr() const; +protected: + alglib_impl::knnreport *p_struct; + bool is_attached; +}; +class knnreport : public _knnreport_owner +{ +public: + knnreport(); + knnreport(alglib_impl::knnreport *attach_to); + knnreport(const knnreport &rhs); + knnreport& operator=(const knnreport &rhs); + virtual ~knnreport(); + double &relclserror; + double &avgce; + double &rmserror; + double &avgerror; + double &avgrelerror; + + +}; +#endif + +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +class _mlpreport_owner; +class mlpreport; +class _mlpcvreport_owner; +class mlpcvreport; +class _mlptrainer_owner; +class mlptrainer; + + +/************************************************************************* +Training report: + * RelCLSError - fraction of misclassified cases. + * AvgCE - acerage cross-entropy + * RMSError - root-mean-square error + * AvgError - average error + * AvgRelError - average relative error + * NGrad - number of gradient calculations + * NHess - number of Hessian calculations + * NCholesky - number of Cholesky decompositions + +NOTE 1: RelCLSError/AvgCE are zero on regression problems. + +NOTE 2: on classification problems RMSError/AvgError/AvgRelError contain + errors in prediction of posterior probabilities +*************************************************************************/ +class _mlpreport_owner +{ +public: + _mlpreport_owner(); + _mlpreport_owner(alglib_impl::mlpreport *attach_to); + _mlpreport_owner(const _mlpreport_owner &rhs); + _mlpreport_owner& operator=(const _mlpreport_owner &rhs); + virtual ~_mlpreport_owner(); + alglib_impl::mlpreport* c_ptr(); + const alglib_impl::mlpreport* c_ptr() const; +protected: + alglib_impl::mlpreport *p_struct; + bool is_attached; +}; +class mlpreport : public _mlpreport_owner +{ +public: + mlpreport(); + mlpreport(alglib_impl::mlpreport *attach_to); + mlpreport(const mlpreport &rhs); + mlpreport& operator=(const mlpreport &rhs); + virtual ~mlpreport(); + double &relclserror; + double &avgce; + double &rmserror; + double &avgerror; + double &avgrelerror; + ae_int_t &ngrad; + ae_int_t &nhess; + ae_int_t &ncholesky; + + +}; + + +/************************************************************************* +Cross-validation estimates of generalization error +*************************************************************************/ +class _mlpcvreport_owner +{ +public: + _mlpcvreport_owner(); + _mlpcvreport_owner(alglib_impl::mlpcvreport *attach_to); + _mlpcvreport_owner(const _mlpcvreport_owner &rhs); + _mlpcvreport_owner& operator=(const _mlpcvreport_owner &rhs); + virtual ~_mlpcvreport_owner(); + alglib_impl::mlpcvreport* c_ptr(); + const alglib_impl::mlpcvreport* c_ptr() const; +protected: + alglib_impl::mlpcvreport *p_struct; + bool is_attached; +}; +class mlpcvreport : public _mlpcvreport_owner +{ +public: + mlpcvreport(); + mlpcvreport(alglib_impl::mlpcvreport *attach_to); + mlpcvreport(const mlpcvreport &rhs); + mlpcvreport& operator=(const mlpcvreport &rhs); + virtual ~mlpcvreport(); + double &relclserror; + double &avgce; + double &rmserror; + double &avgerror; + double &avgrelerror; + + +}; + + +/************************************************************************* +Trainer object for neural network. + +You should not try to access fields of this object directly - use ALGLIB +functions to work with this object. +*************************************************************************/ +class _mlptrainer_owner +{ +public: + _mlptrainer_owner(); + _mlptrainer_owner(alglib_impl::mlptrainer *attach_to); + _mlptrainer_owner(const _mlptrainer_owner &rhs); + _mlptrainer_owner& operator=(const _mlptrainer_owner &rhs); + virtual ~_mlptrainer_owner(); + alglib_impl::mlptrainer* c_ptr(); + const alglib_impl::mlptrainer* c_ptr() const; +protected: + alglib_impl::mlptrainer *p_struct; + bool is_attached; +}; +class mlptrainer : public _mlptrainer_owner +{ +public: + mlptrainer(); + mlptrainer(alglib_impl::mlptrainer *attach_to); + mlptrainer(const mlptrainer &rhs); + mlptrainer& operator=(const mlptrainer &rhs); + virtual ~mlptrainer(); + + +}; +#endif + +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Principal components analysis + +This function builds orthogonal basis where first axis corresponds to +direction with maximum variance, second axis maximizes variance in the +subspace orthogonal to first axis and so on. + +This function builds FULL basis, i.e. returns N vectors corresponding to +ALL directions, no matter how informative. If you need just a few (say, +10 or 50) of the most important directions, you may find it faster to use +one of the reduced versions: +* pcatruncatedsubspace() - for subspace iteration based method + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[NPoints,NVars]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + +OUTPUT PARAMETERS: + S2 - array[NVars]. variance values corresponding + to basis vectors. + V - array[NVars,NVars] + matrix, whose columns store basis vectors. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 25.08.2008 by Bochkanov Sergey +*************************************************************************/ +void pcabuildbasis(const real_2d_array &x, const ae_int_t npoints, const ae_int_t nvars, real_1d_array &s2, real_2d_array &v, const xparams _xparams = alglib::xdefault); +void pcabuildbasis(const real_2d_array &x, real_1d_array &s2, real_2d_array &v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Principal components analysis + +This function performs truncated PCA, i.e. returns just a few most important +directions. + +Internally it uses iterative eigensolver which is very efficient when only +a minor fraction of full basis is required. Thus, if you need full basis, +it is better to use pcabuildbasis() function. + +It should be noted that, unlike LDA, PCA does not use class labels. + +INPUT PARAMETERS: + X - dataset, array[0..NPoints-1,0..NVars-1]. + matrix contains ONLY INDEPENDENT VARIABLES. + NPoints - dataset size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<=0 + NVars - number of independent variables, NVars>=1 + NNeeded - number of requested components, in [1,NVars] range; + this function is efficient only for NNeeded<1) + * -1, incorrect pararemets were passed (N<=0). + * 1, OK + Threshold- partiton boundary. Left part contains values which are + strictly less than Threshold. Right part contains values + which are greater than or equal to Threshold. + PAL, PBL- probabilities P(0|v=Threshold) and P(1|v>=Threshold) + CVE - cross-validation estimate of cross-entropy + + -- ALGLIB -- + Copyright 22.05.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2(const real_1d_array &a, const integer_1d_array &c, const ae_int_t n, ae_int_t &info, double &threshold, double &pal, double &pbl, double &par, double &pbr, double &cve, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Optimal partition, internal subroutine. Fast version. + +Accepts: + A array[0..N-1] array of attributes array[0..N-1] + C array[0..N-1] array of class labels + TiesBuf array[0..N] temporaries (ties) + CntBuf array[0..2*NC-1] temporaries (counts) + Alpha centering factor (0<=alpha<=1, recommended value - 0.05) + BufR array[0..N-1] temporaries + BufI array[0..N-1] temporaries + +Output: + Info error code (">0"=OK, "<0"=bad) + RMS training set RMS error + CVRMS leave-one-out RMS error + +Note: + content of all arrays is changed by subroutine; + it doesn't allocate temporaries. + + -- ALGLIB -- + Copyright 11.12.2008 by Bochkanov Sergey +*************************************************************************/ +void dsoptimalsplit2fast(real_1d_array &a, integer_1d_array &c, integer_1d_array &tiesbuf, integer_1d_array &cntbuf, real_1d_array &bufr, integer_1d_array &bufi, const ae_int_t n, const ae_int_t nc, const double alpha, ae_int_t &info, double &threshold, double &rms, double &cvrms, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void mlpserialize(const multilayerperceptron &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void mlpserialize(const multilayerperceptron &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void mlpunserialize(const std::string &s_in, multilayerperceptron &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void mlpunserialize(const std::istream &s_in, multilayerperceptron &obj); + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers, with linear output layer. Network weights are filled with small +random values. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreate0, but with one hidden layer (NHid neurons) with +non-linear activation function. Output layer is linear. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreate0, but with two hidden layers (NHid1 and NHid2 neurons) +with non-linear activation function. Output layer is linear. + $ALL + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. + +Activation function of the output layer takes values: + + (B, +INF), if D>=0 + +or + + (-INF, B), if D<0. + + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateB0 but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateB0 but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creates neural network with NIn inputs, NOut outputs, without hidden +layers with non-linear output layer. Network weights are filled with small +random values. Activation function of the output layer takes values [A,B]. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateR0, but with non-linear hidden layer. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateR0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpcreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creates classifier network with NIn inputs and NOut possible classes. +Network contains no hidden layers and linear output layer with SOFTMAX- +normalization (so outputs sums up to 1.0 and converge to posterior +probabilities). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec0(const ae_int_t nin, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateC0, but with one non-linear hidden layer. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as MLPCreateC0, but with two non-linear hidden layers. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Copying of neural network + +INPUT PARAMETERS: + Network1 - original + +OUTPUT PARAMETERS: + Network2 - copy + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpcopy(const multilayerperceptron &network1, multilayerperceptron &network2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function copies tunable parameters (weights/means/sigmas) from one +network to another with same architecture. It performs some rudimentary +checks that architectures are same, and throws exception if check fails. + +It is intended for fast copying of states between two network which are +known to have same geometry. + +INPUT PARAMETERS: + Network1 - source, must be correctly initialized + Network2 - target, must have same architecture + +OUTPUT PARAMETERS: + Network2 - network state is copied from source to target + + -- ALGLIB -- + Copyright 20.06.2013 by Bochkanov Sergey +*************************************************************************/ +void mlpcopytunableparameters(const multilayerperceptron &network1, multilayerperceptron &network2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Randomization of neural network weights + + -- ALGLIB -- + Copyright 06.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlprandomize(multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Randomization of neural network weights and standartisator + + -- ALGLIB -- + Copyright 10.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlprandomizefull(multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Internal subroutine. + + -- ALGLIB -- + Copyright 30.03.2008 by Bochkanov Sergey +*************************************************************************/ +void mlpinitpreprocessor(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns information about initialized network: number of inputs, outputs, +weights. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpproperties(const multilayerperceptron &network, ae_int_t &nin, ae_int_t &nout, ae_int_t &wcount, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns number of inputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetinputscount(const multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns number of outputs. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetoutputscount(const multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns number of weights. + + -- ALGLIB -- + Copyright 19.10.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetweightscount(const multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Tells whether network is SOFTMAX-normalized (i.e. classifier) or not. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +bool mlpissoftmax(const multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns total number of layers (including input, hidden and +output layers). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayerscount(const multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns size of K-th layer. + +K=0 corresponds to input layer, K=CNT-1 corresponds to output layer. + +Size of the output layer is always equal to the number of outputs, although +when we have softmax-normalized network, last neuron doesn't have any +connections - it is just zero. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpgetlayersize(const multilayerperceptron &network, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetinputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + +OUTPUT PARAMETERS: + Mean - mean term + Sigma - sigma term, guaranteed to be nonzero. + +I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. In case we have SOFTMAX-normalized network, +we return (Mean,Sigma)=(0.0,1.0). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetoutputscaling(const multilayerperceptron &network, const ae_int_t i, double &mean, double &sigma, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + +OUTPUT PARAMETERS: + FKind - activation function type (used by MLPActivationFunction()) + this value is zero for input or linear neurons + Threshold - also called offset, bias + zero for input neurons + +NOTE: this function throws exception if layer or neuron with given index +do not exists. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpgetneuroninfo(multilayerperceptron &network, const ae_int_t k, const ae_int_t i, ae_int_t &fkind, double &threshold, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + +RESULT: + connection weight (zero for non-existent connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. returns zero if neurons exist, but there is no connection between them + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +double mlpgetweight(multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets offset/scaling coefficients for I-th input of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +NTE: I-th input is passed through linear transformation + IN[i] = (IN[i]-Mean)/Sigma +before feeding to the network. This function sets Mean and Sigma. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetinputscaling(multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets offset/scaling coefficients for I-th output of the +network. + +INPUT PARAMETERS: + Network - network + I - input index + Mean - mean term + Sigma - sigma term (if zero, will be replaced by 1.0) + +OUTPUT PARAMETERS: + +NOTE: I-th output is passed through linear transformation + OUT[i] = OUT[i]*Sigma+Mean +before returning it to user. This function sets Sigma/Mean. In case we +have SOFTMAX-normalized network, you can not set (Sigma,Mean) to anything +other than(0.0,1.0) - this function will throw exception. + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetoutputscaling(multilayerperceptron &network, const ae_int_t i, const double mean, const double sigma, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function modifies information about Ith neuron of Kth layer + +INPUT PARAMETERS: + Network - network + K - layer index + I - neuron index (within layer) + FKind - activation function type (used by MLPActivationFunction()) + this value must be zero for input neurons + (you can not set activation function for input neurons) + Threshold - also called offset, bias + this value must be zero for input neurons + (you can not set threshold for input neurons) + +NOTES: +1. this function throws exception if layer or neuron with given index do + not exists. +2. this function also throws exception when you try to set non-linear + activation function for input neurons (any kind of network) or for output + neurons of classifier network. +3. this function throws exception when you try to set non-zero threshold for + input neurons (any kind of network). + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetneuroninfo(multilayerperceptron &network, const ae_int_t k, const ae_int_t i, const ae_int_t fkind, const double threshold, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function modifies information about connection from I0-th neuron of +K0-th layer to I1-th neuron of K1-th layer. + +INPUT PARAMETERS: + Network - network + K0 - layer index + I0 - neuron index (within layer) + K1 - layer index + I1 - neuron index (within layer) + W - connection weight (must be zero for non-existent + connections) + +This function: +1. throws exception if layer or neuron with given index do not exists. +2. throws exception if you try to set non-zero weight for non-existent + connection + + -- ALGLIB -- + Copyright 25.03.2011 by Bochkanov Sergey +*************************************************************************/ +void mlpsetweight(multilayerperceptron &network, const ae_int_t k0, const ae_int_t i0, const ae_int_t k1, const ae_int_t i1, const double w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Neural network activation function + +INPUT PARAMETERS: + NET - neuron input + K - function index (zero for linear function) + +OUTPUT PARAMETERS: + F - function + DF - its derivative + D2F - its second derivative + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpactivationfunction(const double net, const ae_int_t k, double &f, double &df, double &d2f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Network - neural network + X - input vector, array[0..NIn-1]. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also MLPProcessI + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpprocess(multilayerperceptron &network, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +'interactive' variant of MLPProcess for languages like Python which +support constructs like "Y = MLPProcess(NN,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 21.09.2010 by Bochkanov Sergey +*************************************************************************/ +void mlpprocessi(multilayerperceptron &network, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Error of the neural network on dataset given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0 + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Natural error function for neural network, internal subroutine. + +NOTE: this function is single-threaded. Unlike other error function, it +receives no speed-up from being executed in SMP mode. + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlperrorn(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Classification error of the neural network on dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: + classification error (number of misclassified cases) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +ae_int_t mlpclserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Relative classification error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 25.12.2008 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Relative classification error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. Sparse matrix must use CRS format + for storage. + NPoints - points count, >=0. + +RESULT: +Percent of incorrectly classified cases. Works both for classifier +networks and general purpose networks used as classifiers. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprelclserrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 08.01.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpavgce(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set given by +sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +CrossEntropy/(NPoints*LN(2)). +Zero if network solves regression task. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 9.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgcesparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set given. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +double mlprmserror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Root mean square error. Its meaning for regression task is obvious. As for +classification task, RMS error means error when estimating posterior +probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlprmserrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average absolute error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average absolute error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average error when estimating posterior probabilities. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgerrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average relative error on the test set. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + NPoints - points count. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 11.03.2008 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerror(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average relative error on the test set given by sparse matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + NPoints - points count, >=0. + +RESULT: +Its meaning for regression task is obvious. As for classification task, it +means average relative error when estimating posterior probability of +belonging to the correct class. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 09.08.2012 by Bochkanov Sergey +*************************************************************************/ +double mlpavgrelerrorsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Gradient calculation + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgrad(multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Gradient calculation (natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + X - input vector, length of array must be at least NIn + DesiredY- desired outputs, length of array must be at least NOut + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradn(multilayerperceptron &network, const real_1d_array &x, const real_1d_array &desiredy, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs given by sparse +matrices + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs. + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparse(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch gradient calculation for a subset of dataset + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in dense format; one sample = one row: + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs for a subset of +dataset given by set of indexes. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset in sparse format; one sample = one row: + * MATRIX MUST BE STORED IN CRS FORMAT + * first NIn columns contain inputs, + * for regression problem, next NOut columns store + desired outputs. + * for classification problem, next column (just one!) + stores class number. + SetSize - real size of XY, SetSize>=0; + Idx - subset of SubsetSize elements, array[SubsetSize]: + * Idx[I] stores row index in the original dataset which is + given by XY. Gradient is calculated with respect to rows + whose indexes are stored in Idx[]. + * Idx[] must store correct indexes; this function throws + an exception in case incorrect index (less than 0 or + larger than rows(XY)) is given + * Idx[] may store indexes in any order and even with + repetitions. + SubsetSize- number of elements in Idx[] array: + * positive value means that subset given by Idx[] is processed + * zero value results in zero gradient + * negative value means that full dataset is processed + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, SUM(sqr(y[i]-desiredy[i])/2,i) + Grad - gradient of E with respect to weights of network, + array[WCount] + +NOTE: when SubsetSize<0 is used full dataset by call MLPGradBatchSparse + function. + + -- ALGLIB -- + Copyright 26.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpgradbatchsparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &idx, const ae_int_t subsetsize, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch gradient calculation for a set of inputs/outputs +(natural error function is used) + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - set of inputs/outputs; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SSize - number of elements in XY + Grad - possibly preallocated array. If size of array is smaller + than WCount, it will be reallocated. It is recommended to + reuse previously allocated array to reduce allocation + overhead. + +OUTPUT PARAMETERS: + E - error function, sum-of-squares for regression networks, + cross-entropy for classification networks. + Grad - gradient of E with respect to weights of network, array[WCount] + + -- ALGLIB -- + Copyright 04.11.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpgradnbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch Hessian calculation (natural error function) using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessiannbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Batch Hessian calculation using R-algorithm. +Internal subroutine. + + -- ALGLIB -- + Copyright 26.01.2008 by Bochkanov Sergey. + + Hessian calculation based on R-algorithm described in + "Fast Exact Multiplication by the Hessian", + B. A. Pearlmutter, + Neural Computation, 1994. +*************************************************************************/ +void mlphessianbatch(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t ssize, double &e, real_1d_array &grad, real_2d_array &h, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset; one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of all types of errors on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - network initialized with one of the network creation funcs + XY - original dataset given by sparse matrix; + one sample = one row; + first NIn columns contain inputs, + next NOut columns - desired outputs. + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +OUTPUT PARAMETERS: + Rep - it contains all type of errors. + + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpallerrorssparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, modelerrors &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Error of the neural network on subset of dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format; + SetSize - real size of XY, SetSize>=0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsubset(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Error of the neural network on subset of sparse dataset. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + Network - neural network; + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Sparse matrix must use CRS format for + storage. + SetSize - real size of XY, SetSize>=0; + it is used when SubsetSize<0; + Subset - subset of SubsetSize elements, array[SubsetSize]; + SubsetSize- number of elements in Subset[] array: + * if SubsetSize>0, rows of XY with indices Subset[0]... + ...Subset[SubsetSize-1] are processed + * if SubsetSize=0, zeros are returned + * if SubsetSize<0, entire dataset is processed; Subset[] + array is ignored in this case. + +RESULT: + sum-of-squares error, SUM(sqr(y[i]-desired_y[i])/2) + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +dataset format is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 04.09.2012 by Bochkanov Sergey +*************************************************************************/ +double mlperrorsparsesubset(multilayerperceptron &network, const sparsematrix &xy, const ae_int_t setsize, const integer_1d_array &subset, const ae_int_t subsetsize, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void mlpeserialize(const mlpensemble &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void mlpeserialize(const mlpensemble &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void mlpeunserialize(const std::string &s_in, mlpensemble &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void mlpeunserialize(const std::istream &s_in, mlpensemble &obj); + + +/************************************************************************* +Like MLPCreate0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreate1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreate2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreate2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateB0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb0(const ae_int_t nin, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateB1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateB2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreateb2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double b, const double d, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateR0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater0(const ae_int_t nin, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateR1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateR2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreater2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const double a, const double b, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateC0, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec0(const ae_int_t nin, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateC1, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec1(const ae_int_t nin, const ae_int_t nhid, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like MLPCreateC2, but for ensembles. + + -- ALGLIB -- + Copyright 18.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatec2(const ae_int_t nin, const ae_int_t nhid1, const ae_int_t nhid2, const ae_int_t nout, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creates ensemble from network. Only network geometry is copied. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpecreatefromnetwork(const multilayerperceptron &network, const ae_int_t ensemblesize, mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Randomization of MLP ensemble + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlperandomize(mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Return ensemble properties (number of inputs and outputs). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeproperties(const mlpensemble &ensemble, ae_int_t &nin, ae_int_t &nout, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Return normalization type (whether ensemble is SOFTMAX-normalized or not). + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +bool mlpeissoftmax(const mlpensemble &ensemble, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + Ensemble- neural networks ensemble + X - input vector, array[0..NIn-1]. + Y - (possibly) preallocated buffer; if size of Y is less than + NOut, it will be reallocated. If it is large enough, it + is NOT reallocated, so we can save some time on reallocation. + + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocess(mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +'interactive' variant of MLPEProcess for languages like Python which +support constructs like "Y = MLPEProcess(LM,X)" and interactive mode of the +interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpeprocessi(mlpensemble &ensemble, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Works both for classifier betwork and for regression networks which +are used as classifiers. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlperelclserror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if ensemble solves regression task. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgce(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for classification task +RMS error means error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpermserror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgerror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + Ensemble- ensemble + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for classification task +it means average relative error when estimating posterior probabilities. + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +double mlpeavgrelerror(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes clusterizer object. Newly initialized object is +empty, i.e. it does not contain dataset. You should use it as follows: +1. creation +2. dataset is added with ClusterizerSetPoints() +3. additional parameters are set +3. clusterization is performed with one of the clustering functions + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizercreate(clusterizerstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset to the clusterizer structure. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm), non-squared + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +NOTE 1: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + +NOTE 2: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric + * k-means++ clustering algorithm may be used only with Euclidean + distance function + Thus, list of specific clustering algorithms you may use depends + on distance function you specify when you set your dataset. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetpoints(clusterizerstate &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, const xparams _xparams = alglib::xdefault); +void clusterizersetpoints(clusterizerstate &s, const real_2d_array &xy, const ae_int_t disttype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset given by distance matrix to the clusterizer +structure. It is important that dataset is not given explicitly - only +distance matrix is given. + +This function overrides all previous calls of ClusterizerSetPoints() or +ClusterizerSetDistances(). + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + D - array[NPoints,NPoints], distance matrix given by its upper + or lower triangle (main diagonal is ignored because its + entries are expected to be zero). + NPoints - number of points + IsUpper - whether upper or lower triangle of D is given. + +NOTE 1: different clustering algorithms have different limitations: + * agglomerative hierarchical clustering algorithms may be used with + any kind of distance metric, including one which is given by + distance matrix + * k-means++ clustering algorithm may be used only with Euclidean + distance function and explicitly given points - it can not be + used with dataset given by distance matrix + Thus, if you call this function, you will be unable to use k-means + clustering algorithm to process your problem. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetdistances(clusterizerstate &s, const real_2d_array &d, const ae_int_t npoints, const bool isupper, const xparams _xparams = alglib::xdefault); +void clusterizersetdistances(clusterizerstate &s, const real_2d_array &d, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets agglomerative hierarchical clustering algorithm + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Algo - algorithm type: + * 0 complete linkage (default algorithm) + * 1 single linkage + * 2 unweighted average linkage + * 3 weighted average linkage + * 4 Ward's method + +NOTE: Ward's method works correctly only with Euclidean distance, that's + why algorithm will return negative termination code (failure) for + any other distance type. + + It is possible, however, to use this method with user-supplied + distance matrix. It is your responsibility to pass one which was + calculated with Euclidean distance function. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetahcalgo(clusterizerstate &s, const ae_int_t algo, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets k-means properties: number of restarts and maximum +number of iterations per one run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Restarts- restarts count, >=1. + k-means++ algorithm performs several restarts and chooses + best set of centers (one with minimum squared distance). + MaxIts - maximum number of k-means iterations performed during one + run. >=0, zero value means that algorithm performs unlimited + number of iterations. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeanslimits(clusterizerstate &s, const ae_int_t restarts, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets k-means initialization algorithm. Several different +algorithms can be chosen, including k-means++. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + InitAlgo- initialization algorithm: + * 0 automatic selection ( different versions of ALGLIB + may select different algorithms) + * 1 random initialization + * 2 k-means++ initialization (best quality of initial + centers, but long non-parallelizable initialization + phase with bad cache locality) + * 3 "fast-greedy" algorithm with efficient, easy to + parallelize initialization. Quality of initial centers + is somewhat worse than that of k-means++. This + algorithm is a default one in the current version of + ALGLIB. + *-1 "debug" algorithm which always selects first K rows + of dataset; this algorithm is used for debug purposes + only. Do not use it in the industrial code! + + -- ALGLIB -- + Copyright 21.01.2015 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetkmeansinit(clusterizerstate &s, const ae_int_t initalgo, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets seed which is used to initialize internal RNG. By +default, deterministic seed is used - same for each run of clusterizer. If +you specify non-deterministic seed value, then some algorithms which +depend on random initialization (in current version: k-means) may return +slightly different results after each run. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void clusterizersetseed(clusterizerstate &s, const ae_int_t seed, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function performs agglomerative hierarchical clustering + +NOTE: Agglomerative hierarchical clustering algorithm has two phases: + distance matrix calculation and clustering itself. Only first phase + (distance matrix calculation) is accelerated by SIMD and SMP. Thus, + acceleration is significant only for medium or high-dimensional + problems. + + Although activating multithreading gives some speedup over single- + threaded execution, you should not expect nearly-linear scaling + with respect to cores count. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + +OUTPUT PARAMETERS: + Rep - clustering results; see description of AHCReport + structure for more information. + +NOTE 1: hierarchical clustering algorithms require large amounts of memory. + In particular, this implementation needs sizeof(double)*NPoints^2 + bytes, which are used to store distance matrix. In case we work + with user-supplied matrix, this amount is multiplied by 2 (we have + to store original matrix and to work with its copy). + + For example, problem with 10000 points would require 800M of RAM, + even when working in a 1-dimensional space. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunahc(clusterizerstate &s, ahcreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function performs clustering by k-means++ algorithm. + +You may change algorithm properties by calling: +* ClusterizerSetKMeansLimits() to change number of restarts or iterations +* ClusterizerSetKMeansInit() to change initialization algorithm + +By default, one restart and unlimited number of iterations are used. +Initialization algorithm is chosen automatically. + +NOTE: k-means clustering algorithm has two phases: selection of initial + centers and clustering itself. ALGLIB parallelizes both phases. + Parallel version is optimized for the following scenario: medium or + high-dimensional problem (8 or more dimensions) with large number of + points and clusters. However, some speed-up can be obtained even + when assumptions above are violated. + +INPUT PARAMETERS: + S - clusterizer state, initialized by ClusterizerCreate() + K - number of clusters, K>=0. + K can be zero only when algorithm is called for empty + dataset, in this case completion code is set to + success (+1). + If K=0 and dataset size is non-zero, we can not + meaningfully assign points to some center (there are no + centers because K=0) and return -3 as completion code + (failure). + +OUTPUT PARAMETERS: + Rep - clustering results; see description of KMeansReport + structure for more information. + +NOTE 1: k-means clustering can be performed only for datasets with + Euclidean distance function. Algorithm will return negative + completion code in Rep.TerminationType in case dataset was added + to clusterizer with DistType other than Euclidean (or dataset was + specified by distance matrix instead of explicitly given points). + +NOTE 2: by default, k-means uses non-deterministic seed to initialize RNG + which is used to select initial centers. As result, each run of + algorithm may return different values. If you need deterministic + behavior, use ClusterizerSetSeed() function. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizerrunkmeans(clusterizerstate &s, const ae_int_t k, kmeansreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns distance matrix for dataset + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points, >=0 + NFeatures- number of features, >=1 + DistType- distance function: + * 0 Chebyshev distance (L-inf norm) + * 1 city block distance (L1 norm) + * 2 Euclidean distance (L2 norm, non-squared) + * 10 Pearson correlation: + dist(a,b) = 1-corr(a,b) + * 11 Absolute Pearson correlation: + dist(a,b) = 1-|corr(a,b)| + * 12 Uncentered Pearson correlation (cosine of the angle): + dist(a,b) = a'*b/(|a|*|b|) + * 13 Absolute uncentered Pearson correlation + dist(a,b) = |a'*b|/(|a|*|b|) + * 20 Spearman rank correlation: + dist(a,b) = 1-rankcorr(a,b) + * 21 Absolute Spearman rank correlation + dist(a,b) = 1-|rankcorr(a,b)| + +OUTPUT PARAMETERS: + D - array[NPoints,NPoints], distance matrix + (full matrix is returned, with lower and upper triangles) + +NOTE: different distance functions have different performance penalty: + * Euclidean or Pearson correlation distances are the fastest ones + * Spearman correlation distance function is a bit slower + * city block and Chebyshev distances are order of magnitude slower + + The reason behing difference in performance is that correlation-based + distance functions are computed using optimized linear algebra kernels, + while Chebyshev and city block distance functions are computed using + simple nested loops with two branches at each iteration. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 10.07.2012 by Bochkanov Sergey +*************************************************************************/ +void clusterizergetdistances(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const ae_int_t disttype, real_2d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function takes as input clusterization report Rep, desired clusters +count K, and builds top K clusters from hierarchical clusterization tree. +It returns assignment of points to clusters (array of cluster indexes). + +INPUT PARAMETERS: + Rep - report from ClusterizerRunAHC() performed on XY + K - desired number of clusters, 1<=K<=NPoints. + K can be zero only when NPoints=0. + +OUTPUT PARAMETERS: + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]=0 + +OUTPUT PARAMETERS: + K - number of clusters, 1<=K<=NPoints + CIdx - array[NPoints], I-th element contains cluster index (from + 0 to K-1) for I-th point of the dataset. + CZ - array[K]. This array allows to convert cluster indexes + returned by this function to indexes used by Rep.Z. J-th + cluster returned by this function corresponds to CZ[J]-th + cluster stored in Rep.Z/PZ/PM. + It is guaranteed that CZ[I]=1 + NVars - number of independent variables, NVars>=1 + NClasses - indicates type of the problem being solved: + * NClasses>=2 means that classification problem is + solved (last column of the dataset stores class + number) + * NClasses=1 means that regression problem is solved + (last column of the dataset stores variable value) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetdataset(decisionforestbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets number of variables (in [1,NVars] range) used by +decision forest construction algorithm. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + RndVars - number of randomly selected variables; values outside + of [1,NVars] range are silently clipped. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvars(decisionforestbuilder &s, const ae_int_t rndvars, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets number of variables used by decision forest construction +algorithm as a fraction of total variable count (0,1) range. + +The default option is to use roughly sqrt(NVars) variables. + +INPUT PARAMETERS: + S - decision forest builder object + F - round(NVars*F) variables are selected + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsratio(decisionforestbuilder &s, const double f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells decision forest builder to automatically choose number +of variables used by decision forest construction algorithm. Roughly +sqrt(NVars) variables will be used. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrndvarsauto(decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets size of dataset subsample generated the decision forest +construction algorithm. Size is specified as a fraction of total dataset +size. + +The default option is to use 50% of the dataset for training, 50% for the +OOB estimates. You can decrease fraction F down to 10%, 1% or even below +in order to reduce overfitting. + +INPUT PARAMETERS: + S - decision forest builder object + F - fraction of the dataset to use, in (0,1] range. Values + outside of this range will be silently clipped. At + least one element is always selected for the training + set. + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetsubsampleratio(decisionforestbuilder &s, const double f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets seed used by internal RNG for random subsampling and +random selection of variable subsets. + +By default random seed is used, i.e. every time you build decision forest, +we seed generator with new value obtained from system-wide RNG. Thus, +decision forest builder returns non-deterministic results. You can change +such behavior by specyfing fixed positive seed value. + +INPUT PARAMETERS: + S - decision forest builder object + SeedVal - seed value: + * positive values are used for seeding RNG with fixed + seed, i.e. subsequent runs on same data will return + same decision forests + * non-positive seed means that random seed is used + for every run of builder, i.e. subsequent runs on + same datasets will return slightly different + decision forests + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetseed(decisionforestbuilder &s, const ae_int_t seedval, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets random decision forest construction algorithm. + +As for now, only one decision forest construction algorithm is supported - +a dense "baseline" RDF algorithm. + +INPUT PARAMETERS: + S - decision forest builder object + AlgoType - algorithm type: + * 0 = baseline dense RDF + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfalgo(decisionforestbuilder &s, const ae_int_t algotype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets split selection algorithm used by decision forest +classifier. You may choose several algorithms, with different speed and +quality of the results. + +INPUT PARAMETERS: + S - decision forest builder object + SplitStrength- split type: + * 0 = split at the random position, fastest one + * 1 = split at the middle of the range + * 2 = strong split at the best point of the range (default) + +OUTPUT PARAMETERS: + S - decision forest builder, see + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetrdfsplitstrength(decisionforestbuilder &s, const ae_int_t splitstrength, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells decision forest construction algorithm to use +Gini impurity based variable importance estimation (also known as MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on training sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and beautifully normalized (sum to +one) but have following downsides: +* They ALWAYS sum to 1.0, even if output is completely unpredictable. I.e. + MDI allows to order variables by importance, but does not tell us about + "absolute" importances of variables +* there exist some bias towards continuous and high-cardinality categorical + variables + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancetrngini(decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells decision forest construction algorithm to use +out-of-bag version of Gini variable importance estimation (also known as +OOB-MDI). + +This version of importance estimation algorithm analyzes mean decrease in +impurity (MDI) on out-of-bag sample during splits. The result is divided +by impurity at the root node in order to produce estimate in [0,1] range. + +Such estimates are fast to calculate and resistant to overfitting issues +(thanks to the out-of-bag estimates used). However, OOB Gini rating has +following downsides: +* there exist some bias towards continuous and high-cardinality categorical + variables +* Gini rating allows us to order variables by importance, but it is hard + to define importance of the variable by itself. + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportanceoobgini(decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells decision forest construction algorithm to use +permutation variable importance estimator (also known as MDA). + +This version of importance estimation algorithm analyzes mean increase in +out-of-bag sum of squared residuals after random permutation of J-th +variable. The result is divided by error computed with all variables being +perturbed in order to produce R-squared-like estimate in [0,1] range. + +Such estimate is slower to calculate than Gini-based rating because it +needs multiple inference runs for each of variables being studied. + +ALGLIB uses parallelized and highly optimized algorithm which analyzes +path through the decision tree and allows to handle most perturbations +in O(1) time; nevertheless, requesting MDA importances may increase forest +construction time from 10% to 200% (or more, if you have thousands of +variables). + +However, MDA rating has following benefits over Gini-based ones: +* no bias towards specific variable types +* ability to directly evaluate "absolute" importance of some variable at + "0 to 1" scale (contrary to Gini-based rating, which returns comparative + importances). + +NOTE: informally speaking, MDA (permutation importance) rating answers the + question "what part of the model predictive power is ruined by + permuting k-th variable?" while MDI tells us "what part of the model + predictive power was achieved due to usage of k-th variable". + + Thus, MDA rates each variable independently at "0 to 1" scale while + MDI (and OOB-MDI too) tends to divide "unit amount of importance" + between several important variables. + + If all variables are equally important, they will have same + MDI/OOB-MDI rating, equal (for OOB-MDI: roughly equal) to 1/NVars. + However, roughly same picture will be produced for the "all + variables provide information no one is critical" situation and for + the "all variables are critical, drop any one, everything is ruined" + situation. + + Contrary to that, MDA will rate critical variable as ~1.0 important, + and important but non-critical variable will have less than unit + rating. + +NOTE: quite an often MDA and MDI return same results. It generally happens + on problems with low test set error (a few percents at most) and + large enough training set to avoid overfitting. + + The difference between MDA, MDI and OOB-MDI becomes important only + on "hard" tasks with high test set error and/or small training set. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will produce: + * importance estimates in rep.varimportances field + * variable ranks in rep.topvars field + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancepermutation(decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells decision forest construction algorithm to skip +variable importance estimation. + +INPUT PARAMETERS: + S - decision forest builder object + +OUTPUT PARAMETERS: + S - decision forest builder object. Next call to the forest + construction function will result in forest being built + without variable importance estimation. + + -- ALGLIB -- + Copyright 29.07.2019 by Bochkanov Sergey +*************************************************************************/ +void dfbuildersetimportancenone(decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is an alias for dfbuilderpeekprogress(), left in ALGLIB for +backward compatibility reasons. + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuildergetprogress(const decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to peek into decision forest construction process +from some other thread and get current progress indicator. + +It returns value in [0,1]. + +INPUT PARAMETERS: + S - decision forest builder object used to build forest + in some other thread + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +double dfbuilderpeekprogress(const decisionforestbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds decision forest according to current settings using +dataset internally stored in the builder object. Dense algorithm is used. + +NOTE: this function uses dense algorithm for forest construction + independently from the dataset format (dense or sparse). + +NOTE: forest built with this function is stored in-memory using 64-bit + data structures for offsets/indexes/split values. It is possible to + convert forest into more memory-efficient compressed binary + representation. Depending on the problem properties, 3.7x-5.7x + compression factors are possible. + + The downsides of compression are (a) slight reduction in the model + accuracy and (b) ~1.5x reduction in the inference speed (due to + increased complexity of the storage format). + + See comments on dfbinarycompression() for more info. + +Default settings are used by the algorithm; you can tweak them with the +help of the following functions: +* dfbuildersetrfactor() - to control a fraction of the dataset used for + subsampling +* dfbuildersetrandomvars() - to control number of variables randomly chosen + for decision rule creation + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - decision forest builder object + NTrees - NTrees>=1, number of trees to train + +OUTPUT PARAMETERS: + DF - decision forest. You can compress this forest to more + compact 16-bit representation with dfbinarycompression() + Rep - report, see below for information on its fields. + +=== report information produced by forest construction function ========== + +Decision forest training report includes following information: +* training set errors +* out-of-bag estimates of errors +* variable importance ratings + +Following fields are used to store information: +* training set errors are stored in rep.relclserror, rep.avgce, rep.rmserror, + rep.avgerror and rep.avgrelerror +* out-of-bag estimates of errors are stored in rep.oobrelclserror, rep.oobavgce, + rep.oobrmserror, rep.oobavgerror and rep.oobavgrelerror + +Variable importance reports, if requested by dfbuildersetimportancegini(), +dfbuildersetimportancetrngini() or dfbuildersetimportancepermutation() +call, are stored in: +* rep.varimportances field stores importance ratings +* rep.topvars stores variable indexes ordered from the most important to + less important ones + +You can find more information about report fields in: +* comments on dfreport structure +* comments on dfbuildersetimportancegini function +* comments on dfbuildersetimportancetrngini function +* comments on dfbuildersetimportancepermutation function + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +void dfbuilderbuildrandomforest(decisionforestbuilder &s, const ae_int_t ntrees, decisionforest &df, dfreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function performs binary compression of the decision forest. + +Original decision forest produced by the forest builder is stored using +64-bit representation for all numbers - offsets, variable indexes, split +points. + +It is possible to significantly reduce model size by means of: +* using compressed dynamic encoding for integers (offsets and variable + indexes), which uses just 1 byte to store small ints (less than 128), + just 2 bytes for larger values (less than 128^2) and so on +* storing floating point numbers using 8-bit exponent and 16-bit mantissa + +As result, model needs significantly less memory (compression factor +depends on variable and class counts). In particular: +* NVars<128 and NClasses<128 result in 4.4x-5.7x model size reduction +* NVars<16384 and NClasses<128 result in 3.7x-4.5x model size reduction + +Such storage format performs lossless compression of all integers, but +compression of floating point values (split values) is lossy, with roughly +0.01% relative error introduced during rounding. Thus, we recommend you to +re-evaluate model accuracy after compression. + +Another downside of compression is ~1.5x reduction in the inference +speed due to necessity of dynamic decompression of the compressed model. + +INPUT PARAMETERS: + DF - decision forest built by forest builder + +OUTPUT PARAMETERS: + DF - replaced by compressed forest + +RESULT: + compression factor (in-RAM size of the compressed model vs than of the + uncompressed one), positive number larger than 1.0 + + -- ALGLIB -- + Copyright 22.07.2019 by Bochkanov Sergey +*************************************************************************/ +double dfbinarycompression(decisionforest &df, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inference using decision forest + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + +INPUT PARAMETERS: + DF - decision forest model + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfprocess(const decisionforest &df, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +'interactive' variant of DFProcess for languages like Python which support +constructs like "Y = DFProcessI(DF,X)" and interactive mode of interpreter + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 28.02.2010 by Bochkanov Sergey +*************************************************************************/ +void dfprocessi(const decisionforest &df, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for dfprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - DF model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double dfprocess0(decisionforest &model, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling dfprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use dftsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - decision forest model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t dfclassify(decisionforest &model, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inference using decision forest + +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same DF model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + DF - decision forest model + Buf - buffer object, must be allocated specifically for this + model with dfcreatebuffer(). + X - input vector, array[NVars] + Y - possibly preallocated buffer, reallocated if too small + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + +See also DFProcessI. + + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dftsprocess(const decisionforest &df, decisionforestbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrelclserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/(NPoints*LN(2)). + Zero if model solves regression task. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgce(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + Its meaning for regression task is obvious. As for + classification task, RMS error means error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfrmserror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average error when estimating posterior + probabilities. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average relative error on the test set + +INPUT PARAMETERS: + DF - decision forest model + XY - test set + NPoints - test set size + +RESULT: + Its meaning for regression task is obvious. As for + classification task, it means average relative error when estimating + posterior probability of belonging to the correct class. + + -- ALGLIB -- + Copyright 16.02.2009 by Bochkanov Sergey +*************************************************************************/ +double dfavgrelerror(const decisionforest &df, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforest(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const double r, ae_int_t &info, decisionforest &df, dfreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds random decision forest. + +--------- DEPRECATED VERSION! USE DECISION FOREST BUILDER OBJECT --------- + + -- ALGLIB -- + Copyright 19.02.2009 by Bochkanov Sergey +*************************************************************************/ +void dfbuildrandomdecisionforestx1(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const ae_int_t ntrees, const ae_int_t nrndvars, const double r, ae_int_t &info, decisionforest &df, dfreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Linear regression + +Subroutine builds model: + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + A(N) + +and model found in ALGLIB format, covariation matrix, training set errors +(rms, average, average relative) and leave-one-out cross-validation +estimate of the generalization error. CV estimate calculated using fast +algorithm with O(NPoints*NVars) complexity. + +When covariation matrix is calculated standard deviations of function +values are assumed to be equal to RMS error on the training set. + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + NPoints - training set size, NPoints>NVars+1. An exception is + generated otherwise. + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuild(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); +void lrbuild(const real_2d_array &xy, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Linear regression + +Variant of LRBuild which uses vector of standatd deviations (errors in +function values). + +INPUT PARAMETERS: + XY - training set, array [0..NPoints-1,0..NVars]: + * NVars columns - independent variables + * last column - dependent variable + S - standard deviations (errors in function values) + array[NPoints], S[i]>0. + NPoints - training set size, NPoints>NVars+1 + NVars - number of independent variables + +OUTPUT PARAMETERS: + LM - linear model in the ALGLIB format. Use subroutines of + this unit to work with the model. + Rep - additional results, see comments on LRReport structure. + + -- ALGLIB -- + Copyright 02.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuilds(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); +void lrbuilds(const real_2d_array &xy, const real_1d_array &s, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like LRBuildS, but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); +void lrbuildzs(const real_2d_array &xy, const real_1d_array &s, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Like LRBuild but builds model + + Y = A(0)*X[0] + ... + A(N-1)*X[N-1] + +i.e. with zero constant term. + + -- ALGLIB -- + Copyright 30.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lrbuildz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); +void lrbuildz(const real_2d_array &xy, linearmodel &lm, lrreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacks coefficients of linear model. + +INPUT PARAMETERS: + LM - linear model in ALGLIB format + +OUTPUT PARAMETERS: + V - coefficients, array[0..NVars] + constant term (intercept) is stored in the V[NVars]. + NVars - number of independent variables (one less than number + of coefficients) + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrunpack(const linearmodel &lm, real_1d_array &v, ae_int_t &nvars, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +"Packs" coefficients and creates linear model in ALGLIB format (LRUnpack +reversed). + +INPUT PARAMETERS: + V - coefficients, array[0..NVars] + NVars - number of independent variables + +OUTPUT PAREMETERS: + LM - linear model. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +void lrpack(const real_1d_array &v, const ae_int_t nvars, linearmodel &lm, const xparams _xparams = alglib::xdefault); +void lrpack(const real_1d_array &v, linearmodel &lm, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procesing + +INPUT PARAMETERS: + LM - linear model + X - input vector, array[0..NVars-1]. + +Result: + value of linear model regression estimate + + -- ALGLIB -- + Copyright 03.09.2008 by Bochkanov Sergey +*************************************************************************/ +double lrprocess(const linearmodel &lm, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lrrmserror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set + +INPUT PARAMETERS: + LM - linear model + XY - test set + NPoints - test set size + +RESULT: + average relative error. + + -- ALGLIB -- + Copyright 30.08.2008 by Bochkanov Sergey +*************************************************************************/ +double lravgrelerror(const linearmodel &lm, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Filters: simple moving averages (unsymmetric). + +This filter replaces array by results of SMA(K) filter. SMA(K) is defined +as filter which averages at most K previous points (previous - not points +AROUND central point) - or less, in case of the first K-1 points. + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with SMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filtersma(real_1d_array &x, const ae_int_t n, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void filtersma(real_1d_array &x, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Filters: exponential moving averages. + +This filter replaces array by results of EMA(alpha) filter. EMA(alpha) is +defined as filter which replaces X[] by S[]: + S[0] = X[0] + S[t] = alpha*X[t] + (1-alpha)*S[t-1] + +INPUT PARAMETERS: + X - array[N], array to process. It can be larger than N, + in this case only first N points are processed. + N - points count, N>=0 + alpha - 0=0 + K - K>=1 (K can be larger than N , such cases will be + correctly handled). Window width. K=1 corresponds to + identity transformation (nothing changes). + +OUTPUT PARAMETERS: + X - array, whose first N elements were processed with LRMA(K) + +NOTE 1: this function uses efficient in-place algorithm which does not + allocate temporary arrays. + +NOTE 2: this algorithm makes only one pass through array and uses running + sum to speed-up calculation of the averages. Additional measures + are taken to ensure that running sum on a long sequence of zero + elements will be correctly reset to zero even in the presence of + round-off error. + +NOTE 3: this is unsymmetric version of the algorithm, which does NOT + averages points after the current one. Only X[i], X[i-1], ... are + used when calculating new value of X[i]. We should also note that + this algorithm uses BOTH previous points and current one, i.e. + new value of X[i] depends on BOTH previous point and X[i] itself. + + -- ALGLIB -- + Copyright 25.10.2011 by Bochkanov Sergey +*************************************************************************/ +void filterlrma(real_1d_array &x, const ae_int_t n, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void filterlrma(real_1d_array &x, const ae_int_t k, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function creates SSA model object. Right after creation model is in +"dummy" mode - you can add data, but analyzing/prediction will return +just zeros (it assumes that basis is empty). + +HOW TO USE SSA MODEL: + +1. create model with ssacreate() +2. add data with one/many ssaaddsequence() calls +3. choose SSA algorithm with one of ssasetalgo...() functions: + * ssasetalgotopkdirect() for direct one-run analysis + * ssasetalgotopkrealtime() for algorithm optimized for many subsequent + runs with warm-start capabilities + * ssasetalgoprecomputed() for user-supplied basis +4. set window width with ssasetwindow() +5. perform one of the analysis-related activities: + a) call ssagetbasis() to get basis + b) call ssaanalyzelast() ssaanalyzesequence() or ssaanalyzelastwindow() + to perform analysis (trend/noise separation) + c) call one of the forecasting functions (ssaforecastlast() or + ssaforecastsequence()) to perform prediction; alternatively, you can + extract linear recurrence coefficients with ssagetlrr(). + SSA analysis will be performed during first call to analysis-related + function. SSA model is smart enough to track all changes in the dataset + and model settings, to cache previously computed basis and to + re-evaluate basis only when necessary. + +Additionally, if your setting involves constant stream of incoming data, +you can perform quick update already calculated model with one of the +incremental append-and-update functions: ssaappendpointandupdate() or +ssaappendsequenceandupdate(). + +NOTE: steps (2), (3), (4) can be performed in arbitrary order. + +INPUT PARAMETERS: + none + +OUTPUT PARAMETERS: + S - structure which stores model state + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacreate(ssamodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets window width for SSA model. You should call it before +analysis phase. Default window width is 1 (not for real use). + +Special notes: +* this function call can be performed at any moment before first call to + analysis-related functions +* changing window width invalidates internally stored basis; if you change + window width AFTER you call analysis-related function, next analysis + phase will require re-calculation of the basis according to current + algorithm. +* calling this function with exactly same window width as current one has + no effect +* if you specify window width larger than any data sequence stored in the + model, analysis will return zero basis. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + WindowWidth - >=1, new window width + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetwindow(ssamodel &s, const ae_int_t windowwidth, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets seed which is used to initialize internal RNG when +we make pseudorandom decisions on model updates. + +By default, deterministic seed is used - which results in same sequence of +pseudorandom decisions every time you run SSA model. If you specify non- +deterministic seed value, then SSA model may return slightly different +results after each run. + +This function can be useful when you have several SSA models updated with +sseappendpointandupdate() called with 01 means that delayed power-up is performed + + -- ALGLIB -- + Copyright 03.11.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetpoweruplength(ssamodel &s, const ae_int_t pwlen, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets memory limit of SSA analysis. + +Straightforward SSA with sequence length T and window width W needs O(T*W) +memory. It is possible to reduce memory consumption by splitting task into +smaller chunks. + +Thus function allows you to specify approximate memory limit (measured in +double precision numbers used for buffers). Actual memory consumption will +be comparable to the number specified by you. + +Default memory limit is 50.000.000 (400Mbytes) in current version. + +INPUT PARAMETERS: + S - SSA model + MemLimit- memory limit, >=0. Zero value means no limit. + + -- ALGLIB -- + Copyright 20.12.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetmemorylimit(ssamodel &s, const ae_int_t memlimit, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds data sequence to SSA model. Only single-dimensional +sequences are supported. + +What is a sequences? Following definitions/requirements apply: +* a sequence is an array of values measured in subsequent, equally + separated time moments (ticks). +* you may have many sequences in your dataset; say, one sequence may + correspond to one trading session. +* sequence length should be larger than current window length (shorter + sequences will be ignored during analysis). +* analysis is performed within a sequence; different sequences are NOT + stacked together to produce one large contiguous stream of data. +* analysis is performed for all sequences at once, i.e. same set of basis + vectors is computed for all sequences + +INCREMENTAL ANALYSIS + +This function is non intended for incremental updates of previously found +SSA basis. Calling it invalidates all previous analysis results (basis is +reset and will be recalculated from zero during next analysis). + +If you want to perform incremental/real-time SSA, consider using +following functions: +* ssaappendpointandupdate() for appending one point +* ssaappendsequenceandupdate() for appending new sequence + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - array[N], data, can be larger (additional values + are ignored) + N - data length, can be automatically determined from + the array length. N>=0. + +OUTPUT PARAMETERS: + S - SSA model, updated + +NOTE: you can clear dataset with ssacleardata() + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaaddsequence(ssamodel &s, const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +void ssaaddsequence(ssamodel &s, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends single point to last data sequence stored in the SSA +model and tries to update model in the incremental manner (if possible +with current algorithm). + +If you want to add more than one point at once: +* if you want to add M points to the same sequence, perform M-1 calls with + UpdateIts parameter set to 0.0, and last call with non-zero UpdateIts. +* if you want to add new sequence, use ssaappendsequenceandupdate() + +Running time of this function does NOT depend on dataset size, only on +window width and number of singular vectors. Depending on algorithm being +used, incremental update has complexity: +* for top-K real time - O(UpdateIts*K*Width^2), with fractional UpdateIts +* for top-K direct - O(Width^3) for any non-zero UpdateIts +* for precomputed basis - O(1), no update is performed + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + X - new point + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=1, number of ticks in the sequence + UpdateIts - >=0, floating point (!) value, desired update + frequency: + * zero value means that point is stored, but no + update is performed + * integer part of the value means that specified + number of iterations is always performed + * fractional part of the value means that one + iteration is performed with this probability. + + Recommended value: 0=1 + NBasis - number of basis vectors, 1<=NBasis<=WindowWidth + +OUTPUT PARAMETERS: + S - updated model + +NOTE: calling this function invalidates basis in all cases. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgoprecomputed(ssamodel &s, const real_2d_array &a, const ae_int_t windowwidth, const ae_int_t nbasis, const xparams _xparams = alglib::xdefault); +void ssasetalgoprecomputed(ssamodel &s, const real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets SSA algorithm to "direct top-K" algorithm. + +"Direct top-K" algorithm performs full SVD of the N*WINDOW trajectory +matrix (hence its name - direct solver is used), then extracts top K +components. Overall running time is O(N*WINDOW^2), where N is a number of +ticks in the dataset, WINDOW is window width. + +This algorithm may handle "append" requests which add just one/few ticks +to the end of the last sequence in O(WINDOW^3) time, which is ~N/WINDOW +times faster than re-computing everything from scratch. + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkdirect(ssamodel &s, const ae_int_t topk, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets SSA algorithm to "top-K real time algorithm". This algo +extracts K components with largest singular values. + +It is real-time version of top-K algorithm which is optimized for +incremental processing and fast start-up. Internally it uses subspace +eigensolver for truncated SVD. It results in ability to perform quick +updates of the basis when only a few points/sequences is added to dataset. + +Performance profile of the algorithm is given below: +* O(K*WindowWidth^2) running time for incremental update of the dataset + with one of the "append-and-update" functions (ssaappendpointandupdate() + or ssaappendsequenceandupdate()). +* O(N*WindowWidth^2) running time for initial basis evaluation (N=size of + dataset) +* ability to split costly initialization across several incremental + updates of the basis (so called "Power-Up" functionality, activated by + ssasetpoweruplength() function) + +INPUT PARAMETERS: + S - SSA model + TopK - number of components to analyze; TopK>=1. + +OUTPUT PARAMETERS: + S - updated model + +NOTE: this algorithm is optimized for large-scale tasks with large + datasets. On toy problems with just 5-10 points it can return basis + which is slightly different from that returned by direct algorithm + (ssasetalgotopkdirect() function). However, the difference becomes + negligible as dataset grows. + +NOTE: TopK>WindowWidth is silently decreased to WindowWidth during analysis + phase + +NOTE: calling this function invalidates basis, except for the situation + when this algorithm was already set with same parameters. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssasetalgotopkrealtime(ssamodel &s, const ae_int_t topk, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function clears all data stored in the model and invalidates all +basis components found so far. + +INPUT PARAMETERS: + S - SSA model created with ssacreate() + +OUTPUT PARAMETERS: + S - SSA model, updated + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssacleardata(ssamodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function executes SSA on internally stored dataset and returns basis +found by current method. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth,NBasis], basis; vectors are + stored in matrix columns, by descreasing variance + SV - array[NBasis]: + * zeros - for model initialized with SSASetAlgoPrecomputed() + * singular values - for other algorithms + WindowWidth - current window + NBasis - basis size + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns basis with +just one zero vector. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetbasis(ssamodel &s, real_2d_array &a, real_1d_array &sv, ae_int_t &windowwidth, ae_int_t &nbasis, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns linear recurrence relation (LRR) coefficients found +by current SSA algorithm. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + A - array[WindowWidth-1]. Coefficients of the + linear recurrence of the form: + X[W-1] = X[W-2]*A[W-2] + X[W-3]*A[W-3] + ... + X[0]*A[0]. + Empty array for WindowWidth=1. + WindowWidth - current window width + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Calling this function in degenerate cases (no data or all data are +shorter than window size; no algorithm is specified) returns zeros. + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssagetlrr(ssamodel &s, real_1d_array &a, ae_int_t &windowwidth, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function executes SSA on internally stored dataset and returns +analysis for the last window of the last sequence. Such analysis is +an lightweight alternative for full scale reconstruction (see below). + +Typical use case for this function is real-time setting, when you are +interested in quick-and-dirty (very quick and very dirty) processing of +just a few last ticks of the trend. + +IMPORTANT: full scale SSA involves analysis of the ENTIRE dataset, + with reconstruction being done for all positions of sliding + window with subsequent hankelization (diagonal averaging) of + the resulting matrix. + + Such analysis requires O((DataLen-Window)*Window*NBasis) FLOPs + and can be quite costly. However, it has nice noise-canceling + effects due to averaging. + + This function performs REDUCED analysis of the last window. It + is much faster - just O(Window*NBasis), but its results are + DIFFERENT from that of ssaanalyzelast(). In particular, first + few points of the trend are much more prone to noise. + +INPUT PARAMETERS: + S - SSA model + +OUTPUT PARAMETERS: + Trend - array[WindowSize], reconstructed trend line + Noise - array[WindowSize], the rest of the signal; + it holds that ActualData = Trend+Noise. + NTicks - current WindowSize + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, WindowWidth ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelastwindow(ssamodel &s, real_1d_array &trend, real_1d_array &noise, ae_int_t &nticks, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the last NTicks of the last sequence + +If you want to analyze some other sequence, use ssaanalyzesequence(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +IMPORTANT: due to averaging this function returns different results for + different values of NTicks. It is expected and not a bug. + + For example: + * Trend[NTicks-1] is always same because it is not averaged in + any case (same applies to Trend[0]). + * Trend[NTicks-2] has different values for NTicks=WindowWidth + and NTicks=WindowWidth+1 because former case means that no + averaging is performed, and latter case means that averaging + using two sliding windows is performed. Larger values of + NTicks produce same results as NTicks=WindowWidth+1. + * ...and so on... + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks<=WindowWidth is handled + by analyzing last window and returning NTicks + last ticks. + * special case NTicks>LastSequenceLen is handled + by prepending result with NTicks-LastSequenceLen + zeros. + +OUTPUT PARAMETERS: + Trend - array[NTicks], reconstructed trend line + Noise - array[NTicks], the rest of the signal; + it holds that ActualData = Trend+Noise. + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + +In any case, only basis is reused. Reconstruction is performed from +scratch every time you call this function. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the window length (analysis can be done, + but we can not perform reconstruction on the last sequence) + +Calling this function in degenerate cases returns following result: +* in any case, NTicks ticks is returned +* trend is assumed to be zero +* noise is initialized by the last sequence; if last sequence is shorter + than the window size, it is moved to the end of the array, and the + beginning of the noise array is filled by zeros + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaanalyzelast(ssamodel &s, const ae_int_t nticks, real_1d_array &trend, real_1d_array &noise, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function: +* builds SSA basis using internally stored (entire) dataset +* returns reconstruction for the sequence being passed to this function + +If you want to analyze last sequence stored in the model, use +ssaanalyzelast(). + +Reconstruction phase involves generation of NTicks-WindowWidth sliding +windows, their decomposition using empirical orthogonal functions found by +SSA, followed by averaging of each data point across several overlapping +windows. Thus, every point in the output trend is reconstructed using up +to WindowWidth overlapping windows (WindowWidth windows exactly in the +inner points, just one window at the extremal points). + +PERFORMANCE: this function has O((NTicks-WindowWidth)*WindowWidth*NBasis) + running time. If you work in time-constrained setting and + have to analyze just a few last ticks, choosing NTicks equal + to WindowWidth+SmoothingLen, with SmoothingLen=1...WindowWidth + will result in good compromise between noise cancellation and + analysis speed. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], can be larger (only NTicks leading + elements will be used) + NTicks - number of ticks to analyze, Nticks>=1. + * special case of NTicks=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastlast(ssamodel &s, const ae_int_t nticks, real_1d_array &trend, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from the WindowWidth last elements of the + sequence. This stage is optional, you can turn it off if you pass + data which are already processed with SSA. Of course, you can turn it + off even for raw data, but it is not recommended - noise suppression is + very important for correct prediction. +* then, we apply LRR for last WindowWidth-1 elements of the extracted + trend. + +This function has following running time: +* O(NBasis*WindowWidth) for trend extraction phase +* O(WindowWidth*NTicks) for forecast phase + +NOTE: this algorithm performs prediction using only one - last - sliding + window. Predictions produced by such approach are smooth + continuations of the reconstructed trend line, but they can be + easily corrupted by noise. If you need noise-resistant prediction, + use ssaforecastavgsequence() function, which averages predictions + built using several sliding windows. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not; + if you do not know what to specify, pass True. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastsequence(ssamodel &s, const real_1d_array &data, const ae_int_t datalen, const ae_int_t forecastlen, const bool applysmoothing, real_1d_array &trend, const xparams _xparams = alglib::xdefault); +void ssaforecastsequence(ssamodel &s, const real_1d_array &data, const ae_int_t forecastlen, real_1d_array &trend, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a specified +number of ticks, returning value of trend. + +Forecast is performed as follows: +* SSA trend extraction is applied to last M sliding windows of the + internally stored dataset +* for each of M sliding windows, M predictions are built +* average value of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase (always performed) +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: noise reduction is ALWAYS applied by this algorithm; if you want to + apply recurrence relation to raw unprocessed data, use another + function - ssaforecastsequence() which allows to turn on and off + noise reduction phase. + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + NTicks - number of ticks to forecast, NTicks>=1 + +OUTPUT PARAMETERS: + Trend - array[NTicks], predicted trend line + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* last sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* NTicks copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=NTicks is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavglast(ssamodel &s, const ae_int_t m, const ae_int_t nticks, real_1d_array &trend, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds SSA basis and performs forecasting for a user- +specified sequence, returning value of trend. + +Forecasting is done in two stages: +* first, we extract trend from M last sliding windows of the sequence. + This stage is optional, you can turn it off if you pass data which + are already processed with SSA. Of course, you can turn it off even + for raw data, but it is not recommended - noise suppression is very + important for correct prediction. +* then, we apply LRR independently for M sliding windows +* average of M predictions is returned + +This function has following running time: +* O(NBasis*WindowWidth*M) for trend extraction phase +* O(WindowWidth*NTicks*M) for forecast phase + +NOTE: combination of several predictions results in lesser sensitivity to + noise, but it may produce undesirable discontinuities between last + point of the trend and first point of the prediction. The reason is + that last point of the trend is usually corrupted by noise, but + average value of several predictions is less sensitive to noise, + thus discontinuity appears. It is not a bug. + +INPUT PARAMETERS: + S - SSA model + Data - array[NTicks], data to forecast + DataLen - number of ticks in the data, DataLen>=1 + M - number of sliding windows to combine, M>=1. If + your dataset has less than M sliding windows, this + parameter will be silently reduced. + ForecastLen - number of ticks to predict, ForecastLen>=1 + ApplySmoothing - whether to apply smoothing trend extraction or not. + if you do not know what to specify, pass true. + +OUTPUT PARAMETERS: + Trend - array[ForecastLen], forecasted trend + + +CACHING/REUSE OF THE BASIS + +Caching/reuse of previous results is performed: +* first call performs full run of SSA; basis is stored in the cache +* subsequent calls reuse previously cached basis +* if you call any function which changes model properties (window length, + algorithm, dataset), internal basis will be invalidated. +* the only calls which do NOT invalidate basis are listed below: + a) ssasetwindow() with same window length + b) ssaappendpointandupdate() + c) ssaappendsequenceandupdate() + d) ssasetalgotopk...() with exactly same K + Calling these functions will result in reuse of previously found basis. + + +HANDLING OF DEGENERATE CASES + +Following degenerate cases may happen: +* dataset is empty (no analysis can be done) +* all sequences are shorter than the window length,no analysis can be done +* no algorithm is specified (no analysis can be done) +* data sequence is shorter than the WindowWidth (analysis can be done, + but we can not perform forecasting on the last sequence) +* window lentgh is 1 (impossible to use for forecasting) +* SSA analysis algorithm is configured to extract basis whose size is + equal to window length (impossible to use for forecasting; only basis + whose size is less than window length can be used). + +Calling this function in degenerate cases returns following result: +* ForecastLen copies of the last value is returned for non-empty task with + large enough dataset, but with overcomplete basis (window width=1 or + basis size is equal to window width) +* zero trend with length=ForecastLen is returned for empty task + +No analysis is performed in degenerate cases (we immediately return dummy +values, no basis is ever constructed). + + -- ALGLIB -- + Copyright 30.10.2017 by Bochkanov Sergey +*************************************************************************/ +void ssaforecastavgsequence(ssamodel &s, const real_1d_array &data, const ae_int_t datalen, const ae_int_t m, const ae_int_t forecastlen, const bool applysmoothing, real_1d_array &trend, const xparams _xparams = alglib::xdefault); +void ssaforecastavgsequence(ssamodel &s, const real_1d_array &data, const ae_int_t m, const ae_int_t forecastlen, real_1d_array &trend, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Multiclass Fisher LDA + +The function finds coefficients of a linear combination which optimally +separates training set. Most suited for 2-class problems, see fisherldan() +for an variant that returns N-dimensional basis. + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - linear combination coefficients, array[NVars] + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherlda(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, real_1d_array &w, const xparams _xparams = alglib::xdefault); +void fisherlda(const real_2d_array &xy, const ae_int_t nclasses, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +N-dimensional multiclass Fisher LDA + +Subroutine finds coefficients of linear combinations which optimally separates +training set on classes. It returns N-dimensional basis whose vector are sorted +by quality of training set separation (in descending order). + +INPUT PARAMETERS: + XY - training set, array[NPoints,NVars+1]. + First NVars columns store values of independent + variables, the next column stores class index (from 0 + to NClasses-1) which dataset element belongs to. + Fractional values are rounded to the nearest integer. + The class index must be in the [0,NClasses-1] range, + an exception is generated otherwise. + NPoints - training set size, NPoints>=0 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + + +OUTPUT PARAMETERS: + W - basis, array[NVars,NVars] + columns of matrix stores basis vectors, sorted by + quality of training set separation (in descending order) + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 31.05.2008 by Bochkanov Sergey +*************************************************************************/ +void fisherldan(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, real_2d_array &w, const xparams _xparams = alglib::xdefault); +void fisherldan(const real_2d_array &xy, const ae_int_t nclasses, real_2d_array &w, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +DESCRIPTION: + +This function creates MCPD (Markov Chains for Population Data) solver. + +This solver can be used to find transition matrix P for N-dimensional +prediction problem where transition from X[i] to X[i+1] is modelled as + X[i+1] = P*X[i] +where X[i] and X[i+1] are N-dimensional population vectors (components of +each X are non-negative), and P is a N*N transition matrix (elements of P +are non-negative, each column sums to 1.0). + +Such models arise when when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is constant, i.e. there is no new individuals and no one + leaves population +* you want to model transitions of individuals from one state into another + +USAGE: + +Here we give very brief outline of the MCPD. We strongly recommend you to +read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on data analysis which is available at http://www.alglib.net/dataanalysis/ + +1. User initializes algorithm state with MCPDCreate() call + +2. User adds one or more tracks - sequences of states which describe + evolution of a system being modelled from different starting conditions + +3. User may add optional boundary, equality and/or linear constraints on + the coefficients of P by calling one of the following functions: + * MCPDSetEC() to set equality constraints + * MCPDSetBC() to set bound constraints + * MCPDSetLC() to set linear constraints + +4. Optionally, user may set custom weights for prediction errors (by + default, algorithm assigns non-equal, automatically chosen weights for + errors in the prediction of different components of X). It can be done + with a call of MCPDSetPredictionWeights() function. + +5. User calls MCPDSolve() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +6. User calls MCPDResults() to get solution + +INPUT PARAMETERS: + N - problem dimension, N>=1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreate(const ae_int_t n, mcpdstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "entry" state and is treated +in a special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +Such conditions basically mean that row of P which corresponds to "entry" +state is zero. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - at every moment of time there is some + (unpredictable) amount of "new" individuals, which can transit into one + of the states at the next turn, but still no one leaves population +* you want to model transitions of individuals from one state into another +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentry(const ae_int_t n, const ae_int_t entrystate, mcpdstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Exit-state" model, i.e. model where transition from X[i] to X[i+1] +is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +and one selected component of X[] is called "exit" state and is treated +in a special way: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that column of P which corresponds to +"exit" state is zero. Multiplication by such P may decrease sum of vector +components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant - individuals can move into "exit" state + and leave population at the next turn, but there are no new individuals +* amount of individuals which leave population can be predicted +* you want to model transitions of individuals from one state into another + (including transitions into the "exit" state) + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateexit(const ae_int_t n, const ae_int_t exitstate, mcpdstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +DESCRIPTION: + +This function is a specialized version of MCPDCreate() function, and we +recommend you to read comments for this function for general information +about MCPD solver. + +This function creates MCPD (Markov Chains for Population Data) solver +for "Entry-Exit-states" model, i.e. model where transition from X[i] to +X[i+1] is modelled as + X[i+1] = P*X[i] +where + X[i] and X[i+1] are N-dimensional state vectors + P is a N*N transition matrix +one selected component of X[] is called "entry" state and is treated in a +special way: + system state always transits from "entry" state to some another state + system state can not transit from any state into "entry" state +and another one component of X[] is called "exit" state and is treated in +a special way too: + system state can transit from any state into "exit" state + system state can not transit from "exit" state into any other state + transition operator discards "exit" state (makes it zero at each turn) +Such conditions basically mean that: + row of P which corresponds to "entry" state is zero + column of P which corresponds to "exit" state is zero +Multiplication by such P may decrease sum of vector components. + +Such models arise when: +* there is some population of individuals +* individuals can have different states +* individuals can transit from one state to another +* population size is NOT constant +* at every moment of time there is some (unpredictable) amount of "new" + individuals, which can transit into one of the states at the next turn +* some individuals can move (predictably) into "exit" state and leave + population at the next turn +* you want to model transitions of individuals from one state into another, + including transitions from the "entry" state and into the "exit" state. +* but you do NOT want to predict amount of "new" individuals because it + does not depends on individuals already present (hence system can not + transit INTO entry state - it can only transit FROM it). + +This model is discussed in more details in the ALGLIB User Guide (see +http://www.alglib.net/dataanalysis/ for more data). + +INPUT PARAMETERS: + N - problem dimension, N>=2 + EntryState- index of entry state, in 0..N-1 + ExitState- index of exit state, in 0..N-1 + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdcreateentryexit(const ae_int_t n, const ae_int_t entrystate, const ae_int_t exitstate, mcpdstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to add a track - sequence of system states at the +different moments of its evolution. + +You may add one or several tracks to the MCPD solver. In case you have +several tracks, they won't overwrite each other. For example, if you pass +two tracks, A1-A2-A3 (system at t=A+1, t=A+2 and t=A+3) and B1-B2-B3, then +solver will try to model transitions from t=A+1 to t=A+2, t=A+2 to t=A+3, +t=B+1 to t=B+2, t=B+2 to t=B+3. But it WONT mix these two tracks - i.e. it +wont try to model transition from t=A+3 to t=B+1. + +INPUT PARAMETERS: + S - solver + XY - track, array[K,N]: + * I-th row is a state at t=I + * elements of XY must be non-negative (exception will be + thrown on negative elements) + K - number of points in a track + * if given, only leading K rows of XY are used + * if not given, automatically determined from size of XY + +NOTES: + +1. Track may contain either proportional or population data: + * with proportional data all rows of XY must sum to 1.0, i.e. we have + proportions instead of absolute population values + * with population data rows of XY contain population counts and generally + do not sum to 1.0 (although they still must be non-negative) + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddtrack(mcpdstate &s, const real_2d_array &xy, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void mcpdaddtrack(mcpdstate &s, const real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place equality constraints on arbitrary +subset of elements of P. Set of constraints is specified by EC, which may +contain either NAN's or finite numbers from [0,1]. NAN denotes absence of +constraint, finite number denotes equality constraint on specific element +of P. + +You can also use MCPDAddEC() function which allows to ADD equality +constraint for one element of P without changing constraints for other +elements. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + EC - equality constraints, array[N,N]. Elements of EC can be + either NAN's or finite numbers from [0,1]. NAN denotes + absence of constraints, while finite value denotes + equality constraint on the corresponding element of P. + +NOTES: + +1. infinite values of EC will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetec(mcpdstate &s, const real_2d_array &ec, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to add equality constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD equality constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetEC() function which allows you to specify +arbitrary set of equality constraints in one call. + +These functions (MCPDSetEC and MCPDAddEC) interact as follows: +* there is internal matrix of equality constraints which is stored in the + MCPD solver +* MCPDSetEC() replaces this matrix by another one (SET) +* MCPDAddEC() modifies one element of this matrix and leaves other ones + unchanged (ADD) +* thus MCPDAddEC() call preserves all modifications done by previous + calls, while MCPDSetEC() completely discards all changes done to the + equality constraints. + +INPUT PARAMETERS: + S - solver + I - row index of element being constrained + J - column index of element being constrained + C - value (constraint for P[I,J]). Can be either NAN (no + constraint) or finite value from [0,1]. + +NOTES: + +1. infinite values of C will lead to exception being thrown. Values less +than 0.0 or greater than 1.0 will lead to error code being returned after +call to MCPDSolve(). + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdaddec(mcpdstate &s, const ae_int_t i, const ae_int_t j, const double c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to add bound constraints on the elements of the +transition matrix P. + +MCPD solver has four types of constraints which can be placed on P: +* user-specified equality constraints (optional) +* user-specified bound constraints (optional) +* user-specified general linear constraints (optional) +* basic constraints (always present): + * non-negativity: P[i,j]>=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to place bound constraints on arbitrary +subset of elements of P. Set of constraints is specified by BndL/BndU +matrices, which may contain arbitrary combination of finite numbers or +infinities (like -INF=0 + * consistency: every column of P sums to 1.0 + +Final constraints which are passed to the underlying optimizer are +calculated as intersection of all present constraints. For example, you +may specify boundary constraint on P[0,0] and equality one: + 0.1<=P[0,0]<=0.9 + P[0,0]=0.5 +Such combination of constraints will be silently reduced to their +intersection, which is P[0,0]=0.5. + +This function can be used to ADD bound constraint for one element of P +without changing constraints for other elements. + +You can also use MCPDSetBC() function which allows to place bound +constraints on arbitrary subset of elements of P. Set of constraints is +specified by BndL/BndU matrices, which may contain arbitrary combination +of finite numbers or infinities (like -INF=" (CT[i]>0). + +Your constraint may involve only some subset of P (less than N*N elements). +For example it can be something like + P[0,0] + P[0,1] = 0.5 +In this case you still should pass matrix with N*N+1 columns, but all its +elements (except for C[0,0], C[0,1] and C[0,N*N-1]) will be zero. + +INPUT PARAMETERS: + S - solver + C - array[K,N*N+1] - coefficients of constraints + (see above for complete description) + CT - array[K] - constraint types + (see above for complete description) + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetlc(mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void mcpdsetlc(mcpdstate &s, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function allows to tune amount of Tikhonov regularization being +applied to your problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change coefficient r. You can also change +prior values with MCPDSetPrior() function. + +INPUT PARAMETERS: + S - solver + V - regularization coefficient, finite non-negative value. It + is not recommended to specify zero value unless you are + pretty sure that you want it. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsettikhonovregularizer(mcpdstate &s, const double v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function allows to set prior values used for regularization of your +problem. + +By default, regularizing term is equal to r*||P-prior_P||^2, where r is a +small non-zero value, P is transition matrix, prior_P is identity matrix, +||X||^2 is a sum of squared elements of X. + +This function allows you to change prior values prior_P. You can also +change r with MCPDSetTikhonovRegularizer() function. + +INPUT PARAMETERS: + S - solver + PP - array[N,N], matrix of prior values: + 1. elements must be real numbers from [0,1] + 2. columns must sum to 1.0. + First property is checked (exception is thrown otherwise), + while second one is not checked/enforced. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetprior(mcpdstate &s, const real_2d_array &pp, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to change prediction weights + +MCPD solver scales prediction errors as follows + Error(P) = ||W*(y-P*x)||^2 +where + x is a system state at time t + y is a system state at time t+1 + P is a transition matrix + W is a diagonal scaling matrix + +By default, weights are chosen in order to minimize relative prediction +error instead of absolute one. For example, if one component of state is +about 0.5 in magnitude and another one is about 0.05, then algorithm will +make corresponding weights equal to 2.0 and 20.0. + +INPUT PARAMETERS: + S - solver + PW - array[N], weights: + * must be non-negative values (exception will be thrown otherwise) + * zero values will be replaced by automatically chosen values + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsetpredictionweights(mcpdstate &s, const real_1d_array &pw, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to start solution of the MCPD problem. + +After return from this function, you can use MCPDResults() to get solution +and completion code. + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdsolve(mcpdstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MCPD results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - array[N,N], transition matrix + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one. Speaking short, positive values denote + success, negative ones are failures. + More information about fields of this structure can be + found in the comments on MCPDReport datatype. + + + -- ALGLIB -- + Copyright 23.05.2010 by Bochkanov Sergey +*************************************************************************/ +void mcpdresults(const mcpdstate &s, real_2d_array &p, mcpdreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine trains logit model. + +INPUT PARAMETERS: + XY - training set, array[0..NPoints-1,0..NVars] + First NVars columns store values of independent + variables, next column stores number of class (from 0 + to NClasses-1) which dataset element belongs to. Fractional + values are rounded to nearest integer. + NPoints - training set size, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints=1 + NVars - number of independent variables, NVars>=1 + NOut - number of dependent variables, NOut>=1 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetreg(knnbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nout, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Specifies classification problem (two or more classes are predicted). +There also exists "regression" version of this function. + +This subroutine adds dense dataset to the internal storage of the builder +object. Specifying your dataset in the dense format means that the dense +version of the KNN construction algorithm will be invoked. + +INPUT PARAMETERS: + S - KNN builder object + XY - array[NPoints,NVars+1] (note: actual size can be + larger, only leading part is used anyway), dataset: + * first NVars elements of each row store values of the + independent variables + * next element stores class index, in [0,NClasses) + NPoints - number of rows in the dataset, NPoints>=1 + NVars - number of independent variables, NVars>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - KNN builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetdatasetcls(knnbuilder &s, const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t nclasses, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets norm type used for neighbor search. + +INPUT PARAMETERS: + S - decision forest builder object + NormType - norm type: + * 0 inf-norm + * 1 1-norm + * 2 Euclidean norm (default) + +OUTPUT PARAMETERS: + S - decision forest builder + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuildersetnorm(knnbuilder &s, const ae_int_t nrmtype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds KNN model according to current settings, using +dataset internally stored in the builder object. + +The model being built performs inference using Eps-approximate K nearest +neighbors search algorithm, with: +* K=1, Eps=0 corresponding to the "nearest neighbor algorithm" +* K>1, Eps=0 corresponding to the "K nearest neighbors algorithm" +* K>=1, Eps>0 corresponding to "approximate nearest neighbors algorithm" + +An approximate KNN is a good option for high-dimensional datasets (exact +KNN works slowly when dimensions count grows). + +An ALGLIB implementation of kd-trees is used to perform k-nn searches. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - KNN builder object + K - number of neighbors to search for, K>=1 + Eps - approximation factor: + * Eps=0 means that exact kNN search is performed + * Eps>0 means that (1+Eps)-approximate search is performed + +OUTPUT PARAMETERS: + Model - KNN model + Rep - report + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnbuilderbuildknnmodel(knnbuilder &s, const ae_int_t k, const double eps, knnmodel &model, knnreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Changing search settings of KNN model. + +K and EPS parameters of KNN (AKNN) search are specified during model +construction. However, plain KNN algorithm with Euclidean distance allows +you to change them at any moment. + +NOTE: future versions of KNN model may support advanced versions of KNN, + such as NCA or LMNN. It is possible that such algorithms won't allow + you to change search settings on the fly. If you call this function + for an algorithm which does not support on-the-fly changes, it will + throw an exception. + +INPUT PARAMETERS: + Model - KNN model + K - K>=1, neighbors count + EPS - accuracy of the EPS-approximate NN search. Set to 0.0, if + you want to perform "classic" KNN search. Specify larger + values if you need to speed-up high-dimensional KNN + queries. + +OUTPUT PARAMETERS: + nothing on success, exception on failure + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnrewritekeps(knnmodel &model, const ae_int_t k, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inference using KNN model. + +See also knnprocess0(), knnprocessi() and knnclassify() for options with a +bit more convenient interface. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + Y - possible preallocated buffer. Reused if long enough. + +OUTPUT PARAMETERS: + Y - result. Regression estimate when solving regression task, + vector of posterior probabilities for classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocess(knnmodel &model, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns first component of the inferred vector (i.e. one +with index #0). + +It is a convenience wrapper for knnprocess() intended for either: +* 1-dimensional regression problems +* 2-class classification problems + +In the former case this function returns inference result as scalar, which +is definitely more convenient that wrapping it as vector. In the latter +case it returns probability of object belonging to class #0. + +If you call it for anything different from two cases above, it will work +as defined, i.e. return y[0], although it is of less use in such cases. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + Y[0] + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnprocess0(knnmodel &model, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns most probable class number for an input X. It is +same as calling knnprocess(model,x,y), then determining i=argmax(y[i]) and +returning i. + +A class number in [0,NOut) range in returned for classification problems, +-1 is returned when this function is called for regression problems. + +IMPORTANT: this function is thread-unsafe and modifies internal structures + of the model! You can not use same model object for parallel + evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers, if + you need thread-safe evaluation. + +INPUT PARAMETERS: + Model - KNN model + X - input vector, array[0..NVars-1]. + +RESULT: + class number, -1 for regression tasks + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +ae_int_t knnclassify(knnmodel &model, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +'interactive' variant of knnprocess() for languages like Python which +support constructs like "y = knnprocessi(model,x)" and interactive mode of +the interpreter. + +This function allocates new array on each call, so it is significantly +slower than its 'non-interactive' counterpart, but it is more convenient +when you call it from command line. + +IMPORTANT: this function is thread-unsafe and may modify internal + structures of the model! You can not use same model object for + parallel evaluation from several threads. + + Use knntsprocess() with independent thread-local buffers if + you need thread-safe evaluation. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnprocessi(knnmodel &model, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Thread-safe procesing using external buffer for temporaries. + +This function is thread-safe (i.e . you can use same KNN model from +multiple threads) as long as you use different buffer objects for different +threads. + +INPUT PARAMETERS: + Model - KNN model + Buf - buffer object, must be allocated specifically for this + model with knncreatebuffer(). + X - input vector, array[NVars] + +OUTPUT PARAMETERS: + Y - result, array[NOut]. Regression estimate when solving + regression task, vector of posterior probabilities for + a classification task. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knntsprocess(const knnmodel &model, knnbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Relative classification error on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + percent of incorrectly classified cases. + Zero if model solves regression task. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrelclserror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average cross-entropy (in bits per element) on the test set + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + CrossEntropy/NPoints. + Zero if model solves regression task. + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgce(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +RMS error on the test set. + +Its meaning for regression task is obvious. As for classification problems, +RMS error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + root mean square error. + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnrmserror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgerror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Average relative error on the test set + +Its meaning for regression task is obvious. As for classification problems, +average relative error means error when estimating posterior probabilities. + +INPUT PARAMETERS: + Model - KNN model + XY - test set + NPoints - test set size + +RESULT: + average relative error + +NOTE: if you need several different kinds of error metrics, it is better + to use knnallerrors() which computes all error metric with just one + pass over dataset. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +double knnavgrelerror(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculates all kinds of errors for the model in one call. + +INPUT PARAMETERS: + Model - KNN model + XY - test set: + * one row per point + * first NVars columns store independent variables + * depending on problem type: + * next column stores class number in [0,NClasses) - for + classification problems + * next NOut columns store dependent variables - for + regression problems + NPoints - test set size, NPoints>=0 + +OUTPUT PARAMETERS: + Rep - following fields are loaded with errors for both regression + and classification models: + * rep.rmserror - RMS error for the output + * rep.avgerror - average error + * rep.avgrelerror - average relative error + following fields are set only for classification models, + zero for regression ones: + * relclserror - relative classification error, in [0,1] + * avgce - average cross-entropy in bits per dataset entry + +NOTE: the cross-entropy metric is too unstable when used to evaluate KNN + models (such models can report exactly zero probabilities), so we + do not recommend using it. + + -- ALGLIB -- + Copyright 15.02.2019 by Bochkanov Sergey +*************************************************************************/ +void knnallerrors(const knnmodel &model, const real_2d_array &xy, const ae_int_t npoints, knnreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Neural network training using modified Levenberg-Marquardt with exact +Hessian calculation and regularization. Subroutine trains neural network +with restarts from random positions. Algorithm is well suited for small +and medium scale problems (hundreds of weights). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -9, if internal matrix inverse subroutine failed + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlm(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Neural network training using L-BFGS algorithm with regularization. +Subroutine trains neural network with restarts from random positions. +Algorithm is well suited for problems of any dimensionality (memory +requirements and step complexity are linear by weights number). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts from random position, >0. + If you don't know what Restarts to choose, use 2. + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + MaxIts - stopping criterion. Algorithm stops after MaxIts + iterations (NOT gradient calculations). Zero MaxIts + means stopping when step is sufficiently small. + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlptrainlbfgs(multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Neural network training using early stopping (base algorithm - L-BFGS with +regularization). + +INPUT PARAMETERS: + Network - neural network with initialized geometry + TrnXY - training set + TrnSize - training set size, TrnSize>0 + ValXY - validation set + ValSize - validation set size, ValSize>0 + Decay - weight decay constant, >=0.001 + Decay term 'Decay*||Weights||^2' is added to error + function. + If you don't know what Decay to choose, use 0.001. + Restarts - number of restarts, either: + * strictly positive number - algorithm make specified + number of restarts from random position. + * -1, in which case algorithm makes exactly one run + from the initial state of the network (no randomization). + If you don't know what Restarts to choose, choose one + one the following: + * -1 (deterministic start) + * +1 (one random restart) + * +5 (moderate amount of random restarts) + +OUTPUT PARAMETERS: + Network - trained neural network. + Info - return code: + * -2, if there is a point with class number + outside of [0..NOut-1]. + * -1, if wrong parameters specified + (NPoints<0, Restarts<1, ...). + * 2, task has been solved, stopping criterion met - + sufficiently small step size. Not expected (we + use EARLY stopping) but possible and not an + error. + * 6, task has been solved, stopping criterion met - + increasing of validation set error. + Rep - training report + +NOTE: + +Algorithm stops if validation set error increases for a long enough or +step size is small enought (there are task where validation set may +decrease for eternity). In any case solution returned corresponds to the +minimum of validation set error. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlptraines(multilayerperceptron &network, const real_2d_array &trnxy, const ae_int_t trnsize, const real_2d_array &valxy, const ae_int_t valsize, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - L-BFGS. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlbfgs(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cross-validation estimate of generalization error. + +Base algorithm - Levenberg-Marquardt. + +INPUT PARAMETERS: + Network - neural network with initialized geometry. Network is + not changed during cross-validation - it is used only + as a representative of its architecture. + XY - training set. + SSize - training set size + Decay - weight decay, same as in MLPTrainLBFGS + Restarts - number of restarts, >0. + restarts are counted for each partition separately, so + total number of restarts will be Restarts*FoldsCount. + FoldsCount - number of folds in k-fold cross-validation, + 2<=FoldsCount<=SSize. + recommended value: 10. + +OUTPUT PARAMETERS: + Info - return code, same as in MLPTrainLBFGS + Rep - report, same as in MLPTrainLM/MLPTrainLBFGS + CVRep - generalization error estimates + + -- ALGLIB -- + Copyright 09.12.2007 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcvlm(const multilayerperceptron &network, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const ae_int_t foldscount, ae_int_t &info, mlpreport &rep, mlpcvreport &cvrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function estimates generalization error using cross-validation on the +current dataset with current training settings. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. Network is not changed during cross- + validation and is not trained - it is used only as + representative of its architecture. I.e., we estimate + generalization properties of ARCHITECTURE, not some + specific network. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that for each cross-validation + round specified number of random restarts is + performed, with best network being chosen after + training. + * NRestarts=0 is same as NRestarts=1 + FoldsCount - number of folds in k-fold cross-validation: + * 2<=FoldsCount<=size of dataset + * recommended value: 10. + * values larger than dataset size will be silently + truncated down to dataset size + +OUTPUT PARAMETERS: + Rep - structure which contains cross-validation estimates: + * Rep.RelCLSError - fraction of misclassified cases. + * Rep.AvgCE - acerage cross-entropy + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average error + * Rep.AvgRelError - average relative error + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or subset with only one point was given, zeros are returned as + estimates. + +NOTE: this method performs FoldsCount cross-validation rounds, each one + with NRestarts random starts. Thus, FoldsCount*NRestarts networks + are trained in total. + +NOTE: Rep.RelCLSError/Rep.AvgCE are zero on regression problems. + +NOTE: on classification problems Rep.RMSError/Rep.AvgError/Rep.AvgRelError + contain errors in prediction of posterior probabilities. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpkfoldcv(mlptrainer &s, const multilayerperceptron &network, const ae_int_t nrestarts, const ae_int_t foldscount, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creation of the network trainer object for regression networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NOut - number of outputs, NOut>=1 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any regression + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainer(const ae_int_t nin, const ae_int_t nout, mlptrainer &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Creation of the network trainer object for classification networks + +INPUT PARAMETERS: + NIn - number of inputs, NIn>=1 + NClasses - number of classes, NClasses>=2 + +OUTPUT PARAMETERS: + S - neural network trainer object. + This structure can be used to train any classification + network with NIn inputs and NOut outputs. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpcreatetrainercls(const ae_int_t nin, const ae_int_t nclasses, mlptrainer &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user. + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. + NPoints - points count, >=0. + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdataset(mlptrainer &s, const real_2d_array &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets "current dataset" of the trainer object to one passed +by user (sparse matrix is used to store dataset). + +INPUT PARAMETERS: + S - trainer object + XY - training set, see below for information on the + training set format. This function checks correctness + of the dataset (no NANs/INFs, class numbers are + correct) and throws exception when incorrect dataset + is passed. Any sparse storage format can be used: + Hash-table, CRS... + NPoints - points count, >=0 + +DATASET FORMAT: + +This function uses two different dataset formats - one for regression +networks, another one for classification networks. + +For regression networks with NIn inputs and NOut outputs following dataset +format is used: +* dataset is given by NPoints*(NIn+NOut) matrix +* each row corresponds to one example +* first NIn columns are inputs, next NOut columns are outputs + +For classification networks with NIn inputs and NClasses clases following +datasetformat is used: +* dataset is given by NPoints*(NIn+1) matrix +* each row corresponds to one example +* first NIn columns are inputs, last column stores class number (from 0 to + NClasses-1). + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetsparsedataset(mlptrainer &s, const sparsematrix &xy, const ae_int_t npoints, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets weight decay coefficient which is used for training. + +INPUT PARAMETERS: + S - trainer object + Decay - weight decay coefficient, >=0. Weight decay term + 'Decay*||Weights||^2' is added to error function. If + you don't know what Decay to choose, use 1.0E-3. + Weight decay can be set to zero, in this case network + is trained without weight decay. + +NOTE: by default network uses some small nonzero value for weight decay. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetdecay(mlptrainer &s, const double decay, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping criteria for the optimizer. + +INPUT PARAMETERS: + S - trainer object + WStep - stopping criterion. Algorithm stops if step size is + less than WStep. Recommended value - 0.01. Zero step + size means stopping after MaxIts iterations. + WStep>=0. + MaxIts - stopping criterion. Algorithm stops after MaxIts + epochs (full passes over entire dataset). Zero MaxIts + means stopping when step is sufficiently small. + MaxIts>=0. + +NOTE: by default, WStep=0.005 and MaxIts=0 are used. These values are also + used when MLPSetCond() is called with WStep=0 and MaxIts=0. + +NOTE: these stopping criteria are used for all kinds of neural training - + from "conventional" networks to early stopping ensembles. When used + for "conventional" networks, they are used as the only stopping + criteria. When combined with early stopping, they used as ADDITIONAL + stopping criteria which can terminate early stopping algorithm. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetcond(mlptrainer &s, const double wstep, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets training algorithm: batch training using L-BFGS will be +used. + +This algorithm: +* the most robust for small-scale problems, but may be too slow for large + scale ones. +* perfoms full pass through the dataset before performing step +* uses conditions specified by MLPSetCond() for stopping +* is default one used by trainer object + +INPUT PARAMETERS: + S - trainer object + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpsetalgobatch(mlptrainer &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function trains neural network passed to this function, using current +dataset (one which was passed to MLPSetDataset() or MLPSetSparseDataset()) +and current training settings. Training from NRestarts random starting +positions is performed, best network is chosen. + +Training is performed using current training algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed, best network is chosen after + training + * NRestarts=0 means that current state of the network + is used for training. + +OUTPUT PARAMETERS: + Network - trained network + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + network is filled by zero values. Same behavior for functions + MLPStartTraining and MLPContinueTraining. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainnetwork(mlptrainer &s, multilayerperceptron &network, const ae_int_t nrestarts, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +After call to this function trainer object remembers network and is ready +to train it. However, no training is performed until first call to +MLPContinueTraining() function. Subsequent calls to MLPContinueTraining() +will advance training progress one iteration further. + +EXAMPLE: + > + > ...initialize network and trainer object.... + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > ...visualize training progress... + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network. It must have same number of inputs and + output/classes as was specified during creation of the + trainer object. + RandomStart - randomize network before training or not: + * True means that network is randomized and its + initial state (one which was passed to the trainer + object) is lost. + * False means that training is started from the + current state of the network + +OUTPUT PARAMETERS: + Network - neural network which is ready to training (weights are + initialized, preprocessor is initialized using current + training set) + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +void mlpstarttraining(mlptrainer &s, multilayerperceptron &network, const bool randomstart, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IMPORTANT: this is an "expert" version of the MLPTrain() function. We do + not recommend you to use it unless you are pretty sure that you + need ability to monitor training progress. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +This function performs step-by-step training of the neural network. Here +"step-by-step" means that training starts with MLPStartTraining() call, +and then user subsequently calls MLPContinueTraining() to perform one more +iteration of the training. + +This function performs one more iteration of the training and returns +either True (training continues) or False (training stopped). In case True +was returned, Network weights are updated according to the current state +of the optimization progress. In case False was returned, no additional +updates is performed (previous update of the network weights moved us to +the final point, and no additional updates is needed). + +EXAMPLE: + > + > [initialize network and trainer object] + > + > MLPStartTraining(Trainer, Network, True) + > while MLPContinueTraining(Trainer, Network) do + > [visualize training progress] + > + +INPUT PARAMETERS: + S - trainer object + Network - neural network structure, which is used to store + current state of the training process. + +OUTPUT PARAMETERS: + Network - weights of the neural network are rewritten by the + current approximation. + +NOTE: this method uses sum-of-squares error function for training. + +NOTE: it is expected that trainer object settings are NOT changed during + step-by-step training, i.e. no one changes stopping criteria or + training set during training. It is possible and there is no defense + against such actions, but algorithm behavior in such cases is + undefined and can be unpredictable. + +NOTE: It is expected that Network is the same one which was passed to + MLPStartTraining() function. However, THIS function checks only + following: + * that number of network inputs is consistent with trainer object + settings + * that number of network outputs/classes is consistent with trainer + object settings + * that number of network weights is the same as number of weights in + the network passed to MLPStartTraining() function + Exception is thrown when these conditions are violated. + + It is also expected that you do not change state of the network on + your own - the only party who has right to change network during its + training is a trainer object. Any attempt to interfere with trainer + may lead to unpredictable results. + + + -- ALGLIB -- + Copyright 23.07.2012 by Bochkanov Sergey +*************************************************************************/ +bool mlpcontinuetraining(mlptrainer &s, multilayerperceptron &network, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +Modified Levenberg-Marquardt algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglm(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Training neural networks ensemble using bootstrap aggregating (bagging). +L-BFGS algorithm is used as base training method. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + WStep - stopping criterion, same as in MLPTrainLBFGS + MaxIts - stopping criterion, same as in MLPTrainLBFGS + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -8, if both WStep=0 and MaxIts=0 + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 2, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 17.02.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpebagginglbfgs(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, const double wstep, const ae_int_t maxits, ae_int_t &info, mlpreport &rep, mlpcvreport &ooberrors, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Training neural networks ensemble using early stopping. + +INPUT PARAMETERS: + Ensemble - model with initialized geometry + XY - training set + NPoints - training set size + Decay - weight decay coefficient, >=0.001 + Restarts - restarts, >0. + +OUTPUT PARAMETERS: + Ensemble - trained model + Info - return code: + * -2, if there is a point with class number + outside of [0..NClasses-1]. + * -1, if incorrect parameters was passed + (NPoints<0, Restarts<1). + * 6, if task has been solved. + Rep - training report. + OOBErrors - out-of-bag generalization error estimate + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void mlpetraines(mlpensemble &ensemble, const real_2d_array &xy, const ae_int_t npoints, const double decay, const ae_int_t restarts, ae_int_t &info, mlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function trains neural network ensemble passed to this function using +current dataset and early stopping training algorithm. Each early stopping +round performs NRestarts random restarts (thus, EnsembleSize*NRestarts +training rounds is performed in total). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - trainer object; + Ensemble - neural network ensemble. It must have same number of + inputs and outputs/classes as was specified during + creation of the trainer object. + NRestarts - number of restarts, >=0: + * NRestarts>0 means that specified number of random + restarts are performed during each ES round; + * NRestarts=0 is silently replaced by 1. + +OUTPUT PARAMETERS: + Ensemble - trained ensemble; + Rep - it contains all type of errors. + +NOTE: this training method uses BOTH early stopping and weight decay! So, + you should select weight decay before starting training just as you + select it before training "conventional" networks. + +NOTE: when no dataset was specified with MLPSetDataset/SetSparseDataset(), + or single-point dataset was passed, ensemble is filled by zero + values. + +NOTE: this method uses sum-of-squares error function for training. + + -- ALGLIB -- + Copyright 22.08.2012 by Bochkanov Sergey +*************************************************************************/ +void mlptrainensemblees(mlptrainer &s, mlpensemble &ensemble, const ae_int_t nrestarts, mlpreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +k-means++ clusterization. +Backward compatibility function, we recommend to use CLUSTERING subpackage +as better replacement. + + -- ALGLIB -- + Copyright 21.03.2009 by Bochkanov Sergey +*************************************************************************/ +void kmeansgenerate(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nvars, const ae_int_t k, const ae_int_t restarts, ae_int_t &info, real_2d_array &c, integer_1d_array &xyc, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_PCA) || !defined(AE_PARTIAL_BUILD) +void pcabuildbasis(/* Real */ const ae_matrix* x, + ae_int_t npoints, + ae_int_t nvars, + /* Real */ ae_vector* s2, + /* Real */ ae_matrix* v, + ae_state *_state); +void pcatruncatedsubspace(/* Real */ const ae_matrix* x, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nneeded, + double eps, + ae_int_t maxits, + /* Real */ ae_vector* s2, + /* Real */ ae_matrix* v, + ae_state *_state); +void pcatruncatedsubspacesparse(const sparsematrix* x, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nneeded, + double eps, + ae_int_t maxits, + /* Real */ ae_vector* s2, + /* Real */ ae_matrix* v, + ae_state *_state); +#endif +#if defined(AE_COMPILE_BDSS) || !defined(AE_PARTIAL_BUILD) +void dserrallocate(ae_int_t nclasses, + /* Real */ ae_vector* buf, + ae_state *_state); +void dserraccumulate(/* Real */ ae_vector* buf, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* desiredy, + ae_state *_state); +void dserrfinish(/* Real */ ae_vector* buf, ae_state *_state); +void dsnormalize(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t* info, + /* Real */ ae_vector* means, + /* Real */ ae_vector* sigmas, + ae_state *_state); +void dsnormalizec(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t* info, + /* Real */ ae_vector* means, + /* Real */ ae_vector* sigmas, + ae_state *_state); +double dsgetmeanmindistance(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_state *_state); +void dstie(/* Real */ ae_vector* a, + ae_int_t n, + /* Integer */ ae_vector* ties, + ae_int_t* tiecount, + /* Integer */ ae_vector* p1, + /* Integer */ ae_vector* p2, + ae_state *_state); +void dstiefasti(/* Real */ ae_vector* a, + /* Integer */ ae_vector* b, + ae_int_t n, + /* Integer */ ae_vector* ties, + ae_int_t* tiecount, + /* Real */ ae_vector* bufr, + /* Integer */ ae_vector* bufi, + ae_state *_state); +void dsoptimalsplit2(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t* info, + double* threshold, + double* pal, + double* pbl, + double* par, + double* pbr, + double* cve, + ae_state *_state); +void dsoptimalsplit2fast(/* Real */ ae_vector* a, + /* Integer */ ae_vector* c, + /* Integer */ ae_vector* tiesbuf, + /* Integer */ ae_vector* cntbuf, + /* Real */ ae_vector* bufr, + /* Integer */ ae_vector* bufi, + ae_int_t n, + ae_int_t nc, + double alpha, + ae_int_t* info, + double* threshold, + double* rms, + double* cvrms, + ae_state *_state); +void dssplitk(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t nc, + ae_int_t kmax, + ae_int_t* info, + /* Real */ ae_vector* thresholds, + ae_int_t* ni, + double* cve, + ae_state *_state); +void dsoptimalsplitk(/* Real */ const ae_vector* _a, + /* Integer */ const ae_vector* _c, + ae_int_t n, + ae_int_t nc, + ae_int_t kmax, + ae_int_t* info, + /* Real */ ae_vector* thresholds, + ae_int_t* ni, + double* cve, + ae_state *_state); +void _cvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _cvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _cvreport_clear(void* _p); +void _cvreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MLPBASE) || !defined(AE_PARTIAL_BUILD) +ae_int_t mlpgradsplitcost(ae_state *_state); +ae_int_t mlpgradsplitsize(ae_state *_state); +void mlpcreate0(ae_int_t nin, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcreate1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcreate2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcreateb0(ae_int_t nin, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state); +void mlpcreateb1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state); +void mlpcreateb2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double b, + double d, + multilayerperceptron* network, + ae_state *_state); +void mlpcreater0(ae_int_t nin, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state); +void mlpcreater1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state); +void mlpcreater2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double a, + double b, + multilayerperceptron* network, + ae_state *_state); +void mlpcreatec0(ae_int_t nin, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcreatec1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcreatec2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + multilayerperceptron* network, + ae_state *_state); +void mlpcopy(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state); +void mlpcopyshared(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state); +ae_bool mlpsamearchitecture(const multilayerperceptron* network1, + const multilayerperceptron* network2, + ae_state *_state); +void mlpcopytunableparameters(const multilayerperceptron* network1, + multilayerperceptron* network2, + ae_state *_state); +void mlpexporttunableparameters(const multilayerperceptron* network, + /* Real */ ae_vector* p, + ae_int_t* pcount, + ae_state *_state); +void mlpimporttunableparameters(multilayerperceptron* network, + /* Real */ ae_vector* p, + ae_state *_state); +void mlpserializeold(const multilayerperceptron* network, + /* Real */ ae_vector* ra, + ae_int_t* rlen, + ae_state *_state); +void mlpunserializeold(/* Real */ const ae_vector* ra, + multilayerperceptron* network, + ae_state *_state); +void mlprandomize(multilayerperceptron* network, ae_state *_state); +void mlprandomizefull(multilayerperceptron* network, ae_state *_state); +void mlpinitpreprocessor(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state); +void mlpinitpreprocessorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t ssize, + ae_state *_state); +void mlpinitpreprocessorsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + ae_state *_state); +void mlpinitpreprocessorsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + ae_state *_state); +void mlpproperties(const multilayerperceptron* network, + ae_int_t* nin, + ae_int_t* nout, + ae_int_t* wcount, + ae_state *_state); +ae_int_t mlpntotal(const multilayerperceptron* network, ae_state *_state); +ae_int_t mlpgetinputscount(const multilayerperceptron* network, + ae_state *_state); +ae_int_t mlpgetoutputscount(const multilayerperceptron* network, + ae_state *_state); +ae_int_t mlpgetweightscount(const multilayerperceptron* network, + ae_state *_state); +ae_bool mlpissoftmax(const multilayerperceptron* network, + ae_state *_state); +ae_int_t mlpgetlayerscount(const multilayerperceptron* network, + ae_state *_state); +ae_int_t mlpgetlayersize(const multilayerperceptron* network, + ae_int_t k, + ae_state *_state); +void mlpgetinputscaling(const multilayerperceptron* network, + ae_int_t i, + double* mean, + double* sigma, + ae_state *_state); +void mlpgetoutputscaling(const multilayerperceptron* network, + ae_int_t i, + double* mean, + double* sigma, + ae_state *_state); +void mlpgetneuroninfo(multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + ae_int_t* fkind, + double* threshold, + ae_state *_state); +double mlpgetweight(multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + ae_state *_state); +void mlpsetinputscaling(multilayerperceptron* network, + ae_int_t i, + double mean, + double sigma, + ae_state *_state); +void mlpsetoutputscaling(multilayerperceptron* network, + ae_int_t i, + double mean, + double sigma, + ae_state *_state); +void mlpsetneuroninfo(multilayerperceptron* network, + ae_int_t k, + ae_int_t i, + ae_int_t fkind, + double threshold, + ae_state *_state); +void mlpsetweight(multilayerperceptron* network, + ae_int_t k0, + ae_int_t i0, + ae_int_t k1, + ae_int_t i1, + double w, + ae_state *_state); +void mlpactivationfunction(double net, + ae_int_t k, + double* f, + double* df, + double* d2f, + ae_state *_state); +void mlpprocess(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mlpprocessi(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +double mlperror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlperrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlperrorn(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state); +ae_int_t mlpclserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlprelclserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlprelclserrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgce(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgcesparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlprmserror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlprmserrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgerror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgerrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgrelerror(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpavgrelerrorsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +void mlpgrad(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* desiredy, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradn(multilayerperceptron* network, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* desiredy, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradbatchsparse(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradbatchsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradbatchsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* idx, + ae_int_t subsetsize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlpgradbatchx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + ae_shared_pool* gradbuf, + ae_state *_state); +ae_bool _trypexec_mlpgradbatchx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + ae_shared_pool* gradbuf, ae_state *_state); +void mlpgradnbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + ae_state *_state); +void mlphessiannbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state); +void mlphessianbatch(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + double* e, + /* Real */ ae_vector* grad, + /* Real */ ae_matrix* h, + ae_state *_state); +void mlpinternalprocessvector(/* Integer */ const ae_vector* structinfo, + /* Real */ const ae_vector* weights, + /* Real */ const ae_vector* columnmeans, + /* Real */ const ae_vector* columnsigmas, + /* Real */ ae_vector* neurons, + /* Real */ ae_vector* dfdnet, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mlpalloc(ae_serializer* s, + const multilayerperceptron* network, + ae_state *_state); +void mlpserialize(ae_serializer* s, + const multilayerperceptron* network, + ae_state *_state); +void mlpunserialize(ae_serializer* s, + multilayerperceptron* network, + ae_state *_state); +void mlpallerrorssubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + modelerrors* rep, + ae_state *_state); +void mlpallerrorssparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + modelerrors* rep, + ae_state *_state); +double mlperrorsubset(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_state *_state); +double mlperrorsparsesubset(multilayerperceptron* network, + const sparsematrix* xy, + ae_int_t setsize, + /* Integer */ const ae_vector* subset, + ae_int_t subsetsize, + ae_state *_state); +void mlpallerrorsx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, + ae_state *_state); +ae_bool _trypexec_mlpallerrorsx(const multilayerperceptron* network, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, ae_state *_state); +void _modelerrors_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _modelerrors_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _modelerrors_clear(void* _p); +void _modelerrors_destroy(void* _p); +void _smlpgrad_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _smlpgrad_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _smlpgrad_clear(void* _p); +void _smlpgrad_destroy(void* _p); +void _multilayerperceptron_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _multilayerperceptron_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _multilayerperceptron_clear(void* _p); +void _multilayerperceptron_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MLPE) || !defined(AE_PARTIAL_BUILD) +void mlpecreate0(ae_int_t nin, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreate1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreate2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreateb0(ae_int_t nin, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreateb1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreateb2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double b, + double d, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreater0(ae_int_t nin, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreater1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreater2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + double a, + double b, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreatec0(ae_int_t nin, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreatec1(ae_int_t nin, + ae_int_t nhid, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreatec2(ae_int_t nin, + ae_int_t nhid1, + ae_int_t nhid2, + ae_int_t nout, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecreatefromnetwork(const multilayerperceptron* network, + ae_int_t ensemblesize, + mlpensemble* ensemble, + ae_state *_state); +void mlpecopy(const mlpensemble* ensemble1, + mlpensemble* ensemble2, + ae_state *_state); +void mlperandomize(mlpensemble* ensemble, ae_state *_state); +void mlpeproperties(const mlpensemble* ensemble, + ae_int_t* nin, + ae_int_t* nout, + ae_state *_state); +ae_bool mlpeissoftmax(const mlpensemble* ensemble, ae_state *_state); +void mlpeprocess(mlpensemble* ensemble, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mlpeprocessi(mlpensemble* ensemble, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mlpeallerrorsx(mlpensemble* ensemble, + /* Real */ const ae_matrix* densexy, + const sparsematrix* sparsexy, + ae_int_t datasetsize, + ae_int_t datasettype, + /* Integer */ const ae_vector* idx, + ae_int_t subset0, + ae_int_t subset1, + ae_int_t subsettype, + ae_shared_pool* buf, + modelerrors* rep, + ae_state *_state); +void mlpeallerrorssparse(mlpensemble* ensemble, + const sparsematrix* xy, + ae_int_t npoints, + double* relcls, + double* avgce, + double* rms, + double* avg, + double* avgrel, + ae_state *_state); +double mlperelclserror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpeavgce(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpermserror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpeavgerror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mlpeavgrelerror(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void mlpealloc(ae_serializer* s, + const mlpensemble* ensemble, + ae_state *_state); +void mlpeserialize(ae_serializer* s, + const mlpensemble* ensemble, + ae_state *_state); +void mlpeunserialize(ae_serializer* s, + mlpensemble* ensemble, + ae_state *_state); +void _mlpensemble_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpensemble_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpensemble_clear(void* _p); +void _mlpensemble_destroy(void* _p); +#endif +#if defined(AE_COMPILE_CLUSTERING) || !defined(AE_PARTIAL_BUILD) +void clusterizercreate(clusterizerstate* s, ae_state *_state); +void clusterizersetpoints(clusterizerstate* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_int_t disttype, + ae_state *_state); +void clusterizersetdistances(clusterizerstate* s, + /* Real */ const ae_matrix* d, + ae_int_t npoints, + ae_bool isupper, + ae_state *_state); +void clusterizersetahcalgo(clusterizerstate* s, + ae_int_t algo, + ae_state *_state); +void clusterizersetkmeanslimits(clusterizerstate* s, + ae_int_t restarts, + ae_int_t maxits, + ae_state *_state); +void clusterizersetkmeansinit(clusterizerstate* s, + ae_int_t initalgo, + ae_state *_state); +void clusterizersetseed(clusterizerstate* s, + ae_int_t seed, + ae_state *_state); +void clusterizerrunahc(clusterizerstate* s, + ahcreport* rep, + ae_state *_state); +void clusterizerrunkmeans(clusterizerstate* s, + ae_int_t k, + kmeansreport* rep, + ae_state *_state); +void clusterizergetdistances(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_state *_state); +void clusterizergetdistancesbuf(apbuffers* buf, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_int_t disttype, + /* Real */ ae_matrix* d, + ae_state *_state); +void clusterizergetkclusters(const ahcreport* rep, + ae_int_t k, + /* Integer */ ae_vector* cidx, + /* Integer */ ae_vector* cz, + ae_state *_state); +void clusterizerseparatedbydist(const ahcreport* rep, + double r, + ae_int_t* k, + /* Integer */ ae_vector* cidx, + /* Integer */ ae_vector* cz, + ae_state *_state); +void clusterizerseparatedbycorr(const ahcreport* rep, + double r, + ae_int_t* k, + /* Integer */ ae_vector* cidx, + /* Integer */ ae_vector* cz, + ae_state *_state); +void kmeansinitbuf(kmeansbuffers* buf, ae_state *_state); +void kmeansgenerateinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t k, + ae_int_t initalgo, + ae_int_t seed, + ae_int_t maxits, + ae_int_t restarts, + ae_bool kmeansdbgnoits, + ae_int_t* info, + ae_int_t* iterationscount, + /* Real */ ae_matrix* ccol, + ae_bool needccol, + /* Real */ ae_matrix* crow, + ae_bool needcrow, + /* Integer */ ae_vector* xyc, + double* energy, + kmeansbuffers* buf, + ae_state *_state); +void kmeansupdatedistances(/* Real */ const ae_matrix* xy, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nvars, + /* Real */ const ae_matrix* ct, + ae_int_t cidx0, + ae_int_t cidx1, + /* Integer */ ae_vector* xyc, + /* Real */ ae_vector* xydist2, + ae_shared_pool* bufferpool, + ae_state *_state); +ae_bool _trypexec_kmeansupdatedistances(/* Real */ const ae_matrix* xy, + ae_int_t idx0, + ae_int_t idx1, + ae_int_t nvars, + /* Real */ const ae_matrix* ct, + ae_int_t cidx0, + ae_int_t cidx1, + /* Integer */ ae_vector* xyc, + /* Real */ ae_vector* xydist2, + ae_shared_pool* bufferpool, ae_state *_state); +void _kmeansbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _kmeansbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _kmeansbuffers_clear(void* _p); +void _kmeansbuffers_destroy(void* _p); +void _clusterizerstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _clusterizerstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _clusterizerstate_clear(void* _p); +void _clusterizerstate_destroy(void* _p); +void _ahcreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ahcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ahcreport_clear(void* _p); +void _ahcreport_destroy(void* _p); +void _kmeansreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _kmeansreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _kmeansreport_clear(void* _p); +void _kmeansreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DFOREST) || !defined(AE_PARTIAL_BUILD) +void dfcreatebuffer(const decisionforest* model, + decisionforestbuffer* buf, + ae_state *_state); +void dfbuildercreate(decisionforestbuilder* s, ae_state *_state); +void dfbuildersetdataset(decisionforestbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_state *_state); +void dfbuildersetrndvars(decisionforestbuilder* s, + ae_int_t rndvars, + ae_state *_state); +void dfbuildersetrndvarsratio(decisionforestbuilder* s, + double f, + ae_state *_state); +void dfbuildersetrndvarsauto(decisionforestbuilder* s, ae_state *_state); +void dfbuildersetsubsampleratio(decisionforestbuilder* s, + double f, + ae_state *_state); +void dfbuildersetseed(decisionforestbuilder* s, + ae_int_t seedval, + ae_state *_state); +void dfbuildersetrdfalgo(decisionforestbuilder* s, + ae_int_t algotype, + ae_state *_state); +void dfbuildersetrdfsplitstrength(decisionforestbuilder* s, + ae_int_t splitstrength, + ae_state *_state); +void dfbuildersetimportancetrngini(decisionforestbuilder* s, + ae_state *_state); +void dfbuildersetimportanceoobgini(decisionforestbuilder* s, + ae_state *_state); +void dfbuildersetimportancepermutation(decisionforestbuilder* s, + ae_state *_state); +void dfbuildersetimportancenone(decisionforestbuilder* s, + ae_state *_state); +double dfbuildergetprogress(const decisionforestbuilder* s, + ae_state *_state); +double dfbuilderpeekprogress(const decisionforestbuilder* s, + ae_state *_state); +void dfbuilderbuildrandomforest(decisionforestbuilder* s, + ae_int_t ntrees, + decisionforest* df, + dfreport* rep, + ae_state *_state); +double dfbinarycompression(decisionforest* df, ae_state *_state); +double dfbinarycompression8(decisionforest* df, ae_state *_state); +void dfprocess(const decisionforest* df, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void dfprocessi(const decisionforest* df, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +double dfprocess0(decisionforest* model, + /* Real */ const ae_vector* x, + ae_state *_state); +ae_int_t dfclassify(decisionforest* model, + /* Real */ const ae_vector* x, + ae_state *_state); +void dftsprocess(const decisionforest* df, + decisionforestbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +double dfrelclserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double dfavgce(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double dfrmserror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double dfavgerror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double dfavgrelerror(const decisionforest* df, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void dfcopy(const decisionforest* df1, + decisionforest* df2, + ae_state *_state); +void dfalloc(ae_serializer* s, + const decisionforest* forest, + ae_state *_state); +void dfserialize(ae_serializer* s, + const decisionforest* forest, + ae_state *_state); +void dfunserialize(ae_serializer* s, + decisionforest* forest, + ae_state *_state); +void dfbuildrandomdecisionforest(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + double r, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state); +void dfbuildrandomdecisionforestx1(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + ae_int_t nrndvars, + double r, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state); +void dfbuildinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t ntrees, + ae_int_t samplesize, + ae_int_t nfeatures, + ae_int_t flags, + ae_int_t* info, + decisionforest* df, + dfreport* rep, + ae_state *_state); +void _decisionforestbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _decisionforestbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _decisionforestbuilder_clear(void* _p); +void _decisionforestbuilder_destroy(void* _p); +void _dfworkbuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfworkbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfworkbuf_clear(void* _p); +void _dfworkbuf_destroy(void* _p); +void _dfvotebuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfvotebuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfvotebuf_clear(void* _p); +void _dfvotebuf_destroy(void* _p); +void _dfpermimpbuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfpermimpbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfpermimpbuf_clear(void* _p); +void _dfpermimpbuf_destroy(void* _p); +void _dftreebuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dftreebuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dftreebuf_clear(void* _p); +void _dftreebuf_destroy(void* _p); +void _decisionforestbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _decisionforestbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _decisionforestbuffer_clear(void* _p); +void _decisionforestbuffer_destroy(void* _p); +void _decisionforest_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _decisionforest_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _decisionforest_clear(void* _p); +void _decisionforest_destroy(void* _p); +void _dfreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfreport_clear(void* _p); +void _dfreport_destroy(void* _p); +void _dfinternalbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfinternalbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfinternalbuffers_clear(void* _p); +void _dfinternalbuffers_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LINREG) || !defined(AE_PARTIAL_BUILD) +void lrbuild(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state); +void lrbuilds(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state); +void lrbuildzs(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state); +void lrbuildz(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + linearmodel* lm, + lrreport* rep, + ae_state *_state); +void lrunpack(const linearmodel* lm, + /* Real */ ae_vector* v, + ae_int_t* nvars, + ae_state *_state); +void lrpack(/* Real */ const ae_vector* v, + ae_int_t nvars, + linearmodel* lm, + ae_state *_state); +double lrprocess(const linearmodel* lm, + /* Real */ const ae_vector* x, + ae_state *_state); +double lrrmserror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double lravgerror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double lravgrelerror(const linearmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void lrcopy(const linearmodel* lm1, linearmodel* lm2, ae_state *_state); +void lrlines(/* Real */ const ae_matrix* xy, + /* Real */ const ae_vector* s, + ae_int_t n, + double* a, + double* b, + double* vara, + double* varb, + double* covab, + double* corrab, + double* p, + ae_state *_state); +void lrline(/* Real */ const ae_matrix* xy, + ae_int_t n, + double* a, + double* b, + ae_state *_state); +void _linearmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _linearmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _linearmodel_clear(void* _p); +void _linearmodel_destroy(void* _p); +void _lrreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lrreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lrreport_clear(void* _p); +void _lrreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_FILTERS) || !defined(AE_PARTIAL_BUILD) +void filtersma(/* Real */ ae_vector* x, + ae_int_t n, + ae_int_t k, + ae_state *_state); +void filterema(/* Real */ ae_vector* x, + ae_int_t n, + double alpha, + ae_state *_state); +void filterlrma(/* Real */ ae_vector* x, + ae_int_t n, + ae_int_t k, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SSA) || !defined(AE_PARTIAL_BUILD) +void ssacreate(ssamodel* s, ae_state *_state); +void ssasetwindow(ssamodel* s, ae_int_t windowwidth, ae_state *_state); +void ssasetseed(ssamodel* s, ae_int_t seed, ae_state *_state); +void ssasetpoweruplength(ssamodel* s, ae_int_t pwlen, ae_state *_state); +void ssasetmemorylimit(ssamodel* s, ae_int_t memlimit, ae_state *_state); +void ssaaddsequence(ssamodel* s, + /* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +void ssaappendpointandupdate(ssamodel* s, + double x, + double updateits, + ae_state *_state); +void ssaappendsequenceandupdate(ssamodel* s, + /* Real */ const ae_vector* x, + ae_int_t nticks, + double updateits, + ae_state *_state); +void ssasetalgoprecomputed(ssamodel* s, + /* Real */ const ae_matrix* a, + ae_int_t windowwidth, + ae_int_t nbasis, + ae_state *_state); +void ssasetalgotopkdirect(ssamodel* s, ae_int_t topk, ae_state *_state); +void ssasetalgotopkrealtime(ssamodel* s, ae_int_t topk, ae_state *_state); +void ssacleardata(ssamodel* s, ae_state *_state); +void ssagetbasis(ssamodel* s, + /* Real */ ae_matrix* a, + /* Real */ ae_vector* sv, + ae_int_t* windowwidth, + ae_int_t* nbasis, + ae_state *_state); +void ssagetlrr(ssamodel* s, + /* Real */ ae_vector* a, + ae_int_t* windowwidth, + ae_state *_state); +void ssaanalyzelastwindow(ssamodel* s, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_int_t* nticks, + ae_state *_state); +void ssaanalyzelast(ssamodel* s, + ae_int_t nticks, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_state *_state); +void ssaanalyzesequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t nticks, + /* Real */ ae_vector* trend, + /* Real */ ae_vector* noise, + ae_state *_state); +void ssaforecastlast(ssamodel* s, + ae_int_t nticks, + /* Real */ ae_vector* trend, + ae_state *_state); +void ssaforecastsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t datalen, + ae_int_t forecastlen, + ae_bool applysmoothing, + /* Real */ ae_vector* trend, + ae_state *_state); +void ssaforecastavglast(ssamodel* s, + ae_int_t m, + ae_int_t nticks, + /* Real */ ae_vector* trend, + ae_state *_state); +void ssaforecastavgsequence(ssamodel* s, + /* Real */ const ae_vector* data, + ae_int_t datalen, + ae_int_t m, + ae_int_t forecastlen, + ae_bool applysmoothing, + /* Real */ ae_vector* trend, + ae_state *_state); +void _ssamodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ssamodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ssamodel_clear(void* _p); +void _ssamodel_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LDA) || !defined(AE_PARTIAL_BUILD) +void fisherlda(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + /* Real */ ae_vector* w, + ae_state *_state); +void fisherldan(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + /* Real */ ae_matrix* w, + ae_state *_state); +#endif +#if defined(AE_COMPILE_MCPD) || !defined(AE_PARTIAL_BUILD) +void mcpdcreate(ae_int_t n, mcpdstate* s, ae_state *_state); +void mcpdcreateentry(ae_int_t n, + ae_int_t entrystate, + mcpdstate* s, + ae_state *_state); +void mcpdcreateexit(ae_int_t n, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state); +void mcpdcreateentryexit(ae_int_t n, + ae_int_t entrystate, + ae_int_t exitstate, + mcpdstate* s, + ae_state *_state); +void mcpdaddtrack(mcpdstate* s, + /* Real */ const ae_matrix* xy, + ae_int_t k, + ae_state *_state); +void mcpdsetec(mcpdstate* s, + /* Real */ const ae_matrix* ec, + ae_state *_state); +void mcpdaddec(mcpdstate* s, + ae_int_t i, + ae_int_t j, + double c, + ae_state *_state); +void mcpdsetbc(mcpdstate* s, + /* Real */ const ae_matrix* bndl, + /* Real */ const ae_matrix* bndu, + ae_state *_state); +void mcpdaddbc(mcpdstate* s, + ae_int_t i, + ae_int_t j, + double bndl, + double bndu, + ae_state *_state); +void mcpdsetlc(mcpdstate* s, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void mcpdsettikhonovregularizer(mcpdstate* s, double v, ae_state *_state); +void mcpdsetprior(mcpdstate* s, + /* Real */ const ae_matrix* _pp, + ae_state *_state); +void mcpdsetpredictionweights(mcpdstate* s, + /* Real */ const ae_vector* pw, + ae_state *_state); +void mcpdsolve(mcpdstate* s, ae_state *_state); +void mcpdresults(const mcpdstate* s, + /* Real */ ae_matrix* p, + mcpdreport* rep, + ae_state *_state); +void _mcpdstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mcpdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mcpdstate_clear(void* _p); +void _mcpdstate_destroy(void* _p); +void _mcpdreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mcpdreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mcpdreport_clear(void* _p); +void _mcpdreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LOGIT) || !defined(AE_PARTIAL_BUILD) +void mnltrainh(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_int_t* info, + logitmodel* lm, + mnlreport* rep, + ae_state *_state); +void mnlprocess(logitmodel* lm, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mnlprocessi(logitmodel* lm, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void mnlunpack(const logitmodel* lm, + /* Real */ ae_matrix* a, + ae_int_t* nvars, + ae_int_t* nclasses, + ae_state *_state); +void mnlpack(/* Real */ const ae_matrix* a, + ae_int_t nvars, + ae_int_t nclasses, + logitmodel* lm, + ae_state *_state); +void mnlcopy(const logitmodel* lm1, logitmodel* lm2, ae_state *_state); +double mnlavgce(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mnlrelclserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mnlrmserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mnlavgerror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double mnlavgrelerror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t ssize, + ae_state *_state); +ae_int_t mnlclserror(logitmodel* lm, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void _logitmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _logitmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _logitmodel_clear(void* _p); +void _logitmodel_destroy(void* _p); +void _logitmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _logitmcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _logitmcstate_clear(void* _p); +void _logitmcstate_destroy(void* _p); +void _mnlreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mnlreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mnlreport_clear(void* _p); +void _mnlreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_KNN) || !defined(AE_PARTIAL_BUILD) +void knncreatebuffer(const knnmodel* model, + knnbuffer* buf, + ae_state *_state); +void knnbuildercreate(knnbuilder* s, ae_state *_state); +void knnbuildersetdatasetreg(knnbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nout, + ae_state *_state); +void knnbuildersetdatasetcls(knnbuilder* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t nclasses, + ae_state *_state); +void knnbuildersetnorm(knnbuilder* s, ae_int_t nrmtype, ae_state *_state); +void knnbuilderbuildknnmodel(knnbuilder* s, + ae_int_t k, + double eps, + knnmodel* model, + knnreport* rep, + ae_state *_state); +void knnrewritekeps(knnmodel* model, + ae_int_t k, + double eps, + ae_state *_state); +void knnprocess(knnmodel* model, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +double knnprocess0(knnmodel* model, + /* Real */ const ae_vector* x, + ae_state *_state); +ae_int_t knnclassify(knnmodel* model, + /* Real */ const ae_vector* x, + ae_state *_state); +void knnprocessi(knnmodel* model, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void knntsprocess(const knnmodel* model, + knnbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +double knnrelclserror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double knnavgce(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double knnrmserror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double knnavgerror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +double knnavgrelerror(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void knnallerrors(const knnmodel* model, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + knnreport* rep, + ae_state *_state); +void knnalloc(ae_serializer* s, const knnmodel* model, ae_state *_state); +void knnserialize(ae_serializer* s, + const knnmodel* model, + ae_state *_state); +void knnunserialize(ae_serializer* s, knnmodel* model, ae_state *_state); +void _knnbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _knnbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _knnbuffer_clear(void* _p); +void _knnbuffer_destroy(void* _p); +void _knnbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _knnbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _knnbuilder_clear(void* _p); +void _knnbuilder_destroy(void* _p); +void _knnmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _knnmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _knnmodel_clear(void* _p); +void _knnmodel_destroy(void* _p); +void _knnreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _knnreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _knnreport_clear(void* _p); +void _knnreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MLPTRAIN) || !defined(AE_PARTIAL_BUILD) +void mlptrainlm(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state); +void mlptrainlbfgs(multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + ae_state *_state); +void mlptraines(multilayerperceptron* network, + /* Real */ const ae_matrix* trnxy, + ae_int_t trnsize, + /* Real */ const ae_matrix* valxy, + ae_int_t valsize, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state); +void mlpkfoldcvlbfgs(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t foldscount, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state); +void mlpkfoldcvlm(const multilayerperceptron* network, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t foldscount, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* cvrep, + ae_state *_state); +void mlpkfoldcv(mlptrainer* s, + const multilayerperceptron* network, + ae_int_t nrestarts, + ae_int_t foldscount, + mlpreport* rep, + ae_state *_state); +void mlpcreatetrainer(ae_int_t nin, + ae_int_t nout, + mlptrainer* s, + ae_state *_state); +void mlpcreatetrainercls(ae_int_t nin, + ae_int_t nclasses, + mlptrainer* s, + ae_state *_state); +void mlpsetdataset(mlptrainer* s, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_state *_state); +void mlpsetsparsedataset(mlptrainer* s, + const sparsematrix* xy, + ae_int_t npoints, + ae_state *_state); +void mlpsetdecay(mlptrainer* s, double decay, ae_state *_state); +void mlpsetcond(mlptrainer* s, + double wstep, + ae_int_t maxits, + ae_state *_state); +void mlpsetalgobatch(mlptrainer* s, ae_state *_state); +void mlptrainnetwork(mlptrainer* s, + multilayerperceptron* network, + ae_int_t nrestarts, + mlpreport* rep, + ae_state *_state); +void mlpstarttraining(mlptrainer* s, + multilayerperceptron* network, + ae_bool randomstart, + ae_state *_state); +ae_bool mlpcontinuetraining(mlptrainer* s, + multilayerperceptron* network, + ae_state *_state); +void mlpebagginglm(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state); +void mlpebagginglbfgs(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + double wstep, + ae_int_t maxits, + ae_int_t* info, + mlpreport* rep, + mlpcvreport* ooberrors, + ae_state *_state); +void mlpetraines(mlpensemble* ensemble, + /* Real */ const ae_matrix* xy, + ae_int_t npoints, + double decay, + ae_int_t restarts, + ae_int_t* info, + mlpreport* rep, + ae_state *_state); +void mlptrainensemblees(mlptrainer* s, + mlpensemble* ensemble, + ae_int_t nrestarts, + mlpreport* rep, + ae_state *_state); +void _mlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpreport_clear(void* _p); +void _mlpreport_destroy(void* _p); +void _mlpcvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpcvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpcvreport_clear(void* _p); +void _mlpcvreport_destroy(void* _p); +void _smlptrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _smlptrnsession_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _smlptrnsession_clear(void* _p); +void _smlptrnsession_destroy(void* _p); +void _mlpetrnsession_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpetrnsession_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpetrnsession_clear(void* _p); +void _mlpetrnsession_destroy(void* _p); +void _mlptrainer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlptrainer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlptrainer_clear(void* _p); +void _mlptrainer_destroy(void* _p); +void _mlpparallelizationcv_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mlpparallelizationcv_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mlpparallelizationcv_clear(void* _p); +void _mlpparallelizationcv_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DATACOMP) || !defined(AE_PARTIAL_BUILD) +void kmeansgenerate(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nvars, + ae_int_t k, + ae_int_t restarts, + ae_int_t* info, + /* Real */ ae_matrix* c, + /* Integer */ ae_vector* xyc, + ae_state *_state); +#endif + +} +#endif + diff --git a/core/alglib/diffequations.cpp b/core/alglib/diffequations.cpp index f8ab421f..55d46424 100644 --- a/core/alglib/diffequations.cpp +++ b/core/alglib/diffequations.cpp @@ -1,1187 +1,1345 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "diffequations.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* - -*************************************************************************/ -_odesolverstate_owner::_odesolverstate_owner() -{ - p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_odesolverstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_odesolverstate_owner::_odesolverstate_owner(const _odesolverstate_owner &rhs) -{ - p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_odesolverstate_owner& _odesolverstate_owner::operator=(const _odesolverstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_odesolverstate_clear(p_struct); - if( !alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_odesolverstate_owner::~_odesolverstate_owner() -{ - alglib_impl::_odesolverstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -odesolverstate::odesolverstate() : _odesolverstate_owner() ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) -{ -} - -odesolverstate::odesolverstate(const odesolverstate &rhs):_odesolverstate_owner(rhs) ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) -{ -} - -odesolverstate& odesolverstate::operator=(const odesolverstate &rhs) -{ - if( this==&rhs ) - return *this; - _odesolverstate_owner::operator=(rhs); - return *this; -} - -odesolverstate::~odesolverstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_odesolverreport_owner::_odesolverreport_owner() -{ - p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_odesolverreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_odesolverreport_owner::_odesolverreport_owner(const _odesolverreport_owner &rhs) -{ - p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_odesolverreport_owner& _odesolverreport_owner::operator=(const _odesolverreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_odesolverreport_clear(p_struct); - if( !alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_odesolverreport_owner::~_odesolverreport_owner() -{ - alglib_impl::_odesolverreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -odesolverreport::odesolverreport() : _odesolverreport_owner() ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) -{ -} - -odesolverreport::odesolverreport(const odesolverreport &rhs):_odesolverreport_owner(rhs) ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) -{ -} - -odesolverreport& odesolverreport::operator=(const odesolverreport &rhs) -{ - if( this==&rhs ) - return *this; - _odesolverreport_owner::operator=(rhs); - return *this; -} - -odesolverreport::~odesolverreport() -{ -} - -/************************************************************************* -Cash-Karp adaptive ODE solver. - -This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys -(here Y may be single variable or vector of N variables). - -INPUT PARAMETERS: - Y - initial conditions, array[0..N-1]. - contains values of Y[] at X[0] - N - system size - X - points at which Y should be tabulated, array[0..M-1] - integrations starts at X[0], ends at X[M-1], intermediate - values at X[i] are returned too. - SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!! - M - number of intermediate points + first point + last point: - * M>2 means that you need both Y(X[M-1]) and M-2 values at - intermediate points - * M=2 means that you want just to integrate from X[0] to - X[1] and don't interested in intermediate values. - * M=1 means that you don't want to integrate :) - it is degenerate case, but it will be handled correctly. - * M<1 means error - Eps - tolerance (absolute/relative error on each step will be - less than Eps). When passing: - * Eps>0, it means desired ABSOLUTE error - * Eps<0, it means desired RELATIVE error. Relative errors - are calculated with respect to maximum values of Y seen - so far. Be careful to use this criterion when starting - from Y[] that are close to zero. - H - initial step lenth, it will be adjusted automatically - after the first step. If H=0, step will be selected - automatically (usually it will be equal to 0.001 of - min(x[i]-x[j])). - -OUTPUT PARAMETERS - State - structure which stores algorithm state between subsequent - calls of OdeSolverIteration. Used for reverse communication. - This structure should be passed to the OdeSolverIteration - subroutine. - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. - - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::odesolverrkck(const_cast(y.c_ptr()), n, const_cast(x.c_ptr()), m, eps, h, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cash-Karp adaptive ODE solver. - -This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys -(here Y may be single variable or vector of N variables). - -INPUT PARAMETERS: - Y - initial conditions, array[0..N-1]. - contains values of Y[] at X[0] - N - system size - X - points at which Y should be tabulated, array[0..M-1] - integrations starts at X[0], ends at X[M-1], intermediate - values at X[i] are returned too. - SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!! - M - number of intermediate points + first point + last point: - * M>2 means that you need both Y(X[M-1]) and M-2 values at - intermediate points - * M=2 means that you want just to integrate from X[0] to - X[1] and don't interested in intermediate values. - * M=1 means that you don't want to integrate :) - it is degenerate case, but it will be handled correctly. - * M<1 means error - Eps - tolerance (absolute/relative error on each step will be - less than Eps). When passing: - * Eps>0, it means desired ABSOLUTE error - * Eps<0, it means desired RELATIVE error. Relative errors - are calculated with respect to maximum values of Y seen - so far. Be careful to use this criterion when starting - from Y[] that are close to zero. - H - initial step lenth, it will be adjusted automatically - after the first step. If H=0, step will be selected - automatically (usually it will be equal to 0.001 of - min(x[i]-x[j])). - -OUTPUT PARAMETERS - State - structure which stores algorithm state between subsequent - calls of OdeSolverIteration. Used for reverse communication. - This structure should be passed to the OdeSolverIteration - subroutine. - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. - - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = y.length(); - m = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::odesolverrkck(const_cast(y.c_ptr()), n, const_cast(x.c_ptr()), m, eps, h, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool odesolveriteration(const odesolverstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::odesolveriteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void odesolversolve(odesolverstate &state, - void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), - void *ptr){ - alglib_impl::ae_state _alglib_env_state; - if( diff==NULL ) - throw ap_error("ALGLIB: error in 'odesolversolve()' (diff is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::odesolveriteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needdy ) - { - diff(state.y, state.x, state.dy, ptr); - continue; - } - throw ap_error("ALGLIB: unexpected error in 'odesolversolve'"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -ODE solver results - -Called after OdeSolverIteration returned False. - -INPUT PARAMETERS: - State - algorithm state (used by OdeSolverIteration). - -OUTPUT PARAMETERS: - M - number of tabulated values, M>=1 - XTbl - array[0..M-1], values of X - YTbl - array[0..M-1,0..N-1], values of Y in X[i] - Rep - solver report: - * Rep.TerminationType completion code: - * -2 X is not ordered by ascending/descending or - there are non-distinct X[], i.e. X[i]=X[i+1] - * -1 incorrect parameters were specified - * 1 task has been solved - * Rep.NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::odesolverresults(const_cast(state.c_ptr()), &m, const_cast(xtbl.c_ptr()), const_cast(ytbl.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static double odesolver_odesolvermaxgrow = 3.0; -static double odesolver_odesolvermaxshrink = 10.0; -static void odesolver_odesolverinit(ae_int_t solvertype, - /* Real */ ae_vector* y, - ae_int_t n, - /* Real */ ae_vector* x, - ae_int_t m, - double eps, - double h, - odesolverstate* state, - ae_state *_state); - - - - - -/************************************************************************* -Cash-Karp adaptive ODE solver. - -This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys -(here Y may be single variable or vector of N variables). - -INPUT PARAMETERS: - Y - initial conditions, array[0..N-1]. - contains values of Y[] at X[0] - N - system size - X - points at which Y should be tabulated, array[0..M-1] - integrations starts at X[0], ends at X[M-1], intermediate - values at X[i] are returned too. - SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!! - M - number of intermediate points + first point + last point: - * M>2 means that you need both Y(X[M-1]) and M-2 values at - intermediate points - * M=2 means that you want just to integrate from X[0] to - X[1] and don't interested in intermediate values. - * M=1 means that you don't want to integrate :) - it is degenerate case, but it will be handled correctly. - * M<1 means error - Eps - tolerance (absolute/relative error on each step will be - less than Eps). When passing: - * Eps>0, it means desired ABSOLUTE error - * Eps<0, it means desired RELATIVE error. Relative errors - are calculated with respect to maximum values of Y seen - so far. Be careful to use this criterion when starting - from Y[] that are close to zero. - H - initial step lenth, it will be adjusted automatically - after the first step. If H=0, step will be selected - automatically (usually it will be equal to 0.001 of - min(x[i]-x[j])). - -OUTPUT PARAMETERS - State - structure which stores algorithm state between subsequent - calls of OdeSolverIteration. Used for reverse communication. - This structure should be passed to the OdeSolverIteration - subroutine. - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. - - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverrkck(/* Real */ ae_vector* y, - ae_int_t n, - /* Real */ ae_vector* x, - ae_int_t m, - double eps, - double h, - odesolverstate* state, - ae_state *_state) -{ - - _odesolverstate_clear(state); - - ae_assert(n>=1, "ODESolverRKCK: N<1!", _state); - ae_assert(m>=1, "ODESolverRKCK: M<1!", _state); - ae_assert(y->cnt>=n, "ODESolverRKCK: Length(Y)cnt>=m, "ODESolverRKCK: Length(X)rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - i = state->rstate.ia.ptr.p_int[2]; - j = state->rstate.ia.ptr.p_int[3]; - k = state->rstate.ia.ptr.p_int[4]; - klimit = state->rstate.ia.ptr.p_int[5]; - gridpoint = state->rstate.ba.ptr.p_bool[0]; - xc = state->rstate.ra.ptr.p_double[0]; - v = state->rstate.ra.ptr.p_double[1]; - h = state->rstate.ra.ptr.p_double[2]; - h2 = state->rstate.ra.ptr.p_double[3]; - err = state->rstate.ra.ptr.p_double[4]; - maxgrowpow = state->rstate.ra.ptr.p_double[5]; - } - else - { - n = -983; - m = -989; - i = -834; - j = 900; - k = -287; - klimit = 364; - gridpoint = ae_false; - xc = -338; - v = -686; - h = 912; - h2 = 585; - err = 497; - maxgrowpow = -271; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - - /* - * Routine body - */ - - /* - * prepare - */ - if( state->repterminationtype!=0 ) - { - result = ae_false; - return result; - } - n = state->n; - m = state->m; - h = state->h; - maxgrowpow = ae_pow(odesolver_odesolvermaxgrow, 5, _state); - state->repnfev = 0; - - /* - * some preliminary checks for internal errors - * after this we assume that H>0 and M>1 - */ - ae_assert(ae_fp_greater(state->h,0), "ODESolver: internal error", _state); - ae_assert(m>1, "ODESolverIteration: internal error", _state); - - /* - * choose solver - */ - if( state->solvertype!=0 ) - { - goto lbl_1; - } - - /* - * Cask-Karp solver - * Prepare coefficients table. - * Check it for errors - */ - ae_vector_set_length(&state->rka, 6, _state); - state->rka.ptr.p_double[0] = 0; - state->rka.ptr.p_double[1] = (double)1/(double)5; - state->rka.ptr.p_double[2] = (double)3/(double)10; - state->rka.ptr.p_double[3] = (double)3/(double)5; - state->rka.ptr.p_double[4] = 1; - state->rka.ptr.p_double[5] = (double)7/(double)8; - ae_matrix_set_length(&state->rkb, 6, 5, _state); - state->rkb.ptr.pp_double[1][0] = (double)1/(double)5; - state->rkb.ptr.pp_double[2][0] = (double)3/(double)40; - state->rkb.ptr.pp_double[2][1] = (double)9/(double)40; - state->rkb.ptr.pp_double[3][0] = (double)3/(double)10; - state->rkb.ptr.pp_double[3][1] = -(double)9/(double)10; - state->rkb.ptr.pp_double[3][2] = (double)6/(double)5; - state->rkb.ptr.pp_double[4][0] = -(double)11/(double)54; - state->rkb.ptr.pp_double[4][1] = (double)5/(double)2; - state->rkb.ptr.pp_double[4][2] = -(double)70/(double)27; - state->rkb.ptr.pp_double[4][3] = (double)35/(double)27; - state->rkb.ptr.pp_double[5][0] = (double)1631/(double)55296; - state->rkb.ptr.pp_double[5][1] = (double)175/(double)512; - state->rkb.ptr.pp_double[5][2] = (double)575/(double)13824; - state->rkb.ptr.pp_double[5][3] = (double)44275/(double)110592; - state->rkb.ptr.pp_double[5][4] = (double)253/(double)4096; - ae_vector_set_length(&state->rkc, 6, _state); - state->rkc.ptr.p_double[0] = (double)37/(double)378; - state->rkc.ptr.p_double[1] = 0; - state->rkc.ptr.p_double[2] = (double)250/(double)621; - state->rkc.ptr.p_double[3] = (double)125/(double)594; - state->rkc.ptr.p_double[4] = 0; - state->rkc.ptr.p_double[5] = (double)512/(double)1771; - ae_vector_set_length(&state->rkcs, 6, _state); - state->rkcs.ptr.p_double[0] = (double)2825/(double)27648; - state->rkcs.ptr.p_double[1] = 0; - state->rkcs.ptr.p_double[2] = (double)18575/(double)48384; - state->rkcs.ptr.p_double[3] = (double)13525/(double)55296; - state->rkcs.ptr.p_double[4] = (double)277/(double)14336; - state->rkcs.ptr.p_double[5] = (double)1/(double)4; - ae_matrix_set_length(&state->rkk, 6, n, _state); - - /* - * Main cycle consists of two iterations: - * * outer where we travel from X[i-1] to X[i] - * * inner where we travel inside [X[i-1],X[i]] - */ - ae_matrix_set_length(&state->ytbl, m, n, _state); - ae_vector_set_length(&state->escale, n, _state); - ae_vector_set_length(&state->yn, n, _state); - ae_vector_set_length(&state->yns, n, _state); - xc = state->xg.ptr.p_double[0]; - ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(j=0; j<=n-1; j++) - { - state->escale.ptr.p_double[j] = 0; - } - i = 1; -lbl_3: - if( i>m-1 ) - { - goto lbl_5; - } - - /* - * begin inner iteration - */ -lbl_6: - if( ae_false ) - { - goto lbl_7; - } - - /* - * truncate step if needed (beyond right boundary). - * determine should we store X or not - */ - if( ae_fp_greater_eq(xc+h,state->xg.ptr.p_double[i]) ) - { - h = state->xg.ptr.p_double[i]-xc; - gridpoint = ae_true; - } - else - { - gridpoint = ae_false; - } - - /* - * Update error scale maximums - * - * These maximums are initialized by zeros, - * then updated every iterations. - */ - for(j=0; j<=n-1; j++) - { - state->escale.ptr.p_double[j] = ae_maxreal(state->escale.ptr.p_double[j], ae_fabs(state->yc.ptr.p_double[j], _state), _state); - } - - /* - * make one step: - * 1. calculate all info needed to do step - * 2. update errors scale maximums using values/derivatives - * obtained during (1) - * - * Take into account that we use scaling of X to reduce task - * to the form where x[0] < x[1] < ... < x[n-1]. So X is - * replaced by x=xscale*t, and dy/dx=f(y,x) is replaced - * by dy/dt=xscale*f(y,xscale*t). - */ - ae_v_move(&state->yn.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->yns.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - k = 0; -lbl_8: - if( k>5 ) - { - goto lbl_10; - } - - /* - * prepare data for the next update of YN/YNS - */ - state->x = state->xscale*(xc+state->rka.ptr.p_double[k]*h); - ae_v_move(&state->y.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(j=0; j<=k-1; j++) - { - v = state->rkb.ptr.pp_double[k][j]; - ae_v_addd(&state->y.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); - } - state->needdy = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needdy = ae_false; - state->repnfev = state->repnfev+1; - v = h*state->xscale; - ae_v_moved(&state->rkk.ptr.pp_double[k][0], 1, &state->dy.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - - /* - * update YN/YNS - */ - v = state->rkc.ptr.p_double[k]; - ae_v_addd(&state->yn.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); - v = state->rkcs.ptr.p_double[k]; - ae_v_addd(&state->yns.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); - k = k+1; - goto lbl_8; -lbl_10: - - /* - * estimate error - */ - err = 0; - for(j=0; j<=n-1; j++) - { - if( !state->fraceps ) - { - - /* - * absolute error is estimated - */ - err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state), _state); - } - else - { - - /* - * Relative error is estimated - */ - v = state->escale.ptr.p_double[j]; - if( ae_fp_eq(v,0) ) - { - v = 1; - } - err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state)/v, _state); - } - } - - /* - * calculate new step, restart if necessary - */ - if( ae_fp_less_eq(maxgrowpow*err,state->eps) ) - { - h2 = odesolver_odesolvermaxgrow*h; - } - else - { - h2 = h*ae_pow(state->eps/err, 0.2, _state); - } - if( ae_fp_less(h2,h/odesolver_odesolvermaxshrink) ) - { - h2 = h/odesolver_odesolvermaxshrink; - } - if( ae_fp_greater(err,state->eps) ) - { - h = h2; - goto lbl_6; - } - - /* - * advance position - */ - xc = xc+h; - ae_v_move(&state->yc.ptr.p_double[0], 1, &state->yn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * update H - */ - h = h2; - - /* - * break on grid point - */ - if( gridpoint ) - { - goto lbl_7; - } - goto lbl_6; -lbl_7: - - /* - * save result - */ - ae_v_move(&state->ytbl.ptr.pp_double[i][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - i = i+1; - goto lbl_3; -lbl_5: - state->repterminationtype = 1; - result = ae_false; - return result; -lbl_1: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = i; - state->rstate.ia.ptr.p_int[3] = j; - state->rstate.ia.ptr.p_int[4] = k; - state->rstate.ia.ptr.p_int[5] = klimit; - state->rstate.ba.ptr.p_bool[0] = gridpoint; - state->rstate.ra.ptr.p_double[0] = xc; - state->rstate.ra.ptr.p_double[1] = v; - state->rstate.ra.ptr.p_double[2] = h; - state->rstate.ra.ptr.p_double[3] = h2; - state->rstate.ra.ptr.p_double[4] = err; - state->rstate.ra.ptr.p_double[5] = maxgrowpow; - return result; -} - - -/************************************************************************* -ODE solver results - -Called after OdeSolverIteration returned False. - -INPUT PARAMETERS: - State - algorithm state (used by OdeSolverIteration). - -OUTPUT PARAMETERS: - M - number of tabulated values, M>=1 - XTbl - array[0..M-1], values of X - YTbl - array[0..M-1,0..N-1], values of Y in X[i] - Rep - solver report: - * Rep.TerminationType completion code: - * -2 X is not ordered by ascending/descending or - there are non-distinct X[], i.e. X[i]=X[i+1] - * -1 incorrect parameters were specified - * 1 task has been solved - * Rep.NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverresults(odesolverstate* state, - ae_int_t* m, - /* Real */ ae_vector* xtbl, - /* Real */ ae_matrix* ytbl, - odesolverreport* rep, - ae_state *_state) -{ - double v; - ae_int_t i; - - *m = 0; - ae_vector_clear(xtbl); - ae_matrix_clear(ytbl); - _odesolverreport_clear(rep); - - rep->terminationtype = state->repterminationtype; - if( rep->terminationtype>0 ) - { - *m = state->m; - rep->nfev = state->repnfev; - ae_vector_set_length(xtbl, state->m, _state); - v = state->xscale; - ae_v_moved(&xtbl->ptr.p_double[0], 1, &state->xg.ptr.p_double[0], 1, ae_v_len(0,state->m-1), v); - ae_matrix_set_length(ytbl, state->m, state->n, _state); - for(i=0; i<=state->m-1; i++) - { - ae_v_move(&ytbl->ptr.pp_double[i][0], 1, &state->ytbl.ptr.pp_double[i][0], 1, ae_v_len(0,state->n-1)); - } - } - else - { - rep->nfev = 0; - } -} - - -/************************************************************************* -Internal initialization subroutine -*************************************************************************/ -static void odesolver_odesolverinit(ae_int_t solvertype, - /* Real */ ae_vector* y, - ae_int_t n, - /* Real */ ae_vector* x, - ae_int_t m, - double eps, - double h, - odesolverstate* state, - ae_state *_state) -{ - ae_int_t i; - double v; - - _odesolverstate_clear(state); - - - /* - * Prepare RComm - */ - ae_vector_set_length(&state->rstate.ia, 5+1, _state); - ae_vector_set_length(&state->rstate.ba, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 5+1, _state); - state->rstate.stage = -1; - state->needdy = ae_false; - - /* - * check parameters. - */ - if( (n<=0||m<1)||ae_fp_eq(eps,0) ) - { - state->repterminationtype = -1; - return; - } - if( ae_fp_less(h,0) ) - { - h = -h; - } - - /* - * quick exit if necessary. - * after this block we assume that M>1 - */ - if( m==1 ) - { - state->repnfev = 0; - state->repterminationtype = 1; - ae_matrix_set_length(&state->ytbl, 1, n, _state); - ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_vector_set_length(&state->xg, m, _state); - ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); - return; - } - - /* - * check again: correct order of X[] - */ - if( ae_fp_eq(x->ptr.p_double[1],x->ptr.p_double[0]) ) - { - state->repterminationtype = -2; - return; - } - for(i=1; i<=m-1; i++) - { - if( (ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_less_eq(x->ptr.p_double[i],x->ptr.p_double[i-1]))||(ae_fp_less(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i-1])) ) - { - state->repterminationtype = -2; - return; - } - } - - /* - * auto-select H if necessary - */ - if( ae_fp_eq(h,0) ) - { - v = ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state); - for(i=2; i<=m-1; i++) - { - v = ae_minreal(v, ae_fabs(x->ptr.p_double[i]-x->ptr.p_double[i-1], _state), _state); - } - h = 0.001*v; - } - - /* - * store parameters - */ - state->n = n; - state->m = m; - state->h = h; - state->eps = ae_fabs(eps, _state); - state->fraceps = ae_fp_less(eps,0); - ae_vector_set_length(&state->xg, m, _state); - ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); - if( ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0]) ) - { - state->xscale = 1; - } - else - { - state->xscale = -1; - ae_v_muld(&state->xg.ptr.p_double[0], 1, ae_v_len(0,m-1), -1); - } - ae_vector_set_length(&state->yc, n, _state); - ae_v_move(&state->yc.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->solvertype = solvertype; - state->repterminationtype = 0; - - /* - * Allocate arrays - */ - ae_vector_set_length(&state->y, n, _state); - ae_vector_set_length(&state->dy, n, _state); -} - - -ae_bool _odesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - odesolverstate *p = (odesolverstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->yc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->escale, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dy, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->ytbl, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->yn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->yns, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rka, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rkc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rkcs, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->rkb, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->rkk, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _odesolverstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - odesolverstate *dst = (odesolverstate*)_dst; - odesolverstate *src = (odesolverstate*)_src; - dst->n = src->n; - dst->m = src->m; - dst->xscale = src->xscale; - dst->h = src->h; - dst->eps = src->eps; - dst->fraceps = src->fraceps; - if( !ae_vector_init_copy(&dst->yc, &src->yc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->escale, &src->escale, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xg, &src->xg, _state, make_automatic) ) - return ae_false; - dst->solvertype = src->solvertype; - dst->needdy = src->needdy; - dst->x = src->x; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dy, &src->dy, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->ytbl, &src->ytbl, _state, make_automatic) ) - return ae_false; - dst->repterminationtype = src->repterminationtype; - dst->repnfev = src->repnfev; - if( !ae_vector_init_copy(&dst->yn, &src->yn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->yns, &src->yns, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rka, &src->rka, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rkc, &src->rkc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rkcs, &src->rkcs, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->rkb, &src->rkb, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->rkk, &src->rkk, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _odesolverstate_clear(void* _p) -{ - odesolverstate *p = (odesolverstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->yc); - ae_vector_clear(&p->escale); - ae_vector_clear(&p->xg); - ae_vector_clear(&p->y); - ae_vector_clear(&p->dy); - ae_matrix_clear(&p->ytbl); - ae_vector_clear(&p->yn); - ae_vector_clear(&p->yns); - ae_vector_clear(&p->rka); - ae_vector_clear(&p->rkc); - ae_vector_clear(&p->rkcs); - ae_matrix_clear(&p->rkb); - ae_matrix_clear(&p->rkk); - _rcommstate_clear(&p->rstate); -} - - -void _odesolverstate_destroy(void* _p) -{ - odesolverstate *p = (odesolverstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->yc); - ae_vector_destroy(&p->escale); - ae_vector_destroy(&p->xg); - ae_vector_destroy(&p->y); - ae_vector_destroy(&p->dy); - ae_matrix_destroy(&p->ytbl); - ae_vector_destroy(&p->yn); - ae_vector_destroy(&p->yns); - ae_vector_destroy(&p->rka); - ae_vector_destroy(&p->rkc); - ae_vector_destroy(&p->rkcs); - ae_matrix_destroy(&p->rkb); - ae_matrix_destroy(&p->rkk); - _rcommstate_destroy(&p->rstate); -} - - -ae_bool _odesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - odesolverreport *p = (odesolverreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _odesolverreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - odesolverreport *dst = (odesolverreport*)_dst; - odesolverreport *src = (odesolverreport*)_src; - dst->nfev = src->nfev; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _odesolverreport_clear(void* _p) -{ - odesolverreport *p = (odesolverreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _odesolverreport_destroy(void* _p) -{ - odesolverreport *p = (odesolverreport*)_p; - ae_touch_ptr((void*)p); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "diffequations.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Cash-Karp adaptive ODE solver. + +This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys +(here Y may be single variable or vector of N variables). + +INPUT PARAMETERS: + Y - initial conditions, array[0..N-1]. + contains values of Y[] at X[0] + N - system size + X - points at which Y should be tabulated, array[0..M-1] + integrations starts at X[0], ends at X[M-1], intermediate + values at X[i] are returned too. + SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! + M - number of intermediate points + first point + last point: + * M>2 means that you need both Y(X[M-1]) and M-2 values at + intermediate points + * M=2 means that you want just to integrate from X[0] to + X[1] and don't interested in intermediate values. + * M=1 means that you don't want to integrate :) + it is degenerate case, but it will be handled correctly. + * M<1 means error + Eps - tolerance (absolute/relative error on each step will be + less than Eps). When passing: + * Eps>0, it means desired ABSOLUTE error + * Eps<0, it means desired RELATIVE error. Relative errors + are calculated with respect to maximum values of Y seen + so far. Be careful to use this criterion when starting + from Y[] that are close to zero. + H - initial step lenth, it will be adjusted automatically + after the first step. If H=0, step will be selected + automatically (usualy it will be equal to 0.001 of + min(x[i]-x[j])). + +OUTPUT PARAMETERS + State - structure which stores algorithm state between subsequent + calls of OdeSolverIteration. Used for reverse communication. + This structure should be passed to the OdeSolverIteration + subroutine. + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. + + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::odesolverrkck(y.c_ptr(), n, x.c_ptr(), m, eps, h, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Cash-Karp adaptive ODE solver. + +This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys +(here Y may be single variable or vector of N variables). + +INPUT PARAMETERS: + Y - initial conditions, array[0..N-1]. + contains values of Y[] at X[0] + N - system size + X - points at which Y should be tabulated, array[0..M-1] + integrations starts at X[0], ends at X[M-1], intermediate + values at X[i] are returned too. + SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! + M - number of intermediate points + first point + last point: + * M>2 means that you need both Y(X[M-1]) and M-2 values at + intermediate points + * M=2 means that you want just to integrate from X[0] to + X[1] and don't interested in intermediate values. + * M=1 means that you don't want to integrate :) + it is degenerate case, but it will be handled correctly. + * M<1 means error + Eps - tolerance (absolute/relative error on each step will be + less than Eps). When passing: + * Eps>0, it means desired ABSOLUTE error + * Eps<0, it means desired RELATIVE error. Relative errors + are calculated with respect to maximum values of Y seen + so far. Be careful to use this criterion when starting + from Y[] that are close to zero. + H - initial step lenth, it will be adjusted automatically + after the first step. If H=0, step will be selected + automatically (usualy it will be equal to 0.001 of + min(x[i]-x[j])). + +OUTPUT PARAMETERS + State - structure which stores algorithm state between subsequent + calls of OdeSolverIteration. Used for reverse communication. + This structure should be passed to the OdeSolverIteration + subroutine. + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. + + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = y.length(); + m = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::odesolverrkck(y.c_ptr(), n, x.c_ptr(), m, eps, h, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool odesolveriteration(odesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::odesolveriteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void odesolversolve(odesolverstate &state, + void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), + void *ptr, const xparams _xparams){ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(diff!=NULL, "ALGLIB: error in 'odesolversolve()' (diff is NULL)", &_alglib_env_state); + while( alglib_impl::odesolveriteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needdy ) + { + diff(state.y, state.x, state.dy, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: unexpected error in 'odesolversolve'", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +ODE solver results + +Called after OdeSolverIteration returned False. + +INPUT PARAMETERS: + State - algorithm state (used by OdeSolverIteration). + +OUTPUT PARAMETERS: + M - number of tabulated values, M>=1 + XTbl - array[0..M-1], values of X + YTbl - array[0..M-1,0..N-1], values of Y in X[i] + Rep - solver report: + * Rep.TerminationType completetion code: + * -2 X is not ordered by ascending/descending or + there are non-distinct X[], i.e. X[i]=X[i+1] + * -1 incorrect parameters were specified + * 1 task has been solved + * Rep.NFEV contains number of function calculations + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::odesolverresults(state.c_ptr(), &m, xtbl.c_ptr(), ytbl.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* + +*************************************************************************/ +_odesolverstate_owner::_odesolverstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_odesolverstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::odesolverstate)); + alglib_impl::_odesolverstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_odesolverstate_owner::_odesolverstate_owner(alglib_impl::odesolverstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_odesolverstate_owner::_odesolverstate_owner(const _odesolverstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_odesolverstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: odesolverstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::odesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::odesolverstate)); + alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_odesolverstate_owner& _odesolverstate_owner::operator=(const _odesolverstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: odesolverstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: odesolverstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: odesolverstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_odesolverstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::odesolverstate)); + alglib_impl::_odesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_odesolverstate_owner::~_odesolverstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_odesolverstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::odesolverstate* _odesolverstate_owner::c_ptr() const +{ + return p_struct; +} +odesolverstate::odesolverstate() : _odesolverstate_owner() ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) +{ +} + +odesolverstate::odesolverstate(alglib_impl::odesolverstate *attach_to):_odesolverstate_owner(attach_to) ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) +{ +} + +odesolverstate::odesolverstate(const odesolverstate &rhs):_odesolverstate_owner(rhs) ,needdy(p_struct->needdy),y(&p_struct->y),dy(&p_struct->dy),x(p_struct->x) +{ +} + +odesolverstate& odesolverstate::operator=(const odesolverstate &rhs) +{ + if( this==&rhs ) + return *this; + _odesolverstate_owner::operator=(rhs); + return *this; +} + +odesolverstate::~odesolverstate() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_odesolverreport_owner::_odesolverreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_odesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::odesolverreport)); + alglib_impl::_odesolverreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_odesolverreport_owner::_odesolverreport_owner(alglib_impl::odesolverreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_odesolverreport_owner::_odesolverreport_owner(const _odesolverreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_odesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: odesolverreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::odesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::odesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::odesolverreport)); + alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_odesolverreport_owner& _odesolverreport_owner::operator=(const _odesolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: odesolverreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: odesolverreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: odesolverreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_odesolverreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::odesolverreport)); + alglib_impl::_odesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_odesolverreport_owner::~_odesolverreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_odesolverreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::odesolverreport* _odesolverreport_owner::c_ptr() const +{ + return p_struct; +} +odesolverreport::odesolverreport() : _odesolverreport_owner() ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +odesolverreport::odesolverreport(alglib_impl::odesolverreport *attach_to):_odesolverreport_owner(attach_to) ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +odesolverreport::odesolverreport(const odesolverreport &rhs):_odesolverreport_owner(rhs) ,nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +odesolverreport& odesolverreport::operator=(const odesolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _odesolverreport_owner::operator=(rhs); + return *this; +} + +odesolverreport::~odesolverreport() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +static double odesolver_odesolvermaxgrow = 3.0; +static double odesolver_odesolvermaxshrink = 10.0; +static double odesolver_odesolverguaranteeddecay = 0.9; +static void odesolver_odesolverinit(ae_int_t solvertype, + /* Real */ const ae_vector* y, + ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t m, + double eps, + double h, + odesolverstate* state, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Cash-Karp adaptive ODE solver. + +This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys +(here Y may be single variable or vector of N variables). + +INPUT PARAMETERS: + Y - initial conditions, array[0..N-1]. + contains values of Y[] at X[0] + N - system size + X - points at which Y should be tabulated, array[0..M-1] + integrations starts at X[0], ends at X[M-1], intermediate + values at X[i] are returned too. + SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! + M - number of intermediate points + first point + last point: + * M>2 means that you need both Y(X[M-1]) and M-2 values at + intermediate points + * M=2 means that you want just to integrate from X[0] to + X[1] and don't interested in intermediate values. + * M=1 means that you don't want to integrate :) + it is degenerate case, but it will be handled correctly. + * M<1 means error + Eps - tolerance (absolute/relative error on each step will be + less than Eps). When passing: + * Eps>0, it means desired ABSOLUTE error + * Eps<0, it means desired RELATIVE error. Relative errors + are calculated with respect to maximum values of Y seen + so far. Be careful to use this criterion when starting + from Y[] that are close to zero. + H - initial step lenth, it will be adjusted automatically + after the first step. If H=0, step will be selected + automatically (usualy it will be equal to 0.001 of + min(x[i]-x[j])). + +OUTPUT PARAMETERS + State - structure which stores algorithm state between subsequent + calls of OdeSolverIteration. Used for reverse communication. + This structure should be passed to the OdeSolverIteration + subroutine. + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. + + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverrkck(/* Real */ const ae_vector* y, + ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t m, + double eps, + double h, + odesolverstate* state, + ae_state *_state) +{ + + _odesolverstate_clear(state); + + ae_assert(n>=1, "ODESolverRKCK: N<1!", _state); + ae_assert(m>=1, "ODESolverRKCK: M<1!", _state); + ae_assert(y->cnt>=n, "ODESolverRKCK: Length(Y)cnt>=m, "ODESolverRKCK: Length(X)rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + j = state->rstate.ia.ptr.p_int[3]; + k = state->rstate.ia.ptr.p_int[4]; + klimit = state->rstate.ia.ptr.p_int[5]; + gridpoint = state->rstate.ba.ptr.p_bool[0]; + xc = state->rstate.ra.ptr.p_double[0]; + v = state->rstate.ra.ptr.p_double[1]; + h = state->rstate.ra.ptr.p_double[2]; + h2 = state->rstate.ra.ptr.p_double[3]; + err = state->rstate.ra.ptr.p_double[4]; + maxgrowpow = state->rstate.ra.ptr.p_double[5]; + } + else + { + n = 359; + m = -58; + i = -919; + j = -909; + k = 81; + klimit = 255; + gridpoint = ae_false; + xc = -788.0; + v = 809.0; + h = 205.0; + h2 = -838.0; + err = 939.0; + maxgrowpow = -526.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + + /* + * prepare + */ + if( state->repterminationtype!=0 ) + { + result = ae_false; + return result; + } + n = state->n; + m = state->m; + h = state->h; + maxgrowpow = ae_pow(odesolver_odesolvermaxgrow, (double)(5), _state); + state->repnfev = 0; + + /* + * some preliminary checks for internal errors + * after this we assume that H>0 and M>1 + */ + ae_assert(ae_fp_greater(state->h,(double)(0)), "ODESolver: internal error", _state); + ae_assert(m>1, "ODESolverIteration: internal error", _state); + + /* + * choose solver + */ + if( state->solvertype!=0 ) + { + goto lbl_1; + } + + /* + * Cask-Karp solver + * Prepare coefficients table. + * Check it for errors + */ + ae_vector_set_length(&state->rka, 6, _state); + state->rka.ptr.p_double[0] = (double)(0); + state->rka.ptr.p_double[1] = (double)1/(double)5; + state->rka.ptr.p_double[2] = (double)3/(double)10; + state->rka.ptr.p_double[3] = (double)3/(double)5; + state->rka.ptr.p_double[4] = (double)(1); + state->rka.ptr.p_double[5] = (double)7/(double)8; + ae_matrix_set_length(&state->rkb, 6, 5, _state); + state->rkb.ptr.pp_double[1][0] = (double)1/(double)5; + state->rkb.ptr.pp_double[2][0] = (double)3/(double)40; + state->rkb.ptr.pp_double[2][1] = (double)9/(double)40; + state->rkb.ptr.pp_double[3][0] = (double)3/(double)10; + state->rkb.ptr.pp_double[3][1] = -(double)9/(double)10; + state->rkb.ptr.pp_double[3][2] = (double)6/(double)5; + state->rkb.ptr.pp_double[4][0] = -(double)11/(double)54; + state->rkb.ptr.pp_double[4][1] = (double)5/(double)2; + state->rkb.ptr.pp_double[4][2] = -(double)70/(double)27; + state->rkb.ptr.pp_double[4][3] = (double)35/(double)27; + state->rkb.ptr.pp_double[5][0] = (double)1631/(double)55296; + state->rkb.ptr.pp_double[5][1] = (double)175/(double)512; + state->rkb.ptr.pp_double[5][2] = (double)575/(double)13824; + state->rkb.ptr.pp_double[5][3] = (double)44275/(double)110592; + state->rkb.ptr.pp_double[5][4] = (double)253/(double)4096; + ae_vector_set_length(&state->rkc, 6, _state); + state->rkc.ptr.p_double[0] = (double)37/(double)378; + state->rkc.ptr.p_double[1] = (double)(0); + state->rkc.ptr.p_double[2] = (double)250/(double)621; + state->rkc.ptr.p_double[3] = (double)125/(double)594; + state->rkc.ptr.p_double[4] = (double)(0); + state->rkc.ptr.p_double[5] = (double)512/(double)1771; + ae_vector_set_length(&state->rkcs, 6, _state); + state->rkcs.ptr.p_double[0] = (double)2825/(double)27648; + state->rkcs.ptr.p_double[1] = (double)(0); + state->rkcs.ptr.p_double[2] = (double)18575/(double)48384; + state->rkcs.ptr.p_double[3] = (double)13525/(double)55296; + state->rkcs.ptr.p_double[4] = (double)277/(double)14336; + state->rkcs.ptr.p_double[5] = (double)1/(double)4; + ae_matrix_set_length(&state->rkk, 6, n, _state); + + /* + * Main cycle consists of two iterations: + * * outer where we travel from X[i-1] to X[i] + * * inner where we travel inside [X[i-1],X[i]] + */ + ae_matrix_set_length(&state->ytbl, m, n, _state); + ae_vector_set_length(&state->escale, n, _state); + ae_vector_set_length(&state->yn, n, _state); + ae_vector_set_length(&state->yns, n, _state); + xc = state->xg.ptr.p_double[0]; + ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(j=0; j<=n-1; j++) + { + state->escale.ptr.p_double[j] = (double)(0); + } + i = 1; +lbl_3: + if( i>m-1 ) + { + goto lbl_5; + } + + /* + * begin inner iteration + */ +lbl_6: + if( ae_false ) + { + goto lbl_7; + } + + /* + * truncate step if needed (beyond right boundary). + * determine should we store X or not + */ + if( ae_fp_greater_eq(xc+h,state->xg.ptr.p_double[i]) ) + { + h = state->xg.ptr.p_double[i]-xc; + gridpoint = ae_true; + } + else + { + gridpoint = ae_false; + } + + /* + * Update error scale maximums + * + * These maximums are initialized by zeros, + * then updated every iterations. + */ + for(j=0; j<=n-1; j++) + { + state->escale.ptr.p_double[j] = ae_maxreal(state->escale.ptr.p_double[j], ae_fabs(state->yc.ptr.p_double[j], _state), _state); + } + + /* + * make one step: + * 1. calculate all info needed to do step + * 2. update errors scale maximums using values/derivatives + * obtained during (1) + * + * Take into account that we use scaling of X to reduce task + * to the form where x[0] < x[1] < ... < x[n-1]. So X is + * replaced by x=xscale*t, and dy/dx=f(y,x) is replaced + * by dy/dt=xscale*f(y,xscale*t). + */ + ae_v_move(&state->yn.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->yns.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + k = 0; +lbl_8: + if( k>5 ) + { + goto lbl_10; + } + + /* + * prepare data for the next update of YN/YNS + */ + state->x = state->xscale*(xc+state->rka.ptr.p_double[k]*h); + ae_v_move(&state->y.ptr.p_double[0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(j=0; j<=k-1; j++) + { + v = state->rkb.ptr.pp_double[k][j]; + ae_v_addd(&state->y.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); + } + state->needdy = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needdy = ae_false; + state->repnfev = state->repnfev+1; + v = h*state->xscale; + ae_v_moved(&state->rkk.ptr.pp_double[k][0], 1, &state->dy.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + + /* + * update YN/YNS + */ + v = state->rkc.ptr.p_double[k]; + ae_v_addd(&state->yn.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); + v = state->rkcs.ptr.p_double[k]; + ae_v_addd(&state->yns.ptr.p_double[0], 1, &state->rkk.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); + k = k+1; + goto lbl_8; +lbl_10: + + /* + * estimate error + */ + err = (double)(0); + for(j=0; j<=n-1; j++) + { + if( !state->fraceps ) + { + + /* + * absolute error is estimated + */ + err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state), _state); + } + else + { + + /* + * Relative error is estimated + */ + v = state->escale.ptr.p_double[j]; + if( ae_fp_eq(v,(double)(0)) ) + { + v = (double)(1); + } + err = ae_maxreal(err, ae_fabs(state->yn.ptr.p_double[j]-state->yns.ptr.p_double[j], _state)/v, _state); + } + } + + /* + * calculate new step, restart if necessary + */ + if( ae_fp_less_eq(maxgrowpow*err,state->eps) ) + { + h2 = odesolver_odesolvermaxgrow*h; + } + else + { + h2 = h*ae_pow(state->eps/err, 0.2, _state); + } + if( ae_fp_less(h2,h/odesolver_odesolvermaxshrink) ) + { + h2 = h/odesolver_odesolvermaxshrink; + } + if( ae_fp_greater(err,state->eps) ) + { + h = ae_minreal(h2, odesolver_odesolverguaranteeddecay*h, _state); + goto lbl_6; + } + + /* + * advance position + */ + xc = xc+h; + ae_v_move(&state->yc.ptr.p_double[0], 1, &state->yn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * update H + */ + h = h2; + + /* + * break on grid point + */ + if( gridpoint ) + { + goto lbl_7; + } + goto lbl_6; +lbl_7: + + /* + * save result + */ + ae_v_move(&state->ytbl.ptr.pp_double[i][0], 1, &state->yc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + i = i+1; + goto lbl_3; +lbl_5: + state->repterminationtype = 1; + result = ae_false; + return result; +lbl_1: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = j; + state->rstate.ia.ptr.p_int[4] = k; + state->rstate.ia.ptr.p_int[5] = klimit; + state->rstate.ba.ptr.p_bool[0] = gridpoint; + state->rstate.ra.ptr.p_double[0] = xc; + state->rstate.ra.ptr.p_double[1] = v; + state->rstate.ra.ptr.p_double[2] = h; + state->rstate.ra.ptr.p_double[3] = h2; + state->rstate.ra.ptr.p_double[4] = err; + state->rstate.ra.ptr.p_double[5] = maxgrowpow; + return result; +} + + +/************************************************************************* +ODE solver results + +Called after OdeSolverIteration returned False. + +INPUT PARAMETERS: + State - algorithm state (used by OdeSolverIteration). + +OUTPUT PARAMETERS: + M - number of tabulated values, M>=1 + XTbl - array[0..M-1], values of X + YTbl - array[0..M-1,0..N-1], values of Y in X[i] + Rep - solver report: + * Rep.TerminationType completetion code: + * -2 X is not ordered by ascending/descending or + there are non-distinct X[], i.e. X[i]=X[i+1] + * -1 incorrect parameters were specified + * 1 task has been solved + * Rep.NFEV contains number of function calculations + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverresults(const odesolverstate* state, + ae_int_t* m, + /* Real */ ae_vector* xtbl, + /* Real */ ae_matrix* ytbl, + odesolverreport* rep, + ae_state *_state) +{ + double v; + ae_int_t i; + + *m = 0; + ae_vector_clear(xtbl); + ae_matrix_clear(ytbl); + _odesolverreport_clear(rep); + + rep->terminationtype = state->repterminationtype; + if( rep->terminationtype>0 ) + { + *m = state->m; + rep->nfev = state->repnfev; + ae_vector_set_length(xtbl, state->m, _state); + v = state->xscale; + ae_v_moved(&xtbl->ptr.p_double[0], 1, &state->xg.ptr.p_double[0], 1, ae_v_len(0,state->m-1), v); + ae_matrix_set_length(ytbl, state->m, state->n, _state); + for(i=0; i<=state->m-1; i++) + { + ae_v_move(&ytbl->ptr.pp_double[i][0], 1, &state->ytbl.ptr.pp_double[i][0], 1, ae_v_len(0,state->n-1)); + } + } + else + { + rep->nfev = 0; + } +} + + +/************************************************************************* +Internal initialization subroutine +*************************************************************************/ +static void odesolver_odesolverinit(ae_int_t solvertype, + /* Real */ const ae_vector* y, + ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t m, + double eps, + double h, + odesolverstate* state, + ae_state *_state) +{ + ae_int_t i; + double v; + + _odesolverstate_clear(state); + + + /* + * Prepare RComm + */ + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; + state->needdy = ae_false; + + /* + * check parameters. + */ + if( (n<=0||m<1)||ae_fp_eq(eps,(double)(0)) ) + { + state->repterminationtype = -1; + return; + } + if( ae_fp_less(h,(double)(0)) ) + { + h = -h; + } + + /* + * quick exit if necessary. + * after this block we assume that M>1 + */ + if( m==1 ) + { + state->repnfev = 0; + state->repterminationtype = 1; + ae_matrix_set_length(&state->ytbl, 1, n, _state); + ae_v_move(&state->ytbl.ptr.pp_double[0][0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_vector_set_length(&state->xg, m, _state); + ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); + return; + } + + /* + * check again: correct order of X[] + */ + if( ae_fp_eq(x->ptr.p_double[1],x->ptr.p_double[0]) ) + { + state->repterminationtype = -2; + return; + } + for(i=1; i<=m-1; i++) + { + if( (ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_less_eq(x->ptr.p_double[i],x->ptr.p_double[i-1]))||(ae_fp_less(x->ptr.p_double[1],x->ptr.p_double[0])&&ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i-1])) ) + { + state->repterminationtype = -2; + return; + } + } + + /* + * auto-select H if necessary + */ + if( ae_fp_eq(h,(double)(0)) ) + { + v = ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state); + for(i=2; i<=m-1; i++) + { + v = ae_minreal(v, ae_fabs(x->ptr.p_double[i]-x->ptr.p_double[i-1], _state), _state); + } + h = 0.001*v; + } + + /* + * store parameters + */ + state->n = n; + state->m = m; + state->h = h; + state->eps = ae_fabs(eps, _state); + state->fraceps = ae_fp_less(eps,(double)(0)); + ae_vector_set_length(&state->xg, m, _state); + ae_v_move(&state->xg.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,m-1)); + if( ae_fp_greater(x->ptr.p_double[1],x->ptr.p_double[0]) ) + { + state->xscale = (double)(1); + } + else + { + state->xscale = (double)(-1); + ae_v_muld(&state->xg.ptr.p_double[0], 1, ae_v_len(0,m-1), -1.0); + } + ae_vector_set_length(&state->yc, n, _state); + ae_v_move(&state->yc.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->solvertype = solvertype; + state->repterminationtype = 0; + + /* + * Allocate arrays + */ + ae_vector_set_length(&state->y, n, _state); + ae_vector_set_length(&state->dy, n, _state); +} + + +void _odesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + odesolverstate *p = (odesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->yc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->escale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dy, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ytbl, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yns, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rka, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rkc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rkcs, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rkb, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rkk, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _odesolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + odesolverstate *dst = (odesolverstate*)_dst; + const odesolverstate *src = (const odesolverstate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->xscale = src->xscale; + dst->h = src->h; + dst->eps = src->eps; + dst->fraceps = src->fraceps; + ae_vector_init_copy(&dst->yc, &src->yc, _state, make_automatic); + ae_vector_init_copy(&dst->escale, &src->escale, _state, make_automatic); + ae_vector_init_copy(&dst->xg, &src->xg, _state, make_automatic); + dst->solvertype = src->solvertype; + dst->needdy = src->needdy; + dst->x = src->x; + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->dy, &src->dy, _state, make_automatic); + ae_matrix_init_copy(&dst->ytbl, &src->ytbl, _state, make_automatic); + dst->repterminationtype = src->repterminationtype; + dst->repnfev = src->repnfev; + ae_vector_init_copy(&dst->yn, &src->yn, _state, make_automatic); + ae_vector_init_copy(&dst->yns, &src->yns, _state, make_automatic); + ae_vector_init_copy(&dst->rka, &src->rka, _state, make_automatic); + ae_vector_init_copy(&dst->rkc, &src->rkc, _state, make_automatic); + ae_vector_init_copy(&dst->rkcs, &src->rkcs, _state, make_automatic); + ae_matrix_init_copy(&dst->rkb, &src->rkb, _state, make_automatic); + ae_matrix_init_copy(&dst->rkk, &src->rkk, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _odesolverstate_clear(void* _p) +{ + odesolverstate *p = (odesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->yc); + ae_vector_clear(&p->escale); + ae_vector_clear(&p->xg); + ae_vector_clear(&p->y); + ae_vector_clear(&p->dy); + ae_matrix_clear(&p->ytbl); + ae_vector_clear(&p->yn); + ae_vector_clear(&p->yns); + ae_vector_clear(&p->rka); + ae_vector_clear(&p->rkc); + ae_vector_clear(&p->rkcs); + ae_matrix_clear(&p->rkb); + ae_matrix_clear(&p->rkk); + _rcommstate_clear(&p->rstate); +} + + +void _odesolverstate_destroy(void* _p) +{ + odesolverstate *p = (odesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->yc); + ae_vector_destroy(&p->escale); + ae_vector_destroy(&p->xg); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->dy); + ae_matrix_destroy(&p->ytbl); + ae_vector_destroy(&p->yn); + ae_vector_destroy(&p->yns); + ae_vector_destroy(&p->rka); + ae_vector_destroy(&p->rkc); + ae_vector_destroy(&p->rkcs); + ae_matrix_destroy(&p->rkb); + ae_matrix_destroy(&p->rkk); + _rcommstate_destroy(&p->rstate); +} + + +void _odesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + odesolverreport *p = (odesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _odesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + odesolverreport *dst = (odesolverreport*)_dst; + const odesolverreport *src = (const odesolverreport*)_src; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; +} + + +void _odesolverreport_clear(void* _p) +{ + odesolverreport *p = (odesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _odesolverreport_destroy(void* _p) +{ + odesolverreport *p = (odesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif + +} + diff --git a/core/alglib/diffequations.h b/core/alglib/diffequations.h index d1012692..d3acd925 100644 --- a/core/alglib/diffequations.h +++ b/core/alglib/diffequations.h @@ -1,267 +1,290 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _diffequations_pkg_h -#define _diffequations_pkg_h -#include "ap.h" -#include "alglibinternal.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_int_t n; - ae_int_t m; - double xscale; - double h; - double eps; - ae_bool fraceps; - ae_vector yc; - ae_vector escale; - ae_vector xg; - ae_int_t solvertype; - ae_bool needdy; - double x; - ae_vector y; - ae_vector dy; - ae_matrix ytbl; - ae_int_t repterminationtype; - ae_int_t repnfev; - ae_vector yn; - ae_vector yns; - ae_vector rka; - ae_vector rkc; - ae_vector rkcs; - ae_matrix rkb; - ae_matrix rkk; - rcommstate rstate; -} odesolverstate; -typedef struct -{ - ae_int_t nfev; - ae_int_t terminationtype; -} odesolverreport; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - -/************************************************************************* - -*************************************************************************/ -class _odesolverstate_owner -{ -public: - _odesolverstate_owner(); - _odesolverstate_owner(const _odesolverstate_owner &rhs); - _odesolverstate_owner& operator=(const _odesolverstate_owner &rhs); - virtual ~_odesolverstate_owner(); - alglib_impl::odesolverstate* c_ptr(); - alglib_impl::odesolverstate* c_ptr() const; -protected: - alglib_impl::odesolverstate *p_struct; -}; -class odesolverstate : public _odesolverstate_owner -{ -public: - odesolverstate(); - odesolverstate(const odesolverstate &rhs); - odesolverstate& operator=(const odesolverstate &rhs); - virtual ~odesolverstate(); - ae_bool &needdy; - real_1d_array y; - real_1d_array dy; - double &x; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _odesolverreport_owner -{ -public: - _odesolverreport_owner(); - _odesolverreport_owner(const _odesolverreport_owner &rhs); - _odesolverreport_owner& operator=(const _odesolverreport_owner &rhs); - virtual ~_odesolverreport_owner(); - alglib_impl::odesolverreport* c_ptr(); - alglib_impl::odesolverreport* c_ptr() const; -protected: - alglib_impl::odesolverreport *p_struct; -}; -class odesolverreport : public _odesolverreport_owner -{ -public: - odesolverreport(); - odesolverreport(const odesolverreport &rhs); - odesolverreport& operator=(const odesolverreport &rhs); - virtual ~odesolverreport(); - ae_int_t &nfev; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -Cash-Karp adaptive ODE solver. - -This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys -(here Y may be single variable or vector of N variables). - -INPUT PARAMETERS: - Y - initial conditions, array[0..N-1]. - contains values of Y[] at X[0] - N - system size - X - points at which Y should be tabulated, array[0..M-1] - integrations starts at X[0], ends at X[M-1], intermediate - values at X[i] are returned too. - SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING!!!! - M - number of intermediate points + first point + last point: - * M>2 means that you need both Y(X[M-1]) and M-2 values at - intermediate points - * M=2 means that you want just to integrate from X[0] to - X[1] and don't interested in intermediate values. - * M=1 means that you don't want to integrate :) - it is degenerate case, but it will be handled correctly. - * M<1 means error - Eps - tolerance (absolute/relative error on each step will be - less than Eps). When passing: - * Eps>0, it means desired ABSOLUTE error - * Eps<0, it means desired RELATIVE error. Relative errors - are calculated with respect to maximum values of Y seen - so far. Be careful to use this criterion when starting - from Y[] that are close to zero. - H - initial step lenth, it will be adjusted automatically - after the first step. If H=0, step will be selected - automatically (usually it will be equal to 0.001 of - min(x[i]-x[j])). - -OUTPUT PARAMETERS - State - structure which stores algorithm state between subsequent - calls of OdeSolverIteration. Used for reverse communication. - This structure should be passed to the OdeSolverIteration - subroutine. - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. - - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state); -void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool odesolveriteration(const odesolverstate &state); - - -/************************************************************************* -This function is used to launcn iterations of ODE solver - -It accepts following parameters: - diff - callback which calculates dy/dx for given y and x - ptr - optional pointer which is passed to diff; can be NULL - - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey - -*************************************************************************/ -void odesolversolve(odesolverstate &state, - void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), - void *ptr = NULL); - - -/************************************************************************* -ODE solver results - -Called after OdeSolverIteration returned False. - -INPUT PARAMETERS: - State - algorithm state (used by OdeSolverIteration). - -OUTPUT PARAMETERS: - M - number of tabulated values, M>=1 - XTbl - array[0..M-1], values of X - YTbl - array[0..M-1,0..N-1], values of Y in X[i] - Rep - solver report: - * Rep.TerminationType completion code: - * -2 X is not ordered by ascending/descending or - there are non-distinct X[], i.e. X[i]=X[i+1] - * -1 incorrect parameters were specified - * 1 task has been solved - * Rep.NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 01.09.2009 by Bochkanov Sergey -*************************************************************************/ -void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void odesolverrkck(/* Real */ ae_vector* y, - ae_int_t n, - /* Real */ ae_vector* x, - ae_int_t m, - double eps, - double h, - odesolverstate* state, - ae_state *_state); -ae_bool odesolveriteration(odesolverstate* state, ae_state *_state); -void odesolverresults(odesolverstate* state, - ae_int_t* m, - /* Real */ ae_vector* xtbl, - /* Real */ ae_matrix* ytbl, - odesolverreport* rep, - ae_state *_state); -ae_bool _odesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _odesolverstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _odesolverstate_clear(void* _p); -void _odesolverstate_destroy(void* _p); -ae_bool _odesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _odesolverreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _odesolverreport_clear(void* _p); -void _odesolverreport_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _diffequations_pkg_h +#define _diffequations_pkg_h +#include "ap.h" +#include "alglibinternal.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double xscale; + double h; + double eps; + ae_bool fraceps; + ae_vector yc; + ae_vector escale; + ae_vector xg; + ae_int_t solvertype; + ae_bool needdy; + double x; + ae_vector y; + ae_vector dy; + ae_matrix ytbl; + ae_int_t repterminationtype; + ae_int_t repnfev; + ae_vector yn; + ae_vector yns; + ae_vector rka; + ae_vector rkc; + ae_vector rkcs; + ae_matrix rkb; + ae_matrix rkk; + rcommstate rstate; +} odesolverstate; +typedef struct +{ + ae_int_t nfev; + ae_int_t terminationtype; +} odesolverreport; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +class _odesolverstate_owner; +class odesolverstate; +class _odesolverreport_owner; +class odesolverreport; + + +/************************************************************************* + +*************************************************************************/ +class _odesolverstate_owner +{ +public: + _odesolverstate_owner(); + _odesolverstate_owner(alglib_impl::odesolverstate *attach_to); + _odesolverstate_owner(const _odesolverstate_owner &rhs); + _odesolverstate_owner& operator=(const _odesolverstate_owner &rhs); + virtual ~_odesolverstate_owner(); + alglib_impl::odesolverstate* c_ptr(); + const alglib_impl::odesolverstate* c_ptr() const; +protected: + alglib_impl::odesolverstate *p_struct; + bool is_attached; +}; +class odesolverstate : public _odesolverstate_owner +{ +public: + odesolverstate(); + odesolverstate(alglib_impl::odesolverstate *attach_to); + odesolverstate(const odesolverstate &rhs); + odesolverstate& operator=(const odesolverstate &rhs); + virtual ~odesolverstate(); + ae_bool &needdy; + real_1d_array y; + real_1d_array dy; + double &x; + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _odesolverreport_owner +{ +public: + _odesolverreport_owner(); + _odesolverreport_owner(alglib_impl::odesolverreport *attach_to); + _odesolverreport_owner(const _odesolverreport_owner &rhs); + _odesolverreport_owner& operator=(const _odesolverreport_owner &rhs); + virtual ~_odesolverreport_owner(); + alglib_impl::odesolverreport* c_ptr(); + const alglib_impl::odesolverreport* c_ptr() const; +protected: + alglib_impl::odesolverreport *p_struct; + bool is_attached; +}; +class odesolverreport : public _odesolverreport_owner +{ +public: + odesolverreport(); + odesolverreport(alglib_impl::odesolverreport *attach_to); + odesolverreport(const odesolverreport &rhs); + odesolverreport& operator=(const odesolverreport &rhs); + virtual ~odesolverreport(); + ae_int_t &nfev; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Cash-Karp adaptive ODE solver. + +This subroutine solves ODE Y'=f(Y,x) with initial conditions Y(xs)=Ys +(here Y may be single variable or vector of N variables). + +INPUT PARAMETERS: + Y - initial conditions, array[0..N-1]. + contains values of Y[] at X[0] + N - system size + X - points at which Y should be tabulated, array[0..M-1] + integrations starts at X[0], ends at X[M-1], intermediate + values at X[i] are returned too. + SHOULD BE ORDERED BY ASCENDING OR BY DESCENDING! + M - number of intermediate points + first point + last point: + * M>2 means that you need both Y(X[M-1]) and M-2 values at + intermediate points + * M=2 means that you want just to integrate from X[0] to + X[1] and don't interested in intermediate values. + * M=1 means that you don't want to integrate :) + it is degenerate case, but it will be handled correctly. + * M<1 means error + Eps - tolerance (absolute/relative error on each step will be + less than Eps). When passing: + * Eps>0, it means desired ABSOLUTE error + * Eps<0, it means desired RELATIVE error. Relative errors + are calculated with respect to maximum values of Y seen + so far. Be careful to use this criterion when starting + from Y[] that are close to zero. + H - initial step lenth, it will be adjusted automatically + after the first step. If H=0, step will be selected + automatically (usualy it will be equal to 0.001 of + min(x[i]-x[j])). + +OUTPUT PARAMETERS + State - structure which stores algorithm state between subsequent + calls of OdeSolverIteration. Used for reverse communication. + This structure should be passed to the OdeSolverIteration + subroutine. + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKIteration, AutoGKResults. + + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverrkck(const real_1d_array &y, const ae_int_t n, const real_1d_array &x, const ae_int_t m, const double eps, const double h, odesolverstate &state, const xparams _xparams = alglib::xdefault); +void odesolverrkck(const real_1d_array &y, const real_1d_array &x, const double eps, const double h, odesolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool odesolveriteration(odesolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to start iterations of the ODE solver + +It accepts following parameters: + diff - callback which calculates dy/dx for given y and x + ptr - optional pointer which is passed to diff; can be NULL + + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey + +*************************************************************************/ +void odesolversolve(odesolverstate &state, + void (*diff)(const real_1d_array &y, double x, real_1d_array &dy, void *ptr), + void *ptr = NULL, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +ODE solver results + +Called after OdeSolverIteration returned False. + +INPUT PARAMETERS: + State - algorithm state (used by OdeSolverIteration). + +OUTPUT PARAMETERS: + M - number of tabulated values, M>=1 + XTbl - array[0..M-1], values of X + YTbl - array[0..M-1,0..N-1], values of Y in X[i] + Rep - solver report: + * Rep.TerminationType completetion code: + * -2 X is not ordered by ascending/descending or + there are non-distinct X[], i.e. X[i]=X[i+1] + * -1 incorrect parameters were specified + * 1 task has been solved + * Rep.NFEV contains number of function calculations + + -- ALGLIB -- + Copyright 01.09.2009 by Bochkanov Sergey +*************************************************************************/ +void odesolverresults(const odesolverstate &state, ae_int_t &m, real_1d_array &xtbl, real_2d_array &ytbl, odesolverreport &rep, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ODESOLVER) || !defined(AE_PARTIAL_BUILD) +void odesolverrkck(/* Real */ const ae_vector* y, + ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t m, + double eps, + double h, + odesolverstate* state, + ae_state *_state); +ae_bool odesolveriteration(odesolverstate* state, ae_state *_state); +void odesolverresults(const odesolverstate* state, + ae_int_t* m, + /* Real */ ae_vector* xtbl, + /* Real */ ae_matrix* ytbl, + odesolverreport* rep, + ae_state *_state); +void _odesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _odesolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _odesolverstate_clear(void* _p); +void _odesolverstate_destroy(void* _p); +void _odesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _odesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _odesolverreport_clear(void* _p); +void _odesolverreport_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/fasttransforms.cpp b/core/alglib/fasttransforms.cpp index 2dd0ca38..81014e38 100644 --- a/core/alglib/fasttransforms.cpp +++ b/core/alglib/fasttransforms.cpp @@ -1,3554 +1,4696 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "fasttransforms.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -1-dimensional complex FFT. - -Array size N may be arbitrary number (composite or prime). Composite N's -are handled with cache-oblivious variation of a Cooley-Tukey algorithm. -Small prime-factors are transformed using hard coded codelets (similar to -FFTW codelets, but without low-level optimization), large prime-factors -are handled with Bluestein's algorithm. - -Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), -most fast for powers of 2. When N have prime factors larger than these, -but orders of magnitude smaller than N, computations will be about 4 times -slower than for nearby highly composite N's. When N itself is prime, speed -will be 6 times lower. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1d(complex_1d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftc1d(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex FFT. - -Array size N may be arbitrary number (composite or prime). Composite N's -are handled with cache-oblivious variation of a Cooley-Tukey algorithm. -Small prime-factors are transformed using hard coded codelets (similar to -FFTW codelets, but without low-level optimization), large prime-factors -are handled with Bluestein's algorithm. - -Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), -most fast for powers of 2. When N have prime factors larger than these, -but orders of magnitude smaller than N, computations will be about 4 times -slower than for nearby highly composite N's. When N itself is prime, speed -will be 6 times lower. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1d(complex_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = a.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftc1d(const_cast(a.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex inverse FFT. - -Array size N may be arbitrary number (composite or prime). Algorithm has -O(N*logN) complexity for any N (composite or prime). - -See FFTC1D() description for more information about algorithm performance. - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1dinv(complex_1d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftc1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex inverse FFT. - -Array size N may be arbitrary number (composite or prime). Algorithm has -O(N*logN) complexity for any N (composite or prime). - -See FFTC1D() description for more information about algorithm performance. - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1dinv(complex_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = a.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftc1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - F - DFT of a input array, array[0..N-1] - F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - -NOTE: - F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half -of array is usually needed. But for convenience subroutine returns full -complex array (with frequencies above N/2), so its result may be used by -other FFT-related subroutines. - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftr1d(const_cast(a.c_ptr()), n, const_cast(f.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - F - DFT of a input array, array[0..N-1] - F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - -NOTE: - F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half -of array is usually needed. But for convenience subroutine returns full -complex array (with frequencies above N/2), so its result may be used by -other FFT-related subroutines. - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1d(const real_1d_array &a, complex_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = a.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftr1d(const_cast(a.c_ptr()), n, const_cast(f.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real inverse FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - F - array[0..floor(N/2)] - frequencies from forward real FFT - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - -NOTE: - F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one -half of frequencies array is needed - elements from 0 to floor(N/2). F[0] -is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then -F[floor(N/2)] has no special properties. - -Relying on properties noted above, FFTR1DInv subroutine uses only elements -from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case -N is even it ignores imaginary part of F[floor(N/2)] too. - -When you call this function using full arguments list - "FFTR1DInv(F,N,A)" -- you can pass either either frequencies array with N elements or reduced -array with roughly N/2 elements - subroutine will successfully transform -both. - -If you call this function using reduced arguments list - "FFTR1DInv(F,A)" -- you must pass FULL array with N elements (although higher N/2 are still -not used) because array size is used to automatically determine FFT length - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftr1dinv(const_cast(f.c_ptr()), n, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real inverse FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - F - array[0..floor(N/2)] - frequencies from forward real FFT - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - -NOTE: - F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one -half of frequencies array is needed - elements from 0 to floor(N/2). F[0] -is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then -F[floor(N/2)] has no special properties. - -Relying on properties noted above, FFTR1DInv subroutine uses only elements -from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case -N is even it ignores imaginary part of F[floor(N/2)] too. - -When you call this function using full arguments list - "FFTR1DInv(F,N,A)" -- you can pass either either frequencies array with N elements or reduced -array with roughly N/2 elements - subroutine will successfully transform -both. - -If you call this function using reduced arguments list - "FFTR1DInv(F,A)" -- you must pass FULL array with N elements (although higher N/2 are still -not used) because array size is used to automatically determine FFT length - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinv(const complex_1d_array &f, real_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = f.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fftr1dinv(const_cast(f.c_ptr()), n, const_cast(a.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex convolution. - -For given A/B returns conv(A,B) (non-circular). Subroutine can automatically -choose between three implementations: straightforward O(M*N) formula for -very small N (or M), overlap-add algorithm for cases where max(M,N) is -significantly larger than min(M,N), but O(M*N) algorithm is too slow, and -general FFT-based formula for cases where two previois algorithms are too -slow. - -Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. - -INPUT PARAMETERS - A - array[0..M-1] - complex function to be transformed - M - problem size - B - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convc1d(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length, N<=M - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convc1dinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional circular complex convolution. - -For given S/R returns conv(S,R) (circular). Algorithm has linearithmic -complexity for any M/N. - -IMPORTANT: normal convolution is commutative, i.e. it is symmetric - -conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a -signal, periodic function, and another - R - is a response, non-periodic -function with limited length. - -INPUT PARAMETERS - S - array[0..M-1] - complex periodic signal - M - problem size - B - array[0..N-1] - complex non-periodic response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convc1dcircular(const_cast(s.c_ptr()), m, const_cast(r.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved periodic signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - non-periodic response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-1]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convc1dcircularinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real convolution. - -Analogous to ConvC1D(), see ConvC1D() comments for more details. - -INPUT PARAMETERS - A - array[0..M-1] - real function to be transformed - M - problem size - B - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convr1d(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length, N<=M - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convr1dinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional circular real convolution. - -Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. - -INPUT PARAMETERS - S - array[0..M-1] - real signal - M - problem size - B - array[0..N-1] - real response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convr1dcircular(const_cast(s.c_ptr()), m, const_cast(r.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::convr1dcircularinv(const_cast(a.c_ptr()), m, const_cast(b.c_ptr()), n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(conj(pattern[j])*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::corrc1d(const_cast(signal.c_ptr()), n, const_cast(pattern.c_ptr()), m, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional circular complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::corrc1dcircular(const_cast(signal.c_ptr()), m, const_cast(pattern.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(pattern[j]*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(pattern[j]*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::corrr1d(const_cast(signal.c_ptr()), n, const_cast(pattern.c_ptr()), m, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional circular real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::corrr1dcircular(const_cast(signal.c_ptr()), m, const_cast(pattern.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional Fast Hartley Transform. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - FHT of a input array, array[0..N-1], - A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) - - - -- ALGLIB -- - Copyright 04.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1d(real_1d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fhtr1d(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional inverse FHT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse FHT of a input array, array[0..N-1] - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1dinv(real_1d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fhtr1dinv(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - - - - - - - - - - - -/************************************************************************* -1-dimensional complex FFT. - -Array size N may be arbitrary number (composite or prime). Composite N's -are handled with cache-oblivious variation of a Cooley-Tukey algorithm. -Small prime-factors are transformed using hard coded codelets (similar to -FFTW codelets, but without low-level optimization), large prime-factors -are handled with Bluestein's algorithm. - -Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), -most fast for powers of 2. When N have prime factors larger than these, -but orders of magnitude smaller than N, computations will be about 4 times -slower than for nearby highly composite N's. When N itself is prime, speed -will be 6 times lower. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) -{ - ae_frame _frame_block; - fasttransformplan plan; - ae_int_t i; - ae_vector buf; - - ae_frame_make(_state, &_frame_block); - _fasttransformplan_init(&plan, _state, ae_true); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "FFTC1D: incorrect N!", _state); - ae_assert(a->cnt>=n, "FFTC1D: Length(A)ptr.p_complex[i].x; - buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; - } - - /* - * Generate plan and execute it. - * - * Plan is a combination of a successive factorizations of N and - * precomputed data. It is much like a FFTW plan, but is not stored - * between subroutine calls and is much simpler. - */ - ftcomplexfftplan(n, 1, &plan, _state); - ftapplyplan(&plan, &buf, 0, 1, _state); - - /* - * result - */ - for(i=0; i<=n-1; i++) - { - a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0]; - a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional complex inverse FFT. - -Array size N may be arbitrary number (composite or prime). Algorithm has -O(N*logN) complexity for any N (composite or prime). - -See FFTC1D() description for more information about algorithm performance. - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) -{ - ae_int_t i; - - - ae_assert(n>0, "FFTC1DInv: incorrect N!", _state); - ae_assert(a->cnt>=n, "FFTC1DInv: Length(A)ptr.p_complex[i].y = -a->ptr.p_complex[i].y; - } - fftc1d(a, n, _state); - for(i=0; i<=n-1; i++) - { - a->ptr.p_complex[i].x = a->ptr.p_complex[i].x/n; - a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y/n; - } -} - - -/************************************************************************* -1-dimensional real FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - F - DFT of a input array, array[0..N-1] - F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - -NOTE: - F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half -of array is usually needed. But for convenience subroutine returns full -complex array (with frequencies above N/2), so its result may be used by -other FFT-related subroutines. - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1d(/* Real */ ae_vector* a, - ae_int_t n, - /* Complex */ ae_vector* f, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t n2; - ae_int_t idx; - ae_complex hn; - ae_complex hmnc; - ae_complex v; - ae_vector buf; - fasttransformplan plan; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(f); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - _fasttransformplan_init(&plan, _state, ae_true); - - ae_assert(n>0, "FFTR1D: incorrect N!", _state); - ae_assert(a->cnt>=n, "FFTR1D: Length(A)ptr.p_complex[0] = ae_complex_from_d(a->ptr.p_double[0]); - ae_frame_leave(_state); - return; - } - if( n==2 ) - { - ae_vector_set_length(f, 2, _state); - f->ptr.p_complex[0].x = a->ptr.p_double[0]+a->ptr.p_double[1]; - f->ptr.p_complex[0].y = 0; - f->ptr.p_complex[1].x = a->ptr.p_double[0]-a->ptr.p_double[1]; - f->ptr.p_complex[1].y = 0; - ae_frame_leave(_state); - return; - } - - /* - * Choose between odd-size and even-size FFTs - */ - if( n%2==0 ) - { - - /* - * even-size real FFT, use reduction to the complex task - */ - n2 = n/2; - ae_vector_set_length(&buf, n, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ftcomplexfftplan(n2, 1, &plan, _state); - ftapplyplan(&plan, &buf, 0, 1, _state); - ae_vector_set_length(f, n, _state); - for(i=0; i<=n2; i++) - { - idx = 2*(i%n2); - hn.x = buf.ptr.p_double[idx+0]; - hn.y = buf.ptr.p_double[idx+1]; - idx = 2*((n2-i)%n2); - hmnc.x = buf.ptr.p_double[idx+0]; - hmnc.y = -buf.ptr.p_double[idx+1]; - v.x = -ae_sin(-2*ae_pi*i/n, _state); - v.y = ae_cos(-2*ae_pi*i/n, _state); - f->ptr.p_complex[i] = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); - f->ptr.p_complex[i].x = 0.5*f->ptr.p_complex[i].x; - f->ptr.p_complex[i].y = 0.5*f->ptr.p_complex[i].y; - } - for(i=n2+1; i<=n-1; i++) - { - f->ptr.p_complex[i] = ae_c_conj(f->ptr.p_complex[n-i], _state); - } - } - else - { - - /* - * use complex FFT - */ - ae_vector_set_length(f, n, _state); - for(i=0; i<=n-1; i++) - { - f->ptr.p_complex[i] = ae_complex_from_d(a->ptr.p_double[i]); - } - fftc1d(f, n, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional real inverse FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - F - array[0..floor(N/2)] - frequencies from forward real FFT - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - -NOTE: - F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one -half of frequencies array is needed - elements from 0 to floor(N/2). F[0] -is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then -F[floor(N/2)] has no special properties. - -Relying on properties noted above, FFTR1DInv subroutine uses only elements -from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case -N is even it ignores imaginary part of F[floor(N/2)] too. - -When you call this function using full arguments list - "FFTR1DInv(F,N,A)" -- you can pass either either frequencies array with N elements or reduced -array with roughly N/2 elements - subroutine will successfully transform -both. - -If you call this function using reduced arguments list - "FFTR1DInv(F,A)" -- you must pass FULL array with N elements (although higher N/2 are still -not used) because array size is used to automatically determine FFT length - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinv(/* Complex */ ae_vector* f, - ae_int_t n, - /* Real */ ae_vector* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector h; - ae_vector fh; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(a); - ae_vector_init(&h, 0, DT_REAL, _state, ae_true); - ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0, "FFTR1DInv: incorrect N!", _state); - ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInv: Length(F)ptr.p_complex[0].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); - for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) - { - ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); - } - ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); - if( n%2!=0 ) - { - ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); - } - - /* - * Special case: N=1, FFT is just identity transform. - * After this block we assume that N is strictly greater than 1. - */ - if( n==1 ) - { - ae_vector_set_length(a, 1, _state); - a->ptr.p_double[0] = f->ptr.p_complex[0].x; - ae_frame_leave(_state); - return; - } - - /* - * inverse real FFT is reduced to the inverse real FHT, - * which is reduced to the forward real FHT, - * which is reduced to the forward real FFT. - * - * Don't worry, it is really compact and efficient reduction :) - */ - ae_vector_set_length(&h, n, _state); - ae_vector_set_length(a, n, _state); - h.ptr.p_double[0] = f->ptr.p_complex[0].x; - for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) - { - h.ptr.p_double[i] = f->ptr.p_complex[i].x-f->ptr.p_complex[i].y; - h.ptr.p_double[n-i] = f->ptr.p_complex[i].x+f->ptr.p_complex[i].y; - } - if( n%2==0 ) - { - h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x; - } - else - { - h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x-f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; - h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)+1] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x+f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; - } - fftr1d(&h, n, &fh, _state); - for(i=0; i<=n-1; i++) - { - a->ptr.p_double[i] = (fh.ptr.p_complex[i].x-fh.ptr.p_complex[i].y)/n; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Never call it directly! - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinternaleven(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* buf, - fasttransformplan* plan, - ae_state *_state) -{ - double x; - double y; - ae_int_t i; - ae_int_t n2; - ae_int_t idx; - ae_complex hn; - ae_complex hmnc; - ae_complex v; - - - ae_assert(n>0&&n%2==0, "FFTR1DEvenInplace: incorrect N!", _state); - - /* - * Special cases: - * * N=2 - * - * After this block we assume that N is strictly greater than 2 - */ - if( n==2 ) - { - x = a->ptr.p_double[0]+a->ptr.p_double[1]; - y = a->ptr.p_double[0]-a->ptr.p_double[1]; - a->ptr.p_double[0] = x; - a->ptr.p_double[1] = y; - return; - } - - /* - * even-size real FFT, use reduction to the complex task - */ - n2 = n/2; - ae_v_move(&buf->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ftapplyplan(plan, buf, 0, 1, _state); - a->ptr.p_double[0] = buf->ptr.p_double[0]+buf->ptr.p_double[1]; - for(i=1; i<=n2-1; i++) - { - idx = 2*(i%n2); - hn.x = buf->ptr.p_double[idx+0]; - hn.y = buf->ptr.p_double[idx+1]; - idx = 2*(n2-i); - hmnc.x = buf->ptr.p_double[idx+0]; - hmnc.y = -buf->ptr.p_double[idx+1]; - v.x = -ae_sin(-2*ae_pi*i/n, _state); - v.y = ae_cos(-2*ae_pi*i/n, _state); - v = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); - a->ptr.p_double[2*i+0] = 0.5*v.x; - a->ptr.p_double[2*i+1] = 0.5*v.y; - } - a->ptr.p_double[1] = buf->ptr.p_double[0]-buf->ptr.p_double[1]; -} - - -/************************************************************************* -Internal subroutine. Never call it directly! - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinvinternaleven(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* buf, - fasttransformplan* plan, - ae_state *_state) -{ - double x; - double y; - double t; - ae_int_t i; - ae_int_t n2; - - - ae_assert(n>0&&n%2==0, "FFTR1DInvInternalEven: incorrect N!", _state); - - /* - * Special cases: - * * N=2 - * - * After this block we assume that N is strictly greater than 2 - */ - if( n==2 ) - { - x = 0.5*(a->ptr.p_double[0]+a->ptr.p_double[1]); - y = 0.5*(a->ptr.p_double[0]-a->ptr.p_double[1]); - a->ptr.p_double[0] = x; - a->ptr.p_double[1] = y; - return; - } - - /* - * inverse real FFT is reduced to the inverse real FHT, - * which is reduced to the forward real FHT, - * which is reduced to the forward real FFT. - * - * Don't worry, it is really compact and efficient reduction :) - */ - n2 = n/2; - buf->ptr.p_double[0] = a->ptr.p_double[0]; - for(i=1; i<=n2-1; i++) - { - x = a->ptr.p_double[2*i+0]; - y = a->ptr.p_double[2*i+1]; - buf->ptr.p_double[i] = x-y; - buf->ptr.p_double[n-i] = x+y; - } - buf->ptr.p_double[n2] = a->ptr.p_double[1]; - fftr1dinternaleven(buf, n, a, plan, _state); - a->ptr.p_double[0] = buf->ptr.p_double[0]/n; - t = (double)1/(double)n; - for(i=1; i<=n2-1; i++) - { - x = buf->ptr.p_double[2*i+0]; - y = buf->ptr.p_double[2*i+1]; - a->ptr.p_double[i] = t*(x-y); - a->ptr.p_double[n-i] = t*(x+y); - } - a->ptr.p_double[n2] = buf->ptr.p_double[1]/n; -} - - - - -/************************************************************************* -1-dimensional complex convolution. - -For given A/B returns conv(A,B) (non-circular). Subroutine can automatically -choose between three implementations: straightforward O(M*N) formula for -very small N (or M), overlap-add algorithm for cases where max(M,N) is -significantly larger than min(M,N), but O(M*N) algorithm is too slow, and -general FFT-based formula for cases where two previois algorithms are too -slow. - -Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. - -INPUT PARAMETERS - A - array[0..M-1] - complex function to be transformed - M - problem size - B - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1d(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Complex */ ae_vector* r, - ae_state *_state) -{ - - ae_vector_clear(r); - - ae_assert(n>0&&m>0, "ConvC1D: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer that B. - */ - if( m0&&m>0)&&n<=m, "ConvC1DInv: incorrect N or M!", _state); - p = ftbasefindsmooth(m, _state); - ftcomplexfftplan(p, 1, &plan, _state); - ae_vector_set_length(&buf, 2*p, _state); - for(i=0; i<=m-1; i++) - { - buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; - buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; - } - for(i=m; i<=p-1; i++) - { - buf.ptr.p_double[2*i+0] = 0; - buf.ptr.p_double[2*i+1] = 0; - } - ae_vector_set_length(&buf2, 2*p, _state); - for(i=0; i<=n-1; i++) - { - buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; - buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; - } - for(i=n; i<=p-1; i++) - { - buf2.ptr.p_double[2*i+0] = 0; - buf2.ptr.p_double[2*i+1] = 0; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - ftapplyplan(&plan, &buf2, 0, 1, _state); - for(i=0; i<=p-1; i++) - { - c1.x = buf.ptr.p_double[2*i+0]; - c1.y = buf.ptr.p_double[2*i+1]; - c2.x = buf2.ptr.p_double[2*i+0]; - c2.y = buf2.ptr.p_double[2*i+1]; - c3 = ae_c_div(c1,c2); - buf.ptr.p_double[2*i+0] = c3.x; - buf.ptr.p_double[2*i+1] = -c3.y; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - t = (double)1/(double)p; - ae_vector_set_length(r, m-n+1, _state); - for(i=0; i<=m-n; i++) - { - r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional circular complex convolution. - -For given S/R returns conv(S,R) (circular). Algorithm has linearithmic -complexity for any M/N. - -IMPORTANT: normal convolution is commutative, i.e. it is symmetric - -conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a -signal, periodic function, and another - R - is a response, non-periodic -function with limited length. - -INPUT PARAMETERS - S - array[0..M-1] - complex periodic signal - M - problem size - B - array[0..N-1] - complex non-periodic response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircular(/* Complex */ ae_vector* s, - ae_int_t m, - /* Complex */ ae_vector* r, - ae_int_t n, - /* Complex */ ae_vector* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector buf; - ae_int_t i1; - ae_int_t i2; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(c); - ae_vector_init(&buf, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); - i1 = i1+m; - } - convc1dcircular(s, m, &buf, m, c, _state); - ae_frame_leave(_state); - return; - } - convc1dx(s, m, r, n, ae_true, -1, 0, c, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved periodic signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - non-periodic response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-1]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircularinv(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Complex */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t i1; - ae_int_t i2; - ae_int_t j2; - ae_vector buf; - ae_vector buf2; - ae_vector cbuf; - fasttransformplan plan; - ae_complex c1; - ae_complex c2; - ae_complex c3; - double t; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true); - _fasttransformplan_init(&plan, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); - i1 = i1+m; - } - convc1dcircularinv(a, m, &cbuf, m, r, _state); - ae_frame_leave(_state); - return; - } - - /* - * Task is normalized - */ - ftcomplexfftplan(m, 1, &plan, _state); - ae_vector_set_length(&buf, 2*m, _state); - for(i=0; i<=m-1; i++) - { - buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; - buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; - } - ae_vector_set_length(&buf2, 2*m, _state); - for(i=0; i<=n-1; i++) - { - buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; - buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; - } - for(i=n; i<=m-1; i++) - { - buf2.ptr.p_double[2*i+0] = 0; - buf2.ptr.p_double[2*i+1] = 0; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - ftapplyplan(&plan, &buf2, 0, 1, _state); - for(i=0; i<=m-1; i++) - { - c1.x = buf.ptr.p_double[2*i+0]; - c1.y = buf.ptr.p_double[2*i+1]; - c2.x = buf2.ptr.p_double[2*i+0]; - c2.y = buf2.ptr.p_double[2*i+1]; - c3 = ae_c_div(c1,c2); - buf.ptr.p_double[2*i+0] = c3.x; - buf.ptr.p_double[2*i+1] = -c3.y; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - t = (double)1/(double)m; - ae_vector_set_length(r, m, _state); - for(i=0; i<=m-1; i++) - { - r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional real convolution. - -Analogous to ConvC1D(), see ConvC1D() comments for more details. - -INPUT PARAMETERS - A - array[0..M-1] - real function to be transformed - M - problem size - B - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1d(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* r, - ae_state *_state) -{ - - ae_vector_clear(r); - - ae_assert(n>0&&m>0, "ConvR1D: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer that B. - */ - if( m0&&m>0)&&n<=m, "ConvR1DInv: incorrect N or M!", _state); - p = ftbasefindsmootheven(m, _state); - ae_vector_set_length(&buf, p, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); - for(i=m; i<=p-1; i++) - { - buf.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf2, p, _state); - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=n; i<=p-1; i++) - { - buf2.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf3, p, _state); - ftcomplexfftplan(p/2, 1, &plan, _state); - fftr1dinternaleven(&buf, p, &buf3, &plan, _state); - fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); - buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; - buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; - for(i=1; i<=p/2-1; i++) - { - c1.x = buf.ptr.p_double[2*i+0]; - c1.y = buf.ptr.p_double[2*i+1]; - c2.x = buf2.ptr.p_double[2*i+0]; - c2.y = buf2.ptr.p_double[2*i+1]; - c3 = ae_c_div(c1,c2); - buf.ptr.p_double[2*i+0] = c3.x; - buf.ptr.p_double[2*i+1] = c3.y; - } - fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); - ae_vector_set_length(r, m-n+1, _state); - ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-n)); - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional circular real convolution. - -Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. - -INPUT PARAMETERS - S - array[0..M-1] - real signal - M - problem size - B - array[0..N-1] - real response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircular(/* Real */ ae_vector* s, - ae_int_t m, - /* Real */ ae_vector* r, - ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector buf; - ae_int_t i1; - ae_int_t i2; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(c); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_double[i1], 1, ae_v_len(0,j2)); - i1 = i1+m; - } - convr1dcircular(s, m, &buf, m, c, _state); - ae_frame_leave(_state); - return; - } - - /* - * reduce to usual convolution - */ - convr1dx(s, m, r, n, ae_true, -1, 0, c, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional complex deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircularinv(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t i1; - ae_int_t i2; - ae_int_t j2; - ae_vector buf; - ae_vector buf2; - ae_vector buf3; - ae_vector cbuf; - ae_vector cbuf2; - fasttransformplan plan; - ae_complex c1; - ae_complex c2; - ae_complex c3; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cbuf2, 0, DT_COMPLEX, _state, ae_true); - _fasttransformplan_init(&plan, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_double[i1], 1, ae_v_len(0,j2)); - i1 = i1+m; - } - convr1dcircularinv(a, m, &buf, m, r, _state); - ae_frame_leave(_state); - return; - } - - /* - * Task is normalized - */ - if( m%2==0 ) - { - - /* - * size is even, use fast even-size FFT - */ - ae_vector_set_length(&buf, m, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_vector_set_length(&buf2, m, _state); - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=n; i<=m-1; i++) - { - buf2.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf3, m, _state); - ftcomplexfftplan(m/2, 1, &plan, _state); - fftr1dinternaleven(&buf, m, &buf3, &plan, _state); - fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); - buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; - buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; - for(i=1; i<=m/2-1; i++) - { - c1.x = buf.ptr.p_double[2*i+0]; - c1.y = buf.ptr.p_double[2*i+1]; - c2.x = buf2.ptr.p_double[2*i+0]; - c2.y = buf2.ptr.p_double[2*i+1]; - c3 = ae_c_div(c1,c2); - buf.ptr.p_double[2*i+0] = c3.x; - buf.ptr.p_double[2*i+1] = c3.y; - } - fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); - ae_vector_set_length(r, m, _state); - ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - else - { - - /* - * odd-size, use general real FFT - */ - fftr1d(a, m, &cbuf, _state); - ae_vector_set_length(&buf2, m, _state); - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=n; i<=m-1; i++) - { - buf2.ptr.p_double[i] = 0; - } - fftr1d(&buf2, m, &cbuf2, _state); - for(i=0; i<=ae_ifloor((double)m/(double)2, _state); i++) - { - cbuf.ptr.p_complex[i] = ae_c_div(cbuf.ptr.p_complex[i],cbuf2.ptr.p_complex[i]); - } - fftr1dinv(&cbuf, m, r, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional complex convolution. - -Extended subroutine which allows to choose convolution algorithm. -Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular(). - -INPUT PARAMETERS - A - array[0..M-1] - complex function to be transformed - M - problem size - B - array[0..N-1] - complex function to be transformed - N - problem size, N<=M - Alg - algorithm type: - *-2 auto-select Q for overlap-add - *-1 auto-select algorithm and parameters - * 0 straightforward formula for small N's - * 1 general FFT-based code - * 2 overlap-add with length Q - Q - length for overlap-add - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-1]. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dx(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - ae_bool circular, - ae_int_t alg, - ae_int_t q, - /* Complex */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t p; - ae_int_t ptotal; - ae_int_t i1; - ae_int_t i2; - ae_int_t j1; - ae_int_t j2; - ae_vector bbuf; - ae_complex v; - double ax; - double ay; - double bx; - double by; - double t; - double tx; - double ty; - double flopcand; - double flopbest; - ae_int_t algbest; - fasttransformplan plan; - ae_vector buf; - ae_vector buf2; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - ae_vector_init(&bbuf, 0, DT_COMPLEX, _state, ae_true); - _fasttransformplan_init(&plan, _state, ae_true); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state); - ae_assert(n<=m, "ConvC1DX: Nptr.p_complex[0]; - ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); - ae_frame_leave(_state); - return; - } - - /* - * use straightforward formula - */ - if( circular ) - { - - /* - * circular convolution - */ - ae_vector_set_length(r, m, _state); - v = b->ptr.p_complex[0]; - ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); - for(i=1; i<=n-1; i++) - { - v = b->ptr.p_complex[i]; - i1 = 0; - i2 = i-1; - j1 = m-i; - j2 = m-1; - ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); - i1 = i; - i2 = m-1; - j1 = 0; - j2 = m-i-1; - ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); - } - } - else - { - - /* - * non-circular convolution - */ - ae_vector_set_length(r, m+n-1, _state); - for(i=0; i<=m+n-2; i++) - { - r->ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=0; i<=n-1; i++) - { - v = b->ptr.p_complex[i]; - ae_v_caddc(&r->ptr.p_complex[i], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(i,i+m-1), v); - } - } - ae_frame_leave(_state); - return; - } - - /* - * general FFT-based code for - * circular and non-circular convolutions. - * - * First, if convolution is circular, we test whether M is smooth or not. - * If it is smooth, we just use M-length FFT to calculate convolution. - * If it is not, we calculate non-circular convolution and wrap it arount. - * - * IF convolution is non-circular, we use zero-padding + FFT. - */ - if( alg==1 ) - { - if( circular&&ftbaseissmooth(m, _state) ) - { - - /* - * special code for circular convolution with smooth M - */ - ftcomplexfftplan(m, 1, &plan, _state); - ae_vector_set_length(&buf, 2*m, _state); - for(i=0; i<=m-1; i++) - { - buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; - buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; - } - ae_vector_set_length(&buf2, 2*m, _state); - for(i=0; i<=n-1; i++) - { - buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; - buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; - } - for(i=n; i<=m-1; i++) - { - buf2.ptr.p_double[2*i+0] = 0; - buf2.ptr.p_double[2*i+1] = 0; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - ftapplyplan(&plan, &buf2, 0, 1, _state); - for(i=0; i<=m-1; i++) - { - ax = buf.ptr.p_double[2*i+0]; - ay = buf.ptr.p_double[2*i+1]; - bx = buf2.ptr.p_double[2*i+0]; - by = buf2.ptr.p_double[2*i+1]; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*i+0] = tx; - buf.ptr.p_double[2*i+1] = -ty; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - t = (double)1/(double)m; - ae_vector_set_length(r, m, _state); - for(i=0; i<=m-1; i++) - { - r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; - } - } - else - { - - /* - * M is non-smooth, general code (circular/non-circular): - * * first part is the same for circular and non-circular - * convolutions. zero padding, FFTs, inverse FFTs - * * second part differs: - * * for non-circular convolution we just copy array - * * for circular convolution we add array tail to its head - */ - p = ftbasefindsmooth(m+n-1, _state); - ftcomplexfftplan(p, 1, &plan, _state); - ae_vector_set_length(&buf, 2*p, _state); - for(i=0; i<=m-1; i++) - { - buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; - buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; - } - for(i=m; i<=p-1; i++) - { - buf.ptr.p_double[2*i+0] = 0; - buf.ptr.p_double[2*i+1] = 0; - } - ae_vector_set_length(&buf2, 2*p, _state); - for(i=0; i<=n-1; i++) - { - buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; - buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; - } - for(i=n; i<=p-1; i++) - { - buf2.ptr.p_double[2*i+0] = 0; - buf2.ptr.p_double[2*i+1] = 0; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - ftapplyplan(&plan, &buf2, 0, 1, _state); - for(i=0; i<=p-1; i++) - { - ax = buf.ptr.p_double[2*i+0]; - ay = buf.ptr.p_double[2*i+1]; - bx = buf2.ptr.p_double[2*i+0]; - by = buf2.ptr.p_double[2*i+1]; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*i+0] = tx; - buf.ptr.p_double[2*i+1] = -ty; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - t = (double)1/(double)p; - if( circular ) - { - - /* - * circular, add tail to head - */ - ae_vector_set_length(r, m, _state); - for(i=0; i<=m-1; i++) - { - r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; - } - for(i=m; i<=m+n-2; i++) - { - r->ptr.p_complex[i-m].x = r->ptr.p_complex[i-m].x+t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i-m].y = r->ptr.p_complex[i-m].y-t*buf.ptr.p_double[2*i+1]; - } - } - else - { - - /* - * non-circular, just copy - */ - ae_vector_set_length(r, m+n-1, _state); - for(i=0; i<=m+n-2; i++) - { - r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; - r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * overlap-add method for - * circular and non-circular convolutions. - * - * First part of code (separate FFTs of input blocks) is the same - * for all types of convolution. Second part (overlapping outputs) - * differs for different types of convolution. We just copy output - * when convolution is non-circular. We wrap it around, if it is - * circular. - */ - if( alg==2 ) - { - ae_vector_set_length(&buf, 2*(q+n-1), _state); - - /* - * prepare R - */ - if( circular ) - { - ae_vector_set_length(r, m, _state); - for(i=0; i<=m-1; i++) - { - r->ptr.p_complex[i] = ae_complex_from_d(0); - } - } - else - { - ae_vector_set_length(r, m+n-1, _state); - for(i=0; i<=m+n-2; i++) - { - r->ptr.p_complex[i] = ae_complex_from_d(0); - } - } - - /* - * pre-calculated FFT(B) - */ - ae_vector_set_length(&bbuf, q+n-1, _state); - ae_v_cmove(&bbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - for(j=n; j<=q+n-2; j++) - { - bbuf.ptr.p_complex[j] = ae_complex_from_d(0); - } - fftc1d(&bbuf, q+n-1, _state); - - /* - * prepare FFT plan for chunks of A - */ - ftcomplexfftplan(q+n-1, 1, &plan, _state); - - /* - * main overlap-add cycle - */ - i = 0; - while(i<=m-1) - { - p = ae_minint(q, m-i, _state); - for(j=0; j<=p-1; j++) - { - buf.ptr.p_double[2*j+0] = a->ptr.p_complex[i+j].x; - buf.ptr.p_double[2*j+1] = a->ptr.p_complex[i+j].y; - } - for(j=p; j<=q+n-2; j++) - { - buf.ptr.p_double[2*j+0] = 0; - buf.ptr.p_double[2*j+1] = 0; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - for(j=0; j<=q+n-2; j++) - { - ax = buf.ptr.p_double[2*j+0]; - ay = buf.ptr.p_double[2*j+1]; - bx = bbuf.ptr.p_complex[j].x; - by = bbuf.ptr.p_complex[j].y; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*j+0] = tx; - buf.ptr.p_double[2*j+1] = -ty; - } - ftapplyplan(&plan, &buf, 0, 1, _state); - t = (double)1/(double)(q+n-1); - if( circular ) - { - j1 = ae_minint(i+p+n-2, m-1, _state)-i; - j2 = j1+1; - } - else - { - j1 = p+n-2; - j2 = j1+1; - } - for(j=0; j<=j1; j++) - { - r->ptr.p_complex[i+j].x = r->ptr.p_complex[i+j].x+buf.ptr.p_double[2*j+0]*t; - r->ptr.p_complex[i+j].y = r->ptr.p_complex[i+j].y-buf.ptr.p_double[2*j+1]*t; - } - for(j=j2; j<=p+n-2; j++) - { - r->ptr.p_complex[j-j2].x = r->ptr.p_complex[j-j2].x+buf.ptr.p_double[2*j+0]*t; - r->ptr.p_complex[j-j2].y = r->ptr.p_complex[j-j2].y-buf.ptr.p_double[2*j+1]*t; - } - i = i+p; - } - ae_frame_leave(_state); - return; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional real convolution. - -Extended subroutine which allows to choose convolution algorithm. -Intended for internal use, ALGLIB users should call ConvR1D(). - -INPUT PARAMETERS - A - array[0..M-1] - complex function to be transformed - M - problem size - B - array[0..N-1] - complex function to be transformed - N - problem size, N<=M - Alg - algorithm type: - *-2 auto-select Q for overlap-add - *-1 auto-select algorithm and parameters - * 0 straightforward formula for small N's - * 1 general FFT-based code - * 2 overlap-add with length Q - Q - length for overlap-add - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-1]. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dx(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - ae_bool circular, - ae_int_t alg, - ae_int_t q, - /* Real */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - double v; - ae_int_t i; - ae_int_t j; - ae_int_t p; - ae_int_t ptotal; - ae_int_t i1; - ae_int_t i2; - ae_int_t j1; - ae_int_t j2; - double ax; - double ay; - double bx; - double by; - double tx; - double ty; - double flopcand; - double flopbest; - ae_int_t algbest; - fasttransformplan plan; - ae_vector buf; - ae_vector buf2; - ae_vector buf3; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - _fasttransformplan_init(&plan, _state, ae_true); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state); - ae_assert(n<=m, "ConvC1DX: Nptr.p_double[0]; - ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); - ae_frame_leave(_state); - return; - } - - /* - * use straightforward formula - */ - if( circular ) - { - - /* - * circular convolution - */ - ae_vector_set_length(r, m, _state); - v = b->ptr.p_double[0]; - ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); - for(i=1; i<=n-1; i++) - { - v = b->ptr.p_double[i]; - i1 = 0; - i2 = i-1; - j1 = m-i; - j2 = m-1; - ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); - i1 = i; - i2 = m-1; - j1 = 0; - j2 = m-i-1; - ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); - } - } - else - { - - /* - * non-circular convolution - */ - ae_vector_set_length(r, m+n-1, _state); - for(i=0; i<=m+n-2; i++) - { - r->ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = b->ptr.p_double[i]; - ae_v_addd(&r->ptr.p_double[i], 1, &a->ptr.p_double[0], 1, ae_v_len(i,i+m-1), v); - } - } - ae_frame_leave(_state); - return; - } - - /* - * general FFT-based code for - * circular and non-circular convolutions. - * - * First, if convolution is circular, we test whether M is smooth or not. - * If it is smooth, we just use M-length FFT to calculate convolution. - * If it is not, we calculate non-circular convolution and wrap it arount. - * - * If convolution is non-circular, we use zero-padding + FFT. - * - * We assume that M+N-1>2 - we should call small case code otherwise - */ - if( alg==1 ) - { - ae_assert(m+n-1>2, "ConvR1DX: internal error!", _state); - if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 ) - { - - /* - * special code for circular convolution with smooth even M - */ - ae_vector_set_length(&buf, m, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_vector_set_length(&buf2, m, _state); - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=n; i<=m-1; i++) - { - buf2.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf3, m, _state); - ftcomplexfftplan(m/2, 1, &plan, _state); - fftr1dinternaleven(&buf, m, &buf3, &plan, _state); - fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); - buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; - buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; - for(i=1; i<=m/2-1; i++) - { - ax = buf.ptr.p_double[2*i+0]; - ay = buf.ptr.p_double[2*i+1]; - bx = buf2.ptr.p_double[2*i+0]; - by = buf2.ptr.p_double[2*i+1]; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*i+0] = tx; - buf.ptr.p_double[2*i+1] = ty; - } - fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); - ae_vector_set_length(r, m, _state); - ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - else - { - - /* - * M is non-smooth or non-even, general code (circular/non-circular): - * * first part is the same for circular and non-circular - * convolutions. zero padding, FFTs, inverse FFTs - * * second part differs: - * * for non-circular convolution we just copy array - * * for circular convolution we add array tail to its head - */ - p = ftbasefindsmootheven(m+n-1, _state); - ae_vector_set_length(&buf, p, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); - for(i=m; i<=p-1; i++) - { - buf.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf2, p, _state); - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=n; i<=p-1; i++) - { - buf2.ptr.p_double[i] = 0; - } - ae_vector_set_length(&buf3, p, _state); - ftcomplexfftplan(p/2, 1, &plan, _state); - fftr1dinternaleven(&buf, p, &buf3, &plan, _state); - fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); - buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; - buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; - for(i=1; i<=p/2-1; i++) - { - ax = buf.ptr.p_double[2*i+0]; - ay = buf.ptr.p_double[2*i+1]; - bx = buf2.ptr.p_double[2*i+0]; - by = buf2.ptr.p_double[2*i+1]; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*i+0] = tx; - buf.ptr.p_double[2*i+1] = ty; - } - fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); - if( circular ) - { - - /* - * circular, add tail to head - */ - ae_vector_set_length(r, m, _state); - ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); - if( n>=2 ) - { - ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[m], 1, ae_v_len(0,n-2)); - } - } - else - { - - /* - * non-circular, just copy - */ - ae_vector_set_length(r, m+n-1, _state); - ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m+n-2)); - } - } - ae_frame_leave(_state); - return; - } - - /* - * overlap-add method - */ - if( alg==2 ) - { - ae_assert((q+n-1)%2==0, "ConvR1DX: internal error!", _state); - ae_vector_set_length(&buf, q+n-1, _state); - ae_vector_set_length(&buf2, q+n-1, _state); - ae_vector_set_length(&buf3, q+n-1, _state); - ftcomplexfftplan((q+n-1)/2, 1, &plan, _state); - - /* - * prepare R - */ - if( circular ) - { - ae_vector_set_length(r, m, _state); - for(i=0; i<=m-1; i++) - { - r->ptr.p_double[i] = 0; - } - } - else - { - ae_vector_set_length(r, m+n-1, _state); - for(i=0; i<=m+n-2; i++) - { - r->ptr.p_double[i] = 0; - } - } - - /* - * pre-calculated FFT(B) - */ - ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(j=n; j<=q+n-2; j++) - { - buf2.ptr.p_double[j] = 0; - } - fftr1dinternaleven(&buf2, q+n-1, &buf3, &plan, _state); - - /* - * main overlap-add cycle - */ - i = 0; - while(i<=m-1) - { - p = ae_minint(q, m-i, _state); - ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[i], 1, ae_v_len(0,p-1)); - for(j=p; j<=q+n-2; j++) - { - buf.ptr.p_double[j] = 0; - } - fftr1dinternaleven(&buf, q+n-1, &buf3, &plan, _state); - buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; - buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; - for(j=1; j<=(q+n-1)/2-1; j++) - { - ax = buf.ptr.p_double[2*j+0]; - ay = buf.ptr.p_double[2*j+1]; - bx = buf2.ptr.p_double[2*j+0]; - by = buf2.ptr.p_double[2*j+1]; - tx = ax*bx-ay*by; - ty = ax*by+ay*bx; - buf.ptr.p_double[2*j+0] = tx; - buf.ptr.p_double[2*j+1] = ty; - } - fftr1dinvinternaleven(&buf, q+n-1, &buf3, &plan, _state); - if( circular ) - { - j1 = ae_minint(i+p+n-2, m-1, _state)-i; - j2 = j1+1; - } - else - { - j1 = p+n-2; - j2 = j1+1; - } - ae_v_add(&r->ptr.p_double[i], 1, &buf.ptr.p_double[0], 1, ae_v_len(i,i+j1)); - if( p+n-2>=j2 ) - { - ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[j2], 1, ae_v_len(0,p+n-2-j2)); - } - i = i+p; - } - ae_frame_leave(_state); - return; - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -1-dimensional complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(conj(pattern[j])*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1d(/* Complex */ ae_vector* signal, - ae_int_t n, - /* Complex */ ae_vector* pattern, - ae_int_t m, - /* Complex */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector p; - ae_vector b; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0&&m>0, "CorrC1D: incorrect N or M!", _state); - ae_vector_set_length(&p, m, _state); - for(i=0; i<=m-1; i++) - { - p.ptr.p_complex[m-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); - } - convc1d(&p, m, signal, n, &b, _state); - ae_vector_set_length(r, m+n-1, _state); - ae_v_cmove(&r->ptr.p_complex[0], 1, &b.ptr.p_complex[m-1], 1, "N", ae_v_len(0,n-1)); - if( m+n-2>=n ) - { - ae_v_cmove(&r->ptr.p_complex[n], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(n,m+n-2)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional circular complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1dcircular(/* Complex */ ae_vector* signal, - ae_int_t m, - /* Complex */ ae_vector* pattern, - ae_int_t n, - /* Complex */ ae_vector* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector p; - ae_vector b; - ae_int_t i1; - ae_int_t i2; - ae_int_t i; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(c); - ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); - i1 = i1+m; - } - corrc1dcircular(signal, m, &b, m, c, _state); - ae_frame_leave(_state); - return; - } - - /* - * Task is normalized - */ - ae_vector_set_length(&p, n, _state); - for(i=0; i<=n-1; i++) - { - p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); - } - convc1dcircular(signal, m, &p, n, &b, _state); - ae_vector_set_length(c, m, _state); - ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n)); - if( m-n+1<=m-1 ) - { - ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(pattern[j]*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(pattern[j]*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1d(/* Real */ ae_vector* signal, - ae_int_t n, - /* Real */ ae_vector* pattern, - ae_int_t m, - /* Real */ ae_vector* r, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector p; - ae_vector b; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - ae_vector_init(&p, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0&&m>0, "CorrR1D: incorrect N or M!", _state); - ae_vector_set_length(&p, m, _state); - for(i=0; i<=m-1; i++) - { - p.ptr.p_double[m-1-i] = pattern->ptr.p_double[i]; - } - convr1d(&p, m, signal, n, &b, _state); - ae_vector_set_length(r, m+n-1, _state); - ae_v_move(&r->ptr.p_double[0], 1, &b.ptr.p_double[m-1], 1, ae_v_len(0,n-1)); - if( m+n-2>=n ) - { - ae_v_move(&r->ptr.p_double[n], 1, &b.ptr.p_double[0], 1, ae_v_len(n,m+n-2)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional circular real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1dcircular(/* Real */ ae_vector* signal, - ae_int_t m, - /* Real */ ae_vector* pattern, - ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector p; - ae_vector b; - ae_int_t i1; - ae_int_t i2; - ae_int_t i; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(c); - ae_vector_init(&p, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); - - /* - * normalize task: make M>=N, - * so A will be longer (at least - not shorter) that B. - */ - if( mptr.p_double[i1], 1, ae_v_len(0,j2)); - i1 = i1+m; - } - corrr1dcircular(signal, m, &b, m, c, _state); - ae_frame_leave(_state); - return; - } - - /* - * Task is normalized - */ - ae_vector_set_length(&p, n, _state); - for(i=0; i<=n-1; i++) - { - p.ptr.p_double[n-1-i] = pattern->ptr.p_double[i]; - } - convr1dcircular(signal, m, &p, n, &b, _state); - ae_vector_set_length(c, m, _state); - ae_v_move(&c->ptr.p_double[0], 1, &b.ptr.p_double[n-1], 1, ae_v_len(0,m-n)); - if( m-n+1<=m-1 ) - { - ae_v_move(&c->ptr.p_double[m-n+1], 1, &b.ptr.p_double[0], 1, ae_v_len(m-n+1,m-1)); - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -1-dimensional Fast Hartley Transform. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - FHT of a input array, array[0..N-1], - A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) - - - -- ALGLIB -- - Copyright 04.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector fa; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&fa, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0, "FHTR1D: incorrect N!", _state); - - /* - * Special case: N=1, FHT is just identity transform. - * After this block we assume that N is strictly greater than 1. - */ - if( n==1 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Reduce FHt to real FFT - */ - fftr1d(a, n, &fa, _state); - for(i=0; i<=n-1; i++) - { - a->ptr.p_double[i] = fa.ptr.p_complex[i].x-fa.ptr.p_complex[i].y; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -1-dimensional inverse FHT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse FHT of a input array, array[0..N-1] - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) -{ - ae_int_t i; - - - ae_assert(n>0, "FHTR1DInv: incorrect N!", _state); - - /* - * Special case: N=1, iFHT is just identity transform. - * After this block we assume that N is strictly greater than 1. - */ - if( n==1 ) - { - return; - } - - /* - * Inverse FHT can be expressed in terms of the FHT as - * - * invfht(x) = fht(x)/N - */ - fhtr1d(a, n, _state); - for(i=0; i<=n-1; i++) - { - a->ptr.p_double[i] = a->ptr.p_double[i]/n; - } -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "fasttransforms.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex FFT. + +Array size N may be arbitrary number (composite or prime). Composite N's +are handled with cache-oblivious variation of a Cooley-Tukey algorithm. +Small prime-factors are transformed using hard coded codelets (similar to +FFTW codelets, but without low-level optimization), large prime-factors +are handled with Bluestein's algorithm. + +Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), +most fast for powers of 2. When N have prime factors larger than these, +but orders of magnitude smaller than N, computations will be about 4 times +slower than for nearby highly composite N's. When N itself is prime, speed +will be 6 times lower. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1d(complex_1d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex FFT. + +Array size N may be arbitrary number (composite or prime). Composite N's +are handled with cache-oblivious variation of a Cooley-Tukey algorithm. +Small prime-factors are transformed using hard coded codelets (similar to +FFTW codelets, but without low-level optimization), large prime-factors +are handled with Bluestein's algorithm. + +Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), +most fast for powers of 2. When N have prime factors larger than these, +but orders of magnitude smaller than N, computations will be about 4 times +slower than for nearby highly composite N's. When N itself is prime, speed +will be 6 times lower. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftc1d(complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = a.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +1-dimensional complex inverse FFT. + +Array size N may be arbitrary number (composite or prime). Algorithm has +O(N*logN) complexity for any N (composite or prime). + +See FFTC1D() description for more information about algorithm performance. + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1dinv(complex_1d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex inverse FFT. + +Array size N may be arbitrary number (composite or prime). Algorithm has +O(N*logN) complexity for any N (composite or prime). + +See FFTC1D() description for more information about algorithm performance. + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftc1dinv(complex_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = a.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +1-dimensional real FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + F - DFT of a input array, array[0..N-1] + F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + +NOTE: there is a buffered version of this function, FFTR1DBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half +of array is usually needed. But for convinience subroutine returns full +complex array (with frequencies above N/2), so its result may be used by +other FFT-related subroutines. + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + F - DFT of a input array, array[0..N-1] + F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + +NOTE: there is a buffered version of this function, FFTR1DBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half +of array is usually needed. But for convinience subroutine returns full +complex array (with frequencies above N/2), so its result may be used by +other FFT-related subroutines. + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftr1d(const real_1d_array &a, complex_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = a.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +1-dimensional real FFT, a buffered function which does not reallocate F[] +if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dbuf(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real FFT, a buffered function which does not reallocate F[] +if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftr1dbuf(const real_1d_array &a, complex_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = a.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +1-dimensional real inverse FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + F - array[0..floor(N/2)] - frequencies from forward real FFT + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + +NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one +half of frequencies array is needed - elements from 0 to floor(N/2). F[0] +is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then +F[floor(N/2)] has no special properties. + +Relying on properties noted above, FFTR1DInv subroutine uses only elements +from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case +N is even it ignores imaginary part of F[floor(N/2)] too. + +When you call this function using full arguments list - "FFTR1DInv(F,N,A)" +- you can pass either either frequencies array with N elements or reduced +array with roughly N/2 elements - subroutine will successfully transform +both. + +If you call this function using reduced arguments list - "FFTR1DInv(F,A)" +- you must pass FULL array with N elements (although higher N/2 are still +not used) because array size is used to automatically determine FFT length + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real inverse FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + F - array[0..floor(N/2)] - frequencies from forward real FFT + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + +NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one +half of frequencies array is needed - elements from 0 to floor(N/2). F[0] +is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then +F[floor(N/2)] has no special properties. + +Relying on properties noted above, FFTR1DInv subroutine uses only elements +from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case +N is even it ignores imaginary part of F[floor(N/2)] too. + +When you call this function using full arguments list - "FFTR1DInv(F,N,A)" +- you can pass either either frequencies array with N elements or reduced +array with roughly N/2 elements - subroutine will successfully transform +both. + +If you call this function using reduced arguments list - "FFTR1DInv(F,A)" +- you must pass FULL array with N elements (although higher N/2 are still +not used) because array size is used to automatically determine FFT length + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftr1dinv(const complex_1d_array &f, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = f.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +1-dimensional real inverse FFT, buffered version, which does not reallocate +A[] if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinvbuf(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real inverse FFT, buffered version, which does not reallocate +A[] if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void fftr1dinvbuf(const complex_1d_array &f, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = f.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +#endif + +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional Fast Hartley Transform. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - FHT of a input array, array[0..N-1], + A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) + + + -- ALGLIB -- + Copyright 04.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1d(real_1d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fhtr1d(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional inverse FHT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse FHT of a input array, array[0..N-1] + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1dinv(real_1d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fhtr1dinv(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex convolution. + +For given A/B returns conv(A,B) (non-circular). Subroutine can automatically +choose between three implementations: straightforward O(M*N) formula for +very small N (or M), overlap-add algorithm for cases where max(M,N) is +significantly larger than min(M,N), but O(M*N) algorithm is too slow, and +general FFT-based formula for cases where two previous algorithms are too +slow. + +Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. + +INPUT PARAMETERS + A - array[M] - complex function to be transformed + M - problem size + B - array[N] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[N+M-1] + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both + functions have non-zero values at negative T's, you can still use this + subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex convolution, buffered version of ConvC1DBuf(), which +does not reallocate R[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length, N<=M + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DInvBuf(), + which can reuse space previously allocated in its output parameter R + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). + +A buffered version, which does not reallocate R[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex convolution. + +For given S/R returns conv(S,R) (circular). Algorithm has linearithmic +complexity for any M/N. + +IMPORTANT: normal convolution is commutative, i.e. it is symmetric - +conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a +signal, periodic function, and another - R - is a response, non-periodic +function with limited length. + +INPUT PARAMETERS + S - array[M] - complex periodic signal + M - problem size + B - array[N] - complex non-periodic response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[M]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex convolution. + +Buffered version of ConvC1DCircular(), which does not reallocate C[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularbuf(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved periodic signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - non-periodic response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-1]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convc1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real convolution. + +Analogous to ConvC1D(), see ConvC1D() comments for more details. + +INPUT PARAMETERS + A - array[0..M-1] - real function to be transformed + M - problem size + B - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..N+M-2]. + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DBuf(), + which can reuse space previously allocated in its output parameter R. + + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real convolution. + +Buffered version of ConvR1D(), which does not reallocate R[] if its length +is enough to store the result (i.e. it reuses previously allocated memory +as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length, N<=M + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DInvBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real deconvolution (inverse of ConvR1D()), buffered version, +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular real convolution. + +Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. + +INPUT PARAMETERS + S - array[0..M-1] - real signal + M - problem size + B - array[0..N-1] - real response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular real convolution, buffered version, which does not +reallocate C[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularbuf(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex deconvolution, inverse of ConvR1DCircular(). + +Buffered version, which does not reallocate R[] if its length is enough to +store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::convr1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(conj(pattern[j])*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrc1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional complex cross-correlation, a buffered version of CorrC1D() +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dbuf(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrc1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + non-periodic pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrC1DCircular(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrc1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +A buffered function which does not reallocate C[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircularbuf(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrc1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + pattern to 'search' withing signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(pattern[j]*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(pattern[j]*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrR1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrr1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional real cross-correlation, buffered function, which does not +reallocate R[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dbuf(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrr1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + non-periodic pattern to search withing signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrR1DCircularBuf(), + which can reuse space previously allocated in its output parameter C. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrr1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +1-dimensional circular real cross-correlation, buffered version , which +does not reallocate C[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircularbuf(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::corrr1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) + + +#endif + +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +1-dimensional complex FFT. + +Array size N may be arbitrary number (composite or prime). Composite N's +are handled with cache-oblivious variation of a Cooley-Tukey algorithm. +Small prime-factors are transformed using hard coded codelets (similar to +FFTW codelets, but without low-level optimization), large prime-factors +are handled with Bluestein's algorithm. + +Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), +most fast for powers of 2. When N have prime factors larger than these, +but orders of magnitude smaller than N, computations will be about 4 times +slower than for nearby highly composite N's. When N itself is prime, speed +will be 6 times lower. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) +{ + ae_frame _frame_block; + fasttransformplan plan; + ae_int_t i; + ae_vector buf; + + ae_frame_make(_state, &_frame_block); + memset(&plan, 0, sizeof(plan)); + memset(&buf, 0, sizeof(buf)); + _fasttransformplan_init(&plan, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "FFTC1D: incorrect N!", _state); + ae_assert(a->cnt>=n, "FFTC1D: Length(A)ptr.p_complex[i].x; + buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; + } + + /* + * Generate plan and execute it. + * + * Plan is a combination of a successive factorizations of N and + * precomputed data. It is much like a FFTW plan, but is not stored + * between subroutine calls and is much simpler. + */ + ftcomplexfftplan(n, 1, &plan, _state); + ftapplyplan(&plan, &buf, 0, 1, _state); + + /* + * result + */ + for(i=0; i<=n-1; i++) + { + a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0]; + a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional complex inverse FFT. + +Array size N may be arbitrary number (composite or prime). Algorithm has +O(N*logN) complexity for any N (composite or prime). + +See FFTC1D() description for more information about algorithm performance. + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>0, "FFTC1DInv: incorrect N!", _state); + ae_assert(a->cnt>=n, "FFTC1DInv: Length(A)ptr.p_complex[i].y = -a->ptr.p_complex[i].y; + } + fftc1d(a, n, _state); + for(i=0; i<=n-1; i++) + { + a->ptr.p_complex[i].x = a->ptr.p_complex[i].x/(double)n; + a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y/(double)n; + } +} + + +/************************************************************************* +1-dimensional real FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + F - DFT of a input array, array[0..N-1] + F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + +NOTE: there is a buffered version of this function, FFTR1DBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half +of array is usually needed. But for convinience subroutine returns full +complex array (with frequencies above N/2), so its result may be used by +other FFT-related subroutines. + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1d(/* Real */ const ae_vector* a, + ae_int_t n, + /* Complex */ ae_vector* f, + ae_state *_state) +{ + + ae_vector_clear(f); + + ae_assert(n>0, "FFTR1D: incorrect N!", _state); + ae_assert(a->cnt>=n, "FFTR1D: Length(A)0, "FFTR1DBuf: incorrect N!", _state); + ae_assert(a->cnt>=n, "FFTR1DBuf: Length(A)ptr.p_complex[0] = ae_complex_from_d(a->ptr.p_double[0]); + ae_frame_leave(_state); + return; + } + if( n==2 ) + { + callocv(2, f, _state); + f->ptr.p_complex[0].x = a->ptr.p_double[0]+a->ptr.p_double[1]; + f->ptr.p_complex[0].y = (double)(0); + f->ptr.p_complex[1].x = a->ptr.p_double[0]-a->ptr.p_double[1]; + f->ptr.p_complex[1].y = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Choose between odd-size and even-size FFTs + */ + if( n%2==0 ) + { + + /* + * even-size real FFT, use reduction to the complex task + */ + n2 = n/2; + ae_vector_set_length(&buf, n, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ftcomplexfftplan(n2, 1, &plan, _state); + ftapplyplan(&plan, &buf, 0, 1, _state); + callocv(n, f, _state); + for(i=0; i<=n2; i++) + { + idx = 2*(i%n2); + hn.x = buf.ptr.p_double[idx+0]; + hn.y = buf.ptr.p_double[idx+1]; + idx = 2*((n2-i)%n2); + hmnc.x = buf.ptr.p_double[idx+0]; + hmnc.y = -buf.ptr.p_double[idx+1]; + v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state); + v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state); + f->ptr.p_complex[i] = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); + f->ptr.p_complex[i].x = 0.5*f->ptr.p_complex[i].x; + f->ptr.p_complex[i].y = 0.5*f->ptr.p_complex[i].y; + } + for(i=n2+1; i<=n-1; i++) + { + f->ptr.p_complex[i] = ae_c_conj(f->ptr.p_complex[n-i], _state); + } + } + else + { + + /* + * use complex FFT + */ + callocv(n, f, _state); + for(i=0; i<=n-1; i++) + { + f->ptr.p_complex[i] = ae_complex_from_d(a->ptr.p_double[i]); + } + fftc1d(f, n, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional real inverse FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + F - array[0..floor(N/2)] - frequencies from forward real FFT + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + +NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one +half of frequencies array is needed - elements from 0 to floor(N/2). F[0] +is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then +F[floor(N/2)] has no special properties. + +Relying on properties noted above, FFTR1DInv subroutine uses only elements +from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case +N is even it ignores imaginary part of F[floor(N/2)] too. + +When you call this function using full arguments list - "FFTR1DInv(F,N,A)" +- you can pass either either frequencies array with N elements or reduced +array with roughly N/2 elements - subroutine will successfully transform +both. + +If you call this function using reduced arguments list - "FFTR1DInv(F,A)" +- you must pass FULL array with N elements (although higher N/2 are still +not used) because array size is used to automatically determine FFT length + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinv(/* Complex */ const ae_vector* f, + ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector h; + ae_vector fh; + + ae_frame_make(_state, &_frame_block); + memset(&h, 0, sizeof(h)); + memset(&fh, 0, sizeof(fh)); + ae_vector_clear(a); + ae_vector_init(&h, 0, DT_REAL, _state, ae_true); + ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "FFTR1DInv: incorrect N!", _state); + ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInv: Length(F)ptr.p_complex[0].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); + for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) + { + ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); + } + ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); + if( n%2!=0 ) + { + ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state); + } + fftr1dinvbuf(f, n, a, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional real inverse FFT, buffered version, which does not reallocate +A[] if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinvbuf(/* Complex */ const ae_vector* f, + ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector h; + ae_vector fh; + + ae_frame_make(_state, &_frame_block); + memset(&h, 0, sizeof(h)); + memset(&fh, 0, sizeof(fh)); + ae_vector_init(&h, 0, DT_REAL, _state, ae_true); + ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "FFTR1DInvBuf: incorrect N!", _state); + ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInvBuf: Length(F)ptr.p_complex[0].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state); + for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) + { + ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state); + } + ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state); + if( n%2!=0 ) + { + ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state); + } + + /* + * Special case: N=1, FFT is just identity transform. + * After this block we assume that N is strictly greater than 1. + */ + if( n==1 ) + { + rallocv(1, a, _state); + a->ptr.p_double[0] = f->ptr.p_complex[0].x; + ae_frame_leave(_state); + return; + } + + /* + * inverse real FFT is reduced to the inverse real FHT, + * which is reduced to the forward real FHT, + * which is reduced to the forward real FFT. + * + * Don't worry, it is really compact and efficient reduction :) + */ + ae_vector_set_length(&h, n, _state); + rallocv(n, a, _state); + h.ptr.p_double[0] = f->ptr.p_complex[0].x; + for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++) + { + h.ptr.p_double[i] = f->ptr.p_complex[i].x-f->ptr.p_complex[i].y; + h.ptr.p_double[n-i] = f->ptr.p_complex[i].x+f->ptr.p_complex[i].y; + } + if( n%2==0 ) + { + h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x; + } + else + { + h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x-f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; + h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)+1] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x+f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y; + } + fftr1d(&h, n, &fh, _state); + for(i=0; i<=n-1; i++) + { + a->ptr.p_double[i] = (fh.ptr.p_complex[i].x-fh.ptr.p_complex[i].y)/(double)n; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. Never call it directly! + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinternaleven(/* Real */ ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* buf, + fasttransformplan* plan, + ae_state *_state) +{ + double x; + double y; + ae_int_t i; + ae_int_t n2; + ae_int_t idx; + ae_complex hn; + ae_complex hmnc; + ae_complex v; + + + ae_assert(n>0&&n%2==0, "FFTR1DEvenInplace: incorrect N!", _state); + + /* + * Special cases: + * * N=2 + * + * After this block we assume that N is strictly greater than 2 + */ + if( n==2 ) + { + x = a->ptr.p_double[0]+a->ptr.p_double[1]; + y = a->ptr.p_double[0]-a->ptr.p_double[1]; + a->ptr.p_double[0] = x; + a->ptr.p_double[1] = y; + return; + } + + /* + * even-size real FFT, use reduction to the complex task + */ + n2 = n/2; + ae_v_move(&buf->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ftapplyplan(plan, buf, 0, 1, _state); + a->ptr.p_double[0] = buf->ptr.p_double[0]+buf->ptr.p_double[1]; + for(i=1; i<=n2-1; i++) + { + idx = 2*(i%n2); + hn.x = buf->ptr.p_double[idx+0]; + hn.y = buf->ptr.p_double[idx+1]; + idx = 2*(n2-i); + hmnc.x = buf->ptr.p_double[idx+0]; + hmnc.y = -buf->ptr.p_double[idx+1]; + v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state); + v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state); + v = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc))); + a->ptr.p_double[2*i+0] = 0.5*v.x; + a->ptr.p_double[2*i+1] = 0.5*v.y; + } + a->ptr.p_double[1] = buf->ptr.p_double[0]-buf->ptr.p_double[1]; +} + + +/************************************************************************* +Internal subroutine. Never call it directly! + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinvinternaleven(/* Real */ ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* buf, + fasttransformplan* plan, + ae_state *_state) +{ + double x; + double y; + double t; + ae_int_t i; + ae_int_t n2; + + + ae_assert(n>0&&n%2==0, "FFTR1DInvInternalEven: incorrect N!", _state); + + /* + * Special cases: + * * N=2 + * + * After this block we assume that N is strictly greater than 2 + */ + if( n==2 ) + { + x = 0.5*(a->ptr.p_double[0]+a->ptr.p_double[1]); + y = 0.5*(a->ptr.p_double[0]-a->ptr.p_double[1]); + a->ptr.p_double[0] = x; + a->ptr.p_double[1] = y; + return; + } + + /* + * inverse real FFT is reduced to the inverse real FHT, + * which is reduced to the forward real FHT, + * which is reduced to the forward real FFT. + * + * Don't worry, it is really compact and efficient reduction :) + */ + n2 = n/2; + buf->ptr.p_double[0] = a->ptr.p_double[0]; + for(i=1; i<=n2-1; i++) + { + x = a->ptr.p_double[2*i+0]; + y = a->ptr.p_double[2*i+1]; + buf->ptr.p_double[i] = x-y; + buf->ptr.p_double[n-i] = x+y; + } + buf->ptr.p_double[n2] = a->ptr.p_double[1]; + fftr1dinternaleven(buf, n, a, plan, _state); + a->ptr.p_double[0] = buf->ptr.p_double[0]/(double)n; + t = (double)1/(double)n; + for(i=1; i<=n2-1; i++) + { + x = buf->ptr.p_double[2*i+0]; + y = buf->ptr.p_double[2*i+1]; + a->ptr.p_double[i] = t*(x-y); + a->ptr.p_double[n-i] = t*(x+y); + } + a->ptr.p_double[n2] = buf->ptr.p_double[1]/(double)n; +} + + +#endif +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +1-dimensional Fast Hartley Transform. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - FHT of a input array, array[0..N-1], + A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) + + + -- ALGLIB -- + Copyright 04.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector fa; + + ae_frame_make(_state, &_frame_block); + memset(&fa, 0, sizeof(fa)); + ae_vector_init(&fa, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "FHTR1D: incorrect N!", _state); + + /* + * Special case: N=1, FHT is just identity transform. + * After this block we assume that N is strictly greater than 1. + */ + if( n==1 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Reduce FHt to real FFT + */ + fftr1d(a, n, &fa, _state); + for(i=0; i<=n-1; i++) + { + a->ptr.p_double[i] = fa.ptr.p_complex[i].x-fa.ptr.p_complex[i].y; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional inverse FHT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse FHT of a input array, array[0..N-1] + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>0, "FHTR1DInv: incorrect N!", _state); + + /* + * Special case: N=1, iFHT is just identity transform. + * After this block we assume that N is strictly greater than 1. + */ + if( n==1 ) + { + return; + } + + /* + * Inverse FHT can be expressed in terms of the FHT as + * + * invfht(x) = fht(x)/N + */ + fhtr1d(a, n, _state); + for(i=0; i<=n-1; i++) + { + a->ptr.p_double[i] = a->ptr.p_double[i]/(double)n; + } +} + + +#endif +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +1-dimensional complex convolution. + +For given A/B returns conv(A,B) (non-circular). Subroutine can automatically +choose between three implementations: straightforward O(M*N) formula for +very small N (or M), overlap-add algorithm for cases where max(M,N) is +significantly larger than min(M,N), but O(M*N) algorithm is too slow, and +general FFT-based formula for cases where two previous algorithms are too +slow. + +Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. + +INPUT PARAMETERS + A - array[M] - complex function to be transformed + M - problem size + B - array[N] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[N+M-1] + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both + functions have non-zero values at negative T's, you can still use this + subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1d(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "ConvC1D: incorrect N or M!", _state); + convc1dbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional complex convolution, buffered version of ConvC1DBuf(), which +does not reallocate R[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + + + ae_assert(n>0&&m>0, "ConvC1DBuf: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer that B. + */ + if( m0&&m>0)&&n<=m, "ConvC1DInv: incorrect N or M!", _state); + convc1dinvbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). + +A buffered version, which does not reallocate R[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dinvbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t p; + ae_vector buf; + ae_vector buf2; + fasttransformplan plan; + ae_complex c1; + ae_complex c2; + ae_complex c3; + double t; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + memset(&plan, 0, sizeof(plan)); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + _fasttransformplan_init(&plan, _state, ae_true); + + ae_assert((n>0&&m>0)&&n<=m, "ConvC1DInvBuf: incorrect N or M!", _state); + p = ftbasefindsmooth(m, _state); + ftcomplexfftplan(p, 1, &plan, _state); + ae_vector_set_length(&buf, 2*p, _state); + for(i=0; i<=m-1; i++) + { + buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; + buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; + } + for(i=m; i<=p-1; i++) + { + buf.ptr.p_double[2*i+0] = (double)(0); + buf.ptr.p_double[2*i+1] = (double)(0); + } + ae_vector_set_length(&buf2, 2*p, _state); + for(i=0; i<=n-1; i++) + { + buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; + buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; + } + for(i=n; i<=p-1; i++) + { + buf2.ptr.p_double[2*i+0] = (double)(0); + buf2.ptr.p_double[2*i+1] = (double)(0); + } + ftapplyplan(&plan, &buf, 0, 1, _state); + ftapplyplan(&plan, &buf2, 0, 1, _state); + for(i=0; i<=p-1; i++) + { + c1.x = buf.ptr.p_double[2*i+0]; + c1.y = buf.ptr.p_double[2*i+1]; + c2.x = buf2.ptr.p_double[2*i+0]; + c2.y = buf2.ptr.p_double[2*i+1]; + c3 = ae_c_div(c1,c2); + buf.ptr.p_double[2*i+0] = c3.x; + buf.ptr.p_double[2*i+1] = -c3.y; + } + ftapplyplan(&plan, &buf, 0, 1, _state); + t = (double)1/(double)p; + callocv(m-n+1, r, _state); + for(i=0; i<=m-n; i++) + { + r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular complex convolution. + +For given S/R returns conv(S,R) (circular). Algorithm has linearithmic +complexity for any M/N. + +IMPORTANT: normal convolution is commutative, i.e. it is symmetric - +conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a +signal, periodic function, and another - R - is a response, non-periodic +function with limited length. + +INPUT PARAMETERS + S - array[M] - complex periodic signal + M - problem size + B - array[N] - complex non-periodic response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[M]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircular(/* Complex */ const ae_vector* s, + ae_int_t m, + /* Complex */ const ae_vector* r, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state) +{ + + ae_vector_clear(c); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + convc1dcircularbuf(s, m, r, n, c, _state); +} + + +/************************************************************************* +1-dimensional circular complex convolution. + +Buffered version of ConvC1DCircular(), which does not reallocate C[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularbuf(/* Complex */ const ae_vector* s, + ae_int_t m, + /* Complex */ const ae_vector* r, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector buf; + ae_int_t i1; + ae_int_t i2; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + ae_vector_init(&buf, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); + i1 = i1+m; + } + convc1dcircularbuf(s, m, &buf, m, c, _state); + ae_frame_leave(_state); + return; + } + convc1dx(s, m, r, n, ae_true, -1, 0, c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved periodic signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - non-periodic response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-1]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinv(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state); + convc1dcircularinvbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinvbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t i1; + ae_int_t i2; + ae_int_t j2; + ae_vector buf; + ae_vector buf2; + ae_vector cbuf; + fasttransformplan plan; + ae_complex c1; + ae_complex c2; + ae_complex c3; + double t; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + memset(&cbuf, 0, sizeof(cbuf)); + memset(&plan, 0, sizeof(plan)); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true); + _fasttransformplan_init(&plan, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); + i1 = i1+m; + } + convc1dcircularinvbuf(a, m, &cbuf, m, r, _state); + ae_frame_leave(_state); + return; + } + + /* + * Task is normalized + */ + ftcomplexfftplan(m, 1, &plan, _state); + ae_vector_set_length(&buf, 2*m, _state); + for(i=0; i<=m-1; i++) + { + buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; + buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; + } + ae_vector_set_length(&buf2, 2*m, _state); + for(i=0; i<=n-1; i++) + { + buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; + buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; + } + for(i=n; i<=m-1; i++) + { + buf2.ptr.p_double[2*i+0] = (double)(0); + buf2.ptr.p_double[2*i+1] = (double)(0); + } + ftapplyplan(&plan, &buf, 0, 1, _state); + ftapplyplan(&plan, &buf2, 0, 1, _state); + for(i=0; i<=m-1; i++) + { + c1.x = buf.ptr.p_double[2*i+0]; + c1.y = buf.ptr.p_double[2*i+1]; + c2.x = buf2.ptr.p_double[2*i+0]; + c2.y = buf2.ptr.p_double[2*i+1]; + c3 = ae_c_div(c1,c2); + buf.ptr.p_double[2*i+0] = c3.x; + buf.ptr.p_double[2*i+1] = -c3.y; + } + ftapplyplan(&plan, &buf, 0, 1, _state); + t = (double)1/(double)m; + callocv(m, r, _state); + for(i=0; i<=m-1; i++) + { + r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional real convolution. + +Analogous to ConvC1D(), see ConvC1D() comments for more details. + +INPUT PARAMETERS + A - array[0..M-1] - real function to be transformed + M - problem size + B - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..N+M-2]. + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DBuf(), + which can reuse space previously allocated in its output parameter R. + + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1d(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "ConvR1D: incorrect N or M!", _state); + convr1dbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional real convolution. + +Buffered version of ConvR1D(), which does not reallocate R[] if its length +is enough to store the result (i.e. it reuses previously allocated memory +as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + + ae_assert(n>0&&m>0, "ConvR1DBuf: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer that B. + */ + if( m0&&m>0)&&n<=m, "ConvR1DInv: incorrect N or M!", _state); + convr1dinvbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional real deconvolution (inverse of ConvR1D()), buffered version, +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dinvbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t p; + ae_vector buf; + ae_vector buf2; + ae_vector buf3; + fasttransformplan plan; + ae_complex c1; + ae_complex c2; + ae_complex c3; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + memset(&buf3, 0, sizeof(buf3)); + memset(&plan, 0, sizeof(plan)); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true); + _fasttransformplan_init(&plan, _state, ae_true); + + ae_assert((n>0&&m>0)&&n<=m, "ConvR1DInvBuf: incorrect N or M!", _state); + p = ftbasefindsmootheven(m, _state); + ae_vector_set_length(&buf, p, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); + for(i=m; i<=p-1; i++) + { + buf.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf2, p, _state); + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=n; i<=p-1; i++) + { + buf2.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf3, p, _state); + ftcomplexfftplan(p/2, 1, &plan, _state); + fftr1dinternaleven(&buf, p, &buf3, &plan, _state); + fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); + buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; + buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; + for(i=1; i<=p/2-1; i++) + { + c1.x = buf.ptr.p_double[2*i+0]; + c1.y = buf.ptr.p_double[2*i+1]; + c2.x = buf2.ptr.p_double[2*i+0]; + c2.y = buf2.ptr.p_double[2*i+1]; + c3 = ae_c_div(c1,c2); + buf.ptr.p_double[2*i+0] = c3.x; + buf.ptr.p_double[2*i+1] = c3.y; + } + fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); + rallocv(m-n+1, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-n)); + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular real convolution. + +Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. + +INPUT PARAMETERS + S - array[0..M-1] - real signal + M - problem size + B - array[0..N-1] - real response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircular(/* Real */ const ae_vector* s, + ae_int_t m, + /* Real */ const ae_vector* r, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + + ae_vector_clear(c); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + convr1dcircularbuf(s, m, r, n, c, _state); +} + + +/************************************************************************* +1-dimensional circular real convolution, buffered version, which does not +reallocate C[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularbuf(/* Real */ const ae_vector* s, + ae_int_t m, + /* Real */ const ae_vector* r, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector buf; + ae_int_t i1; + ae_int_t i2; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircularBuf: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_double[i1], 1, ae_v_len(0,j2)); + i1 = i1+m; + } + convr1dcircularbuf(s, m, &buf, m, c, _state); + ae_frame_leave(_state); + return; + } + + /* + * reduce to usual convolution + */ + convr1dx(s, m, r, n, ae_true, -1, 0, c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional complex deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinv(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state); + convr1dcircularinvbuf(a, m, b, n, r, _state); +} + + +/************************************************************************* +1-dimensional complex deconvolution, inverse of ConvR1DCircular(). + +Buffered version, which does not reallocate R[] if its length is enough to +store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinvbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t i1; + ae_int_t i2; + ae_int_t j2; + ae_vector buf; + ae_vector buf2; + ae_vector buf3; + ae_vector cbuf; + ae_vector cbuf2; + fasttransformplan plan; + ae_complex c1; + ae_complex c2; + ae_complex c3; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + memset(&buf3, 0, sizeof(buf3)); + memset(&cbuf, 0, sizeof(cbuf)); + memset(&cbuf2, 0, sizeof(cbuf2)); + memset(&plan, 0, sizeof(plan)); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cbuf2, 0, DT_COMPLEX, _state, ae_true); + _fasttransformplan_init(&plan, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_double[i1], 1, ae_v_len(0,j2)); + i1 = i1+m; + } + convr1dcircularinvbuf(a, m, &buf, m, r, _state); + ae_frame_leave(_state); + return; + } + + /* + * Task is normalized + */ + if( m%2==0 ) + { + + /* + * size is even, use fast even-size FFT + */ + ae_vector_set_length(&buf, m, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); + ae_vector_set_length(&buf2, m, _state); + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=n; i<=m-1; i++) + { + buf2.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf3, m, _state); + ftcomplexfftplan(m/2, 1, &plan, _state); + fftr1dinternaleven(&buf, m, &buf3, &plan, _state); + fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); + buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0]; + buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1]; + for(i=1; i<=m/2-1; i++) + { + c1.x = buf.ptr.p_double[2*i+0]; + c1.y = buf.ptr.p_double[2*i+1]; + c2.x = buf2.ptr.p_double[2*i+0]; + c2.y = buf2.ptr.p_double[2*i+1]; + c3 = ae_c_div(c1,c2); + buf.ptr.p_double[2*i+0] = c3.x; + buf.ptr.p_double[2*i+1] = c3.y; + } + fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); + rallocv(m, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); + } + else + { + + /* + * odd-size, use general real FFT + */ + fftr1d(a, m, &cbuf, _state); + ae_vector_set_length(&buf2, m, _state); + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=n; i<=m-1; i++) + { + buf2.ptr.p_double[i] = (double)(0); + } + fftr1d(&buf2, m, &cbuf2, _state); + for(i=0; i<=ae_ifloor((double)m/(double)2, _state); i++) + { + cbuf.ptr.p_complex[i] = ae_c_div(cbuf.ptr.p_complex[i],cbuf2.ptr.p_complex[i]); + } + fftr1dinvbuf(&cbuf, m, r, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional complex convolution. + +Extended subroutine which allows to choose convolution algorithm. +Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular(). + +INPUT PARAMETERS + A - array[0..M-1] - complex function to be transformed + M - problem size + B - array[0..N-1] - complex function to be transformed + N - problem size, N<=M + Alg - algorithm type: + *-2 auto-select Q for overlap-add + *-1 auto-select algorithm and parameters + * 0 straightforward formula for small N's + * 1 general FFT-based code + * 2 overlap-add with length Q + Q - length for overlap-add + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..N+M-1]. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dx(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + ae_bool circular, + ae_int_t alg, + ae_int_t q, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t p; + ae_int_t ptotal; + ae_int_t i1; + ae_int_t i2; + ae_int_t j1; + ae_int_t j2; + ae_vector bbuf; + ae_complex v; + double ax; + double ay; + double bx; + double by; + double t; + double tx; + double ty; + double flopcand; + double flopbest; + ae_int_t algbest; + fasttransformplan plan; + ae_vector buf; + ae_vector buf2; + + ae_frame_make(_state, &_frame_block); + memset(&bbuf, 0, sizeof(bbuf)); + memset(&plan, 0, sizeof(plan)); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + ae_vector_init(&bbuf, 0, DT_COMPLEX, _state, ae_true); + _fasttransformplan_init(&plan, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state); + ae_assert(n<=m, "ConvC1DX: Nptr.p_complex[0]; + ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); + ae_frame_leave(_state); + return; + } + + /* + * use straightforward formula + */ + if( circular ) + { + + /* + * circular convolution + */ + callocv(m, r, _state); + v = b->ptr.p_complex[0]; + ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v); + for(i=1; i<=n-1; i++) + { + v = b->ptr.p_complex[i]; + i1 = 0; + i2 = i-1; + j1 = m-i; + j2 = m-1; + ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); + i1 = i; + i2 = m-1; + j1 = 0; + j2 = m-i-1; + ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v); + } + } + else + { + + /* + * non-circular convolution + */ + callocv(m+n-1, r, _state); + for(i=0; i<=m+n-2; i++) + { + r->ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=0; i<=n-1; i++) + { + v = b->ptr.p_complex[i]; + ae_v_caddc(&r->ptr.p_complex[i], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(i,i+m-1), v); + } + } + ae_frame_leave(_state); + return; + } + + /* + * general FFT-based code for + * circular and non-circular convolutions. + * + * First, if convolution is circular, we test whether M is smooth or not. + * If it is smooth, we just use M-length FFT to calculate convolution. + * If it is not, we calculate non-circular convolution and wrap it arount. + * + * IF convolution is non-circular, we use zero-padding + FFT. + */ + if( alg==1 ) + { + if( circular&&ftbaseissmooth(m, _state) ) + { + + /* + * special code for circular convolution with smooth M + */ + ftcomplexfftplan(m, 1, &plan, _state); + ae_vector_set_length(&buf, 2*m, _state); + for(i=0; i<=m-1; i++) + { + buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; + buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; + } + ae_vector_set_length(&buf2, 2*m, _state); + for(i=0; i<=n-1; i++) + { + buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; + buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; + } + for(i=n; i<=m-1; i++) + { + buf2.ptr.p_double[2*i+0] = (double)(0); + buf2.ptr.p_double[2*i+1] = (double)(0); + } + ftapplyplan(&plan, &buf, 0, 1, _state); + ftapplyplan(&plan, &buf2, 0, 1, _state); + for(i=0; i<=m-1; i++) + { + ax = buf.ptr.p_double[2*i+0]; + ay = buf.ptr.p_double[2*i+1]; + bx = buf2.ptr.p_double[2*i+0]; + by = buf2.ptr.p_double[2*i+1]; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*i+0] = tx; + buf.ptr.p_double[2*i+1] = -ty; + } + ftapplyplan(&plan, &buf, 0, 1, _state); + t = (double)1/(double)m; + callocv(m, r, _state); + for(i=0; i<=m-1; i++) + { + r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; + } + } + else + { + + /* + * M is non-smooth, general code (circular/non-circular): + * * first part is the same for circular and non-circular + * convolutions. zero padding, FFTs, inverse FFTs + * * second part differs: + * * for non-circular convolution we just copy array + * * for circular convolution we add array tail to its head + */ + p = ftbasefindsmooth(m+n-1, _state); + ftcomplexfftplan(p, 1, &plan, _state); + ae_vector_set_length(&buf, 2*p, _state); + for(i=0; i<=m-1; i++) + { + buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x; + buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y; + } + for(i=m; i<=p-1; i++) + { + buf.ptr.p_double[2*i+0] = (double)(0); + buf.ptr.p_double[2*i+1] = (double)(0); + } + ae_vector_set_length(&buf2, 2*p, _state); + for(i=0; i<=n-1; i++) + { + buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x; + buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y; + } + for(i=n; i<=p-1; i++) + { + buf2.ptr.p_double[2*i+0] = (double)(0); + buf2.ptr.p_double[2*i+1] = (double)(0); + } + ftapplyplan(&plan, &buf, 0, 1, _state); + ftapplyplan(&plan, &buf2, 0, 1, _state); + for(i=0; i<=p-1; i++) + { + ax = buf.ptr.p_double[2*i+0]; + ay = buf.ptr.p_double[2*i+1]; + bx = buf2.ptr.p_double[2*i+0]; + by = buf2.ptr.p_double[2*i+1]; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*i+0] = tx; + buf.ptr.p_double[2*i+1] = -ty; + } + ftapplyplan(&plan, &buf, 0, 1, _state); + t = (double)1/(double)p; + if( circular ) + { + + /* + * circular, add tail to head + */ + callocv(m, r, _state); + for(i=0; i<=m-1; i++) + { + r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; + } + for(i=m; i<=m+n-2; i++) + { + r->ptr.p_complex[i-m].x = r->ptr.p_complex[i-m].x+t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i-m].y = r->ptr.p_complex[i-m].y-t*buf.ptr.p_double[2*i+1]; + } + } + else + { + + /* + * non-circular, just copy + */ + callocv(m+n-1, r, _state); + for(i=0; i<=m+n-2; i++) + { + r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0]; + r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1]; + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * overlap-add method for + * circular and non-circular convolutions. + * + * First part of code (separate FFTs of input blocks) is the same + * for all types of convolution. Second part (overlapping outputs) + * differs for different types of convolution. We just copy output + * when convolution is non-circular. We wrap it around, if it is + * circular. + */ + if( alg==2 ) + { + ae_vector_set_length(&buf, 2*(q+n-1), _state); + + /* + * prepare R + */ + if( circular ) + { + callocv(m, r, _state); + for(i=0; i<=m-1; i++) + { + r->ptr.p_complex[i] = ae_complex_from_i(0); + } + } + else + { + callocv(m+n-1, r, _state); + for(i=0; i<=m+n-2; i++) + { + r->ptr.p_complex[i] = ae_complex_from_i(0); + } + } + + /* + * pre-calculated FFT(B) + */ + ae_vector_set_length(&bbuf, q+n-1, _state); + ae_v_cmove(&bbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + for(j=n; j<=q+n-2; j++) + { + bbuf.ptr.p_complex[j] = ae_complex_from_i(0); + } + fftc1d(&bbuf, q+n-1, _state); + + /* + * prepare FFT plan for chunks of A + */ + ftcomplexfftplan(q+n-1, 1, &plan, _state); + + /* + * main overlap-add cycle + */ + i = 0; + while(i<=m-1) + { + p = ae_minint(q, m-i, _state); + for(j=0; j<=p-1; j++) + { + buf.ptr.p_double[2*j+0] = a->ptr.p_complex[i+j].x; + buf.ptr.p_double[2*j+1] = a->ptr.p_complex[i+j].y; + } + for(j=p; j<=q+n-2; j++) + { + buf.ptr.p_double[2*j+0] = (double)(0); + buf.ptr.p_double[2*j+1] = (double)(0); + } + ftapplyplan(&plan, &buf, 0, 1, _state); + for(j=0; j<=q+n-2; j++) + { + ax = buf.ptr.p_double[2*j+0]; + ay = buf.ptr.p_double[2*j+1]; + bx = bbuf.ptr.p_complex[j].x; + by = bbuf.ptr.p_complex[j].y; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*j+0] = tx; + buf.ptr.p_double[2*j+1] = -ty; + } + ftapplyplan(&plan, &buf, 0, 1, _state); + t = (double)1/(double)(q+n-1); + if( circular ) + { + j1 = ae_minint(i+p+n-2, m-1, _state)-i; + j2 = j1+1; + } + else + { + j1 = p+n-2; + j2 = j1+1; + } + for(j=0; j<=j1; j++) + { + r->ptr.p_complex[i+j].x = r->ptr.p_complex[i+j].x+buf.ptr.p_double[2*j+0]*t; + r->ptr.p_complex[i+j].y = r->ptr.p_complex[i+j].y-buf.ptr.p_double[2*j+1]*t; + } + for(j=j2; j<=p+n-2; j++) + { + r->ptr.p_complex[j-j2].x = r->ptr.p_complex[j-j2].x+buf.ptr.p_double[2*j+0]*t; + r->ptr.p_complex[j-j2].y = r->ptr.p_complex[j-j2].y-buf.ptr.p_double[2*j+1]*t; + } + i = i+p; + } + ae_frame_leave(_state); + return; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional real convolution. + +Extended subroutine which allows to choose convolution algorithm. +Intended for internal use, ALGLIB users should call ConvR1D(). + +INPUT PARAMETERS + A - array[0..M-1] - complex function to be transformed + M - problem size + B - array[0..N-1] - complex function to be transformed + N - problem size, N<=M + Alg - algorithm type: + *-2 auto-select Q for overlap-add + *-1 auto-select algorithm and parameters + * 0 straightforward formula for small N's + * 1 general FFT-based code + * 2 overlap-add with length Q + Q - length for overlap-add + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..N+M-1]. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dx(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + ae_bool circular, + ae_int_t alg, + ae_int_t q, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t p; + ae_int_t ptotal; + ae_int_t i1; + ae_int_t i2; + ae_int_t j1; + ae_int_t j2; + double ax; + double ay; + double bx; + double by; + double tx; + double ty; + double flopcand; + double flopbest; + ae_int_t algbest; + fasttransformplan plan; + ae_vector buf; + ae_vector buf2; + ae_vector buf3; + + ae_frame_make(_state, &_frame_block); + memset(&plan, 0, sizeof(plan)); + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + memset(&buf3, 0, sizeof(buf3)); + _fasttransformplan_init(&plan, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvR1DX: incorrect N or M!", _state); + ae_assert(n<=m, "ConvR1DX: Nptr.p_double[0]; + ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); + ae_frame_leave(_state); + return; + } + + /* + * use straightforward formula + */ + if( circular ) + { + + /* + * circular convolution + */ + rallocv(m, r, _state); + v = b->ptr.p_double[0]; + ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v); + for(i=1; i<=n-1; i++) + { + v = b->ptr.p_double[i]; + i1 = 0; + i2 = i-1; + j1 = m-i; + j2 = m-1; + ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); + i1 = i; + i2 = m-1; + j1 = 0; + j2 = m-i-1; + ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v); + } + } + else + { + + /* + * non-circular convolution + */ + rallocv(m+n-1, r, _state); + for(i=0; i<=m+n-2; i++) + { + r->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = b->ptr.p_double[i]; + ae_v_addd(&r->ptr.p_double[i], 1, &a->ptr.p_double[0], 1, ae_v_len(i,i+m-1), v); + } + } + ae_frame_leave(_state); + return; + } + + /* + * general FFT-based code for + * circular and non-circular convolutions. + * + * First, if convolution is circular, we test whether M is smooth or not. + * If it is smooth, we just use M-length FFT to calculate convolution. + * If it is not, we calculate non-circular convolution and wrap it arount. + * + * If convolution is non-circular, we use zero-padding + FFT. + * + * We assume that M+N-1>2 - we should call small case code otherwise + */ + if( alg==1 ) + { + ae_assert(m+n-1>2, "ConvR1DX: internal error!", _state); + if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 ) + { + + /* + * special code for circular convolution with smooth even M + */ + ae_vector_set_length(&buf, m, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); + ae_vector_set_length(&buf2, m, _state); + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=n; i<=m-1; i++) + { + buf2.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf3, m, _state); + ftcomplexfftplan(m/2, 1, &plan, _state); + fftr1dinternaleven(&buf, m, &buf3, &plan, _state); + fftr1dinternaleven(&buf2, m, &buf3, &plan, _state); + buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; + buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; + for(i=1; i<=m/2-1; i++) + { + ax = buf.ptr.p_double[2*i+0]; + ay = buf.ptr.p_double[2*i+1]; + bx = buf2.ptr.p_double[2*i+0]; + by = buf2.ptr.p_double[2*i+1]; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*i+0] = tx; + buf.ptr.p_double[2*i+1] = ty; + } + fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state); + rallocv(m, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); + } + else + { + + /* + * M is non-smooth or non-even, general code (circular/non-circular): + * * first part is the same for circular and non-circular + * convolutions. zero padding, FFTs, inverse FFTs + * * second part differs: + * * for non-circular convolution we just copy array + * * for circular convolution we add array tail to its head + */ + p = ftbasefindsmootheven(m+n-1, _state); + ae_vector_set_length(&buf, p, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1)); + for(i=m; i<=p-1; i++) + { + buf.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf2, p, _state); + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=n; i<=p-1; i++) + { + buf2.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&buf3, p, _state); + ftcomplexfftplan(p/2, 1, &plan, _state); + fftr1dinternaleven(&buf, p, &buf3, &plan, _state); + fftr1dinternaleven(&buf2, p, &buf3, &plan, _state); + buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; + buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; + for(i=1; i<=p/2-1; i++) + { + ax = buf.ptr.p_double[2*i+0]; + ay = buf.ptr.p_double[2*i+1]; + bx = buf2.ptr.p_double[2*i+0]; + by = buf2.ptr.p_double[2*i+1]; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*i+0] = tx; + buf.ptr.p_double[2*i+1] = ty; + } + fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state); + if( circular ) + { + + /* + * circular, add tail to head + */ + rallocv(m, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1)); + if( n>=2 ) + { + ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[m], 1, ae_v_len(0,n-2)); + } + } + else + { + + /* + * non-circular, just copy + */ + rallocv(m+n-1, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m+n-2)); + } + } + ae_frame_leave(_state); + return; + } + + /* + * overlap-add method + */ + if( alg==2 ) + { + ae_assert((q+n-1)%2==0, "ConvR1DX: internal error!", _state); + ae_vector_set_length(&buf, q+n-1, _state); + ae_vector_set_length(&buf2, q+n-1, _state); + ae_vector_set_length(&buf3, q+n-1, _state); + ftcomplexfftplan((q+n-1)/2, 1, &plan, _state); + + /* + * prepare R + */ + if( circular ) + { + rallocv(m, r, _state); + for(i=0; i<=m-1; i++) + { + r->ptr.p_double[i] = (double)(0); + } + } + else + { + rallocv(m+n-1, r, _state); + for(i=0; i<=m+n-2; i++) + { + r->ptr.p_double[i] = (double)(0); + } + } + + /* + * pre-calculated FFT(B) + */ + ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(j=n; j<=q+n-2; j++) + { + buf2.ptr.p_double[j] = (double)(0); + } + fftr1dinternaleven(&buf2, q+n-1, &buf3, &plan, _state); + + /* + * main overlap-add cycle + */ + i = 0; + while(i<=m-1) + { + p = ae_minint(q, m-i, _state); + ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[i], 1, ae_v_len(0,p-1)); + for(j=p; j<=q+n-2; j++) + { + buf.ptr.p_double[j] = (double)(0); + } + fftr1dinternaleven(&buf, q+n-1, &buf3, &plan, _state); + buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0]; + buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1]; + for(j=1; j<=(q+n-1)/2-1; j++) + { + ax = buf.ptr.p_double[2*j+0]; + ay = buf.ptr.p_double[2*j+1]; + bx = buf2.ptr.p_double[2*j+0]; + by = buf2.ptr.p_double[2*j+1]; + tx = ax*bx-ay*by; + ty = ax*by+ay*bx; + buf.ptr.p_double[2*j+0] = tx; + buf.ptr.p_double[2*j+1] = ty; + } + fftr1dinvinternaleven(&buf, q+n-1, &buf3, &plan, _state); + if( circular ) + { + j1 = ae_minint(i+p+n-2, m-1, _state)-i; + j2 = j1+1; + } + else + { + j1 = p+n-2; + j2 = j1+1; + } + ae_v_add(&r->ptr.p_double[i], 1, &buf.ptr.p_double[0], 1, ae_v_len(i,i+j1)); + if( p+n-2>=j2 ) + { + ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[j2], 1, ae_v_len(0,p+n-2-j2)); + } + i = i+p; + } + ae_frame_leave(_state); + return; + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +1-dimensional complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(conj(pattern[j])*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1d(/* Complex */ const ae_vector* signal, + ae_int_t n, + /* Complex */ const ae_vector* pattern, + ae_int_t m, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "CorrC1D: incorrect N or M!", _state); + corrc1dbuf(signal, n, pattern, m, r, _state); +} + + +/************************************************************************* +1-dimensional complex cross-correlation, a buffered version of CorrC1D() +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dbuf(/* Complex */ const ae_vector* signal, + ae_int_t n, + /* Complex */ const ae_vector* pattern, + ae_int_t m, + /* Complex */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p; + ae_vector b; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&p, 0, sizeof(p)); + memset(&b, 0, sizeof(b)); + ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0&&m>0, "CorrC1DBuf: incorrect N or M!", _state); + ae_vector_set_length(&p, m, _state); + for(i=0; i<=m-1; i++) + { + p.ptr.p_complex[m-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); + } + convc1d(&p, m, signal, n, &b, _state); + callocv(m+n-1, r, _state); + ae_v_cmove(&r->ptr.p_complex[0], 1, &b.ptr.p_complex[m-1], 1, "N", ae_v_len(0,n-1)); + if( m+n-2>=n ) + { + ae_v_cmove(&r->ptr.p_complex[n], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(n,m+n-2)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + non-periodic pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrC1DCircular(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircular(/* Complex */ const ae_vector* signal, + ae_int_t m, + /* Complex */ const ae_vector* pattern, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p; + ae_vector b; + ae_int_t i1; + ae_int_t i2; + ae_int_t i; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&p, 0, sizeof(p)); + memset(&b, 0, sizeof(b)); + ae_vector_clear(c); + ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); + i1 = i1+m; + } + corrc1dcircular(signal, m, &b, m, c, _state); + ae_frame_leave(_state); + return; + } + + /* + * Task is normalized + */ + ae_vector_set_length(&p, n, _state); + for(i=0; i<=n-1; i++) + { + p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); + } + convc1dcircular(signal, m, &p, n, &b, _state); + ae_vector_set_length(c, m, _state); + ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n)); + if( m-n+1<=m-1 ) + { + ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +A buffered function which does not reallocate C[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircularbuf(/* Complex */ const ae_vector* signal, + ae_int_t m, + /* Complex */ const ae_vector* pattern, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p; + ae_vector b; + ae_int_t i1; + ae_int_t i2; + ae_int_t i; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&p, 0, sizeof(p)); + memset(&b, 0, sizeof(b)); + ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_complex[i1], 1, "N", ae_v_len(0,j2)); + i1 = i1+m; + } + corrc1dcircularbuf(signal, m, &b, m, c, _state); + ae_frame_leave(_state); + return; + } + + /* + * Task is normalized + */ + ae_vector_set_length(&p, n, _state); + for(i=0; i<=n-1; i++) + { + p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state); + } + convc1dcircular(signal, m, &p, n, &b, _state); + callocv(m, c, _state); + ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n)); + if( m-n+1<=m-1 ) + { + ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + pattern to 'search' withing signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(pattern[j]*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(pattern[j]*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrR1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1d(/* Real */ const ae_vector* signal, + ae_int_t n, + /* Real */ const ae_vector* pattern, + ae_int_t m, + /* Real */ ae_vector* r, + ae_state *_state) +{ + + ae_vector_clear(r); + + ae_assert(n>0&&m>0, "CorrR1D: incorrect N or M!", _state); + corrr1dbuf(signal, n, pattern, m, r, _state); +} + + +/************************************************************************* +1-dimensional real cross-correlation, buffered function, which does not +reallocate R[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dbuf(/* Real */ const ae_vector* signal, + ae_int_t n, + /* Real */ const ae_vector* pattern, + ae_int_t m, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p; + ae_vector b; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&p, 0, sizeof(p)); + memset(&b, 0, sizeof(b)); + ae_vector_init(&p, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0&&m>0, "CorrR1DBuf: incorrect N or M!", _state); + ae_vector_set_length(&p, m, _state); + for(i=0; i<=m-1; i++) + { + p.ptr.p_double[m-1-i] = pattern->ptr.p_double[i]; + } + convr1d(&p, m, signal, n, &b, _state); + rallocv(m+n-1, r, _state); + ae_v_move(&r->ptr.p_double[0], 1, &b.ptr.p_double[m-1], 1, ae_v_len(0,n-1)); + if( m+n-2>=n ) + { + ae_v_move(&r->ptr.p_double[n], 1, &b.ptr.p_double[0], 1, ae_v_len(n,m+n-2)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +1-dimensional circular real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + non-periodic pattern to search withing signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrR1DCircularBuf(), + which can reuse space previously allocated in its output parameter C. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircular(/* Real */ const ae_vector* signal, + ae_int_t m, + /* Real */ const ae_vector* pattern, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + + ae_vector_clear(c); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + corrr1dcircularbuf(signal, m, pattern, n, c, _state); +} + + +/************************************************************************* +1-dimensional circular real cross-correlation, buffered version , which +does not reallocate C[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircularbuf(/* Real */ const ae_vector* signal, + ae_int_t m, + /* Real */ const ae_vector* pattern, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p; + ae_vector b; + ae_int_t i1; + ae_int_t i2; + ae_int_t i; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&p, 0, sizeof(p)); + memset(&b, 0, sizeof(b)); + ae_vector_init(&p, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state); + + /* + * normalize task: make M>=N, + * so A will be longer (at least - not shorter) that B. + */ + if( mptr.p_double[i1], 1, ae_v_len(0,j2)); + i1 = i1+m; + } + corrr1dcircularbuf(signal, m, &b, m, c, _state); + ae_frame_leave(_state); + return; + } + + /* + * Task is normalized + */ + ae_vector_set_length(&p, n, _state); + for(i=0; i<=n-1; i++) + { + p.ptr.p_double[n-1-i] = pattern->ptr.p_double[i]; + } + convr1dcircularbuf(signal, m, &p, n, &b, _state); + rallocv(m, c, _state); + ae_v_move(&c->ptr.p_double[0], 1, &b.ptr.p_double[n-1], 1, ae_v_len(0,m-n)); + if( m-n+1<=m-1 ) + { + ae_v_move(&c->ptr.p_double[m-n+1], 1, &b.ptr.p_double[0], 1, ae_v_len(m-n+1,m-1)); + } + ae_frame_leave(_state); +} + + +#endif + +} + diff --git a/core/alglib/fasttransforms.h b/core/alglib/fasttransforms.h index 20f91fff..fe619133 100644 --- a/core/alglib/fasttransforms.h +++ b/core/alglib/fasttransforms.h @@ -1,691 +1,1018 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _fasttransforms_pkg_h -#define _fasttransforms_pkg_h -#include "ap.h" -#include "alglibinternal.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -1-dimensional complex FFT. - -Array size N may be arbitrary number (composite or prime). Composite N's -are handled with cache-oblivious variation of a Cooley-Tukey algorithm. -Small prime-factors are transformed using hard coded codelets (similar to -FFTW codelets, but without low-level optimization), large prime-factors -are handled with Bluestein's algorithm. - -Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), -most fast for powers of 2. When N have prime factors larger than these, -but orders of magnitude smaller than N, computations will be about 4 times -slower than for nearby highly composite N's. When N itself is prime, speed -will be 6 times lower. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1d(complex_1d_array &a, const ae_int_t n); -void fftc1d(complex_1d_array &a); - - -/************************************************************************* -1-dimensional complex inverse FFT. - -Array size N may be arbitrary number (composite or prime). Algorithm has -O(N*logN) complexity for any N (composite or prime). - -See FFTC1D() description for more information about algorithm performance. - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fftc1dinv(complex_1d_array &a, const ae_int_t n); -void fftc1dinv(complex_1d_array &a); - - -/************************************************************************* -1-dimensional real FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - F - DFT of a input array, array[0..N-1] - F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) - -NOTE: - F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half -of array is usually needed. But for convenience subroutine returns full -complex array (with frequencies above N/2), so its result may be used by -other FFT-related subroutines. - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f); -void fftr1d(const real_1d_array &a, complex_1d_array &f); - - -/************************************************************************* -1-dimensional real inverse FFT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - F - array[0..floor(N/2)] - frequencies from forward real FFT - N - problem size - -OUTPUT PARAMETERS - A - inverse DFT of a input array, array[0..N-1] - -NOTE: - F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one -half of frequencies array is needed - elements from 0 to floor(N/2). F[0] -is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then -F[floor(N/2)] has no special properties. - -Relying on properties noted above, FFTR1DInv subroutine uses only elements -from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case -N is even it ignores imaginary part of F[floor(N/2)] too. - -When you call this function using full arguments list - "FFTR1DInv(F,N,A)" -- you can pass either either frequencies array with N elements or reduced -array with roughly N/2 elements - subroutine will successfully transform -both. - -If you call this function using reduced arguments list - "FFTR1DInv(F,A)" -- you must pass FULL array with N elements (although higher N/2 are still -not used) because array size is used to automatically determine FFT length - - - -- ALGLIB -- - Copyright 01.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a); -void fftr1dinv(const complex_1d_array &f, real_1d_array &a); - -/************************************************************************* -1-dimensional complex convolution. - -For given A/B returns conv(A,B) (non-circular). Subroutine can automatically -choose between three implementations: straightforward O(M*N) formula for -very small N (or M), overlap-add algorithm for cases where max(M,N) is -significantly larger than min(M,N), but O(M*N) algorithm is too slow, and -general FFT-based formula for cases where two previois algorithms are too -slow. - -Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. - -INPUT PARAMETERS - A - array[0..M-1] - complex function to be transformed - M - problem size - B - array[0..N-1] - complex function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); - - -/************************************************************************* -1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length, N<=M - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); - - -/************************************************************************* -1-dimensional circular complex convolution. - -For given S/R returns conv(S,R) (circular). Algorithm has linearithmic -complexity for any M/N. - -IMPORTANT: normal convolution is commutative, i.e. it is symmetric - -conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a -signal, periodic function, and another - R - is a response, non-periodic -function with limited length. - -INPUT PARAMETERS - S - array[0..M-1] - complex periodic signal - M - problem size - B - array[0..N-1] - complex non-periodic response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c); - - -/************************************************************************* -1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved periodic signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - non-periodic response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-1]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r); - - -/************************************************************************* -1-dimensional real convolution. - -Analogous to ConvC1D(), see ConvC1D() comments for more details. - -INPUT PARAMETERS - A - array[0..M-1] - real function to be transformed - M - problem size - B - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..N+M-2]. - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); - - -/************************************************************************* -1-dimensional real deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length, N<=M - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that A is zero at T<0, B is zero too. If one or both -functions have non-zero values at negative T's, you can still use this -subroutine - just shift its result correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); - - -/************************************************************************* -1-dimensional circular real convolution. - -Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. - -INPUT PARAMETERS - S - array[0..M-1] - real signal - M - problem size - B - array[0..N-1] - real response - N - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c); - - -/************************************************************************* -1-dimensional complex deconvolution (inverse of ConvC1D()). - -Algorithm has M*log(M)) complexity for any M (composite or prime). - -INPUT PARAMETERS - A - array[0..M-1] - convolved signal, A = conv(R, B) - M - convolved signal length - B - array[0..N-1] - response - N - response length - -OUTPUT PARAMETERS - R - deconvolved signal. array[0..M-N]. - -NOTE: - deconvolution is unstable process and may result in division by zero -(if your response function is degenerate, i.e. has zero Fourier coefficient). - -NOTE: - It is assumed that B is zero at T<0. If it has non-zero values at -negative T's, you can still use this subroutine - just shift its result -correspondingly. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r); - -/************************************************************************* -1-dimensional complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(conj(pattern[j])*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r); - - -/************************************************************************* -1-dimensional circular complex cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - complex function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - complex function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c); - - -/************************************************************************* -1-dimensional real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). - -Correlation is calculated using reduction to convolution. Algorithm with -max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info -about performance). - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional - definition of cross-correlation, denoting cross-correlation as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - cross-correlation, array[0..N+M-2]: - * positive lags are stored in R[0..N-1], - R[i] = sum(pattern[j]*signal[i+j] - * negative lags are stored in R[N..N+M-2], - R[N+M-1-i] = sum(pattern[j]*signal[-i+j] - -NOTE: - It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero -on [-K..M-1], you can still use this subroutine, just shift result by K. - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r); - - -/************************************************************************* -1-dimensional circular real cross-correlation. - -For given Pattern/Signal returns corr(Pattern,Signal) (circular). -Algorithm has linearithmic complexity for any M/N. - -IMPORTANT: - for historical reasons subroutine accepts its parameters in reversed - order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using - traditional definition of cross-correlation, denoting cross-correlation - as "x"). - -INPUT PARAMETERS - Signal - array[0..N-1] - real function to be transformed, - periodic signal containing pattern - N - problem size - Pattern - array[0..M-1] - real function to be transformed, - non-periodic pattern to search within signal - M - problem size - -OUTPUT PARAMETERS - R - convolution: A*B. array[0..M-1]. - - - -- ALGLIB -- - Copyright 21.07.2009 by Bochkanov Sergey -*************************************************************************/ -void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c); - -/************************************************************************* -1-dimensional Fast Hartley Transform. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - real function to be transformed - N - problem size - -OUTPUT PARAMETERS - A - FHT of a input array, array[0..N-1], - A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) - - - -- ALGLIB -- - Copyright 04.06.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1d(real_1d_array &a, const ae_int_t n); - - -/************************************************************************* -1-dimensional inverse FHT. - -Algorithm has O(N*logN) complexity for any N (composite or prime). - -INPUT PARAMETERS - A - array[0..N-1] - complex array to be transformed - N - problem size - -OUTPUT PARAMETERS - A - inverse FHT of a input array, array[0..N-1] - - - -- ALGLIB -- - Copyright 29.05.2009 by Bochkanov Sergey -*************************************************************************/ -void fhtr1dinv(real_1d_array &a, const ae_int_t n); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); -void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); -void fftr1d(/* Real */ ae_vector* a, - ae_int_t n, - /* Complex */ ae_vector* f, - ae_state *_state); -void fftr1dinv(/* Complex */ ae_vector* f, - ae_int_t n, - /* Real */ ae_vector* a, - ae_state *_state); -void fftr1dinternaleven(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* buf, - fasttransformplan* plan, - ae_state *_state); -void fftr1dinvinternaleven(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* buf, - fasttransformplan* plan, - ae_state *_state); -void convc1d(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Complex */ ae_vector* r, - ae_state *_state); -void convc1dinv(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Complex */ ae_vector* r, - ae_state *_state); -void convc1dcircular(/* Complex */ ae_vector* s, - ae_int_t m, - /* Complex */ ae_vector* r, - ae_int_t n, - /* Complex */ ae_vector* c, - ae_state *_state); -void convc1dcircularinv(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - /* Complex */ ae_vector* r, - ae_state *_state); -void convr1d(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* r, - ae_state *_state); -void convr1dinv(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* r, - ae_state *_state); -void convr1dcircular(/* Real */ ae_vector* s, - ae_int_t m, - /* Real */ ae_vector* r, - ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -void convr1dcircularinv(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - /* Real */ ae_vector* r, - ae_state *_state); -void convc1dx(/* Complex */ ae_vector* a, - ae_int_t m, - /* Complex */ ae_vector* b, - ae_int_t n, - ae_bool circular, - ae_int_t alg, - ae_int_t q, - /* Complex */ ae_vector* r, - ae_state *_state); -void convr1dx(/* Real */ ae_vector* a, - ae_int_t m, - /* Real */ ae_vector* b, - ae_int_t n, - ae_bool circular, - ae_int_t alg, - ae_int_t q, - /* Real */ ae_vector* r, - ae_state *_state); -void corrc1d(/* Complex */ ae_vector* signal, - ae_int_t n, - /* Complex */ ae_vector* pattern, - ae_int_t m, - /* Complex */ ae_vector* r, - ae_state *_state); -void corrc1dcircular(/* Complex */ ae_vector* signal, - ae_int_t m, - /* Complex */ ae_vector* pattern, - ae_int_t n, - /* Complex */ ae_vector* c, - ae_state *_state); -void corrr1d(/* Real */ ae_vector* signal, - ae_int_t n, - /* Real */ ae_vector* pattern, - ae_int_t m, - /* Real */ ae_vector* r, - ae_state *_state); -void corrr1dcircular(/* Real */ ae_vector* signal, - ae_int_t m, - /* Real */ ae_vector* pattern, - ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); -void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _fasttransforms_pkg_h +#define _fasttransforms_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex FFT. + +Array size N may be arbitrary number (composite or prime). Composite N's +are handled with cache-oblivious variation of a Cooley-Tukey algorithm. +Small prime-factors are transformed using hard coded codelets (similar to +FFTW codelets, but without low-level optimization), large prime-factors +are handled with Bluestein's algorithm. + +Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only), +most fast for powers of 2. When N have prime factors larger than these, +but orders of magnitude smaller than N, computations will be about 4 times +slower than for nearby highly composite N's. When N itself is prime, speed +will be 6 times lower. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1d(complex_1d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +void fftc1d(complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex inverse FFT. + +Array size N may be arbitrary number (composite or prime). Algorithm has +O(N*logN) complexity for any N (composite or prime). + +See FFTC1D() description for more information about algorithm performance. + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fftc1dinv(complex_1d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +void fftc1dinv(complex_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + F - DFT of a input array, array[0..N-1] + F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1) + +NOTE: there is a buffered version of this function, FFTR1DBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half +of array is usually needed. But for convinience subroutine returns full +complex array (with frequencies above N/2), so its result may be used by +other FFT-related subroutines. + + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams = alglib::xdefault); +void fftr1d(const real_1d_array &a, complex_1d_array &f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real FFT, a buffered function which does not reallocate F[] +if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dbuf(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams = alglib::xdefault); +void fftr1dbuf(const real_1d_array &a, complex_1d_array &f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real inverse FFT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + F - array[0..floor(N/2)] - frequencies from forward real FFT + N - problem size + +OUTPUT PARAMETERS + A - inverse DFT of a input array, array[0..N-1] + +NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which + reuses memory previously allocated for A as much as possible. + +NOTE: + F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one +half of frequencies array is needed - elements from 0 to floor(N/2). F[0] +is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then +F[floor(N/2)] has no special properties. + +Relying on properties noted above, FFTR1DInv subroutine uses only elements +from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case +N is even it ignores imaginary part of F[floor(N/2)] too. + +When you call this function using full arguments list - "FFTR1DInv(F,N,A)" +- you can pass either either frequencies array with N elements or reduced +array with roughly N/2 elements - subroutine will successfully transform +both. + +If you call this function using reduced arguments list - "FFTR1DInv(F,A)" +- you must pass FULL array with N elements (although higher N/2 are still +not used) because array size is used to automatically determine FFT length + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams = alglib::xdefault); +void fftr1dinv(const complex_1d_array &f, real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real inverse FFT, buffered version, which does not reallocate +A[] if its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 01.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fftr1dinvbuf(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams = alglib::xdefault); +void fftr1dinvbuf(const complex_1d_array &f, real_1d_array &a, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional Fast Hartley Transform. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + A - FHT of a input array, array[0..N-1], + A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1) + + + -- ALGLIB -- + Copyright 04.06.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1d(real_1d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional inverse FHT. + +Algorithm has O(N*logN) complexity for any N (composite or prime). + +INPUT PARAMETERS + A - array[0..N-1] - complex array to be transformed + N - problem size + +OUTPUT PARAMETERS + A - inverse FHT of a input array, array[0..N-1] + + + -- ALGLIB -- + Copyright 29.05.2009 by Bochkanov Sergey +*************************************************************************/ +void fhtr1dinv(real_1d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex convolution. + +For given A/B returns conv(A,B) (non-circular). Subroutine can automatically +choose between three implementations: straightforward O(M*N) formula for +very small N (or M), overlap-add algorithm for cases where max(M,N) is +significantly larger than min(M,N), but O(M*N) algorithm is too slow, and +general FFT-based formula for cases where two previous algorithms are too +slow. + +Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N. + +INPUT PARAMETERS + A - array[M] - complex function to be transformed + M - problem size + B - array[N] - complex function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[N+M-1] + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both + functions have non-zero values at negative T's, you can still use this + subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex convolution, buffered version of ConvC1DBuf(), which +does not reallocate R[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length, N<=M + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DInvBuf(), + which can reuse space previously allocated in its output parameter R + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex non-circular deconvolution (inverse of ConvC1D()). + +A buffered version, which does not reallocate R[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex convolution. + +For given S/R returns conv(S,R) (circular). Algorithm has linearithmic +complexity for any M/N. + +IMPORTANT: normal convolution is commutative, i.e. it is symmetric - +conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a +signal, periodic function, and another - R - is a response, non-periodic +function with limited length. + +INPUT PARAMETERS + S - array[M] - complex periodic signal + M - problem size + B - array[N] - complex non-periodic response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[M]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex convolution. + +Buffered version of ConvC1DCircular(), which does not reallocate C[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularbuf(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved periodic signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - non-periodic response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-1]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()). + +Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if +its length is enough to store the result (i.e. it reuses previously +allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convc1dcircularinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real convolution. + +Analogous to ConvC1D(), see ConvC1D() comments for more details. + +INPUT PARAMETERS + A - array[0..M-1] - real function to be transformed + M - problem size + B - array[0..N-1] - real function to be transformed + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..N+M-2]. + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DBuf(), + which can reuse space previously allocated in its output parameter R. + + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real convolution. + +Buffered version of ConvR1D(), which does not reallocate R[] if its length +is enough to store the result (i.e. it reuses previously allocated memory +as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length, N<=M + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that A is zero at T<0, B is zero too. If one or both +functions have non-zero values at negative T's, you can still use this +subroutine - just shift its result correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DInvBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real deconvolution (inverse of ConvR1D()), buffered version, +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular real convolution. + +Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details. + +INPUT PARAMETERS + S - array[0..M-1] - real signal + M - problem size + B - array[0..N-1] - real response + N - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + +NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular real convolution, buffered version, which does not +reallocate C[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 30.11.2023 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularbuf(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex deconvolution (inverse of ConvC1D()). + +Algorithm has M*log(M)) complexity for any M (composite or prime). + +INPUT PARAMETERS + A - array[0..M-1] - convolved signal, A = conv(R, B) + M - convolved signal length + B - array[0..N-1] - response + N - response length + +OUTPUT PARAMETERS + R - deconvolved signal. array[0..M-N]. + +NOTE: + deconvolution is unstable process and may result in division by zero +(if your response function is degenerate, i.e. has zero Fourier coefficient). + +NOTE: + It is assumed that B is zero at T<0. If it has non-zero values at +negative T's, you can still use this subroutine - just shift its result +correspondingly. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex deconvolution, inverse of ConvR1DCircular(). + +Buffered version, which does not reallocate R[] if its length is enough to +store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void convr1dcircularinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +1-dimensional complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(conj(pattern[j])*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrC1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional complex cross-correlation, a buffered version of CorrC1D() +which does not reallocate R[] if its length is enough to store the result +(i.e. it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dbuf(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - complex function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - complex function to be transformed, + non-periodic pattern to 'search' within a signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrC1DCircular(), + which can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular complex cross-correlation. + +A buffered function which does not reallocate C[] if its length is enough +to store the result (i.e. it reuses previously allocated memory as much as +possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrc1dcircularbuf(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (non-circular). + +Correlation is calculated using reduction to convolution. Algorithm with +max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info +about performance). + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional + definition of cross-correlation, denoting cross-correlation as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + pattern to 'search' withing signal + M - problem size + +OUTPUT PARAMETERS + R - cross-correlation, array[0..N+M-2]: + * positive lags are stored in R[0..N-1], + R[i] = sum(pattern[j]*signal[i+j] + * negative lags are stored in R[N..N+M-2], + R[N+M-1-i] = sum(pattern[j]*signal[-i+j] + +NOTE: + It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero +on [-K..M-1], you can still use this subroutine, just shift result by K. + +NOTE: there is a buffered version of this function, CorrR1DBuf(), which + can reuse space previously allocated in its output parameter R. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional real cross-correlation, buffered function, which does not +reallocate R[] if its length is enough to store the result (i.e. it reuses +previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dbuf(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular real cross-correlation. + +For given Pattern/Signal returns corr(Pattern,Signal) (circular). +Algorithm has linearithmic complexity for any M/N. + +IMPORTANT: + for historical reasons subroutine accepts its parameters in reversed + order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using + traditional definition of cross-correlation, denoting cross-correlation + as "x"). + +INPUT PARAMETERS + Signal - array[0..N-1] - real function to be transformed, + periodic signal containing pattern + N - problem size + Pattern - array[0..M-1] - real function to be transformed, + non-periodic pattern to search withing signal + M - problem size + +OUTPUT PARAMETERS + R - convolution: A*B. array[0..M-1]. + +NOTE: there is a buffered version of this function, CorrR1DCircularBuf(), + which can reuse space previously allocated in its output parameter C. + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +1-dimensional circular real cross-correlation, buffered version , which +does not reallocate C[] if its length is enough to store the result (i.e. +it reuses previously allocated memory as much as possible). + + -- ALGLIB -- + Copyright 21.07.2009 by Bochkanov Sergey +*************************************************************************/ +void corrr1dcircularbuf(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD) +void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); +void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state); +void fftr1d(/* Real */ const ae_vector* a, + ae_int_t n, + /* Complex */ ae_vector* f, + ae_state *_state); +void fftr1dbuf(/* Real */ const ae_vector* a, + ae_int_t n, + /* Complex */ ae_vector* f, + ae_state *_state); +void fftr1dinv(/* Complex */ const ae_vector* f, + ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state); +void fftr1dinvbuf(/* Complex */ const ae_vector* f, + ae_int_t n, + /* Real */ ae_vector* a, + ae_state *_state); +void fftr1dinternaleven(/* Real */ ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* buf, + fasttransformplan* plan, + ae_state *_state); +void fftr1dinvinternaleven(/* Real */ ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* buf, + fasttransformplan* plan, + ae_state *_state); +#endif +#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD) +void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); +void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state); +#endif +#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD) +void convc1d(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convc1dbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convc1dinv(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convc1dinvbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convc1dcircular(/* Complex */ const ae_vector* s, + ae_int_t m, + /* Complex */ const ae_vector* r, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state); +void convc1dcircularbuf(/* Complex */ const ae_vector* s, + ae_int_t m, + /* Complex */ const ae_vector* r, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state); +void convc1dcircularinv(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convc1dcircularinvbuf(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + /* Complex */ ae_vector* r, + ae_state *_state); +void convr1d(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convr1dbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convr1dinv(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convr1dinvbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convr1dcircular(/* Real */ const ae_vector* s, + ae_int_t m, + /* Real */ const ae_vector* r, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +void convr1dcircularbuf(/* Real */ const ae_vector* s, + ae_int_t m, + /* Real */ const ae_vector* r, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +void convr1dcircularinv(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convr1dcircularinvbuf(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + /* Real */ ae_vector* r, + ae_state *_state); +void convc1dx(/* Complex */ const ae_vector* a, + ae_int_t m, + /* Complex */ const ae_vector* b, + ae_int_t n, + ae_bool circular, + ae_int_t alg, + ae_int_t q, + /* Complex */ ae_vector* r, + ae_state *_state); +void convr1dx(/* Real */ const ae_vector* a, + ae_int_t m, + /* Real */ const ae_vector* b, + ae_int_t n, + ae_bool circular, + ae_int_t alg, + ae_int_t q, + /* Real */ ae_vector* r, + ae_state *_state); +#endif +#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD) +void corrc1d(/* Complex */ const ae_vector* signal, + ae_int_t n, + /* Complex */ const ae_vector* pattern, + ae_int_t m, + /* Complex */ ae_vector* r, + ae_state *_state); +void corrc1dbuf(/* Complex */ const ae_vector* signal, + ae_int_t n, + /* Complex */ const ae_vector* pattern, + ae_int_t m, + /* Complex */ ae_vector* r, + ae_state *_state); +void corrc1dcircular(/* Complex */ const ae_vector* signal, + ae_int_t m, + /* Complex */ const ae_vector* pattern, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state); +void corrc1dcircularbuf(/* Complex */ const ae_vector* signal, + ae_int_t m, + /* Complex */ const ae_vector* pattern, + ae_int_t n, + /* Complex */ ae_vector* c, + ae_state *_state); +void corrr1d(/* Real */ const ae_vector* signal, + ae_int_t n, + /* Real */ const ae_vector* pattern, + ae_int_t m, + /* Real */ ae_vector* r, + ae_state *_state); +void corrr1dbuf(/* Real */ const ae_vector* signal, + ae_int_t n, + /* Real */ const ae_vector* pattern, + ae_int_t m, + /* Real */ ae_vector* r, + ae_state *_state); +void corrr1dcircular(/* Real */ const ae_vector* signal, + ae_int_t m, + /* Real */ const ae_vector* pattern, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +void corrr1dcircularbuf(/* Real */ const ae_vector* signal, + ae_int_t m, + /* Real */ const ae_vector* pattern, + ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +#endif + +} +#endif + diff --git a/core/alglib/integration.cpp b/core/alglib/integration.cpp index 2745889a..3d2126ff 100644 --- a/core/alglib/integration.cpp +++ b/core/alglib/integration.cpp @@ -1,3961 +1,4252 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "integration.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Computation of nodes and weights for a Gauss quadrature formula - -The algorithm generates the N-point Gauss quadrature formula with weight -function given by coefficients alpha and beta of a recurrence relation -which generates a system of orthogonal polynomials: - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-1], alpha coefficients - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the quadrature formula, N>=1 - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgeneraterec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Computation of nodes and weights for a Gauss-Lobatto quadrature formula - -The algorithm generates the N-point Gauss-Lobatto quadrature formula with -weight function given by coefficients alpha and beta of a recurrence which -generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients - Beta – array[0..N-2], beta coefficients. - Zero-indexed element is not used, may be arbitrary. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - B – right boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=3 - (including the left and right boundary nodes). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategausslobattorec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, a, b, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Computation of nodes and weights for a Gauss-Radau quadrature formula - -The algorithm generates the N-point Gauss-Radau quadrature formula with -weight function given by the coefficients alpha and beta of a recurrence -which generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients. - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=2 - (including the left boundary node). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategaussradaurec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, a, n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N -nodes. - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategausslegendre(n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight -function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha/Beta was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategaussjacobi(n, alpha, beta, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with -weight function W(x)=Power(x,Alpha)*Exp(-x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha is too close to -1 to - obtain weights/nodes with high enough accuracy - or, may be, N is too large. Try to use - multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategausslaguerre(n, alpha, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with -weight function W(x)=Exp(-x*x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. May be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gqgenerategausshermite(n, &info, const_cast(x.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Computation of nodes and weights of a Gauss-Kronrod quadrature formula - -The algorithm generates the N-point Gauss-Kronrod quadrature formula with -weight function given by coefficients alpha and beta of a recurrence -relation which generates a system of orthogonal polynomials: - - P-1(x) = 0 - P0(x) = 1 - Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zero moment Mu0 - - Mu0 = integral(W(x)dx,a,b) - - -INPUT PARAMETERS: - Alpha – alpha coefficients, array[0..floor(3*K/2)]. - Beta – beta coefficients, array[0..ceil(3*K/2)]. - Beta[0] is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the Gauss-Kronrod quadrature formula, - N >= 3, - N = 2*K+1. - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 N is too large, task may be ill conditioned - - x[i]=x[i+1] found. - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 08.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gkqgeneraterec(const_cast(alpha.c_ptr()), const_cast(beta.c_ptr()), mu0, n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre -quadrature with N points. - -GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is -used depending on machine precision and number of nodes. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gkqgenerategausslegendre(n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi -quadrature on [-1,1] with weight function - - W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - * +2 OK, but quadrature rule have exterior nodes, - x[0]<-1 or x[n-1]>+1 - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gkqgenerategaussjacobi(n, alpha, beta, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. - -Reduction to tridiagonal eigenproblem is used. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gkqlegendrecalc(n, &info, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using -pre-calculated table. Nodes/weights were computed with accuracy up to -1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision -accuracy reduces to something about 2.0E-16 (depending on your compiler's -handling of long floating point constants). - -INPUT PARAMETERS: - N - number of Kronrod nodes. - N can be 15, 21, 31, 41, 51, 61. - -OUTPUT PARAMETERS: - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::gkqlegendretbl(n, const_cast(x.c_ptr()), const_cast(wkronrod.c_ptr()), const_cast(wgauss.c_ptr()), &eps, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Integration report: -* TerminationType = completion code: - * -5 non-convergence of Gauss-Kronrod nodes - calculation subroutine. - * -1 incorrect parameters were specified - * 1 OK -* Rep.NFEV contains number of function calculations -* Rep.NIntervals contains number of intervals [a,b] - was partitioned into. -*************************************************************************/ -_autogkreport_owner::_autogkreport_owner() -{ - p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_autogkreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_autogkreport_owner::_autogkreport_owner(const _autogkreport_owner &rhs) -{ - p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_autogkreport_owner& _autogkreport_owner::operator=(const _autogkreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_autogkreport_clear(p_struct); - if( !alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_autogkreport_owner::~_autogkreport_owner() -{ - alglib_impl::_autogkreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::autogkreport* _autogkreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::autogkreport* _autogkreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -autogkreport::autogkreport() : _autogkreport_owner() ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) -{ -} - -autogkreport::autogkreport(const autogkreport &rhs):_autogkreport_owner(rhs) ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) -{ -} - -autogkreport& autogkreport::operator=(const autogkreport &rhs) -{ - if( this==&rhs ) - return *this; - _autogkreport_owner::operator=(rhs); - return *this; -} - -autogkreport::~autogkreport() -{ -} - - -/************************************************************************* -This structure stores state of the integration algorithm. - -Although this class has public fields, they are not intended for external -use. You should use ALGLIB functions to work with this class: -* autogksmooth()/AutoGKSmoothW()/... to create objects -* autogkintegrate() to begin integration -* autogkresults() to get results -*************************************************************************/ -_autogkstate_owner::_autogkstate_owner() -{ - p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_autogkstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_autogkstate_owner::_autogkstate_owner(const _autogkstate_owner &rhs) -{ - p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_autogkstate_owner& _autogkstate_owner::operator=(const _autogkstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_autogkstate_clear(p_struct); - if( !alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_autogkstate_owner::~_autogkstate_owner() -{ - alglib_impl::_autogkstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::autogkstate* _autogkstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::autogkstate* _autogkstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -autogkstate::autogkstate() : _autogkstate_owner() ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) -{ -} - -autogkstate::autogkstate(const autogkstate &rhs):_autogkstate_owner(rhs) ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) -{ -} - -autogkstate& autogkstate::operator=(const autogkstate &rhs) -{ - if( this==&rhs ) - return *this; - _autogkstate_owner::operator=(rhs); - return *this; -} - -autogkstate::~autogkstate() -{ -} - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -Algorithm works well only with smooth integrands. It may be used with -continuous non-smooth integrands, but with less performance. - -It should never be used with integrands which have integrable singularities -at lower or upper limits - algorithm may crash. Use AutoGKSingular in such -cases. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmooth(const double a, const double b, autogkstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::autogksmooth(a, b, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -This subroutine is same as AutoGKSmooth(), but it guarantees that interval -[a,b] is partitioned into subintervals which have width at most XWidth. - -Subroutine can be used when integrating nearly-constant function with -narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth -subroutine can overlook them. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::autogksmoothw(a, b, xwidth, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Integration on a finite interval [A,B]. -Integrand have integrable singularities at A/B. - -F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known -alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates -from below can be used (but these estimates should be greater than -1 too). - -One of alpha/beta variables (or even both alpha/beta) may be equal to 0, -which means than function F(x) is non-singular at A/B. Anyway (singular at -bounds or not), function F(x) is supposed to be continuous on (A,B). - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - Alpha - power-law coefficient of the F(x) at A, - Alpha>-1 - Beta - power-law coefficient of the F(x) at B, - Beta>-1 - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSmoothW, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::autogksingular(a, b, alpha, beta, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool autogkiteration(const autogkstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::autogkiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void autogkintegrate(autogkstate &state, - void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), - void *ptr){ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'autogkintegrate()' (func is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::autogkiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.xminusa, state.bminusx, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: unexpected error in 'autogkintegrate()'"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -Adaptive integration results - -Called after AutoGKIteration returned False. - -Input parameters: - State - algorithm state (used by AutoGKIteration). - -Output parameters: - V - integral(f(x)dx,a,b) - Rep - optimization report (see AutoGKReport description) - - -- ALGLIB -- - Copyright 14.11.2007 by Bochkanov Sergey -*************************************************************************/ -void autogkresults(const autogkstate &state, double &v, autogkreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::autogkresults(const_cast(state.c_ptr()), &v, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - - - - -static ae_int_t autogk_maxsubintervals = 10000; -static void autogk_autogkinternalprepare(double a, - double b, - double eps, - double xwidth, - autogkinternalstate* state, - ae_state *_state); -static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, - ae_state *_state); -static void autogk_mheappop(/* Real */ ae_matrix* heap, - ae_int_t heapsize, - ae_int_t heapwidth, - ae_state *_state); -static void autogk_mheappush(/* Real */ ae_matrix* heap, - ae_int_t heapsize, - ae_int_t heapwidth, - ae_state *_state); -static void autogk_mheapresize(/* Real */ ae_matrix* heap, - ae_int_t* heapsize, - ae_int_t newheapsize, - ae_int_t heapwidth, - ae_state *_state); - - - - - -/************************************************************************* -Computation of nodes and weights for a Gauss quadrature formula - -The algorithm generates the N-point Gauss quadrature formula with weight -function given by coefficients alpha and beta of a recurrence relation -which generates a system of orthogonal polynomials: - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-1], alpha coefficients - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the quadrature formula, N>=1 - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgeneraterec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector d; - ae_vector e; - ae_matrix z; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); - - if( n<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Initialize - */ - ae_vector_set_length(&d, n, _state); - ae_vector_set_length(&e, n, _state); - for(i=1; i<=n-1; i++) - { - d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; - if( ae_fp_less_eq(beta->ptr.p_double[i],0) ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); - } - d.ptr.p_double[n-1] = alpha->ptr.p_double[n-1]; - - /* - * EVD - */ - if( !smatrixtdevd(&d, &e, n, 3, &z, _state) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Generate - */ - ae_vector_set_length(x, n, _state); - ae_vector_set_length(w, n, _state); - for(i=1; i<=n; i++) - { - x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; - w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Computation of nodes and weights for a Gauss-Lobatto quadrature formula - -The algorithm generates the N-point Gauss-Lobatto quadrature formula with -weight function given by coefficients alpha and beta of a recurrence which -generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients - Beta – array[0..N-2], beta coefficients. - Zero-indexed element is not used, may be arbitrary. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - B – right boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=3 - (including the left and right boundary nodes). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslobattorec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - double a, - double b, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _alpha; - ae_vector _beta; - ae_int_t i; - ae_vector d; - ae_vector e; - ae_matrix z; - double pim1a; - double pia; - double pim1b; - double pib; - double t; - double a11; - double a12; - double a21; - double a22; - double b1; - double b2; - double alph; - double bet; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_alpha, alpha, _state, ae_true); - alpha = &_alpha; - ae_vector_init_copy(&_beta, beta, _state, ae_true); - beta = &_beta; - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); - - if( n<=2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Initialize, D[1:N+1], E[1:N] - */ - n = n-2; - ae_vector_set_length(&d, n+2, _state); - ae_vector_set_length(&e, n+1, _state); - for(i=1; i<=n+1; i++) - { - d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; - } - for(i=1; i<=n; i++) - { - if( ae_fp_less_eq(beta->ptr.p_double[i],0) ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); - } - - /* - * Caclulate Pn(a), Pn+1(a), Pn(b), Pn+1(b) - */ - beta->ptr.p_double[0] = 0; - pim1a = 0; - pia = 1; - pim1b = 0; - pib = 1; - for(i=1; i<=n+1; i++) - { - - /* - * Pi(a) - */ - t = (a-alpha->ptr.p_double[i-1])*pia-beta->ptr.p_double[i-1]*pim1a; - pim1a = pia; - pia = t; - - /* - * Pi(b) - */ - t = (b-alpha->ptr.p_double[i-1])*pib-beta->ptr.p_double[i-1]*pim1b; - pim1b = pib; - pib = t; - } - - /* - * Calculate alpha'(n+1), beta'(n+1) - */ - a11 = pia; - a12 = pim1a; - a21 = pib; - a22 = pim1b; - b1 = a*pia; - b2 = b*pib; - if( ae_fp_greater(ae_fabs(a11, _state),ae_fabs(a21, _state)) ) - { - a22 = a22-a12*a21/a11; - b2 = b2-b1*a21/a11; - bet = b2/a22; - alph = (b1-bet*a12)/a11; - } - else - { - a12 = a12-a22*a11/a21; - b1 = b1-b2*a11/a21; - bet = b1/a12; - alph = (b2-bet*a22)/a21; - } - if( ae_fp_less(bet,0) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - d.ptr.p_double[n+1] = alph; - e.ptr.p_double[n] = ae_sqrt(bet, _state); - - /* - * EVD - */ - if( !smatrixtdevd(&d, &e, n+2, 3, &z, _state) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Generate - */ - ae_vector_set_length(x, n+2, _state); - ae_vector_set_length(w, n+2, _state); - for(i=1; i<=n+2; i++) - { - x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; - w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Computation of nodes and weights for a Gauss-Radau quadrature formula - -The algorithm generates the N-point Gauss-Radau quadrature formula with -weight function given by the coefficients alpha and beta of a recurrence -which generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients. - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=2 - (including the left boundary node). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussradaurec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - double a, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _alpha; - ae_vector _beta; - ae_int_t i; - ae_vector d; - ae_vector e; - ae_matrix z; - double polim1; - double poli; - double t; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_alpha, alpha, _state, ae_true); - alpha = &_alpha; - ae_vector_init_copy(&_beta, beta, _state, ae_true); - beta = &_beta; - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); - - if( n<2 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * Initialize, D[1:N], E[1:N] - */ - n = n-1; - ae_vector_set_length(&d, n+1, _state); - ae_vector_set_length(&e, n, _state); - for(i=1; i<=n; i++) - { - d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; - if( ae_fp_less_eq(beta->ptr.p_double[i],0) ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); - } - - /* - * Caclulate Pn(a), Pn-1(a), and D[N+1] - */ - beta->ptr.p_double[0] = 0; - polim1 = 0; - poli = 1; - for(i=1; i<=n; i++) - { - t = (a-alpha->ptr.p_double[i-1])*poli-beta->ptr.p_double[i-1]*polim1; - polim1 = poli; - poli = t; - } - d.ptr.p_double[n] = a-beta->ptr.p_double[n]*polim1/poli; - - /* - * EVD - */ - if( !smatrixtdevd(&d, &e, n+1, 3, &z, _state) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Generate - */ - ae_vector_set_length(x, n+1, _state); - ae_vector_set_length(w, n+1, _state); - for(i=1; i<=n+1; i++) - { - x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; - w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N -nodes. - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslegendre(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector alpha; - ae_vector beta; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&alpha, 0, DT_REAL, _state, ae_true); - ae_vector_init(&beta, 0, DT_REAL, _state, ae_true); - - if( n<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&alpha, n, _state); - ae_vector_set_length(&beta, n, _state); - for(i=0; i<=n-1; i++) - { - alpha.ptr.p_double[i] = 0; - } - beta.ptr.p_double[0] = 2; - for(i=1; i<=n-1; i++) - { - beta.ptr.p_double[i] = 1/(4-1/ae_sqr(i, _state)); - } - gqgeneraterec(&alpha, &beta, beta.ptr.p_double[0], n, info, x, w, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - if( ae_fp_less(x->ptr.p_double[0],-1)||ae_fp_greater(x->ptr.p_double[n-1],1) ) - { - *info = -4; - } - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight -function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha/Beta was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussjacobi(ae_int_t n, - double alpha, - double beta, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector a; - ae_vector b; - double alpha2; - double beta2; - double apb; - double t; - ae_int_t i; - double s; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&a, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - if( (n<1||ae_fp_less_eq(alpha,-1))||ae_fp_less_eq(beta,-1) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&a, n, _state); - ae_vector_set_length(&b, n, _state); - apb = alpha+beta; - a.ptr.p_double[0] = (beta-alpha)/(apb+2); - t = (apb+1)*ae_log(2, _state)+lngamma(alpha+1, &s, _state)+lngamma(beta+1, &s, _state)-lngamma(apb+2, &s, _state); - if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - b.ptr.p_double[0] = ae_exp(t, _state); - if( n>1 ) - { - alpha2 = ae_sqr(alpha, _state); - beta2 = ae_sqr(beta, _state); - a.ptr.p_double[1] = (beta2-alpha2)/((apb+2)*(apb+4)); - b.ptr.p_double[1] = 4*(alpha+1)*(beta+1)/((apb+3)*ae_sqr(apb+2, _state)); - for(i=2; i<=n-1; i++) - { - a.ptr.p_double[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i)); - b.ptr.p_double[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*ae_sqr(1+0.5*apb/i, _state)); - } - } - gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - if( ae_fp_less(x->ptr.p_double[0],-1)||ae_fp_greater(x->ptr.p_double[n-1],1) ) - { - *info = -4; - } - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with -weight function W(x)=Power(x,Alpha)*Exp(-x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha is too close to -1 to - obtain weights/nodes with high enough accuracy - or, may be, N is too large. Try to use - multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslaguerre(ae_int_t n, - double alpha, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector a; - ae_vector b; - double t; - ae_int_t i; - double s; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&a, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - if( n<1||ae_fp_less_eq(alpha,-1) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&a, n, _state); - ae_vector_set_length(&b, n, _state); - a.ptr.p_double[0] = alpha+1; - t = lngamma(alpha+1, &s, _state); - if( ae_fp_greater_eq(t,ae_log(ae_maxrealnumber, _state)) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - b.ptr.p_double[0] = ae_exp(t, _state); - if( n>1 ) - { - for(i=1; i<=n-1; i++) - { - a.ptr.p_double[i] = 2*i+alpha+1; - b.ptr.p_double[i] = i*(i+alpha); - } - } - gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - if( ae_fp_less(x->ptr.p_double[0],0) ) - { - *info = -4; - } - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with -weight function W(x)=Exp(-x*x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. May be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausshermite(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector a; - ae_vector b; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(w); - ae_vector_init(&a, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - if( n<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&a, n, _state); - ae_vector_set_length(&b, n, _state); - for(i=0; i<=n-1; i++) - { - a.ptr.p_double[i] = 0; - } - b.ptr.p_double[0] = ae_sqrt(4*ae_atan(1, _state), _state); - if( n>1 ) - { - for(i=1; i<=n-1; i++) - { - b.ptr.p_double[i] = 0.5*i; - } - } - gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Computation of nodes and weights of a Gauss-Kronrod quadrature formula - -The algorithm generates the N-point Gauss-Kronrod quadrature formula with -weight function given by coefficients alpha and beta of a recurrence -relation which generates a system of orthogonal polynomials: - - P-1(x) = 0 - P0(x) = 1 - Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zero moment Mu0 - - Mu0 = integral(W(x)dx,a,b) - - -INPUT PARAMETERS: - Alpha – alpha coefficients, array[0..floor(3*K/2)]. - Beta – beta coefficients, array[0..ceil(3*K/2)]. - Beta[0] is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the Gauss-Kronrod quadrature formula, - N >= 3, - N = 2*K+1. - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 N is too large, task may be ill conditioned - - x[i]=x[i+1] found. - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 08.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgeneraterec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _alpha; - ae_vector _beta; - ae_vector ta; - ae_int_t i; - ae_int_t j; - ae_vector t; - ae_vector s; - ae_int_t wlen; - ae_int_t woffs; - double u; - ae_int_t m; - ae_int_t l; - ae_int_t k; - ae_vector xgtmp; - ae_vector wgtmp; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_alpha, alpha, _state, ae_true); - alpha = &_alpha; - ae_vector_init_copy(&_beta, beta, _state, ae_true); - beta = &_beta; - *info = 0; - ae_vector_clear(x); - ae_vector_clear(wkronrod); - ae_vector_clear(wgauss); - ae_vector_init(&ta, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xgtmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wgtmp, 0, DT_REAL, _state, ae_true); - - if( n%2!=1||n<3 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=ae_iceil((double)(3*(n/2))/(double)2, _state); i++) - { - if( ae_fp_less_eq(beta->ptr.p_double[i],0) ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - } - *info = 1; - - /* - * from external conventions about N/Beta/Mu0 to internal - */ - n = n/2; - beta->ptr.p_double[0] = mu0; - - /* - * Calculate Gauss nodes/weights, save them for later processing - */ - gqgeneraterec(alpha, beta, mu0, n, info, &xgtmp, &wgtmp, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Resize: - * * A from 0..floor(3*n/2) to 0..2*n - * * B from 0..ceil(3*n/2) to 0..2*n - */ - ae_vector_set_length(&ta, ae_ifloor((double)(3*n)/(double)2, _state)+1, _state); - ae_v_move(&ta.ptr.p_double[0], 1, &alpha->ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); - ae_vector_set_length(alpha, 2*n+1, _state); - ae_v_move(&alpha->ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); - for(i=ae_ifloor((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) - { - alpha->ptr.p_double[i] = 0; - } - ae_vector_set_length(&ta, ae_iceil((double)(3*n)/(double)2, _state)+1, _state); - ae_v_move(&ta.ptr.p_double[0], 1, &beta->ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); - ae_vector_set_length(beta, 2*n+1, _state); - ae_v_move(&beta->ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); - for(i=ae_iceil((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) - { - beta->ptr.p_double[i] = 0; - } - - /* - * Initialize T, S - */ - wlen = 2+n/2; - ae_vector_set_length(&t, wlen, _state); - ae_vector_set_length(&s, wlen, _state); - ae_vector_set_length(&ta, wlen, _state); - woffs = 1; - for(i=0; i<=wlen-1; i++) - { - t.ptr.p_double[i] = 0; - s.ptr.p_double[i] = 0; - } - - /* - * Algorithm from Dirk P. Laurie, "Calculation of Gauss-Kronrod quadrature rules", 1997. - */ - t.ptr.p_double[woffs+0] = beta->ptr.p_double[n+1]; - for(m=0; m<=n-2; m++) - { - u = 0; - for(k=(m+1)/2; k>=0; k--) - { - l = m-k; - u = u+(alpha->ptr.p_double[k+n+1]-alpha->ptr.p_double[l])*t.ptr.p_double[woffs+k]+beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+k-1]-beta->ptr.p_double[l]*s.ptr.p_double[woffs+k]; - s.ptr.p_double[woffs+k] = u; - } - ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - } - for(j=n/2; j>=0; j--) - { - s.ptr.p_double[woffs+j] = s.ptr.p_double[woffs+j-1]; - } - for(m=n-1; m<=2*n-3; m++) - { - u = 0; - for(k=m+1-n; k<=(m-1)/2; k++) - { - l = m-k; - j = n-1-l; - u = u-(alpha->ptr.p_double[k+n+1]-alpha->ptr.p_double[l])*t.ptr.p_double[woffs+j]-beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j]+beta->ptr.p_double[l]*s.ptr.p_double[woffs+j+1]; - s.ptr.p_double[woffs+j] = u; - } - if( m%2==0 ) - { - k = m/2; - alpha->ptr.p_double[k+n+1] = alpha->ptr.p_double[k]+(s.ptr.p_double[woffs+j]-beta->ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j+1])/t.ptr.p_double[woffs+j+1]; - } - else - { - k = (m+1)/2; - beta->ptr.p_double[k+n+1] = s.ptr.p_double[woffs+j]/s.ptr.p_double[woffs+j+1]; - } - ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); - } - alpha->ptr.p_double[2*n] = alpha->ptr.p_double[n-1]-beta->ptr.p_double[2*n]*s.ptr.p_double[woffs+0]/t.ptr.p_double[woffs+0]; - - /* - * calculation of Kronrod nodes and weights, unpacking of Gauss weights - */ - gqgeneraterec(alpha, beta, mu0, 2*n+1, info, x, wkronrod, _state); - if( *info==-2 ) - { - *info = -5; - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - for(i=0; i<=2*n-1; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - ae_vector_set_length(wgauss, 2*n+1, _state); - for(i=0; i<=2*n; i++) - { - wgauss->ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - wgauss->ptr.p_double[2*i+1] = wgtmp.ptr.p_double[i]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre -quadrature with N points. - -GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is -used depending on machine precision and number of nodes. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategausslegendre(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state) -{ - double eps; - - *info = 0; - ae_vector_clear(x); - ae_vector_clear(wkronrod); - ae_vector_clear(wgauss); - - if( ae_fp_greater(ae_machineepsilon,1.0E-32)&&(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61) ) - { - *info = 1; - gkqlegendretbl(n, x, wkronrod, wgauss, &eps, _state); - } - else - { - gkqlegendrecalc(n, info, x, wkronrod, wgauss, _state); - } -} - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi -quadrature on [-1,1] with weight function - - W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - * +2 OK, but quadrature rule have exterior nodes, - x[0]<-1 or x[n-1]>+1 - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategaussjacobi(ae_int_t n, - double alpha, - double beta, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t clen; - ae_vector a; - ae_vector b; - double alpha2; - double beta2; - double apb; - double t; - ae_int_t i; - double s; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(wkronrod); - ae_vector_clear(wgauss); - ae_vector_init(&a, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - - if( n%2!=1||n<3 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( ae_fp_less_eq(alpha,-1)||ae_fp_less_eq(beta,-1) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - clen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; - ae_vector_set_length(&a, clen, _state); - ae_vector_set_length(&b, clen, _state); - for(i=0; i<=clen-1; i++) - { - a.ptr.p_double[i] = 0; - } - apb = alpha+beta; - a.ptr.p_double[0] = (beta-alpha)/(apb+2); - t = (apb+1)*ae_log(2, _state)+lngamma(alpha+1, &s, _state)+lngamma(beta+1, &s, _state)-lngamma(apb+2, &s, _state); - if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - b.ptr.p_double[0] = ae_exp(t, _state); - if( clen>1 ) - { - alpha2 = ae_sqr(alpha, _state); - beta2 = ae_sqr(beta, _state); - a.ptr.p_double[1] = (beta2-alpha2)/((apb+2)*(apb+4)); - b.ptr.p_double[1] = 4*(alpha+1)*(beta+1)/((apb+3)*ae_sqr(apb+2, _state)); - for(i=2; i<=clen-1; i++) - { - a.ptr.p_double[i] = 0.25*(beta2-alpha2)/(i*i*(1+0.5*apb/i)*(1+0.5*(apb+2)/i)); - b.ptr.p_double[i] = 0.25*(1+alpha/i)*(1+beta/i)*(1+apb/i)/((1+0.5*(apb+1)/i)*(1+0.5*(apb-1)/i)*ae_sqr(1+0.5*apb/i, _state)); - } - } - gkqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, wkronrod, wgauss, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - if( ae_fp_less(x->ptr.p_double[0],-1)||ae_fp_greater(x->ptr.p_double[n-1],1) ) - { - *info = 2; - } - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. - -Reduction to tridiagonal eigenproblem is used. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendrecalc(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector alpha; - ae_vector beta; - ae_int_t alen; - ae_int_t blen; - double mu0; - ae_int_t k; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(x); - ae_vector_clear(wkronrod); - ae_vector_clear(wgauss); - ae_vector_init(&alpha, 0, DT_REAL, _state, ae_true); - ae_vector_init(&beta, 0, DT_REAL, _state, ae_true); - - if( n%2!=1||n<3 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - mu0 = 2; - alen = ae_ifloor((double)(3*(n/2))/(double)2, _state)+1; - blen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; - ae_vector_set_length(&alpha, alen, _state); - ae_vector_set_length(&beta, blen, _state); - for(k=0; k<=alen-1; k++) - { - alpha.ptr.p_double[k] = 0; - } - beta.ptr.p_double[0] = 2; - for(k=1; k<=blen-1; k++) - { - beta.ptr.p_double[k] = 1/(4-1/ae_sqr(k, _state)); - } - gkqgeneraterec(&alpha, &beta, mu0, n, info, x, wkronrod, wgauss, _state); - - /* - * test basic properties to detect errors - */ - if( *info>0 ) - { - if( ae_fp_less(x->ptr.p_double[0],-1)||ae_fp_greater(x->ptr.p_double[n-1],1) ) - { - *info = -4; - } - for(i=0; i<=n-2; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) - { - *info = -4; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using -pre-calculated table. Nodes/weights were computed with accuracy up to -1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision -accuracy reduces to something about 2.0E-16 (depending on your compiler's -handling of long floating point constants). - -INPUT PARAMETERS: - N - number of Kronrod nodes. - N can be 15, 21, 31, 41, 51, 61. - -OUTPUT PARAMETERS: - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendretbl(ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - double* eps, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t ng; - ae_vector p1; - ae_vector p2; - double tmp; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(x); - ae_vector_clear(wkronrod); - ae_vector_clear(wgauss); - *eps = 0; - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - ng = 0; - - /* - * Process - */ - ae_assert(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61, "GKQNodesTbl: incorrect N!", _state); - ae_vector_set_length(x, n, _state); - ae_vector_set_length(wkronrod, n, _state); - ae_vector_set_length(wgauss, n, _state); - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = 0; - wkronrod->ptr.p_double[i] = 0; - wgauss->ptr.p_double[i] = 0; - } - *eps = ae_maxreal(ae_machineepsilon, 1.0E-32, _state); - if( n==15 ) - { - ng = 4; - wgauss->ptr.p_double[0] = 0.129484966168869693270611432679082; - wgauss->ptr.p_double[1] = 0.279705391489276667901467771423780; - wgauss->ptr.p_double[2] = 0.381830050505118944950369775488975; - wgauss->ptr.p_double[3] = 0.417959183673469387755102040816327; - x->ptr.p_double[0] = 0.991455371120812639206854697526329; - x->ptr.p_double[1] = 0.949107912342758524526189684047851; - x->ptr.p_double[2] = 0.864864423359769072789712788640926; - x->ptr.p_double[3] = 0.741531185599394439863864773280788; - x->ptr.p_double[4] = 0.586087235467691130294144838258730; - x->ptr.p_double[5] = 0.405845151377397166906606412076961; - x->ptr.p_double[6] = 0.207784955007898467600689403773245; - x->ptr.p_double[7] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.022935322010529224963732008058970; - wkronrod->ptr.p_double[1] = 0.063092092629978553290700663189204; - wkronrod->ptr.p_double[2] = 0.104790010322250183839876322541518; - wkronrod->ptr.p_double[3] = 0.140653259715525918745189590510238; - wkronrod->ptr.p_double[4] = 0.169004726639267902826583426598550; - wkronrod->ptr.p_double[5] = 0.190350578064785409913256402421014; - wkronrod->ptr.p_double[6] = 0.204432940075298892414161999234649; - wkronrod->ptr.p_double[7] = 0.209482141084727828012999174891714; - } - if( n==21 ) - { - ng = 5; - wgauss->ptr.p_double[0] = 0.066671344308688137593568809893332; - wgauss->ptr.p_double[1] = 0.149451349150580593145776339657697; - wgauss->ptr.p_double[2] = 0.219086362515982043995534934228163; - wgauss->ptr.p_double[3] = 0.269266719309996355091226921569469; - wgauss->ptr.p_double[4] = 0.295524224714752870173892994651338; - x->ptr.p_double[0] = 0.995657163025808080735527280689003; - x->ptr.p_double[1] = 0.973906528517171720077964012084452; - x->ptr.p_double[2] = 0.930157491355708226001207180059508; - x->ptr.p_double[3] = 0.865063366688984510732096688423493; - x->ptr.p_double[4] = 0.780817726586416897063717578345042; - x->ptr.p_double[5] = 0.679409568299024406234327365114874; - x->ptr.p_double[6] = 0.562757134668604683339000099272694; - x->ptr.p_double[7] = 0.433395394129247190799265943165784; - x->ptr.p_double[8] = 0.294392862701460198131126603103866; - x->ptr.p_double[9] = 0.148874338981631210884826001129720; - x->ptr.p_double[10] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.011694638867371874278064396062192; - wkronrod->ptr.p_double[1] = 0.032558162307964727478818972459390; - wkronrod->ptr.p_double[2] = 0.054755896574351996031381300244580; - wkronrod->ptr.p_double[3] = 0.075039674810919952767043140916190; - wkronrod->ptr.p_double[4] = 0.093125454583697605535065465083366; - wkronrod->ptr.p_double[5] = 0.109387158802297641899210590325805; - wkronrod->ptr.p_double[6] = 0.123491976262065851077958109831074; - wkronrod->ptr.p_double[7] = 0.134709217311473325928054001771707; - wkronrod->ptr.p_double[8] = 0.142775938577060080797094273138717; - wkronrod->ptr.p_double[9] = 0.147739104901338491374841515972068; - wkronrod->ptr.p_double[10] = 0.149445554002916905664936468389821; - } - if( n==31 ) - { - ng = 8; - wgauss->ptr.p_double[0] = 0.030753241996117268354628393577204; - wgauss->ptr.p_double[1] = 0.070366047488108124709267416450667; - wgauss->ptr.p_double[2] = 0.107159220467171935011869546685869; - wgauss->ptr.p_double[3] = 0.139570677926154314447804794511028; - wgauss->ptr.p_double[4] = 0.166269205816993933553200860481209; - wgauss->ptr.p_double[5] = 0.186161000015562211026800561866423; - wgauss->ptr.p_double[6] = 0.198431485327111576456118326443839; - wgauss->ptr.p_double[7] = 0.202578241925561272880620199967519; - x->ptr.p_double[0] = 0.998002298693397060285172840152271; - x->ptr.p_double[1] = 0.987992518020485428489565718586613; - x->ptr.p_double[2] = 0.967739075679139134257347978784337; - x->ptr.p_double[3] = 0.937273392400705904307758947710209; - x->ptr.p_double[4] = 0.897264532344081900882509656454496; - x->ptr.p_double[5] = 0.848206583410427216200648320774217; - x->ptr.p_double[6] = 0.790418501442465932967649294817947; - x->ptr.p_double[7] = 0.724417731360170047416186054613938; - x->ptr.p_double[8] = 0.650996741297416970533735895313275; - x->ptr.p_double[9] = 0.570972172608538847537226737253911; - x->ptr.p_double[10] = 0.485081863640239680693655740232351; - x->ptr.p_double[11] = 0.394151347077563369897207370981045; - x->ptr.p_double[12] = 0.299180007153168812166780024266389; - x->ptr.p_double[13] = 0.201194093997434522300628303394596; - x->ptr.p_double[14] = 0.101142066918717499027074231447392; - x->ptr.p_double[15] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.005377479872923348987792051430128; - wkronrod->ptr.p_double[1] = 0.015007947329316122538374763075807; - wkronrod->ptr.p_double[2] = 0.025460847326715320186874001019653; - wkronrod->ptr.p_double[3] = 0.035346360791375846222037948478360; - wkronrod->ptr.p_double[4] = 0.044589751324764876608227299373280; - wkronrod->ptr.p_double[5] = 0.053481524690928087265343147239430; - wkronrod->ptr.p_double[6] = 0.062009567800670640285139230960803; - wkronrod->ptr.p_double[7] = 0.069854121318728258709520077099147; - wkronrod->ptr.p_double[8] = 0.076849680757720378894432777482659; - wkronrod->ptr.p_double[9] = 0.083080502823133021038289247286104; - wkronrod->ptr.p_double[10] = 0.088564443056211770647275443693774; - wkronrod->ptr.p_double[11] = 0.093126598170825321225486872747346; - wkronrod->ptr.p_double[12] = 0.096642726983623678505179907627589; - wkronrod->ptr.p_double[13] = 0.099173598721791959332393173484603; - wkronrod->ptr.p_double[14] = 0.100769845523875595044946662617570; - wkronrod->ptr.p_double[15] = 0.101330007014791549017374792767493; - } - if( n==41 ) - { - ng = 10; - wgauss->ptr.p_double[0] = 0.017614007139152118311861962351853; - wgauss->ptr.p_double[1] = 0.040601429800386941331039952274932; - wgauss->ptr.p_double[2] = 0.062672048334109063569506535187042; - wgauss->ptr.p_double[3] = 0.083276741576704748724758143222046; - wgauss->ptr.p_double[4] = 0.101930119817240435036750135480350; - wgauss->ptr.p_double[5] = 0.118194531961518417312377377711382; - wgauss->ptr.p_double[6] = 0.131688638449176626898494499748163; - wgauss->ptr.p_double[7] = 0.142096109318382051329298325067165; - wgauss->ptr.p_double[8] = 0.149172986472603746787828737001969; - wgauss->ptr.p_double[9] = 0.152753387130725850698084331955098; - x->ptr.p_double[0] = 0.998859031588277663838315576545863; - x->ptr.p_double[1] = 0.993128599185094924786122388471320; - x->ptr.p_double[2] = 0.981507877450250259193342994720217; - x->ptr.p_double[3] = 0.963971927277913791267666131197277; - x->ptr.p_double[4] = 0.940822633831754753519982722212443; - x->ptr.p_double[5] = 0.912234428251325905867752441203298; - x->ptr.p_double[6] = 0.878276811252281976077442995113078; - x->ptr.p_double[7] = 0.839116971822218823394529061701521; - x->ptr.p_double[8] = 0.795041428837551198350638833272788; - x->ptr.p_double[9] = 0.746331906460150792614305070355642; - x->ptr.p_double[10] = 0.693237656334751384805490711845932; - x->ptr.p_double[11] = 0.636053680726515025452836696226286; - x->ptr.p_double[12] = 0.575140446819710315342946036586425; - x->ptr.p_double[13] = 0.510867001950827098004364050955251; - x->ptr.p_double[14] = 0.443593175238725103199992213492640; - x->ptr.p_double[15] = 0.373706088715419560672548177024927; - x->ptr.p_double[16] = 0.301627868114913004320555356858592; - x->ptr.p_double[17] = 0.227785851141645078080496195368575; - x->ptr.p_double[18] = 0.152605465240922675505220241022678; - x->ptr.p_double[19] = 0.076526521133497333754640409398838; - x->ptr.p_double[20] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.003073583718520531501218293246031; - wkronrod->ptr.p_double[1] = 0.008600269855642942198661787950102; - wkronrod->ptr.p_double[2] = 0.014626169256971252983787960308868; - wkronrod->ptr.p_double[3] = 0.020388373461266523598010231432755; - wkronrod->ptr.p_double[4] = 0.025882133604951158834505067096153; - wkronrod->ptr.p_double[5] = 0.031287306777032798958543119323801; - wkronrod->ptr.p_double[6] = 0.036600169758200798030557240707211; - wkronrod->ptr.p_double[7] = 0.041668873327973686263788305936895; - wkronrod->ptr.p_double[8] = 0.046434821867497674720231880926108; - wkronrod->ptr.p_double[9] = 0.050944573923728691932707670050345; - wkronrod->ptr.p_double[10] = 0.055195105348285994744832372419777; - wkronrod->ptr.p_double[11] = 0.059111400880639572374967220648594; - wkronrod->ptr.p_double[12] = 0.062653237554781168025870122174255; - wkronrod->ptr.p_double[13] = 0.065834597133618422111563556969398; - wkronrod->ptr.p_double[14] = 0.068648672928521619345623411885368; - wkronrod->ptr.p_double[15] = 0.071054423553444068305790361723210; - wkronrod->ptr.p_double[16] = 0.073030690332786667495189417658913; - wkronrod->ptr.p_double[17] = 0.074582875400499188986581418362488; - wkronrod->ptr.p_double[18] = 0.075704497684556674659542775376617; - wkronrod->ptr.p_double[19] = 0.076377867672080736705502835038061; - wkronrod->ptr.p_double[20] = 0.076600711917999656445049901530102; - } - if( n==51 ) - { - ng = 13; - wgauss->ptr.p_double[0] = 0.011393798501026287947902964113235; - wgauss->ptr.p_double[1] = 0.026354986615032137261901815295299; - wgauss->ptr.p_double[2] = 0.040939156701306312655623487711646; - wgauss->ptr.p_double[3] = 0.054904695975835191925936891540473; - wgauss->ptr.p_double[4] = 0.068038333812356917207187185656708; - wgauss->ptr.p_double[5] = 0.080140700335001018013234959669111; - wgauss->ptr.p_double[6] = 0.091028261982963649811497220702892; - wgauss->ptr.p_double[7] = 0.100535949067050644202206890392686; - wgauss->ptr.p_double[8] = 0.108519624474263653116093957050117; - wgauss->ptr.p_double[9] = 0.114858259145711648339325545869556; - wgauss->ptr.p_double[10] = 0.119455763535784772228178126512901; - wgauss->ptr.p_double[11] = 0.122242442990310041688959518945852; - wgauss->ptr.p_double[12] = 0.123176053726715451203902873079050; - x->ptr.p_double[0] = 0.999262104992609834193457486540341; - x->ptr.p_double[1] = 0.995556969790498097908784946893902; - x->ptr.p_double[2] = 0.988035794534077247637331014577406; - x->ptr.p_double[3] = 0.976663921459517511498315386479594; - x->ptr.p_double[4] = 0.961614986425842512418130033660167; - x->ptr.p_double[5] = 0.942974571228974339414011169658471; - x->ptr.p_double[6] = 0.920747115281701561746346084546331; - x->ptr.p_double[7] = 0.894991997878275368851042006782805; - x->ptr.p_double[8] = 0.865847065293275595448996969588340; - x->ptr.p_double[9] = 0.833442628760834001421021108693570; - x->ptr.p_double[10] = 0.797873797998500059410410904994307; - x->ptr.p_double[11] = 0.759259263037357630577282865204361; - x->ptr.p_double[12] = 0.717766406813084388186654079773298; - x->ptr.p_double[13] = 0.673566368473468364485120633247622; - x->ptr.p_double[14] = 0.626810099010317412788122681624518; - x->ptr.p_double[15] = 0.577662930241222967723689841612654; - x->ptr.p_double[16] = 0.526325284334719182599623778158010; - x->ptr.p_double[17] = 0.473002731445714960522182115009192; - x->ptr.p_double[18] = 0.417885382193037748851814394594572; - x->ptr.p_double[19] = 0.361172305809387837735821730127641; - x->ptr.p_double[20] = 0.303089538931107830167478909980339; - x->ptr.p_double[21] = 0.243866883720988432045190362797452; - x->ptr.p_double[22] = 0.183718939421048892015969888759528; - x->ptr.p_double[23] = 0.122864692610710396387359818808037; - x->ptr.p_double[24] = 0.061544483005685078886546392366797; - x->ptr.p_double[25] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.001987383892330315926507851882843; - wkronrod->ptr.p_double[1] = 0.005561932135356713758040236901066; - wkronrod->ptr.p_double[2] = 0.009473973386174151607207710523655; - wkronrod->ptr.p_double[3] = 0.013236229195571674813656405846976; - wkronrod->ptr.p_double[4] = 0.016847817709128298231516667536336; - wkronrod->ptr.p_double[5] = 0.020435371145882835456568292235939; - wkronrod->ptr.p_double[6] = 0.024009945606953216220092489164881; - wkronrod->ptr.p_double[7] = 0.027475317587851737802948455517811; - wkronrod->ptr.p_double[8] = 0.030792300167387488891109020215229; - wkronrod->ptr.p_double[9] = 0.034002130274329337836748795229551; - wkronrod->ptr.p_double[10] = 0.037116271483415543560330625367620; - wkronrod->ptr.p_double[11] = 0.040083825504032382074839284467076; - wkronrod->ptr.p_double[12] = 0.042872845020170049476895792439495; - wkronrod->ptr.p_double[13] = 0.045502913049921788909870584752660; - wkronrod->ptr.p_double[14] = 0.047982537138836713906392255756915; - wkronrod->ptr.p_double[15] = 0.050277679080715671963325259433440; - wkronrod->ptr.p_double[16] = 0.052362885806407475864366712137873; - wkronrod->ptr.p_double[17] = 0.054251129888545490144543370459876; - wkronrod->ptr.p_double[18] = 0.055950811220412317308240686382747; - wkronrod->ptr.p_double[19] = 0.057437116361567832853582693939506; - wkronrod->ptr.p_double[20] = 0.058689680022394207961974175856788; - wkronrod->ptr.p_double[21] = 0.059720340324174059979099291932562; - wkronrod->ptr.p_double[22] = 0.060539455376045862945360267517565; - wkronrod->ptr.p_double[23] = 0.061128509717053048305859030416293; - wkronrod->ptr.p_double[24] = 0.061471189871425316661544131965264; - wkronrod->ptr.p_double[25] = 0.061580818067832935078759824240055; - } - if( n==61 ) - { - ng = 15; - wgauss->ptr.p_double[0] = 0.007968192496166605615465883474674; - wgauss->ptr.p_double[1] = 0.018466468311090959142302131912047; - wgauss->ptr.p_double[2] = 0.028784707883323369349719179611292; - wgauss->ptr.p_double[3] = 0.038799192569627049596801936446348; - wgauss->ptr.p_double[4] = 0.048402672830594052902938140422808; - wgauss->ptr.p_double[5] = 0.057493156217619066481721689402056; - wgauss->ptr.p_double[6] = 0.065974229882180495128128515115962; - wgauss->ptr.p_double[7] = 0.073755974737705206268243850022191; - wgauss->ptr.p_double[8] = 0.080755895229420215354694938460530; - wgauss->ptr.p_double[9] = 0.086899787201082979802387530715126; - wgauss->ptr.p_double[10] = 0.092122522237786128717632707087619; - wgauss->ptr.p_double[11] = 0.096368737174644259639468626351810; - wgauss->ptr.p_double[12] = 0.099593420586795267062780282103569; - wgauss->ptr.p_double[13] = 0.101762389748405504596428952168554; - wgauss->ptr.p_double[14] = 0.102852652893558840341285636705415; - x->ptr.p_double[0] = 0.999484410050490637571325895705811; - x->ptr.p_double[1] = 0.996893484074649540271630050918695; - x->ptr.p_double[2] = 0.991630996870404594858628366109486; - x->ptr.p_double[3] = 0.983668123279747209970032581605663; - x->ptr.p_double[4] = 0.973116322501126268374693868423707; - x->ptr.p_double[5] = 0.960021864968307512216871025581798; - x->ptr.p_double[6] = 0.944374444748559979415831324037439; - x->ptr.p_double[7] = 0.926200047429274325879324277080474; - x->ptr.p_double[8] = 0.905573307699907798546522558925958; - x->ptr.p_double[9] = 0.882560535792052681543116462530226; - x->ptr.p_double[10] = 0.857205233546061098958658510658944; - x->ptr.p_double[11] = 0.829565762382768397442898119732502; - x->ptr.p_double[12] = 0.799727835821839083013668942322683; - x->ptr.p_double[13] = 0.767777432104826194917977340974503; - x->ptr.p_double[14] = 0.733790062453226804726171131369528; - x->ptr.p_double[15] = 0.697850494793315796932292388026640; - x->ptr.p_double[16] = 0.660061064126626961370053668149271; - x->ptr.p_double[17] = 0.620526182989242861140477556431189; - x->ptr.p_double[18] = 0.579345235826361691756024932172540; - x->ptr.p_double[19] = 0.536624148142019899264169793311073; - x->ptr.p_double[20] = 0.492480467861778574993693061207709; - x->ptr.p_double[21] = 0.447033769538089176780609900322854; - x->ptr.p_double[22] = 0.400401254830394392535476211542661; - x->ptr.p_double[23] = 0.352704725530878113471037207089374; - x->ptr.p_double[24] = 0.304073202273625077372677107199257; - x->ptr.p_double[25] = 0.254636926167889846439805129817805; - x->ptr.p_double[26] = 0.204525116682309891438957671002025; - x->ptr.p_double[27] = 0.153869913608583546963794672743256; - x->ptr.p_double[28] = 0.102806937966737030147096751318001; - x->ptr.p_double[29] = 0.051471842555317695833025213166723; - x->ptr.p_double[30] = 0.000000000000000000000000000000000; - wkronrod->ptr.p_double[0] = 0.001389013698677007624551591226760; - wkronrod->ptr.p_double[1] = 0.003890461127099884051267201844516; - wkronrod->ptr.p_double[2] = 0.006630703915931292173319826369750; - wkronrod->ptr.p_double[3] = 0.009273279659517763428441146892024; - wkronrod->ptr.p_double[4] = 0.011823015253496341742232898853251; - wkronrod->ptr.p_double[5] = 0.014369729507045804812451432443580; - wkronrod->ptr.p_double[6] = 0.016920889189053272627572289420322; - wkronrod->ptr.p_double[7] = 0.019414141193942381173408951050128; - wkronrod->ptr.p_double[8] = 0.021828035821609192297167485738339; - wkronrod->ptr.p_double[9] = 0.024191162078080601365686370725232; - wkronrod->ptr.p_double[10] = 0.026509954882333101610601709335075; - wkronrod->ptr.p_double[11] = 0.028754048765041292843978785354334; - wkronrod->ptr.p_double[12] = 0.030907257562387762472884252943092; - wkronrod->ptr.p_double[13] = 0.032981447057483726031814191016854; - wkronrod->ptr.p_double[14] = 0.034979338028060024137499670731468; - wkronrod->ptr.p_double[15] = 0.036882364651821229223911065617136; - wkronrod->ptr.p_double[16] = 0.038678945624727592950348651532281; - wkronrod->ptr.p_double[17] = 0.040374538951535959111995279752468; - wkronrod->ptr.p_double[18] = 0.041969810215164246147147541285970; - wkronrod->ptr.p_double[19] = 0.043452539701356069316831728117073; - wkronrod->ptr.p_double[20] = 0.044814800133162663192355551616723; - wkronrod->ptr.p_double[21] = 0.046059238271006988116271735559374; - wkronrod->ptr.p_double[22] = 0.047185546569299153945261478181099; - wkronrod->ptr.p_double[23] = 0.048185861757087129140779492298305; - wkronrod->ptr.p_double[24] = 0.049055434555029778887528165367238; - wkronrod->ptr.p_double[25] = 0.049795683427074206357811569379942; - wkronrod->ptr.p_double[26] = 0.050405921402782346840893085653585; - wkronrod->ptr.p_double[27] = 0.050881795898749606492297473049805; - wkronrod->ptr.p_double[28] = 0.051221547849258772170656282604944; - wkronrod->ptr.p_double[29] = 0.051426128537459025933862879215781; - wkronrod->ptr.p_double[30] = 0.051494729429451567558340433647099; - } - - /* - * copy nodes - */ - for(i=n-1; i>=n/2; i--) - { - x->ptr.p_double[i] = -x->ptr.p_double[n-1-i]; - } - - /* - * copy Kronrod weights - */ - for(i=n-1; i>=n/2; i--) - { - wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[n-1-i]; - } - - /* - * copy Gauss weights - */ - for(i=ng-1; i>=0; i--) - { - wgauss->ptr.p_double[n-2-2*i] = wgauss->ptr.p_double[i]; - wgauss->ptr.p_double[1+2*i] = wgauss->ptr.p_double[i]; - } - for(i=0; i<=n/2; i++) - { - wgauss->ptr.p_double[2*i] = 0; - } - - /* - * reorder - */ - tagsort(x, n, &p1, &p2, _state); - for(i=0; i<=n-1; i++) - { - tmp = wkronrod->ptr.p_double[i]; - wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[p2.ptr.p_int[i]]; - wkronrod->ptr.p_double[p2.ptr.p_int[i]] = tmp; - tmp = wgauss->ptr.p_double[i]; - wgauss->ptr.p_double[i] = wgauss->ptr.p_double[p2.ptr.p_int[i]]; - wgauss->ptr.p_double[p2.ptr.p_int[i]] = tmp; - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -Algorithm works well only with smooth integrands. It may be used with -continuous non-smooth integrands, but with less performance. - -It should never be used with integrands which have integrable singularities -at lower or upper limits - algorithm may crash. Use AutoGKSingular in such -cases. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmooth(double a, - double b, - autogkstate* state, - ae_state *_state) -{ - - _autogkstate_clear(state); - - ae_assert(ae_isfinite(a, _state), "AutoGKSmooth: A is not finite!", _state); - ae_assert(ae_isfinite(b, _state), "AutoGKSmooth: B is not finite!", _state); - autogksmoothw(a, b, 0.0, state, _state); -} - - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -This subroutine is same as AutoGKSmooth(), but it guarantees that interval -[a,b] is partitioned into subintervals which have width at most XWidth. - -Subroutine can be used when integrating nearly-constant function with -narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth -subroutine can overlook them. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmoothw(double a, - double b, - double xwidth, - autogkstate* state, - ae_state *_state) -{ - - _autogkstate_clear(state); - - ae_assert(ae_isfinite(a, _state), "AutoGKSmoothW: A is not finite!", _state); - ae_assert(ae_isfinite(b, _state), "AutoGKSmoothW: B is not finite!", _state); - ae_assert(ae_isfinite(xwidth, _state), "AutoGKSmoothW: XWidth is not finite!", _state); - state->wrappermode = 0; - state->a = a; - state->b = b; - state->xwidth = xwidth; - state->needf = ae_false; - ae_vector_set_length(&state->rstate.ra, 10+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Integration on a finite interval [A,B]. -Integrand have integrable singularities at A/B. - -F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known -alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates -from below can be used (but these estimates should be greater than -1 too). - -One of alpha/beta variables (or even both alpha/beta) may be equal to 0, -which means than function F(x) is non-singular at A/B. Anyway (singular at -bounds or not), function F(x) is supposed to be continuous on (A,B). - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - Alpha - power-law coefficient of the F(x) at A, - Alpha>-1 - Beta - power-law coefficient of the F(x) at B, - Beta>-1 - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSmoothW, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksingular(double a, - double b, - double alpha, - double beta, - autogkstate* state, - ae_state *_state) -{ - - _autogkstate_clear(state); - - ae_assert(ae_isfinite(a, _state), "AutoGKSingular: A is not finite!", _state); - ae_assert(ae_isfinite(b, _state), "AutoGKSingular: B is not finite!", _state); - ae_assert(ae_isfinite(alpha, _state), "AutoGKSingular: Alpha is not finite!", _state); - ae_assert(ae_isfinite(beta, _state), "AutoGKSingular: Beta is not finite!", _state); - state->wrappermode = 1; - state->a = a; - state->b = b; - state->alpha = alpha; - state->beta = beta; - state->xwidth = 0.0; - state->needf = ae_false; - ae_vector_set_length(&state->rstate.ra, 10+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 07.05.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool autogkiteration(autogkstate* state, ae_state *_state) -{ - double s; - double tmp; - double eps; - double a; - double b; - double x; - double t; - double alpha; - double beta; - double v1; - double v2; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - s = state->rstate.ra.ptr.p_double[0]; - tmp = state->rstate.ra.ptr.p_double[1]; - eps = state->rstate.ra.ptr.p_double[2]; - a = state->rstate.ra.ptr.p_double[3]; - b = state->rstate.ra.ptr.p_double[4]; - x = state->rstate.ra.ptr.p_double[5]; - t = state->rstate.ra.ptr.p_double[6]; - alpha = state->rstate.ra.ptr.p_double[7]; - beta = state->rstate.ra.ptr.p_double[8]; - v1 = state->rstate.ra.ptr.p_double[9]; - v2 = state->rstate.ra.ptr.p_double[10]; - } - else - { - s = -983; - tmp = -989; - eps = -834; - a = 900; - b = -287; - x = 364; - t = 214; - alpha = -338; - beta = -686; - v1 = 912; - v2 = 585; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - - /* - * Routine body - */ - eps = 0; - a = state->a; - b = state->b; - alpha = state->alpha; - beta = state->beta; - state->terminationtype = -1; - state->nfev = 0; - state->nintervals = 0; - - /* - * smooth function at a finite interval - */ - if( state->wrappermode!=0 ) - { - goto lbl_3; - } - - /* - * special case - */ - if( ae_fp_eq(a,b) ) - { - state->terminationtype = 1; - state->v = 0; - result = ae_false; - return result; - } - - /* - * general case - */ - autogk_autogkinternalprepare(a, b, eps, state->xwidth, &state->internalstate, _state); -lbl_5: - if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) - { - goto lbl_6; - } - x = state->internalstate.x; - state->x = x; - state->xminusa = x-a; - state->bminusx = b-x; - state->needf = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needf = ae_false; - state->nfev = state->nfev+1; - state->internalstate.f = state->f; - goto lbl_5; -lbl_6: - state->v = state->internalstate.r; - state->terminationtype = state->internalstate.info; - state->nintervals = state->internalstate.heapused; - result = ae_false; - return result; -lbl_3: - - /* - * function with power-law singularities at the ends of a finite interval - */ - if( state->wrappermode!=1 ) - { - goto lbl_7; - } - - /* - * test coefficients - */ - if( ae_fp_less_eq(alpha,-1)||ae_fp_less_eq(beta,-1) ) - { - state->terminationtype = -1; - state->v = 0; - result = ae_false; - return result; - } - - /* - * special cases - */ - if( ae_fp_eq(a,b) ) - { - state->terminationtype = 1; - state->v = 0; - result = ae_false; - return result; - } - - /* - * reduction to general form - */ - if( ae_fp_less(a,b) ) - { - s = 1; - } - else - { - s = -1; - tmp = a; - a = b; - b = tmp; - tmp = alpha; - alpha = beta; - beta = tmp; - } - alpha = ae_minreal(alpha, 0, _state); - beta = ae_minreal(beta, 0, _state); - - /* - * first, integrate left half of [a,b]: - * integral(f(x)dx, a, (b+a)/2) = - * = 1/(1+alpha) * integral(t^(-alpha/(1+alpha))*f(a+t^(1/(1+alpha)))dt, 0, (0.5*(b-a))^(1+alpha)) - */ - autogk_autogkinternalprepare(0, ae_pow(0.5*(b-a), 1+alpha, _state), eps, state->xwidth, &state->internalstate, _state); -lbl_9: - if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) - { - goto lbl_10; - } - - /* - * Fill State.X, State.XMinusA, State.BMinusX. - * Latter two are filled correctly even if Binternalstate.x; - t = ae_pow(x, 1/(1+alpha), _state); - state->x = a+t; - if( ae_fp_greater(s,0) ) - { - state->xminusa = t; - state->bminusx = b-(a+t); - } - else - { - state->xminusa = a+t-b; - state->bminusx = -t; - } - state->needf = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->needf = ae_false; - if( ae_fp_neq(alpha,0) ) - { - state->internalstate.f = state->f*ae_pow(x, -alpha/(1+alpha), _state)/(1+alpha); - } - else - { - state->internalstate.f = state->f; - } - state->nfev = state->nfev+1; - goto lbl_9; -lbl_10: - v1 = state->internalstate.r; - state->nintervals = state->nintervals+state->internalstate.heapused; - - /* - * then, integrate right half of [a,b]: - * integral(f(x)dx, (b+a)/2, b) = - * = 1/(1+beta) * integral(t^(-beta/(1+beta))*f(b-t^(1/(1+beta)))dt, 0, (0.5*(b-a))^(1+beta)) - */ - autogk_autogkinternalprepare(0, ae_pow(0.5*(b-a), 1+beta, _state), eps, state->xwidth, &state->internalstate, _state); -lbl_11: - if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) - { - goto lbl_12; - } - - /* - * Fill State.X, State.XMinusA, State.BMinusX. - * Latter two are filled correctly (X-A, B-X) even if Binternalstate.x; - t = ae_pow(x, 1/(1+beta), _state); - state->x = b-t; - if( ae_fp_greater(s,0) ) - { - state->xminusa = b-t-a; - state->bminusx = t; - } - else - { - state->xminusa = -t; - state->bminusx = a-(b-t); - } - state->needf = ae_true; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->needf = ae_false; - if( ae_fp_neq(beta,0) ) - { - state->internalstate.f = state->f*ae_pow(x, -beta/(1+beta), _state)/(1+beta); - } - else - { - state->internalstate.f = state->f; - } - state->nfev = state->nfev+1; - goto lbl_11; -lbl_12: - v2 = state->internalstate.r; - state->nintervals = state->nintervals+state->internalstate.heapused; - - /* - * final result - */ - state->v = s*(v1+v2); - state->terminationtype = 1; - result = ae_false; - return result; -lbl_7: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ra.ptr.p_double[0] = s; - state->rstate.ra.ptr.p_double[1] = tmp; - state->rstate.ra.ptr.p_double[2] = eps; - state->rstate.ra.ptr.p_double[3] = a; - state->rstate.ra.ptr.p_double[4] = b; - state->rstate.ra.ptr.p_double[5] = x; - state->rstate.ra.ptr.p_double[6] = t; - state->rstate.ra.ptr.p_double[7] = alpha; - state->rstate.ra.ptr.p_double[8] = beta; - state->rstate.ra.ptr.p_double[9] = v1; - state->rstate.ra.ptr.p_double[10] = v2; - return result; -} - - -/************************************************************************* -Adaptive integration results - -Called after AutoGKIteration returned False. - -Input parameters: - State - algorithm state (used by AutoGKIteration). - -Output parameters: - V - integral(f(x)dx,a,b) - Rep - optimization report (see AutoGKReport description) - - -- ALGLIB -- - Copyright 14.11.2007 by Bochkanov Sergey -*************************************************************************/ -void autogkresults(autogkstate* state, - double* v, - autogkreport* rep, - ae_state *_state) -{ - - *v = 0; - _autogkreport_clear(rep); - - *v = state->v; - rep->terminationtype = state->terminationtype; - rep->nfev = state->nfev; - rep->nintervals = state->nintervals; -} - - -/************************************************************************* -Internal AutoGK subroutine -eps<0 - error -eps=0 - automatic eps selection - -width<0 - error -width=0 - no width requirements -*************************************************************************/ -static void autogk_autogkinternalprepare(double a, - double b, - double eps, - double xwidth, - autogkinternalstate* state, - ae_state *_state) -{ - - - - /* - * Save settings - */ - state->a = a; - state->b = b; - state->eps = eps; - state->xwidth = xwidth; - - /* - * Prepare RComm structure - */ - ae_vector_set_length(&state->rstate.ia, 3+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Internal AutoGK subroutine -*************************************************************************/ -static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, - ae_state *_state) -{ - double c1; - double c2; - ae_int_t i; - ae_int_t j; - double intg; - double intk; - double inta; - double v; - double ta; - double tb; - ae_int_t ns; - double qeps; - ae_int_t info; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - i = state->rstate.ia.ptr.p_int[0]; - j = state->rstate.ia.ptr.p_int[1]; - ns = state->rstate.ia.ptr.p_int[2]; - info = state->rstate.ia.ptr.p_int[3]; - c1 = state->rstate.ra.ptr.p_double[0]; - c2 = state->rstate.ra.ptr.p_double[1]; - intg = state->rstate.ra.ptr.p_double[2]; - intk = state->rstate.ra.ptr.p_double[3]; - inta = state->rstate.ra.ptr.p_double[4]; - v = state->rstate.ra.ptr.p_double[5]; - ta = state->rstate.ra.ptr.p_double[6]; - tb = state->rstate.ra.ptr.p_double[7]; - qeps = state->rstate.ra.ptr.p_double[8]; - } - else - { - i = 497; - j = -271; - ns = -581; - info = 745; - c1 = -533; - c2 = -77; - intg = 678; - intk = -293; - inta = 316; - v = 647; - ta = -756; - tb = 830; - qeps = -871; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - - /* - * Routine body - */ - - /* - * initialize quadratures. - * use 15-point Gauss-Kronrod formula. - */ - state->n = 15; - gkqgenerategausslegendre(state->n, &info, &state->qn, &state->wk, &state->wg, _state); - if( info<0 ) - { - state->info = -5; - state->r = 0; - result = ae_false; - return result; - } - ae_vector_set_length(&state->wr, state->n, _state); - for(i=0; i<=state->n-1; i++) - { - if( i==0 ) - { - state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[1]-state->qn.ptr.p_double[0], _state); - continue; - } - if( i==state->n-1 ) - { - state->wr.ptr.p_double[state->n-1] = 0.5*ae_fabs(state->qn.ptr.p_double[state->n-1]-state->qn.ptr.p_double[state->n-2], _state); - continue; - } - state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[i-1]-state->qn.ptr.p_double[i+1], _state); - } - - /* - * special case - */ - if( ae_fp_eq(state->a,state->b) ) - { - state->info = 1; - state->r = 0; - result = ae_false; - return result; - } - - /* - * test parameters - */ - if( ae_fp_less(state->eps,0)||ae_fp_less(state->xwidth,0) ) - { - state->info = -1; - state->r = 0; - result = ae_false; - return result; - } - state->info = 1; - if( ae_fp_eq(state->eps,0) ) - { - state->eps = 100000*ae_machineepsilon; - } - - /* - * First, prepare heap - * * column 0 - absolute error - * * column 1 - integral of a F(x) (calculated using Kronrod extension nodes) - * * column 2 - integral of a |F(x)| (calculated using modified rect. method) - * * column 3 - left boundary of a subinterval - * * column 4 - right boundary of a subinterval - */ - if( ae_fp_neq(state->xwidth,0) ) - { - goto lbl_3; - } - - /* - * no maximum width requirements - * start from one big subinterval - */ - state->heapwidth = 5; - state->heapsize = 1; - state->heapused = 1; - ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); - c1 = 0.5*(state->b-state->a); - c2 = 0.5*(state->b+state->a); - intg = 0; - intk = 0; - inta = 0; - i = 0; -lbl_5: - if( i>state->n-1 ) - { - goto lbl_7; - } - - /* - * obtain F - */ - state->x = c1*state->qn.ptr.p_double[i]+c2; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - v = state->f; - - /* - * Gauss-Kronrod formula - */ - intk = intk+v*state->wk.ptr.p_double[i]; - if( i%2==1 ) - { - intg = intg+v*state->wg.ptr.p_double[i]; - } - - /* - * Integral |F(x)| - * Use rectangles method - */ - inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; - i = i+1; - goto lbl_5; -lbl_7: - intk = intk*(state->b-state->a)*0.5; - intg = intg*(state->b-state->a)*0.5; - inta = inta*(state->b-state->a)*0.5; - state->heap.ptr.pp_double[0][0] = ae_fabs(intg-intk, _state); - state->heap.ptr.pp_double[0][1] = intk; - state->heap.ptr.pp_double[0][2] = inta; - state->heap.ptr.pp_double[0][3] = state->a; - state->heap.ptr.pp_double[0][4] = state->b; - state->sumerr = state->heap.ptr.pp_double[0][0]; - state->sumabs = ae_fabs(inta, _state); - goto lbl_4; -lbl_3: - - /* - * maximum subinterval should be no more than XWidth. - * so we create Ceil((B-A)/XWidth)+1 small subintervals - */ - ns = ae_iceil(ae_fabs(state->b-state->a, _state)/state->xwidth, _state)+1; - state->heapsize = ns; - state->heapused = ns; - state->heapwidth = 5; - ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); - state->sumerr = 0; - state->sumabs = 0; - j = 0; -lbl_8: - if( j>ns-1 ) - { - goto lbl_10; - } - ta = state->a+j*(state->b-state->a)/ns; - tb = state->a+(j+1)*(state->b-state->a)/ns; - c1 = 0.5*(tb-ta); - c2 = 0.5*(tb+ta); - intg = 0; - intk = 0; - inta = 0; - i = 0; -lbl_11: - if( i>state->n-1 ) - { - goto lbl_13; - } - - /* - * obtain F - */ - state->x = c1*state->qn.ptr.p_double[i]+c2; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - v = state->f; - - /* - * Gauss-Kronrod formula - */ - intk = intk+v*state->wk.ptr.p_double[i]; - if( i%2==1 ) - { - intg = intg+v*state->wg.ptr.p_double[i]; - } - - /* - * Integral |F(x)| - * Use rectangles method - */ - inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; - i = i+1; - goto lbl_11; -lbl_13: - intk = intk*(tb-ta)*0.5; - intg = intg*(tb-ta)*0.5; - inta = inta*(tb-ta)*0.5; - state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); - state->heap.ptr.pp_double[j][1] = intk; - state->heap.ptr.pp_double[j][2] = inta; - state->heap.ptr.pp_double[j][3] = ta; - state->heap.ptr.pp_double[j][4] = tb; - state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; - state->sumabs = state->sumabs+ae_fabs(inta, _state); - j = j+1; - goto lbl_8; -lbl_10: -lbl_4: - - /* - * method iterations - */ -lbl_14: - if( ae_false ) - { - goto lbl_15; - } - - /* - * additional memory if needed - */ - if( state->heapused==state->heapsize ) - { - autogk_mheapresize(&state->heap, &state->heapsize, 4*state->heapsize, state->heapwidth, _state); - } - - /* - * TODO: every 20 iterations recalculate errors/sums - */ - if( ae_fp_less_eq(state->sumerr,state->eps*state->sumabs)||state->heapused>=autogk_maxsubintervals ) - { - state->r = 0; - for(j=0; j<=state->heapused-1; j++) - { - state->r = state->r+state->heap.ptr.pp_double[j][1]; - } - result = ae_false; - return result; - } - - /* - * Exclude interval with maximum absolute error - */ - autogk_mheappop(&state->heap, state->heapused, state->heapwidth, _state); - state->sumerr = state->sumerr-state->heap.ptr.pp_double[state->heapused-1][0]; - state->sumabs = state->sumabs-state->heap.ptr.pp_double[state->heapused-1][2]; - - /* - * Divide interval, create subintervals - */ - ta = state->heap.ptr.pp_double[state->heapused-1][3]; - tb = state->heap.ptr.pp_double[state->heapused-1][4]; - state->heap.ptr.pp_double[state->heapused-1][3] = ta; - state->heap.ptr.pp_double[state->heapused-1][4] = 0.5*(ta+tb); - state->heap.ptr.pp_double[state->heapused][3] = 0.5*(ta+tb); - state->heap.ptr.pp_double[state->heapused][4] = tb; - j = state->heapused-1; -lbl_16: - if( j>state->heapused ) - { - goto lbl_18; - } - c1 = 0.5*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3]); - c2 = 0.5*(state->heap.ptr.pp_double[j][4]+state->heap.ptr.pp_double[j][3]); - intg = 0; - intk = 0; - inta = 0; - i = 0; -lbl_19: - if( i>state->n-1 ) - { - goto lbl_21; - } - - /* - * F(x) - */ - state->x = c1*state->qn.ptr.p_double[i]+c2; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - v = state->f; - - /* - * Gauss-Kronrod formula - */ - intk = intk+v*state->wk.ptr.p_double[i]; - if( i%2==1 ) - { - intg = intg+v*state->wg.ptr.p_double[i]; - } - - /* - * Integral |F(x)| - * Use rectangles method - */ - inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; - i = i+1; - goto lbl_19; -lbl_21: - intk = intk*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; - intg = intg*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; - inta = inta*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; - state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); - state->heap.ptr.pp_double[j][1] = intk; - state->heap.ptr.pp_double[j][2] = inta; - state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; - state->sumabs = state->sumabs+state->heap.ptr.pp_double[j][2]; - j = j+1; - goto lbl_16; -lbl_18: - autogk_mheappush(&state->heap, state->heapused-1, state->heapwidth, _state); - autogk_mheappush(&state->heap, state->heapused, state->heapwidth, _state); - state->heapused = state->heapused+1; - goto lbl_14; -lbl_15: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = i; - state->rstate.ia.ptr.p_int[1] = j; - state->rstate.ia.ptr.p_int[2] = ns; - state->rstate.ia.ptr.p_int[3] = info; - state->rstate.ra.ptr.p_double[0] = c1; - state->rstate.ra.ptr.p_double[1] = c2; - state->rstate.ra.ptr.p_double[2] = intg; - state->rstate.ra.ptr.p_double[3] = intk; - state->rstate.ra.ptr.p_double[4] = inta; - state->rstate.ra.ptr.p_double[5] = v; - state->rstate.ra.ptr.p_double[6] = ta; - state->rstate.ra.ptr.p_double[7] = tb; - state->rstate.ra.ptr.p_double[8] = qeps; - return result; -} - - -static void autogk_mheappop(/* Real */ ae_matrix* heap, - ae_int_t heapsize, - ae_int_t heapwidth, - ae_state *_state) -{ - ae_int_t i; - ae_int_t p; - double t; - ae_int_t maxcp; - - - if( heapsize==1 ) - { - return; - } - for(i=0; i<=heapwidth-1; i++) - { - t = heap->ptr.pp_double[heapsize-1][i]; - heap->ptr.pp_double[heapsize-1][i] = heap->ptr.pp_double[0][i]; - heap->ptr.pp_double[0][i] = t; - } - p = 0; - while(2*p+1ptr.pp_double[2*p+2][0],heap->ptr.pp_double[2*p+1][0]) ) - { - maxcp = 2*p+2; - } - } - if( ae_fp_less(heap->ptr.pp_double[p][0],heap->ptr.pp_double[maxcp][0]) ) - { - for(i=0; i<=heapwidth-1; i++) - { - t = heap->ptr.pp_double[p][i]; - heap->ptr.pp_double[p][i] = heap->ptr.pp_double[maxcp][i]; - heap->ptr.pp_double[maxcp][i] = t; - } - p = maxcp; - } - else - { - break; - } - } -} - - -static void autogk_mheappush(/* Real */ ae_matrix* heap, - ae_int_t heapsize, - ae_int_t heapwidth, - ae_state *_state) -{ - ae_int_t i; - ae_int_t p; - double t; - ae_int_t parent; - - - if( heapsize==0 ) - { - return; - } - p = heapsize; - while(p!=0) - { - parent = (p-1)/2; - if( ae_fp_greater(heap->ptr.pp_double[p][0],heap->ptr.pp_double[parent][0]) ) - { - for(i=0; i<=heapwidth-1; i++) - { - t = heap->ptr.pp_double[p][i]; - heap->ptr.pp_double[p][i] = heap->ptr.pp_double[parent][i]; - heap->ptr.pp_double[parent][i] = t; - } - p = parent; - } - else - { - break; - } - } -} - - -static void autogk_mheapresize(/* Real */ ae_matrix* heap, - ae_int_t* heapsize, - ae_int_t newheapsize, - ae_int_t heapwidth, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix tmp; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init(&tmp, 0, 0, DT_REAL, _state, ae_true); - - ae_matrix_set_length(&tmp, *heapsize, heapwidth, _state); - for(i=0; i<=*heapsize-1; i++) - { - ae_v_move(&tmp.ptr.pp_double[i][0], 1, &heap->ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); - } - ae_matrix_set_length(heap, newheapsize, heapwidth, _state); - for(i=0; i<=*heapsize-1; i++) - { - ae_v_move(&heap->ptr.pp_double[i][0], 1, &tmp.ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); - } - *heapsize = newheapsize; - ae_frame_leave(_state); -} - - -ae_bool _autogkreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - autogkreport *p = (autogkreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _autogkreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - autogkreport *dst = (autogkreport*)_dst; - autogkreport *src = (autogkreport*)_src; - dst->terminationtype = src->terminationtype; - dst->nfev = src->nfev; - dst->nintervals = src->nintervals; - return ae_true; -} - - -void _autogkreport_clear(void* _p) -{ - autogkreport *p = (autogkreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _autogkreport_destroy(void* _p) -{ - autogkreport *p = (autogkreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _autogkinternalstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - autogkinternalstate *p = (autogkinternalstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->heap, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->qn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wr, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _autogkinternalstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - autogkinternalstate *dst = (autogkinternalstate*)_dst; - autogkinternalstate *src = (autogkinternalstate*)_src; - dst->a = src->a; - dst->b = src->b; - dst->eps = src->eps; - dst->xwidth = src->xwidth; - dst->x = src->x; - dst->f = src->f; - dst->info = src->info; - dst->r = src->r; - if( !ae_matrix_init_copy(&dst->heap, &src->heap, _state, make_automatic) ) - return ae_false; - dst->heapsize = src->heapsize; - dst->heapwidth = src->heapwidth; - dst->heapused = src->heapused; - dst->sumerr = src->sumerr; - dst->sumabs = src->sumabs; - if( !ae_vector_init_copy(&dst->qn, &src->qn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wg, &src->wg, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wk, &src->wk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wr, &src->wr, _state, make_automatic) ) - return ae_false; - dst->n = src->n; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _autogkinternalstate_clear(void* _p) -{ - autogkinternalstate *p = (autogkinternalstate*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->heap); - ae_vector_clear(&p->qn); - ae_vector_clear(&p->wg); - ae_vector_clear(&p->wk); - ae_vector_clear(&p->wr); - _rcommstate_clear(&p->rstate); -} - - -void _autogkinternalstate_destroy(void* _p) -{ - autogkinternalstate *p = (autogkinternalstate*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->heap); - ae_vector_destroy(&p->qn); - ae_vector_destroy(&p->wg); - ae_vector_destroy(&p->wk); - ae_vector_destroy(&p->wr); - _rcommstate_destroy(&p->rstate); -} - - -ae_bool _autogkstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - autogkstate *p = (autogkstate*)_p; - ae_touch_ptr((void*)p); - if( !_autogkinternalstate_init(&p->internalstate, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _autogkstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - autogkstate *dst = (autogkstate*)_dst; - autogkstate *src = (autogkstate*)_src; - dst->a = src->a; - dst->b = src->b; - dst->alpha = src->alpha; - dst->beta = src->beta; - dst->xwidth = src->xwidth; - dst->x = src->x; - dst->xminusa = src->xminusa; - dst->bminusx = src->bminusx; - dst->needf = src->needf; - dst->f = src->f; - dst->wrappermode = src->wrappermode; - if( !_autogkinternalstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->v = src->v; - dst->terminationtype = src->terminationtype; - dst->nfev = src->nfev; - dst->nintervals = src->nintervals; - return ae_true; -} - - -void _autogkstate_clear(void* _p) -{ - autogkstate *p = (autogkstate*)_p; - ae_touch_ptr((void*)p); - _autogkinternalstate_clear(&p->internalstate); - _rcommstate_clear(&p->rstate); -} - - -void _autogkstate_destroy(void* _p) -{ - autogkstate *p = (autogkstate*)_p; - ae_touch_ptr((void*)p); - _autogkinternalstate_destroy(&p->internalstate); - _rcommstate_destroy(&p->rstate); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "integration.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Computation of nodes and weights for a Gauss quadrature formula + +The algorithm generates the N-point Gauss quadrature formula with weight +function given by coefficients alpha and beta of a recurrence relation +which generates a system of orthogonal polynomials: + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-1], alpha coefficients + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the quadrature formula, N>=1 + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgeneraterec(alpha.c_ptr(), beta.c_ptr(), mu0, n, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Computation of nodes and weights for a Gauss-Lobatto quadrature formula + +The algorithm generates the N-point Gauss-Lobatto quadrature formula with +weight function given by coefficients alpha and beta of a recurrence which +generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients + Beta - array[0..N-2], beta coefficients. + Zero-indexed element is not used, may be arbitrary. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + B - right boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=3 + (including the left and right boundary nodes). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategausslobattorec(alpha.c_ptr(), beta.c_ptr(), mu0, a, b, n, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Computation of nodes and weights for a Gauss-Radau quadrature formula + +The algorithm generates the N-point Gauss-Radau quadrature formula with +weight function given by the coefficients alpha and beta of a recurrence +which generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients. + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=2 + (including the left boundary node). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategaussradaurec(alpha.c_ptr(), beta.c_ptr(), mu0, a, n, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N +nodes. + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategausslegendre(n, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight +function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha/Beta was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategaussjacobi(n, alpha, beta, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with +weight function W(x)=Power(x,Alpha)*Exp(-x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha is too close to -1 to + obtain weights/nodes with high enough accuracy + or, may be, N is too large. Try to use + multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategausslaguerre(n, alpha, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with +weight function W(x)=Exp(-x*x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. May be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gqgenerategausshermite(n, &info, x.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Computation of nodes and weights of a Gauss-Kronrod quadrature formula + +The algorithm generates the N-point Gauss-Kronrod quadrature formula with +weight function given by coefficients alpha and beta of a recurrence +relation which generates a system of orthogonal polynomials: + + P-1(x) = 0 + P0(x) = 1 + Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zero moment Mu0 + + Mu0 = integral(W(x)dx,a,b) + + +INPUT PARAMETERS: + Alpha - alpha coefficients, array[0..floor(3*K/2)]. + Beta - beta coefficients, array[0..ceil(3*K/2)]. + Beta[0] is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the Gauss-Kronrod quadrature formula, + N >= 3, + N = 2*K+1. + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 N is too large, task may be ill conditioned - + x[i]=x[i+1] found. + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 08.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gkqgeneraterec(alpha.c_ptr(), beta.c_ptr(), mu0, n, &info, x.c_ptr(), wkronrod.c_ptr(), wgauss.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre +quadrature with N points. + +GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is +used depending on machine precision and number of nodes. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gkqgenerategausslegendre(n, &info, x.c_ptr(), wkronrod.c_ptr(), wgauss.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi +quadrature on [-1,1] with weight function + + W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + * +2 OK, but quadrature rule have exterior nodes, + x[0]<-1 or x[n-1]>+1 + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gkqgenerategaussjacobi(n, alpha, beta, &info, x.c_ptr(), wkronrod.c_ptr(), wgauss.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. + +Reduction to tridiagonal eigenproblem is used. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gkqlegendrecalc(n, &info, x.c_ptr(), wkronrod.c_ptr(), wgauss.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using +pre-calculated table. Nodes/weights were computed with accuracy up to +1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision +accuracy reduces to something about 2.0E-16 (depending on your compiler's +handling of long floating point constants). + +INPUT PARAMETERS: + N - number of Kronrod nodes. + N can be 15, 21, 31, 41, 51, 61. + +OUTPUT PARAMETERS: + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::gkqlegendretbl(n, x.c_ptr(), wkronrod.c_ptr(), wgauss.c_ptr(), &eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +Algorithm works well only with smooth integrands. It may be used with +continuous non-smooth integrands, but with less performance. + +It should never be used with integrands which have integrable singularities +at lower or upper limits - algorithm may crash. Use AutoGKSingular in such +cases. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmooth(const double a, const double b, autogkstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::autogksmooth(a, b, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +This subroutine is same as AutoGKSmooth(), but it guarantees that interval +[a,b] is partitioned into subintervals which have width at most XWidth. + +Subroutine can be used when integrating nearly-constant function with +narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth +subroutine can overlook them. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::autogksmoothw(a, b, xwidth, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Integration on a finite interval [A,B]. +Integrand have integrable singularities at A/B. + +F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known +alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates +from below can be used (but these estimates should be greater than -1 too). + +One of alpha/beta variables (or even both alpha/beta) may be equal to 0, +which means than function F(x) is non-singular at A/B. Anyway (singular at +bounds or not), function F(x) is supposed to be continuous on (A,B). + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + Alpha - power-law coefficient of the F(x) at A, + Alpha>-1 + Beta - power-law coefficient of the F(x) at B, + Beta>-1 + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSmoothW, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::autogksingular(a, b, alpha, beta, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool autogkiteration(autogkstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::autogkiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void autogkintegrate(autogkstate &state, + void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), + void *ptr, const xparams _xparams){ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'autogkintegrate()' (func is NULL)", &_alglib_env_state); + while( alglib_impl::autogkiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needf ) + { + func(state.x, state.xminusa, state.bminusx, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: unexpected error in 'autogkintegrate()'", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +Adaptive integration results + +Called after AutoGKIteration returned False. + +Input parameters: + State - algorithm state (used by AutoGKIteration). + +Output parameters: + V - integral(f(x)dx,a,b) + Rep - optimization report (see AutoGKReport description) + + -- ALGLIB -- + Copyright 14.11.2007 by Bochkanov Sergey +*************************************************************************/ +void autogkresults(const autogkstate &state, double &v, autogkreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::autogkresults(state.c_ptr(), &v, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Integration report: +* TerminationType = completetion code: + * -5 non-convergence of Gauss-Kronrod nodes + calculation subroutine. + * -1 incorrect parameters were specified + * 1 OK +* Rep.NFEV countains number of function calculations +* Rep.NIntervals contains number of intervals [a,b] + was partitioned into. +*************************************************************************/ +_autogkreport_owner::_autogkreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_autogkreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::autogkreport)); + alglib_impl::_autogkreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_autogkreport_owner::_autogkreport_owner(alglib_impl::autogkreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_autogkreport_owner::_autogkreport_owner(const _autogkreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_autogkreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: autogkreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::autogkreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::autogkreport)); + alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_autogkreport_owner& _autogkreport_owner::operator=(const _autogkreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: autogkreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: autogkreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: autogkreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_autogkreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::autogkreport)); + alglib_impl::_autogkreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_autogkreport_owner::~_autogkreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_autogkreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::autogkreport* _autogkreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::autogkreport* _autogkreport_owner::c_ptr() const +{ + return p_struct; +} +autogkreport::autogkreport() : _autogkreport_owner() ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) +{ +} + +autogkreport::autogkreport(alglib_impl::autogkreport *attach_to):_autogkreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) +{ +} + +autogkreport::autogkreport(const autogkreport &rhs):_autogkreport_owner(rhs) ,terminationtype(p_struct->terminationtype),nfev(p_struct->nfev),nintervals(p_struct->nintervals) +{ +} + +autogkreport& autogkreport::operator=(const autogkreport &rhs) +{ + if( this==&rhs ) + return *this; + _autogkreport_owner::operator=(rhs); + return *this; +} + +autogkreport::~autogkreport() +{ +} + + + + +/************************************************************************* +This structure stores state of the integration algorithm. + +Although this class has public fields, they are not intended for external +use. You should use ALGLIB functions to work with this class: +* autogksmooth()/AutoGKSmoothW()/... to create objects +* autogkintegrate() to begin integration +* autogkresults() to get results +*************************************************************************/ +_autogkstate_owner::_autogkstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_autogkstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::autogkstate)); + alglib_impl::_autogkstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_autogkstate_owner::_autogkstate_owner(alglib_impl::autogkstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_autogkstate_owner::_autogkstate_owner(const _autogkstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_autogkstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: autogkstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::autogkstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::autogkstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::autogkstate)); + alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_autogkstate_owner& _autogkstate_owner::operator=(const _autogkstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: autogkstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: autogkstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: autogkstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_autogkstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::autogkstate)); + alglib_impl::_autogkstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_autogkstate_owner::~_autogkstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_autogkstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::autogkstate* _autogkstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::autogkstate* _autogkstate_owner::c_ptr() const +{ + return p_struct; +} +autogkstate::autogkstate() : _autogkstate_owner() ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) +{ +} + +autogkstate::autogkstate(alglib_impl::autogkstate *attach_to):_autogkstate_owner(attach_to) ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) +{ +} + +autogkstate::autogkstate(const autogkstate &rhs):_autogkstate_owner(rhs) ,needf(p_struct->needf),x(p_struct->x),xminusa(p_struct->xminusa),bminusx(p_struct->bminusx),f(p_struct->f) +{ +} + +autogkstate& autogkstate::operator=(const autogkstate &rhs) +{ + if( this==&rhs ) + return *this; + _autogkstate_owner::operator=(rhs); + return *this; +} + +autogkstate::~autogkstate() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +static ae_int_t autogk_maxsubintervals = 10000; +static void autogk_autogkinternalprepare(double a, + double b, + double eps, + double xwidth, + autogkinternalstate* state, + ae_state *_state); +static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, + ae_state *_state); +static void autogk_mheappop(/* Real */ ae_matrix* heap, + ae_int_t heapsize, + ae_int_t heapwidth, + ae_state *_state); +static void autogk_mheappush(/* Real */ ae_matrix* heap, + ae_int_t heapsize, + ae_int_t heapwidth, + ae_state *_state); +static void autogk_mheapresize(/* Real */ ae_matrix* heap, + ae_int_t* heapsize, + ae_int_t newheapsize, + ae_int_t heapwidth, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Computation of nodes and weights for a Gauss quadrature formula + +The algorithm generates the N-point Gauss quadrature formula with weight +function given by coefficients alpha and beta of a recurrence relation +which generates a system of orthogonal polynomials: + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-1], alpha coefficients + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the quadrature formula, N>=1 + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgeneraterec(/* Real */ const ae_vector* alpha, + /* Real */ const ae_vector* beta, + double mu0, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector d; + ae_vector e; + ae_matrix z; + + ae_frame_make(_state, &_frame_block); + memset(&d, 0, sizeof(d)); + memset(&e, 0, sizeof(e)); + memset(&z, 0, sizeof(z)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + + if( n<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * Initialize + */ + ae_vector_set_length(&d, n, _state); + ae_vector_set_length(&e, n, _state); + for(i=1; i<=n-1; i++) + { + d.ptr.p_double[i-1] = alpha->ptr.p_double[i-1]; + if( ae_fp_less_eq(beta->ptr.p_double[i],(double)(0)) ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + e.ptr.p_double[i-1] = ae_sqrt(beta->ptr.p_double[i], _state); + } + d.ptr.p_double[n-1] = alpha->ptr.p_double[n-1]; + + /* + * EVD + */ + if( !smatrixtdevd(&d, &e, n, 3, &z, _state) ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * Generate + */ + ae_vector_set_length(x, n, _state); + ae_vector_set_length(w, n, _state); + for(i=1; i<=n; i++) + { + x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; + w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Computation of nodes and weights for a Gauss-Lobatto quadrature formula + +The algorithm generates the N-point Gauss-Lobatto quadrature formula with +weight function given by coefficients alpha and beta of a recurrence which +generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients + Beta - array[0..N-2], beta coefficients. + Zero-indexed element is not used, may be arbitrary. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + B - right boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=3 + (including the left and right boundary nodes). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslobattorec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + double a, + double b, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector alpha; + ae_vector beta; + ae_int_t i; + ae_vector d; + ae_vector e; + ae_matrix z; + double pim1a; + double pia; + double pim1b; + double pib; + double t; + double a11; + double a12; + double a21; + double a22; + double b1; + double b2; + double alph; + double bet; + + ae_frame_make(_state, &_frame_block); + memset(&alpha, 0, sizeof(alpha)); + memset(&beta, 0, sizeof(beta)); + memset(&d, 0, sizeof(d)); + memset(&e, 0, sizeof(e)); + memset(&z, 0, sizeof(z)); + ae_vector_init_copy(&alpha, _alpha, _state, ae_true); + ae_vector_init_copy(&beta, _beta, _state, ae_true); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + + if( n<=2 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * Initialize, D[1:N+1], E[1:N] + */ + n = n-2; + ae_vector_set_length(&d, n+2, _state); + ae_vector_set_length(&e, n+1, _state); + for(i=1; i<=n+1; i++) + { + d.ptr.p_double[i-1] = alpha.ptr.p_double[i-1]; + } + for(i=1; i<=n; i++) + { + if( ae_fp_less_eq(beta.ptr.p_double[i],(double)(0)) ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + e.ptr.p_double[i-1] = ae_sqrt(beta.ptr.p_double[i], _state); + } + + /* + * Caclulate Pn(a), Pn+1(a), Pn(b), Pn+1(b) + */ + beta.ptr.p_double[0] = (double)(0); + pim1a = (double)(0); + pia = (double)(1); + pim1b = (double)(0); + pib = (double)(1); + for(i=1; i<=n+1; i++) + { + + /* + * Pi(a) + */ + t = (a-alpha.ptr.p_double[i-1])*pia-beta.ptr.p_double[i-1]*pim1a; + pim1a = pia; + pia = t; + + /* + * Pi(b) + */ + t = (b-alpha.ptr.p_double[i-1])*pib-beta.ptr.p_double[i-1]*pim1b; + pim1b = pib; + pib = t; + } + + /* + * Calculate alpha'(n+1), beta'(n+1) + */ + a11 = pia; + a12 = pim1a; + a21 = pib; + a22 = pim1b; + b1 = a*pia; + b2 = b*pib; + if( ae_fp_greater(ae_fabs(a11, _state),ae_fabs(a21, _state)) ) + { + a22 = a22-a12*a21/a11; + b2 = b2-b1*a21/a11; + bet = b2/a22; + alph = (b1-bet*a12)/a11; + } + else + { + a12 = a12-a22*a11/a21; + b1 = b1-b2*a11/a21; + bet = b1/a12; + alph = (b2-bet*a22)/a21; + } + if( ae_fp_less(bet,(double)(0)) ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + d.ptr.p_double[n+1] = alph; + e.ptr.p_double[n] = ae_sqrt(bet, _state); + + /* + * EVD + */ + if( !smatrixtdevd(&d, &e, n+2, 3, &z, _state) ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * Generate + */ + ae_vector_set_length(x, n+2, _state); + ae_vector_set_length(w, n+2, _state); + for(i=1; i<=n+2; i++) + { + x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; + w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Computation of nodes and weights for a Gauss-Radau quadrature formula + +The algorithm generates the N-point Gauss-Radau quadrature formula with +weight function given by the coefficients alpha and beta of a recurrence +which generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients. + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=2 + (including the left boundary node). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussradaurec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + double a, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector alpha; + ae_vector beta; + ae_int_t i; + ae_vector d; + ae_vector e; + ae_matrix z; + double polim1; + double poli; + double t; + + ae_frame_make(_state, &_frame_block); + memset(&alpha, 0, sizeof(alpha)); + memset(&beta, 0, sizeof(beta)); + memset(&d, 0, sizeof(d)); + memset(&e, 0, sizeof(e)); + memset(&z, 0, sizeof(z)); + ae_vector_init_copy(&alpha, _alpha, _state, ae_true); + ae_vector_init_copy(&beta, _beta, _state, ae_true); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + + if( n<2 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + *info = 1; + + /* + * Initialize, D[1:N], E[1:N] + */ + n = n-1; + ae_vector_set_length(&d, n+1, _state); + ae_vector_set_length(&e, n, _state); + for(i=1; i<=n; i++) + { + d.ptr.p_double[i-1] = alpha.ptr.p_double[i-1]; + if( ae_fp_less_eq(beta.ptr.p_double[i],(double)(0)) ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + e.ptr.p_double[i-1] = ae_sqrt(beta.ptr.p_double[i], _state); + } + + /* + * Caclulate Pn(a), Pn-1(a), and D[N+1] + */ + beta.ptr.p_double[0] = (double)(0); + polim1 = (double)(0); + poli = (double)(1); + for(i=1; i<=n; i++) + { + t = (a-alpha.ptr.p_double[i-1])*poli-beta.ptr.p_double[i-1]*polim1; + polim1 = poli; + poli = t; + } + d.ptr.p_double[n] = a-beta.ptr.p_double[n]*polim1/poli; + + /* + * EVD + */ + if( !smatrixtdevd(&d, &e, n+1, 3, &z, _state) ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + + /* + * Generate + */ + ae_vector_set_length(x, n+1, _state); + ae_vector_set_length(w, n+1, _state); + for(i=1; i<=n+1; i++) + { + x->ptr.p_double[i-1] = d.ptr.p_double[i-1]; + w->ptr.p_double[i-1] = mu0*ae_sqr(z.ptr.pp_double[0][i-1], _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N +nodes. + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslegendre(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector alpha; + ae_vector beta; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&alpha, 0, sizeof(alpha)); + memset(&beta, 0, sizeof(beta)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&alpha, 0, DT_REAL, _state, ae_true); + ae_vector_init(&beta, 0, DT_REAL, _state, ae_true); + + if( n<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&alpha, n, _state); + ae_vector_set_length(&beta, n, _state); + for(i=0; i<=n-1; i++) + { + alpha.ptr.p_double[i] = (double)(0); + } + beta.ptr.p_double[0] = (double)(2); + for(i=1; i<=n-1; i++) + { + beta.ptr.p_double[i] = (double)1/((double)4-(double)1/ae_sqr((double)(i), _state)); + } + gqgeneraterec(&alpha, &beta, beta.ptr.p_double[0], n, info, x, w, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) + { + *info = -4; + } + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight +function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha/Beta was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussjacobi(ae_int_t n, + double alpha, + double beta, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector b; + double alpha2; + double beta2; + double apb; + double t; + ae_int_t i; + double s; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&b, 0, sizeof(b)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + if( (n<1||ae_fp_less_eq(alpha,(double)(-1)))||ae_fp_less_eq(beta,(double)(-1)) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&a, n, _state); + ae_vector_set_length(&b, n, _state); + apb = alpha+beta; + a.ptr.p_double[0] = (beta-alpha)/(apb+(double)2); + t = (apb+(double)1)*ae_log((double)(2), _state)+lngamma(alpha+(double)1, &s, _state)+lngamma(beta+(double)1, &s, _state)-lngamma(apb+(double)2, &s, _state); + if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + b.ptr.p_double[0] = ae_exp(t, _state); + if( n>1 ) + { + alpha2 = ae_sqr(alpha, _state); + beta2 = ae_sqr(beta, _state); + a.ptr.p_double[1] = (beta2-alpha2)/((apb+(double)2)*(apb+(double)4)); + b.ptr.p_double[1] = (double)4*(alpha+(double)1)*(beta+(double)1)/((apb+(double)3)*ae_sqr(apb+(double)2, _state)); + for(i=2; i<=n-1; i++) + { + a.ptr.p_double[i] = 0.25*(beta2-alpha2)/((double)(i*i)*((double)1+0.5*apb/(double)i)*((double)1+0.5*(apb+(double)2)/(double)i)); + b.ptr.p_double[i] = 0.25*((double)1+alpha/(double)i)*((double)1+beta/(double)i)*((double)1+apb/(double)i)/(((double)1+0.5*(apb+(double)1)/(double)i)*((double)1+0.5*(apb-(double)1)/(double)i)*ae_sqr((double)1+0.5*apb/(double)i, _state)); + } + } + gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) + { + *info = -4; + } + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with +weight function W(x)=Power(x,Alpha)*Exp(-x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha is too close to -1 to + obtain weights/nodes with high enough accuracy + or, may be, N is too large. Try to use + multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslaguerre(ae_int_t n, + double alpha, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector b; + double t; + ae_int_t i; + double s; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&b, 0, sizeof(b)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + if( n<1||ae_fp_less_eq(alpha,(double)(-1)) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&a, n, _state); + ae_vector_set_length(&b, n, _state); + a.ptr.p_double[0] = alpha+(double)1; + t = lngamma(alpha+(double)1, &s, _state); + if( ae_fp_greater_eq(t,ae_log(ae_maxrealnumber, _state)) ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + b.ptr.p_double[0] = ae_exp(t, _state); + if( n>1 ) + { + for(i=1; i<=n-1; i++) + { + a.ptr.p_double[i] = (double)(2*i)+alpha+(double)1; + b.ptr.p_double[i] = (double)i*((double)i+alpha); + } + } + gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + if( ae_fp_less(x->ptr.p_double[0],(double)(0)) ) + { + *info = -4; + } + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with +weight function W(x)=Exp(-x*x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. May be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausshermite(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_vector b; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&b, 0, sizeof(b)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(w); + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + if( n<1 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&a, n, _state); + ae_vector_set_length(&b, n, _state); + for(i=0; i<=n-1; i++) + { + a.ptr.p_double[i] = (double)(0); + } + b.ptr.p_double[0] = ae_sqrt((double)4*ae_atan((double)(1), _state), _state); + if( n>1 ) + { + for(i=1; i<=n-1; i++) + { + b.ptr.p_double[i] = 0.5*(double)i; + } + } + gqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, w, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Computation of nodes and weights of a Gauss-Kronrod quadrature formula + +The algorithm generates the N-point Gauss-Kronrod quadrature formula with +weight function given by coefficients alpha and beta of a recurrence +relation which generates a system of orthogonal polynomials: + + P-1(x) = 0 + P0(x) = 1 + Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zero moment Mu0 + + Mu0 = integral(W(x)dx,a,b) + + +INPUT PARAMETERS: + Alpha - alpha coefficients, array[0..floor(3*K/2)]. + Beta - beta coefficients, array[0..ceil(3*K/2)]. + Beta[0] is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the Gauss-Kronrod quadrature formula, + N >= 3, + N = 2*K+1. + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 N is too large, task may be ill conditioned - + x[i]=x[i+1] found. + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 08.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgeneraterec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector alpha; + ae_vector beta; + ae_vector ta; + ae_int_t i; + ae_int_t j; + ae_vector t; + ae_vector s; + ae_int_t wlen; + ae_int_t woffs; + double u; + ae_int_t m; + ae_int_t l; + ae_int_t k; + ae_vector xgtmp; + ae_vector wgtmp; + + ae_frame_make(_state, &_frame_block); + memset(&alpha, 0, sizeof(alpha)); + memset(&beta, 0, sizeof(beta)); + memset(&ta, 0, sizeof(ta)); + memset(&t, 0, sizeof(t)); + memset(&s, 0, sizeof(s)); + memset(&xgtmp, 0, sizeof(xgtmp)); + memset(&wgtmp, 0, sizeof(wgtmp)); + ae_vector_init_copy(&alpha, _alpha, _state, ae_true); + ae_vector_init_copy(&beta, _beta, _state, ae_true); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(wkronrod); + ae_vector_clear(wgauss); + ae_vector_init(&ta, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xgtmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wgtmp, 0, DT_REAL, _state, ae_true); + + if( n%2!=1||n<3 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=ae_iceil((double)(3*(n/2))/(double)2, _state); i++) + { + if( ae_fp_less_eq(beta.ptr.p_double[i],(double)(0)) ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + } + *info = 1; + + /* + * from external conventions about N/Beta/Mu0 to internal + */ + n = n/2; + beta.ptr.p_double[0] = mu0; + + /* + * Calculate Gauss nodes/weights, save them for later processing + */ + gqgeneraterec(&alpha, &beta, mu0, n, info, &xgtmp, &wgtmp, _state); + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Resize: + * * A from 0..floor(3*n/2) to 0..2*n + * * B from 0..ceil(3*n/2) to 0..2*n + */ + ae_vector_set_length(&ta, ae_ifloor((double)(3*n)/(double)2, _state)+1, _state); + ae_v_move(&ta.ptr.p_double[0], 1, &alpha.ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); + ae_vector_set_length(&alpha, 2*n+1, _state); + ae_v_move(&alpha.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_ifloor((double)(3*n)/(double)2, _state))); + for(i=ae_ifloor((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) + { + alpha.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&ta, ae_iceil((double)(3*n)/(double)2, _state)+1, _state); + ae_v_move(&ta.ptr.p_double[0], 1, &beta.ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); + ae_vector_set_length(&beta, 2*n+1, _state); + ae_v_move(&beta.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,ae_iceil((double)(3*n)/(double)2, _state))); + for(i=ae_iceil((double)(3*n)/(double)2, _state)+1; i<=2*n; i++) + { + beta.ptr.p_double[i] = (double)(0); + } + + /* + * Initialize T, S + */ + wlen = 2+n/2; + ae_vector_set_length(&t, wlen, _state); + ae_vector_set_length(&s, wlen, _state); + ae_vector_set_length(&ta, wlen, _state); + woffs = 1; + for(i=0; i<=wlen-1; i++) + { + t.ptr.p_double[i] = (double)(0); + s.ptr.p_double[i] = (double)(0); + } + + /* + * Algorithm from Dirk P. Laurie, "Calculation of Gauss-Kronrod quadrature rules", 1997. + */ + t.ptr.p_double[woffs+0] = beta.ptr.p_double[n+1]; + for(m=0; m<=n-2; m++) + { + u = (double)(0); + for(k=(m+1)/2; k>=0; k--) + { + l = m-k; + u = u+(alpha.ptr.p_double[k+n+1]-alpha.ptr.p_double[l])*t.ptr.p_double[woffs+k]+beta.ptr.p_double[k+n+1]*s.ptr.p_double[woffs+k-1]-beta.ptr.p_double[l]*s.ptr.p_double[woffs+k]; + s.ptr.p_double[woffs+k] = u; + } + ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + } + for(j=n/2; j>=0; j--) + { + s.ptr.p_double[woffs+j] = s.ptr.p_double[woffs+j-1]; + } + for(m=n-1; m<=2*n-3; m++) + { + u = (double)(0); + for(k=m+1-n; k<=(m-1)/2; k++) + { + l = m-k; + j = n-1-l; + u = u-(alpha.ptr.p_double[k+n+1]-alpha.ptr.p_double[l])*t.ptr.p_double[woffs+j]-beta.ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j]+beta.ptr.p_double[l]*s.ptr.p_double[woffs+j+1]; + s.ptr.p_double[woffs+j] = u; + } + if( m%2==0 ) + { + k = m/2; + alpha.ptr.p_double[k+n+1] = alpha.ptr.p_double[k]+(s.ptr.p_double[woffs+j]-beta.ptr.p_double[k+n+1]*s.ptr.p_double[woffs+j+1])/t.ptr.p_double[woffs+j+1]; + } + else + { + k = (m+1)/2; + beta.ptr.p_double[k+n+1] = s.ptr.p_double[woffs+j]/s.ptr.p_double[woffs+j+1]; + } + ae_v_move(&ta.ptr.p_double[0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + ae_v_move(&t.ptr.p_double[0], 1, &s.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + ae_v_move(&s.ptr.p_double[0], 1, &ta.ptr.p_double[0], 1, ae_v_len(0,wlen-1)); + } + alpha.ptr.p_double[2*n] = alpha.ptr.p_double[n-1]-beta.ptr.p_double[2*n]*s.ptr.p_double[woffs+0]/t.ptr.p_double[woffs+0]; + + /* + * calculation of Kronrod nodes and weights, unpacking of Gauss weights + */ + gqgeneraterec(&alpha, &beta, mu0, 2*n+1, info, x, wkronrod, _state); + if( *info==-2 ) + { + *info = -5; + } + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + for(i=0; i<=2*n-1; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + ae_vector_set_length(wgauss, 2*n+1, _state); + for(i=0; i<=2*n; i++) + { + wgauss->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + wgauss->ptr.p_double[2*i+1] = wgtmp.ptr.p_double[i]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre +quadrature with N points. + +GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is +used depending on machine precision and number of nodes. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategausslegendre(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state) +{ + double eps; + + *info = 0; + ae_vector_clear(x); + ae_vector_clear(wkronrod); + ae_vector_clear(wgauss); + + if( ae_fp_greater(ae_machineepsilon,1.0E-32)&&(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61) ) + { + *info = 1; + gkqlegendretbl(n, x, wkronrod, wgauss, &eps, _state); + } + else + { + gkqlegendrecalc(n, info, x, wkronrod, wgauss, _state); + } +} + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi +quadrature on [-1,1] with weight function + + W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + * +2 OK, but quadrature rule have exterior nodes, + x[0]<-1 or x[n-1]>+1 + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategaussjacobi(ae_int_t n, + double alpha, + double beta, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t clen; + ae_vector a; + ae_vector b; + double alpha2; + double beta2; + double apb; + double t; + ae_int_t i; + double s; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&b, 0, sizeof(b)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(wkronrod); + ae_vector_clear(wgauss); + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + + if( n%2!=1||n<3 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( ae_fp_less_eq(alpha,(double)(-1))||ae_fp_less_eq(beta,(double)(-1)) ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + clen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; + ae_vector_set_length(&a, clen, _state); + ae_vector_set_length(&b, clen, _state); + for(i=0; i<=clen-1; i++) + { + a.ptr.p_double[i] = (double)(0); + } + apb = alpha+beta; + a.ptr.p_double[0] = (beta-alpha)/(apb+(double)2); + t = (apb+(double)1)*ae_log((double)(2), _state)+lngamma(alpha+(double)1, &s, _state)+lngamma(beta+(double)1, &s, _state)-lngamma(apb+(double)2, &s, _state); + if( ae_fp_greater(t,ae_log(ae_maxrealnumber, _state)) ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + b.ptr.p_double[0] = ae_exp(t, _state); + if( clen>1 ) + { + alpha2 = ae_sqr(alpha, _state); + beta2 = ae_sqr(beta, _state); + a.ptr.p_double[1] = (beta2-alpha2)/((apb+(double)2)*(apb+(double)4)); + b.ptr.p_double[1] = (double)4*(alpha+(double)1)*(beta+(double)1)/((apb+(double)3)*ae_sqr(apb+(double)2, _state)); + for(i=2; i<=clen-1; i++) + { + a.ptr.p_double[i] = 0.25*(beta2-alpha2)/((double)(i*i)*((double)1+0.5*apb/(double)i)*((double)1+0.5*(apb+(double)2)/(double)i)); + b.ptr.p_double[i] = 0.25*((double)1+alpha/(double)i)*((double)1+beta/(double)i)*((double)1+apb/(double)i)/(((double)1+0.5*(apb+(double)1)/(double)i)*((double)1+0.5*(apb-(double)1)/(double)i)*ae_sqr((double)1+0.5*apb/(double)i, _state)); + } + } + gkqgeneraterec(&a, &b, b.ptr.p_double[0], n, info, x, wkronrod, wgauss, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) + { + *info = 2; + } + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. + +Reduction to tridiagonal eigenproblem is used. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendrecalc(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector alpha; + ae_vector beta; + ae_int_t alen; + ae_int_t blen; + double mu0; + ae_int_t k; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&alpha, 0, sizeof(alpha)); + memset(&beta, 0, sizeof(beta)); + *info = 0; + ae_vector_clear(x); + ae_vector_clear(wkronrod); + ae_vector_clear(wgauss); + ae_vector_init(&alpha, 0, DT_REAL, _state, ae_true); + ae_vector_init(&beta, 0, DT_REAL, _state, ae_true); + + if( n%2!=1||n<3 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + mu0 = (double)(2); + alen = ae_ifloor((double)(3*(n/2))/(double)2, _state)+1; + blen = ae_iceil((double)(3*(n/2))/(double)2, _state)+1; + ae_vector_set_length(&alpha, alen, _state); + ae_vector_set_length(&beta, blen, _state); + for(k=0; k<=alen-1; k++) + { + alpha.ptr.p_double[k] = (double)(0); + } + beta.ptr.p_double[0] = (double)(2); + for(k=1; k<=blen-1; k++) + { + beta.ptr.p_double[k] = (double)1/((double)4-(double)1/ae_sqr((double)(k), _state)); + } + gkqgeneraterec(&alpha, &beta, mu0, n, info, x, wkronrod, wgauss, _state); + + /* + * test basic properties to detect errors + */ + if( *info>0 ) + { + if( ae_fp_less(x->ptr.p_double[0],(double)(-1))||ae_fp_greater(x->ptr.p_double[n-1],(double)(1)) ) + { + *info = -4; + } + for(i=0; i<=n-2; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],x->ptr.p_double[i+1]) ) + { + *info = -4; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using +pre-calculated table. Nodes/weights were computed with accuracy up to +1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision +accuracy reduces to something about 2.0E-16 (depending on your compiler's +handling of long floating point constants). + +INPUT PARAMETERS: + N - number of Kronrod nodes. + N can be 15, 21, 31, 41, 51, 61. + +OUTPUT PARAMETERS: + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendretbl(ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + double* eps, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t ng; + ae_vector p1; + ae_vector p2; + double tmp; + + ae_frame_make(_state, &_frame_block); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + ae_vector_clear(x); + ae_vector_clear(wkronrod); + ae_vector_clear(wgauss); + *eps = 0.0; + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + ng = 0; + + /* + * Process + */ + ae_assert(((((n==15||n==21)||n==31)||n==41)||n==51)||n==61, "GKQNodesTbl: incorrect N!", _state); + ae_vector_set_length(x, n, _state); + ae_vector_set_length(wkronrod, n, _state); + ae_vector_set_length(wgauss, n, _state); + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + wkronrod->ptr.p_double[i] = (double)(0); + wgauss->ptr.p_double[i] = (double)(0); + } + *eps = ae_maxreal(ae_machineepsilon, 1.0E-32, _state); + if( n==15 ) + { + ng = 4; + wgauss->ptr.p_double[0] = 0.129484966168869693270611432679082; + wgauss->ptr.p_double[1] = 0.279705391489276667901467771423780; + wgauss->ptr.p_double[2] = 0.381830050505118944950369775488975; + wgauss->ptr.p_double[3] = 0.417959183673469387755102040816327; + x->ptr.p_double[0] = 0.991455371120812639206854697526329; + x->ptr.p_double[1] = 0.949107912342758524526189684047851; + x->ptr.p_double[2] = 0.864864423359769072789712788640926; + x->ptr.p_double[3] = 0.741531185599394439863864773280788; + x->ptr.p_double[4] = 0.586087235467691130294144838258730; + x->ptr.p_double[5] = 0.405845151377397166906606412076961; + x->ptr.p_double[6] = 0.207784955007898467600689403773245; + x->ptr.p_double[7] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.022935322010529224963732008058970; + wkronrod->ptr.p_double[1] = 0.063092092629978553290700663189204; + wkronrod->ptr.p_double[2] = 0.104790010322250183839876322541518; + wkronrod->ptr.p_double[3] = 0.140653259715525918745189590510238; + wkronrod->ptr.p_double[4] = 0.169004726639267902826583426598550; + wkronrod->ptr.p_double[5] = 0.190350578064785409913256402421014; + wkronrod->ptr.p_double[6] = 0.204432940075298892414161999234649; + wkronrod->ptr.p_double[7] = 0.209482141084727828012999174891714; + } + if( n==21 ) + { + ng = 5; + wgauss->ptr.p_double[0] = 0.066671344308688137593568809893332; + wgauss->ptr.p_double[1] = 0.149451349150580593145776339657697; + wgauss->ptr.p_double[2] = 0.219086362515982043995534934228163; + wgauss->ptr.p_double[3] = 0.269266719309996355091226921569469; + wgauss->ptr.p_double[4] = 0.295524224714752870173892994651338; + x->ptr.p_double[0] = 0.995657163025808080735527280689003; + x->ptr.p_double[1] = 0.973906528517171720077964012084452; + x->ptr.p_double[2] = 0.930157491355708226001207180059508; + x->ptr.p_double[3] = 0.865063366688984510732096688423493; + x->ptr.p_double[4] = 0.780817726586416897063717578345042; + x->ptr.p_double[5] = 0.679409568299024406234327365114874; + x->ptr.p_double[6] = 0.562757134668604683339000099272694; + x->ptr.p_double[7] = 0.433395394129247190799265943165784; + x->ptr.p_double[8] = 0.294392862701460198131126603103866; + x->ptr.p_double[9] = 0.148874338981631210884826001129720; + x->ptr.p_double[10] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.011694638867371874278064396062192; + wkronrod->ptr.p_double[1] = 0.032558162307964727478818972459390; + wkronrod->ptr.p_double[2] = 0.054755896574351996031381300244580; + wkronrod->ptr.p_double[3] = 0.075039674810919952767043140916190; + wkronrod->ptr.p_double[4] = 0.093125454583697605535065465083366; + wkronrod->ptr.p_double[5] = 0.109387158802297641899210590325805; + wkronrod->ptr.p_double[6] = 0.123491976262065851077958109831074; + wkronrod->ptr.p_double[7] = 0.134709217311473325928054001771707; + wkronrod->ptr.p_double[8] = 0.142775938577060080797094273138717; + wkronrod->ptr.p_double[9] = 0.147739104901338491374841515972068; + wkronrod->ptr.p_double[10] = 0.149445554002916905664936468389821; + } + if( n==31 ) + { + ng = 8; + wgauss->ptr.p_double[0] = 0.030753241996117268354628393577204; + wgauss->ptr.p_double[1] = 0.070366047488108124709267416450667; + wgauss->ptr.p_double[2] = 0.107159220467171935011869546685869; + wgauss->ptr.p_double[3] = 0.139570677926154314447804794511028; + wgauss->ptr.p_double[4] = 0.166269205816993933553200860481209; + wgauss->ptr.p_double[5] = 0.186161000015562211026800561866423; + wgauss->ptr.p_double[6] = 0.198431485327111576456118326443839; + wgauss->ptr.p_double[7] = 0.202578241925561272880620199967519; + x->ptr.p_double[0] = 0.998002298693397060285172840152271; + x->ptr.p_double[1] = 0.987992518020485428489565718586613; + x->ptr.p_double[2] = 0.967739075679139134257347978784337; + x->ptr.p_double[3] = 0.937273392400705904307758947710209; + x->ptr.p_double[4] = 0.897264532344081900882509656454496; + x->ptr.p_double[5] = 0.848206583410427216200648320774217; + x->ptr.p_double[6] = 0.790418501442465932967649294817947; + x->ptr.p_double[7] = 0.724417731360170047416186054613938; + x->ptr.p_double[8] = 0.650996741297416970533735895313275; + x->ptr.p_double[9] = 0.570972172608538847537226737253911; + x->ptr.p_double[10] = 0.485081863640239680693655740232351; + x->ptr.p_double[11] = 0.394151347077563369897207370981045; + x->ptr.p_double[12] = 0.299180007153168812166780024266389; + x->ptr.p_double[13] = 0.201194093997434522300628303394596; + x->ptr.p_double[14] = 0.101142066918717499027074231447392; + x->ptr.p_double[15] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.005377479872923348987792051430128; + wkronrod->ptr.p_double[1] = 0.015007947329316122538374763075807; + wkronrod->ptr.p_double[2] = 0.025460847326715320186874001019653; + wkronrod->ptr.p_double[3] = 0.035346360791375846222037948478360; + wkronrod->ptr.p_double[4] = 0.044589751324764876608227299373280; + wkronrod->ptr.p_double[5] = 0.053481524690928087265343147239430; + wkronrod->ptr.p_double[6] = 0.062009567800670640285139230960803; + wkronrod->ptr.p_double[7] = 0.069854121318728258709520077099147; + wkronrod->ptr.p_double[8] = 0.076849680757720378894432777482659; + wkronrod->ptr.p_double[9] = 0.083080502823133021038289247286104; + wkronrod->ptr.p_double[10] = 0.088564443056211770647275443693774; + wkronrod->ptr.p_double[11] = 0.093126598170825321225486872747346; + wkronrod->ptr.p_double[12] = 0.096642726983623678505179907627589; + wkronrod->ptr.p_double[13] = 0.099173598721791959332393173484603; + wkronrod->ptr.p_double[14] = 0.100769845523875595044946662617570; + wkronrod->ptr.p_double[15] = 0.101330007014791549017374792767493; + } + if( n==41 ) + { + ng = 10; + wgauss->ptr.p_double[0] = 0.017614007139152118311861962351853; + wgauss->ptr.p_double[1] = 0.040601429800386941331039952274932; + wgauss->ptr.p_double[2] = 0.062672048334109063569506535187042; + wgauss->ptr.p_double[3] = 0.083276741576704748724758143222046; + wgauss->ptr.p_double[4] = 0.101930119817240435036750135480350; + wgauss->ptr.p_double[5] = 0.118194531961518417312377377711382; + wgauss->ptr.p_double[6] = 0.131688638449176626898494499748163; + wgauss->ptr.p_double[7] = 0.142096109318382051329298325067165; + wgauss->ptr.p_double[8] = 0.149172986472603746787828737001969; + wgauss->ptr.p_double[9] = 0.152753387130725850698084331955098; + x->ptr.p_double[0] = 0.998859031588277663838315576545863; + x->ptr.p_double[1] = 0.993128599185094924786122388471320; + x->ptr.p_double[2] = 0.981507877450250259193342994720217; + x->ptr.p_double[3] = 0.963971927277913791267666131197277; + x->ptr.p_double[4] = 0.940822633831754753519982722212443; + x->ptr.p_double[5] = 0.912234428251325905867752441203298; + x->ptr.p_double[6] = 0.878276811252281976077442995113078; + x->ptr.p_double[7] = 0.839116971822218823394529061701521; + x->ptr.p_double[8] = 0.795041428837551198350638833272788; + x->ptr.p_double[9] = 0.746331906460150792614305070355642; + x->ptr.p_double[10] = 0.693237656334751384805490711845932; + x->ptr.p_double[11] = 0.636053680726515025452836696226286; + x->ptr.p_double[12] = 0.575140446819710315342946036586425; + x->ptr.p_double[13] = 0.510867001950827098004364050955251; + x->ptr.p_double[14] = 0.443593175238725103199992213492640; + x->ptr.p_double[15] = 0.373706088715419560672548177024927; + x->ptr.p_double[16] = 0.301627868114913004320555356858592; + x->ptr.p_double[17] = 0.227785851141645078080496195368575; + x->ptr.p_double[18] = 0.152605465240922675505220241022678; + x->ptr.p_double[19] = 0.076526521133497333754640409398838; + x->ptr.p_double[20] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.003073583718520531501218293246031; + wkronrod->ptr.p_double[1] = 0.008600269855642942198661787950102; + wkronrod->ptr.p_double[2] = 0.014626169256971252983787960308868; + wkronrod->ptr.p_double[3] = 0.020388373461266523598010231432755; + wkronrod->ptr.p_double[4] = 0.025882133604951158834505067096153; + wkronrod->ptr.p_double[5] = 0.031287306777032798958543119323801; + wkronrod->ptr.p_double[6] = 0.036600169758200798030557240707211; + wkronrod->ptr.p_double[7] = 0.041668873327973686263788305936895; + wkronrod->ptr.p_double[8] = 0.046434821867497674720231880926108; + wkronrod->ptr.p_double[9] = 0.050944573923728691932707670050345; + wkronrod->ptr.p_double[10] = 0.055195105348285994744832372419777; + wkronrod->ptr.p_double[11] = 0.059111400880639572374967220648594; + wkronrod->ptr.p_double[12] = 0.062653237554781168025870122174255; + wkronrod->ptr.p_double[13] = 0.065834597133618422111563556969398; + wkronrod->ptr.p_double[14] = 0.068648672928521619345623411885368; + wkronrod->ptr.p_double[15] = 0.071054423553444068305790361723210; + wkronrod->ptr.p_double[16] = 0.073030690332786667495189417658913; + wkronrod->ptr.p_double[17] = 0.074582875400499188986581418362488; + wkronrod->ptr.p_double[18] = 0.075704497684556674659542775376617; + wkronrod->ptr.p_double[19] = 0.076377867672080736705502835038061; + wkronrod->ptr.p_double[20] = 0.076600711917999656445049901530102; + } + if( n==51 ) + { + ng = 13; + wgauss->ptr.p_double[0] = 0.011393798501026287947902964113235; + wgauss->ptr.p_double[1] = 0.026354986615032137261901815295299; + wgauss->ptr.p_double[2] = 0.040939156701306312655623487711646; + wgauss->ptr.p_double[3] = 0.054904695975835191925936891540473; + wgauss->ptr.p_double[4] = 0.068038333812356917207187185656708; + wgauss->ptr.p_double[5] = 0.080140700335001018013234959669111; + wgauss->ptr.p_double[6] = 0.091028261982963649811497220702892; + wgauss->ptr.p_double[7] = 0.100535949067050644202206890392686; + wgauss->ptr.p_double[8] = 0.108519624474263653116093957050117; + wgauss->ptr.p_double[9] = 0.114858259145711648339325545869556; + wgauss->ptr.p_double[10] = 0.119455763535784772228178126512901; + wgauss->ptr.p_double[11] = 0.122242442990310041688959518945852; + wgauss->ptr.p_double[12] = 0.123176053726715451203902873079050; + x->ptr.p_double[0] = 0.999262104992609834193457486540341; + x->ptr.p_double[1] = 0.995556969790498097908784946893902; + x->ptr.p_double[2] = 0.988035794534077247637331014577406; + x->ptr.p_double[3] = 0.976663921459517511498315386479594; + x->ptr.p_double[4] = 0.961614986425842512418130033660167; + x->ptr.p_double[5] = 0.942974571228974339414011169658471; + x->ptr.p_double[6] = 0.920747115281701561746346084546331; + x->ptr.p_double[7] = 0.894991997878275368851042006782805; + x->ptr.p_double[8] = 0.865847065293275595448996969588340; + x->ptr.p_double[9] = 0.833442628760834001421021108693570; + x->ptr.p_double[10] = 0.797873797998500059410410904994307; + x->ptr.p_double[11] = 0.759259263037357630577282865204361; + x->ptr.p_double[12] = 0.717766406813084388186654079773298; + x->ptr.p_double[13] = 0.673566368473468364485120633247622; + x->ptr.p_double[14] = 0.626810099010317412788122681624518; + x->ptr.p_double[15] = 0.577662930241222967723689841612654; + x->ptr.p_double[16] = 0.526325284334719182599623778158010; + x->ptr.p_double[17] = 0.473002731445714960522182115009192; + x->ptr.p_double[18] = 0.417885382193037748851814394594572; + x->ptr.p_double[19] = 0.361172305809387837735821730127641; + x->ptr.p_double[20] = 0.303089538931107830167478909980339; + x->ptr.p_double[21] = 0.243866883720988432045190362797452; + x->ptr.p_double[22] = 0.183718939421048892015969888759528; + x->ptr.p_double[23] = 0.122864692610710396387359818808037; + x->ptr.p_double[24] = 0.061544483005685078886546392366797; + x->ptr.p_double[25] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.001987383892330315926507851882843; + wkronrod->ptr.p_double[1] = 0.005561932135356713758040236901066; + wkronrod->ptr.p_double[2] = 0.009473973386174151607207710523655; + wkronrod->ptr.p_double[3] = 0.013236229195571674813656405846976; + wkronrod->ptr.p_double[4] = 0.016847817709128298231516667536336; + wkronrod->ptr.p_double[5] = 0.020435371145882835456568292235939; + wkronrod->ptr.p_double[6] = 0.024009945606953216220092489164881; + wkronrod->ptr.p_double[7] = 0.027475317587851737802948455517811; + wkronrod->ptr.p_double[8] = 0.030792300167387488891109020215229; + wkronrod->ptr.p_double[9] = 0.034002130274329337836748795229551; + wkronrod->ptr.p_double[10] = 0.037116271483415543560330625367620; + wkronrod->ptr.p_double[11] = 0.040083825504032382074839284467076; + wkronrod->ptr.p_double[12] = 0.042872845020170049476895792439495; + wkronrod->ptr.p_double[13] = 0.045502913049921788909870584752660; + wkronrod->ptr.p_double[14] = 0.047982537138836713906392255756915; + wkronrod->ptr.p_double[15] = 0.050277679080715671963325259433440; + wkronrod->ptr.p_double[16] = 0.052362885806407475864366712137873; + wkronrod->ptr.p_double[17] = 0.054251129888545490144543370459876; + wkronrod->ptr.p_double[18] = 0.055950811220412317308240686382747; + wkronrod->ptr.p_double[19] = 0.057437116361567832853582693939506; + wkronrod->ptr.p_double[20] = 0.058689680022394207961974175856788; + wkronrod->ptr.p_double[21] = 0.059720340324174059979099291932562; + wkronrod->ptr.p_double[22] = 0.060539455376045862945360267517565; + wkronrod->ptr.p_double[23] = 0.061128509717053048305859030416293; + wkronrod->ptr.p_double[24] = 0.061471189871425316661544131965264; + wkronrod->ptr.p_double[25] = 0.061580818067832935078759824240055; + } + if( n==61 ) + { + ng = 15; + wgauss->ptr.p_double[0] = 0.007968192496166605615465883474674; + wgauss->ptr.p_double[1] = 0.018466468311090959142302131912047; + wgauss->ptr.p_double[2] = 0.028784707883323369349719179611292; + wgauss->ptr.p_double[3] = 0.038799192569627049596801936446348; + wgauss->ptr.p_double[4] = 0.048402672830594052902938140422808; + wgauss->ptr.p_double[5] = 0.057493156217619066481721689402056; + wgauss->ptr.p_double[6] = 0.065974229882180495128128515115962; + wgauss->ptr.p_double[7] = 0.073755974737705206268243850022191; + wgauss->ptr.p_double[8] = 0.080755895229420215354694938460530; + wgauss->ptr.p_double[9] = 0.086899787201082979802387530715126; + wgauss->ptr.p_double[10] = 0.092122522237786128717632707087619; + wgauss->ptr.p_double[11] = 0.096368737174644259639468626351810; + wgauss->ptr.p_double[12] = 0.099593420586795267062780282103569; + wgauss->ptr.p_double[13] = 0.101762389748405504596428952168554; + wgauss->ptr.p_double[14] = 0.102852652893558840341285636705415; + x->ptr.p_double[0] = 0.999484410050490637571325895705811; + x->ptr.p_double[1] = 0.996893484074649540271630050918695; + x->ptr.p_double[2] = 0.991630996870404594858628366109486; + x->ptr.p_double[3] = 0.983668123279747209970032581605663; + x->ptr.p_double[4] = 0.973116322501126268374693868423707; + x->ptr.p_double[5] = 0.960021864968307512216871025581798; + x->ptr.p_double[6] = 0.944374444748559979415831324037439; + x->ptr.p_double[7] = 0.926200047429274325879324277080474; + x->ptr.p_double[8] = 0.905573307699907798546522558925958; + x->ptr.p_double[9] = 0.882560535792052681543116462530226; + x->ptr.p_double[10] = 0.857205233546061098958658510658944; + x->ptr.p_double[11] = 0.829565762382768397442898119732502; + x->ptr.p_double[12] = 0.799727835821839083013668942322683; + x->ptr.p_double[13] = 0.767777432104826194917977340974503; + x->ptr.p_double[14] = 0.733790062453226804726171131369528; + x->ptr.p_double[15] = 0.697850494793315796932292388026640; + x->ptr.p_double[16] = 0.660061064126626961370053668149271; + x->ptr.p_double[17] = 0.620526182989242861140477556431189; + x->ptr.p_double[18] = 0.579345235826361691756024932172540; + x->ptr.p_double[19] = 0.536624148142019899264169793311073; + x->ptr.p_double[20] = 0.492480467861778574993693061207709; + x->ptr.p_double[21] = 0.447033769538089176780609900322854; + x->ptr.p_double[22] = 0.400401254830394392535476211542661; + x->ptr.p_double[23] = 0.352704725530878113471037207089374; + x->ptr.p_double[24] = 0.304073202273625077372677107199257; + x->ptr.p_double[25] = 0.254636926167889846439805129817805; + x->ptr.p_double[26] = 0.204525116682309891438957671002025; + x->ptr.p_double[27] = 0.153869913608583546963794672743256; + x->ptr.p_double[28] = 0.102806937966737030147096751318001; + x->ptr.p_double[29] = 0.051471842555317695833025213166723; + x->ptr.p_double[30] = 0.000000000000000000000000000000000; + wkronrod->ptr.p_double[0] = 0.001389013698677007624551591226760; + wkronrod->ptr.p_double[1] = 0.003890461127099884051267201844516; + wkronrod->ptr.p_double[2] = 0.006630703915931292173319826369750; + wkronrod->ptr.p_double[3] = 0.009273279659517763428441146892024; + wkronrod->ptr.p_double[4] = 0.011823015253496341742232898853251; + wkronrod->ptr.p_double[5] = 0.014369729507045804812451432443580; + wkronrod->ptr.p_double[6] = 0.016920889189053272627572289420322; + wkronrod->ptr.p_double[7] = 0.019414141193942381173408951050128; + wkronrod->ptr.p_double[8] = 0.021828035821609192297167485738339; + wkronrod->ptr.p_double[9] = 0.024191162078080601365686370725232; + wkronrod->ptr.p_double[10] = 0.026509954882333101610601709335075; + wkronrod->ptr.p_double[11] = 0.028754048765041292843978785354334; + wkronrod->ptr.p_double[12] = 0.030907257562387762472884252943092; + wkronrod->ptr.p_double[13] = 0.032981447057483726031814191016854; + wkronrod->ptr.p_double[14] = 0.034979338028060024137499670731468; + wkronrod->ptr.p_double[15] = 0.036882364651821229223911065617136; + wkronrod->ptr.p_double[16] = 0.038678945624727592950348651532281; + wkronrod->ptr.p_double[17] = 0.040374538951535959111995279752468; + wkronrod->ptr.p_double[18] = 0.041969810215164246147147541285970; + wkronrod->ptr.p_double[19] = 0.043452539701356069316831728117073; + wkronrod->ptr.p_double[20] = 0.044814800133162663192355551616723; + wkronrod->ptr.p_double[21] = 0.046059238271006988116271735559374; + wkronrod->ptr.p_double[22] = 0.047185546569299153945261478181099; + wkronrod->ptr.p_double[23] = 0.048185861757087129140779492298305; + wkronrod->ptr.p_double[24] = 0.049055434555029778887528165367238; + wkronrod->ptr.p_double[25] = 0.049795683427074206357811569379942; + wkronrod->ptr.p_double[26] = 0.050405921402782346840893085653585; + wkronrod->ptr.p_double[27] = 0.050881795898749606492297473049805; + wkronrod->ptr.p_double[28] = 0.051221547849258772170656282604944; + wkronrod->ptr.p_double[29] = 0.051426128537459025933862879215781; + wkronrod->ptr.p_double[30] = 0.051494729429451567558340433647099; + } + + /* + * copy nodes + */ + for(i=n-1; i>=n/2; i--) + { + x->ptr.p_double[i] = -x->ptr.p_double[n-1-i]; + } + + /* + * copy Kronrod weights + */ + for(i=n-1; i>=n/2; i--) + { + wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[n-1-i]; + } + + /* + * copy Gauss weights + */ + for(i=ng-1; i>=0; i--) + { + wgauss->ptr.p_double[n-2-2*i] = wgauss->ptr.p_double[i]; + wgauss->ptr.p_double[1+2*i] = wgauss->ptr.p_double[i]; + } + for(i=0; i<=n/2; i++) + { + wgauss->ptr.p_double[2*i] = (double)(0); + } + + /* + * reorder + */ + tagsort(x, n, &p1, &p2, _state); + for(i=0; i<=n-1; i++) + { + tmp = wkronrod->ptr.p_double[i]; + wkronrod->ptr.p_double[i] = wkronrod->ptr.p_double[p2.ptr.p_int[i]]; + wkronrod->ptr.p_double[p2.ptr.p_int[i]] = tmp; + tmp = wgauss->ptr.p_double[i]; + wgauss->ptr.p_double[i] = wgauss->ptr.p_double[p2.ptr.p_int[i]]; + wgauss->ptr.p_double[p2.ptr.p_int[i]] = tmp; + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +Algorithm works well only with smooth integrands. It may be used with +continuous non-smooth integrands, but with less performance. + +It should never be used with integrands which have integrable singularities +at lower or upper limits - algorithm may crash. Use AutoGKSingular in such +cases. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmooth(double a, + double b, + autogkstate* state, + ae_state *_state) +{ + + _autogkstate_clear(state); + + ae_assert(ae_isfinite(a, _state), "AutoGKSmooth: A is not finite!", _state); + ae_assert(ae_isfinite(b, _state), "AutoGKSmooth: B is not finite!", _state); + autogksmoothw(a, b, 0.0, state, _state); +} + + +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +This subroutine is same as AutoGKSmooth(), but it guarantees that interval +[a,b] is partitioned into subintervals which have width at most XWidth. + +Subroutine can be used when integrating nearly-constant function with +narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth +subroutine can overlook them. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmoothw(double a, + double b, + double xwidth, + autogkstate* state, + ae_state *_state) +{ + + _autogkstate_clear(state); + + ae_assert(ae_isfinite(a, _state), "AutoGKSmoothW: A is not finite!", _state); + ae_assert(ae_isfinite(b, _state), "AutoGKSmoothW: B is not finite!", _state); + ae_assert(ae_isfinite(xwidth, _state), "AutoGKSmoothW: XWidth is not finite!", _state); + state->wrappermode = 0; + state->a = a; + state->b = b; + state->xwidth = xwidth; + state->needf = ae_false; + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Integration on a finite interval [A,B]. +Integrand have integrable singularities at A/B. + +F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known +alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates +from below can be used (but these estimates should be greater than -1 too). + +One of alpha/beta variables (or even both alpha/beta) may be equal to 0, +which means than function F(x) is non-singular at A/B. Anyway (singular at +bounds or not), function F(x) is supposed to be continuous on (A,B). + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + Alpha - power-law coefficient of the F(x) at A, + Alpha>-1 + Beta - power-law coefficient of the F(x) at B, + Beta>-1 + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSmoothW, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksingular(double a, + double b, + double alpha, + double beta, + autogkstate* state, + ae_state *_state) +{ + + _autogkstate_clear(state); + + ae_assert(ae_isfinite(a, _state), "AutoGKSingular: A is not finite!", _state); + ae_assert(ae_isfinite(b, _state), "AutoGKSingular: B is not finite!", _state); + ae_assert(ae_isfinite(alpha, _state), "AutoGKSingular: Alpha is not finite!", _state); + ae_assert(ae_isfinite(beta, _state), "AutoGKSingular: Beta is not finite!", _state); + state->wrappermode = 1; + state->a = a; + state->b = b; + state->alpha = alpha; + state->beta = beta; + state->xwidth = 0.0; + state->needf = ae_false; + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 07.05.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool autogkiteration(autogkstate* state, ae_state *_state) +{ + double s; + double tmp; + double eps; + double a; + double b; + double x; + double t; + double alpha; + double beta; + double v1; + double v2; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + s = state->rstate.ra.ptr.p_double[0]; + tmp = state->rstate.ra.ptr.p_double[1]; + eps = state->rstate.ra.ptr.p_double[2]; + a = state->rstate.ra.ptr.p_double[3]; + b = state->rstate.ra.ptr.p_double[4]; + x = state->rstate.ra.ptr.p_double[5]; + t = state->rstate.ra.ptr.p_double[6]; + alpha = state->rstate.ra.ptr.p_double[7]; + beta = state->rstate.ra.ptr.p_double[8]; + v1 = state->rstate.ra.ptr.p_double[9]; + v2 = state->rstate.ra.ptr.p_double[10]; + } + else + { + s = 359.0; + tmp = -58.0; + eps = -919.0; + a = -909.0; + b = 81.0; + x = 255.0; + t = 74.0; + alpha = -788.0; + beta = 809.0; + v1 = 205.0; + v2 = -838.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + eps = (double)(0); + a = state->a; + b = state->b; + alpha = state->alpha; + beta = state->beta; + state->terminationtype = -1; + state->nfev = 0; + state->nintervals = 0; + + /* + * smooth function at a finite interval + */ + if( state->wrappermode!=0 ) + { + goto lbl_3; + } + + /* + * special case + */ + if( ae_fp_eq(a,b) ) + { + state->terminationtype = 1; + state->v = (double)(0); + result = ae_false; + return result; + } + + /* + * general case + */ + autogk_autogkinternalprepare(a, b, eps, state->xwidth, &state->internalstate, _state); +lbl_5: + if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) + { + goto lbl_6; + } + x = state->internalstate.x; + state->x = x; + state->xminusa = x-a; + state->bminusx = b-x; + state->needf = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needf = ae_false; + state->nfev = state->nfev+1; + state->internalstate.f = state->f; + goto lbl_5; +lbl_6: + state->v = state->internalstate.r; + state->terminationtype = state->internalstate.info; + state->nintervals = state->internalstate.heapused; + result = ae_false; + return result; +lbl_3: + + /* + * function with power-law singularities at the ends of a finite interval + */ + if( state->wrappermode!=1 ) + { + goto lbl_7; + } + + /* + * test coefficients + */ + if( ae_fp_less_eq(alpha,(double)(-1))||ae_fp_less_eq(beta,(double)(-1)) ) + { + state->terminationtype = -1; + state->v = (double)(0); + result = ae_false; + return result; + } + + /* + * special cases + */ + if( ae_fp_eq(a,b) ) + { + state->terminationtype = 1; + state->v = (double)(0); + result = ae_false; + return result; + } + + /* + * reduction to general form + */ + if( ae_fp_less(a,b) ) + { + s = (double)(1); + } + else + { + s = (double)(-1); + tmp = a; + a = b; + b = tmp; + tmp = alpha; + alpha = beta; + beta = tmp; + } + alpha = ae_minreal(alpha, (double)(0), _state); + beta = ae_minreal(beta, (double)(0), _state); + + /* + * first, integrate left half of [a,b]: + * integral(f(x)dx, a, (b+a)/2) = + * = 1/(1+alpha) * integral(t^(-alpha/(1+alpha))*f(a+t^(1/(1+alpha)))dt, 0, (0.5*(b-a))^(1+alpha)) + */ + autogk_autogkinternalprepare((double)(0), ae_pow(0.5*(b-a), (double)1+alpha, _state), eps, state->xwidth, &state->internalstate, _state); +lbl_9: + if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) + { + goto lbl_10; + } + + /* + * Fill State.X, State.XMinusA, State.BMinusX. + * Latter two are filled correctly even if Binternalstate.x; + t = ae_pow(x, (double)1/((double)1+alpha), _state); + state->x = a+t; + if( ae_fp_greater(s,(double)(0)) ) + { + state->xminusa = t; + state->bminusx = b-(a+t); + } + else + { + state->xminusa = a+t-b; + state->bminusx = -t; + } + state->needf = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needf = ae_false; + if( ae_fp_neq(alpha,(double)(0)) ) + { + state->internalstate.f = state->f*ae_pow(x, -alpha/((double)1+alpha), _state)/((double)1+alpha); + } + else + { + state->internalstate.f = state->f; + } + state->nfev = state->nfev+1; + goto lbl_9; +lbl_10: + v1 = state->internalstate.r; + state->nintervals = state->nintervals+state->internalstate.heapused; + + /* + * then, integrate right half of [a,b]: + * integral(f(x)dx, (b+a)/2, b) = + * = 1/(1+beta) * integral(t^(-beta/(1+beta))*f(b-t^(1/(1+beta)))dt, 0, (0.5*(b-a))^(1+beta)) + */ + autogk_autogkinternalprepare((double)(0), ae_pow(0.5*(b-a), (double)1+beta, _state), eps, state->xwidth, &state->internalstate, _state); +lbl_11: + if( !autogk_autogkinternaliteration(&state->internalstate, _state) ) + { + goto lbl_12; + } + + /* + * Fill State.X, State.XMinusA, State.BMinusX. + * Latter two are filled correctly (X-A, B-X) even if Binternalstate.x; + t = ae_pow(x, (double)1/((double)1+beta), _state); + state->x = b-t; + if( ae_fp_greater(s,(double)(0)) ) + { + state->xminusa = b-t-a; + state->bminusx = t; + } + else + { + state->xminusa = -t; + state->bminusx = a-(b-t); + } + state->needf = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needf = ae_false; + if( ae_fp_neq(beta,(double)(0)) ) + { + state->internalstate.f = state->f*ae_pow(x, -beta/((double)1+beta), _state)/((double)1+beta); + } + else + { + state->internalstate.f = state->f; + } + state->nfev = state->nfev+1; + goto lbl_11; +lbl_12: + v2 = state->internalstate.r; + state->nintervals = state->nintervals+state->internalstate.heapused; + + /* + * final result + */ + state->v = s*(v1+v2); + state->terminationtype = 1; + result = ae_false; + return result; +lbl_7: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ra.ptr.p_double[0] = s; + state->rstate.ra.ptr.p_double[1] = tmp; + state->rstate.ra.ptr.p_double[2] = eps; + state->rstate.ra.ptr.p_double[3] = a; + state->rstate.ra.ptr.p_double[4] = b; + state->rstate.ra.ptr.p_double[5] = x; + state->rstate.ra.ptr.p_double[6] = t; + state->rstate.ra.ptr.p_double[7] = alpha; + state->rstate.ra.ptr.p_double[8] = beta; + state->rstate.ra.ptr.p_double[9] = v1; + state->rstate.ra.ptr.p_double[10] = v2; + return result; +} + + +/************************************************************************* +Adaptive integration results + +Called after AutoGKIteration returned False. + +Input parameters: + State - algorithm state (used by AutoGKIteration). + +Output parameters: + V - integral(f(x)dx,a,b) + Rep - optimization report (see AutoGKReport description) + + -- ALGLIB -- + Copyright 14.11.2007 by Bochkanov Sergey +*************************************************************************/ +void autogkresults(const autogkstate* state, + double* v, + autogkreport* rep, + ae_state *_state) +{ + + *v = 0.0; + _autogkreport_clear(rep); + + *v = state->v; + rep->terminationtype = state->terminationtype; + rep->nfev = state->nfev; + rep->nintervals = state->nintervals; +} + + +/************************************************************************* +Internal AutoGK subroutine +eps<0 - error +eps=0 - automatic eps selection + +width<0 - error +width=0 - no width requirements +*************************************************************************/ +static void autogk_autogkinternalprepare(double a, + double b, + double eps, + double xwidth, + autogkinternalstate* state, + ae_state *_state) +{ + + + + /* + * Save settings + */ + state->a = a; + state->b = b; + state->eps = eps; + state->xwidth = xwidth; + + /* + * Prepare RComm structure + */ + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ra, 8+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Internal AutoGK subroutine +*************************************************************************/ +static ae_bool autogk_autogkinternaliteration(autogkinternalstate* state, + ae_state *_state) +{ + double c1; + double c2; + ae_int_t i; + ae_int_t j; + double intg; + double intk; + double inta; + double v; + double ta; + double tb; + ae_int_t ns; + double qeps; + ae_int_t info; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + j = state->rstate.ia.ptr.p_int[1]; + ns = state->rstate.ia.ptr.p_int[2]; + info = state->rstate.ia.ptr.p_int[3]; + c1 = state->rstate.ra.ptr.p_double[0]; + c2 = state->rstate.ra.ptr.p_double[1]; + intg = state->rstate.ra.ptr.p_double[2]; + intk = state->rstate.ra.ptr.p_double[3]; + inta = state->rstate.ra.ptr.p_double[4]; + v = state->rstate.ra.ptr.p_double[5]; + ta = state->rstate.ra.ptr.p_double[6]; + tb = state->rstate.ra.ptr.p_double[7]; + qeps = state->rstate.ra.ptr.p_double[8]; + } + else + { + i = 939; + j = -526; + ns = 763; + info = -541; + c1 = -698.0; + c2 = -900.0; + intg = -318.0; + intk = -940.0; + inta = 1016.0; + v = -229.0; + ta = -536.0; + tb = 487.0; + qeps = -115.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + + /* + * initialize quadratures. + * use 15-point Gauss-Kronrod formula. + */ + state->n = 15; + gkqgenerategausslegendre(state->n, &info, &state->qn, &state->wk, &state->wg, _state); + if( info<0 ) + { + state->info = -5; + state->r = (double)(0); + result = ae_false; + return result; + } + ae_vector_set_length(&state->wr, state->n, _state); + for(i=0; i<=state->n-1; i++) + { + if( i==0 ) + { + state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[1]-state->qn.ptr.p_double[0], _state); + continue; + } + if( i==state->n-1 ) + { + state->wr.ptr.p_double[state->n-1] = 0.5*ae_fabs(state->qn.ptr.p_double[state->n-1]-state->qn.ptr.p_double[state->n-2], _state); + continue; + } + state->wr.ptr.p_double[i] = 0.5*ae_fabs(state->qn.ptr.p_double[i-1]-state->qn.ptr.p_double[i+1], _state); + } + + /* + * special case + */ + if( ae_fp_eq(state->a,state->b) ) + { + state->info = 1; + state->r = (double)(0); + result = ae_false; + return result; + } + + /* + * test parameters + */ + if( ae_fp_less(state->eps,(double)(0))||ae_fp_less(state->xwidth,(double)(0)) ) + { + state->info = -1; + state->r = (double)(0); + result = ae_false; + return result; + } + state->info = 1; + if( ae_fp_eq(state->eps,(double)(0)) ) + { + state->eps = (double)100000*ae_machineepsilon; + } + + /* + * First, prepare heap + * * column 0 - absolute error + * * column 1 - integral of a F(x) (calculated using Kronrod extension nodes) + * * column 2 - integral of a |F(x)| (calculated using modified rect. method) + * * column 3 - left boundary of a subinterval + * * column 4 - right boundary of a subinterval + */ + if( ae_fp_neq(state->xwidth,(double)(0)) ) + { + goto lbl_3; + } + + /* + * no maximum width requirements + * start from one big subinterval + */ + state->heapwidth = 5; + state->heapsize = 1; + state->heapused = 1; + ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); + c1 = 0.5*(state->b-state->a); + c2 = 0.5*(state->b+state->a); + intg = (double)(0); + intk = (double)(0); + inta = (double)(0); + i = 0; +lbl_5: + if( i>state->n-1 ) + { + goto lbl_7; + } + + /* + * obtain F + */ + state->x = c1*state->qn.ptr.p_double[i]+c2; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + v = state->f; + + /* + * Gauss-Kronrod formula + */ + intk = intk+v*state->wk.ptr.p_double[i]; + if( i%2==1 ) + { + intg = intg+v*state->wg.ptr.p_double[i]; + } + + /* + * Integral |F(x)| + * Use rectangles method + */ + inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; + i = i+1; + goto lbl_5; +lbl_7: + intk = intk*(state->b-state->a)*0.5; + intg = intg*(state->b-state->a)*0.5; + inta = inta*(state->b-state->a)*0.5; + state->heap.ptr.pp_double[0][0] = ae_fabs(intg-intk, _state); + state->heap.ptr.pp_double[0][1] = intk; + state->heap.ptr.pp_double[0][2] = inta; + state->heap.ptr.pp_double[0][3] = state->a; + state->heap.ptr.pp_double[0][4] = state->b; + state->sumerr = state->heap.ptr.pp_double[0][0]; + state->sumabs = ae_fabs(inta, _state); + goto lbl_4; +lbl_3: + + /* + * maximum subinterval should be no more than XWidth. + * so we create Ceil((B-A)/XWidth)+1 small subintervals + */ + ns = ae_iceil(ae_fabs(state->b-state->a, _state)/state->xwidth, _state)+1; + state->heapsize = ns; + state->heapused = ns; + state->heapwidth = 5; + ae_matrix_set_length(&state->heap, state->heapsize, state->heapwidth, _state); + state->sumerr = (double)(0); + state->sumabs = (double)(0); + j = 0; +lbl_8: + if( j>ns-1 ) + { + goto lbl_10; + } + ta = state->a+(double)j*(state->b-state->a)/(double)ns; + tb = state->a+(double)(j+1)*(state->b-state->a)/(double)ns; + c1 = 0.5*(tb-ta); + c2 = 0.5*(tb+ta); + intg = (double)(0); + intk = (double)(0); + inta = (double)(0); + i = 0; +lbl_11: + if( i>state->n-1 ) + { + goto lbl_13; + } + + /* + * obtain F + */ + state->x = c1*state->qn.ptr.p_double[i]+c2; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + v = state->f; + + /* + * Gauss-Kronrod formula + */ + intk = intk+v*state->wk.ptr.p_double[i]; + if( i%2==1 ) + { + intg = intg+v*state->wg.ptr.p_double[i]; + } + + /* + * Integral |F(x)| + * Use rectangles method + */ + inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; + i = i+1; + goto lbl_11; +lbl_13: + intk = intk*(tb-ta)*0.5; + intg = intg*(tb-ta)*0.5; + inta = inta*(tb-ta)*0.5; + state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); + state->heap.ptr.pp_double[j][1] = intk; + state->heap.ptr.pp_double[j][2] = inta; + state->heap.ptr.pp_double[j][3] = ta; + state->heap.ptr.pp_double[j][4] = tb; + state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; + state->sumabs = state->sumabs+ae_fabs(inta, _state); + j = j+1; + goto lbl_8; +lbl_10: +lbl_4: + + /* + * method iterations + */ +lbl_14: + if( ae_false ) + { + goto lbl_15; + } + + /* + * additional memory if needed + */ + if( state->heapused==state->heapsize ) + { + autogk_mheapresize(&state->heap, &state->heapsize, 4*state->heapsize, state->heapwidth, _state); + } + + /* + * TODO: every 20 iterations recalculate errors/sums + */ + if( ae_fp_less_eq(state->sumerr,state->eps*state->sumabs)||state->heapused>=autogk_maxsubintervals ) + { + state->r = (double)(0); + for(j=0; j<=state->heapused-1; j++) + { + state->r = state->r+state->heap.ptr.pp_double[j][1]; + } + result = ae_false; + return result; + } + + /* + * Exclude interval with maximum absolute error + */ + autogk_mheappop(&state->heap, state->heapused, state->heapwidth, _state); + state->sumerr = state->sumerr-state->heap.ptr.pp_double[state->heapused-1][0]; + state->sumabs = state->sumabs-state->heap.ptr.pp_double[state->heapused-1][2]; + + /* + * Divide interval, create subintervals + */ + ta = state->heap.ptr.pp_double[state->heapused-1][3]; + tb = state->heap.ptr.pp_double[state->heapused-1][4]; + state->heap.ptr.pp_double[state->heapused-1][3] = ta; + state->heap.ptr.pp_double[state->heapused-1][4] = 0.5*(ta+tb); + state->heap.ptr.pp_double[state->heapused][3] = 0.5*(ta+tb); + state->heap.ptr.pp_double[state->heapused][4] = tb; + j = state->heapused-1; +lbl_16: + if( j>state->heapused ) + { + goto lbl_18; + } + c1 = 0.5*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3]); + c2 = 0.5*(state->heap.ptr.pp_double[j][4]+state->heap.ptr.pp_double[j][3]); + intg = (double)(0); + intk = (double)(0); + inta = (double)(0); + i = 0; +lbl_19: + if( i>state->n-1 ) + { + goto lbl_21; + } + + /* + * F(x) + */ + state->x = c1*state->qn.ptr.p_double[i]+c2; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + v = state->f; + + /* + * Gauss-Kronrod formula + */ + intk = intk+v*state->wk.ptr.p_double[i]; + if( i%2==1 ) + { + intg = intg+v*state->wg.ptr.p_double[i]; + } + + /* + * Integral |F(x)| + * Use rectangles method + */ + inta = inta+ae_fabs(v, _state)*state->wr.ptr.p_double[i]; + i = i+1; + goto lbl_19; +lbl_21: + intk = intk*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; + intg = intg*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; + inta = inta*(state->heap.ptr.pp_double[j][4]-state->heap.ptr.pp_double[j][3])*0.5; + state->heap.ptr.pp_double[j][0] = ae_fabs(intg-intk, _state); + state->heap.ptr.pp_double[j][1] = intk; + state->heap.ptr.pp_double[j][2] = inta; + state->sumerr = state->sumerr+state->heap.ptr.pp_double[j][0]; + state->sumabs = state->sumabs+state->heap.ptr.pp_double[j][2]; + j = j+1; + goto lbl_16; +lbl_18: + autogk_mheappush(&state->heap, state->heapused-1, state->heapwidth, _state); + autogk_mheappush(&state->heap, state->heapused, state->heapwidth, _state); + state->heapused = state->heapused+1; + goto lbl_14; +lbl_15: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = j; + state->rstate.ia.ptr.p_int[2] = ns; + state->rstate.ia.ptr.p_int[3] = info; + state->rstate.ra.ptr.p_double[0] = c1; + state->rstate.ra.ptr.p_double[1] = c2; + state->rstate.ra.ptr.p_double[2] = intg; + state->rstate.ra.ptr.p_double[3] = intk; + state->rstate.ra.ptr.p_double[4] = inta; + state->rstate.ra.ptr.p_double[5] = v; + state->rstate.ra.ptr.p_double[6] = ta; + state->rstate.ra.ptr.p_double[7] = tb; + state->rstate.ra.ptr.p_double[8] = qeps; + return result; +} + + +static void autogk_mheappop(/* Real */ ae_matrix* heap, + ae_int_t heapsize, + ae_int_t heapwidth, + ae_state *_state) +{ + ae_int_t i; + ae_int_t p; + double t; + ae_int_t maxcp; + + + if( heapsize==1 ) + { + return; + } + for(i=0; i<=heapwidth-1; i++) + { + t = heap->ptr.pp_double[heapsize-1][i]; + heap->ptr.pp_double[heapsize-1][i] = heap->ptr.pp_double[0][i]; + heap->ptr.pp_double[0][i] = t; + } + p = 0; + while(2*p+1ptr.pp_double[2*p+2][0],heap->ptr.pp_double[2*p+1][0]) ) + { + maxcp = 2*p+2; + } + } + if( ae_fp_less(heap->ptr.pp_double[p][0],heap->ptr.pp_double[maxcp][0]) ) + { + for(i=0; i<=heapwidth-1; i++) + { + t = heap->ptr.pp_double[p][i]; + heap->ptr.pp_double[p][i] = heap->ptr.pp_double[maxcp][i]; + heap->ptr.pp_double[maxcp][i] = t; + } + p = maxcp; + } + else + { + break; + } + } +} + + +static void autogk_mheappush(/* Real */ ae_matrix* heap, + ae_int_t heapsize, + ae_int_t heapwidth, + ae_state *_state) +{ + ae_int_t i; + ae_int_t p; + double t; + ae_int_t parent; + + + if( heapsize==0 ) + { + return; + } + p = heapsize; + while(p!=0) + { + parent = (p-1)/2; + if( ae_fp_greater(heap->ptr.pp_double[p][0],heap->ptr.pp_double[parent][0]) ) + { + for(i=0; i<=heapwidth-1; i++) + { + t = heap->ptr.pp_double[p][i]; + heap->ptr.pp_double[p][i] = heap->ptr.pp_double[parent][i]; + heap->ptr.pp_double[parent][i] = t; + } + p = parent; + } + else + { + break; + } + } +} + + +static void autogk_mheapresize(/* Real */ ae_matrix* heap, + ae_int_t* heapsize, + ae_int_t newheapsize, + ae_int_t heapwidth, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix tmp; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_matrix_init(&tmp, 0, 0, DT_REAL, _state, ae_true); + + ae_matrix_set_length(&tmp, *heapsize, heapwidth, _state); + for(i=0; i<=*heapsize-1; i++) + { + ae_v_move(&tmp.ptr.pp_double[i][0], 1, &heap->ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); + } + ae_matrix_set_length(heap, newheapsize, heapwidth, _state); + for(i=0; i<=*heapsize-1; i++) + { + ae_v_move(&heap->ptr.pp_double[i][0], 1, &tmp.ptr.pp_double[i][0], 1, ae_v_len(0,heapwidth-1)); + } + *heapsize = newheapsize; + ae_frame_leave(_state); +} + + +void _autogkreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + autogkreport *p = (autogkreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _autogkreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + autogkreport *dst = (autogkreport*)_dst; + const autogkreport *src = (const autogkreport*)_src; + dst->terminationtype = src->terminationtype; + dst->nfev = src->nfev; + dst->nintervals = src->nintervals; +} + + +void _autogkreport_clear(void* _p) +{ + autogkreport *p = (autogkreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _autogkreport_destroy(void* _p) +{ + autogkreport *p = (autogkreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _autogkinternalstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + autogkinternalstate *p = (autogkinternalstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->heap, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wr, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _autogkinternalstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + autogkinternalstate *dst = (autogkinternalstate*)_dst; + const autogkinternalstate *src = (const autogkinternalstate*)_src; + dst->a = src->a; + dst->b = src->b; + dst->eps = src->eps; + dst->xwidth = src->xwidth; + dst->x = src->x; + dst->f = src->f; + dst->info = src->info; + dst->r = src->r; + ae_matrix_init_copy(&dst->heap, &src->heap, _state, make_automatic); + dst->heapsize = src->heapsize; + dst->heapwidth = src->heapwidth; + dst->heapused = src->heapused; + dst->sumerr = src->sumerr; + dst->sumabs = src->sumabs; + ae_vector_init_copy(&dst->qn, &src->qn, _state, make_automatic); + ae_vector_init_copy(&dst->wg, &src->wg, _state, make_automatic); + ae_vector_init_copy(&dst->wk, &src->wk, _state, make_automatic); + ae_vector_init_copy(&dst->wr, &src->wr, _state, make_automatic); + dst->n = src->n; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _autogkinternalstate_clear(void* _p) +{ + autogkinternalstate *p = (autogkinternalstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->heap); + ae_vector_clear(&p->qn); + ae_vector_clear(&p->wg); + ae_vector_clear(&p->wk); + ae_vector_clear(&p->wr); + _rcommstate_clear(&p->rstate); +} + + +void _autogkinternalstate_destroy(void* _p) +{ + autogkinternalstate *p = (autogkinternalstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->heap); + ae_vector_destroy(&p->qn); + ae_vector_destroy(&p->wg); + ae_vector_destroy(&p->wk); + ae_vector_destroy(&p->wr); + _rcommstate_destroy(&p->rstate); +} + + +void _autogkstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + autogkstate *p = (autogkstate*)_p; + ae_touch_ptr((void*)p); + _autogkinternalstate_init(&p->internalstate, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _autogkstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + autogkstate *dst = (autogkstate*)_dst; + const autogkstate *src = (const autogkstate*)_src; + dst->a = src->a; + dst->b = src->b; + dst->alpha = src->alpha; + dst->beta = src->beta; + dst->xwidth = src->xwidth; + dst->x = src->x; + dst->xminusa = src->xminusa; + dst->bminusx = src->bminusx; + dst->needf = src->needf; + dst->f = src->f; + dst->wrappermode = src->wrappermode; + _autogkinternalstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->v = src->v; + dst->terminationtype = src->terminationtype; + dst->nfev = src->nfev; + dst->nintervals = src->nintervals; +} + + +void _autogkstate_clear(void* _p) +{ + autogkstate *p = (autogkstate*)_p; + ae_touch_ptr((void*)p); + _autogkinternalstate_clear(&p->internalstate); + _rcommstate_clear(&p->rstate); +} + + +void _autogkstate_destroy(void* _p) +{ + autogkstate *p = (autogkstate*)_p; + ae_touch_ptr((void*)p); + _autogkinternalstate_destroy(&p->internalstate); + _rcommstate_destroy(&p->rstate); +} + + +#endif + +} + diff --git a/core/alglib/integration.h b/core/alglib/integration.h index 62ad78b0..af8a7877 100644 --- a/core/alglib/integration.h +++ b/core/alglib/integration.h @@ -1,837 +1,877 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _integration_pkg_h -#define _integration_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "linalg.h" -#include "specialfunctions.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_int_t terminationtype; - ae_int_t nfev; - ae_int_t nintervals; -} autogkreport; -typedef struct -{ - double a; - double b; - double eps; - double xwidth; - double x; - double f; - ae_int_t info; - double r; - ae_matrix heap; - ae_int_t heapsize; - ae_int_t heapwidth; - ae_int_t heapused; - double sumerr; - double sumabs; - ae_vector qn; - ae_vector wg; - ae_vector wk; - ae_vector wr; - ae_int_t n; - rcommstate rstate; -} autogkinternalstate; -typedef struct -{ - double a; - double b; - double alpha; - double beta; - double xwidth; - double x; - double xminusa; - double bminusx; - ae_bool needf; - double f; - ae_int_t wrappermode; - autogkinternalstate internalstate; - rcommstate rstate; - double v; - ae_int_t terminationtype; - ae_int_t nfev; - ae_int_t nintervals; -} autogkstate; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - - - - -/************************************************************************* -Integration report: -* TerminationType = completion code: - * -5 non-convergence of Gauss-Kronrod nodes - calculation subroutine. - * -1 incorrect parameters were specified - * 1 OK -* Rep.NFEV contains number of function calculations -* Rep.NIntervals contains number of intervals [a,b] - was partitioned into. -*************************************************************************/ -class _autogkreport_owner -{ -public: - _autogkreport_owner(); - _autogkreport_owner(const _autogkreport_owner &rhs); - _autogkreport_owner& operator=(const _autogkreport_owner &rhs); - virtual ~_autogkreport_owner(); - alglib_impl::autogkreport* c_ptr(); - alglib_impl::autogkreport* c_ptr() const; -protected: - alglib_impl::autogkreport *p_struct; -}; -class autogkreport : public _autogkreport_owner -{ -public: - autogkreport(); - autogkreport(const autogkreport &rhs); - autogkreport& operator=(const autogkreport &rhs); - virtual ~autogkreport(); - ae_int_t &terminationtype; - ae_int_t &nfev; - ae_int_t &nintervals; - -}; - - -/************************************************************************* -This structure stores state of the integration algorithm. - -Although this class has public fields, they are not intended for external -use. You should use ALGLIB functions to work with this class: -* autogksmooth()/AutoGKSmoothW()/... to create objects -* autogkintegrate() to begin integration -* autogkresults() to get results -*************************************************************************/ -class _autogkstate_owner -{ -public: - _autogkstate_owner(); - _autogkstate_owner(const _autogkstate_owner &rhs); - _autogkstate_owner& operator=(const _autogkstate_owner &rhs); - virtual ~_autogkstate_owner(); - alglib_impl::autogkstate* c_ptr(); - alglib_impl::autogkstate* c_ptr() const; -protected: - alglib_impl::autogkstate *p_struct; -}; -class autogkstate : public _autogkstate_owner -{ -public: - autogkstate(); - autogkstate(const autogkstate &rhs); - autogkstate& operator=(const autogkstate &rhs); - virtual ~autogkstate(); - ae_bool &needf; - double &x; - double &xminusa; - double &bminusx; - double &f; - -}; - -/************************************************************************* -Computation of nodes and weights for a Gauss quadrature formula - -The algorithm generates the N-point Gauss quadrature formula with weight -function given by coefficients alpha and beta of a recurrence relation -which generates a system of orthogonal polynomials: - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-1], alpha coefficients - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the quadrature formula, N>=1 - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Computation of nodes and weights for a Gauss-Lobatto quadrature formula - -The algorithm generates the N-point Gauss-Lobatto quadrature formula with -weight function given by coefficients alpha and beta of a recurrence which -generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients - Beta – array[0..N-2], beta coefficients. - Zero-indexed element is not used, may be arbitrary. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - B – right boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=3 - (including the left and right boundary nodes). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Computation of nodes and weights for a Gauss-Radau quadrature formula - -The algorithm generates the N-point Gauss-Radau quadrature formula with -weight function given by the coefficients alpha and beta of a recurrence -which generates a system of orthogonal polynomials. - -P-1(x) = 0 -P0(x) = 1 -Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zeroth moment Mu0 - -Mu0 = integral(W(x)dx,a,b) - -INPUT PARAMETERS: - Alpha – array[0..N-2], alpha coefficients. - Beta – array[0..N-1], beta coefficients - Zero-indexed element is not used. - Beta[I]>0 - Mu0 – zeroth moment of the weighting function. - A – left boundary of the integration interval. - N – number of nodes of the quadrature formula, N>=2 - (including the left boundary node). - -OUTPUT PARAMETERS: - Info - error code: - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * 1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 2005-2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N -nodes. - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight -function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha/Beta was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with -weight function W(x)=Power(x,Alpha)*Exp(-x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - Alpha - power-law coefficient, Alpha>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. Alpha is too close to -1 to - obtain weights/nodes with high enough accuracy - or, may be, N is too large. Try to use - multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w); - - -/************************************************************************* -Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with -weight function W(x)=Exp(-x*x) - -INPUT PARAMETERS: - N - number of nodes, >=1 - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. May be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N/Alpha was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - W - array[0..N-1] - array of quadrature weights. - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w); - -/************************************************************************* -Computation of nodes and weights of a Gauss-Kronrod quadrature formula - -The algorithm generates the N-point Gauss-Kronrod quadrature formula with -weight function given by coefficients alpha and beta of a recurrence -relation which generates a system of orthogonal polynomials: - - P-1(x) = 0 - P0(x) = 1 - Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) - -and zero moment Mu0 - - Mu0 = integral(W(x)dx,a,b) - - -INPUT PARAMETERS: - Alpha – alpha coefficients, array[0..floor(3*K/2)]. - Beta – beta coefficients, array[0..ceil(3*K/2)]. - Beta[0] is not used and may be arbitrary. - Beta[I]>0. - Mu0 – zeroth moment of the weight function. - N – number of nodes of the Gauss-Kronrod quadrature formula, - N >= 3, - N = 2*K+1. - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 N is too large, task may be ill conditioned - - x[i]=x[i+1] found. - * -3 internal eigenproblem solver hasn't converged - * -2 Beta[i]<=0 - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, - in ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 08.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre -quadrature with N points. - -GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is -used depending on machine precision and number of nodes. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi -quadrature on [-1,1] with weight function - - W(x)=Power(1-x,Alpha)*Power(1+x,Beta). - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - Alpha - power-law coefficient, Alpha>-1 - Beta - power-law coefficient, Beta>-1 - -OUTPUT PARAMETERS: - Info - error code: - * -5 no real and positive Gauss-Kronrod formula can - be created for such a weight function with a - given number of nodes. - * -4 an error was detected when calculating - weights/nodes. Alpha or Beta are too close - to -1 to obtain weights/nodes with high enough - accuracy, or, may be, N is too large. Try to - use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - * +2 OK, but quadrature rule have exterior nodes, - x[0]<-1 or x[n-1]>+1 - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. - -Reduction to tridiagonal eigenproblem is used. - -INPUT PARAMETERS: - N - number of Kronrod nodes, must be odd number, >=3. - -OUTPUT PARAMETERS: - Info - error code: - * -4 an error was detected when calculating - weights/nodes. N is too large to obtain - weights/nodes with high enough accuracy. - Try to use multiple precision version. - * -3 internal eigenproblem solver hasn't converged - * -1 incorrect N was passed - * +1 OK - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss); - - -/************************************************************************* -Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using -pre-calculated table. Nodes/weights were computed with accuracy up to -1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision -accuracy reduces to something about 2.0E-16 (depending on your compiler's -handling of long floating point constants). - -INPUT PARAMETERS: - N - number of Kronrod nodes. - N can be 15, 21, 31, 41, 51, 61. - -OUTPUT PARAMETERS: - X - array[0..N-1] - array of quadrature nodes, ordered in - ascending order. - WKronrod - array[0..N-1] - Kronrod weights - WGauss - array[0..N-1] - Gauss weights (interleaved with zeros - corresponding to extended Kronrod nodes). - - - -- ALGLIB -- - Copyright 12.05.2009 by Bochkanov Sergey -*************************************************************************/ -void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps); - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -Algorithm works well only with smooth integrands. It may be used with -continuous non-smooth integrands, but with less performance. - -It should never be used with integrands which have integrable singularities -at lower or upper limits - algorithm may crash. Use AutoGKSingular in such -cases. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmoothW, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmooth(const double a, const double b, autogkstate &state); - - -/************************************************************************* -Integration of a smooth function F(x) on a finite interval [a,b]. - -This subroutine is same as AutoGKSmooth(), but it guarantees that interval -[a,b] is partitioned into subintervals which have width at most XWidth. - -Subroutine can be used when integrating nearly-constant function with -narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth -subroutine can overlook them. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSingular, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state); - - -/************************************************************************* -Integration on a finite interval [A,B]. -Integrand have integrable singularities at A/B. - -F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known -alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates -from below can be used (but these estimates should be greater than -1 too). - -One of alpha/beta variables (or even both alpha/beta) may be equal to 0, -which means than function F(x) is non-singular at A/B. Anyway (singular at -bounds or not), function F(x) is supposed to be continuous on (A,B). - -Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result -is calculated with accuracy close to the machine precision. - -INPUT PARAMETERS: - A, B - interval boundaries (AB) - Alpha - power-law coefficient of the F(x) at A, - Alpha>-1 - Beta - power-law coefficient of the F(x) at B, - Beta>-1 - -OUTPUT PARAMETERS - State - structure which stores algorithm state - -SEE ALSO - AutoGKSmooth, AutoGKSmoothW, AutoGKResults. - - - -- ALGLIB -- - Copyright 06.05.2009 by Bochkanov Sergey -*************************************************************************/ -void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool autogkiteration(const autogkstate &state); - - -/************************************************************************* -This function is used to launcn iterations of the 1-dimensional integrator - -It accepts following parameters: - func - callback which calculates f(x) for given x - ptr - optional pointer which is passed to func; can be NULL - - - -- ALGLIB -- - Copyright 07.05.2009 by Bochkanov Sergey - -*************************************************************************/ -void autogkintegrate(autogkstate &state, - void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), - void *ptr = NULL); - - -/************************************************************************* -Adaptive integration results - -Called after AutoGKIteration returned False. - -Input parameters: - State - algorithm state (used by AutoGKIteration). - -Output parameters: - V - integral(f(x)dx,a,b) - Rep - optimization report (see AutoGKReport description) - - -- ALGLIB -- - Copyright 14.11.2007 by Bochkanov Sergey -*************************************************************************/ -void autogkresults(const autogkstate &state, double &v, autogkreport &rep); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void gqgeneraterec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategausslobattorec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - double a, - double b, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategaussradaurec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - double a, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategausslegendre(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategaussjacobi(ae_int_t n, - double alpha, - double beta, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategausslaguerre(ae_int_t n, - double alpha, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gqgenerategausshermite(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* w, - ae_state *_state); -void gkqgeneraterec(/* Real */ ae_vector* alpha, - /* Real */ ae_vector* beta, - double mu0, - ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state); -void gkqgenerategausslegendre(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state); -void gkqgenerategaussjacobi(ae_int_t n, - double alpha, - double beta, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state); -void gkqlegendrecalc(ae_int_t n, - ae_int_t* info, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - ae_state *_state); -void gkqlegendretbl(ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* wkronrod, - /* Real */ ae_vector* wgauss, - double* eps, - ae_state *_state); -void autogksmooth(double a, - double b, - autogkstate* state, - ae_state *_state); -void autogksmoothw(double a, - double b, - double xwidth, - autogkstate* state, - ae_state *_state); -void autogksingular(double a, - double b, - double alpha, - double beta, - autogkstate* state, - ae_state *_state); -ae_bool autogkiteration(autogkstate* state, ae_state *_state); -void autogkresults(autogkstate* state, - double* v, - autogkreport* rep, - ae_state *_state); -ae_bool _autogkreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _autogkreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _autogkreport_clear(void* _p); -void _autogkreport_destroy(void* _p); -ae_bool _autogkinternalstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _autogkinternalstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _autogkinternalstate_clear(void* _p); -void _autogkinternalstate_destroy(void* _p); -ae_bool _autogkstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _autogkstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _autogkstate_clear(void* _p); -void _autogkstate_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _integration_pkg_h +#define _integration_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "specialfunctions.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t terminationtype; + ae_int_t nfev; + ae_int_t nintervals; +} autogkreport; +typedef struct +{ + double a; + double b; + double eps; + double xwidth; + double x; + double f; + ae_int_t info; + double r; + ae_matrix heap; + ae_int_t heapsize; + ae_int_t heapwidth; + ae_int_t heapused; + double sumerr; + double sumabs; + ae_vector qn; + ae_vector wg; + ae_vector wk; + ae_vector wr; + ae_int_t n; + rcommstate rstate; +} autogkinternalstate; +typedef struct +{ + double a; + double b; + double alpha; + double beta; + double xwidth; + double x; + double xminusa; + double bminusx; + ae_bool needf; + double f; + ae_int_t wrappermode; + autogkinternalstate internalstate; + rcommstate rstate; + double v; + ae_int_t terminationtype; + ae_int_t nfev; + ae_int_t nintervals; +} autogkstate; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +class _autogkreport_owner; +class autogkreport; +class _autogkstate_owner; +class autogkstate; + + +/************************************************************************* +Integration report: +* TerminationType = completetion code: + * -5 non-convergence of Gauss-Kronrod nodes + calculation subroutine. + * -1 incorrect parameters were specified + * 1 OK +* Rep.NFEV countains number of function calculations +* Rep.NIntervals contains number of intervals [a,b] + was partitioned into. +*************************************************************************/ +class _autogkreport_owner +{ +public: + _autogkreport_owner(); + _autogkreport_owner(alglib_impl::autogkreport *attach_to); + _autogkreport_owner(const _autogkreport_owner &rhs); + _autogkreport_owner& operator=(const _autogkreport_owner &rhs); + virtual ~_autogkreport_owner(); + alglib_impl::autogkreport* c_ptr(); + const alglib_impl::autogkreport* c_ptr() const; +protected: + alglib_impl::autogkreport *p_struct; + bool is_attached; +}; +class autogkreport : public _autogkreport_owner +{ +public: + autogkreport(); + autogkreport(alglib_impl::autogkreport *attach_to); + autogkreport(const autogkreport &rhs); + autogkreport& operator=(const autogkreport &rhs); + virtual ~autogkreport(); + ae_int_t &terminationtype; + ae_int_t &nfev; + ae_int_t &nintervals; + + +}; + + +/************************************************************************* +This structure stores state of the integration algorithm. + +Although this class has public fields, they are not intended for external +use. You should use ALGLIB functions to work with this class: +* autogksmooth()/AutoGKSmoothW()/... to create objects +* autogkintegrate() to begin integration +* autogkresults() to get results +*************************************************************************/ +class _autogkstate_owner +{ +public: + _autogkstate_owner(); + _autogkstate_owner(alglib_impl::autogkstate *attach_to); + _autogkstate_owner(const _autogkstate_owner &rhs); + _autogkstate_owner& operator=(const _autogkstate_owner &rhs); + virtual ~_autogkstate_owner(); + alglib_impl::autogkstate* c_ptr(); + const alglib_impl::autogkstate* c_ptr() const; +protected: + alglib_impl::autogkstate *p_struct; + bool is_attached; +}; +class autogkstate : public _autogkstate_owner +{ +public: + autogkstate(); + autogkstate(alglib_impl::autogkstate *attach_to); + autogkstate(const autogkstate &rhs); + autogkstate& operator=(const autogkstate &rhs); + virtual ~autogkstate(); + ae_bool &needf; + double &x; + double &xminusa; + double &bminusx; + double &f; + + +}; +#endif + +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Computation of nodes and weights for a Gauss quadrature formula + +The algorithm generates the N-point Gauss quadrature formula with weight +function given by coefficients alpha and beta of a recurrence relation +which generates a system of orthogonal polynomials: + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-1], alpha coefficients + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the quadrature formula, N>=1 + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Computation of nodes and weights for a Gauss-Lobatto quadrature formula + +The algorithm generates the N-point Gauss-Lobatto quadrature formula with +weight function given by coefficients alpha and beta of a recurrence which +generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients + Beta - array[0..N-2], beta coefficients. + Zero-indexed element is not used, may be arbitrary. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + B - right boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=3 + (including the left and right boundary nodes). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslobattorec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const double b, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Computation of nodes and weights for a Gauss-Radau quadrature formula + +The algorithm generates the N-point Gauss-Radau quadrature formula with +weight function given by the coefficients alpha and beta of a recurrence +which generates a system of orthogonal polynomials. + +P-1(x) = 0 +P0(x) = 1 +Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zeroth moment Mu0 + +Mu0 = integral(W(x)dx,a,b) + +INPUT PARAMETERS: + Alpha - array[0..N-2], alpha coefficients. + Beta - array[0..N-1], beta coefficients + Zero-indexed element is not used. + Beta[I]>0 + Mu0 - zeroth moment of the weighting function. + A - left boundary of the integration interval. + N - number of nodes of the quadrature formula, N>=2 + (including the left boundary node). + +OUTPUT PARAMETERS: + Info - error code: + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * 1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 2005-2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussradaurec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const double a, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns nodes/weights for Gauss-Legendre quadrature on [-1,1] with N +nodes. + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns nodes/weights for Gauss-Jacobi quadrature on [-1,1] with weight +function W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha/Beta was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns nodes/weights for Gauss-Laguerre quadrature on [0,+inf) with +weight function W(x)=Power(x,Alpha)*Exp(-x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + Alpha - power-law coefficient, Alpha>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. Alpha is too close to -1 to + obtain weights/nodes with high enough accuracy + or, may be, N is too large. Try to use + multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausslaguerre(const ae_int_t n, const double alpha, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns nodes/weights for Gauss-Hermite quadrature on (-inf,+inf) with +weight function W(x)=Exp(-x*x) + +INPUT PARAMETERS: + N - number of nodes, >=1 + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. May be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N/Alpha was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + W - array[0..N-1] - array of quadrature weights. + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gqgenerategausshermite(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &w, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Computation of nodes and weights of a Gauss-Kronrod quadrature formula + +The algorithm generates the N-point Gauss-Kronrod quadrature formula with +weight function given by coefficients alpha and beta of a recurrence +relation which generates a system of orthogonal polynomials: + + P-1(x) = 0 + P0(x) = 1 + Pn+1(x) = (x-alpha(n))*Pn(x) - beta(n)*Pn-1(x) + +and zero moment Mu0 + + Mu0 = integral(W(x)dx,a,b) + + +INPUT PARAMETERS: + Alpha - alpha coefficients, array[0..floor(3*K/2)]. + Beta - beta coefficients, array[0..ceil(3*K/2)]. + Beta[0] is not used and may be arbitrary. + Beta[I]>0. + Mu0 - zeroth moment of the weight function. + N - number of nodes of the Gauss-Kronrod quadrature formula, + N >= 3, + N = 2*K+1. + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 N is too large, task may be ill conditioned - + x[i]=x[i+1] found. + * -3 internal eigenproblem solver hasn't converged + * -2 Beta[i]<=0 + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, + in ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 08.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgeneraterec(const real_1d_array &alpha, const real_1d_array &beta, const double mu0, const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Legendre +quadrature with N points. + +GKQLegendreCalc (calculation) or GKQLegendreTbl (precomputed table) is +used depending on machine precision and number of nodes. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategausslegendre(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes/weights for Gauss-Jacobi +quadrature on [-1,1] with weight function + + W(x)=Power(1-x,Alpha)*Power(1+x,Beta). + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + Alpha - power-law coefficient, Alpha>-1 + Beta - power-law coefficient, Beta>-1 + +OUTPUT PARAMETERS: + Info - error code: + * -5 no real and positive Gauss-Kronrod formula can + be created for such a weight function with a + given number of nodes. + * -4 an error was detected when calculating + weights/nodes. Alpha or Beta are too close + to -1 to obtain weights/nodes with high enough + accuracy, or, may be, N is too large. Try to + use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + * +2 OK, but quadrature rule have exterior nodes, + x[0]<-1 or x[n-1]>+1 + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqgenerategaussjacobi(const ae_int_t n, const double alpha, const double beta, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points. + +Reduction to tridiagonal eigenproblem is used. + +INPUT PARAMETERS: + N - number of Kronrod nodes, must be odd number, >=3. + +OUTPUT PARAMETERS: + Info - error code: + * -4 an error was detected when calculating + weights/nodes. N is too large to obtain + weights/nodes with high enough accuracy. + Try to use multiple precision version. + * -3 internal eigenproblem solver hasn't converged + * -1 incorrect N was passed + * +1 OK + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendrecalc(const ae_int_t n, ae_int_t &info, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns Gauss and Gauss-Kronrod nodes for quadrature with N points using +pre-calculated table. Nodes/weights were computed with accuracy up to +1.0E-32 (if MPFR version of ALGLIB is used). In standard double precision +accuracy reduces to something about 2.0E-16 (depending on your compiler's +handling of long floating point constants). + +INPUT PARAMETERS: + N - number of Kronrod nodes. + N can be 15, 21, 31, 41, 51, 61. + +OUTPUT PARAMETERS: + X - array[0..N-1] - array of quadrature nodes, ordered in + ascending order. + WKronrod - array[0..N-1] - Kronrod weights + WGauss - array[0..N-1] - Gauss weights (interleaved with zeros + corresponding to extended Kronrod nodes). + + + -- ALGLIB -- + Copyright 12.05.2009 by Bochkanov Sergey +*************************************************************************/ +void gkqlegendretbl(const ae_int_t n, real_1d_array &x, real_1d_array &wkronrod, real_1d_array &wgauss, double &eps, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +Algorithm works well only with smooth integrands. It may be used with +continuous non-smooth integrands, but with less performance. + +It should never be used with integrands which have integrable singularities +at lower or upper limits - algorithm may crash. Use AutoGKSingular in such +cases. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmoothW, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmooth(const double a, const double b, autogkstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Integration of a smooth function F(x) on a finite interval [a,b]. + +This subroutine is same as AutoGKSmooth(), but it guarantees that interval +[a,b] is partitioned into subintervals which have width at most XWidth. + +Subroutine can be used when integrating nearly-constant function with +narrow "bumps" (about XWidth wide). If "bumps" are too narrow, AutoGKSmooth +subroutine can overlook them. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSingular, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksmoothw(const double a, const double b, const double xwidth, autogkstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Integration on a finite interval [A,B]. +Integrand have integrable singularities at A/B. + +F(X) must diverge as "(x-A)^alpha" at A, as "(B-x)^beta" at B, with known +alpha/beta (alpha>-1, beta>-1). If alpha/beta are not known, estimates +from below can be used (but these estimates should be greater than -1 too). + +One of alpha/beta variables (or even both alpha/beta) may be equal to 0, +which means than function F(x) is non-singular at A/B. Anyway (singular at +bounds or not), function F(x) is supposed to be continuous on (A,B). + +Fast-convergent algorithm based on a Gauss-Kronrod formula is used. Result +is calculated with accuracy close to the machine precision. + +INPUT PARAMETERS: + A, B - interval boundaries (AB) + Alpha - power-law coefficient of the F(x) at A, + Alpha>-1 + Beta - power-law coefficient of the F(x) at B, + Beta>-1 + +OUTPUT PARAMETERS + State - structure which stores algorithm state + +SEE ALSO + AutoGKSmooth, AutoGKSmoothW, AutoGKResults. + + + -- ALGLIB -- + Copyright 06.05.2009 by Bochkanov Sergey +*************************************************************************/ +void autogksingular(const double a, const double b, const double alpha, const double beta, autogkstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool autogkiteration(autogkstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to launcn iterations of the 1-dimensional integrator + +It accepts following parameters: + func - callback which calculates f(x) for given x + ptr - optional pointer which is passed to func; can be NULL + + + -- ALGLIB -- + Copyright 07.05.2009 by Bochkanov Sergey + +*************************************************************************/ +void autogkintegrate(autogkstate &state, + void (*func)(double x, double xminusa, double bminusx, double &y, void *ptr), + void *ptr = NULL, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Adaptive integration results + +Called after AutoGKIteration returned False. + +Input parameters: + State - algorithm state (used by AutoGKIteration). + +Output parameters: + V - integral(f(x)dx,a,b) + Rep - optimization report (see AutoGKReport description) + + -- ALGLIB -- + Copyright 14.11.2007 by Bochkanov Sergey +*************************************************************************/ +void autogkresults(const autogkstate &state, double &v, autogkreport &rep, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GQ) || !defined(AE_PARTIAL_BUILD) +void gqgeneraterec(/* Real */ const ae_vector* alpha, + /* Real */ const ae_vector* beta, + double mu0, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategausslobattorec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + double a, + double b, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategaussradaurec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + double a, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategausslegendre(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategaussjacobi(ae_int_t n, + double alpha, + double beta, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategausslaguerre(ae_int_t n, + double alpha, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +void gqgenerategausshermite(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* w, + ae_state *_state); +#endif +#if defined(AE_COMPILE_GKQ) || !defined(AE_PARTIAL_BUILD) +void gkqgeneraterec(/* Real */ const ae_vector* _alpha, + /* Real */ const ae_vector* _beta, + double mu0, + ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state); +void gkqgenerategausslegendre(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state); +void gkqgenerategaussjacobi(ae_int_t n, + double alpha, + double beta, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state); +void gkqlegendrecalc(ae_int_t n, + ae_int_t* info, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + ae_state *_state); +void gkqlegendretbl(ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* wkronrod, + /* Real */ ae_vector* wgauss, + double* eps, + ae_state *_state); +#endif +#if defined(AE_COMPILE_AUTOGK) || !defined(AE_PARTIAL_BUILD) +void autogksmooth(double a, + double b, + autogkstate* state, + ae_state *_state); +void autogksmoothw(double a, + double b, + double xwidth, + autogkstate* state, + ae_state *_state); +void autogksingular(double a, + double b, + double alpha, + double beta, + autogkstate* state, + ae_state *_state); +ae_bool autogkiteration(autogkstate* state, ae_state *_state); +void autogkresults(const autogkstate* state, + double* v, + autogkreport* rep, + ae_state *_state); +void _autogkreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _autogkreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _autogkreport_clear(void* _p); +void _autogkreport_destroy(void* _p); +void _autogkinternalstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _autogkinternalstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _autogkinternalstate_clear(void* _p); +void _autogkinternalstate_destroy(void* _p); +void _autogkstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _autogkstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _autogkstate_clear(void* _p); +void _autogkstate_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/interpolation.cpp b/core/alglib/interpolation.cpp index 6202bb3e..3f8d20fb 100644 --- a/core/alglib/interpolation.cpp +++ b/core/alglib/interpolation.cpp @@ -1,30715 +1,74536 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "interpolation.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -IDW interpolant. -*************************************************************************/ -_idwinterpolant_owner::_idwinterpolant_owner() -{ - p_struct = (alglib_impl::idwinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_idwinterpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_idwinterpolant_owner::_idwinterpolant_owner(const _idwinterpolant_owner &rhs) -{ - p_struct = (alglib_impl::idwinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_idwinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_idwinterpolant_owner& _idwinterpolant_owner::operator=(const _idwinterpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_idwinterpolant_clear(p_struct); - if( !alglib_impl::_idwinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_idwinterpolant_owner::~_idwinterpolant_owner() -{ - alglib_impl::_idwinterpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::idwinterpolant* _idwinterpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::idwinterpolant* _idwinterpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -idwinterpolant::idwinterpolant() : _idwinterpolant_owner() -{ -} - -idwinterpolant::idwinterpolant(const idwinterpolant &rhs):_idwinterpolant_owner(rhs) -{ -} - -idwinterpolant& idwinterpolant::operator=(const idwinterpolant &rhs) -{ - if( this==&rhs ) - return *this; - _idwinterpolant_owner::operator=(rhs); - return *this; -} - -idwinterpolant::~idwinterpolant() -{ -} - -/************************************************************************* -IDW interpolation - -INPUT PARAMETERS: - Z - IDW interpolant built with one of model building - subroutines. - X - array[0..NX-1], interpolation point - -Result: - IDW interpolant Z(X) - - -- ALGLIB -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -double idwcalc(const idwinterpolant &z, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::idwcalc(const_cast(z.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -IDW interpolant using modified Shepard method for uniform point -distributions. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function type, either: - * 0 constant model. Just for demonstration only, worst - model ever. - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - * -1 "fast" linear model, use with caution!!! It is - significantly faster than linear/quadratic and better - than constant model. But it is less robust (especially - in the presence of noise). - NQ - number of points used to calculate nodal functions (ignored - for constant models). NQ should be LARGER than: - * max(1.5*(1+NX),2^NX+1) for linear model, - * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, worst - with constant - models - * when N is large, NQ and NW must be significantly smaller than N both - to obtain optimal performance and to obtain optimal accuracy. In 2 or - 3-dimensional tasks NQ=15 and NW=25 are good values to start with. - * NQ and NW may be greater than N. In such cases they will be - automatically decreased. - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - * this subroutine assumes that point distribution is uniform at the small - scales. If it isn't - for example, points are concentrated along - "lines", but "lines" distribution is uniform at the larger scale - then - you should use IDWBuildModifiedShepardR() - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepard(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::idwbuildmodifiedshepard(const_cast(xy.c_ptr()), n, nx, d, nq, nw, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -IDW interpolant using modified Shepard method for non-uniform datasets. - -This type of model uses constant nodal functions and interpolates using -all nodes which are closer than user-specified radius R. It may be used -when points distribution is non-uniform at the small scale, but it is at -the distances as large as R. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - R - radius, R>0 - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: -* if there is less than IDWKMin points within R-ball, algorithm selects - IDWKMin closest ones, so that continuity properties of interpolant are - preserved even far from points. - - -- ALGLIB PROJECT -- - Copyright 11.04.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepardr(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const double r, idwinterpolant &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::idwbuildmodifiedshepardr(const_cast(xy.c_ptr()), n, nx, r, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -IDW model for noisy data. - -This subroutine may be used to handle noisy data, i.e. data with noise in -OUTPUT values. It differs from IDWBuildModifiedShepard() in the following -aspects: -* nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, - i.e. we have fitting instead of interpolation. -* weights which are used during least squares fitting stage are all equal - to 1.0 (independently of distance) -* "fast"-linear or constant nodal functions are not supported (either not - robust enough or too rigid) - -This problem require far more complex tuning than interpolation problems. -Below you can find some recommendations regarding this problem: -* focus on tuning NQ; it controls noise reduction. As for NW, you can just - make it equal to 2*NQ. -* you can use cross-validation to determine optimal NQ. -* optimal NQ is a result of complex tradeoff between noise level (more - noise = larger NQ required) and underlying function complexity (given - fixed N, larger NQ means smoothing of compex features in the data). For - example, NQ=N will reduce noise to the minimum level possible, but you - will end up with just constant/linear/quadratic (depending on D) least - squares model for the whole dataset. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function degree, either: - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models (or for very - noisy problems). - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - NQ - number of points used to calculate nodal functions. NQ should - be significantly larger than 1.5 times the number of - coefficients in a nodal function to overcome effects of noise: - * larger than 1.5*(1+NX) for linear model, - * larger than 3/4*(NX+2)*(NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ or larger - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, linear models are not - recommended to use unless you are pretty sure that it is what you want - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildnoisy(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::idwbuildnoisy(const_cast(xy.c_ptr()), n, nx, d, nq, nw, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Barycentric interpolant. -*************************************************************************/ -_barycentricinterpolant_owner::_barycentricinterpolant_owner() -{ - p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_barycentricinterpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_barycentricinterpolant_owner::_barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs) -{ - p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_barycentricinterpolant_owner& _barycentricinterpolant_owner::operator=(const _barycentricinterpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_barycentricinterpolant_clear(p_struct); - if( !alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_barycentricinterpolant_owner::~_barycentricinterpolant_owner() -{ - alglib_impl::_barycentricinterpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -barycentricinterpolant::barycentricinterpolant() : _barycentricinterpolant_owner() -{ -} - -barycentricinterpolant::barycentricinterpolant(const barycentricinterpolant &rhs):_barycentricinterpolant_owner(rhs) -{ -} - -barycentricinterpolant& barycentricinterpolant::operator=(const barycentricinterpolant &rhs) -{ - if( this==&rhs ) - return *this; - _barycentricinterpolant_owner::operator=(rhs); - return *this; -} - -barycentricinterpolant::~barycentricinterpolant() -{ -} - -/************************************************************************* -Rational interpolation using barycentric formula - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -Input parameters: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -Result: - barycentric interpolant F(t) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -double barycentriccalc(const barycentricinterpolant &b, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::barycentriccalc(const_cast(b.c_ptr()), t, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Differentiation of barycentric interpolant: first derivative. - -Algorithm used in this subroutine is very robust and should not fail until -provided with values too close to MaxRealNumber (usually MaxRealNumber/N -or greater will overflow). - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - -NOTE - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricdiff1(const_cast(b.c_ptr()), t, &f, &df, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Differentiation of barycentric interpolant: first/second derivatives. - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - D2F - second derivative - -NOTE: this algorithm may fail due to overflow/underflor if used on data -whose values are close to MaxRealNumber or MinRealNumber. Use more robust -BarycentricDiff1() subroutine in such cases. - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricdiff2(const_cast(b.c_ptr()), t, &f, &df, &d2f, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the argument. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: x = CA*t + CB - -OUTPUT PARAMETERS: - B - transformed interpolant with X replaced by T - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentriclintransx(const_cast(b.c_ptr()), ca, cb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the barycentric -interpolant. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB - -OUTPUT PARAMETERS: - B - transformed interpolant - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentriclintransy(const_cast(b.c_ptr()), ca, cb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Extracts X/Y/W arrays from rational interpolant - -INPUT PARAMETERS: - B - barycentric interpolant - -OUTPUT PARAMETERS: - N - nodes count, N>0 - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricunpack(const_cast(b.c_ptr()), &n, const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rational interpolant from X/Y/W arrays - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -INPUT PARAMETERS: - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - N - nodes count, N>0 - -OUTPUT PARAMETERS: - B - barycentric interpolant built from (X, Y, W) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricbuildxyw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rational interpolant without poles - -The subroutine constructs the rational interpolating function without real -poles (see 'Barycentric rational interpolation with no poles and high -rates of approximation', Michael S. Floater. and Kai Hormann, for more -information on this subject). - -Input parameters: - X - interpolation nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of nodes, N>0. - D - order of the interpolation scheme, 0 <= D <= N-1. - D<0 will cause an error. - D>=N it will be replaced with D=N-1. - if you don't know what D to choose, use small value about 3-5. - -Output parameters: - B - barycentric interpolant. - -Note: - this algorithm always succeeds and calculates the weights with close - to machine precision. - - -- ALGLIB PROJECT -- - Copyright 17.06.2007 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricbuildfloaterhormann(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, d, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from barycentric representation to Chebyshev basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - A,B - base interval for Chebyshev polynomials (see below) - A<>B - -OUTPUT PARAMETERS - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, - where Ti - I-th Chebyshev polynomial. - -NOTES: - barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbar2cheb(const_cast(p.c_ptr()), a, b, const_cast(t.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from Chebyshev basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, - where Ti - I-th Chebyshev polynomial. - N - number of coefficients: - * if given, only leading N elements of T are used - * if not given, automatically determined from size of T - A,B - base interval for Chebyshev polynomials (see above) - A(t.c_ptr()), n, a, b, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from Chebyshev basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, - where Ti - I-th Chebyshev polynomial. - N - number of coefficients: - * if given, only leading N elements of T are used - * if not given, automatically determined from size of T - A,B - base interval for Chebyshev polynomials (see above) - A(t.c_ptr()), n, a, b, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from barycentric representation to power basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if P was obtained as - result of interpolation on [-1,+1], you can set C=0 and S=1 and - represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it - is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 - will be better option. Such representation can be obtained by using - 1000.0 as offset C and 1.0 as scale S. - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return coefficients in - any case, but for N>8 they will become unreliable. However, N's - less than 5 are pretty safe. - -3. barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbar2pow(const_cast(p.c_ptr()), c, s, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from barycentric representation to power basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if P was obtained as - result of interpolation on [-1,+1], you can set C=0 and S=1 and - represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it - is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 - will be better option. Such representation can be obtained by using - 1000.0 as offset C and 1.0 as scale S. - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return coefficients in - any case, but for N>8 they will become unreliable. However, N's - less than 5 are pretty safe. - -3. barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - double c; - double s; - - c = 0; - s = 1; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbar2pow(const_cast(p.c_ptr()), c, s, const_cast(a.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from power basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - * if given, only leading N elements of A are used - * if not given, automatically determined from size of A - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - P - polynomial in barycentric form - - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if you interpolate on - [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, - x^3 and so on. In most cases you it is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, - (x-1000)^3 will be better option (you have to specify 1000.0 as offset - C and 1.0 as scale S). - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return barycentric model - in any case, but for N>8 accuracy well degrade. However, N's less than - 5 are pretty safe. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialpow2bar(const_cast(a.c_ptr()), n, c, s, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion from power basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - * if given, only leading N elements of A are used - * if not given, automatically determined from size of A - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - P - polynomial in barycentric form - - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if you interpolate on - [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, - x^3 and so on. In most cases you it is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, - (x-1000)^3 will be better option (you have to specify 1000.0 as offset - C and 1.0 as scale S). - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return barycentric model - in any case, but for N>8 accuracy well degrade. However, N's less than - 5 are pretty safe. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - double c; - double s; - - n = a.length(); - c = 0; - s = 1; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialpow2bar(const_cast(a.c_ptr()), n, c, s, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant: generation of the model on the general grid. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - X - abscissas, array[0..N-1] - Y - function values, array[0..N-1] - N - number of points, N>=1 - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuild(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant: generation of the model on the general grid. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - X - abscissas, array[0..N-1] - Y - function values, array[0..N-1] - N - number of points, N>=1 - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'polynomialbuild': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuild(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant: generation of the model on equidistant grid. -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1] - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildeqdist(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant: generation of the model on equidistant grid. -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1] - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = y.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildeqdist(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (first kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildcheb1(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (first kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = y.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildcheb1(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (second kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildcheb2(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (second kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = y.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialbuildcheb2(a, b, const_cast(y.c_ptr()), n, const_cast(p.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast equidistant polynomial interpolation function with O(N) complexity - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on equidistant grid, N>=1 - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolynomialBuildEqDist()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalceqdist(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast equidistant polynomial interpolation function with O(N) complexity - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on equidistant grid, N>=1 - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolynomialBuildEqDist()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = f.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalceqdist(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (first kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (first kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb1()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalccheb1(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (first kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (first kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb1()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = f.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalccheb1(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (second kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (second kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb2()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalccheb2(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (second kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (second kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb2()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = f.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::polynomialcalccheb2(a, b, const_cast(f.c_ptr()), n, t, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -1-dimensional spline interpolant -*************************************************************************/ -_spline1dinterpolant_owner::_spline1dinterpolant_owner() -{ - p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline1dinterpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline1dinterpolant_owner::_spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs) -{ - p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline1dinterpolant_owner& _spline1dinterpolant_owner::operator=(const _spline1dinterpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_spline1dinterpolant_clear(p_struct); - if( !alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_spline1dinterpolant_owner::~_spline1dinterpolant_owner() -{ - alglib_impl::_spline1dinterpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -spline1dinterpolant::spline1dinterpolant() : _spline1dinterpolant_owner() -{ -} - -spline1dinterpolant::spline1dinterpolant(const spline1dinterpolant &rhs):_spline1dinterpolant_owner(rhs) -{ -} - -spline1dinterpolant& spline1dinterpolant::operator=(const spline1dinterpolant &rhs) -{ - if( this==&rhs ) - return *this; - _spline1dinterpolant_owner::operator=(rhs); - return *this; -} - -spline1dinterpolant::~spline1dinterpolant() -{ -} - -/************************************************************************* -This subroutine builds linear spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildlinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds linear spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dbuildlinear': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildlinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds cubic spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - C - spline interpolant - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds cubic spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - C - spline interpolant - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dbuildcubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns table of function derivatives d[] -(calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D - derivative values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dgriddiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns table of function derivatives d[] -(calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D - derivative values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dgriddiffcubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dgriddiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns tables of first and second -function derivatives d1[] and d2[] (calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D1 - S' values at X[] - D2 - S'' values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dgriddiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d1.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns tables of first and second -function derivatives d1[] and d2[] (calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D1 - S' values at X[] - D2 - S'' values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dgriddiff2cubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dgriddiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(d1.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - ae_int_t n2; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dconvcubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - n2 = x2.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] and derivatives d2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvdiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] and derivatives d2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - ae_int_t n2; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dconvdiffcubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - n2 = x2.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvdiffcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[], first and second derivatives d2[] and dd2[] -(calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - DD2 - second derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvdiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), const_cast(dd2.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[], first and second derivatives d2[] and dd2[] -(calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - DD2 - second derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t boundltype; - double boundl; - ae_int_t boundrtype; - double boundr; - ae_int_t n2; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dconvdiff2cubic': looks like one of arguments has wrong size"); - n = x.length(); - boundltype = 0; - boundl = 0; - boundrtype = 0; - boundr = 0; - n2 = x2.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dconvdiff2cubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast(x2.c_ptr()), n2, const_cast(y2.c_ptr()), const_cast(d2.c_ptr()), const_cast(dd2.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Catmull-Rom spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundType - boundary condition type: - * -1 for periodic boundary condition - * 0 for parabolically terminated spline (default) - Tension - tension parameter: - * tension=0 corresponds to classic Catmull-Rom spline (default) - * 0(x.c_ptr()), const_cast(y.c_ptr()), n, boundtype, tension, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Catmull-Rom spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundType - boundary condition type: - * -1 for periodic boundary condition - * 0 for parabolically terminated spline (default) - Tension - tension parameter: - * tension=0 corresponds to classic Catmull-Rom spline (default) - * 0(x.c_ptr()), const_cast(y.c_ptr()), n, boundtype, tension, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Hermite spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - D - derivatives, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildhermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(d.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Hermite spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - D - derivatives, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length()) || (x.length()!=d.length())) - throw ap_error("Error while calling 'spline1dbuildhermite': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildhermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(d.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Akima spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildakima(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds Akima spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dbuildakima': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildakima(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates the value of the spline at the given point X. - -INPUT PARAMETERS: - C - spline interpolant - X - point - -Result: - S(x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dcalc(const spline1dinterpolant &c, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spline1dcalc(const_cast(c.c_ptr()), x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine differentiates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -Result: - S - S(x) - DS - S'(x) - D2S - S''(x) - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1ddiff(const_cast(c.c_ptr()), x, &s, &ds, &d2s, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine unpacks the spline into the coefficients table. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -OUTPUT PARAMETERS: - Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. - For I = 0...N-2: - Tbl[I,0] = X[i] - Tbl[I,1] = X[i+1] - Tbl[I,2] = C0 - Tbl[I,3] = C1 - Tbl[I,4] = C2 - Tbl[I,5] = C3 - On [x[i], x[i+1]] spline is equals to: - S(x) = C0 + C1*t + C2*t^2 + C3*t^3 - t = x-x[i] - -NOTE: - You can rebuild spline with Spline1DBuildHermite() function, which - accepts as inputs function values and derivatives at nodes, which are - easy to calculate when you have coefficients. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dunpack(const_cast(c.c_ptr()), &n, const_cast(tbl.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: x = A*t + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dlintransx(const_cast(c.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x) = A*S(x) + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dlintransy(const_cast(c.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine integrates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - right bound of the integration interval [a, x], - here 'a' denotes min(x[]) -Result: - integral(S(t)dt,a,x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dintegrate(const spline1dinterpolant &c, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spline1dintegrate(const_cast(c.c_ptr()), x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds monotone cubic Hermite interpolant. This interpolant -is monotonic in [x(0),x(n-1)] and is constant outside of this interval. - -In case y[] form non-monotonic sequence, interpolant is piecewise -monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will -monotonically grow at [0..2] and monotonically decrease at [2..4]. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. Subroutine automatically - sorts points, so caller may pass unsorted array. - Y - function values, array[0..N-1] - N - the number of points(N>=2). - -OUTPUT PARAMETERS: - C - spline interpolant. - - -- ALGLIB PROJECT -- - Copyright 21.06.2012 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildmonotone(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds monotone cubic Hermite interpolant. This interpolant -is monotonic in [x(0),x(n-1)] and is constant outside of this interval. - -In case y[] form non-monotonic sequence, interpolant is piecewise -monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will -monotonically grow at [0..2] and monotonically decrease at [2..4]. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. Subroutine automatically - sorts points, so caller may pass unsorted array. - Y - function values, array[0..N-1] - N - the number of points(N>=2). - -OUTPUT PARAMETERS: - C - spline interpolant. - - -- ALGLIB PROJECT -- - Copyright 21.06.2012 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dbuildmonotone': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dbuildmonotone(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Polynomial fitting report: - TaskRCond reciprocal of task's condition number - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error -*************************************************************************/ -_polynomialfitreport_owner::_polynomialfitreport_owner() -{ - p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_polynomialfitreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_polynomialfitreport_owner::_polynomialfitreport_owner(const _polynomialfitreport_owner &rhs) -{ - p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_polynomialfitreport_owner& _polynomialfitreport_owner::operator=(const _polynomialfitreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_polynomialfitreport_clear(p_struct); - if( !alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_polynomialfitreport_owner::~_polynomialfitreport_owner() -{ - alglib_impl::_polynomialfitreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -polynomialfitreport::polynomialfitreport() : _polynomialfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -polynomialfitreport::polynomialfitreport(const polynomialfitreport &rhs):_polynomialfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -polynomialfitreport& polynomialfitreport::operator=(const polynomialfitreport &rhs) -{ - if( this==&rhs ) - return *this; - _polynomialfitreport_owner::operator=(rhs); - return *this; -} - -polynomialfitreport::~polynomialfitreport() -{ -} - - -/************************************************************************* -Barycentric fitting report: - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - TaskRCond reciprocal of task's condition number -*************************************************************************/ -_barycentricfitreport_owner::_barycentricfitreport_owner() -{ - p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_barycentricfitreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_barycentricfitreport_owner::_barycentricfitreport_owner(const _barycentricfitreport_owner &rhs) -{ - p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_barycentricfitreport_owner& _barycentricfitreport_owner::operator=(const _barycentricfitreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_barycentricfitreport_clear(p_struct); - if( !alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_barycentricfitreport_owner::~_barycentricfitreport_owner() -{ - alglib_impl::_barycentricfitreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -barycentricfitreport::barycentricfitreport() : _barycentricfitreport_owner() ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -barycentricfitreport::barycentricfitreport(const barycentricfitreport &rhs):_barycentricfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -barycentricfitreport& barycentricfitreport::operator=(const barycentricfitreport &rhs) -{ - if( this==&rhs ) - return *this; - _barycentricfitreport_owner::operator=(rhs); - return *this; -} - -barycentricfitreport::~barycentricfitreport() -{ -} - - -/************************************************************************* -Spline fitting report: - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - -Fields below are filled by obsolete functions (Spline1DFitCubic, -Spline1DFitHermite). Modern fitting functions do NOT fill these fields: - TaskRCond reciprocal of task's condition number -*************************************************************************/ -_spline1dfitreport_owner::_spline1dfitreport_owner() -{ - p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline1dfitreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline1dfitreport_owner::_spline1dfitreport_owner(const _spline1dfitreport_owner &rhs) -{ - p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline1dfitreport_owner& _spline1dfitreport_owner::operator=(const _spline1dfitreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_spline1dfitreport_clear(p_struct); - if( !alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_spline1dfitreport_owner::~_spline1dfitreport_owner() -{ - alglib_impl::_spline1dfitreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -spline1dfitreport::spline1dfitreport() : _spline1dfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -spline1dfitreport::spline1dfitreport(const spline1dfitreport &rhs):_spline1dfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) -{ -} - -spline1dfitreport& spline1dfitreport::operator=(const spline1dfitreport &rhs) -{ - if( this==&rhs ) - return *this; - _spline1dfitreport_owner::operator=(rhs); - return *this; -} - -spline1dfitreport::~spline1dfitreport() -{ -} - - -/************************************************************************* -Least squares fitting report. This structure contains informational fields -which are set by fitting functions provided by this unit. - -Different functions initialize different sets of fields, so you should -read documentation on specific function you used in order to know which -fields are initialized. - - TaskRCond reciprocal of task's condition number - IterationsCount number of internal iterations - - VarIdx if user-supplied gradient contains errors which were - detected by nonlinear fitter, this field is set to - index of the first component of gradient which is - suspected to be spoiled by bugs. - - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - - WRMSError weighted RMS error - - CovPar covariance matrix for parameters, filled by some solvers - ErrPar vector of errors in parameters, filled by some solvers - ErrCurve vector of fit errors - variability of the best-fit - curve, filled by some solvers. - Noise vector of per-point noise estimates, filled by - some solvers. - R2 coefficient of determination (non-weighted, non-adjusted), - filled by some solvers. -*************************************************************************/ -_lsfitreport_owner::_lsfitreport_owner() -{ - p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lsfitreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lsfitreport_owner::_lsfitreport_owner(const _lsfitreport_owner &rhs) -{ - p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lsfitreport_owner& _lsfitreport_owner::operator=(const _lsfitreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_lsfitreport_clear(p_struct); - if( !alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_lsfitreport_owner::~_lsfitreport_owner() -{ - alglib_impl::_lsfitreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -lsfitreport::lsfitreport() : _lsfitreport_owner() ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) -{ -} - -lsfitreport::lsfitreport(const lsfitreport &rhs):_lsfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) -{ -} - -lsfitreport& lsfitreport::operator=(const lsfitreport &rhs) -{ - if( this==&rhs ) - return *this; - _lsfitreport_owner::operator=(rhs); - return *this; -} - -lsfitreport::~lsfitreport() -{ -} - - -/************************************************************************* -Nonlinear fitter. - -You should use ALGLIB functions to work with fitter. -Never try to access its fields directly! -*************************************************************************/ -_lsfitstate_owner::_lsfitstate_owner() -{ - p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lsfitstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lsfitstate_owner::_lsfitstate_owner(const _lsfitstate_owner &rhs) -{ - p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lsfitstate_owner& _lsfitstate_owner::operator=(const _lsfitstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_lsfitstate_clear(p_struct); - if( !alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_lsfitstate_owner::~_lsfitstate_owner() -{ - alglib_impl::_lsfitstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -lsfitstate::lsfitstate() : _lsfitstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x) -{ -} - -lsfitstate::lsfitstate(const lsfitstate &rhs):_lsfitstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x) -{ -} - -lsfitstate& lsfitstate::operator=(const lsfitstate &rhs) -{ - if( this==&rhs ) - return *this; - _lsfitstate_owner::operator=(rhs); - return *this; -} - -lsfitstate::~lsfitstate() -{ -} - -/************************************************************************* -Fitting by polynomials in barycentric form. This function provides simple -unterface for unconstrained unweighted fitting. See PolynomialFitWC() if -you need constrained fitting. - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFitWC() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0 - * if given, only leading N elements of X/Y are used - * if not given, automatically determined from sizes of X/Y - M - number of basis functions (= polynomial_degree + 1), M>=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fitting by polynomials in barycentric form. This function provides simple -unterface for unconstrained unweighted fitting. See PolynomialFitWC() if -you need constrained fitting. - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFitWC() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0 - * if given, only leading N elements of X/Y are used - * if not given, automatically determined from sizes of X/Y - M - number of basis functions (= polynomial_degree + 1), M>=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'polynomialfit': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialfit(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by polynomials in barycentric form, with constraints on -function values or first derivatives. - -Small regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFit() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - * if given, only leading N elements of X/Y/W are used - * if not given, automatically determined from sizes of X/Y/W - XC - points where polynomial values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that P(XC[i])=YC[i] - * DC[i]=1 means that P'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* even simple constraints can be inconsistent, see Wikipedia article on - this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the one special cases, however, we can guarantee consistency. This - case is: M>1 and constraints on the function values (NOT DERIVATIVES) - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by polynomials in barycentric form, with constraints on -function values or first derivatives. - -Small regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFit() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - * if given, only leading N elements of X/Y/W are used - * if not given, automatically determined from sizes of X/Y/W - XC - points where polynomial values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that P(XC[i])=YC[i] - * DC[i]=1 means that P'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* even simple constraints can be inconsistent, see Wikipedia article on - this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the one special cases, however, we can guarantee consistency. This - case is: M>1 and constraints on the function values (NOT DERIVATIVES) - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t k; - if( (x.length()!=y.length()) || (x.length()!=w.length())) - throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); - if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) - throw ap_error("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); - n = x.length(); - k = xc.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::polynomialfitwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(p.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weghted rational least squares fitting using Floater-Hormann rational -functions with optimal D chosen from [0,9], with constraints and -individual weights. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least WEIGHTED root -mean square error) is chosen. Task is linear, so linear least squares -solver is used. Complexity of this computational scheme is O(N*M^2) -(mostly dominated by the least squares solver). - -SEE ALSO -* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual - weights and constraints. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - XC - points where function values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -1 means another errors in parameters passed - (N<=0, for example) - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroutine doesn't calculate task's condition number for K<>0. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained barycentric interpolants: -* excessive constraints can be inconsistent. Floater-Hormann basis - functions aren't as flexible as splines (although they are very smooth). -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function VALUES at the interval - boundaries. Note that consustency of the constraints on the function - DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines - which are more flexible). -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricfitfloaterhormannwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::barycentricfitfloaterhormann(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(b.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitpenalized(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by penalized cubic spline. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with natural boundary -conditions. Problem is regularized by adding non-linearity penalty to the -usual least squares penalty function: - - S(x) = arg min { LS + P }, where - LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty - P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty - rho - tunable constant given by user - C - automatically determined scale parameter, - makes penalty invariant with respect to scaling of X, Y, W. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - problem. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - M - number of basis functions ( = number_of_nodes), M>=4. - Rho - regularization constant passed by user. It penalizes - nonlinearity in the regression spline. It is logarithmically - scaled, i.e. actual value of regularization constant is - calculated as 10^Rho. It is automatically scaled so that: - * Rho=2.0 corresponds to moderate amount of nonlinearity - * generally, it should be somewhere in the [-8.0,+8.0] - If you do not want to penalize nonlineary, - pass small Rho. Values as low as -15 should work. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD or - Cholesky decomposition; problem may be - too ill-conditioned (very rare) - S - spline interpolant. - Rep - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTE 1: additional nodes are added to the spline outside of the fitting -interval to force linearity when xmax(x,xc). It is done -for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so -it is natural to force linearity outside of this interval. - -NOTE 2: function automatically sorts points, so caller may pass unsorted -array. - - -- ALGLIB PROJECT -- - Copyright 19.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by penalized cubic spline. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with natural boundary -conditions. Problem is regularized by adding non-linearity penalty to the -usual least squares penalty function: - - S(x) = arg min { LS + P }, where - LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty - P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty - rho - tunable constant given by user - C - automatically determined scale parameter, - makes penalty invariant with respect to scaling of X, Y, W. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - problem. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - M - number of basis functions ( = number_of_nodes), M>=4. - Rho - regularization constant passed by user. It penalizes - nonlinearity in the regression spline. It is logarithmically - scaled, i.e. actual value of regularization constant is - calculated as 10^Rho. It is automatically scaled so that: - * Rho=2.0 corresponds to moderate amount of nonlinearity - * generally, it should be somewhere in the [-8.0,+8.0] - If you do not want to penalize nonlineary, - pass small Rho. Values as low as -15 should work. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD or - Cholesky decomposition; problem may be - too ill-conditioned (very rare) - S - spline interpolant. - Rep - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTE 1: additional nodes are added to the spline outside of the fitting -interval to force linearity when xmax(x,xc). It is done -for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so -it is natural to force linearity outside of this interval. - -NOTE 2: function automatically sorts points, so caller may pass unsorted -array. - - -- ALGLIB PROJECT -- - Copyright 19.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length()) || (x.length()!=w.length())) - throw ap_error("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitpenalizedw(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, m, rho, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by cubic spline, with constraints on function values or -derivatives. - -Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with continuous second -derivatives and non-fixed first derivatives at interval ends. Small -regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, - less smooth) - Spline1DFitCubic() - "lightweight" fitting by cubic splines, - without invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - S - spline interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function values AND/OR its - derivatives at the interval boundaries. -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by cubic spline, with constraints on function values or -derivatives. - -Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with continuous second -derivatives and non-fixed first derivatives at interval ends. Small -regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, - less smooth) - Spline1DFitCubic() - "lightweight" fitting by cubic splines, - without invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - S - spline interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function values AND/OR its - derivatives at the interval boundaries. -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t k; - if( (x.length()!=y.length()) || (x.length()!=w.length())) - throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); - if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) - throw ap_error("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); - n = x.length(); - k = xc.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitcubicwc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by Hermite spline, with constraints on function values -or first derivatives. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are Hermite splines. Small regularizing -term is used when solving constrained tasks (to improve stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, - more smooth) - Spline1DFitHermite() - "lightweight" Hermite fitting, without - invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4, - M IS EVEN! - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -2 means odd M was passed (which is not supported) - -1 means another errors in parameters passed - (N<=0, for example) - S - spline interpolant. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -IMPORTANT: - this subroitine supports only even M's - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the several special cases, however, we can guarantee consistency. -* one of this cases is M>=4 and constraints on the function value - (AND/OR its derivative) at the interval boundaries. -* another special case is M>=4 and ONE constraint on the function value - (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted fitting by Hermite spline, with constraints on function values -or first derivatives. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are Hermite splines. Small regularizing -term is used when solving constrained tasks (to improve stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, - more smooth) - Spline1DFitHermite() - "lightweight" Hermite fitting, without - invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4, - M IS EVEN! - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -2 means odd M was passed (which is not supported) - -1 means another errors in parameters passed - (N<=0, for example) - S - spline interpolant. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -IMPORTANT: - this subroitine supports only even M's - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the several special cases, however, we can guarantee consistency. -* one of this cases is M>=4 and constraints on the function value - (AND/OR its derivative) at the interval boundaries. -* another special case is M>=4 and ONE constraint on the function value - (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t k; - if( (x.length()!=y.length()) || (x.length()!=w.length())) - throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); - if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) - throw ap_error("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); - n = x.length(); - k = xc.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfithermitewc(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), n, const_cast(xc.c_ptr()), const_cast(yc.c_ptr()), const_cast(dc.c_ptr()), k, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Least squares fitting by cubic spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information -about subroutine parameters (we don't duplicate it here because of length) - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Least squares fitting by cubic spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information -about subroutine parameters (we don't duplicate it here because of length) - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfitcubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Least squares fitting by Hermite spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for -more information about subroutine parameters (we don't duplicate it here -because of length). - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Least squares fitting by Hermite spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for -more information about subroutine parameters (we don't duplicate it here -because of length). - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline1dfithermite(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m, &info, const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -1 incorrect N/M were specified - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -1 incorrect N/M were specified - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) - throw ap_error("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size"); - n = y.length(); - m = fmatrix.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearw(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted constained linear least squares fitting. - -This is variation of LSFitLinearW(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted constained linear least squares fitting. - -This is variation of LSFitLinearW(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) - throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); - if( (fmatrix.cols()!=cmatrix.cols()-1)) - throw ap_error("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); - n = y.length(); - m = fmatrix.cols(); - k = cmatrix.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearwc(const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - if( (y.length()!=fmatrix.rows())) - throw ap_error("Error while calling 'lsfitlinear': looks like one of arguments has wrong size"); - n = y.length(); - m = fmatrix.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinear(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), n, m, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Constained linear least squares fitting. - -This is variation of LSFitLinear(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Constained linear least squares fitting. - -This is variation of LSFitLinear(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (y.length()!=fmatrix.rows())) - throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); - if( (fmatrix.cols()!=cmatrix.cols()-1)) - throw ap_error("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); - n = y.length(); - m = fmatrix.cols(); - k = cmatrix.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitlinearc(const_cast(y.c_ptr()), const_cast(fmatrix.c_ptr()), const_cast(cmatrix.c_ptr()), n, m, k, &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewf(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length()) || (x.rows()!=w.length())) - throw ap_error("Error while calling 'lsfitcreatewf': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewf(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatef(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length())) - throw ap_error("Error while calling 'lsfitcreatef': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatef(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient only. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also: - LSFitResults - LSFitCreateFG (fitting without weights) - LSFitCreateWFGH (fitting using Hessian) - LSFitCreateFGH (fitting using Hessian, without weights) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewfg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient only. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also: - LSFitResults - LSFitCreateFG (fitting without weights) - LSFitCreateWFGH (fitting using Hessian) - LSFitCreateFGH (fitting using Hessian, without weights) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const bool cheapfg, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length()) || (x.rows()!=w.length())) - throw ap_error("Error while calling 'lsfitcreatewfg': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewfg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using gradient only, without individual -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatefg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using gradient only, without individual -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const bool cheapfg, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length())) - throw ap_error("Error while calling 'lsfitcreatefg': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatefg(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, cheapfg, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient/Hessian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewfgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient/Hessian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length()) || (x.rows()!=w.length())) - throw ap_error("Error while calling 'lsfitcreatewfgh': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatewfgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(w.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using gradient/Hessian, without individial -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatefgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Nonlinear least squares fitting using gradient/Hessian, without individial -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - ae_int_t k; - if( (x.rows()!=y.length())) - throw ap_error("Error while calling 'lsfitcreatefgh': looks like one of arguments has wrong size"); - n = x.rows(); - m = x.cols(); - k = c.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitcreatefgh(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(c.c_ptr()), n, m, k, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Stopping conditions for nonlinear least squares fitting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - stopping criterion. Algorithm stops if - |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by LSFitSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -NOTE - -Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic -stopping criterion selection (according to the scheme used by MINLM unit). - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetcond(const lsfitstate &state, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetcond(const_cast(state.c_ptr()), epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetstpmax(const lsfitstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -When reports are needed, State.C (current parameters) and State.F (current -value of fitting function) are reported. - - - -- ALGLIB -- - Copyright 15.08.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetxrep(const lsfitstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients for underlying optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetscale(const lsfitstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets boundary constraints for underlying optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[K]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[K]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: unlike other constrained optimization algorithms, this solver has -following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool lsfititeration(const lsfitstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::lsfititeration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.c, state.x, state.f, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.c, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (grad is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.c, state.x, state.f, ptr); - continue; - } - if( state.needfg ) - { - grad(state.c, state.x, state.f, state.g, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.c, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (func is NULL)"); - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (grad is NULL)"); - if( hess==NULL ) - throw ap_error("ALGLIB: error in 'lsfitfit()' (hess is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.c, state.x, state.f, ptr); - continue; - } - if( state.needfg ) - { - grad(state.c, state.x, state.f, state.g, ptr); - continue; - } - if( state.needfgh ) - { - hess(state.c, state.x, state.f, state.g, state.h, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.c, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -Nonlinear least squares fitting results. - -Called after return from LSFitFit(). - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Info - completion code: - * -7 gradient verification failed. - See LSFitSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - C - array[0..K-1], solution - Rep - optimization report. On success following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - * WRMSError weighted rms error on the (X,Y). - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(J*CovPar*J')), - where J is Jacobian matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitresults(const_cast(state.c_ptr()), &info, const_cast(c.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before fitting begins -* LSFitFit() is called -* prior to actual fitting, for each point in data set X_i and each - component of parameters being fited C_j algorithm performs following - steps: - * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], - where C_j is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on C[] - * F(X_i|C) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N*K (points count * parameters count) gradient - evaluations. It is very costly and you should use it only for low - dimensional problems, when you want to be sure that you've - correctly calculated analytic derivatives. You should not use it - in the production code (unless you want to check derivatives - provided by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with LSFitSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -NOTE 4: this function works only for optimizers created with LSFitCreateWFG() - or LSFitCreateFG() constructors. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetgradientcheck(const lsfitstate &state, const double teststep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lsfitsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Parametric spline inteprolant: 2-dimensional curve. - -You should not try to access its members directly - use PSpline2XXXXXXXX() -functions instead. -*************************************************************************/ -_pspline2interpolant_owner::_pspline2interpolant_owner() -{ - p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_pspline2interpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_pspline2interpolant_owner::_pspline2interpolant_owner(const _pspline2interpolant_owner &rhs) -{ - p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_pspline2interpolant_owner& _pspline2interpolant_owner::operator=(const _pspline2interpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_pspline2interpolant_clear(p_struct); - if( !alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_pspline2interpolant_owner::~_pspline2interpolant_owner() -{ - alglib_impl::_pspline2interpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -pspline2interpolant::pspline2interpolant() : _pspline2interpolant_owner() -{ -} - -pspline2interpolant::pspline2interpolant(const pspline2interpolant &rhs):_pspline2interpolant_owner(rhs) -{ -} - -pspline2interpolant& pspline2interpolant::operator=(const pspline2interpolant &rhs) -{ - if( this==&rhs ) - return *this; - _pspline2interpolant_owner::operator=(rhs); - return *this; -} - -pspline2interpolant::~pspline2interpolant() -{ -} - - -/************************************************************************* -Parametric spline inteprolant: 3-dimensional curve. - -You should not try to access its members directly - use PSpline3XXXXXXXX() -functions instead. -*************************************************************************/ -_pspline3interpolant_owner::_pspline3interpolant_owner() -{ - p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_pspline3interpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_pspline3interpolant_owner::_pspline3interpolant_owner(const _pspline3interpolant_owner &rhs) -{ - p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_pspline3interpolant_owner& _pspline3interpolant_owner::operator=(const _pspline3interpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_pspline3interpolant_clear(p_struct); - if( !alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_pspline3interpolant_owner::~_pspline3interpolant_owner() -{ - alglib_impl::_pspline3interpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -pspline3interpolant::pspline3interpolant() : _pspline3interpolant_owner() -{ -} - -pspline3interpolant::pspline3interpolant(const pspline3interpolant &rhs):_pspline3interpolant_owner(rhs) -{ -} - -pspline3interpolant& pspline3interpolant::operator=(const pspline3interpolant &rhs) -{ - if( this==&rhs ) - return *this; - _pspline3interpolant_owner::operator=(rhs); - return *this; -} - -pspline3interpolant::~pspline3interpolant() -{ -} - -/************************************************************************* -This function builds non-periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - Order of points is important! - N - points count, N>=5 for Akima splines, N>=2 for other types of - splines. - ST - spline type: - * 0 Akima spline - * 1 parabolically terminated Catmull-Rom spline (Tension=0) - * 2 parabolically terminated cubic spline - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2build(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds non-periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3build(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then -back to (X[0],Y[0]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - XY[N-1,0:1] must be different from XY[0,0:1]. - Order of points is important! - N - points count, N>=3 for other types of splines. - ST - spline type: - * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions - * 2 cubic spline with cyclic boundary conditions - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). -* last point of sequence is NOT equal to the first point. You shouldn't - make curve "explicitly periodic" by making them equal. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2buildperiodic(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) -and then back to (X[0],Y[0],Z[0]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3buildperiodic(const_cast(xy.c_ptr()), n, st, pt, const_cast(p.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns vector of parameter values correspoding to points. - -I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we -have - (X[0],Y[0]) = PSpline2Calc(P,U[0]), - (X[1],Y[1]) = PSpline2Calc(P,U[1]), - (X[2],Y[2]) = PSpline2Calc(P,U[2]), - ... - -INPUT PARAMETERS: - P - parametric spline interpolant - -OUTPUT PARAMETERS: - N - array size - T - array[0..N-1] - - -NOTES: -* for non-periodic splines U[0]=0, U[0](p.c_ptr()), &n, const_cast(t.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns vector of parameter values correspoding to points. - -Same as PSpline2ParameterValues(), but for 3D. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3parametervalues(const pspline3interpolant &p, ae_int_t &n, real_1d_array &t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3parametervalues(const_cast(p.c_ptr()), &n, const_cast(t.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates the value of the parametric spline for a given -value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2calc(const_cast(p.c_ptr()), t, &x, &y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates the value of the parametric spline for a given -value of parameter T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - Z - Z-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3calc(const_cast(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - -NOTE: - X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2tangent(const_cast(p.c_ptr()), t, &x, &y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - Z - Z-component of tangent vector (normalized) - -NOTE: - X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3tangent(const_cast(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2diff(const_cast(p.c_ptr()), t, &x, &dx, &y, &dy, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - Z - Z-value - DZ - Z-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3diff(const_cast(p.c_ptr()), t, &x, &dx, &y, &dy, &z, &dz, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline2diff2(const_cast(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - Z - Z-value - DZ - derivative - D2Z - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pspline3diff2(const_cast(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &z, &dz, &d2z, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates arc length, i.e. length of curve between t=a -and t=b. - -INPUT PARAMETERS: - P - parametric spline interpolant - A,B - parameter values corresponding to arc ends: - * B>A will result in positive length returned - * B(p.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates arc length, i.e. length of curve between t=a -and t=b. - -INPUT PARAMETERS: - P - parametric spline interpolant - A,B - parameter values corresponding to arc ends: - * B>A will result in positive length returned - * B(p.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -RBF model. - -Never try to directly work with fields of this object - always use ALGLIB -functions to use this object. -*************************************************************************/ -_rbfmodel_owner::_rbfmodel_owner() -{ - p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_rbfmodel_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_rbfmodel_owner::_rbfmodel_owner(const _rbfmodel_owner &rhs) -{ - p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_rbfmodel_owner& _rbfmodel_owner::operator=(const _rbfmodel_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_rbfmodel_clear(p_struct); - if( !alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_rbfmodel_owner::~_rbfmodel_owner() -{ - alglib_impl::_rbfmodel_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() const -{ - return const_cast(p_struct); -} -rbfmodel::rbfmodel() : _rbfmodel_owner() -{ -} - -rbfmodel::rbfmodel(const rbfmodel &rhs):_rbfmodel_owner(rhs) -{ -} - -rbfmodel& rbfmodel::operator=(const rbfmodel &rhs) -{ - if( this==&rhs ) - return *this; - _rbfmodel_owner::operator=(rhs); - return *this; -} - -rbfmodel::~rbfmodel() -{ -} - - -/************************************************************************* -RBF solution report: -* TerminationType - termination type, positive values - success, - non-positive - failure. -*************************************************************************/ -_rbfreport_owner::_rbfreport_owner() -{ - p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_rbfreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_rbfreport_owner::_rbfreport_owner(const _rbfreport_owner &rhs) -{ - p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_rbfreport_owner& _rbfreport_owner::operator=(const _rbfreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_rbfreport_clear(p_struct); - if( !alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_rbfreport_owner::~_rbfreport_owner() -{ - alglib_impl::_rbfreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::rbfreport* _rbfreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::rbfreport* _rbfreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -rbfreport::rbfreport() : _rbfreport_owner() ,arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) -{ -} - -rbfreport::rbfreport(const rbfreport &rhs):_rbfreport_owner(rhs) ,arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) -{ -} - -rbfreport& rbfreport::operator=(const rbfreport &rhs) -{ - if( this==&rhs ) - return *this; - _rbfreport_owner::operator=(rhs); - return *this; -} - -rbfreport::~rbfreport() -{ -} - - -/************************************************************************* -This function serializes data structure to string. - -Important properties of s_out: -* it contains alphanumeric characters, dots, underscores, minus signs -* these symbols are grouped into words, which are separated by spaces - and Windows-style (CR+LF) newlines -* although serializer uses spaces and CR+LF as separators, you can - replace any separator character by arbitrary combination of spaces, - tabs, Windows or Unix newlines. It allows flexible reformatting of - the string in case you want to include it into text or XML file. - But you should not insert separators into the middle of the "words" - nor you should change case of letters. -* s_out can be freely moved between 32-bit and 64-bit systems, little - and big endian machines, and so on. You can serialize structure on - 32-bit machine and unserialize it on 64-bit one (or vice versa), or - serialize it on SPARC and unserialize on x86. You can also - serialize it in C++ version of ALGLIB and unserialize in C# one, - and vice versa. -*************************************************************************/ -void rbfserialize(rbfmodel &obj, std::string &s_out) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - alglib_impl::ae_int_t ssize; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_alloc_start(&serializer); - alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state); - ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); - s_out.clear(); - s_out.reserve((size_t)(ssize+1)); - alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); - alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - if( s_out.length()>(size_t)ssize ) - throw ap_error("ALGLIB: serialization integrity error"); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} -/************************************************************************* -This function unserializes data structure from string. -*************************************************************************/ -void rbfunserialize(std::string &s_in, rbfmodel &obj) -{ - alglib_impl::ae_state state; - alglib_impl::ae_serializer serializer; - - alglib_impl::ae_state_init(&state); - try - { - alglib_impl::ae_serializer_init(&serializer); - alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); - alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state); - alglib_impl::ae_serializer_stop(&serializer); - alglib_impl::ae_serializer_clear(&serializer); - alglib_impl::ae_state_clear(&state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(state.error_msg); - } -} - -/************************************************************************* -This function creates RBF model for a scalar (NY=1) or vector (NY>1) -function in a NX-dimensional space (NX=2 or NX=3). - -Newly created model is empty. It can be used for interpolation right after -creation, but it just returns zeros. You have to add points to the model, -tune interpolation settings, and then call model construction function -RBFBuildModel() which will update model according to your specification. - -USAGE: -1. User creates model with RBFCreate() -2. User adds dataset with RBFSetPoints() (points do NOT have to be on a - regular grid) -3. (OPTIONAL) User chooses polynomial term by calling: - * RBFLinTerm() to set linear term - * RBFConstTerm() to set constant term - * RBFZeroTerm() to set zero term - By default, linear term is used. -4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) - or ML (RBFSetAlgoMultiLayer). -5. User calls RBFBuildModel() function which rebuilds model according to - the specification -6. User may call RBFCalc() to calculate model value at the specified point, - RBFGridCalc() to calculate model values at the points of the regular - grid. User may extract model coefficients with RBFUnpack() call. - -INPUT PARAMETERS: - NX - dimension of the space, NX=2 or NX=3 - NY - function dimension, NY>=1 - -OUTPUT PARAMETERS: - S - RBF model (initially equals to zero) - -NOTE 1: memory requirements. RBF models require amount of memory which is - proportional to the number of data points. Memory is allocated - during model construction, but most of this memory is freed after - model coefficients are calculated. - - Some approximate estimates for N centers with default settings are - given below: - * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is - needed during model construction stage. - * about 15*N*sizeof(double) bytes is needed after model is built. - For example, for N=100000 we may need 0.6 GB of memory to build - model, but just about 0.012 GB to store it. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfcreate(nx, ny, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset. - -This function overrides results of the previous calls, i.e. multiple calls -of this function will result in only the last set being added. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call. - XY - points, array[N,NX+NY]. One row corresponds to one point - in the dataset. First NX elements are coordinates, next - NY elements are function values. Array may be larger than - specific, in this case only leading [N,NX+NY] elements - will be used. - N - number of points in the dataset - -After you've added dataset and (optionally) tuned algorithm settings you -should call RBFBuildModel() in order to build a model for you. - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds dataset. - -This function overrides results of the previous calls, i.e. multiple calls -of this function will result in only the last set being added. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call. - XY - points, array[N,NX+NY]. One row corresponds to one point - in the dataset. First NX elements are coordinates, next - NY elements are function values. Array may be larger than - specific, in this case only leading [N,NX+NY] elements - will be used. - N - number of points in the dataset - -After you've added dataset and (optionally) tuned algorithm settings you -should call RBFBuildModel() in order to build a model for you. - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = xy.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetpoints(const_cast(s.c_ptr()), const_cast(xy.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-QNN and it is good for point sets with -following properties: -a) all points are distinct -b) all points are well separated. -c) points distribution is approximately uniform. There is no "contour - lines", clusters of points, or other small-scale structures. - -Algorithm description: -1) interpolation centers are allocated to data points -2) interpolation radii are calculated as distances to the nearest centers - times Q coefficient (where Q is a value from [0.75,1.50]). -3) after performing (2) radii are transformed in order to avoid situation - when single outlier has very large radius and influences many points - across all dataset. Transformation has following form: - new_r[i] = min(r[i],Z*median(r[])) - where r[i] is I-th radius, median() is a median radius across entire - dataset, Z is user-specified value which controls amount of deviation - from median radius. - -When (a) is violated, we will be unable to build RBF model. When (b) or -(c) are violated, model will be built, but interpolation quality will be -low. See http://www.alglib.net/interpolation/ for more information on this -subject. - -This algorithm is used by default. - -Additional Q parameter controls smoothness properties of the RBF basis: -* Q<0.75 will give perfectly conditioned basis, but terrible smoothness - properties (RBF interpolant will have sharp peaks around function values) -* Q around 1.0 gives good balance between smoothness and condition number -* Q>1.5 will lead to badly conditioned systems and slow convergence of the - underlying linear solver (although smoothness will be very good) -* Q>2.0 will effectively make optimizer useless because it won't converge - within reasonable amount of iterations. It is possible to set such large - Q, but it is advised not to do so. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Q - Q parameter, Q>0, recommended value - 1.0 - Z - Z parameter, Z>0, recommended value - 5.0 - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetalgoqnn(const_cast(s.c_ptr()), q, z, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-QNN and it is good for point sets with -following properties: -a) all points are distinct -b) all points are well separated. -c) points distribution is approximately uniform. There is no "contour - lines", clusters of points, or other small-scale structures. - -Algorithm description: -1) interpolation centers are allocated to data points -2) interpolation radii are calculated as distances to the nearest centers - times Q coefficient (where Q is a value from [0.75,1.50]). -3) after performing (2) radii are transformed in order to avoid situation - when single outlier has very large radius and influences many points - across all dataset. Transformation has following form: - new_r[i] = min(r[i],Z*median(r[])) - where r[i] is I-th radius, median() is a median radius across entire - dataset, Z is user-specified value which controls amount of deviation - from median radius. - -When (a) is violated, we will be unable to build RBF model. When (b) or -(c) are violated, model will be built, but interpolation quality will be -low. See http://www.alglib.net/interpolation/ for more information on this -subject. - -This algorithm is used by default. - -Additional Q parameter controls smoothness properties of the RBF basis: -* Q<0.75 will give perfectly conditioned basis, but terrible smoothness - properties (RBF interpolant will have sharp peaks around function values) -* Q around 1.0 gives good balance between smoothness and condition number -* Q>1.5 will lead to badly conditioned systems and slow convergence of the - underlying linear solver (although smoothness will be very good) -* Q>2.0 will effectively make optimizer useless because it won't converge - within reasonable amount of iterations. It is possible to set such large - Q, but it is advised not to do so. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Q - Q parameter, Q>0, recommended value - 1.0 - Z - Z parameter, Z>0, recommended value - 5.0 - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgoqnn(const rbfmodel &s) -{ - alglib_impl::ae_state _alglib_env_state; - double q; - double z; - - q = 1.0; - z = 5.0; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetalgoqnn(const_cast(s.c_ptr()), q, z, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. -model with subsequently decreasing radii, which allows us to combine -smoothness (due to large radii of the first layers) with exactness (due -to small radii of the last layers) and fast convergence. - -Internally RBF-ML uses many different means of acceleration, from sparse -matrices to KD-trees, which results in algorithm whose working time is -roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a -number of points, Density is an average density if points per unit of the -interpolation space, RBase is an initial radius, NLayers is a number of -layers. - -RBF-ML is good for following kinds of interpolation problems: -1. "exact" problems (perfect fit) with well separated points -2. least squares problems with arbitrary distribution of points (algorithm - gives perfect fit where it is possible, and resorts to least squares - fit in the hard areas). -3. noisy problems where we want to apply some controlled amount of - smoothing. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - RBase - RBase parameter, RBase>0 - NLayers - NLayers parameter, NLayers>0, recommended value to start - with - about 5. - LambdaV - regularization value, can be useful when solving problem - in the least squares sense. Optimal lambda is problem- - dependent and require trial and error. In our experience, - good lambda can be as large as 0.1, and you can use 0.001 - as initial guess. - Default value - 0.01, which is used when LambdaV is not - given. You can specify zero value, but it is not - recommended to do so. - -TUNING ALGORITHM - -In order to use this algorithm you have to choose three parameters: -* initial radius RBase -* number of layers in the model NLayers -* regularization coefficient LambdaV - -Initial radius is easy to choose - you can pick any number several times -larger than the average distance between points. Algorithm won't break -down if you choose radius which is too large (model construction time will -increase, but model will be built correctly). - -Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used -by the last layer) will be smaller than the typical distance between -points. In case model error is too large, you can increase number of -layers. Having more layers will make model construction and evaluation -proportionally slower, but it will allow you to have model which precisely -fits your data. From the other side, if you want to suppress noise, you -can DECREASE number of layers to make your model less flexible. - -Regularization coefficient LambdaV controls smoothness of the individual -models built for each layer. We recommend you to use default value in case -you don't want to tune this parameter, because having non-zero LambdaV -accelerates and stabilizes internal iterative algorithm. In case you want -to suppress noise you can use LambdaV as additional parameter (larger -value = more smoothness) to tune. - -TYPICAL ERRORS - -1. Using initial radius which is too large. Memory requirements of the - RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is - an average density of points per unit of the interpolation space). In - the extreme case of the very large RBase we will need O(N^2) units of - memory - and many layers in order to decrease radius to some reasonably - small value. - -2. Using too small number of layers - RBF models with large radius are not - flexible enough to reproduce small variations in the target function. - You need many layers with different radii, from large to small, in - order to have good model. - -3. Using initial radius which is too small. You will get model with - "holes" in the areas which are too far away from interpolation centers. - However, algorithm will work correctly (and quickly) in this case. - -4. Using too many layers - you will get too large and too slow model. This - model will perfectly reproduce your function, but maybe you will be - able to achieve similar results with less layers (and less memory). - - -- ALGLIB -- - Copyright 02.03.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetalgomultilayer(const_cast(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. -model with subsequently decreasing radii, which allows us to combine -smoothness (due to large radii of the first layers) with exactness (due -to small radii of the last layers) and fast convergence. - -Internally RBF-ML uses many different means of acceleration, from sparse -matrices to KD-trees, which results in algorithm whose working time is -roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a -number of points, Density is an average density if points per unit of the -interpolation space, RBase is an initial radius, NLayers is a number of -layers. - -RBF-ML is good for following kinds of interpolation problems: -1. "exact" problems (perfect fit) with well separated points -2. least squares problems with arbitrary distribution of points (algorithm - gives perfect fit where it is possible, and resorts to least squares - fit in the hard areas). -3. noisy problems where we want to apply some controlled amount of - smoothing. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - RBase - RBase parameter, RBase>0 - NLayers - NLayers parameter, NLayers>0, recommended value to start - with - about 5. - LambdaV - regularization value, can be useful when solving problem - in the least squares sense. Optimal lambda is problem- - dependent and require trial and error. In our experience, - good lambda can be as large as 0.1, and you can use 0.001 - as initial guess. - Default value - 0.01, which is used when LambdaV is not - given. You can specify zero value, but it is not - recommended to do so. - -TUNING ALGORITHM - -In order to use this algorithm you have to choose three parameters: -* initial radius RBase -* number of layers in the model NLayers -* regularization coefficient LambdaV - -Initial radius is easy to choose - you can pick any number several times -larger than the average distance between points. Algorithm won't break -down if you choose radius which is too large (model construction time will -increase, but model will be built correctly). - -Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used -by the last layer) will be smaller than the typical distance between -points. In case model error is too large, you can increase number of -layers. Having more layers will make model construction and evaluation -proportionally slower, but it will allow you to have model which precisely -fits your data. From the other side, if you want to suppress noise, you -can DECREASE number of layers to make your model less flexible. - -Regularization coefficient LambdaV controls smoothness of the individual -models built for each layer. We recommend you to use default value in case -you don't want to tune this parameter, because having non-zero LambdaV -accelerates and stabilizes internal iterative algorithm. In case you want -to suppress noise you can use LambdaV as additional parameter (larger -value = more smoothness) to tune. - -TYPICAL ERRORS - -1. Using initial radius which is too large. Memory requirements of the - RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is - an average density of points per unit of the interpolation space). In - the extreme case of the very large RBase we will need O(N^2) units of - memory - and many layers in order to decrease radius to some reasonably - small value. - -2. Using too small number of layers - RBF models with large radius are not - flexible enough to reproduce small variations in the target function. - You need many layers with different radii, from large to small, in - order to have good model. - -3. Using initial radius which is too small. You will get model with - "holes" in the areas which are too far away from interpolation centers. - However, algorithm will work correctly (and quickly) in this case. - -4. Using too many layers - you will get too large and too slow model. This - model will perfectly reproduce your function, but maybe you will be - able to achieve similar results with less layers (and less memory). - - -- ALGLIB -- - Copyright 02.03.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers) -{ - alglib_impl::ae_state _alglib_env_state; - double lambdav; - - lambdav = 0.01; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetalgomultilayer(const_cast(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear term (model is a sum of radial basis functions -plus linear polynomial). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetlinterm(const rbfmodel &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetlinterm(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets constant term (model is a sum of radial basis functions -plus constant). This function won't have effect until next call to -RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetconstterm(const rbfmodel &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetconstterm(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets zero term (model is a sum of radial basis functions -without polynomial term). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetzeroterm(const rbfmodel &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfsetzeroterm(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function builds RBF model and returns report (contains some -information which can be used for evaluation of the algorithm properties). - -Call to this function modifies RBF model by calculating its centers/radii/ -weights and saving them into RBFModel structure. Initially RBFModel -contain zero coefficients, but after call to this function we will have -coefficients which were calculated in order to fit our dataset. - -After you called this function you can call RBFCalc(), RBFGridCalc() and -other model calculation functions. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Rep - report: - * Rep.TerminationType: - * -5 - non-distinct basis function centers were detected, - interpolation aborted - * -4 - nonconvergence of the internal SVD solver - * 1 - successful termination - Fields are used for debugging purposes: - * Rep.IterationsCount - iterations count of the LSQR solver - * Rep.NMV - number of matrix-vector products - * Rep.ARows - rows count for the system matrix - * Rep.ACols - columns count for the system matrix - * Rep.ANNZ - number of significantly non-zero elements - (elements above some algorithm-determined threshold) - -NOTE: failure to build model will leave current state of the structure -unchanged. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfbuildmodel(const rbfmodel &s, rbfreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfbuildmodel(const_cast(s.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=2 -(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -If you want to calculate function values many times, consider using -RBFGridCalc2(), which is far more efficient than many subsequent calls to -RBFCalc2(). - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc2(const rbfmodel &s, const double x0, const double x1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rbfcalc2(const_cast(s.c_ptr()), x0, x1, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=3 -(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -This function returns 0.0 when: -* model is not initialized -* NX<>3 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - X2 - third coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rbfcalc3(const_cast(s.c_ptr()), x0, x1, x2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -This is general function which can be used for arbitrary NX (dimension of -the space of arguments) and NY (dimension of the function itself). However -when you have NY=1 you may find more convenient to use RBFCalc2() or -RBFCalc3(). - -This function returns 0.0 when model is not initialized. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is out-parameter and - reallocated after call to this function. In case you want - to reuse previously allocated Y, you may use RBFCalcBuf(), - which reallocates Y only when it is too small. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfcalc(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -Same as RBFCalc(), but does not reallocate Y when in is large enough to -store function values. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - Y - possibly preallocated array - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is not reallocated when it - is larger than NY. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfcalcbuf(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates values of the RBF model at the regular grid. - -Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - array of grid nodes, first coordinates, array[N0] - N0 - grid size (number of nodes) in the first dimension - X1 - array of grid nodes, second coordinates, array[N1] - N1 - grid size (number of nodes) in the second dimension - -OUTPUT PARAMETERS: - Y - function values, array[N0,N1]. Y is out-variable and - is reallocated by this function. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfgridcalc2(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_2d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfgridcalc2(const_cast(s.c_ptr()), const_cast(x0.c_ptr()), n0, const_cast(x1.c_ptr()), n1, const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function "unpacks" RBF model by extracting its coefficients. - -INPUT PARAMETERS: - S - RBF model - -OUTPUT PARAMETERS: - NX - dimensionality of argument - NY - dimensionality of the target function - XWR - model information, array[NC,NX+NY+1]. - One row of the array corresponds to one basis function: - * first NX columns - coordinates of the center - * next NY columns - weights, one per dimension of the - function being modelled - * last column - radius, same for all dimensions of - the function being modelled - NC - number of the centers - V - polynomial term , array[NY,NX+1]. One row per one - dimension of the function being modelled. First NX - elements are linear coefficients, V[NX] is equal to the - constant part. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfunpack(const rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rbfunpack(const_cast(s.c_ptr()), &nx, &ny, const_cast(xwr.c_ptr()), &nc, const_cast(v.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -2-dimensional spline inteprolant -*************************************************************************/ -_spline2dinterpolant_owner::_spline2dinterpolant_owner() -{ - p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline2dinterpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline2dinterpolant_owner::_spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs) -{ - p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline2dinterpolant_owner& _spline2dinterpolant_owner::operator=(const _spline2dinterpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_spline2dinterpolant_clear(p_struct); - if( !alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_spline2dinterpolant_owner::~_spline2dinterpolant_owner() -{ - alglib_impl::_spline2dinterpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -spline2dinterpolant::spline2dinterpolant() : _spline2dinterpolant_owner() -{ -} - -spline2dinterpolant::spline2dinterpolant(const spline2dinterpolant &rhs):_spline2dinterpolant_owner(rhs) -{ -} - -spline2dinterpolant& spline2dinterpolant::operator=(const spline2dinterpolant &rhs) -{ - if( this==&rhs ) - return *this; - _spline2dinterpolant_owner::operator=(rhs); - return *this; -} - -spline2dinterpolant::~spline2dinterpolant() -{ -} - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X. - -Input parameters: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y- point - -Result: - S(x,y) - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -double spline2dcalc(const spline2dinterpolant &c, const double x, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spline2dcalc(const_cast(c.c_ptr()), x, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X and its derivatives. - -Input parameters: - C - spline interpolant. - X, Y- point - -Output parameters: - F - S(x,y) - FX - dS(x,y)/dX - FY - dS(x,y)/dY - FXY - d2S(x,y)/dXdY - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2ddiff(const_cast(c.c_ptr()), x, y, &f, &fx, &fy, &fxy, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -Input parameters: - C - spline interpolant - AX, BX - transformation coefficients: x = A*t + B - AY, BY - transformation coefficients: y = A*u + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dlintransxy(const_cast(c.c_ptr()), ax, bx, ay, by, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -Input parameters: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B - -Output parameters: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dlintransf(const_cast(c.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine makes the copy of the spline model. - -Input parameters: - C - spline interpolant - -Output parameters: - CC - spline copy - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dcopy(const_cast(c.c_ptr()), const_cast(cc.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bicubic spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 15 May, 2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dresamplebicubic(const_cast(a.c_ptr()), oldheight, oldwidth, const_cast(b.c_ptr()), newheight, newwidth, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bilinear spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 09.07.2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dresamplebilinear(const_cast(a.c_ptr()), oldheight, oldwidth, const_cast(b.c_ptr()), newheight, newwidth, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds bilinear vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dbuildbilinearv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds bicubic vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dbuildbicubicv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dcalcvbuf(const_cast(c.c_ptr()), x, y, const_cast(f.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dcalcv(const_cast(c.c_ptr()), x, y, const_cast(f.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine unpacks two-dimensional spline into the coefficients table - -Input parameters: - C - spline interpolant. - -Result: - M, N- grid size (x-axis and y-axis) - D - number of components - Tbl - coefficients table, unpacked format, - D - components: [0..(N-1)*(M-1)*D-1, 0..19]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index): - K := T + I*D + J*D*(N-1) - - K-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[K,0] = X[i] - Tbl[K,1] = X[i+1] - Tbl[K,2] = Y[j] - Tbl[K,3] = Y[j+1] - Tbl[K,4] = C00 - Tbl[K,5] = C01 - Tbl[K,6] = C02 - Tbl[K,7] = C03 - Tbl[K,8] = C10 - Tbl[K,9] = C11 - ... - Tbl[K,19] = C33 - On each grid square spline is equals to: - S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) - t = x-x[j] - u = y-y[i] - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dunpackv(const_cast(c.c_ptr()), &m, &n, &d, const_cast(tbl.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBilinearV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dbuildbilinear(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(f.c_ptr()), m, n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBicubicV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dbuildbicubic(const_cast(x.c_ptr()), const_cast(y.c_ptr()), const_cast(f.c_ptr()), m, n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DUnpackV(), which is more flexible -and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline2dunpack(const_cast(c.c_ptr()), &m, &n, const_cast(tbl.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -3-dimensional spline inteprolant -*************************************************************************/ -_spline3dinterpolant_owner::_spline3dinterpolant_owner() -{ - p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline3dinterpolant_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline3dinterpolant_owner::_spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs) -{ - p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_spline3dinterpolant_owner& _spline3dinterpolant_owner::operator=(const _spline3dinterpolant_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_spline3dinterpolant_clear(p_struct); - if( !alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_spline3dinterpolant_owner::~_spline3dinterpolant_owner() -{ - alglib_impl::_spline3dinterpolant_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() const -{ - return const_cast(p_struct); -} -spline3dinterpolant::spline3dinterpolant() : _spline3dinterpolant_owner() -{ -} - -spline3dinterpolant::spline3dinterpolant(const spline3dinterpolant &rhs):_spline3dinterpolant_owner(rhs) -{ -} - -spline3dinterpolant& spline3dinterpolant::operator=(const spline3dinterpolant &rhs) -{ - if( this==&rhs ) - return *this; - _spline3dinterpolant_owner::operator=(rhs); - return *this; -} - -spline3dinterpolant::~spline3dinterpolant() -{ -} - -/************************************************************************* -This subroutine calculates the value of the trilinear or tricubic spline at -the given point (X,Y,Z). - -INPUT PARAMETERS: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y, - Z - point - -Result: - S(x,y,z) - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spline3dcalc(const_cast(c.c_ptr()), x, y, z, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant - AX, BX - transformation coefficients: x = A*u + B - AY, BY - transformation coefficients: y = A*v + B - AZ, BZ - transformation coefficients: z = A*w + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dlintransxyz(const_cast(c.c_ptr()), ax, bx, ay, by, az, bz, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dlintransf(const_cast(c.c_ptr()), a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Trilinear spline resampling - -INPUT PARAMETERS: - A - array[0..OldXCount*OldYCount*OldZCount-1], function - values at the old grid, : - A[0] x=0,y=0,z=0 - A[1] x=1,y=0,z=0 - A[..] ... - A[..] x=oldxcount-1,y=0,z=0 - A[..] x=0,y=1,z=0 - A[..] ... - ... - OldZCount - old Z-count, OldZCount>1 - OldYCount - old Y-count, OldYCount>1 - OldXCount - old X-count, OldXCount>1 - NewZCount - new Z-count, NewZCount>1 - NewYCount - new Y-count, NewYCount>1 - NewXCount - new X-count, NewXCount>1 - -OUTPUT PARAMETERS: - B - array[0..NewXCount*NewYCount*NewZCount-1], function - values at the new grid: - B[0] x=0,y=0,z=0 - B[1] x=1,y=0,z=0 - B[..] ... - B[..] x=newxcount-1,y=0,z=0 - B[..] x=0,y=1,z=0 - B[..] ... - ... - - -- ALGLIB routine -- - 26.04.2012 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dresampletrilinear(const_cast(a.c_ptr()), oldzcount, oldycount, oldxcount, newzcount, newycount, newxcount, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine builds trilinear vector-valued spline. - -INPUT PARAMETERS: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - Z - spline applicates, array[0..L-1] - F - function values, array[0..M*N*L*D-1]: - * first D elements store D values at (X[0],Y[0],Z[0]) - * next D elements store D values at (X[1],Y[0],Z[0]) - * next D elements store D values at (X[2],Y[0],Z[0]) - * ... - * next D elements store D values at (X[0],Y[1],Z[0]) - * next D elements store D values at (X[1],Y[1],Z[0]) - * next D elements store D values at (X[2],Y[1],Z[0]) - * ... - * next D elements store D values at (X[0],Y[0],Z[1]) - * next D elements store D values at (X[1],Y[0],Z[1]) - * next D elements store D values at (X[2],Y[0],Z[1]) - * ... - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. - M,N, - L - grid size, M>=2, N>=2, L>=2 - D - vector dimension, D>=1 - -OUTPUT PARAMETERS: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dbuildtrilinearv(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, const_cast(z.c_ptr()), l, const_cast(f.c_ptr()), d, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dcalcvbuf(const_cast(c.c_ptr()), x, y, z, const_cast(f.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine calculates trilinear or tricubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dcalcv(const_cast(c.c_ptr()), x, y, z, const_cast(f.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine unpacks tri-dimensional spline into the coefficients table - -INPUT PARAMETERS: - C - spline interpolant. - -Result: - N - grid size (X) - M - grid size (Y) - L - grid size (Z) - D - number of components - SType- spline type. Currently, only one spline type is supported: - trilinear spline, as indicated by SType=1. - Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index), K=0..L-2 (z index): - Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), - - Q-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[Q,0] = X[i] - Tbl[Q,1] = X[i+1] - Tbl[Q,2] = Y[j] - Tbl[Q,3] = Y[j+1] - Tbl[Q,4] = Z[k] - Tbl[Q,5] = Z[k+1] - - Tbl[Q,6] = C000 - Tbl[Q,7] = C100 - Tbl[Q,8] = C010 - Tbl[Q,9] = C110 - Tbl[Q,10]= C001 - Tbl[Q,11]= C101 - Tbl[Q,12]= C011 - Tbl[Q,13]= C111 - On each grid square spline is equals to: - S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) - t = x-x[j] - u = y-y[i] - v = z-z[k] - - NOTE: format of Tbl is given for SType=1. Future versions of - ALGLIB can use different formats for different values of - SType. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spline3dunpackv(const_cast(c.c_ptr()), &n, &m, &l, &d, &stype, const_cast(tbl.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static double idwint_idwqfactor = 1.5; -static ae_int_t idwint_idwkmin = 5; -static double idwint_idwcalcq(idwinterpolant* z, - /* Real */ ae_vector* x, - ae_int_t k, - ae_state *_state); -static void idwint_idwinit1(ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state); -static void idwint_idwinternalsolver(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_vector* temp, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* x, - double* taskrcond, - ae_state *_state); - - -static void ratint_barycentricnormalize(barycentricinterpolant* b, - ae_state *_state); - - - - -static void spline1d_spline1dgriddiffcubicinternal(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d, - /* Real */ ae_vector* a1, - /* Real */ ae_vector* a2, - /* Real */ ae_vector* a3, - /* Real */ ae_vector* b, - /* Real */ ae_vector* dt, - ae_state *_state); -static void spline1d_heapsortpoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -static void spline1d_heapsortppoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Integer */ ae_vector* p, - ae_int_t n, - ae_state *_state); -static void spline1d_solvetridiagonal(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - ae_int_t n, - /* Real */ ae_vector* x, - ae_state *_state); -static void spline1d_solvecyclictridiagonal(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - ae_int_t n, - /* Real */ ae_vector* x, - ae_state *_state); -static double spline1d_diffthreepoint(double t, - double x0, - double f0, - double x1, - double f1, - double x2, - double f2, - ae_state *_state); -static void spline1d_hermitecalc(double p0, - double m0, - double p1, - double m1, - double t, - double* s, - double* ds, - ae_state *_state); -static double spline1d_rescaleval(double a0, - double b0, - double a1, - double b1, - double t, - ae_state *_state); - - -static void lsfit_spline1dfitinternal(ae_int_t st, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -static void lsfit_lsfitlinearinternal(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -static void lsfit_lsfitclearrequestfields(lsfitstate* state, - ae_state *_state); -static void lsfit_barycentriccalcbasis(barycentricinterpolant* b, - double t, - /* Real */ ae_vector* y, - ae_state *_state); -static void lsfit_internalchebyshevfit(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -static void lsfit_barycentricfitwcfixedd(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t d, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state); -static void lsfit_clearreport(lsfitreport* rep, ae_state *_state); -static void lsfit_estimateerrors(/* Real */ ae_matrix* f1, - /* Real */ ae_vector* f0, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* x, - /* Real */ ae_vector* s, - ae_int_t n, - ae_int_t k, - lsfitreport* rep, - /* Real */ ae_matrix* z, - ae_int_t zkind, - ae_state *_state); - - -static void pspline_pspline2par(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t pt, - /* Real */ ae_vector* p, - ae_state *_state); -static void pspline_pspline3par(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t pt, - /* Real */ ae_vector* p, - ae_state *_state); - - -static double rbf_eps = 1.0E-6; -static ae_int_t rbf_mxnx = 3; -static double rbf_rbffarradius = 6; -static double rbf_rbfnearradius = 2.1; -static double rbf_rbfmlradius = 3; -static ae_int_t rbf_rbffirstversion = 0; -static void rbf_rbfgridpoints(rbfmodel* s, ae_state *_state); -static void rbf_rbfradnn(rbfmodel* s, - double q, - double z, - ae_state *_state); -static ae_bool rbf_buildlinearmodel(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t ny, - ae_int_t modeltype, - /* Real */ ae_matrix* v, - ae_state *_state); -static void rbf_buildrbfmodellsqr(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - /* Real */ ae_matrix* xc, - /* Real */ ae_vector* r, - ae_int_t n, - ae_int_t nc, - ae_int_t ny, - kdtree* pointstree, - kdtree* centerstree, - double epsort, - double epserr, - ae_int_t maxits, - ae_int_t* gnnz, - ae_int_t* snnz, - /* Real */ ae_matrix* w, - ae_int_t* info, - ae_int_t* iterationscount, - ae_int_t* nmv, - ae_state *_state); -static void rbf_buildrbfmlayersmodellsqr(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - /* Real */ ae_matrix* xc, - double rval, - /* Real */ ae_vector* r, - ae_int_t n, - ae_int_t* nc, - ae_int_t ny, - ae_int_t nlayers, - kdtree* centerstree, - double epsort, - double epserr, - ae_int_t maxits, - double lambdav, - ae_int_t* annz, - /* Real */ ae_matrix* w, - ae_int_t* info, - ae_int_t* iterationscount, - ae_int_t* nmv, - ae_state *_state); - - -static void spline2d_bicubiccalcderivatives(/* Real */ ae_matrix* a, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* dx, - /* Real */ ae_matrix* dy, - /* Real */ ae_matrix* dxy, - ae_state *_state); - - -static void spline3d_spline3ddiff(spline3dinterpolant* c, - double x, - double y, - double z, - double* f, - double* fx, - double* fy, - double* fxy, - ae_state *_state); - - - - - -/************************************************************************* -IDW interpolation - -INPUT PARAMETERS: - Z - IDW interpolant built with one of model building - subroutines. - X - array[0..NX-1], interpolation point - -Result: - IDW interpolant Z(X) - - -- ALGLIB -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -double idwcalc(idwinterpolant* z, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - double r; - double s; - double w; - double v1; - double v2; - double d0; - double di; - double result; - - - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - k = 0; - - /* - * Query - */ - if( z->modeltype==0 ) - { - - /* - * NQ/NW-based model - */ - k = kdtreequeryknn(&z->tree, x, z->nw, ae_true, _state); - kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); - kdtreequeryresultstags(&z->tree, &z->tbuf, _state); - } - if( z->modeltype==1 ) - { - - /* - * R-based model - */ - k = kdtreequeryrnn(&z->tree, x, z->r, ae_true, _state); - kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); - kdtreequeryresultstags(&z->tree, &z->tbuf, _state); - if( ktree, x, idwint_idwkmin, ae_true, _state); - kdtreequeryresultsdistances(&z->tree, &z->rbuf, _state); - kdtreequeryresultstags(&z->tree, &z->tbuf, _state); - } - } - - /* - * initialize weights for linear/quadratic members calculation. - * - * NOTE 1: weights are calculated using NORMALIZED modified - * Shepard's formula. Original formula gives w(i) = sqr((R-di)/(R*di)), - * where di is i-th distance, R is max(di). Modified formula have - * following form: - * w_mod(i) = 1, if di=d0 - * w_mod(i) = w(i)/w(0), if di<>d0 - * - * NOTE 2: self-match is USED for this query - * - * NOTE 3: last point almost always gain zero weight, but it MUST - * be used for fitting because sometimes it will gain NON-ZERO - * weight - for example, when all distances are equal. - */ - r = z->rbuf.ptr.p_double[k-1]; - d0 = z->rbuf.ptr.p_double[0]; - result = 0; - s = 0; - for(i=0; i<=k-1; i++) - { - di = z->rbuf.ptr.p_double[i]; - if( ae_fp_eq(di,d0) ) - { - - /* - * distance is equal to shortest, set it 1.0 - * without explicitly calculating (which would give - * us same result, but 'll expose us to the risk of - * division by zero). - */ - w = 1; - } - else - { - - /* - * use normalized formula - */ - v1 = (r-di)/(r-d0); - v2 = d0/di; - w = ae_sqr(v1*v2, _state); - } - result = result+w*idwint_idwcalcq(z, x, z->tbuf.ptr.p_int[i], _state); - s = s+w; - } - result = result/s; - return result; -} - - -/************************************************************************* -IDW interpolant using modified Shepard method for uniform point -distributions. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function type, either: - * 0 constant model. Just for demonstration only, worst - model ever. - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - * -1 "fast" linear model, use with caution!!! It is - significantly faster than linear/quadratic and better - than constant model. But it is less robust (especially - in the presence of noise). - NQ - number of points used to calculate nodal functions (ignored - for constant models). NQ should be LARGER than: - * max(1.5*(1+NX),2^NX+1) for linear model, - * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, worst - with constant - models - * when N is large, NQ and NW must be significantly smaller than N both - to obtain optimal performance and to obtain optimal accuracy. In 2 or - 3-dimensional tasks NQ=15 and NW=25 are good values to start with. - * NQ and NW may be greater than N. In such cases they will be - automatically decreased. - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - * this subroutine assumes that point distribution is uniform at the small - scales. If it isn't - for example, points are concentrated along - "lines", but "lines" distribution is uniform at the larger scale - then - you should use IDWBuildModifiedShepardR() - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepard(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t j2; - ae_int_t j3; - double v; - double r; - double s; - double d0; - double di; - double v1; - double v2; - ae_int_t nc; - ae_int_t offs; - ae_vector x; - ae_vector qrbuf; - ae_matrix qxybuf; - ae_vector y; - ae_matrix fmatrix; - ae_vector w; - ae_vector qsol; - ae_vector temp; - ae_vector tags; - ae_int_t info; - double taskrcond; - - ae_frame_make(_state, &_frame_block); - _idwinterpolant_clear(z); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&qrbuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&qxybuf, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&qsol, 0, DT_REAL, _state, ae_true); - ae_vector_init(&temp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tags, 0, DT_INT, _state, ae_true); - - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - nc = 0; - - /* - * assertions - */ - ae_assert(n>0, "IDWBuildModifiedShepard: N<=0!", _state); - ae_assert(nx>=1, "IDWBuildModifiedShepard: NX<1!", _state); - ae_assert(d>=-1&&d<=2, "IDWBuildModifiedShepard: D<>-1 and D<>0 and D<>1 and D<>2!", _state); - - /* - * Correct parameters if needed - */ - if( d==1 ) - { - nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(1+nx), _state)+1, _state); - nq = ae_maxint(nq, ae_round(ae_pow(2, nx, _state), _state)+1, _state); - } - if( d==2 ) - { - nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(nx+2)*(nx+1)/2, _state)+1, _state); - nq = ae_maxint(nq, ae_round(ae_pow(2, nx, _state), _state)+1, _state); - } - nw = ae_maxint(nw, ae_round(ae_pow(2, nx, _state), _state)+1, _state); - nq = ae_minint(nq, n, _state); - nw = ae_minint(nw, n, _state); - - /* - * primary initialization of Z - */ - idwint_idwinit1(n, nx, d, nq, nw, z, _state); - z->modeltype = 0; - - /* - * Create KD-tree - */ - ae_vector_set_length(&tags, n, _state); - for(i=0; i<=n-1; i++) - { - tags.ptr.p_int[i] = i; - } - kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); - - /* - * build nodal functions - */ - ae_vector_set_length(&temp, nq+1, _state); - ae_vector_set_length(&x, nx, _state); - ae_vector_set_length(&qrbuf, nq, _state); - ae_matrix_set_length(&qxybuf, nq, nx+1, _state); - if( d==-1 ) - { - ae_vector_set_length(&w, nq, _state); - } - if( d==1 ) - { - ae_vector_set_length(&y, nq, _state); - ae_vector_set_length(&w, nq, _state); - ae_vector_set_length(&qsol, nx, _state); - - /* - * NX for linear members, - * 1 for temporary storage - */ - ae_matrix_set_length(&fmatrix, nq, nx+1, _state); - } - if( d==2 ) - { - ae_vector_set_length(&y, nq, _state); - ae_vector_set_length(&w, nq, _state); - ae_vector_set_length(&qsol, nx+ae_round(nx*(nx+1)*0.5, _state), _state); - - /* - * NX for linear members, - * Round(NX*(NX+1)*0.5) for quadratic model, - * 1 for temporary storage - */ - ae_matrix_set_length(&fmatrix, nq, nx+ae_round(nx*(nx+1)*0.5, _state)+1, _state); - } - for(i=0; i<=n-1; i++) - { - - /* - * Initialize center and function value. - * If D=0 it is all what we need - */ - ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx)); - if( d==0 ) - { - continue; - } - - /* - * calculate weights for linear/quadratic members calculation. - * - * NOTE 1: weights are calculated using NORMALIZED modified - * Shepard's formula. Original formula is w(i) = sqr((R-di)/(R*di)), - * where di is i-th distance, R is max(di). Modified formula have - * following form: - * w_mod(i) = 1, if di=d0 - * w_mod(i) = w(i)/w(0), if di<>d0 - * - * NOTE 2: self-match is NOT used for this query - * - * NOTE 3: last point almost always gain zero weight, but it MUST - * be used for fitting because sometimes it will gain NON-ZERO - * weight - for example, when all distances are equal. - */ - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); - k = kdtreequeryknn(&z->tree, &x, nq, ae_false, _state); - kdtreequeryresultsxy(&z->tree, &qxybuf, _state); - kdtreequeryresultsdistances(&z->tree, &qrbuf, _state); - r = qrbuf.ptr.p_double[k-1]; - d0 = qrbuf.ptr.p_double[0]; - for(j=0; j<=k-1; j++) - { - di = qrbuf.ptr.p_double[j]; - if( ae_fp_eq(di,d0) ) - { - - /* - * distance is equal to shortest, set it 1.0 - * without explicitly calculating (which would give - * us same result, but 'll expose us to the risk of - * division by zero). - */ - w.ptr.p_double[j] = 1; - } - else - { - - /* - * use normalized formula - */ - v1 = (r-di)/(r-d0); - v2 = d0/di; - w.ptr.p_double[j] = ae_sqr(v1*v2, _state); - } - } - - /* - * calculate linear/quadratic members - */ - if( d==-1 ) - { - - /* - * "Fast" linear nodal function calculated using - * inverse distance weighting - */ - for(j=0; j<=nx-1; j++) - { - x.ptr.p_double[j] = 0; - } - s = 0; - for(j=0; j<=k-1; j++) - { - - /* - * calculate J-th inverse distance weighted gradient: - * grad_k = (y_j-y_k)*(x_j-x_k)/sqr(norm(x_j-x_k)) - * grad = sum(wk*grad_k)/sum(w_k) - */ - v = 0; - for(j2=0; j2<=nx-1; j2++) - { - v = v+ae_sqr(qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2], _state); - } - - /* - * Although x_j<>x_k, sqr(norm(x_j-x_k)) may be zero due to - * underflow. If it is, we assume than J-th gradient is zero - * (i.e. don't add anything) - */ - if( ae_fp_neq(v,0) ) - { - for(j2=0; j2<=nx-1; j2++) - { - x.ptr.p_double[j2] = x.ptr.p_double[j2]+w.ptr.p_double[j]*(qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx])*(qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])/v; - } - } - s = s+w.ptr.p_double[j]; - } - for(j=0; j<=nx-1; j++) - { - z->q.ptr.pp_double[i][nx+1+j] = x.ptr.p_double[j]/s; - } - } - else - { - - /* - * Least squares models: build - */ - if( d==1 ) - { - - /* - * Linear nodal function calculated using - * least squares fitting to its neighbors - */ - for(j=0; j<=k-1; j++) - { - for(j2=0; j2<=nx-1; j2++) - { - fmatrix.ptr.pp_double[j][j2] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; - } - y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx]; - } - nc = nx; - } - if( d==2 ) - { - - /* - * Quadratic nodal function calculated using - * least squares fitting to its neighbors - */ - for(j=0; j<=k-1; j++) - { - offs = 0; - for(j2=0; j2<=nx-1; j2++) - { - fmatrix.ptr.pp_double[j][offs] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; - offs = offs+1; - } - for(j2=0; j2<=nx-1; j2++) - { - for(j3=j2; j3<=nx-1; j3++) - { - fmatrix.ptr.pp_double[j][offs] = (qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])*(qxybuf.ptr.pp_double[j][j3]-xy->ptr.pp_double[i][j3]); - offs = offs+1; - } - } - y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]-xy->ptr.pp_double[i][nx]; - } - nc = nx+ae_round(nx*(nx+1)*0.5, _state); - } - idwint_idwinternalsolver(&y, &w, &fmatrix, &temp, k, nc, &info, &qsol, &taskrcond, _state); - - /* - * Least squares models: copy results - */ - if( info>0 ) - { - - /* - * LLS task is solved, copy results - */ - z->debugworstrcond = ae_minreal(z->debugworstrcond, taskrcond, _state); - z->debugbestrcond = ae_maxreal(z->debugbestrcond, taskrcond, _state); - for(j=0; j<=nc-1; j++) - { - z->q.ptr.pp_double[i][nx+1+j] = qsol.ptr.p_double[j]; - } - } - else - { - - /* - * Solver failure, very strange, but we will use - * zero values to handle it. - */ - z->debugsolverfailures = z->debugsolverfailures+1; - for(j=0; j<=nc-1; j++) - { - z->q.ptr.pp_double[i][nx+1+j] = 0; - } - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -IDW interpolant using modified Shepard method for non-uniform datasets. - -This type of model uses constant nodal functions and interpolates using -all nodes which are closer than user-specified radius R. It may be used -when points distribution is non-uniform at the small scale, but it is at -the distances as large as R. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - R - radius, R>0 - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: -* if there is less than IDWKMin points within R-ball, algorithm selects - IDWKMin closest ones, so that continuity properties of interpolant are - preserved even far from points. - - -- ALGLIB PROJECT -- - Copyright 11.04.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepardr(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - double r, - idwinterpolant* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector tags; - - ae_frame_make(_state, &_frame_block); - _idwinterpolant_clear(z); - ae_vector_init(&tags, 0, DT_INT, _state, ae_true); - - - /* - * assertions - */ - ae_assert(n>0, "IDWBuildModifiedShepardR: N<=0!", _state); - ae_assert(nx>=1, "IDWBuildModifiedShepardR: NX<1!", _state); - ae_assert(ae_fp_greater(r,0), "IDWBuildModifiedShepardR: R<=0!", _state); - - /* - * primary initialization of Z - */ - idwint_idwinit1(n, nx, 0, 0, n, z, _state); - z->modeltype = 1; - z->r = r; - - /* - * Create KD-tree - */ - ae_vector_set_length(&tags, n, _state); - for(i=0; i<=n-1; i++) - { - tags.ptr.p_int[i] = i; - } - kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); - - /* - * build nodal functions - */ - for(i=0; i<=n-1; i++) - { - ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -IDW model for noisy data. - -This subroutine may be used to handle noisy data, i.e. data with noise in -OUTPUT values. It differs from IDWBuildModifiedShepard() in the following -aspects: -* nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, - i.e. we have fitting instead of interpolation. -* weights which are used during least squares fitting stage are all equal - to 1.0 (independently of distance) -* "fast"-linear or constant nodal functions are not supported (either not - robust enough or too rigid) - -This problem require far more complex tuning than interpolation problems. -Below you can find some recommendations regarding this problem: -* focus on tuning NQ; it controls noise reduction. As for NW, you can just - make it equal to 2*NQ. -* you can use cross-validation to determine optimal NQ. -* optimal NQ is a result of complex tradeoff between noise level (more - noise = larger NQ required) and underlying function complexity (given - fixed N, larger NQ means smoothing of compex features in the data). For - example, NQ=N will reduce noise to the minimum level possible, but you - will end up with just constant/linear/quadratic (depending on D) least - squares model for the whole dataset. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function degree, either: - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models (or for very - noisy problems). - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - NQ - number of points used to calculate nodal functions. NQ should - be significantly larger than 1.5 times the number of - coefficients in a nodal function to overcome effects of noise: - * larger than 1.5*(1+NX) for linear model, - * larger than 3/4*(NX+2)*(NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ or larger - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, linear models are not - recommended to use unless you are pretty sure that it is what you want - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildnoisy(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t j2; - ae_int_t j3; - double v; - ae_int_t nc; - ae_int_t offs; - double taskrcond; - ae_vector x; - ae_vector qrbuf; - ae_matrix qxybuf; - ae_vector y; - ae_vector w; - ae_matrix fmatrix; - ae_vector qsol; - ae_vector tags; - ae_vector temp; - ae_int_t info; - - ae_frame_make(_state, &_frame_block); - _idwinterpolant_clear(z); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&qrbuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&qxybuf, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&qsol, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tags, 0, DT_INT, _state, ae_true); - ae_vector_init(&temp, 0, DT_REAL, _state, ae_true); - - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - nc = 0; - - /* - * assertions - */ - ae_assert(n>0, "IDWBuildNoisy: N<=0!", _state); - ae_assert(nx>=1, "IDWBuildNoisy: NX<1!", _state); - ae_assert(d>=1&&d<=2, "IDWBuildNoisy: D<>1 and D<>2!", _state); - - /* - * Correct parameters if needed - */ - if( d==1 ) - { - nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(1+nx), _state)+1, _state); - } - if( d==2 ) - { - nq = ae_maxint(nq, ae_iceil(idwint_idwqfactor*(nx+2)*(nx+1)/2, _state)+1, _state); - } - nw = ae_maxint(nw, ae_round(ae_pow(2, nx, _state), _state)+1, _state); - nq = ae_minint(nq, n, _state); - nw = ae_minint(nw, n, _state); - - /* - * primary initialization of Z - */ - idwint_idwinit1(n, nx, d, nq, nw, z, _state); - z->modeltype = 0; - - /* - * Create KD-tree - */ - ae_vector_set_length(&tags, n, _state); - for(i=0; i<=n-1; i++) - { - tags.ptr.p_int[i] = i; - } - kdtreebuildtagged(xy, &tags, n, nx, 1, 2, &z->tree, _state); - - /* - * build nodal functions - * (special algorithm for noisy data is used) - */ - ae_vector_set_length(&temp, nq+1, _state); - ae_vector_set_length(&x, nx, _state); - ae_vector_set_length(&qrbuf, nq, _state); - ae_matrix_set_length(&qxybuf, nq, nx+1, _state); - if( d==1 ) - { - ae_vector_set_length(&y, nq, _state); - ae_vector_set_length(&w, nq, _state); - ae_vector_set_length(&qsol, 1+nx, _state); - - /* - * 1 for constant member, - * NX for linear members, - * 1 for temporary storage - */ - ae_matrix_set_length(&fmatrix, nq, 1+nx+1, _state); - } - if( d==2 ) - { - ae_vector_set_length(&y, nq, _state); - ae_vector_set_length(&w, nq, _state); - ae_vector_set_length(&qsol, 1+nx+ae_round(nx*(nx+1)*0.5, _state), _state); - - /* - * 1 for constant member, - * NX for linear members, - * Round(NX*(NX+1)*0.5) for quadratic model, - * 1 for temporary storage - */ - ae_matrix_set_length(&fmatrix, nq, 1+nx+ae_round(nx*(nx+1)*0.5, _state)+1, _state); - } - for(i=0; i<=n-1; i++) - { - - /* - * Initialize center. - */ - ae_v_move(&z->q.ptr.pp_double[i][0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); - - /* - * Calculate linear/quadratic members - * using least squares fit - * NOTE 1: all weight are equal to 1.0 - * NOTE 2: self-match is USED for this query - */ - ae_v_move(&x.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nx-1)); - k = kdtreequeryknn(&z->tree, &x, nq, ae_true, _state); - kdtreequeryresultsxy(&z->tree, &qxybuf, _state); - kdtreequeryresultsdistances(&z->tree, &qrbuf, _state); - if( d==1 ) - { - - /* - * Linear nodal function calculated using - * least squares fitting to its neighbors - */ - for(j=0; j<=k-1; j++) - { - fmatrix.ptr.pp_double[j][0] = 1.0; - for(j2=0; j2<=nx-1; j2++) - { - fmatrix.ptr.pp_double[j][1+j2] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; - } - y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]; - w.ptr.p_double[j] = 1; - } - nc = 1+nx; - } - if( d==2 ) - { - - /* - * Quadratic nodal function calculated using - * least squares fitting to its neighbors - */ - for(j=0; j<=k-1; j++) - { - fmatrix.ptr.pp_double[j][0] = 1; - offs = 1; - for(j2=0; j2<=nx-1; j2++) - { - fmatrix.ptr.pp_double[j][offs] = qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2]; - offs = offs+1; - } - for(j2=0; j2<=nx-1; j2++) - { - for(j3=j2; j3<=nx-1; j3++) - { - fmatrix.ptr.pp_double[j][offs] = (qxybuf.ptr.pp_double[j][j2]-xy->ptr.pp_double[i][j2])*(qxybuf.ptr.pp_double[j][j3]-xy->ptr.pp_double[i][j3]); - offs = offs+1; - } - } - y.ptr.p_double[j] = qxybuf.ptr.pp_double[j][nx]; - w.ptr.p_double[j] = 1; - } - nc = 1+nx+ae_round(nx*(nx+1)*0.5, _state); - } - idwint_idwinternalsolver(&y, &w, &fmatrix, &temp, k, nc, &info, &qsol, &taskrcond, _state); - - /* - * Least squares models: copy results - */ - if( info>0 ) - { - - /* - * LLS task is solved, copy results - */ - z->debugworstrcond = ae_minreal(z->debugworstrcond, taskrcond, _state); - z->debugbestrcond = ae_maxreal(z->debugbestrcond, taskrcond, _state); - for(j=0; j<=nc-1; j++) - { - z->q.ptr.pp_double[i][nx+j] = qsol.ptr.p_double[j]; - } - } - else - { - - /* - * Solver failure, very strange, but we will use - * zero values to handle it. - */ - z->debugsolverfailures = z->debugsolverfailures+1; - v = 0; - for(j=0; j<=k-1; j++) - { - v = v+qxybuf.ptr.pp_double[j][nx]; - } - z->q.ptr.pp_double[i][nx] = v/k; - for(j=0; j<=nc-2; j++) - { - z->q.ptr.pp_double[i][nx+1+j] = 0; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine: K-th nodal function calculation - - -- ALGLIB -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -static double idwint_idwcalcq(idwinterpolant* z, - /* Real */ ae_vector* x, - ae_int_t k, - ae_state *_state) -{ - ae_int_t nx; - ae_int_t i; - ae_int_t j; - ae_int_t offs; - double result; - - - nx = z->nx; - - /* - * constant member - */ - result = z->q.ptr.pp_double[k][nx]; - - /* - * linear members - */ - if( z->d>=1 ) - { - for(i=0; i<=nx-1; i++) - { - result = result+z->q.ptr.pp_double[k][nx+1+i]*(x->ptr.p_double[i]-z->q.ptr.pp_double[k][i]); - } - } - - /* - * quadratic members - */ - if( z->d>=2 ) - { - offs = nx+1+nx; - for(i=0; i<=nx-1; i++) - { - for(j=i; j<=nx-1; j++) - { - result = result+z->q.ptr.pp_double[k][offs]*(x->ptr.p_double[i]-z->q.ptr.pp_double[k][i])*(x->ptr.p_double[j]-z->q.ptr.pp_double[k][j]); - offs = offs+1; - } - } - } - return result; -} - - -/************************************************************************* -Initialization of internal structures. - -It assumes correctness of all parameters. - - -- ALGLIB -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -static void idwint_idwinit1(ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state) -{ - - - z->debugsolverfailures = 0; - z->debugworstrcond = 1.0; - z->debugbestrcond = 0; - z->n = n; - z->nx = nx; - z->d = 0; - if( d==1 ) - { - z->d = 1; - } - if( d==2 ) - { - z->d = 2; - } - if( d==-1 ) - { - z->d = 1; - } - z->nw = nw; - if( d==-1 ) - { - ae_matrix_set_length(&z->q, n, nx+1+nx, _state); - } - if( d==0 ) - { - ae_matrix_set_length(&z->q, n, nx+1, _state); - } - if( d==1 ) - { - ae_matrix_set_length(&z->q, n, nx+1+nx, _state); - } - if( d==2 ) - { - ae_matrix_set_length(&z->q, n, nx+1+nx+ae_round(nx*(nx+1)*0.5, _state), _state); - } - ae_vector_set_length(&z->tbuf, nw, _state); - ae_vector_set_length(&z->rbuf, nw, _state); - ae_matrix_set_length(&z->xybuf, nw, nx+1, _state); - ae_vector_set_length(&z->xbuf, nx, _state); -} - - -/************************************************************************* -Linear least squares solver for small tasks. - -Works faster than standard ALGLIB solver in non-degenerate cases (due to -absence of internal allocations and optimized row/colums). In degenerate -cases it calls standard solver, which results in small performance penalty -associated with preliminary steps. - -INPUT PARAMETERS: - Y array[0..N-1] - W array[0..N-1] - FMatrix array[0..N-1,0..M], have additional column for temporary - values - Temp array[0..N] -*************************************************************************/ -static void idwint_idwinternalsolver(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_vector* temp, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* x, - double* taskrcond, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double tau; - ae_vector b; - densesolverlsreport srep; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - _densesolverlsreport_init(&srep, _state, ae_true); - - - /* - * set up info - */ - *info = 1; - - /* - * prepare matrix - */ - for(i=0; i<=n-1; i++) - { - fmatrix->ptr.pp_double[i][m] = y->ptr.p_double[i]; - v = w->ptr.p_double[i]; - ae_v_muld(&fmatrix->ptr.pp_double[i][0], 1, ae_v_len(0,m), v); - } - - /* - * use either fast algorithm or general algorithm - */ - if( m<=n ) - { - - /* - * QR decomposition - * We assume that M<=N (we would have called LSFit() otherwise) - */ - for(i=0; i<=m-1; i++) - { - if( iptr.p_double[1], 1, &fmatrix->ptr.pp_double[i][i], fmatrix->stride, ae_v_len(1,n-i)); - generatereflection(temp, n-i, &tau, _state); - fmatrix->ptr.pp_double[i][i] = temp->ptr.p_double[1]; - temp->ptr.p_double[1] = 1; - for(j=i+1; j<=m; j++) - { - v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][j], fmatrix->stride, &temp->ptr.p_double[1], 1, ae_v_len(i,n-1)); - v = tau*v; - ae_v_subd(&fmatrix->ptr.pp_double[i][j], fmatrix->stride, &temp->ptr.p_double[1], 1, ae_v_len(i,n-1), v); - } - } - } - - /* - * Check condition number - */ - *taskrcond = rmatrixtrrcondinf(fmatrix, m, ae_true, ae_false, _state); - - /* - * use either fast algorithm for non-degenerate cases - * or slow algorithm for degenerate cases - */ - if( ae_fp_greater(*taskrcond,10000*n*ae_machineepsilon) ) - { - - /* - * solve triangular system R*x = FMatrix[0:M-1,M] - * using fast algorithm, then exit - */ - x->ptr.p_double[m-1] = fmatrix->ptr.pp_double[m-1][m]/fmatrix->ptr.pp_double[m-1][m-1]; - for(i=m-2; i>=0; i--) - { - v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][i+1], 1, &x->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1)); - x->ptr.p_double[i] = (fmatrix->ptr.pp_double[i][m]-v)/fmatrix->ptr.pp_double[i][i]; - } - } - else - { - - /* - * use more general algorithm - */ - ae_vector_set_length(&b, m, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=i-1; j++) - { - fmatrix->ptr.pp_double[i][j] = 0.0; - } - b.ptr.p_double[i] = fmatrix->ptr.pp_double[i][m]; - } - rmatrixsolvels(fmatrix, m, m, &b, 10000*ae_machineepsilon, info, &srep, x, _state); - } - } - else - { - - /* - * use more general algorithm - */ - ae_vector_set_length(&b, n, _state); - for(i=0; i<=n-1; i++) - { - b.ptr.p_double[i] = fmatrix->ptr.pp_double[i][m]; - } - rmatrixsolvels(fmatrix, n, m, &b, 10000*ae_machineepsilon, info, &srep, x, _state); - *taskrcond = srep.r2; - } - ae_frame_leave(_state); -} - - -ae_bool _idwinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - idwinterpolant *p = (idwinterpolant*)_p; - ae_touch_ptr((void*)p); - if( !_kdtree_init(&p->tree, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tbuf, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->xybuf, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _idwinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - idwinterpolant *dst = (idwinterpolant*)_dst; - idwinterpolant *src = (idwinterpolant*)_src; - dst->n = src->n; - dst->nx = src->nx; - dst->d = src->d; - dst->r = src->r; - dst->nw = src->nw; - if( !_kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic) ) - return ae_false; - dst->modeltype = src->modeltype; - if( !ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xbuf, &src->xbuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tbuf, &src->tbuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rbuf, &src->rbuf, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->xybuf, &src->xybuf, _state, make_automatic) ) - return ae_false; - dst->debugsolverfailures = src->debugsolverfailures; - dst->debugworstrcond = src->debugworstrcond; - dst->debugbestrcond = src->debugbestrcond; - return ae_true; -} - - -void _idwinterpolant_clear(void* _p) -{ - idwinterpolant *p = (idwinterpolant*)_p; - ae_touch_ptr((void*)p); - _kdtree_clear(&p->tree); - ae_matrix_clear(&p->q); - ae_vector_clear(&p->xbuf); - ae_vector_clear(&p->tbuf); - ae_vector_clear(&p->rbuf); - ae_matrix_clear(&p->xybuf); -} - - -void _idwinterpolant_destroy(void* _p) -{ - idwinterpolant *p = (idwinterpolant*)_p; - ae_touch_ptr((void*)p); - _kdtree_destroy(&p->tree); - ae_matrix_destroy(&p->q); - ae_vector_destroy(&p->xbuf); - ae_vector_destroy(&p->tbuf); - ae_vector_destroy(&p->rbuf); - ae_matrix_destroy(&p->xybuf); -} - - - - -/************************************************************************* -Rational interpolation using barycentric formula - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -Input parameters: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -Result: - barycentric interpolant F(t) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -double barycentriccalc(barycentricinterpolant* b, - double t, - ae_state *_state) -{ - double s1; - double s2; - double s; - double v; - ae_int_t i; - double result; - - - ae_assert(!ae_isinf(t, _state), "BarycentricCalc: infinite T!", _state); - - /* - * special case: NaN - */ - if( ae_isnan(t, _state) ) - { - result = _state->v_nan; - return result; - } - - /* - * special case: N=1 - */ - if( b->n==1 ) - { - result = b->sy*b->y.ptr.p_double[0]; - return result; - } - - /* - * Here we assume that task is normalized, i.e.: - * 1. abs(Y[i])<=1 - * 2. abs(W[i])<=1 - * 3. X[] is ordered - */ - s = ae_fabs(t-b->x.ptr.p_double[0], _state); - for(i=0; i<=b->n-1; i++) - { - v = b->x.ptr.p_double[i]; - if( ae_fp_eq(v,t) ) - { - result = b->sy*b->y.ptr.p_double[i]; - return result; - } - v = ae_fabs(t-v, _state); - if( ae_fp_less(v,s) ) - { - s = v; - } - } - s1 = 0; - s2 = 0; - for(i=0; i<=b->n-1; i++) - { - v = s/(t-b->x.ptr.p_double[i]); - v = v*b->w.ptr.p_double[i]; - s1 = s1+v*b->y.ptr.p_double[i]; - s2 = s2+v; - } - result = b->sy*s1/s2; - return result; -} - - -/************************************************************************* -Differentiation of barycentric interpolant: first derivative. - -Algorithm used in this subroutine is very robust and should not fail until -provided with values too close to MaxRealNumber (usually MaxRealNumber/N -or greater will overflow). - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - -NOTE - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff1(barycentricinterpolant* b, - double t, - double* f, - double* df, - ae_state *_state) -{ - double v; - double vv; - ae_int_t i; - ae_int_t k; - double n0; - double n1; - double d0; - double d1; - double s0; - double s1; - double xk; - double xi; - double xmin; - double xmax; - double xscale1; - double xoffs1; - double xscale2; - double xoffs2; - double xprev; - - *f = 0; - *df = 0; - - ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); - - /* - * special case: NaN - */ - if( ae_isnan(t, _state) ) - { - *f = _state->v_nan; - *df = _state->v_nan; - return; - } - - /* - * special case: N=1 - */ - if( b->n==1 ) - { - *f = b->sy*b->y.ptr.p_double[0]; - *df = 0; - return; - } - if( ae_fp_eq(b->sy,0) ) - { - *f = 0; - *df = 0; - return; - } - ae_assert(ae_fp_greater(b->sy,0), "BarycentricDiff1: internal error", _state); - - /* - * We assume than N>1 and B.SY>0. Find: - * 1. pivot point (X[i] closest to T) - * 2. width of interval containing X[i] - */ - v = ae_fabs(b->x.ptr.p_double[0]-t, _state); - k = 0; - xmin = b->x.ptr.p_double[0]; - xmax = b->x.ptr.p_double[0]; - for(i=1; i<=b->n-1; i++) - { - vv = b->x.ptr.p_double[i]; - if( ae_fp_less(ae_fabs(vv-t, _state),v) ) - { - v = ae_fabs(vv-t, _state); - k = i; - } - xmin = ae_minreal(xmin, vv, _state); - xmax = ae_maxreal(xmax, vv, _state); - } - - /* - * pivot point found, calculate dNumerator and dDenominator - */ - xscale1 = 1/(xmax-xmin); - xoffs1 = -xmin/(xmax-xmin)+1; - xscale2 = 2; - xoffs2 = -3; - t = t*xscale1+xoffs1; - t = t*xscale2+xoffs2; - xk = b->x.ptr.p_double[k]; - xk = xk*xscale1+xoffs1; - xk = xk*xscale2+xoffs2; - v = t-xk; - n0 = 0; - n1 = 0; - d0 = 0; - d1 = 0; - xprev = -2; - for(i=0; i<=b->n-1; i++) - { - xi = b->x.ptr.p_double[i]; - xi = xi*xscale1+xoffs1; - xi = xi*xscale2+xoffs2; - ae_assert(ae_fp_greater(xi,xprev), "BarycentricDiff1: points are too close!", _state); - xprev = xi; - if( i!=k ) - { - vv = ae_sqr(t-xi, _state); - s0 = (t-xk)/(t-xi); - s1 = (xk-xi)/vv; - } - else - { - s0 = 1; - s1 = 0; - } - vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; - n0 = n0+s0*vv; - n1 = n1+s1*vv; - vv = b->w.ptr.p_double[i]; - d0 = d0+s0*vv; - d1 = d1+s1*vv; - } - *f = b->sy*n0/d0; - *df = (n1*d0-n0*d1)/ae_sqr(d0, _state); - if( ae_fp_neq(*df,0) ) - { - *df = ae_sign(*df, _state)*ae_exp(ae_log(ae_fabs(*df, _state), _state)+ae_log(b->sy, _state)+ae_log(xscale1, _state)+ae_log(xscale2, _state), _state); - } -} - - -/************************************************************************* -Differentiation of barycentric interpolant: first/second derivatives. - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - D2F - second derivative - -NOTE: this algorithm may fail due to overflow/underflor if used on data -whose values are close to MaxRealNumber or MinRealNumber. Use more robust -BarycentricDiff1() subroutine in such cases. - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff2(barycentricinterpolant* b, - double t, - double* f, - double* df, - double* d2f, - ae_state *_state) -{ - double v; - double vv; - ae_int_t i; - ae_int_t k; - double n0; - double n1; - double n2; - double d0; - double d1; - double d2; - double s0; - double s1; - double s2; - double xk; - double xi; - - *f = 0; - *df = 0; - *d2f = 0; - - ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); - - /* - * special case: NaN - */ - if( ae_isnan(t, _state) ) - { - *f = _state->v_nan; - *df = _state->v_nan; - *d2f = _state->v_nan; - return; - } - - /* - * special case: N=1 - */ - if( b->n==1 ) - { - *f = b->sy*b->y.ptr.p_double[0]; - *df = 0; - *d2f = 0; - return; - } - if( ae_fp_eq(b->sy,0) ) - { - *f = 0; - *df = 0; - *d2f = 0; - return; - } - - /* - * We assume than N>1 and B.SY>0. Find: - * 1. pivot point (X[i] closest to T) - * 2. width of interval containing X[i] - */ - ae_assert(ae_fp_greater(b->sy,0), "BarycentricDiff: internal error", _state); - *f = 0; - *df = 0; - *d2f = 0; - v = ae_fabs(b->x.ptr.p_double[0]-t, _state); - k = 0; - for(i=1; i<=b->n-1; i++) - { - vv = b->x.ptr.p_double[i]; - if( ae_fp_less(ae_fabs(vv-t, _state),v) ) - { - v = ae_fabs(vv-t, _state); - k = i; - } - } - - /* - * pivot point found, calculate dNumerator and dDenominator - */ - xk = b->x.ptr.p_double[k]; - v = t-xk; - n0 = 0; - n1 = 0; - n2 = 0; - d0 = 0; - d1 = 0; - d2 = 0; - for(i=0; i<=b->n-1; i++) - { - if( i!=k ) - { - xi = b->x.ptr.p_double[i]; - vv = ae_sqr(t-xi, _state); - s0 = (t-xk)/(t-xi); - s1 = (xk-xi)/vv; - s2 = -2*(xk-xi)/(vv*(t-xi)); - } - else - { - s0 = 1; - s1 = 0; - s2 = 0; - } - vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; - n0 = n0+s0*vv; - n1 = n1+s1*vv; - n2 = n2+s2*vv; - vv = b->w.ptr.p_double[i]; - d0 = d0+s0*vv; - d1 = d1+s1*vv; - d2 = d2+s2*vv; - } - *f = b->sy*n0/d0; - *df = b->sy*(n1*d0-n0*d1)/ae_sqr(d0, _state); - *d2f = b->sy*((n2*d0-n0*d2)*ae_sqr(d0, _state)-(n1*d0-n0*d1)*2*d0*d1)/ae_sqr(ae_sqr(d0, _state), _state); -} - - -/************************************************************************* -This subroutine performs linear transformation of the argument. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: x = CA*t + CB - -OUTPUT PARAMETERS: - B - transformed interpolant with X replaced by T - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransx(barycentricinterpolant* b, - double ca, - double cb, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - - - - /* - * special case, replace by constant F(CB) - */ - if( ae_fp_eq(ca,0) ) - { - b->sy = barycentriccalc(b, cb, _state); - v = 1; - for(i=0; i<=b->n-1; i++) - { - b->y.ptr.p_double[i] = 1; - b->w.ptr.p_double[i] = v; - v = -v; - } - return; - } - - /* - * general case: CA<>0 - */ - for(i=0; i<=b->n-1; i++) - { - b->x.ptr.p_double[i] = (b->x.ptr.p_double[i]-cb)/ca; - } - if( ae_fp_less(ca,0) ) - { - for(i=0; i<=b->n-1; i++) - { - if( in-1-i ) - { - j = b->n-1-i; - v = b->x.ptr.p_double[i]; - b->x.ptr.p_double[i] = b->x.ptr.p_double[j]; - b->x.ptr.p_double[j] = v; - v = b->y.ptr.p_double[i]; - b->y.ptr.p_double[i] = b->y.ptr.p_double[j]; - b->y.ptr.p_double[j] = v; - v = b->w.ptr.p_double[i]; - b->w.ptr.p_double[i] = b->w.ptr.p_double[j]; - b->w.ptr.p_double[j] = v; - } - else - { - break; - } - } - } -} - - -/************************************************************************* -This subroutine performs linear transformation of the barycentric -interpolant. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB - -OUTPUT PARAMETERS: - B - transformed interpolant - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransy(barycentricinterpolant* b, - double ca, - double cb, - ae_state *_state) -{ - ae_int_t i; - double v; - - - for(i=0; i<=b->n-1; i++) - { - b->y.ptr.p_double[i] = ca*b->sy*b->y.ptr.p_double[i]+cb; - } - b->sy = 0; - for(i=0; i<=b->n-1; i++) - { - b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); - } - if( ae_fp_greater(b->sy,0) ) - { - v = 1/b->sy; - ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); - } -} - - -/************************************************************************* -Extracts X/Y/W arrays from rational interpolant - -INPUT PARAMETERS: - B - barycentric interpolant - -OUTPUT PARAMETERS: - N - nodes count, N>0 - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricunpack(barycentricinterpolant* b, - ae_int_t* n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_state *_state) -{ - double v; - - *n = 0; - ae_vector_clear(x); - ae_vector_clear(y); - ae_vector_clear(w); - - *n = b->n; - ae_vector_set_length(x, *n, _state); - ae_vector_set_length(y, *n, _state); - ae_vector_set_length(w, *n, _state); - v = b->sy; - ae_v_move(&x->ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,*n-1)); - ae_v_moved(&y->ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,*n-1), v); - ae_v_move(&w->ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,*n-1)); -} - - -/************************************************************************* -Rational interpolant from X/Y/W arrays - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -INPUT PARAMETERS: - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - N - nodes count, N>0 - -OUTPUT PARAMETERS: - B - barycentric interpolant built from (X, Y, W) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildxyw(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - barycentricinterpolant* b, - ae_state *_state) -{ - - _barycentricinterpolant_clear(b); - - ae_assert(n>0, "BarycentricBuildXYW: incorrect N!", _state); - - /* - * fill X/Y/W - */ - ae_vector_set_length(&b->x, n, _state); - ae_vector_set_length(&b->y, n, _state); - ae_vector_set_length(&b->w, n, _state); - ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&b->w.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - b->n = n; - - /* - * Normalize - */ - ratint_barycentricnormalize(b, _state); -} - - -/************************************************************************* -Rational interpolant without poles - -The subroutine constructs the rational interpolating function without real -poles (see 'Barycentric rational interpolation with no poles and high -rates of approximation', Michael S. Floater. and Kai Hormann, for more -information on this subject). - -Input parameters: - X - interpolation nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of nodes, N>0. - D - order of the interpolation scheme, 0 <= D <= N-1. - D<0 will cause an error. - D>=N it will be replaced with D=N-1. - if you don't know what D to choose, use small value about 3-5. - -Output parameters: - B - barycentric interpolant. - -Note: - this algorithm always succeeds and calculates the weights with close - to machine precision. - - -- ALGLIB PROJECT -- - Copyright 17.06.2007 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildfloaterhormann(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t d, - barycentricinterpolant* b, - ae_state *_state) -{ - ae_frame _frame_block; - double s0; - double s; - double v; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_vector perm; - ae_vector wtemp; - ae_vector sortrbuf; - ae_vector sortrbuf2; - - ae_frame_make(_state, &_frame_block); - _barycentricinterpolant_clear(b); - ae_vector_init(&perm, 0, DT_INT, _state, ae_true); - ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "BarycentricFloaterHormann: N<=0!", _state); - ae_assert(d>=0, "BarycentricFloaterHormann: incorrect D!", _state); - - /* - * Prepare - */ - if( d>n-1 ) - { - d = n-1; - } - b->n = n; - - /* - * special case: N=1 - */ - if( n==1 ) - { - ae_vector_set_length(&b->x, n, _state); - ae_vector_set_length(&b->y, n, _state); - ae_vector_set_length(&b->w, n, _state); - b->x.ptr.p_double[0] = x->ptr.p_double[0]; - b->y.ptr.p_double[0] = y->ptr.p_double[0]; - b->w.ptr.p_double[0] = 1; - ratint_barycentricnormalize(b, _state); - ae_frame_leave(_state); - return; - } - - /* - * Fill X/Y - */ - ae_vector_set_length(&b->x, n, _state); - ae_vector_set_length(&b->y, n, _state); - ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - tagsortfastr(&b->x, &b->y, &sortrbuf, &sortrbuf2, n, _state); - - /* - * Calculate Wk - */ - ae_vector_set_length(&b->w, n, _state); - s0 = 1; - for(k=1; k<=d; k++) - { - s0 = -s0; - } - for(k=0; k<=n-1; k++) - { - - /* - * Wk - */ - s = 0; - for(i=ae_maxint(k-d, 0, _state); i<=ae_minint(k, n-1-d, _state); i++) - { - v = 1; - for(j=i; j<=i+d; j++) - { - if( j!=k ) - { - v = v/ae_fabs(b->x.ptr.p_double[k]-b->x.ptr.p_double[j], _state); - } - } - s = s+v; - } - b->w.ptr.p_double[k] = s0*s; - - /* - * Next S0 - */ - s0 = -s0; - } - - /* - * Normalize - */ - ratint_barycentricnormalize(b, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Copying of the barycentric interpolant (for internal use only) - -INPUT PARAMETERS: - B - barycentric interpolant - -OUTPUT PARAMETERS: - B2 - copy(B1) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriccopy(barycentricinterpolant* b, - barycentricinterpolant* b2, - ae_state *_state) -{ - - _barycentricinterpolant_clear(b2); - - b2->n = b->n; - b2->sy = b->sy; - ae_vector_set_length(&b2->x, b2->n, _state); - ae_vector_set_length(&b2->y, b2->n, _state); - ae_vector_set_length(&b2->w, b2->n, _state); - ae_v_move(&b2->x.ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); - ae_v_move(&b2->y.ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); - ae_v_move(&b2->w.ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); -} - - -/************************************************************************* -Normalization of barycentric interpolant: -* B.N, B.X, B.Y and B.W are initialized -* B.SY is NOT initialized -* Y[] is normalized, scaling coefficient is stored in B.SY -* W[] is normalized, no scaling coefficient is stored -* X[] is sorted - -Internal subroutine. -*************************************************************************/ -static void ratint_barycentricnormalize(barycentricinterpolant* b, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector p1; - ae_vector p2; - ae_int_t i; - ae_int_t j; - ae_int_t j2; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * Normalize task: |Y|<=1, |W|<=1, sort X[] - */ - b->sy = 0; - for(i=0; i<=b->n-1; i++) - { - b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); - } - if( ae_fp_greater(b->sy,0)&&ae_fp_greater(ae_fabs(b->sy-1, _state),10*ae_machineepsilon) ) - { - v = 1/b->sy; - ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); - } - v = 0; - for(i=0; i<=b->n-1; i++) - { - v = ae_maxreal(v, ae_fabs(b->w.ptr.p_double[i], _state), _state); - } - if( ae_fp_greater(v,0)&&ae_fp_greater(ae_fabs(v-1, _state),10*ae_machineepsilon) ) - { - v = 1/v; - ae_v_muld(&b->w.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); - } - for(i=0; i<=b->n-2; i++) - { - if( ae_fp_less(b->x.ptr.p_double[i+1],b->x.ptr.p_double[i]) ) - { - tagsort(&b->x, b->n, &p1, &p2, _state); - for(j=0; j<=b->n-1; j++) - { - j2 = p2.ptr.p_int[j]; - v = b->y.ptr.p_double[j]; - b->y.ptr.p_double[j] = b->y.ptr.p_double[j2]; - b->y.ptr.p_double[j2] = v; - v = b->w.ptr.p_double[j]; - b->w.ptr.p_double[j] = b->w.ptr.p_double[j2]; - b->w.ptr.p_double[j2] = v; - } - break; - } - } - ae_frame_leave(_state); -} - - -ae_bool _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - barycentricinterpolant *p = (barycentricinterpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - barycentricinterpolant *dst = (barycentricinterpolant*)_dst; - barycentricinterpolant *src = (barycentricinterpolant*)_src; - dst->n = src->n; - dst->sy = src->sy; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _barycentricinterpolant_clear(void* _p) -{ - barycentricinterpolant *p = (barycentricinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->y); - ae_vector_clear(&p->w); -} - - -void _barycentricinterpolant_destroy(void* _p) -{ - barycentricinterpolant *p = (barycentricinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->y); - ae_vector_destroy(&p->w); -} - - - - -/************************************************************************* -Conversion from barycentric representation to Chebyshev basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - A,B - base interval for Chebyshev polynomials (see below) - A<>B - -OUTPUT PARAMETERS - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, - where Ti - I-th Chebyshev polynomial. - -NOTES: - barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2cheb(barycentricinterpolant* p, - double a, - double b, - /* Real */ ae_vector* t, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - ae_vector vp; - ae_vector vx; - ae_vector tk; - ae_vector tk1; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(t); - ae_vector_init(&vp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tk, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state); - ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state); - ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state); - ae_assert(p->n>0, "PolynomialBar2Cheb: P is not correctly initialized barycentric interpolant!", _state); - - /* - * Calculate function values on a Chebyshev grid - */ - ae_vector_set_length(&vp, p->n, _state); - ae_vector_set_length(&vx, p->n, _state); - for(i=0; i<=p->n-1; i++) - { - vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state); - vp.ptr.p_double[i] = barycentriccalc(p, 0.5*(vx.ptr.p_double[i]+1)*(b-a)+a, _state); - } - - /* - * T[0] - */ - ae_vector_set_length(t, p->n, _state); - v = 0; - for(i=0; i<=p->n-1; i++) - { - v = v+vp.ptr.p_double[i]; - } - t->ptr.p_double[0] = v/p->n; - - /* - * other T's. - * - * NOTES: - * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX - * 2. we can do same calculations with fast DCT, but it - * * adds dependencies - * * still leaves us with O(N^2) algorithm because - * preparation of function values is O(N^2) process - */ - if( p->n>1 ) - { - ae_vector_set_length(&tk, p->n, _state); - ae_vector_set_length(&tk1, p->n, _state); - for(i=0; i<=p->n-1; i++) - { - tk.ptr.p_double[i] = vx.ptr.p_double[i]; - tk1.ptr.p_double[i] = 1; - } - for(k=1; k<=p->n-1; k++) - { - - /* - * calculate discrete product of function vector and TK - */ - v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); - t->ptr.p_double[k] = v/(0.5*p->n); - - /* - * Update TK and TK1 - */ - for(i=0; i<=p->n-1; i++) - { - v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; - tk1.ptr.p_double[i] = tk.ptr.p_double[i]; - tk.ptr.p_double[i] = v; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Conversion from Chebyshev basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, - where Ti - I-th Chebyshev polynomial. - N - number of coefficients: - * if given, only leading N elements of T are used - * if not given, automatically determined from size of T - A,B - base interval for Chebyshev polynomials (see above) - A=1, "PolynomialBar2Cheb: N<1", _state); - ae_assert(t->cnt>=n, "PolynomialBar2Cheb: Length(T)ptr.p_double[0]; - tk1 = 1; - tk = vx; - for(k=1; k<=n-1; k++) - { - vy = vy+t->ptr.p_double[k]*tk; - v = 2*vx*tk-tk1; - tk1 = tk; - tk = v; - } - y.ptr.p_double[i] = vy; - } - - /* - * Build barycentric interpolant, map grid from [-1,+1] to [A,B] - */ - polynomialbuildcheb1(a, b, &y, n, p, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Conversion from barycentric representation to power basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if P was obtained as - result of interpolation on [-1,+1], you can set C=0 and S=1 and - represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it - is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 - will be better option. Such representation can be obtained by using - 1000.0 as offset C and 1.0 as scale S. - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return coefficients in - any case, but for N>8 they will become unreliable. However, N's - less than 5 are pretty safe. - -3. barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2pow(barycentricinterpolant* p, - double c, - double s, - /* Real */ ae_vector* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - double e; - double d; - ae_vector vp; - ae_vector vx; - ae_vector tk; - ae_vector tk1; - ae_vector t; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(a); - ae_vector_init(&vp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tk, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_isfinite(c, _state), "PolynomialBar2Pow: C is not finite!", _state); - ae_assert(ae_isfinite(s, _state), "PolynomialBar2Pow: S is not finite!", _state); - ae_assert(ae_fp_neq(s,0), "PolynomialBar2Pow: S=0!", _state); - ae_assert(p->n>0, "PolynomialBar2Pow: P is not correctly initialized barycentric interpolant!", _state); - - /* - * Calculate function values on a Chebyshev grid - */ - ae_vector_set_length(&vp, p->n, _state); - ae_vector_set_length(&vx, p->n, _state); - for(i=0; i<=p->n-1; i++) - { - vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state); - vp.ptr.p_double[i] = barycentriccalc(p, s*vx.ptr.p_double[i]+c, _state); - } - - /* - * T[0] - */ - ae_vector_set_length(&t, p->n, _state); - v = 0; - for(i=0; i<=p->n-1; i++) - { - v = v+vp.ptr.p_double[i]; - } - t.ptr.p_double[0] = v/p->n; - - /* - * other T's. - * - * NOTES: - * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX - * 2. we can do same calculations with fast DCT, but it - * * adds dependencies - * * still leaves us with O(N^2) algorithm because - * preparation of function values is O(N^2) process - */ - if( p->n>1 ) - { - ae_vector_set_length(&tk, p->n, _state); - ae_vector_set_length(&tk1, p->n, _state); - for(i=0; i<=p->n-1; i++) - { - tk.ptr.p_double[i] = vx.ptr.p_double[i]; - tk1.ptr.p_double[i] = 1; - } - for(k=1; k<=p->n-1; k++) - { - - /* - * calculate discrete product of function vector and TK - */ - v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); - t.ptr.p_double[k] = v/(0.5*p->n); - - /* - * Update TK and TK1 - */ - for(i=0; i<=p->n-1; i++) - { - v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; - tk1.ptr.p_double[i] = tk.ptr.p_double[i]; - tk.ptr.p_double[i] = v; - } - } - } - - /* - * Convert from Chebyshev basis to power basis - */ - ae_vector_set_length(a, p->n, _state); - for(i=0; i<=p->n-1; i++) - { - a->ptr.p_double[i] = 0; - } - d = 0; - for(i=0; i<=p->n-1; i++) - { - for(k=i; k<=p->n-1; k++) - { - e = a->ptr.p_double[k]; - a->ptr.p_double[k] = 0; - if( i<=1&&k==i ) - { - a->ptr.p_double[k] = 1; - } - else - { - if( i!=0 ) - { - a->ptr.p_double[k] = 2*d; - } - if( k>i+1 ) - { - a->ptr.p_double[k] = a->ptr.p_double[k]-a->ptr.p_double[k-2]; - } - } - d = e; - } - d = a->ptr.p_double[i]; - e = 0; - k = i; - while(k<=p->n-1) - { - e = e+a->ptr.p_double[k]*t.ptr.p_double[k]; - k = k+2; - } - a->ptr.p_double[i] = e; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Conversion from power basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - * if given, only leading N elements of A are used - * if not given, automatically determined from size of A - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - P - polynomial in barycentric form - - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if you interpolate on - [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, - x^3 and so on. In most cases you it is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, - (x-1000)^3 will be better option (you have to specify 1000.0 as offset - C and 1.0 as scale S). - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return barycentric model - in any case, but for N>8 accuracy well degrade. However, N's less than - 5 are pretty safe. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialpow2bar(/* Real */ ae_vector* a, - ae_int_t n, - double c, - double s, - barycentricinterpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t k; - ae_vector y; - double vx; - double vy; - double px; - - ae_frame_make(_state, &_frame_block); - _barycentricinterpolant_clear(p); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_isfinite(c, _state), "PolynomialPow2Bar: C is not finite!", _state); - ae_assert(ae_isfinite(s, _state), "PolynomialPow2Bar: S is not finite!", _state); - ae_assert(ae_fp_neq(s,0), "PolynomialPow2Bar: S is zero!", _state); - ae_assert(n>=1, "PolynomialPow2Bar: N<1", _state); - ae_assert(a->cnt>=n, "PolynomialPow2Bar: Length(A)ptr.p_double[0]; - px = vx; - for(k=1; k<=n-1; k++) - { - vy = vy+px*a->ptr.p_double[k]; - px = px*vx; - } - y.ptr.p_double[i] = vy; - } - - /* - * Build barycentric interpolant, map grid from [-1,+1] to [A,B] - */ - polynomialbuildcheb1(c-s, c+s, &y, n, p, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Lagrange intepolant: generation of the model on the general grid. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - X - abscissas, array[0..N-1] - Y - function values, array[0..N-1] - N - number of points, N>=1 - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuild(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_int_t j; - ae_int_t k; - ae_vector w; - double b; - double a; - double v; - double mx; - ae_vector sortrbuf; - ae_vector sortrbuf2; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _barycentricinterpolant_clear(p); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "PolynomialBuild: N<=0!", _state); - ae_assert(x->cnt>=n, "PolynomialBuild: Length(X)cnt>=n, "PolynomialBuild: Length(Y)ptr.p_double[0]; - b = x->ptr.p_double[0]; - for(j=0; j<=n-1; j++) - { - w.ptr.p_double[j] = 1; - a = ae_minreal(a, x->ptr.p_double[j], _state); - b = ae_maxreal(b, x->ptr.p_double[j], _state); - } - for(k=0; k<=n-1; k++) - { - - /* - * W[K] is used instead of 0.0 because - * cycle on J does not touch K-th element - * and we MUST get maximum from ALL elements - */ - mx = ae_fabs(w.ptr.p_double[k], _state); - for(j=0; j<=n-1; j++) - { - if( j!=k ) - { - v = (b-a)/(x->ptr.p_double[j]-x->ptr.p_double[k]); - w.ptr.p_double[j] = w.ptr.p_double[j]*v; - mx = ae_maxreal(mx, ae_fabs(w.ptr.p_double[j], _state), _state); - } - } - if( k%5==0 ) - { - - /* - * every 5-th run we renormalize W[] - */ - v = 1/mx; - ae_v_muld(&w.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - } - barycentricbuildxyw(x, y, &w, n, p, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Lagrange intepolant: generation of the model on equidistant grid. -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1] - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildeqdist(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector w; - ae_vector x; - double v; - - ae_frame_make(_state, &_frame_block); - _barycentricinterpolant_clear(p); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "PolynomialBuildEqDist: N<=0!", _state); - ae_assert(y->cnt>=n, "PolynomialBuildEqDist: Length(Y)=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb1(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector w; - ae_vector x; - double v; - double t; - - ae_frame_make(_state, &_frame_block); - _barycentricinterpolant_clear(p); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "PolynomialBuildCheb1: N<=0!", _state); - ae_assert(y->cnt>=n, "PolynomialBuildCheb1: Length(Y)=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb2(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector w; - ae_vector x; - double v; - - ae_frame_make(_state, &_frame_block); - _barycentricinterpolant_clear(p); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "PolynomialBuildCheb2: N<=0!", _state); - ae_assert(y->cnt>=n, "PolynomialBuildCheb2: Length(Y)=1 - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolynomialBuildEqDist()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalceqdist(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state) -{ - double s1; - double s2; - double v; - double threshold; - double s; - double h; - ae_int_t i; - ae_int_t j; - double w; - double x; - double result; - - - ae_assert(n>0, "PolynomialCalcEqDist: N<=0!", _state); - ae_assert(f->cnt>=n, "PolynomialCalcEqDist: Length(F)v_nan; - return result; - } - - /* - * Special case: N=1 - */ - if( n==1 ) - { - result = f->ptr.p_double[0]; - return result; - } - - /* - * First, decide: should we use "safe" formula (guarded - * against overflow) or fast one? - */ - threshold = ae_sqrt(ae_minrealnumber, _state); - j = 0; - s = t-a; - for(i=1; i<=n-1; i++) - { - x = a+(double)i/(double)(n-1)*(b-a); - if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) - { - s = t-x; - j = i; - } - } - if( ae_fp_eq(s,0) ) - { - result = f->ptr.p_double[j]; - return result; - } - if( ae_fp_greater(ae_fabs(s, _state),threshold) ) - { - - /* - * use fast formula - */ - j = -1; - s = 1.0; - } - - /* - * Calculate using safe or fast barycentric formula - */ - s1 = 0; - s2 = 0; - w = 1.0; - h = (b-a)/(n-1); - for(i=0; i<=n-1; i++) - { - if( i!=j ) - { - v = s*w/(t-(a+i*h)); - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - else - { - v = w; - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - w = -w*(n-1-i); - w = w/(i+1); - } - result = s1/s2; - return result; -} - - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (first kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (first kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb1()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb1(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state) -{ - double s1; - double s2; - double v; - double threshold; - double s; - ae_int_t i; - ae_int_t j; - double a0; - double delta; - double alpha; - double beta; - double ca; - double sa; - double tempc; - double temps; - double x; - double w; - double p1; - double result; - - - ae_assert(n>0, "PolynomialCalcCheb1: N<=0!", _state); - ae_assert(f->cnt>=n, "PolynomialCalcCheb1: Length(F)v_nan; - return result; - } - - /* - * Special case: N=1 - */ - if( n==1 ) - { - result = f->ptr.p_double[0]; - return result; - } - - /* - * Prepare information for the recurrence formula - * used to calculate sin(pi*(2j+1)/(2n+2)) and - * cos(pi*(2j+1)/(2n+2)): - * - * A0 = pi/(2n+2) - * Delta = pi/(n+1) - * Alpha = 2 sin^2 (Delta/2) - * Beta = sin(Delta) - * - * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). - * Then we use - * - * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) - * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) - * - * to repeatedly calculate sin(..) and cos(..). - */ - threshold = ae_sqrt(ae_minrealnumber, _state); - t = (t-0.5*(a+b))/(0.5*(b-a)); - a0 = ae_pi/(2*(n-1)+2); - delta = 2*ae_pi/(2*(n-1)+2); - alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state); - beta = ae_sin(delta, _state); - - /* - * First, decide: should we use "safe" formula (guarded - * against overflow) or fast one? - */ - ca = ae_cos(a0, _state); - sa = ae_sin(a0, _state); - j = 0; - x = ca; - s = t-x; - for(i=1; i<=n-1; i++) - { - - /* - * Next X[i] - */ - temps = sa-(alpha*sa-beta*ca); - tempc = ca-(alpha*ca+beta*sa); - sa = temps; - ca = tempc; - x = ca; - - /* - * Use X[i] - */ - if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) - { - s = t-x; - j = i; - } - } - if( ae_fp_eq(s,0) ) - { - result = f->ptr.p_double[j]; - return result; - } - if( ae_fp_greater(ae_fabs(s, _state),threshold) ) - { - - /* - * use fast formula - */ - j = -1; - s = 1.0; - } - - /* - * Calculate using safe or fast barycentric formula - */ - s1 = 0; - s2 = 0; - ca = ae_cos(a0, _state); - sa = ae_sin(a0, _state); - p1 = 1.0; - for(i=0; i<=n-1; i++) - { - - /* - * Calculate X[i], W[i] - */ - x = ca; - w = p1*sa; - - /* - * Proceed - */ - if( i!=j ) - { - v = s*w/(t-x); - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - else - { - v = w; - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - - /* - * Next CA, SA, P1 - */ - temps = sa-(alpha*sa-beta*ca); - tempc = ca-(alpha*ca+beta*sa); - sa = temps; - ca = tempc; - p1 = -p1; - } - result = s1/s2; - return result; -} - - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (second kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (second kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb2()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb2(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state) -{ - double s1; - double s2; - double v; - double threshold; - double s; - ae_int_t i; - ae_int_t j; - double a0; - double delta; - double alpha; - double beta; - double ca; - double sa; - double tempc; - double temps; - double x; - double w; - double p1; - double result; - - - ae_assert(n>0, "PolynomialCalcCheb2: N<=0!", _state); - ae_assert(f->cnt>=n, "PolynomialCalcCheb2: Length(F)v_nan; - return result; - } - - /* - * Special case: N=1 - */ - if( n==1 ) - { - result = f->ptr.p_double[0]; - return result; - } - - /* - * Prepare information for the recurrence formula - * used to calculate sin(pi*i/n) and - * cos(pi*i/n): - * - * A0 = 0 - * Delta = pi/n - * Alpha = 2 sin^2 (Delta/2) - * Beta = sin(Delta) - * - * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). - * Then we use - * - * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) - * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) - * - * to repeatedly calculate sin(..) and cos(..). - */ - threshold = ae_sqrt(ae_minrealnumber, _state); - t = (t-0.5*(a+b))/(0.5*(b-a)); - a0 = 0.0; - delta = ae_pi/(n-1); - alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state); - beta = ae_sin(delta, _state); - - /* - * First, decide: should we use "safe" formula (guarded - * against overflow) or fast one? - */ - ca = ae_cos(a0, _state); - sa = ae_sin(a0, _state); - j = 0; - x = ca; - s = t-x; - for(i=1; i<=n-1; i++) - { - - /* - * Next X[i] - */ - temps = sa-(alpha*sa-beta*ca); - tempc = ca-(alpha*ca+beta*sa); - sa = temps; - ca = tempc; - x = ca; - - /* - * Use X[i] - */ - if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) - { - s = t-x; - j = i; - } - } - if( ae_fp_eq(s,0) ) - { - result = f->ptr.p_double[j]; - return result; - } - if( ae_fp_greater(ae_fabs(s, _state),threshold) ) - { - - /* - * use fast formula - */ - j = -1; - s = 1.0; - } - - /* - * Calculate using safe or fast barycentric formula - */ - s1 = 0; - s2 = 0; - ca = ae_cos(a0, _state); - sa = ae_sin(a0, _state); - p1 = 1.0; - for(i=0; i<=n-1; i++) - { - - /* - * Calculate X[i], W[i] - */ - x = ca; - if( i==0||i==n-1 ) - { - w = 0.5*p1; - } - else - { - w = 1.0*p1; - } - - /* - * Proceed - */ - if( i!=j ) - { - v = s*w/(t-x); - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - else - { - v = w; - s1 = s1+v*f->ptr.p_double[i]; - s2 = s2+v; - } - - /* - * Next CA, SA, P1 - */ - temps = sa-(alpha*sa-beta*ca); - tempc = ca-(alpha*ca+beta*sa); - sa = temps; - ca = tempc; - p1 = -p1; - } - result = s1/s2; - return result; -} - - - - -/************************************************************************* -This subroutine builds linear spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildlinear(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _spline1dinterpolant_clear(c); - - ae_assert(n>1, "Spline1DBuildLinear: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DBuildLinear: Length(X)cnt>=n, "Spline1DBuildLinear: Length(Y)periodic = ae_false; - c->n = n; - c->k = 3; - c->continuity = 0; - ae_vector_set_length(&c->x, n, _state); - ae_vector_set_length(&c->c, 4*(n-1)+2, _state); - for(i=0; i<=n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=n-2; i++) - { - c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i]; - c->c.ptr.p_double[4*i+1] = (y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]); - c->c.ptr.p_double[4*i+2] = 0; - c->c.ptr.p_double[4*i+3] = 0; - } - c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1]; - c->c.ptr.p_double[4*(n-1)+1] = c->c.ptr.p_double[4*(n-2)+1]; - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine builds cubic spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - C - spline interpolant - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - spline1dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector dt; - ae_vector d; - ae_vector p; - ae_int_t ylen; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _spline1dinterpolant_clear(c); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DBuildCubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DBuildCubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DBuildCubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DBuildCubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DBuildCubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DBuildCubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DBuildCubic: Length(X)cnt>=n, "Spline1DBuildCubic: Length(Y)ptr.p_double[n-1] = y->ptr.p_double[0]; - } - spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); - spline1dbuildhermite(x, y, &d, n, c, _state); - c->periodic = boundltype==-1||boundrtype==-1; - c->continuity = 2; - ae_frame_leave(_state); -} - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns table of function derivatives d[] -(calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D - derivative values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiffcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector dt; - ae_vector p; - ae_int_t i; - ae_int_t ylen; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_clear(d); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiffCubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiffCubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiffCubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiffCubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiffCubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DGridDiffCubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DGridDiffCubic: Length(X)cnt>=n, "Spline1DGridDiffCubic: Length(Y)ptr.p_double[i]; - } - ae_v_move(&d->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns tables of first and second -function derivatives d1[] and d2[] (calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D1 - S' values at X[] - D2 - S'' values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiff2cubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d1, - /* Real */ ae_vector* d2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector dt; - ae_vector p; - ae_int_t i; - ae_int_t ylen; - double delta; - double delta2; - double delta3; - double s2; - double s3; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_clear(d1); - ae_vector_clear(d2); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiff2Cubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiff2Cubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiff2Cubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiff2Cubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiff2Cubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DGridDiff2Cubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DGridDiff2Cubic: Length(X)cnt>=n, "Spline1DGridDiff2Cubic: Length(Y)ptr.p_double[i+1]-x->ptr.p_double[i]; - delta2 = ae_sqr(delta, _state); - delta3 = delta*delta2; - s2 = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d1->ptr.p_double[i]*delta-d1->ptr.p_double[i+1]*delta)/delta2; - s3 = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d1->ptr.p_double[i]*delta+d1->ptr.p_double[i+1]*delta)/delta3; - d2->ptr.p_double[i] = 2*s2; - } - d2->ptr.p_double[n-1] = 2*s2+6*s3*delta; - - /* - * Remember that HeapSortPPoints() call? - * Now we have to reorder them back. - */ - if( dt.cntptr.p_double[i]; - } - ae_v_move(&d1->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - dt.ptr.p_double[p.ptr.p_int[i]] = d2->ptr.p_double[i]; - } - ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _x2; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector d; - ae_vector dt; - ae_vector d1; - ae_vector d2; - ae_vector p; - ae_vector p2; - ae_int_t i; - ae_int_t ylen; - double t; - double t2; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_x2, x2, _state, ae_true); - x2 = &_x2; - ae_vector_clear(y2); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvCubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvCubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvCubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DConvCubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DConvCubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DConvCubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DConvCubic: Length(X)cnt>=n, "Spline1DConvCubic: Length(Y)=2, "Spline1DConvCubic: N2<2!", _state); - ae_assert(x2->cnt>=n2, "Spline1DConvCubic: Length(X2)ptr.p_double[i]; - apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); - x2->ptr.p_double[i] = t; - } - } - spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); - - /* - * Now we've checked and preordered everything, so we: - * * call internal GridDiff() function to get Hermite form of spline - * * convert using internal Conv() function - * * convert Y2 back to original order - */ - spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); - spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, &d1, ae_false, &d2, ae_false, _state); - ae_assert(dt.cnt>=n2, "Spline1DConvCubic: internal error!", _state); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; - } - ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] and derivatives d2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiffcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - /* Real */ ae_vector* d2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _x2; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector d; - ae_vector dt; - ae_vector rt1; - ae_vector p; - ae_vector p2; - ae_int_t i; - ae_int_t ylen; - double t; - double t2; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_x2, x2, _state, ae_true); - x2 = &_x2; - ae_vector_clear(y2); - ae_vector_clear(d2); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&rt1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiffCubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiffCubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiffCubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiffCubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiffCubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DConvDiffCubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DConvDiffCubic: Length(X)cnt>=n, "Spline1DConvDiffCubic: Length(Y)=2, "Spline1DConvDiffCubic: N2<2!", _state); - ae_assert(x2->cnt>=n2, "Spline1DConvDiffCubic: Length(X2)ptr.p_double[i]; - apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); - x2->ptr.p_double[i] = t; - } - } - spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); - - /* - * Now we've checked and preordered everything, so we: - * * call internal GridDiff() function to get Hermite form of spline - * * convert using internal Conv() function - * * convert Y2 back to original order - */ - spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); - spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, &rt1, ae_false, _state); - ae_assert(dt.cnt>=n2, "Spline1DConvDiffCubic: internal error!", _state); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; - } - ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; - } - ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[], first and second derivatives d2[] and dd2[] -(calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - DD2 - second derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiff2cubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - /* Real */ ae_vector* d2, - /* Real */ ae_vector* dd2, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _x2; - ae_vector a1; - ae_vector a2; - ae_vector a3; - ae_vector b; - ae_vector d; - ae_vector dt; - ae_vector p; - ae_vector p2; - ae_int_t i; - ae_int_t ylen; - double t; - double t2; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_x2, x2, _state, ae_true); - x2 = &_x2; - ae_vector_clear(y2); - ae_vector_clear(d2); - ae_vector_clear(dd2); - ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - - /* - * check correctness of boundary conditions - */ - ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiff2Cubic: incorrect BoundLType!", _state); - ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiff2Cubic: incorrect BoundRType!", _state); - ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiff2Cubic: incorrect BoundLType/BoundRType!", _state); - if( boundltype==1||boundltype==2 ) - { - ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiff2Cubic: BoundL is infinite or NAN!", _state); - } - if( boundrtype==1||boundrtype==2 ) - { - ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiff2Cubic: BoundR is infinite or NAN!", _state); - } - - /* - * check lengths of arguments - */ - ae_assert(n>=2, "Spline1DConvDiff2Cubic: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DConvDiff2Cubic: Length(X)cnt>=n, "Spline1DConvDiff2Cubic: Length(Y)=2, "Spline1DConvDiff2Cubic: N2<2!", _state); - ae_assert(x2->cnt>=n2, "Spline1DConvDiff2Cubic: Length(X2)ptr.p_double[i]; - apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state); - x2->ptr.p_double[i] = t; - } - } - spline1d_heapsortppoints(x2, &dt, &p2, n2, _state); - - /* - * Now we've checked and preordered everything, so we: - * * call internal GridDiff() function to get Hermite form of spline - * * convert using internal Conv() function - * * convert Y2 back to original order - */ - spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state); - spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, dd2, ae_true, _state); - ae_assert(dt.cnt>=n2, "Spline1DConvDiff2Cubic: internal error!", _state); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; - } - ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; - } - ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - for(i=0; i<=n2-1; i++) - { - dt.ptr.p_double[p2.ptr.p_int[i]] = dd2->ptr.p_double[i]; - } - ae_v_move(&dd2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine builds Catmull-Rom spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundType - boundary condition type: - * -1 for periodic boundary condition - * 0 for parabolically terminated spline (default) - Tension - tension parameter: - * tension=0 corresponds to classic Catmull-Rom spline (default) - * 0=2, "Spline1DBuildCatmullRom: N<2!", _state); - ae_assert(boundtype==-1||boundtype==0, "Spline1DBuildCatmullRom: incorrect BoundType!", _state); - ae_assert(ae_fp_greater_eq(tension,0), "Spline1DBuildCatmullRom: Tension<0!", _state); - ae_assert(ae_fp_less_eq(tension,1), "Spline1DBuildCatmullRom: Tension>1!", _state); - ae_assert(x->cnt>=n, "Spline1DBuildCatmullRom: Length(X)cnt>=n, "Spline1DBuildCatmullRom: Length(Y)ptr.p_double[n-1] = y->ptr.p_double[0]; - ae_vector_set_length(&d, n, _state); - d.ptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[n-2])/(2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2])); - for(i=1; i<=n-2; i++) - { - d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); - } - d.ptr.p_double[n-1] = d.ptr.p_double[0]; - - /* - * Now problem is reduced to the cubic Hermite spline - */ - spline1dbuildhermite(x, y, &d, n, c, _state); - c->periodic = ae_true; - } - else - { - - /* - * Non-periodic boundary conditions - */ - ae_vector_set_length(&d, n, _state); - for(i=1; i<=n-2; i++) - { - d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); - } - d.ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-d.ptr.p_double[1]; - d.ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])-d.ptr.p_double[n-2]; - - /* - * Now problem is reduced to the cubic Hermite spline - */ - spline1dbuildhermite(x, y, &d, n, c, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine builds Hermite spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - D - derivatives, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildhermite(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* d, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _d; - ae_int_t i; - double delta; - double delta2; - double delta3; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_d, d, _state, ae_true); - d = &_d; - _spline1dinterpolant_clear(c); - - ae_assert(n>=2, "Spline1DBuildHermite: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DBuildHermite: Length(X)cnt>=n, "Spline1DBuildHermite: Length(Y)cnt>=n, "Spline1DBuildHermite: Length(D)x, n, _state); - ae_vector_set_length(&c->c, 4*(n-1)+2, _state); - c->periodic = ae_false; - c->k = 3; - c->n = n; - c->continuity = 1; - for(i=0; i<=n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=n-2; i++) - { - delta = x->ptr.p_double[i+1]-x->ptr.p_double[i]; - delta2 = ae_sqr(delta, _state); - delta3 = delta*delta2; - c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i]; - c->c.ptr.p_double[4*i+1] = d->ptr.p_double[i]; - c->c.ptr.p_double[4*i+2] = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d->ptr.p_double[i]*delta-d->ptr.p_double[i+1]*delta)/delta2; - c->c.ptr.p_double[4*i+3] = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d->ptr.p_double[i]*delta+d->ptr.p_double[i+1]*delta)/delta3; - } - c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1]; - c->c.ptr.p_double[4*(n-1)+1] = d->ptr.p_double[n-1]; - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine builds Akima spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildakima(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_int_t i; - ae_vector d; - ae_vector w; - ae_vector diff; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _spline1dinterpolant_clear(c); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&diff, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=2, "Spline1DBuildAkima: N<2!", _state); - ae_assert(x->cnt>=n, "Spline1DBuildAkima: Length(X)cnt>=n, "Spline1DBuildAkima: Length(Y)ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]); - } - for(i=1; i<=n-2; i++) - { - w.ptr.p_double[i] = ae_fabs(diff.ptr.p_double[i]-diff.ptr.p_double[i-1], _state); - } - - /* - * Prepare Hermite interpolation scheme - */ - ae_vector_set_length(&d, n, _state); - for(i=2; i<=n-3; i++) - { - if( ae_fp_neq(ae_fabs(w.ptr.p_double[i-1], _state)+ae_fabs(w.ptr.p_double[i+1], _state),0) ) - { - d.ptr.p_double[i] = (w.ptr.p_double[i+1]*diff.ptr.p_double[i-1]+w.ptr.p_double[i-1]*diff.ptr.p_double[i])/(w.ptr.p_double[i+1]+w.ptr.p_double[i-1]); - } - else - { - d.ptr.p_double[i] = ((x->ptr.p_double[i+1]-x->ptr.p_double[i])*diff.ptr.p_double[i-1]+(x->ptr.p_double[i]-x->ptr.p_double[i-1])*diff.ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); - } - } - d.ptr.p_double[0] = spline1d_diffthreepoint(x->ptr.p_double[0], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state); - d.ptr.p_double[1] = spline1d_diffthreepoint(x->ptr.p_double[1], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state); - d.ptr.p_double[n-2] = spline1d_diffthreepoint(x->ptr.p_double[n-2], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state); - d.ptr.p_double[n-1] = spline1d_diffthreepoint(x->ptr.p_double[n-1], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state); - - /* - * Build Akima spline using Hermite interpolation scheme - */ - spline1dbuildhermite(x, y, &d, n, c, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine calculates the value of the spline at the given point X. - -INPUT PARAMETERS: - C - spline interpolant - X - point - -Result: - S(x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state) -{ - ae_int_t l; - ae_int_t r; - ae_int_t m; - double t; - double result; - - - ae_assert(c->k==3, "Spline1DCalc: internal error", _state); - ae_assert(!ae_isinf(x, _state), "Spline1DCalc: infinite X!", _state); - - /* - * special case: NaN - */ - if( ae_isnan(x, _state) ) - { - result = _state->v_nan; - return result; - } - - /* - * correct if periodic - */ - if( c->periodic ) - { - apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); - } - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = c->n-2+1; - while(l!=r-1) - { - m = (l+r)/2; - if( c->x.ptr.p_double[m]>=x ) - { - r = m; - } - else - { - l = m; - } - } - - /* - * Interpolation - */ - x = x-c->x.ptr.p_double[l]; - m = 4*l; - result = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); - return result; -} - - -/************************************************************************* -This subroutine differentiates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -Result: - S - S(x) - DS - S'(x) - D2S - S''(x) - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1ddiff(spline1dinterpolant* c, - double x, - double* s, - double* ds, - double* d2s, - ae_state *_state) -{ - ae_int_t l; - ae_int_t r; - ae_int_t m; - double t; - - *s = 0; - *ds = 0; - *d2s = 0; - - ae_assert(c->k==3, "Spline1DDiff: internal error", _state); - ae_assert(!ae_isinf(x, _state), "Spline1DDiff: infinite X!", _state); - - /* - * special case: NaN - */ - if( ae_isnan(x, _state) ) - { - *s = _state->v_nan; - *ds = _state->v_nan; - *d2s = _state->v_nan; - return; - } - - /* - * correct if periodic - */ - if( c->periodic ) - { - apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); - } - - /* - * Binary search - */ - l = 0; - r = c->n-2+1; - while(l!=r-1) - { - m = (l+r)/2; - if( c->x.ptr.p_double[m]>=x ) - { - r = m; - } - else - { - l = m; - } - } - - /* - * Differentiation - */ - x = x-c->x.ptr.p_double[l]; - m = 4*l; - *s = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); - *ds = c->c.ptr.p_double[m+1]+2*x*c->c.ptr.p_double[m+2]+3*ae_sqr(x, _state)*c->c.ptr.p_double[m+3]; - *d2s = 2*c->c.ptr.p_double[m+2]+6*x*c->c.ptr.p_double[m+3]; -} - - -/************************************************************************* -This subroutine makes the copy of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - -Result: - CC - spline copy - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dcopy(spline1dinterpolant* c, - spline1dinterpolant* cc, - ae_state *_state) -{ - ae_int_t s; - - _spline1dinterpolant_clear(cc); - - cc->periodic = c->periodic; - cc->n = c->n; - cc->k = c->k; - cc->continuity = c->continuity; - ae_vector_set_length(&cc->x, cc->n, _state); - ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); - s = c->c.cnt; - ae_vector_set_length(&cc->c, s, _state); - ae_v_move(&cc->c.ptr.p_double[0], 1, &c->c.ptr.p_double[0], 1, ae_v_len(0,s-1)); -} - - -/************************************************************************* -This subroutine unpacks the spline into the coefficients table. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -OUTPUT PARAMETERS: - Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. - For I = 0...N-2: - Tbl[I,0] = X[i] - Tbl[I,1] = X[i+1] - Tbl[I,2] = C0 - Tbl[I,3] = C1 - Tbl[I,4] = C2 - Tbl[I,5] = C3 - On [x[i], x[i+1]] spline is equals to: - S(x) = C0 + C1*t + C2*t^2 + C3*t^3 - t = x-x[i] - -NOTE: - You can rebuild spline with Spline1DBuildHermite() function, which - accepts as inputs function values and derivatives at nodes, which are - easy to calculate when you have coefficients. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dunpack(spline1dinterpolant* c, - ae_int_t* n, - /* Real */ ae_matrix* tbl, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - *n = 0; - ae_matrix_clear(tbl); - - ae_matrix_set_length(tbl, c->n-2+1, 2+c->k+1, _state); - *n = c->n; - - /* - * Fill - */ - for(i=0; i<=*n-2; i++) - { - tbl->ptr.pp_double[i][0] = c->x.ptr.p_double[i]; - tbl->ptr.pp_double[i][1] = c->x.ptr.p_double[i+1]; - for(j=0; j<=c->k; j++) - { - tbl->ptr.pp_double[i][2+j] = c->c.ptr.p_double[(c->k+1)*i+j]; - } - } -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: x = A*t + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransx(spline1dinterpolant* c, - double a, - double b, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t n; - double v; - double dv; - double d2v; - ae_vector x; - ae_vector y; - ae_vector d; - ae_bool isperiodic; - ae_int_t contval; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - - ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); - n = c->n; - ae_vector_set_length(&x, n, _state); - ae_vector_set_length(&y, n, _state); - ae_vector_set_length(&d, n, _state); - - /* - * Unpack, X, Y, dY/dX. - * Scale and pack with Spline1DBuildHermite again. - */ - if( ae_fp_eq(a,0) ) - { - - /* - * Special case: A=0 - */ - v = spline1dcalc(c, b, _state); - for(i=0; i<=n-1; i++) - { - x.ptr.p_double[i] = c->x.ptr.p_double[i]; - y.ptr.p_double[i] = v; - d.ptr.p_double[i] = 0.0; - } - } - else - { - - /* - * General case, A<>0 - */ - for(i=0; i<=n-1; i++) - { - x.ptr.p_double[i] = c->x.ptr.p_double[i]; - spline1ddiff(c, x.ptr.p_double[i], &v, &dv, &d2v, _state); - x.ptr.p_double[i] = (x.ptr.p_double[i]-b)/a; - y.ptr.p_double[i] = v; - d.ptr.p_double[i] = a*dv; - } - } - isperiodic = c->periodic; - contval = c->continuity; - if( contval>0 ) - { - spline1dbuildhermite(&x, &y, &d, n, c, _state); - } - else - { - spline1dbuildlinear(&x, &y, n, c, _state); - } - c->periodic = isperiodic; - c->continuity = contval; - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x) = A*S(x) + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransy(spline1dinterpolant* c, - double a, - double b, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - - - ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); - n = c->n; - for(i=0; i<=n-2; i++) - { - c->c.ptr.p_double[4*i] = a*c->c.ptr.p_double[4*i]+b; - for(j=1; j<=3; j++) - { - c->c.ptr.p_double[4*i+j] = a*c->c.ptr.p_double[4*i+j]; - } - } - c->c.ptr.p_double[4*(n-1)+0] = a*c->c.ptr.p_double[4*(n-1)+0]+b; - c->c.ptr.p_double[4*(n-1)+1] = a*c->c.ptr.p_double[4*(n-1)+1]; -} - - -/************************************************************************* -This subroutine integrates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - right bound of the integration interval [a, x], - here 'a' denotes min(x[]) -Result: - integral(S(t)dt,a,x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dintegrate(spline1dinterpolant* c, - double x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - ae_int_t l; - ae_int_t r; - ae_int_t m; - double w; - double v; - double t; - double intab; - double additionalterm; - double result; - - - n = c->n; - - /* - * Periodic splines require special treatment. We make - * following transformation: - * - * integral(S(t)dt,A,X) = integral(S(t)dt,A,Z)+AdditionalTerm - * - * here X may lie outside of [A,B], Z lies strictly in [A,B], - * AdditionalTerm is equals to integral(S(t)dt,A,B) times some - * integer number (may be zero). - */ - if( c->periodic&&(ae_fp_less(x,c->x.ptr.p_double[0])||ae_fp_greater(x,c->x.ptr.p_double[c->n-1])) ) - { - - /* - * compute integral(S(x)dx,A,B) - */ - intab = 0; - for(i=0; i<=c->n-2; i++) - { - w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; - m = (c->k+1)*i; - intab = intab+c->c.ptr.p_double[m]*w; - v = w; - for(j=1; j<=c->k; j++) - { - v = v*w; - intab = intab+c->c.ptr.p_double[m+j]*v/(j+1); - } - } - - /* - * map X into [A,B] - */ - apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); - additionalterm = t*intab; - } - else - { - additionalterm = 0; - } - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = n-2+1; - while(l!=r-1) - { - m = (l+r)/2; - if( ae_fp_greater_eq(c->x.ptr.p_double[m],x) ) - { - r = m; - } - else - { - l = m; - } - } - - /* - * Integration - */ - result = 0; - for(i=0; i<=l-1; i++) - { - w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; - m = (c->k+1)*i; - result = result+c->c.ptr.p_double[m]*w; - v = w; - for(j=1; j<=c->k; j++) - { - v = v*w; - result = result+c->c.ptr.p_double[m+j]*v/(j+1); - } - } - w = x-c->x.ptr.p_double[l]; - m = (c->k+1)*l; - v = w; - result = result+c->c.ptr.p_double[m]*w; - for(j=1; j<=c->k; j++) - { - v = v*w; - result = result+c->c.ptr.p_double[m+j]*v/(j+1); - } - result = result+additionalterm; - return result; -} - - -/************************************************************************* -Internal version of Spline1DConvDiff - -Converts from Hermite spline given by grid XOld to new grid X2 - -INPUT PARAMETERS: - XOld - old grid - YOld - values at old grid - DOld - first derivative at old grid - N - grid size - X2 - new grid - N2 - new grid size - Y - possibly preallocated output array - (reallocate if too small) - NeedY - do we need Y? - D1 - possibly preallocated output array - (reallocate if too small) - NeedD1 - do we need D1? - D2 - possibly preallocated output array - (reallocate if too small) - NeedD2 - do we need D1? - -OUTPUT ARRAYS: - Y - values, if needed - D1 - first derivative, if needed - D2 - second derivative, if needed - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiffinternal(/* Real */ ae_vector* xold, - /* Real */ ae_vector* yold, - /* Real */ ae_vector* dold, - ae_int_t n, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y, - ae_bool needy, - /* Real */ ae_vector* d1, - ae_bool needd1, - /* Real */ ae_vector* d2, - ae_bool needd2, - ae_state *_state) -{ - ae_int_t intervalindex; - ae_int_t pointindex; - ae_bool havetoadvance; - double c0; - double c1; - double c2; - double c3; - double a; - double b; - double w; - double w2; - double w3; - double fa; - double fb; - double da; - double db; - double t; - - - - /* - * Prepare space - */ - if( needy&&y->cntcntcnt=n2 ) - { - break; - } - t = x2->ptr.p_double[pointindex]; - - /* - * do we need to advance interval? - */ - havetoadvance = ae_false; - if( intervalindex==-1 ) - { - havetoadvance = ae_true; - } - else - { - if( intervalindexptr.p_double[intervalindex]; - b = xold->ptr.p_double[intervalindex+1]; - w = b-a; - w2 = w*w; - w3 = w*w2; - fa = yold->ptr.p_double[intervalindex]; - fb = yold->ptr.p_double[intervalindex+1]; - da = dold->ptr.p_double[intervalindex]; - db = dold->ptr.p_double[intervalindex+1]; - c0 = fa; - c1 = da; - c2 = (3*(fb-fa)-2*da*w-db*w)/w2; - c3 = (2*(fa-fb)+da*w+db*w)/w3; - continue; - } - - /* - * Calculate spline and its derivatives using power basis - */ - t = t-a; - if( needy ) - { - y->ptr.p_double[pointindex] = c0+t*(c1+t*(c2+t*c3)); - } - if( needd1 ) - { - d1->ptr.p_double[pointindex] = c1+2*t*c2+3*t*t*c3; - } - if( needd2 ) - { - d2->ptr.p_double[pointindex] = 2*c2+6*t*c3; - } - pointindex = pointindex+1; - } -} - - -/************************************************************************* -This function finds all roots and extrema of the spline S(x) defined at -[A,B] (interval which contains spline nodes). - -It does not extrapolates function, so roots and extrema located outside -of [A,B] will not be found. It returns all isolated (including multiple) -roots and extrema. - -INPUT PARAMETERS - C - spline interpolant - -OUTPUT PARAMETERS - R - array[NR], contains roots of the spline. - In case there is no roots, this array has zero length. - NR - number of roots, >=0 - DR - is set to True in case there is at least one interval - where spline is just a zero constant. Such degenerate - cases are not reported in the R/NR - E - array[NE], contains extrema (maximums/minimums) of - the spline. In case there is no extrema, this array - has zero length. - ET - array[NE], extrema types: - * ET[i]>0 in case I-th extrema is a minimum - * ET[i]<0 in case I-th extrema is a maximum - NE - number of extrema, >=0 - DE - is set to True in case there is at least one interval - where spline is a constant. Such degenerate cases are - not reported in the E/NE. - -NOTES: - -1. This function does NOT report following kinds of roots: - * intervals where function is constantly zero - * roots which are outside of [A,B] (note: it CAN return A or B) - -2. This function does NOT report following kinds of extrema: - * intervals where function is a constant - * extrema which are outside of (A,B) (note: it WON'T return A or B) - - -- ALGLIB PROJECT -- - Copyright 26.09.2011 by Bochkanov Sergey -*************************************************************************/ -void spline1drootsandextrema(spline1dinterpolant* c, - /* Real */ ae_vector* r, - ae_int_t* nr, - ae_bool* dr, - /* Real */ ae_vector* e, - /* Integer */ ae_vector* et, - ae_int_t* ne, - ae_bool* de, - ae_state *_state) -{ - ae_frame _frame_block; - double pl; - double ml; - double pll; - double pr; - double mr; - ae_vector tr; - ae_vector tmpr; - ae_vector tmpe; - ae_vector tmpet; - ae_vector tmpc; - double x0; - double x1; - double x2; - double ex0; - double ex1; - ae_int_t tne; - ae_int_t tnr; - ae_int_t i; - ae_int_t j; - ae_bool nstep; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(r); - *nr = 0; - *dr = ae_false; - ae_vector_clear(e); - ae_vector_clear(et); - *ne = 0; - *de = ae_false; - ae_vector_init(&tr, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpr, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpe, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpet, 0, DT_INT, _state, ae_true); - ae_vector_init(&tmpc, 0, DT_REAL, _state, ae_true); - - - /* - *exception handling - */ - ae_assert(c->k==3, "Spline1DRootsAndExtrema : incorrect parameter C.K!", _state); - ae_assert(c->continuity>=0, "Spline1DRootsAndExtrema : parameter C.Continuity must not be less than 0!", _state); - - /* - *initialization of variable - */ - *nr = 0; - *ne = 0; - *dr = ae_false; - *de = ae_false; - nstep = ae_true; - - /* - *consider case, when C.Continuty=0 - */ - if( c->continuity==0 ) - { - - /* - *allocation for auxiliary arrays - *'TmpR ' - it stores a time value for roots - *'TmpE ' - it stores a time value for extremums - *'TmpET '- it stores a time value for extremums type - */ - rvectorsetlengthatleast(&tmpr, 3*(c->n-1), _state); - rvectorsetlengthatleast(&tmpe, 2*(c->n-1), _state); - ivectorsetlengthatleast(&tmpet, 2*(c->n-1), _state); - - /* - *start calculating - */ - for(i=0; i<=c->n-2; i++) - { - - /* - *initialization pL, mL, pR, mR - */ - pl = c->c.ptr.p_double[4*i]; - ml = c->c.ptr.p_double[4*i+1]; - pr = c->c.ptr.p_double[4*(i+1)]; - mr = c->c.ptr.p_double[4*i+1]+2*c->c.ptr.p_double[4*i+2]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])+3*c->c.ptr.p_double[4*i+3]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]); - - /* - *pre-searching roots and extremums - */ - solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); - *dr = *dr||tnr==-1; - *de = *de||tne==-1; - - /* - *searching of roots - */ - if( tnr==1&&nstep ) - { - - /* - *is there roots? - */ - if( *nr>0 ) - { - - /* - *is a next root equal a previous root? - *if is't, then write new root - */ - if( ae_fp_neq(x0,tmpr.ptr.p_double[*nr-1]) ) - { - tmpr.ptr.p_double[*nr] = x0; - *nr = *nr+1; - } - } - else - { - - /* - *write a first root - */ - tmpr.ptr.p_double[*nr] = x0; - *nr = *nr+1; - } - } - else - { - - /* - *case when function at a segment identically to zero - *then we have to clear a root, if the one located on a - *constant segment - */ - if( tnr==-1 ) - { - - /* - *safe state variable as constant - */ - if( nstep ) - { - nstep = ae_false; - } - - /* - *clear the root, if there is - */ - if( *nr>0 ) - { - if( ae_fp_eq(c->x.ptr.p_double[i],tmpr.ptr.p_double[*nr-1]) ) - { - *nr = *nr-1; - } - } - - /* - *change state for 'DR' - */ - if( !*dr ) - { - *dr = ae_true; - } - } - else - { - nstep = ae_true; - } - } - - /* - *searching of extremums - */ - if( i>0 ) - { - pll = c->c.ptr.p_double[4*(i-1)]; - - /* - *if pL=pLL or pL=pR then - */ - if( tne==-1 ) - { - if( !*de ) - { - *de = ae_true; - } - } - else - { - if( ae_fp_greater(pl,pll)&&ae_fp_greater(pl,pr) ) - { - - /* - *maximum - */ - tmpet.ptr.p_int[*ne] = -1; - tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; - *ne = *ne+1; - } - else - { - if( ae_fp_less(pl,pll)&&ae_fp_less(pl,pr) ) - { - - /* - *minimum - */ - tmpet.ptr.p_int[*ne] = 1; - tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; - *ne = *ne+1; - } - } - } - } - } - - /* - *write final result - */ - rvectorsetlengthatleast(r, *nr, _state); - rvectorsetlengthatleast(e, *ne, _state); - ivectorsetlengthatleast(et, *ne, _state); - - /* - *write roots - */ - for(i=0; i<=*nr-1; i++) - { - r->ptr.p_double[i] = tmpr.ptr.p_double[i]; - } - - /* - *write extremums and their types - */ - for(i=0; i<=*ne-1; i++) - { - e->ptr.p_double[i] = tmpe.ptr.p_double[i]; - et->ptr.p_int[i] = tmpet.ptr.p_int[i]; - } - } - else - { - - /* - *case, when C.Continuity>=1 - *'TmpR ' - it stores a time value for roots - *'TmpC' - it stores a time value for extremums and - *their function value (TmpC={EX0,F(EX0), EX1,F(EX1), ..., EXn,F(EXn)};) - *'TmpE' - it stores a time value for extremums only - *'TmpET'- it stores a time value for extremums type - */ - rvectorsetlengthatleast(&tmpr, 2*c->n-1, _state); - rvectorsetlengthatleast(&tmpc, 4*c->n, _state); - rvectorsetlengthatleast(&tmpe, 2*c->n, _state); - ivectorsetlengthatleast(&tmpet, 2*c->n, _state); - - /* - *start calculating - */ - for(i=0; i<=c->n-2; i++) - { - - /* - *we calculate pL,mL, pR,mR as Fi+1(F'i+1) at left border - */ - pl = c->c.ptr.p_double[4*i]; - ml = c->c.ptr.p_double[4*i+1]; - pr = c->c.ptr.p_double[4*(i+1)]; - mr = c->c.ptr.p_double[4*(i+1)+1]; - - /* - *calculating roots and extremums at [X[i],X[i+1]] - */ - solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); - - /* - *searching roots - */ - if( tnr>0 ) - { - - /* - *re-init tR - */ - if( tnr>=1 ) - { - tr.ptr.p_double[0] = x0; - } - if( tnr>=2 ) - { - tr.ptr.p_double[1] = x1; - } - if( tnr==3 ) - { - tr.ptr.p_double[2] = x2; - } - - /* - *start root selection - */ - if( *nr>0 ) - { - if( ae_fp_neq(tmpr.ptr.p_double[*nr-1],x0) ) - { - - /* - *previous segment was't constant identical zero - */ - if( nstep ) - { - for(j=0; j<=tnr-1; j++) - { - tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; - } - *nr = *nr+tnr; - } - else - { - - /* - *previous segment was constant identical zero - *and we must ignore [NR+j-1] root - */ - for(j=1; j<=tnr-1; j++) - { - tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; - } - *nr = *nr+tnr-1; - nstep = ae_true; - } - } - else - { - for(j=1; j<=tnr-1; j++) - { - tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; - } - *nr = *nr+tnr-1; - } - } - else - { - - /* - *write first root - */ - for(j=0; j<=tnr-1; j++) - { - tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; - } - *nr = *nr+tnr; - } - } - else - { - if( tnr==-1 ) - { - - /* - *decrement 'NR' if at previous step was written a root - *(previous segment identical zero) - */ - if( *nr>0&&nstep ) - { - *nr = *nr-1; - } - - /* - *previous segment is't constant - */ - if( nstep ) - { - nstep = ae_false; - } - - /* - *rewrite 'DR' - */ - if( !*dr ) - { - *dr = ae_true; - } - } - } - - /* - *searching extremums - *write all term like extremums - */ - if( tne==1 ) - { - if( *ne>0 ) - { - - /* - *just ignore identical extremums - *because he must be one - */ - if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) - { - tmpc.ptr.p_double[*ne] = ex0; - tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); - *ne = *ne+2; - } - } - else - { - - /* - *write first extremum and it function value - */ - tmpc.ptr.p_double[*ne] = ex0; - tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); - *ne = *ne+2; - } - } - else - { - if( tne==2 ) - { - if( *ne>0 ) - { - - /* - *ignore identical extremum - */ - if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) - { - tmpc.ptr.p_double[*ne] = ex0; - tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); - *ne = *ne+2; - } - } - else - { - - /* - *write first extremum - */ - tmpc.ptr.p_double[*ne] = ex0; - tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); - *ne = *ne+2; - } - - /* - *write second extremum - */ - tmpc.ptr.p_double[*ne] = ex1; - tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i]); - *ne = *ne+2; - } - else - { - if( tne==-1 ) - { - if( !*de ) - { - *de = ae_true; - } - } - } - } - } - - /* - *checking of arrays - *get number of extremums (tNe=NE/2) - *initialize pL as value F0(X[0]) and - *initialize pR as value Fn-1(X[N]) - */ - tne = *ne/2; - *ne = 0; - pl = c->c.ptr.p_double[0]; - pr = c->c.ptr.p_double[4*(c->n-1)]; - for(i=0; i<=tne-1; i++) - { - if( i>0&&ix.ptr.p_double[0]) ) - { - if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) - { - - /* - *maximum - */ - tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; - tmpet.ptr.p_int[*ne] = -1; - *ne = *ne+1; - } - else - { - if( ae_fp_less(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) - { - - /* - *minimum - */ - tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; - tmpet.ptr.p_int[*ne] = 1; - *ne = *ne+1; - } - } - } - } - else - { - if( i==tne-1 ) - { - if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[c->n-1]) ) - { - if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],pr) ) - { - - /* - *maximum - */ - tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; - tmpet.ptr.p_int[*ne] = -1; - *ne = *ne+1; - } - else - { - if( ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_less(tmpc.ptr.p_double[2*i+1],pr) ) - { - - /* - *minimum - */ - tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; - tmpet.ptr.p_int[*ne] = 1; - *ne = *ne+1; - } - } - } - } - } - } - } - - /* - *final results - *allocate R, E, ET - */ - rvectorsetlengthatleast(r, *nr, _state); - rvectorsetlengthatleast(e, *ne, _state); - ivectorsetlengthatleast(et, *ne, _state); - - /* - *write result for extremus and their types - */ - for(i=0; i<=*ne-1; i++) - { - e->ptr.p_double[i] = tmpe.ptr.p_double[i]; - et->ptr.p_int[i] = tmpet.ptr.p_int[i]; - } - - /* - *write result for roots - */ - for(i=0; i<=*nr-1; i++) - { - r->ptr.p_double[i] = tmpr.ptr.p_double[i]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Heap sort. -*************************************************************************/ -void heapsortdpoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* d, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector rbuf; - ae_vector ibuf; - ae_vector rbuf2; - ae_vector ibuf2; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true); - ae_vector_init(&rbuf2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ibuf2, 0, DT_INT, _state, ae_true); - - ae_vector_set_length(&ibuf, n, _state); - ae_vector_set_length(&rbuf, n, _state); - for(i=0; i<=n-1; i++) - { - ibuf.ptr.p_int[i] = i; - } - tagsortfasti(x, &ibuf, &rbuf2, &ibuf2, n, _state); - for(i=0; i<=n-1; i++) - { - rbuf.ptr.p_double[i] = y->ptr.p_double[ibuf.ptr.p_int[i]]; - } - ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - rbuf.ptr.p_double[i] = d->ptr.p_double[ibuf.ptr.p_int[i]]; - } - ae_v_move(&d->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -This procedure search roots of an quadratic equation inside [0;1] and it number of roots. - -INPUT PARAMETERS: - P0 - value of a function at 0 - M0 - value of a derivative at 0 - P1 - value of a function at 1 - M1 - value of a derivative at 1 - -OUTPUT PARAMETERS: - X0 - first root of an equation - X1 - second root of an equation - NR - number of roots - -RESTRICTIONS OF PARAMETERS: - -Parameters for this procedure has't to be zero simultaneously. Is expected, -that input polinom is't degenerate or constant identicaly ZERO. - - -REMARK: - -The procedure always fill value for X1 and X2, even if it is't belongs to [0;1]. -But first true root(even if existing one) is in X1. -Number of roots is NR. - - -- ALGLIB PROJECT -- - Copyright 26.09.2011 by Bochkanov Sergey -*************************************************************************/ -void solvepolinom2(double p0, - double m0, - double p1, - double m1, - double* x0, - double* x1, - ae_int_t* nr, - ae_state *_state) -{ - double a; - double b; - double c; - double dd; - double tmp; - double exf; - double extr; - - *x0 = 0; - *x1 = 0; - *nr = 0; - - - /* - *calculate parameters for equation: A, B and C - */ - a = 6*p0+3*m0-6*p1+3*m1; - b = -6*p0-4*m0+6*p1-2*m1; - c = m0; - - /* - *check case, when A=0 - *we are considering the linear equation - */ - if( ae_fp_eq(a,0) ) - { - - /* - *B<>0 and root inside [0;1] - *one root - */ - if( (ae_fp_neq(b,0)&&ae_sign(c, _state)*ae_sign(b, _state)<=0)&&ae_fp_greater_eq(ae_fabs(b, _state),ae_fabs(c, _state)) ) - { - *x0 = -c/b; - *nr = 1; - return; - } - else - { - *nr = 0; - return; - } - } - - /* - *consider case, when extremumu outside (0;1) - *exist one root only - */ - if( ae_fp_less_eq(ae_fabs(2*a, _state),ae_fabs(b, _state))||ae_sign(b, _state)*ae_sign(a, _state)>=0 ) - { - if( ae_sign(m0, _state)*ae_sign(m1, _state)>0 ) - { - *nr = 0; - return; - } - - /* - *consider case, when the one exist - *same sign of derivative - */ - if( ae_sign(m0, _state)*ae_sign(m1, _state)<0 ) - { - *nr = 1; - extr = -b/(2*a); - dd = b*b-4*a*c; - if( ae_fp_less(dd,0) ) - { - return; - } - *x0 = (-b-ae_sqrt(dd, _state))/(2*a); - *x1 = (-b+ae_sqrt(dd, _state))/(2*a); - if( (ae_fp_greater_eq(extr,1)&&ae_fp_less_eq(*x1,extr))||(ae_fp_less_eq(extr,0)&&ae_fp_greater_eq(*x1,extr)) ) - { - *x0 = *x1; - } - return; - } - - /* - *consider case, when the one is 0 - */ - if( ae_fp_eq(m0,0) ) - { - *x0 = 0; - *nr = 1; - return; - } - if( ae_fp_eq(m1,0) ) - { - *x0 = 1; - *nr = 1; - return; - } - } - else - { - - /* - *consider case, when both of derivatives is 0 - */ - if( ae_fp_eq(m0,0)&&ae_fp_eq(m1,0) ) - { - *x0 = 0; - *x1 = 1; - *nr = 2; - return; - } - - /* - *consider case, when derivative at 0 is 0, and derivative at 1 is't 0 - */ - if( ae_fp_eq(m0,0)&&ae_fp_neq(m1,0) ) - { - dd = b*b-4*a*c; - if( ae_fp_less(dd,0) ) - { - *x0 = 0; - *nr = 1; - return; - } - *x0 = (-b-ae_sqrt(dd, _state))/(2*a); - *x1 = (-b+ae_sqrt(dd, _state))/(2*a); - extr = -b/(2*a); - exf = a*extr*extr+b*extr+c; - if( ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) - { - *x0 = 0; - *nr = 1; - return; - } - else - { - if( ae_fp_greater(extr,*x0) ) - { - *x0 = 0; - } - else - { - *x1 = 0; - } - *nr = 2; - - /* - *roots must placed ascending - */ - if( ae_fp_greater(*x0,*x1) ) - { - tmp = *x0; - *x0 = *x1; - *x1 = tmp; - } - return; - } - } - if( ae_fp_eq(m1,0)&&ae_fp_neq(m0,0) ) - { - dd = b*b-4*a*c; - if( ae_fp_less(dd,0) ) - { - *x0 = 1; - *nr = 1; - return; - } - *x0 = (-b-ae_sqrt(dd, _state))/(2*a); - *x1 = (-b+ae_sqrt(dd, _state))/(2*a); - extr = -b/(2*a); - exf = a*extr*extr+b*extr+c; - if( ae_sign(exf, _state)*ae_sign(m0, _state)>0 ) - { - *x0 = 1; - *nr = 1; - return; - } - else - { - if( ae_fp_less(extr,*x0) ) - { - *x0 = 1; - } - else - { - *x1 = 1; - } - *nr = 2; - - /* - *roots must placed ascending - */ - if( ae_fp_greater(*x0,*x1) ) - { - tmp = *x0; - *x0 = *x1; - *x1 = tmp; - } - return; - } - } - else - { - extr = -b/(2*a); - exf = a*extr*extr+b*extr+c; - if( ae_sign(exf, _state)*ae_sign(m0, _state)>0&&ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) - { - *nr = 0; - return; - } - dd = b*b-4*a*c; - if( ae_fp_less(dd,0) ) - { - *nr = 0; - return; - } - *x0 = (-b-ae_sqrt(dd, _state))/(2*a); - *x1 = (-b+ae_sqrt(dd, _state))/(2*a); - - /* - *if EXF and m0, EXF and m1 has different signs, then equation has two roots - */ - if( ae_sign(exf, _state)*ae_sign(m0, _state)<0&&ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) - { - *nr = 2; - - /* - *roots must placed ascending - */ - if( ae_fp_greater(*x0,*x1) ) - { - tmp = *x0; - *x0 = *x1; - *x1 = tmp; - } - return; - } - else - { - *nr = 1; - if( ae_sign(exf, _state)*ae_sign(m0, _state)<0 ) - { - if( ae_fp_less(*x1,extr) ) - { - *x0 = *x1; - } - return; - } - if( ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) - { - if( ae_fp_greater(*x1,extr) ) - { - *x0 = *x1; - } - return; - } - } - } - } -} - - -/************************************************************************* -This procedure search roots of an cubic equation inside [A;B], it number of roots -and number of extremums. - -INPUT PARAMETERS: - pA - value of a function at A - mA - value of a derivative at A - pB - value of a function at B - mB - value of a derivative at B - A0 - left border [A0;B0] - B0 - right border [A0;B0] - -OUTPUT PARAMETERS: - X0 - first root of an equation - X1 - second root of an equation - X2 - third root of an equation - EX0 - first extremum of a function - EX0 - second extremum of a function - NR - number of roots - NR - number of extrmums - -RESTRICTIONS OF PARAMETERS: - -Length of [A;B] must be positive and is't zero, i.e. A<>B and AB - */ - ae_assert(ae_fp_less(a,b), "\nSolveCubicPolinom: incorrect borders for [A;B]!\n", _state); - - /* - *case 1 - *function can be identicaly to ZERO - */ - if( ((ae_fp_eq(ma,0)&&ae_fp_eq(mb,0))&&ae_fp_eq(pa,pb))&&ae_fp_eq(pa,0) ) - { - *nr = -1; - *ne = -1; - return; - } - if( (ae_fp_eq(ma,0)&&ae_fp_eq(mb,0))&&ae_fp_eq(pa,pb) ) - { - *nr = 0; - *ne = -1; - return; - } - tmpma = ma*(b-a); - tmpmb = mb*(b-a); - solvepolinom2(pa, tmpma, pb, tmpmb, ex0, ex1, ne, _state); - *ex0 = spline1d_rescaleval(0, 1, a, b, *ex0, _state); - *ex1 = spline1d_rescaleval(0, 1, a, b, *ex1, _state); - - /* - *case 3.1 - *no extremums at [A;B] - */ - if( *ne==0 ) - { - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, 1, x0, _state); - if( *nr==1 ) - { - *x0 = spline1d_rescaleval(0, 1, a, b, *x0, _state); - } - return; - } - - /* - *case 3.2 - *one extremum - */ - if( *ne==1 ) - { - if( ae_fp_eq(*ex0,a)||ae_fp_eq(*ex0,b) ) - { - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, 1, x0, _state); - if( *nr==1 ) - { - *x0 = spline1d_rescaleval(0, 1, a, b, *x0, _state); - } - return; - } - else - { - *nr = 0; - i = 0; - tex0 = spline1d_rescaleval(a, b, 0, 1, *ex0, _state); - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, tex0, x0, _state)+(*nr); - if( *nr>i ) - { - tempdata->ptr.p_double[i] = spline1d_rescaleval(0, tex0, a, *ex0, *x0, _state); - i = i+1; - } - *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, 1, x0, _state)+(*nr); - if( *nr>i ) - { - *x0 = spline1d_rescaleval(tex0, 1, *ex0, b, *x0, _state); - if( i>0 ) - { - if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - else - { - *nr = *nr-1; - } - } - else - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - } - if( *nr>0 ) - { - *x0 = tempdata->ptr.p_double[0]; - if( *nr>1 ) - { - *x1 = tempdata->ptr.p_double[1]; - } - return; - } - } - return; - } - else - { - - /* - *case 3.3 - *two extremums(or more, but it's impossible) - * - * - *case 3.3.0 - *both extremums at the border - */ - if( ae_fp_eq(*ex0,a)&&ae_fp_eq(*ex1,b) ) - { - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, 1, x0, _state); - if( *nr==1 ) - { - *x0 = spline1d_rescaleval(0, 1, a, b, *x0, _state); - } - return; - } - if( ae_fp_eq(*ex0,a)&&ae_fp_neq(*ex1,b) ) - { - *nr = 0; - i = 0; - tex1 = spline1d_rescaleval(a, b, 0, 1, *ex1, _state); - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, tex1, x0, _state)+(*nr); - if( *nr>i ) - { - tempdata->ptr.p_double[i] = spline1d_rescaleval(0, tex1, a, *ex1, *x0, _state); - i = i+1; - } - *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, 1, x0, _state)+(*nr); - if( *nr>i ) - { - *x0 = spline1d_rescaleval(tex1, 1, *ex1, b, *x0, _state); - if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - else - { - *nr = *nr-1; - } - } - if( *nr>0 ) - { - *x0 = tempdata->ptr.p_double[0]; - if( *nr>1 ) - { - *x1 = tempdata->ptr.p_double[1]; - } - return; - } - } - if( ae_fp_eq(*ex1,b)&&ae_fp_neq(*ex0,a) ) - { - *nr = 0; - i = 0; - tex0 = spline1d_rescaleval(a, b, 0, 1, *ex0, _state); - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, tex0, x0, _state)+(*nr); - if( *nr>i ) - { - tempdata->ptr.p_double[i] = spline1d_rescaleval(0, tex0, a, *ex0, *x0, _state); - i = i+1; - } - *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, 1, x0, _state)+(*nr); - if( *nr>i ) - { - *x0 = spline1d_rescaleval(tex0, 1, *ex0, b, *x0, _state); - if( i>0 ) - { - if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - else - { - *nr = *nr-1; - } - } - else - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - } - if( *nr>0 ) - { - *x0 = tempdata->ptr.p_double[0]; - if( *nr>1 ) - { - *x1 = tempdata->ptr.p_double[1]; - } - return; - } - } - else - { - - /* - *case 3.3.2 - *both extremums inside (0;1) - */ - *nr = 0; - i = 0; - tex0 = spline1d_rescaleval(a, b, 0, 1, *ex0, _state); - tex1 = spline1d_rescaleval(a, b, 0, 1, *ex1, _state); - *nr = bisectmethod(pa, tmpma, pb, tmpmb, 0, tex0, x0, _state)+(*nr); - if( *nr>i ) - { - tempdata->ptr.p_double[i] = spline1d_rescaleval(0, tex0, a, *ex0, *x0, _state); - i = i+1; - } - *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, tex1, x0, _state)+(*nr); - if( *nr>i ) - { - *x0 = spline1d_rescaleval(tex0, tex1, *ex0, *ex1, *x0, _state); - if( i>0 ) - { - if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - else - { - *nr = *nr-1; - } - } - else - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - } - *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, 1, x0, _state)+(*nr); - if( *nr>i ) - { - *x0 = spline1d_rescaleval(tex1, 1, *ex1, b, *x0, _state); - if( i>0 ) - { - if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - else - { - *nr = *nr-1; - } - } - else - { - tempdata->ptr.p_double[i] = *x0; - i = i+1; - } - } - - /* - *write are found roots - */ - if( *nr>0 ) - { - *x0 = tempdata->ptr.p_double[0]; - if( *nr>1 ) - { - *x1 = tempdata->ptr.p_double[1]; - } - if( *nr>2 ) - { - *x2 = tempdata->ptr.p_double[2]; - } - return; - } - } - } -} - - -/************************************************************************* -Function for searching a root at [A;B] by bisection method and return number of roots -(0 or 1) - -INPUT PARAMETERS: - pA - value of a function at A - mA - value of a derivative at A - pB - value of a function at B - mB - value of a derivative at B - A0 - left border [A0;B0] - B0 - right border [A0;B0] - -RESTRICTIONS OF PARAMETERS: - -We assume, that B0>A0. - - -REMARK: - -Assume, that exist one root only at [A;B], else -function may be work incorrectly. -The function don't check value A0,B0! - - -- ALGLIB PROJECT -- - Copyright 26.09.2011 by Bochkanov Sergey -*************************************************************************/ -ae_int_t bisectmethod(double pa, - double ma, - double pb, - double mb, - double a, - double b, - double* x, - ae_state *_state) -{ - double vacuum; - double eps; - double a0; - double b0; - double m; - double lf; - double rf; - double mf; - ae_int_t result; - - *x = 0; - - - /* - *accuracy - */ - eps = 1000*(b-a)*ae_machineepsilon; - - /* - *initialization left and right borders - */ - a0 = a; - b0 = b; - - /* - *initialize function value at 'A' and 'B' - */ - spline1d_hermitecalc(pa, ma, pb, mb, a, &lf, &vacuum, _state); - spline1d_hermitecalc(pa, ma, pb, mb, b, &rf, &vacuum, _state); - - /* - *check, that 'A' and 'B' are't roots, - *and that root exist - */ - if( ae_sign(lf, _state)*ae_sign(rf, _state)>0 ) - { - result = 0; - return result; - } - else - { - if( ae_fp_eq(lf,0) ) - { - *x = a; - result = 1; - return result; - } - else - { - if( ae_fp_eq(rf,0) ) - { - *x = b; - result = 1; - return result; - } - } - } - - /* - *searching a root - */ - do - { - m = (b0+a0)/2; - spline1d_hermitecalc(pa, ma, pb, mb, a0, &lf, &vacuum, _state); - spline1d_hermitecalc(pa, ma, pb, mb, b0, &rf, &vacuum, _state); - spline1d_hermitecalc(pa, ma, pb, mb, m, &mf, &vacuum, _state); - if( ae_sign(mf, _state)*ae_sign(lf, _state)<0 ) - { - b0 = m; - } - else - { - if( ae_sign(mf, _state)*ae_sign(rf, _state)<0 ) - { - a0 = m; - } - else - { - if( ae_fp_eq(lf,0) ) - { - *x = a0; - result = 1; - return result; - } - if( ae_fp_eq(rf,0) ) - { - *x = b0; - result = 1; - return result; - } - if( ae_fp_eq(mf,0) ) - { - *x = m; - result = 1; - return result; - } - } - } - } - while(ae_fp_greater_eq(ae_fabs(b0-a0, _state),eps)); - *x = m; - result = 1; - return result; -} - - -/************************************************************************* -This function builds monotone cubic Hermite interpolant. This interpolant -is monotonic in [x(0),x(n-1)] and is constant outside of this interval. - -In case y[] form non-monotonic sequence, interpolant is piecewise -monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will -monotonically grow at [0..2] and monotonically decrease at [2..4]. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. Subroutine automatically - sorts points, so caller may pass unsorted array. - Y - function values, array[0..N-1] - N - the number of points(N>=2). - -OUTPUT PARAMETERS: - C - spline interpolant. - - -- ALGLIB PROJECT -- - Copyright 21.06.2012 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildmonotone(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector d; - ae_vector ex; - ae_vector ey; - ae_vector p; - double delta; - double alpha; - double beta; - ae_int_t tmpn; - ae_int_t sn; - double ca; - double cb; - double epsilon; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _spline1dinterpolant_clear(c); - ae_vector_init(&d, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ey, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * Check lengths of arguments - */ - ae_assert(n>=2, "Spline1DBuildMonotone: N<2", _state); - ae_assert(x->cnt>=n, "Spline1DBuildMonotone: Length(X)cnt>=n, "Spline1DBuildMonotone: Length(Y)ptr.p_double[0]-ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state); - ex.ptr.p_double[n-1] = x->ptr.p_double[n-3]+ae_fabs(x->ptr.p_double[n-3]-x->ptr.p_double[n-4], _state); - ey.ptr.p_double[0] = y->ptr.p_double[0]; - ey.ptr.p_double[n-1] = y->ptr.p_double[n-3]; - for(i=1; i<=n-2; i++) - { - ex.ptr.p_double[i] = x->ptr.p_double[i-1]; - ey.ptr.p_double[i] = y->ptr.p_double[i-1]; - } - - /* - * Init sign of the function for first segment - */ - i = 0; - ca = 0; - do - { - ca = ey.ptr.p_double[i+1]-ey.ptr.p_double[i]; - i = i+1; - } - while(!(ae_fp_neq(ca,0)||i>n-2)); - if( ae_fp_neq(ca,0) ) - { - ca = ca/ae_fabs(ca, _state); - } - i = 0; - while(i=2, "Spline1DBuildMonotone: internal error", _state); - - /* - * Calculate derivatives for current segment - */ - d.ptr.p_double[i] = 0; - d.ptr.p_double[sn-1] = 0; - for(j=i+1; j<=sn-2; j++) - { - d.ptr.p_double[j] = ((ey.ptr.p_double[j]-ey.ptr.p_double[j-1])/(ex.ptr.p_double[j]-ex.ptr.p_double[j-1])+(ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]))/2; - } - for(j=i; j<=sn-2; j++) - { - delta = (ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]); - if( ae_fp_less_eq(ae_fabs(delta, _state),epsilon) ) - { - d.ptr.p_double[j] = 0; - d.ptr.p_double[j+1] = 0; - } - else - { - alpha = d.ptr.p_double[j]/delta; - beta = d.ptr.p_double[j+1]/delta; - if( ae_fp_neq(alpha,0) ) - { - cb = alpha*ae_sqrt(1+ae_sqr(beta/alpha, _state), _state); - } - else - { - if( ae_fp_neq(beta,0) ) - { - cb = beta; - } - else - { - continue; - } - } - if( ae_fp_greater(cb,3) ) - { - d.ptr.p_double[j] = 3*alpha*delta/cb; - d.ptr.p_double[j+1] = 3*beta*delta/cb; - } - } - } - - /* - * Transition to next segment - */ - i = sn-1; - } - spline1dbuildhermite(&ex, &ey, &d, n, c, _state); - c->continuity = 2; - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal version of Spline1DGridDiffCubic. - -Accepts pre-ordered X/Y, temporary arrays (which may be preallocated, if -you want to save time, or not) and output array (which may be preallocated -too). - -Y is passed as var-parameter because we may need to force last element to -be equal to the first one (if periodic boundary conditions are specified). - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -static void spline1d_spline1dgriddiffcubicinternal(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d, - /* Real */ ae_vector* a1, - /* Real */ ae_vector* a2, - /* Real */ ae_vector* a3, - /* Real */ ae_vector* b, - /* Real */ ae_vector* dt, - ae_state *_state) -{ - ae_int_t i; - - - - /* - * allocate arrays - */ - if( d->cntcntcntcntcntcntptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); - d->ptr.p_double[1] = d->ptr.p_double[0]; - return; - } - if( (n==2&&boundltype==-1)&&boundrtype==-1 ) - { - d->ptr.p_double[0] = 0; - d->ptr.p_double[1] = 0; - return; - } - - /* - * Periodic and non-periodic boundary conditions are - * two separate classes - */ - if( boundrtype==-1&&boundltype==-1 ) - { - - /* - * Periodic boundary conditions - */ - y->ptr.p_double[n-1] = y->ptr.p_double[0]; - - /* - * Boundary conditions at N-1 points - * (one point less because last point is the same as first point). - */ - a1->ptr.p_double[0] = x->ptr.p_double[1]-x->ptr.p_double[0]; - a2->ptr.p_double[0] = 2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); - a3->ptr.p_double[0] = x->ptr.p_double[n-1]-x->ptr.p_double[n-2]; - b->ptr.p_double[0] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])*(x->ptr.p_double[1]-x->ptr.p_double[0])+3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); - for(i=1; i<=n-2; i++) - { - - /* - * Although last point is [N-2], we use X[N-1] and Y[N-1] - * (because of periodicity) - */ - a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; - a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); - a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; - b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); - } - - /* - * Solve, add last point (with index N-1) - */ - spline1d_solvecyclictridiagonal(a1, a2, a3, b, n-1, dt, _state); - ae_v_move(&d->ptr.p_double[0], 1, &dt->ptr.p_double[0], 1, ae_v_len(0,n-2)); - d->ptr.p_double[n-1] = d->ptr.p_double[0]; - } - else - { - - /* - * Non-periodic boundary condition. - * Left boundary conditions. - */ - if( boundltype==0 ) - { - a1->ptr.p_double[0] = 0; - a2->ptr.p_double[0] = 1; - a3->ptr.p_double[0] = 1; - b->ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); - } - if( boundltype==1 ) - { - a1->ptr.p_double[0] = 0; - a2->ptr.p_double[0] = 1; - a3->ptr.p_double[0] = 0; - b->ptr.p_double[0] = boundl; - } - if( boundltype==2 ) - { - a1->ptr.p_double[0] = 0; - a2->ptr.p_double[0] = 2; - a3->ptr.p_double[0] = 1; - b->ptr.p_double[0] = 3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-0.5*boundl*(x->ptr.p_double[1]-x->ptr.p_double[0]); - } - - /* - * Central conditions - */ - for(i=1; i<=n-2; i++) - { - a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; - a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); - a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; - b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); - } - - /* - * Right boundary conditions - */ - if( boundrtype==0 ) - { - a1->ptr.p_double[n-1] = 1; - a2->ptr.p_double[n-1] = 1; - a3->ptr.p_double[n-1] = 0; - b->ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); - } - if( boundrtype==1 ) - { - a1->ptr.p_double[n-1] = 0; - a2->ptr.p_double[n-1] = 1; - a3->ptr.p_double[n-1] = 0; - b->ptr.p_double[n-1] = boundr; - } - if( boundrtype==2 ) - { - a1->ptr.p_double[n-1] = 1; - a2->ptr.p_double[n-1] = 2; - a3->ptr.p_double[n-1] = 0; - b->ptr.p_double[n-1] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])+0.5*boundr*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); - } - - /* - * Solve - */ - spline1d_solvetridiagonal(a1, a2, a3, b, n, d, _state); - } -} - - -/************************************************************************* -Internal subroutine. Heap sort. -*************************************************************************/ -static void spline1d_heapsortpoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector bufx; - ae_vector bufy; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true); - - tagsortfastr(x, y, &bufx, &bufy, n, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Heap sort. - -Accepts: - X, Y - points - P - empty or preallocated array - -Returns: - X, Y - sorted by X - P - array of permutations; I-th position of output - arrays X/Y contains (X[P[I]],Y[P[I]]) -*************************************************************************/ -static void spline1d_heapsortppoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Integer */ ae_vector* p, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector rbuf; - ae_vector ibuf; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true); - - if( p->cntptr.p_int[i] = i; - } - tagsortfasti(x, p, &rbuf, &ibuf, n, _state); - for(i=0; i<=n-1; i++) - { - rbuf.ptr.p_double[i] = y->ptr.p_double[p->ptr.p_int[i]]; - } - ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Tridiagonal solver. Solves - -( B[0] C[0] -( A[1] B[1] C[1] ) -( A[2] B[2] C[2] ) -( .......... ) * X = D -( .......... ) -( A[N-2] B[N-2] C[N-2] ) -( A[N-1] B[N-1] ) - -*************************************************************************/ -static void spline1d_solvetridiagonal(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - ae_int_t n, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _b; - ae_vector _d; - ae_int_t k; - double t; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_b, b, _state, ae_true); - b = &_b; - ae_vector_init_copy(&_d, d, _state, ae_true); - d = &_d; - - if( x->cntptr.p_double[k]/b->ptr.p_double[k-1]; - b->ptr.p_double[k] = b->ptr.p_double[k]-t*c->ptr.p_double[k-1]; - d->ptr.p_double[k] = d->ptr.p_double[k]-t*d->ptr.p_double[k-1]; - } - x->ptr.p_double[n-1] = d->ptr.p_double[n-1]/b->ptr.p_double[n-1]; - for(k=n-2; k>=0; k--) - { - x->ptr.p_double[k] = (d->ptr.p_double[k]-c->ptr.p_double[k]*x->ptr.p_double[k+1])/b->ptr.p_double[k]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Cyclic tridiagonal solver. Solves - -( B[0] C[0] A[0] ) -( A[1] B[1] C[1] ) -( A[2] B[2] C[2] ) -( .......... ) * X = D -( .......... ) -( A[N-2] B[N-2] C[N-2] ) -( C[N-1] A[N-1] B[N-1] ) -*************************************************************************/ -static void spline1d_solvecyclictridiagonal(/* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - ae_int_t n, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _b; - ae_int_t k; - double alpha; - double beta; - double gamma; - ae_vector y; - ae_vector z; - ae_vector u; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_b, b, _state, ae_true); - b = &_b; - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&z, 0, DT_REAL, _state, ae_true); - ae_vector_init(&u, 0, DT_REAL, _state, ae_true); - - if( x->cntptr.p_double[0]; - alpha = c->ptr.p_double[n-1]; - gamma = -b->ptr.p_double[0]; - b->ptr.p_double[0] = 2*b->ptr.p_double[0]; - b->ptr.p_double[n-1] = b->ptr.p_double[n-1]-alpha*beta/gamma; - ae_vector_set_length(&u, n, _state); - for(k=0; k<=n-1; k++) - { - u.ptr.p_double[k] = 0; - } - u.ptr.p_double[0] = gamma; - u.ptr.p_double[n-1] = alpha; - spline1d_solvetridiagonal(a, b, c, d, n, &y, _state); - spline1d_solvetridiagonal(a, b, c, &u, n, &z, _state); - for(k=0; k<=n-1; k++) - { - x->ptr.p_double[k] = y.ptr.p_double[k]-(y.ptr.p_double[0]+beta/gamma*y.ptr.p_double[n-1])/(1+z.ptr.p_double[0]+beta/gamma*z.ptr.p_double[n-1])*z.ptr.p_double[k]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. Three-point differentiation -*************************************************************************/ -static double spline1d_diffthreepoint(double t, - double x0, - double f0, - double x1, - double f1, - double x2, - double f2, - ae_state *_state) -{ - double a; - double b; - double result; - - - t = t-x0; - x1 = x1-x0; - x2 = x2-x0; - a = (f2-f0-x2/x1*(f1-f0))/(ae_sqr(x2, _state)-x1*x2); - b = (f1-f0-a*ae_sqr(x1, _state))/x1; - result = 2*a*t+b; - return result; -} - - -/************************************************************************* -Procedure for calculating value of a function is providet in the form of -Hermite polinom - -INPUT PARAMETERS: - P0 - value of a function at 0 - M0 - value of a derivative at 0 - P1 - value of a function at 1 - M1 - value of a derivative at 1 - T - point inside [0;1] - -OUTPUT PARAMETERS: - S - value of a function at T - B0 - value of a derivative function at T - - -- ALGLIB PROJECT -- - Copyright 26.09.2011 by Bochkanov Sergey -*************************************************************************/ -static void spline1d_hermitecalc(double p0, - double m0, - double p1, - double m1, - double t, - double* s, - double* ds, - ae_state *_state) -{ - - *s = 0; - *ds = 0; - - *s = p0*(1+2*t)*(1-t)*(1-t)+m0*t*(1-t)*(1-t)+p1*(3-2*t)*t*t+m1*t*t*(t-1); - *ds = -p0*6*t*(1-t)+m0*(1-t)*(1-3*t)+p1*6*t*(1-t)+m1*t*(3*t-2); -} - - -/************************************************************************* -Function for mapping from [A0;B0] to [A1;B1] - -INPUT PARAMETERS: - A0 - left border [A0;B0] - B0 - right border [A0;B0] - A1 - left border [A1;B1] - B1 - right border [A1;B1] - T - value inside [A0;B0] - -RESTRICTIONS OF PARAMETERS: - -We assume, that B0>A0 and B1>A1. But we chech, that T is inside [A0;B0], -and if TB0 then T - B1. - -INPUT PARAMETERS: - A0 - left border for segment [A0;B0] from 'T' is converted to [A1;B1] - B0 - right border for segment [A0;B0] from 'T' is converted to [A1;B1] - A1 - left border for segment [A1;B1] to 'T' is converted from [A0;B0] - B1 - right border for segment [A1;B1] to 'T' is converted from [A0;B0] - T - the parameter is mapped from [A0;B0] to [A1;B1] - -Result: - is converted value for 'T' from [A0;B0] to [A1;B1] - -REMARK: - -The function don't check value A0,B0 and A1,B1! - - -- ALGLIB PROJECT -- - Copyright 26.09.2011 by Bochkanov Sergey -*************************************************************************/ -static double spline1d_rescaleval(double a0, - double b0, - double a1, - double b1, - double t, - ae_state *_state) -{ - double result; - - - - /* - *return left border - */ - if( ae_fp_less_eq(t,a0) ) - { - result = a1; - return result; - } - - /* - *return right border - */ - if( ae_fp_greater_eq(t,b0) ) - { - result = b1; - return result; - } - - /* - *return value between left and right borders - */ - result = (b1-a1)*(t-a0)/(b0-a0)+a1; - return result; -} - - -ae_bool _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - spline1dinterpolant *p = (spline1dinterpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - spline1dinterpolant *dst = (spline1dinterpolant*)_dst; - spline1dinterpolant *src = (spline1dinterpolant*)_src; - dst->periodic = src->periodic; - dst->n = src->n; - dst->k = src->k; - dst->continuity = src->continuity; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _spline1dinterpolant_clear(void* _p) -{ - spline1dinterpolant *p = (spline1dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->c); -} - - -void _spline1dinterpolant_destroy(void* _p) -{ - spline1dinterpolant *p = (spline1dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->c); -} - - - - -/************************************************************************* -Fitting by polynomials in barycentric form. This function provides simple -unterface for unconstrained unweighted fitting. See PolynomialFitWC() if -you need constrained fitting. - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFitWC() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0 - * if given, only leading N elements of X/Y are used - * if not given, automatically determined from sizes of X/Y - M - number of basis functions (= polynomial_degree + 1), M>=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfit(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* p, - polynomialfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector w; - ae_vector xc; - ae_vector yc; - ae_vector dc; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _barycentricinterpolant_clear(p); - _polynomialfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dc, 0, DT_INT, _state, ae_true); - - ae_assert(n>0, "PolynomialFit: N<=0!", _state); - ae_assert(m>0, "PolynomialFit: M<=0!", _state); - ae_assert(x->cnt>=n, "PolynomialFit: Length(X)cnt>=n, "PolynomialFit: Length(Y)0. - * if given, only leading N elements of X/Y/W are used - * if not given, automatically determined from sizes of X/Y/W - XC - points where polynomial values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that P(XC[i])=YC[i] - * DC[i]=1 means that P'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* even simple constraints can be inconsistent, see Wikipedia article on - this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the one special cases, however, we can guarantee consistency. This - case is: M>1 and constraints on the function values (NOT DERIVATIVES) - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfitwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* p, - polynomialfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _w; - ae_vector _xc; - ae_vector _yc; - double xa; - double xb; - double sa; - double sb; - ae_vector xoriginal; - ae_vector yoriginal; - ae_vector y2; - ae_vector w2; - ae_vector tmp; - ae_vector tmp2; - ae_vector bx; - ae_vector by; - ae_vector bw; - ae_int_t i; - ae_int_t j; - double u; - double v; - double s; - ae_int_t relcnt; - lsfitreport lrep; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_w, w, _state, ae_true); - w = &_w; - ae_vector_init_copy(&_xc, xc, _state, ae_true); - xc = &_xc; - ae_vector_init_copy(&_yc, yc, _state, ae_true); - yc = &_yc; - *info = 0; - _barycentricinterpolant_clear(p); - _polynomialfitreport_clear(rep); - ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&by, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bw, 0, DT_REAL, _state, ae_true); - _lsfitreport_init(&lrep, _state, ae_true); - - ae_assert(n>0, "PolynomialFitWC: N<=0!", _state); - ae_assert(m>0, "PolynomialFitWC: M<=0!", _state); - ae_assert(k>=0, "PolynomialFitWC: K<0!", _state); - ae_assert(k=M!", _state); - ae_assert(x->cnt>=n, "PolynomialFitWC: Length(X)cnt>=n, "PolynomialFitWC: Length(Y)cnt>=n, "PolynomialFitWC: Length(W)cnt>=k, "PolynomialFitWC: Length(XC)cnt>=k, "PolynomialFitWC: Length(YC)cnt>=k, "PolynomialFitWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "PolynomialFitWC: one of DC[] is not 0 or 1!", _state); - } - - /* - * Scale X, Y, XC, YC. - * Solve scaled problem using internal Chebyshev fitting function. - */ - lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); - lsfit_internalchebyshevfit(x, y, w, n, xc, yc, dc, k, m, info, &tmp, &lrep, _state); - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Generate barycentric model and scale it - * * BX, BY store barycentric model nodes - * * FMatrix is reused (remember - it is at least MxM, what we need) - * - * Model initialization is done in O(M^2). In principle, it can be - * done in O(M*log(M)), but before it we solved task with O(N*M^2) - * complexity, so it is only a small amount of total time spent. - */ - ae_vector_set_length(&bx, m, _state); - ae_vector_set_length(&by, m, _state); - ae_vector_set_length(&bw, m, _state); - ae_vector_set_length(&tmp2, m, _state); - s = 1; - for(i=0; i<=m-1; i++) - { - if( m!=1 ) - { - u = ae_cos(ae_pi*i/(m-1), _state); - } - else - { - u = 0; - } - v = 0; - for(j=0; j<=m-1; j++) - { - if( j==0 ) - { - tmp2.ptr.p_double[j] = 1; - } - else - { - if( j==1 ) - { - tmp2.ptr.p_double[j] = u; - } - else - { - tmp2.ptr.p_double[j] = 2*u*tmp2.ptr.p_double[j-1]-tmp2.ptr.p_double[j-2]; - } - } - v = v+tmp.ptr.p_double[j]*tmp2.ptr.p_double[j]; - } - bx.ptr.p_double[i] = u; - by.ptr.p_double[i] = v; - bw.ptr.p_double[i] = s; - if( i==0||i==m-1 ) - { - bw.ptr.p_double[i] = 0.5*bw.ptr.p_double[i]; - } - s = -s; - } - barycentricbuildxyw(&bx, &by, &bw, m, p, _state); - barycentriclintransx(p, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); - barycentriclintransy(p, sb-sa, sa, _state); - - /* - * Scale absolute errors obtained from LSFitLinearW. - * Relative error should be calculated separately - * (because of shifting/scaling of the task) - */ - rep->taskrcond = lrep.taskrcond; - rep->rmserror = lrep.rmserror*(sb-sa); - rep->avgerror = lrep.avgerror*(sb-sa); - rep->maxerror = lrep.maxerror*(sb-sa); - rep->avgrelerror = 0; - relcnt = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(yoriginal.ptr.p_double[i],0) ) - { - rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(p, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); - relcnt = relcnt+1; - } - } - if( relcnt!=0 ) - { - rep->avgrelerror = rep->avgrelerror/relcnt; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Weghted rational least squares fitting using Floater-Hormann rational -functions with optimal D chosen from [0,9], with constraints and -individual weights. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least WEIGHTED root -mean square error) is chosen. Task is linear, so linear least squares -solver is used. Complexity of this computational scheme is O(N*M^2) -(mostly dominated by the least squares solver). - -SEE ALSO -* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual - weights and constraints. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - XC - points where function values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -1 means another errors in parameters passed - (N<=0, for example) - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroutine doesn't calculate task's condition number for K<>0. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained barycentric interpolants: -* excessive constraints can be inconsistent. Floater-Hormann basis - functions aren't as flexible as splines (although they are very smooth). -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function VALUES at the interval - boundaries. Note that consustency of the constraints on the function - DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines - which are more flexible). -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t d; - ae_int_t i; - double wrmscur; - double wrmsbest; - barycentricinterpolant locb; - barycentricfitreport locrep; - ae_int_t locinfo; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _barycentricinterpolant_clear(b); - _barycentricfitreport_clear(rep); - _barycentricinterpolant_init(&locb, _state, ae_true); - _barycentricfitreport_init(&locrep, _state, ae_true); - - ae_assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!", _state); - ae_assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!", _state); - ae_assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!", _state); - ae_assert(k=M!", _state); - ae_assert(x->cnt>=n, "BarycentricFitFloaterHormannWC: Length(X)cnt>=n, "BarycentricFitFloaterHormannWC: Length(Y)cnt>=n, "BarycentricFitFloaterHormannWC: Length(W)cnt>=k, "BarycentricFitFloaterHormannWC: Length(XC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(YC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!", _state); - } - - /* - * Find optimal D - * - * Info is -3 by default (degenerate constraints). - * If LocInfo will always be equal to -3, Info will remain equal to -3. - * If at least once LocInfo will be -4, Info will be -4. - */ - wrmsbest = ae_maxrealnumber; - rep->dbest = -1; - *info = -3; - for(d=0; d<=ae_minint(9, n-1, _state); d++) - { - lsfit_barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, &locinfo, &locb, &locrep, _state); - ae_assert((locinfo==-4||locinfo==-3)||locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!", _state); - if( locinfo>0 ) - { - - /* - * Calculate weghted RMS - */ - wrmscur = 0; - for(i=0; i<=n-1; i++) - { - wrmscur = wrmscur+ae_sqr(w->ptr.p_double[i]*(y->ptr.p_double[i]-barycentriccalc(&locb, x->ptr.p_double[i], _state)), _state); - } - wrmscur = ae_sqrt(wrmscur/n, _state); - if( ae_fp_less(wrmscur,wrmsbest)||rep->dbest<0 ) - { - barycentriccopy(&locb, b, _state); - rep->dbest = d; - *info = 1; - rep->rmserror = locrep.rmserror; - rep->avgerror = locrep.avgerror; - rep->avgrelerror = locrep.avgrelerror; - rep->maxerror = locrep.maxerror; - rep->taskrcond = locrep.taskrcond; - wrmsbest = wrmscur; - } - } - else - { - if( locinfo!=-3&&*info<0 ) - { - *info = locinfo; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormann(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector w; - ae_vector xc; - ae_vector yc; - ae_vector dc; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _barycentricinterpolant_clear(b); - _barycentricfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dc, 0, DT_INT, _state, ae_true); - - ae_assert(n>0, "BarycentricFitFloaterHormann: N<=0!", _state); - ae_assert(m>0, "BarycentricFitFloaterHormann: M<=0!", _state); - ae_assert(x->cnt>=n, "BarycentricFitFloaterHormann: Length(X)cnt>=n, "BarycentricFitFloaterHormann: Length(Y)0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalized(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - double rho, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector w; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "Spline1DFitPenalized: N<1!", _state); - ae_assert(m>=4, "Spline1DFitPenalized: M<4!", _state); - ae_assert(x->cnt>=n, "Spline1DFitPenalized: Length(X)cnt>=n, "Spline1DFitPenalized: Length(Y)0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - M - number of basis functions ( = number_of_nodes), M>=4. - Rho - regularization constant passed by user. It penalizes - nonlinearity in the regression spline. It is logarithmically - scaled, i.e. actual value of regularization constant is - calculated as 10^Rho. It is automatically scaled so that: - * Rho=2.0 corresponds to moderate amount of nonlinearity - * generally, it should be somewhere in the [-8.0,+8.0] - If you do not want to penalize nonlineary, - pass small Rho. Values as low as -15 should work. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD or - Cholesky decomposition; problem may be - too ill-conditioned (very rare) - S - spline interpolant. - Rep - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTE 1: additional nodes are added to the spline outside of the fitting -interval to force linearity when xmax(x,xc). It is done -for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so -it is natural to force linearity outside of this interval. - -NOTE 2: function automatically sorts points, so caller may pass unsorted -array. - - -- ALGLIB PROJECT -- - Copyright 19.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalizedw(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - ae_int_t m, - double rho, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _w; - ae_int_t i; - ae_int_t j; - ae_int_t b; - double v; - double relcnt; - double xa; - double xb; - double sa; - double sb; - ae_vector xoriginal; - ae_vector yoriginal; - double pdecay; - double tdecay; - ae_matrix fmatrix; - ae_vector fcolumn; - ae_vector y2; - ae_vector w2; - ae_vector xc; - ae_vector yc; - ae_vector dc; - double fdmax; - double admax; - ae_matrix amatrix; - ae_matrix d2matrix; - double fa; - double ga; - double fb; - double gb; - double lambdav; - ae_vector bx; - ae_vector by; - ae_vector bd1; - ae_vector bd2; - ae_vector tx; - ae_vector ty; - ae_vector td; - spline1dinterpolant bs; - ae_matrix nmatrix; - ae_vector rightpart; - fblslincgstate cgstate; - ae_vector c; - ae_vector tmp0; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_w, w, _state, ae_true); - w = &_w; - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&fcolumn, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dc, 0, DT_INT, _state, ae_true); - ae_matrix_init(&amatrix, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&d2matrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&by, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bd1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bd2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ty, 0, DT_REAL, _state, ae_true); - ae_vector_init(&td, 0, DT_REAL, _state, ae_true); - _spline1dinterpolant_init(&bs, _state, ae_true); - ae_matrix_init(&nmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&rightpart, 0, DT_REAL, _state, ae_true); - _fblslincgstate_init(&cgstate, _state, ae_true); - ae_vector_init(&c, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "Spline1DFitPenalizedW: N<1!", _state); - ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state); - ae_assert(x->cnt>=n, "Spline1DFitPenalizedW: Length(X)cnt>=n, "Spline1DFitPenalizedW: Length(Y)cnt>=n, "Spline1DFitPenalizedW: Length(W)ptr.p_double[i]*fcolumn.ptr.p_double[i], _state); - } - fdmax = ae_maxreal(fdmax, v, _state); - - /* - * Fill temporary with second derivatives of basis function - */ - ae_v_move(&d2matrix.ptr.pp_double[b][0], 1, &bd2.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - - /* - * * calculate penalty matrix A - * * calculate max of diagonal elements of A - * * calculate PDecay - coefficient before penalty matrix - */ - for(i=0; i<=m-1; i++) - { - for(j=i; j<=m-1; j++) - { - - /* - * calculate integral(B_i''*B_j'') where B_i and B_j are - * i-th and j-th basis splines. - * B_i and B_j are piecewise linear functions. - */ - v = 0; - for(b=0; b<=m-2; b++) - { - fa = d2matrix.ptr.pp_double[i][b]; - fb = d2matrix.ptr.pp_double[i][b+1]; - ga = d2matrix.ptr.pp_double[j][b]; - gb = d2matrix.ptr.pp_double[j][b+1]; - v = v+(bx.ptr.p_double[b+1]-bx.ptr.p_double[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3); - } - amatrix.ptr.pp_double[i][j] = v; - amatrix.ptr.pp_double[j][i] = v; - } - } - admax = 0; - for(i=0; i<=m-1; i++) - { - admax = ae_maxreal(admax, ae_fabs(amatrix.ptr.pp_double[i][i], _state), _state); - } - pdecay = lambdav*fdmax/admax; - - /* - * Calculate TDecay for Tikhonov regularization - */ - tdecay = fdmax*(1+pdecay)*10*ae_machineepsilon; - - /* - * Prepare system - * - * NOTE: FMatrix is spoiled during this process - */ - for(i=0; i<=n-1; i++) - { - v = w->ptr.p_double[i]; - ae_v_muld(&fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - rmatrixgemm(m, m, n, 1.0, &fmatrix, 0, 0, 1, &fmatrix, 0, 0, 0, 0.0, &nmatrix, 0, 0, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=m-1; j++) - { - nmatrix.ptr.pp_double[i][j] = nmatrix.ptr.pp_double[i][j]+pdecay*amatrix.ptr.pp_double[i][j]; - } - } - for(i=0; i<=m-1; i++) - { - nmatrix.ptr.pp_double[i][i] = nmatrix.ptr.pp_double[i][i]+tdecay; - } - for(i=0; i<=m-1; i++) - { - rightpart.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = y->ptr.p_double[i]*w->ptr.p_double[i]; - ae_v_addd(&rightpart.ptr.p_double[0], 1, &fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - - /* - * Solve system - */ - if( !spdmatrixcholesky(&nmatrix, m, ae_true, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - fblscholeskysolve(&nmatrix, 1.0, m, ae_true, &rightpart, &tmp0, _state); - ae_v_move(&c.ptr.p_double[0], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(0,m-1)); - - /* - * add nodes to force linearity outside of the fitting interval - */ - spline1dgriddiffcubic(&bx, &c, m, 2, 0.0, 2, 0.0, &bd1, _state); - ae_vector_set_length(&tx, m+2, _state); - ae_vector_set_length(&ty, m+2, _state); - ae_vector_set_length(&td, m+2, _state); - ae_v_move(&tx.ptr.p_double[1], 1, &bx.ptr.p_double[0], 1, ae_v_len(1,m)); - ae_v_move(&ty.ptr.p_double[1], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(1,m)); - ae_v_move(&td.ptr.p_double[1], 1, &bd1.ptr.p_double[0], 1, ae_v_len(1,m)); - tx.ptr.p_double[0] = tx.ptr.p_double[1]-(tx.ptr.p_double[2]-tx.ptr.p_double[1]); - ty.ptr.p_double[0] = ty.ptr.p_double[1]-td.ptr.p_double[1]*(tx.ptr.p_double[2]-tx.ptr.p_double[1]); - td.ptr.p_double[0] = td.ptr.p_double[1]; - tx.ptr.p_double[m+1] = tx.ptr.p_double[m]+(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); - ty.ptr.p_double[m+1] = ty.ptr.p_double[m]+td.ptr.p_double[m]*(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]); - td.ptr.p_double[m+1] = td.ptr.p_double[m]; - spline1dbuildhermite(&tx, &ty, &td, m+2, s, _state); - spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); - spline1dlintransy(s, sb-sa, sa, _state); - *info = 1; - - /* - * Fill report - */ - rep->rmserror = 0; - rep->avgerror = 0; - rep->avgrelerror = 0; - rep->maxerror = 0; - relcnt = 0; - spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state); - for(i=0; i<=n-1; i++) - { - v = (sb-sa)*fcolumn.ptr.p_double[i]+sa; - rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state); - rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state); - if( ae_fp_neq(yoriginal.ptr.p_double[i],0) ) - { - rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); - relcnt = relcnt+1; - } - rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state); - } - rep->rmserror = ae_sqrt(rep->rmserror/n, _state); - rep->avgerror = rep->avgerror/n; - if( ae_fp_neq(relcnt,0) ) - { - rep->avgrelerror = rep->avgrelerror/relcnt; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Weighted fitting by cubic spline, with constraints on function values or -derivatives. - -Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with continuous second -derivatives and non-fixed first derivatives at interval ends. Small -regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, - less smooth) - Spline1DFitCubic() - "lightweight" fitting by cubic splines, - without invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - S - spline interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function values AND/OR its - derivatives at the interval boundaries. -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubicwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_int_t i; - - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - - ae_assert(n>=1, "Spline1DFitCubicWC: N<1!", _state); - ae_assert(m>=4, "Spline1DFitCubicWC: M<4!", _state); - ae_assert(k>=0, "Spline1DFitCubicWC: K<0!", _state); - ae_assert(k=M!", _state); - ae_assert(x->cnt>=n, "Spline1DFitCubicWC: Length(X)cnt>=n, "Spline1DFitCubicWC: Length(Y)cnt>=n, "Spline1DFitCubicWC: Length(W)cnt>=k, "Spline1DFitCubicWC: Length(XC)cnt>=k, "Spline1DFitCubicWC: Length(YC)cnt>=k, "Spline1DFitCubicWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitCubicWC: DC[i] is neither 0 or 1!", _state); - } - lsfit_spline1dfitinternal(0, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state); -} - - -/************************************************************************* -Weighted fitting by Hermite spline, with constraints on function values -or first derivatives. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are Hermite splines. Small regularizing -term is used when solving constrained tasks (to improve stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, - more smooth) - Spline1DFitHermite() - "lightweight" Hermite fitting, without - invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4, - M IS EVEN! - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -2 means odd M was passed (which is not supported) - -1 means another errors in parameters passed - (N<=0, for example) - S - spline interpolant. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -IMPORTANT: - this subroitine supports only even M's - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the several special cases, however, we can guarantee consistency. -* one of this cases is M>=4 and constraints on the function value - (AND/OR its derivative) at the interval boundaries. -* another special case is M>=4 and ONE constraint on the function value - (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermitewc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_int_t i; - - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - - ae_assert(n>=1, "Spline1DFitHermiteWC: N<1!", _state); - ae_assert(m>=4, "Spline1DFitHermiteWC: M<4!", _state); - ae_assert(m%2==0, "Spline1DFitHermiteWC: M is odd!", _state); - ae_assert(k>=0, "Spline1DFitHermiteWC: K<0!", _state); - ae_assert(k=M!", _state); - ae_assert(x->cnt>=n, "Spline1DFitHermiteWC: Length(X)cnt>=n, "Spline1DFitHermiteWC: Length(Y)cnt>=n, "Spline1DFitHermiteWC: Length(W)cnt>=k, "Spline1DFitHermiteWC: Length(XC)cnt>=k, "Spline1DFitHermiteWC: Length(YC)cnt>=k, "Spline1DFitHermiteWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitHermiteWC: DC[i] is neither 0 or 1!", _state); - } - lsfit_spline1dfitinternal(1, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state); -} - - -/************************************************************************* -Least squares fitting by cubic spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information -about subroutine parameters (we don't duplicate it here because of length) - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector w; - ae_vector xc; - ae_vector yc; - ae_vector dc; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&dc, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "Spline1DFitCubic: N<1!", _state); - ae_assert(m>=4, "Spline1DFitCubic: M<4!", _state); - ae_assert(x->cnt>=n, "Spline1DFitCubic: Length(X)cnt>=n, "Spline1DFitCubic: Length(Y)=1, "Spline1DFitHermite: N<1!", _state); - ae_assert(m>=4, "Spline1DFitHermite: M<4!", _state); - ae_assert(m%2==0, "Spline1DFitHermite: M is odd!", _state); - ae_assert(x->cnt>=n, "Spline1DFitHermite: Length(X)cnt>=n, "Spline1DFitHermite: Length(Y)=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -1 incorrect N/M were specified - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearw(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - - ae_assert(n>=1, "LSFitLinearW: N<1!", _state); - ae_assert(m>=1, "LSFitLinearW: M<1!", _state); - ae_assert(y->cnt>=n, "LSFitLinearW: length(Y)cnt>=n, "LSFitLinearW: length(W)rows>=n, "LSFitLinearW: rows(FMatrix)cols>=m, "LSFitLinearW: cols(FMatrix)=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearwc(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_matrix* cmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _y; - ae_matrix _cmatrix; - ae_int_t i; - ae_int_t j; - ae_vector tau; - ae_matrix q; - ae_matrix f2; - ae_vector tmp; - ae_vector c0; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_matrix_init_copy(&_cmatrix, cmatrix, _state, ae_true); - cmatrix = &_cmatrix; - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&f2, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c0, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "LSFitLinearWC: N<1!", _state); - ae_assert(m>=1, "LSFitLinearWC: M<1!", _state); - ae_assert(k>=0, "LSFitLinearWC: K<0!", _state); - ae_assert(y->cnt>=n, "LSFitLinearWC: length(Y)cnt>=n, "LSFitLinearWC: length(W)rows>=n, "LSFitLinearWC: rows(FMatrix)cols>=m, "LSFitLinearWC: cols(FMatrix)rows>=k, "LSFitLinearWC: rows(CMatrix)cols>=m+1||k==0, "LSFitLinearWC: cols(CMatrix)=m ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Solve - */ - if( k==0 ) - { - - /* - * no constraints - */ - lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state); - } - else - { - - /* - * First, find general form solution of constraints system: - * * factorize C = L*Q - * * unpack Q - * * fill upper part of C with zeros (for RCond) - * - * We got C=C0+Q2'*y where Q2 is lower M-K rows of Q. - */ - rmatrixlq(cmatrix, k, m, &tau, _state); - rmatrixlqunpackq(cmatrix, k, m, &tau, m, &q, _state); - for(i=0; i<=k-1; i++) - { - for(j=i+1; j<=m-1; j++) - { - cmatrix->ptr.pp_double[i][j] = 0.0; - } - } - if( ae_fp_less(rmatrixlurcondinf(cmatrix, k, _state),1000*ae_machineepsilon) ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&tmp, k, _state); - for(i=0; i<=k-1; i++) - { - if( i>0 ) - { - v = ae_v_dotproduct(&cmatrix->ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1)); - } - else - { - v = 0; - } - tmp.ptr.p_double[i] = (cmatrix->ptr.pp_double[i][m]-v)/cmatrix->ptr.pp_double[i][i]; - } - ae_vector_set_length(&c0, m, _state); - for(i=0; i<=m-1; i++) - { - c0.ptr.p_double[i] = 0; - } - for(i=0; i<=k-1; i++) - { - v = tmp.ptr.p_double[i]; - ae_v_addd(&c0.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - - /* - * Second, prepare modified matrix F2 = F*Q2' and solve modified task - */ - ae_vector_set_length(&tmp, ae_maxint(n, m, _state)+1, _state); - ae_matrix_set_length(&f2, n, m-k, _state); - matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &c0, 0, m-1, -1.0, y, 0, n-1, 1.0, _state); - matrixmatrixmultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &q, k, m-1, 0, m-1, ae_true, 1.0, &f2, 0, n-1, 0, m-k-1, 0.0, &tmp, _state); - lsfit_lsfitlinearinternal(y, w, &f2, n, m-k, info, &tmp, rep, _state); - rep->taskrcond = -1; - if( *info<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * then, convert back to original answer: C = C0 + Q2'*Y0 - */ - ae_vector_set_length(c, m, _state); - ae_v_move(&c->ptr.p_double[0], 1, &c0.ptr.p_double[0], 1, ae_v_len(0,m-1)); - matrixvectormultiply(&q, k, m-1, 0, m-1, ae_true, &tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinear(/* Real */ ae_vector* y, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector w; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "LSFitLinear: N<1!", _state); - ae_assert(m>=1, "LSFitLinear: M<1!", _state); - ae_assert(y->cnt>=n, "LSFitLinear: length(Y)rows>=n, "LSFitLinear: rows(FMatrix)cols>=m, "LSFitLinear: cols(FMatrix)=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearc(/* Real */ ae_vector* y, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_matrix* cmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _y; - ae_vector w; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "LSFitLinearC: N<1!", _state); - ae_assert(m>=1, "LSFitLinearC: M<1!", _state); - ae_assert(k>=0, "LSFitLinearC: K<0!", _state); - ae_assert(y->cnt>=n, "LSFitLinearC: length(Y)rows>=n, "LSFitLinearC: rows(FMatrix)cols>=m, "LSFitLinearC: cols(FMatrix)rows>=k, "LSFitLinearC: rows(CMatrix)cols>=m+1||k==0, "LSFitLinearC: cols(CMatrix)1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewf(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - double diffstep, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateWF: N<1!", _state); - ae_assert(m>=1, "LSFitCreateWF: M<1!", _state); - ae_assert(k>=1, "LSFitCreateWF: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateWF: length(C)cnt>=n, "LSFitCreateWF: length(Y)cnt>=n, "LSFitCreateWF: length(W)rows>=n, "LSFitCreateWF: rows(X)cols>=m, "LSFitCreateWF: cols(X)teststep = 0; - state->diffstep = diffstep; - state->npoints = n; - state->nweights = n; - state->wkind = 1; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->taskw, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 0; - state->prevnpt = -1; - state->prevalgo = -1; - minlmcreatev(k, n, &state->c, diffstep, &state->optstate, _state); - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatef(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - double diffstep, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateF: N<1!", _state); - ae_assert(m>=1, "LSFitCreateF: M<1!", _state); - ae_assert(k>=1, "LSFitCreateF: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateF: length(C)cnt>=n, "LSFitCreateF: length(Y)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)teststep = 0; - state->diffstep = diffstep; - state->npoints = n; - state->wkind = 0; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 0; - state->prevnpt = -1; - state->prevalgo = -1; - minlmcreatev(k, n, &state->c, diffstep, &state->optstate, _state); - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient only. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also: - LSFitResults - LSFitCreateFG (fitting without weights) - LSFitCreateWFGH (fitting using Hessian) - LSFitCreateFGH (fitting using Hessian, without weights) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfg(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_bool cheapfg, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateWFG: N<1!", _state); - ae_assert(m>=1, "LSFitCreateWFG: M<1!", _state); - ae_assert(k>=1, "LSFitCreateWFG: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateWFG: length(C)cnt>=n, "LSFitCreateWFG: length(Y)cnt>=n, "LSFitCreateWFG: length(W)rows>=n, "LSFitCreateWFG: rows(X)cols>=m, "LSFitCreateWFG: cols(X)teststep = 0; - state->diffstep = 0; - state->npoints = n; - state->nweights = n; - state->wkind = 1; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->taskw, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_vector_set_length(&state->g, k, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 1; - state->prevnpt = -1; - state->prevalgo = -1; - if( cheapfg ) - { - minlmcreatevgj(k, n, &state->c, &state->optstate, _state); - } - else - { - minlmcreatevj(k, n, &state->c, &state->optstate, _state); - } - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Nonlinear least squares fitting using gradient only, without individual -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefg(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_bool cheapfg, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateFG: N<1!", _state); - ae_assert(m>=1, "LSFitCreateFG: M<1!", _state); - ae_assert(k>=1, "LSFitCreateFG: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateFG: length(C)cnt>=n, "LSFitCreateFG: length(Y)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)teststep = 0; - state->diffstep = 0; - state->npoints = n; - state->wkind = 0; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_vector_set_length(&state->g, k, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 1; - state->prevnpt = -1; - state->prevalgo = -1; - if( cheapfg ) - { - minlmcreatevgj(k, n, &state->c, &state->optstate, _state); - } - else - { - minlmcreatevj(k, n, &state->c, &state->optstate, _state); - } - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient/Hessian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfgh(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateWFGH: N<1!", _state); - ae_assert(m>=1, "LSFitCreateWFGH: M<1!", _state); - ae_assert(k>=1, "LSFitCreateWFGH: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateWFGH: length(C)cnt>=n, "LSFitCreateWFGH: length(Y)cnt>=n, "LSFitCreateWFGH: length(W)rows>=n, "LSFitCreateWFGH: rows(X)cols>=m, "LSFitCreateWFGH: cols(X)teststep = 0; - state->diffstep = 0; - state->npoints = n; - state->nweights = n; - state->wkind = 1; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->taskw, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_matrix_set_length(&state->h, k, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_vector_set_length(&state->g, k, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 2; - state->prevnpt = -1; - state->prevalgo = -1; - minlmcreatefgh(k, &state->c, &state->optstate, _state); - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Nonlinear least squares fitting using gradient/Hessian, without individial -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefgh(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - lsfitstate* state, - ae_state *_state) -{ - ae_int_t i; - - _lsfitstate_clear(state); - - ae_assert(n>=1, "LSFitCreateFGH: N<1!", _state); - ae_assert(m>=1, "LSFitCreateFGH: M<1!", _state); - ae_assert(k>=1, "LSFitCreateFGH: K<1!", _state); - ae_assert(c->cnt>=k, "LSFitCreateFGH: length(C)cnt>=n, "LSFitCreateFGH: length(Y)rows>=n, "LSFitCreateFGH: rows(X)cols>=m, "LSFitCreateFGH: cols(X)teststep = 0; - state->diffstep = 0; - state->npoints = n; - state->wkind = 0; - state->m = m; - state->k = k; - lsfitsetcond(state, 0.0, 0.0, 0, _state); - lsfitsetstpmax(state, 0.0, _state); - lsfitsetxrep(state, ae_false, _state); - ae_matrix_set_length(&state->taskx, n, m, _state); - ae_vector_set_length(&state->tasky, n, _state); - ae_vector_set_length(&state->c, k, _state); - ae_matrix_set_length(&state->h, k, k, _state); - ae_vector_set_length(&state->x, m, _state); - ae_vector_set_length(&state->g, k, _state); - ae_v_move(&state->c.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); - for(i=0; i<=n-1; i++) - { - ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; - } - ae_vector_set_length(&state->s, k, _state); - ae_vector_set_length(&state->bndl, k, _state); - ae_vector_set_length(&state->bndu, k, _state); - for(i=0; i<=k-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - } - state->optalgo = 2; - state->prevnpt = -1; - state->prevalgo = -1; - minlmcreatefgh(k, &state->c, &state->optstate, _state); - lsfit_lsfitclearrequestfields(state, _state); - ae_vector_set_length(&state->rstate.ia, 6+1, _state); - ae_vector_set_length(&state->rstate.ra, 8+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Stopping conditions for nonlinear least squares fitting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - stopping criterion. Algorithm stops if - |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by LSFitSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -NOTE - -Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic -stopping criterion selection (according to the scheme used by MINLM unit). - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetcond(lsfitstate* state, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsf, _state), "LSFitSetCond: EpsF is not finite!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "LSFitSetCond: negative EpsF!", _state); - ae_assert(ae_isfinite(epsx, _state), "LSFitSetCond: EpsX is not finite!", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "LSFitSetCond: negative EpsX!", _state); - ae_assert(maxits>=0, "LSFitSetCond: negative MaxIts!", _state); - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state) -{ - - - ae_assert(ae_fp_greater_eq(stpmax,0), "LSFitSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -When reports are needed, State.C (current parameters) and State.F (current -value of fitting function) are reported. - - - -- ALGLIB -- - Copyright 15.08.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function sets scaling coefficients for underlying optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetscale(lsfitstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(s->cnt>=state->k, "LSFitSetScale: Length(S)k-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "LSFitSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "LSFitSetScale: S contains infinite or NAN elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function sets boundary constraints for underlying optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[K]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[K]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: unlike other constrained optimization algorithms, this solver has -following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetbc(lsfitstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - - k = state->k; - ae_assert(bndl->cnt>=k, "LSFitSetBC: Length(BndL)cnt>=k, "LSFitSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "LSFitSetBC: BndL contains NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "LSFitSetBC: BndU contains NAN or -INF", _state); - if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) ) - { - ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "LSFitSetBC: BndL[i]>BndU[i]", _state); - } - state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; - state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; - } -} - - -/************************************************************************* -NOTES: - -1. this algorithm is somewhat unusual because it works with parameterized - function f(C,X), where X is a function argument (we have many points - which are characterized by different argument values), and C is a - parameter to fit. - - For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then - x will be argument, and {c0,c1} will be parameters. - - It is important to understand that this algorithm finds minimum in the - space of function PARAMETERS (not arguments), so it needs derivatives - of f() with respect to C, not X. - - In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} - instead of {df/dx} = {c0}. - -2. Callback functions accept C as the first parameter, and X as the second - -3. If state was created with LSFitCreateFG(), algorithm needs just - function and its gradient, but if state was created with - LSFitCreateFGH(), algorithm will need function, gradient and Hessian. - - According to the said above, there ase several versions of this - function, which accept different sets of callbacks. - - This flexibility opens way to subtle errors - you may create state with - LSFitCreateFGH() (optimization using Hessian), but call function which - does not accept Hessian. So when algorithm will request Hessian, there - will be no callback to call. In this case exception will be thrown. - - Be careful to avoid such errors because there is no way to find them at - compile time - you can see them at runtime only. - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool lsfititeration(lsfitstate* state, ae_state *_state) -{ - double lx; - double lf; - double ld; - double rx; - double rf; - double rd; - ae_int_t n; - ae_int_t m; - ae_int_t k; - double v; - double vv; - double relcnt; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t info; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - k = state->rstate.ia.ptr.p_int[2]; - i = state->rstate.ia.ptr.p_int[3]; - j = state->rstate.ia.ptr.p_int[4]; - j1 = state->rstate.ia.ptr.p_int[5]; - info = state->rstate.ia.ptr.p_int[6]; - lx = state->rstate.ra.ptr.p_double[0]; - lf = state->rstate.ra.ptr.p_double[1]; - ld = state->rstate.ra.ptr.p_double[2]; - rx = state->rstate.ra.ptr.p_double[3]; - rf = state->rstate.ra.ptr.p_double[4]; - rd = state->rstate.ra.ptr.p_double[5]; - v = state->rstate.ra.ptr.p_double[6]; - vv = state->rstate.ra.ptr.p_double[7]; - relcnt = state->rstate.ra.ptr.p_double[8]; - } - else - { - n = -983; - m = -989; - k = -834; - i = 900; - j = -287; - j1 = 364; - info = 214; - lx = -338; - lf = -686; - ld = 912; - rx = 585; - rf = 497; - rd = -271; - v = -581; - vv = 745; - relcnt = -533; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - - /* - * Routine body - */ - - /* - * Init - */ - if( state->wkind==1 ) - { - ae_assert(state->npoints==state->nweights, "LSFitFit: number of points is not equal to the number of weights", _state); - } - state->repvaridx = -1; - n = state->npoints; - m = state->m; - k = state->k; - minlmsetcond(&state->optstate, 0.0, state->epsf, state->epsx, state->maxits, _state); - minlmsetstpmax(&state->optstate, state->stpmax, _state); - minlmsetxrep(&state->optstate, state->xrep, _state); - minlmsetscale(&state->optstate, &state->s, _state); - minlmsetbc(&state->optstate, &state->bndl, &state->bndu, _state); - - /* - * Check that user-supplied gradient is correct - */ - lsfit_lsfitclearrequestfields(state, _state); - if( !(ae_fp_greater(state->teststep,0)&&state->optalgo==1) ) - { - goto lbl_14; - } - for(i=0; i<=k-1; i++) - { - if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - } - state->needfg = ae_true; - i = 0; -lbl_16: - if( i>k-1 ) - { - goto lbl_18; - } - ae_assert(ae_fp_less_eq(state->bndl.ptr.p_double[i],state->c.ptr.p_double[i])&&ae_fp_less_eq(state->c.ptr.p_double[i],state->bndu.ptr.p_double[i]), "LSFitIteration: internal error(State.C is out of bounds)", _state); - v = state->c.ptr.p_double[i]; - j = 0; -lbl_19: - if( j>n-1 ) - { - goto lbl_21; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[j][0], 1, ae_v_len(0,m-1)); - state->c.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; - if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - lx = state->c.ptr.p_double[i]; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - lf = state->f; - ld = state->g.ptr.p_double[i]; - state->c.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; - if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - rx = state->c.ptr.p_double[i]; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - rf = state->f; - rd = state->g.ptr.p_double[i]; - state->c.ptr.p_double[i] = (lx+rx)/2; - if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) - { - state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->c.ptr.p_double[i] = v; - if( !derivativecheck(lf, ld, rf, rd, state->f, state->g.ptr.p_double[i], rx-lx, _state) ) - { - state->repvaridx = i; - state->repterminationtype = -7; - result = ae_false; - return result; - } - j = j+1; - goto lbl_19; -lbl_21: - i = i+1; - goto lbl_16; -lbl_18: - state->needfg = ae_false; -lbl_14: - - /* - * Fill WCur by weights: - * * for WKind=0 unit weights are chosen - * * for WKind=1 we use user-supplied weights stored in State.TaskW - */ - rvectorsetlengthatleast(&state->wcur, n, _state); - for(i=0; i<=n-1; i++) - { - state->wcur.ptr.p_double[i] = 1.0; - if( state->wkind==1 ) - { - state->wcur.ptr.p_double[i] = state->taskw.ptr.p_double[i]; - } - } - - /* - * Optimize - */ -lbl_22: - if( !minlmiteration(&state->optstate, _state) ) - { - goto lbl_23; - } - if( !state->optstate.needfi ) - { - goto lbl_24; - } - - /* - * calculate f[] = wi*(f(xi,c)-yi) - */ - i = 0; -lbl_26: - if( i>n-1 ) - { - goto lbl_28; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needf = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needf = ae_false; - vv = state->wcur.ptr.p_double[i]; - state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); - i = i+1; - goto lbl_26; -lbl_28: - goto lbl_22; -lbl_24: - if( !state->optstate.needf ) - { - goto lbl_29; - } - - /* - * calculate F = sum (wi*(f(xi,c)-yi))^2 - */ - state->optstate.f = 0; - i = 0; -lbl_31: - if( i>n-1 ) - { - goto lbl_33; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needf = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->needf = ae_false; - vv = state->wcur.ptr.p_double[i]; - state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); - i = i+1; - goto lbl_31; -lbl_33: - goto lbl_22; -lbl_29: - if( !state->optstate.needfg ) - { - goto lbl_34; - } - - /* - * calculate F/gradF - */ - state->optstate.f = 0; - for(i=0; i<=k-1; i++) - { - state->optstate.g.ptr.p_double[i] = 0; - } - i = 0; -lbl_36: - if( i>n-1 ) - { - goto lbl_38; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->needfg = ae_false; - vv = state->wcur.ptr.p_double[i]; - state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); - v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]); - ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); - i = i+1; - goto lbl_36; -lbl_38: - goto lbl_22; -lbl_34: - if( !state->optstate.needfij ) - { - goto lbl_39; - } - - /* - * calculate Fi/jac(Fi) - */ - i = 0; -lbl_41: - if( i>n-1 ) - { - goto lbl_43; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->needfg = ae_false; - vv = state->wcur.ptr.p_double[i]; - state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); - ae_v_moved(&state->optstate.j.ptr.pp_double[i][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), vv); - i = i+1; - goto lbl_41; -lbl_43: - goto lbl_22; -lbl_39: - if( !state->optstate.needfgh ) - { - goto lbl_44; - } - - /* - * calculate F/grad(F)/hess(F) - */ - state->optstate.f = 0; - for(i=0; i<=k-1; i++) - { - state->optstate.g.ptr.p_double[i] = 0; - } - for(i=0; i<=k-1; i++) - { - for(j=0; j<=k-1; j++) - { - state->optstate.h.ptr.pp_double[i][j] = 0; - } - } - i = 0; -lbl_46: - if( i>n-1 ) - { - goto lbl_48; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needfgh = ae_true; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->needfgh = ae_false; - vv = state->wcur.ptr.p_double[i]; - state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); - v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]); - ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); - for(j=0; j<=k-1; j++) - { - v = 2*ae_sqr(vv, _state)*state->g.ptr.p_double[j]; - ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); - v = 2*ae_sqr(vv, _state)*(state->f-state->tasky.ptr.p_double[i]); - ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->h.ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); - } - i = i+1; - goto lbl_46; -lbl_48: - goto lbl_22; -lbl_44: - if( !state->optstate.xupdated ) - { - goto lbl_49; - } - - /* - * Report new iteration - */ - ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); - state->f = state->optstate.f; - lsfit_lsfitclearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->xupdated = ae_false; - goto lbl_22; -lbl_49: - goto lbl_22; -lbl_23: - minlmresults(&state->optstate, &state->c, &state->optrep, _state); - state->repterminationtype = state->optrep.terminationtype; - state->repiterationscount = state->optrep.iterationscount; - - /* - * calculate errors - */ - if( state->repterminationtype<=0 ) - { - goto lbl_51; - } - - /* - * Calculate RMS/Avg/Max/... errors - */ - state->reprmserror = 0; - state->repwrmserror = 0; - state->repavgerror = 0; - state->repavgrelerror = 0; - state->repmaxerror = 0; - relcnt = 0; - i = 0; -lbl_53: - if( i>n-1 ) - { - goto lbl_55; - } - ae_v_move(&state->c.ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,k-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - lsfit_lsfitclearrequestfields(state, _state); - state->needf = ae_true; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->needf = ae_false; - v = state->f; - vv = state->wcur.ptr.p_double[i]; - state->reprmserror = state->reprmserror+ae_sqr(v-state->tasky.ptr.p_double[i], _state); - state->repwrmserror = state->repwrmserror+ae_sqr(vv*(v-state->tasky.ptr.p_double[i]), _state); - state->repavgerror = state->repavgerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state); - if( ae_fp_neq(state->tasky.ptr.p_double[i],0) ) - { - state->repavgrelerror = state->repavgrelerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state)/ae_fabs(state->tasky.ptr.p_double[i], _state); - relcnt = relcnt+1; - } - state->repmaxerror = ae_maxreal(state->repmaxerror, ae_fabs(v-state->tasky.ptr.p_double[i], _state), _state); - i = i+1; - goto lbl_53; -lbl_55: - state->reprmserror = ae_sqrt(state->reprmserror/n, _state); - state->repwrmserror = ae_sqrt(state->repwrmserror/n, _state); - state->repavgerror = state->repavgerror/n; - if( ae_fp_neq(relcnt,0) ) - { - state->repavgrelerror = state->repavgrelerror/relcnt; - } - - /* - * Calculate covariance matrix - */ - rmatrixsetlengthatleast(&state->tmpjac, n, k, _state); - rvectorsetlengthatleast(&state->tmpf, n, _state); - rvectorsetlengthatleast(&state->tmp, k, _state); - if( ae_fp_less_eq(state->diffstep,0) ) - { - goto lbl_56; - } - - /* - * Compute Jacobian by means of numerical differentiation - */ - lsfit_lsfitclearrequestfields(state, _state); - state->needf = ae_true; - i = 0; -lbl_58: - if( i>n-1 ) - { - goto lbl_60; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->tmpf.ptr.p_double[i] = state->f; - j = 0; -lbl_61: - if( j>k-1 ) - { - goto lbl_63; - } - v = state->c.ptr.p_double[j]; - lx = v-state->diffstep*state->s.ptr.p_double[j]; - state->c.ptr.p_double[j] = lx; - if( ae_isfinite(state->bndl.ptr.p_double[j], _state) ) - { - state->c.ptr.p_double[j] = ae_maxreal(state->c.ptr.p_double[j], state->bndl.ptr.p_double[j], _state); - } - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - lf = state->f; - rx = v+state->diffstep*state->s.ptr.p_double[j]; - state->c.ptr.p_double[j] = rx; - if( ae_isfinite(state->bndu.ptr.p_double[j], _state) ) - { - state->c.ptr.p_double[j] = ae_minreal(state->c.ptr.p_double[j], state->bndu.ptr.p_double[j], _state); - } - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - rf = state->f; - state->c.ptr.p_double[j] = v; - if( ae_fp_neq(rx,lx) ) - { - state->tmpjac.ptr.pp_double[i][j] = (rf-lf)/(rx-lx); - } - else - { - state->tmpjac.ptr.pp_double[i][j] = 0; - } - j = j+1; - goto lbl_61; -lbl_63: - i = i+1; - goto lbl_58; -lbl_60: - state->needf = ae_false; - goto lbl_57; -lbl_56: - - /* - * Jacobian is calculated with user-provided analytic gradient - */ - lsfit_lsfitclearrequestfields(state, _state); - state->needfg = ae_true; - i = 0; -lbl_64: - if( i>n-1 ) - { - goto lbl_66; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); - state->pointindex = i; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->tmpf.ptr.p_double[i] = state->f; - for(j=0; j<=k-1; j++) - { - state->tmpjac.ptr.pp_double[i][j] = state->g.ptr.p_double[j]; - } - i = i+1; - goto lbl_64; -lbl_66: - state->needfg = ae_false; -lbl_57: - for(i=0; i<=k-1; i++) - { - state->tmp.ptr.p_double[i] = 0.0; - } - lsfit_estimateerrors(&state->tmpjac, &state->tmpf, &state->tasky, &state->wcur, &state->tmp, &state->s, n, k, &state->rep, &state->tmpjacw, 0, _state); -lbl_51: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = k; - state->rstate.ia.ptr.p_int[3] = i; - state->rstate.ia.ptr.p_int[4] = j; - state->rstate.ia.ptr.p_int[5] = j1; - state->rstate.ia.ptr.p_int[6] = info; - state->rstate.ra.ptr.p_double[0] = lx; - state->rstate.ra.ptr.p_double[1] = lf; - state->rstate.ra.ptr.p_double[2] = ld; - state->rstate.ra.ptr.p_double[3] = rx; - state->rstate.ra.ptr.p_double[4] = rf; - state->rstate.ra.ptr.p_double[5] = rd; - state->rstate.ra.ptr.p_double[6] = v; - state->rstate.ra.ptr.p_double[7] = vv; - state->rstate.ra.ptr.p_double[8] = relcnt; - return result; -} - - -/************************************************************************* -Nonlinear least squares fitting results. - -Called after return from LSFitFit(). - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Info - completion code: - * -7 gradient verification failed. - See LSFitSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - C - array[0..K-1], solution - Rep - optimization report. On success following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - * WRMSError weighted rms error on the (X,Y). - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(J*CovPar*J')), - where J is Jacobian matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitresults(lsfitstate* state, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - - lsfit_clearreport(rep, _state); - *info = state->repterminationtype; - rep->varidx = state->repvaridx; - if( *info>0 ) - { - ae_vector_set_length(c, state->k, _state); - ae_v_move(&c->ptr.p_double[0], 1, &state->c.ptr.p_double[0], 1, ae_v_len(0,state->k-1)); - rep->rmserror = state->reprmserror; - rep->wrmserror = state->repwrmserror; - rep->avgerror = state->repavgerror; - rep->avgrelerror = state->repavgrelerror; - rep->maxerror = state->repmaxerror; - rep->iterationscount = state->repiterationscount; - ae_matrix_set_length(&rep->covpar, state->k, state->k, _state); - ae_vector_set_length(&rep->errpar, state->k, _state); - ae_vector_set_length(&rep->errcurve, state->npoints, _state); - ae_vector_set_length(&rep->noise, state->npoints, _state); - rep->r2 = state->rep.r2; - for(i=0; i<=state->k-1; i++) - { - for(j=0; j<=state->k-1; j++) - { - rep->covpar.ptr.pp_double[i][j] = state->rep.covpar.ptr.pp_double[i][j]; - } - rep->errpar.ptr.p_double[i] = state->rep.errpar.ptr.p_double[i]; - } - for(i=0; i<=state->npoints-1; i++) - { - rep->errcurve.ptr.p_double[i] = state->rep.errcurve.ptr.p_double[i]; - rep->noise.ptr.p_double[i] = state->rep.noise.ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before fitting begins -* LSFitFit() is called -* prior to actual fitting, for each point in data set X_i and each - component of parameters being fited C_j algorithm performs following - steps: - * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], - where C_j is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on C[] - * F(X_i|C) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N*K (points count * parameters count) gradient - evaluations. It is very costly and you should use it only for low - dimensional problems, when you want to be sure that you've - correctly calculated analytic derivatives. You should not use it - in the production code (unless you want to check derivatives - provided by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with LSFitSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -NOTE 4: this function works only for optimizers created with LSFitCreateWFG() - or LSFitCreateFG() constructors. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetgradientcheck(lsfitstate* state, - double teststep, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(teststep, _state), "LSFitSetGradientCheck: TestStep contains NaN or Infinite", _state); - ae_assert(ae_fp_greater_eq(teststep,0), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); - state->teststep = teststep; -} - - -/************************************************************************* -Internal subroutine: automatic scaling for LLS tasks. -NEVER CALL IT DIRECTLY! - -Maps abscissas to [-1,1], standartizes ordinates and correspondingly scales -constraints. It also scales weights so that max(W[i])=1 - -Transformations performed: -* X, XC [XA,XB] => [-1,+1] - transformation makes min(X)=-1, max(X)=+1 - -* Y [SA,SB] => [0,1] - transformation makes mean(Y)=0, stddev(Y)=1 - -* YC transformed accordingly to SA, SB, DC[I] - - -- ALGLIB PROJECT -- - Copyright 08.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitscalexy(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - double* xa, - double* xb, - double* sa, - double* sb, - /* Real */ ae_vector* xoriginal, - /* Real */ ae_vector* yoriginal, - ae_state *_state) -{ - double xmin; - double xmax; - ae_int_t i; - double mx; - - *xa = 0; - *xb = 0; - *sa = 0; - *sb = 0; - ae_vector_clear(xoriginal); - ae_vector_clear(yoriginal); - - ae_assert(n>=1, "LSFitScaleXY: incorrect N", _state); - ae_assert(k>=0, "LSFitScaleXY: incorrect K", _state); - - /* - * Calculate xmin/xmax. - * Force xmin<>xmax. - */ - xmin = x->ptr.p_double[0]; - xmax = x->ptr.p_double[0]; - for(i=1; i<=n-1; i++) - { - xmin = ae_minreal(xmin, x->ptr.p_double[i], _state); - xmax = ae_maxreal(xmax, x->ptr.p_double[i], _state); - } - for(i=0; i<=k-1; i++) - { - xmin = ae_minreal(xmin, xc->ptr.p_double[i], _state); - xmax = ae_maxreal(xmax, xc->ptr.p_double[i], _state); - } - if( ae_fp_eq(xmin,xmax) ) - { - if( ae_fp_eq(xmin,0) ) - { - xmin = -1; - xmax = 1; - } - else - { - if( ae_fp_greater(xmin,0) ) - { - xmin = 0.5*xmin; - } - else - { - xmax = 0.5*xmax; - } - } - } - - /* - * Transform abscissas: map [XA,XB] to [0,1] - * - * Store old X[] in XOriginal[] (it will be used - * to calculate relative error). - */ - ae_vector_set_length(xoriginal, n, _state); - ae_v_move(&xoriginal->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - *xa = xmin; - *xb = xmax; - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = 2*(x->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); - } - for(i=0; i<=k-1; i++) - { - ae_assert(dc->ptr.p_int[i]>=0, "LSFitScaleXY: internal error!", _state); - xc->ptr.p_double[i] = 2*(xc->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); - yc->ptr.p_double[i] = yc->ptr.p_double[i]*ae_pow(0.5*(*xb-(*xa)), dc->ptr.p_int[i], _state); - } - - /* - * Transform function values: map [SA,SB] to [0,1] - * SA = mean(Y), - * SB = SA+stddev(Y). - * - * Store old Y[] in YOriginal[] (it will be used - * to calculate relative error). - */ - ae_vector_set_length(yoriginal, n, _state); - ae_v_move(&yoriginal->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - *sa = 0; - for(i=0; i<=n-1; i++) - { - *sa = *sa+y->ptr.p_double[i]; - } - *sa = *sa/n; - *sb = 0; - for(i=0; i<=n-1; i++) - { - *sb = *sb+ae_sqr(y->ptr.p_double[i]-(*sa), _state); - } - *sb = ae_sqrt(*sb/n, _state)+(*sa); - if( ae_fp_eq(*sb,*sa) ) - { - *sb = 2*(*sa); - } - if( ae_fp_eq(*sb,*sa) ) - { - *sb = *sa+1; - } - for(i=0; i<=n-1; i++) - { - y->ptr.p_double[i] = (y->ptr.p_double[i]-(*sa))/(*sb-(*sa)); - } - for(i=0; i<=k-1; i++) - { - if( dc->ptr.p_int[i]==0 ) - { - yc->ptr.p_double[i] = (yc->ptr.p_double[i]-(*sa))/(*sb-(*sa)); - } - else - { - yc->ptr.p_double[i] = yc->ptr.p_double[i]/(*sb-(*sa)); - } - } - - /* - * Scale weights - */ - mx = 0; - for(i=0; i<=n-1; i++) - { - mx = ae_maxreal(mx, ae_fabs(w->ptr.p_double[i], _state), _state); - } - if( ae_fp_neq(mx,0) ) - { - for(i=0; i<=n-1; i++) - { - w->ptr.p_double[i] = w->ptr.p_double[i]/mx; - } - } -} - - -/************************************************************************* -Internal spline fitting subroutine - - -- ALGLIB PROJECT -- - Copyright 08.09.2009 by Bochkanov Sergey -*************************************************************************/ -static void lsfit_spline1dfitinternal(ae_int_t st, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _w; - ae_vector _xc; - ae_vector _yc; - ae_matrix fmatrix; - ae_matrix cmatrix; - ae_vector y2; - ae_vector w2; - ae_vector sx; - ae_vector sy; - ae_vector sd; - ae_vector tmp; - ae_vector xoriginal; - ae_vector yoriginal; - lsfitreport lrep; - double v0; - double v1; - double v2; - double mx; - spline1dinterpolant s2; - ae_int_t i; - ae_int_t j; - ae_int_t relcnt; - double xa; - double xb; - double sa; - double sb; - double bl; - double br; - double decay; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_w, w, _state, ae_true); - w = &_w; - ae_vector_init_copy(&_xc, xc, _state, ae_true); - xc = &_xc; - ae_vector_init_copy(&_yc, yc, _state, ae_true); - yc = &_yc; - *info = 0; - _spline1dinterpolant_clear(s); - _spline1dfitreport_clear(rep); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sd, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); - _lsfitreport_init(&lrep, _state, ae_true); - _spline1dinterpolant_init(&s2, _state, ae_true); - - ae_assert(st==0||st==1, "Spline1DFit: internal error!", _state); - if( st==0&&m<4 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( st==1&&m<4 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( (n<1||k<0)||k>=m ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=k-1; i++) - { - *info = 0; - if( dc->ptr.p_int[i]<0 ) - { - *info = -1; - } - if( dc->ptr.p_int[i]>1 ) - { - *info = -1; - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - } - if( st==1&&m%2!=0 ) - { - - /* - * Hermite fitter must have even number of basis functions - */ - *info = -2; - ae_frame_leave(_state); - return; - } - - /* - * weight decay for correct handling of task which becomes - * degenerate after constraints are applied - */ - decay = 10000*ae_machineepsilon; - - /* - * Scale X, Y, XC, YC - */ - lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); - - /* - * allocate space, initialize: - * * SX - grid for basis functions - * * SY - values of basis functions at grid points - * * FMatrix- values of basis functions at X[] - * * CMatrix- values (derivatives) of basis functions at XC[] - */ - ae_vector_set_length(&y2, n+m, _state); - ae_vector_set_length(&w2, n+m, _state); - ae_matrix_set_length(&fmatrix, n+m, m, _state); - if( k>0 ) - { - ae_matrix_set_length(&cmatrix, k, m+1, _state); - } - if( st==0 ) - { - - /* - * allocate space for cubic spline - */ - ae_vector_set_length(&sx, m-2, _state); - ae_vector_set_length(&sy, m-2, _state); - for(j=0; j<=m-2-1; j++) - { - sx.ptr.p_double[j] = (double)(2*j)/(double)(m-2-1)-1; - } - } - if( st==1 ) - { - - /* - * allocate space for Hermite spline - */ - ae_vector_set_length(&sx, m/2, _state); - ae_vector_set_length(&sy, m/2, _state); - ae_vector_set_length(&sd, m/2, _state); - for(j=0; j<=m/2-1; j++) - { - sx.ptr.p_double[j] = (double)(2*j)/(double)(m/2-1)-1; - } - } - - /* - * Prepare design and constraints matrices: - * * fill constraints matrix - * * fill first N rows of design matrix with values - * * fill next M rows of design matrix with regularizing term - * * append M zeros to Y - * * append M elements, mean(abs(W)) each, to W - */ - for(j=0; j<=m-1; j++) - { - - /* - * prepare Jth basis function - */ - if( st==0 ) - { - - /* - * cubic spline basis - */ - for(i=0; i<=m-2-1; i++) - { - sy.ptr.p_double[i] = 0; - } - bl = 0; - br = 0; - if( jptr.p_double[i], _state); - } - for(i=0; i<=k-1; i++) - { - ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=2, "Spline1DFit: internal error!", _state); - spline1ddiff(&s2, xc->ptr.p_double[i], &v0, &v1, &v2, _state); - if( dc->ptr.p_int[i]==0 ) - { - cmatrix.ptr.pp_double[i][j] = v0; - } - if( dc->ptr.p_int[i]==1 ) - { - cmatrix.ptr.pp_double[i][j] = v1; - } - if( dc->ptr.p_int[i]==2 ) - { - cmatrix.ptr.pp_double[i][j] = v2; - } - } - } - for(i=0; i<=k-1; i++) - { - cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; - } - for(i=0; i<=m-1; i++) - { - for(j=0; j<=m-1; j++) - { - if( i==j ) - { - fmatrix.ptr.pp_double[n+i][j] = decay; - } - else - { - fmatrix.ptr.pp_double[n+i][j] = 0; - } - } - } - ae_vector_set_length(&y2, n+m, _state); - ae_vector_set_length(&w2, n+m, _state); - ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - mx = 0; - for(i=0; i<=n-1; i++) - { - mx = mx+ae_fabs(w->ptr.p_double[i], _state); - } - mx = mx/n; - for(i=0; i<=m-1; i++) - { - y2.ptr.p_double[n+i] = 0; - w2.ptr.p_double[n+i] = mx; - } - - /* - * Solve constrained task - */ - if( k>0 ) - { - - /* - * solve using regularization - */ - lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state); - } - else - { - - /* - * no constraints, no regularization needed - */ - lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state); - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Generate spline and scale it - */ - if( st==0 ) - { - - /* - * cubic spline basis - */ - ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-2-1)); - spline1dbuildcubic(&sx, &sy, m-2, 1, tmp.ptr.p_double[m-2], 1, tmp.ptr.p_double[m-1], s, _state); - } - if( st==1 ) - { - - /* - * Hermite basis - */ - for(i=0; i<=m/2-1; i++) - { - sy.ptr.p_double[i] = tmp.ptr.p_double[2*i]; - sd.ptr.p_double[i] = tmp.ptr.p_double[2*i+1]; - } - spline1dbuildhermite(&sx, &sy, &sd, m/2, s, _state); - } - spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); - spline1dlintransy(s, sb-sa, sa, _state); - - /* - * Scale absolute errors obtained from LSFitLinearW. - * Relative error should be calculated separately - * (because of shifting/scaling of the task) - */ - rep->taskrcond = lrep.taskrcond; - rep->rmserror = lrep.rmserror*(sb-sa); - rep->avgerror = lrep.avgerror*(sb-sa); - rep->maxerror = lrep.maxerror*(sb-sa); - rep->avgrelerror = 0; - relcnt = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(yoriginal.ptr.p_double[i],0) ) - { - rep->avgrelerror = rep->avgrelerror+ae_fabs(spline1dcalc(s, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); - relcnt = relcnt+1; - } - } - if( relcnt!=0 ) - { - rep->avgrelerror = rep->avgrelerror/relcnt; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal fitting subroutine -*************************************************************************/ -static void lsfit_lsfitlinearinternal(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - double threshold; - ae_matrix ft; - ae_matrix q; - ae_matrix l; - ae_matrix r; - ae_vector b; - ae_vector wmod; - ae_vector tau; - ae_vector nzeros; - ae_vector s; - ae_int_t i; - ae_int_t j; - double v; - ae_vector sv; - ae_matrix u; - ae_matrix vt; - ae_vector tmp; - ae_vector utb; - ae_vector sutb; - ae_int_t relcnt; - - ae_frame_make(_state, &_frame_block); - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - ae_matrix_init(&ft, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&l, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&b, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wmod, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&nzeros, 0, DT_REAL, _state, ae_true); - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&utb, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true); - - lsfit_clearreport(rep, _state); - if( n<1||m<1 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - *info = 1; - threshold = ae_sqrt(ae_machineepsilon, _state); - - /* - * Degenerate case, needs special handling - */ - if( nptr.p_double[j]; - ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); - b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; - wmod.ptr.p_double[j] = 1; - } - - /* - * LQ decomposition and reduction to M=N - */ - ae_vector_set_length(c, m, _state); - for(i=0; i<=m-1; i++) - { - c->ptr.p_double[i] = 0; - } - rep->taskrcond = 0; - rmatrixlq(&ft, n, m, &tau, _state); - rmatrixlqunpackq(&ft, n, m, &tau, n, &q, _state); - rmatrixlqunpackl(&ft, n, m, &l, _state); - lsfit_lsfitlinearinternal(&b, &wmod, &l, n, n, info, &tmp, rep, _state); - if( *info<=0 ) - { - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - v = tmp.ptr.p_double[i]; - ae_v_addd(&c->ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - ae_frame_leave(_state); - return; - } - - /* - * N>=M. Generate design matrix and reduce to N=M using - * QR decomposition. - */ - ae_matrix_set_length(&ft, n, m, _state); - ae_vector_set_length(&b, n, _state); - for(j=0; j<=n-1; j++) - { - v = w->ptr.p_double[j]; - ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); - b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; - } - rmatrixqr(&ft, n, m, &tau, _state); - rmatrixqrunpackq(&ft, n, m, &tau, m, &q, _state); - rmatrixqrunpackr(&ft, n, m, &r, _state); - ae_vector_set_length(&tmp, m, _state); - for(i=0; i<=m-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = b.ptr.p_double[i]; - ae_v_addd(&tmp.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - ae_vector_set_length(&b, m, _state); - ae_v_move(&b.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); - - /* - * R contains reduced MxM design upper triangular matrix, - * B contains reduced Mx1 right part. - * - * Determine system condition number and decide - * should we use triangular solver (faster) or - * SVD-based solver (more stable). - * - * We can use LU-based RCond estimator for this task. - */ - rep->taskrcond = rmatrixlurcondinf(&r, m, _state); - if( ae_fp_greater(rep->taskrcond,threshold) ) - { - - /* - * use QR-based solver - */ - ae_vector_set_length(c, m, _state); - c->ptr.p_double[m-1] = b.ptr.p_double[m-1]/r.ptr.pp_double[m-1][m-1]; - for(i=m-2; i>=0; i--) - { - v = ae_v_dotproduct(&r.ptr.pp_double[i][i+1], 1, &c->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1)); - c->ptr.p_double[i] = (b.ptr.p_double[i]-v)/r.ptr.pp_double[i][i]; - } - } - else - { - - /* - * use SVD-based solver - */ - if( !rmatrixsvd(&r, m, m, 1, 1, 2, &sv, &u, &vt, _state) ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&utb, m, _state); - ae_vector_set_length(&sutb, m, _state); - for(i=0; i<=m-1; i++) - { - utb.ptr.p_double[i] = 0; - } - for(i=0; i<=m-1; i++) - { - v = b.ptr.p_double[i]; - ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - if( ae_fp_greater(sv.ptr.p_double[0],0) ) - { - rep->taskrcond = sv.ptr.p_double[m-1]/sv.ptr.p_double[0]; - for(i=0; i<=m-1; i++) - { - if( ae_fp_greater(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) - { - sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i]; - } - else - { - sutb.ptr.p_double[i] = 0; - } - } - } - else - { - rep->taskrcond = 0; - for(i=0; i<=m-1; i++) - { - sutb.ptr.p_double[i] = 0; - } - } - ae_vector_set_length(c, m, _state); - for(i=0; i<=m-1; i++) - { - c->ptr.p_double[i] = 0; - } - for(i=0; i<=m-1; i++) - { - v = sutb.ptr.p_double[i]; - ae_v_addd(&c->ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - } - } - - /* - * calculate errors - */ - rep->rmserror = 0; - rep->avgerror = 0; - rep->avgrelerror = 0; - rep->maxerror = 0; - relcnt = 0; - for(i=0; i<=n-1; i++) - { - v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); - rep->rmserror = rep->rmserror+ae_sqr(v-y->ptr.p_double[i], _state); - rep->avgerror = rep->avgerror+ae_fabs(v-y->ptr.p_double[i], _state); - if( ae_fp_neq(y->ptr.p_double[i],0) ) - { - rep->avgrelerror = rep->avgrelerror+ae_fabs(v-y->ptr.p_double[i], _state)/ae_fabs(y->ptr.p_double[i], _state); - relcnt = relcnt+1; - } - rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-y->ptr.p_double[i], _state), _state); - } - rep->rmserror = ae_sqrt(rep->rmserror/n, _state); - rep->avgerror = rep->avgerror/n; - if( relcnt!=0 ) - { - rep->avgrelerror = rep->avgrelerror/relcnt; - } - ae_vector_set_length(&nzeros, n, _state); - ae_vector_set_length(&s, m, _state); - for(i=0; i<=m-1; i++) - { - s.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - s.ptr.p_double[j] = s.ptr.p_double[j]+ae_sqr(fmatrix->ptr.pp_double[i][j], _state); - } - nzeros.ptr.p_double[i] = 0; - } - for(i=0; i<=m-1; i++) - { - if( ae_fp_neq(s.ptr.p_double[i],0) ) - { - s.ptr.p_double[i] = ae_sqrt(1/s.ptr.p_double[i], _state); - } - else - { - s.ptr.p_double[i] = 1; - } - } - lsfit_estimateerrors(fmatrix, &nzeros, y, w, c, &s, n, m, rep, &r, 1, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine -*************************************************************************/ -static void lsfit_lsfitclearrequestfields(lsfitstate* state, - ae_state *_state) -{ - - - state->needf = ae_false; - state->needfg = ae_false; - state->needfgh = ae_false; - state->xupdated = ae_false; -} - - -/************************************************************************* -Internal subroutine, calculates barycentric basis functions. -Used for efficient simultaneous calculation of N basis functions. - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -static void lsfit_barycentriccalcbasis(barycentricinterpolant* b, - double t, - /* Real */ ae_vector* y, - ae_state *_state) -{ - double s2; - double s; - double v; - ae_int_t i; - ae_int_t j; - - - - /* - * special case: N=1 - */ - if( b->n==1 ) - { - y->ptr.p_double[0] = 1; - return; - } - - /* - * Here we assume that task is normalized, i.e.: - * 1. abs(Y[i])<=1 - * 2. abs(W[i])<=1 - * 3. X[] is ordered - * - * First, we decide: should we use "safe" formula (guarded - * against overflow) or fast one? - */ - s = ae_fabs(t-b->x.ptr.p_double[0], _state); - for(i=0; i<=b->n-1; i++) - { - v = b->x.ptr.p_double[i]; - if( ae_fp_eq(v,t) ) - { - for(j=0; j<=b->n-1; j++) - { - y->ptr.p_double[j] = 0; - } - y->ptr.p_double[i] = 1; - return; - } - v = ae_fabs(t-v, _state); - if( ae_fp_less(v,s) ) - { - s = v; - } - } - s2 = 0; - for(i=0; i<=b->n-1; i++) - { - v = s/(t-b->x.ptr.p_double[i]); - v = v*b->w.ptr.p_double[i]; - y->ptr.p_double[i] = v; - s2 = s2+v; - } - v = 1/s2; - ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); -} - - -/************************************************************************* -This is internal function for Chebyshev fitting. - -It assumes that input data are normalized: -* X/XC belong to [-1,+1], -* mean(Y)=0, stddev(Y)=1. - -It does not checks inputs for errors. - -This function is used to fit general (shifted) Chebyshev models, power -basis models or barycentric models. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - N - number of points, N>0. - XC - points where polynomial values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that P(XC[i])=YC[i] - * DC[i]=1 means that P'(XC[i])=YC[i] - K - number of constraints, 0<=K=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - C - interpolant in Chebyshev form; [-1,+1] is used as base interval - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -static void lsfit_internalchebyshevfit(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _xc; - ae_vector _yc; - ae_vector y2; - ae_vector w2; - ae_vector tmp; - ae_vector tmp2; - ae_vector tmpdiff; - ae_vector bx; - ae_vector by; - ae_vector bw; - ae_matrix fmatrix; - ae_matrix cmatrix; - ae_int_t i; - ae_int_t j; - double mx; - double decay; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_xc, xc, _state, ae_true); - xc = &_xc; - ae_vector_init_copy(&_yc, yc, _state, ae_true); - yc = &_yc; - *info = 0; - ae_vector_clear(c); - _lsfitreport_clear(rep); - ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpdiff, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&by, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bw, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); - - lsfit_clearreport(rep, _state); - - /* - * weight decay for correct handling of task which becomes - * degenerate after constraints are applied - */ - decay = 10000*ae_machineepsilon; - - /* - * allocate space, initialize/fill: - * * FMatrix- values of basis functions at X[] - * * CMatrix- values (derivatives) of basis functions at XC[] - * * fill constraints matrix - * * fill first N rows of design matrix with values - * * fill next M rows of design matrix with regularizing term - * * append M zeros to Y - * * append M elements, mean(abs(W)) each, to W - */ - ae_vector_set_length(&y2, n+m, _state); - ae_vector_set_length(&w2, n+m, _state); - ae_vector_set_length(&tmp, m, _state); - ae_vector_set_length(&tmpdiff, m, _state); - ae_matrix_set_length(&fmatrix, n+m, m, _state); - if( k>0 ) - { - ae_matrix_set_length(&cmatrix, k, m+1, _state); - } - - /* - * Fill design matrix, Y2, W2: - * * first N rows with basis functions for original points - * * next M rows with decay terms - */ - for(i=0; i<=n-1; i++) - { - - /* - * prepare Ith row - * use Tmp for calculations to avoid multidimensional arrays overhead - */ - for(j=0; j<=m-1; j++) - { - if( j==0 ) - { - tmp.ptr.p_double[j] = 1; - } - else - { - if( j==1 ) - { - tmp.ptr.p_double[j] = x->ptr.p_double[i]; - } - else - { - tmp.ptr.p_double[j] = 2*x->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; - } - } - } - ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - for(i=0; i<=m-1; i++) - { - for(j=0; j<=m-1; j++) - { - if( i==j ) - { - fmatrix.ptr.pp_double[n+i][j] = decay; - } - else - { - fmatrix.ptr.pp_double[n+i][j] = 0; - } - } - } - ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); - mx = 0; - for(i=0; i<=n-1; i++) - { - mx = mx+ae_fabs(w->ptr.p_double[i], _state); - } - mx = mx/n; - for(i=0; i<=m-1; i++) - { - y2.ptr.p_double[n+i] = 0; - w2.ptr.p_double[n+i] = mx; - } - - /* - * fill constraints matrix - */ - for(i=0; i<=k-1; i++) - { - - /* - * prepare Ith row - * use Tmp for basis function values, - * TmpDiff for basos function derivatives - */ - for(j=0; j<=m-1; j++) - { - if( j==0 ) - { - tmp.ptr.p_double[j] = 1; - tmpdiff.ptr.p_double[j] = 0; - } - else - { - if( j==1 ) - { - tmp.ptr.p_double[j] = xc->ptr.p_double[i]; - tmpdiff.ptr.p_double[j] = 1; - } - else - { - tmp.ptr.p_double[j] = 2*xc->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; - tmpdiff.ptr.p_double[j] = 2*(tmp.ptr.p_double[j-1]+xc->ptr.p_double[i]*tmpdiff.ptr.p_double[j-1])-tmpdiff.ptr.p_double[j-2]; - } - } - } - if( dc->ptr.p_int[i]==0 ) - { - ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - if( dc->ptr.p_int[i]==1 ) - { - ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmpdiff.ptr.p_double[0], 1, ae_v_len(0,m-1)); - } - cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; - } - - /* - * Solve constrained task - */ - if( k>0 ) - { - - /* - * solve using regularization - */ - lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, c, rep, _state); - } - else - { - - /* - * no constraints, no regularization needed - */ - lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, 0, info, c, rep, _state); - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal Floater-Hormann fitting subroutine for fixed D -*************************************************************************/ -static void lsfit_barycentricfitwcfixedd(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t d, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - ae_vector _w; - ae_vector _xc; - ae_vector _yc; - ae_matrix fmatrix; - ae_matrix cmatrix; - ae_vector y2; - ae_vector w2; - ae_vector sx; - ae_vector sy; - ae_vector sbf; - ae_vector xoriginal; - ae_vector yoriginal; - ae_vector tmp; - lsfitreport lrep; - double v0; - double v1; - double mx; - barycentricinterpolant b2; - ae_int_t i; - ae_int_t j; - ae_int_t relcnt; - double xa; - double xb; - double sa; - double sb; - double decay; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_vector_init_copy(&_w, w, _state, ae_true); - w = &_w; - ae_vector_init_copy(&_xc, xc, _state, ae_true); - xc = &_xc; - ae_vector_init_copy(&_yc, yc, _state, ae_true); - yc = &_yc; - *info = 0; - _barycentricinterpolant_clear(b); - _barycentricfitreport_clear(rep); - ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sbf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - _lsfitreport_init(&lrep, _state, ae_true); - _barycentricinterpolant_init(&b2, _state, ae_true); - - if( ((n<1||m<2)||k<0)||k>=m ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=k-1; i++) - { - *info = 0; - if( dc->ptr.p_int[i]<0 ) - { - *info = -1; - } - if( dc->ptr.p_int[i]>1 ) - { - *info = -1; - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - } - - /* - * weight decay for correct handling of task which becomes - * degenerate after constraints are applied - */ - decay = 10000*ae_machineepsilon; - - /* - * Scale X, Y, XC, YC - */ - lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); - - /* - * allocate space, initialize: - * * FMatrix- values of basis functions at X[] - * * CMatrix- values (derivatives) of basis functions at XC[] - */ - ae_vector_set_length(&y2, n+m, _state); - ae_vector_set_length(&w2, n+m, _state); - ae_matrix_set_length(&fmatrix, n+m, m, _state); - if( k>0 ) - { - ae_matrix_set_length(&cmatrix, k, m+1, _state); - } - ae_vector_set_length(&y2, n+m, _state); - ae_vector_set_length(&w2, n+m, _state); - - /* - * Prepare design and constraints matrices: - * * fill constraints matrix - * * fill first N rows of design matrix with values - * * fill next M rows of design matrix with regularizing term - * * append M zeros to Y - * * append M elements, mean(abs(W)) each, to W - */ - ae_vector_set_length(&sx, m, _state); - ae_vector_set_length(&sy, m, _state); - ae_vector_set_length(&sbf, m, _state); - for(j=0; j<=m-1; j++) - { - sx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1; - } - for(i=0; i<=m-1; i++) - { - sy.ptr.p_double[i] = 1; - } - barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); - mx = 0; - for(i=0; i<=n-1; i++) - { - lsfit_barycentriccalcbasis(&b2, x->ptr.p_double[i], &sbf, _state); - ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &sbf.ptr.p_double[0], 1, ae_v_len(0,m-1)); - y2.ptr.p_double[i] = y->ptr.p_double[i]; - w2.ptr.p_double[i] = w->ptr.p_double[i]; - mx = mx+ae_fabs(w->ptr.p_double[i], _state)/n; - } - for(i=0; i<=m-1; i++) - { - for(j=0; j<=m-1; j++) - { - if( i==j ) - { - fmatrix.ptr.pp_double[n+i][j] = decay; - } - else - { - fmatrix.ptr.pp_double[n+i][j] = 0; - } - } - y2.ptr.p_double[n+i] = 0; - w2.ptr.p_double[n+i] = mx; - } - if( k>0 ) - { - for(j=0; j<=m-1; j++) - { - for(i=0; i<=m-1; i++) - { - sy.ptr.p_double[i] = 0; - } - sy.ptr.p_double[j] = 1; - barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); - for(i=0; i<=k-1; i++) - { - ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=1, "BarycentricFit: internal error!", _state); - barycentricdiff1(&b2, xc->ptr.p_double[i], &v0, &v1, _state); - if( dc->ptr.p_int[i]==0 ) - { - cmatrix.ptr.pp_double[i][j] = v0; - } - if( dc->ptr.p_int[i]==1 ) - { - cmatrix.ptr.pp_double[i][j] = v1; - } - } - } - for(i=0; i<=k-1; i++) - { - cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i]; - } - } - - /* - * Solve constrained task - */ - if( k>0 ) - { - - /* - * solve using regularization - */ - lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state); - } - else - { - - /* - * no constraints, no regularization needed - */ - lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state); - } - if( *info<0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Generate interpolant and scale it - */ - ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); - barycentricbuildfloaterhormann(&sx, &sy, m, d, b, _state); - barycentriclintransx(b, 2/(xb-xa), -(xa+xb)/(xb-xa), _state); - barycentriclintransy(b, sb-sa, sa, _state); - - /* - * Scale absolute errors obtained from LSFitLinearW. - * Relative error should be calculated separately - * (because of shifting/scaling of the task) - */ - rep->taskrcond = lrep.taskrcond; - rep->rmserror = lrep.rmserror*(sb-sa); - rep->avgerror = lrep.avgerror*(sb-sa); - rep->maxerror = lrep.maxerror*(sb-sa); - rep->avgrelerror = 0; - relcnt = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(yoriginal.ptr.p_double[i],0) ) - { - rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(b, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); - relcnt = relcnt+1; - } - } - if( relcnt!=0 ) - { - rep->avgrelerror = rep->avgrelerror/relcnt; - } - ae_frame_leave(_state); -} - - -static void lsfit_clearreport(lsfitreport* rep, ae_state *_state) -{ - - - rep->taskrcond = 0; - rep->iterationscount = 0; - rep->varidx = -1; - rep->rmserror = 0; - rep->avgerror = 0; - rep->avgrelerror = 0; - rep->maxerror = 0; - rep->wrmserror = 0; - rep->r2 = 0; - ae_matrix_set_length(&rep->covpar, 0, 0, _state); - ae_vector_set_length(&rep->errpar, 0, _state); - ae_vector_set_length(&rep->errcurve, 0, _state); - ae_vector_set_length(&rep->noise, 0, _state); -} - - -/************************************************************************* -This internal function estimates covariance matrix and other error-related -information for linear/nonlinear least squares model. - -It has a bit awkward interface, but it can be used for both linear and -nonlinear problems. - -INPUT PARAMETERS: - F1 - array[0..N-1,0..K-1]: - * for linear problems - matrix of function values - * for nonlinear problems - Jacobian matrix - F0 - array[0..N-1]: - * for linear problems - must be filled with zeros - * for nonlinear problems - must store values of function being - fitted - Y - array[0..N-1]: - * for linear and nonlinear problems - must store target values - W - weights, array[0..N-1]: - * for linear and nonlinear problems - weights - X - array[0..K-1]: - * for linear and nonlinear problems - current solution - S - array[0..K-1]: - * its components should be strictly positive - * squared inverse of this diagonal matrix is used as damping - factor for covariance matrix (linear and nonlinear problems) - * for nonlinear problems, when scale of the variables is usually - explicitly given by user, you may use scale vector for this - parameter - * for linear problems you may set this parameter to - S=sqrt(1/diag(F'*F)) - * this parameter is automatically rescaled by this function, - only relative magnitudes of its components (with respect to - each other) matter. - N - number of points, N>0. - K - number of dimensions - Rep - structure which is used to store results - Z - additional matrix which, depending on ZKind, may contain some - information used to accelerate calculations - or just can be - temporary buffer: - * for ZKind=0 Z contains no information, just temporary - buffer which can be resized and used as needed - * for ZKind=1 Z contains triangular matrix from QR - decomposition of W*F1. This matrix can be used - to speedup calculation of covariance matrix. - It should not be changed by algorithm. - ZKind- contents of Z - -OUTPUT PARAMETERS: - -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(J*CovPar*J')), - where J is Jacobian matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] -* Rep.R2 coefficient of determination (non-weighted) - -Other fields of Rep are not changed. - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -static void lsfit_estimateerrors(/* Real */ ae_matrix* f1, - /* Real */ ae_vector* f0, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* x, - /* Real */ ae_vector* s, - ae_int_t n, - ae_int_t k, - lsfitreport* rep, - /* Real */ ae_matrix* z, - ae_int_t zkind, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _s; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - double v; - double noisec; - ae_int_t info; - matinvreport invrep; - ae_int_t nzcnt; - double avg; - double rss; - double tss; - double sz; - double ss; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_s, s, _state, ae_true); - s = &_s; - _matinvreport_init(&invrep, _state, ae_true); - - - /* - * Compute NZCnt - count of non-zero weights - */ - nzcnt = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(w->ptr.p_double[i],0) ) - { - nzcnt = nzcnt+1; - } - } - - /* - * Compute R2 - */ - if( nzcnt>0 ) - { - avg = 0.0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(w->ptr.p_double[i],0) ) - { - avg = avg+y->ptr.p_double[i]; - } - } - avg = avg/nzcnt; - rss = 0.0; - tss = 0.0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(w->ptr.p_double[i],0) ) - { - v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); - v = v+f0->ptr.p_double[i]; - rss = rss+ae_sqr(v-y->ptr.p_double[i], _state); - tss = tss+ae_sqr(y->ptr.p_double[i]-avg, _state); - } - } - if( ae_fp_neq(tss,0) ) - { - rep->r2 = ae_maxreal(1.0-rss/tss, 0.0, _state); - } - else - { - rep->r2 = 1.0; - } - } - else - { - rep->r2 = 0; - } - - /* - * Compute estimate of proportionality between noise in the data and weights: - * NoiseC = mean(per-point-noise*per-point-weight) - * Noise level (standard deviation) at each point is equal to NoiseC/W[I]. - */ - if( nzcnt>k ) - { - noisec = 0.0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(w->ptr.p_double[i],0) ) - { - v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); - v = v+f0->ptr.p_double[i]; - noisec = noisec+ae_sqr((v-y->ptr.p_double[i])*w->ptr.p_double[i], _state); - } - } - noisec = ae_sqrt(noisec/(nzcnt-k), _state); - } - else - { - noisec = 0.0; - } - - /* - * Two branches on noise level: - * * NoiseC>0 normal situation - * * NoiseC=0 degenerate case CovPar is filled by zeros - */ - rmatrixsetlengthatleast(&rep->covpar, k, k, _state); - if( ae_fp_greater(noisec,0) ) - { - - /* - * Normal situation: non-zero noise level - */ - ae_assert(zkind==0||zkind==1, "LSFit: internal error in EstimateErrors() function", _state); - if( zkind==0 ) - { - - /* - * Z contains no additional information which can be used to speed up - * calculations. We have to calculate covariance matrix on our own: - * * Compute scaled Jacobian N*J, where N[i,i]=WCur[I]/NoiseC, store in Z - * * Compute Z'*Z, store in CovPar - * * Apply moderate regularization to CovPar and compute matrix inverse. - * In case inverse failed, increase regularization parameter and try - * again. - */ - rmatrixsetlengthatleast(z, n, k, _state); - for(i=0; i<=n-1; i++) - { - v = w->ptr.p_double[i]/noisec; - ae_v_moved(&z->ptr.pp_double[i][0], 1, &f1->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); - } - - /* - * Convert S to automatically scaled damped matrix: - * * calculate SZ - sum of diagonal elements of Z'*Z - * * calculate SS - sum of diagonal elements of S^(-2) - * * overwrite S by (SZ/SS)*S^(-2) - * * now S has approximately same magnitude as giagonal of Z'*Z - */ - sz = 0; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=k-1; j++) - { - sz = sz+z->ptr.pp_double[i][j]*z->ptr.pp_double[i][j]; - } - } - if( ae_fp_eq(sz,0) ) - { - sz = 1; - } - ss = 0; - for(j=0; j<=k-1; j++) - { - ss = ss+1/ae_sqr(s->ptr.p_double[j], _state); - } - for(j=0; j<=k-1; j++) - { - s->ptr.p_double[j] = sz/ss/ae_sqr(s->ptr.p_double[j], _state); - } - - /* - * Calculate damped inverse inv(Z'*Z+S). - * We increase damping factor V until Z'*Z become well-conditioned. - */ - v = 1.0E3*ae_machineepsilon; - do - { - rmatrixsyrk(k, n, 1.0, z, 0, 0, 2, 0.0, &rep->covpar, 0, 0, ae_true, _state); - for(i=0; i<=k-1; i++) - { - rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i]; - } - spdmatrixinverse(&rep->covpar, k, ae_true, &info, &invrep, _state); - v = 10*v; - } - while(info<=0); - for(i=0; i<=k-1; i++) - { - for(j=i+1; j<=k-1; j++) - { - rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; - } - } - } - if( zkind==1 ) - { - - /* - * We can reuse additional information: - * * Z contains R matrix from QR decomposition of W*F1 - * * After multiplication by 1/NoiseC we get Z_mod = N*F1, where diag(N)=w[i]/NoiseC - * * Such triangular Z_mod is a Cholesky factor from decomposition of J'*N'*N*J. - * Thus, we can calculate covariance matrix as inverse of the matrix given by - * its Cholesky decomposition. It allow us to avoid time-consuming calculation - * of J'*N'*N*J in CovPar - complexity is reduced from O(N*K^2) to O(K^3), which - * is quite good because K is usually orders of magnitude smaller than N. - * - * First, convert S to automatically scaled damped matrix: - * * calculate SZ - sum of magnitudes of diagonal elements of Z/NoiseC - * * calculate SS - sum of diagonal elements of S^(-1) - * * overwrite S by (SZ/SS)*S^(-1) - * * now S has approximately same magnitude as giagonal of Z'*Z - */ - sz = 0; - for(j=0; j<=k-1; j++) - { - sz = sz+ae_fabs(z->ptr.pp_double[j][j]/noisec, _state); - } - if( ae_fp_eq(sz,0) ) - { - sz = 1; - } - ss = 0; - for(j=0; j<=k-1; j++) - { - ss = ss+1/s->ptr.p_double[j]; - } - for(j=0; j<=k-1; j++) - { - s->ptr.p_double[j] = sz/ss/s->ptr.p_double[j]; - } - - /* - * Calculate damped inverse of inv((Z+v*S)'*(Z+v*S)) - * We increase damping factor V until matrix become well-conditioned. - */ - v = 1.0E3*ae_machineepsilon; - do - { - for(i=0; i<=k-1; i++) - { - for(j=i; j<=k-1; j++) - { - rep->covpar.ptr.pp_double[i][j] = z->ptr.pp_double[i][j]/noisec; - } - rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i]; - } - spdmatrixcholeskyinverse(&rep->covpar, k, ae_true, &info, &invrep, _state); - v = 10*v; - } - while(info<=0); - for(i=0; i<=k-1; i++) - { - for(j=i+1; j<=k-1; j++) - { - rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; - } - } - } - } - else - { - - /* - * Degenerate situation: zero noise level, covariance matrix is zero. - */ - for(i=0; i<=k-1; i++) - { - for(j=0; j<=k-1; j++) - { - rep->covpar.ptr.pp_double[j][i] = 0; - } - } - } - - /* - * Estimate erorrs in parameters, curve and per-point noise - */ - rvectorsetlengthatleast(&rep->errpar, k, _state); - rvectorsetlengthatleast(&rep->errcurve, n, _state); - rvectorsetlengthatleast(&rep->noise, n, _state); - for(i=0; i<=k-1; i++) - { - rep->errpar.ptr.p_double[i] = ae_sqrt(rep->covpar.ptr.pp_double[i][i], _state); - } - for(i=0; i<=n-1; i++) - { - - /* - * ErrCurve[I] is sqrt(P[i,i]) where P=J*CovPar*J' - */ - v = 0.0; - for(j=0; j<=k-1; j++) - { - for(j1=0; j1<=k-1; j1++) - { - v = v+f1->ptr.pp_double[i][j]*rep->covpar.ptr.pp_double[j][j1]*f1->ptr.pp_double[i][j1]; - } - } - rep->errcurve.ptr.p_double[i] = ae_sqrt(v, _state); - - /* - * Noise[i] is filled using weights and current estimate of noise level - */ - if( ae_fp_neq(w->ptr.p_double[i],0) ) - { - rep->noise.ptr.p_double[i] = noisec/w->ptr.p_double[i]; - } - else - { - rep->noise.ptr.p_double[i] = 0; - } - } - ae_frame_leave(_state); -} - - -ae_bool _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - polynomialfitreport *p = (polynomialfitreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - polynomialfitreport *dst = (polynomialfitreport*)_dst; - polynomialfitreport *src = (polynomialfitreport*)_src; - dst->taskrcond = src->taskrcond; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->maxerror = src->maxerror; - return ae_true; -} - - -void _polynomialfitreport_clear(void* _p) -{ - polynomialfitreport *p = (polynomialfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _polynomialfitreport_destroy(void* _p) -{ - polynomialfitreport *p = (polynomialfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - barycentricfitreport *p = (barycentricfitreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - barycentricfitreport *dst = (barycentricfitreport*)_dst; - barycentricfitreport *src = (barycentricfitreport*)_src; - dst->taskrcond = src->taskrcond; - dst->dbest = src->dbest; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->maxerror = src->maxerror; - return ae_true; -} - - -void _barycentricfitreport_clear(void* _p) -{ - barycentricfitreport *p = (barycentricfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _barycentricfitreport_destroy(void* _p) -{ - barycentricfitreport *p = (barycentricfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - spline1dfitreport *p = (spline1dfitreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - spline1dfitreport *dst = (spline1dfitreport*)_dst; - spline1dfitreport *src = (spline1dfitreport*)_src; - dst->taskrcond = src->taskrcond; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->maxerror = src->maxerror; - return ae_true; -} - - -void _spline1dfitreport_clear(void* _p) -{ - spline1dfitreport *p = (spline1dfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _spline1dfitreport_destroy(void* _p) -{ - spline1dfitreport *p = (spline1dfitreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - lsfitreport *p = (lsfitreport*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->covpar, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->errpar, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->errcurve, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->noise, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - lsfitreport *dst = (lsfitreport*)_dst; - lsfitreport *src = (lsfitreport*)_src; - dst->taskrcond = src->taskrcond; - dst->iterationscount = src->iterationscount; - dst->varidx = src->varidx; - dst->rmserror = src->rmserror; - dst->avgerror = src->avgerror; - dst->avgrelerror = src->avgrelerror; - dst->maxerror = src->maxerror; - dst->wrmserror = src->wrmserror; - if( !ae_matrix_init_copy(&dst->covpar, &src->covpar, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->errpar, &src->errpar, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->errcurve, &src->errcurve, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->noise, &src->noise, _state, make_automatic) ) - return ae_false; - dst->r2 = src->r2; - return ae_true; -} - - -void _lsfitreport_clear(void* _p) -{ - lsfitreport *p = (lsfitreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->covpar); - ae_vector_clear(&p->errpar); - ae_vector_clear(&p->errcurve); - ae_vector_clear(&p->noise); -} - - -void _lsfitreport_destroy(void* _p) -{ - lsfitreport *p = (lsfitreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->covpar); - ae_vector_destroy(&p->errpar); - ae_vector_destroy(&p->errcurve); - ae_vector_destroy(&p->noise); -} - - -ae_bool _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - lsfitstate *p = (lsfitstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->taskx, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tasky, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->taskw, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->wcur, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpjac, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpjacw, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_matinvreport_init(&p->invrep, _state, make_automatic) ) - return ae_false; - if( !_lsfitreport_init(&p->rep, _state, make_automatic) ) - return ae_false; - if( !_minlmstate_init(&p->optstate, _state, make_automatic) ) - return ae_false; - if( !_minlmreport_init(&p->optrep, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - lsfitstate *dst = (lsfitstate*)_dst; - lsfitstate *src = (lsfitstate*)_src; - dst->optalgo = src->optalgo; - dst->m = src->m; - dst->k = src->k; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->stpmax = src->stpmax; - dst->xrep = src->xrep; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->taskx, &src->taskx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tasky, &src->tasky, _state, make_automatic) ) - return ae_false; - dst->npoints = src->npoints; - if( !ae_vector_init_copy(&dst->taskw, &src->taskw, _state, make_automatic) ) - return ae_false; - dst->nweights = src->nweights; - dst->wkind = src->wkind; - dst->wits = src->wits; - dst->diffstep = src->diffstep; - dst->teststep = src->teststep; - dst->xupdated = src->xupdated; - dst->needf = src->needf; - dst->needfg = src->needfg; - dst->needfgh = src->needfgh; - dst->pointindex = src->pointindex; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->wcur, &src->wcur, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp, &src->tmp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpf, &src->tmpf, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpjac, &src->tmpjac, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpjacw, &src->tmpjacw, _state, make_automatic) ) - return ae_false; - dst->tmpnoise = src->tmpnoise; - if( !_matinvreport_init_copy(&dst->invrep, &src->invrep, _state, make_automatic) ) - return ae_false; - dst->repiterationscount = src->repiterationscount; - dst->repterminationtype = src->repterminationtype; - dst->repvaridx = src->repvaridx; - dst->reprmserror = src->reprmserror; - dst->repavgerror = src->repavgerror; - dst->repavgrelerror = src->repavgrelerror; - dst->repmaxerror = src->repmaxerror; - dst->repwrmserror = src->repwrmserror; - if( !_lsfitreport_init_copy(&dst->rep, &src->rep, _state, make_automatic) ) - return ae_false; - if( !_minlmstate_init_copy(&dst->optstate, &src->optstate, _state, make_automatic) ) - return ae_false; - if( !_minlmreport_init_copy(&dst->optrep, &src->optrep, _state, make_automatic) ) - return ae_false; - dst->prevnpt = src->prevnpt; - dst->prevalgo = src->prevalgo; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _lsfitstate_clear(void* _p) -{ - lsfitstate *p = (lsfitstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->s); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_matrix_clear(&p->taskx); - ae_vector_clear(&p->tasky); - ae_vector_clear(&p->taskw); - ae_vector_clear(&p->x); - ae_vector_clear(&p->c); - ae_vector_clear(&p->g); - ae_matrix_clear(&p->h); - ae_vector_clear(&p->wcur); - ae_vector_clear(&p->tmp); - ae_vector_clear(&p->tmpf); - ae_matrix_clear(&p->tmpjac); - ae_matrix_clear(&p->tmpjacw); - _matinvreport_clear(&p->invrep); - _lsfitreport_clear(&p->rep); - _minlmstate_clear(&p->optstate); - _minlmreport_clear(&p->optrep); - _rcommstate_clear(&p->rstate); -} - - -void _lsfitstate_destroy(void* _p) -{ - lsfitstate *p = (lsfitstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_matrix_destroy(&p->taskx); - ae_vector_destroy(&p->tasky); - ae_vector_destroy(&p->taskw); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->c); - ae_vector_destroy(&p->g); - ae_matrix_destroy(&p->h); - ae_vector_destroy(&p->wcur); - ae_vector_destroy(&p->tmp); - ae_vector_destroy(&p->tmpf); - ae_matrix_destroy(&p->tmpjac); - ae_matrix_destroy(&p->tmpjacw); - _matinvreport_destroy(&p->invrep); - _lsfitreport_destroy(&p->rep); - _minlmstate_destroy(&p->optstate); - _minlmreport_destroy(&p->optrep); - _rcommstate_destroy(&p->rstate); -} - - - - -/************************************************************************* -This function builds non-periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - Order of points is important! - N - points count, N>=5 for Akima splines, N>=2 for other types of - splines. - ST - spline type: - * 0 Akima spline - * 1 parabolically terminated Catmull-Rom spline (Tension=0) - * 2 parabolically terminated cubic spline - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2build(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline2interpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _xy; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_xy, xy, _state, ae_true); - xy = &_xy; - _pspline2interpolant_clear(p); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - ae_assert(st>=0&&st<=2, "PSpline2Build: incorrect spline type!", _state); - ae_assert(pt>=0&&pt<=2, "PSpline2Build: incorrect parameterization type!", _state); - if( st==0 ) - { - ae_assert(n>=5, "PSpline2Build: N<5 (minimum value for Akima splines)!", _state); - } - else - { - ae_assert(n>=2, "PSpline2Build: N<2!", _state); - } - - /* - * Prepare - */ - p->n = n; - p->periodic = ae_false; - ae_vector_set_length(&tmp, n, _state); - - /* - * Build parameterization, check that all parameters are distinct - */ - pspline_pspline2par(xy, n, pt, &p->p, _state); - ae_assert(aredistinct(&p->p, n, _state), "PSpline2Build: consequent points are too close!", _state); - - /* - * Build splines - */ - if( st==0 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); - } - if( st==1 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); - } - if( st==2 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function builds non-periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3build(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline3interpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _xy; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_xy, xy, _state, ae_true); - xy = &_xy; - _pspline3interpolant_clear(p); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - ae_assert(st>=0&&st<=2, "PSpline3Build: incorrect spline type!", _state); - ae_assert(pt>=0&&pt<=2, "PSpline3Build: incorrect parameterization type!", _state); - if( st==0 ) - { - ae_assert(n>=5, "PSpline3Build: N<5 (minimum value for Akima splines)!", _state); - } - else - { - ae_assert(n>=2, "PSpline3Build: N<2!", _state); - } - - /* - * Prepare - */ - p->n = n; - p->periodic = ae_false; - ae_vector_set_length(&tmp, n, _state); - - /* - * Build parameterization, check that all parameters are distinct - */ - pspline_pspline3par(xy, n, pt, &p->p, _state); - ae_assert(aredistinct(&p->p, n, _state), "PSpline3Build: consequent points are too close!", _state); - - /* - * Build splines - */ - if( st==0 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); - spline1dbuildakima(&p->p, &tmp, n, &p->z, _state); - } - if( st==1 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->z, _state); - } - if( st==2 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); - spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->z, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function builds periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then -back to (X[0],Y[0]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - XY[N-1,0:1] must be different from XY[0,0:1]. - Order of points is important! - N - points count, N>=3 for other types of splines. - ST - spline type: - * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions - * 2 cubic spline with cyclic boundary conditions - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). -* last point of sequence is NOT equal to the first point. You shouldn't - make curve "explicitly periodic" by making them equal. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2buildperiodic(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline2interpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _xy; - ae_matrix xyp; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_xy, xy, _state, ae_true); - xy = &_xy; - _pspline2interpolant_clear(p); - ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - ae_assert(st>=1&&st<=2, "PSpline2BuildPeriodic: incorrect spline type!", _state); - ae_assert(pt>=0&&pt<=2, "PSpline2BuildPeriodic: incorrect parameterization type!", _state); - ae_assert(n>=3, "PSpline2BuildPeriodic: N<3!", _state); - - /* - * Prepare - */ - p->n = n; - p->periodic = ae_true; - ae_vector_set_length(&tmp, n+1, _state); - ae_matrix_set_length(&xyp, n+1, 2, _state); - ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,1)); - - /* - * Build parameterization, check that all parameters are distinct - */ - pspline_pspline2par(&xyp, n+1, pt, &p->p, _state); - ae_assert(aredistinct(&p->p, n+1, _state), "PSpline2BuildPeriodic: consequent (or first and last) points are too close!", _state); - - /* - * Build splines - */ - if( st==1 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); - spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); - spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); - } - if( st==2 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); - spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); - spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function builds periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) -and then back to (X[0],Y[0],Z[0]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3buildperiodic(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline3interpolant* p, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _xy; - ae_matrix xyp; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_xy, xy, _state, ae_true); - xy = &_xy; - _pspline3interpolant_clear(p); - ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - ae_assert(st>=1&&st<=2, "PSpline3BuildPeriodic: incorrect spline type!", _state); - ae_assert(pt>=0&&pt<=2, "PSpline3BuildPeriodic: incorrect parameterization type!", _state); - ae_assert(n>=3, "PSpline3BuildPeriodic: N<3!", _state); - - /* - * Prepare - */ - p->n = n; - p->periodic = ae_true; - ae_vector_set_length(&tmp, n+1, _state); - ae_matrix_set_length(&xyp, n+1, 3, _state); - ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1)); - ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1)); - ae_v_move(&xyp.ptr.pp_double[0][2], xyp.stride, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1)); - ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,2)); - - /* - * Build parameterization, check that all parameters are distinct - */ - pspline_pspline3par(&xyp, n+1, pt, &p->p, _state); - ae_assert(aredistinct(&p->p, n+1, _state), "PSplineBuild2Periodic: consequent (or first and last) points are too close!", _state); - - /* - * Build splines - */ - if( st==1 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); - spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); - spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); - spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->z, _state); - } - if( st==2 ) - { - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); - spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); - spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); - ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); - spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->z, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function returns vector of parameter values correspoding to points. - -I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we -have - (X[0],Y[0]) = PSpline2Calc(P,U[0]), - (X[1],Y[1]) = PSpline2Calc(P,U[1]), - (X[2],Y[2]) = PSpline2Calc(P,U[2]), - ... - -INPUT PARAMETERS: - P - parametric spline interpolant - -OUTPUT PARAMETERS: - N - array size - T - array[0..N-1] - - -NOTES: -* for non-periodic splines U[0]=0, U[0]n>=2, "PSpline2ParameterValues: internal error!", _state); - *n = p->n; - ae_vector_set_length(t, *n, _state); - ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); - t->ptr.p_double[0] = 0; - if( !p->periodic ) - { - t->ptr.p_double[*n-1] = 1; - } -} - - -/************************************************************************* -This function returns vector of parameter values correspoding to points. - -Same as PSpline2ParameterValues(), but for 3D. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3parametervalues(pspline3interpolant* p, - ae_int_t* n, - /* Real */ ae_vector* t, - ae_state *_state) -{ - - *n = 0; - ae_vector_clear(t); - - ae_assert(p->n>=2, "PSpline3ParameterValues: internal error!", _state); - *n = p->n; - ae_vector_set_length(t, *n, _state); - ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); - t->ptr.p_double[0] = 0; - if( !p->periodic ) - { - t->ptr.p_double[*n-1] = 1; - } -} - - -/************************************************************************* -This function calculates the value of the parametric spline for a given -value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2calc(pspline2interpolant* p, - double t, - double* x, - double* y, - ae_state *_state) -{ - - *x = 0; - *y = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - *x = spline1dcalc(&p->x, t, _state); - *y = spline1dcalc(&p->y, t, _state); -} - - -/************************************************************************* -This function calculates the value of the parametric spline for a given -value of parameter T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - Z - Z-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3calc(pspline3interpolant* p, - double t, - double* x, - double* y, - double* z, - ae_state *_state) -{ - - *x = 0; - *y = 0; - *z = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - *x = spline1dcalc(&p->x, t, _state); - *y = spline1dcalc(&p->y, t, _state); - *z = spline1dcalc(&p->z, t, _state); -} - - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - -NOTE: - X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2tangent(pspline2interpolant* p, - double t, - double* x, - double* y, - ae_state *_state) -{ - double v; - double v0; - double v1; - - *x = 0; - *y = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - pspline2diff(p, t, &v0, x, &v1, y, _state); - if( ae_fp_neq(*x,0)||ae_fp_neq(*y,0) ) - { - - /* - * this code is a bit more complex than X^2+Y^2 to avoid - * overflow for large values of X and Y. - */ - v = safepythag2(*x, *y, _state); - *x = *x/v; - *y = *y/v; - } -} - - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - Z - Z-component of tangent vector (normalized) - -NOTE: - X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3tangent(pspline3interpolant* p, - double t, - double* x, - double* y, - double* z, - ae_state *_state) -{ - double v; - double v0; - double v1; - double v2; - - *x = 0; - *y = 0; - *z = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - pspline3diff(p, t, &v0, x, &v1, y, &v2, z, _state); - if( (ae_fp_neq(*x,0)||ae_fp_neq(*y,0))||ae_fp_neq(*z,0) ) - { - v = safepythag3(*x, *y, *z, _state); - *x = *x/v; - *y = *y/v; - *z = *z/v; - } -} - - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff(pspline2interpolant* p, - double t, - double* x, - double* dx, - double* y, - double* dy, - ae_state *_state) -{ - double d2s; - - *x = 0; - *dx = 0; - *y = 0; - *dy = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - spline1ddiff(&p->x, t, x, dx, &d2s, _state); - spline1ddiff(&p->y, t, y, dy, &d2s, _state); -} - - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - Z - Z-value - DZ - Z-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff(pspline3interpolant* p, - double t, - double* x, - double* dx, - double* y, - double* dy, - double* z, - double* dz, - ae_state *_state) -{ - double d2s; - - *x = 0; - *dx = 0; - *y = 0; - *dy = 0; - *z = 0; - *dz = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - spline1ddiff(&p->x, t, x, dx, &d2s, _state); - spline1ddiff(&p->y, t, y, dy, &d2s, _state); - spline1ddiff(&p->z, t, z, dz, &d2s, _state); -} - - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff2(pspline2interpolant* p, - double t, - double* x, - double* dx, - double* d2x, - double* y, - double* dy, - double* d2y, - ae_state *_state) -{ - - *x = 0; - *dx = 0; - *d2x = 0; - *y = 0; - *dy = 0; - *d2y = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - spline1ddiff(&p->x, t, x, dx, d2x, _state); - spline1ddiff(&p->y, t, y, dy, d2y, _state); -} - - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - Z - Z-value - DZ - derivative - D2Z - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff2(pspline3interpolant* p, - double t, - double* x, - double* dx, - double* d2x, - double* y, - double* dy, - double* d2y, - double* z, - double* dz, - double* d2z, - ae_state *_state) -{ - - *x = 0; - *dx = 0; - *d2x = 0; - *y = 0; - *dy = 0; - *d2y = 0; - *z = 0; - *dz = 0; - *d2z = 0; - - if( p->periodic ) - { - t = t-ae_ifloor(t, _state); - } - spline1ddiff(&p->x, t, x, dx, d2x, _state); - spline1ddiff(&p->y, t, y, dy, d2y, _state); - spline1ddiff(&p->z, t, z, dz, d2z, _state); -} - - -/************************************************************************* -This function calculates arc length, i.e. length of curve between t=a -and t=b. - -INPUT PARAMETERS: - P - parametric spline interpolant - A,B - parameter values corresponding to arc ends: - * B>A will result in positive length returned - * Bx, state.x, &sx, &dsx, &d2sx, _state); - spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); - state.f = safepythag2(dsx, dsy, _state); - } - autogkresults(&state, &result, &rep, _state); - ae_assert(rep.terminationtype>0, "PSpline2ArcLength: internal error!", _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -This function calculates arc length, i.e. length of curve between t=a -and t=b. - -INPUT PARAMETERS: - P - parametric spline interpolant - A,B - parameter values corresponding to arc ends: - * B>A will result in positive length returned - * Bx, state.x, &sx, &dsx, &d2sx, _state); - spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); - spline1ddiff(&p->z, state.x, &sz, &dsz, &d2sz, _state); - state.f = safepythag3(dsx, dsy, dsz, _state); - } - autogkresults(&state, &result, &rep, _state); - ae_assert(rep.terminationtype>0, "PSpline3ArcLength: internal error!", _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Builds non-periodic parameterization for 2-dimensional spline -*************************************************************************/ -static void pspline_pspline2par(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t pt, - /* Real */ ae_vector* p, - ae_state *_state) -{ - double v; - ae_int_t i; - - ae_vector_clear(p); - - ae_assert(pt>=0&&pt<=2, "PSpline2Par: internal error!", _state); - - /* - * Build parameterization: - * * fill by non-normalized values - * * normalize them so we have P[0]=0, P[N-1]=1. - */ - ae_vector_set_length(p, n, _state); - if( pt==0 ) - { - for(i=0; i<=n-1; i++) - { - p->ptr.p_double[i] = i; - } - } - if( pt==1 ) - { - p->ptr.p_double[0] = 0; - for(i=1; i<=n-1; i++) - { - p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state); - } - } - if( pt==2 ) - { - p->ptr.p_double[0] = 0; - for(i=1; i<=n-1; i++) - { - p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state), _state); - } - } - v = 1/p->ptr.p_double[n-1]; - ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); -} - - -/************************************************************************* -Builds non-periodic parameterization for 3-dimensional spline -*************************************************************************/ -static void pspline_pspline3par(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t pt, - /* Real */ ae_vector* p, - ae_state *_state) -{ - double v; - ae_int_t i; - - ae_vector_clear(p); - - ae_assert(pt>=0&&pt<=2, "PSpline3Par: internal error!", _state); - - /* - * Build parameterization: - * * fill by non-normalized values - * * normalize them so we have P[0]=0, P[N-1]=1. - */ - ae_vector_set_length(p, n, _state); - if( pt==0 ) - { - for(i=0; i<=n-1; i++) - { - p->ptr.p_double[i] = i; - } - } - if( pt==1 ) - { - p->ptr.p_double[0] = 0; - for(i=1; i<=n-1; i++) - { - p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state); - } - } - if( pt==2 ) - { - p->ptr.p_double[0] = 0; - for(i=1; i<=n-1; i++) - { - p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state), _state); - } - } - v = 1/p->ptr.p_double[n-1]; - ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); -} - - -ae_bool _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - pspline2interpolant *p = (pspline2interpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init(&p->x, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init(&p->y, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - pspline2interpolant *dst = (pspline2interpolant*)_dst; - pspline2interpolant *src = (pspline2interpolant*)_src; - dst->n = src->n; - dst->periodic = src->periodic; - if( !ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _pspline2interpolant_clear(void* _p) -{ - pspline2interpolant *p = (pspline2interpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->p); - _spline1dinterpolant_clear(&p->x); - _spline1dinterpolant_clear(&p->y); -} - - -void _pspline2interpolant_destroy(void* _p) -{ - pspline2interpolant *p = (pspline2interpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->p); - _spline1dinterpolant_destroy(&p->x); - _spline1dinterpolant_destroy(&p->y); -} - - -ae_bool _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - pspline3interpolant *p = (pspline3interpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init(&p->x, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init(&p->y, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init(&p->z, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - pspline3interpolant *dst = (pspline3interpolant*)_dst; - pspline3interpolant *src = (pspline3interpolant*)_src; - dst->n = src->n; - dst->periodic = src->periodic; - if( !ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !_spline1dinterpolant_init_copy(&dst->z, &src->z, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _pspline3interpolant_clear(void* _p) -{ - pspline3interpolant *p = (pspline3interpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->p); - _spline1dinterpolant_clear(&p->x); - _spline1dinterpolant_clear(&p->y); - _spline1dinterpolant_clear(&p->z); -} - - -void _pspline3interpolant_destroy(void* _p) -{ - pspline3interpolant *p = (pspline3interpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->p); - _spline1dinterpolant_destroy(&p->x); - _spline1dinterpolant_destroy(&p->y); - _spline1dinterpolant_destroy(&p->z); -} - - - - -/************************************************************************* -This function creates RBF model for a scalar (NY=1) or vector (NY>1) -function in a NX-dimensional space (NX=2 or NX=3). - -Newly created model is empty. It can be used for interpolation right after -creation, but it just returns zeros. You have to add points to the model, -tune interpolation settings, and then call model construction function -RBFBuildModel() which will update model according to your specification. - -USAGE: -1. User creates model with RBFCreate() -2. User adds dataset with RBFSetPoints() (points do NOT have to be on a - regular grid) -3. (OPTIONAL) User chooses polynomial term by calling: - * RBFLinTerm() to set linear term - * RBFConstTerm() to set constant term - * RBFZeroTerm() to set zero term - By default, linear term is used. -4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) - or ML (RBFSetAlgoMultiLayer). -5. User calls RBFBuildModel() function which rebuilds model according to - the specification -6. User may call RBFCalc() to calculate model value at the specified point, - RBFGridCalc() to calculate model values at the points of the regular - grid. User may extract model coefficients with RBFUnpack() call. - -INPUT PARAMETERS: - NX - dimension of the space, NX=2 or NX=3 - NY - function dimension, NY>=1 - -OUTPUT PARAMETERS: - S - RBF model (initially equals to zero) - -NOTE 1: memory requirements. RBF models require amount of memory which is - proportional to the number of data points. Memory is allocated - during model construction, but most of this memory is freed after - model coefficients are calculated. - - Some approximate estimates for N centers with default settings are - given below: - * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is - needed during model construction stage. - * about 15*N*sizeof(double) bytes is needed after model is built. - For example, for N=100000 we may need 0.6 GB of memory to build - model, but just about 0.012 GB to store it. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - _rbfmodel_clear(s); - - ae_assert(nx==2||nx==3, "RBFCreate: NX<>2 and NX<>3", _state); - ae_assert(ny>=1, "RBFCreate: NY<1", _state); - s->nx = nx; - s->ny = ny; - s->nl = 0; - s->nc = 0; - ae_matrix_set_length(&s->v, ny, rbf_mxnx+1, _state); - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - s->v.ptr.pp_double[i][j] = 0; - } - } - s->n = 0; - s->rmax = 0; - s->gridtype = 2; - s->fixrad = ae_false; - s->radvalue = 1; - s->radzvalue = 5; - s->aterm = 1; - s->algorithmtype = 1; - - /* - * stopping criteria - */ - s->epsort = rbf_eps; - s->epserr = rbf_eps; - s->maxits = 0; -} - - -/************************************************************************* -This function adds dataset. - -This function overrides results of the previous calls, i.e. multiple calls -of this function will result in only the last set being added. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call. - XY - points, array[N,NX+NY]. One row corresponds to one point - in the dataset. First NX elements are coordinates, next - NY elements are function values. Array may be larger than - specific, in this case only leading [N,NX+NY] elements - will be used. - N - number of points in the dataset - -After you've added dataset and (optionally) tuned algorithm settings you -should call RBFBuildModel() in order to build a model for you. - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetpoints(rbfmodel* s, - /* Real */ ae_matrix* xy, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - ae_assert(n>0, "RBFSetPoints: N<0", _state); - ae_assert(xy->rows>=n, "RBFSetPoints: Rows(XY)cols>=s->nx+s->ny, "RBFSetPoints: Cols(XY)n = n; - ae_matrix_set_length(&s->x, s->n, rbf_mxnx, _state); - ae_matrix_set_length(&s->y, s->n, s->ny, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - s->x.ptr.pp_double[i][j] = 0; - } - for(j=0; j<=s->nx-1; j++) - { - s->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; - } - for(j=0; j<=s->ny-1; j++) - { - s->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+s->nx]; - } - } -} - - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-QNN and it is good for point sets with -following properties: -a) all points are distinct -b) all points are well separated. -c) points distribution is approximately uniform. There is no "contour - lines", clusters of points, or other small-scale structures. - -Algorithm description: -1) interpolation centers are allocated to data points -2) interpolation radii are calculated as distances to the nearest centers - times Q coefficient (where Q is a value from [0.75,1.50]). -3) after performing (2) radii are transformed in order to avoid situation - when single outlier has very large radius and influences many points - across all dataset. Transformation has following form: - new_r[i] = min(r[i],Z*median(r[])) - where r[i] is I-th radius, median() is a median radius across entire - dataset, Z is user-specified value which controls amount of deviation - from median radius. - -When (a) is violated, we will be unable to build RBF model. When (b) or -(c) are violated, model will be built, but interpolation quality will be -low. See http://www.alglib.net/interpolation/ for more information on this -subject. - -This algorithm is used by default. - -Additional Q parameter controls smoothness properties of the RBF basis: -* Q<0.75 will give perfectly conditioned basis, but terrible smoothness - properties (RBF interpolant will have sharp peaks around function values) -* Q around 1.0 gives good balance between smoothness and condition number -* Q>1.5 will lead to badly conditioned systems and slow convergence of the - underlying linear solver (although smoothness will be very good) -* Q>2.0 will effectively make optimizer useless because it won't converge - within reasonable amount of iterations. It is possible to set such large - Q, but it is advised not to do so. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Q - Q parameter, Q>0, recommended value - 1.0 - Z - Z parameter, Z>0, recommended value - 5.0 - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state) -{ - - - ae_assert(ae_isfinite(q, _state), "RBFSetAlgoQNN: Q is infinite or NAN", _state); - ae_assert(ae_fp_greater(q,0), "RBFSetAlgoQNN: Q<=0", _state); - rbf_rbfgridpoints(s, _state); - rbf_rbfradnn(s, q, z, _state); - s->algorithmtype = 1; -} - - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. -model with subsequently decreasing radii, which allows us to combine -smoothness (due to large radii of the first layers) with exactness (due -to small radii of the last layers) and fast convergence. - -Internally RBF-ML uses many different means of acceleration, from sparse -matrices to KD-trees, which results in algorithm whose working time is -roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a -number of points, Density is an average density if points per unit of the -interpolation space, RBase is an initial radius, NLayers is a number of -layers. - -RBF-ML is good for following kinds of interpolation problems: -1. "exact" problems (perfect fit) with well separated points -2. least squares problems with arbitrary distribution of points (algorithm - gives perfect fit where it is possible, and resorts to least squares - fit in the hard areas). -3. noisy problems where we want to apply some controlled amount of - smoothing. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - RBase - RBase parameter, RBase>0 - NLayers - NLayers parameter, NLayers>0, recommended value to start - with - about 5. - LambdaV - regularization value, can be useful when solving problem - in the least squares sense. Optimal lambda is problem- - dependent and require trial and error. In our experience, - good lambda can be as large as 0.1, and you can use 0.001 - as initial guess. - Default value - 0.01, which is used when LambdaV is not - given. You can specify zero value, but it is not - recommended to do so. - -TUNING ALGORITHM - -In order to use this algorithm you have to choose three parameters: -* initial radius RBase -* number of layers in the model NLayers -* regularization coefficient LambdaV - -Initial radius is easy to choose - you can pick any number several times -larger than the average distance between points. Algorithm won't break -down if you choose radius which is too large (model construction time will -increase, but model will be built correctly). - -Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used -by the last layer) will be smaller than the typical distance between -points. In case model error is too large, you can increase number of -layers. Having more layers will make model construction and evaluation -proportionally slower, but it will allow you to have model which precisely -fits your data. From the other side, if you want to suppress noise, you -can DECREASE number of layers to make your model less flexible. - -Regularization coefficient LambdaV controls smoothness of the individual -models built for each layer. We recommend you to use default value in case -you don't want to tune this parameter, because having non-zero LambdaV -accelerates and stabilizes internal iterative algorithm. In case you want -to suppress noise you can use LambdaV as additional parameter (larger -value = more smoothness) to tune. - -TYPICAL ERRORS - -1. Using initial radius which is too large. Memory requirements of the - RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is - an average density of points per unit of the interpolation space). In - the extreme case of the very large RBase we will need O(N^2) units of - memory - and many layers in order to decrease radius to some reasonably - small value. - -2. Using too small number of layers - RBF models with large radius are not - flexible enough to reproduce small variations in the target function. - You need many layers with different radii, from large to small, in - order to have good model. - -3. Using initial radius which is too small. You will get model with - "holes" in the areas which are too far away from interpolation centers. - However, algorithm will work correctly (and quickly) in this case. - -4. Using too many layers - you will get too large and too slow model. This - model will perfectly reproduce your function, but maybe you will be - able to achieve similar results with less layers (and less memory). - - -- ALGLIB -- - Copyright 02.03.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgomultilayer(rbfmodel* s, - double rbase, - ae_int_t nlayers, - double lambdav, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoMultiLayer: RBase is infinite or NaN", _state); - ae_assert(ae_fp_greater(rbase,0), "RBFSetAlgoMultiLayer: RBase<=0", _state); - ae_assert(nlayers>=0, "RBFSetAlgoMultiLayer: NLayers<0", _state); - ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiLayer: LambdaV is infinite or NAN", _state); - ae_assert(ae_fp_greater_eq(lambdav,0), "RBFSetAlgoMultiLayer: LambdaV<0", _state); - s->radvalue = rbase; - s->nlayers = nlayers; - s->algorithmtype = 2; - s->lambdav = lambdav; -} - - -/************************************************************************* -This function sets linear term (model is a sum of radial basis functions -plus linear polynomial). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetlinterm(rbfmodel* s, ae_state *_state) -{ - - - s->aterm = 1; -} - - -/************************************************************************* -This function sets constant term (model is a sum of radial basis functions -plus constant). This function won't have effect until next call to -RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetconstterm(rbfmodel* s, ae_state *_state) -{ - - - s->aterm = 2; -} - - -/************************************************************************* -This function sets zero term (model is a sum of radial basis functions -without polynomial term). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetzeroterm(rbfmodel* s, ae_state *_state) -{ - - - s->aterm = 3; -} - - -/************************************************************************* -This function sets stopping criteria of the underlying linear solver. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - EpsOrt - orthogonality stopping criterion, EpsOrt>=0. Algorithm will - stop when ||A'*r||<=EpsOrt where A' is a transpose of the - system matrix, r is a residual vector. - Recommended value of EpsOrt is equal to 1E-6. - This criterion will stop algorithm when we have "bad fit" - situation, i.e. when we should stop in a point with large, - nonzero residual. - EpsErr - residual stopping criterion. Algorithm will stop when - ||r||<=EpsErr*||b||, where r is a residual vector, b is a - right part of the system (function values). - Recommended value of EpsErr is equal to 1E-3 or 1E-6. - This criterion will stop algorithm in a "good fit" - situation when we have near-zero residual near the desired - solution. - MaxIts - this criterion will stop algorithm after MaxIts iterations. - It should be used for debugging purposes only! - Zero MaxIts means that no limit is placed on the number of - iterations. - -We recommend to set moderate non-zero values EpsOrt and EpsErr -simultaneously. Values equal to 10E-6 are good to start with. In case you -need high performance and do not need high precision , you may decrease -EpsErr down to 0.001. However, we do not recommend decreasing EpsOrt. - -As for MaxIts, we recommend to leave it zero unless you know what you do. - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetcond(rbfmodel* s, - double epsort, - double epserr, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsort, _state)&&ae_fp_greater_eq(epsort,0), "RBFSetCond: EpsOrt is negative, INF or NAN", _state); - ae_assert(ae_isfinite(epserr, _state)&&ae_fp_greater_eq(epserr,0), "RBFSetCond: EpsB is negative, INF or NAN", _state); - ae_assert(maxits>=0, "RBFSetCond: MaxIts is negative", _state); - if( (ae_fp_eq(epsort,0)&&ae_fp_eq(epserr,0))&&maxits==0 ) - { - s->epsort = rbf_eps; - s->epserr = rbf_eps; - s->maxits = 0; - } - else - { - s->epsort = epsort; - s->epserr = epserr; - s->maxits = maxits; - } -} - - -/************************************************************************* -This function builds RBF model and returns report (contains some -information which can be used for evaluation of the algorithm properties). - -Call to this function modifies RBF model by calculating its centers/radii/ -weights and saving them into RBFModel structure. Initially RBFModel -contain zero coefficients, but after call to this function we will have -coefficients which were calculated in order to fit our dataset. - -After you called this function you can call RBFCalc(), RBFGridCalc() and -other model calculation functions. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Rep - report: - * Rep.TerminationType: - * -5 - non-distinct basis function centers were detected, - interpolation aborted - * -4 - nonconvergence of the internal SVD solver - * 1 - successful termination - Fields are used for debugging purposes: - * Rep.IterationsCount - iterations count of the LSQR solver - * Rep.NMV - number of matrix-vector products - * Rep.ARows - rows count for the system matrix - * Rep.ACols - columns count for the system matrix - * Rep.ANNZ - number of significantly non-zero elements - (elements above some algorithm-determined threshold) - -NOTE: failure to build model will leave current state of the structure -unchanged. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state) -{ - ae_frame _frame_block; - kdtree tree; - kdtree ctree; - ae_vector dist; - ae_vector xcx; - ae_matrix a; - ae_matrix v; - ae_matrix omega; - ae_vector y; - ae_matrix residualy; - ae_vector radius; - ae_matrix xc; - ae_vector mnx; - ae_vector mxx; - ae_vector edge; - ae_vector mxsteps; - ae_int_t nc; - double rmax; - ae_vector tags; - ae_vector ctags; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t k2; - ae_int_t snnz; - ae_vector tmp0; - ae_vector tmp1; - ae_int_t layerscnt; - - ae_frame_make(_state, &_frame_block); - _rbfreport_clear(rep); - _kdtree_init(&tree, _state, ae_true); - _kdtree_init(&ctree, _state, ae_true); - ae_vector_init(&dist, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&omega, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&radius, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&mnx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&mxx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&edge, 0, DT_REAL, _state, ae_true); - ae_vector_init(&mxsteps, 0, DT_INT, _state, ae_true); - ae_vector_init(&tags, 0, DT_INT, _state, ae_true); - ae_vector_init(&ctags, 0, DT_INT, _state, ae_true); - ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); - - ae_assert(s->nx==2||s->nx==3, "RBFBuildModel: S.NX<>2 or S.NX<>3!", _state); - - /* - * Quick exit when we have no points - */ - if( s->n==0 ) - { - rep->terminationtype = 1; - rep->iterationscount = 0; - rep->nmv = 0; - rep->arows = 0; - rep->acols = 0; - kdtreebuildtagged(&s->xc, &tags, 0, rbf_mxnx, 0, 2, &s->tree, _state); - ae_matrix_set_length(&s->xc, 0, 0, _state); - ae_matrix_set_length(&s->wr, 0, 0, _state); - s->nc = 0; - s->rmax = 0; - ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); - for(i=0; i<=s->ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - s->v.ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * General case, N>0 - */ - rep->annz = 0; - rep->iterationscount = 0; - rep->nmv = 0; - ae_vector_set_length(&xcx, rbf_mxnx, _state); - - /* - * First model in a sequence - linear model. - * Residuals from linear regression are stored in the ResidualY variable - * (used later to build RBF models). - */ - ae_matrix_set_length(&residualy, s->n, s->ny, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=s->ny-1; j++) - { - residualy.ptr.pp_double[i][j] = s->y.ptr.pp_double[i][j]; - } - } - if( !rbf_buildlinearmodel(&s->x, &residualy, s->n, s->ny, s->aterm, &v, _state) ) - { - rep->terminationtype = -5; - ae_frame_leave(_state); - return; - } - - /* - * Handle special case: multilayer model with NLayers=0. - * Quick exit. - */ - if( s->algorithmtype==2&&s->nlayers==0 ) - { - rep->terminationtype = 1; - rep->iterationscount = 0; - rep->nmv = 0; - rep->arows = 0; - rep->acols = 0; - kdtreebuildtagged(&s->xc, &tags, 0, rbf_mxnx, 0, 2, &s->tree, _state); - ae_matrix_set_length(&s->xc, 0, 0, _state); - ae_matrix_set_length(&s->wr, 0, 0, _state); - s->nc = 0; - s->rmax = 0; - ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); - for(i=0; i<=s->ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Second model in a sequence - RBF term. - * - * NOTE: assignments below are not necessary, but without them - * MSVC complains about unitialized variables. - */ - nc = 0; - rmax = 0; - layerscnt = 0; - if( s->algorithmtype==1 ) - { - - /* - * Add RBF model. - * This model uses local KD-trees to speed-up nearest neighbor searches. - */ - if( s->gridtype==1 ) - { - ae_vector_set_length(&mxx, s->nx, _state); - ae_vector_set_length(&mnx, s->nx, _state); - ae_vector_set_length(&mxsteps, s->nx, _state); - ae_vector_set_length(&edge, s->nx, _state); - for(i=0; i<=s->nx-1; i++) - { - mxx.ptr.p_double[i] = s->x.ptr.pp_double[0][i]; - mnx.ptr.p_double[i] = s->x.ptr.pp_double[0][i]; - } - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=s->nx-1; j++) - { - if( ae_fp_less(mxx.ptr.p_double[j],s->x.ptr.pp_double[i][j]) ) - { - mxx.ptr.p_double[j] = s->x.ptr.pp_double[i][j]; - } - if( ae_fp_greater(mnx.ptr.p_double[j],s->x.ptr.pp_double[i][j]) ) - { - mnx.ptr.p_double[j] = s->x.ptr.pp_double[i][j]; - } - } - } - for(i=0; i<=s->nx-1; i++) - { - mxsteps.ptr.p_int[i] = ae_trunc((mxx.ptr.p_double[i]-mnx.ptr.p_double[i])/(2*s->h), _state)+1; - edge.ptr.p_double[i] = (mxx.ptr.p_double[i]+mnx.ptr.p_double[i])/2-s->h*mxsteps.ptr.p_int[i]; - } - nc = 1; - for(i=0; i<=s->nx-1; i++) - { - mxsteps.ptr.p_int[i] = 2*mxsteps.ptr.p_int[i]+1; - nc = nc*mxsteps.ptr.p_int[i]; - } - ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); - if( s->nx==2 ) - { - for(i=0; i<=mxsteps.ptr.p_int[0]-1; i++) - { - for(j=0; j<=mxsteps.ptr.p_int[1]-1; j++) - { - for(k2=0; k2<=rbf_mxnx-1; k2++) - { - xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][k2] = 0; - } - xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][0] = edge.ptr.p_double[0]+s->h*i; - xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][1] = edge.ptr.p_double[1]+s->h*j; - } - } - } - if( s->nx==3 ) - { - for(i=0; i<=mxsteps.ptr.p_int[0]-1; i++) - { - for(j=0; j<=mxsteps.ptr.p_int[1]-1; j++) - { - for(k=0; k<=mxsteps.ptr.p_int[2]-1; k++) - { - for(k2=0; k2<=rbf_mxnx-1; k2++) - { - xc.ptr.pp_double[i*mxsteps.ptr.p_int[1]+j][k2] = 0; - } - xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][0] = edge.ptr.p_double[0]+s->h*i; - xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][1] = edge.ptr.p_double[1]+s->h*j; - xc.ptr.pp_double[(i*mxsteps.ptr.p_int[1]+j)*mxsteps.ptr.p_int[2]+k][2] = edge.ptr.p_double[2]+s->h*k; - } - } - } - } - } - else - { - if( s->gridtype==2 ) - { - nc = s->n; - ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); - for(i=0; i<=nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xc.ptr.pp_double[i][j] = s->x.ptr.pp_double[i][j]; - } - } - } - else - { - if( s->gridtype==3 ) - { - nc = s->nc; - ae_matrix_set_length(&xc, nc, rbf_mxnx, _state); - for(i=0; i<=nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xc.ptr.pp_double[i][j] = s->xc.ptr.pp_double[i][j]; - } - } - } - else - { - ae_assert(ae_false, "RBFBuildModel: either S.GridType<1 or S.GridType>3!", _state); - } - } - } - rmax = 0; - ae_vector_set_length(&radius, nc, _state); - ae_vector_set_length(&ctags, nc, _state); - for(i=0; i<=nc-1; i++) - { - ctags.ptr.p_int[i] = i; - } - kdtreebuildtagged(&xc, &ctags, nc, rbf_mxnx, 0, 2, &ctree, _state); - if( s->fixrad ) - { - - /* - * Fixed radius - */ - for(i=0; i<=nc-1; i++) - { - radius.ptr.p_double[i] = s->radvalue; - } - rmax = radius.ptr.p_double[0]; - } - else - { - - /* - * Dynamic radius - */ - if( nc==0 ) - { - rmax = 1; - } - else - { - if( nc==1 ) - { - radius.ptr.p_double[0] = s->radvalue; - rmax = radius.ptr.p_double[0]; - } - else - { - - /* - * NC>1, calculate radii using distances to nearest neigbors - */ - for(i=0; i<=nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xcx.ptr.p_double[j] = xc.ptr.pp_double[i][j]; - } - if( kdtreequeryknn(&ctree, &xcx, 1, ae_false, _state)>0 ) - { - kdtreequeryresultsdistances(&ctree, &dist, _state); - radius.ptr.p_double[i] = s->radvalue*dist.ptr.p_double[0]; - } - else - { - - /* - * No neighbors found (it will happen when we have only one center). - * Initialize radius with default value. - */ - radius.ptr.p_double[i] = 1.0; - } - } - - /* - * Apply filtering - */ - rvectorsetlengthatleast(&tmp0, nc, _state); - for(i=0; i<=nc-1; i++) - { - tmp0.ptr.p_double[i] = radius.ptr.p_double[i]; - } - tagsortfast(&tmp0, &tmp1, nc, _state); - for(i=0; i<=nc-1; i++) - { - radius.ptr.p_double[i] = ae_minreal(radius.ptr.p_double[i], s->radzvalue*tmp0.ptr.p_double[nc/2], _state); - } - - /* - * Calculate RMax, check that all radii are non-zero - */ - for(i=0; i<=nc-1; i++) - { - rmax = ae_maxreal(rmax, radius.ptr.p_double[i], _state); - } - for(i=0; i<=nc-1; i++) - { - if( ae_fp_eq(radius.ptr.p_double[i],0) ) - { - rep->terminationtype = -5; - ae_frame_leave(_state); - return; - } - } - } - } - } - ivectorsetlengthatleast(&tags, s->n, _state); - for(i=0; i<=s->n-1; i++) - { - tags.ptr.p_int[i] = i; - } - kdtreebuildtagged(&s->x, &tags, s->n, rbf_mxnx, 0, 2, &tree, _state); - rbf_buildrbfmodellsqr(&s->x, &residualy, &xc, &radius, s->n, nc, s->ny, &tree, &ctree, s->epsort, s->epserr, s->maxits, &rep->annz, &snnz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); - layerscnt = 1; - } - else - { - if( s->algorithmtype==2 ) - { - rmax = s->radvalue; - rbf_buildrbfmlayersmodellsqr(&s->x, &residualy, &xc, s->radvalue, &radius, s->n, &nc, s->ny, s->nlayers, &ctree, 1.0E-6, 1.0E-6, 50, s->lambdav, &rep->annz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); - layerscnt = s->nlayers; - } - else - { - ae_assert(ae_false, "RBFBuildModel: internal error(AlgorithmType neither 1 nor 2)", _state); - } - } - if( rep->terminationtype<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Model is built - */ - s->nc = nc/layerscnt; - s->rmax = rmax; - s->nl = layerscnt; - ae_matrix_set_length(&s->xc, s->nc, rbf_mxnx, _state); - ae_matrix_set_length(&s->wr, s->nc, 1+s->nl*s->ny, _state); - ae_matrix_set_length(&s->v, s->ny, rbf_mxnx+1, _state); - for(i=0; i<=s->nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - s->xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]; - } - } - ivectorsetlengthatleast(&tags, s->nc, _state); - for(i=0; i<=s->nc-1; i++) - { - tags.ptr.p_int[i] = i; - } - kdtreebuildtagged(&s->xc, &tags, s->nc, rbf_mxnx, 0, 2, &s->tree, _state); - for(i=0; i<=s->nc-1; i++) - { - s->wr.ptr.pp_double[i][0] = radius.ptr.p_double[i]; - for(k=0; k<=layerscnt-1; k++) - { - for(j=0; j<=s->ny-1; j++) - { - s->wr.ptr.pp_double[i][1+k*s->ny+j] = omega.ptr.pp_double[k*s->nc+i][j]; - } - } - } - for(i=0; i<=s->ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; - } - } - rep->terminationtype = 1; - rep->arows = s->n; - rep->acols = s->nc; - ae_frame_leave(_state); -} - - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=2 -(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -If you want to calculate function values many times, consider using -RBFGridCalc2(), which is far more efficient than many subsequent calls to -RBFCalc2(). - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t lx; - ae_int_t tg; - double d2; - double t; - double bfcur; - double rcur; - double result; - - - ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); - ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); - if( s->ny!=1||s->nx!=2 ) - { - result = 0; - return result; - } - result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][rbf_mxnx]; - if( s->nc==0 ) - { - return result; - } - rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); - for(i=0; i<=rbf_mxnx-1; i++) - { - s->calcbufxcx.ptr.p_double[i] = 0.0; - } - s->calcbufxcx.ptr.p_double[0] = x0; - s->calcbufxcx.ptr.p_double[1] = x1; - lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); - kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); - kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); - for(i=0; i<=lx-1; i++) - { - tg = s->calcbuftags.ptr.p_int[i]; - d2 = ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state); - rcur = s->wr.ptr.pp_double[tg][0]; - bfcur = ae_exp(-d2/(rcur*rcur), _state); - for(j=0; j<=s->nl-1; j++) - { - result = result+bfcur*s->wr.ptr.pp_double[tg][1+j]; - rcur = 0.5*rcur; - t = bfcur*bfcur; - bfcur = t*t; - } - } - return result; -} - - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=3 -(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -This function returns 0.0 when: -* model is not initialized -* NX<>3 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - X2 - third coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc3(rbfmodel* s, - double x0, - double x1, - double x2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t lx; - ae_int_t tg; - double t; - double rcur; - double bf; - double result; - - - ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); - ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); - ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); - if( s->ny!=1||s->nx!=3 ) - { - result = 0; - return result; - } - result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][rbf_mxnx]; - if( s->nc==0 ) - { - return result; - } - - /* - * calculating value for F(X) - */ - rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); - for(i=0; i<=rbf_mxnx-1; i++) - { - s->calcbufxcx.ptr.p_double[i] = 0.0; - } - s->calcbufxcx.ptr.p_double[0] = x0; - s->calcbufxcx.ptr.p_double[1] = x1; - s->calcbufxcx.ptr.p_double[2] = x2; - lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); - kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); - kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); - for(i=0; i<=lx-1; i++) - { - tg = s->calcbuftags.ptr.p_int[i]; - rcur = s->wr.ptr.pp_double[tg][0]; - bf = ae_exp(-(ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state)+ae_sqr(x2-s->calcbufx.ptr.pp_double[i][2], _state))/ae_sqr(rcur, _state), _state); - for(j=0; j<=s->nl-1; j++) - { - result = result+bf*s->wr.ptr.pp_double[tg][1+j]; - t = bf*bf; - bf = t*t; - } - } - return result; -} - - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -This is general function which can be used for arbitrary NX (dimension of -the space of arguments) and NY (dimension of the function itself). However -when you have NY=1 you may find more convenient to use RBFCalc2() or -RBFCalc3(). - -This function returns 0.0 when model is not initialized. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is out-parameter and - reallocated after call to this function. In case you want - to reuse previously allocated Y, you may use RBFCalcBuf(), - which reallocates Y only when it is too small. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalc(rbfmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - - ae_vector_clear(y); - - ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)nx, _state), "RBFCalc: X contains infinite or NaN values", _state); - rbfcalcbuf(s, x, y, _state); -} - - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -Same as RBFCalc(), but does not reallocate Y when in is large enough to -store function values. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - Y - possibly preallocated array - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is not reallocated when it - is larger than NY. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalcbuf(rbfmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t lx; - ae_int_t tg; - double t; - double rcur; - double bf; - - - ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); - if( y->cntny ) - { - ae_vector_set_length(y, s->ny, _state); - } - for(i=0; i<=s->ny-1; i++) - { - y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbf_mxnx]; - for(j=0; j<=s->nx-1; j++) - { - y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; - } - } - if( s->nc==0 ) - { - return; - } - rvectorsetlengthatleast(&s->calcbufxcx, rbf_mxnx, _state); - for(i=0; i<=rbf_mxnx-1; i++) - { - s->calcbufxcx.ptr.p_double[i] = 0.0; - } - for(i=0; i<=s->nx-1; i++) - { - s->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; - } - lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbf_rbffarradius, ae_true, _state); - kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); - kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); - for(i=0; i<=s->ny-1; i++) - { - for(j=0; j<=lx-1; j++) - { - tg = s->calcbuftags.ptr.p_int[j]; - rcur = s->wr.ptr.pp_double[tg][0]; - bf = ae_exp(-(ae_sqr(s->calcbufxcx.ptr.p_double[0]-s->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[1]-s->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[2]-s->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state); - for(k=0; k<=s->nl-1; k++) - { - y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i]; - t = bf*bf; - bf = t*t; - } - } - } -} - - -/************************************************************************* -This function calculates values of the RBF model at the regular grid. - -Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - array of grid nodes, first coordinates, array[N0] - N0 - grid size (number of nodes) in the first dimension - X1 - array of grid nodes, second coordinates, array[N1] - N1 - grid size (number of nodes) in the second dimension - -OUTPUT PARAMETERS: - Y - function values, array[N0,N1]. Y is out-variable and - is reallocated by this function. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfgridcalc2(rbfmodel* s, - /* Real */ ae_vector* x0, - ae_int_t n0, - /* Real */ ae_vector* x1, - ae_int_t n1, - /* Real */ ae_matrix* y, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector cpx0; - ae_vector cpx1; - ae_vector p01; - ae_vector p11; - ae_vector p2; - double rlimit; - double xcnorm2; - ae_int_t hp01; - double hcpx0; - double xc0; - double xc1; - double omega; - double radius; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t d; - ae_int_t i00; - ae_int_t i01; - ae_int_t i10; - ae_int_t i11; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(y); - ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p01, 0, DT_INT, _state, ae_true); - ae_vector_init(&p11, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - - ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state); - ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state); - ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)cnt>=n1, "RBFGridCalc2: Length(X1)ptr.pp_double[i][j] = 0; - } - } - if( (s->ny!=1||s->nx!=2)||s->nc==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - *create and sort arrays - */ - ae_vector_set_length(&cpx0, n0, _state); - for(i=0; i<=n0-1; i++) - { - cpx0.ptr.p_double[i] = x0->ptr.p_double[i]; - } - tagsort(&cpx0, n0, &p01, &p2, _state); - ae_vector_set_length(&cpx1, n1, _state); - for(i=0; i<=n1-1; i++) - { - cpx1.ptr.p_double[i] = x1->ptr.p_double[i]; - } - tagsort(&cpx1, n1, &p11, &p2, _state); - - /* - *calculate function's value - */ - for(i=0; i<=s->nc-1; i++) - { - radius = s->wr.ptr.pp_double[i][0]; - for(d=0; d<=s->nl-1; d++) - { - omega = s->wr.ptr.pp_double[i][1+d]; - rlimit = radius*rbf_rbffarradius; - - /* - *search lower and upper indexes - */ - i00 = lowerbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]-rlimit, _state); - i01 = upperbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]+rlimit, _state); - i10 = lowerbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]-rlimit, _state); - i11 = upperbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]+rlimit, _state); - xc0 = s->xc.ptr.pp_double[i][0]; - xc1 = s->xc.ptr.pp_double[i][1]; - for(j=i00; j<=i01-1; j++) - { - hcpx0 = cpx0.ptr.p_double[j]; - hp01 = p01.ptr.p_int[j]; - for(k=i10; k<=i11-1; k++) - { - xcnorm2 = ae_sqr(hcpx0-xc0, _state)+ae_sqr(cpx1.ptr.p_double[k]-xc1, _state); - if( ae_fp_less_eq(xcnorm2,rlimit*rlimit) ) - { - y->ptr.pp_double[hp01][p11.ptr.p_int[k]] = y->ptr.pp_double[hp01][p11.ptr.p_int[k]]+ae_exp(-xcnorm2/ae_sqr(radius, _state), _state)*omega; - } - } - } - radius = 0.5*radius; - } - } - - /* - *add linear term - */ - for(i=0; i<=n0-1; i++) - { - for(j=0; j<=n1-1; j++) - { - y->ptr.pp_double[i][j] = y->ptr.pp_double[i][j]+s->v.ptr.pp_double[0][0]*x0->ptr.p_double[i]+s->v.ptr.pp_double[0][1]*x1->ptr.p_double[j]+s->v.ptr.pp_double[0][rbf_mxnx]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function "unpacks" RBF model by extracting its coefficients. - -INPUT PARAMETERS: - S - RBF model - -OUTPUT PARAMETERS: - NX - dimensionality of argument - NY - dimensionality of the target function - XWR - model information, array[NC,NX+NY+1]. - One row of the array corresponds to one basis function: - * first NX columns - coordinates of the center - * next NY columns - weights, one per dimension of the - function being modelled - * last column - radius, same for all dimensions of - the function being modelled - NC - number of the centers - V - polynomial term , array[NY,NX+1]. One row per one - dimension of the function being modelled. First NX - elements are linear coefficients, V[NX] is equal to the - constant part. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfunpack(rbfmodel* s, - ae_int_t* nx, - ae_int_t* ny, - /* Real */ ae_matrix* xwr, - ae_int_t* nc, - /* Real */ ae_matrix* v, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double rcur; - - *nx = 0; - *ny = 0; - ae_matrix_clear(xwr); - *nc = 0; - ae_matrix_clear(v); - - *nx = s->nx; - *ny = s->ny; - *nc = s->nc; - - /* - * Fill V - */ - ae_matrix_set_length(v, s->ny, s->nx+1, _state); - for(i=0; i<=s->ny-1; i++) - { - ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); - v->ptr.pp_double[i][s->nx] = s->v.ptr.pp_double[i][rbf_mxnx]; - } - - /* - * Fill XWR and V - */ - if( *nc*s->nl>0 ) - { - ae_matrix_set_length(xwr, s->nc*s->nl, s->nx+s->ny+1, _state); - for(i=0; i<=s->nc-1; i++) - { - rcur = s->wr.ptr.pp_double[i][0]; - for(j=0; j<=s->nl-1; j++) - { - ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][0], 1, &s->xc.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); - ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][s->nx], 1, &s->wr.ptr.pp_double[i][1+j*s->ny], 1, ae_v_len(s->nx,s->nx+s->ny-1)); - xwr->ptr.pp_double[i*s->nl+j][s->nx+s->ny] = rcur; - rcur = 0.5*rcur; - } - } - } -} - - -/************************************************************************* -Serializer: allocation - - -- ALGLIB -- - Copyright 02.02.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state) -{ - - - - /* - * Header - */ - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - - /* - * Data - */ - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - ae_serializer_alloc_entry(s); - kdtreealloc(s, &model->tree, _state); - allocrealmatrix(s, &model->xc, -1, -1, _state); - allocrealmatrix(s, &model->wr, -1, -1, _state); - ae_serializer_alloc_entry(s); - allocrealmatrix(s, &model->v, -1, -1, _state); -} - - -/************************************************************************* -Serializer: serialization - - -- ALGLIB -- - Copyright 02.02.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state) -{ - - - - /* - * Header - */ - ae_serializer_serialize_int(s, getrbfserializationcode(_state), _state); - ae_serializer_serialize_int(s, rbf_rbffirstversion, _state); - - /* - * Data - */ - ae_serializer_serialize_int(s, model->nx, _state); - ae_serializer_serialize_int(s, model->ny, _state); - ae_serializer_serialize_int(s, model->nc, _state); - ae_serializer_serialize_int(s, model->nl, _state); - kdtreeserialize(s, &model->tree, _state); - serializerealmatrix(s, &model->xc, -1, -1, _state); - serializerealmatrix(s, &model->wr, -1, -1, _state); - ae_serializer_serialize_double(s, model->rmax, _state); - serializerealmatrix(s, &model->v, -1, -1, _state); -} - - -/************************************************************************* -Serializer: unserialization - - -- ALGLIB -- - Copyright 02.02.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state) -{ - ae_int_t i0; - ae_int_t i1; - ae_int_t nx; - ae_int_t ny; - - _rbfmodel_clear(model); - - - /* - * Header - */ - ae_serializer_unserialize_int(s, &i0, _state); - ae_assert(i0==getrbfserializationcode(_state), "RBFUnserialize: stream header corrupted", _state); - ae_serializer_unserialize_int(s, &i1, _state); - ae_assert(i1==rbf_rbffirstversion, "RBFUnserialize: stream header corrupted", _state); - - /* - * Unserialize primary model parameters, initialize model. - * - * It is necessary to call RBFCreate() because some internal fields - * which are NOT unserialized will need initialization. - */ - ae_serializer_unserialize_int(s, &nx, _state); - ae_serializer_unserialize_int(s, &ny, _state); - rbfcreate(nx, ny, model, _state); - ae_serializer_unserialize_int(s, &model->nc, _state); - ae_serializer_unserialize_int(s, &model->nl, _state); - kdtreeunserialize(s, &model->tree, _state); - unserializerealmatrix(s, &model->xc, _state); - unserializerealmatrix(s, &model->wr, _state); - ae_serializer_unserialize_double(s, &model->rmax, _state); - unserializerealmatrix(s, &model->v, _state); -} - - -/************************************************************************* -This function changes centers allocation algorithm to one which allocates -centers exactly at the dataset points (one input point = one center). This -function won't have effect until next call to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -static void rbf_rbfgridpoints(rbfmodel* s, ae_state *_state) -{ - - - s->gridtype = 2; -} - - -/************************************************************************* -This function changes radii calculation algorithm to one which makes -radius for I-th node equal to R[i]=DistNN[i]*Q, where: -* R[i] is a radius calculated by the algorithm -* DistNN[i] is distance from I-th center to its nearest neighbor center -* Q is a scale parameter, which should be within [0.75,1.50], with - recommended value equal to 1.0 -* after performing radii calculation, radii are transformed in order to - avoid situation when single outlier has very large radius and influences - many points across entire dataset. Transformation has following form: - new_r[i] = min(r[i],Z*median(r[])) - where r[i] is I-th radius, median() is a median radius across entire - dataset, Z is user-specified value which controls amount of deviation - from median radius. - -This function won't have effect until next call to RBFBuildModel(). - -The idea behind this algorithm is to choose radii corresponding to basis -functions is such way that I-th radius is approximately equal to distance -from I-th center to its nearest neighbor. In this case interactions with -distant points will be insignificant, and we will get well conditioned -basis. - -Properties of this basis depend on the value of Q: -* Q<0.75 will give perfectly conditioned basis, but terrible smoothness - properties (RBF interpolant will have sharp peaks around function values) -* Q>1.5 will lead to badly conditioned systems and slow convergence of the - underlying linear solver (although smoothness will be very good) -* Q around 1.0 gives good balance between smoothness and condition number - - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Q - radius coefficient, Q>0 - Z - z-parameter, Z>0 - -Default value of Q is equal to 1.0 -Default value of Z is equal to 5.0 - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -static void rbf_rbfradnn(rbfmodel* s, - double q, - double z, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(q, _state)&&ae_fp_greater(q,0), "RBFRadNN: Q<=0, infinite or NAN", _state); - ae_assert(ae_isfinite(z, _state)&&ae_fp_greater(z,0), "RBFRadNN: Z<=0, infinite or NAN", _state); - s->fixrad = ae_false; - s->radvalue = q; - s->radzvalue = z; -} - - -static ae_bool rbf_buildlinearmodel(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t ny, - ae_int_t modeltype, - /* Real */ ae_matrix* v, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmpy; - ae_matrix a; - double scaling; - ae_vector shifting; - double mn; - double mx; - ae_vector c; - lsfitreport rep; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t info; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(v); - ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_REAL, _state, ae_true); - _lsfitreport_init(&rep, _state, ae_true); - - ae_assert(n>=0, "BuildLinearModel: N<0", _state); - ae_assert(ny>0, "BuildLinearModel: NY<=0", _state); - - /* - * Handle degenerate case (N=0) - */ - result = ae_true; - ae_matrix_set_length(v, ny, rbf_mxnx+1, _state); - if( n==0 ) - { - for(j=0; j<=rbf_mxnx; j++) - { - for(i=0; i<=ny-1; i++) - { - v->ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return result; - } - - /* - * Allocate temporaries - */ - ae_vector_set_length(&tmpy, n, _state); - - /* - * General linear model. - */ - if( modeltype==1 ) - { - - /* - * Calculate scaling/shifting, transform variables, prepare LLS problem - */ - ae_matrix_set_length(&a, n, rbf_mxnx+1, _state); - ae_vector_set_length(&shifting, rbf_mxnx, _state); - scaling = 0; - for(i=0; i<=rbf_mxnx-1; i++) - { - mn = x->ptr.pp_double[0][i]; - mx = mn; - for(j=1; j<=n-1; j++) - { - if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) ) - { - mn = x->ptr.pp_double[j][i]; - } - if( ae_fp_less(mx,x->ptr.pp_double[j][i]) ) - { - mx = x->ptr.pp_double[j][i]; - } - } - scaling = ae_maxreal(scaling, mx-mn, _state); - shifting.ptr.p_double[i] = 0.5*(mx+mn); - } - if( ae_fp_eq(scaling,0) ) - { - scaling = 1; - } - else - { - scaling = 0.5*scaling; - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling; - } - } - for(i=0; i<=n-1; i++) - { - a.ptr.pp_double[i][rbf_mxnx] = 1; - } - - /* - * Solve linear system in transformed variables, make backward - */ - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=n-1; j++) - { - tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; - } - lsfitlinear(&tmpy, &a, n, rbf_mxnx+1, &info, &c, &rep, _state); - if( info<=0 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - for(j=0; j<=rbf_mxnx-1; j++) - { - v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling; - } - v->ptr.pp_double[i][rbf_mxnx] = c.ptr.p_double[rbf_mxnx]; - for(j=0; j<=rbf_mxnx-1; j++) - { - v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j]; - } - for(j=0; j<=n-1; j++) - { - for(k=0; k<=rbf_mxnx-1; k++) - { - y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k]; - } - y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbf_mxnx]; - } - } - ae_frame_leave(_state); - return result; - } - - /* - * Constant model, very simple - */ - if( modeltype==2 ) - { - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - v->ptr.pp_double[i][j] = 0; - } - for(j=0; j<=n-1; j++) - { - v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]+y->ptr.pp_double[j][i]; - } - if( n>0 ) - { - v->ptr.pp_double[i][rbf_mxnx] = v->ptr.pp_double[i][rbf_mxnx]/n; - } - for(j=0; j<=n-1; j++) - { - y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbf_mxnx]; - } - } - ae_frame_leave(_state); - return result; - } - - /* - * Zero model - */ - ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state); - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=rbf_mxnx; j++) - { - v->ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return result; -} - - -static void rbf_buildrbfmodellsqr(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - /* Real */ ae_matrix* xc, - /* Real */ ae_vector* r, - ae_int_t n, - ae_int_t nc, - ae_int_t ny, - kdtree* pointstree, - kdtree* centerstree, - double epsort, - double epserr, - ae_int_t maxits, - ae_int_t* gnnz, - ae_int_t* snnz, - /* Real */ ae_matrix* w, - ae_int_t* info, - ae_int_t* iterationscount, - ae_int_t* nmv, - ae_state *_state) -{ - ae_frame _frame_block; - linlsqrstate state; - linlsqrreport lsqrrep; - sparsematrix spg; - sparsematrix sps; - ae_vector nearcenterscnt; - ae_vector nearpointscnt; - ae_vector skipnearpointscnt; - ae_vector farpointscnt; - ae_int_t maxnearcenterscnt; - ae_int_t maxnearpointscnt; - ae_int_t maxfarpointscnt; - ae_int_t sumnearcenterscnt; - ae_int_t sumnearpointscnt; - ae_int_t sumfarpointscnt; - double maxrad; - ae_vector pointstags; - ae_vector centerstags; - ae_matrix nearpoints; - ae_matrix nearcenters; - ae_matrix farpoints; - ae_int_t tmpi; - ae_int_t pointscnt; - ae_int_t centerscnt; - ae_vector xcx; - ae_vector tmpy; - ae_vector tc; - ae_vector g; - ae_vector c; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t sind; - ae_matrix a; - double vv; - double vx; - double vy; - double vz; - double vr; - double gnorm2; - ae_vector tmp0; - ae_vector tmp1; - ae_vector tmp2; - double fx; - ae_matrix xx; - ae_matrix cx; - double mrad; - - ae_frame_make(_state, &_frame_block); - *gnnz = 0; - *snnz = 0; - ae_matrix_clear(w); - *info = 0; - *iterationscount = 0; - *nmv = 0; - _linlsqrstate_init(&state, _state, ae_true); - _linlsqrreport_init(&lsqrrep, _state, ae_true); - _sparsematrix_init(&spg, _state, ae_true); - _sparsematrix_init(&sps, _state, ae_true); - ae_vector_init(&nearcenterscnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&nearpointscnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&skipnearpointscnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&farpointscnt, 0, DT_INT, _state, ae_true); - ae_vector_init(&pointstags, 0, DT_INT, _state, ae_true); - ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true); - ae_matrix_init(&nearpoints, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&nearcenters, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&farpoints, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&g, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xx, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true); - - - /* - * Handle special cases: NC=0 - */ - if( nc==0 ) - { - *info = 1; - *iterationscount = 0; - *nmv = 0; - ae_frame_leave(_state); - return; - } - - /* - * Prepare for general case, NC>0 - */ - ae_vector_set_length(&xcx, rbf_mxnx, _state); - ae_vector_set_length(&pointstags, n, _state); - ae_vector_set_length(¢erstags, nc, _state); - *info = -1; - *iterationscount = 0; - *nmv = 0; - - /* - * This block prepares quantities used to compute approximate cardinal basis functions (ACBFs): - * * NearCentersCnt[] - array[NC], whose elements store number of near centers used to build ACBF - * * NearPointsCnt[] - array[NC], number of near points used to build ACBF - * * FarPointsCnt[] - array[NC], number of far points (ones where ACBF is nonzero) - * * MaxNearCentersCnt - max(NearCentersCnt) - * * MaxNearPointsCnt - max(NearPointsCnt) - * * SumNearCentersCnt - sum(NearCentersCnt) - * * SumNearPointsCnt - sum(NearPointsCnt) - * * SumFarPointsCnt - sum(FarPointsCnt) - */ - ae_vector_set_length(&nearcenterscnt, nc, _state); - ae_vector_set_length(&nearpointscnt, nc, _state); - ae_vector_set_length(&skipnearpointscnt, nc, _state); - ae_vector_set_length(&farpointscnt, nc, _state); - maxnearcenterscnt = 0; - maxnearpointscnt = 0; - maxfarpointscnt = 0; - sumnearcenterscnt = 0; - sumnearpointscnt = 0; - sumfarpointscnt = 0; - for(i=0; i<=nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; - } - - /* - * Determine number of near centers and maximum radius of near centers - */ - nearcenterscnt.ptr.p_int[i] = kdtreequeryrnn(centerstree, &xcx, r->ptr.p_double[i]*rbf_rbfnearradius, ae_true, _state); - kdtreequeryresultstags(centerstree, ¢erstags, _state); - maxrad = 0; - for(j=0; j<=nearcenterscnt.ptr.p_int[i]-1; j++) - { - maxrad = ae_maxreal(maxrad, ae_fabs(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); - } - - /* - * Determine number of near points (ones which used to build ACBF) - * and skipped points (the most near points which are NOT used to build ACBF - * and are NOT included in the near points count - */ - skipnearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, 0.1*r->ptr.p_double[i], ae_true, _state); - nearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, (r->ptr.p_double[i]+maxrad)*rbf_rbfnearradius, ae_true, _state)-skipnearpointscnt.ptr.p_int[i]; - ae_assert(nearpointscnt.ptr.p_int[i]>=0, "BuildRBFModelLSQR: internal error", _state); - - /* - * Determine number of far points - */ - farpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, ae_maxreal(r->ptr.p_double[i]*rbf_rbfnearradius+maxrad*rbf_rbffarradius, r->ptr.p_double[i]*rbf_rbffarradius, _state), ae_true, _state); - - /* - * calculate sum and max, make some basic checks - */ - ae_assert(nearcenterscnt.ptr.p_int[i]>0, "BuildRBFModelLSQR: internal error", _state); - maxnearcenterscnt = ae_maxint(maxnearcenterscnt, nearcenterscnt.ptr.p_int[i], _state); - maxnearpointscnt = ae_maxint(maxnearpointscnt, nearpointscnt.ptr.p_int[i], _state); - maxfarpointscnt = ae_maxint(maxfarpointscnt, farpointscnt.ptr.p_int[i], _state); - sumnearcenterscnt = sumnearcenterscnt+nearcenterscnt.ptr.p_int[i]; - sumnearpointscnt = sumnearpointscnt+nearpointscnt.ptr.p_int[i]; - sumfarpointscnt = sumfarpointscnt+farpointscnt.ptr.p_int[i]; - } - *snnz = sumnearcenterscnt; - *gnnz = sumfarpointscnt; - ae_assert(maxnearcenterscnt>0, "BuildRBFModelLSQR: internal error", _state); - - /* - * Allocate temporaries. - * - * NOTE: we want to avoid allocation of zero-size arrays, so we - * use max(desired_size,1) instead of desired_size when performing - * memory allocation. - */ - ae_matrix_set_length(&a, maxnearpointscnt+maxnearcenterscnt, maxnearcenterscnt, _state); - ae_vector_set_length(&tmpy, maxnearpointscnt+maxnearcenterscnt, _state); - ae_vector_set_length(&g, maxnearcenterscnt, _state); - ae_vector_set_length(&c, maxnearcenterscnt, _state); - ae_matrix_set_length(&nearcenters, maxnearcenterscnt, rbf_mxnx, _state); - ae_matrix_set_length(&nearpoints, ae_maxint(maxnearpointscnt, 1, _state), rbf_mxnx, _state); - ae_matrix_set_length(&farpoints, ae_maxint(maxfarpointscnt, 1, _state), rbf_mxnx, _state); - - /* - * fill matrix SpG - */ - sparsecreate(n, nc, *gnnz, &spg, _state); - sparsecreate(nc, nc, *snnz, &sps, _state); - for(i=0; i<=nc-1; i++) - { - centerscnt = nearcenterscnt.ptr.p_int[i]; - - /* - * main center - */ - for(j=0; j<=rbf_mxnx-1; j++) - { - xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; - } - - /* - * center's tree - */ - tmpi = kdtreequeryknn(centerstree, &xcx, centerscnt, ae_true, _state); - ae_assert(tmpi==centerscnt, "BuildRBFModelLSQR: internal error", _state); - kdtreequeryresultsx(centerstree, &cx, _state); - kdtreequeryresultstags(centerstree, ¢erstags, _state); - - /* - * point's tree - */ - mrad = 0; - for(j=0; j<=centerscnt-1; j++) - { - mrad = ae_maxreal(mrad, r->ptr.p_double[centerstags.ptr.p_int[j]], _state); - } - - /* - * we need to be sure that 'CTree' contains - * at least one side center - */ - sparseset(&sps, i, i, 1, _state); - c.ptr.p_double[0] = 1.0; - for(j=1; j<=centerscnt-1; j++) - { - c.ptr.p_double[j] = 0.0; - } - if( centerscnt>1&&nearpointscnt.ptr.p_int[i]>0 ) - { - - /* - * first KDTree request for points - */ - pointscnt = nearpointscnt.ptr.p_int[i]; - tmpi = kdtreequeryknn(pointstree, &xcx, skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], ae_true, _state); - ae_assert(tmpi==skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], "BuildRBFModelLSQR: internal error", _state); - kdtreequeryresultsx(pointstree, &xx, _state); - sind = skipnearpointscnt.ptr.p_int[i]; - for(j=0; j<=pointscnt-1; j++) - { - vx = xx.ptr.pp_double[sind+j][0]; - vy = xx.ptr.pp_double[sind+j][1]; - vz = xx.ptr.pp_double[sind+j][2]; - for(k=0; k<=centerscnt-1; k++) - { - vr = 0.0; - vv = vx-cx.ptr.pp_double[k][0]; - vr = vr+vv*vv; - vv = vy-cx.ptr.pp_double[k][1]; - vr = vr+vv*vv; - vv = vz-cx.ptr.pp_double[k][2]; - vr = vr+vv*vv; - vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; - a.ptr.pp_double[j][k] = ae_exp(-vr/(vv*vv), _state); - } - } - for(j=0; j<=centerscnt-1; j++) - { - g.ptr.p_double[j] = ae_exp(-(ae_sqr(xcx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xcx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xcx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); - } - - /* - * calculate the problem - */ - gnorm2 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); - for(j=0; j<=pointscnt-1; j++) - { - vv = ae_v_dotproduct(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); - vv = vv/gnorm2; - tmpy.ptr.p_double[j] = -vv; - ae_v_subd(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); - } - for(j=pointscnt; j<=pointscnt+centerscnt-1; j++) - { - for(k=0; k<=centerscnt-1; k++) - { - a.ptr.pp_double[j][k] = 0.0; - } - a.ptr.pp_double[j][j-pointscnt] = 1.0E-6; - tmpy.ptr.p_double[j] = 0.0; - } - fblssolvels(&a, &tmpy, pointscnt+centerscnt, centerscnt, &tmp0, &tmp1, &tmp2, _state); - ae_v_move(&c.ptr.p_double[0], 1, &tmpy.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); - vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); - vv = vv/gnorm2; - ae_v_subd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); - vv = 1/gnorm2; - ae_v_addd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); - for(j=0; j<=centerscnt-1; j++) - { - sparseset(&sps, i, centerstags.ptr.p_int[j], c.ptr.p_double[j], _state); - } - } - - /* - * second KDTree request for points - */ - pointscnt = farpointscnt.ptr.p_int[i]; - tmpi = kdtreequeryknn(pointstree, &xcx, pointscnt, ae_true, _state); - ae_assert(tmpi==pointscnt, "BuildRBFModelLSQR: internal error", _state); - kdtreequeryresultsx(pointstree, &xx, _state); - kdtreequeryresultstags(pointstree, &pointstags, _state); - - /* - *fill SpG matrix - */ - for(j=0; j<=pointscnt-1; j++) - { - fx = 0; - vx = xx.ptr.pp_double[j][0]; - vy = xx.ptr.pp_double[j][1]; - vz = xx.ptr.pp_double[j][2]; - for(k=0; k<=centerscnt-1; k++) - { - vr = 0.0; - vv = vx-cx.ptr.pp_double[k][0]; - vr = vr+vv*vv; - vv = vy-cx.ptr.pp_double[k][1]; - vr = vr+vv*vv; - vv = vz-cx.ptr.pp_double[k][2]; - vr = vr+vv*vv; - vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; - vv = vv*vv; - fx = fx+c.ptr.p_double[k]*ae_exp(-vr/vv, _state); - } - sparseset(&spg, pointstags.ptr.p_int[j], i, fx, _state); - } - } - sparseconverttocrs(&spg, _state); - sparseconverttocrs(&sps, _state); - - /* - * solve by LSQR method - */ - ae_vector_set_length(&tmpy, n, _state); - ae_vector_set_length(&tc, nc, _state); - ae_matrix_set_length(w, nc, ny, _state); - linlsqrcreate(n, nc, &state, _state); - linlsqrsetcond(&state, epsort, epserr, maxits, _state); - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=n-1; j++) - { - tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; - } - linlsqrsolvesparse(&state, &spg, &tmpy, _state); - linlsqrresults(&state, &c, &lsqrrep, _state); - if( lsqrrep.terminationtype<=0 ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - sparsemtv(&sps, &c, &tc, _state); - for(j=0; j<=nc-1; j++) - { - w->ptr.pp_double[j][i] = tc.ptr.p_double[j]; - } - *iterationscount = *iterationscount+lsqrrep.iterationscount; - *nmv = *nmv+lsqrrep.nmv; - } - *info = 1; - ae_frame_leave(_state); -} - - -static void rbf_buildrbfmlayersmodellsqr(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - /* Real */ ae_matrix* xc, - double rval, - /* Real */ ae_vector* r, - ae_int_t n, - ae_int_t* nc, - ae_int_t ny, - ae_int_t nlayers, - kdtree* centerstree, - double epsort, - double epserr, - ae_int_t maxits, - double lambdav, - ae_int_t* annz, - /* Real */ ae_matrix* w, - ae_int_t* info, - ae_int_t* iterationscount, - ae_int_t* nmv, - ae_state *_state) -{ - ae_frame _frame_block; - linlsqrstate state; - linlsqrreport lsqrrep; - sparsematrix spa; - double anorm; - ae_vector omega; - ae_vector xx; - ae_vector tmpy; - ae_matrix cx; - double yval; - ae_int_t nec; - ae_vector centerstags; - ae_int_t layer; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - double rmaxbefore; - double rmaxafter; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(xc); - ae_vector_clear(r); - *nc = 0; - *annz = 0; - ae_matrix_clear(w); - *info = 0; - *iterationscount = 0; - *nmv = 0; - _linlsqrstate_init(&state, _state, ae_true); - _linlsqrreport_init(&lsqrrep, _state, ae_true); - _sparsematrix_init(&spa, _state, ae_true); - ae_vector_init(&omega, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true); - - ae_assert(nlayers>=0, "BuildRBFMLayersModelLSQR: invalid argument(NLayers<0)", _state); - ae_assert(n>=0, "BuildRBFMLayersModelLSQR: invalid argument(N<0)", _state); - ae_assert(rbf_mxnx>0&&rbf_mxnx<=3, "BuildRBFMLayersModelLSQR: internal error(invalid global const MxNX: either MxNX<=0 or MxNX>3)", _state); - *annz = 0; - if( n==0||nlayers==0 ) - { - *info = 1; - *iterationscount = 0; - *nmv = 0; - ae_frame_leave(_state); - return; - } - *nc = n*nlayers; - ae_vector_set_length(&xx, rbf_mxnx, _state); - ae_vector_set_length(¢erstags, n, _state); - ae_matrix_set_length(xc, *nc, rbf_mxnx, _state); - ae_vector_set_length(r, *nc, _state); - for(i=0; i<=*nc-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xc->ptr.pp_double[i][j] = x->ptr.pp_double[i%n][j]; - } - } - for(i=0; i<=*nc-1; i++) - { - r->ptr.p_double[i] = rval/ae_pow(2, i/n, _state); - } - for(i=0; i<=n-1; i++) - { - centerstags.ptr.p_int[i] = i; - } - kdtreebuildtagged(xc, ¢erstags, n, rbf_mxnx, 0, 2, centerstree, _state); - ae_vector_set_length(&omega, n, _state); - ae_vector_set_length(&tmpy, n, _state); - ae_matrix_set_length(w, *nc, ny, _state); - *info = -1; - *iterationscount = 0; - *nmv = 0; - linlsqrcreate(n, n, &state, _state); - linlsqrsetcond(&state, epsort, epserr, maxits, _state); - linlsqrsetlambdai(&state, 1.0E-6, _state); - - /* - * calculate number of non-zero elements for sparse matrix - */ - for(i=0; i<=n-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; - } - *annz = *annz+kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[0]*rbf_rbfmlradius, ae_true, _state); - } - for(layer=0; layer<=nlayers-1; layer++) - { - - /* - * Fill sparse matrix, calculate norm(A) - */ - anorm = 0.0; - sparsecreate(n, n, *annz, &spa, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=rbf_mxnx-1; j++) - { - xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; - } - nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbf_rbfmlradius, ae_true, _state); - kdtreequeryresultsx(centerstree, &cx, _state); - kdtreequeryresultstags(centerstree, ¢erstags, _state); - for(j=0; j<=nec-1; j++) - { - v = ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[j]], _state), _state); - sparseset(&spa, i, centerstags.ptr.p_int[j], v, _state); - anorm = anorm+ae_sqr(v, _state); - } - } - anorm = ae_sqrt(anorm, _state); - sparseconverttocrs(&spa, _state); - - /* - * Calculate maximum residual before adding new layer. - * This value is not used by algorithm, the only purpose is to make debugging easier. - */ - rmaxbefore = 0.0; - for(j=0; j<=n-1; j++) - { - for(i=0; i<=ny-1; i++) - { - rmaxbefore = ae_maxreal(rmaxbefore, ae_fabs(y->ptr.pp_double[j][i], _state), _state); - } - } - - /* - * Process NY dimensions of the target function - */ - for(i=0; i<=ny-1; i++) - { - for(j=0; j<=n-1; j++) - { - tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; - } - - /* - * calculate Omega for current layer - */ - linlsqrsetlambdai(&state, lambdav*anorm/n, _state); - linlsqrsolvesparse(&state, &spa, &tmpy, _state); - linlsqrresults(&state, &omega, &lsqrrep, _state); - if( lsqrrep.terminationtype<=0 ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - - /* - * calculate error for current layer - */ - for(j=0; j<=n-1; j++) - { - yval = 0; - for(k=0; k<=rbf_mxnx-1; k++) - { - xx.ptr.p_double[k] = x->ptr.pp_double[j][k]; - } - nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbf_rbffarradius, ae_true, _state); - kdtreequeryresultsx(centerstree, &cx, _state); - kdtreequeryresultstags(centerstree, ¢erstags, _state); - for(k=0; k<=nec-1; k++) - { - yval = yval+omega.ptr.p_double[centerstags.ptr.p_int[k]]*ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[k][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[k][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[k][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[k]], _state), _state); - } - y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-yval; - } - - /* - * write Omega in out parameter W - */ - for(j=0; j<=n-1; j++) - { - w->ptr.pp_double[layer*n+j][i] = omega.ptr.p_double[j]; - } - *iterationscount = *iterationscount+lsqrrep.iterationscount; - *nmv = *nmv+lsqrrep.nmv; - } - - /* - * Calculate maximum residual before adding new layer. - * This value is not used by algorithm, the only purpose is to make debugging easier. - */ - rmaxafter = 0.0; - for(j=0; j<=n-1; j++) - { - for(i=0; i<=ny-1; i++) - { - rmaxafter = ae_maxreal(rmaxafter, ae_fabs(y->ptr.pp_double[j][i], _state), _state); - } - } - } - *info = 1; - ae_frame_leave(_state); -} - - -ae_bool _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - rbfmodel *p = (rbfmodel*)_p; - ae_touch_ptr((void*)p); - if( !_kdtree_init(&p->tree, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->xc, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->wr, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - rbfmodel *dst = (rbfmodel*)_dst; - rbfmodel *src = (rbfmodel*)_src; - dst->ny = src->ny; - dst->nx = src->nx; - dst->nc = src->nc; - dst->nl = src->nl; - if( !_kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->xc, &src->xc, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->wr, &src->wr, _state, make_automatic) ) - return ae_false; - dst->rmax = src->rmax; - if( !ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic) ) - return ae_false; - dst->gridtype = src->gridtype; - dst->fixrad = src->fixrad; - dst->lambdav = src->lambdav; - dst->radvalue = src->radvalue; - dst->radzvalue = src->radzvalue; - dst->nlayers = src->nlayers; - dst->aterm = src->aterm; - dst->algorithmtype = src->algorithmtype; - dst->epsort = src->epsort; - dst->epserr = src->epserr; - dst->maxits = src->maxits; - dst->h = src->h; - dst->n = src->n; - if( !ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _rbfmodel_clear(void* _p) -{ - rbfmodel *p = (rbfmodel*)_p; - ae_touch_ptr((void*)p); - _kdtree_clear(&p->tree); - ae_matrix_clear(&p->xc); - ae_matrix_clear(&p->wr); - ae_matrix_clear(&p->v); - ae_matrix_clear(&p->x); - ae_matrix_clear(&p->y); - ae_vector_clear(&p->calcbufxcx); - ae_matrix_clear(&p->calcbufx); - ae_vector_clear(&p->calcbuftags); -} - - -void _rbfmodel_destroy(void* _p) -{ - rbfmodel *p = (rbfmodel*)_p; - ae_touch_ptr((void*)p); - _kdtree_destroy(&p->tree); - ae_matrix_destroy(&p->xc); - ae_matrix_destroy(&p->wr); - ae_matrix_destroy(&p->v); - ae_matrix_destroy(&p->x); - ae_matrix_destroy(&p->y); - ae_vector_destroy(&p->calcbufxcx); - ae_matrix_destroy(&p->calcbufx); - ae_vector_destroy(&p->calcbuftags); -} - - -ae_bool _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - rbfreport *p = (rbfreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - rbfreport *dst = (rbfreport*)_dst; - rbfreport *src = (rbfreport*)_src; - dst->arows = src->arows; - dst->acols = src->acols; - dst->annz = src->annz; - dst->iterationscount = src->iterationscount; - dst->nmv = src->nmv; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _rbfreport_clear(void* _p) -{ - rbfreport *p = (rbfreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _rbfreport_destroy(void* _p) -{ - rbfreport *p = (rbfreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X. - -Input parameters: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y- point - -Result: - S(x,y) - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -double spline2dcalc(spline2dinterpolant* c, - double x, - double y, - ae_state *_state) -{ - double v; - double vx; - double vy; - double vxy; - double result; - - - ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalc: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalc: X or Y contains NaN or Infinite value", _state); - if( c->d!=1 ) - { - result = 0; - return result; - } - spline2ddiff(c, x, y, &v, &vx, &vy, &vxy, _state); - result = v; - return result; -} - - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X and its derivatives. - -Input parameters: - C - spline interpolant. - X, Y- point - -Output parameters: - F - S(x,y) - FX - dS(x,y)/dX - FY - dS(x,y)/dY - FXY - d2S(x,y)/dXdY - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2ddiff(spline2dinterpolant* c, - double x, - double y, - double* f, - double* fx, - double* fy, - double* fxy, - ae_state *_state) -{ - double t; - double dt; - double u; - double du; - ae_int_t ix; - ae_int_t iy; - ae_int_t l; - ae_int_t r; - ae_int_t h; - ae_int_t s1; - ae_int_t s2; - ae_int_t s3; - ae_int_t s4; - ae_int_t sfx; - ae_int_t sfy; - ae_int_t sfxy; - double y1; - double y2; - double y3; - double y4; - double v; - double t0; - double t1; - double t2; - double t3; - double u0; - double u1; - double u2; - double u3; - - *f = 0; - *fx = 0; - *fy = 0; - *fxy = 0; - - ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state); - - /* - * Prepare F, dF/dX, dF/dY, d2F/dXdY - */ - *f = 0; - *fx = 0; - *fy = 0; - *fxy = 0; - if( c->d!=1 ) - { - return; - } - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = c->n-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) - { - r = h; - } - else - { - l = h; - } - } - t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); - dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); - ix = l; - - /* - * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) - */ - l = 0; - r = c->m-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) - { - r = h; - } - else - { - l = h; - } - } - u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); - du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); - iy = l; - - /* - * Bilinear interpolation - */ - if( c->stype==-1 ) - { - y1 = c->f.ptr.p_double[c->n*iy+ix]; - y2 = c->f.ptr.p_double[c->n*iy+(ix+1)]; - y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)]; - y4 = c->f.ptr.p_double[c->n*(iy+1)+ix]; - *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4; - *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt; - *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du; - *fxy = (y1-y2+y3-y4)*du*dt; - return; - } - - /* - * Bicubic interpolation - */ - if( c->stype==-3 ) - { - - /* - * Prepare info - */ - t0 = 1; - t1 = t; - t2 = ae_sqr(t, _state); - t3 = t*t2; - u0 = 1; - u1 = u; - u2 = ae_sqr(u, _state); - u3 = u*u2; - sfx = c->n*c->m; - sfy = 2*c->n*c->m; - sfxy = 3*c->n*c->m; - s1 = c->n*iy+ix; - s2 = c->n*iy+(ix+1); - s3 = c->n*(iy+1)+(ix+1); - s4 = c->n*(iy+1)+ix; - - /* - * Calculate - */ - v = c->f.ptr.p_double[s1]; - *f = *f+v*t0*u0; - v = c->f.ptr.p_double[sfy+s1]/du; - *f = *f+v*t0*u1; - *fy = *fy+v*t0*u0*du; - v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; - *f = *f+v*t0*u2; - *fy = *fy+2*v*t0*u1*du; - v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; - *f = *f+v*t0*u3; - *fy = *fy+3*v*t0*u2*du; - v = c->f.ptr.p_double[sfx+s1]/dt; - *f = *f+v*t1*u0; - *fx = *fx+v*t0*u0*dt; - v = c->f.ptr.p_double[sfxy+s1]/(dt*du); - *f = *f+v*t1*u1; - *fx = *fx+v*t0*u1*dt; - *fy = *fy+v*t1*u0*du; - *fxy = *fxy+v*t0*u0*dt*du; - v = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t1*u2; - *fx = *fx+v*t0*u2*dt; - *fy = *fy+2*v*t1*u1*du; - *fxy = *fxy+2*v*t0*u1*dt*du; - v = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t1*u3; - *fx = *fx+v*t0*u3*dt; - *fy = *fy+3*v*t1*u2*du; - *fxy = *fxy+3*v*t0*u2*dt*du; - v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; - *f = *f+v*t2*u0; - *fx = *fx+2*v*t1*u0*dt; - v = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); - *f = *f+v*t2*u1; - *fx = *fx+2*v*t1*u1*dt; - *fy = *fy+v*t2*u0*du; - *fxy = *fxy+2*v*t1*u0*dt*du; - v = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t2*u2; - *fx = *fx+2*v*t1*u2*dt; - *fy = *fy+2*v*t2*u1*du; - *fxy = *fxy+4*v*t1*u1*dt*du; - v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t2*u3; - *fx = *fx+2*v*t1*u3*dt; - *fy = *fy+3*v*t2*u2*du; - *fxy = *fxy+6*v*t1*u2*dt*du; - v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; - *f = *f+v*t3*u0; - *fx = *fx+3*v*t2*u0*dt; - v = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); - *f = *f+v*t3*u1; - *fx = *fx+3*v*t2*u1*dt; - *fy = *fy+v*t3*u0*du; - *fxy = *fxy+3*v*t2*u0*dt*du; - v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t3*u2; - *fx = *fx+3*v*t2*u2*dt; - *fy = *fy+2*v*t3*u1*du; - *fxy = *fxy+6*v*t2*u1*dt*du; - v = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - *f = *f+v*t3*u3; - *fx = *fx+3*v*t2*u3*dt; - *fy = *fy+3*v*t3*u2*du; - *fxy = *fxy+9*v*t2*u2*dt*du; - return; - } -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -Input parameters: - C - spline interpolant - AX, BX - transformation coefficients: x = A*t + B - AY, BY - transformation coefficients: y = A*u + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransxy(spline2dinterpolant* c, - double ax, - double bx, - double ay, - double by, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_vector f; - ae_vector v; - ae_int_t i; - ae_int_t j; - ae_int_t k; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&f, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - - ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransXY: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(ax, _state), "Spline2DLinTransXY: AX is infinite or NaN", _state); - ae_assert(ae_isfinite(bx, _state), "Spline2DLinTransXY: BX is infinite or NaN", _state); - ae_assert(ae_isfinite(ay, _state), "Spline2DLinTransXY: AY is infinite or NaN", _state); - ae_assert(ae_isfinite(by, _state), "Spline2DLinTransXY: BY is infinite or NaN", _state); - ae_vector_set_length(&x, c->n, _state); - ae_vector_set_length(&y, c->m, _state); - ae_vector_set_length(&f, c->m*c->n*c->d, _state); - for(j=0; j<=c->n-1; j++) - { - x.ptr.p_double[j] = c->x.ptr.p_double[j]; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = c->y.ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - for(k=0; k<=c->d-1; k++) - { - f.ptr.p_double[c->d*(i*c->n+j)+k] = c->f.ptr.p_double[c->d*(i*c->n+j)+k]; - } - } - } - - /* - * Handle different combinations of AX/AY - */ - if( ae_fp_eq(ax,0)&&ae_fp_neq(ay,0) ) - { - for(i=0; i<=c->m-1; i++) - { - spline2dcalcvbuf(c, bx, y.ptr.p_double[i], &v, _state); - y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; - for(j=0; j<=c->n-1; j++) - { - for(k=0; k<=c->d-1; k++) - { - f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; - } - } - } - } - if( ae_fp_neq(ax,0)&&ae_fp_eq(ay,0) ) - { - for(j=0; j<=c->n-1; j++) - { - spline2dcalcvbuf(c, x.ptr.p_double[j], by, &v, _state); - x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; - for(i=0; i<=c->m-1; i++) - { - for(k=0; k<=c->d-1; k++) - { - f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; - } - } - } - } - if( ae_fp_neq(ax,0)&&ae_fp_neq(ay,0) ) - { - for(j=0; j<=c->n-1; j++) - { - x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; - } - } - if( ae_fp_eq(ax,0)&&ae_fp_eq(ay,0) ) - { - spline2dcalcvbuf(c, bx, by, &v, _state); - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - for(k=0; k<=c->d-1; k++) - { - f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; - } - } - } - } - - /* - * Rebuild spline - */ - if( c->stype==-3 ) - { - spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state); - } - if( c->stype==-1 ) - { - spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -Input parameters: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B - -Output parameters: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransf(spline2dinterpolant* c, - double a, - double b, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_vector f; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&f, 0, DT_REAL, _state, ae_true); - - ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransF: incorrect C (incorrect parameter C.SType)", _state); - ae_vector_set_length(&x, c->n, _state); - ae_vector_set_length(&y, c->m, _state); - ae_vector_set_length(&f, c->m*c->n*c->d, _state); - for(j=0; j<=c->n-1; j++) - { - x.ptr.p_double[j] = c->x.ptr.p_double[j]; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = c->y.ptr.p_double[i]; - } - for(i=0; i<=c->m*c->n*c->d-1; i++) - { - f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; - } - if( c->stype==-3 ) - { - spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state); - } - if( c->stype==-1 ) - { - spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine makes the copy of the spline model. - -Input parameters: - C - spline interpolant - -Output parameters: - CC - spline copy - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dcopy(spline2dinterpolant* c, - spline2dinterpolant* cc, - ae_state *_state) -{ - ae_int_t tblsize; - - _spline2dinterpolant_clear(cc); - - ae_assert(c->k==1||c->k==3, "Spline2DCopy: incorrect C (incorrect parameter C.K)", _state); - cc->k = c->k; - cc->n = c->n; - cc->m = c->m; - cc->d = c->d; - cc->stype = c->stype; - tblsize = -1; - if( c->stype==-3 ) - { - tblsize = 4*c->n*c->m*c->d; - } - if( c->stype==-1 ) - { - tblsize = c->n*c->m*c->d; - } - ae_assert(tblsize>0, "Spline2DCopy: internal error", _state); - ae_vector_set_length(&cc->x, cc->n, _state); - ae_vector_set_length(&cc->y, cc->m, _state); - ae_vector_set_length(&cc->f, tblsize, _state); - ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); - ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); - ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); -} - - -/************************************************************************* -Bicubic spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 15 May, 2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebicubic(/* Real */ ae_matrix* a, - ae_int_t oldheight, - ae_int_t oldwidth, - /* Real */ ae_matrix* b, - ae_int_t newheight, - ae_int_t newwidth, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix buf; - ae_vector x; - ae_vector y; - spline1dinterpolant c; - ae_int_t mw; - ae_int_t mh; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(b); - ae_matrix_init(&buf, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - _spline1dinterpolant_init(&c, _state, ae_true); - - ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); - ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); - - /* - * Prepare - */ - mw = ae_maxint(oldwidth, newwidth, _state); - mh = ae_maxint(oldheight, newheight, _state); - ae_matrix_set_length(b, newheight, newwidth, _state); - ae_matrix_set_length(&buf, oldheight, newwidth, _state); - ae_vector_set_length(&x, ae_maxint(mw, mh, _state), _state); - ae_vector_set_length(&y, ae_maxint(mw, mh, _state), _state); - - /* - * Horizontal interpolation - */ - for(i=0; i<=oldheight-1; i++) - { - - /* - * Fill X, Y - */ - for(j=0; j<=oldwidth-1; j++) - { - x.ptr.p_double[j] = (double)j/(double)(oldwidth-1); - y.ptr.p_double[j] = a->ptr.pp_double[i][j]; - } - - /* - * Interpolate and place result into temporary matrix - */ - spline1dbuildcubic(&x, &y, oldwidth, 0, 0.0, 0, 0.0, &c, _state); - for(j=0; j<=newwidth-1; j++) - { - buf.ptr.pp_double[i][j] = spline1dcalc(&c, (double)j/(double)(newwidth-1), _state); - } - } - - /* - * Vertical interpolation - */ - for(j=0; j<=newwidth-1; j++) - { - - /* - * Fill X, Y - */ - for(i=0; i<=oldheight-1; i++) - { - x.ptr.p_double[i] = (double)i/(double)(oldheight-1); - y.ptr.p_double[i] = buf.ptr.pp_double[i][j]; - } - - /* - * Interpolate and place result into B - */ - spline1dbuildcubic(&x, &y, oldheight, 0, 0.0, 0, 0.0, &c, _state); - for(i=0; i<=newheight-1; i++) - { - b->ptr.pp_double[i][j] = spline1dcalc(&c, (double)i/(double)(newheight-1), _state); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Bilinear spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 09.07.2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebilinear(/* Real */ ae_matrix* a, - ae_int_t oldheight, - ae_int_t oldwidth, - /* Real */ ae_matrix* b, - ae_int_t newheight, - ae_int_t newwidth, - ae_state *_state) -{ - ae_int_t l; - ae_int_t c; - double t; - double u; - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(b); - - ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); - ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); - ae_matrix_set_length(b, newheight, newwidth, _state); - for(i=0; i<=newheight-1; i++) - { - for(j=0; j<=newwidth-1; j++) - { - l = i*(oldheight-1)/(newheight-1); - if( l==oldheight-1 ) - { - l = oldheight-2; - } - u = (double)i/(double)(newheight-1)*(oldheight-1)-l; - c = j*(oldwidth-1)/(newwidth-1); - if( c==oldwidth-1 ) - { - c = oldwidth-2; - } - t = (double)(j*(oldwidth-1))/(double)(newwidth-1)-c; - b->ptr.pp_double[i][j] = (1-t)*(1-u)*a->ptr.pp_double[l][c]+t*(1-u)*a->ptr.pp_double[l][c+1]+t*u*a->ptr.pp_double[l+1][c+1]+(1-t)*u*a->ptr.pp_double[l+1][c]; - } - } -} - - -/************************************************************************* -This subroutine builds bilinear vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinearv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* f, - ae_int_t d, - spline2dinterpolant* c, - ae_state *_state) -{ - double t; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t i0; - - _spline2dinterpolant_clear(c); - - ae_assert(n>=2, "Spline2DBuildBilinearV: N is less then 2", _state); - ae_assert(m>=2, "Spline2DBuildBilinearV: M is less then 2", _state); - ae_assert(d>=1, "Spline2DBuildBilinearV: invalid argument D (D<1)", _state); - ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearV: length of X or Y is too short (Length(X/Y)cnt>=k, "Spline2DBuildBilinearV: length of F is too short (Length(F)k = 1; - c->n = n; - c->m = m; - c->d = d; - c->stype = -1; - ae_vector_set_length(&c->x, c->n, _state); - ae_vector_set_length(&c->y, c->m, _state); - ae_vector_set_length(&c->f, k, _state); - for(i=0; i<=c->n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - c->y.ptr.p_double[i] = y->ptr.p_double[i]; - } - for(i=0; i<=k-1; i++) - { - c->f.ptr.p_double[i] = f->ptr.p_double[i]; - } - - /* - * Sort points - */ - for(j=0; j<=c->n-1; j++) - { - k = j; - for(i=j+1; i<=c->n-1; i++) - { - if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) - { - k = i; - } - } - if( k!=j ) - { - for(i=0; i<=c->m-1; i++) - { - for(i0=0; i0<=c->d-1; i0++) - { - t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; - c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0]; - c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t; - } - } - t = c->x.ptr.p_double[j]; - c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; - c->x.ptr.p_double[k] = t; - } - } - for(i=0; i<=c->m-1; i++) - { - k = i; - for(j=i+1; j<=c->m-1; j++) - { - if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) - { - k = j; - } - } - if( k!=i ) - { - for(j=0; j<=c->n-1; j++) - { - for(i0=0; i0<=c->d-1; i0++) - { - t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; - c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0]; - c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t; - } - } - t = c->y.ptr.p_double[i]; - c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; - c->y.ptr.p_double[k] = t; - } - } -} - - -/************************************************************************* -This subroutine builds bicubic vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubicv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* f, - ae_int_t d, - spline2dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _f; - ae_matrix tf; - ae_matrix dx; - ae_matrix dy; - ae_matrix dxy; - double t; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t di; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_f, f, _state, ae_true); - f = &_f; - _spline2dinterpolant_clear(c); - ae_matrix_init(&tf, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=2, "Spline2DBuildBicubicV: N is less than 2", _state); - ae_assert(m>=2, "Spline2DBuildBicubicV: M is less than 2", _state); - ae_assert(d>=1, "Spline2DBuildBicubicV: invalid argument D (D<1)", _state); - ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicV: length of X or Y is too short (Length(X/Y)cnt>=k, "Spline2DBuildBicubicV: length of F is too short (Length(F)k = 3; - c->d = d; - c->n = n; - c->m = m; - c->stype = -3; - k = 4*k; - ae_vector_set_length(&c->x, c->n, _state); - ae_vector_set_length(&c->y, c->m, _state); - ae_vector_set_length(&c->f, k, _state); - ae_matrix_set_length(&tf, c->m, c->n, _state); - for(i=0; i<=c->n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - c->y.ptr.p_double[i] = y->ptr.p_double[i]; - } - - /* - * Sort points - */ - for(j=0; j<=c->n-1; j++) - { - k = j; - for(i=j+1; i<=c->n-1; i++) - { - if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) - { - k = i; - } - } - if( k!=j ) - { - for(i=0; i<=c->m-1; i++) - { - for(di=0; di<=c->d-1; di++) - { - t = f->ptr.p_double[c->d*(i*c->n+j)+di]; - f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(i*c->n+k)+di]; - f->ptr.p_double[c->d*(i*c->n+k)+di] = t; - } - } - t = c->x.ptr.p_double[j]; - c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; - c->x.ptr.p_double[k] = t; - } - } - for(i=0; i<=c->m-1; i++) - { - k = i; - for(j=i+1; j<=c->m-1; j++) - { - if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) - { - k = j; - } - } - if( k!=i ) - { - for(j=0; j<=c->n-1; j++) - { - for(di=0; di<=c->d-1; di++) - { - t = f->ptr.p_double[c->d*(i*c->n+j)+di]; - f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(k*c->n+j)+di]; - f->ptr.p_double[c->d*(k*c->n+j)+di] = t; - } - } - t = c->y.ptr.p_double[i]; - c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; - c->y.ptr.p_double[k] = t; - } - } - for(di=0; di<=c->d-1; di++) - { - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - tf.ptr.pp_double[i][j] = f->ptr.p_double[c->d*(i*c->n+j)+di]; - } - } - spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state); - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - k = c->d*(i*c->n+j)+di; - c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j]; - c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j]; - c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j]; - c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j]; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcvbuf(spline2dinterpolant* c, - double x, - double y, - /* Real */ ae_vector* f, - ae_state *_state) -{ - double t; - double dt; - double u; - double du; - ae_int_t ix; - ae_int_t iy; - ae_int_t l; - ae_int_t r; - ae_int_t h; - ae_int_t s1; - ae_int_t s2; - ae_int_t s3; - ae_int_t s4; - ae_int_t sfx; - ae_int_t sfy; - ae_int_t sfxy; - double y1; - double y2; - double y3; - double y4; - double v; - double t0; - double t1; - double t2; - double t3; - double u0; - double u1; - double u2; - double u3; - ae_int_t i; - - - ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVBuf: either X=NaN/Infinite or Y=NaN/Infinite", _state); - rvectorsetlengthatleast(f, c->d, _state); - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = c->n-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) - { - r = h; - } - else - { - l = h; - } - } - t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); - dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); - ix = l; - - /* - * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) - */ - l = 0; - r = c->m-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) - { - r = h; - } - else - { - l = h; - } - } - u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); - du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); - iy = l; - - /* - * Bilinear interpolation - */ - if( c->stype==-1 ) - { - for(i=0; i<=c->d-1; i++) - { - y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i]; - y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i]; - y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i]; - y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i]; - f->ptr.p_double[i] = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4; - } - return; - } - - /* - * Bicubic interpolation - */ - if( c->stype==-3 ) - { - - /* - * Prepare info - */ - t0 = 1; - t1 = t; - t2 = ae_sqr(t, _state); - t3 = t*t2; - u0 = 1; - u1 = u; - u2 = ae_sqr(u, _state); - u3 = u*u2; - sfx = c->n*c->m*c->d; - sfy = 2*c->n*c->m*c->d; - sfxy = 3*c->n*c->m*c->d; - for(i=0; i<=c->d-1; i++) - { - - /* - * Prepare F, dF/dX, dF/dY, d2F/dXdY - */ - f->ptr.p_double[i] = 0; - s1 = c->d*(c->n*iy+ix)+i; - s2 = c->d*(c->n*iy+(ix+1))+i; - s3 = c->d*(c->n*(iy+1)+(ix+1))+i; - s4 = c->d*(c->n*(iy+1)+ix)+i; - - /* - * Calculate - */ - v = c->f.ptr.p_double[s1]; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u0; - v = c->f.ptr.p_double[sfy+s1]/du; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u1; - v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u2; - v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t0*u3; - v = c->f.ptr.p_double[sfx+s1]/dt; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u0; - v = c->f.ptr.p_double[sfxy+s1]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u1; - v = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u2; - v = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t1*u3; - v = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u0; - v = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u1; - v = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u2; - v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t2*u3; - v = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u0; - v = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u1; - v = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u2; - v = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - f->ptr.p_double[i] = f->ptr.p_double[i]+v*t3*u3; - } - return; - } -} - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcv(spline2dinterpolant* c, - double x, - double y, - /* Real */ ae_vector* f, - ae_state *_state) -{ - - ae_vector_clear(f); - - ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcV: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcV: either X=NaN/Infinite or Y=NaN/Infinite", _state); - ae_vector_set_length(f, c->d, _state); - spline2dcalcvbuf(c, x, y, f, _state); -} - - -/************************************************************************* -This subroutine unpacks two-dimensional spline into the coefficients table - -Input parameters: - C - spline interpolant. - -Result: - M, N- grid size (x-axis and y-axis) - D - number of components - Tbl - coefficients table, unpacked format, - D - components: [0..(N-1)*(M-1)*D-1, 0..19]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index): - K := T + I*D + J*D*(N-1) - - K-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[K,0] = X[i] - Tbl[K,1] = X[i+1] - Tbl[K,2] = Y[j] - Tbl[K,3] = Y[j+1] - Tbl[K,4] = C00 - Tbl[K,5] = C01 - Tbl[K,6] = C02 - Tbl[K,7] = C03 - Tbl[K,8] = C10 - Tbl[K,9] = C11 - ... - Tbl[K,19] = C33 - On each grid square spline is equals to: - S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) - t = x-x[j] - u = y-y[i] - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpackv(spline2dinterpolant* c, - ae_int_t* m, - ae_int_t* n, - ae_int_t* d, - /* Real */ ae_matrix* tbl, - ae_state *_state) -{ - ae_int_t k; - ae_int_t p; - ae_int_t ci; - ae_int_t cj; - ae_int_t s1; - ae_int_t s2; - ae_int_t s3; - ae_int_t s4; - ae_int_t sfx; - ae_int_t sfy; - ae_int_t sfxy; - double y1; - double y2; - double y3; - double y4; - double dt; - double du; - ae_int_t i; - ae_int_t j; - ae_int_t k0; - - *m = 0; - *n = 0; - *d = 0; - ae_matrix_clear(tbl); - - ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpackV: incorrect C (incorrect parameter C.SType)", _state); - *n = c->n; - *m = c->m; - *d = c->d; - ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*d), 20, _state); - sfx = *n*(*m)*(*d); - sfy = 2*(*n)*(*m)*(*d); - sfxy = 3*(*n)*(*m)*(*d); - for(i=0; i<=*m-2; i++) - { - for(j=0; j<=*n-2; j++) - { - for(k=0; k<=*d-1; k++) - { - p = *d*(i*(*n-1)+j)+k; - tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; - tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; - tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; - tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; - dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); - du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); - - /* - * Bilinear interpolation - */ - if( c->stype==-1 ) - { - for(k0=4; k0<=19; k0++) - { - tbl->ptr.pp_double[p][k0] = 0; - } - y1 = c->f.ptr.p_double[*d*(*n*i+j)+k]; - y2 = c->f.ptr.p_double[*d*(*n*i+(j+1))+k]; - y3 = c->f.ptr.p_double[*d*(*n*(i+1)+(j+1))+k]; - y4 = c->f.ptr.p_double[*d*(*n*(i+1)+j)+k]; - tbl->ptr.pp_double[p][4] = y1; - tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; - tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; - tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; - } - - /* - * Bicubic interpolation - */ - if( c->stype==-3 ) - { - s1 = *d*(*n*i+j)+k; - s2 = *d*(*n*i+(j+1))+k; - s3 = *d*(*n*(i+1)+(j+1))+k; - s4 = *d*(*n*(i+1)+j)+k; - tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; - tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; - tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; - tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; - tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; - tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); - tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; - tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; - tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - } - - /* - * Rescale Cij - */ - for(ci=0; ci<=3; ci++) - { - for(cj=0; cj<=3; cj++) - { - tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, ci, _state)*ae_pow(du, cj, _state); - } - } - } - } - } -} - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBilinearV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinear(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_matrix* f, - ae_int_t m, - ae_int_t n, - spline2dinterpolant* c, - ae_state *_state) -{ - double t; - ae_int_t i; - ae_int_t j; - ae_int_t k; - - _spline2dinterpolant_clear(c); - - ae_assert(n>=2, "Spline2DBuildBilinear: N<2", _state); - ae_assert(m>=2, "Spline2DBuildBilinear: M<2", _state); - ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinear: length of X or Y is too short (Length(X/Y)rows>=m&&f->cols>=n, "Spline2DBuildBilinear: size of F is too small (rows(F)k = 1; - c->n = n; - c->m = m; - c->d = 1; - c->stype = -1; - ae_vector_set_length(&c->x, c->n, _state); - ae_vector_set_length(&c->y, c->m, _state); - ae_vector_set_length(&c->f, c->n*c->m, _state); - for(i=0; i<=c->n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - c->y.ptr.p_double[i] = y->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - c->f.ptr.p_double[i*c->n+j] = f->ptr.pp_double[i][j]; - } - } - - /* - * Sort points - */ - for(j=0; j<=c->n-1; j++) - { - k = j; - for(i=j+1; i<=c->n-1; i++) - { - if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) - { - k = i; - } - } - if( k!=j ) - { - for(i=0; i<=c->m-1; i++) - { - t = c->f.ptr.p_double[i*c->n+j]; - c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[i*c->n+k]; - c->f.ptr.p_double[i*c->n+k] = t; - } - t = c->x.ptr.p_double[j]; - c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; - c->x.ptr.p_double[k] = t; - } - } - for(i=0; i<=c->m-1; i++) - { - k = i; - for(j=i+1; j<=c->m-1; j++) - { - if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) - { - k = j; - } - } - if( k!=i ) - { - for(j=0; j<=c->n-1; j++) - { - t = c->f.ptr.p_double[i*c->n+j]; - c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[k*c->n+j]; - c->f.ptr.p_double[k*c->n+j] = t; - } - t = c->y.ptr.p_double[i]; - c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; - c->y.ptr.p_double[k] = t; - } - } -} - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBicubicV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_matrix* f, - ae_int_t m, - ae_int_t n, - spline2dinterpolant* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _f; - ae_int_t sfx; - ae_int_t sfy; - ae_int_t sfxy; - ae_matrix dx; - ae_matrix dy; - ae_matrix dxy; - double t; - ae_int_t i; - ae_int_t j; - ae_int_t k; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_f, f, _state, ae_true); - f = &_f; - _spline2dinterpolant_clear(c); - ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=2, "Spline2DBuildBicubicSpline: N<2", _state); - ae_assert(m>=2, "Spline2DBuildBicubicSpline: M<2", _state); - ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubic: length of X or Y is too short (Length(X/Y)rows>=m&&f->cols>=n, "Spline2DBuildBicubic: size of F is too small (rows(F)k = 3; - c->d = 1; - c->n = n; - c->m = m; - c->stype = -3; - sfx = c->n*c->m; - sfy = 2*c->n*c->m; - sfxy = 3*c->n*c->m; - ae_vector_set_length(&c->x, c->n, _state); - ae_vector_set_length(&c->y, c->m, _state); - ae_vector_set_length(&c->f, 4*c->n*c->m, _state); - for(i=0; i<=c->n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - c->y.ptr.p_double[i] = y->ptr.p_double[i]; - } - - /* - * Sort points - */ - for(j=0; j<=c->n-1; j++) - { - k = j; - for(i=j+1; i<=c->n-1; i++) - { - if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) - { - k = i; - } - } - if( k!=j ) - { - for(i=0; i<=c->m-1; i++) - { - t = f->ptr.pp_double[i][j]; - f->ptr.pp_double[i][j] = f->ptr.pp_double[i][k]; - f->ptr.pp_double[i][k] = t; - } - t = c->x.ptr.p_double[j]; - c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; - c->x.ptr.p_double[k] = t; - } - } - for(i=0; i<=c->m-1; i++) - { - k = i; - for(j=i+1; j<=c->m-1; j++) - { - if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) - { - k = j; - } - } - if( k!=i ) - { - for(j=0; j<=c->n-1; j++) - { - t = f->ptr.pp_double[i][j]; - f->ptr.pp_double[i][j] = f->ptr.pp_double[k][j]; - f->ptr.pp_double[k][j] = t; - } - t = c->y.ptr.p_double[i]; - c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; - c->y.ptr.p_double[k] = t; - } - } - spline2d_bicubiccalcderivatives(f, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state); - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->n-1; j++) - { - k = i*c->n+j; - c->f.ptr.p_double[k] = f->ptr.pp_double[i][j]; - c->f.ptr.p_double[sfx+k] = dx.ptr.pp_double[i][j]; - c->f.ptr.p_double[sfy+k] = dy.ptr.pp_double[i][j]; - c->f.ptr.p_double[sfxy+k] = dxy.ptr.pp_double[i][j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DUnpackV(), which is more flexible -and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpack(spline2dinterpolant* c, - ae_int_t* m, - ae_int_t* n, - /* Real */ ae_matrix* tbl, - ae_state *_state) -{ - ae_int_t k; - ae_int_t p; - ae_int_t ci; - ae_int_t cj; - ae_int_t s1; - ae_int_t s2; - ae_int_t s3; - ae_int_t s4; - ae_int_t sfx; - ae_int_t sfy; - ae_int_t sfxy; - double y1; - double y2; - double y3; - double y4; - double dt; - double du; - ae_int_t i; - ae_int_t j; - - *m = 0; - *n = 0; - ae_matrix_clear(tbl); - - ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpack: incorrect C (incorrect parameter C.SType)", _state); - if( c->d!=1 ) - { - *n = 0; - *m = 0; - return; - } - *n = c->n; - *m = c->m; - ae_matrix_set_length(tbl, (*n-1)*(*m-1), 20, _state); - sfx = *n*(*m); - sfy = 2*(*n)*(*m); - sfxy = 3*(*n)*(*m); - - /* - * Fill - */ - for(i=0; i<=*m-2; i++) - { - for(j=0; j<=*n-2; j++) - { - p = i*(*n-1)+j; - tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; - tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; - tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; - tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; - dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); - du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); - - /* - * Bilinear interpolation - */ - if( c->stype==-1 ) - { - for(k=4; k<=19; k++) - { - tbl->ptr.pp_double[p][k] = 0; - } - y1 = c->f.ptr.p_double[*n*i+j]; - y2 = c->f.ptr.p_double[*n*i+(j+1)]; - y3 = c->f.ptr.p_double[*n*(i+1)+(j+1)]; - y4 = c->f.ptr.p_double[*n*(i+1)+j]; - tbl->ptr.pp_double[p][4] = y1; - tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; - tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; - tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; - } - - /* - * Bicubic interpolation - */ - if( c->stype==-3 ) - { - s1 = *n*i+j; - s2 = *n*i+(j+1); - s3 = *n*(i+1)+(j+1); - s4 = *n*(i+1)+j; - tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; - tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; - tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; - tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; - tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; - tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); - tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; - tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; - tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); - tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); - } - - /* - * Rescale Cij - */ - for(ci=0; ci<=3; ci++) - { - for(cj=0; cj<=3; cj++) - { - tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, ci, _state)*ae_pow(du, cj, _state); - } - } - } - } -} - - -/************************************************************************* -Internal subroutine. -Calculation of the first derivatives and the cross-derivative. -*************************************************************************/ -static void spline2d_bicubiccalcderivatives(/* Real */ ae_matrix* a, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* dx, - /* Real */ ae_matrix* dy, - /* Real */ ae_matrix* dxy, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector xt; - ae_vector ft; - double s; - double ds; - double d2s; - spline1dinterpolant c; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(dx); - ae_matrix_clear(dy); - ae_matrix_clear(dxy); - ae_vector_init(&xt, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ft, 0, DT_REAL, _state, ae_true); - _spline1dinterpolant_init(&c, _state, ae_true); - - ae_matrix_set_length(dx, m, n, _state); - ae_matrix_set_length(dy, m, n, _state); - ae_matrix_set_length(dxy, m, n, _state); - - /* - * dF/dX - */ - ae_vector_set_length(&xt, n, _state); - ae_vector_set_length(&ft, n, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - xt.ptr.p_double[j] = x->ptr.p_double[j]; - ft.ptr.p_double[j] = a->ptr.pp_double[i][j]; - } - spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state); - for(j=0; j<=n-1; j++) - { - spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state); - dx->ptr.pp_double[i][j] = ds; - } - } - - /* - * dF/dY - */ - ae_vector_set_length(&xt, m, _state); - ae_vector_set_length(&ft, m, _state); - for(j=0; j<=n-1; j++) - { - for(i=0; i<=m-1; i++) - { - xt.ptr.p_double[i] = y->ptr.p_double[i]; - ft.ptr.p_double[i] = a->ptr.pp_double[i][j]; - } - spline1dbuildcubic(&xt, &ft, m, 0, 0.0, 0, 0.0, &c, _state); - for(i=0; i<=m-1; i++) - { - spline1ddiff(&c, y->ptr.p_double[i], &s, &ds, &d2s, _state); - dy->ptr.pp_double[i][j] = ds; - } - } - - /* - * d2F/dXdY - */ - ae_vector_set_length(&xt, n, _state); - ae_vector_set_length(&ft, n, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - xt.ptr.p_double[j] = x->ptr.p_double[j]; - ft.ptr.p_double[j] = dy->ptr.pp_double[i][j]; - } - spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state); - for(j=0; j<=n-1; j++) - { - spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state); - dxy->ptr.pp_double[i][j] = ds; - } - } - ae_frame_leave(_state); -} - - -ae_bool _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - spline2dinterpolant *p = (spline2dinterpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - spline2dinterpolant *dst = (spline2dinterpolant*)_dst; - spline2dinterpolant *src = (spline2dinterpolant*)_src; - dst->k = src->k; - dst->stype = src->stype; - dst->n = src->n; - dst->m = src->m; - dst->d = src->d; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _spline2dinterpolant_clear(void* _p) -{ - spline2dinterpolant *p = (spline2dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->y); - ae_vector_clear(&p->f); -} - - -void _spline2dinterpolant_destroy(void* _p) -{ - spline2dinterpolant *p = (spline2dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->y); - ae_vector_destroy(&p->f); -} - - - - -/************************************************************************* -This subroutine calculates the value of the trilinear or tricubic spline at -the given point (X,Y,Z). - -INPUT PARAMETERS: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y, - Z - point - -Result: - S(x,y,z) - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -double spline3dcalc(spline3dinterpolant* c, - double x, - double y, - double z, - ae_state *_state) -{ - double v; - double vx; - double vy; - double vxy; - double result; - - - ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalc: incorrect C (incorrect parameter C.SType)", _state); - ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalc: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); - if( c->d!=1 ) - { - result = 0; - return result; - } - spline3d_spline3ddiff(c, x, y, z, &v, &vx, &vy, &vxy, _state); - result = v; - return result; -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant - AX, BX - transformation coefficients: x = A*u + B - AY, BY - transformation coefficients: y = A*v + B - AZ, BZ - transformation coefficients: z = A*w + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransxyz(spline3dinterpolant* c, - double ax, - double bx, - double ay, - double by, - double az, - double bz, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_vector z; - ae_vector f; - ae_vector v; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t di; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&z, 0, DT_REAL, _state, ae_true); - ae_vector_init(&f, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - - ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransXYZ: incorrect C (incorrect parameter C.SType)", _state); - ae_vector_set_length(&x, c->n, _state); - ae_vector_set_length(&y, c->m, _state); - ae_vector_set_length(&z, c->l, _state); - ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); - for(j=0; j<=c->n-1; j++) - { - x.ptr.p_double[j] = c->x.ptr.p_double[j]; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = c->y.ptr.p_double[i]; - } - for(i=0; i<=c->l-1; i++) - { - z.ptr.p_double[i] = c->z.ptr.p_double[i]; - } - - /* - * Handle different combinations of zero/nonzero AX/AY/AZ - */ - if( (ae_fp_neq(ax,0)&&ae_fp_neq(ay,0))&&ae_fp_neq(az,0) ) - { - ae_v_move(&f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,c->m*c->n*c->l*c->d-1)); - } - if( (ae_fp_eq(ax,0)&&ae_fp_neq(ay,0))&&ae_fp_neq(az,0) ) - { - for(i=0; i<=c->m-1; i++) - { - for(j=0; j<=c->l-1; j++) - { - spline3dcalcv(c, bx, y.ptr.p_double[i], z.ptr.p_double[j], &v, _state); - for(k=0; k<=c->n-1; k++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*j+i)+k)+di] = v.ptr.p_double[di]; - } - } - } - } - ax = 1; - bx = 0; - } - if( (ae_fp_neq(ax,0)&&ae_fp_eq(ay,0))&&ae_fp_neq(az,0) ) - { - for(i=0; i<=c->n-1; i++) - { - for(j=0; j<=c->l-1; j++) - { - spline3dcalcv(c, x.ptr.p_double[i], by, z.ptr.p_double[j], &v, _state); - for(k=0; k<=c->m-1; k++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*j+k)+i)+di] = v.ptr.p_double[di]; - } - } - } - } - ay = 1; - by = 0; - } - if( (ae_fp_neq(ax,0)&&ae_fp_neq(ay,0))&&ae_fp_eq(az,0) ) - { - for(i=0; i<=c->n-1; i++) - { - for(j=0; j<=c->m-1; j++) - { - spline3dcalcv(c, x.ptr.p_double[i], y.ptr.p_double[j], bz, &v, _state); - for(k=0; k<=c->l-1; k++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; - } - } - } - } - az = 1; - bz = 0; - } - if( (ae_fp_eq(ax,0)&&ae_fp_eq(ay,0))&&ae_fp_neq(az,0) ) - { - for(i=0; i<=c->l-1; i++) - { - spline3dcalcv(c, bx, by, z.ptr.p_double[i], &v, _state); - for(k=0; k<=c->m-1; k++) - { - for(j=0; j<=c->n-1; j++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*i+k)+j)+di] = v.ptr.p_double[di]; - } - } - } - } - ax = 1; - bx = 0; - ay = 1; - by = 0; - } - if( (ae_fp_eq(ax,0)&&ae_fp_neq(ay,0))&&ae_fp_eq(az,0) ) - { - for(i=0; i<=c->m-1; i++) - { - spline3dcalcv(c, bx, y.ptr.p_double[i], bz, &v, _state); - for(k=0; k<=c->l-1; k++) - { - for(j=0; j<=c->n-1; j++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*k+i)+j)+di] = v.ptr.p_double[di]; - } - } - } - } - ax = 1; - bx = 0; - az = 1; - bz = 0; - } - if( (ae_fp_neq(ax,0)&&ae_fp_eq(ay,0))&&ae_fp_eq(az,0) ) - { - for(i=0; i<=c->n-1; i++) - { - spline3dcalcv(c, x.ptr.p_double[i], by, bz, &v, _state); - for(k=0; k<=c->l-1; k++) - { - for(j=0; j<=c->m-1; j++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; - } - } - } - } - ay = 1; - by = 0; - az = 1; - bz = 0; - } - if( (ae_fp_eq(ax,0)&&ae_fp_eq(ay,0))&&ae_fp_eq(az,0) ) - { - spline3dcalcv(c, bx, by, bz, &v, _state); - for(k=0; k<=c->l-1; k++) - { - for(j=0; j<=c->m-1; j++) - { - for(i=0; i<=c->n-1; i++) - { - for(di=0; di<=c->d-1; di++) - { - f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; - } - } - } - } - ax = 1; - bx = 0; - ay = 1; - by = 0; - az = 1; - bz = 0; - } - - /* - * General case: AX<>0, AY<>0, AZ<>0 - * Unpack, scale and pack again. - */ - for(i=0; i<=c->n-1; i++) - { - x.ptr.p_double[i] = (x.ptr.p_double[i]-bx)/ax; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; - } - for(i=0; i<=c->l-1; i++) - { - z.ptr.p_double[i] = (z.ptr.p_double[i]-bz)/az; - } - if( c->stype==-1 ) - { - spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransf(spline3dinterpolant* c, - double a, - double b, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector x; - ae_vector y; - ae_vector z; - ae_vector f; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&x, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&z, 0, DT_REAL, _state, ae_true); - ae_vector_init(&f, 0, DT_REAL, _state, ae_true); - - ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransF: incorrect C (incorrect parameter C.SType)", _state); - ae_vector_set_length(&x, c->n, _state); - ae_vector_set_length(&y, c->m, _state); - ae_vector_set_length(&z, c->l, _state); - ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); - for(j=0; j<=c->n-1; j++) - { - x.ptr.p_double[j] = c->x.ptr.p_double[j]; - } - for(i=0; i<=c->m-1; i++) - { - y.ptr.p_double[i] = c->y.ptr.p_double[i]; - } - for(i=0; i<=c->l-1; i++) - { - z.ptr.p_double[i] = c->z.ptr.p_double[i]; - } - for(i=0; i<=c->m*c->n*c->l*c->d-1; i++) - { - f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; - } - if( c->stype==-1 ) - { - spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine makes the copy of the spline model. - -INPUT PARAMETERS: - C - spline interpolant - -OUTPUT PARAMETERS: - CC - spline copy - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcopy(spline3dinterpolant* c, - spline3dinterpolant* cc, - ae_state *_state) -{ - ae_int_t tblsize; - - _spline3dinterpolant_clear(cc); - - ae_assert(c->k==1||c->k==3, "Spline3DCopy: incorrect C (incorrect parameter C.K)", _state); - cc->k = c->k; - cc->n = c->n; - cc->m = c->m; - cc->l = c->l; - cc->d = c->d; - tblsize = c->n*c->m*c->l*c->d; - cc->stype = c->stype; - ae_vector_set_length(&cc->x, cc->n, _state); - ae_vector_set_length(&cc->y, cc->m, _state); - ae_vector_set_length(&cc->z, cc->l, _state); - ae_vector_set_length(&cc->f, tblsize, _state); - ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); - ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); - ae_v_move(&cc->z.ptr.p_double[0], 1, &c->z.ptr.p_double[0], 1, ae_v_len(0,cc->l-1)); - ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); -} - - -/************************************************************************* -Trilinear spline resampling - -INPUT PARAMETERS: - A - array[0..OldXCount*OldYCount*OldZCount-1], function - values at the old grid, : - A[0] x=0,y=0,z=0 - A[1] x=1,y=0,z=0 - A[..] ... - A[..] x=oldxcount-1,y=0,z=0 - A[..] x=0,y=1,z=0 - A[..] ... - ... - OldZCount - old Z-count, OldZCount>1 - OldYCount - old Y-count, OldYCount>1 - OldXCount - old X-count, OldXCount>1 - NewZCount - new Z-count, NewZCount>1 - NewYCount - new Y-count, NewYCount>1 - NewXCount - new X-count, NewXCount>1 - -OUTPUT PARAMETERS: - B - array[0..NewXCount*NewYCount*NewZCount-1], function - values at the new grid: - B[0] x=0,y=0,z=0 - B[1] x=1,y=0,z=0 - B[..] ... - B[..] x=newxcount-1,y=0,z=0 - B[..] x=0,y=1,z=0 - B[..] ... - ... - - -- ALGLIB routine -- - 26.04.2012 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline3dresampletrilinear(/* Real */ ae_vector* a, - ae_int_t oldzcount, - ae_int_t oldycount, - ae_int_t oldxcount, - ae_int_t newzcount, - ae_int_t newycount, - ae_int_t newxcount, - /* Real */ ae_vector* b, - ae_state *_state) -{ - double xd; - double yd; - double zd; - double c0; - double c1; - double c2; - double c3; - ae_int_t ix; - ae_int_t iy; - ae_int_t iz; - ae_int_t i; - ae_int_t j; - ae_int_t k; - - ae_vector_clear(b); - - ae_assert((oldycount>1&&oldzcount>1)&&oldxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); - ae_assert((newycount>1&&newzcount>1)&&newxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); - ae_assert(a->cnt>=oldycount*oldzcount*oldxcount, "Spline3DResampleTrilinear: length/width/height less than 1", _state); - ae_vector_set_length(b, newxcount*newycount*newzcount, _state); - for(i=0; i<=newxcount-1; i++) - { - for(j=0; j<=newycount-1; j++) - { - for(k=0; k<=newzcount-1; k++) - { - ix = i*(oldxcount-1)/(newxcount-1); - if( ix==oldxcount-1 ) - { - ix = oldxcount-2; - } - xd = (double)(i*(oldxcount-1))/(double)(newxcount-1)-ix; - iy = j*(oldycount-1)/(newycount-1); - if( iy==oldycount-1 ) - { - iy = oldycount-2; - } - yd = (double)(j*(oldycount-1))/(double)(newycount-1)-iy; - iz = k*(oldzcount-1)/(newzcount-1); - if( iz==oldzcount-1 ) - { - iz = oldzcount-2; - } - zd = (double)(k*(oldzcount-1))/(double)(newzcount-1)-iz; - c0 = a->ptr.p_double[oldxcount*(oldycount*iz+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+iy)+(ix+1)]*xd; - c1 = a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+(ix+1)]*xd; - c2 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+(ix+1)]*xd; - c3 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+(ix+1)]*xd; - c0 = c0*(1-yd)+c1*yd; - c1 = c2*(1-yd)+c3*yd; - b->ptr.p_double[newxcount*(newycount*k+j)+i] = c0*(1-zd)+c1*zd; - } - } - } -} - - -/************************************************************************* -This subroutine builds trilinear vector-valued spline. - -INPUT PARAMETERS: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - Z - spline applicates, array[0..L-1] - F - function values, array[0..M*N*L*D-1]: - * first D elements store D values at (X[0],Y[0],Z[0]) - * next D elements store D values at (X[1],Y[0],Z[0]) - * next D elements store D values at (X[2],Y[0],Z[0]) - * ... - * next D elements store D values at (X[0],Y[1],Z[0]) - * next D elements store D values at (X[1],Y[1],Z[0]) - * next D elements store D values at (X[2],Y[1],Z[0]) - * ... - * next D elements store D values at (X[0],Y[0],Z[1]) - * next D elements store D values at (X[1],Y[0],Z[1]) - * next D elements store D values at (X[2],Y[0],Z[1]) - * ... - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. - M,N, - L - grid size, M>=2, N>=2, L>=2 - D - vector dimension, D>=1 - -OUTPUT PARAMETERS: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dbuildtrilinearv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* z, - ae_int_t l, - /* Real */ ae_vector* f, - ae_int_t d, - spline3dinterpolant* c, - ae_state *_state) -{ - double t; - ae_int_t tblsize; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t i0; - ae_int_t j0; - - _spline3dinterpolant_clear(c); - - ae_assert(m>=2, "Spline3DBuildTrilinearV: M<2", _state); - ae_assert(n>=2, "Spline3DBuildTrilinearV: N<2", _state); - ae_assert(l>=2, "Spline3DBuildTrilinearV: L<2", _state); - ae_assert(d>=1, "Spline3DBuildTrilinearV: D<1", _state); - ae_assert((x->cnt>=n&&y->cnt>=m)&&z->cnt>=l, "Spline3DBuildTrilinearV: length of X, Y or Z is too short (Length(X/Y/Z)cnt>=tblsize, "Spline3DBuildTrilinearV: length of F is too short (Length(F)k = 1; - c->n = n; - c->m = m; - c->l = l; - c->d = d; - c->stype = -1; - ae_vector_set_length(&c->x, c->n, _state); - ae_vector_set_length(&c->y, c->m, _state); - ae_vector_set_length(&c->z, c->l, _state); - ae_vector_set_length(&c->f, tblsize, _state); - for(i=0; i<=c->n-1; i++) - { - c->x.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=c->m-1; i++) - { - c->y.ptr.p_double[i] = y->ptr.p_double[i]; - } - for(i=0; i<=c->l-1; i++) - { - c->z.ptr.p_double[i] = z->ptr.p_double[i]; - } - for(i=0; i<=tblsize-1; i++) - { - c->f.ptr.p_double[i] = f->ptr.p_double[i]; - } - - /* - * Sort points: - * * sort x; - * * sort y; - * * sort z. - */ - for(j=0; j<=c->n-1; j++) - { - k = j; - for(i=j+1; i<=c->n-1; i++) - { - if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) - { - k = i; - } - } - if( k!=j ) - { - for(i=0; i<=c->m-1; i++) - { - for(j0=0; j0<=c->l-1; j0++) - { - for(i0=0; i0<=c->d-1; i0++) - { - t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0] = t; - } - } - } - t = c->x.ptr.p_double[j]; - c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; - c->x.ptr.p_double[k] = t; - } - } - for(i=0; i<=c->m-1; i++) - { - k = i; - for(j=i+1; j<=c->m-1; j++) - { - if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) - { - k = j; - } - } - if( k!=i ) - { - for(j=0; j<=c->n-1; j++) - { - for(j0=0; j0<=c->l-1; j0++) - { - for(i0=0; i0<=c->d-1; i0++) - { - t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0] = t; - } - } - } - t = c->y.ptr.p_double[i]; - c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; - c->y.ptr.p_double[k] = t; - } - } - for(k=0; k<=c->l-1; k++) - { - i = k; - for(j=i+1; j<=c->l-1; j++) - { - if( ae_fp_less(c->z.ptr.p_double[j],c->z.ptr.p_double[i]) ) - { - i = j; - } - } - if( i!=k ) - { - for(j=0; j<=c->m-1; j++) - { - for(j0=0; j0<=c->n-1; j0++) - { - for(i0=0; i0<=c->d-1; i0++) - { - t = c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0]; - c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0] = t; - } - } - } - t = c->z.ptr.p_double[k]; - c->z.ptr.p_double[k] = c->z.ptr.p_double[i]; - c->z.ptr.p_double[i] = t; - } - } -} - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcvbuf(spline3dinterpolant* c, - double x, - double y, - double z, - /* Real */ ae_vector* f, - ae_state *_state) -{ - double xd; - double yd; - double zd; - double c0; - double c1; - double c2; - double c3; - ae_int_t ix; - ae_int_t iy; - ae_int_t iz; - ae_int_t l; - ae_int_t r; - ae_int_t h; - ae_int_t i; - - - ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); - ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcVBuf: X, Y or Z contains NaN/Infinite", _state); - rvectorsetlengthatleast(f, c->d, _state); - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = c->n-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) - { - r = h; - } - else - { - l = h; - } - } - ix = l; - - /* - * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) - */ - l = 0; - r = c->m-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) - { - r = h; - } - else - { - l = h; - } - } - iy = l; - - /* - * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) - */ - l = 0; - r = c->l-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) - { - r = h; - } - else - { - l = h; - } - } - iz = l; - xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); - yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); - zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); - for(i=0; i<=c->d-1; i++) - { - - /* - * Trilinear interpolation - */ - if( c->stype==-1 ) - { - c0 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+(ix+1))+i]*xd; - c1 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+(ix+1))+i]*xd; - c2 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+(ix+1))+i]*xd; - c3 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+(ix+1))+i]*xd; - c0 = c0*(1-yd)+c1*yd; - c1 = c2*(1-yd)+c3*yd; - f->ptr.p_double[i] = c0*(1-zd)+c1*zd; - } - } -} - - -/************************************************************************* -This subroutine calculates trilinear or tricubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcv(spline3dinterpolant* c, - double x, - double y, - double z, - /* Real */ ae_vector* f, - ae_state *_state) -{ - - ae_vector_clear(f); - - ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcV: incorrect C (incorrect parameter C.SType)", _state); - ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcV: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); - ae_vector_set_length(f, c->d, _state); - spline3dcalcvbuf(c, x, y, z, f, _state); -} - - -/************************************************************************* -This subroutine unpacks tri-dimensional spline into the coefficients table - -INPUT PARAMETERS: - C - spline interpolant. - -Result: - N - grid size (X) - M - grid size (Y) - L - grid size (Z) - D - number of components - SType- spline type. Currently, only one spline type is supported: - trilinear spline, as indicated by SType=1. - Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index), K=0..L-2 (z index): - Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), - - Q-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[Q,0] = X[i] - Tbl[Q,1] = X[i+1] - Tbl[Q,2] = Y[j] - Tbl[Q,3] = Y[j+1] - Tbl[Q,4] = Z[k] - Tbl[Q,5] = Z[k+1] - - Tbl[Q,6] = C000 - Tbl[Q,7] = C100 - Tbl[Q,8] = C010 - Tbl[Q,9] = C110 - Tbl[Q,10]= C001 - Tbl[Q,11]= C101 - Tbl[Q,12]= C011 - Tbl[Q,13]= C111 - On each grid square spline is equals to: - S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) - t = x-x[j] - u = y-y[i] - v = z-z[k] - - NOTE: format of Tbl is given for SType=1. Future versions of - ALGLIB can use different formats for different values of - SType. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dunpackv(spline3dinterpolant* c, - ae_int_t* n, - ae_int_t* m, - ae_int_t* l, - ae_int_t* d, - ae_int_t* stype, - /* Real */ ae_matrix* tbl, - ae_state *_state) -{ - ae_int_t p; - ae_int_t ci; - ae_int_t cj; - ae_int_t ck; - double du; - double dv; - double dw; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t di; - ae_int_t i0; - - *n = 0; - *m = 0; - *l = 0; - *d = 0; - *stype = 0; - ae_matrix_clear(tbl); - - ae_assert(c->stype==-1, "Spline3DUnpackV: incorrect C (incorrect parameter C.SType)", _state); - *n = c->n; - *m = c->m; - *l = c->l; - *d = c->d; - *stype = ae_iabs(c->stype, _state); - ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*l-1)*(*d), 14, _state); - - /* - * Fill - */ - for(i=0; i<=*n-2; i++) - { - for(j=0; j<=*m-2; j++) - { - for(k=0; k<=*l-2; k++) - { - for(di=0; di<=*d-1; di++) - { - p = *d*((*n-1)*((*m-1)*k+j)+i)+di; - tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[i]; - tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[i+1]; - tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[j]; - tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[j+1]; - tbl->ptr.pp_double[p][4] = c->z.ptr.p_double[k]; - tbl->ptr.pp_double[p][5] = c->z.ptr.p_double[k+1]; - du = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); - dv = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); - dw = 1/(tbl->ptr.pp_double[p][5]-tbl->ptr.pp_double[p][4]); - - /* - * Trilinear interpolation - */ - if( c->stype==-1 ) - { - for(i0=6; i0<=13; i0++) - { - tbl->ptr.pp_double[p][i0] = 0; - } - tbl->ptr.pp_double[p][6+2*(2*0+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*0+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*0+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*0+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*1+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*1+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*1+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - tbl->ptr.pp_double[p][6+2*(2*1+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; - } - - /* - * Rescale Cij - */ - for(ci=0; ci<=1; ci++) - { - for(cj=0; cj<=1; cj++) - { - for(ck=0; ck<=1; ck++) - { - tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci] = tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci]*ae_pow(du, ci, _state)*ae_pow(dv, cj, _state)*ae_pow(dw, ck, _state); - } - } - } - } - } - } - } -} - - -/************************************************************************* -This subroutine calculates the value of the trilinear(or tricubic;possible -will be later) spline at the given point X(and its derivatives; possible -will be later). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, Z - point - -OUTPUT PARAMETERS: - F - S(x,y,z) - FX - dS(x,y,z)/dX - FY - dS(x,y,z)/dY - FXY - d2S(x,y,z)/dXdY - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -static void spline3d_spline3ddiff(spline3dinterpolant* c, - double x, - double y, - double z, - double* f, - double* fx, - double* fy, - double* fxy, - ae_state *_state) -{ - double xd; - double yd; - double zd; - double c0; - double c1; - double c2; - double c3; - ae_int_t ix; - ae_int_t iy; - ae_int_t iz; - ae_int_t l; - ae_int_t r; - ae_int_t h; - - *f = 0; - *fx = 0; - *fy = 0; - *fxy = 0; - - ae_assert(c->stype==-1||c->stype==-3, "Spline3DDiff: incorrect C (incorrect parameter C.SType)", _state); - ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline3DDiff: X or Y contains NaN or Infinite value", _state); - - /* - * Prepare F, dF/dX, dF/dY, d2F/dXdY - */ - *f = 0; - *fx = 0; - *fy = 0; - *fxy = 0; - if( c->d!=1 ) - { - return; - } - - /* - * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) - */ - l = 0; - r = c->n-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) - { - r = h; - } - else - { - l = h; - } - } - ix = l; - - /* - * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) - */ - l = 0; - r = c->m-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) - { - r = h; - } - else - { - l = h; - } - } - iy = l; - - /* - * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) - */ - l = 0; - r = c->l-1; - while(l!=r-1) - { - h = (l+r)/2; - if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) - { - r = h; - } - else - { - l = h; - } - } - iz = l; - xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); - yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); - zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); - - /* - * Trilinear interpolation - */ - if( c->stype==-1 ) - { - c0 = c->f.ptr.p_double[c->n*(c->m*iz+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+iy)+(ix+1)]*xd; - c1 = c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+(ix+1)]*xd; - c2 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+(ix+1)]*xd; - c3 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+(ix+1)]*xd; - c0 = c0*(1-yd)+c1*yd; - c1 = c2*(1-yd)+c3*yd; - *f = c0*(1-zd)+c1*zd; - } -} - - -ae_bool _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - spline3dinterpolant *p = (spline3dinterpolant*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - spline3dinterpolant *dst = (spline3dinterpolant*)_dst; - spline3dinterpolant *src = (spline3dinterpolant*)_src; - dst->k = src->k; - dst->stype = src->stype; - dst->n = src->n; - dst->m = src->m; - dst->l = src->l; - dst->d = src->d; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _spline3dinterpolant_clear(void* _p) -{ - spline3dinterpolant *p = (spline3dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->y); - ae_vector_clear(&p->z); - ae_vector_clear(&p->f); -} - - -void _spline3dinterpolant_destroy(void* _p) -{ - spline3dinterpolant *p = (spline3dinterpolant*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->y); - ae_vector_destroy(&p->z); - ae_vector_destroy(&p->f); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "interpolation.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Rational interpolation using barycentric formula + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +Input parameters: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +Result: + barycentric interpolant F(t) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +double barycentriccalc(const barycentricinterpolant &b, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::barycentriccalc(b.c_ptr(), t, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Differentiation of barycentric interpolant: first derivative. + +Algorithm used in this subroutine is very robust and should not fail until +provided with values too close to MaxRealNumber (usually MaxRealNumber/N +or greater will overflow). + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + +NOTE + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricdiff1(b.c_ptr(), t, &f, &df, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Differentiation of barycentric interpolant: first/second derivatives. + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + D2F - second derivative + +NOTE: this algorithm may fail due to overflow/underflor if used on data +whose values are close to MaxRealNumber or MinRealNumber. Use more robust +BarycentricDiff1() subroutine in such cases. + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricdiff2(b.c_ptr(), t, &f, &df, &d2f, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the argument. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: x = CA*t + CB + +OUTPUT PARAMETERS: + B - transformed interpolant with X replaced by T + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransx(barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentriclintransx(b.c_ptr(), ca, cb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the barycentric +interpolant. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB + +OUTPUT PARAMETERS: + B - transformed interpolant + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransy(barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentriclintransy(b.c_ptr(), ca, cb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Extracts X/Y/W arrays from rational interpolant + +INPUT PARAMETERS: + B - barycentric interpolant + +OUTPUT PARAMETERS: + N - nodes count, N>0 + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricunpack(b.c_ptr(), &n, x.c_ptr(), y.c_ptr(), w.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Rational interpolant from X/Y/W arrays + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +INPUT PARAMETERS: + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + N - nodes count, N>0 + +OUTPUT PARAMETERS: + B - barycentric interpolant built from (X, Y, W) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricbuildxyw(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Rational interpolant without poles + +The subroutine constructs the rational interpolating function without real +poles (see 'Barycentric rational interpolation with no poles and high +rates of approximation', Michael S. Floater. and Kai Hormann, for more +information on this subject). + +Input parameters: + X - interpolation nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of nodes, N>0. + D - order of the interpolation scheme, 0 <= D <= N-1. + D<0 will cause an error. + D>=N it will be replaced with D=N-1. + if you don't know what D to choose, use small value about 3-5. + +Output parameters: + B - barycentric interpolant. + +Note: + this algorithm always succeeds and calculates the weights with close + to machine precision. + + -- ALGLIB PROJECT -- + Copyright 17.06.2007 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricbuildfloaterhormann(x.c_ptr(), y.c_ptr(), n, d, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Barycentric interpolant. +*************************************************************************/ +_barycentricinterpolant_owner::_barycentricinterpolant_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_barycentricinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant)); + alglib_impl::_barycentricinterpolant_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_barycentricinterpolant_owner::_barycentricinterpolant_owner(alglib_impl::barycentricinterpolant *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_barycentricinterpolant_owner::_barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_barycentricinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant)); + alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_barycentricinterpolant_owner& _barycentricinterpolant_owner::operator=(const _barycentricinterpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: barycentricinterpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_barycentricinterpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant)); + alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_barycentricinterpolant_owner::~_barycentricinterpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_barycentricinterpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() const +{ + return p_struct; +} +barycentricinterpolant::barycentricinterpolant() : _barycentricinterpolant_owner() +{ +} + +barycentricinterpolant::barycentricinterpolant(alglib_impl::barycentricinterpolant *attach_to):_barycentricinterpolant_owner(attach_to) +{ +} + +barycentricinterpolant::barycentricinterpolant(const barycentricinterpolant &rhs):_barycentricinterpolant_owner(rhs) +{ +} + +barycentricinterpolant& barycentricinterpolant::operator=(const barycentricinterpolant &rhs) +{ + if( this==&rhs ) + return *this; + _barycentricinterpolant_owner::operator=(rhs); + return *this; +} + +barycentricinterpolant::~barycentricinterpolant() +{ +} +#endif + +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void idwserialize(const idwmodel &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void idwserialize(const idwmodel &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void idwunserialize(const std::string &s_in, idwmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void idwunserialize(const std::istream &s_in, idwmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel IDW model evaluations (with one IDW model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with idwtscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create IDW model structure or load it from file +* call idwcreatecalcbuffer(), once per thread working with IDW model (you + should call this function only AFTER model initialization, see below for + more information) +* call idwtscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - IDW model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with IDW model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of the IDW structure. + +IMPORTANT: you should call this function only for model which was built + with model builder (or unserialized from file). Sizes of some + internal structures are determined only after model is built, + so buffer object created before model construction stage will + be useless (and any attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 22.10.2018 by Sergey Bochkanov +*************************************************************************/ +void idwcreatecalcbuffer(const idwmodel &s, idwcalcbuffer &buf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwcreatecalcbuffer(s.c_ptr(), buf.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine creates builder object used to generate IDW model from +irregularly sampled (scattered) dataset. Multidimensional scalar/vector- +-valued are supported. + +Builder object is used to fit model to data as follows: +* builder object is created with idwbuildercreate() function +* dataset is added with idwbuildersetpoints() function +* one of the modern IDW algorithms is chosen with either: + * idwbuildersetalgomstab() - Multilayer STABilized algorithm (interpolation) + Alternatively, one of the textbook algorithms can be chosen (not recommended): + * idwbuildersetalgotextbookshepard() - textbook Shepard algorithm + * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm +* finally, model construction is performed with idwfit() function. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + NX - dimensionality of the argument, NX>=1 + NY - dimensionality of the function being modeled, NY>=1; + NY=1 corresponds to classic scalar function, NY>=1 corresponds + to vector-valued function. + +OUTPUT PARAMETERS: + State- builder object + + -- ALGLIB PROJECT -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildercreate(const ae_int_t nx, const ae_int_t ny, idwbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildercreate(nx, ny, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes number of layers used by IDW-MSTAB algorithm. + +The more layers you have, the finer details can be reproduced with IDW +model. The less layers you have, the less memory and CPU time is consumed +by the model. + +Memory consumption grows linearly with layers count, running time grows +sub-linearly. + +The default number of layers is 16, which allows you to reproduce details +at distance down to SRad/65536. You will rarely need to change it. + +INPUT PARAMETERS: + State - builder object + NLayers - NLayers>=1, the number of layers used by the model. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetnlayers(idwbuilder &state, const ae_int_t nlayers, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetnlayers(state.c_ptr(), nlayers, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + State - builder object + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset, N>=0. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetpoints(idwbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetpoints(state.c_ptr(), xy.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + State - builder object + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset, N>=0. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void idwbuildersetpoints(idwbuilder &state, const real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetpoints(state.c_ptr(), xy.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets IDW model construction algorithm to the Multilayer +Stabilized IDW method (IDW-MSTAB), a latest incarnation of the inverse +distance weighting interpolation which fixes shortcomings of the original +and modified Shepard's variants. + +The distinctive features of IDW-MSTAB are: +1) exact interpolation is pursued (as opposed to fitting and noise + suppression) +2) improved robustness when compared with that of other algorithms: + * MSTAB shows almost no strange fitting artifacts like ripples and + sharp spikes (unlike N-dimensional splines and HRBFs) + * MSTAB does not return function values far from the interval spanned + by the dataset; say, if all your points have |f|<=1, you can be sure + that model value won't deviate too much from [-1,+1] +3) good model construction time competing with that of HRBFs and bicubic + splines +4) ability to work with any number of dimensions, starting from NX=1 + +The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are: +1) dependence of the model evaluation time on the search radius +2) bad extrapolation properties, models built by this method are usually + conservative in their predictions + +Thus, IDW-MSTAB is a good "default" option if you want to perform +scattered multidimensional interpolation. Although it has its drawbacks, +it is easy to use and robust, which makes it a good first step. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + SRad - initial search radius, SRad>0 is required. A model value + is obtained by "smart" averaging of the dataset points + within search radius. + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + +NOTE 2: the memory requirements for model storage are O(NPoints*NLayers). + The model construction needs twice as much memory as model storage. + +NOTE 3: by default 16 IDW layers are built which is enough for most cases. + You can change this parameter with idwbuildersetnlayers() method. + Larger values may be necessary if you need to reproduce extrafine + details at distances smaller than SRad/65536. Smaller value may + be necessary if you have to save memory and computing time, and + ready to sacrifice some model quality. + + +ALGORITHM DESCRIPTION + +ALGLIB implementation of IDW is somewhat similar to the modified Shepard's +method (one with search radius R) but overcomes several of its drawbacks, +namely: +1) a tendency to show stepwise behavior for uniform datasets +2) a tendency to show terrible interpolation properties for highly + nonuniform datasets which often arise in geospatial tasks + (function values are densely sampled across multiple separated + "tracks") + +IDW-MSTAB method performs several passes over dataset and builds a sequence +of progressively refined IDW models (layers), which starts from one with +largest search radius SRad and continues to smaller search radii until +required number of layers is built. Highest layers reproduce global +behavior of the target function at larger distances whilst lower layers +reproduce fine details at smaller distances. + +Each layer is an IDW model built with following modifications: +* weights go to zero when distance approach to the current search radius +* an additional regularizing term is added to the distance: w=1/(d^2+lambda) +* an additional fictional term with unit weight and zero function value is + added in order to promote continuity properties at the isolated and + boundary points + +By default, 16 layers is built, which is enough for most cases. You can +change this parameter with idwbuildersetnlayers() method. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgomstab(idwbuilder &state, const double srad, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetalgomstab(state.c_ptr(), srad, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets IDW model construction algorithm to the textbook +Shepard's algorithm with custom (user-specified) power parameter. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + P - power parameter, P>0; good value to start with is 2.0 + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookshepard(idwbuilder &state, const double p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetalgotextbookshepard(state.c_ptr(), p, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets IDW model construction algorithm to the 'textbook' +modified Shepard's algorithm with user-specified search radius. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + R - search radius + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookmodshepard(idwbuilder &state, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetalgotextbookmodshepard(state.c_ptr(), r, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets prior term (model value at infinity) as user-specified +value. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + +NOTE: for vector-valued models all components of the prior are set to same + user-specified value + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetuserterm(idwbuilder &state, const double v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetuserterm(state.c_ptr(), v, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets constant prior term (model value at infinity). + +Constant prior term is determined as mean value over dataset. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetconstterm(idwbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetconstterm(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets zero prior term (model value at infinity). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetzeroterm(idwbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwbuildersetzeroterm(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +IDW interpolation: scalar target, 1-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0 - argument value + +Result: + IDW interpolant S(X0) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc1(idwmodel &s, const double x0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::idwcalc1(s.c_ptr(), x0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +IDW interpolation: scalar target, 2-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0, X1 - argument value + +Result: + IDW interpolant S(X0,X1) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc2(idwmodel &s, const double x0, const double x1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::idwcalc2(s.c_ptr(), x0, x1, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +IDW interpolation: scalar target, 3-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0,X1,X2- argument value + +Result: + IDW interpolant S(X0,X1,X2) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc3(idwmodel &s, const double x0, const double x1, const double x2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::idwcalc3(s.c_ptr(), x0, x1, x2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use idwcalc1(), +idwcalc2() or idwcalc3(). + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and will be + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use idwcalcbuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalc(idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwcalc(s.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +Same as idwcalc(), but does not reallocate Y when in is large enough to +store function values. + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalcbuf(idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwcalcbuf(s.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the IDW model at the given point, using +external buffer object (internal temporaries of IDW model are not +modified). + +This function allows to use same IDW model object in different threads, +assuming that different threads use different instances of the buffer +structure. + +INPUT PARAMETERS: + S - IDW model, may be shared between different threads + Buf - buffer object created for this particular instance of IDW + model with idwcreatecalcbuffer(). + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void idwtscalcbuf(const idwmodel &s, idwcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwtscalcbuf(s.c_ptr(), buf.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function fits IDW model to the dataset using current IDW construction +algorithm. A model being built and fitting report are returned. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + +OUTPUT PARAMETERS: + Model - an IDW model built with current algorithm + Rep - model fitting report, fields of this structure contain + information about average fitting errors. + +NOTE: although IDW-MSTAB algorithm is an interpolation method, i.e. it + tries to fit the model exactly, it can handle datasets with non- + distinct points which can not be fit exactly; in such cases least- + squares fitting is performed. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwfit(idwbuilder &state, idwmodel &model, idwreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwfit(state.c_ptr(), model.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to peek into the IDW construction process from some +other thread and get the progress indicator. It returns value in [0,1]. + +IMPORTANT: only MSTAB algorithm supports peeking into progress indicator. + Legacy versions of the Shepard's method do not support it. You + will always get zero as the result. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 27.11.2023 by Bochkanov Sergey +*************************************************************************/ +double idwpeekprogress(const idwbuilder &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::idwpeekprogress(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates values of an IDW model at a regular grid, +which has N0*N1 points, with Point[I,J] = (X0[I], X1[J]). Vector-valued +IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued IDW models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use idwgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2v(const idwmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwgridcalc2v(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of an IDW model at some subset of a +regular grid: +* the grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of the grid are required +Vector-valued IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued IDW models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. Generally, + they are not calculated, but future SIMD-capable + versions may compute several elements in a batch. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2vsubset(const idwmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::idwgridcalc2vsubset(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, flagy.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Buffer object which is used to perform evaluation requests in the +multithreaded mode (multiple threads working with same IDW object). + +This object should be created with idwcreatecalcbuffer(). +*************************************************************************/ +_idwcalcbuffer_owner::_idwcalcbuffer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwcalcbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer)); + alglib_impl::_idwcalcbuffer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwcalcbuffer_owner::_idwcalcbuffer_owner(alglib_impl::idwcalcbuffer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_idwcalcbuffer_owner::_idwcalcbuffer_owner(const _idwcalcbuffer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwcalcbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer)); + alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwcalcbuffer_owner& _idwcalcbuffer_owner::operator=(const _idwcalcbuffer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: idwcalcbuffer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_idwcalcbuffer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer)); + alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_idwcalcbuffer_owner::~_idwcalcbuffer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_idwcalcbuffer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr() const +{ + return p_struct; +} +idwcalcbuffer::idwcalcbuffer() : _idwcalcbuffer_owner() +{ +} + +idwcalcbuffer::idwcalcbuffer(alglib_impl::idwcalcbuffer *attach_to):_idwcalcbuffer_owner(attach_to) +{ +} + +idwcalcbuffer::idwcalcbuffer(const idwcalcbuffer &rhs):_idwcalcbuffer_owner(rhs) +{ +} + +idwcalcbuffer& idwcalcbuffer::operator=(const idwcalcbuffer &rhs) +{ + if( this==&rhs ) + return *this; + _idwcalcbuffer_owner::operator=(rhs); + return *this; +} + +idwcalcbuffer::~idwcalcbuffer() +{ +} + + + + +/************************************************************************* +IDW (Inverse Distance Weighting) model object. +*************************************************************************/ +_idwmodel_owner::_idwmodel_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwmodel)); + alglib_impl::_idwmodel_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwmodel_owner::_idwmodel_owner(alglib_impl::idwmodel *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_idwmodel_owner::_idwmodel_owner(const _idwmodel_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwmodel)); + alglib_impl::_idwmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwmodel_owner& _idwmodel_owner::operator=(const _idwmodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: idwmodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_idwmodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::idwmodel)); + alglib_impl::_idwmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_idwmodel_owner::~_idwmodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_idwmodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::idwmodel* _idwmodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::idwmodel* _idwmodel_owner::c_ptr() const +{ + return p_struct; +} +idwmodel::idwmodel() : _idwmodel_owner() +{ +} + +idwmodel::idwmodel(alglib_impl::idwmodel *attach_to):_idwmodel_owner(attach_to) +{ +} + +idwmodel::idwmodel(const idwmodel &rhs):_idwmodel_owner(rhs) +{ +} + +idwmodel& idwmodel::operator=(const idwmodel &rhs) +{ + if( this==&rhs ) + return *this; + _idwmodel_owner::operator=(rhs); + return *this; +} + +idwmodel::~idwmodel() +{ +} + + + + +/************************************************************************* +Builder object used to generate IDW (Inverse Distance Weighting) model. +*************************************************************************/ +_idwbuilder_owner::_idwbuilder_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwbuilder)); + alglib_impl::_idwbuilder_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwbuilder_owner::_idwbuilder_owner(alglib_impl::idwbuilder *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_idwbuilder_owner::_idwbuilder_owner(const _idwbuilder_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwbuilder)); + alglib_impl::_idwbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwbuilder_owner& _idwbuilder_owner::operator=(const _idwbuilder_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: idwbuilder assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_idwbuilder_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::idwbuilder)); + alglib_impl::_idwbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_idwbuilder_owner::~_idwbuilder_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_idwbuilder_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr() const +{ + return p_struct; +} +idwbuilder::idwbuilder() : _idwbuilder_owner() +{ +} + +idwbuilder::idwbuilder(alglib_impl::idwbuilder *attach_to):_idwbuilder_owner(attach_to) +{ +} + +idwbuilder::idwbuilder(const idwbuilder &rhs):_idwbuilder_owner(rhs) +{ +} + +idwbuilder& idwbuilder::operator=(const idwbuilder &rhs) +{ + if( this==&rhs ) + return *this; + _idwbuilder_owner::operator=(rhs); + return *this; +} + +idwbuilder::~idwbuilder() +{ +} + + + + +/************************************************************************* +IDW fitting report: + rmserror RMS error + avgerror average error + maxerror maximum error + r2 coefficient of determination, R-squared, 1-RSS/TSS +*************************************************************************/ +_idwreport_owner::_idwreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwreport)); + alglib_impl::_idwreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwreport_owner::_idwreport_owner(alglib_impl::idwreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_idwreport_owner::_idwreport_owner(const _idwreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_idwreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::idwreport)); + alglib_impl::_idwreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_idwreport_owner& _idwreport_owner::operator=(const _idwreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: idwreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_idwreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::idwreport)); + alglib_impl::_idwreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_idwreport_owner::~_idwreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_idwreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::idwreport* _idwreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::idwreport* _idwreport_owner::c_ptr() const +{ + return p_struct; +} +idwreport::idwreport() : _idwreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +idwreport::idwreport(alglib_impl::idwreport *attach_to):_idwreport_owner(attach_to) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +idwreport::idwreport(const idwreport &rhs):_idwreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +idwreport& idwreport::operator=(const idwreport &rhs) +{ + if( this==&rhs ) + return *this; + _idwreport_owner::operator=(rhs); + return *this; +} + +idwreport::~idwreport() +{ +} +#endif + +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Conversion from barycentric representation to Chebyshev basis. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + P - polynomial in barycentric form + A,B - base interval for Chebyshev polynomials (see below) + A<>B + +OUTPUT PARAMETERS + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, + where Ti - I-th Chebyshev polynomial. + +NOTES: + barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbar2cheb(p.c_ptr(), a, b, t.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conversion from Chebyshev basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, + where Ti - I-th Chebyshev polynomial. + N - number of coefficients: + * if given, only leading N elements of T are used + * if not given, automatically determined from size of T + A,B - base interval for Chebyshev polynomials (see above) + A0. + +OUTPUT PARAMETERS + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if P was obtained as + result of interpolation on [-1,+1], you can set C=0 and S=1 and + represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it + is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 + will be better option. Such representation can be obtained by using + 1000.0 as offset C and 1.0 as scale S. + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return coefficients in + any case, but for N>8 they will become unreliable. However, N's + less than 5 are pretty safe. + +3. barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbar2pow(p.c_ptr(), c, s, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conversion from barycentric representation to power basis. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + P - polynomial in barycentric form + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if P was obtained as + result of interpolation on [-1,+1], you can set C=0 and S=1 and + represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it + is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 + will be better option. Such representation can be obtained by using + 1000.0 as offset C and 1.0 as scale S. + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return coefficients in + any case, but for N>8 they will become unreliable. However, N's + less than 5 are pretty safe. + +3. barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double c; + double s; + + c = 0; + s = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbar2pow(p.c_ptr(), c, s, a.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Conversion from power basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + * if given, only leading N elements of A are used + * if not given, automatically determined from size of A + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + P - polynomial in barycentric form + + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if you interpolate on + [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, + x^3 and so on. In most cases you it is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, + (x-1000)^3 will be better option (you have to specify 1000.0 as offset + C and 1.0 as scale S). + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return barycentric model + in any case, but for N>8 accuracy well degrade. However, N's less than + 5 are pretty safe. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialpow2bar(a.c_ptr(), n, c, s, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conversion from power basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + * if given, only leading N elements of A are used + * if not given, automatically determined from size of A + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + P - polynomial in barycentric form + + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if you interpolate on + [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, + x^3 and so on. In most cases you it is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, + (x-1000)^3 will be better option (you have to specify 1000.0 as offset + C and 1.0 as scale S). + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return barycentric model + in any case, but for N>8 accuracy well degrade. However, N's less than + 5 are pretty safe. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + double c; + double s; + + n = a.length(); + c = 0; + s = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialpow2bar(a.c_ptr(), n, c, s, p.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Lagrange intepolant: generation of the model on the general grid. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + X - abscissas, array[0..N-1] + Y - function values, array[0..N-1] + N - number of points, N>=1 + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuild(x.c_ptr(), y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Lagrange intepolant: generation of the model on the general grid. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + X - abscissas, array[0..N-1] + Y - function values, array[0..N-1] + N - number of points, N>=1 + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialbuild': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuild(x.c_ptr(), y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Lagrange intepolant: generation of the model on equidistant grid. +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1] + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildeqdist(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Lagrange intepolant: generation of the model on equidistant grid. +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1] + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildeqdist(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (first kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildcheb1(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (first kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildcheb1(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (second kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildcheb2(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (second kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialbuildcheb2(a, b, y.c_ptr(), n, p.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Fast equidistant polynomial interpolation function with O(N) complexity + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on equidistant grid, N>=1 + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolynomialBuildEqDist()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalceqdist(a, b, f.c_ptr(), n, t, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Fast equidistant polynomial interpolation function with O(N) complexity + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on equidistant grid, N>=1 + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolynomialBuildEqDist()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = f.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalceqdist(a, b, f.c_ptr(), n, t, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (first kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (first kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb1()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalccheb1(a, b, f.c_ptr(), n, t, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (first kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (first kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb1()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = f.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalccheb1(a, b, f.c_ptr(), n, t, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (second kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (second kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb2()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalccheb2(a, b, f.c_ptr(), n, t, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (second kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (second kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb2()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = f.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::polynomialcalccheb2(a, b, f.c_ptr(), n, t, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif +#endif + +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void spline1dserialize(const spline1dinterpolant &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::spline1dalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::spline1dserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void spline1dserialize(const spline1dinterpolant &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::spline1dalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::spline1dserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void spline1dunserialize(const std::string &s_in, spline1dinterpolant &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::spline1dunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void spline1dunserialize(const std::istream &s_in, spline1dinterpolant &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::spline1dunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This subroutine builds linear spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildlinear(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds linear spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildlinear': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildlinear(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds linear spline interpolant. + +Buffered version of Spline1DBuildLinear() which reused memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinearbuf(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildlinearbuf(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds linear spline interpolant. + +Buffered version of Spline1DBuildLinear() which reused memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildlinearbuf(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildlinearbuf': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildlinearbuf(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds cubic spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + C - spline interpolant + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds cubic spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + C - spline interpolant + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildcubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns table of function derivatives d[] +(calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D - derivative values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dgriddiffcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns table of function derivatives d[] +(calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D - derivative values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiffcubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dgriddiffcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, d.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns tables of first and second +function derivatives d1[] and d2[] (calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D1 - S' values at X[] + D2 - S'' values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dgriddiff2cubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, d1.c_ptr(), d2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns tables of first and second +function derivatives d1[] and d2[] (calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D1 - S' values at X[] + D2 - S'' values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiff2cubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dgriddiff2cubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, d1.c_ptr(), d2.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DCalc() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DCalc() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + ae_int_t n2; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvcubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + n2 = x2.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] and derivatives d2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvdiffcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), d2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] and derivatives d2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + ae_int_t n2; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiffcubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + n2 = x2.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvdiffcubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), d2.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[], first and second derivatives d2[] and dd2[] +(calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + DD2 - second derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvdiff2cubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), d2.c_ptr(), dd2.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[], first and second derivatives d2[] and dd2[] +(calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + DD2 - second derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t boundltype; + double boundl; + ae_int_t boundrtype; + double boundr; + ae_int_t n2; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiff2cubic': looks like one of arguments has wrong size"); + n = x.length(); + boundltype = 0; + boundl = 0; + boundrtype = 0; + boundr = 0; + n2 = x2.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dconvdiff2cubic(x.c_ptr(), y.c_ptr(), n, boundltype, boundl, boundrtype, boundr, x2.c_ptr(), n2, y2.c_ptr(), d2.c_ptr(), dd2.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds Catmull-Rom spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundType - boundary condition type: + * -1 for periodic boundary condition + * 0 for parabolically terminated spline (default) + Tension - tension parameter: + * tension=0 corresponds to classic Catmull-Rom spline (default) + * 0=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundType - boundary condition type: + * -1 for periodic boundary condition + * 0 for parabolically terminated spline (default) + Tension - tension parameter: + * tension=0 corresponds to classic Catmull-Rom spline (default) + * 0=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildhermite(x.c_ptr(), y.c_ptr(), d.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + D - derivatives, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length()) || (x.length()!=d.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildhermite': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildhermite(x.c_ptr(), y.c_ptr(), d.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +Buffered version which reuses memory previously allocated in C as much as +possible. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermitebuf(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildhermitebuf(x.c_ptr(), y.c_ptr(), d.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +Buffered version which reuses memory previously allocated in C as much as +possible. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildhermitebuf(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length()) || (x.length()!=d.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildhermitebuf': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildhermitebuf(x.c_ptr(), y.c_ptr(), d.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds Akima spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildakima(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds Akima spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildakima': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildakima(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds modified Akima spline interpolant, with weights + + W[i]=|Delta[I]-Delta[I-1]| + +replaced by + + W[i]=|Delta[I]-Delta[I-1]|+0.5*|Delta[I]+Delta[I-1]| + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakimamod(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildakimamod(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds modified Akima spline interpolant, with weights + + W[i]=|Delta[I]-Delta[I-1]| + +replaced by + + W[i]=|Delta[I]-Delta[I-1]|+0.5*|Delta[I]+Delta[I-1]| + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildakimamod(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildakimamod': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildakimamod(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine calculates the value of the spline at the given point X. + +INPUT PARAMETERS: + C - spline interpolant + X - point + +Result: + S(x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dcalc(const spline1dinterpolant &c, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spline1dcalc(c.c_ptr(), x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine differentiates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +Result: + S - S(x) + DS - S'(x) + D2S - S''(x) + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1ddiff(c.c_ptr(), x, &s, &ds, &d2s, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine unpacks the spline into the coefficients table. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +OUTPUT PARAMETERS: + Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. + For I = 0...N-2: + Tbl[I,0] = X[i] + Tbl[I,1] = X[i+1] + Tbl[I,2] = C0 + Tbl[I,3] = C1 + Tbl[I,4] = C2 + Tbl[I,5] = C3 + On [x[i], x[i+1]] spline is equals to: + S(x) = C0 + C1*t + C2*t^2 + C3*t^3 + t = x-x[i] + +NOTE: + You can rebuild spline with Spline1DBuildHermite() function, which + accepts as inputs function values and derivatives at nodes, which are + easy to calculate when you have coefficients. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dunpack(c.c_ptr(), &n, tbl.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: x = A*t + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransx(spline1dinterpolant &c, const double a, const double b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dlintransx(c.c_ptr(), a, b, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x) = A*S(x) + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransy(spline1dinterpolant &c, const double a, const double b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dlintransy(c.c_ptr(), a, b, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine integrates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - right bound of the integration interval [a, x], + here 'a' denotes min(x[]) +Result: + integral(S(t)dt,a,x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dintegrate(const spline1dinterpolant &c, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spline1dintegrate(c.c_ptr(), x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Fitting by the smoothing (penalized) cubic spline. + +This function approximates N scattered points (some of X[] may be equal to +each other) by the cubic spline with M equidistant nodes spanning interval +[min(x),max(x)]. + +The problem is regularized by adding nonlinearity penalty to the usual +least squares penalty function: + + MERIT_FUNC = F_LS + F_NL + +where F_LS is a least squares error term, and F_NL is a nonlinearity +penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }. +Algorithm applies automatic renormalization of F_NL which makes penalty +term roughly invariant to scaling of X[] and changes in M. + +This function is a new edition of penalized regression spline fitting, +a fast and compact one which needs much less resources that its previous +version: just O(maxMN) memory and O(maxMN) time. + +NOTE: it is OK to run this function with both M<>N; say, it is + possible to process 100 points with 1000-node spline. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y are processed + * if not given, automatically determined from lengths + M - number of basis functions ( = number_of_nodes), M>=4. + LambdaNS - LambdaNS>=0, regularization constant passed by user. + It penalizes nonlinearity in the regression spline. + Possible values to start from are 0.00001, 0.1, 1 + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - Following fields are set: + * TerminationType set to 1 + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + + -- ALGLIB PROJECT -- + Copyright 10.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfit(x.c_ptr(), y.c_ptr(), n, m, lambdans, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fitting by the smoothing (penalized) cubic spline. + +This function approximates N scattered points (some of X[] may be equal to +each other) by the cubic spline with M equidistant nodes spanning interval +[min(x),max(x)]. + +The problem is regularized by adding nonlinearity penalty to the usual +least squares penalty function: + + MERIT_FUNC = F_LS + F_NL + +where F_LS is a least squares error term, and F_NL is a nonlinearity +penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }. +Algorithm applies automatic renormalization of F_NL which makes penalty +term roughly invariant to scaling of X[] and changes in M. + +This function is a new edition of penalized regression spline fitting, +a fast and compact one which needs much less resources that its previous +version: just O(maxMN) memory and O(maxMN) time. + +NOTE: it is OK to run this function with both M<>N; say, it is + possible to process 100 points with 1000-node spline. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y are processed + * if not given, automatically determined from lengths + M - number of basis functions ( = number_of_nodes), M>=4. + LambdaNS - LambdaNS>=0, regularization constant passed by user. + It penalizes nonlinearity in the regression spline. + Possible values to start from are 0.00001, 0.1, 1 + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - Following fields are set: + * TerminationType set to 1 + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + + -- ALGLIB PROJECT -- + Copyright 10.04.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfit': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfit(x.c_ptr(), y.c_ptr(), n, m, lambdans, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function builds monotone cubic Hermite interpolant. This interpolant +is monotonic in [x(0),x(n-1)] and is constant outside of this interval. + +In case y[] form non-monotonic sequence, interpolant is piecewise +monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will +monotonically grow at [0..2] and monotonically decrease at [2..4]. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. Subroutine automatically + sorts points, so caller may pass unsorted array. + Y - function values, array[0..N-1] + N - the number of points(N>=2). + +OUTPUT PARAMETERS: + C - spline interpolant. + + -- ALGLIB PROJECT -- + Copyright 21.06.2012 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildmonotone(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds monotone cubic Hermite interpolant. This interpolant +is monotonic in [x(0),x(n-1)] and is constant outside of this interval. + +In case y[] form non-monotonic sequence, interpolant is piecewise +monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will +monotonically grow at [0..2] and monotonically decrease at [2..4]. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. Subroutine automatically + sorts points, so caller may pass unsorted array. + Y - function values, array[0..N-1] + N - the number of points(N>=2). + +OUTPUT PARAMETERS: + C - spline interpolant. + + -- ALGLIB PROJECT -- + Copyright 21.06.2012 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildmonotone': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dbuildmonotone(x.c_ptr(), y.c_ptr(), n, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + + +/************************************************************************* +1-dimensional spline interpolant +*************************************************************************/ +_spline1dinterpolant_owner::_spline1dinterpolant_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline1dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant)); + alglib_impl::_spline1dinterpolant_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline1dinterpolant_owner::_spline1dinterpolant_owner(alglib_impl::spline1dinterpolant *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline1dinterpolant_owner::_spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline1dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant)); + alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline1dinterpolant_owner& _spline1dinterpolant_owner::operator=(const _spline1dinterpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline1dinterpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline1dinterpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant)); + alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline1dinterpolant_owner::~_spline1dinterpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline1dinterpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() const +{ + return p_struct; +} +spline1dinterpolant::spline1dinterpolant() : _spline1dinterpolant_owner() +{ +} + +spline1dinterpolant::spline1dinterpolant(alglib_impl::spline1dinterpolant *attach_to):_spline1dinterpolant_owner(attach_to) +{ +} + +spline1dinterpolant::spline1dinterpolant(const spline1dinterpolant &rhs):_spline1dinterpolant_owner(rhs) +{ +} + +spline1dinterpolant& spline1dinterpolant::operator=(const spline1dinterpolant &rhs) +{ + if( this==&rhs ) + return *this; + _spline1dinterpolant_owner::operator=(rhs); + return *this; +} + +spline1dinterpolant::~spline1dinterpolant() +{ +} + + + + +/************************************************************************* +Spline fitting report: + TerminationType completion code: + * >0 for success + * <0 for failure + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + +Fields below are filled by obsolete functions (Spline1DFitCubic, +Spline1DFitHermite). Modern fitting functions do NOT fill these fields: + TaskRCond reciprocal of task's condition number +*************************************************************************/ +_spline1dfitreport_owner::_spline1dfitreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline1dfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport)); + alglib_impl::_spline1dfitreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline1dfitreport_owner::_spline1dfitreport_owner(alglib_impl::spline1dfitreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline1dfitreport_owner::_spline1dfitreport_owner(const _spline1dfitreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline1dfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport)); + alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline1dfitreport_owner& _spline1dfitreport_owner::operator=(const _spline1dfitreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline1dfitreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline1dfitreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport)); + alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline1dfitreport_owner::~_spline1dfitreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline1dfitreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() const +{ + return p_struct; +} +spline1dfitreport::spline1dfitreport() : _spline1dfitreport_owner() ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +spline1dfitreport::spline1dfitreport(alglib_impl::spline1dfitreport *attach_to):_spline1dfitreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +spline1dfitreport::spline1dfitreport(const spline1dfitreport &rhs):_spline1dfitreport_owner(rhs) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +spline1dfitreport& spline1dfitreport::operator=(const spline1dfitreport &rhs) +{ + if( this==&rhs ) + return *this; + _spline1dfitreport_owner::operator=(rhs); + return *this; +} + +spline1dfitreport::~spline1dfitreport() +{ +} +#endif + +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine fits piecewise linear curve to points with Ramer-Douglas- +Peucker algorithm, which stops after generating specified number of linear +sections. + +IMPORTANT: +* it does NOT perform least-squares fitting; it builds curve, but this + curve does not minimize some least squares metric. See description of + RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. +* this function does NOT work with parametric curves (i.e. curves which + can be represented as {X(t),Y(t)}. It works with curves which can be + represented as Y(X). Thus, it is impossible to model figures like + circles with this functions. + If you want to work with parametric curves, you should use + ParametricRDPFixed() function provided by "Parametric" subpackage of + "Interpolation" package. + +INPUT PARAMETERS: + X - array of X-coordinates: + * at least N elements + * can be unordered (points are automatically sorted) + * this function may accept non-distinct X (see below for + more information on handling of such inputs) + Y - array of Y-coordinates: + * at least N elements + N - number of elements in X/Y + M - desired number of sections: + * at most M sections are generated by this function + * less than M sections can be generated if we have N0 + * if given, only leading N elements of X/Y are used + * if not given, automatically determined from sizes of X/Y + M - number of basis functions (= polynomial_degree + 1), M>=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code which is always + set to 1 (success) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialfit(x.c_ptr(), y.c_ptr(), n, m, p.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fitting by polynomials in barycentric form. This function provides simple +unterface for unconstrained unweighted fitting. See PolynomialFitWC() if +you need constrained fitting. + +The task is linear, thus the linear least squares solver is used. The +complexity of this computational scheme is O(N*M^2), mostly dominated by +the least squares solver + +SEE ALSO: + PolynomialFitWC() + +NOTES: + you can convert P from barycentric form to the power or Chebyshev + basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from + POLINT subpackage. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points, N>0 + * if given, only leading N elements of X/Y are used + * if not given, automatically determined from sizes of X/Y + M - number of basis functions (= polynomial_degree + 1), M>=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code which is always + set to 1 (success) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfit': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialfit(x.c_ptr(), y.c_ptr(), n, m, p.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted fitting by polynomials in barycentric form, with constraints on +function values or first derivatives. + +Small regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +SEE ALSO: + PolynomialFit() + +NOTES: + you can convert P from barycentric form to the power or Chebyshev + basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from + the POLINT subpackage. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + * if given, only leading N elements of X/Y/W are used + * if not given, automatically determined from sizes of X/Y/W + XC - points where polynomial values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that P(XC[i])=YC[i] + * DC[i]=1 means that P'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* even simple constraints can be inconsistent, see Wikipedia article on + this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the one special cases, however, we can guarantee consistency. This + case is: M>1 and constraints on the function values (NOT DERIVATIVES) + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialfitwc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, p.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted fitting by polynomials in barycentric form, with constraints on +function values or first derivatives. + +Small regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +SEE ALSO: + PolynomialFit() + +NOTES: + you can convert P from barycentric form to the power or Chebyshev + basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from + the POLINT subpackage. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + * if given, only leading N elements of X/Y/W are used + * if not given, automatically determined from sizes of X/Y/W + XC - points where polynomial values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that P(XC[i])=YC[i] + * DC[i]=1 means that P'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* even simple constraints can be inconsistent, see Wikipedia article on + this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the one special cases, however, we can guarantee consistency. This + case is: M>1 and constraints on the function values (NOT DERIVATIVES) + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t k; + if( (x.length()!=y.length()) || (x.length()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); + if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size"); + n = x.length(); + k = xc.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialfitwc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, p.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function calculates value of four-parameter logistic (4PL) model at +specified point X. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D- parameters of 4PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X + (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc4(const double x, const double a, const double b, const double c, const double d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::logisticcalc4(x, a, b, c, d, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates value of five-parameter logistic (5PL) model at +specified point X. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D, G- parameters of 5PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + * G>0, non-positive value results in exception + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for + zero X (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::logisticcalc5(x, a, b, c, d, g, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::logisticfit4(x.c_ptr(), y.c_ptr(), n, &a, &b, &c, &d, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user, with optional constraints on parameters A and D. 4PL model has +following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - with optional equality constraints + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::logisticfit4ec(x.c_ptr(), y.c_ptr(), n, cnstrleft, cnstrright, &a, &b, &c, &d, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - unconstrained + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::logisticfit5(x.c_ptr(), y.c_ptr(), n, &a, &b, &c, &d, &g, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user, subject to optional equality constraints on parameters A and D. +5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - with optional equality constraints + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. + +Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign +of B. Thus, negative B's are possible, and left constraint may constrain +parameter A (for positive B's) - or parameter D (for negative B's). +Similarly changes meaning of right constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::logisticfit5ec(x.c_ptr(), y.c_ptr(), n, cnstrleft, cnstrright, &a, &b, &c, &d, &g, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is "expert" 4PL/5PL fitting function, which can be used if you need +better control over fitting process than provided by LogisticFit4() or +LogisticFit5(). + +This function fits model of the form + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) + +or + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) + +Here: + * A, D - unconstrained + * B>=0 for 4PL, unconstrained for 5PL + * C>0 + * G>0 (if present) + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + Is4PL - whether 4PL or 5PL models are fitted + LambdaV - regularization coefficient, LambdaV>=0. + Set it to zero unless you know what you are doing. + EpsX - stopping condition (step size), EpsX>=0. + Zero value means that small step is automatically chosen. + See notes below for more information. + RsCnt - number of repeated restarts from random points. 4PL/5PL + models are prone to problem of bad local extrema. Utilizing + multiple random restarts allows us to improve algorithm + convergence. + RsCnt>=0. + Zero value means that function automatically choose small + amount of restarts (recommended). + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + G - parameter of 5PL model; for Is4PL=True, G=1 is returned. + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + +For 5PL model things are different. Unlike 4PL one, 5PL model is NOT +symmetric with respect to change in sign of B. Thus, negative B's are +possible, and left constraint may constrain parameter A (for positive B's) +- or parameter D (for negative B's). Similarly changes meaning of right +constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit45x(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, const bool is4pl, const double lambdav, const double epsx, const ae_int_t rscnt, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::logisticfit45x(x.c_ptr(), y.c_ptr(), n, cnstrleft, cnstrright, is4pl, lambdav, epsx, rscnt, &a, &b, &c, &d, &g, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weghted rational least squares fitting using Floater-Hormann rational +functions with optimal D chosen from [0,9], with constraints and +individual weights. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least WEIGHTED root +mean square error) is chosen. Task is linear, so linear least squares +solver is used. Complexity of this computational scheme is O(N*M^2) +(mostly dominated by the least squares solver). + +SEE ALSO +* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual + weights and constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + XC - points where function values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. Undefined for rep.terminationtype<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroutine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained barycentric interpolants: +* excessive constraints can be inconsistent. Floater-Hormann basis + functions aren't as flexible as splines (although they are very smooth). +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function VALUES at the interval + boundaries. Note that consustency of the constraints on the function + DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines + which are more flexible). +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricfitfloaterhormannwc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, b.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Rational least squares fitting using Floater-Hormann rational functions +with optimal D chosen from [0,9]. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least root mean +square error) is chosen. Task is linear, so linear least squares solver +is used. Complexity of this computational scheme is O(N*M^2) (mostly +dominated by the least squares solver). + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points, N>0. + M - number of basis functions ( = number_of_nodes), M>=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code, always set to 1 + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::barycentricfitfloaterhormann(x.c_ptr(), y.c_ptr(), n, m, b.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted fitting by cubic spline, with constraints on function values or +derivatives. + +Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are cubic splines with continuous second +derivatives and non-fixed first derivatives at interval ends. Small +regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4. + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function values AND/OR its + derivatives at the interval boundaries. +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitcubicwc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted fitting by cubic spline, with constraints on function values or +derivatives. + +Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are cubic splines with continuous second +derivatives and non-fixed first derivatives at interval ends. Small +regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4. + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function values AND/OR its + derivatives at the interval boundaries. +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t k; + if( (x.length()!=y.length()) || (x.length()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); + if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size"); + n = x.length(); + k = xc.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitcubicwc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted fitting by Hermite spline, with constraints on function values +or first derivatives. + +Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are Hermite splines. Small regularizing +term is used when solving constrained tasks (to improve stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4, + M IS EVEN! + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +IMPORTANT: + this subroitine supports only even M's + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the several special cases, however, we can guarantee consistency. +* one of this cases is M>=4 and constraints on the function value + (AND/OR its derivative) at the interval boundaries. +* another special case is M>=4 and ONE constraint on the function value + (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermitewc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted fitting by Hermite spline, with constraints on function values +or first derivatives. + +Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are Hermite splines. Small regularizing +term is used when solving constrained tasks (to improve stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4, + M IS EVEN! + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +IMPORTANT: + this subroitine supports only even M's + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the several special cases, however, we can guarantee consistency. +* one of this cases is M>=4 and constraints on the function value + (AND/OR its derivative) at the interval boundaries. +* another special case is M>=4 and ONE constraint on the function value + (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t k; + if( (x.length()!=y.length()) || (x.length()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); + if( (xc.length()!=yc.length()) || (xc.length()!=dc.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size"); + n = x.length(); + k = xc.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermitewc(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, xc.c_ptr(), yc.c_ptr(), dc.c_ptr(), k, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermitedeprecated(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermitedeprecated(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfithermitedeprecated(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitedeprecated': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermitedeprecated(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType always set to 1 (success) + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearw(y.c_ptr(), w.c_ptr(), fmatrix.c_ptr(), n, m, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType always set to 1 (success) + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size"); + n = y.length(); + m = fmatrix.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearw(y.c_ptr(), w.c_ptr(), fmatrix.c_ptr(), n, m, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted constained linear least squares fitting. + +This is variation of LSFitLinearW(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearwc(y.c_ptr(), w.c_ptr(), fmatrix.c_ptr(), cmatrix.c_ptr(), n, m, k, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted constained linear least squares fitting. + +This is variation of LSFitLinearW(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); + if( (fmatrix.cols()!=cmatrix.cols()-1)) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size"); + n = y.length(); + m = fmatrix.cols(); + k = cmatrix.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearwc(y.c_ptr(), w.c_ptr(), fmatrix.c_ptr(), cmatrix.c_ptr(), n, m, k, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code, always set to + 1 which denotes success + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinear(y.c_ptr(), fmatrix.c_ptr(), n, m, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code, always set to + 1 which denotes success + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (y.length()!=fmatrix.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinear': looks like one of arguments has wrong size"); + n = y.length(); + m = fmatrix.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinear(y.c_ptr(), fmatrix.c_ptr(), n, m, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Constained linear least squares fitting. + +This is variation of LSFitLinear(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearc(y.c_ptr(), fmatrix.c_ptr(), cmatrix.c_ptr(), n, m, k, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Constained linear least squares fitting. + +This is variation of LSFitLinear(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (y.length()!=fmatrix.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); + if( (fmatrix.cols()!=cmatrix.cols()-1)) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size"); + n = y.length(); + m = fmatrix.cols(); + k = cmatrix.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitlinearc(y.c_ptr(), fmatrix.c_ptr(), cmatrix.c_ptr(), n, m, k, c.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatewf(x.c_ptr(), y.c_ptr(), w.c_ptr(), c.c_ptr(), n, m, k, diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (x.rows()!=y.length()) || (x.rows()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewf': looks like one of arguments has wrong size"); + n = x.rows(); + m = x.cols(); + k = c.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatewf(x.c_ptr(), y.c_ptr(), w.c_ptr(), c.c_ptr(), n, m, k, diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatef(x.c_ptr(), y.c_ptr(), c.c_ptr(), n, m, k, diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (x.rows()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatef': looks like one of arguments has wrong size"); + n = x.rows(); + m = x.cols(); + k = c.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatef(x.c_ptr(), y.c_ptr(), c.c_ptr(), n, m, k, diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Weighted nonlinear least squares fitting using gradient only. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also: + LSFitResults + LSFitCreateFG (fitting without weights) + LSFitCreateWFGH (fitting using Hessian) + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatewfg(x.c_ptr(), y.c_ptr(), w.c_ptr(), c.c_ptr(), n, m, k, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Weighted nonlinear least squares fitting using gradient only. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also: + LSFitResults + LSFitCreateFG (fitting without weights) + LSFitCreateWFGH (fitting using Hessian) + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (x.rows()!=y.length()) || (x.rows()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewfg': looks like one of arguments has wrong size"); + n = x.rows(); + m = x.cols(); + k = c.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatewfg(x.c_ptr(), y.c_ptr(), w.c_ptr(), c.c_ptr(), n, m, k, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Nonlinear least squares fitting using gradient only, without individual +weights. + +Nonlinear task min(F(c)) is solved, where + + F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatefg(x.c_ptr(), y.c_ptr(), c.c_ptr(), n, m, k, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Nonlinear least squares fitting using gradient only, without individual +weights. + +Nonlinear task min(F(c)) is solved, where + + F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + ae_int_t k; + if( (x.rows()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatefg': looks like one of arguments has wrong size"); + n = x.rows(); + m = x.cols(); + k = c.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitcreatefg(x.c_ptr(), y.c_ptr(), c.c_ptr(), n, m, k, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LSFIT solver compares squared errors f[1] at the +trial point with the value at the current point f[0]. Only steps that +decrease f() are accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnonmonotonicsteps(lsfitstate &state, const ae_int_t cnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetnonmonotonicsteps(state.c_ptr(), cnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers configured to use numerical differentiation; +in other cases it has no effect. + +INPUT PARAMETERS: + State - optimizer + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnumdiff(lsfitstate &state, const ae_int_t formulatype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetnumdiff(state.c_ptr(), formulatype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Stopping conditions for nonlinear least squares fitting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by LSFitSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +NOTE + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (according to the scheme used by MINLM unit). + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetcond(lsfitstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetcond(state.c_ptr(), epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetstpmax(lsfitstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +When reports are needed, State.C (current parameters) and State.F (current +value of fitting function) are reported. + + + -- ALGLIB -- + Copyright 15.08.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetxrep(lsfitstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for underlying optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetscale(lsfitstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets boundary constraints for underlying optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[K]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[K]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unlike other constrained optimization algorithms, this solver has +following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetbc(lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for underlying optimizer + +Linear constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetLC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with lsfitsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +NOTE: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 29.04.2017 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetlc(lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for underlying optimizer + +Linear constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetLC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with lsfitsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +NOTE: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 29.04.2017 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void lsfitsetlc(lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool lsfititeration(lsfitstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void lsfitfit(lsfitstate &state, + void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &c, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::lsfitstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "lsfit"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state); +callbacks.func_p = func; + + alglib_impl::lsfitsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'lsfitfit()' (grad is NULL)", &_alglib_env_state); +callbacks.func_p = func; +callbacks.grad_p = grad; + + alglib_impl::lsfitsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidx0 activates verification + + -- ALGLIB -- + Copyright 15.06.2012 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetgradientcheck(lsfitstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lsfitsetgradientcheck(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Polynomial fitting report: + TerminationType completion code: >0 for success, <0 for failure + TaskRCond reciprocal of task's condition number + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error +*************************************************************************/ +_polynomialfitreport_owner::_polynomialfitreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_polynomialfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport)); + alglib_impl::_polynomialfitreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_polynomialfitreport_owner::_polynomialfitreport_owner(alglib_impl::polynomialfitreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_polynomialfitreport_owner::_polynomialfitreport_owner(const _polynomialfitreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_polynomialfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport)); + alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_polynomialfitreport_owner& _polynomialfitreport_owner::operator=(const _polynomialfitreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: polynomialfitreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_polynomialfitreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport)); + alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_polynomialfitreport_owner::~_polynomialfitreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_polynomialfitreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() const +{ + return p_struct; +} +polynomialfitreport::polynomialfitreport() : _polynomialfitreport_owner() ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +polynomialfitreport::polynomialfitreport(alglib_impl::polynomialfitreport *attach_to):_polynomialfitreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +polynomialfitreport::polynomialfitreport(const polynomialfitreport &rhs):_polynomialfitreport_owner(rhs) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +polynomialfitreport& polynomialfitreport::operator=(const polynomialfitreport &rhs) +{ + if( this==&rhs ) + return *this; + _polynomialfitreport_owner::operator=(rhs); + return *this; +} + +polynomialfitreport::~polynomialfitreport() +{ +} + + + + +/************************************************************************* +Barycentric fitting report: + TerminationType completion code: >0 for success, <0 for failure + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + TaskRCond reciprocal of task's condition number +*************************************************************************/ +_barycentricfitreport_owner::_barycentricfitreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_barycentricfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport)); + alglib_impl::_barycentricfitreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_barycentricfitreport_owner::_barycentricfitreport_owner(alglib_impl::barycentricfitreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_barycentricfitreport_owner::_barycentricfitreport_owner(const _barycentricfitreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_barycentricfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport)); + alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_barycentricfitreport_owner& _barycentricfitreport_owner::operator=(const _barycentricfitreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: barycentricfitreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_barycentricfitreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport)); + alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_barycentricfitreport_owner::~_barycentricfitreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_barycentricfitreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() const +{ + return p_struct; +} +barycentricfitreport::barycentricfitreport() : _barycentricfitreport_owner() ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +barycentricfitreport::barycentricfitreport(alglib_impl::barycentricfitreport *attach_to):_barycentricfitreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +barycentricfitreport::barycentricfitreport(const barycentricfitreport &rhs):_barycentricfitreport_owner(rhs) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror) +{ +} + +barycentricfitreport& barycentricfitreport::operator=(const barycentricfitreport &rhs) +{ + if( this==&rhs ) + return *this; + _barycentricfitreport_owner::operator=(rhs); + return *this; +} + +barycentricfitreport::~barycentricfitreport() +{ +} + + + + +/************************************************************************* +Least squares fitting report. This structure contains informational fields +which are set by fitting functions provided by this unit. + +Different functions initialize different sets of fields, so you should +read documentation on specific function you used in order to know which +fields are initialized. + + TerminationType filled by all solvers: + * positive values, usually 1, denote success + * negative values denote various failure scenarios + + TaskRCond reciprocal of task's condition number + IterationsCount number of internal iterations + + VarIdx if user-supplied gradient contains errors which were + detected by nonlinear fitter, this field is set to + index of the first component of gradient which is + suspected to be spoiled by bugs. + + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + + WRMSError weighted RMS error + + CovPar covariance matrix for parameters, filled by some solvers + ErrPar vector of errors in parameters, filled by some solvers + ErrCurve vector of fit errors - variability of the best-fit + curve, filled by some solvers. + Noise vector of per-point noise estimates, filled by + some solvers. + R2 coefficient of determination (non-weighted, non-adjusted), + filled by some solvers. +*************************************************************************/ +_lsfitreport_owner::_lsfitreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lsfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lsfitreport)); + alglib_impl::_lsfitreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lsfitreport_owner::_lsfitreport_owner(alglib_impl::lsfitreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lsfitreport_owner::_lsfitreport_owner(const _lsfitreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lsfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lsfitreport)); + alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lsfitreport_owner& _lsfitreport_owner::operator=(const _lsfitreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lsfitreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lsfitreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lsfitreport)); + alglib_impl::_lsfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lsfitreport_owner::~_lsfitreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lsfitreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() const +{ + return p_struct; +} +lsfitreport::lsfitreport() : _lsfitreport_owner() ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) +{ +} + +lsfitreport::lsfitreport(alglib_impl::lsfitreport *attach_to):_lsfitreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) +{ +} + +lsfitreport::lsfitreport(const lsfitreport &rhs):_lsfitreport_owner(rhs) ,terminationtype(p_struct->terminationtype),taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2) +{ +} + +lsfitreport& lsfitreport::operator=(const lsfitreport &rhs) +{ + if( this==&rhs ) + return *this; + _lsfitreport_owner::operator=(rhs); + return *this; +} + +lsfitreport::~lsfitreport() +{ +} + + + + +/************************************************************************* +Nonlinear fitter. + +You should use ALGLIB functions to work with fitter. +Never try to access its fields directly! +*************************************************************************/ +_lsfitstate_owner::_lsfitstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lsfitstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lsfitstate)); + alglib_impl::_lsfitstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lsfitstate_owner::_lsfitstate_owner(alglib_impl::lsfitstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lsfitstate_owner::_lsfitstate_owner(const _lsfitstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lsfitstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lsfitstate)); + alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lsfitstate_owner& _lsfitstate_owner::operator=(const _lsfitstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lsfitstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lsfitstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lsfitstate)); + alglib_impl::_lsfitstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lsfitstate_owner::~_lsfitstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lsfitstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() const +{ + return p_struct; +} +lsfitstate::lsfitstate() : _lsfitstate_owner() +{ +} + +lsfitstate::lsfitstate(alglib_impl::lsfitstate *attach_to):_lsfitstate_owner(attach_to) +{ +} + +lsfitstate::lsfitstate(const lsfitstate &rhs):_lsfitstate_owner(rhs) +{ +} + +lsfitstate& lsfitstate::operator=(const lsfitstate &rhs) +{ + if( this==&rhs ) + return *this; + _lsfitstate_owner::operator=(rhs); + return *this; +} + +lsfitstate::~lsfitstate() +{ +} +#endif + +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Fits least squares (LS) circle (or NX-dimensional sphere) to data (a set +of points in NX-dimensional space). + +Least squares circle minimizes sum of squared deviations between distances +from points to the center and some "candidate" radius, which is also +fitted to the data. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + R - radius + + -- ALGLIB -- + Copyright 07.05.2018 by Bochkanov Sergey +*************************************************************************/ +void fitspherels(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fitspherels(xy.c_ptr(), npoints, nx, cx.c_ptr(), &r, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to data +(a set of points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RHi - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fitspheremc(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremi(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fitspheremi(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rlo, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fits minimum zone circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius of inscribed circle + RHo - radius of circumscribed circle + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fitspheremz(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rlo, &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Fitting minimum circumscribed, maximum inscribed or minimum zone circles +(or NX-dimensional spheres) to data (a set of points in NX-dimensional +space). + +This is expert function which allows to tweak many parameters of +underlying nonlinear solver: +* stopping criteria for inner iterations +* number of outer iterations + +You may tweak all these parameters or only some of them, leaving other +ones at their default state - just specify zero value, and solver will +fill it with appropriate default one. + +These comments also include some discussion of approach used to handle +such unusual fitting problem, its stability, drawbacks of alternative +methods, and convergence properties. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + ProblemType-used to encode problem type: + * 0 for least squares circle + * 1 for minimum circumscribed circle/sphere fitting (MC) + * 2 for maximum inscribed circle/sphere fitting (MI) + * 3 for minimum zone circle fitting (difference between + Rhi and Rlo is minimized), denoted as MZ + EpsX - stopping condition for NLC optimizer: + * must be non-negative + * use 0 to choose default value (1.0E-12 is used by default) + * you may specify larger values, up to 1.0E-6, if you want + to speed-up solver; NLC solver performs several + preconditioned outer iterations, so final result + typically has precision much better than EpsX. + AULIts - number of outer iterations performed by NLC optimizer: + * must be non-negative + * use 0 to choose default value (20 is used by default) + * you may specify values smaller than 20 if you want to + speed up solver; 10 often results in good combination of + precision and speed; sometimes you may get good results + with just 6 outer iterations. + Ignored for ProblemType=0. + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius: + * for ProblemType=2,3, radius of the inscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=1 - zero + RHo - radius: + * for ProblemType=1,3, radius of the circumscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=2 - zero + +NOTE: ON THE UNIQUENESS OF SOLUTIONS + +ALGLIB provides solution to several related circle fitting problems: MC +(minimum circumscribed), MI (maximum inscribed) and MZ (minimum zone) +fitting, LS (least squares) fitting. + +It is important to note that among these problems only MC and LS are +convex and have unique solution independently from starting point. + +As for MI, it may (or may not, depending on dataset properties) have +multiple solutions, and it always has one degenerate solution C=infinity +which corresponds to infinitely large radius. Thus, there are no guarantees +that solution to MI returned by this solver will be the best one (and no +one can provide you with such guarantee because problem is NP-hard). The +only guarantee you have is that this solution is locally optimal, i.e. it +can not be improved by infinitesimally small tweaks in the parameters. + +It is also possible to "run away" to infinity when started from bad +initial point located outside of point cloud (or when point cloud does not +span entire circumference/surface of the sphere). + +Finally, MZ (minimum zone circle) stands somewhere between MC and MI in +stability. It is somewhat regularized by "circumscribed" term of the merit +function; however, solutions to MZ may be non-unique, and in some unlucky +cases it is also possible to "run away to infinity". + + +NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH + +The problem formulation for MC (minimum circumscribed circle; for the +sake of simplicity we omit MZ and MI here) is: + + [ [ ]2 ] + min [ max [ XY[i]-C ] ] + C [ i [ ] ] + +i.e. it is unconstrained nonsmooth optimization problem of finding "best" +central point, with radius R being unambiguously determined from C. In +order to move away from non-smoothness we use following reformulation: + + [ ] [ ]2 + min [ R ] subject to R>=0, [ XY[i]-C ] <= R^2 + C,R [ ] [ ] + +i.e. it becomes smooth quadratically constrained optimization problem with +linear target function. Such problem statement is 100% equivalent to the +original nonsmooth one, but much easier to approach. We solve it with +MinNLC solver provided by ALGLIB. + + +NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH + +ALGLIB has nonlinearly constrained solver which proved to be stable on +such problems. However, some authors proposed to linearize constraints in +the vicinity of current approximation (Ci,Ri) and to get next approximate +solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously, +LP problems are easier than nonlinearly constrained ones. + +Indeed, such approach to MC/MI/MZ resulted in ~10-20x increase in +performance (when compared with NLC solver). However, it turned out that +in some cases linearized model fails to predict correct direction for next +step and tells us that we converged to solution even when we are still 2-4 +digits of precision away from it. + +It is important that it is not failure of LP solver - it is failure of the +linear model; even when solved exactly, it fails to handle subtle +nonlinearities which arise near the solution. We validated it by comparing +results returned by ALGLIB linear solver with that of MATLAB. + +In our experiments with linearization: +* MC failed most often, at both realistic and synthetic datasets +* MI sometimes failed, but sometimes succeeded +* MZ often succeeded; our guess is that presence of two independent sets + of constraints (one set for Rlo and another one for Rhi) and two terms + in the target function (Rlo and Rhi) regularizes task, so when linear + model fails to handle nonlinearities from Rlo, it uses Rhi as a hint + (and vice versa). + +Because linearization approach failed to achieve stable results, we do not +include it in ALGLIB. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fitspherex(xy.c_ptr(), npoints, nx, problemtype, epsx, aulits, cx.c_ptr(), &rlo, &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function builds non-periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + Order of points is important! + N - points count, N>=5 for Akima splines, N>=2 for other types of + splines. + ST - spline type: + * 0 Akima spline + * 1 parabolically terminated Catmull-Rom spline (Tension=0) + * 2 parabolically terminated cubic spline + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2build(xy.c_ptr(), n, st, pt, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds non-periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3build(xy.c_ptr(), n, st, pt, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then +back to (X[0],Y[0]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + XY[N-1,0:1] must be different from XY[0,0:1]. + Order of points is important! + N - points count, N>=3 for other types of splines. + ST - spline type: + * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions + * 2 cubic spline with cyclic boundary conditions + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). +* last point of sequence is NOT equal to the first point. You shouldn't + make curve "explicitly periodic" by making them equal. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2buildperiodic(xy.c_ptr(), n, st, pt, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) +and then back to (X[0],Y[0],Z[0]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3buildperiodic(xy.c_ptr(), n, st, pt, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns vector of parameter values correspoding to points. + +I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we +have + (X[0],Y[0]) = PSpline2Calc(P,U[0]), + (X[1],Y[1]) = PSpline2Calc(P,U[1]), + (X[2],Y[2]) = PSpline2Calc(P,U[2]), + ... + +INPUT PARAMETERS: + P - parametric spline interpolant + +OUTPUT PARAMETERS: + N - array size + T - array[0..N-1] + + +NOTES: +* for non-periodic splines U[0]=0, U[0]1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2calc(p.c_ptr(), t, &x, &y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates the value of the parametric spline for a given +value of parameter T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + Z - Z-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3calc(p.c_ptr(), t, &x, &y, &z, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + +NOTE: + X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2tangent(p.c_ptr(), t, &x, &y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + Z - Z-component of tangent vector (normalized) + +NOTE: + X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3tangent(p.c_ptr(), t, &x, &y, &z, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2diff(p.c_ptr(), t, &x, &dx, &y, &dy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + Z - Z-value + DZ - Z-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3diff(p.c_ptr(), t, &x, &dx, &y, &dy, &z, &dz, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline2diff2(p.c_ptr(), t, &x, &dx, &d2x, &y, &dy, &d2y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + Z - Z-value + DZ - derivative + D2Z - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pspline3diff2(p.c_ptr(), t, &x, &dx, &d2x, &y, &dy, &d2y, &z, &dz, &d2z, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates arc length, i.e. length of curve between t=a +and t=b. + +INPUT PARAMETERS: + P - parametric spline interpolant + A,B - parameter values corresponding to arc ends: + * B>A will result in positive length returned + * BA will result in positive length returned + * B(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_pspline2interpolant_owner& _pspline2interpolant_owner::operator=(const _pspline2interpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: pspline2interpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_pspline2interpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant)); + alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_pspline2interpolant_owner::~_pspline2interpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_pspline2interpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() const +{ + return p_struct; +} +pspline2interpolant::pspline2interpolant() : _pspline2interpolant_owner() +{ +} + +pspline2interpolant::pspline2interpolant(alglib_impl::pspline2interpolant *attach_to):_pspline2interpolant_owner(attach_to) +{ +} + +pspline2interpolant::pspline2interpolant(const pspline2interpolant &rhs):_pspline2interpolant_owner(rhs) +{ +} + +pspline2interpolant& pspline2interpolant::operator=(const pspline2interpolant &rhs) +{ + if( this==&rhs ) + return *this; + _pspline2interpolant_owner::operator=(rhs); + return *this; +} + +pspline2interpolant::~pspline2interpolant() +{ +} + + + + +/************************************************************************* +Parametric spline inteprolant: 3-dimensional curve. + +You should not try to access its members directly - use PSpline3XXXXXXXX() +functions instead. +*************************************************************************/ +_pspline3interpolant_owner::_pspline3interpolant_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_pspline3interpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant)); + alglib_impl::_pspline3interpolant_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_pspline3interpolant_owner::_pspline3interpolant_owner(alglib_impl::pspline3interpolant *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_pspline3interpolant_owner::_pspline3interpolant_owner(const _pspline3interpolant_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_pspline3interpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant)); + alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_pspline3interpolant_owner& _pspline3interpolant_owner::operator=(const _pspline3interpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: pspline3interpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_pspline3interpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant)); + alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_pspline3interpolant_owner::~_pspline3interpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_pspline3interpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() const +{ + return p_struct; +} +pspline3interpolant::pspline3interpolant() : _pspline3interpolant_owner() +{ +} + +pspline3interpolant::pspline3interpolant(alglib_impl::pspline3interpolant *attach_to):_pspline3interpolant_owner(attach_to) +{ +} + +pspline3interpolant::pspline3interpolant(const pspline3interpolant &rhs):_pspline3interpolant_owner(rhs) +{ +} + +pspline3interpolant& pspline3interpolant::operator=(const pspline3interpolant &rhs) +{ + if( this==&rhs ) + return *this; + _pspline3interpolant_owner::operator=(rhs); + return *this; +} + +pspline3interpolant::~pspline3interpolant() +{ +} +#endif + +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void spline2dserialize(const spline2dinterpolant &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void spline2dserialize(const spline2dinterpolant &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void spline2dunserialize(const std::string &s_in, spline2dinterpolant &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void spline2dunserialize(const std::istream &s_in, spline2dinterpolant &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This subroutine calculates the value of the bilinear or bicubic spline at +the given point X. + +Input parameters: + C - 2D spline object. + Built by spline2dbuildbilinearv or spline2dbuildbicubicv. + X, Y- point + +Result: + S(x,y) + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +double spline2dcalc(const spline2dinterpolant &c, const double x, const double y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spline2dcalc(c.c_ptr(), x, y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine calculates the value of a bilinear or bicubic spline and +its derivatives. + +Use Spline2DDiff2() if you need second derivatives Sxx and Syy. + +Input parameters: + C - spline interpolant. + X, Y- point + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2ddiff(c.c_ptr(), x, y, &f, &fx, &fy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates the value of a bilinear or bicubic spline and +its second derivatives. + +Input parameters: + C - spline interpolant. + X, Y- point + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + FXX - d2S(x,y)/dXdX + FXY - d2S(x,y)/dXdY + FYY - d2S(x,y)/dYdY + + -- ALGLIB PROJECT -- + Copyright 17.04.2023 by Bochkanov Sergey. + + The second derivatives code was contributed by Horst Greiner under + public domain terms. +*************************************************************************/ +void spline2ddiff2(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxx, double &fxy, double &fyy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2ddiff2(c.c_ptr(), x, y, &f, &fx, &fy, &fxx, &fxy, &fyy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y). + +If you need just some specific component of vector-valued spline, you can +use spline2dcalcvi() function. + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + F - output buffer, possibly preallocated array. In case array size + is large enough to store result, it is not reallocated. Array + which is too short will be reallocated + +OUTPUT PARAMETERS: + F - array[D] (or larger) which stores function values + + -- ALGLIB PROJECT -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dcalcvbuf(c.c_ptr(), x, y, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates specific component of vector-valued bilinear or +bicubic spline at the given point (X,Y). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + I - component index, in [0,D). An exception is generated for out + of range values. + +RESULT: + value of I-th component + + -- ALGLIB PROJECT -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +double spline2dcalcvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spline2dcalcvi(c.c_ptr(), x, y, i, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + +OUTPUT PARAMETERS: + F - array[D] which stores function values. F is out-parameter and + it is reallocated after call to this function. In case you + want to reuse previously allocated F, you may use + Spline2DCalcVBuf(), which reallocates F only when it is too + small. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dcalcv(c.c_ptr(), x, y, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates the value and the derivatives of I-th component +of a vector-valued bilinear or bicubic spline. + +Input parameters: + C - spline interpolant. + X, Y- point + I - component index, in [0,D) + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2ddiffvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, double &f, double &fx, double &fy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2ddiffvi(c.c_ptr(), x, y, i, &f, &fx, &fy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates the value and the derivatives of I-th component +of a vector-valued bilinear or bicubic spline. + +Input parameters: + C - spline interpolant. + X, Y- point + I - component index, in [0,D) + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + FXX - d2S(x,y)/dXdX + FXY - d2S(x,y)/dXdY + FYY - d2S(x,y)/dYdY + + -- ALGLIB PROJECT -- + Copyright 17.04.2023 by Bochkanov Sergey. + + The second derivatives code was contributed by Horst Greiner under + public domain terms. +*************************************************************************/ +void spline2ddiff2vi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, double &f, double &fx, double &fy, double &fxx, double &fxy, double &fyy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2ddiff2vi(c.c_ptr(), x, y, i, &f, &fx, &fy, &fxx, &fxy, &fyy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +Input parameters: + C - spline interpolant + AX, BX - transformation coefficients: x = A*t + B + AY, BY - transformation coefficients: y = A*u + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dlintransxy(spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dlintransxy(c.c_ptr(), ax, bx, ay, by, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +Input parameters: + C - spline interpolant. + A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B + +Output parameters: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dlintransf(spline2dinterpolant &c, const double a, const double b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dlintransf(c.c_ptr(), a, b, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine makes the copy of the spline model. + +Input parameters: + C - spline interpolant + +Output parameters: + CC - spline copy + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dcopy(c.c_ptr(), cc.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Bicubic spline resampling + +Input parameters: + A - function values at the old grid, + array[0..OldHeight-1, 0..OldWidth-1] + OldHeight - old grid height, OldHeight>1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 15 May, 2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dresamplebicubic(a.c_ptr(), oldheight, oldwidth, b.c_ptr(), newheight, newwidth, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Bilinear spline resampling + +Input parameters: + A - function values at the old grid, + array[0..OldHeight-1, 0..OldWidth-1] + OldHeight - old grid height, OldHeight>1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 09.07.2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dresamplebilinear(a.c_ptr(), oldheight, oldwidth, b.c_ptr(), newheight, newwidth, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbilinearv(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +Buffered version of Spline2DBuildBilinearV() which reuses memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbilinearvbuf(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissing(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbilinearmissing(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), missing.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBilinearMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissingbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbilinearmissingbuf(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), missing.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using parabolically +terminated end conditions. + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubicv(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using parabolically +terminated end conditions. + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline2dbuildbicubicv(const real_1d_array &x, const real_1d_array &y, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.length(); + m = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubicv(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using clamped +boundary conditions: +* spline values at the grid nodes are specified +* boundary conditions for first, second derivatives or for parabolic + termination at four boundaries (bottom y=min(Y[]), top y=max(Y[]), left + x=min(X[]), right x=max(X[])) are specified +* mixed derivatives at corners are specified +* it is possible to have different boundary conditions for different + boundaries (first derivatives along one boundary, second derivatives + along other one, parabolic termination along the rest and so on) +* it is possible to have either a scalar (D=1) or a vector-valued spline + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + BndBtm - array[D*N], boundary conditions at the bottom boundary + of the interpolation area (corresponds to y=min(Y[]): + * if BndTypeBtm=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndBtm is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeBtm=1, first derivatives are given + * if BndTypeBtm=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=minY, + subsequent D entries store derivatives at x=X[1], + y=minY and so on + BndTop - array[D*N], boundary conditions at the top boundary + of the interpolation area (corresponds to y=max(Y[]): + * if BndTypeTop=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndTop is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeTop=1, first derivatives are given + * if BndTypeTop=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=maxY, + subsequent D entries store derivatives at x=X[1], + y=maxY and so on + BndLft - array[D*M], boundary conditions at the left boundary + of the interpolation area (corresponds to x=min(X[]): + * if BndTypeLft=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndLft is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeLft=1, first derivatives are given + * if BndTypeLft=2, second derivatives are given + * first D entries store derivatives at x=minX, y=Y[0], + subsequent D entries store derivatives at x=minX, + y=Y[1] and so on + BndRgt - array[D*M], boundary conditions at the right boundary + of the interpolation area (corresponds to x=max(X[]): + * if BndTypeRgt=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndRgt is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeRgt=1, first derivatives are given + * if BndTypeRgt=2, second derivatives are given + * first D entries store derivatives at x=maxX, y=Y[0], + subsequent D entries store derivatives at x=maxX, + y=Y[1] and so on + MixedD - array[D*4], mixed derivatives at 4 corners of the + interpolation area: + * derivative order depends on the order of boundary + conditions (bottom/top and left/right) intersecting + at that corner: + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=1 user has + to provide d2S/dXdY + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=2 user has + to provide d4S/(dX^2*dY^2) + ** for BndType(Btm|Top)=1, BndType(Lft|Rgt)=2 user + has to provide d3S/(dX^2*dY) + ** for BndType(Btm|Top)=2, BndType(Lft|Rgt)=1 user + has to provide d3S/(dX*dY^2) + ** if one of the intersecting bounds has 'parabolic + termination' condition, this specific mixed + derivative is not used + * first D entries store derivatives at the bottom left + corner x=min(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the bottom + right corner x=max(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the top + left corner x=min(X[]), y=max(Y[]) + * subsequent D entries store derivatives at the top + right corner x=max(X[]), y=max(Y[]) + * if all bounds have 'parabolic termination' condition, + MixedD[] is not referenced at all and can be + unallocated. + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are + stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildclampedv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &bndbtm, const ae_int_t bndtypebtm, const real_1d_array &bndtop, const ae_int_t bndtypetop, const real_1d_array &bndlft, const ae_int_t bndtypelft, const real_1d_array &bndrgt, const ae_int_t bndtypergt, const real_1d_array &mixedd, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildclampedv(x.c_ptr(), n, y.c_ptr(), m, bndbtm.c_ptr(), bndtypebtm, bndtop.c_ptr(), bndtypetop, bndlft.c_ptr(), bndtypelft, bndrgt.c_ptr(), bndtypergt, mixedd.c_ptr(), f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using clamped +boundary conditions: +* spline values at the grid nodes are specified +* boundary conditions for first, second derivatives or for parabolic + termination at four boundaries (bottom y=min(Y[]), top y=max(Y[]), left + x=min(X[]), right x=max(X[])) are specified +* mixed derivatives at corners are specified +* it is possible to have different boundary conditions for different + boundaries (first derivatives along one boundary, second derivatives + along other one, parabolic termination along the rest and so on) +* it is possible to have either a scalar (D=1) or a vector-valued spline + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + BndBtm - array[D*N], boundary conditions at the bottom boundary + of the interpolation area (corresponds to y=min(Y[]): + * if BndTypeBtm=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndBtm is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeBtm=1, first derivatives are given + * if BndTypeBtm=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=minY, + subsequent D entries store derivatives at x=X[1], + y=minY and so on + BndTop - array[D*N], boundary conditions at the top boundary + of the interpolation area (corresponds to y=max(Y[]): + * if BndTypeTop=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndTop is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeTop=1, first derivatives are given + * if BndTypeTop=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=maxY, + subsequent D entries store derivatives at x=X[1], + y=maxY and so on + BndLft - array[D*M], boundary conditions at the left boundary + of the interpolation area (corresponds to x=min(X[]): + * if BndTypeLft=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndLft is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeLft=1, first derivatives are given + * if BndTypeLft=2, second derivatives are given + * first D entries store derivatives at x=minX, y=Y[0], + subsequent D entries store derivatives at x=minX, + y=Y[1] and so on + BndRgt - array[D*M], boundary conditions at the right boundary + of the interpolation area (corresponds to x=max(X[]): + * if BndTypeRgt=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndRgt is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeRgt=1, first derivatives are given + * if BndTypeRgt=2, second derivatives are given + * first D entries store derivatives at x=maxX, y=Y[0], + subsequent D entries store derivatives at x=maxX, + y=Y[1] and so on + MixedD - array[D*4], mixed derivatives at 4 corners of the + interpolation area: + * derivative order depends on the order of boundary + conditions (bottom/top and left/right) intersecting + at that corner: + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=1 user has + to provide d2S/dXdY + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=2 user has + to provide d4S/(dX^2*dY^2) + ** for BndType(Btm|Top)=1, BndType(Lft|Rgt)=2 user + has to provide d3S/(dX^2*dY) + ** for BndType(Btm|Top)=2, BndType(Lft|Rgt)=1 user + has to provide d3S/(dX*dY^2) + ** if one of the intersecting bounds has 'parabolic + termination' condition, this specific mixed + derivative is not used + * first D entries store derivatives at the bottom left + corner x=min(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the bottom + right corner x=max(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the top + left corner x=min(X[]), y=max(Y[]) + * subsequent D entries store derivatives at the top + right corner x=max(X[]), y=max(Y[]) + * if all bounds have 'parabolic termination' condition, + MixedD[] is not referenced at all and can be + unallocated. + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are + stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline2dbuildclampedv(const real_1d_array &x, const real_1d_array &y, const real_1d_array &bndbtm, const ae_int_t bndtypebtm, const real_1d_array &bndtop, const ae_int_t bndtypetop, const real_1d_array &bndlft, const ae_int_t bndtypelft, const real_1d_array &bndrgt, const ae_int_t bndtypergt, const real_1d_array &mixedd, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.length(); + m = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildclampedv(x.c_ptr(), n, y.c_ptr(), m, bndbtm.c_ptr(), bndtypebtm, bndtop.c_ptr(), bndtypetop, bndlft.c_ptr(), bndtypelft, bndrgt.c_ptr(), bndtypergt, mixedd.c_ptr(), f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds a Hermite bicubic vector-valued spline. + +This function produces merely C1-continuous spline, i.e. the spline has +smooth first derivatives. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdX- spline derivatives with respect to X, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdY- spline derivatives with respect to Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + d2FdXdY-mixed derivatives with respect to X and Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildhermitev(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const real_1d_array &dfdx, const real_1d_array &dfdy, const real_1d_array &d2fdxdy, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildhermitev(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), dfdx.c_ptr(), dfdy.c_ptr(), d2fdxdy.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds a Hermite bicubic vector-valued spline. + +This function produces merely C1-continuous spline, i.e. the spline has +smooth first derivatives. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdX- spline derivatives with respect to X, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdY- spline derivatives with respect to Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + d2FdXdY-mixed derivatives with respect to X and Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline2dbuildhermitev(const real_1d_array &x, const real_1d_array &y, const real_1d_array &f, const real_1d_array &dfdx, const real_1d_array &dfdy, const real_1d_array &d2fdxdy, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.length(); + m = y.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildhermitev(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), dfdx.c_ptr(), dfdy.c_ptr(), d2fdxdy.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine builds bicubic vector-valued spline. + +Buffered version of Spline2DBuildBicubicV() which reuses memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubicvbuf(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C2-continuous spline, i.e. the has smooth first and +second derivatives both inside spline cells and at the boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissing(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubicmissing(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), missing.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBicubicMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissingbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubicmissingbuf(x.c_ptr(), n, y.c_ptr(), m, f.c_ptr(), missing.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine unpacks two-dimensional spline into the coefficients table + +Input parameters: + C - spline interpolant. + +Result: + M, N- grid size (x-axis and y-axis) + D - number of components + Tbl - coefficients table, unpacked format, + D - components: [0..(N-1)*(M-1)*D-1, 0..20]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index): + K := T + I*D + J*D*(N-1) + + K-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[K,0] = X[i] + Tbl[K,1] = X[i+1] + Tbl[K,2] = Y[j] + Tbl[K,3] = Y[j+1] + Tbl[K,4] = C00 + Tbl[K,5] = C01 + Tbl[K,6] = C02 + Tbl[K,7] = C03 + Tbl[K,8] = C10 + Tbl[K,9] = C11 + ... + Tbl[K,19] = C33 + Tbl[K,20] = 1 if the cell is present, 0 if the cell is missing. + In the latter case Tbl[4..19] are exactly zero. + On each grid square spline is equals to: + S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) + t = x-x[j] + u = y-y[i] + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dunpackv(c.c_ptr(), &m, &n, &d, tbl.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBilinearV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbilinear(x.c_ptr(), y.c_ptr(), f.c_ptr(), m, n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBicubicV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildbicubic(x.c_ptr(), y.c_ptr(), f.c_ptr(), m, n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DUnpackV(), which is more flexible +and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dunpack(c.c_ptr(), &m, &n, tbl.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine creates least squares solver used to fit 2D splines to +irregularly sampled (scattered) data. + +Solver object is used to perform spline fits as follows: +* solver object is created with spline2dbuildercreate() function +* dataset is added with spline2dbuildersetpoints() function +* fit area is chosen: + * spline2dbuildersetarea() - for user-defined area + * spline2dbuildersetareaauto() - for automatically chosen area +* number of grid nodes is chosen with spline2dbuildersetgrid() +* prior term is chosen with one of the following functions: + * spline2dbuildersetlinterm() to set linear prior + * spline2dbuildersetconstterm() to set constant prior + * spline2dbuildersetzeroterm() to set zero prior + * spline2dbuildersetuserterm() to set user-defined constant prior +* solver algorithm is chosen with either: + * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems + * spline2dbuildersetalgofastddm() - FastDDM algorithm, large-scale problems +* finally, fitting itself is performed with spline2dfit() function. + +Most of the steps above can be omitted, solver is configured with good +defaults. The minimum is to call: +* spline2dbuildercreate() to create solver object +* spline2dbuildersetpoints() to specify dataset +* spline2dbuildersetgrid() to tell how many nodes you need +* spline2dfit() to perform fit + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + D - positive number, number of Y-components: D=1 for simple scalar + fit, D>1 for vector-valued spline fitting. + +OUTPUT PARAMETERS: + S - solver object + + -- ALGLIB PROJECT -- + Copyright 29.01.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildercreate(const ae_int_t d, spline2dbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildercreate(d, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetuserterm(spline2dbuilder &state, const double v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetuserterm(state.c_ptr(), v, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +Linear prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetlinterm(spline2dbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetlinterm(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetconstterm(spline2dbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetconstterm(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets zero prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetzeroterm(spline2dbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetzeroterm(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + S - spline 2D builder object + XY - points, array[N,2+D]. One row corresponds to one point + in the dataset. First 2 elements are coordinates, next + D elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetpoints(spline2dbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetpoints(state.c_ptr(), xy.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets area where 2D spline interpolant is built. "Auto" means +that area extent is determined automatically from dataset extent. + +INPUT PARAMETERS: + S - spline 2D builder object + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetareaauto(spline2dbuilder &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetareaauto(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets area where 2D spline interpolant is built to +user-defined one: [XA,XB]*[YA,YB] + +INPUT PARAMETERS: + S - spline 2D builder object + XA,XB - spatial extent in the first (X) dimension, XA=1 means that up to chosen number of bottom + layers is fitted + * NLayers=0 means that maximum number of layers is chosen + (according to current grid size) + * NLayers<=-1 means that up to |NLayers| topmost layers is + skipped + Recommendations: + * good "default" value is 2 layers + * you may need more layers, if your dataset is very + irregular and you want to "patch" large holes. For a + grid step H (equal to AreaWidth/GridSize) you may expect + that last layer reproduces variations at distance H (and + can patch holes that wide); that higher layers operate + at distances 2*H, 4*H, 8*H and so on. + * good value for "bullletproof" mode is NLayers=0, which + results in complete hierarchy of layers being generated. + LambdaV - regularization coefficient, chosen in such a way that it + penalizes bottom layers (fine details) first. + LambdaV>=0, zero value means that no penalty is applied. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgofastddm(spline2dbuilder &state, const ae_int_t nlayers, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetalgofastddm(state.c_ptr(), nlayers, lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "BlockLLS", which performs +least squares fitting with fast sparse direct solver, with optional +nonsmoothness penalty being applied. + +This solver produces C2-continuous spline. + +Nonlinearity penalty has the following form: + + [ ] + P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy + [ ] + +here integral is calculated over entire grid, and "~" means "proportional" +because integral is normalized after calcilation. Extremely large values +of Lambda result in linear fit being performed. + +NOTE: this algorithm is the most robust and controllable one, but it is + limited by 512x512 grids and (say) up to 1.000.000 points. However, + ALGLIB has one more spline solver: FastDDM algorithm, which is + intended for really large-scale problems (in 10M-100M range). FastDDM + algorithm also has better parallelism properties. + +More information on BlockLLS solver: +* memory requirements: ~[32*K^3+256*NPoints] bytes for KxK grid with + NPoints-sized dataset +* serial running time: O(K^4+NPoints) +* parallelism potential: limited. You may get some sublinear gain when + working with large grids (K's in 256..512 range) + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- non-negative value: + * positive value means that some smoothing is applied + * zero value means that no smoothing is applied, and + corresponding entries of design matrix are numerically + zero and dropped from consideration. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgoblocklls(spline2dbuilder &state, const double lambdans, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetalgoblocklls(state.c_ptr(), lambdans, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "NaiveLLS". + +IMPORTANT: NaiveLLS is NOT intended to be used in real life code! This + algorithm solves problem by generated dense (K^2)x(K^2+NPoints) + matrix and solves linear least squares problem with dense + solver. + + It is here just to test BlockLLS against reference solver + (and maybe for someone trying to compare well optimized solver + against straightforward approach to the LLS problem). + +More information on naive LLS solver: +* memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid. +* serial running time: O(K^6+NPoints) for KxK grid +* when compared with BlockLLS, NaiveLLS has ~K larger memory demand and + ~K^2 larger running time. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- nonsmoothness penalty + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgonaivells(spline2dbuilder &state, const double lambdans, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dbuildersetalgonaivells(state.c_ptr(), lambdans, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function fits bicubic spline to current dataset, using current area/ +grid and current LLS solver. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - spline 2D builder object + +OUTPUT PARAMETERS: + S - 2D spline, fit result + Rep - fitting report, which provides some additional info about + errors, R2 coefficient and so on. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dfit(spline2dbuilder &state, spline2dinterpolant &s, spline2dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline2dfit(state.c_ptr(), s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +2-dimensional spline inteprolant +*************************************************************************/ +_spline2dinterpolant_owner::_spline2dinterpolant_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant)); + alglib_impl::_spline2dinterpolant_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dinterpolant_owner::_spline2dinterpolant_owner(alglib_impl::spline2dinterpolant *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline2dinterpolant_owner::_spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant)); + alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dinterpolant_owner& _spline2dinterpolant_owner::operator=(const _spline2dinterpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline2dinterpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline2dinterpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant)); + alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline2dinterpolant_owner::~_spline2dinterpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline2dinterpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() const +{ + return p_struct; +} +spline2dinterpolant::spline2dinterpolant() : _spline2dinterpolant_owner() +{ +} + +spline2dinterpolant::spline2dinterpolant(alglib_impl::spline2dinterpolant *attach_to):_spline2dinterpolant_owner(attach_to) +{ +} + +spline2dinterpolant::spline2dinterpolant(const spline2dinterpolant &rhs):_spline2dinterpolant_owner(rhs) +{ +} + +spline2dinterpolant& spline2dinterpolant::operator=(const spline2dinterpolant &rhs) +{ + if( this==&rhs ) + return *this; + _spline2dinterpolant_owner::operator=(rhs); + return *this; +} + +spline2dinterpolant::~spline2dinterpolant() +{ +} + + + + +/************************************************************************* +Nonlinear least squares solver used to fit 2D splines to data +*************************************************************************/ +_spline2dbuilder_owner::_spline2dbuilder_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder)); + alglib_impl::_spline2dbuilder_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dbuilder_owner::_spline2dbuilder_owner(alglib_impl::spline2dbuilder *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline2dbuilder_owner::_spline2dbuilder_owner(const _spline2dbuilder_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dbuilder_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder)); + alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dbuilder_owner& _spline2dbuilder_owner::operator=(const _spline2dbuilder_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline2dbuilder assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline2dbuilder_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder)); + alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline2dbuilder_owner::~_spline2dbuilder_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline2dbuilder_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr() const +{ + return p_struct; +} +spline2dbuilder::spline2dbuilder() : _spline2dbuilder_owner() +{ +} + +spline2dbuilder::spline2dbuilder(alglib_impl::spline2dbuilder *attach_to):_spline2dbuilder_owner(attach_to) +{ +} + +spline2dbuilder::spline2dbuilder(const spline2dbuilder &rhs):_spline2dbuilder_owner(rhs) +{ +} + +spline2dbuilder& spline2dbuilder::operator=(const spline2dbuilder &rhs) +{ + if( this==&rhs ) + return *this; + _spline2dbuilder_owner::operator=(rhs); + return *this; +} + +spline2dbuilder::~spline2dbuilder() +{ +} + + + + +/************************************************************************* +Spline 2D fitting report: + rmserror RMS error + avgerror average error + maxerror maximum error + r2 coefficient of determination, R-squared, 1-RSS/TSS +*************************************************************************/ +_spline2dfitreport_owner::_spline2dfitreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport)); + alglib_impl::_spline2dfitreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dfitreport_owner::_spline2dfitreport_owner(alglib_impl::spline2dfitreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline2dfitreport_owner::_spline2dfitreport_owner(const _spline2dfitreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline2dfitreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport)); + alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline2dfitreport_owner& _spline2dfitreport_owner::operator=(const _spline2dfitreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline2dfitreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline2dfitreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport)); + alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline2dfitreport_owner::~_spline2dfitreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline2dfitreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr() const +{ + return p_struct; +} +spline2dfitreport::spline2dfitreport() : _spline2dfitreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +spline2dfitreport::spline2dfitreport(alglib_impl::spline2dfitreport *attach_to):_spline2dfitreport_owner(attach_to) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +spline2dfitreport::spline2dfitreport(const spline2dfitreport &rhs):_spline2dfitreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2) +{ +} + +spline2dfitreport& spline2dfitreport::operator=(const spline2dfitreport &rhs) +{ + if( this==&rhs ) + return *this; + _spline2dfitreport_owner::operator=(rhs); + return *this; +} + +spline2dfitreport::~spline2dfitreport() +{ +} +#endif + +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine calculates the value of the trilinear or tricubic spline at +the given point (X,Y,Z). + +INPUT PARAMETERS: + C - coefficients table. + Built by BuildBilinearSpline or BuildBicubicSpline. + X, Y, + Z - point + +Result: + S(x,y,z) + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spline3dcalc(c.c_ptr(), x, y, z, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant + AX, BX - transformation coefficients: x = A*u + B + AY, BY - transformation coefficients: y = A*v + B + AZ, BZ - transformation coefficients: z = A*w + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransxyz(spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dlintransxyz(c.c_ptr(), ax, bx, ay, by, az, bz, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransf(spline3dinterpolant &c, const double a, const double b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dlintransf(c.c_ptr(), a, b, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Trilinear spline resampling + +INPUT PARAMETERS: + A - array[0..OldXCount*OldYCount*OldZCount-1], function + values at the old grid, : + A[0] x=0,y=0,z=0 + A[1] x=1,y=0,z=0 + A[..] ... + A[..] x=oldxcount-1,y=0,z=0 + A[..] x=0,y=1,z=0 + A[..] ... + ... + OldZCount - old Z-count, OldZCount>1 + OldYCount - old Y-count, OldYCount>1 + OldXCount - old X-count, OldXCount>1 + NewZCount - new Z-count, NewZCount>1 + NewYCount - new Y-count, NewYCount>1 + NewXCount - new X-count, NewXCount>1 + +OUTPUT PARAMETERS: + B - array[0..NewXCount*NewYCount*NewZCount-1], function + values at the new grid: + B[0] x=0,y=0,z=0 + B[1] x=1,y=0,z=0 + B[..] ... + B[..] x=newxcount-1,y=0,z=0 + B[..] x=0,y=1,z=0 + B[..] ... + ... + + -- ALGLIB routine -- + 26.04.2012 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dresampletrilinear(a.c_ptr(), oldzcount, oldycount, oldxcount, newzcount, newycount, newxcount, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +INPUT PARAMETERS: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + Z - spline applicates, array[0..L-1] + F - function values, array[0..M*N*L*D-1]: + * first D elements store D values at (X[0],Y[0],Z[0]) + * next D elements store D values at (X[1],Y[0],Z[0]) + * next D elements store D values at (X[2],Y[0],Z[0]) + * ... + * next D elements store D values at (X[0],Y[1],Z[0]) + * next D elements store D values at (X[1],Y[1],Z[0]) + * next D elements store D values at (X[2],Y[1],Z[0]) + * ... + * next D elements store D values at (X[0],Y[0],Z[1]) + * next D elements store D values at (X[1],Y[0],Z[1]) + * next D elements store D values at (X[2],Y[0],Z[1]) + * ... + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. + M,N, + L - grid size, M>=2, N>=2, L>=2 + D - vector dimension, D>=1 + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dbuildtrilinearv(x.c_ptr(), n, y.c_ptr(), m, z.c_ptr(), l, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +Buffered version of Spline3DBuildTrilinearV() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dbuildtrilinearvbuf(x.c_ptr(), n, y.c_ptr(), m, z.c_ptr(), l, f.c_ptr(), d, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + F - output buffer, possibly preallocated array. In case array size + is large enough to store result, it is not reallocated. Array + which is too short will be reallocated + +OUTPUT PARAMETERS: + F - array[D] (or larger) which stores function values + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dcalcvbuf(c.c_ptr(), x, y, z, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates trilinear or tricubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + +OUTPUT PARAMETERS: + F - array[D] which stores function values. F is out-parameter and + it is reallocated after call to this function. In case you + want to reuse previously allocated F, you may use + Spline2DCalcVBuf(), which reallocates F only when it is too + small. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dcalcv(c.c_ptr(), x, y, z, f.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine unpacks tri-dimensional spline into the coefficients table + +INPUT PARAMETERS: + C - spline interpolant. + +Result: + N - grid size (X) + M - grid size (Y) + L - grid size (Z) + D - number of components + SType- spline type. Currently, only one spline type is supported: + trilinear spline, as indicated by SType=1. + Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index), K=0..L-2 (z index): + Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), + + Q-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[Q,0] = X[i] + Tbl[Q,1] = X[i+1] + Tbl[Q,2] = Y[j] + Tbl[Q,3] = Y[j+1] + Tbl[Q,4] = Z[k] + Tbl[Q,5] = Z[k+1] + + Tbl[Q,6] = C000 + Tbl[Q,7] = C100 + Tbl[Q,8] = C010 + Tbl[Q,9] = C110 + Tbl[Q,10]= C001 + Tbl[Q,11]= C101 + Tbl[Q,12]= C011 + Tbl[Q,13]= C111 + On each grid square spline is equals to: + S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) + t = x-x[j] + u = y-y[i] + v = z-z[k] + + NOTE: format of Tbl is given for SType=1. Future versions of + ALGLIB can use different formats for different values of + SType. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline3dunpackv(c.c_ptr(), &n, &m, &l, &d, &stype, tbl.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +3-dimensional spline inteprolant +*************************************************************************/ +_spline3dinterpolant_owner::_spline3dinterpolant_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline3dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant)); + alglib_impl::_spline3dinterpolant_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline3dinterpolant_owner::_spline3dinterpolant_owner(alglib_impl::spline3dinterpolant *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_spline3dinterpolant_owner::_spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_spline3dinterpolant_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state); + memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant)); + alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_spline3dinterpolant_owner& _spline3dinterpolant_owner::operator=(const _spline3dinterpolant_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: spline3dinterpolant assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_spline3dinterpolant_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant)); + alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_spline3dinterpolant_owner::~_spline3dinterpolant_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_spline3dinterpolant_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() const +{ + return p_struct; +} +spline3dinterpolant::spline3dinterpolant() : _spline3dinterpolant_owner() +{ +} + +spline3dinterpolant::spline3dinterpolant(alglib_impl::spline3dinterpolant *attach_to):_spline3dinterpolant_owner(attach_to) +{ +} + +spline3dinterpolant::spline3dinterpolant(const spline3dinterpolant &rhs):_spline3dinterpolant_owner(rhs) +{ +} + +spline3dinterpolant& spline3dinterpolant::operator=(const spline3dinterpolant &rhs) +{ + if( this==&rhs ) + return *this; + _spline3dinterpolant_owner::operator=(rhs); + return *this; +} + +spline3dinterpolant::~spline3dinterpolant() +{ +} +#endif + +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremc() instead. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremcc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nsfitspheremcc(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremi() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremic(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nsfitspheremic(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rlo, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremz() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremzc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nsfitspheremzc(xy.c_ptr(), npoints, nx, cx.c_ptr(), &rlo, &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is left for backward compatibility. +Use fitspherex() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, const double penalty, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nsfitspherex(xy.c_ptr(), npoints, nx, problemtype, epsx, aulits, penalty, cx.c_ptr(), &rlo, &rhi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitpenalized(x.c_ptr(), y.c_ptr(), n, m, rho, &info, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitpenalized(x.c_ptr(), y.c_ptr(), n, m, rho, &info, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 19.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitpenalizedw(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, m, rho, &info, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 19.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length()) || (x.length()!=w.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitpenalizedw(x.c_ptr(), y.c_ptr(), w.c_ptr(), n, m, rho, &info, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitcubic(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfitcubic(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermite(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spline1dfithermite(x.c_ptr(), y.c_ptr(), n, m, s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +#endif + +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void rbfserialize(const rbfmodel &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void rbfserialize(const rbfmodel &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void rbfunserialize(const std::string &s_in, rbfmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void rbfunserialize(const std::istream &s_in, rbfmodel &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX>=1). + +Newly created model is empty. It can be used for interpolation right after +creation, but it just returns zeros. You have to add points to the model, +tune interpolation settings, and then call model construction function +rbfbuildmodel() which will update model according to your specification. + +USAGE: +1. User creates model with rbfcreate() +2. User adds dataset with rbfsetpoints() or rbfsetpointsandscales() +3. User selects RBF solver by calling: + * rbfsetalgohierarchical() - for a HRBF solver, a hierarchical large- + scale Gaussian RBFs (works well for uniformly distributed point + clouds, but may fail when the data are non-uniform; use other solvers + below in such cases) + * rbfsetalgothinplatespline() - for a large-scale DDM-RBF solver with + thin plate spline basis function being used + * rbfsetalgobiharmonic() - for a large-scale DDM-RBF solver with + biharmonic basis function being used + * rbfsetalgomultiquadricauto() - for a large-scale DDM-RBF solver with + multiquadric basis function being used (automatic selection of the + scale parameter Alpha) + * rbfsetalgomultiquadricmanual() - for a large-scale DDM-RBF solver + with multiquadric basis function being used (manual selection of the + scale parameter Alpha) +4. (OPTIONAL) User chooses polynomial term by calling: + * rbflinterm() to set linear term (default) + * rbfconstterm() to set constant term + * rbfzeroterm() to set zero term +5. User calls rbfbuildmodel() function which rebuilds model according to + the specification + +INPUT PARAMETERS: + NX - dimension of the space, NX>=1 + NY - function dimension, NY>=1 + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + +NOTE 1: memory requirements. RBF models require amount of memory which is + proportional to the number of data points. Some additional memory + is allocated during model construction, but most of this memory is + freed after the model coefficients are calculated. Amount of + this additional memory depends on model construction algorithm + being used. + + -- ALGLIB -- + Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfcreate(nx, ny, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of the buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +A buffer creation function (this function) is also thread-safe. I.e. you +may safely create multiple buffers for the same RBF model from multiple +threads. + +NOTE: the buffer object is just a collection of several preallocated + dynamic arrays and precomputed values. If you delete its "parent" + RBF model when the buffer is still alive, nothing bad will happen + (no dangling pointers or resource leaks). The buffer will simply + become useless. + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. +* it is recommended to reuse buffer as much as possible because buffer + creation involves allocation of several large dynamic arrays. It is a + huge waste of resource to use it just once. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2016 by Sergey Bochkanov +*************************************************************************/ +void rbfcreatecalcbuffer(const rbfmodel &s, rbfcalcbuffer &buf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfcreatecalcbuffer(s.c_ptr(), buf.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: ALGLIB version 3.11 and later allows you to specify a set of + per-dimension scales. Interpolation radii are multiplied by the + scale vector. It may be useful if you have mixed spatio-temporal + data (say, a set of 3D slices recorded at different times). + You should call rbfsetpointsandscales() function to use this + feature. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpoints(rbfmodel &s, const real_2d_array &xy, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetpoints(s.c_ptr(), xy.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: ALGLIB version 3.11 and later allows you to specify a set of + per-dimension scales. Interpolation radii are multiplied by the + scale vector. It may be useful if you have mixed spatio-temporal + data (say, a set of 3D slices recorded at different times). + You should call rbfsetpointsandscales() function to use this + feature. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetpoints(rbfmodel &s, const real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetpoints(s.c_ptr(), xy.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function adds dataset and a vector of per-dimension scales. + +It may be useful if you have mixed spatio-temporal data - say, a set of 3D +slices recorded at different times. Such data typically require different +RBF radii for spatial and temporal dimensions. ALGLIB solves this problem +by specifying single RBF radius, which is (optionally) multiplied by the +scale vector. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: only modern RBF algorithms support variable scaling. Legacy + algorithms like RBF-ML or QNN algorithms will result in -3 + completion code being returned (incorrect algorithm). + +INPUT PARAMETERS: + R - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + S - array[NX], scale vector, S[i]>0. + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpointsandscales(rbfmodel &r, const real_2d_array &xy, const ae_int_t n, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetpointsandscales(r.c_ptr(), xy.c_ptr(), n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds dataset and a vector of per-dimension scales. + +It may be useful if you have mixed spatio-temporal data - say, a set of 3D +slices recorded at different times. Such data typically require different +RBF radii for spatial and temporal dimensions. ALGLIB solves this problem +by specifying single RBF radius, which is (optionally) multiplied by the +scale vector. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: only modern RBF algorithms support variable scaling. Legacy + algorithms like RBF-ML or QNN algorithms will result in -3 + completion code being returned (incorrect algorithm). + +INPUT PARAMETERS: + R - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + S - array[NX], scale vector, S[i]>0. + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetpointsandscales(rbfmodel &r, const real_2d_array &xy, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = xy.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetpointsandscales(r.c_ptr(), xy.c_ptr(), n, s.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgoqnn(rbfmodel &s, const double q, const double z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgoqnn(s.c_ptr(), q, z, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgoqnn(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double q; + double z; + + q = 1.0; + z = 5.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgoqnn(s.c_ptr(), q, z, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 02.03.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultilayer(rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultilayer(s.c_ptr(), rbase, nlayers, lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 02.03.2012 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgomultilayer(rbfmodel &s, const double rbase, const ae_int_t nlayers, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double lambdav; + + lambdav = 0.01; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultilayer(s.c_ptr(), rbase, nlayers, lambdav, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function chooses HRBF solver, a 2nd version of ALGLIB RBFs. + +This algorithm is called Hierarchical RBF. It similar to its previous +incarnation, RBF-ML, i.e. it also builds a sequence of models with +decreasing radii. However, it uses more economical way of building upper +layers (ones with large radii), which results in faster model construction +and evaluation, as well as smaller memory footprint during construction. + +This algorithm has following important features: +* ability to handle millions of points +* controllable smoothing via nonlinearity penalization +* support for specification of per-dimensional radii via scale vector, + which is set by means of rbfsetpointsandscales() function. This feature + is useful if you solve spatio-temporal interpolation problems, where + different radii are required for spatial and temporal dimensions. + +Running times are roughly proportional to: +* N*log(N)*NLayers - for the model construction +* N*NLayers - for the model evaluation +You may see that running time does not depend on search radius or points +density, just on the number of layers in the hierarchy. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + RBase - RBase parameter, RBase>0 + NLayers - NLayers parameter, NLayers>0, recommended value to start + with - about 5. + LambdaNS- >=0, nonlinearity penalty coefficient, negative values are + not allowed. This parameter adds controllable smoothing to + the problem, which may reduce noise. Specification of non- + zero lambda means that in addition to fitting error solver + will also minimize LambdaNS*|S''(x)|^2 (appropriately + generalized to multiple dimensions. + + Specification of exactly zero value means that no penalty + is added (we do not even evaluate matrix of second + derivatives which is necessary for smoothing). + + Calculation of nonlinearity penalty is costly - it results + in several-fold increase of model construction time. + Evaluation time remains the same. + + Optimal lambda is problem-dependent and requires trial + and error. Good value to start from is 1e-5...1e-6, + which corresponds to slightly noticeable smoothing of the + function. Value 1e-2 usually means that quite heavy + smoothing is applied. + +TUNING ALGORITHM + +In order to use this algorithm you have to choose three parameters: +* initial radius RBase +* number of layers in the model NLayers +* penalty coefficient LambdaNS + +Initial radius is easy to choose - you can pick any number several times +larger than the average distance between points. Algorithm won't break +down if you choose radius which is too large (model construction time will +increase, but model will be built correctly). + +Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used +by the last layer) will be smaller than the typical distance between +points. In case model error is too large, you can increase number of +layers. Having more layers will make model construction and evaluation +proportionally slower, but it will allow you to have model which precisely +fits your data. From the other side, if you want to suppress noise, you +can DECREASE number of layers to make your model less flexible (or specify +non-zero LambdaNS). + +TYPICAL ERRORS + +1. Using too small number of layers - RBF models with large radius are not + flexible enough to reproduce small variations in the target function. + You need many layers with different radii, from large to small, in + order to have good model. + +2. Using initial radius which is too small. You will get model with + "holes" in the areas which are too far away from interpolation centers. + However, algorithm will work correctly (and quickly) in this case. + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgohierarchical(rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdans, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgohierarchical(s.c_ptr(), rbase, nlayers, lambdans, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function chooses a thin plate spline DDM-RBF solver, a fast RBF +solver with f(r)=r^2*ln(r) basis function. + +This algorithm has following important features: +* easy setup - no tunable parameters +* C1 continuous RBF model (gradient is defined everywhere, but Hessian is + undefined at nodes), high-quality interpolation +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a smoothing thin plate spline is + built, with larger LambdaV corresponding to models with + less nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgothinplatespline(rbfmodel &s, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgothinplatespline(s.c_ptr(), lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function chooses a thin plate spline DDM-RBF solver, a fast RBF +solver with f(r)=r^2*ln(r) basis function. + +This algorithm has following important features: +* easy setup - no tunable parameters +* C1 continuous RBF model (gradient is defined everywhere, but Hessian is + undefined at nodes), high-quality interpolation +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a smoothing thin plate spline is + built, with larger LambdaV corresponding to models with + less nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgothinplatespline(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double lambdav; + + lambdav = 0.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgothinplatespline(s.c_ptr(), lambdav, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with manual choice of +the scale parameter Alpha. + +This algorithm has following important features: +* C2 continuous RBF model (when Alpha>0 is used; for Alpha=0 the model is + merely C0 continuous) +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +One important point is that this algorithm includes tunable parameter +Alpha, which should be carefully chosen. Selecting too large value will +result in extremely badly conditioned problems (interpolation accuracy +may degrade up to complete breakdown) whilst selecting too small value may +produce models that are precise but nearly nonsmooth at the nodes. + +Good value to start from is mean distance between nodes. Generally, +choosing too small Alpha is better than choosing too large - in the former +case you still have model that reproduces target values at the nodes. + +In most cases, better option is to choose good Alpha automatically - it is +done by another version of the same algorithm that is activated by calling +rbfsetalgomultiquadricauto() method. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + Alpha - basis function parameter, Alpha>=0: + * Alpha>0 means that multiquadric algorithm is used which + produces C2-continuous RBF model + * Alpha=0 means that the multiquadric kernel effectively + becomes a biharmonic one: f=r. As a result, the model + becomes nonsmooth at nodes, and hence is C0 continuous + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricmanual(rbfmodel &s, const double alpha, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultiquadricmanual(s.c_ptr(), alpha, lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with manual choice of +the scale parameter Alpha. + +This algorithm has following important features: +* C2 continuous RBF model (when Alpha>0 is used; for Alpha=0 the model is + merely C0 continuous) +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +One important point is that this algorithm includes tunable parameter +Alpha, which should be carefully chosen. Selecting too large value will +result in extremely badly conditioned problems (interpolation accuracy +may degrade up to complete breakdown) whilst selecting too small value may +produce models that are precise but nearly nonsmooth at the nodes. + +Good value to start from is mean distance between nodes. Generally, +choosing too small Alpha is better than choosing too large - in the former +case you still have model that reproduces target values at the nodes. + +In most cases, better option is to choose good Alpha automatically - it is +done by another version of the same algorithm that is activated by calling +rbfsetalgomultiquadricauto() method. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + Alpha - basis function parameter, Alpha>=0: + * Alpha>0 means that multiquadric algorithm is used which + produces C2-continuous RBF model + * Alpha=0 means that the multiquadric kernel effectively + becomes a biharmonic one: f=r. As a result, the model + becomes nonsmooth at nodes, and hence is C0 continuous + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgomultiquadricmanual(rbfmodel &s, const double alpha, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double lambdav; + + lambdav = 0.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultiquadricmanual(s.c_ptr(), alpha, lambdav, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with Alpha being +automatically determined. + +This algorithm has following important features: +* easy setup - no need to tune Alpha, good value is automatically assigned +* C2 continuous RBF model +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +This algorithm automatically selects Alpha as a mean distance to the +nearest neighbor (ignoring neighbors that are too close). + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricauto(rbfmodel &s, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultiquadricauto(s.c_ptr(), lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with Alpha being +automatically determined. + +This algorithm has following important features: +* easy setup - no need to tune Alpha, good value is automatically assigned +* C2 continuous RBF model +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +This algorithm automatically selects Alpha as a mean distance to the +nearest neighbor (ignoring neighbors that are too close). + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgomultiquadricauto(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double lambdav; + + lambdav = 0.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgomultiquadricauto(s.c_ptr(), lambdav, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function chooses a biharmonic DDM-RBF solver, a fast RBF solver +with f(r)=r as a basis function. + +This algorithm has following important features: +* no tunable parameters +* C0 continuous RBF model (the model has discontinuous derivatives at the + interpolation nodes) +* fast model construction algorithm with O(N) memory and O(N*logN) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* accelerated evaluation using far field expansions (aka fast multipoles + method) is supported. See rbffastcalc() for more information. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgobiharmonic(rbfmodel &s, const double lambdav, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgobiharmonic(s.c_ptr(), lambdav, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function chooses a biharmonic DDM-RBF solver, a fast RBF solver +with f(r)=r as a basis function. + +This algorithm has following important features: +* no tunable parameters +* C0 continuous RBF model (the model has discontinuous derivatives at the + interpolation nodes) +* fast model construction algorithm with O(N) memory and O(N*logN) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* accelerated evaluation using far field expansions (aka fast multipoles + method) is supported. See rbffastcalc() for more information. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rbfsetalgobiharmonic(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double lambdav; + + lambdav = 0.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetalgobiharmonic(s.c_ptr(), lambdav, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets linear term (model is a sum of radial basis functions +plus linear polynomial). This function won't have effect until next call +to RBFBuildModel(). + +Using linear term is a default option and it is the best one - it provides +best convergence guarantees for all RBF model types: legacy RBF-QNN and +RBF-ML, Gaussian HRBFs and all types of DDM-RBF models. + +Other options, like constant or zero term, work for HRBFs, almost always +work for DDM-RBFs but provide no stability guarantees in the latter case +(e.g. the solver may fail on some carefully prepared problems). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetlinterm(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetlinterm(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets constant term (model is a sum of radial basis functions +plus constant). This function won't have effect until next call to +RBFBuildModel(). + +IMPORTANT: thin plate splines require polynomial term to be linear, not + constant, in order to provide interpolation guarantees. + Although failures are exceptionally rare, some small toy + problems may result in degenerate linear systems. Thus, it is + advised to use linear term when one fits data with TPS. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetconstterm(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetconstterm(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets zero term (model is a sum of radial basis functions +without polynomial term). This function won't have effect until next call +to RBFBuildModel(). + +IMPORTANT: only Gaussian RBFs (HRBF algorithm) provide interpolation + guarantees when no polynomial term is used. Most other RBFs, + including biharmonic splines, thin plate splines and + multiquadrics, require at least constant term (biharmonic and + multiquadric) or linear one (thin plate splines) in order to + guarantee non-degeneracy of linear systems being solved. + + Although failures are exceptionally rare, some small toy + problems still may result in degenerate linear systems. Thus,it + is advised to use constant/linear term, unless one is 100% sure + that he needs zero term. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetzeroterm(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetzeroterm(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets basis function type, which can be: +* 0 for classic Gaussian +* 1 for fast and compact bell-like basis function, which becomes exactly + zero at distance equal to 3*R (default option). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + BF - basis function type: + * 0 - classic Gaussian + * 1 - fast and compact one + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2bf(rbfmodel &s, const ae_int_t bf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetv2bf(s.c_ptr(), bf, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping criteria of the underlying linear solver for +hierarchical (version 2) RBF constructor. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + MaxIts - this criterion will stop algorithm after MaxIts iterations. + Typically a few hundreds iterations is required, with 400 + being a good default value to start experimentation. + Zero value means that default value will be selected. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2its(rbfmodel &s, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetv2its(s.c_ptr(), maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets support radius parameter of hierarchical (version 2) +RBF constructor. + +Hierarchical RBF model achieves great speed-up by removing from the model +excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter, +and two nodes are just 1 millimeter apart, you may remove one of them +without reducing model quality. + +Support radius parameter is used to justify which points need removal, and +which do not. If two points are less than SUPPORT_R*CUR_RADIUS units of +distance apart, one of them is removed from the model. The larger support +radius is, the faster model construction AND evaluation are. However, +too large values result in "bumpy" models. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + R - support radius coefficient, >=0. + Recommended values are [0.1,0.4] range, with 0.1 being + default value. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2supportr(rbfmodel &s, const double r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetv2supportr(s.c_ptr(), r, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets desired accuracy for a version 3 RBF model. + +As of ALGLIB 3.20.0, version 3 models include biharmonic RBFs, thin plate +splines, multiquadrics. + +Version 3 models are fit with specialized domain decomposition method +which splits problem into smaller chunks. Models with size less than +the DDM chunk size are computed nearly exactly in one step. Larger models +are built with an iterative linear solver. This function controls accuracy +of the solver. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + TOL - desired precision: + * must be non-negative + * should be somewhere between 0.001 and 0.000001 + * values higher than 0.001 make little sense - you may + lose a lot of precision with no performance gains. + * values below 1E-6 usually require too much time to converge, + so they are silenly replaced by a 1E-6 cutoff value. Thus, + zero can be used to denote 'maximum precision'. + + -- ALGLIB -- + Copyright 01.10.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv3tol(rbfmodel &s, const double tol, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetv3tol(s.c_ptr(), tol, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function builds RBF model and returns report (contains some +information which can be used for evaluation of the algorithm properties). + +Call to this function modifies RBF model by calculating its centers/radii/ +weights and saving them into RBFModel structure. Initially RBFModel +contain zero coefficients, but after call to this function we will have +coefficients which were calculated in order to fit our dataset. + +After you called this function you can call RBFCalc(), RBFGridCalc() and +other model calculation functions. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + Rep - report: + * Rep.TerminationType: + * -5 - non-distinct basis function centers were detected, + interpolation aborted; only QNN returns this + error code, other algorithms can handle non- + distinct nodes. + * -4 - nonconvergence of the internal SVD solver + * -3 incorrect model construction algorithm was chosen: + QNN or RBF-ML, combined with one of the incompatible + features: + * NX=1 or NX>3 + * points with per-dimension scales. + * 1 - successful termination + * 8 - a termination request was submitted via + rbfrequesttermination() function. + + Fields which are set only by modern RBF solvers (hierarchical + or nonnegative; older solvers like QNN and ML initialize these + fields by NANs): + * rep.rmserror - root-mean-square error at nodes + * rep.maxerror - maximum error at nodes + + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the LSQR solver + * Rep.NMV - number of matrix-vector products + * Rep.ARows - rows count for the system matrix + * Rep.ACols - columns count for the system matrix + * Rep.ANNZ - number of significantly non-zero elements + (elements above some algorithm-determined threshold) + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfbuildmodel(rbfmodel &s, rbfreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfbuildmodel(s.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the 1-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: this function works only with modern (hierarchical) RBFs. It + can not be used with legacy (version 1) RBFs because older RBF + code does not support 1-dimensional models. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* the model is not initialized +* NX<>1 +* NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - X-coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc1(rbfmodel &s, const double x0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rbfcalc1(s.c_ptr(), x0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates values of the 2-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc2(rbfmodel &s, const double x0, const double x1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rbfcalc2(s.c_ptr(), x0, x1, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates values of the 3-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc3(rbfmodel &s, const double x0, const double x1, const double x2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rbfcalc3(s.c_ptr(), x0, x1, x2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates value and derivatives of the 1-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>1 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff1(rbfmodel &s, const double x0, double &y, double &dy0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfdiff1(s.c_ptr(), x0, &y, &dy0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates value and derivatives of the 2-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>2 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff2(rbfmodel &s, const double x0, const double x1, double &y, double &dy0, double &dy1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfdiff2(s.c_ptr(), x0, x1, &y, &dy0, &dy1, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates value and derivatives of the 3-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>3 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + DY2 - derivative with respect to X2 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff3(rbfmodel &s, const double x0, const double x1, const double x2, double &y, double &dy0, double &dy1, double &dy2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfdiff3(s.c_ptr(), x0, x1, x2, &y, &dy0, &dy1, &dy2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets absolute accuracy of a fast evaluation algorithm used +by rbffastcalc() and other fast evaluation functions. + +A fast evaluation algorithm is model-dependent and is available only for +some RBF models. Usually it utilizes far field expansions (a generalization +of the fast multipoles method). If no approximate fast evaluator is +available for the current RBF model type, this function has no effect. + +NOTE: this function can be called before or after the model was built. The + result will be the same. + +NOTE: this function has O(N) running time, where N is a points count. + Most fast evaluators work by aggregating influence of point groups, + i.e. by computing so called far field. Changing evaluator tolerance + means that far field radii have to be recomputed for each point + cluster, and we have O(N) such clusters. + + This function is still very fast, but it should not be called too + often, e.g. every time you call rbffastcalc() in a loop. + +NOTE: the tolerance set by this function is an accuracy of an evaluator + which computes the value of the model. It is NOT accuracy of the + model itself. + + E.g., if you set evaluation accuracy to 1E-12, the model value will + be computed with required precision. However, the model itself is an + approximation of the target (the default requirement is to fit model + with ~6 digits of precision) and THIS accuracy can not be changed + after the model was built. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. Calling it while another thread + tries to use rbffastcalc() is unsafe because it means that the + accuracy requirements will change in the middle of computations. + The algorithm may behave unpredictably. + +INPUT PARAMETERS: + S - RBF model + TOL - TOL>0, desired evaluation tolerance: + * should be somewhere between 1E-3 and 1E-6 + * values outside of this range will cause no problems (the + evaluator will do the job anyway). However, too strict + precision requirements may mean that no approximation + speed-up will be achieved. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetfastevaltol(rbfmodel &s, const double tol, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfsetfastevaltol(s.c_ptr(), tol, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model at the given point using +a fast approximate algorithm whenever possible. If no fast algorithm is +available for a given model type, traditional O(N) approach is used. + +Presently, fast evaluation is implemented only for biharmonic splines. + +The absolute approximation accuracy is controlled by the rbfsetfastevaltol() +function. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with a per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbffastcalc(rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbffastcalc(s.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use rbfcalc2() or +rbfcalc3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfcalc(rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfcalc(s.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model and its derivatives at +the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +if you have NX=3 and NY=1, you may find more convenient to use rbfdiff3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftsdiffbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFDiffBuf(), + which reallocates Y only when it is too small. + DY - derivatives, array[NX*NY]: + * Y[I*NX+J] with 0<=I1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + Y is out-parameter and reallocated after call to this + function. In case you want to reuse previously allocated + Y, you may use RBFHessBuf(), which reallocates Y only when + it is too small. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y- possible preallocated output arrays. If these arrays are + smaller than required to store the result, they are + automatically reallocated. If array is large enough, it is + not resized. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 27.01.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfgridcalc2v(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfgridcalc2vsubset(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, flagy.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model at the regular grid, +which has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]). +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + * I2=0...N2-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc3vsubset(). + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfgridcalc3v(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, x2.c_ptr(), n2, y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + + FlagY - array[N0*N1*N2]: + * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfgridcalc3vsubset(s.c_ptr(), x0.c_ptr(), n0, x1.c_ptr(), n1, x2.c_ptr(), n2, flagy.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information , 2D array. One row of the array + corresponds to one basis function. + + For ModelVersion=1 we have NX+NY+1 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last column - radius, same for all dimensions of + the function being modeled + + For ModelVersion=2 we have NX+NY+NX columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last NX columns - radii, one per dimension + + For ModelVersion=3 we have NX+NY+NX+3 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * next NX columns - radii, one per dimension + * next column - basis function type: + * 1 for f=r + * 2 for f=r^2*ln(r) + * 10 for multiquadric f=sqrt(r^2+alpha^2) + * next column - basis function parameter: + * alpha, for basis function type 10 + * ignored (zero) for other basis function types + * next column - point index in the original dataset, + or -1 for an artificial node created + by the solver. The algorithm may reorder + the nodes, drop some nodes or add + artificial nodes. Thus, one parsing + this column should expect all these + kinds of alterations in the dataset. + + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + ModelVersion-version of the RBF model: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + * 3 - for models created by DDM-RBF, requires + ALGLIB 3.19 or later + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfunpack(rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v, ae_int_t &modelversion, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfunpack(s.c_ptr(), &nx, &ny, xwr.c_ptr(), &nc, v.c_ptr(), &modelversion, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function returns model version. + +INPUT PARAMETERS: + S - RBF model + +RESULT: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + + -- ALGLIB -- + Copyright 06.07.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t rbfgetmodelversion(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::rbfgetmodelversion(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function is used to peek into hierarchical RBF construction process +from some other thread and get current progress indicator. It returns +value in [0,1]. + +IMPORTANT: only HRBFs (hierarchical RBFs) support peeking into progress + indicator. Legacy RBF-ML and RBF-QNN do not support it. You + will always get 0 value. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +double rbfpeekprogress(const rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rbfpeekprogress(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function is used to submit a request for termination of the +hierarchical RBF construction process from some other thread. As result, +RBF construction is terminated smoothly (with proper deallocation of all +necessary resources) and resultant model is filled by zeros. + +A rep.terminationtype=8 will be returned upon receiving such request. + +IMPORTANT: only HRBFs (hierarchical RBFs) support termination requests. + Legacy RBF-ML and RBF-QNN do not support it. An attempt to + terminate their construction will be ignored. + +IMPORTANT: termination request flag is cleared when the model construction + starts. Thus, any pre-construction termination requests will be + silently ignored - only ones submitted AFTER construction has + actually began will be handled. + +INPUT PARAMETERS: + S - RBF model object + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +void rbfrequesttermination(rbfmodel &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rbfrequesttermination(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Buffer object which is used to perform RBF model calculation in the +multithreaded mode (multiple threads working with same RBF object). + +This object should be created with RBFCreateCalcBuffer(). +*************************************************************************/ +_rbfcalcbuffer_owner::_rbfcalcbuffer_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfcalcbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer)); + alglib_impl::_rbfcalcbuffer_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfcalcbuffer_owner::_rbfcalcbuffer_owner(alglib_impl::rbfcalcbuffer *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_rbfcalcbuffer_owner::_rbfcalcbuffer_owner(const _rbfcalcbuffer_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfcalcbuffer_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer)); + alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfcalcbuffer_owner& _rbfcalcbuffer_owner::operator=(const _rbfcalcbuffer_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: rbfcalcbuffer assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_rbfcalcbuffer_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer)); + alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_rbfcalcbuffer_owner::~_rbfcalcbuffer_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_rbfcalcbuffer_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr() const +{ + return p_struct; +} +rbfcalcbuffer::rbfcalcbuffer() : _rbfcalcbuffer_owner() +{ +} + +rbfcalcbuffer::rbfcalcbuffer(alglib_impl::rbfcalcbuffer *attach_to):_rbfcalcbuffer_owner(attach_to) +{ +} + +rbfcalcbuffer::rbfcalcbuffer(const rbfcalcbuffer &rhs):_rbfcalcbuffer_owner(rhs) +{ +} + +rbfcalcbuffer& rbfcalcbuffer::operator=(const rbfcalcbuffer &rhs) +{ + if( this==&rhs ) + return *this; + _rbfcalcbuffer_owner::operator=(rhs); + return *this; +} + +rbfcalcbuffer::~rbfcalcbuffer() +{ +} + + + + +/************************************************************************* +RBF model. + +Never try to directly work with fields of this object - always use ALGLIB +functions to use this object. +*************************************************************************/ +_rbfmodel_owner::_rbfmodel_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfmodel)); + alglib_impl::_rbfmodel_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfmodel_owner::_rbfmodel_owner(alglib_impl::rbfmodel *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_rbfmodel_owner::_rbfmodel_owner(const _rbfmodel_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfmodel_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfmodel)); + alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfmodel_owner& _rbfmodel_owner::operator=(const _rbfmodel_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: rbfmodel assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_rbfmodel_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::rbfmodel)); + alglib_impl::_rbfmodel_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_rbfmodel_owner::~_rbfmodel_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_rbfmodel_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() const +{ + return p_struct; +} +rbfmodel::rbfmodel() : _rbfmodel_owner() +{ +} + +rbfmodel::rbfmodel(alglib_impl::rbfmodel *attach_to):_rbfmodel_owner(attach_to) +{ +} + +rbfmodel::rbfmodel(const rbfmodel &rhs):_rbfmodel_owner(rhs) +{ +} + +rbfmodel& rbfmodel::operator=(const rbfmodel &rhs) +{ + if( this==&rhs ) + return *this; + _rbfmodel_owner::operator=(rhs); + return *this; +} + +rbfmodel::~rbfmodel() +{ +} + + + + +/************************************************************************* +RBF solution report: +* TerminationType - termination type, positive values - success, + non-positive - failure. + +Fields which are set by modern RBF solvers (hierarchical): +* RMSError - root-mean-square error; NAN for old solvers (ML, QNN) +* MaxError - maximum error; NAN for old solvers (ML, QNN) +*************************************************************************/ +_rbfreport_owner::_rbfreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfreport)); + alglib_impl::_rbfreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfreport_owner::_rbfreport_owner(alglib_impl::rbfreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_rbfreport_owner::_rbfreport_owner(const _rbfreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_rbfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::rbfreport)); + alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_rbfreport_owner& _rbfreport_owner::operator=(const _rbfreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: rbfreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_rbfreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::rbfreport)); + alglib_impl::_rbfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_rbfreport_owner::~_rbfreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_rbfreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::rbfreport* _rbfreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::rbfreport* _rbfreport_owner::c_ptr() const +{ + return p_struct; +} +rbfreport::rbfreport() : _rbfreport_owner() ,rmserror(p_struct->rmserror),maxerror(p_struct->maxerror),arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +rbfreport::rbfreport(alglib_impl::rbfreport *attach_to):_rbfreport_owner(attach_to) ,rmserror(p_struct->rmserror),maxerror(p_struct->maxerror),arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +rbfreport::rbfreport(const rbfreport &rhs):_rbfreport_owner(rhs) ,rmserror(p_struct->rmserror),maxerror(p_struct->maxerror),arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +rbfreport& rbfreport::operator=(const rbfreport &rhs) +{ + if( this==&rhs ) + return *this; + _rbfreport_owner::operator=(rhs); + return *this; +} + +rbfreport::~rbfreport() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +static void ratint_barycentricnormalize(barycentricinterpolant* b, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +static double idw_w0 = 1.0; +static double idw_meps = 1.0E-50; +static ae_int_t idw_defaultnlayers = 16; +static double idw_defaultlambda0 = 0.3333; +static ae_int_t idw_idwbatchsize = 128; +static void idw_idwgridcalc2rec(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t begin0, + ae_int_t end0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t begin1, + ae_int_t end1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_shared_pool* cbpool, + ae_bool isrootcall, + double evalcost, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool _trypexec_idw_idwgridcalc2rec(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t begin0, + ae_int_t end0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t begin1, + ae_int_t end1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_shared_pool* cbpool, + ae_bool isrootcall, + double evalcost, + /* Real */ ae_vector* y, ae_state *_state); +static void idw_errormetricsviacalc(idwbuilder* state, + idwmodel* model, + idwreport* rep, + ae_state *_state); +static void idw_mstabrec(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + ae_shared_pool* mbpool, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, + ae_state *_state); +ae_bool _trypexec_idw_mstabrec(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + ae_shared_pool* mbpool, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, ae_state *_state); +static void idw_mstabbasecase(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + mstabbuffer* buf, + ae_int_t idx0, + ae_int_t idx1, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +static double spline1d_lambdareg = 1.0e-10; +static double spline1d_cholreg = 1.0e-14; +static void spline1d_bbasisinit(spline1dbbasis* basis, + ae_int_t m, + ae_state *_state); +static double spline1d_basiscalc(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state); +static double spline1d_basisdiff(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state); +static double spline1d_basisdiff2(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state); +static void spline1d_buildakimax(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_bool modakima, + spline1dinterpolant* c, + ae_state *_state); +static void spline1d_heapsortpoints(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_int_t n, + ae_state *_state); +static void spline1d_heapsortppoints(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Integer */ ae_vector* p, + ae_int_t n, + ae_state *_state); +static void spline1d_solvetridiagonal(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* _b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* _d, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); +static void spline1d_solvecyclictridiagonal(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* _b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* d, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); +static double spline1d_diffthreepoint(double t, + double x0, + double f0, + double x1, + double f1, + double x2, + double f2, + ae_state *_state); +static void spline1d_hermitecalc(double p0, + double m0, + double p1, + double m1, + double t, + double* s, + double* ds, + ae_state *_state); +static double spline1d_rescaleval(double a0, + double b0, + double a1, + double b1, + double t, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +static void lsfit_rdpanalyzesection(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t i0, + ae_int_t i1, + ae_int_t* worstidx, + double* worsterror, + ae_state *_state); +static void lsfit_rdprecursive(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t i0, + ae_int_t i1, + double eps, + /* Real */ ae_vector* xout, + /* Real */ ae_vector* yout, + ae_int_t* nout, + ae_state *_state); +static void lsfit_logisticfitinternal(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_bool is4pl, + double lambdav, + minlmstate* state, + minlmreport* replm, + /* Real */ ae_vector* p1, + double* flast, + ae_state *_state); +static void lsfit_logisticfit45errors(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + double a, + double b, + double c, + double d, + double g, + lsfitreport* rep, + ae_state *_state); +static void lsfit_spline1dfitinternal(ae_int_t st, + /* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +static void lsfit_lsfitlinearinternal(/* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +static void lsfit_lsfitclearrequestfields(lsfitstate* state, + ae_state *_state); +static void lsfit_barycentriccalcbasis(const barycentricinterpolant* b, + double t, + /* Real */ ae_vector* y, + ae_state *_state); +static void lsfit_internalchebyshevfit(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +static void lsfit_barycentricfitwcfixedd(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + ae_int_t d, + ae_int_t* info, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state); +static void lsfit_clearreport(lsfitreport* rep, ae_state *_state); +static void lsfit_estimateerrors(/* Real */ const ae_matrix* f1, + /* Real */ const ae_vector* f0, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* _s, + ae_int_t n, + ae_int_t k, + lsfitreport* rep, + /* Real */ ae_matrix* z, + ae_int_t zkind, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +static void parametric_pspline2par(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t pt, + /* Real */ ae_vector* p, + ae_state *_state); +static void parametric_pspline3par(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t pt, + /* Real */ ae_vector* p, + ae_state *_state); +static void parametric_rdpanalyzesectionpar(/* Real */ const ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t d, + ae_int_t* worstidx, + double* worsterror, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) +static ae_int_t rbfv1_mxnx = 3; +static double rbfv1_rbffarradius = 6; +static double rbfv1_rbfnearradius = 2.1; +static double rbfv1_rbfmlradius = 3; +static double rbfv1_minbasecasecost = 100000; +static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_int_t n, + ae_int_t ny, + ae_int_t modeltype, + /* Real */ ae_matrix* v, + ae_state *_state); +static void rbfv1_buildrbfmodellsqr(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + /* Real */ const ae_matrix* xc, + /* Real */ const ae_vector* r, + ae_int_t n, + ae_int_t nc, + ae_int_t ny, + kdtree* pointstree, + kdtree* centerstree, + double epsort, + double epserr, + ae_int_t maxits, + ae_int_t* gnnz, + ae_int_t* snnz, + /* Real */ ae_matrix* w, + ae_int_t* info, + ae_int_t* iterationscount, + ae_int_t* nmv, + ae_state *_state); +static void rbfv1_buildrbfmlayersmodellsqr(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + /* Real */ ae_matrix* xc, + double rval, + /* Real */ ae_vector* r, + ae_int_t n, + ae_int_t* nc, + ae_int_t ny, + ae_int_t nlayers, + kdtree* centerstree, + double epsort, + double epserr, + ae_int_t maxits, + double lambdav, + ae_int_t* annz, + /* Real */ ae_matrix* w, + ae_int_t* info, + ae_int_t* iterationscount, + ae_int_t* nmv, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_bool rbfv3farfields_bhpaneleval1fastkernel(double d0, + double d1, + double d2, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_bool rbfv3farfields_bhpanelevalfastkernel(double d0, + double d1, + double d2, + ae_int_t ny, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + /* Real */ ae_vector* f, + double* invpowrpplus1, + ae_state *_state); +#endif + + +#endif +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) +static double rbfv3_epsred = 0.999999; +static ae_int_t rbfv3_maxddmits = 25; +static double rbfv3_polyharmonic2scale = 4.0; +static ae_int_t rbfv3_acbfparallelthreshold = 512; +static ae_int_t rbfv3_ddmparallelthreshold = 512; +static ae_int_t rbfv3_bfparallelthreshold = 512; +static ae_int_t rbfv3_defaultmaxpanelsize = 128; +static ae_int_t rbfv3_maxcomputebatchsize = 128; +static ae_int_t rbfv3_minfarfieldsize = 256; +static ae_int_t rbfv3_biharmonicseriesmax = 15; +static ae_int_t rbfv3_farfieldnone = -1; +static ae_int_t rbfv3_farfieldbiharmonic = 1; +static double rbfv3_defaultfastevaltol = 1.0E-3; +static ae_bool rbfv3_userelaxederrorestimates = ae_true; +static void rbfv3_evalbufferinit(rbf3evaluatorbuffer* buf, + ae_int_t nx, + ae_int_t maxpanelsize, + ae_state *_state); +static ae_int_t rbfv3_fastevaluatorinitrec(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* xx, + /* Integer */ ae_vector* ptidx, + /* Real */ ae_vector* coordbuf, + ae_int_t idx0, + ae_int_t idx1, + ae_nxpool* nxpool, + ae_state *_state); +static void rbfv3_fastevaluatorinit(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* _x, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t maxpanelsize, + ae_int_t bftype, + double bfparam, + ae_bool usedebugcounters, + ae_state *_state); +static void rbfv3_fastevaluatorloadcoeffsrec(rbf3fastevaluator* eval, + ae_int_t treenodeidx, + ae_state *_state); +static void rbfv3_fastevaluatorloadcoeffs1(rbf3fastevaluator* eval, + /* Real */ const ae_vector* w, + ae_state *_state); +static void rbfv3_fastevaluatorloadcoeffs(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* w, + ae_state *_state); +static void rbfv3_fastevaluatorpushtolrec(rbf3fastevaluator* eval, + ae_int_t treenodeidx, + ae_bool dotrace, + ae_int_t dbglevel, + double maxcomputeerr, + ae_state *_state); +static void rbfv3_fastevaluatorpushtol(rbf3fastevaluator* eval, + double maxcomputeerr, + ae_state *_state); +static void rbfv3_fastevaluatorcomputepanel2panel(rbf3fastevaluator* eval, + rbf3panel* dstpanel, + rbf3panel* srcpanel, + rbf3evaluatorbuffer* buf, + /* Real */ ae_vector* y, + ae_state *_state); +static void rbfv3_fastevaluatorcomputeallrecurseonsources(rbf3fastevaluator* eval, + rbf3panel* dstpanel, + rbf3evaluatorbuffer* buf, + ae_int_t sourcetreenode, + /* Real */ ae_vector* y, + ae_state *_state); +static void rbfv3_fastevaluatorcomputeallrecurseontargets(rbf3fastevaluator* eval, + ae_int_t targettreenode, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool _trypexec_rbfv3_fastevaluatorcomputeallrecurseontargets(rbf3fastevaluator* eval, + ae_int_t targettreenode, + /* Real */ ae_vector* y, ae_state *_state); +static void rbfv3_fastevaluatorcomputeall(rbf3fastevaluator* eval, + /* Real */ ae_vector* y, + ae_state *_state); +static void rbfv3_fastevaluatorcomputebatchrecurseonsources(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t tgtidx, + ae_int_t sourcetreenode, + ae_bool usefarfields, + rbf3evaluatorbuffer* buf, + /* Real */ ae_matrix* y, + ae_state *_state); +ae_bool _trypexec_rbfv3_fastevaluatorcomputebatchrecurseonsources(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t tgtidx, + ae_int_t sourcetreenode, + ae_bool usefarfields, + rbf3evaluatorbuffer* buf, + /* Real */ ae_matrix* y, ae_state *_state); +static void rbfv3_fastevaluatorcomputebatchrecurseontargets(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + ae_bool usefarfields, + /* Real */ ae_matrix* y, + ae_state *_state); +ae_bool _trypexec_rbfv3_fastevaluatorcomputebatchrecurseontargets(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + ae_bool usefarfields, + /* Real */ ae_matrix* y, ae_state *_state); +static void rbfv3_fastevaluatorcomputebatch(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_bool usefarfields, + /* Real */ ae_matrix* y, + ae_state *_state); +static void rbfv3_createfastevaluator(rbfv3model* model, ae_state *_state); +static void rbfv3_gridcalcrec(const rbfv3model* s, + ae_int_t simdwidth, + ae_int_t tileidx0, + ae_int_t tileidx1, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_shared_pool* calcpool, + ae_bool isrootcall, + ae_state *_state); +ae_bool _trypexec_rbfv3_gridcalcrec(const rbfv3model* s, + ae_int_t simdwidth, + ae_int_t tileidx0, + ae_int_t tileidx1, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_shared_pool* calcpool, + ae_bool isrootcall, ae_state *_state); +static void rbfv3_zerofill(rbfv3model* s, + ae_int_t nx, + ae_int_t ny, + ae_state *_state); +static void rbfv3_allocatecalcbuffer(const rbfv3model* s, + rbfv3calcbuffer* buf, + ae_state *_state); +static void rbfv3_preprocessdatasetrec(/* Real */ ae_matrix* xbuf, + /* Real */ ae_matrix* ybuf, + /* Integer */ ae_vector* initidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nx, + ae_int_t ny, + double mergetol, + /* Real */ ae_vector* tmpboxmin, + /* Real */ ae_vector* tmpboxmax, + /* Real */ ae_matrix* xout, + /* Real */ ae_matrix* yout, + /* Integer */ ae_vector* raw2wrkmap, + /* Integer */ ae_vector* wrk2rawmap, + ae_int_t* nout, + ae_state *_state); +static void rbfv3_preprocessdataset(/* Real */ const ae_matrix* _xraw, + double mergetol, + /* Real */ const ae_matrix* _yraw, + /* Real */ const ae_vector* _xscaleraw, + ae_int_t nraw, + ae_int_t nx, + ae_int_t ny, + ae_int_t bftype, + double bfparamraw, + double lambdavraw, + /* Real */ ae_matrix* xwrk, + /* Real */ ae_matrix* ywrk, + /* Integer */ ae_vector* raw2wrkmap, + /* Integer */ ae_vector* wrk2rawmap, + ae_int_t* nwrk, + /* Real */ ae_vector* xscalewrk, + /* Real */ ae_vector* xshift, + double* bfparamwrk, + double* lambdavwrk, + double* addxrescaleaplied, + ae_state *_state); +static void rbfv3_selectglobalnodes(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + /* Integer */ const ae_vector* existingnodes, + ae_int_t nexisting, + ae_int_t nspec, + /* Integer */ ae_vector* nodes, + ae_int_t* nchosen, + double* maxdist, + ae_state *_state); +static void rbfv3_buildsimplifiedkdtree(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t reducefactor, + ae_int_t minsize, + kdtree* kdt, + ae_state *_state); +static void rbfv3_computetargetscatterdesignmatrices(/* Real */ const ae_matrix* xx, + ae_int_t ntotal, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Integer */ const ae_vector* workingnodes, + ae_int_t nwrk, + /* Integer */ const ae_vector* scatternodes, + ae_int_t nscatter, + /* Real */ ae_matrix* atwrk, + /* Real */ ae_matrix* atsctr, + ae_state *_state); +static void rbfv3_computeacbfpreconditionerbasecase(acbfbuilder* builder, + acbfbuffer* buf, + ae_int_t wrk0, + ae_int_t wrk1, + ae_state *_state); +static void rbfv3_computeacbfpreconditionerrecv2(acbfbuilder* builder, + ae_int_t wrk0, + ae_int_t wrk1, + ae_state *_state); +ae_bool _trypexec_rbfv3_computeacbfpreconditionerrecv2(acbfbuilder* builder, + ae_int_t wrk0, + ae_int_t wrk1, ae_state *_state); +static void rbfv3_computeacbfpreconditioner(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + ae_int_t aterm, + ae_int_t batchsize, + ae_int_t nglobal, + ae_int_t nlocal, + ae_int_t ncorrection, + ae_int_t correctorgrowth, + ae_int_t simplificationfactor, + double lambdav, + sparsematrix* sp, + ae_state *_state); +static void rbfv3_ddmsolverinitbasecase(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + rbf3ddmbuffer* buf, + /* Integer */ ae_vector* tgtidx, + ae_int_t tgt0, + ae_int_t tgt1, + ae_int_t nneighbors, + ae_bool dodetailedtrace, + ae_state *_state); +static void rbfv3_ddmsolverinitrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + /* Integer */ ae_vector* wrkidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_bool dodetailedtrace, + ae_state *_state); +ae_bool _trypexec_rbfv3_ddmsolverinitrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + /* Integer */ ae_vector* wrkidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_bool dodetailedtrace, ae_state *_state); +static void rbfv3_ddmsolverinit(/* Real */ const ae_matrix* x, + double rescaledby, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + ae_int_t bftype, + double bfparam, + double lambdav, + ae_int_t aterm, + const sparsematrix* sp, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_int_t ncorrector, + ae_bool dotrace, + ae_bool dodetailedtrace, + rbf3ddmsolver* solver, + ae_int_t* timeddminit, + ae_int_t* timecorrinit, + ae_state *_state); +static void rbfv3_ddmsolverrunrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* res, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + /* Real */ ae_matrix* c, + ae_int_t cnt, + ae_state *_state); +static void rbfv3_ddmsolverrun(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* res, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + const sparsematrix* sp, + rbf3evaluator* bfmatrix, + rbf3fastevaluator* fasteval, + double fastevaltol, + /* Real */ ae_matrix* upd, + ae_int_t* timeddmsolve, + ae_int_t* timecorrsolve, + ae_state *_state); +static void rbfv3_ddmsolverrun1(rbf3ddmsolver* solver, + /* Real */ const ae_vector* res, + ae_int_t n, + ae_int_t nx, + const sparsematrix* sp, + rbf3evaluator* bfmatrix, + rbf3fastevaluator* fasteval, + double fastevaltol, + /* Real */ ae_vector* upd, + ae_int_t* timeddmsolve, + ae_int_t* timecorrsolve, + ae_state *_state); +static double rbfv3_autodetectscaleparameter(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_state *_state); +static void rbfv3_computebfmatrixrec(/* Real */ const ae_matrix* xx, + ae_int_t range0, + ae_int_t range1, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, + ae_state *_state); +ae_bool _trypexec_rbfv3_computebfmatrixrec(/* Real */ const ae_matrix* xx, + ae_int_t range0, + ae_int_t range1, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, ae_state *_state); +static void rbfv3_computebfmatrix(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, + ae_state *_state); +static void rbfv3_modelmatrixinit(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + ae_int_t storagetype, + rbf3evaluator* modelmatrix, + ae_state *_state); +static void rbfv3_modelmatrixcomputepartial(const rbf3evaluator* modelmatrix, + /* Integer */ const ae_vector* ridx, + ae_int_t m0, + /* Integer */ const ae_vector* cidx, + ae_int_t m1, + /* Real */ ae_matrix* r, + ae_state *_state); +static void rbfv3_computerowchunk(const rbf3evaluator* evaluator, + /* Real */ const ae_vector* x, + rbf3evaluatorbuffer* buf, + ae_int_t chunksize, + ae_int_t chunkidx, + double distance0, + ae_int_t needgradinfo, + ae_state *_state); +static ae_bool rbfv3_iscpdfunction(ae_int_t functype, + ae_int_t aterm, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) +static double spline2d_cholreg = 1.0E-12; +static double spline2d_lambdaregblocklls = 1.0E-6; +static double spline2d_lambdaregfastddm = 1.0E-4; +static double spline2d_lambdadecay = 0.5; +static void spline2d_bicubiccalcderivatives(/* Real */ const ae_matrix* a, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* bndbtm, + ae_int_t bndtypebtm, + /* Real */ const ae_vector* bndtop, + ae_int_t bndtypetop, + /* Real */ const ae_vector* bndlft, + ae_int_t bndtypelft, + /* Real */ const ae_vector* bndrgt, + ae_int_t bndtypergt, + /* Real */ const ae_vector* dfmixed, + /* Real */ ae_matrix* dx, + /* Real */ ae_matrix* dy, + /* Real */ ae_matrix* dxy, + ae_state *_state); +static void spline2d_bicubiccalcderivativesmissing(/* Real */ const ae_matrix* a, + /* Boolean */ const ae_vector* ismissingnode, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* dx, + /* Real */ ae_matrix* dy, + /* Real */ ae_matrix* dxy, + ae_state *_state); +static ae_bool spline2d_scanfornonmissingsegment(/* Boolean */ const ae_vector* ismissing, + ae_int_t n, + ae_int_t* i1, + ae_int_t* i2, + ae_state *_state); +static void spline2d_spline2dbuildhermitevbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Real */ const ae_vector* _dfdx, + /* Real */ const ae_vector* _dfdy, + /* Real */ const ae_vector* _d2fdxdy, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +static void spline2d_generatedesignmatrix(/* Real */ const ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + ae_int_t kx, + ae_int_t ky, + double smoothing, + double lambdareg, + const spline1dinterpolant* basis1, + sparsematrix* av, + sparsematrix* ah, + ae_int_t* arows, + ae_state *_state); +static void spline2d_updatesplinetable(/* Real */ const ae_vector* z, + ae_int_t kx, + ae_int_t ky, + ae_int_t d, + const spline1dinterpolant* basis1, + ae_int_t bfrad, + /* Real */ ae_vector* ftbl, + ae_int_t m, + ae_int_t n, + ae_int_t scalexy, + ae_state *_state); +static void spline2d_fastddmfit(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + ae_int_t kx, + ae_int_t ky, + ae_int_t basecasex, + ae_int_t basecasey, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t nlayers, + double smoothing, + ae_int_t lsqrcnt, + const spline1dinterpolant* basis1, + spline2dinterpolant* spline, + spline2dfitreport* rep, + double tss, + ae_state *_state); +static void spline2d_fastddmfitlayer(/* Real */ const ae_vector* xy, + ae_int_t d, + ae_int_t scalexy, + /* Integer */ const ae_vector* xyindex, + ae_int_t basecasex, + ae_int_t tilex0, + ae_int_t tilex1, + ae_int_t tilescountx, + ae_int_t basecasey, + ae_int_t tiley0, + ae_int_t tiley1, + ae_int_t tilescounty, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t lsqrcnt, + double lambdareg, + const spline1dinterpolant* basis1, + ae_shared_pool* pool, + spline2dinterpolant* spline, + ae_state *_state); +ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real */ const ae_vector* xy, + ae_int_t d, + ae_int_t scalexy, + /* Integer */ const ae_vector* xyindex, + ae_int_t basecasex, + ae_int_t tilex0, + ae_int_t tilex1, + ae_int_t tilescountx, + ae_int_t basecasey, + ae_int_t tiley0, + ae_int_t tiley1, + ae_int_t tilescounty, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t lsqrcnt, + double lambdareg, + const spline1dinterpolant* basis1, + ae_shared_pool* pool, + spline2dinterpolant* spline, ae_state *_state); +static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign, + ae_int_t lsqrcnt, + /* Real */ ae_vector* z, + spline2dfitreport* rep, + double tss, + spline2dblockllsbuf* buf, + ae_state *_state); +static void spline2d_naivellsfit(const sparsematrix* av, + const sparsematrix* ah, + ae_int_t arows, + /* Real */ ae_vector* xy, + ae_int_t kx, + ae_int_t ky, + ae_int_t npoints, + ae_int_t d, + ae_int_t lsqrcnt, + /* Real */ ae_vector* z, + spline2dfitreport* rep, + double tss, + ae_state *_state); +static ae_int_t spline2d_getcelloffset(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + ae_int_t i, + ae_int_t j, + ae_state *_state); +static void spline2d_copycellto(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + /* Real */ const ae_matrix* blockata, + ae_int_t i, + ae_int_t j, + /* Real */ ae_matrix* dst, + ae_int_t dst0, + ae_int_t dst1, + ae_state *_state); +static void spline2d_flushtozerocell(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + /* Real */ ae_matrix* blockata, + ae_int_t i, + ae_int_t j, + double eps, + ae_state *_state); +static ae_bool spline2d_blockllscholesky(/* Real */ ae_matrix* blockata, + ae_int_t kx, + ae_int_t ky, + /* Real */ ae_matrix* trsmbuf2, + /* Real */ ae_matrix* cholbuf2, + /* Real */ ae_vector* cholbuf1, + ae_state *_state); +static void spline2d_blockllstrsv(/* Real */ const ae_matrix* blockata, + ae_int_t kx, + ae_int_t ky, + ae_bool transu, + /* Real */ ae_vector* b, + ae_state *_state); +static void spline2d_computeresidualsfromscratch(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t npoints, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_state *_state); +ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t npoints, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, ae_state *_state); +static void spline2d_computeresidualsfromscratchrec(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t pt0, + ae_int_t pt1, + ae_int_t chunksize, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_shared_pool* pool, + ae_state *_state); +ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t pt0, + ae_int_t pt1, + ae_int_t chunksize, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_shared_pool* pool, ae_state *_state); +static void spline2d_reorderdatasetandbuildindex(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + ae_int_t kx, + ae_int_t ky, + /* Integer */ ae_vector* xyindex, + /* Integer */ ae_vector* bufi, + ae_state *_state); +static void spline2d_rescaledatasetandrefineindex(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + ae_int_t kx, + ae_int_t ky, + /* Integer */ ae_vector* xyindex, + /* Integer */ ae_vector* bufi, + ae_state *_state); +static void spline2d_expandindexrows(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindexprev, + ae_int_t row0, + ae_int_t row1, + /* Integer */ ae_vector* xyindexnew, + ae_int_t kxnew, + ae_int_t kynew, + ae_bool rootcall, + ae_state *_state); +ae_bool _trypexec_spline2d_expandindexrows(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindexprev, + ae_int_t row0, + ae_int_t row1, + /* Integer */ ae_vector* xyindexnew, + ae_int_t kxnew, + ae_int_t kynew, + ae_bool rootcall, ae_state *_state); +static void spline2d_reorderdatasetandbuildindexrec(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindex, + ae_int_t idx0, + ae_int_t idx1, + ae_bool rootcall, + ae_state *_state); +ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindex, + ae_int_t idx0, + ae_int_t idx1, + ae_bool rootcall, ae_state *_state); +static void spline2d_xdesigngenerate(/* Real */ const ae_vector* xy, + /* Integer */ const ae_vector* xyindex, + ae_int_t kx0, + ae_int_t kx1, + ae_int_t kxtotal, + ae_int_t ky0, + ae_int_t ky1, + ae_int_t kytotal, + ae_int_t d, + double lambdareg, + double lambdans, + const spline1dinterpolant* basis1, + spline2dxdesignmatrix* a, + ae_state *_state); +static void spline2d_xdesignmv(spline2dxdesignmatrix* a, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static void spline2d_xdesignmtv(spline2dxdesignmatrix* a, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static void spline2d_xdesignblockata(spline2dxdesignmatrix* a, + /* Real */ ae_matrix* blockata, + double* mxata, + ae_state *_state); +static ae_bool spline2d_adjustevaluationinterval(const spline2dinterpolant* s, + double* x, + double* t, + double* dt, + ae_int_t* ix, + double* y, + double* u, + double* du, + ae_int_t* iy, + ae_state *_state); +static void spline2d_sortgrid(/* Real */ ae_vector* x, + ae_int_t n, + /* Real */ ae_vector* y, + ae_int_t m, + /* Real */ ae_vector* bndbtm, + ae_bool hasbndbtm, + /* Real */ ae_vector* bndtop, + ae_bool hasbndtop, + /* Real */ ae_vector* bndlft, + ae_bool hasbndlft, + /* Real */ ae_vector* bndrgt, + ae_bool hasbndrgt, + /* Real */ ae_vector* f, + ae_int_t d, + /* Real */ ae_vector* dfdx, + /* Real */ ae_vector* dfdy, + /* Real */ ae_vector* d2fdxdy, + ae_bool hasderivatives, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) +static double rbfv2_defaultlambdareg = 1.0E-6; +static double rbfv2_defaultsupportr = 0.10; +static ae_int_t rbfv2_defaultmaxits = 400; +static ae_int_t rbfv2_defaultbf = 1; +static ae_int_t rbfv2_maxnodesize = 6; +static double rbfv2_complexitymultiplier = 100.0; +static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + /* Real */ ae_matrix* v, + ae_state *_state); +static void rbfv2_allocatecalcbuffer(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_state *_state); +static void rbfv2_convertandappendtree(const kdtree* curtree, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + /* Integer */ ae_vector* kdnodes, + /* Real */ ae_vector* kdsplits, + /* Real */ ae_vector* cw, + ae_state *_state); +static void rbfv2_converttreerec(const kdtree* curtree, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t nodeoffset, + ae_int_t nodesbase, + ae_int_t splitsbase, + ae_int_t cwbase, + /* Integer */ ae_vector* localnodes, + ae_int_t* localnodessize, + /* Real */ ae_vector* localsplits, + ae_int_t* localsplitssize, + /* Real */ ae_vector* localcw, + ae_int_t* localcwsize, + /* Real */ ae_matrix* xybuf, + ae_state *_state); +static void rbfv2_partialcalcrec(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double invr2, + double queryr2, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_int_t needdy, + ae_state *_state); +static void rbfv2_partialrowcalcrec(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double invr2, + double rquery2, + double rfar2, + /* Real */ const ae_vector* cx, + /* Real */ const ae_vector* rx, + /* Boolean */ const ae_vector* rf, + ae_int_t rowsize, + /* Real */ ae_vector* ry, + ae_state *_state); +static void rbfv2_preparepartialquery(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + ae_int_t nx, + rbfv2calcbuffer* buf, + ae_int_t* cnt, + ae_state *_state); +static void rbfv2_partialqueryrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + ae_int_t nx, + ae_int_t ny, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double queryr2, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r2, + /* Integer */ ae_vector* offs, + ae_int_t* k, + ae_state *_state); +static ae_int_t rbfv2_partialcountrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + ae_int_t nx, + ae_int_t ny, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double queryr2, + /* Real */ const ae_vector* x, + ae_state *_state); +static void rbfv2_partialunpackrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* s, + ae_int_t nx, + ae_int_t ny, + ae_int_t rootidx, + double r, + /* Real */ ae_matrix* xwr, + ae_int_t* k, + ae_state *_state); +static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* ri, + /* Integer */ const ae_vector* kdroots, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + ae_int_t nx, + ae_int_t ny, + ae_int_t nh, + ae_int_t level, + double rcoeff, + /* Real */ ae_vector* x0, + rbfv2calcbuffer* calcbuf, + ae_state *_state); +static void rbfv2_designmatrixgeneraterow(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* ri, + /* Integer */ const ae_vector* kdroots, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + /* Integer */ const ae_vector* cwrange, + ae_int_t nx, + ae_int_t ny, + ae_int_t nh, + ae_int_t level, + ae_int_t bf, + double rcoeff, + ae_int_t rowsperpoint, + double penalty, + /* Real */ ae_vector* x0, + rbfv2calcbuffer* calcbuf, + /* Real */ ae_vector* tmpr2, + /* Integer */ ae_vector* tmpoffs, + /* Integer */ ae_vector* rowidx, + /* Real */ ae_vector* rowval, + ae_int_t* rowsize, + ae_state *_state); +static void rbfv2_zerofill(rbfv2model* s, + ae_int_t nx, + ae_int_t ny, + ae_int_t bf, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +static void spline3d_spline3ddiff(const spline3dinterpolant* c, + double x, + double y, + double z, + double* f, + double* fx, + double* fy, + double* fxy, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +static double rbf_eps = 1.0E-6; +static double rbf_rbffarradius = 6; +static ae_int_t rbf_rbffirstversion = 0; +static ae_int_t rbf_rbfversion2 = 2; +static ae_int_t rbf_rbfversion3 = 3; +static void rbf_rbfpreparenonserializablefields(rbfmodel* s, + ae_state *_state); +static void rbf_initializev1(ae_int_t nx, + ae_int_t ny, + rbfv1model* s, + ae_state *_state); +static void rbf_initializev2(ae_int_t nx, + ae_int_t ny, + rbfv2model* s, + ae_state *_state); +static void rbf_initializev3(ae_int_t nx, + ae_int_t ny, + rbfv3model* s, + ae_state *_state); +static void rbf_clearreportfields(rbfreport* rep, ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Rational interpolation using barycentric formula + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +Input parameters: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +Result: + barycentric interpolant F(t) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +double barycentriccalc(const barycentricinterpolant* b, + double t, + ae_state *_state) +{ + double s1; + double s2; + double s; + double v; + ae_int_t i; + double result; + + + ae_assert(!ae_isinf(t, _state), "BarycentricCalc: infinite T!", _state); + + /* + * special case: NaN + */ + if( ae_isnan(t, _state) ) + { + result = _state->v_nan; + return result; + } + + /* + * special case: N=1 + */ + if( b->n==1 ) + { + result = b->sy*b->y.ptr.p_double[0]; + return result; + } + + /* + * Here we assume that task is normalized, i.e.: + * 1. abs(Y[i])<=1 + * 2. abs(W[i])<=1 + * 3. X[] is ordered + */ + s = ae_fabs(t-b->x.ptr.p_double[0], _state); + for(i=0; i<=b->n-1; i++) + { + v = b->x.ptr.p_double[i]; + if( ae_fp_eq(v,t) ) + { + result = b->sy*b->y.ptr.p_double[i]; + return result; + } + v = ae_fabs(t-v, _state); + if( ae_fp_less(v,s) ) + { + s = v; + } + } + s1 = (double)(0); + s2 = (double)(0); + for(i=0; i<=b->n-1; i++) + { + v = s/(t-b->x.ptr.p_double[i]); + v = v*b->w.ptr.p_double[i]; + s1 = s1+v*b->y.ptr.p_double[i]; + s2 = s2+v; + } + result = b->sy*s1/s2; + return result; +} + + +/************************************************************************* +Differentiation of barycentric interpolant: first derivative. + +Algorithm used in this subroutine is very robust and should not fail until +provided with values too close to MaxRealNumber (usually MaxRealNumber/N +or greater will overflow). + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + +NOTE + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff1(const barycentricinterpolant* b, + double t, + double* f, + double* df, + ae_state *_state) +{ + double v; + double vv; + ae_int_t i; + ae_int_t k; + double n0; + double n1; + double d0; + double d1; + double s0; + double s1; + double xk; + double xi; + double xmin; + double xmax; + double xscale1; + double xoffs1; + double xscale2; + double xoffs2; + double xprev; + + *f = 0.0; + *df = 0.0; + + ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); + + /* + * special case: NaN + */ + if( ae_isnan(t, _state) ) + { + *f = _state->v_nan; + *df = _state->v_nan; + return; + } + + /* + * special case: N=1 + */ + if( b->n==1 ) + { + *f = b->sy*b->y.ptr.p_double[0]; + *df = (double)(0); + return; + } + if( ae_fp_eq(b->sy,(double)(0)) ) + { + *f = (double)(0); + *df = (double)(0); + return; + } + ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff1: internal error", _state); + + /* + * We assume than N>1 and B.SY>0. Find: + * 1. pivot point (X[i] closest to T) + * 2. width of interval containing X[i] + */ + v = ae_fabs(b->x.ptr.p_double[0]-t, _state); + k = 0; + xmin = b->x.ptr.p_double[0]; + xmax = b->x.ptr.p_double[0]; + for(i=1; i<=b->n-1; i++) + { + vv = b->x.ptr.p_double[i]; + if( ae_fp_less(ae_fabs(vv-t, _state),v) ) + { + v = ae_fabs(vv-t, _state); + k = i; + } + xmin = ae_minreal(xmin, vv, _state); + xmax = ae_maxreal(xmax, vv, _state); + } + + /* + * pivot point found, calculate dNumerator and dDenominator + */ + xscale1 = (double)1/(xmax-xmin); + xoffs1 = -xmin/(xmax-xmin)+(double)1; + xscale2 = (double)(2); + xoffs2 = (double)(-3); + t = t*xscale1+xoffs1; + t = t*xscale2+xoffs2; + xk = b->x.ptr.p_double[k]; + xk = xk*xscale1+xoffs1; + xk = xk*xscale2+xoffs2; + v = t-xk; + n0 = (double)(0); + n1 = (double)(0); + d0 = (double)(0); + d1 = (double)(0); + xprev = (double)(-2); + for(i=0; i<=b->n-1; i++) + { + xi = b->x.ptr.p_double[i]; + xi = xi*xscale1+xoffs1; + xi = xi*xscale2+xoffs2; + ae_assert(ae_fp_greater(xi,xprev), "BarycentricDiff1: points are too close!", _state); + xprev = xi; + if( i!=k ) + { + vv = ae_sqr(t-xi, _state); + s0 = (t-xk)/(t-xi); + s1 = (xk-xi)/vv; + } + else + { + s0 = (double)(1); + s1 = (double)(0); + } + vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; + n0 = n0+s0*vv; + n1 = n1+s1*vv; + vv = b->w.ptr.p_double[i]; + d0 = d0+s0*vv; + d1 = d1+s1*vv; + } + *f = b->sy*n0/d0; + *df = (n1*d0-n0*d1)/ae_sqr(d0, _state); + if( ae_fp_neq(*df,(double)(0)) ) + { + *df = (double)ae_sign(*df, _state)*ae_exp(ae_log(ae_fabs(*df, _state), _state)+ae_log(b->sy, _state)+ae_log(xscale1, _state)+ae_log(xscale2, _state), _state); + } +} + + +/************************************************************************* +Differentiation of barycentric interpolant: first/second derivatives. + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + D2F - second derivative + +NOTE: this algorithm may fail due to overflow/underflor if used on data +whose values are close to MaxRealNumber or MinRealNumber. Use more robust +BarycentricDiff1() subroutine in such cases. + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff2(const barycentricinterpolant* b, + double t, + double* f, + double* df, + double* d2f, + ae_state *_state) +{ + double v; + double vv; + ae_int_t i; + ae_int_t k; + double n0; + double n1; + double n2; + double d0; + double d1; + double d2; + double s0; + double s1; + double s2; + double xk; + double xi; + + *f = 0.0; + *df = 0.0; + *d2f = 0.0; + + ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state); + + /* + * special case: NaN + */ + if( ae_isnan(t, _state) ) + { + *f = _state->v_nan; + *df = _state->v_nan; + *d2f = _state->v_nan; + return; + } + + /* + * special case: N=1 + */ + if( b->n==1 ) + { + *f = b->sy*b->y.ptr.p_double[0]; + *df = (double)(0); + *d2f = (double)(0); + return; + } + if( ae_fp_eq(b->sy,(double)(0)) ) + { + *f = (double)(0); + *df = (double)(0); + *d2f = (double)(0); + return; + } + + /* + * We assume than N>1 and B.SY>0. Find: + * 1. pivot point (X[i] closest to T) + * 2. width of interval containing X[i] + */ + ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff: internal error", _state); + *f = (double)(0); + *df = (double)(0); + *d2f = (double)(0); + v = ae_fabs(b->x.ptr.p_double[0]-t, _state); + k = 0; + for(i=1; i<=b->n-1; i++) + { + vv = b->x.ptr.p_double[i]; + if( ae_fp_less(ae_fabs(vv-t, _state),v) ) + { + v = ae_fabs(vv-t, _state); + k = i; + } + } + + /* + * pivot point found, calculate dNumerator and dDenominator + */ + xk = b->x.ptr.p_double[k]; + v = t-xk; + n0 = (double)(0); + n1 = (double)(0); + n2 = (double)(0); + d0 = (double)(0); + d1 = (double)(0); + d2 = (double)(0); + for(i=0; i<=b->n-1; i++) + { + if( i!=k ) + { + xi = b->x.ptr.p_double[i]; + vv = ae_sqr(t-xi, _state); + s0 = (t-xk)/(t-xi); + s1 = (xk-xi)/vv; + s2 = -(double)2*(xk-xi)/(vv*(t-xi)); + } + else + { + s0 = (double)(1); + s1 = (double)(0); + s2 = (double)(0); + } + vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i]; + n0 = n0+s0*vv; + n1 = n1+s1*vv; + n2 = n2+s2*vv; + vv = b->w.ptr.p_double[i]; + d0 = d0+s0*vv; + d1 = d1+s1*vv; + d2 = d2+s2*vv; + } + *f = b->sy*n0/d0; + *df = b->sy*(n1*d0-n0*d1)/ae_sqr(d0, _state); + *d2f = b->sy*((n2*d0-n0*d2)*ae_sqr(d0, _state)-(n1*d0-n0*d1)*(double)2*d0*d1)/ae_sqr(ae_sqr(d0, _state), _state); +} + + +/************************************************************************* +This subroutine performs linear transformation of the argument. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: x = CA*t + CB + +OUTPUT PARAMETERS: + B - transformed interpolant with X replaced by T + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransx(barycentricinterpolant* b, + double ca, + double cb, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * special case, replace by constant F(CB) + */ + if( ae_fp_eq(ca,(double)(0)) ) + { + b->sy = barycentriccalc(b, cb, _state); + v = (double)(1); + for(i=0; i<=b->n-1; i++) + { + b->y.ptr.p_double[i] = (double)(1); + b->w.ptr.p_double[i] = v; + v = -v; + } + return; + } + + /* + * general case: CA<>0 + */ + for(i=0; i<=b->n-1; i++) + { + b->x.ptr.p_double[i] = (b->x.ptr.p_double[i]-cb)/ca; + } + if( ae_fp_less(ca,(double)(0)) ) + { + for(i=0; i<=b->n-1; i++) + { + if( in-1-i ) + { + j = b->n-1-i; + v = b->x.ptr.p_double[i]; + b->x.ptr.p_double[i] = b->x.ptr.p_double[j]; + b->x.ptr.p_double[j] = v; + v = b->y.ptr.p_double[i]; + b->y.ptr.p_double[i] = b->y.ptr.p_double[j]; + b->y.ptr.p_double[j] = v; + v = b->w.ptr.p_double[i]; + b->w.ptr.p_double[i] = b->w.ptr.p_double[j]; + b->w.ptr.p_double[j] = v; + } + else + { + break; + } + } + } +} + + +/************************************************************************* +This subroutine performs linear transformation of the barycentric +interpolant. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB + +OUTPUT PARAMETERS: + B - transformed interpolant + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransy(barycentricinterpolant* b, + double ca, + double cb, + ae_state *_state) +{ + ae_int_t i; + double v; + + + for(i=0; i<=b->n-1; i++) + { + b->y.ptr.p_double[i] = ca*b->sy*b->y.ptr.p_double[i]+cb; + } + b->sy = (double)(0); + for(i=0; i<=b->n-1; i++) + { + b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); + } + if( ae_fp_greater(b->sy,(double)(0)) ) + { + v = (double)1/b->sy; + ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); + } +} + + +/************************************************************************* +Extracts X/Y/W arrays from rational interpolant + +INPUT PARAMETERS: + B - barycentric interpolant + +OUTPUT PARAMETERS: + N - nodes count, N>0 + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricunpack(const barycentricinterpolant* b, + ae_int_t* n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* w, + ae_state *_state) +{ + double v; + + *n = 0; + ae_vector_clear(x); + ae_vector_clear(y); + ae_vector_clear(w); + + *n = b->n; + ae_vector_set_length(x, *n, _state); + ae_vector_set_length(y, *n, _state); + ae_vector_set_length(w, *n, _state); + v = b->sy; + ae_v_move(&x->ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,*n-1)); + ae_v_moved(&y->ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,*n-1), v); + ae_v_move(&w->ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,*n-1)); +} + + +/************************************************************************* +Rational interpolant from X/Y/W arrays + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +INPUT PARAMETERS: + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + N - nodes count, N>0 + +OUTPUT PARAMETERS: + B - barycentric interpolant built from (X, Y, W) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildxyw(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + barycentricinterpolant* b, + ae_state *_state) +{ + + _barycentricinterpolant_clear(b); + + ae_assert(n>0, "BarycentricBuildXYW: incorrect N!", _state); + + /* + * fill X/Y/W + */ + ae_vector_set_length(&b->x, n, _state); + ae_vector_set_length(&b->y, n, _state); + ae_vector_set_length(&b->w, n, _state); + ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&b->w.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); + b->n = n; + + /* + * Normalize + */ + ratint_barycentricnormalize(b, _state); +} + + +/************************************************************************* +Rational interpolant without poles + +The subroutine constructs the rational interpolating function without real +poles (see 'Barycentric rational interpolation with no poles and high +rates of approximation', Michael S. Floater. and Kai Hormann, for more +information on this subject). + +Input parameters: + X - interpolation nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of nodes, N>0. + D - order of the interpolation scheme, 0 <= D <= N-1. + D<0 will cause an error. + D>=N it will be replaced with D=N-1. + if you don't know what D to choose, use small value about 3-5. + +Output parameters: + B - barycentric interpolant. + +Note: + this algorithm always succeeds and calculates the weights with close + to machine precision. + + -- ALGLIB PROJECT -- + Copyright 17.06.2007 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildfloaterhormann(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t d, + barycentricinterpolant* b, + ae_state *_state) +{ + ae_frame _frame_block; + double s0; + double s; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector perm; + ae_vector wtemp; + ae_vector sortrbuf; + ae_vector sortrbuf2; + + ae_frame_make(_state, &_frame_block); + memset(&perm, 0, sizeof(perm)); + memset(&wtemp, 0, sizeof(wtemp)); + memset(&sortrbuf, 0, sizeof(sortrbuf)); + memset(&sortrbuf2, 0, sizeof(sortrbuf2)); + _barycentricinterpolant_clear(b); + ae_vector_init(&perm, 0, DT_INT, _state, ae_true); + ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "BarycentricFloaterHormann: N<=0!", _state); + ae_assert(d>=0, "BarycentricFloaterHormann: incorrect D!", _state); + + /* + * Prepare + */ + if( d>n-1 ) + { + d = n-1; + } + b->n = n; + + /* + * special case: N=1 + */ + if( n==1 ) + { + ae_vector_set_length(&b->x, n, _state); + ae_vector_set_length(&b->y, n, _state); + ae_vector_set_length(&b->w, n, _state); + b->x.ptr.p_double[0] = x->ptr.p_double[0]; + b->y.ptr.p_double[0] = y->ptr.p_double[0]; + b->w.ptr.p_double[0] = (double)(1); + ratint_barycentricnormalize(b, _state); + ae_frame_leave(_state); + return; + } + + /* + * Fill X/Y + */ + ae_vector_set_length(&b->x, n, _state); + ae_vector_set_length(&b->y, n, _state); + ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + tagsortfastr(&b->x, &b->y, &sortrbuf, &sortrbuf2, n, _state); + + /* + * Calculate Wk + */ + ae_vector_set_length(&b->w, n, _state); + s0 = (double)(1); + for(k=1; k<=d; k++) + { + s0 = -s0; + } + for(k=0; k<=n-1; k++) + { + + /* + * Wk + */ + s = (double)(0); + for(i=ae_maxint(k-d, 0, _state); i<=ae_minint(k, n-1-d, _state); i++) + { + v = (double)(1); + for(j=i; j<=i+d; j++) + { + if( j!=k ) + { + v = v/ae_fabs(b->x.ptr.p_double[k]-b->x.ptr.p_double[j], _state); + } + } + s = s+v; + } + b->w.ptr.p_double[k] = s0*s; + + /* + * Next S0 + */ + s0 = -s0; + } + + /* + * Normalize + */ + ratint_barycentricnormalize(b, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Copying of the barycentric interpolant (for internal use only) + +INPUT PARAMETERS: + B - barycentric interpolant + +OUTPUT PARAMETERS: + B2 - copy(B1) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriccopy(const barycentricinterpolant* b, + barycentricinterpolant* b2, + ae_state *_state) +{ + + _barycentricinterpolant_clear(b2); + + b2->n = b->n; + b2->sy = b->sy; + ae_vector_set_length(&b2->x, b2->n, _state); + ae_vector_set_length(&b2->y, b2->n, _state); + ae_vector_set_length(&b2->w, b2->n, _state); + ae_v_move(&b2->x.ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); + ae_v_move(&b2->y.ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); + ae_v_move(&b2->w.ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,b2->n-1)); +} + + +/************************************************************************* +Normalization of barycentric interpolant: +* B.N, B.X, B.Y and B.W are initialized +* B.SY is NOT initialized +* Y[] is normalized, scaling coefficient is stored in B.SY +* W[] is normalized, no scaling coefficient is stored +* X[] is sorted + +Internal subroutine. +*************************************************************************/ +static void ratint_barycentricnormalize(barycentricinterpolant* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector p1; + ae_vector p2; + ae_int_t i; + ae_int_t j; + ae_int_t j2; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * Normalize task: |Y|<=1, |W|<=1, sort X[] + */ + b->sy = (double)(0); + for(i=0; i<=b->n-1; i++) + { + b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state); + } + if( ae_fp_greater(b->sy,(double)(0))&&ae_fp_greater(ae_fabs(b->sy-(double)1, _state),(double)10*ae_machineepsilon) ) + { + v = (double)1/b->sy; + ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); + } + v = (double)(0); + for(i=0; i<=b->n-1; i++) + { + v = ae_maxreal(v, ae_fabs(b->w.ptr.p_double[i], _state), _state); + } + if( ae_fp_greater(v,(double)(0))&&ae_fp_greater(ae_fabs(v-(double)1, _state),(double)10*ae_machineepsilon) ) + { + v = (double)1/v; + ae_v_muld(&b->w.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); + } + for(i=0; i<=b->n-2; i++) + { + if( ae_fp_less(b->x.ptr.p_double[i+1],b->x.ptr.p_double[i]) ) + { + tagsort(&b->x, b->n, &p1, &p2, _state); + for(j=0; j<=b->n-1; j++) + { + j2 = p2.ptr.p_int[j]; + v = b->y.ptr.p_double[j]; + b->y.ptr.p_double[j] = b->y.ptr.p_double[j2]; + b->y.ptr.p_double[j2] = v; + v = b->w.ptr.p_double[j]; + b->w.ptr.p_double[j] = b->w.ptr.p_double[j2]; + b->w.ptr.p_double[j2] = v; + } + break; + } + } + ae_frame_leave(_state); +} + + +void _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + barycentricinterpolant *p = (barycentricinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic); +} + + +void _barycentricinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + barycentricinterpolant *dst = (barycentricinterpolant*)_dst; + const barycentricinterpolant *src = (const barycentricinterpolant*)_src; + dst->n = src->n; + dst->sy = src->sy; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic); +} + + +void _barycentricinterpolant_clear(void* _p) +{ + barycentricinterpolant *p = (barycentricinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->w); +} + + +void _barycentricinterpolant_destroy(void* _p) +{ + barycentricinterpolant *p = (barycentricinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->w); +} + + +#endif +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel IDW model evaluations (with one IDW model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with idwtscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create IDW model structure or load it from file +* call idwcreatecalcbuffer(), once per thread working with IDW model (you + should call this function only AFTER model initialization, see below for + more information) +* call idwtscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - IDW model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with IDW model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of the IDW structure. + +IMPORTANT: you should call this function only for model which was built + with model builder (or unserialized from file). Sizes of some + internal structures are determined only after model is built, + so buffer object created before model construction stage will + be useless (and any attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 22.10.2018 by Sergey Bochkanov +*************************************************************************/ +void idwcreatecalcbuffer(const idwmodel* s, + idwcalcbuffer* buf, + ae_state *_state) +{ + + _idwcalcbuffer_clear(buf); + + ae_assert(s->nx>=1, "IDWCreateCalcBuffer: integrity check failed", _state); + ae_assert(s->ny>=1, "IDWCreateCalcBuffer: integrity check failed", _state); + ae_assert(s->nlayers>=0, "IDWCreateCalcBuffer: integrity check failed", _state); + ae_assert(s->algotype>=0, "IDWCreateCalcBuffer: integrity check failed", _state); + if( s->nlayers>=1&&s->algotype!=0 ) + { + kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state); + } + rvectorsetlengthatleast(&buf->x, s->nx, _state); + rvectorsetlengthatleast(&buf->y, s->ny, _state); + rvectorsetlengthatleast(&buf->tsyw, s->ny*ae_maxint(s->nlayers, 1, _state), _state); + rvectorsetlengthatleast(&buf->tsw, ae_maxint(s->nlayers, 1, _state), _state); +} + + +/************************************************************************* +This subroutine creates builder object used to generate IDW model from +irregularly sampled (scattered) dataset. Multidimensional scalar/vector- +-valued are supported. + +Builder object is used to fit model to data as follows: +* builder object is created with idwbuildercreate() function +* dataset is added with idwbuildersetpoints() function +* one of the modern IDW algorithms is chosen with either: + * idwbuildersetalgomstab() - Multilayer STABilized algorithm (interpolation) + Alternatively, one of the textbook algorithms can be chosen (not recommended): + * idwbuildersetalgotextbookshepard() - textbook Shepard algorithm + * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm +* finally, model construction is performed with idwfit() function. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + NX - dimensionality of the argument, NX>=1 + NY - dimensionality of the function being modeled, NY>=1; + NY=1 corresponds to classic scalar function, NY>=1 corresponds + to vector-valued function. + +OUTPUT PARAMETERS: + State- builder object + + -- ALGLIB PROJECT -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildercreate(ae_int_t nx, + ae_int_t ny, + idwbuilder* state, + ae_state *_state) +{ + + _idwbuilder_clear(state); + + ae_assert(nx>=1, "IDWBuilderCreate: NX<=0", _state); + ae_assert(ny>=1, "IDWBuilderCreate: NY<=0", _state); + + /* + * We choose reasonable defaults for the algorithm: + * * MSTAB algorithm + * * 12 layers + * * default radius + * * default Lambda0 + */ + state->algotype = 2; + state->priortermtype = 2; + rvectorsetlengthatleast(&state->priortermval, ny, _state); + state->nlayers = idw_defaultnlayers; + state->r0 = (double)(0); + state->rdecay = 0.5; + state->lambda0 = idw_defaultlambda0; + state->lambdalast = (double)(0); + state->lambdadecay = 1.0; + state->debugprofile = ae_false; + + /* + * Other parameters, not used but initialized + */ + state->shepardp = (double)(0); + + /* + * Initial dataset is empty + */ + state->npoints = 0; + state->nx = nx; + state->ny = ny; + + /* + * Initial progress is zero + */ + state->mprogress = (double)(0); +} + + +/************************************************************************* +This function changes number of layers used by IDW-MSTAB algorithm. + +The more layers you have, the finer details can be reproduced with IDW +model. The less layers you have, the less memory and CPU time is consumed +by the model. + +Memory consumption grows linearly with layers count, running time grows +sub-linearly. + +The default number of layers is 16, which allows you to reproduce details +at distance down to SRad/65536. You will rarely need to change it. + +INPUT PARAMETERS: + State - builder object + NLayers - NLayers>=1, the number of layers used by the model. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetnlayers(idwbuilder* state, + ae_int_t nlayers, + ae_state *_state) +{ + + + ae_assert(nlayers>=1, "IDWBuilderSetNLayers: N<1", _state); + state->nlayers = nlayers; +} + + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + State - builder object + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset, N>=0. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetpoints(idwbuilder* state, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ew; + + + ae_assert(n>=0, "IDWBuilderSetPoints: N<0", _state); + ae_assert(xy->rows>=n, "IDWBuilderSetPoints: Rows(XY)cols>=state->nx+state->ny, "IDWBuilderSetPoints: Cols(XY)nx+state->ny, _state), "IDWBuilderSetPoints: XY contains infinite or NaN values!", _state); + state->npoints = n; + ew = state->nx+state->ny; + rvectorsetlengthatleast(&state->xy, n*ew, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ew-1; j++) + { + state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function sets IDW model construction algorithm to the Multilayer +Stabilized IDW method (IDW-MSTAB), a latest incarnation of the inverse +distance weighting interpolation which fixes shortcomings of the original +and modified Shepard's variants. + +The distinctive features of IDW-MSTAB are: +1) exact interpolation is pursued (as opposed to fitting and noise + suppression) +2) improved robustness when compared with that of other algorithms: + * MSTAB shows almost no strange fitting artifacts like ripples and + sharp spikes (unlike N-dimensional splines and HRBFs) + * MSTAB does not return function values far from the interval spanned + by the dataset; say, if all your points have |f|<=1, you can be sure + that model value won't deviate too much from [-1,+1] +3) good model construction time competing with that of HRBFs and bicubic + splines +4) ability to work with any number of dimensions, starting from NX=1 + +The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are: +1) dependence of the model evaluation time on the search radius +2) bad extrapolation properties, models built by this method are usually + conservative in their predictions + +Thus, IDW-MSTAB is a good "default" option if you want to perform +scattered multidimensional interpolation. Although it has its drawbacks, +it is easy to use and robust, which makes it a good first step. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + SRad - initial search radius, SRad>0 is required. A model value + is obtained by "smart" averaging of the dataset points + within search radius. + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + +NOTE 2: the memory requirements for model storage are O(NPoints*NLayers). + The model construction needs twice as much memory as model storage. + +NOTE 3: by default 16 IDW layers are built which is enough for most cases. + You can change this parameter with idwbuildersetnlayers() method. + Larger values may be necessary if you need to reproduce extrafine + details at distances smaller than SRad/65536. Smaller value may + be necessary if you have to save memory and computing time, and + ready to sacrifice some model quality. + + +ALGORITHM DESCRIPTION + +ALGLIB implementation of IDW is somewhat similar to the modified Shepard's +method (one with search radius R) but overcomes several of its drawbacks, +namely: +1) a tendency to show stepwise behavior for uniform datasets +2) a tendency to show terrible interpolation properties for highly + nonuniform datasets which often arise in geospatial tasks + (function values are densely sampled across multiple separated + "tracks") + +IDW-MSTAB method performs several passes over dataset and builds a sequence +of progressively refined IDW models (layers), which starts from one with +largest search radius SRad and continues to smaller search radii until +required number of layers is built. Highest layers reproduce global +behavior of the target function at larger distances whilst lower layers +reproduce fine details at smaller distances. + +Each layer is an IDW model built with following modifications: +* weights go to zero when distance approach to the current search radius +* an additional regularizing term is added to the distance: w=1/(d^2+lambda) +* an additional fictional term with unit weight and zero function value is + added in order to promote continuity properties at the isolated and + boundary points + +By default, 16 layers is built, which is enough for most cases. You can +change this parameter with idwbuildersetnlayers() method. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgomstab(idwbuilder* state, + double srad, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(srad, _state), "IDWBuilderSetAlgoMSTAB: SRad is not finite", _state); + ae_assert(ae_fp_greater(srad,(double)(0)), "IDWBuilderSetAlgoMSTAB: SRad<=0", _state); + + /* + * Set algorithm + */ + state->algotype = 2; + + /* + * Set options + */ + state->r0 = srad; + state->rdecay = 0.5; + state->lambda0 = idw_defaultlambda0; + state->lambdalast = (double)(0); + state->lambdadecay = 1.0; +} + + +/************************************************************************* +This function sets IDW model construction algorithm to the textbook +Shepard's algorithm with custom (user-specified) power parameter. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + P - power parameter, P>0; good value to start with is 2.0 + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookshepard(idwbuilder* state, + double p, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(p, _state), "IDWBuilderSetAlgoShepard: P is not finite", _state); + ae_assert(ae_fp_greater(p,(double)(0)), "IDWBuilderSetAlgoShepard: P<=0", _state); + + /* + * Set algorithm and options + */ + state->algotype = 0; + state->shepardp = p; +} + + +/************************************************************************* +This function sets IDW model construction algorithm to the 'textbook' +modified Shepard's algorithm with user-specified search radius. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + R - search radius + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookmodshepard(idwbuilder* state, + double r, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(r, _state), "IDWBuilderSetAlgoModShepard: R is not finite", _state); + ae_assert(ae_fp_greater(r,(double)(0)), "IDWBuilderSetAlgoModShepard: R<=0", _state); + + /* + * Set algorithm and options + */ + state->algotype = 1; + state->r0 = r; +} + + +/************************************************************************* +This function sets prior term (model value at infinity) as user-specified +value. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + +NOTE: for vector-valued models all components of the prior are set to same + user-specified value + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetuserterm(idwbuilder* state, double v, ae_state *_state) +{ + ae_int_t j; + + + ae_assert(ae_isfinite(v, _state), "IDWBuilderSetUserTerm: infinite/NAN value passed", _state); + state->priortermtype = 0; + for(j=0; j<=state->ny-1; j++) + { + state->priortermval.ptr.p_double[j] = v; + } +} + + +/************************************************************************* +This function sets constant prior term (model value at infinity). + +Constant prior term is determined as mean value over dataset. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetconstterm(idwbuilder* state, ae_state *_state) +{ + + + state->priortermtype = 2; +} + + +/************************************************************************* +This function sets zero prior term (model value at infinity). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetzeroterm(idwbuilder* state, ae_state *_state) +{ + + + state->priortermtype = 3; +} + + +/************************************************************************* +IDW interpolation: scalar target, 1-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0 - argument value + +Result: + IDW interpolant S(X0) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc1(idwmodel* s, double x0, ae_state *_state) +{ + double result; + + + ae_assert(s->nx==1, "IDWCalc1: S.NX<>1", _state); + ae_assert(s->ny==1, "IDWCalc1: S.NY<>1", _state); + ae_assert(ae_isfinite(x0, _state), "IDWCalc1: X0 is INF or NAN", _state); + s->buffer.x.ptr.p_double[0] = x0; + idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state); + result = s->buffer.y.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +IDW interpolation: scalar target, 2-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0, X1 - argument value + +Result: + IDW interpolant S(X0,X1) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc2(idwmodel* s, double x0, double x1, ae_state *_state) +{ + double result; + + + ae_assert(s->nx==2, "IDWCalc2: S.NX<>2", _state); + ae_assert(s->ny==1, "IDWCalc2: S.NY<>1", _state); + ae_assert(ae_isfinite(x0, _state), "IDWCalc2: X0 is INF or NAN", _state); + ae_assert(ae_isfinite(x1, _state), "IDWCalc2: X1 is INF or NAN", _state); + s->buffer.x.ptr.p_double[0] = x0; + s->buffer.x.ptr.p_double[1] = x1; + idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state); + result = s->buffer.y.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +IDW interpolation: scalar target, 3-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0,X1,X2- argument value + +Result: + IDW interpolant S(X0,X1,X2) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc3(idwmodel* s, + double x0, + double x1, + double x2, + ae_state *_state) +{ + double result; + + + ae_assert(s->nx==3, "IDWCalc3: S.NX<>3", _state); + ae_assert(s->ny==1, "IDWCalc3: S.NY<>1", _state); + ae_assert(ae_isfinite(x0, _state), "IDWCalc3: X0 is INF or NAN", _state); + ae_assert(ae_isfinite(x1, _state), "IDWCalc3: X1 is INF or NAN", _state); + ae_assert(ae_isfinite(x2, _state), "IDWCalc3: X2 is INF or NAN", _state); + s->buffer.x.ptr.p_double[0] = x0; + s->buffer.x.ptr.p_double[1] = x1; + s->buffer.x.ptr.p_double[2] = x2; + idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state); + result = s->buffer.y.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use idwcalc1(), +idwcalc2() or idwcalc3(). + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and will be + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use idwcalcbuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalc(idwmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + idwtscalcbuf(s, &s->buffer, x, y, _state); +} + + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +Same as idwcalc(), but does not reallocate Y when in is large enough to +store function values. + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalcbuf(idwmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + idwtscalcbuf(s, &s->buffer, x, y, _state); +} + + +/************************************************************************* +This function calculates values of the IDW model at the given point, using +external buffer object (internal temporaries of IDW model are not +modified). + +This function allows to use same IDW model object in different threads, +assuming that different threads use different instances of the buffer +structure. + +INPUT PARAMETERS: + S - IDW model, may be shared between different threads + Buf - buffer object created for this particular instance of IDW + model with idwcreatecalcbuffer(). + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void idwtscalcbuf(const idwmodel* s, + idwcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ew; + ae_int_t k; + ae_int_t layeridx; + ae_int_t nx; + ae_int_t ny; + ae_int_t npoints; + double v; + double vv; + double f; + double p; + double r; + double eps; + double lambdacur; + double lambdadecay; + double invrdecay; + double invr; + ae_bool fastcalcpossible; + double wf0; + double ws0; + double wf1; + double ws1; + + + nx = s->nx; + ny = s->ny; + ae_assert(x->cnt>=nx, "IDWTsCalcBuf: Length(X)cntnlayers==0 ) + { + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = s->globalprior.ptr.p_double[j]; + } + return; + } + + /* + * Textbook Shepard's method + */ + if( s->algotype==0 ) + { + npoints = s->npoints; + ae_assert(npoints>0, "IDWTsCalcBuf: integrity check failed", _state); + eps = 1.0E-50; + ew = nx+ny; + p = s->shepardp; + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = (double)(0); + buf->tsyw.ptr.p_double[j] = eps; + } + for(i=0; i<=npoints-1; i++) + { + + /* + * Compute squared distance + */ + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + vv = s->shepardxy.ptr.p_double[i*ew+j]-x->ptr.p_double[j]; + v = v+vv*vv; + } + + /* + * Compute weight (with small regularizing addition) + */ + v = ae_pow(v, p*0.5, _state); + v = (double)1/(eps+v); + + /* + * Accumulate + */ + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+v*s->shepardxy.ptr.p_double[i*ew+nx+j]; + buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v; + } + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j]; + } + return; + } + + /* + * Textbook modified Shepard's method + */ + if( s->algotype==1 ) + { + eps = 1.0E-50; + r = s->r0; + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = (double)(0); + buf->tsyw.ptr.p_double[j] = eps; + } + k = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, x, r, ae_true, _state); + kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state); + kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state); + for(i=0; i<=k-1; i++) + { + v = buf->tsdist.ptr.p_double[i]; + v = (r-v)/(r*v+eps); + v = v*v; + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+v*buf->tsxy.ptr.pp_double[i][nx+j]; + buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v; + } + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j]; + } + return; + } + + /* + * MSTAB + */ + if( s->algotype==2 ) + { + ae_assert(ae_fp_eq(idw_w0,(double)(1)), "IDWTsCalcBuf: unexpected W0, integrity check failed", _state); + invrdecay = (double)1/s->rdecay; + invr = (double)1/s->r0; + lambdadecay = s->lambdadecay; + fastcalcpossible = (ny==1&&s->nlayers>=3)&&ae_fp_eq(lambdadecay,(double)(1)); + if( fastcalcpossible ) + { + + /* + * Important special case, NY=1, no lambda-decay, + * we can perform optimized fast evaluation + */ + wf0 = (double)(0); + ws0 = idw_w0; + wf1 = (double)(0); + ws1 = idw_w0; + for(j=0; j<=s->nlayers-1; j++) + { + buf->tsyw.ptr.p_double[j] = (double)(0); + buf->tsw.ptr.p_double[j] = idw_w0; + } + } + else + { + + /* + * Setup variables for generic evaluation path + */ + for(j=0; j<=ny*s->nlayers-1; j++) + { + buf->tsyw.ptr.p_double[j] = (double)(0); + } + for(j=0; j<=s->nlayers-1; j++) + { + buf->tsw.ptr.p_double[j] = idw_w0; + } + } + k = kdtreetsqueryrnnu(&s->tree, &buf->requestbuffer, x, s->r0, ae_true, _state); + kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state); + kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state); + for(i=0; i<=k-1; i++) + { + lambdacur = s->lambda0; + vv = buf->tsdist.ptr.p_double[i]*invr; + if( fastcalcpossible ) + { + + /* + * Important special case, fast evaluation possible + */ + v = vv*vv; + v = ((double)1-v)*((double)1-v)/(v+lambdacur); + f = buf->tsxy.ptr.pp_double[i][nx+0]; + wf0 = wf0+v*f; + ws0 = ws0+v; + vv = vv*invrdecay; + if( vv>=1.0 ) + { + continue; + } + v = vv*vv; + v = ((double)1-v)*((double)1-v)/(v+lambdacur); + f = buf->tsxy.ptr.pp_double[i][nx+1]; + wf1 = wf1+v*f; + ws1 = ws1+v; + vv = vv*invrdecay; + if( vv>=1.0 ) + { + continue; + } + for(layeridx=2; layeridx<=s->nlayers-1; layeridx++) + { + if( layeridx==s->nlayers-1 ) + { + lambdacur = s->lambdalast; + } + v = vv*vv; + v = ((double)1-v)*((double)1-v)/(v+lambdacur); + f = buf->tsxy.ptr.pp_double[i][nx+layeridx]; + buf->tsyw.ptr.p_double[layeridx] = buf->tsyw.ptr.p_double[layeridx]+v*f; + buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v; + vv = vv*invrdecay; + if( vv>=1.0 ) + { + break; + } + } + } + else + { + + /* + * General case + */ + for(layeridx=0; layeridx<=s->nlayers-1; layeridx++) + { + if( layeridx==s->nlayers-1 ) + { + lambdacur = s->lambdalast; + } + if( vv>=1.0 ) + { + break; + } + v = vv*vv; + v = ((double)1-v)*((double)1-v)/(v+lambdacur); + for(j=0; j<=ny-1; j++) + { + f = buf->tsxy.ptr.pp_double[i][nx+layeridx*ny+j]; + buf->tsyw.ptr.p_double[layeridx*ny+j] = buf->tsyw.ptr.p_double[layeridx*ny+j]+v*f; + } + buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v; + lambdacur = lambdacur*lambdadecay; + vv = vv*invrdecay; + } + } + } + if( fastcalcpossible ) + { + + /* + * Important special case, finalize evaluations + */ + buf->tsyw.ptr.p_double[0] = wf0; + buf->tsw.ptr.p_double[0] = ws0; + buf->tsyw.ptr.p_double[1] = wf1; + buf->tsw.ptr.p_double[1] = ws1; + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = s->globalprior.ptr.p_double[j]; + } + for(layeridx=0; layeridx<=s->nlayers-1; layeridx++) + { + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+buf->tsyw.ptr.p_double[layeridx*ny+j]/buf->tsw.ptr.p_double[layeridx]; + } + } + return; + } + + /* + * + */ + ae_assert(ae_false, "IDWTsCalcBuf: unexpected AlgoType", _state); +} + + +/************************************************************************* +This function fits IDW model to the dataset using current IDW construction +algorithm. A model being built and fitting report are returned. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + +OUTPUT PARAMETERS: + Model - an IDW model built with current algorithm + Rep - model fitting report, fields of this structure contain + information about average fitting errors. + +NOTE: although IDW-MSTAB algorithm is an interpolation method, i.e. it + tries to fit the model exactly, it can handle datasets with non- + distinct points which can not be fit exactly; in such cases least- + squares fitting is performed. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwfit(idwbuilder* state, + idwmodel* model, + idwreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t layeridx; + double v; + ae_int_t npoints; + ae_int_t nx; + ae_int_t ny; + double rss; + double tss; + mstabbuffer mbuffer; + ae_shared_pool mbpool; + ae_vector layerrad; + ae_vector layerlambda; + ae_vector querycosts; + double totalcost; + + ae_frame_make(_state, &_frame_block); + memset(&mbuffer, 0, sizeof(mbuffer)); + memset(&mbpool, 0, sizeof(mbpool)); + memset(&layerrad, 0, sizeof(layerrad)); + memset(&layerlambda, 0, sizeof(layerlambda)); + memset(&querycosts, 0, sizeof(querycosts)); + _idwmodel_clear(model); + _idwreport_clear(rep); + _mstabbuffer_init(&mbuffer, _state, ae_true); + ae_shared_pool_init(&mbpool, _state, ae_true); + ae_vector_init(&layerrad, 0, DT_REAL, _state, ae_true); + ae_vector_init(&layerlambda, 0, DT_REAL, _state, ae_true); + ae_vector_init(&querycosts, 0, DT_REAL, _state, ae_true); + + nx = state->nx; + ny = state->ny; + npoints = state->npoints; + + /* + * Clear report fields + */ + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rep->r2 = 1.0; + state->mprogress = (double)(0); + + /* + * Quick exit for empty dataset + */ + if( state->npoints==0 ) + { + model->nx = nx; + model->ny = ny; + ae_vector_set_length(&model->globalprior, ny, _state); + for(i=0; i<=ny-1; i++) + { + model->globalprior.ptr.p_double[i] = (double)(0); + } + model->algotype = 0; + model->nlayers = 0; + model->r0 = (double)(1); + model->rdecay = 0.5; + model->lambda0 = (double)(0); + model->lambdalast = (double)(0); + model->lambdadecay = (double)(1); + model->shepardp = (double)(2); + model->npoints = 0; + model->debugprofile = ae_false; + idwcreatecalcbuffer(model, &model->buffer, _state); + state->mprogress = 1.0; + ae_frame_leave(_state); + return; + } + + /* + * Compute temporaries which will be required later: + * * global mean + */ + ae_assert(state->npoints>0, "IDWFit: integrity check failed", _state); + rvectorsetlengthatleast(&state->tmpmean, ny, _state); + for(j=0; j<=ny-1; j++) + { + state->tmpmean.ptr.p_double[j] = (double)(0); + } + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=ny-1; j++) + { + state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]+state->xy.ptr.p_double[i*(nx+ny)+nx+j]; + } + } + for(j=0; j<=ny-1; j++) + { + state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]/(double)npoints; + } + + /* + * Compute global prior + * + * NOTE: for original Shepard's method it is always mean value + */ + rvectorsetlengthatleast(&model->globalprior, ny, _state); + for(j=0; j<=ny-1; j++) + { + model->globalprior.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]; + } + if( state->algotype!=0 ) + { + + /* + * Algorithm is set to one of the "advanced" versions with search + * radius which can handle non-mean prior term + */ + if( state->priortermtype==0 ) + { + + /* + * User-specified prior + */ + for(j=0; j<=ny-1; j++) + { + model->globalprior.ptr.p_double[j] = state->priortermval.ptr.p_double[j]; + } + } + if( state->priortermtype==3 ) + { + + /* + * Zero prior + */ + for(j=0; j<=ny-1; j++) + { + model->globalprior.ptr.p_double[j] = (double)(0); + } + } + } + + /* + * Textbook Shepard + */ + if( state->algotype==0 ) + { + + /* + * Initialize model + */ + model->algotype = 0; + model->nx = nx; + model->ny = ny; + model->nlayers = 1; + model->r0 = (double)(1); + model->rdecay = 0.5; + model->lambda0 = (double)(0); + model->lambdalast = (double)(0); + model->lambdadecay = (double)(1); + model->shepardp = state->shepardp; + model->debugprofile = ae_false; + + /* + * Copy dataset + */ + rvectorsetlengthatleast(&model->shepardxy, npoints*(nx+ny), _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nx-1; j++) + { + model->shepardxy.ptr.p_double[i*(nx+ny)+j] = state->xy.ptr.p_double[i*(nx+ny)+j]; + } + for(j=0; j<=ny-1; j++) + { + model->shepardxy.ptr.p_double[i*(nx+ny)+nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j]; + } + } + model->npoints = npoints; + + /* + * Prepare internal buffer + * Evaluate report fields + */ + idwcreatecalcbuffer(model, &model->buffer, _state); + idw_errormetricsviacalc(state, model, rep, _state); + state->mprogress = 1.0; + ae_frame_leave(_state); + return; + } + + /* + * Textbook modified Shepard's method + */ + if( state->algotype==1 ) + { + + /* + * Initialize model + */ + model->algotype = 1; + model->nx = nx; + model->ny = ny; + model->nlayers = 1; + model->r0 = state->r0; + model->rdecay = (double)(1); + model->lambda0 = (double)(0); + model->lambdalast = (double)(0); + model->lambdadecay = (double)(1); + model->shepardp = (double)(0); + model->debugprofile = ae_false; + + /* + * Build kd-tree search structure + */ + rmatrixsetlengthatleast(&state->tmpxy, npoints, nx+ny, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nx-1; j++) + { + state->tmpxy.ptr.pp_double[i][j] = state->xy.ptr.p_double[i*(nx+ny)+j]; + } + for(j=0; j<=ny-1; j++) + { + state->tmpxy.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j]; + } + } + kdtreebuild(&state->tmpxy, npoints, nx, ny, 2, &model->tree, _state); + + /* + * Prepare internal buffer + * Evaluate report fields + */ + idwcreatecalcbuffer(model, &model->buffer, _state); + idw_errormetricsviacalc(state, model, rep, _state); + state->mprogress = 1.0; + ae_frame_leave(_state); + return; + } + + /* + * MSTAB algorithm + */ + if( state->algotype==2 ) + { + ae_assert(state->nlayers>=1, "IDWFit: integrity check failed", _state); + + /* + * Initialize model + */ + model->algotype = 2; + model->nx = nx; + model->ny = ny; + model->nlayers = state->nlayers; + model->r0 = state->r0; + model->rdecay = 0.5; + model->lambda0 = state->lambda0; + model->lambdadecay = 1.0; + model->lambdalast = idw_meps; + model->shepardp = (double)(0); + model->debugprofile = ae_false; + + /* + * Build kd-tree search structure, + * prepare input residuals for the first layer of the model + */ + rmatrixsetlengthatleast(&state->tmpxy, npoints, nx, _state); + rmatrixsetlengthatleast(&state->tmplayers, npoints, nx+ny*(state->nlayers+1), _state); + ivectorsetlengthatleast(&state->tmptags, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nx-1; j++) + { + v = state->xy.ptr.p_double[i*(nx+ny)+j]; + state->tmpxy.ptr.pp_double[i][j] = v; + state->tmplayers.ptr.pp_double[i][j] = v; + } + state->tmptags.ptr.p_int[i] = i; + for(j=0; j<=ny-1; j++) + { + state->tmplayers.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j]; + } + } + kdtreebuildtagged(&state->tmpxy, &state->tmptags, npoints, nx, 0, 2, &state->tmptree, _state); + + /* + * Evaluate per-layer parameters: + * * query radius R + * * smoothing parameter Lambda + * * cost of a R-nn query (the biggest part of the model evaluation) + * + * Set global fields depending on the profile and cost of computations. + */ + rallocv(state->nlayers, &layerrad, _state); + rallocv(state->nlayers, &layerlambda, _state); + rallocv(state->nlayers, &querycosts, _state); + totalcost = (double)(0); + for(layeridx=0; layeridx<=state->nlayers-1; layeridx++) + { + + /* + * Determine layer metrics + */ + layerrad.ptr.p_double[layeridx] = model->r0*ae_pow(model->rdecay, (double)(layeridx), _state); + layerlambda.ptr.p_double[layeridx] = model->lambda0*ae_pow(model->lambdadecay, (double)(layeridx), _state); + if( layeridx==state->nlayers-1 ) + { + layerlambda.ptr.p_double[layeridx] = model->lambdalast; + } + querycosts.ptr.p_double[layeridx] = kdtreeapproxrnnquerycost(&state->tmptree, layerrad.ptr.p_double[layeridx], _state); + totalcost = totalcost+querycosts.ptr.p_double[layeridx]*(double)npoints; + } + if( state->debugprofile ) + { + + /* + * Use debug profile for the model construction + */ + state->mbatchsize = 1+ae_randominteger(3, _state); + } + else + { + + /* + * Use performance profile for the model construction + */ + state->mbatchsize = idw_idwbatchsize; + } + + /* + * Prepare temporary buffer for MSTABBasecase + */ + rallocv(nx, &mbuffer.x, _state); + rallocv(ny, &mbuffer.w, _state); + rallocv(ny, &mbuffer.wy, _state); + kdtreecreaterequestbuffer(&state->tmptree, &mbuffer.requestbuffer, _state); + + /* + * Iteratively build layer by layer + */ + for(layeridx=0; layeridx<=state->nlayers-1; layeridx++) + { + + /* + * For each point compute residual from fitting with current layer + */ + if( npoints>state->mbatchsize&&(ae_fp_greater((double)npoints*querycosts.ptr.p_double[layeridx],smpactivationlevel(_state))||state->debugprofile) ) + { + ae_shared_pool_set_seed(&mbpool, &mbuffer, (ae_int_t)sizeof(mbuffer), (ae_copy_constructor)_mstabbuffer_init_copy, (ae_destructor)_mstabbuffer_destroy, _state); + idw_mstabrec(state, layerrad.ptr.p_double[layeridx], layerlambda.ptr.p_double[layeridx], layeridx, &mbpool, 0, npoints, ae_true, querycosts.ptr.p_double[layeridx], totalcost, &state->tmplayers, _state); + } + else + { + idw_mstabbasecase(state, layerrad.ptr.p_double[layeridx], layerlambda.ptr.p_double[layeridx], layeridx, &mbuffer, 0, npoints, querycosts.ptr.p_double[layeridx], totalcost, &state->tmplayers, _state); + } + } + kdtreebuild(&state->tmplayers, npoints, nx, ny*state->nlayers, 2, &model->tree, _state); + + /* + * Evaluate report fields + */ + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rss = (double)(0); + tss = (double)(0); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=ny-1; j++) + { + v = ae_fabs(state->tmplayers.ptr.pp_double[i][nx+state->nlayers*ny+j], _state); + rep->rmserror = rep->rmserror+v*v; + rep->avgerror = rep->avgerror+v; + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + rss = rss+v*v; + tss = tss+ae_sqr(state->xy.ptr.p_double[i*(nx+ny)+nx+j]-state->tmpmean.ptr.p_double[j], _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)(npoints*ny), _state); + rep->avgerror = rep->avgerror/(double)(npoints*ny); + rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state); + state->mprogress = 1.0; + + /* + * Prepare internal buffer + */ + idwcreatecalcbuffer(model, &model->buffer, _state); + ae_frame_leave(_state); + return; + } + + /* + * Unknown algorithm + */ + ae_assert(ae_false, "IDWFit: integrity check failed, unexpected algorithm", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function is used to peek into the IDW construction process from some +other thread and get the progress indicator. It returns value in [0,1]. + +IMPORTANT: only MSTAB algorithm supports peeking into progress indicator. + Legacy versions of the Shepard's method do not support it. You + will always get zero as the result. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 27.11.2023 by Bochkanov Sergey +*************************************************************************/ +double idwpeekprogress(const idwbuilder* s, ae_state *_state) +{ + double result; + + + result = s->mprogress; + return result; +} + + +/************************************************************************* +This function calculates values of an IDW model at a regular grid, +which has N0*N1 points, with Point[I,J] = (X0[I], X1[J]). Vector-valued +IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued IDW models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use idwgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2v(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector dummy; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_clear(y); + ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true); + + ae_assert(n0>0, "IDWGridCalc2V: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "IDWGridCalc2V: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "IDWGridCalc2V: Length(X0)cnt>=n1, "IDWGridCalc2V: Length(X1)ptr.p_double[i],x0->ptr.p_double[i+1]), "IDWGridCalc2V: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "IDWGridCalc2V: X1 is not ordered by ascending", _state); + } + idwgridcalc2vx(s, x0, n0, x1, n1, &dummy, ae_false, y, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates values of an IDW model at some subset of a +regular grid: +* the grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of the grid are required +Vector-valued IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued IDW models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. Generally, + they are not calculated, but future SIMD-capable + versions may compute several elements in a batch. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2vsubset(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(y); + + ae_assert(n0>0, "IDWGridCalc2VSubset: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "IDWGridCalc2VSubset: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "IDWGridCalc2VSubset: Length(X0)cnt>=n1, "IDWGridCalc2VSubset: Length(X1)cnt>=n0*n1, "IDWGridCalc2VSubset: Length(FlagY)ptr.p_double[i],x0->ptr.p_double[i+1]), "IDWGridCalc2VSubset: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "IDWGridCalc2VSubset: X1 is not ordered by ascending", _state); + } + idwgridcalc2vx(s, x0, n0, x1, n1, flagy, ae_true, y, _state); +} + + +/************************************************************************* +This function, depending on SparseY, acts as IDWGridCalc2V (SparseY=False) +or IDWGridCalc2VSubset (SparseY=True) function. See comments for these +functions for more information + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2vx(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t k; + double rcur; + ae_int_t ylen; + double evalcost; + ae_shared_pool cbpool; + idwcalcbuffer *calcbuf; + ae_smart_ptr _calcbuf; + + ae_frame_make(_state, &_frame_block); + memset(&cbpool, 0, sizeof(cbpool)); + memset(&_calcbuf, 0, sizeof(_calcbuf)); + ae_shared_pool_init(&cbpool, _state, ae_true); + ae_smart_ptr_init(&_calcbuf, (void**)&calcbuf, ae_false, _state, ae_true); + + ae_assert(n0>0, "IDWGridCalc2VX: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "IDWGridCalc2VX: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "IDWGridCalc2VX: Length(X0)cnt>=n1, "IDWGridCalc2VX: Length(X1)ptr.p_double[i],x0->ptr.p_double[i+1]), "IDWGridCalc2VX: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "IDWGridCalc2VX: X1 is not ordered by ascending", _state); + } + + /* + * Prepare local variables + */ + nx = s->nx; + ny = s->ny; + ae_shared_pool_set_seed(&cbpool, &s->buffer, (ae_int_t)sizeof(s->buffer), (ae_copy_constructor)_idwcalcbuffer_init_copy, (ae_destructor)_idwcalcbuffer_destroy, _state); + + /* + * Prepare output array + */ + ylen = ny*n0*n1; + ae_vector_set_length(y, ylen, _state); + rsetv(ylen, 0.0, y, _state); + if( nx!=2 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Evaluate cost (in CPU cycles) of a single model evaluation. + * Very crude approximation is used. + */ + evalcost = (double)(0); + ae_assert((s->algotype==0||s->algotype==1)||s->algotype==2, "IDW: integrity check 9144 failed", _state); + if( s->algotype==0 ) + { + + /* + * Original Shepard: single evaluation cost is O(NPoints) + */ + evalcost = evalcost+(double)(s->npoints*(5*nx+5*ny+50)); + } + if( s->algotype==1 ) + { + + /* + * Modified Shepard: single evaluation cost is mostly kd-tree request + */ + ae_shared_pool_retrieve(&cbpool, &_calcbuf, _state); + evalcost = evalcost+kdtreetsapproxrnnquerycost(&s->tree, &calcbuf->requestbuffer, s->r0, _state); + ae_shared_pool_recycle(&cbpool, &_calcbuf, _state); + } + if( s->algotype==2 ) + { + + /* + * MSTAB: single evaluation cost is a sum of per-layer costs + */ + ae_shared_pool_retrieve(&cbpool, &_calcbuf, _state); + rcur = s->r0; + for(k=0; k<=s->nlayers-1; k++) + { + evalcost = evalcost+(kdtreetsapproxrnnquerycost(&s->tree, &calcbuf->requestbuffer, rcur, _state)+(double)50); + rcur = rcur*s->rdecay; + } + ae_shared_pool_recycle(&cbpool, &_calcbuf, _state); + } + evalcost = coalesce(evalcost, (double)(50), _state); + + /* + * Perform the evaluation + */ + idw_idwgridcalc2rec(s, x0, 0, n0, n0, x1, 0, n1, n1, flagy, sparsey, &cbpool, ae_true, evalcost, y, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void idwalloc(ae_serializer* s, const idwmodel* model, ae_state *_state) +{ + ae_bool processed; + + + + /* + * Header + */ + ae_serializer_alloc_entry(s); + + /* + * Algorithm type and fields which are set for all algorithms + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &model->globalprior, -1, _state); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + + /* + * Algorithm-specific fields + */ + processed = ae_false; + if( model->algotype==0 ) + { + ae_serializer_alloc_entry(s); + allocrealarray(s, &model->shepardxy, -1, _state); + processed = ae_true; + } + if( model->algotype>0 ) + { + kdtreealloc(s, &model->tree, _state); + processed = ae_true; + } + ae_assert(processed, "IDW: integrity check failed during serialization", _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void idwserialize(ae_serializer* s, + const idwmodel* model, + ae_state *_state) +{ + ae_bool processed; + + + + /* + * Header + */ + ae_serializer_serialize_int(s, getidwserializationcode(_state), _state); + + /* + * Algorithm type and fields which are set for all algorithms + */ + ae_serializer_serialize_int(s, model->algotype, _state); + ae_serializer_serialize_int(s, model->nx, _state); + ae_serializer_serialize_int(s, model->ny, _state); + serializerealarray(s, &model->globalprior, -1, _state); + ae_serializer_serialize_int(s, model->nlayers, _state); + ae_serializer_serialize_double(s, model->r0, _state); + ae_serializer_serialize_double(s, model->rdecay, _state); + ae_serializer_serialize_double(s, model->lambda0, _state); + ae_serializer_serialize_double(s, model->lambdalast, _state); + ae_serializer_serialize_double(s, model->lambdadecay, _state); + ae_serializer_serialize_double(s, model->shepardp, _state); + + /* + * Algorithm-specific fields + */ + processed = ae_false; + if( model->algotype==0 ) + { + ae_serializer_serialize_int(s, model->npoints, _state); + serializerealarray(s, &model->shepardxy, -1, _state); + processed = ae_true; + } + if( model->algotype>0 ) + { + kdtreeserialize(s, &model->tree, _state); + processed = ae_true; + } + ae_assert(processed, "IDW: integrity check failed during serialization", _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void idwunserialize(ae_serializer* s, idwmodel* model, ae_state *_state) +{ + ae_bool processed; + ae_int_t scode; + + _idwmodel_clear(model); + + + /* + * Header + */ + ae_serializer_unserialize_int(s, &scode, _state); + ae_assert(scode==getidwserializationcode(_state), "IDWUnserialize: stream header corrupted", _state); + + /* + * Algorithm type and fields which are set for all algorithms + */ + ae_serializer_unserialize_int(s, &model->algotype, _state); + ae_serializer_unserialize_int(s, &model->nx, _state); + ae_serializer_unserialize_int(s, &model->ny, _state); + unserializerealarray(s, &model->globalprior, _state); + ae_serializer_unserialize_int(s, &model->nlayers, _state); + ae_serializer_unserialize_double(s, &model->r0, _state); + ae_serializer_unserialize_double(s, &model->rdecay, _state); + ae_serializer_unserialize_double(s, &model->lambda0, _state); + ae_serializer_unserialize_double(s, &model->lambdalast, _state); + ae_serializer_unserialize_double(s, &model->lambdadecay, _state); + ae_serializer_unserialize_double(s, &model->shepardp, _state); + model->debugprofile = ae_false; + + /* + * Algorithm-specific fields + */ + processed = ae_false; + if( model->algotype==0 ) + { + ae_serializer_unserialize_int(s, &model->npoints, _state); + unserializerealarray(s, &model->shepardxy, _state); + processed = ae_true; + } + if( model->algotype>0 ) + { + kdtreeunserialize(s, &model->tree, _state); + processed = ae_true; + } + ae_assert(processed, "IDW: integrity check failed during serialization", _state); + + /* + * Temporary buffers + */ + idwcreatecalcbuffer(model, &model->buffer, _state); +} + + +/************************************************************************* +This function, depending on SparseY, acts as IDWGridCalc2V (SparseY=False) +or IDWGridCalc2VSubset (SparseY=True) function. See comments for these +functions for more information + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +static void idw_idwgridcalc2rec(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t begin0, + ae_int_t end0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t begin1, + ae_int_t end1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_shared_pool* cbpool, + ae_bool isrootcall, + double evalcost, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t batchsize; + ae_int_t chunksize; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool abovepexeclevel; + ae_bool abovespawnlevel; + idwcalcbuffer *calcbuf; + ae_smart_ptr _calcbuf; + + ae_frame_make(_state, &_frame_block); + memset(&_calcbuf, 0, sizeof(_calcbuf)); + ae_smart_ptr_init(&_calcbuf, (void**)&calcbuf, ae_false, _state, ae_true); + + nx = s->nx; + ny = s->ny; + batchsize = icase2(s->debugprofile, 1, idw_idwbatchsize, _state); + chunksize = (end0-begin0)*(end1-begin1); + ae_assert(nx==2, "IDW: integrity check 5621 failed", _state); + + /* + * Perform parallel execution if needed + */ + abovepexeclevel = ae_fp_greater((double)chunksize*evalcost,smpactivationlevel(_state))||s->debugprofile; + if( (isrootcall&&chunksize>batchsize)&&abovepexeclevel ) + { + if( _trypexec_idw_idwgridcalc2rec(s,x0,begin0,end0,n0,x1,begin1,end1,n1,flagy,sparsey,cbpool,isrootcall,evalcost,y, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Perform subdivision + */ + abovespawnlevel = ae_fp_greater((double)chunksize*evalcost,spawnlevel(_state))||s->debugprofile; + if( chunksize>batchsize&&abovespawnlevel ) + { + + /* + * Subdivision + */ + ae_assert(ae_maxint(end0-begin0, end1-begin1, _state)>1, "IDW: integrity check 6712 failed", _state); + if( end0-begin0>end1-begin1 ) + { + + /* + * Split on variable 0 + */ + k = begin0+(end0-begin0)/2; + idw_idwgridcalc2rec(s, x0, begin0, k, n0, x1, begin1, end1, n1, flagy, sparsey, cbpool, ae_false, evalcost, y, _state); + idw_idwgridcalc2rec(s, x0, k, end0, n0, x1, begin1, end1, n1, flagy, sparsey, cbpool, ae_false, evalcost, y, _state); + } + else + { + k = begin1+(end1-begin1)/2; + idw_idwgridcalc2rec(s, x0, begin0, end0, n0, x1, begin1, k, n1, flagy, sparsey, cbpool, ae_false, evalcost, y, _state); + idw_idwgridcalc2rec(s, x0, begin0, end0, n0, x1, k, end1, n1, flagy, sparsey, cbpool, ae_false, evalcost, y, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * Basecase code + */ + ae_shared_pool_retrieve(cbpool, &_calcbuf, _state); + rallocv(nx, &calcbuf->x, _state); + for(i=begin0; i<=end0-1; i++) + { + for(j=begin1; j<=end1-1; j++) + { + if( !sparsey||flagy->ptr.p_bool[i+j*n0] ) + { + calcbuf->x.ptr.p_double[0] = x0->ptr.p_double[i]; + calcbuf->x.ptr.p_double[1] = x1->ptr.p_double[j]; + idwtscalcbuf(s, calcbuf, &calcbuf->x, &calcbuf->y, _state); + for(k=0; k<=ny-1; k++) + { + y->ptr.p_double[k+ny*(i+j*n0)] = calcbuf->y.ptr.p_double[k]; + } + } + } + } + ae_shared_pool_recycle(cbpool, &_calcbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_idw_idwgridcalc2rec(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t begin0, + ae_int_t end0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t begin1, + ae_int_t end1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_shared_pool* cbpool, + ae_bool isrootcall, + double evalcost, + /* Real */ ae_vector* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function evaluates error metrics for the model using IDWTsCalcBuf() +to calculate model at each point. + +NOTE: modern IDW algorithms (MSTAB, MSMOOTH) can generate residuals during + model construction, so they do not need this function in order to + evaluate error metrics. + +Following fields of Rep are filled: +* rep.rmserror +* rep.avgerror +* rep.maxerror +* rep.r2 + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +static void idw_errormetricsviacalc(idwbuilder* state, + idwmodel* model, + idwreport* rep, + ae_state *_state) +{ + ae_int_t npoints; + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double rss; + double tss; + + + npoints = state->npoints; + nx = state->nx; + ny = state->ny; + if( npoints==0 ) + { + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rep->r2 = (double)(1); + return; + } + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rss = (double)(0); + tss = (double)(0); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nx-1; j++) + { + model->buffer.x.ptr.p_double[j] = state->xy.ptr.p_double[i*(nx+ny)+j]; + } + idwtscalcbuf(model, &model->buffer, &model->buffer.x, &model->buffer.y, _state); + for(j=0; j<=ny-1; j++) + { + vv = state->xy.ptr.p_double[i*(nx+ny)+nx+j]; + v = ae_fabs(vv-model->buffer.y.ptr.p_double[j], _state); + rep->rmserror = rep->rmserror+v*v; + rep->avgerror = rep->avgerror+v; + rep->maxerror = ae_maxreal(rep->maxerror, v, _state); + rss = rss+v*v; + tss = tss+ae_sqr(vv-state->tmpmean.ptr.p_double[j], _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)(npoints*ny), _state); + rep->avgerror = rep->avgerror/(double)(npoints*ny); + rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state); +} + + +/************************************************************************* +Basecase for IDW-MSTAB model construction algorithm + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +static void idw_mstabrec(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + ae_shared_pool* mbpool, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t tile0; + ae_int_t tile1; + mstabbuffer *mbuffer; + ae_smart_ptr _mbuffer; + ae_bool abovepexeclevel; + ae_bool abovespawnlevel; + + ae_frame_make(_state, &_frame_block); + memset(&_mbuffer, 0, sizeof(_mbuffer)); + ae_smart_ptr_init(&_mbuffer, (void**)&mbuffer, ae_false, _state, ae_true); + + + /* + * Try parallel execution, if needed + */ + abovepexeclevel = ae_fp_greater((double)(idx1-idx0)*querycost,smpactivationlevel(_state))||state->debugprofile; + if( (isrootcall&&idx1-idx0>state->mbatchsize)&&abovepexeclevel ) + { + if( _trypexec_idw_mstabrec(state,rcur,lambdacur,layeridx,mbpool,idx0,idx1,isrootcall,querycost,totalcost,layers, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Handle basecase or recursively subdivide + */ + abovespawnlevel = ae_fp_greater((double)(idx1-idx0)*querycost,spawnlevel(_state))||state->debugprofile; + if( idx1-idx0>state->mbatchsize&&abovespawnlevel ) + { + + /* + * Subdivision + */ + tiledsplit(idx1-idx0, state->mbatchsize, &tile0, &tile1, _state); + idw_mstabrec(state, rcur, lambdacur, layeridx, mbpool, idx0, idx0+tile0, ae_false, querycost, totalcost, layers, _state); + idw_mstabrec(state, rcur, lambdacur, layeridx, mbpool, idx0+tile0, idx1, ae_false, querycost, totalcost, layers, _state); + ae_frame_leave(_state); + return; + } + + /* + * Basecase + */ + ae_shared_pool_retrieve(mbpool, &_mbuffer, _state); + idw_mstabbasecase(state, rcur, lambdacur, layeridx, mbuffer, idx0, idx1, querycost, totalcost, layers, _state); + ae_shared_pool_recycle(mbpool, &_mbuffer, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_idw_mstabrec(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + ae_shared_pool* mbpool, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Basecase for IDW-MSTAB model construction algorithm + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +static void idw_mstabbasecase(idwbuilder* state, + double rcur, + double lambdacur, + ae_int_t layeridx, + mstabbuffer* buf, + ae_int_t idx0, + ae_int_t idx1, + double querycost, + double totalcost, + /* Real */ ae_matrix* layers, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + ae_int_t srcidx; + ae_int_t nx; + ae_int_t ny; + double v; + double vv; + double localprogress; + + + nx = state->nx; + ny = state->ny; + localprogress = 0.0; + for(i=idx0; i<=idx1-1; i++) + { + + /* + * Build the model + */ + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = layers->ptr.pp_double[i][j]; + } + k = kdtreetsqueryrnn(&state->tmptree, &buf->requestbuffer, &buf->x, rcur, ae_true, _state); + kdtreetsqueryresultstags(&state->tmptree, &buf->requestbuffer, &buf->tags, _state); + kdtreetsqueryresultsdistances(&state->tmptree, &buf->requestbuffer, &buf->dist, _state); + for(j=0; j<=ny-1; j++) + { + buf->wy.ptr.p_double[j] = (double)(0); + buf->w.ptr.p_double[j] = idw_w0; + } + for(i0=0; i0<=k-1; i0++) + { + vv = buf->dist.ptr.p_double[i0]/rcur; + vv = vv*vv; + v = ((double)1-vv)*((double)1-vv)/(vv+lambdacur); + srcidx = buf->tags.ptr.p_int[i0]; + for(j=0; j<=ny-1; j++) + { + buf->wy.ptr.p_double[j] = buf->wy.ptr.p_double[j]+v*layers->ptr.pp_double[srcidx][nx+layeridx*ny+j]; + buf->w.ptr.p_double[j] = buf->w.ptr.p_double[j]+v; + } + } + for(j=0; j<=ny-1; j++) + { + v = layers->ptr.pp_double[i][nx+layeridx*ny+j]; + layers->ptr.pp_double[i][nx+(layeridx+1)*ny+j] = v-buf->wy.ptr.p_double[j]/buf->w.ptr.p_double[j]; + } + + /* + * Update progress + */ + localprogress = localprogress+querycost/coalesce(totalcost, (double)(1), _state); + if( ae_fp_greater_eq(localprogress,0.001)||i==idx1-1 ) + { + rthreadunsafeset(&state->mprogress, boundval(rthreadunsafeget(&state->mprogress, _state)+localprogress, (double)(0), (double)(1), _state), _state); + localprogress = 0.0; + } + } +} + + +void _idwcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + idwcalcbuffer *p = (idwcalcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tsyw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tsw, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tsxy, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tsdist, 0, DT_REAL, _state, make_automatic); + _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic); +} + + +void _idwcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + idwcalcbuffer *dst = (idwcalcbuffer*)_dst; + const idwcalcbuffer *src = (const idwcalcbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->tsyw, &src->tsyw, _state, make_automatic); + ae_vector_init_copy(&dst->tsw, &src->tsw, _state, make_automatic); + ae_matrix_init_copy(&dst->tsxy, &src->tsxy, _state, make_automatic); + ae_vector_init_copy(&dst->tsdist, &src->tsdist, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic); +} + + +void _idwcalcbuffer_clear(void* _p) +{ + idwcalcbuffer *p = (idwcalcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->tsyw); + ae_vector_clear(&p->tsw); + ae_matrix_clear(&p->tsxy); + ae_vector_clear(&p->tsdist); + _kdtreerequestbuffer_clear(&p->requestbuffer); +} + + +void _idwcalcbuffer_destroy(void* _p) +{ + idwcalcbuffer *p = (idwcalcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->tsyw); + ae_vector_destroy(&p->tsw); + ae_matrix_destroy(&p->tsxy); + ae_vector_destroy(&p->tsdist); + _kdtreerequestbuffer_destroy(&p->requestbuffer); +} + + +void _mstabbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mstabbuffer *p = (mstabbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->dist, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tags, 0, DT_INT, _state, make_automatic); + _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic); +} + + +void _mstabbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mstabbuffer *dst = (mstabbuffer*)_dst; + const mstabbuffer *src = (const mstabbuffer*)_src; + ae_vector_init_copy(&dst->dist, &src->dist, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic); + ae_vector_init_copy(&dst->wy, &src->wy, _state, make_automatic); + ae_vector_init_copy(&dst->tags, &src->tags, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic); +} + + +void _mstabbuffer_clear(void* _p) +{ + mstabbuffer *p = (mstabbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->dist); + ae_vector_clear(&p->x); + ae_vector_clear(&p->w); + ae_vector_clear(&p->wy); + ae_vector_clear(&p->tags); + _kdtreerequestbuffer_clear(&p->requestbuffer); +} + + +void _mstabbuffer_destroy(void* _p) +{ + mstabbuffer *p = (mstabbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->dist); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->w); + ae_vector_destroy(&p->wy); + ae_vector_destroy(&p->tags); + _kdtreerequestbuffer_destroy(&p->requestbuffer); +} + + +void _idwmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + idwmodel *p = (idwmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->globalprior, 0, DT_REAL, _state, make_automatic); + _kdtree_init(&p->tree, _state, make_automatic); + ae_vector_init(&p->shepardxy, 0, DT_REAL, _state, make_automatic); + _idwcalcbuffer_init(&p->buffer, _state, make_automatic); +} + + +void _idwmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + idwmodel *dst = (idwmodel*)_dst; + const idwmodel *src = (const idwmodel*)_src; + dst->nx = src->nx; + dst->ny = src->ny; + ae_vector_init_copy(&dst->globalprior, &src->globalprior, _state, make_automatic); + dst->algotype = src->algotype; + dst->nlayers = src->nlayers; + dst->r0 = src->r0; + dst->rdecay = src->rdecay; + dst->lambda0 = src->lambda0; + dst->lambdalast = src->lambdalast; + dst->lambdadecay = src->lambdadecay; + dst->shepardp = src->shepardp; + dst->debugprofile = src->debugprofile; + _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic); + dst->npoints = src->npoints; + ae_vector_init_copy(&dst->shepardxy, &src->shepardxy, _state, make_automatic); + _idwcalcbuffer_init_copy(&dst->buffer, &src->buffer, _state, make_automatic); +} + + +void _idwmodel_clear(void* _p) +{ + idwmodel *p = (idwmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->globalprior); + _kdtree_clear(&p->tree); + ae_vector_clear(&p->shepardxy); + _idwcalcbuffer_clear(&p->buffer); +} + + +void _idwmodel_destroy(void* _p) +{ + idwmodel *p = (idwmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->globalprior); + _kdtree_destroy(&p->tree); + ae_vector_destroy(&p->shepardxy); + _idwcalcbuffer_destroy(&p->buffer); +} + + +void _idwbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + idwbuilder *p = (idwbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->priortermval, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpxy, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmplayers, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmptags, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpdist, 0, DT_REAL, _state, make_automatic); + _kdtree_init(&p->tmptree, _state, make_automatic); + ae_vector_init(&p->tmpmean, 0, DT_REAL, _state, make_automatic); +} + + +void _idwbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + idwbuilder *dst = (idwbuilder*)_dst; + const idwbuilder *src = (const idwbuilder*)_src; + dst->priortermtype = src->priortermtype; + ae_vector_init_copy(&dst->priortermval, &src->priortermval, _state, make_automatic); + dst->algotype = src->algotype; + dst->nlayers = src->nlayers; + dst->r0 = src->r0; + dst->rdecay = src->rdecay; + dst->lambda0 = src->lambda0; + dst->lambdalast = src->lambdalast; + dst->lambdadecay = src->lambdadecay; + dst->shepardp = src->shepardp; + dst->debugprofile = src->debugprofile; + dst->mbatchsize = src->mbatchsize; + dst->mprogress = src->mprogress; + ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic); + dst->npoints = src->npoints; + dst->nx = src->nx; + dst->ny = src->ny; + ae_matrix_init_copy(&dst->tmpxy, &src->tmpxy, _state, make_automatic); + ae_matrix_init_copy(&dst->tmplayers, &src->tmplayers, _state, make_automatic); + ae_vector_init_copy(&dst->tmptags, &src->tmptags, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdist, &src->tmpdist, _state, make_automatic); + _kdtree_init_copy(&dst->tmptree, &src->tmptree, _state, make_automatic); + ae_vector_init_copy(&dst->tmpmean, &src->tmpmean, _state, make_automatic); +} + + +void _idwbuilder_clear(void* _p) +{ + idwbuilder *p = (idwbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->priortermval); + ae_vector_clear(&p->xy); + ae_matrix_clear(&p->tmpxy); + ae_matrix_clear(&p->tmplayers); + ae_vector_clear(&p->tmptags); + ae_vector_clear(&p->tmpdist); + _kdtree_clear(&p->tmptree); + ae_vector_clear(&p->tmpmean); +} + + +void _idwbuilder_destroy(void* _p) +{ + idwbuilder *p = (idwbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->priortermval); + ae_vector_destroy(&p->xy); + ae_matrix_destroy(&p->tmpxy); + ae_matrix_destroy(&p->tmplayers); + ae_vector_destroy(&p->tmptags); + ae_vector_destroy(&p->tmpdist); + _kdtree_destroy(&p->tmptree); + ae_vector_destroy(&p->tmpmean); +} + + +void _idwreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + idwreport *p = (idwreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _idwreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + idwreport *dst = (idwreport*)_dst; + const idwreport *src = (const idwreport*)_src; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->maxerror = src->maxerror; + dst->r2 = src->r2; +} + + +void _idwreport_clear(void* _p) +{ + idwreport *p = (idwreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _idwreport_destroy(void* _p) +{ + idwreport *p = (idwreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Internal subroutine: automatic scaling for LLS tasks. +NEVER CALL IT DIRECTLY! + +Maps abscissas to [-1,1], standartizes ordinates and correspondingly scales +constraints. It also scales weights so that max(W[i])=1 + +Transformations performed: +* X, XC [XA,XB] => [-1,+1] + transformation makes min(X)=-1, max(X)=+1 + +* Y [SA,SB] => [0,1] + transformation makes mean(Y)=0, stddev(Y)=1 + +* YC transformed accordingly to SA, SB, DC[I] + + -- ALGLIB PROJECT -- + Copyright 08.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitscalexy(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* w, + ae_int_t n, + /* Real */ ae_vector* xc, + /* Real */ ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + double* xa, + double* xb, + double* sa, + double* sb, + /* Real */ ae_vector* xoriginal, + /* Real */ ae_vector* yoriginal, + ae_state *_state) +{ + double xmin; + double xmax; + ae_int_t i; + double mx; + + *xa = 0.0; + *xb = 0.0; + *sa = 0.0; + *sb = 0.0; + ae_vector_clear(xoriginal); + ae_vector_clear(yoriginal); + + ae_assert(n>=1, "LSFitScaleXY: incorrect N", _state); + ae_assert(k>=0, "LSFitScaleXY: incorrect K", _state); + xmin = x->ptr.p_double[0]; + xmax = x->ptr.p_double[0]; + for(i=1; i<=n-1; i++) + { + xmin = ae_minreal(xmin, x->ptr.p_double[i], _state); + xmax = ae_maxreal(xmax, x->ptr.p_double[i], _state); + } + for(i=0; i<=k-1; i++) + { + xmin = ae_minreal(xmin, xc->ptr.p_double[i], _state); + xmax = ae_maxreal(xmax, xc->ptr.p_double[i], _state); + } + if( ae_fp_eq(xmin,xmax) ) + { + if( ae_fp_eq(xmin,(double)(0)) ) + { + xmin = (double)(-1); + xmax = (double)(1); + } + else + { + if( ae_fp_greater(xmin,(double)(0)) ) + { + xmin = 0.5*xmin; + } + else + { + xmax = 0.5*xmax; + } + } + } + ae_vector_set_length(xoriginal, n, _state); + ae_v_move(&xoriginal->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + *xa = xmin; + *xb = xmax; + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)2*(x->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); + } + for(i=0; i<=k-1; i++) + { + ae_assert(dc->ptr.p_int[i]>=0, "LSFitScaleXY: internal error!", _state); + xc->ptr.p_double[i] = (double)2*(xc->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa)); + yc->ptr.p_double[i] = yc->ptr.p_double[i]*ae_pow(0.5*(*xb-(*xa)), (double)(dc->ptr.p_int[i]), _state); + } + ae_vector_set_length(yoriginal, n, _state); + ae_v_move(&yoriginal->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + *sa = (double)(0); + for(i=0; i<=n-1; i++) + { + *sa = *sa+y->ptr.p_double[i]; + } + *sa = *sa/(double)n; + *sb = (double)(0); + for(i=0; i<=n-1; i++) + { + *sb = *sb+ae_sqr(y->ptr.p_double[i]-(*sa), _state); + } + *sb = ae_sqrt(*sb/(double)n, _state)+(*sa); + if( ae_fp_eq(*sb,*sa) ) + { + *sb = (double)2*(*sa); + } + if( ae_fp_eq(*sb,*sa) ) + { + *sb = *sa+(double)1; + } + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = (y->ptr.p_double[i]-(*sa))/(*sb-(*sa)); + } + for(i=0; i<=k-1; i++) + { + if( dc->ptr.p_int[i]==0 ) + { + yc->ptr.p_double[i] = (yc->ptr.p_double[i]-(*sa))/(*sb-(*sa)); + } + else + { + yc->ptr.p_double[i] = yc->ptr.p_double[i]/(*sb-(*sa)); + } + } + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(w->ptr.p_double[i], _state), _state); + } + if( ae_fp_neq(mx,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + w->ptr.p_double[i] = w->ptr.p_double[i]/mx; + } + } +} + + +void buildpriorterm(/* Real */ ae_matrix* xy, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + double priorval, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double rj; + ae_matrix araw; + ae_matrix amod; + ae_matrix braw; + ae_vector tmp0; + double lambdareg; + ae_int_t rfsits; + + ae_frame_make(_state, &_frame_block); + memset(&araw, 0, sizeof(araw)); + memset(&amod, 0, sizeof(amod)); + memset(&braw, 0, sizeof(braw)); + memset(&tmp0, 0, sizeof(tmp0)); + ae_matrix_clear(v); + ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "BuildPriorTerm: N<0", _state); + ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state); + ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state); + ae_matrix_set_length(v, ny, nx+1, _state); + for(i=0; i<=v->rows-1; i++) + { + for(j=0; j<=v->cols-1; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + if( n==0 ) + { + if( modeltype==0 ) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][nx] = priorval; + } + ae_frame_leave(_state); + return; + } + if( modeltype==1 ) + { + ae_frame_leave(_state); + return; + } + if( modeltype==2 ) + { + ae_frame_leave(_state); + return; + } + if( modeltype==3 ) + { + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state); + } + if( modeltype==0 ) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][nx] = priorval; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-priorval; + } + } + ae_frame_leave(_state); + return; + } + if( modeltype==2 ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy->ptr.pp_double[i][nx+j]; + } + } + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state); + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-v->ptr.pp_double[j][nx]; + } + } + ae_frame_leave(_state); + return; + } + if( modeltype==3 ) + { + ae_frame_leave(_state); + return; + } + ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state); + lambdareg = 0.0; + ae_matrix_set_length(&araw, nx+1, nx+1, _state); + ae_matrix_set_length(&braw, nx+1, ny, _state); + ae_vector_set_length(&tmp0, nx+1, _state); + ae_matrix_set_length(&amod, nx+1, nx+1, _state); + for(i=0; i<=nx; i++) + { + for(j=0; j<=nx; j++) + { + araw.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j0=0; j0<=nx; j0++) + { + for(j1=0; j1<=nx; j1++) + { + araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1]; + } + } + } + for(rfsits=1; rfsits<=3; rfsits++) + { + for(i=0; i<=nx; i++) + { + for(j=0; j<=ny-1; j++) + { + braw.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j=0; j<=ny-1; j++) + { + rj = xy->ptr.pp_double[i][nx+j]; + for(j0=0; j0<=nx; j0++) + { + rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0]; + } + for(j0=0; j0<=nx; j0++) + { + braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0]; + } + } + } + for(;;) + { + for(i=0; i<=nx; i++) + { + for(j=0; j<=nx; j++) + { + amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j]; + } + amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state); + } + if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) ) + { + break; + } + lambdareg = coalesce((double)10*lambdareg, 1.0E-12, _state); + } + rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state); + rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state); + for(i=0; i<=nx; i++) + { + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j]; + } + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j=0; j<=ny-1; j++) + { + rj = 0.0; + for(j0=0; j0<=nx; j0++) + { + rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0]; + } + xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-rj; + } + } + ae_frame_leave(_state); +} + + +void buildpriorterm1(/* Real */ ae_vector* xy1, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + double priorval, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t ew; + double rj; + ae_matrix araw; + ae_matrix amod; + ae_matrix braw; + ae_vector tmp0; + double lambdareg; + ae_int_t rfsits; + + ae_frame_make(_state, &_frame_block); + memset(&araw, 0, sizeof(araw)); + memset(&amod, 0, sizeof(amod)); + memset(&braw, 0, sizeof(braw)); + memset(&tmp0, 0, sizeof(tmp0)); + ae_matrix_clear(v); + ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "BuildPriorTerm: N<0", _state); + ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state); + ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state); + ew = nx+ny; + ae_matrix_set_length(v, ny, nx+1, _state); + for(i=0; i<=v->rows-1; i++) + { + for(j=0; j<=v->cols-1; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + if( n==0 ) + { + if( modeltype==0 ) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][nx] = priorval; + } + ae_frame_leave(_state); + return; + } + if( modeltype==1 ) + { + ae_frame_leave(_state); + return; + } + if( modeltype==2 ) + { + ae_frame_leave(_state); + return; + } + if( modeltype==3 ) + { + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state); + } + if( modeltype==0 ) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][nx] = priorval; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-priorval; + } + } + ae_frame_leave(_state); + return; + } + if( modeltype==2 ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy1->ptr.p_double[i*ew+nx+j]; + } + } + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state); + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-v->ptr.pp_double[j][nx]; + } + } + ae_frame_leave(_state); + return; + } + if( modeltype==3 ) + { + ae_frame_leave(_state); + return; + } + ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state); + lambdareg = 0.0; + ae_matrix_set_length(&araw, nx+1, nx+1, _state); + ae_matrix_set_length(&braw, nx+1, ny, _state); + ae_vector_set_length(&tmp0, nx+1, _state); + ae_matrix_set_length(&amod, nx+1, nx+1, _state); + for(i=0; i<=nx; i++) + { + for(j=0; j<=nx; j++) + { + araw.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j0=0; j0<=nx; j0++) + { + for(j1=0; j1<=nx; j1++) + { + araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1]; + } + } + } + for(rfsits=1; rfsits<=1; rfsits++) + { + for(i=0; i<=nx; i++) + { + for(j=0; j<=ny-1; j++) + { + braw.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j=0; j<=ny-1; j++) + { + rj = xy1->ptr.p_double[i*ew+nx+j]; + for(j0=0; j0<=nx; j0++) + { + rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0]; + } + for(j0=0; j0<=nx; j0++) + { + braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0]; + } + } + } + for(;;) + { + for(i=0; i<=nx; i++) + { + for(j=0; j<=nx; j++) + { + amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j]; + } + amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state); + } + if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) ) + { + break; + } + lambdareg = coalesce((double)10*lambdareg, 1.0E-12, _state); + } + rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state); + rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state); + for(i=0; i<=nx; i++) + { + for(j=0; j<=ny-1; j++) + { + v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j]; + } + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j]; + } + tmp0.ptr.p_double[nx] = 1.0; + for(j=0; j<=ny-1; j++) + { + rj = 0.0; + for(j0=0; j0<=nx; j0++) + { + rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0]; + } + xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-rj; + } + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Conversion from barycentric representation to Chebyshev basis. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + P - polynomial in barycentric form + A,B - base interval for Chebyshev polynomials (see below) + A<>B + +OUTPUT PARAMETERS + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, + where Ti - I-th Chebyshev polynomial. + +NOTES: + barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2cheb(const barycentricinterpolant* p, + double a, + double b, + /* Real */ ae_vector* t, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_vector vp; + ae_vector vx; + ae_vector tk; + ae_vector tk1; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&vp, 0, sizeof(vp)); + memset(&vx, 0, sizeof(vx)); + memset(&tk, 0, sizeof(tk)); + memset(&tk1, 0, sizeof(tk1)); + ae_vector_clear(t); + ae_vector_init(&vp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tk, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state); + ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state); + ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state); + ae_assert(p->n>0, "PolynomialBar2Cheb: P is not correctly initialized barycentric interpolant!", _state); + + /* + * Calculate function values on a Chebyshev grid + */ + ae_vector_set_length(&vp, p->n, _state); + ae_vector_set_length(&vx, p->n, _state); + for(i=0; i<=p->n-1; i++) + { + vx.ptr.p_double[i] = ae_cos(ae_pi*((double)i+0.5)/(double)p->n, _state); + vp.ptr.p_double[i] = barycentriccalc(p, 0.5*(vx.ptr.p_double[i]+(double)1)*(b-a)+a, _state); + } + + /* + * T[0] + */ + ae_vector_set_length(t, p->n, _state); + v = (double)(0); + for(i=0; i<=p->n-1; i++) + { + v = v+vp.ptr.p_double[i]; + } + t->ptr.p_double[0] = v/(double)p->n; + + /* + * other T's. + * + * NOTES: + * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX + * 2. we can do same calculations with fast DCT, but it + * * adds dependencies + * * still leaves us with O(N^2) algorithm because + * preparation of function values is O(N^2) process + */ + if( p->n>1 ) + { + ae_vector_set_length(&tk, p->n, _state); + ae_vector_set_length(&tk1, p->n, _state); + for(i=0; i<=p->n-1; i++) + { + tk.ptr.p_double[i] = vx.ptr.p_double[i]; + tk1.ptr.p_double[i] = (double)(1); + } + for(k=1; k<=p->n-1; k++) + { + + /* + * calculate discrete product of function vector and TK + */ + v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); + t->ptr.p_double[k] = v/(0.5*(double)p->n); + + /* + * Update TK and TK1 + */ + for(i=0; i<=p->n-1; i++) + { + v = (double)2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; + tk1.ptr.p_double[i] = tk.ptr.p_double[i]; + tk.ptr.p_double[i] = v; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Conversion from Chebyshev basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, + where Ti - I-th Chebyshev polynomial. + N - number of coefficients: + * if given, only leading N elements of T are used + * if not given, automatically determined from size of T + A,B - base interval for Chebyshev polynomials (see above) + A=1, "PolynomialBar2Cheb: N<1", _state); + ae_assert(t->cnt>=n, "PolynomialBar2Cheb: Length(T)ptr.p_double[0]; + tk1 = (double)(1); + tk = vx; + for(k=1; k<=n-1; k++) + { + vy = vy+t->ptr.p_double[k]*tk; + v = (double)2*vx*tk-tk1; + tk1 = tk; + tk = v; + } + y.ptr.p_double[i] = vy; + } + + /* + * Build barycentric interpolant, map grid from [-1,+1] to [A,B] + */ + polynomialbuildcheb1(a, b, &y, n, p, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Conversion from barycentric representation to power basis. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + P - polynomial in barycentric form + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if P was obtained as + result of interpolation on [-1,+1], you can set C=0 and S=1 and + represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it + is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 + will be better option. Such representation can be obtained by using + 1000.0 as offset C and 1.0 as scale S. + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return coefficients in + any case, but for N>8 they will become unreliable. However, N's + less than 5 are pretty safe. + +3. barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2pow(const barycentricinterpolant* p, + double c, + double s, + /* Real */ ae_vector* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + double e; + double d; + ae_vector vp; + ae_vector vx; + ae_vector tk; + ae_vector tk1; + ae_vector t; + double v; + double c0; + double s0; + double va; + double vb; + ae_vector vai; + ae_vector vbi; + double minx; + double maxx; + + ae_frame_make(_state, &_frame_block); + memset(&vp, 0, sizeof(vp)); + memset(&vx, 0, sizeof(vx)); + memset(&tk, 0, sizeof(tk)); + memset(&tk1, 0, sizeof(tk1)); + memset(&t, 0, sizeof(t)); + memset(&vai, 0, sizeof(vai)); + memset(&vbi, 0, sizeof(vbi)); + ae_vector_clear(a); + ae_vector_init(&vp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tk, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vai, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vbi, 0, DT_REAL, _state, ae_true); + + + /* + * We have barycentric model built using set of points X[], and we + * want to convert it to power basis centered about point C with + * scale S: I-th basis function is ((X-C)/S)^i. + * + * We use following three-stage algorithm: + * + * 1. we build Chebyshev representation of polynomial using + * intermediate center C0 and scale S0, which are derived from X[]: + * C0 = 0.5*(min(X)+max(X)), S0 = 0.5*(max(X)-min(X)). Chebyshev + * representation is built by sampling points around center C0, + * with typical distance between them proportional to S0. + * 2. then we transform form Chebyshev basis to intermediate power + * basis, using same center/scale C0/S0. + * 3. after that, we apply linear transformation to intermediate + * power basis which moves it to final center/scale C/S. + * + * The idea of such multi-stage algorithm is that it is much easier to + * transform barycentric model to Chebyshev basis, and only later to + * power basis, than transforming it directly to power basis. It is + * also more numerically stable to sample points using intermediate C0/S0, + * which are derived from user-supplied model, than using "final" C/S, + * which may be unsuitable for sampling (say, if S=1, we may have stability + * problems when working with models built from dataset with non-unit + * scale of abscissas). + */ + ae_assert(ae_isfinite(c, _state), "PolynomialBar2Pow: C is not finite!", _state); + ae_assert(ae_isfinite(s, _state), "PolynomialBar2Pow: S is not finite!", _state); + ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialBar2Pow: S=0!", _state); + ae_assert(p->n>0, "PolynomialBar2Pow: P is not correctly initialized barycentric interpolant!", _state); + + /* + * Select intermediate center/scale + */ + minx = p->x.ptr.p_double[0]; + maxx = p->x.ptr.p_double[0]; + for(i=1; i<=p->n-1; i++) + { + minx = ae_minreal(minx, p->x.ptr.p_double[i], _state); + maxx = ae_maxreal(maxx, p->x.ptr.p_double[i], _state); + } + if( ae_fp_eq(minx,maxx) ) + { + c0 = minx; + s0 = 1.0; + } + else + { + c0 = 0.5*(maxx+minx); + s0 = 0.5*(maxx-minx); + } + + /* + * Calculate function values on a Chebyshev grid using intermediate C0/S0 + */ + ae_vector_set_length(&vp, p->n+1, _state); + ae_vector_set_length(&vx, p->n, _state); + for(i=0; i<=p->n-1; i++) + { + vx.ptr.p_double[i] = ae_cos(ae_pi*((double)i+0.5)/(double)p->n, _state); + vp.ptr.p_double[i] = barycentriccalc(p, s0*vx.ptr.p_double[i]+c0, _state); + } + + /* + * T[0] + */ + ae_vector_set_length(&t, p->n, _state); + v = (double)(0); + for(i=0; i<=p->n-1; i++) + { + v = v+vp.ptr.p_double[i]; + } + t.ptr.p_double[0] = v/(double)p->n; + + /* + * other T's. + * + * NOTES: + * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX + * 2. we can do same calculations with fast DCT, but it + * * adds dependencies + * * still leaves us with O(N^2) algorithm because + * preparation of function values is O(N^2) process + */ + if( p->n>1 ) + { + ae_vector_set_length(&tk, p->n, _state); + ae_vector_set_length(&tk1, p->n, _state); + for(i=0; i<=p->n-1; i++) + { + tk.ptr.p_double[i] = vx.ptr.p_double[i]; + tk1.ptr.p_double[i] = (double)(1); + } + for(k=1; k<=p->n-1; k++) + { + + /* + * calculate discrete product of function vector and TK + */ + v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1)); + t.ptr.p_double[k] = v/(0.5*(double)p->n); + + /* + * Update TK and TK1 + */ + for(i=0; i<=p->n-1; i++) + { + v = (double)2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i]; + tk1.ptr.p_double[i] = tk.ptr.p_double[i]; + tk.ptr.p_double[i] = v; + } + } + } + + /* + * Convert from Chebyshev basis to power basis + */ + ae_vector_set_length(a, p->n, _state); + for(i=0; i<=p->n-1; i++) + { + a->ptr.p_double[i] = (double)(0); + } + d = (double)(0); + for(i=0; i<=p->n-1; i++) + { + for(k=i; k<=p->n-1; k++) + { + e = a->ptr.p_double[k]; + a->ptr.p_double[k] = (double)(0); + if( i<=1&&k==i ) + { + a->ptr.p_double[k] = (double)(1); + } + else + { + if( i!=0 ) + { + a->ptr.p_double[k] = (double)2*d; + } + if( k>i+1 ) + { + a->ptr.p_double[k] = a->ptr.p_double[k]-a->ptr.p_double[k-2]; + } + } + d = e; + } + d = a->ptr.p_double[i]; + e = (double)(0); + k = i; + while(k<=p->n-1) + { + e = e+a->ptr.p_double[k]*t.ptr.p_double[k]; + k = k+2; + } + a->ptr.p_double[i] = e; + } + + /* + * Apply linear transformation which converts basis from intermediate + * one Fi=((x-C0)/S0)^i to final one Fi=((x-C)/S)^i. + * + * We have y=(x-C0)/S0, z=(x-C)/S, and coefficients A[] for basis Fi(y). + * Because we have y=A*z+B, for A=s/s0 and B=c/s0-c0/s0, we can perform + * substitution and get coefficients A_new[] in basis Fi(z). + */ + ae_assert(vp.cnt>=p->n+1, "PolynomialBar2Pow: internal error", _state); + ae_assert(t.cnt>=p->n, "PolynomialBar2Pow: internal error", _state); + for(i=0; i<=p->n-1; i++) + { + t.ptr.p_double[i] = 0.0; + } + va = s/s0; + vb = c/s0-c0/s0; + ae_vector_set_length(&vai, p->n, _state); + ae_vector_set_length(&vbi, p->n, _state); + vai.ptr.p_double[0] = (double)(1); + vbi.ptr.p_double[0] = (double)(1); + for(k=1; k<=p->n-1; k++) + { + vai.ptr.p_double[k] = vai.ptr.p_double[k-1]*va; + vbi.ptr.p_double[k] = vbi.ptr.p_double[k-1]*vb; + } + for(k=0; k<=p->n-1; k++) + { + + /* + * Generate set of binomial coefficients in VP[] + */ + if( k>0 ) + { + vp.ptr.p_double[k] = (double)(1); + for(i=k-1; i>=1; i--) + { + vp.ptr.p_double[i] = vp.ptr.p_double[i]+vp.ptr.p_double[i-1]; + } + vp.ptr.p_double[0] = (double)(1); + } + else + { + vp.ptr.p_double[0] = (double)(1); + } + + /* + * Update T[] with expansion of K-th basis function + */ + for(i=0; i<=k; i++) + { + t.ptr.p_double[i] = t.ptr.p_double[i]+a->ptr.p_double[k]*vai.ptr.p_double[i]*vbi.ptr.p_double[k-i]*vp.ptr.p_double[i]; + } + } + for(k=0; k<=p->n-1; k++) + { + a->ptr.p_double[k] = t.ptr.p_double[k]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Conversion from power basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + * if given, only leading N elements of A are used + * if not given, automatically determined from size of A + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + P - polynomial in barycentric form + + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if you interpolate on + [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, + x^3 and so on. In most cases you it is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, + (x-1000)^3 will be better option (you have to specify 1000.0 as offset + C and 1.0 as scale S). + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return barycentric model + in any case, but for N>8 accuracy well degrade. However, N's less than + 5 are pretty safe. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialpow2bar(/* Real */ const ae_vector* a, + ae_int_t n, + double c, + double s, + barycentricinterpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_vector y; + double vx; + double vy; + double px; + + ae_frame_make(_state, &_frame_block); + memset(&y, 0, sizeof(y)); + _barycentricinterpolant_clear(p); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_isfinite(c, _state), "PolynomialPow2Bar: C is not finite!", _state); + ae_assert(ae_isfinite(s, _state), "PolynomialPow2Bar: S is not finite!", _state); + ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialPow2Bar: S is zero!", _state); + ae_assert(n>=1, "PolynomialPow2Bar: N<1", _state); + ae_assert(a->cnt>=n, "PolynomialPow2Bar: Length(A)ptr.p_double[0]; + px = vx; + for(k=1; k<=n-1; k++) + { + vy = vy+px*a->ptr.p_double[k]; + px = px*vx; + } + y.ptr.p_double[i] = vy; + } + + /* + * Build barycentric interpolant, map grid from [-1,+1] to [A,B] + */ + polynomialbuildcheb1(c-s, c+s, &y, n, p, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Lagrange intepolant: generation of the model on the general grid. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + X - abscissas, array[0..N-1] + Y - function values, array[0..N-1] + N - number of points, N>=1 + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuild(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t j; + ae_int_t k; + ae_vector w; + double b; + double a; + double v; + double mx; + ae_vector sortrbuf; + ae_vector sortrbuf2; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + memset(&sortrbuf, 0, sizeof(sortrbuf)); + memset(&sortrbuf2, 0, sizeof(sortrbuf2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _barycentricinterpolant_clear(p); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "PolynomialBuild: N<=0!", _state); + ae_assert(x.cnt>=n, "PolynomialBuild: Length(X)=n, "PolynomialBuild: Length(Y)=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildeqdist(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector w; + ae_vector x; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&x, 0, sizeof(x)); + _barycentricinterpolant_clear(p); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "PolynomialBuildEqDist: N<=0!", _state); + ae_assert(y->cnt>=n, "PolynomialBuildEqDist: Length(Y)=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb1(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector w; + ae_vector x; + double v; + double t; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&x, 0, sizeof(x)); + _barycentricinterpolant_clear(p); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "PolynomialBuildCheb1: N<=0!", _state); + ae_assert(y->cnt>=n, "PolynomialBuildCheb1: Length(Y)=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb2(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector w; + ae_vector x; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&x, 0, sizeof(x)); + _barycentricinterpolant_clear(p); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "PolynomialBuildCheb2: N<=0!", _state); + ae_assert(y->cnt>=n, "PolynomialBuildCheb2: Length(Y)=1 + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolynomialBuildEqDist()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalceqdist(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state) +{ + double s1; + double s2; + double v; + double threshold; + double s; + double h; + ae_int_t i; + ae_int_t j; + double w; + double x; + double result; + + + ae_assert(n>0, "PolynomialCalcEqDist: N<=0!", _state); + ae_assert(f->cnt>=n, "PolynomialCalcEqDist: Length(F)v_nan; + return result; + } + + /* + * Special case: N=1 + */ + if( n==1 ) + { + result = f->ptr.p_double[0]; + return result; + } + + /* + * First, decide: should we use "safe" formula (guarded + * against overflow) or fast one? + */ + threshold = ae_sqrt(ae_minrealnumber, _state); + j = 0; + s = t-a; + for(i=1; i<=n-1; i++) + { + x = a+(double)i/(double)(n-1)*(b-a); + if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) + { + s = t-x; + j = i; + } + } + if( ae_fp_eq(s,(double)(0)) ) + { + result = f->ptr.p_double[j]; + return result; + } + if( ae_fp_greater(ae_fabs(s, _state),threshold) ) + { + + /* + * use fast formula + */ + j = -1; + s = 1.0; + } + + /* + * Calculate using safe or fast barycentric formula + */ + s1 = (double)(0); + s2 = (double)(0); + w = 1.0; + h = (b-a)/(double)(n-1); + for(i=0; i<=n-1; i++) + { + if( i!=j ) + { + v = s*w/(t-(a+(double)i*h)); + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + else + { + v = w; + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + w = -w*(double)(n-1-i); + w = w/(double)(i+1); + } + result = s1/s2; + return result; +} + + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (first kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (first kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb1()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb1(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state) +{ + double s1; + double s2; + double v; + double threshold; + double s; + ae_int_t i; + ae_int_t j; + double a0; + double delta; + double alpha; + double beta; + double ca; + double sa; + double tempc; + double temps; + double x; + double w; + double p1; + double result; + + + ae_assert(n>0, "PolynomialCalcCheb1: N<=0!", _state); + ae_assert(f->cnt>=n, "PolynomialCalcCheb1: Length(F)v_nan; + return result; + } + + /* + * Special case: N=1 + */ + if( n==1 ) + { + result = f->ptr.p_double[0]; + return result; + } + + /* + * Prepare information for the recurrence formula + * used to calculate sin(pi*(2j+1)/(2n+2)) and + * cos(pi*(2j+1)/(2n+2)): + * + * A0 = pi/(2n+2) + * Delta = pi/(n+1) + * Alpha = 2 sin^2 (Delta/2) + * Beta = sin(Delta) + * + * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). + * Then we use + * + * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) + * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) + * + * to repeatedly calculate sin(..) and cos(..). + */ + threshold = ae_sqrt(ae_minrealnumber, _state); + t = (t-0.5*(a+b))/(0.5*(b-a)); + a0 = ae_pi/(double)(2*(n-1)+2); + delta = (double)2*ae_pi/(double)(2*(n-1)+2); + alpha = (double)2*ae_sqr(ae_sin(delta/(double)2, _state), _state); + beta = ae_sin(delta, _state); + + /* + * First, decide: should we use "safe" formula (guarded + * against overflow) or fast one? + */ + ca = ae_cos(a0, _state); + sa = ae_sin(a0, _state); + j = 0; + x = ca; + s = t-x; + for(i=1; i<=n-1; i++) + { + + /* + * Next X[i] + */ + temps = sa-(alpha*sa-beta*ca); + tempc = ca-(alpha*ca+beta*sa); + sa = temps; + ca = tempc; + x = ca; + + /* + * Use X[i] + */ + if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) + { + s = t-x; + j = i; + } + } + if( ae_fp_eq(s,(double)(0)) ) + { + result = f->ptr.p_double[j]; + return result; + } + if( ae_fp_greater(ae_fabs(s, _state),threshold) ) + { + + /* + * use fast formula + */ + j = -1; + s = 1.0; + } + + /* + * Calculate using safe or fast barycentric formula + */ + s1 = (double)(0); + s2 = (double)(0); + ca = ae_cos(a0, _state); + sa = ae_sin(a0, _state); + p1 = 1.0; + for(i=0; i<=n-1; i++) + { + + /* + * Calculate X[i], W[i] + */ + x = ca; + w = p1*sa; + + /* + * Proceed + */ + if( i!=j ) + { + v = s*w/(t-x); + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + else + { + v = w; + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + + /* + * Next CA, SA, P1 + */ + temps = sa-(alpha*sa-beta*ca); + tempc = ca-(alpha*ca+beta*sa); + sa = temps; + ca = tempc; + p1 = -p1; + } + result = s1/s2; + return result; +} + + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (second kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (second kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb2()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb2(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state) +{ + double s1; + double s2; + double v; + double threshold; + double s; + ae_int_t i; + ae_int_t j; + double a0; + double delta; + double alpha; + double beta; + double ca; + double sa; + double tempc; + double temps; + double x; + double w; + double p1; + double result; + + + ae_assert(n>0, "PolynomialCalcCheb2: N<=0!", _state); + ae_assert(f->cnt>=n, "PolynomialCalcCheb2: Length(F)v_nan; + return result; + } + + /* + * Special case: N=1 + */ + if( n==1 ) + { + result = f->ptr.p_double[0]; + return result; + } + + /* + * Prepare information for the recurrence formula + * used to calculate sin(pi*i/n) and + * cos(pi*i/n): + * + * A0 = 0 + * Delta = pi/n + * Alpha = 2 sin^2 (Delta/2) + * Beta = sin(Delta) + * + * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta). + * Then we use + * + * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x)) + * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x)) + * + * to repeatedly calculate sin(..) and cos(..). + */ + threshold = ae_sqrt(ae_minrealnumber, _state); + t = (t-0.5*(a+b))/(0.5*(b-a)); + a0 = 0.0; + delta = ae_pi/(double)(n-1); + alpha = (double)2*ae_sqr(ae_sin(delta/(double)2, _state), _state); + beta = ae_sin(delta, _state); + + /* + * First, decide: should we use "safe" formula (guarded + * against overflow) or fast one? + */ + ca = ae_cos(a0, _state); + sa = ae_sin(a0, _state); + j = 0; + x = ca; + s = t-x; + for(i=1; i<=n-1; i++) + { + + /* + * Next X[i] + */ + temps = sa-(alpha*sa-beta*ca); + tempc = ca-(alpha*ca+beta*sa); + sa = temps; + ca = tempc; + x = ca; + + /* + * Use X[i] + */ + if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) ) + { + s = t-x; + j = i; + } + } + if( ae_fp_eq(s,(double)(0)) ) + { + result = f->ptr.p_double[j]; + return result; + } + if( ae_fp_greater(ae_fabs(s, _state),threshold) ) + { + + /* + * use fast formula + */ + j = -1; + s = 1.0; + } + + /* + * Calculate using safe or fast barycentric formula + */ + s1 = (double)(0); + s2 = (double)(0); + ca = ae_cos(a0, _state); + sa = ae_sin(a0, _state); + p1 = 1.0; + for(i=0; i<=n-1; i++) + { + + /* + * Calculate X[i], W[i] + */ + x = ca; + if( i==0||i==n-1 ) + { + w = 0.5*p1; + } + else + { + w = 1.0*p1; + } + + /* + * Proceed + */ + if( i!=j ) + { + v = s*w/(t-x); + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + else + { + v = w; + s1 = s1+v*f->ptr.p_double[i]; + s2 = s2+v; + } + + /* + * Next CA, SA, P1 + */ + temps = sa-(alpha*sa-beta*ca); + tempc = ca-(alpha*ca+beta*sa); + sa = temps; + ca = tempc; + p1 = -p1; + } + result = s1/s2; + return result; +} + + +#endif +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine builds linear spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinear(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + + _spline1dinterpolant_clear(c); + + spline1dbuildlinearbuf(x, y, n, c, _state); +} + + +/************************************************************************* +This subroutine builds linear spline interpolant. + +Buffered version of Spline1DBuildLinear() which reused memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinearbuf(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + + ae_assert(n>1, "Spline1DBuildLinear: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DBuildLinear: Length(X)=n, "Spline1DBuildLinear: Length(Y)periodic = ae_false; + c->n = n; + c->k = 3; + c->continuity = 0; + ae_vector_set_length(&c->x, n, _state); + ae_vector_set_length(&c->c, 4*(n-1)+2, _state); + for(i=0; i<=n-1; i++) + { + c->x.ptr.p_double[i] = x.ptr.p_double[i]; + } + for(i=0; i<=n-2; i++) + { + c->c.ptr.p_double[4*i+0] = y.ptr.p_double[i]; + c->c.ptr.p_double[4*i+1] = (y.ptr.p_double[i+1]-y.ptr.p_double[i])/(x.ptr.p_double[i+1]-x.ptr.p_double[i]); + c->c.ptr.p_double[4*i+2] = (double)(0); + c->c.ptr.p_double[4*i+3] = (double)(0); + } + c->c.ptr.p_double[4*(n-1)+0] = y.ptr.p_double[n-1]; + c->c.ptr.p_double[4*(n-1)+1] = c->c.ptr.p_double[4*(n-2)+1]; + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds cubic spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + C - spline interpolant + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + spline1dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector dt; + ae_vector d; + ae_vector p; + ae_int_t ylen; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&dt, 0, sizeof(dt)); + memset(&d, 0, sizeof(d)); + memset(&p, 0, sizeof(p)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _spline1dinterpolant_clear(c); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DBuildCubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DBuildCubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DBuildCubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DBuildCubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DBuildCubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DBuildCubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DBuildCubic: Length(X)=n, "Spline1DBuildCubic: Length(Y)periodic = boundltype==-1||boundrtype==-1; + c->continuity = 2; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns table of function derivatives d[] +(calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D - derivative values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiffcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector dt; + ae_vector p; + ae_int_t i; + ae_int_t ylen; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&dt, 0, sizeof(dt)); + memset(&p, 0, sizeof(p)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_clear(d); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiffCubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiffCubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiffCubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiffCubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiffCubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DGridDiffCubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DGridDiffCubic: Length(X)=n, "Spline1DGridDiffCubic: Length(Y)ptr.p_double[i]; + } + ae_v_move(&d->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns tables of first and second +function derivatives d1[] and d2[] (calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D1 - S' values at X[] + D2 - S'' values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiff2cubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d1, + /* Real */ ae_vector* d2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector dt; + ae_vector p; + ae_int_t i; + ae_int_t ylen; + double delta; + double delta2; + double delta3; + double s2; + double s3; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&dt, 0, sizeof(dt)); + memset(&p, 0, sizeof(p)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_clear(d1); + ae_vector_clear(d2); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiff2Cubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiff2Cubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiff2Cubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiff2Cubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiff2Cubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DGridDiff2Cubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DGridDiff2Cubic: Length(X)=n, "Spline1DGridDiff2Cubic: Length(Y)ptr.p_double[i]*delta-d1->ptr.p_double[i+1]*delta)/delta2; + s3 = ((double)2*(y.ptr.p_double[i]-y.ptr.p_double[i+1])+d1->ptr.p_double[i]*delta+d1->ptr.p_double[i+1]*delta)/delta3; + d2->ptr.p_double[i] = (double)2*s2; + } + d2->ptr.p_double[n-1] = (double)2*s2+(double)6*s3*delta; + + /* + * Remember that HeapSortPPoints() call? + * Now we have to reorder them back. + */ + if( dt.cntptr.p_double[i]; + } + ae_v_move(&d1->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + dt.ptr.p_double[p.ptr.p_int[i]] = d2->ptr.p_double[i]; + } + ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DCalc() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector x2; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector d; + ae_vector dt; + ae_vector d1; + ae_vector d2; + ae_vector p; + ae_vector p2; + ae_int_t i; + ae_int_t ylen; + double t; + double t2; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&x2, 0, sizeof(x2)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&d, 0, sizeof(d)); + memset(&dt, 0, sizeof(dt)); + memset(&d1, 0, sizeof(d1)); + memset(&d2, 0, sizeof(d2)); + memset(&p, 0, sizeof(p)); + memset(&p2, 0, sizeof(p2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&x2, _x2, _state, ae_true); + ae_vector_clear(y2); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvCubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvCubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvCubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DConvCubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DConvCubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DConvCubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DConvCubic: Length(X)=n, "Spline1DConvCubic: Length(Y)=2, "Spline1DConvCubic: N2<2!", _state); + ae_assert(x2.cnt>=n2, "Spline1DConvCubic: Length(X2)=n2, "Spline1DConvCubic: internal error!", _state); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; + } + ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] and derivatives d2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiffcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + /* Real */ ae_vector* d2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector x2; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector d; + ae_vector dt; + ae_vector rt1; + ae_vector p; + ae_vector p2; + ae_int_t i; + ae_int_t ylen; + double t; + double t2; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&x2, 0, sizeof(x2)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&d, 0, sizeof(d)); + memset(&dt, 0, sizeof(dt)); + memset(&rt1, 0, sizeof(rt1)); + memset(&p, 0, sizeof(p)); + memset(&p2, 0, sizeof(p2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&x2, _x2, _state, ae_true); + ae_vector_clear(y2); + ae_vector_clear(d2); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rt1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiffCubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiffCubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiffCubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiffCubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiffCubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DConvDiffCubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DConvDiffCubic: Length(X)=n, "Spline1DConvDiffCubic: Length(Y)=2, "Spline1DConvDiffCubic: N2<2!", _state); + ae_assert(x2.cnt>=n2, "Spline1DConvDiffCubic: Length(X2)=n2, "Spline1DConvDiffCubic: internal error!", _state); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; + } + ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; + } + ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[], first and second derivatives d2[] and dd2[] +(calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + DD2 - second derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiff2cubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + /* Real */ ae_vector* d2, + /* Real */ ae_vector* dd2, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector x2; + ae_vector a1; + ae_vector a2; + ae_vector a3; + ae_vector b; + ae_vector d; + ae_vector dt; + ae_vector p; + ae_vector p2; + ae_int_t i; + ae_int_t ylen; + double t; + double t2; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&x2, 0, sizeof(x2)); + memset(&a1, 0, sizeof(a1)); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&b, 0, sizeof(b)); + memset(&d, 0, sizeof(d)); + memset(&dt, 0, sizeof(dt)); + memset(&p, 0, sizeof(p)); + memset(&p2, 0, sizeof(p2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&x2, _x2, _state, ae_true); + ae_vector_clear(y2); + ae_vector_clear(d2); + ae_vector_clear(dd2); + ae_vector_init(&a1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + + /* + * check correctness of boundary conditions + */ + ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiff2Cubic: incorrect BoundLType!", _state); + ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiff2Cubic: incorrect BoundRType!", _state); + ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiff2Cubic: incorrect BoundLType/BoundRType!", _state); + if( boundltype==1||boundltype==2 ) + { + ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiff2Cubic: BoundL is infinite or NAN!", _state); + } + if( boundrtype==1||boundrtype==2 ) + { + ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiff2Cubic: BoundR is infinite or NAN!", _state); + } + + /* + * check lengths of arguments + */ + ae_assert(n>=2, "Spline1DConvDiff2Cubic: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DConvDiff2Cubic: Length(X)=n, "Spline1DConvDiff2Cubic: Length(Y)=2, "Spline1DConvDiff2Cubic: N2<2!", _state); + ae_assert(x2.cnt>=n2, "Spline1DConvDiff2Cubic: Length(X2)=n2, "Spline1DConvDiff2Cubic: internal error!", _state); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i]; + } + ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i]; + } + ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + for(i=0; i<=n2-1; i++) + { + dt.ptr.p_double[p2.ptr.p_int[i]] = dd2->ptr.p_double[i]; + } + ae_v_move(&dd2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds Catmull-Rom spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundType - boundary condition type: + * -1 for periodic boundary condition + * 0 for parabolically terminated spline (default) + Tension - tension parameter: + * tension=0 corresponds to classic Catmull-Rom spline (default) + * 0=2, "Spline1DBuildCatmullRom: N<2!", _state); + ae_assert(boundtype==-1||boundtype==0, "Spline1DBuildCatmullRom: incorrect BoundType!", _state); + ae_assert(ae_fp_greater_eq(tension,(double)(0)), "Spline1DBuildCatmullRom: Tension<0!", _state); + ae_assert(ae_fp_less_eq(tension,(double)(1)), "Spline1DBuildCatmullRom: Tension>1!", _state); + ae_assert(x.cnt>=n, "Spline1DBuildCatmullRom: Length(X)=n, "Spline1DBuildCatmullRom: Length(Y)periodic = ae_true; + } + else + { + + /* + * Non-periodic boundary conditions + */ + ae_vector_set_length(&d, n, _state); + for(i=1; i<=n-2; i++) + { + d.ptr.p_double[i] = ((double)1-tension)*(y.ptr.p_double[i+1]-y.ptr.p_double[i-1])/(x.ptr.p_double[i+1]-x.ptr.p_double[i-1]); + } + d.ptr.p_double[0] = (double)2*(y.ptr.p_double[1]-y.ptr.p_double[0])/(x.ptr.p_double[1]-x.ptr.p_double[0])-d.ptr.p_double[1]; + d.ptr.p_double[n-1] = (double)2*(y.ptr.p_double[n-1]-y.ptr.p_double[n-2])/(x.ptr.p_double[n-1]-x.ptr.p_double[n-2])-d.ptr.p_double[n-2]; + + /* + * Now problem is reduced to the cubic Hermite spline + */ + spline1dbuildhermite(&x, &y, &d, n, c, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + D - derivatives, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermite(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* d, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + + _spline1dinterpolant_clear(c); + + spline1dbuildhermitebuf(x, y, d, n, c, _state); +} + + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +Buffered version which reuses memory previously allocated in C as much as +possible. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermitebuf(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _d, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector d; + ae_int_t i; + double delta; + double delta2; + double delta3; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&d, 0, sizeof(d)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&d, _d, _state, ae_true); + + ae_assert(n>=2, "Spline1DBuildHermite: N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DBuildHermite: Length(X)=n, "Spline1DBuildHermite: Length(Y)=n, "Spline1DBuildHermite: Length(D)x, n, _state); + ae_vector_set_length(&c->c, 4*(n-1)+2, _state); + c->periodic = ae_false; + c->k = 3; + c->n = n; + c->continuity = 1; + for(i=0; i<=n-1; i++) + { + c->x.ptr.p_double[i] = x.ptr.p_double[i]; + } + for(i=0; i<=n-2; i++) + { + delta = x.ptr.p_double[i+1]-x.ptr.p_double[i]; + delta2 = ae_sqr(delta, _state); + delta3 = delta*delta2; + c->c.ptr.p_double[4*i+0] = y.ptr.p_double[i]; + c->c.ptr.p_double[4*i+1] = d.ptr.p_double[i]; + c->c.ptr.p_double[4*i+2] = ((double)3*(y.ptr.p_double[i+1]-y.ptr.p_double[i])-(double)2*d.ptr.p_double[i]*delta-d.ptr.p_double[i+1]*delta)/delta2; + c->c.ptr.p_double[4*i+3] = ((double)2*(y.ptr.p_double[i]-y.ptr.p_double[i+1])+d.ptr.p_double[i]*delta+d.ptr.p_double[i+1]*delta)/delta3; + } + c->c.ptr.p_double[4*(n-1)+0] = y.ptr.p_double[n-1]; + c->c.ptr.p_double[4*(n-1)+1] = d.ptr.p_double[n-1]; + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds Akima spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakima(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + + _spline1dinterpolant_clear(c); + + spline1d_buildakimax(x, y, n, ae_false, c, _state); +} + + +/************************************************************************* +This subroutine builds modified Akima spline interpolant, with weights + + W[i]=|Delta[I]-Delta[I-1]| + +replaced by + + W[i]=|Delta[I]-Delta[I-1]|+0.5*|Delta[I]+Delta[I-1]| + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakimamod(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + + _spline1dinterpolant_clear(c); + + spline1d_buildakimax(x, y, n, ae_true, c, _state); +} + + +/************************************************************************* +This subroutine calculates the value of the spline at the given point X. + +INPUT PARAMETERS: + C - spline interpolant + X - point + +Result: + S(x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dcalc(const spline1dinterpolant* c, + double x, + ae_state *_state) +{ + ae_int_t l; + ae_int_t r; + ae_int_t m; + double t; + double result; + + + ae_assert(c->k==3, "Spline1DCalc: internal error", _state); + ae_assert(!ae_isinf(x, _state), "Spline1DCalc: infinite X!", _state); + + /* + * special case: NaN + */ + if( ae_isnan(x, _state) ) + { + result = _state->v_nan; + return result; + } + + /* + * correct if periodic + */ + if( c->periodic ) + { + apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); + } + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-2+1; + while(l!=r-1) + { + m = (l+r)/2; + if( c->x.ptr.p_double[m]>=x ) + { + r = m; + } + else + { + l = m; + } + } + + /* + * Interpolation + */ + x = x-c->x.ptr.p_double[l]; + m = 4*l; + result = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); + return result; +} + + +/************************************************************************* +This subroutine differentiates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +Result: + S - S(x) + DS - S'(x) + D2S - S''(x) + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1ddiff(const spline1dinterpolant* c, + double x, + double* s, + double* ds, + double* d2s, + ae_state *_state) +{ + ae_int_t l; + ae_int_t r; + ae_int_t m; + double t; + + *s = 0.0; + *ds = 0.0; + *d2s = 0.0; + + ae_assert(c->k==3, "Spline1DDiff: internal error", _state); + ae_assert(!ae_isinf(x, _state), "Spline1DDiff: infinite X!", _state); + + /* + * special case: NaN + */ + if( ae_isnan(x, _state) ) + { + *s = _state->v_nan; + *ds = _state->v_nan; + *d2s = _state->v_nan; + return; + } + + /* + * correct if periodic + */ + if( c->periodic ) + { + apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); + } + + /* + * Binary search + */ + l = 0; + r = c->n-2+1; + while(l!=r-1) + { + m = (l+r)/2; + if( c->x.ptr.p_double[m]>=x ) + { + r = m; + } + else + { + l = m; + } + } + + /* + * Differentiation + */ + x = x-c->x.ptr.p_double[l]; + m = 4*l; + *s = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3])); + *ds = c->c.ptr.p_double[m+1]+(double)2*x*c->c.ptr.p_double[m+2]+(double)3*ae_sqr(x, _state)*c->c.ptr.p_double[m+3]; + *d2s = (double)2*c->c.ptr.p_double[m+2]+(double)6*x*c->c.ptr.p_double[m+3]; +} + + +/************************************************************************* +This subroutine makes the copy of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + +Result: + CC - spline copy + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dcopy(const spline1dinterpolant* c, + spline1dinterpolant* cc, + ae_state *_state) +{ + ae_int_t s; + + _spline1dinterpolant_clear(cc); + + cc->periodic = c->periodic; + cc->n = c->n; + cc->k = c->k; + cc->continuity = c->continuity; + ae_vector_set_length(&cc->x, cc->n, _state); + ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); + s = c->c.cnt; + ae_vector_set_length(&cc->c, s, _state); + ae_v_move(&cc->c.ptr.p_double[0], 1, &c->c.ptr.p_double[0], 1, ae_v_len(0,s-1)); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 16.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dalloc(ae_serializer* s, + const spline1dinterpolant* model, + ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &model->x, model->n, _state); + allocrealarray(s, &model->c, 4*(model->n-1)+2, _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 16.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dserialize(ae_serializer* s, + const spline1dinterpolant* model, + ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_serialize_int(s, getspline1dserializationcode(_state), _state); + ae_serializer_serialize_int(s, 0, _state); + + /* + * Data + */ + ae_serializer_serialize_bool(s, model->periodic, _state); + ae_serializer_serialize_int(s, model->n, _state); + ae_serializer_serialize_int(s, model->k, _state); + ae_serializer_serialize_int(s, model->continuity, _state); + serializerealarray(s, &model->x, model->n, _state); + serializerealarray(s, &model->c, 4*(model->n-1)+2, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 16.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dunserialize(ae_serializer* s, + spline1dinterpolant* model, + ae_state *_state) +{ + ae_int_t k; + + _spline1dinterpolant_clear(model); + + + /* + * Header + */ + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==getspline1dserializationcode(_state), "Spline1DUnserialize: stream header corrupted or wrong data supplied to unserializer", _state); + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==0, "Spline1DUnserialize: unsupported spline version", _state); + + /* + * Data + */ + ae_serializer_unserialize_bool(s, &model->periodic, _state); + ae_serializer_unserialize_int(s, &model->n, _state); + ae_serializer_unserialize_int(s, &model->k, _state); + ae_serializer_unserialize_int(s, &model->continuity, _state); + unserializerealarray(s, &model->x, _state); + unserializerealarray(s, &model->c, _state); +} + + +/************************************************************************* +This subroutine unpacks the spline into the coefficients table. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +OUTPUT PARAMETERS: + Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. + For I = 0...N-2: + Tbl[I,0] = X[i] + Tbl[I,1] = X[i+1] + Tbl[I,2] = C0 + Tbl[I,3] = C1 + Tbl[I,4] = C2 + Tbl[I,5] = C3 + On [x[i], x[i+1]] spline is equals to: + S(x) = C0 + C1*t + C2*t^2 + C3*t^3 + t = x-x[i] + +NOTE: + You can rebuild spline with Spline1DBuildHermite() function, which + accepts as inputs function values and derivatives at nodes, which are + easy to calculate when you have coefficients. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dunpack(const spline1dinterpolant* c, + ae_int_t* n, + /* Real */ ae_matrix* tbl, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + *n = 0; + ae_matrix_clear(tbl); + + ae_matrix_set_length(tbl, c->n-2+1, 2+c->k+1, _state); + *n = c->n; + + /* + * Fill + */ + for(i=0; i<=*n-2; i++) + { + tbl->ptr.pp_double[i][0] = c->x.ptr.p_double[i]; + tbl->ptr.pp_double[i][1] = c->x.ptr.p_double[i+1]; + for(j=0; j<=c->k; j++) + { + tbl->ptr.pp_double[i][2+j] = c->c.ptr.p_double[(c->k+1)*i+j]; + } + } +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: x = A*t + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransx(spline1dinterpolant* c, + double a, + double b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t n; + double v; + double dv; + double d2v; + ae_vector x; + ae_vector y; + ae_vector d; + ae_bool isperiodic; + ae_int_t contval; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&d, 0, sizeof(d)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + + ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); + n = c->n; + ae_vector_set_length(&x, n, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&d, n, _state); + + /* + * Unpack, X, Y, dY/dX. + * Scale and pack with Spline1DBuildHermite again. + */ + if( ae_fp_eq(a,(double)(0)) ) + { + + /* + * Special case: A=0 + */ + v = spline1dcalc(c, b, _state); + for(i=0; i<=n-1; i++) + { + x.ptr.p_double[i] = c->x.ptr.p_double[i]; + y.ptr.p_double[i] = v; + d.ptr.p_double[i] = 0.0; + } + } + else + { + + /* + * General case, A<>0 + */ + for(i=0; i<=n-1; i++) + { + x.ptr.p_double[i] = c->x.ptr.p_double[i]; + spline1ddiff(c, x.ptr.p_double[i], &v, &dv, &d2v, _state); + x.ptr.p_double[i] = (x.ptr.p_double[i]-b)/a; + y.ptr.p_double[i] = v; + d.ptr.p_double[i] = a*dv; + } + } + isperiodic = c->periodic; + contval = c->continuity; + if( contval>0 ) + { + spline1dbuildhermitebuf(&x, &y, &d, n, c, _state); + } + else + { + spline1dbuildlinearbuf(&x, &y, n, c, _state); + } + c->periodic = isperiodic; + c->continuity = contval; + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x) = A*S(x) + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransy(spline1dinterpolant* c, + double a, + double b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + + ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state); + n = c->n; + for(i=0; i<=n-2; i++) + { + c->c.ptr.p_double[4*i] = a*c->c.ptr.p_double[4*i]+b; + for(j=1; j<=3; j++) + { + c->c.ptr.p_double[4*i+j] = a*c->c.ptr.p_double[4*i+j]; + } + } + c->c.ptr.p_double[4*(n-1)+0] = a*c->c.ptr.p_double[4*(n-1)+0]+b; + c->c.ptr.p_double[4*(n-1)+1] = a*c->c.ptr.p_double[4*(n-1)+1]; +} + + +/************************************************************************* +This subroutine integrates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - right bound of the integration interval [a, x], + here 'a' denotes min(x[]) +Result: + integral(S(t)dt,a,x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dintegrate(const spline1dinterpolant* c, + double x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t l; + ae_int_t r; + ae_int_t m; + double w; + double v; + double t; + double intab; + double additionalterm; + double result; + + + n = c->n; + + /* + * Periodic splines require special treatment. We make + * following transformation: + * + * integral(S(t)dt,A,X) = integral(S(t)dt,A,Z)+AdditionalTerm + * + * here X may lie outside of [A,B], Z lies strictly in [A,B], + * AdditionalTerm is equals to integral(S(t)dt,A,B) times some + * integer number (may be zero). + */ + if( c->periodic&&(ae_fp_less(x,c->x.ptr.p_double[0])||ae_fp_greater(x,c->x.ptr.p_double[c->n-1])) ) + { + + /* + * compute integral(S(x)dx,A,B) + */ + intab = (double)(0); + for(i=0; i<=c->n-2; i++) + { + w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; + m = (c->k+1)*i; + intab = intab+c->c.ptr.p_double[m]*w; + v = w; + for(j=1; j<=c->k; j++) + { + v = v*w; + intab = intab+c->c.ptr.p_double[m+j]*v/(double)(j+1); + } + } + + /* + * map X into [A,B] + */ + apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state); + additionalterm = t*intab; + } + else + { + additionalterm = (double)(0); + } + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = n-2+1; + while(l!=r-1) + { + m = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[m],x) ) + { + r = m; + } + else + { + l = m; + } + } + + /* + * Integration + */ + result = (double)(0); + for(i=0; i<=l-1; i++) + { + w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]; + m = (c->k+1)*i; + result = result+c->c.ptr.p_double[m]*w; + v = w; + for(j=1; j<=c->k; j++) + { + v = v*w; + result = result+c->c.ptr.p_double[m+j]*v/(double)(j+1); + } + } + w = x-c->x.ptr.p_double[l]; + m = (c->k+1)*l; + v = w; + result = result+c->c.ptr.p_double[m]*w; + for(j=1; j<=c->k; j++) + { + v = v*w; + result = result+c->c.ptr.p_double[m+j]*v/(double)(j+1); + } + result = result+additionalterm; + return result; +} + + +/************************************************************************* +Fitting by the smoothing (penalized) cubic spline. + +This function approximates N scattered points (some of X[] may be equal to +each other) by the cubic spline with M equidistant nodes spanning interval +[min(x),max(x)]. + +The problem is regularized by adding nonlinearity penalty to the usual +least squares penalty function: + + MERIT_FUNC = F_LS + F_NL + +where F_LS is a least squares error term, and F_NL is a nonlinearity +penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }. +Algorithm applies automatic renormalization of F_NL which makes penalty +term roughly invariant to scaling of X[] and changes in M. + +This function is a new edition of penalized regression spline fitting, +a fast and compact one which needs much less resources that its previous +version: just O(maxMN) memory and O(maxMN) time. + +NOTE: it is OK to run this function with both M<>N; say, it is + possible to process 100 points with 1000-node spline. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y are processed + * if not given, automatically determined from lengths + M - number of basis functions ( = number_of_nodes), M>=4. + LambdaNS - LambdaNS>=0, regularization constant passed by user. + It penalizes nonlinearity in the regression spline. + Possible values to start from are 0.00001, 0.1, 1 + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - Following fields are set: + * TerminationType set to 1 + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + + -- ALGLIB PROJECT -- + Copyright 10.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dfit(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t m, + double lambdans, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + double xa; + double xb; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + ae_vector xywork; + ae_matrix vterm; + ae_vector sx; + ae_vector sy; + ae_vector sdy; + sparsematrix av; + sparsematrix ah; + sparsematrix ata; + ae_vector targets; + double meany; + ae_int_t lsqrcnt; + ae_int_t nrel; + double rss; + double tss; + ae_int_t arows; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + linlsqrstate solver; + linlsqrreport srep; + double creg; + double mxata; + ae_int_t bw; + ae_vector nzidx0; + ae_vector nzval0; + ae_int_t nzcnt0; + ae_vector nzidx1; + ae_vector nzval1; + ae_int_t nzcnt1; + ae_int_t nnz; + ae_int_t offs; + ae_int_t outrow; + double scaletargetsby; + double scalepenaltyby; + spline1dbbasis basis; + ae_bool dotrace; + ae_int_t itidx; + ae_vector tmpx; + ae_vector tmpy; + spline1dinterpolant tmps; + ae_int_t tstart; + ae_int_t t1; + ae_matrix densea; + ae_vector tau; + double f; + double df; + double d2f; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&xywork, 0, sizeof(xywork)); + memset(&vterm, 0, sizeof(vterm)); + memset(&sx, 0, sizeof(sx)); + memset(&sy, 0, sizeof(sy)); + memset(&sdy, 0, sizeof(sdy)); + memset(&av, 0, sizeof(av)); + memset(&ah, 0, sizeof(ah)); + memset(&ata, 0, sizeof(ata)); + memset(&targets, 0, sizeof(targets)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&tmp2, 0, sizeof(tmp2)); + memset(&solver, 0, sizeof(solver)); + memset(&srep, 0, sizeof(srep)); + memset(&nzidx0, 0, sizeof(nzidx0)); + memset(&nzval0, 0, sizeof(nzval0)); + memset(&nzidx1, 0, sizeof(nzidx1)); + memset(&nzval1, 0, sizeof(nzval1)); + memset(&basis, 0, sizeof(basis)); + memset(&tmpx, 0, sizeof(tmpx)); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&tmps, 0, sizeof(tmps)); + memset(&densea, 0, sizeof(densea)); + memset(&tau, 0, sizeof(tau)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sdy, 0, DT_REAL, _state, ae_true); + _sparsematrix_init(&av, _state, ae_true); + _sparsematrix_init(&ah, _state, ae_true); + _sparsematrix_init(&ata, _state, ae_true); + ae_vector_init(&targets, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + _linlsqrstate_init(&solver, _state, ae_true); + _linlsqrreport_init(&srep, _state, ae_true); + ae_vector_init(&nzidx0, 0, DT_INT, _state, ae_true); + ae_vector_init(&nzval0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&nzidx1, 0, DT_INT, _state, ae_true); + ae_vector_init(&nzval1, 0, DT_REAL, _state, ae_true); + _spline1dbbasis_init(&basis, _state, ae_true); + ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + _spline1dinterpolant_init(&tmps, _state, ae_true); + ae_matrix_init(&densea, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "Spline1DFit: N<1!", _state); + ae_assert(m>=1, "Spline1DFit: M<1!", _state); + ae_assert(x.cnt>=n, "Spline1DFit: Length(X)=n, "Spline1DFit: Length(Y) dataset sorted in %0d ms, interpolation interval determined to be [%0.6e,%0.6e]\n", + (int)(ae_tickcount()-t1), + (double)(xa), + (double)(xb)); + } + + /* + * Convert X/Y to work representation, remove linear trend (in + * order to improve condition number). + * + * Compute total-sum-of-squares (needed later for R2 coefficient). + */ + ae_vector_set_length(&xywork, 2*n, _state); + for(i=0; i<=n-1; i++) + { + xywork.ptr.p_double[2*i+0] = (x.ptr.p_double[i]-xa)/(xb-xa); + xywork.ptr.p_double[2*i+1] = y.ptr.p_double[i]; + } + buildpriorterm1(&xywork, n, 1, 1, 1, 0.0, &vterm, _state); + meany = (double)(0); + for(i=0; i<=n-1; i++) + { + meany = meany+y.ptr.p_double[i]; + } + meany = meany/(double)n; + tss = (double)(0); + for(i=0; i<=n-1; i++) + { + tss = tss+ae_sqr(y.ptr.p_double[i]-meany, _state); + } + + /* + * Depending on M, use either general purpose algorithm that needs M>=4 or a compact one + */ + arows = n+m+m; + if( m>=4 ) + { + + /* + * Generate design matrix and targets + */ + if( dotrace ) + { + t1 = ae_tickcount(); + } + rsetallocv(arows, 0.0, &targets, _state); + spline1d_bbasisinit(&basis, m, _state); + nnz = (n+m)*2*basis.bfrad+m; + av.m = arows; + av.n = m; + iallocv(av.m+1, &av.ridx, _state); + iallocv(nnz, &av.idx, _state); + rallocv(nnz, &av.vals, _state); + av.ridx.ptr.p_int[0] = 0; + offs = 0; + outrow = 0; + for(i=0; i<=n-1; i++) + { + + /* + * Generate design matrix row #I which corresponds to I-th dataset point + */ + k = ae_ifloor(boundval(xywork.ptr.p_double[2*i+0]*(double)(m-1), (double)(0), (double)(m-1), _state), _state); + k0 = ae_maxint(k-(basis.bfrad-1), 0, _state); + k1 = ae_minint(k+1+(basis.bfrad-1), m-1, _state); + for(j=k0; j<=k1; j++) + { + av.idx.ptr.p_int[offs] = j; + av.vals.ptr.p_double[offs] = spline1d_basiscalc(&basis, j, xywork.ptr.p_double[2*i+0], _state)*scaletargetsby; + offs = offs+1; + } + targets.ptr.p_double[i] = xywork.ptr.p_double[2*i+1]*scaletargetsby; + av.ridx.ptr.p_int[outrow+1] = offs; + outrow = outrow+1; + } + for(i=0; i<=m-1; i++) + { + + /* + * Generate design matrix row #(I+N) which corresponds to nonlinearity penalty at I-th node + */ + k0 = ae_maxint(i-(basis.bfrad-1), 0, _state); + k1 = ae_minint(i+(basis.bfrad-1), m-1, _state); + for(j=k0; j<=k1; j++) + { + av.idx.ptr.p_int[offs] = j; + av.vals.ptr.p_double[offs] = spline1d_basisdiff2(&basis, j, (double)i/(double)(m-1), _state)*scalepenaltyby*lambdans; + offs = offs+1; + } + av.ridx.ptr.p_int[outrow+1] = offs; + outrow = outrow+1; + } + for(i=0; i<=m-1; i++) + { + + /* + * Generate design matrix row #(I+N+M) which corresponds to regularization for I-th coefficient + */ + av.idx.ptr.p_int[offs] = i; + av.vals.ptr.p_double[offs] = spline1d_lambdareg; + offs = offs+1; + av.ridx.ptr.p_int[outrow+1] = offs; + outrow = outrow+1; + } + ae_assert(outrow==av.m&&offs<=nnz, "SPLINE1DFIT: integrity check 6606 failed", _state); + sparsecreatecrsinplace(&av, _state); + sparsecopytransposecrs(&av, &ah, _state); + if( dotrace ) + { + ae_trace("> design matrix generated in %0d ms, %0d nonzeros\n", + (int)(ae_tickcount()-t1), + (int)(av.ridx.ptr.p_int[av.m])); + } + + /* + * Build 7-diagonal (bandwidth=3) normal equations matrix and perform Cholesky + * decomposition (to be used later as preconditioner for LSQR iterations). + */ + if( dotrace ) + { + t1 = ae_tickcount(); + } + bw = 2*(basis.bfrad-1); + sparsecreatesksband(m, m, bw, &ata, _state); + mxata = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=i; j<=ae_minint(i+bw, m-1, _state); j++) + { + + /* + * Get pattern of nonzeros in one of the rows (let it be I-th one) + * and compute dot product only for nonzero entries. + */ + sparsegetcompressedrow(&ah, i, &nzidx0, &nzval0, &nzcnt0, _state); + sparsegetcompressedrow(&ah, j, &nzidx1, &nzval1, &nzcnt1, _state); + v = (double)(0); + k0 = 0; + k1 = 0; + for(;;) + { + if( k0==nzcnt0 ) + { + break; + } + if( k1==nzcnt1 ) + { + break; + } + if( nzidx0.ptr.p_int[k0]nzidx1.ptr.p_int[k1] ) + { + k1 = k1+1; + continue; + } + v = v+nzval0.ptr.p_double[k0]*nzval1.ptr.p_double[k1]; + k0 = k0+1; + k1 = k1+1; + } + + /* + * Update ATA and max(ATA) + */ + sparseset(&ata, i, j, v, _state); + if( i==j ) + { + mxata = ae_maxreal(mxata, ae_fabs(v, _state), _state); + } + } + } + mxata = coalesce(mxata, 1.0, _state); + creg = spline1d_cholreg; + for(;;) + { + + /* + * Regularization + */ + for(i=0; i<=m-1; i++) + { + sparseset(&ata, i, i, sparseget(&ata, i, i, _state)+mxata*creg, _state); + } + + /* + * Try Cholesky factorization. + */ + if( !sparsecholeskyskyline(&ata, m, ae_true, _state) ) + { + + /* + * Factorization failed, increase regularizer and repeat + */ + creg = coalesce((double)10*creg, 1.0E-12, _state); + if( dotrace ) + { + ae_trace("> preconditioner factorization failed, increasing regularization to %0.2e\n", + (double)(creg)); + } + continue; + } + break; + } + if( dotrace ) + { + ae_trace("> preconditioner generated in %0d ms\n", + (int)(ae_tickcount()-t1)); + } + + /* + * Solve with preconditioned LSQR: + * + * use Cholesky factor U of squared design matrix A'*A to + * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x. + * + * Preconditioned problem is solved with LSQR solver, which + * gives superior results to normal equations approach. Due + * to Cholesky preconditioner being utilized we can solve + * problem in just a few iterations. + */ + rallocv(arows, &tmp0, _state); + rallocv(m, &tmp1, _state); + rallocv(m, &tmp2, _state); + linlsqrcreatebuf(arows, m, &solver, _state); + linlsqrsetb(&solver, &targets, _state); + linlsqrsetcond(&solver, (double)1000*ae_machineepsilon, (double)1000*ae_machineepsilon, lsqrcnt, _state); + if( dotrace ) + { + t1 = ae_tickcount(); + ae_trace("> starting LSQR iterations:\n"); + linlsqrsetxrep(&solver, ae_true, _state); + } + itidx = 0; + while(linlsqriteration(&solver, _state)) + { + if( solver.needmv ) + { + for(i=0; i<=m-1; i++) + { + tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i]; + } + + /* + * Use Cholesky factorization of the system matrix + * as preconditioner: solve TRSV(U,Solver.X) + */ + sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state); + + /* + * After preconditioning is done, multiply by A + */ + sparsemv(&av, &tmp1, &solver.mv, _state); + continue; + } + if( solver.needmtv ) + { + + /* + * Multiply by design matrix A + */ + sparsemtv(&av, &solver.x, &solver.mtv, _state); + + /* + * Multiply by preconditioner: solve TRSV(U',A*Solver.X) + */ + sparsetrsv(&ata, ae_true, ae_false, 1, &solver.mtv, _state); + continue; + } + if( solver.xupdated ) + { + + /* + * Compute squared residual for normal equations system (more meaningful reports) + */ + if( dotrace ) + { + + /* + * Compute A*x + */ + rcopyv(m, &solver.x, &tmp2, _state); + sparsetrsv(&ata, ae_true, ae_false, 0, &tmp2, _state); + sparsemv(&av, &tmp2, &tmp0, _state); + + /* + * Compute residual r + */ + raddv(arows, -1.0, &targets, &tmp0, _state); + + /* + * Compute A'*r + */ + sparsemtv(&av, &tmp0, &tmp1, _state); + sparsetrsv(&ata, ae_true, ae_false, 1, &tmp1, _state); + ae_trace(">> iteration %0d, |r|=%0.2e, |(A^T)*r|=%0.2e\n", + (int)(itidx), + (double)(ae_sqrt(rdotv2(arows, &tmp0, _state), _state)), + (double)(ae_sqrt(rdotv2(m, &tmp1, _state), _state))); + } + itidx = itidx+1; + continue; + } + ae_assert(ae_false, "SPLINE1D: integrity check 6344 failed", _state); + } + linlsqrresults(&solver, &tmp1, &srep, _state); + sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state); + if( dotrace ) + { + ae_trace(">> solved in %0d ms, solution norm is %0.2e\n", + (int)(ae_tickcount()-t1), + (double)(ae_sqrt(rdotv2(m, &tmp1, _state), _state))); + } + + /* + * Convert from B-basis to C2-continuous Hermite spline + */ + rallocv(m, &sx, _state); + for(i=0; i<=m-1; i++) + { + sx.ptr.p_double[i] = (double)i/(double)(m-1); + } + rsetallocv(m, 0.0, &sy, _state); + rsetallocv(m, 0.0, &sdy, _state); + for(i=0; i<=m-1; i++) + { + for(j=ae_maxint(i-(basis.bfrad-1), 0, _state); j<=ae_minint(i+(basis.bfrad-1), m-1, _state); j++) + { + sy.ptr.p_double[j] = sy.ptr.p_double[j]+tmp1.ptr.p_double[i]*spline1d_basiscalc(&basis, i, (double)j/(double)(m-1), _state); + sdy.ptr.p_double[j] = sdy.ptr.p_double[j]+tmp1.ptr.p_double[i]*spline1d_basisdiff(&basis, i, (double)j/(double)(m-1), _state); + } + } + spline1dbuildhermite(&sx, &sy, &sdy, m, &tmps, _state); + } + else + { + + /* + * A special purpose algorithm for M<4 + */ + rsetallocm(arows, m+1, 0.0, &densea, _state); + for(i=0; i<=n-1; i++) + { + densea.ptr.pp_double[i][m] = xywork.ptr.p_double[2*i+1]*scaletargetsby; + } + rallocv(m, &tmpx, _state); + for(i=0; i<=m-1; i++) + { + tmpx.ptr.p_double[i] = (double)i/(double)(m-1); + } + for(j=0; j<=m-1; j++) + { + rsetallocv(m, 0.0, &tmpy, _state); + tmpy.ptr.p_double[j] = (double)(1); + spline1dbuildcubic(&tmpx, &tmpy, m, 2, 0.0, 2, 0.0, &tmps, _state); + for(i=0; i<=n-1; i++) + { + densea.ptr.pp_double[i][j] = spline1dcalc(&tmps, xywork.ptr.p_double[2*i+0], _state)*scaletargetsby; + } + for(i=0; i<=m-1; i++) + { + spline1ddiff(&tmps, (double)i/(double)(m-1), &f, &df, &d2f, _state); + densea.ptr.pp_double[n+i][j] = d2f*scalepenaltyby*lambdans; + } + } + for(i=0; i<=m-1; i++) + { + densea.ptr.pp_double[n+m+i][i] = spline1d_lambdareg; + } + rmatrixqr(&densea, arows, m+1, &tau, _state); + if( dotrace ) + { + ae_trace("> running low-dimensional QR-based algorithm, |r|=%0.2e\n", + (double)(ae_fabs(densea.ptr.pp_double[m][m], _state))); + } + rallocv(m, &sy, _state); + rcopycv(m, &densea, m, &sy, _state); + rmatrixtrsv(m, &densea, 0, 0, ae_true, ae_false, 0, &sy, 0, _state); + rallocv(m, &sx, _state); + for(i=0; i<=m-1; i++) + { + sx.ptr.p_double[i] = (double)i/(double)(m-1); + } + spline1dbuildcubic(&sx, &sy, m, 2, 0.0, 2, 0.0, &tmps, _state); + rallocv(m, &sdy, _state); + for(i=0; i<=m-1; i++) + { + spline1ddiff(&tmps, (double)i/(double)(m-1), &f, &df, &d2f, _state); + sdy.ptr.p_double[i] = df; + } + } + + /* + * Calculate model values, report + */ + rss = 0.0; + nrel = 0; + rep->terminationtype = 1; + rep->rmserror = (double)(0); + rep->maxerror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + for(i=0; i<=n-1; i++) + { + v = spline1dcalc(&tmps, xywork.ptr.p_double[2*i+0], _state)-xywork.ptr.p_double[2*i+1]; + rss = rss+v*v; + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + if( ae_fp_neq(y.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y.ptr.p_double[i], _state); + nrel = nrel+1; + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)n, _state); + rep->avgerror = rep->avgerror/(double)n; + rep->avgrelerror = rep->avgrelerror/coalesce((double)(nrel), 1.0, _state); + if( dotrace ) + { + ae_trace("> printing fitting errors:\n"); + ae_trace("rms.err = %9.3e\n", + (double)(rep->rmserror)); + ae_trace("max.err = %9.3e\n", + (double)(rep->maxerror)); + ae_trace("avg.err = %9.3e\n", + (double)(rep->avgerror)); + ae_trace("avg.rel.err = %9.3e\n", + (double)(rep->avgrelerror)); + ae_trace("R2 = %0.6f (coefficient of determination)\n", + (double)(1.0-rss/coalesce(tss, 1.0, _state))); + } + + /* + * Append prior term. + * Transform spline to original coordinates. + * Output. + */ + for(i=0; i<=m-1; i++) + { + sy.ptr.p_double[i] = sy.ptr.p_double[i]+vterm.ptr.pp_double[0][0]*sx.ptr.p_double[i]+vterm.ptr.pp_double[0][1]; + sdy.ptr.p_double[i] = sdy.ptr.p_double[i]+vterm.ptr.pp_double[0][0]; + } + for(i=0; i<=m-1; i++) + { + sx.ptr.p_double[i] = sx.ptr.p_double[i]*(xb-xa)+xa; + sdy.ptr.p_double[i] = sdy.ptr.p_double[i]/(xb-xa); + } + spline1dbuildhermite(&sx, &sy, &sdy, m, s, _state); + + /* + * Done + */ + if( dotrace ) + { + ae_trace("> done in %0d ms\n", + (int)(ae_tickcount()-tstart)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal version of Spline1DGridDiffCubic. + +Accepts pre-ordered X/Y, temporary arrays (which may be preallocated, if +you want to save time, or not) and output array (which may be preallocated +too). + +Y is passed as var-parameter because we may need to force last element to +be equal to the first one (if periodic boundary conditions are specified). + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiffcubicinternal(/* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d, + /* Real */ ae_vector* a1, + /* Real */ ae_vector* a2, + /* Real */ ae_vector* a3, + /* Real */ ae_vector* b, + /* Real */ ae_vector* dt, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * allocate arrays + */ + if( d->cntcntcntcntcntcntptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); + d->ptr.p_double[1] = d->ptr.p_double[0]; + return; + } + if( (n==2&&boundltype==-1)&&boundrtype==-1 ) + { + d->ptr.p_double[0] = (double)(0); + d->ptr.p_double[1] = (double)(0); + return; + } + + /* + * Periodic and non-periodic boundary conditions are + * two separate classes + */ + if( boundrtype==-1&&boundltype==-1 ) + { + + /* + * Periodic boundary conditions + */ + y->ptr.p_double[n-1] = y->ptr.p_double[0]; + + /* + * Boundary conditions at N-1 points + * (one point less because last point is the same as first point). + */ + a1->ptr.p_double[0] = x->ptr.p_double[1]-x->ptr.p_double[0]; + a2->ptr.p_double[0] = (double)2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); + a3->ptr.p_double[0] = x->ptr.p_double[n-1]-x->ptr.p_double[n-2]; + b->ptr.p_double[0] = (double)3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])*(x->ptr.p_double[1]-x->ptr.p_double[0])+(double)3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); + for(i=1; i<=n-2; i++) + { + + /* + * Altough last point is [N-2], we use X[N-1] and Y[N-1] + * (because of periodicity) + */ + a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; + a2->ptr.p_double[i] = (double)2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); + a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; + b->ptr.p_double[i] = (double)3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+(double)3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); + } + + /* + * Solve, add last point (with index N-1) + */ + spline1d_solvecyclictridiagonal(a1, a2, a3, b, n-1, dt, _state); + ae_v_move(&d->ptr.p_double[0], 1, &dt->ptr.p_double[0], 1, ae_v_len(0,n-2)); + d->ptr.p_double[n-1] = d->ptr.p_double[0]; + } + else + { + + /* + * Non-periodic boundary condition. + * Left boundary conditions. + */ + if( boundltype==0 ) + { + a1->ptr.p_double[0] = (double)(0); + a2->ptr.p_double[0] = (double)(1); + a3->ptr.p_double[0] = (double)(1); + b->ptr.p_double[0] = (double)2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]); + } + if( boundltype==1 ) + { + a1->ptr.p_double[0] = (double)(0); + a2->ptr.p_double[0] = (double)(1); + a3->ptr.p_double[0] = (double)(0); + b->ptr.p_double[0] = boundl; + } + if( boundltype==2 ) + { + a1->ptr.p_double[0] = (double)(0); + a2->ptr.p_double[0] = (double)(2); + a3->ptr.p_double[0] = (double)(1); + b->ptr.p_double[0] = (double)3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-0.5*boundl*(x->ptr.p_double[1]-x->ptr.p_double[0]); + } + + /* + * Central conditions + */ + for(i=1; i<=n-2; i++) + { + a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i]; + a2->ptr.p_double[i] = (double)2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]); + a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1]; + b->ptr.p_double[i] = (double)3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+(double)3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]); + } + + /* + * Right boundary conditions + */ + if( boundrtype==0 ) + { + a1->ptr.p_double[n-1] = (double)(1); + a2->ptr.p_double[n-1] = (double)(1); + a3->ptr.p_double[n-1] = (double)(0); + b->ptr.p_double[n-1] = (double)2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); + } + if( boundrtype==1 ) + { + a1->ptr.p_double[n-1] = (double)(0); + a2->ptr.p_double[n-1] = (double)(1); + a3->ptr.p_double[n-1] = (double)(0); + b->ptr.p_double[n-1] = boundr; + } + if( boundrtype==2 ) + { + a1->ptr.p_double[n-1] = (double)(1); + a2->ptr.p_double[n-1] = (double)(2); + a3->ptr.p_double[n-1] = (double)(0); + b->ptr.p_double[n-1] = (double)3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])+0.5*boundr*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]); + } + + /* + * Solve + */ + spline1d_solvetridiagonal(a1, a2, a3, b, n, d, _state); + } +} + + +/************************************************************************* +Internal version of Spline1DConvDiff + +Converts from Hermite spline given by grid XOld to new grid X2 + +INPUT PARAMETERS: + XOld - old grid + YOld - values at old grid + DOld - first derivative at old grid + N - grid size + X2 - new grid + N2 - new grid size + Y - possibly preallocated output array + (reallocate if too small) + NeedY - do we need Y? + D1 - possibly preallocated output array + (reallocate if too small) + NeedD1 - do we need D1? + D2 - possibly preallocated output array + (reallocate if too small) + NeedD2 - do we need D1? + +OUTPUT ARRAYS: + Y - values, if needed + D1 - first derivative, if needed + D2 - second derivative, if needed + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiffinternal(/* Real */ const ae_vector* xold, + /* Real */ const ae_vector* yold, + /* Real */ const ae_vector* dold, + ae_int_t n, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ ae_vector* y, + ae_bool needy, + /* Real */ ae_vector* d1, + ae_bool needd1, + /* Real */ ae_vector* d2, + ae_bool needd2, + ae_state *_state) +{ + ae_int_t intervalindex; + ae_int_t pointindex; + ae_bool havetoadvance; + double c0; + double c1; + double c2; + double c3; + double a; + double b; + double w; + double w2; + double w3; + double fa; + double fb; + double da; + double db; + double t; + + + + /* + * Prepare space + */ + if( needy&&y->cntcntcnt=n2 ) + { + break; + } + t = x2->ptr.p_double[pointindex]; + + /* + * do we need to advance interval? + */ + havetoadvance = ae_false; + if( intervalindex==-1 ) + { + havetoadvance = ae_true; + } + else + { + if( intervalindexptr.p_double[intervalindex]; + b = xold->ptr.p_double[intervalindex+1]; + w = b-a; + w2 = w*w; + w3 = w*w2; + fa = yold->ptr.p_double[intervalindex]; + fb = yold->ptr.p_double[intervalindex+1]; + da = dold->ptr.p_double[intervalindex]; + db = dold->ptr.p_double[intervalindex+1]; + c0 = fa; + c1 = da; + c2 = ((double)3*(fb-fa)-(double)2*da*w-db*w)/w2; + c3 = ((double)2*(fa-fb)+da*w+db*w)/w3; + continue; + } + + /* + * Calculate spline and its derivatives using power basis + */ + t = t-a; + if( needy ) + { + y->ptr.p_double[pointindex] = c0+t*(c1+t*(c2+t*c3)); + } + if( needd1 ) + { + d1->ptr.p_double[pointindex] = c1+(double)2*t*c2+(double)3*t*t*c3; + } + if( needd2 ) + { + d2->ptr.p_double[pointindex] = (double)2*c2+(double)6*t*c3; + } + pointindex = pointindex+1; + } +} + + +/************************************************************************* +This function finds all roots and extrema of the spline S(x) defined at +[A,B] (interval which contains spline nodes). + +It does not extrapolates function, so roots and extrema located outside +of [A,B] will not be found. It returns all isolated (including multiple) +roots and extrema. + +INPUT PARAMETERS + C - spline interpolant + +OUTPUT PARAMETERS + R - array[NR], contains roots of the spline. + In case there is no roots, this array has zero length. + NR - number of roots, >=0 + DR - is set to True in case there is at least one interval + where spline is just a zero constant. Such degenerate + cases are not reported in the R/NR + E - array[NE], contains extrema (maximums/minimums) of + the spline. In case there is no extrema, this array + has zero length. + ET - array[NE], extrema types: + * ET[i]>0 in case I-th extrema is a minimum + * ET[i]<0 in case I-th extrema is a maximum + NE - number of extrema, >=0 + DE - is set to True in case there is at least one interval + where spline is a constant. Such degenerate cases are + not reported in the E/NE. + +NOTES: + +1. This function does NOT report following kinds of roots: + * intervals where function is constantly zero + * roots which are outside of [A,B] (note: it CAN return A or B) + +2. This function does NOT report following kinds of extrema: + * intervals where function is a constant + * extrema which are outside of (A,B) (note: it WON'T return A or B) + + -- ALGLIB PROJECT -- + Copyright 26.09.2011 by Bochkanov Sergey +*************************************************************************/ +void spline1drootsandextrema(const spline1dinterpolant* c, + /* Real */ ae_vector* r, + ae_int_t* nr, + ae_bool* dr, + /* Real */ ae_vector* e, + /* Integer */ ae_vector* et, + ae_int_t* ne, + ae_bool* de, + ae_state *_state) +{ + ae_frame _frame_block; + double pl; + double ml; + double pll; + double pr; + double mr; + ae_vector tr; + ae_vector tmpr; + ae_vector tmpe; + ae_vector tmpet; + ae_vector tmpc; + double x0; + double x1; + double x2; + double ex0; + double ex1; + ae_int_t tne; + ae_int_t tnr; + ae_int_t i; + ae_int_t j; + ae_bool nstep; + + ae_frame_make(_state, &_frame_block); + memset(&tr, 0, sizeof(tr)); + memset(&tmpr, 0, sizeof(tmpr)); + memset(&tmpe, 0, sizeof(tmpe)); + memset(&tmpet, 0, sizeof(tmpet)); + memset(&tmpc, 0, sizeof(tmpc)); + ae_vector_clear(r); + *nr = 0; + *dr = ae_false; + ae_vector_clear(e); + ae_vector_clear(et); + *ne = 0; + *de = ae_false; + ae_vector_init(&tr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpe, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpet, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmpc, 0, DT_REAL, _state, ae_true); + + + /* + *exception handling + */ + ae_assert(c->k==3, "Spline1DRootsAndExtrema : incorrect parameter C.K!", _state); + ae_assert(c->continuity>=0, "Spline1DRootsAndExtrema : parameter C.Continuity must not be less than 0!", _state); + + /* + *initialization of variable + */ + *nr = 0; + *ne = 0; + *dr = ae_false; + *de = ae_false; + nstep = ae_true; + + /* + *consider case, when C.Continuty=0 + */ + if( c->continuity==0 ) + { + + /* + *allocation for auxiliary arrays + *'TmpR ' - it stores a time value for roots + *'TmpE ' - it stores a time value for extremums + *'TmpET '- it stores a time value for extremums type + */ + rvectorsetlengthatleast(&tmpr, 3*(c->n-1), _state); + rvectorsetlengthatleast(&tmpe, 2*(c->n-1), _state); + ivectorsetlengthatleast(&tmpet, 2*(c->n-1), _state); + + /* + *start calculating + */ + for(i=0; i<=c->n-2; i++) + { + + /* + *initialization pL, mL, pR, mR + */ + pl = c->c.ptr.p_double[4*i]; + ml = c->c.ptr.p_double[4*i+1]; + pr = c->c.ptr.p_double[4*(i+1)]; + mr = c->c.ptr.p_double[4*i+1]+(double)2*c->c.ptr.p_double[4*i+2]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])+(double)3*c->c.ptr.p_double[4*i+3]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]); + + /* + *pre-searching roots and extremums + */ + solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); + *dr = *dr||tnr==-1; + *de = *de||tne==-1; + + /* + *searching of roots + */ + if( tnr==1&&nstep ) + { + + /* + *is there roots? + */ + if( *nr>0 ) + { + + /* + *is a next root equal a previous root? + *if is't, then write new root + */ + if( ae_fp_neq(x0,tmpr.ptr.p_double[*nr-1]) ) + { + tmpr.ptr.p_double[*nr] = x0; + *nr = *nr+1; + } + } + else + { + + /* + *write a first root + */ + tmpr.ptr.p_double[*nr] = x0; + *nr = *nr+1; + } + } + else + { + + /* + *case when function at a segment identically to zero + *then we have to clear a root, if the one located on a + *constant segment + */ + if( tnr==-1 ) + { + + /* + *safe state variable as constant + */ + if( nstep ) + { + nstep = ae_false; + } + + /* + *clear the root, if there is + */ + if( *nr>0 ) + { + if( ae_fp_eq(c->x.ptr.p_double[i],tmpr.ptr.p_double[*nr-1]) ) + { + *nr = *nr-1; + } + } + + /* + *change state for 'DR' + */ + if( !*dr ) + { + *dr = ae_true; + } + } + else + { + nstep = ae_true; + } + } + + /* + *searching of extremums + */ + if( i>0 ) + { + pll = c->c.ptr.p_double[4*(i-1)]; + + /* + *if pL=pLL or pL=pR then + */ + if( tne==-1 ) + { + if( !*de ) + { + *de = ae_true; + } + } + else + { + if( ae_fp_greater(pl,pll)&&ae_fp_greater(pl,pr) ) + { + + /* + *maximum + */ + tmpet.ptr.p_int[*ne] = -1; + tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; + *ne = *ne+1; + } + else + { + if( ae_fp_less(pl,pll)&&ae_fp_less(pl,pr) ) + { + + /* + *minimum + */ + tmpet.ptr.p_int[*ne] = 1; + tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i]; + *ne = *ne+1; + } + } + } + } + } + + /* + *write final result + */ + rvectorsetlengthatleast(r, *nr, _state); + rvectorsetlengthatleast(e, *ne, _state); + ivectorsetlengthatleast(et, *ne, _state); + + /* + *write roots + */ + for(i=0; i<=*nr-1; i++) + { + r->ptr.p_double[i] = tmpr.ptr.p_double[i]; + } + + /* + *write extremums and their types + */ + for(i=0; i<=*ne-1; i++) + { + e->ptr.p_double[i] = tmpe.ptr.p_double[i]; + et->ptr.p_int[i] = tmpet.ptr.p_int[i]; + } + } + else + { + + /* + *case, when C.Continuity>=1 + *'TmpR ' - it stores a time value for roots + *'TmpC' - it stores a time value for extremums and + *their function value (TmpC={EX0,F(EX0), EX1,F(EX1), ..., EXn,F(EXn)};) + *'TmpE' - it stores a time value for extremums only + *'TmpET'- it stores a time value for extremums type + */ + rvectorsetlengthatleast(&tmpr, 2*c->n-1, _state); + rvectorsetlengthatleast(&tmpc, 4*c->n, _state); + rvectorsetlengthatleast(&tmpe, 2*c->n, _state); + ivectorsetlengthatleast(&tmpet, 2*c->n, _state); + + /* + *start calculating + */ + for(i=0; i<=c->n-2; i++) + { + + /* + *we calculate pL,mL, pR,mR as Fi+1(F'i+1) at left border + */ + pl = c->c.ptr.p_double[4*i]; + ml = c->c.ptr.p_double[4*i+1]; + pr = c->c.ptr.p_double[4*(i+1)]; + mr = c->c.ptr.p_double[4*(i+1)+1]; + + /* + *calculating roots and extremums at [X[i],X[i+1]] + */ + solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state); + + /* + *searching roots + */ + if( tnr>0 ) + { + + /* + *re-init tR + */ + if( tnr>=1 ) + { + tr.ptr.p_double[0] = x0; + } + if( tnr>=2 ) + { + tr.ptr.p_double[1] = x1; + } + if( tnr==3 ) + { + tr.ptr.p_double[2] = x2; + } + + /* + *start root selection + */ + if( *nr>0 ) + { + if( ae_fp_neq(tmpr.ptr.p_double[*nr-1],x0) ) + { + + /* + *previous segment was't constant identical zero + */ + if( nstep ) + { + for(j=0; j<=tnr-1; j++) + { + tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; + } + *nr = *nr+tnr; + } + else + { + + /* + *previous segment was constant identical zero + *and we must ignore [NR+j-1] root + */ + for(j=1; j<=tnr-1; j++) + { + tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; + } + *nr = *nr+tnr-1; + nstep = ae_true; + } + } + else + { + for(j=1; j<=tnr-1; j++) + { + tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j]; + } + *nr = *nr+tnr-1; + } + } + else + { + + /* + *write first root + */ + for(j=0; j<=tnr-1; j++) + { + tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j]; + } + *nr = *nr+tnr; + } + } + else + { + if( tnr==-1 ) + { + + /* + *decrement 'NR' if at previous step was writen a root + *(previous segment identical zero) + */ + if( *nr>0&&nstep ) + { + *nr = *nr-1; + } + + /* + *previous segment is't constant + */ + if( nstep ) + { + nstep = ae_false; + } + + /* + *rewrite 'DR' + */ + if( !*dr ) + { + *dr = ae_true; + } + } + } + + /* + *searching extremums + *write all term like extremums + */ + if( tne==1 ) + { + if( *ne>0 ) + { + + /* + *just ignore identical extremums + *because he must be one + */ + if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) + { + tmpc.ptr.p_double[*ne] = ex0; + tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); + *ne = *ne+2; + } + } + else + { + + /* + *write first extremum and it function value + */ + tmpc.ptr.p_double[*ne] = ex0; + tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); + *ne = *ne+2; + } + } + else + { + if( tne==2 ) + { + if( *ne>0 ) + { + + /* + *ignore identical extremum + */ + if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) ) + { + tmpc.ptr.p_double[*ne] = ex0; + tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); + *ne = *ne+2; + } + } + else + { + + /* + *write first extremum + */ + tmpc.ptr.p_double[*ne] = ex0; + tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]); + *ne = *ne+2; + } + + /* + *write second extremum + */ + tmpc.ptr.p_double[*ne] = ex1; + tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i]); + *ne = *ne+2; + } + else + { + if( tne==-1 ) + { + if( !*de ) + { + *de = ae_true; + } + } + } + } + } + + /* + *checking of arrays + *get number of extremums (tNe=NE/2) + *initialize pL as value F0(X[0]) and + *initialize pR as value Fn-1(X[N]) + */ + tne = *ne/2; + *ne = 0; + pl = c->c.ptr.p_double[0]; + pr = c->c.ptr.p_double[4*(c->n-1)]; + for(i=0; i<=tne-1; i++) + { + if( i>0&&ix.ptr.p_double[0]) ) + { + if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) + { + + /* + *maximum + */ + tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; + tmpet.ptr.p_int[*ne] = -1; + *ne = *ne+1; + } + else + { + if( ae_fp_less(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) ) + { + + /* + *minimum + */ + tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; + tmpet.ptr.p_int[*ne] = 1; + *ne = *ne+1; + } + } + } + } + else + { + if( i==tne-1 ) + { + if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[c->n-1]) ) + { + if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],pr) ) + { + + /* + *maximum + */ + tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; + tmpet.ptr.p_int[*ne] = -1; + *ne = *ne+1; + } + else + { + if( ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_less(tmpc.ptr.p_double[2*i+1],pr) ) + { + + /* + *minimum + */ + tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i]; + tmpet.ptr.p_int[*ne] = 1; + *ne = *ne+1; + } + } + } + } + } + } + } + + /* + *final results + *allocate R, E, ET + */ + rvectorsetlengthatleast(r, *nr, _state); + rvectorsetlengthatleast(e, *ne, _state); + ivectorsetlengthatleast(et, *ne, _state); + + /* + *write result for extremus and their types + */ + for(i=0; i<=*ne-1; i++) + { + e->ptr.p_double[i] = tmpe.ptr.p_double[i]; + et->ptr.p_int[i] = tmpet.ptr.p_int[i]; + } + + /* + *write result for roots + */ + for(i=0; i<=*nr-1; i++) + { + r->ptr.p_double[i] = tmpr.ptr.p_double[i]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. Heap sort. +*************************************************************************/ +void heapsortdpoints(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* d, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector rbuf; + ae_vector ibuf; + ae_vector rbuf2; + ae_vector ibuf2; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&rbuf, 0, sizeof(rbuf)); + memset(&ibuf, 0, sizeof(ibuf)); + memset(&rbuf2, 0, sizeof(rbuf2)); + memset(&ibuf2, 0, sizeof(ibuf2)); + ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true); + ae_vector_init(&rbuf2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ibuf2, 0, DT_INT, _state, ae_true); + + ae_vector_set_length(&ibuf, n, _state); + ae_vector_set_length(&rbuf, n, _state); + for(i=0; i<=n-1; i++) + { + ibuf.ptr.p_int[i] = i; + } + tagsortfasti(x, &ibuf, &rbuf2, &ibuf2, n, _state); + for(i=0; i<=n-1; i++) + { + rbuf.ptr.p_double[i] = y->ptr.p_double[ibuf.ptr.p_int[i]]; + } + ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + rbuf.ptr.p_double[i] = d->ptr.p_double[ibuf.ptr.p_int[i]]; + } + ae_v_move(&d->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +This procedure search roots of an quadratic equation inside [0;1] and it number of roots. + +INPUT PARAMETERS: + P0 - value of a function at 0 + M0 - value of a derivative at 0 + P1 - value of a function at 1 + M1 - value of a derivative at 1 + +OUTPUT PARAMETERS: + X0 - first root of an equation + X1 - second root of an equation + NR - number of roots + +RESTRICTIONS OF PARAMETERS: + +Parameters for this procedure has't to be zero simultaneously. Is expected, +that input polinom is't degenerate or constant identicaly ZERO. + + +REMARK: + +The procedure always fill value for X1 and X2, even if it is't belongs to [0;1]. +But first true root(even if existing one) is in X1. +Number of roots is NR. + + -- ALGLIB PROJECT -- + Copyright 26.09.2011 by Bochkanov Sergey +*************************************************************************/ +void solvepolinom2(double p0, + double m0, + double p1, + double m1, + double* x0, + double* x1, + ae_int_t* nr, + ae_state *_state) +{ + double a; + double b; + double c; + double dd; + double tmp; + double exf; + double extr; + + *x0 = 0.0; + *x1 = 0.0; + *nr = 0; + + + /* + *calculate parameters for equation: A, B and C + */ + a = (double)6*p0+(double)3*m0-(double)6*p1+(double)3*m1; + b = -(double)6*p0-(double)4*m0+(double)6*p1-(double)2*m1; + c = m0; + + /* + *check case, when A=0 + *we are considering the linear equation + */ + if( ae_fp_eq(a,(double)(0)) ) + { + + /* + *B<>0 and root inside [0;1] + *one root + */ + if( (ae_fp_neq(b,(double)(0))&&ae_sign(c, _state)*ae_sign(b, _state)<=0)&&ae_fp_greater_eq(ae_fabs(b, _state),ae_fabs(c, _state)) ) + { + *x0 = -c/b; + *nr = 1; + return; + } + else + { + *nr = 0; + return; + } + } + + /* + *consider case, when extremumu outside (0;1) + *exist one root only + */ + if( ae_fp_less_eq(ae_fabs((double)2*a, _state),ae_fabs(b, _state))||ae_sign(b, _state)*ae_sign(a, _state)>=0 ) + { + if( ae_sign(m0, _state)*ae_sign(m1, _state)>0 ) + { + *nr = 0; + return; + } + + /* + *consider case, when the one exist + *same sign of derivative + */ + if( ae_sign(m0, _state)*ae_sign(m1, _state)<0 ) + { + *nr = 1; + extr = -b/((double)2*a); + dd = b*b-(double)4*a*c; + if( ae_fp_less(dd,(double)(0)) ) + { + return; + } + *x0 = (-b-ae_sqrt(dd, _state))/((double)2*a); + *x1 = (-b+ae_sqrt(dd, _state))/((double)2*a); + if( (ae_fp_greater_eq(extr,(double)(1))&&ae_fp_less_eq(*x1,extr))||(ae_fp_less_eq(extr,(double)(0))&&ae_fp_greater_eq(*x1,extr)) ) + { + *x0 = *x1; + } + return; + } + + /* + *consider case, when the one is 0 + */ + if( ae_fp_eq(m0,(double)(0)) ) + { + *x0 = (double)(0); + *nr = 1; + return; + } + if( ae_fp_eq(m1,(double)(0)) ) + { + *x0 = (double)(1); + *nr = 1; + return; + } + } + else + { + + /* + *consider case, when both of derivatives is 0 + */ + if( ae_fp_eq(m0,(double)(0))&&ae_fp_eq(m1,(double)(0)) ) + { + *x0 = (double)(0); + *x1 = (double)(1); + *nr = 2; + return; + } + + /* + *consider case, when derivative at 0 is 0, and derivative at 1 is't 0 + */ + if( ae_fp_eq(m0,(double)(0))&&ae_fp_neq(m1,(double)(0)) ) + { + dd = b*b-(double)4*a*c; + if( ae_fp_less(dd,(double)(0)) ) + { + *x0 = (double)(0); + *nr = 1; + return; + } + *x0 = (-b-ae_sqrt(dd, _state))/((double)2*a); + *x1 = (-b+ae_sqrt(dd, _state))/((double)2*a); + extr = -b/((double)2*a); + exf = a*extr*extr+b*extr+c; + if( ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) + { + *x0 = (double)(0); + *nr = 1; + return; + } + else + { + if( ae_fp_greater(extr,*x0) ) + { + *x0 = (double)(0); + } + else + { + *x1 = (double)(0); + } + *nr = 2; + + /* + *roots must placed ascending + */ + if( ae_fp_greater(*x0,*x1) ) + { + tmp = *x0; + *x0 = *x1; + *x1 = tmp; + } + return; + } + } + if( ae_fp_eq(m1,(double)(0))&&ae_fp_neq(m0,(double)(0)) ) + { + dd = b*b-(double)4*a*c; + if( ae_fp_less(dd,(double)(0)) ) + { + *x0 = (double)(1); + *nr = 1; + return; + } + *x0 = (-b-ae_sqrt(dd, _state))/((double)2*a); + *x1 = (-b+ae_sqrt(dd, _state))/((double)2*a); + extr = -b/((double)2*a); + exf = a*extr*extr+b*extr+c; + if( ae_sign(exf, _state)*ae_sign(m0, _state)>0 ) + { + *x0 = (double)(1); + *nr = 1; + return; + } + else + { + if( ae_fp_less(extr,*x0) ) + { + *x0 = (double)(1); + } + else + { + *x1 = (double)(1); + } + *nr = 2; + + /* + *roots must placed ascending + */ + if( ae_fp_greater(*x0,*x1) ) + { + tmp = *x0; + *x0 = *x1; + *x1 = tmp; + } + return; + } + } + else + { + extr = -b/((double)2*a); + exf = a*extr*extr+b*extr+c; + if( ae_sign(exf, _state)*ae_sign(m0, _state)>0&&ae_sign(exf, _state)*ae_sign(m1, _state)>0 ) + { + *nr = 0; + return; + } + dd = b*b-(double)4*a*c; + if( ae_fp_less(dd,(double)(0)) ) + { + *nr = 0; + return; + } + *x0 = (-b-ae_sqrt(dd, _state))/((double)2*a); + *x1 = (-b+ae_sqrt(dd, _state))/((double)2*a); + + /* + *if EXF and m0, EXF and m1 has different signs, then equation has two roots + */ + if( ae_sign(exf, _state)*ae_sign(m0, _state)<0&&ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) + { + *nr = 2; + + /* + *roots must placed ascending + */ + if( ae_fp_greater(*x0,*x1) ) + { + tmp = *x0; + *x0 = *x1; + *x1 = tmp; + } + return; + } + else + { + *nr = 1; + if( ae_sign(exf, _state)*ae_sign(m0, _state)<0 ) + { + if( ae_fp_less(*x1,extr) ) + { + *x0 = *x1; + } + return; + } + if( ae_sign(exf, _state)*ae_sign(m1, _state)<0 ) + { + if( ae_fp_greater(*x1,extr) ) + { + *x0 = *x1; + } + return; + } + } + } + } +} + + +/************************************************************************* +This procedure search roots of an cubic equation inside [A;B], it number of roots +and number of extremums. + +INPUT PARAMETERS: + pA - value of a function at A + mA - value of a derivative at A + pB - value of a function at B + mB - value of a derivative at B + A0 - left border [A0;B0] + B0 - right border [A0;B0] + +OUTPUT PARAMETERS: + X0 - first root of an equation + X1 - second root of an equation + X2 - third root of an equation + EX0 - first extremum of a function + EX0 - second extremum of a function + NR - number of roots + NR - number of extrmums + +RESTRICTIONS OF PARAMETERS: + +Length of [A;B] must be positive and is't zero, i.e. A<>B and AB + */ + ae_assert(ae_fp_less(a,b), "\nSolveCubicPolinom: incorrect borders for [A;B]!\n", _state); + + /* + *case 1 + *function can be identicaly to ZERO + */ + if( ((ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb))&&ae_fp_eq(pa,(double)(0)) ) + { + *nr = -1; + *ne = -1; + return; + } + if( (ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb) ) + { + *nr = 0; + *ne = -1; + return; + } + tmpma = ma*(b-a); + tmpmb = mb*(b-a); + solvepolinom2(pa, tmpma, pb, tmpmb, ex0, ex1, ne, _state); + *ex0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex0, _state); + *ex1 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex1, _state); + + /* + *case 3.1 + *no extremums at [A;B] + */ + if( *ne==0 ) + { + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); + if( *nr==1 ) + { + *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); + } + return; + } + + /* + *case 3.2 + *one extremum + */ + if( *ne==1 ) + { + if( ae_fp_eq(*ex0,a)||ae_fp_eq(*ex0,b) ) + { + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); + if( *nr==1 ) + { + *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); + } + return; + } + else + { + *nr = 0; + i = 0; + tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); + if( *nr>i ) + { + tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); + i = i+1; + } + *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr); + if( *nr>i ) + { + *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state); + if( i>0 ) + { + if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + else + { + *nr = *nr-1; + } + } + else + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + } + if( *nr>0 ) + { + *x0 = tempdata->ptr.p_double[0]; + if( *nr>1 ) + { + *x1 = tempdata->ptr.p_double[1]; + } + return; + } + } + return; + } + else + { + + /* + *case 3.3 + *two extremums(or more, but it's impossible) + * + * + *case 3.3.0 + *both extremums at the border + */ + if( ae_fp_eq(*ex0,a)&&ae_fp_eq(*ex1,b) ) + { + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state); + if( *nr==1 ) + { + *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state); + } + return; + } + if( ae_fp_eq(*ex0,a)&&ae_fp_neq(*ex1,b) ) + { + *nr = 0; + i = 0; + tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state); + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex1, x0, _state)+(*nr); + if( *nr>i ) + { + tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex1, a, *ex1, *x0, _state); + i = i+1; + } + *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr); + if( *nr>i ) + { + *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state); + if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + else + { + *nr = *nr-1; + } + } + if( *nr>0 ) + { + *x0 = tempdata->ptr.p_double[0]; + if( *nr>1 ) + { + *x1 = tempdata->ptr.p_double[1]; + } + return; + } + } + if( ae_fp_eq(*ex1,b)&&ae_fp_neq(*ex0,a) ) + { + *nr = 0; + i = 0; + tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); + if( *nr>i ) + { + tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); + i = i+1; + } + *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr); + if( *nr>i ) + { + *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state); + if( i>0 ) + { + if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + else + { + *nr = *nr-1; + } + } + else + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + } + if( *nr>0 ) + { + *x0 = tempdata->ptr.p_double[0]; + if( *nr>1 ) + { + *x1 = tempdata->ptr.p_double[1]; + } + return; + } + } + else + { + + /* + *case 3.3.2 + *both extremums inside (0;1) + */ + *nr = 0; + i = 0; + tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state); + tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state); + *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr); + if( *nr>i ) + { + tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state); + i = i+1; + } + *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, tex1, x0, _state)+(*nr); + if( *nr>i ) + { + *x0 = spline1d_rescaleval(tex0, tex1, *ex0, *ex1, *x0, _state); + if( i>0 ) + { + if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + else + { + *nr = *nr-1; + } + } + else + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + } + *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr); + if( *nr>i ) + { + *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state); + if( i>0 ) + { + if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) ) + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + else + { + *nr = *nr-1; + } + } + else + { + tempdata->ptr.p_double[i] = *x0; + i = i+1; + } + } + + /* + *write are found roots + */ + if( *nr>0 ) + { + *x0 = tempdata->ptr.p_double[0]; + if( *nr>1 ) + { + *x1 = tempdata->ptr.p_double[1]; + } + if( *nr>2 ) + { + *x2 = tempdata->ptr.p_double[2]; + } + return; + } + } + } +} + + +/************************************************************************* +Function for searching a root at [A;B] by bisection method and return number of roots +(0 or 1) + +INPUT PARAMETERS: + pA - value of a function at A + mA - value of a derivative at A + pB - value of a function at B + mB - value of a derivative at B + A0 - left border [A0;B0] + B0 - right border [A0;B0] + +RESTRICTIONS OF PARAMETERS: + +We assume, that B0>A0. + + +REMARK: + +Assume, that exist one root only at [A;B], else +function may be work incorrectly. +The function dont check value A0,B0! + + -- ALGLIB PROJECT -- + Copyright 26.09.2011 by Bochkanov Sergey +*************************************************************************/ +ae_int_t bisectmethod(double pa, + double ma, + double pb, + double mb, + double a, + double b, + double* x, + ae_state *_state) +{ + double vacuum; + double eps; + double a0; + double b0; + double m; + double lf; + double rf; + double mf; + ae_int_t result; + + *x = 0.0; + + + /* + *accuracy + */ + eps = (double)1000*(b-a)*ae_machineepsilon; + + /* + *initialization left and right borders + */ + a0 = a; + b0 = b; + + /* + *initialize function value at 'A' and 'B' + */ + spline1d_hermitecalc(pa, ma, pb, mb, a, &lf, &vacuum, _state); + spline1d_hermitecalc(pa, ma, pb, mb, b, &rf, &vacuum, _state); + + /* + *check, that 'A' and 'B' are't roots, + *and that root exist + */ + if( ae_sign(lf, _state)*ae_sign(rf, _state)>0 ) + { + result = 0; + return result; + } + else + { + if( ae_fp_eq(lf,(double)(0)) ) + { + *x = a; + result = 1; + return result; + } + else + { + if( ae_fp_eq(rf,(double)(0)) ) + { + *x = b; + result = 1; + return result; + } + } + } + + /* + *searching a root + */ + do + { + m = (b0+a0)/(double)2; + spline1d_hermitecalc(pa, ma, pb, mb, a0, &lf, &vacuum, _state); + spline1d_hermitecalc(pa, ma, pb, mb, b0, &rf, &vacuum, _state); + spline1d_hermitecalc(pa, ma, pb, mb, m, &mf, &vacuum, _state); + if( ae_sign(mf, _state)*ae_sign(lf, _state)<0 ) + { + b0 = m; + } + else + { + if( ae_sign(mf, _state)*ae_sign(rf, _state)<0 ) + { + a0 = m; + } + else + { + if( ae_fp_eq(lf,(double)(0)) ) + { + *x = a0; + result = 1; + return result; + } + if( ae_fp_eq(rf,(double)(0)) ) + { + *x = b0; + result = 1; + return result; + } + if( ae_fp_eq(mf,(double)(0)) ) + { + *x = m; + result = 1; + return result; + } + } + } + } + while(ae_fp_greater_eq(ae_fabs(b0-a0, _state),eps)); + *x = m; + result = 1; + return result; +} + + +/************************************************************************* +This function builds monotone cubic Hermite interpolant. This interpolant +is monotonic in [x(0),x(n-1)] and is constant outside of this interval. + +In case y[] form non-monotonic sequence, interpolant is piecewise +monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will +monotonically grow at [0..2] and monotonically decrease at [2..4]. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. Subroutine automatically + sorts points, so caller may pass unsorted array. + Y - function values, array[0..N-1] + N - the number of points(N>=2). + +OUTPUT PARAMETERS: + C - spline interpolant. + + -- ALGLIB PROJECT -- + Copyright 21.06.2012 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildmonotone(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector d; + ae_vector ex; + ae_vector ey; + ae_vector p; + double delta; + double alpha; + double beta; + ae_int_t tmpn; + ae_int_t sn; + double ca; + double cb; + double epsilon; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&d, 0, sizeof(d)); + memset(&ex, 0, sizeof(ex)); + memset(&ey, 0, sizeof(ey)); + memset(&p, 0, sizeof(p)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _spline1dinterpolant_clear(c); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ey, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + + /* + * Check lengths of arguments + */ + ae_assert(n>=2, "Spline1DBuildMonotone: N<2", _state); + ae_assert(x.cnt>=n, "Spline1DBuildMonotone: Length(X)=n, "Spline1DBuildMonotone: Length(Y)n-2)); + if( ae_fp_neq(ca,(double)(0)) ) + { + ca = ca/ae_fabs(ca, _state); + } + i = 0; + while(i=2, "Spline1DBuildMonotone: internal error", _state); + + /* + * Calculate derivatives for current segment + */ + d.ptr.p_double[i] = (double)(0); + d.ptr.p_double[sn-1] = (double)(0); + for(j=i+1; j<=sn-2; j++) + { + d.ptr.p_double[j] = ((ey.ptr.p_double[j]-ey.ptr.p_double[j-1])/(ex.ptr.p_double[j]-ex.ptr.p_double[j-1])+(ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]))/(double)2; + } + for(j=i; j<=sn-2; j++) + { + delta = (ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]); + if( ae_fp_less_eq(ae_fabs(delta, _state),epsilon) ) + { + d.ptr.p_double[j] = (double)(0); + d.ptr.p_double[j+1] = (double)(0); + } + else + { + alpha = d.ptr.p_double[j]/delta; + beta = d.ptr.p_double[j+1]/delta; + if( ae_fp_neq(alpha,(double)(0)) ) + { + cb = alpha*ae_sqrt((double)1+ae_sqr(beta/alpha, _state), _state); + } + else + { + if( ae_fp_neq(beta,(double)(0)) ) + { + cb = beta; + } + else + { + continue; + } + } + if( ae_fp_greater(cb,(double)(3)) ) + { + d.ptr.p_double[j] = (double)3*alpha*delta/cb; + d.ptr.p_double[j+1] = (double)3*beta*delta/cb; + } + } + } + + /* + * Transition to next segment + */ + i = sn-1; + } + spline1dbuildhermite(&ex, &ey, &d, n, c, _state); + c->continuity = 2; + ae_frame_leave(_state); +} + + +/************************************************************************* +Prepare approximate cardinal basis + + -- ALGLIB PROJECT -- + Copyright 09.04.2022 by Bochkanov Sergey. +*************************************************************************/ +static void spline1d_bbasisinit(spline1dbbasis* basis, + ae_int_t m, + ae_state *_state) +{ + + + rallocv(7, &basis->tmpx, _state); + rallocv(7, &basis->tmpy, _state); + + /* + * Special cases: M=2 or M=3 + */ + if( m==2 ) + { + basis->bfrad = 1; + basis->m = 2; + basis->tmpx.ptr.p_double[0] = (double)0/(double)(m-1); + basis->tmpx.ptr.p_double[1] = (double)1/(double)(m-1); + basis->tmpy.ptr.p_double[0] = (double)(1); + basis->tmpy.ptr.p_double[1] = (double)(0); + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 2, 2, 0.0, 2, 0.0, &basis->s0, _state); + return; + } + if( m==3 ) + { + basis->bfrad = 2; + basis->m = 3; + basis->tmpx.ptr.p_double[0] = (double)0/(double)(m-1); + basis->tmpx.ptr.p_double[1] = (double)1/(double)(m-1); + basis->tmpx.ptr.p_double[2] = (double)2/(double)(m-1); + basis->tmpy.ptr.p_double[0] = (double)(1); + basis->tmpy.ptr.p_double[1] = (double)(0); + basis->tmpy.ptr.p_double[2] = (double)(0); + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 3, 2, 0.0, 2, 0.0, &basis->s0, _state); + basis->tmpy.ptr.p_double[0] = (double)(0); + basis->tmpy.ptr.p_double[1] = (double)(1); + basis->tmpy.ptr.p_double[2] = (double)(0); + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 3, 2, 0.0, 2, 0.0, &basis->s1, _state); + return; + } + + /* + * General case: M>=4 + */ + basis->bfrad = 2; + basis->m = m; + + /* + * Generate S0 - leftmost kernel + */ + basis->tmpx.ptr.p_double[0] = -(double)1/(double)(m-1); + basis->tmpx.ptr.p_double[1] = (double)0/(double)(m-1); + basis->tmpx.ptr.p_double[2] = (double)1/(double)(m-1); + basis->tmpx.ptr.p_double[3] = (double)2/(double)(m-1); + basis->tmpx.ptr.p_double[4] = (double)3/(double)(m-1); + basis->tmpy.ptr.p_double[0] = (double)(2); + basis->tmpy.ptr.p_double[1] = (double)(1); + basis->tmpy.ptr.p_double[2] = (double)1/(double)6; + basis->tmpy.ptr.p_double[3] = (double)(0); + basis->tmpy.ptr.p_double[4] = (double)(0); + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 5, 2, 0.0, 2, 0.0, &basis->s0, _state); + + /* + * Generate S1 - second from the left + */ + basis->tmpx.ptr.p_double[0] = -(double)1/(double)(m-1); + basis->tmpx.ptr.p_double[1] = (double)0/(double)(m-1); + basis->tmpx.ptr.p_double[2] = (double)1/(double)(m-1); + basis->tmpx.ptr.p_double[3] = (double)2/(double)(m-1); + basis->tmpx.ptr.p_double[4] = (double)3/(double)(m-1); + basis->tmpx.ptr.p_double[5] = (double)4/(double)(m-1); + basis->tmpy.ptr.p_double[0] = (double)(-1); + basis->tmpy.ptr.p_double[1] = (double)(0); + basis->tmpy.ptr.p_double[2] = (double)2/(double)3; + basis->tmpy.ptr.p_double[3] = (double)1/(double)6; + basis->tmpy.ptr.p_double[4] = (double)(0); + basis->tmpy.ptr.p_double[5] = (double)(0); + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 6, 2, 0.0, 2, 0.0, &basis->s1, _state); + + /* + * Generate S2 - centrally symmetric kernel, generated only for M>=5 + */ + basis->tmpx.ptr.p_double[0] = -(double)3/(double)(m-1); + basis->tmpx.ptr.p_double[1] = -(double)2/(double)(m-1); + basis->tmpx.ptr.p_double[2] = -(double)1/(double)(m-1); + basis->tmpx.ptr.p_double[3] = (double)0/(double)(m-1); + basis->tmpx.ptr.p_double[4] = (double)1/(double)(m-1); + basis->tmpx.ptr.p_double[5] = (double)2/(double)(m-1); + basis->tmpx.ptr.p_double[6] = (double)3/(double)(m-1); + if( m>=5 ) + { + basis->tmpy.ptr.p_double[0] = (double)(0); + basis->tmpy.ptr.p_double[1] = (double)(0); + basis->tmpy.ptr.p_double[2] = (double)1/(double)12; + basis->tmpy.ptr.p_double[3] = (double)2/(double)6; + basis->tmpy.ptr.p_double[4] = (double)1/(double)12; + basis->tmpy.ptr.p_double[5] = (double)(0); + basis->tmpy.ptr.p_double[6] = (double)(0); + } + else + { + rsetv(7, 0.0, &basis->tmpy, _state); + } + spline1dbuildcubic(&basis->tmpx, &basis->tmpy, 7, 2, 0.0, 2, 0.0, &basis->s2, _state); +} + + +/************************************************************************* +Computes B-basis function #K at point X. + + + -- ALGLIB PROJECT -- + Copyright 09.04.2022 by Bochkanov Sergey. +*************************************************************************/ +static double spline1d_basiscalc(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state) +{ + double delta; + double y; + double result; + + + if( k>basis->m-1-k ) + { + k = basis->m-1-k; + x = (double)1-x; + } + delta = (double)1/(double)(basis->m-1); + y = x-(double)k*delta; + if( ae_fp_less_eq(y,-(double)basis->bfrad*delta)||ae_fp_greater_eq(y,(double)basis->bfrad*delta) ) + { + result = (double)(0); + return result; + } + if( k==0 ) + { + result = spline1dcalc(&basis->s0, x, _state); + return result; + } + if( k==1 ) + { + result = spline1dcalc(&basis->s1, x, _state); + return result; + } + result = spline1dcalc(&basis->s2, y, _state); + return result; +} + + +/************************************************************************* +Computes B-basis function #K at point X. + + + -- ALGLIB PROJECT -- + Copyright 09.04.2022 by Bochkanov Sergey. +*************************************************************************/ +static double spline1d_basisdiff(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state) +{ + double delta; + double y; + double f; + double df; + double d2f; + double sgn; + double result; + + + sgn = (double)(1); + if( k>basis->m-1-k ) + { + k = basis->m-1-k; + x = (double)1-x; + sgn = (double)(-1); + } + delta = (double)1/(double)(basis->m-1); + y = x-(double)k*delta; + if( ae_fp_less_eq(y,-(double)basis->bfrad*delta)||ae_fp_greater_eq(y,(double)basis->bfrad*delta) ) + { + result = (double)(0); + return result; + } + if( k==0 ) + { + spline1ddiff(&basis->s0, x, &f, &df, &d2f, _state); + result = sgn*df; + return result; + } + if( k==1 ) + { + spline1ddiff(&basis->s1, x, &f, &df, &d2f, _state); + result = sgn*df; + return result; + } + spline1ddiff(&basis->s2, y, &f, &df, &d2f, _state); + result = sgn*df; + return result; +} + + +/************************************************************************* +Computes B-basis function #K at point X. + + + -- ALGLIB PROJECT -- + Copyright 09.04.2022 by Bochkanov Sergey. +*************************************************************************/ +static double spline1d_basisdiff2(const spline1dbbasis* basis, + ae_int_t k, + double x, + ae_state *_state) +{ + double delta; + double y; + double f; + double df; + double d2f; + double result; + + + if( k>basis->m-1-k ) + { + k = basis->m-1-k; + x = (double)1-x; + } + delta = (double)1/(double)(basis->m-1); + y = x-(double)k*delta; + if( ae_fp_less_eq(y,-(double)basis->bfrad*delta)||ae_fp_greater_eq(y,(double)basis->bfrad*delta) ) + { + result = (double)(0); + return result; + } + if( k==0 ) + { + spline1ddiff(&basis->s0, x, &f, &df, &d2f, _state); + result = d2f; + return result; + } + if( k==1 ) + { + spline1ddiff(&basis->s1, x, &f, &df, &d2f, _state); + result = d2f; + return result; + } + spline1ddiff(&basis->s2, y, &f, &df, &d2f, _state); + result = d2f; + return result; +} + + +/************************************************************************* +This subroutine builds Akima spline interpolant, either original or modified +one. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +static void spline1d_buildakimax(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_bool modakima, + spline1dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + double modmult; + ae_vector d; + ae_vector w; + ae_vector diff; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&d, 0, sizeof(d)); + memset(&w, 0, sizeof(w)); + memset(&diff, 0, sizeof(diff)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _spline1dinterpolant_clear(c); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&diff, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=2, "Spline1DBuildAkima(Mod): N<2!", _state); + ae_assert(x.cnt>=n, "Spline1DBuildAkima(Mod): Length(X)=n, "Spline1DBuildAkima(Mod): Length(Y)cntptr.p_int[i] = i; + } + tagsortfasti(x, p, &rbuf, &ibuf, n, _state); + for(i=0; i<=n-1; i++) + { + rbuf.ptr.p_double[i] = y->ptr.p_double[p->ptr.p_int[i]]; + } + ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. Tridiagonal solver. Solves + +( B[0] C[0] +( A[1] B[1] C[1] ) +( A[2] B[2] C[2] ) +( .......... ) * X = D +( .......... ) +( A[N-2] B[N-2] C[N-2] ) +( A[N-1] B[N-1] ) + +*************************************************************************/ +static void spline1d_solvetridiagonal(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* _b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* _d, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector b; + ae_vector d; + ae_int_t k; + double t; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + memset(&d, 0, sizeof(d)); + ae_vector_init_copy(&b, _b, _state, ae_true); + ae_vector_init_copy(&d, _d, _state, ae_true); + + if( x->cntptr.p_double[k]/b.ptr.p_double[k-1]; + b.ptr.p_double[k] = b.ptr.p_double[k]-t*c->ptr.p_double[k-1]; + d.ptr.p_double[k] = d.ptr.p_double[k]-t*d.ptr.p_double[k-1]; + } + x->ptr.p_double[n-1] = d.ptr.p_double[n-1]/b.ptr.p_double[n-1]; + for(k=n-2; k>=0; k--) + { + x->ptr.p_double[k] = (d.ptr.p_double[k]-c->ptr.p_double[k]*x->ptr.p_double[k+1])/b.ptr.p_double[k]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. Cyclic tridiagonal solver. Solves + +( B[0] C[0] A[0] ) +( A[1] B[1] C[1] ) +( A[2] B[2] C[2] ) +( .......... ) * X = D +( .......... ) +( A[N-2] B[N-2] C[N-2] ) +( C[N-1] A[N-1] B[N-1] ) +*************************************************************************/ +static void spline1d_solvecyclictridiagonal(/* Real */ const ae_vector* a, + /* Real */ const ae_vector* _b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* d, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector b; + ae_int_t k; + double alpha; + double beta; + double gamma; + ae_vector y; + ae_vector z; + ae_vector u; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + memset(&y, 0, sizeof(y)); + memset(&z, 0, sizeof(z)); + memset(&u, 0, sizeof(u)); + ae_vector_init_copy(&b, _b, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + ae_vector_init(&u, 0, DT_REAL, _state, ae_true); + + if( x->cntptr.p_double[0]; + alpha = c->ptr.p_double[n-1]; + gamma = -b.ptr.p_double[0]; + b.ptr.p_double[0] = (double)2*b.ptr.p_double[0]; + b.ptr.p_double[n-1] = b.ptr.p_double[n-1]-alpha*beta/gamma; + ae_vector_set_length(&u, n, _state); + for(k=0; k<=n-1; k++) + { + u.ptr.p_double[k] = (double)(0); + } + u.ptr.p_double[0] = gamma; + u.ptr.p_double[n-1] = alpha; + spline1d_solvetridiagonal(a, &b, c, d, n, &y, _state); + spline1d_solvetridiagonal(a, &b, c, &u, n, &z, _state); + for(k=0; k<=n-1; k++) + { + x->ptr.p_double[k] = y.ptr.p_double[k]-(y.ptr.p_double[0]+beta/gamma*y.ptr.p_double[n-1])/((double)1+z.ptr.p_double[0]+beta/gamma*z.ptr.p_double[n-1])*z.ptr.p_double[k]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. Three-point differentiation +*************************************************************************/ +static double spline1d_diffthreepoint(double t, + double x0, + double f0, + double x1, + double f1, + double x2, + double f2, + ae_state *_state) +{ + double a; + double b; + double result; + + + t = t-x0; + x1 = x1-x0; + x2 = x2-x0; + a = (f2-f0-x2/x1*(f1-f0))/(ae_sqr(x2, _state)-x1*x2); + b = (f1-f0-a*ae_sqr(x1, _state))/x1; + result = (double)2*a*t+b; + return result; +} + + +/************************************************************************* +Procedure for calculating value of a function is providet in the form of +Hermite polinom + +INPUT PARAMETERS: + P0 - value of a function at 0 + M0 - value of a derivative at 0 + P1 - value of a function at 1 + M1 - value of a derivative at 1 + T - point inside [0;1] + +OUTPUT PARAMETERS: + S - value of a function at T + B0 - value of a derivative function at T + + -- ALGLIB PROJECT -- + Copyright 26.09.2011 by Bochkanov Sergey +*************************************************************************/ +static void spline1d_hermitecalc(double p0, + double m0, + double p1, + double m1, + double t, + double* s, + double* ds, + ae_state *_state) +{ + + *s = 0.0; + *ds = 0.0; + + *s = p0*((double)1+(double)2*t)*((double)1-t)*((double)1-t)+m0*t*((double)1-t)*((double)1-t)+p1*((double)3-(double)2*t)*t*t+m1*t*t*(t-(double)1); + *ds = -p0*(double)6*t*((double)1-t)+m0*((double)1-t)*((double)1-(double)3*t)+p1*(double)6*t*((double)1-t)+m1*t*((double)3*t-(double)2); +} + + +/************************************************************************* +Function for mapping from [A0;B0] to [A1;B1] + +INPUT PARAMETERS: + A0 - left border [A0;B0] + B0 - right border [A0;B0] + A1 - left border [A1;B1] + B1 - right border [A1;B1] + T - value inside [A0;B0] + +RESTRICTIONS OF PARAMETERS: + +We assume, that B0>A0 and B1>A1. But we chech, that T is inside [A0;B0], +and if TB0 then T - B1. + +INPUT PARAMETERS: + A0 - left border for segment [A0;B0] from 'T' is converted to [A1;B1] + B0 - right border for segment [A0;B0] from 'T' is converted to [A1;B1] + A1 - left border for segment [A1;B1] to 'T' is converted from [A0;B0] + B1 - right border for segment [A1;B1] to 'T' is converted from [A0;B0] + T - the parameter is mapped from [A0;B0] to [A1;B1] + +Result: + is converted value for 'T' from [A0;B0] to [A1;B1] + +REMARK: + +The function dont check value A0,B0 and A1,B1! + + -- ALGLIB PROJECT -- + Copyright 26.09.2011 by Bochkanov Sergey +*************************************************************************/ +static double spline1d_rescaleval(double a0, + double b0, + double a1, + double b1, + double t, + ae_state *_state) +{ + double result; + + + + /* + *return left border + */ + if( ae_fp_less_eq(t,a0) ) + { + result = a1; + return result; + } + + /* + *return right border + */ + if( ae_fp_greater_eq(t,b0) ) + { + result = b1; + return result; + } + + /* + *return value between left and right borders + */ + result = (b1-a1)*(t-a0)/(b0-a0)+a1; + return result; +} + + +void _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline1dinterpolant *p = (spline1dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); +} + + +void _spline1dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline1dinterpolant *dst = (spline1dinterpolant*)_dst; + const spline1dinterpolant *src = (const spline1dinterpolant*)_src; + dst->periodic = src->periodic; + dst->n = src->n; + dst->k = src->k; + dst->continuity = src->continuity; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); +} + + +void _spline1dinterpolant_clear(void* _p) +{ + spline1dinterpolant *p = (spline1dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->c); +} + + +void _spline1dinterpolant_destroy(void* _p) +{ + spline1dinterpolant *p = (spline1dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->c); +} + + +void _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline1dfitreport *p = (spline1dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline1dfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline1dfitreport *dst = (spline1dfitreport*)_dst; + const spline1dfitreport *src = (const spline1dfitreport*)_src; + dst->terminationtype = src->terminationtype; + dst->taskrcond = src->taskrcond; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->maxerror = src->maxerror; +} + + +void _spline1dfitreport_clear(void* _p) +{ + spline1dfitreport *p = (spline1dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline1dfitreport_destroy(void* _p) +{ + spline1dfitreport *p = (spline1dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline1dbbasis_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline1dbbasis *p = (spline1dbbasis*)_p; + ae_touch_ptr((void*)p); + _spline1dinterpolant_init(&p->s0, _state, make_automatic); + _spline1dinterpolant_init(&p->s1, _state, make_automatic); + _spline1dinterpolant_init(&p->s2, _state, make_automatic); + ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpy, 0, DT_REAL, _state, make_automatic); +} + + +void _spline1dbbasis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline1dbbasis *dst = (spline1dbbasis*)_dst; + const spline1dbbasis *src = (const spline1dbbasis*)_src; + dst->m = src->m; + dst->bfrad = src->bfrad; + _spline1dinterpolant_init_copy(&dst->s0, &src->s0, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->s1, &src->s1, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->s2, &src->s2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpy, &src->tmpy, _state, make_automatic); +} + + +void _spline1dbbasis_clear(void* _p) +{ + spline1dbbasis *p = (spline1dbbasis*)_p; + ae_touch_ptr((void*)p); + _spline1dinterpolant_clear(&p->s0); + _spline1dinterpolant_clear(&p->s1); + _spline1dinterpolant_clear(&p->s2); + ae_vector_clear(&p->tmpx); + ae_vector_clear(&p->tmpy); +} + + +void _spline1dbbasis_destroy(void* _p) +{ + spline1dbbasis *p = (spline1dbbasis*)_p; + ae_touch_ptr((void*)p); + _spline1dinterpolant_destroy(&p->s0); + _spline1dinterpolant_destroy(&p->s1); + _spline1dinterpolant_destroy(&p->s2); + ae_vector_destroy(&p->tmpx); + ae_vector_destroy(&p->tmpy); +} + + +#endif +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine fits piecewise linear curve to points with Ramer-Douglas- +Peucker algorithm, which stops after generating specified number of linear +sections. + +IMPORTANT: +* it does NOT perform least-squares fitting; it builds curve, but this + curve does not minimize some least squares metric. See description of + RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. +* this function does NOT work with parametric curves (i.e. curves which + can be represented as {X(t),Y(t)}. It works with curves which can be + represented as Y(X). Thus, it is impossible to model figures like + circles with this functions. + If you want to work with parametric curves, you should use + ParametricRDPFixed() function provided by "Parametric" subpackage of + "Interpolation" package. + +INPUT PARAMETERS: + X - array of X-coordinates: + * at least N elements + * can be unordered (points are automatically sorted) + * this function may accept non-distinct X (see below for + more information on handling of such inputs) + Y - array of Y-coordinates: + * at least N elements + N - number of elements in X/Y + M - desired number of sections: + * at most M sections are generated by this function + * less than M sections can be generated if we have N=0, "LSTFitPiecewiseLinearRDPFixed: N<0", _state); + ae_assert(m>=1, "LSTFitPiecewiseLinearRDPFixed: M<1", _state); + ae_assert(x.cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(X)=n, "LSTFitPiecewiseLinearRDPFixed: Length(Y)ptr.p_double[i] = x.ptr.p_double[ae_round(points.ptr.p_double[i], _state)]; + y2->ptr.p_double[i] = y.ptr.p_double[ae_round(points.ptr.p_double[i], _state)]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine fits piecewise linear curve to points with Ramer-Douglas- +Peucker algorithm, which stops after achieving desired precision. + +IMPORTANT: +* it performs non-least-squares fitting; it builds curve, but this curve + does not minimize some least squares metric. See description of RDP + algorithm (say, in Wikipedia) for more details on WHAT is performed. +* this function does NOT work with parametric curves (i.e. curves which + can be represented as {X(t),Y(t)}. It works with curves which can be + represented as Y(X). Thus, it is impossible to model figures like circles + with this functions. + If you want to work with parametric curves, you should use + ParametricRDPFixed() function provided by "Parametric" subpackage of + "Interpolation" package. + +INPUT PARAMETERS: + X - array of X-coordinates: + * at least N elements + * can be unordered (points are automatically sorted) + * this function may accept non-distinct X (see below for + more information on handling of such inputs) + Y - array of Y-coordinates: + * at least N elements + N - number of elements in X/Y + Eps - positive number, desired precision. + + +OUTPUT PARAMETERS: + X2 - X-values of corner points for piecewise approximation, + has length NSections+1 or zero (for NSections=0). + Y2 - Y-values of corner points, + has length NSections+1 or zero (for NSections=0). + NSections- number of sections found by algorithm, + NSections can be zero for degenerate datasets + (N<=1 or all X[] are non-distinct). + +NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is a first point of + curve, (X2[NSection-1],Y2[NSection-1]) is the last point. + + -- ALGLIB -- + Copyright 02.10.2014 by Bochkanov Sergey +*************************************************************************/ +void lstfitpiecewiselinearrdp(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double eps, + /* Real */ ae_vector* x2, + /* Real */ ae_vector* y2, + ae_int_t* nsections, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector buf0; + ae_vector buf1; + ae_vector xtmp; + ae_vector ytmp; + double v; + ae_int_t npts; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&buf0, 0, sizeof(buf0)); + memset(&buf1, 0, sizeof(buf1)); + memset(&xtmp, 0, sizeof(xtmp)); + memset(&ytmp, 0, sizeof(ytmp)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_clear(x2); + ae_vector_clear(y2); + *nsections = 0; + ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xtmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ytmp, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "LSTFitPiecewiseLinearRDP: N<0", _state); + ae_assert(ae_fp_greater(eps,(double)(0)), "LSTFitPiecewiseLinearRDP: Eps<=0", _state); + ae_assert(x.cnt>=n, "LSTFitPiecewiseLinearRDP: Length(X)=n, "LSTFitPiecewiseLinearRDP: Length(Y)ptr.p_double[i] = xtmp.ptr.p_double[i]; + y2->ptr.p_double[i] = ytmp.ptr.p_double[i]; + } + tagsortfastr(x2, y2, &buf0, &buf1, npts, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Fitting by polynomials in barycentric form. This function provides simple +unterface for unconstrained unweighted fitting. See PolynomialFitWC() if +you need constrained fitting. + +The task is linear, thus the linear least squares solver is used. The +complexity of this computational scheme is O(N*M^2), mostly dominated by +the least squares solver + +SEE ALSO: + PolynomialFitWC() + +NOTES: + you can convert P from barycentric form to the power or Chebyshev + basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from + POLINT subpackage. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points, N>0 + * if given, only leading N elements of X/Y are used + * if not given, automatically determined from sizes of X/Y + M - number of basis functions (= polynomial_degree + 1), M>=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code which is always + set to 1 (success) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfit(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + barycentricinterpolant* p, + polynomialfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector w; + ae_vector xc; + ae_vector yc; + ae_vector dc; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&dc, 0, sizeof(dc)); + _barycentricinterpolant_clear(p); + _polynomialfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dc, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "PolynomialFit: N<=0!", _state); + ae_assert(m>0, "PolynomialFit: M<=0!", _state); + ae_assert(x->cnt>=n, "PolynomialFit: Length(X)cnt>=n, "PolynomialFit: Length(Y)0. + * if given, only leading N elements of X/Y/W are used + * if not given, automatically determined from sizes of X/Y/W + XC - points where polynomial values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that P(XC[i])=YC[i] + * DC[i]=1 means that P'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* even simple constraints can be inconsistent, see Wikipedia article on + this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the one special cases, however, we can guarantee consistency. This + case is: M>1 and constraints on the function values (NOT DERIVATIVES) + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfitwc(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + barycentricinterpolant* p, + polynomialfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector w; + ae_vector xc; + ae_vector yc; + double xa; + double xb; + double sa; + double sb; + ae_vector xoriginal; + ae_vector yoriginal; + ae_vector y2; + ae_vector w2; + ae_vector tmp; + ae_vector tmp2; + ae_vector bx; + ae_vector by; + ae_vector bw; + ae_int_t i; + ae_int_t j; + double u; + double v; + double s; + ae_int_t relcnt; + lsfitreport lrep; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&xoriginal, 0, sizeof(xoriginal)); + memset(&yoriginal, 0, sizeof(yoriginal)); + memset(&y2, 0, sizeof(y2)); + memset(&w2, 0, sizeof(w2)); + memset(&tmp, 0, sizeof(tmp)); + memset(&tmp2, 0, sizeof(tmp2)); + memset(&bx, 0, sizeof(bx)); + memset(&by, 0, sizeof(by)); + memset(&bw, 0, sizeof(bw)); + memset(&lrep, 0, sizeof(lrep)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&w, _w, _state, ae_true); + ae_vector_init_copy(&xc, _xc, _state, ae_true); + ae_vector_init_copy(&yc, _yc, _state, ae_true); + _barycentricinterpolant_clear(p); + _polynomialfitreport_clear(rep); + ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&by, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bw, 0, DT_REAL, _state, ae_true); + _lsfitreport_init(&lrep, _state, ae_true); + + ae_assert(n>0, "PolynomialFitWC: N<=0!", _state); + ae_assert(m>0, "PolynomialFitWC: M<=0!", _state); + ae_assert(k>=0, "PolynomialFitWC: K<0!", _state); + ae_assert(k=M!", _state); + ae_assert(x.cnt>=n, "PolynomialFitWC: Length(X)=n, "PolynomialFitWC: Length(Y)=n, "PolynomialFitWC: Length(W)=k, "PolynomialFitWC: Length(XC)=k, "PolynomialFitWC: Length(YC)cnt>=k, "PolynomialFitWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "PolynomialFitWC: one of DC[] is not 0 or 1!", _state); + } + + /* + * Scale X, Y, XC, YC. + * Solve scaled problem using internal Chebyshev fitting function. + */ + lsfitscalexy(&x, &y, &w, n, &xc, &yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); + lsfit_internalchebyshevfit(&x, &y, &w, n, &xc, &yc, dc, k, m, &tmp, &lrep, _state); + rep->terminationtype = lrep.terminationtype; + if( rep->terminationtype<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Generate barycentric model and scale it + * * BX, BY store barycentric model nodes + * * FMatrix is reused (remember - it is at least MxM, what we need) + * + * Model intialization is done in O(M^2). In principle, it can be + * done in O(M*log(M)), but before it we solved task with O(N*M^2) + * complexity, so it is only a small amount of total time spent. + */ + ae_vector_set_length(&bx, m, _state); + ae_vector_set_length(&by, m, _state); + ae_vector_set_length(&bw, m, _state); + ae_vector_set_length(&tmp2, m, _state); + s = (double)(1); + for(i=0; i<=m-1; i++) + { + if( m!=1 ) + { + u = ae_cos(ae_pi*(double)i/(double)(m-1), _state); + } + else + { + u = (double)(0); + } + v = (double)(0); + for(j=0; j<=m-1; j++) + { + if( j==0 ) + { + tmp2.ptr.p_double[j] = (double)(1); + } + else + { + if( j==1 ) + { + tmp2.ptr.p_double[j] = u; + } + else + { + tmp2.ptr.p_double[j] = (double)2*u*tmp2.ptr.p_double[j-1]-tmp2.ptr.p_double[j-2]; + } + } + v = v+tmp.ptr.p_double[j]*tmp2.ptr.p_double[j]; + } + bx.ptr.p_double[i] = u; + by.ptr.p_double[i] = v; + bw.ptr.p_double[i] = s; + if( i==0||i==m-1 ) + { + bw.ptr.p_double[i] = 0.5*bw.ptr.p_double[i]; + } + s = -s; + } + barycentricbuildxyw(&bx, &by, &bw, m, p, _state); + barycentriclintransx(p, (double)2/(xb-xa), -(xa+xb)/(xb-xa), _state); + barycentriclintransy(p, sb-sa, sa, _state); + + /* + * Scale absolute errors obtained from LSFitLinearW. + * Relative error should be calculated separately + * (because of shifting/scaling of the task) + */ + rep->taskrcond = lrep.taskrcond; + rep->rmserror = lrep.rmserror*(sb-sa); + rep->avgerror = lrep.avgerror*(sb-sa); + rep->maxerror = lrep.maxerror*(sb-sa); + rep->avgrelerror = (double)(0); + relcnt = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(p, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); + relcnt = relcnt+1; + } + } + if( relcnt!=0 ) + { + rep->avgrelerror = rep->avgrelerror/(double)relcnt; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates value of four-parameter logistic (4PL) model at +specified point X. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D- parameters of 4PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X + (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc4(double x, + double a, + double b, + double c, + double d, + ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x, _state), "LogisticCalc4: X is not finite", _state); + ae_assert(ae_isfinite(a, _state), "LogisticCalc4: A is not finite", _state); + ae_assert(ae_isfinite(b, _state), "LogisticCalc4: B is not finite", _state); + ae_assert(ae_isfinite(c, _state), "LogisticCalc4: C is not finite", _state); + ae_assert(ae_isfinite(d, _state), "LogisticCalc4: D is not finite", _state); + ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc4: X is negative", _state); + ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc4: C is non-positive", _state); + + /* + * Check for degenerate cases + */ + if( ae_fp_eq(b,(double)(0)) ) + { + result = 0.5*(a+d); + return result; + } + if( ae_fp_eq(x,(double)(0)) ) + { + if( ae_fp_greater(b,(double)(0)) ) + { + result = a; + } + else + { + result = d; + } + return result; + } + + /* + * General case + */ + result = d+(a-d)/(1.0+ae_pow(x/c, b, _state)); + ae_assert(ae_isfinite(result, _state), "LogisticCalc4: overflow during calculations", _state); + return result; +} + + +/************************************************************************* +This function calculates value of five-parameter logistic (5PL) model at +specified point X. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D, G- parameters of 5PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + * G>0, non-positive value results in exception + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for + zero X (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc5(double x, + double a, + double b, + double c, + double d, + double g, + ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x, _state), "LogisticCalc5: X is not finite", _state); + ae_assert(ae_isfinite(a, _state), "LogisticCalc5: A is not finite", _state); + ae_assert(ae_isfinite(b, _state), "LogisticCalc5: B is not finite", _state); + ae_assert(ae_isfinite(c, _state), "LogisticCalc5: C is not finite", _state); + ae_assert(ae_isfinite(d, _state), "LogisticCalc5: D is not finite", _state); + ae_assert(ae_isfinite(g, _state), "LogisticCalc5: G is not finite", _state); + ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc5: X is negative", _state); + ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc5: C is non-positive", _state); + ae_assert(ae_fp_greater(g,(double)(0)), "LogisticCalc5: G is non-positive", _state); + + /* + * Check for degenerate cases + */ + if( ae_fp_eq(b,(double)(0)) ) + { + result = d+(a-d)/ae_pow(2.0, g, _state); + return result; + } + if( ae_fp_eq(x,(double)(0)) ) + { + if( ae_fp_greater(b,(double)(0)) ) + { + result = a; + } + else + { + result = d; + } + return result; + } + + /* + * General case + */ + result = d+(a-d)/ae_pow(1.0+ae_pow(x/c, b, _state), g, _state); + ae_assert(ae_isfinite(result, _state), "LogisticCalc5: overflow during calculations", _state); + return result; +} + + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double* a, + double* b, + double* c, + double* d, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + double g; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *a = 0.0; + *b = 0.0; + *c = 0.0; + *d = 0.0; + _lsfitreport_clear(rep); + + logisticfit45x(&x, &y, n, _state->v_nan, _state->v_nan, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user, with optional constraints on parameters A and D. 4PL model has +following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - with optional equality constraints + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4ec(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + double* a, + double* b, + double* c, + double* d, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + double g; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *a = 0.0; + *b = 0.0; + *c = 0.0; + *d = 0.0; + _lsfitreport_clear(rep); + + logisticfit45x(&x, &y, n, cnstrleft, cnstrright, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - unconstrained + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *a = 0.0; + *b = 0.0; + *c = 0.0; + *d = 0.0; + *g = 0.0; + _lsfitreport_clear(rep); + + logisticfit45x(&x, &y, n, _state->v_nan, _state->v_nan, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user, subject to optional equality constraints on parameters A and D. +5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - with optional equality constraints + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. + +Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign +of B. Thus, negative B's are possible, and left constraint may constrain +parameter A (for positive B's) - or parameter D (for negative B's). +Similarly changes meaning of right constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5ec(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *a = 0.0; + *b = 0.0; + *c = 0.0; + *d = 0.0; + *g = 0.0; + _lsfitreport_clear(rep); + + logisticfit45x(&x, &y, n, cnstrleft, cnstrright, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This is "expert" 4PL/5PL fitting function, which can be used if you need +better control over fitting process than provided by LogisticFit4() or +LogisticFit5(). + +This function fits model of the form + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) + +or + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) + +Here: + * A, D - unconstrained + * B>=0 for 4PL, unconstrained for 5PL + * C>0 + * G>0 (if present) + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + Is4PL - whether 4PL or 5PL models are fitted + LambdaV - regularization coefficient, LambdaV>=0. + Set it to zero unless you know what you are doing. + EpsX - stopping condition (step size), EpsX>=0. + Zero value means that small step is automatically chosen. + See notes below for more information. + RsCnt - number of repeated restarts from random points. 4PL/5PL + models are prone to problem of bad local extrema. Utilizing + multiple random restarts allows us to improve algorithm + convergence. + RsCnt>=0. + Zero value means that function automatically choose small + amount of restarts (recommended). + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + G - parameter of 5PL model; for Is4PL=True, G=1 is returned. + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + +For 5PL model things are different. Unlike 4PL one, 5PL model is NOT +symmetric with respect to change in sign of B. Thus, negative B's are +possible, and left constraint may constrain parameter A (for positive B's) +- or parameter D (for negative B's). Similarly changes meaning of right +constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit45x(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + ae_bool is4pl, + double lambdav, + double epsx, + ae_int_t rscnt, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_int_t i; + ae_int_t outerit; + ae_int_t nz; + double v; + ae_vector p0; + ae_vector p1; + ae_vector p2; + ae_vector bndl; + ae_vector bndu; + ae_vector s; + ae_vector bndl1; + ae_vector bndu1; + ae_vector bndl2; + ae_vector bndu2; + ae_matrix z; + hqrndstate rs; + minlmstate state; + minlmreport replm; + ae_int_t maxits; + double fbest; + double flast; + double scalex; + double scaley; + ae_vector bufx; + ae_vector bufy; + double fposb; + double fnegb; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&p0, 0, sizeof(p0)); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + memset(&bndl, 0, sizeof(bndl)); + memset(&bndu, 0, sizeof(bndu)); + memset(&s, 0, sizeof(s)); + memset(&bndl1, 0, sizeof(bndl1)); + memset(&bndu1, 0, sizeof(bndu1)); + memset(&bndl2, 0, sizeof(bndl2)); + memset(&bndu2, 0, sizeof(bndu2)); + memset(&z, 0, sizeof(z)); + memset(&rs, 0, sizeof(rs)); + memset(&state, 0, sizeof(state)); + memset(&replm, 0, sizeof(replm)); + memset(&bufx, 0, sizeof(bufx)); + memset(&bufy, 0, sizeof(bufy)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *a = 0.0; + *b = 0.0; + *c = 0.0; + *d = 0.0; + *g = 0.0; + _lsfitreport_clear(rep); + ae_vector_init(&p0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndl, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndu, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndl1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndu1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndl2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndu2, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + _minlmstate_init(&state, _state, ae_true); + _minlmreport_init(&replm, _state, ae_true); + ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_isfinite(epsx, _state), "LogisticFitX: EpsX is infinite/NAN", _state); + ae_assert(ae_isfinite(lambdav, _state), "LogisticFitX: LambdaV is infinite/NAN", _state); + ae_assert(ae_isfinite(cnstrleft, _state)||ae_isnan(cnstrleft, _state), "LogisticFitX: CnstrLeft is NOT finite or NAN", _state); + ae_assert(ae_isfinite(cnstrright, _state)||ae_isnan(cnstrright, _state), "LogisticFitX: CnstrRight is NOT finite or NAN", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "LogisticFitX: negative LambdaV", _state); + ae_assert(n>0, "LogisticFitX: N<=0", _state); + ae_assert(rscnt>=0, "LogisticFitX: RsCnt<0", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LogisticFitX: EpsX<0", _state); + ae_assert(x.cnt>=n, "LogisticFitX: Length(X)=n, "LogisticFitX: Length(Y)iterationscount = 0; + if( nz==n ) + { + + /* + * NZ=N, degenerate problem. + * No need to run optimizer. + */ + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+y.ptr.p_double[i]; + } + v = v/(double)n; + if( ae_isfinite(cnstrleft, _state) ) + { + *a = cnstrleft; + } + else + { + *a = v; + } + *b = (double)(1); + *c = (double)(1); + if( ae_isfinite(cnstrright, _state) ) + { + *d = cnstrright; + } + else + { + *d = *a; + } + *g = (double)(1); + lsfit_logisticfit45errors(&x, &y, n, *a, *b, *c, *d, *g, rep, _state); + ae_frame_leave(_state); + return; + } + + /* + * Non-degenerate problem. + * Determine scale of data. + */ + scalex = x.ptr.p_double[nz+(n-nz)/2]; + ae_assert(ae_fp_greater(scalex,(double)(0)), "LogisticFitX: internal error", _state); + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+y.ptr.p_double[i]; + } + v = v/(double)n; + scaley = 0.0; + for(i=0; i<=n-1; i++) + { + scaley = scaley+ae_sqr(y.ptr.p_double[i]-v, _state); + } + scaley = ae_sqrt(scaley/(double)n, _state); + if( ae_fp_eq(scaley,(double)(0)) ) + { + scaley = 1.0; + } + ae_vector_set_length(&s, 5, _state); + s.ptr.p_double[0] = scaley; + s.ptr.p_double[1] = 0.1; + s.ptr.p_double[2] = scalex; + s.ptr.p_double[3] = scaley; + s.ptr.p_double[4] = 0.1; + ae_vector_set_length(&p0, 5, _state); + p0.ptr.p_double[0] = (double)(0); + p0.ptr.p_double[1] = (double)(0); + p0.ptr.p_double[2] = (double)(0); + p0.ptr.p_double[3] = (double)(0); + p0.ptr.p_double[4] = (double)(0); + ae_vector_set_length(&bndl, 5, _state); + ae_vector_set_length(&bndu, 5, _state); + ae_vector_set_length(&bndl1, 5, _state); + ae_vector_set_length(&bndu1, 5, _state); + ae_vector_set_length(&bndl2, 5, _state); + ae_vector_set_length(&bndu2, 5, _state); + minlmcreatevj(5, n+5, &p0, &state, _state); + minlmsetscale(&state, &s, _state); + minlmsetcond(&state, epsx, maxits, _state); + minlmsetxrep(&state, ae_true, _state); + ae_vector_set_length(&p1, 5, _state); + ae_vector_set_length(&p2, 5, _state); + + /* + * Is it 4PL problem? + */ + if( is4pl ) + { + + /* + * Run outer iterations + */ + *a = (double)(0); + *b = (double)(1); + *c = (double)(1); + *d = (double)(1); + *g = (double)(1); + fbest = ae_maxrealnumber; + for(outerit=0; outerit<=rscnt-1; outerit++) + { + + /* + * Prepare initial point; use B>0 + */ + if( ae_isfinite(cnstrleft, _state) ) + { + p1.ptr.p_double[0] = cnstrleft; + } + else + { + p1.ptr.p_double[0] = y.ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5); + } + p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state); + p1.ptr.p_double[2] = x.ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)]; + if( ae_isfinite(cnstrright, _state) ) + { + p1.ptr.p_double[3] = cnstrright; + } + else + { + p1.ptr.p_double[3] = y.ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5); + } + p1.ptr.p_double[4] = 1.0; + + /* + * Run optimization with tight constraints and increased regularization + */ + if( ae_isfinite(cnstrleft, _state) ) + { + bndl.ptr.p_double[0] = cnstrleft; + bndu.ptr.p_double[0] = cnstrleft; + } + else + { + bndl.ptr.p_double[0] = _state->v_neginf; + bndu.ptr.p_double[0] = _state->v_posinf; + } + bndl.ptr.p_double[1] = 0.5; + bndu.ptr.p_double[1] = 2.0; + bndl.ptr.p_double[2] = 0.5*scalex; + bndu.ptr.p_double[2] = 2.0*scalex; + if( ae_isfinite(cnstrright, _state) ) + { + bndl.ptr.p_double[3] = cnstrright; + bndu.ptr.p_double[3] = cnstrright; + } + else + { + bndl.ptr.p_double[3] = _state->v_neginf; + bndu.ptr.p_double[3] = _state->v_posinf; + } + bndl.ptr.p_double[4] = 1.0; + bndu.ptr.p_double[4] = 1.0; + minlmsetbc(&state, &bndl, &bndu, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, (double)100*lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Relax constraints, run optimization one more time + */ + bndl.ptr.p_double[1] = 0.1; + bndu.ptr.p_double[1] = 10.0; + bndl.ptr.p_double[2] = ae_machineepsilon*scalex; + bndu.ptr.p_double[2] = scalex/ae_machineepsilon; + minlmsetbc(&state, &bndl, &bndu, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Relax constraints more, run optimization one more time + */ + bndl.ptr.p_double[1] = 0.01; + bndu.ptr.p_double[1] = 100.0; + minlmsetbc(&state, &bndl, &bndu, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Relax constraints ever more, run optimization one more time + */ + bndl.ptr.p_double[1] = 0.001; + bndu.ptr.p_double[1] = 1000.0; + minlmsetbc(&state, &bndl, &bndu, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Compare results with best value found so far. + */ + if( ae_fp_less(flast,fbest) ) + { + *a = p1.ptr.p_double[0]; + *b = p1.ptr.p_double[1]; + *c = p1.ptr.p_double[2]; + *d = p1.ptr.p_double[3]; + *g = p1.ptr.p_double[4]; + fbest = flast; + } + } + lsfit_logisticfit45errors(&x, &y, n, *a, *b, *c, *d, *g, rep, _state); + ae_frame_leave(_state); + return; + } + + /* + * Well.... we have 5PL fit, and we have to test two separate branches: + * B>0 and B<0, because of asymmetry in the curve. First, we run optimization + * with tight constraints two times, in order to determine better sign for B. + * + * Run outer iterations + */ + *a = (double)(0); + *b = (double)(1); + *c = (double)(1); + *d = (double)(1); + *g = (double)(1); + fbest = ae_maxrealnumber; + for(outerit=0; outerit<=rscnt-1; outerit++) + { + + /* + * First, we try positive B. + */ + p1.ptr.p_double[0] = y.ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5); + p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state); + p1.ptr.p_double[2] = x.ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)]; + p1.ptr.p_double[3] = y.ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5); + p1.ptr.p_double[4] = 1.0; + bndl1.ptr.p_double[0] = _state->v_neginf; + bndu1.ptr.p_double[0] = _state->v_posinf; + bndl1.ptr.p_double[1] = 0.5; + bndu1.ptr.p_double[1] = 2.0; + bndl1.ptr.p_double[2] = 0.5*scalex; + bndu1.ptr.p_double[2] = 2.0*scalex; + bndl1.ptr.p_double[3] = _state->v_neginf; + bndu1.ptr.p_double[3] = _state->v_posinf; + bndl1.ptr.p_double[4] = 0.5; + bndu1.ptr.p_double[4] = 2.0; + if( ae_isfinite(cnstrleft, _state) ) + { + p1.ptr.p_double[0] = cnstrleft; + bndl1.ptr.p_double[0] = cnstrleft; + bndu1.ptr.p_double[0] = cnstrleft; + } + if( ae_isfinite(cnstrright, _state) ) + { + p1.ptr.p_double[3] = cnstrright; + bndl1.ptr.p_double[3] = cnstrright; + bndu1.ptr.p_double[3] = cnstrright; + } + minlmsetbc(&state, &bndl1, &bndu1, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, (double)100*lambdav, &state, &replm, &p1, &fposb, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Second attempt - with negative B (constraints are still tight). + */ + p2.ptr.p_double[0] = y.ptr.p_double[n-1]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5); + p2.ptr.p_double[1] = -(0.5+hqrnduniformr(&rs, _state)); + p2.ptr.p_double[2] = x.ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)]; + p2.ptr.p_double[3] = y.ptr.p_double[0]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5); + p2.ptr.p_double[4] = 1.0; + bndl2.ptr.p_double[0] = _state->v_neginf; + bndu2.ptr.p_double[0] = _state->v_posinf; + bndl2.ptr.p_double[1] = -2.0; + bndu2.ptr.p_double[1] = -0.5; + bndl2.ptr.p_double[2] = 0.5*scalex; + bndu2.ptr.p_double[2] = 2.0*scalex; + bndl2.ptr.p_double[3] = _state->v_neginf; + bndu2.ptr.p_double[3] = _state->v_posinf; + bndl2.ptr.p_double[4] = 0.5; + bndu2.ptr.p_double[4] = 2.0; + if( ae_isfinite(cnstrleft, _state) ) + { + p2.ptr.p_double[3] = cnstrleft; + bndl2.ptr.p_double[3] = cnstrleft; + bndu2.ptr.p_double[3] = cnstrleft; + } + if( ae_isfinite(cnstrright, _state) ) + { + p2.ptr.p_double[0] = cnstrright; + bndl2.ptr.p_double[0] = cnstrright; + bndu2.ptr.p_double[0] = cnstrright; + } + minlmsetbc(&state, &bndl2, &bndu2, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, (double)100*lambdav, &state, &replm, &p2, &fnegb, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Select best version of B sign + */ + if( ae_fp_less(fposb,fnegb) ) + { + + /* + * Prepare relaxed constraints assuming that B is positive + */ + bndl1.ptr.p_double[1] = 0.1; + bndu1.ptr.p_double[1] = 10.0; + bndl1.ptr.p_double[2] = ae_machineepsilon*scalex; + bndu1.ptr.p_double[2] = scalex/ae_machineepsilon; + bndl1.ptr.p_double[4] = 0.1; + bndu1.ptr.p_double[4] = 10.0; + minlmsetbc(&state, &bndl1, &bndu1, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Prepare stronger relaxation of constraints + */ + bndl1.ptr.p_double[1] = 0.01; + bndu1.ptr.p_double[1] = 100.0; + minlmsetbc(&state, &bndl1, &bndu1, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Prepare stronger relaxation of constraints + */ + bndl1.ptr.p_double[1] = 0.001; + bndu1.ptr.p_double[1] = 1000.0; + minlmsetbc(&state, &bndl1, &bndu1, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Compare results with best value found so far. + */ + if( ae_fp_less(flast,fbest) ) + { + *a = p1.ptr.p_double[0]; + *b = p1.ptr.p_double[1]; + *c = p1.ptr.p_double[2]; + *d = p1.ptr.p_double[3]; + *g = p1.ptr.p_double[4]; + fbest = flast; + } + } + else + { + + /* + * Prepare relaxed constraints assuming that B is negative + */ + bndl2.ptr.p_double[1] = -10.0; + bndu2.ptr.p_double[1] = -0.1; + bndl2.ptr.p_double[2] = ae_machineepsilon*scalex; + bndu2.ptr.p_double[2] = scalex/ae_machineepsilon; + bndl2.ptr.p_double[4] = 0.1; + bndu2.ptr.p_double[4] = 10.0; + minlmsetbc(&state, &bndl2, &bndu2, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Prepare stronger relaxation + */ + bndl2.ptr.p_double[1] = -100.0; + bndu2.ptr.p_double[1] = -0.01; + minlmsetbc(&state, &bndl2, &bndu2, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Prepare stronger relaxation + */ + bndl2.ptr.p_double[1] = -1000.0; + bndu2.ptr.p_double[1] = -0.001; + minlmsetbc(&state, &bndl2, &bndu2, _state); + lsfit_logisticfitinternal(&x, &y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state); + rep->iterationscount = rep->iterationscount+replm.iterationscount; + + /* + * Compare results with best value found so far. + */ + if( ae_fp_less(flast,fbest) ) + { + *a = p2.ptr.p_double[0]; + *b = p2.ptr.p_double[1]; + *c = p2.ptr.p_double[2]; + *d = p2.ptr.p_double[3]; + *g = p2.ptr.p_double[4]; + fbest = flast; + } + } + } + lsfit_logisticfit45errors(&x, &y, n, *a, *b, *c, *d, *g, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Weghted rational least squares fitting using Floater-Hormann rational +functions with optimal D chosen from [0,9], with constraints and +individual weights. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least WEIGHTED root +mean square error) is chosen. Task is linear, so linear least squares +solver is used. Complexity of this computational scheme is O(N*M^2) +(mostly dominated by the least squares solver). + +SEE ALSO +* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual + weights and constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + XC - points where function values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. Undefined for rep.terminationtype<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroutine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained barycentric interpolants: +* excessive constraints can be inconsistent. Floater-Hormann basis + functions aren't as flexible as splines (although they are very smooth). +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function VALUES at the interval + boundaries. Note that consustency of the constraints on the function + DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines + which are more flexible). +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormannwc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t d; + ae_int_t i; + double wrmscur; + double wrmsbest; + barycentricinterpolant locb; + barycentricfitreport locrep; + ae_int_t locinfo; + + ae_frame_make(_state, &_frame_block); + memset(&locb, 0, sizeof(locb)); + memset(&locrep, 0, sizeof(locrep)); + _barycentricinterpolant_clear(b); + _barycentricfitreport_clear(rep); + _barycentricinterpolant_init(&locb, _state, ae_true); + _barycentricfitreport_init(&locrep, _state, ae_true); + + ae_assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!", _state); + ae_assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!", _state); + ae_assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!", _state); + ae_assert(k=M!", _state); + ae_assert(x->cnt>=n, "BarycentricFitFloaterHormannWC: Length(X)cnt>=n, "BarycentricFitFloaterHormannWC: Length(Y)cnt>=n, "BarycentricFitFloaterHormannWC: Length(W)cnt>=k, "BarycentricFitFloaterHormannWC: Length(XC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(YC)cnt>=k, "BarycentricFitFloaterHormannWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!", _state); + } + + /* + * Find optimal D + * + * Info is -3 by default (degenerate constraints). + * If LocInfo will always be equal to -3, Info will remain equal to -3. + * If at least once LocInfo will be -4, Info will be -4. + */ + wrmsbest = ae_maxrealnumber; + rep->dbest = -1; + rep->terminationtype = -3; + for(d=0; d<=ae_minint(9, n-1, _state); d++) + { + lsfit_barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, &locinfo, &locb, &locrep, _state); + ae_assert((locinfo==-4||locinfo==-3)||locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!", _state); + if( locinfo>0 ) + { + + /* + * Calculate weghted RMS + */ + wrmscur = (double)(0); + for(i=0; i<=n-1; i++) + { + wrmscur = wrmscur+ae_sqr(w->ptr.p_double[i]*(y->ptr.p_double[i]-barycentriccalc(&locb, x->ptr.p_double[i], _state)), _state); + } + wrmscur = ae_sqrt(wrmscur/(double)n, _state); + if( ae_fp_less(wrmscur,wrmsbest)||rep->dbest<0 ) + { + barycentriccopy(&locb, b, _state); + rep->dbest = d; + rep->terminationtype = 1; + rep->rmserror = locrep.rmserror; + rep->avgerror = locrep.avgerror; + rep->avgrelerror = locrep.avgrelerror; + rep->maxerror = locrep.maxerror; + rep->taskrcond = locrep.taskrcond; + wrmsbest = wrmscur; + } + } + else + { + if( locinfo!=-3&&rep->terminationtype<0 ) + { + rep->terminationtype = locinfo; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Rational least squares fitting using Floater-Hormann rational functions +with optimal D chosen from [0,9]. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least root mean +square error) is chosen. Task is linear, so linear least squares solver +is used. Complexity of this computational scheme is O(N*M^2) (mostly +dominated by the least squares solver). + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points, N>0. + M - number of basis functions ( = number_of_nodes), M>=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code, always set to 1 + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormann(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector w; + ae_vector xc; + ae_vector yc; + ae_vector dc; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&dc, 0, sizeof(dc)); + _barycentricinterpolant_clear(b); + _barycentricfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dc, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "BarycentricFitFloaterHormann: N<=0!", _state); + ae_assert(m>0, "BarycentricFitFloaterHormann: M<=0!", _state); + ae_assert(x->cnt>=n, "BarycentricFitFloaterHormann: Length(X)cnt>=n, "BarycentricFitFloaterHormann: Length(Y)0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4. + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function values AND/OR its + derivatives at the interval boundaries. +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubicwc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_int_t i; + + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + + ae_assert(n>=1, "Spline1DFitCubicWC: N<1!", _state); + ae_assert(m>=4, "Spline1DFitCubicWC: M<4!", _state); + ae_assert(k>=0, "Spline1DFitCubicWC: K<0!", _state); + ae_assert(k=M!", _state); + ae_assert(x->cnt>=n, "Spline1DFitCubicWC: Length(X)cnt>=n, "Spline1DFitCubicWC: Length(Y)cnt>=n, "Spline1DFitCubicWC: Length(W)cnt>=k, "Spline1DFitCubicWC: Length(XC)cnt>=k, "Spline1DFitCubicWC: Length(YC)cnt>=k, "Spline1DFitCubicWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitCubicWC: DC[i] is neither 0 or 1!", _state); + } + lsfit_spline1dfitinternal(0, x, y, w, n, xc, yc, dc, k, m, s, rep, _state); +} + + +/************************************************************************* +Weighted fitting by Hermite spline, with constraints on function values +or first derivatives. + +Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are Hermite splines. Small regularizing +term is used when solving constrained tasks (to improve stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4, + M IS EVEN! + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +IMPORTANT: + this subroitine supports only even M's + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the several special cases, however, we can guarantee consistency. +* one of this cases is M>=4 and constraints on the function value + (AND/OR its derivative) at the interval boundaries. +* another special case is M>=4 and ONE constraint on the function value + (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermitewc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_int_t i; + + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + + ae_assert(n>=1, "Spline1DFitHermiteWC: N<1!", _state); + ae_assert(m>=4, "Spline1DFitHermiteWC: M<4!", _state); + ae_assert(m%2==0, "Spline1DFitHermiteWC: M is odd!", _state); + ae_assert(k>=0, "Spline1DFitHermiteWC: K<0!", _state); + ae_assert(k=M!", _state); + ae_assert(x->cnt>=n, "Spline1DFitHermiteWC: Length(X)cnt>=n, "Spline1DFitHermiteWC: Length(Y)cnt>=n, "Spline1DFitHermiteWC: Length(W)cnt>=k, "Spline1DFitHermiteWC: Length(XC)cnt>=k, "Spline1DFitHermiteWC: Length(YC)cnt>=k, "Spline1DFitHermiteWC: Length(DC)ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitHermiteWC: DC[i] is neither 0 or 1!", _state); + } + lsfit_spline1dfitinternal(1, x, y, w, n, xc, yc, dc, k, m, s, rep, _state); +} + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubicdeprecated(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector w; + ae_vector xc; + ae_vector yc; + ae_vector dc; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&dc, 0, sizeof(dc)); + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dc, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "Spline1DFitCubic: N<1!", _state); + ae_assert(m>=4, "Spline1DFitCubic: M<4!", _state); + ae_assert(x->cnt>=n, "Spline1DFitCubic: Length(X)cnt>=n, "Spline1DFitCubic: Length(Y)=1, "Spline1DFitHermite: N<1!", _state); + ae_assert(m>=4, "Spline1DFitHermite: M<4!", _state); + ae_assert(m%2==0, "Spline1DFitHermite: M is odd!", _state); + ae_assert(x->cnt>=n, "Spline1DFitHermite: Length(X)cnt>=n, "Spline1DFitHermite: Length(Y)=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType always set to 1 (success) + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearw(/* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + + ae_vector_clear(c); + _lsfitreport_clear(rep); + + ae_assert(n>=1, "LSFitLinearW: N<1!", _state); + ae_assert(m>=1, "LSFitLinearW: M<1!", _state); + ae_assert(y->cnt>=n, "LSFitLinearW: length(Y)cnt>=n, "LSFitLinearW: length(W)rows>=n, "LSFitLinearW: rows(FMatrix)cols>=m, "LSFitLinearW: cols(FMatrix)=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearwc(/* Real */ const ae_vector* _y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + /* Real */ const ae_matrix* _cmatrix, + ae_int_t n, + ae_int_t m, + ae_int_t k, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector y; + ae_matrix cmatrix; + ae_int_t i; + ae_int_t j; + ae_vector tau; + ae_matrix q; + ae_matrix f2; + ae_vector tmp; + ae_vector c0; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&y, 0, sizeof(y)); + memset(&cmatrix, 0, sizeof(cmatrix)); + memset(&tau, 0, sizeof(tau)); + memset(&q, 0, sizeof(q)); + memset(&f2, 0, sizeof(f2)); + memset(&tmp, 0, sizeof(tmp)); + memset(&c0, 0, sizeof(c0)); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_matrix_init_copy(&cmatrix, _cmatrix, _state, ae_true); + ae_vector_clear(c); + _lsfitreport_clear(rep); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&f2, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "LSFitLinearWC: N<1!", _state); + ae_assert(m>=1, "LSFitLinearWC: M<1!", _state); + ae_assert(k>=0, "LSFitLinearWC: K<0!", _state); + ae_assert(y.cnt>=n, "LSFitLinearWC: length(Y)cnt>=n, "LSFitLinearWC: length(W)rows>=n, "LSFitLinearWC: rows(FMatrix)cols>=m, "LSFitLinearWC: cols(FMatrix)=k, "LSFitLinearWC: rows(CMatrix)=m+1||k==0, "LSFitLinearWC: cols(CMatrix)=m ) + { + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Solve + */ + if( k==0 ) + { + + /* + * no constraints + */ + lsfit_lsfitlinearinternal(&y, w, fmatrix, n, m, c, rep, _state); + } + else + { + + /* + * First, find general form solution of constraints system: + * * factorize C = L*Q + * * unpack Q + * * fill upper part of C with zeros (for RCond) + * + * We got C=C0+Q2'*y where Q2 is lower M-K rows of Q. + */ + rmatrixlq(&cmatrix, k, m, &tau, _state); + rmatrixlqunpackq(&cmatrix, k, m, &tau, m, &q, _state); + for(i=0; i<=k-1; i++) + { + for(j=i+1; j<=m-1; j++) + { + cmatrix.ptr.pp_double[i][j] = 0.0; + } + } + if( ae_fp_less(rmatrixlurcondinf(&cmatrix, k, _state),(double)1000*ae_machineepsilon) ) + { + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&tmp, k, _state); + for(i=0; i<=k-1; i++) + { + if( i>0 ) + { + v = ae_v_dotproduct(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1)); + } + else + { + v = (double)(0); + } + tmp.ptr.p_double[i] = (cmatrix.ptr.pp_double[i][m]-v)/cmatrix.ptr.pp_double[i][i]; + } + ae_vector_set_length(&c0, m, _state); + for(i=0; i<=m-1; i++) + { + c0.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=k-1; i++) + { + v = tmp.ptr.p_double[i]; + ae_v_addd(&c0.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + } + + /* + * Second, prepare modified matrix F2 = F*Q2' and solve modified task + */ + ae_vector_set_length(&tmp, ae_maxint(n, m, _state)+1, _state); + ae_matrix_set_length(&f2, n, m-k, _state); + matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &c0, 0, m-1, -1.0, &y, 0, n-1, 1.0, _state); + rmatrixgemm(n, m-k, m, 1.0, fmatrix, 0, 0, 0, &q, k, 0, 1, 0.0, &f2, 0, 0, _state); + lsfit_lsfitlinearinternal(&y, w, &f2, n, m-k, &tmp, rep, _state); + rep->taskrcond = (double)(-1); + if( rep->terminationtype<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * then, convert back to original answer: C = C0 + Q2'*Y0 + */ + ae_vector_set_length(c, m, _state); + ae_v_move(&c->ptr.p_double[0], 1, &c0.ptr.p_double[0], 1, ae_v_len(0,m-1)); + matrixvectormultiply(&q, k, m-1, 0, m-1, ae_true, &tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code, always set to + 1 which denotes success + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinear(/* Real */ const ae_vector* y, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector w; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + ae_vector_clear(c); + _lsfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "LSFitLinear: N<1!", _state); + ae_assert(m>=1, "LSFitLinear: M<1!", _state); + ae_assert(y->cnt>=n, "LSFitLinear: length(Y)rows>=n, "LSFitLinear: rows(FMatrix)cols>=m, "LSFitLinear: cols(FMatrix)=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearc(/* Real */ const ae_vector* _y, + /* Real */ const ae_matrix* fmatrix, + /* Real */ const ae_matrix* cmatrix, + ae_int_t n, + ae_int_t m, + ae_int_t k, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector y; + ae_vector w; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_clear(c); + _lsfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "LSFitLinearC: N<1!", _state); + ae_assert(m>=1, "LSFitLinearC: M<1!", _state); + ae_assert(k>=0, "LSFitLinearC: K<0!", _state); + ae_assert(y.cnt>=n, "LSFitLinearC: length(Y)rows>=n, "LSFitLinearC: rows(FMatrix)cols>=m, "LSFitLinearC: cols(FMatrix)rows>=k, "LSFitLinearC: rows(CMatrix)cols>=m+1||k==0, "LSFitLinearC: cols(CMatrix)1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewf(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + double diffstep, + lsfitstate* state, + ae_state *_state) +{ + ae_int_t i; + + _lsfitstate_clear(state); + + ae_assert(n>=1, "LSFitCreateWF: N<1!", _state); + ae_assert(m>=1, "LSFitCreateWF: M<1!", _state); + ae_assert(k>=1, "LSFitCreateWF: K<1!", _state); + ae_assert(c->cnt>=k, "LSFitCreateWF: length(C)cnt>=n, "LSFitCreateWF: length(Y)cnt>=n, "LSFitCreateWF: length(W)rows>=n, "LSFitCreateWF: rows(X)cols>=m, "LSFitCreateWF: cols(X)protocolversion = 1; + state->formulatype = 0; + state->teststep = (double)(0); + state->diffstep = diffstep; + state->npoints = n; + state->nweights = n; + state->wkind = 1; + state->m = m; + state->k = k; + lsfitsetcond(state, 0.0, 0, _state); + lsfitsetstpmax(state, 0.0, _state); + lsfitsetxrep(state, ae_false, _state); + ae_matrix_set_length(&state->taskx, n, m, _state); + ae_vector_set_length(&state->tasky, n, _state); + ae_vector_set_length(&state->taskw, n, _state); + ae_vector_set_length(&state->c, k, _state); + ae_vector_set_length(&state->c0, k, _state); + ae_vector_set_length(&state->c1, k, _state); + ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_vector_set_length(&state->x, m, _state); + ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; + } + ae_vector_set_length(&state->s, k, _state); + ae_vector_set_length(&state->bndl, k, _state); + ae_vector_set_length(&state->bndu, k, _state); + for(i=0; i<=k-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + } + state->optalgo = 0; + state->prevnpt = -1; + state->prevalgo = -1; + state->nec = 0; + state->nic = 0; + state->nonmonotoniccnt = 0; + minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state); + lsfit_lsfitclearrequestfields(state, _state); + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatef(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + double diffstep, + lsfitstate* state, + ae_state *_state) +{ + ae_int_t i; + + _lsfitstate_clear(state); + + ae_assert(n>=1, "LSFitCreateF: N<1!", _state); + ae_assert(m>=1, "LSFitCreateF: M<1!", _state); + ae_assert(k>=1, "LSFitCreateF: K<1!", _state); + ae_assert(c->cnt>=k, "LSFitCreateF: length(C)cnt>=n, "LSFitCreateF: length(Y)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)rows>=n, "LSFitCreateF: rows(X)cols>=m, "LSFitCreateF: cols(X)protocolversion = 1; + state->formulatype = 0; + state->teststep = (double)(0); + state->diffstep = diffstep; + state->npoints = n; + state->wkind = 0; + state->m = m; + state->k = k; + lsfitsetcond(state, 0.0, 0, _state); + lsfitsetstpmax(state, 0.0, _state); + lsfitsetxrep(state, ae_false, _state); + ae_matrix_set_length(&state->taskx, n, m, _state); + ae_vector_set_length(&state->tasky, n, _state); + ae_vector_set_length(&state->c, k, _state); + ae_vector_set_length(&state->c0, k, _state); + ae_vector_set_length(&state->c1, k, _state); + ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_vector_set_length(&state->x, m, _state); + for(i=0; i<=n-1; i++) + { + ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; + } + ae_vector_set_length(&state->s, k, _state); + ae_vector_set_length(&state->bndl, k, _state); + ae_vector_set_length(&state->bndu, k, _state); + for(i=0; i<=k-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + } + state->optalgo = 0; + state->prevnpt = -1; + state->prevalgo = -1; + state->nec = 0; + state->nic = 0; + state->nonmonotoniccnt = 0; + minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state); + lsfit_lsfitclearrequestfields(state, _state); + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Weighted nonlinear least squares fitting using gradient only. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also: + LSFitResults + LSFitCreateFG (fitting without weights) + LSFitCreateWFGH (fitting using Hessian) + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewfg(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + lsfitstate* state, + ae_state *_state) +{ + ae_int_t i; + + _lsfitstate_clear(state); + + ae_assert(n>=1, "LSFitCreateWFG: N<1!", _state); + ae_assert(m>=1, "LSFitCreateWFG: M<1!", _state); + ae_assert(k>=1, "LSFitCreateWFG: K<1!", _state); + ae_assert(c->cnt>=k, "LSFitCreateWFG: length(C)cnt>=n, "LSFitCreateWFG: length(Y)cnt>=n, "LSFitCreateWFG: length(W)rows>=n, "LSFitCreateWFG: rows(X)cols>=m, "LSFitCreateWFG: cols(X)protocolversion = 1; + state->formulatype = 0; + state->teststep = (double)(0); + state->diffstep = (double)(0); + state->npoints = n; + state->nweights = n; + state->wkind = 1; + state->m = m; + state->k = k; + lsfitsetcond(state, 0.0, 0, _state); + lsfitsetstpmax(state, 0.0, _state); + lsfitsetxrep(state, ae_false, _state); + ae_matrix_set_length(&state->taskx, n, m, _state); + ae_vector_set_length(&state->tasky, n, _state); + ae_vector_set_length(&state->taskw, n, _state); + ae_vector_set_length(&state->c, k, _state); + ae_vector_set_length(&state->c0, k, _state); + ae_vector_set_length(&state->c1, k, _state); + ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_vector_set_length(&state->x, m, _state); + ae_vector_set_length(&state->g, k, _state); + ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; + } + ae_vector_set_length(&state->s, k, _state); + ae_vector_set_length(&state->bndl, k, _state); + ae_vector_set_length(&state->bndu, k, _state); + for(i=0; i<=k-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + } + state->optalgo = 1; + state->prevnpt = -1; + state->prevalgo = -1; + state->nec = 0; + state->nic = 0; + state->nonmonotoniccnt = 0; + minlmcreatevj(k, n, &state->c0, &state->optstate, _state); + lsfit_lsfitclearrequestfields(state, _state); + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Nonlinear least squares fitting using gradient only, without individual +weights. + +Nonlinear task min(F(c)) is solved, where + + F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatefg(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + lsfitstate* state, + ae_state *_state) +{ + ae_int_t i; + + _lsfitstate_clear(state); + + ae_assert(n>=1, "LSFitCreateFG: N<1!", _state); + ae_assert(m>=1, "LSFitCreateFG: M<1!", _state); + ae_assert(k>=1, "LSFitCreateFG: K<1!", _state); + ae_assert(c->cnt>=k, "LSFitCreateFG: length(C)cnt>=n, "LSFitCreateFG: length(Y)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)rows>=n, "LSFitCreateFG: rows(X)cols>=m, "LSFitCreateFG: cols(X)protocolversion = 1; + state->formulatype = 0; + state->teststep = (double)(0); + state->diffstep = (double)(0); + state->npoints = n; + state->wkind = 0; + state->m = m; + state->k = k; + lsfitsetcond(state, 0.0, 0, _state); + lsfitsetstpmax(state, 0.0, _state); + lsfitsetxrep(state, ae_false, _state); + ae_matrix_set_length(&state->taskx, n, m, _state); + ae_vector_set_length(&state->tasky, n, _state); + ae_vector_set_length(&state->c, k, _state); + ae_vector_set_length(&state->c0, k, _state); + ae_vector_set_length(&state->c1, k, _state); + ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_vector_set_length(&state->x, m, _state); + ae_vector_set_length(&state->g, k, _state); + for(i=0; i<=n-1; i++) + { + ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->tasky.ptr.p_double[i] = y->ptr.p_double[i]; + } + ae_vector_set_length(&state->s, k, _state); + ae_vector_set_length(&state->bndl, k, _state); + ae_vector_set_length(&state->bndu, k, _state); + for(i=0; i<=k-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + } + state->optalgo = 1; + state->prevnpt = -1; + state->prevalgo = -1; + state->nec = 0; + state->nic = 0; + state->nonmonotoniccnt = 0; + minlmcreatevj(k, n, &state->c0, &state->optstate, _state); + lsfit_lsfitclearrequestfields(state, _state); + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LSFIT solver compares squared errors f[1] at the +trial point with the value at the current point f[0]. Only steps that +decrease f() are accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnonmonotonicsteps(lsfitstate* state, + ae_int_t cnt, + ae_state *_state) +{ + + + ae_assert(cnt>=0, "LSFitSetNonmonotonicSteps: incorrect AccType!", _state); + state->nonmonotoniccnt = cnt; +} + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers configured to use numerical differentiation; +in other cases it has no effect. + +INPUT PARAMETERS: + State - optimizer + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnumdiff(lsfitstate* state, + ae_int_t formulatype, + ae_state *_state) +{ + + + ae_assert(formulatype==2||formulatype==3, "LSFitSetNumDiff: unexpected formula type", _state); + state->formulatype = formulatype; +} + + +/************************************************************************* +Stopping conditions for nonlinear least squares fitting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by LSFitSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +NOTE + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (according to the scheme used by MINLM unit). + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetcond(lsfitstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "LSFitSetCond: EpsX is not finite!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LSFitSetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "LSFitSetCond: negative MaxIts!", _state); + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "LSFitSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +When reports are needed, State.C (current parameters) and State.F (current +value of fitting function) are reported. + + + -- ALGLIB -- + Copyright 15.08.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets scaling coefficients for underlying optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetscale(lsfitstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->k, "LSFitSetScale: Length(S)k-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "LSFitSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "LSFitSetScale: S contains infinite or NAN elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets boundary constraints for underlying optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[K]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[K]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unlike other constrained optimization algorithms, this solver has +following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetbc(lsfitstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + k = state->k; + ae_assert(bndl->cnt>=k, "LSFitSetBC: Length(BndL)cnt>=k, "LSFitSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "LSFitSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "LSFitSetBC: BndU contains NAN or -INF", _state); + if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "LSFitSetBC: BndL[i]>BndU[i]", _state); + } + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets linear constraints for underlying optimizer + +Linear constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetLC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with lsfitsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +NOTE: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 29.04.2017 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetlc(lsfitstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->k; + + /* + * First, check for errors in the inputs + */ + ae_assert(k>=0, "LSFitSetLC: K<0", _state); + ae_assert(c->cols>=n+1||k==0, "LSFitSetLC: Cols(C)rows>=k, "LSFitSetLC: Rows(C)cnt>=k, "LSFitSetLC: Length(CT)nec = 0; + state->nic = 0; + return; + } + + /* + * Equality constraints are stored first, in the upper + * NEC rows of State.CLEIC matrix. Inequality constraints + * are stored in the next NIC rows. + * + * NOTE: we convert inequality constraints to the form + * A*x<=b before copying them. + */ + rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); + state->nec = 0; + state->nic = 0; + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]==0 ) + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + state->nec = state->nec+1; + } + } + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]!=0 ) + { + if( ct->ptr.p_int[i]>0 ) + { + ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + else + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + state->nic = state->nic+1; + } + } +} + + +/************************************************************************* + +CALLBACK PARALLELISM: + +The LSFIT optimizer supports parallel model evaluation and parallel +numerical differentiation ('callback parallelism'). This feature, which is +present in commercial ALGLIB editions, greatly accelerates fits with large +datasets and/or expensive target functions. + +Callback parallelism is usually beneficial when a single pass over the +entire dataset requires more than several milliseconds. In this case the +job of computing model values at dataset points can be split between +multiple threads. + +If you employ a numerical differentiation scheme, you can also parallelize +computation of different components of a numerical gradient. Generally, the +mode computationally demanding your problem is (many points, numerical differentiation, +expensive model), the more you can get for multithreading. + +ALGLIB Reference Manual, 'Working with commercial version' section, +describes how to activate callback parallelism for your programming language. + +CALLBACK ARGUMENTS + +This algorithm is somewhat unusual because it works with parameterized +function f(C,X), where X is a function argument (we have many points +which are characterized by different argument values), and C is a +parameter to fit. + +For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then +x will be argument, and {c0,c1} will be parameters. + +It is important to understand that this algorithm finds minimum in the +space of function PARAMETERS (not arguments), so it needs derivatives +of f() with respect to C, not X. + +In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} +instead of {df/dx} = {c0}. + + -- ALGLIB -- + Copyright 17.12.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool lsfititeration(lsfitstate* state, ae_state *_state) +{ + double lx; + double lf; + double ld; + double rx; + double rf; + double rd; + ae_int_t n; + ae_int_t m; + ae_int_t k; + double v; + double vv; + double v1; + double v2; + double relcnt; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t offs; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + j = state->rstate.ia.ptr.p_int[4]; + j1 = state->rstate.ia.ptr.p_int[5]; + offs = state->rstate.ia.ptr.p_int[6]; + lx = state->rstate.ra.ptr.p_double[0]; + lf = state->rstate.ra.ptr.p_double[1]; + ld = state->rstate.ra.ptr.p_double[2]; + rx = state->rstate.ra.ptr.p_double[3]; + rf = state->rstate.ra.ptr.p_double[4]; + rd = state->rstate.ra.ptr.p_double[5]; + v = state->rstate.ra.ptr.p_double[6]; + vv = state->rstate.ra.ptr.p_double[7]; + v1 = state->rstate.ra.ptr.p_double[8]; + v2 = state->rstate.ra.ptr.p_double[9]; + relcnt = state->rstate.ra.ptr.p_double[10]; + } + else + { + n = 359; + m = -58; + k = -919; + i = -909; + j = 81; + j1 = 255; + offs = 74; + lx = -788.0; + lf = 809.0; + ld = 205.0; + rx = -838.0; + rf = 939.0; + rd = -526.0; + v = 763.0; + vv = -541.0; + v1 = -698.0; + v2 = -900.0; + relcnt = -318.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + if( state->rstate.stage==20 ) + { + goto lbl_20; + } + if( state->rstate.stage==21 ) + { + goto lbl_21; + } + if( state->rstate.stage==22 ) + { + goto lbl_22; + } + + /* + * Routine body + */ + + /* + * Init + */ + if( state->wkind==1 ) + { + ae_assert(state->npoints==state->nweights, "LSFitFit: number of points is not equal to the number of weights", _state); + } + state->repvaridx = -1; + n = state->npoints; + m = state->m; + k = state->k; + ivectorsetlengthatleast(&state->tmpct, state->nec+state->nic, _state); + for(i=0; i<=state->nec-1; i++) + { + state->tmpct.ptr.p_int[i] = 0; + } + for(i=0; i<=state->nic-1; i++) + { + state->tmpct.ptr.p_int[state->nec+i] = -1; + } + minlmsetcond(&state->optstate, state->epsx, state->maxits, _state); + minlmsetstpmax(&state->optstate, state->stpmax, _state); + minlmsetxrep(&state->optstate, state->xrep, _state); + minlmsetscale(&state->optstate, &state->s, _state); + minlmsetbc(&state->optstate, &state->bndl, &state->bndu, _state); + minlmsetlc(&state->optstate, &state->cleic, &state->tmpct, state->nec+state->nic, _state); + minlmsetnonmonotonicsteps(&state->optstate, state->nonmonotoniccnt, _state); + if( state->formulatype!=0 ) + { + minlmsetnumdiff(&state->optstate, state->formulatype, _state); + } + state->requesttype = 0; + + /* + * Allocate temporaries, as mandated by the V2 protocol + */ + if( state->protocolversion==2 ) + { + rallocm(1, k, &state->tmpj1, _state); + rallocv(1, &state->tmpf1, _state); + rallocv(k, &state->tmpg1, _state); + rallocv(k, &state->tmpx1, _state); + rallocv(m, &state->tmpc1, _state); + } + + /* + * Check that user-supplied gradient is correct + */ + if( state->protocolversion==1 ) + { + lsfit_lsfitclearrequestfields(state, _state); + } + if( !(ae_fp_greater(state->teststep,(double)(0))&&state->optalgo==1) ) + { + goto lbl_23; + } + for(i=0; i<=k-1; i++) + { + state->c.ptr.p_double[i] = state->c0.ptr.p_double[i]; + if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); + } + if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + } + i = 0; +lbl_25: + if( i>k-1 ) + { + goto lbl_27; + } + ae_assert(ae_fp_less_eq(state->bndl.ptr.p_double[i],state->c.ptr.p_double[i])&&ae_fp_less_eq(state->c.ptr.p_double[i],state->bndu.ptr.p_double[i]), "LSFitIteration: internal error(State.C is out of bounds)", _state); + if( state->protocolversion!=2 ) + { + goto lbl_28; + } + + /* + * Test using V2 protocol + */ + rallocv(k+m, &state->querydata, _state); + j = 0; +lbl_30: + if( j>n-1 ) + { + goto lbl_32; + } + + /* + * Query value at the left point + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rcopyv(k, &state->c, &state->querydata, _state); + state->querydata.ptr.p_double[i] = state->c.ptr.p_double[i]-state->teststep*state->s.ptr.p_double[i]; + if( ae_isfinite(state->bndl.ptr.p_double[i], _state)&&state->querydata.ptr.p_double[i]bndl.ptr.p_double[i] ) + { + state->querydata.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + lx = state->querydata.ptr.p_double[i]; + for(j1=0; j1<=m-1; j1++) + { + state->querydata.ptr.p_double[k+j1] = state->taskx.ptr.pp_double[j][j1]; + } + rallocv(1, &state->replyfi, _state); + rallocv(k, &state->replydj, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + lf = state->replyfi.ptr.p_double[0]; + ld = state->replydj.ptr.p_double[i]; + + /* + * Query value at the right point + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rcopyv(k, &state->c, &state->querydata, _state); + state->querydata.ptr.p_double[i] = state->c.ptr.p_double[i]+state->teststep*state->s.ptr.p_double[i]; + if( ae_isfinite(state->bndu.ptr.p_double[i], _state)&&state->querydata.ptr.p_double[i]>state->bndu.ptr.p_double[i] ) + { + state->querydata.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + rx = state->querydata.ptr.p_double[i]; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rf = state->replyfi.ptr.p_double[0]; + rd = state->replydj.ptr.p_double[i]; + + /* + * Query value at the middle, perform derivative check + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rcopyv(k, &state->c, &state->querydata, _state); + state->querydata.ptr.p_double[i] = (lx+rx)/(double)2; + if( ae_isfinite(state->bndl.ptr.p_double[i], _state)&&state->querydata.ptr.p_double[i]bndl.ptr.p_double[i] ) + { + state->querydata.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( ae_isfinite(state->bndu.ptr.p_double[i], _state)&&state->querydata.ptr.p_double[i]>state->bndu.ptr.p_double[i] ) + { + state->querydata.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfg = ae_false; + if( !derivativecheck(lf, ld, rf, rd, state->replyfi.ptr.p_double[0], state->replydj.ptr.p_double[i], rx-lx, _state) ) + { + state->repvaridx = i; + state->repterminationtype = -7; + result = ae_false; + return result; + } + j = j+1; + goto lbl_30; +lbl_32: + goto lbl_29; +lbl_28: + ae_assert(state->protocolversion==1, "LSFIT: integrity check 8428 failed", _state); + v = state->c.ptr.p_double[i]; + j = 0; +lbl_33: + if( j>n-1 ) + { + goto lbl_35; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[j][0], 1, ae_v_len(0,m-1)); + state->c.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; + if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); + } + lx = state->c.ptr.p_double[i]; + state->needfg = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfg = ae_false; + lf = state->f; + ld = state->g.ptr.p_double[i]; + state->c.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; + if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + rx = state->c.ptr.p_double[i]; + state->needfg = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfg = ae_false; + rf = state->f; + rd = state->g.ptr.p_double[i]; + state->c.ptr.p_double[i] = (lx+rx)/(double)2; + if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); + } + if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + state->needfg = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->needfg = ae_false; + state->c.ptr.p_double[i] = v; + if( !derivativecheck(lf, ld, rf, rd, state->f, state->g.ptr.p_double[i], rx-lx, _state) ) + { + state->repvaridx = i; + state->repterminationtype = -7; + result = ae_false; + return result; + } + j = j+1; + goto lbl_33; +lbl_35: +lbl_29: + i = i+1; + goto lbl_25; +lbl_27: +lbl_23: + + /* + * Fill WCur by weights: + * * for WKind=0 unit weights are chosen + * * for WKind=1 we use user-supplied weights stored in State.TaskW + */ + rvectorsetlengthatleast(&state->wcur, n, _state); + rallocv(n*k, &state->tmpwk, _state); + for(i=0; i<=n-1; i++) + { + state->wcur.ptr.p_double[i] = 1.0; + if( state->wkind==1 ) + { + state->wcur.ptr.p_double[i] = state->taskw.ptr.p_double[i]; + } + for(j=0; j<=k-1; j++) + { + state->tmpwk.ptr.p_double[i*k+j] = state->wcur.ptr.p_double[i]; + } + } + + /* + * Optimize + */ + if( state->protocolversion==1 ) + { + minlmsetprotocolv1(&state->optstate, _state); + } + else + { + ae_assert(state->protocolversion==2, "LSFIT: integrity check 2839 failed", _state); + minlmsetprotocolv2(&state->optstate, _state); + } +lbl_36: + if( !minlmiteration(&state->optstate, _state) ) + { + goto lbl_37; + } + if( state->protocolversion!=1 ) + { + goto lbl_38; + } + if( !state->optstate.needfi ) + { + goto lbl_40; + } + + /* + * calculate f[] = wi*(f(xi,c)-yi) + */ + i = 0; +lbl_42: + if( i>n-1 ) + { + goto lbl_44; + } + ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + lsfit_lsfitclearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->needf = ae_false; + vv = state->wcur.ptr.p_double[i]; + state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); + i = i+1; + goto lbl_42; +lbl_44: + goto lbl_36; +lbl_40: + if( !state->optstate.needf ) + { + goto lbl_45; + } + + /* + * calculate F = sum (wi*(f(xi,c)-yi))^2 + */ + state->optstate.f = (double)(0); + i = 0; +lbl_47: + if( i>n-1 ) + { + goto lbl_49; + } + ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + lsfit_lsfitclearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->needf = ae_false; + vv = state->wcur.ptr.p_double[i]; + state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); + i = i+1; + goto lbl_47; +lbl_49: + goto lbl_36; +lbl_45: + if( !state->optstate.needfg ) + { + goto lbl_50; + } + + /* + * calculate F/gradF + */ + state->optstate.f = (double)(0); + for(i=0; i<=k-1; i++) + { + state->optstate.g.ptr.p_double[i] = (double)(0); + } + i = 0; +lbl_52: + if( i>n-1 ) + { + goto lbl_54; + } + ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + lsfit_lsfitclearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->needfg = ae_false; + vv = state->wcur.ptr.p_double[i]; + state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state); + v = ae_sqr(vv, _state)*(double)2*(state->f-state->tasky.ptr.p_double[i]); + ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v); + i = i+1; + goto lbl_52; +lbl_54: + goto lbl_36; +lbl_50: + if( !state->optstate.needfij ) + { + goto lbl_55; + } + + /* + * calculate Fi/jac(Fi) + */ + i = 0; +lbl_57: + if( i>n-1 ) + { + goto lbl_59; + } + ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + lsfit_lsfitclearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->needfg = ae_false; + vv = state->wcur.ptr.p_double[i]; + state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]); + ae_v_moved(&state->optstate.j.ptr.pp_double[i][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), vv); + i = i+1; + goto lbl_57; +lbl_59: + goto lbl_36; +lbl_55: + if( !state->optstate.xupdated ) + { + goto lbl_60; + } + + /* + * Report new iteration + */ + ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1)); + state->f = state->optstate.f; + lsfit_lsfitclearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->xupdated = ae_false; + goto lbl_36; +lbl_60: +lbl_38: + if( state->protocolversion!=2 ) + { + goto lbl_62; + } + if( state->optstate.requesttype!=-1 ) + { + goto lbl_64; + } + + /* + * Report current point + */ + state->requesttype = -1; + state->queryvars = k; + state->reportf = state->optstate.reportf; + rcopyallocv(k, &state->optstate.reportx, &state->reportx, _state); + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + goto lbl_36; +lbl_64: + if( state->optstate.requesttype!=2 ) + { + goto lbl_66; + } + + /* + * Request a batch of dense derivatives, repack request by MinLM (one query for N + * functions) to the format used by LSFit (N single-function queries) + */ + ae_assert(state->optstate.querysize==1, "LSFIT: integrity check 5248 failed", _state); + ae_assert(state->optstate.queryfuncs==n, "LSFIT: integrity check 5249 failed", _state); + ae_assert(state->optstate.queryvars==k, "LSFIT: integrity check 5250 failed", _state); + ae_assert(state->optstate.querydim==0, "LSFIT: integrity check 5251 failed", _state); + state->requesttype = 2; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rallocv(n*(k+m), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->optstate.querydata.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + } + rallocv(n, &state->replyfi, _state); + rallocv(n*k, &state->replydj, _state); + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + + /* + * Handle reply: replace f by weight*(f-y), scale gradient + */ + state->optstate.requesttype = 0; + rcopyv(n, &state->replyfi, &state->optstate.replyfi, _state); + raddv(n, -1.0, &state->tasky, &state->optstate.replyfi, _state); + rmergemulv(n, &state->wcur, &state->optstate.replyfi, _state); + rcopyv(n*k, &state->replydj, &state->optstate.replydj, _state); + rmergemulv(n*k, &state->tmpwk, &state->optstate.replydj, _state); + goto lbl_36; +lbl_66: + if( state->optstate.requesttype!=3 ) + { + goto lbl_68; + } + + /* + * Numerical differentiation request: repack request by MinLM (one query for N + * functions) to the format used by LSFit (N single-function queries) + */ + ae_assert(state->optstate.querysize==1, "LSFIT: integrity check 3348 failed", _state); + ae_assert(state->optstate.queryfuncs==n, "LSFIT: integrity check 3349 failed", _state); + ae_assert(state->optstate.queryvars==k, "LSFIT: integrity check 3350 failed", _state); + ae_assert(state->optstate.querydim==0, "LSFIT: integrity check 3351 failed", _state); + ae_assert(state->optstate.queryformulasize>=2, "LSFIT: integrity check 3352 failed", _state); + state->requesttype = 3; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + state->queryformulasize = state->optstate.queryformulasize; + rallocv(n*(k+m+k*2*state->queryformulasize), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->optstate.querydata.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + for(j=0; j<=k*2*state->queryformulasize-1; j++) + { + state->querydata.ptr.p_double[offs] = state->optstate.querydata.ptr.p_double[k+j]; + offs = offs+1; + } + } + rallocv(n, &state->replyfi, _state); + rallocv(n*k, &state->replydj, _state); + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + + /* + * Handle reply: replace f by weight*(f-y), scale gradient + */ + state->optstate.requesttype = 0; + rcopyv(n, &state->replyfi, &state->optstate.replyfi, _state); + raddv(n, -1.0, &state->tasky, &state->optstate.replyfi, _state); + rmergemulv(n, &state->wcur, &state->optstate.replyfi, _state); + rcopyv(n*k, &state->replydj, &state->optstate.replydj, _state); + rmergemulv(n*k, &state->tmpwk, &state->optstate.replydj, _state); + goto lbl_36; +lbl_68: + if( state->optstate.requesttype!=4 ) + { + goto lbl_70; + } + + /* + * Request a batch of target values, repack request by MinLM (one query for N + * functions) to the format used by LSFit (N single-function queries) + */ + ae_assert(state->optstate.querysize==1, "LSFIT: integrity check 5248 failed", _state); + ae_assert(state->optstate.queryfuncs==n, "LSFIT: integrity check 5249 failed", _state); + ae_assert(state->optstate.queryvars==k, "LSFIT: integrity check 5250 failed", _state); + ae_assert(state->optstate.querydim==0, "LSFIT: integrity check 5251 failed", _state); + state->requesttype = 4; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rallocv(n*(k+m), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->optstate.querydata.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + } + rallocv(n, &state->replyfi, _state); + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->optstate.requesttype = 0; + rcopyv(n, &state->replyfi, &state->optstate.replyfi, _state); + raddv(n, -1.0, &state->tasky, &state->optstate.replyfi, _state); + rmergemulv(n, &state->wcur, &state->optstate.replyfi, _state); + goto lbl_36; +lbl_70: +lbl_62: + ae_assert(ae_false, "LSFIT: integrity check 2012 failed (unexpected request)", _state); + goto lbl_36; +lbl_37: + + /* + * Extract results + * + * NOTE: reverse communication protocol used by this unit does NOT + * allow us to reallocate State.C[] array. Thus, we extract + * results to the temporary variable in order to avoid possible + * reallocation. + */ + minlmresults(&state->optstate, &state->c1, &state->optrep, _state); + state->repterminationtype = state->optrep.terminationtype; + state->repiterationscount = state->optrep.iterationscount; + + /* + * calculate errors + */ + if( state->repterminationtype<=0 ) + { + goto lbl_72; + } + + /* + * Calculate RMS/Avg/Max/... errors + */ + state->reprmserror = (double)(0); + state->repwrmserror = (double)(0); + state->repavgerror = (double)(0); + state->repavgrelerror = (double)(0); + state->repmaxerror = (double)(0); + if( state->protocolversion!=1 ) + { + goto lbl_74; + } + + /* + * Get target values using V1 protocol, load them to ReplyFi (it is not used anyway) + */ + rallocv(n, &state->replyfi, _state); + i = 0; +lbl_76: + if( i>n-1 ) + { + goto lbl_78; + } + ae_v_move(&state->c.ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,k-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + lsfit_lsfitclearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->needf = ae_false; + state->replyfi.ptr.p_double[i] = state->f; + i = i+1; + goto lbl_76; +lbl_78: + goto lbl_75; +lbl_74: + + /* + * Get target values using V2 protocol + */ + ae_assert(state->protocolversion==2, "LSFIT: integrity check 7320 failed", _state); + state->requesttype = 4; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rallocv(n*(k+m), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->c1.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + } + rallocv(n, &state->replyfi, _state); + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: +lbl_75: + relcnt = (double)(0); + for(i=0; i<=n-1; i++) + { + v = state->replyfi.ptr.p_double[i]; + vv = state->wcur.ptr.p_double[i]; + state->reprmserror = state->reprmserror+ae_sqr(v-state->tasky.ptr.p_double[i], _state); + state->repwrmserror = state->repwrmserror+ae_sqr(vv*(v-state->tasky.ptr.p_double[i]), _state); + state->repavgerror = state->repavgerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state); + if( ae_fp_neq(state->tasky.ptr.p_double[i],(double)(0)) ) + { + state->repavgrelerror = state->repavgrelerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state)/ae_fabs(state->tasky.ptr.p_double[i], _state); + relcnt = relcnt+(double)1; + } + state->repmaxerror = ae_maxreal(state->repmaxerror, ae_fabs(v-state->tasky.ptr.p_double[i], _state), _state); + } + state->reprmserror = ae_sqrt(state->reprmserror/(double)n, _state); + state->repwrmserror = ae_sqrt(state->repwrmserror/(double)n, _state); + state->repavgerror = state->repavgerror/(double)n; + if( ae_fp_neq(relcnt,(double)(0)) ) + { + state->repavgrelerror = state->repavgrelerror/relcnt; + } + + /* + * Calculate covariance matrix + */ + rmatrixsetlengthatleast(&state->tmpjac, n, k, _state); + rvectorsetlengthatleast(&state->tmpf, n, _state); + rvectorsetlengthatleast(&state->tmp, k, _state); + if( ae_fp_less_eq(state->diffstep,(double)(0)) ) + { + goto lbl_79; + } + + /* + * Compute Jacobian by means of numerical differentiation + */ + if( state->protocolversion!=1 ) + { + goto lbl_81; + } + + /* + * Use V1 protocol + */ + lsfit_lsfitclearrequestfields(state, _state); + state->needf = ae_true; + i = 0; +lbl_83: + if( i>n-1 ) + { + goto lbl_85; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->tmpf.ptr.p_double[i] = state->f; + j = 0; +lbl_86: + if( j>k-1 ) + { + goto lbl_88; + } + v = state->c.ptr.p_double[j]; + lx = v-state->diffstep*state->s.ptr.p_double[j]; + state->c.ptr.p_double[j] = lx; + if( ae_isfinite(state->bndl.ptr.p_double[j], _state) ) + { + state->c.ptr.p_double[j] = ae_maxreal(state->c.ptr.p_double[j], state->bndl.ptr.p_double[j], _state); + } + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + lf = state->f; + rx = v+state->diffstep*state->s.ptr.p_double[j]; + state->c.ptr.p_double[j] = rx; + if( ae_isfinite(state->bndu.ptr.p_double[j], _state) ) + { + state->c.ptr.p_double[j] = ae_minreal(state->c.ptr.p_double[j], state->bndu.ptr.p_double[j], _state); + } + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + rf = state->f; + state->c.ptr.p_double[j] = v; + if( ae_fp_neq(rx,lx) ) + { + state->tmpjac.ptr.pp_double[i][j] = (rf-lf)/(rx-lx); + } + else + { + state->tmpjac.ptr.pp_double[i][j] = (double)(0); + } + j = j+1; + goto lbl_86; +lbl_88: + i = i+1; + goto lbl_83; +lbl_85: + state->needf = ae_false; + goto lbl_82; +lbl_81: + + /* + * Use V2 protocol + */ + state->requesttype = 3; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + state->queryformulasize = 2; + rallocv(n*(k+m+k*2*state->queryformulasize), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->c1.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + for(j=0; j<=k-1; j++) + { + + /* + * We guard X[J] from leaving [BndL,BndU]. + * In case BndL=BndU, we assume that derivative in this direction is zero. + */ + v = state->diffstep*state->s.ptr.p_double[j]; + v1 = state->c1.ptr.p_double[j]-v; + if( ae_isfinite(state->bndl.ptr.p_double[j], _state)&&v1bndl.ptr.p_double[j] ) + { + v1 = state->bndl.ptr.p_double[j]; + } + v2 = state->c1.ptr.p_double[j]+v; + if( ae_isfinite(state->bndu.ptr.p_double[j], _state)&&v2>state->bndu.ptr.p_double[j] ) + { + v2 = state->bndu.ptr.p_double[j]; + } + v = (double)(0); + if( v1querydata.ptr.p_double[offs+0*2+0] = v1; + state->querydata.ptr.p_double[offs+0*2+1] = -v; + state->querydata.ptr.p_double[offs+1*2+0] = v2; + state->querydata.ptr.p_double[offs+1*2+1] = v; + offs = offs+2*state->queryformulasize; + } + } + rallocv(n, &state->replyfi, _state); + rallocv(n*k, &state->replydj, _state); + state->rstate.stage = 20; + goto lbl_rcomm; +lbl_20: + rcopyv(n, &state->replyfi, &state->tmpf, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->tmpjac.ptr.pp_double[i][j] = state->replydj.ptr.p_double[i*k+j]; + } + } +lbl_82: + goto lbl_80; +lbl_79: + + /* + * Jacobian is calculated with user-provided analytic gradient + */ + if( state->protocolversion!=1 ) + { + goto lbl_89; + } + + /* + * Use V1 protocol + */ + lsfit_lsfitclearrequestfields(state, _state); + state->needfg = ae_true; + i = 0; +lbl_91: + if( i>n-1 ) + { + goto lbl_93; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1)); + state->pointindex = i; + state->rstate.stage = 21; + goto lbl_rcomm; +lbl_21: + state->tmpf.ptr.p_double[i] = state->f; + for(j=0; j<=k-1; j++) + { + state->tmpjac.ptr.pp_double[i][j] = state->g.ptr.p_double[j]; + } + i = i+1; + goto lbl_91; +lbl_93: + state->needfg = ae_false; + goto lbl_90; +lbl_89: + + /* + * Use V2 protocol + */ + ae_assert(state->protocolversion==2, "LSFIT: integrity check 7321 failed", _state); + state->requesttype = 2; + state->querysize = n; + state->queryfuncs = 1; + state->queryvars = k; + state->querydim = m; + rallocv(n*(k+m), &state->querydata, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->querydata.ptr.p_double[offs] = state->c1.ptr.p_double[j]; + offs = offs+1; + } + for(j=0; j<=m-1; j++) + { + state->querydata.ptr.p_double[offs] = state->taskx.ptr.pp_double[i][j]; + offs = offs+1; + } + } + rallocv(n, &state->replyfi, _state); + rallocv(n*k, &state->replydj, _state); + state->rstate.stage = 22; + goto lbl_rcomm; +lbl_22: + rcopyv(n, &state->replyfi, &state->tmpf, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + state->tmpjac.ptr.pp_double[i][j] = state->replydj.ptr.p_double[i*k+j]; + } + } +lbl_90: +lbl_80: + for(i=0; i<=k-1; i++) + { + state->tmp.ptr.p_double[i] = 0.0; + } + lsfit_estimateerrors(&state->tmpjac, &state->tmpf, &state->tasky, &state->wcur, &state->tmp, &state->s, n, k, &state->rep, &state->tmpjacw, 0, _state); +lbl_72: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = k; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = j; + state->rstate.ia.ptr.p_int[5] = j1; + state->rstate.ia.ptr.p_int[6] = offs; + state->rstate.ra.ptr.p_double[0] = lx; + state->rstate.ra.ptr.p_double[1] = lf; + state->rstate.ra.ptr.p_double[2] = ld; + state->rstate.ra.ptr.p_double[3] = rx; + state->rstate.ra.ptr.p_double[4] = rf; + state->rstate.ra.ptr.p_double[5] = rd; + state->rstate.ra.ptr.p_double[6] = v; + state->rstate.ra.ptr.p_double[7] = vv; + state->rstate.ra.ptr.p_double[8] = v1; + state->rstate.ra.ptr.p_double[9] = v2; + state->rstate.ra.ptr.p_double[10] = relcnt; + return result; +} + + +/************************************************************************* +Nonlinear least squares fitting results. + +Called after return from LSFitFit(). + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + C - array[K], solution + Rep - optimization report. On success following fields are set: + * TerminationType completion code: + * -8 optimizer detected NAN/INF in the target + function and/or gradient + * -7 gradient verification failed. + See LSFitSetGradientCheck() for more information. + * -3 inconsistent constraints + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + * WRMSError weighted rms error on the (X,Y). + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(J*CovPar*J')), + where J is Jacobian matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitresults(const lsfitstate* state, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_vector_clear(c); + _lsfitreport_clear(rep); + + lsfit_clearreport(rep, _state); + rep->terminationtype = state->repterminationtype; + rep->varidx = state->repvaridx; + if( rep->terminationtype>0 ) + { + ae_vector_set_length(c, state->k, _state); + ae_v_move(&c->ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,state->k-1)); + rep->rmserror = state->reprmserror; + rep->wrmserror = state->repwrmserror; + rep->avgerror = state->repavgerror; + rep->avgrelerror = state->repavgrelerror; + rep->maxerror = state->repmaxerror; + rep->iterationscount = state->repiterationscount; + ae_matrix_set_length(&rep->covpar, state->k, state->k, _state); + ae_vector_set_length(&rep->errpar, state->k, _state); + ae_vector_set_length(&rep->errcurve, state->npoints, _state); + ae_vector_set_length(&rep->noise, state->npoints, _state); + rep->r2 = state->rep.r2; + for(i=0; i<=state->k-1; i++) + { + for(j=0; j<=state->k-1; j++) + { + rep->covpar.ptr.pp_double[i][j] = state->rep.covpar.ptr.pp_double[i][j]; + } + rep->errpar.ptr.p_double[i] = state->rep.errpar.ptr.p_double[i]; + } + for(i=0; i<=state->npoints-1; i++) + { + rep->errcurve.ptr.p_double[i] = state->rep.errcurve.ptr.p_double[i]; + rep->noise.ptr.p_double[i] = state->rep.noise.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This subroutine turns on verification of the user-supplied analytic +gradient: +* user calls this subroutine before fitting begins +* LSFitFit() is called +* prior to actual fitting, for each point in data set X_i and each + component of parameters being fited C_j algorithm performs following + steps: + * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], + where C_j is j-th parameter and S[j] is a scale of j-th parameter + * if needed, steps are bounded with respect to constraints on C[] + * F(X_i|C) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + * in case difference between prediction and actual value is higher than + some predetermined threshold, algorithm stops with completion code -7; + Rep.VarIdx is set to index of the parameter with incorrect derivative. +* after verification is over, algorithm proceeds to the actual optimization. + +NOTE 1: verification needs N*K (points count * parameters count) gradient + evaluations. It is very costly and you should use it only for low + dimensional problems, when you want to be sure that you've + correctly calculated analytic derivatives. You should not use it + in the production code (unless you want to check derivatives + provided by some third party). + +NOTE 2: you should carefully choose TestStep. Value which is too large + (so large that function behaviour is significantly non-cubic) will + lead to false alarms. You may use different step for different + parameters by means of setting scale with LSFitSetScale(). + +NOTE 3: this function may lead to false positives. In case it reports that + I-th derivative was calculated incorrectly, you may decrease test + step and try one more time - maybe your function changes too + sharply and your step is too large for such rapidly chanding + function. + +NOTE 4: this function works only for optimizers created with LSFitCreateWFG() + or LSFitCreateFG() constructors. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step: + * TestStep=0 turns verification off + * TestStep>0 activates verification + + -- ALGLIB -- + Copyright 15.06.2012 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetgradientcheck(lsfitstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "LSFitSetGradientCheck: TestStep contains NaN or Infinite", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void lsfitsetprotocolv1(lsfitstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol +*************************************************************************/ +void lsfitsetprotocolv2(lsfitstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function analyzes section of curve for processing by RDP algorithm: +given set of points X,Y with indexes [I0,I1] it returns point with +worst deviation from linear model (non-parametric version which sees curve +as Y(x)). + +Input parameters: + X, Y - SORTED arrays. + I0,I1 - interval (boundaries included) to process + Eps - desired precision + +OUTPUT PARAMETERS: + WorstIdx - index of worst point + WorstError - error at worst point + +NOTE: this function guarantees that it returns exactly zero for a section + with less than 3 points. + + -- ALGLIB PROJECT -- + Copyright 02.10.2014 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_rdpanalyzesection(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t i0, + ae_int_t i1, + ae_int_t* worstidx, + double* worsterror, + ae_state *_state) +{ + ae_int_t i; + double xleft; + double xright; + double vx; + double ve; + double a; + double b; + + *worstidx = 0; + *worsterror = 0.0; + + xleft = x->ptr.p_double[i0]; + xright = x->ptr.p_double[i1]; + if( i1-i0+1<3||ae_fp_eq(xright,xleft) ) + { + *worstidx = i0; + *worsterror = 0.0; + return; + } + a = (y->ptr.p_double[i1]-y->ptr.p_double[i0])/(xright-xleft); + b = (y->ptr.p_double[i0]*xright-y->ptr.p_double[i1]*xleft)/(xright-xleft); + *worstidx = -1; + *worsterror = (double)(0); + for(i=i0+1; i<=i1-1; i++) + { + vx = x->ptr.p_double[i]; + ve = ae_fabs(a*vx+b-y->ptr.p_double[i], _state); + if( (ae_fp_greater(vx,xleft)&&ae_fp_less(vx,xright))&&ae_fp_greater(ve,*worsterror) ) + { + *worsterror = ve; + *worstidx = i; + } + } +} + + +/************************************************************************* +Recursive splitting of interval [I0,I1] (right boundary included) with RDP +algorithm (non-parametric version which sees curve as Y(x)). + +Input parameters: + X, Y - SORTED arrays. + I0,I1 - interval (boundaries included) to process + Eps - desired precision + XOut,YOut - preallocated output arrays large enough to store result; + XOut[0..1], YOut[0..1] contain first and last points of + curve + NOut - must contain 2 on input + +OUTPUT PARAMETERS: + XOut, YOut - curve generated by RDP algorithm, UNSORTED + NOut - number of points in curve + + -- ALGLIB PROJECT -- + Copyright 02.10.2014 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_rdprecursive(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t i0, + ae_int_t i1, + double eps, + /* Real */ ae_vector* xout, + /* Real */ ae_vector* yout, + ae_int_t* nout, + ae_state *_state) +{ + ae_int_t worstidx; + double worsterror; + + + ae_assert(ae_fp_greater(eps,(double)(0)), "RDPRecursive: internal error, Eps<0", _state); + lsfit_rdpanalyzesection(x, y, i0, i1, &worstidx, &worsterror, _state); + if( ae_fp_less_eq(worsterror,eps) ) + { + return; + } + xout->ptr.p_double[*nout] = x->ptr.p_double[worstidx]; + yout->ptr.p_double[*nout] = y->ptr.p_double[worstidx]; + *nout = *nout+1; + if( worstidx-i0x.ptr.p_double[0]; + tb = state->x.ptr.p_double[1]; + tc = state->x.ptr.p_double[2]; + td = state->x.ptr.p_double[3]; + tg = state->x.ptr.p_double[4]; + if( state->xupdated ) + { + + /* + * Save best function value obtained so far. + */ + *flast = state->f; + continue; + } + if( state->needfi||state->needfij ) + { + + /* + * Function vector and Jacobian + */ + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)), "LogisticFitInternal: integrity error", _state); + + /* + * Handle zero X + */ + if( ae_fp_eq(x->ptr.p_double[i],(double)(0)) ) + { + if( ae_fp_greater_eq(tb,(double)(0)) ) + { + + /* + * Positive or zero TB, limit X^TB subject to X->+0 is equal to zero. + */ + state->fi.ptr.p_double[i] = ta-y->ptr.p_double[i]; + if( state->needfij ) + { + state->j.ptr.pp_double[i][0] = (double)(1); + state->j.ptr.pp_double[i][1] = (double)(0); + state->j.ptr.pp_double[i][2] = (double)(0); + state->j.ptr.pp_double[i][3] = (double)(0); + state->j.ptr.pp_double[i][4] = (double)(0); + } + } + else + { + + /* + * Negative TB, limit X^TB subject to X->+0 is equal to +INF. + */ + state->fi.ptr.p_double[i] = td-y->ptr.p_double[i]; + if( state->needfij ) + { + state->j.ptr.pp_double[i][0] = (double)(0); + state->j.ptr.pp_double[i][1] = (double)(0); + state->j.ptr.pp_double[i][2] = (double)(0); + state->j.ptr.pp_double[i][3] = (double)(1); + state->j.ptr.pp_double[i][4] = (double)(0); + } + } + continue; + } + + /* + * Positive X. + * Prepare VP0/VP1, it may become infinite or nearly overflow in some rare cases, + * handle these cases + */ + vp0 = ae_pow(x->ptr.p_double[i]/tc, tb, _state); + if( is4pl ) + { + vp1 = (double)1+vp0; + } + else + { + vp1 = ae_pow((double)1+vp0, tg, _state); + } + if( (!ae_isfinite(vp1, _state)||ae_fp_greater(vp0,1.0E50))||ae_fp_greater(vp1,1.0E50) ) + { + + /* + * VP0/VP1 are not finite, assume that it is +INF or -INF + */ + state->fi.ptr.p_double[i] = td-y->ptr.p_double[i]; + if( state->needfij ) + { + state->j.ptr.pp_double[i][0] = (double)(0); + state->j.ptr.pp_double[i][1] = (double)(0); + state->j.ptr.pp_double[i][2] = (double)(0); + state->j.ptr.pp_double[i][3] = (double)(1); + state->j.ptr.pp_double[i][4] = (double)(0); + } + continue; + } + + /* + * VP0/VP1 are finite, normal processing + */ + if( is4pl ) + { + state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i]; + if( state->needfij ) + { + state->j.ptr.pp_double[i][0] = (double)1/vp1; + state->j.ptr.pp_double[i][1] = -(ta-td)*vp0*ae_log(x->ptr.p_double[i]/tc, _state)/ae_sqr(vp1, _state); + state->j.ptr.pp_double[i][2] = (ta-td)*(tb/tc)*vp0/ae_sqr(vp1, _state); + state->j.ptr.pp_double[i][3] = (double)1-(double)1/vp1; + state->j.ptr.pp_double[i][4] = (double)(0); + } + } + else + { + state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i]; + if( state->needfij ) + { + state->j.ptr.pp_double[i][0] = (double)1/vp1; + state->j.ptr.pp_double[i][1] = (ta-td)*(-tg)*ae_pow((double)1+vp0, -tg-(double)1, _state)*vp0*ae_log(x->ptr.p_double[i]/tc, _state); + state->j.ptr.pp_double[i][2] = (ta-td)*(-tg)*ae_pow((double)1+vp0, -tg-(double)1, _state)*vp0*(-tb/tc); + state->j.ptr.pp_double[i][3] = (double)1-(double)1/vp1; + state->j.ptr.pp_double[i][4] = -(ta-td)/vp1*ae_log((double)1+vp0, _state); + } + } + } + + /* + * Add regularizer + */ + for(i=0; i<=4; i++) + { + state->fi.ptr.p_double[n+i] = lambdav*state->x.ptr.p_double[i]; + if( state->needfij ) + { + for(j=0; j<=4; j++) + { + state->j.ptr.pp_double[n+i][j] = 0.0; + } + state->j.ptr.pp_double[n+i][i] = lambdav; + } + } + + /* + * Done + */ + continue; + } + ae_assert(ae_false, "LogisticFitX: internal error", _state); + } + minlmresultsbuf(state, p1, replm, _state); + ae_assert(replm->terminationtype>0, "LogisticFitX: internal error", _state); +} + + +/************************************************************************* +Calculate errors for 4PL/5PL fit. +Leaves other fields of Rep unchanged, so caller should properly initialize +it with ClearRep() call. + + -- ALGLIB PROJECT -- + Copyright 28.04.2017 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_logisticfit45errors(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + double a, + double b, + double c, + double d, + double g, + lsfitreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double v; + double rss; + double tss; + double meany; + + + + /* + * Calculate errors + */ + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->maxerror = (double)(0); + k = 0; + rss = 0.0; + tss = 0.0; + meany = 0.0; + for(i=0; i<=n-1; i++) + { + meany = meany+y->ptr.p_double[i]; + } + meany = meany/(double)n; + for(i=0; i<=n-1; i++) + { + + /* + * Calculate residual from regression + */ + if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) + { + v = d+(a-d)/ae_pow(1.0+ae_pow(x->ptr.p_double[i]/c, b, _state), g, _state)-y->ptr.p_double[i]; + } + else + { + if( ae_fp_greater_eq(b,(double)(0)) ) + { + v = a-y->ptr.p_double[i]; + } + else + { + v = d-y->ptr.p_double[i]; + } + } + + /* + * Update RSS (residual sum of squares) and TSS (total sum of squares) + * which are used to calculate coefficient of determination. + * + * NOTE: we use formula R2 = 1-RSS/TSS because it has nice property of + * being equal to 0.0 if and only if model perfectly fits data. + * + * When we fit nonlinear models, there are exist multiple ways of + * determining R2, each of them giving different results. Formula + * above is the most intuitive one. + */ + rss = rss+v*v; + tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state); + + /* + * Update errors + */ + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state); + k = k+1; + } + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)n, _state); + rep->avgerror = rep->avgerror/(double)n; + if( k>0 ) + { + rep->avgrelerror = rep->avgrelerror/(double)k; + } + rep->r2 = 1.0-rss/tss; +} + + +/************************************************************************* +Internal spline fitting subroutine + + -- ALGLIB PROJECT -- + Copyright 08.09.2009 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_spline1dfitinternal(ae_int_t st, + /* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector w; + ae_vector xc; + ae_vector yc; + ae_matrix fmatrix; + ae_matrix cmatrix; + ae_vector y2; + ae_vector w2; + ae_vector sx; + ae_vector sy; + ae_vector sd; + ae_vector tmp; + ae_vector xoriginal; + ae_vector yoriginal; + lsfitreport lrep; + double v0; + double v1; + double v2; + double mx; + spline1dinterpolant s2; + ae_int_t i; + ae_int_t j; + ae_int_t relcnt; + double xa; + double xb; + double sa; + double sb; + double bl; + double br; + double decay; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&fmatrix, 0, sizeof(fmatrix)); + memset(&cmatrix, 0, sizeof(cmatrix)); + memset(&y2, 0, sizeof(y2)); + memset(&w2, 0, sizeof(w2)); + memset(&sx, 0, sizeof(sx)); + memset(&sy, 0, sizeof(sy)); + memset(&sd, 0, sizeof(sd)); + memset(&tmp, 0, sizeof(tmp)); + memset(&xoriginal, 0, sizeof(xoriginal)); + memset(&yoriginal, 0, sizeof(yoriginal)); + memset(&lrep, 0, sizeof(lrep)); + memset(&s2, 0, sizeof(s2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&w, _w, _state, ae_true); + ae_vector_init_copy(&xc, _xc, _state, ae_true); + ae_vector_init_copy(&yc, _yc, _state, ae_true); + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sd, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); + _lsfitreport_init(&lrep, _state, ae_true); + _spline1dinterpolant_init(&s2, _state, ae_true); + + ae_assert(st==0||st==1, "Spline1DFit: internal error!", _state); + if( st==0&&m<4 ) + { + ae_assert(ae_false, "LSFIT: integrity check 5729 failed", _state); + ae_frame_leave(_state); + return; + } + if( st==1&&m<4 ) + { + ae_assert(ae_false, "LSFIT: integrity check 6229 failed", _state); + ae_frame_leave(_state); + return; + } + if( (n<1||k<0)||k>=m ) + { + ae_assert(ae_false, "LSFIT: integrity check 6729 failed", _state); + ae_frame_leave(_state); + return; + } + for(i=0; i<=k-1; i++) + { + if( dc->ptr.p_int[i]<0 ) + { + ae_assert(ae_false, "LSFIT: integrity check 7329 failed", _state); + } + if( dc->ptr.p_int[i]>1 ) + { + ae_assert(ae_false, "LSFIT: integrity check 7529 failed", _state); + } + } + if( st==1&&m%2!=0 ) + { + + /* + * Hermite fitter must have even number of basis functions + */ + ae_assert(ae_false, "LSFIT: integrity check 8229 failed", _state); + ae_frame_leave(_state); + return; + } + + /* + * weight decay for correct handling of task which becomes + * degenerate after constraints are applied + */ + decay = (double)10000*ae_machineepsilon; + + /* + * Scale X, Y, XC, YC + */ + lsfitscalexy(&x, &y, &w, n, &xc, &yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); + + /* + * allocate space, initialize: + * * SX - grid for basis functions + * * SY - values of basis functions at grid points + * * FMatrix- values of basis functions at X[] + * * CMatrix- values (derivatives) of basis functions at XC[] + */ + ae_vector_set_length(&y2, n+m, _state); + ae_vector_set_length(&w2, n+m, _state); + ae_matrix_set_length(&fmatrix, n+m, m, _state); + if( k>0 ) + { + ae_matrix_set_length(&cmatrix, k, m+1, _state); + } + if( st==0 ) + { + + /* + * allocate space for cubic spline + */ + ae_vector_set_length(&sx, m-2, _state); + ae_vector_set_length(&sy, m-2, _state); + for(j=0; j<=m-2-1; j++) + { + sx.ptr.p_double[j] = (double)(2*j)/(double)(m-2-1)-(double)1; + } + } + if( st==1 ) + { + + /* + * allocate space for Hermite spline + */ + ae_vector_set_length(&sx, m/2, _state); + ae_vector_set_length(&sy, m/2, _state); + ae_vector_set_length(&sd, m/2, _state); + for(j=0; j<=m/2-1; j++) + { + sx.ptr.p_double[j] = (double)(2*j)/(double)(m/2-1)-(double)1; + } + } + + /* + * Prepare design and constraints matrices: + * * fill constraints matrix + * * fill first N rows of design matrix with values + * * fill next M rows of design matrix with regularizing term + * * append M zeros to Y + * * append M elements, mean(abs(W)) each, to W + */ + for(j=0; j<=m-1; j++) + { + + /* + * prepare Jth basis function + */ + if( st==0 ) + { + + /* + * cubic spline basis + */ + for(i=0; i<=m-2-1; i++) + { + sy.ptr.p_double[i] = (double)(0); + } + bl = (double)(0); + br = (double)(0); + if( jptr.p_int[i]>=0&&dc->ptr.p_int[i]<=2, "Spline1DFit: internal error!", _state); + spline1ddiff(&s2, xc.ptr.p_double[i], &v0, &v1, &v2, _state); + if( dc->ptr.p_int[i]==0 ) + { + cmatrix.ptr.pp_double[i][j] = v0; + } + if( dc->ptr.p_int[i]==1 ) + { + cmatrix.ptr.pp_double[i][j] = v1; + } + if( dc->ptr.p_int[i]==2 ) + { + cmatrix.ptr.pp_double[i][j] = v2; + } + } + } + for(i=0; i<=k-1; i++) + { + cmatrix.ptr.pp_double[i][m] = yc.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + for(j=0; j<=m-1; j++) + { + if( i==j ) + { + fmatrix.ptr.pp_double[n+i][j] = decay; + } + else + { + fmatrix.ptr.pp_double[n+i][j] = (double)(0); + } + } + } + ae_vector_set_length(&y2, n+m, _state); + ae_vector_set_length(&w2, n+m, _state); + ae_v_move(&y2.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&w2.ptr.p_double[0], 1, &w.ptr.p_double[0], 1, ae_v_len(0,n-1)); + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + mx = mx+ae_fabs(w.ptr.p_double[i], _state); + } + mx = mx/(double)n; + for(i=0; i<=m-1; i++) + { + y2.ptr.p_double[n+i] = (double)(0); + w2.ptr.p_double[n+i] = mx; + } + + /* + * Solve constrained task + */ + if( k>0 ) + { + + /* + * solve using regularization + */ + lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, &tmp, &lrep, _state); + } + else + { + + /* + * no constraints, no regularization needed + */ + lsfitlinearwc(&y, &w, &fmatrix, &cmatrix, n, m, k, &tmp, &lrep, _state); + } + rep->terminationtype = lrep.terminationtype; + if( rep->terminationtype<0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Generate spline and scale it + */ + if( st==0 ) + { + + /* + * cubic spline basis + */ + ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-2-1)); + spline1dbuildcubic(&sx, &sy, m-2, 1, tmp.ptr.p_double[m-2], 1, tmp.ptr.p_double[m-1], s, _state); + } + if( st==1 ) + { + + /* + * Hermite basis + */ + for(i=0; i<=m/2-1; i++) + { + sy.ptr.p_double[i] = tmp.ptr.p_double[2*i]; + sd.ptr.p_double[i] = tmp.ptr.p_double[2*i+1]; + } + spline1dbuildhermite(&sx, &sy, &sd, m/2, s, _state); + } + spline1dlintransx(s, (double)2/(xb-xa), -(xa+xb)/(xb-xa), _state); + spline1dlintransy(s, sb-sa, sa, _state); + + /* + * Scale absolute errors obtained from LSFitLinearW. + * Relative error should be calculated separately + * (because of shifting/scaling of the task) + */ + rep->taskrcond = lrep.taskrcond; + rep->rmserror = lrep.rmserror*(sb-sa); + rep->avgerror = lrep.avgerror*(sb-sa); + rep->maxerror = lrep.maxerror*(sb-sa); + rep->avgrelerror = (double)(0); + relcnt = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(spline1dcalc(s, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); + relcnt = relcnt+1; + } + } + if( relcnt!=0 ) + { + rep->avgrelerror = rep->avgrelerror/(double)relcnt; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal fitting subroutine +*************************************************************************/ +static void lsfit_lsfitlinearinternal(/* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + double threshold; + ae_matrix ft; + ae_matrix q; + ae_matrix l; + ae_matrix r; + ae_vector b; + ae_vector wmod; + ae_vector tau; + ae_vector nzeros; + ae_vector s; + ae_int_t i; + ae_int_t j; + double v; + ae_vector sv; + ae_matrix u; + ae_matrix vt; + ae_vector tmp; + ae_vector utb; + ae_vector sutb; + ae_int_t relcnt; + + ae_frame_make(_state, &_frame_block); + memset(&ft, 0, sizeof(ft)); + memset(&q, 0, sizeof(q)); + memset(&l, 0, sizeof(l)); + memset(&r, 0, sizeof(r)); + memset(&b, 0, sizeof(b)); + memset(&wmod, 0, sizeof(wmod)); + memset(&tau, 0, sizeof(tau)); + memset(&nzeros, 0, sizeof(nzeros)); + memset(&s, 0, sizeof(s)); + memset(&sv, 0, sizeof(sv)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + memset(&tmp, 0, sizeof(tmp)); + memset(&utb, 0, sizeof(utb)); + memset(&sutb, 0, sizeof(sutb)); + ae_vector_clear(c); + _lsfitreport_clear(rep); + ae_matrix_init(&ft, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&l, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wmod, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&nzeros, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&utb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true); + + lsfit_clearreport(rep, _state); + ae_assert(!(n<1||m<1), "LSFIT: integrity check 2508 failed", _state); + rep->terminationtype = 1; + threshold = ae_sqrt(ae_machineepsilon, _state); + + /* + * Degenerate case, needs special handling + */ + if( nptr.p_double[j]; + ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); + b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; + wmod.ptr.p_double[j] = (double)(1); + } + + /* + * LQ decomposition and reduction to M=N + */ + ae_vector_set_length(c, m, _state); + for(i=0; i<=m-1; i++) + { + c->ptr.p_double[i] = (double)(0); + } + rep->taskrcond = (double)(0); + rmatrixlq(&ft, n, m, &tau, _state); + rmatrixlqunpackq(&ft, n, m, &tau, n, &q, _state); + rmatrixlqunpackl(&ft, n, m, &l, _state); + lsfit_lsfitlinearinternal(&b, &wmod, &l, n, n, &tmp, rep, _state); + if( rep->terminationtype<=0 ) + { + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + v = tmp.ptr.p_double[i]; + ae_v_addd(&c->ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + } + ae_frame_leave(_state); + return; + } + + /* + * N>=M. Generate design matrix and reduce to N=M using + * QR decomposition. + */ + ae_matrix_set_length(&ft, n, m, _state); + ae_vector_set_length(&b, n, _state); + for(j=0; j<=n-1; j++) + { + v = w->ptr.p_double[j]; + ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v); + b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j]; + } + rmatrixqr(&ft, n, m, &tau, _state); + rmatrixqrunpackq(&ft, n, m, &tau, m, &q, _state); + rmatrixqrunpackr(&ft, n, m, &r, _state); + ae_vector_set_length(&tmp, m, _state); + for(i=0; i<=m-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = b.ptr.p_double[i]; + ae_v_addd(&tmp.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + } + ae_vector_set_length(&b, m, _state); + ae_v_move(&b.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); + + /* + * R contains reduced MxM design upper triangular matrix, + * B contains reduced Mx1 right part. + * + * Determine system condition number and decide + * should we use triangular solver (faster) or + * SVD-based solver (more stable). + * + * We can use LU-based RCond estimator for this task. + */ + rep->taskrcond = rmatrixlurcondinf(&r, m, _state); + if( ae_fp_greater(rep->taskrcond,threshold) ) + { + + /* + * use QR-based solver + */ + ae_vector_set_length(c, m, _state); + c->ptr.p_double[m-1] = b.ptr.p_double[m-1]/r.ptr.pp_double[m-1][m-1]; + for(i=m-2; i>=0; i--) + { + v = ae_v_dotproduct(&r.ptr.pp_double[i][i+1], 1, &c->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1)); + c->ptr.p_double[i] = (b.ptr.p_double[i]-v)/r.ptr.pp_double[i][i]; + } + } + else + { + + /* + * use SVD-based solver + */ + if( !rmatrixsvd(&r, m, m, 1, 1, 2, &sv, &u, &vt, _state) ) + { + ae_assert(ae_false, "LSFitLinearXX: critical failure - internal SVD solver failed", _state); + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&utb, m, _state); + ae_vector_set_length(&sutb, m, _state); + for(i=0; i<=m-1; i++) + { + utb.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=m-1; i++) + { + v = b.ptr.p_double[i]; + ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + } + if( ae_fp_greater(sv.ptr.p_double[0],(double)(0)) ) + { + rep->taskrcond = sv.ptr.p_double[m-1]/sv.ptr.p_double[0]; + for(i=0; i<=m-1; i++) + { + if( ae_fp_greater(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) + { + sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i]; + } + else + { + sutb.ptr.p_double[i] = (double)(0); + } + } + } + else + { + rep->taskrcond = (double)(0); + for(i=0; i<=m-1; i++) + { + sutb.ptr.p_double[i] = (double)(0); + } + } + ae_vector_set_length(c, m, _state); + for(i=0; i<=m-1; i++) + { + c->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=m-1; i++) + { + v = sutb.ptr.p_double[i]; + ae_v_addd(&c->ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + } + } + + /* + * calculate errors + */ + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->maxerror = (double)(0); + relcnt = 0; + for(i=0; i<=n-1; i++) + { + v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1)); + rep->rmserror = rep->rmserror+ae_sqr(v-y->ptr.p_double[i], _state); + rep->avgerror = rep->avgerror+ae_fabs(v-y->ptr.p_double[i], _state); + if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(v-y->ptr.p_double[i], _state)/ae_fabs(y->ptr.p_double[i], _state); + relcnt = relcnt+1; + } + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-y->ptr.p_double[i], _state), _state); + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)n, _state); + rep->avgerror = rep->avgerror/(double)n; + if( relcnt!=0 ) + { + rep->avgrelerror = rep->avgrelerror/(double)relcnt; + } + ae_vector_set_length(&nzeros, n, _state); + ae_vector_set_length(&s, m, _state); + for(i=0; i<=m-1; i++) + { + s.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + s.ptr.p_double[j] = s.ptr.p_double[j]+ae_sqr(fmatrix->ptr.pp_double[i][j], _state); + } + nzeros.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=m-1; i++) + { + if( ae_fp_neq(s.ptr.p_double[i],(double)(0)) ) + { + s.ptr.p_double[i] = ae_sqrt((double)1/s.ptr.p_double[i], _state); + } + else + { + s.ptr.p_double[i] = (double)(1); + } + } + lsfit_estimateerrors(fmatrix, &nzeros, y, w, c, &s, n, m, rep, &r, 1, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine +*************************************************************************/ +static void lsfit_lsfitclearrequestfields(lsfitstate* state, + ae_state *_state) +{ + + + ae_assert(state->protocolversion==1, "LSFIT: unexpected protocol", _state); + state->needf = ae_false; + state->needfg = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Internal subroutine, calculates barycentric basis functions. +Used for efficient simultaneous calculation of N basis functions. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_barycentriccalcbasis(const barycentricinterpolant* b, + double t, + /* Real */ ae_vector* y, + ae_state *_state) +{ + double s2; + double s; + double v; + ae_int_t i; + ae_int_t j; + + + + /* + * special case: N=1 + */ + if( b->n==1 ) + { + y->ptr.p_double[0] = (double)(1); + return; + } + + /* + * Here we assume that task is normalized, i.e.: + * 1. abs(Y[i])<=1 + * 2. abs(W[i])<=1 + * 3. X[] is ordered + * + * First, we decide: should we use "safe" formula (guarded + * against overflow) or fast one? + */ + s = ae_fabs(t-b->x.ptr.p_double[0], _state); + for(i=0; i<=b->n-1; i++) + { + v = b->x.ptr.p_double[i]; + if( ae_fp_eq(v,t) ) + { + for(j=0; j<=b->n-1; j++) + { + y->ptr.p_double[j] = (double)(0); + } + y->ptr.p_double[i] = (double)(1); + return; + } + v = ae_fabs(t-v, _state); + if( ae_fp_less(v,s) ) + { + s = v; + } + } + s2 = (double)(0); + for(i=0; i<=b->n-1; i++) + { + v = s/(t-b->x.ptr.p_double[i]); + v = v*b->w.ptr.p_double[i]; + y->ptr.p_double[i] = v; + s2 = s2+v; + } + v = (double)1/s2; + ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,b->n-1), v); +} + + +/************************************************************************* +This is internal function for Chebyshev fitting. + +It assumes that input data are normalized: +* X/XC belong to [-1,+1], +* mean(Y)=0, stddev(Y)=1. + +It does not checks inputs for errors. + +This function is used to fit general (shifted) Chebyshev models, power +basis models or barycentric models. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + N - number of points, N>0. + XC - points where polynomial values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that P(XC[i])=YC[i] + * DC[i]=1 means that P'(XC[i])=YC[i] + K - number of constraints, 0<=K=1 + +OUTPUT PARAMETERS: + C - interpolant in Chebyshev form; [-1,+1] is used as base interval + Rep - report, same format as in LSFitLinearW() subroutine. + Following fields are set: + * TerminationType + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_internalchebyshevfit(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector xc; + ae_vector yc; + ae_vector y2; + ae_vector w2; + ae_vector tmp; + ae_vector tmp2; + ae_vector tmpdiff; + ae_vector bx; + ae_vector by; + ae_vector bw; + ae_matrix fmatrix; + ae_matrix cmatrix; + ae_int_t i; + ae_int_t j; + double mx; + double decay; + + ae_frame_make(_state, &_frame_block); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&y2, 0, sizeof(y2)); + memset(&w2, 0, sizeof(w2)); + memset(&tmp, 0, sizeof(tmp)); + memset(&tmp2, 0, sizeof(tmp2)); + memset(&tmpdiff, 0, sizeof(tmpdiff)); + memset(&bx, 0, sizeof(bx)); + memset(&by, 0, sizeof(by)); + memset(&bw, 0, sizeof(bw)); + memset(&fmatrix, 0, sizeof(fmatrix)); + memset(&cmatrix, 0, sizeof(cmatrix)); + ae_vector_init_copy(&xc, _xc, _state, ae_true); + ae_vector_init_copy(&yc, _yc, _state, ae_true); + ae_vector_clear(c); + _lsfitreport_clear(rep); + ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpdiff, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&by, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bw, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); + + lsfit_clearreport(rep, _state); + + /* + * weight decay for correct handling of task which becomes + * degenerate after constraints are applied + */ + decay = (double)10000*ae_machineepsilon; + + /* + * allocate space, initialize/fill: + * * FMatrix- values of basis functions at X[] + * * CMatrix- values (derivatives) of basis functions at XC[] + * * fill constraints matrix + * * fill first N rows of design matrix with values + * * fill next M rows of design matrix with regularizing term + * * append M zeros to Y + * * append M elements, mean(abs(W)) each, to W + */ + ae_vector_set_length(&y2, n+m, _state); + ae_vector_set_length(&w2, n+m, _state); + ae_vector_set_length(&tmp, m, _state); + ae_vector_set_length(&tmpdiff, m, _state); + ae_matrix_set_length(&fmatrix, n+m, m, _state); + if( k>0 ) + { + ae_matrix_set_length(&cmatrix, k, m+1, _state); + } + + /* + * Fill design matrix, Y2, W2: + * * first N rows with basis functions for original points + * * next M rows with decay terms + */ + for(i=0; i<=n-1; i++) + { + + /* + * prepare Ith row + * use Tmp for calculations to avoid multidimensional arrays overhead + */ + for(j=0; j<=m-1; j++) + { + if( j==0 ) + { + tmp.ptr.p_double[j] = (double)(1); + } + else + { + if( j==1 ) + { + tmp.ptr.p_double[j] = x->ptr.p_double[i]; + } + else + { + tmp.ptr.p_double[j] = (double)2*x->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; + } + } + } + ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); + } + for(i=0; i<=m-1; i++) + { + for(j=0; j<=m-1; j++) + { + if( i==j ) + { + fmatrix.ptr.pp_double[n+i][j] = decay; + } + else + { + fmatrix.ptr.pp_double[n+i][j] = (double)(0); + } + } + } + ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1)); + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + mx = mx+ae_fabs(w->ptr.p_double[i], _state); + } + mx = mx/(double)n; + for(i=0; i<=m-1; i++) + { + y2.ptr.p_double[n+i] = (double)(0); + w2.ptr.p_double[n+i] = mx; + } + + /* + * fill constraints matrix + */ + for(i=0; i<=k-1; i++) + { + + /* + * prepare Ith row + * use Tmp for basis function values, + * TmpDiff for basos function derivatives + */ + for(j=0; j<=m-1; j++) + { + if( j==0 ) + { + tmp.ptr.p_double[j] = (double)(1); + tmpdiff.ptr.p_double[j] = (double)(0); + } + else + { + if( j==1 ) + { + tmp.ptr.p_double[j] = xc.ptr.p_double[i]; + tmpdiff.ptr.p_double[j] = (double)(1); + } + else + { + tmp.ptr.p_double[j] = (double)2*xc.ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2]; + tmpdiff.ptr.p_double[j] = (double)2*(tmp.ptr.p_double[j-1]+xc.ptr.p_double[i]*tmpdiff.ptr.p_double[j-1])-tmpdiff.ptr.p_double[j-2]; + } + } + } + if( dc->ptr.p_int[i]==0 ) + { + ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); + } + if( dc->ptr.p_int[i]==1 ) + { + ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmpdiff.ptr.p_double[0], 1, ae_v_len(0,m-1)); + } + cmatrix.ptr.pp_double[i][m] = yc.ptr.p_double[i]; + } + + /* + * Solve constrained task + */ + if( k>0 ) + { + + /* + * solve using regularization + */ + lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, c, rep, _state); + } + else + { + + /* + * no constraints, no regularization needed + */ + lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, 0, c, rep, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal Floater-Hormann fitting subroutine for fixed D +*************************************************************************/ +static void lsfit_barycentricfitwcfixedd(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + ae_int_t d, + ae_int_t* info, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector w; + ae_vector xc; + ae_vector yc; + ae_matrix fmatrix; + ae_matrix cmatrix; + ae_vector y2; + ae_vector w2; + ae_vector sx; + ae_vector sy; + ae_vector sbf; + ae_vector xoriginal; + ae_vector yoriginal; + ae_vector tmp; + lsfitreport lrep; + double v0; + double v1; + double mx; + barycentricinterpolant b2; + ae_int_t i; + ae_int_t j; + ae_int_t relcnt; + double xa; + double xb; + double sa; + double sb; + double decay; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&fmatrix, 0, sizeof(fmatrix)); + memset(&cmatrix, 0, sizeof(cmatrix)); + memset(&y2, 0, sizeof(y2)); + memset(&w2, 0, sizeof(w2)); + memset(&sx, 0, sizeof(sx)); + memset(&sy, 0, sizeof(sy)); + memset(&sbf, 0, sizeof(sbf)); + memset(&xoriginal, 0, sizeof(xoriginal)); + memset(&yoriginal, 0, sizeof(yoriginal)); + memset(&tmp, 0, sizeof(tmp)); + memset(&lrep, 0, sizeof(lrep)); + memset(&b2, 0, sizeof(b2)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + ae_vector_init_copy(&w, _w, _state, ae_true); + ae_vector_init_copy(&xc, _xc, _state, ae_true); + ae_vector_init_copy(&yc, _yc, _state, ae_true); + *info = 0; + _barycentricinterpolant_clear(b); + _barycentricfitreport_clear(rep); + ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sbf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + _lsfitreport_init(&lrep, _state, ae_true); + _barycentricinterpolant_init(&b2, _state, ae_true); + + if( ((n<1||m<2)||k<0)||k>=m ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + for(i=0; i<=k-1; i++) + { + *info = 0; + if( dc->ptr.p_int[i]<0 ) + { + *info = -1; + } + if( dc->ptr.p_int[i]>1 ) + { + *info = -1; + } + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * weight decay for correct handling of task which becomes + * degenerate after constraints are applied + */ + decay = (double)10000*ae_machineepsilon; + + /* + * Scale X, Y, XC, YC + */ + lsfitscalexy(&x, &y, &w, n, &xc, &yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state); + + /* + * allocate space, initialize: + * * FMatrix- values of basis functions at X[] + * * CMatrix- values (derivatives) of basis functions at XC[] + */ + ae_vector_set_length(&y2, n+m, _state); + ae_vector_set_length(&w2, n+m, _state); + ae_matrix_set_length(&fmatrix, n+m, m, _state); + if( k>0 ) + { + ae_matrix_set_length(&cmatrix, k, m+1, _state); + } + ae_vector_set_length(&y2, n+m, _state); + ae_vector_set_length(&w2, n+m, _state); + + /* + * Prepare design and constraints matrices: + * * fill constraints matrix + * * fill first N rows of design matrix with values + * * fill next M rows of design matrix with regularizing term + * * append M zeros to Y + * * append M elements, mean(abs(W)) each, to W + */ + ae_vector_set_length(&sx, m, _state); + ae_vector_set_length(&sy, m, _state); + ae_vector_set_length(&sbf, m, _state); + for(j=0; j<=m-1; j++) + { + sx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-(double)1; + } + for(i=0; i<=m-1; i++) + { + sy.ptr.p_double[i] = (double)(1); + } + barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + lsfit_barycentriccalcbasis(&b2, x.ptr.p_double[i], &sbf, _state); + ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &sbf.ptr.p_double[0], 1, ae_v_len(0,m-1)); + y2.ptr.p_double[i] = y.ptr.p_double[i]; + w2.ptr.p_double[i] = w.ptr.p_double[i]; + mx = mx+ae_fabs(w.ptr.p_double[i], _state)/(double)n; + } + for(i=0; i<=m-1; i++) + { + for(j=0; j<=m-1; j++) + { + if( i==j ) + { + fmatrix.ptr.pp_double[n+i][j] = decay; + } + else + { + fmatrix.ptr.pp_double[n+i][j] = (double)(0); + } + } + y2.ptr.p_double[n+i] = (double)(0); + w2.ptr.p_double[n+i] = mx; + } + if( k>0 ) + { + for(j=0; j<=m-1; j++) + { + for(i=0; i<=m-1; i++) + { + sy.ptr.p_double[i] = (double)(0); + } + sy.ptr.p_double[j] = (double)(1); + barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state); + for(i=0; i<=k-1; i++) + { + ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=1, "BarycentricFit: internal error!", _state); + barycentricdiff1(&b2, xc.ptr.p_double[i], &v0, &v1, _state); + if( dc->ptr.p_int[i]==0 ) + { + cmatrix.ptr.pp_double[i][j] = v0; + } + if( dc->ptr.p_int[i]==1 ) + { + cmatrix.ptr.pp_double[i][j] = v1; + } + } + } + for(i=0; i<=k-1; i++) + { + cmatrix.ptr.pp_double[i][m] = yc.ptr.p_double[i]; + } + } + + /* + * Solve constrained task + */ + if( k>0 ) + { + + /* + * solve using regularization + */ + lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, &tmp, &lrep, _state); + } + else + { + + /* + * no constraints, no regularization needed + */ + lsfitlinearwc(&y, &w, &fmatrix, &cmatrix, n, m, k, &tmp, &lrep, _state); + } + *info = lrep.terminationtype; + if( *info<0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Generate interpolant and scale it + */ + ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1)); + barycentricbuildfloaterhormann(&sx, &sy, m, d, b, _state); + barycentriclintransx(b, (double)2/(xb-xa), -(xa+xb)/(xb-xa), _state); + barycentriclintransy(b, sb-sa, sa, _state); + + /* + * Scale absolute errors obtained from LSFitLinearW. + * Relative error should be calculated separately + * (because of shifting/scaling of the task) + */ + rep->taskrcond = lrep.taskrcond; + rep->rmserror = lrep.rmserror*(sb-sa); + rep->avgerror = lrep.avgerror*(sb-sa); + rep->maxerror = lrep.maxerror*(sb-sa); + rep->avgrelerror = (double)(0); + relcnt = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(b, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); + relcnt = relcnt+1; + } + } + if( relcnt!=0 ) + { + rep->avgrelerror = rep->avgrelerror/(double)relcnt; + } + ae_frame_leave(_state); +} + + +static void lsfit_clearreport(lsfitreport* rep, ae_state *_state) +{ + + + rep->taskrcond = (double)(0); + rep->iterationscount = 0; + rep->varidx = -1; + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->maxerror = (double)(0); + rep->wrmserror = (double)(0); + rep->r2 = (double)(0); + ae_matrix_set_length(&rep->covpar, 0, 0, _state); + ae_vector_set_length(&rep->errpar, 0, _state); + ae_vector_set_length(&rep->errcurve, 0, _state); + ae_vector_set_length(&rep->noise, 0, _state); +} + + +/************************************************************************* +This internal function estimates covariance matrix and other error-related +information for linear/nonlinear least squares model. + +It has a bit awkward interface, but it can be used for both linear and +nonlinear problems. + +INPUT PARAMETERS: + F1 - array[0..N-1,0..K-1]: + * for linear problems - matrix of function values + * for nonlinear problems - Jacobian matrix + F0 - array[0..N-1]: + * for linear problems - must be filled with zeros + * for nonlinear problems - must store values of function being + fitted + Y - array[0..N-1]: + * for linear and nonlinear problems - must store target values + W - weights, array[0..N-1]: + * for linear and nonlinear problems - weights + X - array[0..K-1]: + * for linear and nonlinear problems - current solution + S - array[0..K-1]: + * its components should be strictly positive + * squared inverse of this diagonal matrix is used as damping + factor for covariance matrix (linear and nonlinear problems) + * for nonlinear problems, when scale of the variables is usually + explicitly given by user, you may use scale vector for this + parameter + * for linear problems you may set this parameter to + S=sqrt(1/diag(F'*F)) + * this parameter is automatically rescaled by this function, + only relative magnitudes of its components (with respect to + each other) matter. + N - number of points, N>0. + K - number of dimensions + Rep - structure which is used to store results + Z - additional matrix which, depending on ZKind, may contain some + information used to accelerate calculations - or just can be + temporary buffer: + * for ZKind=0 Z contains no information, just temporary + buffer which can be resized and used as needed + * for ZKind=1 Z contains triangular matrix from QR + decomposition of W*F1. This matrix can be used + to speedup calculation of covariance matrix. + It should not be changed by algorithm. + ZKind- contents of Z + +OUTPUT PARAMETERS: + +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(J*CovPar*J')), + where J is Jacobian matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] +* Rep.R2 coefficient of determination (non-weighted) + +Other fields of Rep are not changed. + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +static void lsfit_estimateerrors(/* Real */ const ae_matrix* f1, + /* Real */ const ae_vector* f0, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* _s, + ae_int_t n, + ae_int_t k, + lsfitreport* rep, + /* Real */ ae_matrix* z, + ae_int_t zkind, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector s; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + double v; + double noisec; + matinvreport invrep; + ae_int_t nzcnt; + double avg; + double rss; + double tss; + double sz; + double ss; + + ae_frame_make(_state, &_frame_block); + memset(&s, 0, sizeof(s)); + memset(&invrep, 0, sizeof(invrep)); + ae_vector_init_copy(&s, _s, _state, ae_true); + _matinvreport_init(&invrep, _state, ae_true); + + + /* + * Compute NZCnt - count of non-zero weights + */ + nzcnt = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) + { + nzcnt = nzcnt+1; + } + } + + /* + * Compute R2 + */ + if( nzcnt>0 ) + { + avg = 0.0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) + { + avg = avg+y->ptr.p_double[i]; + } + } + avg = avg/(double)nzcnt; + rss = 0.0; + tss = 0.0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) + { + v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); + v = v+f0->ptr.p_double[i]; + rss = rss+ae_sqr(v-y->ptr.p_double[i], _state); + tss = tss+ae_sqr(y->ptr.p_double[i]-avg, _state); + } + } + if( ae_fp_neq(tss,(double)(0)) ) + { + rep->r2 = ae_maxreal(1.0-rss/tss, 0.0, _state); + } + else + { + rep->r2 = 1.0; + } + } + else + { + rep->r2 = (double)(0); + } + + /* + * Compute estimate of proportionality between noise in the data and weights: + * NoiseC = mean(per-point-noise*per-point-weight) + * Noise level (standard deviation) at each point is equal to NoiseC/W[I]. + */ + if( nzcnt>k ) + { + noisec = 0.0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) + { + v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1)); + v = v+f0->ptr.p_double[i]; + noisec = noisec+ae_sqr((v-y->ptr.p_double[i])*w->ptr.p_double[i], _state); + } + } + noisec = ae_sqrt(noisec/(double)(nzcnt-k), _state); + } + else + { + noisec = 0.0; + } + + /* + * Two branches on noise level: + * * NoiseC>0 normal situation + * * NoiseC=0 degenerate case CovPar is filled by zeros + */ + rmatrixsetlengthatleast(&rep->covpar, k, k, _state); + if( ae_fp_greater(noisec,(double)(0)) ) + { + + /* + * Normal situation: non-zero noise level + */ + ae_assert(zkind==0||zkind==1, "LSFit: internal error in EstimateErrors() function", _state); + if( zkind==0 ) + { + + /* + * Z contains no additional information which can be used to speed up + * calculations. We have to calculate covariance matrix on our own: + * * Compute scaled Jacobian N*J, where N[i,i]=WCur[I]/NoiseC, store in Z + * * Compute Z'*Z, store in CovPar + * * Apply moderate regularization to CovPar and compute matrix inverse. + * In case inverse failed, increase regularization parameter and try + * again. + */ + rmatrixsetlengthatleast(z, n, k, _state); + for(i=0; i<=n-1; i++) + { + v = w->ptr.p_double[i]/noisec; + ae_v_moved(&z->ptr.pp_double[i][0], 1, &f1->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + + /* + * Convert S to automatically scaled damped matrix: + * * calculate SZ - sum of diagonal elements of Z'*Z + * * calculate SS - sum of diagonal elements of S^(-2) + * * overwrite S by (SZ/SS)*S^(-2) + * * now S has approximately same magnitude as giagonal of Z'*Z + */ + sz = (double)(0); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + sz = sz+z->ptr.pp_double[i][j]*z->ptr.pp_double[i][j]; + } + } + if( ae_fp_eq(sz,(double)(0)) ) + { + sz = (double)(1); + } + ss = (double)(0); + for(j=0; j<=k-1; j++) + { + ss = ss+(double)1/ae_sqr(s.ptr.p_double[j], _state); + } + for(j=0; j<=k-1; j++) + { + s.ptr.p_double[j] = sz/ss/ae_sqr(s.ptr.p_double[j], _state); + } + + /* + * Calculate damped inverse inv(Z'*Z+S). + * We increase damping factor V until Z'*Z become well-conditioned. + */ + v = 1.0E3*ae_machineepsilon; + do + { + rmatrixsyrk(k, n, 1.0, z, 0, 0, 2, 0.0, &rep->covpar, 0, 0, ae_true, _state); + for(i=0; i<=k-1; i++) + { + rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s.ptr.p_double[i]; + } + spdmatrixinverse(&rep->covpar, k, ae_true, &invrep, _state); + v = (double)10*v; + } + while(invrep.terminationtype<=0); + for(i=0; i<=k-1; i++) + { + for(j=i+1; j<=k-1; j++) + { + rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; + } + } + } + if( zkind==1 ) + { + + /* + * We can reuse additional information: + * * Z contains R matrix from QR decomposition of W*F1 + * * After multiplication by 1/NoiseC we get Z_mod = N*F1, where diag(N)=w[i]/NoiseC + * * Such triangular Z_mod is a Cholesky factor from decomposition of J'*N'*N*J. + * Thus, we can calculate covariance matrix as inverse of the matrix given by + * its Cholesky decomposition. It allow us to avoid time-consuming calculation + * of J'*N'*N*J in CovPar - complexity is reduced from O(N*K^2) to O(K^3), which + * is quite good because K is usually orders of magnitude smaller than N. + * + * First, convert S to automatically scaled damped matrix: + * * calculate SZ - sum of magnitudes of diagonal elements of Z/NoiseC + * * calculate SS - sum of diagonal elements of S^(-1) + * * overwrite S by (SZ/SS)*S^(-1) + * * now S has approximately same magnitude as giagonal of Z'*Z + */ + sz = (double)(0); + for(j=0; j<=k-1; j++) + { + sz = sz+ae_fabs(z->ptr.pp_double[j][j]/noisec, _state); + } + if( ae_fp_eq(sz,(double)(0)) ) + { + sz = (double)(1); + } + ss = (double)(0); + for(j=0; j<=k-1; j++) + { + ss = ss+(double)1/s.ptr.p_double[j]; + } + for(j=0; j<=k-1; j++) + { + s.ptr.p_double[j] = sz/ss/s.ptr.p_double[j]; + } + + /* + * Calculate damped inverse of inv((Z+v*S)'*(Z+v*S)) + * We increase damping factor V until matrix become well-conditioned. + */ + v = 1.0E3*ae_machineepsilon; + do + { + for(i=0; i<=k-1; i++) + { + for(j=i; j<=k-1; j++) + { + rep->covpar.ptr.pp_double[i][j] = z->ptr.pp_double[i][j]/noisec; + } + rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s.ptr.p_double[i]; + } + spdmatrixcholeskyinverse(&rep->covpar, k, ae_true, &invrep, _state); + v = (double)10*v; + } + while(invrep.terminationtype<=0); + for(i=0; i<=k-1; i++) + { + for(j=i+1; j<=k-1; j++) + { + rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j]; + } + } + } + } + else + { + + /* + * Degenerate situation: zero noise level, covariance matrix is zero. + */ + for(i=0; i<=k-1; i++) + { + for(j=0; j<=k-1; j++) + { + rep->covpar.ptr.pp_double[j][i] = (double)(0); + } + } + } + + /* + * Estimate erorrs in parameters, curve and per-point noise + */ + rvectorsetlengthatleast(&rep->errpar, k, _state); + rvectorsetlengthatleast(&rep->errcurve, n, _state); + rvectorsetlengthatleast(&rep->noise, n, _state); + for(i=0; i<=k-1; i++) + { + rep->errpar.ptr.p_double[i] = ae_sqrt(rep->covpar.ptr.pp_double[i][i], _state); + } + for(i=0; i<=n-1; i++) + { + + /* + * ErrCurve[I] is sqrt(P[i,i]) where P=J*CovPar*J' + */ + v = 0.0; + for(j=0; j<=k-1; j++) + { + for(j1=0; j1<=k-1; j1++) + { + v = v+f1->ptr.pp_double[i][j]*rep->covpar.ptr.pp_double[j][j1]*f1->ptr.pp_double[i][j1]; + } + } + rep->errcurve.ptr.p_double[i] = ae_sqrt(v, _state); + + /* + * Noise[i] is filled using weights and current estimate of noise level + */ + if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) ) + { + rep->noise.ptr.p_double[i] = noisec/w->ptr.p_double[i]; + } + else + { + rep->noise.ptr.p_double[i] = (double)(0); + } + } + ae_frame_leave(_state); +} + + +void _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + polynomialfitreport *p = (polynomialfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _polynomialfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + polynomialfitreport *dst = (polynomialfitreport*)_dst; + const polynomialfitreport *src = (const polynomialfitreport*)_src; + dst->terminationtype = src->terminationtype; + dst->taskrcond = src->taskrcond; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->maxerror = src->maxerror; +} + + +void _polynomialfitreport_clear(void* _p) +{ + polynomialfitreport *p = (polynomialfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _polynomialfitreport_destroy(void* _p) +{ + polynomialfitreport *p = (polynomialfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + barycentricfitreport *p = (barycentricfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _barycentricfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + barycentricfitreport *dst = (barycentricfitreport*)_dst; + const barycentricfitreport *src = (const barycentricfitreport*)_src; + dst->terminationtype = src->terminationtype; + dst->taskrcond = src->taskrcond; + dst->dbest = src->dbest; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->maxerror = src->maxerror; +} + + +void _barycentricfitreport_clear(void* _p) +{ + barycentricfitreport *p = (barycentricfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _barycentricfitreport_destroy(void* _p) +{ + barycentricfitreport *p = (barycentricfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lsfitreport *p = (lsfitreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->covpar, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->errpar, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->errcurve, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->noise, 0, DT_REAL, _state, make_automatic); +} + + +void _lsfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lsfitreport *dst = (lsfitreport*)_dst; + const lsfitreport *src = (const lsfitreport*)_src; + dst->terminationtype = src->terminationtype; + dst->taskrcond = src->taskrcond; + dst->iterationscount = src->iterationscount; + dst->varidx = src->varidx; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->avgrelerror = src->avgrelerror; + dst->maxerror = src->maxerror; + dst->wrmserror = src->wrmserror; + ae_matrix_init_copy(&dst->covpar, &src->covpar, _state, make_automatic); + ae_vector_init_copy(&dst->errpar, &src->errpar, _state, make_automatic); + ae_vector_init_copy(&dst->errcurve, &src->errcurve, _state, make_automatic); + ae_vector_init_copy(&dst->noise, &src->noise, _state, make_automatic); + dst->r2 = src->r2; +} + + +void _lsfitreport_clear(void* _p) +{ + lsfitreport *p = (lsfitreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->covpar); + ae_vector_clear(&p->errpar); + ae_vector_clear(&p->errcurve); + ae_vector_clear(&p->noise); +} + + +void _lsfitreport_destroy(void* _p) +{ + lsfitreport *p = (lsfitreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->covpar); + ae_vector_destroy(&p->errpar); + ae_vector_destroy(&p->errcurve); + ae_vector_destroy(&p->noise); +} + + +void _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lsfitstate *p = (lsfitstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->c0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->taskx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tasky, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->taskw, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + ae_vector_init(&p->wcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpwk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpct, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpjac, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpjacw, 0, 0, DT_REAL, _state, make_automatic); + _lsfitreport_init(&p->rep, _state, make_automatic); + _minlmstate_init(&p->optstate, _state, make_automatic); + _minlmreport_init(&p->optrep, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _lsfitstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lsfitstate *dst = (lsfitstate*)_dst; + const lsfitstate *src = (const lsfitstate*)_src; + dst->protocolversion = src->protocolversion; + dst->formulatype = src->formulatype; + dst->optalgo = src->optalgo; + dst->m = src->m; + dst->k = src->k; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->stpmax = src->stpmax; + dst->xrep = src->xrep; + ae_vector_init_copy(&dst->c0, &src->c0, _state, make_automatic); + ae_vector_init_copy(&dst->c1, &src->c1, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_matrix_init_copy(&dst->taskx, &src->taskx, _state, make_automatic); + ae_vector_init_copy(&dst->tasky, &src->tasky, _state, make_automatic); + dst->npoints = src->npoints; + ae_vector_init_copy(&dst->taskw, &src->taskw, _state, make_automatic); + dst->nweights = src->nweights; + dst->wkind = src->wkind; + dst->wits = src->wits; + dst->diffstep = src->diffstep; + dst->teststep = src->teststep; + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + dst->nonmonotoniccnt = src->nonmonotoniccnt; + dst->xupdated = src->xupdated; + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->pointindex = src->pointindex; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + ae_vector_init_copy(&dst->wcur, &src->wcur, _state, make_automatic); + ae_vector_init_copy(&dst->tmpwk, &src->tmpwk, _state, make_automatic); + ae_vector_init_copy(&dst->tmpct, &src->tmpct, _state, make_automatic); + ae_vector_init_copy(&dst->tmp, &src->tmp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf, &src->tmpf, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpjac, &src->tmpjac, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpjacw, &src->tmpjacw, _state, make_automatic); + dst->tmpnoise = src->tmpnoise; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repvaridx = src->repvaridx; + dst->reprmserror = src->reprmserror; + dst->repavgerror = src->repavgerror; + dst->repavgrelerror = src->repavgrelerror; + dst->repmaxerror = src->repmaxerror; + dst->repwrmserror = src->repwrmserror; + _lsfitreport_init_copy(&dst->rep, &src->rep, _state, make_automatic); + _minlmstate_init_copy(&dst->optstate, &src->optstate, _state, make_automatic); + _minlmreport_init_copy(&dst->optrep, &src->optrep, _state, make_automatic); + dst->prevnpt = src->prevnpt; + dst->prevalgo = src->prevalgo; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _lsfitstate_clear(void* _p) +{ + lsfitstate *p = (lsfitstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->c0); + ae_vector_clear(&p->c1); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_matrix_clear(&p->taskx); + ae_vector_clear(&p->tasky); + ae_vector_clear(&p->taskw); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->x); + ae_vector_clear(&p->c); + ae_vector_clear(&p->g); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + ae_vector_clear(&p->wcur); + ae_vector_clear(&p->tmpwk); + ae_vector_clear(&p->tmpct); + ae_vector_clear(&p->tmp); + ae_vector_clear(&p->tmpf); + ae_matrix_clear(&p->tmpjac); + ae_matrix_clear(&p->tmpjacw); + _lsfitreport_clear(&p->rep); + _minlmstate_clear(&p->optstate); + _minlmreport_clear(&p->optrep); + _rcommstate_clear(&p->rstate); +} + + +void _lsfitstate_destroy(void* _p) +{ + lsfitstate *p = (lsfitstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->c0); + ae_vector_destroy(&p->c1); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_matrix_destroy(&p->taskx); + ae_vector_destroy(&p->tasky); + ae_vector_destroy(&p->taskw); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->c); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + ae_vector_destroy(&p->wcur); + ae_vector_destroy(&p->tmpwk); + ae_vector_destroy(&p->tmpct); + ae_vector_destroy(&p->tmp); + ae_vector_destroy(&p->tmpf); + ae_matrix_destroy(&p->tmpjac); + ae_matrix_destroy(&p->tmpjacw); + _lsfitreport_destroy(&p->rep); + _minlmstate_destroy(&p->optstate); + _minlmreport_destroy(&p->optrep); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Fits least squares (LS) circle (or NX-dimensional sphere) to data (a set +of points in NX-dimensional space). + +Least squares circle minimizes sum of squared deviations between distances +from points to the center and some "candidate" radius, which is also +fitted to the data. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + R - radius + + -- ALGLIB -- + Copyright 07.05.2018 by Bochkanov Sergey +*************************************************************************/ +void fitspherels(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* r, + ae_state *_state) +{ + double dummy; + + ae_vector_clear(cx); + *r = 0.0; + + fitspherex(xy, npoints, nx, 0, 0.0, 0, cx, &dummy, r, _state); +} + + +/************************************************************************* +Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to data +(a set of points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RHi - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rhi, + ae_state *_state) +{ + double dummy; + + ae_vector_clear(cx); + *rhi = 0.0; + + fitspherex(xy, npoints, nx, 1, 0.0, 0, cx, &dummy, rhi, _state); +} + + +/************************************************************************* +Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremi(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + ae_state *_state) +{ + double dummy; + + ae_vector_clear(cx); + *rlo = 0.0; + + fitspherex(xy, npoints, nx, 2, 0.0, 0, cx, rlo, &dummy, _state); +} + + +/************************************************************************* +Fits minimum zone circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius of inscribed circle + RHo - radius of circumscribed circle + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremz(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state) +{ + + ae_vector_clear(cx); + *rlo = 0.0; + *rhi = 0.0; + + fitspherex(xy, npoints, nx, 3, 0.0, 0, cx, rlo, rhi, _state); +} + + +/************************************************************************* +Fitting minimum circumscribed, maximum inscribed or minimum zone circles +(or NX-dimensional spheres) to data (a set of points in NX-dimensional +space). + +This is expert function which allows to tweak many parameters of +underlying nonlinear solver: +* stopping criteria for inner iterations +* number of outer iterations + +You may tweak all these parameters or only some of them, leaving other +ones at their default state - just specify zero value, and solver will +fill it with appropriate default one. + +These comments also include some discussion of approach used to handle +such unusual fitting problem, its stability, drawbacks of alternative +methods, and convergence properties. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + ProblemType-used to encode problem type: + * 0 for least squares circle + * 1 for minimum circumscribed circle/sphere fitting (MC) + * 2 for maximum inscribed circle/sphere fitting (MI) + * 3 for minimum zone circle fitting (difference between + Rhi and Rlo is minimized), denoted as MZ + EpsX - stopping condition for NLC optimizer: + * must be non-negative + * use 0 to choose default value (1.0E-12 is used by default) + * you may specify larger values, up to 1.0E-6, if you want + to speed-up solver; NLC solver performs several + preconditioned outer iterations, so final result + typically has precision much better than EpsX. + AULIts - number of outer iterations performed by NLC optimizer: + * must be non-negative + * use 0 to choose default value (20 is used by default) + * you may specify values smaller than 20 if you want to + speed up solver; 10 often results in good combination of + precision and speed; sometimes you may get good results + with just 6 outer iterations. + Ignored for ProblemType=0. + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius: + * for ProblemType=2,3, radius of the inscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=1 - zero + RHo - radius: + * for ProblemType=1,3, radius of the circumscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=2 - zero + +NOTE: ON THE UNIQUENESS OF SOLUTIONS + +ALGLIB provides solution to several related circle fitting problems: MC +(minimum circumscribed), MI (maximum inscribed) and MZ (minimum zone) +fitting, LS (least squares) fitting. + +It is important to note that among these problems only MC and LS are +convex and have unique solution independently from starting point. + +As for MI, it may (or may not, depending on dataset properties) have +multiple solutions, and it always has one degenerate solution C=infinity +which corresponds to infinitely large radius. Thus, there are no guarantees +that solution to MI returned by this solver will be the best one (and no +one can provide you with such guarantee because problem is NP-hard). The +only guarantee you have is that this solution is locally optimal, i.e. it +can not be improved by infinitesimally small tweaks in the parameters. + +It is also possible to "run away" to infinity when started from bad +initial point located outside of point cloud (or when point cloud does not +span entire circumference/surface of the sphere). + +Finally, MZ (minimum zone circle) stands somewhere between MC and MI in +stability. It is somewhat regularized by "circumscribed" term of the merit +function; however, solutions to MZ may be non-unique, and in some unlucky +cases it is also possible to "run away to infinity". + + +NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH + +The problem formulation for MC (minimum circumscribed circle; for the +sake of simplicity we omit MZ and MI here) is: + + [ [ ]2 ] + min [ max [ XY[i]-C ] ] + C [ i [ ] ] + +i.e. it is unconstrained nonsmooth optimization problem of finding "best" +central point, with radius R being unambiguously determined from C. In +order to move away from non-smoothness we use following reformulation: + + [ ] [ ]2 + min [ R ] subject to R>=0, [ XY[i]-C ] <= R^2 + C,R [ ] [ ] + +i.e. it becomes smooth quadratically constrained optimization problem with +linear target function. Such problem statement is 100% equivalent to the +original nonsmooth one, but much easier to approach. We solve it with +MinNLC solver provided by ALGLIB. + + +NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH + +ALGLIB has nonlinearly constrained solver which proved to be stable on +such problems. However, some authors proposed to linearize constraints in +the vicinity of current approximation (Ci,Ri) and to get next approximate +solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously, +LP problems are easier than nonlinearly constrained ones. + +Indeed, such approach to MC/MI/MZ resulted in ~10-20x increase in +performance (when compared with NLC solver). However, it turned out that +in some cases linearized model fails to predict correct direction for next +step and tells us that we converged to solution even when we are still 2-4 +digits of precision away from it. + +It is important that it is not failure of LP solver - it is failure of the +linear model; even when solved exactly, it fails to handle subtle +nonlinearities which arise near the solution. We validated it by comparing +results returned by ALGLIB linear solver with that of MATLAB. + +In our experiments with linearization: +* MC failed most often, at both realistic and synthetic datasets +* MI sometimes failed, but sometimes succeeded +* MZ often succeeded; our guess is that presence of two independent sets + of constraints (one set for Rlo and another one for Rhi) and two terms + in the target function (Rlo and Rhi) regularizes task, so when linear + model fails to handle nonlinearities from Rlo, it uses Rhi as a hint + (and vice versa). + +Because linearization approach failed to achieve stable results, we do not +include it in ALGLIB. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspherex(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + double epsx, + ae_int_t aulits, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state) +{ + ae_frame _frame_block; + fitsphereinternalreport rep; + + ae_frame_make(_state, &_frame_block); + memset(&rep, 0, sizeof(rep)); + ae_vector_clear(cx); + *rlo = 0.0; + *rhi = 0.0; + _fitsphereinternalreport_init(&rep, _state, ae_true); + + ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state); + ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state); + fitsphereinternal(xy, npoints, nx, problemtype, 0, epsx, aulits, cx, rlo, rhi, &rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Fitting minimum circumscribed, maximum inscribed or minimum zone circles +(or NX-dimensional spheres) to data (a set of points in NX-dimensional +space). + +Internal computational function. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + ProblemType-used to encode problem type: + * 0 for least squares circle + * 1 for minimum circumscribed circle/sphere fitting (MC) + * 2 for maximum inscribed circle/sphere fitting (MI) + * 3 for minimum zone circle fitting (difference between + Rhi and Rlo is minimized), denoted as MZ + SolverType- solver to use: + * 0 use best solver available (1 in current version) + * 1 use nonlinearly constrained optimization approach, AUL + (it is roughly 10-20 times slower than SPC-LIN, but + much more stable) + * 2 use special fast IMPRECISE solver, SPC-LIN sequential + linearization approach; SPC-LIN is fast, but sometimes + fails to converge with more than 3 digits of precision; + see comments below. + NOT RECOMMENDED UNLESS YOU REALLY NEED HIGH PERFORMANCE + AT THE COST OF SOME PRECISION. + * 3 use nonlinearly constrained optimization approach, SQP + Ignored for ProblemType=0. + EpsX - stopping criteria for SQP and NLC optimizers: + * must be non-negative + * use 0 to choose default value (1.0E-12 is used by default) + * if you use SQP solver, you should use default values + * if you use NLC solver, you may specify larger values, up + to 1.0E-6, if you want to speed-up solver; NLC solver + performs several preconditioned outer iterations, so final + result typically has precision much better than EpsX. + AULIts - number of iterations performed by NLC optimizer: + * must be non-negative + * use 0 to choose default value (20 is used by default) + * you may specify values smaller than 20 if you want to + speed up solver; 10 often results in good combination of + precision and speed + Ignored for ProblemType=0. + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius: + * for ProblemType=2,3, radius of the inscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=1 - zero + RHo - radius: + * for ProblemType=1,3, radius of the circumscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=2 - zero + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitsphereinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + ae_int_t solvertype, + double epsx, + ae_int_t aulits, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + fitsphereinternalreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double vv; + ae_int_t cpr; + ae_bool userlo; + ae_bool userhi; + double vlo; + double vhi; + ae_vector vmin; + ae_vector vmax; + double spread; + ae_vector pcr; + ae_vector scr; + ae_vector bl; + ae_vector bu; + ae_int_t suboffset; + ae_int_t dstrow; + minnlcstate nlcstate; + minnlcreport nlcrep; + ae_matrix cmatrix; + ae_vector ct; + ae_int_t outeridx; + ae_int_t maxouterits; + ae_int_t maxits; + double safeguard; + double bi; + minbleicstate blcstate; + minbleicreport blcrep; + ae_vector prevc; + minlmstate lmstate; + minlmreport lmrep; + + ae_frame_make(_state, &_frame_block); + memset(&vmin, 0, sizeof(vmin)); + memset(&vmax, 0, sizeof(vmax)); + memset(&pcr, 0, sizeof(pcr)); + memset(&scr, 0, sizeof(scr)); + memset(&bl, 0, sizeof(bl)); + memset(&bu, 0, sizeof(bu)); + memset(&nlcstate, 0, sizeof(nlcstate)); + memset(&nlcrep, 0, sizeof(nlcrep)); + memset(&cmatrix, 0, sizeof(cmatrix)); + memset(&ct, 0, sizeof(ct)); + memset(&blcstate, 0, sizeof(blcstate)); + memset(&blcrep, 0, sizeof(blcrep)); + memset(&prevc, 0, sizeof(prevc)); + memset(&lmstate, 0, sizeof(lmstate)); + memset(&lmrep, 0, sizeof(lmrep)); + ae_vector_clear(cx); + *rlo = 0.0; + *rhi = 0.0; + _fitsphereinternalreport_clear(rep); + ae_vector_init(&vmin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vmax, 0, DT_REAL, _state, ae_true); + ae_vector_init(&pcr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&scr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bl, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bu, 0, DT_REAL, _state, ae_true); + _minnlcstate_init(&nlcstate, _state, ae_true); + _minnlcreport_init(&nlcrep, _state, ae_true); + ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + _minbleicstate_init(&blcstate, _state, ae_true); + _minbleicreport_init(&blcrep, _state, ae_true); + ae_vector_init(&prevc, 0, DT_REAL, _state, ae_true); + _minlmstate_init(&lmstate, _state, ae_true); + _minlmreport_init(&lmrep, _state, ae_true); + + + /* + * Check input parameters + */ + ae_assert(npoints>0, "FitSphereX: NPoints<=0", _state); + ae_assert(nx>0, "FitSphereX: NX<=0", _state); + ae_assert(apservisfinitematrix(xy, npoints, nx, _state), "FitSphereX: XY contains infinite or NAN values", _state); + ae_assert(problemtype>=0&&problemtype<=3, "FitSphereX: ProblemType is neither 0, 1, 2 or 3", _state); + ae_assert(solvertype>=0&&solvertype<=3, "FitSphereX: ProblemType is neither 1, 2 or 3", _state); + ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state); + ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state); + if( solvertype==0 ) + { + solvertype = 1; + } + if( ae_fp_eq(epsx,(double)(0)) ) + { + epsx = 1.0E-12; + } + if( aulits==0 ) + { + aulits = 20; + } + safeguard = (double)(10); + maxouterits = 10; + maxits = 10000; + rep->nfev = 0; + rep->iterationscount = 0; + + /* + * Determine initial values, initial estimates and spread of the points + */ + ae_vector_set_length(&vmin, nx, _state); + ae_vector_set_length(&vmax, nx, _state); + ae_vector_set_length(cx, nx, _state); + for(j=0; j<=nx-1; j++) + { + vmin.ptr.p_double[j] = xy->ptr.pp_double[0][j]; + vmax.ptr.p_double[j] = xy->ptr.pp_double[0][j]; + cx->ptr.p_double[j] = (double)(0); + } + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = cx->ptr.p_double[j]+xy->ptr.pp_double[i][j]; + vmin.ptr.p_double[j] = ae_minreal(vmin.ptr.p_double[j], xy->ptr.pp_double[i][j], _state); + vmax.ptr.p_double[j] = ae_maxreal(vmax.ptr.p_double[j], xy->ptr.pp_double[i][j], _state); + } + } + spread = (double)(0); + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = cx->ptr.p_double[j]/(double)npoints; + spread = ae_maxreal(spread, vmax.ptr.p_double[j]-vmin.ptr.p_double[j], _state); + } + *rlo = ae_maxrealnumber; + *rhi = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + *rhi = ae_maxreal(*rhi, v, _state); + *rlo = ae_minreal(*rlo, v, _state); + } + + /* + * Handle degenerate case of zero spread + */ + if( ae_fp_eq(spread,(double)(0)) ) + { + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = vmin.ptr.p_double[j]; + } + *rhi = (double)(0); + *rlo = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Prepare initial point for optimizer, scale vector and box constraints + */ + ae_vector_set_length(&pcr, nx+2, _state); + ae_vector_set_length(&scr, nx+2, _state); + ae_vector_set_length(&bl, nx+2, _state); + ae_vector_set_length(&bu, nx+2, _state); + for(j=0; j<=nx-1; j++) + { + pcr.ptr.p_double[j] = cx->ptr.p_double[j]; + scr.ptr.p_double[j] = 0.1*spread; + bl.ptr.p_double[j] = cx->ptr.p_double[j]-safeguard*spread; + bu.ptr.p_double[j] = cx->ptr.p_double[j]+safeguard*spread; + } + pcr.ptr.p_double[nx+0] = *rlo; + pcr.ptr.p_double[nx+1] = *rhi; + scr.ptr.p_double[nx+0] = 0.5*spread; + scr.ptr.p_double[nx+1] = 0.5*spread; + bl.ptr.p_double[nx+0] = (double)(0); + bl.ptr.p_double[nx+1] = (double)(0); + bu.ptr.p_double[nx+0] = safeguard*(*rhi); + bu.ptr.p_double[nx+1] = safeguard*(*rhi); + + /* + * First branch: least squares fitting vs MI/MC/MZ fitting + */ + if( problemtype==0 ) + { + + /* + * Solve problem with Levenberg-Marquardt algorithm + */ + pcr.ptr.p_double[nx] = *rhi; + minlmcreatevj(nx+1, npoints, &pcr, &lmstate, _state); + minlmsetscale(&lmstate, &scr, _state); + minlmsetbc(&lmstate, &bl, &bu, _state); + minlmsetcond(&lmstate, epsx, maxits, _state); + while(minlmiteration(&lmstate, _state)) + { + if( lmstate.needfij||lmstate.needfi ) + { + inc(&rep->nfev, _state); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j], _state); + } + lmstate.fi.ptr.p_double[i] = ae_sqrt(v, _state)-lmstate.x.ptr.p_double[nx]; + if( lmstate.needfij ) + { + for(j=0; j<=nx-1; j++) + { + lmstate.j.ptr.pp_double[i][j] = 0.5/(1.0E-9*spread+ae_sqrt(v, _state))*(double)2*(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j]); + } + lmstate.j.ptr.pp_double[i][nx] = (double)(-1); + } + } + continue; + } + ae_assert(ae_false, "Assertion failed", _state); + } + minlmresults(&lmstate, &pcr, &lmrep, _state); + ae_assert(lmrep.terminationtype>0, "FitSphereX: unexpected failure of LM solver", _state); + rep->iterationscount = rep->iterationscount+lmrep.iterationscount; + + /* + * Offload center coordinates from PCR to CX, + * re-calculate exact value of RLo/RHi using CX. + */ + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = pcr.ptr.p_double[j]; + } + vv = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + vv = vv+v/(double)npoints; + } + *rlo = vv; + *rhi = vv; + } + else + { + + /* + * MI, MC, MZ fitting. + * Prepare problem metrics + */ + userlo = problemtype==2||problemtype==3; + userhi = problemtype==1||problemtype==3; + if( userlo&&userhi ) + { + cpr = 2; + } + else + { + cpr = 1; + } + if( userlo ) + { + vlo = (double)(1); + } + else + { + vlo = (double)(0); + } + if( userhi ) + { + vhi = (double)(1); + } + else + { + vhi = (double)(0); + } + + /* + * Solve with NLC solver; problem is treated as general nonlinearly constrained + * programming, with augmented Lagrangian solver or SQP being used. + */ + if( solvertype==1||solvertype==3 ) + { + minnlccreate(nx+2, &pcr, &nlcstate, _state); + minnlcsetscale(&nlcstate, &scr, _state); + minnlcsetbc(&nlcstate, &bl, &bu, _state); + minnlcsetnlc(&nlcstate, 0, cpr*npoints, _state); + minnlcsetcond(&nlcstate, epsx, maxits, _state); + minnlcsetstpmax(&nlcstate, 0.1, _state); + if( solvertype==1 ) + { + minnlcsetalgoaul2(&nlcstate, aulits, _state); + } + else + { + minnlcsetalgosqp(&nlcstate, _state); + } + minnlcsetalgosqp(&nlcstate, _state); + minnlcrestartfrom(&nlcstate, &pcr, _state); + while(minnlciteration(&nlcstate, _state)) + { + if( nlcstate.needfij ) + { + inc(&rep->nfev, _state); + nlcstate.fi.ptr.p_double[0] = vhi*nlcstate.x.ptr.p_double[nx+1]-vlo*nlcstate.x.ptr.p_double[nx+0]; + for(j=0; j<=nx-1; j++) + { + nlcstate.j.ptr.pp_double[0][j] = (double)(0); + } + nlcstate.j.ptr.pp_double[0][nx+0] = -(double)1*vlo; + nlcstate.j.ptr.pp_double[0][nx+1] = (double)1*vhi; + for(i=0; i<=npoints-1; i++) + { + suboffset = 0; + if( userhi ) + { + dstrow = 1+cpr*i+suboffset; + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j]; + v = v+vv*vv; + nlcstate.j.ptr.pp_double[dstrow][j] = (double)2*vv; + } + vv = nlcstate.x.ptr.p_double[nx+1]; + v = v-vv*vv; + nlcstate.j.ptr.pp_double[dstrow][nx+0] = (double)(0); + nlcstate.j.ptr.pp_double[dstrow][nx+1] = -(double)2*vv; + nlcstate.fi.ptr.p_double[dstrow] = v; + inc(&suboffset, _state); + } + if( userlo ) + { + dstrow = 1+cpr*i+suboffset; + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j]; + v = v-vv*vv; + nlcstate.j.ptr.pp_double[dstrow][j] = -(double)2*vv; + } + vv = nlcstate.x.ptr.p_double[nx+0]; + v = v+vv*vv; + nlcstate.j.ptr.pp_double[dstrow][nx+0] = (double)2*vv; + nlcstate.j.ptr.pp_double[dstrow][nx+1] = (double)(0); + nlcstate.fi.ptr.p_double[dstrow] = v; + inc(&suboffset, _state); + } + ae_assert(suboffset==cpr, "Assertion failed", _state); + } + continue; + } + ae_assert(ae_false, "Assertion failed", _state); + } + minnlcresults(&nlcstate, &pcr, &nlcrep, _state); + ae_assert(nlcrep.terminationtype>0, "FitSphereX: unexpected failure of NLC solver", _state); + rep->iterationscount = rep->iterationscount+nlcrep.iterationscount; + + /* + * Offload center coordinates from PCR to CX, + * re-calculate exact value of RLo/RHi using CX. + */ + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = pcr.ptr.p_double[j]; + } + *rlo = ae_maxrealnumber; + *rhi = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + *rhi = ae_maxreal(*rhi, v, _state); + *rlo = ae_minreal(*rlo, v, _state); + } + if( !userlo ) + { + *rlo = (double)(0); + } + if( !userhi ) + { + *rhi = (double)(0); + } + ae_frame_leave(_state); + return; + } + + /* + * Solve problem with SQP (sequential QP) approach; this approach + * is much faster than NLP, but often fails for MI and MC (for MZ + * it performs well enough). + * + * REFERENCE: "On a sequential linear programming approach to finding + * the smallest circumscribed, largest inscribed, and minimum + * zone circle or sphere", Helmuth Spath and G.A.Watson + */ + if( solvertype==2 ) + { + ae_matrix_set_length(&cmatrix, cpr*npoints, nx+3, _state); + ae_vector_set_length(&ct, cpr*npoints, _state); + ae_vector_set_length(&prevc, nx, _state); + minbleiccreate(nx+2, &pcr, &blcstate, _state); + minbleicsetscale(&blcstate, &scr, _state); + minbleicsetbc(&blcstate, &bl, &bu, _state); + minbleicsetcond(&blcstate, (double)(0), (double)(0), epsx, maxits, _state); + for(outeridx=0; outeridx<=maxouterits-1; outeridx++) + { + + /* + * Prepare initial point for algorithm; center coordinates at + * PCR are used to calculate RLo/RHi and update PCR with them. + */ + *rlo = ae_maxrealnumber; + *rhi = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-pcr.ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + *rhi = ae_maxreal(*rhi, v, _state); + *rlo = ae_minreal(*rlo, v, _state); + } + pcr.ptr.p_double[nx+0] = *rlo*0.99999; + pcr.ptr.p_double[nx+1] = *rhi/0.99999; + + /* + * Generate matrix of linear constraints + */ + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j], _state); + } + bi = -v/(double)2; + suboffset = 0; + if( userhi ) + { + dstrow = cpr*i+suboffset; + for(j=0; j<=nx-1; j++) + { + cmatrix.ptr.pp_double[dstrow][j] = pcr.ptr.p_double[j]/(double)2-xy->ptr.pp_double[i][j]; + } + cmatrix.ptr.pp_double[dstrow][nx+0] = (double)(0); + cmatrix.ptr.pp_double[dstrow][nx+1] = -*rhi/(double)2; + cmatrix.ptr.pp_double[dstrow][nx+2] = bi; + ct.ptr.p_int[dstrow] = -1; + inc(&suboffset, _state); + } + if( userlo ) + { + dstrow = cpr*i+suboffset; + for(j=0; j<=nx-1; j++) + { + cmatrix.ptr.pp_double[dstrow][j] = -(pcr.ptr.p_double[j]/(double)2-xy->ptr.pp_double[i][j]); + } + cmatrix.ptr.pp_double[dstrow][nx+0] = *rlo/(double)2; + cmatrix.ptr.pp_double[dstrow][nx+1] = (double)(0); + cmatrix.ptr.pp_double[dstrow][nx+2] = -bi; + ct.ptr.p_int[dstrow] = -1; + inc(&suboffset, _state); + } + ae_assert(suboffset==cpr, "Assertion failed", _state); + } + + /* + * Solve LP subproblem with MinBLEIC + */ + for(j=0; j<=nx-1; j++) + { + prevc.ptr.p_double[j] = pcr.ptr.p_double[j]; + } + minbleicsetlc(&blcstate, &cmatrix, &ct, cpr*npoints, _state); + minbleicrestartfrom(&blcstate, &pcr, _state); + while(minbleiciteration(&blcstate, _state)) + { + if( blcstate.needfg ) + { + inc(&rep->nfev, _state); + blcstate.f = vhi*blcstate.x.ptr.p_double[nx+1]-vlo*blcstate.x.ptr.p_double[nx+0]; + for(j=0; j<=nx-1; j++) + { + blcstate.g.ptr.p_double[j] = (double)(0); + } + blcstate.g.ptr.p_double[nx+0] = -(double)1*vlo; + blcstate.g.ptr.p_double[nx+1] = (double)1*vhi; + continue; + } + } + minbleicresults(&blcstate, &pcr, &blcrep, _state); + ae_assert(blcrep.terminationtype>0, "FitSphereX: unexpected failure of BLEIC solver", _state); + rep->iterationscount = rep->iterationscount+blcrep.iterationscount; + + /* + * Terminate iterations early if we converged + */ + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(prevc.ptr.p_double[j]-pcr.ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + if( ae_fp_less_eq(v,epsx) ) + { + break; + } + } + + /* + * Offload center coordinates from PCR to CX, + * re-calculate exact value of RLo/RHi using CX. + */ + for(j=0; j<=nx-1; j++) + { + cx->ptr.p_double[j] = pcr.ptr.p_double[j]; + } + *rlo = ae_maxrealnumber; + *rhi = (double)(0); + for(i=0; i<=npoints-1; i++) + { + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + *rhi = ae_maxreal(*rhi, v, _state); + *rlo = ae_minreal(*rlo, v, _state); + } + if( !userlo ) + { + *rlo = (double)(0); + } + if( !userhi ) + { + *rhi = (double)(0); + } + ae_frame_leave(_state); + return; + } + + /* + * Oooops...! + */ + ae_assert(ae_false, "FitSphereX: integrity check failed", _state); + } + ae_frame_leave(_state); +} + + +void _fitsphereinternalreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + fitsphereinternalreport *p = (fitsphereinternalreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _fitsphereinternalreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + fitsphereinternalreport *dst = (fitsphereinternalreport*)_dst; + const fitsphereinternalreport *src = (const fitsphereinternalreport*)_src; + dst->nfev = src->nfev; + dst->iterationscount = src->iterationscount; +} + + +void _fitsphereinternalreport_clear(void* _p) +{ + fitsphereinternalreport *p = (fitsphereinternalreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _fitsphereinternalreport_destroy(void* _p) +{ + fitsphereinternalreport *p = (fitsphereinternalreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function builds non-periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + Order of points is important! + N - points count, N>=5 for Akima splines, N>=2 for other types of + splines. + ST - spline type: + * 0 Akima spline + * 1 parabolically terminated Catmull-Rom spline (Tension=0) + * 2 parabolically terminated cubic spline + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2build(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline2interpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xy; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&tmp, 0, sizeof(tmp)); + ae_matrix_init_copy(&xy, _xy, _state, ae_true); + _pspline2interpolant_clear(p); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(st>=0&&st<=2, "PSpline2Build: incorrect spline type!", _state); + ae_assert(pt>=0&&pt<=2, "PSpline2Build: incorrect parameterization type!", _state); + if( st==0 ) + { + ae_assert(n>=5, "PSpline2Build: N<5 (minimum value for Akima splines)!", _state); + } + else + { + ae_assert(n>=2, "PSpline2Build: N<2!", _state); + } + + /* + * Prepare + */ + p->n = n; + p->periodic = ae_false; + ae_vector_set_length(&tmp, n, _state); + + /* + * Build parameterization, check that all parameters are distinct + */ + parametric_pspline2par(&xy, n, pt, &p->p, _state); + ae_assert(aredistinct(&p->p, n, _state), "PSpline2Build: consequent points are too close!", _state); + + /* + * Build splines + */ + if( st==0 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); + } + if( st==1 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); + } + if( st==2 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function builds non-periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3build(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline3interpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xy; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&tmp, 0, sizeof(tmp)); + ae_matrix_init_copy(&xy, _xy, _state, ae_true); + _pspline3interpolant_clear(p); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(st>=0&&st<=2, "PSpline3Build: incorrect spline type!", _state); + ae_assert(pt>=0&&pt<=2, "PSpline3Build: incorrect parameterization type!", _state); + if( st==0 ) + { + ae_assert(n>=5, "PSpline3Build: N<5 (minimum value for Akima splines)!", _state); + } + else + { + ae_assert(n>=2, "PSpline3Build: N<2!", _state); + } + + /* + * Prepare + */ + p->n = n; + p->periodic = ae_false; + ae_vector_set_length(&tmp, n, _state); + + /* + * Build parameterization, check that all parameters are distinct + */ + parametric_pspline3par(&xy, n, pt, &p->p, _state); + ae_assert(aredistinct(&p->p, n, _state), "PSpline3Build: consequent points are too close!", _state); + + /* + * Build splines + */ + if( st==0 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildakima(&p->p, &tmp, n, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildakima(&p->p, &tmp, n, &p->y, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][2], xy.stride, ae_v_len(0,n-1)); + spline1dbuildakima(&p->p, &tmp, n, &p->z, _state); + } + if( st==1 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][2], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->z, _state); + } + if( st==2 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xy.ptr.pp_double[0][2], xy.stride, ae_v_len(0,n-1)); + spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->z, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function builds periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then +back to (X[0],Y[0]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + XY[N-1,0:1] must be different from XY[0,0:1]. + Order of points is important! + N - points count, N>=3 for other types of splines. + ST - spline type: + * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions + * 2 cubic spline with cyclic boundary conditions + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). +* last point of sequence is NOT equal to the first point. You shouldn't + make curve "explicitly periodic" by making them equal. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2buildperiodic(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline2interpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xy; + ae_matrix xyp; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&xyp, 0, sizeof(xyp)); + memset(&tmp, 0, sizeof(tmp)); + ae_matrix_init_copy(&xy, _xy, _state, ae_true); + _pspline2interpolant_clear(p); + ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(st>=1&&st<=2, "PSpline2BuildPeriodic: incorrect spline type!", _state); + ae_assert(pt>=0&&pt<=2, "PSpline2BuildPeriodic: incorrect parameterization type!", _state); + ae_assert(n>=3, "PSpline2BuildPeriodic: N<3!", _state); + + /* + * Prepare + */ + p->n = n; + p->periodic = ae_true; + ae_vector_set_length(&tmp, n+1, _state); + ae_matrix_set_length(&xyp, n+1, 2, _state); + ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy.ptr.pp_double[0][0], 1, ae_v_len(0,1)); + + /* + * Build parameterization, check that all parameters are distinct + */ + parametric_pspline2par(&xyp, n+1, pt, &p->p, _state); + ae_assert(aredistinct(&p->p, n+1, _state), "PSpline2BuildPeriodic: consequent (or first and last) points are too close!", _state); + + /* + * Build splines + */ + if( st==1 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); + spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); + spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); + } + if( st==2 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); + spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); + spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function builds periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) +and then back to (X[0],Y[0],Z[0]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3buildperiodic(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline3interpolant* p, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix xy; + ae_matrix xyp; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&xy, 0, sizeof(xy)); + memset(&xyp, 0, sizeof(xyp)); + memset(&tmp, 0, sizeof(tmp)); + ae_matrix_init_copy(&xy, _xy, _state, ae_true); + _pspline3interpolant_clear(p); + ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(st>=1&&st<=2, "PSpline3BuildPeriodic: incorrect spline type!", _state); + ae_assert(pt>=0&&pt<=2, "PSpline3BuildPeriodic: incorrect parameterization type!", _state); + ae_assert(n>=3, "PSpline3BuildPeriodic: N<3!", _state); + + /* + * Prepare + */ + p->n = n; + p->periodic = ae_true; + ae_vector_set_length(&tmp, n+1, _state); + ae_matrix_set_length(&xyp, n+1, 3, _state); + ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy.ptr.pp_double[0][0], xy.stride, ae_v_len(0,n-1)); + ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy.ptr.pp_double[0][1], xy.stride, ae_v_len(0,n-1)); + ae_v_move(&xyp.ptr.pp_double[0][2], xyp.stride, &xy.ptr.pp_double[0][2], xy.stride, ae_v_len(0,n-1)); + ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy.ptr.pp_double[0][0], 1, ae_v_len(0,2)); + + /* + * Build parameterization, check that all parameters are distinct + */ + parametric_pspline3par(&xyp, n+1, pt, &p->p, _state); + ae_assert(aredistinct(&p->p, n+1, _state), "PSplineBuild2Periodic: consequent (or first and last) points are too close!", _state); + + /* + * Build splines + */ + if( st==1 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); + spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); + spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); + spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->z, _state); + } + if( st==2 ) + { + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n)); + spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n)); + spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state); + ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n)); + spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->z, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function returns vector of parameter values correspoding to points. + +I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we +have + (X[0],Y[0]) = PSpline2Calc(P,U[0]), + (X[1],Y[1]) = PSpline2Calc(P,U[1]), + (X[2],Y[2]) = PSpline2Calc(P,U[2]), + ... + +INPUT PARAMETERS: + P - parametric spline interpolant + +OUTPUT PARAMETERS: + N - array size + T - array[0..N-1] + + +NOTES: +* for non-periodic splines U[0]=0, U[0]n>=2, "PSpline2ParameterValues: internal error!", _state); + *n = p->n; + ae_vector_set_length(t, *n, _state); + ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); + t->ptr.p_double[0] = (double)(0); + if( !p->periodic ) + { + t->ptr.p_double[*n-1] = (double)(1); + } +} + + +/************************************************************************* +This function returns vector of parameter values correspoding to points. + +Same as PSpline2ParameterValues(), but for 3D. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3parametervalues(const pspline3interpolant* p, + ae_int_t* n, + /* Real */ ae_vector* t, + ae_state *_state) +{ + + *n = 0; + ae_vector_clear(t); + + ae_assert(p->n>=2, "PSpline3ParameterValues: internal error!", _state); + *n = p->n; + ae_vector_set_length(t, *n, _state); + ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1)); + t->ptr.p_double[0] = (double)(0); + if( !p->periodic ) + { + t->ptr.p_double[*n-1] = (double)(1); + } +} + + +/************************************************************************* +This function calculates the value of the parametric spline for a given +value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2calc(const pspline2interpolant* p, + double t, + double* x, + double* y, + ae_state *_state) +{ + + *x = 0.0; + *y = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + *x = spline1dcalc(&p->x, t, _state); + *y = spline1dcalc(&p->y, t, _state); +} + + +/************************************************************************* +This function calculates the value of the parametric spline for a given +value of parameter T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + Z - Z-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3calc(const pspline3interpolant* p, + double t, + double* x, + double* y, + double* z, + ae_state *_state) +{ + + *x = 0.0; + *y = 0.0; + *z = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + *x = spline1dcalc(&p->x, t, _state); + *y = spline1dcalc(&p->y, t, _state); + *z = spline1dcalc(&p->z, t, _state); +} + + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + +NOTE: + X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2tangent(const pspline2interpolant* p, + double t, + double* x, + double* y, + ae_state *_state) +{ + double v; + double v0; + double v1; + + *x = 0.0; + *y = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + pspline2diff(p, t, &v0, x, &v1, y, _state); + if( ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)) ) + { + + /* + * this code is a bit more complex than X^2+Y^2 to avoid + * overflow for large values of X and Y. + */ + v = safepythag2(*x, *y, _state); + *x = *x/v; + *y = *y/v; + } +} + + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + Z - Z-component of tangent vector (normalized) + +NOTE: + X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3tangent(const pspline3interpolant* p, + double t, + double* x, + double* y, + double* z, + ae_state *_state) +{ + double v; + double v0; + double v1; + double v2; + + *x = 0.0; + *y = 0.0; + *z = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + pspline3diff(p, t, &v0, x, &v1, y, &v2, z, _state); + if( (ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))||ae_fp_neq(*z,(double)(0)) ) + { + v = safepythag3(*x, *y, *z, _state); + *x = *x/v; + *y = *y/v; + *z = *z/v; + } +} + + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff(const pspline2interpolant* p, + double t, + double* x, + double* dx, + double* y, + double* dy, + ae_state *_state) +{ + double d2s; + + *x = 0.0; + *dx = 0.0; + *y = 0.0; + *dy = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + spline1ddiff(&p->x, t, x, dx, &d2s, _state); + spline1ddiff(&p->y, t, y, dy, &d2s, _state); +} + + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + Z - Z-value + DZ - Z-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff(const pspline3interpolant* p, + double t, + double* x, + double* dx, + double* y, + double* dy, + double* z, + double* dz, + ae_state *_state) +{ + double d2s; + + *x = 0.0; + *dx = 0.0; + *y = 0.0; + *dy = 0.0; + *z = 0.0; + *dz = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + spline1ddiff(&p->x, t, x, dx, &d2s, _state); + spline1ddiff(&p->y, t, y, dy, &d2s, _state); + spline1ddiff(&p->z, t, z, dz, &d2s, _state); +} + + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff2(const pspline2interpolant* p, + double t, + double* x, + double* dx, + double* d2x, + double* y, + double* dy, + double* d2y, + ae_state *_state) +{ + + *x = 0.0; + *dx = 0.0; + *d2x = 0.0; + *y = 0.0; + *dy = 0.0; + *d2y = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + spline1ddiff(&p->x, t, x, dx, d2x, _state); + spline1ddiff(&p->y, t, y, dy, d2y, _state); +} + + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + Z - Z-value + DZ - derivative + D2Z - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff2(const pspline3interpolant* p, + double t, + double* x, + double* dx, + double* d2x, + double* y, + double* dy, + double* d2y, + double* z, + double* dz, + double* d2z, + ae_state *_state) +{ + + *x = 0.0; + *dx = 0.0; + *d2x = 0.0; + *y = 0.0; + *dy = 0.0; + *d2y = 0.0; + *z = 0.0; + *dz = 0.0; + *d2z = 0.0; + + if( p->periodic ) + { + t = t-(double)ae_ifloor(t, _state); + } + spline1ddiff(&p->x, t, x, dx, d2x, _state); + spline1ddiff(&p->y, t, y, dy, d2y, _state); + spline1ddiff(&p->z, t, z, dz, d2z, _state); +} + + +/************************************************************************* +This function calculates arc length, i.e. length of curve between t=a +and t=b. + +INPUT PARAMETERS: + P - parametric spline interpolant + A,B - parameter values corresponding to arc ends: + * B>A will result in positive length returned + * Bx, state.x, &sx, &dsx, &d2sx, _state); + spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); + state.f = safepythag2(dsx, dsy, _state); + } + autogkresults(&state, &result, &rep, _state); + ae_assert(rep.terminationtype>0, "PSpline2ArcLength: internal error!", _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function calculates arc length, i.e. length of curve between t=a +and t=b. + +INPUT PARAMETERS: + P - parametric spline interpolant + A,B - parameter values corresponding to arc ends: + * B>A will result in positive length returned + * Bx, state.x, &sx, &dsx, &d2sx, _state); + spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state); + spline1ddiff(&p->z, state.x, &sz, &dsz, &d2sz, _state); + state.f = safepythag3(dsx, dsy, dsz, _state); + } + autogkresults(&state, &result, &rep, _state); + ae_assert(rep.terminationtype>0, "PSpline3ArcLength: internal error!", _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This subroutine fits piecewise linear curve to points with Ramer-Douglas- +Peucker algorithm. This function performs PARAMETRIC fit, i.e. it can be +used to fit curves like circles. + +On input it accepts dataset which describes parametric multidimensional +curve X(t), with X being vector, and t taking values in [0,N), where N is +a number of points in dataset. As result, it returns reduced dataset X2, +which can be used to build parametric curve X2(t), which approximates +X(t) with desired precision (or has specified number of sections). + + +INPUT PARAMETERS: + X - array of multidimensional points: + * at least N elements, leading N elements are used if more + than N elements were specified + * order of points is IMPORTANT because it is parametric + fit + * each row of array is one point which has D coordinates + N - number of elements in X + D - number of dimensions (elements per row of X) + StopM - stopping condition - desired number of sections: + * at most M sections are generated by this function + * less than M sections can be generated if we have N=0, "LSTFitPiecewiseLinearParametricRDP: N<0", _state); + ae_assert(d>=1, "LSTFitPiecewiseLinearParametricRDP: D<=0", _state); + ae_assert(stopm>=0, "LSTFitPiecewiseLinearParametricRDP: StopM<1", _state); + ae_assert(ae_isfinite(stopeps, _state)&&ae_fp_greater_eq(stopeps,(double)(0)), "LSTFitPiecewiseLinearParametricRDP: StopEps<0 or is infinite", _state); + ae_assert(x->rows>=n, "LSTFitPiecewiseLinearParametricRDP: Rows(X)cols>=d, "LSTFitPiecewiseLinearParametricRDP: Cols(X)ptr.pp_double[i][j],x->ptr.pp_double[0][j]); + } + } + if( allsame ) + { + *nsections = 0; + ae_frame_leave(_state); + return; + } + + /* + * Prepare first section + */ + parametric_rdpanalyzesectionpar(x, 0, n-1, d, &worstidx, &worsterror, _state); + ae_matrix_set_length(§ions, n, 4, _state); + ae_vector_set_length(&heaperrors, n, _state); + ae_vector_set_length(&heaptags, n, _state); + *nsections = 1; + sections.ptr.pp_double[0][0] = (double)(0); + sections.ptr.pp_double[0][1] = (double)(n-1); + sections.ptr.pp_double[0][2] = (double)(worstidx); + sections.ptr.pp_double[0][3] = worsterror; + heaperrors.ptr.p_double[0] = worsterror; + heaptags.ptr.p_int[0] = 0; + ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state); + + /* + * Main loop. + * Repeatedly find section with worst error and divide it. + * Terminate after M-th section, or because of other reasons (see loop internals). + */ + for(;;) + { + + /* + * Break loop if one of the stopping conditions was met. + * Store index of worst section to K. + */ + if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) ) + { + break; + } + if( ae_fp_greater(stopeps,(double)(0))&&ae_fp_less_eq(heaperrors.ptr.p_double[0],stopeps) ) + { + break; + } + if( stopm>0&&*nsections>=stopm ) + { + break; + } + k = heaptags.ptr.p_int[0]; + + /* + * K-th section is divided in two: + * * first one spans interval from X[Sections[K,0]] to X[Sections[K,2]] + * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]] + * + * First section is stored at K-th position, second one is appended to the table. + * Then we update heap which stores pairs of (error,section_index) + */ + k0 = ae_round(sections.ptr.pp_double[k][0], _state); + k1 = ae_round(sections.ptr.pp_double[k][1], _state); + k2 = ae_round(sections.ptr.pp_double[k][2], _state); + parametric_rdpanalyzesectionpar(x, k0, k2, d, &idx0, &e0, _state); + parametric_rdpanalyzesectionpar(x, k2, k1, d, &idx1, &e1, _state); + sections.ptr.pp_double[k][0] = (double)(k0); + sections.ptr.pp_double[k][1] = (double)(k2); + sections.ptr.pp_double[k][2] = (double)(idx0); + sections.ptr.pp_double[k][3] = e0; + tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state); + sections.ptr.pp_double[*nsections][0] = (double)(k2); + sections.ptr.pp_double[*nsections][1] = (double)(k1); + sections.ptr.pp_double[*nsections][2] = (double)(idx1); + sections.ptr.pp_double[*nsections][3] = e1; + tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state); + } + + /* + * Convert from sections to indexes + */ + ae_vector_set_length(&buf0, *nsections+1, _state); + for(i=0; i<=*nsections-1; i++) + { + buf0.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state)); + } + buf0.ptr.p_double[*nsections] = (double)(n-1); + tagsortfast(&buf0, &buf1, *nsections+1, _state); + ae_vector_set_length(idx2, *nsections+1, _state); + for(i=0; i<=*nsections; i++) + { + idx2->ptr.p_int[i] = ae_round(buf0.ptr.p_double[i], _state); + } + ae_assert(idx2->ptr.p_int[0]==0, "RDP algorithm: integrity check failed", _state); + ae_assert(idx2->ptr.p_int[*nsections]==n-1, "RDP algorithm: integrity check failed", _state); + + /* + * Output sections: + * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections + * * last element of X2/Y2 is filled by right boundary of rightmost section + * * X2/Y2 is sorted by ascending of X2 + */ + ae_matrix_set_length(x2, *nsections+1, d, _state); + for(i=0; i<=*nsections; i++) + { + for(j=0; j<=d-1; j++) + { + x2->ptr.pp_double[i][j] = x->ptr.pp_double[idx2->ptr.p_int[i]][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Builds non-periodic parameterization for 2-dimensional spline +*************************************************************************/ +static void parametric_pspline2par(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t pt, + /* Real */ ae_vector* p, + ae_state *_state) +{ + double v; + ae_int_t i; + + ae_vector_clear(p); + + ae_assert(pt>=0&&pt<=2, "PSpline2Par: internal error!", _state); + + /* + * Build parameterization: + * * fill by non-normalized values + * * normalize them so we have P[0]=0, P[N-1]=1. + */ + ae_vector_set_length(p, n, _state); + if( pt==0 ) + { + for(i=0; i<=n-1; i++) + { + p->ptr.p_double[i] = (double)(i); + } + } + if( pt==1 ) + { + p->ptr.p_double[0] = (double)(0); + for(i=1; i<=n-1; i++) + { + p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state); + } + } + if( pt==2 ) + { + p->ptr.p_double[0] = (double)(0); + for(i=1; i<=n-1; i++) + { + p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state), _state); + } + } + v = (double)1/p->ptr.p_double[n-1]; + ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); +} + + +/************************************************************************* +Builds non-periodic parameterization for 3-dimensional spline +*************************************************************************/ +static void parametric_pspline3par(/* Real */ const ae_matrix* xy, + ae_int_t n, + ae_int_t pt, + /* Real */ ae_vector* p, + ae_state *_state) +{ + double v; + ae_int_t i; + + ae_vector_clear(p); + + ae_assert(pt>=0&&pt<=2, "PSpline3Par: internal error!", _state); + + /* + * Build parameterization: + * * fill by non-normalized values + * * normalize them so we have P[0]=0, P[N-1]=1. + */ + ae_vector_set_length(p, n, _state); + if( pt==0 ) + { + for(i=0; i<=n-1; i++) + { + p->ptr.p_double[i] = (double)(i); + } + } + if( pt==1 ) + { + p->ptr.p_double[0] = (double)(0); + for(i=1; i<=n-1; i++) + { + p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state); + } + } + if( pt==2 ) + { + p->ptr.p_double[0] = (double)(0); + for(i=1; i<=n-1; i++) + { + p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state), _state); + } + } + v = (double)1/p->ptr.p_double[n-1]; + ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v); +} + + +/************************************************************************* +This function analyzes section of curve for processing by RDP algorithm: +given set of points X,Y with indexes [I0,I1] it returns point with +worst deviation from linear model (PARAMETRIC version which sees curve +as X(t) with vector X). + +Input parameters: + XY - array + I0,I1 - interval (boundaries included) to process + D - number of dimensions + +OUTPUT PARAMETERS: + WorstIdx - index of worst point + WorstError - error at worst point + +NOTE: this function guarantees that it returns exactly zero for a section + with less than 3 points. + + -- ALGLIB PROJECT -- + Copyright 02.10.2014 by Bochkanov Sergey +*************************************************************************/ +static void parametric_rdpanalyzesectionpar(/* Real */ const ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t d, + ae_int_t* worstidx, + double* worsterror, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double d2; + double ts; + double vv; + + *worstidx = 0; + *worsterror = 0.0; + + + /* + * Quick exit for 0, 1, 2 points + */ + if( i1-i0+1<3 ) + { + *worstidx = i0; + *worsterror = 0.0; + return; + } + + /* + * Estimate D2 - squared distance between XY[I1] and XY[I0]. + * In case D2=0 handle it as special case. + */ + d2 = 0.0; + for(j=0; j<=d-1; j++) + { + d2 = d2+ae_sqr(xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j], _state); + } + if( ae_fp_eq(d2,(double)(0)) ) + { + + /* + * First and last points are equal, interval evaluation is + * trivial - we just calculate distance from all points to + * the first/last one. + */ + *worstidx = i0; + *worsterror = 0.0; + for(i=i0+1; i<=i1-1; i++) + { + vv = 0.0; + for(j=0; j<=d-1; j++) + { + v = xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + if( ae_fp_greater(vv,*worsterror) ) + { + *worsterror = vv; + *worstidx = i; + } + } + return; + } + + /* + * General case + * + * Current section of curve is modeled as x(t) = d*t+c, where + * d = XY[I1]-XY[I0] + * c = XY[I0] + * t is in [0,1] + */ + *worstidx = i0; + *worsterror = 0.0; + for(i=i0+1; i<=i1-1; i++) + { + + /* + * Determine t_s - parameter value for projected point. + */ + ts = (double)(i-i0)/(double)(i1-i0); + + /* + * Estimate error norm + */ + vv = 0.0; + for(j=0; j<=d-1; j++) + { + v = (xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j])*ts-(xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j]); + vv = vv+ae_sqr(v, _state); + } + vv = ae_sqrt(vv, _state); + if( ae_fp_greater(vv,*worsterror) ) + { + *worsterror = vv; + *worstidx = i; + } + } +} + + +void _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + pspline2interpolant *p = (pspline2interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic); + _spline1dinterpolant_init(&p->x, _state, make_automatic); + _spline1dinterpolant_init(&p->y, _state, make_automatic); +} + + +void _pspline2interpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + pspline2interpolant *dst = (pspline2interpolant*)_dst; + const pspline2interpolant *src = (const pspline2interpolant*)_src; + dst->n = src->n; + dst->periodic = src->periodic; + ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic); +} + + +void _pspline2interpolant_clear(void* _p) +{ + pspline2interpolant *p = (pspline2interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->p); + _spline1dinterpolant_clear(&p->x); + _spline1dinterpolant_clear(&p->y); +} + + +void _pspline2interpolant_destroy(void* _p) +{ + pspline2interpolant *p = (pspline2interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->p); + _spline1dinterpolant_destroy(&p->x); + _spline1dinterpolant_destroy(&p->y); +} + + +void _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + pspline3interpolant *p = (pspline3interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic); + _spline1dinterpolant_init(&p->x, _state, make_automatic); + _spline1dinterpolant_init(&p->y, _state, make_automatic); + _spline1dinterpolant_init(&p->z, _state, make_automatic); +} + + +void _pspline3interpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + pspline3interpolant *dst = (pspline3interpolant*)_dst; + const pspline3interpolant *src = (const pspline3interpolant*)_src; + dst->n = src->n; + dst->periodic = src->periodic; + ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic); + _spline1dinterpolant_init_copy(&dst->z, &src->z, _state, make_automatic); +} + + +void _pspline3interpolant_clear(void* _p) +{ + pspline3interpolant *p = (pspline3interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->p); + _spline1dinterpolant_clear(&p->x); + _spline1dinterpolant_clear(&p->y); + _spline1dinterpolant_clear(&p->z); +} + + +void _pspline3interpolant_destroy(void* _p) +{ + pspline3interpolant *p = (pspline3interpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->p); + _spline1dinterpolant_destroy(&p->x); + _spline1dinterpolant_destroy(&p->y); + _spline1dinterpolant_destroy(&p->z); +} + + +#endif +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX=2 or NX=3). + +INPUT PARAMETERS: + NX - dimension of the space, NX=2 or NX=3 + NY - function dimension, NY>=1 + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1create(ae_int_t nx, + ae_int_t ny, + rbfv1model* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + _rbfv1model_clear(s); + + ae_assert(nx==2||nx==3, "RBFCreate: NX<>2 and NX<>3", _state); + ae_assert(ny>=1, "RBFCreate: NY<1", _state); + s->nx = nx; + s->ny = ny; + s->nl = 0; + s->nc = 0; + ae_matrix_set_length(&s->v, ny, rbfv1_mxnx+1, _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + s->v.ptr.pp_double[i][j] = (double)(0); + } + } + s->rmax = (double)(0); +} + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2016 by Sergey Bochkanov +*************************************************************************/ +void rbfv1createcalcbuffer(const rbfv1model* s, + rbfv1calcbuffer* buf, + ae_state *_state) +{ + + _rbfv1calcbuffer_clear(buf); + + kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state); +} + + +/************************************************************************* +This function builds RBF model and returns report (contains some +information which can be used for evaluation of the algorithm properties). + +Call to this function modifies RBF model by calculating its centers/radii/ +weights and saving them into RBFModel structure. Initially RBFModel +contain zero coefficients, but after call to this function we will have +coefficients which were calculated in order to fit our dataset. + +After you called this function you can call RBFCalc(), RBFGridCalc() and +other model calculation functions. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + Rep - report: + * Rep.TerminationType: + * -5 - non-distinct basis function centers were detected, + interpolation aborted + * -4 - nonconvergence of the internal SVD solver + * 1 - successful termination + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the LSQR solver + * Rep.NMV - number of matrix-vector products + * Rep.ARows - rows count for the system matrix + * Rep.ACols - columns count for the system matrix + * Rep.ANNZ - number of significantly non-zero elements + (elements above some algorithm-determined threshold) + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1buildmodel(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + ae_int_t aterm, + ae_int_t algorithmtype, + ae_int_t nlayers, + double radvalue, + double radzvalue, + double lambdav, + double epsort, + double epserr, + ae_int_t maxits, + rbfv1model* s, + rbfv1report* rep, + ae_state *_state) +{ + ae_frame _frame_block; + kdtree tree; + kdtree ctree; + ae_vector dist; + ae_vector xcx; + ae_matrix a; + ae_matrix v; + ae_matrix omega; + ae_matrix residualy; + ae_vector radius; + ae_matrix xc; + ae_int_t nc; + double rmax; + ae_vector tags; + ae_vector ctags; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t snnz; + ae_vector tmp0; + ae_vector tmp1; + ae_int_t layerscnt; + ae_bool modelstatus; + + ae_frame_make(_state, &_frame_block); + memset(&tree, 0, sizeof(tree)); + memset(&ctree, 0, sizeof(ctree)); + memset(&dist, 0, sizeof(dist)); + memset(&xcx, 0, sizeof(xcx)); + memset(&a, 0, sizeof(a)); + memset(&v, 0, sizeof(v)); + memset(&omega, 0, sizeof(omega)); + memset(&residualy, 0, sizeof(residualy)); + memset(&radius, 0, sizeof(radius)); + memset(&xc, 0, sizeof(xc)); + memset(&tags, 0, sizeof(tags)); + memset(&ctags, 0, sizeof(ctags)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + _rbfv1report_clear(rep); + _kdtree_init(&tree, _state, ae_true); + _kdtree_init(&ctree, _state, ae_true); + ae_vector_init(&dist, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&omega, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&radius, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tags, 0, DT_INT, _state, ae_true); + ae_vector_init(&ctags, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + + ae_assert(s->nx==2||s->nx==3, "RBFBuildModel: S.NX<>2 or S.NX<>3!", _state); + + /* + * Quick exit when we have no points + */ + if( n==0 ) + { + rep->terminationtype = 1; + rep->iterationscount = 0; + rep->nmv = 0; + rep->arows = 0; + rep->acols = 0; + kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state); + ae_matrix_set_length(&s->xc, 0, 0, _state); + ae_matrix_set_length(&s->wr, 0, 0, _state); + s->nc = 0; + s->rmax = (double)(0); + ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + s->v.ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * General case, N>0 + */ + rep->annz = 0; + rep->iterationscount = 0; + rep->nmv = 0; + ae_vector_set_length(&xcx, rbfv1_mxnx, _state); + + /* + * First model in a sequence - linear model. + * Residuals from linear regression are stored in the ResidualY variable + * (used later to build RBF models). + */ + ae_matrix_set_length(&residualy, n, s->ny, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=s->ny-1; j++) + { + residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j]; + } + } + if( !rbfv1_rbfv1buildlinearmodel(x, &residualy, n, s->ny, aterm, &v, _state) ) + { + rep->terminationtype = -5; + ae_frame_leave(_state); + return; + } + + /* + * Handle special case: multilayer model with NLayers=0. + * Quick exit. + */ + if( algorithmtype==2&&nlayers==0 ) + { + rep->terminationtype = 1; + rep->iterationscount = 0; + rep->nmv = 0; + rep->arows = 0; + rep->acols = 0; + kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state); + ae_matrix_set_length(&s->xc, 0, 0, _state); + ae_matrix_set_length(&s->wr, 0, 0, _state); + s->nc = 0; + s->rmax = (double)(0); + ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); + return; + } + + /* + * Second model in a sequence - RBF term. + * + * NOTE: assignments below are not necessary, but without them + * MSVC complains about unitialized variables. + */ + nc = 0; + rmax = (double)(0); + layerscnt = 0; + modelstatus = ae_false; + if( algorithmtype==1 ) + { + + /* + * Add RBF model. + * This model uses local KD-trees to speed-up nearest neighbor searches. + */ + nc = n; + ae_matrix_set_length(&xc, nc, rbfv1_mxnx, _state); + for(i=0; i<=nc-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xc.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]; + } + } + rmax = (double)(0); + ae_vector_set_length(&radius, nc, _state); + ae_vector_set_length(&ctags, nc, _state); + for(i=0; i<=nc-1; i++) + { + ctags.ptr.p_int[i] = i; + } + kdtreebuildtagged(&xc, &ctags, nc, rbfv1_mxnx, 0, 2, &ctree, _state); + if( nc==0 ) + { + rmax = (double)(1); + } + else + { + if( nc==1 ) + { + radius.ptr.p_double[0] = radvalue; + rmax = radius.ptr.p_double[0]; + } + else + { + + /* + * NC>1, calculate radii using distances to nearest neigbors + */ + for(i=0; i<=nc-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xcx.ptr.p_double[j] = xc.ptr.pp_double[i][j]; + } + if( kdtreequeryknn(&ctree, &xcx, 1, ae_false, _state)>0 ) + { + kdtreequeryresultsdistances(&ctree, &dist, _state); + radius.ptr.p_double[i] = radvalue*dist.ptr.p_double[0]; + } + else + { + + /* + * No neighbors found (it will happen when we have only one center). + * Initialize radius with default value. + */ + radius.ptr.p_double[i] = 1.0; + } + } + + /* + * Apply filtering + */ + rvectorsetlengthatleast(&tmp0, nc, _state); + for(i=0; i<=nc-1; i++) + { + tmp0.ptr.p_double[i] = radius.ptr.p_double[i]; + } + tagsortfast(&tmp0, &tmp1, nc, _state); + for(i=0; i<=nc-1; i++) + { + radius.ptr.p_double[i] = ae_minreal(radius.ptr.p_double[i], radzvalue*tmp0.ptr.p_double[nc/2], _state); + } + + /* + * Calculate RMax, check that all radii are non-zero + */ + for(i=0; i<=nc-1; i++) + { + rmax = ae_maxreal(rmax, radius.ptr.p_double[i], _state); + } + for(i=0; i<=nc-1; i++) + { + if( ae_fp_eq(radius.ptr.p_double[i],(double)(0)) ) + { + rep->terminationtype = -5; + ae_frame_leave(_state); + return; + } + } + } + } + ivectorsetlengthatleast(&tags, n, _state); + for(i=0; i<=n-1; i++) + { + tags.ptr.p_int[i] = i; + } + kdtreebuildtagged(x, &tags, n, rbfv1_mxnx, 0, 2, &tree, _state); + rbfv1_buildrbfmodellsqr(x, &residualy, &xc, &radius, n, nc, s->ny, &tree, &ctree, epsort, epserr, maxits, &rep->annz, &snnz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); + layerscnt = 1; + modelstatus = ae_true; + } + if( algorithmtype==2 ) + { + rmax = radvalue; + rbfv1_buildrbfmlayersmodellsqr(x, &residualy, &xc, radvalue, &radius, n, &nc, s->ny, nlayers, &ctree, 1.0E-6, 1.0E-6, 50, lambdav, &rep->annz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state); + layerscnt = nlayers; + modelstatus = ae_true; + } + ae_assert(modelstatus, "RBFBuildModel: integrity error", _state); + if( rep->terminationtype<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Model is built + */ + s->nc = nc/layerscnt; + s->rmax = rmax; + s->nl = layerscnt; + ae_matrix_set_length(&s->xc, s->nc, rbfv1_mxnx, _state); + ae_matrix_set_length(&s->wr, s->nc, 1+s->nl*s->ny, _state); + ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state); + for(i=0; i<=s->nc-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + s->xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]; + } + } + ivectorsetlengthatleast(&tags, s->nc, _state); + for(i=0; i<=s->nc-1; i++) + { + tags.ptr.p_int[i] = i; + } + kdtreebuildtagged(&s->xc, &tags, s->nc, rbfv1_mxnx, 0, 2, &s->tree, _state); + for(i=0; i<=s->nc-1; i++) + { + s->wr.ptr.pp_double[i][0] = radius.ptr.p_double[i]; + for(k=0; k<=layerscnt-1; k++) + { + for(j=0; j<=s->ny-1; j++) + { + s->wr.ptr.pp_double[i][1+k*s->ny+j] = omega.ptr.pp_double[k*s->nc+i][j]; + } + } + } + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; + } + } + rep->terminationtype = 1; + rep->arows = n; + rep->acols = s->nc; + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv1alloc(ae_serializer* s, + const rbfv1model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + kdtreealloc(s, &model->tree, _state); + allocrealmatrix(s, &model->xc, -1, -1, _state); + allocrealmatrix(s, &model->wr, -1, -1, _state); + ae_serializer_alloc_entry(s); + allocrealmatrix(s, &model->v, -1, -1, _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv1serialize(ae_serializer* s, + const rbfv1model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_serialize_int(s, model->nx, _state); + ae_serializer_serialize_int(s, model->ny, _state); + ae_serializer_serialize_int(s, model->nc, _state); + ae_serializer_serialize_int(s, model->nl, _state); + kdtreeserialize(s, &model->tree, _state); + serializerealmatrix(s, &model->xc, -1, -1, _state); + serializerealmatrix(s, &model->wr, -1, -1, _state); + ae_serializer_serialize_double(s, model->rmax, _state); + serializerealmatrix(s, &model->v, -1, -1, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv1unserialize(ae_serializer* s, + rbfv1model* model, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + + _rbfv1model_clear(model); + + + /* + * Unserialize primary model parameters, initialize model. + * + * It is necessary to call RBFCreate() because some internal fields + * which are NOT unserialized will need initialization. + */ + ae_serializer_unserialize_int(s, &nx, _state); + ae_serializer_unserialize_int(s, &ny, _state); + rbfv1create(nx, ny, model, _state); + ae_serializer_unserialize_int(s, &model->nc, _state); + ae_serializer_unserialize_int(s, &model->nl, _state); + kdtreeunserialize(s, &model->tree, _state); + unserializerealmatrix(s, &model->xc, _state); + unserializerealmatrix(s, &model->wr, _state); + ae_serializer_unserialize_double(s, &model->rmax, _state); + unserializerealmatrix(s, &model->v, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=2 +(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +If you want to calculate function values many times, consider using +RBFGridCalc2(), which is far more efficient than many subsequent calls to +RBFCalc2(). + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfv1calc2(rbfv1model* s, double x0, double x1, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t lx; + ae_int_t tg; + double d2; + double t; + double bfcur; + double rcur; + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); + if( s->ny!=1||s->nx!=2 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][rbfv1_mxnx]; + if( s->nc==0 ) + { + return result; + } + rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + s->calcbufxcx.ptr.p_double[i] = 0.0; + } + s->calcbufxcx.ptr.p_double[0] = x0; + s->calcbufxcx.ptr.p_double[1] = x1; + lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); + kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); + for(i=0; i<=lx-1; i++) + { + tg = s->calcbuftags.ptr.p_int[i]; + d2 = ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state); + rcur = s->wr.ptr.pp_double[tg][0]; + bfcur = ae_exp(-d2/(rcur*rcur), _state); + for(j=0; j<=s->nl-1; j++) + { + result = result+bfcur*s->wr.ptr.pp_double[tg][1+j]; + rcur = 0.5*rcur; + t = bfcur*bfcur; + bfcur = t*t; + } + } + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=3 +(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfv1calc3(rbfv1model* s, + double x0, + double x1, + double x2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t lx; + ae_int_t tg; + double t; + double rcur; + double bf; + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); + if( s->ny!=1||s->nx!=3 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][rbfv1_mxnx]; + if( s->nc==0 ) + { + return result; + } + + /* + * calculating value for F(X) + */ + rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + s->calcbufxcx.ptr.p_double[i] = 0.0; + } + s->calcbufxcx.ptr.p_double[0] = x0; + s->calcbufxcx.ptr.p_double[1] = x1; + s->calcbufxcx.ptr.p_double[2] = x2; + lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); + kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); + for(i=0; i<=lx-1; i++) + { + tg = s->calcbuftags.ptr.p_int[i]; + rcur = s->wr.ptr.pp_double[tg][0]; + bf = ae_exp(-(ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state)+ae_sqr(x2-s->calcbufx.ptr.pp_double[i][2], _state))/ae_sqr(rcur, _state), _state); + for(j=0; j<=s->nl-1; j++) + { + result = result+bf*s->wr.ptr.pp_double[tg][1+j]; + t = bf*bf; + bf = t*t; + } + } + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +Same as RBFCalc(), but does not reallocate Y when in is large enough to +store function values. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1calcbuf(rbfv1model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t lx; + ae_int_t tg; + double t; + double rcur; + double bf; + + + ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx]; + for(j=0; j<=s->nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + if( s->nc==0 ) + { + return; + } + rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + s->calcbufxcx.ptr.p_double[i] = 0.0; + } + for(i=0; i<=s->nx-1; i++) + { + s->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; + } + lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreequeryresultsx(&s->tree, &s->calcbufx, _state); + kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=lx-1; j++) + { + tg = s->calcbuftags.ptr.p_int[j]; + rcur = s->wr.ptr.pp_double[tg][0]; + bf = ae_exp(-(ae_sqr(s->calcbufxcx.ptr.p_double[0]-s->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[1]-s->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[2]-s->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state); + for(k=0; k<=s->nl-1; k++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i]; + t = bf*bf; + bf = t*t; + } + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point, using +external buffer object (internal temporaries of RBF model are not +modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1tscalcbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t lx; + ae_int_t tg; + double t; + double rcur; + double bf; + + + ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx]; + for(j=0; j<=s->nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + if( s->nc==0 ) + { + return; + } + rvectorsetlengthatleast(&buf->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = 0.0; + } + for(i=0; i<=s->nx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; + } + lx = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, &buf->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreetsqueryresultsx(&s->tree, &buf->requestbuffer, &buf->calcbufx, _state); + kdtreetsqueryresultstags(&s->tree, &buf->requestbuffer, &buf->calcbuftags, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=lx-1; j++) + { + tg = buf->calcbuftags.ptr.p_int[j]; + rcur = s->wr.ptr.pp_double[tg][0]; + bf = ae_exp(-(ae_sqr(buf->calcbufxcx.ptr.p_double[0]-buf->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[1]-buf->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[2]-buf->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state); + for(k=0; k<=s->nl-1; k++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i]; + t = bf*bf; + bf = t*t; + } + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its derivatives, using external buffer object (internal temporaries of the +RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv1tsdiffbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t kk; + ae_int_t lx; + ae_int_t tg; + double t; + double rcur; + double invrcur2; + double f; + double df; + double w; + + + ae_assert(x->cnt>=s->nx, "RBFDiffBuf: Length(X)nx, _state), "RBFDiffBuf: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx]; + for(j=0; j<=s->nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*s->nx+j] = s->v.ptr.pp_double[i][j]; + } + } + if( s->nc==0 ) + { + return; + } + rvectorsetlengthatleast(&buf->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = 0.0; + } + for(i=0; i<=s->nx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; + } + lx = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, &buf->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreetsqueryresultsx(&s->tree, &buf->requestbuffer, &buf->calcbufx, _state); + kdtreetsqueryresultstags(&s->tree, &buf->requestbuffer, &buf->calcbuftags, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=lx-1; j++) + { + tg = buf->calcbuftags.ptr.p_int[j]; + rcur = s->wr.ptr.pp_double[tg][0]; + invrcur2 = (double)1/(rcur*rcur); + f = ae_exp(-(ae_sqr(buf->calcbufxcx.ptr.p_double[0]-buf->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[1]-buf->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[2]-buf->calcbufx.ptr.pp_double[j][2], _state))*invrcur2, _state); + df = -f; + for(k=0; k<=s->nl-1; k++) + { + w = s->wr.ptr.pp_double[tg][1+k*s->ny+i]; + y->ptr.p_double[i] = y->ptr.p_double[i]+f*w; + for(kk=0; kk<=s->nx-1; kk++) + { + dy->ptr.p_double[i*s->nx+kk] = dy->ptr.p_double[i*s->nx+kk]+w*df*invrcur2*(double)2*(buf->calcbufxcx.ptr.p_double[kk]-buf->calcbufx.ptr.pp_double[j][kk]); + } + t = f*f; + f = t*t; + df = -f; + invrcur2 = (double)4*invrcur2; + } + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its first/second derivatives, using external buffer object (internal +temporaries of the RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY, D2Y - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + D2Y - derivatives, array[NY*NX*NX]. D2Y is not reallocated when + it is larger than NY*NX*NX. + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv1tshessbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + ae_int_t i1; + ae_int_t lx; + ae_int_t tg; + double t; + double rcur; + double invrcur2; + double f; + double df; + double d2f; + double w; + + + ae_assert(x->cnt>=s->nx, "RBFDiffBuf: Length(X)nx, _state), "RBFDiffBuf: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + if( d2y->cntny*s->nx*s->nx ) + { + ae_vector_set_length(d2y, s->ny*s->nx*s->nx, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx]; + for(j=0; j<=s->nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*s->nx+j] = s->v.ptr.pp_double[i][j]; + } + } + rsetv(s->ny*s->nx*s->nx, 0.0, d2y, _state); + if( s->nc==0 ) + { + return; + } + rvectorsetlengthatleast(&buf->calcbufxcx, rbfv1_mxnx, _state); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = 0.0; + } + for(i=0; i<=s->nx-1; i++) + { + buf->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i]; + } + lx = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, &buf->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state); + kdtreetsqueryresultsx(&s->tree, &buf->requestbuffer, &buf->calcbufx, _state); + kdtreetsqueryresultstags(&s->tree, &buf->requestbuffer, &buf->calcbuftags, _state); + for(i=0; i<=s->ny-1; i++) + { + for(j=0; j<=lx-1; j++) + { + tg = buf->calcbuftags.ptr.p_int[j]; + rcur = s->wr.ptr.pp_double[tg][0]; + invrcur2 = (double)1/(rcur*rcur); + f = ae_exp(-(ae_sqr(buf->calcbufxcx.ptr.p_double[0]-buf->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[1]-buf->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[2]-buf->calcbufx.ptr.pp_double[j][2], _state))*invrcur2, _state); + df = -f; + d2f = f; + for(k=0; k<=s->nl-1; k++) + { + w = s->wr.ptr.pp_double[tg][1+k*s->ny+i]; + y->ptr.p_double[i] = y->ptr.p_double[i]+f*w; + for(i0=0; i0<=s->nx-1; i0++) + { + for(i1=0; i1<=s->nx-1; i1++) + { + if( i0==i1 ) + { + + /* + * Compute derivative and diagonal element of the Hessian + */ + dy->ptr.p_double[i*s->nx+i0] = dy->ptr.p_double[i*s->nx+i0]+w*df*invrcur2*(double)2*(buf->calcbufxcx.ptr.p_double[i0]-buf->calcbufx.ptr.pp_double[j][i0]); + d2y->ptr.p_double[i*s->nx*s->nx+i0*s->nx+i1] = d2y->ptr.p_double[i*s->nx*s->nx+i0*s->nx+i1]+w*(d2f*invrcur2*invrcur2*(double)4*ae_sqr(buf->calcbufxcx.ptr.p_double[i0]-buf->calcbufx.ptr.pp_double[j][i0], _state)+df*invrcur2*(double)2); + } + else + { + + /* + * Compute off-diagonal element of the Hessian + */ + d2y->ptr.p_double[i*s->nx*s->nx+i0*s->nx+i1] = d2y->ptr.p_double[i*s->nx*s->nx+i0*s->nx+i1]+w*d2f*invrcur2*invrcur2*(double)4*(buf->calcbufxcx.ptr.p_double[i0]-buf->calcbufx.ptr.pp_double[j][i0])*(buf->calcbufxcx.ptr.p_double[i1]-buf->calcbufx.ptr.pp_double[j][i1]); + } + } + } + t = f*f; + f = t*t; + df = -f; + d2f = f; + invrcur2 = (double)4*invrcur2; + } + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the regular grid. + +Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - array of grid nodes, first coordinates, array[N0] + N0 - grid size (number of nodes) in the first dimension + X1 - array of grid nodes, second coordinates, array[N1] + N1 - grid size (number of nodes) in the second dimension + +OUTPUT PARAMETERS: + Y - function values, array[N0,N1]. Y is out-variable and + is reallocated by this function. + +NOTE: as a special exception, this function supports unordered arrays X0 + and X1. However, future versions may be more efficient for X0/X1 + ordered by ascending. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1gridcalc2(rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector cpx0; + ae_vector cpx1; + ae_vector p01; + ae_vector p11; + ae_vector p2; + double rlimit; + double xcnorm2; + ae_int_t hp01; + double hcpx0; + double xc0; + double xc1; + double omega; + double radius; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t d; + ae_int_t i00; + ae_int_t i01; + ae_int_t i10; + ae_int_t i11; + + ae_frame_make(_state, &_frame_block); + memset(&cpx0, 0, sizeof(cpx0)); + memset(&cpx1, 0, sizeof(cpx1)); + memset(&p01, 0, sizeof(p01)); + memset(&p11, 0, sizeof(p11)); + memset(&p2, 0, sizeof(p2)); + ae_matrix_clear(y); + ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p01, 0, DT_INT, _state, ae_true); + ae_vector_init(&p11, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)cnt>=n1, "RBFGridCalc2: Length(X1)ptr.pp_double[i][j] = (double)(0); + } + } + if( (s->ny!=1||s->nx!=2)||s->nc==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + *create and sort arrays + */ + ae_vector_set_length(&cpx0, n0, _state); + for(i=0; i<=n0-1; i++) + { + cpx0.ptr.p_double[i] = x0->ptr.p_double[i]; + } + tagsort(&cpx0, n0, &p01, &p2, _state); + ae_vector_set_length(&cpx1, n1, _state); + for(i=0; i<=n1-1; i++) + { + cpx1.ptr.p_double[i] = x1->ptr.p_double[i]; + } + tagsort(&cpx1, n1, &p11, &p2, _state); + + /* + *calculate function's value + */ + for(i=0; i<=s->nc-1; i++) + { + radius = s->wr.ptr.pp_double[i][0]; + for(d=0; d<=s->nl-1; d++) + { + omega = s->wr.ptr.pp_double[i][1+d]; + rlimit = radius*rbfv1_rbffarradius; + + /* + *search lower and upper indexes + */ + i00 = lowerbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]-rlimit, _state); + i01 = upperbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]+rlimit, _state); + i10 = lowerbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]-rlimit, _state); + i11 = upperbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]+rlimit, _state); + xc0 = s->xc.ptr.pp_double[i][0]; + xc1 = s->xc.ptr.pp_double[i][1]; + for(j=i00; j<=i01-1; j++) + { + hcpx0 = cpx0.ptr.p_double[j]; + hp01 = p01.ptr.p_int[j]; + for(k=i10; k<=i11-1; k++) + { + xcnorm2 = ae_sqr(hcpx0-xc0, _state)+ae_sqr(cpx1.ptr.p_double[k]-xc1, _state); + if( ae_fp_less_eq(xcnorm2,rlimit*rlimit) ) + { + y->ptr.pp_double[hp01][p11.ptr.p_int[k]] = y->ptr.pp_double[hp01][p11.ptr.p_int[k]]+ae_exp(-xcnorm2/ae_sqr(radius, _state), _state)*omega; + } + } + } + radius = 0.5*radius; + } + } + + /* + *add linear term + */ + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + y->ptr.pp_double[i][j] = y->ptr.pp_double[i][j]+s->v.ptr.pp_double[0][0]*x0->ptr.p_double[i]+s->v.ptr.pp_double[0][1]*x1->ptr.p_double[j]+s->v.ptr.pp_double[0][rbfv1_mxnx]; + } + } + ae_frame_leave(_state); +} + + +void rbfv1gridcalc3vrec(const rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + double searchradius, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t t; + ae_int_t l; + ae_int_t i0; + ae_int_t i1; + ae_int_t i2; + ae_int_t ic; + gridcalc3v1buf *pbuf; + ae_smart_ptr _pbuf; + ae_int_t flag12dim1; + ae_int_t flag12dim2; + double problemcost; + ae_int_t maxbs; + ae_int_t nx; + ae_int_t ny; + double v; + ae_int_t kc; + ae_int_t tg; + double rcur; + double rcur2; + double basisfuncval; + ae_int_t dstoffs; + ae_int_t srcoffs; + ae_int_t ubnd; + double w0; + double w1; + double w2; + ae_bool allnodes; + ae_bool somenodes; + + ae_frame_make(_state, &_frame_block); + memset(&_pbuf, 0, sizeof(_pbuf)); + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + + nx = s->nx; + ny = s->ny; + + /* + * Try to split large problem + */ + problemcost = (double)((s->nl+1)*s->ny*2)*(avgfuncpernode+(double)1); + problemcost = problemcost*(double)(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]); + problemcost = problemcost*(double)(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]); + problemcost = problemcost*(double)(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]); + maxbs = 0; + maxbs = ae_maxint(maxbs, block0b-block0a, _state); + maxbs = ae_maxint(maxbs, block1b-block1a, _state); + maxbs = ae_maxint(maxbs, block2b-block2a, _state); + if( ae_fp_greater_eq(problemcost,rbfv1_minbasecasecost)&&maxbs>=2 ) + { + if( block0b-block0a==maxbs ) + { + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0a+maxbs/2, blocks1, block1a, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a+maxbs/2, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + if( block1b-block1a==maxbs ) + { + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1a+maxbs/2, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a+maxbs/2, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + if( block2b-block2a==maxbs ) + { + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2a+maxbs/2, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a+maxbs/2, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + } + + /* + * Retrieve buffer object from pool (it will be returned later) + */ + ae_shared_pool_retrieve(bufpool, &_pbuf, _state); + + /* + * Calculate RBF model + */ + for(i2=block2a; i2<=block2b-1; i2++) + { + for(i1=block1a; i1<=block1b-1; i1++) + { + for(i0=block0a; i0<=block0b-1; i0++) + { + + /* + * Analyze block - determine what elements are needed and what are not. + * + * After this block is done, two flag variables can be used: + * * SomeNodes, which is True when there are at least one node which have + * to be calculated + * * AllNodes, which is True when all nodes are required + */ + somenodes = ae_true; + allnodes = ae_true; + flag12dim1 = blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]; + flag12dim2 = blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]; + if( sparsey ) + { + + /* + * Use FlagY to determine what is required. + */ + bvectorsetlengthatleast(&pbuf->flag0, n0, _state); + bvectorsetlengthatleast(&pbuf->flag1, n1, _state); + bvectorsetlengthatleast(&pbuf->flag2, n2, _state); + bvectorsetlengthatleast(&pbuf->flag12, flag12dim1*flag12dim2, _state); + for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++) + { + pbuf->flag0.ptr.p_bool[i] = ae_false; + } + for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++) + { + pbuf->flag1.ptr.p_bool[j] = ae_false; + } + for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++) + { + pbuf->flag2.ptr.p_bool[k] = ae_false; + } + for(i=0; i<=flag12dim1*flag12dim2-1; i++) + { + pbuf->flag12.ptr.p_bool[i] = ae_false; + } + somenodes = ae_false; + allnodes = ae_true; + for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++) + { + for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++) + { + dstoffs = j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2]); + srcoffs = j*n0+k*n0*n1; + for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++) + { + if( flagy->ptr.p_bool[srcoffs+i] ) + { + pbuf->flag0.ptr.p_bool[i] = ae_true; + pbuf->flag1.ptr.p_bool[j] = ae_true; + pbuf->flag2.ptr.p_bool[k] = ae_true; + pbuf->flag12.ptr.p_bool[dstoffs] = ae_true; + somenodes = ae_true; + } + else + { + allnodes = ae_false; + } + } + } + } + } + + /* + * Skip block if it is completely empty. + */ + if( !somenodes ) + { + continue; + } + + /* + * compute linear term for block (I0,I1,I2) + */ + for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++) + { + for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++) + { + + /* + * do we need this micro-row? + */ + if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] ) + { + continue; + } + + /* + * Compute linear term + */ + for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++) + { + pbuf->tx.ptr.p_double[0] = x0->ptr.p_double[i]; + pbuf->tx.ptr.p_double[1] = x1->ptr.p_double[j]; + pbuf->tx.ptr.p_double[2] = x2->ptr.p_double[k]; + for(l=0; l<=s->ny-1; l++) + { + v = s->v.ptr.pp_double[l][rbfv1_mxnx]; + for(t=0; t<=nx-1; t++) + { + v = v+s->v.ptr.pp_double[l][t]*pbuf->tx.ptr.p_double[t]; + } + y->ptr.p_double[l+ny*(i+j*n0+k*n0*n1)] = v; + } + } + } + } + + /* + * compute RBF term for block (I0,I1,I2) + */ + pbuf->tx.ptr.p_double[0] = 0.5*(x0->ptr.p_double[blocks0->ptr.p_int[i0]]+x0->ptr.p_double[blocks0->ptr.p_int[i0+1]-1]); + pbuf->tx.ptr.p_double[1] = 0.5*(x1->ptr.p_double[blocks1->ptr.p_int[i1]]+x1->ptr.p_double[blocks1->ptr.p_int[i1+1]-1]); + pbuf->tx.ptr.p_double[2] = 0.5*(x2->ptr.p_double[blocks2->ptr.p_int[i2]]+x2->ptr.p_double[blocks2->ptr.p_int[i2+1]-1]); + kc = kdtreetsqueryrnn(&s->tree, &pbuf->requestbuf, &pbuf->tx, searchradius, ae_true, _state); + kdtreetsqueryresultsx(&s->tree, &pbuf->requestbuf, &pbuf->calcbufx, _state); + kdtreetsqueryresultstags(&s->tree, &pbuf->requestbuf, &pbuf->calcbuftags, _state); + for(ic=0; ic<=kc-1; ic++) + { + pbuf->cx.ptr.p_double[0] = pbuf->calcbufx.ptr.pp_double[ic][0]; + pbuf->cx.ptr.p_double[1] = pbuf->calcbufx.ptr.pp_double[ic][1]; + pbuf->cx.ptr.p_double[2] = pbuf->calcbufx.ptr.pp_double[ic][2]; + tg = pbuf->calcbuftags.ptr.p_int[ic]; + rcur = s->wr.ptr.pp_double[tg][0]; + rcur2 = rcur*rcur; + for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++) + { + if( allnodes||pbuf->flag0.ptr.p_bool[i] ) + { + pbuf->expbuf0.ptr.p_double[i] = ae_exp(-ae_sqr(x0->ptr.p_double[i]-pbuf->cx.ptr.p_double[0], _state)/rcur2, _state); + } + else + { + pbuf->expbuf0.ptr.p_double[i] = 0.0; + } + } + for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++) + { + if( allnodes||pbuf->flag1.ptr.p_bool[j] ) + { + pbuf->expbuf1.ptr.p_double[j] = ae_exp(-ae_sqr(x1->ptr.p_double[j]-pbuf->cx.ptr.p_double[1], _state)/rcur2, _state); + } + else + { + pbuf->expbuf1.ptr.p_double[j] = 0.0; + } + } + for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++) + { + if( allnodes||pbuf->flag2.ptr.p_bool[k] ) + { + pbuf->expbuf2.ptr.p_double[k] = ae_exp(-ae_sqr(x2->ptr.p_double[k]-pbuf->cx.ptr.p_double[2], _state)/rcur2, _state); + } + else + { + pbuf->expbuf2.ptr.p_double[k] = 0.0; + } + } + for(t=0; t<=s->nl-1; t++) + { + + /* + * Calculate + */ + for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++) + { + for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++) + { + + /* + * do we need this micro-row? + */ + if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] ) + { + continue; + } + + /* + * Prepare local variables + */ + dstoffs = ny*(blocks0->ptr.p_int[i0]+j*n0+k*n0*n1); + v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf2.ptr.p_double[k]; + + /* + * Optimized for NY=1 + */ + if( s->ny==1 ) + { + w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0]; + ubnd = blocks0->ptr.p_int[i0+1]-1; + for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++) + { + basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v; + y->ptr.p_double[dstoffs] = y->ptr.p_double[dstoffs]+basisfuncval*w0; + dstoffs = dstoffs+1; + } + continue; + } + + /* + * Optimized for NY=2 + */ + if( s->ny==2 ) + { + w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0]; + w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1]; + ubnd = blocks0->ptr.p_int[i0+1]-1; + for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++) + { + basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v; + y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0; + y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1; + dstoffs = dstoffs+2; + } + continue; + } + + /* + * Optimized for NY=3 + */ + if( s->ny==3 ) + { + w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0]; + w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1]; + w2 = s->wr.ptr.pp_double[tg][1+t*s->ny+2]; + ubnd = blocks0->ptr.p_int[i0+1]-1; + for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++) + { + basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v; + y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0; + y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1; + y->ptr.p_double[dstoffs+2] = y->ptr.p_double[dstoffs+2]+basisfuncval*w2; + dstoffs = dstoffs+3; + } + continue; + } + + /* + * General case + */ + for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++) + { + basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v; + for(l=0; l<=s->ny-1; l++) + { + y->ptr.p_double[l+dstoffs] = y->ptr.p_double[l+dstoffs]+basisfuncval*s->wr.ptr.pp_double[tg][1+t*s->ny+l]; + } + dstoffs = dstoffs+ny; + } + } + } + + /* + * Update basis functions + */ + if( t!=s->nl-1 ) + { + ubnd = blocks0->ptr.p_int[i0+1]-1; + for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++) + { + if( allnodes||pbuf->flag0.ptr.p_bool[i] ) + { + v = pbuf->expbuf0.ptr.p_double[i]*pbuf->expbuf0.ptr.p_double[i]; + pbuf->expbuf0.ptr.p_double[i] = v*v; + } + } + ubnd = blocks1->ptr.p_int[i1+1]-1; + for(j=blocks1->ptr.p_int[i1]; j<=ubnd; j++) + { + if( allnodes||pbuf->flag1.ptr.p_bool[j] ) + { + v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf1.ptr.p_double[j]; + pbuf->expbuf1.ptr.p_double[j] = v*v; + } + } + ubnd = blocks2->ptr.p_int[i2+1]-1; + for(k=blocks2->ptr.p_int[i2]; k<=ubnd; k++) + { + if( allnodes||pbuf->flag2.ptr.p_bool[k] ) + { + v = pbuf->expbuf2.ptr.p_double[k]*pbuf->expbuf2.ptr.p_double[k]; + pbuf->expbuf2.ptr.p_double[k] = v*v; + } + } + } + } + } + } + } + } + + /* + * Recycle buffer object back to pool + */ + ae_shared_pool_recycle(bufpool, &_pbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv1gridcalc3vrec(const rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + double searchradius, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information, array[NC,NX+NY+1]. + One row of the array corresponds to one basis function: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modelled + * last column - radius, same for all dimensions of + the function being modelled + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv1unpack(rbfv1model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double rcur; + + *nx = 0; + *ny = 0; + ae_matrix_clear(xwr); + *nc = 0; + ae_matrix_clear(v); + + *nx = s->nx; + *ny = s->ny; + *nc = s->nc; + + /* + * Fill V + */ + ae_matrix_set_length(v, s->ny, s->nx+1, _state); + for(i=0; i<=s->ny-1; i++) + { + ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); + v->ptr.pp_double[i][s->nx] = s->v.ptr.pp_double[i][rbfv1_mxnx]; + } + + /* + * Fill XWR and V + */ + if( *nc*s->nl>0 ) + { + ae_matrix_set_length(xwr, s->nc*s->nl, s->nx+s->ny+1, _state); + for(i=0; i<=s->nc-1; i++) + { + rcur = s->wr.ptr.pp_double[i][0]; + for(j=0; j<=s->nl-1; j++) + { + ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][0], 1, &s->xc.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1)); + ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][s->nx], 1, &s->wr.ptr.pp_double[i][1+j*s->ny], 1, ae_v_len(s->nx,s->nx+s->ny-1)); + xwr->ptr.pp_double[i*s->nl+j][s->nx+s->ny] = rcur; + rcur = 0.5*rcur; + } + } + } +} + + +static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_int_t n, + ae_int_t ny, + ae_int_t modeltype, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmpy; + ae_matrix a; + double scaling; + ae_vector shifting; + double mn; + double mx; + ae_vector c; + lsfitreport rep; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&a, 0, sizeof(a)); + memset(&shifting, 0, sizeof(shifting)); + memset(&c, 0, sizeof(c)); + memset(&rep, 0, sizeof(rep)); + ae_matrix_clear(v); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + _lsfitreport_init(&rep, _state, ae_true); + + ae_assert(n>=0, "BuildLinearModel: N<0", _state); + ae_assert(ny>0, "BuildLinearModel: NY<=0", _state); + + /* + * Handle degenerate case (N=0) + */ + result = ae_true; + ae_matrix_set_length(v, ny, rbfv1_mxnx+1, _state); + if( n==0 ) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Allocate temporaries + */ + ae_vector_set_length(&tmpy, n, _state); + + /* + * General linear model. + */ + if( modeltype==1 ) + { + + /* + * Calculate scaling/shifting, transform variables, prepare LLS problem + */ + ae_matrix_set_length(&a, n, rbfv1_mxnx+1, _state); + ae_vector_set_length(&shifting, rbfv1_mxnx, _state); + scaling = (double)(0); + for(i=0; i<=rbfv1_mxnx-1; i++) + { + mn = x->ptr.pp_double[0][i]; + mx = mn; + for(j=1; j<=n-1; j++) + { + if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) ) + { + mn = x->ptr.pp_double[j][i]; + } + if( ae_fp_less(mx,x->ptr.pp_double[j][i]) ) + { + mx = x->ptr.pp_double[j][i]; + } + } + scaling = ae_maxreal(scaling, mx-mn, _state); + shifting.ptr.p_double[i] = 0.5*(mx+mn); + } + if( ae_fp_eq(scaling,(double)(0)) ) + { + scaling = (double)(1); + } + else + { + scaling = 0.5*scaling; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling; + } + } + for(i=0; i<=n-1; i++) + { + a.ptr.pp_double[i][rbfv1_mxnx] = (double)(1); + } + + /* + * Solve linear system in transformed variables, make backward + */ + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=n-1; j++) + { + tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; + } + lsfitlinear(&tmpy, &a, n, rbfv1_mxnx+1, &c, &rep, _state); + if( rep.terminationtype<=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + for(j=0; j<=rbfv1_mxnx-1; j++) + { + v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling; + } + v->ptr.pp_double[i][rbfv1_mxnx] = c.ptr.p_double[rbfv1_mxnx]; + for(j=0; j<=rbfv1_mxnx-1; j++) + { + v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j]; + } + for(j=0; j<=n-1; j++) + { + for(k=0; k<=rbfv1_mxnx-1; k++) + { + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k]; + } + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx]; + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Constant model, very simple + */ + if( modeltype==2 ) + { + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + for(j=0; j<=n-1; j++) + { + v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]+y->ptr.pp_double[j][i]; + } + if( n>0 ) + { + v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]/(double)n; + } + for(j=0; j<=n-1; j++) + { + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx]; + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Zero model + */ + ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=rbfv1_mxnx; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return result; +} + + +static void rbfv1_buildrbfmodellsqr(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + /* Real */ const ae_matrix* xc, + /* Real */ const ae_vector* r, + ae_int_t n, + ae_int_t nc, + ae_int_t ny, + kdtree* pointstree, + kdtree* centerstree, + double epsort, + double epserr, + ae_int_t maxits, + ae_int_t* gnnz, + ae_int_t* snnz, + /* Real */ ae_matrix* w, + ae_int_t* info, + ae_int_t* iterationscount, + ae_int_t* nmv, + ae_state *_state) +{ + ae_frame _frame_block; + linlsqrstate state; + linlsqrreport lsqrrep; + sparsematrix spg; + sparsematrix sps; + ae_vector nearcenterscnt; + ae_vector nearpointscnt; + ae_vector skipnearpointscnt; + ae_vector farpointscnt; + ae_int_t maxnearcenterscnt; + ae_int_t maxnearpointscnt; + ae_int_t maxfarpointscnt; + ae_int_t sumnearcenterscnt; + ae_int_t sumnearpointscnt; + ae_int_t sumfarpointscnt; + double maxrad; + ae_vector pointstags; + ae_vector centerstags; + ae_matrix nearpoints; + ae_matrix nearcenters; + ae_matrix farpoints; + ae_int_t tmpi; + ae_int_t pointscnt; + ae_int_t centerscnt; + ae_vector xcx; + ae_vector tmpy; + ae_vector tc; + ae_vector g; + ae_vector c; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t sind; + ae_matrix a; + double vv; + double vx; + double vy; + double vz; + double vr; + double gnorm2; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + double fx; + ae_matrix xx; + ae_matrix cx; + double mrad; + + ae_frame_make(_state, &_frame_block); + memset(&state, 0, sizeof(state)); + memset(&lsqrrep, 0, sizeof(lsqrrep)); + memset(&spg, 0, sizeof(spg)); + memset(&sps, 0, sizeof(sps)); + memset(&nearcenterscnt, 0, sizeof(nearcenterscnt)); + memset(&nearpointscnt, 0, sizeof(nearpointscnt)); + memset(&skipnearpointscnt, 0, sizeof(skipnearpointscnt)); + memset(&farpointscnt, 0, sizeof(farpointscnt)); + memset(&pointstags, 0, sizeof(pointstags)); + memset(¢erstags, 0, sizeof(centerstags)); + memset(&nearpoints, 0, sizeof(nearpoints)); + memset(&nearcenters, 0, sizeof(nearcenters)); + memset(&farpoints, 0, sizeof(farpoints)); + memset(&xcx, 0, sizeof(xcx)); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&tc, 0, sizeof(tc)); + memset(&g, 0, sizeof(g)); + memset(&c, 0, sizeof(c)); + memset(&a, 0, sizeof(a)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&tmp2, 0, sizeof(tmp2)); + memset(&xx, 0, sizeof(xx)); + memset(&cx, 0, sizeof(cx)); + *gnnz = 0; + *snnz = 0; + ae_matrix_clear(w); + *info = 0; + *iterationscount = 0; + *nmv = 0; + _linlsqrstate_init(&state, _state, ae_true); + _linlsqrreport_init(&lsqrrep, _state, ae_true); + _sparsematrix_init(&spg, _state, ae_true); + _sparsematrix_init(&sps, _state, ae_true); + ae_vector_init(&nearcenterscnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&nearpointscnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&skipnearpointscnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&farpointscnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&pointstags, 0, DT_INT, _state, ae_true); + ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true); + ae_matrix_init(&nearpoints, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&nearcenters, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&farpoints, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&g, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Handle special cases: NC=0 + */ + if( nc==0 ) + { + *info = 1; + *iterationscount = 0; + *nmv = 0; + ae_frame_leave(_state); + return; + } + + /* + * Prepare for general case, NC>0 + */ + ae_vector_set_length(&xcx, rbfv1_mxnx, _state); + ae_vector_set_length(&pointstags, n, _state); + ae_vector_set_length(¢erstags, nc, _state); + *info = -1; + *iterationscount = 0; + *nmv = 0; + + /* + * This block prepares quantities used to compute approximate cardinal basis functions (ACBFs): + * * NearCentersCnt[] - array[NC], whose elements store number of near centers used to build ACBF + * * NearPointsCnt[] - array[NC], number of near points used to build ACBF + * * FarPointsCnt[] - array[NC], number of far points (ones where ACBF is nonzero) + * * MaxNearCentersCnt - max(NearCentersCnt) + * * MaxNearPointsCnt - max(NearPointsCnt) + * * SumNearCentersCnt - sum(NearCentersCnt) + * * SumNearPointsCnt - sum(NearPointsCnt) + * * SumFarPointsCnt - sum(FarPointsCnt) + */ + ae_vector_set_length(&nearcenterscnt, nc, _state); + ae_vector_set_length(&nearpointscnt, nc, _state); + ae_vector_set_length(&skipnearpointscnt, nc, _state); + ae_vector_set_length(&farpointscnt, nc, _state); + maxnearcenterscnt = 0; + maxnearpointscnt = 0; + maxfarpointscnt = 0; + sumnearcenterscnt = 0; + sumnearpointscnt = 0; + sumfarpointscnt = 0; + for(i=0; i<=nc-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; + } + + /* + * Determine number of near centers and maximum radius of near centers + */ + nearcenterscnt.ptr.p_int[i] = kdtreequeryrnn(centerstree, &xcx, r->ptr.p_double[i]*rbfv1_rbfnearradius, ae_true, _state); + kdtreequeryresultstags(centerstree, ¢erstags, _state); + maxrad = (double)(0); + for(j=0; j<=nearcenterscnt.ptr.p_int[i]-1; j++) + { + maxrad = ae_maxreal(maxrad, ae_fabs(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); + } + + /* + * Determine number of near points (ones which used to build ACBF) + * and skipped points (the most near points which are NOT used to build ACBF + * and are NOT included in the near points count + */ + skipnearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, 0.1*r->ptr.p_double[i], ae_true, _state); + nearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, (r->ptr.p_double[i]+maxrad)*rbfv1_rbfnearradius, ae_true, _state)-skipnearpointscnt.ptr.p_int[i]; + ae_assert(nearpointscnt.ptr.p_int[i]>=0, "BuildRBFModelLSQR: internal error", _state); + + /* + * Determine number of far points + */ + farpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, ae_maxreal(r->ptr.p_double[i]*rbfv1_rbfnearradius+maxrad*rbfv1_rbffarradius, r->ptr.p_double[i]*rbfv1_rbffarradius, _state), ae_true, _state); + + /* + * calculate sum and max, make some basic checks + */ + ae_assert(nearcenterscnt.ptr.p_int[i]>0, "BuildRBFModelLSQR: internal error", _state); + maxnearcenterscnt = ae_maxint(maxnearcenterscnt, nearcenterscnt.ptr.p_int[i], _state); + maxnearpointscnt = ae_maxint(maxnearpointscnt, nearpointscnt.ptr.p_int[i], _state); + maxfarpointscnt = ae_maxint(maxfarpointscnt, farpointscnt.ptr.p_int[i], _state); + sumnearcenterscnt = sumnearcenterscnt+nearcenterscnt.ptr.p_int[i]; + sumnearpointscnt = sumnearpointscnt+nearpointscnt.ptr.p_int[i]; + sumfarpointscnt = sumfarpointscnt+farpointscnt.ptr.p_int[i]; + } + *snnz = sumnearcenterscnt; + *gnnz = sumfarpointscnt; + ae_assert(maxnearcenterscnt>0, "BuildRBFModelLSQR: internal error", _state); + + /* + * Allocate temporaries. + * + * NOTE: we want to avoid allocation of zero-size arrays, so we + * use max(desired_size,1) instead of desired_size when performing + * memory allocation. + */ + ae_matrix_set_length(&a, maxnearpointscnt+maxnearcenterscnt, maxnearcenterscnt, _state); + ae_vector_set_length(&tmpy, maxnearpointscnt+maxnearcenterscnt, _state); + ae_vector_set_length(&g, maxnearcenterscnt, _state); + ae_vector_set_length(&c, maxnearcenterscnt, _state); + ae_matrix_set_length(&nearcenters, maxnearcenterscnt, rbfv1_mxnx, _state); + ae_matrix_set_length(&nearpoints, ae_maxint(maxnearpointscnt, 1, _state), rbfv1_mxnx, _state); + ae_matrix_set_length(&farpoints, ae_maxint(maxfarpointscnt, 1, _state), rbfv1_mxnx, _state); + + /* + * fill matrix SpG + */ + sparsecreate(n, nc, *gnnz, &spg, _state); + sparsecreate(nc, nc, *snnz, &sps, _state); + for(i=0; i<=nc-1; i++) + { + centerscnt = nearcenterscnt.ptr.p_int[i]; + + /* + * main center + */ + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j]; + } + + /* + * center's tree + */ + tmpi = kdtreequeryknn(centerstree, &xcx, centerscnt, ae_true, _state); + ae_assert(tmpi==centerscnt, "BuildRBFModelLSQR: internal error", _state); + kdtreequeryresultsx(centerstree, &cx, _state); + kdtreequeryresultstags(centerstree, ¢erstags, _state); + + /* + * point's tree + */ + mrad = (double)(0); + for(j=0; j<=centerscnt-1; j++) + { + mrad = ae_maxreal(mrad, r->ptr.p_double[centerstags.ptr.p_int[j]], _state); + } + + /* + * we need to be sure that 'CTree' contains + * at least one side center + */ + sparseset(&sps, i, i, (double)(1), _state); + c.ptr.p_double[0] = 1.0; + for(j=1; j<=centerscnt-1; j++) + { + c.ptr.p_double[j] = 0.0; + } + if( centerscnt>1&&nearpointscnt.ptr.p_int[i]>0 ) + { + + /* + * first KDTree request for points + */ + pointscnt = nearpointscnt.ptr.p_int[i]; + tmpi = kdtreequeryknn(pointstree, &xcx, skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], ae_true, _state); + ae_assert(tmpi==skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], "BuildRBFModelLSQR: internal error", _state); + kdtreequeryresultsx(pointstree, &xx, _state); + sind = skipnearpointscnt.ptr.p_int[i]; + for(j=0; j<=pointscnt-1; j++) + { + vx = xx.ptr.pp_double[sind+j][0]; + vy = xx.ptr.pp_double[sind+j][1]; + vz = xx.ptr.pp_double[sind+j][2]; + for(k=0; k<=centerscnt-1; k++) + { + vr = 0.0; + vv = vx-cx.ptr.pp_double[k][0]; + vr = vr+vv*vv; + vv = vy-cx.ptr.pp_double[k][1]; + vr = vr+vv*vv; + vv = vz-cx.ptr.pp_double[k][2]; + vr = vr+vv*vv; + vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; + a.ptr.pp_double[j][k] = ae_exp(-vr/(vv*vv), _state); + } + } + for(j=0; j<=centerscnt-1; j++) + { + g.ptr.p_double[j] = ae_exp(-(ae_sqr(xcx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xcx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xcx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state); + } + + /* + * calculate the problem + */ + gnorm2 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); + for(j=0; j<=pointscnt-1; j++) + { + vv = ae_v_dotproduct(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); + vv = vv/gnorm2; + tmpy.ptr.p_double[j] = -vv; + ae_v_subd(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); + } + for(j=pointscnt; j<=pointscnt+centerscnt-1; j++) + { + for(k=0; k<=centerscnt-1; k++) + { + a.ptr.pp_double[j][k] = 0.0; + } + a.ptr.pp_double[j][j-pointscnt] = 1.0E-6; + tmpy.ptr.p_double[j] = 0.0; + } + fblssolvels(&a, &tmpy, pointscnt+centerscnt, centerscnt, &tmp0, &tmp1, &tmp2, _state); + ae_v_move(&c.ptr.p_double[0], 1, &tmpy.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); + vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1)); + vv = vv/gnorm2; + ae_v_subd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); + vv = (double)1/gnorm2; + ae_v_addd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv); + for(j=0; j<=centerscnt-1; j++) + { + sparseset(&sps, i, centerstags.ptr.p_int[j], c.ptr.p_double[j], _state); + } + } + + /* + * second KDTree request for points + */ + pointscnt = farpointscnt.ptr.p_int[i]; + tmpi = kdtreequeryknn(pointstree, &xcx, pointscnt, ae_true, _state); + ae_assert(tmpi==pointscnt, "BuildRBFModelLSQR: internal error", _state); + kdtreequeryresultsx(pointstree, &xx, _state); + kdtreequeryresultstags(pointstree, &pointstags, _state); + + /* + *fill SpG matrix + */ + for(j=0; j<=pointscnt-1; j++) + { + fx = (double)(0); + vx = xx.ptr.pp_double[j][0]; + vy = xx.ptr.pp_double[j][1]; + vz = xx.ptr.pp_double[j][2]; + for(k=0; k<=centerscnt-1; k++) + { + vr = 0.0; + vv = vx-cx.ptr.pp_double[k][0]; + vr = vr+vv*vv; + vv = vy-cx.ptr.pp_double[k][1]; + vr = vr+vv*vv; + vv = vz-cx.ptr.pp_double[k][2]; + vr = vr+vv*vv; + vv = r->ptr.p_double[centerstags.ptr.p_int[k]]; + vv = vv*vv; + fx = fx+c.ptr.p_double[k]*ae_exp(-vr/vv, _state); + } + sparseset(&spg, pointstags.ptr.p_int[j], i, fx, _state); + } + } + sparseconverttocrs(&spg, _state); + sparseconverttocrs(&sps, _state); + + /* + * solve by LSQR method + */ + ae_vector_set_length(&tmpy, n, _state); + ae_vector_set_length(&tc, nc, _state); + ae_matrix_set_length(w, nc, ny, _state); + linlsqrcreate(n, nc, &state, _state); + linlsqrsetcond(&state, epsort, epserr, maxits, _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=n-1; j++) + { + tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; + } + linlsqrsolvesparse(&state, &spg, &tmpy, _state); + linlsqrresults(&state, &c, &lsqrrep, _state); + if( lsqrrep.terminationtype<=0 ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + sparsemtv(&sps, &c, &tc, _state); + for(j=0; j<=nc-1; j++) + { + w->ptr.pp_double[j][i] = tc.ptr.p_double[j]; + } + *iterationscount = *iterationscount+lsqrrep.iterationscount; + *nmv = *nmv+lsqrrep.nmv; + } + *info = 1; + ae_frame_leave(_state); +} + + +static void rbfv1_buildrbfmlayersmodellsqr(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + /* Real */ ae_matrix* xc, + double rval, + /* Real */ ae_vector* r, + ae_int_t n, + ae_int_t* nc, + ae_int_t ny, + ae_int_t nlayers, + kdtree* centerstree, + double epsort, + double epserr, + ae_int_t maxits, + double lambdav, + ae_int_t* annz, + /* Real */ ae_matrix* w, + ae_int_t* info, + ae_int_t* iterationscount, + ae_int_t* nmv, + ae_state *_state) +{ + ae_frame _frame_block; + linlsqrstate state; + linlsqrreport lsqrrep; + sparsematrix spa; + double anorm; + ae_vector omega; + ae_vector xx; + ae_vector tmpy; + ae_matrix cx; + double yval; + ae_int_t nec; + ae_vector centerstags; + ae_int_t layer; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double rmaxbefore; + double rmaxafter; + + ae_frame_make(_state, &_frame_block); + memset(&state, 0, sizeof(state)); + memset(&lsqrrep, 0, sizeof(lsqrrep)); + memset(&spa, 0, sizeof(spa)); + memset(&omega, 0, sizeof(omega)); + memset(&xx, 0, sizeof(xx)); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&cx, 0, sizeof(cx)); + memset(¢erstags, 0, sizeof(centerstags)); + ae_matrix_clear(xc); + ae_vector_clear(r); + *nc = 0; + *annz = 0; + ae_matrix_clear(w); + *info = 0; + *iterationscount = 0; + *nmv = 0; + _linlsqrstate_init(&state, _state, ae_true); + _linlsqrreport_init(&lsqrrep, _state, ae_true); + _sparsematrix_init(&spa, _state, ae_true); + ae_vector_init(&omega, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true); + + ae_assert(nlayers>=0, "BuildRBFMLayersModelLSQR: invalid argument(NLayers<0)", _state); + ae_assert(n>=0, "BuildRBFMLayersModelLSQR: invalid argument(N<0)", _state); + ae_assert(rbfv1_mxnx>0&&rbfv1_mxnx<=3, "BuildRBFMLayersModelLSQR: internal error(invalid global const MxNX: either MxNX<=0 or MxNX>3)", _state); + *annz = 0; + if( n==0||nlayers==0 ) + { + *info = 1; + *iterationscount = 0; + *nmv = 0; + ae_frame_leave(_state); + return; + } + *nc = n*nlayers; + ae_vector_set_length(&xx, rbfv1_mxnx, _state); + ae_vector_set_length(¢erstags, n, _state); + ae_matrix_set_length(xc, *nc, rbfv1_mxnx, _state); + ae_vector_set_length(r, *nc, _state); + for(i=0; i<=*nc-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xc->ptr.pp_double[i][j] = x->ptr.pp_double[i%n][j]; + } + } + for(i=0; i<=*nc-1; i++) + { + r->ptr.p_double[i] = rval/ae_pow((double)(2), (double)(i/n), _state); + } + for(i=0; i<=n-1; i++) + { + centerstags.ptr.p_int[i] = i; + } + kdtreebuildtagged(xc, ¢erstags, n, rbfv1_mxnx, 0, 2, centerstree, _state); + ae_vector_set_length(&omega, n, _state); + ae_vector_set_length(&tmpy, n, _state); + ae_matrix_set_length(w, *nc, ny, _state); + *info = -1; + *iterationscount = 0; + *nmv = 0; + linlsqrcreate(n, n, &state, _state); + linlsqrsetcond(&state, epsort, epserr, maxits, _state); + linlsqrsetlambdai(&state, 1.0E-6, _state); + + /* + * calculate number of non-zero elements for sparse matrix + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; + } + *annz = *annz+kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[0]*rbfv1_rbfmlradius, ae_true, _state); + } + for(layer=0; layer<=nlayers-1; layer++) + { + + /* + * Fill sparse matrix, calculate norm(A) + */ + anorm = 0.0; + sparsecreate(n, n, *annz, &spa, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=rbfv1_mxnx-1; j++) + { + xx.ptr.p_double[j] = x->ptr.pp_double[i][j]; + } + nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbfmlradius, ae_true, _state); + kdtreequeryresultsx(centerstree, &cx, _state); + kdtreequeryresultstags(centerstree, ¢erstags, _state); + for(j=0; j<=nec-1; j++) + { + v = ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[j]], _state), _state); + sparseset(&spa, i, centerstags.ptr.p_int[j], v, _state); + anorm = anorm+ae_sqr(v, _state); + } + } + anorm = ae_sqrt(anorm, _state); + sparseconverttocrs(&spa, _state); + + /* + * Calculate maximum residual before adding new layer. + * This value is not used by algorithm, the only purpose is to make debugging easier. + */ + rmaxbefore = 0.0; + for(j=0; j<=n-1; j++) + { + for(i=0; i<=ny-1; i++) + { + rmaxbefore = ae_maxreal(rmaxbefore, ae_fabs(y->ptr.pp_double[j][i], _state), _state); + } + } + + /* + * Process NY dimensions of the target function + */ + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=n-1; j++) + { + tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; + } + + /* + * calculate Omega for current layer + */ + linlsqrsetlambdai(&state, lambdav*anorm/(double)n, _state); + linlsqrsolvesparse(&state, &spa, &tmpy, _state); + linlsqrresults(&state, &omega, &lsqrrep, _state); + if( lsqrrep.terminationtype<=0 ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + + /* + * calculate error for current layer + */ + for(j=0; j<=n-1; j++) + { + yval = (double)(0); + for(k=0; k<=rbfv1_mxnx-1; k++) + { + xx.ptr.p_double[k] = x->ptr.pp_double[j][k]; + } + nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbffarradius, ae_true, _state); + kdtreequeryresultsx(centerstree, &cx, _state); + kdtreequeryresultstags(centerstree, ¢erstags, _state); + for(k=0; k<=nec-1; k++) + { + yval = yval+omega.ptr.p_double[centerstags.ptr.p_int[k]]*ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[k][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[k][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[k][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[k]], _state), _state); + } + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-yval; + } + + /* + * write Omega in out parameter W + */ + for(j=0; j<=n-1; j++) + { + w->ptr.pp_double[layer*n+j][i] = omega.ptr.p_double[j]; + } + *iterationscount = *iterationscount+lsqrrep.iterationscount; + *nmv = *nmv+lsqrrep.nmv; + } + + /* + * Calculate maximum residual before adding new layer. + * This value is not used by algorithm, the only purpose is to make debugging easier. + */ + rmaxafter = 0.0; + for(j=0; j<=n-1; j++) + { + for(i=0; i<=ny-1; i++) + { + rmaxafter = ae_maxreal(rmaxafter, ae_fabs(y->ptr.pp_double[j][i], _state), _state); + } + } + } + *info = 1; + ae_frame_leave(_state); +} + + +void _rbfv1calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic); + _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic); +} + + +void _rbfv1calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv1calcbuffer *dst = (rbfv1calcbuffer*)_dst; + const rbfv1calcbuffer *src = (const rbfv1calcbuffer*)_src; + ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic); + ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic); + ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic); +} + + +void _rbfv1calcbuffer_clear(void* _p) +{ + rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->calcbufxcx); + ae_matrix_clear(&p->calcbufx); + ae_vector_clear(&p->calcbuftags); + _kdtreerequestbuffer_clear(&p->requestbuffer); +} + + +void _rbfv1calcbuffer_destroy(void* _p) +{ + rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->calcbufxcx); + ae_matrix_destroy(&p->calcbufx); + ae_vector_destroy(&p->calcbuftags); + _kdtreerequestbuffer_destroy(&p->requestbuffer); +} + + +void _rbfv1model_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv1model *p = (rbfv1model*)_p; + ae_touch_ptr((void*)p); + _kdtree_init(&p->tree, _state, make_automatic); + ae_matrix_init(&p->xc, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wr, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic); +} + + +void _rbfv1model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv1model *dst = (rbfv1model*)_dst; + const rbfv1model *src = (const rbfv1model*)_src; + dst->ny = src->ny; + dst->nx = src->nx; + dst->nc = src->nc; + dst->nl = src->nl; + _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic); + ae_matrix_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_matrix_init_copy(&dst->wr, &src->wr, _state, make_automatic); + dst->rmax = src->rmax; + ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic); + ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic); + ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic); + ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic); +} + + +void _rbfv1model_clear(void* _p) +{ + rbfv1model *p = (rbfv1model*)_p; + ae_touch_ptr((void*)p); + _kdtree_clear(&p->tree); + ae_matrix_clear(&p->xc); + ae_matrix_clear(&p->wr); + ae_matrix_clear(&p->v); + ae_vector_clear(&p->calcbufxcx); + ae_matrix_clear(&p->calcbufx); + ae_vector_clear(&p->calcbuftags); +} + + +void _rbfv1model_destroy(void* _p) +{ + rbfv1model *p = (rbfv1model*)_p; + ae_touch_ptr((void*)p); + _kdtree_destroy(&p->tree); + ae_matrix_destroy(&p->xc); + ae_matrix_destroy(&p->wr); + ae_matrix_destroy(&p->v); + ae_vector_destroy(&p->calcbufxcx); + ae_matrix_destroy(&p->calcbufx); + ae_vector_destroy(&p->calcbuftags); +} + + +void _gridcalc3v1buf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gridcalc3v1buf *p = (gridcalc3v1buf*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->flag0, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->flag1, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->flag2, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->flag12, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->expbuf0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->expbuf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->expbuf2, 0, DT_REAL, _state, make_automatic); + _kdtreerequestbuffer_init(&p->requestbuf, _state, make_automatic); + ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic); +} + + +void _gridcalc3v1buf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gridcalc3v1buf *dst = (gridcalc3v1buf*)_dst; + const gridcalc3v1buf *src = (const gridcalc3v1buf*)_src; + ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic); + ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic); + ae_vector_init_copy(&dst->flag0, &src->flag0, _state, make_automatic); + ae_vector_init_copy(&dst->flag1, &src->flag1, _state, make_automatic); + ae_vector_init_copy(&dst->flag2, &src->flag2, _state, make_automatic); + ae_vector_init_copy(&dst->flag12, &src->flag12, _state, make_automatic); + ae_vector_init_copy(&dst->expbuf0, &src->expbuf0, _state, make_automatic); + ae_vector_init_copy(&dst->expbuf1, &src->expbuf1, _state, make_automatic); + ae_vector_init_copy(&dst->expbuf2, &src->expbuf2, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->requestbuf, &src->requestbuf, _state, make_automatic); + ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic); + ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic); +} + + +void _gridcalc3v1buf_clear(void* _p) +{ + gridcalc3v1buf *p = (gridcalc3v1buf*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->tx); + ae_vector_clear(&p->cx); + ae_vector_clear(&p->ty); + ae_vector_clear(&p->flag0); + ae_vector_clear(&p->flag1); + ae_vector_clear(&p->flag2); + ae_vector_clear(&p->flag12); + ae_vector_clear(&p->expbuf0); + ae_vector_clear(&p->expbuf1); + ae_vector_clear(&p->expbuf2); + _kdtreerequestbuffer_clear(&p->requestbuf); + ae_matrix_clear(&p->calcbufx); + ae_vector_clear(&p->calcbuftags); +} + + +void _gridcalc3v1buf_destroy(void* _p) +{ + gridcalc3v1buf *p = (gridcalc3v1buf*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->tx); + ae_vector_destroy(&p->cx); + ae_vector_destroy(&p->ty); + ae_vector_destroy(&p->flag0); + ae_vector_destroy(&p->flag1); + ae_vector_destroy(&p->flag2); + ae_vector_destroy(&p->flag12); + ae_vector_destroy(&p->expbuf0); + ae_vector_destroy(&p->expbuf1); + ae_vector_destroy(&p->expbuf2); + _kdtreerequestbuffer_destroy(&p->requestbuf); + ae_matrix_destroy(&p->calcbufx); + ae_vector_destroy(&p->calcbuftags); +} + + +void _rbfv1report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv1report *p = (rbfv1report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv1report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv1report *dst = (rbfv1report*)_dst; + const rbfv1report *src = (const rbfv1report*)_src; + dst->arows = src->arows; + dst->acols = src->acols; + dst->annz = src->annz; + dst->iterationscount = src->iterationscount; + dst->nmv = src->nmv; + dst->terminationtype = src->terminationtype; +} + + +void _rbfv1report_clear(void* _p) +{ + rbfv1report *p = (rbfv1report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv1report_destroy(void* _p) +{ + rbfv1report *p = (rbfv1report*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initialize precomputed table for a biharmonic evaluator + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +void biharmonicevaluatorinit(biharmonicevaluator* eval, + ae_int_t maxp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t m; + ae_complex cplxi; + ae_complex cplxminusi; + + + ae_assert(maxp>=2, "BiharmonicEvaluatorInit: MaxP<2", _state); + eval->maxp = maxp; + + /* + * Precompute some often used values + * + * NOTE: we use SetLength() instead of rAllocV() in order to enforce strict length + * of the precomputed tables which results in better bounds checking during + * the running time. + */ + eval->precomputedcount = 2*maxp+3; + ae_vector_set_length(&eval->tpowminus1, eval->precomputedcount, _state); + ae_vector_set_length(&eval->tpowminusi, eval->precomputedcount, _state); + ae_vector_set_length(&eval->tpowi, eval->precomputedcount, _state); + cplxi.x = (double)(0); + cplxi.y = (double)(1); + cplxminusi.x = (double)(0); + cplxminusi.y = (double)(-1); + eval->tpowminus1.ptr.p_double[0] = (double)(1); + eval->tpowminusi.ptr.p_complex[0] = ae_complex_from_i(1); + eval->tpowi.ptr.p_complex[0] = ae_complex_from_i(1); + for(i=1; i<=eval->precomputedcount-1; i++) + { + eval->tpowminus1.ptr.p_double[i] = eval->tpowminus1.ptr.p_double[i-1]*(double)(-1); + eval->tpowminusi.ptr.p_complex[i] = ae_c_mul(eval->tpowminusi.ptr.p_complex[i-1],cplxminusi); + eval->tpowi.ptr.p_complex[i] = ae_c_mul(eval->tpowi.ptr.p_complex[i-1],cplxi); + } + ae_vector_set_length(&eval->tfactorial, eval->precomputedcount, _state); + ae_vector_set_length(&eval->tsqrtfactorial, eval->precomputedcount, _state); + eval->tfactorial.ptr.p_double[0] = (double)(1); + for(i=1; i<=eval->precomputedcount-1; i++) + { + eval->tfactorial.ptr.p_double[i] = (double)i*eval->tfactorial.ptr.p_double[i-1]; + } + for(i=0; i<=eval->precomputedcount-1; i++) + { + eval->tsqrtfactorial.ptr.p_double[i] = ae_sqrt(eval->tfactorial.ptr.p_double[i], _state); + } + ae_vector_set_length(&eval->tdoublefactorial, eval->precomputedcount, _state); + ae_assert(eval->precomputedcount>=2, "BiharmonicEvaluatorInit: integrity check 8446 failed", _state); + eval->tdoublefactorial.ptr.p_double[0] = (double)(1); + eval->tdoublefactorial.ptr.p_double[1] = (double)(1); + for(i=2; i<=eval->precomputedcount-1; i++) + { + eval->tdoublefactorial.ptr.p_double[i] = (double)i*eval->tdoublefactorial.ptr.p_double[i-2]; + } + + /* + * Precompute coefficients for the associated Legendre recurrence relation + * + * P[n+1,m] = P[n,m]*CosTheta*(2*n-1)/(N-M) - P[n-1,m]*(N+M-1)/(N-M) (for n>m) + * = P[n,m]*CosTheta*PnmA[n+1,m] + P[n-1,m]*PnmB[n+1,m] (for n>m) + */ + rsetallocv((maxp+1)*(maxp+1), 0.0, &eval->pnma, _state); + rsetallocv((maxp+1)*(maxp+1), 0.0, &eval->pnmb, _state); + for(n=0; n<=maxp; n++) + { + for(m=0; m<=n-1; m++) + { + eval->pnma.ptr.p_double[n*(maxp+1)+m] = (double)(2*n-1)/(double)(n-m); + eval->pnmb.ptr.p_double[n*(maxp+1)+m] = -(double)(n+m-1)/(double)(n-m); + } + } + + /* + * Precompute coefficient used during computation of initial values of the + * associated Legendre recurrence + */ + rsetallocv(maxp+1, 0.0, &eval->pmmc, _state); + rsetallocv((maxp+1)*(maxp+1), 0.0, &eval->pmmcdiag, _state); + for(m=0; m<=maxp; m++) + { + eval->pmmc.ptr.p_double[m] = eval->tpowminus1.ptr.p_double[m]*eval->tdoublefactorial.ptr.p_double[ae_maxint(2*m-1, 0, _state)]; + eval->pmmcdiag.ptr.p_double[m*(maxp+1)+m] = eval->pmmc.ptr.p_double[m]; + } + + /* + * Precompute coefficient YnmA used during computation of the spherical harmonic Ynm + */ + rsetallocv((maxp+1)*(maxp+1), 0.0, &eval->ynma, _state); + for(n=0; n<=maxp; n++) + { + for(m=0; m<=n; m++) + { + eval->ynma.ptr.p_double[n*(maxp+1)+m] = eval->tpowminus1.ptr.p_double[m]*eval->tsqrtfactorial.ptr.p_double[n-m]/eval->tsqrtfactorial.ptr.p_double[n+m]; + } + } + + /* + * Precompute coefficient InmA used during computation of the inner function Inm + */ + csetallocv((maxp+1)*(maxp+1), ae_complex_from_d(0.0), &eval->inma, _state); + for(n=0; n<=maxp; n++) + { + for(m=0; m<=n; m++) + { + eval->inma.ptr.p_complex[n*(maxp+1)+m] = ae_c_mul_d(eval->tpowminusi.ptr.p_complex[m],eval->tpowminus1.ptr.p_double[n]/(eval->tsqrtfactorial.ptr.p_double[n+m]*eval->tsqrtfactorial.ptr.p_double[n-m])); + } + } + + /* + * Precompute coefficients MnmA and NnmA used during computation of expansion functions Mnm and Nnm + */ + rsetallocv(maxp+1, 0.0, &eval->mnma, _state); + rsetallocv(maxp+1, 0.0, &eval->nnma, _state); + for(n=0; n<=maxp; n++) + { + eval->nnma.ptr.p_double[n] = -eval->tpowminus1.ptr.p_double[n]/(double)(2*n-1); + if( n<=maxp-2 ) + { + eval->mnma.ptr.p_double[n] = eval->tpowminus1.ptr.p_double[n]/(double)(2*n+3); + } + } +} + + +/************************************************************************* +Build a panel with biharmonic far field expansions. The function assumes +that we work with 3D data. Lower dimensional data can be zero-padded. Data +with higher dimensionality is NOT supported by biharmonic code. + +IMPORTANT: this function computes far field expansion, but it does NOT + compute error bounds. By default, far field distance is set to + some extremely big number. + You should explicitly set desired far field tolerance (which + leads to automatic computation of the UseAtDistance field) by + calling bhPanelSetPrec(). + +INPUT PARAMETERS: + Panel - panel to be initialized. Previously allocated + memory is reused as much as possible. + XW - array[?,3+NY]: + * 3 first columns are X,Y,Z coordinates + * subsequent NY columns are basis function coefficients + XIdx0, XIdx1 - defines row range [XIdx0,XIdx1) of XW to process, + XIdx1-XIdx0 rows are processed, the rest is ignored + NY - NY>=1, output values count + Eval - precomputed table + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +void bhpanelinit(biharmonicpanel* panel, + /* Real */ const ae_matrix* xw, + ae_int_t xidx0, + ae_int_t xidx1, + ae_int_t ny, + const biharmonicevaluator* eval, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t d; + ae_int_t n; + ae_int_t offs; + ae_int_t doffs; + double x0; + double x1; + double x2; + double r; + double r2; + double r01; + double v; + double v0; + double v1; + double v2; + double vnij; + double vmij; + double costheta; + double sintheta; + double powsinthetaj; + double pnmprev; + double pnm; + double pnmnew; + ae_complex inma; + ae_complex expiminusphi; + ae_complex expiminusjphi; + ae_complex sphericaly; + ae_complex innernm; + ae_complex nnm; + ae_complex mnm; + ae_complex fmult; + ae_int_t stride2; + + + ae_assert(xidx1-xidx0>=1, "bhPanelInit: XIdx1<=XIdx0", _state); + + /* + * Allocate space + */ + panel->ny = ny; + panel->p = eval->maxp; + panel->stride = eval->maxp+1; + panel->sizeinner = eval->maxp+1; + panel->sizen = eval->maxp+1; + panel->sizem = eval->maxp-1; + panel->useatdistance = 0.001*ae_sqrt(ae_maxrealnumber, _state); + csetallocv(ny*panel->stride*panel->stride, ae_complex_from_d(0.0), &panel->tbln, _state); + csetallocv(ny*panel->stride*panel->stride, ae_complex_from_d(0.0), &panel->tblm, _state); + csetallocv(ny*panel->stride*panel->stride, ae_complex_from_d(0.0), &panel->tblmodn, _state); + csetallocv(ny*panel->stride*panel->stride, ae_complex_from_d(0.0), &panel->tblmodm, _state); + rsetallocv(ny*4*panel->stride*panel->stride, 0.0, &panel->tblrmodmn, _state); + stride2 = panel->stride*panel->stride; + + /* + * Compute center, SubAbs and RMax + */ + panel->maxsumabs = (double)(0); + panel->c0 = (double)(0); + panel->c1 = (double)(0); + panel->c2 = (double)(0); + for(k=xidx0; k<=xidx1-1; k++) + { + panel->c0 = panel->c0+xw->ptr.pp_double[k][0]; + panel->c1 = panel->c1+xw->ptr.pp_double[k][1]; + panel->c2 = panel->c2+xw->ptr.pp_double[k][2]; + } + panel->c0 = panel->c0/(double)(xidx1-xidx0); + panel->c1 = panel->c1/(double)(xidx1-xidx0); + panel->c2 = panel->c2/(double)(xidx1-xidx0); + panel->rmax = ae_machineepsilon; + for(k=xidx0; k<=xidx1-1; k++) + { + v0 = xw->ptr.pp_double[k][0]-panel->c0; + v1 = xw->ptr.pp_double[k][1]-panel->c1; + v2 = xw->ptr.pp_double[k][2]-panel->c2; + panel->rmax = ae_maxreal(panel->rmax, ae_sqrt(v0*v0+v1*v1+v2*v2, _state), _state); + } + for(d=0; d<=ny-1; d++) + { + v = (double)(0); + for(k=xidx0; k<=xidx1-1; k++) + { + v = v+ae_fabs(xw->ptr.pp_double[k][3+d], _state); + } + panel->maxsumabs = ae_maxreal(panel->maxsumabs, v, _state); + } + + /* + * Precompute powers of RMax up to MaxP+1 + */ + rallocv(eval->maxp+2, &panel->tblpowrmax, _state); + panel->tblpowrmax.ptr.p_double[0] = (double)(1); + for(i=1; i<=eval->maxp+1; i++) + { + panel->tblpowrmax.ptr.p_double[i] = panel->tblpowrmax.ptr.p_double[i-1]*panel->rmax; + } + + /* + * Fill tables N and M + */ + rallocv(panel->sizeinner, &panel->tpowr, _state); + for(k=xidx0; k<=xidx1-1; k++) + { + + /* + * Prepare table of spherical harmonics for point K (to be used later to compute + * inner functions I_nm and expansion functions N_nm and M_nm). + */ + x0 = xw->ptr.pp_double[k][0]-panel->c0; + x1 = xw->ptr.pp_double[k][1]-panel->c1; + x2 = xw->ptr.pp_double[k][2]-panel->c2; + r2 = x0*x0+x1*x1+x2*x2+ae_minrealnumber; + r = ae_sqrt(r2, _state); + r01 = ae_sqrt(x0*x0+x1*x1+ae_minrealnumber, _state); + costheta = x2/r; + sintheta = r01/r; + expiminusphi.x = x0/r01; + expiminusphi.y = -x1/r01; + panel->tpowr.ptr.p_double[0] = (double)(1); + for(i=1; i<=panel->sizeinner-1; i++) + { + panel->tpowr.ptr.p_double[i] = panel->tpowr.ptr.p_double[i-1]*r; + } + + /* + * Compute table of associated Legrengre polynomials, with + * + * P_nm(N=I,M=-J,X) + * + * being an associated Legendre polynomial, as defined in "Numerical + * recipes in C" and Wikipedia. + * + * It is important that the section 3 of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan + * uses different formulation of P_nm. We will account for the difference + * during the computation of the spherical harmonics. + */ + powsinthetaj = 1.0; + expiminusjphi.x = 1.0; + expiminusjphi.y = 0.0; + for(j=0; j<=panel->stride-1; j++) + { + + /* + * Prepare recursion for associated Legendre polynomials + */ + pnmprev = (double)(0); + pnm = powsinthetaj*eval->pmmc.ptr.p_double[j]; + + /* + * Perform recursion on N + */ + for(n=j; n<=panel->stride-1; n++) + { + offs = n*panel->stride+j; + + /* + * Compute table of associated Legrengre polynomials with + * + * P_nm(N=I,M=-J,X) + * + * being an associated Legendre polynomial, as defined in "Numerical + * recipes in C" and Wikipedia. + * + * It is important that the section 3 of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan + * uses different formulation of P_nm. We will account for the difference + * during the computation of the spherical harmonics. + */ + if( n>j ) + { + + /* + * Recursion on N + */ + pnmnew = pnm*costheta*eval->pnma.ptr.p_double[offs]+pnmprev*eval->pnmb.ptr.p_double[offs]; + pnmprev = pnm; + pnm = pnmnew; + } + + /* + * Compute table of spherical harmonics Y_nm(N=I,M=-J) with + * + * Y_nm(N,M) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(cos(theta))*exp(i*m*phi) + * E_m = m>0 ? pow(-1,m) : 1 + * (because we always compute Y_nm for m<=0, E_m is always 1) + * + * being a spherical harmonic, as defined in the equation (18) of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan. + * + * Here P_nm is an associated Legendre polynomial as defined by Beatson et al. However, Pnm variable + * stores values of associated Legendre polynomials as defined by Wikipedia. Below we perform conversion + * between one format and another one: + * + * P_nm(Beatson) = P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)! + * Y_nm(n=N,m=-J) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Beatson)*exp(i*m*phi) + * = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)!*exp(i*m*phi) + * = [E_m*(-1)^(-m)*sqrt((n+m)!/(n-m)!)*P_nm(Wiki)]*exp(i*m*phi) + * = A_ynm*P_nm(Wiki)*exp(i*m*phi) + */ + v = pnm*eval->ynma.ptr.p_double[offs]; + sphericaly.x = v*expiminusjphi.x; + sphericaly.y = v*expiminusjphi.y; + + /* + * Compute inner functions table where + * + * InnerNM = I_nm(n=I,m=-J), + * + * with + * + * I_nm(n,m) = pow(i,|m|)*pow(-1,n)*pow(r,n)/sqrt((n-m)!(n+m)!)*Y_nm(theta,phi) + * = I_ynm*r^n*Y_nm(theta,phi) + * + * being an inner function, as defined in equation (20) of 'Fast evaluation of polyharmonic splines in three dimensions' + * by R.K. Beatson, M.J.D. Powell and A.M. Tan 1. + */ + v = panel->tpowr.ptr.p_double[n]; + inma = eval->inma.ptr.p_complex[offs]; + innernm.x = v*(inma.x*sphericaly.x-inma.y*sphericaly.y); + innernm.y = v*(inma.x*sphericaly.y+inma.y*sphericaly.x); + + /* + * Update expansion functions N_nm and M_nm with harmonics coming from the point #K + * + * NOTE: precomputed coefficient MnmA[] takes care of the fact that we require + * Mnm for n,m>P-2 to be zero. It is exactly zero at the corresponding positions, + * so we may proceed without conditional operators. + */ + for(d=0; d<=ny-1; d++) + { + doffs = offs+d*stride2; + vnij = xw->ptr.pp_double[k][3+d]*eval->nnma.ptr.p_double[n]; + nnm = panel->tbln.ptr.p_complex[doffs]; + panel->tbln.ptr.p_complex[doffs].x = nnm.x+vnij*innernm.x; + panel->tbln.ptr.p_complex[doffs].y = nnm.y+vnij*innernm.y; + vmij = xw->ptr.pp_double[k][3+d]*panel->tpowr.ptr.p_double[2]*eval->mnma.ptr.p_double[n]; + mnm = panel->tblm.ptr.p_complex[doffs]; + panel->tblm.ptr.p_complex[doffs].x = mnm.x+vmij*innernm.x; + panel->tblm.ptr.p_complex[doffs].y = mnm.y+vmij*innernm.y; + } + } + + /* + * Prepare for the next iteration + */ + powsinthetaj = powsinthetaj*sintheta; + v0 = expiminusjphi.x*expiminusphi.x-expiminusjphi.y*expiminusphi.y; + v1 = expiminusjphi.x*expiminusphi.y+expiminusjphi.y*expiminusphi.x; + expiminusjphi.x = v0; + expiminusjphi.y = v1; + } + } + + /* + * Compute modified N_nm and M_nm by multiplying original values by sqrt((n-m)!(n+m)!)*i^(-m), + * with additional multiplication by 2 for J<>0 + * + * This scaling factor is a part of the outer function O_nm which is computed during the model + * evaluation, and it does NOT depends on the trial point X. So, merging it with N_nm/M_nm + * saves us a lot of computational effort. + */ + for(i=0; i<=panel->p; i++) + { + for(j=0; j<=i; j++) + { + v = eval->tsqrtfactorial.ptr.p_double[i+j]*eval->tsqrtfactorial.ptr.p_double[i-j]; + if( j!=0 ) + { + v = v*(double)2; + } + fmult = eval->tpowi.ptr.p_complex[j]; + fmult.x = fmult.x*v; + fmult.y = fmult.y*v; + if( isizen ) + { + for(d=0; d<=ny-1; d++) + { + nnm = panel->tbln.ptr.p_complex[d*stride2+i*panel->stride+j]; + panel->tblmodn.ptr.p_complex[d*stride2+i*panel->stride+j].x = nnm.x*fmult.x-nnm.y*fmult.y; + panel->tblmodn.ptr.p_complex[d*stride2+i*panel->stride+j].y = nnm.x*fmult.y+nnm.y*fmult.x; + } + } + if( isizem ) + { + for(d=0; d<=ny-1; d++) + { + mnm = panel->tblm.ptr.p_complex[d*stride2+i*panel->stride+j]; + panel->tblmodm.ptr.p_complex[d*stride2+i*panel->stride+j].x = mnm.x*fmult.x-mnm.y*fmult.y; + panel->tblmodm.ptr.p_complex[d*stride2+i*panel->stride+j].y = mnm.x*fmult.y+mnm.y*fmult.x; + } + } + } + } + + /* + * Convert tblModN and tblModN into packed storage + */ + offs = 0; + doffs = 0; + for(i=0; i<=(panel->p+1)*ny-1; i++) + { + for(j=0; j<=panel->p; j++) + { + panel->tblrmodmn.ptr.p_double[doffs+j] = panel->tblmodm.ptr.p_complex[offs+j].x; + } + doffs = doffs+panel->stride; + for(j=0; j<=panel->p; j++) + { + panel->tblrmodmn.ptr.p_double[doffs+j] = panel->tblmodm.ptr.p_complex[offs+j].y; + } + doffs = doffs+panel->stride; + for(j=0; j<=panel->p; j++) + { + panel->tblrmodmn.ptr.p_double[doffs+j] = panel->tblmodn.ptr.p_complex[offs+j].x; + } + doffs = doffs+panel->stride; + for(j=0; j<=panel->p; j++) + { + panel->tblrmodmn.ptr.p_double[doffs+j] = panel->tblmodn.ptr.p_complex[offs+j].y; + } + doffs = doffs+panel->stride; + offs = offs+panel->stride; + } + + /* + * Default UseAtDistance, means that far field is not used + */ + panel->useatdistance = 1.0E50+1.0E6*panel->rmax; +} + + +/************************************************************************* +This function sets far field distance depending on desired accuracy. + +INPUT PARAMETERS: + Panel - panel with valid far field expansion + Tol - desired tolerance + + -- ALGLIB -- + Copyright 20.11.2022 by Sergey Bochkanov +*************************************************************************/ +void bhpanelsetprec(biharmonicpanel* panel, double tol, ae_state *_state) +{ + double errbnd; + double rcand; + + + ae_assert(ae_isfinite(tol, _state)&&ae_fp_greater(tol,(double)(0)), "bhPanelSetPrec: Tol<=0 or infinite", _state); + rcand = panel->rmax; + do + { + rcand = 1.05*rcand+ae_machineepsilon; + errbnd = panel->maxsumabs*rcand*((double)2/(double)(2*panel->p+1))*ae_pow(panel->rmax/rcand, (double)(panel->p+1), _state)/((double)1-panel->rmax/rcand); + } + while(ae_fp_greater_eq(errbnd,tol)); + panel->useatdistance = rcand; +} + + +/************************************************************************* +Tries evaluating model using the far field expansion stored in the panel, +special case for NY=1 + +INPUT PARAMETERS: + Panel - panel + Eval - precomputed table + X0, X1, X2 - evaluation point + NeedErrBnd - whether error bound is needed or not + +OUTPUT PARAMETERS: + F - model value + ErrBnd - upper bound on the far field expansion error, if + requested. Zero otherwise. + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +void bhpaneleval1(const biharmonicpanel* panel, + const biharmonicevaluator* eval, + double x0, + double x1, + double x2, + double* f, + ae_bool neederrbnd, + double* errbnd, + ae_state *_state) +{ + ae_int_t j; + ae_int_t n; + ae_complex vsummn; + double v; + double r; + double r2; + double r01; + double v0; + double v1; + double invr; + double invpowrmplus1; + double invpowrnplus1; + double invpowrpplus1; + double pnmnew; + double pnm; + double pnmprev; + double sintheta; + double powsinthetaj; + double costheta; + ae_complex expiphi; + ae_complex expijphi; + ae_complex sphericaly; + ae_int_t offs; + + *f = 0.0; + *errbnd = 0.0; + + ae_assert(panel->ny==1, "RBF3EVAL1: NY>1", _state); + + /* + * Center evaluation point + */ + x0 = x0-panel->c0; + x1 = x1-panel->c1; + x2 = x2-panel->c2; + r2 = x0*x0+x1*x1+x2*x2+ae_minrealnumber; + r = ae_sqrt(r2, _state); + + /* + * Try to use fast kernel. + * If fast kernel returns False, use reference implementation below. + */ + if( !rbfv3farfields_bhpaneleval1fastkernel(x0, x1, x2, panel->p, &eval->pnma, &eval->pnmb, &eval->pmmcdiag, &eval->ynma, &panel->tblrmodmn, f, &invpowrpplus1, _state) ) + { + + /* + * No fast kernel. + * + * Convert to spherical polar coordinates. + * + * NOTE: we make sure that R is non-zero by adding extremely small perturbation + */ + r01 = ae_sqrt(x0*x0+x1*x1+ae_minrealnumber, _state); + costheta = x2/r; + sintheta = r01/r; + expiphi.x = x0/r01; + expiphi.y = x1/r01; + + /* + * Compute far field expansion for a cluster of basis functions f=r + * + * NOTE: the original paper by Beatson et al. uses f=r as the basis function, + * whilst ALGLIB uses f=-r due to conditional positive definiteness requirement. + * We will perform conversion later. + */ + powsinthetaj = 1.0; + *f = (double)(0); + invr = (double)1/r; + invpowrmplus1 = invr; + expijphi.x = 1.0; + expijphi.y = 0.0; + for(j=0; j<=panel->p; j++) + { + invpowrnplus1 = invpowrmplus1; + + /* + * Prepare recursion for associated Legendre polynomials + */ + pnmprev = (double)(0); + pnm = powsinthetaj*eval->pmmc.ptr.p_double[j]; + + /* + * + */ + for(n=j; n<=panel->p; n++) + { + offs = n*panel->stride+j; + + /* + * Compute table of associated Legrengre polynomials with + * + * P_nm(N=I,M=-J,X) + * + * being an associated Legendre polynomial, as defined in "Numerical + * recipes in C" and Wikipedia. + * + * It is important that the section 3 of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan + * uses different formulation of P_nm. We will account for the difference + * during the computation of the spherical harmonics. + */ + if( n>j ) + { + + /* + * Recursion on N + */ + pnmnew = pnm*costheta*eval->pnma.ptr.p_double[offs]+pnmprev*eval->pnmb.ptr.p_double[offs]; + pnmprev = pnm; + pnm = pnmnew; + } + + /* + * Compute table of spherical harmonics where + * + * funcSphericalY[I*N+J] = Y_nm(N=I,M=-J), + * + * with + * + * Y_nm(N,M) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(cos(theta))*exp(i*m*phi) + * E_m = m>0 ? pow(-1,m) : 1 + * (because we always compute Y_nm for m<=0, E_m is always 1) + * + * being a spherical harmonic, as defined in the equation (18) of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan. + * + * Here P_nm is an associated Legendre polynomial as defined by Beatson et al. However, the Pnm + * variable stores values of associated Legendre polynomials as defined by Wikipedia. Below we perform conversion + * between one format and another one: + * + * P_nm(Beatson) = P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)! + * Y_nm(N,M) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Beatson)*exp(i*m*phi) + * = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)!*exp(i*m*phi) + * = [E_m*(-1)^(-m)*sqrt((n+m)!/(n-m)!)*P_nm(Wiki)]*exp(i*m*phi) + * = YnmA[n,m]*P_nm(Wiki)*exp(i*m*phi) + */ + v = pnm*eval->ynma.ptr.p_double[offs]; + sphericaly.x = v*expijphi.x; + sphericaly.y = v*expijphi.y; + + /* + * Compute outer function for n=N, m=1..N + * Update result with O_mn*(M_mn + R^2*N_mn). + * + * The most straighforward implementation of the loop below should look like as follows: + * + * O_nm = [sqrt((n-m)!(n+m)!)*i^m]*Y_nm/R^(n+1) + * RES += 2*RealPart[(R^2*N_nm+M_nm)*O_nm] + * + * However, we may save a lot of computational effort by moving [sqrt((n-m)!(n+m)!)*i^m] + * multiplier to the left part of the product, i.e. by merging it with N_nm and M_nm + * and producing MODIFIED expansions NMod and MMod. Because computing this multiplier + * involves three lookups into precomputed tables and one complex product, it may + * save us a lot of time. + */ + vsummn.x = r2*panel->tblmodn.ptr.p_complex[offs].x+panel->tblmodm.ptr.p_complex[offs].x; + vsummn.y = r2*panel->tblmodn.ptr.p_complex[offs].y+panel->tblmodm.ptr.p_complex[offs].y; + *f = *f+invpowrnplus1*(vsummn.x*sphericaly.x-vsummn.y*sphericaly.y); + invpowrnplus1 = invpowrnplus1*invr; + } + + /* + * Prepare for the next iteration + */ + powsinthetaj = powsinthetaj*sintheta; + invpowrmplus1 = invpowrmplus1*invr; + v0 = expijphi.x*expiphi.x-expijphi.y*expiphi.y; + v1 = expijphi.x*expiphi.y+expijphi.y*expiphi.x; + expijphi.x = v0; + expijphi.y = v1; + } + invpowrpplus1 = r*invpowrmplus1; + } + + /* + * Convert from f=r to f=-r + */ + *f = -*f; + + /* + * Compute error bound + */ + *errbnd = 0.0; + if( neederrbnd ) + { + *errbnd = panel->maxsumabs*r2*(double)2*panel->tblpowrmax.ptr.p_double[panel->p+1]*invpowrpplus1/((double)(2*panel->p+1)*(r-panel->rmax)); + *errbnd = *errbnd+(double)100*ae_machineepsilon*(panel->maxsumabs*r+ae_fabs(*f, _state)); + } +} + + +/************************************************************************* +Tries evaluating model using the far field expansion stored in the panel, +general case for NY>=1 + +INPUT PARAMETERS: + Panel - panel + Eval - precomputed table + X0, X1, X2 - evaluation point + NeedErrBnd - whether error bound is needed or not + +OUTPUT PARAMETERS: + F - model value + ErrBnd - upper bound on the far field expansion error, if + requested. Zero otherwise. + + -- ALGLIB -- + Copyright 10.11.2022 by Sergey Bochkanov +*************************************************************************/ +void bhpaneleval(const biharmonicpanel* panel, + const biharmonicevaluator* eval, + double x0, + double x1, + double x2, + /* Real */ ae_vector* f, + ae_bool neederrbnd, + double* errbnd, + ae_state *_state) +{ + ae_int_t j; + ae_int_t k; + ae_int_t n; + ae_int_t ny; + ae_int_t stride2; + ae_complex vsummn; + double v; + double r; + double r2; + double r01; + double v0; + double v1; + double invr; + double invpowrmplus1; + double invpowrnplus1; + double pnmnew; + double pnm; + double pnmprev; + double sintheta; + double powsinthetaj; + double invpowrpplus1; + double costheta; + ae_complex expiphi; + ae_complex expijphi; + ae_complex sphericaly; + ae_int_t offs; + ae_int_t offsk; + double af; + + *errbnd = 0.0; + + ny = panel->ny; + if( f->cntc0; + x1 = x1-panel->c1; + x2 = x2-panel->c2; + r2 = x0*x0+x1*x1+x2*x2+ae_minrealnumber; + r = ae_sqrt(r2, _state); + r01 = ae_sqrt(x0*x0+x1*x1+ae_minrealnumber, _state); + costheta = x2/r; + sintheta = r01/r; + expiphi.x = x0/r01; + expiphi.y = x1/r01; + + /* + * Try to use fast kernel. + * If fast kernel returns False, use reference implementation below. + */ + if( !rbfv3farfields_bhpanelevalfastkernel(x0, x1, x2, ny, panel->p, &eval->pnma, &eval->pnmb, &eval->pmmcdiag, &eval->ynma, &panel->tblrmodmn, f, &invpowrpplus1, _state) ) + { + + /* + * No fast kernel. + * + * Compute far field expansion for a cluster of basis functions f=r + * + * NOTE: the original paper by Beatson et al. uses f=r as the basis function, + * whilst ALGLIB uses f=-r due to conditional positive definiteness requirement. + * We will perform conversion later. + */ + powsinthetaj = 1.0; + for(k=0; k<=ny-1; k++) + { + f->ptr.p_double[k] = (double)(0); + } + invr = (double)1/r; + invpowrmplus1 = invr; + expijphi.x = 1.0; + expijphi.y = 0.0; + stride2 = panel->stride*panel->stride; + for(j=0; j<=panel->p; j++) + { + invpowrnplus1 = invpowrmplus1; + + /* + * Prepare recursion for associated Legendre polynomials + */ + pnmprev = (double)(0); + pnm = powsinthetaj*eval->pmmc.ptr.p_double[j]; + + /* + * + */ + for(n=j; n<=panel->p; n++) + { + offs = n*panel->stride+j; + + /* + * Compute table of associated Legrengre polynomials with + * + * P_nm(N=I,M=-J,X) + * + * being an associated Legendre polynomial, as defined in "Numerical + * recipes in C" and Wikipedia. + * + * It is important that the section 3 of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan + * uses different formulation of P_nm. We will account for the difference + * during the computation of the spherical harmonics. + */ + if( n>j ) + { + + /* + * Recursion on N + */ + pnmnew = pnm*costheta*eval->pnma.ptr.p_double[offs]+pnmprev*eval->pnmb.ptr.p_double[offs]; + pnmprev = pnm; + pnm = pnmnew; + } + + /* + * Compute table of spherical harmonics where + * + * funcSphericalY[I*N+J] = Y_nm(N=I,M=-J), + * + * with + * + * Y_nm(N,M) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(cos(theta))*exp(i*m*phi) + * E_m = m>0 ? pow(-1,m) : 1 + * (because we always compute Y_nm for m<=0, E_m is always 1) + * + * being a spherical harmonic, as defined in the equation (18) of 'Fast evaluation of polyharmonic + * splines in three dimensions' by R.K. Beatson, M.J.D. Powell and A.M. Tan. + * + * Here P_nm is an associated Legendre polynomial as defined by Beatson et al. However, the Pnm + * variable stores values of associated Legendre polynomials as defined by Wikipedia. Below we perform conversion + * between one format and another one: + * + * P_nm(Beatson) = P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)! + * Y_nm(N,M) = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Beatson)*exp(i*m*phi) + * = E_m*sqrt((n-m)!/(n+m)!)*P_nm(Wiki)*(-1)^(-m)*(n+m)!/(n-m)!*exp(i*m*phi) + * = [E_m*(-1)^(-m)*sqrt((n+m)!/(n-m)!)*P_nm(Wiki)]*exp(i*m*phi) + * = YnmA[n,m]*P_nm(Wiki)*exp(i*m*phi) + */ + v = pnm*eval->ynma.ptr.p_double[offs]; + sphericaly.x = v*expijphi.x; + sphericaly.y = v*expijphi.y; + + /* + * Compute outer function for n=N, m=1..N + * Update result with O_mn*(M_mn + R^2*N_mn). + * + * The most straighforward implementation of the loop below should look like as follows: + * + * O_nm = [sqrt((n-m)!(n+m)!)*i^m]*Y_nm/R^(n+1) + * RES += 2*RealPart[(R^2*N_nm+M_nm)*O_nm] + * + * However, we may save a lot of computational effort by moving [sqrt((n-m)!(n+m)!)*i^m] + * multiplier to the left part of the product, i.e. by merging it with N_nm and M_nm + * and producing MODIFIED expansions NMod and MMod. Because computing this multiplier + * involves three lookups into precomputed tables and one complex product, it may + * save us a lot of time. + */ + offsk = offs; + for(k=0; k<=ny-1; k++) + { + vsummn.x = r2*panel->tblmodn.ptr.p_complex[offsk].x+panel->tblmodm.ptr.p_complex[offsk].x; + vsummn.y = r2*panel->tblmodn.ptr.p_complex[offsk].y+panel->tblmodm.ptr.p_complex[offsk].y; + f->ptr.p_double[k] = f->ptr.p_double[k]+invpowrnplus1*(vsummn.x*sphericaly.x-vsummn.y*sphericaly.y); + offsk = offsk+stride2; + } + invpowrnplus1 = invpowrnplus1*invr; + } + + /* + * Prepare for the next iteration + */ + powsinthetaj = powsinthetaj*sintheta; + invpowrmplus1 = invpowrmplus1*invr; + v0 = expijphi.x*expiphi.x-expijphi.y*expiphi.y; + v1 = expijphi.x*expiphi.y+expijphi.y*expiphi.x; + expijphi.x = v0; + expijphi.y = v1; + } + invpowrpplus1 = r*invpowrmplus1; + } + + /* + * Convert from f=r to f=-r + */ + for(k=0; k<=ny-1; k++) + { + f->ptr.p_double[k] = -f->ptr.p_double[k]; + } + + /* + * Compute error bound, if needed + */ + *errbnd = 0.0; + if( neederrbnd ) + { + af = (double)(0); + for(k=0; k<=ny-1; k++) + { + af = ae_maxreal(af, ae_fabs(f->ptr.p_double[k], _state), _state); + } + *errbnd = panel->maxsumabs*r2*(double)2*panel->tblpowrmax.ptr.p_double[panel->p+1]*invpowrpplus1/((double)(2*panel->p+1)*(r-panel->rmax)); + *errbnd = *errbnd+(double)100*ae_machineepsilon*(panel->maxsumabs*r+af); + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Fast kernel for biharmonic panel with NY=1 + +INPUT PARAMETERS: + D0, D1, D2 - evaluation point minus (Panel.C0,Panel.C1,Panel.C2) + +OUTPUT PARAMETERS: + F - model value + InvPowRPPlus1 - 1/(R^(P+1)) + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +static ae_bool rbfv3farfields_bhpaneleval1fastkernel(double d0, + double d1, + double d2, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state) +{ + ae_bool result; + + *f = 0.0; + *invpowrpplus1 = 0.0; + + *f = (double)(0); + *invpowrpplus1 = (double)(0); + result = ae_false; + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Fast kernel for biharmonic panel with general NY + +INPUT PARAMETERS: + D0, D1, D2 - evaluation point minus (Panel.C0,Panel.C1,Panel.C2) + +OUTPUT PARAMETERS: + F - model value + InvPowRPPlus1 - 1/(R^(P+1)) + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +static ae_bool rbfv3farfields_bhpanelevalfastkernel(double d0, + double d1, + double d2, + ae_int_t ny, + ae_int_t panelp, + /* Real */ const ae_vector* pnma, + /* Real */ const ae_vector* pnmb, + /* Real */ const ae_vector* pmmcdiag, + /* Real */ const ae_vector* ynma, + /* Real */ const ae_vector* tblrmodmn, + /* Real */ ae_vector* f, + double* invpowrpplus1, + ae_state *_state) +{ + ae_bool result; + + *invpowrpplus1 = 0.0; + + *invpowrpplus1 = (double)(0); + result = ae_false; + return result; +} +#endif + + +void _biharmonicevaluator_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + biharmonicevaluator *p = (biharmonicevaluator*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->tdoublefactorial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tfactorial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tsqrtfactorial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tpowminus1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tpowi, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tpowminusi, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->ynma, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pnma, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pnmb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pmmc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pmmcdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mnma, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nnma, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->inma, 0, DT_COMPLEX, _state, make_automatic); +} + + +void _biharmonicevaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + biharmonicevaluator *dst = (biharmonicevaluator*)_dst; + const biharmonicevaluator *src = (const biharmonicevaluator*)_src; + dst->maxp = src->maxp; + dst->precomputedcount = src->precomputedcount; + ae_vector_init_copy(&dst->tdoublefactorial, &src->tdoublefactorial, _state, make_automatic); + ae_vector_init_copy(&dst->tfactorial, &src->tfactorial, _state, make_automatic); + ae_vector_init_copy(&dst->tsqrtfactorial, &src->tsqrtfactorial, _state, make_automatic); + ae_vector_init_copy(&dst->tpowminus1, &src->tpowminus1, _state, make_automatic); + ae_vector_init_copy(&dst->tpowi, &src->tpowi, _state, make_automatic); + ae_vector_init_copy(&dst->tpowminusi, &src->tpowminusi, _state, make_automatic); + ae_vector_init_copy(&dst->ynma, &src->ynma, _state, make_automatic); + ae_vector_init_copy(&dst->pnma, &src->pnma, _state, make_automatic); + ae_vector_init_copy(&dst->pnmb, &src->pnmb, _state, make_automatic); + ae_vector_init_copy(&dst->pmmc, &src->pmmc, _state, make_automatic); + ae_vector_init_copy(&dst->pmmcdiag, &src->pmmcdiag, _state, make_automatic); + ae_vector_init_copy(&dst->mnma, &src->mnma, _state, make_automatic); + ae_vector_init_copy(&dst->nnma, &src->nnma, _state, make_automatic); + ae_vector_init_copy(&dst->inma, &src->inma, _state, make_automatic); +} + + +void _biharmonicevaluator_clear(void* _p) +{ + biharmonicevaluator *p = (biharmonicevaluator*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->tdoublefactorial); + ae_vector_clear(&p->tfactorial); + ae_vector_clear(&p->tsqrtfactorial); + ae_vector_clear(&p->tpowminus1); + ae_vector_clear(&p->tpowi); + ae_vector_clear(&p->tpowminusi); + ae_vector_clear(&p->ynma); + ae_vector_clear(&p->pnma); + ae_vector_clear(&p->pnmb); + ae_vector_clear(&p->pmmc); + ae_vector_clear(&p->pmmcdiag); + ae_vector_clear(&p->mnma); + ae_vector_clear(&p->nnma); + ae_vector_clear(&p->inma); +} + + +void _biharmonicevaluator_destroy(void* _p) +{ + biharmonicevaluator *p = (biharmonicevaluator*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->tdoublefactorial); + ae_vector_destroy(&p->tfactorial); + ae_vector_destroy(&p->tsqrtfactorial); + ae_vector_destroy(&p->tpowminus1); + ae_vector_destroy(&p->tpowi); + ae_vector_destroy(&p->tpowminusi); + ae_vector_destroy(&p->ynma); + ae_vector_destroy(&p->pnma); + ae_vector_destroy(&p->pnmb); + ae_vector_destroy(&p->pmmc); + ae_vector_destroy(&p->pmmcdiag); + ae_vector_destroy(&p->mnma); + ae_vector_destroy(&p->nnma); + ae_vector_destroy(&p->inma); +} + + +void _biharmonicpanel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + biharmonicpanel *p = (biharmonicpanel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->tbln, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tblm, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tblmodn, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tblmodm, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tblpowrmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tblrmodmn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->funcsphericaly, 0, DT_COMPLEX, _state, make_automatic); + ae_vector_init(&p->tpowr, 0, DT_REAL, _state, make_automatic); +} + + +void _biharmonicpanel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + biharmonicpanel *dst = (biharmonicpanel*)_dst; + const biharmonicpanel *src = (const biharmonicpanel*)_src; + dst->c0 = src->c0; + dst->c1 = src->c1; + dst->c2 = src->c2; + dst->rmax = src->rmax; + dst->useatdistance = src->useatdistance; + dst->ny = src->ny; + dst->p = src->p; + dst->sizen = src->sizen; + dst->sizem = src->sizem; + dst->stride = src->stride; + dst->sizeinner = src->sizeinner; + ae_vector_init_copy(&dst->tbln, &src->tbln, _state, make_automatic); + ae_vector_init_copy(&dst->tblm, &src->tblm, _state, make_automatic); + ae_vector_init_copy(&dst->tblmodn, &src->tblmodn, _state, make_automatic); + ae_vector_init_copy(&dst->tblmodm, &src->tblmodm, _state, make_automatic); + ae_vector_init_copy(&dst->tblpowrmax, &src->tblpowrmax, _state, make_automatic); + ae_vector_init_copy(&dst->tblrmodmn, &src->tblrmodmn, _state, make_automatic); + dst->maxsumabs = src->maxsumabs; + ae_vector_init_copy(&dst->funcsphericaly, &src->funcsphericaly, _state, make_automatic); + ae_vector_init_copy(&dst->tpowr, &src->tpowr, _state, make_automatic); +} + + +void _biharmonicpanel_clear(void* _p) +{ + biharmonicpanel *p = (biharmonicpanel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->tbln); + ae_vector_clear(&p->tblm); + ae_vector_clear(&p->tblmodn); + ae_vector_clear(&p->tblmodm); + ae_vector_clear(&p->tblpowrmax); + ae_vector_clear(&p->tblrmodmn); + ae_vector_clear(&p->funcsphericaly); + ae_vector_clear(&p->tpowr); +} + + +void _biharmonicpanel_destroy(void* _p) +{ + biharmonicpanel *p = (biharmonicpanel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->tbln); + ae_vector_destroy(&p->tblm); + ae_vector_destroy(&p->tblmodn); + ae_vector_destroy(&p->tblmodm); + ae_vector_destroy(&p->tblpowrmax); + ae_vector_destroy(&p->tblrmodmn); + ae_vector_destroy(&p->funcsphericaly); + ae_vector_destroy(&p->tpowr); +} + + +#endif +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX>=1). + +INPUT PARAMETERS: + NX - dimension of the space, NX>=1 + NY - function dimension, NY>=1 + BF - basis function type: + * 1 for biharmonic/multiquadric f=sqrt(r^2+alpha^2) (with f=r being a special case) + * 2 for polyharmonic f=r^2*ln(r) + BFP - basis function parameter: + * BF=0 parameter ignored + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3create(ae_int_t nx, + ae_int_t ny, + ae_int_t bf, + double bfp, + rbfv3model* s, + ae_state *_state) +{ + + _rbfv3model_clear(s); + + ae_assert(nx>=1, "RBFCreate: NX<1", _state); + ae_assert(ny>=1, "RBFCreate: NY<1", _state); + ae_assert(bf==1||bf==2, "RBFCreate: unsupported basis function type", _state); + ae_assert(ae_isfinite(bfp, _state)&&ae_fp_greater_eq(bfp,(double)(0)), "RBFCreate: infinite or negative basis function parameter", _state); + + /* + * Serializable parameters + */ + s->nx = nx; + s->ny = ny; + s->bftype = bf; + s->bfparam = bfp; + s->nc = 0; + rsetallocv(nx, 1.0, &s->s, _state); + rsetallocm(ny, nx+1, 0.0, &s->v, _state); + rbfv3_allocatecalcbuffer(s, &s->calcbuf, _state); + + /* + * Debug counters + */ + s->dbgregqrusedforddm = ae_false; + s->dbgworstfirstdecay = 0.0; +} + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2022 by Sergey Bochkanov +*************************************************************************/ +void rbfv3createcalcbuffer(const rbfv3model* s, + rbfv3calcbuffer* buf, + ae_state *_state) +{ + + _rbfv3calcbuffer_clear(buf); + + rbfv3_allocatecalcbuffer(s, buf, _state); +} + + +/************************************************************************* +This function builds hierarchical RBF model. + +INPUT PARAMETERS: + X - array[N,S.NX], X-values + Y - array[N,S.NY], Y-values + ScaleVec- array[S.NX], vector of per-dimension scales + N - points count + BFtype - basis function type: + * 1 for biharmonic spline f=r or multiquadric f=sqrt(r^2+param^2) + * 2 for thin plate spline f=r^2*ln(r) + BFParam - for BFType=1 zero value means biharmonic, nonzero means multiquadric + ignored for BFType=2 + LambdaV - regularization parameter + ATerm - polynomial term type: + * 1 for linear term (STRONGLY RECOMMENDED) + * 2 for constant term (may break convergence guarantees for thin plate splines) + * 3 for zero term (may break convergence guarantees for all types of splines) + RBFProfile- RBF profile to use: + * 0 for the 'standard' profile + * -1 for the 'debug' profile intended to test all possible code branches even + on small-scale problems. The idea is to choose very small batch sizes and + threshold values, such that small problems with N=100..200 can test all + nested levels of the algorithm. + TOL - desired relative accuracy: + * should between 1E-3 and 1E-6 + * values higher than 1E-3 usually make no sense (bad accuracy, no performance benefits) + * values below 1E-6 may result in algorithm taking too much time, + so we silently override them to 1.0E-6 + S - RBF model, already initialized by RBFCreate() call. + progress10000- variable used for progress reports, it is regularly set + to the current progress multiplied by 10000, in order to + get value in [0,10000] range. The rationale for such scaling + is that it allows us to use integer type to store progress, + which has less potential for non-atomic corruption on unprotected + reads from another threads. + You can read this variable from some other thread to get + estimate of the current progress. + Initial value of this variable is ignored, it is written by + this function, but not read. + terminationrequest - variable used for termination requests; its initial + value must be False, and you can set it to True from some + other thread. This routine regularly checks this variable + and will terminate model construction shortly upon discovering + that termination was requested. + +OUTPUT PARAMETERS: + S - updated model (for rep.terminationtype>0, unchanged otherwise) + Rep - report: + * Rep.TerminationType: + * 1 - successful termination + * 8 terminated by user via rbfrequesttermination() + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the GMRES solver + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3build(/* Real */ const ae_matrix* xraw, + /* Real */ const ae_matrix* yraw, + ae_int_t nraw, + /* Real */ const ae_vector* scaleraw, + ae_int_t bftype, + double bfparamraw, + double lambdavraw, + ae_int_t aterm, + ae_int_t rbfprofile, + double tol, + rbfv3model* s, + ae_int_t* progress10000, + ae_bool* terminationrequest, + rbfv3report* rep, + ae_state *_state) +{ + ae_frame _frame_block; + double fastevaltol; + ae_int_t n; + ae_int_t nx; + ae_int_t ny; + double bfparamscaled; + double lambdavwrk; + double rescaledby; + double mergetol; + ae_int_t matrixformat; + ae_int_t acbfbatch; + ae_int_t acbfglobal; + ae_int_t acbflocal; + ae_int_t acbfcorrection; + ae_int_t ddmbatch; + ae_int_t ddmneighbors; + ae_int_t ddmcoarse; + ae_int_t maxpanelsize; + ae_matrix xscaled; + ae_matrix yscaled; + ae_matrix xcoarse; + ae_matrix x1t; + rbf3evaluator bfmatrix; + rbf3fastevaluator fasteval; + ae_vector b; + ae_vector x0; + ae_vector x1; + ae_vector y0; + ae_vector y1; + ae_vector sft; + ae_vector scalewrk; + ae_matrix c2; + ae_matrix res; + ae_matrix upd0; + ae_matrix upd1; + ae_matrix ortbasis; + ae_int_t ortbasissize; + ae_vector raw2wrkmap; + ae_vector wrk2rawmap; + ae_vector idummy; + sparsematrix sp; + sparsesolverstate ss; + sparsesolverreport ssrep; + rbf3ddmsolver ddmsolver; + double resnrm; + double res0nrm; + ae_int_t iteridx; + ae_int_t yidx; + ae_bool dotrace; + ae_bool dodetailedtrace; + fblsgmresstate gmressolver; + double orterr; + double l1nrm; + double linfnrm; + ae_int_t timeprec; + ae_int_t timedesign; + ae_int_t timeddminit; + ae_int_t timeddmsolve; + ae_int_t timecorrinit; + ae_int_t timecorrsolve; + ae_int_t timereeval; + ae_int_t timetotal; + savgcounter dbgfarfieldspeedup; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + ae_matrix refrhs; + ae_vector refrhs1; + ae_vector refsol1; + double debugdamping; + + ae_frame_make(_state, &_frame_block); + memset(&xscaled, 0, sizeof(xscaled)); + memset(&yscaled, 0, sizeof(yscaled)); + memset(&xcoarse, 0, sizeof(xcoarse)); + memset(&x1t, 0, sizeof(x1t)); + memset(&bfmatrix, 0, sizeof(bfmatrix)); + memset(&fasteval, 0, sizeof(fasteval)); + memset(&b, 0, sizeof(b)); + memset(&x0, 0, sizeof(x0)); + memset(&x1, 0, sizeof(x1)); + memset(&y0, 0, sizeof(y0)); + memset(&y1, 0, sizeof(y1)); + memset(&sft, 0, sizeof(sft)); + memset(&scalewrk, 0, sizeof(scalewrk)); + memset(&c2, 0, sizeof(c2)); + memset(&res, 0, sizeof(res)); + memset(&upd0, 0, sizeof(upd0)); + memset(&upd1, 0, sizeof(upd1)); + memset(&ortbasis, 0, sizeof(ortbasis)); + memset(&raw2wrkmap, 0, sizeof(raw2wrkmap)); + memset(&wrk2rawmap, 0, sizeof(wrk2rawmap)); + memset(&idummy, 0, sizeof(idummy)); + memset(&sp, 0, sizeof(sp)); + memset(&ss, 0, sizeof(ss)); + memset(&ssrep, 0, sizeof(ssrep)); + memset(&ddmsolver, 0, sizeof(ddmsolver)); + memset(&gmressolver, 0, sizeof(gmressolver)); + memset(&dbgfarfieldspeedup, 0, sizeof(dbgfarfieldspeedup)); + memset(&refrhs, 0, sizeof(refrhs)); + memset(&refrhs1, 0, sizeof(refrhs1)); + memset(&refsol1, 0, sizeof(refsol1)); + _rbfv3report_clear(rep); + ae_matrix_init(&xscaled, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&yscaled, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xcoarse, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&x1t, 0, 0, DT_REAL, _state, ae_true); + _rbf3evaluator_init(&bfmatrix, _state, ae_true); + _rbf3fastevaluator_init(&fasteval, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sft, 0, DT_REAL, _state, ae_true); + ae_vector_init(&scalewrk, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&c2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&res, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&upd0, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&upd1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ortbasis, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&raw2wrkmap, 0, DT_INT, _state, ae_true); + ae_vector_init(&wrk2rawmap, 0, DT_INT, _state, ae_true); + ae_vector_init(&idummy, 0, DT_INT, _state, ae_true); + _sparsematrix_init(&sp, _state, ae_true); + _sparsesolverstate_init(&ss, _state, ae_true); + _sparsesolverreport_init(&ssrep, _state, ae_true); + _rbf3ddmsolver_init(&ddmsolver, _state, ae_true); + _fblsgmresstate_init(&gmressolver, _state, ae_true); + _savgcounter_init(&dbgfarfieldspeedup, _state, ae_true); + ae_matrix_init(&refrhs, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&refrhs1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&refsol1, 0, DT_REAL, _state, ae_true); + + mergetol = (double)1000*ae_machineepsilon; + ae_assert(ae_isfinite(tol, _state), "RBFV3Build: incorrect TOL", _state); + ae_assert(s->nx>0, "RBFV3Build: incorrect NX", _state); + ae_assert(s->ny>0, "RBFV3Build: incorrect NY", _state); + ae_assert((bftype==1||bftype==2)||bftype==3, "RBFV3Build: incorrect BFType", _state); + ae_assert((aterm==1||aterm==2)||aterm==3, "RBFV3Build: incorrect ATerm", _state); + ae_assert((rbfprofile==-2||rbfprofile==-1)||rbfprofile==0, "RBFV3Build: incorrect RBFProfile", _state); + for(j=0; j<=s->nx-1; j++) + { + ae_assert(ae_fp_greater(scaleraw->ptr.p_double[j],(double)(0)), "RBFV2BuildHierarchical: incorrect ScaleVec", _state); + } + nx = s->nx; + ny = s->ny; + bfparamscaled = bfparamraw; + + /* + * Trace output (if needed) + */ + dotrace = ae_is_trace_enabled("RBF"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("RBF.DETAILED"); + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// DDM-RBF builder started //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Clean up communication and report fields + */ + *progress10000 = 0; + rep->maxerror = (double)(0); + rep->rmserror = (double)(0); + rep->iterationscount = 0; + timeprec = 0; + timedesign = 0; + timeddminit = 0; + timeddmsolve = 0; + timecorrinit = 0; + timecorrsolve = 0; + timereeval = 0; + timetotal = 0-ae_tickcount(); + s->dbgregqrusedforddm = ae_false; + s->dbgworstfirstdecay = 0.0; + savgcounterinit(&dbgfarfieldspeedup, 0.0, _state); + + /* + * Quick exit when we have no points + */ + if( nraw==0 ) + { + rbfv3_zerofill(s, nx, ny, _state); + rep->terminationtype = 1; + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + + /* + * Preprocess dataset (scale points, merge nondistinct ones) + */ + rbfv3_preprocessdataset(xraw, mergetol, yraw, scaleraw, nraw, nx, ny, bftype, bfparamraw, lambdavraw, &xscaled, &yscaled, &raw2wrkmap, &wrk2rawmap, &n, &scalewrk, &sft, &bfparamscaled, &lambdavwrk, &rescaledby, _state); + rallocm(nx+1, n, &x1t, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + x1t.ptr.pp_double[j][i] = xscaled.ptr.pp_double[i][j]; + } + x1t.ptr.pp_double[nx][i] = 1.0; + } + + /* + * Set algorithm parameters according to the current profile + */ + ae_assert((rbfprofile==-2||rbfprofile==-1)||rbfprofile==0, "RBFV3Build: incorrect RBFProfile", _state); + if( dotrace ) + { + ae_trace("=== PRINTING ALGORITHM SETTINGS ====================================================================\n"); + ae_trace("TOL = %0.2e\nPROFILE = %0d\n", + (double)(tol), + (int)(rbfprofile)); + } + tol = ae_maxreal(tol, 1.0E-6, _state); + acbfglobal = 0; + acbflocal = ae_maxint(ae_round(ae_pow(5.0, (double)(nx), _state), _state), 25, _state); + acbfcorrection = ae_round(ae_pow((double)(5), (double)(nx), _state), _state); + acbfbatch = 32; + ddmneighbors = 0; + ddmbatch = imin2(1000, n, _state); + ddmcoarse = imin3(ae_round(0.1*(double)n+(double)10, _state), 2048, n, _state); + maxpanelsize = rbfv3_defaultmaxpanelsize; + debugdamping = 0.0; + if( rbfprofile==-1||rbfprofile==-2 ) + { + + /* + * Decrease batch sizes and corrector efficiency. + * Add debug damping which produces suboptimal ACBF basis. + */ + if( dotrace ) + { + ae_trace("> debug profile activated\n"); + } + acbfbatch = 16; + ddmneighbors = 3; + ddmbatch = 16; + ddmcoarse = imin3(ae_round(0.05*(double)n+(double)2, _state), 512, n, _state); + maxpanelsize = 16; + if( rbfprofile==-2 ) + { + debugdamping = 0.000001; + } + } + + /* + * Prepare fast evaluator + * + * NOTE: we set fast evaluation tolerance to TOL. Actually, it is better to have it somewhat below + * TOL, e.g. TOL/10 or TOL/100. However, we rely on the fact that fast evaluator error estimate + * is inherently pessimistic, i.e. actual evaluation accuracy is better than that. + */ + fastevaltol = tol; + rbfv3_fastevaluatorinit(&fasteval, &xscaled, n, nx, 1, maxpanelsize, bftype, bfparamscaled, dotrace, _state); + + /* + * Compute design matrix + */ + matrixformat = 1; + if( dotrace ) + { + ae_trace("=== MODEL MATRIX INITIALIZATION STARTED ============================================================\n"); + ae_trace("N = %0d\nNX = %0d\nNY = %0d\n", + (int)(n), + (int)(nx), + (int)(ny)); + ae_trace("BFType = %0d", + (int)(bftype)); + if( bftype==1&&ae_fp_greater(bfparamraw,(double)(0)) ) + { + ae_trace(" ( f=sqrt(r^2+alpha^2), alpha=%0.3f, multiquadric with manual radius)", + (double)(bfparamraw)); + } + if( bftype==1&&ae_fp_eq(bfparamraw,(double)(0)) ) + { + ae_trace(" ( f=r, biharmonic spline )"); + } + if( bftype==1&&ae_fp_less(bfparamraw,(double)(0)) ) + { + ae_trace(" ( f=sqrt(r^2+alpha^2), alpha=AUTO*%0.3f=%0.2e, multiquadric )", + (double)(-bfparamraw), + (double)(bfparamscaled)); + } + if( bftype==2 ) + { + ae_trace(" ( f=log(r)*r^2, thin plate spline )"); + } + if( bftype==3 ) + { + ae_trace(" ( f=r^3 )"); + } + ae_trace("\n"); + ae_trace("Polinom.term= %0d ", + (int)(aterm)); + if( aterm==1 ) + { + ae_trace("(linear term)"); + } + if( aterm==2 ) + { + ae_trace("(constant term)"); + } + if( aterm==3 ) + { + ae_trace("(zero term)"); + } + ae_trace("\n"); + ae_trace("LambdaV = %0.2e (raw value of the smoothing parameter; effective value after adjusting for data spread is %0.2e)\n", + (double)(lambdavraw), + (double)(lambdavwrk)); + ae_trace("VarScales = "); + tracevectore3(scaleraw, 0, nx, _state); + ae_trace(" (raw values of variable scales)\n"); + } + timedesign = timedesign-ae_tickcount(); + rbfv3_modelmatrixinit(&xscaled, n, nx, bftype, bfparamscaled, matrixformat, &bfmatrix, _state); + timedesign = timedesign+ae_tickcount(); + if( dotrace ) + { + ae_trace("> model matrix initialized in %0d ms\n", + (int)(timedesign)); + } + + /* + * Build orthogonal basis of the subspace spanned by polynomials of 1st degree. + * This basis is used later to check orthogonality conditions for the coefficients. + */ + rallocm(nx+1, n, &ortbasis, _state); + rsetr(n, (double)1/ae_sqrt((double)(n), _state), &ortbasis, 0, _state); + ortbasissize = 1; + rallocv(n, &x0, _state); + for(k=0; k<=nx-1; k++) + { + for(j=0; j<=n-1; j++) + { + x0.ptr.p_double[j] = xscaled.ptr.pp_double[j][k]; + } + v = ae_sqrt(rdotv2(n, &x0, _state), _state); + rowwisegramschmidt(&ortbasis, ortbasissize, n, &x0, &x0, ae_false, _state); + vv = ae_sqrt(rdotv2(n, &x0, _state), _state); + if( ae_fp_greater(vv,ae_sqrt(ae_machineepsilon, _state)*(v+(double)1)) ) + { + rcopymulvr(n, (double)1/vv, &x0, &ortbasis, ortbasissize, _state); + ortbasissize = ortbasissize+1; + } + } + + /* + * Build preconditioner + */ + if( dotrace ) + { + ae_trace("=== PRECONDITIONER CONSTRUCTION STARTED ============================================================\n"); + ae_trace("nglobal = %0d\nnlocal = %0d\nncorrection = %0d\nnbatch = %0d\n", + (int)(acbfglobal), + (int)(acbflocal), + (int)(acbfcorrection), + (int)(acbfbatch)); + } + timeprec = timeprec-ae_tickcount(); + rbfv3_computeacbfpreconditioner(&xscaled, n, nx, bftype, bfparamscaled, aterm, acbfbatch, acbfglobal, acbflocal, acbfcorrection, 5, 2, lambdavwrk+debugdamping, &sp, _state); + timeprec = timeprec+ae_tickcount(); + if( dotrace ) + { + ae_trace("> ACBF preconditioner computed in %0d ms\n", + (int)(timeprec)); + } + + /* + * DDM + */ + if( dotrace ) + { + ae_trace("=== DOMAIN DECOMPOSITION METHOD STARTED ============================================================\n"); + } + rsetallocm(n+nx+1, ny, 0.0, &c2, _state); + if( dotrace ) + { + ae_trace("> problem metrics and settings\n"); + ae_trace("NNeighbors = %0d\n", + (int)(ddmneighbors)); + ae_trace("NBatch = %0d\n", + (int)(ddmbatch)); + ae_trace("NCoarse = %0d\n", + (int)(ddmcoarse)); + } + rbfv3_ddmsolverinit(&xscaled, rescaledby, n, nx, &bfmatrix, bftype, bfparamscaled, lambdavwrk, aterm, &sp, ddmneighbors, ddmbatch, ddmcoarse, dotrace, dodetailedtrace, &ddmsolver, &timeddminit, &timecorrinit, _state); + if( dotrace ) + { + ae_trace("> DDM initialization done in %0d ms, %0d subproblems solved (%0d well-conditioned, %0d ill-conditioned)\n", + (int)(timeddminit), + (int)(ddmsolver.subproblemscnt), + (int)(ddmsolver.cntlu), + (int)(ddmsolver.cntregqr)); + } + + /* + * Use preconditioned GMRES + */ + rep->rmserror = (double)(0); + rep->maxerror = (double)(0); + rep->iterationscount = 0; + for(yidx=0; yidx<=ny-1; yidx++) + { + if( dotrace ) + { + ae_trace("> solving for component %2d:\n", + (int)(yidx)); + } + rsetallocv(n+nx+1, 0.0, &y0, _state); + rsetallocv(n+nx+1, 0.0, &y1, _state); + rcopycv(n, &yscaled, yidx, &y0, _state); + res0nrm = ae_sqrt(rdotv2(n, &y0, _state), _state); + fblsgmrescreate(&y0, n, ae_minint(rbfv3_maxddmits, n, _state), &gmressolver, _state); + gmressolver.epsres = tol; + gmressolver.epsred = rbfv3_epsred; + iteridx = 0; + while(fblsgmresiteration(&gmressolver, _state)) + { + if( dotrace ) + { + ae_trace(">> DDM iteration %2d: %0.2e relative residual\n", + (int)(iteridx), + (double)(gmressolver.reprelres)); + } + rallocv(n+nx+1, &y0, _state); + rallocv(n+nx+1, &y1, _state); + rbfv3_ddmsolverrun1(&ddmsolver, &gmressolver.x, n, nx, &sp, &bfmatrix, &fasteval, fastevaltol, &y0, &timeddmsolve, &timecorrsolve, _state); + timereeval = timereeval-ae_tickcount(); + rbfv3_fastevaluatorloadcoeffs1(&fasteval, &y0, _state); + rbfv3_fastevaluatorpushtol(&fasteval, fastevaltol*res0nrm, _state); + rbfv3_fastevaluatorcomputeall(&fasteval, &y1, _state); + savgcounterenqueue(&dbgfarfieldspeedup, ae_sqr((double)(fasteval.dbgpanelscnt), _state)/coalesce((double)(fasteval.dbgpanel2panelcnt+fasteval.dbgfield2panelcnt), (double)(1), _state), _state); + rgemvx(n, nx+1, 1.0, &x1t, 0, 0, 1, &y0, n, 1.0, &y1, 0, _state); + for(i=0; i<=n-1; i++) + { + y1.ptr.p_double[i] = y1.ptr.p_double[i]+lambdavwrk*y0.ptr.p_double[i]; + } + timereeval = timereeval+ae_tickcount(); + rcopyv(n, &y1, &gmressolver.ax, _state); + rep->iterationscount = rep->iterationscount+1; + if( iteridx==1 ) + { + s->dbgworstfirstdecay = ae_maxreal(gmressolver.reprelres, s->dbgworstfirstdecay, _state); + } + iteridx = iteridx+1; + } + rbfv3_ddmsolverrun1(&ddmsolver, &gmressolver.xs, n, nx, &sp, &bfmatrix, &fasteval, fastevaltol, &x1, &timeddmsolve, &timecorrsolve, _state); + ae_assert(ae_isfinite(rdotv2(n+nx+1, &x1, _state), _state), "RBF3: integrity check 4359 failed", _state); + rcopyvc(n+nx+1, &x1, &c2, yidx, _state); + + /* + * Compute predictions and errors + * + * NOTE: because dataset preprocessing may reorder and merge points we have + * to use raw-to-work mapping in order to be able to compute correct + * error metrics. + */ + timereeval = timereeval-ae_tickcount(); + rbfv3_fastevaluatorloadcoeffs1(&fasteval, &x1, _state); + rbfv3_fastevaluatorpushtol(&fasteval, fastevaltol*res0nrm, _state); + rbfv3_fastevaluatorcomputeall(&fasteval, &y1, _state); + rgemvx(n, nx+1, 1.0, &x1t, 0, 0, 1, &x1, n, 1.0, &y1, 0, _state); + timereeval = timereeval+ae_tickcount(); + resnrm = (double)(0); + for(i=0; i<=n-1; i++) + { + resnrm = resnrm+ae_sqr(yscaled.ptr.pp_double[i][yidx]-y1.ptr.p_double[i]-lambdavwrk*x1.ptr.p_double[i], _state); + } + resnrm = ae_sqrt(resnrm, _state); + for(i=0; i<=nraw-1; i++) + { + v = yraw->ptr.pp_double[i][yidx]-y1.ptr.p_double[raw2wrkmap.ptr.p_int[i]]; + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + rep->rmserror = rep->rmserror+v*v; + } + if( dotrace ) + { + ae_trace(">> done with %0.2e relative residual, GMRES completion code %0d\n", + (double)(resnrm/coalesce(res0nrm, (double)(1), _state)), + (int)(gmressolver.retcode)); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)(nraw*ny), _state); + timetotal = timetotal+ae_tickcount(); + if( dotrace ) + { + rallocv(n, &y0, _state); + orterr = (double)(0); + l1nrm = (double)(0); + linfnrm = (double)(0); + for(k=0; k<=ny-1; k++) + { + rcopycv(n, &c2, k, &y0, _state); + linfnrm = ae_maxreal(linfnrm, rmaxabsv(n, &y0, _state), _state); + for(i=0; i<=n-1; i++) + { + l1nrm = l1nrm+ae_fabs(y0.ptr.p_double[i], _state); + } + for(i=0; i<=ortbasissize-1; i++) + { + orterr = ae_maxreal(orterr, ae_fabs(rdotvr(n, &y0, &ortbasis, i, _state), _state), _state); + } + } + ae_trace("=== PRINTING RBF SOLVER RESULTS ====================================================================\n"); + ae_trace("> errors\n"); + ae_trace("RMS.err = %0.2e\n", + (double)(rep->rmserror)); + ae_trace("MAX.err = %0.2e\n", + (double)(rep->maxerror)); + ae_trace("ORT.err = %0.2e (orthogonality condition)\n", + (double)(orterr)); + ae_trace("> solution statistics:\n"); + ae_trace("L1-norm = %0.2e\n", + (double)(l1nrm)); + ae_trace("Linf-norm = %0.2e\n", + (double)(linfnrm)); + ae_trace("> DDM iterations\n"); + ae_trace("ItsCnt = %0d\n", + (int)(rep->iterationscount)); + ae_trace("> speedup due to far field expansions (ok to be 1.0x for datasets below 100K):\n"); + ae_trace("reeval = %0.1fx (speed-up of the model reevaluation phase)\n", + (double)(savgcounterget(&dbgfarfieldspeedup, _state))); + ae_trace("overall = %0.1fx (overall speed-up)\n", + (double)(((double)timetotal+(double)timereeval*(savgcounterget(&dbgfarfieldspeedup, _state)-(double)1))/((double)timetotal+ae_machineepsilon))); + ae_trace("> total running time is %0d ms, including:\n", + (int)(timetotal)); + ae_trace(">> model matrix generation %8d ms\n", + (int)(timedesign)); + ae_trace(">> ACBF preconditioner construction %8d ms\n", + (int)(timeprec)); + ae_trace(">> DDM solver initialization %8d ms\n", + (int)(timeddminit)); + ae_trace(">> DDM corrector initialization %8d ms\n", + (int)(timecorrinit)); + ae_trace(">> DDM solution phase %8d ms\n", + (int)(timeddmsolve)); + ae_trace(">> DDM correction phase %8d ms\n", + (int)(timecorrsolve)); + ae_trace(">> DDM solver model reevaluation %8d ms\n", + (int)(timereeval)); + } + s->bftype = bftype; + s->bfparam = bfparamscaled; + rcopyallocv(nx, &scalewrk, &s->s, _state); + for(j=0; j<=ny-1; j++) + { + s->v.ptr.pp_double[j][nx] = c2.ptr.pp_double[n+nx][j]; + for(i=0; i<=nx-1; i++) + { + s->v.ptr.pp_double[j][i] = c2.ptr.pp_double[n+i][j]/scalewrk.ptr.p_double[i]; + s->v.ptr.pp_double[j][nx] = s->v.ptr.pp_double[j][nx]-c2.ptr.pp_double[n+i][j]*sft.ptr.p_double[i]/scalewrk.ptr.p_double[i]; + } + } + rallocv(n*(nx+ny), &s->cw, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + s->cw.ptr.p_double[i*(nx+ny)+j] = xscaled.ptr.pp_double[i][j]+sft.ptr.p_double[j]/scalewrk.ptr.p_double[j]; + } + for(j=0; j<=ny-1; j++) + { + s->cw.ptr.p_double[i*(nx+ny)+nx+j] = c2.ptr.pp_double[i][j]; + } + } + icopyallocv(n, &wrk2rawmap, &s->pointindexes, _state); + s->nc = n; + rbfv3_createfastevaluator(s, _state); + + /* + * Set up debug fields + */ + s->dbgregqrusedforddm = ddmsolver.cntregqr>0; + + /* + * Update progress reports + */ + rep->terminationtype = 1; + *progress10000 = 10000; + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3alloc(ae_serializer* s, + const rbfv3model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &model->s, model->nx, _state); + allocrealmatrix(s, &model->v, model->ny, model->nx+1, _state); + allocrealarray(s, &model->cw, model->nc*(model->nx+model->ny), _state); + allocintegerarray(s, &model->pointindexes, model->nc, _state); + + /* + * End of stream, no additional data + */ + ae_serializer_alloc_entry(s); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3serialize(ae_serializer* s, + const rbfv3model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_serialize_int(s, model->nx, _state); + ae_serializer_serialize_int(s, model->ny, _state); + ae_serializer_serialize_int(s, model->bftype, _state); + ae_serializer_serialize_double(s, model->bfparam, _state); + ae_serializer_serialize_int(s, model->nc, _state); + serializerealarray(s, &model->s, model->nx, _state); + serializerealmatrix(s, &model->v, model->ny, model->nx+1, _state); + serializerealarray(s, &model->cw, model->nc*(model->nx+model->ny), _state); + serializeintegerarray(s, &model->pointindexes, model->nc, _state); + + /* + * End of stream, no additional data + */ + ae_serializer_serialize_int(s, 117256, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3unserialize(ae_serializer* s, + rbfv3model* model, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t bftype; + ae_int_t k; + double bfparam; + + _rbfv3model_clear(model); + + + /* + * Unserialize primary model parameters, initialize model. + * + * It is necessary to call RBFCreate() because some internal fields + * which are NOT unserialized will need initialization. + */ + ae_serializer_unserialize_int(s, &nx, _state); + ae_serializer_unserialize_int(s, &ny, _state); + ae_serializer_unserialize_int(s, &bftype, _state); + ae_serializer_unserialize_double(s, &bfparam, _state); + rbfv3create(nx, ny, bftype, bfparam, model, _state); + ae_serializer_unserialize_int(s, &model->nc, _state); + unserializerealarray(s, &model->s, _state); + unserializerealmatrix(s, &model->v, _state); + unserializerealarray(s, &model->cw, _state); + unserializeintegerarray(s, &model->pointindexes, _state); + + /* + * End of stream, check that no additional data is present + */ + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==117256, "RBFV3Unserialize: unexpected payload detected in the data stream. Integrity check failed", _state); + + /* + * Finalize construction + */ + rbfv3_createfastevaluator(model, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=1 +(1-dimensional space). + +This function returns 0.0 when: +* the model is not initialized +* NX<>1 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - X-coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +double rbfv3calc1(rbfv3model* s, double x0, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state); + if( s->ny!=1||s->nx!=1 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0-s->v.ptr.pp_double[0][1]; + s->calcbuf.x123.ptr.p_double[0] = x0; + rbfv3tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=2 +(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +If you want to calculate function values many times, consider using +RBFGridCalc2(), which is far more efficient than many subsequent calls to +RBFCalc2(). + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +double rbfv3calc2(rbfv3model* s, double x0, double x1, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); + if( s->ny!=1||s->nx!=2 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]; + if( s->nc==0 ) + { + return result; + } + s->calcbuf.x123.ptr.p_double[0] = x0; + s->calcbuf.x123.ptr.p_double[1] = x1; + rbfv3tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=3 +(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +double rbfv3calc3(rbfv3model* s, + double x0, + double x1, + double x2, + ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); + if( s->ny!=1||s->nx!=3 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][3]; + if( s->nc==0 ) + { + return result; + } + s->calcbuf.x123.ptr.p_double[0] = x0; + s->calcbuf.x123.ptr.p_double[1] = x1; + s->calcbuf.x123.ptr.p_double[2] = x2; + rbfv3tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +Same as RBFCalc(), but does not reallocate Y when in is large enough to +store function values. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv3calcbuf(rbfv3model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + rbfv3tscalcbuf(s, &s->calcbuf, x, y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point, using +external buffer object (internal temporaries of RBF model are not +modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3tscalcbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + double distance0; + ae_int_t colidx; + ae_int_t srcidx; + ae_int_t widx; + ae_int_t curchunk; + + + ae_assert(x->cnt>=s->nx, "RBFV3TsCalcBuf: Length(X)nx, _state), "RBFV3TsCalcBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + + /* + * Handle linear term + */ + if( y->cntptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + if( s->nc==0 ) + { + return; + } + + /* + * Handle RBF term + */ + ae_assert((s->bftype==1||s->bftype==2)||s->bftype==3, "RBFV3TsCalcBuf: unsupported basis function type", _state); + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + rallocv(s->evaluator.chunksize, &buf->evalbuf.funcbuf, _state); + rallocv(s->evaluator.chunksize, &buf->evalbuf.wrkbuf, _state); + colidx = 0; + srcidx = 0; + widx = 0; + distance0 = 1.0E-50; + if( s->bftype==1 ) + { + + /* + * Kernels that add squared parameter to the squared distance + */ + distance0 = ae_sqr(s->bfparam, _state); + } + while(colidxnc) + { + + /* + * Handle basecase with size at most ChunkSize*ChunkSize + */ + curchunk = ae_minint(s->evaluator.chunksize, s->nc-colidx, _state); + rbfv3_computerowchunk(&s->evaluator, &buf->x, &buf->evalbuf, curchunk, srcidx, distance0, 0, _state); + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+rdotvr(curchunk, &buf->evalbuf.funcbuf, &s->wchunked, widx+i, _state); + } + colidx = colidx+curchunk; + srcidx = srcidx+nx; + widx = widx+ny; + } +} + + +/************************************************************************* +This function performs fast calculation using far field expansion (if +supported for a current model, and if model size justifies utilization of +far fields), using currently stored fast evaluation tolerance. + +If no far field is present, straightforward O(N) evaluation is performed. + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 01.11.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfv3tsfastcalcbuf(rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + + + ae_assert(x->cnt>=s->nx, "RBFV3TsCalcBuf: Length(X)nx, _state), "RBFV3TsCalcBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + + /* + * Handle linear term + */ + if( y->cntptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + if( s->nc==0 ) + { + return; + } + + /* + * Handle RBF term + */ + rallocm(1, nx, &buf->x2d, _state); + for(j=0; j<=nx-1; j++) + { + buf->x2d.ptr.pp_double[0][j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + rbfv3_fastevaluatorcomputebatch(&s->fasteval, &buf->x2d, 1, ae_true, &buf->y2d, _state); + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+buf->y2d.ptr.pp_double[i][0]; + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its derivatives, using external buffer object (internal temporaries of the +RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3tsdiffbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + double smalldist2; + ae_bool nograd; + ae_int_t colidx; + ae_int_t srcidx; + ae_int_t widx; + ae_int_t curchunk; + ae_int_t maxchunksize; + double distance0; + + + ae_assert(x->cnt>=s->nx, "RBFV3TsCalcBuf: Length(X)nx, _state), "RBFV3TsCalcBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + + /* + * Handle linear term + */ + if( y->cntcntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*nx+j] = s->v.ptr.pp_double[i][j]; + } + } + if( s->nc==0 ) + { + return; + } + + /* + * Rescale X and DY to the internal scaling used by the RBF model + */ + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]*s->s.ptr.p_double[j]; + } + } + + /* + * Prepare information necessary for the detection of the nonexistent gradient + */ + nograd = ae_false; + smalldist2 = (rdotv2(nx, &buf->x, _state)+1.0)*ae_sqr((double)100*ae_machineepsilon, _state); + + /* + * Handle RBF term + */ + ae_assert((s->bftype==1||s->bftype==2)||s->bftype==3, "RBFV3TsDiffBuf: unsupported basis function type", _state); + ae_assert(s->bftype!=1||ae_fp_greater_eq(s->bfparam,(double)(0)), "RBFV3TsDiffBuf: inconsistent BFType/BFParam", _state); + maxchunksize = s->evaluator.chunksize; + rallocv(maxchunksize, &buf->evalbuf.funcbuf, _state); + rallocv(maxchunksize, &buf->evalbuf.wrkbuf, _state); + rallocv(maxchunksize, &buf->evalbuf.df1, _state); + rallocm(nx, maxchunksize, &buf->evalbuf.deltabuf, _state); + rsetallocv(maxchunksize, 1.0E50, &buf->evalbuf.mindist2, _state); + colidx = 0; + srcidx = 0; + widx = 0; + distance0 = 1.0E-50; + if( s->bftype==1 ) + { + + /* + * Kernels that add squared parameter to the squared distance + */ + distance0 = ae_sqr(s->bfparam, _state); + } + while(colidxnc) + { + + /* + * Handle basecase with size at most ChunkSize*ChunkSize + */ + curchunk = ae_minint(maxchunksize, s->nc-colidx, _state); + rbfv3_computerowchunk(&s->evaluator, &buf->x, &buf->evalbuf, curchunk, srcidx, distance0, 1, _state); + for(j=0; j<=nx-1; j++) + { + rmergemulvr(curchunk, &buf->evalbuf.df1, &buf->evalbuf.deltabuf, j, _state); + } + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+rdotvr(curchunk, &buf->evalbuf.funcbuf, &s->wchunked, widx+i, _state); + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]+(double)2*rdotrr(curchunk, &s->wchunked, widx+i, &buf->evalbuf.deltabuf, j, _state); + } + } + colidx = colidx+curchunk; + srcidx = srcidx+nx; + widx = widx+ny; + } + if( s->bftype==1&&ae_fp_eq(s->bfparam,(double)(0)) ) + { + + /* + * The kernel function is nondifferentiable at nodes, check whether we are close to one of the nodes or not + */ + for(i=0; i<=maxchunksize-1; i++) + { + nograd = nograd||buf->evalbuf.mindist2.ptr.p_double[i]<=smalldist2; + } + if( nograd ) + { + + /* + * The gradient is undefined at the trial point, flush it to zero + */ + rsetv(ny*nx, 0.0, dy, _state); + } + } + + /* + * Rescale derivatives back + */ + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]/s->s.ptr.p_double[j]; + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its first and second derivatives, using external buffer object (internal +temporaries of the RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + D2Y - second derivatives, array[NY*NX*NX]. + D2Y is not reallocated when it is larger than NY*NX*NX. + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3tshessbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_bool nearnode; + ae_bool nograd; + ae_bool nohess; + double smalldist2; + ae_int_t colidx; + ae_int_t srcidx; + ae_int_t widx; + ae_int_t curchunk; + ae_int_t maxchunksize; + double distance0; + + + ae_assert(x->cnt>=s->nx, "RBFV3TsCalcBuf: Length(X)nx, _state), "RBFV3TsCalcBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + + /* + * Handle linear term + */ + if( y->cntcntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + if( d2y->cntptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*nx+j] = s->v.ptr.pp_double[i][j]; + } + } + rsetv(ny*nx*nx, 0.0, d2y, _state); + if( s->nc==0 ) + { + return; + } + + /* + * Rescale X and DY to the internal scaling used by the RBF model (D2Y is zero, + * so it does not need rescaling). + */ + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]*s->s.ptr.p_double[j]; + } + } + + /* + * Prepare information necessary for the detection of the nonexistent Hessian + */ + nograd = ae_false; + nohess = ae_false; + smalldist2 = (rdotv2(nx, &buf->x, _state)+1.0)*ae_sqr((double)100*ae_machineepsilon, _state); + + /* + * Handle RBF term + */ + ae_assert(s->bftype==1||s->bftype==2, "RBFV3TsHessBuf: unsupported basis function type", _state); + ae_assert(s->bftype!=1||ae_fp_greater_eq(s->bfparam,(double)(0)), "RBFV3TsHessBuf: inconsistent BFType/BFParam", _state); + maxchunksize = s->evaluator.chunksize; + rallocv(maxchunksize, &buf->evalbuf.funcbuf, _state); + rallocv(maxchunksize, &buf->evalbuf.wrkbuf, _state); + rallocv(maxchunksize, &buf->evalbuf.df1, _state); + rallocv(maxchunksize, &buf->evalbuf.df2, _state); + rallocm(nx, maxchunksize, &buf->evalbuf.deltabuf, _state); + rsetallocv(maxchunksize, 1.0E50, &buf->evalbuf.mindist2, _state); + colidx = 0; + srcidx = 0; + widx = 0; + distance0 = 1.0E-50; + if( s->bftype==1 ) + { + + /* + * Kernels that add squared parameter to the squared distance + */ + distance0 = ae_sqr(s->bfparam, _state); + } + while(colidxnc) + { + + /* + * Handle basecase with size at most ChunkSize*ChunkSize + */ + curchunk = ae_minint(maxchunksize, s->nc-colidx, _state); + rbfv3_computerowchunk(&s->evaluator, &buf->x, &buf->evalbuf, curchunk, srcidx, distance0, 2, _state); + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+rdotvr(curchunk, &buf->evalbuf.funcbuf, &s->wchunked, widx+i, _state); + for(k0=0; k0<=nx-1; k0++) + { + rcopyrv(curchunk, &buf->evalbuf.deltabuf, k0, &buf->evalbuf.wrkbuf, _state); + rmergemulv(curchunk, &buf->evalbuf.df1, &buf->evalbuf.wrkbuf, _state); + dy->ptr.p_double[i*nx+k0] = dy->ptr.p_double[i*nx+k0]+(double)2*rdotvr(curchunk, &buf->evalbuf.wrkbuf, &s->wchunked, widx+i, _state); + } + for(k0=0; k0<=nx-1; k0++) + { + for(k1=0; k1<=nx-1; k1++) + { + rcopyv(curchunk, &buf->evalbuf.df2, &buf->evalbuf.wrkbuf, _state); + rmergemulrv(curchunk, &buf->evalbuf.deltabuf, k0, &buf->evalbuf.wrkbuf, _state); + rmergemulrv(curchunk, &buf->evalbuf.deltabuf, k1, &buf->evalbuf.wrkbuf, _state); + d2y->ptr.p_double[i*nx*nx+k0*nx+k1] = d2y->ptr.p_double[i*nx*nx+k0*nx+k1]+(double)4*rdotvr(curchunk, &buf->evalbuf.wrkbuf, &s->wchunked, widx+i, _state); + if( k0==k1 ) + { + d2y->ptr.p_double[i*nx*nx+k0*nx+k1] = d2y->ptr.p_double[i*nx*nx+k0*nx+k1]+(double)2*rdotvr(curchunk, &buf->evalbuf.df1, &s->wchunked, widx+i, _state); + } + } + } + } + colidx = colidx+curchunk; + srcidx = srcidx+nx; + widx = widx+ny; + } + nearnode = ae_false; + if( (s->bftype==1&&ae_fp_eq(s->bfparam,(double)(0)))||s->bftype==2 ) + { + + /* + * The kernel function is nondifferentiable at nodes, check whether we are close to one of the nodes or not + */ + for(i=0; i<=maxchunksize-1; i++) + { + nearnode = nearnode||buf->evalbuf.mindist2.ptr.p_double[i]<=smalldist2; + } + } + nograd = nearnode&&(s->bftype==1&&ae_fp_eq(s->bfparam,(double)(0))); + nohess = nearnode&&((s->bftype==1&&ae_fp_eq(s->bfparam,(double)(0)))||s->bftype==2); + if( nograd ) + { + + /* + * The gradient is undefined at the trial point, flush it to zero + */ + rsetv(ny*nx, 0.0, dy, _state); + } + if( nohess ) + { + + /* + * The Hessian is undefined at the trial point, flush it to zero + */ + rsetv(ny*nx*nx, 0.0, d2y, _state); + } + + /* + * Rescale derivatives back + */ + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]/s->s.ptr.p_double[j]; + } + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + for(k=0; k<=nx-1; k++) + { + d2y->ptr.p_double[i*nx*nx+j*nx+k] = d2y->ptr.p_double[i*nx*nx+j*nx+k]/(s->s.ptr.p_double[j]*s->s.ptr.p_double[k]); + } + } + } +} + + +/************************************************************************* +This function is used to perform gridded calculation for 2D, 3D or 4D +problems. It accepts parameters X0...X3 and counters N0...N3. If RBF model +has dimensionality less than 4, corresponding arrays should contain just +one element equal to zero, and corresponding N's should be equal to 1. + +NOTE: array Y should be preallocated by caller. + + -- ALGLIB -- + Copyright 12.07.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfv3gridcalcvx(const rbfv3model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + rbfv3calcbuffer bufseed; + ae_shared_pool bufpool; + ae_int_t simdwidth; + ae_int_t tilescnt; + + ae_frame_make(_state, &_frame_block); + memset(&bufseed, 0, sizeof(bufseed)); + memset(&bufpool, 0, sizeof(bufpool)); + _rbfv3calcbuffer_init(&bufseed, _state, ae_true); + ae_shared_pool_init(&bufpool, _state, ae_true); + + + /* + * Perform integrity checks + */ + ae_assert(s->nx==2||s->nx==3, "RBFGridCalcVX: integrity check failed", _state); + ae_assert(((n0>=1&&n1>=1)&&n2>=1)&&n3>=1, "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=4||((x3->cnt>=1&&ae_fp_eq(x3->ptr.p_double[0],(double)(0)))&&n3==1), "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=3||((x2->cnt>=1&&ae_fp_eq(x2->ptr.p_double[0],(double)(0)))&&n2==1), "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=2||((x1->cnt>=1&&ae_fp_eq(x1->ptr.p_double[0],(double)(0)))&&n1==1), "RBFGridCalcVX: integrity check failed", _state); + ae_assert(!sparsey||flagy->cnt>=n0*n1*n2*n3, "RBFGridCalcVX: integrity check failed", _state); + + /* + * Prepare shared pool + */ + rbfv3createcalcbuffer(s, &bufseed, _state); + ae_shared_pool_set_seed(&bufpool, &bufseed, (ae_int_t)sizeof(bufseed), (ae_copy_constructor)_rbfv3calcbuffer_init_copy, (ae_destructor)_rbfv3calcbuffer_destroy, _state); + + /* + * Call worker function + */ + simdwidth = 8; + tilescnt = idivup(n0, simdwidth, _state)*idivup(n1, simdwidth, _state)*idivup(n2, simdwidth, _state)*idivup(n3, simdwidth, _state); + rbfv3_gridcalcrec(s, simdwidth, 0, tilescnt, x0, n0, x1, n1, x2, n2, x3, n3, flagy, sparsey, y, &bufpool, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information, array[NC,NX+NY+NX+2]. + One row of the array corresponds to one basis function + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * next NX columns - radii, one per dimension + * next column - basis function type: + * 1 for f=r + * 2 for f=r^2*ln(r) + * 10 for multiquadric f=sqrt(r^2+alpha^2) + * next column - basis function parameter: + * alpha, for basis function type 10 + * ignored (zero) for other basis function types + * next column - point index in the original dataset, + or -1 for an artificial node created + by the solver. The algorithm may reorder + the nodes, drop some nodes or add + artificial nodes. Thus, one parsing + this column should expect all these + kinds of alterations in the dataset. + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv3unpack(rbfv3model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t cwwidth; + ae_bool recognized; + + *nx = 0; + *ny = 0; + ae_matrix_clear(xwr); + *nc = 0; + ae_matrix_clear(v); + + *nx = s->nx; + *ny = s->ny; + *nc = s->nc; + + /* + * Fill V + */ + ae_matrix_set_length(v, s->ny, s->nx+1, _state); + for(i=0; i<=s->ny-1; i++) + { + rcopyrr(*nx+1, &s->v, i, v, i, _state); + } + + /* + * Fill XWR + */ + if( *nc>0 ) + { + cwwidth = *nx+(*ny); + ae_matrix_set_length(xwr, *nc, *nx+(*ny)+(*nx)+3, _state); + for(i=0; i<=*nc-1; i++) + { + + /* + * Output centers (in the original variable scaling), weights and radii + */ + for(j=0; j<=*nx-1; j++) + { + xwr->ptr.pp_double[i][j] = s->cw.ptr.p_double[i*cwwidth+j]*s->s.ptr.p_double[j]; + } + for(j=0; j<=*ny-1; j++) + { + xwr->ptr.pp_double[i][*nx+j] = s->cw.ptr.p_double[i*cwwidth+(*nx)+j]; + } + for(j=0; j<=*nx-1; j++) + { + xwr->ptr.pp_double[i][*nx+(*ny)+j] = s->s.ptr.p_double[j]; + } + + /* + * Recognize specific basis function used and perform post-processing + */ + recognized = ae_false; + if( s->bftype==1&&ae_fp_eq(s->bfparam,(double)(0)) ) + { + + /* + * Biharmonic kernel f=r + * + * Weights are multiplied by -1 because actually it is f=-r (the latter + * is conditionally positive definite basis function, and the former is + * how it is known to most users) + */ + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+0] = (double)(1); + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+1] = 0.0; + for(j=0; j<=*ny-1; j++) + { + xwr->ptr.pp_double[i][*nx+j] = -xwr->ptr.pp_double[i][*nx+j]; + } + recognized = ae_true; + } + if( s->bftype==1&&ae_fp_greater(s->bfparam,(double)(0)) ) + { + + /* + * Multiquadric f=sqrt(r^2+alpha^2) + * + * Weights are multiplied by -1 because actually it is f=-sqrt(r^2+alpha^2) + * (the latter is conditionally positive definite basis function, and the + * former is how it is known to most users) + */ + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+0] = (double)(10); + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+1] = s->bfparam; + for(j=0; j<=*ny-1; j++) + { + xwr->ptr.pp_double[i][*nx+j] = -xwr->ptr.pp_double[i][*nx+j]; + } + recognized = ae_true; + } + if( s->bftype==2 ) + { + + /* + * Thin plate spline f=r^2*ln(r) + */ + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+0] = (double)(2); + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+1] = (double)(0); + recognized = ae_true; + } + ae_assert(recognized, "RBFV3: integrity check 5342 failed", _state); + + /* + * Output indexes + */ + xwr->ptr.pp_double[i][*nx+(*ny)+(*nx)+2] = (double)(s->pointindexes.ptr.p_int[i]); + } + } +} + + +/************************************************************************* +Get maximum panel size for a fast evaluator + + -- ALGLIB -- + Copyright 27.08.2022 by Sergey Bochkanov +*************************************************************************/ +ae_int_t rbf3getmaxpanelsize(ae_state *_state) +{ + ae_int_t result; + + + result = rbfv3_defaultmaxpanelsize; + return result; +} + + +/************************************************************************* +Changes fast evaluator tolerance. + +The original fast evaluator provides too conservative error estimates, +even when relaxed tolerances are used. Thus, far field expansions are +often ignored when it is pretty safe to use them and save computational +time. + +This function does the following: +* pushes 'raw' tolerance specified by user to the fast evaluator +* samples about 100 randomly selected points, computes true average and + maximum errors of the fast evaluator on these points. + Usually these errors are 1000x-10000x less than ones allowed by user. +* adjusts 'raw' tolerance, producing so called 'working' tolerance in order + to bring maximum error closer to limits, improving performance due to + looser tolerances + +The running time of this function is O(N). It is not thread-safe. + + -- ALGLIB -- + Copyright 01.11.2022 by Sergey Bochkanov +*************************************************************************/ +void rbf3pushfastevaltol(rbfv3model* s, double tol, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t seed0; + ae_int_t seed1; + hqrndstate rs; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nsampled; + ae_vector x; + ae_vector ya; + ae_vector yb; + double avgrawerror; + double maxrawerror; + rbfv3calcbuffer buf; + double tolgrowth; + double maxtolgrowth; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + memset(&x, 0, sizeof(x)); + memset(&ya, 0, sizeof(ya)); + memset(&yb, 0, sizeof(yb)); + memset(&buf, 0, sizeof(buf)); + _hqrndstate_init(&rs, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ya, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yb, 0, DT_REAL, _state, ae_true); + _rbfv3calcbuffer_init(&buf, _state, ae_true); + + ae_assert(ae_fp_greater(tol,(double)(0)), "RBF3PushFastEvalTol: TOL<=0", _state); + if( s->nc==0 ) + { + ae_frame_leave(_state); + return; + } + rbfv3createcalcbuffer(s, &buf, _state); + + /* + * Choose seeds for RNG that produces indexes of points being sampled + */ + nsampled = 100; + maxtolgrowth = 1.0E6; + seed0 = 47623; + seed1 = 83645264; + + /* + * Push 'raw' tolerance, sample random points and compute errors + */ + rbfv3_fastevaluatorpushtol(&s->fasteval, tol, _state); + avgrawerror = (double)(0); + maxrawerror = (double)(0); + rallocv(s->nx, &x, _state); + hqrndseed(seed0, seed1, &rs, _state); + for(i=0; i<=nsampled-1; i++) + { + + /* + * Sample point + */ + k = hqrnduniformi(&rs, s->nc, _state); + for(j=0; j<=s->nx-1; j++) + { + x.ptr.p_double[j] = s->cw.ptr.p_double[(s->nx+s->ny)*k+j]; + } + + /* + * Compute reference value, fast value, compare + */ + rbfv3tscalcbuf(s, &buf, &x, &ya, _state); + rbfv3tsfastcalcbuf(s, &buf, &x, &yb, _state); + for(j=0; j<=s->ny-1; j++) + { + avgrawerror = avgrawerror+ae_fabs(ya.ptr.p_double[j]-yb.ptr.p_double[j], _state); + maxrawerror = ae_maxreal(maxrawerror, ae_fabs(ya.ptr.p_double[j]-yb.ptr.p_double[j], _state), _state); + } + } + avgrawerror = avgrawerror/(double)(nsampled*s->ny); + + /* + * Compute proposed growth for the target tolerance. + * + * NOTE: a heuristic formula is used which works well in practice. + */ + tolgrowth = tol/ae_maxreal(avgrawerror*(double)25+tol/maxtolgrowth, maxrawerror*(double)5+tol/maxtolgrowth, _state); + if( ae_fp_less(tolgrowth,(double)(1)) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Adjust tolerance + */ + rbfv3_fastevaluatorpushtol(&s->fasteval, tol*tolgrowth, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Allocate temporaries in the evaluator buffer +*************************************************************************/ +static void rbfv3_evalbufferinit(rbf3evaluatorbuffer* buf, + ae_int_t nx, + ae_int_t maxpanelsize, + ae_state *_state) +{ + + + rallocv(maxpanelsize, &buf->funcbuf, _state); + rallocv(maxpanelsize, &buf->wrkbuf, _state); + rallocv(maxpanelsize, &buf->df1, _state); + rallocv(maxpanelsize, &buf->df2, _state); + rallocm(nx, maxpanelsize, &buf->deltabuf, _state); + rallocv(maxpanelsize, &buf->mindist2, _state); + rallocv(maxpanelsize, &buf->coeffbuf, _state); + rallocv(nx, &buf->x, _state); +} + + +/************************************************************************* +Recursive function for the fast evaluator +*************************************************************************/ +static ae_int_t rbfv3_fastevaluatorinitrec(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* xx, + /* Integer */ ae_vector* ptidx, + /* Real */ ae_vector* coordbuf, + ae_int_t idx0, + ae_int_t idx1, + ae_nxpool* nxpool, + ae_state *_state) +{ + ae_frame _frame_block; + rbf3panel *panel; + ae_smart_ptr _panel; + ae_vector boxmin; + ae_vector boxmax; + ae_int_t i; + ae_int_t j; + double v; + ae_int_t idxmid; + ae_int_t subsetlength; + ae_int_t subset0; + ae_int_t subset1; + ae_int_t largestdim; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&_panel, 0, sizeof(_panel)); + memset(&boxmin, 0, sizeof(boxmin)); + memset(&boxmax, 0, sizeof(boxmax)); + ae_smart_ptr_init(&_panel, (void**)&panel, ae_false, _state, ae_true); + ae_vector_init(&boxmin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&boxmax, 0, DT_REAL, _state, ae_true); + + ae_assert(idx1>idx0, "FastEvaluatorInitRec: Idx1<=Idx0", _state); + subsetlength = idx1-idx0; + + /* + * Add panel to the array, prepare to return its index + */ + panel = (rbf3panel*)ae_malloc(sizeof(rbf3panel), _state); /* note: using panel as a temporary prior to assigning its value to _panel */ + memset(panel, 0, sizeof(rbf3panel)); + _rbf3panel_init(panel, _state, ae_false); + ae_smart_ptr_assign(&_panel, panel, ae_true, ae_true, (ae_int_t)sizeof(rbf3panel), _rbf3panel_init_copy, _rbf3panel_destroy); + result = ae_obj_array_append_transfer(&eval->panels, &_panel, _state); + + /* + * Prepare panel fields that are always set: + * * panel center and radius + * * default far field state (not present) + */ + rsetallocv(eval->nx, 0.0, &panel->clustercenter, _state); + for(i=idx0; i<=idx1-1; i++) + { + for(j=0; j<=eval->nx-1; j++) + { + panel->clustercenter.ptr.p_double[j] = panel->clustercenter.ptr.p_double[j]+xx->ptr.pp_double[ptidx->ptr.p_int[i]][j]; + } + } + for(j=0; j<=eval->nx-1; j++) + { + panel->clustercenter.ptr.p_double[j] = panel->clustercenter.ptr.p_double[j]/(double)subsetlength; + } + if( eval->nx<=4&&eval->nx>0 ) + { + panel->c0 = panel->clustercenter.ptr.p_double[0]; + } + if( eval->nx<=4&&eval->nx>1 ) + { + panel->c1 = panel->clustercenter.ptr.p_double[1]; + } + if( eval->nx<=4&&eval->nx>2 ) + { + panel->c2 = panel->clustercenter.ptr.p_double[2]; + } + if( eval->nx<=4&&eval->nx>3 ) + { + panel->c3 = panel->clustercenter.ptr.p_double[3]; + } + panel->clusterrad = 1.0E-50; + for(i=idx0; i<=idx1-1; i++) + { + v = (double)(0); + for(j=0; j<=eval->nx-1; j++) + { + v = v+ae_sqr(panel->clustercenter.ptr.p_double[j]-xx->ptr.pp_double[ptidx->ptr.p_int[i]][j], _state); + } + panel->clusterrad = ae_maxreal(panel->clusterrad, v, _state); + } + panel->clusterrad = ae_sqrt(panel->clusterrad, _state); + panel->farfieldexpansion = rbfv3_farfieldnone; + panel->farfielddistance = 0.0; + panel->idx0 = idx0; + panel->idx1 = idx1; + + /* + * Handle leaf panel (small enough) + */ + if( subsetlength<=eval->maxpanelsize ) + { + panel->paneltype = 0; + iallocv(subsetlength, &panel->ptidx, _state); + rallocm(eval->nx, subsetlength, &panel->xt, _state); + for(i=idx0; i<=idx1-1; i++) + { + panel->ptidx.ptr.p_int[i-idx0] = ptidx->ptr.p_int[i]; + for(j=0; j<=eval->nx-1; j++) + { + v = xx->ptr.pp_double[ptidx->ptr.p_int[i]][j]; + panel->xt.ptr.pp_double[j][i-idx0] = v; + eval->permx.ptr.pp_double[i][j] = v; + } + } + rsetallocm(eval->ny, subsetlength, 0.0, &panel->wt, _state); + rbfv3_evalbufferinit(&panel->tgtbuf, eval->nx, eval->maxpanelsize, _state); + ae_frame_leave(_state); + return result; + } + + /* + * Prepare temporaries + */ + ae_nxpool_retrieve(nxpool, &boxmin, _state); + ae_nxpool_retrieve(nxpool, &boxmax, _state); + + /* + * Prepare to split large panel: + * * compute bounding box and its largest dimension + * * sort points by largest dimension of the bounding box + * * split in two + */ + rcopyrv(eval->nx, xx, ptidx->ptr.p_int[idx0], &boxmin, _state); + rcopyrv(eval->nx, xx, ptidx->ptr.p_int[idx0], &boxmax, _state); + for(i=idx0+1; i<=idx1-1; i++) + { + for(j=0; j<=eval->nx-1; j++) + { + boxmin.ptr.p_double[j] = ae_minreal(boxmin.ptr.p_double[j], xx->ptr.pp_double[ptidx->ptr.p_int[i]][j], _state); + boxmax.ptr.p_double[j] = ae_maxreal(boxmax.ptr.p_double[j], xx->ptr.pp_double[ptidx->ptr.p_int[i]][j], _state); + } + } + largestdim = 0; + for(j=1; j<=eval->nx-1; j++) + { + if( ae_fp_greater(boxmax.ptr.p_double[j]-boxmin.ptr.p_double[j],boxmax.ptr.p_double[largestdim]-boxmin.ptr.p_double[largestdim]) ) + { + largestdim = j; + } + } + for(i=idx0; i<=idx1-1; i++) + { + coordbuf->ptr.p_double[i] = xx->ptr.pp_double[ptidx->ptr.p_int[i]][largestdim]; + } + tagsortmiddleri(coordbuf, ptidx, idx0, subsetlength, _state); + ae_assert(subsetlength>eval->maxpanelsize, "RBF3: integrity check 2955 failed", _state); + tiledsplit(subsetlength, icase2(subsetlength>rbfv3_minfarfieldsize, rbfv3_minfarfieldsize, eval->maxpanelsize, _state), &subset0, &subset1, _state); + idxmid = idx0+subset0; + + /* + * Return temporaries back to nxPool and perform recursive processing + */ + ae_nxpool_recycle(nxpool, &boxmin, _state); + ae_nxpool_recycle(nxpool, &boxmax, _state); + panel->paneltype = 1; + panel->childa = rbfv3_fastevaluatorinitrec(eval, xx, ptidx, coordbuf, idx0, idxmid, nxpool, _state); + panel->childb = rbfv3_fastevaluatorinitrec(eval, xx, ptidx, coordbuf, idxmid, idx1, nxpool, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Initialize fast model evaluator using current dataset and default (zero) +coefficients. + +The coefficients can be loaded later with RBF3FastEvaluatorLoadCoeffs() +or RBF3FastEvaluatorLoadCoeffs1(). +*************************************************************************/ +static void rbfv3_fastevaluatorinit(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* _x, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t maxpanelsize, + ae_int_t bftype, + double bfparam, + ae_bool usedebugcounters, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix x; + ae_vector coordbuf; + ae_int_t rootidx; + ae_nxpool nxpool; + ae_int_t i; + rbf3evaluatorbuffer bufseed; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&coordbuf, 0, sizeof(coordbuf)); + memset(&nxpool, 0, sizeof(nxpool)); + memset(&bufseed, 0, sizeof(bufseed)); + ae_matrix_init_copy(&x, _x, _state, ae_true); + ae_vector_init(&coordbuf, 0, DT_REAL, _state, ae_true); + ae_nxpool_init(&nxpool, DT_REAL, _state, ae_true); + _rbf3evaluatorbuffer_init(&bufseed, _state, ae_true); + + + /* + * Prepare the evaluator and temporaries + */ + eval->n = n; + eval->nx = nx; + eval->ny = ny; + eval->maxpanelsize = maxpanelsize; + eval->functype = bftype; + eval->funcparam = bfparam; + ae_obj_array_clear(&eval->panels); + rsetallocm(n, 3+ny, 0.0, &eval->tmpx3w, _state); + rsetallocm(ny, n, 0.0, &eval->wstoredorig, _state); + rallocm(n, nx, &eval->permx, _state); + rbfv3_evalbufferinit(&bufseed, eval->nx, eval->maxpanelsize, _state); + ae_shared_pool_set_seed(&eval->bufferpool, &bufseed, (ae_int_t)sizeof(bufseed), (ae_copy_constructor)_rbf3evaluatorbuffer_init_copy, (ae_destructor)_rbf3evaluatorbuffer_destroy, _state); + eval->usedebugcounters = usedebugcounters; + eval->dbgpanel2panelcnt = 0; + eval->dbgfield2panelcnt = 0; + eval->dbgpanelscnt = 0; + eval->isloaded = ae_false; + + /* + * Perform recursive subdivision, generate panels + */ + iallocv(n, &eval->origptidx, _state); + for(i=0; i<=n-1; i++) + { + eval->origptidx.ptr.p_int[i] = i; + } + rallocv(n, &coordbuf, _state); + ae_nxpool_alloc(&nxpool, nx, _state); + rootidx = rbfv3_fastevaluatorinitrec(eval, &x, &eval->origptidx, &coordbuf, 0, n, &nxpool, _state); + ae_assert(rootidx==0, "FastEvaluatorInit: integrity check for RootIdx failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive subroutine that loads coefficients into the fast evaluator. The +coefficients are expected to be in Eval.WStoredOrig[NY,N] + +Depending on the settings specified during evaluator creation (basis +function type and parameter), far field expansion can be built for the +model. +*************************************************************************/ +static void rbfv3_fastevaluatorloadcoeffsrec(rbf3fastevaluator* eval, + ae_int_t treenodeidx, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t npts; + rbf3panel *panel; + ae_smart_ptr _panel; + + ae_frame_make(_state, &_frame_block); + memset(&_panel, 0, sizeof(_panel)); + ae_smart_ptr_init(&_panel, (void**)&panel, ae_false, _state, ae_true); + + ae_obj_array_get(&eval->panels, treenodeidx, &_panel, _state); + npts = panel->idx1-panel->idx0; + + /* + * Create far field expansion, if possible + */ + panel->farfieldexpansion = rbfv3_farfieldnone; + if( ((eval->functype==1&&npts>=rbfv3_minfarfieldsize)&&ae_fp_eq(eval->funcparam,0.0))&&eval->nx<=3 ) + { + + /* + * Use far field expansions for a biharmonic kernel + */ + for(i=panel->idx0; i<=panel->idx1-1; i++) + { + for(j=0; j<=eval->nx-1; j++) + { + eval->tmpx3w.ptr.pp_double[i][j] = eval->permx.ptr.pp_double[i][j]; + } + for(j=0; j<=eval->ny-1; j++) + { + eval->tmpx3w.ptr.pp_double[i][3+j] = eval->wstoredorig.ptr.pp_double[j][eval->origptidx.ptr.p_int[i]]; + } + } + bhpanelinit(&panel->bhexpansion, &eval->tmpx3w, panel->idx0, panel->idx1, eval->ny, &eval->bheval, _state); + panel->farfieldexpansion = rbfv3_farfieldbiharmonic; + panel->farfielddistance = panel->bhexpansion.useatdistance; + } + + /* + * Non-leaf panel with two children + */ + if( panel->paneltype==1 ) + { + + /* + * Load coefficients into child panels. + */ + rbfv3_fastevaluatorloadcoeffsrec(eval, panel->childa, _state); + rbfv3_fastevaluatorloadcoeffsrec(eval, panel->childb, _state); + ae_frame_leave(_state); + return; + } + + /* + * Leaf panel + */ + ae_assert(panel->paneltype==0, "RBF3: integrity check 4594 failed", _state); + for(i=0; i<=eval->ny-1; i++) + { + for(j=0; j<=npts-1; j++) + { + panel->wt.ptr.pp_double[i][j] = eval->wstoredorig.ptr.pp_double[i][panel->ptidx.ptr.p_int[j]]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Loads coefficients into fast evaluator built with NY=1. + +Depending on the settings specified during evaluator creation (basis +function type and parameter), far field expansion can be built for the +model. + +INPUT PARAMETERS: + Eval - fast evaluator to load coefficients to + W - coeffs vector +*************************************************************************/ +static void rbfv3_fastevaluatorloadcoeffs1(rbf3fastevaluator* eval, + /* Real */ const ae_vector* w, + ae_state *_state) +{ + + + ae_assert(eval->ny==1, "FastEvaluatorLoadCoeffs1: Eval.NY<>1", _state); + ae_assert(ae_obj_array_get_length(&eval->panels)>0, "FastEvaluatorLoadCoeffs1: Length(Panels)=0", _state); + + /* + * Prepare problem-specific evaluator, if any + */ + if( (eval->functype==1&&ae_fp_eq(eval->funcparam,0.0))&&eval->nx<=3 ) + { + biharmonicevaluatorinit(&eval->bheval, rbfv3_biharmonicseriesmax, _state); + } + + /* + * Recursively load coefficients into panels + */ + rcopyvr(eval->n, w, &eval->wstoredorig, 0, _state); + rbfv3_fastevaluatorloadcoeffsrec(eval, 0, _state); + + /* + * Done + */ + eval->isloaded = ae_true; +} + + +/************************************************************************* +Loads coefficients into fast evaluator (works with any NY>=1) + +Depending on the settings specified during evaluator creation (basis +function type and parameter), far field expansion can be built for the +model. + +INPUT PARAMETERS: + Eval - fast evaluator to load coefficients to + W - coeffs vector, array[NY,N] +*************************************************************************/ +static void rbfv3_fastevaluatorloadcoeffs(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* w, + ae_state *_state) +{ + + + ae_assert(eval->ny<=w->rows, "FastEvaluatorLoadCoeffs: Eval.NY>Rows(W)", _state); + ae_assert(ae_obj_array_get_length(&eval->panels)>0, "FastEvaluatorLoadCoeffs: Length(Panels)=0", _state); + + /* + * Prepare problem-specific evaluator, if any + */ + if( (eval->functype==1&&ae_fp_eq(eval->funcparam,0.0))&&eval->nx<=3 ) + { + biharmonicevaluatorinit(&eval->bheval, rbfv3_biharmonicseriesmax, _state); + } + + /* + * Recursively load coefficients into panels + */ + rmatrixcopy(eval->ny, eval->n, w, 0, 0, &eval->wstoredorig, 0, 0, _state); + rbfv3_fastevaluatorloadcoeffsrec(eval, 0, _state); + + /* + * Done + */ + eval->isloaded = ae_true; +} + + +/************************************************************************* +Recursive subroutine that recomputes far field radii according to user- +specified accuracy requirements. + +It should be called only for properly initialized models with coefficients +being loaded into them. +*************************************************************************/ +static void rbfv3_fastevaluatorpushtolrec(rbf3fastevaluator* eval, + ae_int_t treenodeidx, + ae_bool dotrace, + ae_int_t dbglevel, + double maxcomputeerr, + ae_state *_state) +{ + ae_frame _frame_block; + double childerr; + rbf3panel *panel; + ae_smart_ptr _panel; + ae_bool farfieldreconfigured; + + ae_frame_make(_state, &_frame_block); + memset(&_panel, 0, sizeof(_panel)); + ae_smart_ptr_init(&_panel, (void**)&panel, ae_false, _state, ae_true); + + ae_obj_array_get(&eval->panels, treenodeidx, &_panel, _state); + + /* + * Reconfigure far field expansion, if present + */ + if( panel->farfieldexpansion!=rbfv3_farfieldnone ) + { + farfieldreconfigured = ae_false; + + /* + * Far field expansions for a biharmonic kernel + */ + if( panel->farfieldexpansion==rbfv3_farfieldbiharmonic ) + { + bhpanelsetprec(&panel->bhexpansion, maxcomputeerr, _state); + panel->farfielddistance = panel->bhexpansion.useatdistance; + farfieldreconfigured = ae_true; + if( dotrace ) + { + tracespaces(dbglevel, _state); + ae_trace("* n=%0d, |c|=%0.1e, r/R=%0.1f\n", + (int)(panel->idx1-panel->idx0), + (double)(panel->bhexpansion.maxsumabs), + (double)(panel->bhexpansion.useatdistance/(panel->bhexpansion.rmax+1.0E-50))); + } + } + + /* + * Check that far field was recognized and processed + */ + ae_assert(farfieldreconfigured, "RBF3: unexpected far field at PushTolRec()", _state); + } + + /* + * Non-leaf panel with two children + */ + if( panel->paneltype==1 ) + { + + /* + * Propagate relaxed error bounds to children. Instead of requiring it to be + * MaxComputeErr/2 for each of the subpanels (the sum is MaxComputeErr, which + * guarantees that the error bound is satisfied) we use larger value: MaxComputeErr/sqrt(2). + * + * The idea is that individual panel errors are uncorrelated, so we can achieve + * better results by using relaxed error tolerances, but still having total + * sum - on average - within prescribed bounds. Because error estimates are + * overly cautious, it usually works fine. + */ + childerr = rcase2(rbfv3_userelaxederrorestimates, maxcomputeerr/1.41, maxcomputeerr/(double)2, _state); + rbfv3_fastevaluatorpushtolrec(eval, panel->childa, dotrace, dbglevel+1, childerr, _state); + rbfv3_fastevaluatorpushtolrec(eval, panel->childb, dotrace, dbglevel+1, childerr, _state); + ae_frame_leave(_state); + return; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Sets fast evaluator tolerance, reconfiguring far field radii all along +the evaluation tree. Assumes that coefficients were loaded with one of +FastEvaluatorLoadCoeffs()/FastEvaluatorLoadCoeffs1() calls. + +INPUT PARAMETERS: + Eval - fast evaluator with loaded coefficients + MaxComputeErr - non-negative value which controls accuracy of the + model evaluation: + * =0 means that we try to perform exact evaluation + (subject to rounding errors) and do not try + to utilize far field expansions + * >0 means that far field expansions are used when + we can save some time. Maximum absolute error + of the model will be at most MaxComputeErr. +*************************************************************************/ +static void rbfv3_fastevaluatorpushtol(rbf3fastevaluator* eval, + double maxcomputeerr, + ae_state *_state) +{ + ae_bool dotrace; + + + ae_assert(ae_isfinite(maxcomputeerr, _state), "FastEvaluatorPushTol: MaxComputeErr is not finite", _state); + ae_assert(ae_fp_greater_eq(maxcomputeerr,(double)(0)), "FastEvaluatorPushTol: MaxComputeErr<0", _state); + ae_assert(eval->isloaded, "FastEvaluatorPushTol: coefficients are not loaded", _state); + dotrace = ae_is_trace_enabled("RBF.DETAILED"); + if( dotrace ) + { + ae_trace("----- recomputing fast eval tolerances, printing far field info ------------------------------------\n"); + ae_trace("> new tolerance is %0.3e\n", + (double)(maxcomputeerr)); + } + rbfv3_fastevaluatorpushtolrec(eval, 0, dotrace, 0, maxcomputeerr, _state); +} + + +/************************************************************************* +Updates Y[] with result of panel-to-panel interaction using straightforward +O(PANELSIZE^2) computation formula. +*************************************************************************/ +static void rbfv3_fastevaluatorcomputepanel2panel(rbf3fastevaluator* eval, + rbf3panel* dstpanel, + rbf3panel* srcpanel, + rbf3evaluatorbuffer* buf, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t ndstpts; + ae_int_t i0; + ae_int_t k; + double distance0; + ae_int_t srcsize; + + + ae_assert(eval->ny==1, "RBF3Panel2Panel: ny>1", _state); + ae_assert(dstpanel->paneltype==0&&dstpanel->idx1-dstpanel->idx0<=eval->maxpanelsize, "RBF3: integrity check 2735 failed", _state); + ae_assert(srcpanel->paneltype==0&&srcpanel->idx1-srcpanel->idx0<=eval->maxpanelsize, "RBF3: integrity check 2736 failed", _state); + ndstpts = dstpanel->idx1-dstpanel->idx0; + srcsize = srcpanel->idx1-srcpanel->idx0; + distance0 = 1.0E-50; + if( eval->functype==1 ) + { + distance0 = distance0+ae_sqr(eval->funcparam, _state); + } + ae_assert(eval->functype==1||eval->functype==2, "RBF3: integrity check 9132 failed", _state); + for(i0=0; i0<=ndstpts-1; i0++) + { + rsetv(srcsize, distance0, &buf->funcbuf, _state); + for(k=0; k<=eval->nx-1; k++) + { + rsetv(srcsize, dstpanel->xt.ptr.pp_double[k][i0], &buf->wrkbuf, _state); + raddrv(srcsize, -1.0, &srcpanel->xt, k, &buf->wrkbuf, _state); + rmuladdv(srcsize, &buf->wrkbuf, &buf->wrkbuf, &buf->funcbuf, _state); + } + if( eval->functype==1 ) + { + + /* + * f=-sqrt(r^2+alpha^2), including f=-r as a special case + */ + rsqrtv(srcsize, &buf->funcbuf, _state); + rmulv(srcsize, -1.0, &buf->funcbuf, _state); + } + if( eval->functype==2 ) + { + + /* + * f=r^2*ln(r) + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle ln(0) as a special case. + */ + for(k=0; k<=srcsize-1; k++) + { + buf->funcbuf.ptr.p_double[k] = buf->funcbuf.ptr.p_double[k]*0.5*ae_log(buf->funcbuf.ptr.p_double[k], _state); + } + } + y->ptr.p_double[dstpanel->ptidx.ptr.p_int[i0]] = y->ptr.p_double[dstpanel->ptidx.ptr.p_int[i0]]+rdotvr(srcsize, &buf->funcbuf, &srcpanel->wt, 0, _state); + } +} + + +/************************************************************************* +Recursive evaluation function that recursively evaluates all source panels. + +The plan is for each target panel to evaluate all source panels that may +contribute to model values at target points. This function evaluates all +sources, given some target. + +This function has to be called with SourceTreeNode=0. +*************************************************************************/ +static void rbfv3_fastevaluatorcomputeallrecurseonsources(rbf3fastevaluator* eval, + rbf3panel* dstpanel, + rbf3evaluatorbuffer* buf, + ae_int_t sourcetreenode, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + rbf3panel *srcpanel; + ae_smart_ptr _srcpanel; + ae_int_t i0; + ae_int_t k; + double v; + double vv; + double dstpaneldistance; + ae_bool farfieldprocessed; + double c0; + double c1; + double c2; + ae_int_t ndstpts; + + ae_frame_make(_state, &_frame_block); + memset(&_srcpanel, 0, sizeof(_srcpanel)); + ae_smart_ptr_init(&_srcpanel, (void**)&srcpanel, ae_false, _state, ae_true); + + ndstpts = dstpanel->idx1-dstpanel->idx0; + ae_obj_array_get(&eval->panels, sourcetreenode, &_srcpanel, _state); + + /* + * Analyze possibility of applying far field expansion + */ + if( srcpanel->farfieldexpansion!=rbfv3_farfieldnone ) + { + dstpaneldistance = (double)(0); + for(k=0; k<=eval->nx-1; k++) + { + dstpaneldistance = dstpaneldistance+ae_sqr(dstpanel->clustercenter.ptr.p_double[k]-srcpanel->clustercenter.ptr.p_double[k], _state); + } + dstpaneldistance = ae_sqrt(dstpaneldistance, _state); + dstpaneldistance = dstpaneldistance-dstpanel->clusterrad; + if( ae_fp_greater(dstpaneldistance,srcpanel->farfielddistance) ) + { + farfieldprocessed = ae_false; + c0 = (double)(0); + c1 = (double)(0); + c2 = (double)(0); + if( srcpanel->farfieldexpansion==rbfv3_farfieldbiharmonic ) + { + for(i0=0; i0<=ndstpts-1; i0++) + { + if( eval->nx>=1 ) + { + c0 = dstpanel->xt.ptr.pp_double[0][i0]; + } + if( eval->nx>=2 ) + { + c1 = dstpanel->xt.ptr.pp_double[1][i0]; + } + if( eval->nx>=3 ) + { + c2 = dstpanel->xt.ptr.pp_double[2][i0]; + } + bhpaneleval1(&srcpanel->bhexpansion, &eval->bheval, c0, c1, c2, &v, ae_false, &vv, _state); + y->ptr.p_double[dstpanel->ptidx.ptr.p_int[i0]] = y->ptr.p_double[dstpanel->ptidx.ptr.p_int[i0]]+v; + } + farfieldprocessed = ae_true; + } + ae_assert(farfieldprocessed, "RBF3: integrity check 4832 failed", _state); + if( eval->usedebugcounters ) + { + threadunsafeinc(&eval->dbgfield2panelcnt, _state); + } + ae_frame_leave(_state); + return; + } + } + + /* + * Far field expansion is not present, or we are too close to the expansion center. + * Try recursive processing or handle leaf panel. + */ + if( srcpanel->paneltype==1 ) + { + rbfv3_fastevaluatorcomputeallrecurseonsources(eval, dstpanel, buf, srcpanel->childa, y, _state); + rbfv3_fastevaluatorcomputeallrecurseonsources(eval, dstpanel, buf, srcpanel->childb, y, _state); + } + else + { + rbfv3_fastevaluatorcomputepanel2panel(eval, dstpanel, srcpanel, buf, y, _state); + if( eval->usedebugcounters ) + { + threadunsafeinc(&eval->dbgpanel2panelcnt, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive evaluation function that recursively evaluates all target panels. + +The plan is for each target panel to evaluate all source panels that may +contribute to model values at target points. This function evaluates all +targets, and it passes control to another function that evaluates all +sources. + +This function has to be called with TargetTreeNode=0. +It can parallelize its computations. +*************************************************************************/ +static void rbfv3_fastevaluatorcomputeallrecurseontargets(rbf3fastevaluator* eval, + ae_int_t targettreenode, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + rbf3panel *dstpanel; + ae_smart_ptr _dstpanel; + + ae_frame_make(_state, &_frame_block); + memset(&_dstpanel, 0, sizeof(_dstpanel)); + ae_smart_ptr_init(&_dstpanel, (void**)&dstpanel, ae_false, _state, ae_true); + + + /* + * Do we need parallel execution? + * Checked only at the root. + */ + if( (targettreenode==0&&ae_fp_greater(rmul2((double)(eval->n), (double)(eval->n), _state),smpactivationlevel(_state)))&&ae_obj_array_get_length(&eval->panels)>1 ) + { + if( _trypexec_rbfv3_fastevaluatorcomputeallrecurseontargets(eval,targettreenode,y, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Evaluate destination panel + */ + ae_obj_array_get(&eval->panels, targettreenode, &_dstpanel, _state); + if( dstpanel->paneltype==1 ) + { + rbfv3_fastevaluatorcomputeallrecurseontargets(eval, dstpanel->childa, y, _state); + rbfv3_fastevaluatorcomputeallrecurseontargets(eval, dstpanel->childb, y, _state); + ae_frame_leave(_state); + return; + } + ae_assert(dstpanel->paneltype==0, "RBF3: integrity check 2735 failed", _state); + + /* + * Recurse on sources. + * Use evaluator buffer stored in target panel for temporaries. + */ + rbfv3_fastevaluatorcomputeallrecurseonsources(eval, dstpanel, &dstpanel->tgtbuf, 0, y, _state); + threadunsafeinc(&eval->dbgpanelscnt, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_fastevaluatorcomputeallrecurseontargets(rbf3fastevaluator* eval, + ae_int_t targettreenode, + /* Real */ ae_vector* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Performs batch evaluation at each node (assuming NY=1). +*************************************************************************/ +static void rbfv3_fastevaluatorcomputeall(rbf3fastevaluator* eval, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + ae_assert(eval->ny==1, "FastEvaluatorComputeAll: Eval.NY<>1", _state); + rsetallocv(eval->n, 0.0, y, _state); + eval->dbgpanel2panelcnt = 0; + eval->dbgfield2panelcnt = 0; + eval->dbgpanelscnt = 0; + rbfv3_fastevaluatorcomputeallrecurseontargets(eval, 0, y, _state); +} + + +/************************************************************************* +Recursion on source panels for batch evaluation + +NOTE: this function is thread-safe, the same Eval object can be used by + multiple threads calling ComputeBatch() concurrently. Although for + technical reasons Eval is accepted as non-const parameter, thread- + safety is guaranteed. + +INPUT PARAMETERS: + Eval - evaluator + X - array[N,NX], dataset + TgtIdx - target row index + SourceTreeNode- index of the current panel in the tree; must be zero. + UseFarFields- use far fields to accelerate computations - or use + slow but exact formulae + +OUTPUT PARAMETERS: + Y - array[NY,N], column TgtIdx is updated +*************************************************************************/ +static void rbfv3_fastevaluatorcomputebatchrecurseonsources(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t tgtidx, + ae_int_t sourcetreenode, + ae_bool usefarfields, + rbf3evaluatorbuffer* buf, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_frame _frame_block; + rbf3panel *srcpanel; + ae_smart_ptr _srcpanel; + ae_int_t srcsize; + ae_int_t k; + ae_int_t d; + double distance0; + double paneldistance; + ae_bool farfieldprocessed; + double c0; + double c1; + double c2; + double v; + double vv; + + ae_frame_make(_state, &_frame_block); + memset(&_srcpanel, 0, sizeof(_srcpanel)); + ae_smart_ptr_init(&_srcpanel, (void**)&srcpanel, ae_false, _state, ae_true); + + ae_obj_array_get(&eval->panels, sourcetreenode, &_srcpanel, _state); + + /* + * Analyze possibility of applying far field expansion + */ + if( srcpanel->farfieldexpansion!=rbfv3_farfieldnone&&usefarfields ) + { + paneldistance = (double)(0); + for(k=0; k<=eval->nx-1; k++) + { + paneldistance = paneldistance+ae_sqr(x->ptr.pp_double[tgtidx][k]-srcpanel->clustercenter.ptr.p_double[k], _state); + } + paneldistance = ae_sqrt(paneldistance, _state); + if( ae_fp_greater(paneldistance,srcpanel->farfielddistance) ) + { + farfieldprocessed = ae_false; + c0 = (double)(0); + c1 = (double)(0); + c2 = (double)(0); + if( srcpanel->farfieldexpansion==rbfv3_farfieldbiharmonic ) + { + if( eval->nx>=1 ) + { + c0 = x->ptr.pp_double[tgtidx][0]; + } + if( eval->nx>=2 ) + { + c1 = x->ptr.pp_double[tgtidx][1]; + } + if( eval->nx>=3 ) + { + c2 = x->ptr.pp_double[tgtidx][2]; + } + if( eval->ny==1 ) + { + bhpaneleval1(&srcpanel->bhexpansion, &eval->bheval, c0, c1, c2, &v, ae_false, &vv, _state); + y->ptr.pp_double[0][tgtidx] = y->ptr.pp_double[0][tgtidx]+v; + } + else + { + bhpaneleval(&srcpanel->bhexpansion, &eval->bheval, c0, c1, c2, &buf->y, ae_false, &vv, _state); + for(k=0; k<=eval->ny-1; k++) + { + y->ptr.pp_double[k][tgtidx] = y->ptr.pp_double[k][tgtidx]+buf->y.ptr.p_double[k]; + } + } + farfieldprocessed = ae_true; + } + ae_assert(farfieldprocessed, "RBF3: integrity check 4832 failed", _state); + if( eval->usedebugcounters ) + { + threadunsafeinc(&eval->dbgfield2panelcnt, _state); + } + ae_frame_leave(_state); + return; + } + } + + /* + * Perform recursive processing if needed + */ + if( srcpanel->paneltype==1 ) + { + rbfv3_fastevaluatorcomputebatchrecurseonsources(eval, x, tgtidx, srcpanel->childa, usefarfields, buf, y, _state); + rbfv3_fastevaluatorcomputebatchrecurseonsources(eval, x, tgtidx, srcpanel->childb, usefarfields, buf, y, _state); + ae_frame_leave(_state); + return; + } + ae_assert(srcpanel->paneltype==0&&srcpanel->idx1-srcpanel->idx0<=eval->maxpanelsize, "RBF3: integrity check 2735 failed", _state); + + /* + * Obtain evaluation buffer and process panel. + * Recycle the buffer later. + */ + ae_assert(eval->functype==1||eval->functype==2, "RBF3: integrity check 1132 failed", _state); + srcsize = srcpanel->idx1-srcpanel->idx0; + distance0 = 1.0E-50; + if( eval->functype==1 ) + { + distance0 = distance0+ae_sqr(eval->funcparam, _state); + } + rsetv(srcsize, distance0, &buf->funcbuf, _state); + for(k=0; k<=eval->nx-1; k++) + { + rsetv(srcsize, x->ptr.pp_double[tgtidx][k], &buf->wrkbuf, _state); + raddrv(srcsize, -1.0, &srcpanel->xt, k, &buf->wrkbuf, _state); + rmuladdv(srcsize, &buf->wrkbuf, &buf->wrkbuf, &buf->funcbuf, _state); + } + if( eval->functype==1 ) + { + + /* + * f=-sqrt(r^2+alpha^2), including f=-r as a special case + */ + rsqrtv(srcsize, &buf->funcbuf, _state); + rmulv(srcsize, -1.0, &buf->funcbuf, _state); + } + if( eval->functype==2 ) + { + + /* + * f=r^2*ln(r) + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle ln(0) as a special case. + */ + for(k=0; k<=srcsize-1; k++) + { + buf->funcbuf.ptr.p_double[k] = buf->funcbuf.ptr.p_double[k]*0.5*ae_log(buf->funcbuf.ptr.p_double[k], _state); + } + } + for(d=0; d<=eval->ny-1; d++) + { + y->ptr.pp_double[d][tgtidx] = y->ptr.pp_double[d][tgtidx]+rdotvr(srcsize, &buf->funcbuf, &srcpanel->wt, d, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_fastevaluatorcomputebatchrecurseonsources(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t tgtidx, + ae_int_t sourcetreenode, + ae_bool usefarfields, + rbf3evaluatorbuffer* buf, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Recursion on targets for batch evaluation, splits interval into smaller +ones. + +NOTE: this function is thread-safe, the same Eval object can be used by + multiple threads calling ComputeBatch() concurrently. Although for + technical reasons Eval is accepted as non-const parameter, thread- + safety is guaranteed. + +INPUT PARAMETERS: + Eval - evaluator + X - array[N,NX], dataset + Idx0,Idx1 - target range + IsRootCall - must be True + UseFarFields- use far fields to accelerate computations - or use + slow but exact formulae + +OUTPUT PARAMETERS: + Y - array[NY,N], computed values +*************************************************************************/ +static void rbfv3_fastevaluatorcomputebatchrecurseontargets(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + ae_bool usefarfields, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t size0; + ae_int_t size1; + rbf3evaluatorbuffer *buf; + ae_smart_ptr _buf; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + + /* + * Do we need parallel execution? + * Checked only at the root. + */ + if( (isrootcall&&idx1-idx0>rbfv3_maxcomputebatchsize)&&ae_fp_greater(rmul2((double)(eval->n), (double)(idx1-idx0), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_rbfv3_fastevaluatorcomputebatchrecurseontargets(eval,x,idx0,idx1,isrootcall,usefarfields,y, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Split targets + */ + if( idx1-idx0>rbfv3_maxcomputebatchsize ) + { + tiledsplit(idx1-idx0, rbfv3_maxcomputebatchsize, &size0, &size1, _state); + rbfv3_fastevaluatorcomputebatchrecurseontargets(eval, x, idx0, idx0+size0, ae_false, usefarfields, y, _state); + rbfv3_fastevaluatorcomputebatchrecurseontargets(eval, x, idx0+size0, idx1, ae_false, usefarfields, y, _state); + ae_frame_leave(_state); + return; + } + + /* + * Run recursion on sources + */ + ae_shared_pool_retrieve(&eval->bufferpool, &_buf, _state); + for(i=idx0; i<=idx1-1; i++) + { + rbfv3_fastevaluatorcomputebatchrecurseonsources(eval, x, i, 0, usefarfields, buf, y, _state); + } + ae_shared_pool_recycle(&eval->bufferpool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_fastevaluatorcomputebatchrecurseontargets(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t idx0, + ae_int_t idx1, + ae_bool isrootcall, + ae_bool usefarfields, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Performs batch evaluation at user-specified points which does not have to +coincide with nodes. Assumes NY=1. + +NOTE: this function is thread-safe, the same Eval object can be used by + multiple threads calling ComputeBatch() concurrently. Although for + technical reasons Eval is accepted as non-const parameter, thread- + safety is guaranteed. + +INPUT PARAMETERS: + Eval - evaluator + X - array[N,NX], dataset + N - rows count + UseFarFields- use far fields to accelerate computations - or use + slow but exact formulae + +OUTPUT PARAMETERS: + Y - array[NY,N], computed values. + The array is reallocated if needed. +*************************************************************************/ +static void rbfv3_fastevaluatorcomputebatch(rbf3fastevaluator* eval, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_bool usefarfields, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + + + rsetallocm(eval->ny, n, 0.0, y, _state); + rbfv3_fastevaluatorcomputebatchrecurseontargets(eval, x, 0, n, ae_true, usefarfields, y, _state); +} + + +/************************************************************************* +Creates fast evaluation structures after initialization of the model + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_createfastevaluator(rbfv3model* model, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t offs; + ae_int_t ontheflystorage; + ae_int_t i; + ae_int_t j; + ae_int_t nchunks; + ae_int_t srcoffs; + ae_int_t dstoffs; + ae_int_t curlen; + ae_matrix xx; + ae_matrix ct; + + ae_frame_make(_state, &_frame_block); + memset(&xx, 0, sizeof(xx)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&xx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ct, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Extract dataset into separate matrix + */ + rallocm(model->nc, model->nx, &xx, _state); + rallocm(model->ny, model->nc, &ct, _state); + offs = 0; + for(i=0; i<=model->nc-1; i++) + { + for(j=0; j<=model->nx-1; j++) + { + xx.ptr.pp_double[i][j] = model->cw.ptr.p_double[offs+j]; + } + offs = offs+model->nx; + for(j=0; j<=model->ny-1; j++) + { + ct.ptr.pp_double[j][i] = model->cw.ptr.p_double[offs+j]; + } + offs = offs+model->ny; + } + + /* + * Prepare fast evaluator + */ + rbfv3_fastevaluatorinit(&model->fasteval, &xx, model->nc, model->nx, model->ny, rbfv3_defaultmaxpanelsize, model->bftype, model->bfparam, ae_false, _state); + rbfv3_fastevaluatorloadcoeffs(&model->fasteval, &ct, _state); + rbfv3_fastevaluatorpushtol(&model->fasteval, rbfv3_defaultfastevaltol, _state); + + /* + * Setup model matrix structure + */ + ontheflystorage = 1; + rbfv3_modelmatrixinit(&xx, model->nc, model->nx, model->bftype, model->bfparam, ontheflystorage, &model->evaluator, _state); + + /* + * Store model coefficients in the efficient chunked format (chunk size is aligned with that + * of the Model.Evaluator). + */ + ae_assert(model->evaluator.chunksize>=1, "RBFV3: integrity check 3535 failed", _state); + nchunks = idivup(model->nc, model->evaluator.chunksize, _state); + rsetallocm(nchunks*model->ny, model->evaluator.chunksize, 0.0, &model->wchunked, _state); + srcoffs = 0; + dstoffs = 0; + while(srcoffsnc) + { + curlen = ae_minint(model->evaluator.chunksize, model->nc-srcoffs, _state); + for(i=0; i<=curlen-1; i++) + { + for(j=0; j<=model->ny-1; j++) + { + model->wchunked.ptr.pp_double[dstoffs+j][i] = model->cw.ptr.p_double[(srcoffs+i)*(model->nx+model->ny)+model->nx+j]; + } + } + srcoffs = srcoffs+curlen; + dstoffs = dstoffs+model->ny; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive worker function for gridded calculation + + -- ALGLIB -- + Copyright 01.05.2022 by Bochkanov Sergey +*************************************************************************/ +static void rbfv3_gridcalcrec(const rbfv3model* s, + ae_int_t simdwidth, + ae_int_t tileidx0, + ae_int_t tileidx1, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_shared_pool* calcpool, + ae_bool isrootcall, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t dstoffs; + ae_int_t l; + rbfv3calcbuffer *buf; + ae_smart_ptr _buf; + double problemcost; + ae_int_t tileidxm; + ae_int_t k0; + ae_int_t k1; + ae_int_t k2; + ae_int_t r0a; + ae_int_t r0b; + ae_int_t r1a; + ae_int_t r1b; + ae_int_t r2a; + ae_int_t r2b; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + ny = s->ny; + + /* + * Try parallelism if needed; then perform parallel subdivision: + * * make all dimensions either (a) multiples of SIMDWidth or (b) less than SIMDWidth by + * splitting small chunks from tails + * * after that iteratively subdivide largest side of the grid (one having largest length, + * not largest points count) until we have a chunk with nodes count not greater than SIMDWidth + */ + problemcost = rmul2((double)(tileidx1-tileidx0), (double)(s->nc), _state); + problemcost = problemcost*rmul4((double)(ae_minint(n0, simdwidth, _state)), (double)(ae_minint(n1, simdwidth, _state)), (double)(ae_minint(n2, simdwidth, _state)), (double)(ae_minint(n3, simdwidth, _state)), _state); + if( isrootcall&&ae_fp_greater_eq(problemcost,smpactivationlevel(_state)) ) + { + if( _trypexec_rbfv3_gridcalcrec(s,simdwidth,tileidx0,tileidx1,x0,n0,x1,n1,x2,n2,x3,n3,flagy,sparsey,y,calcpool,isrootcall, _state) ) + { + ae_frame_leave(_state); + return; + } + } + if( ae_fp_greater_eq(problemcost,spawnlevel(_state))&&tileidx1-tileidx0>=2 ) + { + } + if( tileidx1-tileidx0>=2 ) + { + tileidxm = tileidx0+idivup(tileidx1-tileidx0, 2, _state); + rbfv3_gridcalcrec(s, simdwidth, tileidx0, tileidxm, x0, n0, x1, n1, x2, n2, x3, n3, flagy, sparsey, y, calcpool, ae_false, _state); + rbfv3_gridcalcrec(s, simdwidth, tileidxm, tileidx1, x0, n0, x1, n1, x2, n2, x3, n3, flagy, sparsey, y, calcpool, ae_false, _state); + ae_frame_leave(_state); + return; + } + + /* + * Handle basecase + */ + k = tileidx0; + k0 = k%idivup(n0, simdwidth, _state); + k = k/idivup(n0, simdwidth, _state); + k1 = k%idivup(n1, simdwidth, _state); + k = k/idivup(n1, simdwidth, _state); + k2 = k%idivup(n2, simdwidth, _state); + k = k/idivup(n2, simdwidth, _state); + k = k/idivup(n3, simdwidth, _state); + ae_assert(k==0, "RBFV3: integrity check 7350 failed", _state); + r0a = k0*simdwidth; + r0b = ae_minint(r0a+simdwidth, n0, _state); + r1a = k1*simdwidth; + r1b = ae_minint(r1a+simdwidth, n1, _state); + r2a = k2*simdwidth; + r2b = ae_minint(r2a+simdwidth, n2, _state); + ae_shared_pool_retrieve(calcpool, &_buf, _state); + for(i=r0a; i<=r0b-1; i++) + { + for(j=r1a; j<=r1b-1; j++) + { + for(k=r2a; k<=r2b-1; k++) + { + dstoffs = i+j*n0+k*n0*n1; + if( sparsey&&!flagy->ptr.p_bool[dstoffs] ) + { + for(l=0; l<=ny-1; l++) + { + y->ptr.p_double[l+ny*dstoffs] = (double)(0); + } + continue; + } + buf->xg.ptr.p_double[0] = x0->ptr.p_double[i]; + buf->xg.ptr.p_double[1] = x1->ptr.p_double[j]; + buf->xg.ptr.p_double[2] = x2->ptr.p_double[k]; + rbfv3tscalcbuf(s, buf, &buf->xg, &buf->yg, _state); + for(l=0; l<=ny-1; l++) + { + y->ptr.p_double[l+ny*dstoffs] = buf->yg.ptr.p_double[l]; + } + } + } + } + ae_shared_pool_recycle(calcpool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_gridcalcrec(const rbfv3model* s, + ae_int_t simdwidth, + ae_int_t tileidx0, + ae_int_t tileidx1, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_shared_pool* calcpool, + ae_bool isrootcall, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function fills RBF model by zeros, also cleans up debug fields. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +static void rbfv3_zerofill(rbfv3model* s, + ae_int_t nx, + ae_int_t ny, + ae_state *_state) +{ + + + s->bftype = 0; + s->bfparam = (double)(0); + s->nc = 0; + rsetallocv(nx, 1.0, &s->s, _state); + rsetallocm(ny, nx+1, 0.0, &s->v, _state); +} + + +/************************************************************************* +Reallocates calcBuf if necessary, reuses previously allocated space if +possible. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_allocatecalcbuffer(const rbfv3model* s, + rbfv3calcbuffer* buf, + ae_state *_state) +{ + + + if( buf->x.cntnx ) + { + ae_vector_set_length(&buf->x, s->nx, _state); + } + if( buf->x123.cntnx ) + { + ae_vector_set_length(&buf->x123, s->nx, _state); + } + if( buf->y123.cntny ) + { + ae_vector_set_length(&buf->y123, s->ny, _state); + } + if( buf->xg.cnt<4 ) + { + ae_vector_set_length(&buf->xg, 4, _state); + } + if( buf->yg.cntny ) + { + ae_vector_set_length(&buf->yg, s->ny, _state); + } +} + + +/************************************************************************* +Recursive function that merges points, used by PreprocessDataset() + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_preprocessdatasetrec(/* Real */ ae_matrix* xbuf, + /* Real */ ae_matrix* ybuf, + /* Integer */ ae_vector* initidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nx, + ae_int_t ny, + double mergetol, + /* Real */ ae_vector* tmpboxmin, + /* Real */ ae_vector* tmpboxmax, + /* Real */ ae_matrix* xout, + /* Real */ ae_matrix* yout, + /* Integer */ ae_vector* raw2wrkmap, + /* Integer */ ae_vector* wrk2rawmap, + ae_int_t* nout, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t largestdim; + double splitval; + + + if( wrk1<=wrk0 ) + { + return; + } + + /* + * Analyze current working set + */ + rallocv(nx, tmpboxmin, _state); + rallocv(nx, tmpboxmax, _state); + rcopyrv(nx, xbuf, wrk0, tmpboxmin, _state); + rcopyrv(nx, xbuf, wrk0, tmpboxmax, _state); + for(i=wrk0+1; i<=wrk1-1; i++) + { + for(j=0; j<=nx-1; j++) + { + tmpboxmin->ptr.p_double[j] = ae_minreal(tmpboxmin->ptr.p_double[j], xbuf->ptr.pp_double[i][j], _state); + tmpboxmax->ptr.p_double[j] = ae_maxreal(tmpboxmax->ptr.p_double[j], xbuf->ptr.pp_double[i][j], _state); + } + } + largestdim = 0; + for(j=1; j<=nx-1; j++) + { + if( ae_fp_greater(tmpboxmax->ptr.p_double[j]-tmpboxmin->ptr.p_double[j],tmpboxmax->ptr.p_double[largestdim]-tmpboxmin->ptr.p_double[largestdim]) ) + { + largestdim = j; + } + } + + /* + * Handle basecase or perform recursive split + */ + if( wrk1-wrk0==1||ae_fp_less(tmpboxmax->ptr.p_double[largestdim]-tmpboxmin->ptr.p_double[largestdim],mergetol*rmax3(rmaxabsv(nx, tmpboxmax, _state), rmaxabsv(nx, tmpboxmin, _state), (double)(1), _state)) ) + { + + /* + * Merge all points, output + */ + rsetr(nx, 0.0, xout, *nout, _state); + rsetr(ny, 0.0, yout, *nout, _state); + for(i=wrk0; i<=wrk1-1; i++) + { + raddrr(nx, (double)1/(double)(wrk1-wrk0), xbuf, i, xout, *nout, _state); + raddrr(ny, (double)1/(double)(wrk1-wrk0), ybuf, i, yout, *nout, _state); + raw2wrkmap->ptr.p_int[initidx->ptr.p_int[i]] = *nout; + } + wrk2rawmap->ptr.p_int[*nout] = initidx->ptr.p_int[wrk0]; + *nout = *nout+1; + } + else + { + + /* + * Perform recursive split along largest axis + */ + splitval = 0.5*(tmpboxmax->ptr.p_double[largestdim]+tmpboxmin->ptr.p_double[largestdim]); + k0 = wrk0; + k1 = wrk1-1; + while(k0<=k1) + { + if( ae_fp_less_eq(xbuf->ptr.pp_double[k0][largestdim],splitval) ) + { + k0 = k0+1; + continue; + } + if( ae_fp_greater(xbuf->ptr.pp_double[k1][largestdim],splitval) ) + { + k1 = k1-1; + continue; + } + swaprows(xbuf, k0, k1, nx, _state); + swaprows(ybuf, k0, k1, ny, _state); + swapelementsi(initidx, k0, k1, _state); + k0 = k0+1; + k1 = k1-1; + } + ae_assert(k0>wrk0&&k10, NX>0, NY>0 + BFType - basis function type + BFParamRaw - initial value for basis function paramerer (before + applying additional rescaling AddXRescaleAplied) + LambdaVRaw - smoothing coefficient, as specified by user + +OUTPUT PARAMETERS: + XWrk - array[NWrk,NX], processed points, XWrk=(XRaw-XShift)/XScaleWrk + YWrk - array[NWrk,NY], targets, scaled by dividing by YScale + PointIndexes- array[NWrk], point indexes in the original dataset + NWrk - number of points after preprocessing, 0=1, "RBFV3: integrity check 7295 failed", _state); + + /* + * Scale dataset: + * * first, scale it according to user-supplied scale + * * second, analyze original dataset and rescale it one more time (same scaling across + * all dimensions) so it has zero mean and unit deviation + * As a result, user-supplied scaling handles dimensionality issues and our additional + * scaling normalizes data. + * + * After this block we have NRaw-sized dataset in XWrk/YWrk + */ + rcopyallocv(nx, &xscaleraw, xscalewrk, _state); + rsetallocv(nx, 0.0, xshift, _state); + rallocm(nraw, nx, xwrk, _state); + for(i=0; i<=nraw-1; i++) + { + for(j=0; j<=nx-1; j++) + { + xwrk->ptr.pp_double[i][j] = xraw.ptr.pp_double[i][j]/xscalewrk->ptr.p_double[j]; + xshift->ptr.p_double[j] = xshift->ptr.p_double[j]+xwrk->ptr.pp_double[i][j]; + } + } + rmulv(nx, (double)1/(double)nraw, xshift, _state); + v = (double)(0); + for(i=0; i<=nraw-1; i++) + { + for(j=0; j<=nx-1; j++) + { + v = v+(xwrk->ptr.pp_double[i][j]-xshift->ptr.p_double[j])*(xwrk->ptr.pp_double[i][j]-xshift->ptr.p_double[j]); + } + } + *addxrescaleaplied = ae_sqrt((v+ae_sqrt(ae_machineepsilon, _state))/(double)(nraw*nx), _state); + *bfparamwrk = bfparamraw; + if( bftype==1 ) + { + + /* + * Basis function parameter needs rescaling + */ + if( ae_fp_less(bfparamraw,(double)(0)) ) + { + *bfparamwrk = rbfv3_autodetectscaleparameter(xwrk, nraw, nx, _state)*(-bfparamraw)/(*addxrescaleaplied); + } + else + { + *bfparamwrk = bfparamraw/(*addxrescaleaplied); + } + } + else + { + if( bftype==2 ) + { + + /* + * Thin plate splines need special scaling; no params to rescale + */ + *addxrescaleaplied = rbfv3_polyharmonic2scale*(*addxrescaleaplied); + } + else + { + ae_assert(ae_false, "RBFV3: integrity check 0632 failed", _state); + } + } + rmulv(nx, *addxrescaleaplied, xscalewrk, _state); + for(i=0; i<=nraw-1; i++) + { + for(j=0; j<=nx-1; j++) + { + xwrk->ptr.pp_double[i][j] = (xraw.ptr.pp_double[i][j]-xshift->ptr.p_double[j])/xscalewrk->ptr.p_double[j]; + } + } + rcopyallocm(nraw, ny, &yraw, ywrk, _state); + + /* + * Merge nondistinct points + */ + iallocv(nraw, &initidx, _state); + for(i=0; i<=nraw-1; i++) + { + initidx.ptr.p_int[i] = i; + } + rcopyallocm(nraw, nx, xwrk, &xbuf, _state); + rcopyallocm(nraw, ny, ywrk, &ybuf, _state); + iallocv(nraw, raw2wrkmap, _state); + iallocv(nraw, wrk2rawmap, _state); + *nwrk = 0; + rbfv3_preprocessdatasetrec(&xbuf, &ybuf, &initidx, 0, nraw, nx, ny, mergetol, &tmp0, &tmp1, xwrk, ywrk, raw2wrkmap, wrk2rawmap, nwrk, _state); + + /* + * Compute LambdaV: + * * compute bounding box + * * compute DIAG2 = squared diagonal of the box + * * set LambdaVWrk = LambdaVRaw times upper bound of the basis function value + */ + rallocv(nx, &boxmin, _state); + rallocv(nx, &boxmax, _state); + rcopyrv(nx, xwrk, 0, &boxmin, _state); + rcopyrv(nx, xwrk, 0, &boxmax, _state); + for(i=1; i<=*nwrk-1; i++) + { + rmergeminrv(nx, xwrk, i, &boxmin, _state); + rmergemaxrv(nx, xwrk, i, &boxmax, _state); + } + diag2 = (double)(0); + for(i=0; i<=nx-1; i++) + { + diag2 = diag2+ae_sqr(boxmax.ptr.p_double[i]-boxmin.ptr.p_double[i], _state); + } + diag2 = ae_maxreal(diag2, (double)(1), _state); + if( bftype==1 ) + { + *lambdavwrk = lambdavraw*ae_sqrt(diag2+*bfparamwrk*(*bfparamwrk), _state); + } + else + { + if( bftype==2 ) + { + *lambdavwrk = lambdavraw*diag2*ae_maxreal(ae_fabs(0.5*ae_log(diag2, _state), _state), 1.0, _state); + } + else + { + *lambdavwrk = lambdavraw; + ae_assert(ae_false, "RBFV3: integrity check 7232 failed", _state); + } + } + *lambdavwrk = *lambdavwrk/ae_sqr(*addxrescaleaplied, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function selects NSpec global nodes for approximate cardinal basis functions. + +This function has O(N*NSpec) running time and O(N) memory requirements. + +Each approximate cardinal basis function is a combination of several local +nodes (ones nearby to the center) and several global nodes (ones scattered +over entire dataset span). + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_selectglobalnodes(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + /* Integer */ const ae_vector* existingnodes, + ae_int_t nexisting, + ae_int_t nspec, + /* Integer */ ae_vector* nodes, + ae_int_t* nchosen, + double* maxdist, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector d2; + ae_vector x; + ae_vector busy; + double v; + double vv; + + ae_frame_make(_state, &_frame_block); + memset(&d2, 0, sizeof(d2)); + memset(&x, 0, sizeof(x)); + memset(&busy, 0, sizeof(busy)); + *nchosen = 0; + *maxdist = 0.0; + ae_vector_init(&d2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&busy, 0, DT_BOOL, _state, ae_true); + + ae_assert(n>=1, "RBFV3: integrity check 6429 failed", _state); + ae_assert(nexisting>=0, "RBFV3: integrity check 6412 failed", _state); + ae_assert(nspec>=1, "RBFV3: integrity check 6430 failed", _state); + nspec = ae_minint(nspec, n, _state); + rsetallocv(n, 1.0E50, &d2, _state); + rsetallocv(nx, 0.0, &x, _state); + bsetallocv(n, ae_false, &busy, _state); + if( nexisting==0 ) + { + + /* + * No initial grid is provided, start distance evaluation from the data center + */ + for(i=0; i<=n-1; i++) + { + rcopyrv(nx, xx, i, &x, _state); + } + rmulv(nx, (double)1/(double)n, &x, _state); + } + else + { + + /* + * + */ + ae_assert(ae_false, "SelectGlobalNodes: NExisting<>0", _state); + } + iallocv(nspec, nodes, _state); + *nchosen = 0; + *maxdist = ae_maxrealnumber; + while(*nchosenptr.pp_double[j][k]; + v = v+vv*vv; + } + d2.ptr.p_double[j] = ae_minreal(d2.ptr.p_double[j], v, _state); + } + + /* + * Select point with largest distance, add + */ + k = 0; + for(j=0; j<=n-1; j++) + { + if( ae_fp_greater(d2.ptr.p_double[j],d2.ptr.p_double[k])&&!busy.ptr.p_bool[j] ) + { + k = j; + } + } + if( busy.ptr.p_bool[k] ) + { + break; + } + *maxdist = ae_minreal(*maxdist, d2.ptr.p_double[k], _state); + nodes->ptr.p_int[*nchosen] = k; + busy.ptr.p_bool[k] = ae_true; + rcopyrv(nx, xx, k, &x, _state); + *nchosen = *nchosen+1; + } + *maxdist = ae_sqrt(*maxdist, _state); + ae_assert(*nchosen>=1||nexisting>0, "RBFV3: integrity check 6431 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function builds simplified tagged KD-tree: it assigns a tag (index in +the dataset) to each point, then drops most points (leaving approximately +1/ReduceFactor of the entire dataset) trying to spread residual points +uniformly, and then constructs KD-tree. + +It ensures that at least min(N,MinSize) points is retained. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_buildsimplifiedkdtree(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t reducefactor, + ae_int_t minsize, + kdtree* kdt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t ns; + ae_matrix xs; + ae_vector idx; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&xs, 0, sizeof(xs)); + memset(&idx, 0, sizeof(idx)); + memset(&rs, 0, sizeof(rs)); + _kdtree_clear(kdt); + ae_matrix_init(&xs, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&idx, 0, DT_INT, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(n>=1, "BuildSimplifiedKDTree: N<1", _state); + ae_assert(reducefactor>=1, "BuildSimplifiedKDTree: ReduceFactor<1", _state); + ae_assert(minsize>=0, "BuildSimplifiedKDTree: ReduceFactor<1", _state); + hqrndseed(7674, 45775, &rs, _state); + ns = imax3(ae_round((double)n/(double)reducefactor, _state), minsize, 1, _state); + ns = ae_minint(ns, n, _state); + iallocv(n, &idx, _state); + rallocm(ns, nx, &xs, _state); + for(i=0; i<=n-1; i++) + { + idx.ptr.p_int[i] = i; + } + for(i=0; i<=ns-1; i++) + { + j = i+hqrnduniformi(&rs, n-i, _state); + k = idx.ptr.p_int[i]; + idx.ptr.p_int[i] = idx.ptr.p_int[j]; + idx.ptr.p_int[j] = k; + rcopyrr(nx, xx, idx.ptr.p_int[i], &xs, i, _state); + } + kdtreebuildtagged(&xs, &idx, ns, nx, 0, 2, kdt, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Compute design matrices for the target-scatter preconditioner + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computetargetscatterdesignmatrices(/* Real */ const ae_matrix* xx, + ae_int_t ntotal, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Integer */ const ae_vector* workingnodes, + ae_int_t nwrk, + /* Integer */ const ae_vector* scatternodes, + ae_int_t nscatter, + /* Real */ ae_matrix* atwrk, + /* Real */ ae_matrix* atsctr, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + ae_int_t ni; + ae_int_t nj; + double alpha2; + + + + /* + * Compute working set and scatter set design matrices ATWrk and ATSctr + * + * ATWrk is a (NWrk+NX+1)*NWrk matrix whose entries a[i,j] store: + * * for Iptr.p_int[i]; + for(j=i; j<=nwrk-1; j++) + { + nj = workingnodes->ptr.p_int[j]; + v = (double)(0); + for(k=0; k<=nx-1; k++) + { + vv = xx->ptr.pp_double[ni][k]-xx->ptr.pp_double[nj][k]; + v = v+vv*vv; + } + if( functype==1 ) + { + v = -ae_sqrt(v+alpha2, _state); + } + if( functype==2 ) + { + if( v!=(double)0 ) + { + v = v*0.5*ae_log(v, _state); + } + else + { + v = (double)(0); + } + } + if( functype==3 ) + { + v = v*ae_sqrt(v, _state); + } + atwrk->ptr.pp_double[i][j] = v; + atwrk->ptr.pp_double[j][i] = v; + } + } + for(j=0; j<=nwrk-1; j++) + { + nj = workingnodes->ptr.p_int[j]; + for(i=0; i<=nx-1; i++) + { + atwrk->ptr.pp_double[nwrk+i][j] = xx->ptr.pp_double[nj][i]; + } + } + for(j=0; j<=nwrk-1; j++) + { + atwrk->ptr.pp_double[nwrk+nx][j] = 1.0; + } + if( nscatter>0 ) + { + + /* + * We have scattered points too + */ + rallocm(nwrk+nx+1, nscatter, atsctr, _state); + for(i=0; i<=nwrk-1; i++) + { + ni = workingnodes->ptr.p_int[i]; + for(j=0; j<=nscatter-1; j++) + { + nj = scatternodes->ptr.p_int[j]; + v = (double)(0); + for(k=0; k<=nx-1; k++) + { + vv = xx->ptr.pp_double[ni][k]-xx->ptr.pp_double[nj][k]; + v = v+vv*vv; + } + if( functype==1 ) + { + v = -ae_sqrt(v+alpha2, _state); + } + if( functype==2 ) + { + if( v!=(double)0 ) + { + v = v*0.5*ae_log(v, _state); + } + else + { + v = (double)(0); + } + } + if( functype==3 ) + { + v = v*ae_sqrt(v, _state); + } + atsctr->ptr.pp_double[i][j] = v; + } + } + for(j=0; j<=nscatter-1; j++) + { + nj = scatternodes->ptr.p_int[j]; + for(i=0; i<=nx-1; i++) + { + atsctr->ptr.pp_double[nwrk+i][j] = xx->ptr.pp_double[nj][i]; + } + } + for(j=0; j<=nscatter-1; j++) + { + atsctr->ptr.pp_double[nwrk+nx][j] = 1.0; + } + } +} + + +/************************************************************************* +ACBF preconditioner generation basecase. + +PARAMETERS: + Builder - ACBF builder object + Wrk0, Wrk1 - elements [Wrk0...Wrk1-1] of Builder.WrkIdx[] + array store row indexes of XX that are processed. + +OUTPUT: + Builder.OutputPool is updated with new chunks + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computeacbfpreconditionerbasecase(acbfbuilder* builder, + acbfbuffer* buf, + ae_int_t wrk0, + ae_int_t wrk1, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t widx; + ae_int_t targetidx; + ae_int_t nx; + ae_int_t nglobal; + ae_int_t nlocal; + ae_int_t ncorrection; + ae_int_t ncenters; + ae_int_t nchosen; + ae_int_t ncoeff; + ae_int_t batchsize; + ae_int_t nk; + ae_int_t nq; + ae_vector x; + ae_vector batchcenter; + ae_vector idummy; + double localrad; + double currentrad; + double reg; + double v; + double vv; + double mx; + double maxdist2; + ae_int_t ortbasissize; + ae_vector ortbasismap; + acbfchunk *precchunk; + ae_smart_ptr _precchunk; + ae_int_t expansionscount; + ae_matrix dbgb; + double dbgerrnodes; + double dbgerrort; + double dbgcondq; + double dbgmaxc; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&batchcenter, 0, sizeof(batchcenter)); + memset(&idummy, 0, sizeof(idummy)); + memset(&ortbasismap, 0, sizeof(ortbasismap)); + memset(&_precchunk, 0, sizeof(_precchunk)); + memset(&dbgb, 0, sizeof(dbgb)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&batchcenter, 0, DT_REAL, _state, ae_true); + ae_vector_init(&idummy, 0, DT_INT, _state, ae_true); + ae_vector_init(&ortbasismap, 0, DT_INT, _state, ae_true); + ae_smart_ptr_init(&_precchunk, (void**)&precchunk, ae_false, _state, ae_true); + ae_matrix_init(&dbgb, 0, 0, DT_REAL, _state, ae_true); + + if( wrk1<=wrk0 ) + { + ae_frame_leave(_state); + return; + } + nx = builder->nx; + nglobal = builder->nglobal; + nlocal = builder->nlocal; + ncorrection = builder->ncorrection; + reg = ae_sqrt(ae_machineepsilon, _state); + rallocv(nx, &x, _state); + expansionscount = 0; + + /* + * First, select a batch of central points and compute batch center + */ + batchsize = wrk1-wrk0; + iallocv(batchsize, &buf->currentnodes, _state); + rsetallocv(nx, 0.0, &batchcenter, _state); + for(i=0; i<=batchsize-1; i++) + { + targetidx = builder->wrkidx.ptr.p_int[wrk0+i]; + buf->currentnodes.ptr.p_int[i] = targetidx; + buf->bflags.ptr.p_bool[targetidx] = ae_true; + raddrv(nx, (double)1/(double)batchsize, &builder->xx, builder->wrkidx.ptr.p_int[wrk0+i], &batchcenter, _state); + } + ncenters = batchsize; + + /* + * Then, add a hull of nearest neighbors and compute its radius + */ + localrad = (double)(0); + for(widx=0; widx<=batchsize-1; widx++) + { + + /* + * Select immediate neighbors + */ + rcopyrv(nx, &builder->xx, builder->wrkidx.ptr.p_int[wrk0+widx], &x, _state); + nq = kdtreetsqueryknn(&builder->kdt, &buf->kdtbuf, &x, nlocal, ae_true, _state); + kdtreetsqueryresultstags(&builder->kdt, &buf->kdtbuf, &buf->neighbors, _state); + kdtreetsqueryresultsdistances(&builder->kdt, &buf->kdtbuf, &buf->d, _state); + for(k=0; k<=nq-1; k++) + { + nk = buf->neighbors.ptr.p_int[k]; + if( !buf->bflags.ptr.p_bool[nk] ) + { + buf->bflags.ptr.p_bool[nk] = ae_true; + igrowv(ncenters+1, &buf->currentnodes, _state); + buf->currentnodes.ptr.p_int[ncenters] = nk; + ncenters = ncenters+1; + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+(builder->xx.ptr.pp_double[nk][j]-batchcenter.ptr.p_double[j])*(builder->xx.ptr.pp_double[nk][j]-batchcenter.ptr.p_double[j]); + } + localrad = ae_maxreal(localrad, v, _state); + } + } + } + localrad = ae_sqrt(localrad, _state); + currentrad = localrad; + + /* + * Add global grid + */ + if( nglobal>0 ) + { + for(k=0; k<=nglobal-1; k++) + { + nk = builder->globalgrid.ptr.p_int[k]; + if( !buf->bflags.ptr.p_bool[nk] ) + { + buf->bflags.ptr.p_bool[nk] = ae_true; + igrowv(ncenters+1, &buf->currentnodes, _state); + buf->currentnodes.ptr.p_int[ncenters] = nk; + ncenters = ncenters+1; + } + } + } + + /* + * Add local correction grid: select more distant neighbors + */ + while((ncorrection>0&&ae_fp_greater(currentrad,(double)(0)))&&ae_fp_less(currentrad,builder->roughdatasetdiameter)) + { + + /* + * Select neighbors within CurrentRad*Builder.CorrectorGrowth + */ + if( expansionscount==0 ) + { + + /* + * First expansion, use simplified kd-tree #1 + */ + nq = kdtreetsqueryrnn(&builder->kdt1, &buf->kdt1buf, &batchcenter, currentrad*builder->correctorgrowth, ae_true, _state); + kdtreetsqueryresultstags(&builder->kdt1, &buf->kdt1buf, &buf->neighbors, _state); + } + else + { + + /* + * Subsequent expansions, use simplified kd-tree #2 + */ + nq = kdtreetsqueryrnn(&builder->kdt2, &buf->kdt2buf, &batchcenter, currentrad*builder->correctorgrowth, ae_true, _state); + kdtreetsqueryresultstags(&builder->kdt2, &buf->kdt2buf, &buf->neighbors, _state); + } + + /* + * Compute a grid of well-separated nodes using neighbors + */ + rallocm(nq, nx, &buf->xq, _state); + for(k=0; k<=nq-1; k++) + { + nk = buf->neighbors.ptr.p_int[k]; + for(j=0; j<=nx-1; j++) + { + buf->xq.ptr.pp_double[k][j] = builder->xx.ptr.pp_double[nk][j]; + } + } + rbfv3_selectglobalnodes(&buf->xq, nq, nx, &idummy, 0, ncorrection, &buf->chosenneighbors, &nchosen, &maxdist2, _state); + + /* + * Select neighbrs that are NOT within CurrentRad from the batch center + * and that are NOT already chosen. + */ + for(k=0; k<=nchosen-1; k++) + { + nk = buf->neighbors.ptr.p_int[buf->chosenneighbors.ptr.p_int[k]]; + v = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = v+ae_sqr(builder->xx.ptr.pp_double[nk][j]-batchcenter.ptr.p_double[j], _state); + } + v = ae_sqrt(v, _state); + if( !buf->bflags.ptr.p_bool[nk]&&ae_fp_greater(v,currentrad) ) + { + buf->bflags.ptr.p_bool[nk] = ae_true; + igrowv(ncenters+1, &buf->currentnodes, _state); + buf->currentnodes.ptr.p_int[ncenters] = nk; + ncenters = ncenters+1; + } + } + + /* + * Update radius and debug counters + */ + currentrad = currentrad*builder->correctorgrowth; + inc(&expansionscount, _state); + } + + /* + * Clean up bFlags[] + */ + for(k=0; k<=ncenters-1; k++) + { + buf->bflags.ptr.p_bool[buf->currentnodes.ptr.p_int[k]] = ae_false; + } + + /* + * Compute working set and scatter set design matrices ATWrk and ATSctr + * + * ATWrk is a (NWrk+NX+1)*NWrk matrix whose entries a[i,j] store: + * * for Ixx, builder->ntotal, nx, builder->functype, builder->funcparam, &buf->currentnodes, ncenters, &buf->currentnodes, 0, &buf->atwrk, &buf->atwrk, _state); + + /* + * Prepare and solve linear system, coefficients are stored in rows of Buf.B + * + * Depending on whether the basis is conditionally positive definite (given current polynomial term type), + * we either: + * * use generic QR solver to solve the linear system (when the basis is not CPD) + * * use specialized CPD solver that is several times faster and is more accurate + */ + if( builder->aterm!=1||!rbfv3_iscpdfunction(builder->functype, builder->aterm, _state) ) + { + ae_assert(ae_fp_greater_eq(builder->lambdav,(double)(0)), "RBF3: integrity check 8363 failed", _state); + ae_assert((builder->aterm==1||builder->aterm==2)||builder->aterm==3, "RBF3: integrity check 8364 failed", _state); + + /* + * Basis function has no conditional positive definiteness guarantees (given the linear term type). + * + * Solve using QR decomposition. + */ + ncoeff = ncenters+nx+1; + rsetallocm(ncoeff, ncoeff+batchsize, 0.0, &buf->q, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrr(ncenters, &buf->atwrk, i, &buf->q, i, _state); + buf->q.ptr.pp_double[i][i] = buf->q.ptr.pp_double[i][i]+builder->lambdav; + } + if( builder->aterm==1 ) + { + + /* + * Linear term is used + */ + for(i=0; i<=nx; i++) + { + for(j=0; j<=ncenters-1; j++) + { + buf->q.ptr.pp_double[ncenters+i][j] = buf->atwrk.ptr.pp_double[ncenters+i][j]; + buf->q.ptr.pp_double[j][ncenters+i] = buf->atwrk.ptr.pp_double[ncenters+i][j]; + } + } + } + if( builder->aterm==2 ) + { + + /* + * Constant term is used + */ + for(i=0; i<=nx-1; i++) + { + buf->q.ptr.pp_double[ncenters+i][ncenters+i] = 1.0; + } + for(j=0; j<=ncenters-1; j++) + { + buf->q.ptr.pp_double[ncenters+nx][j] = 1.0; + buf->q.ptr.pp_double[j][ncenters+nx] = 1.0; + } + } + if( builder->aterm==3 ) + { + + /* + * Zero term is used + */ + for(i=0; i<=nx; i++) + { + buf->q.ptr.pp_double[ncenters+i][ncenters+i] = 1.0; + } + } + for(i=0; i<=batchsize-1; i++) + { + buf->q.ptr.pp_double[i][ncoeff+i] = 1.0; + } + mx = 1.0; + for(i=0; i<=ncoeff-1; i++) + { + for(j=i; j<=ncoeff-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(buf->q.ptr.pp_double[i][j], _state), _state); + } + } + for(j=0; j<=ncoeff-1; j++) + { + buf->q.ptr.pp_double[j][j] = buf->q.ptr.pp_double[j][j]+reg*mx*possign(buf->q.ptr.pp_double[j][j], _state); + } + rmatrixqr(&buf->q, ncoeff, ncoeff+batchsize, &buf->tau, _state); + rallocm(batchsize, ncoeff, &buf->b, _state); + rmatrixtranspose(ncoeff, batchsize, &buf->q, 0, ncoeff, &buf->b, 0, 0, _state); + rmatrixrighttrsm(batchsize, ncoeff, &buf->q, 0, 0, ae_true, ae_false, 1, &buf->b, 0, 0, _state); + } + else + { + ae_assert(ae_fp_greater_eq(builder->lambdav,(double)(0)), "RBF3: integrity check 8368 failed", _state); + ae_assert(builder->aterm==1, "RBF3: integrity check 7365 failed", _state); + ncoeff = ncenters+nx+1; + + /* + * First, compute orthogonal basis of space spanned by polynomials of degree 1 + */ + rallocm(ncenters, ncenters, &buf->r, _state); + rallocm(nx+1, ncenters, &buf->q1, _state); + iallocv(nx+1, &ortbasismap, _state); + rsetr(ncenters, (double)1/ae_sqrt((double)(ncenters), _state), &buf->q1, 0, _state); + buf->r.ptr.pp_double[0][0] = ae_sqrt((double)(ncenters), _state); + ortbasismap.ptr.p_int[0] = nx; + ortbasissize = 1; + rallocv(ncenters, &buf->z, _state); + for(k=0; k<=nx-1; k++) + { + for(j=0; j<=ncenters-1; j++) + { + buf->z.ptr.p_double[j] = buf->atwrk.ptr.pp_double[ncenters+k][j]; + } + v = ae_sqrt(rdotv2(ncenters, &buf->z, _state), _state); + rowwisegramschmidt(&buf->q1, ortbasissize, ncenters, &buf->z, &buf->y, ae_true, _state); + vv = ae_sqrt(rdotv2(ncenters, &buf->z, _state), _state); + if( ae_fp_greater(vv,ae_sqrt(ae_machineepsilon, _state)*(v+(double)1)) ) + { + rcopymulvr(ncenters, (double)1/vv, &buf->z, &buf->q1, ortbasissize, _state); + rcopyvc(ortbasissize, &buf->y, &buf->r, ortbasissize, _state); + buf->r.ptr.pp_double[ortbasissize][ortbasissize] = vv; + ortbasismap.ptr.p_int[ortbasissize] = k; + ortbasissize = ortbasissize+1; + } + } + + /* + * Second, compute system matrix Q and target values for cardinal basis functions B. + * + * The Q is conditionally positive definite, i.e. x'*Q*x>0 for any x satisfying orthogonality conditions + * (orthogonal with respect to basis stored in Q1). + */ + rsetallocm(ncenters, ncenters, 0.0, &buf->q, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrr(ncenters, &buf->atwrk, i, &buf->q, i, _state); + } + rsetallocm(batchsize, ncoeff, 0.0, &buf->b, _state); + for(i=0; i<=batchsize-1; i++) + { + buf->b.ptr.pp_double[i][i] = 1.0; + } + for(i=0; i<=ncenters-1; i++) + { + buf->q.ptr.pp_double[i][i] = buf->q.ptr.pp_double[i][i]+builder->lambdav; + } + + /* + * Transform Q from conditionally positive definite to the (simply) positive definite one: + * multiply linear system Q*x=RHS from both sides by (I-Q1'*Q1), apply additional regularization. + * + * NOTE: RHS is also multiplied by (I-Q1'*Q1), but from the left only. + */ + rallocv(ncenters, &buf->z, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &buf->q, i, &buf->z, _state); + rowwisegramschmidt(&buf->q1, ortbasissize, ncenters, &buf->z, &buf->y, ae_false, _state); + rcopyvr(ncenters, &buf->z, &buf->q, i, _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopycv(ncenters, &buf->q, i, &buf->z, _state); + rowwisegramschmidt(&buf->q1, ortbasissize, ncenters, &buf->z, &buf->y, ae_false, _state); + rcopyvc(ncenters, &buf->z, &buf->q, i, _state); + } + for(i=0; i<=batchsize-1; i++) + { + rcopyrv(ncenters, &buf->b, i, &buf->z, _state); + rowwisegramschmidt(&buf->q1, ortbasissize, ncenters, &buf->z, &buf->y, ae_false, _state); + rcopyvr(ncenters, &buf->z, &buf->b, i, _state); + } + mx = 1.0; + for(i=0; i<=ncenters-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(buf->q.ptr.pp_double[i][i], _state), _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &buf->q, i, &buf->z, _state); + for(j=0; j<=ortbasissize-1; j++) + { + raddrv(ncenters, mx*buf->q1.ptr.pp_double[j][i], &buf->q1, j, &buf->z, _state); + } + rcopyvr(ncenters, &buf->z, &buf->q, i, _state); + } + if( builder->dodetailedtrace ) + { + + /* + * Compute condition number for future reports + */ + dbgcondq = (double)1/(spdmatrixrcond(&buf->q, ncenters, ae_false, _state)+ae_machineepsilon); + } + else + { + dbgcondq = (double)(0); + } + for(i=0; i<=ncenters-1; i++) + { + buf->q.ptr.pp_double[i][i] = buf->q.ptr.pp_double[i][i]+reg*mx; + } + + /* + * Perform Cholesky factorization, solve and obtain RBF coefficients (we still have + * to compute polynomial term - it will be done later) + */ + if( !spdmatrixcholeskyrec(&buf->q, 0, ncenters, ae_false, &buf->choltmp, _state) ) + { + ae_assert(ae_false, "RBFV3: ACBF solver failed due to extreme degeneracy", _state); + } + rmatrixrighttrsm(batchsize, ncenters, &buf->q, 0, 0, ae_false, ae_false, 1, &buf->b, 0, 0, _state); + rmatrixrighttrsm(batchsize, ncenters, &buf->q, 0, 0, ae_false, ae_false, 0, &buf->b, 0, 0, _state); + + /* + * Now, having RBF coefficients we can compute residual from fitting ACBF targets + * with pure RBF term and fit polynomial term to this residual. In the ideal world + * it should result in the nice and precise polynomial coefficients. + */ + rallocv(ncenters, &buf->z, _state); + rsetallocm(batchsize, ncenters, 0.0, &buf->c, _state); + for(i=0; i<=batchsize-1; i++) + { + buf->c.ptr.pp_double[i][i] = 1.0; + } + rmatrixgemm(batchsize, ncenters, ncenters, -1.0, &buf->b, 0, 0, 0, &buf->atwrk, 0, 0, 1, 1.0, &buf->c, 0, 0, _state); + for(i=0; i<=batchsize-1; i++) + { + rcopyrv(ncenters, &buf->c, i, &buf->z, _state); + rowwisegramschmidt(&buf->q1, ortbasissize, ncenters, &buf->z, &buf->y, ae_true, _state); + rmatrixtrsv(ortbasissize, &buf->r, 0, 0, ae_true, ae_false, 0, &buf->y, 0, _state); + for(j=0; j<=nx; j++) + { + buf->b.ptr.pp_double[i][ncenters+j] = 0.0; + } + for(j=0; j<=ortbasissize-1; j++) + { + buf->b.ptr.pp_double[i][ncenters+ortbasismap.ptr.p_int[j]] = buf->y.ptr.p_double[j]; + } + } + + /* + * Trace if needeed + */ + if( builder->dodetailedtrace ) + { + rallocm(batchsize, ncenters, &dbgb, _state); + rmatrixgemm(batchsize, ncenters, ncoeff, -1.0, &buf->b, 0, 0, 0, &buf->atwrk, 0, 0, 0, 0.0, &dbgb, 0, 0, _state); + for(i=0; i<=batchsize-1; i++) + { + dbgb.ptr.pp_double[i][i] = dbgb.ptr.pp_double[i][i]+1.0; + } + dbgmaxc = (double)(0); + for(i=0; i<=batchsize-1; i++) + { + dbgmaxc = ae_maxreal(dbgmaxc, rmaxabsr(ncenters, &buf->b, i, _state), _state); + } + dbgerrnodes = (double)(0); + for(i=0; i<=batchsize-1; i++) + { + dbgerrnodes = dbgerrnodes+rdotrr(ncenters, &dbgb, i, &dbgb, i, _state); + } + dbgerrnodes = ae_sqrt(dbgerrnodes/(double)(batchsize*ncenters), _state); + dbgerrort = (double)(0); + for(i=0; i<=batchsize-1; i++) + { + for(j=0; j<=ortbasissize-1; j++) + { + dbgerrort = ae_maxreal(dbgerrort, ae_fabs(rdotrr(ncenters, &buf->b, i, &buf->q1, j, _state), _state), _state); + } + } + ae_trace("[ACBF_subprob] BatchSize=%3d NCenters=%4d RadiusExpansions=%0d cond(Q)=%0.2e max|C|=%0.2e rmsErr=%0.2e OrtErr=%0.2e\n", + (int)(batchsize), + (int)(ncenters), + (int)(expansionscount), + (double)(dbgcondq), + (double)(dbgmaxc), + (double)(dbgerrnodes), + (double)(dbgerrort)); + } + } + + /* + * Solve and save solution to Builder.ChunksPool + */ + ae_shared_pool_retrieve(&builder->chunksproducer, &_precchunk, _state); + ae_assert(precchunk->ntargetrows==-117, "RBFV3: integrity check 9724 failed", _state); + ae_assert(precchunk->ntargetcols==-119, "RBFV3: integrity check 9725 failed", _state); + precchunk->ntargetrows = batchsize; + precchunk->ntargetcols = ncoeff; + iallocv(precchunk->ntargetrows, &precchunk->targetrows, _state); + iallocv(precchunk->ntargetcols, &precchunk->targetcols, _state); + rallocm(batchsize, ncoeff, &precchunk->s, _state); + for(widx=0; widx<=batchsize-1; widx++) + { + precchunk->targetrows.ptr.p_int[widx] = builder->wrkidx.ptr.p_int[wrk0+widx]; + } + iallocv(ncoeff, &buf->perm, _state); + for(k=0; k<=ncoeff-1; k++) + { + if( ktargetcols.ptr.p_int[k] = buf->currentnodes.ptr.p_int[k]; + } + else + { + precchunk->targetcols.ptr.p_int[k] = builder->ntotal+(k-ncenters); + } + buf->perm.ptr.p_int[k] = k; + } + tagsortmiddleii(&precchunk->targetcols, &buf->perm, 0, ncoeff, _state); + for(widx=0; widx<=batchsize-1; widx++) + { + for(k=0; k<=ncoeff-1; k++) + { + precchunk->s.ptr.pp_double[widx][k] = buf->b.ptr.pp_double[widx][buf->perm.ptr.p_int[k]]; + } + } + ae_shared_pool_recycle(&builder->chunkspool, &_precchunk, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive ACBF preconditioner generation subroutine. + +PARAMETERS: + Builder - ACBF builder object + Wrk0, Wrk1 - elements [Wrk0...Wrk1-1] of Builder.WrkIdx[] + array store row indexes of XX that are processed. + +OUTPUT: + Builder.OutputPool is updated with new chunks + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computeacbfpreconditionerrecv2(acbfbuilder* builder, + ae_int_t wrk0, + ae_int_t wrk1, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t largestdim; + double splitval; + double basecasecomplexity; + acbfbuffer *buf; + ae_smart_ptr _buf; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + nx = builder->nx; + if( wrk1<=wrk0 ) + { + ae_frame_leave(_state); + return; + } + basecasecomplexity = rmul3((double)(builder->nglobal+builder->nlocal+2*builder->ncorrection), (double)(builder->nglobal+builder->nlocal+2*builder->ncorrection), (double)(builder->nglobal+builder->nlocal+2*builder->ncorrection), _state); + + /* + * Decide on parallelism + */ + if( ae_fp_greater_eq(rmul2((double)(builder->ntotal), basecasecomplexity, _state),smpactivationlevel(_state))&&builder->ntotal>=rbfv3_acbfparallelthreshold ) + { + if( _trypexec_rbfv3_computeacbfpreconditionerrecv2(builder,wrk0,wrk1, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Retrieve temporary buffer + */ + ae_shared_pool_retrieve(&builder->bufferpool, &_buf, _state); + + /* + * Analyze current working set + */ + rallocv(nx, &buf->tmpboxmin, _state); + rallocv(nx, &buf->tmpboxmax, _state); + rcopyrv(nx, &builder->xx, builder->wrkidx.ptr.p_int[wrk0], &buf->tmpboxmin, _state); + rcopyrv(nx, &builder->xx, builder->wrkidx.ptr.p_int[wrk0], &buf->tmpboxmax, _state); + for(i=wrk0+1; i<=wrk1-1; i++) + { + for(j=0; j<=nx-1; j++) + { + buf->tmpboxmin.ptr.p_double[j] = ae_minreal(buf->tmpboxmin.ptr.p_double[j], builder->xx.ptr.pp_double[builder->wrkidx.ptr.p_int[i]][j], _state); + buf->tmpboxmax.ptr.p_double[j] = ae_maxreal(buf->tmpboxmax.ptr.p_double[j], builder->xx.ptr.pp_double[builder->wrkidx.ptr.p_int[i]][j], _state); + } + } + largestdim = 0; + for(j=1; j<=nx-1; j++) + { + if( ae_fp_greater(buf->tmpboxmax.ptr.p_double[j]-buf->tmpboxmin.ptr.p_double[j],buf->tmpboxmax.ptr.p_double[largestdim]-buf->tmpboxmin.ptr.p_double[largestdim]) ) + { + largestdim = j; + } + } + + /* + * Perform either batch processing or recursive split + */ + if( wrk1-wrk0<=builder->batchsize||ae_fp_eq(buf->tmpboxmax.ptr.p_double[largestdim],buf->tmpboxmin.ptr.p_double[largestdim]) ) + { + + /* + * Either working set size is small enough or all points are non-distinct. + * Perform batch processing + */ + rbfv3_computeacbfpreconditionerbasecase(builder, buf, wrk0, wrk1, _state); + + /* + * Recycle temporary buffers + */ + ae_shared_pool_recycle(&builder->bufferpool, &_buf, _state); + } + else + { + + /* + * Compute recursive split along largest axis + */ + splitval = 0.5*(buf->tmpboxmax.ptr.p_double[largestdim]+buf->tmpboxmin.ptr.p_double[largestdim]); + k0 = wrk0; + k1 = wrk1-1; + while(k0<=k1) + { + if( ae_fp_less_eq(builder->xx.ptr.pp_double[builder->wrkidx.ptr.p_int[k0]][largestdim],splitval) ) + { + k0 = k0+1; + continue; + } + if( ae_fp_greater(builder->xx.ptr.pp_double[builder->wrkidx.ptr.p_int[k1]][largestdim],splitval) ) + { + k1 = k1-1; + continue; + } + swapelementsi(&builder->wrkidx, k0, k1, _state); + k0 = k0+1; + k1 = k1-1; + } + ae_assert(k0>wrk0&&k1bufferpool, &_buf, _state); + rbfv3_computeacbfpreconditionerrecv2(builder, wrk0, k0, _state); + rbfv3_computeacbfpreconditionerrecv2(builder, k0, wrk1, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_computeacbfpreconditionerrecv2(acbfbuilder* builder, + ae_int_t wrk0, + ae_int_t wrk1, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function generates ACBF (approximate cardinal basis functions) +preconditioner. + +PARAMETERS: + XX - dataset (X-values), array[N,NX] + N - points count, N>=1 + NX - dimensions count, NX>=1 + FuncType - basis function type + +OUTPUT: + SP - preconditioner, sparse matrix in CRS format + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computeacbfpreconditioner(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + ae_int_t aterm, + ae_int_t batchsize, + ae_int_t nglobal, + ae_int_t nlocal, + ae_int_t ncorrection, + ae_int_t correctorgrowth, + ae_int_t simplificationfactor, + double lambdav, + sparsematrix* sp, + ae_state *_state) +{ + ae_frame _frame_block; + acbfbuilder builder; + acbfbuffer bufferseed; + acbfchunk chunkseed; + acbfchunk *precchunk; + ae_smart_ptr _precchunk; + ae_int_t i; + ae_int_t j; + ae_int_t offs; + ae_vector idummy; + ae_vector rowsizes; + ae_vector boxmin; + ae_vector boxmax; + + ae_frame_make(_state, &_frame_block); + memset(&builder, 0, sizeof(builder)); + memset(&bufferseed, 0, sizeof(bufferseed)); + memset(&chunkseed, 0, sizeof(chunkseed)); + memset(&_precchunk, 0, sizeof(_precchunk)); + memset(&idummy, 0, sizeof(idummy)); + memset(&rowsizes, 0, sizeof(rowsizes)); + memset(&boxmin, 0, sizeof(boxmin)); + memset(&boxmax, 0, sizeof(boxmax)); + _acbfbuilder_init(&builder, _state, ae_true); + _acbfbuffer_init(&bufferseed, _state, ae_true); + _acbfchunk_init(&chunkseed, _state, ae_true); + ae_smart_ptr_init(&_precchunk, (void**)&precchunk, ae_false, _state, ae_true); + ae_vector_init(&idummy, 0, DT_INT, _state, ae_true); + ae_vector_init(&rowsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(&boxmin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&boxmax, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RBFV3: integrity check 2524 failed", _state); + + /* + * Prepare builder + */ + builder.dodetailedtrace = ae_is_trace_enabled("RBF.DETAILED"); + builder.functype = functype; + builder.funcparam = funcparam; + builder.ntotal = n; + builder.nx = nx; + builder.batchsize = batchsize; + if( nglobal>0 ) + { + rbfv3_selectglobalnodes(xx, n, nx, &idummy, 0, nglobal, &builder.globalgrid, &builder.nglobal, &builder.globalgridseparation, _state); + } + else + { + builder.nglobal = 0; + } + builder.nlocal = nlocal; + builder.ncorrection = ncorrection; + builder.correctorgrowth = (double)(correctorgrowth); + builder.lambdav = lambdav; + builder.aterm = aterm; + rcopyallocm(n, nx, xx, &builder.xx, _state); + rallocv(nx, &boxmin, _state); + rallocv(nx, &boxmax, _state); + rcopyrv(nx, xx, 0, &boxmin, _state); + rcopyrv(nx, xx, 0, &boxmax, _state); + for(i=1; i<=n-1; i++) + { + rmergeminrv(nx, xx, i, &boxmin, _state); + rmergemaxrv(nx, xx, i, &boxmax, _state); + } + builder.roughdatasetdiameter = (double)(0); + for(i=0; i<=nx-1; i++) + { + builder.roughdatasetdiameter = builder.roughdatasetdiameter+ae_sqr(boxmax.ptr.p_double[i]-boxmin.ptr.p_double[i], _state); + } + builder.roughdatasetdiameter = ae_sqrt(builder.roughdatasetdiameter, _state); + iallocv(n, &builder.wrkidx, _state); + for(i=0; i<=n-1; i++) + { + builder.wrkidx.ptr.p_int[i] = i; + } + kdtreebuildtagged(xx, &builder.wrkidx, n, nx, 0, 2, &builder.kdt, _state); + rbfv3_buildsimplifiedkdtree(xx, n, nx, ae_round(ae_pow((double)(simplificationfactor), (double)(nx), _state), _state), ae_round(ae_pow((double)(5), (double)(nx), _state), _state), &builder.kdt1, _state); + rbfv3_buildsimplifiedkdtree(xx, n, nx, ae_round(ae_pow((double)(simplificationfactor), (double)(2*nx), _state), _state), ae_round(ae_pow((double)(5), (double)(nx), _state), _state), &builder.kdt2, _state); + bsetallocv(n, ae_false, &bufferseed.bflags, _state); + rallocv(nx, &bufferseed.tmpboxmin, _state); + rallocv(nx, &bufferseed.tmpboxmax, _state); + kdtreecreaterequestbuffer(&builder.kdt, &bufferseed.kdtbuf, _state); + kdtreecreaterequestbuffer(&builder.kdt1, &bufferseed.kdt1buf, _state); + kdtreecreaterequestbuffer(&builder.kdt2, &bufferseed.kdt2buf, _state); + ae_shared_pool_set_seed(&builder.bufferpool, &bufferseed, (ae_int_t)sizeof(bufferseed), (ae_copy_constructor)_acbfbuffer_init_copy, (ae_destructor)_acbfbuffer_destroy, _state); + chunkseed.ntargetrows = -117; + chunkseed.ntargetcols = -119; + ae_shared_pool_set_seed(&builder.chunksproducer, &chunkseed, (ae_int_t)sizeof(chunkseed), (ae_copy_constructor)_acbfchunk_init_copy, (ae_destructor)_acbfchunk_destroy, _state); + ae_shared_pool_set_seed(&builder.chunkspool, &chunkseed, (ae_int_t)sizeof(chunkseed), (ae_copy_constructor)_acbfchunk_init_copy, (ae_destructor)_acbfchunk_destroy, _state); + + /* + * Prepare preconditioner matrix + */ + rbfv3_computeacbfpreconditionerrecv2(&builder, 0, n, _state); + isetallocv(n, -1, &rowsizes, _state); + ae_shared_pool_first_recycled(&builder.chunkspool, &_precchunk, _state); + while(precchunk!=NULL) + { + for(i=0; i<=precchunk->ntargetrows-1; i++) + { + ae_assert(rowsizes.ptr.p_int[precchunk->targetrows.ptr.p_int[i]]==-1, "RBFV3: integrity check 2568 failed", _state); + rowsizes.ptr.p_int[precchunk->targetrows.ptr.p_int[i]] = precchunk->ntargetcols; + } + ae_shared_pool_next_recycled(&builder.chunkspool, &_precchunk, _state); + } + sp->matrixtype = 1; + sp->m = n+nx+1; + sp->n = n+nx+1; + iallocv(n+nx+2, &sp->ridx, _state); + sp->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + ae_assert(rowsizes.ptr.p_int[i]>0, "RBFV3: integrity check 2668 failed", _state); + sp->ridx.ptr.p_int[i+1] = sp->ridx.ptr.p_int[i]+rowsizes.ptr.p_int[i]; + } + for(i=n; i<=n+nx; i++) + { + sp->ridx.ptr.p_int[i+1] = sp->ridx.ptr.p_int[i]+1; + } + iallocv(sp->ridx.ptr.p_int[sp->m], &sp->idx, _state); + rallocv(sp->ridx.ptr.p_int[sp->m], &sp->vals, _state); + for(i=n; i<=n+nx; i++) + { + sp->idx.ptr.p_int[sp->ridx.ptr.p_int[i]] = i; + sp->vals.ptr.p_double[sp->ridx.ptr.p_int[i]] = 1.0; + } + ae_shared_pool_first_recycled(&builder.chunkspool, &_precchunk, _state); + while(precchunk!=NULL) + { + for(i=0; i<=precchunk->ntargetrows-1; i++) + { + offs = sp->ridx.ptr.p_int[precchunk->targetrows.ptr.p_int[i]]; + for(j=0; j<=precchunk->ntargetcols-1; j++) + { + sp->idx.ptr.p_int[offs+j] = precchunk->targetcols.ptr.p_int[j]; + sp->vals.ptr.p_double[offs+j] = precchunk->s.ptr.pp_double[i][j]; + } + } + ae_shared_pool_next_recycled(&builder.chunkspool, &_precchunk, _state); + } + sp->ninitialized = sp->ridx.ptr.p_int[sp->m]; + sparseinitduidx(sp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Basecase initialization routine for DDM solver. + + +Appends an instance of RBF3DDMSubproblem to Solver.SubproblemsPool. + +INPUT PARAMETERS: + Solver - solver object. This function may be called from the + multiple threads, so it is important to work with + Solver object using only thread-safe functions. + X - array[N,NX], dataset points + N, NX - dataset metrics, N>0, NX>0 + BFMatrix - basis function matrix object + LambdaV - smoothing parameter + SP - sparse ACBF preconditioner, (N+NX+1)*(N+NX+1) matrix + stored in CRS format + Buf - an instance of RBF3DDMBuffer, reusable temporary buffers + TgtIdx - array[], contains indexes of points in the current target + set. Elements [Tgt0,Tgt1) are processed by this function. + NNeighbors - neighbors count; NNeighbors nearby nodes are added to + inner points of the chunk + DoDetailedTrace-whether trace output is needed or not. When trace is + activated, solver computes condition numbers. It results + in the several-fold slowdown of the algorithm. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverinitbasecase(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + rbf3ddmbuffer* buf, + /* Integer */ ae_vector* tgtidx, + ae_int_t tgt0, + ae_int_t tgt1, + ae_int_t nneighbors, + ae_bool dodetailedtrace, + ae_state *_state) +{ + ae_frame _frame_block; + rbf3ddmsubproblem *subproblem; + ae_smart_ptr _subproblem; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nc; + ae_int_t nk; + double v; + double reg; + ae_int_t nwrk; + ae_int_t npreccol; + ae_vector neighbors; + ae_vector workingnodes; + ae_vector preccolumns; + ae_vector tau; + ae_matrix q; + ae_vector x0; + double lurcond; + ae_bool lusuccess; + ae_int_t ni; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_matrix suba; + ae_matrix subsp; + ae_matrix dbga; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + memset(&neighbors, 0, sizeof(neighbors)); + memset(&workingnodes, 0, sizeof(workingnodes)); + memset(&preccolumns, 0, sizeof(preccolumns)); + memset(&tau, 0, sizeof(tau)); + memset(&q, 0, sizeof(q)); + memset(&x0, 0, sizeof(x0)); + memset(&suba, 0, sizeof(suba)); + memset(&subsp, 0, sizeof(subsp)); + memset(&dbga, 0, sizeof(dbga)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + ae_vector_init(&neighbors, 0, DT_INT, _state, ae_true); + ae_vector_init(&workingnodes, 0, DT_INT, _state, ae_true); + ae_vector_init(&preccolumns, 0, DT_INT, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&suba, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&subsp, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dbga, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(tgt1-tgt0>0, "RBFV3: integrity check 7364 failed", _state); + ae_assert(nneighbors>=0, "RBFV3: integrity check 7365 failed", _state); + reg = ((double)100+ae_sqrt((double)(tgt1-tgt0+nneighbors), _state))*ae_machineepsilon; + + /* + * Retrieve fresh subproblem. We expect that Solver.SubproblemsBuffer contains + * no recycled entries and that fresh subproblem with Subproblem.IsValid=False + * is returned. + * + * Start initialization + */ + ae_shared_pool_retrieve(&solver->subproblemsbuffer, &_subproblem, _state); + ae_assert(!subproblem->isvalid, "RBFV3: SubproblemsBuffer integrity check failed", _state); + subproblem->isvalid = ae_true; + subproblem->ntarget = tgt1-tgt0; + iallocv(tgt1-tgt0, &subproblem->targetnodes, _state); + icopyvx(tgt1-tgt0, tgtidx, tgt0, &subproblem->targetnodes, 0, _state); + + /* + * Prepare working arrays + */ + rallocv(nx, &x0, _state); + + /* + * Determine working set: target nodes + neighbors of targets. + * Prepare mapping from node index to position in WorkingNodes[] + */ + nwrk = 0; + iallocv(tgt1-tgt0, &workingnodes, _state); + for(i=tgt0; i<=tgt1-1; i++) + { + nk = tgtidx->ptr.p_int[i]; + buf->bflags.ptr.p_bool[nk] = ae_true; + workingnodes.ptr.p_int[nwrk] = nk; + nwrk = nwrk+1; + } + for(i=tgt0; i<=tgt1-1; i++) + { + rcopyrv(nx, x, tgtidx->ptr.p_int[i], &x0, _state); + nc = kdtreetsqueryknn(&solver->kdt, &buf->kdtbuf, &x0, nneighbors+1, ae_true, _state); + kdtreetsqueryresultstags(&solver->kdt, &buf->kdtbuf, &neighbors, _state); + for(k=0; k<=nc-1; k++) + { + nk = neighbors.ptr.p_int[k]; + if( !buf->bflags.ptr.p_bool[nk] ) + { + buf->bflags.ptr.p_bool[nk] = ae_true; + igrowv(nwrk+1, &workingnodes, _state); + workingnodes.ptr.p_int[nwrk] = nk; + nwrk = nwrk+1; + } + } + } + for(i=0; i<=nwrk-1; i++) + { + buf->bflags.ptr.p_bool[workingnodes.ptr.p_int[i]] = ae_false; + } + ae_assert(nwrk>0, "ACBF: integrity check for NWrk failed", _state); + subproblem->nwork = nwrk; + icopyallocv(nwrk, &workingnodes, &subproblem->workingnodes, _state); + + /* + * Determine preconditioner columns that have nonzeros in rows corresponding + * to working nodes. Prepare mapping from [0,N+NX+1) column indexing to [0,NPrecCol) + * compressed one. Only these columns are extracted from the preconditioner + * during design system computation. + * + * NOTE: we ensure that preconditioner columns N...N+NX which correspond to linear + * terms are placed last. It greatly simplifies desi + */ + npreccol = 0; + for(i=0; i<=nwrk-1; i++) + { + j0 = sp->ridx.ptr.p_int[workingnodes.ptr.p_int[i]]; + j1 = sp->ridx.ptr.p_int[workingnodes.ptr.p_int[i]+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = sp->idx.ptr.p_int[jj]; + if( jbflags.ptr.p_bool[j] ) + { + buf->bflags.ptr.p_bool[j] = ae_true; + igrowv(npreccol+1, &preccolumns, _state); + preccolumns.ptr.p_int[npreccol] = j; + npreccol = npreccol+1; + } + } + } + for(j=n; j<=n+nx; j++) + { + ae_assert(!buf->bflags.ptr.p_bool[j], "RBFV3: integrity check 9435 failed", _state); + buf->bflags.ptr.p_bool[j] = ae_true; + igrowv(npreccol+1, &preccolumns, _state); + preccolumns.ptr.p_int[npreccol] = j; + npreccol = npreccol+1; + } + for(i=0; i<=npreccol-1; i++) + { + buf->idx2preccol.ptr.p_int[preccolumns.ptr.p_int[i]] = i; + buf->bflags.ptr.p_bool[preccolumns.ptr.p_int[i]] = ae_false; + } + + /* + * Generate working system, apply regularization + */ + rsetallocm(nwrk, npreccol, 0.0, &suba, _state); + rbfv3_modelmatrixcomputepartial(bfmatrix, &workingnodes, nwrk, &preccolumns, npreccol-(nx+1), &suba, _state); + for(i=0; i<=nwrk-1; i++) + { + ni = workingnodes.ptr.p_int[i]; + for(j=0; j<=nx-1; j++) + { + suba.ptr.pp_double[i][npreccol-(nx+1)+j] = x->ptr.pp_double[ni][j]; + } + suba.ptr.pp_double[i][npreccol-1] = 1.0; + } + for(i=0; i<=nwrk-1; i++) + { + j = buf->idx2preccol.ptr.p_int[workingnodes.ptr.p_int[i]]; + suba.ptr.pp_double[i][j] = suba.ptr.pp_double[i][j]+lambdav; + } + rsetallocm(nwrk, npreccol, 0.0, &subsp, _state); + for(i=0; i<=nwrk-1; i++) + { + ni = workingnodes.ptr.p_int[i]; + j0 = sp->ridx.ptr.p_int[ni]; + j1 = sp->ridx.ptr.p_int[ni+1]-1; + for(jj=j0; jj<=j1; jj++) + { + subsp.ptr.pp_double[i][buf->idx2preccol.ptr.p_int[sp->idx.ptr.p_int[jj]]] = sp->vals.ptr.p_double[jj]; + } + } + rallocm(nwrk, nwrk, &subproblem->regsystem, _state); + rmatrixgemm(nwrk, nwrk, npreccol, 1.0, &suba, 0, 0, 0, &subsp, 0, 0, 1, 0.0, &subproblem->regsystem, 0, 0, _state); + + /* + * Try solving with LU decomposition + */ + rcopyallocm(nwrk, nwrk, &subproblem->regsystem, &subproblem->wrklu, _state); + rmatrixlu(&subproblem->wrklu, nwrk, nwrk, &subproblem->wrkp, _state); + lurcond = rmatrixlurcondinf(&subproblem->wrklu, nwrk, _state); + if( ae_fp_greater(lurcond,ae_sqrt(ae_machineepsilon, _state)) ) + { + + /* + * LU success + */ + subproblem->decomposition = 0; + lusuccess = ae_true; + if( dodetailedtrace ) + { + ae_trace(">> DDM subproblem: LU success, |target|=%4d, |wrk|=%4d, |preccol|=%4d, cond(LU)=%0.2e\n", + (int)(tgt1-tgt0), + (int)(nwrk), + (int)(npreccol), + (double)((double)1/(lurcond+ae_machineepsilon))); + } + } + else + { + lusuccess = ae_false; + } + + /* + * Apply regularized QR if needed + */ + if( !lusuccess ) + { + rsetallocm(2*nwrk, nwrk, 0.0, &subproblem->wrkr, _state); + rcopym(nwrk, nwrk, &subproblem->regsystem, &subproblem->wrkr, _state); + v = ae_sqrt(reg, _state); + for(i=0; i<=nwrk-1; i++) + { + subproblem->wrkr.ptr.pp_double[nwrk+i][i] = v; + } + rmatrixqr(&subproblem->wrkr, 2*nwrk, nwrk, &tau, _state); + rmatrixqrunpackq(&subproblem->wrkr, 2*nwrk, nwrk, &tau, nwrk, &subproblem->wrkq, _state); + subproblem->decomposition = 1; + if( dodetailedtrace ) + { + ae_trace(">> DDM subproblem: LU failure, using reg-QR, |target|=%4d, |wrk|=%4d, |preccol|=%4d, cond(R)=%0.2e (cond(LU)=%0.2e)\n", + (int)(tgt1-tgt0), + (int)(nwrk), + (int)(npreccol), + (double)((double)1/(rmatrixtrrcondinf(&subproblem->wrkr, nwrk, ae_true, ae_false, _state)+ae_machineepsilon)), + (double)((double)1/(lurcond+ae_machineepsilon))); + } + } + + /* + * Subproblem is ready. + * Move it to the SubproblemsPool + */ + ae_shared_pool_recycle(&solver->subproblemspool, &_subproblem, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive initialization routine for DDM solver + +INPUT PARAMETERS: + Solver - solver structure + X - array[N,NX], dataset points + N, NX - dataset metrics, N>0, NX>0 + BFMatrix - basis function evaluator + LambdaV - smoothing parameter + SP - sparse ACBF preconditioner, (N+NX+1)*(N+NX+1) matrix + stored in CRS format + WrkIdx - array[], contains indexes of points in the current working + set. Elements [Wrk0,Wrk1) are processed by this function. + NNeighbors - neighbors count; NNeighbors nearby nodes are added to + inner points of the chunk + NBatch - batch size + DoDetailedTrace-whether trace output is needed or not. When trace is + activated, solver computes condition numbers. It results + in the several-fold slowdown of the algorithm. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverinitrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + /* Integer */ ae_vector* wrkidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_bool dodetailedtrace, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t largestdim; + double splitval; + double basecasecomplexity; + rbf3ddmbuffer *buf; + ae_smart_ptr _buf; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + if( wrk1<=wrk0 ) + { + ae_frame_leave(_state); + return; + } + basecasecomplexity = rmul3((double)(nbatch+nneighbors+nx+1), (double)(nbatch+nneighbors+nx+1), (double)(nbatch+nneighbors+nx+1), _state); + + /* + * Decide on parallelism + */ + if( (ae_fp_greater_eq(basecasecomplexity*((double)n/(double)nbatch),smpactivationlevel(_state))&&ae_fp_greater_eq((double)n/(double)nbatch,(double)(2)))&&n>=rbfv3_ddmparallelthreshold ) + { + if( _trypexec_rbfv3_ddmsolverinitrec(solver,x,n,nx,bfmatrix,lambdav,sp,wrkidx,wrk0,wrk1,nneighbors,nbatch,dodetailedtrace, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Retrieve temporary buffer + */ + ae_shared_pool_retrieve(&solver->bufferpool, &_buf, _state); + + /* + * Analyze current working set + */ + rallocv(nx, &buf->tmpboxmin, _state); + rallocv(nx, &buf->tmpboxmax, _state); + rcopyrv(nx, x, wrkidx->ptr.p_int[wrk0], &buf->tmpboxmin, _state); + rcopyrv(nx, x, wrkidx->ptr.p_int[wrk0], &buf->tmpboxmax, _state); + for(i=wrk0+1; i<=wrk1-1; i++) + { + for(j=0; j<=nx-1; j++) + { + buf->tmpboxmin.ptr.p_double[j] = ae_minreal(buf->tmpboxmin.ptr.p_double[j], x->ptr.pp_double[wrkidx->ptr.p_int[i]][j], _state); + buf->tmpboxmax.ptr.p_double[j] = ae_maxreal(buf->tmpboxmax.ptr.p_double[j], x->ptr.pp_double[wrkidx->ptr.p_int[i]][j], _state); + } + } + largestdim = 0; + for(j=1; j<=nx-1; j++) + { + if( ae_fp_greater(buf->tmpboxmax.ptr.p_double[j]-buf->tmpboxmin.ptr.p_double[j],buf->tmpboxmax.ptr.p_double[largestdim]-buf->tmpboxmin.ptr.p_double[largestdim]) ) + { + largestdim = j; + } + } + + /* + * Perform either batch processing or recursive split + */ + if( wrk1-wrk0<=nbatch||ae_fp_eq(buf->tmpboxmax.ptr.p_double[largestdim],buf->tmpboxmin.ptr.p_double[largestdim]) ) + { + + /* + * Either working set size is small enough or all points are non-distinct. + * Stop recursive subdivision. + */ + rbfv3_ddmsolverinitbasecase(solver, x, n, nx, bfmatrix, lambdav, sp, buf, wrkidx, wrk0, wrk1, nneighbors, dodetailedtrace, _state); + + /* + * Recycle temporary buffers + */ + ae_shared_pool_recycle(&solver->bufferpool, &_buf, _state); + } + else + { + + /* + * Compute recursive split along largest axis + */ + splitval = 0.5*(buf->tmpboxmax.ptr.p_double[largestdim]+buf->tmpboxmin.ptr.p_double[largestdim]); + k0 = wrk0; + k1 = wrk1-1; + while(k0<=k1) + { + if( ae_fp_less_eq(x->ptr.pp_double[wrkidx->ptr.p_int[k0]][largestdim],splitval) ) + { + k0 = k0+1; + continue; + } + if( ae_fp_greater(x->ptr.pp_double[wrkidx->ptr.p_int[k1]][largestdim],splitval) ) + { + k1 = k1-1; + continue; + } + swapelementsi(wrkidx, k0, k1, _state); + k0 = k0+1; + k1 = k1-1; + } + ae_assert(k0>wrk0&&k1bufferpool, &_buf, _state); + rbfv3_ddmsolverinitrec(solver, x, n, nx, bfmatrix, lambdav, sp, wrkidx, wrk0, k0, nneighbors, nbatch, dodetailedtrace, _state); + rbfv3_ddmsolverinitrec(solver, x, n, nx, bfmatrix, lambdav, sp, wrkidx, k0, wrk1, nneighbors, nbatch, dodetailedtrace, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_ddmsolverinitrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + double lambdav, + const sparsematrix* sp, + /* Integer */ ae_vector* wrkidx, + ae_int_t wrk0, + ae_int_t wrk1, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_bool dodetailedtrace, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function prepares domain decomposition method for RBF interpolation +problem - it partitions problem into subproblems and precomputes +factorizations, and prepares a smaller correction spline that is used to +correct distortions introduced by domain decomposition and imperfections +in approximate cardinal basis. + +INPUT PARAMETERS: + X - array[N,NX], dataset points + RescaledBy - additional scaling coefficient that was applied to the + dataset by preprocessor. Used ONLY for logging purposes + - without it all distances will be reported in [0,1] + scale, not one set by user. + N, NX - dataset metrics, N>0, NX>0 + BFMatrix - RBF evaluator + BFType - basis function type + BFParam - basis function parameter + LambdaV - regularization parameter, >=0 + ATerm - polynomial term type (1 for linear, 2 for constant, 3 for zero) + SP - sparse ACBF preconditioner, (N+NX+1)*(N+NX+1) matrix + stored in CRS format + NNeighbors - neighbors count; NNeighbors nearby nodes are added to + inner points of the batch + NBatch - batch size + NCorrector - nodes count for correction spline + DoTrace - whether low overhead logging is needed or not + DoDetailedTrace-whether detailed trace output is needed or not. When trace is + activated, solver computes condition numbers. It results + in the small slowdown of the algorithm. + +OUTPUT PARAMETERS: + Solver - DDM solver + timeDDMInit- time used by the DDM part initialization, ms + timeCorrInit- time used by the corrector initialization, ms + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverinit(/* Real */ const ae_matrix* x, + double rescaledby, + ae_int_t n, + ae_int_t nx, + const rbf3evaluator* bfmatrix, + ae_int_t bftype, + double bfparam, + double lambdav, + ae_int_t aterm, + const sparsematrix* sp, + ae_int_t nneighbors, + ae_int_t nbatch, + ae_int_t ncorrector, + ae_bool dotrace, + ae_bool dodetailedtrace, + rbf3ddmsolver* solver, + ae_int_t* timeddminit, + ae_int_t* timecorrinit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector idx; + rbf3ddmbuffer bufferseed; + rbf3ddmsubproblem subproblem; + rbf3ddmsubproblem *p; + ae_smart_ptr _p; + double correctorgridseparation; + ae_matrix corrsys; + ae_vector corrtau; + ae_vector idummy; + double reg; + ae_int_t nsys; + + ae_frame_make(_state, &_frame_block); + memset(&idx, 0, sizeof(idx)); + memset(&bufferseed, 0, sizeof(bufferseed)); + memset(&subproblem, 0, sizeof(subproblem)); + memset(&_p, 0, sizeof(_p)); + memset(&corrsys, 0, sizeof(corrsys)); + memset(&corrtau, 0, sizeof(corrtau)); + memset(&idummy, 0, sizeof(idummy)); + *timeddminit = 0; + *timecorrinit = 0; + ae_vector_init(&idx, 0, DT_INT, _state, ae_true); + _rbf3ddmbuffer_init(&bufferseed, _state, ae_true); + _rbf3ddmsubproblem_init(&subproblem, _state, ae_true); + ae_smart_ptr_init(&_p, (void**)&p, ae_false, _state, ae_true); + ae_matrix_init(&corrsys, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&corrtau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&idummy, 0, DT_INT, _state, ae_true); + + ae_assert((aterm==1||aterm==2)||aterm==3, "RBF3: integrity check 3320 failed", _state); + + /* + * Start DDM part + */ + *timeddminit = ae_tickcount(); + + /* + * Save problem info + */ + solver->lambdav = lambdav; + + /* + * Prepare KD-tree + */ + iallocv(n, &idx, _state); + for(i=0; i<=n-1; i++) + { + idx.ptr.p_int[i] = i; + } + kdtreebuildtagged(x, &idx, n, nx, 0, 2, &solver->kdt, _state); + + /* + * Prepare temporary buffer pool + */ + bsetallocv(n+nx+1, ae_false, &bufferseed.bflags, _state); + iallocv(n+nx+1, &bufferseed.idx2preccol, _state); + rallocv(nx, &bufferseed.tmpboxmin, _state); + rallocv(nx, &bufferseed.tmpboxmax, _state); + kdtreecreaterequestbuffer(&solver->kdt, &bufferseed.kdtbuf, _state); + ae_shared_pool_set_seed(&solver->bufferpool, &bufferseed, (ae_int_t)sizeof(bufferseed), (ae_copy_constructor)_rbf3ddmbuffer_init_copy, (ae_destructor)_rbf3ddmbuffer_destroy, _state); + + /* + * Prepare default subproblems buffer, run recursive procedure + * and count subproblems in the buffer + */ + subproblem.isvalid = ae_false; + ae_shared_pool_set_seed(&solver->subproblemspool, &subproblem, (ae_int_t)sizeof(subproblem), (ae_copy_constructor)_rbf3ddmsubproblem_init_copy, (ae_destructor)_rbf3ddmsubproblem_destroy, _state); + ae_shared_pool_set_seed(&solver->subproblemsbuffer, &subproblem, (ae_int_t)sizeof(subproblem), (ae_copy_constructor)_rbf3ddmsubproblem_init_copy, (ae_destructor)_rbf3ddmsubproblem_destroy, _state); + rbfv3_ddmsolverinitrec(solver, x, n, nx, bfmatrix, solver->lambdav, sp, &idx, 0, n, nneighbors, nbatch, dodetailedtrace, _state); + solver->subproblemscnt = 0; + solver->cntlu = 0; + solver->cntregqr = 0; + ae_shared_pool_first_recycled(&solver->subproblemspool, &_p, _state); + while(p!=NULL) + { + solver->subproblemscnt = solver->subproblemscnt+1; + if( p->decomposition==0 ) + { + inc(&solver->cntlu, _state); + } + if( p->decomposition==1 ) + { + inc(&solver->cntregqr, _state); + } + ae_shared_pool_next_recycled(&solver->subproblemspool, &_p, _state); + } + ae_assert(solver->cntlu+solver->cntregqr==solver->subproblemscnt, "RBFV3: integrity check 5296 failed", _state); + ae_assert(solver->subproblemscnt>0, "RBFV3: subproblems pool is empty, critical integrity check failed", _state); + + /* + * DDM part is done + */ + *timeddminit = ae_tickcount()-(*timeddminit); + if( dotrace ) + { + ae_trace("> DDM part was prepared in %0d ms, %0d subproblems solved (%0d well-conditioned, %0d ill-conditioned)\n", + (int)(*timeddminit), + (int)(solver->subproblemscnt), + (int)(solver->cntlu), + (int)(solver->cntregqr)); + } + + /* + * Prepare correction spline + */ + *timecorrinit = ae_tickcount(); + rbfv3_selectglobalnodes(x, n, nx, &idummy, 0, ncorrector, &solver->corrnodes, &solver->ncorrector, &correctorgridseparation, _state); + ncorrector = solver->ncorrector; + ae_assert(ncorrector>0, "RBFV3: NCorrector=0", _state); + nsys = ncorrector+nx+1; + rsetallocm(2*nsys, nsys, 0.0, &corrsys, _state); + rallocm(ncorrector, nx, &solver->corrx, _state); + for(i=0; i<=ncorrector-1; i++) + { + rcopyrr(nx, x, solver->corrnodes.ptr.p_int[i], &solver->corrx, i, _state); + } + rbfv3_computebfmatrix(&solver->corrx, ncorrector, nx, bftype, bfparam, &corrsys, _state); + if( aterm==1 ) + { + + /* + * Use linear term + */ + for(i=0; i<=nx-1; i++) + { + for(j=0; j<=ncorrector-1; j++) + { + corrsys.ptr.pp_double[ncorrector+i][j] = x->ptr.pp_double[solver->corrnodes.ptr.p_int[j]][i]; + corrsys.ptr.pp_double[j][ncorrector+i] = x->ptr.pp_double[solver->corrnodes.ptr.p_int[j]][i]; + } + } + for(j=0; j<=ncorrector-1; j++) + { + corrsys.ptr.pp_double[ncorrector+nx][j] = 1.0; + corrsys.ptr.pp_double[j][ncorrector+nx] = 1.0; + } + } + if( aterm==2 ) + { + + /* + * Use constant term + */ + for(i=0; i<=nx-1; i++) + { + corrsys.ptr.pp_double[ncorrector+i][ncorrector+i] = 1.0; + } + for(j=0; j<=ncorrector-1; j++) + { + corrsys.ptr.pp_double[ncorrector+nx][j] = 1.0; + corrsys.ptr.pp_double[j][ncorrector+nx] = 1.0; + } + } + if( aterm==3 ) + { + + /* + * Use zero term + */ + for(i=0; i<=nx; i++) + { + corrsys.ptr.pp_double[ncorrector+i][ncorrector+i] = 1.0; + } + } + for(j=0; j<=ncorrector-1; j++) + { + corrsys.ptr.pp_double[j][j] = corrsys.ptr.pp_double[j][j]+solver->lambdav; + } + reg = 1.0; + for(i=0; i<=nsys-1; i++) + { + reg = ae_maxreal(reg, rmaxabsr(nsys, &corrsys, i, _state), _state); + } + reg = ae_sqrt(ae_machineepsilon, _state)*reg; + for(j=0; j<=nsys-1; j++) + { + corrsys.ptr.pp_double[nsys+j][j] = reg; + } + rmatrixqr(&corrsys, 2*nsys, nsys, &corrtau, _state); + rmatrixqrunpackq(&corrsys, 2*nsys, nsys, &corrtau, nsys, &solver->corrq, _state); + rmatrixqrunpackr(&corrsys, 2*nsys, nsys, &solver->corrr, _state); + *timecorrinit = ae_tickcount()-(*timecorrinit); + if( dotrace ) + { + ae_trace("> Corrector spline was prepared in %0d ms (%0d nodes, max distance from dataset points to nearest grid node is %0.2e)\n", + (int)(*timecorrinit), + (int)(ncorrector), + (double)(correctorgridseparation*rescaledby)); + } + if( dodetailedtrace ) + { + ae_trace("> printing condition numbers for correction spline:\n"); + ae_trace("cond(A) = %0.2e (Linf norm, leading NCoarsexNCoarse block)\n", + (double)((double)1/(rmatrixtrrcondinf(&solver->corrr, ncorrector, ae_true, ae_false, _state)+ae_machineepsilon))); + ae_trace("cond(A) = %0.2e (Linf norm, full system)\n", + (double)((double)1/(rmatrixtrrcondinf(&solver->corrr, nsys, ae_true, ae_false, _state)+ae_machineepsilon))); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive subroutine for DDM method. Given initial subproblems count Cnt, +it perform two recursive calls (spawns children in parallel when possible) +with Cnt~Cnt/2 until we end up with Cnt=1. + +Case with Cnt=1 is handled by retrieving subproblem from Solver.SubproblemsPool, +solving it and pushing subproblem to Solver.SubproblemsBuffer. + +INPUT PARAMETERS: + Solver - DDM solver object + Res - array[N,NY], current residuals + N, NX, NY - dataset metrics, N>0, NX>0, NY>0 + C - preallocated array[N+NX+1,NY] + Cnt - number of subproblems to process + +OUTPUT PARAMETERS: + C - rows 0..N-1 contain spline coefficients + rows N..N+NX are filled by zeros + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverrunrec(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* res, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + /* Real */ ae_matrix* c, + ae_int_t cnt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nwrk; + ae_int_t ntarget; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + rbf3ddmsubproblem *subproblem; + ae_smart_ptr _subproblem; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + + + /* + * Run recursive procedure if needed + */ + if( cnt>1 ) + { + k = cnt/2; + ae_assert(k<=cnt-k, "RBFV3: integrity check 2733 failed", _state); + rbfv3_ddmsolverrunrec(solver, res, n, nx, ny, c, cnt-k, _state); + rbfv3_ddmsolverrunrec(solver, res, n, nx, ny, c, k, _state); + ae_frame_leave(_state); + return; + } + + /* + * Retrieve subproblem from the source pool, solve it + */ + ae_shared_pool_retrieve(&solver->subproblemspool, &_subproblem, _state); + ae_assert(subproblem!=NULL&&subproblem->isvalid, "RBFV3: integrity check 1742 failed", _state); + nwrk = subproblem->nwork; + ntarget = subproblem->ntarget; + if( subproblem->decomposition==0 ) + { + + /* + * Solve using LU decomposition (the fastest option) + */ + rallocm(nwrk, ny, &subproblem->rhs, _state); + for(i=0; i<=nwrk-1; i++) + { + for(j=0; j<=ny-1; j++) + { + subproblem->rhs.ptr.pp_double[i][j] = res->ptr.pp_double[subproblem->workingnodes.ptr.p_int[i]][j]; + } + } + for(i=0; i<=nwrk-1; i++) + { + if( subproblem->wrkp.ptr.p_int[i]!=i ) + { + for(j=0; j<=ny-1; j++) + { + v = subproblem->rhs.ptr.pp_double[i][j]; + subproblem->rhs.ptr.pp_double[i][j] = subproblem->rhs.ptr.pp_double[subproblem->wrkp.ptr.p_int[i]][j]; + subproblem->rhs.ptr.pp_double[subproblem->wrkp.ptr.p_int[i]][j] = v; + } + } + } + rmatrixlefttrsm(nwrk, ny, &subproblem->wrklu, 0, 0, ae_false, ae_true, 0, &subproblem->rhs, 0, 0, _state); + rmatrixlefttrsm(nwrk, ny, &subproblem->wrklu, 0, 0, ae_true, ae_false, 0, &subproblem->rhs, 0, 0, _state); + rcopyallocm(nwrk, ny, &subproblem->rhs, &subproblem->sol, _state); + } + else + { + + /* + * Solve using regularized QR (well, we tried LU but it failed) + */ + ae_assert(subproblem->decomposition==1, "RBFV3: integrity check 1743 failed", _state); + rallocm(nwrk, ny, &subproblem->rhs, _state); + for(i=0; i<=nwrk-1; i++) + { + for(j=0; j<=ny-1; j++) + { + subproblem->rhs.ptr.pp_double[i][j] = res->ptr.pp_double[subproblem->workingnodes.ptr.p_int[i]][j]; + } + } + rallocm(nwrk, ny, &subproblem->qtrhs, _state); + rmatrixgemm(nwrk, ny, nwrk, 1.0, &subproblem->wrkq, 0, 0, 1, &subproblem->rhs, 0, 0, 0, 0.0, &subproblem->qtrhs, 0, 0, _state); + rmatrixlefttrsm(nwrk, ny, &subproblem->wrkr, 0, 0, ae_true, ae_false, 0, &subproblem->qtrhs, 0, 0, _state); + rcopyallocm(nwrk, ny, &subproblem->qtrhs, &subproblem->sol, _state); + } + for(i=0; i<=ntarget-1; i++) + { + for(j=0; j<=ny-1; j++) + { + c->ptr.pp_double[subproblem->targetnodes.ptr.p_int[i]][j] = subproblem->sol.ptr.pp_double[i][j]; + } + } + + /* + * Push to the destination pool + */ + ae_shared_pool_recycle(&solver->subproblemsbuffer, &_subproblem, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function APPROXIMATELY solves RBF interpolation problem using domain +decomposition method. Given current residuals Res, it computes approximate +basis function coefficients C (but does NOT compute linear coefficients +- these are set to zero). + +This function is a linear operator with respect to its input RES, thus it +can be used as a preconditioner for an iterative linear solver like GMRES. + +INPUT PARAMETERS: + Solver - DDM solver object + Res - array[N,NY], current residuals + N, NX, NY - dataset metrics, N>0, NX>0, NY>0 + SP - preconditioner, (N+NX+1)*(N+NX+1) sparse matrix + BFMatrix - basis functions evaluator + C - preallocated array[N+NX+1,NY] + timeDDMSolve, + timeCorrSolve- on input contain already accumulated timings + for DDM and CORR parts + +OUTPUT PARAMETERS: + C - rows 0..N-1 contain spline coefficients + rows N..N+NX are filled by zeros + timeDDMSolve, + timeCorrSolve- updated with new timings + + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverrun(rbf3ddmsolver* solver, + /* Real */ const ae_matrix* res, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + const sparsematrix* sp, + rbf3evaluator* bfmatrix, + rbf3fastevaluator* fasteval, + double fastevaltol, + /* Real */ ae_matrix* upd, + ae_int_t* timeddmsolve, + ae_int_t* timecorrsolve, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + rbf3ddmsubproblem *subproblem; + ae_smart_ptr _subproblem; + ae_matrix c; + ae_vector x0; + ae_vector x1; + ae_vector refrhs1; + ae_matrix corrpred; + ae_matrix updt; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + memset(&c, 0, sizeof(c)); + memset(&x0, 0, sizeof(x0)); + memset(&x1, 0, sizeof(x1)); + memset(&refrhs1, 0, sizeof(refrhs1)); + memset(&corrpred, 0, sizeof(corrpred)); + memset(&updt, 0, sizeof(updt)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&refrhs1, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&corrpred, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&updt, 0, 0, DT_REAL, _state, ae_true); + + rsetallocm(ny, n+nx+1, 0.0, &updt, _state); + rsetallocm(n+nx+1, ny, 0.0, &c, _state); + for(j=0; j<=ny-1; j++) + { + for(i=n; i<=n+nx; i++) + { + c.ptr.pp_double[i][j] = (double)(0); + } + } + + /* + * Solve DDM part: + * * run recursive procedure that computes DDM part. + * * clean-up: move processed subproblems from Solver.SubproblemsBuffer back to Solver.SubproblemsPool + * * multiply solution by the preconditioner matrix + */ + *timeddmsolve = *timeddmsolve-ae_tickcount(); + rbfv3_ddmsolverrunrec(solver, res, n, nx, ny, &c, solver->subproblemscnt, _state); + for(i=0; i<=solver->subproblemscnt-1; i++) + { + ae_shared_pool_retrieve(&solver->subproblemsbuffer, &_subproblem, _state); + ae_assert(subproblem!=NULL&&subproblem->isvalid, "RBFV3: integrity check 5223 failed", _state); + ae_shared_pool_recycle(&solver->subproblemspool, &_subproblem, _state); + } + *timeddmsolve = *timeddmsolve+ae_tickcount(); + rallocv(n+nx+1, &x0, _state); + rallocv(n+nx+1, &x1, _state); + for(j=0; j<=ny-1; j++) + { + rcopycv(n+nx+1, &c, j, &x0, _state); + sparsegemv(sp, 1.0, 1, &x0, 0, 0.0, &x1, 0, _state); + rcopyvr(n+nx+1, &x1, &updt, j, _state); + } + + /* + * Compute correction spline that fixes oscillations introduced by the DDM part + */ + *timecorrsolve = *timecorrsolve-ae_tickcount(); + rallocv(solver->ncorrector+nx+1, &x0, _state); + rallocv(n+nx+1, &x1, _state); + for(j=0; j<=ny-1; j++) + { + + /* + * Prepare right-hand side for the QR solver + */ + rsetallocm(1, solver->ncorrector+nx+1, 0.0, &corrpred, _state); + rsetallocv(solver->ncorrector+nx+1, 0.0, &refrhs1, _state); + rcopyrv(n+nx+1, &updt, j, &x1, _state); + rbfv3_fastevaluatorloadcoeffs1(fasteval, &x1, _state); + rbfv3_fastevaluatorpushtol(fasteval, fastevaltol, _state); + rbfv3_fastevaluatorcomputebatch(fasteval, &solver->corrx, solver->ncorrector, ae_true, &corrpred, _state); + for(i=0; i<=solver->ncorrector-1; i++) + { + refrhs1.ptr.p_double[i] = res->ptr.pp_double[solver->corrnodes.ptr.p_int[i]][j]-corrpred.ptr.pp_double[0][i]; + for(k=0; k<=nx-1; k++) + { + refrhs1.ptr.p_double[i] = refrhs1.ptr.p_double[i]-solver->corrx.ptr.pp_double[i][k]*x1.ptr.p_double[n+k]; + } + refrhs1.ptr.p_double[i] = refrhs1.ptr.p_double[i]-x1.ptr.p_double[n+nx]; + refrhs1.ptr.p_double[i] = refrhs1.ptr.p_double[i]-solver->lambdav*x1.ptr.p_double[solver->corrnodes.ptr.p_int[i]]; + } + + /* + * Solve QR-factorized system + */ + rgemv(solver->ncorrector+nx+1, solver->ncorrector+nx+1, 1.0, &solver->corrq, 1, &refrhs1, 0.0, &x0, _state); + rmatrixtrsv(solver->ncorrector+nx+1, &solver->corrr, 0, 0, ae_true, ae_false, 0, &x0, 0, _state); + for(i=0; i<=solver->ncorrector-1; i++) + { + updt.ptr.pp_double[j][solver->corrnodes.ptr.p_int[i]] = updt.ptr.pp_double[j][solver->corrnodes.ptr.p_int[i]]+x0.ptr.p_double[i]; + } + for(i=0; i<=nx; i++) + { + updt.ptr.pp_double[j][n+i] = updt.ptr.pp_double[j][n+i]+x0.ptr.p_double[solver->ncorrector+i]; + } + } + *timecorrsolve = *timecorrsolve+ae_tickcount(); + rallocm(n+nx+1, ny, upd, _state); + rmatrixtranspose(ny, n+nx+1, &updt, 0, 0, upd, 0, 0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function is a specialized version of DDMSolverRun() for NY=1. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_ddmsolverrun1(rbf3ddmsolver* solver, + /* Real */ const ae_vector* res, + ae_int_t n, + ae_int_t nx, + const sparsematrix* sp, + rbf3evaluator* bfmatrix, + rbf3fastevaluator* fasteval, + double fastevaltol, + /* Real */ ae_vector* upd, + ae_int_t* timeddmsolve, + ae_int_t* timecorrsolve, + ae_state *_state) +{ + + + rallocm(n, 1, &solver->tmpres1, _state); + rcopyvc(n, res, &solver->tmpres1, 0, _state); + rbfv3_ddmsolverrun(solver, &solver->tmpres1, n, nx, 1, sp, bfmatrix, fasteval, fastevaltol, &solver->tmpupd1, timeddmsolve, timecorrsolve, _state); + rallocv(n+nx+1, upd, _state); + rcopycv(n+nx+1, &solver->tmpupd1, 0, upd, _state); +} + + +/************************************************************************* +Automatically detect scale parameter as a mean distance towards nearest +neighbor (not counting nearest neighbors that are too close) + +PARAMETERS: + XX - dataset (X-values), array[N,NX] + N - points count, N>=1 + NX - dimensions count, NX>=1 + +RESULT: + suggested scale + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static double rbfv3_autodetectscaleparameter(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t nq; + ae_int_t nlocal; + kdtree kdt; + ae_vector x; + ae_vector d; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&kdt, 0, sizeof(kdt)); + memset(&x, 0, sizeof(x)); + memset(&d, 0, sizeof(d)); + _kdtree_init(&kdt, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RBFV3: integrity check 7624 failed", _state); + rallocv(nx, &x, _state); + kdtreebuild(xx, n, nx, 0, 2, &kdt, _state); + nlocal = ae_round(ae_pow((double)(2), (double)(nx), _state)+(double)1, _state); + result = (double)(0); + for(i=0; i<=n-1; i++) + { + + /* + * Query a batch of nearest neighbors + */ + rcopyrv(nx, xx, i, &x, _state); + nq = kdtreequeryknn(&kdt, &x, nlocal, ae_true, _state); + ae_assert(nq>=1, "RBFV3: integrity check 7625 failed", _state); + kdtreequeryresultsdistances(&kdt, &d, _state); + + /* + * In order to filter out nearest neighbors that are too close, + * we use distance R toward most distant of NQ nearest neighbors as + * a reference and select nearest neighbor with distance >=0.5*R/NQ + */ + for(j=0; j<=nq-1; j++) + { + if( ae_fp_greater_eq(d.ptr.p_double[j],0.5*d.ptr.p_double[nq-1]/(double)nq) ) + { + result = result+d.ptr.p_double[j]; + break; + } + } + } + result = result/(double)n; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Recursive functions matrix computation + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computebfmatrixrec(/* Real */ const ae_matrix* xx, + ae_int_t range0, + ae_int_t range1, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double elemcost; + double alpha2; + + + ae_assert((functype==1||functype==2)||functype==3, "RBFV3.ComputeTransposedDesignSystem: unexpected FuncType", _state); + + /* + * Try to parallelize + */ + elemcost = 10.0; + if( ((range0==0&&range1==n)&&ae_fp_greater_eq(0.5*rmul3((double)(n), (double)(n), elemcost, _state),smpactivationlevel(_state)))&&n>=rbfv3_bfparallelthreshold ) + { + if( _trypexec_rbfv3_computebfmatrixrec(xx,range0,range1,n,nx,functype,funcparam,f, _state) ) + { + return; + } + } + + /* + * Try recursive splits + */ + if( range1-range0>16 ) + { + k = range0+(range1-range0)/2; + rbfv3_computebfmatrixrec(xx, range0, k, n, nx, functype, funcparam, f, _state); + rbfv3_computebfmatrixrec(xx, k, range1, n, nx, functype, funcparam, f, _state); + return; + } + + /* + * Serial processing + */ + alpha2 = funcparam*funcparam; + for(i=range0; i<=range1-1; i++) + { + for(j=i; j<=n-1; j++) + { + v = (double)(0); + for(k=0; k<=nx-1; k++) + { + vv = xx->ptr.pp_double[i][k]-xx->ptr.pp_double[j][k]; + v = v+vv*vv; + } + if( functype==1 ) + { + v = -ae_sqrt(v+alpha2, _state); + } + if( functype==2 ) + { + if( v!=0.0 ) + { + v = v*0.5*ae_log(v, _state); + } + else + { + v = 0.0; + } + } + if( functype==3 ) + { + v = v*ae_sqrt(v, _state); + } + f->ptr.pp_double[i][j] = v; + f->ptr.pp_double[j][i] = v; + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv3_computebfmatrixrec(/* Real */ const ae_matrix* xx, + ae_int_t range0, + ae_int_t range1, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function computes basis functions matrix (both upper and lower +triangles) + + + [ f(dist(x0,x0)) ... f(dist(x0,x(n-1))) ] + [ f(dist(x1,x0)) ... f(dist(x1,x(n-1))) ] + [ ............................................. ] + [ f(dist(x(n-1),x0)) ... f(dist(x(n-1),x(n-1))) ] + +NOTE: if F is large enough to store result, it is not reallocated. Values + outside of [0,N)x[0,N) range are not modified. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computebfmatrix(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + /* Real */ ae_matrix* f, + ae_state *_state) +{ + + + rallocm(n, n, f, _state); + rbfv3_computebfmatrixrec(xx, 0, n, n, nx, functype, funcparam, f, _state); +} + + +/************************************************************************* +Initializes model matrix using specified matrix storage format: +* StorageType=0 a N*N matrix of basis function values is stored +* StorageType=1 basis function values are recomputed on demand + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_modelmatrixinit(/* Real */ const ae_matrix* xx, + ae_int_t n, + ae_int_t nx, + ae_int_t functype, + double funcparam, + ae_int_t storagetype, + rbf3evaluator* modelmatrix, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nchunks; + ae_int_t i; + ae_int_t j; + ae_int_t srcoffs; + ae_int_t dstoffs; + ae_int_t curlen; + rbf3evaluatorbuffer bufseed; + + ae_frame_make(_state, &_frame_block); + memset(&bufseed, 0, sizeof(bufseed)); + _rbf3evaluator_clear(modelmatrix); + _rbf3evaluatorbuffer_init(&bufseed, _state, ae_true); + + ae_assert(storagetype==0||storagetype==1, "RBFV3: unexpected StorageType for ModelMatrixInit()", _state); + modelmatrix->n = n; + modelmatrix->storagetype = storagetype; + if( storagetype==0 ) + { + rbfv3_computebfmatrix(xx, n, nx, functype, funcparam, &modelmatrix->f, _state); + ae_frame_leave(_state); + return; + } + if( storagetype==1 ) + { + + /* + * Save model parameters + */ + modelmatrix->nx = nx; + modelmatrix->functype = functype; + modelmatrix->funcparam = funcparam; + modelmatrix->chunksize = 128; + + /* + * Prepare temporary buffers + */ + ae_shared_pool_set_seed(&modelmatrix->bufferpool, &bufseed, (ae_int_t)sizeof(bufseed), (ae_copy_constructor)_rbf3evaluatorbuffer_init_copy, (ae_destructor)_rbf3evaluatorbuffer_destroy, _state); + rsetallocv(modelmatrix->chunksize, 1.0, &modelmatrix->chunk1, _state); + + /* + * Store dataset in the chunked row storage format (rows with size at most ChunkSize, one row per dimension/chunk) + */ + iallocv(n, &modelmatrix->entireset, _state); + for(i=0; i<=n-1; i++) + { + modelmatrix->entireset.ptr.p_int[i] = i; + } + rcopyallocm(n, nx, xx, &modelmatrix->x, _state); + nchunks = idivup(n, modelmatrix->chunksize, _state); + rsetallocm(nchunks*nx, modelmatrix->chunksize, 0.0, &modelmatrix->xtchunked, _state); + srcoffs = 0; + dstoffs = 0; + while(srcoffschunksize, n-srcoffs, _state); + for(i=0; i<=curlen-1; i++) + { + for(j=0; j<=nx-1; j++) + { + modelmatrix->xtchunked.ptr.pp_double[dstoffs+j][i] = xx->ptr.pp_double[srcoffs+i][j]; + } + } + srcoffs = srcoffs+curlen; + dstoffs = dstoffs+nx; + } + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "ModelMatrixInit: integrity check failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Computes subset of the model matrix (subset of rows, subset of columns) and +writes result to R. + +NOTE: If R is longer than M0xM1, it is not reallocated and additional elements + are not modified. + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_modelmatrixcomputepartial(const rbf3evaluator* modelmatrix, + /* Integer */ const ae_vector* ridx, + ae_int_t m0, + /* Integer */ const ae_vector* cidx, + ae_int_t m1, + /* Real */ ae_matrix* r, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t ni; + ae_int_t nj; + double v; + double vv; + + + ae_assert(modelmatrix->storagetype==0||modelmatrix->storagetype==1, "ModelMatrixComputePartial: unexpected StorageType", _state); + rallocm(m0, m1, r, _state); + if( modelmatrix->storagetype==0 ) + { + for(i=0; i<=m0-1; i++) + { + ni = ridx->ptr.p_int[i]; + for(j=0; j<=m1-1; j++) + { + r->ptr.pp_double[i][j] = modelmatrix->f.ptr.pp_double[ni][cidx->ptr.p_int[j]]; + } + } + return; + } + if( modelmatrix->storagetype==1 ) + { + ae_assert(modelmatrix->functype==1||modelmatrix->functype==2, "ModelMatrixComputePartial: unexpected FuncType", _state); + for(i=0; i<=m0-1; i++) + { + ni = ridx->ptr.p_int[i]; + for(j=0; j<=m1-1; j++) + { + nj = cidx->ptr.p_int[j]; + v = (double)(0); + if( modelmatrix->functype==1 ) + { + v = modelmatrix->funcparam*modelmatrix->funcparam; + } + if( modelmatrix->functype==2 ) + { + v = 1.0E-50; + } + for(k=0; k<=modelmatrix->nx-1; k++) + { + vv = modelmatrix->x.ptr.pp_double[ni][k]-modelmatrix->x.ptr.pp_double[nj][k]; + v = v+vv*vv; + } + if( modelmatrix->functype==1 ) + { + v = -ae_sqrt(v, _state); + } + if( modelmatrix->functype==2 ) + { + v = v*0.5*ae_log(v, _state); + } + r->ptr.pp_double[i][j] = v; + } + } + return; + } + ae_assert(ae_false, "ModelMatrixComputePartial: integrity check failed", _state); +} + + +/************************************************************************* +This function computes ChunkSize basis function values and stores them in +the evaluator buffer. This function does not modify Evaluator object, thus +it can be used in multiple threads with the same evaluator as long as different +buffers are used. + +INPUT PARAMETERS: + Evaluator - evaluator object + X - origin point + Buf - preallocated buffers. Following fields are used and + must have at least ChunkSize elements: + * Buf.FuncBuf + * Buf.WrkBuf + When NeedGradInfo>=1, additionally we need + the following fields to be preallocated: + * Buf.MinDist2 - array[ChunkSize], filled by some + positive values; on the very first call it is 1.0E50 + or something comparably large + * Buf.DeltaBuf - array[NX,ChunkSize] + * Buf.DF1 - array[ChunkSize] + When NeedGradInfo>=2, additionally we need + the following fields to be preallocated: + * Buf.DF2 - array[ChunkSize] + ChunkSize - amount of basis functions to compute, + 0=1 then its + I-th element is updated as MinDist2[I]:=min(MinDist2[I],DISTANCE_SQUARED(X,CENTER[I])) + Buf.DeltaBuf - array[NX,ChunkSize], if NeedGradInfo>=1 then + J-th element of K-th row is set to X[K]-CENTER[J,K] + Buf.DF1 - array[ChunkSize], if NeedGradInfo>=1 then + J-th element is derivative of the kernel function + with respect to its input (squared distance) + Buf.DF2 - array[ChunkSize], if NeedGradInfo>=2 then + J-th element is derivative of the kernel function + with respect to its input (squared distance) + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static void rbfv3_computerowchunk(const rbf3evaluator* evaluator, + /* Real */ const ae_vector* x, + rbf3evaluatorbuffer* buf, + ae_int_t chunksize, + ae_int_t chunkidx, + double distance0, + ae_int_t needgradinfo, + ae_state *_state) +{ + ae_int_t k; + double r2; + double lnr; + + + + /* + * Compute squared distance in Buf.FuncBuf + */ + rsetv(chunksize, distance0, &buf->funcbuf, _state); + for(k=0; k<=evaluator->nx-1; k++) + { + rsetv(chunksize, x->ptr.p_double[k], &buf->wrkbuf, _state); + raddrv(chunksize, -1.0, &evaluator->xtchunked, chunkidx+k, &buf->wrkbuf, _state); + rmuladdv(chunksize, &buf->wrkbuf, &buf->wrkbuf, &buf->funcbuf, _state); + if( needgradinfo>=1 ) + { + rcopyvr(chunksize, &buf->wrkbuf, &buf->deltabuf, k, _state); + } + } + if( needgradinfo>=1 ) + { + rmergeminv(chunksize, &buf->funcbuf, &buf->mindist2, _state); + } + + /* + * Apply kernel function + */ + if( evaluator->functype==1 ) + { + + /* + * f=-sqrt(r^2+alpha^2), including f=-r as a special case + */ + if( needgradinfo==0 ) + { + + /* + * Only target f(r2)=-sqrt(r2) is needed + */ + rsqrtv(chunksize, &buf->funcbuf, _state); + rmulv(chunksize, -1.0, &buf->funcbuf, _state); + } + if( needgradinfo==1 ) + { + + /* + * First derivative is needed: + * + * f(r2) = -sqrt(r2) + * f'(r2) = -0.5/sqrt(r2) + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle zero value as a special case + */ + rsqrtv(chunksize, &buf->funcbuf, _state); + rmulv(chunksize, -1.0, &buf->funcbuf, _state); + rsetv(chunksize, 0.5, &buf->df1, _state); + rmergedivv(chunksize, &buf->funcbuf, &buf->df1, _state); + } + if( needgradinfo==2 ) + { + + /* + * Second derivatives is needed: + * + * f(r2) = -sqrt(r2+alpha2) + * f'(r2) = -0.5/sqrt(r2+alpha2) + * f''(r2) = 0.25/((r2+alpha2)^(3/2)) + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle zero value as a special case + */ + rcopymulv(chunksize, -2.0, &buf->funcbuf, &buf->wrkbuf, _state); + rsqrtv(chunksize, &buf->funcbuf, _state); + rmulv(chunksize, -1.0, &buf->funcbuf, _state); + rsetv(chunksize, 0.5, &buf->df1, _state); + rmergedivv(chunksize, &buf->funcbuf, &buf->df1, _state); + rcopyv(chunksize, &buf->df1, &buf->df2, _state); + rmergedivv(chunksize, &buf->wrkbuf, &buf->df2, _state); + } + return; + } + if( evaluator->functype==2 ) + { + + /* + * f=r^2*ln(r) + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle ln(0) as a special case. + */ + if( needgradinfo==0 ) + { + + /* + * No gradient info is required + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle zero value as a special case + */ + for(k=0; k<=chunksize-1; k++) + { + buf->funcbuf.ptr.p_double[k] = buf->funcbuf.ptr.p_double[k]*0.5*ae_log(buf->funcbuf.ptr.p_double[k], _state); + } + } + if( needgradinfo==1 ) + { + + /* + * First derivative is needed: + * + * f(r2) = 0.5*r2*ln(r2) + * f'(r2) = 0.5*ln(r2) + 0.5 = 0.5*(ln(r2)+1) =ln(r)+0.5 + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle zero value as a special case + */ + for(k=0; k<=chunksize-1; k++) + { + r2 = buf->funcbuf.ptr.p_double[k]; + lnr = 0.5*ae_log(r2, _state); + buf->funcbuf.ptr.p_double[k] = r2*lnr; + buf->df1.ptr.p_double[k] = lnr+0.5; + } + } + if( needgradinfo==2 ) + { + + /* + * Second derivative is needed: + * + * f(r2) = 0.5*r2*ln(r2) + * f'(r2) = 0.5*ln(r2) + 0.5 = 0.5*(ln(r2)+1) =ln(r)+0.5 + * f''(r2)= 0.5/r2 + * + * NOTE: FuncBuf[] is always positive due to small correction added, + * thus we have no need to handle zero value as a special case + */ + for(k=0; k<=chunksize-1; k++) + { + r2 = buf->funcbuf.ptr.p_double[k]; + lnr = 0.5*ae_log(r2, _state); + buf->funcbuf.ptr.p_double[k] = r2*lnr; + buf->df1.ptr.p_double[k] = lnr+0.5; + buf->df2.ptr.p_double[k] = 0.5/r2; + } + } + return; + } + ae_assert(ae_false, "RBFV3: unexpected FuncType in ComputeRowChunk()", _state); +} + + +/************************************************************************* +Checks whether basis function is conditionally positive definite or not, +given the polynomial term type (ATerm=1 means linear, ATerm=2 means constant, +ATerm=3 means no polynomial term). + + -- ALGLIB -- + Copyright 12.12.2021 by Sergey Bochkanov +*************************************************************************/ +static ae_bool rbfv3_iscpdfunction(ae_int_t functype, + ae_int_t aterm, + ae_state *_state) +{ + ae_bool result; + + + ae_assert((aterm==1||aterm==2)||aterm==3, "RBFV3: integrity check 3563 failed", _state); + result = ae_false; + if( functype==1 ) + { + result = aterm==2||aterm==1; + return result; + } + if( functype==2 ) + { + result = aterm==1; + return result; + } + ae_assert(ae_false, "IsCPDFunction: unexpected FuncType", _state); + return result; +} + + +void _rbf3evaluatorbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3evaluatorbuffer *p = (rbf3evaluatorbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->coeffbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->funcbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mindist2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->df1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->df2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->deltabuf, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3evaluatorbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3evaluatorbuffer *dst = (rbf3evaluatorbuffer*)_dst; + const rbf3evaluatorbuffer *src = (const rbf3evaluatorbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->coeffbuf, &src->coeffbuf, _state, make_automatic); + ae_vector_init_copy(&dst->funcbuf, &src->funcbuf, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbuf, &src->wrkbuf, _state, make_automatic); + ae_vector_init_copy(&dst->mindist2, &src->mindist2, _state, make_automatic); + ae_vector_init_copy(&dst->df1, &src->df1, _state, make_automatic); + ae_vector_init_copy(&dst->df2, &src->df2, _state, make_automatic); + ae_vector_init_copy(&dst->x2, &src->x2, _state, make_automatic); + ae_vector_init_copy(&dst->y2, &src->y2, _state, make_automatic); + ae_matrix_init_copy(&dst->deltabuf, &src->deltabuf, _state, make_automatic); +} + + +void _rbf3evaluatorbuffer_clear(void* _p) +{ + rbf3evaluatorbuffer *p = (rbf3evaluatorbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->coeffbuf); + ae_vector_clear(&p->funcbuf); + ae_vector_clear(&p->wrkbuf); + ae_vector_clear(&p->mindist2); + ae_vector_clear(&p->df1); + ae_vector_clear(&p->df2); + ae_vector_clear(&p->x2); + ae_vector_clear(&p->y2); + ae_matrix_clear(&p->deltabuf); +} + + +void _rbf3evaluatorbuffer_destroy(void* _p) +{ + rbf3evaluatorbuffer *p = (rbf3evaluatorbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->coeffbuf); + ae_vector_destroy(&p->funcbuf); + ae_vector_destroy(&p->wrkbuf); + ae_vector_destroy(&p->mindist2); + ae_vector_destroy(&p->df1); + ae_vector_destroy(&p->df2); + ae_vector_destroy(&p->x2); + ae_vector_destroy(&p->y2); + ae_matrix_destroy(&p->deltabuf); +} + + +void _rbf3panel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3panel *p = (rbf3panel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->clustercenter, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ptidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->xt, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wt, 0, 0, DT_REAL, _state, make_automatic); + _biharmonicpanel_init(&p->bhexpansion, _state, make_automatic); + _rbf3evaluatorbuffer_init(&p->tgtbuf, _state, make_automatic); +} + + +void _rbf3panel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3panel *dst = (rbf3panel*)_dst; + const rbf3panel *src = (const rbf3panel*)_src; + dst->paneltype = src->paneltype; + dst->clusterrad = src->clusterrad; + ae_vector_init_copy(&dst->clustercenter, &src->clustercenter, _state, make_automatic); + dst->c0 = src->c0; + dst->c1 = src->c1; + dst->c2 = src->c2; + dst->c3 = src->c3; + dst->farfieldexpansion = src->farfieldexpansion; + dst->farfielddistance = src->farfielddistance; + dst->idx0 = src->idx0; + dst->idx1 = src->idx1; + dst->childa = src->childa; + dst->childb = src->childb; + ae_vector_init_copy(&dst->ptidx, &src->ptidx, _state, make_automatic); + ae_matrix_init_copy(&dst->xt, &src->xt, _state, make_automatic); + ae_matrix_init_copy(&dst->wt, &src->wt, _state, make_automatic); + _biharmonicpanel_init_copy(&dst->bhexpansion, &src->bhexpansion, _state, make_automatic); + _rbf3evaluatorbuffer_init_copy(&dst->tgtbuf, &src->tgtbuf, _state, make_automatic); +} + + +void _rbf3panel_clear(void* _p) +{ + rbf3panel *p = (rbf3panel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->clustercenter); + ae_vector_clear(&p->ptidx); + ae_matrix_clear(&p->xt); + ae_matrix_clear(&p->wt); + _biharmonicpanel_clear(&p->bhexpansion); + _rbf3evaluatorbuffer_clear(&p->tgtbuf); +} + + +void _rbf3panel_destroy(void* _p) +{ + rbf3panel *p = (rbf3panel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->clustercenter); + ae_vector_destroy(&p->ptidx); + ae_matrix_destroy(&p->xt); + ae_matrix_destroy(&p->wt); + _biharmonicpanel_destroy(&p->bhexpansion); + _rbf3evaluatorbuffer_destroy(&p->tgtbuf); +} + + +void _rbf3fastevaluator_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3fastevaluator *p = (rbf3fastevaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->permx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->origptidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->wstoredorig, 0, 0, DT_REAL, _state, make_automatic); + ae_obj_array_init(&p->panels, _state, make_automatic); + _biharmonicevaluator_init(&p->bheval, _state, make_automatic); + ae_shared_pool_init(&p->bufferpool, _state, make_automatic); + ae_matrix_init(&p->tmpx3w, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3fastevaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3fastevaluator *dst = (rbf3fastevaluator*)_dst; + const rbf3fastevaluator *src = (const rbf3fastevaluator*)_src; + dst->n = src->n; + dst->nx = src->nx; + dst->ny = src->ny; + dst->maxpanelsize = src->maxpanelsize; + dst->functype = src->functype; + dst->funcparam = src->funcparam; + ae_matrix_init_copy(&dst->permx, &src->permx, _state, make_automatic); + ae_vector_init_copy(&dst->origptidx, &src->origptidx, _state, make_automatic); + ae_matrix_init_copy(&dst->wstoredorig, &src->wstoredorig, _state, make_automatic); + dst->isloaded = src->isloaded; + ae_obj_array_init_copy(&dst->panels, &src->panels, _state, make_automatic); + _biharmonicevaluator_init_copy(&dst->bheval, &src->bheval, _state, make_automatic); + ae_shared_pool_init_copy(&dst->bufferpool, &src->bufferpool, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpx3w, &src->tmpx3w, _state, make_automatic); + dst->usedebugcounters = src->usedebugcounters; + dst->dbgpanel2panelcnt = src->dbgpanel2panelcnt; + dst->dbgfield2panelcnt = src->dbgfield2panelcnt; + dst->dbgpanelscnt = src->dbgpanelscnt; +} + + +void _rbf3fastevaluator_clear(void* _p) +{ + rbf3fastevaluator *p = (rbf3fastevaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->permx); + ae_vector_clear(&p->origptidx); + ae_matrix_clear(&p->wstoredorig); + ae_obj_array_clear(&p->panels); + _biharmonicevaluator_clear(&p->bheval); + ae_shared_pool_clear(&p->bufferpool); + ae_matrix_clear(&p->tmpx3w); +} + + +void _rbf3fastevaluator_destroy(void* _p) +{ + rbf3fastevaluator *p = (rbf3fastevaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->permx); + ae_vector_destroy(&p->origptidx); + ae_matrix_destroy(&p->wstoredorig); + ae_obj_array_destroy(&p->panels); + _biharmonicevaluator_destroy(&p->bheval); + ae_shared_pool_destroy(&p->bufferpool); + ae_matrix_destroy(&p->tmpx3w); +} + + +void _rbf3evaluator_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3evaluator *p = (rbf3evaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->f, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->entireset, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xtchunked, 0, 0, DT_REAL, _state, make_automatic); + ae_shared_pool_init(&p->bufferpool, _state, make_automatic); + ae_vector_init(&p->chunk1, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3evaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3evaluator *dst = (rbf3evaluator*)_dst; + const rbf3evaluator *src = (const rbf3evaluator*)_src; + dst->n = src->n; + dst->storagetype = src->storagetype; + ae_matrix_init_copy(&dst->f, &src->f, _state, make_automatic); + dst->nx = src->nx; + dst->functype = src->functype; + dst->funcparam = src->funcparam; + dst->chunksize = src->chunksize; + ae_vector_init_copy(&dst->entireset, &src->entireset, _state, make_automatic); + ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_matrix_init_copy(&dst->xtchunked, &src->xtchunked, _state, make_automatic); + ae_shared_pool_init_copy(&dst->bufferpool, &src->bufferpool, _state, make_automatic); + ae_vector_init_copy(&dst->chunk1, &src->chunk1, _state, make_automatic); +} + + +void _rbf3evaluator_clear(void* _p) +{ + rbf3evaluator *p = (rbf3evaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->f); + ae_vector_clear(&p->entireset); + ae_matrix_clear(&p->x); + ae_matrix_clear(&p->xtchunked); + ae_shared_pool_clear(&p->bufferpool); + ae_vector_clear(&p->chunk1); +} + + +void _rbf3evaluator_destroy(void* _p) +{ + rbf3evaluator *p = (rbf3evaluator*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->f); + ae_vector_destroy(&p->entireset); + ae_matrix_destroy(&p->x); + ae_matrix_destroy(&p->xtchunked); + ae_shared_pool_destroy(&p->bufferpool); + ae_vector_destroy(&p->chunk1); +} + + +void _rbfv3calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv3calcbuffer *p = (rbfv3calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + _rbf3evaluatorbuffer_init(&p->evalbuf, _state, make_automatic); + ae_vector_init(&p->x123, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y123, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->x2d, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->y2d, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yg, 0, DT_REAL, _state, make_automatic); +} + + +void _rbfv3calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv3calcbuffer *dst = (rbfv3calcbuffer*)_dst; + const rbfv3calcbuffer *src = (const rbfv3calcbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + _rbf3evaluatorbuffer_init_copy(&dst->evalbuf, &src->evalbuf, _state, make_automatic); + ae_vector_init_copy(&dst->x123, &src->x123, _state, make_automatic); + ae_vector_init_copy(&dst->y123, &src->y123, _state, make_automatic); + ae_matrix_init_copy(&dst->x2d, &src->x2d, _state, make_automatic); + ae_matrix_init_copy(&dst->y2d, &src->y2d, _state, make_automatic); + ae_vector_init_copy(&dst->xg, &src->xg, _state, make_automatic); + ae_vector_init_copy(&dst->yg, &src->yg, _state, make_automatic); +} + + +void _rbfv3calcbuffer_clear(void* _p) +{ + rbfv3calcbuffer *p = (rbfv3calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + _rbf3evaluatorbuffer_clear(&p->evalbuf); + ae_vector_clear(&p->x123); + ae_vector_clear(&p->y123); + ae_matrix_clear(&p->x2d); + ae_matrix_clear(&p->y2d); + ae_vector_clear(&p->xg); + ae_vector_clear(&p->yg); +} + + +void _rbfv3calcbuffer_destroy(void* _p) +{ + rbfv3calcbuffer *p = (rbfv3calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + _rbf3evaluatorbuffer_destroy(&p->evalbuf); + ae_vector_destroy(&p->x123); + ae_vector_destroy(&p->y123); + ae_matrix_destroy(&p->x2d); + ae_matrix_destroy(&p->y2d); + ae_vector_destroy(&p->xg); + ae_vector_destroy(&p->yg); +} + + +void _acbfbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + acbfbuilder *p = (acbfbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->xx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->globalgrid, 0, DT_INT, _state, make_automatic); + _kdtree_init(&p->kdt, _state, make_automatic); + _kdtree_init(&p->kdt1, _state, make_automatic); + _kdtree_init(&p->kdt2, _state, make_automatic); + ae_shared_pool_init(&p->bufferpool, _state, make_automatic); + ae_shared_pool_init(&p->chunksproducer, _state, make_automatic); + ae_shared_pool_init(&p->chunkspool, _state, make_automatic); + ae_vector_init(&p->wrkidx, 0, DT_INT, _state, make_automatic); +} + + +void _acbfbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + acbfbuilder *dst = (acbfbuilder*)_dst; + const acbfbuilder *src = (const acbfbuilder*)_src; + dst->dodetailedtrace = src->dodetailedtrace; + dst->ntotal = src->ntotal; + dst->nx = src->nx; + ae_matrix_init_copy(&dst->xx, &src->xx, _state, make_automatic); + dst->functype = src->functype; + dst->funcparam = src->funcparam; + dst->roughdatasetdiameter = src->roughdatasetdiameter; + dst->nglobal = src->nglobal; + ae_vector_init_copy(&dst->globalgrid, &src->globalgrid, _state, make_automatic); + dst->globalgridseparation = src->globalgridseparation; + dst->nlocal = src->nlocal; + dst->ncorrection = src->ncorrection; + dst->correctorgrowth = src->correctorgrowth; + dst->batchsize = src->batchsize; + dst->lambdav = src->lambdav; + dst->aterm = src->aterm; + _kdtree_init_copy(&dst->kdt, &src->kdt, _state, make_automatic); + _kdtree_init_copy(&dst->kdt1, &src->kdt1, _state, make_automatic); + _kdtree_init_copy(&dst->kdt2, &src->kdt2, _state, make_automatic); + ae_shared_pool_init_copy(&dst->bufferpool, &src->bufferpool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->chunksproducer, &src->chunksproducer, _state, make_automatic); + ae_shared_pool_init_copy(&dst->chunkspool, &src->chunkspool, _state, make_automatic); + ae_vector_init_copy(&dst->wrkidx, &src->wrkidx, _state, make_automatic); +} + + +void _acbfbuilder_clear(void* _p) +{ + acbfbuilder *p = (acbfbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->xx); + ae_vector_clear(&p->globalgrid); + _kdtree_clear(&p->kdt); + _kdtree_clear(&p->kdt1); + _kdtree_clear(&p->kdt2); + ae_shared_pool_clear(&p->bufferpool); + ae_shared_pool_clear(&p->chunksproducer); + ae_shared_pool_clear(&p->chunkspool); + ae_vector_clear(&p->wrkidx); +} + + +void _acbfbuilder_destroy(void* _p) +{ + acbfbuilder *p = (acbfbuilder*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->xx); + ae_vector_destroy(&p->globalgrid); + _kdtree_destroy(&p->kdt); + _kdtree_destroy(&p->kdt1); + _kdtree_destroy(&p->kdt2); + ae_shared_pool_destroy(&p->bufferpool); + ae_shared_pool_destroy(&p->chunksproducer); + ae_shared_pool_destroy(&p->chunkspool); + ae_vector_destroy(&p->wrkidx); +} + + +void _acbfbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + acbfbuffer *p = (acbfbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->bflags, 0, DT_BOOL, _state, make_automatic); + _kdtreerequestbuffer_init(&p->kdtbuf, _state, make_automatic); + _kdtreerequestbuffer_init(&p->kdt1buf, _state, make_automatic); + _kdtreerequestbuffer_init(&p->kdt2buf, _state, make_automatic); + ae_vector_init(&p->tmpboxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpboxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentnodes, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->neighbors, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->chosenneighbors, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->atwrk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q1, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wrkq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->b, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->c, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->choltmp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tau, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->r, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->perm, 0, DT_INT, _state, make_automatic); +} + + +void _acbfbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + acbfbuffer *dst = (acbfbuffer*)_dst; + const acbfbuffer *src = (const acbfbuffer*)_src; + ae_vector_init_copy(&dst->bflags, &src->bflags, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->kdtbuf, &src->kdtbuf, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->kdt1buf, &src->kdt1buf, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->kdt2buf, &src->kdt2buf, _state, make_automatic); + ae_vector_init_copy(&dst->tmpboxmin, &src->tmpboxmin, _state, make_automatic); + ae_vector_init_copy(&dst->tmpboxmax, &src->tmpboxmax, _state, make_automatic); + ae_vector_init_copy(&dst->currentnodes, &src->currentnodes, _state, make_automatic); + ae_vector_init_copy(&dst->neighbors, &src->neighbors, _state, make_automatic); + ae_vector_init_copy(&dst->chosenneighbors, &src->chosenneighbors, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_matrix_init_copy(&dst->atwrk, &src->atwrk, _state, make_automatic); + ae_matrix_init_copy(&dst->xq, &src->xq, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); + ae_matrix_init_copy(&dst->q1, &src->q1, _state, make_automatic); + ae_matrix_init_copy(&dst->wrkq, &src->wrkq, _state, make_automatic); + ae_matrix_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_matrix_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->choltmp, &src->choltmp, _state, make_automatic); + ae_vector_init_copy(&dst->tau, &src->tau, _state, make_automatic); + ae_matrix_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->perm, &src->perm, _state, make_automatic); +} + + +void _acbfbuffer_clear(void* _p) +{ + acbfbuffer *p = (acbfbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->bflags); + _kdtreerequestbuffer_clear(&p->kdtbuf); + _kdtreerequestbuffer_clear(&p->kdt1buf); + _kdtreerequestbuffer_clear(&p->kdt2buf); + ae_vector_clear(&p->tmpboxmin); + ae_vector_clear(&p->tmpboxmax); + ae_vector_clear(&p->currentnodes); + ae_vector_clear(&p->neighbors); + ae_vector_clear(&p->chosenneighbors); + ae_vector_clear(&p->y); + ae_vector_clear(&p->z); + ae_vector_clear(&p->d); + ae_matrix_clear(&p->atwrk); + ae_matrix_clear(&p->xq); + ae_matrix_clear(&p->q); + ae_matrix_clear(&p->q1); + ae_matrix_clear(&p->wrkq); + ae_matrix_clear(&p->b); + ae_matrix_clear(&p->c); + ae_vector_clear(&p->choltmp); + ae_vector_clear(&p->tau); + ae_matrix_clear(&p->r); + ae_vector_clear(&p->perm); +} + + +void _acbfbuffer_destroy(void* _p) +{ + acbfbuffer *p = (acbfbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->bflags); + _kdtreerequestbuffer_destroy(&p->kdtbuf); + _kdtreerequestbuffer_destroy(&p->kdt1buf); + _kdtreerequestbuffer_destroy(&p->kdt2buf); + ae_vector_destroy(&p->tmpboxmin); + ae_vector_destroy(&p->tmpboxmax); + ae_vector_destroy(&p->currentnodes); + ae_vector_destroy(&p->neighbors); + ae_vector_destroy(&p->chosenneighbors); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->z); + ae_vector_destroy(&p->d); + ae_matrix_destroy(&p->atwrk); + ae_matrix_destroy(&p->xq); + ae_matrix_destroy(&p->q); + ae_matrix_destroy(&p->q1); + ae_matrix_destroy(&p->wrkq); + ae_matrix_destroy(&p->b); + ae_matrix_destroy(&p->c); + ae_vector_destroy(&p->choltmp); + ae_vector_destroy(&p->tau); + ae_matrix_destroy(&p->r); + ae_vector_destroy(&p->perm); +} + + +void _acbfchunk_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + acbfchunk *p = (acbfchunk*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->targetrows, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->targetcols, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->s, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _acbfchunk_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + acbfchunk *dst = (acbfchunk*)_dst; + const acbfchunk *src = (const acbfchunk*)_src; + dst->ntargetrows = src->ntargetrows; + dst->ntargetcols = src->ntargetcols; + ae_vector_init_copy(&dst->targetrows, &src->targetrows, _state, make_automatic); + ae_vector_init_copy(&dst->targetcols, &src->targetcols, _state, make_automatic); + ae_matrix_init_copy(&dst->s, &src->s, _state, make_automatic); +} + + +void _acbfchunk_clear(void* _p) +{ + acbfchunk *p = (acbfchunk*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->targetrows); + ae_vector_clear(&p->targetcols); + ae_matrix_clear(&p->s); +} + + +void _acbfchunk_destroy(void* _p) +{ + acbfchunk *p = (acbfchunk*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->targetrows); + ae_vector_destroy(&p->targetcols); + ae_matrix_destroy(&p->s); +} + + +void _rbf3ddmbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmbuffer *p = (rbf3ddmbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->bflags, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->idx2preccol, 0, DT_INT, _state, make_automatic); + _kdtreerequestbuffer_init(&p->kdtbuf, _state, make_automatic); + ae_vector_init(&p->tmpboxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpboxmax, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3ddmbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmbuffer *dst = (rbf3ddmbuffer*)_dst; + const rbf3ddmbuffer *src = (const rbf3ddmbuffer*)_src; + ae_vector_init_copy(&dst->bflags, &src->bflags, _state, make_automatic); + ae_vector_init_copy(&dst->idx2preccol, &src->idx2preccol, _state, make_automatic); + _kdtreerequestbuffer_init_copy(&dst->kdtbuf, &src->kdtbuf, _state, make_automatic); + ae_vector_init_copy(&dst->tmpboxmin, &src->tmpboxmin, _state, make_automatic); + ae_vector_init_copy(&dst->tmpboxmax, &src->tmpboxmax, _state, make_automatic); +} + + +void _rbf3ddmbuffer_clear(void* _p) +{ + rbf3ddmbuffer *p = (rbf3ddmbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->bflags); + ae_vector_clear(&p->idx2preccol); + _kdtreerequestbuffer_clear(&p->kdtbuf); + ae_vector_clear(&p->tmpboxmin); + ae_vector_clear(&p->tmpboxmax); +} + + +void _rbf3ddmbuffer_destroy(void* _p) +{ + rbf3ddmbuffer *p = (rbf3ddmbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->bflags); + ae_vector_destroy(&p->idx2preccol); + _kdtreerequestbuffer_destroy(&p->kdtbuf); + ae_vector_destroy(&p->tmpboxmin); + ae_vector_destroy(&p->tmpboxmax); +} + + +void _rbf3ddmsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmsubproblem *p = (rbf3ddmsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->targetnodes, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->workingnodes, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->regsystem, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wrklu, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rhs, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->qtrhs, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sol, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->pred, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkp, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->wrkq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wrkr, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3ddmsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmsubproblem *dst = (rbf3ddmsubproblem*)_dst; + const rbf3ddmsubproblem *src = (const rbf3ddmsubproblem*)_src; + dst->isvalid = src->isvalid; + dst->ntarget = src->ntarget; + ae_vector_init_copy(&dst->targetnodes, &src->targetnodes, _state, make_automatic); + dst->nwork = src->nwork; + ae_vector_init_copy(&dst->workingnodes, &src->workingnodes, _state, make_automatic); + ae_matrix_init_copy(&dst->regsystem, &src->regsystem, _state, make_automatic); + dst->decomposition = src->decomposition; + ae_matrix_init_copy(&dst->wrklu, &src->wrklu, _state, make_automatic); + ae_matrix_init_copy(&dst->rhs, &src->rhs, _state, make_automatic); + ae_matrix_init_copy(&dst->qtrhs, &src->qtrhs, _state, make_automatic); + ae_matrix_init_copy(&dst->sol, &src->sol, _state, make_automatic); + ae_matrix_init_copy(&dst->pred, &src->pred, _state, make_automatic); + ae_vector_init_copy(&dst->wrkp, &src->wrkp, _state, make_automatic); + ae_matrix_init_copy(&dst->wrkq, &src->wrkq, _state, make_automatic); + ae_matrix_init_copy(&dst->wrkr, &src->wrkr, _state, make_automatic); +} + + +void _rbf3ddmsubproblem_clear(void* _p) +{ + rbf3ddmsubproblem *p = (rbf3ddmsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->targetnodes); + ae_vector_clear(&p->workingnodes); + ae_matrix_clear(&p->regsystem); + ae_matrix_clear(&p->wrklu); + ae_matrix_clear(&p->rhs); + ae_matrix_clear(&p->qtrhs); + ae_matrix_clear(&p->sol); + ae_matrix_clear(&p->pred); + ae_vector_clear(&p->wrkp); + ae_matrix_clear(&p->wrkq); + ae_matrix_clear(&p->wrkr); +} + + +void _rbf3ddmsubproblem_destroy(void* _p) +{ + rbf3ddmsubproblem *p = (rbf3ddmsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->targetnodes); + ae_vector_destroy(&p->workingnodes); + ae_matrix_destroy(&p->regsystem); + ae_matrix_destroy(&p->wrklu); + ae_matrix_destroy(&p->rhs); + ae_matrix_destroy(&p->qtrhs); + ae_matrix_destroy(&p->sol); + ae_matrix_destroy(&p->pred); + ae_vector_destroy(&p->wrkp); + ae_matrix_destroy(&p->wrkq); + ae_matrix_destroy(&p->wrkr); +} + + +void _rbf3ddmsolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmsolver *p = (rbf3ddmsolver*)_p; + ae_touch_ptr((void*)p); + _kdtree_init(&p->kdt, _state, make_automatic); + ae_shared_pool_init(&p->bufferpool, _state, make_automatic); + ae_shared_pool_init(&p->subproblemspool, _state, make_automatic); + ae_shared_pool_init(&p->subproblemsbuffer, _state, make_automatic); + ae_matrix_init(&p->corrq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->corrr, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->corrnodes, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->corrx, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpres1, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpupd1, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _rbf3ddmsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbf3ddmsolver *dst = (rbf3ddmsolver*)_dst; + const rbf3ddmsolver *src = (const rbf3ddmsolver*)_src; + dst->lambdav = src->lambdav; + _kdtree_init_copy(&dst->kdt, &src->kdt, _state, make_automatic); + ae_shared_pool_init_copy(&dst->bufferpool, &src->bufferpool, _state, make_automatic); + dst->subproblemscnt = src->subproblemscnt; + ae_shared_pool_init_copy(&dst->subproblemspool, &src->subproblemspool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->subproblemsbuffer, &src->subproblemsbuffer, _state, make_automatic); + dst->ncorrector = src->ncorrector; + ae_matrix_init_copy(&dst->corrq, &src->corrq, _state, make_automatic); + ae_matrix_init_copy(&dst->corrr, &src->corrr, _state, make_automatic); + ae_vector_init_copy(&dst->corrnodes, &src->corrnodes, _state, make_automatic); + ae_matrix_init_copy(&dst->corrx, &src->corrx, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpres1, &src->tmpres1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpupd1, &src->tmpupd1, _state, make_automatic); + dst->cntlu = src->cntlu; + dst->cntregqr = src->cntregqr; +} + + +void _rbf3ddmsolver_clear(void* _p) +{ + rbf3ddmsolver *p = (rbf3ddmsolver*)_p; + ae_touch_ptr((void*)p); + _kdtree_clear(&p->kdt); + ae_shared_pool_clear(&p->bufferpool); + ae_shared_pool_clear(&p->subproblemspool); + ae_shared_pool_clear(&p->subproblemsbuffer); + ae_matrix_clear(&p->corrq); + ae_matrix_clear(&p->corrr); + ae_vector_clear(&p->corrnodes); + ae_matrix_clear(&p->corrx); + ae_matrix_clear(&p->tmpres1); + ae_matrix_clear(&p->tmpupd1); +} + + +void _rbf3ddmsolver_destroy(void* _p) +{ + rbf3ddmsolver *p = (rbf3ddmsolver*)_p; + ae_touch_ptr((void*)p); + _kdtree_destroy(&p->kdt); + ae_shared_pool_destroy(&p->bufferpool); + ae_shared_pool_destroy(&p->subproblemspool); + ae_shared_pool_destroy(&p->subproblemsbuffer); + ae_matrix_destroy(&p->corrq); + ae_matrix_destroy(&p->corrr); + ae_vector_destroy(&p->corrnodes); + ae_matrix_destroy(&p->corrx); + ae_matrix_destroy(&p->tmpres1); + ae_matrix_destroy(&p->tmpupd1); +} + + +void _rbfv3model_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv3model *p = (rbfv3model*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pointindexes, 0, DT_INT, _state, make_automatic); + _rbf3evaluator_init(&p->evaluator, _state, make_automatic); + _rbf3fastevaluator_init(&p->fasteval, _state, make_automatic); + ae_matrix_init(&p->wchunked, 0, 0, DT_REAL, _state, make_automatic); + _rbfv3calcbuffer_init(&p->calcbuf, _state, make_automatic); +} + + +void _rbfv3model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv3model *dst = (rbfv3model*)_dst; + const rbfv3model *src = (const rbfv3model*)_src; + dst->ny = src->ny; + dst->nx = src->nx; + dst->bftype = src->bftype; + dst->bfparam = src->bfparam; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic); + ae_vector_init_copy(&dst->cw, &src->cw, _state, make_automatic); + ae_vector_init_copy(&dst->pointindexes, &src->pointindexes, _state, make_automatic); + dst->nc = src->nc; + _rbf3evaluator_init_copy(&dst->evaluator, &src->evaluator, _state, make_automatic); + _rbf3fastevaluator_init_copy(&dst->fasteval, &src->fasteval, _state, make_automatic); + ae_matrix_init_copy(&dst->wchunked, &src->wchunked, _state, make_automatic); + _rbfv3calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic); + dst->dbgregqrusedforddm = src->dbgregqrusedforddm; + dst->dbgworstfirstdecay = src->dbgworstfirstdecay; +} + + +void _rbfv3model_clear(void* _p) +{ + rbfv3model *p = (rbfv3model*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_matrix_clear(&p->v); + ae_vector_clear(&p->cw); + ae_vector_clear(&p->pointindexes); + _rbf3evaluator_clear(&p->evaluator); + _rbf3fastevaluator_clear(&p->fasteval); + ae_matrix_clear(&p->wchunked); + _rbfv3calcbuffer_clear(&p->calcbuf); +} + + +void _rbfv3model_destroy(void* _p) +{ + rbfv3model *p = (rbfv3model*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_matrix_destroy(&p->v); + ae_vector_destroy(&p->cw); + ae_vector_destroy(&p->pointindexes); + _rbf3evaluator_destroy(&p->evaluator); + _rbf3fastevaluator_destroy(&p->fasteval); + ae_matrix_destroy(&p->wchunked); + _rbfv3calcbuffer_destroy(&p->calcbuf); +} + + +void _rbfv3report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv3report *p = (rbfv3report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv3report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv3report *dst = (rbfv3report*)_dst; + const rbfv3report *src = (const rbfv3report*)_src; + dst->terminationtype = src->terminationtype; + dst->maxerror = src->maxerror; + dst->rmserror = src->rmserror; + dst->iterationscount = src->iterationscount; +} + + +void _rbfv3report_clear(void* _p) +{ + rbfv3report *p = (rbfv3report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv3report_destroy(void* _p) +{ + rbfv3report *p = (rbfv3report*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine calculates the value of the bilinear or bicubic spline at +the given point X. + +Input parameters: + C - 2D spline object. + Built by spline2dbuildbilinearv or spline2dbuildbicubicv. + X, Y- point + +Result: + S(x,y) + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +double spline2dcalc(const spline2dinterpolant* c, + double x, + double y, + ae_state *_state) +{ + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + double t; + double dt; + double u; + double du; + double y1; + double y2; + double y3; + double y4; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double result; + + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalc: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalc: X or Y contains NaN or Infinite value", _state); + if( c->d!=1 ) + { + result = (double)(0); + return result; + } + + /* + * Determine evaluation interval + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + t = (x-c->x.ptr.p_double[l])*dt; + ix = l; + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + u = (y-c->y.ptr.p_double[l])*du; + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + result = _state->v_nan; + return result; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[c->n*iy+ix]; + y2 = c->f.ptr.p_double[c->n*iy+(ix+1)]; + y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)]; + y4 = c->f.ptr.p_double[c->n*(iy+1)+ix]; + result = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + return result; + } + + /* + * Bicubic interpolation: + * * calculate Hermite basis for dimensions X and Y (variables T and U), + * here HTij means basis function whose I-th derivative has value 1 at T=J. + * Same for HUij. + * * after initial calculation, apply scaling by DT/DU to the basis + * * calculate using stored table of second derivatives + */ + ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state); + sfx = c->n*c->m; + sfy = 2*c->n*c->m; + sfxy = 3*c->n*c->m; + s1 = c->n*iy+ix; + s2 = c->n*iy+(ix+1); + s3 = c->n*(iy+1)+ix; + s4 = c->n*(iy+1)+(ix+1); + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + result = (double)(0); + result = result+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01; + result = result+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01; + result = result+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11; + result = result+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11; + return result; +} + + +/************************************************************************* +This subroutine calculates the value of a bilinear or bicubic spline and +its derivatives. + +Use Spline2DDiff2() if you need second derivatives Sxx and Syy. + +Input parameters: + C - spline interpolant. + X, Y- point + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2ddiff(const spline2dinterpolant* c, + double x, + double y, + double* f, + double* fx, + double* fy, + ae_state *_state) +{ + double t; + double dt; + double u; + double du; + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double v0; + double v1; + double v2; + double v3; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double dht00; + double dht01; + double dht10; + double dht11; + double dhu00; + double dhu01; + double dhu10; + double dhu11; + + *f = 0.0; + *fx = 0.0; + *fy = 0.0; + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state); + + /* + * Prepare F, dF/dX, dF/dY, d2F/dXdY + */ + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + if( c->d!=1 ) + { + return; + } + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + ix = l; + + /* + * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + *f = _state->v_nan; + *fx = _state->v_nan; + *fy = _state->v_nan; + return; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[c->n*iy+ix]; + y2 = c->f.ptr.p_double[c->n*iy+(ix+1)]; + y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)]; + y4 = c->f.ptr.p_double[c->n*(iy+1)+ix]; + *f = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + *fx = (-((double)1-u)*y1+((double)1-u)*y2+u*y3-u*y4)*dt; + *fy = (-((double)1-t)*y1-t*y2+t*y3+((double)1-t)*y4)*du; + return; + } + + /* + * Bicubic interpolation + */ + if( c->stype==-3 ) + { + sfx = c->n*c->m; + sfy = 2*c->n*c->m; + sfxy = 3*c->n*c->m; + s1 = c->n*iy+ix; + s2 = c->n*iy+(ix+1); + s3 = c->n*(iy+1)+ix; + s4 = c->n*(iy+1)+(ix+1); + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + dht00 = (double)6*t2-(double)6*t; + dht10 = (double)3*t2-(double)4*t+(double)1; + dht01 = -(double)6*t2+(double)6*t; + dht11 = (double)3*t2-(double)2*t; + dhu00 = (double)6*u2-(double)6*u; + dhu10 = (double)3*u2-(double)4*u+(double)1; + dhu01 = -(double)6*u2+(double)6*u; + dhu11 = (double)3*u2-(double)2*u; + dht00 = dht00*dt; + dht01 = dht01*dt; + dhu00 = dhu00*du; + dhu01 = dhu01*du; + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + v0 = c->f.ptr.p_double[s1]; + v1 = c->f.ptr.p_double[s2]; + v2 = c->f.ptr.p_double[s3]; + v3 = c->f.ptr.p_double[s4]; + *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01; + *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01; + *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01; + v0 = c->f.ptr.p_double[sfx+s1]; + v1 = c->f.ptr.p_double[sfx+s2]; + v2 = c->f.ptr.p_double[sfx+s3]; + v3 = c->f.ptr.p_double[sfx+s4]; + *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01; + *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01; + *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01; + v0 = c->f.ptr.p_double[sfy+s1]; + v1 = c->f.ptr.p_double[sfy+s2]; + v2 = c->f.ptr.p_double[sfy+s3]; + v3 = c->f.ptr.p_double[sfy+s4]; + *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11; + *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11; + *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11; + v0 = c->f.ptr.p_double[sfxy+s1]; + v1 = c->f.ptr.p_double[sfxy+s2]; + v2 = c->f.ptr.p_double[sfxy+s3]; + v3 = c->f.ptr.p_double[sfxy+s4]; + *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11; + *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11; + *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11; + return; + } +} + + +/************************************************************************* +This subroutine calculates the value of a bilinear or bicubic spline and +its second derivatives. + +Input parameters: + C - spline interpolant. + X, Y- point + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + FXX - d2S(x,y)/dXdX + FXY - d2S(x,y)/dXdY + FYY - d2S(x,y)/dYdY + + -- ALGLIB PROJECT -- + Copyright 17.04.2023 by Bochkanov Sergey. + + The second derivatives code was contributed by Horst Greiner under + public domain terms. +*************************************************************************/ +void spline2ddiff2(const spline2dinterpolant* c, + double x, + double y, + double* f, + double* fx, + double* fy, + double* fxx, + double* fxy, + double* fyy, + ae_state *_state) +{ + double t; + double dt; + double u; + double du; + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double v0; + double v1; + double v2; + double v3; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double dht00; + double dht01; + double dht10; + double dht11; + double dhu00; + double dhu01; + double dhu10; + double dhu11; + double d2ht00; + double d2ht01; + double d2ht10; + double d2ht11; + double d2hu00; + double d2hu01; + double d2hu10; + double d2hu11; + + *f = 0.0; + *fx = 0.0; + *fy = 0.0; + *fxx = 0.0; + *fxy = 0.0; + *fyy = 0.0; + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state); + + /* + * Prepare F, dF/dX, dF/dY, d2F/dXdY + */ + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + *fxx = (double)(0); + *fxy = (double)(0); + *fyy = (double)(0); + if( c->d!=1 ) + { + return; + } + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + ix = l; + + /* + * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + *f = _state->v_nan; + *fx = _state->v_nan; + *fy = _state->v_nan; + *fxx = _state->v_nan; + *fxy = _state->v_nan; + *fyy = _state->v_nan; + return; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[c->n*iy+ix]; + y2 = c->f.ptr.p_double[c->n*iy+(ix+1)]; + y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)]; + y4 = c->f.ptr.p_double[c->n*(iy+1)+ix]; + *f = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + *fx = (-((double)1-u)*y1+((double)1-u)*y2+u*y3-u*y4)*dt; + *fy = (-((double)1-t)*y1-t*y2+t*y3+((double)1-t)*y4)*du; + *fxx = (double)(0); + *fxy = (y1-y2+y3-y4)*du*dt; + *fyy = (double)(0); + return; + } + + /* + * Bicubic interpolation + */ + if( c->stype==-3 ) + { + sfx = c->n*c->m; + sfy = 2*c->n*c->m; + sfxy = 3*c->n*c->m; + s1 = c->n*iy+ix; + s2 = c->n*iy+(ix+1); + s3 = c->n*(iy+1)+ix; + s4 = c->n*(iy+1)+(ix+1); + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + dht00 = (double)6*t2-(double)6*t; + dht10 = (double)3*t2-(double)4*t+(double)1; + dht01 = -(double)6*t2+(double)6*t; + dht11 = (double)3*t2-(double)2*t; + dhu00 = (double)6*u2-(double)6*u; + dhu10 = (double)3*u2-(double)4*u+(double)1; + dhu01 = -(double)6*u2+(double)6*u; + dhu11 = (double)3*u2-(double)2*u; + dht00 = dht00*dt; + dht01 = dht01*dt; + dhu00 = dhu00*du; + dhu01 = dhu01*du; + d2ht00 = ((double)12*t-(double)6)*dt*dt; + d2ht01 = (-(double)12*t+(double)6)*dt*dt; + d2ht10 = ((double)6*t-(double)4)*dt; + d2ht11 = ((double)6*t-(double)2)*dt; + d2hu00 = ((double)12*u-(double)6)*du*du; + d2hu01 = (-(double)12*u+(double)6)*du*du; + d2hu10 = ((double)6*u-(double)4)*du; + d2hu11 = ((double)6*u-(double)2)*du; + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + *fxy = (double)(0); + v0 = c->f.ptr.p_double[s1]; + v1 = c->f.ptr.p_double[s2]; + v2 = c->f.ptr.p_double[s3]; + v3 = c->f.ptr.p_double[s4]; + *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01; + *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01; + *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01; + *fxx = *fxx+v0*d2ht00*hu00+v1*d2ht01*hu00+v2*d2ht00*hu01+v3*d2ht01*hu01; + *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01; + *fyy = *fyy+v0*ht00*d2hu00+v1*ht01*d2hu00+v2*ht00*d2hu01+v3*ht01*d2hu01; + v0 = c->f.ptr.p_double[sfx+s1]; + v1 = c->f.ptr.p_double[sfx+s2]; + v2 = c->f.ptr.p_double[sfx+s3]; + v3 = c->f.ptr.p_double[sfx+s4]; + *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01; + *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01; + *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01; + *fxx = *fxx+v0*d2ht10*hu00+v1*d2ht11*hu00+v2*d2ht10*hu01+v3*d2ht11*hu01; + *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01; + *fyy = *fyy+v0*ht10*d2hu00+v1*ht11*d2hu00+v2*ht10*d2hu01+v3*ht11*d2hu01; + v0 = c->f.ptr.p_double[sfy+s1]; + v1 = c->f.ptr.p_double[sfy+s2]; + v2 = c->f.ptr.p_double[sfy+s3]; + v3 = c->f.ptr.p_double[sfy+s4]; + *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11; + *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11; + *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11; + *fxx = *fxx+v0*d2ht00*hu10+v1*d2ht01*hu10+v2*d2ht00*hu11+v3*d2ht01*hu11; + *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11; + *fyy = *fyy+v0*ht00*d2hu10+v1*ht01*d2hu10+v2*ht00*d2hu11+v3*ht01*d2hu11; + v0 = c->f.ptr.p_double[sfxy+s1]; + v1 = c->f.ptr.p_double[sfxy+s2]; + v2 = c->f.ptr.p_double[sfxy+s3]; + v3 = c->f.ptr.p_double[sfxy+s4]; + *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11; + *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11; + *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11; + *fxx = *fxx+v0*d2ht10*hu10+v1*d2ht11*hu10+v2*d2ht10*hu11+v3*d2ht11*hu11; + *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11; + *fyy = *fyy+v0*ht10*d2hu10+v1*ht11*d2hu10+v2*ht10*d2hu11+v3*ht11*d2hu11; + return; + } +} + + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y). + +If you need just some specific component of vector-valued spline, you can +use spline2dcalcvi() function. + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + F - output buffer, possibly preallocated array. In case array size + is large enough to store result, it is not reallocated. Array + which is too short will be reallocated + +OUTPUT PARAMETERS: + F - array[D] (or larger) which stores function values + + -- ALGLIB PROJECT -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dcalcvbuf(const spline2dinterpolant* c, + double x, + double y, + /* Real */ ae_vector* f, + ae_state *_state) +{ + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t i; + double t; + double dt; + double u; + double du; + double y1; + double y2; + double y3; + double y4; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVBuf: X or Y contains NaN or Infinite value", _state); + + /* + * Allocate place for output + */ + rvectorsetlengthatleast(f, c->d, _state); + + /* + * Determine evaluation interval + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + t = (x-c->x.ptr.p_double[l])*dt; + ix = l; + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + u = (y-c->y.ptr.p_double[l])*du; + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + rsetv(c->d, _state->v_nan, f, _state); + return; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + for(i=0; i<=c->d-1; i++) + { + y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i]; + y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i]; + y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i]; + y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i]; + f->ptr.p_double[i] = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + } + return; + } + + /* + * Bicubic interpolation: + * * calculate Hermite basis for dimensions X and Y (variables T and U), + * here HTij means basis function whose I-th derivative has value 1 at T=J. + * Same for HUij. + * * after initial calculation, apply scaling by DT/DU to the basis + * * calculate using stored table of second derivatives + */ + ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state); + sfx = c->n*c->m*c->d; + sfy = 2*c->n*c->m*c->d; + sfxy = 3*c->n*c->m*c->d; + s1 = (c->n*iy+ix)*c->d; + s2 = (c->n*iy+(ix+1))*c->d; + s3 = (c->n*(iy+1)+ix)*c->d; + s4 = (c->n*(iy+1)+(ix+1))*c->d; + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + for(i=0; i<=c->d-1; i++) + { + + /* + * Calculate I-th component + */ + f->ptr.p_double[i] = (double)(0); + f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01; + f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01; + f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11; + f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11; + + /* + * Advance source indexes + */ + s1 = s1+1; + s2 = s2+1; + s3 = s3+1; + s4 = s4+1; + } +} + + +/************************************************************************* +This subroutine calculates specific component of vector-valued bilinear or +bicubic spline at the given point (X,Y). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + I - component index, in [0,D). An exception is generated for out + of range values. + +RESULT: + value of I-th component + + -- ALGLIB PROJECT -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +double spline2dcalcvi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + ae_state *_state) +{ + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + double t; + double dt; + double u; + double du; + double y1; + double y2; + double y3; + double y4; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double result; + + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVi: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVi: X or Y contains NaN or Infinite value", _state); + ae_assert(i>=0&&id, "Spline2DCalcVi: incorrect I (I<0 or I>=D)", _state); + + /* + * Determine evaluation interval + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + t = (x-c->x.ptr.p_double[l])*dt; + ix = l; + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + u = (y-c->y.ptr.p_double[l])*du; + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + result = _state->v_nan; + return result; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i]; + y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i]; + y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i]; + y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i]; + result = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + return result; + } + + /* + * Bicubic interpolation: + * * calculate Hermite basis for dimensions X and Y (variables T and U), + * here HTij means basis function whose I-th derivative has value 1 at T=J. + * Same for HUij. + * * after initial calculation, apply scaling by DT/DU to the basis + * * calculate using stored table of second derivatives + */ + ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state); + sfx = c->n*c->m*c->d; + sfy = 2*c->n*c->m*c->d; + sfxy = 3*c->n*c->m*c->d; + s1 = (c->n*iy+ix)*c->d; + s2 = (c->n*iy+(ix+1))*c->d; + s3 = (c->n*(iy+1)+ix)*c->d; + s4 = (c->n*(iy+1)+(ix+1))*c->d; + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + + /* + * Advance source indexes to I-th position + */ + s1 = s1+i; + s2 = s2+i; + s3 = s3+i; + s4 = s4+i; + + /* + * Calculate I-th component + */ + result = (double)(0); + result = result+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01; + result = result+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01; + result = result+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11; + result = result+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11; + return result; +} + + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y- point + +OUTPUT PARAMETERS: + F - array[D] which stores function values. F is out-parameter and + it is reallocated after call to this function. In case you + want to reuse previously allocated F, you may use + Spline2DCalcVBuf(), which reallocates F only when it is too + small. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dcalcv(const spline2dinterpolant* c, + double x, + double y, + /* Real */ ae_vector* f, + ae_state *_state) +{ + + ae_vector_clear(f); + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcV: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcV: either X=NaN/Infinite or Y=NaN/Infinite", _state); + spline2dcalcvbuf(c, x, y, f, _state); +} + + +/************************************************************************* +This subroutine calculates the value and the derivatives of I-th component +of a vector-valued bilinear or bicubic spline. + +Input parameters: + C - spline interpolant. + X, Y- point + I - component index, in [0,D) + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2ddiffvi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + double* f, + double* fx, + double* fy, + ae_state *_state) +{ + ae_int_t d; + double t; + double dt; + double u; + double du; + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double v0; + double v1; + double v2; + double v3; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double dht00; + double dht01; + double dht10; + double dht11; + double dhu00; + double dhu01; + double dhu10; + double dhu11; + + *f = 0.0; + *fx = 0.0; + *fy = 0.0; + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiffVI: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiffVI: X or Y contains NaN or Infinite value", _state); + ae_assert(i>=0&&id, "Spline2DDiffVI: I<0 or I>=D", _state); + + /* + * Prepare F, dF/dX, dF/dY, d2F/dXdY + */ + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + d = c->d; + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + ix = l; + + /* + * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + *f = _state->v_nan; + *fx = _state->v_nan; + *fy = _state->v_nan; + return; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[d*(c->n*iy+ix)+i]; + y2 = c->f.ptr.p_double[d*(c->n*iy+(ix+1))+i]; + y3 = c->f.ptr.p_double[d*(c->n*(iy+1)+(ix+1))+i]; + y4 = c->f.ptr.p_double[d*(c->n*(iy+1)+ix)+i]; + *f = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + *fx = (-((double)1-u)*y1+((double)1-u)*y2+u*y3-u*y4)*dt; + *fy = (-((double)1-t)*y1-t*y2+t*y3+((double)1-t)*y4)*du; + return; + } + + /* + * Bicubic interpolation + */ + if( c->stype==-3 ) + { + sfx = c->n*c->m*d; + sfy = 2*c->n*c->m*d; + sfxy = 3*c->n*c->m*d; + s1 = d*(c->n*iy+ix)+i; + s2 = d*(c->n*iy+(ix+1))+i; + s3 = d*(c->n*(iy+1)+ix)+i; + s4 = d*(c->n*(iy+1)+(ix+1))+i; + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + dht00 = (double)6*t2-(double)6*t; + dht10 = (double)3*t2-(double)4*t+(double)1; + dht01 = -(double)6*t2+(double)6*t; + dht11 = (double)3*t2-(double)2*t; + dhu00 = (double)6*u2-(double)6*u; + dhu10 = (double)3*u2-(double)4*u+(double)1; + dhu01 = -(double)6*u2+(double)6*u; + dhu11 = (double)3*u2-(double)2*u; + dht00 = dht00*dt; + dht01 = dht01*dt; + dhu00 = dhu00*du; + dhu01 = dhu01*du; + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + v0 = c->f.ptr.p_double[s1]; + v1 = c->f.ptr.p_double[s2]; + v2 = c->f.ptr.p_double[s3]; + v3 = c->f.ptr.p_double[s4]; + *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01; + *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01; + *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01; + v0 = c->f.ptr.p_double[sfx+s1]; + v1 = c->f.ptr.p_double[sfx+s2]; + v2 = c->f.ptr.p_double[sfx+s3]; + v3 = c->f.ptr.p_double[sfx+s4]; + *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01; + *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01; + *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01; + v0 = c->f.ptr.p_double[sfy+s1]; + v1 = c->f.ptr.p_double[sfy+s2]; + v2 = c->f.ptr.p_double[sfy+s3]; + v3 = c->f.ptr.p_double[sfy+s4]; + *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11; + *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11; + *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11; + v0 = c->f.ptr.p_double[sfxy+s1]; + v1 = c->f.ptr.p_double[sfxy+s2]; + v2 = c->f.ptr.p_double[sfxy+s3]; + v3 = c->f.ptr.p_double[sfxy+s4]; + *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11; + *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11; + *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11; + return; + } +} + + +/************************************************************************* +This subroutine calculates the value and the derivatives of I-th component +of a vector-valued bilinear or bicubic spline. + +Input parameters: + C - spline interpolant. + X, Y- point + I - component index, in [0,D) + +Output parameters: + F - S(x,y) + FX - dS(x,y)/dX + FY - dS(x,y)/dY + FXX - d2S(x,y)/dXdX + FXY - d2S(x,y)/dXdY + FYY - d2S(x,y)/dYdY + + -- ALGLIB PROJECT -- + Copyright 17.04.2023 by Bochkanov Sergey. + + The second derivatives code was contributed by Horst Greiner under + public domain terms. +*************************************************************************/ +void spline2ddiff2vi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + double* f, + double* fx, + double* fy, + double* fxx, + double* fxy, + double* fyy, + ae_state *_state) +{ + ae_int_t d; + double t; + double dt; + double u; + double du; + ae_int_t ix; + ae_int_t iy; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double v0; + double v1; + double v2; + double v3; + double t2; + double t3; + double u2; + double u3; + double ht00; + double ht01; + double ht10; + double ht11; + double hu00; + double hu01; + double hu10; + double hu11; + double dht00; + double dht01; + double dht10; + double dht11; + double dhu00; + double dhu01; + double dhu10; + double dhu11; + double d2ht00; + double d2ht01; + double d2ht10; + double d2ht11; + double d2hu00; + double d2hu01; + double d2hu10; + double d2hu11; + + *f = 0.0; + *fx = 0.0; + *fy = 0.0; + *fxx = 0.0; + *fxy = 0.0; + *fyy = 0.0; + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiffVI: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiffVI: X or Y contains NaN or Infinite value", _state); + ae_assert(i>=0&&id, "Spline2DDiffVI: I<0 or I>=D", _state); + + /* + * Prepare F, dF/dX, dF/dY, d2F/dXdY + */ + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + *fxx = (double)(0); + *fxy = (double)(0); + *fyy = (double)(0); + d = c->d; + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]); + ix = l; + + /* + * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]); + iy = l; + + /* + * Handle possible missing cells + */ + if( c->hasmissingcells&&!spline2d_adjustevaluationinterval(c, &x, &t, &dt, &ix, &y, &u, &du, &iy, _state) ) + { + *f = _state->v_nan; + *fx = _state->v_nan; + *fy = _state->v_nan; + *fxx = _state->v_nan; + *fxy = _state->v_nan; + *fyy = _state->v_nan; + return; + } + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + y1 = c->f.ptr.p_double[d*(c->n*iy+ix)+i]; + y2 = c->f.ptr.p_double[d*(c->n*iy+(ix+1))+i]; + y3 = c->f.ptr.p_double[d*(c->n*(iy+1)+(ix+1))+i]; + y4 = c->f.ptr.p_double[d*(c->n*(iy+1)+ix)+i]; + *f = ((double)1-t)*((double)1-u)*y1+t*((double)1-u)*y2+t*u*y3+((double)1-t)*u*y4; + *fx = (-((double)1-u)*y1+((double)1-u)*y2+u*y3-u*y4)*dt; + *fy = (-((double)1-t)*y1-t*y2+t*y3+((double)1-t)*y4)*du; + *fxx = (double)(0); + *fxy = (y1-y2+y3-y4)*du*dt; + *fyy = (double)(0); + return; + } + + /* + * Bicubic interpolation + */ + if( c->stype==-3 ) + { + sfx = c->n*c->m*d; + sfy = 2*c->n*c->m*d; + sfxy = 3*c->n*c->m*d; + s1 = d*(c->n*iy+ix)+i; + s2 = d*(c->n*iy+(ix+1))+i; + s3 = d*(c->n*(iy+1)+ix)+i; + s4 = d*(c->n*(iy+1)+(ix+1))+i; + t2 = t*t; + t3 = t*t2; + u2 = u*u; + u3 = u*u2; + ht00 = (double)2*t3-(double)3*t2+(double)1; + ht10 = t3-(double)2*t2+t; + ht01 = -(double)2*t3+(double)3*t2; + ht11 = t3-t2; + hu00 = (double)2*u3-(double)3*u2+(double)1; + hu10 = u3-(double)2*u2+u; + hu01 = -(double)2*u3+(double)3*u2; + hu11 = u3-u2; + ht10 = ht10/dt; + ht11 = ht11/dt; + hu10 = hu10/du; + hu11 = hu11/du; + dht00 = (double)6*t2-(double)6*t; + dht10 = (double)3*t2-(double)4*t+(double)1; + dht01 = -(double)6*t2+(double)6*t; + dht11 = (double)3*t2-(double)2*t; + dhu00 = (double)6*u2-(double)6*u; + dhu10 = (double)3*u2-(double)4*u+(double)1; + dhu01 = -(double)6*u2+(double)6*u; + dhu11 = (double)3*u2-(double)2*u; + dht00 = dht00*dt; + dht01 = dht01*dt; + dhu00 = dhu00*du; + dhu01 = dhu01*du; + d2ht00 = ((double)12*t-(double)6)*dt*dt; + d2ht01 = (-(double)12*t+(double)6)*dt*dt; + d2ht10 = ((double)6*t-(double)4)*dt; + d2ht11 = ((double)6*t-(double)2)*dt; + d2hu00 = ((double)12*u-(double)6)*du*du; + d2hu01 = (-(double)12*u+(double)6)*du*du; + d2hu10 = ((double)6*u-(double)4)*du; + d2hu11 = ((double)6*u-(double)2)*du; + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + *fxy = (double)(0); + v0 = c->f.ptr.p_double[s1]; + v1 = c->f.ptr.p_double[s2]; + v2 = c->f.ptr.p_double[s3]; + v3 = c->f.ptr.p_double[s4]; + *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01; + *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01; + *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01; + *fxx = *fxx+v0*d2ht00*hu00+v1*d2ht01*hu00+v2*d2ht00*hu01+v3*d2ht01*hu01; + *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01; + *fyy = *fyy+v0*ht00*d2hu00+v1*ht01*d2hu00+v2*ht00*d2hu01+v3*ht01*d2hu01; + v0 = c->f.ptr.p_double[sfx+s1]; + v1 = c->f.ptr.p_double[sfx+s2]; + v2 = c->f.ptr.p_double[sfx+s3]; + v3 = c->f.ptr.p_double[sfx+s4]; + *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01; + *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01; + *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01; + *fxx = *fxx+v0*d2ht10*hu00+v1*d2ht11*hu00+v2*d2ht10*hu01+v3*d2ht11*hu01; + *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01; + *fyy = *fyy+v0*ht10*d2hu00+v1*ht11*d2hu00+v2*ht10*d2hu01+v3*ht11*d2hu01; + v0 = c->f.ptr.p_double[sfy+s1]; + v1 = c->f.ptr.p_double[sfy+s2]; + v2 = c->f.ptr.p_double[sfy+s3]; + v3 = c->f.ptr.p_double[sfy+s4]; + *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11; + *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11; + *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11; + *fxx = *fxx+v0*d2ht00*hu10+v1*d2ht01*hu10+v2*d2ht00*hu11+v3*d2ht01*hu11; + *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11; + *fyy = *fyy+v0*ht00*d2hu10+v1*ht01*d2hu10+v2*ht00*d2hu11+v3*ht01*d2hu11; + v0 = c->f.ptr.p_double[sfxy+s1]; + v1 = c->f.ptr.p_double[sfxy+s2]; + v2 = c->f.ptr.p_double[sfxy+s3]; + v3 = c->f.ptr.p_double[sfxy+s4]; + *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11; + *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11; + *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11; + *fxx = *fxx+v0*d2ht10*hu10+v1*d2ht11*hu10+v2*d2ht10*hu11+v3*d2ht11*hu11; + *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11; + *fyy = *fyy+v0*ht10*d2hu10+v1*ht11*d2hu10+v2*ht10*d2hu11+v3*ht11*d2hu11; + return; + } +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +Input parameters: + C - spline interpolant + AX, BX - transformation coefficients: x = A*t + B + AY, BY - transformation coefficients: y = A*u + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dlintransxy(spline2dinterpolant* c, + double ax, + double bx, + double ay, + double by, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector f; + ae_vector dfdx; + ae_vector dfdy; + ae_vector d2fdxdy; + ae_vector v; + ae_vector missing; + ae_bool missingv; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double s; + double dsdx; + double dsdy; + double d2sdx2; + double d2sdxdy; + double d2sdy2; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&f, 0, sizeof(f)); + memset(&dfdx, 0, sizeof(dfdx)); + memset(&dfdy, 0, sizeof(dfdy)); + memset(&d2fdxdy, 0, sizeof(d2fdxdy)); + memset(&v, 0, sizeof(v)); + memset(&missing, 0, sizeof(missing)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&f, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dfdx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dfdy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d2fdxdy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&missing, 0, DT_BOOL, _state, ae_true); + + ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransXY: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(ax, _state), "Spline2DLinTransXY: AX is infinite or NaN", _state); + ae_assert(ae_isfinite(bx, _state), "Spline2DLinTransXY: BX is infinite or NaN", _state); + ae_assert(ae_isfinite(ay, _state), "Spline2DLinTransXY: AY is infinite or NaN", _state); + ae_assert(ae_isfinite(by, _state), "Spline2DLinTransXY: BY is infinite or NaN", _state); + ae_vector_set_length(&x, c->n, _state); + ae_vector_set_length(&y, c->m, _state); + ae_vector_set_length(&f, c->m*c->n*c->d, _state); + ae_vector_set_length(&dfdx, c->m*c->n*c->d, _state); + ae_vector_set_length(&dfdy, c->m*c->n*c->d, _state); + ae_vector_set_length(&d2fdxdy, c->m*c->n*c->d, _state); + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = c->x.ptr.p_double[j]; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = c->y.ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + for(k=0; k<=c->d-1; k++) + { + f.ptr.p_double[c->d*(i*c->n+j)+k] = c->f.ptr.p_double[c->d*(i*c->n+j)+k]; + } + } + } + + /* + * Handle different combinations of AX/AY + */ + bsetallocv(c->n*c->m, ae_false, &missing, _state); + if( ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) ) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + missingv = ae_false; + for(k=0; k<=c->d-1; k++) + { + spline2ddiff2vi(c, bx, y.ptr.p_double[i], k, &s, &dsdx, &dsdy, &d2sdx2, &d2sdxdy, &d2sdy2, _state); + f.ptr.p_double[c->d*(i*c->n+j)+k] = s; + dfdx.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + dfdy.ptr.p_double[c->d*(i*c->n+j)+k] = ay*dsdy; + d2fdxdy.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + missingv = missingv||!ae_isfinite(s, _state); + } + missing.ptr.p_bool[i*c->n+j] = missingv; + } + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; + } + } + if( ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) ) + { + for(j=0; j<=c->n-1; j++) + { + for(i=0; i<=c->m-1; i++) + { + missingv = ae_false; + for(k=0; k<=c->d-1; k++) + { + spline2ddiff2vi(c, x.ptr.p_double[j], by, k, &s, &dsdx, &dsdy, &d2sdx2, &d2sdxdy, &d2sdy2, _state); + f.ptr.p_double[c->d*(i*c->n+j)+k] = s; + dfdx.ptr.p_double[c->d*(i*c->n+j)+k] = ax*dsdx; + dfdy.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + d2fdxdy.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + missingv = missingv||!ae_isfinite(s, _state); + } + missing.ptr.p_bool[i*c->n+j] = missingv; + } + } + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; + } + } + if( ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) ) + { + for(j=0; j<=c->n-1; j++) + { + for(i=0; i<=c->m-1; i++) + { + missingv = ae_false; + for(k=0; k<=c->d-1; k++) + { + spline2ddiff2vi(c, x.ptr.p_double[j], y.ptr.p_double[i], k, &s, &dsdx, &dsdy, &d2sdx2, &d2sdxdy, &d2sdy2, _state); + f.ptr.p_double[c->d*(i*c->n+j)+k] = s; + dfdx.ptr.p_double[c->d*(i*c->n+j)+k] = ax*dsdx; + dfdy.ptr.p_double[c->d*(i*c->n+j)+k] = ay*dsdy; + d2fdxdy.ptr.p_double[c->d*(i*c->n+j)+k] = ax*ay*d2sdxdy; + missingv = missingv||!ae_isfinite(s, _state); + } + missing.ptr.p_bool[i*c->n+j] = missingv; + } + } + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; + } + } + if( ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) ) + { + spline2dcalcvbuf(c, bx, by, &v, _state); + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + for(k=0; k<=c->d-1; k++) + { + f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k]; + dfdx.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + dfdy.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + d2fdxdy.ptr.p_double[c->d*(i*c->n+j)+k] = (double)(0); + } + } + } + bsetv(c->n*c->m, !ae_isfinite(v.ptr.p_double[0], _state), &missing, _state); + } + + /* + * Rebuild spline + */ + if( !c->hasmissingcells ) + { + if( c->stype==-3 ) + { + spline2d_spline2dbuildhermitevbuf(&x, c->n, &y, c->m, &f, &dfdx, &dfdy, &d2fdxdy, c->d, c, _state); + } + if( c->stype==-1 ) + { + spline2dbuildbilinearvbuf(&x, c->n, &y, c->m, &f, c->d, c, _state); + } + } + else + { + if( c->stype==-3 ) + { + spline2dbuildbicubicmissingbuf(&x, c->n, &y, c->m, &f, &missing, c->d, c, _state); + } + if( c->stype==-1 ) + { + spline2dbuildbilinearmissingbuf(&x, c->n, &y, c->m, &f, &missing, c->d, c, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +Input parameters: + C - spline interpolant. + A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B + +Output parameters: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dlintransf(spline2dinterpolant* c, + double a, + double b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector f; + ae_vector missing; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&f, 0, sizeof(f)); + memset(&missing, 0, sizeof(missing)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&f, 0, DT_REAL, _state, ae_true); + ae_vector_init(&missing, 0, DT_BOOL, _state, ae_true); + + ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransF: incorrect C (incorrect parameter C.SType)", _state); + if( c->stype==-1 ) + { + + /* + * Bilinear spline + */ + if( !c->hasmissingcells ) + { + + /* + * Quick code for a spline without missing cells + */ + for(i=0; i<=c->m*c->n*c->d-1; i++) + { + c->f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; + } + } + else + { + + /* + * Slower code for missing cells + */ + for(i=0; i<=c->m*c->n*c->d-1; i++) + { + if( !c->ismissingnode.ptr.p_bool[i/c->d] ) + { + c->f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; + } + } + } + } + else + { + + /* + * Bicubic spline + */ + if( !c->hasmissingcells ) + { + + /* + * Quick code for a spline without missing cells + */ + for(i=0; i<=c->m*c->n*c->d-1; i++) + { + c->f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; + } + for(i=c->m*c->n*c->d; i<=4*c->m*c->n*c->d-1; i++) + { + c->f.ptr.p_double[i] = a*c->f.ptr.p_double[i]; + } + } + else + { + + /* + * Slower code for missing cells + */ + ae_vector_set_length(&x, c->n, _state); + ae_vector_set_length(&y, c->m, _state); + rsetallocv(c->m*c->n*c->d, 0.0, &f, _state); + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = c->x.ptr.p_double[j]; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = c->y.ptr.p_double[i]; + } + for(i=0; i<=c->m*c->n*c->d-1; i++) + { + if( !c->ismissingnode.ptr.p_bool[i/c->d] ) + { + f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; + } + } + bcopyallocv(c->m*c->n, &c->ismissingnode, &missing, _state); + spline2dbuildbicubicmissingbuf(&x, c->n, &y, c->m, &f, &missing, c->d, c, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine makes the copy of the spline model. + +Input parameters: + C - spline interpolant + +Output parameters: + CC - spline copy + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dcopy(const spline2dinterpolant* c, + spline2dinterpolant* cc, + ae_state *_state) +{ + ae_int_t tblsize; + + _spline2dinterpolant_clear(cc); + + ae_assert(c->stype==-1||c->stype==-3, "Spline2DCopy: incorrect C (incorrect parameter C.SType)", _state); + cc->n = c->n; + cc->m = c->m; + cc->d = c->d; + cc->stype = c->stype; + cc->hasmissingcells = c->hasmissingcells; + tblsize = -1; + if( c->stype==-3 ) + { + tblsize = 4*c->n*c->m*c->d; + } + if( c->stype==-1 ) + { + tblsize = c->n*c->m*c->d; + } + ae_assert(tblsize>0, "Spline2DCopy: internal error", _state); + ae_vector_set_length(&cc->x, cc->n, _state); + ae_vector_set_length(&cc->y, cc->m, _state); + ae_vector_set_length(&cc->f, tblsize, _state); + ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); + ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); + ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); + if( c->hasmissingcells ) + { + bcopyallocv(c->n*c->m, &c->ismissingnode, &cc->ismissingnode, _state); + bcopyallocv((c->n-1)*(c->m-1), &c->ismissingcell, &cc->ismissingcell, _state); + } +} + + +/************************************************************************* +Bicubic spline resampling + +Input parameters: + A - function values at the old grid, + array[0..OldHeight-1, 0..OldWidth-1] + OldHeight - old grid height, OldHeight>1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 15 May, 2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebicubic(/* Real */ const ae_matrix* a, + ae_int_t oldheight, + ae_int_t oldwidth, + /* Real */ ae_matrix* b, + ae_int_t newheight, + ae_int_t newwidth, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix buf; + ae_vector x; + ae_vector y; + spline1dinterpolant c; + ae_int_t mw; + ae_int_t mh; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&c, 0, sizeof(c)); + ae_matrix_clear(b); + ae_matrix_init(&buf, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + _spline1dinterpolant_init(&c, _state, ae_true); + + ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); + ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBicubic: width/height less than 1", _state); + + /* + * Prepare + */ + mw = ae_maxint(oldwidth, newwidth, _state); + mh = ae_maxint(oldheight, newheight, _state); + ae_matrix_set_length(b, newheight, newwidth, _state); + ae_matrix_set_length(&buf, oldheight, newwidth, _state); + ae_vector_set_length(&x, ae_maxint(mw, mh, _state), _state); + ae_vector_set_length(&y, ae_maxint(mw, mh, _state), _state); + + /* + * Horizontal interpolation + */ + for(i=0; i<=oldheight-1; i++) + { + + /* + * Fill X, Y + */ + for(j=0; j<=oldwidth-1; j++) + { + x.ptr.p_double[j] = (double)j/(double)(oldwidth-1); + y.ptr.p_double[j] = a->ptr.pp_double[i][j]; + } + + /* + * Interpolate and place result into temporary matrix + */ + spline1dbuildcubic(&x, &y, oldwidth, 0, 0.0, 0, 0.0, &c, _state); + for(j=0; j<=newwidth-1; j++) + { + buf.ptr.pp_double[i][j] = spline1dcalc(&c, (double)j/(double)(newwidth-1), _state); + } + } + + /* + * Vertical interpolation + */ + for(j=0; j<=newwidth-1; j++) + { + + /* + * Fill X, Y + */ + for(i=0; i<=oldheight-1; i++) + { + x.ptr.p_double[i] = (double)i/(double)(oldheight-1); + y.ptr.p_double[i] = buf.ptr.pp_double[i][j]; + } + + /* + * Interpolate and place result into B + */ + spline1dbuildcubic(&x, &y, oldheight, 0, 0.0, 0, 0.0, &c, _state); + for(i=0; i<=newheight-1; i++) + { + b->ptr.pp_double[i][j] = spline1dcalc(&c, (double)i/(double)(newheight-1), _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Bilinear spline resampling + +Input parameters: + A - function values at the old grid, + array[0..OldHeight-1, 0..OldWidth-1] + OldHeight - old grid height, OldHeight>1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 09.07.2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebilinear(/* Real */ const ae_matrix* a, + ae_int_t oldheight, + ae_int_t oldwidth, + /* Real */ ae_matrix* b, + ae_int_t newheight, + ae_int_t newwidth, + ae_state *_state) +{ + ae_int_t l; + ae_int_t c; + double t; + double u; + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(b); + + ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); + ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBilinear: width/height less than 1", _state); + ae_matrix_set_length(b, newheight, newwidth, _state); + for(i=0; i<=newheight-1; i++) + { + for(j=0; j<=newwidth-1; j++) + { + l = i*(oldheight-1)/(newheight-1); + if( l==oldheight-1 ) + { + l = oldheight-2; + } + u = (double)i/(double)(newheight-1)*(double)(oldheight-1)-(double)l; + c = j*(oldwidth-1)/(newwidth-1); + if( c==oldwidth-1 ) + { + c = oldwidth-2; + } + t = (double)(j*(oldwidth-1))/(double)(newwidth-1)-(double)c; + b->ptr.pp_double[i][j] = ((double)1-t)*((double)1-u)*a->ptr.pp_double[l][c]+t*((double)1-u)*a->ptr.pp_double[l][c+1]+t*u*a->ptr.pp_double[l+1][c+1]+((double)1-t)*u*a->ptr.pp_double[l+1][c]; + } + } +} + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + + _spline2dinterpolant_clear(c); + + spline2dbuildbilinearvbuf(x, n, y, m, f, d, c, _state); +} + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +Buffered version of Spline2DBuildBilinearV() which reuses memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearvbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + double t; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + + + ae_assert(n>=2, "Spline2DBuildBilinearV: N is less then 2", _state); + ae_assert(m>=2, "Spline2DBuildBilinearV: M is less then 2", _state); + ae_assert(d>=1, "Spline2DBuildBilinearV: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearV: length of X or Y is too short (Length(X/Y)cnt>=k, "Spline2DBuildBilinearV: length of F is too short (Length(F)n = n; + c->m = m; + c->d = d; + c->stype = -1; + c->hasmissingcells = ae_false; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, k, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + c->f.ptr.p_double[i] = f->ptr.p_double[i]; + } + + /* + * Sort points + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t; + } + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t; + } + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } +} + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissing(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + ae_vector_init_copy(&f, _f, _state, ae_true); + _spline2dinterpolant_clear(c); + + spline2dbuildbilinearmissingbuf(x, n, y, m, &f, missing, d, c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBilinearMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissingbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + double t; + ae_bool tb; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + ae_vector_init_copy(&f, _f, _state, ae_true); + + ae_assert(n>=2, "Spline2DBuildBilinearMissing: N is less then 2", _state); + ae_assert(m>=2, "Spline2DBuildBilinearMissing: M is less then 2", _state); + ae_assert(d>=1, "Spline2DBuildBilinearMissing: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearMissing: length of X or Y is too short (Length(X/Y)=k, "Spline2DBuildBilinearMissing: length of F is too short (Length(F)cnt>=n*m, "Spline2DBuildBilinearMissing: Missing[] is shorter than M*N", _state); + for(i=0; i<=k-1; i++) + { + if( !missing->ptr.p_bool[i/d]&&!ae_isfinite(f.ptr.p_double[i], _state) ) + { + ae_assert(ae_false, "Spline2DBuildBilinearMissing: F[] contains NAN or INF in its non-missing entries", _state); + } + } + + /* + * Fill interpolant. + * + * NOTE: we make sure that missing entries of F[] are filled by zeros. + */ + c->n = n; + c->m = m; + c->d = d; + c->stype = -1; + c->hasmissingcells = ae_true; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + rsetallocv(k, 0.0, &c->f, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + if( !missing->ptr.p_bool[i/d] ) + { + c->f.ptr.p_double[i] = f.ptr.p_double[i]; + } + } + bcopyallocv(c->n*c->m, missing, &c->ismissingnode, _state); + + /* + * Sort points + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t; + } + tb = c->ismissingnode.ptr.p_bool[i*c->n+j]; + c->ismissingnode.ptr.p_bool[i*c->n+j] = c->ismissingnode.ptr.p_bool[i*c->n+k]; + c->ismissingnode.ptr.p_bool[i*c->n+k] = tb; + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t; + } + tb = c->ismissingnode.ptr.p_bool[i*c->n+j]; + c->ismissingnode.ptr.p_bool[i*c->n+j] = c->ismissingnode.ptr.p_bool[k*c->n+j]; + c->ismissingnode.ptr.p_bool[k*c->n+j] = tb; + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } + + /* + * 1. Determine cells that are not missing. A cell is non-missing if it has four non-missing + * nodes at its corners. + * 2. Normalize IsMissingNode[] array - all isolated points that are not part of some non-missing + * cell are marked as missing too + */ + bsetallocv((c->m-1)*(c->n-1), ae_true, &c->ismissingcell, _state); + for(i=0; i<=c->m-2; i++) + { + for(j=0; j<=c->n-2; j++) + { + if( ((!c->ismissingnode.ptr.p_bool[i*c->n+j]&&!c->ismissingnode.ptr.p_bool[(i+1)*c->n+j])&&!c->ismissingnode.ptr.p_bool[i*c->n+(j+1)])&&!c->ismissingnode.ptr.p_bool[(i+1)*c->n+(j+1)] ) + { + c->ismissingcell.ptr.p_bool[i*(c->n-1)+j] = ae_false; + } + } + } + bsetv(c->m*c->n, ae_true, &c->ismissingnode, _state); + for(i=0; i<=c->m-2; i++) + { + for(j=0; j<=c->n-2; j++) + { + if( !c->ismissingcell.ptr.p_bool[i*(c->n-1)+j] ) + { + c->ismissingnode.ptr.p_bool[i*c->n+j] = ae_false; + c->ismissingnode.ptr.p_bool[(i+1)*c->n+j] = ae_false; + c->ismissingnode.ptr.p_bool[i*c->n+(j+1)] = ae_false; + c->ismissingnode.ptr.p_bool[(i+1)*c->n+(j+1)] = ae_false; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using parabolically +terminated end conditions. + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + + _spline2dinterpolant_clear(c); + + spline2dbuildbicubicvbuf(x, n, y, m, f, d, c, _state); +} + + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using clamped +boundary conditions: +* spline values at the grid nodes are specified +* boundary conditions for first, second derivatives or for parabolic + termination at four boundaries (bottom y=min(Y[]), top y=max(Y[]), left + x=min(X[]), right x=max(X[])) are specified +* mixed derivatives at corners are specified +* it is possible to have different boundary conditions for different + boundaries (first derivatives along one boundary, second derivatives + along other one, parabolic termination along the rest and so on) +* it is possible to have either a scalar (D=1) or a vector-valued spline + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + BndBtm - array[D*N], boundary conditions at the bottom boundary + of the interpolation area (corresponds to y=min(Y[]): + * if BndTypeBtm=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndBtm is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeBtm=1, first derivatives are given + * if BndTypeBtm=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=minY, + subsequent D entries store derivatives at x=X[1], + y=minY and so on + BndTop - array[D*N], boundary conditions at the top boundary + of the interpolation area (corresponds to y=max(Y[]): + * if BndTypeTop=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndTop is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeTop=1, first derivatives are given + * if BndTypeTop=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=maxY, + subsequent D entries store derivatives at x=X[1], + y=maxY and so on + BndLft - array[D*M], boundary conditions at the left boundary + of the interpolation area (corresponds to x=min(X[]): + * if BndTypeLft=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndLft is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeLft=1, first derivatives are given + * if BndTypeLft=2, second derivatives are given + * first D entries store derivatives at x=minX, y=Y[0], + subsequent D entries store derivatives at x=minX, + y=Y[1] and so on + BndRgt - array[D*M], boundary conditions at the right boundary + of the interpolation area (corresponds to x=max(X[]): + * if BndTypeRgt=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndRgt is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeRgt=1, first derivatives are given + * if BndTypeRgt=2, second derivatives are given + * first D entries store derivatives at x=maxX, y=Y[0], + subsequent D entries store derivatives at x=maxX, + y=Y[1] and so on + MixedD - array[D*4], mixed derivatives at 4 corners of the + interpolation area: + * derivative order depends on the order of boundary + conditions (bottom/top and left/right) intersecting + at that corner: + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=1 user has + to provide d2S/dXdY + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=2 user has + to provide d4S/(dX^2*dY^2) + ** for BndType(Btm|Top)=1, BndType(Lft|Rgt)=2 user + has to provide d3S/(dX^2*dY) + ** for BndType(Btm|Top)=2, BndType(Lft|Rgt)=1 user + has to provide d3S/(dX*dY^2) + ** if one of the intersecting bounds has 'parabolic + termination' condition, this specific mixed + derivative is not used + * first D entries store derivatives at the bottom left + corner x=min(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the bottom + right corner x=max(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the top + left corner x=min(X[]), y=max(Y[]) + * subsequent D entries store derivatives at the top + right corner x=max(X[]), y=max(Y[]) + * if all bounds have 'parabolic termination' condition, + MixedD[] is not referenced at all and can be + unallocated. + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are + stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildclampedv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _bndbtm, + ae_int_t bndtypebtm, + /* Real */ const ae_vector* _bndtop, + ae_int_t bndtypetop, + /* Real */ const ae_vector* _bndlft, + ae_int_t bndtypelft, + /* Real */ const ae_vector* _bndrgt, + ae_int_t bndtypergt, + /* Real */ const ae_vector* mixedd, + /* Real */ const ae_vector* _f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector bndbtm; + ae_vector bndtop; + ae_vector bndlft; + ae_vector bndrgt; + ae_vector f; + ae_matrix tf; + ae_matrix dx; + ae_matrix dy; + ae_matrix dxy; + ae_vector bndbtm1; + ae_vector bndtop1; + ae_vector bndlft1; + ae_vector bndrgt1; + ae_vector mixed1; + ae_vector dummy; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + ae_bool allzero; + + ae_frame_make(_state, &_frame_block); + memset(&bndbtm, 0, sizeof(bndbtm)); + memset(&bndtop, 0, sizeof(bndtop)); + memset(&bndlft, 0, sizeof(bndlft)); + memset(&bndrgt, 0, sizeof(bndrgt)); + memset(&f, 0, sizeof(f)); + memset(&tf, 0, sizeof(tf)); + memset(&dx, 0, sizeof(dx)); + memset(&dy, 0, sizeof(dy)); + memset(&dxy, 0, sizeof(dxy)); + memset(&bndbtm1, 0, sizeof(bndbtm1)); + memset(&bndtop1, 0, sizeof(bndtop1)); + memset(&bndlft1, 0, sizeof(bndlft1)); + memset(&bndrgt1, 0, sizeof(bndrgt1)); + memset(&mixed1, 0, sizeof(mixed1)); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_init_copy(&bndbtm, _bndbtm, _state, ae_true); + ae_vector_init_copy(&bndtop, _bndtop, _state, ae_true); + ae_vector_init_copy(&bndlft, _bndlft, _state, ae_true); + ae_vector_init_copy(&bndrgt, _bndrgt, _state, ae_true); + ae_vector_init_copy(&f, _f, _state, ae_true); + _spline2dinterpolant_clear(c); + ae_matrix_init(&tf, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndbtm1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndtop1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndlft1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndrgt1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&mixed1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummy, 0, DT_REAL, _state, ae_true); + + allzero = imin4(bndtypebtm, bndtypetop, bndtypelft, bndtypergt, _state)==0&&imax4(bndtypebtm, bndtypetop, bndtypelft, bndtypergt, _state)==0; + ae_assert(n>=2, "Spline2DBuildClampedV: N is less than 2", _state); + ae_assert(m>=2, "Spline2DBuildClampedV: M is less than 2", _state); + ae_assert(d>=1, "Spline2DBuildClampedV: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildClampedV: length of X or Y is too short (Length(X/Y)=n*d, "Spline2DBuildClampedV: length of BndBtm is less than N*D", _state); + ae_assert(bndtypebtm==0||isfinitevector(&bndbtm, n*d, _state), "Spline2DBuildClampedV: BndBtm contains NaN or Infinite value", _state); + ae_assert(bndtypetop==0||bndtop.cnt>=n*d, "Spline2DBuildClampedV: length of BndTop is less than N*D", _state); + ae_assert(bndtypetop==0||isfinitevector(&bndtop, n*d, _state), "Spline2DBuildClampedV: BndTop contains NaN or Infinite value", _state); + ae_assert(bndtypelft==0||bndlft.cnt>=m*d, "Spline2DBuildClampedV: length of BndLft is less than M*D", _state); + ae_assert(bndtypelft==0||isfinitevector(&bndlft, m*d, _state), "Spline2DBuildClampedV: BndLft contains NaN or Infinite value", _state); + ae_assert(bndtypergt==0||bndrgt.cnt>=m*d, "Spline2DBuildClampedV: length of BndRgt is less than M*D", _state); + ae_assert(bndtypergt==0||isfinitevector(&bndrgt, m*d, _state), "Spline2DBuildClampedV: BndRgt contains NaN or Infinite value", _state); + ae_assert(allzero||mixedd->cnt>=4*d, "Spline2DBuildClampedV: length of MixedD is less than 4*D", _state); + ae_assert(allzero||isfinitevector(mixedd, 4*d, _state), "Spline2DBuildClampedV: MixedD contains NaN or Infinite value", _state); + ae_assert((bndtypebtm==0||bndtypebtm==1)||bndtypebtm==2, "Spline2DBuildClampedV: BndTypeBtm is neither 0, 1 or 2", _state); + ae_assert((bndtypetop==0||bndtypetop==1)||bndtypetop==2, "Spline2DBuildClampedV: BndTypeTop is neither 0, 1 or 2", _state); + ae_assert((bndtypelft==0||bndtypelft==1)||bndtypelft==2, "Spline2DBuildClampedV: BndTypeLft is neither 0, 1 or 2", _state); + ae_assert((bndtypergt==0||bndtypergt==1)||bndtypergt==2, "Spline2DBuildClampedV: BndTypeRgt is neither 0, 1 or 2", _state); + k = n*m*d; + ae_assert(f.cnt>=k, "Spline2DBuildClampedV: length of F is too short (Length(F)d = d; + c->n = n; + c->m = m; + c->stype = -3; + c->hasmissingcells = ae_false; + k = 4*k; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, k, _state); + ae_matrix_set_length(&tf, c->m, c->n, _state); + ae_vector_set_length(&bndbtm1, n, _state); + ae_vector_set_length(&bndtop1, n, _state); + ae_vector_set_length(&bndlft1, m, _state); + ae_vector_set_length(&bndrgt1, m, _state); + ae_vector_set_length(&mixed1, 4, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + spline2d_sortgrid(&c->x, n, &c->y, m, &bndbtm, bndtypebtm!=0, &bndtop, bndtypetop!=0, &bndlft, bndtypelft!=0, &bndrgt, bndtypergt!=0, &f, d, &dummy, &dummy, &dummy, ae_false, _state); + for(di=0; di<=c->d-1; di++) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + tf.ptr.pp_double[i][j] = f.ptr.p_double[c->d*(i*c->n+j)+di]; + } + } + if( bndtypebtm!=0 ) + { + for(i=0; i<=c->n-1; i++) + { + bndbtm1.ptr.p_double[i] = bndbtm.ptr.p_double[i*d+di]; + } + } + if( bndtypetop!=0 ) + { + for(i=0; i<=c->n-1; i++) + { + bndtop1.ptr.p_double[i] = bndtop.ptr.p_double[i*d+di]; + } + } + if( bndtypelft!=0 ) + { + for(i=0; i<=c->m-1; i++) + { + bndlft1.ptr.p_double[i] = bndlft.ptr.p_double[i*d+di]; + } + } + if( bndtypergt!=0 ) + { + for(i=0; i<=c->m-1; i++) + { + bndrgt1.ptr.p_double[i] = bndrgt.ptr.p_double[i*d+di]; + } + } + if( !allzero ) + { + for(i=0; i<=3; i++) + { + mixed1.ptr.p_double[i] = mixedd->ptr.p_double[i*d+di]; + } + } + spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &bndbtm1, bndtypebtm, &bndtop1, bndtypetop, &bndlft1, bndtypelft, &bndrgt1, bndtypergt, &mixed1, &dx, &dy, &dxy, _state); + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + k = c->d*(i*c->n+j)+di; + c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j]; + c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j]; + c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j]; + c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds a Hermite bicubic vector-valued spline. + +This function produces merely C1-continuous spline, i.e. the spline has +smooth first derivatives. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdX- spline derivatives with respect to X, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdY- spline derivatives with respect to Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + d2FdXdY-mixed derivatives with respect to X and Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildhermitev(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Real */ const ae_vector* _dfdx, + /* Real */ const ae_vector* _dfdy, + /* Real */ const ae_vector* _d2fdxdy, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + ae_vector dfdx; + ae_vector dfdy; + ae_vector d2fdxdy; + ae_int_t k; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + memset(&dfdx, 0, sizeof(dfdx)); + memset(&dfdy, 0, sizeof(dfdy)); + memset(&d2fdxdy, 0, sizeof(d2fdxdy)); + ae_vector_init_copy(&f, _f, _state, ae_true); + ae_vector_init_copy(&dfdx, _dfdx, _state, ae_true); + ae_vector_init_copy(&dfdy, _dfdy, _state, ae_true); + ae_vector_init_copy(&d2fdxdy, _d2fdxdy, _state, ae_true); + _spline2dinterpolant_clear(c); + + ae_assert(n>=2, "Spline2DBuildHermiteV: N is less than 2", _state); + ae_assert(m>=2, "Spline2DBuildHermiteV: M is less than 2", _state); + ae_assert(d>=1, "Spline2DBuildHermiteV: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildHermiteV: X or Y is too short (Length(X/Y)=k, "Spline2DBuildHermiteV: F is too short (Length(F)=k, "Spline2DBuildHermiteV: dFdX is too short (Length(dFdX)=k, "Spline2DBuildHermiteV: dFdY is too short (Length(dFdY)=k, "Spline2DBuildHermiteV: d2FdXdY is too short (Length(d2FdXdY)=2, "Spline2DBuildBicubicV: N is less than 2", _state); + ae_assert(m>=2, "Spline2DBuildBicubicV: M is less than 2", _state); + ae_assert(d>=1, "Spline2DBuildBicubicV: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicV: length of X or Y is too short (Length(X/Y)=k, "Spline2DBuildBicubicV: length of F is too short (Length(F)d = d; + c->n = n; + c->m = m; + c->stype = -3; + c->hasmissingcells = ae_false; + k = 4*k; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, k, _state); + ae_matrix_set_length(&tf, c->m, c->n, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + spline2d_sortgrid(&c->x, n, &c->y, m, &c->x, ae_false, &c->x, ae_false, &c->y, ae_false, &c->y, ae_false, &f, d, &dummy, &dummy, &dummy, ae_false, _state); + for(di=0; di<=c->d-1; di++) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + tf.ptr.pp_double[i][j] = f.ptr.p_double[c->d*(i*c->n+j)+di]; + } + } + spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &dummy, 0, &dummy, 0, &dummy, 0, &dummy, 0, &dummy, &dx, &dy, &dxy, _state); + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + k = c->d*(i*c->n+j)+di; + c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j]; + c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j]; + c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j]; + c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C2-continuous spline, i.e. the has smooth first and +second derivatives both inside spline cells and at the boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissing(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + ae_vector_init_copy(&f, _f, _state, ae_true); + _spline2dinterpolant_clear(c); + + spline2dbuildbicubicmissingbuf(x, n, y, m, &f, missing, d, c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBicubicMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissingbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + ae_matrix tf; + ae_matrix dx; + ae_matrix dy; + ae_matrix dxy; + double t; + ae_bool tb; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + ae_int_t i0; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + memset(&tf, 0, sizeof(tf)); + memset(&dx, 0, sizeof(dx)); + memset(&dy, 0, sizeof(dy)); + memset(&dxy, 0, sizeof(dxy)); + ae_vector_init_copy(&f, _f, _state, ae_true); + ae_matrix_init(&tf, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=2, "Spline2DBuildBicubicMissing: N is less than 2", _state); + ae_assert(m>=2, "Spline2DBuildBicubicMissing: M is less than 2", _state); + ae_assert(d>=1, "Spline2DBuildBicubicMissing: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicMissing: length of X or Y is too short (Length(X/Y)=k, "Spline2DBuildBicubicMissing: length of F is too short (Length(F)cnt>=n*m, "Spline2DBuildBicubicMissing: Missing[] is shorter than M*N", _state); + for(i=0; i<=k-1; i++) + { + if( !missing->ptr.p_bool[i/d]&&!ae_isfinite(f.ptr.p_double[i], _state) ) + { + ae_assert(ae_false, "Spline2DBuildBicubicMissing: F[] contains NAN or INF in its non-missing entries", _state); + } + } + + /* + * Fill interpolant: + * F[0]...F[N*M*D-1]: + * f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on... + * F[N*M*D]...F[2*N*M*D-1]: + * df(i,j)/dx table. + * F[2*N*M*D]...F[3*N*M*D-1]: + * df(i,j)/dy table. + * F[3*N*M*D]...F[4*N*M*D-1]: + * d2f(i,j)/dxdy table. + */ + c->d = d; + c->n = n; + c->m = m; + c->stype = -3; + c->hasmissingcells = ae_true; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + rsetallocv(4*k, 0.0, &c->f, _state); + bcopyallocv(c->n*c->m, missing, &c->ismissingnode, _state); + ae_matrix_set_length(&tf, c->m, c->n, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + if( !missing->ptr.p_bool[i/d] ) + { + c->f.ptr.p_double[i] = f.ptr.p_double[i]; + } + } + + /* + * Sort points + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t; + } + tb = c->ismissingnode.ptr.p_bool[i*c->n+j]; + c->ismissingnode.ptr.p_bool[i*c->n+j] = c->ismissingnode.ptr.p_bool[i*c->n+k]; + c->ismissingnode.ptr.p_bool[i*c->n+k] = tb; + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0]; + c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t; + } + tb = c->ismissingnode.ptr.p_bool[i*c->n+j]; + c->ismissingnode.ptr.p_bool[i*c->n+j] = c->ismissingnode.ptr.p_bool[k*c->n+j]; + c->ismissingnode.ptr.p_bool[k*c->n+j] = tb; + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } + + /* + * 1. Determine cells that are not missing. A cell is non-missing if it has four non-missing + * nodes at its corners. + * 2. Normalize IsMissingNode[] array - all isolated points that are not part of some non-missing + * cell are marked as missing too + */ + bsetallocv((c->m-1)*(c->n-1), ae_true, &c->ismissingcell, _state); + for(i=0; i<=c->m-2; i++) + { + for(j=0; j<=c->n-2; j++) + { + if( ((!c->ismissingnode.ptr.p_bool[i*c->n+j]&&!c->ismissingnode.ptr.p_bool[(i+1)*c->n+j])&&!c->ismissingnode.ptr.p_bool[i*c->n+(j+1)])&&!c->ismissingnode.ptr.p_bool[(i+1)*c->n+(j+1)] ) + { + c->ismissingcell.ptr.p_bool[i*(c->n-1)+j] = ae_false; + } + } + } + bsetv(c->m*c->n, ae_true, &c->ismissingnode, _state); + for(i=0; i<=c->m-2; i++) + { + for(j=0; j<=c->n-2; j++) + { + if( !c->ismissingcell.ptr.p_bool[i*(c->n-1)+j] ) + { + c->ismissingnode.ptr.p_bool[i*c->n+j] = ae_false; + c->ismissingnode.ptr.p_bool[(i+1)*c->n+j] = ae_false; + c->ismissingnode.ptr.p_bool[i*c->n+(j+1)] = ae_false; + c->ismissingnode.ptr.p_bool[(i+1)*c->n+(j+1)] = ae_false; + } + } + } + for(di=0; di<=c->d-1; di++) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + tf.ptr.pp_double[i][j] = c->f.ptr.p_double[c->d*(i*c->n+j)+di]; + } + } + spline2d_bicubiccalcderivativesmissing(&tf, &c->ismissingnode, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state); + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + k = c->d*(i*c->n+j)+di; + c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j]; + c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j]; + c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j]; + c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine unpacks two-dimensional spline into the coefficients table + +Input parameters: + C - spline interpolant. + +Result: + M, N- grid size (x-axis and y-axis) + D - number of components + Tbl - coefficients table, unpacked format, + D - components: [0..(N-1)*(M-1)*D-1, 0..20]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index): + K := T + I*D + J*D*(N-1) + + K-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[K,0] = X[i] + Tbl[K,1] = X[i+1] + Tbl[K,2] = Y[j] + Tbl[K,3] = Y[j+1] + Tbl[K,4] = C00 + Tbl[K,5] = C01 + Tbl[K,6] = C02 + Tbl[K,7] = C03 + Tbl[K,8] = C10 + Tbl[K,9] = C11 + ... + Tbl[K,19] = C33 + Tbl[K,20] = 1 if the cell is present, 0 if the cell is missing. + In the latter case Tbl[4..19] are exactly zero. + On each grid square spline is equals to: + S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) + t = x-x[j] + u = y-y[i] + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpackv(const spline2dinterpolant* c, + ae_int_t* m, + ae_int_t* n, + ae_int_t* d, + /* Real */ ae_matrix* tbl, + ae_state *_state) +{ + ae_int_t k; + ae_int_t p; + ae_int_t ci; + ae_int_t cj; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double dt; + double du; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + + *m = 0; + *n = 0; + *d = 0; + ae_matrix_clear(tbl); + + ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpackV: incorrect C (incorrect parameter C.SType)", _state); + *n = c->n; + *m = c->m; + *d = c->d; + rsetallocm((*n-1)*(*m-1)*(*d), 21, 0.0, tbl, _state); + sfx = *n*(*m)*(*d); + sfy = 2*(*n)*(*m)*(*d); + sfxy = 3*(*n)*(*m)*(*d); + for(i=0; i<=*m-2; i++) + { + for(j=0; j<=*n-2; j++) + { + for(k=0; k<=*d-1; k++) + { + p = *d*(i*(*n-1)+j)+k; + + /* + * Set up cell dimensions (always present) + */ + tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; + tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; + tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; + tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; + dt = (double)1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); + du = (double)1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); + + /* + * Skip cell if it is missing + */ + if( c->hasmissingcells&&c->ismissingcell.ptr.p_bool[i*(c->n-1)+j] ) + { + continue; + } + tbl->ptr.pp_double[p][20] = (double)(1); + + /* + * Bilinear interpolation: output coefficients + */ + if( c->stype==-1 ) + { + for(k0=4; k0<=19; k0++) + { + tbl->ptr.pp_double[p][k0] = (double)(0); + } + y1 = c->f.ptr.p_double[*d*(*n*i+j)+k]; + y2 = c->f.ptr.p_double[*d*(*n*i+(j+1))+k]; + y3 = c->f.ptr.p_double[*d*(*n*(i+1)+(j+1))+k]; + y4 = c->f.ptr.p_double[*d*(*n*(i+1)+j)+k]; + tbl->ptr.pp_double[p][4] = y1; + tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; + tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; + tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; + } + + /* + * Bicubic interpolation: output coefficients + */ + if( c->stype==-3 ) + { + s1 = *d*(*n*i+j)+k; + s2 = *d*(*n*i+(j+1))+k; + s3 = *d*(*n*(i+1)+(j+1))+k; + s4 = *d*(*n*(i+1)+j)+k; + tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; + tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; + tbl->ptr.pp_double[p][4+0*4+2] = -(double)3*c->f.ptr.p_double[s1]+(double)3*c->f.ptr.p_double[s4]-(double)2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; + tbl->ptr.pp_double[p][4+0*4+3] = (double)2*c->f.ptr.p_double[s1]-(double)2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; + tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; + tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); + tbl->ptr.pp_double[p][4+1*4+2] = -(double)3*c->f.ptr.p_double[sfx+s1]/dt+(double)3*c->f.ptr.p_double[sfx+s4]/dt-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+1*4+3] = (double)2*c->f.ptr.p_double[sfx+s1]/dt-(double)2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+0] = -(double)3*c->f.ptr.p_double[s1]+(double)3*c->f.ptr.p_double[s2]-(double)2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; + tbl->ptr.pp_double[p][4+2*4+1] = -(double)3*c->f.ptr.p_double[sfy+s1]/du+(double)3*c->f.ptr.p_double[sfy+s2]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+2] = (double)9*c->f.ptr.p_double[s1]-(double)9*c->f.ptr.p_double[s2]+(double)9*c->f.ptr.p_double[s3]-(double)9*c->f.ptr.p_double[s4]+(double)6*c->f.ptr.p_double[sfx+s1]/dt+(double)3*c->f.ptr.p_double[sfx+s2]/dt-(double)3*c->f.ptr.p_double[sfx+s3]/dt-(double)6*c->f.ptr.p_double[sfx+s4]/dt+(double)6*c->f.ptr.p_double[sfy+s1]/du-(double)6*c->f.ptr.p_double[sfy+s2]/du-(double)3*c->f.ptr.p_double[sfy+s3]/du+(double)3*c->f.ptr.p_double[sfy+s4]/du+(double)4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+(double)2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+(double)2*c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+3] = -(double)6*c->f.ptr.p_double[s1]+(double)6*c->f.ptr.p_double[s2]-(double)6*c->f.ptr.p_double[s3]+(double)6*c->f.ptr.p_double[s4]-(double)4*c->f.ptr.p_double[sfx+s1]/dt-(double)2*c->f.ptr.p_double[sfx+s2]/dt+(double)2*c->f.ptr.p_double[sfx+s3]/dt+(double)4*c->f.ptr.p_double[sfx+s4]/dt-(double)3*c->f.ptr.p_double[sfy+s1]/du+(double)3*c->f.ptr.p_double[sfy+s2]/du+(double)3*c->f.ptr.p_double[sfy+s3]/du-(double)3*c->f.ptr.p_double[sfy+s4]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-(double)2*c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+0] = (double)2*c->f.ptr.p_double[s1]-(double)2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; + tbl->ptr.pp_double[p][4+3*4+1] = (double)2*c->f.ptr.p_double[sfy+s1]/du-(double)2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+2] = -(double)6*c->f.ptr.p_double[s1]+(double)6*c->f.ptr.p_double[s2]-(double)6*c->f.ptr.p_double[s3]+(double)6*c->f.ptr.p_double[s4]-(double)3*c->f.ptr.p_double[sfx+s1]/dt-(double)3*c->f.ptr.p_double[sfx+s2]/dt+(double)3*c->f.ptr.p_double[sfx+s3]/dt+(double)3*c->f.ptr.p_double[sfx+s4]/dt-(double)4*c->f.ptr.p_double[sfy+s1]/du+(double)4*c->f.ptr.p_double[sfy+s2]/du+(double)2*c->f.ptr.p_double[sfy+s3]/du-(double)2*c->f.ptr.p_double[sfy+s4]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-(double)2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+3] = (double)4*c->f.ptr.p_double[s1]-(double)4*c->f.ptr.p_double[s2]+(double)4*c->f.ptr.p_double[s3]-(double)4*c->f.ptr.p_double[s4]+(double)2*c->f.ptr.p_double[sfx+s1]/dt+(double)2*c->f.ptr.p_double[sfx+s2]/dt-(double)2*c->f.ptr.p_double[sfx+s3]/dt-(double)2*c->f.ptr.p_double[sfx+s4]/dt+(double)2*c->f.ptr.p_double[sfy+s1]/du-(double)2*c->f.ptr.p_double[sfy+s2]/du-(double)2*c->f.ptr.p_double[sfy+s3]/du+(double)2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); + } + + /* + * Rescale Cij + */ + for(ci=0; ci<=3; ci++) + { + for(cj=0; cj<=3; cj++) + { + tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state); + } + } + } + } + } +} + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBilinearV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinear(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_matrix* f, + ae_int_t m, + ae_int_t n, + spline2dinterpolant* c, + ae_state *_state) +{ + double t; + ae_int_t i; + ae_int_t j; + ae_int_t k; + + _spline2dinterpolant_clear(c); + + ae_assert(n>=2, "Spline2DBuildBilinear: N<2", _state); + ae_assert(m>=2, "Spline2DBuildBilinear: M<2", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinear: length of X or Y is too short (Length(X/Y)rows>=m&&f->cols>=n, "Spline2DBuildBilinear: size of F is too small (rows(F)n = n; + c->m = m; + c->d = 1; + c->stype = -1; + c->hasmissingcells = ae_false; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, c->n*c->m, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + c->f.ptr.p_double[i*c->n+j] = f->ptr.pp_double[i][j]; + } + } + + /* + * Sort points + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + t = c->f.ptr.p_double[i*c->n+j]; + c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[i*c->n+k]; + c->f.ptr.p_double[i*c->n+k] = t; + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + t = c->f.ptr.p_double[i*c->n+j]; + c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[k*c->n+j]; + c->f.ptr.p_double[k*c->n+j] = t; + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } +} + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBicubicV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubic(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_matrix* _f, + ae_int_t m, + ae_int_t n, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix f; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + ae_matrix dx; + ae_matrix dy; + ae_matrix dxy; + double t; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector dummy; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + memset(&dx, 0, sizeof(dx)); + memset(&dy, 0, sizeof(dy)); + memset(&dxy, 0, sizeof(dxy)); + memset(&dummy, 0, sizeof(dummy)); + ae_matrix_init_copy(&f, _f, _state, ae_true); + _spline2dinterpolant_clear(c); + ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummy, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=2, "Spline2DBuildBicubicSpline: N<2", _state); + ae_assert(m>=2, "Spline2DBuildBicubicSpline: M<2", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubic: length of X or Y is too short (Length(X/Y)=m&&f.cols>=n, "Spline2DBuildBicubic: size of F is too small (rows(F)d = 1; + c->n = n; + c->m = m; + c->stype = -3; + c->hasmissingcells = ae_false; + sfx = c->n*c->m; + sfy = 2*c->n*c->m; + sfxy = 3*c->n*c->m; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, 4*c->n*c->m, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + + /* + * Sort points + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + t = f.ptr.pp_double[i][j]; + f.ptr.pp_double[i][j] = f.ptr.pp_double[i][k]; + f.ptr.pp_double[i][k] = t; + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + t = f.ptr.pp_double[i][j]; + f.ptr.pp_double[i][j] = f.ptr.pp_double[k][j]; + f.ptr.pp_double[k][j] = t; + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } + spline2d_bicubiccalcderivatives(&f, &c->x, &c->y, c->m, c->n, &dummy, 0, &dummy, 0, &dummy, 0, &dummy, 0, &dummy, &dx, &dy, &dxy, _state); + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + k = i*c->n+j; + c->f.ptr.p_double[k] = f.ptr.pp_double[i][j]; + c->f.ptr.p_double[sfx+k] = dx.ptr.pp_double[i][j]; + c->f.ptr.p_double[sfy+k] = dy.ptr.pp_double[i][j]; + c->f.ptr.p_double[sfxy+k] = dxy.ptr.pp_double[i][j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DUnpackV(), which is more flexible +and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpack(const spline2dinterpolant* c, + ae_int_t* m, + ae_int_t* n, + /* Real */ ae_matrix* tbl, + ae_state *_state) +{ + ae_int_t k; + ae_int_t p; + ae_int_t ci; + ae_int_t cj; + ae_int_t s1; + ae_int_t s2; + ae_int_t s3; + ae_int_t s4; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double y1; + double y2; + double y3; + double y4; + double dt; + double du; + ae_int_t i; + ae_int_t j; + + *m = 0; + *n = 0; + ae_matrix_clear(tbl); + + ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpack: incorrect C (incorrect parameter C.SType)", _state); + if( c->d!=1 ) + { + *n = 0; + *m = 0; + return; + } + *n = c->n; + *m = c->m; + ae_matrix_set_length(tbl, (*n-1)*(*m-1), 20, _state); + sfx = *n*(*m); + sfy = 2*(*n)*(*m); + sfxy = 3*(*n)*(*m); + + /* + * Fill + */ + for(i=0; i<=*m-2; i++) + { + for(j=0; j<=*n-2; j++) + { + p = i*(*n-1)+j; + tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j]; + tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1]; + tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i]; + tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1]; + dt = (double)1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); + du = (double)1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); + + /* + * Bilinear interpolation + */ + if( c->stype==-1 ) + { + for(k=4; k<=19; k++) + { + tbl->ptr.pp_double[p][k] = (double)(0); + } + y1 = c->f.ptr.p_double[*n*i+j]; + y2 = c->f.ptr.p_double[*n*i+(j+1)]; + y3 = c->f.ptr.p_double[*n*(i+1)+(j+1)]; + y4 = c->f.ptr.p_double[*n*(i+1)+j]; + tbl->ptr.pp_double[p][4] = y1; + tbl->ptr.pp_double[p][4+1*4+0] = y2-y1; + tbl->ptr.pp_double[p][4+0*4+1] = y4-y1; + tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1; + } + + /* + * Bicubic interpolation + */ + if( c->stype==-3 ) + { + s1 = *n*i+j; + s2 = *n*i+(j+1); + s3 = *n*(i+1)+(j+1); + s4 = *n*(i+1)+j; + tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1]; + tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du; + tbl->ptr.pp_double[p][4+0*4+2] = -(double)3*c->f.ptr.p_double[s1]+(double)3*c->f.ptr.p_double[s4]-(double)2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du; + tbl->ptr.pp_double[p][4+0*4+3] = (double)2*c->f.ptr.p_double[s1]-(double)2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du; + tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt; + tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du); + tbl->ptr.pp_double[p][4+1*4+2] = -(double)3*c->f.ptr.p_double[sfx+s1]/dt+(double)3*c->f.ptr.p_double[sfx+s4]/dt-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+1*4+3] = (double)2*c->f.ptr.p_double[sfx+s1]/dt-(double)2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+0] = -(double)3*c->f.ptr.p_double[s1]+(double)3*c->f.ptr.p_double[s2]-(double)2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt; + tbl->ptr.pp_double[p][4+2*4+1] = -(double)3*c->f.ptr.p_double[sfy+s1]/du+(double)3*c->f.ptr.p_double[sfy+s2]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+2] = (double)9*c->f.ptr.p_double[s1]-(double)9*c->f.ptr.p_double[s2]+(double)9*c->f.ptr.p_double[s3]-(double)9*c->f.ptr.p_double[s4]+(double)6*c->f.ptr.p_double[sfx+s1]/dt+(double)3*c->f.ptr.p_double[sfx+s2]/dt-(double)3*c->f.ptr.p_double[sfx+s3]/dt-(double)6*c->f.ptr.p_double[sfx+s4]/dt+(double)6*c->f.ptr.p_double[sfy+s1]/du-(double)6*c->f.ptr.p_double[sfy+s2]/du-(double)3*c->f.ptr.p_double[sfy+s3]/du+(double)3*c->f.ptr.p_double[sfy+s4]/du+(double)4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+(double)2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+(double)2*c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+2*4+3] = -(double)6*c->f.ptr.p_double[s1]+(double)6*c->f.ptr.p_double[s2]-(double)6*c->f.ptr.p_double[s3]+(double)6*c->f.ptr.p_double[s4]-(double)4*c->f.ptr.p_double[sfx+s1]/dt-(double)2*c->f.ptr.p_double[sfx+s2]/dt+(double)2*c->f.ptr.p_double[sfx+s3]/dt+(double)4*c->f.ptr.p_double[sfx+s4]/dt-(double)3*c->f.ptr.p_double[sfy+s1]/du+(double)3*c->f.ptr.p_double[sfy+s2]/du+(double)3*c->f.ptr.p_double[sfy+s3]/du-(double)3*c->f.ptr.p_double[sfy+s4]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-(double)2*c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+0] = (double)2*c->f.ptr.p_double[s1]-(double)2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt; + tbl->ptr.pp_double[p][4+3*4+1] = (double)2*c->f.ptr.p_double[sfy+s1]/du-(double)2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+2] = -(double)6*c->f.ptr.p_double[s1]+(double)6*c->f.ptr.p_double[s2]-(double)6*c->f.ptr.p_double[s3]+(double)6*c->f.ptr.p_double[s4]-(double)3*c->f.ptr.p_double[sfx+s1]/dt-(double)3*c->f.ptr.p_double[sfx+s2]/dt+(double)3*c->f.ptr.p_double[sfx+s3]/dt+(double)3*c->f.ptr.p_double[sfx+s4]/dt-(double)4*c->f.ptr.p_double[sfy+s1]/du+(double)4*c->f.ptr.p_double[sfy+s2]/du+(double)2*c->f.ptr.p_double[sfy+s3]/du-(double)2*c->f.ptr.p_double[sfy+s4]/du-(double)2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-(double)2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du); + tbl->ptr.pp_double[p][4+3*4+3] = (double)4*c->f.ptr.p_double[s1]-(double)4*c->f.ptr.p_double[s2]+(double)4*c->f.ptr.p_double[s3]-(double)4*c->f.ptr.p_double[s4]+(double)2*c->f.ptr.p_double[sfx+s1]/dt+(double)2*c->f.ptr.p_double[sfx+s2]/dt-(double)2*c->f.ptr.p_double[sfx+s3]/dt-(double)2*c->f.ptr.p_double[sfx+s4]/dt+(double)2*c->f.ptr.p_double[sfy+s1]/du-(double)2*c->f.ptr.p_double[sfy+s2]/du-(double)2*c->f.ptr.p_double[sfy+s3]/du+(double)2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du); + } + + /* + * Rescale Cij + */ + for(ci=0; ci<=3; ci++) + { + for(cj=0; cj<=3; cj++) + { + tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state); + } + } + } + } +} + + +/************************************************************************* +This subroutine creates least squares solver used to fit 2D splines to +irregularly sampled (scattered) data. + +Solver object is used to perform spline fits as follows: +* solver object is created with spline2dbuildercreate() function +* dataset is added with spline2dbuildersetpoints() function +* fit area is chosen: + * spline2dbuildersetarea() - for user-defined area + * spline2dbuildersetareaauto() - for automatically chosen area +* number of grid nodes is chosen with spline2dbuildersetgrid() +* prior term is chosen with one of the following functions: + * spline2dbuildersetlinterm() to set linear prior + * spline2dbuildersetconstterm() to set constant prior + * spline2dbuildersetzeroterm() to set zero prior + * spline2dbuildersetuserterm() to set user-defined constant prior +* solver algorithm is chosen with either: + * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems + * spline2dbuildersetalgofastddm() - FastDDM algorithm, large-scale problems +* finally, fitting itself is performed with spline2dfit() function. + +Most of the steps above can be omitted, solver is configured with good +defaults. The minimum is to call: +* spline2dbuildercreate() to create solver object +* spline2dbuildersetpoints() to specify dataset +* spline2dbuildersetgrid() to tell how many nodes you need +* spline2dfit() to perform fit + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + D - positive number, number of Y-components: D=1 for simple scalar + fit, D>1 for vector-valued spline fitting. + +OUTPUT PARAMETERS: + S - solver object + + -- ALGLIB PROJECT -- + Copyright 29.01.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildercreate(ae_int_t d, + spline2dbuilder* state, + ae_state *_state) +{ + + _spline2dbuilder_clear(state); + + ae_assert(d>=1, "Spline2DBuilderCreate: D<=0", _state); + + /* + * NOTES: + * + * 1. Prior term is set to linear one (good default option) + * 2. Solver is set to BlockLLS - good enough for small-scale problems. + * 3. Refinement rounds: 5; enough to get good convergence. + */ + state->priorterm = 1; + state->priortermval = (double)(0); + state->areatype = 0; + state->gridtype = 0; + state->smoothing = 0.0; + state->nlayers = 0; + state->solvertype = 1; + state->npoints = 0; + state->d = d; + state->sx = 1.0; + state->sy = 1.0; + state->lsqrcnt = 5; + + /* + * Algorithm settings + */ + state->adddegreeoffreedom = ae_true; + state->maxcoresize = 16; + state->interfacesize = 5; +} + + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetuserterm(spline2dbuilder* state, + double v, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(v, _state), "Spline2DBuilderSetUserTerm: infinite/NAN value passed", _state); + state->priorterm = 0; + state->priortermval = v; +} + + +/************************************************************************* +This function sets linear prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +Linear prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetlinterm(spline2dbuilder* state, ae_state *_state) +{ + + + state->priorterm = 1; +} + + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetconstterm(spline2dbuilder* state, ae_state *_state) +{ + + + state->priorterm = 2; +} + + +/************************************************************************* +This function sets zero prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetzeroterm(spline2dbuilder* state, ae_state *_state) +{ + + + state->priorterm = 3; +} + + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + S - spline 2D builder object + XY - points, array[N,2+D]. One row corresponds to one point + in the dataset. First 2 elements are coordinates, next + D elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetpoints(spline2dbuilder* state, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ew; + + + ae_assert(n>0, "Spline2DBuilderSetPoints: N<0", _state); + ae_assert(xy->rows>=n, "Spline2DBuilderSetPoints: Rows(XY)cols>=2+state->d, "Spline2DBuilderSetPoints: Cols(XY)d, _state), "Spline2DBuilderSetPoints: XY contains infinite or NaN values!", _state); + state->npoints = n; + ew = 2+state->d; + rvectorsetlengthatleast(&state->xy, n*ew, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ew-1; j++) + { + state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function sets area where 2D spline interpolant is built. "Auto" means +that area extent is determined automatically from dataset extent. + +INPUT PARAMETERS: + S - spline 2D builder object + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetareaauto(spline2dbuilder* state, ae_state *_state) +{ + + + state->areatype = 0; +} + + +/************************************************************************* +This function sets area where 2D spline interpolant is built to +user-defined one: [XA,XB]*[YA,YB] + +INPUT PARAMETERS: + S - spline 2D builder object + XA,XB - spatial extent in the first (X) dimension, XA=XB", _state); + ae_assert(ae_fp_less(ya,yb), "Spline2DBuilderSetArea: YA>=YB", _state); + state->areatype = 1; + state->xa = xa; + state->xb = xb; + state->ya = ya; + state->yb = yb; +} + + +/************************************************************************* +This function sets nodes count for 2D spline interpolant. Fitting is +performed on area defined with one of the "setarea" functions; this one +sets number of nodes placed upon the fitting area. + +INPUT PARAMETERS: + S - spline 2D builder object + KX - nodes count for the first (X) dimension; fitting interval + [XA,XB] is separated into KX-1 subintervals, with KX nodes + created at the boundaries. + KY - nodes count for the first (Y) dimension; fitting interval + [YA,YB] is separated into KY-1 subintervals, with KY nodes + created at the boundaries. + +NOTE: at least 4 nodes is created in each dimension, so KX and KY are + silently increased if needed. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetgrid(spline2dbuilder* state, + ae_int_t kx, + ae_int_t ky, + ae_state *_state) +{ + + + ae_assert(kx>0, "Spline2DBuilderSetGridSizePrecisely: KX<=0", _state); + ae_assert(ky>0, "Spline2DBuilderSetGridSizePrecisely: KY<=0", _state); + state->gridtype = 1; + state->kx = ae_maxint(kx, 4, _state); + state->ky = ae_maxint(ky, 4, _state); +} + + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "FastDDM", which performs +fast parallel fitting by splitting problem into smaller chunks and merging +results together. + +Unlike BlockLLS, this solver produces merely C1 continuous models because +domain decomposition part disrupts C2 continuity. + +This solver is optimized for large-scale problems, starting from 256x256 +grids, and up to 10000x10000 grids. Of course, it will work for smaller +grids too. + +More detailed description of the algorithm is given below: +* algorithm generates hierarchy of nested grids, ranging from ~16x16 + (topmost "layer" of the model) to ~KX*KY one (final layer). Upper layers + model global behavior of the function, lower layers are used to model + fine details. Moving from layer to layer doubles grid density. +* fitting is started from topmost layer, subsequent layers are fitted + using residuals from previous ones. +* user may choose to skip generation of upper layers and generate only a + few bottom ones, which will result in much better performance and + parallelization efficiency, at the cost of algorithm inability to "patch" + large holes in the dataset. +* every layer is regularized using progressively increasing regularization + coefficient; thus, increasing LambdaV penalizes fine details first, + leaving lower frequencies almost intact for a while. +* after fitting is done, all layers are merged together into one bicubic + spline + +IMPORTANT: regularization coefficient used by this solver is different + from the one used by BlockLLS. Latter utilizes nonlinearity + penalty, which is global in nature (large regularization + results in global linear trend being extracted); this solver + uses another, localized form of penalty, which is suitable for + parallel processing. + +Notes on memory and performance: +* memory requirements: most memory is consumed during modeling of the + higher layers; ~[512*NPoints] bytes is required for a model with full + hierarchy of grids being generated. However, if you skip a few topmost + layers, you will get nearly constant (wrt. points count and grid size) + memory consumption. +* serial running time: O(K*K)+O(NPoints) for a KxK grid +* parallelism potential: good. You may get nearly linear speed-up when + performing fitting with just a few layers. Adding more layers results in + model becoming more global, which somewhat reduces efficiency of the + parallel code. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - spline 2D builder object + NLayers - number of layers in the model: + * NLayers>=1 means that up to chosen number of bottom + layers is fitted + * NLayers=0 means that maximum number of layers is chosen + (according to current grid size) + * NLayers<=-1 means that up to |NLayers| topmost layers is + skipped + Recommendations: + * good "default" value is 2 layers + * you may need more layers, if your dataset is very + irregular and you want to "patch" large holes. For a + grid step H (equal to AreaWidth/GridSize) you may expect + that last layer reproduces variations at distance H (and + can patch holes that wide); that higher layers operate + at distances 2*H, 4*H, 8*H and so on. + * good value for "bullletproof" mode is NLayers=0, which + results in complete hierarchy of layers being generated. + LambdaV - regularization coefficient, chosen in such a way that it + penalizes bottom layers (fine details) first. + LambdaV>=0, zero value means that no penalty is applied. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgofastddm(spline2dbuilder* state, + ae_int_t nlayers, + double lambdav, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdav, _state), "Spline2DBuilderSetAlgoFastDDM: LambdaV is not finite value", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "Spline2DBuilderSetAlgoFastDDM: LambdaV<0", _state); + state->solvertype = 3; + state->nlayers = nlayers; + state->smoothing = lambdav; +} + + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "BlockLLS", which performs +least squares fitting with fast sparse direct solver, with optional +nonsmoothness penalty being applied. + +This solver produces C2-continuous spline. + +Nonlinearity penalty has the following form: + + [ ] + P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy + [ ] + +here integral is calculated over entire grid, and "~" means "proportional" +because integral is normalized after calcilation. Extremely large values +of Lambda result in linear fit being performed. + +NOTE: this algorithm is the most robust and controllable one, but it is + limited by 512x512 grids and (say) up to 1.000.000 points. However, + ALGLIB has one more spline solver: FastDDM algorithm, which is + intended for really large-scale problems (in 10M-100M range). FastDDM + algorithm also has better parallelism properties. + +More information on BlockLLS solver: +* memory requirements: ~[32*K^3+256*NPoints] bytes for KxK grid with + NPoints-sized dataset +* serial running time: O(K^4+NPoints) +* parallelism potential: limited. You may get some sublinear gain when + working with large grids (K's in 256..512 range) + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- non-negative value: + * positive value means that some smoothing is applied + * zero value means that no smoothing is applied, and + corresponding entries of design matrix are numerically + zero and dropped from consideration. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgoblocklls(spline2dbuilder* state, + double lambdans, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state); + ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state); + state->solvertype = 1; + state->smoothing = lambdans; +} + + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "NaiveLLS". + +IMPORTANT: NaiveLLS is NOT intended to be used in real life code! This + algorithm solves problem by generated dense (K^2)x(K^2+NPoints) + matrix and solves linear least squares problem with dense + solver. + + It is here just to test BlockLLS against reference solver + (and maybe for someone trying to compare well optimized solver + against straightforward approach to the LLS problem). + +More information on naive LLS solver: +* memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid. +* serial running time: O(K^6+NPoints) for KxK grid +* when compared with BlockLLS, NaiveLLS has ~K larger memory demand and + ~K^2 larger running time. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- nonsmoothness penalty + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgonaivells(spline2dbuilder* state, + double lambdans, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state); + ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state); + state->solvertype = 2; + state->smoothing = lambdans; +} + + +/************************************************************************* +This function fits bicubic spline to current dataset, using current area/ +grid and current LLS solver. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - spline 2D builder object + +OUTPUT PARAMETERS: + S - 2D spline, fit result + Rep - fitting report, which provides some additional info about + errors, R2 coefficient and so on. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dfit(spline2dbuilder* state, + spline2dinterpolant* s, + spline2dfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + double xa; + double xb; + double ya; + double yb; + double xaraw; + double xbraw; + double yaraw; + double ybraw; + ae_int_t kx; + ae_int_t ky; + double hx; + double hy; + double invhx; + double invhy; + ae_int_t gridexpansion; + ae_int_t nzwidth; + ae_int_t bfrad; + ae_int_t npoints; + ae_int_t d; + ae_int_t ew; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_int_t k0; + ae_int_t k1; + double vx; + double vy; + ae_int_t arows; + ae_int_t acopied; + ae_int_t basecasex; + ae_int_t basecasey; + double eps; + ae_vector xywork; + ae_matrix vterm; + ae_vector tmpx; + ae_vector tmpy; + ae_vector tmp0; + ae_vector tmp1; + ae_vector meany; + ae_vector xyindex; + ae_vector tmpi; + spline1dinterpolant basis1; + sparsematrix av; + sparsematrix ah; + spline2dxdesignmatrix xdesignmatrix; + ae_vector z; + spline2dblockllsbuf blockllsbuf; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double tss; + ae_int_t dstidx; + + ae_frame_make(_state, &_frame_block); + memset(&xywork, 0, sizeof(xywork)); + memset(&vterm, 0, sizeof(vterm)); + memset(&tmpx, 0, sizeof(tmpx)); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&meany, 0, sizeof(meany)); + memset(&xyindex, 0, sizeof(xyindex)); + memset(&tmpi, 0, sizeof(tmpi)); + memset(&basis1, 0, sizeof(basis1)); + memset(&av, 0, sizeof(av)); + memset(&ah, 0, sizeof(ah)); + memset(&xdesignmatrix, 0, sizeof(xdesignmatrix)); + memset(&z, 0, sizeof(z)); + memset(&blockllsbuf, 0, sizeof(blockllsbuf)); + _spline2dinterpolant_clear(s); + _spline2dfitreport_clear(rep); + ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&meany, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmpi, 0, DT_INT, _state, ae_true); + _spline1dinterpolant_init(&basis1, _state, ae_true); + _sparsematrix_init(&av, _state, ae_true); + _sparsematrix_init(&ah, _state, ae_true); + _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true); + + nzwidth = 4; + bfrad = 2; + npoints = state->npoints; + d = state->d; + ew = 2+d; + + /* + * Integrity checks + */ + ae_assert(ae_fp_eq(state->sx,(double)(1)), "Spline2DFit: integrity error", _state); + ae_assert(ae_fp_eq(state->sy,(double)(1)), "Spline2DFit: integrity error", _state); + + /* + * Determine actual area size and grid step + * + * NOTE: initialize vars by zeros in order to avoid spurious + * compiler warnings. + */ + xa = (double)(0); + xb = (double)(0); + ya = (double)(0); + yb = (double)(0); + if( state->areatype==0 ) + { + if( npoints>0 ) + { + xa = state->xy.ptr.p_double[0]; + xb = state->xy.ptr.p_double[0]; + ya = state->xy.ptr.p_double[1]; + yb = state->xy.ptr.p_double[1]; + for(i=1; i<=npoints-1; i++) + { + xa = ae_minreal(xa, state->xy.ptr.p_double[i*ew+0], _state); + xb = ae_maxreal(xb, state->xy.ptr.p_double[i*ew+0], _state); + ya = ae_minreal(ya, state->xy.ptr.p_double[i*ew+1], _state); + yb = ae_maxreal(yb, state->xy.ptr.p_double[i*ew+1], _state); + } + } + else + { + xa = (double)(-1); + xb = (double)(1); + ya = (double)(-1); + yb = (double)(1); + } + } + else + { + if( state->areatype==1 ) + { + xa = state->xa; + xb = state->xb; + ya = state->ya; + yb = state->yb; + } + else + { + ae_assert(ae_false, "Assertion failed", _state); + } + } + if( ae_fp_eq(xa,xb) ) + { + v = xa; + if( ae_fp_greater_eq(v,(double)(0)) ) + { + xa = v/(double)2-(double)1; + xb = v*(double)2+(double)1; + } + else + { + xa = v*(double)2-(double)1; + xb = v/(double)2+(double)1; + } + } + if( ae_fp_eq(ya,yb) ) + { + v = ya; + if( ae_fp_greater_eq(v,(double)(0)) ) + { + ya = v/(double)2-(double)1; + yb = v*(double)2+(double)1; + } + else + { + ya = v*(double)2-(double)1; + yb = v/(double)2+(double)1; + } + } + ae_assert(ae_fp_less(xa,xb), "Spline2DFit: integrity error", _state); + ae_assert(ae_fp_less(ya,yb), "Spline2DFit: integrity error", _state); + kx = 0; + ky = 0; + if( state->gridtype==0 ) + { + kx = 4; + ky = 4; + } + else + { + if( state->gridtype==1 ) + { + kx = state->kx; + ky = state->ky; + } + else + { + ae_assert(ae_false, "Assertion failed", _state); + } + } + ae_assert(kx>0, "Spline2DFit: integrity error", _state); + ae_assert(ky>0, "Spline2DFit: integrity error", _state); + basecasex = -1; + basecasey = -1; + if( state->solvertype==3 ) + { + + /* + * Large-scale solver with special requirements to grid size. + */ + kx = ae_maxint(kx, nzwidth, _state); + ky = ae_maxint(ky, nzwidth, _state); + k = 1; + while(imin2(kx, ky, _state)>state->maxcoresize+1) + { + kx = idivup(kx-1, 2, _state)+1; + ky = idivup(ky-1, 2, _state)+1; + k = k+1; + } + basecasex = kx-1; + k0 = 1; + while(kx>state->maxcoresize+1) + { + basecasex = idivup(kx-1, 2, _state); + kx = basecasex+1; + k0 = k0+1; + } + while(k0>1) + { + kx = (kx-1)*2+1; + k0 = k0-1; + } + basecasey = ky-1; + k1 = 1; + while(ky>state->maxcoresize+1) + { + basecasey = idivup(ky-1, 2, _state); + ky = basecasey+1; + k1 = k1+1; + } + while(k1>1) + { + ky = (ky-1)*2+1; + k1 = k1-1; + } + while(k>1) + { + kx = (kx-1)*2+1; + ky = (ky-1)*2+1; + k = k-1; + } + + /* + * Grid is NOT expanded. We have very strict requirements on + * grid size, and we do not want to overcomplicate it by + * playing with grid size in order to add one more degree of + * freedom. It is not relevant for such large tasks. + */ + gridexpansion = 0; + } + else + { + + /* + * Medium-scale solvers which are tolerant to grid size. + */ + kx = ae_maxint(kx, nzwidth, _state); + ky = ae_maxint(ky, nzwidth, _state); + + /* + * Grid is expanded by 1 in order to add one more effective degree + * of freedom to the spline. Having additional nodes outside of the + * area allows us to emulate changes in the derivative at the bound + * without having specialized "boundary" version of the basis function. + */ + if( state->adddegreeoffreedom ) + { + gridexpansion = 1; + } + else + { + gridexpansion = 0; + } + } + hx = coalesce(xb-xa, 1.0, _state)/(double)(kx-1); + hy = coalesce(yb-ya, 1.0, _state)/(double)(ky-1); + invhx = (double)1/hx; + invhy = (double)1/hy; + + /* + * We determined "raw" grid size. Now perform a grid correction according + * to current grid expansion size. + */ + xaraw = xa; + yaraw = ya; + xbraw = xb; + ybraw = yb; + xa = xa-hx*(double)gridexpansion; + ya = ya-hy*(double)gridexpansion; + xb = xb+hx*(double)gridexpansion; + yb = yb+hy*(double)gridexpansion; + kx = kx+2*gridexpansion; + ky = ky+2*gridexpansion; + + /* + * Create output spline using transformed (unit-scale) + * coordinates, fill by zero values + */ + s->d = d; + s->n = kx; + s->m = ky; + s->stype = -3; + s->hasmissingcells = ae_false; + sfx = s->n*s->m*d; + sfy = 2*s->n*s->m*d; + sfxy = 3*s->n*s->m*d; + ae_vector_set_length(&s->x, s->n, _state); + ae_vector_set_length(&s->y, s->m, _state); + ae_vector_set_length(&s->f, 4*s->n*s->m*d, _state); + for(i=0; i<=s->n-1; i++) + { + s->x.ptr.p_double[i] = (double)(i); + } + for(i=0; i<=s->m-1; i++) + { + s->y.ptr.p_double[i] = (double)(i); + } + for(i=0; i<=4*s->n*s->m*d-1; i++) + { + s->f.ptr.p_double[i] = 0.0; + } + + /* + * Create local copy of dataset (only points in the grid are copied; + * we allow small step out of the grid, by Eps*H, in order to deal + * with numerical rounding errors). + * + * An additional copy of Y-values is created at columns beyond 2+J; + * it is preserved during all transformations. This copy is used + * to calculate error-related metrics. + * + * Calculate mean(Y), TSS + */ + ae_vector_set_length(&meany, d, _state); + for(j=0; j<=d-1; j++) + { + meany.ptr.p_double[j] = (double)(0); + } + rvectorsetlengthatleast(&xywork, npoints*ew, _state); + acopied = 0; + eps = 1.0E-6; + for(i=0; i<=npoints-1; i++) + { + vx = state->xy.ptr.p_double[i*ew+0]; + vy = state->xy.ptr.p_double[i*ew+1]; + if( ((ae_fp_less_eq(xaraw-eps*hx,vx)&&ae_fp_less_eq(vx,xbraw+eps*hx))&&ae_fp_less_eq(yaraw-eps*hy,vy))&&ae_fp_less_eq(vy,ybraw+eps*hy) ) + { + xywork.ptr.p_double[acopied*ew+0] = (vx-xa)*invhx; + xywork.ptr.p_double[acopied*ew+1] = (vy-ya)*invhy; + for(j=0; j<=d-1; j++) + { + v = state->xy.ptr.p_double[i*ew+2+j]; + xywork.ptr.p_double[acopied*ew+2+j] = v; + meany.ptr.p_double[j] = meany.ptr.p_double[j]+v; + } + acopied = acopied+1; + } + } + npoints = acopied; + for(j=0; j<=d-1; j++) + { + meany.ptr.p_double[j] = meany.ptr.p_double[j]/coalesce((double)(npoints), (double)(1), _state); + } + tss = 0.0; + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=d-1; j++) + { + tss = tss+ae_sqr(xywork.ptr.p_double[i*ew+2+j]-meany.ptr.p_double[j], _state); + } + } + tss = coalesce(tss, 1.0, _state); + + /* + * Handle prior term. + * Modify output spline. + * Quick exit if dataset is empty. + */ + buildpriorterm1(&xywork, npoints, 2, d, state->priorterm, state->priortermval, &vterm, _state); + if( npoints==0 ) + { + + /* + * Quick exit + */ + for(k=0; k<=s->n*s->m-1; k++) + { + k0 = k%s->n; + k1 = k/s->n; + for(j=0; j<=d-1; j++) + { + dstidx = d*(k1*s->n+k0)+j; + s->f.ptr.p_double[dstidx] = s->f.ptr.p_double[dstidx]+vterm.ptr.pp_double[j][0]*s->x.ptr.p_double[k0]+vterm.ptr.pp_double[j][1]*s->y.ptr.p_double[k1]+vterm.ptr.pp_double[j][2]; + s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0]; + s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1]; + } + } + for(i=0; i<=s->n-1; i++) + { + s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa; + } + for(i=0; i<=s->m-1; i++) + { + s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya; + } + for(i=0; i<=s->n*s->m*d-1; i++) + { + s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx; + s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy; + s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy; + } + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rep->r2 = 1.0; + ae_frame_leave(_state); + return; + } + + /* + * Build 1D compact basis function + * Generate design matrix + */ + ae_vector_set_length(&tmpx, 7, _state); + ae_vector_set_length(&tmpy, 7, _state); + tmpx.ptr.p_double[0] = (double)(-3); + tmpx.ptr.p_double[1] = (double)(-2); + tmpx.ptr.p_double[2] = (double)(-1); + tmpx.ptr.p_double[3] = (double)(0); + tmpx.ptr.p_double[4] = (double)(1); + tmpx.ptr.p_double[5] = (double)(2); + tmpx.ptr.p_double[6] = (double)(3); + tmpy.ptr.p_double[0] = (double)(0); + tmpy.ptr.p_double[1] = (double)(0); + tmpy.ptr.p_double[2] = (double)1/(double)12; + tmpy.ptr.p_double[3] = (double)2/(double)6; + tmpy.ptr.p_double[4] = (double)1/(double)12; + tmpy.ptr.p_double[5] = (double)(0); + tmpy.ptr.p_double[6] = (double)(0); + spline1dbuildcubic(&tmpx, &tmpy, tmpx.cnt, 2, 0.0, 2, 0.0, &basis1, _state); + + /* + * Solve. + * Update spline. + */ + if( state->solvertype==1 ) + { + + /* + * BlockLLS + */ + spline2d_reorderdatasetandbuildindex(&xywork, npoints, d, &tmp0, 0, kx, ky, &xyindex, &tmpi, _state); + spline2d_xdesigngenerate(&xywork, &xyindex, 0, kx, kx, 0, ky, ky, d, spline2d_lambdaregblocklls, state->smoothing, &basis1, &xdesignmatrix, _state); + spline2d_blockllsfit(&xdesignmatrix, state->lsqrcnt, &z, rep, tss, &blockllsbuf, _state); + spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state); + } + else + { + if( state->solvertype==2 ) + { + + /* + * NaiveLLS, reference implementation + */ + spline2d_generatedesignmatrix(&xywork, npoints, d, kx, ky, state->smoothing, spline2d_lambdaregblocklls, &basis1, &av, &ah, &arows, _state); + spline2d_naivellsfit(&av, &ah, arows, &xywork, kx, ky, npoints, d, state->lsqrcnt, &z, rep, tss, _state); + spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state); + } + else + { + if( state->solvertype==3 ) + { + + /* + * FastDDM method + */ + ae_assert(basecasex>0, "Spline2DFit: integrity error", _state); + ae_assert(basecasey>0, "Spline2DFit: integrity error", _state); + spline2d_fastddmfit(&xywork, npoints, d, kx, ky, basecasex, basecasey, state->maxcoresize, state->interfacesize, state->nlayers, state->smoothing, state->lsqrcnt, &basis1, s, rep, tss, _state); + } + else + { + ae_assert(ae_false, "Spline2DFit: integrity error", _state); + } + } + } + + /* + * Append prior term. + * Transform spline to original coordinates + */ + for(k=0; k<=s->n*s->m-1; k++) + { + k0 = k%s->n; + k1 = k/s->n; + for(j=0; j<=d-1; j++) + { + dstidx = d*(k1*s->n+k0)+j; + s->f.ptr.p_double[dstidx] = s->f.ptr.p_double[dstidx]+vterm.ptr.pp_double[j][0]*s->x.ptr.p_double[k0]+vterm.ptr.pp_double[j][1]*s->y.ptr.p_double[k1]+vterm.ptr.pp_double[j][2]; + s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0]; + s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1]; + } + } + for(i=0; i<=s->n-1; i++) + { + s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa; + } + for(i=0; i<=s->m-1; i++) + { + s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya; + } + for(i=0; i<=s->n*s->m*d-1; i++) + { + s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx; + s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy; + s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dalloc(ae_serializer* s, + const spline2dinterpolant* spline, + ae_state *_state) +{ + + + + /* + * Which spline 2D format to use - V1 (no missing nodes) or V2 (missing nodes)? + */ + if( !spline->hasmissingcells ) + { + + /* + * V1 format + */ + ae_serializer_alloc_entry(s); + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &spline->x, -1, _state); + allocrealarray(s, &spline->y, -1, _state); + allocrealarray(s, &spline->f, -1, _state); + } + else + { + + /* + * V2 format + */ + ae_serializer_alloc_entry(s); + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &spline->x, -1, _state); + allocrealarray(s, &spline->y, -1, _state); + allocrealarray(s, &spline->f, -1, _state); + allocbooleanarray(s, &spline->ismissingnode, -1, _state); + allocbooleanarray(s, &spline->ismissingcell, -1, _state); + } +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dserialize(ae_serializer* s, + const spline2dinterpolant* spline, + ae_state *_state) +{ + + + + /* + * Which spline 2D format to use - V1 (no missing nodes) or V2 (missing nodes)? + */ + if( !spline->hasmissingcells ) + { + + /* + * V1 format + */ + ae_serializer_serialize_int(s, getspline2dserializationcode(_state), _state); + + /* + * Data + */ + ae_serializer_serialize_int(s, spline->stype, _state); + ae_serializer_serialize_int(s, spline->n, _state); + ae_serializer_serialize_int(s, spline->m, _state); + ae_serializer_serialize_int(s, spline->d, _state); + serializerealarray(s, &spline->x, -1, _state); + serializerealarray(s, &spline->y, -1, _state); + serializerealarray(s, &spline->f, -1, _state); + } + else + { + + /* + * V2 format + */ + ae_serializer_serialize_int(s, getspline2dwithmissingnodesserializationcode(_state), _state); + + /* + * Data + */ + ae_serializer_serialize_int(s, spline->stype, _state); + ae_serializer_serialize_int(s, spline->n, _state); + ae_serializer_serialize_int(s, spline->m, _state); + ae_serializer_serialize_int(s, spline->d, _state); + serializerealarray(s, &spline->x, -1, _state); + serializerealarray(s, &spline->y, -1, _state); + serializerealarray(s, &spline->f, -1, _state); + serializebooleanarray(s, &spline->ismissingnode, -1, _state); + serializebooleanarray(s, &spline->ismissingcell, -1, _state); + } +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 28.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dunserialize(ae_serializer* s, + spline2dinterpolant* spline, + ae_state *_state) +{ + ae_int_t scode; + + _spline2dinterpolant_clear(spline); + + + /* + * Header + */ + ae_serializer_unserialize_int(s, &scode, _state); + ae_assert(scode==getspline2dserializationcode(_state)||scode==getspline2dwithmissingnodesserializationcode(_state), "Spline2DUnserialize: stream header corrupted", _state); + + /* + * Data + */ + if( scode==getspline2dserializationcode(_state) ) + { + ae_serializer_unserialize_int(s, &spline->stype, _state); + ae_serializer_unserialize_int(s, &spline->n, _state); + ae_serializer_unserialize_int(s, &spline->m, _state); + ae_serializer_unserialize_int(s, &spline->d, _state); + unserializerealarray(s, &spline->x, _state); + unserializerealarray(s, &spline->y, _state); + unserializerealarray(s, &spline->f, _state); + spline->hasmissingcells = ae_false; + } + else + { + ae_serializer_unserialize_int(s, &spline->stype, _state); + ae_serializer_unserialize_int(s, &spline->n, _state); + ae_serializer_unserialize_int(s, &spline->m, _state); + ae_serializer_unserialize_int(s, &spline->d, _state); + unserializerealarray(s, &spline->x, _state); + unserializerealarray(s, &spline->y, _state); + unserializerealarray(s, &spline->f, _state); + unserializebooleanarray(s, &spline->ismissingnode, _state); + unserializebooleanarray(s, &spline->ismissingcell, _state); + spline->hasmissingcells = ae_true; + } +} + + +/************************************************************************* +Internal subroutine. +Calculation of the first derivatives and the cross-derivative. +*************************************************************************/ +static void spline2d_bicubiccalcderivatives(/* Real */ const ae_matrix* a, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* bndbtm, + ae_int_t bndtypebtm, + /* Real */ const ae_vector* bndtop, + ae_int_t bndtypetop, + /* Real */ const ae_vector* bndlft, + ae_int_t bndtypelft, + /* Real */ const ae_vector* bndrgt, + ae_int_t bndtypergt, + /* Real */ const ae_vector* dfmixed, + /* Real */ ae_matrix* dx, + /* Real */ ae_matrix* dy, + /* Real */ ae_matrix* dxy, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector xt; + ae_vector yt; + ae_vector ft; + ae_vector dt; + ae_vector dleft; + ae_vector dright; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmp3; + ae_vector tmp4; + double s; + double ds; + double d2s; + double v0; + double v1; + spline1dinterpolant c; + + ae_frame_make(_state, &_frame_block); + memset(&xt, 0, sizeof(xt)); + memset(&yt, 0, sizeof(yt)); + memset(&ft, 0, sizeof(ft)); + memset(&dt, 0, sizeof(dt)); + memset(&dleft, 0, sizeof(dleft)); + memset(&dright, 0, sizeof(dright)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&tmp2, 0, sizeof(tmp2)); + memset(&tmp3, 0, sizeof(tmp3)); + memset(&tmp4, 0, sizeof(tmp4)); + memset(&c, 0, sizeof(c)); + ae_matrix_clear(dx); + ae_matrix_clear(dy); + ae_matrix_clear(dxy); + ae_vector_init(&xt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&yt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ft, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dleft, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dright, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp4, 0, DT_REAL, _state, ae_true); + _spline1dinterpolant_init(&c, _state, ae_true); + + ae_assert(imax4(bndtypebtm, bndtypetop, bndtypelft, bndtypergt, _state)<=2&&imin4(bndtypebtm, bndtypetop, bndtypelft, bndtypergt, _state)>=0, "SPLINE2D: integrity check 9513 failed", _state); + ae_matrix_set_length(dx, m, n, _state); + ae_matrix_set_length(dy, m, n, _state); + ae_matrix_set_length(dxy, m, n, _state); + + /* + * dF/dX + */ + ae_vector_set_length(&xt, n, _state); + ae_vector_set_length(&ft, n, _state); + v0 = (double)(0); + v1 = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + xt.ptr.p_double[j] = x->ptr.p_double[j]; + ft.ptr.p_double[j] = a->ptr.pp_double[i][j]; + } + if( bndtypelft!=0 ) + { + v0 = bndlft->ptr.p_double[i]; + } + if( bndtypergt!=0 ) + { + v1 = bndrgt->ptr.p_double[i]; + } + rallocv(n, &dt, _state); + spline1dgriddiffcubicinternal(&xt, &ft, n, bndtypelft, v0, bndtypergt, v1, &dt, &tmp0, &tmp1, &tmp2, &tmp3, &tmp4, _state); + for(j=0; j<=n-1; j++) + { + dx->ptr.pp_double[i][j] = dt.ptr.p_double[j]; + } + } + + /* + * dF/dY + */ + ae_vector_set_length(&xt, m, _state); + ae_vector_set_length(&ft, m, _state); + v0 = (double)(0); + v1 = (double)(0); + for(j=0; j<=n-1; j++) + { + for(i=0; i<=m-1; i++) + { + xt.ptr.p_double[i] = y->ptr.p_double[i]; + ft.ptr.p_double[i] = a->ptr.pp_double[i][j]; + } + if( bndtypebtm!=0 ) + { + v0 = bndbtm->ptr.p_double[j]; + } + if( bndtypetop!=0 ) + { + v1 = bndtop->ptr.p_double[j]; + } + rallocv(m, &dt, _state); + spline1dgriddiffcubicinternal(&xt, &ft, m, bndtypebtm, v0, bndtypetop, v1, &dt, &tmp0, &tmp1, &tmp2, &tmp3, &tmp4, _state); + for(i=0; i<=m-1; i++) + { + dy->ptr.pp_double[i][j] = dt.ptr.p_double[i]; + } + } + + /* + * d2F/dXdY + */ + rsetallocv(m, 0.0, &dleft, _state); + rsetallocv(m, 0.0, &dright, _state); + if( bndtypelft!=0 ) + { + rcopyallocv(m, y, &yt, _state); + rcopyallocv(m, bndlft, &dt, _state); + spline1dbuildcubic(&yt, &dt, m, bndtypebtm, rcase2(bndtypebtm!=0, dfmixed->ptr.p_double[0], 0.0, _state), bndtypetop, rcase2(bndtypetop!=0, dfmixed->ptr.p_double[2], (double)(0), _state), &c, _state); + for(j=0; j<=m-1; j++) + { + spline1ddiff(&c, y->ptr.p_double[j], &s, &ds, &d2s, _state); + dleft.ptr.p_double[j] = ds; + } + } + if( bndtypergt!=0 ) + { + rcopyallocv(m, y, &yt, _state); + rcopyallocv(m, bndrgt, &dt, _state); + spline1dbuildcubic(&yt, &dt, m, bndtypebtm, rcase2(bndtypebtm!=0, dfmixed->ptr.p_double[1], 0.0, _state), bndtypetop, rcase2(bndtypetop!=0, dfmixed->ptr.p_double[3], (double)(0), _state), &c, _state); + for(j=0; j<=m-1; j++) + { + spline1ddiff(&c, y->ptr.p_double[j], &s, &ds, &d2s, _state); + dright.ptr.p_double[j] = ds; + } + } + rallocv(n, &xt, _state); + rallocv(n, &ft, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + xt.ptr.p_double[j] = x->ptr.p_double[j]; + ft.ptr.p_double[j] = dy->ptr.pp_double[i][j]; + } + rallocv(n, &dt, _state); + spline1dgriddiffcubicinternal(&xt, &ft, n, bndtypelft, dleft.ptr.p_double[i], bndtypergt, dright.ptr.p_double[i], &dt, &tmp0, &tmp1, &tmp2, &tmp3, &tmp4, _state); + for(j=0; j<=n-1; j++) + { + dxy->ptr.pp_double[i][j] = dt.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. + +Calculation of the first derivatives and the cross-derivative subject to +a missing values map in IsMissingNode[]. + +The missing values map should be normalized, i.e. any isolated point that +is not part of some non-missing cell should be marked as missing too. +*************************************************************************/ +static void spline2d_bicubiccalcderivativesmissing(/* Real */ const ae_matrix* a, + /* Boolean */ const ae_vector* ismissingnode, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* dx, + /* Real */ ae_matrix* dy, + /* Real */ ae_matrix* dxy, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k1; + ae_int_t k2; + ae_vector xt; + ae_vector ft; + ae_vector t; + ae_vector b; + spline1dinterpolant c; + double s; + double ds; + double d2s; + + ae_frame_make(_state, &_frame_block); + memset(&xt, 0, sizeof(xt)); + memset(&ft, 0, sizeof(ft)); + memset(&t, 0, sizeof(t)); + memset(&b, 0, sizeof(b)); + memset(&c, 0, sizeof(c)); + ae_matrix_clear(dx); + ae_matrix_clear(dy); + ae_matrix_clear(dxy); + ae_vector_init(&xt, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ft, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&b, 0, DT_BOOL, _state, ae_true); + _spline1dinterpolant_init(&c, _state, ae_true); + + ae_assert(m>=2, "BicubicCalcDerivativesMissing: internal error (M<2)", _state); + ae_assert(n>=2, "BicubicCalcDerivativesMissing: internal error (N<2)", _state); + + /* + * Allocate DX/DY/DXY and make initial fill by zeros + */ + rsetallocm(m, n, 0.0, dx, _state); + rsetallocm(m, n, 0.0, dy, _state); + rsetallocm(m, n, 0.0, dxy, _state); + + /* + * dF/dX + */ + ballocv(n, &b, _state); + ae_vector_set_length(&xt, n, _state); + ae_vector_set_length(&ft, n, _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=m-1; i++) + { + k1 = -1; + k2 = -1; + rcopyrv(n, a, i, &t, _state); + for(j=0; j<=n-1; j++) + { + b.ptr.p_bool[j] = ismissingnode->ptr.p_bool[i*n+j]; + } + while(spline2d_scanfornonmissingsegment(&b, n, &k1, &k2, _state)) + { + ae_v_move(&xt.ptr.p_double[0], 1, &x->ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + ae_v_move(&ft.ptr.p_double[0], 1, &t.ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + spline1dbuildcubic(&xt, &ft, k2-k1+1, 0, 0.0, 0, 0.0, &c, _state); + for(j=0; j<=k2-k1; j++) + { + spline1ddiff(&c, x->ptr.p_double[k1+j], &s, &ds, &d2s, _state); + dx->ptr.pp_double[i][k1+j] = ds; + } + } + } + + /* + * dF/dY + */ + ballocv(m, &b, _state); + ae_vector_set_length(&xt, m, _state); + ae_vector_set_length(&ft, m, _state); + ae_vector_set_length(&t, m, _state); + for(j=0; j<=n-1; j++) + { + k1 = -1; + k2 = -1; + ae_v_move(&t.ptr.p_double[0], 1, &a->ptr.pp_double[0][j], a->stride, ae_v_len(0,m-1)); + for(i=0; i<=m-1; i++) + { + b.ptr.p_bool[i] = ismissingnode->ptr.p_bool[i*n+j]; + } + while(spline2d_scanfornonmissingsegment(&b, m, &k1, &k2, _state)) + { + ae_v_move(&xt.ptr.p_double[0], 1, &y->ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + ae_v_move(&ft.ptr.p_double[0], 1, &t.ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + spline1dbuildcubic(&xt, &ft, k2-k1+1, 0, 0.0, 0, 0.0, &c, _state); + for(i=0; i<=k2-k1; i++) + { + spline1ddiff(&c, y->ptr.p_double[k1+i], &s, &ds, &d2s, _state); + dy->ptr.pp_double[k1+i][j] = ds; + } + } + } + + /* + * d2F/dXdY + */ + ballocv(n, &b, _state); + ae_vector_set_length(&xt, n, _state); + ae_vector_set_length(&ft, n, _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=m-1; i++) + { + k1 = -1; + k2 = -1; + ae_v_move(&t.ptr.p_double[0], 1, &dy->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + for(j=0; j<=n-1; j++) + { + b.ptr.p_bool[j] = ismissingnode->ptr.p_bool[i*n+j]; + } + while(spline2d_scanfornonmissingsegment(&b, n, &k1, &k2, _state)) + { + ae_v_move(&xt.ptr.p_double[0], 1, &x->ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + ae_v_move(&ft.ptr.p_double[0], 1, &t.ptr.p_double[k1], 1, ae_v_len(0,k2-k1)); + spline1dbuildcubic(&xt, &ft, k2-k1+1, 0, 0.0, 0, 0.0, &c, _state); + for(j=0; j<=k2-k1; j++) + { + spline1ddiff(&c, x->ptr.p_double[k1+j], &s, &ds, &d2s, _state); + dxy->ptr.pp_double[i][k1+j] = ds; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Scans array IsMissing[] for segment containing non-missing values. + +On the first call I1=I2=-1. +Ater return from subsequent call either +* 0<=I1=2, "ScanForNonmissingSegment: internal error (N<2)", _state); + ae_assert(*i1<=(*i2), "ScanForNonmissingSegment: internal error (I1>I2)", _state); + result = ae_false; + + /* + * Initial call: prepare and pass + */ + if( *i1<0||*i2<0 ) + { + *i1 = -1; + *i2 = -1; + } + + /* + * Scan for the next segment + */ + if( *i1=n ) + { + return result; + } + if( !ismissing->ptr.p_bool[i] ) + { + *i1 = i; + break; + } + i = i+1; + } + + /* + * Scan for segment's end + */ + for(;;) + { + if( i>=n ) + { + *i2 = n-1; + break; + } + if( ismissing->ptr.p_bool[i] ) + { + *i2 = i-1; + break; + } + i = i+1; + } + ae_assert(*i2>(*i1), "ScanForFiniteSegment: internal error (segment is too short)", _state); + result = ae_true; + } + return result; +} + + +/************************************************************************* +Actual construction of a Hermite spline + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_spline2dbuildhermitevbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Real */ const ae_vector* _dfdx, + /* Real */ const ae_vector* _dfdy, + /* Real */ const ae_vector* _d2fdxdy, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector f; + ae_vector dfdx; + ae_vector dfdy; + ae_vector d2fdxdy; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + + ae_frame_make(_state, &_frame_block); + memset(&f, 0, sizeof(f)); + memset(&dfdx, 0, sizeof(dfdx)); + memset(&dfdy, 0, sizeof(dfdy)); + memset(&d2fdxdy, 0, sizeof(d2fdxdy)); + ae_vector_init_copy(&f, _f, _state, ae_true); + ae_vector_init_copy(&dfdx, _dfdx, _state, ae_true); + ae_vector_init_copy(&dfdy, _dfdy, _state, ae_true); + ae_vector_init_copy(&d2fdxdy, _d2fdxdy, _state, ae_true); + + ae_assert(n>=2, "Spline2DBuildHermiteV: N is less than 2", _state); + ae_assert(m>=2, "Spline2DBuildHermiteV: M is less than 2", _state); + ae_assert(d>=1, "Spline2DBuildHermiteV: invalid argument D (D<1)", _state); + ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildHermiteV: X or Y is too short (Length(X/Y)=k, "Spline2DBuildHermiteV: F is too short (Length(F)=k, "Spline2DBuildHermiteV: dFdX is too short (Length(dFdX)=k, "Spline2DBuildHermiteV: dFdY is too short (Length(dFdY)=k, "Spline2DBuildHermiteV: d2FdXdY is too short (Length(d2FdXdY)d = d; + c->n = n; + c->m = m; + c->stype = -3; + c->hasmissingcells = ae_false; + k = 4*k; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->f, k, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + spline2d_sortgrid(&c->x, n, &c->y, m, &c->x, ae_false, &c->x, ae_false, &c->y, ae_false, &c->y, ae_false, &f, d, &dfdx, &dfdy, &d2fdxdy, ae_true, _state); + for(di=0; di<=c->d-1; di++) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->n-1; j++) + { + k = c->d*(i*c->n+j)+di; + c->f.ptr.p_double[k] = f.ptr.p_double[c->d*(i*c->n+j)+di]; + c->f.ptr.p_double[c->n*c->m*c->d+k] = dfdx.ptr.p_double[c->d*(i*c->n+j)+di]; + c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dfdy.ptr.p_double[c->d*(i*c->n+j)+di]; + c->f.ptr.p_double[3*c->n*c->m*c->d+k] = d2fdxdy.ptr.p_double[c->d*(i*c->n+j)+di]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function generates design matrix for the problem (in fact, two design +matrices are generated: "vertical" one and transposed (horizontal) one. + +INPUT PARAMETERS: + XY - array[NPoints*(2+D)]; dataset after scaling in such + way that grid step is equal to 1.0 in both dimensions. + NPoints - dataset size, NPoints>=1 + KX, KY - grid size, KX,KY>=4 + Smoothing - nonlinearity penalty coefficient, >=0 + LambdaReg - regularization coefficient, >=0 + Basis1 - basis spline, expected to be non-zero only at [-2,+2] + AV, AH - possibly preallocated buffers + +OUTPUT PARAMETERS: + AV - sparse matrix[ARows,KX*KY]; design matrix + AH - transpose of AV + ARows - number of rows in design matrix + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_generatedesignmatrix(/* Real */ const ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + ae_int_t kx, + ae_int_t ky, + double smoothing, + double lambdareg, + const spline1dinterpolant* basis1, + sparsematrix* av, + sparsematrix* ah, + ae_int_t* arows, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nzwidth; + ae_int_t nzshift; + ae_int_t ew; + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t k0; + ae_int_t k1; + ae_int_t dstidx; + double v; + double v0; + double v1; + double v2; + double w0; + double w1; + double w2; + ae_vector crx; + ae_vector cry; + ae_vector nrs; + ae_matrix d2x; + ae_matrix d2y; + ae_matrix dxy; + + ae_frame_make(_state, &_frame_block); + memset(&crx, 0, sizeof(crx)); + memset(&cry, 0, sizeof(cry)); + memset(&nrs, 0, sizeof(nrs)); + memset(&d2x, 0, sizeof(d2x)); + memset(&d2y, 0, sizeof(d2y)); + memset(&dxy, 0, sizeof(dxy)); + *arows = 0; + ae_vector_init(&crx, 0, DT_INT, _state, ae_true); + ae_vector_init(&cry, 0, DT_INT, _state, ae_true); + ae_vector_init(&nrs, 0, DT_INT, _state, ae_true); + ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); + + nzwidth = 4; + nzshift = 1; + ae_assert(npoints>0, "Spline2DFit: integrity check failed", _state); + ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state); + ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state); + ew = 2+d; + + /* + * Determine canonical rectangle for every point. Every point of the dataset is + * influenced by at most NZWidth*NZWidth basis functions, which form NZWidth*NZWidth + * canonical rectangle. + * + * Thus, we have (KX-NZWidth+1)*(KY-NZWidth+1) overlapping canonical rectangles. + * Assigning every point to its rectangle simplifies creation of sparse basis + * matrix at the next steps. + */ + ae_vector_set_length(&crx, npoints, _state); + ae_vector_set_length(&cry, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + crx.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+0], _state)-nzshift, 0, kx-nzwidth, _state); + cry.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+1], _state)-nzshift, 0, ky-nzwidth, _state); + } + + /* + * Create vertical and horizontal design matrices + */ + *arows = npoints+kx*ky; + if( ae_fp_neq(smoothing,0.0) ) + { + ae_assert(ae_fp_greater(smoothing,0.0), "Spline2DFit: integrity check failed", _state); + *arows = *arows+3*(kx-2)*(ky-2); + } + ae_vector_set_length(&nrs, *arows, _state); + dstidx = 0; + for(i=0; i<=npoints-1; i++) + { + nrs.ptr.p_int[dstidx+i] = nzwidth*nzwidth; + } + dstidx = dstidx+npoints; + for(i=0; i<=kx*ky-1; i++) + { + nrs.ptr.p_int[dstidx+i] = 1; + } + dstidx = dstidx+kx*ky; + if( ae_fp_neq(smoothing,0.0) ) + { + for(i=0; i<=3*(kx-2)*(ky-2)-1; i++) + { + nrs.ptr.p_int[dstidx+i] = 3*3; + } + dstidx = dstidx+3*(kx-2)*(ky-2); + } + ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state); + sparsecreatecrs(*arows, kx*ky, &nrs, av, _state); + dstidx = 0; + for(i=0; i<=npoints-1; i++) + { + for(j1=0; j1<=nzwidth-1; j1++) + { + for(j0=0; j0<=nzwidth-1; j0++) + { + v0 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+0]-(double)(crx.ptr.p_int[i]+j0), _state); + v1 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+1]-(double)(cry.ptr.p_int[i]+j1), _state); + sparseset(av, dstidx+i, (cry.ptr.p_int[i]+j1)*kx+(crx.ptr.p_int[i]+j0), v0*v1, _state); + } + } + } + dstidx = dstidx+npoints; + for(i=0; i<=kx*ky-1; i++) + { + sparseset(av, dstidx+i, i, lambdareg, _state); + } + dstidx = dstidx+kx*ky; + if( ae_fp_neq(smoothing,0.0) ) + { + + /* + * Smoothing is applied. Because all grid nodes are same, + * we apply same smoothing kernel, which is calculated only + * once at the beginning of design matrix generation. + */ + ae_matrix_set_length(&d2x, 3, 3, _state); + ae_matrix_set_length(&d2y, 3, 3, _state); + ae_matrix_set_length(&dxy, 3, 3, _state); + for(j1=0; j1<=2; j1++) + { + for(j0=0; j0<=2; j0++) + { + d2x.ptr.pp_double[j0][j1] = 0.0; + d2y.ptr.pp_double[j0][j1] = 0.0; + dxy.ptr.pp_double[j0][j1] = 0.0; + } + } + for(k1=0; k1<=2; k1++) + { + for(k0=0; k0<=2; k0++) + { + spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state); + spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state); + d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0; + d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0; + dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1; + } + } + + /* + * Now, kernel is ready - apply it to all inner nodes of the grid. + */ + for(j1=1; j1<=ky-2; j1++) + { + for(j0=1; j0<=kx-2; j0++) + { + + /* + * d2F/dx2 term + */ + v = smoothing; + for(k1=-1; k1<=1; k1++) + { + for(k0=-1; k0<=1; k0++) + { + sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2x.ptr.pp_double[1+k0][1+k1], _state); + } + } + dstidx = dstidx+1; + + /* + * d2F/dy2 term + */ + v = smoothing; + for(k1=-1; k1<=1; k1++) + { + for(k0=-1; k0<=1; k0++) + { + sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2y.ptr.pp_double[1+k0][1+k1], _state); + } + } + dstidx = dstidx+1; + + /* + * 2*d2F/dxdy term + */ + v = ae_sqrt((double)(2), _state)*smoothing; + for(k1=-1; k1<=1; k1++) + { + for(k0=-1; k0<=1; k0++) + { + sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*dxy.ptr.pp_double[1+k0][1+k1], _state); + } + } + dstidx = dstidx+1; + } + } + } + ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state); + sparsecopy(av, ah, _state); + sparsetransposecrs(ah, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function updates table of spline values/derivatives using coefficients +for a layer of basis functions. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_updatesplinetable(/* Real */ const ae_vector* z, + ae_int_t kx, + ae_int_t ky, + ae_int_t d, + const spline1dinterpolant* basis1, + ae_int_t bfrad, + /* Real */ ae_vector* ftbl, + ae_int_t m, + ae_int_t n, + ae_int_t scalexy, + ae_state *_state) +{ + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t j0a; + ae_int_t j0b; + ae_int_t j1a; + ae_int_t j1b; + double v; + double v0; + double v1; + double v01; + double v11; + double rdummy; + ae_int_t dstidx; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double invscalexy; + + + ae_assert(n==(kx-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state); + ae_assert(m==(ky-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state); + invscalexy = (double)1/(double)scalexy; + sfx = n*m*d; + sfy = 2*n*m*d; + sfxy = 3*n*m*d; + for(k=0; k<=kx*ky-1; k++) + { + k0 = k%kx; + k1 = k/kx; + j0a = iboundval(k0*scalexy-(bfrad*scalexy-1), 0, n-1, _state); + j0b = iboundval(k0*scalexy+(bfrad*scalexy-1), 0, n-1, _state); + j1a = iboundval(k1*scalexy-(bfrad*scalexy-1), 0, m-1, _state); + j1b = iboundval(k1*scalexy+(bfrad*scalexy-1), 0, m-1, _state); + for(j1=j1a; j1<=j1b; j1++) + { + spline1ddiff(basis1, (double)(j1-k1*scalexy)*invscalexy, &v1, &v11, &rdummy, _state); + v11 = v11*invscalexy; + for(j0=j0a; j0<=j0b; j0++) + { + spline1ddiff(basis1, (double)(j0-k0*scalexy)*invscalexy, &v0, &v01, &rdummy, _state); + v01 = v01*invscalexy; + for(j=0; j<=d-1; j++) + { + dstidx = d*(j1*n+j0)+j; + v = z->ptr.p_double[j*kx*ky+k]; + ftbl->ptr.p_double[dstidx] = ftbl->ptr.p_double[dstidx]+v0*v1*v; + ftbl->ptr.p_double[sfx+dstidx] = ftbl->ptr.p_double[sfx+dstidx]+v01*v1*v; + ftbl->ptr.p_double[sfy+dstidx] = ftbl->ptr.p_double[sfy+dstidx]+v0*v11*v; + ftbl->ptr.p_double[sfxy+dstidx] = ftbl->ptr.p_double[sfxy+dstidx]+v01*v11*v; + } + } + } + } +} + + +/************************************************************************* +This function performs fitting with FastDDM solver. +Internal function, never use it directly. + +INPUT PARAMETERS: + XY - array[NPoints*(2+D)], dataset; destroyed in process + KX, KY - grid size + TileSize - tile size + InterfaceSize- interface size + NPoints - points count + D - number of components in vector-valued spline, D>=1 + LSQRCnt - number of iterations, non-zero: + * LSQRCnt>0 means that specified amount of preconditioned + LSQR iterations will be performed to solve problem; + usually we need 2..5 its. Recommended option - best + convergence and stability/quality. + * LSQRCnt<0 means that instead of LSQR we use iterative + refinement on normal equations. Again, 2..5 its is enough. + Basis1 - basis spline, expected to be non-zero only at [-2,+2] + Z - possibly preallocated buffer for solution + Residuals - possibly preallocated buffer for residuals at dataset points + Rep - report structure; fields which are not set by this function + are left intact + TSS - total sum of squares; used to calculate R2 + + +OUTPUT PARAMETERS: + XY - destroyed in process + Z - array[KX*KY*D], filled by solution; KX*KY coefficients + corresponding to each of D dimensions are stored contiguously. + Rep - following fields are set: + * Rep.RMSError + * Rep.AvgError + * Rep.MaxError + * Rep.R2 + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_fastddmfit(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + ae_int_t kx, + ae_int_t ky, + ae_int_t basecasex, + ae_int_t basecasey, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t nlayers, + double smoothing, + ae_int_t lsqrcnt, + const spline1dinterpolant* basis1, + spline2dinterpolant* spline, + spline2dfitreport* rep, + double tss, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t nzwidth; + ae_int_t xew; + ae_int_t ntotallayers; + ae_int_t scaleidx; + ae_int_t scalexy; + double invscalexy; + ae_int_t kxcur; + ae_int_t kycur; + ae_int_t tilescount0; + ae_int_t tilescount1; + double v; + double rss; + ae_vector yraw; + ae_vector xyindex; + ae_vector tmp0; + ae_vector bufi; + spline2dfastddmbuf seed; + ae_shared_pool pool; + spline2dxdesignmatrix xdesignmatrix; + spline2dblockllsbuf blockllsbuf; + spline2dfitreport dummyrep; + + ae_frame_make(_state, &_frame_block); + memset(&yraw, 0, sizeof(yraw)); + memset(&xyindex, 0, sizeof(xyindex)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&bufi, 0, sizeof(bufi)); + memset(&seed, 0, sizeof(seed)); + memset(&pool, 0, sizeof(pool)); + memset(&xdesignmatrix, 0, sizeof(xdesignmatrix)); + memset(&blockllsbuf, 0, sizeof(blockllsbuf)); + memset(&dummyrep, 0, sizeof(dummyrep)); + ae_vector_init(&yraw, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bufi, 0, DT_INT, _state, ae_true); + _spline2dfastddmbuf_init(&seed, _state, ae_true); + ae_shared_pool_init(&pool, _state, ae_true); + _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true); + _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true); + _spline2dfitreport_init(&dummyrep, _state, ae_true); + + + /* + * Dataset metrics and integrity checks + */ + nzwidth = 4; + xew = 2+d; + ae_assert(maxcoresize>=2, "Spline2DFit: integrity check failed", _state); + ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state); + ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state); + ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state); + + /* + * Verify consistency of the grid size (KX,KY) with basecase sizes. + * Determine full number of layers. + */ + ae_assert(basecasex<=maxcoresize, "Spline2DFit: integrity error", _state); + ae_assert(basecasey<=maxcoresize, "Spline2DFit: integrity error", _state); + ntotallayers = 1; + scalexy = 1; + kxcur = kx; + kycur = ky; + while(kxcur>basecasex+1&&kycur>basecasey+1) + { + ae_assert(kxcur%2==1, "Spline2DFit: integrity error", _state); + ae_assert(kycur%2==1, "Spline2DFit: integrity error", _state); + kxcur = (kxcur-1)/2+1; + kycur = (kycur-1)/2+1; + scalexy = scalexy*2; + inc(&ntotallayers, _state); + } + invscalexy = (double)1/(double)scalexy; + ae_assert((kxcur<=maxcoresize+1&&kxcur==basecasex+1)||kxcur%basecasex==1, "Spline2DFit: integrity error", _state); + ae_assert((kycur<=maxcoresize+1&&kycur==basecasey+1)||kycur%basecasey==1, "Spline2DFit: integrity error", _state); + ae_assert(kxcur==basecasex+1||kycur==basecasey+1, "Spline2DFit: integrity error", _state); + + /* + * Initial scaling of dataset. + * Store original target values to YRaw. + */ + rvectorsetlengthatleast(&yraw, npoints*d, _state); + for(i=0; i<=npoints-1; i++) + { + xy->ptr.p_double[xew*i+0] = xy->ptr.p_double[xew*i+0]*invscalexy; + xy->ptr.p_double[xew*i+1] = xy->ptr.p_double[xew*i+1]*invscalexy; + for(j=0; j<=d-1; j++) + { + yraw.ptr.p_double[i*d+j] = xy->ptr.p_double[xew*i+2+j]; + } + } + kxcur = (kx-1)/scalexy+1; + kycur = (ky-1)/scalexy+1; + + /* + * Build initial dataset index; area is divided into (KXCur-1)*(KYCur-1) + * cells, with contiguous storage of points in the same cell. + * Iterate over different scales + */ + ae_shared_pool_set_seed(&pool, &seed, (ae_int_t)sizeof(seed), (ae_copy_constructor)_spline2dfastddmbuf_init_copy, (ae_destructor)_spline2dfastddmbuf_destroy, _state); + spline2d_reorderdatasetandbuildindex(xy, npoints, d, &yraw, d, kxcur, kycur, &xyindex, &bufi, _state); + for(scaleidx=ntotallayers-1; scaleidx>=0; scaleidx--) + { + if( (nlayers>0&&scaleidxrmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rss = 0.0; + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=d-1; j++) + { + v = xy->ptr.p_double[i*xew+2+j]; + rss = rss+v*v; + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state); + rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state); + rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive fitting function for FastDDM algorithm. + +Works with KX*KY grid, with KX=BasecaseX*TilesCountX+1 and KY=BasecaseY*TilesCountY+1, +which is partitioned into TilesCountX*TilesCountY tiles, each having size +BasecaseX*BasecaseY. + +This function processes tiles in range [TileX0,TileX1)x[TileY0,TileY1) and +recursively divides this range until we move down to single tile, which +is processed with BlockLLS solver. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_fastddmfitlayer(/* Real */ const ae_vector* xy, + ae_int_t d, + ae_int_t scalexy, + /* Integer */ const ae_vector* xyindex, + ae_int_t basecasex, + ae_int_t tilex0, + ae_int_t tilex1, + ae_int_t tilescountx, + ae_int_t basecasey, + ae_int_t tiley0, + ae_int_t tiley1, + ae_int_t tilescounty, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t lsqrcnt, + double lambdareg, + const spline1dinterpolant* basis1, + ae_shared_pool* pool, + spline2dinterpolant* spline, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t kx; + ae_int_t ky; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t bfrad; + ae_int_t xa; + ae_int_t xb; + ae_int_t ya; + ae_int_t yb; + ae_int_t tile0; + ae_int_t tile1; + ae_int_t tilesize0; + ae_int_t tilesize1; + ae_int_t sfx; + ae_int_t sfy; + ae_int_t sfxy; + double dummytss; + double invscalexy; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t offs; + double vs; + double vsx; + double vsy; + double vsxx; + double vsxy; + double vsyy; + spline2dfastddmbuf *buf; + ae_smart_ptr _buf; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + + /* + * Dataset metrics and fast integrity checks; + * no code with side effects is allowed before parallel split. + */ + bfrad = 2; + invscalexy = (double)1/(double)scalexy; + kx = basecasex*tilescountx+1; + ky = basecasey*tilescounty+1; + + /* + * Parallelism; because this function is intended for + * large-scale problems, we always try to: + * * invoke parallel execution mode + * * activate spawn support + */ + if( _trypexec_spline2d_fastddmfitlayer(xy,d,scalexy,xyindex,basecasex,tilex0,tilex1,tilescountx,basecasey,tiley0,tiley1,tilescounty,maxcoresize,interfacesize,lsqrcnt,lambdareg,basis1,pool,spline, _state) ) + { + ae_frame_leave(_state); + return; + } + if( imax2(tiley1-tiley0, tilex1-tilex0, _state)>=2 ) + { + if( tiley1-tiley0>tilex1-tilex0 ) + { + + /* + * Split problem in Y dimension + * + * NOTE: recursive calls to FastDDMFitLayer() compute + * residuals in the inner cells defined by XYIndex[], + * but we still have to compute residuals for cells + * BETWEEN two recursive subdivisions of the task. + */ + tiledsplit(tiley1-tiley0, 1, &j0, &j1, _state); + spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0, tiley0+j0, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state); + spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0+j0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state); + } + else + { + + /* + * Split problem in X dimension + * + * NOTE: recursive calls to FastDDMFitLayer() compute + * residuals in the inner cells defined by XYIndex[], + * but we still have to compute residuals for cells + * BETWEEN two recursive subdivisions of the task. + */ + tiledsplit(tilex1-tilex0, 1, &j0, &j1, _state); + spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex0+j0, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state); + spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0+j0, tilex1, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state); + } + ae_frame_leave(_state); + return; + } + ae_assert(tiley0==tiley1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state); + ae_assert(tilex0==tilex1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state); + tile1 = tiley0; + tile0 = tilex0; + + /* + * Retrieve temporaries + */ + ae_shared_pool_retrieve(pool, &_buf, _state); + + /* + * Analyze dataset + */ + xa = iboundval(tile0*basecasex-interfacesize, 0, kx, _state); + xb = iboundval((tile0+1)*basecasex+interfacesize, 0, kx, _state); + ya = iboundval(tile1*basecasey-interfacesize, 0, ky, _state); + yb = iboundval((tile1+1)*basecasey+interfacesize, 0, ky, _state); + tilesize0 = xb-xa; + tilesize1 = yb-ya; + + /* + * Solve current chunk with BlockLLS + */ + dummytss = 1.0; + spline2d_xdesigngenerate(xy, xyindex, xa, xb, kx, ya, yb, ky, d, lambdareg, 0.0, basis1, &buf->xdesignmatrix, _state); + spline2d_blockllsfit(&buf->xdesignmatrix, lsqrcnt, &buf->tmpz, &buf->dummyrep, dummytss, &buf->blockllsbuf, _state); + buf->localmodel.d = d; + buf->localmodel.m = tilesize1; + buf->localmodel.n = tilesize0; + buf->localmodel.stype = -3; + buf->localmodel.hasmissingcells = ae_false; + rvectorsetlengthatleast(&buf->localmodel.x, tilesize0, _state); + rvectorsetlengthatleast(&buf->localmodel.y, tilesize1, _state); + rvectorsetlengthatleast(&buf->localmodel.f, tilesize0*tilesize1*d*4, _state); + for(i=0; i<=tilesize0-1; i++) + { + buf->localmodel.x.ptr.p_double[i] = (double)(xa+i); + } + for(i=0; i<=tilesize1-1; i++) + { + buf->localmodel.y.ptr.p_double[i] = (double)(ya+i); + } + for(i=0; i<=tilesize0*tilesize1*d*4-1; i++) + { + buf->localmodel.f.ptr.p_double[i] = 0.0; + } + spline2d_updatesplinetable(&buf->tmpz, tilesize0, tilesize1, d, basis1, bfrad, &buf->localmodel.f, tilesize1, tilesize0, 1, _state); + + /* + * Transform local spline to original coordinates + */ + sfx = buf->localmodel.n*buf->localmodel.m*d; + sfy = 2*buf->localmodel.n*buf->localmodel.m*d; + sfxy = 3*buf->localmodel.n*buf->localmodel.m*d; + for(i=0; i<=tilesize0-1; i++) + { + buf->localmodel.x.ptr.p_double[i] = buf->localmodel.x.ptr.p_double[i]*(double)scalexy; + } + for(i=0; i<=tilesize1-1; i++) + { + buf->localmodel.y.ptr.p_double[i] = buf->localmodel.y.ptr.p_double[i]*(double)scalexy; + } + for(i=0; i<=tilesize0*tilesize1*d-1; i++) + { + buf->localmodel.f.ptr.p_double[sfx+i] = buf->localmodel.f.ptr.p_double[sfx+i]*invscalexy; + buf->localmodel.f.ptr.p_double[sfy+i] = buf->localmodel.f.ptr.p_double[sfy+i]*invscalexy; + buf->localmodel.f.ptr.p_double[sfxy+i] = buf->localmodel.f.ptr.p_double[sfxy+i]*(invscalexy*invscalexy); + } + + /* + * Output results; for inner and topmost/leftmost tiles we output only BasecaseX*BasecaseY + * inner elements; for rightmost/bottom ones we also output one column/row of the interface + * part. + * + * Such complexity is explained by the fact that area size (by design) is not evenly divisible + * by the tile size; it is divisible with remainder=1, and we expect that interface size is + * at least 1, so we can fill the missing rightmost/bottom elements of Z by the interface + * values. + */ + ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state); + sfx = spline->n*spline->m*d; + sfy = 2*spline->n*spline->m*d; + sfxy = 3*spline->n*spline->m*d; + cnt0 = basecasex*scalexy; + cnt1 = basecasey*scalexy; + if( tile0==tilescountx-1 ) + { + inc(&cnt0, _state); + } + if( tile1==tilescounty-1 ) + { + inc(&cnt1, _state); + } + offs = d*(spline->n*tile1*basecasey*scalexy+tile0*basecasex*scalexy); + for(j1=0; j1<=cnt1-1; j1++) + { + for(j0=0; j0<=cnt0-1; j0++) + { + for(j=0; j<=d-1; j++) + { + spline2ddiff2vi(&buf->localmodel, (double)(tile0*basecasex*scalexy+j0), (double)(tile1*basecasey*scalexy+j1), j, &vs, &vsx, &vsy, &vsxx, &vsxy, &vsyy, _state); + spline->f.ptr.p_double[offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[offs+d*(spline->n*j1+j0)+j]+vs; + spline->f.ptr.p_double[sfx+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfx+offs+d*(spline->n*j1+j0)+j]+vsx; + spline->f.ptr.p_double[sfy+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfy+offs+d*(spline->n*j1+j0)+j]+vsy; + spline->f.ptr.p_double[sfxy+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfxy+offs+d*(spline->n*j1+j0)+j]+vsxy; + } + } + } + + /* + * Recycle temporaries + */ + ae_shared_pool_recycle(pool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real */ const ae_vector* xy, + ae_int_t d, + ae_int_t scalexy, + /* Integer */ const ae_vector* xyindex, + ae_int_t basecasex, + ae_int_t tilex0, + ae_int_t tilex1, + ae_int_t tilescountx, + ae_int_t basecasey, + ae_int_t tiley0, + ae_int_t tiley1, + ae_int_t tilescounty, + ae_int_t maxcoresize, + ae_int_t interfacesize, + ae_int_t lsqrcnt, + double lambdareg, + const spline1dinterpolant* basis1, + ae_shared_pool* pool, + spline2dinterpolant* spline, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function performs fitting with BlockLLS solver. Internal function, +never use it directly. + +IMPORTANT: performance and memory requirements of this function are + asymmetric w.r.t. KX and KY: it has + * O(KY*KX^2) memory requirements + * O(KY*KX^3) running time + Thus, if you have large KY and small KX, simple transposition + of your dataset may give you great speedup. + +INPUT PARAMETERS: + AV - sparse matrix, [ARows,KX*KY] in size. "Vertical" version + of design matrix, rows [0,NPoints) contain values of basis + functions at dataset points. Other rows are used for + nonlinearity penalty and other stuff like that. + AH - transpose(AV), "horizontal" version of AV + ARows - rows count + XY - array[NPoints*(2+D)], dataset + KX, KY - grid size + NPoints - points count + D - number of components in vector-valued spline, D>=1 + LSQRCnt - number of iterations, non-zero: + * LSQRCnt>0 means that specified amount of preconditioned + LSQR iterations will be performed to solve problem; + usually we need 2..5 its. Recommended option - best + convergence and stability/quality. + * LSQRCnt<0 means that instead of LSQR we use iterative + refinement on normal equations. Again, 2..5 its is enough. + Z - possibly preallocated buffer for solution + Rep - report structure; fields which are not set by this function + are left intact + TSS - total sum of squares; used to calculate R2 + + +OUTPUT PARAMETERS: + XY - destroyed in process + Z - array[KX*KY*D], filled by solution; KX*KY coefficients + corresponding to each of D dimensions are stored contiguously. + Rep - following fields are set: + * Rep.RMSError + * Rep.AvgError + * Rep.MaxError + * Rep.R2 + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign, + ae_int_t lsqrcnt, + /* Real */ ae_vector* z, + spline2dfitreport* rep, + double tss, + spline2dblockllsbuf* buf, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t blockbandwidth; + ae_int_t d; + ae_int_t i; + ae_int_t j; + double lambdachol; + sreal mxata; + double v; + ae_int_t celloffset; + ae_int_t i0; + ae_int_t i1; + double rss; + ae_int_t arows; + ae_int_t bw2; + ae_int_t kx; + ae_int_t ky; + + ae_frame_make(_state, &_frame_block); + memset(&mxata, 0, sizeof(mxata)); + _sreal_init(&mxata, _state, ae_true); + + ae_assert(xdesign->blockwidth==4, "Spline2DFit: integrity check failed", _state); + blockbandwidth = 3; + d = xdesign->d; + arows = xdesign->nrows; + kx = xdesign->kx; + ky = xdesign->ky; + bw2 = xdesign->blockwidth*xdesign->blockwidth; + + /* + * Initial values for Z/Residuals + */ + rvectorsetlengthatleast(z, kx*ky*d, _state); + for(i=0; i<=kx*ky*d-1; i++) + { + z->ptr.p_double[i] = (double)(0); + } + + /* + * Create and factorize design matrix. Add regularizer if + * factorization failed (happens sometimes with zero + * smoothing and sparsely populated datasets). + * + * The algorithm below is refactoring of NaiveLLS algorithm, + * which uses sparsity properties and compressed block storage. + * + * Problem sparsity pattern results in block-band-diagonal + * matrix (block matrix with limited bandwidth, equal to 3 + * for bicubic splines). Thus, we have KY*KY blocks, each + * of them is KX*KX in size. Design matrix is stored in + * large NROWS*KX matrix, with NROWS=(BlockBandwidth+1)*KY*KX. + * + * We use adaptation of block skyline storage format, with + * TOWERSIZE*KX skyline bands (towers) stored sequentially; + * here TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY + * "towers", stored one below other, in BlockATA matrix. + * Every "tower" is a sequence of BlockBandwidth+1 cells, + * each of them being KX*KX in size. + */ + lambdachol = spline2d_cholreg; + rmatrixsetlengthatleast(&buf->blockata, (blockbandwidth+1)*ky*kx, kx, _state); + for(;;) + { + + /* + * Parallel generation of squared design matrix. + */ + spline2d_xdesignblockata(xdesign, &buf->blockata, &mxata.val, _state); + + /* + * Regularization + */ + v = coalesce(mxata.val, 1.0, _state)*lambdachol; + for(i1=0; i1<=ky-1; i1++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state); + for(i0=0; i0<=kx-1; i0++) + { + buf->blockata.ptr.pp_double[celloffset+i0][i0] = buf->blockata.ptr.pp_double[celloffset+i0][i0]+v; + } + } + + /* + * Try Cholesky factorization. + */ + if( !spline2d_blockllscholesky(&buf->blockata, kx, ky, &buf->trsmbuf2, &buf->cholbuf2, &buf->cholbuf1, _state) ) + { + + /* + * Factorization failed, increase regularizer and repeat + */ + lambdachol = coalesce((double)10*lambdachol, 1.0E-12, _state); + continue; + } + break; + } + + /* + * Solve + */ + rss = 0.0; + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + ae_assert(lsqrcnt>0, "Spline2DFit: integrity failure", _state); + rvectorsetlengthatleast(&buf->tmp0, arows, _state); + rvectorsetlengthatleast(&buf->tmp1, kx*ky, _state); + linlsqrcreatebuf(arows, kx*ky, &buf->solver, _state); + for(j=0; j<=d-1; j++) + { + + /* + * Preconditioned LSQR: + * + * use Cholesky factor U of squared design matrix A'*A to + * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x. + * + * Preconditioned problem is solved with LSQR solver, which + * gives superior results than normal equations. + */ + for(i=0; i<=arows-1; i++) + { + if( inpoints ) + { + buf->tmp0.ptr.p_double[i] = xdesign->vals.ptr.pp_double[i][bw2+j]; + } + else + { + buf->tmp0.ptr.p_double[i] = 0.0; + } + } + linlsqrrestart(&buf->solver, _state); + linlsqrsetb(&buf->solver, &buf->tmp0, _state); + linlsqrsetcond(&buf->solver, 1.0E-14, 1.0E-14, lsqrcnt, _state); + while(linlsqriteration(&buf->solver, _state)) + { + if( buf->solver.needmv ) + { + + /* + * Use Cholesky factorization of the system matrix + * as preconditioner: solve TRSV(U,Solver.X) + */ + for(i=0; i<=kx*ky-1; i++) + { + buf->tmp1.ptr.p_double[i] = buf->solver.x.ptr.p_double[i]; + } + spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state); + + /* + * After preconditioning is done, multiply by A + */ + spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->solver.mv, _state); + } + if( buf->solver.needmtv ) + { + + /* + * Multiply by design matrix A + */ + spline2d_xdesignmtv(xdesign, &buf->solver.x, &buf->solver.mtv, _state); + + /* + * Multiply by preconditioner: solve TRSV(U',A*Solver.X) + */ + spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_true, &buf->solver.mtv, _state); + } + } + + /* + * Get results and post-multiply by preconditioner to get + * original variables. + */ + linlsqrresults(&buf->solver, &buf->tmp1, &buf->solverrep, _state); + spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state); + for(i=0; i<=kx*ky-1; i++) + { + z->ptr.p_double[kx*ky*j+i] = buf->tmp1.ptr.p_double[i]; + } + + /* + * Calculate model values + */ + spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->tmp0, _state); + for(i=0; i<=xdesign->npoints-1; i++) + { + v = xdesign->vals.ptr.pp_double[i][bw2+j]-buf->tmp0.ptr.p_double[i]; + rss = rss+v*v; + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(xdesign->npoints*d), 1.0, _state), _state); + rep->avgerror = rep->avgerror/coalesce((double)(xdesign->npoints*d), 1.0, _state); + rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs fitting with NaiveLLS solver. Internal function, +never use it directly. + +INPUT PARAMETERS: + AV - sparse matrix, [ARows,KX*KY] in size. "Vertical" version + of design matrix, rows [0,NPoints] contain values of basis + functions at dataset points. Other rows are used for + nonlinearity penalty and other stuff like that. + AH - transpose(AV), "horizontal" version of AV + ARows - rows count + XY - array[NPoints*(2+D)], dataset + KX, KY - grid size + NPoints - points count + D - number of components in vector-valued spline, D>=1 + LSQRCnt - number of iterations, non-zero: + * LSQRCnt>0 means that specified amount of preconditioned + LSQR iterations will be performed to solve problem; + usually we need 2..5 its. Recommended option - best + convergence and stability/quality. + * LSQRCnt<0 means that instead of LSQR we use iterative + refinement on normal equations. Again, 2..5 its is enough. + Z - possibly preallocated buffer for solution + Rep - report structure; fields which are not set by this function + are left intact + TSS - total sum of squares; used to calculate R2 + + +OUTPUT PARAMETERS: + XY - destroyed in process + Z - array[KX*KY*D], filled by solution; KX*KY coefficients + corresponding to each of D dimensions are stored contiguously. + Rep - following fields are set: + * Rep.RMSError + * Rep.AvgError + * Rep.MaxError + * Rep.R2 + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_naivellsfit(const sparsematrix* av, + const sparsematrix* ah, + ae_int_t arows, + /* Real */ ae_vector* xy, + ae_int_t kx, + ae_int_t ky, + ae_int_t npoints, + ae_int_t d, + ae_int_t lsqrcnt, + /* Real */ ae_vector* z, + spline2dfitreport* rep, + double tss, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t ew; + ae_int_t i; + ae_int_t j; + ae_int_t i0; + ae_int_t i1; + ae_int_t j0; + ae_int_t j1; + double v; + ae_int_t blockbandwidth; + double lambdareg; + ae_int_t srci; + ae_int_t srcj; + ae_int_t idxi; + ae_int_t idxj; + ae_int_t endi; + ae_int_t endj; + ae_int_t rfsidx; + ae_matrix ata; + ae_vector tmp0; + ae_vector tmp1; + double mxata; + linlsqrstate solver; + linlsqrreport solverrep; + double rss; + + ae_frame_make(_state, &_frame_block); + memset(&ata, 0, sizeof(ata)); + memset(&tmp0, 0, sizeof(tmp0)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&solver, 0, sizeof(solver)); + memset(&solverrep, 0, sizeof(solverrep)); + ae_matrix_init(&ata, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true); + _linlsqrstate_init(&solver, _state, ae_true); + _linlsqrreport_init(&solverrep, _state, ae_true); + + blockbandwidth = 3; + ew = 2+d; + + /* + * Initial values for Z/Residuals + */ + rvectorsetlengthatleast(z, kx*ky*d, _state); + for(i=0; i<=kx*ky*d-1; i++) + { + z->ptr.p_double[i] = (double)(0); + } + + /* + * Create and factorize design matrix. + * + * Add regularizer if factorization failed (happens sometimes + * with zero smoothing and sparsely populated datasets). + */ + lambdareg = spline2d_cholreg; + rmatrixsetlengthatleast(&ata, kx*ky, kx*ky, _state); + for(;;) + { + mxata = 0.0; + for(i=0; i<=kx*ky-1; i++) + { + for(j=i; j<=kx*ky-1; j++) + { + + /* + * Initialize by zero + */ + ata.ptr.pp_double[i][j] = (double)(0); + + /* + * Determine grid nodes corresponding to I and J; + * skip if too far away + */ + i0 = i%kx; + i1 = i/kx; + j0 = j%kx; + j1 = j/kx; + if( ae_iabs(i0-j0, _state)>blockbandwidth||ae_iabs(i1-j1, _state)>blockbandwidth ) + { + continue; + } + + /* + * Nodes are close enough, calculate product of columns I and J of A. + */ + v = (double)(0); + srci = ah->ridx.ptr.p_int[i]; + srcj = ah->ridx.ptr.p_int[j]; + endi = ah->ridx.ptr.p_int[i+1]; + endj = ah->ridx.ptr.p_int[j+1]; + for(;;) + { + if( srci>=endi||srcj>=endj ) + { + break; + } + idxi = ah->idx.ptr.p_int[srci]; + idxj = ah->idx.ptr.p_int[srcj]; + if( idxi==idxj ) + { + v = v+ah->vals.ptr.p_double[srci]*ah->vals.ptr.p_double[srcj]; + srci = srci+1; + srcj = srcj+1; + continue; + } + if( idxi0 ) + { + linlsqrcreate(arows, kx*ky, &solver, _state); + } + for(j=0; j<=d-1; j++) + { + ae_assert(lsqrcnt!=0, "Spline2DFit: integrity failure", _state); + if( lsqrcnt>0 ) + { + + /* + * Preconditioned LSQR: + * + * use Cholesky factor U of squared design matrix A'*A to + * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x. + * + * Preconditioned problem is solved with LSQR solver, which + * gives superior results than normal equations. + */ + linlsqrcreate(arows, kx*ky, &solver, _state); + for(i=0; i<=arows-1; i++) + { + if( iptr.p_double[i*ew+2+j]; + } + else + { + tmp0.ptr.p_double[i] = 0.0; + } + } + linlsqrsetb(&solver, &tmp0, _state); + linlsqrsetcond(&solver, 1.0E-14, 1.0E-14, lsqrcnt, _state); + while(linlsqriteration(&solver, _state)) + { + if( solver.needmv ) + { + + /* + * Use Cholesky factorization of the system matrix + * as preconditioner: solve TRSV(U,Solver.X) + */ + for(i=0; i<=kx*ky-1; i++) + { + tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i]; + } + rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state); + + /* + * After preconditioning is done, multiply by A + */ + sparsemv(av, &tmp1, &solver.mv, _state); + } + if( solver.needmtv ) + { + + /* + * Multiply by design matrix A + */ + sparsemv(ah, &solver.x, &solver.mtv, _state); + + /* + * Multiply by preconditioner: solve TRSV(U',A*Solver.X) + */ + rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &solver.mtv, 0, _state); + } + } + linlsqrresults(&solver, &tmp1, &solverrep, _state); + rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state); + for(i=0; i<=kx*ky-1; i++) + { + z->ptr.p_double[kx*ky*j+i] = tmp1.ptr.p_double[i]; + } + + /* + * Calculate model values + */ + sparsemv(av, &tmp1, &tmp0, _state); + for(i=0; i<=npoints-1; i++) + { + xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i]; + } + } + else + { + + /* + * Iterative refinement, inferior to LSQR + * + * For each dimension D: + * * fetch current estimate for solution from Z to Tmp1 + * * calculate residual r for current estimate, store in Tmp0 + * * calculate product of residual and design matrix A'*r, store it in Tmp1 + * * Cholesky solver + * * update current estimate + */ + for(rfsidx=1; rfsidx<=-lsqrcnt; rfsidx++) + { + for(i=0; i<=kx*ky-1; i++) + { + tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i]; + } + sparsemv(av, &tmp1, &tmp0, _state); + for(i=0; i<=arows-1; i++) + { + if( iptr.p_double[i*ew+2+j]; + } + else + { + v = (double)(0); + } + tmp0.ptr.p_double[i] = v-tmp0.ptr.p_double[i]; + } + sparsemv(ah, &tmp0, &tmp1, _state); + rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &tmp1, 0, _state); + rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state); + for(i=0; i<=kx*ky-1; i++) + { + z->ptr.p_double[kx*ky*j+i] = z->ptr.p_double[kx*ky*j+i]+tmp1.ptr.p_double[i]; + } + } + + /* + * Calculate model values + */ + for(i=0; i<=kx*ky-1; i++) + { + tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i]; + } + sparsemv(av, &tmp1, &tmp0, _state); + for(i=0; i<=npoints-1; i++) + { + xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i]; + } + } + } + + /* + * Generate report + */ + rep->rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->maxerror = (double)(0); + rss = 0.0; + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=d-1; j++) + { + v = xy->ptr.p_double[i*ew+2+j]; + rss = rss+v*v; + rep->rmserror = rep->rmserror+ae_sqr(v, _state); + rep->avgerror = rep->avgerror+ae_fabs(v, _state); + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state); + rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state); + rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This is convenience function for band block storage format; it returns +offset of KX*KX-sized block (I,J) in a compressed 2D array. + +For specific offset=OFFSET, +block (I,J) will be stored in entries BlockMatrix[OFFSET:OFFSET+KX-1,0:KX-1] + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t spline2d_getcelloffset(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + ae_int_t i, + ae_int_t j, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(i>=0&&i=0&&j=i&&j<=i+blockbandwidth, "Spline2DFit: GetCellOffset() integrity error", _state); + result = j*(blockbandwidth+1)*kx; + result = result+(blockbandwidth-(j-i))*kx; + return result; +} + + +/************************************************************************* +This is convenience function for band block storage format; it copies +cell (I,J) from compressed format to uncompressed general matrix, at desired +position. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_copycellto(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + /* Real */ const ae_matrix* blockata, + ae_int_t i, + ae_int_t j, + /* Real */ ae_matrix* dst, + ae_int_t dst0, + ae_int_t dst1, + ae_state *_state) +{ + ae_int_t celloffset; + ae_int_t idx0; + ae_int_t idx1; + + + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state); + for(idx0=0; idx0<=kx-1; idx0++) + { + for(idx1=0; idx1<=kx-1; idx1++) + { + dst->ptr.pp_double[dst0+idx0][dst1+idx1] = blockata->ptr.pp_double[celloffset+idx0][idx1]; + } + } +} + + +/************************************************************************* +This is convenience function for band block storage format; it +truncates all elements of cell (I,J) which are less than Eps in magnitude. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_flushtozerocell(ae_int_t kx, + ae_int_t ky, + ae_int_t blockbandwidth, + /* Real */ ae_matrix* blockata, + ae_int_t i, + ae_int_t j, + double eps, + ae_state *_state) +{ + ae_int_t celloffset; + ae_int_t idx0; + ae_int_t idx1; + double eps2; + double v; + + + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state); + eps2 = eps*eps; + for(idx0=0; idx0<=kx-1; idx0++) + { + for(idx1=0; idx1<=kx-1; idx1++) + { + v = blockata->ptr.pp_double[celloffset+idx0][idx1]; + if( v*vptr.pp_double[celloffset+idx0][idx1] = (double)(0); + } + } + } +} + + +/************************************************************************* +This function performs Cholesky decomposition of squared design matrix +stored in block band format. + +INPUT PARAMETERS: + BlockATA - array[KY*(BlockBandwidth+1)*KX,KX], matrix in compressed + block band format + KX, KY - grid size + TrsmBuf2, + CholBuf2, + CholBuf1 - buffers; reused by this function on subsequent calls, + automatically preallocated on the first call + +OUTPUT PARAMETERS: + BlockATA- Cholesky factor, in compressed block band format + +Result: + True on success, False on Cholesky failure + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool spline2d_blockllscholesky(/* Real */ ae_matrix* blockata, + ae_int_t kx, + ae_int_t ky, + /* Real */ ae_matrix* trsmbuf2, + /* Real */ ae_matrix* cholbuf2, + /* Real */ ae_vector* cholbuf1, + ae_state *_state) +{ + ae_int_t blockbandwidth; + ae_int_t blockidx; + ae_int_t i; + ae_int_t j; + ae_int_t celloffset; + ae_int_t celloffset1; + ae_bool result; + + + blockbandwidth = 3; + rmatrixsetlengthatleast(trsmbuf2, (blockbandwidth+1)*kx, (blockbandwidth+1)*kx, _state); + rmatrixsetlengthatleast(cholbuf2, kx, kx, _state); + rvectorsetlengthatleast(cholbuf1, kx, _state); + result = ae_true; + for(blockidx=0; blockidx<=ky-1; blockidx++) + { + + /* + * TRSM for TRAIL*TRAIL block matrix before current cell; + * here TRAIL=MinInt(BlockIdx,BlockBandwidth). + */ + for(i=0; i<=ae_minint(blockidx, blockbandwidth, _state)-1; i++) + { + for(j=i; j<=ae_minint(blockidx, blockbandwidth, _state)-1; j++) + { + spline2d_copycellto(kx, ky, blockbandwidth, blockata, ae_maxint(blockidx-blockbandwidth, 0, _state)+i, ae_maxint(blockidx-blockbandwidth, 0, _state)+j, trsmbuf2, i*kx, j*kx, _state); + } + } + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state); + rmatrixlefttrsm(ae_minint(blockidx, blockbandwidth, _state)*kx, kx, trsmbuf2, 0, 0, ae_true, ae_false, 1, blockata, celloffset, 0, _state); + + /* + * SYRK for diagonal cell: MaxInt(BlockIdx-BlockBandwidth,0) + * cells above diagonal one are used for update. + */ + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state); + celloffset1 = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state); + rmatrixsyrk(kx, ae_minint(blockidx, blockbandwidth, _state)*kx, -1.0, blockata, celloffset, 0, 1, 1.0, blockata, celloffset1, 0, ae_true, _state); + + /* + * Factorize diagonal cell + */ + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state); + rmatrixcopy(kx, kx, blockata, celloffset, 0, cholbuf2, 0, 0, _state); + if( !spdmatrixcholeskyrec(cholbuf2, 0, kx, ae_true, cholbuf1, _state) ) + { + result = ae_false; + return result; + } + rmatrixcopy(kx, kx, cholbuf2, 0, 0, blockata, celloffset, 0, _state); + + /* + * PERFORMANCE TWEAK: drop nearly-denormals from last "tower". + * + * Sparse matrices like these may produce denormal numbers on + * sparse datasets, with significant (10x!) performance penalty + * on Intel chips. In order to avoid it, we manually truncate + * small enough numbers. + * + * We use 1.0E-50 as clipping level (not really denormal, but + * such small numbers are not actually important anyway). + */ + for(i=ae_maxint(blockidx-blockbandwidth, 0, _state); i<=blockidx; i++) + { + spline2d_flushtozerocell(kx, ky, blockbandwidth, blockata, i, blockidx, 1.0E-50, _state); + } + } + return result; +} + + +/************************************************************************* +This function performs TRSV on upper triangular Cholesky factor U, solving +either U*x=b or U'*x=b. + +INPUT PARAMETERS: + BlockATA - array[KY*(BlockBandwidth+1)*KX,KX], matrix U + in compressed block band format + KX, KY - grid size + TransU - whether to transpose U or not + B - array[KX*KY], on entry - stores right part B + +OUTPUT PARAMETERS: + B - replaced by X + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_blockllstrsv(/* Real */ const ae_matrix* blockata, + ae_int_t kx, + ae_int_t ky, + ae_bool transu, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t blockbandwidth; + ae_int_t blockidx; + ae_int_t blockidx1; + ae_int_t celloffset; + + + blockbandwidth = 3; + if( !transu ) + { + + /* + * Solve U*x=b + */ + for(blockidx=ky-1; blockidx>=0; blockidx--) + { + for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state); + rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 0, b, (blockidx+blockidx1)*kx, 1.0, b, blockidx*kx, _state); + } + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state); + rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 0, b, blockidx*kx, _state); + } + } + else + { + + /* + * Solve U'*x=b + */ + for(blockidx=0; blockidx<=ky-1; blockidx++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state); + rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 1, b, blockidx*kx, _state); + for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state); + rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 1, b, blockidx*kx, 1.0, b, (blockidx+blockidx1)*kx, _state); + } + } + } +} + + +/************************************************************************* +This function computes residuals for dataset XY[], using array of original +values YRaw[], and loads residuals to XY. + +Processing is performed in parallel manner. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_computeresidualsfromscratch(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t npoints, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_state *_state) +{ + ae_frame _frame_block; + srealarray seed; + ae_shared_pool pool; + ae_int_t chunksize; + double pointcost; + + ae_frame_make(_state, &_frame_block); + memset(&seed, 0, sizeof(seed)); + memset(&pool, 0, sizeof(pool)); + _srealarray_init(&seed, _state, ae_true); + ae_shared_pool_init(&pool, _state, ae_true); + + + /* + * Setting up + */ + chunksize = 1000; + pointcost = 100.0; + if( ae_fp_greater((double)npoints*pointcost,smpactivationlevel(_state)) ) + { + if( _trypexec_spline2d_computeresidualsfromscratch(xy,yraw,npoints,d,scalexy,spline, _state) ) + { + ae_frame_leave(_state); + return; + } + } + ae_shared_pool_set_seed(&pool, &seed, (ae_int_t)sizeof(seed), (ae_copy_constructor)_srealarray_init_copy, (ae_destructor)_srealarray_destroy, _state); + + /* + * Call compute workhorse + */ + spline2d_computeresidualsfromscratchrec(xy, yraw, 0, npoints, chunksize, d, scalexy, spline, &pool, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t npoints, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Recursive workhorse for ComputeResidualsFromScratch. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_computeresidualsfromscratchrec(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t pt0, + ae_int_t pt1, + ae_int_t chunksize, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_shared_pool* pool, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + srealarray *pbuf; + ae_smart_ptr _pbuf; + ae_int_t xew; + + ae_frame_make(_state, &_frame_block); + memset(&_pbuf, 0, sizeof(_pbuf)); + ae_smart_ptr_init(&_pbuf, (void**)&pbuf, ae_false, _state, ae_true); + + xew = 2+d; + + /* + * Parallelism + */ + if( pt1-pt0>chunksize ) + { + tiledsplit(pt1-pt0, chunksize, &i, &j, _state); + spline2d_computeresidualsfromscratchrec(xy, yraw, pt0, pt0+i, chunksize, d, scalexy, spline, pool, _state); + spline2d_computeresidualsfromscratchrec(xy, yraw, pt0+i, pt1, chunksize, d, scalexy, spline, pool, _state); + ae_frame_leave(_state); + return; + } + + /* + * Serial execution + */ + ae_shared_pool_retrieve(pool, &_pbuf, _state); + for(i=pt0; i<=pt1-1; i++) + { + spline2dcalcvbuf(spline, xy->ptr.p_double[i*xew+0]*(double)scalexy, xy->ptr.p_double[i*xew+1]*(double)scalexy, &pbuf->val, _state); + for(j=0; j<=d-1; j++) + { + xy->ptr.p_double[i*xew+2+j] = yraw->ptr.p_double[i*d+j]-pbuf->val.ptr.p_double[j]; + } + } + ae_shared_pool_recycle(pool, &_pbuf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real */ ae_vector* xy, + /* Real */ const ae_vector* yraw, + ae_int_t pt0, + ae_int_t pt1, + ae_int_t chunksize, + ae_int_t d, + ae_int_t scalexy, + const spline2dinterpolant* spline, + ae_shared_pool* pool, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function reorders dataset and builds index: +* it is assumed that all points have X in [0,KX-1], Y in [0,KY-1] +* area is divided into (KX-1)*(KY-1) cells +* all points are reordered in such way that points in same cell are stored + contiguously +* dataset index, array[(KX-1)*(KY-1)+1], is generated. Points of cell I + now have indexes XYIndex[I]..XYIndex[I+1]-1; + +INPUT PARAMETERS: + XY - array[NPoints*(2+D)], dataset + KX, KY, D - grid size and dimensionality of the outputs + Shadow - shadow array[NPoints*NS], which is sorted together + with XY; if NS=0, it is not referenced at all. + NS - entry width of shadow array + BufI - possibly preallocated temporary buffer; resized if + needed. + +OUTPUT PARAMETERS: + XY - reordered + XYIndex - array[(KX-1)*(KY-1)+1], dataset index + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_reorderdatasetandbuildindex(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + ae_int_t kx, + ae_int_t ky, + /* Integer */ ae_vector* xyindex, + /* Integer */ ae_vector* bufi, + ae_state *_state) +{ + ae_int_t i; + ae_int_t i0; + ae_int_t i1; + ae_int_t entrywidth; + + + + /* + * Set up + */ + ae_assert(kx>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state); + ae_assert(ky>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state); + entrywidth = 2+d; + ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state); + ivectorsetlengthatleast(bufi, npoints, _state); + for(i=0; i<=npoints-1; i++) + { + i0 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+0], _state), 0, kx-2, _state); + i1 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+1], _state), 0, ky-2, _state); + bufi->ptr.p_int[i] = i1*(kx-1)+i0; + } + + /* + * Reorder + */ + spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, bufi, 0, npoints, xyindex, 0, (kx-1)*(ky-1), ae_true, _state); + xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints; +} + + +/************************************************************************* +This function multiplies all points in dataset by 2.0 and rebuilds index, +given previous index built for KX_prev=(KX-1)/2 and KY_prev=(KY-1)/2 + +INPUT PARAMETERS: + XY - array[NPoints*(2+D)], dataset BEFORE scaling + NPoints, D - dataset size and dimensionality of the outputs + Shadow - shadow array[NPoints*NS], which is sorted together + with XY; if NS=0, it is not referenced at all. + NS - entry width of shadow array + KX, KY - new grid dimensionality + XYIndex - index built for previous values of KX and KY + BufI - possibly preallocated temporary buffer; resized if + needed. + +OUTPUT PARAMETERS: + XY - reordered and multiplied by 2.0 + XYIndex - array[(KX-1)*(KY-1)+1], dataset index + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_rescaledatasetandrefineindex(/* Real */ ae_vector* xy, + ae_int_t npoints, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + ae_int_t kx, + ae_int_t ky, + /* Integer */ ae_vector* xyindex, + /* Integer */ ae_vector* bufi, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector xyindexprev; + + ae_frame_make(_state, &_frame_block); + memset(&xyindexprev, 0, sizeof(xyindexprev)); + ae_vector_init(&xyindexprev, 0, DT_INT, _state, ae_true); + + + /* + * Set up + */ + ae_assert(kx>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state); + ae_assert(ky>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state); + ae_assert((kx-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state); + ae_assert((ky-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state); + ae_swap_vectors(xyindex, &xyindexprev); + ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state); + ivectorsetlengthatleast(bufi, npoints, _state); + + /* + * Refine + */ + spline2d_expandindexrows(xy, d, shadow, ns, bufi, 0, npoints, &xyindexprev, 0, (ky+1)/2-1, xyindex, kx, ky, ae_true, _state); + xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints; + + /* + * Integrity check + */ + ae_frame_leave(_state); +} + + +/************************************************************************* +Recurrent divide-and-conquer indexing function + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_expandindexrows(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindexprev, + ae_int_t row0, + ae_int_t row1, + /* Integer */ ae_vector* xyindexnew, + ae_int_t kxnew, + ae_int_t kynew, + ae_bool rootcall, + ae_state *_state) +{ + ae_int_t i; + ae_int_t entrywidth; + ae_int_t kxprev; + double v; + ae_int_t i0; + ae_int_t i1; + double efficiency; + double cost; + ae_int_t rowmid; + + + kxprev = (kxnew+1)/2; + entrywidth = 2+d; + efficiency = 0.1; + cost = (double)(d*(pt1-pt0+1))*(ae_log((double)(kxnew), _state)/ae_log((double)(2), _state))/efficiency; + ae_assert(xyindexprev->ptr.p_int[row0*(kxprev-1)+0]==pt0, "Spline2DFit.ExpandIndexRows: integrity check failed", _state); + ae_assert(xyindexprev->ptr.p_int[row1*(kxprev-1)+0]==pt1, "Spline2DFit.ExpandIndexRows: integrity check failed", _state); + + /* + * Parallelism + */ + if( ((rootcall&&pt1-pt0>10000)&&row1-row0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) ) + { + if( _trypexec_spline2d_expandindexrows(xy,d,shadow,ns,cidx,pt0,pt1,xyindexprev,row0,row1,xyindexnew,kxnew,kynew,rootcall, _state) ) + { + return; + } + } + + /* + * Partition + */ + if( row1-row0>=2 ) + { + tiledsplit(row1-row0, 1, &i0, &i1, _state); + rowmid = row0+i0; + spline2d_expandindexrows(xy, d, shadow, ns, cidx, pt0, xyindexprev->ptr.p_int[rowmid*(kxprev-1)+0], xyindexprev, row0, rowmid, xyindexnew, kxnew, kynew, ae_false, _state); + spline2d_expandindexrows(xy, d, shadow, ns, cidx, xyindexprev->ptr.p_int[rowmid*(kxprev-1)+0], pt1, xyindexprev, rowmid, row1, xyindexnew, kxnew, kynew, ae_false, _state); + return; + } + + /* + * Serial execution + */ + for(i=pt0; i<=pt1-1; i++) + { + v = (double)2*xy->ptr.p_double[i*entrywidth+0]; + xy->ptr.p_double[i*entrywidth+0] = v; + i0 = iboundval(ae_ifloor(v, _state), 0, kxnew-2, _state); + v = (double)2*xy->ptr.p_double[i*entrywidth+1]; + xy->ptr.p_double[i*entrywidth+1] = v; + i1 = iboundval(ae_ifloor(v, _state), 0, kynew-2, _state); + cidx->ptr.p_int[i] = i1*(kxnew-1)+i0; + } + spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, pt1, xyindexnew, 2*row0*(kxnew-1)+0, 2*row1*(kxnew-1)+0, ae_false, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spline2d_expandindexrows(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindexprev, + ae_int_t row0, + ae_int_t row1, + /* Integer */ ae_vector* xyindexnew, + ae_int_t kxnew, + ae_int_t kynew, + ae_bool rootcall, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Recurrent divide-and-conquer indexing function + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_reorderdatasetandbuildindexrec(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindex, + ae_int_t idx0, + ae_int_t idx1, + ae_bool rootcall, + ae_state *_state) +{ + ae_int_t entrywidth; + ae_int_t idxmid; + ae_int_t wrk0; + ae_int_t wrk1; + double efficiency; + double cost; + + + + /* + * Efficiency - performance of the code when compared with that + * of linear algebra code. + */ + entrywidth = 2+d; + efficiency = 0.1; + cost = (double)(d*(pt1-pt0+1))*ae_log((double)(idx1-idx0+1), _state)/ae_log((double)(2), _state)/efficiency; + + /* + * Parallelism + */ + if( ((rootcall&&pt1-pt0>10000)&&idx1-idx0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) ) + { + if( _trypexec_spline2d_reorderdatasetandbuildindexrec(xy,d,shadow,ns,cidx,pt0,pt1,xyindex,idx0,idx1,rootcall, _state) ) + { + return; + } + } + + /* + * Store left bound to XYIndex + */ + xyindex->ptr.p_int[idx0] = pt0; + + /* + * Quick exit strategies + */ + if( idx1<=idx0+1 ) + { + return; + } + if( pt0==pt1 ) + { + for(idxmid=idx0+1; idxmid<=idx1-1; idxmid++) + { + xyindex->ptr.p_int[idxmid] = pt1; + } + return; + } + + /* + * Select middle element + */ + idxmid = idx0+(idx1-idx0)/2; + ae_assert(idx0ptr.p_int[wrk0]=pt0&&cidx->ptr.p_int[wrk1]>=idxmid) + { + wrk1 = wrk1-1; + } + if( wrk1<=wrk0 ) + { + break; + } + swapentries(xy, wrk0, wrk1, entrywidth, _state); + if( ns>0 ) + { + swapentries(shadow, wrk0, wrk1, ns, _state); + } + swapelementsi(cidx, wrk0, wrk1, _state); + } + spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, wrk0, xyindex, idx0, idxmid, ae_false, _state); + spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, wrk0, pt1, xyindex, idxmid, idx1, ae_false, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real */ ae_vector* xy, + ae_int_t d, + /* Real */ ae_vector* shadow, + ae_int_t ns, + /* Integer */ ae_vector* cidx, + ae_int_t pt0, + ae_int_t pt1, + /* Integer */ ae_vector* xyindex, + ae_int_t idx0, + ae_int_t idx1, + ae_bool rootcall, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function performs fitting with BlockLLS solver. Internal function, +never use it directly. + +INPUT PARAMETERS: + XY - dataset, array[NPoints,2+D] + XYIndex - dataset index, see ReorderDatasetAndBuildIndex() for more info + KX0, KX1- X-indices of basis functions to select and fit; + range [KX0,KX1) is processed + KXTotal - total number of indexes in the entire grid + KY0, KY1- Y-indices of basis functions to select and fit; + range [KY0,KY1) is processed + KYTotal - total number of indexes in the entire grid + D - number of components in vector-valued spline, D>=1 + LambdaReg- regularization coefficient + LambdaNS- nonlinearity penalty, exactly zero value is specially handled + (entire set of rows is not added to the matrix) + Basis1 - single-dimensional B-spline + + +OUTPUT PARAMETERS: + A - design matrix + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_xdesigngenerate(/* Real */ const ae_vector* xy, + /* Integer */ const ae_vector* xyindex, + ae_int_t kx0, + ae_int_t kx1, + ae_int_t kxtotal, + ae_int_t ky0, + ae_int_t ky1, + ae_int_t kytotal, + ae_int_t d, + double lambdareg, + double lambdans, + const spline1dinterpolant* basis1, + spline2dxdesignmatrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t entrywidth; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t k0; + ae_int_t k1; + ae_int_t kx; + ae_int_t ky; + ae_int_t rowsdone; + ae_int_t batchesdone; + ae_int_t pt0; + ae_int_t pt1; + ae_int_t base0; + ae_int_t base1; + ae_int_t baseidx; + ae_int_t nzshift; + ae_int_t nzwidth; + ae_matrix d2x; + ae_matrix d2y; + ae_matrix dxy; + double v; + double v0; + double v1; + double v2; + double w0; + double w1; + double w2; + + ae_frame_make(_state, &_frame_block); + memset(&d2x, 0, sizeof(d2x)); + memset(&d2y, 0, sizeof(d2y)); + memset(&dxy, 0, sizeof(dxy)); + ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true); + + nzshift = 1; + nzwidth = 4; + entrywidth = 2+d; + kx = kx1-kx0; + ky = ky1-ky0; + a->lambdareg = lambdareg; + a->blockwidth = 4; + a->kx = kx; + a->ky = ky; + a->d = d; + a->npoints = 0; + a->ndenserows = 0; + a->ndensebatches = 0; + a->maxbatch = 0; + for(j1=ky0; j1<=ky1-2; j1++) + { + for(j0=kx0; j0<=kx1-2; j0++) + { + i = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1]-xyindex->ptr.p_int[j1*(kxtotal-1)+j0]; + a->npoints = a->npoints+i; + a->ndenserows = a->ndenserows+i; + a->ndensebatches = a->ndensebatches+1; + a->maxbatch = ae_maxint(a->maxbatch, i, _state); + } + } + if( ae_fp_neq(lambdans,(double)(0)) ) + { + ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DFit: integrity check failed", _state); + a->ndenserows = a->ndenserows+3*(kx-2)*(ky-2); + a->ndensebatches = a->ndensebatches+(kx-2)*(ky-2); + a->maxbatch = ae_maxint(a->maxbatch, 3, _state); + } + a->nrows = a->ndenserows+kx*ky; + rmatrixsetlengthatleast(&a->vals, a->ndenserows, a->blockwidth*a->blockwidth+d, _state); + ivectorsetlengthatleast(&a->batches, a->ndensebatches+1, _state); + ivectorsetlengthatleast(&a->batchbases, a->ndensebatches, _state); + + /* + * Setup output counters + */ + batchesdone = 0; + rowsdone = 0; + + /* + * Generate rows corresponding to dataset points + */ + ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state); + ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state); + rvectorsetlengthatleast(&a->tmp0, nzwidth, _state); + rvectorsetlengthatleast(&a->tmp1, nzwidth, _state); + a->batches.ptr.p_int[batchesdone] = 0; + for(j1=ky0; j1<=ky1-2; j1++) + { + for(j0=kx0; j0<=kx1-2; j0++) + { + pt0 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0]; + pt1 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1]; + base0 = iboundval(j0-kx0-nzshift, 0, kx-nzwidth, _state); + base1 = iboundval(j1-ky0-nzshift, 0, ky-nzwidth, _state); + baseidx = base1*kx+base0; + a->batchbases.ptr.p_int[batchesdone] = baseidx; + for(i=pt0; i<=pt1-1; i++) + { + for(k0=0; k0<=nzwidth-1; k0++) + { + a->tmp0.ptr.p_double[k0] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+0]-(double)(base0+kx0+k0), _state); + } + for(k1=0; k1<=nzwidth-1; k1++) + { + a->tmp1.ptr.p_double[k1] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+1]-(double)(base1+ky0+k1), _state); + } + for(k1=0; k1<=nzwidth-1; k1++) + { + for(k0=0; k0<=nzwidth-1; k0++) + { + a->vals.ptr.pp_double[rowsdone][k1*nzwidth+k0] = a->tmp0.ptr.p_double[k0]*a->tmp1.ptr.p_double[k1]; + } + } + for(j=0; j<=d-1; j++) + { + a->vals.ptr.pp_double[rowsdone][nzwidth*nzwidth+j] = xy->ptr.p_double[i*entrywidth+2+j]; + } + rowsdone = rowsdone+1; + } + batchesdone = batchesdone+1; + a->batches.ptr.p_int[batchesdone] = rowsdone; + } + } + + /* + * Generate rows corresponding to nonlinearity penalty + */ + if( ae_fp_greater(lambdans,(double)(0)) ) + { + + /* + * Smoothing is applied. Because all grid nodes are same, + * we apply same smoothing kernel, which is calculated only + * once at the beginning of design matrix generation. + */ + ae_matrix_set_length(&d2x, 3, 3, _state); + ae_matrix_set_length(&d2y, 3, 3, _state); + ae_matrix_set_length(&dxy, 3, 3, _state); + for(j1=0; j1<=2; j1++) + { + for(j0=0; j0<=2; j0++) + { + d2x.ptr.pp_double[j0][j1] = 0.0; + d2y.ptr.pp_double[j0][j1] = 0.0; + dxy.ptr.pp_double[j0][j1] = 0.0; + } + } + for(k1=0; k1<=2; k1++) + { + for(k0=0; k0<=2; k0++) + { + spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state); + spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state); + d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0; + d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0; + dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1; + } + } + + /* + * Now, kernel is ready - apply it to all inner nodes of the grid. + */ + for(j1=1; j1<=ky-2; j1++) + { + for(j0=1; j0<=kx-2; j0++) + { + base0 = imax2(j0-2, 0, _state); + base1 = imax2(j1-2, 0, _state); + baseidx = base1*kx+base0; + a->batchbases.ptr.p_int[batchesdone] = baseidx; + + /* + * d2F/dx2 term + */ + v = lambdans; + for(j=0; j<=nzwidth*nzwidth+d-1; j++) + { + a->vals.ptr.pp_double[rowsdone][j] = (double)(0); + } + for(k1=j1-1; k1<=j1+1; k1++) + { + for(k0=j0-1; k0<=j0+1; k0++) + { + a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2x.ptr.pp_double[1+(k0-j0)][1+(k1-j1)]; + } + } + rowsdone = rowsdone+1; + + /* + * d2F/dy2 term + */ + v = lambdans; + for(j=0; j<=nzwidth*nzwidth+d-1; j++) + { + a->vals.ptr.pp_double[rowsdone][j] = (double)(0); + } + for(k1=j1-1; k1<=j1+1; k1++) + { + for(k0=j0-1; k0<=j0+1; k0++) + { + a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2y.ptr.pp_double[1+(k0-j0)][1+(k1-j1)]; + } + } + rowsdone = rowsdone+1; + + /* + * 2*d2F/dxdy term + */ + v = ae_sqrt((double)(2), _state)*lambdans; + for(j=0; j<=nzwidth*nzwidth+d-1; j++) + { + a->vals.ptr.pp_double[rowsdone][j] = (double)(0); + } + for(k1=j1-1; k1<=j1+1; k1++) + { + for(k0=j0-1; k0<=j0+1; k0++) + { + a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*dxy.ptr.pp_double[1+(k0-j0)][1+(k1-j1)]; + } + } + rowsdone = rowsdone+1; + batchesdone = batchesdone+1; + a->batches.ptr.p_int[batchesdone] = rowsdone; + } + } + } + + /* + * Integrity post-check + */ + ae_assert(batchesdone==a->ndensebatches, "Spline2DFit: integrity check failed", _state); + ae_assert(rowsdone==a->ndenserows, "Spline2DFit: integrity check failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs matrix-vector product of design matrix and dense +vector. + +INPUT PARAMETERS: + A - design matrix, (a.nrows) X (a.kx*a.ky); + some fields of A are used for temporaries, + so it is non-constant. + X - array[A.KX*A.KY] + + +OUTPUT PARAMETERS: + Y - product, array[A.NRows], automatically allocated + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_xdesignmv(spline2dxdesignmatrix* a, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t bidx; + ae_int_t i; + ae_int_t cnt; + double v; + ae_int_t baseidx; + ae_int_t outidx; + ae_int_t batchsize; + ae_int_t kx; + ae_int_t k0; + ae_int_t k1; + ae_int_t nzwidth; + + + nzwidth = 4; + ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state); + ae_assert(x->cnt>=a->kx*a->ky, "Spline2DFit: integrity check failed", _state); + + /* + * Prepare + */ + rvectorsetlengthatleast(y, a->nrows, _state); + rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state); + rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state); + kx = a->kx; + outidx = 0; + + /* + * Process dense part + */ + for(bidx=0; bidx<=a->ndensebatches-1; bidx++) + { + if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 ) + { + batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]; + baseidx = a->batchbases.ptr.p_int[bidx]; + for(k1=0; k1<=nzwidth-1; k1++) + { + for(k0=0; k0<=nzwidth-1; k0++) + { + a->tmp0.ptr.p_double[k1*nzwidth+k0] = x->ptr.p_double[baseidx+k1*kx+k0]; + } + } + rmatrixgemv(batchsize, nzwidth*nzwidth, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 0, &a->tmp0, 0, 0.0, &a->tmp1, 0, _state); + for(i=0; i<=batchsize-1; i++) + { + y->ptr.p_double[outidx+i] = a->tmp1.ptr.p_double[i]; + } + outidx = outidx+batchsize; + } + } + ae_assert(outidx==a->ndenserows, "Spline2DFit: integrity check failed", _state); + + /* + * Process regularizer + */ + v = a->lambdareg; + cnt = a->kx*a->ky; + for(i=0; i<=cnt-1; i++) + { + y->ptr.p_double[outidx+i] = v*x->ptr.p_double[i]; + } + outidx = outidx+cnt; + + /* + * Post-check + */ + ae_assert(outidx==a->nrows, "Spline2DFit: integrity check failed", _state); +} + + +/************************************************************************* +This function performs matrix-vector product of transposed design matrix and dense +vector. + +INPUT PARAMETERS: + A - design matrix, (a.nrows) X (a.kx*a.ky); + some fields of A are used for temporaries, + so it is non-constant. + X - array[A.NRows] + + +OUTPUT PARAMETERS: + Y - product, array[A.KX*A.KY], automatically allocated + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_xdesignmtv(spline2dxdesignmatrix* a, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t bidx; + ae_int_t i; + ae_int_t cnt; + double v; + ae_int_t baseidx; + ae_int_t inidx; + ae_int_t batchsize; + ae_int_t kx; + ae_int_t k0; + ae_int_t k1; + ae_int_t nzwidth; + + + nzwidth = 4; + ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state); + ae_assert(x->cnt>=a->nrows, "Spline2DFit: integrity check failed", _state); + + /* + * Prepare + */ + rvectorsetlengthatleast(y, a->kx*a->ky, _state); + rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state); + rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state); + kx = a->kx; + inidx = 0; + cnt = a->kx*a->ky; + for(i=0; i<=cnt-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + + /* + * Process dense part + */ + for(bidx=0; bidx<=a->ndensebatches-1; bidx++) + { + if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 ) + { + batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]; + baseidx = a->batchbases.ptr.p_int[bidx]; + for(i=0; i<=batchsize-1; i++) + { + a->tmp1.ptr.p_double[i] = x->ptr.p_double[inidx+i]; + } + rmatrixgemv(nzwidth*nzwidth, batchsize, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 1, &a->tmp1, 0, 0.0, &a->tmp0, 0, _state); + for(k1=0; k1<=nzwidth-1; k1++) + { + for(k0=0; k0<=nzwidth-1; k0++) + { + y->ptr.p_double[baseidx+k1*kx+k0] = y->ptr.p_double[baseidx+k1*kx+k0]+a->tmp0.ptr.p_double[k1*nzwidth+k0]; + } + } + inidx = inidx+batchsize; + } + } + ae_assert(inidx==a->ndenserows, "Spline2DFit: integrity check failed", _state); + + /* + * Process regularizer + */ + v = a->lambdareg; + cnt = a->kx*a->ky; + for(i=0; i<=cnt-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+v*x->ptr.p_double[inidx+i]; + } + inidx = inidx+cnt; + + /* + * Post-check + */ + ae_assert(inidx==a->nrows, "Spline2DFit: integrity check failed", _state); +} + + +/************************************************************************* +This function generates squared design matrix stored in block band format. + +We use an adaptation of block skyline storage format, with +TOWERSIZE*KX skyline bands (towers) stored sequentially; here +TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY "towers", stored one below +other, in BlockATA matrix. Every "tower" is a sequence of BlockBandwidth+1 +cells, each of them being KX*KX in size. + +INPUT PARAMETERS: + A - design matrix; some of its fields are used for temporaries + BlockATA- array[KY*(BlockBandwidth+1)*KX,KX], preallocated storage + for output matrix in compressed block band format + +OUTPUT PARAMETERS: + BlockATA- AH*AH', stored in compressed block band format + MXATA - max(|AH*AH'|), elementwise + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_xdesignblockata(spline2dxdesignmatrix* a, + /* Real */ ae_matrix* blockata, + double* mxata, + ae_state *_state) +{ + ae_int_t blockbandwidth; + ae_int_t nzwidth; + ae_int_t kx; + ae_int_t ky; + ae_int_t i0; + ae_int_t i1; + ae_int_t j0; + ae_int_t j1; + ae_int_t celloffset; + ae_int_t bidx; + ae_int_t baseidx; + ae_int_t batchsize; + ae_int_t offs0; + ae_int_t offs1; + double v; + + + blockbandwidth = 3; + nzwidth = 4; + kx = a->kx; + ky = a->ky; + ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state); + rmatrixsetlengthatleast(&a->tmp2, nzwidth*nzwidth, nzwidth*nzwidth, _state); + + /* + * Initial zero-fill: + * * zero-fill ALL elements of BlockATA + * * zero-fill ALL elements of Tmp2 + * + * Filling ALL elements, including unused ones, is essential for the + * purposes of calculating max(BlockATA). + */ + for(i1=0; i1<=ky-1; i1++) + { + for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state); + for(j1=0; j1<=kx-1; j1++) + { + for(j0=0; j0<=kx-1; j0++) + { + blockata->ptr.pp_double[celloffset+j1][j0] = 0.0; + } + } + } + } + for(j1=0; j1<=nzwidth*nzwidth-1; j1++) + { + for(j0=0; j0<=nzwidth*nzwidth-1; j0++) + { + a->tmp2.ptr.pp_double[j1][j0] = 0.0; + } + } + + /* + * Process dense part of A + */ + for(bidx=0; bidx<=a->ndensebatches-1; bidx++) + { + if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 ) + { + + /* + * Generate 16x16 U = BATCH'*BATCH and add it to ATA. + * + * NOTE: it is essential that lower triangle of Tmp2 is + * filled by zeros. + */ + batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]; + rmatrixsyrk(nzwidth*nzwidth, batchsize, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 2, 0.0, &a->tmp2, 0, 0, ae_true, _state); + baseidx = a->batchbases.ptr.p_int[bidx]; + for(i1=0; i1<=nzwidth-1; i1++) + { + for(j1=i1; j1<=nzwidth-1; j1++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, baseidx/kx+i1, baseidx/kx+j1, _state); + offs0 = baseidx%kx; + offs1 = baseidx%kx; + for(i0=0; i0<=nzwidth-1; i0++) + { + for(j0=0; j0<=nzwidth-1; j0++) + { + v = a->tmp2.ptr.pp_double[i1*nzwidth+i0][j1*nzwidth+j0]; + blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0] = blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0]+v; + } + } + } + } + } + } + + /* + * Process regularizer term + */ + for(i1=0; i1<=ky-1; i1++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state); + for(j1=0; j1<=kx-1; j1++) + { + blockata->ptr.pp_double[celloffset+j1][j1] = blockata->ptr.pp_double[celloffset+j1][j1]+ae_sqr(a->lambdareg, _state); + } + } + + /* + * Calculate max(ATA) + * + * NOTE: here we rely on zero initialization of unused parts of + * BlockATA and Tmp2. + */ + *mxata = 0.0; + for(i1=0; i1<=ky-1; i1++) + { + for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++) + { + celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state); + for(j1=0; j1<=kx-1; j1++) + { + for(j0=0; j0<=kx-1; j0++) + { + *mxata = ae_maxreal(*mxata, ae_fabs(blockata->ptr.pp_double[celloffset+j1][j0], _state), _state); + } + } + } + } +} + + +/************************************************************************* +Adjust evaluation interval: if we are inside missing cell, but very close +to the nonmissing one, move to its boundaries. + +This function is used to avoid situation when evaluation at the nodes adjacent +to missing cells fails due to rounding errors that move us away from the +feasible cell. + +Returns True if X/Y, DX/DY, IX/IY were successfully repositioned to the +nearest nonmissing cell (or were feasible from the very beginning). False +is returned if we are deep in the missing cell. + + -- ALGLIB -- + Copyright 26.06.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool spline2d_adjustevaluationinterval(const spline2dinterpolant* s, + double* x, + double* t, + double* dt, + ae_int_t* ix, + double* y, + double* u, + double* du, + ae_int_t* iy, + ae_state *_state) +{ + double tol; + ae_bool tryleftbndx; + ae_bool tryrightbndx; + ae_bool trycenterx; + ae_bool tryleftbndy; + ae_bool tryrightbndy; + ae_bool trycentery; + ae_bool result; + + + + /* + * Quick exit - no missing cells, or we are at non-missing cell + */ + result = !s->hasmissingcells||!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy)+(*ix)]; + if( result ) + { + return result; + } + + /* + * Missing cell, but maybe we are really close to some non-missing cell? + */ + tol = (double)1000*ae_machineepsilon; + tryleftbndx = ae_fp_less(*t,tol)&&*ix>0; + tryrightbndx = ae_fp_greater(*t,(double)1-tol)&&*ix+1n-1; + trycenterx = ae_true; + tryleftbndy = ae_fp_less(*u,tol)&&*iy>0; + tryrightbndy = ae_fp_greater(*u,(double)1-tol)&&*iy+1m-1; + trycentery = ae_true; + if( ((!result&&tryleftbndx)&&tryleftbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy-1)+(*ix-1)] ) + { + *ix = *ix-1; + *iy = *iy-1; + *x = s->x.ptr.p_double[*ix+1]; + *y = s->y.ptr.p_double[*iy+1]; + result = ae_true; + } + if( ((!result&&tryleftbndx)&&trycentery)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy+0)+(*ix-1)] ) + { + *ix = *ix-1; + *x = s->x.ptr.p_double[*ix+1]; + result = ae_true; + } + if( ((!result&&tryleftbndx)&&tryrightbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy+1)+(*ix-1)] ) + { + *ix = *ix-1; + *iy = *iy+1; + *x = s->x.ptr.p_double[*ix+1]; + *y = s->y.ptr.p_double[*iy]; + result = ae_true; + } + if( ((!result&&trycenterx)&&tryleftbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy-1)+(*ix+0)] ) + { + *iy = *iy-1; + *y = s->y.ptr.p_double[*iy+1]; + result = ae_true; + } + if( ((!result&&trycenterx)&&tryrightbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy+1)+(*ix+0)] ) + { + *iy = *iy+1; + *y = s->y.ptr.p_double[*iy]; + result = ae_true; + } + if( ((!result&&tryrightbndx)&&tryleftbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy-1)+(*ix+1)] ) + { + *ix = *ix+1; + *iy = *iy-1; + *x = s->x.ptr.p_double[*ix]; + *y = s->y.ptr.p_double[*iy+1]; + result = ae_true; + } + if( ((!result&&tryrightbndx)&&trycentery)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy+0)+(*ix+1)] ) + { + *ix = *ix+1; + *x = s->x.ptr.p_double[*ix]; + result = ae_true; + } + if( ((!result&&tryrightbndx)&&tryrightbndy)&&!s->ismissingcell.ptr.p_bool[(s->n-1)*(*iy+1)+(*ix+1)] ) + { + *ix = *ix+1; + *iy = *iy+1; + *x = s->x.ptr.p_double[*ix]; + *y = s->y.ptr.p_double[*iy]; + result = ae_true; + } + if( result ) + { + *dt = 1.0/(s->x.ptr.p_double[*ix+1]-s->x.ptr.p_double[*ix]); + *t = (*x-s->x.ptr.p_double[*ix])*(*dt); + *du = 1.0/(s->y.ptr.p_double[*iy+1]-s->y.ptr.p_double[*iy]); + *u = (*y-s->y.ptr.p_double[*iy])*(*du); + } + return result; +} + + +/************************************************************************* +This subroutine sorts grid nodes by ascending and also sorts boundary +conditions and target values + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +static void spline2d_sortgrid(/* Real */ ae_vector* x, + ae_int_t n, + /* Real */ ae_vector* y, + ae_int_t m, + /* Real */ ae_vector* bndbtm, + ae_bool hasbndbtm, + /* Real */ ae_vector* bndtop, + ae_bool hasbndtop, + /* Real */ ae_vector* bndlft, + ae_bool hasbndlft, + /* Real */ ae_vector* bndrgt, + ae_bool hasbndrgt, + /* Real */ ae_vector* f, + ae_int_t d, + /* Real */ ae_vector* dfdx, + /* Real */ ae_vector* dfdy, + /* Real */ ae_vector* d2fdxdy, + ae_bool hasderivatives, + ae_state *_state) +{ + double t; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + + + ae_assert(n>=2, "Spline2DSortGrid: N is less than 2", _state); + ae_assert(m>=2, "Spline2DSortGrid: M is less than 2", _state); + ae_assert(d>=1, "Spline2DSortGrid: invalid argument D (D<1)", _state); + k = n*m*d; + for(j=0; j<=n-1; j++) + { + k = j; + for(i=j+1; i<=n-1; i++) + { + if( ae_fp_less(x->ptr.p_double[i],x->ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=m-1; i++) + { + for(di=0; di<=d-1; di++) + { + t = f->ptr.p_double[d*(i*n+j)+di]; + f->ptr.p_double[d*(i*n+j)+di] = f->ptr.p_double[d*(i*n+k)+di]; + f->ptr.p_double[d*(i*n+k)+di] = t; + if( hasderivatives ) + { + t = dfdx->ptr.p_double[d*(i*n+j)+di]; + dfdx->ptr.p_double[d*(i*n+j)+di] = dfdx->ptr.p_double[d*(i*n+k)+di]; + dfdx->ptr.p_double[d*(i*n+k)+di] = t; + t = dfdy->ptr.p_double[d*(i*n+j)+di]; + dfdy->ptr.p_double[d*(i*n+j)+di] = dfdy->ptr.p_double[d*(i*n+k)+di]; + dfdy->ptr.p_double[d*(i*n+k)+di] = t; + t = d2fdxdy->ptr.p_double[d*(i*n+j)+di]; + d2fdxdy->ptr.p_double[d*(i*n+j)+di] = d2fdxdy->ptr.p_double[d*(i*n+k)+di]; + d2fdxdy->ptr.p_double[d*(i*n+k)+di] = t; + } + } + } + t = x->ptr.p_double[j]; + x->ptr.p_double[j] = x->ptr.p_double[k]; + x->ptr.p_double[k] = t; + if( hasbndbtm ) + { + for(di=0; di<=d-1; di++) + { + t = bndbtm->ptr.p_double[j*d+di]; + bndbtm->ptr.p_double[j*d+di] = bndbtm->ptr.p_double[k*d+di]; + bndbtm->ptr.p_double[k*d+di] = t; + } + } + if( hasbndtop ) + { + for(di=0; di<=d-1; di++) + { + t = bndtop->ptr.p_double[j*d+di]; + bndtop->ptr.p_double[j*d+di] = bndtop->ptr.p_double[k*d+di]; + bndtop->ptr.p_double[k*d+di] = t; + } + } + } + } + for(i=0; i<=m-1; i++) + { + k = i; + for(j=i+1; j<=m-1; j++) + { + if( ae_fp_less(y->ptr.p_double[j],y->ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=n-1; j++) + { + for(di=0; di<=d-1; di++) + { + t = f->ptr.p_double[d*(i*n+j)+di]; + f->ptr.p_double[d*(i*n+j)+di] = f->ptr.p_double[d*(k*n+j)+di]; + f->ptr.p_double[d*(k*n+j)+di] = t; + if( hasderivatives ) + { + t = dfdx->ptr.p_double[d*(i*n+j)+di]; + dfdx->ptr.p_double[d*(i*n+j)+di] = dfdx->ptr.p_double[d*(k*n+j)+di]; + dfdx->ptr.p_double[d*(k*n+j)+di] = t; + t = dfdy->ptr.p_double[d*(i*n+j)+di]; + dfdy->ptr.p_double[d*(i*n+j)+di] = dfdy->ptr.p_double[d*(k*n+j)+di]; + dfdy->ptr.p_double[d*(k*n+j)+di] = t; + t = d2fdxdy->ptr.p_double[d*(i*n+j)+di]; + d2fdxdy->ptr.p_double[d*(i*n+j)+di] = d2fdxdy->ptr.p_double[d*(k*n+j)+di]; + d2fdxdy->ptr.p_double[d*(k*n+j)+di] = t; + } + } + } + t = y->ptr.p_double[i]; + y->ptr.p_double[i] = y->ptr.p_double[k]; + y->ptr.p_double[k] = t; + if( hasbndlft ) + { + for(di=0; di<=d-1; di++) + { + t = bndlft->ptr.p_double[i*d+di]; + bndlft->ptr.p_double[i*d+di] = bndlft->ptr.p_double[k*d+di]; + bndlft->ptr.p_double[k*d+di] = t; + } + } + if( hasbndrgt ) + { + for(di=0; di<=d-1; di++) + { + t = bndrgt->ptr.p_double[i*d+di]; + bndrgt->ptr.p_double[i*d+di] = bndrgt->ptr.p_double[k*d+di]; + bndrgt->ptr.p_double[k*d+di] = t; + } + } + } + } +} + + +void _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dinterpolant *p = (spline2dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ismissingnode, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->ismissingcell, 0, DT_BOOL, _state, make_automatic); +} + + +void _spline2dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dinterpolant *dst = (spline2dinterpolant*)_dst; + const spline2dinterpolant *src = (const spline2dinterpolant*)_src; + dst->stype = src->stype; + dst->hasmissingcells = src->hasmissingcells; + dst->n = src->n; + dst->m = src->m; + dst->d = src->d; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic); + ae_vector_init_copy(&dst->ismissingnode, &src->ismissingnode, _state, make_automatic); + ae_vector_init_copy(&dst->ismissingcell, &src->ismissingcell, _state, make_automatic); +} + + +void _spline2dinterpolant_clear(void* _p) +{ + spline2dinterpolant *p = (spline2dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->f); + ae_vector_clear(&p->ismissingnode); + ae_vector_clear(&p->ismissingcell); +} + + +void _spline2dinterpolant_destroy(void* _p) +{ + spline2dinterpolant *p = (spline2dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->f); + ae_vector_destroy(&p->ismissingnode); + ae_vector_destroy(&p->ismissingcell); +} + + +void _spline2dbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dbuilder *p = (spline2dbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic); +} + + +void _spline2dbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dbuilder *dst = (spline2dbuilder*)_dst; + const spline2dbuilder *src = (const spline2dbuilder*)_src; + dst->priorterm = src->priorterm; + dst->priortermval = src->priortermval; + dst->areatype = src->areatype; + dst->xa = src->xa; + dst->xb = src->xb; + dst->ya = src->ya; + dst->yb = src->yb; + dst->gridtype = src->gridtype; + dst->kx = src->kx; + dst->ky = src->ky; + dst->smoothing = src->smoothing; + dst->nlayers = src->nlayers; + dst->solvertype = src->solvertype; + dst->lambdabase = src->lambdabase; + ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic); + dst->npoints = src->npoints; + dst->d = src->d; + dst->sx = src->sx; + dst->sy = src->sy; + dst->adddegreeoffreedom = src->adddegreeoffreedom; + dst->interfacesize = src->interfacesize; + dst->lsqrcnt = src->lsqrcnt; + dst->maxcoresize = src->maxcoresize; +} + + +void _spline2dbuilder_clear(void* _p) +{ + spline2dbuilder *p = (spline2dbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xy); +} + + +void _spline2dbuilder_destroy(void* _p) +{ + spline2dbuilder *p = (spline2dbuilder*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xy); +} + + +void _spline2dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dfitreport *p = (spline2dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline2dfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dfitreport *dst = (spline2dfitreport*)_dst; + const spline2dfitreport *src = (const spline2dfitreport*)_src; + dst->rmserror = src->rmserror; + dst->avgerror = src->avgerror; + dst->maxerror = src->maxerror; + dst->r2 = src->r2; +} + + +void _spline2dfitreport_clear(void* _p) +{ + spline2dfitreport *p = (spline2dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline2dfitreport_destroy(void* _p) +{ + spline2dfitreport *p = (spline2dfitreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _spline2dxdesignmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->vals, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->batches, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->batchbases, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _spline2dxdesignmatrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dxdesignmatrix *dst = (spline2dxdesignmatrix*)_dst; + const spline2dxdesignmatrix *src = (const spline2dxdesignmatrix*)_src; + dst->blockwidth = src->blockwidth; + dst->kx = src->kx; + dst->ky = src->ky; + dst->npoints = src->npoints; + dst->nrows = src->nrows; + dst->ndenserows = src->ndenserows; + dst->ndensebatches = src->ndensebatches; + dst->d = src->d; + dst->maxbatch = src->maxbatch; + ae_matrix_init_copy(&dst->vals, &src->vals, _state, make_automatic); + ae_vector_init_copy(&dst->batches, &src->batches, _state, make_automatic); + ae_vector_init_copy(&dst->batchbases, &src->batchbases, _state, make_automatic); + dst->lambdareg = src->lambdareg; + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); +} + + +void _spline2dxdesignmatrix_clear(void* _p) +{ + spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->vals); + ae_vector_clear(&p->batches); + ae_vector_clear(&p->batchbases); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_matrix_clear(&p->tmp2); +} + + +void _spline2dxdesignmatrix_destroy(void* _p) +{ + spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->vals); + ae_vector_destroy(&p->batches); + ae_vector_destroy(&p->batchbases); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_matrix_destroy(&p->tmp2); +} + + +void _spline2dblockllsbuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p; + ae_touch_ptr((void*)p); + _linlsqrstate_init(&p->solver, _state, make_automatic); + _linlsqrreport_init(&p->solverrep, _state, make_automatic); + ae_matrix_init(&p->blockata, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->trsmbuf2, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cholbuf2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cholbuf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); +} + + +void _spline2dblockllsbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dblockllsbuf *dst = (spline2dblockllsbuf*)_dst; + const spline2dblockllsbuf *src = (const spline2dblockllsbuf*)_src; + _linlsqrstate_init_copy(&dst->solver, &src->solver, _state, make_automatic); + _linlsqrreport_init_copy(&dst->solverrep, &src->solverrep, _state, make_automatic); + ae_matrix_init_copy(&dst->blockata, &src->blockata, _state, make_automatic); + ae_matrix_init_copy(&dst->trsmbuf2, &src->trsmbuf2, _state, make_automatic); + ae_matrix_init_copy(&dst->cholbuf2, &src->cholbuf2, _state, make_automatic); + ae_vector_init_copy(&dst->cholbuf1, &src->cholbuf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); +} + + +void _spline2dblockllsbuf_clear(void* _p) +{ + spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p; + ae_touch_ptr((void*)p); + _linlsqrstate_clear(&p->solver); + _linlsqrreport_clear(&p->solverrep); + ae_matrix_clear(&p->blockata); + ae_matrix_clear(&p->trsmbuf2); + ae_matrix_clear(&p->cholbuf2); + ae_vector_clear(&p->cholbuf1); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); +} + + +void _spline2dblockllsbuf_destroy(void* _p) +{ + spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p; + ae_touch_ptr((void*)p); + _linlsqrstate_destroy(&p->solver); + _linlsqrreport_destroy(&p->solverrep); + ae_matrix_destroy(&p->blockata); + ae_matrix_destroy(&p->trsmbuf2); + ae_matrix_destroy(&p->cholbuf2); + ae_vector_destroy(&p->cholbuf1); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); +} + + +void _spline2dfastddmbuf_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p; + ae_touch_ptr((void*)p); + _spline2dxdesignmatrix_init(&p->xdesignmatrix, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpz, 0, DT_REAL, _state, make_automatic); + _spline2dfitreport_init(&p->dummyrep, _state, make_automatic); + _spline2dinterpolant_init(&p->localmodel, _state, make_automatic); + _spline2dblockllsbuf_init(&p->blockllsbuf, _state, make_automatic); +} + + +void _spline2dfastddmbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline2dfastddmbuf *dst = (spline2dfastddmbuf*)_dst; + const spline2dfastddmbuf *src = (const spline2dfastddmbuf*)_src; + _spline2dxdesignmatrix_init_copy(&dst->xdesignmatrix, &src->xdesignmatrix, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpz, &src->tmpz, _state, make_automatic); + _spline2dfitreport_init_copy(&dst->dummyrep, &src->dummyrep, _state, make_automatic); + _spline2dinterpolant_init_copy(&dst->localmodel, &src->localmodel, _state, make_automatic); + _spline2dblockllsbuf_init_copy(&dst->blockllsbuf, &src->blockllsbuf, _state, make_automatic); +} + + +void _spline2dfastddmbuf_clear(void* _p) +{ + spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p; + ae_touch_ptr((void*)p); + _spline2dxdesignmatrix_clear(&p->xdesignmatrix); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmpz); + _spline2dfitreport_clear(&p->dummyrep); + _spline2dinterpolant_clear(&p->localmodel); + _spline2dblockllsbuf_clear(&p->blockllsbuf); +} + + +void _spline2dfastddmbuf_destroy(void* _p) +{ + spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p; + ae_touch_ptr((void*)p); + _spline2dxdesignmatrix_destroy(&p->xdesignmatrix); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmpz); + _spline2dfitreport_destroy(&p->dummyrep); + _spline2dinterpolant_destroy(&p->localmodel); + _spline2dblockllsbuf_destroy(&p->blockllsbuf); +} + + +#endif +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX=2 or NX=3). + +INPUT PARAMETERS: + NX - dimension of the space, NX=2 or NX=3 + NY - function dimension, NY>=1 + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv2create(ae_int_t nx, + ae_int_t ny, + rbfv2model* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + _rbfv2model_clear(s); + + ae_assert(nx>=1, "RBFCreate: NX<1", _state); + ae_assert(ny>=1, "RBFCreate: NY<1", _state); + + /* + * Serializable parameters + */ + s->nx = nx; + s->ny = ny; + s->bf = 0; + s->nh = 0; + ae_matrix_set_length(&s->v, ny, nx+1, _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx; j++) + { + s->v.ptr.pp_double[i][j] = (double)(0); + } + } + + /* + * Non-serializable parameters + */ + s->lambdareg = rbfv2_defaultlambdareg; + s->maxits = rbfv2_defaultmaxits; + s->supportr = rbfv2_defaultsupportr; + s->basisfunction = rbfv2_defaultbf; +} + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2016 by Sergey Bochkanov +*************************************************************************/ +void rbfv2createcalcbuffer(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_state *_state) +{ + + _rbfv2calcbuffer_clear(buf); + + rbfv2_allocatecalcbuffer(s, buf, _state); +} + + +/************************************************************************* +This function builds hierarchical RBF model. + +INPUT PARAMETERS: + X - array[N,S.NX], X-values + Y - array[N,S.NY], Y-values + ScaleVec- array[S.NX], vector of per-dimension scales + N - points count + ATerm - linear term type, 1 for linear, 2 for constant, 3 for zero. + NH - hierarchy height + RBase - base RBF radius + BF - basis function type: 0 for Gaussian, 1 for compact + LambdaNS- non-smoothness penalty coefficient. Exactly zero value means + that no penalty is applied, and even system matrix does not + contain penalty-related rows. Value of 1 means + S - RBF model, initialized by RBFCreate() call. + progress10000- variable used for progress reports, it is regularly set + to the current progress multiplied by 10000, in order to + get value in [0,10000] range. The rationale for such scaling + is that it allows us to use integer type to store progress, + which has less potential for non-atomic corruption on unprotected + reads from another threads. + You can read this variable from some other thread to get + estimate of the current progress. + Initial value of this variable is ignored, it is written by + this function, but not read. + terminationrequest - variable used for termination requests; its initial + value must be False, and you can set it to True from some + other thread. This routine regularly checks this variable + and will terminate model construction shortly upon discovering + that termination was requested. + +OUTPUT PARAMETERS: + S - updated model (for rep.terminationtype>0, unchanged otherwise) + Rep - report: + * Rep.TerminationType: + * -5 - non-distinct basis function centers were detected, + interpolation aborted + * -4 - nonconvergence of the internal SVD solver + * 1 - successful termination + * 8 terminated by user via rbfrequesttermination() + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the LSQR solver + * Rep.NMV - number of matrix-vector products + * Rep.ARows - rows count for the system matrix + * Rep.ACols - columns count for the system matrix + * Rep.ANNZ - number of significantly non-zero elements + (elements above some algorithm-determined threshold) + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfv2buildhierarchical(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + /* Real */ const ae_vector* scalevec, + ae_int_t aterm, + ae_int_t nh, + double rbase, + double lambdans, + rbfv2model* s, + ae_int_t* progress10000, + ae_bool* terminationrequest, + rbfv2report* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t bf; + ae_matrix rhs; + ae_matrix residualy; + ae_matrix v; + ae_int_t rowsperpoint; + ae_vector hidx; + ae_vector xr; + ae_vector ri; + ae_vector kdroots; + ae_vector kdnodes; + ae_vector kdsplits; + ae_vector kdboxmin; + ae_vector kdboxmax; + ae_vector cw; + ae_vector cwrange; + ae_matrix curxy; + ae_int_t curn; + ae_int_t nbasis; + kdtree curtree; + kdtree globaltree; + ae_vector x0; + ae_vector x1; + ae_vector tags; + ae_vector dist; + ae_vector nncnt; + ae_vector rowsizes; + ae_vector diagata; + ae_vector prec; + ae_vector tmpx; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k2; + ae_int_t levelidx; + ae_int_t offsi; + ae_int_t offsj; + double val; + double criticalr; + ae_int_t cnt; + double avgdiagata; + ae_vector avgrowsize; + double sumrowsize; + double rprogress; + ae_int_t maxits; + linlsqrstate linstate; + linlsqrreport lsqrrep; + sparsematrix sparseacrs; + ae_vector densew1; + ae_vector denseb1; + rbfv2calcbuffer calcbuf; + ae_vector vr2; + ae_vector voffs; + ae_vector rowindexes; + ae_vector rowvals; + double penalty; + + ae_frame_make(_state, &_frame_block); + memset(&rhs, 0, sizeof(rhs)); + memset(&residualy, 0, sizeof(residualy)); + memset(&v, 0, sizeof(v)); + memset(&hidx, 0, sizeof(hidx)); + memset(&xr, 0, sizeof(xr)); + memset(&ri, 0, sizeof(ri)); + memset(&kdroots, 0, sizeof(kdroots)); + memset(&kdnodes, 0, sizeof(kdnodes)); + memset(&kdsplits, 0, sizeof(kdsplits)); + memset(&kdboxmin, 0, sizeof(kdboxmin)); + memset(&kdboxmax, 0, sizeof(kdboxmax)); + memset(&cw, 0, sizeof(cw)); + memset(&cwrange, 0, sizeof(cwrange)); + memset(&curxy, 0, sizeof(curxy)); + memset(&curtree, 0, sizeof(curtree)); + memset(&globaltree, 0, sizeof(globaltree)); + memset(&x0, 0, sizeof(x0)); + memset(&x1, 0, sizeof(x1)); + memset(&tags, 0, sizeof(tags)); + memset(&dist, 0, sizeof(dist)); + memset(&nncnt, 0, sizeof(nncnt)); + memset(&rowsizes, 0, sizeof(rowsizes)); + memset(&diagata, 0, sizeof(diagata)); + memset(&prec, 0, sizeof(prec)); + memset(&tmpx, 0, sizeof(tmpx)); + memset(&avgrowsize, 0, sizeof(avgrowsize)); + memset(&linstate, 0, sizeof(linstate)); + memset(&lsqrrep, 0, sizeof(lsqrrep)); + memset(&sparseacrs, 0, sizeof(sparseacrs)); + memset(&densew1, 0, sizeof(densew1)); + memset(&denseb1, 0, sizeof(denseb1)); + memset(&calcbuf, 0, sizeof(calcbuf)); + memset(&vr2, 0, sizeof(vr2)); + memset(&voffs, 0, sizeof(voffs)); + memset(&rowindexes, 0, sizeof(rowindexes)); + memset(&rowvals, 0, sizeof(rowvals)); + _rbfv2report_clear(rep); + ae_matrix_init(&rhs, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&hidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&xr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ri, 0, DT_REAL, _state, ae_true); + ae_vector_init(&kdroots, 0, DT_INT, _state, ae_true); + ae_vector_init(&kdnodes, 0, DT_INT, _state, ae_true); + ae_vector_init(&kdsplits, 0, DT_REAL, _state, ae_true); + ae_vector_init(&kdboxmin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&kdboxmax, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cw, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cwrange, 0, DT_INT, _state, ae_true); + ae_matrix_init(&curxy, 0, 0, DT_REAL, _state, ae_true); + _kdtree_init(&curtree, _state, ae_true); + _kdtree_init(&globaltree, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tags, 0, DT_INT, _state, ae_true); + ae_vector_init(&dist, 0, DT_REAL, _state, ae_true); + ae_vector_init(&nncnt, 0, DT_INT, _state, ae_true); + ae_vector_init(&rowsizes, 0, DT_INT, _state, ae_true); + ae_vector_init(&diagata, 0, DT_REAL, _state, ae_true); + ae_vector_init(&prec, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&avgrowsize, 0, DT_REAL, _state, ae_true); + _linlsqrstate_init(&linstate, _state, ae_true); + _linlsqrreport_init(&lsqrrep, _state, ae_true); + _sparsematrix_init(&sparseacrs, _state, ae_true); + ae_vector_init(&densew1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&denseb1, 0, DT_REAL, _state, ae_true); + _rbfv2calcbuffer_init(&calcbuf, _state, ae_true); + ae_vector_init(&vr2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&voffs, 0, DT_INT, _state, ae_true); + ae_vector_init(&rowindexes, 0, DT_INT, _state, ae_true); + ae_vector_init(&rowvals, 0, DT_REAL, _state, ae_true); + + ae_assert(s->nx>0, "RBFV2BuildHierarchical: incorrect NX", _state); + ae_assert(s->ny>0, "RBFV2BuildHierarchical: incorrect NY", _state); + ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "RBFV2BuildHierarchical: incorrect LambdaNS", _state); + for(j=0; j<=s->nx-1; j++) + { + ae_assert(ae_fp_greater(scalevec->ptr.p_double[j],(double)(0)), "RBFV2BuildHierarchical: incorrect ScaleVec", _state); + } + nx = s->nx; + ny = s->ny; + bf = s->basisfunction; + ae_assert(bf==0||bf==1, "RBFV2BuildHierarchical: incorrect BF", _state); + + /* + * Clean up communication and report fields + */ + *progress10000 = 0; + rep->maxerror = (double)(0); + rep->rmserror = (double)(0); + + /* + * Quick exit when we have no points + */ + if( n==0 ) + { + rbfv2_zerofill(s, nx, ny, bf, _state); + rep->terminationtype = 1; + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + + /* + * First model in a sequence - linear model. + * Residuals from linear regression are stored in the ResidualY variable + * (used later to build RBF models). + */ + ae_matrix_set_length(&residualy, n, ny, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j]; + } + } + if( !rbfv2_rbfv2buildlinearmodel(x, &residualy, n, nx, ny, aterm, &v, _state) ) + { + rbfv2_zerofill(s, nx, ny, bf, _state); + rep->terminationtype = -5; + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + + /* + * Handle special case: multilayer model with NLayers=0. + * Quick exit. + */ + if( nh==0 ) + { + rep->terminationtype = 1; + rbfv2_zerofill(s, nx, ny, bf, _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx; j++) + { + s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j]; + } + } + rep->maxerror = (double)(0); + rep->rmserror = (double)(0); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(residualy.ptr.pp_double[i][j], _state), _state); + rep->rmserror = rep->rmserror+ae_sqr(residualy.ptr.pp_double[i][j], _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)(n*ny), _state); + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + + /* + * Penalty coefficient is set to LambdaNS*RBase^2. + * + * We use such normalization because VALUES of radial basis + * functions have roughly unit magnitude, but their DERIVATIVES + * are (roughly) inversely proportional to the radius. Thus, + * without additional scaling, regularization coefficient + * looses invariancy w.r.t. scaling of variables. + */ + if( ae_fp_eq(lambdans,(double)(0)) ) + { + rowsperpoint = 1; + } + else + { + + /* + * NOTE: simplified penalty function is used, which does not provide rotation invariance + */ + rowsperpoint = 1+nx; + } + penalty = lambdans*ae_sqr(rbase, _state); + + /* + * Prepare temporary structures + */ + ae_matrix_set_length(&rhs, n*rowsperpoint, ny, _state); + ae_matrix_set_length(&curxy, n, nx+ny, _state); + ae_vector_set_length(&x0, nx, _state); + ae_vector_set_length(&x1, nx, _state); + ae_vector_set_length(&tags, n, _state); + ae_vector_set_length(&dist, n, _state); + ae_vector_set_length(&vr2, n, _state); + ae_vector_set_length(&voffs, n, _state); + ae_vector_set_length(&nncnt, n, _state); + ae_vector_set_length(&rowsizes, n*rowsperpoint, _state); + ae_vector_set_length(&denseb1, n*rowsperpoint, _state); + for(i=0; i<=n*rowsperpoint-1; i++) + { + for(j=0; j<=ny-1; j++) + { + rhs.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j]; + } + for(j=0; j<=ny-1; j++) + { + rhs.ptr.pp_double[i*rowsperpoint][j] = residualy.ptr.pp_double[i][j]; + } + tags.ptr.p_int[i] = i; + } + kdtreebuildtagged(&curxy, &tags, n, nx, 0, 2, &globaltree, _state); + + /* + * Generate sequence of layer radii. + * Prepare assignment of different levels to points. + */ + ae_assert(n>0, "RBFV2BuildHierarchical: integrity check failed", _state); + ae_vector_set_length(&ri, nh, _state); + for(levelidx=0; levelidx<=nh-1; levelidx++) + { + ri.ptr.p_double[levelidx] = rbase*ae_pow((double)(2), (double)(-levelidx), _state); + } + ae_vector_set_length(&hidx, n, _state); + ae_vector_set_length(&xr, n, _state); + for(i=0; i<=n-1; i++) + { + hidx.ptr.p_int[i] = nh; + xr.ptr.p_double[i] = ae_maxrealnumber; + ae_assert(ae_fp_greater(xr.ptr.p_double[i],ri.ptr.p_double[0]), "RBFV2BuildHierarchical: integrity check failed", _state); + } + for(levelidx=0; levelidx<=nh-1; levelidx++) + { + + /* + * Scan dataset points, for each such point that distance to nearest + * "support" point is larger than SupportR*Ri[LevelIdx] we: + * * set distance of current point to 0 (it is support now) and update HIdx + * * perform R-NN request with radius SupportR*Ri[LevelIdx] + * * for each point in request update its distance + */ + criticalr = s->supportr*ri.ptr.p_double[levelidx]; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(xr.ptr.p_double[i],criticalr) ) + { + + /* + * Mark point as support + */ + ae_assert(hidx.ptr.p_int[i]==nh, "RBFV2BuildHierarchical: integrity check failed", _state); + hidx.ptr.p_int[i] = levelidx; + xr.ptr.p_double[i] = (double)(0); + + /* + * Update neighbors + */ + for(j=0; j<=nx-1; j++) + { + x0.ptr.p_double[j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j]; + } + k = kdtreequeryrnn(&globaltree, &x0, criticalr, ae_true, _state); + kdtreequeryresultstags(&globaltree, &tags, _state); + kdtreequeryresultsdistances(&globaltree, &dist, _state); + for(j=0; j<=k-1; j++) + { + xr.ptr.p_double[tags.ptr.p_int[j]] = ae_minreal(xr.ptr.p_double[tags.ptr.p_int[j]], dist.ptr.p_double[j], _state); + } + } + } + } + + /* + * Build multitree (with zero weights) according to hierarchy. + * + * NOTE: this code assumes that during every iteration kdNodes, + * kdSplits and CW have size which EXACTLY fits their + * contents, and that these variables are resized at each + * iteration when we add new hierarchical model. + */ + ae_vector_set_length(&kdroots, nh+1, _state); + ae_vector_set_length(&kdnodes, 0, _state); + ae_vector_set_length(&kdsplits, 0, _state); + ae_vector_set_length(&kdboxmin, nx, _state); + ae_vector_set_length(&kdboxmax, nx, _state); + ae_vector_set_length(&cw, 0, _state); + ae_vector_set_length(&cwrange, nh+1, _state); + kdtreeexplorebox(&globaltree, &kdboxmin, &kdboxmax, _state); + cwrange.ptr.p_int[0] = 0; + for(levelidx=0; levelidx<=nh-1; levelidx++) + { + + /* + * Prepare radius and root offset + */ + kdroots.ptr.p_int[levelidx] = kdnodes.cnt; + + /* + * Generate LevelIdx-th tree and append to multi-tree + */ + curn = 0; + for(i=0; i<=n-1; i++) + { + if( hidx.ptr.p_int[i]<=levelidx ) + { + for(j=0; j<=nx-1; j++) + { + curxy.ptr.pp_double[curn][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j]; + } + for(j=0; j<=ny-1; j++) + { + curxy.ptr.pp_double[curn][nx+j] = (double)(0); + } + inc(&curn, _state); + } + } + ae_assert(curn>0, "RBFV2BuildHierarchical: integrity check failed", _state); + kdtreebuild(&curxy, curn, nx, ny, 2, &curtree, _state); + rbfv2_convertandappendtree(&curtree, curn, nx, ny, &kdnodes, &kdsplits, &cw, _state); + + /* + * Fill entry of CWRange (we assume that length of CW exactly fits its actual size) + */ + cwrange.ptr.p_int[levelidx+1] = cw.cnt; + } + kdroots.ptr.p_int[nh] = kdnodes.cnt; + + /* + * Prepare buffer and scaled dataset + */ + rbfv2_allocatecalcbuffer(s, &calcbuf, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j]; + } + } + + /* + * Calculate average row sizes for each layer; these values are used + * for smooth progress reporting (it adds some overhead, but in most + * cases - insignificant one). + */ + rvectorsetlengthatleast(&avgrowsize, nh, _state); + sumrowsize = (double)(0); + for(levelidx=0; levelidx<=nh-1; levelidx++) + { + cnt = 0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j]; + } + cnt = cnt+rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state); + } + avgrowsize.ptr.p_double[levelidx] = coalesce((double)(cnt), (double)(1), _state)/coalesce((double)(n), (double)(1), _state); + sumrowsize = sumrowsize+avgrowsize.ptr.p_double[levelidx]; + } + + /* + * Build unconstrained model with LSQR solver, applied layer by layer + */ + for(levelidx=0; levelidx<=nh-1; levelidx++) + { + + /* + * Generate A - matrix of basis functions (near radius is used) + * + * NOTE: AvgDiagATA is average value of diagonal element of A^T*A. + * It is used to calculate value of Tikhonov regularization + * coefficient. + */ + nbasis = (cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx])/(nx+ny); + ae_assert(cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx]==nbasis*(nx+ny), "Assertion failed", _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j]; + } + cnt = rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state); + nncnt.ptr.p_int[i] = cnt; + for(j=0; j<=rowsperpoint-1; j++) + { + rowsizes.ptr.p_int[i*rowsperpoint+j] = cnt; + } + } + ivectorsetlengthatleast(&rowindexes, nbasis, _state); + rvectorsetlengthatleast(&rowvals, nbasis*rowsperpoint, _state); + rvectorsetlengthatleast(&diagata, nbasis, _state); + sparsecreatecrsbuf(n*rowsperpoint, nbasis, &rowsizes, &sparseacrs, _state); + avgdiagata = 0.0; + for(j=0; j<=nbasis-1; j++) + { + diagata.ptr.p_double[j] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + + /* + * Fill design matrix row, diagonal of A^T*A + */ + for(j=0; j<=nx-1; j++) + { + x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j]; + } + rbfv2_designmatrixgeneraterow(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, &cwrange, nx, ny, nh, levelidx, bf, rbfv2nearradius(bf, _state), rowsperpoint, penalty, &x0, &calcbuf, &vr2, &voffs, &rowindexes, &rowvals, &cnt, _state); + ae_assert(cnt==nncnt.ptr.p_int[i], "RBFV2BuildHierarchical: integrity check failed", _state); + for(k=0; k<=rowsperpoint-1; k++) + { + for(j=0; j<=cnt-1; j++) + { + val = rowvals.ptr.p_double[j*rowsperpoint+k]; + sparseset(&sparseacrs, i*rowsperpoint+k, rowindexes.ptr.p_int[j], val, _state); + avgdiagata = avgdiagata+ae_sqr(val, _state); + diagata.ptr.p_double[rowindexes.ptr.p_int[j]] = diagata.ptr.p_double[rowindexes.ptr.p_int[j]]+ae_sqr(val, _state); + } + } + + /* + * Handle possible termination requests + */ + if( *terminationrequest ) + { + + /* + * Request for termination was submitted, terminate immediately + */ + rbfv2_zerofill(s, nx, ny, bf, _state); + rep->terminationtype = 8; + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + } + avgdiagata = avgdiagata/(double)nbasis; + rvectorsetlengthatleast(&prec, nbasis, _state); + for(j=0; j<=nbasis-1; j++) + { + prec.ptr.p_double[j] = (double)1/coalesce(ae_sqrt(diagata.ptr.p_double[j], _state), (double)(1), _state); + } + + /* + * solve + */ + maxits = coalescei(s->maxits, rbfv2_defaultmaxits, _state); + rvectorsetlengthatleast(&tmpx, nbasis, _state); + linlsqrcreate(n*rowsperpoint, nbasis, &linstate, _state); + linlsqrsetcond(&linstate, 0.0, 0.0, maxits, _state); + linlsqrsetlambdai(&linstate, ae_sqrt(s->lambdareg*avgdiagata, _state), _state); + for(j=0; j<=ny-1; j++) + { + for(i=0; i<=n*rowsperpoint-1; i++) + { + denseb1.ptr.p_double[i] = rhs.ptr.pp_double[i][j]; + } + linlsqrsetb(&linstate, &denseb1, _state); + linlsqrrestart(&linstate, _state); + linlsqrsetxrep(&linstate, ae_true, _state); + while(linlsqriteration(&linstate, _state)) + { + if( *terminationrequest ) + { + + /* + * Request for termination was submitted, terminate immediately + */ + rbfv2_zerofill(s, nx, ny, bf, _state); + rep->terminationtype = 8; + *progress10000 = 10000; + ae_frame_leave(_state); + return; + } + if( linstate.needmv ) + { + for(i=0; i<=nbasis-1; i++) + { + tmpx.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.x.ptr.p_double[i]; + } + sparsemv(&sparseacrs, &tmpx, &linstate.mv, _state); + continue; + } + if( linstate.needmtv ) + { + sparsemtv(&sparseacrs, &linstate.x, &linstate.mtv, _state); + for(i=0; i<=nbasis-1; i++) + { + linstate.mtv.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.mtv.ptr.p_double[i]; + } + continue; + } + if( linstate.xupdated ) + { + rprogress = (double)(0); + for(i=0; i<=levelidx-1; i++) + { + rprogress = rprogress+(double)(maxits*ny)*avgrowsize.ptr.p_double[i]; + } + rprogress = rprogress+(double)(linlsqrpeekiterationscount(&linstate, _state)+j*maxits)*avgrowsize.ptr.p_double[levelidx]; + rprogress = rprogress/(sumrowsize*(double)maxits*(double)ny); + rprogress = (double)10000*rprogress; + rprogress = ae_maxreal(rprogress, (double)(0), _state); + rprogress = ae_minreal(rprogress, (double)(10000), _state); + ae_assert(*progress10000<=ae_round(rprogress, _state)+1, "HRBF: integrity check failed (progress indicator) even after +1 safeguard correction", _state); + *progress10000 = ae_round(rprogress, _state); + continue; + } + ae_assert(ae_false, "HRBF: unexpected request from LSQR solver", _state); + } + linlsqrresults(&linstate, &densew1, &lsqrrep, _state); + ae_assert(lsqrrep.terminationtype>0, "RBFV2BuildHierarchical: integrity check failed", _state); + for(i=0; i<=nbasis-1; i++) + { + densew1.ptr.p_double[i] = prec.ptr.p_double[i]*densew1.ptr.p_double[i]; + } + for(i=0; i<=nbasis-1; i++) + { + offsi = cwrange.ptr.p_int[levelidx]+(nx+ny)*i; + cw.ptr.p_double[offsi+nx+j] = densew1.ptr.p_double[i]; + } + } + + /* + * Update residuals (far radius is used) + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j]; + } + rbfv2_designmatrixgeneraterow(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, &cwrange, nx, ny, nh, levelidx, bf, rbfv2farradius(bf, _state), rowsperpoint, penalty, &x0, &calcbuf, &vr2, &voffs, &rowindexes, &rowvals, &cnt, _state); + for(j=0; j<=cnt-1; j++) + { + offsj = cwrange.ptr.p_int[levelidx]+(nx+ny)*rowindexes.ptr.p_int[j]+nx; + for(k=0; k<=rowsperpoint-1; k++) + { + val = rowvals.ptr.p_double[j*rowsperpoint+k]; + for(k2=0; k2<=ny-1; k2++) + { + rhs.ptr.pp_double[i*rowsperpoint+k][k2] = rhs.ptr.pp_double[i*rowsperpoint+k][k2]-val*cw.ptr.p_double[offsj+k2]; + } + } + } + } + } + + /* + * Model is built. + * + * Copy local variables by swapping, global ones (ScaleVec) are copied + * explicitly. + */ + s->bf = bf; + s->nh = nh; + ae_swap_vectors(&s->ri, &ri); + ae_swap_vectors(&s->kdroots, &kdroots); + ae_swap_vectors(&s->kdnodes, &kdnodes); + ae_swap_vectors(&s->kdsplits, &kdsplits); + ae_swap_vectors(&s->kdboxmin, &kdboxmin); + ae_swap_vectors(&s->kdboxmax, &kdboxmax); + ae_swap_vectors(&s->cw, &cw); + ae_swap_matrices(&s->v, &v); + ae_vector_set_length(&s->s, nx, _state); + for(i=0; i<=nx-1; i++) + { + s->s.ptr.p_double[i] = scalevec->ptr.p_double[i]; + } + rep->terminationtype = 1; + + /* + * Calculate maximum and RMS errors + */ + rep->maxerror = (double)(0); + rep->rmserror = (double)(0); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ny-1; j++) + { + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(rhs.ptr.pp_double[i*rowsperpoint][j], _state), _state); + rep->rmserror = rep->rmserror+ae_sqr(rhs.ptr.pp_double[i*rowsperpoint][j], _state); + } + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)(n*ny), _state); + + /* + * Update progress reports + */ + *progress10000 = 10000; + ae_frame_leave(_state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv2alloc(ae_serializer* s, + const rbfv2model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &model->ri, -1, _state); + allocrealarray(s, &model->s, -1, _state); + allocintegerarray(s, &model->kdroots, -1, _state); + allocintegerarray(s, &model->kdnodes, -1, _state); + allocrealarray(s, &model->kdsplits, -1, _state); + allocrealarray(s, &model->kdboxmin, -1, _state); + allocrealarray(s, &model->kdboxmax, -1, _state); + allocrealarray(s, &model->cw, -1, _state); + allocrealmatrix(s, &model->v, -1, -1, _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv2serialize(ae_serializer* s, + const rbfv2model* model, + ae_state *_state) +{ + + + + /* + * Data + */ + ae_serializer_serialize_int(s, model->nx, _state); + ae_serializer_serialize_int(s, model->ny, _state); + ae_serializer_serialize_int(s, model->nh, _state); + ae_serializer_serialize_int(s, model->bf, _state); + serializerealarray(s, &model->ri, -1, _state); + serializerealarray(s, &model->s, -1, _state); + serializeintegerarray(s, &model->kdroots, -1, _state); + serializeintegerarray(s, &model->kdnodes, -1, _state); + serializerealarray(s, &model->kdsplits, -1, _state); + serializerealarray(s, &model->kdboxmin, -1, _state); + serializerealarray(s, &model->kdboxmax, -1, _state); + serializerealarray(s, &model->cw, -1, _state); + serializerealmatrix(s, &model->v, -1, -1, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfv2unserialize(ae_serializer* s, + rbfv2model* model, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t ny; + + _rbfv2model_clear(model); + + + /* + * Unserialize primary model parameters, initialize model. + * + * It is necessary to call RBFCreate() because some internal fields + * which are NOT unserialized will need initialization. + */ + ae_serializer_unserialize_int(s, &nx, _state); + ae_serializer_unserialize_int(s, &ny, _state); + rbfv2create(nx, ny, model, _state); + ae_serializer_unserialize_int(s, &model->nh, _state); + ae_serializer_unserialize_int(s, &model->bf, _state); + unserializerealarray(s, &model->ri, _state); + unserializerealarray(s, &model->s, _state); + unserializeintegerarray(s, &model->kdroots, _state); + unserializeintegerarray(s, &model->kdnodes, _state); + unserializerealarray(s, &model->kdsplits, _state); + unserializerealarray(s, &model->kdboxmin, _state); + unserializerealarray(s, &model->kdboxmax, _state); + unserializerealarray(s, &model->cw, _state); + unserializerealmatrix(s, &model->v, _state); +} + + +/************************************************************************* +Returns far radius for basis function type +*************************************************************************/ +double rbfv2farradius(ae_int_t bf, ae_state *_state) +{ + double result; + + + result = (double)(1); + if( bf==0 ) + { + result = 5.0; + } + if( bf==1 ) + { + result = (double)(3); + } + return result; +} + + +/************************************************************************* +Returns near radius for basis function type +*************************************************************************/ +double rbfv2nearradius(ae_int_t bf, ae_state *_state) +{ + double result; + + + result = (double)(1); + if( bf==0 ) + { + result = 3.0; + } + if( bf==1 ) + { + result = (double)(3); + } + return result; +} + + +/************************************************************************* +Returns basis function value. +Assumes that D2>=0 +*************************************************************************/ +double rbfv2basisfunc(ae_int_t bf, double d2, ae_state *_state) +{ + double v; + double result; + + + result = (double)(0); + if( bf==0 ) + { + result = ae_exp(-d2, _state); + return result; + } + if( bf==1 ) + { + + /* + * if D2<3: + * Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9)) + * else: + * 0 + */ + v = (double)1-d2/(double)9; + if( ae_fp_less_eq(v,(double)(0)) ) + { + result = (double)(0); + return result; + } + result = 2.718281828459045*ae_exp(-d2, _state)*ae_exp(-(double)1/v, _state); + return result; + } + ae_assert(ae_false, "RBFV2BasisFunc: unknown BF type", _state); + return result; +} + + +/************************************************************************* +Returns basis function value, first and second derivatives +Assumes that D2>=0 +*************************************************************************/ +void rbfv2basisfuncdiff2(ae_int_t bf, + double d2, + double* f, + double* df, + double* d2f, + ae_state *_state) +{ + double v; + + *f = 0.0; + *df = 0.0; + *d2f = 0.0; + + if( bf==0 ) + { + *f = ae_exp(-d2, _state); + *df = -*f; + *d2f = *f; + return; + } + if( bf==1 ) + { + + /* + * if D2<3: + * F = Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9)) + * dF = -F * [pow(D2/9-1,-2)/9 + 1] + * d2F = -dF * [pow(D2/9-1,-2)/9 + 1] - F*(2/81)*pow(D2/9-1,-3) + * else: + * 0 + */ + v = (double)1-d2/(double)9; + if( ae_fp_less_eq(v,(double)(0)) ) + { + *f = (double)(0); + *df = (double)(0); + *d2f = (double)(0); + return; + } + *f = ae_exp((double)(1), _state)*ae_exp(-d2, _state)*ae_exp(-(double)1/v, _state); + *df = -*f*((double)1/((double)9*v*v)+(double)1); + *d2f = -*df*((double)1/((double)9*v*v)+(double)1)-*f*((double)2/(double)81)/(v*v*v); + return; + } + ae_assert(ae_false, "RBFV2BasisFuncDiff2: unknown BF type", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=1 +(1-dimensional space). + +This function returns 0.0 when: +* model is not initialized +* NX<>1 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - X-coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfv2calc1(rbfv2model* s, double x0, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state); + if( s->ny!=1||s->nx!=1 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0-s->v.ptr.pp_double[0][1]; + if( s->nh==0 ) + { + return result; + } + rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state); + s->calcbuf.x123.ptr.p_double[0] = x0; + rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=2 +(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +If you want to calculate function values many times, consider using +RBFGridCalc2(), which is far more efficient than many subsequent calls to +RBFCalc2(). + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfv2calc2(rbfv2model* s, double x0, double x1, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); + if( s->ny!=1||s->nx!=2 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]; + if( s->nh==0 ) + { + return result; + } + rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state); + s->calcbuf.x123.ptr.p_double[0] = x0; + s->calcbuf.x123.ptr.p_double[1] = x1; + rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model in the given point. + +This function should be used when we have NY=1 (scalar function) and NX=3 +(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If +you have general situation (NX-dimensional space, NY-dimensional function) +you should use general, less efficient implementation RBFCalc(). + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfv2calc3(rbfv2model* s, + double x0, + double x1, + double x2, + ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); + if( s->ny!=1||s->nx!=3 ) + { + result = (double)(0); + return result; + } + result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][3]; + if( s->nh==0 ) + { + return result; + } + rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state); + s->calcbuf.x123.ptr.p_double[0] = x0; + s->calcbuf.x123.ptr.p_double[1] = x1; + s->calcbuf.x123.ptr.p_double[2] = x2; + rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state); + result = s->calcbuf.y123.ptr.p_double[0]; + return result; +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +Same as RBFCalc(), but does not reallocate Y when in is large enough to +store function values. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv2calcbuf(rbfv2model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + + rbfv2tscalcbuf(s, &s->calcbuf, x, y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point, using +external buffer object (internal temporaries of RBF model are not +modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv2tscalcbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t levelidx; + double rcur; + double rquery2; + double invrc2; + ae_int_t nx; + ae_int_t ny; + + + ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + + /* + * Handle linear term + */ + if( y->cntptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + if( s->nh==0 ) + { + return; + } + + /* + * Handle nonlinear term + */ + rbfv2_allocatecalcbuffer(s, buf, _state); + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + for(levelidx=0; levelidx<=s->nh-1; levelidx++) + { + + /* + * Prepare fields of Buf required by PartialCalcRec() + */ + buf->curdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + buf->curboxmin.ptr.p_double[j] = s->kdboxmin.ptr.p_double[j]; + buf->curboxmax.ptr.p_double[j] = s->kdboxmax.ptr.p_double[j]; + if( ae_fp_less(buf->x.ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-buf->x.ptr.p_double[j], _state); + } + else + { + if( ae_fp_greater(buf->x.ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->x.ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state); + } + } + } + + /* + * Call PartialCalcRec() + */ + rcur = s->ri.ptr.p_double[levelidx]; + invrc2 = (double)1/(rcur*rcur); + rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + rbfv2_partialcalcrec(s, buf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->x, y, y, y, 0, _state); + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its derivatives, using external buffer object (internal temporaries of the +RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv2tsdiffbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t levelidx; + double rcur; + double rquery2; + double invrc2; + ae_int_t nx; + ae_int_t ny; + + + ae_assert(x->cnt>=s->nx, "RBFDiffBuf: Length(X)nx, _state), "RBFDiffBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + + /* + * Handle linear term + */ + for(i=0; i<=ny-1; i++) + { + y->ptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*nx+j] = s->v.ptr.pp_double[i][j]; + } + } + if( s->nh==0 ) + { + return; + } + + /* + * Handle nonlinear term + */ + rbfv2_allocatecalcbuffer(s, buf, _state); + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]*s->s.ptr.p_double[j]; + } + } + for(levelidx=0; levelidx<=s->nh-1; levelidx++) + { + + /* + * Prepare fields of Buf required by PartialCalcRec() + */ + buf->curdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + buf->curboxmin.ptr.p_double[j] = s->kdboxmin.ptr.p_double[j]; + buf->curboxmax.ptr.p_double[j] = s->kdboxmax.ptr.p_double[j]; + if( ae_fp_less(buf->x.ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-buf->x.ptr.p_double[j], _state); + } + else + { + if( ae_fp_greater(buf->x.ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->x.ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state); + } + } + } + + /* + * Call PartialCalcRec() + */ + rcur = s->ri.ptr.p_double[levelidx]; + invrc2 = (double)1/(rcur*rcur); + rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + rbfv2_partialcalcrec(s, buf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->x, y, dy, dy, 1, _state); + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]/s->s.ptr.p_double[j]; + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point and +its first and second derivatives, using external buffer object (internal +temporaries of the RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y - possibly preallocated arrays + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + DY - derivatives, array[NY*NX]. DY is not reallocated when it + is larger than NY*NX. + D2Y - second derivatives, array[NY*NX*NX] + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfv2tshessbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t levelidx; + double rcur; + double rquery2; + double invrc2; + ae_int_t nx; + ae_int_t ny; + + + ae_assert(x->cnt>=s->nx, "RBFDiffBuf: Length(X)nx, _state), "RBFDiffBuf: X contains infinite or NaN values", _state); + nx = s->nx; + ny = s->ny; + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + if( d2y->cntptr.p_double[i] = s->v.ptr.pp_double[i][nx]; + for(j=0; j<=nx-1; j++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j]; + dy->ptr.p_double[i*nx+j] = s->v.ptr.pp_double[i][j]; + } + } + rsetv(ny*nx*nx, 0.0, d2y, _state); + if( s->nh==0 ) + { + return; + } + + /* + * Handle nonlinear term + */ + rbfv2_allocatecalcbuffer(s, buf, _state); + for(j=0; j<=nx-1; j++) + { + buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j]; + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]*s->s.ptr.p_double[j]; + } + } + for(levelidx=0; levelidx<=s->nh-1; levelidx++) + { + + /* + * Prepare fields of Buf required by PartialCalcRec() + */ + buf->curdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + buf->curboxmin.ptr.p_double[j] = s->kdboxmin.ptr.p_double[j]; + buf->curboxmax.ptr.p_double[j] = s->kdboxmax.ptr.p_double[j]; + if( ae_fp_less(buf->x.ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-buf->x.ptr.p_double[j], _state); + } + else + { + if( ae_fp_greater(buf->x.ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->x.ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state); + } + } + } + + /* + * Call PartialCalcRec() + */ + rcur = s->ri.ptr.p_double[levelidx]; + invrc2 = (double)1/(rcur*rcur); + rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + rbfv2_partialcalcrec(s, buf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->x, y, dy, d2y, 2, _state); + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + dy->ptr.p_double[i*nx+j] = dy->ptr.p_double[i*nx+j]/s->s.ptr.p_double[j]; + } + } + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx-1; j++) + { + for(k=0; k<=nx-1; k++) + { + d2y->ptr.p_double[i*nx*nx+j*nx+k] = d2y->ptr.p_double[i*nx*nx+j*nx+k]/(s->s.ptr.p_double[j]*s->s.ptr.p_double[k]); + } + } + } +} + + +/************************************************************************* +This function calculates values of the RBF model at the regular grid. + +Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - array of grid nodes, first coordinates, array[N0] + N0 - grid size (number of nodes) in the first dimension + X1 - array of grid nodes, second coordinates, array[N1] + N1 - grid size (number of nodes) in the second dimension + +OUTPUT PARAMETERS: + Y - function values, array[N0,N1]. Y is out-variable and + is reallocated by this function. + +NOTE: as a special exception, this function supports unordered arrays X0 + and X1. However, future versions may be more efficient for X0/X1 + ordered by ascending. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv2gridcalc2(rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector cpx0; + ae_vector cpx1; + ae_vector dummyx2; + ae_vector dummyx3; + ae_vector dummyflag; + ae_vector p01; + ae_vector p11; + ae_vector p2; + ae_vector vy; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&cpx0, 0, sizeof(cpx0)); + memset(&cpx1, 0, sizeof(cpx1)); + memset(&dummyx2, 0, sizeof(dummyx2)); + memset(&dummyx3, 0, sizeof(dummyx3)); + memset(&dummyflag, 0, sizeof(dummyflag)); + memset(&p01, 0, sizeof(p01)); + memset(&p11, 0, sizeof(p11)); + memset(&p2, 0, sizeof(p2)); + memset(&vy, 0, sizeof(vy)); + ae_matrix_clear(y); + ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyflag, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&p01, 0, DT_INT, _state, ae_true); + ae_vector_init(&p11, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + ae_vector_init(&vy, 0, DT_REAL, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)cnt>=n1, "RBFGridCalc2: Length(X1)ptr.pp_double[i][j] = (double)(0); + } + } + if( s->ny!=1||s->nx!=2 ) + { + ae_frame_leave(_state); + return; + } + + /* + *create and sort arrays + */ + ae_vector_set_length(&cpx0, n0, _state); + for(i=0; i<=n0-1; i++) + { + cpx0.ptr.p_double[i] = x0->ptr.p_double[i]; + } + tagsort(&cpx0, n0, &p01, &p2, _state); + ae_vector_set_length(&cpx1, n1, _state); + for(i=0; i<=n1-1; i++) + { + cpx1.ptr.p_double[i] = x1->ptr.p_double[i]; + } + tagsort(&cpx1, n1, &p11, &p2, _state); + ae_vector_set_length(&dummyx2, 1, _state); + dummyx2.ptr.p_double[0] = (double)(0); + ae_vector_set_length(&dummyx3, 1, _state); + dummyx3.ptr.p_double[0] = (double)(0); + ae_vector_set_length(&vy, n0*n1, _state); + rbfv2gridcalcvx(s, &cpx0, n0, &cpx1, n1, &dummyx2, 1, &dummyx3, 1, &dummyflag, ae_false, &vy, _state); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + y->ptr.pp_double[i][j] = vy.ptr.p_double[i+j*n0]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function is used to perform gridded calculation for 2D, 3D or 4D +problems. It accepts parameters X0...X3 and counters N0...N3. If RBF model +has dimensionality less than 4, corresponding arrays should contain just +one element equal to zero, and corresponding N's should be equal to 1. + +NOTE: array Y should be preallocated by caller. + + -- ALGLIB -- + Copyright 12.07.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfv2gridcalcvx(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector tx; + ae_vector ty; + ae_vector z; + ae_int_t dstoffs; + ae_int_t dummy; + rbfv2gridcalcbuffer bufseedv2; + ae_shared_pool bufpool; + ae_int_t rowidx; + ae_int_t rowcnt; + double v; + double rcur; + ae_int_t levelidx; + double searchradius2; + ae_int_t ntrials; + double avgfuncpernode; + hqrndstate rs; + ae_vector blocks0; + ae_vector blocks1; + ae_vector blocks2; + ae_vector blocks3; + ae_int_t blockscnt0; + ae_int_t blockscnt1; + ae_int_t blockscnt2; + ae_int_t blockscnt3; + double blockwidth0; + double blockwidth1; + double blockwidth2; + double blockwidth3; + ae_int_t maxblocksize; + + ae_frame_make(_state, &_frame_block); + memset(&tx, 0, sizeof(tx)); + memset(&ty, 0, sizeof(ty)); + memset(&z, 0, sizeof(z)); + memset(&bufseedv2, 0, sizeof(bufseedv2)); + memset(&bufpool, 0, sizeof(bufpool)); + memset(&rs, 0, sizeof(rs)); + memset(&blocks0, 0, sizeof(blocks0)); + memset(&blocks1, 0, sizeof(blocks1)); + memset(&blocks2, 0, sizeof(blocks2)); + memset(&blocks3, 0, sizeof(blocks3)); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ty, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + _rbfv2gridcalcbuffer_init(&bufseedv2, _state, ae_true); + ae_shared_pool_init(&bufpool, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true); + ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true); + ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true); + ae_vector_init(&blocks3, 0, DT_INT, _state, ae_true); + + nx = s->nx; + ny = s->ny; + hqrndseed(532, 54734, &rs, _state); + + /* + * Perform integrity checks + */ + ae_assert(s->nx==2||s->nx==3, "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=4||((x3->cnt>=1&&ae_fp_eq(x3->ptr.p_double[0],(double)(0)))&&n3==1), "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=3||((x2->cnt>=1&&ae_fp_eq(x2->ptr.p_double[0],(double)(0)))&&n2==1), "RBFGridCalcVX: integrity check failed", _state); + ae_assert(s->nx>=2||((x1->cnt>=1&&ae_fp_eq(x1->ptr.p_double[0],(double)(0)))&&n1==1), "RBFGridCalcVX: integrity check failed", _state); + + /* + * Allocate arrays + */ + ae_assert(s->nx<=4, "RBFGridCalcVX: integrity check failed", _state); + ae_vector_set_length(&z, ny, _state); + ae_vector_set_length(&tx, 4, _state); + ae_vector_set_length(&ty, ny, _state); + + /* + * Calculate linear term + */ + rowcnt = n1*n2*n3; + for(rowidx=0; rowidx<=rowcnt-1; rowidx++) + { + + /* + * Calculate TX - current position + */ + k = rowidx; + tx.ptr.p_double[0] = (double)(0); + tx.ptr.p_double[1] = x1->ptr.p_double[k%n1]; + k = k/n1; + tx.ptr.p_double[2] = x2->ptr.p_double[k%n2]; + k = k/n2; + tx.ptr.p_double[3] = x3->ptr.p_double[k%n3]; + k = k/n3; + ae_assert(k==0, "RBFGridCalcVX: integrity check failed", _state); + for(j=0; j<=ny-1; j++) + { + v = s->v.ptr.pp_double[j][nx]; + for(k=1; k<=nx-1; k++) + { + v = v+tx.ptr.p_double[k]*s->v.ptr.pp_double[j][k]; + } + z.ptr.p_double[j] = v; + } + for(i=0; i<=n0-1; i++) + { + dstoffs = ny*(rowidx*n0+i); + if( sparsey&&!flagy->ptr.p_bool[rowidx*n0+i] ) + { + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j+dstoffs] = (double)(0); + } + continue; + } + v = x0->ptr.p_double[i]; + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j+dstoffs] = z.ptr.p_double[j]+v*s->v.ptr.pp_double[j][0]; + } + } + } + if( s->nh==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Process RBF terms, layer by layer + */ + for(levelidx=0; levelidx<=s->nh-1; levelidx++) + { + rcur = s->ri.ptr.p_double[levelidx]; + blockwidth0 = (double)(1); + blockwidth1 = (double)(1); + blockwidth2 = (double)(1); + blockwidth3 = (double)(1); + if( nx>=1 ) + { + blockwidth0 = rcur*s->s.ptr.p_double[0]; + } + if( nx>=2 ) + { + blockwidth1 = rcur*s->s.ptr.p_double[1]; + } + if( nx>=3 ) + { + blockwidth2 = rcur*s->s.ptr.p_double[2]; + } + if( nx>=4 ) + { + blockwidth3 = rcur*s->s.ptr.p_double[3]; + } + maxblocksize = 8; + + /* + * Group grid nodes into blocks according to current radius + */ + ae_vector_set_length(&blocks0, n0+1, _state); + blockscnt0 = 0; + blocks0.ptr.p_int[0] = 0; + for(i=1; i<=n0-1; i++) + { + if( ae_fp_greater(x0->ptr.p_double[i]-x0->ptr.p_double[blocks0.ptr.p_int[blockscnt0]],blockwidth0)||i-blocks0.ptr.p_int[blockscnt0]>=maxblocksize ) + { + inc(&blockscnt0, _state); + blocks0.ptr.p_int[blockscnt0] = i; + } + } + inc(&blockscnt0, _state); + blocks0.ptr.p_int[blockscnt0] = n0; + ae_vector_set_length(&blocks1, n1+1, _state); + blockscnt1 = 0; + blocks1.ptr.p_int[0] = 0; + for(i=1; i<=n1-1; i++) + { + if( ae_fp_greater(x1->ptr.p_double[i]-x1->ptr.p_double[blocks1.ptr.p_int[blockscnt1]],blockwidth1)||i-blocks1.ptr.p_int[blockscnt1]>=maxblocksize ) + { + inc(&blockscnt1, _state); + blocks1.ptr.p_int[blockscnt1] = i; + } + } + inc(&blockscnt1, _state); + blocks1.ptr.p_int[blockscnt1] = n1; + ae_vector_set_length(&blocks2, n2+1, _state); + blockscnt2 = 0; + blocks2.ptr.p_int[0] = 0; + for(i=1; i<=n2-1; i++) + { + if( ae_fp_greater(x2->ptr.p_double[i]-x2->ptr.p_double[blocks2.ptr.p_int[blockscnt2]],blockwidth2)||i-blocks2.ptr.p_int[blockscnt2]>=maxblocksize ) + { + inc(&blockscnt2, _state); + blocks2.ptr.p_int[blockscnt2] = i; + } + } + inc(&blockscnt2, _state); + blocks2.ptr.p_int[blockscnt2] = n2; + ae_vector_set_length(&blocks3, n3+1, _state); + blockscnt3 = 0; + blocks3.ptr.p_int[0] = 0; + for(i=1; i<=n3-1; i++) + { + if( ae_fp_greater(x3->ptr.p_double[i]-x3->ptr.p_double[blocks3.ptr.p_int[blockscnt3]],blockwidth3)||i-blocks3.ptr.p_int[blockscnt3]>=maxblocksize ) + { + inc(&blockscnt3, _state); + blocks3.ptr.p_int[blockscnt3] = i; + } + } + inc(&blockscnt3, _state); + blocks3.ptr.p_int[blockscnt3] = n3; + + /* + * Prepare seed for shared pool + */ + rbfv2_allocatecalcbuffer(s, &bufseedv2.calcbuf, _state); + ae_shared_pool_set_seed(&bufpool, &bufseedv2, (ae_int_t)sizeof(bufseedv2), (ae_copy_constructor)_rbfv2gridcalcbuffer_init_copy, (ae_destructor)_rbfv2gridcalcbuffer_destroy, _state); + + /* + * Determine average number of neighbor per node + */ + searchradius2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + ntrials = 100; + avgfuncpernode = 0.0; + for(i=0; i<=ntrials-1; i++) + { + tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)]; + tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)]; + tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)]; + tx.ptr.p_double[3] = x3->ptr.p_double[hqrnduniformi(&rs, n3, _state)]; + rbfv2_preparepartialquery(&tx, &s->kdboxmin, &s->kdboxmax, nx, &bufseedv2.calcbuf, &dummy, _state); + avgfuncpernode = avgfuncpernode+(double)rbfv2_partialcountrec(&s->kdnodes, &s->kdsplits, &s->cw, nx, ny, &bufseedv2.calcbuf, s->kdroots.ptr.p_int[levelidx], searchradius2, &tx, _state)/(double)ntrials; + } + + /* + * Perform calculation in multithreaded mode + */ + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, &blocks0, 0, blockscnt0, &blocks1, 0, blockscnt1, &blocks2, 0, blockscnt2, &blocks3, 0, blockscnt3, flagy, sparsey, levelidx, avgfuncpernode, &bufpool, y, _state); + } + ae_frame_leave(_state); +} + + +void rbfv2partialgridcalcrec(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Integer */ const ae_vector* blocks3, + ae_int_t block3a, + ae_int_t block3b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_int_t levelidx, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t k; + ae_int_t l; + ae_int_t blkidx; + ae_int_t blkcnt; + ae_int_t nodeidx; + ae_int_t nodescnt; + ae_int_t rowidx; + ae_int_t rowscnt; + ae_int_t i0; + ae_int_t i1; + ae_int_t i2; + ae_int_t i3; + ae_int_t j0; + ae_int_t j1; + ae_int_t j2; + ae_int_t j3; + double rcur; + double invrc2; + double rquery2; + double rfar2; + ae_int_t dstoffs; + ae_int_t srcoffs; + ae_int_t dummy; + double rowwidth; + double maxrowwidth; + double problemcost; + ae_int_t maxbs; + ae_int_t midpoint; + ae_bool emptyrow; + rbfv2gridcalcbuffer *buf; + ae_smart_ptr _buf; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + nx = s->nx; + ny = s->ny; + + /* + * Integrity checks + */ + ae_assert(s->nx==2||s->nx==3, "RBFV2PartialGridCalcRec: integrity check failed", _state); + + /* + * Try to split large problem + */ + problemcost = (double)(s->ny*2)*(avgfuncpernode+(double)1); + problemcost = problemcost*(double)(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]); + problemcost = problemcost*(double)(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]); + problemcost = problemcost*(double)(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]); + problemcost = problemcost*(double)(blocks3->ptr.p_int[block3b]-blocks3->ptr.p_int[block3a]); + maxbs = 0; + maxbs = ae_maxint(maxbs, block0b-block0a, _state); + maxbs = ae_maxint(maxbs, block1b-block1a, _state); + maxbs = ae_maxint(maxbs, block2b-block2a, _state); + maxbs = ae_maxint(maxbs, block3b-block3a, _state); + if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,smpactivationlevel(_state)) ) + { + if( _trypexec_rbfv2partialgridcalcrec(s,x0,n0,x1,n1,x2,n2,x3,n3,blocks0,block0a,block0b,blocks1,block1a,block1b,blocks2,block2a,block2b,blocks3,block3a,block3b,flagy,sparsey,levelidx,avgfuncpernode,bufpool,y, _state) ) + { + ae_frame_leave(_state); + return; + } + } + if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,spawnlevel(_state))&&maxbs>=2 ) + { + if( block0b-block0a==maxbs ) + { + midpoint = block0a+maxbs/2; + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, midpoint, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, midpoint, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + if( block1b-block1a==maxbs ) + { + midpoint = block1a+maxbs/2; + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, midpoint, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, midpoint, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + if( block2b-block2a==maxbs ) + { + midpoint = block2a+maxbs/2; + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, midpoint, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, midpoint, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + if( block3b-block3a==maxbs ) + { + midpoint = block3a+maxbs/2; + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, midpoint, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, midpoint, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state); + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "RBFV2PartialGridCalcRec: integrity check failed", _state); + } + + /* + * Retrieve buffer object from pool (it will be returned later) + */ + ae_shared_pool_retrieve(bufpool, &_buf, _state); + + /* + * Calculate RBF model + */ + ae_assert(nx<=4, "RBFV2PartialGridCalcRec: integrity check failed", _state); + ae_vector_set_length(&buf->tx, 4, _state); + ae_vector_set_length(&buf->cx, 4, _state); + ae_vector_set_length(&buf->ty, ny, _state); + rcur = s->ri.ptr.p_double[levelidx]; + invrc2 = (double)1/(rcur*rcur); + blkcnt = (block3b-block3a)*(block2b-block2a)*(block1b-block1a)*(block0b-block0a); + for(blkidx=0; blkidx<=blkcnt-1; blkidx++) + { + + /* + * Select block (I0,I1,I2,I3). + * + * NOTE: for problems with NX<4 corresponding I_? are zero. + */ + k = blkidx; + i0 = block0a+k%(block0b-block0a); + k = k/(block0b-block0a); + i1 = block1a+k%(block1b-block1a); + k = k/(block1b-block1a); + i2 = block2a+k%(block2b-block2a); + k = k/(block2b-block2a); + i3 = block3a+k%(block3b-block3a); + k = k/(block3b-block3a); + ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state); + + /* + * We partitioned grid into blocks and selected block with + * index (I0,I1,I2,I3). This block is a 4D cube (some dimensions + * may be zero) of nodes with indexes (J0,J1,J2,J3), which is + * further partitioned into a set of rows, each row corresponding + * to indexes J1...J3 being fixed. + * + * We process block row by row, and each row may be handled + * by either "generic" (nodes are processed separately) or + * batch algorithm (that's the reason to use rows, after all). + * + * + * Process nodes of the block + */ + rowscnt = (blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3])*(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2])*(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]); + for(rowidx=0; rowidx<=rowscnt-1; rowidx++) + { + + /* + * Find out node indexes (*,J1,J2,J3). + * + * NOTE: for problems with NX<4 corresponding J_? are zero. + */ + k = rowidx; + j1 = blocks1->ptr.p_int[i1]+k%(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]); + k = k/(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]); + j2 = blocks2->ptr.p_int[i2]+k%(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]); + k = k/(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]); + j3 = blocks3->ptr.p_int[i3]+k%(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]); + k = k/(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]); + ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state); + + /* + * Analyze row, skip completely empty rows + */ + nodescnt = blocks0->ptr.p_int[i0+1]-blocks0->ptr.p_int[i0]; + srcoffs = blocks0->ptr.p_int[i0]+(j1+(j2+j3*n2)*n1)*n0; + emptyrow = ae_true; + for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++) + { + emptyrow = emptyrow&&(sparsey&&!flagy->ptr.p_bool[srcoffs+nodeidx]); + } + if( emptyrow ) + { + continue; + } + + /* + * Process row - use either "batch" (rowsize>1) or "generic" + * (row size is 1) algorithm. + * + * NOTE: "generic" version may also be used as fallback code for + * situations when we do not want to use batch code. + */ + maxrowwidth = 0.5*rbfv2nearradius(s->bf, _state)*rcur*s->s.ptr.p_double[0]; + rowwidth = x0->ptr.p_double[blocks0->ptr.p_int[i0+1]-1]-x0->ptr.p_double[blocks0->ptr.p_int[i0]]; + if( nodescnt>1&&ae_fp_less_eq(rowwidth,maxrowwidth) ) + { + + /* + * "Batch" code which processes entire row at once, saving + * some time in kd-tree search code. + */ + rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state)+0.5*rowwidth/s->s.ptr.p_double[0], _state); + rfar2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + j0 = blocks0->ptr.p_int[i0]; + if( nx>0 ) + { + buf->cx.ptr.p_double[0] = (x0->ptr.p_double[j0]+0.5*rowwidth)/s->s.ptr.p_double[0]; + } + if( nx>1 ) + { + buf->cx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1]; + } + if( nx>2 ) + { + buf->cx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2]; + } + if( nx>3 ) + { + buf->cx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3]; + } + srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0; + dstoffs = ny*srcoffs; + rvectorsetlengthatleast(&buf->rx, nodescnt, _state); + bvectorsetlengthatleast(&buf->rf, nodescnt, _state); + rvectorsetlengthatleast(&buf->ry, nodescnt*ny, _state); + for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++) + { + buf->rx.ptr.p_double[nodeidx] = x0->ptr.p_double[j0+nodeidx]/s->s.ptr.p_double[0]; + buf->rf.ptr.p_bool[nodeidx] = !sparsey||flagy->ptr.p_bool[srcoffs+nodeidx]; + } + for(k=0; k<=nodescnt*ny-1; k++) + { + buf->ry.ptr.p_double[k] = (double)(0); + } + rbfv2_preparepartialquery(&buf->cx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state); + rbfv2_partialrowcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, rfar2, &buf->cx, &buf->rx, &buf->rf, nodescnt, &buf->ry, _state); + for(k=0; k<=nodescnt*ny-1; k++) + { + y->ptr.p_double[dstoffs+k] = y->ptr.p_double[dstoffs+k]+buf->ry.ptr.p_double[k]; + } + } + else + { + + /* + * "Generic" code. Although we usually move here + * only when NodesCnt=1, we still use a loop on + * NodeIdx just to be able to use this branch as + * fallback code without any modifications. + */ + rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state); + for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++) + { + + /* + * Prepare TX - current point + */ + j0 = blocks0->ptr.p_int[i0]+nodeidx; + if( nx>0 ) + { + buf->tx.ptr.p_double[0] = x0->ptr.p_double[j0]/s->s.ptr.p_double[0]; + } + if( nx>1 ) + { + buf->tx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1]; + } + if( nx>2 ) + { + buf->tx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2]; + } + if( nx>3 ) + { + buf->tx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3]; + } + + /* + * Evaluate and add to Y + */ + srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0; + dstoffs = ny*srcoffs; + for(l=0; l<=ny-1; l++) + { + buf->ty.ptr.p_double[l] = (double)(0); + } + if( !sparsey||flagy->ptr.p_bool[srcoffs] ) + { + rbfv2_preparepartialquery(&buf->tx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state); + rbfv2_partialcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->tx, &buf->ty, &buf->ty, &buf->ty, 0, _state); + } + for(l=0; l<=ny-1; l++) + { + y->ptr.p_double[dstoffs+l] = y->ptr.p_double[dstoffs+l]+buf->ty.ptr.p_double[l]; + } + } + } + } + } + + /* + * Recycle buffer object back to pool + */ + ae_shared_pool_recycle(bufpool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rbfv2partialgridcalcrec(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Integer */ const ae_vector* blocks3, + ae_int_t block3a, + ae_int_t block3b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_int_t levelidx, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information, array[NC,NX+NY+1]. + One row of the array corresponds to one basis function: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modelled + * last NX columns - radii, per dimension + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfv2unpack(rbfv2model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ncactual; + + *nx = 0; + *ny = 0; + ae_matrix_clear(xwr); + *nc = 0; + ae_matrix_clear(v); + + *nx = s->nx; + *ny = s->ny; + *nc = 0; + + /* + * Fill V + */ + ae_matrix_set_length(v, s->ny, s->nx+1, _state); + for(i=0; i<=s->ny-1; i++) + { + ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx)); + } + + /* + * Fill XWR + */ + ae_assert(s->cw.cnt%(s->nx+s->ny)==0, "RBFV2Unpack: integrity error", _state); + *nc = s->cw.cnt/(s->nx+s->ny); + ncactual = 0; + if( *nc>0 ) + { + ae_matrix_set_length(xwr, *nc, s->nx+s->ny+s->nx, _state); + for(i=0; i<=s->nh-1; i++) + { + rbfv2_partialunpackrec(&s->kdnodes, &s->kdsplits, &s->cw, &s->s, s->nx, s->ny, s->kdroots.ptr.p_int[i], s->ri.ptr.p_double[i], xwr, &ncactual, _state); + } + } + ae_assert(*nc==ncactual, "RBFV2Unpack: integrity error", _state); +} + + +static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real */ const ae_matrix* x, + /* Real */ ae_matrix* y, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + /* Real */ ae_matrix* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmpy; + ae_matrix a; + double scaling; + ae_vector shifting; + double mn; + double mx; + ae_vector c; + lsfitreport rep; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&tmpy, 0, sizeof(tmpy)); + memset(&a, 0, sizeof(a)); + memset(&shifting, 0, sizeof(shifting)); + memset(&c, 0, sizeof(c)); + memset(&rep, 0, sizeof(rep)); + ae_matrix_clear(v); + ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + _lsfitreport_init(&rep, _state, ae_true); + + ae_assert(n>=0, "BuildLinearModel: N<0", _state); + ae_assert(nx>0, "BuildLinearModel: NX<=0", _state); + ae_assert(ny>0, "BuildLinearModel: NY<=0", _state); + + /* + * Handle degenerate case (N=0) + */ + result = ae_true; + ae_matrix_set_length(v, ny, nx+1, _state); + if( n==0 ) + { + for(j=0; j<=nx; j++) + { + for(i=0; i<=ny-1; i++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Allocate temporaries + */ + ae_vector_set_length(&tmpy, n, _state); + + /* + * General linear model. + */ + if( modeltype==1 ) + { + + /* + * Calculate scaling/shifting, transform variables, prepare LLS problem + */ + ae_matrix_set_length(&a, n, nx+1, _state); + ae_vector_set_length(&shifting, nx, _state); + scaling = (double)(0); + for(i=0; i<=nx-1; i++) + { + mn = x->ptr.pp_double[0][i]; + mx = mn; + for(j=1; j<=n-1; j++) + { + if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) ) + { + mn = x->ptr.pp_double[j][i]; + } + if( ae_fp_less(mx,x->ptr.pp_double[j][i]) ) + { + mx = x->ptr.pp_double[j][i]; + } + } + scaling = ae_maxreal(scaling, mx-mn, _state); + shifting.ptr.p_double[i] = 0.5*(mx+mn); + } + if( ae_fp_eq(scaling,(double)(0)) ) + { + scaling = (double)(1); + } + else + { + scaling = 0.5*scaling; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nx-1; j++) + { + a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling; + } + } + for(i=0; i<=n-1; i++) + { + a.ptr.pp_double[i][nx] = (double)(1); + } + + /* + * Solve linear system in transformed variables, make backward + */ + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=n-1; j++) + { + tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i]; + } + lsfitlinear(&tmpy, &a, n, nx+1, &c, &rep, _state); + if( rep.terminationtype<=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + for(j=0; j<=nx-1; j++) + { + v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling; + } + v->ptr.pp_double[i][nx] = c.ptr.p_double[nx]; + for(j=0; j<=nx-1; j++) + { + v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j]; + } + for(j=0; j<=n-1; j++) + { + for(k=0; k<=nx-1; k++) + { + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k]; + } + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx]; + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Constant model, very simple + */ + if( modeltype==2 ) + { + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + for(j=0; j<=n-1; j++) + { + v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]+y->ptr.pp_double[j][i]; + } + if( n>0 ) + { + v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]/(double)n; + } + for(j=0; j<=n-1; j++) + { + y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx]; + } + } + ae_frame_leave(_state); + return result; + } + + /* + * Zero model + */ + ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx; j++) + { + v->ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Reallocates calcBuf if necessary, reuses previously allocated space if +possible. + + -- ALGLIB -- + Copyright 20.06.2016 by Sergey Bochkanov +*************************************************************************/ +static void rbfv2_allocatecalcbuffer(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_state *_state) +{ + + + if( buf->x.cntnx ) + { + ae_vector_set_length(&buf->x, s->nx, _state); + } + if( buf->curboxmin.cntnx ) + { + ae_vector_set_length(&buf->curboxmin, s->nx, _state); + } + if( buf->curboxmax.cntnx ) + { + ae_vector_set_length(&buf->curboxmax, s->nx, _state); + } + if( buf->x123.cntnx ) + { + ae_vector_set_length(&buf->x123, s->nx, _state); + } + if( buf->y123.cntny ) + { + ae_vector_set_length(&buf->y123, s->ny, _state); + } +} + + +/************************************************************************* +Extracts structure (and XY-values too) from kd-tree built for a small +subset of points and appends it to multi-tree. + + + -- ALGLIB -- + Copyright 20.06.2016 by Sergey Bochkanov +*************************************************************************/ +static void rbfv2_convertandappendtree(const kdtree* curtree, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + /* Integer */ ae_vector* kdnodes, + /* Real */ ae_vector* kdsplits, + /* Real */ ae_vector* cw, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nodesbase; + ae_int_t splitsbase; + ae_int_t cwbase; + ae_vector localnodes; + ae_vector localsplits; + ae_vector localcw; + ae_matrix xybuf; + ae_int_t localnodessize; + ae_int_t localsplitssize; + ae_int_t localcwsize; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&localnodes, 0, sizeof(localnodes)); + memset(&localsplits, 0, sizeof(localsplits)); + memset(&localcw, 0, sizeof(localcw)); + memset(&xybuf, 0, sizeof(xybuf)); + ae_vector_init(&localnodes, 0, DT_INT, _state, ae_true); + ae_vector_init(&localsplits, 0, DT_REAL, _state, ae_true); + ae_vector_init(&localcw, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xybuf, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Calculate base offsets + */ + nodesbase = kdnodes->cnt; + splitsbase = kdsplits->cnt; + cwbase = cw->cnt; + + /* + * Prepare local copy of tree + */ + ae_vector_set_length(&localnodes, n*rbfv2_maxnodesize, _state); + ae_vector_set_length(&localsplits, n, _state); + ae_vector_set_length(&localcw, (nx+ny)*n, _state); + localnodessize = 0; + localsplitssize = 0; + localcwsize = 0; + rbfv2_converttreerec(curtree, n, nx, ny, 0, nodesbase, splitsbase, cwbase, &localnodes, &localnodessize, &localsplits, &localsplitssize, &localcw, &localcwsize, &xybuf, _state); + + /* + * Append to multi-tree + */ + ivectorresize(kdnodes, kdnodes->cnt+localnodessize, _state); + rvectorresize(kdsplits, kdsplits->cnt+localsplitssize, _state); + rvectorresize(cw, cw->cnt+localcwsize, _state); + for(i=0; i<=localnodessize-1; i++) + { + kdnodes->ptr.p_int[nodesbase+i] = localnodes.ptr.p_int[i]; + } + for(i=0; i<=localsplitssize-1; i++) + { + kdsplits->ptr.p_double[splitsbase+i] = localsplits.ptr.p_double[i]; + } + for(i=0; i<=localcwsize-1; i++) + { + cw->ptr.p_double[cwbase+i] = localcw.ptr.p_double[i]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Recurrent tree conversion + + CurTree - tree to convert + N, NX, NY - dataset metrics + NodeOffset - offset of current tree node, 0 for root + NodesBase - a value which is added to intra-tree node indexes; + although this tree is stored in separate array, it + is intended to be stored in the larger tree, with + localNodes being moved to offset NodesBase. + SplitsBase - similarly, offset of localSplits in the final tree + CWBase - similarly, offset of localCW in the final tree +*************************************************************************/ +static void rbfv2_converttreerec(const kdtree* curtree, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t nodeoffset, + ae_int_t nodesbase, + ae_int_t splitsbase, + ae_int_t cwbase, + /* Integer */ ae_vector* localnodes, + ae_int_t* localnodessize, + /* Real */ ae_vector* localsplits, + ae_int_t* localsplitssize, + /* Real */ ae_vector* localcw, + ae_int_t* localcwsize, + /* Real */ ae_matrix* xybuf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nodetype; + ae_int_t cnt; + ae_int_t d; + double s; + ae_int_t nodele; + ae_int_t nodege; + ae_int_t oldnodessize; + + + kdtreeexplorenodetype(curtree, nodeoffset, &nodetype, _state); + + /* + * Leaf node + */ + if( nodetype==0 ) + { + kdtreeexploreleaf(curtree, nodeoffset, xybuf, &cnt, _state); + ae_assert(localnodes->cnt>=*localnodessize+2, "ConvertTreeRec: integrity check failed", _state); + ae_assert(localcw->cnt>=*localcwsize+cnt*(nx+ny), "ConvertTreeRec: integrity check failed", _state); + localnodes->ptr.p_int[*localnodessize+0] = cnt; + localnodes->ptr.p_int[*localnodessize+1] = cwbase+(*localcwsize); + *localnodessize = *localnodessize+2; + for(i=0; i<=cnt-1; i++) + { + for(j=0; j<=nx+ny-1; j++) + { + localcw->ptr.p_double[*localcwsize+i*(nx+ny)+j] = xybuf->ptr.pp_double[i][j]; + } + } + *localcwsize = *localcwsize+cnt*(nx+ny); + return; + } + + /* + * Split node + */ + if( nodetype==1 ) + { + kdtreeexploresplit(curtree, nodeoffset, &d, &s, &nodele, &nodege, _state); + ae_assert(localnodes->cnt>=*localnodessize+rbfv2_maxnodesize, "ConvertTreeRec: integrity check failed", _state); + ae_assert(localsplits->cnt>=*localsplitssize+1, "ConvertTreeRec: integrity check failed", _state); + oldnodessize = *localnodessize; + localnodes->ptr.p_int[*localnodessize+0] = 0; + localnodes->ptr.p_int[*localnodessize+1] = d; + localnodes->ptr.p_int[*localnodessize+2] = splitsbase+(*localsplitssize); + localnodes->ptr.p_int[*localnodessize+3] = -1; + localnodes->ptr.p_int[*localnodessize+4] = -1; + *localnodessize = *localnodessize+5; + localsplits->ptr.p_double[*localsplitssize+0] = s; + *localsplitssize = *localsplitssize+1; + localnodes->ptr.p_int[oldnodessize+3] = nodesbase+(*localnodessize); + rbfv2_converttreerec(curtree, n, nx, ny, nodele, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state); + localnodes->ptr.p_int[oldnodessize+4] = nodesbase+(*localnodessize); + rbfv2_converttreerec(curtree, n, nx, ny, nodege, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state); + return; + } + + /* + * Integrity error + */ + ae_assert(ae_false, "ConvertTreeRec: integrity check failed", _state); +} + + +/************************************************************************* +This function performs partial calculation of hierarchical model: given +evaluation point X and partially computed value Y, it updates Y by values +computed using part of multi-tree given by RootIdx. + +INPUT PARAMETERS: + S - V2 model + Buf - calc-buffer, this function uses following fields: + * Buf.CurBoxMin - should be set by caller + * Buf.CurBoxMax - should be set by caller + * Buf.CurDist2 - squared distance from X to current bounding box, + should be set by caller + RootIdx - offset of partial kd-tree + InvR2 - 1/R^2, where R is basis function radius + QueryR2 - squared query radius, usually it is (R*FarRadius(BasisFunction))^2 + X - evaluation point, array[NX] + Y - current value for target, array[NY] + DY - current value for derivative, array[NY*NX], if NeedDY>=1 + D2Y - current value for derivative, array[NY*NX*NX], if NeedDY>=2 + NeedDY - whether derivatives are required or not: + * 0 if only Y is needed + * 1 if Y and DY are needed + * 2 if Y, DY, D2Y are needed + +OUTPUT PARAMETERS + Y - updated partial value + DY - updated derivatives, if NeedDY>=1 + D2Y - updated Hessian, if NeedDY>=2 + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_partialcalcrec(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double invr2, + double queryr2, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_int_t needdy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double ptdist2; + double w; + double v; + double v0; + double v1; + ae_int_t cwoffs; + ae_int_t cwcnt; + ae_int_t itemoffs; + double arg; + double val; + double df; + double d2f; + ae_int_t d; + double split; + ae_int_t childle; + ae_int_t childge; + ae_int_t childoffs; + ae_bool updatemin; + double prevdist2; + double t1; + ae_int_t nx; + ae_int_t ny; + + + nx = s->nx; + ny = s->ny; + + /* + * Helps to avoid spurious warnings + */ + val = (double)(0); + + /* + * Leaf node. + */ + if( s->kdnodes.ptr.p_int[rootidx]>0 ) + { + cwcnt = s->kdnodes.ptr.p_int[rootidx+0]; + cwoffs = s->kdnodes.ptr.p_int[rootidx+1]; + for(i=0; i<=cwcnt-1; i++) + { + + /* + * Calculate distance + */ + itemoffs = cwoffs+i*(nx+ny); + ptdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = s->cw.ptr.p_double[itemoffs+j]-x->ptr.p_double[j]; + ptdist2 = ptdist2+v*v; + } + + /* + * Skip points if distance too large + */ + if( ptdist2>=queryr2 ) + { + continue; + } + + /* + * Update Y + */ + arg = ptdist2*invr2; + val = (double)(0); + df = (double)(0); + d2f = (double)(0); + if( needdy==2 ) + { + if( s->bf==0 ) + { + val = ae_exp(-arg, _state); + df = -val; + d2f = val; + } + else + { + if( s->bf==1 ) + { + rbfv2basisfuncdiff2(s->bf, arg, &val, &df, &d2f, _state); + } + else + { + ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state); + } + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+val*s->cw.ptr.p_double[itemoffs+nx+j]; + w = s->cw.ptr.p_double[itemoffs+nx+j]; + v = w*df*invr2*(double)2; + for(k0=0; k0<=nx-1; k0++) + { + for(k1=0; k1<=nx-1; k1++) + { + if( k0==k1 ) + { + + /* + * Compute derivative and diagonal element of the Hessian + */ + dy->ptr.p_double[j*nx+k0] = dy->ptr.p_double[j*nx+k0]+v*(x->ptr.p_double[k0]-s->cw.ptr.p_double[itemoffs+k0]); + d2y->ptr.p_double[j*nx*nx+k0*nx+k1] = d2y->ptr.p_double[j*nx*nx+k0*nx+k1]+w*(d2f*invr2*invr2*(double)4*ae_sqr(x->ptr.p_double[k0]-s->cw.ptr.p_double[itemoffs+k0], _state)+df*invr2*(double)2); + } + else + { + + /* + * Compute offdiagonal element of the Hessian + */ + d2y->ptr.p_double[j*nx*nx+k0*nx+k1] = d2y->ptr.p_double[j*nx*nx+k0*nx+k1]+w*d2f*invr2*invr2*(double)4*(x->ptr.p_double[k0]-s->cw.ptr.p_double[itemoffs+k0])*(x->ptr.p_double[k1]-s->cw.ptr.p_double[itemoffs+k1]); + } + } + } + } + } + if( needdy==1 ) + { + if( s->bf==0 ) + { + val = ae_exp(-arg, _state); + df = -val; + } + else + { + if( s->bf==1 ) + { + rbfv2basisfuncdiff2(s->bf, arg, &val, &df, &d2f, _state); + } + else + { + ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state); + } + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+val*s->cw.ptr.p_double[itemoffs+nx+j]; + v = s->cw.ptr.p_double[itemoffs+nx+j]*df*invr2*(double)2; + for(k=0; k<=nx-1; k++) + { + dy->ptr.p_double[j*nx+k] = dy->ptr.p_double[j*nx+k]+v*(x->ptr.p_double[k]-s->cw.ptr.p_double[itemoffs+k]); + } + } + } + if( needdy==0 ) + { + if( s->bf==0 ) + { + val = ae_exp(-arg, _state); + } + else + { + if( s->bf==1 ) + { + val = rbfv2basisfunc(s->bf, arg, _state); + } + else + { + ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state); + } + } + for(j=0; j<=ny-1; j++) + { + y->ptr.p_double[j] = y->ptr.p_double[j]+val*s->cw.ptr.p_double[itemoffs+nx+j]; + } + } + } + return; + } + + /* + * Simple split + */ + if( s->kdnodes.ptr.p_int[rootidx]==0 ) + { + + /* + * Load: + * * D dimension to split + * * Split split position + * * ChildLE, ChildGE - indexes of childs + */ + d = s->kdnodes.ptr.p_int[rootidx+1]; + split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]]; + childle = s->kdnodes.ptr.p_int[rootidx+3]; + childge = s->kdnodes.ptr.p_int[rootidx+4]; + + /* + * Navigate through childs + */ + for(i=0; i<=1; i++) + { + + /* + * Select child to process: + * * ChildOffs current child offset in Nodes[] + * * UpdateMin whether minimum or maximum value + * of bounding box is changed on update + */ + updatemin = i!=0; + if( i==0 ) + { + childoffs = childle; + } + else + { + childoffs = childge; + } + + /* + * Update bounding box and current distance + */ + prevdist2 = buf->curdist2; + t1 = x->ptr.p_double[d]; + if( updatemin ) + { + v = buf->curboxmin.ptr.p_double[d]; + if( t1<=split ) + { + v0 = v-t1; + if( v0<(double)0 ) + { + v0 = (double)(0); + } + v1 = split-t1; + buf->curdist2 = buf->curdist2-v0*v0+v1*v1; + } + buf->curboxmin.ptr.p_double[d] = split; + } + else + { + v = buf->curboxmax.ptr.p_double[d]; + if( t1>=split ) + { + v0 = t1-v; + if( v0<(double)0 ) + { + v0 = (double)(0); + } + v1 = t1-split; + buf->curdist2 = buf->curdist2-v0*v0+v1*v1; + } + buf->curboxmax.ptr.p_double[d] = split; + } + + /* + * Decide: to dive into cell or not to dive + */ + if( buf->curdist2curboxmin.ptr.p_double[d] = v; + } + else + { + buf->curboxmax.ptr.p_double[d] = v; + } + buf->curdist2 = prevdist2; + } + return; + } + + /* + * Integrity failure + */ + ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state); +} + + +/************************************************************************* +This function performs same operation as partialcalcrec(), but for entire +row of the grid. "Row" is a set of nodes (x0,x1,x2,x3) which share x1..x3, +but have different x0's. (note: for 2D/3D problems x2..x3 are zero). + +Row is given by: +* central point XC, which is located at the center of the row, and used to + perform kd-tree requests +* set of x0 coordinates stored in RX array (array may be unordered, but it + is expected that spread of x0 is no more than R; function may be + inefficient for larger spreads). +* set of YFlag values stored in RF + +INPUT PARAMETERS: + S - V2 model + Buf - calc-buffer, this function uses following fields: + * Buf.CurBoxMin - should be set by caller + * Buf.CurBoxMax - should be set by caller + * Buf.CurDist2 - squared distance from X to current bounding box, + should be set by caller + RootIdx - offset of partial kd-tree + InvR2 - 1/R^2, where R is basis function radius + RQuery2 - squared query radius, usually it is (R*FarRadius(BasisFunction)+0.5*RowWidth)^2, + where RowWidth is its spatial extent (after scaling of + variables). This radius is used to perform initial query + for neighbors of CX. + RFar2 - squared far radius; far radius is used to perform actual + filtering of results of query made with RQuery2. + CX - central point, array[NX], used for queries + RX - x0 coordinates, array[RowSize] + RF - sparsity flags, array[RowSize] + RowSize - row size in elements + RY - input partial value, array[NY] + +OUTPUT PARAMETERS + RY - updated partial value (function adds its results to RY) + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_partialrowcalcrec(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double invr2, + double rquery2, + double rfar2, + /* Real */ const ae_vector* cx, + /* Real */ const ae_vector* rx, + /* Boolean */ const ae_vector* rf, + ae_int_t rowsize, + /* Real */ ae_vector* ry, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t i0; + ae_int_t i1; + double partialptdist2; + double ptdist2; + double v; + double v0; + double v1; + ae_int_t cwoffs; + ae_int_t cwcnt; + ae_int_t itemoffs; + ae_int_t woffs; + double val; + ae_int_t d; + double split; + ae_int_t childle; + ae_int_t childge; + ae_int_t childoffs; + ae_bool updatemin; + double prevdist2; + double t1; + ae_int_t nx; + ae_int_t ny; + + + nx = s->nx; + ny = s->ny; + + /* + * Leaf node. + */ + if( s->kdnodes.ptr.p_int[rootidx]>0 ) + { + cwcnt = s->kdnodes.ptr.p_int[rootidx+0]; + cwoffs = s->kdnodes.ptr.p_int[rootidx+1]; + for(i0=0; i0<=cwcnt-1; i0++) + { + + /* + * Calculate partial distance (components from 1 to NX-1) + */ + itemoffs = cwoffs+i0*(nx+ny); + partialptdist2 = (double)(0); + for(j=1; j<=nx-1; j++) + { + v = s->cw.ptr.p_double[itemoffs+j]-cx->ptr.p_double[j]; + partialptdist2 = partialptdist2+v*v; + } + + /* + * Process each element of the row + */ + for(i1=0; i1<=rowsize-1; i1++) + { + if( rf->ptr.p_bool[i1] ) + { + + /* + * Calculate distance + */ + v = s->cw.ptr.p_double[itemoffs]-rx->ptr.p_double[i1]; + ptdist2 = partialptdist2+v*v; + + /* + * Skip points if distance too large + */ + if( ptdist2>=rfar2 ) + { + continue; + } + + /* + * Update Y + */ + val = rbfv2basisfunc(s->bf, ptdist2*invr2, _state); + woffs = itemoffs+nx; + for(j=0; j<=ny-1; j++) + { + ry->ptr.p_double[j+i1*ny] = ry->ptr.p_double[j+i1*ny]+val*s->cw.ptr.p_double[woffs+j]; + } + } + } + } + return; + } + + /* + * Simple split + */ + if( s->kdnodes.ptr.p_int[rootidx]==0 ) + { + + /* + * Load: + * * D dimension to split + * * Split split position + * * ChildLE, ChildGE - indexes of childs + */ + d = s->kdnodes.ptr.p_int[rootidx+1]; + split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]]; + childle = s->kdnodes.ptr.p_int[rootidx+3]; + childge = s->kdnodes.ptr.p_int[rootidx+4]; + + /* + * Navigate through childs + */ + for(i=0; i<=1; i++) + { + + /* + * Select child to process: + * * ChildOffs current child offset in Nodes[] + * * UpdateMin whether minimum or maximum value + * of bounding box is changed on update + */ + updatemin = i!=0; + if( i==0 ) + { + childoffs = childle; + } + else + { + childoffs = childge; + } + + /* + * Update bounding box and current distance + */ + prevdist2 = buf->curdist2; + t1 = cx->ptr.p_double[d]; + if( updatemin ) + { + v = buf->curboxmin.ptr.p_double[d]; + if( t1<=split ) + { + v0 = v-t1; + if( v0<(double)0 ) + { + v0 = (double)(0); + } + v1 = split-t1; + buf->curdist2 = buf->curdist2-v0*v0+v1*v1; + } + buf->curboxmin.ptr.p_double[d] = split; + } + else + { + v = buf->curboxmax.ptr.p_double[d]; + if( t1>=split ) + { + v0 = t1-v; + if( v0<(double)0 ) + { + v0 = (double)(0); + } + v1 = t1-split; + buf->curdist2 = buf->curdist2-v0*v0+v1*v1; + } + buf->curboxmax.ptr.p_double[d] = split; + } + + /* + * Decide: to dive into cell or not to dive + */ + if( buf->curdist2curboxmin.ptr.p_double[d] = v; + } + else + { + buf->curboxmax.ptr.p_double[d] = v; + } + buf->curdist2 = prevdist2; + } + return; + } + + /* + * Integrity failure + */ + ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state); +} + + +/************************************************************************* +This function prepares partial query + +INPUT PARAMETERS: + X - query point + kdBoxMin, kdBoxMax - current bounding box + NX - problem size + Buf - preallocated buffer; this function just loads data, but + does not allocate place for them. + Cnt - counter variable which is set to zery by this function, as + convenience, and to remember about necessity to zero counter + prior to calling partialqueryrec(). + +OUTPUT PARAMETERS + Buf - calc-buffer: + * Buf.CurBoxMin - current box + * Buf.CurBoxMax - current box + * Buf.CurDist2 - squared distance from X to current box + Cnt - set to zero + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_preparepartialquery(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + ae_int_t nx, + rbfv2calcbuffer* buf, + ae_int_t* cnt, + ae_state *_state) +{ + ae_int_t j; + + + *cnt = 0; + buf->curdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + buf->curboxmin.ptr.p_double[j] = kdboxmin->ptr.p_double[j]; + buf->curboxmax.ptr.p_double[j] = kdboxmax->ptr.p_double[j]; + if( ae_fp_less(x->ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-x->ptr.p_double[j], _state); + } + else + { + if( ae_fp_greater(x->ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) ) + { + buf->curdist2 = buf->curdist2+ae_sqr(x->ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state); + } + } + } +} + + +/************************************************************************* +This function performs partial (for just one subtree of multi-tree) query +for neighbors located in R-sphere around X. It returns squared distances +from X to points and offsets in S.CW[] array for points being found. + +INPUT PARAMETERS: + kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model + Buf - calc-buffer, this function uses following fields: + * Buf.CurBoxMin - should be set by caller + * Buf.CurBoxMax - should be set by caller + * Buf.CurDist2 - squared distance from X to current + bounding box, should be set by caller + You may use preparepartialquery() function to initialize + these fields. + RootIdx - offset of partial kd-tree + QueryR2 - squared query radius + X - array[NX], point being queried + R2 - preallocated output buffer; it is caller's responsibility + to make sure that R2 has enough space. + Offs - preallocated output buffer; it is caller's responsibility + to make sure that Offs has enough space. + K - MUST BE ZERO ON INITIAL CALL. This variable is incremented, + not set. So, any no-zero value will result in the incorrect + points count being returned. + +OUTPUT PARAMETERS + R2 - squared distances in first K elements + Offs - offsets in S.CW in first K elements + K - points count + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_partialqueryrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + ae_int_t nx, + ae_int_t ny, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double queryr2, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r2, + /* Integer */ ae_vector* offs, + ae_int_t* k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double ptdist2; + double v; + ae_int_t cwoffs; + ae_int_t cwcnt; + ae_int_t itemoffs; + ae_int_t d; + double split; + ae_int_t childle; + ae_int_t childge; + ae_int_t childoffs; + ae_bool updatemin; + double prevdist2; + double t1; + + + + /* + * Leaf node. + */ + if( kdnodes->ptr.p_int[rootidx]>0 ) + { + cwcnt = kdnodes->ptr.p_int[rootidx+0]; + cwoffs = kdnodes->ptr.p_int[rootidx+1]; + for(i=0; i<=cwcnt-1; i++) + { + + /* + * Calculate distance + */ + itemoffs = cwoffs+i*(nx+ny); + ptdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j]; + ptdist2 = ptdist2+v*v; + } + + /* + * Skip points if distance too large + */ + if( ae_fp_greater_eq(ptdist2,queryr2) ) + { + continue; + } + + /* + * Output + */ + r2->ptr.p_double[*k] = ptdist2; + offs->ptr.p_int[*k] = itemoffs; + *k = *k+1; + } + return; + } + + /* + * Simple split + */ + if( kdnodes->ptr.p_int[rootidx]==0 ) + { + + /* + * Load: + * * D dimension to split + * * Split split position + * * ChildLE, ChildGE - indexes of childs + */ + d = kdnodes->ptr.p_int[rootidx+1]; + split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]]; + childle = kdnodes->ptr.p_int[rootidx+3]; + childge = kdnodes->ptr.p_int[rootidx+4]; + + /* + * Navigate through childs + */ + for(i=0; i<=1; i++) + { + + /* + * Select child to process: + * * ChildOffs current child offset in Nodes[] + * * UpdateMin whether minimum or maximum value + * of bounding box is changed on update + */ + updatemin = i!=0; + if( i==0 ) + { + childoffs = childle; + } + else + { + childoffs = childge; + } + + /* + * Update bounding box and current distance + */ + prevdist2 = buf->curdist2; + t1 = x->ptr.p_double[d]; + if( updatemin ) + { + v = buf->curboxmin.ptr.p_double[d]; + if( ae_fp_less_eq(t1,split) ) + { + buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state); + } + buf->curboxmin.ptr.p_double[d] = split; + } + else + { + v = buf->curboxmax.ptr.p_double[d]; + if( ae_fp_greater_eq(t1,split) ) + { + buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state); + } + buf->curboxmax.ptr.p_double[d] = split; + } + + /* + * Decide: to dive into cell or not to dive + */ + if( ae_fp_less(buf->curdist2,queryr2) ) + { + rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, r2, offs, k, _state); + } + + /* + * Restore bounding box and distance + */ + if( updatemin ) + { + buf->curboxmin.ptr.p_double[d] = v; + } + else + { + buf->curboxmax.ptr.p_double[d] = v; + } + buf->curdist2 = prevdist2; + } + return; + } + + /* + * Integrity failure + */ + ae_assert(ae_false, "PartialQueryRec: integrity check failed", _state); +} + + +/************************************************************************* +This function performs partial (for just one subtree of multi-tree) +counting of neighbors located in R-sphere around X. + +This function does not guarantee consistency of results with other partial +queries, it should be used only to get approximate estimates (well, we do +not use approximate algorithms, but rounding errors may give us +inconsistent results in just-at-the-boundary cases). + +INPUT PARAMETERS: + kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model + Buf - calc-buffer, this function uses following fields: + * Buf.CurBoxMin - should be set by caller + * Buf.CurBoxMax - should be set by caller + * Buf.CurDist2 - squared distance from X to current + bounding box, should be set by caller + You may use preparepartialquery() function to initialize + these fields. + RootIdx - offset of partial kd-tree + QueryR2 - squared query radius + X - array[NX], point being queried + +RESULT: + points count + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t rbfv2_partialcountrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + ae_int_t nx, + ae_int_t ny, + rbfv2calcbuffer* buf, + ae_int_t rootidx, + double queryr2, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double ptdist2; + double v; + ae_int_t cwoffs; + ae_int_t cwcnt; + ae_int_t itemoffs; + ae_int_t d; + double split; + ae_int_t childle; + ae_int_t childge; + ae_int_t childoffs; + ae_bool updatemin; + double prevdist2; + double t1; + ae_int_t result; + + + result = 0; + + /* + * Leaf node. + */ + if( kdnodes->ptr.p_int[rootidx]>0 ) + { + cwcnt = kdnodes->ptr.p_int[rootidx+0]; + cwoffs = kdnodes->ptr.p_int[rootidx+1]; + for(i=0; i<=cwcnt-1; i++) + { + + /* + * Calculate distance + */ + itemoffs = cwoffs+i*(nx+ny); + ptdist2 = (double)(0); + for(j=0; j<=nx-1; j++) + { + v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j]; + ptdist2 = ptdist2+v*v; + } + + /* + * Skip points if distance too large + */ + if( ae_fp_greater_eq(ptdist2,queryr2) ) + { + continue; + } + + /* + * Output + */ + result = result+1; + } + return result; + } + + /* + * Simple split + */ + if( kdnodes->ptr.p_int[rootidx]==0 ) + { + + /* + * Load: + * * D dimension to split + * * Split split position + * * ChildLE, ChildGE - indexes of childs + */ + d = kdnodes->ptr.p_int[rootidx+1]; + split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]]; + childle = kdnodes->ptr.p_int[rootidx+3]; + childge = kdnodes->ptr.p_int[rootidx+4]; + + /* + * Navigate through childs + */ + for(i=0; i<=1; i++) + { + + /* + * Select child to process: + * * ChildOffs current child offset in Nodes[] + * * UpdateMin whether minimum or maximum value + * of bounding box is changed on update + */ + updatemin = i!=0; + if( i==0 ) + { + childoffs = childle; + } + else + { + childoffs = childge; + } + + /* + * Update bounding box and current distance + */ + prevdist2 = buf->curdist2; + t1 = x->ptr.p_double[d]; + if( updatemin ) + { + v = buf->curboxmin.ptr.p_double[d]; + if( ae_fp_less_eq(t1,split) ) + { + buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state); + } + buf->curboxmin.ptr.p_double[d] = split; + } + else + { + v = buf->curboxmax.ptr.p_double[d]; + if( ae_fp_greater_eq(t1,split) ) + { + buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state); + } + buf->curboxmax.ptr.p_double[d] = split; + } + + /* + * Decide: to dive into cell or not to dive + */ + if( ae_fp_less(buf->curdist2,queryr2) ) + { + result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, _state); + } + + /* + * Restore bounding box and distance + */ + if( updatemin ) + { + buf->curboxmin.ptr.p_double[d] = v; + } + else + { + buf->curboxmax.ptr.p_double[d] = v; + } + buf->curdist2 = prevdist2; + } + return result; + } + + /* + * Integrity failure + */ + ae_assert(ae_false, "PartialCountRec: integrity check failed", _state); + return result; +} + + +/************************************************************************* +This function performs partial (for just one subtree of multi-tree) unpack +for RBF model. It appends center coordinates, weights and per-dimension +radii (according to current scaling) to preallocated output array. + +INPUT PARAMETERS: + kdNodes, kdSplits, CW, S, NX, NY - corresponding fields of V2 model + RootIdx - offset of partial kd-tree + R - radius for current partial tree + XWR - preallocated output buffer; it is caller's responsibility + to make sure that XWR has enough space. First K rows are + already occupied. + K - number of already occupied rows in XWR. + +OUTPUT PARAMETERS + XWR - updated XWR + K - updated rows count + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_partialunpackrec(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* s, + ae_int_t nx, + ae_int_t ny, + ae_int_t rootidx, + double r, + /* Real */ ae_matrix* xwr, + ae_int_t* k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t childle; + ae_int_t childge; + ae_int_t itemoffs; + ae_int_t cwoffs; + ae_int_t cwcnt; + + + + /* + * Leaf node. + */ + if( kdnodes->ptr.p_int[rootidx]>0 ) + { + cwcnt = kdnodes->ptr.p_int[rootidx+0]; + cwoffs = kdnodes->ptr.p_int[rootidx+1]; + for(i=0; i<=cwcnt-1; i++) + { + itemoffs = cwoffs+i*(nx+ny); + for(j=0; j<=nx+ny-1; j++) + { + xwr->ptr.pp_double[*k][j] = cw->ptr.p_double[itemoffs+j]; + } + for(j=0; j<=nx-1; j++) + { + xwr->ptr.pp_double[*k][j] = xwr->ptr.pp_double[*k][j]*s->ptr.p_double[j]; + } + for(j=0; j<=nx-1; j++) + { + xwr->ptr.pp_double[*k][nx+ny+j] = r*s->ptr.p_double[j]; + } + *k = *k+1; + } + return; + } + + /* + * Simple split + */ + if( kdnodes->ptr.p_int[rootidx]==0 ) + { + + /* + * Load: + * * ChildLE, ChildGE - indexes of childs + */ + childle = kdnodes->ptr.p_int[rootidx+3]; + childge = kdnodes->ptr.p_int[rootidx+4]; + + /* + * Process both parts of split + */ + rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childle, r, xwr, k, _state); + rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childge, r, xwr, k, _state); + return; + } + + /* + * Integrity failure + */ + ae_assert(ae_false, "PartialUnpackRec: integrity check failed", _state); +} + + +/************************************************************************* +This function returns size of design matrix row for evaluation point X0, +given: +* query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius()) +* hierarchy level: value in [0,NH) for single-level model, or negative + value for multilevel model (all levels of hierarchy in single matrix, + like one used by nonnegative RBF) + +INPUT PARAMETERS: + kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model + Level - value in [0,NH) for single-level design matrix, negative + value for multilevel design matrix + RCoeff - radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius() + X0 - query point + CalcBuf - buffer for PreparePartialQuery(), allocated by caller + +RESULT: + row size + + -- ALGLIB -- + Copyright 28.09.2016 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* ri, + /* Integer */ const ae_vector* kdroots, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + ae_int_t nx, + ae_int_t ny, + ae_int_t nh, + ae_int_t level, + double rcoeff, + /* Real */ ae_vector* x0, + rbfv2calcbuffer* calcbuf, + ae_state *_state) +{ + ae_int_t dummy; + ae_int_t levelidx; + ae_int_t level0; + ae_int_t level1; + double curradius2; + ae_int_t result; + + + ae_assert(nh>0, "DesignMatrixRowSize: integrity failure", _state); + if( level>=0 ) + { + level0 = level; + level1 = level; + } + else + { + level0 = 0; + level1 = nh-1; + } + result = 0; + for(levelidx=level0; levelidx<=level1; levelidx++) + { + curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state); + rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &dummy, _state); + result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, _state); + } + return result; +} + + +/************************************************************************* +This function generates design matrix row for evaluation point X0, given: +* query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius()) +* hierarchy level: value in [0,NH) for single-level model, or negative + value for multilevel model (all levels of hierarchy in single matrix, + like one used by nonnegative RBF) + +INPUT PARAMETERS: + kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model + + CWRange - internal array[NH+1] used by RBF construction function, + stores ranges of CW occupied by NH trees. + Level - value in [0,NH) for single-level design matrix, negative + value for multilevel design matrix + BF - basis function type + RCoeff - radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius() + RowsPerPoint-equal to: + * 1 for unpenalized regression model + * 1+NX for basic form of nonsmoothness penalty + Penalty - nonsmoothness penalty coefficient + + X0 - query point + + CalcBuf - buffer for PreparePartialQuery(), allocated by caller + R2 - preallocated temporary buffer, size is at least NPoints; + it is caller's responsibility to make sure that R2 has enough space. + Offs - preallocated temporary buffer; size is at least NPoints; + it is caller's responsibility to make sure that Offs has enough space. + K - MUST BE ZERO ON INITIAL CALL. This variable is incremented, + not set. So, any no-zero value will result in the incorrect + points count being returned. + RowIdx - preallocated array, at least RowSize elements + RowVal - preallocated array, at least RowSize*RowsPerPoint elements + +RESULT: + RowIdx - RowSize elements are filled with column indexes of non-zero + design matrix entries + RowVal - RowSize*RowsPerPoint elements are filled with design matrix + values, with column RowIdx[0] being stored in first RowsPerPoint + elements of RowVal, column RowIdx[1] being stored in next + RowsPerPoint elements, and so on. + + First element in contiguous set of RowsPerPoint elements + corresponds to + + RowSize - number of columns per row + + -- ALGLIB -- + Copyright 28.09.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_designmatrixgeneraterow(/* Integer */ const ae_vector* kdnodes, + /* Real */ const ae_vector* kdsplits, + /* Real */ const ae_vector* cw, + /* Real */ const ae_vector* ri, + /* Integer */ const ae_vector* kdroots, + /* Real */ const ae_vector* kdboxmin, + /* Real */ const ae_vector* kdboxmax, + /* Integer */ const ae_vector* cwrange, + ae_int_t nx, + ae_int_t ny, + ae_int_t nh, + ae_int_t level, + ae_int_t bf, + double rcoeff, + ae_int_t rowsperpoint, + double penalty, + /* Real */ ae_vector* x0, + rbfv2calcbuffer* calcbuf, + /* Real */ ae_vector* tmpr2, + /* Integer */ ae_vector* tmpoffs, + /* Integer */ ae_vector* rowidx, + /* Real */ ae_vector* rowval, + ae_int_t* rowsize, + ae_state *_state) +{ + ae_int_t j; + ae_int_t k; + ae_int_t cnt; + ae_int_t levelidx; + ae_int_t level0; + ae_int_t level1; + double invri2; + double curradius2; + double val; + double dval; + double d2val; + + *rowsize = 0; + + ae_assert(nh>0, "DesignMatrixGenerateRow: integrity failure (a)", _state); + ae_assert(rowsperpoint==1||rowsperpoint==1+nx, "DesignMatrixGenerateRow: integrity failure (b)", _state); + if( level>=0 ) + { + level0 = level; + level1 = level; + } + else + { + level0 = 0; + level1 = nh-1; + } + *rowsize = 0; + for(levelidx=level0; levelidx<=level1; levelidx++) + { + curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state); + invri2 = (double)1/ae_sqr(ri->ptr.p_double[levelidx], _state); + rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &cnt, _state); + rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, tmpr2, tmpoffs, &cnt, _state); + ae_assert(tmpr2->cnt>=cnt, "DesignMatrixRowSize: integrity failure (c)", _state); + ae_assert(tmpoffs->cnt>=cnt, "DesignMatrixRowSize: integrity failure (d)", _state); + ae_assert(rowidx->cnt>=*rowsize+cnt, "DesignMatrixRowSize: integrity failure (e)", _state); + ae_assert(rowval->cnt>=rowsperpoint*(*rowsize+cnt), "DesignMatrixRowSize: integrity failure (f)", _state); + for(j=0; j<=cnt-1; j++) + { + + /* + * Generate element corresponding to fitting error. + * Store derivative information which may be required later. + */ + ae_assert((tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])%(nx+ny)==0, "DesignMatrixRowSize: integrity failure (g)", _state); + rbfv2basisfuncdiff2(bf, tmpr2->ptr.p_double[j]*invri2, &val, &dval, &d2val, _state); + rowidx->ptr.p_int[*rowsize+j] = (tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])/(nx+ny); + rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+0] = val; + if( rowsperpoint==1 ) + { + continue; + } + + /* + * Generate elements corresponding to nonsmoothness penalty + */ + ae_assert(rowsperpoint==1+nx, "DesignMatrixRowSize: integrity failure (h)", _state); + for(k=0; k<=nx-1; k++) + { + rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+1+k] = penalty*(dval*(double)2*invri2+d2val*ae_sqr((double)2*(x0->ptr.p_double[k]-cw->ptr.p_double[tmpoffs->ptr.p_int[j]+k])*invri2, _state)); + } + } + + /* + * Update columns counter + */ + *rowsize = *rowsize+cnt; + } +} + + +/************************************************************************* +This function fills RBF model by zeros. + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +static void rbfv2_zerofill(rbfv2model* s, + ae_int_t nx, + ae_int_t ny, + ae_int_t bf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + s->bf = bf; + s->nh = 0; + ae_vector_set_length(&s->ri, 0, _state); + ae_vector_set_length(&s->s, 0, _state); + ae_vector_set_length(&s->kdroots, 0, _state); + ae_vector_set_length(&s->kdnodes, 0, _state); + ae_vector_set_length(&s->kdsplits, 0, _state); + ae_vector_set_length(&s->kdboxmin, 0, _state); + ae_vector_set_length(&s->kdboxmax, 0, _state); + ae_vector_set_length(&s->cw, 0, _state); + ae_matrix_set_length(&s->v, ny, nx+1, _state); + for(i=0; i<=ny-1; i++) + { + for(j=0; j<=nx; j++) + { + s->v.ptr.pp_double[i][j] = (double)(0); + } + } +} + + +void _rbfv2calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x123, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y123, 0, DT_REAL, _state, make_automatic); +} + + +void _rbfv2calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv2calcbuffer *dst = (rbfv2calcbuffer*)_dst; + const rbfv2calcbuffer *src = (const rbfv2calcbuffer*)_src; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic); + ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic); + dst->curdist2 = src->curdist2; + ae_vector_init_copy(&dst->x123, &src->x123, _state, make_automatic); + ae_vector_init_copy(&dst->y123, &src->y123, _state, make_automatic); +} + + +void _rbfv2calcbuffer_clear(void* _p) +{ + rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->curboxmin); + ae_vector_clear(&p->curboxmax); + ae_vector_clear(&p->x123); + ae_vector_clear(&p->y123); +} + + +void _rbfv2calcbuffer_destroy(void* _p) +{ + rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->curboxmin); + ae_vector_destroy(&p->curboxmax); + ae_vector_destroy(&p->x123); + ae_vector_destroy(&p->y123); +} + + +void _rbfv2model_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv2model *p = (rbfv2model*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->ri, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->kdroots, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->kdnodes, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->kdsplits, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->kdboxmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->kdboxmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cw, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic); + _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic); +} + + +void _rbfv2model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv2model *dst = (rbfv2model*)_dst; + const rbfv2model *src = (const rbfv2model*)_src; + dst->ny = src->ny; + dst->nx = src->nx; + dst->bf = src->bf; + dst->nh = src->nh; + ae_vector_init_copy(&dst->ri, &src->ri, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->kdroots, &src->kdroots, _state, make_automatic); + ae_vector_init_copy(&dst->kdnodes, &src->kdnodes, _state, make_automatic); + ae_vector_init_copy(&dst->kdsplits, &src->kdsplits, _state, make_automatic); + ae_vector_init_copy(&dst->kdboxmin, &src->kdboxmin, _state, make_automatic); + ae_vector_init_copy(&dst->kdboxmax, &src->kdboxmax, _state, make_automatic); + ae_vector_init_copy(&dst->cw, &src->cw, _state, make_automatic); + ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic); + dst->lambdareg = src->lambdareg; + dst->maxits = src->maxits; + dst->supportr = src->supportr; + dst->basisfunction = src->basisfunction; + _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic); +} + + +void _rbfv2model_clear(void* _p) +{ + rbfv2model *p = (rbfv2model*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->ri); + ae_vector_clear(&p->s); + ae_vector_clear(&p->kdroots); + ae_vector_clear(&p->kdnodes); + ae_vector_clear(&p->kdsplits); + ae_vector_clear(&p->kdboxmin); + ae_vector_clear(&p->kdboxmax); + ae_vector_clear(&p->cw); + ae_matrix_clear(&p->v); + _rbfv2calcbuffer_clear(&p->calcbuf); +} + + +void _rbfv2model_destroy(void* _p) +{ + rbfv2model *p = (rbfv2model*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->ri); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->kdroots); + ae_vector_destroy(&p->kdnodes); + ae_vector_destroy(&p->kdsplits); + ae_vector_destroy(&p->kdboxmin); + ae_vector_destroy(&p->kdboxmax); + ae_vector_destroy(&p->cw); + ae_matrix_destroy(&p->v); + _rbfv2calcbuffer_destroy(&p->calcbuf); +} + + +void _rbfv2gridcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic); + ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ry, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rf, 0, DT_BOOL, _state, make_automatic); +} + + +void _rbfv2gridcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv2gridcalcbuffer *dst = (rbfv2gridcalcbuffer*)_dst; + const rbfv2gridcalcbuffer *src = (const rbfv2gridcalcbuffer*)_src; + _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic); + ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic); + ae_vector_init_copy(&dst->ry, &src->ry, _state, make_automatic); + ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic); + ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic); + ae_vector_init_copy(&dst->rf, &src->rf, _state, make_automatic); +} + + +void _rbfv2gridcalcbuffer_clear(void* _p) +{ + rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv2calcbuffer_clear(&p->calcbuf); + ae_vector_clear(&p->cx); + ae_vector_clear(&p->rx); + ae_vector_clear(&p->ry); + ae_vector_clear(&p->tx); + ae_vector_clear(&p->ty); + ae_vector_clear(&p->rf); +} + + +void _rbfv2gridcalcbuffer_destroy(void* _p) +{ + rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv2calcbuffer_destroy(&p->calcbuf); + ae_vector_destroy(&p->cx); + ae_vector_destroy(&p->rx); + ae_vector_destroy(&p->ry); + ae_vector_destroy(&p->tx); + ae_vector_destroy(&p->ty); + ae_vector_destroy(&p->rf); +} + + +void _rbfv2report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfv2report *p = (rbfv2report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv2report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfv2report *dst = (rbfv2report*)_dst; + const rbfv2report *src = (const rbfv2report*)_src; + dst->terminationtype = src->terminationtype; + dst->maxerror = src->maxerror; + dst->rmserror = src->rmserror; +} + + +void _rbfv2report_clear(void* _p) +{ + rbfv2report *p = (rbfv2report*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfv2report_destroy(void* _p) +{ + rbfv2report *p = (rbfv2report*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine calculates the value of the trilinear or tricubic spline at +the given point (X,Y,Z). + +INPUT PARAMETERS: + C - coefficients table. + Built by BuildBilinearSpline or BuildBicubicSpline. + X, Y, + Z - point + +Result: + S(x,y,z) + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +double spline3dcalc(const spline3dinterpolant* c, + double x, + double y, + double z, + ae_state *_state) +{ + double v; + double vx; + double vy; + double vxy; + double result; + + + ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalc: incorrect C (incorrect parameter C.SType)", _state); + ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalc: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); + if( c->d!=1 ) + { + result = (double)(0); + return result; + } + spline3d_spline3ddiff(c, x, y, z, &v, &vx, &vy, &vxy, _state); + result = v; + return result; +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant + AX, BX - transformation coefficients: x = A*u + B + AY, BY - transformation coefficients: y = A*v + B + AZ, BZ - transformation coefficients: z = A*w + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransxyz(spline3dinterpolant* c, + double ax, + double bx, + double ay, + double by, + double az, + double bz, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector z; + ae_vector f; + ae_vector v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&z, 0, sizeof(z)); + memset(&f, 0, sizeof(f)); + memset(&v, 0, sizeof(v)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + ae_vector_init(&f, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + + ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransXYZ: incorrect C (incorrect parameter C.SType)", _state); + ae_vector_set_length(&x, c->n, _state); + ae_vector_set_length(&y, c->m, _state); + ae_vector_set_length(&z, c->l, _state); + ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = c->x.ptr.p_double[j]; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = c->y.ptr.p_double[i]; + } + for(i=0; i<=c->l-1; i++) + { + z.ptr.p_double[i] = c->z.ptr.p_double[i]; + } + + /* + * Handle different combinations of zero/nonzero AX/AY/AZ + */ + if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) + { + ae_v_move(&f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,c->m*c->n*c->l*c->d-1)); + } + if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) + { + for(i=0; i<=c->m-1; i++) + { + for(j=0; j<=c->l-1; j++) + { + spline3dcalcv(c, bx, y.ptr.p_double[i], z.ptr.p_double[j], &v, _state); + for(k=0; k<=c->n-1; k++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*j+i)+k)+di] = v.ptr.p_double[di]; + } + } + } + } + ax = (double)(1); + bx = (double)(0); + } + if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) + { + for(i=0; i<=c->n-1; i++) + { + for(j=0; j<=c->l-1; j++) + { + spline3dcalcv(c, x.ptr.p_double[i], by, z.ptr.p_double[j], &v, _state); + for(k=0; k<=c->m-1; k++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*j+k)+i)+di] = v.ptr.p_double[di]; + } + } + } + } + ay = (double)(1); + by = (double)(0); + } + if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) + { + for(i=0; i<=c->n-1; i++) + { + for(j=0; j<=c->m-1; j++) + { + spline3dcalcv(c, x.ptr.p_double[i], y.ptr.p_double[j], bz, &v, _state); + for(k=0; k<=c->l-1; k++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; + } + } + } + } + az = (double)(1); + bz = (double)(0); + } + if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) ) + { + for(i=0; i<=c->l-1; i++) + { + spline3dcalcv(c, bx, by, z.ptr.p_double[i], &v, _state); + for(k=0; k<=c->m-1; k++) + { + for(j=0; j<=c->n-1; j++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*i+k)+j)+di] = v.ptr.p_double[di]; + } + } + } + } + ax = (double)(1); + bx = (double)(0); + ay = (double)(1); + by = (double)(0); + } + if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) + { + for(i=0; i<=c->m-1; i++) + { + spline3dcalcv(c, bx, y.ptr.p_double[i], bz, &v, _state); + for(k=0; k<=c->l-1; k++) + { + for(j=0; j<=c->n-1; j++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*k+i)+j)+di] = v.ptr.p_double[di]; + } + } + } + } + ax = (double)(1); + bx = (double)(0); + az = (double)(1); + bz = (double)(0); + } + if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) + { + for(i=0; i<=c->n-1; i++) + { + spline3dcalcv(c, x.ptr.p_double[i], by, bz, &v, _state); + for(k=0; k<=c->l-1; k++) + { + for(j=0; j<=c->m-1; j++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; + } + } + } + } + ay = (double)(1); + by = (double)(0); + az = (double)(1); + bz = (double)(0); + } + if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) ) + { + spline3dcalcv(c, bx, by, bz, &v, _state); + for(k=0; k<=c->l-1; k++) + { + for(j=0; j<=c->m-1; j++) + { + for(i=0; i<=c->n-1; i++) + { + for(di=0; di<=c->d-1; di++) + { + f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di]; + } + } + } + } + ax = (double)(1); + bx = (double)(0); + ay = (double)(1); + by = (double)(0); + az = (double)(1); + bz = (double)(0); + } + + /* + * General case: AX<>0, AY<>0, AZ<>0 + * Unpack, scale and pack again. + */ + for(i=0; i<=c->n-1; i++) + { + x.ptr.p_double[i] = (x.ptr.p_double[i]-bx)/ax; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay; + } + for(i=0; i<=c->l-1; i++) + { + z.ptr.p_double[i] = (z.ptr.p_double[i]-bz)/az; + } + if( c->stype==-1 ) + { + spline3dbuildtrilinearvbuf(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransf(spline3dinterpolant* c, + double a, + double b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector z; + ae_vector f; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&z, 0, sizeof(z)); + memset(&f, 0, sizeof(f)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + ae_vector_init(&f, 0, DT_REAL, _state, ae_true); + + ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransF: incorrect C (incorrect parameter C.SType)", _state); + ae_vector_set_length(&x, c->n, _state); + ae_vector_set_length(&y, c->m, _state); + ae_vector_set_length(&z, c->l, _state); + ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state); + for(j=0; j<=c->n-1; j++) + { + x.ptr.p_double[j] = c->x.ptr.p_double[j]; + } + for(i=0; i<=c->m-1; i++) + { + y.ptr.p_double[i] = c->y.ptr.p_double[i]; + } + for(i=0; i<=c->l-1; i++) + { + z.ptr.p_double[i] = c->z.ptr.p_double[i]; + } + for(i=0; i<=c->m*c->n*c->l*c->d-1; i++) + { + f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b; + } + if( c->stype==-1 ) + { + spline3dbuildtrilinearvbuf(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine makes the copy of the spline model. + +INPUT PARAMETERS: + C - spline interpolant + +OUTPUT PARAMETERS: + CC - spline copy + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcopy(const spline3dinterpolant* c, + spline3dinterpolant* cc, + ae_state *_state) +{ + ae_int_t tblsize; + + _spline3dinterpolant_clear(cc); + + ae_assert(c->k==1||c->k==3, "Spline3DCopy: incorrect C (incorrect parameter C.K)", _state); + cc->k = c->k; + cc->n = c->n; + cc->m = c->m; + cc->l = c->l; + cc->d = c->d; + tblsize = c->n*c->m*c->l*c->d; + cc->stype = c->stype; + ae_vector_set_length(&cc->x, cc->n, _state); + ae_vector_set_length(&cc->y, cc->m, _state); + ae_vector_set_length(&cc->z, cc->l, _state); + ae_vector_set_length(&cc->f, tblsize, _state); + ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1)); + ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1)); + ae_v_move(&cc->z.ptr.p_double[0], 1, &c->z.ptr.p_double[0], 1, ae_v_len(0,cc->l-1)); + ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1)); +} + + +/************************************************************************* +Trilinear spline resampling + +INPUT PARAMETERS: + A - array[0..OldXCount*OldYCount*OldZCount-1], function + values at the old grid, : + A[0] x=0,y=0,z=0 + A[1] x=1,y=0,z=0 + A[..] ... + A[..] x=oldxcount-1,y=0,z=0 + A[..] x=0,y=1,z=0 + A[..] ... + ... + OldZCount - old Z-count, OldZCount>1 + OldYCount - old Y-count, OldYCount>1 + OldXCount - old X-count, OldXCount>1 + NewZCount - new Z-count, NewZCount>1 + NewYCount - new Y-count, NewYCount>1 + NewXCount - new X-count, NewXCount>1 + +OUTPUT PARAMETERS: + B - array[0..NewXCount*NewYCount*NewZCount-1], function + values at the new grid: + B[0] x=0,y=0,z=0 + B[1] x=1,y=0,z=0 + B[..] ... + B[..] x=newxcount-1,y=0,z=0 + B[..] x=0,y=1,z=0 + B[..] ... + ... + + -- ALGLIB routine -- + 26.04.2012 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline3dresampletrilinear(/* Real */ const ae_vector* a, + ae_int_t oldzcount, + ae_int_t oldycount, + ae_int_t oldxcount, + ae_int_t newzcount, + ae_int_t newycount, + ae_int_t newxcount, + /* Real */ ae_vector* b, + ae_state *_state) +{ + double xd; + double yd; + double zd; + double c0; + double c1; + double c2; + double c3; + ae_int_t ix; + ae_int_t iy; + ae_int_t iz; + ae_int_t i; + ae_int_t j; + ae_int_t k; + + ae_vector_clear(b); + + ae_assert((oldycount>1&&oldzcount>1)&&oldxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); + ae_assert((newycount>1&&newzcount>1)&&newxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state); + ae_assert(a->cnt>=oldycount*oldzcount*oldxcount, "Spline3DResampleTrilinear: length/width/height less than 1", _state); + ae_vector_set_length(b, newxcount*newycount*newzcount, _state); + for(i=0; i<=newxcount-1; i++) + { + for(j=0; j<=newycount-1; j++) + { + for(k=0; k<=newzcount-1; k++) + { + ix = i*(oldxcount-1)/(newxcount-1); + if( ix==oldxcount-1 ) + { + ix = oldxcount-2; + } + xd = (double)(i*(oldxcount-1))/(double)(newxcount-1)-(double)ix; + iy = j*(oldycount-1)/(newycount-1); + if( iy==oldycount-1 ) + { + iy = oldycount-2; + } + yd = (double)(j*(oldycount-1))/(double)(newycount-1)-(double)iy; + iz = k*(oldzcount-1)/(newzcount-1); + if( iz==oldzcount-1 ) + { + iz = oldzcount-2; + } + zd = (double)(k*(oldzcount-1))/(double)(newzcount-1)-(double)iz; + c0 = a->ptr.p_double[oldxcount*(oldycount*iz+iy)+ix]*((double)1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+iy)+(ix+1)]*xd; + c1 = a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+ix]*((double)1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+(ix+1)]*xd; + c2 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+ix]*((double)1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+(ix+1)]*xd; + c3 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+ix]*((double)1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+(ix+1)]*xd; + c0 = c0*((double)1-yd)+c1*yd; + c1 = c2*((double)1-yd)+c3*yd; + b->ptr.p_double[newxcount*(newycount*k+j)+i] = c0*((double)1-zd)+c1*zd; + } + } + } +} + + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +INPUT PARAMETERS: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + Z - spline applicates, array[0..L-1] + F - function values, array[0..M*N*L*D-1]: + * first D elements store D values at (X[0],Y[0],Z[0]) + * next D elements store D values at (X[1],Y[0],Z[0]) + * next D elements store D values at (X[2],Y[0],Z[0]) + * ... + * next D elements store D values at (X[0],Y[1],Z[0]) + * next D elements store D values at (X[1],Y[1],Z[0]) + * next D elements store D values at (X[2],Y[1],Z[0]) + * ... + * next D elements store D values at (X[0],Y[0],Z[1]) + * next D elements store D values at (X[1],Y[0],Z[1]) + * next D elements store D values at (X[2],Y[0],Z[1]) + * ... + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. + M,N, + L - grid size, M>=2, N>=2, L>=2 + D - vector dimension, D>=1 + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* z, + ae_int_t l, + /* Real */ const ae_vector* f, + ae_int_t d, + spline3dinterpolant* c, + ae_state *_state) +{ + + _spline3dinterpolant_clear(c); + + spline3dbuildtrilinearvbuf(x, n, y, m, z, l, f, d, c, _state); +} + + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +Buffered version of Spline3DBuildTrilinearV() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearvbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* z, + ae_int_t l, + /* Real */ const ae_vector* f, + ae_int_t d, + spline3dinterpolant* c, + ae_state *_state) +{ + double t; + ae_int_t tblsize; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + ae_int_t j0; + + + ae_assert(m>=2, "Spline3DBuildTrilinearV: M<2", _state); + ae_assert(n>=2, "Spline3DBuildTrilinearV: N<2", _state); + ae_assert(l>=2, "Spline3DBuildTrilinearV: L<2", _state); + ae_assert(d>=1, "Spline3DBuildTrilinearV: D<1", _state); + ae_assert((x->cnt>=n&&y->cnt>=m)&&z->cnt>=l, "Spline3DBuildTrilinearV: length of X, Y or Z is too short (Length(X/Y/Z)cnt>=tblsize, "Spline3DBuildTrilinearV: length of F is too short (Length(F)k = 1; + c->n = n; + c->m = m; + c->l = l; + c->d = d; + c->stype = -1; + ae_vector_set_length(&c->x, c->n, _state); + ae_vector_set_length(&c->y, c->m, _state); + ae_vector_set_length(&c->z, c->l, _state); + ae_vector_set_length(&c->f, tblsize, _state); + for(i=0; i<=c->n-1; i++) + { + c->x.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=0; i<=c->m-1; i++) + { + c->y.ptr.p_double[i] = y->ptr.p_double[i]; + } + for(i=0; i<=c->l-1; i++) + { + c->z.ptr.p_double[i] = z->ptr.p_double[i]; + } + for(i=0; i<=tblsize-1; i++) + { + c->f.ptr.p_double[i] = f->ptr.p_double[i]; + } + + /* + * Sort points: + * * sort x; + * * sort y; + * * sort z. + */ + for(j=0; j<=c->n-1; j++) + { + k = j; + for(i=j+1; i<=c->n-1; i++) + { + if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) ) + { + k = i; + } + } + if( k!=j ) + { + for(i=0; i<=c->m-1; i++) + { + for(j0=0; j0<=c->l-1; j0++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0] = t; + } + } + } + t = c->x.ptr.p_double[j]; + c->x.ptr.p_double[j] = c->x.ptr.p_double[k]; + c->x.ptr.p_double[k] = t; + } + } + for(i=0; i<=c->m-1; i++) + { + k = i; + for(j=i+1; j<=c->m-1; j++) + { + if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) ) + { + k = j; + } + } + if( k!=i ) + { + for(j=0; j<=c->n-1; j++) + { + for(j0=0; j0<=c->l-1; j0++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0] = t; + } + } + } + t = c->y.ptr.p_double[i]; + c->y.ptr.p_double[i] = c->y.ptr.p_double[k]; + c->y.ptr.p_double[k] = t; + } + } + for(k=0; k<=c->l-1; k++) + { + i = k; + for(j=i+1; j<=c->l-1; j++) + { + if( ae_fp_less(c->z.ptr.p_double[j],c->z.ptr.p_double[i]) ) + { + i = j; + } + } + if( i!=k ) + { + for(j=0; j<=c->m-1; j++) + { + for(j0=0; j0<=c->n-1; j0++) + { + for(i0=0; i0<=c->d-1; i0++) + { + t = c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0]; + c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0] = t; + } + } + } + t = c->z.ptr.p_double[k]; + c->z.ptr.p_double[k] = c->z.ptr.p_double[i]; + c->z.ptr.p_double[i] = t; + } + } +} + + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + F - output buffer, possibly preallocated array. In case array size + is large enough to store result, it is not reallocated. Array + which is too short will be reallocated + +OUTPUT PARAMETERS: + F - array[D] (or larger) which stores function values + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcvbuf(const spline3dinterpolant* c, + double x, + double y, + double z, + /* Real */ ae_vector* f, + ae_state *_state) +{ + double xd; + double yd; + double zd; + double c0; + double c1; + double c2; + double c3; + ae_int_t ix; + ae_int_t iy; + ae_int_t iz; + ae_int_t l; + ae_int_t r; + ae_int_t h; + ae_int_t i; + + + ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state); + ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcVBuf: X, Y or Z contains NaN/Infinite", _state); + rvectorsetlengthatleast(f, c->d, _state); + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + ix = l; + + /* + * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + iy = l; + + /* + * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) + */ + l = 0; + r = c->l-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) + { + r = h; + } + else + { + l = h; + } + } + iz = l; + xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); + yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); + zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); + for(i=0; i<=c->d-1; i++) + { + + /* + * Trilinear interpolation + */ + if( c->stype==-1 ) + { + c0 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+ix)+i]*((double)1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+(ix+1))+i]*xd; + c1 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+ix)+i]*((double)1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+(ix+1))+i]*xd; + c2 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+ix)+i]*((double)1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+(ix+1))+i]*xd; + c3 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+ix)+i]*((double)1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+(ix+1))+i]*xd; + c0 = c0*((double)1-yd)+c1*yd; + c1 = c2*((double)1-yd)+c3*yd; + f->ptr.p_double[i] = c0*((double)1-zd)+c1*zd; + } + } +} + + +/************************************************************************* +This subroutine calculates trilinear or tricubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + +OUTPUT PARAMETERS: + F - array[D] which stores function values. F is out-parameter and + it is reallocated after call to this function. In case you + want to reuse previously allocated F, you may use + Spline2DCalcVBuf(), which reallocates F only when it is too + small. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcv(const spline3dinterpolant* c, + double x, + double y, + double z, + /* Real */ ae_vector* f, + ae_state *_state) +{ + + ae_vector_clear(f); + + ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcV: incorrect C (incorrect parameter C.SType)", _state); + ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcV: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state); + ae_vector_set_length(f, c->d, _state); + spline3dcalcvbuf(c, x, y, z, f, _state); +} + + +/************************************************************************* +This subroutine unpacks tri-dimensional spline into the coefficients table + +INPUT PARAMETERS: + C - spline interpolant. + +Result: + N - grid size (X) + M - grid size (Y) + L - grid size (Z) + D - number of components + SType- spline type. Currently, only one spline type is supported: + trilinear spline, as indicated by SType=1. + Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index), K=0..L-2 (z index): + Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), + + Q-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[Q,0] = X[i] + Tbl[Q,1] = X[i+1] + Tbl[Q,2] = Y[j] + Tbl[Q,3] = Y[j+1] + Tbl[Q,4] = Z[k] + Tbl[Q,5] = Z[k+1] + + Tbl[Q,6] = C000 + Tbl[Q,7] = C100 + Tbl[Q,8] = C010 + Tbl[Q,9] = C110 + Tbl[Q,10]= C001 + Tbl[Q,11]= C101 + Tbl[Q,12]= C011 + Tbl[Q,13]= C111 + On each grid square spline is equals to: + S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) + t = x-x[j] + u = y-y[i] + v = z-z[k] + + NOTE: format of Tbl is given for SType=1. Future versions of + ALGLIB can use different formats for different values of + SType. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dunpackv(const spline3dinterpolant* c, + ae_int_t* n, + ae_int_t* m, + ae_int_t* l, + ae_int_t* d, + ae_int_t* stype, + /* Real */ ae_matrix* tbl, + ae_state *_state) +{ + ae_int_t p; + ae_int_t ci; + ae_int_t cj; + ae_int_t ck; + double du; + double dv; + double dw; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t di; + ae_int_t i0; + + *n = 0; + *m = 0; + *l = 0; + *d = 0; + *stype = 0; + ae_matrix_clear(tbl); + + ae_assert(c->stype==-1, "Spline3DUnpackV: incorrect C (incorrect parameter C.SType)", _state); + *n = c->n; + *m = c->m; + *l = c->l; + *d = c->d; + *stype = ae_iabs(c->stype, _state); + ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*l-1)*(*d), 14, _state); + + /* + * Fill + */ + for(i=0; i<=*n-2; i++) + { + for(j=0; j<=*m-2; j++) + { + for(k=0; k<=*l-2; k++) + { + for(di=0; di<=*d-1; di++) + { + p = *d*((*n-1)*((*m-1)*k+j)+i)+di; + tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[i]; + tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[i+1]; + tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[j]; + tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[j+1]; + tbl->ptr.pp_double[p][4] = c->z.ptr.p_double[k]; + tbl->ptr.pp_double[p][5] = c->z.ptr.p_double[k+1]; + du = (double)1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]); + dv = (double)1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]); + dw = (double)1/(tbl->ptr.pp_double[p][5]-tbl->ptr.pp_double[p][4]); + + /* + * Trilinear interpolation + */ + if( c->stype==-1 ) + { + for(i0=6; i0<=13; i0++) + { + tbl->ptr.pp_double[p][i0] = (double)(0); + } + tbl->ptr.pp_double[p][6+2*(2*0+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*0+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*0+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*0+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*1+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*1+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*1+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + tbl->ptr.pp_double[p][6+2*(2*1+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di]; + } + + /* + * Rescale Cij + */ + for(ci=0; ci<=1; ci++) + { + for(cj=0; cj<=1; cj++) + { + for(ck=0; ck<=1; ck++) + { + tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci] = tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci]*ae_pow(du, (double)(ci), _state)*ae_pow(dv, (double)(cj), _state)*ae_pow(dw, (double)(ck), _state); + } + } + } + } + } + } + } +} + + +/************************************************************************* +This subroutine calculates the value of the trilinear(or tricubic;possible +will be later) spline at the given point X(and its derivatives; possible +will be later). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, Z - point + +OUTPUT PARAMETERS: + F - S(x,y,z) + FX - dS(x,y,z)/dX + FY - dS(x,y,z)/dY + FXY - d2S(x,y,z)/dXdY + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +static void spline3d_spline3ddiff(const spline3dinterpolant* c, + double x, + double y, + double z, + double* f, + double* fx, + double* fy, + double* fxy, + ae_state *_state) +{ + double xd; + double yd; + double zd; + double c0; + double c1; + double c2; + double c3; + ae_int_t ix; + ae_int_t iy; + ae_int_t iz; + ae_int_t l; + ae_int_t r; + ae_int_t h; + + *f = 0.0; + *fx = 0.0; + *fy = 0.0; + *fxy = 0.0; + + ae_assert(c->stype==-1||c->stype==-3, "Spline3DDiff: incorrect C (incorrect parameter C.SType)", _state); + ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline3DDiff: X or Y contains NaN or Infinite value", _state); + + /* + * Prepare F, dF/dX, dF/dY, d2F/dXdY + */ + *f = (double)(0); + *fx = (double)(0); + *fy = (double)(0); + *fxy = (double)(0); + if( c->d!=1 ) + { + return; + } + + /* + * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included) + */ + l = 0; + r = c->n-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) ) + { + r = h; + } + else + { + l = h; + } + } + ix = l; + + /* + * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included) + */ + l = 0; + r = c->m-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) ) + { + r = h; + } + else + { + l = h; + } + } + iy = l; + + /* + * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included) + */ + l = 0; + r = c->l-1; + while(l!=r-1) + { + h = (l+r)/2; + if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) ) + { + r = h; + } + else + { + l = h; + } + } + iz = l; + xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]); + yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]); + zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]); + + /* + * Trilinear interpolation + */ + if( c->stype==-1 ) + { + c0 = c->f.ptr.p_double[c->n*(c->m*iz+iy)+ix]*((double)1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+iy)+(ix+1)]*xd; + c1 = c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+ix]*((double)1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+(ix+1)]*xd; + c2 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+ix]*((double)1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+(ix+1)]*xd; + c3 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+ix]*((double)1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+(ix+1)]*xd; + c0 = c0*((double)1-yd)+c1*yd; + c1 = c2*((double)1-yd)+c3*yd; + *f = c0*((double)1-zd)+c1*zd; + } +} + + +void _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spline3dinterpolant *p = (spline3dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic); +} + + +void _spline3dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spline3dinterpolant *dst = (spline3dinterpolant*)_dst; + const spline3dinterpolant *src = (const spline3dinterpolant*)_src; + dst->k = src->k; + dst->stype = src->stype; + dst->n = src->n; + dst->m = src->m; + dst->l = src->l; + dst->d = src->d; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic); + ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic); +} + + +void _spline3dinterpolant_clear(void* _p) +{ + spline3dinterpolant *p = (spline3dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->z); + ae_vector_clear(&p->f); +} + + +void _spline3dinterpolant_destroy(void* _p) +{ + spline3dinterpolant *p = (spline3dinterpolant*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->z); + ae_vector_destroy(&p->f); +} + + +#endif +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremc() instead. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremcc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rhi, + ae_state *_state) +{ + double dummy; + + ae_vector_clear(cx); + *rhi = 0.0; + + nsfitspherex(xy, npoints, nx, 1, 0.0, 0, 0.0, cx, &dummy, rhi, _state); +} + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremi() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremic(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + ae_state *_state) +{ + double dummy; + + ae_vector_clear(cx); + *rlo = 0.0; + + nsfitspherex(xy, npoints, nx, 2, 0.0, 0, 0.0, cx, rlo, &dummy, _state); +} + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremz() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremzc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state) +{ + + ae_vector_clear(cx); + *rlo = 0.0; + *rhi = 0.0; + + nsfitspherex(xy, npoints, nx, 3, 0.0, 0, 0.0, cx, rlo, rhi, _state); +} + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspherex() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspherex(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + double epsx, + ae_int_t aulits, + double penalty, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state) +{ + + ae_vector_clear(cx); + *rlo = 0.0; + *rhi = 0.0; + + fitspherex(xy, npoints, nx, problemtype, epsx, aulits, cx, rlo, rhi, _state); +} + + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitpenalized(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t m, + double rho, + ae_int_t* info, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + ae_vector w; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&w, 0, sizeof(w)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + *info = 0; + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "Spline1DFitPenalized: N<1!", _state); + ae_assert(m>=4, "Spline1DFitPenalized: M<4!", _state); + ae_assert(x.cnt>=n, "Spline1DFitPenalized: Length(X)=n, "Spline1DFitPenalized: Length(Y)=1, "Spline1DFitPenalizedW: N<1!", _state); + ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state); + ae_assert(x.cnt>=n, "Spline1DFitPenalizedW: Length(X)=n, "Spline1DFitPenalizedW: Length(Y)=n, "Spline1DFitPenalizedW: Length(W)rmserror = (double)(0); + rep->avgerror = (double)(0); + rep->avgrelerror = (double)(0); + rep->maxerror = (double)(0); + relcnt = (double)(0); + spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, &x, n, &fcolumn, _state); + for(i=0; i<=n-1; i++) + { + v = (sb-sa)*fcolumn.ptr.p_double[i]+sa; + rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state); + rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state); + if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state); + relcnt = relcnt+(double)1; + } + rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state); + } + rep->rmserror = ae_sqrt(rep->rmserror/(double)n, _state); + rep->avgerror = rep->avgerror/(double)n; + if( ae_fp_neq(relcnt,(double)(0)) ) + { + rep->avgrelerror = rep->avgrelerror/relcnt; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubic(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + + spline1dfitcubicdeprecated(x, y, n, m, s, rep, _state); +} + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermite(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state) +{ + + _spline1dinterpolant_clear(s); + _spline1dfitreport_clear(rep); + + spline1dfithermitedeprecated(x, y, n, m, s, rep, _state); +} + + +#endif +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX>=1). + +Newly created model is empty. It can be used for interpolation right after +creation, but it just returns zeros. You have to add points to the model, +tune interpolation settings, and then call model construction function +rbfbuildmodel() which will update model according to your specification. + +USAGE: +1. User creates model with rbfcreate() +2. User adds dataset with rbfsetpoints() or rbfsetpointsandscales() +3. User selects RBF solver by calling: + * rbfsetalgohierarchical() - for a HRBF solver, a hierarchical large- + scale Gaussian RBFs (works well for uniformly distributed point + clouds, but may fail when the data are non-uniform; use other solvers + below in such cases) + * rbfsetalgothinplatespline() - for a large-scale DDM-RBF solver with + thin plate spline basis function being used + * rbfsetalgobiharmonic() - for a large-scale DDM-RBF solver with + biharmonic basis function being used + * rbfsetalgomultiquadricauto() - for a large-scale DDM-RBF solver with + multiquadric basis function being used (automatic selection of the + scale parameter Alpha) + * rbfsetalgomultiquadricmanual() - for a large-scale DDM-RBF solver + with multiquadric basis function being used (manual selection of the + scale parameter Alpha) +4. (OPTIONAL) User chooses polynomial term by calling: + * rbflinterm() to set linear term (default) + * rbfconstterm() to set constant term + * rbfzeroterm() to set zero term +5. User calls rbfbuildmodel() function which rebuilds model according to + the specification + +INPUT PARAMETERS: + NX - dimension of the space, NX>=1 + NY - function dimension, NY>=1 + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + +NOTE 1: memory requirements. RBF models require amount of memory which is + proportional to the number of data points. Some additional memory + is allocated during model construction, but most of this memory is + freed after the model coefficients are calculated. Amount of + this additional memory depends on model construction algorithm + being used. + + -- ALGLIB -- + Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state) +{ + + _rbfmodel_clear(s); + + ae_assert(nx>=1, "RBFCreate: NX<1", _state); + ae_assert(ny>=1, "RBFCreate: NY<1", _state); + s->nx = nx; + s->ny = ny; + rbf_rbfpreparenonserializablefields(s, _state); + + /* + * Select default model version according to NX. + * + * The idea is that when we call this function with NX=2 or NX=3, backward + * compatible dummy (zero) V1 model is created, so serialization produces + * model which are compatible with pre-3.11 ALGLIB. + */ + rbf_initializev1(nx, ny, &s->model1, _state); + rbf_initializev2(nx, ny, &s->model2, _state); + rbf_initializev3(nx, ny, &s->model3, _state); + if( nx==2||nx==3 ) + { + s->modelversion = 1; + } + else + { + s->modelversion = 2; + } + + /* + * Report fields + */ + s->progress10000 = 0; + s->terminationrequest = ae_false; + + /* + * Prepare buffers + */ + rbfcreatecalcbuffer(s, &s->calcbuf, _state); +} + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of the buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +A buffer creation function (this function) is also thread-safe. I.e. you +may safely create multiple buffers for the same RBF model from multiple +threads. + +NOTE: the buffer object is just a collection of several preallocated + dynamic arrays and precomputed values. If you delete its "parent" + RBF model when the buffer is still alive, nothing bad will happen + (no dangling pointers or resource leaks). The buffer will simply + become useless. + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. +* it is recommended to reuse buffer as much as possible because buffer + creation involves allocation of several large dynamic arrays. It is a + huge waste of resource to use it just once. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2016 by Sergey Bochkanov +*************************************************************************/ +void rbfcreatecalcbuffer(const rbfmodel* s, + rbfcalcbuffer* buf, + ae_state *_state) +{ + + _rbfcalcbuffer_clear(buf); + + if( s->modelversion==1 ) + { + buf->modelversion = 1; + rbfv1createcalcbuffer(&s->model1, &buf->bufv1, _state); + return; + } + if( s->modelversion==2 ) + { + buf->modelversion = 2; + rbfv2createcalcbuffer(&s->model2, &buf->bufv2, _state); + return; + } + if( s->modelversion==3 ) + { + buf->modelversion = 3; + rbfv3createcalcbuffer(&s->model3, &buf->bufv3, _state); + return; + } + ae_assert(ae_false, "RBFCreateCalcBuffer: integrity check failed", _state); +} + + +/************************************************************************* +This function adds dataset. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: ALGLIB version 3.11 and later allows you to specify a set of + per-dimension scales. Interpolation radii are multiplied by the + scale vector. It may be useful if you have mixed spatio-temporal + data (say, a set of 3D slices recorded at different times). + You should call rbfsetpointsandscales() function to use this + feature. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpoints(rbfmodel* s, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(n>0, "RBFSetPoints: N<=0", _state); + ae_assert(xy->rows>=n, "RBFSetPoints: Rows(XY)cols>=s->nx+s->ny, "RBFSetPoints: Cols(XY)nx+s->ny, _state), "RBFSetPoints: XY contains infinite or NaN values!", _state); + s->n = n; + s->hasscale = ae_false; + ae_matrix_set_length(&s->x, s->n, s->nx, _state); + ae_matrix_set_length(&s->y, s->n, s->ny, _state); + for(i=0; i<=s->n-1; i++) + { + for(j=0; j<=s->nx-1; j++) + { + s->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; + } + for(j=0; j<=s->ny-1; j++) + { + s->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+s->nx]; + } + } +} + + +/************************************************************************* +This function adds dataset and a vector of per-dimension scales. + +It may be useful if you have mixed spatio-temporal data - say, a set of 3D +slices recorded at different times. Such data typically require different +RBF radii for spatial and temporal dimensions. ALGLIB solves this problem +by specifying single RBF radius, which is (optionally) multiplied by the +scale vector. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: only modern RBF algorithms support variable scaling. Legacy + algorithms like RBF-ML or QNN algorithms will result in -3 + completion code being returned (incorrect algorithm). + +INPUT PARAMETERS: + R - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + S - array[NX], scale vector, S[i]>0. + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpointsandscales(rbfmodel* r, + /* Real */ const ae_matrix* xy, + ae_int_t n, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(n>0, "RBFSetPointsAndScales: N<=0", _state); + ae_assert(xy->rows>=n, "RBFSetPointsAndScales: Rows(XY)cols>=r->nx+r->ny, "RBFSetPointsAndScales: Cols(XY)cnt>=r->nx, "RBFSetPointsAndScales: Length(S)n = n; + r->hasscale = ae_true; + ae_matrix_set_length(&r->x, r->n, r->nx, _state); + ae_matrix_set_length(&r->y, r->n, r->ny, _state); + for(i=0; i<=r->n-1; i++) + { + for(j=0; j<=r->nx-1; j++) + { + r->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j]; + } + for(j=0; j<=r->ny-1; j++) + { + r->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+r->nx]; + } + } + ae_vector_set_length(&r->s, r->nx, _state); + for(i=0; i<=r->nx-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "RBFSetPointsAndScales: S[i] is not finite number", _state); + ae_assert(ae_fp_greater(s->ptr.p_double[i],(double)(0)), "RBFSetPointsAndScales: S[i]<=0", _state); + r->s.ptr.p_double[i] = s->ptr.p_double[i]; + } +} + + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state) +{ + + + ae_assert(ae_isfinite(q, _state), "RBFSetAlgoQNN: Q is infinite or NAN", _state); + ae_assert(ae_fp_greater(q,(double)(0)), "RBFSetAlgoQNN: Q<=0", _state); + ae_assert(ae_isfinite(z, _state), "RBFSetAlgoQNN: Z is infinite or NAN", _state); + ae_assert(ae_fp_greater(z,(double)(0)), "RBFSetAlgoQNN: Z<=0", _state); + s->radvalue = q; + s->radzvalue = z; + s->algorithmtype = 1; +} + + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 02.03.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultilayer(rbfmodel* s, + double rbase, + ae_int_t nlayers, + double lambdav, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoMultiLayer: RBase is infinite or NaN", _state); + ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoMultiLayer: RBase<=0", _state); + ae_assert(nlayers>=0, "RBFSetAlgoMultiLayer: NLayers<0", _state); + ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiLayer: LambdaV is infinite or NAN", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiLayer: LambdaV<0", _state); + s->radvalue = rbase; + s->nlayers = nlayers; + s->algorithmtype = 2; + s->lambdav = lambdav; +} + + +/************************************************************************* +This function chooses HRBF solver, a 2nd version of ALGLIB RBFs. + +This algorithm is called Hierarchical RBF. It similar to its previous +incarnation, RBF-ML, i.e. it also builds a sequence of models with +decreasing radii. However, it uses more economical way of building upper +layers (ones with large radii), which results in faster model construction +and evaluation, as well as smaller memory footprint during construction. + +This algorithm has following important features: +* ability to handle millions of points +* controllable smoothing via nonlinearity penalization +* support for specification of per-dimensional radii via scale vector, + which is set by means of rbfsetpointsandscales() function. This feature + is useful if you solve spatio-temporal interpolation problems, where + different radii are required for spatial and temporal dimensions. + +Running times are roughly proportional to: +* N*log(N)*NLayers - for the model construction +* N*NLayers - for the model evaluation +You may see that running time does not depend on search radius or points +density, just on the number of layers in the hierarchy. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + RBase - RBase parameter, RBase>0 + NLayers - NLayers parameter, NLayers>0, recommended value to start + with - about 5. + LambdaNS- >=0, nonlinearity penalty coefficient, negative values are + not allowed. This parameter adds controllable smoothing to + the problem, which may reduce noise. Specification of non- + zero lambda means that in addition to fitting error solver + will also minimize LambdaNS*|S''(x)|^2 (appropriately + generalized to multiple dimensions. + + Specification of exactly zero value means that no penalty + is added (we do not even evaluate matrix of second + derivatives which is necessary for smoothing). + + Calculation of nonlinearity penalty is costly - it results + in several-fold increase of model construction time. + Evaluation time remains the same. + + Optimal lambda is problem-dependent and requires trial + and error. Good value to start from is 1e-5...1e-6, + which corresponds to slightly noticeable smoothing of the + function. Value 1e-2 usually means that quite heavy + smoothing is applied. + +TUNING ALGORITHM + +In order to use this algorithm you have to choose three parameters: +* initial radius RBase +* number of layers in the model NLayers +* penalty coefficient LambdaNS + +Initial radius is easy to choose - you can pick any number several times +larger than the average distance between points. Algorithm won't break +down if you choose radius which is too large (model construction time will +increase, but model will be built correctly). + +Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used +by the last layer) will be smaller than the typical distance between +points. In case model error is too large, you can increase number of +layers. Having more layers will make model construction and evaluation +proportionally slower, but it will allow you to have model which precisely +fits your data. From the other side, if you want to suppress noise, you +can DECREASE number of layers to make your model less flexible (or specify +non-zero LambdaNS). + +TYPICAL ERRORS + +1. Using too small number of layers - RBF models with large radius are not + flexible enough to reproduce small variations in the target function. + You need many layers with different radii, from large to small, in + order to have good model. + +2. Using initial radius which is too small. You will get model with + "holes" in the areas which are too far away from interpolation centers. + However, algorithm will work correctly (and quickly) in this case. + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgohierarchical(rbfmodel* s, + double rbase, + ae_int_t nlayers, + double lambdans, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoHierarchical: RBase is infinite or NaN", _state); + ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoHierarchical: RBase<=0", _state); + ae_assert(nlayers>=0, "RBFSetAlgoHierarchical: NLayers<0", _state); + ae_assert(ae_isfinite(lambdans, _state)&&ae_fp_greater_eq(lambdans,(double)(0)), "RBFSetAlgoHierarchical: LambdaNS<0 or infinite", _state); + s->radvalue = rbase; + s->nlayers = nlayers; + s->algorithmtype = 3; + s->lambdav = lambdans; +} + + +/************************************************************************* +This function chooses a thin plate spline DDM-RBF solver, a fast RBF +solver with f(r)=r^2*ln(r) basis function. + +This algorithm has following important features: +* easy setup - no tunable parameters +* C1 continuous RBF model (gradient is defined everywhere, but Hessian is + undefined at nodes), high-quality interpolation +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a smoothing thin plate spline is + built, with larger LambdaV corresponding to models with + less nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgothinplatespline(rbfmodel* s, + double lambdav, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoThinPlateSpline: LambdaV is not finite number", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoThinPlateSpline: LambdaV is negative", _state); + s->algorithmtype = 4; + s->bftype = 2; + s->bfparam = (double)(0); + s->lambdav = lambdav; +} + + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with manual choice of +the scale parameter Alpha. + +This algorithm has following important features: +* C2 continuous RBF model (when Alpha>0 is used; for Alpha=0 the model is + merely C0 continuous) +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +One important point is that this algorithm includes tunable parameter +Alpha, which should be carefully chosen. Selecting too large value will +result in extremely badly conditioned problems (interpolation accuracy +may degrade up to complete breakdown) whilst selecting too small value may +produce models that are precise but nearly nonsmooth at the nodes. + +Good value to start from is mean distance between nodes. Generally, +choosing too small Alpha is better than choosing too large - in the former +case you still have model that reproduces target values at the nodes. + +In most cases, better option is to choose good Alpha automatically - it is +done by another version of the same algorithm that is activated by calling +rbfsetalgomultiquadricauto() method. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + Alpha - basis function parameter, Alpha>=0: + * Alpha>0 means that multiquadric algorithm is used which + produces C2-continuous RBF model + * Alpha=0 means that the multiquadric kernel effectively + becomes a biharmonic one: f=r. As a result, the model + becomes nonsmooth at nodes, and hence is C0 continuous + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricmanual(rbfmodel* s, + double alpha, + double lambdav, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(alpha, _state), "RBFSetAlgoMultiquadricManual: Alpha is infinite or NAN", _state); + ae_assert(ae_fp_greater_eq(alpha,(double)(0)), "RBFSetAlgoMultiquadricManual: Alpha<0", _state); + ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiquadricManual: LambdaV is not finite number", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiquadricManual: LambdaV is negative", _state); + s->algorithmtype = 4; + s->bftype = 1; + s->bfparam = alpha; + s->lambdav = lambdav; +} + + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with Alpha being +automatically determined. + +This algorithm has following important features: +* easy setup - no need to tune Alpha, good value is automatically assigned +* C2 continuous RBF model +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +This algorithm automatically selects Alpha as a mean distance to the +nearest neighbor (ignoring neighbors that are too close). + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricauto(rbfmodel* s, + double lambdav, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiquadricAuto: LambdaV is not finite number", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiquadricAuto: LambdaV is negative", _state); + s->algorithmtype = 4; + s->bftype = 1; + s->bfparam = -1.0; + s->lambdav = lambdav; +} + + +/************************************************************************* +This function chooses a biharmonic DDM-RBF solver, a fast RBF solver +with f(r)=r as a basis function. + +This algorithm has following important features: +* no tunable parameters +* C0 continuous RBF model (the model has discontinuous derivatives at the + interpolation nodes) +* fast model construction algorithm with O(N) memory and O(N*logN) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* accelerated evaluation using far field expansions (aka fast multipoles + method) is supported. See rbffastcalc() for more information. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgobiharmonic(rbfmodel* s, double lambdav, ae_state *_state) +{ + + + ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoBiharmonic: LambdaV is not finite number", _state); + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoBiharmonic: LambdaV is negative", _state); + s->algorithmtype = 4; + s->bftype = 1; + s->bfparam = (double)(0); + s->lambdav = lambdav; +} + + +/************************************************************************* +This function sets linear term (model is a sum of radial basis functions +plus linear polynomial). This function won't have effect until next call +to RBFBuildModel(). + +Using linear term is a default option and it is the best one - it provides +best convergence guarantees for all RBF model types: legacy RBF-QNN and +RBF-ML, Gaussian HRBFs and all types of DDM-RBF models. + +Other options, like constant or zero term, work for HRBFs, almost always +work for DDM-RBFs but provide no stability guarantees in the latter case +(e.g. the solver may fail on some carefully prepared problems). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetlinterm(rbfmodel* s, ae_state *_state) +{ + + + s->aterm = 1; +} + + +/************************************************************************* +This function sets constant term (model is a sum of radial basis functions +plus constant). This function won't have effect until next call to +RBFBuildModel(). + +IMPORTANT: thin plate splines require polynomial term to be linear, not + constant, in order to provide interpolation guarantees. + Although failures are exceptionally rare, some small toy + problems may result in degenerate linear systems. Thus, it is + advised to use linear term when one fits data with TPS. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetconstterm(rbfmodel* s, ae_state *_state) +{ + + + s->aterm = 2; +} + + +/************************************************************************* +This function sets zero term (model is a sum of radial basis functions +without polynomial term). This function won't have effect until next call +to RBFBuildModel(). + +IMPORTANT: only Gaussian RBFs (HRBF algorithm) provide interpolation + guarantees when no polynomial term is used. Most other RBFs, + including biharmonic splines, thin plate splines and + multiquadrics, require at least constant term (biharmonic and + multiquadric) or linear one (thin plate splines) in order to + guarantee non-degeneracy of linear systems being solved. + + Although failures are exceptionally rare, some small toy + problems still may result in degenerate linear systems. Thus,it + is advised to use constant/linear term, unless one is 100% sure + that he needs zero term. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetzeroterm(rbfmodel* s, ae_state *_state) +{ + + + s->aterm = 3; +} + + +/************************************************************************* +This function sets basis function type, which can be: +* 0 for classic Gaussian +* 1 for fast and compact bell-like basis function, which becomes exactly + zero at distance equal to 3*R (default option). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + BF - basis function type: + * 0 - classic Gaussian + * 1 - fast and compact one + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2bf(rbfmodel* s, ae_int_t bf, ae_state *_state) +{ + + + ae_assert(bf==0||bf==1, "RBFSetV2Its: BF<>0 and BF<>1", _state); + s->model2.basisfunction = bf; +} + + +/************************************************************************* +This function sets stopping criteria of the underlying linear solver for +hierarchical (version 2) RBF constructor. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + MaxIts - this criterion will stop algorithm after MaxIts iterations. + Typically a few hundreds iterations is required, with 400 + being a good default value to start experimentation. + Zero value means that default value will be selected. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2its(rbfmodel* s, ae_int_t maxits, ae_state *_state) +{ + + + ae_assert(maxits>=0, "RBFSetV2Its: MaxIts is negative", _state); + s->model2.maxits = maxits; +} + + +/************************************************************************* +This function sets support radius parameter of hierarchical (version 2) +RBF constructor. + +Hierarchical RBF model achieves great speed-up by removing from the model +excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter, +and two nodes are just 1 millimeter apart, you may remove one of them +without reducing model quality. + +Support radius parameter is used to justify which points need removal, and +which do not. If two points are less than SUPPORT_R*CUR_RADIUS units of +distance apart, one of them is removed from the model. The larger support +radius is, the faster model construction AND evaluation are. However, +too large values result in "bumpy" models. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + R - support radius coefficient, >=0. + Recommended values are [0.1,0.4] range, with 0.1 being + default value. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2supportr(rbfmodel* s, double r, ae_state *_state) +{ + + + ae_assert(ae_isfinite(r, _state), "RBFSetV2SupportR: R is not finite", _state); + ae_assert(ae_fp_greater_eq(r,(double)(0)), "RBFSetV2SupportR: R<0", _state); + s->model2.supportr = r; +} + + +/************************************************************************* +This function sets desired accuracy for a version 3 RBF model. + +As of ALGLIB 3.20.0, version 3 models include biharmonic RBFs, thin plate +splines, multiquadrics. + +Version 3 models are fit with specialized domain decomposition method +which splits problem into smaller chunks. Models with size less than +the DDM chunk size are computed nearly exactly in one step. Larger models +are built with an iterative linear solver. This function controls accuracy +of the solver. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + TOL - desired precision: + * must be non-negative + * should be somewhere between 0.001 and 0.000001 + * values higher than 0.001 make little sense - you may + lose a lot of precision with no performance gains. + * values below 1E-6 usually require too much time to converge, + so they are silenly replaced by a 1E-6 cutoff value. Thus, + zero can be used to denote 'maximum precision'. + + -- ALGLIB -- + Copyright 01.10.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv3tol(rbfmodel* s, double tol, ae_state *_state) +{ + + + ae_assert(ae_isfinite(tol, _state)&&ae_fp_greater_eq(tol,(double)(0)), "RBFSetV3TOL: TOL is negative or infinite", _state); + s->v3tol = tol; +} + + +/************************************************************************* +This function sets stopping criteria of the underlying linear solver. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + EpsOrt - orthogonality stopping criterion, EpsOrt>=0. Algorithm will + stop when ||A'*r||<=EpsOrt where A' is a transpose of the + system matrix, r is a residual vector. + Recommended value of EpsOrt is equal to 1E-6. + This criterion will stop algorithm when we have "bad fit" + situation, i.e. when we should stop in a point with large, + nonzero residual. + EpsErr - residual stopping criterion. Algorithm will stop when + ||r||<=EpsErr*||b||, where r is a residual vector, b is a + right part of the system (function values). + Recommended value of EpsErr is equal to 1E-3 or 1E-6. + This criterion will stop algorithm in a "good fit" + situation when we have near-zero residual near the desired + solution. + MaxIts - this criterion will stop algorithm after MaxIts iterations. + It should be used for debugging purposes only! + Zero MaxIts means that no limit is placed on the number of + iterations. + +We recommend to set moderate non-zero values EpsOrt and EpsErr +simultaneously. Values equal to 10E-6 are good to start with. In case you +need high performance and do not need high precision , you may decrease +EpsErr down to 0.001. However, we do not recommend decreasing EpsOrt. + +As for MaxIts, we recommend to leave it zero unless you know what you do. + +NOTE: this function has some serialization-related subtleties. We + recommend you to study serialization examples from ALGLIB Reference + Manual if you want to perform serialization of your models. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetcond(rbfmodel* s, + double epsort, + double epserr, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsort, _state)&&ae_fp_greater_eq(epsort,(double)(0)), "RBFSetCond: EpsOrt is negative, INF or NAN", _state); + ae_assert(ae_isfinite(epserr, _state)&&ae_fp_greater_eq(epserr,(double)(0)), "RBFSetCond: EpsB is negative, INF or NAN", _state); + ae_assert(maxits>=0, "RBFSetCond: MaxIts is negative", _state); + if( (ae_fp_eq(epsort,(double)(0))&&ae_fp_eq(epserr,(double)(0)))&&maxits==0 ) + { + s->epsort = rbf_eps; + s->epserr = rbf_eps; + s->maxits = 0; + } + else + { + s->epsort = epsort; + s->epserr = epserr; + s->maxits = maxits; + } +} + + +/************************************************************************* +This function builds RBF model and returns report (contains some +information which can be used for evaluation of the algorithm properties). + +Call to this function modifies RBF model by calculating its centers/radii/ +weights and saving them into RBFModel structure. Initially RBFModel +contain zero coefficients, but after call to this function we will have +coefficients which were calculated in order to fit our dataset. + +After you called this function you can call RBFCalc(), RBFGridCalc() and +other model calculation functions. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + Rep - report: + * Rep.TerminationType: + * -5 - non-distinct basis function centers were detected, + interpolation aborted; only QNN returns this + error code, other algorithms can handle non- + distinct nodes. + * -4 - nonconvergence of the internal SVD solver + * -3 incorrect model construction algorithm was chosen: + QNN or RBF-ML, combined with one of the incompatible + features: + * NX=1 or NX>3 + * points with per-dimension scales. + * 1 - successful termination + * 8 - a termination request was submitted via + rbfrequesttermination() function. + + Fields which are set only by modern RBF solvers (hierarchical + or nonnegative; older solvers like QNN and ML initialize these + fields by NANs): + * rep.rmserror - root-mean-square error at nodes + * rep.maxerror - maximum error at nodes + + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the LSQR solver + * Rep.NMV - number of matrix-vector products + * Rep.ARows - rows count for the system matrix + * Rep.ACols - columns count for the system matrix + * Rep.ANNZ - number of significantly non-zero elements + (elements above some algorithm-determined threshold) + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state) +{ + ae_frame _frame_block; + rbfv1report rep1; + rbfv2report rep2; + rbfv3report rep3; + ae_matrix x3; + ae_vector scalevec; + ae_int_t i; + ae_int_t v3bftype; + double v3bfparam; + ae_int_t curalgorithmtype; + + ae_frame_make(_state, &_frame_block); + memset(&rep1, 0, sizeof(rep1)); + memset(&rep2, 0, sizeof(rep2)); + memset(&rep3, 0, sizeof(rep3)); + memset(&x3, 0, sizeof(x3)); + memset(&scalevec, 0, sizeof(scalevec)); + _rbfreport_clear(rep); + _rbfv1report_init(&rep1, _state, ae_true); + _rbfv2report_init(&rep2, _state, ae_true); + _rbfv3report_init(&rep3, _state, ae_true); + ae_matrix_init(&x3, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&scalevec, 0, DT_REAL, _state, ae_true); + + + /* + * Clean fields prior to processing + */ + rbf_clearreportfields(rep, _state); + s->progress10000 = 0; + s->terminationrequest = ae_false; + + /* + * Autoselect algorithm + */ + v3bftype = -999; + v3bfparam = 0.0; + if( s->algorithmtype==0 ) + { + curalgorithmtype = 4; + v3bftype = 2; + v3bfparam = 0.0; + } + else + { + curalgorithmtype = s->algorithmtype; + if( s->algorithmtype==4 ) + { + v3bftype = s->bftype; + v3bfparam = s->bfparam; + } + } + + /* + * Algorithms which generate V1 models + */ + if( curalgorithmtype==1||curalgorithmtype==2 ) + { + + /* + * Perform compatibility checks + */ + if( (s->nx<2||s->nx>3)||s->hasscale ) + { + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Try to build model. + * + * NOTE: due to historical reasons RBFV1BuildModel() accepts points + * cast to 3-dimensional space, even if they are really 2-dimensional. + * So, for 2D data we have to explicitly convert them to 3D. + */ + if( s->nx==2 ) + { + + /* + * Convert data to 3D + */ + rmatrixsetlengthatleast(&x3, s->n, 3, _state); + for(i=0; i<=s->n-1; i++) + { + x3.ptr.pp_double[i][0] = s->x.ptr.pp_double[i][0]; + x3.ptr.pp_double[i][1] = s->x.ptr.pp_double[i][1]; + x3.ptr.pp_double[i][2] = (double)(0); + } + rbfv1buildmodel(&x3, &s->y, s->n, s->aterm, curalgorithmtype, s->nlayers, s->radvalue, s->radzvalue, s->lambdav, s->epsort, s->epserr, s->maxits, &s->model1, &rep1, _state); + } + else + { + + /* + * Work with raw data + */ + rbfv1buildmodel(&s->x, &s->y, s->n, s->aterm, curalgorithmtype, s->nlayers, s->radvalue, s->radzvalue, s->lambdav, s->epsort, s->epserr, s->maxits, &s->model1, &rep1, _state); + } + s->modelversion = 1; + rbfcreatecalcbuffer(s, &s->calcbuf, _state); + + /* + * Convert report fields + */ + rep->arows = rep1.arows; + rep->acols = rep1.acols; + rep->annz = rep1.annz; + rep->iterationscount = rep1.iterationscount; + rep->nmv = rep1.nmv; + rep->terminationtype = rep1.terminationtype; + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * Algorithms which generate V2 models + */ + if( curalgorithmtype==3 ) + { + + /* + * Prepare scale vector - use unit values or user supplied ones + */ + ae_vector_set_length(&scalevec, s->nx, _state); + for(i=0; i<=s->nx-1; i++) + { + if( s->hasscale ) + { + scalevec.ptr.p_double[i] = s->s.ptr.p_double[i]; + } + else + { + scalevec.ptr.p_double[i] = (double)(1); + } + } + + /* + * Build model + */ + rbfv2buildhierarchical(&s->x, &s->y, s->n, &scalevec, s->aterm, s->nlayers, s->radvalue, s->lambdav, &s->model2, &s->progress10000, &s->terminationrequest, &rep2, _state); + s->modelversion = 2; + rbfcreatecalcbuffer(s, &s->calcbuf, _state); + + /* + * Convert report fields + */ + rep->terminationtype = rep2.terminationtype; + rep->rmserror = rep2.rmserror; + rep->maxerror = rep2.maxerror; + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * Algorithms which generate DDM-RBF models + */ + if( curalgorithmtype==4 ) + { + + /* + * Prepare scale vector - use unit values or user supplied ones + */ + ae_vector_set_length(&scalevec, s->nx, _state); + for(i=0; i<=s->nx-1; i++) + { + if( s->hasscale ) + { + scalevec.ptr.p_double[i] = s->s.ptr.p_double[i]; + } + else + { + scalevec.ptr.p_double[i] = (double)(1); + } + } + + /* + * Build model + */ + rbfv3build(&s->x, &s->y, s->n, &scalevec, v3bftype, v3bfparam, s->lambdav, s->aterm, s->rbfprofile, s->v3tol, &s->model3, &s->progress10000, &s->terminationrequest, &rep3, _state); + s->modelversion = 3; + rbfcreatecalcbuffer(s, &s->calcbuf, _state); + pushfastevaltol(s, s->fastevaltol, _state); + + /* + * Convert report fields + */ + rep->iterationscount = rep3.iterationscount; + rep->terminationtype = rep3.terminationtype; + rep->rmserror = rep3.rmserror; + rep->maxerror = rep3.maxerror; + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * Critical error + */ + ae_assert(ae_false, "RBFBuildModel: integrity check failure", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates values of the 1-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: this function works only with modern (hierarchical) RBFs. It + can not be used with legacy (version 1) RBFs because older RBF + code does not support 1-dimensional models. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* the model is not initialized +* NX<>1 +* NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - X-coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc1(rbfmodel* s, double x0, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state); + result = (double)(0); + if( s->ny!=1||s->nx!=1 ) + { + return result; + } + if( s->modelversion==1 ) + { + result = (double)(0); + return result; + } + if( s->modelversion==2 ) + { + result = rbfv2calc1(&s->model2, x0, _state); + return result; + } + if( s->modelversion==3 ) + { + result = rbfv3calc1(&s->model3, x0, _state); + return result; + } + ae_assert(ae_false, "RBFCalc1: integrity check failed", _state); + return result; +} + + +/************************************************************************* +This function calculates values of the 2-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state); + result = (double)(0); + if( s->ny!=1||s->nx!=2 ) + { + return result; + } + if( s->modelversion==1 ) + { + result = rbfv1calc2(&s->model1, x0, x1, _state); + return result; + } + if( s->modelversion==2 ) + { + result = rbfv2calc2(&s->model2, x0, x1, _state); + return result; + } + if( s->modelversion==3 ) + { + result = rbfv3calc2(&s->model3, x0, x1, _state); + return result; + } + ae_assert(ae_false, "RBFCalc2: integrity check failed", _state); + return result; +} + + +/************************************************************************* +This function calculates values of the 3-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc3(rbfmodel* s, + double x0, + double x1, + double x2, + ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state); + result = (double)(0); + if( s->ny!=1||s->nx!=3 ) + { + return result; + } + if( s->modelversion==1 ) + { + result = rbfv1calc3(&s->model1, x0, x1, x2, _state); + return result; + } + if( s->modelversion==2 ) + { + result = rbfv2calc3(&s->model2, x0, x1, x2, _state); + return result; + } + if( s->modelversion==3 ) + { + result = rbfv3calc3(&s->model3, x0, x1, x2, _state); + return result; + } + ae_assert(ae_false, "RBFCalc3: integrity check failed", _state); + return result; +} + + +/************************************************************************* +This function calculates value and derivatives of the 1-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>1 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff1(rbfmodel* s, + double x0, + double* y, + double* dy0, + ae_state *_state) +{ + + *y = 0.0; + *dy0 = 0.0; + + ae_assert(ae_isfinite(x0, _state), "RBFDiff1: invalid value for X0 (X0 is Inf or NaN)!", _state); + *y = (double)(0); + *dy0 = (double)(0); + if( s->ny!=1||s->nx!=1 ) + { + return; + } + rallocv(1, &s->calcbuf.x, _state); + s->calcbuf.x.ptr.p_double[0] = x0; + rbftsdiffbuf(s, &s->calcbuf, &s->calcbuf.x, &s->calcbuf.y, &s->calcbuf.dy, _state); + *y = s->calcbuf.y.ptr.p_double[0]; + *dy0 = s->calcbuf.dy.ptr.p_double[0]; +} + + +/************************************************************************* +This function calculates value and derivatives of the 2-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>2 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff2(rbfmodel* s, + double x0, + double x1, + double* y, + double* dy0, + double* dy1, + ae_state *_state) +{ + + *y = 0.0; + *dy0 = 0.0; + *dy1 = 0.0; + + ae_assert(ae_isfinite(x0, _state), "RBFDiff2: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFDiff2: invalid value for X1 (X1 is Inf or NaN)!", _state); + *y = (double)(0); + *dy0 = (double)(0); + *dy1 = (double)(0); + if( s->ny!=1||s->nx!=2 ) + { + return; + } + rallocv(2, &s->calcbuf.x, _state); + s->calcbuf.x.ptr.p_double[0] = x0; + s->calcbuf.x.ptr.p_double[1] = x1; + rbftsdiffbuf(s, &s->calcbuf, &s->calcbuf.x, &s->calcbuf.y, &s->calcbuf.dy, _state); + *y = s->calcbuf.y.ptr.p_double[0]; + *dy0 = s->calcbuf.dy.ptr.p_double[0]; + *dy1 = s->calcbuf.dy.ptr.p_double[1]; +} + + +/************************************************************************* +This function calculates value and derivatives of the 3-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>3 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + DY2 - derivative with respect to X2 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff3(rbfmodel* s, + double x0, + double x1, + double x2, + double* y, + double* dy0, + double* dy1, + double* dy2, + ae_state *_state) +{ + + *y = 0.0; + *dy0 = 0.0; + *dy1 = 0.0; + *dy2 = 0.0; + + ae_assert(ae_isfinite(x0, _state), "RBFDiff3: invalid value for X0 (X0 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x1, _state), "RBFDiff3: invalid value for X1 (X1 is Inf or NaN)!", _state); + ae_assert(ae_isfinite(x2, _state), "RBFDiff3: invalid value for X2 (X2 is Inf or NaN)!", _state); + *y = (double)(0); + *dy0 = (double)(0); + *dy1 = (double)(0); + *dy2 = (double)(0); + if( s->ny!=1||s->nx!=3 ) + { + return; + } + rallocv(3, &s->calcbuf.x, _state); + s->calcbuf.x.ptr.p_double[0] = x0; + s->calcbuf.x.ptr.p_double[1] = x1; + s->calcbuf.x.ptr.p_double[2] = x2; + rbftsdiffbuf(s, &s->calcbuf, &s->calcbuf.x, &s->calcbuf.y, &s->calcbuf.dy, _state); + *y = s->calcbuf.y.ptr.p_double[0]; + *dy0 = s->calcbuf.dy.ptr.p_double[0]; + *dy1 = s->calcbuf.dy.ptr.p_double[1]; + *dy2 = s->calcbuf.dy.ptr.p_double[2]; +} + + +/************************************************************************* +This function sets absolute accuracy of a fast evaluation algorithm used +by rbffastcalc() and other fast evaluation functions. + +A fast evaluation algorithm is model-dependent and is available only for +some RBF models. Usually it utilizes far field expansions (a generalization +of the fast multipoles method). If no approximate fast evaluator is +available for the current RBF model type, this function has no effect. + +NOTE: this function can be called before or after the model was built. The + result will be the same. + +NOTE: this function has O(N) running time, where N is a points count. + Most fast evaluators work by aggregating influence of point groups, + i.e. by computing so called far field. Changing evaluator tolerance + means that far field radii have to be recomputed for each point + cluster, and we have O(N) such clusters. + + This function is still very fast, but it should not be called too + often, e.g. every time you call rbffastcalc() in a loop. + +NOTE: the tolerance set by this function is an accuracy of an evaluator + which computes the value of the model. It is NOT accuracy of the + model itself. + + E.g., if you set evaluation accuracy to 1E-12, the model value will + be computed with required precision. However, the model itself is an + approximation of the target (the default requirement is to fit model + with ~6 digits of precision) and THIS accuracy can not be changed + after the model was built. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. Calling it while another thread + tries to use rbffastcalc() is unsafe because it means that the + accuracy requirements will change in the middle of computations. + The algorithm may behave unpredictably. + +INPUT PARAMETERS: + S - RBF model + TOL - TOL>0, desired evaluation tolerance: + * should be somewhere between 1E-3 and 1E-6 + * values outside of this range will cause no problems (the + evaluator will do the job anyway). However, too strict + precision requirements may mean that no approximation + speed-up will be achieved. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetfastevaltol(rbfmodel* s, double tol, ae_state *_state) +{ + + + ae_assert(ae_isfinite(tol, _state), "RBFSetFastEvalTol: TOL is not a finite number", _state); + ae_assert(ae_fp_greater(tol,(double)(0)), "RBFSetFastEvalTol: TOL<=0", _state); + s->fastevaltol = tol; + pushfastevaltol(s, tol, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point using +a fast approximate algorithm whenever possible. If no fast algorithm is +available for a given model type, traditional O(N) approach is used. + +Presently, fast evaluation is implemented only for biharmonic splines. + +The absolute approximation accuracy is controlled by the rbfsetfastevaltol() +function. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with a per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbffastcalc(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(y); + + ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)nx, _state), "RBFCalc: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1calcbuf(&s->model1, x, y, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2calcbuf(&s->model2, x, y, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3tsfastcalcbuf(&s->model3, &s->model3.calcbuf, x, y, _state); + return; + } + ae_assert(ae_false, "RBFCalcBuf: integrity check failed", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use rbfcalc2() or +rbfcalc3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfcalc(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + + ae_vector_clear(y); + + ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)nx, _state), "RBFCalc: X contains infinite or NaN values", _state); + rbfcalcbuf(s, x, y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its derivatives at +the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +if you have NX=3 and NY=1, you may find more convenient to use rbfdiff3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftsdiffbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFDiffBuf(), + which reallocates Y only when it is too small. + DY - derivatives, array[NX*NY]: + * Y[I*NX+J] with 0<=Icnt>=s->nx, "RBFDiff: Length(X)nx, _state), "RBFDiff: X contains infinite or NaN values", _state); + rbfdiffbuf(s, x, y, dy, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its first and second +derivatives (Hessian matrix) at the given point. + +This function supports both scalar (NY=1) and vector-valued (NY>1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + Y is out-parameter and reallocated after call to this + function. In case you want to reuse previously allocated + Y, you may use RBFHessBuf(), which reallocates Y only when + it is too small. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=Kcnt>=s->nx, "RBFHess: Length(X)nx, _state), "RBFHess: X contains infinite or NaN values", _state); + rbftshessbuf(s, &s->calcbuf, x, y, dy, d2y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +Same as rbfcalc(), but does not reallocate Y when in is large enough to +store function values. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfcalcbuf(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1calcbuf(&s->model1, x, y, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2calcbuf(&s->model2, x, y, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3calcbuf(&s->model3, x, y, _state); + return; + } + ae_assert(ae_false, "RBFCalcBuf: integrity check failed", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its derivatives at +the given point. It is a buffered version of the RBFDiff() which tries to +reuse possibly preallocated output arrays Y/DY as much as possible. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +if you have NX=1, 2 or 3 and NY=1, you may find more convenient to use +rbfdiff1(), rbfdiff2() or rbfdiff3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftsdiffbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY - possibly preallocated arrays; if array size is large enough + to store results, this function does not reallocate array + to fit output size exactly. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - derivatives, array[NX*NY]: + * Y[I*NX+J] with 0<=Icnt>=s->nx, "RBFDiffBuf: Length(X)nx, _state), "RBFDiffBuf: X contains infinite or NaN values", _state); + ae_assert(s->modelversion==s->calcbuf.modelversion, "RBF: integrity check 3945 failed", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=s->ny*s->nx-1; i++) + { + dy->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1tsdiffbuf(&s->model1, &s->calcbuf.bufv1, x, y, dy, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2tsdiffbuf(&s->model2, &s->calcbuf.bufv2, x, y, dy, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3tsdiffbuf(&s->model3, &s->calcbuf.bufv3, x, y, dy, _state); + return; + } + ae_assert(ae_false, "RBFDiffBuf: integrity check failed", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its first and second +derivatives (Hessian matrix) at the given point. It is a buffered version +that reuses memory allocated in output buffers Y/DY/D2Y as much as +possible. + +This function supports both scalar (NY=1) and vector-valued (NY>1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y- possible preallocated output arrays. If these arrays are + smaller than required to store the result, they are + automatically reallocated. If array is large enough, it is + not resized. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=Kcnt>=s->nx, "RBFHess: Length(X)nx, _state), "RBFHess: X contains infinite or NaN values", _state); + rbftshessbuf(s, &s->calcbuf, x, y, dy, d2y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the given point, using +external buffer object (internal temporaries of RBF model are not +modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of buffer +structure. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbftscalcbuf(const rbfmodel* s, + rbfcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state); + ae_assert(s->modelversion==buf->modelversion, "RBFCalcBuf: buffer object is not compatible with RBF model", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1tscalcbuf(&s->model1, &buf->bufv1, x, y, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2tscalcbuf(&s->model2, &buf->bufv2, x, y, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3tscalcbuf(&s->model3, &buf->bufv3, x, y, _state); + return; + } + ae_assert(ae_false, "RBFTsCalcBuf: integrity check failed", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its derivatives at +the given point, using external buffer object (internal temporaries of the +RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of the buffer +structure. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y, DY - possibly preallocated arrays; if array size is large enough + to store results, this function does not reallocate array + to fit output size exactly. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - derivatives, array[NX*NY]: + * Y[I*NX+J] with 0<=Icnt>=s->nx, "RBFTsDiffBuf: Length(X)nx, _state), "RBFTsDiffBuf: X contains infinite or NaN values", _state); + ae_assert(s->modelversion==buf->modelversion, "RBFTsDiffBuf: integrity check 3985 failed", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=s->ny*s->nx-1; i++) + { + dy->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1tsdiffbuf(&s->model1, &buf->bufv1, x, y, dy, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2tsdiffbuf(&s->model2, &buf->bufv2, x, y, dy, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3tsdiffbuf(&s->model3, &buf->bufv3, x, y, dy, _state); + return; + } + ae_assert(ae_false, "RBFDiffBuf: integrity check failed", _state); +} + + +/************************************************************************* +This function calculates values of the RBF model and its first and second +derivatives (Hessian matrix) at the given point, using external buffer +object (internal temporaries of the RBF model are not modified). + +This function allows to use same RBF model object in different threads, +assuming that different threads use different instances of the buffer +structure. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model, may be shared between different threads + Buf - buffer object created for this particular instance of RBF + model with rbfcreatecalcbuffer(). + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y- possible preallocated output arrays. If these arrays are + smaller than required to store the result, they are + automatically reallocated. If array is large enough, it is + not resized. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=Kcnt>=s->nx, "RBFTsHessBuf: Length(X)nx, _state), "RBFTsHessBuf: X contains infinite or NaN values", _state); + ae_assert(s->modelversion==buf->modelversion, "RBFTsHessBuf: integrity check 3953 failed", _state); + if( y->cntny ) + { + ae_vector_set_length(y, s->ny, _state); + } + if( dy->cntny*s->nx ) + { + ae_vector_set_length(dy, s->ny*s->nx, _state); + } + if( d2y->cntny*s->nx*s->nx ) + { + ae_vector_set_length(d2y, s->ny*s->nx*s->nx, _state); + } + for(i=0; i<=s->ny-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=s->ny*s->nx-1; i++) + { + dy->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=s->ny*s->nx*s->nx-1; i++) + { + d2y->ptr.p_double[i] = (double)(0); + } + if( s->modelversion==1 ) + { + rbfv1tshessbuf(&s->model1, &buf->bufv1, x, y, dy, d2y, _state); + return; + } + if( s->modelversion==2 ) + { + rbfv2tshessbuf(&s->model2, &buf->bufv2, x, y, dy, d2y, _state); + return; + } + if( s->modelversion==3 ) + { + rbfv3tshessbuf(&s->model3, &buf->bufv3, x, y, dy, d2y, _state); + return; + } + ae_assert(ae_false, "RBFDiffBuf: integrity check failed", _state); +} + + +/************************************************************************* +This is legacy function for gridded calculation of RBF model. + +It is superseded by rbfgridcalc2v() and rbfgridcalc2vsubset() functions. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2(rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector yy; + + ae_frame_make(_state, &_frame_block); + memset(&yy, 0, sizeof(yy)); + ae_matrix_clear(y); + ae_vector_init(&yy, 0, DT_REAL, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)cnt>=n1, "RBFGridCalc2: Length(X1)modelversion==1 ) + { + rbfv1gridcalc2(&s->model1, x0, n0, x1, n1, y, _state); + ae_frame_leave(_state); + return; + } + if( s->modelversion==2 ) + { + rbfv2gridcalc2(&s->model2, x0, n0, x1, n1, y, _state); + ae_frame_leave(_state); + return; + } + if( s->modelversion==3 ) + { + rallocm(n0, n1, y, _state); + if( s->nx!=2||s->ny!=1 ) + { + rsetm(n0, n1, 0.0, y, _state); + ae_frame_leave(_state); + return; + } + rbfgridcalc2v(s, x0, n0, x1, n1, &yy, _state); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + y->ptr.pp_double[i][j] = yy.ptr.p_double[i+j*n0]; + } + } + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "RBFGridCalc2: integrity check failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the regular grid, +which has N0*N1 points, with Point[I,J] = (X0[I], X1[J]). Vector-valued +RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 27.01.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2v(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector dummy; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_clear(y); + ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc2V: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2V: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2V: Length(X0)cnt>=n1, "RBFGridCalc2V: Length(X1)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2V: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2V: X1 is not ordered by ascending", _state); + } + rbfgridcalc2vx(s, x0, n0, x1, n1, &dummy, ae_false, y, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2vsubset(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(y); + + ae_assert(n0>0, "RBFGridCalc2VSubset: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2VSubset: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2VSubset: Length(X0)cnt>=n1, "RBFGridCalc2VSubset: Length(X1)cnt>=n0*n1, "RBFGridCalc2VSubset: Length(FlagY)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2VSubset: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2VSubset: X1 is not ordered by ascending", _state); + } + rbfgridcalc2vx(s, x0, n0, x1, n1, flagy, ae_true, y, _state); +} + + +/************************************************************************* +This function calculates values of the RBF model at the regular grid, +which has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]). +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + * I2=0...N2-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc3vsubset(). + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3v(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector dummy; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_clear(y); + ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state); + ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)cnt>=n1, "RBFGridCalc3V: Length(X1)cnt>=n2, "RBFGridCalc3V: Length(X2)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3V: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3V: X1 is not ordered by ascending", _state); + } + for(i=0; i<=n2-2; i++) + { + ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3V: X2 is not ordered by ascending", _state); + } + rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, &dummy, ae_false, y, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + + FlagY - array[N0*N1*N2]: + * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3vsubset(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(y); + + ae_assert(n0>0, "RBFGridCalc3VSubset: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc3VSubset: invalid value for N1 (N1<=0)!", _state); + ae_assert(n2>0, "RBFGridCalc3VSubset: invalid value for N2 (N2<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc3VSubset: Length(X0)cnt>=n1, "RBFGridCalc3VSubset: Length(X1)cnt>=n2, "RBFGridCalc3VSubset: Length(X2)cnt>=n0*n1*n2, "RBFGridCalc3VSubset: Length(FlagY)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X1 is not ordered by ascending", _state); + } + for(i=0; i<=n2-2; i++) + { + ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X2 is not ordered by ascending", _state); + } + rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, flagy, ae_true, y, _state); +} + + +/************************************************************************* +This function, depending on SparseY, acts as RBFGridCalc2V (SparseY=False) +or RBFGridCalc2VSubset (SparseY=True) function. See comments for these +functions for more information + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2vx(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t ny; + ae_int_t ylen; + hqrndstate rs; + ae_vector dummyx2; + ae_vector dummyx3; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t l; + ae_vector tx; + ae_vector ty; + ae_int_t dstoffs; + rbfcalcbuffer calcbuf; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + memset(&dummyx2, 0, sizeof(dummyx2)); + memset(&dummyx3, 0, sizeof(dummyx3)); + memset(&tx, 0, sizeof(tx)); + memset(&ty, 0, sizeof(ty)); + memset(&calcbuf, 0, sizeof(calcbuf)); + _hqrndstate_init(&rs, _state, ae_true); + ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ty, 0, DT_REAL, _state, ae_true); + _rbfcalcbuffer_init(&calcbuf, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc2VX: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc2VX: invalid value for N1 (N1<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc2VX: Length(X0)cnt>=n1, "RBFGridCalc2VX: Length(X1)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2VX: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2VX: X1 is not ordered by ascending", _state); + } + + /* + * Prepare local variables + */ + nx = s->nx; + ny = s->ny; + hqrndseed(325, 46345, &rs, _state); + + /* + * Prepare output array + */ + ylen = ny*n0*n1; + ae_vector_set_length(y, ylen, _state); + for(i=0; i<=ylen-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->nx!=2 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Reference code for V3 models + */ + if( s->modelversion==3 ) + { + ae_vector_set_length(&dummyx2, 1, _state); + dummyx2.ptr.p_double[0] = (double)(0); + ae_vector_set_length(&dummyx3, 1, _state); + dummyx3.ptr.p_double[0] = (double)(0); + rbfv3gridcalcvx(&s->model3, x0, n0, x1, n1, &dummyx2, 1, &dummyx3, 1, flagy, sparsey, y, _state); + ae_frame_leave(_state); + return; + } + + /* + * Process V2 model + */ + if( s->modelversion==2 ) + { + ae_vector_set_length(&dummyx2, 1, _state); + dummyx2.ptr.p_double[0] = (double)(0); + ae_vector_set_length(&dummyx3, 1, _state); + dummyx3.ptr.p_double[0] = (double)(0); + rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, &dummyx2, 1, &dummyx3, 1, flagy, sparsey, y, _state); + ae_frame_leave(_state); + return; + } + + /* + * Reference code for V1 models + */ + if( s->modelversion==1 ) + { + ae_vector_set_length(&tx, nx, _state); + rbfcreatecalcbuffer(s, &calcbuf, _state); + for(i=0; i<=n0-1; i++) + { + for(j=0; j<=n1-1; j++) + { + k = i+j*n0; + dstoffs = ny*k; + if( sparsey&&!flagy->ptr.p_bool[k] ) + { + for(l=0; l<=ny-1; l++) + { + y->ptr.p_double[l+dstoffs] = (double)(0); + } + continue; + } + tx.ptr.p_double[0] = x0->ptr.p_double[i]; + tx.ptr.p_double[1] = x1->ptr.p_double[j]; + rbftscalcbuf(s, &calcbuf, &tx, &ty, _state); + for(l=0; l<=ny-1; l++) + { + y->ptr.p_double[l+dstoffs] = ty.ptr.p_double[l]; + } + } + } + ae_frame_leave(_state); + return; + } + + /* + * Unknown model + */ + ae_assert(ae_false, "RBFGridCalc2VX: integrity check failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function, depending on SparseY, acts as RBFGridCalc3V (SparseY=False) +or RBFGridCalc3VSubset (SparseY=True) function. See comments for these +functions for more information + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3vx(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t ylen; + ae_int_t nx; + ae_int_t ny; + double rmax; + ae_vector blocks0; + ae_vector blocks1; + ae_vector blocks2; + ae_int_t blockscnt0; + ae_int_t blockscnt1; + ae_int_t blockscnt2; + double blockwidth; + double searchradius; + double avgfuncpernode; + ae_int_t ntrials; + ae_int_t maxblocksize; + gridcalc3v1buf bufseedv1; + ae_shared_pool bufpool; + hqrndstate rs; + ae_vector dummyx3; + + ae_frame_make(_state, &_frame_block); + memset(&blocks0, 0, sizeof(blocks0)); + memset(&blocks1, 0, sizeof(blocks1)); + memset(&blocks2, 0, sizeof(blocks2)); + memset(&bufseedv1, 0, sizeof(bufseedv1)); + memset(&bufpool, 0, sizeof(bufpool)); + memset(&rs, 0, sizeof(rs)); + memset(&dummyx3, 0, sizeof(dummyx3)); + ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true); + ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true); + ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true); + _gridcalc3v1buf_init(&bufseedv1, _state, ae_true); + ae_shared_pool_init(&bufpool, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true); + + ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state); + ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state); + ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state); + ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)cnt>=n1, "RBFGridCalc3V: Length(X1)cnt>=n2, "RBFGridCalc3V: Length(X2)ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3V: X0 is not ordered by ascending", _state); + } + for(i=0; i<=n1-2; i++) + { + ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3V: X1 is not ordered by ascending", _state); + } + for(i=0; i<=n2-2; i++) + { + ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3V: X2 is not ordered by ascending", _state); + } + + /* + * Prepare local variables + */ + nx = s->nx; + ny = s->ny; + hqrndseed(325, 46345, &rs, _state); + + /* + * Prepare output array + */ + ylen = ny*n0*n1*n2; + ae_vector_set_length(y, ylen, _state); + for(i=0; i<=ylen-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->nx!=3 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Process V1 model + */ + if( s->modelversion==1 ) + { + + /* + * Fast exit for models without centers + */ + if( s->model1.nc==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Prepare seed, create shared pool of temporary buffers + */ + ae_vector_set_length(&bufseedv1.cx, nx, _state); + ae_vector_set_length(&bufseedv1.tx, nx, _state); + ae_vector_set_length(&bufseedv1.ty, ny, _state); + ae_vector_set_length(&bufseedv1.expbuf0, n0, _state); + ae_vector_set_length(&bufseedv1.expbuf1, n1, _state); + ae_vector_set_length(&bufseedv1.expbuf2, n2, _state); + kdtreecreaterequestbuffer(&s->model1.tree, &bufseedv1.requestbuf, _state); + ae_shared_pool_set_seed(&bufpool, &bufseedv1, (ae_int_t)sizeof(bufseedv1), (ae_copy_constructor)_gridcalc3v1buf_init_copy, (ae_destructor)_gridcalc3v1buf_destroy, _state); + + /* + * Analyze input grid: + * * analyze average number of basis functions per grid node + * * partition grid in into blocks + */ + rmax = s->model1.rmax; + blockwidth = (double)2*rmax; + maxblocksize = 8; + searchradius = rmax*rbf_rbffarradius+0.5*ae_sqrt((double)(s->nx), _state)*blockwidth; + ntrials = 100; + avgfuncpernode = 0.0; + for(i=0; i<=ntrials-1; i++) + { + bufseedv1.tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)]; + bufseedv1.tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)]; + bufseedv1.tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)]; + avgfuncpernode = avgfuncpernode+(double)kdtreetsqueryrnn(&s->model1.tree, &bufseedv1.requestbuf, &bufseedv1.tx, searchradius, ae_true, _state)/(double)ntrials; + } + ae_vector_set_length(&blocks0, n0+1, _state); + blockscnt0 = 0; + blocks0.ptr.p_int[0] = 0; + for(i=1; i<=n0-1; i++) + { + if( ae_fp_greater(x0->ptr.p_double[i]-x0->ptr.p_double[blocks0.ptr.p_int[blockscnt0]],blockwidth)||i-blocks0.ptr.p_int[blockscnt0]>=maxblocksize ) + { + inc(&blockscnt0, _state); + blocks0.ptr.p_int[blockscnt0] = i; + } + } + inc(&blockscnt0, _state); + blocks0.ptr.p_int[blockscnt0] = n0; + ae_vector_set_length(&blocks1, n1+1, _state); + blockscnt1 = 0; + blocks1.ptr.p_int[0] = 0; + for(i=1; i<=n1-1; i++) + { + if( ae_fp_greater(x1->ptr.p_double[i]-x1->ptr.p_double[blocks1.ptr.p_int[blockscnt1]],blockwidth)||i-blocks1.ptr.p_int[blockscnt1]>=maxblocksize ) + { + inc(&blockscnt1, _state); + blocks1.ptr.p_int[blockscnt1] = i; + } + } + inc(&blockscnt1, _state); + blocks1.ptr.p_int[blockscnt1] = n1; + ae_vector_set_length(&blocks2, n2+1, _state); + blockscnt2 = 0; + blocks2.ptr.p_int[0] = 0; + for(i=1; i<=n2-1; i++) + { + if( ae_fp_greater(x2->ptr.p_double[i]-x2->ptr.p_double[blocks2.ptr.p_int[blockscnt2]],blockwidth)||i-blocks2.ptr.p_int[blockscnt2]>=maxblocksize ) + { + inc(&blockscnt2, _state); + blocks2.ptr.p_int[blockscnt2] = i; + } + } + inc(&blockscnt2, _state); + blocks2.ptr.p_int[blockscnt2] = n2; + + /* + * Perform calculation in multithreaded mode + */ + rbfv1gridcalc3vrec(&s->model1, x0, n0, x1, n1, x2, n2, &blocks0, 0, blockscnt0, &blocks1, 0, blockscnt1, &blocks2, 0, blockscnt2, flagy, sparsey, searchradius, avgfuncpernode, &bufpool, y, _state); + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * Process V2 model + */ + if( s->modelversion==2 ) + { + ae_vector_set_length(&dummyx3, 1, _state); + dummyx3.ptr.p_double[0] = (double)(0); + rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, x2, n2, &dummyx3, 1, flagy, sparsey, y, _state); + ae_frame_leave(_state); + return; + } + + /* + * Process V3 model + */ + if( s->modelversion==3 ) + { + ae_vector_set_length(&dummyx3, 1, _state); + dummyx3.ptr.p_double[0] = (double)(0); + rbfv3gridcalcvx(&s->model3, x0, n0, x1, n1, x2, n2, &dummyx3, 1, flagy, sparsey, y, _state); + ae_frame_leave(_state); + return; + } + + /* + * Unknown model + */ + ae_assert(ae_false, "RBFGridCalc3VX: integrity check failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information , 2D array. One row of the array + corresponds to one basis function. + + For ModelVersion=1 we have NX+NY+1 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last column - radius, same for all dimensions of + the function being modeled + + For ModelVersion=2 we have NX+NY+NX columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last NX columns - radii, one per dimension + + For ModelVersion=3 we have NX+NY+NX+3 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * next NX columns - radii, one per dimension + * next column - basis function type: + * 1 for f=r + * 2 for f=r^2*ln(r) + * 10 for multiquadric f=sqrt(r^2+alpha^2) + * next column - basis function parameter: + * alpha, for basis function type 10 + * ignored (zero) for other basis function types + * next column - point index in the original dataset, + or -1 for an artificial node created + by the solver. The algorithm may reorder + the nodes, drop some nodes or add + artificial nodes. Thus, one parsing + this column should expect all these + kinds of alterations in the dataset. + + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + ModelVersion-version of the RBF model: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + * 3 - for models created by DDM-RBF, requires + ALGLIB 3.19 or later + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfunpack(rbfmodel* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_int_t* modelversion, + ae_state *_state) +{ + + *nx = 0; + *ny = 0; + ae_matrix_clear(xwr); + *nc = 0; + ae_matrix_clear(v); + *modelversion = 0; + + if( s->modelversion==1 ) + { + *modelversion = 1; + rbfv1unpack(&s->model1, nx, ny, xwr, nc, v, _state); + return; + } + if( s->modelversion==2 ) + { + *modelversion = 2; + rbfv2unpack(&s->model2, nx, ny, xwr, nc, v, _state); + return; + } + if( s->modelversion==3 ) + { + *modelversion = 3; + rbfv3unpack(&s->model3, nx, ny, xwr, nc, v, _state); + return; + } + ae_assert(ae_false, "RBFUnpack: integrity check failure", _state); +} + + +/************************************************************************* +This function returns model version. + +INPUT PARAMETERS: + S - RBF model + +RESULT: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + + -- ALGLIB -- + Copyright 06.07.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t rbfgetmodelversion(rbfmodel* s, ae_state *_state) +{ + ae_int_t result; + + + result = s->modelversion; + return result; +} + + +/************************************************************************* +This function is used to peek into hierarchical RBF construction process +from some other thread and get current progress indicator. It returns +value in [0,1]. + +IMPORTANT: only HRBFs (hierarchical RBFs) support peeking into progress + indicator. Legacy RBF-ML and RBF-QNN do not support it. You + will always get 0 value. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +double rbfpeekprogress(const rbfmodel* s, ae_state *_state) +{ + double result; + + + result = (double)s->progress10000/(double)10000; + return result; +} + + +/************************************************************************* +This function is used to submit a request for termination of the +hierarchical RBF construction process from some other thread. As result, +RBF construction is terminated smoothly (with proper deallocation of all +necessary resources) and resultant model is filled by zeros. + +A rep.terminationtype=8 will be returned upon receiving such request. + +IMPORTANT: only HRBFs (hierarchical RBFs) support termination requests. + Legacy RBF-ML and RBF-QNN do not support it. An attempt to + terminate their construction will be ignored. + +IMPORTANT: termination request flag is cleared when the model construction + starts. Thus, any pre-construction termination requests will be + silently ignored - only ones submitted AFTER construction has + actually began will be handled. + +INPUT PARAMETERS: + S - RBF model object + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +void rbfrequesttermination(rbfmodel* s, ae_state *_state) +{ + + + s->terminationrequest = ae_true; +} + + +/************************************************************************* +This function sets RBF profile to standard or debug + +INPUT PARAMETERS: + S - RBF model object + P - profile type: + * 0 for standard + * -1 for debug + * -2 for debug with artificially worsened numerical + precision. This profile is designed to test algorithm + ability to deal with difficult problems, + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +void rbfsetprofile(rbfmodel* s, ae_int_t p, ae_state *_state) +{ + + + ae_assert((p==-2||p==-1)||p==0, "RBFSetProfile: incorrect P", _state); + s->rbfprofile = p; +} + + +/************************************************************************* +This function changes evaluation tolerance of a fast evaluator (if present). +It is an actual implementation that is used by RBFSetFastEvalTol(). + +It usually has O(N) running time because evaluator has to be rebuilt according +to the new tolerance. + +INPUT PARAMETERS: + S - RBF model object + TOL - desired tolerance + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void pushfastevaltol(rbfmodel* s, double tol, ae_state *_state) +{ + + + if( s->modelversion!=3 ) + { + return; + } + rbf3pushfastevaltol(&s->model3, tol, _state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfalloc(ae_serializer* s, const rbfmodel* model, ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_alloc_entry(s); + + /* + * V1 model + */ + if( model->modelversion==1 ) + { + + /* + * Header + */ + ae_serializer_alloc_entry(s); + rbfv1alloc(s, &model->model1, _state); + return; + } + + /* + * V2 model + */ + if( model->modelversion==2 ) + { + + /* + * Header + */ + ae_serializer_alloc_entry(s); + rbfv2alloc(s, &model->model2, _state); + return; + } + + /* + * V3 model + */ + if( model->modelversion==3 ) + { + + /* + * Header + */ + ae_serializer_alloc_entry(s); + rbfv3alloc(s, &model->model3, _state); + return; + } + ae_assert(ae_false, "Assertion failed", _state); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfserialize(ae_serializer* s, + const rbfmodel* model, + ae_state *_state) +{ + + + + /* + * Header + */ + ae_serializer_serialize_int(s, getrbfserializationcode(_state), _state); + + /* + * V1 model + */ + if( model->modelversion==1 ) + { + ae_serializer_serialize_int(s, rbf_rbffirstversion, _state); + rbfv1serialize(s, &model->model1, _state); + return; + } + + /* + * V2 model + */ + if( model->modelversion==2 ) + { + + /* + * Header + */ + ae_serializer_serialize_int(s, rbf_rbfversion2, _state); + rbfv2serialize(s, &model->model2, _state); + return; + } + + /* + * V3 model + */ + if( model->modelversion==3 ) + { + + /* + * Header + */ + ae_serializer_serialize_int(s, rbf_rbfversion3, _state); + rbfv3serialize(s, &model->model3, _state); + return; + } + ae_assert(ae_false, "Assertion failed", _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 02.02.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state) +{ + ae_int_t i0; + ae_int_t i1; + + _rbfmodel_clear(model); + + rbf_rbfpreparenonserializablefields(model, _state); + + /* + * Header + */ + ae_serializer_unserialize_int(s, &i0, _state); + ae_assert(i0==getrbfserializationcode(_state), "RBFUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_assert((i1==rbf_rbffirstversion||i1==rbf_rbfversion2)||i1==rbf_rbfversion3, "RBFUnserialize: stream header corrupted", _state); + + /* + * V1 model + */ + if( i1==rbf_rbffirstversion ) + { + rbfv1unserialize(s, &model->model1, _state); + model->modelversion = 1; + model->ny = model->model1.ny; + model->nx = model->model1.nx; + rbf_initializev2(model->nx, model->ny, &model->model2, _state); + rbf_initializev3(model->nx, model->ny, &model->model3, _state); + rbfcreatecalcbuffer(model, &model->calcbuf, _state); + pushfastevaltol(model, model->fastevaltol, _state); + return; + } + + /* + * V2 model + */ + if( i1==rbf_rbfversion2 ) + { + rbfv2unserialize(s, &model->model2, _state); + model->modelversion = 2; + model->ny = model->model2.ny; + model->nx = model->model2.nx; + rbf_initializev1(model->nx, model->ny, &model->model1, _state); + rbf_initializev3(model->nx, model->ny, &model->model3, _state); + rbfcreatecalcbuffer(model, &model->calcbuf, _state); + pushfastevaltol(model, model->fastevaltol, _state); + return; + } + + /* + * V3 model + */ + if( i1==rbf_rbfversion3 ) + { + rbfv3unserialize(s, &model->model3, _state); + model->modelversion = 3; + model->ny = model->model3.ny; + model->nx = model->model3.nx; + rbf_initializev1(model->nx, model->ny, &model->model1, _state); + rbf_initializev2(model->nx, model->ny, &model->model2, _state); + rbfcreatecalcbuffer(model, &model->calcbuf, _state); + pushfastevaltol(model, model->fastevaltol, _state); + return; + } + ae_assert(ae_false, "RBF: unserialiation error (unexpected model type)", _state); +} + + +/************************************************************************* +Initialize empty model + + -- ALGLIB -- + Copyright 12.05.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbf_rbfpreparenonserializablefields(rbfmodel* s, + ae_state *_state) +{ + + + s->n = 0; + s->hasscale = ae_false; + s->radvalue = (double)(1); + s->radzvalue = (double)(5); + s->nlayers = 0; + s->lambdav = (double)(0); + s->aterm = 1; + s->algorithmtype = 0; + s->rbfprofile = 0; + s->epsort = rbf_eps; + s->epserr = rbf_eps; + s->maxits = 0; + s->v3tol = 1.0E-6; + s->nnmaxits = 100; + s->fastevaltol = 1.0E-3; +} + + +/************************************************************************* +Initialize V1 model (skip initialization for NX=1 or NX>3) + + -- ALGLIB -- + Copyright 12.05.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbf_initializev1(ae_int_t nx, + ae_int_t ny, + rbfv1model* s, + ae_state *_state) +{ + + _rbfv1model_clear(s); + + if( nx==2||nx==3 ) + { + rbfv1create(nx, ny, s, _state); + } +} + + +/************************************************************************* +Initialize V2 model + + -- ALGLIB -- + Copyright 12.05.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbf_initializev2(ae_int_t nx, + ae_int_t ny, + rbfv2model* s, + ae_state *_state) +{ + + _rbfv2model_clear(s); + + rbfv2create(nx, ny, s, _state); +} + + +/************************************************************************* +Initialize V3 model + + -- ALGLIB -- + Copyright 12.05.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbf_initializev3(ae_int_t nx, + ae_int_t ny, + rbfv3model* s, + ae_state *_state) +{ + + _rbfv3model_clear(s); + + rbfv3create(nx, ny, 2, (double)(0), s, _state); +} + + +/************************************************************************* +Cleans report fields + + -- ALGLIB -- + Copyright 16.06.2016 by Bochkanov Sergey +*************************************************************************/ +static void rbf_clearreportfields(rbfreport* rep, ae_state *_state) +{ + + + rep->rmserror = _state->v_nan; + rep->maxerror = _state->v_nan; + rep->arows = 0; + rep->acols = 0; + rep->annz = 0; + rep->iterationscount = 0; + rep->nmv = 0; + rep->terminationtype = 0; +} + + +void _rbfcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfcalcbuffer *p = (rbfcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv1calcbuffer_init(&p->bufv1, _state, make_automatic); + _rbfv2calcbuffer_init(&p->bufv2, _state, make_automatic); + _rbfv3calcbuffer_init(&p->bufv3, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dy, 0, DT_REAL, _state, make_automatic); +} + + +void _rbfcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfcalcbuffer *dst = (rbfcalcbuffer*)_dst; + const rbfcalcbuffer *src = (const rbfcalcbuffer*)_src; + dst->modelversion = src->modelversion; + _rbfv1calcbuffer_init_copy(&dst->bufv1, &src->bufv1, _state, make_automatic); + _rbfv2calcbuffer_init_copy(&dst->bufv2, &src->bufv2, _state, make_automatic); + _rbfv3calcbuffer_init_copy(&dst->bufv3, &src->bufv3, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->dy, &src->dy, _state, make_automatic); +} + + +void _rbfcalcbuffer_clear(void* _p) +{ + rbfcalcbuffer *p = (rbfcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv1calcbuffer_clear(&p->bufv1); + _rbfv2calcbuffer_clear(&p->bufv2); + _rbfv3calcbuffer_clear(&p->bufv3); + ae_vector_clear(&p->x); + ae_vector_clear(&p->y); + ae_vector_clear(&p->dy); +} + + +void _rbfcalcbuffer_destroy(void* _p) +{ + rbfcalcbuffer *p = (rbfcalcbuffer*)_p; + ae_touch_ptr((void*)p); + _rbfv1calcbuffer_destroy(&p->bufv1); + _rbfv2calcbuffer_destroy(&p->bufv2); + _rbfv3calcbuffer_destroy(&p->bufv3); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->dy); +} + + +void _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfmodel *p = (rbfmodel*)_p; + ae_touch_ptr((void*)p); + _rbfv1model_init(&p->model1, _state, make_automatic); + _rbfv2model_init(&p->model2, _state, make_automatic); + _rbfv3model_init(&p->model3, _state, make_automatic); + _rbfcalcbuffer_init(&p->calcbuf, _state, make_automatic); + ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); +} + + +void _rbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfmodel *dst = (rbfmodel*)_dst; + const rbfmodel *src = (const rbfmodel*)_src; + dst->nx = src->nx; + dst->ny = src->ny; + dst->modelversion = src->modelversion; + _rbfv1model_init_copy(&dst->model1, &src->model1, _state, make_automatic); + _rbfv2model_init_copy(&dst->model2, &src->model2, _state, make_automatic); + _rbfv3model_init_copy(&dst->model3, &src->model3, _state, make_automatic); + _rbfcalcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic); + dst->lambdav = src->lambdav; + dst->radvalue = src->radvalue; + dst->radzvalue = src->radzvalue; + dst->nlayers = src->nlayers; + dst->aterm = src->aterm; + dst->algorithmtype = src->algorithmtype; + dst->rbfprofile = src->rbfprofile; + dst->bftype = src->bftype; + dst->bfparam = src->bfparam; + dst->epsort = src->epsort; + dst->epserr = src->epserr; + dst->maxits = src->maxits; + dst->v3tol = src->v3tol; + dst->nnmaxits = src->nnmaxits; + dst->n = src->n; + ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic); + dst->hasscale = src->hasscale; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->fastevaltol = src->fastevaltol; + dst->progress10000 = src->progress10000; + dst->terminationrequest = src->terminationrequest; +} + + +void _rbfmodel_clear(void* _p) +{ + rbfmodel *p = (rbfmodel*)_p; + ae_touch_ptr((void*)p); + _rbfv1model_clear(&p->model1); + _rbfv2model_clear(&p->model2); + _rbfv3model_clear(&p->model3); + _rbfcalcbuffer_clear(&p->calcbuf); + ae_matrix_clear(&p->x); + ae_matrix_clear(&p->y); + ae_vector_clear(&p->s); +} + + +void _rbfmodel_destroy(void* _p) +{ + rbfmodel *p = (rbfmodel*)_p; + ae_touch_ptr((void*)p); + _rbfv1model_destroy(&p->model1); + _rbfv2model_destroy(&p->model2); + _rbfv3model_destroy(&p->model3); + _rbfcalcbuffer_destroy(&p->calcbuf); + ae_matrix_destroy(&p->x); + ae_matrix_destroy(&p->y); + ae_vector_destroy(&p->s); +} + + +void _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfreport *p = (rbfreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfreport *dst = (rbfreport*)_dst; + const rbfreport *src = (const rbfreport*)_src; + dst->rmserror = src->rmserror; + dst->maxerror = src->maxerror; + dst->arows = src->arows; + dst->acols = src->acols; + dst->annz = src->annz; + dst->iterationscount = src->iterationscount; + dst->nmv = src->nmv; + dst->terminationtype = src->terminationtype; +} + + +void _rbfreport_clear(void* _p) +{ + rbfreport *p = (rbfreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _rbfreport_destroy(void* _p) +{ + rbfreport *p = (rbfreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif + +} + diff --git a/core/alglib/interpolation.h b/core/alglib/interpolation.h index 18c06678..2201e375 100644 --- a/core/alglib/interpolation.h +++ b/core/alglib/interpolation.h @@ -1,5906 +1,12340 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _interpolation_pkg_h -#define _interpolation_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "alglibmisc.h" -#include "linalg.h" -#include "solvers.h" -#include "optimization.h" -#include "specialfunctions.h" -#include "integration.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_int_t n; - ae_int_t nx; - ae_int_t d; - double r; - ae_int_t nw; - kdtree tree; - ae_int_t modeltype; - ae_matrix q; - ae_vector xbuf; - ae_vector tbuf; - ae_vector rbuf; - ae_matrix xybuf; - ae_int_t debugsolverfailures; - double debugworstrcond; - double debugbestrcond; -} idwinterpolant; -typedef struct -{ - ae_int_t n; - double sy; - ae_vector x; - ae_vector y; - ae_vector w; -} barycentricinterpolant; -typedef struct -{ - ae_bool periodic; - ae_int_t n; - ae_int_t k; - ae_int_t continuity; - ae_vector x; - ae_vector c; -} spline1dinterpolant; -typedef struct -{ - double taskrcond; - double rmserror; - double avgerror; - double avgrelerror; - double maxerror; -} polynomialfitreport; -typedef struct -{ - double taskrcond; - ae_int_t dbest; - double rmserror; - double avgerror; - double avgrelerror; - double maxerror; -} barycentricfitreport; -typedef struct -{ - double taskrcond; - double rmserror; - double avgerror; - double avgrelerror; - double maxerror; -} spline1dfitreport; -typedef struct -{ - double taskrcond; - ae_int_t iterationscount; - ae_int_t varidx; - double rmserror; - double avgerror; - double avgrelerror; - double maxerror; - double wrmserror; - ae_matrix covpar; - ae_vector errpar; - ae_vector errcurve; - ae_vector noise; - double r2; -} lsfitreport; -typedef struct -{ - ae_int_t optalgo; - ae_int_t m; - ae_int_t k; - double epsf; - double epsx; - ae_int_t maxits; - double stpmax; - ae_bool xrep; - ae_vector s; - ae_vector bndl; - ae_vector bndu; - ae_matrix taskx; - ae_vector tasky; - ae_int_t npoints; - ae_vector taskw; - ae_int_t nweights; - ae_int_t wkind; - ae_int_t wits; - double diffstep; - double teststep; - ae_bool xupdated; - ae_bool needf; - ae_bool needfg; - ae_bool needfgh; - ae_int_t pointindex; - ae_vector x; - ae_vector c; - double f; - ae_vector g; - ae_matrix h; - ae_vector wcur; - ae_vector tmp; - ae_vector tmpf; - ae_matrix tmpjac; - ae_matrix tmpjacw; - double tmpnoise; - matinvreport invrep; - ae_int_t repiterationscount; - ae_int_t repterminationtype; - ae_int_t repvaridx; - double reprmserror; - double repavgerror; - double repavgrelerror; - double repmaxerror; - double repwrmserror; - lsfitreport rep; - minlmstate optstate; - minlmreport optrep; - ae_int_t prevnpt; - ae_int_t prevalgo; - rcommstate rstate; -} lsfitstate; -typedef struct -{ - ae_int_t n; - ae_bool periodic; - ae_vector p; - spline1dinterpolant x; - spline1dinterpolant y; -} pspline2interpolant; -typedef struct -{ - ae_int_t n; - ae_bool periodic; - ae_vector p; - spline1dinterpolant x; - spline1dinterpolant y; - spline1dinterpolant z; -} pspline3interpolant; -typedef struct -{ - ae_int_t ny; - ae_int_t nx; - ae_int_t nc; - ae_int_t nl; - kdtree tree; - ae_matrix xc; - ae_matrix wr; - double rmax; - ae_matrix v; - ae_int_t gridtype; - ae_bool fixrad; - double lambdav; - double radvalue; - double radzvalue; - ae_int_t nlayers; - ae_int_t aterm; - ae_int_t algorithmtype; - double epsort; - double epserr; - ae_int_t maxits; - double h; - ae_int_t n; - ae_matrix x; - ae_matrix y; - ae_vector calcbufxcx; - ae_matrix calcbufx; - ae_vector calcbuftags; -} rbfmodel; -typedef struct -{ - ae_int_t arows; - ae_int_t acols; - ae_int_t annz; - ae_int_t iterationscount; - ae_int_t nmv; - ae_int_t terminationtype; -} rbfreport; -typedef struct -{ - ae_int_t k; - ae_int_t stype; - ae_int_t n; - ae_int_t m; - ae_int_t d; - ae_vector x; - ae_vector y; - ae_vector f; -} spline2dinterpolant; -typedef struct -{ - ae_int_t k; - ae_int_t stype; - ae_int_t n; - ae_int_t m; - ae_int_t l; - ae_int_t d; - ae_vector x; - ae_vector y; - ae_vector z; - ae_vector f; -} spline3dinterpolant; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - -/************************************************************************* -IDW interpolant. -*************************************************************************/ -class _idwinterpolant_owner -{ -public: - _idwinterpolant_owner(); - _idwinterpolant_owner(const _idwinterpolant_owner &rhs); - _idwinterpolant_owner& operator=(const _idwinterpolant_owner &rhs); - virtual ~_idwinterpolant_owner(); - alglib_impl::idwinterpolant* c_ptr(); - alglib_impl::idwinterpolant* c_ptr() const; -protected: - alglib_impl::idwinterpolant *p_struct; -}; -class idwinterpolant : public _idwinterpolant_owner -{ -public: - idwinterpolant(); - idwinterpolant(const idwinterpolant &rhs); - idwinterpolant& operator=(const idwinterpolant &rhs); - virtual ~idwinterpolant(); - -}; - -/************************************************************************* -Barycentric interpolant. -*************************************************************************/ -class _barycentricinterpolant_owner -{ -public: - _barycentricinterpolant_owner(); - _barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs); - _barycentricinterpolant_owner& operator=(const _barycentricinterpolant_owner &rhs); - virtual ~_barycentricinterpolant_owner(); - alglib_impl::barycentricinterpolant* c_ptr(); - alglib_impl::barycentricinterpolant* c_ptr() const; -protected: - alglib_impl::barycentricinterpolant *p_struct; -}; -class barycentricinterpolant : public _barycentricinterpolant_owner -{ -public: - barycentricinterpolant(); - barycentricinterpolant(const barycentricinterpolant &rhs); - barycentricinterpolant& operator=(const barycentricinterpolant &rhs); - virtual ~barycentricinterpolant(); - -}; - - - -/************************************************************************* -1-dimensional spline interpolant -*************************************************************************/ -class _spline1dinterpolant_owner -{ -public: - _spline1dinterpolant_owner(); - _spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs); - _spline1dinterpolant_owner& operator=(const _spline1dinterpolant_owner &rhs); - virtual ~_spline1dinterpolant_owner(); - alglib_impl::spline1dinterpolant* c_ptr(); - alglib_impl::spline1dinterpolant* c_ptr() const; -protected: - alglib_impl::spline1dinterpolant *p_struct; -}; -class spline1dinterpolant : public _spline1dinterpolant_owner -{ -public: - spline1dinterpolant(); - spline1dinterpolant(const spline1dinterpolant &rhs); - spline1dinterpolant& operator=(const spline1dinterpolant &rhs); - virtual ~spline1dinterpolant(); - -}; - -/************************************************************************* -Polynomial fitting report: - TaskRCond reciprocal of task's condition number - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error -*************************************************************************/ -class _polynomialfitreport_owner -{ -public: - _polynomialfitreport_owner(); - _polynomialfitreport_owner(const _polynomialfitreport_owner &rhs); - _polynomialfitreport_owner& operator=(const _polynomialfitreport_owner &rhs); - virtual ~_polynomialfitreport_owner(); - alglib_impl::polynomialfitreport* c_ptr(); - alglib_impl::polynomialfitreport* c_ptr() const; -protected: - alglib_impl::polynomialfitreport *p_struct; -}; -class polynomialfitreport : public _polynomialfitreport_owner -{ -public: - polynomialfitreport(); - polynomialfitreport(const polynomialfitreport &rhs); - polynomialfitreport& operator=(const polynomialfitreport &rhs); - virtual ~polynomialfitreport(); - double &taskrcond; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &maxerror; - -}; - - -/************************************************************************* -Barycentric fitting report: - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - TaskRCond reciprocal of task's condition number -*************************************************************************/ -class _barycentricfitreport_owner -{ -public: - _barycentricfitreport_owner(); - _barycentricfitreport_owner(const _barycentricfitreport_owner &rhs); - _barycentricfitreport_owner& operator=(const _barycentricfitreport_owner &rhs); - virtual ~_barycentricfitreport_owner(); - alglib_impl::barycentricfitreport* c_ptr(); - alglib_impl::barycentricfitreport* c_ptr() const; -protected: - alglib_impl::barycentricfitreport *p_struct; -}; -class barycentricfitreport : public _barycentricfitreport_owner -{ -public: - barycentricfitreport(); - barycentricfitreport(const barycentricfitreport &rhs); - barycentricfitreport& operator=(const barycentricfitreport &rhs); - virtual ~barycentricfitreport(); - double &taskrcond; - ae_int_t &dbest; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &maxerror; - -}; - - -/************************************************************************* -Spline fitting report: - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - -Fields below are filled by obsolete functions (Spline1DFitCubic, -Spline1DFitHermite). Modern fitting functions do NOT fill these fields: - TaskRCond reciprocal of task's condition number -*************************************************************************/ -class _spline1dfitreport_owner -{ -public: - _spline1dfitreport_owner(); - _spline1dfitreport_owner(const _spline1dfitreport_owner &rhs); - _spline1dfitreport_owner& operator=(const _spline1dfitreport_owner &rhs); - virtual ~_spline1dfitreport_owner(); - alglib_impl::spline1dfitreport* c_ptr(); - alglib_impl::spline1dfitreport* c_ptr() const; -protected: - alglib_impl::spline1dfitreport *p_struct; -}; -class spline1dfitreport : public _spline1dfitreport_owner -{ -public: - spline1dfitreport(); - spline1dfitreport(const spline1dfitreport &rhs); - spline1dfitreport& operator=(const spline1dfitreport &rhs); - virtual ~spline1dfitreport(); - double &taskrcond; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &maxerror; - -}; - - -/************************************************************************* -Least squares fitting report. This structure contains informational fields -which are set by fitting functions provided by this unit. - -Different functions initialize different sets of fields, so you should -read documentation on specific function you used in order to know which -fields are initialized. - - TaskRCond reciprocal of task's condition number - IterationsCount number of internal iterations - - VarIdx if user-supplied gradient contains errors which were - detected by nonlinear fitter, this field is set to - index of the first component of gradient which is - suspected to be spoiled by bugs. - - RMSError RMS error - AvgError average error - AvgRelError average relative error (for non-zero Y[I]) - MaxError maximum error - - WRMSError weighted RMS error - - CovPar covariance matrix for parameters, filled by some solvers - ErrPar vector of errors in parameters, filled by some solvers - ErrCurve vector of fit errors - variability of the best-fit - curve, filled by some solvers. - Noise vector of per-point noise estimates, filled by - some solvers. - R2 coefficient of determination (non-weighted, non-adjusted), - filled by some solvers. -*************************************************************************/ -class _lsfitreport_owner -{ -public: - _lsfitreport_owner(); - _lsfitreport_owner(const _lsfitreport_owner &rhs); - _lsfitreport_owner& operator=(const _lsfitreport_owner &rhs); - virtual ~_lsfitreport_owner(); - alglib_impl::lsfitreport* c_ptr(); - alglib_impl::lsfitreport* c_ptr() const; -protected: - alglib_impl::lsfitreport *p_struct; -}; -class lsfitreport : public _lsfitreport_owner -{ -public: - lsfitreport(); - lsfitreport(const lsfitreport &rhs); - lsfitreport& operator=(const lsfitreport &rhs); - virtual ~lsfitreport(); - double &taskrcond; - ae_int_t &iterationscount; - ae_int_t &varidx; - double &rmserror; - double &avgerror; - double &avgrelerror; - double &maxerror; - double &wrmserror; - real_2d_array covpar; - real_1d_array errpar; - real_1d_array errcurve; - real_1d_array noise; - double &r2; - -}; - - -/************************************************************************* -Nonlinear fitter. - -You should use ALGLIB functions to work with fitter. -Never try to access its fields directly! -*************************************************************************/ -class _lsfitstate_owner -{ -public: - _lsfitstate_owner(); - _lsfitstate_owner(const _lsfitstate_owner &rhs); - _lsfitstate_owner& operator=(const _lsfitstate_owner &rhs); - virtual ~_lsfitstate_owner(); - alglib_impl::lsfitstate* c_ptr(); - alglib_impl::lsfitstate* c_ptr() const; -protected: - alglib_impl::lsfitstate *p_struct; -}; -class lsfitstate : public _lsfitstate_owner -{ -public: - lsfitstate(); - lsfitstate(const lsfitstate &rhs); - lsfitstate& operator=(const lsfitstate &rhs); - virtual ~lsfitstate(); - ae_bool &needf; - ae_bool &needfg; - ae_bool &needfgh; - ae_bool &xupdated; - real_1d_array c; - double &f; - real_1d_array g; - real_2d_array h; - real_1d_array x; - -}; - -/************************************************************************* -Parametric spline inteprolant: 2-dimensional curve. - -You should not try to access its members directly - use PSpline2XXXXXXXX() -functions instead. -*************************************************************************/ -class _pspline2interpolant_owner -{ -public: - _pspline2interpolant_owner(); - _pspline2interpolant_owner(const _pspline2interpolant_owner &rhs); - _pspline2interpolant_owner& operator=(const _pspline2interpolant_owner &rhs); - virtual ~_pspline2interpolant_owner(); - alglib_impl::pspline2interpolant* c_ptr(); - alglib_impl::pspline2interpolant* c_ptr() const; -protected: - alglib_impl::pspline2interpolant *p_struct; -}; -class pspline2interpolant : public _pspline2interpolant_owner -{ -public: - pspline2interpolant(); - pspline2interpolant(const pspline2interpolant &rhs); - pspline2interpolant& operator=(const pspline2interpolant &rhs); - virtual ~pspline2interpolant(); - -}; - - -/************************************************************************* -Parametric spline inteprolant: 3-dimensional curve. - -You should not try to access its members directly - use PSpline3XXXXXXXX() -functions instead. -*************************************************************************/ -class _pspline3interpolant_owner -{ -public: - _pspline3interpolant_owner(); - _pspline3interpolant_owner(const _pspline3interpolant_owner &rhs); - _pspline3interpolant_owner& operator=(const _pspline3interpolant_owner &rhs); - virtual ~_pspline3interpolant_owner(); - alglib_impl::pspline3interpolant* c_ptr(); - alglib_impl::pspline3interpolant* c_ptr() const; -protected: - alglib_impl::pspline3interpolant *p_struct; -}; -class pspline3interpolant : public _pspline3interpolant_owner -{ -public: - pspline3interpolant(); - pspline3interpolant(const pspline3interpolant &rhs); - pspline3interpolant& operator=(const pspline3interpolant &rhs); - virtual ~pspline3interpolant(); - -}; - -/************************************************************************* -RBF model. - -Never try to directly work with fields of this object - always use ALGLIB -functions to use this object. -*************************************************************************/ -class _rbfmodel_owner -{ -public: - _rbfmodel_owner(); - _rbfmodel_owner(const _rbfmodel_owner &rhs); - _rbfmodel_owner& operator=(const _rbfmodel_owner &rhs); - virtual ~_rbfmodel_owner(); - alglib_impl::rbfmodel* c_ptr(); - alglib_impl::rbfmodel* c_ptr() const; -protected: - alglib_impl::rbfmodel *p_struct; -}; -class rbfmodel : public _rbfmodel_owner -{ -public: - rbfmodel(); - rbfmodel(const rbfmodel &rhs); - rbfmodel& operator=(const rbfmodel &rhs); - virtual ~rbfmodel(); - -}; - - -/************************************************************************* -RBF solution report: -* TerminationType - termination type, positive values - success, - non-positive - failure. -*************************************************************************/ -class _rbfreport_owner -{ -public: - _rbfreport_owner(); - _rbfreport_owner(const _rbfreport_owner &rhs); - _rbfreport_owner& operator=(const _rbfreport_owner &rhs); - virtual ~_rbfreport_owner(); - alglib_impl::rbfreport* c_ptr(); - alglib_impl::rbfreport* c_ptr() const; -protected: - alglib_impl::rbfreport *p_struct; -}; -class rbfreport : public _rbfreport_owner -{ -public: - rbfreport(); - rbfreport(const rbfreport &rhs); - rbfreport& operator=(const rbfreport &rhs); - virtual ~rbfreport(); - ae_int_t &arows; - ae_int_t &acols; - ae_int_t &annz; - ae_int_t &iterationscount; - ae_int_t &nmv; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -2-dimensional spline inteprolant -*************************************************************************/ -class _spline2dinterpolant_owner -{ -public: - _spline2dinterpolant_owner(); - _spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs); - _spline2dinterpolant_owner& operator=(const _spline2dinterpolant_owner &rhs); - virtual ~_spline2dinterpolant_owner(); - alglib_impl::spline2dinterpolant* c_ptr(); - alglib_impl::spline2dinterpolant* c_ptr() const; -protected: - alglib_impl::spline2dinterpolant *p_struct; -}; -class spline2dinterpolant : public _spline2dinterpolant_owner -{ -public: - spline2dinterpolant(); - spline2dinterpolant(const spline2dinterpolant &rhs); - spline2dinterpolant& operator=(const spline2dinterpolant &rhs); - virtual ~spline2dinterpolant(); - -}; - -/************************************************************************* -3-dimensional spline inteprolant -*************************************************************************/ -class _spline3dinterpolant_owner -{ -public: - _spline3dinterpolant_owner(); - _spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs); - _spline3dinterpolant_owner& operator=(const _spline3dinterpolant_owner &rhs); - virtual ~_spline3dinterpolant_owner(); - alglib_impl::spline3dinterpolant* c_ptr(); - alglib_impl::spline3dinterpolant* c_ptr() const; -protected: - alglib_impl::spline3dinterpolant *p_struct; -}; -class spline3dinterpolant : public _spline3dinterpolant_owner -{ -public: - spline3dinterpolant(); - spline3dinterpolant(const spline3dinterpolant &rhs); - spline3dinterpolant& operator=(const spline3dinterpolant &rhs); - virtual ~spline3dinterpolant(); - -}; - -/************************************************************************* -IDW interpolation - -INPUT PARAMETERS: - Z - IDW interpolant built with one of model building - subroutines. - X - array[0..NX-1], interpolation point - -Result: - IDW interpolant Z(X) - - -- ALGLIB -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -double idwcalc(const idwinterpolant &z, const real_1d_array &x); - - -/************************************************************************* -IDW interpolant using modified Shepard method for uniform point -distributions. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function type, either: - * 0 constant model. Just for demonstration only, worst - model ever. - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - * -1 "fast" linear model, use with caution!!! It is - significantly faster than linear/quadratic and better - than constant model. But it is less robust (especially - in the presence of noise). - NQ - number of points used to calculate nodal functions (ignored - for constant models). NQ should be LARGER than: - * max(1.5*(1+NX),2^NX+1) for linear model, - * max(3/4*(NX+2)*(NX+1),2^NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, worst - with constant - models - * when N is large, NQ and NW must be significantly smaller than N both - to obtain optimal performance and to obtain optimal accuracy. In 2 or - 3-dimensional tasks NQ=15 and NW=25 are good values to start with. - * NQ and NW may be greater than N. In such cases they will be - automatically decreased. - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - * this subroutine assumes that point distribution is uniform at the small - scales. If it isn't - for example, points are concentrated along - "lines", but "lines" distribution is uniform at the larger scale - then - you should use IDWBuildModifiedShepardR() - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepard(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z); - - -/************************************************************************* -IDW interpolant using modified Shepard method for non-uniform datasets. - -This type of model uses constant nodal functions and interpolates using -all nodes which are closer than user-specified radius R. It may be used -when points distribution is non-uniform at the small scale, but it is at -the distances as large as R. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - R - radius, R>0 - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: -* if there is less than IDWKMin points within R-ball, algorithm selects - IDWKMin closest ones, so that continuity properties of interpolant are - preserved even far from points. - - -- ALGLIB PROJECT -- - Copyright 11.04.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildmodifiedshepardr(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const double r, idwinterpolant &z); - - -/************************************************************************* -IDW model for noisy data. - -This subroutine may be used to handle noisy data, i.e. data with noise in -OUTPUT values. It differs from IDWBuildModifiedShepard() in the following -aspects: -* nodal functions are not constrained to pass through nodes: Qi(xi)<>yi, - i.e. we have fitting instead of interpolation. -* weights which are used during least squares fitting stage are all equal - to 1.0 (independently of distance) -* "fast"-linear or constant nodal functions are not supported (either not - robust enough or too rigid) - -This problem require far more complex tuning than interpolation problems. -Below you can find some recommendations regarding this problem: -* focus on tuning NQ; it controls noise reduction. As for NW, you can just - make it equal to 2*NQ. -* you can use cross-validation to determine optimal NQ. -* optimal NQ is a result of complex tradeoff between noise level (more - noise = larger NQ required) and underlying function complexity (given - fixed N, larger NQ means smoothing of compex features in the data). For - example, NQ=N will reduce noise to the minimum level possible, but you - will end up with just constant/linear/quadratic (depending on D) least - squares model for the whole dataset. - -INPUT PARAMETERS: - XY - X and Y values, array[0..N-1,0..NX]. - First NX columns contain X-values, last column contain - Y-values. - N - number of nodes, N>0. - NX - space dimension, NX>=1. - D - nodal function degree, either: - * 1 linear model, least squares fitting. Simpe model for - datasets too small for quadratic models (or for very - noisy problems). - * 2 quadratic model, least squares fitting. Best model - available (if your dataset is large enough). - NQ - number of points used to calculate nodal functions. NQ should - be significantly larger than 1.5 times the number of - coefficients in a nodal function to overcome effects of noise: - * larger than 1.5*(1+NX) for linear model, - * larger than 3/4*(NX+2)*(NX+1) for quadratic model. - Values less than this threshold will be silently increased. - NW - number of points used to calculate weights and to interpolate. - Required: >=2^NX+1, values less than this threshold will be - silently increased. - Recommended value: about 2*NQ or larger - -OUTPUT PARAMETERS: - Z - IDW interpolant. - -NOTES: - * best results are obtained with quadratic models, linear models are not - recommended to use unless you are pretty sure that it is what you want - * this subroutine is always succeeds (as long as correct parameters are - passed). - * see 'Multivariate Interpolation of Large Sets of Scattered Data' by - Robert J. Renka for more information on this algorithm. - - - -- ALGLIB PROJECT -- - Copyright 02.03.2010 by Bochkanov Sergey -*************************************************************************/ -void idwbuildnoisy(const real_2d_array &xy, const ae_int_t n, const ae_int_t nx, const ae_int_t d, const ae_int_t nq, const ae_int_t nw, idwinterpolant &z); - -/************************************************************************* -Rational interpolation using barycentric formula - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -Input parameters: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -Result: - barycentric interpolant F(t) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -double barycentriccalc(const barycentricinterpolant &b, const double t); - - -/************************************************************************* -Differentiation of barycentric interpolant: first derivative. - -Algorithm used in this subroutine is very robust and should not fail until -provided with values too close to MaxRealNumber (usually MaxRealNumber/N -or greater will overflow). - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - -NOTE - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df); - - -/************************************************************************* -Differentiation of barycentric interpolant: first/second derivatives. - -INPUT PARAMETERS: - B - barycentric interpolant built with one of model building - subroutines. - T - interpolation point - -OUTPUT PARAMETERS: - F - barycentric interpolant at T - DF - first derivative - D2F - second derivative - -NOTE: this algorithm may fail due to overflow/underflor if used on data -whose values are close to MaxRealNumber or MinRealNumber. Use more robust -BarycentricDiff1() subroutine in such cases. - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f); - - -/************************************************************************* -This subroutine performs linear transformation of the argument. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: x = CA*t + CB - -OUTPUT PARAMETERS: - B - transformed interpolant with X replaced by T - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb); - - -/************************************************************************* -This subroutine performs linear transformation of the barycentric -interpolant. - -INPUT PARAMETERS: - B - rational interpolant in barycentric form - CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB - -OUTPUT PARAMETERS: - B - transformed interpolant - - -- ALGLIB PROJECT -- - Copyright 19.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb); - - -/************************************************************************* -Extracts X/Y/W arrays from rational interpolant - -INPUT PARAMETERS: - B - barycentric interpolant - -OUTPUT PARAMETERS: - N - nodes count, N>0 - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w); - - -/************************************************************************* -Rational interpolant from X/Y/W arrays - -F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) - -INPUT PARAMETERS: - X - interpolation nodes, array[0..N-1] - F - function values, array[0..N-1] - W - barycentric weights, array[0..N-1] - N - nodes count, N>0 - -OUTPUT PARAMETERS: - B - barycentric interpolant built from (X, Y, W) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b); - - -/************************************************************************* -Rational interpolant without poles - -The subroutine constructs the rational interpolating function without real -poles (see 'Barycentric rational interpolation with no poles and high -rates of approximation', Michael S. Floater. and Kai Hormann, for more -information on this subject). - -Input parameters: - X - interpolation nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of nodes, N>0. - D - order of the interpolation scheme, 0 <= D <= N-1. - D<0 will cause an error. - D>=N it will be replaced with D=N-1. - if you don't know what D to choose, use small value about 3-5. - -Output parameters: - B - barycentric interpolant. - -Note: - this algorithm always succeeds and calculates the weights with close - to machine precision. - - -- ALGLIB PROJECT -- - Copyright 17.06.2007 by Bochkanov Sergey -*************************************************************************/ -void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b); - -/************************************************************************* -Conversion from barycentric representation to Chebyshev basis. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - P - polynomial in barycentric form - A,B - base interval for Chebyshev polynomials (see below) - A<>B - -OUTPUT PARAMETERS - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, - where Ti - I-th Chebyshev polynomial. - -NOTES: - barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t); - - -/************************************************************************* -Conversion from Chebyshev basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - T - coefficients of Chebyshev representation; - P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, - where Ti - I-th Chebyshev polynomial. - N - number of coefficients: - * if given, only leading N elements of T are used - * if not given, automatically determined from size of T - A,B - base interval for Chebyshev polynomials (see above) - A0. - -OUTPUT PARAMETERS - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if P was obtained as - result of interpolation on [-1,+1], you can set C=0 and S=1 and - represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it - is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 - will be better option. Such representation can be obtained by using - 1000.0 as offset C and 1.0 as scale S. - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return coefficients in - any case, but for N>8 they will become unreliable. However, N's - less than 5 are pretty safe. - -3. barycentric interpolant passed as P may be either polynomial obtained - from polynomial interpolation/ fitting or rational function which is - NOT polynomial. We can't distinguish between these two cases, and this - algorithm just tries to work assuming that P IS a polynomial. If not, - algorithm will return results, but they won't have any meaning. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a); -void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a); - - -/************************************************************************* -Conversion from power basis to barycentric representation. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } - N - number of coefficients (polynomial degree plus 1) - * if given, only leading N elements of A are used - * if not given, automatically determined from size of A - C - offset (see below); 0.0 is used as default value. - S - scale (see below); 1.0 is used as default value. S<>0. - -OUTPUT PARAMETERS - P - polynomial in barycentric form - - -NOTES: -1. this function accepts offset and scale, which can be set to improve - numerical properties of polynomial. For example, if you interpolate on - [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, - x^3 and so on. In most cases you it is exactly what you need. - - However, if your interpolation model was built on [999,1001], you will - see significant growth of numerical errors when using {1, x, x^2, x^3} - as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, - (x-1000)^3 will be better option (you have to specify 1000.0 as offset - C and 1.0 as scale S). - -2. power basis is ill-conditioned and tricks described above can't solve - this problem completely. This function will return barycentric model - in any case, but for N>8 accuracy well degrade. However, N's less than - 5 are pretty safe. - - -- ALGLIB -- - Copyright 30.09.2010 by Bochkanov Sergey -*************************************************************************/ -void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p); -void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p); - - -/************************************************************************* -Lagrange intepolant: generation of the model on the general grid. -This function has O(N^2) complexity. - -INPUT PARAMETERS: - X - abscissas, array[0..N-1] - Y - function values, array[0..N-1] - N - number of points, N>=1 - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); -void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p); - - -/************************************************************************* -Lagrange intepolant: generation of the model on equidistant grid. -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1] - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); -void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); - - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (first kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); -void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); - - -/************************************************************************* -Lagrange intepolant on Chebyshev grid (second kind). -This function has O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - Y - function values at the nodes, array[0..N-1], - Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) - N - number of points, N>=1 - for N=1 a constant model is constructed. - -OUTPUT PARAMETERS - P - barycentric model which represents Lagrange interpolant - (see ratint unit info and BarycentricCalc() description for - more information). - - -- ALGLIB -- - Copyright 03.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p); -void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p); - - -/************************************************************************* -Fast equidistant polynomial interpolation function with O(N) complexity - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on equidistant grid, N>=1 - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolynomialBuildEqDist()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); -double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t); - - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (first kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (first kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb1()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); -double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t); - - -/************************************************************************* -Fast polynomial interpolation function on Chebyshev points (second kind) -with O(N) complexity. - -INPUT PARAMETERS: - A - left boundary of [A,B] - B - right boundary of [A,B] - F - function values, array[0..N-1] - N - number of points on Chebyshev grid (second kind), - X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) - for N=1 a constant model is constructed. - T - position where P(x) is calculated - -RESULT - value of the Lagrange interpolant at T - -IMPORTANT - this function provides fast interface which is not overflow-safe - nor it is very precise. - the best option is to use PolIntBuildCheb2()/BarycentricCalc() - subroutines unless you are pretty sure that your data will not result - in overflow. - - -- ALGLIB -- - Copyright 02.12.2009 by Bochkanov Sergey -*************************************************************************/ -double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t); -double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t); - -/************************************************************************* -This subroutine builds linear spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); -void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); - - -/************************************************************************* -This subroutine builds cubic spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - C - spline interpolant - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c); -void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns table of function derivatives d[] -(calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D - derivative values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d); -void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d); - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at nodes x[], it calculates and returns tables of first and second -function derivatives d1[] and d2[] (calculated at the same nodes x[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - spline nodes - Y - function values - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - -OUTPUT PARAMETERS: - D1 - S' values at X[] - D2 - S'' values at X[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Derivative values are correctly reordered on return, so D[I] is always -equal to S'(X[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2); -void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2); - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2); -void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2); - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[] and derivatives d2[] (calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2); -void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2); - - -/************************************************************************* -This function solves following problem: given table y[] of function values -at old nodes x[] and new nodes x2[], it calculates and returns table of -function values y2[], first and second derivatives d2[] and dd2[] -(calculated at x2[]). - -This function yields same result as Spline1DBuildCubic() call followed by -sequence of Spline1DDiff() calls, but it can be several times faster when -called for ordered X[] and X2[]. - -INPUT PARAMETERS: - X - old spline nodes - Y - function values - X2 - new spline nodes - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points from X/Y are used - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundLType - boundary condition type for the left boundary - BoundL - left boundary condition (first or second derivative, - depending on the BoundLType) - BoundRType - boundary condition type for the right boundary - BoundR - right boundary condition (first or second derivative, - depending on the BoundRType) - N2 - new points count: - * N2>=2 - * if given, only first N2 points from X2 are used - * if not given, automatically detected from X2 size - -OUTPUT PARAMETERS: - F2 - function values at X2[] - D2 - first derivatives at X2[] - DD2 - second derivatives at X2[] - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. -Function values are correctly reordered on return, so F2[I] is always -equal to S(X2[I]) independently of points order. - -SETTING BOUNDARY VALUES: - -The BoundLType/BoundRType parameters can have the following values: - * -1, which corresonds to the periodic (cyclic) boundary conditions. - In this case: - * both BoundLType and BoundRType must be equal to -1. - * BoundL/BoundR are ignored - * Y[last] is ignored (it is assumed to be equal to Y[first]). - * 0, which corresponds to the parabolically terminated spline - (BoundL and/or BoundR are ignored). - * 1, which corresponds to the first derivative boundary condition - * 2, which corresponds to the second derivative boundary condition - * by default, BoundType=0 is used - -PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: - -Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. -However, this subroutine doesn't require you to specify equal values for -the first and last points - it automatically forces them to be equal by -copying Y[first_point] (corresponds to the leftmost, minimal X[]) to -Y[last_point]. However it is recommended to pass consistent values of Y[], -i.e. to make Y[first_point]=Y[last_point]. - - -- ALGLIB PROJECT -- - Copyright 03.09.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2); -void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2); - - -/************************************************************************* -This subroutine builds Catmull-Rom spline interpolant. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. - Y - function values, array[0..N-1]. - -OPTIONAL PARAMETERS: - N - points count: - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - BoundType - boundary condition type: - * -1 for periodic boundary condition - * 0 for parabolically terminated spline (default) - Tension - tension parameter: - * tension=0 corresponds to classic Catmull-Rom spline (default) - * 0=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c); -void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c); - - -/************************************************************************* -This subroutine builds Akima spline interpolant - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1] - Y - function values, array[0..N-1] - N - points count (optional): - * N>=2 - * if given, only first N points are used to build spline - * if not given, automatically detected from X/Y sizes - (len(X) must be equal to len(Y)) - -OUTPUT PARAMETERS: - C - spline interpolant - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); -void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); - - -/************************************************************************* -This subroutine calculates the value of the spline at the given point X. - -INPUT PARAMETERS: - C - spline interpolant - X - point - -Result: - S(x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dcalc(const spline1dinterpolant &c, const double x); - - -/************************************************************************* -This subroutine differentiates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -Result: - S - S(x) - DS - S'(x) - D2S - S''(x) - - -- ALGLIB PROJECT -- - Copyright 24.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s); - - -/************************************************************************* -This subroutine unpacks the spline into the coefficients table. - -INPUT PARAMETERS: - C - spline interpolant. - X - point - -OUTPUT PARAMETERS: - Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. - For I = 0...N-2: - Tbl[I,0] = X[i] - Tbl[I,1] = X[i+1] - Tbl[I,2] = C0 - Tbl[I,3] = C1 - Tbl[I,4] = C2 - Tbl[I,5] = C3 - On [x[i], x[i+1]] spline is equals to: - S(x) = C0 + C1*t + C2*t^2 + C3*t^3 - t = x-x[i] - -NOTE: - You can rebuild spline with Spline1DBuildHermite() function, which - accepts as inputs function values and derivatives at nodes, which are - easy to calculate when you have coefficients. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl); - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: x = A*t + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b); - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x) = A*S(x) + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b); - - -/************************************************************************* -This subroutine integrates the spline. - -INPUT PARAMETERS: - C - spline interpolant. - X - right bound of the integration interval [a, x], - here 'a' denotes min(x[]) -Result: - integral(S(t)dt,a,x) - - -- ALGLIB PROJECT -- - Copyright 23.06.2007 by Bochkanov Sergey -*************************************************************************/ -double spline1dintegrate(const spline1dinterpolant &c, const double x); - - -/************************************************************************* -This function builds monotone cubic Hermite interpolant. This interpolant -is monotonic in [x(0),x(n-1)] and is constant outside of this interval. - -In case y[] form non-monotonic sequence, interpolant is piecewise -monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will -monotonically grow at [0..2] and monotonically decrease at [2..4]. - -INPUT PARAMETERS: - X - spline nodes, array[0..N-1]. Subroutine automatically - sorts points, so caller may pass unsorted array. - Y - function values, array[0..N-1] - N - the number of points(N>=2). - -OUTPUT PARAMETERS: - C - spline interpolant. - - -- ALGLIB PROJECT -- - Copyright 21.06.2012 by Bochkanov Sergey -*************************************************************************/ -void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c); -void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c); - -/************************************************************************* -Fitting by polynomials in barycentric form. This function provides simple -unterface for unconstrained unweighted fitting. See PolynomialFitWC() if -you need constrained fitting. - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFitWC() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0 - * if given, only leading N elements of X/Y are used - * if not given, automatically determined from sizes of X/Y - M - number of basis functions (= polynomial_degree + 1), M>=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); -void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); - - -/************************************************************************* -Weighted fitting by polynomials in barycentric form, with constraints on -function values or first derivatives. - -Small regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO: - PolynomialFit() - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - * if given, only leading N elements of X/Y/W are used - * if not given, automatically determined from sizes of X/Y/W - XC - points where polynomial values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that P(XC[i])=YC[i] - * DC[i]=1 means that P'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=1 - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - P - interpolant in barycentric form. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTES: - you can convert P from barycentric form to the power or Chebyshev - basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from - POLINT subpackage. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* even simple constraints can be inconsistent, see Wikipedia article on - this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the one special cases, however, we can guarantee consistency. This - case is: M>1 and constraints on the function values (NOT DERIVATIVES) - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 10.12.2009 by Bochkanov Sergey -*************************************************************************/ -void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); -void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep); - - -/************************************************************************* -Weghted rational least squares fitting using Floater-Hormann rational -functions with optimal D chosen from [0,9], with constraints and -individual weights. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least WEIGHTED root -mean square error) is chosen. Task is linear, so linear least squares -solver is used. Complexity of this computational scheme is O(N*M^2) -(mostly dominated by the least squares solver). - -SEE ALSO -* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual - weights and constraints. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points, N>0. - XC - points where function values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints, 0<=K=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -1 means another errors in parameters passed - (N<=0, for example) - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroutine doesn't calculate task's condition number for K<>0. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained barycentric interpolants: -* excessive constraints can be inconsistent. Floater-Hormann basis - functions aren't as flexible as splines (although they are very smooth). -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function VALUES at the interval - boundaries. Note that consustency of the constraints on the function - DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines - which are more flexible). -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); - - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep); - - -/************************************************************************* -Rational least squares fitting using Floater-Hormann rational functions -with optimal D chosen from [0,9]. - -Equidistant grid with M node on [min(x),max(x)] is used to build basis -functions. Different values of D are tried, optimal D (least root mean -square error) is chosen. Task is linear, so linear least squares solver -is used. Complexity of this computational scheme is O(N*M^2) (mostly -dominated by the least squares solver). - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - N - number of points, N>0. - M - number of basis functions ( = number_of_nodes), M>=2. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - B - barycentric interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * DBest best value of the D parameter - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Weighted fitting by penalized cubic spline. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with natural boundary -conditions. Problem is regularized by adding non-linearity penalty to the -usual least squares penalty function: - - S(x) = arg min { LS + P }, where - LS = SUM { w[i]^2*(y[i] - S(x[i]))^2 } - least squares penalty - P = C*10^rho*integral{ S''(x)^2*dx } - non-linearity penalty - rho - tunable constant given by user - C - automatically determined scale parameter, - makes penalty invariant with respect to scaling of X, Y, W. - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - problem. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - M - number of basis functions ( = number_of_nodes), M>=4. - Rho - regularization constant passed by user. It penalizes - nonlinearity in the regression spline. It is logarithmically - scaled, i.e. actual value of regularization constant is - calculated as 10^Rho. It is automatically scaled so that: - * Rho=2.0 corresponds to moderate amount of nonlinearity - * generally, it should be somewhere in the [-8.0,+8.0] - If you do not want to penalize nonlineary, - pass small Rho. Values as low as -15 should work. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD or - Cholesky decomposition; problem may be - too ill-conditioned (very rare) - S - spline interpolant. - Rep - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -NOTE 1: additional nodes are added to the spline outside of the fitting -interval to force linearity when xmax(x,xc). It is done -for consistency - we penalize non-linearity at [min(x,xc),max(x,xc)], so -it is natural to force linearity outside of this interval. - -NOTE 2: function automatically sorts points, so caller may pass unsorted -array. - - -- ALGLIB PROJECT -- - Copyright 19.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Weighted fitting by cubic spline, with constraints on function values or -derivatives. - -Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are cubic splines with continuous second -derivatives and non-fixed first derivatives at interval ends. Small -regularizing term is used when solving constrained tasks (to improve -stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitHermiteWC() - fitting by Hermite splines (more flexible, - less smooth) - Spline1DFitCubic() - "lightweight" fitting by cubic splines, - without invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4. - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearWC() subroutine. - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - S - spline interpolant. - Rep - report, same format as in LSFitLinearWC() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints IS NOT GUARANTEED. -* in the several special cases, however, we CAN guarantee consistency. -* one of this cases is constraints on the function values AND/OR its - derivatives at the interval boundaries. -* another special case is ONE constraint on the function value (OR, but - not AND, derivative) anywhere in the interval - -Our final recommendation is to use constraints WHEN AND ONLY WHEN you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Weighted fitting by Hermite spline, with constraints on function values -or first derivatives. - -Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build -basis functions. Basis functions are Hermite splines. Small regularizing -term is used when solving constrained tasks (to improve stability). - -Task is linear, so linear least squares solver is used. Complexity of this -computational scheme is O(N*M^2), mostly dominated by least squares solver - -SEE ALSO - Spline1DFitCubicWC() - fitting by Cubic splines (less flexible, - more smooth) - Spline1DFitHermite() - "lightweight" Hermite fitting, without - invididual weights and constraints - -INPUT PARAMETERS: - X - points, array[0..N-1]. - Y - function values, array[0..N-1]. - W - weights, array[0..N-1] - Each summand in square sum of approximation deviations from - given values is multiplied by the square of corresponding - weight. Fill it by 1's if you don't want to solve weighted - task. - N - number of points (optional): - * N>0 - * if given, only first N elements of X/Y/W are processed - * if not given, automatically determined from X/Y/W sizes - XC - points where spline values/derivatives are constrained, - array[0..K-1]. - YC - values of constraints, array[0..K-1] - DC - array[0..K-1], types of constraints: - * DC[i]=0 means that S(XC[i])=YC[i] - * DC[i]=1 means that S'(XC[i])=YC[i] - SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS - K - number of constraints (optional): - * 0<=K=4, - M IS EVEN! - -OUTPUT PARAMETERS: - Info- same format as in LSFitLinearW() subroutine: - * Info>0 task is solved - * Info<=0 an error occurred: - -4 means inconvergence of internal SVD - -3 means inconsistent constraints - -2 means odd M was passed (which is not supported) - -1 means another errors in parameters passed - (N<=0, for example) - S - spline interpolant. - Rep - report, same format as in LSFitLinearW() subroutine. - Following fields are set: - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -IMPORTANT: - this subroitine supports only even M's - - -ORDER OF POINTS - -Subroutine automatically sorts points, so caller may pass unsorted array. - -SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: - -Setting constraints can lead to undesired results, like ill-conditioned -behavior, or inconsistency being detected. From the other side, it allows -us to improve quality of the fit. Here we summarize our experience with -constrained regression splines: -* excessive constraints can be inconsistent. Splines are piecewise cubic - functions, and it is easy to create an example, where large number of - constraints concentrated in small area will result in inconsistency. - Just because spline is not flexible enough to satisfy all of them. And - same constraints spread across the [min(x),max(x)] will be perfectly - consistent. -* the more evenly constraints are spread across [min(x),max(x)], the more - chances that they will be consistent -* the greater is M (given fixed constraints), the more chances that - constraints will be consistent -* in the general case, consistency of constraints is NOT GUARANTEED. -* in the several special cases, however, we can guarantee consistency. -* one of this cases is M>=4 and constraints on the function value - (AND/OR its derivative) at the interval boundaries. -* another special case is M>=4 and ONE constraint on the function value - (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] - -Our final recommendation is to use constraints WHEN AND ONLY when you -can't solve your task without them. Anything beyond special cases given -above is not guaranteed and may result in inconsistency. - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Least squares fitting by cubic spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitCubicWC(). See Spline1DFitCubicWC() for more information -about subroutine parameters (we don't duplicate it here because of length) - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Least squares fitting by Hermite spline. - -This subroutine is "lightweight" alternative for more complex and feature- -rich Spline1DFitHermiteWC(). See Spline1DFitHermiteWC() description for -more information about subroutine parameters (we don't duplicate it here -because of length). - - -- ALGLIB PROJECT -- - Copyright 18.08.2009 by Bochkanov Sergey -*************************************************************************/ -void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); -void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep); - - -/************************************************************************* -Weighted linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -1 incorrect N/M were specified - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); -void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); - - -/************************************************************************* -Weighted constained linear least squares fitting. - -This is variation of LSFitLinearW(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - W - array[0..N-1] Weights corresponding to function values. - Each summand in square sum of approximation deviations - from given values is multiplied by the square of - corresponding weight. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); -void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); - - -/************************************************************************* -Linear least squares fitting. - -QR decomposition is used to reduce task to MxM, then triangular solver or -SVD-based solver is used depending on condition number of the system. It -allows to maximize speed and retain decent accuracy. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I, J] - value of J-th basis function in I-th point. - N - number of points used. N>=1. - M - number of basis functions, M>=1. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * Rep.TaskRCond reciprocal of condition number - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep); -void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); - - -/************************************************************************* -Constained linear least squares fitting. - -This is variation of LSFitLinear(), which searchs for min|A*x=b| given -that K additional constraints C*x=bc are satisfied. It reduces original -task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() -is called. - -IMPORTANT: if you want to perform polynomial fitting, it may be more - convenient to use PolynomialFit() function. This function gives - best results on polynomial problems and solves numerical - stability issues which arise when you fit high-degree - polynomials to your data. - -INPUT PARAMETERS: - Y - array[0..N-1] Function values in N points. - FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. - FMatrix[I,J] - value of J-th basis function in I-th point. - CMatrix - a table of constraints, array[0..K-1,0..M]. - I-th row of CMatrix corresponds to I-th linear constraint: - CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] - N - number of points used. N>=1. - M - number of basis functions, M>=1. - K - number of constraints, 0 <= K < M - K=0 corresponds to absence of constraints. - -OUTPUT PARAMETERS: - Info - error code: - * -4 internal SVD decomposition subroutine failed (very - rare and for degenerate systems only) - * -3 either too many constraints (M or more), - degenerate constraints (some constraints are - repetead twice) or inconsistent constraints were - specified. - * 1 task is solved - C - decomposition coefficients, array[0..M-1] - Rep - fitting report. Following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - -IMPORTANT: - this subroitine doesn't calculate task's condition number for K<>0. - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(F*CovPar*F')), - where F is functions matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 07.09.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep); -void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep); - - -/************************************************************************* -Weighted nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state); -void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state); - - -/************************************************************************* -Nonlinear least squares fitting using function values only. - -Combination of numerical differentiation and secant updates is used to -obtain function Jacobian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]). - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - DiffStep- numerical differentiation step; - should not be very small or large; - large = loss of accuracy - small = growth of round-off errors - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 18.10.2008 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state); -void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state); - - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient only. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also: - LSFitResults - LSFitCreateFG (fitting without weights) - LSFitCreateWFGH (fitting using Hessian) - LSFitCreateFGH (fitting using Hessian, without weights) - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state); -void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const bool cheapfg, lsfitstate &state); - - -/************************************************************************* -Nonlinear least squares fitting using gradient only, without individual -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses only f(c,x[i]) and its gradient. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - CheapFG - boolean flag, which is: - * True if both function and gradient calculation complexity - are less than O(M^2). An improved algorithm can - be used which corresponds to FGJ scheme from - MINLM unit. - * False otherwise. - Standard Jacibian-bases Levenberg-Marquardt algo - will be used (FJ scheme). - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state); -void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const bool cheapfg, lsfitstate &state); - - -/************************************************************************* -Weighted nonlinear least squares fitting using gradient/Hessian. - -Nonlinear task min(F(c)) is solved, where - - F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * w is an N-dimensional vector of weight coefficients, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - W - weights, array[0..N-1] - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state); -void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state); - - -/************************************************************************* -Nonlinear least squares fitting using gradient/Hessian, without individial -weights. - -Nonlinear task min(F(c)) is solved, where - - F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, - - * N is a number of points, - * M is a dimension of a space points belong to, - * K is a dimension of a space of parameters being fitted, - * x is a set of N points, each of them is an M-dimensional vector, - * c is a K-dimensional vector of parameters being fitted - -This subroutine uses f(c,x[i]), its gradient and its Hessian. - -INPUT PARAMETERS: - X - array[0..N-1,0..M-1], points (one row = one point) - Y - array[0..N-1], function values. - C - array[0..K-1], initial approximation to the solution, - N - number of points, N>1 - M - dimension of space - K - number of parameters being fitted - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state); -void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state); - - -/************************************************************************* -Stopping conditions for nonlinear least squares fitting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - stopping criterion. Algorithm stops if - |F(k+1)-F(k)| <= EpsF*max{|F(k)|, |F(k+1)|, 1} - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by LSFitSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -NOTE - -Passing EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic -stopping criterion selection (according to the scheme used by MINLM unit). - - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetcond(const lsfitstate &state, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetstpmax(const lsfitstate &state, const double stpmax); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -When reports are needed, State.C (current parameters) and State.F (current -value of fitting function) are reported. - - - -- ALGLIB -- - Copyright 15.08.2010 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetxrep(const lsfitstate &state, const bool needxrep); - - -/************************************************************************* -This function sets scaling coefficients for underlying optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetscale(const lsfitstate &state, const real_1d_array &s); - - -/************************************************************************* -This function sets boundary constraints for underlying optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[K]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[K]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: unlike other constrained optimization algorithms, this solver has -following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool lsfititeration(const lsfitstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear fitter - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - hess - callback which calculates function (or merit function) - value func, gradient grad and Hessian hess at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - -NOTES: - -1. this algorithm is somewhat unusual because it works with parameterized - function f(C,X), where X is a function argument (we have many points - which are characterized by different argument values), and C is a - parameter to fit. - - For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then - x will be argument, and {c0,c1} will be parameters. - - It is important to understand that this algorithm finds minimum in the - space of function PARAMETERS (not arguments), so it needs derivatives - of f() with respect to C, not X. - - In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} - instead of {df/dx} = {c0}. - -2. Callback functions accept C as the first parameter, and X as the second - -3. If state was created with LSFitCreateFG(), algorithm needs just - function and its gradient, but if state was created with - LSFitCreateFGH(), algorithm will need function, gradient and Hessian. - - According to the said above, there ase several versions of this - function, which accept different sets of callbacks. - - This flexibility opens way to subtle errors - you may create state with - LSFitCreateFGH() (optimization using Hessian), but call function which - does not accept Hessian. So when algorithm will request Hessian, there - will be no callback to call. In this case exception will be thrown. - - Be careful to avoid such errors because there is no way to find them at - compile time - you can see them at runtime only. - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey - -*************************************************************************/ -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, - void *ptr = NULL); -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, - void *ptr = NULL); -void lsfitfit(lsfitstate &state, - void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), - void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -Nonlinear least squares fitting results. - -Called after return from LSFitFit(). - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Info - completion code: - * -7 gradient verification failed. - See LSFitSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - C - array[0..K-1], solution - Rep - optimization report. On success following fields are set: - * R2 non-adjusted coefficient of determination - (non-weighted) - * RMSError rms error on the (X,Y). - * AvgError average error on the (X,Y). - * AvgRelError average relative error on the non-zero Y - * MaxError maximum error - NON-WEIGHTED ERRORS ARE CALCULATED - * WRMSError weighted rms error on the (X,Y). - -ERRORS IN PARAMETERS - -This solver also calculates different kinds of errors in parameters and -fills corresponding fields of report: -* Rep.CovPar covariance matrix for parameters, array[K,K]. -* Rep.ErrPar errors in parameters, array[K], - errpar = sqrt(diag(CovPar)) -* Rep.ErrCurve vector of fit errors - standard deviations of empirical - best-fit curve from "ideal" best-fit curve built with - infinite number of samples, array[N]. - errcurve = sqrt(diag(J*CovPar*J')), - where J is Jacobian matrix. -* Rep.Noise vector of per-point estimates of noise, array[N] - -IMPORTANT: errors in parameters are calculated without taking into - account boundary/linear constraints! Presence of constraints - changes distribution of errors, but there is no easy way to - account for constraints when you calculate covariance matrix. - -NOTE: noise in the data is estimated as follows: - * for fitting without user-supplied weights all points are - assumed to have same level of noise, which is estimated from - the data - * for fitting with user-supplied weights we assume that noise - level in I-th point is inversely proportional to Ith weight. - Coefficient of proportionality is estimated from the data. - -NOTE: we apply small amount of regularization when we invert squared - Jacobian and calculate covariance matrix. It guarantees that - algorithm won't divide by zero during inversion, but skews - error estimates a bit (fractional error is about 10^-9). - - However, we believe that this difference is insignificant for - all practical purposes except for the situation when you want - to compare ALGLIB results with "reference" implementation up - to the last significant digit. - -NOTE: covariance matrix is estimated using correction for degrees - of freedom (covariances are divided by N-M instead of dividing - by N). - - -- ALGLIB -- - Copyright 17.08.2009 by Bochkanov Sergey -*************************************************************************/ -void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep); - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before fitting begins -* LSFitFit() is called -* prior to actual fitting, for each point in data set X_i and each - component of parameters being fited C_j algorithm performs following - steps: - * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], - where C_j is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on C[] - * F(X_i|C) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N*K (points count * parameters count) gradient - evaluations. It is very costly and you should use it only for low - dimensional problems, when you want to be sure that you've - correctly calculated analytic derivatives. You should not use it - in the production code (unless you want to check derivatives - provided by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with LSFitSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -NOTE 4: this function works only for optimizers created with LSFitCreateWFG() - or LSFitCreateFG() constructors. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void lsfitsetgradientcheck(const lsfitstate &state, const double teststep); - -/************************************************************************* -This function builds non-periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - Order of points is important! - N - points count, N>=5 for Akima splines, N>=2 for other types of - splines. - ST - spline type: - * 0 Akima spline - * 1 parabolically terminated Catmull-Rom spline (Tension=0) - * 2 parabolically terminated cubic spline - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p); - - -/************************************************************************* -This function builds non-periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p); - - -/************************************************************************* -This function builds periodic 2-dimensional parametric spline which -starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then -back to (X[0],Y[0]). - -INPUT PARAMETERS: - XY - points, array[0..N-1,0..1]. - XY[I,0:1] corresponds to the Ith point. - XY[N-1,0:1] must be different from XY[0,0:1]. - Order of points is important! - N - points count, N>=3 for other types of splines. - ST - spline type: - * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions - * 2 cubic spline with cyclic boundary conditions - PT - parameterization type: - * 0 uniform - * 1 chord length - * 2 centripetal - -OUTPUT PARAMETERS: - P - parametric spline interpolant - - -NOTES: -* this function assumes that there all consequent points are distinct. - I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. - However, non-consequent points may coincide, i.e. we can have (x0,y0)= - =(x2,y2). -* last point of sequence is NOT equal to the first point. You shouldn't - make curve "explicitly periodic" by making them equal. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p); - - -/************************************************************************* -This function builds periodic 3-dimensional parametric spline which -starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) -and then back to (X[0],Y[0],Z[0]). - -Same as PSpline2Build() function, but for 3D, so we won't duplicate its -description here. - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p); - - -/************************************************************************* -This function returns vector of parameter values correspoding to points. - -I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we -have - (X[0],Y[0]) = PSpline2Calc(P,U[0]), - (X[1],Y[1]) = PSpline2Calc(P,U[1]), - (X[2],Y[2]) = PSpline2Calc(P,U[2]), - ... - -INPUT PARAMETERS: - P - parametric spline interpolant - -OUTPUT PARAMETERS: - N - array size - T - array[0..N-1] - - -NOTES: -* for non-periodic splines U[0]=0, U[0]1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y); - - -/************************************************************************* -This function calculates the value of the parametric spline for a given -value of parameter T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-position - Y - Y-position - Z - Z-position - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z); - - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - -NOTE: - X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y); - - -/************************************************************************* -This function calculates tangent vector for a given value of parameter T - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-component of tangent vector (normalized) - Y - Y-component of tangent vector (normalized) - Z - Z-component of tangent vector (normalized) - -NOTE: - X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z); - - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy); - - -/************************************************************************* -This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - X-derivative - Y - Y-value - DY - Y-derivative - Z - Z-value - DZ - Z-derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz); - - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y); - - -/************************************************************************* -This function calculates first and second derivative with respect to T. - -INPUT PARAMETERS: - P - parametric spline interpolant - T - point: - * T in [0,1] corresponds to interval spanned by points - * for non-periodic splines T<0 (or T>1) correspond to parts of - the curve before the first (after the last) point - * for periodic splines T<0 (or T>1) are projected into [0,1] - by making T=T-floor(T). - -OUTPUT PARAMETERS: - X - X-value - DX - derivative - D2X - second derivative - Y - Y-value - DY - derivative - D2Y - second derivative - Z - Z-value - DZ - derivative - D2Z - second derivative - - - -- ALGLIB PROJECT -- - Copyright 28.05.2010 by Bochkanov Sergey -*************************************************************************/ -void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z); - - -/************************************************************************* -This function calculates arc length, i.e. length of curve between t=a -and t=b. - -INPUT PARAMETERS: - P - parametric spline interpolant - A,B - parameter values corresponding to arc ends: - * B>A will result in positive length returned - * BA will result in positive length returned - * B1) -function in a NX-dimensional space (NX=2 or NX=3). - -Newly created model is empty. It can be used for interpolation right after -creation, but it just returns zeros. You have to add points to the model, -tune interpolation settings, and then call model construction function -RBFBuildModel() which will update model according to your specification. - -USAGE: -1. User creates model with RBFCreate() -2. User adds dataset with RBFSetPoints() (points do NOT have to be on a - regular grid) -3. (OPTIONAL) User chooses polynomial term by calling: - * RBFLinTerm() to set linear term - * RBFConstTerm() to set constant term - * RBFZeroTerm() to set zero term - By default, linear term is used. -4. User chooses specific RBF algorithm to use: either QNN (RBFSetAlgoQNN) - or ML (RBFSetAlgoMultiLayer). -5. User calls RBFBuildModel() function which rebuilds model according to - the specification -6. User may call RBFCalc() to calculate model value at the specified point, - RBFGridCalc() to calculate model values at the points of the regular - grid. User may extract model coefficients with RBFUnpack() call. - -INPUT PARAMETERS: - NX - dimension of the space, NX=2 or NX=3 - NY - function dimension, NY>=1 - -OUTPUT PARAMETERS: - S - RBF model (initially equals to zero) - -NOTE 1: memory requirements. RBF models require amount of memory which is - proportional to the number of data points. Memory is allocated - during model construction, but most of this memory is freed after - model coefficients are calculated. - - Some approximate estimates for N centers with default settings are - given below: - * about 250*N*(sizeof(double)+2*sizeof(int)) bytes of memory is - needed during model construction stage. - * about 15*N*sizeof(double) bytes is needed after model is built. - For example, for N=100000 we may need 0.6 GB of memory to build - model, but just about 0.012 GB to store it. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s); - - -/************************************************************************* -This function adds dataset. - -This function overrides results of the previous calls, i.e. multiple calls -of this function will result in only the last set being added. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call. - XY - points, array[N,NX+NY]. One row corresponds to one point - in the dataset. First NX elements are coordinates, next - NY elements are function values. Array may be larger than - specific, in this case only leading [N,NX+NY] elements - will be used. - N - number of points in the dataset - -After you've added dataset and (optionally) tuned algorithm settings you -should call RBFBuildModel() in order to build a model for you. - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n); -void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy); - - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-QNN and it is good for point sets with -following properties: -a) all points are distinct -b) all points are well separated. -c) points distribution is approximately uniform. There is no "contour - lines", clusters of points, or other small-scale structures. - -Algorithm description: -1) interpolation centers are allocated to data points -2) interpolation radii are calculated as distances to the nearest centers - times Q coefficient (where Q is a value from [0.75,1.50]). -3) after performing (2) radii are transformed in order to avoid situation - when single outlier has very large radius and influences many points - across all dataset. Transformation has following form: - new_r[i] = min(r[i],Z*median(r[])) - where r[i] is I-th radius, median() is a median radius across entire - dataset, Z is user-specified value which controls amount of deviation - from median radius. - -When (a) is violated, we will be unable to build RBF model. When (b) or -(c) are violated, model will be built, but interpolation quality will be -low. See http://www.alglib.net/interpolation/ for more information on this -subject. - -This algorithm is used by default. - -Additional Q parameter controls smoothness properties of the RBF basis: -* Q<0.75 will give perfectly conditioned basis, but terrible smoothness - properties (RBF interpolant will have sharp peaks around function values) -* Q around 1.0 gives good balance between smoothness and condition number -* Q>1.5 will lead to badly conditioned systems and slow convergence of the - underlying linear solver (although smoothness will be very good) -* Q>2.0 will effectively make optimizer useless because it won't converge - within reasonable amount of iterations. It is possible to set such large - Q, but it is advised not to do so. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Q - Q parameter, Q>0, recommended value - 1.0 - Z - Z parameter, Z>0, recommended value - 5.0 - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z); -void rbfsetalgoqnn(const rbfmodel &s); - - -/************************************************************************* -This function sets RBF interpolation algorithm. ALGLIB supports several -RBF algorithms with different properties. - -This algorithm is called RBF-ML. It builds multilayer RBF model, i.e. -model with subsequently decreasing radii, which allows us to combine -smoothness (due to large radii of the first layers) with exactness (due -to small radii of the last layers) and fast convergence. - -Internally RBF-ML uses many different means of acceleration, from sparse -matrices to KD-trees, which results in algorithm whose working time is -roughly proportional to N*log(N)*Density*RBase^2*NLayers, where N is a -number of points, Density is an average density if points per unit of the -interpolation space, RBase is an initial radius, NLayers is a number of -layers. - -RBF-ML is good for following kinds of interpolation problems: -1. "exact" problems (perfect fit) with well separated points -2. least squares problems with arbitrary distribution of points (algorithm - gives perfect fit where it is possible, and resorts to least squares - fit in the hard areas). -3. noisy problems where we want to apply some controlled amount of - smoothing. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - RBase - RBase parameter, RBase>0 - NLayers - NLayers parameter, NLayers>0, recommended value to start - with - about 5. - LambdaV - regularization value, can be useful when solving problem - in the least squares sense. Optimal lambda is problem- - dependent and require trial and error. In our experience, - good lambda can be as large as 0.1, and you can use 0.001 - as initial guess. - Default value - 0.01, which is used when LambdaV is not - given. You can specify zero value, but it is not - recommended to do so. - -TUNING ALGORITHM - -In order to use this algorithm you have to choose three parameters: -* initial radius RBase -* number of layers in the model NLayers -* regularization coefficient LambdaV - -Initial radius is easy to choose - you can pick any number several times -larger than the average distance between points. Algorithm won't break -down if you choose radius which is too large (model construction time will -increase, but model will be built correctly). - -Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used -by the last layer) will be smaller than the typical distance between -points. In case model error is too large, you can increase number of -layers. Having more layers will make model construction and evaluation -proportionally slower, but it will allow you to have model which precisely -fits your data. From the other side, if you want to suppress noise, you -can DECREASE number of layers to make your model less flexible. - -Regularization coefficient LambdaV controls smoothness of the individual -models built for each layer. We recommend you to use default value in case -you don't want to tune this parameter, because having non-zero LambdaV -accelerates and stabilizes internal iterative algorithm. In case you want -to suppress noise you can use LambdaV as additional parameter (larger -value = more smoothness) to tune. - -TYPICAL ERRORS - -1. Using initial radius which is too large. Memory requirements of the - RBF-ML are roughly proportional to N*Density*RBase^2 (where Density is - an average density of points per unit of the interpolation space). In - the extreme case of the very large RBase we will need O(N^2) units of - memory - and many layers in order to decrease radius to some reasonably - small value. - -2. Using too small number of layers - RBF models with large radius are not - flexible enough to reproduce small variations in the target function. - You need many layers with different radii, from large to small, in - order to have good model. - -3. Using initial radius which is too small. You will get model with - "holes" in the areas which are too far away from interpolation centers. - However, algorithm will work correctly (and quickly) in this case. - -4. Using too many layers - you will get too large and too slow model. This - model will perfectly reproduce your function, but maybe you will be - able to achieve similar results with less layers (and less memory). - - -- ALGLIB -- - Copyright 02.03.2012 by Bochkanov Sergey -*************************************************************************/ -void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav); -void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers); - - -/************************************************************************* -This function sets linear term (model is a sum of radial basis functions -plus linear polynomial). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetlinterm(const rbfmodel &s); - - -/************************************************************************* -This function sets constant term (model is a sum of radial basis functions -plus constant). This function won't have effect until next call to -RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetconstterm(const rbfmodel &s); - - -/************************************************************************* -This function sets zero term (model is a sum of radial basis functions -without polynomial term). This function won't have effect until next call -to RBFBuildModel(). - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - -NOTE: this function has some serialization-related subtleties. We - recommend you to study serialization examples from ALGLIB Reference - Manual if you want to perform serialization of your models. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfsetzeroterm(const rbfmodel &s); - - -/************************************************************************* -This function builds RBF model and returns report (contains some -information which can be used for evaluation of the algorithm properties). - -Call to this function modifies RBF model by calculating its centers/radii/ -weights and saving them into RBFModel structure. Initially RBFModel -contain zero coefficients, but after call to this function we will have -coefficients which were calculated in order to fit our dataset. - -After you called this function you can call RBFCalc(), RBFGridCalc() and -other model calculation functions. - -INPUT PARAMETERS: - S - RBF model, initialized by RBFCreate() call - Rep - report: - * Rep.TerminationType: - * -5 - non-distinct basis function centers were detected, - interpolation aborted - * -4 - nonconvergence of the internal SVD solver - * 1 - successful termination - Fields are used for debugging purposes: - * Rep.IterationsCount - iterations count of the LSQR solver - * Rep.NMV - number of matrix-vector products - * Rep.ARows - rows count for the system matrix - * Rep.ACols - columns count for the system matrix - * Rep.ANNZ - number of significantly non-zero elements - (elements above some algorithm-determined threshold) - -NOTE: failure to build model will leave current state of the structure -unchanged. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfbuildmodel(const rbfmodel &s, rbfreport &rep); - - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=2 -(2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -If you want to calculate function values many times, consider using -RBFGridCalc2(), which is far more efficient than many subsequent calls to -RBFCalc2(). - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc2(const rbfmodel &s, const double x0, const double x1); - - -/************************************************************************* -This function calculates values of the RBF model in the given point. - -This function should be used when we have NY=1 (scalar function) and NX=3 -(3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If -you have general situation (NX-dimensional space, NY-dimensional function) -you should use general, less efficient implementation RBFCalc(). - -This function returns 0.0 when: -* model is not initialized -* NX<>3 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - first coordinate, finite number - X1 - second coordinate, finite number - X2 - third coordinate, finite number - -RESULT: - value of the model or 0.0 (as defined above) - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2); - - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -This is general function which can be used for arbitrary NX (dimension of -the space of arguments) and NY (dimension of the function itself). However -when you have NY=1 you may find more convenient to use RBFCalc2() or -RBFCalc3(). - -This function returns 0.0 when model is not initialized. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is out-parameter and - reallocated after call to this function. In case you want - to reuse previously allocated Y, you may use RBFCalcBuf(), - which reallocates Y only when it is too small. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -This function calculates values of the RBF model at the given point. - -Same as RBFCalc(), but does not reallocate Y when in is large enough to -store function values. - -INPUT PARAMETERS: - S - RBF model - X - coordinates, array[NX]. - X may have more than NX elements, in this case only - leading NX will be used. - Y - possibly preallocated array - -OUTPUT PARAMETERS: - Y - function value, array[NY]. Y is not reallocated when it - is larger than NY. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -This function calculates values of the RBF model at the regular grid. - -Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J]) - -This function returns 0.0 when: -* model is not initialized -* NX<>2 - *NY<>1 - -INPUT PARAMETERS: - S - RBF model - X0 - array of grid nodes, first coordinates, array[N0] - N0 - grid size (number of nodes) in the first dimension - X1 - array of grid nodes, second coordinates, array[N1] - N1 - grid size (number of nodes) in the second dimension - -OUTPUT PARAMETERS: - Y - function values, array[N0,N1]. Y is out-variable and - is reallocated by this function. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfgridcalc2(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_2d_array &y); - - -/************************************************************************* -This function "unpacks" RBF model by extracting its coefficients. - -INPUT PARAMETERS: - S - RBF model - -OUTPUT PARAMETERS: - NX - dimensionality of argument - NY - dimensionality of the target function - XWR - model information, array[NC,NX+NY+1]. - One row of the array corresponds to one basis function: - * first NX columns - coordinates of the center - * next NY columns - weights, one per dimension of the - function being modelled - * last column - radius, same for all dimensions of - the function being modelled - NC - number of the centers - V - polynomial term , array[NY,NX+1]. One row per one - dimension of the function being modelled. First NX - elements are linear coefficients, V[NX] is equal to the - constant part. - - -- ALGLIB -- - Copyright 13.12.2011 by Bochkanov Sergey -*************************************************************************/ -void rbfunpack(const rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v); - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X. - -Input parameters: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y- point - -Result: - S(x,y) - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -double spline2dcalc(const spline2dinterpolant &c, const double x, const double y); - - -/************************************************************************* -This subroutine calculates the value of the bilinear or bicubic spline at -the given point X and its derivatives. - -Input parameters: - C - spline interpolant. - X, Y- point - -Output parameters: - F - S(x,y) - FX - dS(x,y)/dX - FY - dS(x,y)/dY - FXY - d2S(x,y)/dXdY - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy); - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -Input parameters: - C - spline interpolant - AX, BX - transformation coefficients: x = A*t + B - AY, BY - transformation coefficients: y = A*u + B -Result: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by); - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -Input parameters: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y) + B - -Output parameters: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 30.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b); - - -/************************************************************************* -This subroutine makes the copy of the spline model. - -Input parameters: - C - spline interpolant - -Output parameters: - CC - spline copy - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc); - - -/************************************************************************* -Bicubic spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 15 May, 2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth); - - -/************************************************************************* -Bilinear spline resampling - -Input parameters: - A - function values at the old grid, - array[0..OldHeight-1, 0..OldWidth-1] - OldHeight - old grid height, OldHeight>1 - OldWidth - old grid width, OldWidth>1 - NewHeight - new grid height, NewHeight>1 - NewWidth - new grid width, NewWidth>1 - -Output parameters: - B - function values at the new grid, - array[0..NewHeight-1, 0..NewWidth-1] - - -- ALGLIB routine -- - 09.07.2007 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth); - - -/************************************************************************* -This subroutine builds bilinear vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c); - - -/************************************************************************* -This subroutine builds bicubic vector-valued spline. - -Input parameters: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - F - function values, array[0..M*N*D-1]: - * first D elements store D values at (X[0],Y[0]) - * next D elements store D values at (X[1],Y[0]) - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(J*N+I)...D*(J*N+I)+D-1]. - M,N - grid size, M>=2, N>=2 - D - vector dimension, D>=1 - -Output parameters: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c); - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f); - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y- point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f); - - -/************************************************************************* -This subroutine unpacks two-dimensional spline into the coefficients table - -Input parameters: - C - spline interpolant. - -Result: - M, N- grid size (x-axis and y-axis) - D - number of components - Tbl - coefficients table, unpacked format, - D - components: [0..(N-1)*(M-1)*D-1, 0..19]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index): - K := T + I*D + J*D*(N-1) - - K-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[K,0] = X[i] - Tbl[K,1] = X[i+1] - Tbl[K,2] = Y[j] - Tbl[K,3] = Y[j+1] - Tbl[K,4] = C00 - Tbl[K,5] = C01 - Tbl[K,6] = C02 - Tbl[K,7] = C03 - Tbl[K,8] = C10 - Tbl[K,9] = C11 - ... - Tbl[K,19] = C33 - On each grid square spline is equals to: - S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) - t = x-x[j] - u = y-y[i] - - -- ALGLIB PROJECT -- - Copyright 16.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl); - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBilinearV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c); - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DBuildBicubicV(), which is more -flexible and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 05.07.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c); - - -/************************************************************************* -This subroutine was deprecated in ALGLIB 3.6.0 - -We recommend you to switch to Spline2DUnpackV(), which is more flexible -and accepts its arguments in more convenient order. - - -- ALGLIB PROJECT -- - Copyright 29.06.2007 by Bochkanov Sergey -*************************************************************************/ -void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl); - -/************************************************************************* -This subroutine calculates the value of the trilinear or tricubic spline at -the given point (X,Y,Z). - -INPUT PARAMETERS: - C - coefficients table. - Built by BuildBilinearSpline or BuildBicubicSpline. - X, Y, - Z - point - -Result: - S(x,y,z) - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z); - - -/************************************************************************* -This subroutine performs linear transformation of the spline argument. - -INPUT PARAMETERS: - C - spline interpolant - AX, BX - transformation coefficients: x = A*u + B - AY, BY - transformation coefficients: y = A*v + B - AZ, BZ - transformation coefficients: z = A*w + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz); - - -/************************************************************************* -This subroutine performs linear transformation of the spline. - -INPUT PARAMETERS: - C - spline interpolant. - A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B - -OUTPUT PARAMETERS: - C - transformed spline - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b); - - -/************************************************************************* -Trilinear spline resampling - -INPUT PARAMETERS: - A - array[0..OldXCount*OldYCount*OldZCount-1], function - values at the old grid, : - A[0] x=0,y=0,z=0 - A[1] x=1,y=0,z=0 - A[..] ... - A[..] x=oldxcount-1,y=0,z=0 - A[..] x=0,y=1,z=0 - A[..] ... - ... - OldZCount - old Z-count, OldZCount>1 - OldYCount - old Y-count, OldYCount>1 - OldXCount - old X-count, OldXCount>1 - NewZCount - new Z-count, NewZCount>1 - NewYCount - new Y-count, NewYCount>1 - NewXCount - new X-count, NewXCount>1 - -OUTPUT PARAMETERS: - B - array[0..NewXCount*NewYCount*NewZCount-1], function - values at the new grid: - B[0] x=0,y=0,z=0 - B[1] x=1,y=0,z=0 - B[..] ... - B[..] x=newxcount-1,y=0,z=0 - B[..] x=0,y=1,z=0 - B[..] ... - ... - - -- ALGLIB routine -- - 26.04.2012 - Copyright by Bochkanov Sergey -*************************************************************************/ -void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b); - - -/************************************************************************* -This subroutine builds trilinear vector-valued spline. - -INPUT PARAMETERS: - X - spline abscissas, array[0..N-1] - Y - spline ordinates, array[0..M-1] - Z - spline applicates, array[0..L-1] - F - function values, array[0..M*N*L*D-1]: - * first D elements store D values at (X[0],Y[0],Z[0]) - * next D elements store D values at (X[1],Y[0],Z[0]) - * next D elements store D values at (X[2],Y[0],Z[0]) - * ... - * next D elements store D values at (X[0],Y[1],Z[0]) - * next D elements store D values at (X[1],Y[1],Z[0]) - * next D elements store D values at (X[2],Y[1],Z[0]) - * ... - * next D elements store D values at (X[0],Y[0],Z[1]) - * next D elements store D values at (X[1],Y[0],Z[1]) - * next D elements store D values at (X[2],Y[0],Z[1]) - * ... - * general form - D function values at (X[i],Y[j]) are stored - at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. - M,N, - L - grid size, M>=2, N>=2, L>=2 - D - vector dimension, D>=1 - -OUTPUT PARAMETERS: - C - spline interpolant - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c); - - -/************************************************************************* -This subroutine calculates bilinear or bicubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - F - output buffer, possibly preallocated array. In case array size - is large enough to store result, it is not reallocated. Array - which is too short will be reallocated - -OUTPUT PARAMETERS: - F - array[D] (or larger) which stores function values - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f); - - -/************************************************************************* -This subroutine calculates trilinear or tricubic vector-valued spline at the -given point (X,Y,Z). - -INPUT PARAMETERS: - C - spline interpolant. - X, Y, - Z - point - -OUTPUT PARAMETERS: - F - array[D] which stores function values. F is out-parameter and - it is reallocated after call to this function. In case you - want to reuse previously allocated F, you may use - Spline2DCalcVBuf(), which reallocates F only when it is too - small. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f); - - -/************************************************************************* -This subroutine unpacks tri-dimensional spline into the coefficients table - -INPUT PARAMETERS: - C - spline interpolant. - -Result: - N - grid size (X) - M - grid size (Y) - L - grid size (Z) - D - number of components - SType- spline type. Currently, only one spline type is supported: - trilinear spline, as indicated by SType=1. - Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. - For T=0..D-1 (component index), I = 0...N-2 (x index), - J=0..M-2 (y index), K=0..L-2 (z index): - Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), - - Q-th row stores decomposition for T-th component of the - vector-valued function - - Tbl[Q,0] = X[i] - Tbl[Q,1] = X[i+1] - Tbl[Q,2] = Y[j] - Tbl[Q,3] = Y[j+1] - Tbl[Q,4] = Z[k] - Tbl[Q,5] = Z[k+1] - - Tbl[Q,6] = C000 - Tbl[Q,7] = C100 - Tbl[Q,8] = C010 - Tbl[Q,9] = C110 - Tbl[Q,10]= C001 - Tbl[Q,11]= C101 - Tbl[Q,12]= C011 - Tbl[Q,13]= C111 - On each grid square spline is equals to: - S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) - t = x-x[j] - u = y-y[i] - v = z-z[k] - - NOTE: format of Tbl is given for SType=1. Future versions of - ALGLIB can use different formats for different values of - SType. - - -- ALGLIB PROJECT -- - Copyright 26.04.2012 by Bochkanov Sergey -*************************************************************************/ -void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -double idwcalc(idwinterpolant* z, - /* Real */ ae_vector* x, - ae_state *_state); -void idwbuildmodifiedshepard(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state); -void idwbuildmodifiedshepardr(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - double r, - idwinterpolant* z, - ae_state *_state); -void idwbuildnoisy(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t nx, - ae_int_t d, - ae_int_t nq, - ae_int_t nw, - idwinterpolant* z, - ae_state *_state); -ae_bool _idwinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _idwinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _idwinterpolant_clear(void* _p); -void _idwinterpolant_destroy(void* _p); -double barycentriccalc(barycentricinterpolant* b, - double t, - ae_state *_state); -void barycentricdiff1(barycentricinterpolant* b, - double t, - double* f, - double* df, - ae_state *_state); -void barycentricdiff2(barycentricinterpolant* b, - double t, - double* f, - double* df, - double* d2f, - ae_state *_state); -void barycentriclintransx(barycentricinterpolant* b, - double ca, - double cb, - ae_state *_state); -void barycentriclintransy(barycentricinterpolant* b, - double ca, - double cb, - ae_state *_state); -void barycentricunpack(barycentricinterpolant* b, - ae_int_t* n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_state *_state); -void barycentricbuildxyw(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - barycentricinterpolant* b, - ae_state *_state); -void barycentricbuildfloaterhormann(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t d, - barycentricinterpolant* b, - ae_state *_state); -void barycentriccopy(barycentricinterpolant* b, - barycentricinterpolant* b2, - ae_state *_state); -ae_bool _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _barycentricinterpolant_clear(void* _p); -void _barycentricinterpolant_destroy(void* _p); -void polynomialbar2cheb(barycentricinterpolant* p, - double a, - double b, - /* Real */ ae_vector* t, - ae_state *_state); -void polynomialcheb2bar(/* Real */ ae_vector* t, - ae_int_t n, - double a, - double b, - barycentricinterpolant* p, - ae_state *_state); -void polynomialbar2pow(barycentricinterpolant* p, - double c, - double s, - /* Real */ ae_vector* a, - ae_state *_state); -void polynomialpow2bar(/* Real */ ae_vector* a, - ae_int_t n, - double c, - double s, - barycentricinterpolant* p, - ae_state *_state); -void polynomialbuild(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state); -void polynomialbuildeqdist(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state); -void polynomialbuildcheb1(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state); -void polynomialbuildcheb2(double a, - double b, - /* Real */ ae_vector* y, - ae_int_t n, - barycentricinterpolant* p, - ae_state *_state); -double polynomialcalceqdist(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state); -double polynomialcalccheb1(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state); -double polynomialcalccheb2(double a, - double b, - /* Real */ ae_vector* f, - ae_int_t n, - double t, - ae_state *_state); -void spline1dbuildlinear(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state); -void spline1dbuildcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - spline1dinterpolant* c, - ae_state *_state); -void spline1dgriddiffcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d, - ae_state *_state); -void spline1dgriddiff2cubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* d1, - /* Real */ ae_vector* d2, - ae_state *_state); -void spline1dconvcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - ae_state *_state); -void spline1dconvdiffcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - /* Real */ ae_vector* d2, - ae_state *_state); -void spline1dconvdiff2cubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundltype, - double boundl, - ae_int_t boundrtype, - double boundr, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y2, - /* Real */ ae_vector* d2, - /* Real */ ae_vector* dd2, - ae_state *_state); -void spline1dbuildcatmullrom(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t boundtype, - double tension, - spline1dinterpolant* c, - ae_state *_state); -void spline1dbuildhermite(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* d, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state); -void spline1dbuildakima(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state); -double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state); -void spline1ddiff(spline1dinterpolant* c, - double x, - double* s, - double* ds, - double* d2s, - ae_state *_state); -void spline1dcopy(spline1dinterpolant* c, - spline1dinterpolant* cc, - ae_state *_state); -void spline1dunpack(spline1dinterpolant* c, - ae_int_t* n, - /* Real */ ae_matrix* tbl, - ae_state *_state); -void spline1dlintransx(spline1dinterpolant* c, - double a, - double b, - ae_state *_state); -void spline1dlintransy(spline1dinterpolant* c, - double a, - double b, - ae_state *_state); -double spline1dintegrate(spline1dinterpolant* c, - double x, - ae_state *_state); -void spline1dconvdiffinternal(/* Real */ ae_vector* xold, - /* Real */ ae_vector* yold, - /* Real */ ae_vector* dold, - ae_int_t n, - /* Real */ ae_vector* x2, - ae_int_t n2, - /* Real */ ae_vector* y, - ae_bool needy, - /* Real */ ae_vector* d1, - ae_bool needd1, - /* Real */ ae_vector* d2, - ae_bool needd2, - ae_state *_state); -void spline1drootsandextrema(spline1dinterpolant* c, - /* Real */ ae_vector* r, - ae_int_t* nr, - ae_bool* dr, - /* Real */ ae_vector* e, - /* Integer */ ae_vector* et, - ae_int_t* ne, - ae_bool* de, - ae_state *_state); -void heapsortdpoints(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* d, - ae_int_t n, - ae_state *_state); -void solvepolinom2(double p0, - double m0, - double p1, - double m1, - double* x0, - double* x1, - ae_int_t* nr, - ae_state *_state); -void solvecubicpolinom(double pa, - double ma, - double pb, - double mb, - double a, - double b, - double* x0, - double* x1, - double* x2, - double* ex0, - double* ex1, - ae_int_t* nr, - ae_int_t* ne, - /* Real */ ae_vector* tempdata, - ae_state *_state); -ae_int_t bisectmethod(double pa, - double ma, - double pb, - double mb, - double a, - double b, - double* x, - ae_state *_state); -void spline1dbuildmonotone(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - spline1dinterpolant* c, - ae_state *_state); -ae_bool _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _spline1dinterpolant_clear(void* _p); -void _spline1dinterpolant_destroy(void* _p); -void polynomialfit(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* p, - polynomialfitreport* rep, - ae_state *_state); -void polynomialfitwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* p, - polynomialfitreport* rep, - ae_state *_state); -void barycentricfitfloaterhormannwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state); -void barycentricfitfloaterhormann(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - barycentricinterpolant* b, - barycentricfitreport* rep, - ae_state *_state); -void spline1dfitpenalized(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - double rho, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void spline1dfitpenalizedw(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - ae_int_t m, - double rho, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void spline1dfitcubicwc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void spline1dfithermitewc(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void spline1dfitcubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void spline1dfithermite(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - spline1dinterpolant* s, - spline1dfitreport* rep, - ae_state *_state); -void lsfitlinearw(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -void lsfitlinearwc(/* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_matrix* cmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -void lsfitlinear(/* Real */ ae_vector* y, - /* Real */ ae_matrix* fmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -void lsfitlinearc(/* Real */ ae_vector* y, - /* Real */ ae_matrix* fmatrix, - /* Real */ ae_matrix* cmatrix, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -void lsfitcreatewf(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - double diffstep, - lsfitstate* state, - ae_state *_state); -void lsfitcreatef(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - double diffstep, - lsfitstate* state, - ae_state *_state); -void lsfitcreatewfg(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_bool cheapfg, - lsfitstate* state, - ae_state *_state); -void lsfitcreatefg(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - ae_bool cheapfg, - lsfitstate* state, - ae_state *_state); -void lsfitcreatewfgh(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - lsfitstate* state, - ae_state *_state); -void lsfitcreatefgh(/* Real */ ae_matrix* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* c, - ae_int_t n, - ae_int_t m, - ae_int_t k, - lsfitstate* state, - ae_state *_state); -void lsfitsetcond(lsfitstate* state, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state); -void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state); -void lsfitsetscale(lsfitstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void lsfitsetbc(lsfitstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -ae_bool lsfititeration(lsfitstate* state, ae_state *_state); -void lsfitresults(lsfitstate* state, - ae_int_t* info, - /* Real */ ae_vector* c, - lsfitreport* rep, - ae_state *_state); -void lsfitsetgradientcheck(lsfitstate* state, - double teststep, - ae_state *_state); -void lsfitscalexy(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* w, - ae_int_t n, - /* Real */ ae_vector* xc, - /* Real */ ae_vector* yc, - /* Integer */ ae_vector* dc, - ae_int_t k, - double* xa, - double* xb, - double* sa, - double* sb, - /* Real */ ae_vector* xoriginal, - /* Real */ ae_vector* yoriginal, - ae_state *_state); -ae_bool _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _polynomialfitreport_clear(void* _p); -void _polynomialfitreport_destroy(void* _p); -ae_bool _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _barycentricfitreport_clear(void* _p); -void _barycentricfitreport_destroy(void* _p); -ae_bool _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _spline1dfitreport_clear(void* _p); -void _spline1dfitreport_destroy(void* _p); -ae_bool _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _lsfitreport_clear(void* _p); -void _lsfitreport_destroy(void* _p); -ae_bool _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _lsfitstate_clear(void* _p); -void _lsfitstate_destroy(void* _p); -void pspline2build(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline2interpolant* p, - ae_state *_state); -void pspline3build(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline3interpolant* p, - ae_state *_state); -void pspline2buildperiodic(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline2interpolant* p, - ae_state *_state); -void pspline3buildperiodic(/* Real */ ae_matrix* xy, - ae_int_t n, - ae_int_t st, - ae_int_t pt, - pspline3interpolant* p, - ae_state *_state); -void pspline2parametervalues(pspline2interpolant* p, - ae_int_t* n, - /* Real */ ae_vector* t, - ae_state *_state); -void pspline3parametervalues(pspline3interpolant* p, - ae_int_t* n, - /* Real */ ae_vector* t, - ae_state *_state); -void pspline2calc(pspline2interpolant* p, - double t, - double* x, - double* y, - ae_state *_state); -void pspline3calc(pspline3interpolant* p, - double t, - double* x, - double* y, - double* z, - ae_state *_state); -void pspline2tangent(pspline2interpolant* p, - double t, - double* x, - double* y, - ae_state *_state); -void pspline3tangent(pspline3interpolant* p, - double t, - double* x, - double* y, - double* z, - ae_state *_state); -void pspline2diff(pspline2interpolant* p, - double t, - double* x, - double* dx, - double* y, - double* dy, - ae_state *_state); -void pspline3diff(pspline3interpolant* p, - double t, - double* x, - double* dx, - double* y, - double* dy, - double* z, - double* dz, - ae_state *_state); -void pspline2diff2(pspline2interpolant* p, - double t, - double* x, - double* dx, - double* d2x, - double* y, - double* dy, - double* d2y, - ae_state *_state); -void pspline3diff2(pspline3interpolant* p, - double t, - double* x, - double* dx, - double* d2x, - double* y, - double* dy, - double* d2y, - double* z, - double* dz, - double* d2z, - ae_state *_state); -double pspline2arclength(pspline2interpolant* p, - double a, - double b, - ae_state *_state); -double pspline3arclength(pspline3interpolant* p, - double a, - double b, - ae_state *_state); -ae_bool _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _pspline2interpolant_clear(void* _p); -void _pspline2interpolant_destroy(void* _p); -ae_bool _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _pspline3interpolant_clear(void* _p); -void _pspline3interpolant_destroy(void* _p); -void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state); -void rbfsetpoints(rbfmodel* s, - /* Real */ ae_matrix* xy, - ae_int_t n, - ae_state *_state); -void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state); -void rbfsetalgomultilayer(rbfmodel* s, - double rbase, - ae_int_t nlayers, - double lambdav, - ae_state *_state); -void rbfsetlinterm(rbfmodel* s, ae_state *_state); -void rbfsetconstterm(rbfmodel* s, ae_state *_state); -void rbfsetzeroterm(rbfmodel* s, ae_state *_state); -void rbfsetcond(rbfmodel* s, - double epsort, - double epserr, - ae_int_t maxits, - ae_state *_state); -void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state); -double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state); -double rbfcalc3(rbfmodel* s, - double x0, - double x1, - double x2, - ae_state *_state); -void rbfcalc(rbfmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void rbfcalcbuf(rbfmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void rbfgridcalc2(rbfmodel* s, - /* Real */ ae_vector* x0, - ae_int_t n0, - /* Real */ ae_vector* x1, - ae_int_t n1, - /* Real */ ae_matrix* y, - ae_state *_state); -void rbfunpack(rbfmodel* s, - ae_int_t* nx, - ae_int_t* ny, - /* Real */ ae_matrix* xwr, - ae_int_t* nc, - /* Real */ ae_matrix* v, - ae_state *_state); -void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state); -void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state); -void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state); -ae_bool _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _rbfmodel_clear(void* _p); -void _rbfmodel_destroy(void* _p); -ae_bool _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _rbfreport_clear(void* _p); -void _rbfreport_destroy(void* _p); -double spline2dcalc(spline2dinterpolant* c, - double x, - double y, - ae_state *_state); -void spline2ddiff(spline2dinterpolant* c, - double x, - double y, - double* f, - double* fx, - double* fy, - double* fxy, - ae_state *_state); -void spline2dlintransxy(spline2dinterpolant* c, - double ax, - double bx, - double ay, - double by, - ae_state *_state); -void spline2dlintransf(spline2dinterpolant* c, - double a, - double b, - ae_state *_state); -void spline2dcopy(spline2dinterpolant* c, - spline2dinterpolant* cc, - ae_state *_state); -void spline2dresamplebicubic(/* Real */ ae_matrix* a, - ae_int_t oldheight, - ae_int_t oldwidth, - /* Real */ ae_matrix* b, - ae_int_t newheight, - ae_int_t newwidth, - ae_state *_state); -void spline2dresamplebilinear(/* Real */ ae_matrix* a, - ae_int_t oldheight, - ae_int_t oldwidth, - /* Real */ ae_matrix* b, - ae_int_t newheight, - ae_int_t newwidth, - ae_state *_state); -void spline2dbuildbilinearv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* f, - ae_int_t d, - spline2dinterpolant* c, - ae_state *_state); -void spline2dbuildbicubicv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* f, - ae_int_t d, - spline2dinterpolant* c, - ae_state *_state); -void spline2dcalcvbuf(spline2dinterpolant* c, - double x, - double y, - /* Real */ ae_vector* f, - ae_state *_state); -void spline2dcalcv(spline2dinterpolant* c, - double x, - double y, - /* Real */ ae_vector* f, - ae_state *_state); -void spline2dunpackv(spline2dinterpolant* c, - ae_int_t* m, - ae_int_t* n, - ae_int_t* d, - /* Real */ ae_matrix* tbl, - ae_state *_state); -void spline2dbuildbilinear(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_matrix* f, - ae_int_t m, - ae_int_t n, - spline2dinterpolant* c, - ae_state *_state); -void spline2dbuildbicubic(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_matrix* f, - ae_int_t m, - ae_int_t n, - spline2dinterpolant* c, - ae_state *_state); -void spline2dunpack(spline2dinterpolant* c, - ae_int_t* m, - ae_int_t* n, - /* Real */ ae_matrix* tbl, - ae_state *_state); -ae_bool _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _spline2dinterpolant_clear(void* _p); -void _spline2dinterpolant_destroy(void* _p); -double spline3dcalc(spline3dinterpolant* c, - double x, - double y, - double z, - ae_state *_state); -void spline3dlintransxyz(spline3dinterpolant* c, - double ax, - double bx, - double ay, - double by, - double az, - double bz, - ae_state *_state); -void spline3dlintransf(spline3dinterpolant* c, - double a, - double b, - ae_state *_state); -void spline3dcopy(spline3dinterpolant* c, - spline3dinterpolant* cc, - ae_state *_state); -void spline3dresampletrilinear(/* Real */ ae_vector* a, - ae_int_t oldzcount, - ae_int_t oldycount, - ae_int_t oldxcount, - ae_int_t newzcount, - ae_int_t newycount, - ae_int_t newxcount, - /* Real */ ae_vector* b, - ae_state *_state); -void spline3dbuildtrilinearv(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - /* Real */ ae_vector* z, - ae_int_t l, - /* Real */ ae_vector* f, - ae_int_t d, - spline3dinterpolant* c, - ae_state *_state); -void spline3dcalcvbuf(spline3dinterpolant* c, - double x, - double y, - double z, - /* Real */ ae_vector* f, - ae_state *_state); -void spline3dcalcv(spline3dinterpolant* c, - double x, - double y, - double z, - /* Real */ ae_vector* f, - ae_state *_state); -void spline3dunpackv(spline3dinterpolant* c, - ae_int_t* n, - ae_int_t* m, - ae_int_t* l, - ae_int_t* d, - ae_int_t* stype, - /* Real */ ae_matrix* tbl, - ae_state *_state); -ae_bool _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _spline3dinterpolant_clear(void* _p); -void _spline3dinterpolant_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _interpolation_pkg_h +#define _interpolation_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "solvers.h" +#include "optimization.h" +#include "specialfunctions.h" +#include "integration.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + double sy; + ae_vector x; + ae_vector y; + ae_vector w; +} barycentricinterpolant; +#endif +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector x; + ae_vector y; + ae_vector tsyw; + ae_vector tsw; + ae_matrix tsxy; + ae_vector tsdist; + kdtreerequestbuffer requestbuffer; +} idwcalcbuffer; +typedef struct +{ + ae_vector dist; + ae_vector x; + ae_vector w; + ae_vector wy; + ae_vector tags; + kdtreerequestbuffer requestbuffer; +} mstabbuffer; +typedef struct +{ + ae_int_t nx; + ae_int_t ny; + ae_vector globalprior; + ae_int_t algotype; + ae_int_t nlayers; + double r0; + double rdecay; + double lambda0; + double lambdalast; + double lambdadecay; + double shepardp; + ae_bool debugprofile; + kdtree tree; + ae_int_t npoints; + ae_vector shepardxy; + idwcalcbuffer buffer; +} idwmodel; +typedef struct +{ + ae_int_t priortermtype; + ae_vector priortermval; + ae_int_t algotype; + ae_int_t nlayers; + double r0; + double rdecay; + double lambda0; + double lambdalast; + double lambdadecay; + double shepardp; + ae_bool debugprofile; + ae_int_t mbatchsize; + double mprogress; + ae_vector xy; + ae_int_t npoints; + ae_int_t nx; + ae_int_t ny; + ae_matrix tmpxy; + ae_matrix tmplayers; + ae_vector tmptags; + ae_vector tmpdist; + kdtree tmptree; + ae_vector tmpmean; +} idwbuilder; +typedef struct +{ + double rmserror; + double avgerror; + double maxerror; + double r2; +} idwreport; +#endif +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool periodic; + ae_int_t n; + ae_int_t k; + ae_int_t continuity; + ae_vector x; + ae_vector c; +} spline1dinterpolant; +typedef struct +{ + ae_int_t terminationtype; + double taskrcond; + double rmserror; + double avgerror; + double avgrelerror; + double maxerror; +} spline1dfitreport; +typedef struct +{ + ae_int_t m; + ae_int_t bfrad; + spline1dinterpolant s0; + spline1dinterpolant s1; + spline1dinterpolant s2; + ae_vector tmpx; + ae_vector tmpy; +} spline1dbbasis; +#endif +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t terminationtype; + double taskrcond; + double rmserror; + double avgerror; + double avgrelerror; + double maxerror; +} polynomialfitreport; +typedef struct +{ + ae_int_t terminationtype; + double taskrcond; + ae_int_t dbest; + double rmserror; + double avgerror; + double avgrelerror; + double maxerror; +} barycentricfitreport; +typedef struct +{ + ae_int_t terminationtype; + double taskrcond; + ae_int_t iterationscount; + ae_int_t varidx; + double rmserror; + double avgerror; + double avgrelerror; + double maxerror; + double wrmserror; + ae_matrix covpar; + ae_vector errpar; + ae_vector errcurve; + ae_vector noise; + double r2; +} lsfitreport; +typedef struct +{ + ae_int_t protocolversion; + ae_int_t formulatype; + ae_int_t optalgo; + ae_int_t m; + ae_int_t k; + double epsx; + ae_int_t maxits; + double stpmax; + ae_bool xrep; + ae_vector c0; + ae_vector c1; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_matrix taskx; + ae_vector tasky; + ae_int_t npoints; + ae_vector taskw; + ae_int_t nweights; + ae_int_t wkind; + ae_int_t wits; + double diffstep; + double teststep; + ae_matrix cleic; + ae_int_t nec; + ae_int_t nic; + ae_int_t nonmonotoniccnt; + ae_bool xupdated; + ae_bool needf; + ae_bool needfg; + ae_int_t pointindex; + ae_vector x; + ae_vector c; + double f; + ae_vector g; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_vector wcur; + ae_vector tmpwk; + ae_vector tmpct; + ae_vector tmp; + ae_vector tmpf; + ae_matrix tmpjac; + ae_matrix tmpjacw; + double tmpnoise; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_int_t repvaridx; + double reprmserror; + double repavgerror; + double repavgrelerror; + double repmaxerror; + double repwrmserror; + lsfitreport rep; + minlmstate optstate; + minlmreport optrep; + ae_int_t prevnpt; + ae_int_t prevalgo; + rcommstate rstate; +} lsfitstate; +#endif +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t nfev; + ae_int_t iterationscount; +} fitsphereinternalreport; +#endif +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_bool periodic; + ae_vector p; + spline1dinterpolant x; + spline1dinterpolant y; +} pspline2interpolant; +typedef struct +{ + ae_int_t n; + ae_bool periodic; + ae_vector p; + spline1dinterpolant x; + spline1dinterpolant y; + spline1dinterpolant z; +} pspline3interpolant; +#endif +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector calcbufxcx; + ae_matrix calcbufx; + ae_vector calcbuftags; + kdtreerequestbuffer requestbuffer; +} rbfv1calcbuffer; +typedef struct +{ + ae_int_t ny; + ae_int_t nx; + ae_int_t nc; + ae_int_t nl; + kdtree tree; + ae_matrix xc; + ae_matrix wr; + double rmax; + ae_matrix v; + ae_vector calcbufxcx; + ae_matrix calcbufx; + ae_vector calcbuftags; +} rbfv1model; +typedef struct +{ + ae_vector tx; + ae_vector cx; + ae_vector ty; + ae_vector flag0; + ae_vector flag1; + ae_vector flag2; + ae_vector flag12; + ae_vector expbuf0; + ae_vector expbuf1; + ae_vector expbuf2; + kdtreerequestbuffer requestbuf; + ae_matrix calcbufx; + ae_vector calcbuftags; +} gridcalc3v1buf; +typedef struct +{ + ae_int_t arows; + ae_int_t acols; + ae_int_t annz; + ae_int_t iterationscount; + ae_int_t nmv; + ae_int_t terminationtype; +} rbfv1report; +#endif +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t maxp; + ae_int_t precomputedcount; + ae_vector tdoublefactorial; + ae_vector tfactorial; + ae_vector tsqrtfactorial; + ae_vector tpowminus1; + ae_vector tpowi; + ae_vector tpowminusi; + ae_vector ynma; + ae_vector pnma; + ae_vector pnmb; + ae_vector pmmc; + ae_vector pmmcdiag; + ae_vector mnma; + ae_vector nnma; + ae_vector inma; +} biharmonicevaluator; +typedef struct +{ + double c0; + double c1; + double c2; + double rmax; + double useatdistance; + ae_int_t ny; + ae_int_t p; + ae_int_t sizen; + ae_int_t sizem; + ae_int_t stride; + ae_int_t sizeinner; + ae_vector tbln; + ae_vector tblm; + ae_vector tblmodn; + ae_vector tblmodm; + ae_vector tblpowrmax; + ae_vector tblrmodmn; + double maxsumabs; + ae_vector funcsphericaly; + ae_vector tpowr; +} biharmonicpanel; +#endif +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector x; + ae_vector y; + ae_vector coeffbuf; + ae_vector funcbuf; + ae_vector wrkbuf; + ae_vector mindist2; + ae_vector df1; + ae_vector df2; + ae_vector x2; + ae_vector y2; + ae_matrix deltabuf; +} rbf3evaluatorbuffer; +typedef struct +{ + ae_int_t paneltype; + double clusterrad; + ae_vector clustercenter; + double c0; + double c1; + double c2; + double c3; + ae_int_t farfieldexpansion; + double farfielddistance; + ae_int_t idx0; + ae_int_t idx1; + ae_int_t childa; + ae_int_t childb; + ae_vector ptidx; + ae_matrix xt; + ae_matrix wt; + biharmonicpanel bhexpansion; + rbf3evaluatorbuffer tgtbuf; +} rbf3panel; +typedef struct +{ + ae_int_t n; + ae_int_t nx; + ae_int_t ny; + ae_int_t maxpanelsize; + ae_int_t functype; + double funcparam; + ae_matrix permx; + ae_vector origptidx; + ae_matrix wstoredorig; + ae_bool isloaded; + ae_obj_array panels; + biharmonicevaluator bheval; + ae_shared_pool bufferpool; + ae_matrix tmpx3w; + ae_bool usedebugcounters; + ae_int_t dbgpanel2panelcnt; + ae_int_t dbgfield2panelcnt; + ae_int_t dbgpanelscnt; +} rbf3fastevaluator; +typedef struct +{ + ae_int_t n; + ae_int_t storagetype; + ae_matrix f; + ae_int_t nx; + ae_int_t functype; + double funcparam; + ae_int_t chunksize; + ae_vector entireset; + ae_matrix x; + ae_matrix xtchunked; + ae_shared_pool bufferpool; + ae_vector chunk1; +} rbf3evaluator; +typedef struct +{ + ae_vector x; + rbf3evaluatorbuffer evalbuf; + ae_vector x123; + ae_vector y123; + ae_matrix x2d; + ae_matrix y2d; + ae_vector xg; + ae_vector yg; +} rbfv3calcbuffer; +typedef struct +{ + ae_bool dodetailedtrace; + ae_int_t ntotal; + ae_int_t nx; + ae_matrix xx; + ae_int_t functype; + double funcparam; + double roughdatasetdiameter; + ae_int_t nglobal; + ae_vector globalgrid; + double globalgridseparation; + ae_int_t nlocal; + ae_int_t ncorrection; + double correctorgrowth; + ae_int_t batchsize; + double lambdav; + ae_int_t aterm; + kdtree kdt; + kdtree kdt1; + kdtree kdt2; + ae_shared_pool bufferpool; + ae_shared_pool chunksproducer; + ae_shared_pool chunkspool; + ae_vector wrkidx; +} acbfbuilder; +typedef struct +{ + ae_vector bflags; + kdtreerequestbuffer kdtbuf; + kdtreerequestbuffer kdt1buf; + kdtreerequestbuffer kdt2buf; + ae_vector tmpboxmin; + ae_vector tmpboxmax; + ae_vector currentnodes; + ae_vector neighbors; + ae_vector chosenneighbors; + ae_vector y; + ae_vector z; + ae_vector d; + ae_matrix atwrk; + ae_matrix xq; + ae_matrix q; + ae_matrix q1; + ae_matrix wrkq; + ae_matrix b; + ae_matrix c; + ae_vector choltmp; + ae_vector tau; + ae_matrix r; + ae_vector perm; +} acbfbuffer; +typedef struct +{ + ae_int_t ntargetrows; + ae_int_t ntargetcols; + ae_vector targetrows; + ae_vector targetcols; + ae_matrix s; +} acbfchunk; +typedef struct +{ + ae_vector bflags; + ae_vector idx2preccol; + kdtreerequestbuffer kdtbuf; + ae_vector tmpboxmin; + ae_vector tmpboxmax; +} rbf3ddmbuffer; +typedef struct +{ + ae_bool isvalid; + ae_int_t ntarget; + ae_vector targetnodes; + ae_int_t nwork; + ae_vector workingnodes; + ae_matrix regsystem; + ae_int_t decomposition; + ae_matrix wrklu; + ae_matrix rhs; + ae_matrix qtrhs; + ae_matrix sol; + ae_matrix pred; + ae_vector wrkp; + ae_matrix wrkq; + ae_matrix wrkr; +} rbf3ddmsubproblem; +typedef struct +{ + double lambdav; + kdtree kdt; + ae_shared_pool bufferpool; + ae_int_t subproblemscnt; + ae_shared_pool subproblemspool; + ae_shared_pool subproblemsbuffer; + ae_int_t ncorrector; + ae_matrix corrq; + ae_matrix corrr; + ae_vector corrnodes; + ae_matrix corrx; + ae_matrix tmpres1; + ae_matrix tmpupd1; + ae_int_t cntlu; + ae_int_t cntregqr; +} rbf3ddmsolver; +typedef struct +{ + ae_int_t ny; + ae_int_t nx; + ae_int_t bftype; + double bfparam; + ae_vector s; + ae_matrix v; + ae_vector cw; + ae_vector pointindexes; + ae_int_t nc; + rbf3evaluator evaluator; + rbf3fastevaluator fasteval; + ae_matrix wchunked; + rbfv3calcbuffer calcbuf; + ae_bool dbgregqrusedforddm; + double dbgworstfirstdecay; +} rbfv3model; +typedef struct +{ + ae_int_t terminationtype; + double maxerror; + double rmserror; + ae_int_t iterationscount; +} rbfv3report; +#endif +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t stype; + ae_bool hasmissingcells; + ae_int_t n; + ae_int_t m; + ae_int_t d; + ae_vector x; + ae_vector y; + ae_vector f; + ae_vector ismissingnode; + ae_vector ismissingcell; +} spline2dinterpolant; +typedef struct +{ + ae_int_t priorterm; + double priortermval; + ae_int_t areatype; + double xa; + double xb; + double ya; + double yb; + ae_int_t gridtype; + ae_int_t kx; + ae_int_t ky; + double smoothing; + ae_int_t nlayers; + ae_int_t solvertype; + double lambdabase; + ae_vector xy; + ae_int_t npoints; + ae_int_t d; + double sx; + double sy; + ae_bool adddegreeoffreedom; + ae_int_t interfacesize; + ae_int_t lsqrcnt; + ae_int_t maxcoresize; +} spline2dbuilder; +typedef struct +{ + double rmserror; + double avgerror; + double maxerror; + double r2; +} spline2dfitreport; +typedef struct +{ + ae_int_t blockwidth; + ae_int_t kx; + ae_int_t ky; + ae_int_t npoints; + ae_int_t nrows; + ae_int_t ndenserows; + ae_int_t ndensebatches; + ae_int_t d; + ae_int_t maxbatch; + ae_matrix vals; + ae_vector batches; + ae_vector batchbases; + double lambdareg; + ae_vector tmp0; + ae_vector tmp1; + ae_matrix tmp2; +} spline2dxdesignmatrix; +typedef struct +{ + linlsqrstate solver; + linlsqrreport solverrep; + ae_matrix blockata; + ae_matrix trsmbuf2; + ae_matrix cholbuf2; + ae_vector cholbuf1; + ae_vector tmp0; + ae_vector tmp1; +} spline2dblockllsbuf; +typedef struct +{ + spline2dxdesignmatrix xdesignmatrix; + ae_vector tmp0; + ae_vector tmpz; + spline2dfitreport dummyrep; + spline2dinterpolant localmodel; + spline2dblockllsbuf blockllsbuf; +} spline2dfastddmbuf; +#endif +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector x; + ae_vector curboxmin; + ae_vector curboxmax; + double curdist2; + ae_vector x123; + ae_vector y123; +} rbfv2calcbuffer; +typedef struct +{ + ae_int_t ny; + ae_int_t nx; + ae_int_t bf; + ae_int_t nh; + ae_vector ri; + ae_vector s; + ae_vector kdroots; + ae_vector kdnodes; + ae_vector kdsplits; + ae_vector kdboxmin; + ae_vector kdboxmax; + ae_vector cw; + ae_matrix v; + double lambdareg; + ae_int_t maxits; + double supportr; + ae_int_t basisfunction; + rbfv2calcbuffer calcbuf; +} rbfv2model; +typedef struct +{ + rbfv2calcbuffer calcbuf; + ae_vector cx; + ae_vector rx; + ae_vector ry; + ae_vector tx; + ae_vector ty; + ae_vector rf; +} rbfv2gridcalcbuffer; +typedef struct +{ + ae_int_t terminationtype; + double maxerror; + double rmserror; +} rbfv2report; +#endif +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t k; + ae_int_t stype; + ae_int_t n; + ae_int_t m; + ae_int_t l; + ae_int_t d; + ae_vector x; + ae_vector y; + ae_vector z; + ae_vector f; +} spline3dinterpolant; +#endif +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t modelversion; + rbfv1calcbuffer bufv1; + rbfv2calcbuffer bufv2; + rbfv3calcbuffer bufv3; + ae_vector x; + ae_vector y; + ae_vector dy; +} rbfcalcbuffer; +typedef struct +{ + ae_int_t nx; + ae_int_t ny; + ae_int_t modelversion; + rbfv1model model1; + rbfv2model model2; + rbfv3model model3; + rbfcalcbuffer calcbuf; + double lambdav; + double radvalue; + double radzvalue; + ae_int_t nlayers; + ae_int_t aterm; + ae_int_t algorithmtype; + ae_int_t rbfprofile; + ae_int_t bftype; + double bfparam; + double epsort; + double epserr; + ae_int_t maxits; + double v3tol; + ae_int_t nnmaxits; + ae_int_t n; + ae_matrix x; + ae_matrix y; + ae_bool hasscale; + ae_vector s; + double fastevaltol; + ae_int_t progress10000; + ae_bool terminationrequest; +} rbfmodel; +typedef struct +{ + double rmserror; + double maxerror; + ae_int_t arows; + ae_int_t acols; + ae_int_t annz; + ae_int_t iterationscount; + ae_int_t nmv; + ae_int_t terminationtype; +} rbfreport; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +class _barycentricinterpolant_owner; +class barycentricinterpolant; + + +/************************************************************************* +Barycentric interpolant. +*************************************************************************/ +class _barycentricinterpolant_owner +{ +public: + _barycentricinterpolant_owner(); + _barycentricinterpolant_owner(alglib_impl::barycentricinterpolant *attach_to); + _barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs); + _barycentricinterpolant_owner& operator=(const _barycentricinterpolant_owner &rhs); + virtual ~_barycentricinterpolant_owner(); + alglib_impl::barycentricinterpolant* c_ptr(); + const alglib_impl::barycentricinterpolant* c_ptr() const; +protected: + alglib_impl::barycentricinterpolant *p_struct; + bool is_attached; +}; +class barycentricinterpolant : public _barycentricinterpolant_owner +{ +public: + barycentricinterpolant(); + barycentricinterpolant(alglib_impl::barycentricinterpolant *attach_to); + barycentricinterpolant(const barycentricinterpolant &rhs); + barycentricinterpolant& operator=(const barycentricinterpolant &rhs); + virtual ~barycentricinterpolant(); + + +}; +#endif + +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +class _idwcalcbuffer_owner; +class idwcalcbuffer; +class _idwmodel_owner; +class idwmodel; +class _idwbuilder_owner; +class idwbuilder; +class _idwreport_owner; +class idwreport; + + +/************************************************************************* +Buffer object which is used to perform evaluation requests in the +multithreaded mode (multiple threads working with same IDW object). + +This object should be created with idwcreatecalcbuffer(). +*************************************************************************/ +class _idwcalcbuffer_owner +{ +public: + _idwcalcbuffer_owner(); + _idwcalcbuffer_owner(alglib_impl::idwcalcbuffer *attach_to); + _idwcalcbuffer_owner(const _idwcalcbuffer_owner &rhs); + _idwcalcbuffer_owner& operator=(const _idwcalcbuffer_owner &rhs); + virtual ~_idwcalcbuffer_owner(); + alglib_impl::idwcalcbuffer* c_ptr(); + const alglib_impl::idwcalcbuffer* c_ptr() const; +protected: + alglib_impl::idwcalcbuffer *p_struct; + bool is_attached; +}; +class idwcalcbuffer : public _idwcalcbuffer_owner +{ +public: + idwcalcbuffer(); + idwcalcbuffer(alglib_impl::idwcalcbuffer *attach_to); + idwcalcbuffer(const idwcalcbuffer &rhs); + idwcalcbuffer& operator=(const idwcalcbuffer &rhs); + virtual ~idwcalcbuffer(); + + +}; + + +/************************************************************************* +IDW (Inverse Distance Weighting) model object. +*************************************************************************/ +class _idwmodel_owner +{ +public: + _idwmodel_owner(); + _idwmodel_owner(alglib_impl::idwmodel *attach_to); + _idwmodel_owner(const _idwmodel_owner &rhs); + _idwmodel_owner& operator=(const _idwmodel_owner &rhs); + virtual ~_idwmodel_owner(); + alglib_impl::idwmodel* c_ptr(); + const alglib_impl::idwmodel* c_ptr() const; +protected: + alglib_impl::idwmodel *p_struct; + bool is_attached; +}; +class idwmodel : public _idwmodel_owner +{ +public: + idwmodel(); + idwmodel(alglib_impl::idwmodel *attach_to); + idwmodel(const idwmodel &rhs); + idwmodel& operator=(const idwmodel &rhs); + virtual ~idwmodel(); + + +}; + + +/************************************************************************* +Builder object used to generate IDW (Inverse Distance Weighting) model. +*************************************************************************/ +class _idwbuilder_owner +{ +public: + _idwbuilder_owner(); + _idwbuilder_owner(alglib_impl::idwbuilder *attach_to); + _idwbuilder_owner(const _idwbuilder_owner &rhs); + _idwbuilder_owner& operator=(const _idwbuilder_owner &rhs); + virtual ~_idwbuilder_owner(); + alglib_impl::idwbuilder* c_ptr(); + const alglib_impl::idwbuilder* c_ptr() const; +protected: + alglib_impl::idwbuilder *p_struct; + bool is_attached; +}; +class idwbuilder : public _idwbuilder_owner +{ +public: + idwbuilder(); + idwbuilder(alglib_impl::idwbuilder *attach_to); + idwbuilder(const idwbuilder &rhs); + idwbuilder& operator=(const idwbuilder &rhs); + virtual ~idwbuilder(); + + +}; + + +/************************************************************************* +IDW fitting report: + rmserror RMS error + avgerror average error + maxerror maximum error + r2 coefficient of determination, R-squared, 1-RSS/TSS +*************************************************************************/ +class _idwreport_owner +{ +public: + _idwreport_owner(); + _idwreport_owner(alglib_impl::idwreport *attach_to); + _idwreport_owner(const _idwreport_owner &rhs); + _idwreport_owner& operator=(const _idwreport_owner &rhs); + virtual ~_idwreport_owner(); + alglib_impl::idwreport* c_ptr(); + const alglib_impl::idwreport* c_ptr() const; +protected: + alglib_impl::idwreport *p_struct; + bool is_attached; +}; +class idwreport : public _idwreport_owner +{ +public: + idwreport(); + idwreport(alglib_impl::idwreport *attach_to); + idwreport(const idwreport &rhs); + idwreport& operator=(const idwreport &rhs); + virtual ~idwreport(); + double &rmserror; + double &avgerror; + double &maxerror; + double &r2; + + +}; +#endif + +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +class _spline1dinterpolant_owner; +class spline1dinterpolant; +class _spline1dfitreport_owner; +class spline1dfitreport; + + +/************************************************************************* +1-dimensional spline interpolant +*************************************************************************/ +class _spline1dinterpolant_owner +{ +public: + _spline1dinterpolant_owner(); + _spline1dinterpolant_owner(alglib_impl::spline1dinterpolant *attach_to); + _spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs); + _spline1dinterpolant_owner& operator=(const _spline1dinterpolant_owner &rhs); + virtual ~_spline1dinterpolant_owner(); + alglib_impl::spline1dinterpolant* c_ptr(); + const alglib_impl::spline1dinterpolant* c_ptr() const; +protected: + alglib_impl::spline1dinterpolant *p_struct; + bool is_attached; +}; +class spline1dinterpolant : public _spline1dinterpolant_owner +{ +public: + spline1dinterpolant(); + spline1dinterpolant(alglib_impl::spline1dinterpolant *attach_to); + spline1dinterpolant(const spline1dinterpolant &rhs); + spline1dinterpolant& operator=(const spline1dinterpolant &rhs); + virtual ~spline1dinterpolant(); + + +}; + + +/************************************************************************* +Spline fitting report: + TerminationType completion code: + * >0 for success + * <0 for failure + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + +Fields below are filled by obsolete functions (Spline1DFitCubic, +Spline1DFitHermite). Modern fitting functions do NOT fill these fields: + TaskRCond reciprocal of task's condition number +*************************************************************************/ +class _spline1dfitreport_owner +{ +public: + _spline1dfitreport_owner(); + _spline1dfitreport_owner(alglib_impl::spline1dfitreport *attach_to); + _spline1dfitreport_owner(const _spline1dfitreport_owner &rhs); + _spline1dfitreport_owner& operator=(const _spline1dfitreport_owner &rhs); + virtual ~_spline1dfitreport_owner(); + alglib_impl::spline1dfitreport* c_ptr(); + const alglib_impl::spline1dfitreport* c_ptr() const; +protected: + alglib_impl::spline1dfitreport *p_struct; + bool is_attached; +}; +class spline1dfitreport : public _spline1dfitreport_owner +{ +public: + spline1dfitreport(); + spline1dfitreport(alglib_impl::spline1dfitreport *attach_to); + spline1dfitreport(const spline1dfitreport &rhs); + spline1dfitreport& operator=(const spline1dfitreport &rhs); + virtual ~spline1dfitreport(); + ae_int_t &terminationtype; + double &taskrcond; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &maxerror; + + +}; +#endif + +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +class _polynomialfitreport_owner; +class polynomialfitreport; +class _barycentricfitreport_owner; +class barycentricfitreport; +class _lsfitreport_owner; +class lsfitreport; +class _lsfitstate_owner; +class lsfitstate; + + +/************************************************************************* +Polynomial fitting report: + TerminationType completion code: >0 for success, <0 for failure + TaskRCond reciprocal of task's condition number + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error +*************************************************************************/ +class _polynomialfitreport_owner +{ +public: + _polynomialfitreport_owner(); + _polynomialfitreport_owner(alglib_impl::polynomialfitreport *attach_to); + _polynomialfitreport_owner(const _polynomialfitreport_owner &rhs); + _polynomialfitreport_owner& operator=(const _polynomialfitreport_owner &rhs); + virtual ~_polynomialfitreport_owner(); + alglib_impl::polynomialfitreport* c_ptr(); + const alglib_impl::polynomialfitreport* c_ptr() const; +protected: + alglib_impl::polynomialfitreport *p_struct; + bool is_attached; +}; +class polynomialfitreport : public _polynomialfitreport_owner +{ +public: + polynomialfitreport(); + polynomialfitreport(alglib_impl::polynomialfitreport *attach_to); + polynomialfitreport(const polynomialfitreport &rhs); + polynomialfitreport& operator=(const polynomialfitreport &rhs); + virtual ~polynomialfitreport(); + ae_int_t &terminationtype; + double &taskrcond; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &maxerror; + + +}; + + +/************************************************************************* +Barycentric fitting report: + TerminationType completion code: >0 for success, <0 for failure + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + TaskRCond reciprocal of task's condition number +*************************************************************************/ +class _barycentricfitreport_owner +{ +public: + _barycentricfitreport_owner(); + _barycentricfitreport_owner(alglib_impl::barycentricfitreport *attach_to); + _barycentricfitreport_owner(const _barycentricfitreport_owner &rhs); + _barycentricfitreport_owner& operator=(const _barycentricfitreport_owner &rhs); + virtual ~_barycentricfitreport_owner(); + alglib_impl::barycentricfitreport* c_ptr(); + const alglib_impl::barycentricfitreport* c_ptr() const; +protected: + alglib_impl::barycentricfitreport *p_struct; + bool is_attached; +}; +class barycentricfitreport : public _barycentricfitreport_owner +{ +public: + barycentricfitreport(); + barycentricfitreport(alglib_impl::barycentricfitreport *attach_to); + barycentricfitreport(const barycentricfitreport &rhs); + barycentricfitreport& operator=(const barycentricfitreport &rhs); + virtual ~barycentricfitreport(); + ae_int_t &terminationtype; + double &taskrcond; + ae_int_t &dbest; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &maxerror; + + +}; + + +/************************************************************************* +Least squares fitting report. This structure contains informational fields +which are set by fitting functions provided by this unit. + +Different functions initialize different sets of fields, so you should +read documentation on specific function you used in order to know which +fields are initialized. + + TerminationType filled by all solvers: + * positive values, usually 1, denote success + * negative values denote various failure scenarios + + TaskRCond reciprocal of task's condition number + IterationsCount number of internal iterations + + VarIdx if user-supplied gradient contains errors which were + detected by nonlinear fitter, this field is set to + index of the first component of gradient which is + suspected to be spoiled by bugs. + + RMSError RMS error + AvgError average error + AvgRelError average relative error (for non-zero Y[I]) + MaxError maximum error + + WRMSError weighted RMS error + + CovPar covariance matrix for parameters, filled by some solvers + ErrPar vector of errors in parameters, filled by some solvers + ErrCurve vector of fit errors - variability of the best-fit + curve, filled by some solvers. + Noise vector of per-point noise estimates, filled by + some solvers. + R2 coefficient of determination (non-weighted, non-adjusted), + filled by some solvers. +*************************************************************************/ +class _lsfitreport_owner +{ +public: + _lsfitreport_owner(); + _lsfitreport_owner(alglib_impl::lsfitreport *attach_to); + _lsfitreport_owner(const _lsfitreport_owner &rhs); + _lsfitreport_owner& operator=(const _lsfitreport_owner &rhs); + virtual ~_lsfitreport_owner(); + alglib_impl::lsfitreport* c_ptr(); + const alglib_impl::lsfitreport* c_ptr() const; +protected: + alglib_impl::lsfitreport *p_struct; + bool is_attached; +}; +class lsfitreport : public _lsfitreport_owner +{ +public: + lsfitreport(); + lsfitreport(alglib_impl::lsfitreport *attach_to); + lsfitreport(const lsfitreport &rhs); + lsfitreport& operator=(const lsfitreport &rhs); + virtual ~lsfitreport(); + ae_int_t &terminationtype; + double &taskrcond; + ae_int_t &iterationscount; + ae_int_t &varidx; + double &rmserror; + double &avgerror; + double &avgrelerror; + double &maxerror; + double &wrmserror; + real_2d_array covpar; + real_1d_array errpar; + real_1d_array errcurve; + real_1d_array noise; + double &r2; + + +}; + + +/************************************************************************* +Nonlinear fitter. + +You should use ALGLIB functions to work with fitter. +Never try to access its fields directly! +*************************************************************************/ +class _lsfitstate_owner +{ +public: + _lsfitstate_owner(); + _lsfitstate_owner(alglib_impl::lsfitstate *attach_to); + _lsfitstate_owner(const _lsfitstate_owner &rhs); + _lsfitstate_owner& operator=(const _lsfitstate_owner &rhs); + virtual ~_lsfitstate_owner(); + alglib_impl::lsfitstate* c_ptr(); + const alglib_impl::lsfitstate* c_ptr() const; +protected: + alglib_impl::lsfitstate *p_struct; + bool is_attached; +}; +class lsfitstate : public _lsfitstate_owner +{ +public: + lsfitstate(); + lsfitstate(alglib_impl::lsfitstate *attach_to); + lsfitstate(const lsfitstate &rhs); + lsfitstate& operator=(const lsfitstate &rhs); + virtual ~lsfitstate(); + + +}; +#endif + +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +class _pspline2interpolant_owner; +class pspline2interpolant; +class _pspline3interpolant_owner; +class pspline3interpolant; + + +/************************************************************************* +Parametric spline inteprolant: 2-dimensional curve. + +You should not try to access its members directly - use PSpline2XXXXXXXX() +functions instead. +*************************************************************************/ +class _pspline2interpolant_owner +{ +public: + _pspline2interpolant_owner(); + _pspline2interpolant_owner(alglib_impl::pspline2interpolant *attach_to); + _pspline2interpolant_owner(const _pspline2interpolant_owner &rhs); + _pspline2interpolant_owner& operator=(const _pspline2interpolant_owner &rhs); + virtual ~_pspline2interpolant_owner(); + alglib_impl::pspline2interpolant* c_ptr(); + const alglib_impl::pspline2interpolant* c_ptr() const; +protected: + alglib_impl::pspline2interpolant *p_struct; + bool is_attached; +}; +class pspline2interpolant : public _pspline2interpolant_owner +{ +public: + pspline2interpolant(); + pspline2interpolant(alglib_impl::pspline2interpolant *attach_to); + pspline2interpolant(const pspline2interpolant &rhs); + pspline2interpolant& operator=(const pspline2interpolant &rhs); + virtual ~pspline2interpolant(); + + +}; + + +/************************************************************************* +Parametric spline inteprolant: 3-dimensional curve. + +You should not try to access its members directly - use PSpline3XXXXXXXX() +functions instead. +*************************************************************************/ +class _pspline3interpolant_owner +{ +public: + _pspline3interpolant_owner(); + _pspline3interpolant_owner(alglib_impl::pspline3interpolant *attach_to); + _pspline3interpolant_owner(const _pspline3interpolant_owner &rhs); + _pspline3interpolant_owner& operator=(const _pspline3interpolant_owner &rhs); + virtual ~_pspline3interpolant_owner(); + alglib_impl::pspline3interpolant* c_ptr(); + const alglib_impl::pspline3interpolant* c_ptr() const; +protected: + alglib_impl::pspline3interpolant *p_struct; + bool is_attached; +}; +class pspline3interpolant : public _pspline3interpolant_owner +{ +public: + pspline3interpolant(); + pspline3interpolant(alglib_impl::pspline3interpolant *attach_to); + pspline3interpolant(const pspline3interpolant &rhs); + pspline3interpolant& operator=(const pspline3interpolant &rhs); + virtual ~pspline3interpolant(); + + +}; +#endif + +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) +class _spline2dinterpolant_owner; +class spline2dinterpolant; +class _spline2dbuilder_owner; +class spline2dbuilder; +class _spline2dfitreport_owner; +class spline2dfitreport; + + +/************************************************************************* +2-dimensional spline inteprolant +*************************************************************************/ +class _spline2dinterpolant_owner +{ +public: + _spline2dinterpolant_owner(); + _spline2dinterpolant_owner(alglib_impl::spline2dinterpolant *attach_to); + _spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs); + _spline2dinterpolant_owner& operator=(const _spline2dinterpolant_owner &rhs); + virtual ~_spline2dinterpolant_owner(); + alglib_impl::spline2dinterpolant* c_ptr(); + const alglib_impl::spline2dinterpolant* c_ptr() const; +protected: + alglib_impl::spline2dinterpolant *p_struct; + bool is_attached; +}; +class spline2dinterpolant : public _spline2dinterpolant_owner +{ +public: + spline2dinterpolant(); + spline2dinterpolant(alglib_impl::spline2dinterpolant *attach_to); + spline2dinterpolant(const spline2dinterpolant &rhs); + spline2dinterpolant& operator=(const spline2dinterpolant &rhs); + virtual ~spline2dinterpolant(); + + +}; + + +/************************************************************************* +Nonlinear least squares solver used to fit 2D splines to data +*************************************************************************/ +class _spline2dbuilder_owner +{ +public: + _spline2dbuilder_owner(); + _spline2dbuilder_owner(alglib_impl::spline2dbuilder *attach_to); + _spline2dbuilder_owner(const _spline2dbuilder_owner &rhs); + _spline2dbuilder_owner& operator=(const _spline2dbuilder_owner &rhs); + virtual ~_spline2dbuilder_owner(); + alglib_impl::spline2dbuilder* c_ptr(); + const alglib_impl::spline2dbuilder* c_ptr() const; +protected: + alglib_impl::spline2dbuilder *p_struct; + bool is_attached; +}; +class spline2dbuilder : public _spline2dbuilder_owner +{ +public: + spline2dbuilder(); + spline2dbuilder(alglib_impl::spline2dbuilder *attach_to); + spline2dbuilder(const spline2dbuilder &rhs); + spline2dbuilder& operator=(const spline2dbuilder &rhs); + virtual ~spline2dbuilder(); + + +}; + + +/************************************************************************* +Spline 2D fitting report: + rmserror RMS error + avgerror average error + maxerror maximum error + r2 coefficient of determination, R-squared, 1-RSS/TSS +*************************************************************************/ +class _spline2dfitreport_owner +{ +public: + _spline2dfitreport_owner(); + _spline2dfitreport_owner(alglib_impl::spline2dfitreport *attach_to); + _spline2dfitreport_owner(const _spline2dfitreport_owner &rhs); + _spline2dfitreport_owner& operator=(const _spline2dfitreport_owner &rhs); + virtual ~_spline2dfitreport_owner(); + alglib_impl::spline2dfitreport* c_ptr(); + const alglib_impl::spline2dfitreport* c_ptr() const; +protected: + alglib_impl::spline2dfitreport *p_struct; + bool is_attached; +}; +class spline2dfitreport : public _spline2dfitreport_owner +{ +public: + spline2dfitreport(); + spline2dfitreport(alglib_impl::spline2dfitreport *attach_to); + spline2dfitreport(const spline2dfitreport &rhs); + spline2dfitreport& operator=(const spline2dfitreport &rhs); + virtual ~spline2dfitreport(); + double &rmserror; + double &avgerror; + double &maxerror; + double &r2; + + +}; +#endif + +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +class _spline3dinterpolant_owner; +class spline3dinterpolant; + + +/************************************************************************* +3-dimensional spline inteprolant +*************************************************************************/ +class _spline3dinterpolant_owner +{ +public: + _spline3dinterpolant_owner(); + _spline3dinterpolant_owner(alglib_impl::spline3dinterpolant *attach_to); + _spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs); + _spline3dinterpolant_owner& operator=(const _spline3dinterpolant_owner &rhs); + virtual ~_spline3dinterpolant_owner(); + alglib_impl::spline3dinterpolant* c_ptr(); + const alglib_impl::spline3dinterpolant* c_ptr() const; +protected: + alglib_impl::spline3dinterpolant *p_struct; + bool is_attached; +}; +class spline3dinterpolant : public _spline3dinterpolant_owner +{ +public: + spline3dinterpolant(); + spline3dinterpolant(alglib_impl::spline3dinterpolant *attach_to); + spline3dinterpolant(const spline3dinterpolant &rhs); + spline3dinterpolant& operator=(const spline3dinterpolant &rhs); + virtual ~spline3dinterpolant(); + + +}; +#endif + +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +class _rbfcalcbuffer_owner; +class rbfcalcbuffer; +class _rbfmodel_owner; +class rbfmodel; +class _rbfreport_owner; +class rbfreport; + + +/************************************************************************* +Buffer object which is used to perform RBF model calculation in the +multithreaded mode (multiple threads working with same RBF object). + +This object should be created with RBFCreateCalcBuffer(). +*************************************************************************/ +class _rbfcalcbuffer_owner +{ +public: + _rbfcalcbuffer_owner(); + _rbfcalcbuffer_owner(alglib_impl::rbfcalcbuffer *attach_to); + _rbfcalcbuffer_owner(const _rbfcalcbuffer_owner &rhs); + _rbfcalcbuffer_owner& operator=(const _rbfcalcbuffer_owner &rhs); + virtual ~_rbfcalcbuffer_owner(); + alglib_impl::rbfcalcbuffer* c_ptr(); + const alglib_impl::rbfcalcbuffer* c_ptr() const; +protected: + alglib_impl::rbfcalcbuffer *p_struct; + bool is_attached; +}; +class rbfcalcbuffer : public _rbfcalcbuffer_owner +{ +public: + rbfcalcbuffer(); + rbfcalcbuffer(alglib_impl::rbfcalcbuffer *attach_to); + rbfcalcbuffer(const rbfcalcbuffer &rhs); + rbfcalcbuffer& operator=(const rbfcalcbuffer &rhs); + virtual ~rbfcalcbuffer(); + + +}; + + +/************************************************************************* +RBF model. + +Never try to directly work with fields of this object - always use ALGLIB +functions to use this object. +*************************************************************************/ +class _rbfmodel_owner +{ +public: + _rbfmodel_owner(); + _rbfmodel_owner(alglib_impl::rbfmodel *attach_to); + _rbfmodel_owner(const _rbfmodel_owner &rhs); + _rbfmodel_owner& operator=(const _rbfmodel_owner &rhs); + virtual ~_rbfmodel_owner(); + alglib_impl::rbfmodel* c_ptr(); + const alglib_impl::rbfmodel* c_ptr() const; +protected: + alglib_impl::rbfmodel *p_struct; + bool is_attached; +}; +class rbfmodel : public _rbfmodel_owner +{ +public: + rbfmodel(); + rbfmodel(alglib_impl::rbfmodel *attach_to); + rbfmodel(const rbfmodel &rhs); + rbfmodel& operator=(const rbfmodel &rhs); + virtual ~rbfmodel(); + + +}; + + +/************************************************************************* +RBF solution report: +* TerminationType - termination type, positive values - success, + non-positive - failure. + +Fields which are set by modern RBF solvers (hierarchical): +* RMSError - root-mean-square error; NAN for old solvers (ML, QNN) +* MaxError - maximum error; NAN for old solvers (ML, QNN) +*************************************************************************/ +class _rbfreport_owner +{ +public: + _rbfreport_owner(); + _rbfreport_owner(alglib_impl::rbfreport *attach_to); + _rbfreport_owner(const _rbfreport_owner &rhs); + _rbfreport_owner& operator=(const _rbfreport_owner &rhs); + virtual ~_rbfreport_owner(); + alglib_impl::rbfreport* c_ptr(); + const alglib_impl::rbfreport* c_ptr() const; +protected: + alglib_impl::rbfreport *p_struct; + bool is_attached; +}; +class rbfreport : public _rbfreport_owner +{ +public: + rbfreport(); + rbfreport(alglib_impl::rbfreport *attach_to); + rbfreport(const rbfreport &rhs); + rbfreport& operator=(const rbfreport &rhs); + virtual ~rbfreport(); + double &rmserror; + double &maxerror; + ae_int_t &arows; + ae_int_t &acols; + ae_int_t &annz; + ae_int_t &iterationscount; + ae_int_t &nmv; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Rational interpolation using barycentric formula + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +Input parameters: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +Result: + barycentric interpolant F(t) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +double barycentriccalc(const barycentricinterpolant &b, const double t, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Differentiation of barycentric interpolant: first derivative. + +Algorithm used in this subroutine is very robust and should not fail until +provided with values too close to MaxRealNumber (usually MaxRealNumber/N +or greater will overflow). + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + +NOTE + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Differentiation of barycentric interpolant: first/second derivatives. + +INPUT PARAMETERS: + B - barycentric interpolant built with one of model building + subroutines. + T - interpolation point + +OUTPUT PARAMETERS: + F - barycentric interpolant at T + DF - first derivative + D2F - second derivative + +NOTE: this algorithm may fail due to overflow/underflor if used on data +whose values are close to MaxRealNumber or MinRealNumber. Use more robust +BarycentricDiff1() subroutine in such cases. + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the argument. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: x = CA*t + CB + +OUTPUT PARAMETERS: + B - transformed interpolant with X replaced by T + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransx(barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the barycentric +interpolant. + +INPUT PARAMETERS: + B - rational interpolant in barycentric form + CA, CB - transformation coefficients: B2(x) = CA*B(x) + CB + +OUTPUT PARAMETERS: + B - transformed interpolant + + -- ALGLIB PROJECT -- + Copyright 19.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentriclintransy(barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Extracts X/Y/W arrays from rational interpolant + +INPUT PARAMETERS: + B - barycentric interpolant + +OUTPUT PARAMETERS: + N - nodes count, N>0 + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Rational interpolant from X/Y/W arrays + +F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i])) + +INPUT PARAMETERS: + X - interpolation nodes, array[0..N-1] + F - function values, array[0..N-1] + W - barycentric weights, array[0..N-1] + N - nodes count, N>0 + +OUTPUT PARAMETERS: + B - barycentric interpolant built from (X, Y, W) + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Rational interpolant without poles + +The subroutine constructs the rational interpolating function without real +poles (see 'Barycentric rational interpolation with no poles and high +rates of approximation', Michael S. Floater. and Kai Hormann, for more +information on this subject). + +Input parameters: + X - interpolation nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of nodes, N>0. + D - order of the interpolation scheme, 0 <= D <= N-1. + D<0 will cause an error. + D>=N it will be replaced with D=N-1. + if you don't know what D to choose, use small value about 3-5. + +Output parameters: + B - barycentric interpolant. + +Note: + this algorithm always succeeds and calculates the weights with close + to machine precision. + + -- ALGLIB PROJECT -- + Copyright 17.06.2007 by Bochkanov Sergey +*************************************************************************/ +void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void idwserialize(const idwmodel &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void idwserialize(const idwmodel &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void idwunserialize(const std::string &s_in, idwmodel &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void idwunserialize(const std::istream &s_in, idwmodel &obj); + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel IDW model evaluations (with one IDW model instance being +used from multiple threads, as long as different threads use different +instances of buffer). + +This buffer object can be used with idwtscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +How to use it: +* create IDW model structure or load it from file +* call idwcreatecalcbuffer(), once per thread working with IDW model (you + should call this function only AFTER model initialization, see below for + more information) +* call idwtscalcbuf() from different threads, with each thread working + with its own copy of buffer object. + +INPUT PARAMETERS + S - IDW model + +OUTPUT PARAMETERS + Buf - external buffer. + + +IMPORTANT: buffer object should be used only with IDW model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of the IDW structure. + +IMPORTANT: you should call this function only for model which was built + with model builder (or unserialized from file). Sizes of some + internal structures are determined only after model is built, + so buffer object created before model construction stage will + be useless (and any attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 22.10.2018 by Sergey Bochkanov +*************************************************************************/ +void idwcreatecalcbuffer(const idwmodel &s, idwcalcbuffer &buf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine creates builder object used to generate IDW model from +irregularly sampled (scattered) dataset. Multidimensional scalar/vector- +-valued are supported. + +Builder object is used to fit model to data as follows: +* builder object is created with idwbuildercreate() function +* dataset is added with idwbuildersetpoints() function +* one of the modern IDW algorithms is chosen with either: + * idwbuildersetalgomstab() - Multilayer STABilized algorithm (interpolation) + Alternatively, one of the textbook algorithms can be chosen (not recommended): + * idwbuildersetalgotextbookshepard() - textbook Shepard algorithm + * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm +* finally, model construction is performed with idwfit() function. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + NX - dimensionality of the argument, NX>=1 + NY - dimensionality of the function being modeled, NY>=1; + NY=1 corresponds to classic scalar function, NY>=1 corresponds + to vector-valued function. + +OUTPUT PARAMETERS: + State- builder object + + -- ALGLIB PROJECT -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildercreate(const ae_int_t nx, const ae_int_t ny, idwbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes number of layers used by IDW-MSTAB algorithm. + +The more layers you have, the finer details can be reproduced with IDW +model. The less layers you have, the less memory and CPU time is consumed +by the model. + +Memory consumption grows linearly with layers count, running time grows +sub-linearly. + +The default number of layers is 16, which allows you to reproduce details +at distance down to SRad/65536. You will rarely need to change it. + +INPUT PARAMETERS: + State - builder object + NLayers - NLayers>=1, the number of layers used by the model. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetnlayers(idwbuilder &state, const ae_int_t nlayers, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + State - builder object + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset, N>=0. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetpoints(idwbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams = alglib::xdefault); +void idwbuildersetpoints(idwbuilder &state, const real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets IDW model construction algorithm to the Multilayer +Stabilized IDW method (IDW-MSTAB), a latest incarnation of the inverse +distance weighting interpolation which fixes shortcomings of the original +and modified Shepard's variants. + +The distinctive features of IDW-MSTAB are: +1) exact interpolation is pursued (as opposed to fitting and noise + suppression) +2) improved robustness when compared with that of other algorithms: + * MSTAB shows almost no strange fitting artifacts like ripples and + sharp spikes (unlike N-dimensional splines and HRBFs) + * MSTAB does not return function values far from the interval spanned + by the dataset; say, if all your points have |f|<=1, you can be sure + that model value won't deviate too much from [-1,+1] +3) good model construction time competing with that of HRBFs and bicubic + splines +4) ability to work with any number of dimensions, starting from NX=1 + +The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are: +1) dependence of the model evaluation time on the search radius +2) bad extrapolation properties, models built by this method are usually + conservative in their predictions + +Thus, IDW-MSTAB is a good "default" option if you want to perform +scattered multidimensional interpolation. Although it has its drawbacks, +it is easy to use and robust, which makes it a good first step. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + SRad - initial search radius, SRad>0 is required. A model value + is obtained by "smart" averaging of the dataset points + within search radius. + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + +NOTE 2: the memory requirements for model storage are O(NPoints*NLayers). + The model construction needs twice as much memory as model storage. + +NOTE 3: by default 16 IDW layers are built which is enough for most cases. + You can change this parameter with idwbuildersetnlayers() method. + Larger values may be necessary if you need to reproduce extrafine + details at distances smaller than SRad/65536. Smaller value may + be necessary if you have to save memory and computing time, and + ready to sacrifice some model quality. + + +ALGORITHM DESCRIPTION + +ALGLIB implementation of IDW is somewhat similar to the modified Shepard's +method (one with search radius R) but overcomes several of its drawbacks, +namely: +1) a tendency to show stepwise behavior for uniform datasets +2) a tendency to show terrible interpolation properties for highly + nonuniform datasets which often arise in geospatial tasks + (function values are densely sampled across multiple separated + "tracks") + +IDW-MSTAB method performs several passes over dataset and builds a sequence +of progressively refined IDW models (layers), which starts from one with +largest search radius SRad and continues to smaller search radii until +required number of layers is built. Highest layers reproduce global +behavior of the target function at larger distances whilst lower layers +reproduce fine details at smaller distances. + +Each layer is an IDW model built with following modifications: +* weights go to zero when distance approach to the current search radius +* an additional regularizing term is added to the distance: w=1/(d^2+lambda) +* an additional fictional term with unit weight and zero function value is + added in order to promote continuity properties at the isolated and + boundary points + +By default, 16 layers is built, which is enough for most cases. You can +change this parameter with idwbuildersetnlayers() method. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgomstab(idwbuilder &state, const double srad, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets IDW model construction algorithm to the textbook +Shepard's algorithm with custom (user-specified) power parameter. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + P - power parameter, P>0; good value to start with is 2.0 + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookshepard(idwbuilder &state, const double p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets IDW model construction algorithm to the 'textbook' +modified Shepard's algorithm with user-specified search radius. + +IMPORTANT: we do NOT recommend using textbook IDW algorithms because they + have terrible interpolation properties. Use MSTAB in all cases. + +INPUT PARAMETERS: + State - builder object + R - search radius + +NOTE 1: IDW interpolation can correctly handle ANY dataset, including + datasets with non-distinct points. In case non-distinct points are + found, an average value for this point will be calculated. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetalgotextbookmodshepard(idwbuilder &state, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets prior term (model value at infinity) as user-specified +value. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + +NOTE: for vector-valued models all components of the prior are set to same + user-specified value + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetuserterm(idwbuilder &state, const double v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets constant prior term (model value at infinity). + +Constant prior term is determined as mean value over dataset. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetconstterm(idwbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets zero prior term (model value at infinity). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 29.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwbuildersetzeroterm(idwbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IDW interpolation: scalar target, 1-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0 - argument value + +Result: + IDW interpolant S(X0) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc1(idwmodel &s, const double x0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IDW interpolation: scalar target, 2-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0, X1 - argument value + +Result: + IDW interpolant S(X0,X1) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc2(idwmodel &s, const double x0, const double x1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IDW interpolation: scalar target, 3-dimensional argument + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW interpolant built with IDW builder + X0,X1,X2- argument value + +Result: + IDW interpolant S(X0,X1,X2) + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +double idwcalc3(idwmodel &s, const double x0, const double x1, const double x2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use idwcalc1(), +idwcalc2() or idwcalc3(). + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and will be + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use idwcalcbuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalc(idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the IDW model at the given point. + +Same as idwcalc(), but does not reallocate Y when in is large enough to +store function values. + +NOTE: this function modifies internal temporaries of the IDW model, thus + IT IS NOT THREAD-SAFE! If you want to perform parallel model + evaluation from the multiple threads, use idwtscalcbuf() with per- + thread buffer object. + +INPUT PARAMETERS: + S - IDW model + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwcalcbuf(idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the IDW model at the given point, using +external buffer object (internal temporaries of IDW model are not +modified). + +This function allows to use same IDW model object in different threads, +assuming that different threads use different instances of the buffer +structure. + +INPUT PARAMETERS: + S - IDW model, may be shared between different threads + Buf - buffer object created for this particular instance of IDW + model with idwcreatecalcbuffer(). + X - coordinates, array[NX]. X may have more than NX elements, + in this case only leading NX will be used. + Y - possibly preallocated array + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is not reallocated when it + is larger than NY. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void idwtscalcbuf(const idwmodel &s, idwcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits IDW model to the dataset using current IDW construction +algorithm. A model being built and fitting report are returned. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - builder object + +OUTPUT PARAMETERS: + Model - an IDW model built with current algorithm + Rep - model fitting report, fields of this structure contain + information about average fitting errors. + +NOTE: although IDW-MSTAB algorithm is an interpolation method, i.e. it + tries to fit the model exactly, it can handle datasets with non- + distinct points which can not be fit exactly; in such cases least- + squares fitting is performed. + + -- ALGLIB -- + Copyright 22.10.2018 by Bochkanov Sergey +*************************************************************************/ +void idwfit(idwbuilder &state, idwmodel &model, idwreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to peek into the IDW construction process from some +other thread and get the progress indicator. It returns value in [0,1]. + +IMPORTANT: only MSTAB algorithm supports peeking into progress indicator. + Legacy versions of the Shepard's method do not support it. You + will always get zero as the result. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 27.11.2023 by Bochkanov Sergey +*************************************************************************/ +double idwpeekprogress(const idwbuilder &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of an IDW model at a regular grid, +which has N0*N1 points, with Point[I,J] = (X0[I], X1[J]). Vector-valued +IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued IDW models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use idwgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2v(const idwmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of an IDW model at some subset of a +regular grid: +* the grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of the grid are required +Vector-valued IDW models are supported. + +This function returns 0.0 when: +* the model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (MSTAB) IDW's. + +INPUT PARAMETERS: + S - IDW model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension, N0>=1 + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension, N1>=1 + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued IDW models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. Generally, + they are not calculated, but future SIMD-capable + versions may compute several elements in a batch. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same idwmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 24.11.2023 by Bochkanov Sergey +*************************************************************************/ +void idwgridcalc2vsubset(const idwmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Conversion from barycentric representation to Chebyshev basis. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + P - polynomial in barycentric form + A,B - base interval for Chebyshev polynomials (see below) + A<>B + +OUTPUT PARAMETERS + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 }, + where Ti - I-th Chebyshev polynomial. + +NOTES: + barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Conversion from Chebyshev basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + T - coefficients of Chebyshev representation; + P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N }, + where Ti - I-th Chebyshev polynomial. + N - number of coefficients: + * if given, only leading N elements of T are used + * if not given, automatically determined from size of T + A,B - base interval for Chebyshev polynomials (see above) + A0. + +OUTPUT PARAMETERS + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if P was obtained as + result of interpolation on [-1,+1], you can set C=0 and S=1 and + represent P as sum of 1, x, x^2, x^3 and so on. In most cases you it + is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3 + will be better option. Such representation can be obtained by using + 1000.0 as offset C and 1.0 as scale S. + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return coefficients in + any case, but for N>8 they will become unreliable. However, N's + less than 5 are pretty safe. + +3. barycentric interpolant passed as P may be either polynomial obtained + from polynomial interpolation/ fitting or rational function which is + NOT polynomial. We can't distinguish between these two cases, and this + algorithm just tries to work assuming that P IS a polynomial. If not, + algorithm will return results, but they won't have any meaning. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a, const xparams _xparams = alglib::xdefault); +void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Conversion from power basis to barycentric representation. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + A - coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 } + N - number of coefficients (polynomial degree plus 1) + * if given, only leading N elements of A are used + * if not given, automatically determined from size of A + C - offset (see below); 0.0 is used as default value. + S - scale (see below); 1.0 is used as default value. S<>0. + +OUTPUT PARAMETERS + P - polynomial in barycentric form + + +NOTES: +1. this function accepts offset and scale, which can be set to improve + numerical properties of polynomial. For example, if you interpolate on + [-1,+1], you can set C=0 and S=1 and convert from sum of 1, x, x^2, + x^3 and so on. In most cases you it is exactly what you need. + + However, if your interpolation model was built on [999,1001], you will + see significant growth of numerical errors when using {1, x, x^2, x^3} + as input basis. Converting from sum of 1, (x-1000), (x-1000)^2, + (x-1000)^3 will be better option (you have to specify 1000.0 as offset + C and 1.0 as scale S). + +2. power basis is ill-conditioned and tricks described above can't solve + this problem completely. This function will return barycentric model + in any case, but for N>8 accuracy well degrade. However, N's less than + 5 are pretty safe. + + -- ALGLIB -- + Copyright 30.09.2010 by Bochkanov Sergey +*************************************************************************/ +void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); +void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Lagrange intepolant: generation of the model on the general grid. +This function has O(N^2) complexity. + +INPUT PARAMETERS: + X - abscissas, array[0..N-1] + Y - function values, array[0..N-1] + N - number of points, N>=1 + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); +void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Lagrange intepolant: generation of the model on equidistant grid. +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1] + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); +void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (first kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); +void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Lagrange intepolant on Chebyshev grid (second kind). +This function has O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + Y - function values at the nodes, array[0..N-1], + Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))) + N - number of points, N>=1 + for N=1 a constant model is constructed. + +OUTPUT PARAMETERS + P - barycentric model which represents Lagrange interpolant + (see ratint unit info and BarycentricCalc() description for + more information). + + -- ALGLIB -- + Copyright 03.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); +void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fast equidistant polynomial interpolation function with O(N) complexity + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on equidistant grid, N>=1 + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolynomialBuildEqDist()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams = alglib::xdefault); +double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (first kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (first kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb1()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams = alglib::xdefault); +double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fast polynomial interpolation function on Chebyshev points (second kind) +with O(N) complexity. + +INPUT PARAMETERS: + A - left boundary of [A,B] + B - right boundary of [A,B] + F - function values, array[0..N-1] + N - number of points on Chebyshev grid (second kind), + X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)) + for N=1 a constant model is constructed. + T - position where P(x) is calculated + +RESULT + value of the Lagrange interpolant at T + +IMPORTANT + this function provides fast interface which is not overflow-safe + nor it is very precise. + the best option is to use PolIntBuildCheb2()/BarycentricCalc() + subroutines unless you are pretty sure that your data will not result + in overflow. + + -- ALGLIB -- + Copyright 02.12.2009 by Bochkanov Sergey +*************************************************************************/ +double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams = alglib::xdefault); +double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void spline1dserialize(const spline1dinterpolant &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void spline1dserialize(const spline1dinterpolant &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void spline1dunserialize(const std::string &s_in, spline1dinterpolant &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void spline1dunserialize(const std::istream &s_in, spline1dinterpolant &obj); + + +/************************************************************************* +This subroutine builds linear spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds linear spline interpolant. + +Buffered version of Spline1DBuildLinear() which reused memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildlinearbuf(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildlinearbuf(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds cubic spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + C - spline interpolant + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns table of function derivatives d[] +(calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D - derivative values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d, const xparams _xparams = alglib::xdefault); +void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at nodes x[], it calculates and returns tables of first and second +function derivatives d1[] and d2[] (calculated at the same nodes x[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + + +INPUT PARAMETERS: + X - spline nodes + Y - function values + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + +OUTPUT PARAMETERS: + D1 - S' values at X[] + D2 - S'' values at X[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Derivative values are correctly reordered on return, so D[I] is always +equal to S'(X[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2, const xparams _xparams = alglib::xdefault); +void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DCalc() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, const xparams _xparams = alglib::xdefault); +void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[] and derivatives d2[] (calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams = alglib::xdefault); +void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves following problem: given table y[] of function values +at old nodes x[] and new nodes x2[], it calculates and returns table of +function values y2[], first and second derivatives d2[] and dd2[] +(calculated at x2[]). + +This function yields same result as Spline1DBuildCubic() call followed by +sequence of Spline1DDiff2() calls, but it can be several times faster, +whilst still having the same O(N*logN) running time. + +When called for ordered X[], this function has O(N) running time instead +of O(N*logN). + +INPUT PARAMETERS: + X - old spline nodes + Y - function values + X2 - new spline nodes + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points from X/Y are used + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundLType - boundary condition type for the left boundary + BoundL - left boundary condition (first or second derivative, + depending on the BoundLType) + BoundRType - boundary condition type for the right boundary + BoundR - right boundary condition (first or second derivative, + depending on the BoundRType) + N2 - new points count: + * N2>=2 + * if given, only first N2 points from X2 are used + * if not given, automatically detected from X2 size + +OUTPUT PARAMETERS: + F2 - function values at X2[] + D2 - first derivatives at X2[] + DD2 - second derivatives at X2[] + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. +Function values are correctly reordered on return, so F2[I] is always +equal to S(X2[I]) independently of points order. + +SETTING BOUNDARY VALUES: + +The BoundLType/BoundRType parameters can have the following values: + * -1, which corresonds to the periodic (cyclic) boundary conditions. + In this case: + * both BoundLType and BoundRType must be equal to -1. + * BoundL/BoundR are ignored + * Y[last] is ignored (it is assumed to be equal to Y[first]). + * 0, which corresponds to the parabolically terminated spline + (BoundL and/or BoundR are ignored). + * 1, which corresponds to the first derivative boundary condition + * 2, which corresponds to the second derivative boundary condition + * by default, BoundType=0 is used + +PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS: + +Problems with periodic boundary conditions have Y[first_point]=Y[last_point]. +However, this subroutine doesn't require you to specify equal values for +the first and last points - it automatically forces them to be equal by +copying Y[first_point] (corresponds to the leftmost, minimal X[]) to +Y[last_point]. However it is recommended to pass consistent values of Y[], +i.e. to make Y[first_point]=Y[last_point]. + + -- ALGLIB PROJECT -- + Copyright 03.09.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams = alglib::xdefault); +void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds Catmull-Rom spline interpolant. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. + Y - function values, array[0..N-1]. + +OPTIONAL PARAMETERS: + N - points count: + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + BoundType - boundary condition type: + * -1 for periodic boundary condition + * 0 for parabolically terminated spline (default) + Tension - tension parameter: + * tension=0 corresponds to classic Catmull-Rom spline (default) + * 0=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds Hermite spline interpolant. + +Buffered version which reuses memory previously allocated in C as much as +possible. + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildhermitebuf(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildhermitebuf(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds Akima spline interpolant + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds modified Akima spline interpolant, with weights + + W[i]=|Delta[I]-Delta[I-1]| + +replaced by + + W[i]=|Delta[I]-Delta[I-1]|+0.5*|Delta[I]+Delta[I-1]| + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1] + Y - function values, array[0..N-1] + N - points count (optional): + * N>=2 + * if given, only first N points are used to build spline + * if not given, automatically detected from X/Y sizes + (len(X) must be equal to len(Y)) + +OUTPUT PARAMETERS: + C - spline interpolant + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildakimamod(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildakimamod(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates the value of the spline at the given point X. + +INPUT PARAMETERS: + C - spline interpolant + X - point + +Result: + S(x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dcalc(const spline1dinterpolant &c, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine differentiates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +Result: + S - S(x) + DS - S'(x) + D2S - S''(x) + + -- ALGLIB PROJECT -- + Copyright 24.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine unpacks the spline into the coefficients table. + +INPUT PARAMETERS: + C - spline interpolant. + X - point + +OUTPUT PARAMETERS: + Tbl - coefficients table, unpacked format, array[0..N-2, 0..5]. + For I = 0...N-2: + Tbl[I,0] = X[i] + Tbl[I,1] = X[i+1] + Tbl[I,2] = C0 + Tbl[I,3] = C1 + Tbl[I,4] = C2 + Tbl[I,5] = C3 + On [x[i], x[i+1]] spline is equals to: + S(x) = C0 + C1*t + C2*t^2 + C3*t^3 + t = x-x[i] + +NOTE: + You can rebuild spline with Spline1DBuildHermite() function, which + accepts as inputs function values and derivatives at nodes, which are + easy to calculate when you have coefficients. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: x = A*t + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransx(spline1dinterpolant &c, const double a, const double b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x) = A*S(x) + B +Result: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 30.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline1dlintransy(spline1dinterpolant &c, const double a, const double b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine integrates the spline. + +INPUT PARAMETERS: + C - spline interpolant. + X - right bound of the integration interval [a, x], + here 'a' denotes min(x[]) +Result: + integral(S(t)dt,a,x) + + -- ALGLIB PROJECT -- + Copyright 23.06.2007 by Bochkanov Sergey +*************************************************************************/ +double spline1dintegrate(const spline1dinterpolant &c, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fitting by the smoothing (penalized) cubic spline. + +This function approximates N scattered points (some of X[] may be equal to +each other) by the cubic spline with M equidistant nodes spanning interval +[min(x),max(x)]. + +The problem is regularized by adding nonlinearity penalty to the usual +least squares penalty function: + + MERIT_FUNC = F_LS + F_NL + +where F_LS is a least squares error term, and F_NL is a nonlinearity +penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }. +Algorithm applies automatic renormalization of F_NL which makes penalty +term roughly invariant to scaling of X[] and changes in M. + +This function is a new edition of penalized regression spline fitting, +a fast and compact one which needs much less resources that its previous +version: just O(maxMN) memory and O(maxMN) time. + +NOTE: it is OK to run this function with both M<>N; say, it is + possible to process 100 points with 1000-node spline. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y are processed + * if not given, automatically determined from lengths + M - number of basis functions ( = number_of_nodes), M>=4. + LambdaNS - LambdaNS>=0, regularization constant passed by user. + It penalizes nonlinearity in the regression spline. + Possible values to start from are 0.00001, 0.1, 1 + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - Following fields are set: + * TerminationType set to 1 + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + + -- ALGLIB PROJECT -- + Copyright 10.04.2023 by Bochkanov Sergey +*************************************************************************/ +void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds monotone cubic Hermite interpolant. This interpolant +is monotonic in [x(0),x(n-1)] and is constant outside of this interval. + +In case y[] form non-monotonic sequence, interpolant is piecewise +monotonic. Say, for x=(0,1,2,3,4) and y=(0,1,2,1,0) interpolant will +monotonically grow at [0..2] and monotonically decrease at [2..4]. + +INPUT PARAMETERS: + X - spline nodes, array[0..N-1]. Subroutine automatically + sorts points, so caller may pass unsorted array. + Y - function values, array[0..N-1] + N - the number of points(N>=2). + +OUTPUT PARAMETERS: + C - spline interpolant. + + -- ALGLIB PROJECT -- + Copyright 21.06.2012 by Bochkanov Sergey +*************************************************************************/ +void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine fits piecewise linear curve to points with Ramer-Douglas- +Peucker algorithm, which stops after generating specified number of linear +sections. + +IMPORTANT: +* it does NOT perform least-squares fitting; it builds curve, but this + curve does not minimize some least squares metric. See description of + RDP algorithm (say, in Wikipedia) for more details on WHAT is performed. +* this function does NOT work with parametric curves (i.e. curves which + can be represented as {X(t),Y(t)}. It works with curves which can be + represented as Y(X). Thus, it is impossible to model figures like + circles with this functions. + If you want to work with parametric curves, you should use + ParametricRDPFixed() function provided by "Parametric" subpackage of + "Interpolation" package. + +INPUT PARAMETERS: + X - array of X-coordinates: + * at least N elements + * can be unordered (points are automatically sorted) + * this function may accept non-distinct X (see below for + more information on handling of such inputs) + Y - array of Y-coordinates: + * at least N elements + N - number of elements in X/Y + M - desired number of sections: + * at most M sections are generated by this function + * less than M sections can be generated if we have N0 + * if given, only leading N elements of X/Y are used + * if not given, automatically determined from sizes of X/Y + M - number of basis functions (= polynomial_degree + 1), M>=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code which is always + set to 1 (success) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams = alglib::xdefault); +void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted fitting by polynomials in barycentric form, with constraints on +function values or first derivatives. + +Small regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +SEE ALSO: + PolynomialFit() + +NOTES: + you can convert P from barycentric form to the power or Chebyshev + basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions from + the POLINT subpackage. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + * if given, only leading N elements of X/Y/W are used + * if not given, automatically determined from sizes of X/Y/W + XC - points where polynomial values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that P(XC[i])=YC[i] + * DC[i]=1 means that P'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=1 + +OUTPUT PARAMETERS: + P - interpolant in barycentric form for Rep.TerminationType>0. + undefined for Rep.TerminationType<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* even simple constraints can be inconsistent, see Wikipedia article on + this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the one special cases, however, we can guarantee consistency. This + case is: M>1 and constraints on the function values (NOT DERIVATIVES) + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 10.12.2009 by Bochkanov Sergey +*************************************************************************/ +void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams = alglib::xdefault); +void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates value of four-parameter logistic (4PL) model at +specified point X. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D- parameters of 4PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to 2.0 even for zero X + (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc4(const double x, const double a, const double b, const double c, const double d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates value of five-parameter logistic (5PL) model at +specified point X. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +INPUT PARAMETERS: + X - current point, X>=0: + * zero X is correctly handled even for B<=0 + * negative X results in exception. + A, B, C, D, G- parameters of 5PL model: + * A is unconstrained + * B is unconstrained; zero or negative values are handled + correctly. + * C>0, non-positive value results in exception + * D is unconstrained + * G>0, non-positive value results in exception + +RESULT: + model value at X + +NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even for + zero X (strictly speaking, 0^0 is undefined). + +NOTE: this function also throws exception if all input parameters are + correct, but overflow was detected during calculations. + +NOTE: this function performs a lot of checks; if you need really high + performance, consider evaluating model yourself, without checking + for degenerate cases. + + + -- ALGLIB PROJECT -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user. 4PL model has following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL) + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits four-parameter logistic (4PL) model to data provided +by user, with optional constraints on parameters A and D. 4PL model has +following form: + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) + +Here: + * A, D - with optional equality constraints + * B>=0 + * C>0 + +IMPORTANT: output of this function is constrained in such way that B>0. + Because 4PL model is symmetric with respect to B, there is no + need to explore B<0. Constraining B makes algorithm easier + to stabilize and debug. + Users who for some reason prefer to work with negative B's + should transform output themselves (swap A and D, replace B by + -B). + +4PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". +* second Levenberg-Marquardt round is performed without excessive + constraints. Results from the previous round are used as initial guess. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for stability reasons the B parameter is restricted by [1/1000,1000] + range. It prevents algorithm from making trial steps deep into the + area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc4() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit4ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user. 5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - unconstrained + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits five-parameter logistic (5PL) model to data provided +by user, subject to optional equality constraints on parameters A and D. +5PL model has following form: + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) + +Here: + * A, D - with optional equality constraints + * B - unconstrained + * C>0 + * G>0 + +IMPORTANT: unlike in 4PL fitting, output of this function is NOT + constrained in such way that B is guaranteed to be positive. + Furthermore, unlike 4PL, 5PL model is NOT symmetric with + respect to B, so you can NOT transform model to equivalent one, + with B having desired sign (>0 or <0). + +5PL fitting is implemented as follows: +* we perform small number of restarts from random locations which helps to + solve problem of bad local extrema. Locations are only partially random + - we use input data to determine good initial guess, but we include + controlled amount of randomness. +* we perform Levenberg-Marquardt fitting with very tight constraints on + parameters B and C - it allows us to find good initial guess for the + second stage without risk of running into "flat spot". Parameter G is + fixed at G=1. +* second Levenberg-Marquardt round is performed without excessive + constraints on B and C, but with G still equal to 1. Results from the + previous round are used as initial guess. +* third Levenberg-Marquardt round relaxes constraints on G and tries two + different models - one with B>0 and one with B<0. +* after fitting is done, we compare results with best values found so far, + rewrite "best solution" if needed, and move to next random location. + +Overall algorithm is very stable and is not prone to bad local extrema. +Furthermore, it automatically scales when input data have very large or +very small range. + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + +OUTPUT PARAMETERS: + A,B,C,D,G- parameters of 5PL model + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: if you need better control over fitting process than provided by this + function, you may use LogisticFit45X(). + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. + +Unlike 4PL one, 5PL model is NOT symmetric with respect to change in sign +of B. Thus, negative B's are possible, and left constraint may constrain +parameter A (for positive B's) - or parameter D (for negative B's). +Similarly changes meaning of right constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit5ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is "expert" 4PL/5PL fitting function, which can be used if you need +better control over fitting process than provided by LogisticFit4() or +LogisticFit5(). + +This function fits model of the form + + F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B)) (4PL model) + +or + + F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G) (5PL model) + +Here: + * A, D - unconstrained + * B>=0 for 4PL, unconstrained for 5PL + * C>0 + * G>0 (if present) + +INPUT PARAMETERS: + X - array[N], stores X-values. + MUST include only non-negative numbers (but may include + zero values). Can be unsorted. + Y - array[N], values to fit. + N - number of points. If N is less than length of X/Y, only + leading N elements are used. + CnstrLeft- optional equality constraint for model value at the left + boundary (at X=0). Specify NAN (Not-a-Number) if you do + not need constraint on the model value at X=0 (in C++ you + can pass alglib::fp_nan as parameter, in C# it will be + Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + CnstrRight- optional equality constraint for model value at X=infinity. + Specify NAN (Not-a-Number) if you do not need constraint + on the model value (in C++ you can pass alglib::fp_nan as + parameter, in C# it will be Double.NaN). + See below, section "EQUALITY CONSTRAINTS" for more + information about constraints. + Is4PL - whether 4PL or 5PL models are fitted + LambdaV - regularization coefficient, LambdaV>=0. + Set it to zero unless you know what you are doing. + EpsX - stopping condition (step size), EpsX>=0. + Zero value means that small step is automatically chosen. + See notes below for more information. + RsCnt - number of repeated restarts from random points. 4PL/5PL + models are prone to problem of bad local extrema. Utilizing + multiple random restarts allows us to improve algorithm + convergence. + RsCnt>=0. + Zero value means that function automatically choose small + amount of restarts (recommended). + +OUTPUT PARAMETERS: + A, B, C, D- parameters of 4PL model + G - parameter of 5PL model; for Is4PL=True, G=1 is returned. + Rep - fitting report. This structure has many fields, but ONLY + ONES LISTED BELOW ARE SET: + * Rep.IterationsCount - number of iterations performed + * Rep.RMSError - root-mean-square error + * Rep.AvgError - average absolute error + * Rep.AvgRelError - average relative error (calculated for + non-zero Y-values) + * Rep.MaxError - maximum absolute error + * Rep.R2 - coefficient of determination, R-squared. This + coefficient is calculated as R2=1-RSS/TSS (in case + of nonlinear regression there are multiple ways to + define R2, each of them giving different results). + +NOTE: for better stability B parameter is restricted by [+-1/1000,+-1000] + range, and G is restricted by [1/10,10] range. It prevents algorithm + from making trial steps deep into the area of bad parameters. + +NOTE: after you obtained coefficients, you can evaluate model with + LogisticCalc5() function. + +NOTE: step is automatically scaled according to scale of parameters being + fitted before we compare its length with EpsX. Thus, this function + can be used to fit data with very small or very large values without + changing EpsX. + +EQUALITY CONSTRAINTS ON PARAMETERS + +4PL/5PL solver supports equality constraints on model values at the left +boundary (X=0) and right boundary (X=infinity). These constraints are +completely optional and you can specify both of them, only one - or no +constraints at all. + +Parameter CnstrLeft contains left constraint (or NAN for unconstrained +fitting), and CnstrRight contains right one. For 4PL, left constraint +ALWAYS corresponds to parameter A, and right one is ALWAYS constraint on +D. That's because 4PL model is normalized in such way that B>=0. + +For 5PL model things are different. Unlike 4PL one, 5PL model is NOT +symmetric with respect to change in sign of B. Thus, negative B's are +possible, and left constraint may constrain parameter A (for positive B's) +- or parameter D (for negative B's). Similarly changes meaning of right +constraint. + +You do not have to decide what parameter to constrain - algorithm will +automatically determine correct parameters as fitting progresses. However, +question highlighted above is important when you interpret fitting results. + + + -- ALGLIB PROJECT -- + Copyright 14.02.2014 by Bochkanov Sergey +*************************************************************************/ +void logisticfit45x(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, const bool is4pl, const double lambdav, const double epsx, const ae_int_t rscnt, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weghted rational least squares fitting using Floater-Hormann rational +functions with optimal D chosen from [0,9], with constraints and +individual weights. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least WEIGHTED root +mean square error) is chosen. Task is linear, so linear least squares +solver is used. Complexity of this computational scheme is O(N*M^2) +(mostly dominated by the least squares solver). + +SEE ALSO +* BarycentricFitFloaterHormann(), "lightweight" fitting without invididual + weights and constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points, N>0. + XC - points where function values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints, 0<=K=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. Undefined for rep.terminationtype<0. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroutine doesn't calculate task's condition number for K<>0. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained barycentric interpolants: +* excessive constraints can be inconsistent. Floater-Hormann basis + functions aren't as flexible as splines (although they are very smooth). +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function VALUES at the interval + boundaries. Note that consustency of the constraints on the function + DERIVATIVES is NOT guaranteed (you can use in such cases cubic splines + which are more flexible). +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Rational least squares fitting using Floater-Hormann rational functions +with optimal D chosen from [0,9]. + +Equidistant grid with M node on [min(x),max(x)] is used to build basis +functions. Different values of D are tried, optimal D (least root mean +square error) is chosen. Task is linear, so linear least squares solver +is used. Complexity of this computational scheme is O(N*M^2) (mostly +dominated by the least squares solver). + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + N - number of points, N>0. + M - number of basis functions ( = number_of_nodes), M>=2. + +OUTPUT PARAMETERS: + B - barycentric interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code, always set to 1 + * DBest best value of the D parameter + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted fitting by cubic spline, with constraints on function values or +derivatives. + +Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are cubic splines with continuous second +derivatives and non-fixed first derivatives at interval ends. Small +regularizing term is used when solving constrained tasks (to improve +stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4. + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints IS NOT GUARANTEED. +* in the several special cases, however, we CAN guarantee consistency. +* one of this cases is constraints on the function values AND/OR its + derivatives at the interval boundaries. +* another special case is ONE constraint on the function value (OR, but + not AND, derivative) anywhere in the interval + +Our final recommendation is to use constraints WHEN AND ONLY WHEN you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted fitting by Hermite spline, with constraints on function values +or first derivatives. + +Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is used to build +basis functions. Basis functions are Hermite splines. Small regularizing +term is used when solving constrained tasks (to improve stability). + +Task is linear, so linear least squares solver is used. Complexity of this +computational scheme is O(N*M^2), mostly dominated by least squares solver + +IMPORTANT: ALGLIB has a much faster version of the cubic spline fitting + function - spline1dfit(). This function performs least squares + fit in O(max(M,N)) time/memory. However, it does not support + constraints. + +INPUT PARAMETERS: + X - points, array[0..N-1]. + Y - function values, array[0..N-1]. + W - weights, array[0..N-1] + Each summand in square sum of approximation deviations from + given values is multiplied by the square of corresponding + weight. Fill it by 1's if you don't want to solve weighted + task. + N - number of points (optional): + * N>0 + * if given, only first N elements of X/Y/W are processed + * if not given, automatically determined from X/Y/W sizes + XC - points where spline values/derivatives are constrained, + array[0..K-1]. + YC - values of constraints, array[0..K-1] + DC - array[0..K-1], types of constraints: + * DC[i]=0 means that S(XC[i])=YC[i] + * DC[i]=1 means that S'(XC[i])=YC[i] + SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS + K - number of constraints (optional): + * 0<=K=4, + M IS EVEN! + +OUTPUT PARAMETERS: + S - spline interpolant. + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints, degenerate constraints + or inconsistent constraints were passed + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +IMPORTANT: + this subroitine supports only even M's + + +ORDER OF POINTS + +Subroutine automatically sorts points, so caller may pass unsorted array. + +SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES: + +Setting constraints can lead to undesired results, like ill-conditioned +behavior, or inconsistency being detected. From the other side, it allows +us to improve quality of the fit. Here we summarize our experience with +constrained regression splines: +* excessive constraints can be inconsistent. Splines are piecewise cubic + functions, and it is easy to create an example, where large number of + constraints concentrated in small area will result in inconsistency. + Just because spline is not flexible enough to satisfy all of them. And + same constraints spread across the [min(x),max(x)] will be perfectly + consistent. +* the more evenly constraints are spread across [min(x),max(x)], the more + chances that they will be consistent +* the greater is M (given fixed constraints), the more chances that + constraints will be consistent +* in the general case, consistency of constraints is NOT GUARANTEED. +* in the several special cases, however, we can guarantee consistency. +* one of this cases is M>=4 and constraints on the function value + (AND/OR its derivative) at the interval boundaries. +* another special case is M>=4 and ONE constraint on the function value + (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)] + +Our final recommendation is to use constraints WHEN AND ONLY when you +can't solve your task without them. Anything beyond special cases given +above is not guaranteed and may result in inconsistency. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermitedeprecated(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfithermitedeprecated(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType always set to 1 (success) + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); +void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted constained linear least squares fitting. + +This is variation of LSFitLinearW(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinearW() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + W - array[0..N-1] Weights corresponding to function values. + Each summand in square sum of approximation deviations + from given values is multiplied by the square of + corresponding weight. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. The following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); +void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Linear least squares fitting. + +QR decomposition is used to reduce task to MxM, then triangular solver or +SVD-based solver is used depending on condition number of the system. It +allows to maximize speed and retain decent accuracy. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I, J] - value of J-th basis function in I-th point. + N - number of points used. N>=1. + M - number of basis functions, M>=1. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code, always set to + 1 which denotes success + * Rep.TaskRCond reciprocal of condition number + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); +void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Constained linear least squares fitting. + +This is variation of LSFitLinear(), which searchs for min|A*x=b| given +that K additional constaints C*x=bc are satisfied. It reduces original +task to modified one: min|B*y-d| WITHOUT constraints, then LSFitLinear() +is called. + +IMPORTANT: if you want to perform polynomial fitting, it may be more + convenient to use PolynomialFit() function. This function gives + best results on polynomial problems and solves numerical + stability issues which arise when you fit high-degree + polynomials to your data. + +INPUT PARAMETERS: + Y - array[0..N-1] Function values in N points. + FMatrix - a table of basis functions values, array[0..N-1, 0..M-1]. + FMatrix[I,J] - value of J-th basis function in I-th point. + CMatrix - a table of constaints, array[0..K-1,0..M]. + I-th row of CMatrix corresponds to I-th linear constraint: + CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M] + N - number of points used. N>=1. + M - number of basis functions, M>=1. + K - number of constraints, 0 <= K < M + K=0 corresponds to absence of constraints. + +OUTPUT PARAMETERS: + C - decomposition coefficients, array[0..M-1] + Rep - fitting report. Following fields are set: + * Rep.TerminationType is a completion code: + * set to 1 on success + * set to -3 on failure due to problematic constraints: + either too many constraints (M or more), degenerate + constraints (some constraints are repetead twice) or + inconsistent constraints are specified + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + +IMPORTANT: + this subroitine doesn't calculate task's condition number for K<>0. + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(F*CovPar*F')), + where F is functions matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 07.09.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); +void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams = alglib::xdefault); +void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Nonlinear least squares fitting using function values only. + +Combination of numerical differentiation and secant updates is used to +obtain function Jacobian. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]). + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + DiffStep- numerical differentiation step, >0; Obviously, step size + should not be too large in order to get a good numerical + derivative. However, it also should not be too small + because numerical errors are greatly amplified by numerical + differentiation. + By default, symmetric 3-point formula which provides good + accuracy is used. It can be changed to a faster but less + precise 2-point one with minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 18.10.2008 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams = alglib::xdefault); +void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Weighted nonlinear least squares fitting using gradient only. + +Nonlinear task min(F(c)) is solved, where + + F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * w is an N-dimensional vector of weight coefficients, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + W - weights, array[0..N-1] + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also: + LSFitResults + LSFitCreateFG (fitting without weights) + LSFitCreateWFGH (fitting using Hessian) + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams = alglib::xdefault); +void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, lsfitstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Nonlinear least squares fitting using gradient only, without individual +weights. + +Nonlinear task min(F(c)) is solved, where + + F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2, + + * N is a number of points, + * M is a dimension of a space points belong to, + * K is a dimension of a space of parameters being fitted, + * x is a set of N points, each of them is an M-dimensional vector, + * c is a K-dimensional vector of parameters being fitted + +This subroutine uses only f(c,x[i]) and its gradient. + +INPUT PARAMETERS: + X - array[0..N-1,0..M-1], points (one row = one point) + Y - array[0..N-1], function values. + C - array[0..K-1], initial approximation to the solution, + N - number of points, N>1 + M - dimension of space + K - number of parameters being fitted + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LSFIT optimizer supports parallel model evaluation and + parallel numerical differentiation ('callback parallelism'). + This feature, which is present in commercial ALGLIB editions, + greatly accelerates fits with large datasets and/or expensive + target functions. + + Callback parallelism is usually beneficial when a single pass + over the entire dataset requires more than several + milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on lsfitfit() function for more + information. + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams = alglib::xdefault); +void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LSFIT solver compares squared errors f[1] at the +trial point with the value at the current point f[0]. Only steps that +decrease f() are accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnonmonotonicsteps(lsfitstate &state, const ae_int_t cnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers configured to use numerical differentiation; +in other cases it has no effect. + +INPUT PARAMETERS: + State - optimizer + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetnumdiff(lsfitstate &state, const ae_int_t formulatype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Stopping conditions for nonlinear least squares fitting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by LSFitSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +NOTE + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (according to the scheme used by MINLM unit). + + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetcond(lsfitstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetstpmax(lsfitstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +When reports are needed, State.C (current parameters) and State.F (current +value of fitting function) are reported. + + + -- ALGLIB -- + Copyright 15.08.2010 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetxrep(lsfitstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for underlying optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetscale(lsfitstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for underlying optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[K]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[K]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unlike other constrained optimization algorithms, this solver has +following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetbc(lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear constraints for underlying optimizer + +Linear constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetLC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with lsfitsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +NOTE: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 29.04.2017 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetlc(lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void lsfitsetlc(lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool lsfititeration(lsfitstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear fitter + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM: + +The LSFIT optimizer supports parallel model evaluation and parallel +numerical differentiation ('callback parallelism'). This feature, which is +present in commercial ALGLIB editions, greatly accelerates fits with large +datasets and/or expensive target functions. + +Callback parallelism is usually beneficial when a single pass over the +entire dataset requires more than several milliseconds. In this case the +job of computing model values at dataset points can be split between +multiple threads. + +If you employ a numerical differentiation scheme, you can also parallelize +computation of different components of a numerical gradient. Generally, the +mode computationally demanding your problem is (many points, numerical differentiation, +expensive model), the more you can get for multithreading. + +ALGLIB Reference Manual, 'Working with commercial version' section, +describes how to activate callback parallelism for your programming language. + +CALLBACK ARGUMENTS + +This algorithm is somewhat unusual because it works with parameterized +function f(C,X), where X is a function argument (we have many points +which are characterized by different argument values), and C is a +parameter to fit. + +For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1, then +x will be argument, and {c0,c1} will be parameters. + +It is important to understand that this algorithm finds minimum in the +space of function PARAMETERS (not arguments), so it needs derivatives +of f() with respect to C, not X. + +In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1} +instead of {df/dx} = {c0}. + + -- ALGLIB -- + Copyright 17.12.2023 by Bochkanov Sergey + + +*************************************************************************/ +void lsfitfit(lsfitstate &state, + void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void lsfitfit(lsfitstate &state, + void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr), + void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &c, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Nonlinear least squares fitting results. + +Called after return from LSFitFit(). + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + C - array[K], solution + Rep - optimization report. On success following fields are set: + * TerminationType completion code: + * -8 optimizer detected NAN/INF in the target + function and/or gradient + * -7 gradient verification failed. + See LSFitSetGradientCheck() for more information. + * -3 inconsistent constraints + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * R2 non-adjusted coefficient of determination + (non-weighted) + * RMSError rms error on the (X,Y). + * AvgError average error on the (X,Y). + * AvgRelError average relative error on the non-zero Y + * MaxError maximum error + NON-WEIGHTED ERRORS ARE CALCULATED + * WRMSError weighted rms error on the (X,Y). + +ERRORS IN PARAMETERS + +This solver also calculates different kinds of errors in parameters and +fills corresponding fields of report: +* Rep.CovPar covariance matrix for parameters, array[K,K]. +* Rep.ErrPar errors in parameters, array[K], + errpar = sqrt(diag(CovPar)) +* Rep.ErrCurve vector of fit errors - standard deviations of empirical + best-fit curve from "ideal" best-fit curve built with + infinite number of samples, array[N]. + errcurve = sqrt(diag(J*CovPar*J')), + where J is Jacobian matrix. +* Rep.Noise vector of per-point estimates of noise, array[N] + +IMPORTANT: errors in parameters are calculated without taking into + account boundary/linear constraints! Presence of constraints + changes distribution of errors, but there is no easy way to + account for constraints when you calculate covariance matrix. + +NOTE: noise in the data is estimated as follows: + * for fitting without user-supplied weights all points are + assumed to have same level of noise, which is estimated from + the data + * for fitting with user-supplied weights we assume that noise + level in I-th point is inversely proportional to Ith weight. + Coefficient of proportionality is estimated from the data. + +NOTE: we apply small amount of regularization when we invert squared + Jacobian and calculate covariance matrix. It guarantees that + algorithm won't divide by zero during inversion, but skews + error estimates a bit (fractional error is about 10^-9). + + However, we believe that this difference is insignificant for + all practical purposes except for the situation when you want + to compare ALGLIB results with "reference" implementation up + to the last significant digit. + +NOTE: covariance matrix is estimated using correction for degrees + of freedom (covariances are divided by N-M instead of dividing + by N). + + -- ALGLIB -- + Copyright 17.08.2009 by Bochkanov Sergey +*************************************************************************/ +void lsfitresults(const lsfitstate &state, real_1d_array &c, lsfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine turns on verification of the user-supplied analytic +gradient: +* user calls this subroutine before fitting begins +* LSFitFit() is called +* prior to actual fitting, for each point in data set X_i and each + component of parameters being fited C_j algorithm performs following + steps: + * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j], + where C_j is j-th parameter and S[j] is a scale of j-th parameter + * if needed, steps are bounded with respect to constraints on C[] + * F(X_i|C) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + * in case difference between prediction and actual value is higher than + some predetermined threshold, algorithm stops with completion code -7; + Rep.VarIdx is set to index of the parameter with incorrect derivative. +* after verification is over, algorithm proceeds to the actual optimization. + +NOTE 1: verification needs N*K (points count * parameters count) gradient + evaluations. It is very costly and you should use it only for low + dimensional problems, when you want to be sure that you've + correctly calculated analytic derivatives. You should not use it + in the production code (unless you want to check derivatives + provided by some third party). + +NOTE 2: you should carefully choose TestStep. Value which is too large + (so large that function behaviour is significantly non-cubic) will + lead to false alarms. You may use different step for different + parameters by means of setting scale with LSFitSetScale(). + +NOTE 3: this function may lead to false positives. In case it reports that + I-th derivative was calculated incorrectly, you may decrease test + step and try one more time - maybe your function changes too + sharply and your step is too large for such rapidly chanding + function. + +NOTE 4: this function works only for optimizers created with LSFitCreateWFG() + or LSFitCreateFG() constructors. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step: + * TestStep=0 turns verification off + * TestStep>0 activates verification + + -- ALGLIB -- + Copyright 15.06.2012 by Bochkanov Sergey +*************************************************************************/ +void lsfitsetgradientcheck(lsfitstate &state, const double teststep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Fits least squares (LS) circle (or NX-dimensional sphere) to data (a set +of points in NX-dimensional space). + +Least squares circle minimizes sum of squared deviations between distances +from points to the center and some "candidate" radius, which is also +fitted to the data. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + R - radius + + -- ALGLIB -- + Copyright 07.05.2018 by Bochkanov Sergey +*************************************************************************/ +void fitspherels(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to data +(a set of points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RHi - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremi(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fits minimum zone circle (or NX-dimensional sphere) to data (a set of +points in NX-dimensional space). + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius of inscribed circle + RHo - radius of circumscribed circle + +NOTE: this function is an easy-to-use wrapper around more powerful "expert" + function fitspherex(). + + This wrapper is optimized for ease of use and stability - at the + cost of somewhat lower performance (we have to use very tight + stopping criteria for inner optimizer because we want to make sure + that it will converge on any dataset). + + If you are ready to experiment with settings of "expert" function, + you can achieve ~2-4x speedup over standard "bulletproof" settings. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspheremz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Fitting minimum circumscribed, maximum inscribed or minimum zone circles +(or NX-dimensional spheres) to data (a set of points in NX-dimensional +space). + +This is expert function which allows to tweak many parameters of +underlying nonlinear solver: +* stopping criteria for inner iterations +* number of outer iterations + +You may tweak all these parameters or only some of them, leaving other +ones at their default state - just specify zero value, and solver will +fill it with appropriate default one. + +These comments also include some discussion of approach used to handle +such unusual fitting problem, its stability, drawbacks of alternative +methods, and convergence properties. + +INPUT PARAMETERS: + XY - array[NPoints,NX] (or larger), contains dataset. + One row = one point in NX-dimensional space. + NPoints - dataset size, NPoints>0 + NX - space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on) + ProblemType-used to encode problem type: + * 0 for least squares circle + * 1 for minimum circumscribed circle/sphere fitting (MC) + * 2 for maximum inscribed circle/sphere fitting (MI) + * 3 for minimum zone circle fitting (difference between + Rhi and Rlo is minimized), denoted as MZ + EpsX - stopping condition for NLC optimizer: + * must be non-negative + * use 0 to choose default value (1.0E-12 is used by default) + * you may specify larger values, up to 1.0E-6, if you want + to speed-up solver; NLC solver performs several + preconditioned outer iterations, so final result + typically has precision much better than EpsX. + AULIts - number of outer iterations performed by NLC optimizer: + * must be non-negative + * use 0 to choose default value (20 is used by default) + * you may specify values smaller than 20 if you want to + speed up solver; 10 often results in good combination of + precision and speed; sometimes you may get good results + with just 6 outer iterations. + Ignored for ProblemType=0. + +OUTPUT PARAMETERS: + CX - central point for a sphere + RLo - radius: + * for ProblemType=2,3, radius of the inscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=1 - zero + RHo - radius: + * for ProblemType=1,3, radius of the circumscribed sphere + * for ProblemType=0 - radius of the least squares sphere + * for ProblemType=2 - zero + +NOTE: ON THE UNIQUENESS OF SOLUTIONS + +ALGLIB provides solution to several related circle fitting problems: MC +(minimum circumscribed), MI (maximum inscribed) and MZ (minimum zone) +fitting, LS (least squares) fitting. + +It is important to note that among these problems only MC and LS are +convex and have unique solution independently from starting point. + +As for MI, it may (or may not, depending on dataset properties) have +multiple solutions, and it always has one degenerate solution C=infinity +which corresponds to infinitely large radius. Thus, there are no guarantees +that solution to MI returned by this solver will be the best one (and no +one can provide you with such guarantee because problem is NP-hard). The +only guarantee you have is that this solution is locally optimal, i.e. it +can not be improved by infinitesimally small tweaks in the parameters. + +It is also possible to "run away" to infinity when started from bad +initial point located outside of point cloud (or when point cloud does not +span entire circumference/surface of the sphere). + +Finally, MZ (minimum zone circle) stands somewhere between MC and MI in +stability. It is somewhat regularized by "circumscribed" term of the merit +function; however, solutions to MZ may be non-unique, and in some unlucky +cases it is also possible to "run away to infinity". + + +NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH + +The problem formulation for MC (minimum circumscribed circle; for the +sake of simplicity we omit MZ and MI here) is: + + [ [ ]2 ] + min [ max [ XY[i]-C ] ] + C [ i [ ] ] + +i.e. it is unconstrained nonsmooth optimization problem of finding "best" +central point, with radius R being unambiguously determined from C. In +order to move away from non-smoothness we use following reformulation: + + [ ] [ ]2 + min [ R ] subject to R>=0, [ XY[i]-C ] <= R^2 + C,R [ ] [ ] + +i.e. it becomes smooth quadratically constrained optimization problem with +linear target function. Such problem statement is 100% equivalent to the +original nonsmooth one, but much easier to approach. We solve it with +MinNLC solver provided by ALGLIB. + + +NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH + +ALGLIB has nonlinearly constrained solver which proved to be stable on +such problems. However, some authors proposed to linearize constraints in +the vicinity of current approximation (Ci,Ri) and to get next approximate +solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously, +LP problems are easier than nonlinearly constrained ones. + +Indeed, such approach to MC/MI/MZ resulted in ~10-20x increase in +performance (when compared with NLC solver). However, it turned out that +in some cases linearized model fails to predict correct direction for next +step and tells us that we converged to solution even when we are still 2-4 +digits of precision away from it. + +It is important that it is not failure of LP solver - it is failure of the +linear model; even when solved exactly, it fails to handle subtle +nonlinearities which arise near the solution. We validated it by comparing +results returned by ALGLIB linear solver with that of MATLAB. + +In our experiments with linearization: +* MC failed most often, at both realistic and synthetic datasets +* MI sometimes failed, but sometimes succeeded +* MZ often succeeded; our guess is that presence of two independent sets + of constraints (one set for Rlo and another one for Rhi) and two terms + in the target function (Rlo and Rhi) regularizes task, so when linear + model fails to handle nonlinearities from Rlo, it uses Rhi as a hint + (and vice versa). + +Because linearization approach failed to achieve stable results, we do not +include it in ALGLIB. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void fitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function builds non-periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + Order of points is important! + N - points count, N>=5 for Akima splines, N>=2 for other types of + splines. + ST - spline type: + * 0 Akima spline + * 1 parabolically terminated Catmull-Rom spline (Tension=0) + * 2 parabolically terminated cubic spline + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds non-periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds periodic 2-dimensional parametric spline which +starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then +back to (X[0],Y[0]). + +INPUT PARAMETERS: + XY - points, array[0..N-1,0..1]. + XY[I,0:1] corresponds to the Ith point. + XY[N-1,0:1] must be different from XY[0,0:1]. + Order of points is important! + N - points count, N>=3 for other types of splines. + ST - spline type: + * 1 Catmull-Rom spline (Tension=0) with cyclic boundary conditions + * 2 cubic spline with cyclic boundary conditions + PT - parameterization type: + * 0 uniform + * 1 chord length + * 2 centripetal + +OUTPUT PARAMETERS: + P - parametric spline interpolant + + +NOTES: +* this function assumes that there all consequent points are distinct. + I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2), (x2,y2)<>(x3,y3) and so on. + However, non-consequent points may coincide, i.e. we can have (x0,y0)= + =(x2,y2). +* last point of sequence is NOT equal to the first point. You shouldn't + make curve "explicitly periodic" by making them equal. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds periodic 3-dimensional parametric spline which +starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1]) +and then back to (X[0],Y[0],Z[0]). + +Same as PSpline2Build() function, but for 3D, so we won't duplicate its +description here. + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns vector of parameter values correspoding to points. + +I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P) we +have + (X[0],Y[0]) = PSpline2Calc(P,U[0]), + (X[1],Y[1]) = PSpline2Calc(P,U[1]), + (X[2],Y[2]) = PSpline2Calc(P,U[2]), + ... + +INPUT PARAMETERS: + P - parametric spline interpolant + +OUTPUT PARAMETERS: + N - array size + T - array[0..N-1] + + +NOTES: +* for non-periodic splines U[0]=0, U[0]1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates the value of the parametric spline for a given +value of parameter T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-position + Y - Y-position + Z - Z-position + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + +NOTE: + X^2+Y^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates tangent vector for a given value of parameter T + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-component of tangent vector (normalized) + Y - Y-component of tangent vector (normalized) + Z - Z-component of tangent vector (normalized) + +NOTE: + X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0. + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT). + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - X-derivative + Y - Y-value + DY - Y-derivative + Z - Z-value + DZ - Z-derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates first and second derivative with respect to T. + +INPUT PARAMETERS: + P - parametric spline interpolant + T - point: + * T in [0,1] corresponds to interval spanned by points + * for non-periodic splines T<0 (or T>1) correspond to parts of + the curve before the first (after the last) point + * for periodic splines T<0 (or T>1) are projected into [0,1] + by making T=T-floor(T). + +OUTPUT PARAMETERS: + X - X-value + DX - derivative + D2X - second derivative + Y - Y-value + DY - derivative + D2Y - second derivative + Z - Z-value + DZ - derivative + D2Z - second derivative + + + -- ALGLIB PROJECT -- + Copyright 28.05.2010 by Bochkanov Sergey +*************************************************************************/ +void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates arc length, i.e. length of curve between t=a +and t=b. + +INPUT PARAMETERS: + P - parametric spline interpolant + A,B - parameter values corresponding to arc ends: + * B>A will result in positive length returned + * BA will result in positive length returned + * B1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 15 May, 2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bilinear spline resampling + +Input parameters: + A - function values at the old grid, + array[0..OldHeight-1, 0..OldWidth-1] + OldHeight - old grid height, OldHeight>1 + OldWidth - old grid width, OldWidth>1 + NewHeight - new grid height, NewHeight>1 + NewWidth - new grid width, NewWidth>1 + +Output parameters: + B - function values at the new grid, + array[0..NewHeight-1, 0..NewWidth-1] + + -- ALGLIB routine -- + 09.07.2007 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline. + +Buffered version of Spline2DBuildBilinearV() which reuses memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C0-continuous spline, i.e. the spline itself is +continuous, however its first and second derivatives have discontinuities +at the spline cell boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissing(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bilinear vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBilinearMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinearmissingbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using parabolically +terminated end conditions. + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline2dbuildbicubicv(const real_1d_array &x, const real_1d_array &y, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds a bicubic vector-valued spline using clamped +boundary conditions: +* spline values at the grid nodes are specified +* boundary conditions for first, second derivatives or for parabolic + termination at four boundaries (bottom y=min(Y[]), top y=max(Y[]), left + x=min(X[]), right x=max(X[])) are specified +* mixed derivatives at corners are specified +* it is possible to have different boundary conditions for different + boundaries (first derivatives along one boundary, second derivatives + along other one, parabolic termination along the rest and so on) +* it is possible to have either a scalar (D=1) or a vector-valued spline + +This function produces a C2-continuous spline, i.e. the spline has smooth +first and second derivatives both inside spline cells and at their +boundaries. + +INPUT PARAMETERS: + X - spline abscissas, array[N]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M]. Can be unsorted, the + function will sort it together with boundary conditions + and F[] array (the same set of permutations will be + applied to X[] and F[]). + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + BndBtm - array[D*N], boundary conditions at the bottom boundary + of the interpolation area (corresponds to y=min(Y[]): + * if BndTypeBtm=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndBtm is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeBtm=1, first derivatives are given + * if BndTypeBtm=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=minY, + subsequent D entries store derivatives at x=X[1], + y=minY and so on + BndTop - array[D*N], boundary conditions at the top boundary + of the interpolation area (corresponds to y=max(Y[]): + * if BndTypeTop=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndTop is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to X + * if BndTypeTop=1, first derivatives are given + * if BndTypeTop=2, second derivatives are given + * first D entries store derivatives at x=X[0], y=maxY, + subsequent D entries store derivatives at x=X[1], + y=maxY and so on + BndLft - array[D*M], boundary conditions at the left boundary + of the interpolation area (corresponds to x=min(X[]): + * if BndTypeLft=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndLft is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeLft=1, first derivatives are given + * if BndTypeLft=2, second derivatives are given + * first D entries store derivatives at x=minX, y=Y[0], + subsequent D entries store derivatives at x=minX, + y=Y[1] and so on + BndRgt - array[D*M], boundary conditions at the right boundary + of the interpolation area (corresponds to x=max(X[]): + * if BndTypeRgt=0, the spline has a 'parabolic + termination' boundary condition across that specific + boundary. In this case BndRgt is not even referenced + by the function and can be unallocated. + * otherwise contains derivatives with respect to Y + * if BndTypeRgt=1, first derivatives are given + * if BndTypeRgt=2, second derivatives are given + * first D entries store derivatives at x=maxX, y=Y[0], + subsequent D entries store derivatives at x=maxX, + y=Y[1] and so on + MixedD - array[D*4], mixed derivatives at 4 corners of the + interpolation area: + * derivative order depends on the order of boundary + conditions (bottom/top and left/right) intersecting + at that corner: + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=1 user has + to provide d2S/dXdY + ** for BndType(Btm|Top)=BndType(Lft|Rgt)=2 user has + to provide d4S/(dX^2*dY^2) + ** for BndType(Btm|Top)=1, BndType(Lft|Rgt)=2 user + has to provide d3S/(dX^2*dY) + ** for BndType(Btm|Top)=2, BndType(Lft|Rgt)=1 user + has to provide d3S/(dX*dY^2) + ** if one of the intersecting bounds has 'parabolic + termination' condition, this specific mixed + derivative is not used + * first D entries store derivatives at the bottom left + corner x=min(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the bottom + right corner x=max(X[]), y=min(Y[]) + * subsequent D entries store derivatives at the top + left corner x=min(X[]), y=max(Y[]) + * subsequent D entries store derivatives at the top + right corner x=max(X[]), y=max(Y[]) + * if all bounds have 'parabolic termination' condition, + MixedD[] is not referenced at all and can be + unallocated. + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are + stored at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildclampedv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &bndbtm, const ae_int_t bndtypebtm, const real_1d_array &bndtop, const ae_int_t bndtypetop, const real_1d_array &bndlft, const ae_int_t bndtypelft, const real_1d_array &bndrgt, const ae_int_t bndtypergt, const real_1d_array &mixedd, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline2dbuildclampedv(const real_1d_array &x, const real_1d_array &y, const real_1d_array &bndbtm, const ae_int_t bndtypebtm, const real_1d_array &bndtop, const ae_int_t bndtypetop, const real_1d_array &bndlft, const ae_int_t bndtypelft, const real_1d_array &bndrgt, const ae_int_t bndtypergt, const real_1d_array &mixedd, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds a Hermite bicubic vector-valued spline. + +This function produces merely C1-continuous spline, i.e. the spline has +smooth first derivatives. + +INPUT PARAMETERS: + X - spline abscissas, array[N] + N - N>=2: + * if not given, automatically determined as len(X) + * if given, only leading N elements of X are used + Y - spline ordinates, array[M] + M - M>=2: + * if not given, automatically determined as len(Y) + * if given, only leading M elements of Y are used + F - function values, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdX- spline derivatives with respect to X, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + dFdY- spline derivatives with respect to Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + d2FdXdY-mixed derivatives with respect to X and Y, array[M*N*D]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + D - vector dimension, D>=1: + * D=1 means scalar-valued bicubic spline + * D>1 means vector-valued bicubic spline + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 2012-2023 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildhermitev(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const real_1d_array &dfdx, const real_1d_array &dfdy, const real_1d_array &d2fdxdy, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); +void spline2dbuildhermitev(const real_1d_array &x, const real_1d_array &y, const real_1d_array &f, const real_1d_array &dfdx, const real_1d_array &dfdy, const real_1d_array &d2fdxdy, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bicubic vector-valued spline. + +Buffered version of Spline2DBuildBicubicV() which reuses memory previously +allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +This function produces C2-continuous spline, i.e. the has smooth first and +second derivatives both inside spline cells and at the boundaries. + +When the node (i,j) is missing, it means that: a) we don't have function +value at this point (elements of F[] are ignored), and b) we don't need +spline value at cells adjacent to the node (i,j), i.e. up to 4 spline cells +will be dropped. An attempt to compute spline value at the missing cell +will return NAN. + +It is important to understand that this subroutine does NOT support +interpolation on scattered grids. It allows us to drop some nodes, but at +the cost of making a "hole in the spline" around this point. If you want +function that can "fill the gap", use RBF or another scattered +interpolation method. + +The intended usage for this subroutine are regularly sampled, but +non-rectangular datasets. + +Input parameters: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + F - function values, array[0..M*N*D-1]: + * first D elements store D values at (X[0],Y[0]) + * next D elements store D values at (X[1],Y[0]) + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(J*N+I)...D*(J*N+I)+D-1]. + * missing values are ignored + Missing array[M*N], Missing[J*N+I]=True means that corresponding entries + of F[] are missing nodes. + M,N - grid size, M>=2, N>=2 + D - vector dimension, D>=1 + +Output parameters: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissing(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds bicubic vector-valued spline, with some spline +cells being missing due to missing nodes. + +Buffered version of Spline2DBuildBicubicMissing() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 27.06.2022 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubicmissingbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const boolean_1d_array &missing, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine unpacks two-dimensional spline into the coefficients table + +Input parameters: + C - spline interpolant. + +Result: + M, N- grid size (x-axis and y-axis) + D - number of components + Tbl - coefficients table, unpacked format, + D - components: [0..(N-1)*(M-1)*D-1, 0..20]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index): + K := T + I*D + J*D*(N-1) + + K-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[K,0] = X[i] + Tbl[K,1] = X[i+1] + Tbl[K,2] = Y[j] + Tbl[K,3] = Y[j+1] + Tbl[K,4] = C00 + Tbl[K,5] = C01 + Tbl[K,6] = C02 + Tbl[K,7] = C03 + Tbl[K,8] = C10 + Tbl[K,9] = C11 + ... + Tbl[K,19] = C33 + Tbl[K,20] = 1 if the cell is present, 0 if the cell is missing. + In the latter case Tbl[4..19] are exactly zero. + On each grid square spline is equals to: + S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3) + t = x-x[j] + u = y-y[i] + + -- ALGLIB PROJECT -- + Copyright 16.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBilinearV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DBuildBicubicV(), which is more +flexible and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 05.07.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine was deprecated in ALGLIB 3.6.0 + +We recommend you to switch to Spline2DUnpackV(), which is more flexible +and accepts its arguments in more convenient order. + + -- ALGLIB PROJECT -- + Copyright 29.06.2007 by Bochkanov Sergey +*************************************************************************/ +void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine creates least squares solver used to fit 2D splines to +irregularly sampled (scattered) data. + +Solver object is used to perform spline fits as follows: +* solver object is created with spline2dbuildercreate() function +* dataset is added with spline2dbuildersetpoints() function +* fit area is chosen: + * spline2dbuildersetarea() - for user-defined area + * spline2dbuildersetareaauto() - for automatically chosen area +* number of grid nodes is chosen with spline2dbuildersetgrid() +* prior term is chosen with one of the following functions: + * spline2dbuildersetlinterm() to set linear prior + * spline2dbuildersetconstterm() to set constant prior + * spline2dbuildersetzeroterm() to set zero prior + * spline2dbuildersetuserterm() to set user-defined constant prior +* solver algorithm is chosen with either: + * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems + * spline2dbuildersetalgofastddm() - FastDDM algorithm, large-scale problems +* finally, fitting itself is performed with spline2dfit() function. + +Most of the steps above can be omitted, solver is configured with good +defaults. The minimum is to call: +* spline2dbuildercreate() to create solver object +* spline2dbuildersetpoints() to specify dataset +* spline2dbuildersetgrid() to tell how many nodes you need +* spline2dfit() to perform fit + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + D - positive number, number of Y-components: D=1 for simple scalar + fit, D>1 for vector-valued spline fitting. + +OUTPUT PARAMETERS: + S - solver object + + -- ALGLIB PROJECT -- + Copyright 29.01.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildercreate(const ae_int_t d, spline2dbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + V - value for user-defined prior + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetuserterm(spline2dbuilder &state, const double v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +Linear prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetlinterm(spline2dbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets constant prior term (model is a sum of bicubic spline +and global prior, which can be linear, constant, user-defined constant or +zero). + +Constant prior term is determined by least squares fitting. + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetconstterm(spline2dbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets zero prior term (model is a sum of bicubic spline and +global prior, which can be linear, constant, user-defined constant or +zero). + +INPUT PARAMETERS: + S - spline builder + + -- ALGLIB -- + Copyright 01.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetzeroterm(spline2dbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset to the builder object. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +INPUT PARAMETERS: + S - spline 2D builder object + XY - points, array[N,2+D]. One row corresponds to one point + in the dataset. First 2 elements are coordinates, next + D elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetpoints(spline2dbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets area where 2D spline interpolant is built. "Auto" means +that area extent is determined automatically from dataset extent. + +INPUT PARAMETERS: + S - spline 2D builder object + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetareaauto(spline2dbuilder &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets area where 2D spline interpolant is built to +user-defined one: [XA,XB]*[YA,YB] + +INPUT PARAMETERS: + S - spline 2D builder object + XA,XB - spatial extent in the first (X) dimension, XA=1 means that up to chosen number of bottom + layers is fitted + * NLayers=0 means that maximum number of layers is chosen + (according to current grid size) + * NLayers<=-1 means that up to |NLayers| topmost layers is + skipped + Recommendations: + * good "default" value is 2 layers + * you may need more layers, if your dataset is very + irregular and you want to "patch" large holes. For a + grid step H (equal to AreaWidth/GridSize) you may expect + that last layer reproduces variations at distance H (and + can patch holes that wide); that higher layers operate + at distances 2*H, 4*H, 8*H and so on. + * good value for "bullletproof" mode is NLayers=0, which + results in complete hierarchy of layers being generated. + LambdaV - regularization coefficient, chosen in such a way that it + penalizes bottom layers (fine details) first. + LambdaV>=0, zero value means that no penalty is applied. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgofastddm(spline2dbuilder &state, const ae_int_t nlayers, const double lambdav, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "BlockLLS", which performs +least squares fitting with fast sparse direct solver, with optional +nonsmoothness penalty being applied. + +This solver produces C2-continuous spline. + +Nonlinearity penalty has the following form: + + [ ] + P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy + [ ] + +here integral is calculated over entire grid, and "~" means "proportional" +because integral is normalized after calcilation. Extremely large values +of Lambda result in linear fit being performed. + +NOTE: this algorithm is the most robust and controllable one, but it is + limited by 512x512 grids and (say) up to 1.000.000 points. However, + ALGLIB has one more spline solver: FastDDM algorithm, which is + intended for really large-scale problems (in 10M-100M range). FastDDM + algorithm also has better parallelism properties. + +More information on BlockLLS solver: +* memory requirements: ~[32*K^3+256*NPoints] bytes for KxK grid with + NPoints-sized dataset +* serial running time: O(K^4+NPoints) +* parallelism potential: limited. You may get some sublinear gain when + working with large grids (K's in 256..512 range) + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- non-negative value: + * positive value means that some smoothing is applied + * zero value means that no smoothing is applied, and + corresponding entries of design matrix are numerically + zero and dropped from consideration. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgoblocklls(spline2dbuilder &state, const double lambdans, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function allows you to choose least squares solver used to perform +fitting. This function sets solver algorithm to "NaiveLLS". + +IMPORTANT: NaiveLLS is NOT intended to be used in real life code! This + algorithm solves problem by generated dense (K^2)x(K^2+NPoints) + matrix and solves linear least squares problem with dense + solver. + + It is here just to test BlockLLS against reference solver + (and maybe for someone trying to compare well optimized solver + against straightforward approach to the LLS problem). + +More information on naive LLS solver: +* memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid. +* serial running time: O(K^6+NPoints) for KxK grid +* when compared with BlockLLS, NaiveLLS has ~K larger memory demand and + ~K^2 larger running time. + +INPUT PARAMETERS: + S - spline 2D builder object + LambdaNS- nonsmoothness penalty + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dbuildersetalgonaivells(spline2dbuilder &state, const double lambdans, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function fits bicubic spline to current dataset, using current area/ +grid and current LLS solver. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + State - spline 2D builder object + +OUTPUT PARAMETERS: + S - 2D spline, fit result + Rep - fitting report, which provides some additional info about + errors, R2 coefficient and so on. + + -- ALGLIB -- + Copyright 05.02.2018 by Bochkanov Sergey +*************************************************************************/ +void spline2dfit(spline2dbuilder &state, spline2dinterpolant &s, spline2dfitreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This subroutine calculates the value of the trilinear or tricubic spline at +the given point (X,Y,Z). + +INPUT PARAMETERS: + C - coefficients table. + Built by BuildBilinearSpline or BuildBicubicSpline. + X, Y, + Z - point + +Result: + S(x,y,z) + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the spline argument. + +INPUT PARAMETERS: + C - spline interpolant + AX, BX - transformation coefficients: x = A*u + B + AY, BY - transformation coefficients: y = A*v + B + AZ, BZ - transformation coefficients: z = A*w + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransxyz(spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine performs linear transformation of the spline. + +INPUT PARAMETERS: + C - spline interpolant. + A, B- transformation coefficients: S2(x,y) = A*S(x,y,z) + B + +OUTPUT PARAMETERS: + C - transformed spline + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dlintransf(spline3dinterpolant &c, const double a, const double b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Trilinear spline resampling + +INPUT PARAMETERS: + A - array[0..OldXCount*OldYCount*OldZCount-1], function + values at the old grid, : + A[0] x=0,y=0,z=0 + A[1] x=1,y=0,z=0 + A[..] ... + A[..] x=oldxcount-1,y=0,z=0 + A[..] x=0,y=1,z=0 + A[..] ... + ... + OldZCount - old Z-count, OldZCount>1 + OldYCount - old Y-count, OldYCount>1 + OldXCount - old X-count, OldXCount>1 + NewZCount - new Z-count, NewZCount>1 + NewYCount - new Y-count, NewYCount>1 + NewXCount - new X-count, NewXCount>1 + +OUTPUT PARAMETERS: + B - array[0..NewXCount*NewYCount*NewZCount-1], function + values at the new grid: + B[0] x=0,y=0,z=0 + B[1] x=1,y=0,z=0 + B[..] ... + B[..] x=newxcount-1,y=0,z=0 + B[..] x=0,y=1,z=0 + B[..] ... + ... + + -- ALGLIB routine -- + 26.04.2012 + Copyright by Bochkanov Sergey +*************************************************************************/ +void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +INPUT PARAMETERS: + X - spline abscissas, array[0..N-1] + Y - spline ordinates, array[0..M-1] + Z - spline applicates, array[0..L-1] + F - function values, array[0..M*N*L*D-1]: + * first D elements store D values at (X[0],Y[0],Z[0]) + * next D elements store D values at (X[1],Y[0],Z[0]) + * next D elements store D values at (X[2],Y[0],Z[0]) + * ... + * next D elements store D values at (X[0],Y[1],Z[0]) + * next D elements store D values at (X[1],Y[1],Z[0]) + * next D elements store D values at (X[2],Y[1],Z[0]) + * ... + * next D elements store D values at (X[0],Y[0],Z[1]) + * next D elements store D values at (X[1],Y[0],Z[1]) + * next D elements store D values at (X[2],Y[0],Z[1]) + * ... + * general form - D function values at (X[i],Y[j]) are stored + at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1]. + M,N, + L - grid size, M>=2, N>=2, L>=2 + D - vector dimension, D>=1 + +OUTPUT PARAMETERS: + C - spline interpolant + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine builds trilinear vector-valued spline. + +Buffered version of Spline3DBuildTrilinearV() which reuses memory +previously allocated in C as much as possible. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dbuildtrilinearvbuf(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates bilinear or bicubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + F - output buffer, possibly preallocated array. In case array size + is large enough to store result, it is not reallocated. Array + which is too short will be reallocated + +OUTPUT PARAMETERS: + F - array[D] (or larger) which stores function values + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates trilinear or tricubic vector-valued spline at the +given point (X,Y,Z). + +INPUT PARAMETERS: + C - spline interpolant. + X, Y, + Z - point + +OUTPUT PARAMETERS: + F - array[D] which stores function values. F is out-parameter and + it is reallocated after call to this function. In case you + want to reuse previously allocated F, you may use + Spline2DCalcVBuf(), which reallocates F only when it is too + small. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine unpacks tri-dimensional spline into the coefficients table + +INPUT PARAMETERS: + C - spline interpolant. + +Result: + N - grid size (X) + M - grid size (Y) + L - grid size (Z) + D - number of components + SType- spline type. Currently, only one spline type is supported: + trilinear spline, as indicated by SType=1. + Tbl - spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13]. + For T=0..D-1 (component index), I = 0...N-2 (x index), + J=0..M-2 (y index), K=0..L-2 (z index): + Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1), + + Q-th row stores decomposition for T-th component of the + vector-valued function + + Tbl[Q,0] = X[i] + Tbl[Q,1] = X[i+1] + Tbl[Q,2] = Y[j] + Tbl[Q,3] = Y[j+1] + Tbl[Q,4] = Z[k] + Tbl[Q,5] = Z[k+1] + + Tbl[Q,6] = C000 + Tbl[Q,7] = C100 + Tbl[Q,8] = C010 + Tbl[Q,9] = C110 + Tbl[Q,10]= C001 + Tbl[Q,11]= C101 + Tbl[Q,12]= C011 + Tbl[Q,13]= C111 + On each grid square spline is equals to: + S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1) + t = x-x[j] + u = y-y[i] + v = z-z[k] + + NOTE: format of Tbl is given for SType=1. Future versions of + ALGLIB can use different formats for different values of + SType. + + -- ALGLIB PROJECT -- + Copyright 26.04.2012 by Bochkanov Sergey +*************************************************************************/ +void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremc() instead. + + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremcc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremi() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremic(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspheremz() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspheremzc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is left for backward compatibility. +Use fitspherex() instead. + + -- ALGLIB -- + Copyright 14.04.2017 by Bochkanov Sergey +*************************************************************************/ +void nsfitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, const double penalty, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is an obsolete and deprecated version of fitting by +penalized cubic spline. + +It was superseded by spline1dfit(), which is an orders of magnitude faster +and more memory-efficient implementation. + +Do NOT use this function in the new code! + + -- ALGLIB PROJECT -- + Copyright 19.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Deprecated fitting function with O(N*M^2+M^3) running time. Superseded by +spline1dfit(). + + -- ALGLIB PROJECT -- + Copyright 18.08.2009 by Bochkanov Sergey +*************************************************************************/ +void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void rbfserialize(const rbfmodel &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void rbfserialize(const rbfmodel &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void rbfunserialize(const std::string &s_in, rbfmodel &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void rbfunserialize(const std::istream &s_in, rbfmodel &obj); + + +/************************************************************************* +This function creates RBF model for a scalar (NY=1) or vector (NY>1) +function in a NX-dimensional space (NX>=1). + +Newly created model is empty. It can be used for interpolation right after +creation, but it just returns zeros. You have to add points to the model, +tune interpolation settings, and then call model construction function +rbfbuildmodel() which will update model according to your specification. + +USAGE: +1. User creates model with rbfcreate() +2. User adds dataset with rbfsetpoints() or rbfsetpointsandscales() +3. User selects RBF solver by calling: + * rbfsetalgohierarchical() - for a HRBF solver, a hierarchical large- + scale Gaussian RBFs (works well for uniformly distributed point + clouds, but may fail when the data are non-uniform; use other solvers + below in such cases) + * rbfsetalgothinplatespline() - for a large-scale DDM-RBF solver with + thin plate spline basis function being used + * rbfsetalgobiharmonic() - for a large-scale DDM-RBF solver with + biharmonic basis function being used + * rbfsetalgomultiquadricauto() - for a large-scale DDM-RBF solver with + multiquadric basis function being used (automatic selection of the + scale parameter Alpha) + * rbfsetalgomultiquadricmanual() - for a large-scale DDM-RBF solver + with multiquadric basis function being used (manual selection of the + scale parameter Alpha) +4. (OPTIONAL) User chooses polynomial term by calling: + * rbflinterm() to set linear term (default) + * rbfconstterm() to set constant term + * rbfzeroterm() to set zero term +5. User calls rbfbuildmodel() function which rebuilds model according to + the specification + +INPUT PARAMETERS: + NX - dimension of the space, NX>=1 + NY - function dimension, NY>=1 + +OUTPUT PARAMETERS: + S - RBF model (initially equals to zero) + +NOTE 1: memory requirements. RBF models require amount of memory which is + proportional to the number of data points. Some additional memory + is allocated during model construction, but most of this memory is + freed after the model coefficients are calculated. Amount of + this additional memory depends on model construction algorithm + being used. + + -- ALGLIB -- + Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates buffer structure which can be used to perform +parallel RBF model evaluations (with one RBF model instance being +used from multiple threads, as long as different threads use different +instances of the buffer). + +This buffer object can be used with rbftscalcbuf() function (here "ts" +stands for "thread-safe", "buf" is a suffix which denotes function which +reuses previously allocated output space). + +A buffer creation function (this function) is also thread-safe. I.e. you +may safely create multiple buffers for the same RBF model from multiple +threads. + +NOTE: the buffer object is just a collection of several preallocated + dynamic arrays and precomputed values. If you delete its "parent" + RBF model when the buffer is still alive, nothing bad will happen + (no dangling pointers or resource leaks). The buffer will simply + become useless. + +How to use it: +* create RBF model structure with rbfcreate() +* load data, tune parameters +* call rbfbuildmodel() +* call rbfcreatecalcbuffer(), once per thread working with RBF model (you + should call this function only AFTER call to rbfbuildmodel(), see below + for more information) +* call rbftscalcbuf() from different threads, with each thread working + with its own copy of buffer object. +* it is recommended to reuse buffer as much as possible because buffer + creation involves allocation of several large dynamic arrays. It is a + huge waste of resource to use it just once. + +INPUT PARAMETERS + S - RBF model + +OUTPUT PARAMETERS + Buf - external buffer. + +IMPORTANT: buffer object should be used only with RBF model object which + was used to initialize buffer. Any attempt to use buffer with + different object is dangerous - you may get memory violation + error because sizes of internal arrays do not fit to dimensions + of RBF structure. + +IMPORTANT: you should call this function only for model which was built + with rbfbuildmodel() function, after successful invocation of + rbfbuildmodel(). Sizes of some internal structures are + determined only after model is built, so buffer object created + before model construction stage will be useless (and any + attempt to use it will result in exception). + + -- ALGLIB -- + Copyright 02.04.2016 by Sergey Bochkanov +*************************************************************************/ +void rbfcreatecalcbuffer(const rbfmodel &s, rbfcalcbuffer &buf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: ALGLIB version 3.11 and later allows you to specify a set of + per-dimension scales. Interpolation radii are multiplied by the + scale vector. It may be useful if you have mixed spatio-temporal + data (say, a set of 3D slices recorded at different times). + You should call rbfsetpointsandscales() function to use this + feature. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpoints(rbfmodel &s, const real_2d_array &xy, const ae_int_t n, const xparams _xparams = alglib::xdefault); +void rbfsetpoints(rbfmodel &s, const real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds dataset and a vector of per-dimension scales. + +It may be useful if you have mixed spatio-temporal data - say, a set of 3D +slices recorded at different times. Such data typically require different +RBF radii for spatial and temporal dimensions. ALGLIB solves this problem +by specifying single RBF radius, which is (optionally) multiplied by the +scale vector. + +This function overrides results of the previous calls, i.e. multiple calls +of this function will result in only the last set being added. + +IMPORTANT: only modern RBF algorithms support variable scaling. Legacy + algorithms like RBF-ML or QNN algorithms will result in -3 + completion code being returned (incorrect algorithm). + +INPUT PARAMETERS: + R - RBF model, initialized by rbfcreate() call. + XY - points, array[N,NX+NY]. One row corresponds to one point + in the dataset. First NX elements are coordinates, next + NY elements are function values. Array may be larger than + specified, in this case only leading [N,NX+NY] elements + will be used. + N - number of points in the dataset + S - array[NX], scale vector, S[i]>0. + +After you've added dataset and (optionally) tuned algorithm settings you +should call rbfbuildmodel() in order to build a model for you. + +NOTE: dataset added by this function is not saved during model serialization. + MODEL ITSELF is serialized, but data used to build it are not. + + So, if you 1) add dataset to empty RBF model, 2) serialize and + unserialize it, then you will get an empty RBF model with no dataset + being attached. + + From the other side, if you call rbfbuildmodel() between (1) and (2), + then after (2) you will get your fully constructed RBF model - but + again with no dataset attached, so subsequent calls to rbfbuildmodel() + will produce empty model. + + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetpointsandscales(rbfmodel &r, const real_2d_array &xy, const ae_int_t n, const real_1d_array &s, const xparams _xparams = alglib::xdefault); +void rbfsetpointsandscales(rbfmodel &r, const real_2d_array &xy, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgoqnn(rbfmodel &s, const double q, const double z, const xparams _xparams = alglib::xdefault); +void rbfsetalgoqnn(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +DEPRECATED: this function is deprecated. ALGLIB includes new RBF model + construction algorithms: DDM-RBF (since version 3.19) and HRBF + (since version 3.11). + + -- ALGLIB -- + Copyright 02.03.2012 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultilayer(rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav, const xparams _xparams = alglib::xdefault); +void rbfsetalgomultilayer(rbfmodel &s, const double rbase, const ae_int_t nlayers, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function chooses HRBF solver, a 2nd version of ALGLIB RBFs. + +This algorithm is called Hierarchical RBF. It similar to its previous +incarnation, RBF-ML, i.e. it also builds a sequence of models with +decreasing radii. However, it uses more economical way of building upper +layers (ones with large radii), which results in faster model construction +and evaluation, as well as smaller memory footprint during construction. + +This algorithm has following important features: +* ability to handle millions of points +* controllable smoothing via nonlinearity penalization +* support for specification of per-dimensional radii via scale vector, + which is set by means of rbfsetpointsandscales() function. This feature + is useful if you solve spatio-temporal interpolation problems, where + different radii are required for spatial and temporal dimensions. + +Running times are roughly proportional to: +* N*log(N)*NLayers - for the model construction +* N*NLayers - for the model evaluation +You may see that running time does not depend on search radius or points +density, just on the number of layers in the hierarchy. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + RBase - RBase parameter, RBase>0 + NLayers - NLayers parameter, NLayers>0, recommended value to start + with - about 5. + LambdaNS- >=0, nonlinearity penalty coefficient, negative values are + not allowed. This parameter adds controllable smoothing to + the problem, which may reduce noise. Specification of non- + zero lambda means that in addition to fitting error solver + will also minimize LambdaNS*|S''(x)|^2 (appropriately + generalized to multiple dimensions. + + Specification of exactly zero value means that no penalty + is added (we do not even evaluate matrix of second + derivatives which is necessary for smoothing). + + Calculation of nonlinearity penalty is costly - it results + in several-fold increase of model construction time. + Evaluation time remains the same. + + Optimal lambda is problem-dependent and requires trial + and error. Good value to start from is 1e-5...1e-6, + which corresponds to slightly noticeable smoothing of the + function. Value 1e-2 usually means that quite heavy + smoothing is applied. + +TUNING ALGORITHM + +In order to use this algorithm you have to choose three parameters: +* initial radius RBase +* number of layers in the model NLayers +* penalty coefficient LambdaNS + +Initial radius is easy to choose - you can pick any number several times +larger than the average distance between points. Algorithm won't break +down if you choose radius which is too large (model construction time will +increase, but model will be built correctly). + +Choose such number of layers that RLast=RBase/2^(NLayers-1) (radius used +by the last layer) will be smaller than the typical distance between +points. In case model error is too large, you can increase number of +layers. Having more layers will make model construction and evaluation +proportionally slower, but it will allow you to have model which precisely +fits your data. From the other side, if you want to suppress noise, you +can DECREASE number of layers to make your model less flexible (or specify +non-zero LambdaNS). + +TYPICAL ERRORS + +1. Using too small number of layers - RBF models with large radius are not + flexible enough to reproduce small variations in the target function. + You need many layers with different radii, from large to small, in + order to have good model. + +2. Using initial radius which is too small. You will get model with + "holes" in the areas which are too far away from interpolation centers. + However, algorithm will work correctly (and quickly) in this case. + + -- ALGLIB -- + Copyright 20.06.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgohierarchical(rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdans, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function chooses a thin plate spline DDM-RBF solver, a fast RBF +solver with f(r)=r^2*ln(r) basis function. + +This algorithm has following important features: +* easy setup - no tunable parameters +* C1 continuous RBF model (gradient is defined everywhere, but Hessian is + undefined at nodes), high-quality interpolation +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a smoothing thin plate spline is + built, with larger LambdaV corresponding to models with + less nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgothinplatespline(rbfmodel &s, const double lambdav, const xparams _xparams = alglib::xdefault); +void rbfsetalgothinplatespline(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with manual choice of +the scale parameter Alpha. + +This algorithm has following important features: +* C2 continuous RBF model (when Alpha>0 is used; for Alpha=0 the model is + merely C0 continuous) +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +One important point is that this algorithm includes tunable parameter +Alpha, which should be carefully chosen. Selecting too large value will +result in extremely badly conditioned problems (interpolation accuracy +may degrade up to complete breakdown) whilst selecting too small value may +produce models that are precise but nearly nonsmooth at the nodes. + +Good value to start from is mean distance between nodes. Generally, +choosing too small Alpha is better than choosing too large - in the former +case you still have model that reproduces target values at the nodes. + +In most cases, better option is to choose good Alpha automatically - it is +done by another version of the same algorithm that is activated by calling +rbfsetalgomultiquadricauto() method. + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + Alpha - basis function parameter, Alpha>=0: + * Alpha>0 means that multiquadric algorithm is used which + produces C2-continuous RBF model + * Alpha=0 means that the multiquadric kernel effectively + becomes a biharmonic one: f=r. As a result, the model + becomes nonsmooth at nodes, and hence is C0 continuous + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricmanual(rbfmodel &s, const double alpha, const double lambdav, const xparams _xparams = alglib::xdefault); +void rbfsetalgomultiquadricmanual(rbfmodel &s, const double alpha, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function chooses a multiquadric DDM-RBF solver, a fast RBF solver +with f(r)=sqrt(r^2+Alpha^2) as a basis function, with Alpha being +automatically determined. + +This algorithm has following important features: +* easy setup - no need to tune Alpha, good value is automatically assigned +* C2 continuous RBF model +* fast model construction algorithm with O(N) memory and O(N^2) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* controllable smoothing via optional nonlinearity penalty + +This algorithm automatically selects Alpha as a mean distance to the +nearest neighbor (ignoring neighbors that are too close). + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgomultiquadricauto(rbfmodel &s, const double lambdav, const xparams _xparams = alglib::xdefault); +void rbfsetalgomultiquadricauto(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function chooses a biharmonic DDM-RBF solver, a fast RBF solver +with f(r)=r as a basis function. + +This algorithm has following important features: +* no tunable parameters +* C0 continuous RBF model (the model has discontinuous derivatives at the + interpolation nodes) +* fast model construction algorithm with O(N) memory and O(N*logN) running + time requirements. Hundreds of thousands of points can be handled with + this algorithm. +* accelerated evaluation using far field expansions (aka fast multipoles + method) is supported. See rbffastcalc() for more information. +* controllable smoothing via optional nonlinearity penalty + +INPUT PARAMETERS: + S - RBF model, initialized by rbfcreate() call + LambdaV - smoothing parameter, LambdaV>=0, defaults to 0.0: + * LambdaV=0 means that no smoothing is applied, i.e. the + spline tries to pass through all dataset points exactly + * LambdaV>0 means that a multiquadric spline is built with + larger LambdaV corresponding to models with less + nonlinearities. Smoothing spline reproduces target + values at nodes with small error; from the other side, + it is much more stable. + Recommended values: + * 1.0E-6 for minimal stability improving smoothing + * 1.0E-3 a good value to start experiments; first results + are visible + * 1.0 for strong smoothing + +IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.19 + and produces models which are INCOMPATIBLE with previous + versions of ALGLIB. You can not unserialize models produced + with this function in ALGLIB 3.18 or earlier. + +NOTE: polyharmonic RBFs, including thin plate splines, are somewhat + slower than compactly supported RBFs built with HRBF algorithm + due to the fact that non-compact basis function does not vanish + far away from the nodes. From the other side, polyharmonic RBFs + often produce much better results than HRBFs. + +NOTE: this algorithm supports specification of per-dimensional radii + via scale vector, which is set by means of rbfsetpointsandscales() + function. This feature is useful if you solve spatio-temporal + interpolation problems where different radii are required for + spatial and temporal dimensions. + + -- ALGLIB -- + Copyright 12.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfsetalgobiharmonic(rbfmodel &s, const double lambdav, const xparams _xparams = alglib::xdefault); +void rbfsetalgobiharmonic(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear term (model is a sum of radial basis functions +plus linear polynomial). This function won't have effect until next call +to RBFBuildModel(). + +Using linear term is a default option and it is the best one - it provides +best convergence guarantees for all RBF model types: legacy RBF-QNN and +RBF-ML, Gaussian HRBFs and all types of DDM-RBF models. + +Other options, like constant or zero term, work for HRBFs, almost always +work for DDM-RBFs but provide no stability guarantees in the latter case +(e.g. the solver may fail on some carefully prepared problems). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetlinterm(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets constant term (model is a sum of radial basis functions +plus constant). This function won't have effect until next call to +RBFBuildModel(). + +IMPORTANT: thin plate splines require polynomial term to be linear, not + constant, in order to provide interpolation guarantees. + Although failures are exceptionally rare, some small toy + problems may result in degenerate linear systems. Thus, it is + advised to use linear term when one fits data with TPS. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetconstterm(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets zero term (model is a sum of radial basis functions +without polynomial term). This function won't have effect until next call +to RBFBuildModel(). + +IMPORTANT: only Gaussian RBFs (HRBF algorithm) provide interpolation + guarantees when no polynomial term is used. Most other RBFs, + including biharmonic splines, thin plate splines and + multiquadrics, require at least constant term (biharmonic and + multiquadric) or linear one (thin plate splines) in order to + guarantee non-degeneracy of linear systems being solved. + + Although failures are exceptionally rare, some small toy + problems still may result in degenerate linear systems. Thus,it + is advised to use constant/linear term, unless one is 100% sure + that he needs zero term. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfsetzeroterm(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets basis function type, which can be: +* 0 for classic Gaussian +* 1 for fast and compact bell-like basis function, which becomes exactly + zero at distance equal to 3*R (default option). + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + BF - basis function type: + * 0 - classic Gaussian + * 1 - fast and compact one + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2bf(rbfmodel &s, const ae_int_t bf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping criteria of the underlying linear solver for +hierarchical (version 2) RBF constructor. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + MaxIts - this criterion will stop algorithm after MaxIts iterations. + Typically a few hundreds iterations is required, with 400 + being a good default value to start experimentation. + Zero value means that default value will be selected. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2its(rbfmodel &s, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets support radius parameter of hierarchical (version 2) +RBF constructor. + +Hierarchical RBF model achieves great speed-up by removing from the model +excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter, +and two nodes are just 1 millimeter apart, you may remove one of them +without reducing model quality. + +Support radius parameter is used to justify which points need removal, and +which do not. If two points are less than SUPPORT_R*CUR_RADIUS units of +distance apart, one of them is removed from the model. The larger support +radius is, the faster model construction AND evaluation are. However, +too large values result in "bumpy" models. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + R - support radius coefficient, >=0. + Recommended values are [0.1,0.4] range, with 0.1 being + default value. + + -- ALGLIB -- + Copyright 01.02.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv2supportr(rbfmodel &s, const double r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets desired accuracy for a version 3 RBF model. + +As of ALGLIB 3.20.0, version 3 models include biharmonic RBFs, thin plate +splines, multiquadrics. + +Version 3 models are fit with specialized domain decomposition method +which splits problem into smaller chunks. Models with size less than +the DDM chunk size are computed nearly exactly in one step. Larger models +are built with an iterative linear solver. This function controls accuracy +of the solver. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + TOL - desired precision: + * must be non-negative + * should be somewhere between 0.001 and 0.000001 + * values higher than 0.001 make little sense - you may + lose a lot of precision with no performance gains. + * values below 1E-6 usually require too much time to converge, + so they are silenly replaced by a 1E-6 cutoff value. Thus, + zero can be used to denote 'maximum precision'. + + -- ALGLIB -- + Copyright 01.10.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetv3tol(rbfmodel &s, const double tol, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function builds RBF model and returns report (contains some +information which can be used for evaluation of the algorithm properties). + +Call to this function modifies RBF model by calculating its centers/radii/ +weights and saving them into RBFModel structure. Initially RBFModel +contain zero coefficients, but after call to this function we will have +coefficients which were calculated in order to fit our dataset. + +After you called this function you can call RBFCalc(), RBFGridCalc() and +other model calculation functions. + +INPUT PARAMETERS: + S - RBF model, initialized by RBFCreate() call + Rep - report: + * Rep.TerminationType: + * -5 - non-distinct basis function centers were detected, + interpolation aborted; only QNN returns this + error code, other algorithms can handle non- + distinct nodes. + * -4 - nonconvergence of the internal SVD solver + * -3 incorrect model construction algorithm was chosen: + QNN or RBF-ML, combined with one of the incompatible + features: + * NX=1 or NX>3 + * points with per-dimension scales. + * 1 - successful termination + * 8 - a termination request was submitted via + rbfrequesttermination() function. + + Fields which are set only by modern RBF solvers (hierarchical + or nonnegative; older solvers like QNN and ML initialize these + fields by NANs): + * rep.rmserror - root-mean-square error at nodes + * rep.maxerror - maximum error at nodes + + Fields are used for debugging purposes: + * Rep.IterationsCount - iterations count of the LSQR solver + * Rep.NMV - number of matrix-vector products + * Rep.ARows - rows count for the system matrix + * Rep.ACols - columns count for the system matrix + * Rep.ANNZ - number of significantly non-zero elements + (elements above some algorithm-determined threshold) + +NOTE: failure to build model will leave current state of the structure +unchanged. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfbuildmodel(rbfmodel &s, rbfreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the 1-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: this function works only with modern (hierarchical) RBFs. It + can not be used with legacy (version 1) RBFs because older RBF + code does not support 1-dimensional models. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* the model is not initialized +* NX<>1 +* NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - X-coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc1(rbfmodel &s, const double x0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the 2-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc2(rbfmodel &s, const double x0, const double x1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the 3-dimensional RBF model with scalar +output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + *NY<>1 + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +RESULT: + value of the model or 0.0 (as defined above) + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +double rbfcalc3(rbfmodel &s, const double x0, const double x1, const double x2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates value and derivatives of the 1-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>1 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff1(rbfmodel &s, const double x0, double &y, double &dy0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates value and derivatives of the 2-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>2 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff2(rbfmodel &s, const double x0, const double x1, double &y, double &dy0, double &dy1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates value and derivatives of the 3-dimensional RBF +model with scalar output (NY=1) at the given point. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* NX<>3 or NY<>1 (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X0 - first coordinate, finite number + X1 - second coordinate, finite number + X2 - third coordinate, finite number + +OUTPUT PARAMETERS: + Y - value of the model or 0.0 (as defined above) + DY0 - derivative with respect to X0 + DY1 - derivative with respect to X1 + DY2 - derivative with respect to X2 + + -- ALGLIB -- + Copyright 13.12.2021 by Bochkanov Sergey +*************************************************************************/ +void rbfdiff3(rbfmodel &s, const double x0, const double x1, const double x2, double &y, double &dy0, double &dy1, double &dy2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets absolute accuracy of a fast evaluation algorithm used +by rbffastcalc() and other fast evaluation functions. + +A fast evaluation algorithm is model-dependent and is available only for +some RBF models. Usually it utilizes far field expansions (a generalization +of the fast multipoles method). If no approximate fast evaluator is +available for the current RBF model type, this function has no effect. + +NOTE: this function can be called before or after the model was built. The + result will be the same. + +NOTE: this function has O(N) running time, where N is a points count. + Most fast evaluators work by aggregating influence of point groups, + i.e. by computing so called far field. Changing evaluator tolerance + means that far field radii have to be recomputed for each point + cluster, and we have O(N) such clusters. + + This function is still very fast, but it should not be called too + often, e.g. every time you call rbffastcalc() in a loop. + +NOTE: the tolerance set by this function is an accuracy of an evaluator + which computes the value of the model. It is NOT accuracy of the + model itself. + + E.g., if you set evaluation accuracy to 1E-12, the model value will + be computed with required precision. However, the model itself is an + approximation of the target (the default requirement is to fit model + with ~6 digits of precision) and THIS accuracy can not be changed + after the model was built. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. Calling it while another thread + tries to use rbffastcalc() is unsafe because it means that the + accuracy requirements will change in the middle of computations. + The algorithm may behave unpredictably. + +INPUT PARAMETERS: + S - RBF model + TOL - TOL>0, desired evaluation tolerance: + * should be somewhere between 1E-3 and 1E-6 + * values outside of this range will cause no problems (the + evaluator will do the job anyway). However, too strict + precision requirements may mean that no approximation + speed-up will be achieved. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbfsetfastevaltol(rbfmodel &s, const double tol, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model at the given point using +a fast approximate algorithm whenever possible. If no fast algorithm is +available for a given model type, traditional O(N) approach is used. + +Presently, fast evaluation is implemented only for biharmonic splines. + +The absolute approximation accuracy is controlled by the rbfsetfastevaltol() +function. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with a per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 19.09.2022 by Bochkanov Sergey +*************************************************************************/ +void rbffastcalc(rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model at the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +when you have NY=1 you may find more convenient to use rbfcalc2() or +rbfcalc3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + If you want to perform parallel model evaluation from multiple + threads, use rbftscalcbuf() with per-thread buffer object. + +This function returns 0.0 when model is not initialized. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFCalcBuf(), + which reallocates Y only when it is too small. + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfcalc(rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model and its derivatives at +the given point. + +This is general function which can be used for arbitrary NX (dimension of +the space of arguments) and NY (dimension of the function itself). However +if you have NX=3 and NY=1, you may find more convenient to use rbfdiff3(). + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftsdiffbuf() with per-thread buffer object. + +This function returns 0.0 in Y and/or DY in the following cases: +* the model is not initialized (Y=0, DY=0) +* the gradient is undefined at the trial point. Some basis functions have + discontinuous derivatives at the interpolation nodes: + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only DY is set to zero (Y is still returned) + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. Y is out-parameter and + reallocated after call to this function. In case you want + to reuse previously allocated Y, you may use RBFDiffBuf(), + which reallocates Y only when it is too small. + DY - derivatives, array[NX*NY]: + * Y[I*NX+J] with 0<=I1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + Y is out-parameter and reallocated after call to this + function. In case you want to reuse previously allocated + Y, you may use RBFHessBuf(), which reallocates Y only when + it is too small. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K1) RBFs. + +IMPORTANT: THIS FUNCTION IS THREAD-UNSAFE. It uses fields of rbfmodel as + temporary arrays, i.e. it is impossible to perform parallel + evaluation on the same rbfmodel object (parallel calls of this + function for independent rbfmodel objects are safe). + + If you want to perform parallel model evaluation from multiple + threads, use rbftshessbuf() with per-thread buffer object. + +This function returns 0 in Y and/or DY and/or D2Y in the following cases: +* the model is not initialized (Y=0, DY=0, D2Y=0) +* the gradient and/or Hessian is undefined at the trial point. Some basis + functions have discontinuous derivatives at the interpolation nodes: + * thin plate splines have no Hessian at the nodes + * biharmonic splines f=r have no Hessian and no gradient at the nodes + In these cases only corresponding derivative is set to zero, and the + rest of the derivatives is still returned. + +INPUT PARAMETERS: + S - RBF model + X - coordinates, array[NX]. + X may have more than NX elements, in this case only + leading NX will be used. + Y,DY,D2Y- possible preallocated output arrays. If these arrays are + smaller than required to store the result, they are + automatically reallocated. If array is large enough, it is + not resized. + +OUTPUT PARAMETERS: + Y - function value, array[NY]. + DY - first derivatives, array[NY*NX]: + * Y[I*NX+J] with 0<=I1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K1 it contains NY + subsequently stored Hessians: an element Y[K*NX*NX+I*NX+J] + with 0<=K2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1], where NY is a number of + "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc2vsubset(). + + -- ALGLIB -- + Copyright 27.01.2017 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + FlagY - array[N0*N1]: + * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc2vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model at the regular grid, +which has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]). +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models). Y is out-variable and is reallocated + by this function. + Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for: + * K=0...NY-1 + * I0=0...N0-1 + * I1=0...N1-1 + * I2=0...N2-1 + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + +NOTE: if you need function values on some subset of regular grid, which + may be described as "several compact and dense islands", you may + use rbfgridcalc3vsubset(). + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates values of the RBF model at some subset of regular +grid: +* grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K]) +* only values at some subset of this grid are required +Vector-valued RBF models are supported. + +This function returns 0.0 when: +* model is not initialized +* NX<>3 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +NOTE: Parallel processing is implemented only for modern (hierarchical) + RBFs. Legacy version 1 RBFs (created by QNN or RBF-ML) are still + processed serially. + +INPUT PARAMETERS: + S - RBF model, used in read-only mode, can be shared between + multiple invocations of this function from multiple + threads. + + X0 - array of grid nodes, first coordinates, array[N0]. + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N0 - grid size (number of nodes) in the first dimension + + X1 - array of grid nodes, second coordinates, array[N1] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N1 - grid size (number of nodes) in the second dimension + + X2 - array of grid nodes, third coordinates, array[N2] + Must be ordered by ascending. Exception is generated + if the array is not correctly ordered. + N2 - grid size (number of nodes) in the third dimension + + FlagY - array[N0*N1*N2]: + * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2]) + * it is a "bitmap" array which contains False for nodes + which are NOT calculated, and True for nodes which are + required. + +OUTPUT PARAMETERS: + Y - function values, array[NY*N0*N1*N2], where NY is a number + of "output" vector values (this function supports vector- + valued RBF models): + * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), + for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1. + * elements of Y[] which correspond to FlagY[]=True are + loaded by model values (which may be exactly zero for + some nodes). + * elements of Y[] which correspond to FlagY[]=False MAY be + initialized by zeros OR may be calculated. This function + processes grid as a hierarchy of nested blocks and + micro-rows. If just one element of micro-row is required, + entire micro-row (up to 8 nodes in the current version, + but no promises) is calculated. + +NOTE: this function supports weakly ordered grid nodes, i.e. you may have + X[i]=X[i+1] for some i. It does not provide you any performance + benefits due to duplication of points, just convenience and + flexibility. + +NOTE: this function is re-entrant, i.e. you may use same rbfmodel + structure in multiple threads calling this function for different + grids. + + -- ALGLIB -- + Copyright 04.03.2016 by Bochkanov Sergey +*************************************************************************/ +void rbfgridcalc3vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function "unpacks" RBF model by extracting its coefficients. + +INPUT PARAMETERS: + S - RBF model + +OUTPUT PARAMETERS: + NX - dimensionality of argument + NY - dimensionality of the target function + XWR - model information , 2D array. One row of the array + corresponds to one basis function. + + For ModelVersion=1 we have NX+NY+1 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last column - radius, same for all dimensions of + the function being modeled + + For ModelVersion=2 we have NX+NY+NX columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * last NX columns - radii, one per dimension + + For ModelVersion=3 we have NX+NY+NX+3 columns: + * first NX columns - coordinates of the center + * next NY columns - weights, one per dimension of the + function being modeled + * next NX columns - radii, one per dimension + * next column - basis function type: + * 1 for f=r + * 2 for f=r^2*ln(r) + * 10 for multiquadric f=sqrt(r^2+alpha^2) + * next column - basis function parameter: + * alpha, for basis function type 10 + * ignored (zero) for other basis function types + * next column - point index in the original dataset, + or -1 for an artificial node created + by the solver. The algorithm may reorder + the nodes, drop some nodes or add + artificial nodes. Thus, one parsing + this column should expect all these + kinds of alterations in the dataset. + + NC - number of the centers + V - polynomial term , array[NY,NX+1]. One row per one + dimension of the function being modelled. First NX + elements are linear coefficients, V[NX] is equal to the + constant part. + ModelVersion-version of the RBF model: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + * 3 - for models created by DDM-RBF, requires + ALGLIB 3.19 or later + + -- ALGLIB -- + Copyright 13.12.2011 by Bochkanov Sergey +*************************************************************************/ +void rbfunpack(rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v, ae_int_t &modelversion, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function returns model version. + +INPUT PARAMETERS: + S - RBF model + +RESULT: + * 1 - for models created by QNN and RBF-ML algorithms, + compatible with ALGLIB 3.10 or earlier. + * 2 - for models created by HierarchicalRBF, requires + ALGLIB 3.11 or later + + -- ALGLIB -- + Copyright 06.07.2016 by Bochkanov Sergey +*************************************************************************/ +ae_int_t rbfgetmodelversion(rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to peek into hierarchical RBF construction process +from some other thread and get current progress indicator. It returns +value in [0,1]. + +IMPORTANT: only HRBFs (hierarchical RBFs) support peeking into progress + indicator. Legacy RBF-ML and RBF-QNN do not support it. You + will always get 0 value. + +INPUT PARAMETERS: + S - RBF model object + +RESULT: + progress value, in [0,1] + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +double rbfpeekprogress(const rbfmodel &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to submit a request for termination of the +hierarchical RBF construction process from some other thread. As result, +RBF construction is terminated smoothly (with proper deallocation of all +necessary resources) and resultant model is filled by zeros. + +A rep.terminationtype=8 will be returned upon receiving such request. + +IMPORTANT: only HRBFs (hierarchical RBFs) support termination requests. + Legacy RBF-ML and RBF-QNN do not support it. An attempt to + terminate their construction will be ignored. + +IMPORTANT: termination request flag is cleared when the model construction + starts. Thus, any pre-construction termination requests will be + silently ignored - only ones submitted AFTER construction has + actually began will be handled. + +INPUT PARAMETERS: + S - RBF model object + + -- ALGLIB -- + Copyright 17.11.2018 by Bochkanov Sergey +*************************************************************************/ +void rbfrequesttermination(rbfmodel &s, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD) +double barycentriccalc(const barycentricinterpolant* b, + double t, + ae_state *_state); +void barycentricdiff1(const barycentricinterpolant* b, + double t, + double* f, + double* df, + ae_state *_state); +void barycentricdiff2(const barycentricinterpolant* b, + double t, + double* f, + double* df, + double* d2f, + ae_state *_state); +void barycentriclintransx(barycentricinterpolant* b, + double ca, + double cb, + ae_state *_state); +void barycentriclintransy(barycentricinterpolant* b, + double ca, + double cb, + ae_state *_state); +void barycentricunpack(const barycentricinterpolant* b, + ae_int_t* n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* w, + ae_state *_state); +void barycentricbuildxyw(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + barycentricinterpolant* b, + ae_state *_state); +void barycentricbuildfloaterhormann(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t d, + barycentricinterpolant* b, + ae_state *_state); +void barycentriccopy(const barycentricinterpolant* b, + barycentricinterpolant* b2, + ae_state *_state); +void _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _barycentricinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _barycentricinterpolant_clear(void* _p); +void _barycentricinterpolant_destroy(void* _p); +#endif +#if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD) +void idwcreatecalcbuffer(const idwmodel* s, + idwcalcbuffer* buf, + ae_state *_state); +void idwbuildercreate(ae_int_t nx, + ae_int_t ny, + idwbuilder* state, + ae_state *_state); +void idwbuildersetnlayers(idwbuilder* state, + ae_int_t nlayers, + ae_state *_state); +void idwbuildersetpoints(idwbuilder* state, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state); +void idwbuildersetalgomstab(idwbuilder* state, + double srad, + ae_state *_state); +void idwbuildersetalgotextbookshepard(idwbuilder* state, + double p, + ae_state *_state); +void idwbuildersetalgotextbookmodshepard(idwbuilder* state, + double r, + ae_state *_state); +void idwbuildersetuserterm(idwbuilder* state, double v, ae_state *_state); +void idwbuildersetconstterm(idwbuilder* state, ae_state *_state); +void idwbuildersetzeroterm(idwbuilder* state, ae_state *_state); +double idwcalc1(idwmodel* s, double x0, ae_state *_state); +double idwcalc2(idwmodel* s, double x0, double x1, ae_state *_state); +double idwcalc3(idwmodel* s, + double x0, + double x1, + double x2, + ae_state *_state); +void idwcalc(idwmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void idwcalcbuf(idwmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void idwtscalcbuf(const idwmodel* s, + idwcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void idwfit(idwbuilder* state, + idwmodel* model, + idwreport* rep, + ae_state *_state); +double idwpeekprogress(const idwbuilder* s, ae_state *_state); +void idwgridcalc2v(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_vector* y, + ae_state *_state); +void idwgridcalc2vsubset(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state); +void idwgridcalc2vx(const idwmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state); +void idwalloc(ae_serializer* s, const idwmodel* model, ae_state *_state); +void idwserialize(ae_serializer* s, + const idwmodel* model, + ae_state *_state); +void idwunserialize(ae_serializer* s, idwmodel* model, ae_state *_state); +void _idwcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _idwcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _idwcalcbuffer_clear(void* _p); +void _idwcalcbuffer_destroy(void* _p); +void _mstabbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mstabbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mstabbuffer_clear(void* _p); +void _mstabbuffer_destroy(void* _p); +void _idwmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _idwmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _idwmodel_clear(void* _p); +void _idwmodel_destroy(void* _p); +void _idwbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _idwbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _idwbuilder_clear(void* _p); +void _idwbuilder_destroy(void* _p); +void _idwreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _idwreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _idwreport_clear(void* _p); +void _idwreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD) +void lsfitscalexy(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* w, + ae_int_t n, + /* Real */ ae_vector* xc, + /* Real */ ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + double* xa, + double* xb, + double* sa, + double* sb, + /* Real */ ae_vector* xoriginal, + /* Real */ ae_vector* yoriginal, + ae_state *_state); +void buildpriorterm(/* Real */ ae_matrix* xy, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + double priorval, + /* Real */ ae_matrix* v, + ae_state *_state); +void buildpriorterm1(/* Real */ ae_vector* xy1, + ae_int_t n, + ae_int_t nx, + ae_int_t ny, + ae_int_t modeltype, + double priorval, + /* Real */ ae_matrix* v, + ae_state *_state); +#endif +#if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD) +void polynomialbar2cheb(const barycentricinterpolant* p, + double a, + double b, + /* Real */ ae_vector* t, + ae_state *_state); +void polynomialcheb2bar(/* Real */ const ae_vector* t, + ae_int_t n, + double a, + double b, + barycentricinterpolant* p, + ae_state *_state); +void polynomialbar2pow(const barycentricinterpolant* p, + double c, + double s, + /* Real */ ae_vector* a, + ae_state *_state); +void polynomialpow2bar(/* Real */ const ae_vector* a, + ae_int_t n, + double c, + double s, + barycentricinterpolant* p, + ae_state *_state); +void polynomialbuild(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state); +void polynomialbuildeqdist(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state); +void polynomialbuildcheb1(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state); +void polynomialbuildcheb2(double a, + double b, + /* Real */ const ae_vector* y, + ae_int_t n, + barycentricinterpolant* p, + ae_state *_state); +double polynomialcalceqdist(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state); +double polynomialcalccheb1(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state); +double polynomialcalccheb2(double a, + double b, + /* Real */ const ae_vector* f, + ae_int_t n, + double t, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD) +void spline1dbuildlinear(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildlinearbuf(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + spline1dinterpolant* c, + ae_state *_state); +void spline1dgriddiffcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d, + ae_state *_state); +void spline1dgriddiff2cubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d1, + /* Real */ ae_vector* d2, + ae_state *_state); +void spline1dconvcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + ae_state *_state); +void spline1dconvdiffcubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + /* Real */ ae_vector* d2, + ae_state *_state); +void spline1dconvdiff2cubic(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ const ae_vector* _x2, + ae_int_t n2, + /* Real */ ae_vector* y2, + /* Real */ ae_vector* d2, + /* Real */ ae_vector* dd2, + ae_state *_state); +void spline1dbuildcatmullrom(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t boundtype, + double tension, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildhermite(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* d, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildhermitebuf(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _d, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildakima(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void spline1dbuildakimamod(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +double spline1dcalc(const spline1dinterpolant* c, + double x, + ae_state *_state); +void spline1ddiff(const spline1dinterpolant* c, + double x, + double* s, + double* ds, + double* d2s, + ae_state *_state); +void spline1dcopy(const spline1dinterpolant* c, + spline1dinterpolant* cc, + ae_state *_state); +void spline1dalloc(ae_serializer* s, + const spline1dinterpolant* model, + ae_state *_state); +void spline1dserialize(ae_serializer* s, + const spline1dinterpolant* model, + ae_state *_state); +void spline1dunserialize(ae_serializer* s, + spline1dinterpolant* model, + ae_state *_state); +void spline1dunpack(const spline1dinterpolant* c, + ae_int_t* n, + /* Real */ ae_matrix* tbl, + ae_state *_state); +void spline1dlintransx(spline1dinterpolant* c, + double a, + double b, + ae_state *_state); +void spline1dlintransy(spline1dinterpolant* c, + double a, + double b, + ae_state *_state); +double spline1dintegrate(const spline1dinterpolant* c, + double x, + ae_state *_state); +void spline1dfit(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t m, + double lambdans, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dgriddiffcubicinternal(/* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_int_t n, + ae_int_t boundltype, + double boundl, + ae_int_t boundrtype, + double boundr, + /* Real */ ae_vector* d, + /* Real */ ae_vector* a1, + /* Real */ ae_vector* a2, + /* Real */ ae_vector* a3, + /* Real */ ae_vector* b, + /* Real */ ae_vector* dt, + ae_state *_state); +void spline1dconvdiffinternal(/* Real */ const ae_vector* xold, + /* Real */ const ae_vector* yold, + /* Real */ const ae_vector* dold, + ae_int_t n, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ ae_vector* y, + ae_bool needy, + /* Real */ ae_vector* d1, + ae_bool needd1, + /* Real */ ae_vector* d2, + ae_bool needd2, + ae_state *_state); +void spline1drootsandextrema(const spline1dinterpolant* c, + /* Real */ ae_vector* r, + ae_int_t* nr, + ae_bool* dr, + /* Real */ ae_vector* e, + /* Integer */ ae_vector* et, + ae_int_t* ne, + ae_bool* de, + ae_state *_state); +void heapsortdpoints(/* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* d, + ae_int_t n, + ae_state *_state); +void solvepolinom2(double p0, + double m0, + double p1, + double m1, + double* x0, + double* x1, + ae_int_t* nr, + ae_state *_state); +void solvecubicpolinom(double pa, + double ma, + double pb, + double mb, + double a, + double b, + double* x0, + double* x1, + double* x2, + double* ex0, + double* ex1, + ae_int_t* nr, + ae_int_t* ne, + /* Real */ ae_vector* tempdata, + ae_state *_state); +ae_int_t bisectmethod(double pa, + double ma, + double pb, + double mb, + double a, + double b, + double* x, + ae_state *_state); +void spline1dbuildmonotone(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + spline1dinterpolant* c, + ae_state *_state); +void _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline1dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline1dinterpolant_clear(void* _p); +void _spline1dinterpolant_destroy(void* _p); +void _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline1dfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline1dfitreport_clear(void* _p); +void _spline1dfitreport_destroy(void* _p); +void _spline1dbbasis_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline1dbbasis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline1dbbasis_clear(void* _p); +void _spline1dbbasis_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD) +void lstfitpiecewiselinearrdpfixed(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* x2, + /* Real */ ae_vector* y2, + ae_int_t* nsections, + ae_state *_state); +void lstfitpiecewiselinearrdp(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double eps, + /* Real */ ae_vector* x2, + /* Real */ ae_vector* y2, + ae_int_t* nsections, + ae_state *_state); +void polynomialfit(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + barycentricinterpolant* p, + polynomialfitreport* rep, + ae_state *_state); +void polynomialfitwc(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + /* Real */ const ae_vector* _xc, + /* Real */ const ae_vector* _yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + barycentricinterpolant* p, + polynomialfitreport* rep, + ae_state *_state); +double logisticcalc4(double x, + double a, + double b, + double c, + double d, + ae_state *_state); +double logisticcalc5(double x, + double a, + double b, + double c, + double d, + double g, + ae_state *_state); +void logisticfit4(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double* a, + double* b, + double* c, + double* d, + lsfitreport* rep, + ae_state *_state); +void logisticfit4ec(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + double* a, + double* b, + double* c, + double* d, + lsfitreport* rep, + ae_state *_state); +void logisticfit5(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state); +void logisticfit5ec(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state); +void logisticfit45x(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + double cnstrleft, + double cnstrright, + ae_bool is4pl, + double lambdav, + double epsx, + ae_int_t rscnt, + double* a, + double* b, + double* c, + double* d, + double* g, + lsfitreport* rep, + ae_state *_state); +void barycentricfitfloaterhormannwc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state); +void barycentricfitfloaterhormann(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + barycentricinterpolant* b, + barycentricfitreport* rep, + ae_state *_state); +void spline1dfitcubicwc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfithermitewc(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + ae_int_t n, + /* Real */ const ae_vector* xc, + /* Real */ const ae_vector* yc, + /* Integer */ const ae_vector* dc, + ae_int_t k, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfitcubicdeprecated(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfithermitedeprecated(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void lsfitlinearw(/* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +void lsfitlinearwc(/* Real */ const ae_vector* _y, + /* Real */ const ae_vector* w, + /* Real */ const ae_matrix* fmatrix, + /* Real */ const ae_matrix* _cmatrix, + ae_int_t n, + ae_int_t m, + ae_int_t k, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +void lsfitlinear(/* Real */ const ae_vector* y, + /* Real */ const ae_matrix* fmatrix, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +void lsfitlinearc(/* Real */ const ae_vector* _y, + /* Real */ const ae_matrix* fmatrix, + /* Real */ const ae_matrix* cmatrix, + ae_int_t n, + ae_int_t m, + ae_int_t k, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +void lsfitcreatewf(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + double diffstep, + lsfitstate* state, + ae_state *_state); +void lsfitcreatef(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + double diffstep, + lsfitstate* state, + ae_state *_state); +void lsfitcreatewfg(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* w, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + lsfitstate* state, + ae_state *_state); +void lsfitcreatefg(/* Real */ const ae_matrix* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_vector* c, + ae_int_t n, + ae_int_t m, + ae_int_t k, + lsfitstate* state, + ae_state *_state); +void lsfitsetnonmonotonicsteps(lsfitstate* state, + ae_int_t cnt, + ae_state *_state); +void lsfitsetnumdiff(lsfitstate* state, + ae_int_t formulatype, + ae_state *_state); +void lsfitsetcond(lsfitstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state); +void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state); +void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state); +void lsfitsetscale(lsfitstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void lsfitsetbc(lsfitstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void lsfitsetlc(lsfitstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +ae_bool lsfititeration(lsfitstate* state, ae_state *_state); +void lsfitresults(const lsfitstate* state, + /* Real */ ae_vector* c, + lsfitreport* rep, + ae_state *_state); +void lsfitsetgradientcheck(lsfitstate* state, + double teststep, + ae_state *_state); +void lsfitsetprotocolv1(lsfitstate* state, ae_state *_state); +void lsfitsetprotocolv2(lsfitstate* state, ae_state *_state); +void _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _polynomialfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _polynomialfitreport_clear(void* _p); +void _polynomialfitreport_destroy(void* _p); +void _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _barycentricfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _barycentricfitreport_clear(void* _p); +void _barycentricfitreport_destroy(void* _p); +void _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lsfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lsfitreport_clear(void* _p); +void _lsfitreport_destroy(void* _p); +void _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lsfitstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lsfitstate_clear(void* _p); +void _lsfitstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD) +void fitspherels(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* r, + ae_state *_state); +void fitspheremc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rhi, + ae_state *_state); +void fitspheremi(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + ae_state *_state); +void fitspheremz(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state); +void fitspherex(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + double epsx, + ae_int_t aulits, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state); +void fitsphereinternal(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + ae_int_t solvertype, + double epsx, + ae_int_t aulits, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + fitsphereinternalreport* rep, + ae_state *_state); +void _fitsphereinternalreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _fitsphereinternalreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _fitsphereinternalreport_clear(void* _p); +void _fitsphereinternalreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD) +void pspline2build(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline2interpolant* p, + ae_state *_state); +void pspline3build(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline3interpolant* p, + ae_state *_state); +void pspline2buildperiodic(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline2interpolant* p, + ae_state *_state); +void pspline3buildperiodic(/* Real */ const ae_matrix* _xy, + ae_int_t n, + ae_int_t st, + ae_int_t pt, + pspline3interpolant* p, + ae_state *_state); +void pspline2parametervalues(const pspline2interpolant* p, + ae_int_t* n, + /* Real */ ae_vector* t, + ae_state *_state); +void pspline3parametervalues(const pspline3interpolant* p, + ae_int_t* n, + /* Real */ ae_vector* t, + ae_state *_state); +void pspline2calc(const pspline2interpolant* p, + double t, + double* x, + double* y, + ae_state *_state); +void pspline3calc(const pspline3interpolant* p, + double t, + double* x, + double* y, + double* z, + ae_state *_state); +void pspline2tangent(const pspline2interpolant* p, + double t, + double* x, + double* y, + ae_state *_state); +void pspline3tangent(const pspline3interpolant* p, + double t, + double* x, + double* y, + double* z, + ae_state *_state); +void pspline2diff(const pspline2interpolant* p, + double t, + double* x, + double* dx, + double* y, + double* dy, + ae_state *_state); +void pspline3diff(const pspline3interpolant* p, + double t, + double* x, + double* dx, + double* y, + double* dy, + double* z, + double* dz, + ae_state *_state); +void pspline2diff2(const pspline2interpolant* p, + double t, + double* x, + double* dx, + double* d2x, + double* y, + double* dy, + double* d2y, + ae_state *_state); +void pspline3diff2(const pspline3interpolant* p, + double t, + double* x, + double* dx, + double* d2x, + double* y, + double* dy, + double* d2y, + double* z, + double* dz, + double* d2z, + ae_state *_state); +double pspline2arclength(const pspline2interpolant* p, + double a, + double b, + ae_state *_state); +double pspline3arclength(const pspline3interpolant* p, + double a, + double b, + ae_state *_state); +void parametricrdpfixed(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t d, + ae_int_t stopm, + double stopeps, + /* Real */ ae_matrix* x2, + /* Integer */ ae_vector* idx2, + ae_int_t* nsections, + ae_state *_state); +void _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _pspline2interpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _pspline2interpolant_clear(void* _p); +void _pspline2interpolant_destroy(void* _p); +void _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _pspline3interpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _pspline3interpolant_clear(void* _p); +void _pspline3interpolant_destroy(void* _p); +#endif +#if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD) +void rbfv1create(ae_int_t nx, + ae_int_t ny, + rbfv1model* s, + ae_state *_state); +void rbfv1createcalcbuffer(const rbfv1model* s, + rbfv1calcbuffer* buf, + ae_state *_state); +void rbfv1buildmodel(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + ae_int_t aterm, + ae_int_t algorithmtype, + ae_int_t nlayers, + double radvalue, + double radzvalue, + double lambdav, + double epsort, + double epserr, + ae_int_t maxits, + rbfv1model* s, + rbfv1report* rep, + ae_state *_state); +void rbfv1alloc(ae_serializer* s, + const rbfv1model* model, + ae_state *_state); +void rbfv1serialize(ae_serializer* s, + const rbfv1model* model, + ae_state *_state); +void rbfv1unserialize(ae_serializer* s, + rbfv1model* model, + ae_state *_state); +double rbfv1calc2(rbfv1model* s, double x0, double x1, ae_state *_state); +double rbfv1calc3(rbfv1model* s, + double x0, + double x1, + double x2, + ae_state *_state); +void rbfv1calcbuf(rbfv1model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv1tscalcbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv1tsdiffbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbfv1tshessbuf(const rbfv1model* s, + rbfv1calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbfv1gridcalc2(rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state); +void rbfv1gridcalc3vrec(const rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + double searchradius, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool _trypexec_rbfv1gridcalc3vrec(const rbfv1model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + double searchradius, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, ae_state *_state); +void rbfv1unpack(rbfv1model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state); +void _rbfv1calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv1calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv1calcbuffer_clear(void* _p); +void _rbfv1calcbuffer_destroy(void* _p); +void _rbfv1model_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv1model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv1model_clear(void* _p); +void _rbfv1model_destroy(void* _p); +void _gridcalc3v1buf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gridcalc3v1buf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gridcalc3v1buf_clear(void* _p); +void _gridcalc3v1buf_destroy(void* _p); +void _rbfv1report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv1report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv1report_clear(void* _p); +void _rbfv1report_destroy(void* _p); +#endif +#if defined(AE_COMPILE_RBFV3FARFIELDS) || !defined(AE_PARTIAL_BUILD) +void biharmonicevaluatorinit(biharmonicevaluator* eval, + ae_int_t maxp, + ae_state *_state); +void bhpanelinit(biharmonicpanel* panel, + /* Real */ const ae_matrix* xw, + ae_int_t xidx0, + ae_int_t xidx1, + ae_int_t ny, + const biharmonicevaluator* eval, + ae_state *_state); +void bhpanelsetprec(biharmonicpanel* panel, double tol, ae_state *_state); +void bhpaneleval1(const biharmonicpanel* panel, + const biharmonicevaluator* eval, + double x0, + double x1, + double x2, + double* f, + ae_bool neederrbnd, + double* errbnd, + ae_state *_state); +void bhpaneleval(const biharmonicpanel* panel, + const biharmonicevaluator* eval, + double x0, + double x1, + double x2, + /* Real */ ae_vector* f, + ae_bool neederrbnd, + double* errbnd, + ae_state *_state); +void _biharmonicevaluator_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _biharmonicevaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _biharmonicevaluator_clear(void* _p); +void _biharmonicevaluator_destroy(void* _p); +void _biharmonicpanel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _biharmonicpanel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _biharmonicpanel_clear(void* _p); +void _biharmonicpanel_destroy(void* _p); +#endif +#if defined(AE_COMPILE_RBFV3) || !defined(AE_PARTIAL_BUILD) +void rbfv3create(ae_int_t nx, + ae_int_t ny, + ae_int_t bf, + double bfp, + rbfv3model* s, + ae_state *_state); +void rbfv3createcalcbuffer(const rbfv3model* s, + rbfv3calcbuffer* buf, + ae_state *_state); +void rbfv3build(/* Real */ const ae_matrix* xraw, + /* Real */ const ae_matrix* yraw, + ae_int_t nraw, + /* Real */ const ae_vector* scaleraw, + ae_int_t bftype, + double bfparamraw, + double lambdavraw, + ae_int_t aterm, + ae_int_t rbfprofile, + double tol, + rbfv3model* s, + ae_int_t* progress10000, + ae_bool* terminationrequest, + rbfv3report* rep, + ae_state *_state); +void rbfv3alloc(ae_serializer* s, + const rbfv3model* model, + ae_state *_state); +void rbfv3serialize(ae_serializer* s, + const rbfv3model* model, + ae_state *_state); +void rbfv3unserialize(ae_serializer* s, + rbfv3model* model, + ae_state *_state); +double rbfv3calc1(rbfv3model* s, double x0, ae_state *_state); +double rbfv3calc2(rbfv3model* s, double x0, double x1, ae_state *_state); +double rbfv3calc3(rbfv3model* s, + double x0, + double x1, + double x2, + ae_state *_state); +void rbfv3calcbuf(rbfv3model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv3tscalcbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv3tsfastcalcbuf(rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv3tsdiffbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbfv3tshessbuf(const rbfv3model* s, + rbfv3calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbfv3gridcalcvx(const rbfv3model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv3unpack(rbfv3model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state); +ae_int_t rbf3getmaxpanelsize(ae_state *_state); +void rbf3pushfastevaltol(rbfv3model* s, double tol, ae_state *_state); +void _rbf3evaluatorbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3evaluatorbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3evaluatorbuffer_clear(void* _p); +void _rbf3evaluatorbuffer_destroy(void* _p); +void _rbf3panel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3panel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3panel_clear(void* _p); +void _rbf3panel_destroy(void* _p); +void _rbf3fastevaluator_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3fastevaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3fastevaluator_clear(void* _p); +void _rbf3fastevaluator_destroy(void* _p); +void _rbf3evaluator_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3evaluator_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3evaluator_clear(void* _p); +void _rbf3evaluator_destroy(void* _p); +void _rbfv3calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv3calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv3calcbuffer_clear(void* _p); +void _rbfv3calcbuffer_destroy(void* _p); +void _acbfbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _acbfbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _acbfbuilder_clear(void* _p); +void _acbfbuilder_destroy(void* _p); +void _acbfbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _acbfbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _acbfbuffer_clear(void* _p); +void _acbfbuffer_destroy(void* _p); +void _acbfchunk_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _acbfchunk_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _acbfchunk_clear(void* _p); +void _acbfchunk_destroy(void* _p); +void _rbf3ddmbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmbuffer_clear(void* _p); +void _rbf3ddmbuffer_destroy(void* _p); +void _rbf3ddmsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmsubproblem_clear(void* _p); +void _rbf3ddmsubproblem_destroy(void* _p); +void _rbf3ddmsolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbf3ddmsolver_clear(void* _p); +void _rbf3ddmsolver_destroy(void* _p); +void _rbfv3model_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv3model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv3model_clear(void* _p); +void _rbfv3model_destroy(void* _p); +void _rbfv3report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv3report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv3report_clear(void* _p); +void _rbfv3report_destroy(void* _p); +#endif +#if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD) +double spline2dcalc(const spline2dinterpolant* c, + double x, + double y, + ae_state *_state); +void spline2ddiff(const spline2dinterpolant* c, + double x, + double y, + double* f, + double* fx, + double* fy, + ae_state *_state); +void spline2ddiff2(const spline2dinterpolant* c, + double x, + double y, + double* f, + double* fx, + double* fy, + double* fxx, + double* fxy, + double* fyy, + ae_state *_state); +void spline2dcalcvbuf(const spline2dinterpolant* c, + double x, + double y, + /* Real */ ae_vector* f, + ae_state *_state); +double spline2dcalcvi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + ae_state *_state); +void spline2dcalcv(const spline2dinterpolant* c, + double x, + double y, + /* Real */ ae_vector* f, + ae_state *_state); +void spline2ddiffvi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + double* f, + double* fx, + double* fy, + ae_state *_state); +void spline2ddiff2vi(const spline2dinterpolant* c, + double x, + double y, + ae_int_t i, + double* f, + double* fx, + double* fy, + double* fxx, + double* fxy, + double* fyy, + ae_state *_state); +void spline2dlintransxy(spline2dinterpolant* c, + double ax, + double bx, + double ay, + double by, + ae_state *_state); +void spline2dlintransf(spline2dinterpolant* c, + double a, + double b, + ae_state *_state); +void spline2dcopy(const spline2dinterpolant* c, + spline2dinterpolant* cc, + ae_state *_state); +void spline2dresamplebicubic(/* Real */ const ae_matrix* a, + ae_int_t oldheight, + ae_int_t oldwidth, + /* Real */ ae_matrix* b, + ae_int_t newheight, + ae_int_t newwidth, + ae_state *_state); +void spline2dresamplebilinear(/* Real */ const ae_matrix* a, + ae_int_t oldheight, + ae_int_t oldwidth, + /* Real */ ae_matrix* b, + ae_int_t newheight, + ae_int_t newwidth, + ae_state *_state); +void spline2dbuildbilinearv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbilinearvbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbilinearmissing(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbilinearmissingbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbicubicv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildclampedv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _bndbtm, + ae_int_t bndtypebtm, + /* Real */ const ae_vector* _bndtop, + ae_int_t bndtypetop, + /* Real */ const ae_vector* _bndlft, + ae_int_t bndtypelft, + /* Real */ const ae_vector* _bndrgt, + ae_int_t bndtypergt, + /* Real */ const ae_vector* mixedd, + /* Real */ const ae_vector* _f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildhermitev(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Real */ const ae_vector* _dfdx, + /* Real */ const ae_vector* _dfdy, + /* Real */ const ae_vector* _d2fdxdy, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbicubicvbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbicubicmissing(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbicubicmissingbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* _f, + /* Boolean */ const ae_vector* missing, + ae_int_t d, + spline2dinterpolant* c, + ae_state *_state); +void spline2dunpackv(const spline2dinterpolant* c, + ae_int_t* m, + ae_int_t* n, + ae_int_t* d, + /* Real */ ae_matrix* tbl, + ae_state *_state); +void spline2dbuildbilinear(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_matrix* f, + ae_int_t m, + ae_int_t n, + spline2dinterpolant* c, + ae_state *_state); +void spline2dbuildbicubic(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ const ae_matrix* _f, + ae_int_t m, + ae_int_t n, + spline2dinterpolant* c, + ae_state *_state); +void spline2dunpack(const spline2dinterpolant* c, + ae_int_t* m, + ae_int_t* n, + /* Real */ ae_matrix* tbl, + ae_state *_state); +void spline2dbuildercreate(ae_int_t d, + spline2dbuilder* state, + ae_state *_state); +void spline2dbuildersetuserterm(spline2dbuilder* state, + double v, + ae_state *_state); +void spline2dbuildersetlinterm(spline2dbuilder* state, ae_state *_state); +void spline2dbuildersetconstterm(spline2dbuilder* state, ae_state *_state); +void spline2dbuildersetzeroterm(spline2dbuilder* state, ae_state *_state); +void spline2dbuildersetpoints(spline2dbuilder* state, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state); +void spline2dbuildersetareaauto(spline2dbuilder* state, ae_state *_state); +void spline2dbuildersetarea(spline2dbuilder* state, + double xa, + double xb, + double ya, + double yb, + ae_state *_state); +void spline2dbuildersetgrid(spline2dbuilder* state, + ae_int_t kx, + ae_int_t ky, + ae_state *_state); +void spline2dbuildersetalgofastddm(spline2dbuilder* state, + ae_int_t nlayers, + double lambdav, + ae_state *_state); +void spline2dbuildersetalgoblocklls(spline2dbuilder* state, + double lambdans, + ae_state *_state); +void spline2dbuildersetalgonaivells(spline2dbuilder* state, + double lambdans, + ae_state *_state); +void spline2dfit(spline2dbuilder* state, + spline2dinterpolant* s, + spline2dfitreport* rep, + ae_state *_state); +void spline2dalloc(ae_serializer* s, + const spline2dinterpolant* spline, + ae_state *_state); +void spline2dserialize(ae_serializer* s, + const spline2dinterpolant* spline, + ae_state *_state); +void spline2dunserialize(ae_serializer* s, + spline2dinterpolant* spline, + ae_state *_state); +void _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dinterpolant_clear(void* _p); +void _spline2dinterpolant_destroy(void* _p); +void _spline2dbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dbuilder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dbuilder_clear(void* _p); +void _spline2dbuilder_destroy(void* _p); +void _spline2dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dfitreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dfitreport_clear(void* _p); +void _spline2dfitreport_destroy(void* _p); +void _spline2dxdesignmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dxdesignmatrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dxdesignmatrix_clear(void* _p); +void _spline2dxdesignmatrix_destroy(void* _p); +void _spline2dblockllsbuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dblockllsbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dblockllsbuf_clear(void* _p); +void _spline2dblockllsbuf_destroy(void* _p); +void _spline2dfastddmbuf_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline2dfastddmbuf_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline2dfastddmbuf_clear(void* _p); +void _spline2dfastddmbuf_destroy(void* _p); +#endif +#if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD) +void rbfv2create(ae_int_t nx, + ae_int_t ny, + rbfv2model* s, + ae_state *_state); +void rbfv2createcalcbuffer(const rbfv2model* s, + rbfv2calcbuffer* buf, + ae_state *_state); +void rbfv2buildhierarchical(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + /* Real */ const ae_vector* scalevec, + ae_int_t aterm, + ae_int_t nh, + double rbase, + double lambdans, + rbfv2model* s, + ae_int_t* progress10000, + ae_bool* terminationrequest, + rbfv2report* rep, + ae_state *_state); +void rbfv2alloc(ae_serializer* s, + const rbfv2model* model, + ae_state *_state); +void rbfv2serialize(ae_serializer* s, + const rbfv2model* model, + ae_state *_state); +void rbfv2unserialize(ae_serializer* s, + rbfv2model* model, + ae_state *_state); +double rbfv2farradius(ae_int_t bf, ae_state *_state); +double rbfv2nearradius(ae_int_t bf, ae_state *_state); +double rbfv2basisfunc(ae_int_t bf, double d2, ae_state *_state); +void rbfv2basisfuncdiff2(ae_int_t bf, + double d2, + double* f, + double* df, + double* d2f, + ae_state *_state); +double rbfv2calc1(rbfv2model* s, double x0, ae_state *_state); +double rbfv2calc2(rbfv2model* s, double x0, double x1, ae_state *_state); +double rbfv2calc3(rbfv2model* s, + double x0, + double x1, + double x2, + ae_state *_state); +void rbfv2calcbuf(rbfv2model* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv2tscalcbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv2tsdiffbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbfv2tshessbuf(const rbfv2model* s, + rbfv2calcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbfv2gridcalc2(rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state); +void rbfv2gridcalcvx(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfv2partialgridcalcrec(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Integer */ const ae_vector* blocks3, + ae_int_t block3a, + ae_int_t block3b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_int_t levelidx, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool _trypexec_rbfv2partialgridcalcrec(const rbfv2model* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ const ae_vector* x3, + ae_int_t n3, + /* Integer */ const ae_vector* blocks0, + ae_int_t block0a, + ae_int_t block0b, + /* Integer */ const ae_vector* blocks1, + ae_int_t block1a, + ae_int_t block1b, + /* Integer */ const ae_vector* blocks2, + ae_int_t block2a, + ae_int_t block2b, + /* Integer */ const ae_vector* blocks3, + ae_int_t block3a, + ae_int_t block3b, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + ae_int_t levelidx, + double avgfuncpernode, + ae_shared_pool* bufpool, + /* Real */ ae_vector* y, ae_state *_state); +void rbfv2unpack(rbfv2model* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_state *_state); +void _rbfv2calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv2calcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv2calcbuffer_clear(void* _p); +void _rbfv2calcbuffer_destroy(void* _p); +void _rbfv2model_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv2model_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv2model_clear(void* _p); +void _rbfv2model_destroy(void* _p); +void _rbfv2gridcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv2gridcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv2gridcalcbuffer_clear(void* _p); +void _rbfv2gridcalcbuffer_destroy(void* _p); +void _rbfv2report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfv2report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfv2report_clear(void* _p); +void _rbfv2report_destroy(void* _p); +#endif +#if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD) +double spline3dcalc(const spline3dinterpolant* c, + double x, + double y, + double z, + ae_state *_state); +void spline3dlintransxyz(spline3dinterpolant* c, + double ax, + double bx, + double ay, + double by, + double az, + double bz, + ae_state *_state); +void spline3dlintransf(spline3dinterpolant* c, + double a, + double b, + ae_state *_state); +void spline3dcopy(const spline3dinterpolant* c, + spline3dinterpolant* cc, + ae_state *_state); +void spline3dresampletrilinear(/* Real */ const ae_vector* a, + ae_int_t oldzcount, + ae_int_t oldycount, + ae_int_t oldxcount, + ae_int_t newzcount, + ae_int_t newycount, + ae_int_t newxcount, + /* Real */ ae_vector* b, + ae_state *_state); +void spline3dbuildtrilinearv(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* z, + ae_int_t l, + /* Real */ const ae_vector* f, + ae_int_t d, + spline3dinterpolant* c, + ae_state *_state); +void spline3dbuildtrilinearvbuf(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + /* Real */ const ae_vector* z, + ae_int_t l, + /* Real */ const ae_vector* f, + ae_int_t d, + spline3dinterpolant* c, + ae_state *_state); +void spline3dcalcvbuf(const spline3dinterpolant* c, + double x, + double y, + double z, + /* Real */ ae_vector* f, + ae_state *_state); +void spline3dcalcv(const spline3dinterpolant* c, + double x, + double y, + double z, + /* Real */ ae_vector* f, + ae_state *_state); +void spline3dunpackv(const spline3dinterpolant* c, + ae_int_t* n, + ae_int_t* m, + ae_int_t* l, + ae_int_t* d, + ae_int_t* stype, + /* Real */ ae_matrix* tbl, + ae_state *_state); +void _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spline3dinterpolant_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spline3dinterpolant_clear(void* _p); +void _spline3dinterpolant_destroy(void* _p); +#endif +#if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD) +void nsfitspheremcc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rhi, + ae_state *_state); +void nsfitspheremic(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + ae_state *_state); +void nsfitspheremzc(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state); +void nsfitspherex(/* Real */ const ae_matrix* xy, + ae_int_t npoints, + ae_int_t nx, + ae_int_t problemtype, + double epsx, + ae_int_t aulits, + double penalty, + /* Real */ ae_vector* cx, + double* rlo, + double* rhi, + ae_state *_state); +void spline1dfitpenalized(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_int_t m, + double rho, + ae_int_t* info, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfitpenalizedw(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + /* Real */ const ae_vector* _w, + ae_int_t n, + ae_int_t m, + double rho, + ae_int_t* info, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfitcubic(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +void spline1dfithermite(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_int_t m, + spline1dinterpolant* s, + spline1dfitreport* rep, + ae_state *_state); +#endif +#if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD) +void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state); +void rbfcreatecalcbuffer(const rbfmodel* s, + rbfcalcbuffer* buf, + ae_state *_state); +void rbfsetpoints(rbfmodel* s, + /* Real */ const ae_matrix* xy, + ae_int_t n, + ae_state *_state); +void rbfsetpointsandscales(rbfmodel* r, + /* Real */ const ae_matrix* xy, + ae_int_t n, + /* Real */ const ae_vector* s, + ae_state *_state); +void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state); +void rbfsetalgomultilayer(rbfmodel* s, + double rbase, + ae_int_t nlayers, + double lambdav, + ae_state *_state); +void rbfsetalgohierarchical(rbfmodel* s, + double rbase, + ae_int_t nlayers, + double lambdans, + ae_state *_state); +void rbfsetalgothinplatespline(rbfmodel* s, + double lambdav, + ae_state *_state); +void rbfsetalgomultiquadricmanual(rbfmodel* s, + double alpha, + double lambdav, + ae_state *_state); +void rbfsetalgomultiquadricauto(rbfmodel* s, + double lambdav, + ae_state *_state); +void rbfsetalgobiharmonic(rbfmodel* s, double lambdav, ae_state *_state); +void rbfsetlinterm(rbfmodel* s, ae_state *_state); +void rbfsetconstterm(rbfmodel* s, ae_state *_state); +void rbfsetzeroterm(rbfmodel* s, ae_state *_state); +void rbfsetv2bf(rbfmodel* s, ae_int_t bf, ae_state *_state); +void rbfsetv2its(rbfmodel* s, ae_int_t maxits, ae_state *_state); +void rbfsetv2supportr(rbfmodel* s, double r, ae_state *_state); +void rbfsetv3tol(rbfmodel* s, double tol, ae_state *_state); +void rbfsetcond(rbfmodel* s, + double epsort, + double epserr, + ae_int_t maxits, + ae_state *_state); +void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state); +double rbfcalc1(rbfmodel* s, double x0, ae_state *_state); +double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state); +double rbfcalc3(rbfmodel* s, + double x0, + double x1, + double x2, + ae_state *_state); +void rbfdiff1(rbfmodel* s, + double x0, + double* y, + double* dy0, + ae_state *_state); +void rbfdiff2(rbfmodel* s, + double x0, + double x1, + double* y, + double* dy0, + double* dy1, + ae_state *_state); +void rbfdiff3(rbfmodel* s, + double x0, + double x1, + double x2, + double* y, + double* dy0, + double* dy1, + double* dy2, + ae_state *_state); +void rbfsetfastevaltol(rbfmodel* s, double tol, ae_state *_state); +void rbffastcalc(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfcalc(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfdiff(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbfhess(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbfcalcbuf(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfdiffbuf(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbfhessbuf(rbfmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbftscalcbuf(const rbfmodel* s, + rbfcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void rbftsdiffbuf(const rbfmodel* s, + rbfcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + ae_state *_state); +void rbftshessbuf(const rbfmodel* s, + rbfcalcbuffer* buf, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* dy, + /* Real */ ae_vector* d2y, + ae_state *_state); +void rbfgridcalc2(rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_matrix* y, + ae_state *_state); +void rbfgridcalc2v(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfgridcalc2vsubset(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfgridcalc3v(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfgridcalc3vsubset(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Boolean */ const ae_vector* flagy, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfgridcalc2vx(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfgridcalc3vx(const rbfmodel* s, + /* Real */ const ae_vector* x0, + ae_int_t n0, + /* Real */ const ae_vector* x1, + ae_int_t n1, + /* Real */ const ae_vector* x2, + ae_int_t n2, + /* Boolean */ const ae_vector* flagy, + ae_bool sparsey, + /* Real */ ae_vector* y, + ae_state *_state); +void rbfunpack(rbfmodel* s, + ae_int_t* nx, + ae_int_t* ny, + /* Real */ ae_matrix* xwr, + ae_int_t* nc, + /* Real */ ae_matrix* v, + ae_int_t* modelversion, + ae_state *_state); +ae_int_t rbfgetmodelversion(rbfmodel* s, ae_state *_state); +double rbfpeekprogress(const rbfmodel* s, ae_state *_state); +void rbfrequesttermination(rbfmodel* s, ae_state *_state); +void rbfsetprofile(rbfmodel* s, ae_int_t p, ae_state *_state); +void pushfastevaltol(rbfmodel* s, double tol, ae_state *_state); +void rbfalloc(ae_serializer* s, const rbfmodel* model, ae_state *_state); +void rbfserialize(ae_serializer* s, + const rbfmodel* model, + ae_state *_state); +void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state); +void _rbfcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfcalcbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfcalcbuffer_clear(void* _p); +void _rbfcalcbuffer_destroy(void* _p); +void _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfmodel_clear(void* _p); +void _rbfmodel_destroy(void* _p); +void _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfreport_clear(void* _p); +void _rbfreport_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/kernels_avx2.cpp b/core/alglib/kernels_avx2.cpp new file mode 100644 index 00000000..c383f945 --- /dev/null +++ b/core/alglib/kernels_avx2.cpp @@ -0,0 +1,2175 @@ +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" + +// +// Must be defined before we include kernel header +// +#define _ALGLIB_IMPL_DEFINES +#define _ALGLIB_INTEGRITY_CHECKS_ONCE + +#include "kernels_avx2.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +namespace alglib_impl +{ + + + +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_AVX2_INTRINSICS) + +double rdotv_avx2(const ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ const double* __restrict y, + const ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t avx2len = n>>2; + const ae_int_t fmaLen = (avx2len >> 2) << 2; + const __m256d* __restrict pX = (const __m256d*)(x); + const __m256d* __restrict pY = (const __m256d*)(y); + __m256d ans; + if(fmaLen >= 4) { + __m256d fmaUnroll[4]; + fmaUnroll[0] = _mm256_mul_pd(pX[0], pY[0]); + fmaUnroll[1] = _mm256_mul_pd(pX[1], pY[1]); + fmaUnroll[2] = _mm256_mul_pd(pX[2], pY[2]); + fmaUnroll[3] = _mm256_mul_pd(pX[3], pY[3]); + for(i=4; i>2; + const ae_int_t fmaLen = (avx2len >> 2) << 2; + const __m256d* __restrict pX = (const __m256d*)(x); + __m256d ans; + if(fmaLen >= 4) { + //TODO: this can be further unrolled to 8 because AVX(2) provides 16 registers + __m256d fmaUnroll[4]; + fmaUnroll[0] = _mm256_mul_pd(pX[0], pX[0]); + fmaUnroll[1] = _mm256_mul_pd(pX[1], pX[1]); + fmaUnroll[2] = _mm256_mul_pd(pX[2], pX[2]); + fmaUnroll[3] = _mm256_mul_pd(pX[3], pX[3]); + for(i=4; i>2; + const ae_int_t tail = avx2len<<2; + const __m256d* __restrict pSrc = (const __m256d*)(x); + __m256d* __restrict pDest = (__m256d*)(y); + for(i=0; i>2; + const ae_int_t tail = avx2len<<2; + const __m256d* __restrict pSrc = (const __m256d*)(x); + __m256d* __restrict pDest = (__m256d*)(y); + const __m256d avx2v = _mm256_set1_pd(v); + for(i=0; i>5; + ae_int_t i; + for(i=0; i>5; + ae_int_t i; + for(i=0; i>2; + __m256d* __restrict pDest = (__m256d*)(x); + const __m256d avx2v = _mm256_set1_pd(v); + for(i=0; i>3); + rsetv_avx2(n-nDone, v, x+nDone, _state); + return; + } + } +} + +void isetv_avx2(const ae_int_t n, const ae_int_t v, + ae_int_t* __restrict x, ae_state* __restrict _state) +{ + const ae_int_t tail = (n*sizeof(ae_int_t)) & 31; + const ae_int_t even = (n*sizeof(ae_int_t)) - tail; + __m256i *__restrict pDest = (__m256i*)x; + const __m256i avx2v = ((sizeof(v) == 4) ? _mm256_set1_epi32((ae_int32_t)v) : _mm256_set1_epi64x(v)); + const ae_int_t nVec = even>>5; + ae_int_t i; + for(i=0; i>5; + ae_int_t i; + for(i=0; i>2; + __m256d* __restrict pDest = (__m256d*)(x); + const __m256d avx2v = _mm256_set1_pd(v); + for(i=0; i>2; + const ae_int_t tail = avx2len<<2; + __m256d* __restrict pDest = (__m256d*)(x); + for(i=0; i>3); + rmulv_avx2(n-nDone, v, x+nDone, _state); + return; + } + } +} + +void raddv_avx2(const ae_int_t n, + const double alpha, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t avx2len = n>>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + const __m256d avx2alpha = _mm256_set1_pd(alpha); + for(i=0; i>2)<<2; + const __m256d avx2alpha = _mm256_set1_pd(alpha); + __m256d* __restrict pDest = (__m256d*)x; + for(i=0; i>2; + pDest[iDest] = _mm256_add_pd(_mm256_mul_pd(avx2alpha, _mm256_loadu_pd(y+i)), pDest[iDest]); + } + switch(n-vecLen) { + case 1: + x[i] += alpha*y[i]; + break; + case 2: { + const ae_int_t iDest = i>>2; + *(__m128d*)(pDest+iDest) = _mm_add_pd(_mm_mul_pd(_mm256_extractf128_pd(avx2alpha, 0),_mm_loadu_pd(y+i)),*(const __m128d*)(pDest+iDest)); + break; + } + case 3: + { + const ae_int_t iDest = i>>2; + *(__m128d*)(pDest+iDest) = _mm_add_pd(_mm_mul_pd(_mm256_extractf128_pd(avx2alpha, 0),_mm_loadu_pd(y+i)),*(const __m128d*)(pDest+iDest)); + x[i+2] += alpha*y[i+2]; + break; + } + } +} + +void raddvx_avx2(const ae_int_t n, const double alpha, const double* __restrict y, + double* __restrict x, ae_state *_state) +{ + const ptrdiff_t unal = ((ptrdiff_t)x) & 31; + if( n<=4 ) + { + ae_int_t i; + for(i=0; i<=n-1; i++) + x[i] += alpha*y[i]; + return; + } + switch(unal) + { + case 0: + raddvx_avx_xaligned(n, alpha, y, x, _state); + return; + case 8: + x[2] += alpha*y[2]; + case 16: + x[1] += alpha*y[1]; + case 24: + { + x[0] += alpha*y[0]; + const ptrdiff_t nDone = 4-(unal>>3); + raddvx_avx_xaligned(n-nDone, alpha, y+nDone, x+nDone, _state); + return; + } + } +} + +void rmergemulv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t avx2len = n>>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + for(i=0; i>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + for(i=0; i>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + for(i=0; i*(const double*)(pDest+i) ? *(const double*)(pSrc+i) : *(const double*)(pDest+i); + break; + case 2: + *(__m128d*)(pDest+i) = _mm_max_pd(*(const __m128d*)(pSrc+i), *(const __m128d*)(pDest+i)); + break; + case 3: + { + double s2 = ((const double*)(pSrc+i))[2]; + double *d2 = ((double*)(pDest+i))+2; + *(__m128d*)(pDest+i) = _mm_max_pd(*(const __m128d*)(pSrc+i), *(const __m128d*)(pDest+i)); + *d2 = s2>*d2 ? s2 : *d2; + break; + } + } +} + +void rmergeminv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t avx2len = n>>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + for(i=0; i>2; + const ae_int_t tail = avx2len<<2; + const __m256d* __restrict pSrc = (const __m256d*)(x); + if( n<=4 ) + { + double result; + if(n == 0) + return 0.0; + result = x[0]; + for(i=1; i<=n-1; i++) + { + double v = x[i]; + if( v>result ) + result = v; + } + return result; + } + __m256d curMax = pSrc[0]; + for(i=1; i pComps[1]) ? pComps[0] : pComps[1]; + const double *p_tail = (const double*)(pSrc+i); + switch(n-tail) + { + case 1: + { + dMax = p_tail[0]>dMax ? p_tail[0] : dMax; + break; + } + case 2: { + dMax = p_tail[0]>dMax ? p_tail[0] : dMax; + dMax = p_tail[1]>dMax ? p_tail[1] : dMax; + break; + } + case 3: { + dMax = p_tail[0]>dMax ? p_tail[0] : dMax; + dMax = p_tail[1]>dMax ? p_tail[1] : dMax; + dMax = p_tail[2]>dMax ? p_tail[2] : dMax; + break; + } + } + return dMax; +} + +double rmaxabsv_avx2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state) +{ + const __m256d signMask = _mm256_set1_pd(-0.); // -0. = 1 << 63 + const ae_int_t avx2len = n>>2; + const __m256d* __restrict pSrc = (const __m256d*)(x); + if( n<=4 ) + { + double result; + ae_int_t i; + result = 0; + for(i=0; i<=n-1; i++) + { + double v = fabs(x[i]); + if( v>result ) + result = v; + } + return result; + } + __m256d curMax = _mm256_andnot_pd(signMask, pSrc[0]); // abs + ae_int_t i; + for(i=1; i pComps[1]) ? pComps[0] : pComps[1]; + switch(n-tail) + { + case 1: + { + double a0 = fabs(p_tail[0]); + dMax = a0>dMax ? a0 : dMax; + break; + } + case 2: + { + double a0 = fabs(p_tail[0]); + double a1 = fabs(p_tail[1]); + dMax = a0>dMax ? a0 : dMax; + dMax = a1>dMax ? a1 : dMax; + break; + } + case 3: + { + double a0 = fabs(p_tail[0]); + double a1 = fabs(p_tail[1]); + double a2 = fabs(p_tail[2]); + dMax = a0>dMax ? a0 : dMax; + dMax = a1>dMax ? a1 : dMax; + dMax = a2>dMax ? a2 : dMax; + break; + } + } + return dMax; +} + +static void rcopyvx_avx2_xaligned(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state) +{ + ae_int_t i; + const ae_int_t vecLen = (n>>2)<<2; + const __m256d* __restrict pSrc = (const __m256d*)x; + for(i=0; i>2; + _mm256_storeu_pd(y+i, pSrc[iSrc]); + } + switch(n-vecLen) { + case 1: + y[i] = x[i]; + break; + case 2: { + const ae_int_t iSrc = i>>2; + _mm_storeu_pd(y+i, *(const __m128d*)(pSrc+iSrc)); + break; + } + case 3: { + const ae_int_t iSrc = i>>2; + const __m256d t = pSrc[iSrc]; + _mm_storeu_pd(y+i, _mm256_extractf128_pd(t, 0)); + y[i+2] = *(((const double*)&t)+2); + break; + } + } +} + +void rcopyvx_avx2(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state) +{ + const ptrdiff_t unal = ((ptrdiff_t)x) & 31; + if( n<=4 ) + { + ae_int_t j; + for(j=0; j>3); + rcopyvx_avx2_xaligned(n-nDone, x+nDone, y+nDone, _state); + return; + } + } +} + +static void icopyvx_avx2_xaligned(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state) +{ + const ae_int_t tail = (n*sizeof(ae_int_t)) & 31; + const ae_int_t even = (n*sizeof(ae_int_t)) - tail; + const __m256i* __restrict pSrc = (const __m256i*)x; + const ae_int_t nVec = even>>5; + const ae_int_t shift_by = 3-sizeof(ae_int_t)/8; + ae_int_t i; + for(i=0; i> 2; + const ae_int_t nUnroll = nVec >> 3; + __m256d sum = _mm256_setzero_pd(); + for(i=0; iptr.pp_double[i]; + if(nUnroll >= 1) { + __m256d u0 = _mm256_mul_pd(pRow[0], pX[0]); + __m256d u1 = _mm256_mul_pd(pRow[1], pX[1]); + __m256d u2 = _mm256_mul_pd(pRow[2], pX[2]); + __m256d u3 = _mm256_mul_pd(pRow[3], pX[3]); + __m256d u4 = _mm256_mul_pd(pRow[4], pX[4]); + __m256d u5 = _mm256_mul_pd(pRow[5], pX[5]); + __m256d u6 = _mm256_mul_pd(pRow[6], pX[6]); + __m256d u7 = _mm256_mul_pd(pRow[7], pX[7]); + for(j=1; jptr.pp_double[i][j] * x[j]; + } + y[i] += alpha*ans; + } +} + +void rgemv_transposed_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + __m256d* __restrict pY = (__m256d*)y; + const ae_int_t nVec = m >> 2; + + for(i=0; i<=n-1; i++) + { + const __m256d* __restrict pRow = (const __m256d*)a->ptr.pp_double[i]; + const double v = alpha*x[i]; + const __m256d vV = _mm256_set1_pd(v); + for(j=0; jptr.pp_double[i][j]; + } + } +} + +void rgemvx_straight_avx2_xaligned(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + const __m256d* __restrict pX = (const __m256d*)x; + const ae_int_t nVec = n >> 2; + const ae_int_t nUnroll = nVec >> 3; + __m256d sum = _mm256_setzero_pd(); + for(i=0; iptr.pp_double[i+ia]+ja); + if(nUnroll >= 1) { + __m256d u0 = _mm256_mul_pd(ULOAD256PD(pRow[0]), pX[0]); + __m256d u1 = _mm256_mul_pd(ULOAD256PD(pRow[1]), pX[1]); + __m256d u2 = _mm256_mul_pd(ULOAD256PD(pRow[2]), pX[2]); + __m256d u3 = _mm256_mul_pd(ULOAD256PD(pRow[3]), pX[3]); + __m256d u4 = _mm256_mul_pd(ULOAD256PD(pRow[4]), pX[4]); + __m256d u5 = _mm256_mul_pd(ULOAD256PD(pRow[5]), pX[5]); + __m256d u6 = _mm256_mul_pd(ULOAD256PD(pRow[6]), pX[6]); + __m256d u7 = _mm256_mul_pd(ULOAD256PD(pRow[7]), pX[7]); + for(j=1; jptr.pp_double[i+ia][j+ja] * x[j]; + } + y[i] += alpha*ans; + } +} + +void rgemvx_straight_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + if( n<=3 ) { + for(i=0; iptr.pp_double[ia+i]+ja; + double v = 0.0; + for(j=0; j>3); + for(i=0; iptr.pp_double[ia+i]+ja; + double v = 0.0; + for(j=0; j> 2; + + for(i=0; i<=n-1; i++) + { + const __m256d* __restrict pRow = (const __m256d*)(a->ptr.pp_double[i+ia]+ja); + const double v = alpha*x[i]; + const __m256d vV = _mm256_set1_pd(v); + for(j=0; jptr.pp_double[i+ia][j+ja]; + } + } +} + +void rgemvx_transposed_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, double* __restrict y, + ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + if( m<=3 ) { + for(i=0; iptr.pp_double[ia+i]+ja; + const double v = alpha*x[i]; + for(j=0; j>3); + for(i=0; iptr.pp_double[ia+i]+ja; + const double v = alpha*x[i]; + for(j=0; j>3)<<3; + const double *src1 = src+src_stride; + double *dst1 = dst+block_size; + if( opsrc_width==2 ) + { + /* + * Width=2 + */ + for(i=0; i>2)<<2; + const double *srci = src; + double *dst1 = dst+block_size; + if( opsrc_width==2 ) + { + /* + * Width=2 + */ + for(i=0; i>2)<<2; + for(i=opsrc_length; i0 && (((ptrdiff_t)dst)&31) ) + { + *dst += alpha*(*src); + n--; + dst++; + src++; + } + n4=(n>>2)<<2; + for(i=0; i0 && (((ptrdiff_t)dst)&31) ) + { + *dst = alpha*(*src) + beta*(*dst); + n--; + dst++; + src++; + } + n4=(n>>2)<<2; + for(i=0; iptr.p_double; + double* __restrict diagd = _diagd->ptr.p_double; + const ae_int_t* __restrict raw2smap = _raw2smap->ptr.p_int; + const ae_int_t* __restrict superrowidx = _superrowidx->ptr.p_int; + ae_int_t k; + ae_int_t targetrow; + ae_int_t targetcol; + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + if( twidth<3||twidth>4 ) + { + return ae_false; + } + if( uwidth<1||uwidth>4 ) + { + return ae_false; + } + if( urank>4 ) + { + return ae_false; + } + + /* + * Shift input arrays to the beginning of the working area. + * Prepare SIMD masks + */ + __m256i v_rankmask = _mm256_cmpgt_epi64(_mm256_set_epi64x(urank, urank, urank, urank), _mm256_set_epi64x(3, 2, 1, 0)); + double *update_storage = rowstorage+offsu; + double *target_storage = rowstorage+offss; + superrowidx += urbase; + + /* + * Load head of the update matrix + */ + __m256d v_d0123 = _mm256_maskload_pd(diagd+offsd, v_rankmask); + __m256d u_0_0123 = _mm256_setzero_pd(); + __m256d u_1_0123 = _mm256_setzero_pd(); + __m256d u_2_0123 = _mm256_setzero_pd(); + __m256d u_3_0123 = _mm256_setzero_pd(); + for(k=0; k<=uwidth-1; k++) + { + targetcol = raw2smap[superrowidx[k]]; + if( targetcol==0 ) + u_0_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==1 ) + u_1_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==2 ) + u_2_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==3 ) + u_3_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + } + + /* + * Transpose head + */ + __m256d u01_lo = _mm256_unpacklo_pd(u_0_0123,u_1_0123); + __m256d u01_hi = _mm256_unpackhi_pd(u_0_0123,u_1_0123); + __m256d u23_lo = _mm256_unpacklo_pd(u_2_0123,u_3_0123); + __m256d u23_hi = _mm256_unpackhi_pd(u_2_0123,u_3_0123); + __m256d u_0123_0 = _mm256_permute2f128_pd(u01_lo, u23_lo, 0x20); + __m256d u_0123_1 = _mm256_permute2f128_pd(u01_hi, u23_hi, 0x20); + __m256d u_0123_2 = _mm256_permute2f128_pd(u23_lo, u01_lo, 0x13); + __m256d u_0123_3 = _mm256_permute2f128_pd(u23_hi, u01_hi, 0x13); + + /* + * Run update + */ + if( urank==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_sub_pd(_mm256_load_pd(target_storage+targetrow), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+0), u_0123_0))); + } + } + if( urank==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_sub_pd(_mm256_sub_pd(_mm256_load_pd(target_storage+targetrow), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+1), u_0123_1)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+0), u_0123_0))); + } + } + if( urank==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_sub_pd(_mm256_sub_pd(_mm256_sub_pd(_mm256_load_pd(target_storage+targetrow), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+2), u_0123_2)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+1), u_0123_1)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+0), u_0123_0))); + } + } + if( urank==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_sub_pd(_mm256_sub_pd(_mm256_sub_pd(_mm256_sub_pd(_mm256_load_pd(target_storage+targetrow), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+3), u_0123_3)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+2), u_0123_2)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+1), u_0123_1)), + _mm256_mul_pd(_mm256_broadcast_sd(update_row+0), u_0123_0))); + } + } + return ae_true; +} + +ae_bool spchol_updatekernel4444_avx2( + double* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + const double* diagd, + ae_int_t offsd, + const ae_int_t* raw2smap, + const ae_int_t* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + ae_int_t offsk; + __m256d v_negd_u0, v_negd_u1, v_negd_u2, v_negd_u3, v_negd; + __m256d v_w0, v_w1, v_w2, v_w3, u01_lo, u01_hi, u23_lo, u23_hi; + + /* + * Compute W = -D*transpose(U[0:3]) + */ + v_negd = _mm256_mul_pd(_mm256_loadu_pd(diagd+offsd),_mm256_set1_pd(-1.0)); + v_negd_u0 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+0*4),v_negd); + v_negd_u1 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+1*4),v_negd); + v_negd_u2 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+2*4),v_negd); + v_negd_u3 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+3*4),v_negd); + u01_lo = _mm256_unpacklo_pd(v_negd_u0,v_negd_u1); + u01_hi = _mm256_unpackhi_pd(v_negd_u0,v_negd_u1); + u23_lo = _mm256_unpacklo_pd(v_negd_u2,v_negd_u3); + u23_hi = _mm256_unpackhi_pd(v_negd_u2,v_negd_u3); + v_w0 = _mm256_permute2f128_pd(u01_lo, u23_lo, 0x20); + v_w1 = _mm256_permute2f128_pd(u01_hi, u23_hi, 0x20); + v_w2 = _mm256_permute2f128_pd(u23_lo, u01_lo, 0x13); + v_w3 = _mm256_permute2f128_pd(u23_hi, u01_hi, 0x13); + + // + // Compute update S:= S + row_scatter(U*W) + // + if( sheight==uheight ) + { + /* + * No row scatter, the most efficient code + */ + for(k=0; k<=uheight-1; k++) + { + __m256d target; + + targetrow = offss+k*4; + offsk = offsu+k*4; + + target = _mm256_load_pd(rowstorage+targetrow); + target = _mm256_add_pd(_mm256_mul_pd(_mm256_broadcast_sd(rowstorage+offsk+0),v_w0),target); + target = _mm256_add_pd(_mm256_mul_pd(_mm256_broadcast_sd(rowstorage+offsk+1),v_w1),target); + target = _mm256_add_pd(_mm256_mul_pd(_mm256_broadcast_sd(rowstorage+offsk+2),v_w2),target); + target = _mm256_add_pd(_mm256_mul_pd(_mm256_broadcast_sd(rowstorage+offsk+3),v_w3),target); + _mm256_store_pd(rowstorage+targetrow, target); + } + } + else + { + /* + * Row scatter is performed, less efficient code using double mapping to determine target row index + */ + for(k=0; k<=uheight-1; k++) + { + __m256d v_uk0, v_uk1, v_uk2, v_uk3, target; + + targetrow = offss+raw2smap[superrowidx[urbase+k]]*4; + offsk = offsu+k*4; + + target = _mm256_load_pd(rowstorage+targetrow); + v_uk0 = _mm256_broadcast_sd(rowstorage+offsk+0); + v_uk1 = _mm256_broadcast_sd(rowstorage+offsk+1); + v_uk2 = _mm256_broadcast_sd(rowstorage+offsk+2); + v_uk3 = _mm256_broadcast_sd(rowstorage+offsk+3); + target = _mm256_add_pd(_mm256_mul_pd(v_uk0,v_w0),target); + target = _mm256_add_pd(_mm256_mul_pd(v_uk1,v_w1),target); + target = _mm256_add_pd(_mm256_mul_pd(v_uk2,v_w2),target); + target = _mm256_add_pd(_mm256_mul_pd(v_uk3,v_w3),target); + _mm256_store_pd(rowstorage+targetrow, target); + } + } + return ae_true; +} + + +/************************************************************************* +Fast kernel for biharmonic panel with NY=1 + +INPUT PARAMETERS: + D0, D1, D2 - evaluation point minus (Panel.C0,Panel.C1,Panel.C2) + +OUTPUT PARAMETERS: + F - model value + InvPowRPPlus1 - 1/(R^(P+1)) + + -- ALGLIB -- + Copyright 26.08.2022 by Sergey Bochkanov +*************************************************************************/ +ae_bool rbfv3farfields_bhpaneleval1fastkernel16_avx2(double d0, + double d1, + double d2, + const double* pnma, + const double* pnmb, + const double* pmmcdiag, + const double* ynma, + const double* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state) +{ + ae_int_t n; + double r, r2, r01, invr; + double sintheta, costheta; + ae_complex expiphi, expiphi2, expiphi3, expiphi4; + ae_int_t jj; + ae_bool result; + + *f = 0.0; + *invpowrpplus1 = 0.0; + result = ae_true; + + /* + *Convert to spherical polar coordinates. + * + * NOTE: we make sure that R is non-zero by adding extremely small perturbation + */ + r2 = d0*d0+d1*d1+d2*d2+ae_minrealnumber; + r = ae_sqrt(r2, _state); + r01 = ae_sqrt(d0*d0+d1*d1+ae_minrealnumber, _state); + costheta = d2/r; + sintheta = r01/r; + expiphi.x = d0/r01; + expiphi.y = d1/r01; + invr = (double)1/r; + + /* + * prepare precomputed quantities + */ + double powsintheta2 = sintheta*sintheta; + double powsintheta3 = powsintheta2*sintheta; + double powsintheta4 = powsintheta2*powsintheta2; + expiphi2.x = expiphi.x*expiphi.x-expiphi.y*expiphi.y; + expiphi2.y = 2*expiphi.x*expiphi.y; + expiphi3.x = expiphi2.x*expiphi.x-expiphi2.y*expiphi.y; + expiphi3.y = expiphi2.x*expiphi.y+expiphi.x*expiphi2.y; + expiphi4.x = expiphi2.x*expiphi2.x-expiphi2.y*expiphi2.y; + expiphi4.y = 2*expiphi2.x*expiphi2.y; + + /* + * Compute far field expansion for a cluster of basis functions f=r + * + * NOTE: the original paper by Beatson et al. uses f=r as the basis function, + * whilst ALGLIB uses f=-r due to conditional positive definiteness requirement. + * We will perform conversion later. + */ + __m256d v_costheta = _mm256_set1_pd(costheta); + __m256d v_r2 = _mm256_set1_pd(r2); + __m256d v_f = _mm256_setzero_pd(); + __m256d v_invr = _mm256_set1_pd(invr); + __m256d v_powsinthetaj = _mm256_set_pd(powsintheta3, powsintheta2, sintheta, 1.0); + __m256d v_powsintheta4 = _mm256_set1_pd(powsintheta4); + __m256d v_expijphix = _mm256_set_pd(expiphi3.x, expiphi2.x, expiphi.x, 1.0); + __m256d v_expijphiy = _mm256_set_pd(expiphi3.y, expiphi2.y, expiphi.y, 0.0); + __m256d v_expi4phix = _mm256_set1_pd(expiphi4.x); + __m256d v_expi4phiy = _mm256_set1_pd(expiphi4.y); + *f = (double)(0); + for(jj=0; jj<4; jj++) + { + __m256d pnm_cur = _mm256_setzero_pd(), pnm_prev = _mm256_setzero_pd(), pnm_new; + __m256d v_powrminusj1 = _mm256_set1_pd(invr); + for(n=0; n16 ) + return ae_false; + for(int k=0; k>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _kernels_avx2_h +#define _kernels_avx2_h + +#include "ap.h" + +#define AE_USE_CPP + + + +namespace alglib_impl +{ +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_AVX2_INTRINSICS) + +double rdotv_avx2(const ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ const double* __restrict y, + const ae_state* __restrict _state); +double rdotv2_avx2(const ae_int_t n, + /* Real */ const double* __restrict x, + const ae_state* __restrict _state); +void rcopyv_avx2(ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ double* __restrict y, + ae_state* __restrict _state); +void rcopymulv_avx2(const ae_int_t n, + const double v, + /* Real */ const double* __restrict x, + /* Real */ double* __restrict y, + const ae_state* __restrict _state); +void icopyv_avx2(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state); +void bcopyv_avx2(const ae_int_t n, const ae_bool* __restrict x, + ae_bool* __restrict y, ae_state* __restrict _state); +void rsetv_avx2(const ae_int_t n, + const double v, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void rsetvx_avx2(const ae_int_t n, const double v, double* __restrict x, + const ae_state* __restrict _state); +void isetv_avx2(const ae_int_t n, const ae_int_t v, + ae_int_t* __restrict x, ae_state* __restrict _state); +void bsetv_avx2(const ae_int_t n, const ae_bool v, ae_bool* __restrict x, + ae_state* __restrict _state); +void rmulv_avx2(const ae_int_t n, const double v, double* __restrict x, + const ae_state* __restrict _state); +void rsqrtv_avx2(const ae_int_t n, double* __restrict x, const ae_state* __restrict _state); +void rmulvx_avx2(const ae_int_t n, const double v, double* __restrict x, + const ae_state* __restrict _state); +void raddv_avx2(const ae_int_t n, + const double alpha, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void raddvx_avx2(const ae_int_t n, const double alpha, const double* __restrict y, + double* __restrict x, ae_state *_state); +void rmergemulv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void rmergedivv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void rmergemaxv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + ae_state* __restrict _state); +void rmergeminv_avx2(ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + ae_state* __restrict _state); +double rmaxv_avx2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state); +double rmaxabsv_avx2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state); +void rcopyvx_avx2(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state); +void icopyvx_avx2(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state); + +void rgemv_straight_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state); +void rgemv_transposed_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state); +void rgemvx_straight_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state); +void rgemvx_transposed_avx2(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, double* __restrict y, + ae_state* _state); + +ae_int_t ablasf_packblkh_avx2( + const double *src, + ae_int_t src_stride, + ae_int_t op, + ae_int_t opsrc_length, + ae_int_t opsrc_width, + double *dst, + ae_int_t block_size, + ae_int_t micro_size); +ae_int_t ablasf_packblkh32_avx2( + const double *src, + ae_int_t src_stride, + ae_int_t op, + ae_int_t ignore_opsrc_length, + ae_int_t opsrc_width, + double *dst, + ae_int_t ignore_block_size, + ae_int_t micro_size); +void ablasf_dotblkh_avx2( + const double *src_a, + const double *src_b, + ae_int_t round_length, + ae_int_t block_size, + ae_int_t micro_size, + double *dst, + ae_int_t dst_stride); +void ablasf_daxpby_avx2( + ae_int_t n, + double alpha, + const double *src, + double beta, + double *dst); +ae_bool spchol_updatekernelabc4_avx2(ae_vector* _rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t urank, + ae_int_t urowstride, + ae_int_t uwidth, + const ae_vector* _diagd, + ae_int_t offsd, + const ae_vector* _raw2smap, + const ae_vector* _superrowidx, + ae_int_t urbase, + ae_state *_state); +ae_bool spchol_updatekernel4444_avx2( + double* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + const double* diagd, + ae_int_t offsd, + const ae_int_t* raw2smap, + const ae_int_t* superrowidx, + ae_int_t urbase, + ae_state *_state); +ae_bool rbfv3farfields_bhpaneleval1fastkernel16_avx2(double d0, + double d1, + double d2, + const double* pnma, + const double* pnmb, + const double* pmmcdiag, + const double* ynma, + const double* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state); +ae_bool rbfv3farfields_bhpanelevalfastkernel16_avx2(double d0, + double d1, + double d2, + ae_int_t ny, + const double* pnma, + const double* pnmb, + const double* pmmcdiag, + const double* ynma, + const double* tblrmodmn, + double* f, + double* invpowrpplus1, + ae_state *_state); + +/* ALGLIB_NO_FAST_KERNELS, _ALGLIB_HAS_AVX2_INTRINSICS */ +#endif + +} + +#endif + diff --git a/core/alglib/kernels_fma.cpp b/core/alglib/kernels_fma.cpp new file mode 100644 index 00000000..6820618b --- /dev/null +++ b/core/alglib/kernels_fma.cpp @@ -0,0 +1,1069 @@ +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" + +// +// Must be defined before we include kernel header +// +#define _ALGLIB_IMPL_DEFINES +#define _ALGLIB_INTEGRITY_CHECKS_ONCE + +#include "kernels_fma.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +namespace alglib_impl +{ + + + +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_FMA_INTRINSICS) +double rdotv_fma(const ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ const double* __restrict y, + const ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t avx2len = n>>2; + const ae_int_t fmaLen = (avx2len >> 2) << 2; + const __m256d* __restrict pX = (const __m256d*)(x); + const __m256d* __restrict pY = (const __m256d*)(y); + __m256d ans; + if(fmaLen >= 4) { + __m256d fmaUnroll[4]; + fmaUnroll[0] = _mm256_mul_pd(pX[0], pY[0]); + fmaUnroll[1] = _mm256_mul_pd(pX[1], pY[1]); + fmaUnroll[2] = _mm256_mul_pd(pX[2], pY[2]); + fmaUnroll[3] = _mm256_mul_pd(pX[3], pY[3]); + for(i=4; i>2; + const ae_int_t fmaLen = (avx2len >> 2) << 2; + const __m256d* __restrict pX = (const __m256d*)(x); + __m256d ans; + if(fmaLen >= 4) { + //TODO: this can be further unrolled to 8 because AVX(2) provides 16 registers + __m256d fmaUnroll[4]; + fmaUnroll[0] = _mm256_mul_pd(pX[0], pX[0]); + fmaUnroll[1] = _mm256_mul_pd(pX[1], pX[1]); + fmaUnroll[2] = _mm256_mul_pd(pX[2], pX[2]); + fmaUnroll[3] = _mm256_mul_pd(pX[3], pX[3]); + for(i=4; i>2; + const __m256d* __restrict pSrc = (const __m256d*)(y); + __m256d* __restrict pDest = (__m256d*)(x); + const __m256d avx2alpha = _mm256_set1_pd(alpha); + for(i=0; i>2)<<2; + const __m256d avx2alpha = _mm256_set1_pd(alpha); + __m256d* __restrict pDest = (__m256d*)x; + for(i=0; i>2; + pDest[iDest] = _mm256_fmadd_pd(avx2alpha, _mm256_loadu_pd(y+i), pDest[iDest]); + } + switch(n-vecLen) { + case 1: + x[i] += alpha*y[i]; + break; + case 2: { + const ae_int_t iDest = i>>2; + *(__m128d*)(pDest+iDest) = _mm_fmadd_pd(_mm256_extractf128_pd(avx2alpha, 0), + _mm_loadu_pd(y+i), *(const __m128d*)(pDest+iDest)); + break; + } + case 3: + { + const ae_int_t iDest = i>>2; + *(__m128d*)(pDest+iDest) = _mm_fmadd_pd(_mm256_extractf128_pd(avx2alpha, 0), _mm_loadu_pd(y+i), *(const __m128d*)(pDest+iDest)); + x[i+2] += alpha*y[i+2]; + break; + } + } +} + +void raddvx_fma(const ae_int_t n, const double alpha, const double* __restrict y, double* __restrict x, ae_state *_state) +{ + const ptrdiff_t unal = ((ptrdiff_t)x) & 31; + if( n<=4 ) + { + ae_int_t i; + for(i=0; i<=n-1; i++) + x[i] += alpha*y[i]; + return; + } + switch(unal) { + case 0: + raddvx_fma3avx_xaligned(n, alpha, y, x, _state); + return; + case 8: + x[2] += alpha*y[2]; + case 16: + x[1] += alpha*y[1]; + case 24: { + x[0] += alpha*y[0]; + const ptrdiff_t nDone = 4-(unal>>3); + raddvx_fma3avx_xaligned(n-nDone, alpha, y+nDone, x+nDone, _state); + return; + } + } +} + +void rmuladdv_fma(const ae_int_t n, + const double* __restrict y, + const double* __restrict z, + double* __restrict x, + const ae_state* _state) +{ + ae_int_t i; + const ae_int_t avx2len = n>>2; + const __m256d* __restrict pSrc0 = (const __m256d*)y; + const __m256d* __restrict pSrc1 = (const __m256d*)z; + __m256d* __restrict pDest = (__m256d*)x; + for(i=0; i>2; + const __m256d* __restrict pSrc0 = (const __m256d*)y; + const __m256d* __restrict pSrc1 = (const __m256d*)z; + __m256d* __restrict pDest = (__m256d*)x; + for(i=0; i>2; + const __m256d* __restrict pSrc0 = (const __m256d*)y; + const __m256d* __restrict pSrc1 = (const __m256d*)z; + const __m256d* __restrict pSrc2 = (const __m256d*)x; + __m256d* __restrict pDest = (__m256d*)r; + for(i=0; i>2; + const __m256d* __restrict pSrc0 = (const __m256d*)y; + const __m256d* __restrict pSrc1 = (const __m256d*)z; + const __m256d* __restrict pSrc2 = (const __m256d*)x; + __m256d* __restrict pDest = (__m256d*)r; + for(i=0; i> 2; + const ae_int_t nUnroll = nVec >> 3; + for(i=0; iptr.pp_double[i]; + if(nUnroll >= 1) { + __m256d u0 = _mm256_mul_pd(pRow[0], pX[0]); + __m256d u1 = _mm256_mul_pd(pRow[1], pX[1]); + __m256d u2 = _mm256_mul_pd(pRow[2], pX[2]); + __m256d u3 = _mm256_mul_pd(pRow[3], pX[3]); + __m256d u4 = _mm256_mul_pd(pRow[4], pX[4]); + __m256d u5 = _mm256_mul_pd(pRow[5], pX[5]); + __m256d u6 = _mm256_mul_pd(pRow[6], pX[6]); + __m256d u7 = _mm256_mul_pd(pRow[7], pX[7]); + for(j=1; jptr.pp_double[i][j] * x[j]; + } + y[i] += alpha*ans; + } +} + +void rgemv_transposed_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + __m256d* __restrict pY = (__m256d*)y; + const ae_int_t nVec = m >> 2; + + for(i=0; i<=n-1; i++) + { + const __m256d* __restrict pRow = (const __m256d*)a->ptr.pp_double[i]; + const double v = alpha*x[i]; + const __m256d vV = _mm256_set1_pd(v); + for(j=0; jptr.pp_double[i][j]; + } + } +} + +void rgemvx_straight_fma_xaligned(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + const __m256d* __restrict pX = (const __m256d*)x; + const ae_int_t nVec = n >> 2; + const ae_int_t nUnroll = nVec >> 3; + __m256d sum = _mm256_setzero_pd(); + for(i=0; iptr.pp_double[i+ia]+ja); + if(nUnroll >= 1) { + __m256d u0 = _mm256_mul_pd(ULOAD256PD(pRow[0]), pX[0]); + __m256d u1 = _mm256_mul_pd(ULOAD256PD(pRow[1]), pX[1]); + __m256d u2 = _mm256_mul_pd(ULOAD256PD(pRow[2]), pX[2]); + __m256d u3 = _mm256_mul_pd(ULOAD256PD(pRow[3]), pX[3]); + __m256d u4 = _mm256_mul_pd(ULOAD256PD(pRow[4]), pX[4]); + __m256d u5 = _mm256_mul_pd(ULOAD256PD(pRow[5]), pX[5]); + __m256d u6 = _mm256_mul_pd(ULOAD256PD(pRow[6]), pX[6]); + __m256d u7 = _mm256_mul_pd(ULOAD256PD(pRow[7]), pX[7]); + for(j=1; jptr.pp_double[i+ia][j+ja] * x[j]; + } + y[i] += alpha*ans; + } +} + +void rgemvx_straight_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + if( n<=3 ) { + for(i=0; iptr.pp_double[ia+i]+ja; + double v = 0.0; + for(j=0; j>3); + for(i=0; iptr.pp_double[ia+i]+ja; + double v = 0.0; + for(j=0; j> 2; + + for(i=0; i<=n-1; i++) + { + const __m256d* __restrict pRow = (const __m256d*)(a->ptr.pp_double[i+ia]+ja); + const double v = alpha*x[i]; + const __m256d vV = _mm256_set1_pd(v); + for(j=0; jptr.pp_double[i+ia][j+ja]; + } + } +} + +void rgemvx_transposed_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, double* __restrict y, + ae_state* _state) +{ + ae_int_t i; + ae_int_t j; + if( m<=3 ) { + for(i=0; iptr.pp_double[ia+i]+ja; + const double v = alpha*x[i]; + for(j=0; j>3); + for(i=0; iptr.pp_double[ia+i]+ja; + const double v = alpha*x[i]; + for(j=0; jptr.p_double+offss+blocksize*4; + double *p_simd_buf = simdbuf->ptr.p_double; + ae_int_t *p_rowidx = superrowidx->ptr.p_int+rbase; + if( blocksize==3 ) + { + double xx[4]; + xx[0] = x->ptr.p_double[cols0]; + xx[1] = x->ptr.p_double[cols0+1]; + xx[2] = x->ptr.p_double[cols0+2]; + xx[3] = 0; + x_simd = _mm256_loadu_pd(xx); + } + else + x_simd = _mm256_loadu_pd(x->ptr.p_double+cols0); + for(k=0; kptr.p_double+cols0); + double *p_mat_row = rowstorage->ptr.p_double+offss+2*2; + double *p_simd_buf = simdbuf->ptr.p_double; + ae_int_t *p_rowidx = superrowidx->ptr.p_int+rbase; + for(k=0; kptr.p_double; + double* __restrict diagd = _diagd->ptr.p_double; + const ae_int_t* __restrict raw2smap = _raw2smap->ptr.p_int; + const ae_int_t* __restrict superrowidx = _superrowidx->ptr.p_int; + ae_int_t k; + ae_int_t targetrow; + ae_int_t targetcol; + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + if( twidth<3||twidth>4 ) + { + return ae_false; + } + if( uwidth<1||uwidth>4 ) + { + return ae_false; + } + if( urank>4 ) + { + return ae_false; + } + + /* + * Shift input arrays to the beginning of the working area. + * Prepare SIMD masks + */ + __m256i v_rankmask = _mm256_cmpgt_epi64(_mm256_set_epi64x(urank, urank, urank, urank), _mm256_set_epi64x(3, 2, 1, 0)); + double *update_storage = rowstorage+offsu; + double *target_storage = rowstorage+offss; + superrowidx += urbase; + + /* + * Load head of the update matrix + */ + __m256d v_d0123 = _mm256_maskload_pd(diagd+offsd, v_rankmask); + __m256d u_0_0123 = _mm256_setzero_pd(); + __m256d u_1_0123 = _mm256_setzero_pd(); + __m256d u_2_0123 = _mm256_setzero_pd(); + __m256d u_3_0123 = _mm256_setzero_pd(); + for(k=0; k<=uwidth-1; k++) + { + targetcol = raw2smap[superrowidx[k]]; + if( targetcol==0 ) + u_0_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==1 ) + u_1_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==2 ) + u_2_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + if( targetcol==3 ) + u_3_0123 = _mm256_mul_pd(v_d0123, _mm256_maskload_pd(update_storage+k*urowstride, v_rankmask)); + } + + /* + * Transpose head + */ + __m256d u01_lo = _mm256_unpacklo_pd(u_0_0123,u_1_0123); + __m256d u01_hi = _mm256_unpackhi_pd(u_0_0123,u_1_0123); + __m256d u23_lo = _mm256_unpacklo_pd(u_2_0123,u_3_0123); + __m256d u23_hi = _mm256_unpackhi_pd(u_2_0123,u_3_0123); + __m256d u_0123_0 = _mm256_permute2f128_pd(u01_lo, u23_lo, 0x20); + __m256d u_0123_1 = _mm256_permute2f128_pd(u01_hi, u23_hi, 0x20); + __m256d u_0123_2 = _mm256_permute2f128_pd(u23_lo, u01_lo, 0x13); + __m256d u_0123_3 = _mm256_permute2f128_pd(u23_hi, u01_hi, 0x13); + + /* + * Run update + */ + if( urank==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+0), u_0123_0, + _mm256_load_pd(target_storage+targetrow))); + } + } + if( urank==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+1), u_0123_1, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+0), u_0123_0, + _mm256_load_pd(target_storage+targetrow)))); + } + } + if( urank==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+2), u_0123_2, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+1), u_0123_1, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+0), u_0123_0, + _mm256_load_pd(target_storage+targetrow))))); + } + } + if( urank==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = raw2smap[superrowidx[k]]*4; + double *update_row = rowstorage+offsu+k*urowstride; + _mm256_store_pd(target_storage+targetrow, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+3), u_0123_3, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+2), u_0123_2, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+1), u_0123_1, + _mm256_fnmadd_pd(_mm256_broadcast_sd(update_row+0), u_0123_0, + _mm256_load_pd(target_storage+targetrow)))))); + } + } + return ae_true; +} + +ae_bool spchol_updatekernel4444_fma( + double* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + const double* diagd, + ae_int_t offsd, + const ae_int_t* raw2smap, + const ae_int_t* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + ae_int_t offsk; + __m256d v_negd_u0, v_negd_u1, v_negd_u2, v_negd_u3, v_negd; + __m256d v_w0, v_w1, v_w2, v_w3, u01_lo, u01_hi, u23_lo, u23_hi; + + /* + * Compute W = -D*transpose(U[0:3]) + */ + v_negd = _mm256_mul_pd(_mm256_loadu_pd(diagd+offsd),_mm256_set1_pd(-1.0)); + v_negd_u0 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+0*4),v_negd); + v_negd_u1 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+1*4),v_negd); + v_negd_u2 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+2*4),v_negd); + v_negd_u3 = _mm256_mul_pd(_mm256_load_pd(rowstorage+offsu+3*4),v_negd); + u01_lo = _mm256_unpacklo_pd(v_negd_u0,v_negd_u1); + u01_hi = _mm256_unpackhi_pd(v_negd_u0,v_negd_u1); + u23_lo = _mm256_unpacklo_pd(v_negd_u2,v_negd_u3); + u23_hi = _mm256_unpackhi_pd(v_negd_u2,v_negd_u3); + v_w0 = _mm256_permute2f128_pd(u01_lo, u23_lo, 0x20); + v_w1 = _mm256_permute2f128_pd(u01_hi, u23_hi, 0x20); + v_w2 = _mm256_permute2f128_pd(u23_lo, u01_lo, 0x13); + v_w3 = _mm256_permute2f128_pd(u23_hi, u01_hi, 0x13); + + // + // Compute update S:= S + row_scatter(U*W) + // + if( sheight==uheight ) + { + /* + * No row scatter, the most efficient code + */ + for(k=0; k>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _kernels_fma_h +#define _kernels_fma_h + +#include "ap.h" + +#define AE_USE_CPP + + + +namespace alglib_impl +{ +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_AVX2_INTRINSICS) + +double rdotv_fma(const ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ const double* __restrict y, + const ae_state* __restrict _state); +double rdotv2_fma(const ae_int_t n, + /* Real */ const double* __restrict x, + const ae_state* __restrict _state); +void raddv_fma(const ae_int_t n, + const double alpha, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void raddvx_fma(const ae_int_t n, const double alpha, const double* __restrict y, double* __restrict x, ae_state *_state); +void rmuladdv_fma(const ae_int_t n, + const double* __restrict y, + const double* __restrict z, + double* __restrict x, + const ae_state* _state); +void rnegmuladdv_fma(const ae_int_t n, + const double* __restrict y, + const double* __restrict z, + double* __restrict x, + const ae_state* _state); +void rcopymuladdv_fma(const ae_int_t n, + const double* __restrict y, + const double* __restrict z, + const double* __restrict x, + double* __restrict r, + const ae_state* _state); +void rcopynegmuladdv_fma(const ae_int_t n, + const double* __restrict y, + const double* __restrict z, + const double* __restrict x, + double* __restrict r, + const ae_state* _state); +void rgemv_straight_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state); +void rgemv_transposed_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, + const double* __restrict x, double* __restrict y, ae_state* _state); +void rgemvx_straight_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, + double* __restrict y, ae_state* _state); +void rgemvx_transposed_fma(const ae_int_t m, const ae_int_t n, + const double alpha, const ae_matrix* __restrict a, const ae_int_t ia, + const ae_int_t ja, const double* __restrict x, double* __restrict y, + ae_state* _state); + +void ablasf_dotblkh_fma( + const double *src_a, + const double *src_b, + ae_int_t round_length, + ae_int_t block_size, + ae_int_t micro_size, + double *dst, + ae_int_t dst_stride); +void spchol_propagatefwd_fma(/* Real */ const ae_vector* x, + ae_int_t cols0, + ae_int_t blocksize, + /* Integer */ const ae_vector* superrowidx, + ae_int_t rbase, + ae_int_t offdiagsize, + /* Real */ const ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sstride, + /* Real */ ae_vector* simdbuf, + ae_int_t simdwidth, + ae_state *_state); +ae_bool spchol_updatekernelabc4_fma(ae_vector* _rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t urank, + ae_int_t urowstride, + ae_int_t uwidth, + const ae_vector* _diagd, + ae_int_t offsd, + const ae_vector* _raw2smap, + const ae_vector* _superrowidx, + ae_int_t urbase, + ae_state *_state); +ae_bool spchol_updatekernel4444_fma( + double* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + const double* diagd, + ae_int_t offsd, + const ae_int_t* raw2smap, + const ae_int_t* superrowidx, + ae_int_t urbase, + ae_state *_state); + + +/* ALGLIB_NO_FAST_KERNELS, _ALGLIB_HAS_AVX2_INTRINSICS */ +#endif + +} + +#endif + diff --git a/core/alglib/kernels_sse2.cpp b/core/alglib/kernels_sse2.cpp new file mode 100644 index 00000000..417aede1 --- /dev/null +++ b/core/alglib/kernels_sse2.cpp @@ -0,0 +1,735 @@ +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" + +// +// Must be defined before we include kernel header +// +#define _ALGLIB_IMPL_DEFINES +#define _ALGLIB_INTEGRITY_CHECKS_ONCE + +#include "kernels_sse2.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +namespace alglib_impl +{ + + + +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_SSE2_INTRINSICS) + +double rdotv_sse2(ae_int_t n, + /* Real */ const double* x, + /* Real */ const double* y, + ae_state *_state) +{ + ae_int_t i; + + const ae_int_t sse2len = n>>1; + const ae_int_t unrollLen = (sse2len>>3)<<3; + const __m128d* __restrict pX = (const __m128d*)(x); + const __m128d* __restrict pY = (const __m128d*)(y); + __m128d ans; + if(unrollLen >= 8) { + __m128d unroll0 = _mm_mul_pd(pX[0], pY[0]); + __m128d unroll1 = _mm_mul_pd(pX[1], pY[1]); + __m128d unroll2 = _mm_mul_pd(pX[2], pY[2]); + __m128d unroll3 = _mm_mul_pd(pX[3], pY[3]); + __m128d unroll4 = _mm_mul_pd(pX[4], pY[4]); + __m128d unroll5 = _mm_mul_pd(pX[5], pY[5]); + __m128d unroll6 = _mm_mul_pd(pX[6], pY[6]); + __m128d unroll7 = _mm_mul_pd(pX[7], pY[7]); + for(i=8; i>1; + const ae_int_t unrollLen = (sse2len>>3)<<3; + const __m128d* __restrict pX = (const __m128d*)(x); + __m128d ans; + if(unrollLen >= 8) { + __m128d unroll0 = _mm_mul_pd(pX[0], pX[0]); + __m128d unroll1 = _mm_mul_pd(pX[1], pX[1]); + __m128d unroll2 = _mm_mul_pd(pX[2], pX[2]); + __m128d unroll3 = _mm_mul_pd(pX[3], pX[3]); + __m128d unroll4 = _mm_mul_pd(pX[4], pX[4]); + __m128d unroll5 = _mm_mul_pd(pX[5], pX[5]); + __m128d unroll6 = _mm_mul_pd(pX[6], pX[6]); + __m128d unroll7 = _mm_mul_pd(pX[7], pX[7]); + for(i=8; i>1; + const ae_int_t tail = sse2len<<1; + const __m128d* __restrict pSrc = (const __m128d*)(x); + __m128d* __restrict pDest = (__m128d*)(y); + + for(i=0; i>1; + const __m128d* __restrict pSrc = (const __m128d*)(x); + __m128d* __restrict pDest = (__m128d*)(y); + const __m128d sse2v = _mm_set1_pd(v); + const ae_int_t tail = sse2len<<1; + for(i=0; i>4; + ae_int_t i; + for(i=0; i>4; + ae_int_t i; + for(i=0; i>1; + __m128d* __restrict pDest = (__m128d*)(x); + const __m128d sse2v = _mm_set1_pd(v); + for(i=0; i>4; + ae_int_t i; + for(i=0; i>4; + ae_int_t i; + for(i=0; i>1; + __m128d* __restrict pDest = (__m128d*)(x); + const __m128d sse2v = _mm_set1_pd(v); + for(i=0; i>1; + const __m128d* __restrict pSrc = (const __m128d*)(y); + __m128d* __restrict pDest = (__m128d*)(x); + const __m128d sse2alpha = _mm_set1_pd(alpha); + for(i=0; i>1)<<1; + const __m128d sse2alpha = _mm_set1_pd(alpha); + __m128d * __restrict pDest = (__m128d*)x; + for(i=0; i>1; + pDest[iDest] = _mm_add_pd(_mm_mul_pd(sse2alpha, _mm_loadu_pd(y+i)), pDest[iDest]); + } + if(n-vecLen) + x[i] += alpha*y[i]; +} + +void raddvx_sse2(const ae_int_t n, const double alpha, + const double* __restrict y, double* __restrict x, ae_state *_state) +{ + if( n<=4 ) + { + ae_int_t i; + for(i=0; i<=n-1; i++) + x[i] += alpha*y[i]; + return; + } + if((((ptrdiff_t)x) & 15) == 0) + { + raddvx_sse2_xaligned(n, alpha, y, x, _state); + return; + } + x[0] += alpha*y[0]; + raddvx_sse2_xaligned(n-1, alpha, y+1, x+1, _state); +} + +void rmergemulv_sse2(const ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state) +{ + ae_int_t i; + + const ae_int_t sse2len = n>>1; + const __m128d* __restrict pSrc = (const __m128d*)(y); + __m128d* __restrict pDest = (__m128d*)(x); + for(i=0; i>1; + const __m128d* __restrict pSrc = (const __m128d*)(y); + __m128d* __restrict pDest = (__m128d*)(x); + for(i=0; i>1; + const __m128d* __restrict pSrc = (const __m128d*)(y); + __m128d* __restrict pDest = (__m128d*)(x); + for(i=0; i>1; + const __m128d* __restrict pSrc = (const __m128d*)(x); + if( n<=4 ) + { + double result; + if(n == 0) + return 0.0; + result = x[0]; + for(i=1; i<=n-1; i++) + { + double v = x[i]; + if( v>result ) + result = v; + } + return result; + } + __m128d curMax = pSrc[0]; + for(i=1; i pComps[1]) ? pComps[0] : pComps[1]; + const ae_int_t tail = sse2len<<1; + if(n-tail) { + const double candidate = *(const double*)(pSrc+i); + return (candidate > dMax) ? candidate : dMax; + } + else { + return dMax; + } +} + +double rmaxabsv_sse2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state) +{ + const __m128d signMask = _mm_set1_pd(-0.); // -0. = 1 << 63 + const ae_int_t sse2len = n>>1; + const __m128d* __restrict pSrc = (const __m128d*)(x); + if( n<=4 ) + { + double result; + ae_int_t i; + result = 0; + for(i=0; i<=n-1; i++) + { + double v = fabs(x[i]); + if( v>result ) + result = v; + } + return result; + } + __m128d curMax = _mm_andnot_pd(signMask, pSrc[0]); // abs + ae_int_t i; + for(i=1; i pComps[1]) ? pComps[0] : pComps[1]; + const ae_int_t tail = sse2len<<1; + if(n-tail) { + const double candidate = ae_fabs(*(const double*)(pSrc+i), _state); + return (candidate > dMax) ? candidate : dMax; + } + else { + return dMax; + } +} + +static void rcopyvx_sse2_xaligned(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state) +{ + ae_int_t i; + + const ae_int_t vecLen = (n>>1)<<1; + const __m128d * __restrict pSrc = (const __m128d*)x; + for(i=0; i>1; + _mm_storeu_pd(y+i, pSrc[iSrc]); + } + if(n-vecLen) { + y[i] = x[i]; + } +} + +void rcopyvx_sse2(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state) +{ + if((((ptrdiff_t)x) & 15) == 0) + { + rcopyvx_sse2_xaligned(n, x, y, _state); + return; + } + y[0] = x[0]; + rcopyvx_sse2_xaligned(n-1, x+1, y+1, _state); +} + +static void icopyvx_sse2_xaligned(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state) +{ + const ae_int_t tail = (n*sizeof(ae_int_t)) & 15; + const ae_int_t even = (n*sizeof(ae_int_t)) - tail; + const __m128i* __restrict pSrc = (const __m128i*)x; + const ae_int_t nVec = even>>4; + const ae_int_t shift_by = 2-sizeof(ae_int_t)/8; + ae_int_t i; + for(i=0; i>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _kernels_sse2_h +#define _kernels_sse2_h + +#include "ap.h" + +#define AE_USE_CPP + + + +namespace alglib_impl +{ +#if !defined(ALGLIB_NO_FAST_KERNELS) && defined(_ALGLIB_HAS_SSE2_INTRINSICS) + +double rdotv_sse2(ae_int_t n, + /* Real */ const double* x, + /* Real */ const double* y, + ae_state *_state); +double rdotv2_sse2(ae_int_t n, + /* Real */ const double* x, + ae_state *_state); +void rcopyv_sse2(const ae_int_t n, + /* Real */ const double* __restrict x, + /* Real */ double* __restrict y, + ae_state* __restrict _state); +void rcopymulv_sse2(const ae_int_t n, + const double v, + /* Real */ const double* __restrict x, + /* Real */ double* __restrict y, + const ae_state* __restrict _state); +void icopyv_sse2(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state); +void bcopyv_sse2(const ae_int_t n, const ae_bool* __restrict x, + ae_bool* __restrict y, ae_state* __restrict _state); +void rsetv_sse2(const ae_int_t n, + const double v, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void rsetvx_sse2(const ae_int_t n, + const double v, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void isetv_sse2(const ae_int_t n, const ae_int_t v, + ae_int_t* __restrict x, ae_state* __restrict _state); +void bsetv_sse2(const ae_int_t n, const ae_bool v, ae_bool* __restrict x, + ae_state* __restrict _state); +void rmulv_sse2(const ae_int_t n, const double v, double* __restrict x, + const ae_state* __restrict _state); +void rmulvx_sse2(const ae_int_t n, const double v, double* __restrict x, + const ae_state* __restrict _state); +void raddv_sse2(const ae_int_t n, + const double alpha, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void raddvx_sse2(const ae_int_t n, const double alpha, + const double* __restrict y, double* __restrict x, ae_state *_state); +void rmergemulv_sse2(const ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + const ae_state* __restrict _state); +void rmergemaxv_sse2(const ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + ae_state* __restrict _state); +void rmergeminv_sse2(const ae_int_t n, + /* Real */ const double* __restrict y, + /* Real */ double* __restrict x, + ae_state* __restrict _state); +double rmaxv_sse2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state); +double rmaxabsv_sse2(ae_int_t n, /* Real */ const double* __restrict x, ae_state* __restrict _state); +void rcopyvx_sse2(const ae_int_t n, const double* __restrict x, + double* __restrict y, ae_state *_state); +void icopyvx_sse2(const ae_int_t n, const ae_int_t* __restrict x, + ae_int_t* __restrict y, ae_state* __restrict _state); +/* ALGLIB_NO_FAST_KERNELS, _ALGLIB_HAS_SSE2_INTRINSICS */ +#endif + +} + +#endif + diff --git a/core/alglib/linalg.cpp b/core/alglib/linalg.cpp index f970dc30..1c47e54c 100644 --- a/core/alglib/linalg.cpp +++ b/core/alglib/linalg.cpp @@ -1,33805 +1,66604 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "linalg.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Cache-oblivous complex "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixtranspose(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cache-oblivous real "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixtranspose(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This code enforces symmetricy of the matrix by copying Upper part to lower -one (or vice versa). - -INPUT PARAMETERS: - A - matrix - N - number of rows/columns - IsUpper - whether we want to copy upper triangle to lower one (True) - or vice versa (False). -*************************************************************************/ -void rmatrixenforcesymmetricity(const real_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixenforcesymmetricity(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixcopy(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixcopy(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(b.c_ptr()), ib, jb, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_1d_array &u, const ae_int_t iu, complex_1d_array &v, const ae_int_t iv) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrank1(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(u.c_ptr()), iu, const_cast(v.c_ptr()), iv, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_1d_array &u, const ae_int_t iu, real_1d_array &v, const ae_int_t iv) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrank1(m, n, const_cast(a.c_ptr()), ia, ja, const_cast(u.c_ptr()), iu, const_cast(v.c_ptr()), iv, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - M>=0 - N - number of columns of op(A) - N>=0 - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - * OpA=2 => op(A) = A^H - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixmv(m, n, const_cast(a.c_ptr()), ia, ja, opa, const_cast(x.c_ptr()), ix, const_cast(y.c_ptr()), iy, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - N - number of columns of op(A) - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixmv(m, n, const_cast(a.c_ptr()), ia, ja, opa, const_cast(x.c_ptr()), ix, const_cast(y.c_ptr()), iy, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_cmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_cmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rmatrixrighttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rmatrixlefttrsm(m, n, const_cast(a.c_ptr()), i1, j1, isupper, isunit, optype, const_cast(x.c_ptr()), i2, j2, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_cmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rmatrixsyrk(n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, beta, const_cast(c.c_ptr()), ic, jc, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixgemm(m, n, k, *alpha.c_ptr(), const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, *beta.c_ptr(), const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_cmatrixgemm(m, n, k, *alpha.c_ptr(), const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, *beta.c_ptr(), const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixgemm(m, n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, beta, const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rmatrixgemm(m, n, k, alpha, const_cast(a.c_ptr()), ia, ja, optypea, const_cast(b.c_ptr()), ib, jb, optypeb, beta, const_cast(c.c_ptr()), ic, jc, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -QR decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form (see below). - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. - -The elements of matrix R are located on and above the main diagonal of -matrix A. The elements which are located in Tau array and below the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(k-1), - -where k = min(m,n), and each H(i) is in the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, -so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -LQ decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices L and Q in compact form (see below) - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0..Min(M,N)-1]. - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. - -The elements of matrix L are located on and below the main diagonal of -matrix A. The elements which are located in Tau array and above the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(k-1)*H(k-2)*...*H(1)*H(0), - -where k = min(m,n), and each H(i) is of the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, -v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -QR decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixqr(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -LQ decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and L in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Partial unpacking of matrix Q from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixQR subroutine. - QColumns - required number of columns of matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose indexes range within [0..M-1, 0..QColumns-1]. - If QColumns=0, the array remains unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixqrunpackr(const_cast(a.c_ptr()), m, n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Partial unpacking of matrix Q from the LQ decomposition of a matrix A - -Input parameters: - A - matrices L and Q in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixLQ subroutine. - QRows - required number of rows in matrix Q. N>=QRows>=0. - -Output parameters: - Q - first QRows rows of matrix Q. Array whose indexes range - within [0..QRows-1, 0..N-1]. If QRows=0, the array remains - unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlqunpackl(const_cast(a.c_ptr()), m, n, const_cast(l.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Partial unpacking of matrix Q from QR decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixQR subroutine . - QColumns - required number of columns in matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose index ranges within [0..M-1, 0..QColumns-1]. - If QColumns=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixqrunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixqrunpackr(const_cast(a.c_ptr()), m, n, const_cast(r.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixLQ subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixLQ subroutine . - QRows - required number of rows in matrix Q. N>=QColumns>=0. - -Output parameters: - Q - first QRows rows of matrix Q. - Array whose index ranges within [0..QRows-1, 0..N-1]. - If QRows=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlqunpackq(const_cast(a.c_ptr()), m, n, const_cast(tau.c_ptr()), qrows, const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of CMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlqunpackl(const_cast(a.c_ptr()), m, n, const_cast(l.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Reduction of a rectangular matrix to bidiagonal form - -The algorithm reduces the rectangular matrix A to bidiagonal form by -orthogonal transformations P and Q: A = Q*B*P. - -Input parameters: - A - source matrix. array[0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q, B, P in compact form (see below). - TauQ - scalar factors which are used to form matrix Q. - TauP - scalar factors which are used to form matrix P. - -The main diagonal and one of the secondary diagonals of matrix A are -replaced with bidiagonal matrix B. Other elements contain elementary -reflections which form MxM matrix Q and NxN matrix P, respectively. - -If M>=N, B is the upper bidiagonal MxN matrix and is stored in the -corresponding elements of matrix A. Matrix Q is represented as a -product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where -H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and -vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is -stored in elements A(i+1:m-1,i). Matrix P is as follows: P = -G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], -u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). - -If M n): m=5, n=6 (m < n): - -( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) -( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) -( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) -( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) -( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) -( v1 v2 v3 v4 v5 ) - -Here vi and ui are vectors which form H(i) and G(i), and d and e - -are the diagonal and off-diagonal elements of matrix B. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbd(const_cast(a.c_ptr()), m, n, const_cast(tauq.c_ptr()), const_cast(taup.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix Q which reduces a matrix to bidiagonal form. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - QColumns - required number of columns in matrix Q. - M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array[0..M-1, 0..QColumns-1] - If QColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbdunpackq(const_cast(qp.c_ptr()), m, n, const_cast(tauq.c_ptr()), qcolumns, const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication by matrix Q which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by Q or Q'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - Z - multiplied matrix. - array[0..ZRows-1,0..ZColumns-1] - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=M, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=M, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by Q or Q'. - -Output parameters: - Z - product of Z and Q. - Array[0..ZRows-1,0..ZColumns-1] - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbdmultiplybyq(const_cast(qp.c_ptr()), m, n, const_cast(tauq.c_ptr()), const_cast(z.c_ptr()), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix P which reduces matrix A to bidiagonal form. -The subroutine returns transposed matrix P. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of ToBidiagonal subroutine. - PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. - -Output parameters: - PT - first PTRows columns of matrix P^T - Array[0..PTRows-1, 0..N-1] - If PTRows=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbdunpackpt(const_cast(qp.c_ptr()), m, n, const_cast(taup.c_ptr()), ptrows, const_cast(pt.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication by matrix P which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by P or P'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of RMatrixBD subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of RMatrixBD subroutine. - Z - multiplied matrix. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=N, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=N, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by P or P'. - -Output parameters: - Z - product of Z and P. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbdmultiplybyp(const_cast(qp.c_ptr()), m, n, const_cast(taup.c_ptr()), const_cast(z.c_ptr()), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking of the main and secondary diagonals of bidiagonal decomposition -of matrix A. - -Input parameters: - B - output of RMatrixBD subroutine. - M - number of rows in matrix B. - N - number of columns in matrix B. - -Output parameters: - IsUpper - True, if the matrix is upper bidiagonal. - otherwise IsUpper is False. - D - the main diagonal. - Array whose index ranges within [0..Min(M,N)-1]. - E - the secondary diagonal (upper or lower, depending on - the value of IsUpper). - Array index ranges within [0..Min(M,N)-1], the last - element is not used. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixbdunpackdiagonals(const_cast(b.c_ptr()), m, n, &isupper, const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, -where Q is an orthogonal matrix, H - Hessenberg matrix. - -Input parameters: - A - matrix A with elements [0..N-1, 0..N-1] - N - size of matrix A. - -Output parameters: - A - matrices Q and P in compact form (see below). - Tau - array of scalar factors which are used to form matrix Q. - Array whose index ranges within [0..N-2] - -Matrix H is located on the main diagonal, on the lower secondary diagonal -and above the main diagonal of matrix A. The elements which are used to -form matrix Q are situated in array Tau and below the lower secondary -diagonal of matrix A as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(n-2), - -where each H(i) is given by - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - is a real vector, -so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixhessenberg(const_cast(a.c_ptr()), n, const_cast(tau.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix Q which reduces matrix A to upper Hessenberg form - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - Tau - scalar factors which are used to form Q. - Output of RMatrixHessenberg subroutine. - -Output parameters: - Q - matrix Q. - Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixhessenbergunpackq(const_cast(a.c_ptr()), n, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - -Output parameters: - H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixhessenbergunpackh(const_cast(a.c_ptr()), n, const_cast(h.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Reduction of a symmetric matrix which is given by its higher or lower -triangular part to a tridiagonal matrix using orthogonal similarity -transformation: Q'*A*Q=T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - - where d and e denote diagonal and off-diagonal elements of T, and vi - denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::smatrixtd(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix Q which reduces symmetric matrix to a tridiagonal -form. - -Input parameters: - A - the result of a SMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of SMatrixTD subroutine) - Tau - the result of a SMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::smatrixtdunpackq(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Reduction of a Hermitian matrix which is given by its higher or lower -triangular part to a real tridiagonal matrix using unitary similarity -transformation: Q'*A*Q = T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of real symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of real symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - -where d and e denote diagonal and off-diagonal elements of T, and vi -denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hmatrixtd(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(d.c_ptr()), const_cast(e.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal -form. - -Input parameters: - A - the result of a HMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of HMatrixTD subroutine) - Tau - the result of a HMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hmatrixtdunpackq(const_cast(a.c_ptr()), n, isupper, const_cast(tau.c_ptr()), const_cast(q.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Singular value decomposition of a bidiagonal matrix (extended algorithm) - -The algorithm performs the singular value decomposition of a bidiagonal -matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - -orthogonal matrices, S - diagonal matrix with non-negative elements on the -main diagonal, in descending order. - -The algorithm finds singular values. In addition, the algorithm can -calculate matrices Q and P (more precisely, not the matrices, but their -product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, -matrices U and VT can be of any type, including identity. Furthermore, the -algorithm can calculate Q'*C (this product is calculated more effectively -than U*Q, because this calculation operates with rows instead of matrix -columns). - -The feature of the algorithm is its ability to find all singular values -including those which are arbitrarily close to 0 with relative accuracy -close to machine precision. If the parameter IsFractionalAccuracyRequired -is set to True, all singular values will have high relative accuracy close -to machine precision. If the parameter is set to False, only the biggest -singular value will have relative accuracy close to machine precision. -The absolute error of other singular values is equal to the absolute error -of the biggest singular value. - -Input parameters: - D - main diagonal of matrix B. - Array whose index ranges within [0..N-1]. - E - superdiagonal (or subdiagonal) of matrix B. - Array whose index ranges within [0..N-2]. - N - size of matrix B. - IsUpper - True, if the matrix is upper bidiagonal. - IsFractionalAccuracyRequired - - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 - SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. - U - matrix to be multiplied by Q. - Array whose indexes range within [0..NRU-1, 0..N-1]. - The matrix can be bigger, in that case only the submatrix - [0..NRU-1, 0..N-1] will be multiplied by Q. - NRU - number of rows in matrix U. - C - matrix to be multiplied by Q'. - Array whose indexes range within [0..N-1, 0..NCC-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCC-1] will be multiplied by Q'. - NCC - number of columns in matrix C. - VT - matrix to be multiplied by P^T. - Array whose indexes range within [0..N-1, 0..NCVT-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCVT-1] will be multiplied by P^T. - NCVT - number of columns in matrix VT. - -Output parameters: - D - singular values of matrix B in descending order. - U - if NRU>0, contains matrix U*Q. - VT - if NCVT>0, contains matrix (P^T)*VT. - C - if NCC>0, contains matrix Q'*C. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Additional information: - The type of convergence is controlled by the internal parameter TOL. - If the parameter is greater than 0, the singular values will have - relative accuracy TOL. If TOL<0, the singular values will have - absolute accuracy ABS(TOL)*norm(B). - By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, - where Epsilon is the machine precision. It is not recommended to use - TOL less than 10*Epsilon since this will considerably slow down the - algorithm and may not lead to error decreasing. -History: - * 31 March, 2007. - changed MAXITR from 6 to 12. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1999. -*************************************************************************/ -bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::rmatrixbdsvd(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, isupper, isfractionalaccuracyrequired, const_cast(u.c_ptr()), nru, const_cast(c.c_ptr()), ncc, const_cast(vt.c_ptr()), ncvt, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Singular value decomposition of a rectangular matrix. - -The algorithm calculates the singular value decomposition of a matrix of -size MxN: A = U * S * V^T - -The algorithm finds the singular values and, optionally, matrices U and V^T. -The algorithm can find both first min(M,N) columns of matrix U and rows of -matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM -and NxN respectively). - -Take into account that the subroutine does not return matrix V but V^T. - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - UNeeded - 0, 1 or 2. See the description of the parameter U. - VTNeeded - 0, 1 or 2. See the description of the parameter VT. - AdditionalMemory - - If the parameter: - * equals 0, the algorithm doesn’t use additional - memory (lower requirements, lower performance). - * equals 1, the algorithm uses additional - memory of size min(M,N)*min(M,N) of real numbers. - It often speeds up the algorithm. - * equals 2, the algorithm uses additional - memory of size M*min(M,N) of real numbers. - It allows to get a maximum performance. - The recommended value of the parameter is 2. - -Output parameters: - W - contains singular values in descending order. - U - if UNeeded=0, U isn't changed, the left singular vectors - are not calculated. - if Uneeded=1, U contains left singular vectors (first - min(M,N) columns of matrix U). Array whose indexes range - within [0..M-1, 0..Min(M,N)-1]. - if UNeeded=2, U contains matrix U wholly. Array whose - indexes range within [0..M-1, 0..M-1]. - VT - if VTNeeded=0, VT isn’t changed, the right singular vectors - are not calculated. - if VTNeeded=1, VT contains right singular vectors (first - min(M,N) rows of matrix V^T). Array whose indexes range - within [0..min(M,N)-1, 0..N-1]. - if VTNeeded=2, VT contains matrix V^T wholly. Array whose - indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::rmatrixsvd(const_cast(a.c_ptr()), m, n, uneeded, vtneeded, additionalmemory, const_cast(w.c_ptr()), const_cast(u.c_ptr()), const_cast(vt.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a symmetric matrix - -The algorithm finds eigen pairs of a symmetric matrix by reducing it to -tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpper - storage format. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixevd(const_cast(a.c_ptr()), n, zneeded, isupper, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric -matrix in a given half open interval (A, B] by using a bisection and -inverse iteration - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half open interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval (M>=0). - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, - M is equal to 0. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixevdr(const_cast(a.c_ptr()), n, zneeded, isupper, b1, b2, &m, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a symmetric -matrix with given indexes by using bisection and inverse iteration methods. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixevdi(const_cast(a.c_ptr()), n, zneeded, isupper, i1, i2, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a Hermitian matrix - -The algorithm finds eigen pairs of a Hermitian matrix by reducing it to -real tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Note: - eigenvectors of Hermitian matrix are defined up to multiplication by - a complex number L, such that |L|=1. - - -- ALGLIB -- - Copyright 2005, 23 March 2007 by Bochkanov Sergey -*************************************************************************/ -bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::hmatrixevd(const_cast(a.c_ptr()), n, zneeded, isupper, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian -matrix in a given half-interval (A, B] by using a bisection and inverse -iteration - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. Array whose indexes range within - [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half-interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval, M>=0 - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, M is - equal to 0. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::hmatrixevdr(const_cast(a.c_ptr()), n, zneeded, isupper, b1, b2, &m, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a Hermitian -matrix with given indexes by using bisection and inverse iteration methods - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix - columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::hmatrixevdi(const_cast(a.c_ptr()), n, zneeded, isupper, i1, i2, const_cast(w.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix - -The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by -using an QL/QR algorithm with implicit shifts. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix - are multiplied by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity - transformation of a symmetric matrix; - * 2, the eigenvectors of a tridiagonal matrix replace the - square matrix Z; - * 3, matrix Z contains the first row of the eigenvectors - matrix. - Z - if ZNeeded=1, Z contains the square matrix by which the - eigenvectors are multiplied. - Array whose indexes range within [0..N-1, 0..N-1]. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the product of a given matrix (from the left) - and the eigenvectors matrix (from the right); - * 2, Z contains the eigenvectors. - * 3, Z contains the first row of the eigenvectors matrix. - If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. - In that case, the eigenvectors are stored in the matrix columns. - If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixtdevd(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a -given half-interval (A, B] by using bisection and inverse iteration. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix, N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the tridiagonal - matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. - A, B - half-interval (A, B] to search eigenvalues in. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range - within [0..N-1, 0..N-1]) which reduces the given symmetric - matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - M - number of eigenvalues found in the given half-interval (M>=0). - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the - left) and NxM matrix of the eigenvectors found (from the - right). Array whose indexes range within [0..N-1, 0..M-1]. - * 2, contains the matrix of the eigenvectors found. - Array whose indexes range within [0..N-1, 0..M-1]. - -Result: - - True, if successful. In that case, M contains the number of eigenvalues - in the given half-interval (could be equal to 0), D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. In that case, - the eigenvalues and eigenvectors are not returned, M is equal to 0. - - -- ALGLIB -- - Copyright 31.03.2008 by Bochkanov Sergey -*************************************************************************/ -bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixtdevdr(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, a, b, &m, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine for finding tridiagonal matrix eigenvalues/vectors with given -indexes (in ascending order) by using the bisection and inverse iteraion. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix. N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace - matrix Z. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) - which reduces the given symmetric matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the left) and - Nx(I2-I1) matrix of the eigenvectors found (from the right). - Array whose indexes range within [0..N-1, 0..I2-I1]. - * 2, contains the matrix of the eigenvalues found. - Array whose indexes range within [0..N-1, 0..I2-I1]. - - -Result: - - True, if successful. In that case, D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the eigenvalues - in the given interval or if the inverse iteration subroutine wasn't able - to find all the corresponding eigenvectors. In that case, the eigenvalues - and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 25.12.2005 by Bochkanov Sergey -*************************************************************************/ -bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixtdevdi(const_cast(d.c_ptr()), const_cast(e.c_ptr()), n, zneeded, i1, i2, const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Finding eigenvalues and eigenvectors of a general matrix - -The algorithm finds eigenvalues and eigenvectors of a general matrix by -using the QR algorithm with multiple shifts. The algorithm can find -eigenvalues and both left and right eigenvectors. - -The right eigenvector is a vector x such that A*x = w*x, and the left -eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex -conjugate transposition of vector y). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - VNeeded - flag controlling whether eigenvectors are needed or not. - If VNeeded is equal to: - * 0, eigenvectors are not returned; - * 1, right eigenvectors are returned; - * 2, left eigenvectors are returned; - * 3, both left and right eigenvectors are returned. - -Output parameters: - WR - real parts of eigenvalues. - Array whose index ranges within [0..N-1]. - WR - imaginary parts of eigenvalues. - Array whose index ranges within [0..N-1]. - VL, VR - arrays of left and right eigenvectors (if they are needed). - If WI[i]=0, the respective eigenvalue is a real number, - and it corresponds to the column number I of matrices VL/VR. - If WI[i]>0, we have a pair of complex conjugate numbers with - positive and negative imaginary parts: - the first eigenvalue WR[i] + sqrt(-1)*WI[i]; - the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; - WI[i]>0 - WI[i+1] = -WI[i] < 0 - In that case, the eigenvector corresponding to the first - eigenvalue is located in i and i+1 columns of matrices - VL/VR (the column number i contains the real part, and the - column number i+1 contains the imaginary part), and the vector - corresponding to the second eigenvalue is a complex conjugate to - the first vector. - Arrays whose indexes range within [0..N-1, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm has not converged. - -Note 1: - Some users may ask the following question: what if WI[N-1]>0? - WI[N] must contain an eigenvalue which is complex conjugate to the - N-th eigenvalue, but the array has only size N? - The answer is as follows: such a situation cannot occur because the - algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is - strictly less than N-1. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms of linear algebra). If you require maximum performance - on your machine, it is recommended to adjust this parameter manually. - - -See also the InternalTREVC subroutine. - -The algorithm is based on the LAPACK 3.0 library. -*************************************************************************/ -bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::rmatrixevd(const_cast(a.c_ptr()), n, vneeded, const_cast(wr.c_ptr()), const_cast(wi.c_ptr()), const_cast(vl.c_ptr()), const_cast(vr.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of a random uniformly distributed (Haar) orthogonal matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrndorthogonal(n, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN matrix with given condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of a random Haar distributed orthogonal complex matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrndorthogonal(n, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN complex matrix with given condition number C and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN symmetric matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::smatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN symmetric positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random SPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN Hermitian matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Generation of random NxN Hermitian positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random HPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixrndcond(n, c, const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrndorthogonalfromtheright(const_cast(a.c_ptr()), m, n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixrndorthogonalfromtheleft(const_cast(a.c_ptr()), m, n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication of MxN complex matrix by NxN random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrndorthogonalfromtheright(const_cast(a.c_ptr()), m, n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Multiplication of MxN complex matrix by MxM random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixrndorthogonalfromtheleft(const_cast(a.c_ptr()), m, n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Symmetric multiplication of NxN matrix by random Haar distributed -orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q'*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndmultiply(real_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::smatrixrndmultiply(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Hermitian multiplication of NxN matrix by random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q^H*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hmatrixrndmultiply(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -LU decomposition of a general real matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. -It is optimized for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -LU decomposition of a general complex matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. It is optimized -for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlu(const_cast(a.c_ptr()), m, n, const_cast(pivots.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a Hermitian positive- -definite matrix. The result of an algorithm is a representation of A as -A=U'*U or A=L*L' (here X' detones conj(X^T)). - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U'*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::hpdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a symmetric positive- -definite matrix. The result of an algorithm is a representation of A as -A=U^T*U or A=L*L^T - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U^T*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::spdmatrixcholesky(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcond1(const real_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixrcond1(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixrcondinf(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - symmetric positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixtrrcond1(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixtrrcondinf(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - Hermitian positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hpdmatrixrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixrcond1(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixrcondinf(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixlurcond1(const_cast(lua.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixlurcondinf(const_cast(lua.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixcholeskyrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hpdmatrixcholeskyrcond(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixlurcond1(const_cast(lua.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixlurcondinf(const_cast(lua.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixtrrcond1(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cmatrixtrrcondinf(const_cast(a.c_ptr()), n, isupper, isunit, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Matrix inverse report: -* R1 reciprocal of condition number in 1-norm -* RInf reciprocal of condition number in inf-norm -*************************************************************************/ -_matinvreport_owner::_matinvreport_owner() -{ - p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_matinvreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_matinvreport_owner::_matinvreport_owner(const _matinvreport_owner &rhs) -{ - p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_matinvreport_owner& _matinvreport_owner::operator=(const _matinvreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_matinvreport_clear(p_struct); - if( !alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_matinvreport_owner::~_matinvreport_owner() -{ - alglib_impl::_matinvreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::matinvreport* _matinvreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::matinvreport* _matinvreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -matinvreport::matinvreport() : _matinvreport_owner() ,r1(p_struct->r1),rinf(p_struct->rinf) -{ -} - -matinvreport::matinvreport(const matinvreport &rhs):_matinvreport_owner(rhs) ,r1(p_struct->r1),rinf(p_struct->rinf) -{ -} - -matinvreport& matinvreport::operator=(const matinvreport &rhs) -{ - if( this==&rhs ) - return *this; - _matinvreport_owner::operator=(rhs); - return *this; -} - -matinvreport::~matinvreport() -{ -} - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of RMatrixLU subroutine). - Pivots - table of permutations - (the output of RMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code: - * -3 A is singular, or VERY close to singular. - it is filled by zeros in such cases. - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - A - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of RMatrixLU subroutine). - Pivots - table of permutations - (the output of RMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code: - * -3 A is singular, or VERY close to singular. - it is filled by zeros in such cases. - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - A - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) - throw ap_error("Error while calling 'rmatrixluinverse': looks like one of arguments has wrong size"); - n = a.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - -Result: - True, if the matrix is not singular. - False, if the matrix is singular. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - -Result: - True, if the matrix is not singular. - False, if the matrix is singular. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'rmatrixinverse': looks like one of arguments has wrong size"); - n = a.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of CMatrixLU subroutine). - Pivots - table of permutations - (the output of CMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of CMatrixLU subroutine). - Pivots - table of permutations - (the output of CMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) - throw ap_error("Error while calling 'cmatrixluinverse': looks like one of arguments has wrong size"); - n = a.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixluinverse(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'cmatrixinverse': looks like one of arguments has wrong size"); - n = a.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixinverse(const_cast(a.c_ptr()), n, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a symmetric positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of SPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a symmetric positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of SPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isupper; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'spdmatrixcholeskyinverse': looks like one of arguments has wrong size"); - n = a.cols(); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a symmetric positive definite matrix. - -Given an upper or lower triangle of a symmetric positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a symmetric positive definite matrix. - -Given an upper or lower triangle of a symmetric positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isupper; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'spdmatrixinverse': looks like one of arguments has wrong size"); - if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) - throw ap_error("'a' parameter is not symmetric matrix"); - n = a.cols(); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - if( !alglib_impl::ae_force_symmetric(const_cast(a.c_ptr())) ) - throw ap_error("Internal error while forcing symmetricity of 'a' parameter"); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a Hermitian positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of HPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a Hermitian positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of HPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isupper; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'hpdmatrixcholeskyinverse': looks like one of arguments has wrong size"); - n = a.cols(); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixcholeskyinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a Hermitian positive definite matrix. - -Given an upper or lower triangle of a Hermitian positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inversion of a Hermitian positive definite matrix. - -Given an upper or lower triangle of a Hermitian positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isupper; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'hpdmatrixinverse': looks like one of arguments has wrong size"); - if( !alglib_impl::ae_is_hermitian(const_cast(a.c_ptr())) ) - throw ap_error("'a' parameter is not Hermitian matrix"); - n = a.cols(); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixinverse(const_cast(a.c_ptr()), n, isupper, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - if( !alglib_impl::ae_force_hermitian(const_cast(a.c_ptr())) ) - throw ap_error("Internal error while forcing Hermitian properties of 'a' parameter"); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix inverse (real) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix inverse (real) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isunit; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'rmatrixtrinverse': looks like one of arguments has wrong size"); - n = a.cols(); - isunit = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix inverse (complex) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Triangular matrix inverse (complex) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isunit; - if( (a.cols()!=a.rows())) - throw ap_error("Error while calling 'cmatrixtrinverse': looks like one of arguments has wrong size"); - n = a.cols(); - isunit = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixtrinverse(const_cast(a.c_ptr()), n, isupper, isunit, &info, const_cast(rep.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Sparse matrix - -You should use ALGLIB functions to work with sparse matrix. -Never try to access its fields directly! -*************************************************************************/ -_sparsematrix_owner::_sparsematrix_owner() -{ - p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_sparsematrix_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_sparsematrix_owner::_sparsematrix_owner(const _sparsematrix_owner &rhs) -{ - p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_sparsematrix_owner& _sparsematrix_owner::operator=(const _sparsematrix_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_sparsematrix_clear(p_struct); - if( !alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_sparsematrix_owner::~_sparsematrix_owner() -{ - alglib_impl::_sparsematrix_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() const -{ - return const_cast(p_struct); -} -sparsematrix::sparsematrix() : _sparsematrix_owner() -{ -} - -sparsematrix::sparsematrix(const sparsematrix &rhs):_sparsematrix_owner(rhs) -{ -} - -sparsematrix& sparsematrix::operator=(const sparsematrix &rhs) -{ - if( this==&rhs ) - return *this; - _sparsematrix_owner::operator=(rhs); - return *this; -} - -sparsematrix::~sparsematrix() -{ -} - -/************************************************************************* -This function creates sparse matrix in a Hash-Table format. - -This function creates Hast-Table matrix, which can be converted to CRS -format after its initialization is over. Typical usage scenario for a -sparse matrix is: -1. creation in a Hash-Table format -2. insertion of the matrix elements -3. conversion to the CRS representation -4. matrix is passed to some linear algebra algorithm - -Some information about different matrix formats can be found below, in -the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - K - K>=0, expected number of non-zero elements in a matrix. - K can be inexact approximation, can be less than actual - number of elements (table will grow when needed) or - even zero). - It is important to understand that although hash-table - may grow automatically, it is better to provide good - estimate of data size. - -OUTPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - All elements of the matrix are zero. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecreate(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function creates sparse matrix in a Hash-Table format. - -This function creates Hast-Table matrix, which can be converted to CRS -format after its initialization is over. Typical usage scenario for a -sparse matrix is: -1. creation in a Hash-Table format -2. insertion of the matrix elements -3. conversion to the CRS representation -4. matrix is passed to some linear algebra algorithm - -Some information about different matrix formats can be found below, in -the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - K - K>=0, expected number of non-zero elements in a matrix. - K can be inexact approximation, can be less than actual - number of elements (table will grow when needed) or - even zero). - It is important to understand that although hash-table - may grow automatically, it is better to provide good - estimate of data size. - -OUTPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - All elements of the matrix are zero. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t k; - - k = 0; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecreate(m, n, k, const_cast(s.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function creates sparse matrix in a CRS format (expert function for -situations when you are running out of memory). - -This function creates CRS matrix. Typical usage scenario for a CRS matrix -is: -1. creation (you have to tell number of non-zero elements at each row at - this moment) -2. insertion of the matrix elements (row by row, from left to right) -3. matrix is passed to some linear algebra algorithm - -This function is a memory-efficient alternative to SparseCreate(), but it -is more complex because it requires you to know in advance how large your -matrix is. Some information about different matrix formats can be found -below, in the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - NER - number of elements at each row, array[M], NER[I]>=0 - -OUTPUT PARAMETERS - S - sparse M*N matrix in CRS representation. - You have to fill ALL non-zero elements by calling - SparseSet() BEFORE you try to use this matrix. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecreatecrs(m, n, const_cast(ner.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function copies S0 to S1. - -NOTE: this function does not verify its arguments, it just copies all -fields of the structure. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecopy(const sparsematrix &s0, sparsematrix &s1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecopy(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function adds value to S[i,j] - element of the sparse matrix. Matrix -must be in a Hash-Table mode. - -In case S[i,j] already exists in the table, V i added to its value. In -case S[i,j] is non-existent, it is inserted in the table. Table -automatically grows when necessary. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function modifies S[i,j] - element of the sparse matrix. - -For Hash-based storage format: -* new value can be zero or non-zero. In case new value of S[i,j] is zero, - this element is deleted from the table. -* this function has no effect when called with zero V for non-existent - element. - -For CRS-bases storage format: -* new value MUST be non-zero. Exception will be thrown for zero V. -* elements must be initialized in correct order - from top row to bottom, - within row - from left to right. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns S[i,j] - element of the sparse matrix. Matrix can -be in any mode (Hash-Table or CRS), but this function is less efficient -for CRS matrices. Hash-Table matrices can find element in O(1) time, -while CRS matrices need O(log(RS)) time, where RS is an number of non- -zero elements in a row. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - row index of the element to modify, 0<=I(s.c_ptr()), i, j, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns I-th diagonal element of the sparse matrix. - -Matrix can be in any mode (Hash-Table or CRS storage), but this function -is most efficient for CRS matrices - it requires less than 50 CPU cycles -to extract diagonal element. For Hash-Table matrices we still have O(1) -query time, but function is many times slower. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - index of the element to modify, 0<=I(s.c_ptr()), i, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function converts matrix to CRS format. - -Some algorithms (linear algebra ones, for example) require matrices in -CRS format. - -INPUT PARAMETERS - S - sparse M*N matrix in any format - -OUTPUT PARAMETERS - S - matrix in CRS format - -NOTE: this function has no effect when called with matrix which is -already in CRS mode. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparseconverttocrs(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparseconverttocrs(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-vector product S*x. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[M], S*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemv(const sparsematrix &s, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemv(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-vector product S^T*x. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[M], input vector. For performance reasons we - make only quick checks - we check that array size is - at least M, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[N], S^T*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemtv(const sparsematrix &s, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemtv(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function simultaneously calculates two matrix-vector products: - S*x and S^T*x. -S must be square (non-rectangular) matrix stored in CRS format (exception -will be thrown otherwise). - -INPUT PARAMETERS - S - sparse N*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y0 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - Y1 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y0 - array[N], S*x - Y1 - array[N], S^T*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. It also throws exception when S is non-square. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemv2(const sparsematrix &s, const real_1d_array &x, real_1d_array &y0, real_1d_array &y1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemv2(const_cast(s.c_ptr()), const_cast(x.c_ptr()), const_cast(y0.c_ptr()), const_cast(y1.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-vector product S*x, when S is symmetric -matrix. Matrix S must be stored in CRS format (exception will be -thrown otherwise). - -INPUT PARAMETERS - S - sparse M*M matrix in CRS format (you MUST convert it - to CRS before calling this function). - IsUpper - whether upper or lower triangle of S is given: - * if upper triangle is given, only S[i,j] for j>=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[M], S*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsesmv(const_cast(s.c_ptr()), isupper, const_cast(x.c_ptr()), const_cast(y.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-matrix product S*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size - is at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemm(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-matrix product S^T*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[M][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least M, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemtm(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function simultaneously calculates two matrix-matrix products: - S*A and S^T*A. -S must be square (non-rectangular) matrix stored in CRS format (exception -will be thrown otherwise). - -INPUT PARAMETERS - S - sparse N*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B0 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - B1 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B0 - array[N][K], S*A - B1 - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. It also throws exception when S is non-square. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsemm2(const_cast(s.c_ptr()), const_cast(a.c_ptr()), k, const_cast(b0.c_ptr()), const_cast(b1.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function calculates matrix-matrix product S*A, when S is symmetric -matrix. Matrix S must be stored in CRS format (exception will be -thrown otherwise). - -INPUT PARAMETERS - S - sparse M*M matrix in CRS format (you MUST convert it - to CRS before calling this function). - IsUpper - whether upper or lower triangle of S is given: - * if upper triangle is given, only S[i,j] for j>=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsesmm(const_cast(s.c_ptr()), isupper, const_cast(a.c_ptr()), k, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This procedure resizes Hash-Table matrix. It can be called when you have -deleted too many elements from the matrix, and you want to free unneeded -memory. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparseresizematrix(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparseresizematrix(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to enumerate all elements of the sparse matrix. -Before first call user initializes T0 and T1 counters by zero. These -counters are used to remember current position in a matrix; after each -call they are updated by the function. - -Subsequent calls to this function return non-zero elements of the sparse -matrix, one by one. If you enumerate CRS matrix, matrix is traversed from -left to right, from top to bottom. In case you enumerate matrix stored as -Hash table, elements are returned in random order. - -EXAMPLE - > T0=0 - > T1=0 - > while SparseEnumerate(S,T0,T1,I,J,V) do - > ....do something with I,J,V - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - T0 - internal counter - T1 - internal counter - -OUTPUT PARAMETERS - T0 - new value of the internal counter - T1 - new value of the internal counter - I - row index of non-zero element, 0<=I(s.c_ptr()), &t0, &t1, &i, &j, &v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function rewrites existing (non-zero) element. It returns True if -element exists or False, when it is called for non-existing (zero) -element. - -The purpose of this function is to provide convenient thread-safe way to -modify sparse matrix. Such modification (already existing element is -rewritten) is guaranteed to be thread-safe without any synchronization, as -long as different threads modify different elements. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - I - row index of non-zero element to modify, 0<=I(s.c_ptr()), i, j, v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns I-th row of the sparse matrix stored in CRS format. - -NOTE: when incorrect I (outside of [0,M-1]) or matrix (non-CRS) are - passed, this function throws exception. - -INPUT PARAMETERS: - S - sparse M*N matrix in CRS format - I - row index, 0<=I(s.c_ptr()), i, const_cast(irow.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function performs in-place conversion from CRS format to Hash table -storage. - -INPUT PARAMETERS - S - sparse matrix in CRS format. - -OUTPUT PARAMETERS - S - sparse matrix in Hash table format. - -NOTE: this function has no effect when called with matrix which is -already in Hash table mode. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparseconverttohash(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparseconverttohash(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function performs out-of-place conversion to Hash table storage -format. S0 is copied to S1 and converted on-the-fly. - -INPUT PARAMETERS - S0 - sparse matrix in any format. - -OUTPUT PARAMETERS - S1 - sparse matrix in Hash table format. - -NOTE: if S0 is stored as Hash-table, it is just copied without conversion. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsecopytohash(const sparsematrix &s0, sparsematrix &s1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecopytohash(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function performs out-of-place conversion to CRS format. S0 is -copied to S1 and converted on-the-fly. - -INPUT PARAMETERS - S0 - sparse matrix in any format. - -OUTPUT PARAMETERS - S1 - sparse matrix in CRS format. - -NOTE: if S0 is stored as CRS, it is just copied without conversion. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsecopytocrs(const sparsematrix &s0, sparsematrix &s1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsecopytocrs(const_cast(s0.c_ptr()), const_cast(s1.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function returns type of the matrix storage format. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - sparse storage format used by matrix: - 0 - Hash-table - 1 - CRS-format - -NOTE: future versions of ALGLIB may include additional sparse storage - formats. - - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetmatrixtype(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::sparsegetmatrixtype(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function checks matrix storage format and returns True when matrix is -stored using Hash table representation. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - True if matrix type is Hash table - False if matrix type is not Hash table - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -bool sparseishash(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::sparseishash(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function checks matrix storage format and returns True when matrix is -stored using CRS representation. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - True if matrix type is CRS - False if matrix type is not CRS - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -bool sparseiscrs(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::sparseiscrs(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The function frees all memory occupied by sparse matrix. Sparse matrix -structure becomes unusable after this call. - -OUTPUT PARAMETERS - S - sparse matrix to delete - - -- ALGLIB PROJECT -- - Copyright 24.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsefree(sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sparsefree(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The function returns number of rows of a sparse matrix. - -RESULT: number of rows of a sparse matrix. - - -- ALGLIB PROJECT -- - Copyright 23.08.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetnrows(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::sparsegetnrows(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The function returns number of columns of a sparse matrix. - -RESULT: number of columns of a sparse matrix. - - -- ALGLIB PROJECT -- - Copyright 23.08.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetncols(const sparsematrix &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_int_t result = alglib_impl::sparsegetncols(const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -This object stores state of the iterative norm estimation algorithm. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -_normestimatorstate_owner::_normestimatorstate_owner() -{ - p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_normestimatorstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_normestimatorstate_owner::_normestimatorstate_owner(const _normestimatorstate_owner &rhs) -{ - p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_normestimatorstate_owner& _normestimatorstate_owner::operator=(const _normestimatorstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_normestimatorstate_clear(p_struct); - if( !alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_normestimatorstate_owner::~_normestimatorstate_owner() -{ - alglib_impl::_normestimatorstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -normestimatorstate::normestimatorstate() : _normestimatorstate_owner() -{ -} - -normestimatorstate::normestimatorstate(const normestimatorstate &rhs):_normestimatorstate_owner(rhs) -{ -} - -normestimatorstate& normestimatorstate::operator=(const normestimatorstate &rhs) -{ - if( this==&rhs ) - return *this; - _normestimatorstate_owner::operator=(rhs); - return *this; -} - -normestimatorstate::~normestimatorstate() -{ -} - -/************************************************************************* -This procedure initializes matrix norm estimator. - -USAGE: -1. User initializes algorithm state with NormEstimatorCreate() call -2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) -3. User calls NormEstimatorResults() to get solution. - -INPUT PARAMETERS: - M - number of rows in the matrix being estimated, M>0 - N - number of columns in the matrix being estimated, N>0 - NStart - number of random starting vectors - recommended value - at least 5. - NIts - number of iterations to do with best starting vector - recommended value - at least 5. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTE: this algorithm is effectively deterministic, i.e. it always returns -same result when repeatedly called for the same matrix. In fact, algorithm -uses randomized starting vectors, but internal random numbers generator -always generates same sequence of the random values (it is a feature, not -bug). - -Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::normestimatorcreate(m, n, nstart, nits, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function changes seed value used by algorithm. In some cases we need -deterministic processing, i.e. subsequent calls must return equal results, -in other cases we need non-deterministic algorithm which returns different -results for the same matrix on every pass. - -Setting zero seed will lead to non-deterministic algorithm, while non-zero -value will make our algorithm deterministic. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - SeedVal - seed value, >=0. Zero value = non-deterministic algo. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorsetseed(const normestimatorstate &state, const ae_int_t seedval) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::normestimatorsetseed(const_cast(state.c_ptr()), seedval, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function estimates norm of the sparse M*N matrix A. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - A - sparse M*N matrix, must be converted to CRS format - prior to calling this function. - -After this function is over you can call NormEstimatorResults() to get -estimate of the norm(A). - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorestimatesparse(const normestimatorstate &state, const sparsematrix &a) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::normestimatorestimatesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Matrix norm estimation results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Nrm - estimate of the matrix norm, Nrm>=0 - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorresults(const normestimatorstate &state, double &nrm) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::normestimatorresults(const_cast(state.c_ptr()), &nrm, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) - throw ap_error("Error while calling 'rmatrixludet': looks like one of arguments has wrong size"); - n = a.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixdet(const real_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixdet(const real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.rows()!=a.cols())) - throw ap_error("Error while calling 'rmatrixdet': looks like one of arguments has wrong size"); - n = a.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::rmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_complex result = alglib_impl::cmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) - throw ap_error("Error while calling 'cmatrixludet': looks like one of arguments has wrong size"); - n = a.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_complex result = alglib_impl::cmatrixludet(const_cast(a.c_ptr()), const_cast(pivots.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_complex result = alglib_impl::cmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixdet(const complex_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.rows()!=a.cols())) - throw ap_error("Error while calling 'cmatrixdet': looks like one of arguments has wrong size"); - n = a.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ae_complex result = alglib_impl::cmatrixdet(const_cast(a.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by the Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition, - output of SMatrixCholesky subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -As the determinant is equal to the product of squares of diagonal elements, -it’s not necessary to specify which triangle - lower or upper - the matrix -is stored in. - -Result: - matrix determinant. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixcholeskydet(const_cast(a.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the matrix given by the Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition, - output of SMatrixCholesky subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -As the determinant is equal to the product of squares of diagonal elements, -it’s not necessary to specify which triangle - lower or upper - the matrix -is stored in. - -Result: - matrix determinant. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixcholeskydet(const real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (a.rows()!=a.cols())) - throw ap_error("Error while calling 'spdmatrixcholeskydet': looks like one of arguments has wrong size"); - n = a.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixcholeskydet(const_cast(a.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the symmetric positive definite matrix. - -Input parameters: - A - matrix. Array with elements [0..N-1, 0..N-1]. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Result: - determinant of matrix A. - If matrix A is not positive definite, exception is thrown. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixdet(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Determinant calculation of the symmetric positive definite matrix. - -Input parameters: - A - matrix. Array with elements [0..N-1, 0..N-1]. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Result: - determinant of matrix A. - If matrix A is not positive definite, exception is thrown. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixdet(const real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - bool isupper; - if( (a.rows()!=a.cols())) - throw ap_error("Error while calling 'spdmatrixdet': looks like one of arguments has wrong size"); - if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) - throw ap_error("'a' parameter is not symmetric matrix"); - n = a.rows(); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spdmatrixdet(const_cast(a.c_ptr()), n, isupper, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Algorithm for solving the following generalized symmetric positive-definite -eigenproblem: - A*x = lambda*B*x (1) or - A*B*x = lambda*x (2) or - B*A*x = lambda*x (3). -where A is a symmetric matrix, B - symmetric positive-definite matrix. -The problem is solved by reducing it to an ordinary symmetric eigenvalue -problem. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrices A and B. - IsUpperA - storage format of matrix A. - B - symmetric positive-definite matrix which is given by - its upper or lower triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperB - storage format of matrix B. - ZNeeded - if ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - ProblemType - if ProblemType is equal to: - * 1, the following problem is solved: A*x = lambda*B*x; - * 2, the following problem is solved: A*B*x = lambda*x; - * 3, the following problem is solved: B*A*x = lambda*x. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in matrix columns. It should - be noted that the eigenvectors in such problems do not - form an orthogonal system. - -Result: - True, if the problem was solved successfully. - False, if the error occurred during the Cholesky decomposition of matrix - B (the matrix isn’t positive-definite) or during the work of the iterative - algorithm for solving the symmetric eigenproblem. - -See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. - - -- ALGLIB -- - Copyright 1.28.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixgevd(const_cast(a.c_ptr()), n, isuppera, const_cast(b.c_ptr()), isupperb, zneeded, problemtype, const_cast(d.c_ptr()), const_cast(z.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Algorithm for reduction of the following generalized symmetric positive- -definite eigenvalue problem: - A*x = lambda*B*x (1) or - A*B*x = lambda*x (2) or - B*A*x = lambda*x (3) -to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and -the given problems are the same, and the eigenvectors of the given problem -could be obtained by multiplying the obtained eigenvectors by the -transformation matrix x = R*y). - -Here A is a symmetric matrix, B - symmetric positive-definite matrix. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrices A and B. - IsUpperA - storage format of matrix A. - B - symmetric positive-definite matrix which is given by - its upper or lower triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperB - storage format of matrix B. - ProblemType - if ProblemType is equal to: - * 1, the following problem is solved: A*x = lambda*B*x; - * 2, the following problem is solved: A*B*x = lambda*x; - * 3, the following problem is solved: B*A*x = lambda*x. - -Output parameters: - A - symmetric matrix which is given by its upper or lower - triangle depending on IsUpperA. Contains matrix C. - Array whose indexes range within [0..N-1, 0..N-1]. - R - upper triangular or low triangular transformation matrix - which is used to obtain the eigenvectors of a given problem - as the product of eigenvectors of C (from the right) and - matrix R (from the left). If the matrix is upper - triangular, the elements below the main diagonal - are equal to 0 (and vice versa). Thus, we can perform - the multiplication without taking into account the - internal structure (which is an easier though less - effective way). - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperR - type of matrix R (upper or lower triangular). - -Result: - True, if the problem was reduced successfully. - False, if the error occurred during the Cholesky decomposition of - matrix B (the matrix is not positive-definite). - - -- ALGLIB -- - Copyright 1.28.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::smatrixgevdreduce(const_cast(a.c_ptr()), n, isuppera, const_cast(b.c_ptr()), isupperb, problemtype, const_cast(r.c_ptr()), &isupperr, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a number to an element -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - row where the element to be updated is stored. - UpdColumn - column where the element to be updated is stored. - UpdVal - a number to be added to the element. - - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinvupdatesimple(const_cast(inva.c_ptr()), n, updrow, updcolumn, updval, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a row -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - the row of A whose vector V was added. - 0 <= Row <= N-1 - V - the vector to be added to a row. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinvupdaterow(const_cast(inva.c_ptr()), n, updrow, const_cast(v.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a column -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdColumn - the column of A whose vector U was added. - 0 <= UpdColumn <= N-1 - U - the vector to be added to a column. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinvupdatecolumn(const_cast(inva.c_ptr()), n, updcolumn, const_cast(u.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm computes the inverse of matrix A+u*v’ by using the given matrix -A^-1 and the vectors u and v. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - U - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - V - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of matrix A + u*v'. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixinvupdateuv(const_cast(inva.c_ptr()), n, const_cast(u.c_ptr()), const_cast(v.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Subroutine performing the Schur decomposition of a general matrix by using -the QR algorithm with multiple shifts. - -The source matrix A is represented as S'*A*S = T, where S is an orthogonal -matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of -sizes 1x1 and 2x2 on the main diagonal). - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of A, N>=0. - - -Output parameters: - A - contains matrix T. - Array whose indexes range within [0..N-1, 0..N-1]. - S - contains Schur vectors. - Array whose indexes range within [0..N-1, 0..N-1]. - -Note 1: - The block structure of matrix T can be easily recognized: since all - the elements below the blocks are zeros, the elements a[i+1,i] which - are equal to 0 show the block border. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms in linear algebra). If you require maximum performance on - your machine, it is recommended to adjust this parameter manually. - -Result: - True, - if the algorithm has converged and parameters A and S contain the result. - False, - if the algorithm has not converged. - -Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). -*************************************************************************/ -bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::rmatrixschur(const_cast(a.c_ptr()), n, const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static ae_int_t ablas_rgemmparallelsize = 64; -static ae_int_t ablas_cgemmparallelsize = 64; -static void ablas_ablasinternalsplitlength(ae_int_t n, - ae_int_t nb, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state); -static void ablas_cmatrixrighttrsm2(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -static void ablas_cmatrixlefttrsm2(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -static void ablas_rmatrixrighttrsm2(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -static void ablas_rmatrixlefttrsm2(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -static void ablas_cmatrixsyrk2(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -static void ablas_rmatrixsyrk2(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); - - -static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* work, - /* Complex */ ae_vector* t, - /* Complex */ ae_vector* tau, - ae_state *_state); -static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* work, - /* Complex */ ae_vector* t, - /* Complex */ ae_vector* tau, - ae_state *_state); -static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, - /* Real */ ae_vector* tau, - ae_bool columnwisea, - ae_int_t lengtha, - ae_int_t blocksize, - /* Real */ ae_matrix* t, - /* Real */ ae_vector* work, - ae_state *_state); -static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, - /* Complex */ ae_vector* tau, - ae_bool columnwisea, - ae_int_t lengtha, - ae_int_t blocksize, - /* Complex */ ae_matrix* t, - /* Complex */ ae_vector* work, - ae_state *_state); - - -static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t ustart, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t cstart, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t vstart, - ae_int_t ncvt, - ae_state *_state); -static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state); -static void bdsvd_svd2x2(double f, - double g, - double h, - double* ssmin, - double* ssmax, - ae_state *_state); -static void bdsvd_svdv2x2(double f, - double g, - double h, - double* ssmin, - double* ssmax, - double* snr, - double* csr, - double* snl, - double* csl, - ae_state *_state); - - - - -static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - /* Real */ ae_matrix* z, - ae_state *_state); -static void evd_tdevde2(double a, - double b, - double c, - double* rt1, - double* rt2, - ae_state *_state); -static void evd_tdevdev2(double a, - double b, - double c, - double* rt1, - double* rt2, - double* cs1, - double* sn1, - ae_state *_state); -static double evd_tdevdpythag(double a, double b, ae_state *_state); -static double evd_tdevdextsign(double a, double b, ae_state *_state); -static ae_bool evd_internalbisectioneigenvalues(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t irange, - ae_int_t iorder, - double vl, - double vu, - ae_int_t il, - ae_int_t iu, - double abstol, - /* Real */ ae_vector* w, - ae_int_t* m, - ae_int_t* nsplit, - /* Integer */ ae_vector* iblock, - /* Integer */ ae_vector* isplit, - ae_int_t* errorcode, - ae_state *_state); -static void evd_internaldstein(ae_int_t n, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t m, - /* Real */ ae_vector* w, - /* Integer */ ae_vector* iblock, - /* Integer */ ae_vector* isplit, - /* Real */ ae_matrix* z, - /* Integer */ ae_vector* ifail, - ae_int_t* info, - ae_state *_state); -static void evd_tdininternaldlagtf(ae_int_t n, - /* Real */ ae_vector* a, - double lambdav, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - double tol, - /* Real */ ae_vector* d, - /* Integer */ ae_vector* iin, - ae_int_t* info, - ae_state *_state); -static void evd_tdininternaldlagts(ae_int_t n, - /* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - /* Integer */ ae_vector* iin, - /* Real */ ae_vector* y, - double* tol, - ae_int_t* info, - ae_state *_state); -static void evd_internaldlaebz(ae_int_t ijob, - ae_int_t nitmax, - ae_int_t n, - ae_int_t mmax, - ae_int_t minp, - double abstol, - double reltol, - double pivmin, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - /* Real */ ae_vector* e2, - /* Integer */ ae_vector* nval, - /* Real */ ae_matrix* ab, - /* Real */ ae_vector* c, - ae_int_t* mout, - /* Integer */ ae_matrix* nab, - /* Real */ ae_vector* work, - /* Integer */ ae_vector* iwork, - ae_int_t* info, - ae_state *_state); -static void evd_internaltrevc(/* Real */ ae_matrix* t, - ae_int_t n, - ae_int_t side, - ae_int_t howmny, - /* Boolean */ ae_vector* vselect, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_int_t* m, - ae_int_t* info, - ae_state *_state); -static void evd_internalhsevdlaln2(ae_bool ltrans, - ae_int_t na, - ae_int_t nw, - double smin, - double ca, - /* Real */ ae_matrix* a, - double d1, - double d2, - /* Real */ ae_matrix* b, - double wr, - double wi, - /* Boolean */ ae_vector* rswap4, - /* Boolean */ ae_vector* zswap4, - /* Integer */ ae_matrix* ipivot44, - /* Real */ ae_vector* civ4, - /* Real */ ae_vector* crv4, - /* Real */ ae_matrix* x, - double* scl, - double* xnorm, - ae_int_t* info, - ae_state *_state); -static void evd_internalhsevdladiv(double a, - double b, - double c, - double d, - double* p, - double* q, - ae_state *_state); -static ae_bool evd_nonsymmetricevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t vneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_state *_state); -static void evd_toupperhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state); -static void evd_unpackqfromupperhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state); - - - - -static void trfac_cmatrixluprec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static void trfac_rmatrixluprec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void trfac_cmatrixplurec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static void trfac_rmatrixplurec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void trfac_cmatrixlup2(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static void trfac_rmatrixlup2(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void trfac_cmatrixplu2(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static void trfac_rmatrixplu2(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state); -static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state); - - -static void rcond_rmatrixrcondtrinternal(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_bool onenorm, - double anorm, - double* rc, - ae_state *_state); -static void rcond_cmatrixrcondtrinternal(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_bool onenorm, - double anorm, - double* rc, - ae_state *_state); -static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - ae_bool isnormprovided, - double anorm, - double* rc, - ae_state *_state); -static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - ae_bool isnormprovided, - double anorm, - double* rc, - ae_state *_state); -static void rcond_rmatrixrcondluinternal(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_bool onenorm, - ae_bool isanormprovided, - double anorm, - double* rc, - ae_state *_state); -static void rcond_cmatrixrcondluinternal(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_bool onenorm, - ae_bool isanormprovided, - double anorm, - double* rc, - ae_state *_state); -static void rcond_rmatrixestimatenorm(ae_int_t n, - /* Real */ ae_vector* v, - /* Real */ ae_vector* x, - /* Integer */ ae_vector* isgn, - double* est, - ae_int_t* kase, - ae_state *_state); -static void rcond_cmatrixestimatenorm(ae_int_t n, - /* Complex */ ae_vector* v, - /* Complex */ ae_vector* x, - double* est, - ae_int_t* kase, - /* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_state *_state); -static double rcond_internalcomplexrcondscsum1(/* Complex */ ae_vector* x, - ae_int_t n, - ae_state *_state); -static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ ae_vector* x, - ae_int_t n, - ae_state *_state); -static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_int_t* i, - ae_int_t* iter, - ae_int_t* j, - ae_int_t* jlast, - ae_int_t* jump, - double* absxi, - double* altsgn, - double* estold, - double* temp, - ae_state *_state); -static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_int_t* i, - ae_int_t* iter, - ae_int_t* j, - ae_int_t* jlast, - ae_int_t* jump, - double* absxi, - double* altsgn, - double* estold, - double* temp, - ae_state *_state); - - -static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - /* Real */ ae_vector* tmp, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - /* Complex */ ae_vector* tmp, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - /* Real */ ae_vector* work, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - /* Complex */ ae_vector* work, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -static void matinv_spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state); - - -static double sparse_desiredloadfactor = 0.66; -static double sparse_maxloadfactor = 0.75; -static double sparse_growfactor = 2.00; -static ae_int_t sparse_additional = 10; -static ae_int_t sparse_linalgswitch = 16; -static void sparse_sparseinitduidx(sparsematrix* s, ae_state *_state); -static ae_int_t sparse_hash(ae_int_t i, - ae_int_t j, - ae_int_t tabsize, - ae_state *_state); - - - - - - - - - - - - - - - - - -/************************************************************************* -Splits matrix length in two parts, left part should match ABLAS block size - -INPUT PARAMETERS - A - real matrix, is passed to ensure that we didn't split - complex matrix using real splitting subroutine. - matrix itself is not changed. - N - length, N>0 - -OUTPUT PARAMETERS - N1 - length - N2 - length - -N1+N2=N, N1>=N2, N2 may be zero - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -void ablassplitlength(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state) -{ - - *n1 = 0; - *n2 = 0; - - if( n>ablasblocksize(a, _state) ) - { - ablas_ablasinternalsplitlength(n, ablasblocksize(a, _state), n1, n2, _state); - } - else - { - ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); - } -} - - -/************************************************************************* -Complex ABLASSplitLength - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -void ablascomplexsplitlength(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state) -{ - - *n1 = 0; - *n2 = 0; - - if( n>ablascomplexblocksize(a, _state) ) - { - ablas_ablasinternalsplitlength(n, ablascomplexblocksize(a, _state), n1, n2, _state); - } - else - { - ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); - } -} - - -/************************************************************************* -Returns block size - subdivision size where cache-oblivious soubroutines -switch to the optimized kernel. - -INPUT PARAMETERS - A - real matrix, is passed to ensure that we didn't split - complex matrix using real splitting subroutine. - matrix itself is not changed. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_int_t ablasblocksize(/* Real */ ae_matrix* a, ae_state *_state) -{ - ae_int_t result; - - - result = 32; - return result; -} - - -/************************************************************************* -Block size for complex subroutines. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_int_t ablascomplexblocksize(/* Complex */ ae_matrix* a, - ae_state *_state) -{ - ae_int_t result; - - - result = 24; - return result; -} - - -/************************************************************************* -Microblock size - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_int_t ablasmicroblocksize(ae_state *_state) -{ - ae_int_t result; - - - result = 8; - return result; -} - - -/************************************************************************* -Cache-oblivous complex "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixtranspose(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state) -{ - ae_int_t i; - ae_int_t s1; - ae_int_t s2; - - - if( m<=2*ablascomplexblocksize(a, _state)&&n<=2*ablascomplexblocksize(a, _state) ) - { - - /* - * base case - */ - for(i=0; i<=m-1; i++) - { - ae_v_cmove(&b->ptr.pp_complex[ib][jb+i], b->stride, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(ib,ib+n-1)); - } - } - else - { - - /* - * Cache-oblivious recursion - */ - if( m>n ) - { - ablascomplexsplitlength(a, m, &s1, &s2, _state); - cmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); - cmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); - } - else - { - ablascomplexsplitlength(a, n, &s1, &s2, _state); - cmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); - cmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); - } - } -} - - -/************************************************************************* -Cache-oblivous real "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixtranspose(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state) -{ - ae_int_t i; - ae_int_t s1; - ae_int_t s2; - - - if( m<=2*ablasblocksize(a, _state)&&n<=2*ablasblocksize(a, _state) ) - { - - /* - * base case - */ - for(i=0; i<=m-1; i++) - { - ae_v_move(&b->ptr.pp_double[ib][jb+i], b->stride, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(ib,ib+n-1)); - } - } - else - { - - /* - * Cache-oblivious recursion - */ - if( m>n ) - { - ablassplitlength(a, m, &s1, &s2, _state); - rmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); - rmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); - } - else - { - ablassplitlength(a, n, &s1, &s2, _state); - rmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); - rmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); - } - } -} - - -/************************************************************************* -This code enforces symmetricy of the matrix by copying Upper part to lower -one (or vice versa). - -INPUT PARAMETERS: - A - matrix - N - number of rows/columns - IsUpper - whether we want to copy upper triangle to lower one (True) - or vice versa (False). -*************************************************************************/ -void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - if( isupper ) - { - for(i=0; i<=n-1; i++) - { - for(j=i+1; j<=n-1; j++) - { - a->ptr.pp_double[j][i] = a->ptr.pp_double[i][j]; - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - for(j=i+1; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = a->ptr.pp_double[j][i]; - } - } - } -} - - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixcopy(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state) -{ - ae_int_t i; - - - if( m==0||n==0 ) - { - return; - } - for(i=0; i<=m-1; i++) - { - ae_v_cmove(&b->ptr.pp_complex[ib+i][jb], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(jb,jb+n-1)); - } -} - - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixcopy(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state) -{ - ae_int_t i; - - - if( m==0||n==0 ) - { - return; - } - for(i=0; i<=m-1; i++) - { - ae_v_move(&b->ptr.pp_double[ib+i][jb], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(jb,jb+n-1)); - } -} - - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void cmatrixrank1(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_vector* u, - ae_int_t iu, - /* Complex */ ae_vector* v, - ae_int_t iv, - ae_state *_state) -{ - ae_int_t i; - ae_complex s; - - - if( m==0||n==0 ) - { - return; - } - if( cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) - { - return; - } - for(i=0; i<=m-1; i++) - { - s = u->ptr.p_complex[iu+i]; - ae_v_caddc(&a->ptr.pp_complex[ia+i][ja], 1, &v->ptr.p_complex[iv], 1, "N", ae_v_len(ja,ja+n-1), s); - } -} - - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void rmatrixrank1(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_vector* u, - ae_int_t iu, - /* Real */ ae_vector* v, - ae_int_t iv, - ae_state *_state) -{ - ae_int_t i; - double s; - - - if( m==0||n==0 ) - { - return; - } - if( rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) - { - return; - } - for(i=0; i<=m-1; i++) - { - s = u->ptr.p_double[iu+i]; - ae_v_addd(&a->ptr.pp_double[ia+i][ja], 1, &v->ptr.p_double[iv], 1, ae_v_len(ja,ja+n-1), s); - } -} - - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - M>=0 - N - number of columns of op(A) - N>=0 - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - * OpA=2 => op(A) = A^H - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixmv(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Complex */ ae_vector* x, - ae_int_t ix, - /* Complex */ ae_vector* y, - ae_int_t iy, - ae_state *_state) -{ - ae_int_t i; - ae_complex v; - - - if( m==0 ) - { - return; - } - if( n==0 ) - { - for(i=0; i<=m-1; i++) - { - y->ptr.p_complex[iy+i] = ae_complex_from_d(0); - } - return; - } - if( cmatrixmvf(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) - { - return; - } - if( opa==0 ) - { - - /* - * y = A*x - */ - for(i=0; i<=m-1; i++) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &x->ptr.p_complex[ix], 1, "N", ae_v_len(ja,ja+n-1)); - y->ptr.p_complex[iy+i] = v; - } - return; - } - if( opa==1 ) - { - - /* - * y = A^T*x - */ - for(i=0; i<=m-1; i++) - { - y->ptr.p_complex[iy+i] = ae_complex_from_d(0); - } - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_complex[ix+i]; - ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(iy,iy+m-1), v); - } - return; - } - if( opa==2 ) - { - - /* - * y = A^H*x - */ - for(i=0; i<=m-1; i++) - { - y->ptr.p_complex[iy+i] = ae_complex_from_d(0); - } - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_complex[ix+i]; - ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "Conj", ae_v_len(iy,iy+m-1), v); - } - return; - } -} - - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - N - number of columns of op(A) - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixmv(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Real */ ae_vector* x, - ae_int_t ix, - /* Real */ ae_vector* y, - ae_int_t iy, - ae_state *_state) -{ - ae_int_t i; - double v; - - - if( m==0 ) - { - return; - } - if( n==0 ) - { - for(i=0; i<=m-1; i++) - { - y->ptr.p_double[iy+i] = 0; - } - return; - } - if( rmatrixmvf(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) - { - return; - } - if( opa==0 ) - { - - /* - * y = A*x - */ - for(i=0; i<=m-1; i++) - { - v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &x->ptr.p_double[ix], 1, ae_v_len(ja,ja+n-1)); - y->ptr.p_double[iy+i] = v; - } - return; - } - if( opa==1 ) - { - - /* - * y = A^T*x - */ - for(i=0; i<=m-1; i++) - { - y->ptr.p_double[iy+i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_double[ix+i]; - ae_v_addd(&y->ptr.p_double[iy], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(iy,iy+m-1), v); - } - return; - } -} - - -void cmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablascomplexblocksize(a, _state); - if( m<=bs&&n<=bs ) - { - ablas_cmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( m>=n ) - { - - /* - * Split X: X*A = (X1 X2)^T*A - */ - ablascomplexsplitlength(a, m, &s1, &s2, _state); - cmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - else - { - - /* - * Split A: - * (A1 A12) - * X*op(A) = X*op( ) - * ( A2) - * - * Different variants depending on - * IsUpper/OpType combinations - */ - ablascomplexsplitlength(a, n, &s1, &s2, _state); - if( isupper&&optype==0 ) - { - - /* - * (A1 A12)-1 - * X*A^-1 = (X1 X2)*( ) - * ( A2) - */ - cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1, j1+s1, 0, ae_complex_from_d(1.0), x, i2, j2+s1, _state); - cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - return; - } - if( isupper&&optype!=0 ) - { - - /* - * (A1' )-1 - * X*A^-1 = (X1 X2)*( ) - * (A12' A2') - */ - cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1, j1+s1, optype, ae_complex_from_d(1.0), x, i2, j2, _state); - cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( !isupper&&optype==0 ) - { - - /* - * (A1 )-1 - * X*A^-1 = (X1 X2)*( ) - * (A21 A2) - */ - cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1+s1, j1, 0, ae_complex_from_d(1.0), x, i2, j2, _state); - cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( !isupper&&optype!=0 ) - { - - /* - * (A1' A21')-1 - * X*A^-1 = (X1 X2)*( ) - * ( A2') - */ - cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1+s1, j1, optype, ae_complex_from_d(1.0), x, i2, j2+s1, _state); - cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_cmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state) -{ - cmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); -} - - -void cmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablascomplexblocksize(a, _state); - if( m<=bs&&n<=bs ) - { - ablas_cmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( n>=m ) - { - - /* - * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) - */ - ablascomplexsplitlength(x, n, &s1, &s2, _state); - cmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); - return; - } - else - { - - /* - * Split A - */ - ablascomplexsplitlength(a, m, &s1, &s2, _state); - if( isupper&&optype==0 ) - { - - /* - * (A1 A12)-1 ( X1 ) - * A^-1*X* = ( ) *( ) - * ( A2) ( X2 ) - */ - cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1, j1+s1, 0, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); - cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( isupper&&optype!=0 ) - { - - /* - * (A1' )-1 ( X1 ) - * A^-1*X = ( ) *( ) - * (A12' A2') ( X2 ) - */ - cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1, j1+s1, optype, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); - cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - if( !isupper&&optype==0 ) - { - - /* - * (A1 )-1 ( X1 ) - * A^-1*X = ( ) *( ) - * (A21 A2) ( X2 ) - */ - cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1+s1, j1, 0, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); - cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - if( !isupper&&optype!=0 ) - { - - /* - * (A1' A21')-1 ( X1 ) - * A^-1*X = ( ) *( ) - * ( A2') ( X2 ) - */ - cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1+s1, j1, optype, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); - cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_cmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state) -{ - cmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); -} - - -void rmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablasblocksize(a, _state); - if( m<=bs&&n<=bs ) - { - ablas_rmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( m>=n ) - { - - /* - * Split X: X*A = (X1 X2)^T*A - */ - ablassplitlength(a, m, &s1, &s2, _state); - rmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - else - { - - /* - * Split A: - * (A1 A12) - * X*op(A) = X*op( ) - * ( A2) - * - * Different variants depending on - * IsUpper/OpType combinations - */ - ablassplitlength(a, n, &s1, &s2, _state); - if( isupper&&optype==0 ) - { - - /* - * (A1 A12)-1 - * X*A^-1 = (X1 X2)*( ) - * ( A2) - */ - rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1, j1+s1, 0, 1.0, x, i2, j2+s1, _state); - rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - return; - } - if( isupper&&optype!=0 ) - { - - /* - * (A1' )-1 - * X*A^-1 = (X1 X2)*( ) - * (A12' A2') - */ - rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1, j1+s1, optype, 1.0, x, i2, j2, _state); - rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( !isupper&&optype==0 ) - { - - /* - * (A1 )-1 - * X*A^-1 = (X1 X2)*( ) - * (A21 A2) - */ - rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1+s1, j1, 0, 1.0, x, i2, j2, _state); - rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( !isupper&&optype!=0 ) - { - - /* - * (A1' A21')-1 - * X*A^-1 = (X1 X2)*( ) - * ( A2') - */ - rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1+s1, j1, optype, 1.0, x, i2, j2+s1, _state); - rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_rmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state) -{ - rmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); -} - - -void rmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablasblocksize(a, _state); - if( m<=bs&&n<=bs ) - { - ablas_rmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( n>=m ) - { - - /* - * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) - */ - ablassplitlength(x, n, &s1, &s2, _state); - rmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); - } - else - { - - /* - * Split A - */ - ablassplitlength(a, m, &s1, &s2, _state); - if( isupper&&optype==0 ) - { - - /* - * (A1 A12)-1 ( X1 ) - * A^-1*X* = ( ) *( ) - * ( A2) ( X2 ) - */ - rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - rmatrixgemm(s1, n, s2, -1.0, a, i1, j1+s1, 0, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); - rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - if( isupper&&optype!=0 ) - { - - /* - * (A1' )-1 ( X1 ) - * A^-1*X = ( ) *( ) - * (A12' A2') ( X2 ) - */ - rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixgemm(s2, n, s1, -1.0, a, i1, j1+s1, optype, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); - rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - if( !isupper&&optype==0 ) - { - - /* - * (A1 )-1 ( X1 ) - * A^-1*X = ( ) *( ) - * (A21 A2) ( X2 ) - */ - rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - rmatrixgemm(s2, n, s1, -1.0, a, i1+s1, j1, 0, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); - rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - return; - } - if( !isupper&&optype!=0 ) - { - - /* - * (A1' A21')-1 ( X1 ) - * A^-1*X = ( ) *( ) - * ( A2') ( X2 ) - */ - rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); - rmatrixgemm(s1, n, s2, -1.0, a, i1+s1, j1, optype, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); - rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_rmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state) -{ - rmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state); -} - - -void cmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablascomplexblocksize(a, _state); - if( n<=bs&&k<=bs ) - { - ablas_cmatrixsyrk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - return; - } - if( k>=n ) - { - - /* - * Split K - */ - ablascomplexsplitlength(a, k, &s1, &s2, _state); - if( optypea==0 ) - { - cmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixsyrk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); - } - else - { - cmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixsyrk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); - } - } - else - { - - /* - * Split N - */ - ablascomplexsplitlength(a, n, &s1, &s2, _state); - if( optypea==0&&isupper ) - { - cmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 0, a, ia+s1, ja, 2, ae_complex_from_d(beta), c, ic, jc+s1, _state); - cmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea==0&&!isupper ) - { - cmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia+s1, ja, 0, a, ia, ja, 2, ae_complex_from_d(beta), c, ic+s1, jc, _state); - cmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea!=0&&isupper ) - { - cmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 2, a, ia, ja+s1, 0, ae_complex_from_d(beta), c, ic, jc+s1, _state); - cmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea!=0&&!isupper ) - { - cmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia, ja+s1, 2, a, ia, ja, 0, ae_complex_from_d(beta), c, ic+s1, jc, _state); - cmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_cmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, ae_state *_state) -{ - cmatrixsyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state); -} - - -void rmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablasblocksize(a, _state); - - /* - * Use MKL or generic basecase code - */ - if( rmatrixsyrkmkl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) - { - return; - } - if( n<=bs&&k<=bs ) - { - ablas_rmatrixsyrk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - return; - } - - /* - * Recursive subdivision of the problem - */ - if( k>=n ) - { - - /* - * Split K - */ - ablassplitlength(a, k, &s1, &s2, _state); - if( optypea==0 ) - { - rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixsyrk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); - } - else - { - rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixsyrk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); - } - } - else - { - - /* - * Split N - */ - ablassplitlength(a, n, &s1, &s2, _state); - if( optypea==0&&isupper ) - { - rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 0, a, ia+s1, ja, 1, beta, c, ic, jc+s1, _state); - rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea==0&&!isupper ) - { - rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixgemm(s2, s1, k, alpha, a, ia+s1, ja, 0, a, ia, ja, 1, beta, c, ic+s1, jc, _state); - rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea!=0&&isupper ) - { - rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 1, a, ia, ja+s1, 0, beta, c, ic, jc+s1, _state); - rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - if( optypea!=0&&!isupper ) - { - rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); - rmatrixgemm(s2, s1, k, alpha, a, ia, ja+s1, 1, a, ia, ja, 0, beta, c, ic+s1, jc, _state); - rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); - return; - } - } -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_rmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, ae_state *_state) -{ - rmatrixsyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state); -} - - -void cmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablascomplexblocksize(a, _state); - if( (m<=bs&&n<=bs)&&k<=bs ) - { - cmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - return; - } - - /* - * SMP support is turned on when M or N are larger than some boundary value. - * Magnitude of K is not taken into account because splitting on K does not - * allow us to spawn child tasks. - */ - - /* - * Recursive algorithm: parallel splitting on M/N - */ - if( m>=n&&m>=k ) - { - - /* - * A*B = (A1 A2)^T*B - */ - ablascomplexsplitlength(a, m, &s1, &s2, _state); - cmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - if( optypea==0 ) - { - cmatrixgemm(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); - } - else - { - cmatrixgemm(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); - } - return; - } - if( n>=m&&n>=k ) - { - - /* - * A*B = A*(B1 B2) - */ - ablascomplexsplitlength(a, n, &s1, &s2, _state); - if( optypeb==0 ) - { - cmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); - } - else - { - cmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); - } - return; - } - - /* - * Recursive algorithm: serial splitting on K - */ - - /* - * A*B = (A1 A2)*(B1 B2)^T - */ - ablascomplexsplitlength(a, k, &s1, &s2, _state); - if( optypea==0&&optypeb==0 ) - { - cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); - } - if( optypea==0&&optypeb!=0 ) - { - cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); - } - if( optypea!=0&&optypeb==0 ) - { - cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); - } - if( optypea!=0&&optypeb!=0 ) - { - cmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - cmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); - } - return; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_cmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, ae_state *_state) -{ - cmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state); -} - - -void rmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state) -{ - ae_int_t s1; - ae_int_t s2; - ae_int_t bs; - - - bs = ablasblocksize(a, _state); - - /* - * Check input sizes for correctness - */ - ae_assert(optypea==0||optypea==1, "RMatrixGEMM: incorrect OpTypeA (must be 0 or 1)", _state); - ae_assert(optypeb==0||optypeb==1, "RMatrixGEMM: incorrect OpTypeB (must be 0 or 1)", _state); - ae_assert(ic+m<=c->rows, "RMatrixGEMM: incorect size of output matrix C", _state); - ae_assert(jc+n<=c->cols, "RMatrixGEMM: incorect size of output matrix C", _state); - - /* - * Use MKL or ALGLIB basecase code - */ - if( rmatrixgemmmkl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) - { - return; - } - if( (m<=bs&&n<=bs)&&k<=bs ) - { - rmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - return; - } - - /* - * SMP support is turned on when M or N are larger than some boundary value. - * Magnitude of K is not taken into account because splitting on K does not - * allow us to spawn child tasks. - */ - - /* - * Recursive algorithm: split on M or N - */ - if( m>=n&&m>=k ) - { - - /* - * A*B = (A1 A2)^T*B - */ - ablassplitlength(a, m, &s1, &s2, _state); - if( optypea==0 ) - { - rmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); - } - else - { - rmatrixgemm(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); - } - return; - } - if( n>=m&&n>=k ) - { - - /* - * A*B = A*(B1 B2) - */ - ablassplitlength(a, n, &s1, &s2, _state); - if( optypeb==0 ) - { - rmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); - } - else - { - rmatrixgemm(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); - } - return; - } - - /* - * Recursive algorithm: split on K - */ - - /* - * A*B = (A1 A2)*(B1 B2)^T - */ - ablassplitlength(a, k, &s1, &s2, _state); - if( optypea==0&&optypeb==0 ) - { - rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); - } - if( optypea==0&&optypeb!=0 ) - { - rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); - } - if( optypea!=0&&optypeb==0 ) - { - rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); - } - if( optypea!=0&&optypeb!=0 ) - { - rmatrixgemm(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); - rmatrixgemm(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); - } - return; -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_rmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, ae_state *_state) -{ - rmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state); -} - - -/************************************************************************* -Complex ABLASSplitLength - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -static void ablas_ablasinternalsplitlength(ae_int_t n, - ae_int_t nb, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state) -{ - ae_int_t r; - - *n1 = 0; - *n2 = 0; - - if( n<=nb ) - { - - /* - * Block size, no further splitting - */ - *n1 = n; - *n2 = 0; - } - else - { - - /* - * Greater than block size - */ - if( n%nb!=0 ) - { - - /* - * Split remainder - */ - *n2 = n%nb; - *n1 = n-(*n2); - } - else - { - - /* - * Split on block boundaries - */ - *n2 = n/2; - *n1 = n-(*n2); - if( *n1%nb==0 ) - { - return; - } - r = nb-*n1%nb; - *n1 = *n1+r; - *n2 = *n2-r; - } - } -} - - -/************************************************************************* -Level 2 variant of CMatrixRightTRSM -*************************************************************************/ -static void ablas_cmatrixrighttrsm2(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_complex vc; - ae_complex vd; - - - - /* - * Special case - */ - if( n*m==0 ) - { - return; - } - - /* - * Try to call fast TRSM - */ - if( cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) - { - return; - } - - /* - * General case - */ - if( isupper ) - { - - /* - * Upper triangular matrix - */ - if( optype==0 ) - { - - /* - * X*A^(-1) - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = a->ptr.pp_complex[i1+j][j1+j]; - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); - if( jptr.pp_complex[i2+i][j2+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+i][j2+j+1], 1, &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1), vc); - } - } - } - return; - } - if( optype==1 ) - { - - /* - * X*A^(-T) - */ - for(i=0; i<=m-1; i++) - { - for(j=n-1; j>=0; j--) - { - vc = ae_complex_from_d(0); - vd = ae_complex_from_d(1); - if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1)); - } - if( !isunit ) - { - vd = a->ptr.pp_complex[i1+j][j1+j]; - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); - } - } - return; - } - if( optype==2 ) - { - - /* - * X*A^(-H) - */ - for(i=0; i<=m-1; i++) - { - for(j=n-1; j>=0; j--) - { - vc = ae_complex_from_d(0); - vd = ae_complex_from_d(1); - if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "Conj", ae_v_len(j2+j+1,j2+n-1)); - } - if( !isunit ) - { - vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); - } - } - return; - } - } - else - { - - /* - * Lower triangular matrix - */ - if( optype==0 ) - { - - /* - * X*A^(-1) - */ - for(i=0; i<=m-1; i++) - { - for(j=n-1; j>=0; j--) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = a->ptr.pp_complex[i1+j][j1+j]; - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); - if( j>0 ) - { - vc = x->ptr.pp_complex[i2+i][j2+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1), vc); - } - } - } - return; - } - if( optype==1 ) - { - - /* - * X*A^(-T) - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - vc = ae_complex_from_d(0); - vd = ae_complex_from_d(1); - if( j>0 ) - { - vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1)); - } - if( !isunit ) - { - vd = a->ptr.pp_complex[i1+j][j1+j]; - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); - } - } - return; - } - if( optype==2 ) - { - - /* - * X*A^(-H) - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - vc = ae_complex_from_d(0); - vd = ae_complex_from_d(1); - if( j>0 ) - { - vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "Conj", ae_v_len(j2,j2+j-1)); - } - if( !isunit ) - { - vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); - } - x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); - } - } - return; - } - } -} - - -/************************************************************************* -Level-2 subroutine -*************************************************************************/ -static void ablas_cmatrixlefttrsm2(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_complex vc; - ae_complex vd; - - - - /* - * Special case - */ - if( n*m==0 ) - { - return; - } - - /* - * Try to call fast TRSM - */ - if( cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) - { - return; - } - - /* - * General case - */ - if( isupper ) - { - - /* - * Upper triangular matrix - */ - if( optype==0 ) - { - - /* - * A^(-1)*X - */ - for(i=m-1; i>=0; i--) - { - for(j=i+1; j<=m-1; j++) - { - vc = a->ptr.pp_complex[i1+i][j1+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - if( !isunit ) - { - vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - } - } - return; - } - if( optype==1 ) - { - - /* - * A^(-T)*X - */ - for(i=0; i<=m-1; i++) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); - } - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i+1; j<=m-1; j++) - { - vc = a->ptr.pp_complex[i1+i][j1+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - } - return; - } - if( optype==2 ) - { - - /* - * A^(-H)*X - */ - for(i=0; i<=m-1; i++) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = ae_c_d_div(1,ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); - } - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i+1; j<=m-1; j++) - { - vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); - ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - } - return; - } - } - else - { - - /* - * Lower triangular matrix - */ - if( optype==0 ) - { - - /* - * A^(-1)*X - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=i-1; j++) - { - vc = a->ptr.pp_complex[i1+i][j1+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = ae_c_d_div(1,a->ptr.pp_complex[i1+j][j1+j]); - } - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - } - return; - } - if( optype==1 ) - { - - /* - * A^(-T)*X - */ - for(i=m-1; i>=0; i--) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = ae_c_d_div(1,a->ptr.pp_complex[i1+i][j1+i]); - } - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i-1; j>=0; j--) - { - vc = a->ptr.pp_complex[i1+i][j1+j]; - ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - } - return; - } - if( optype==2 ) - { - - /* - * A^(-H)*X - */ - for(i=m-1; i>=0; i--) - { - if( isunit ) - { - vd = ae_complex_from_d(1); - } - else - { - vd = ae_c_d_div(1,ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); - } - ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i-1; j>=0; j--) - { - vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); - ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); - } - } - return; - } - } -} - - -/************************************************************************* -Level 2 subroutine - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -static void ablas_rmatrixrighttrsm2(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double vr; - double vd; - - - - /* - * Special case - */ - if( n*m==0 ) - { - return; - } - - /* - * Try to use "fast" code - */ - if( rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) - { - return; - } - - /* - * General case - */ - if( isupper ) - { - - /* - * Upper triangular matrix - */ - if( optype==0 ) - { - - /* - * X*A^(-1) - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( isunit ) - { - vd = 1; - } - else - { - vd = a->ptr.pp_double[i1+j][j1+j]; - } - x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; - if( jptr.pp_double[i2+i][j2+j]; - ae_v_subd(&x->ptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1), vr); - } - } - } - return; - } - if( optype==1 ) - { - - /* - * X*A^(-T) - */ - for(i=0; i<=m-1; i++) - { - for(j=n-1; j>=0; j--) - { - vr = 0; - vd = 1; - if( jptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1)); - } - if( !isunit ) - { - vd = a->ptr.pp_double[i1+j][j1+j]; - } - x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; - } - } - return; - } - } - else - { - - /* - * Lower triangular matrix - */ - if( optype==0 ) - { - - /* - * X*A^(-1) - */ - for(i=0; i<=m-1; i++) - { - for(j=n-1; j>=0; j--) - { - if( isunit ) - { - vd = 1; - } - else - { - vd = a->ptr.pp_double[i1+j][j1+j]; - } - x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; - if( j>0 ) - { - vr = x->ptr.pp_double[i2+i][j2+j]; - ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1), vr); - } - } - } - return; - } - if( optype==1 ) - { - - /* - * X*A^(-T) - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - vr = 0; - vd = 1; - if( j>0 ) - { - vr = ae_v_dotproduct(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1)); - } - if( !isunit ) - { - vd = a->ptr.pp_double[i1+j][j1+j]; - } - x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; - } - } - return; - } - } -} - - -/************************************************************************* -Level 2 subroutine -*************************************************************************/ -static void ablas_rmatrixlefttrsm2(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double vr; - double vd; - - - - /* - * Special case - */ - if( n==0||m==0 ) - { - return; - } - - /* - * Try fast code - */ - if( rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) - { - return; - } - - /* - * General case - */ - if( isupper ) - { - - /* - * Upper triangular matrix - */ - if( optype==0 ) - { - - /* - * A^(-1)*X - */ - for(i=m-1; i>=0; i--) - { - for(j=i+1; j<=m-1; j++) - { - vr = a->ptr.pp_double[i1+i][j1+j]; - ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); - } - if( !isunit ) - { - vd = 1/a->ptr.pp_double[i1+i][j1+i]; - ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - } - } - return; - } - if( optype==1 ) - { - - /* - * A^(-T)*X - */ - for(i=0; i<=m-1; i++) - { - if( isunit ) - { - vd = 1; - } - else - { - vd = 1/a->ptr.pp_double[i1+i][j1+i]; - } - ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i+1; j<=m-1; j++) - { - vr = a->ptr.pp_double[i1+i][j1+j]; - ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); - } - } - return; - } - } - else - { - - /* - * Lower triangular matrix - */ - if( optype==0 ) - { - - /* - * A^(-1)*X - */ - for(i=0; i<=m-1; i++) - { - for(j=0; j<=i-1; j++) - { - vr = a->ptr.pp_double[i1+i][j1+j]; - ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); - } - if( isunit ) - { - vd = 1; - } - else - { - vd = 1/a->ptr.pp_double[i1+j][j1+j]; - } - ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - } - return; - } - if( optype==1 ) - { - - /* - * A^(-T)*X - */ - for(i=m-1; i>=0; i--) - { - if( isunit ) - { - vd = 1; - } - else - { - vd = 1/a->ptr.pp_double[i1+i][j1+i]; - } - ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); - for(j=i-1; j>=0; j--) - { - vr = a->ptr.pp_double[i1+i][j1+j]; - ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); - } - } - return; - } - } -} - - -/************************************************************************* -Level 2 subroutine -*************************************************************************/ -static void ablas_cmatrixsyrk2(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - ae_complex v; - - - - /* - * Fast exit (nothing to be done) - */ - if( (ae_fp_eq(alpha,0)||k==0)&&ae_fp_eq(beta,1) ) - { - return; - } - - /* - * Try to call fast SYRK - */ - if( cmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) - { - return; - } - - /* - * SYRK - */ - if( optypea==0 ) - { - - /* - * C=alpha*A*A^H+beta*C - */ - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - if( ae_fp_neq(alpha,0)&&k>0 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &a->ptr.pp_complex[ia+j][ja], 1, "Conj", ae_v_len(ja,ja+k-1)); - } - else - { - v = ae_complex_from_d(0); - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul_d(v,alpha); - } - else - { - c->ptr.pp_complex[ic+i][jc+j] = ae_c_add(ae_c_mul_d(c->ptr.pp_complex[ic+i][jc+j],beta),ae_c_mul_d(v,alpha)); - } - } - } - return; - } - else - { - - /* - * C=alpha*A^H*A+beta*C - */ - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - if( ae_fp_eq(beta,0) ) - { - for(j=j1; j<=j2; j++) - { - c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_d(0); - } - } - else - { - ae_v_cmuld(&c->ptr.pp_complex[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); - } - } - for(i=0; i<=k-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( isupper ) - { - j1 = j; - j2 = n-1; - } - else - { - j1 = 0; - j2 = j; - } - v = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[ia+i][ja+j], _state),alpha); - ae_v_caddc(&c->ptr.pp_complex[ic+j][jc+j1], 1, &a->ptr.pp_complex[ia+i][ja+j1], 1, "N", ae_v_len(jc+j1,jc+j2), v); - } - } - return; - } -} - - -/************************************************************************* -Level 2 subrotuine -*************************************************************************/ -static void ablas_rmatrixsyrk2(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - double v; - - - - /* - * Fast exit (nothing to be done) - */ - if( (ae_fp_eq(alpha,0)||k==0)&&ae_fp_eq(beta,1) ) - { - return; - } - - /* - * Try to call fast SYRK - */ - if( rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) - { - return; - } - - /* - * SYRK - */ - if( optypea==0 ) - { - - /* - * C=alpha*A*A^H+beta*C - */ - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - if( ae_fp_neq(alpha,0)&&k>0 ) - { - v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &a->ptr.pp_double[ia+j][ja], 1, ae_v_len(ja,ja+k-1)); - } - else - { - v = 0; - } - if( ae_fp_eq(beta,0) ) - { - c->ptr.pp_double[ic+i][jc+j] = alpha*v; - } - else - { - c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]+alpha*v; - } - } - } - return; - } - else - { - - /* - * C=alpha*A^H*A+beta*C - */ - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - if( ae_fp_eq(beta,0) ) - { - for(j=j1; j<=j2; j++) - { - c->ptr.pp_double[ic+i][jc+j] = 0; - } - } - else - { - ae_v_muld(&c->ptr.pp_double[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); - } - } - for(i=0; i<=k-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( isupper ) - { - j1 = j; - j2 = n-1; - } - else - { - j1 = 0; - j2 = j; - } - v = alpha*a->ptr.pp_double[ia+i][ja+j]; - ae_v_addd(&c->ptr.pp_double[ic+j][jc+j1], 1, &a->ptr.pp_double[ia+i][ja+j1], 1, ae_v_len(jc+j1,jc+j2), v); - } - } - return; - } -} - - - - -/************************************************************************* -QR decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form (see below). - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. - -The elements of matrix R are located on and above the main diagonal of -matrix A. The elements which are located in Tau array and below the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(k-1), - -where k = min(m,n), and each H(i) is in the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, -so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqr(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t rowscount; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); - - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - minmn = ae_minint(m, n, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(tau, minmn, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, m, ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, 2*ablasblocksize(a, _state), n, _state); - - /* - * Blocked code - */ - blockstart = 0; - while(blockstart!=minmn) - { - - /* - * Determine block size - */ - blocksize = minmn-blockstart; - if( blocksize>ablasblocksize(a, _state) ) - { - blocksize = ablasblocksize(a, _state); - } - rowscount = m-blockstart; - - /* - * QR decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); - rmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); - rmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); - ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); - - /* - * Update the rest, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( blockstart+blocksize<=n-1 ) - { - if( n-blockstart-blocksize>=2*ablasblocksize(a, _state)||rowscount>=4*ablasblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q'. - * - * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' - */ - rmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, 1.0, &tmpa, 0, 0, 1, a, blockstart, blockstart+blocksize, 0, 0.0, &tmpr, 0, 0, _state); - rmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, 1.0, &tmpt, 0, 0, 1, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); - rmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, a, blockstart, blockstart+blocksize, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=0; i<=blocksize-1; i++) - { - ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); - t.ptr.p_double[1] = 1; - applyreflectionfromtheleft(a, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart+blocksize; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -LQ decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices L and Q in compact form (see below) - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0..Min(M,N)-1]. - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. - -The elements of matrix L are located on and below the main diagonal of -matrix A. The elements which are located in Tau array and above the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(k-1)*H(k-2)*...*H(1)*H(0), - -where k = min(m,n), and each H(i) is of the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, -v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t columnscount; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); - - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - minmn = ae_minint(m, n, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(tau, minmn, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, ablasblocksize(a, _state), n, _state); - ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, m, 2*ablasblocksize(a, _state), _state); - - /* - * Blocked code - */ - blockstart = 0; - while(blockstart!=minmn) - { - - /* - * Determine block size - */ - blocksize = minmn-blockstart; - if( blocksize>ablasblocksize(a, _state) ) - { - blocksize = ablasblocksize(a, _state); - } - columnscount = n-blockstart; - - /* - * LQ decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); - rmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); - rmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); - ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); - - /* - * Update the rest, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( blockstart+blocksize<=m-1 ) - { - if( m-blockstart-blocksize>=2*ablasblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q. - * - * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA - */ - rmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, 1.0, a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); - rmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, 0.0, &tmpr, 0, blocksize, _state); - rmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, a, blockstart+blocksize, blockstart, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=0; i<=blocksize-1; i++) - { - ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); - t.ptr.p_double[1] = 1; - applyreflectionfromtheright(a, taubuf.ptr.p_double[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart+blocksize; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -QR decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixqr(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t rowscount; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); - - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - minmn = ae_minint(m, n, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(tau, minmn, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, m, ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, 2*ablascomplexblocksize(a, _state), n, _state); - - /* - * Blocked code - */ - blockstart = 0; - while(blockstart!=minmn) - { - - /* - * Determine block size - */ - blocksize = minmn-blockstart; - if( blocksize>ablascomplexblocksize(a, _state) ) - { - blocksize = ablascomplexblocksize(a, _state); - } - rowscount = m-blockstart; - - /* - * QR decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ortfac_cmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); - cmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); - ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); - - /* - * Update the rest, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( blockstart+blocksize<=n-1 ) - { - if( n-blockstart-blocksize>=2*ablascomplexblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q'. - * - * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' - */ - cmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, a, blockstart, blockstart+blocksize, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); - cmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 2, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); - cmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), a, blockstart, blockstart+blocksize, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=0; i<=blocksize-1; i++) - { - ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); - t.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheleft(a, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart+blocksize; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -LQ decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and L in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixlq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t columnscount; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); - - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - minmn = ae_minint(m, n, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(tau, minmn, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, ablascomplexblocksize(a, _state), n, _state); - ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, m, 2*ablascomplexblocksize(a, _state), _state); - - /* - * Blocked code - */ - blockstart = 0; - while(blockstart!=minmn) - { - - /* - * Determine block size - */ - blocksize = minmn-blockstart; - if( blocksize>ablascomplexblocksize(a, _state) ) - { - blocksize = ablascomplexblocksize(a, _state); - } - columnscount = n-blockstart; - - /* - * LQ decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ortfac_cmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); - cmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); - ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); - - /* - * Update the rest, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( blockstart+blocksize<=m-1 ) - { - if( m-blockstart-blocksize>=2*ablascomplexblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q. - * - * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA - */ - cmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); - cmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); - cmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=0; i<=blocksize-1; i++) - { - ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); - t.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheright(a, taubuf.ptr.p_complex[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart+blocksize; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Partial unpacking of matrix Q from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixQR subroutine. - QColumns - required number of columns of matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose indexes range within [0..M-1, 0..QColumns-1]. - If QColumns=0, the array remains unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_int_t qcolumns, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_int_t refcnt; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t rowscount; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); - if( (m<=0||n<=0)||qcolumns<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - minmn = ae_minint(m, n, _state); - refcnt = ae_minint(minmn, qcolumns, _state); - ae_matrix_set_length(q, m, qcolumns, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=qcolumns-1; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - ae_vector_set_length(&work, ae_maxint(m, qcolumns, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, qcolumns, _state)+1, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, m, ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, 2*ablasblocksize(a, _state), qcolumns, _state); - - /* - * Blocked code - */ - blockstart = ablasblocksize(a, _state)*(refcnt/ablasblocksize(a, _state)); - blocksize = refcnt-blockstart; - while(blockstart>=0) - { - rowscount = m-blockstart; - if( blocksize>0 ) - { - - /* - * Copy current block - */ - rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); - - /* - * Update, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( qcolumns>=2*ablasblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply matrix by Q. - * - * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - */ - rmatrixgemm(blocksize, qcolumns, rowscount, 1.0, &tmpa, 0, 0, 1, q, blockstart, 0, 0, 0.0, &tmpr, 0, 0, _state); - rmatrixgemm(blocksize, qcolumns, blocksize, 1.0, &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); - rmatrixgemm(rowscount, qcolumns, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, q, blockstart, 0, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=blocksize-1; i>=0; i--) - { - ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); - t.ptr.p_double[1] = 1; - applyreflectionfromtheleft(q, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart-ablasblocksize(a, _state); - blocksize = ablasblocksize(a, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackr(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* r, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - ae_matrix_clear(r); - - if( m<=0||n<=0 ) - { - return; - } - k = ae_minint(m, n, _state); - ae_matrix_set_length(r, m, n, _state); - for(i=0; i<=n-1; i++) - { - r->ptr.pp_double[0][i] = 0; - } - for(i=1; i<=m-1; i++) - { - ae_v_move(&r->ptr.pp_double[i][0], 1, &r->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); - } - for(i=0; i<=k-1; i++) - { - ae_v_move(&r->ptr.pp_double[i][i], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); - } -} - - -/************************************************************************* -Partial unpacking of matrix Q from the LQ decomposition of a matrix A - -Input parameters: - A - matrices L and Q in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixLQ subroutine. - QRows - required number of rows in matrix Q. N>=QRows>=0. - -Output parameters: - Q - first QRows rows of matrix Q. Array whose indexes range - within [0..QRows-1, 0..N-1]. If QRows=0, the array remains - unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_int_t qrows, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_int_t refcnt; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t columnscount; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(qrows<=n, "RMatrixLQUnpackQ: QRows>N!", _state); - if( (m<=0||n<=0)||qrows<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - minmn = ae_minint(m, n, _state); - refcnt = ae_minint(minmn, qrows, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, ablasblocksize(a, _state), n, _state); - ae_matrix_set_length(&tmpt, ablasblocksize(a, _state), 2*ablasblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, qrows, 2*ablasblocksize(a, _state), _state); - ae_matrix_set_length(q, qrows, n, _state); - for(i=0; i<=qrows-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * Blocked code - */ - blockstart = ablasblocksize(a, _state)*(refcnt/ablasblocksize(a, _state)); - blocksize = refcnt-blockstart; - while(blockstart>=0) - { - columnscount = n-blockstart; - if( blocksize>0 ) - { - - /* - * Copy submatrix - */ - rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); - - /* - * Update matrix, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( qrows>=2*ablasblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q'. - * - * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA - */ - rmatrixgemm(qrows, blocksize, columnscount, 1.0, q, 0, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); - rmatrixgemm(qrows, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 1, 0.0, &tmpr, 0, blocksize, _state); - rmatrixgemm(qrows, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, q, 0, blockstart, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=blocksize-1; i>=0; i--) - { - ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); - t.ptr.p_double[1] = 1; - applyreflectionfromtheright(q, taubuf.ptr.p_double[i], &t, 0, qrows-1, blockstart+i, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart-ablasblocksize(a, _state); - blocksize = ablasblocksize(a, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackl(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* l, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - ae_matrix_clear(l); - - if( m<=0||n<=0 ) - { - return; - } - ae_matrix_set_length(l, m, n, _state); - for(i=0; i<=n-1; i++) - { - l->ptr.pp_double[0][i] = 0; - } - for(i=1; i<=m-1; i++) - { - ae_v_move(&l->ptr.pp_double[i][0], 1, &l->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); - } - for(i=0; i<=m-1; i++) - { - k = ae_minint(i, n-1, _state); - ae_v_move(&l->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k)); - } -} - - -/************************************************************************* -Partial unpacking of matrix Q from QR decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixQR subroutine . - QColumns - required number of columns in matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose index ranges within [0..M-1, 0..QColumns-1]. - If QColumns=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_int_t qcolumns, - /* Complex */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_int_t refcnt; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t rowscount; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - minmn = ae_minint(m, n, _state); - refcnt = ae_minint(minmn, qcolumns, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, m, ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, 2*ablascomplexblocksize(a, _state), qcolumns, _state); - ae_matrix_set_length(q, m, qcolumns, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=qcolumns-1; j++) - { - if( i==j ) - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(1); - } - else - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - - /* - * Blocked code - */ - blockstart = ablascomplexblocksize(a, _state)*(refcnt/ablascomplexblocksize(a, _state)); - blocksize = refcnt-blockstart; - while(blockstart>=0) - { - rowscount = m-blockstart; - if( blocksize>0 ) - { - - /* - * QR decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); - - /* - * Update matrix, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( qcolumns>=2*ablascomplexblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q. - * - * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' - */ - cmatrixgemm(blocksize, qcolumns, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, q, blockstart, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); - cmatrixgemm(blocksize, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); - cmatrixgemm(rowscount, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), q, blockstart, 0, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=blocksize-1; i>=0; i--) - { - ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); - t.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheleft(q, taubuf.ptr.p_complex[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart-ablascomplexblocksize(a, _state); - blocksize = ablascomplexblocksize(a, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackr(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* r, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - ae_matrix_clear(r); - - if( m<=0||n<=0 ) - { - return; - } - k = ae_minint(m, n, _state); - ae_matrix_set_length(r, m, n, _state); - for(i=0; i<=n-1; i++) - { - r->ptr.pp_complex[0][i] = ae_complex_from_d(0); - } - for(i=1; i<=m-1; i++) - { - ae_v_cmove(&r->ptr.pp_complex[i][0], 1, &r->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); - } - for(i=0; i<=k-1; i++) - { - ae_v_cmove(&r->ptr.pp_complex[i][i], 1, &a->ptr.pp_complex[i][i], 1, "N", ae_v_len(i,n-1)); - } -} - - -/************************************************************************* -Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixLQ subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixLQ subroutine . - QRows - required number of rows in matrix Q. N>=QColumns>=0. - -Output parameters: - Q - first QRows rows of matrix Q. - Array whose index ranges within [0..QRows-1, 0..N-1]. - If QRows=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_int_t qrows, - /* Complex */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_vector taubuf; - ae_int_t minmn; - ae_int_t refcnt; - ae_matrix tmpa; - ae_matrix tmpt; - ae_matrix tmpr; - ae_int_t blockstart; - ae_int_t blocksize; - ae_int_t columnscount; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); - - if( m<=0||n<=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Init - */ - minmn = ae_minint(m, n, _state); - refcnt = ae_minint(minmn, qrows, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); - ae_vector_set_length(&taubuf, minmn, _state); - ae_matrix_set_length(&tmpa, ablascomplexblocksize(a, _state), n, _state); - ae_matrix_set_length(&tmpt, ablascomplexblocksize(a, _state), ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(&tmpr, qrows, 2*ablascomplexblocksize(a, _state), _state); - ae_matrix_set_length(q, qrows, n, _state); - for(i=0; i<=qrows-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(1); - } - else - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - - /* - * Blocked code - */ - blockstart = ablascomplexblocksize(a, _state)*(refcnt/ablascomplexblocksize(a, _state)); - blocksize = refcnt-blockstart; - while(blockstart>=0) - { - columnscount = n-blockstart; - if( blocksize>0 ) - { - - /* - * LQ decomposition of submatrix. - * Matrix is copied to temporary storage to solve - * some TLB issues arising from non-contiguous memory - * access pattern. - */ - cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); - ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); - - /* - * Update matrix, choose between: - * a) Level 2 algorithm (when the rest of the matrix is small enough) - * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY - * representation for products of Householder transformations', - * by R. Schreiber and C. Van Loan. - */ - if( qrows>=2*ablascomplexblocksize(a, _state) ) - { - - /* - * Prepare block reflector - */ - ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); - - /* - * Multiply the rest of A by Q'. - * - * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA - */ - cmatrixgemm(qrows, blocksize, columnscount, ae_complex_from_d(1.0), q, 0, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); - cmatrixgemm(qrows, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); - cmatrixgemm(qrows, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), q, 0, blockstart, _state); - } - else - { - - /* - * Level 2 algorithm - */ - for(i=blocksize-1; i>=0; i--) - { - ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); - t.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheright(q, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, 0, qrows-1, blockstart+i, n-1, &work, _state); - } - } - } - - /* - * Advance - */ - blockstart = blockstart-ablascomplexblocksize(a, _state); - blocksize = ablascomplexblocksize(a, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of CMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackl(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* l, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - - ae_matrix_clear(l); - - if( m<=0||n<=0 ) - { - return; - } - ae_matrix_set_length(l, m, n, _state); - for(i=0; i<=n-1; i++) - { - l->ptr.pp_complex[0][i] = ae_complex_from_d(0); - } - for(i=1; i<=m-1; i++) - { - ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &l->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); - } - for(i=0; i<=m-1; i++) - { - k = ae_minint(i, n-1, _state); - ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,k)); - } -} - - -/************************************************************************* -Base case for real QR - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -void rmatrixqrbasecase(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* work, - /* Real */ ae_vector* t, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t minmn; - double tmp; - - - minmn = ae_minint(m, n, _state); - - /* - * Test the input arguments - */ - k = minmn; - for(i=0; i<=k-1; i++) - { - - /* - * Generate elementary reflector H(i) to annihilate A(i+1:m,i) - */ - ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); - generatereflection(t, m-i, &tmp, _state); - tau->ptr.p_double[i] = tmp; - ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t->ptr.p_double[1], 1, ae_v_len(i,m-1)); - t->ptr.p_double[1] = 1; - if( iptr.p_double[i], t, i, m-1, i+1, n-1, work, _state); - } - } -} - - -/************************************************************************* -Base case for real LQ - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -void rmatrixlqbasecase(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* work, - /* Real */ ae_vector* t, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - double tmp; - - - k = ae_minint(m, n, _state); - for(i=0; i<=k-1; i++) - { - - /* - * Generate elementary reflector H(i) to annihilate A(i,i+1:n-1) - */ - ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); - generatereflection(t, n-i, &tmp, _state); - tau->ptr.p_double[i] = tmp; - ae_v_move(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[1], 1, ae_v_len(i,n-1)); - t->ptr.p_double[1] = 1; - if( iptr.p_double[i], t, i+1, m-1, i, n-1, work, _state); - } - } -} - - -/************************************************************************* -Reduction of a rectangular matrix to bidiagonal form - -The algorithm reduces the rectangular matrix A to bidiagonal form by -orthogonal transformations P and Q: A = Q*B*P. - -Input parameters: - A - source matrix. array[0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q, B, P in compact form (see below). - TauQ - scalar factors which are used to form matrix Q. - TauP - scalar factors which are used to form matrix P. - -The main diagonal and one of the secondary diagonals of matrix A are -replaced with bidiagonal matrix B. Other elements contain elementary -reflections which form MxM matrix Q and NxN matrix P, respectively. - -If M>=N, B is the upper bidiagonal MxN matrix and is stored in the -corresponding elements of matrix A. Matrix Q is represented as a -product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where -H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and -vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is -stored in elements A(i+1:m-1,i). Matrix P is as follows: P = -G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], -u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). - -If M n): m=5, n=6 (m < n): - -( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) -( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) -( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) -( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) -( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) -( v1 v2 v3 v4 v5 ) - -Here vi and ui are vectors which form H(i) and G(i), and d and e - -are the diagonal and off-diagonal elements of matrix B. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -void rmatrixbd(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - /* Real */ ae_vector* taup, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_vector t; - ae_int_t maxmn; - ae_int_t i; - double ltau; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tauq); - ae_vector_clear(taup); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - - /* - * Prepare - */ - if( n<=0||m<=0 ) - { - ae_frame_leave(_state); - return; - } - maxmn = ae_maxint(m, n, _state); - ae_vector_set_length(&work, maxmn+1, _state); - ae_vector_set_length(&t, maxmn+1, _state); - if( m>=n ) - { - ae_vector_set_length(tauq, n, _state); - ae_vector_set_length(taup, n, _state); - } - else - { - ae_vector_set_length(tauq, m, _state); - ae_vector_set_length(taup, m, _state); - } - if( m>=n ) - { - - /* - * Reduce to upper bidiagonal form - */ - for(i=0; i<=n-1; i++) - { - - /* - * Generate elementary reflector H(i) to annihilate A(i+1:m-1,i) - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); - generatereflection(&t, m-i, <au, _state); - tauq->ptr.p_double[i] = ltau; - ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i,m-1)); - t.ptr.p_double[1] = 1; - - /* - * Apply H(i) to A(i:m-1,i+1:n-1) from the left - */ - applyreflectionfromtheleft(a, ltau, &t, i, m-1, i+1, n-1, &work, _state); - if( iptr.pp_double[i][i+1], 1, ae_v_len(1,n-i-1)); - generatereflection(&t, n-1-i, <au, _state); - taup->ptr.p_double[i] = ltau; - ae_v_move(&a->ptr.pp_double[i][i+1], 1, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); - t.ptr.p_double[1] = 1; - - /* - * Apply G(i) to A(i+1:m-1,i+1:n-1) from the right - */ - applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); - } - else - { - taup->ptr.p_double[i] = 0; - } - } - } - else - { - - /* - * Reduce to lower bidiagonal form - */ - for(i=0; i<=m-1; i++) - { - - /* - * Generate elementary reflector G(i) to annihilate A(i,i+1:n-1) - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); - generatereflection(&t, n-i, <au, _state); - taup->ptr.p_double[i] = ltau; - ae_v_move(&a->ptr.pp_double[i][i], 1, &t.ptr.p_double[1], 1, ae_v_len(i,n-1)); - t.ptr.p_double[1] = 1; - - /* - * Apply G(i) to A(i+1:m-1,i:n-1) from the right - */ - applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i, n-1, &work, _state); - if( iptr.pp_double[i+1][i], a->stride, ae_v_len(1,m-1-i)); - generatereflection(&t, m-1-i, <au, _state); - tauq->ptr.p_double[i] = ltau; - ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,m-1)); - t.ptr.p_double[1] = 1; - - /* - * Apply H(i) to A(i+1:m-1,i+1:n-1) from the left - */ - applyreflectionfromtheleft(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); - } - else - { - tauq->ptr.p_double[i] = 0; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix Q which reduces a matrix to bidiagonal form. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - QColumns - required number of columns in matrix Q. - M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array[0..M-1, 0..QColumns-1] - If QColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackq(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - ae_int_t qcolumns, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(q); - - ae_assert(qcolumns<=m, "RMatrixBDUnpackQ: QColumns>M!", _state); - ae_assert(qcolumns>=0, "RMatrixBDUnpackQ: QColumns<0!", _state); - if( (m==0||n==0)||qcolumns==0 ) - { - return; - } - - /* - * prepare Q - */ - ae_matrix_set_length(q, m, qcolumns, _state); - for(i=0; i<=m-1; i++) - { - for(j=0; j<=qcolumns-1; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * Calculate - */ - rmatrixbdmultiplybyq(qp, m, n, tauq, q, m, qcolumns, ae_false, ae_false, _state); -} - - -/************************************************************************* -Multiplication by matrix Q which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by Q or Q'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - Z - multiplied matrix. - array[0..ZRows-1,0..ZColumns-1] - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=M, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=M, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by Q or Q'. - -Output parameters: - Z - product of Z and Q. - Array[0..ZRows-1,0..ZColumns-1] - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyq(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - /* Real */ ae_matrix* z, - ae_int_t zrows, - ae_int_t zcolumns, - ae_bool fromtheright, - ae_bool dotranspose, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t i1; - ae_int_t i2; - ae_int_t istep; - ae_vector v; - ae_vector work; - ae_int_t mx; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) - { - ae_frame_leave(_state); - return; - } - ae_assert((fromtheright&&zcolumns==m)||(!fromtheright&&zrows==m), "RMatrixBDMultiplyByQ: incorrect Z size!", _state); - - /* - * init - */ - mx = ae_maxint(m, n, _state); - mx = ae_maxint(mx, zrows, _state); - mx = ae_maxint(mx, zcolumns, _state); - ae_vector_set_length(&v, mx+1, _state); - ae_vector_set_length(&work, mx+1, _state); - if( m>=n ) - { - - /* - * setup - */ - if( fromtheright ) - { - i1 = 0; - i2 = n-1; - istep = 1; - } - else - { - i1 = n-1; - i2 = 0; - istep = -1; - } - if( dotranspose ) - { - i = i1; - i1 = i2; - i2 = i; - istep = -istep; - } - - /* - * Process - */ - i = i1; - do - { - ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], qp->stride, ae_v_len(1,m-i)); - v.ptr.p_double[1] = 1; - if( fromtheright ) - { - applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i, m-1, &work, _state); - } - else - { - applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i, m-1, 0, zcolumns-1, &work, _state); - } - i = i+istep; - } - while(i!=i2+istep); - } - else - { - - /* - * setup - */ - if( fromtheright ) - { - i1 = 0; - i2 = m-2; - istep = 1; - } - else - { - i1 = m-2; - i2 = 0; - istep = -1; - } - if( dotranspose ) - { - i = i1; - i1 = i2; - i2 = i; - istep = -istep; - } - - /* - * Process - */ - if( m-1>0 ) - { - i = i1; - do - { - ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i+1][i], qp->stride, ae_v_len(1,m-i-1)); - v.ptr.p_double[1] = 1; - if( fromtheright ) - { - applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i+1, m-1, &work, _state); - } - else - { - applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i+1, m-1, 0, zcolumns-1, &work, _state); - } - i = i+istep; - } - while(i!=i2+istep); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix P which reduces matrix A to bidiagonal form. -The subroutine returns transposed matrix P. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of ToBidiagonal subroutine. - PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. - -Output parameters: - PT - first PTRows columns of matrix P^T - Array[0..PTRows-1, 0..N-1] - If PTRows=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackpt(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* taup, - ae_int_t ptrows, - /* Real */ ae_matrix* pt, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(pt); - - ae_assert(ptrows<=n, "RMatrixBDUnpackPT: PTRows>N!", _state); - ae_assert(ptrows>=0, "RMatrixBDUnpackPT: PTRows<0!", _state); - if( (m==0||n==0)||ptrows==0 ) - { - return; - } - - /* - * prepare PT - */ - ae_matrix_set_length(pt, ptrows, n, _state); - for(i=0; i<=ptrows-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - pt->ptr.pp_double[i][j] = 1; - } - else - { - pt->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * Calculate - */ - rmatrixbdmultiplybyp(qp, m, n, taup, pt, ptrows, n, ae_true, ae_true, _state); -} - - -/************************************************************************* -Multiplication by matrix P which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by P or P'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of RMatrixBD subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of RMatrixBD subroutine. - Z - multiplied matrix. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=N, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=N, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by P or P'. - -Output parameters: - Z - product of Z and P. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyp(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* taup, - /* Real */ ae_matrix* z, - ae_int_t zrows, - ae_int_t zcolumns, - ae_bool fromtheright, - ae_bool dotranspose, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector v; - ae_vector work; - ae_int_t mx; - ae_int_t i1; - ae_int_t i2; - ae_int_t istep; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) - { - ae_frame_leave(_state); - return; - } - ae_assert((fromtheright&&zcolumns==n)||(!fromtheright&&zrows==n), "RMatrixBDMultiplyByP: incorrect Z size!", _state); - - /* - * init - */ - mx = ae_maxint(m, n, _state); - mx = ae_maxint(mx, zrows, _state); - mx = ae_maxint(mx, zcolumns, _state); - ae_vector_set_length(&v, mx+1, _state); - ae_vector_set_length(&work, mx+1, _state); - if( m>=n ) - { - - /* - * setup - */ - if( fromtheright ) - { - i1 = n-2; - i2 = 0; - istep = -1; - } - else - { - i1 = 0; - i2 = n-2; - istep = 1; - } - if( !dotranspose ) - { - i = i1; - i1 = i2; - i2 = i; - istep = -istep; - } - - /* - * Process - */ - if( n-1>0 ) - { - i = i1; - do - { - ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i+1], 1, ae_v_len(1,n-1-i)); - v.ptr.p_double[1] = 1; - if( fromtheright ) - { - applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i+1, n-1, &work, _state); - } - else - { - applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i+1, n-1, 0, zcolumns-1, &work, _state); - } - i = i+istep; - } - while(i!=i2+istep); - } - } - else - { - - /* - * setup - */ - if( fromtheright ) - { - i1 = m-1; - i2 = 0; - istep = -1; - } - else - { - i1 = 0; - i2 = m-1; - istep = 1; - } - if( !dotranspose ) - { - i = i1; - i1 = i2; - i2 = i; - istep = -istep; - } - - /* - * Process - */ - i = i1; - do - { - ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); - v.ptr.p_double[1] = 1; - if( fromtheright ) - { - applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i, n-1, &work, _state); - } - else - { - applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i, n-1, 0, zcolumns-1, &work, _state); - } - i = i+istep; - } - while(i!=i2+istep); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking of the main and secondary diagonals of bidiagonal decomposition -of matrix A. - -Input parameters: - B - output of RMatrixBD subroutine. - M - number of rows in matrix B. - N - number of columns in matrix B. - -Output parameters: - IsUpper - True, if the matrix is upper bidiagonal. - otherwise IsUpper is False. - D - the main diagonal. - Array whose index ranges within [0..Min(M,N)-1]. - E - the secondary diagonal (upper or lower, depending on - the value of IsUpper). - Array index ranges within [0..Min(M,N)-1], the last - element is not used. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackdiagonals(/* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t n, - ae_bool* isupper, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state) -{ - ae_int_t i; - - *isupper = ae_false; - ae_vector_clear(d); - ae_vector_clear(e); - - *isupper = m>=n; - if( m<=0||n<=0 ) - { - return; - } - if( *isupper ) - { - ae_vector_set_length(d, n, _state); - ae_vector_set_length(e, n, _state); - for(i=0; i<=n-2; i++) - { - d->ptr.p_double[i] = b->ptr.pp_double[i][i]; - e->ptr.p_double[i] = b->ptr.pp_double[i][i+1]; - } - d->ptr.p_double[n-1] = b->ptr.pp_double[n-1][n-1]; - } - else - { - ae_vector_set_length(d, m, _state); - ae_vector_set_length(e, m, _state); - for(i=0; i<=m-2; i++) - { - d->ptr.p_double[i] = b->ptr.pp_double[i][i]; - e->ptr.p_double[i] = b->ptr.pp_double[i+1][i]; - } - d->ptr.p_double[m-1] = b->ptr.pp_double[m-1][m-1]; - } -} - - -/************************************************************************* -Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, -where Q is an orthogonal matrix, H - Hessenberg matrix. - -Input parameters: - A - matrix A with elements [0..N-1, 0..N-1] - N - size of matrix A. - -Output parameters: - A - matrices Q and P in compact form (see below). - Tau - array of scalar factors which are used to form matrix Q. - Array whose index ranges within [0..N-2] - -Matrix H is located on the main diagonal, on the lower secondary diagonal -and above the main diagonal of matrix A. The elements which are used to -form matrix Q are situated in array Tau and below the lower secondary -diagonal of matrix A as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(n-2), - -where each H(i) is given by - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - is a real vector, -so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void rmatrixhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - double v; - ae_vector t; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "RMatrixHessenberg: incorrect N!", _state); - - /* - * Quick return if possible - */ - if( n<=1 ) - { - ae_frame_leave(_state); - return; - } - ae_vector_set_length(tau, n-2+1, _state); - ae_vector_set_length(&t, n+1, _state); - ae_vector_set_length(&work, n-1+1, _state); - for(i=0; i<=n-2; i++) - { - - /* - * Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - generatereflection(&t, n-i-1, &v, _state); - ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); - tau->ptr.p_double[i] = v; - t.ptr.p_double[1] = 1; - - /* - * Apply H(i) to A(1:ihi,i+1:ihi) from the right - */ - applyreflectionfromtheright(a, v, &t, 0, n-1, i+1, n-1, &work, _state); - - /* - * Apply H(i) to A(i+1:ihi,i+1:n) from the left - */ - applyreflectionfromtheleft(a, v, &t, i+1, n-1, i+1, n-1, &work, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix Q which reduces matrix A to upper Hessenberg form - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - Tau - scalar factors which are used to form Q. - Output of RMatrixHessenberg subroutine. - -Output parameters: - Q - matrix Q. - Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackq(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector v; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - ae_matrix_set_length(q, n-1+1, n-1+1, _state); - ae_vector_set_length(&v, n-1+1, _state); - ae_vector_set_length(&work, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * unpack Q - */ - for(i=0; i<=n-2; i++) - { - - /* - * Apply H(i) - */ - ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - v.ptr.p_double[1] = 1; - applyreflectionfromtheright(q, tau->ptr.p_double[i], &v, 0, n-1, i+1, n-1, &work, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - -Output parameters: - H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackh(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* h, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector v; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(h); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(h, n-1+1, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-2; j++) - { - h->ptr.pp_double[i][j] = 0; - } - j = ae_maxint(0, i-1, _state); - ae_v_move(&h->ptr.pp_double[i][j], 1, &a->ptr.pp_double[i][j], 1, ae_v_len(j,n-1)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Reduction of a symmetric matrix which is given by its higher or lower -triangular part to a tridiagonal matrix using orthogonal similarity -transformation: Q'*A*Q=T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - - where d and e denote diagonal and off-diagonal elements of T, and vi - denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void smatrixtd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tau, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - double alpha; - double taui; - double v; - ae_vector t; - ae_vector t2; - ae_vector t3; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_clear(d); - ae_vector_clear(e); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t3, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&t, n+1, _state); - ae_vector_set_length(&t2, n+1, _state); - ae_vector_set_length(&t3, n+1, _state); - if( n>1 ) - { - ae_vector_set_length(tau, n-2+1, _state); - } - ae_vector_set_length(d, n-1+1, _state); - if( n>1 ) - { - ae_vector_set_length(e, n-2+1, _state); - } - if( isupper ) - { - - /* - * Reduce the upper triangle of A - */ - for(i=n-2; i>=0; i--) - { - - /* - * Generate elementary reflector H() = E - tau * v * v' - */ - if( i>=1 ) - { - ae_v_move(&t.ptr.p_double[2], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(2,i+1)); - } - t.ptr.p_double[1] = a->ptr.pp_double[i][i+1]; - generatereflection(&t, i+1, &taui, _state); - if( i>=1 ) - { - ae_v_move(&a->ptr.pp_double[0][i+1], a->stride, &t.ptr.p_double[2], 1, ae_v_len(0,i-1)); - } - a->ptr.pp_double[i][i+1] = t.ptr.p_double[1]; - e->ptr.p_double[i] = a->ptr.pp_double[i][i+1]; - if( ae_fp_neq(taui,0) ) - { - - /* - * Apply H from both sides to A - */ - a->ptr.pp_double[i][i+1] = 1; - - /* - * Compute x := tau * A * v storing x in TAU - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); - symmetricmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t3, _state); - ae_v_move(&tau->ptr.p_double[0], 1, &t3.ptr.p_double[1], 1, ae_v_len(0,i)); - - /* - * Compute w := x - 1/2 * tau * (x'*v) * v - */ - v = ae_v_dotproduct(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i)); - alpha = -0.5*taui*v; - ae_v_addd(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i), alpha); - - /* - * Apply the transformation as a rank-2 update: - * A := A - v * w' - w * v' - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); - ae_v_move(&t3.ptr.p_double[1], 1, &tau->ptr.p_double[0], 1, ae_v_len(1,i+1)); - symmetricrank2update(a, isupper, 0, i, &t, &t3, &t2, -1, _state); - a->ptr.pp_double[i][i+1] = e->ptr.p_double[i]; - } - d->ptr.p_double[i+1] = a->ptr.pp_double[i+1][i+1]; - tau->ptr.p_double[i] = taui; - } - d->ptr.p_double[0] = a->ptr.pp_double[0][0]; - } - else - { - - /* - * Reduce the lower triangle of A - */ - for(i=0; i<=n-2; i++) - { - - /* - * Generate elementary reflector H = E - tau * v * v' - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - generatereflection(&t, n-i-1, &taui, _state); - ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); - e->ptr.p_double[i] = a->ptr.pp_double[i+1][i]; - if( ae_fp_neq(taui,0) ) - { - - /* - * Apply H from both sides to A - */ - a->ptr.pp_double[i+1][i] = 1; - - /* - * Compute x := tau * A * v storing y in TAU - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - symmetricmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); - ae_v_move(&tau->ptr.p_double[i], 1, &t2.ptr.p_double[1], 1, ae_v_len(i,n-2)); - - /* - * Compute w := x - 1/2 * tau * (x'*v) * v - */ - v = ae_v_dotproduct(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2)); - alpha = -0.5*taui*v; - ae_v_addd(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2), alpha); - - /* - * Apply the transformation as a rank-2 update: - * A := A - v * w' - w * v' - * - */ - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - ae_v_move(&t2.ptr.p_double[1], 1, &tau->ptr.p_double[i], 1, ae_v_len(1,n-i-1)); - symmetricrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, -1, _state); - a->ptr.pp_double[i+1][i] = e->ptr.p_double[i]; - } - d->ptr.p_double[i] = a->ptr.pp_double[i][i]; - tau->ptr.p_double[i] = taui; - } - d->ptr.p_double[n-1] = a->ptr.pp_double[n-1][n-1]; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix Q which reduces symmetric matrix to a tridiagonal -form. - -Input parameters: - A - the result of a SMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of SMatrixTD subroutine) - Tau - the result of a SMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void smatrixtdunpackq(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector v; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - ae_matrix_set_length(q, n-1+1, n-1+1, _state); - ae_vector_set_length(&v, n+1, _state); - ae_vector_set_length(&work, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * unpack Q - */ - if( isupper ) - { - for(i=0; i<=n-2; i++) - { - - /* - * Apply H(i) - */ - ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); - v.ptr.p_double[i+1] = 1; - applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, 0, i, 0, n-1, &work, _state); - } - } - else - { - for(i=n-2; i>=0; i--) - { - - /* - * Apply H(i) - */ - ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); - v.ptr.p_double[1] = 1; - applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, i+1, n-1, 0, n-1, &work, _state); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Reduction of a Hermitian matrix which is given by its higher or lower -triangular part to a real tridiagonal matrix using unitary similarity -transformation: Q'*A*Q = T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of real symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of real symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - -where d and e denote diagonal and off-diagonal elements of T, and vi -denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void hmatrixtd(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tau, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_complex alpha; - ae_complex taui; - ae_complex v; - ae_vector t; - ae_vector t2; - ae_vector t3; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_clear(d); - ae_vector_clear(e); - ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t2, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&t3, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - ae_assert(ae_fp_eq(a->ptr.pp_complex[i][i].y,0), "Assertion failed", _state); - } - if( n>1 ) - { - ae_vector_set_length(tau, n-2+1, _state); - ae_vector_set_length(e, n-2+1, _state); - } - ae_vector_set_length(d, n-1+1, _state); - ae_vector_set_length(&t, n-1+1, _state); - ae_vector_set_length(&t2, n-1+1, _state); - ae_vector_set_length(&t3, n-1+1, _state); - if( isupper ) - { - - /* - * Reduce the upper triangle of A - */ - a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(a->ptr.pp_complex[n-1][n-1].x); - for(i=n-2; i>=0; i--) - { - - /* - * Generate elementary reflector H = I+1 - tau * v * v' - */ - alpha = a->ptr.pp_complex[i][i+1]; - t.ptr.p_complex[1] = alpha; - if( i>=1 ) - { - ae_v_cmove(&t.ptr.p_complex[2], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(2,i+1)); - } - complexgeneratereflection(&t, i+1, &taui, _state); - if( i>=1 ) - { - ae_v_cmove(&a->ptr.pp_complex[0][i+1], a->stride, &t.ptr.p_complex[2], 1, "N", ae_v_len(0,i-1)); - } - alpha = t.ptr.p_complex[1]; - e->ptr.p_double[i] = alpha.x; - if( ae_c_neq_d(taui,0) ) - { - - /* - * Apply H(I+1) from both sides to A - */ - a->ptr.pp_complex[i][i+1] = ae_complex_from_d(1); - - /* - * Compute x := tau * A * v storing x in TAU - */ - ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); - hermitianmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t2, _state); - ae_v_cmove(&tau->ptr.p_complex[0], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(0,i)); - - /* - * Compute w := x - 1/2 * tau * (x'*v) * v - */ - v = ae_v_cdotproduct(&tau->ptr.p_complex[0], 1, "Conj", &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i)); - alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); - ae_v_caddc(&tau->ptr.p_complex[0], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i), alpha); - - /* - * Apply the transformation as a rank-2 update: - * A := A - v * w' - w * v' - */ - ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); - ae_v_cmove(&t3.ptr.p_complex[1], 1, &tau->ptr.p_complex[0], 1, "N", ae_v_len(1,i+1)); - hermitianrank2update(a, isupper, 0, i, &t, &t3, &t2, ae_complex_from_d(-1), _state); - } - else - { - a->ptr.pp_complex[i][i] = ae_complex_from_d(a->ptr.pp_complex[i][i].x); - } - a->ptr.pp_complex[i][i+1] = ae_complex_from_d(e->ptr.p_double[i]); - d->ptr.p_double[i+1] = a->ptr.pp_complex[i+1][i+1].x; - tau->ptr.p_complex[i] = taui; - } - d->ptr.p_double[0] = a->ptr.pp_complex[0][0].x; - } - else - { - - /* - * Reduce the lower triangle of A - */ - a->ptr.pp_complex[0][0] = ae_complex_from_d(a->ptr.pp_complex[0][0].x); - for(i=0; i<=n-2; i++) - { - - /* - * Generate elementary reflector H = I - tau * v * v' - */ - ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); - complexgeneratereflection(&t, n-i-1, &taui, _state); - ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &t.ptr.p_complex[1], 1, "N", ae_v_len(i+1,n-1)); - e->ptr.p_double[i] = a->ptr.pp_complex[i+1][i].x; - if( ae_c_neq_d(taui,0) ) - { - - /* - * Apply H(i) from both sides to A(i+1:n,i+1:n) - */ - a->ptr.pp_complex[i+1][i] = ae_complex_from_d(1); - - /* - * Compute x := tau * A * v storing y in TAU - */ - ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); - hermitianmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); - ae_v_cmove(&tau->ptr.p_complex[i], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(i,n-2)); - - /* - * Compute w := x - 1/2 * tau * (x'*v) * v - */ - v = ae_v_cdotproduct(&tau->ptr.p_complex[i], 1, "Conj", &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2)); - alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); - ae_v_caddc(&tau->ptr.p_complex[i], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2), alpha); - - /* - * Apply the transformation as a rank-2 update: - * A := A - v * w' - w * v' - */ - ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); - ae_v_cmove(&t2.ptr.p_complex[1], 1, &tau->ptr.p_complex[i], 1, "N", ae_v_len(1,n-i-1)); - hermitianrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, ae_complex_from_d(-1), _state); - } - else - { - a->ptr.pp_complex[i+1][i+1] = ae_complex_from_d(a->ptr.pp_complex[i+1][i+1].x); - } - a->ptr.pp_complex[i+1][i] = ae_complex_from_d(e->ptr.p_double[i]); - d->ptr.p_double[i] = a->ptr.pp_complex[i][i].x; - tau->ptr.p_complex[i] = taui; - } - d->ptr.p_double[n-1] = a->ptr.pp_complex[n-1][n-1].x; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal -form. - -Input parameters: - A - the result of a HMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of HMatrixTD subroutine) - Tau - the result of a HMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void hmatrixtdunpackq(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tau, - /* Complex */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector v; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); - - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - ae_matrix_set_length(q, n-1+1, n-1+1, _state); - ae_vector_set_length(&v, n+1, _state); - ae_vector_set_length(&work, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(1); - } - else - { - q->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - - /* - * unpack Q - */ - if( isupper ) - { - for(i=0; i<=n-2; i++) - { - - /* - * Apply H(i) - */ - ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); - v.ptr.p_complex[i+1] = ae_complex_from_d(1); - complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, 0, i, 0, n-1, &work, _state); - } - } - else - { - for(i=n-2; i>=0; i--) - { - - /* - * Apply H(i) - */ - ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); - v.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, i+1, n-1, 0, n-1, &work, _state); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Base case for complex QR - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* work, - /* Complex */ ae_vector* t, - /* Complex */ ae_vector* tau, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_int_t mmi; - ae_int_t minmn; - ae_complex tmp; - - - minmn = ae_minint(m, n, _state); - if( minmn<=0 ) - { - return; - } - - /* - * Test the input arguments - */ - k = ae_minint(m, n, _state); - for(i=0; i<=k-1; i++) - { - - /* - * Generate elementary reflector H(i) to annihilate A(i+1:m,i) - */ - mmi = m-i; - ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], a->stride, "N", ae_v_len(1,mmi)); - complexgeneratereflection(t, mmi, &tmp, _state); - tau->ptr.p_complex[i] = tmp; - ae_v_cmove(&a->ptr.pp_complex[i][i], a->stride, &t->ptr.p_complex[1], 1, "N", ae_v_len(i,m-1)); - t->ptr.p_complex[1] = ae_complex_from_d(1); - if( iptr.p_complex[i], _state), t, i, m-1, i+1, n-1, work, _state); - } - } -} - - -/************************************************************************* -Base case for complex LQ - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* work, - /* Complex */ ae_vector* t, - /* Complex */ ae_vector* tau, - ae_state *_state) -{ - ae_int_t i; - ae_int_t minmn; - ae_complex tmp; - - - minmn = ae_minint(m, n, _state); - if( minmn<=0 ) - { - return; - } - - /* - * Test the input arguments - */ - for(i=0; i<=minmn-1; i++) - { - - /* - * Generate elementary reflector H(i) - * - * NOTE: ComplexGenerateReflection() generates left reflector, - * i.e. H which reduces x by applyiong from the left, but we - * need RIGHT reflector. So we replace H=E-tau*v*v' by H^H, - * which changes v to conj(v). - */ - ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,n-i)); - complexgeneratereflection(t, n-i, &tmp, _state); - tau->ptr.p_complex[i] = tmp; - ae_v_cmove(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[1], 1, "Conj", ae_v_len(i,n-1)); - t->ptr.p_complex[1] = ae_complex_from_d(1); - if( iptr.p_complex[i], t, i+1, m-1, i, n-1, work, _state); - } - } -} - - -/************************************************************************* -Generate block reflector: -* fill unused parts of reflectors matrix by zeros -* fill diagonal of reflectors matrix by ones -* generate triangular factor T - -PARAMETERS: - A - either LengthA*BlockSize (if ColumnwiseA) or - BlockSize*LengthA (if not ColumnwiseA) matrix of - elementary reflectors. - Modified on exit. - Tau - scalar factors - ColumnwiseA - reflectors are stored in rows or in columns - LengthA - length of largest reflector - BlockSize - number of reflectors - T - array[BlockSize,2*BlockSize]. Left BlockSize*BlockSize - submatrix stores triangular factor on exit. - WORK - array[BlockSize] - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, - /* Real */ ae_vector* tau, - ae_bool columnwisea, - ae_int_t lengtha, - ae_int_t blocksize, - /* Real */ ae_matrix* t, - /* Real */ ae_vector* work, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - - - - /* - * fill beginning of new column with zeros, - * load 1.0 in the first non-zero element - */ - for(k=0; k<=blocksize-1; k++) - { - if( columnwisea ) - { - for(i=0; i<=k-1; i++) - { - a->ptr.pp_double[i][k] = 0; - } - } - else - { - for(i=0; i<=k-1; i++) - { - a->ptr.pp_double[k][i] = 0; - } - } - a->ptr.pp_double[k][k] = 1; - } - - /* - * Calculate Gram matrix of A - */ - for(i=0; i<=blocksize-1; i++) - { - for(j=0; j<=blocksize-1; j++) - { - t->ptr.pp_double[i][blocksize+j] = 0; - } - } - for(k=0; k<=lengtha-1; k++) - { - for(j=1; j<=blocksize-1; j++) - { - if( columnwisea ) - { - v = a->ptr.pp_double[k][j]; - if( ae_fp_neq(v,0) ) - { - ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[k][0], 1, ae_v_len(blocksize,blocksize+j-1), v); - } - } - else - { - v = a->ptr.pp_double[j][k]; - if( ae_fp_neq(v,0) ) - { - ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[0][k], a->stride, ae_v_len(blocksize,blocksize+j-1), v); - } - } - } - } - - /* - * Prepare Y (stored in TmpA) and T (stored in TmpT) - */ - for(k=0; k<=blocksize-1; k++) - { - - /* - * fill non-zero part of T, use pre-calculated Gram matrix - */ - ae_v_move(&work->ptr.p_double[0], 1, &t->ptr.pp_double[k][blocksize], 1, ae_v_len(0,k-1)); - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&t->ptr.pp_double[i][i], 1, &work->ptr.p_double[i], 1, ae_v_len(i,k-1)); - t->ptr.pp_double[i][k] = -tau->ptr.p_double[k]*v; - } - t->ptr.pp_double[k][k] = -tau->ptr.p_double[k]; - - /* - * Rest of T is filled by zeros - */ - for(i=k+1; i<=blocksize-1; i++) - { - t->ptr.pp_double[i][k] = 0; - } - } -} - - -/************************************************************************* -Generate block reflector (complex): -* fill unused parts of reflectors matrix by zeros -* fill diagonal of reflectors matrix by ones -* generate triangular factor T - - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, - /* Complex */ ae_vector* tau, - ae_bool columnwisea, - ae_int_t lengtha, - ae_int_t blocksize, - /* Complex */ ae_matrix* t, - /* Complex */ ae_vector* work, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - ae_complex v; - - - - /* - * Prepare Y (stored in TmpA) and T (stored in TmpT) - */ - for(k=0; k<=blocksize-1; k++) - { - - /* - * fill beginning of new column with zeros, - * load 1.0 in the first non-zero element - */ - if( columnwisea ) - { - for(i=0; i<=k-1; i++) - { - a->ptr.pp_complex[i][k] = ae_complex_from_d(0); - } - } - else - { - for(i=0; i<=k-1; i++) - { - a->ptr.pp_complex[k][i] = ae_complex_from_d(0); - } - } - a->ptr.pp_complex[k][k] = ae_complex_from_d(1); - - /* - * fill non-zero part of T, - */ - for(i=0; i<=k-1; i++) - { - if( columnwisea ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[k][i], a->stride, "Conj", &a->ptr.pp_complex[k][k], a->stride, "N", ae_v_len(k,lengtha-1)); - } - else - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[i][k], 1, "N", &a->ptr.pp_complex[k][k], 1, "Conj", ae_v_len(k,lengtha-1)); - } - work->ptr.p_complex[i] = v; - } - for(i=0; i<=k-1; i++) - { - v = ae_v_cdotproduct(&t->ptr.pp_complex[i][i], 1, "N", &work->ptr.p_complex[i], 1, "N", ae_v_len(i,k-1)); - t->ptr.pp_complex[i][k] = ae_c_neg(ae_c_mul(tau->ptr.p_complex[k],v)); - } - t->ptr.pp_complex[k][k] = ae_c_neg(tau->ptr.p_complex[k]); - - /* - * Rest of T is filled by zeros - */ - for(i=k+1; i<=blocksize-1; i++) - { - t->ptr.pp_complex[i][k] = ae_complex_from_d(0); - } - } -} - - - - -/************************************************************************* -Singular value decomposition of a bidiagonal matrix (extended algorithm) - -The algorithm performs the singular value decomposition of a bidiagonal -matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - -orthogonal matrices, S - diagonal matrix with non-negative elements on the -main diagonal, in descending order. - -The algorithm finds singular values. In addition, the algorithm can -calculate matrices Q and P (more precisely, not the matrices, but their -product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, -matrices U and VT can be of any type, including identity. Furthermore, the -algorithm can calculate Q'*C (this product is calculated more effectively -than U*Q, because this calculation operates with rows instead of matrix -columns). - -The feature of the algorithm is its ability to find all singular values -including those which are arbitrarily close to 0 with relative accuracy -close to machine precision. If the parameter IsFractionalAccuracyRequired -is set to True, all singular values will have high relative accuracy close -to machine precision. If the parameter is set to False, only the biggest -singular value will have relative accuracy close to machine precision. -The absolute error of other singular values is equal to the absolute error -of the biggest singular value. - -Input parameters: - D - main diagonal of matrix B. - Array whose index ranges within [0..N-1]. - E - superdiagonal (or subdiagonal) of matrix B. - Array whose index ranges within [0..N-2]. - N - size of matrix B. - IsUpper - True, if the matrix is upper bidiagonal. - IsFractionalAccuracyRequired - - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 - SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. - U - matrix to be multiplied by Q. - Array whose indexes range within [0..NRU-1, 0..N-1]. - The matrix can be bigger, in that case only the submatrix - [0..NRU-1, 0..N-1] will be multiplied by Q. - NRU - number of rows in matrix U. - C - matrix to be multiplied by Q'. - Array whose indexes range within [0..N-1, 0..NCC-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCC-1] will be multiplied by Q'. - NCC - number of columns in matrix C. - VT - matrix to be multiplied by P^T. - Array whose indexes range within [0..N-1, 0..NCVT-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCVT-1] will be multiplied by P^T. - NCVT - number of columns in matrix VT. - -Output parameters: - D - singular values of matrix B in descending order. - U - if NRU>0, contains matrix U*Q. - VT - if NCVT>0, contains matrix (P^T)*VT. - C - if NCC>0, contains matrix Q'*C. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Additional information: - The type of convergence is controlled by the internal parameter TOL. - If the parameter is greater than 0, the singular values will have - relative accuracy TOL. If TOL<0, the singular values will have - absolute accuracy ABS(TOL)*norm(B). - By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, - where Epsilon is the machine precision. It is not recommended to use - TOL less than 10*Epsilon since this will considerably slow down the - algorithm and may not lead to error decreasing. -History: - * 31 March, 2007. - changed MAXITR from 6 to 12. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1999. -*************************************************************************/ -ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t ncvt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_vector d1; - ae_vector e1; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&d1, n+1, _state); - ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); - if( n>1 ) - { - ae_vector_set_length(&e1, n-1+1, _state); - ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); - } - result = bdsvd_bidiagonalsvddecompositioninternal(&d1, &e1, n, isupper, isfractionalaccuracyrequired, u, 0, nru, c, 0, ncc, vt, 0, ncvt, _state); - ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); - return result; -} - - -ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t ncvt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - - result = bdsvd_bidiagonalsvddecompositioninternal(d, e, n, isupper, isfractionalaccuracyrequired, u, 1, nru, c, 1, ncc, vt, 1, ncvt, _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Internal working subroutine for bidiagonal decomposition -*************************************************************************/ -static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t ustart, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t cstart, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t vstart, - ae_int_t ncvt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_int_t i; - ae_int_t idir; - ae_int_t isub; - ae_int_t iter; - ae_int_t j; - ae_int_t ll; - ae_int_t lll; - ae_int_t m; - ae_int_t maxit; - ae_int_t oldll; - ae_int_t oldm; - double abse; - double abss; - double cosl; - double cosr; - double cs; - double eps; - double f; - double g; - double h; - double mu; - double oldcs; - double oldsn; - double r; - double shift; - double sigmn; - double sigmx; - double sinl; - double sinr; - double sll; - double smax; - double smin; - double sminl; - double sminoa; - double sn; - double thresh; - double tol; - double tolmul; - double unfl; - ae_vector work0; - ae_vector work1; - ae_vector work2; - ae_vector work3; - ae_int_t maxitr; - ae_bool matrixsplitflag; - ae_bool iterflag; - ae_vector utemp; - ae_vector vttemp; - ae_vector ctemp; - ae_vector etemp; - ae_bool fwddir; - double tmp; - ae_int_t mm1; - ae_int_t mm0; - ae_bool bchangedir; - ae_int_t uend; - ae_int_t cend; - ae_int_t vend; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_init(&work0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&utemp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&vttemp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ctemp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&etemp, 0, DT_REAL, _state, ae_true); - - result = ae_true; - if( n==0 ) - { - ae_frame_leave(_state); - return result; - } - if( n==1 ) - { - if( ae_fp_less(d->ptr.p_double[1],0) ) - { - d->ptr.p_double[1] = -d->ptr.p_double[1]; - if( ncvt>0 ) - { - ae_v_muld(&vt->ptr.pp_double[vstart][vstart], 1, ae_v_len(vstart,vstart+ncvt-1), -1); - } - } - ae_frame_leave(_state); - return result; - } - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - ll = 0; - oldsn = 0; - - /* - * init - */ - ae_vector_set_length(&work0, n-1+1, _state); - ae_vector_set_length(&work1, n-1+1, _state); - ae_vector_set_length(&work2, n-1+1, _state); - ae_vector_set_length(&work3, n-1+1, _state); - uend = ustart+ae_maxint(nru-1, 0, _state); - vend = vstart+ae_maxint(ncvt-1, 0, _state); - cend = cstart+ae_maxint(ncc-1, 0, _state); - ae_vector_set_length(&utemp, uend+1, _state); - ae_vector_set_length(&vttemp, vend+1, _state); - ae_vector_set_length(&ctemp, cend+1, _state); - maxitr = 12; - fwddir = ae_true; - - /* - * resize E from N-1 to N - */ - ae_vector_set_length(&etemp, n+1, _state); - for(i=1; i<=n-1; i++) - { - etemp.ptr.p_double[i] = e->ptr.p_double[i]; - } - ae_vector_set_length(e, n+1, _state); - for(i=1; i<=n-1; i++) - { - e->ptr.p_double[i] = etemp.ptr.p_double[i]; - } - e->ptr.p_double[n] = 0; - idir = 0; - - /* - * Get machine constants - */ - eps = ae_machineepsilon; - unfl = ae_minrealnumber; - - /* - * If matrix lower bidiagonal, rotate to be upper bidiagonal - * by applying Givens rotations on the left - */ - if( !isupper ) - { - for(i=1; i<=n-1; i++) - { - generaterotation(d->ptr.p_double[i], e->ptr.p_double[i], &cs, &sn, &r, _state); - d->ptr.p_double[i] = r; - e->ptr.p_double[i] = sn*d->ptr.p_double[i+1]; - d->ptr.p_double[i+1] = cs*d->ptr.p_double[i+1]; - work0.ptr.p_double[i] = cs; - work1.ptr.p_double[i] = sn; - } - - /* - * Update singular vectors if desired - */ - if( nru>0 ) - { - applyrotationsfromtheright(fwddir, ustart, uend, 1+ustart-1, n+ustart-1, &work0, &work1, u, &utemp, _state); - } - if( ncc>0 ) - { - applyrotationsfromtheleft(fwddir, 1+cstart-1, n+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); - } - } - - /* - * Compute singular values to relative accuracy TOL - * (By setting TOL to be negative, algorithm will compute - * singular values to absolute accuracy ABS(TOL)*norm(input matrix)) - */ - tolmul = ae_maxreal(10, ae_minreal(100, ae_pow(eps, -0.125, _state), _state), _state); - tol = tolmul*eps; - - /* - * Compute approximate maximum, minimum singular values - */ - smax = 0; - for(i=1; i<=n; i++) - { - smax = ae_maxreal(smax, ae_fabs(d->ptr.p_double[i], _state), _state); - } - for(i=1; i<=n-1; i++) - { - smax = ae_maxreal(smax, ae_fabs(e->ptr.p_double[i], _state), _state); - } - sminl = 0; - if( ae_fp_greater_eq(tol,0) ) - { - - /* - * Relative accuracy desired - */ - sminoa = ae_fabs(d->ptr.p_double[1], _state); - if( ae_fp_neq(sminoa,0) ) - { - mu = sminoa; - for(i=2; i<=n; i++) - { - mu = ae_fabs(d->ptr.p_double[i], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[i-1], _state))); - sminoa = ae_minreal(sminoa, mu, _state); - if( ae_fp_eq(sminoa,0) ) - { - break; - } - } - } - sminoa = sminoa/ae_sqrt(n, _state); - thresh = ae_maxreal(tol*sminoa, maxitr*n*n*unfl, _state); - } - else - { - - /* - * Absolute accuracy desired - */ - thresh = ae_maxreal(ae_fabs(tol, _state)*smax, maxitr*n*n*unfl, _state); - } - - /* - * Prepare for main iteration loop for the singular values - * (MAXIT is the maximum number of passes through the inner - * loop permitted before nonconvergence signalled.) - */ - maxit = maxitr*n*n; - iter = 0; - oldll = -1; - oldm = -1; - - /* - * M points to last element of unconverged part of matrix - */ - m = n; - - /* - * Begin main iteration loop - */ - for(;;) - { - - /* - * Check for convergence or exceeding iteration count - */ - if( m<=1 ) - { - break; - } - if( iter>maxit ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Find diagonal block of matrix to work on - */ - if( ae_fp_less(tol,0)&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[m], _state),thresh) ) - { - d->ptr.p_double[m] = 0; - } - smax = ae_fabs(d->ptr.p_double[m], _state); - smin = smax; - matrixsplitflag = ae_false; - for(lll=1; lll<=m-1; lll++) - { - ll = m-lll; - abss = ae_fabs(d->ptr.p_double[ll], _state); - abse = ae_fabs(e->ptr.p_double[ll], _state); - if( ae_fp_less(tol,0)&&ae_fp_less_eq(abss,thresh) ) - { - d->ptr.p_double[ll] = 0; - } - if( ae_fp_less_eq(abse,thresh) ) - { - matrixsplitflag = ae_true; - break; - } - smin = ae_minreal(smin, abss, _state); - smax = ae_maxreal(smax, ae_maxreal(abss, abse, _state), _state); - } - if( !matrixsplitflag ) - { - ll = 0; - } - else - { - - /* - * Matrix splits since E(LL) = 0 - */ - e->ptr.p_double[ll] = 0; - if( ll==m-1 ) - { - - /* - * Convergence of bottom singular value, return to top of loop - */ - m = m-1; - continue; - } - } - ll = ll+1; - - /* - * E(LL) through E(M-1) are nonzero, E(LL-1) is zero - */ - if( ll==m-1 ) - { - - /* - * 2 by 2 block, handle separately - */ - bdsvd_svdv2x2(d->ptr.p_double[m-1], e->ptr.p_double[m-1], d->ptr.p_double[m], &sigmn, &sigmx, &sinr, &cosr, &sinl, &cosl, _state); - d->ptr.p_double[m-1] = sigmx; - e->ptr.p_double[m-1] = 0; - d->ptr.p_double[m] = sigmn; - - /* - * Compute singular vectors, if desired - */ - if( ncvt>0 ) - { - mm0 = m+(vstart-1); - mm1 = m-1+(vstart-1); - ae_v_moved(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), cosr); - ae_v_addd(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), sinr); - ae_v_muld(&vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), cosr); - ae_v_subd(&vt->ptr.pp_double[mm0][vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), sinr); - ae_v_move(&vt->ptr.pp_double[mm1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); - } - if( nru>0 ) - { - mm0 = m+ustart-1; - mm1 = m-1+ustart-1; - ae_v_moved(&utemp.ptr.p_double[ustart], 1, &u->ptr.pp_double[ustart][mm1], u->stride, ae_v_len(ustart,uend), cosl); - ae_v_addd(&utemp.ptr.p_double[ustart], 1, &u->ptr.pp_double[ustart][mm0], u->stride, ae_v_len(ustart,uend), sinl); - ae_v_muld(&u->ptr.pp_double[ustart][mm0], u->stride, ae_v_len(ustart,uend), cosl); - ae_v_subd(&u->ptr.pp_double[ustart][mm0], u->stride, &u->ptr.pp_double[ustart][mm1], u->stride, ae_v_len(ustart,uend), sinl); - ae_v_move(&u->ptr.pp_double[ustart][mm1], u->stride, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); - } - if( ncc>0 ) - { - mm0 = m+cstart-1; - mm1 = m-1+cstart-1; - ae_v_moved(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), cosl); - ae_v_addd(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), sinl); - ae_v_muld(&c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), cosl); - ae_v_subd(&c->ptr.pp_double[mm0][cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), sinl); - ae_v_move(&c->ptr.pp_double[mm1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); - } - m = m-2; - continue; - } - - /* - * If working on new submatrix, choose shift direction - * (from larger end diagonal element towards smaller) - * - * Previously was - * "if (LL>OLDM) or (M - * Very strange that LAPACK still contains it. - */ - bchangedir = ae_false; - if( idir==1&&ae_fp_less(ae_fabs(d->ptr.p_double[ll], _state),1.0E-3*ae_fabs(d->ptr.p_double[m], _state)) ) - { - bchangedir = ae_true; - } - if( idir==2&&ae_fp_less(ae_fabs(d->ptr.p_double[m], _state),1.0E-3*ae_fabs(d->ptr.p_double[ll], _state)) ) - { - bchangedir = ae_true; - } - if( (ll!=oldll||m!=oldm)||bchangedir ) - { - if( ae_fp_greater_eq(ae_fabs(d->ptr.p_double[ll], _state),ae_fabs(d->ptr.p_double[m], _state)) ) - { - - /* - * Chase bulge from top (big end) to bottom (small end) - */ - idir = 1; - } - else - { - - /* - * Chase bulge from bottom (big end) to top (small end) - */ - idir = 2; - } - } - - /* - * Apply convergence tests - */ - if( idir==1 ) - { - - /* - * Run convergence test in forward direction - * First apply standard test to bottom of matrix - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[m], _state))||(ae_fp_less(tol,0)&&ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh)) ) - { - e->ptr.p_double[m-1] = 0; - continue; - } - if( ae_fp_greater_eq(tol,0) ) - { - - /* - * If relative accuracy desired, - * apply convergence criterion forward - */ - mu = ae_fabs(d->ptr.p_double[ll], _state); - sminl = mu; - iterflag = ae_false; - for(lll=ll; lll<=m-1; lll++) - { - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[lll], _state),tol*mu) ) - { - e->ptr.p_double[lll] = 0; - iterflag = ae_true; - break; - } - mu = ae_fabs(d->ptr.p_double[lll+1], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[lll], _state))); - sminl = ae_minreal(sminl, mu, _state); - } - if( iterflag ) - { - continue; - } - } - } - else - { - - /* - * Run convergence test in backward direction - * First apply standard test to top of matrix - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[ll], _state))||(ae_fp_less(tol,0)&&ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh)) ) - { - e->ptr.p_double[ll] = 0; - continue; - } - if( ae_fp_greater_eq(tol,0) ) - { - - /* - * If relative accuracy desired, - * apply convergence criterion backward - */ - mu = ae_fabs(d->ptr.p_double[m], _state); - sminl = mu; - iterflag = ae_false; - for(lll=m-1; lll>=ll; lll--) - { - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[lll], _state),tol*mu) ) - { - e->ptr.p_double[lll] = 0; - iterflag = ae_true; - break; - } - mu = ae_fabs(d->ptr.p_double[lll], _state)*(mu/(mu+ae_fabs(e->ptr.p_double[lll], _state))); - sminl = ae_minreal(sminl, mu, _state); - } - if( iterflag ) - { - continue; - } - } - } - oldll = ll; - oldm = m; - - /* - * Compute shift. First, test if shifting would ruin relative - * accuracy, and if so set the shift to zero. - */ - if( ae_fp_greater_eq(tol,0)&&ae_fp_less_eq(n*tol*(sminl/smax),ae_maxreal(eps, 0.01*tol, _state)) ) - { - - /* - * Use a zero shift to avoid loss of relative accuracy - */ - shift = 0; - } - else - { - - /* - * Compute the shift from 2-by-2 block at end of matrix - */ - if( idir==1 ) - { - sll = ae_fabs(d->ptr.p_double[ll], _state); - bdsvd_svd2x2(d->ptr.p_double[m-1], e->ptr.p_double[m-1], d->ptr.p_double[m], &shift, &r, _state); - } - else - { - sll = ae_fabs(d->ptr.p_double[m], _state); - bdsvd_svd2x2(d->ptr.p_double[ll], e->ptr.p_double[ll], d->ptr.p_double[ll+1], &shift, &r, _state); - } - - /* - * Test if shift negligible, and if so set to zero - */ - if( ae_fp_greater(sll,0) ) - { - if( ae_fp_less(ae_sqr(shift/sll, _state),eps) ) - { - shift = 0; - } - } - } - - /* - * Increment iteration count - */ - iter = iter+m-ll; - - /* - * If SHIFT = 0, do simplified QR iteration - */ - if( ae_fp_eq(shift,0) ) - { - if( idir==1 ) - { - - /* - * Chase bulge from top to bottom - * Save cosines and sines for later singular vector updates - */ - cs = 1; - oldcs = 1; - for(i=ll; i<=m-1; i++) - { - generaterotation(d->ptr.p_double[i]*cs, e->ptr.p_double[i], &cs, &sn, &r, _state); - if( i>ll ) - { - e->ptr.p_double[i-1] = oldsn*r; - } - generaterotation(oldcs*r, d->ptr.p_double[i+1]*sn, &oldcs, &oldsn, &tmp, _state); - d->ptr.p_double[i] = tmp; - work0.ptr.p_double[i-ll+1] = cs; - work1.ptr.p_double[i-ll+1] = sn; - work2.ptr.p_double[i-ll+1] = oldcs; - work3.ptr.p_double[i-ll+1] = oldsn; - } - h = d->ptr.p_double[m]*cs; - d->ptr.p_double[m] = h*oldcs; - e->ptr.p_double[m-1] = h*oldsn; - - /* - * Update singular vectors - */ - if( ncvt>0 ) - { - applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); - } - if( nru>0 ) - { - applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, &work2, &work3, u, &utemp, _state); - } - if( ncc>0 ) - { - applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); - } - - /* - * Test convergence - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh) ) - { - e->ptr.p_double[m-1] = 0; - } - } - else - { - - /* - * Chase bulge from bottom to top - * Save cosines and sines for later singular vector updates - */ - cs = 1; - oldcs = 1; - for(i=m; i>=ll+1; i--) - { - generaterotation(d->ptr.p_double[i]*cs, e->ptr.p_double[i-1], &cs, &sn, &r, _state); - if( iptr.p_double[i] = oldsn*r; - } - generaterotation(oldcs*r, d->ptr.p_double[i-1]*sn, &oldcs, &oldsn, &tmp, _state); - d->ptr.p_double[i] = tmp; - work0.ptr.p_double[i-ll] = cs; - work1.ptr.p_double[i-ll] = -sn; - work2.ptr.p_double[i-ll] = oldcs; - work3.ptr.p_double[i-ll] = -oldsn; - } - h = d->ptr.p_double[ll]*cs; - d->ptr.p_double[ll] = h*oldcs; - e->ptr.p_double[ll] = h*oldsn; - - /* - * Update singular vectors - */ - if( ncvt>0 ) - { - applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); - } - if( nru>0 ) - { - applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, &work0, &work1, u, &utemp, _state); - } - if( ncc>0 ) - { - applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); - } - - /* - * Test convergence - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh) ) - { - e->ptr.p_double[ll] = 0; - } - } - } - else - { - - /* - * Use nonzero shift - */ - if( idir==1 ) - { - - /* - * Chase bulge from top to bottom - * Save cosines and sines for later singular vector updates - */ - f = (ae_fabs(d->ptr.p_double[ll], _state)-shift)*(bdsvd_extsignbdsqr(1, d->ptr.p_double[ll], _state)+shift/d->ptr.p_double[ll]); - g = e->ptr.p_double[ll]; - for(i=ll; i<=m-1; i++) - { - generaterotation(f, g, &cosr, &sinr, &r, _state); - if( i>ll ) - { - e->ptr.p_double[i-1] = r; - } - f = cosr*d->ptr.p_double[i]+sinr*e->ptr.p_double[i]; - e->ptr.p_double[i] = cosr*e->ptr.p_double[i]-sinr*d->ptr.p_double[i]; - g = sinr*d->ptr.p_double[i+1]; - d->ptr.p_double[i+1] = cosr*d->ptr.p_double[i+1]; - generaterotation(f, g, &cosl, &sinl, &r, _state); - d->ptr.p_double[i] = r; - f = cosl*e->ptr.p_double[i]+sinl*d->ptr.p_double[i+1]; - d->ptr.p_double[i+1] = cosl*d->ptr.p_double[i+1]-sinl*e->ptr.p_double[i]; - if( iptr.p_double[i+1]; - e->ptr.p_double[i+1] = cosl*e->ptr.p_double[i+1]; - } - work0.ptr.p_double[i-ll+1] = cosr; - work1.ptr.p_double[i-ll+1] = sinr; - work2.ptr.p_double[i-ll+1] = cosl; - work3.ptr.p_double[i-ll+1] = sinl; - } - e->ptr.p_double[m-1] = f; - - /* - * Update singular vectors - */ - if( ncvt>0 ) - { - applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); - } - if( nru>0 ) - { - applyrotationsfromtheright(fwddir, ustart, uend, ll+ustart-1, m+ustart-1, &work2, &work3, u, &utemp, _state); - } - if( ncc>0 ) - { - applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); - } - - /* - * Test convergence - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[m-1], _state),thresh) ) - { - e->ptr.p_double[m-1] = 0; - } - } - else - { - - /* - * Chase bulge from bottom to top - * Save cosines and sines for later singular vector updates - */ - f = (ae_fabs(d->ptr.p_double[m], _state)-shift)*(bdsvd_extsignbdsqr(1, d->ptr.p_double[m], _state)+shift/d->ptr.p_double[m]); - g = e->ptr.p_double[m-1]; - for(i=m; i>=ll+1; i--) - { - generaterotation(f, g, &cosr, &sinr, &r, _state); - if( iptr.p_double[i] = r; - } - f = cosr*d->ptr.p_double[i]+sinr*e->ptr.p_double[i-1]; - e->ptr.p_double[i-1] = cosr*e->ptr.p_double[i-1]-sinr*d->ptr.p_double[i]; - g = sinr*d->ptr.p_double[i-1]; - d->ptr.p_double[i-1] = cosr*d->ptr.p_double[i-1]; - generaterotation(f, g, &cosl, &sinl, &r, _state); - d->ptr.p_double[i] = r; - f = cosl*e->ptr.p_double[i-1]+sinl*d->ptr.p_double[i-1]; - d->ptr.p_double[i-1] = cosl*d->ptr.p_double[i-1]-sinl*e->ptr.p_double[i-1]; - if( i>ll+1 ) - { - g = sinl*e->ptr.p_double[i-2]; - e->ptr.p_double[i-2] = cosl*e->ptr.p_double[i-2]; - } - work0.ptr.p_double[i-ll] = cosr; - work1.ptr.p_double[i-ll] = -sinr; - work2.ptr.p_double[i-ll] = cosl; - work3.ptr.p_double[i-ll] = -sinl; - } - e->ptr.p_double[ll] = f; - - /* - * Test convergence - */ - if( ae_fp_less_eq(ae_fabs(e->ptr.p_double[ll], _state),thresh) ) - { - e->ptr.p_double[ll] = 0; - } - - /* - * Update singular vectors if desired - */ - if( ncvt>0 ) - { - applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); - } - if( nru>0 ) - { - applyrotationsfromtheright(!fwddir, ustart, uend, ll+ustart-1, m+ustart-1, &work0, &work1, u, &utemp, _state); - } - if( ncc>0 ) - { - applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); - } - } - } - - /* - * QR iteration finished, go back and check convergence - */ - continue; - } - - /* - * All singular values converged, so make them positive - */ - for(i=1; i<=n; i++) - { - if( ae_fp_less(d->ptr.p_double[i],0) ) - { - d->ptr.p_double[i] = -d->ptr.p_double[i]; - - /* - * Change sign of singular vectors, if desired - */ - if( ncvt>0 ) - { - ae_v_muld(&vt->ptr.pp_double[i+vstart-1][vstart], 1, ae_v_len(vstart,vend), -1); - } - } - } - - /* - * Sort the singular values into decreasing order (insertion sort on - * singular values, but only one transposition per singular vector) - */ - for(i=1; i<=n-1; i++) - { - - /* - * Scan for smallest D(I) - */ - isub = 1; - smin = d->ptr.p_double[1]; - for(j=2; j<=n+1-i; j++) - { - if( ae_fp_less_eq(d->ptr.p_double[j],smin) ) - { - isub = j; - smin = d->ptr.p_double[j]; - } - } - if( isub!=n+1-i ) - { - - /* - * Swap singular values and vectors - */ - d->ptr.p_double[isub] = d->ptr.p_double[n+1-i]; - d->ptr.p_double[n+1-i] = smin; - if( ncvt>0 ) - { - j = n+1-i; - ae_v_move(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[isub+vstart-1][vstart], 1, ae_v_len(vstart,vend)); - ae_v_move(&vt->ptr.pp_double[isub+vstart-1][vstart], 1, &vt->ptr.pp_double[j+vstart-1][vstart], 1, ae_v_len(vstart,vend)); - ae_v_move(&vt->ptr.pp_double[j+vstart-1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); - } - if( nru>0 ) - { - j = n+1-i; - ae_v_move(&utemp.ptr.p_double[ustart], 1, &u->ptr.pp_double[ustart][isub+ustart-1], u->stride, ae_v_len(ustart,uend)); - ae_v_move(&u->ptr.pp_double[ustart][isub+ustart-1], u->stride, &u->ptr.pp_double[ustart][j+ustart-1], u->stride, ae_v_len(ustart,uend)); - ae_v_move(&u->ptr.pp_double[ustart][j+ustart-1], u->stride, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); - } - if( ncc>0 ) - { - j = n+1-i; - ae_v_move(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[isub+cstart-1][cstart], 1, ae_v_len(cstart,cend)); - ae_v_move(&c->ptr.pp_double[isub+cstart-1][cstart], 1, &c->ptr.pp_double[j+cstart-1][cstart], 1, ae_v_len(cstart,cend)); - ae_v_move(&c->ptr.pp_double[j+cstart-1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); - } - } - } - ae_frame_leave(_state); - return result; -} - - -static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state) -{ - double result; - - - if( ae_fp_greater_eq(b,0) ) - { - result = ae_fabs(a, _state); - } - else - { - result = -ae_fabs(a, _state); - } - return result; -} - - -static void bdsvd_svd2x2(double f, - double g, - double h, - double* ssmin, - double* ssmax, - ae_state *_state) -{ - double aas; - double at; - double au; - double c; - double fa; - double fhmn; - double fhmx; - double ga; - double ha; - - *ssmin = 0; - *ssmax = 0; - - fa = ae_fabs(f, _state); - ga = ae_fabs(g, _state); - ha = ae_fabs(h, _state); - fhmn = ae_minreal(fa, ha, _state); - fhmx = ae_maxreal(fa, ha, _state); - if( ae_fp_eq(fhmn,0) ) - { - *ssmin = 0; - if( ae_fp_eq(fhmx,0) ) - { - *ssmax = ga; - } - else - { - *ssmax = ae_maxreal(fhmx, ga, _state)*ae_sqrt(1+ae_sqr(ae_minreal(fhmx, ga, _state)/ae_maxreal(fhmx, ga, _state), _state), _state); - } - } - else - { - if( ae_fp_less(ga,fhmx) ) - { - aas = 1+fhmn/fhmx; - at = (fhmx-fhmn)/fhmx; - au = ae_sqr(ga/fhmx, _state); - c = 2/(ae_sqrt(aas*aas+au, _state)+ae_sqrt(at*at+au, _state)); - *ssmin = fhmn*c; - *ssmax = fhmx/c; - } - else - { - au = fhmx/ga; - if( ae_fp_eq(au,0) ) - { - - /* - * Avoid possible harmful underflow if exponent range - * asymmetric (true SSMIN may not underflow even if - * AU underflows) - */ - *ssmin = fhmn*fhmx/ga; - *ssmax = ga; - } - else - { - aas = 1+fhmn/fhmx; - at = (fhmx-fhmn)/fhmx; - c = 1/(ae_sqrt(1+ae_sqr(aas*au, _state), _state)+ae_sqrt(1+ae_sqr(at*au, _state), _state)); - *ssmin = fhmn*c*au; - *ssmin = *ssmin+(*ssmin); - *ssmax = ga/(c+c); - } - } - } -} - - -static void bdsvd_svdv2x2(double f, - double g, - double h, - double* ssmin, - double* ssmax, - double* snr, - double* csr, - double* snl, - double* csl, - ae_state *_state) -{ - ae_bool gasmal; - ae_bool swp; - ae_int_t pmax; - double a; - double clt; - double crt; - double d; - double fa; - double ft; - double ga; - double gt; - double ha; - double ht; - double l; - double m; - double mm; - double r; - double s; - double slt; - double srt; - double t; - double temp; - double tsign; - double tt; - double v; - - *ssmin = 0; - *ssmax = 0; - *snr = 0; - *csr = 0; - *snl = 0; - *csl = 0; - - ft = f; - fa = ae_fabs(ft, _state); - ht = h; - ha = ae_fabs(h, _state); - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - clt = 0; - crt = 0; - slt = 0; - srt = 0; - tsign = 0; - - /* - * PMAX points to the maximum absolute element of matrix - * PMAX = 1 if F largest in absolute values - * PMAX = 2 if G largest in absolute values - * PMAX = 3 if H largest in absolute values - */ - pmax = 1; - swp = ae_fp_greater(ha,fa); - if( swp ) - { - - /* - * Now FA .ge. HA - */ - pmax = 3; - temp = ft; - ft = ht; - ht = temp; - temp = fa; - fa = ha; - ha = temp; - } - gt = g; - ga = ae_fabs(gt, _state); - if( ae_fp_eq(ga,0) ) - { - - /* - * Diagonal matrix - */ - *ssmin = ha; - *ssmax = fa; - clt = 1; - crt = 1; - slt = 0; - srt = 0; - } - else - { - gasmal = ae_true; - if( ae_fp_greater(ga,fa) ) - { - pmax = 2; - if( ae_fp_less(fa/ga,ae_machineepsilon) ) - { - - /* - * Case of very large GA - */ - gasmal = ae_false; - *ssmax = ga; - if( ae_fp_greater(ha,1) ) - { - v = ga/ha; - *ssmin = fa/v; - } - else - { - v = fa/ga; - *ssmin = v*ha; - } - clt = 1; - slt = ht/gt; - srt = 1; - crt = ft/gt; - } - } - if( gasmal ) - { - - /* - * Normal case - */ - d = fa-ha; - if( ae_fp_eq(d,fa) ) - { - l = 1; - } - else - { - l = d/fa; - } - m = gt/ft; - t = 2-l; - mm = m*m; - tt = t*t; - s = ae_sqrt(tt+mm, _state); - if( ae_fp_eq(l,0) ) - { - r = ae_fabs(m, _state); - } - else - { - r = ae_sqrt(l*l+mm, _state); - } - a = 0.5*(s+r); - *ssmin = ha/a; - *ssmax = fa*a; - if( ae_fp_eq(mm,0) ) - { - - /* - * Note that M is very tiny - */ - if( ae_fp_eq(l,0) ) - { - t = bdsvd_extsignbdsqr(2, ft, _state)*bdsvd_extsignbdsqr(1, gt, _state); - } - else - { - t = gt/bdsvd_extsignbdsqr(d, ft, _state)+m/t; - } - } - else - { - t = (m/(s+t)+m/(r+l))*(1+a); - } - l = ae_sqrt(t*t+4, _state); - crt = 2/l; - srt = t/l; - clt = (crt+srt*m)/a; - v = ht/ft; - slt = v*srt/a; - } - } - if( swp ) - { - *csl = srt; - *snl = crt; - *csr = slt; - *snr = clt; - } - else - { - *csl = clt; - *snl = slt; - *csr = crt; - *snr = srt; - } - - /* - * Correct signs of SSMAX and SSMIN - */ - if( pmax==1 ) - { - tsign = bdsvd_extsignbdsqr(1, *csr, _state)*bdsvd_extsignbdsqr(1, *csl, _state)*bdsvd_extsignbdsqr(1, f, _state); - } - if( pmax==2 ) - { - tsign = bdsvd_extsignbdsqr(1, *snr, _state)*bdsvd_extsignbdsqr(1, *csl, _state)*bdsvd_extsignbdsqr(1, g, _state); - } - if( pmax==3 ) - { - tsign = bdsvd_extsignbdsqr(1, *snr, _state)*bdsvd_extsignbdsqr(1, *snl, _state)*bdsvd_extsignbdsqr(1, h, _state); - } - *ssmax = bdsvd_extsignbdsqr(*ssmax, tsign, _state); - *ssmin = bdsvd_extsignbdsqr(*ssmin, tsign*bdsvd_extsignbdsqr(1, f, _state)*bdsvd_extsignbdsqr(1, h, _state), _state); -} - - - - -/************************************************************************* -Singular value decomposition of a rectangular matrix. - -The algorithm calculates the singular value decomposition of a matrix of -size MxN: A = U * S * V^T - -The algorithm finds the singular values and, optionally, matrices U and V^T. -The algorithm can find both first min(M,N) columns of matrix U and rows of -matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM -and NxN respectively). - -Take into account that the subroutine does not return matrix V but V^T. - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - UNeeded - 0, 1 or 2. See the description of the parameter U. - VTNeeded - 0, 1 or 2. See the description of the parameter VT. - AdditionalMemory - - If the parameter: - * equals 0, the algorithm doesn’t use additional - memory (lower requirements, lower performance). - * equals 1, the algorithm uses additional - memory of size min(M,N)*min(M,N) of real numbers. - It often speeds up the algorithm. - * equals 2, the algorithm uses additional - memory of size M*min(M,N) of real numbers. - It allows to get a maximum performance. - The recommended value of the parameter is 2. - -Output parameters: - W - contains singular values in descending order. - U - if UNeeded=0, U isn't changed, the left singular vectors - are not calculated. - if Uneeded=1, U contains left singular vectors (first - min(M,N) columns of matrix U). Array whose indexes range - within [0..M-1, 0..Min(M,N)-1]. - if UNeeded=2, U contains matrix U wholly. Array whose - indexes range within [0..M-1, 0..M-1]. - VT - if VTNeeded=0, VT isn’t changed, the right singular vectors - are not calculated. - if VTNeeded=1, VT contains right singular vectors (first - min(M,N) rows of matrix V^T). Array whose indexes range - within [0..min(M,N)-1, 0..N-1]. - if VTNeeded=2, VT contains matrix V^T wholly. Array whose - indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -ae_bool rmatrixsvd(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_int_t uneeded, - ae_int_t vtneeded, - ae_int_t additionalmemory, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* u, - /* Real */ ae_matrix* vt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector tauq; - ae_vector taup; - ae_vector tau; - ae_vector e; - ae_vector work; - ae_matrix t2; - ae_bool isupper; - ae_int_t minmn; - ae_int_t ncu; - ae_int_t nrvt; - ae_int_t nru; - ae_int_t ncvt; - ae_int_t i; - ae_int_t j; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(w); - ae_matrix_clear(u); - ae_matrix_clear(vt); - ae_vector_init(&tauq, 0, DT_REAL, _state, ae_true); - ae_vector_init(&taup, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&t2, 0, 0, DT_REAL, _state, ae_true); - - result = ae_true; - if( m==0||n==0 ) - { - ae_frame_leave(_state); - return result; - } - ae_assert(uneeded>=0&&uneeded<=2, "SVDDecomposition: wrong parameters!", _state); - ae_assert(vtneeded>=0&&vtneeded<=2, "SVDDecomposition: wrong parameters!", _state); - ae_assert(additionalmemory>=0&&additionalmemory<=2, "SVDDecomposition: wrong parameters!", _state); - - /* - * initialize - */ - minmn = ae_minint(m, n, _state); - ae_vector_set_length(w, minmn+1, _state); - ncu = 0; - nru = 0; - if( uneeded==1 ) - { - nru = m; - ncu = minmn; - ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); - } - if( uneeded==2 ) - { - nru = m; - ncu = m; - ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); - } - nrvt = 0; - ncvt = 0; - if( vtneeded==1 ) - { - nrvt = minmn; - ncvt = n; - ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); - } - if( vtneeded==2 ) - { - nrvt = n; - ncvt = n; - ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); - } - - /* - * M much larger than N - * Use bidiagonal reduction with QR-decomposition - */ - if( ae_fp_greater(m,1.6*n) ) - { - if( uneeded==0 ) - { - - /* - * No left singular vectors to be computed - */ - rmatrixqr(a, m, n, &tau, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rmatrixbd(a, n, n, &tauq, &taup, _state); - rmatrixbdunpackpt(a, n, n, &taup, nrvt, vt, _state); - rmatrixbdunpackdiagonals(a, n, n, &isupper, w, &e, _state); - result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, a, 0, vt, ncvt, _state); - ae_frame_leave(_state); - return result; - } - else - { - - /* - * Left singular vectors (may be full matrix U) to be computed - */ - rmatrixqr(a, m, n, &tau, _state); - rmatrixqrunpackq(a, m, n, &tau, ncu, u, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rmatrixbd(a, n, n, &tauq, &taup, _state); - rmatrixbdunpackpt(a, n, n, &taup, nrvt, vt, _state); - rmatrixbdunpackdiagonals(a, n, n, &isupper, w, &e, _state); - if( additionalmemory<1 ) - { - - /* - * No additional memory can be used - */ - rmatrixbdmultiplybyq(a, n, n, &tauq, u, m, n, ae_true, ae_false, _state); - result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, m, a, 0, vt, ncvt, _state); - } - else - { - - /* - * Large U. Transforming intermediate matrix T2 - */ - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - rmatrixbdunpackq(a, n, n, &tauq, n, &t2, _state); - copymatrix(u, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1, _state); - inplacetranspose(&t2, 0, n-1, 0, n-1, &work, _state); - result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, &t2, n, vt, ncvt, _state); - matrixmatrixmultiply(a, 0, m-1, 0, n-1, ae_false, &t2, 0, n-1, 0, n-1, ae_true, 1.0, u, 0, m-1, 0, n-1, 0.0, &work, _state); - } - ae_frame_leave(_state); - return result; - } - } - - /* - * N much larger than M - * Use bidiagonal reduction with LQ-decomposition - */ - if( ae_fp_greater(n,1.6*m) ) - { - if( vtneeded==0 ) - { - - /* - * No right singular vectors to be computed - */ - rmatrixlq(a, m, n, &tau, _state); - for(i=0; i<=m-1; i++) - { - for(j=i+1; j<=m-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rmatrixbd(a, m, m, &tauq, &taup, _state); - rmatrixbdunpackq(a, m, m, &tauq, ncu, u, _state); - rmatrixbdunpackdiagonals(a, m, m, &isupper, w, &e, _state); - ae_vector_set_length(&work, m+1, _state); - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, vt, 0, _state); - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - ae_frame_leave(_state); - return result; - } - else - { - - /* - * Right singular vectors (may be full matrix VT) to be computed - */ - rmatrixlq(a, m, n, &tau, _state); - rmatrixlqunpackq(a, m, n, &tau, nrvt, vt, _state); - for(i=0; i<=m-1; i++) - { - for(j=i+1; j<=m-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rmatrixbd(a, m, m, &tauq, &taup, _state); - rmatrixbdunpackq(a, m, m, &tauq, ncu, u, _state); - rmatrixbdunpackdiagonals(a, m, m, &isupper, w, &e, _state); - ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - if( additionalmemory<1 ) - { - - /* - * No additional memory available - */ - rmatrixbdmultiplybyp(a, m, m, &taup, vt, m, n, ae_false, ae_true, _state); - result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, vt, n, _state); - } - else - { - - /* - * Large VT. Transforming intermediate matrix T2 - */ - rmatrixbdunpackpt(a, m, m, &taup, m, &t2, _state); - result = rmatrixbdsvd(w, &e, m, isupper, ae_false, a, 0, u, nru, &t2, m, _state); - copymatrix(vt, 0, m-1, 0, n-1, a, 0, m-1, 0, n-1, _state); - matrixmatrixmultiply(&t2, 0, m-1, 0, m-1, ae_false, a, 0, m-1, 0, n-1, ae_false, 1.0, vt, 0, m-1, 0, n-1, 0.0, &work, _state); - } - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - ae_frame_leave(_state); - return result; - } - } - - /* - * M<=N - * We can use inplace transposition of U to get rid of columnwise operations - */ - if( m<=n ) - { - rmatrixbd(a, m, n, &tauq, &taup, _state); - rmatrixbdunpackq(a, m, n, &tauq, ncu, u, _state); - rmatrixbdunpackpt(a, m, n, &taup, nrvt, vt, _state); - rmatrixbdunpackdiagonals(a, m, n, &isupper, w, &e, _state); - ae_vector_set_length(&work, m+1, _state); - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, a, 0, u, nru, vt, ncvt, _state); - inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); - ae_frame_leave(_state); - return result; - } - - /* - * Simple bidiagonal reduction - */ - rmatrixbd(a, m, n, &tauq, &taup, _state); - rmatrixbdunpackq(a, m, n, &tauq, ncu, u, _state); - rmatrixbdunpackpt(a, m, n, &taup, nrvt, vt, _state); - rmatrixbdunpackdiagonals(a, m, n, &isupper, w, &e, _state); - if( additionalmemory<2||uneeded==0 ) - { - - /* - * We can't use additional memory or there is no need in such operations - */ - result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, nru, a, 0, vt, ncvt, _state); - } - else - { - - /* - * We can use additional memory - */ - ae_matrix_set_length(&t2, minmn-1+1, m-1+1, _state); - copyandtranspose(u, 0, m-1, 0, minmn-1, &t2, 0, minmn-1, 0, m-1, _state); - result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, 0, &t2, m, vt, ncvt, _state); - copyandtranspose(&t2, 0, minmn-1, 0, m-1, u, 0, m-1, 0, minmn-1, _state); - } - ae_frame_leave(_state); - return result; -} - - - - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a symmetric matrix - -The algorithm finds eigen pairs of a symmetric matrix by reducing it to -tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpper - storage format. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - /* Real */ ae_vector* d, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector tau; - ae_vector e; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(d); - ae_matrix_clear(z); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "SMatrixEVD: incorrect ZNeeded", _state); - smatrixtd(a, n, isupper, &tau, d, &e, _state); - if( zneeded==1 ) - { - smatrixtdunpackq(a, n, isupper, &tau, z, _state); - } - result = smatrixtdevd(d, &e, n, zneeded, z, _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric -matrix in a given half open interval (A, B] by using a bisection and -inverse iteration - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half open interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval (M>=0). - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, - M is equal to 0. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixevdr(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - double b1, - double b2, - ae_int_t* m, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector tau; - ae_vector e; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - *m = 0; - ae_vector_clear(w); - ae_matrix_clear(z); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "SMatrixTDEVDR: incorrect ZNeeded", _state); - smatrixtd(a, n, isupper, &tau, w, &e, _state); - if( zneeded==1 ) - { - smatrixtdunpackq(a, n, isupper, &tau, z, _state); - } - result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, z, _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a symmetric -matrix with given indexes by using bisection and inverse iteration methods. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixevdi(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector tau; - ae_vector e; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(w); - ae_matrix_clear(z); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "SMatrixEVDI: incorrect ZNeeded", _state); - smatrixtd(a, n, isupper, &tau, w, &e, _state); - if( zneeded==1 ) - { - smatrixtdunpackq(a, n, isupper, &tau, z, _state); - } - result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, z, _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a Hermitian matrix - -The algorithm finds eigen pairs of a Hermitian matrix by reducing it to -real tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Note: - eigenvectors of Hermitian matrix are defined up to multiplication by - a complex number L, such that |L|=1. - - -- ALGLIB -- - Copyright 2005, 23 March 2007 by Bochkanov Sergey -*************************************************************************/ -ae_bool hmatrixevd(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - /* Real */ ae_vector* d, - /* Complex */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector tau; - ae_vector e; - ae_vector work; - ae_matrix t; - ae_matrix q; - ae_int_t i; - ae_int_t k; - double v; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(d); - ae_matrix_clear(z); - ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "HermitianEVD: incorrect ZNeeded", _state); - - /* - * Reduce to tridiagonal form - */ - hmatrixtd(a, n, isupper, &tau, d, &e, _state); - if( zneeded==1 ) - { - hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); - zneeded = 2; - } - - /* - * TDEVD - */ - result = smatrixtdevd(d, &e, n, zneeded, &t, _state); - - /* - * Eigenvectors are needed - * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T - */ - if( result&&zneeded!=0 ) - { - ae_vector_set_length(&work, n-1+1, _state); - ae_matrix_set_length(z, n-1+1, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - - /* - * Calculate real part - */ - for(k=0; k<=n-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].x; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); - } - for(k=0; k<=n-1; k++) - { - z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; - } - - /* - * Calculate imaginary part - */ - for(k=0; k<=n-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].y; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,n-1), v); - } - for(k=0; k<=n-1; k++) - { - z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; - } - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian -matrix in a given half-interval (A, B] by using a bisection and inverse -iteration - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. Array whose indexes range within - [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half-interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval, M>=0 - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, M is - equal to 0. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -ae_bool hmatrixevdr(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - double b1, - double b2, - ae_int_t* m, - /* Real */ ae_vector* w, - /* Complex */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_matrix q; - ae_matrix t; - ae_vector tau; - ae_vector e; - ae_vector work; - ae_int_t i; - ae_int_t k; - double v; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - *m = 0; - ae_vector_clear(w); - ae_matrix_clear(z); - ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsInInterval: incorrect ZNeeded", _state); - - /* - * Reduce to tridiagonal form - */ - hmatrixtd(a, n, isupper, &tau, w, &e, _state); - if( zneeded==1 ) - { - hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); - zneeded = 2; - } - - /* - * Bisection and inverse iteration - */ - result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, &t, _state); - - /* - * Eigenvectors are needed - * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T - */ - if( (result&&zneeded!=0)&&*m!=0 ) - { - ae_vector_set_length(&work, *m-1+1, _state); - ae_matrix_set_length(z, n-1+1, *m-1+1, _state); - for(i=0; i<=n-1; i++) - { - - /* - * Calculate real part - */ - for(k=0; k<=*m-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].x; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); - } - for(k=0; k<=*m-1; k++) - { - z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; - } - - /* - * Calculate imaginary part - */ - for(k=0; k<=*m-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].y; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); - } - for(k=0; k<=*m-1; k++) - { - z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; - } - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a Hermitian -matrix with given indexes by using bisection and inverse iteration methods - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix - columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -ae_bool hmatrixevdi(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* w, - /* Complex */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_matrix q; - ae_matrix t; - ae_vector tau; - ae_vector e; - ae_vector work; - ae_int_t i; - ae_int_t k; - double v; - ae_int_t m; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(w); - ae_matrix_clear(z); - ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&e, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded", _state); - - /* - * Reduce to tridiagonal form - */ - hmatrixtd(a, n, isupper, &tau, w, &e, _state); - if( zneeded==1 ) - { - hmatrixtdunpackq(a, n, isupper, &tau, &q, _state); - zneeded = 2; - } - - /* - * Bisection and inverse iteration - */ - result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, &t, _state); - - /* - * Eigenvectors are needed - * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T - */ - m = i2-i1+1; - if( result&&zneeded!=0 ) - { - ae_vector_set_length(&work, m-1+1, _state); - ae_matrix_set_length(z, n-1+1, m-1+1, _state); - for(i=0; i<=n-1; i++) - { - - /* - * Calculate real part - */ - for(k=0; k<=m-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].x; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); - } - for(k=0; k<=m-1; k++) - { - z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; - } - - /* - * Calculate imaginary part - */ - for(k=0; k<=m-1; k++) - { - work.ptr.p_double[k] = 0; - } - for(k=0; k<=n-1; k++) - { - v = q.ptr.pp_complex[i][k].y; - ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); - } - for(k=0; k<=m-1; k++) - { - z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; - } - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix - -The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by -using an QL/QR algorithm with implicit shifts. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix - are multiplied by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity - transformation of a symmetric matrix; - * 2, the eigenvectors of a tridiagonal matrix replace the - square matrix Z; - * 3, matrix Z contains the first row of the eigenvectors - matrix. - Z - if ZNeeded=1, Z contains the square matrix by which the - eigenvectors are multiplied. - Array whose indexes range within [0..N-1, 0..N-1]. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the product of a given matrix (from the left) - and the eigenvectors matrix (from the right); - * 2, Z contains the eigenvectors. - * 3, Z contains the first row of the eigenvectors matrix. - If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. - In that case, the eigenvectors are stored in the matrix columns. - If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -ae_bool smatrixtdevd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_vector d1; - ae_vector e1; - ae_matrix z1; - ae_int_t i; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z1, 0, 0, DT_REAL, _state, ae_true); - - - /* - * Prepare 1-based task - */ - ae_vector_set_length(&d1, n+1, _state); - ae_vector_set_length(&e1, n+1, _state); - ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); - if( n>1 ) - { - ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); - } - if( zneeded==1 ) - { - ae_matrix_set_length(&z1, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&z1.ptr.pp_double[i][1], 1, &z->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); - } - } - - /* - * Solve 1-based task - */ - result = evd_tridiagonalevd(&d1, &e1, n, zneeded, &z1, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - - /* - * Convert back to 0-based result - */ - ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); - if( zneeded!=0 ) - { - if( zneeded==1 ) - { - for(i=1; i<=n; i++) - { - ae_v_move(&z->ptr.pp_double[i-1][0], 1, &z1.ptr.pp_double[i][1], 1, ae_v_len(0,n-1)); - } - ae_frame_leave(_state); - return result; - } - if( zneeded==2 ) - { - ae_matrix_set_length(z, n-1+1, n-1+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&z->ptr.pp_double[i-1][0], 1, &z1.ptr.pp_double[i][1], 1, ae_v_len(0,n-1)); - } - ae_frame_leave(_state); - return result; - } - if( zneeded==3 ) - { - ae_matrix_set_length(z, 0+1, n-1+1, _state); - ae_v_move(&z->ptr.pp_double[0][0], 1, &z1.ptr.pp_double[1][1], 1, ae_v_len(0,n-1)); - ae_frame_leave(_state); - return result; - } - ae_assert(ae_false, "SMatrixTDEVD: Incorrect ZNeeded!", _state); - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a -given half-interval (A, B] by using bisection and inverse iteration. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix, N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the tridiagonal - matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. - A, B - half-interval (A, B] to search eigenvalues in. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range - within [0..N-1, 0..N-1]) which reduces the given symmetric - matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - M - number of eigenvalues found in the given half-interval (M>=0). - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the - left) and NxM matrix of the eigenvectors found (from the - right). Array whose indexes range within [0..N-1, 0..M-1]. - * 2, contains the matrix of the eigenvectors found. - Array whose indexes range within [0..N-1, 0..M-1]. - -Result: - - True, if successful. In that case, M contains the number of eigenvalues - in the given half-interval (could be equal to 0), D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. In that case, - the eigenvalues and eigenvectors are not returned, M is equal to 0. - - -- ALGLIB -- - Copyright 31.03.2008 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixtdevdr(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - double a, - double b, - ae_int_t* m, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t errorcode; - ae_int_t nsplit; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t cr; - ae_vector iblock; - ae_vector isplit; - ae_vector ifail; - ae_vector d1; - ae_vector e1; - ae_vector w; - ae_matrix z2; - ae_matrix z3; - double v; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - *m = 0; - ae_vector_init(&iblock, 0, DT_INT, _state, ae_true); - ae_vector_init(&isplit, 0, DT_INT, _state, ae_true); - ae_vector_init(&ifail, 0, DT_INT, _state, ae_true); - ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z3, 0, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded>=0&&zneeded<=2, "SMatrixTDEVDR: incorrect ZNeeded!", _state); - - /* - * Special cases - */ - if( ae_fp_less_eq(b,a) ) - { - *m = 0; - result = ae_true; - ae_frame_leave(_state); - return result; - } - if( n<=0 ) - { - *m = 0; - result = ae_true; - ae_frame_leave(_state); - return result; - } - - /* - * Copy D,E to D1, E1 - */ - ae_vector_set_length(&d1, n+1, _state); - ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); - if( n>1 ) - { - ae_vector_set_length(&e1, n-1+1, _state); - ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); - } - - /* - * No eigen vectors - */ - if( zneeded==0 ) - { - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 1, a, b, 0, 0, -1, &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result||*m==0 ) - { - *m = 0; - ae_frame_leave(_state); - return result; - } - ae_vector_set_length(d, *m-1+1, _state); - ae_v_move(&d->ptr.p_double[0], 1, &w.ptr.p_double[1], 1, ae_v_len(0,*m-1)); - ae_frame_leave(_state); - return result; - } - - /* - * Eigen vectors are multiplied by Z - */ - if( zneeded==1 ) - { - - /* - * Find eigen pairs - */ - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, -1, &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result||*m==0 ) - { - *m = 0; - ae_frame_leave(_state); - return result; - } - evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); - if( cr!=0 ) - { - *m = 0; - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Sort eigen values and vectors - */ - for(i=1; i<=*m; i++) - { - k = i; - for(j=i; j<=*m; j++) - { - if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) - { - k = j; - } - } - v = w.ptr.p_double[i]; - w.ptr.p_double[i] = w.ptr.p_double[k]; - w.ptr.p_double[k] = v; - for(j=1; j<=n; j++) - { - v = z2.ptr.pp_double[j][i]; - z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; - z2.ptr.pp_double[j][k] = v; - } - } - - /* - * Transform Z2 and overwrite Z - */ - ae_matrix_set_length(&z3, *m+1, n+1, _state); - for(i=1; i<=*m; i++) - { - ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); - } - for(i=1; i<=n; i++) - { - for(j=1; j<=*m; j++) - { - v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); - z2.ptr.pp_double[i][j] = v; - } - } - ae_matrix_set_length(z, n-1+1, *m-1+1, _state); - for(i=1; i<=*m; i++) - { - ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); - } - - /* - * Store W - */ - ae_vector_set_length(d, *m-1+1, _state); - for(i=1; i<=*m; i++) - { - d->ptr.p_double[i-1] = w.ptr.p_double[i]; - } - ae_frame_leave(_state); - return result; - } - - /* - * Eigen vectors are stored in Z - */ - if( zneeded==2 ) - { - - /* - * Find eigen pairs - */ - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, -1, &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result||*m==0 ) - { - *m = 0; - ae_frame_leave(_state); - return result; - } - evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); - if( cr!=0 ) - { - *m = 0; - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Sort eigen values and vectors - */ - for(i=1; i<=*m; i++) - { - k = i; - for(j=i; j<=*m; j++) - { - if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) - { - k = j; - } - } - v = w.ptr.p_double[i]; - w.ptr.p_double[i] = w.ptr.p_double[k]; - w.ptr.p_double[k] = v; - for(j=1; j<=n; j++) - { - v = z2.ptr.pp_double[j][i]; - z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; - z2.ptr.pp_double[j][k] = v; - } - } - - /* - * Store W - */ - ae_vector_set_length(d, *m-1+1, _state); - for(i=1; i<=*m; i++) - { - d->ptr.p_double[i-1] = w.ptr.p_double[i]; - } - ae_matrix_set_length(z, n-1+1, *m-1+1, _state); - for(i=1; i<=*m; i++) - { - ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); - } - ae_frame_leave(_state); - return result; - } - result = ae_false; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Subroutine for finding tridiagonal matrix eigenvalues/vectors with given -indexes (in ascending order) by using the bisection and inverse iteraion. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix. N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace - matrix Z. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) - which reduces the given symmetric matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the left) and - Nx(I2-I1) matrix of the eigenvectors found (from the right). - Array whose indexes range within [0..N-1, 0..I2-I1]. - * 2, contains the matrix of the eigenvalues found. - Array whose indexes range within [0..N-1, 0..I2-I1]. - - -Result: - - True, if successful. In that case, D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the eigenvalues - in the given interval or if the inverse iteration subroutine wasn't able - to find all the corresponding eigenvectors. In that case, the eigenvalues - and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 25.12.2005 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixtdevdi(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t errorcode; - ae_int_t nsplit; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t m; - ae_int_t cr; - ae_vector iblock; - ae_vector isplit; - ae_vector ifail; - ae_vector w; - ae_vector d1; - ae_vector e1; - ae_matrix z2; - ae_matrix z3; - double v; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&iblock, 0, DT_INT, _state, ae_true); - ae_vector_init(&isplit, 0, DT_INT, _state, ae_true); - ae_vector_init(&ifail, 0, DT_INT, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&z3, 0, 0, DT_REAL, _state, ae_true); - - ae_assert((0<=i1&&i1<=i2)&&i2ptr.p_double[0], 1, ae_v_len(1,n)); - if( n>1 ) - { - ae_vector_set_length(&e1, n-1+1, _state); - ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); - } - - /* - * No eigen vectors - */ - if( zneeded==0 ) - { - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 1, 0, 0, i1+1, i2+1, -1, &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - if( m!=i2-i1+1 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - ae_vector_set_length(d, m-1+1, _state); - for(i=1; i<=m; i++) - { - d->ptr.p_double[i-1] = w.ptr.p_double[i]; - } - ae_frame_leave(_state); - return result; - } - - /* - * Eigen vectors are multiplied by Z - */ - if( zneeded==1 ) - { - - /* - * Find eigen pairs - */ - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, 0, 0, i1+1, i2+1, -1, &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - if( m!=i2-i1+1 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); - if( cr!=0 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Sort eigen values and vectors - */ - for(i=1; i<=m; i++) - { - k = i; - for(j=i; j<=m; j++) - { - if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) - { - k = j; - } - } - v = w.ptr.p_double[i]; - w.ptr.p_double[i] = w.ptr.p_double[k]; - w.ptr.p_double[k] = v; - for(j=1; j<=n; j++) - { - v = z2.ptr.pp_double[j][i]; - z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; - z2.ptr.pp_double[j][k] = v; - } - } - - /* - * Transform Z2 and overwrite Z - */ - ae_matrix_set_length(&z3, m+1, n+1, _state); - for(i=1; i<=m; i++) - { - ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); - } - for(i=1; i<=n; i++) - { - for(j=1; j<=m; j++) - { - v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); - z2.ptr.pp_double[i][j] = v; - } - } - ae_matrix_set_length(z, n-1+1, m-1+1, _state); - for(i=1; i<=m; i++) - { - ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); - } - - /* - * Store W - */ - ae_vector_set_length(d, m-1+1, _state); - for(i=1; i<=m; i++) - { - d->ptr.p_double[i-1] = w.ptr.p_double[i]; - } - ae_frame_leave(_state); - return result; - } - - /* - * Eigen vectors are stored in Z - */ - if( zneeded==2 ) - { - - /* - * Find eigen pairs - */ - result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, 0, 0, i1+1, i2+1, -1, &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); - if( !result ) - { - ae_frame_leave(_state); - return result; - } - if( m!=i2-i1+1 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); - if( cr!=0 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Sort eigen values and vectors - */ - for(i=1; i<=m; i++) - { - k = i; - for(j=i; j<=m; j++) - { - if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) - { - k = j; - } - } - v = w.ptr.p_double[i]; - w.ptr.p_double[i] = w.ptr.p_double[k]; - w.ptr.p_double[k] = v; - for(j=1; j<=n; j++) - { - v = z2.ptr.pp_double[j][i]; - z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; - z2.ptr.pp_double[j][k] = v; - } - } - - /* - * Store Z - */ - ae_matrix_set_length(z, n-1+1, m-1+1, _state); - for(i=1; i<=m; i++) - { - ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); - } - - /* - * Store W - */ - ae_vector_set_length(d, m-1+1, _state); - for(i=1; i<=m; i++) - { - d->ptr.p_double[i-1] = w.ptr.p_double[i]; - } - ae_frame_leave(_state); - return result; - } - result = ae_false; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Finding eigenvalues and eigenvectors of a general matrix - -The algorithm finds eigenvalues and eigenvectors of a general matrix by -using the QR algorithm with multiple shifts. The algorithm can find -eigenvalues and both left and right eigenvectors. - -The right eigenvector is a vector x such that A*x = w*x, and the left -eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex -conjugate transposition of vector y). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - VNeeded - flag controlling whether eigenvectors are needed or not. - If VNeeded is equal to: - * 0, eigenvectors are not returned; - * 1, right eigenvectors are returned; - * 2, left eigenvectors are returned; - * 3, both left and right eigenvectors are returned. - -Output parameters: - WR - real parts of eigenvalues. - Array whose index ranges within [0..N-1]. - WR - imaginary parts of eigenvalues. - Array whose index ranges within [0..N-1]. - VL, VR - arrays of left and right eigenvectors (if they are needed). - If WI[i]=0, the respective eigenvalue is a real number, - and it corresponds to the column number I of matrices VL/VR. - If WI[i]>0, we have a pair of complex conjugate numbers with - positive and negative imaginary parts: - the first eigenvalue WR[i] + sqrt(-1)*WI[i]; - the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; - WI[i]>0 - WI[i+1] = -WI[i] < 0 - In that case, the eigenvector corresponding to the first - eigenvalue is located in i and i+1 columns of matrices - VL/VR (the column number i contains the real part, and the - column number i+1 contains the imaginary part), and the vector - corresponding to the second eigenvalue is a complex conjugate to - the first vector. - Arrays whose indexes range within [0..N-1, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm has not converged. - -Note 1: - Some users may ask the following question: what if WI[N-1]>0? - WI[N] must contain an eigenvalue which is complex conjugate to the - N-th eigenvalue, but the array has only size N? - The answer is as follows: such a situation cannot occur because the - algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is - strictly less than N-1. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms of linear algebra). If you require maximum performance - on your machine, it is recommended to adjust this parameter manually. - - -See also the InternalTREVC subroutine. - -The algorithm is based on the LAPACK 3.0 library. -*************************************************************************/ -ae_bool rmatrixevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t vneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_matrix a1; - ae_matrix vl1; - ae_matrix vr1; - ae_vector wr1; - ae_vector wi1; - ae_int_t i; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(wr); - ae_vector_clear(wi); - ae_matrix_clear(vl); - ae_matrix_clear(vr); - ae_matrix_init(&a1, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vl1, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vr1, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wr1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wi1, 0, DT_REAL, _state, ae_true); - - ae_assert(vneeded>=0&&vneeded<=3, "RMatrixEVD: incorrect VNeeded!", _state); - ae_matrix_set_length(&a1, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&a1.ptr.pp_double[i][1], 1, &a->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); - } - result = evd_nonsymmetricevd(&a1, n, vneeded, &wr1, &wi1, &vl1, &vr1, _state); - if( result ) - { - ae_vector_set_length(wr, n-1+1, _state); - ae_vector_set_length(wi, n-1+1, _state); - ae_v_move(&wr->ptr.p_double[0], 1, &wr1.ptr.p_double[1], 1, ae_v_len(0,n-1)); - ae_v_move(&wi->ptr.p_double[0], 1, &wi1.ptr.p_double[1], 1, ae_v_len(0,n-1)); - if( vneeded==2||vneeded==3 ) - { - ae_matrix_set_length(vl, n-1+1, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - ae_v_move(&vl->ptr.pp_double[i][0], 1, &vl1.ptr.pp_double[i+1][1], 1, ae_v_len(0,n-1)); - } - } - if( vneeded==1||vneeded==3 ) - { - ae_matrix_set_length(vr, n-1+1, n-1+1, _state); - for(i=0; i<=n-1; i++) - { - ae_v_move(&vr->ptr.pp_double[i][0], 1, &vr1.ptr.pp_double[i+1][1], 1, ae_v_len(0,n-1)); - } - } - } - ae_frame_leave(_state); - return result; -} - - -static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - /* Real */ ae_matrix* z, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_int_t maxit; - ae_int_t i; - ae_int_t ii; - ae_int_t iscale; - ae_int_t j; - ae_int_t jtot; - ae_int_t k; - ae_int_t t; - ae_int_t l; - ae_int_t l1; - ae_int_t lend; - ae_int_t lendm1; - ae_int_t lendp1; - ae_int_t lendsv; - ae_int_t lm1; - ae_int_t lsv; - ae_int_t m; - ae_int_t mm1; - ae_int_t nm1; - ae_int_t nmaxit; - ae_int_t tmpint; - double anorm; - double b; - double c; - double eps; - double eps2; - double f; - double g; - double p; - double r; - double rt1; - double rt2; - double s; - double safmax; - double safmin; - double ssfmax; - double ssfmin; - double tst; - double tmp; - ae_vector work1; - ae_vector work2; - ae_vector workc; - ae_vector works; - ae_vector wtemp; - ae_bool gotoflag; - ae_int_t zrows; - ae_bool wastranspose; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&workc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&works, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true); - - ae_assert(zneeded>=0&&zneeded<=3, "TridiagonalEVD: Incorrent ZNeeded", _state); - - /* - * Quick return if possible - */ - if( zneeded<0||zneeded>3 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - result = ae_true; - if( n==0 ) - { - ae_frame_leave(_state); - return result; - } - if( n==1 ) - { - if( zneeded==2||zneeded==3 ) - { - ae_matrix_set_length(z, 1+1, 1+1, _state); - z->ptr.pp_double[1][1] = 1; - } - ae_frame_leave(_state); - return result; - } - maxit = 30; - - /* - * Initialize arrays - */ - ae_vector_set_length(&wtemp, n+1, _state); - ae_vector_set_length(&work1, n-1+1, _state); - ae_vector_set_length(&work2, n-1+1, _state); - ae_vector_set_length(&workc, n+1, _state); - ae_vector_set_length(&works, n+1, _state); - - /* - * Determine the unit roundoff and over/underflow thresholds. - */ - eps = ae_machineepsilon; - eps2 = ae_sqr(eps, _state); - safmin = ae_minrealnumber; - safmax = ae_maxrealnumber; - ssfmax = ae_sqrt(safmax, _state)/3; - ssfmin = ae_sqrt(safmin, _state)/eps2; - - /* - * Prepare Z - * - * Here we are using transposition to get rid of column operations - * - */ - wastranspose = ae_false; - zrows = 0; - if( zneeded==1 ) - { - zrows = n; - } - if( zneeded==2 ) - { - zrows = n; - } - if( zneeded==3 ) - { - zrows = 1; - } - if( zneeded==1 ) - { - wastranspose = ae_true; - inplacetranspose(z, 1, n, 1, n, &wtemp, _state); - } - if( zneeded==2 ) - { - wastranspose = ae_true; - ae_matrix_set_length(z, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - for(j=1; j<=n; j++) - { - if( i==j ) - { - z->ptr.pp_double[i][j] = 1; - } - else - { - z->ptr.pp_double[i][j] = 0; - } - } - } - } - if( zneeded==3 ) - { - wastranspose = ae_false; - ae_matrix_set_length(z, 1+1, n+1, _state); - for(j=1; j<=n; j++) - { - if( j==1 ) - { - z->ptr.pp_double[1][j] = 1; - } - else - { - z->ptr.pp_double[1][j] = 0; - } - } - } - nmaxit = n*maxit; - jtot = 0; - - /* - * Determine where the matrix splits and choose QL or QR iteration - * for each block, according to whether top or bottom diagonal - * element is smaller. - */ - l1 = 1; - nm1 = n-1; - for(;;) - { - if( l1>n ) - { - break; - } - if( l1>1 ) - { - e->ptr.p_double[l1-1] = 0; - } - gotoflag = ae_false; - m = l1; - if( l1<=nm1 ) - { - for(m=l1; m<=nm1; m++) - { - tst = ae_fabs(e->ptr.p_double[m], _state); - if( ae_fp_eq(tst,0) ) - { - gotoflag = ae_true; - break; - } - if( ae_fp_less_eq(tst,ae_sqrt(ae_fabs(d->ptr.p_double[m], _state), _state)*ae_sqrt(ae_fabs(d->ptr.p_double[m+1], _state), _state)*eps) ) - { - e->ptr.p_double[m] = 0; - gotoflag = ae_true; - break; - } - } - } - if( !gotoflag ) - { - m = n; - } - - /* - * label 30: - */ - l = l1; - lsv = l; - lend = m; - lendsv = lend; - l1 = m+1; - if( lend==l ) - { - continue; - } - - /* - * Scale submatrix in rows and columns L to LEND - */ - if( l==lend ) - { - anorm = ae_fabs(d->ptr.p_double[l], _state); - } - else - { - anorm = ae_maxreal(ae_fabs(d->ptr.p_double[l], _state)+ae_fabs(e->ptr.p_double[l], _state), ae_fabs(e->ptr.p_double[lend-1], _state)+ae_fabs(d->ptr.p_double[lend], _state), _state); - for(i=l+1; i<=lend-1; i++) - { - anorm = ae_maxreal(anorm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i-1], _state), _state); - } - } - iscale = 0; - if( ae_fp_eq(anorm,0) ) - { - continue; - } - if( ae_fp_greater(anorm,ssfmax) ) - { - iscale = 1; - tmp = ssfmax/anorm; - tmpint = lend-1; - ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); - ae_v_muld(&e->ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); - } - if( ae_fp_less(anorm,ssfmin) ) - { - iscale = 2; - tmp = ssfmin/anorm; - tmpint = lend-1; - ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); - ae_v_muld(&e->ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); - } - - /* - * Choose between QL and QR iteration - */ - if( ae_fp_less(ae_fabs(d->ptr.p_double[lend], _state),ae_fabs(d->ptr.p_double[l], _state)) ) - { - lend = lsv; - l = lendsv; - } - if( lend>l ) - { - - /* - * QL Iteration - * - * Look for small subdiagonal element. - */ - for(;;) - { - gotoflag = ae_false; - if( l!=lend ) - { - lendm1 = lend-1; - for(m=l; m<=lendm1; m++) - { - tst = ae_sqr(ae_fabs(e->ptr.p_double[m], _state), _state); - if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m+1], _state)+safmin) ) - { - gotoflag = ae_true; - break; - } - } - } - if( !gotoflag ) - { - m = lend; - } - if( mptr.p_double[m] = 0; - } - p = d->ptr.p_double[l]; - if( m!=l ) - { - - /* - * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 - * to compute its eigensystem. - */ - if( m==l+1 ) - { - if( zneeded>0 ) - { - evd_tdevdev2(d->ptr.p_double[l], e->ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, &c, &s, _state); - work1.ptr.p_double[l] = c; - work2.ptr.p_double[l] = s; - workc.ptr.p_double[1] = work1.ptr.p_double[l]; - works.ptr.p_double[1] = work2.ptr.p_double[l]; - if( !wastranspose ) - { - applyrotationsfromtheright(ae_false, 1, zrows, l, l+1, &workc, &works, z, &wtemp, _state); - } - else - { - applyrotationsfromtheleft(ae_false, l, l+1, 1, zrows, &workc, &works, z, &wtemp, _state); - } - } - else - { - evd_tdevde2(d->ptr.p_double[l], e->ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, _state); - } - d->ptr.p_double[l] = rt1; - d->ptr.p_double[l+1] = rt2; - e->ptr.p_double[l] = 0; - l = l+2; - if( l<=lend ) - { - continue; - } - - /* - * GOTO 140 - */ - break; - } - if( jtot==nmaxit ) - { - - /* - * GOTO 140 - */ - break; - } - jtot = jtot+1; - - /* - * Form shift. - */ - g = (d->ptr.p_double[l+1]-p)/(2*e->ptr.p_double[l]); - r = evd_tdevdpythag(g, 1, _state); - g = d->ptr.p_double[m]-p+e->ptr.p_double[l]/(g+evd_tdevdextsign(r, g, _state)); - s = 1; - c = 1; - p = 0; - - /* - * Inner loop - */ - mm1 = m-1; - for(i=mm1; i>=l; i--) - { - f = s*e->ptr.p_double[i]; - b = c*e->ptr.p_double[i]; - generaterotation(g, f, &c, &s, &r, _state); - if( i!=m-1 ) - { - e->ptr.p_double[i+1] = r; - } - g = d->ptr.p_double[i+1]-p; - r = (d->ptr.p_double[i]-g)*s+2*c*b; - p = s*r; - d->ptr.p_double[i+1] = g+p; - g = c*r-b; - - /* - * If eigenvectors are desired, then save rotations. - */ - if( zneeded>0 ) - { - work1.ptr.p_double[i] = c; - work2.ptr.p_double[i] = -s; - } - } - - /* - * If eigenvectors are desired, then apply saved rotations. - */ - if( zneeded>0 ) - { - for(i=l; i<=m-1; i++) - { - workc.ptr.p_double[i-l+1] = work1.ptr.p_double[i]; - works.ptr.p_double[i-l+1] = work2.ptr.p_double[i]; - } - if( !wastranspose ) - { - applyrotationsfromtheright(ae_false, 1, zrows, l, m, &workc, &works, z, &wtemp, _state); - } - else - { - applyrotationsfromtheleft(ae_false, l, m, 1, zrows, &workc, &works, z, &wtemp, _state); - } - } - d->ptr.p_double[l] = d->ptr.p_double[l]-p; - e->ptr.p_double[l] = g; - continue; - } - - /* - * Eigenvalue found. - */ - d->ptr.p_double[l] = p; - l = l+1; - if( l<=lend ) - { - continue; - } - break; - } - } - else - { - - /* - * QR Iteration - * - * Look for small superdiagonal element. - */ - for(;;) - { - gotoflag = ae_false; - if( l!=lend ) - { - lendp1 = lend+1; - for(m=l; m>=lendp1; m--) - { - tst = ae_sqr(ae_fabs(e->ptr.p_double[m-1], _state), _state); - if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m-1], _state)+safmin) ) - { - gotoflag = ae_true; - break; - } - } - } - if( !gotoflag ) - { - m = lend; - } - if( m>lend ) - { - e->ptr.p_double[m-1] = 0; - } - p = d->ptr.p_double[l]; - if( m!=l ) - { - - /* - * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 - * to compute its eigensystem. - */ - if( m==l-1 ) - { - if( zneeded>0 ) - { - evd_tdevdev2(d->ptr.p_double[l-1], e->ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, &c, &s, _state); - work1.ptr.p_double[m] = c; - work2.ptr.p_double[m] = s; - workc.ptr.p_double[1] = c; - works.ptr.p_double[1] = s; - if( !wastranspose ) - { - applyrotationsfromtheright(ae_true, 1, zrows, l-1, l, &workc, &works, z, &wtemp, _state); - } - else - { - applyrotationsfromtheleft(ae_true, l-1, l, 1, zrows, &workc, &works, z, &wtemp, _state); - } - } - else - { - evd_tdevde2(d->ptr.p_double[l-1], e->ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, _state); - } - d->ptr.p_double[l-1] = rt1; - d->ptr.p_double[l] = rt2; - e->ptr.p_double[l-1] = 0; - l = l-2; - if( l>=lend ) - { - continue; - } - break; - } - if( jtot==nmaxit ) - { - break; - } - jtot = jtot+1; - - /* - * Form shift. - */ - g = (d->ptr.p_double[l-1]-p)/(2*e->ptr.p_double[l-1]); - r = evd_tdevdpythag(g, 1, _state); - g = d->ptr.p_double[m]-p+e->ptr.p_double[l-1]/(g+evd_tdevdextsign(r, g, _state)); - s = 1; - c = 1; - p = 0; - - /* - * Inner loop - */ - lm1 = l-1; - for(i=m; i<=lm1; i++) - { - f = s*e->ptr.p_double[i]; - b = c*e->ptr.p_double[i]; - generaterotation(g, f, &c, &s, &r, _state); - if( i!=m ) - { - e->ptr.p_double[i-1] = r; - } - g = d->ptr.p_double[i]-p; - r = (d->ptr.p_double[i+1]-g)*s+2*c*b; - p = s*r; - d->ptr.p_double[i] = g+p; - g = c*r-b; - - /* - * If eigenvectors are desired, then save rotations. - */ - if( zneeded>0 ) - { - work1.ptr.p_double[i] = c; - work2.ptr.p_double[i] = s; - } - } - - /* - * If eigenvectors are desired, then apply saved rotations. - */ - if( zneeded>0 ) - { - for(i=m; i<=l-1; i++) - { - workc.ptr.p_double[i-m+1] = work1.ptr.p_double[i]; - works.ptr.p_double[i-m+1] = work2.ptr.p_double[i]; - } - if( !wastranspose ) - { - applyrotationsfromtheright(ae_true, 1, zrows, m, l, &workc, &works, z, &wtemp, _state); - } - else - { - applyrotationsfromtheleft(ae_true, m, l, 1, zrows, &workc, &works, z, &wtemp, _state); - } - } - d->ptr.p_double[l] = d->ptr.p_double[l]-p; - e->ptr.p_double[lm1] = g; - continue; - } - - /* - * Eigenvalue found. - */ - d->ptr.p_double[l] = p; - l = l-1; - if( l>=lend ) - { - continue; - } - break; - } - } - - /* - * Undo scaling if necessary - */ - if( iscale==1 ) - { - tmp = anorm/ssfmax; - tmpint = lendsv-1; - ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); - ae_v_muld(&e->ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); - } - if( iscale==2 ) - { - tmp = anorm/ssfmin; - tmpint = lendsv-1; - ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); - ae_v_muld(&e->ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); - } - - /* - * Check for no convergence to an eigenvalue after a total - * of N*MAXIT iterations. - */ - if( jtot>=nmaxit ) - { - result = ae_false; - if( wastranspose ) - { - inplacetranspose(z, 1, n, 1, n, &wtemp, _state); - } - ae_frame_leave(_state); - return result; - } - } - - /* - * Order eigenvalues and eigenvectors. - */ - if( zneeded==0 ) - { - - /* - * Sort - */ - if( n==1 ) - { - ae_frame_leave(_state); - return result; - } - if( n==2 ) - { - if( ae_fp_greater(d->ptr.p_double[1],d->ptr.p_double[2]) ) - { - tmp = d->ptr.p_double[1]; - d->ptr.p_double[1] = d->ptr.p_double[2]; - d->ptr.p_double[2] = tmp; - } - ae_frame_leave(_state); - return result; - } - i = 2; - do - { - t = i; - while(t!=1) - { - k = t/2; - if( ae_fp_greater_eq(d->ptr.p_double[k],d->ptr.p_double[t]) ) - { - t = 1; - } - else - { - tmp = d->ptr.p_double[k]; - d->ptr.p_double[k] = d->ptr.p_double[t]; - d->ptr.p_double[t] = tmp; - t = k; - } - } - i = i+1; - } - while(i<=n); - i = n-1; - do - { - tmp = d->ptr.p_double[i+1]; - d->ptr.p_double[i+1] = d->ptr.p_double[1]; - d->ptr.p_double[1] = tmp; - t = 1; - while(t!=0) - { - k = 2*t; - if( k>i ) - { - t = 0; - } - else - { - if( kptr.p_double[k+1],d->ptr.p_double[k]) ) - { - k = k+1; - } - } - if( ae_fp_greater_eq(d->ptr.p_double[t],d->ptr.p_double[k]) ) - { - t = 0; - } - else - { - tmp = d->ptr.p_double[k]; - d->ptr.p_double[k] = d->ptr.p_double[t]; - d->ptr.p_double[t] = tmp; - t = k; - } - } - } - i = i-1; - } - while(i>=1); - } - else - { - - /* - * Use Selection Sort to minimize swaps of eigenvectors - */ - for(ii=2; ii<=n; ii++) - { - i = ii-1; - k = i; - p = d->ptr.p_double[i]; - for(j=ii; j<=n; j++) - { - if( ae_fp_less(d->ptr.p_double[j],p) ) - { - k = j; - p = d->ptr.p_double[j]; - } - } - if( k!=i ) - { - d->ptr.p_double[k] = d->ptr.p_double[i]; - d->ptr.p_double[i] = p; - if( wastranspose ) - { - ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[i][1], 1, ae_v_len(1,n)); - ae_v_move(&z->ptr.pp_double[i][1], 1, &z->ptr.pp_double[k][1], 1, ae_v_len(1,n)); - ae_v_move(&z->ptr.pp_double[k][1], 1, &wtemp.ptr.p_double[1], 1, ae_v_len(1,n)); - } - else - { - ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[1][i], z->stride, ae_v_len(1,zrows)); - ae_v_move(&z->ptr.pp_double[1][i], z->stride, &z->ptr.pp_double[1][k], z->stride, ae_v_len(1,zrows)); - ae_v_move(&z->ptr.pp_double[1][k], z->stride, &wtemp.ptr.p_double[1], 1, ae_v_len(1,zrows)); - } - } - } - if( wastranspose ) - { - inplacetranspose(z, 1, n, 1, n, &wtemp, _state); - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix - [ A B ] - [ B C ]. -On return, RT1 is the eigenvalue of larger absolute value, and RT2 -is the eigenvalue of smaller absolute value. - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -static void evd_tdevde2(double a, - double b, - double c, - double* rt1, - double* rt2, - ae_state *_state) -{ - double ab; - double acmn; - double acmx; - double adf; - double df; - double rt; - double sm; - double tb; - - *rt1 = 0; - *rt2 = 0; - - sm = a+c; - df = a-c; - adf = ae_fabs(df, _state); - tb = b+b; - ab = ae_fabs(tb, _state); - if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) - { - acmx = a; - acmn = c; - } - else - { - acmx = c; - acmn = a; - } - if( ae_fp_greater(adf,ab) ) - { - rt = adf*ae_sqrt(1+ae_sqr(ab/adf, _state), _state); - } - else - { - if( ae_fp_less(adf,ab) ) - { - rt = ab*ae_sqrt(1+ae_sqr(adf/ab, _state), _state); - } - else - { - - /* - * Includes case AB=ADF=0 - */ - rt = ab*ae_sqrt(2, _state); - } - } - if( ae_fp_less(sm,0) ) - { - *rt1 = 0.5*(sm-rt); - - /* - * Order of execution important. - * To get fully accurate smaller eigenvalue, - * next line needs to be executed in higher precision. - */ - *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; - } - else - { - if( ae_fp_greater(sm,0) ) - { - *rt1 = 0.5*(sm+rt); - - /* - * Order of execution important. - * To get fully accurate smaller eigenvalue, - * next line needs to be executed in higher precision. - */ - *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; - } - else - { - - /* - * Includes case RT1 = RT2 = 0 - */ - *rt1 = 0.5*rt; - *rt2 = -0.5*rt; - } - } -} - - -/************************************************************************* -DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix - - [ A B ] - [ B C ]. - -On return, RT1 is the eigenvalue of larger absolute value, RT2 is the -eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right -eigenvector for RT1, giving the decomposition - - [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] - [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. - - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -static void evd_tdevdev2(double a, - double b, - double c, - double* rt1, - double* rt2, - double* cs1, - double* sn1, - ae_state *_state) -{ - ae_int_t sgn1; - ae_int_t sgn2; - double ab; - double acmn; - double acmx; - double acs; - double adf; - double cs; - double ct; - double df; - double rt; - double sm; - double tb; - double tn; - - *rt1 = 0; - *rt2 = 0; - *cs1 = 0; - *sn1 = 0; - - - /* - * Compute the eigenvalues - */ - sm = a+c; - df = a-c; - adf = ae_fabs(df, _state); - tb = b+b; - ab = ae_fabs(tb, _state); - if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) - { - acmx = a; - acmn = c; - } - else - { - acmx = c; - acmn = a; - } - if( ae_fp_greater(adf,ab) ) - { - rt = adf*ae_sqrt(1+ae_sqr(ab/adf, _state), _state); - } - else - { - if( ae_fp_less(adf,ab) ) - { - rt = ab*ae_sqrt(1+ae_sqr(adf/ab, _state), _state); - } - else - { - - /* - * Includes case AB=ADF=0 - */ - rt = ab*ae_sqrt(2, _state); - } - } - if( ae_fp_less(sm,0) ) - { - *rt1 = 0.5*(sm-rt); - sgn1 = -1; - - /* - * Order of execution important. - * To get fully accurate smaller eigenvalue, - * next line needs to be executed in higher precision. - */ - *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; - } - else - { - if( ae_fp_greater(sm,0) ) - { - *rt1 = 0.5*(sm+rt); - sgn1 = 1; - - /* - * Order of execution important. - * To get fully accurate smaller eigenvalue, - * next line needs to be executed in higher precision. - */ - *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; - } - else - { - - /* - * Includes case RT1 = RT2 = 0 - */ - *rt1 = 0.5*rt; - *rt2 = -0.5*rt; - sgn1 = 1; - } - } - - /* - * Compute the eigenvector - */ - if( ae_fp_greater_eq(df,0) ) - { - cs = df+rt; - sgn2 = 1; - } - else - { - cs = df-rt; - sgn2 = -1; - } - acs = ae_fabs(cs, _state); - if( ae_fp_greater(acs,ab) ) - { - ct = -tb/cs; - *sn1 = 1/ae_sqrt(1+ct*ct, _state); - *cs1 = ct*(*sn1); - } - else - { - if( ae_fp_eq(ab,0) ) - { - *cs1 = 1; - *sn1 = 0; - } - else - { - tn = -cs/tb; - *cs1 = 1/ae_sqrt(1+tn*tn, _state); - *sn1 = tn*(*cs1); - } - } - if( sgn1==sgn2 ) - { - tn = *cs1; - *cs1 = -*sn1; - *sn1 = tn; - } -} - - -/************************************************************************* -Internal routine -*************************************************************************/ -static double evd_tdevdpythag(double a, double b, ae_state *_state) -{ - double result; - - - if( ae_fp_less(ae_fabs(a, _state),ae_fabs(b, _state)) ) - { - result = ae_fabs(b, _state)*ae_sqrt(1+ae_sqr(a/b, _state), _state); - } - else - { - result = ae_fabs(a, _state)*ae_sqrt(1+ae_sqr(b/a, _state), _state); - } - return result; -} - - -/************************************************************************* -Internal routine -*************************************************************************/ -static double evd_tdevdextsign(double a, double b, ae_state *_state) -{ - double result; - - - if( ae_fp_greater_eq(b,0) ) - { - result = ae_fabs(a, _state); - } - else - { - result = -ae_fabs(a, _state); - } - return result; -} - - -static ae_bool evd_internalbisectioneigenvalues(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t irange, - ae_int_t iorder, - double vl, - double vu, - ae_int_t il, - ae_int_t iu, - double abstol, - /* Real */ ae_vector* w, - ae_int_t* m, - ae_int_t* nsplit, - /* Integer */ ae_vector* iblock, - /* Integer */ ae_vector* isplit, - ae_int_t* errorcode, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _d; - ae_vector _e; - double fudge; - double relfac; - ae_bool ncnvrg; - ae_bool toofew; - ae_int_t ib; - ae_int_t ibegin; - ae_int_t idiscl; - ae_int_t idiscu; - ae_int_t ie; - ae_int_t iend; - ae_int_t iinfo; - ae_int_t im; - ae_int_t iin; - ae_int_t ioff; - ae_int_t iout; - ae_int_t itmax; - ae_int_t iw; - ae_int_t iwoff; - ae_int_t j; - ae_int_t itmp1; - ae_int_t jb; - ae_int_t jdisc; - ae_int_t je; - ae_int_t nwl; - ae_int_t nwu; - double atoli; - double bnorm; - double gl; - double gu; - double pivmin; - double rtoli; - double safemn; - double tmp1; - double tmp2; - double tnorm; - double ulp; - double wkill; - double wl; - double wlu; - double wu; - double wul; - double scalefactor; - double t; - ae_vector idumma; - ae_vector work; - ae_vector iwork; - ae_vector ia1s2; - ae_vector ra1s2; - ae_matrix ra1s2x2; - ae_matrix ia1s2x2; - ae_vector ra1siin; - ae_vector ra2siin; - ae_vector ra3siin; - ae_vector ra4siin; - ae_matrix ra1siinx2; - ae_matrix ia1siinx2; - ae_vector iworkspace; - ae_vector rworkspace; - ae_int_t tmpi; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_d, d, _state, ae_true); - d = &_d; - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_clear(w); - *m = 0; - *nsplit = 0; - ae_vector_clear(iblock); - ae_vector_clear(isplit); - *errorcode = 0; - ae_vector_init(&idumma, 0, DT_INT, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); - ae_vector_init(&ia1s2, 0, DT_INT, _state, ae_true); - ae_vector_init(&ra1s2, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ra1s2x2, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ia1s2x2, 0, 0, DT_INT, _state, ae_true); - ae_vector_init(&ra1siin, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ra2siin, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ra3siin, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ra4siin, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ra1siinx2, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ia1siinx2, 0, 0, DT_INT, _state, ae_true); - ae_vector_init(&iworkspace, 0, DT_INT, _state, ae_true); - ae_vector_init(&rworkspace, 0, DT_REAL, _state, ae_true); - - - /* - * Quick return if possible - */ - *m = 0; - if( n==0 ) - { - result = ae_true; - ae_frame_leave(_state); - return result; - } - - /* - * Get machine constants - * NB is the minimum vector length for vector bisection, or 0 - * if only scalar is to be done. - */ - fudge = 2; - relfac = 2; - safemn = ae_minrealnumber; - ulp = 2*ae_machineepsilon; - rtoli = ulp*relfac; - ae_vector_set_length(&idumma, 1+1, _state); - ae_vector_set_length(&work, 4*n+1, _state); - ae_vector_set_length(&iwork, 3*n+1, _state); - ae_vector_set_length(w, n+1, _state); - ae_vector_set_length(iblock, n+1, _state); - ae_vector_set_length(isplit, n+1, _state); - ae_vector_set_length(&ia1s2, 2+1, _state); - ae_vector_set_length(&ra1s2, 2+1, _state); - ae_matrix_set_length(&ra1s2x2, 2+1, 2+1, _state); - ae_matrix_set_length(&ia1s2x2, 2+1, 2+1, _state); - ae_vector_set_length(&ra1siin, n+1, _state); - ae_vector_set_length(&ra2siin, n+1, _state); - ae_vector_set_length(&ra3siin, n+1, _state); - ae_vector_set_length(&ra4siin, n+1, _state); - ae_matrix_set_length(&ra1siinx2, n+1, 2+1, _state); - ae_matrix_set_length(&ia1siinx2, n+1, 2+1, _state); - ae_vector_set_length(&iworkspace, n+1, _state); - ae_vector_set_length(&rworkspace, n+1, _state); - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - wlu = 0; - wul = 0; - - /* - * Check for Errors - */ - result = ae_false; - *errorcode = 0; - if( irange<=0||irange>=4 ) - { - *errorcode = -4; - } - if( iorder<=0||iorder>=3 ) - { - *errorcode = -5; - } - if( n<0 ) - { - *errorcode = -3; - } - if( irange==2&&ae_fp_greater_eq(vl,vu) ) - { - *errorcode = -6; - } - if( irange==3&&(il<1||il>ae_maxint(1, n, _state)) ) - { - *errorcode = -8; - } - if( irange==3&&(iun) ) - { - *errorcode = -9; - } - if( *errorcode!=0 ) - { - ae_frame_leave(_state); - return result; - } - - /* - * Initialize error flags - */ - ncnvrg = ae_false; - toofew = ae_false; - - /* - * Simplifications: - */ - if( (irange==3&&il==1)&&iu==n ) - { - irange = 1; - } - - /* - * Special Case when N=1 - */ - if( n==1 ) - { - *nsplit = 1; - isplit->ptr.p_int[1] = 1; - if( irange==2&&(ae_fp_greater_eq(vl,d->ptr.p_double[1])||ae_fp_less(vu,d->ptr.p_double[1])) ) - { - *m = 0; - } - else - { - w->ptr.p_double[1] = d->ptr.p_double[1]; - iblock->ptr.p_int[1] = 1; - *m = 1; - } - result = ae_true; - ae_frame_leave(_state); - return result; - } - - /* - * Scaling - */ - t = ae_fabs(d->ptr.p_double[n], _state); - for(j=1; j<=n-1; j++) - { - t = ae_maxreal(t, ae_fabs(d->ptr.p_double[j], _state), _state); - t = ae_maxreal(t, ae_fabs(e->ptr.p_double[j], _state), _state); - } - scalefactor = 1; - if( ae_fp_neq(t,0) ) - { - if( ae_fp_greater(t,ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state)*ae_sqrt(ae_maxrealnumber, _state)) ) - { - scalefactor = t; - } - if( ae_fp_less(t,ae_sqrt(ae_sqrt(ae_maxrealnumber, _state), _state)*ae_sqrt(ae_minrealnumber, _state)) ) - { - scalefactor = t; - } - for(j=1; j<=n-1; j++) - { - d->ptr.p_double[j] = d->ptr.p_double[j]/scalefactor; - e->ptr.p_double[j] = e->ptr.p_double[j]/scalefactor; - } - d->ptr.p_double[n] = d->ptr.p_double[n]/scalefactor; - } - - /* - * Compute Splitting Points - */ - *nsplit = 1; - work.ptr.p_double[n] = 0; - pivmin = 1; - for(j=2; j<=n; j++) - { - tmp1 = ae_sqr(e->ptr.p_double[j-1], _state); - if( ae_fp_greater(ae_fabs(d->ptr.p_double[j]*d->ptr.p_double[j-1], _state)*ae_sqr(ulp, _state)+safemn,tmp1) ) - { - isplit->ptr.p_int[*nsplit] = j-1; - *nsplit = *nsplit+1; - work.ptr.p_double[j-1] = 0; - } - else - { - work.ptr.p_double[j-1] = tmp1; - pivmin = ae_maxreal(pivmin, tmp1, _state); - } - } - isplit->ptr.p_int[*nsplit] = n; - pivmin = pivmin*safemn; - - /* - * Compute Interval and ATOLI - */ - if( irange==3 ) - { - - /* - * RANGE='I': Compute the interval containing eigenvalues - * IL through IU. - * - * Compute Gershgorin interval for entire (split) matrix - * and use it as the initial interval - */ - gu = d->ptr.p_double[1]; - gl = d->ptr.p_double[1]; - tmp1 = 0; - for(j=1; j<=n-1; j++) - { - tmp2 = ae_sqrt(work.ptr.p_double[j], _state); - gu = ae_maxreal(gu, d->ptr.p_double[j]+tmp1+tmp2, _state); - gl = ae_minreal(gl, d->ptr.p_double[j]-tmp1-tmp2, _state); - tmp1 = tmp2; - } - gu = ae_maxreal(gu, d->ptr.p_double[n]+tmp1, _state); - gl = ae_minreal(gl, d->ptr.p_double[n]-tmp1, _state); - tnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); - gl = gl-fudge*tnorm*ulp*n-fudge*2*pivmin; - gu = gu+fudge*tnorm*ulp*n+fudge*pivmin; - - /* - * Compute Iteration parameters - */ - itmax = ae_iceil((ae_log(tnorm+pivmin, _state)-ae_log(pivmin, _state))/ae_log(2, _state), _state)+2; - if( ae_fp_less_eq(abstol,0) ) - { - atoli = ulp*tnorm; - } - else - { - atoli = abstol; - } - work.ptr.p_double[n+1] = gl; - work.ptr.p_double[n+2] = gl; - work.ptr.p_double[n+3] = gu; - work.ptr.p_double[n+4] = gu; - work.ptr.p_double[n+5] = gl; - work.ptr.p_double[n+6] = gu; - iwork.ptr.p_int[1] = -1; - iwork.ptr.p_int[2] = -1; - iwork.ptr.p_int[3] = n+1; - iwork.ptr.p_int[4] = n+1; - iwork.ptr.p_int[5] = il-1; - iwork.ptr.p_int[6] = iu; - - /* - * Calling DLAEBZ - * - * DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN, D, E, - * WORK, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT, - * IWORK, W, IBLOCK, IINFO ) - */ - ia1s2.ptr.p_int[1] = iwork.ptr.p_int[5]; - ia1s2.ptr.p_int[2] = iwork.ptr.p_int[6]; - ra1s2.ptr.p_double[1] = work.ptr.p_double[n+5]; - ra1s2.ptr.p_double[2] = work.ptr.p_double[n+6]; - ra1s2x2.ptr.pp_double[1][1] = work.ptr.p_double[n+1]; - ra1s2x2.ptr.pp_double[2][1] = work.ptr.p_double[n+2]; - ra1s2x2.ptr.pp_double[1][2] = work.ptr.p_double[n+3]; - ra1s2x2.ptr.pp_double[2][2] = work.ptr.p_double[n+4]; - ia1s2x2.ptr.pp_int[1][1] = iwork.ptr.p_int[1]; - ia1s2x2.ptr.pp_int[2][1] = iwork.ptr.p_int[2]; - ia1s2x2.ptr.pp_int[1][2] = iwork.ptr.p_int[3]; - ia1s2x2.ptr.pp_int[2][2] = iwork.ptr.p_int[4]; - evd_internaldlaebz(3, itmax, n, 2, 2, atoli, rtoli, pivmin, d, e, &work, &ia1s2, &ra1s2x2, &ra1s2, &iout, &ia1s2x2, w, iblock, &iinfo, _state); - iwork.ptr.p_int[5] = ia1s2.ptr.p_int[1]; - iwork.ptr.p_int[6] = ia1s2.ptr.p_int[2]; - work.ptr.p_double[n+5] = ra1s2.ptr.p_double[1]; - work.ptr.p_double[n+6] = ra1s2.ptr.p_double[2]; - work.ptr.p_double[n+1] = ra1s2x2.ptr.pp_double[1][1]; - work.ptr.p_double[n+2] = ra1s2x2.ptr.pp_double[2][1]; - work.ptr.p_double[n+3] = ra1s2x2.ptr.pp_double[1][2]; - work.ptr.p_double[n+4] = ra1s2x2.ptr.pp_double[2][2]; - iwork.ptr.p_int[1] = ia1s2x2.ptr.pp_int[1][1]; - iwork.ptr.p_int[2] = ia1s2x2.ptr.pp_int[2][1]; - iwork.ptr.p_int[3] = ia1s2x2.ptr.pp_int[1][2]; - iwork.ptr.p_int[4] = ia1s2x2.ptr.pp_int[2][2]; - if( iwork.ptr.p_int[6]==iu ) - { - wl = work.ptr.p_double[n+1]; - wlu = work.ptr.p_double[n+3]; - nwl = iwork.ptr.p_int[1]; - wu = work.ptr.p_double[n+4]; - wul = work.ptr.p_double[n+2]; - nwu = iwork.ptr.p_int[4]; - } - else - { - wl = work.ptr.p_double[n+2]; - wlu = work.ptr.p_double[n+4]; - nwl = iwork.ptr.p_int[2]; - wu = work.ptr.p_double[n+3]; - wul = work.ptr.p_double[n+1]; - nwu = iwork.ptr.p_int[3]; - } - if( ((nwl<0||nwl>=n)||nwu<1)||nwu>n ) - { - *errorcode = 4; - result = ae_false; - ae_frame_leave(_state); - return result; - } - } - else - { - - /* - * RANGE='A' or 'V' -- Set ATOLI - */ - tnorm = ae_maxreal(ae_fabs(d->ptr.p_double[1], _state)+ae_fabs(e->ptr.p_double[1], _state), ae_fabs(d->ptr.p_double[n], _state)+ae_fabs(e->ptr.p_double[n-1], _state), _state); - for(j=2; j<=n-1; j++) - { - tnorm = ae_maxreal(tnorm, ae_fabs(d->ptr.p_double[j], _state)+ae_fabs(e->ptr.p_double[j-1], _state)+ae_fabs(e->ptr.p_double[j], _state), _state); - } - if( ae_fp_less_eq(abstol,0) ) - { - atoli = ulp*tnorm; - } - else - { - atoli = abstol; - } - if( irange==2 ) - { - wl = vl; - wu = vu; - } - else - { - wl = 0; - wu = 0; - } - } - - /* - * Find Eigenvalues -- Loop Over Blocks and recompute NWL and NWU. - * NWL accumulates the number of eigenvalues .le. WL, - * NWU accumulates the number of eigenvalues .le. WU - */ - *m = 0; - iend = 0; - *errorcode = 0; - nwl = 0; - nwu = 0; - for(jb=1; jb<=*nsplit; jb++) - { - ioff = iend; - ibegin = ioff+1; - iend = isplit->ptr.p_int[jb]; - iin = iend-ioff; - if( iin==1 ) - { - - /* - * Special Case -- IIN=1 - */ - if( irange==1||ae_fp_greater_eq(wl,d->ptr.p_double[ibegin]-pivmin) ) - { - nwl = nwl+1; - } - if( irange==1||ae_fp_greater_eq(wu,d->ptr.p_double[ibegin]-pivmin) ) - { - nwu = nwu+1; - } - if( irange==1||(ae_fp_less(wl,d->ptr.p_double[ibegin]-pivmin)&&ae_fp_greater_eq(wu,d->ptr.p_double[ibegin]-pivmin)) ) - { - *m = *m+1; - w->ptr.p_double[*m] = d->ptr.p_double[ibegin]; - iblock->ptr.p_int[*m] = jb; - } - } - else - { - - /* - * General Case -- IIN > 1 - * - * Compute Gershgorin Interval - * and use it as the initial interval - */ - gu = d->ptr.p_double[ibegin]; - gl = d->ptr.p_double[ibegin]; - tmp1 = 0; - for(j=ibegin; j<=iend-1; j++) - { - tmp2 = ae_fabs(e->ptr.p_double[j], _state); - gu = ae_maxreal(gu, d->ptr.p_double[j]+tmp1+tmp2, _state); - gl = ae_minreal(gl, d->ptr.p_double[j]-tmp1-tmp2, _state); - tmp1 = tmp2; - } - gu = ae_maxreal(gu, d->ptr.p_double[iend]+tmp1, _state); - gl = ae_minreal(gl, d->ptr.p_double[iend]-tmp1, _state); - bnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); - gl = gl-fudge*bnorm*ulp*iin-fudge*pivmin; - gu = gu+fudge*bnorm*ulp*iin+fudge*pivmin; - - /* - * Compute ATOLI for the current submatrix - */ - if( ae_fp_less_eq(abstol,0) ) - { - atoli = ulp*ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); - } - else - { - atoli = abstol; - } - if( irange>1 ) - { - if( ae_fp_less(gu,wl) ) - { - nwl = nwl+iin; - nwu = nwu+iin; - continue; - } - gl = ae_maxreal(gl, wl, _state); - gu = ae_minreal(gu, wu, _state); - if( ae_fp_greater_eq(gl,gu) ) - { - continue; - } - } - - /* - * Set Up Initial Interval - */ - work.ptr.p_double[n+1] = gl; - work.ptr.p_double[n+iin+1] = gu; - - /* - * Calling DLAEBZ - * - * CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, - * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), - * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM, - * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) - */ - for(tmpi=1; tmpi<=iin; tmpi++) - { - ra1siin.ptr.p_double[tmpi] = d->ptr.p_double[ibegin-1+tmpi]; - if( ibegin-1+tmpiptr.p_double[ibegin-1+tmpi]; - } - ra3siin.ptr.p_double[tmpi] = work.ptr.p_double[ibegin-1+tmpi]; - ra1siinx2.ptr.pp_double[tmpi][1] = work.ptr.p_double[n+tmpi]; - ra1siinx2.ptr.pp_double[tmpi][2] = work.ptr.p_double[n+tmpi+iin]; - ra4siin.ptr.p_double[tmpi] = work.ptr.p_double[n+2*iin+tmpi]; - rworkspace.ptr.p_double[tmpi] = w->ptr.p_double[*m+tmpi]; - iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; - ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; - ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; - } - evd_internaldlaebz(1, 0, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &im, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); - for(tmpi=1; tmpi<=iin; tmpi++) - { - work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; - work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; - work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; - w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; - iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; - iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; - iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; - } - nwl = nwl+iwork.ptr.p_int[1]; - nwu = nwu+iwork.ptr.p_int[iin+1]; - iwoff = *m-iwork.ptr.p_int[1]; - - /* - * Compute Eigenvalues - */ - itmax = ae_iceil((ae_log(gu-gl+pivmin, _state)-ae_log(pivmin, _state))/ae_log(2, _state), _state)+2; - - /* - * Calling DLAEBZ - * - *CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, - * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), - * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT, - * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) - */ - for(tmpi=1; tmpi<=iin; tmpi++) - { - ra1siin.ptr.p_double[tmpi] = d->ptr.p_double[ibegin-1+tmpi]; - if( ibegin-1+tmpiptr.p_double[ibegin-1+tmpi]; - } - ra3siin.ptr.p_double[tmpi] = work.ptr.p_double[ibegin-1+tmpi]; - ra1siinx2.ptr.pp_double[tmpi][1] = work.ptr.p_double[n+tmpi]; - ra1siinx2.ptr.pp_double[tmpi][2] = work.ptr.p_double[n+tmpi+iin]; - ra4siin.ptr.p_double[tmpi] = work.ptr.p_double[n+2*iin+tmpi]; - rworkspace.ptr.p_double[tmpi] = w->ptr.p_double[*m+tmpi]; - iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; - ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; - ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; - } - evd_internaldlaebz(2, itmax, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &iout, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); - for(tmpi=1; tmpi<=iin; tmpi++) - { - work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; - work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; - work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; - w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; - iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; - iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; - iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; - } - - /* - * Copy Eigenvalues Into W and IBLOCK - * Use -JB for block number for unconverged eigenvalues. - */ - for(j=1; j<=iout; j++) - { - tmp1 = 0.5*(work.ptr.p_double[j+n]+work.ptr.p_double[j+iin+n]); - - /* - * Flag non-convergence. - */ - if( j>iout-iinfo ) - { - ncnvrg = ae_true; - ib = -jb; - } - else - { - ib = jb; - } - for(je=iwork.ptr.p_int[j]+1+iwoff; je<=iwork.ptr.p_int[j+iin]+iwoff; je++) - { - w->ptr.p_double[je] = tmp1; - iblock->ptr.p_int[je] = ib; - } - } - *m = *m+im; - } - } - - /* - * If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU - * If NWL+1 < IL or NWU > IU, discard extra eigenvalues. - */ - if( irange==3 ) - { - im = 0; - idiscl = il-1-nwl; - idiscu = nwu-iu; - if( idiscl>0||idiscu>0 ) - { - for(je=1; je<=*m; je++) - { - if( ae_fp_less_eq(w->ptr.p_double[je],wlu)&&idiscl>0 ) - { - idiscl = idiscl-1; - } - else - { - if( ae_fp_greater_eq(w->ptr.p_double[je],wul)&&idiscu>0 ) - { - idiscu = idiscu-1; - } - else - { - im = im+1; - w->ptr.p_double[im] = w->ptr.p_double[je]; - iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; - } - } - } - *m = im; - } - if( idiscl>0||idiscu>0 ) - { - - /* - * Code to deal with effects of bad arithmetic: - * Some low eigenvalues to be discarded are not in (WL,WLU], - * or high eigenvalues to be discarded are not in (WUL,WU] - * so just kill off the smallest IDISCL/largest IDISCU - * eigenvalues, by simply finding the smallest/largest - * eigenvalue(s). - * - * (If N(w) is monotone non-decreasing, this should never - * happen.) - */ - if( idiscl>0 ) - { - wkill = wu; - for(jdisc=1; jdisc<=idiscl; jdisc++) - { - iw = 0; - for(je=1; je<=*m; je++) - { - if( iblock->ptr.p_int[je]!=0&&(ae_fp_less(w->ptr.p_double[je],wkill)||iw==0) ) - { - iw = je; - wkill = w->ptr.p_double[je]; - } - } - iblock->ptr.p_int[iw] = 0; - } - } - if( idiscu>0 ) - { - wkill = wl; - for(jdisc=1; jdisc<=idiscu; jdisc++) - { - iw = 0; - for(je=1; je<=*m; je++) - { - if( iblock->ptr.p_int[je]!=0&&(ae_fp_greater(w->ptr.p_double[je],wkill)||iw==0) ) - { - iw = je; - wkill = w->ptr.p_double[je]; - } - } - iblock->ptr.p_int[iw] = 0; - } - } - im = 0; - for(je=1; je<=*m; je++) - { - if( iblock->ptr.p_int[je]!=0 ) - { - im = im+1; - w->ptr.p_double[im] = w->ptr.p_double[je]; - iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; - } - } - *m = im; - } - if( idiscl<0||idiscu<0 ) - { - toofew = ae_true; - } - } - - /* - * If ORDER='B', do nothing -- the eigenvalues are already sorted - * by block. - * If ORDER='E', sort the eigenvalues from smallest to largest - */ - if( iorder==1&&*nsplit>1 ) - { - for(je=1; je<=*m-1; je++) - { - ie = 0; - tmp1 = w->ptr.p_double[je]; - for(j=je+1; j<=*m; j++) - { - if( ae_fp_less(w->ptr.p_double[j],tmp1) ) - { - ie = j; - tmp1 = w->ptr.p_double[j]; - } - } - if( ie!=0 ) - { - itmp1 = iblock->ptr.p_int[ie]; - w->ptr.p_double[ie] = w->ptr.p_double[je]; - iblock->ptr.p_int[ie] = iblock->ptr.p_int[je]; - w->ptr.p_double[je] = tmp1; - iblock->ptr.p_int[je] = itmp1; - } - } - } - for(j=1; j<=*m; j++) - { - w->ptr.p_double[j] = w->ptr.p_double[j]*scalefactor; - } - *errorcode = 0; - if( ncnvrg ) - { - *errorcode = *errorcode+1; - } - if( toofew ) - { - *errorcode = *errorcode+2; - } - result = *errorcode==0; - ae_frame_leave(_state); - return result; -} - - -static void evd_internaldstein(ae_int_t n, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t m, - /* Real */ ae_vector* w, - /* Integer */ ae_vector* iblock, - /* Integer */ ae_vector* isplit, - /* Real */ ae_matrix* z, - /* Integer */ ae_vector* ifail, - ae_int_t* info, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _e; - ae_vector _w; - ae_int_t maxits; - ae_int_t extra; - ae_int_t b1; - ae_int_t blksiz; - ae_int_t bn; - ae_int_t gpind; - ae_int_t i; - ae_int_t iinfo; - ae_int_t its; - ae_int_t j; - ae_int_t j1; - ae_int_t jblk; - ae_int_t jmax; - ae_int_t nblk; - ae_int_t nrmchk; - double dtpcrt; - double eps; - double eps1; - double nrm; - double onenrm; - double ortol; - double pertol; - double scl; - double sep; - double tol; - double xj; - double xjm; - double ztr; - ae_vector work1; - ae_vector work2; - ae_vector work3; - ae_vector work4; - ae_vector work5; - ae_vector iwork; - ae_bool tmpcriterion; - ae_int_t ti; - ae_int_t i1; - ae_int_t i2; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_e, e, _state, ae_true); - e = &_e; - ae_vector_init_copy(&_w, w, _state, ae_true); - w = &_w; - ae_matrix_clear(z); - ae_vector_clear(ifail); - *info = 0; - ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work3, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work4, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work5, 0, DT_REAL, _state, ae_true); - ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); - - maxits = 5; - extra = 2; - ae_vector_set_length(&work1, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&work2, ae_maxint(n-1, 1, _state)+1, _state); - ae_vector_set_length(&work3, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&work4, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&work5, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(&iwork, ae_maxint(n, 1, _state)+1, _state); - ae_vector_set_length(ifail, ae_maxint(m, 1, _state)+1, _state); - ae_matrix_set_length(z, ae_maxint(n, 1, _state)+1, ae_maxint(m, 1, _state)+1, _state); - - /* - * these initializers are not really necessary, - * but without them compiler complains about uninitialized locals - */ - gpind = 0; - onenrm = 0; - ortol = 0; - dtpcrt = 0; - xjm = 0; - - /* - * Test the input parameters. - */ - *info = 0; - for(i=1; i<=m; i++) - { - ifail->ptr.p_int[i] = 0; - } - if( n<0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( m<0||m>n ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - for(j=2; j<=m; j++) - { - if( iblock->ptr.p_int[j]ptr.p_int[j-1] ) - { - *info = -6; - break; - } - if( iblock->ptr.p_int[j]==iblock->ptr.p_int[j-1]&&ae_fp_less(w->ptr.p_double[j],w->ptr.p_double[j-1]) ) - { - *info = -5; - break; - } - } - if( *info!=0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Quick return if possible - */ - if( n==0||m==0 ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - z->ptr.pp_double[1][1] = 1; - ae_frame_leave(_state); - return; - } - - /* - * Some preparations - */ - ti = n-1; - ae_v_move(&work1.ptr.p_double[1], 1, &e->ptr.p_double[1], 1, ae_v_len(1,ti)); - ae_vector_set_length(e, n+1, _state); - ae_v_move(&e->ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,ti)); - ae_v_move(&work1.ptr.p_double[1], 1, &w->ptr.p_double[1], 1, ae_v_len(1,m)); - ae_vector_set_length(w, n+1, _state); - ae_v_move(&w->ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,m)); - - /* - * Get machine constants. - */ - eps = ae_machineepsilon; - - /* - * Compute eigenvectors of matrix blocks. - */ - j1 = 1; - for(nblk=1; nblk<=iblock->ptr.p_int[m]; nblk++) - { - - /* - * Find starting and ending indices of block nblk. - */ - if( nblk==1 ) - { - b1 = 1; - } - else - { - b1 = isplit->ptr.p_int[nblk-1]+1; - } - bn = isplit->ptr.p_int[nblk]; - blksiz = bn-b1+1; - if( blksiz!=1 ) - { - - /* - * Compute reorthogonalization criterion and stopping criterion. - */ - gpind = b1; - onenrm = ae_fabs(d->ptr.p_double[b1], _state)+ae_fabs(e->ptr.p_double[b1], _state); - onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[bn], _state)+ae_fabs(e->ptr.p_double[bn-1], _state), _state); - for(i=b1+1; i<=bn-1; i++) - { - onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e->ptr.p_double[i-1], _state)+ae_fabs(e->ptr.p_double[i], _state), _state); - } - ortol = 0.001*onenrm; - dtpcrt = ae_sqrt(0.1/blksiz, _state); - } - - /* - * Loop through eigenvalues of block nblk. - */ - jblk = 0; - for(j=j1; j<=m; j++) - { - if( iblock->ptr.p_int[j]!=nblk ) - { - j1 = j; - break; - } - jblk = jblk+1; - xj = w->ptr.p_double[j]; - if( blksiz==1 ) - { - - /* - * Skip all the work if the block size is one. - */ - work1.ptr.p_double[1] = 1; - } - else - { - - /* - * If eigenvalues j and j-1 are too close, add a relatively - * small perturbation. - */ - if( jblk>1 ) - { - eps1 = ae_fabs(eps*xj, _state); - pertol = 10*eps1; - sep = xj-xjm; - if( ae_fp_less(sep,pertol) ) - { - xj = xjm+pertol; - } - } - its = 0; - nrmchk = 0; - - /* - * Get random starting vector. - */ - for(ti=1; ti<=blksiz; ti++) - { - work1.ptr.p_double[ti] = 2*ae_randomreal(_state)-1; - } - - /* - * Copy the matrix T so it won't be destroyed in factorization. - */ - for(ti=1; ti<=blksiz-1; ti++) - { - work2.ptr.p_double[ti] = e->ptr.p_double[b1+ti-1]; - work3.ptr.p_double[ti] = e->ptr.p_double[b1+ti-1]; - work4.ptr.p_double[ti] = d->ptr.p_double[b1+ti-1]; - } - work4.ptr.p_double[blksiz] = d->ptr.p_double[b1+blksiz-1]; - - /* - * Compute LU factors with partial pivoting ( PT = LU ) - */ - tol = 0; - evd_tdininternaldlagtf(blksiz, &work4, xj, &work2, &work3, tol, &work5, &iwork, &iinfo, _state); - - /* - * Update iteration count. - */ - do - { - its = its+1; - if( its>maxits ) - { - - /* - * If stopping criterion was not satisfied, update info and - * store eigenvector number in array ifail. - */ - *info = *info+1; - ifail->ptr.p_int[*info] = j; - break; - } - - /* - * Normalize and scale the righthand side vector Pb. - */ - v = 0; - for(ti=1; ti<=blksiz; ti++) - { - v = v+ae_fabs(work1.ptr.p_double[ti], _state); - } - scl = blksiz*onenrm*ae_maxreal(eps, ae_fabs(work4.ptr.p_double[blksiz], _state), _state)/v; - ae_v_muld(&work1.ptr.p_double[1], 1, ae_v_len(1,blksiz), scl); - - /* - * Solve the system LU = Pb. - */ - evd_tdininternaldlagts(blksiz, &work4, &work2, &work3, &work5, &iwork, &work1, &tol, &iinfo, _state); - - /* - * Reorthogonalize by modified Gram-Schmidt if eigenvalues are - * close enough. - */ - if( jblk!=1 ) - { - if( ae_fp_greater(ae_fabs(xj-xjm, _state),ortol) ) - { - gpind = j; - } - if( gpind!=j ) - { - for(i=gpind; i<=j-1; i++) - { - i1 = b1; - i2 = b1+blksiz-1; - ztr = ae_v_dotproduct(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz)); - ae_v_subd(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz), ztr); - touchint(&i2, _state); - } - } - } - - /* - * Check the infinity norm of the iterate. - */ - jmax = vectoridxabsmax(&work1, 1, blksiz, _state); - nrm = ae_fabs(work1.ptr.p_double[jmax], _state); - - /* - * Continue for additional iterations after norm reaches - * stopping criterion. - */ - tmpcriterion = ae_false; - if( ae_fp_less(nrm,dtpcrt) ) - { - tmpcriterion = ae_true; - } - else - { - nrmchk = nrmchk+1; - if( nrmchkptr.pp_double[i][j] = 0; - } - for(i=1; i<=blksiz; i++) - { - z->ptr.pp_double[b1+i-1][j] = work1.ptr.p_double[i]; - } - - /* - * Save the shift to check eigenvalue spacing at next - * iteration. - */ - xjm = xj; - } - } - ae_frame_leave(_state); -} - - -static void evd_tdininternaldlagtf(ae_int_t n, - /* Real */ ae_vector* a, - double lambdav, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - double tol, - /* Real */ ae_vector* d, - /* Integer */ ae_vector* iin, - ae_int_t* info, - ae_state *_state) -{ - ae_int_t k; - double eps; - double mult; - double piv1; - double piv2; - double scale1; - double scale2; - double temp; - double tl; - - *info = 0; - - *info = 0; - if( n<0 ) - { - *info = -1; - return; - } - if( n==0 ) - { - return; - } - a->ptr.p_double[1] = a->ptr.p_double[1]-lambdav; - iin->ptr.p_int[n] = 0; - if( n==1 ) - { - if( ae_fp_eq(a->ptr.p_double[1],0) ) - { - iin->ptr.p_int[1] = 1; - } - return; - } - eps = ae_machineepsilon; - tl = ae_maxreal(tol, eps, _state); - scale1 = ae_fabs(a->ptr.p_double[1], _state)+ae_fabs(b->ptr.p_double[1], _state); - for(k=1; k<=n-1; k++) - { - a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-lambdav; - scale2 = ae_fabs(c->ptr.p_double[k], _state)+ae_fabs(a->ptr.p_double[k+1], _state); - if( kptr.p_double[k+1], _state); - } - if( ae_fp_eq(a->ptr.p_double[k],0) ) - { - piv1 = 0; - } - else - { - piv1 = ae_fabs(a->ptr.p_double[k], _state)/scale1; - } - if( ae_fp_eq(c->ptr.p_double[k],0) ) - { - iin->ptr.p_int[k] = 0; - piv2 = 0; - scale1 = scale2; - if( kptr.p_double[k] = 0; - } - } - else - { - piv2 = ae_fabs(c->ptr.p_double[k], _state)/scale2; - if( ae_fp_less_eq(piv2,piv1) ) - { - iin->ptr.p_int[k] = 0; - scale1 = scale2; - c->ptr.p_double[k] = c->ptr.p_double[k]/a->ptr.p_double[k]; - a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-c->ptr.p_double[k]*b->ptr.p_double[k]; - if( kptr.p_double[k] = 0; - } - } - else - { - iin->ptr.p_int[k] = 1; - mult = a->ptr.p_double[k]/c->ptr.p_double[k]; - a->ptr.p_double[k] = c->ptr.p_double[k]; - temp = a->ptr.p_double[k+1]; - a->ptr.p_double[k+1] = b->ptr.p_double[k]-mult*temp; - if( kptr.p_double[k] = b->ptr.p_double[k+1]; - b->ptr.p_double[k+1] = -mult*d->ptr.p_double[k]; - } - b->ptr.p_double[k] = temp; - c->ptr.p_double[k] = mult; - } - } - if( ae_fp_less_eq(ae_maxreal(piv1, piv2, _state),tl)&&iin->ptr.p_int[n]==0 ) - { - iin->ptr.p_int[n] = k; - } - } - if( ae_fp_less_eq(ae_fabs(a->ptr.p_double[n], _state),scale1*tl)&&iin->ptr.p_int[n]==0 ) - { - iin->ptr.p_int[n] = n; - } -} - - -static void evd_tdininternaldlagts(ae_int_t n, - /* Real */ ae_vector* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* c, - /* Real */ ae_vector* d, - /* Integer */ ae_vector* iin, - /* Real */ ae_vector* y, - double* tol, - ae_int_t* info, - ae_state *_state) -{ - ae_int_t k; - double absak; - double ak; - double bignum; - double eps; - double pert; - double sfmin; - double temp; - - *info = 0; - - *info = 0; - if( n<0 ) - { - *info = -1; - return; - } - if( n==0 ) - { - return; - } - eps = ae_machineepsilon; - sfmin = ae_minrealnumber; - bignum = 1/sfmin; - if( ae_fp_less_eq(*tol,0) ) - { - *tol = ae_fabs(a->ptr.p_double[1], _state); - if( n>1 ) - { - *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[2], _state), ae_fabs(b->ptr.p_double[1], _state), _state), _state); - } - for(k=3; k<=n; k++) - { - *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[k], _state), ae_maxreal(ae_fabs(b->ptr.p_double[k-1], _state), ae_fabs(d->ptr.p_double[k-2], _state), _state), _state), _state); - } - *tol = *tol*eps; - if( ae_fp_eq(*tol,0) ) - { - *tol = eps; - } - } - for(k=2; k<=n; k++) - { - if( iin->ptr.p_int[k-1]==0 ) - { - y->ptr.p_double[k] = y->ptr.p_double[k]-c->ptr.p_double[k-1]*y->ptr.p_double[k-1]; - } - else - { - temp = y->ptr.p_double[k-1]; - y->ptr.p_double[k-1] = y->ptr.p_double[k]; - y->ptr.p_double[k] = temp-c->ptr.p_double[k-1]*y->ptr.p_double[k]; - } - } - for(k=n; k>=1; k--) - { - if( k<=n-2 ) - { - temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]-d->ptr.p_double[k]*y->ptr.p_double[k+2]; - } - else - { - if( k==n-1 ) - { - temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]; - } - else - { - temp = y->ptr.p_double[k]; - } - } - ak = a->ptr.p_double[k]; - pert = ae_fabs(*tol, _state); - if( ae_fp_less(ak,0) ) - { - pert = -pert; - } - for(;;) - { - absak = ae_fabs(ak, _state); - if( ae_fp_less(absak,1) ) - { - if( ae_fp_less(absak,sfmin) ) - { - if( ae_fp_eq(absak,0)||ae_fp_greater(ae_fabs(temp, _state)*sfmin,absak) ) - { - ak = ak+pert; - pert = 2*pert; - continue; - } - else - { - temp = temp*bignum; - ak = ak*bignum; - } - } - else - { - if( ae_fp_greater(ae_fabs(temp, _state),absak*bignum) ) - { - ak = ak+pert; - pert = 2*pert; - continue; - } - } - } - break; - } - y->ptr.p_double[k] = temp/ak; - } -} - - -static void evd_internaldlaebz(ae_int_t ijob, - ae_int_t nitmax, - ae_int_t n, - ae_int_t mmax, - ae_int_t minp, - double abstol, - double reltol, - double pivmin, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - /* Real */ ae_vector* e2, - /* Integer */ ae_vector* nval, - /* Real */ ae_matrix* ab, - /* Real */ ae_vector* c, - ae_int_t* mout, - /* Integer */ ae_matrix* nab, - /* Real */ ae_vector* work, - /* Integer */ ae_vector* iwork, - ae_int_t* info, - ae_state *_state) -{ - ae_int_t itmp1; - ae_int_t itmp2; - ae_int_t j; - ae_int_t ji; - ae_int_t jit; - ae_int_t jp; - ae_int_t kf; - ae_int_t kfnew; - ae_int_t kl; - ae_int_t klnew; - double tmp1; - double tmp2; - - *mout = 0; - *info = 0; - - *info = 0; - if( ijob<1||ijob>3 ) - { - *info = -1; - return; - } - - /* - * Initialize NAB - */ - if( ijob==1 ) - { - - /* - * Compute the number of eigenvalues in the initial intervals. - */ - *mout = 0; - - /* - *DIR$ NOVECTOR - */ - for(ji=1; ji<=minp; ji++) - { - for(jp=1; jp<=2; jp++) - { - tmp1 = d->ptr.p_double[1]-ab->ptr.pp_double[ji][jp]; - if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) - { - tmp1 = -pivmin; - } - nab->ptr.pp_int[ji][jp] = 0; - if( ae_fp_less_eq(tmp1,0) ) - { - nab->ptr.pp_int[ji][jp] = 1; - } - for(j=2; j<=n; j++) - { - tmp1 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp1-ab->ptr.pp_double[ji][jp]; - if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) - { - tmp1 = -pivmin; - } - if( ae_fp_less_eq(tmp1,0) ) - { - nab->ptr.pp_int[ji][jp] = nab->ptr.pp_int[ji][jp]+1; - } - } - } - *mout = *mout+nab->ptr.pp_int[ji][2]-nab->ptr.pp_int[ji][1]; - } - return; - } - - /* - * Initialize for loop - * - * KF and KL have the following meaning: - * Intervals 1,...,KF-1 have converged. - * Intervals KF,...,KL still need to be refined. - */ - kf = 1; - kl = minp; - - /* - * If IJOB=2, initialize C. - * If IJOB=3, use the user-supplied starting point. - */ - if( ijob==2 ) - { - for(ji=1; ji<=minp; ji++) - { - c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); - } - } - - /* - * Iteration loop - */ - for(jit=1; jit<=nitmax; jit++) - { - - /* - * Loop over intervals - * - * - * Serial Version of the loop - */ - klnew = kl; - for(ji=kf; ji<=kl; ji++) - { - - /* - * Compute N(w), the number of eigenvalues less than w - */ - tmp1 = c->ptr.p_double[ji]; - tmp2 = d->ptr.p_double[1]-tmp1; - itmp1 = 0; - if( ae_fp_less_eq(tmp2,pivmin) ) - { - itmp1 = 1; - tmp2 = ae_minreal(tmp2, -pivmin, _state); - } - - /* - * A series of compiler directives to defeat vectorization - * for the next loop - * - **$PL$ CMCHAR=' ' - *CDIR$ NEXTSCALAR - *C$DIR SCALAR - *CDIR$ NEXT SCALAR - *CVD$L NOVECTOR - *CDEC$ NOVECTOR - *CVD$ NOVECTOR - **VDIR NOVECTOR - **VOCL LOOP,SCALAR - *CIBM PREFER SCALAR - **$PL$ CMCHAR='*' - */ - for(j=2; j<=n; j++) - { - tmp2 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp2-tmp1; - if( ae_fp_less_eq(tmp2,pivmin) ) - { - itmp1 = itmp1+1; - tmp2 = ae_minreal(tmp2, -pivmin, _state); - } - } - if( ijob<=2 ) - { - - /* - * IJOB=2: Choose all intervals containing eigenvalues. - * - * Insure that N(w) is monotone - */ - itmp1 = ae_minint(nab->ptr.pp_int[ji][2], ae_maxint(nab->ptr.pp_int[ji][1], itmp1, _state), _state); - - /* - * Update the Queue -- add intervals if both halves - * contain eigenvalues. - */ - if( itmp1==nab->ptr.pp_int[ji][2] ) - { - - /* - * No eigenvalue in the upper interval: - * just use the lower interval. - */ - ab->ptr.pp_double[ji][2] = tmp1; - } - else - { - if( itmp1==nab->ptr.pp_int[ji][1] ) - { - - /* - * No eigenvalue in the lower interval: - * just use the upper interval. - */ - ab->ptr.pp_double[ji][1] = tmp1; - } - else - { - if( klnewptr.pp_double[klnew][2] = ab->ptr.pp_double[ji][2]; - nab->ptr.pp_int[klnew][2] = nab->ptr.pp_int[ji][2]; - ab->ptr.pp_double[klnew][1] = tmp1; - nab->ptr.pp_int[klnew][1] = itmp1; - ab->ptr.pp_double[ji][2] = tmp1; - nab->ptr.pp_int[ji][2] = itmp1; - } - else - { - *info = mmax+1; - return; - } - } - } - } - else - { - - /* - * IJOB=3: Binary search. Keep only the interval - * containing w s.t. N(w) = NVAL - */ - if( itmp1<=nval->ptr.p_int[ji] ) - { - ab->ptr.pp_double[ji][1] = tmp1; - nab->ptr.pp_int[ji][1] = itmp1; - } - if( itmp1>=nval->ptr.p_int[ji] ) - { - ab->ptr.pp_double[ji][2] = tmp1; - nab->ptr.pp_int[ji][2] = itmp1; - } - } - } - kl = klnew; - - /* - * Check for convergence - */ - kfnew = kf; - for(ji=kf; ji<=kl; ji++) - { - tmp1 = ae_fabs(ab->ptr.pp_double[ji][2]-ab->ptr.pp_double[ji][1], _state); - tmp2 = ae_maxreal(ae_fabs(ab->ptr.pp_double[ji][2], _state), ae_fabs(ab->ptr.pp_double[ji][1], _state), _state); - if( ae_fp_less(tmp1,ae_maxreal(abstol, ae_maxreal(pivmin, reltol*tmp2, _state), _state))||nab->ptr.pp_int[ji][1]>=nab->ptr.pp_int[ji][2] ) - { - - /* - * Converged -- Swap with position KFNEW, - * then increment KFNEW - */ - if( ji>kfnew ) - { - tmp1 = ab->ptr.pp_double[ji][1]; - tmp2 = ab->ptr.pp_double[ji][2]; - itmp1 = nab->ptr.pp_int[ji][1]; - itmp2 = nab->ptr.pp_int[ji][2]; - ab->ptr.pp_double[ji][1] = ab->ptr.pp_double[kfnew][1]; - ab->ptr.pp_double[ji][2] = ab->ptr.pp_double[kfnew][2]; - nab->ptr.pp_int[ji][1] = nab->ptr.pp_int[kfnew][1]; - nab->ptr.pp_int[ji][2] = nab->ptr.pp_int[kfnew][2]; - ab->ptr.pp_double[kfnew][1] = tmp1; - ab->ptr.pp_double[kfnew][2] = tmp2; - nab->ptr.pp_int[kfnew][1] = itmp1; - nab->ptr.pp_int[kfnew][2] = itmp2; - if( ijob==3 ) - { - itmp1 = nval->ptr.p_int[ji]; - nval->ptr.p_int[ji] = nval->ptr.p_int[kfnew]; - nval->ptr.p_int[kfnew] = itmp1; - } - } - kfnew = kfnew+1; - } - } - kf = kfnew; - - /* - * Choose Midpoints - */ - for(ji=kf; ji<=kl; ji++) - { - c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); - } - - /* - * If no more intervals to refine, quit. - */ - if( kf>kl ) - { - break; - } - } - - /* - * Converged - */ - *info = ae_maxint(kl+1-kf, 0, _state); - *mout = kl; -} - - -/************************************************************************* -Internal subroutine - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - June 30, 1999 -*************************************************************************/ -static void evd_internaltrevc(/* Real */ ae_matrix* t, - ae_int_t n, - ae_int_t side, - ae_int_t howmny, - /* Boolean */ ae_vector* vselect, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_int_t* m, - ae_int_t* info, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _vselect; - ae_bool allv; - ae_bool bothv; - ae_bool leftv; - ae_bool over; - ae_bool pair; - ae_bool rightv; - ae_bool somev; - ae_int_t i; - ae_int_t ierr; - ae_int_t ii; - ae_int_t ip; - ae_int_t iis; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - ae_int_t jnxt; - ae_int_t k; - ae_int_t ki; - ae_int_t n2; - double beta; - double bignum; - double emax; - double rec; - double remax; - double scl; - double smin; - double smlnum; - double ulp; - double unfl; - double vcrit; - double vmax; - double wi; - double wr; - double xnorm; - ae_matrix x; - ae_vector work; - ae_vector temp; - ae_matrix temp11; - ae_matrix temp22; - ae_matrix temp11b; - ae_matrix temp21b; - ae_matrix temp12b; - ae_matrix temp22b; - ae_bool skipflag; - ae_int_t k1; - ae_int_t k2; - ae_int_t k3; - ae_int_t k4; - double vt; - ae_vector rswap4; - ae_vector zswap4; - ae_matrix ipivot44; - ae_vector civ4; - ae_vector crv4; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_vselect, vselect, _state, ae_true); - vselect = &_vselect; - *m = 0; - *info = 0; - ae_matrix_init(&x, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - ae_vector_init(&temp, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp11, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp22, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp11b, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp21b, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp12b, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&temp22b, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&rswap4, 0, DT_BOOL, _state, ae_true); - ae_vector_init(&zswap4, 0, DT_BOOL, _state, ae_true); - ae_matrix_init(&ipivot44, 0, 0, DT_INT, _state, ae_true); - ae_vector_init(&civ4, 0, DT_REAL, _state, ae_true); - ae_vector_init(&crv4, 0, DT_REAL, _state, ae_true); - - ae_matrix_set_length(&x, 2+1, 2+1, _state); - ae_matrix_set_length(&temp11, 1+1, 1+1, _state); - ae_matrix_set_length(&temp11b, 1+1, 1+1, _state); - ae_matrix_set_length(&temp21b, 2+1, 1+1, _state); - ae_matrix_set_length(&temp12b, 1+1, 2+1, _state); - ae_matrix_set_length(&temp22b, 2+1, 2+1, _state); - ae_matrix_set_length(&temp22, 2+1, 2+1, _state); - ae_vector_set_length(&work, 3*n+1, _state); - ae_vector_set_length(&temp, n+1, _state); - ae_vector_set_length(&rswap4, 4+1, _state); - ae_vector_set_length(&zswap4, 4+1, _state); - ae_matrix_set_length(&ipivot44, 4+1, 4+1, _state); - ae_vector_set_length(&civ4, 4+1, _state); - ae_vector_set_length(&crv4, 4+1, _state); - if( howmny!=1 ) - { - if( side==1||side==3 ) - { - ae_matrix_set_length(vr, n+1, n+1, _state); - } - if( side==2||side==3 ) - { - ae_matrix_set_length(vl, n+1, n+1, _state); - } - } - - /* - * Decode and test the input parameters - */ - bothv = side==3; - rightv = side==1||bothv; - leftv = side==2||bothv; - allv = howmny==2; - over = howmny==1; - somev = howmny==3; - *info = 0; - if( n<0 ) - { - *info = -2; - ae_frame_leave(_state); - return; - } - if( !rightv&&!leftv ) - { - *info = -3; - ae_frame_leave(_state); - return; - } - if( (!allv&&!over)&&!somev ) - { - *info = -4; - ae_frame_leave(_state); - return; - } - - /* - * Set M to the number of columns required to store the selected - * eigenvectors, standardize the array SELECT if necessary, and - * test MM. - */ - if( somev ) - { - *m = 0; - pair = ae_false; - for(j=1; j<=n; j++) - { - if( pair ) - { - pair = ae_false; - vselect->ptr.p_bool[j] = ae_false; - } - else - { - if( jptr.pp_double[j+1][j],0) ) - { - if( vselect->ptr.p_bool[j] ) - { - *m = *m+1; - } - } - else - { - pair = ae_true; - if( vselect->ptr.p_bool[j]||vselect->ptr.p_bool[j+1] ) - { - vselect->ptr.p_bool[j] = ae_true; - *m = *m+2; - } - } - } - else - { - if( vselect->ptr.p_bool[n] ) - { - *m = *m+1; - } - } - } - } - } - else - { - *m = n; - } - - /* - * Quick return if possible. - */ - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Set the constants to control overflow. - */ - unfl = ae_minrealnumber; - ulp = ae_machineepsilon; - smlnum = unfl*(n/ulp); - bignum = (1-ulp)/smlnum; - - /* - * Compute 1-norm of each column of strictly upper triangular - * part of T to control overflow in triangular solver. - */ - work.ptr.p_double[1] = 0; - for(j=2; j<=n; j++) - { - work.ptr.p_double[j] = 0; - for(i=1; i<=j-1; i++) - { - work.ptr.p_double[j] = work.ptr.p_double[j]+ae_fabs(t->ptr.pp_double[i][j], _state); - } - } - - /* - * Index IP is used to specify the real or complex eigenvalue: - * IP = 0, real eigenvalue, - * 1, first of conjugate complex pair: (wr,wi) - * -1, second of conjugate complex pair: (wr,wi) - */ - n2 = 2*n; - if( rightv ) - { - - /* - * Compute right eigenvectors. - */ - ip = 0; - iis = *m; - for(ki=n; ki>=1; ki--) - { - skipflag = ae_false; - if( ip==1 ) - { - skipflag = ae_true; - } - else - { - if( ki!=1 ) - { - if( ae_fp_neq(t->ptr.pp_double[ki][ki-1],0) ) - { - ip = -1; - } - } - if( somev ) - { - if( ip==0 ) - { - if( !vselect->ptr.p_bool[ki] ) - { - skipflag = ae_true; - } - } - else - { - if( !vselect->ptr.p_bool[ki-1] ) - { - skipflag = ae_true; - } - } - } - } - if( !skipflag ) - { - - /* - * Compute the KI-th eigenvalue (WR,WI). - */ - wr = t->ptr.pp_double[ki][ki]; - wi = 0; - if( ip!=0 ) - { - wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki-1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki-1][ki], _state), _state); - } - smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); - if( ip==0 ) - { - - /* - * Real right eigenvector - */ - work.ptr.p_double[ki+n] = 1; - - /* - * Form right-hand side - */ - for(k=1; k<=ki-1; k++) - { - work.ptr.p_double[k+n] = -t->ptr.pp_double[k][ki]; - } - - /* - * Solve the upper quasi-triangular system: - * (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. - */ - jnxt = ki-1; - for(j=ki-1; j>=1; j--) - { - if( j>jnxt ) - { - continue; - } - j1 = j; - j2 = j; - jnxt = j-1; - if( j>1 ) - { - if( ae_fp_neq(t->ptr.pp_double[j][j-1],0) ) - { - j1 = j-1; - jnxt = j-2; - } - } - if( j1==j2 ) - { - - /* - * 1-by-1 diagonal block - */ - temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - evd_internalhsevdlaln2(ae_false, 1, 1, smin, 1, &temp11, 1.0, 1.0, &temp11b, wr, 0.0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale X(1,1) to avoid overflow when updating - * the right-hand side. - */ - if( ae_fp_greater(xnorm,1) ) - { - if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) - { - x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; - scl = scl/xnorm; - } - } - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - k1 = n+1; - k2 = n+ki; - ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - - /* - * Update right-hand side - */ - k1 = 1+n; - k2 = j-1+n; - k3 = j-1; - vt = -x.ptr.pp_double[1][1]; - ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); - } - else - { - - /* - * 2-by-2 diagonal block - */ - temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; - temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; - temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; - temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; - temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; - temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; - evd_internalhsevdlaln2(ae_false, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, 0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale X(1,1) and X(2,1) to avoid overflow when - * updating the right-hand side. - */ - if( ae_fp_greater(xnorm,1) ) - { - beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); - if( ae_fp_greater(beta,bignum/xnorm) ) - { - x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; - x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]/xnorm; - scl = scl/xnorm; - } - } - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - k1 = 1+n; - k2 = ki+n; - ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); - } - work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; - - /* - * Update right-hand side - */ - k1 = 1+n; - k2 = j-2+n; - k3 = j-2; - k4 = j-1; - vt = -x.ptr.pp_double[1][1]; - ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][k4], t->stride, ae_v_len(k1,k2), vt); - vt = -x.ptr.pp_double[2][1]; - ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); - } - } - - /* - * Copy the vector x or Q*x to VR and normalize. - */ - if( !over ) - { - k1 = 1+n; - k2 = ki+n; - ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[k1], 1, ae_v_len(1,ki)); - ii = columnidxabsmax(vr, 1, ki, iis, _state); - remax = 1/ae_fabs(vr->ptr.pp_double[ii][iis], _state); - ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); - for(k=ki+1; k<=n; k++) - { - vr->ptr.pp_double[k][iis] = 0; - } - } - else - { - if( ki>1 ) - { - ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); - matrixvectormultiply(vr, 1, n, 1, ki-1, ae_false, &work, 1+n, ki-1+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); - ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - } - ii = columnidxabsmax(vr, 1, n, ki, _state); - remax = 1/ae_fabs(vr->ptr.pp_double[ii][ki], _state); - ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); - } - } - else - { - - /* - * Complex right eigenvector. - * - * Initial solve - * [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. - * [ (T(KI,KI-1) T(KI,KI) ) ] - */ - if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki-1][ki], _state),ae_fabs(t->ptr.pp_double[ki][ki-1], _state)) ) - { - work.ptr.p_double[ki-1+n] = 1; - work.ptr.p_double[ki+n2] = wi/t->ptr.pp_double[ki-1][ki]; - } - else - { - work.ptr.p_double[ki-1+n] = -wi/t->ptr.pp_double[ki][ki-1]; - work.ptr.p_double[ki+n2] = 1; - } - work.ptr.p_double[ki+n] = 0; - work.ptr.p_double[ki-1+n2] = 0; - - /* - * Form right-hand side - */ - for(k=1; k<=ki-2; k++) - { - work.ptr.p_double[k+n] = -work.ptr.p_double[ki-1+n]*t->ptr.pp_double[k][ki-1]; - work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+n2]*t->ptr.pp_double[k][ki]; - } - - /* - * Solve upper quasi-triangular system: - * (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) - */ - jnxt = ki-2; - for(j=ki-2; j>=1; j--) - { - if( j>jnxt ) - { - continue; - } - j1 = j; - j2 = j; - jnxt = j-1; - if( j>1 ) - { - if( ae_fp_neq(t->ptr.pp_double[j][j-1],0) ) - { - j1 = j-1; - jnxt = j-2; - } - } - if( j1==j2 ) - { - - /* - * 1-by-1 diagonal block - */ - temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; - evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale X(1,1) and X(1,2) to avoid overflow when - * updating the right-hand side. - */ - if( ae_fp_greater(xnorm,1) ) - { - if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) - { - x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; - x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]/xnorm; - scl = scl/xnorm; - } - } - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - k1 = 1+n; - k2 = ki+n; - ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); - k1 = 1+n2; - k2 = ki+n2; - ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; - - /* - * Update the right-hand side - */ - k1 = 1+n; - k2 = j-1+n; - k3 = 1; - k4 = j-1; - vt = -x.ptr.pp_double[1][1]; - ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); - k1 = 1+n2; - k2 = j-1+n2; - k3 = 1; - k4 = j-1; - vt = -x.ptr.pp_double[1][2]; - ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); - } - else - { - - /* - * 2-by-2 diagonal block - */ - temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; - temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; - temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; - temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; - temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; - temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j-1+n+n]; - temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; - temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+n+n]; - evd_internalhsevdlaln2(ae_false, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale X to avoid overflow when updating - * the right-hand side. - */ - if( ae_fp_greater(xnorm,1) ) - { - beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); - if( ae_fp_greater(beta,bignum/xnorm) ) - { - rec = 1/xnorm; - x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]*rec; - x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]*rec; - x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]*rec; - x.ptr.pp_double[2][2] = x.ptr.pp_double[2][2]*rec; - scl = scl*rec; - } - } - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - ae_v_muld(&work.ptr.p_double[1+n], 1, ae_v_len(1+n,ki+n), scl); - ae_v_muld(&work.ptr.p_double[1+n2], 1, ae_v_len(1+n2,ki+n2), scl); - } - work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; - work.ptr.p_double[j-1+n2] = x.ptr.pp_double[1][2]; - work.ptr.p_double[j+n2] = x.ptr.pp_double[2][2]; - - /* - * Update the right-hand side - */ - vt = -x.ptr.pp_double[1][1]; - ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n+1,n+j-2), vt); - vt = -x.ptr.pp_double[2][1]; - ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n+1,n+j-2), vt); - vt = -x.ptr.pp_double[1][2]; - ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n2+1,n2+j-2), vt); - vt = -x.ptr.pp_double[2][2]; - ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n2+1,n2+j-2), vt); - } - } - - /* - * Copy the vector x or Q*x to VR and normalize. - */ - if( !over ) - { - ae_v_move(&vr->ptr.pp_double[1][iis-1], vr->stride, &work.ptr.p_double[n+1], 1, ae_v_len(1,ki)); - ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[n2+1], 1, ae_v_len(1,ki)); - emax = 0; - for(k=1; k<=ki; k++) - { - emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][iis-1], _state)+ae_fabs(vr->ptr.pp_double[k][iis], _state), _state); - } - remax = 1/emax; - ae_v_muld(&vr->ptr.pp_double[1][iis-1], vr->stride, ae_v_len(1,ki), remax); - ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); - for(k=ki+1; k<=n; k++) - { - vr->ptr.pp_double[k][iis-1] = 0; - vr->ptr.pp_double[k][iis] = 0; - } - } - else - { - if( ki>2 ) - { - ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n)); - matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n, ki-2+n, 1.0, &temp, 1, n, work.ptr.p_double[ki-1+n], _state); - ae_v_move(&vr->ptr.pp_double[1][ki-1], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); - matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n2, ki-2+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+n2], _state); - ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - } - else - { - vt = work.ptr.p_double[ki-1+n]; - ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), vt); - vt = work.ptr.p_double[ki+n2]; - ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), vt); - } - emax = 0; - for(k=1; k<=n; k++) - { - emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][ki-1], _state)+ae_fabs(vr->ptr.pp_double[k][ki], _state), _state); - } - remax = 1/emax; - ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), remax); - ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); - } - } - iis = iis-1; - if( ip!=0 ) - { - iis = iis-1; - } - } - if( ip==1 ) - { - ip = 0; - } - if( ip==-1 ) - { - ip = 1; - } - } - } - if( leftv ) - { - - /* - * Compute left eigenvectors. - */ - ip = 0; - iis = 1; - for(ki=1; ki<=n; ki++) - { - skipflag = ae_false; - if( ip==-1 ) - { - skipflag = ae_true; - } - else - { - if( ki!=n ) - { - if( ae_fp_neq(t->ptr.pp_double[ki+1][ki],0) ) - { - ip = 1; - } - } - if( somev ) - { - if( !vselect->ptr.p_bool[ki] ) - { - skipflag = ae_true; - } - } - } - if( !skipflag ) - { - - /* - * Compute the KI-th eigenvalue (WR,WI). - */ - wr = t->ptr.pp_double[ki][ki]; - wi = 0; - if( ip!=0 ) - { - wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki+1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki+1][ki], _state), _state); - } - smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); - if( ip==0 ) - { - - /* - * Real left eigenvector. - */ - work.ptr.p_double[ki+n] = 1; - - /* - * Form right-hand side - */ - for(k=ki+1; k<=n; k++) - { - work.ptr.p_double[k+n] = -t->ptr.pp_double[ki][k]; - } - - /* - * Solve the quasi-triangular system: - * (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK - */ - vmax = 1; - vcrit = bignum; - jnxt = ki+1; - for(j=ki+1; j<=n; j++) - { - if( jptr.pp_double[j+1][j],0) ) - { - j2 = j+1; - jnxt = j+2; - } - } - if( j1==j2 ) - { - - /* - * 1-by-1 diagonal block - * - * Scale if necessary to avoid overflow when forming - * the right-hand side. - */ - if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) - { - rec = 1/vmax; - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); - vmax = 1; - vcrit = bignum; - } - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); - work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; - - /* - * Solve (T(J,J)-WR)'*X = WORK - */ - temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - evd_internalhsevdlaln2(ae_false, 1, 1, smin, 1.0, &temp11, 1.0, 1.0, &temp11b, wr, 0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), vmax, _state); - vcrit = bignum/vmax; - } - else - { - - /* - * 2-by-2 diagonal block - * - * Scale if necessary to avoid overflow when forming - * the right-hand side. - */ - beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); - if( ae_fp_greater(beta,vcrit) ) - { - rec = 1/vmax; - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); - vmax = 1; - vcrit = bignum; - } - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); - work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j+1], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); - work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; - - /* - * Solve - * [T(J,J)-WR T(J,J+1) ]'* X = SCALE*( WORK1 ) - * [T(J+1,J) T(J+1,J+1)-WR] ( WORK2 ) - */ - temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; - temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; - temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; - temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; - evd_internalhsevdlaln2(ae_true, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, 0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; - vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+1+n], _state), vmax, _state), _state); - vcrit = bignum/vmax; - } - } - - /* - * Copy the vector x or Q*x to VL and normalize. - */ - if( !over ) - { - ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); - ii = columnidxabsmax(vl, ki, n, iis, _state); - remax = 1/ae_fabs(vl->ptr.pp_double[ii][iis], _state); - ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); - for(k=1; k<=ki-1; k++) - { - vl->ptr.pp_double[k][iis] = 0; - } - } - else - { - if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); - matrixvectormultiply(vl, 1, n, ki+1, n, ae_false, &work, ki+1+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); - ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - } - ii = columnidxabsmax(vl, 1, n, ki, _state); - remax = 1/ae_fabs(vl->ptr.pp_double[ii][ki], _state); - ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); - } - } - else - { - - /* - * Complex left eigenvector. - * - * Initial solve: - * ((T(KI,KI) T(KI,KI+1) )' - (WR - I* WI))*X = 0. - * ((T(KI+1,KI) T(KI+1,KI+1)) ) - */ - if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki][ki+1], _state),ae_fabs(t->ptr.pp_double[ki+1][ki], _state)) ) - { - work.ptr.p_double[ki+n] = wi/t->ptr.pp_double[ki][ki+1]; - work.ptr.p_double[ki+1+n2] = 1; - } - else - { - work.ptr.p_double[ki+n] = 1; - work.ptr.p_double[ki+1+n2] = -wi/t->ptr.pp_double[ki+1][ki]; - } - work.ptr.p_double[ki+1+n] = 0; - work.ptr.p_double[ki+n2] = 0; - - /* - * Form right-hand side - */ - for(k=ki+2; k<=n; k++) - { - work.ptr.p_double[k+n] = -work.ptr.p_double[ki+n]*t->ptr.pp_double[ki][k]; - work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+1+n2]*t->ptr.pp_double[ki+1][k]; - } - - /* - * Solve complex quasi-triangular system: - * ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 - */ - vmax = 1; - vcrit = bignum; - jnxt = ki+2; - for(j=ki+2; j<=n; j++) - { - if( jptr.pp_double[j+1][j],0) ) - { - j2 = j+1; - jnxt = j+2; - } - } - if( j1==j2 ) - { - - /* - * 1-by-1 diagonal block - * - * Scale if necessary to avoid overflow when - * forming the right-hand side elements. - */ - if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) - { - rec = 1/vmax; - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); - ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); - vmax = 1; - vcrit = bignum; - } - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; - - /* - * Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 - */ - temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; - evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); - ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; - vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+n2], _state), vmax, _state), _state); - vcrit = bignum/vmax; - } - else - { - - /* - * 2-by-2 diagonal block - * - * Scale if necessary to avoid overflow when forming - * the right-hand side elements. - */ - beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); - if( ae_fp_greater(beta,vcrit) ) - { - rec = 1/vmax; - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); - ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); - vmax = 1; - vcrit = bignum; - } - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; - vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); - work.ptr.p_double[j+1+n2] = work.ptr.p_double[j+1+n2]-vt; - - /* - * Solve 2-by-2 complex linear equation - * ([T(j,j) T(j,j+1) ]'-(wr-i*wi)*I)*X = SCALE*B - * ([T(j+1,j) T(j+1,j+1)] ) - */ - temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; - temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; - temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; - temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; - temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; - temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; - temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; - temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+1+n+n]; - evd_internalhsevdlaln2(ae_true, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); - - /* - * Scale if necessary - */ - if( ae_fp_neq(scl,1) ) - { - ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); - ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); - } - work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; - work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; - work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; - work.ptr.p_double[j+1+n2] = x.ptr.pp_double[2][2]; - vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][1], _state), vmax, _state); - vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][2], _state), vmax, _state); - vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][1], _state), vmax, _state); - vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][2], _state), vmax, _state); - vcrit = bignum/vmax; - } - } - - /* - * Copy the vector x or Q*x to VL and normalize. - */ - if( !over ) - { - ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); - ae_v_move(&vl->ptr.pp_double[ki][iis+1], vl->stride, &work.ptr.p_double[ki+n2], 1, ae_v_len(ki,n)); - emax = 0; - for(k=ki; k<=n; k++) - { - emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][iis], _state)+ae_fabs(vl->ptr.pp_double[k][iis+1], _state), _state); - } - remax = 1/emax; - ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); - ae_v_muld(&vl->ptr.pp_double[ki][iis+1], vl->stride, ae_v_len(ki,n), remax); - for(k=1; k<=ki-1; k++) - { - vl->ptr.pp_double[k][iis] = 0; - vl->ptr.pp_double[k][iis+1] = 0; - } - } - else - { - if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); - matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); - ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - ae_v_move(&temp.ptr.p_double[1], 1, &vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n)); - matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n2, n+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+1+n2], _state); - ae_v_move(&vl->ptr.pp_double[1][ki+1], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); - } - else - { - vt = work.ptr.p_double[ki+n]; - ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), vt); - vt = work.ptr.p_double[ki+1+n2]; - ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), vt); - } - emax = 0; - for(k=1; k<=n; k++) - { - emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][ki], _state)+ae_fabs(vl->ptr.pp_double[k][ki+1], _state), _state); - } - remax = 1/emax; - ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); - ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), remax); - } - } - iis = iis+1; - if( ip!=0 ) - { - iis = iis+1; - } - } - if( ip==-1 ) - { - ip = 0; - } - if( ip==1 ) - { - ip = -1; - } - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -DLALN2 solves a system of the form (ca A - w D ) X = s B -or (ca A' - w D) X = s B with possible scaling ("s") and -perturbation of A. (A' means A-transpose.) - -A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA -real diagonal matrix, w is a real or complex value, and X and B are -NA x 1 matrices -- real if w is real, complex if w is complex. NA -may be 1 or 2. - -If w is complex, X and B are represented as NA x 2 matrices, -the first column of each being the real part and the second -being the imaginary part. - -"s" is a scaling factor (.LE. 1), computed by DLALN2, which is -so chosen that X can be computed without overflow. X is further -scaled if necessary to assure that norm(ca A - w D)*norm(X) is less -than overflow. - -If both singular values of (ca A - w D) are less than SMIN, -SMIN*identity will be used instead of (ca A - w D). If only one -singular value is less than SMIN, one element of (ca A - w D) will be -perturbed enough to make the smallest singular value roughly SMIN. -If both singular values are at least SMIN, (ca A - w D) will not be -perturbed. In any case, the perturbation will be at most some small -multiple of max( SMIN, ulp*norm(ca A - w D) ). The singular values -are computed by infinity-norm approximations, and thus will only be -correct to a factor of 2 or so. - -Note: all input quantities are assumed to be smaller than overflow -by a reasonable factor. (See BIGNUM.) - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -static void evd_internalhsevdlaln2(ae_bool ltrans, - ae_int_t na, - ae_int_t nw, - double smin, - double ca, - /* Real */ ae_matrix* a, - double d1, - double d2, - /* Real */ ae_matrix* b, - double wr, - double wi, - /* Boolean */ ae_vector* rswap4, - /* Boolean */ ae_vector* zswap4, - /* Integer */ ae_matrix* ipivot44, - /* Real */ ae_vector* civ4, - /* Real */ ae_vector* crv4, - /* Real */ ae_matrix* x, - double* scl, - double* xnorm, - ae_int_t* info, - ae_state *_state) -{ - ae_int_t icmax; - ae_int_t j; - double bbnd; - double bi1; - double bi2; - double bignum; - double bnorm; - double br1; - double br2; - double ci21; - double ci22; - double cmax; - double cnorm; - double cr21; - double cr22; - double csi; - double csr; - double li21; - double lr21; - double smini; - double smlnum; - double temp; - double u22abs; - double ui11; - double ui11r; - double ui12; - double ui12s; - double ui22; - double ur11; - double ur11r; - double ur12; - double ur12s; - double ur22; - double xi1; - double xi2; - double xr1; - double xr2; - double tmp1; - double tmp2; - - *scl = 0; - *xnorm = 0; - *info = 0; - - zswap4->ptr.p_bool[1] = ae_false; - zswap4->ptr.p_bool[2] = ae_false; - zswap4->ptr.p_bool[3] = ae_true; - zswap4->ptr.p_bool[4] = ae_true; - rswap4->ptr.p_bool[1] = ae_false; - rswap4->ptr.p_bool[2] = ae_true; - rswap4->ptr.p_bool[3] = ae_false; - rswap4->ptr.p_bool[4] = ae_true; - ipivot44->ptr.pp_int[1][1] = 1; - ipivot44->ptr.pp_int[2][1] = 2; - ipivot44->ptr.pp_int[3][1] = 3; - ipivot44->ptr.pp_int[4][1] = 4; - ipivot44->ptr.pp_int[1][2] = 2; - ipivot44->ptr.pp_int[2][2] = 1; - ipivot44->ptr.pp_int[3][2] = 4; - ipivot44->ptr.pp_int[4][2] = 3; - ipivot44->ptr.pp_int[1][3] = 3; - ipivot44->ptr.pp_int[2][3] = 4; - ipivot44->ptr.pp_int[3][3] = 1; - ipivot44->ptr.pp_int[4][3] = 2; - ipivot44->ptr.pp_int[1][4] = 4; - ipivot44->ptr.pp_int[2][4] = 3; - ipivot44->ptr.pp_int[3][4] = 2; - ipivot44->ptr.pp_int[4][4] = 1; - smlnum = 2*ae_minrealnumber; - bignum = 1/smlnum; - smini = ae_maxreal(smin, smlnum, _state); - - /* - * Don't check for input errors - */ - *info = 0; - - /* - * Standard Initializations - */ - *scl = 1; - if( na==1 ) - { - - /* - * 1 x 1 (i.e., scalar) system C X = B - */ - if( nw==1 ) - { - - /* - * Real 1x1 system. - * - * C = ca A - w D - */ - csr = ca*a->ptr.pp_double[1][1]-wr*d1; - cnorm = ae_fabs(csr, _state); - - /* - * If | C | < SMINI, use C = SMINI - */ - if( ae_fp_less(cnorm,smini) ) - { - csr = smini; - cnorm = smini; - *info = 1; - } - - /* - * Check scaling for X = B / C - */ - bnorm = ae_fabs(b->ptr.pp_double[1][1], _state); - if( ae_fp_less(cnorm,1)&&ae_fp_greater(bnorm,1) ) - { - if( ae_fp_greater(bnorm,bignum*cnorm) ) - { - *scl = 1/bnorm; - } - } - - /* - * Compute X - */ - x->ptr.pp_double[1][1] = b->ptr.pp_double[1][1]*(*scl)/csr; - *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state); - } - else - { - - /* - * Complex 1x1 system (w is complex) - * - * C = ca A - w D - */ - csr = ca*a->ptr.pp_double[1][1]-wr*d1; - csi = -wi*d1; - cnorm = ae_fabs(csr, _state)+ae_fabs(csi, _state); - - /* - * If | C | < SMINI, use C = SMINI - */ - if( ae_fp_less(cnorm,smini) ) - { - csr = smini; - csi = 0; - cnorm = smini; - *info = 1; - } - - /* - * Check scaling for X = B / C - */ - bnorm = ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state); - if( ae_fp_less(cnorm,1)&&ae_fp_greater(bnorm,1) ) - { - if( ae_fp_greater(bnorm,bignum*cnorm) ) - { - *scl = 1/bnorm; - } - } - - /* - * Compute X - */ - evd_internalhsevdladiv(*scl*b->ptr.pp_double[1][1], *scl*b->ptr.pp_double[1][2], csr, csi, &tmp1, &tmp2, _state); - x->ptr.pp_double[1][1] = tmp1; - x->ptr.pp_double[1][2] = tmp2; - *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state)+ae_fabs(x->ptr.pp_double[1][2], _state); - } - } - else - { - - /* - * 2x2 System - * - * Compute the real part of C = ca A - w D (or ca A' - w D ) - */ - crv4->ptr.p_double[1+0] = ca*a->ptr.pp_double[1][1]-wr*d1; - crv4->ptr.p_double[2+2] = ca*a->ptr.pp_double[2][2]-wr*d2; - if( ltrans ) - { - crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[2][1]; - crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[1][2]; - } - else - { - crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[2][1]; - crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[1][2]; - } - if( nw==1 ) - { - - /* - * Real 2x2 system (w is real) - * - * Find the largest element in C - */ - cmax = 0; - icmax = 0; - for(j=1; j<=4; j++) - { - if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state),cmax) ) - { - cmax = ae_fabs(crv4->ptr.p_double[j], _state); - icmax = j; - } - } - - /* - * If norm(C) < SMINI, use SMINI*identity. - */ - if( ae_fp_less(cmax,smini) ) - { - bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state), ae_fabs(b->ptr.pp_double[2][1], _state), _state); - if( ae_fp_less(smini,1)&&ae_fp_greater(bnorm,1) ) - { - if( ae_fp_greater(bnorm,bignum*smini) ) - { - *scl = 1/bnorm; - } - } - temp = *scl/smini; - x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; - x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; - *xnorm = temp*bnorm; - *info = 1; - return; - } - - /* - * Gaussian elimination with complete pivoting. - */ - ur11 = crv4->ptr.p_double[icmax]; - cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; - ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; - cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; - ur11r = 1/ur11; - lr21 = ur11r*cr21; - ur22 = cr22-ur12*lr21; - - /* - * If smaller pivot < SMINI, use SMINI - */ - if( ae_fp_less(ae_fabs(ur22, _state),smini) ) - { - ur22 = smini; - *info = 1; - } - if( rswap4->ptr.p_bool[icmax] ) - { - br1 = b->ptr.pp_double[2][1]; - br2 = b->ptr.pp_double[1][1]; - } - else - { - br1 = b->ptr.pp_double[1][1]; - br2 = b->ptr.pp_double[2][1]; - } - br2 = br2-lr21*br1; - bbnd = ae_maxreal(ae_fabs(br1*(ur22*ur11r), _state), ae_fabs(br2, _state), _state); - if( ae_fp_greater(bbnd,1)&&ae_fp_less(ae_fabs(ur22, _state),1) ) - { - if( ae_fp_greater_eq(bbnd,bignum*ae_fabs(ur22, _state)) ) - { - *scl = 1/bbnd; - } - } - xr2 = br2*(*scl)/ur22; - xr1 = *scl*br1*ur11r-xr2*(ur11r*ur12); - if( zswap4->ptr.p_bool[icmax] ) - { - x->ptr.pp_double[1][1] = xr2; - x->ptr.pp_double[2][1] = xr1; - } - else - { - x->ptr.pp_double[1][1] = xr1; - x->ptr.pp_double[2][1] = xr2; - } - *xnorm = ae_maxreal(ae_fabs(xr1, _state), ae_fabs(xr2, _state), _state); - - /* - * Further scaling if norm(A) norm(X) > overflow - */ - if( ae_fp_greater(*xnorm,1)&&ae_fp_greater(cmax,1) ) - { - if( ae_fp_greater(*xnorm,bignum/cmax) ) - { - temp = cmax/bignum; - x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; - x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; - *xnorm = temp*(*xnorm); - *scl = temp*(*scl); - } - } - } - else - { - - /* - * Complex 2x2 system (w is complex) - * - * Find the largest element in C - */ - civ4->ptr.p_double[1+0] = -wi*d1; - civ4->ptr.p_double[2+0] = 0; - civ4->ptr.p_double[1+2] = 0; - civ4->ptr.p_double[2+2] = -wi*d2; - cmax = 0; - icmax = 0; - for(j=1; j<=4; j++) - { - if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state),cmax) ) - { - cmax = ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state); - icmax = j; - } - } - - /* - * If norm(C) < SMINI, use SMINI*identity. - */ - if( ae_fp_less(cmax,smini) ) - { - bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state), ae_fabs(b->ptr.pp_double[2][1], _state)+ae_fabs(b->ptr.pp_double[2][2], _state), _state); - if( ae_fp_less(smini,1)&&ae_fp_greater(bnorm,1) ) - { - if( ae_fp_greater(bnorm,bignum*smini) ) - { - *scl = 1/bnorm; - } - } - temp = *scl/smini; - x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; - x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; - x->ptr.pp_double[1][2] = temp*b->ptr.pp_double[1][2]; - x->ptr.pp_double[2][2] = temp*b->ptr.pp_double[2][2]; - *xnorm = temp*bnorm; - *info = 1; - return; - } - - /* - * Gaussian elimination with complete pivoting. - */ - ur11 = crv4->ptr.p_double[icmax]; - ui11 = civ4->ptr.p_double[icmax]; - cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; - ci21 = civ4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; - ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; - ui12 = civ4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; - cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; - ci22 = civ4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; - if( icmax==1||icmax==4 ) - { - - /* - * Code when off-diagonals of pivoted C are real - */ - if( ae_fp_greater(ae_fabs(ur11, _state),ae_fabs(ui11, _state)) ) - { - temp = ui11/ur11; - ur11r = 1/(ur11*(1+ae_sqr(temp, _state))); - ui11r = -temp*ur11r; - } - else - { - temp = ur11/ui11; - ui11r = -1/(ui11*(1+ae_sqr(temp, _state))); - ur11r = -temp*ui11r; - } - lr21 = cr21*ur11r; - li21 = cr21*ui11r; - ur12s = ur12*ur11r; - ui12s = ur12*ui11r; - ur22 = cr22-ur12*lr21; - ui22 = ci22-ur12*li21; - } - else - { - - /* - * Code when diagonals of pivoted C are real - */ - ur11r = 1/ur11; - ui11r = 0; - lr21 = cr21*ur11r; - li21 = ci21*ur11r; - ur12s = ur12*ur11r; - ui12s = ui12*ur11r; - ur22 = cr22-ur12*lr21+ui12*li21; - ui22 = -ur12*li21-ui12*lr21; - } - u22abs = ae_fabs(ur22, _state)+ae_fabs(ui22, _state); - - /* - * If smaller pivot < SMINI, use SMINI - */ - if( ae_fp_less(u22abs,smini) ) - { - ur22 = smini; - ui22 = 0; - *info = 1; - } - if( rswap4->ptr.p_bool[icmax] ) - { - br2 = b->ptr.pp_double[1][1]; - br1 = b->ptr.pp_double[2][1]; - bi2 = b->ptr.pp_double[1][2]; - bi1 = b->ptr.pp_double[2][2]; - } - else - { - br1 = b->ptr.pp_double[1][1]; - br2 = b->ptr.pp_double[2][1]; - bi1 = b->ptr.pp_double[1][2]; - bi2 = b->ptr.pp_double[2][2]; - } - br2 = br2-lr21*br1+li21*bi1; - bi2 = bi2-li21*br1-lr21*bi1; - bbnd = ae_maxreal((ae_fabs(br1, _state)+ae_fabs(bi1, _state))*(u22abs*(ae_fabs(ur11r, _state)+ae_fabs(ui11r, _state))), ae_fabs(br2, _state)+ae_fabs(bi2, _state), _state); - if( ae_fp_greater(bbnd,1)&&ae_fp_less(u22abs,1) ) - { - if( ae_fp_greater_eq(bbnd,bignum*u22abs) ) - { - *scl = 1/bbnd; - br1 = *scl*br1; - bi1 = *scl*bi1; - br2 = *scl*br2; - bi2 = *scl*bi2; - } - } - evd_internalhsevdladiv(br2, bi2, ur22, ui22, &xr2, &xi2, _state); - xr1 = ur11r*br1-ui11r*bi1-ur12s*xr2+ui12s*xi2; - xi1 = ui11r*br1+ur11r*bi1-ui12s*xr2-ur12s*xi2; - if( zswap4->ptr.p_bool[icmax] ) - { - x->ptr.pp_double[1][1] = xr2; - x->ptr.pp_double[2][1] = xr1; - x->ptr.pp_double[1][2] = xi2; - x->ptr.pp_double[2][2] = xi1; - } - else - { - x->ptr.pp_double[1][1] = xr1; - x->ptr.pp_double[2][1] = xr2; - x->ptr.pp_double[1][2] = xi1; - x->ptr.pp_double[2][2] = xi2; - } - *xnorm = ae_maxreal(ae_fabs(xr1, _state)+ae_fabs(xi1, _state), ae_fabs(xr2, _state)+ae_fabs(xi2, _state), _state); - - /* - * Further scaling if norm(A) norm(X) > overflow - */ - if( ae_fp_greater(*xnorm,1)&&ae_fp_greater(cmax,1) ) - { - if( ae_fp_greater(*xnorm,bignum/cmax) ) - { - temp = cmax/bignum; - x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; - x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; - x->ptr.pp_double[1][2] = temp*x->ptr.pp_double[1][2]; - x->ptr.pp_double[2][2] = temp*x->ptr.pp_double[2][2]; - *xnorm = temp*(*xnorm); - *scl = temp*(*scl); - } - } - } - } -} - - -/************************************************************************* -performs complex division in real arithmetic - - a + i*b - p + i*q = --------- - c + i*d - -The algorithm is due to Robert L. Smith and can be found -in D. Knuth, The art of Computer Programming, Vol.2, p.195 - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -static void evd_internalhsevdladiv(double a, - double b, - double c, - double d, - double* p, - double* q, - ae_state *_state) -{ - double e; - double f; - - *p = 0; - *q = 0; - - if( ae_fp_less(ae_fabs(d, _state),ae_fabs(c, _state)) ) - { - e = d/c; - f = c+d*e; - *p = (a+b*e)/f; - *q = (b-a*e)/f; - } - else - { - e = c/d; - f = d+c*e; - *p = (b+a*e)/f; - *q = (-a+b*e)/f; - } -} - - -static ae_bool evd_nonsymmetricevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t vneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_matrix s; - ae_vector tau; - ae_vector sel; - ae_int_t i; - ae_int_t info; - ae_int_t m; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_clear(wr); - ae_vector_clear(wi); - ae_matrix_clear(vl); - ae_matrix_clear(vr); - ae_matrix_init(&s, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sel, 0, DT_BOOL, _state, ae_true); - - ae_assert(vneeded>=0&&vneeded<=3, "NonSymmetricEVD: incorrect VNeeded!", _state); - if( vneeded==0 ) - { - - /* - * Eigen values only - */ - evd_toupperhessenberg(a, n, &tau, _state); - internalschurdecomposition(a, n, 0, 0, wr, wi, &s, &info, _state); - result = info==0; - ae_frame_leave(_state); - return result; - } - - /* - * Eigen values and vectors - */ - evd_toupperhessenberg(a, n, &tau, _state); - evd_unpackqfromupperhessenberg(a, n, &tau, &s, _state); - internalschurdecomposition(a, n, 1, 1, wr, wi, &s, &info, _state); - result = info==0; - if( !result ) - { - ae_frame_leave(_state); - return result; - } - if( vneeded==1||vneeded==3 ) - { - ae_matrix_set_length(vr, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&vr->ptr.pp_double[i][1], 1, &s.ptr.pp_double[i][1], 1, ae_v_len(1,n)); - } - } - if( vneeded==2||vneeded==3 ) - { - ae_matrix_set_length(vl, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - ae_v_move(&vl->ptr.pp_double[i][1], 1, &s.ptr.pp_double[i][1], 1, ae_v_len(1,n)); - } - } - evd_internaltrevc(a, n, vneeded, 1, &sel, vl, vr, &m, &info, _state); - result = info==0; - ae_frame_leave(_state); - return result; -} - - -static void evd_toupperhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t ip1; - ae_int_t nmi; - double v; - ae_vector t; - ae_vector work; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(tau); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "ToUpperHessenberg: incorrect N!", _state); - - /* - * Quick return if possible - */ - if( n<=1 ) - { - ae_frame_leave(_state); - return; - } - ae_vector_set_length(tau, n-1+1, _state); - ae_vector_set_length(&t, n+1, _state); - ae_vector_set_length(&work, n+1, _state); - for(i=1; i<=n-1; i++) - { - - /* - * Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) - */ - ip1 = i+1; - nmi = n-i; - ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[ip1][i], a->stride, ae_v_len(1,nmi)); - generatereflection(&t, nmi, &v, _state); - ae_v_move(&a->ptr.pp_double[ip1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(ip1,n)); - tau->ptr.p_double[i] = v; - t.ptr.p_double[1] = 1; - - /* - * Apply H(i) to A(1:ihi,i+1:ihi) from the right - */ - applyreflectionfromtheright(a, v, &t, 1, n, i+1, n, &work, _state); - - /* - * Apply H(i) to A(i+1:ihi,i+1:n) from the left - */ - applyreflectionfromtheleft(a, v, &t, i+1, n, i+1, n, &work, _state); - } - ae_frame_leave(_state); -} - - -static void evd_unpackqfromupperhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector v; - ae_vector work; - ae_int_t ip1; - ae_int_t nmi; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(q); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - if( n==0 ) - { - ae_frame_leave(_state); - return; - } - - /* - * init - */ - ae_matrix_set_length(q, n+1, n+1, _state); - ae_vector_set_length(&v, n+1, _state); - ae_vector_set_length(&work, n+1, _state); - for(i=1; i<=n; i++) - { - for(j=1; j<=n; j++) - { - if( i==j ) - { - q->ptr.pp_double[i][j] = 1; - } - else - { - q->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * unpack Q - */ - for(i=1; i<=n-1; i++) - { - - /* - * Apply H(i) - */ - ip1 = i+1; - nmi = n-i; - ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[ip1][i], a->stride, ae_v_len(1,nmi)); - v.ptr.p_double[1] = 1; - applyreflectionfromtheright(q, tau->ptr.p_double[i], &v, 1, n, i+1, n, &work, _state); - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Generation of a random uniformly distributed (Haar) orthogonal matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonal(ae_int_t n, - /* Real */ ae_matrix* a, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(a); - - ae_assert(n>=1, "RMatrixRndOrthogonal: N<1!", _state); - ae_matrix_set_length(a, n, n, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - a->ptr.pp_double[i][j] = 1; - } - else - { - a->ptr.pp_double[i][j] = 0; - } - } - } - rmatrixrndorthogonalfromtheright(a, n, n, _state); -} - - -/************************************************************************* -Generation of random NxN matrix with given condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&rs, _state, ae_true); - - ae_assert(n>=1&&ae_fp_greater_eq(c,1), "RMatrixRndCond: N<1 or C<1!", _state); - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - - /* - * special case - */ - a->ptr.pp_double[0][0] = 2*ae_randominteger(2, _state)-1; - ae_frame_leave(_state); - return; - } - hqrndrandomize(&rs, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - a->ptr.pp_double[0][0] = ae_exp(l1, _state); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); - } - a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); - rmatrixrndorthogonalfromtheleft(a, n, n, _state); - rmatrixrndorthogonalfromtheright(a, n, n, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Generation of a random Haar distributed orthogonal complex matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonal(ae_int_t n, - /* Complex */ ae_matrix* a, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - ae_matrix_clear(a); - - ae_assert(n>=1, "CMatrixRndOrthogonal: N<1!", _state); - ae_matrix_set_length(a, n, n, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - if( i==j ) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(1); - } - else - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - cmatrixrndorthogonalfromtheright(a, n, n, _state); -} - - -/************************************************************************* -Generation of random NxN complex matrix with given condition number C and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate state; - ae_complex v; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&state, _state, ae_true); - - ae_assert(n>=1&&ae_fp_greater_eq(c,1), "CMatrixRndCond: N<1 or C<1!", _state); - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - - /* - * special case - */ - hqrndrandomize(&state, _state); - hqrndunit2(&state, &v.x, &v.y, _state); - a->ptr.pp_complex[0][0] = v; - ae_frame_leave(_state); - return; - } - hqrndrandomize(&state, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&state, _state)*(l2-l1)+l1, _state)); - } - a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); - cmatrixrndorthogonalfromtheleft(a, n, n, _state); - cmatrixrndorthogonalfromtheright(a, n, n, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Generation of random NxN symmetric matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&rs, _state, ae_true); - - ae_assert(n>=1&&ae_fp_greater_eq(c,1), "SMatrixRndCond: N<1 or C<1!", _state); - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - - /* - * special case - */ - a->ptr.pp_double[0][0] = 2*ae_randominteger(2, _state)-1; - ae_frame_leave(_state); - return; - } - - /* - * Prepare matrix - */ - hqrndrandomize(&rs, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - a->ptr.pp_double[0][0] = ae_exp(l1, _state); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_double[i][i] = (2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); - } - a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); - - /* - * Multiply - */ - smatrixrndmultiply(a, n, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Generation of random NxN symmetric positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random SPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&rs, _state, ae_true); - - - /* - * Special cases - */ - if( n<=0||ae_fp_less(c,1) ) - { - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - a->ptr.pp_double[0][0] = 1; - ae_frame_leave(_state); - return; - } - - /* - * Prepare matrix - */ - hqrndrandomize(&rs, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - a->ptr.pp_double[0][0] = ae_exp(l1, _state); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); - } - a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); - - /* - * Multiply - */ - smatrixrndmultiply(a, n, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Generation of random NxN Hermitian matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&rs, _state, ae_true); - - ae_assert(n>=1&&ae_fp_greater_eq(c,1), "HMatrixRndCond: N<1 or C<1!", _state); - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - - /* - * special case - */ - a->ptr.pp_complex[0][0] = ae_complex_from_d(2*ae_randominteger(2, _state)-1); - ae_frame_leave(_state); - return; - } - - /* - * Prepare matrix - */ - hqrndrandomize(&rs, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_complex[i][i] = ae_complex_from_d((2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); - } - a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); - - /* - * Multiply - */ - hmatrixrndmultiply(a, n, _state); - - /* - * post-process to ensure that matrix diagonal is real - */ - for(i=0; i<=n-1; i++) - { - a->ptr.pp_complex[i][i].y = 0; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Generation of random NxN Hermitian positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random HPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double l1; - double l2; - hqrndstate rs; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(a); - _hqrndstate_init(&rs, _state, ae_true); - - - /* - * Special cases - */ - if( n<=0||ae_fp_less(c,1) ) - { - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(a, n, n, _state); - if( n==1 ) - { - a->ptr.pp_complex[0][0] = ae_complex_from_d(1); - ae_frame_leave(_state); - return; - } - - /* - * Prepare matrix - */ - hqrndrandomize(&rs, _state); - l1 = 0; - l2 = ae_log(1/c, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); - for(i=1; i<=n-2; i++) - { - a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); - } - a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); - - /* - * Multiply - */ - hmatrixrndmultiply(a, n, _state); - - /* - * post-process to ensure that matrix diagonal is real - */ - for(i=0; i<=n-1; i++) - { - a->ptr.pp_complex[i][i].y = 0; - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - double tau; - double lambdav; - ae_int_t s; - ae_int_t i; - double u1; - double u2; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); - if( n==1 ) - { - - /* - * Special case - */ - tau = 2*ae_randominteger(2, _state)-1; - for(i=0; i<=m-1; i++) - { - a->ptr.pp_double[i][0] = a->ptr.pp_double[i][0]*tau; - } - ae_frame_leave(_state); - return; - } - - /* - * General case. - * First pass. - */ - ae_vector_set_length(&w, m, _state); - ae_vector_set_length(&v, n+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=n; s++) - { - - /* - * Prepare random normal v - */ - do - { - i = 1; - while(i<=s) - { - hqrndnormal2(&state, &u1, &u2, _state); - v.ptr.p_double[i] = u1; - if( i+1<=s ) - { - v.ptr.p_double[i+1] = u2; - } - i = i+2; - } - lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); - } - while(ae_fp_eq(lambdav,0)); - - /* - * Prepare and apply reflection - */ - generatereflection(&v, s, &tau, _state); - v.ptr.p_double[1] = 1; - applyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=n-1; i++) - { - tau = 2*hqrnduniformi(&state, 2, _state)-1; - ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,m-1), tau); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - double tau; - double lambdav; - ae_int_t s; - ae_int_t i; - ae_int_t j; - double u1; - double u2; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); - if( m==1 ) - { - - /* - * special case - */ - tau = 2*ae_randominteger(2, _state)-1; - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[0][j] = a->ptr.pp_double[0][j]*tau; - } - ae_frame_leave(_state); - return; - } - - /* - * General case. - * First pass. - */ - ae_vector_set_length(&w, n, _state); - ae_vector_set_length(&v, m+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=m; s++) - { - - /* - * Prepare random normal v - */ - do - { - i = 1; - while(i<=s) - { - hqrndnormal2(&state, &u1, &u2, _state); - v.ptr.p_double[i] = u1; - if( i+1<=s ) - { - v.ptr.p_double[i+1] = u2; - } - i = i+2; - } - lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); - } - while(ae_fp_eq(lambdav,0)); - - /* - * Prepare and apply reflection - */ - generatereflection(&v, s, &tau, _state); - v.ptr.p_double[1] = 1; - applyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=m-1; i++) - { - tau = 2*hqrnduniformi(&state, 2, _state)-1; - ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Multiplication of MxN complex matrix by NxN random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_complex lambdav; - ae_complex tau; - ae_int_t s; - ae_int_t i; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); - if( n==1 ) - { - - /* - * Special case - */ - hqrndrandomize(&state, _state); - hqrndunit2(&state, &tau.x, &tau.y, _state); - for(i=0; i<=m-1; i++) - { - a->ptr.pp_complex[i][0] = ae_c_mul(a->ptr.pp_complex[i][0],tau); - } - ae_frame_leave(_state); - return; - } - - /* - * General case. - * First pass. - */ - ae_vector_set_length(&w, m, _state); - ae_vector_set_length(&v, n+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=n; s++) - { - - /* - * Prepare random normal v - */ - do - { - for(i=1; i<=s; i++) - { - hqrndnormal2(&state, &tau.x, &tau.y, _state); - v.ptr.p_complex[i] = tau; - } - lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); - } - while(ae_c_eq_d(lambdav,0)); - - /* - * Prepare and apply reflection - */ - complexgeneratereflection(&v, s, &tau, _state); - v.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=n-1; i++) - { - hqrndunit2(&state, &tau.x, &tau.y, _state); - ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,m-1), tau); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Multiplication of MxN complex matrix by MxM random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_complex tau; - ae_complex lambdav; - ae_int_t s; - ae_int_t i; - ae_int_t j; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); - if( m==1 ) - { - - /* - * special case - */ - hqrndrandomize(&state, _state); - hqrndunit2(&state, &tau.x, &tau.y, _state); - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[0][j] = ae_c_mul(a->ptr.pp_complex[0][j],tau); - } - ae_frame_leave(_state); - return; - } - - /* - * General case. - * First pass. - */ - ae_vector_set_length(&w, n, _state); - ae_vector_set_length(&v, m+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=m; s++) - { - - /* - * Prepare random normal v - */ - do - { - for(i=1; i<=s; i++) - { - hqrndnormal2(&state, &tau.x, &tau.y, _state); - v.ptr.p_complex[i] = tau; - } - lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); - } - while(ae_c_eq_d(lambdav,0)); - - /* - * Prepare and apply reflection - */ - complexgeneratereflection(&v, s, &tau, _state); - v.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=m-1; i++) - { - hqrndunit2(&state, &tau.x, &tau.y, _state); - ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Symmetric multiplication of NxN matrix by random Haar distributed -orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q'*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndmultiply(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - double tau; - double lambdav; - ae_int_t s; - ae_int_t i; - double u1; - double u2; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&v, 0, DT_REAL, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - - /* - * General case. - */ - ae_vector_set_length(&w, n, _state); - ae_vector_set_length(&v, n+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=n; s++) - { - - /* - * Prepare random normal v - */ - do - { - i = 1; - while(i<=s) - { - hqrndnormal2(&state, &u1, &u2, _state); - v.ptr.p_double[i] = u1; - if( i+1<=s ) - { - v.ptr.p_double[i+1] = u2; - } - i = i+2; - } - lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); - } - while(ae_fp_eq(lambdav,0)); - - /* - * Prepare and apply reflection - */ - generatereflection(&v, s, &tau, _state); - v.ptr.p_double[1] = 1; - applyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); - applyreflectionfromtheleft(a, tau, &v, n-s, n-1, 0, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=n-1; i++) - { - tau = 2*hqrnduniformi(&state, 2, _state)-1; - ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,n-1), tau); - ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); - } - - /* - * Copy upper triangle to lower - */ - for(i=0; i<=n-2; i++) - { - ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &a->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1)); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Hermitian multiplication of NxN matrix by random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q^H*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndmultiply(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_complex tau; - ae_complex lambdav; - ae_int_t s; - ae_int_t i; - ae_vector w; - ae_vector v; - hqrndstate state; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); - _hqrndstate_init(&state, _state, ae_true); - - - /* - * General case. - */ - ae_vector_set_length(&w, n, _state); - ae_vector_set_length(&v, n+1, _state); - hqrndrandomize(&state, _state); - for(s=2; s<=n; s++) - { - - /* - * Prepare random normal v - */ - do - { - for(i=1; i<=s; i++) - { - hqrndnormal2(&state, &tau.x, &tau.y, _state); - v.ptr.p_complex[i] = tau; - } - lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); - } - while(ae_c_eq_d(lambdav,0)); - - /* - * Prepare and apply reflection - */ - complexgeneratereflection(&v, s, &tau, _state); - v.ptr.p_complex[1] = ae_complex_from_d(1); - complexapplyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); - complexapplyreflectionfromtheleft(a, ae_c_conj(tau, _state), &v, n-s, n-1, 0, n-1, &w, _state); - } - - /* - * Second pass. - */ - for(i=0; i<=n-1; i++) - { - hqrndunit2(&state, &tau.x, &tau.y, _state); - ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,n-1), tau); - tau = ae_c_conj(tau, _state); - ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); - } - - /* - * Change all values from lower triangle by complex-conjugate values - * from upper one - */ - for(i=0; i<=n-2; i++) - { - ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &a->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1)); - } - for(s=0; s<=n-2; s++) - { - for(i=s+1; i<=n-1; i++) - { - a->ptr.pp_complex[i][s].y = -a->ptr.pp_complex[i][s].y; - } - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -LU decomposition of a general real matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. -It is optimized for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlu(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - - ae_vector_clear(pivots); - - ae_assert(m>0, "RMatrixLU: incorrect M!", _state); - ae_assert(n>0, "RMatrixLU: incorrect N!", _state); - rmatrixplu(a, m, n, pivots, _state); -} - - -/************************************************************************* -LU decomposition of a general complex matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. It is optimized -for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlu(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - - ae_vector_clear(pivots); - - ae_assert(m>0, "CMatrixLU: incorrect M!", _state); - ae_assert(n>0, "CMatrixLU: incorrect N!", _state); - cmatrixplu(a, m, n, pivots, _state); -} - - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a Hermitian positive- -definite matrix. The result of an algorithm is a representation of A as -A=U'*U or A=L*L' (here X' detones conj(X^T)). - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U'*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_bool hpdmatrixcholesky(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - if( n<1 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - result = trfac_hpdmatrixcholeskyrec(a, 0, n, isupper, &tmp, _state); - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a symmetric positive- -definite matrix. The result of an algorithm is a representation of A as -A=U^T*U or A=L*L^T - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U^T*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_bool spdmatrixcholesky(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - if( n<1 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - result = spdmatrixcholeskyrec(a, 0, n, isupper, &tmp, _state); - ae_frame_leave(_state); - return result; -} - - -void rmatrixlup(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_int_t i; - ae_int_t j; - double mx; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(pivots); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * Internal LU decomposition subroutine. - * Never call it directly. - */ - ae_assert(m>0, "RMatrixLUP: incorrect M!", _state); - ae_assert(n>0, "RMatrixLUP: incorrect N!", _state); - - /* - * Scale matrix to avoid overflows, - * decompose it, then scale back. - */ - mx = 0; - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_neq(mx,0) ) - { - v = 1/mx; - for(i=0; i<=m-1; i++) - { - ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - } - ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); - ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); - trfac_rmatrixluprec(a, 0, m, n, pivots, &tmp, _state); - if( ae_fp_neq(mx,0) ) - { - v = mx; - for(i=0; i<=m-1; i++) - { - ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); - } - } - ae_frame_leave(_state); -} - - -void cmatrixlup(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_int_t i; - ae_int_t j; - double mx; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(pivots); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - - /* - * Internal LU decomposition subroutine. - * Never call it directly. - */ - ae_assert(m>0, "CMatrixLUP: incorrect M!", _state); - ae_assert(n>0, "CMatrixLUP: incorrect N!", _state); - - /* - * Scale matrix to avoid overflows, - * decompose it, then scale back. - */ - mx = 0; - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_neq(mx,0) ) - { - v = 1/mx; - for(i=0; i<=m-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); - } - } - ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); - ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); - trfac_cmatrixluprec(a, 0, m, n, pivots, &tmp, _state); - if( ae_fp_neq(mx,0) ) - { - v = mx; - for(i=0; i<=m-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); - } - } - ae_frame_leave(_state); -} - - -void rmatrixplu(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_int_t i; - ae_int_t j; - double mx; - double v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(pivots); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * Internal LU decomposition subroutine. - * Never call it directly. - */ - ae_assert(m>0, "RMatrixPLU: incorrect M!", _state); - ae_assert(n>0, "RMatrixPLU: incorrect N!", _state); - ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); - ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); - - /* - * Scale matrix to avoid overflows, - * decompose it, then scale back. - */ - mx = 0; - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_neq(mx,0) ) - { - v = 1/mx; - for(i=0; i<=m-1; i++) - { - ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - } - trfac_rmatrixplurec(a, 0, m, n, pivots, &tmp, _state); - if( ae_fp_neq(mx,0) ) - { - v = mx; - for(i=0; i<=ae_minint(m, n, _state)-1; i++) - { - ae_v_muld(&a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); - } - } - ae_frame_leave(_state); -} - - -void cmatrixplu(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tmp; - ae_int_t i; - ae_int_t j; - double mx; - ae_complex v; - - ae_frame_make(_state, &_frame_block); - ae_vector_clear(pivots); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - - /* - * Internal LU decomposition subroutine. - * Never call it directly. - */ - ae_assert(m>0, "CMatrixPLU: incorrect M!", _state); - ae_assert(n>0, "CMatrixPLU: incorrect N!", _state); - ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); - ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); - - /* - * Scale matrix to avoid overflows, - * decompose it, then scale back. - */ - mx = 0; - for(i=0; i<=m-1; i++) - { - for(j=0; j<=n-1; j++) - { - mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_neq(mx,0) ) - { - v = ae_complex_from_d(1/mx); - for(i=0; i<=m-1; i++) - { - ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); - } - } - trfac_cmatrixplurec(a, 0, m, n, pivots, &tmp, _state); - if( ae_fp_neq(mx,0) ) - { - v = ae_complex_from_d(mx); - for(i=0; i<=ae_minint(m, n, _state)-1; i++) - { - ae_v_cmulc(&a->ptr.pp_complex[i][i], 1, ae_v_len(i,n-1), v); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Recursive computational subroutine for SPDMatrixCholesky. - -INPUT PARAMETERS: - A - matrix given by upper or lower triangle - Offs - offset of diagonal block to decompose - N - diagonal block size - IsUpper - what half is given - Tmp - temporary array; allocated by function, if its size is too - small; can be reused on subsequent calls. - -OUTPUT PARAMETERS: - A - upper (or lower) triangle contains Cholesky decomposition - -RESULT: - True, on success - False, on failure - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t n1; - ae_int_t n2; - ae_bool result; - - - - /* - * check N - */ - if( n<1 ) - { - result = ae_false; - return result; - } - - /* - * Prepare buffer - */ - if( tmp->cnt<2*n ) - { - ae_vector_set_length(tmp, 2*n, _state); - } - - /* - * special cases - */ - if( n==1 ) - { - if( ae_fp_greater(a->ptr.pp_double[offs][offs],0) ) - { - a->ptr.pp_double[offs][offs] = ae_sqrt(a->ptr.pp_double[offs][offs], _state); - result = ae_true; - } - else - { - result = ae_false; - } - return result; - } - if( n<=ablasblocksize(a, _state) ) - { - result = trfac_spdmatrixcholesky2(a, offs, n, isupper, tmp, _state); - return result; - } - - /* - * general case: split task in cache-oblivious manner - */ - result = ae_true; - ablassplitlength(a, n, &n1, &n2, _state); - result = spdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); - if( !result ) - { - return result; - } - if( n2>0 ) - { - if( isupper ) - { - rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 1, a, offs, offs+n1, _state); - rmatrixsyrk(n2, n1, -1.0, a, offs, offs+n1, 1, 1.0, a, offs+n1, offs+n1, isupper, _state); - } - else - { - rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 1, a, offs+n1, offs, _state); - rmatrixsyrk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); - } - result = spdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); - if( !result ) - { - return result; - } - } - return result; -} - - -/************************************************************************* -Recurrent complex LU subroutine. -Never call it directly. - - -- ALGLIB routine -- - 04.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_cmatrixluprec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t m1; - ae_int_t m2; - - - - /* - * Kernel case - */ - if( ae_minint(m, n, _state)<=ablascomplexblocksize(a, _state) ) - { - trfac_cmatrixlup2(a, offs, m, n, pivots, tmp, _state); - return; - } - - /* - * Preliminary step, make N>=M - * - * ( A1 ) - * A = ( ), where A1 is square - * ( A2 ) - * - * Factorize A1, update A2 - */ - if( m>n ) - { - trfac_cmatrixluprec(a, offs, n, n, pivots, tmp, _state); - for(i=0; i<=n-1; i++) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n][offs+i], a->stride, "N", ae_v_len(0,m-n-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+n][offs+i], a->stride, &a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+n,offs+m-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n,offs+m-1)); - } - cmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); - return; - } - - /* - * Non-kernel case - */ - ablascomplexsplitlength(a, m, &m1, &m2, _state); - trfac_cmatrixluprec(a, offs, m1, n, pivots, tmp, _state); - if( m2>0 ) - { - for(i=0; i<=m1-1; i++) - { - if( offs+i!=pivots->ptr.p_int[offs+i] ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+m1][offs+i], a->stride, "N", ae_v_len(0,m2-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+m1][offs+i], a->stride, &a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+m1,offs+m-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m1,offs+m-1)); - } - } - cmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); - cmatrixgemm(m-m1, n-m1, m1, ae_complex_from_d(-1.0), a, offs+m1, offs, 0, a, offs, offs+m1, 0, ae_complex_from_d(1.0), a, offs+m1, offs+m1, _state); - trfac_cmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); - for(i=0; i<=m2-1; i++) - { - if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+m1+i], a->stride, "N", ae_v_len(0,m1-1)); - ae_v_cmove(&a->ptr.pp_complex[offs][offs+m1+i], a->stride, &a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, "N", ae_v_len(offs,offs+m1-1)); - ae_v_cmove(&a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m1-1)); - } - } - } -} - - -/************************************************************************* -Recurrent real LU subroutine. -Never call it directly. - - -- ALGLIB routine -- - 04.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_rmatrixluprec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t m1; - ae_int_t m2; - - - - /* - * Kernel case - */ - if( ae_minint(m, n, _state)<=ablasblocksize(a, _state) ) - { - trfac_rmatrixlup2(a, offs, m, n, pivots, tmp, _state); - return; - } - - /* - * Preliminary step, make N>=M - * - * ( A1 ) - * A = ( ), where A1 is square - * ( A2 ) - * - * Factorize A1, update A2 - */ - if( m>n ) - { - trfac_rmatrixluprec(a, offs, n, n, pivots, tmp, _state); - for(i=0; i<=n-1; i++) - { - if( offs+i!=pivots->ptr.p_int[offs+i] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n][offs+i], a->stride, ae_v_len(0,m-n-1)); - ae_v_move(&a->ptr.pp_double[offs+n][offs+i], a->stride, &a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+n,offs+m-1)); - ae_v_move(&a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n,offs+m-1)); - } - } - rmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); - return; - } - - /* - * Non-kernel case - */ - ablassplitlength(a, m, &m1, &m2, _state); - trfac_rmatrixluprec(a, offs, m1, n, pivots, tmp, _state); - if( m2>0 ) - { - for(i=0; i<=m1-1; i++) - { - if( offs+i!=pivots->ptr.p_int[offs+i] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+m1][offs+i], a->stride, ae_v_len(0,m2-1)); - ae_v_move(&a->ptr.pp_double[offs+m1][offs+i], a->stride, &a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+m1,offs+m-1)); - ae_v_move(&a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m1,offs+m-1)); - } - } - rmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); - rmatrixgemm(m-m1, n-m1, m1, -1.0, a, offs+m1, offs, 0, a, offs, offs+m1, 0, 1.0, a, offs+m1, offs+m1, _state); - trfac_rmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); - for(i=0; i<=m2-1; i++) - { - if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+m1+i], a->stride, ae_v_len(0,m1-1)); - ae_v_move(&a->ptr.pp_double[offs][offs+m1+i], a->stride, &a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, ae_v_len(offs,offs+m1-1)); - ae_v_move(&a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m1-1)); - } - } - } -} - - -/************************************************************************* -Recurrent complex LU subroutine. -Never call it directly. - - -- ALGLIB routine -- - 04.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_cmatrixplurec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n1; - ae_int_t n2; - - - - /* - * Kernel case - */ - if( ae_minint(m, n, _state)<=ablascomplexblocksize(a, _state) ) - { - trfac_cmatrixplu2(a, offs, m, n, pivots, tmp, _state); - return; - } - - /* - * Preliminary step, make M>=N. - * - * A = (A1 A2), where A1 is square - * Factorize A1, update A2 - */ - if( n>m ) - { - trfac_cmatrixplurec(a, offs, m, m, pivots, tmp, _state); - for(i=0; i<=m-1; i++) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+m], 1, "N", ae_v_len(0,n-m-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+m], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, "N", ae_v_len(offs+m,offs+n-1)); - ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m,offs+n-1)); - } - cmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); - return; - } - - /* - * Non-kernel case - */ - ablascomplexsplitlength(a, n, &n1, &n2, _state); - trfac_cmatrixplurec(a, offs, m, n1, pivots, tmp, _state); - if( n2>0 ) - { - for(i=0; i<=n1-1; i++) - { - if( offs+i!=pivots->ptr.p_int[offs+i] ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+n1], 1, "N", ae_v_len(0,n2-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+n1], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, "N", ae_v_len(offs+n1,offs+n-1)); - ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n1,offs+n-1)); - } - } - cmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); - cmatrixgemm(m-n1, n-n1, n1, ae_complex_from_d(-1.0), a, offs+n1, offs, 0, a, offs, offs+n1, 0, ae_complex_from_d(1.0), a, offs+n1, offs+n1, _state); - trfac_cmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); - for(i=0; i<=n2-1; i++) - { - if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n1+i][offs], 1, "N", ae_v_len(0,n1-1)); - ae_v_cmove(&a->ptr.pp_complex[offs+n1+i][offs], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, "N", ae_v_len(offs,offs+n1-1)); - ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+n1-1)); - } - } - } -} - - -/************************************************************************* -Recurrent real LU subroutine. -Never call it directly. - - -- ALGLIB routine -- - 04.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_rmatrixplurec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n1; - ae_int_t n2; - - - - /* - * Kernel case - */ - if( ae_minint(m, n, _state)<=ablasblocksize(a, _state) ) - { - trfac_rmatrixplu2(a, offs, m, n, pivots, tmp, _state); - return; - } - - /* - * Preliminary step, make M>=N. - * - * A = (A1 A2), where A1 is square - * Factorize A1, update A2 - */ - if( n>m ) - { - trfac_rmatrixplurec(a, offs, m, m, pivots, tmp, _state); - for(i=0; i<=m-1; i++) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+m], 1, ae_v_len(0,n-m-1)); - ae_v_move(&a->ptr.pp_double[offs+i][offs+m], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, ae_v_len(offs+m,offs+n-1)); - ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m,offs+n-1)); - } - rmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); - return; - } - - /* - * Non-kernel case - */ - ablassplitlength(a, n, &n1, &n2, _state); - trfac_rmatrixplurec(a, offs, m, n1, pivots, tmp, _state); - if( n2>0 ) - { - for(i=0; i<=n1-1; i++) - { - if( offs+i!=pivots->ptr.p_int[offs+i] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(0,n2-1)); - ae_v_move(&a->ptr.pp_double[offs+i][offs+n1], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, ae_v_len(offs+n1,offs+n-1)); - ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n1,offs+n-1)); - } - } - rmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); - rmatrixgemm(m-n1, n-n1, n1, -1.0, a, offs+n1, offs, 0, a, offs, offs+n1, 0, 1.0, a, offs+n1, offs+n1, _state); - trfac_rmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); - for(i=0; i<=n2-1; i++) - { - if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(0,n1-1)); - ae_v_move(&a->ptr.pp_double[offs+n1+i][offs], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, ae_v_len(offs,offs+n1-1)); - ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+n1-1)); - } - } - } -} - - -/************************************************************************* -Complex LUP kernel - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_cmatrixlup2(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t jp; - ae_complex s; - - - - /* - * Quick return if possible - */ - if( m==0||n==0 ) - { - return; - } - - /* - * main cycle - */ - for(j=0; j<=ae_minint(m-1, n-1, _state); j++) - { - - /* - * Find pivot, swap columns - */ - jp = j; - for(i=j+1; i<=n-1; i++) - { - if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+j][offs+i], _state),ae_c_abs(a->ptr.pp_complex[offs+j][offs+jp], _state)) ) - { - jp = i; - } - } - pivots->ptr.p_int[offs+j] = offs+jp; - if( jp!=j ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+j], a->stride, "N", ae_v_len(0,m-1)); - ae_v_cmove(&a->ptr.pp_complex[offs][offs+j], a->stride, &a->ptr.pp_complex[offs][offs+jp], a->stride, "N", ae_v_len(offs,offs+m-1)); - ae_v_cmove(&a->ptr.pp_complex[offs][offs+jp], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m-1)); - } - - /* - * LU decomposition of 1x(N-J) matrix - */ - if( ae_c_neq_d(a->ptr.pp_complex[offs+j][offs+j],0)&&j+1<=n-1 ) - { - s = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); - ae_v_cmulc(&a->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); - } - - /* - * Update trailing (M-J-1)x(N-J-1) matrix - */ - if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); - ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); - cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); - } - } -} - - -/************************************************************************* -Real LUP kernel - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -static void trfac_rmatrixlup2(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t jp; - double s; - - - - /* - * Quick return if possible - */ - if( m==0||n==0 ) - { - return; - } - - /* - * main cycle - */ - for(j=0; j<=ae_minint(m-1, n-1, _state); j++) - { - - /* - * Find pivot, swap columns - */ - jp = j; - for(i=j+1; i<=n-1; i++) - { - if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+j][offs+i], _state),ae_fabs(a->ptr.pp_double[offs+j][offs+jp], _state)) ) - { - jp = i; - } - } - pivots->ptr.p_int[offs+j] = offs+jp; - if( jp!=j ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+j], a->stride, ae_v_len(0,m-1)); - ae_v_move(&a->ptr.pp_double[offs][offs+j], a->stride, &a->ptr.pp_double[offs][offs+jp], a->stride, ae_v_len(offs,offs+m-1)); - ae_v_move(&a->ptr.pp_double[offs][offs+jp], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m-1)); - } - - /* - * LU decomposition of 1x(N-J) matrix - */ - if( ae_fp_neq(a->ptr.pp_double[offs+j][offs+j],0)&&j+1<=n-1 ) - { - s = 1/a->ptr.pp_double[offs+j][offs+j]; - ae_v_muld(&a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); - } - - /* - * Update trailing (M-J-1)x(N-J-1) matrix - */ - if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); - ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); - rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); - } - } -} - - -/************************************************************************* -Complex PLU kernel - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - June 30, 1992 -*************************************************************************/ -static void trfac_cmatrixplu2(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t jp; - ae_complex s; - - - - /* - * Quick return if possible - */ - if( m==0||n==0 ) - { - return; - } - for(j=0; j<=ae_minint(m-1, n-1, _state); j++) - { - - /* - * Find pivot and test for singularity. - */ - jp = j; - for(i=j+1; i<=m-1; i++) - { - if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+i][offs+j], _state),ae_c_abs(a->ptr.pp_complex[offs+jp][offs+j], _state)) ) - { - jp = i; - } - } - pivots->ptr.p_int[offs+j] = offs+jp; - if( ae_c_neq_d(a->ptr.pp_complex[offs+jp][offs+j],0) ) - { - - /* - *Apply the interchange to rows - */ - if( jp!=j ) - { - for(i=0; i<=n-1; i++) - { - s = a->ptr.pp_complex[offs+j][offs+i]; - a->ptr.pp_complex[offs+j][offs+i] = a->ptr.pp_complex[offs+jp][offs+i]; - a->ptr.pp_complex[offs+jp][offs+i] = s; - } - } - - /* - *Compute elements J+1:M of J-th column. - */ - if( j+1<=m-1 ) - { - s = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); - ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); - } - } - if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); - ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); - cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); - } - } -} - - -/************************************************************************* -Real PLU kernel - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - June 30, 1992 -*************************************************************************/ -static void trfac_rmatrixplu2(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t jp; - double s; - - - - /* - * Quick return if possible - */ - if( m==0||n==0 ) - { - return; - } - for(j=0; j<=ae_minint(m-1, n-1, _state); j++) - { - - /* - * Find pivot and test for singularity. - */ - jp = j; - for(i=j+1; i<=m-1; i++) - { - if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+i][offs+j], _state),ae_fabs(a->ptr.pp_double[offs+jp][offs+j], _state)) ) - { - jp = i; - } - } - pivots->ptr.p_int[offs+j] = offs+jp; - if( ae_fp_neq(a->ptr.pp_double[offs+jp][offs+j],0) ) - { - - /* - *Apply the interchange to rows - */ - if( jp!=j ) - { - for(i=0; i<=n-1; i++) - { - s = a->ptr.pp_double[offs+j][offs+i]; - a->ptr.pp_double[offs+j][offs+i] = a->ptr.pp_double[offs+jp][offs+i]; - a->ptr.pp_double[offs+jp][offs+i] = s; - } - } - - /* - *Compute elements J+1:M of J-th column. - */ - if( j+1<=m-1 ) - { - s = 1/a->ptr.pp_double[offs+j][offs+j]; - ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); - } - } - if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); - ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); - rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); - } - } -} - - -/************************************************************************* -Recursive computational subroutine for HPDMatrixCholesky - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t n1; - ae_int_t n2; - ae_bool result; - - - - /* - * check N - */ - if( n<1 ) - { - result = ae_false; - return result; - } - - /* - * Prepare buffer - */ - if( tmp->cnt<2*n ) - { - ae_vector_set_length(tmp, 2*n, _state); - } - - /* - * special cases - */ - if( n==1 ) - { - if( ae_fp_greater(a->ptr.pp_complex[offs][offs].x,0) ) - { - a->ptr.pp_complex[offs][offs] = ae_complex_from_d(ae_sqrt(a->ptr.pp_complex[offs][offs].x, _state)); - result = ae_true; - } - else - { - result = ae_false; - } - return result; - } - if( n<=ablascomplexblocksize(a, _state) ) - { - result = trfac_hpdmatrixcholesky2(a, offs, n, isupper, tmp, _state); - return result; - } - - /* - * general case: split task in cache-oblivious manner - */ - result = ae_true; - ablascomplexsplitlength(a, n, &n1, &n2, _state); - result = trfac_hpdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); - if( !result ) - { - return result; - } - if( n2>0 ) - { - if( isupper ) - { - cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 2, a, offs, offs+n1, _state); - cmatrixsyrk(n2, n1, -1.0, a, offs, offs+n1, 2, 1.0, a, offs+n1, offs+n1, isupper, _state); - } - else - { - cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 2, a, offs+n1, offs, _state); - cmatrixsyrk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); - } - result = trfac_hpdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); - if( !result ) - { - return result; - } - } - return result; -} - - -/************************************************************************* -Level-2 Hermitian Cholesky subroutine. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double ajj; - ae_complex v; - double r; - ae_bool result; - - - result = ae_true; - if( n<0 ) - { - result = ae_false; - return result; - } - - /* - * Quick return if possible - */ - if( n==0 ) - { - return result; - } - if( isupper ) - { - - /* - * Compute the Cholesky factorization A = U'*U. - */ - for(j=0; j<=n-1; j++) - { - - /* - * Compute U(J,J) and test for non-positive-definiteness. - */ - v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "N", ae_v_len(offs,offs+j-1)); - ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; - if( ae_fp_less_eq(ajj,0) ) - { - aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); - result = ae_false; - return result; - } - ajj = ae_sqrt(ajj, _state); - aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); - - /* - * Compute elements J+1:N-1 of row J. - */ - if( j0 ) - { - ae_v_cmoveneg(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", ae_v_len(0,j-1)); - cmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); - ae_v_cadd(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, &tmp->ptr.p_complex[n], 1, "N", ae_v_len(offs+j+1,offs+n-1)); - } - r = 1/ajj; - ae_v_cmuld(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); - } - } - } - else - { - - /* - * Compute the Cholesky factorization A = L*L'. - */ - for(j=0; j<=n-1; j++) - { - - /* - * Compute L(J+1,J+1) and test for non-positive-definiteness. - */ - v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", &aaa->ptr.pp_complex[offs+j][offs], 1, "N", ae_v_len(offs,offs+j-1)); - ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; - if( ae_fp_less_eq(ajj,0) ) - { - aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); - result = ae_false; - return result; - } - ajj = ae_sqrt(ajj, _state); - aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); - - /* - * Compute elements J+1:N of column J. - */ - if( j0 ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", ae_v_len(0,j-1)); - cmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); - for(i=0; i<=n-j-2; i++) - { - aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_div_d(ae_c_sub(aaa->ptr.pp_complex[offs+j+1+i][offs+j],tmp->ptr.p_complex[n+i]),ajj); - } - } - else - { - for(i=0; i<=n-j-2; i++) - { - aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_div_d(aaa->ptr.pp_complex[offs+j+1+i][offs+j],ajj); - } - } - } - } - } - return result; -} - - -/************************************************************************* -Level-2 Cholesky subroutine - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double ajj; - double v; - double r; - ae_bool result; - - - result = ae_true; - if( n<0 ) - { - result = ae_false; - return result; - } - - /* - * Quick return if possible - */ - if( n==0 ) - { - return result; - } - if( isupper ) - { - - /* - * Compute the Cholesky factorization A = U'*U. - */ - for(j=0; j<=n-1; j++) - { - - /* - * Compute U(J,J) and test for non-positive-definiteness. - */ - v = ae_v_dotproduct(&aaa->ptr.pp_double[offs][offs+j], aaa->stride, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(offs,offs+j-1)); - ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; - if( ae_fp_less_eq(ajj,0) ) - { - aaa->ptr.pp_double[offs+j][offs+j] = ajj; - result = ae_false; - return result; - } - ajj = ae_sqrt(ajj, _state); - aaa->ptr.pp_double[offs+j][offs+j] = ajj; - - /* - * Compute elements J+1:N-1 of row J. - */ - if( j0 ) - { - ae_v_moveneg(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(0,j-1)); - rmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); - ae_v_add(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, &tmp->ptr.p_double[n], 1, ae_v_len(offs+j+1,offs+n-1)); - } - r = 1/ajj; - ae_v_muld(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); - } - } - } - else - { - - /* - * Compute the Cholesky factorization A = L*L'. - */ - for(j=0; j<=n-1; j++) - { - - /* - * Compute L(J+1,J+1) and test for non-positive-definiteness. - */ - v = ae_v_dotproduct(&aaa->ptr.pp_double[offs+j][offs], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(offs,offs+j-1)); - ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; - if( ae_fp_less_eq(ajj,0) ) - { - aaa->ptr.pp_double[offs+j][offs+j] = ajj; - result = ae_false; - return result; - } - ajj = ae_sqrt(ajj, _state); - aaa->ptr.pp_double[offs+j][offs+j] = ajj; - - /* - * Compute elements J+1:N of column J. - */ - if( j0 ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(0,j-1)); - rmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); - for(i=0; i<=n-j-2; i++) - { - aaa->ptr.pp_double[offs+j+1+i][offs+j] = (aaa->ptr.pp_double[offs+j+1+i][offs+j]-tmp->ptr.p_double[n+i])/ajj; - } - } - else - { - for(i=0; i<=n-j-2; i++) - { - aaa->ptr.pp_double[offs+j+1+i][offs+j] = aaa->ptr.pp_double[offs+j+1+i][offs+j]/ajj; - } - } - } - } - } - return result; -} - - - - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcond1(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_vector t; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "RMatrixRCond1: N<1!", _state); - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - rmatrixlu(a, n, n, &pivots, _state); - rcond_rmatrixrcondluinternal(a, n, ae_true, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcondinf(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "RMatrixRCondInf: N<1!", _state); - nrm = 0; - for(i=0; i<=n-1; i++) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+ae_fabs(a->ptr.pp_double[i][j], _state); - } - nrm = ae_maxreal(nrm, v, _state); - } - rmatrixlu(a, n, n, &pivots, _state); - rcond_rmatrixrcondluinternal(a, n, ae_false, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - symmetric positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixrcond(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - double v; - double nrm; - ae_vector t; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - if( i==j ) - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][i], _state); - } - else - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][j], _state); - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); - } - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - if( spdmatrixcholesky(a, n, isupper, _state) ) - { - rcond_spdmatrixrcondcholeskyinternal(a, n, isupper, ae_true, nrm, &v, _state); - result = v; - } - else - { - result = -1; - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcond1(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_vector t; - ae_int_t j1; - ae_int_t j2; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - for(j=j1; j<=j2; j++) - { - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); - } - if( isunit ) - { - t.ptr.p_double[i] = t.ptr.p_double[i]+1; - } - else - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][i], _state); - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcondinf(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_int_t j1; - ae_int_t j2; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); - nrm = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - v = 0; - for(j=j1; j<=j2; j++) - { - v = v+ae_fabs(a->ptr.pp_double[i][j], _state); - } - if( isunit ) - { - v = v+1; - } - else - { - v = v+ae_fabs(a->ptr.pp_double[i][i], _state); - } - nrm = ae_maxreal(nrm, v, _state); - } - rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - Hermitian positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixrcond(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - double v; - double nrm; - ae_vector t; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - if( i==j ) - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][i], _state); - } - else - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][j], _state); - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); - } - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - if( hpdmatrixcholesky(a, n, isupper, _state) ) - { - rcond_hpdmatrixrcondcholeskyinternal(a, n, isupper, ae_true, nrm, &v, _state); - result = v; - } - else - { - result = -1; - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcond1(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_vector t; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "CMatrixRCond1: N<1!", _state); - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - cmatrixlu(a, n, n, &pivots, _state); - rcond_cmatrixrcondluinternal(a, n, ae_true, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcondinf(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "CMatrixRCondInf: N<1!", _state); - nrm = 0; - for(i=0; i<=n-1; i++) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+ae_c_abs(a->ptr.pp_complex[i][j], _state); - } - nrm = ae_maxreal(nrm, v, _state); - } - cmatrixlu(a, n, n, &pivots, _state); - rcond_cmatrixrcondluinternal(a, n, ae_false, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcond1(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_state *_state) -{ - double v; - double result; - - - rcond_rmatrixrcondluinternal(lua, n, ae_true, ae_false, 0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcondinf(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_state *_state) -{ - double v; - double result; - - - rcond_rmatrixrcondluinternal(lua, n, ae_false, ae_false, 0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixcholeskyrcond(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - double v; - double result; - - - rcond_spdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, 0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixcholeskyrcond(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - double v; - double result; - - - rcond_hpdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, 0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcond1(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_state *_state) -{ - double v; - double result; - - - ae_assert(n>=1, "CMatrixLURCond1: N<1!", _state); - rcond_cmatrixrcondluinternal(lua, n, ae_true, ae_false, 0.0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcondinf(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_state *_state) -{ - double v; - double result; - - - ae_assert(n>=1, "CMatrixLURCondInf: N<1!", _state); - rcond_cmatrixrcondluinternal(lua, n, ae_false, ae_false, 0.0, &v, _state); - result = v; - return result; -} - - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcond1(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_vector t; - ae_int_t j1; - ae_int_t j2; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); - ae_vector_set_length(&t, n, _state); - for(i=0; i<=n-1; i++) - { - t.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - for(j=j1; j<=j2; j++) - { - t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); - } - if( isunit ) - { - t.ptr.p_double[i] = t.ptr.p_double[i]+1; - } - else - { - t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][i], _state); - } - } - nrm = 0; - for(i=0; i<=n-1; i++) - { - nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); - } - rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcondinf(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double nrm; - ae_vector pivots; - ae_int_t j1; - ae_int_t j2; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); - nrm = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - v = 0; - for(j=j1; j<=j2; j++) - { - v = v+ae_c_abs(a->ptr.pp_complex[i][j], _state); - } - if( isunit ) - { - v = v+1; - } - else - { - v = v+ae_c_abs(a->ptr.pp_complex[i][i], _state); - } - nrm = ae_maxreal(nrm, v, _state); - } - rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); - result = v; - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Threshold for rcond: matrices with condition number beyond this threshold -are considered singular. - -Threshold must be far enough from underflow, at least Sqr(Threshold) must -be greater than underflow. -*************************************************************************/ -double rcondthreshold(ae_state *_state) -{ - double result; - - - result = ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state); - return result; -} - - -/************************************************************************* -Internal subroutine for condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static void rcond_rmatrixrcondtrinternal(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_bool onenorm, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector ex; - ae_vector ev; - ae_vector iwork; - ae_vector tmp; - ae_int_t i; - ae_int_t j; - ae_int_t kase; - ae_int_t kase1; - ae_int_t j1; - ae_int_t j2; - double ainvnm; - double maxgrowth; - double s; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); - ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * RC=0 if something happens - */ - *rc = 0; - - /* - * init - */ - if( onenorm ) - { - kase1 = 1; - } - else - { - kase1 = 2; - } - ae_vector_set_length(&iwork, n+1, _state); - ae_vector_set_length(&tmp, n, _state); - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - s = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - for(j=j1; j<=j2; j++) - { - s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - if( isunit ) - { - s = ae_maxreal(s, 1, _state); - } - else - { - s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][i], _state), _state); - } - } - if( ae_fp_eq(s,0) ) - { - s = 1; - } - s = 1/s; - - /* - * Scale according to S - */ - anorm = anorm*s; - - /* - * Quick return if possible - * We assume that ANORM<>0 after this block - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - - /* - * Estimate the norm of inv(A). - */ - ainvnm = 0; - kase = 0; - for(;;) - { - rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); - if( kase==0 ) - { - break; - } - - /* - * from 1-based array to 0-based - */ - for(i=0; i<=n-1; i++) - { - ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; - } - - /* - * multiply by inv(A) or inv(A') - */ - if( kase==kase1 ) - { - - /* - * multiply by inv(A) - */ - if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * multiply by inv(A') - */ - if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 1, isunit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - - /* - * from 0-based array to 1-based - */ - for(i=n-1; i>=0; i--) - { - ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - *rc = 1/ainvnm; - *rc = *rc/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - March 31, 1993 -*************************************************************************/ -static void rcond_cmatrixrcondtrinternal(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_bool onenorm, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector ex; - ae_vector cwork2; - ae_vector cwork3; - ae_vector cwork4; - ae_vector isave; - ae_vector rsave; - ae_int_t kase; - ae_int_t kase1; - double ainvnm; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - double s; - double maxgrowth; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork2, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork3, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork4, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&isave, 0, DT_INT, _state, ae_true); - ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); - - - /* - * RC=0 if something happens - */ - *rc = 0; - - /* - * init - */ - if( n<=0 ) - { - ae_frame_leave(_state); - return; - } - if( n==0 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&cwork2, n+1, _state); - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - s = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i+1; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i-1; - } - for(j=j1; j<=j2; j++) - { - s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - if( isunit ) - { - s = ae_maxreal(s, 1, _state); - } - else - { - s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][i], _state), _state); - } - } - if( ae_fp_eq(s,0) ) - { - s = 1; - } - s = 1/s; - - /* - * Scale according to S - */ - anorm = anorm*s; - - /* - * Quick return if possible - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Estimate the norm of inv(A). - */ - ainvnm = 0; - if( onenorm ) - { - kase1 = 1; - } - else - { - kase1 = 2; - } - kase = 0; - for(;;) - { - rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); - if( kase==0 ) - { - break; - } - - /* - * From 1-based to 0-based - */ - for(i=0; i<=n-1; i++) - { - ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; - } - - /* - * multiply by inv(A) or inv(A') - */ - if( kase==kase1 ) - { - - /* - * multiply by inv(A) - */ - if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * multiply by inv(A') - */ - if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 2, isunit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - - /* - * from 0-based to 1-based - */ - for(i=n-1; i>=0; i--) - { - ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - *rc = 1/ainvnm; - *rc = *rc/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine for condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - ae_bool isnormprovided, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t kase; - double ainvnm; - ae_vector ex; - ae_vector ev; - ae_vector tmp; - ae_vector iwork; - double sa; - double v; - double maxgrowth; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "Assertion failed", _state); - ae_vector_set_length(&tmp, n, _state); - - /* - * RC=0 if something happens - */ - *rc = 0; - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - sa = 0; - if( isupper ) - { - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i; j++) - { - sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); - } - } - } - if( ae_fp_eq(sa,0) ) - { - sa = 1; - } - sa = 1/sa; - - /* - * Estimate the norm of A. - */ - if( !isnormprovided ) - { - kase = 0; - anorm = 0; - for(;;) - { - rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); - if( kase==0 ) - { - break; - } - if( isupper ) - { - - /* - * Multiply by U - */ - for(i=1; i<=n; i++) - { - v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); - ex.ptr.p_double[i] = v; - } - ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); - - /* - * Multiply by U' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_double[i+1]; - ae_v_addd(&tmp.ptr.p_double[i], 1, &cha->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); - } - ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); - ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); - } - else - { - - /* - * Multiply by L' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_double[i+1]; - ae_v_addd(&tmp.ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i), v); - } - ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); - ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); - - /* - * Multiply by L - */ - for(i=n; i>=1; i--) - { - v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-1)); - ex.ptr.p_double[i] = v; - } - ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); - } - } - } - - /* - * Quick return if possible - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - - /* - * Estimate the 1-norm of inv(A). - */ - kase = 0; - for(;;) - { - rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); - if( kase==0 ) - { - break; - } - for(i=0; i<=n-1; i++) - { - ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; - } - if( isupper ) - { - - /* - * Multiply by inv(U'). - */ - if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(U). - */ - if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * Multiply by inv(L). - */ - if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(L'). - */ - if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - for(i=n-1; i>=0; i--) - { - ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - v = 1/ainvnm; - *rc = v/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine for condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - ae_bool isnormprovided, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector isave; - ae_vector rsave; - ae_vector ex; - ae_vector ev; - ae_vector tmp; - ae_int_t kase; - double ainvnm; - ae_complex v; - ae_int_t i; - ae_int_t j; - double sa; - double maxgrowth; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&isave, 0, DT_INT, _state, ae_true); - ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&ev, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>=1, "Assertion failed", _state); - ae_vector_set_length(&tmp, n, _state); - - /* - * RC=0 if something happens - */ - *rc = 0; - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - sa = 0; - if( isupper ) - { - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i; j++) - { - sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); - } - } - } - if( ae_fp_eq(sa,0) ) - { - sa = 1; - } - sa = 1/sa; - - /* - * Estimate the norm of A - */ - if( !isnormprovided ) - { - anorm = 0; - kase = 0; - for(;;) - { - rcond_cmatrixestimatenorm(n, &ev, &ex, &anorm, &kase, &isave, &rsave, _state); - if( kase==0 ) - { - break; - } - if( isupper ) - { - - /* - * Multiply by U - */ - for(i=1; i<=n; i++) - { - v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); - ex.ptr.p_complex[i] = v; - } - ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); - - /* - * Multiply by U' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_complex[i+1]; - ae_v_caddc(&tmp.ptr.p_complex[i], 1, &cha->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(i,n-1), v); - } - ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); - ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); - } - else - { - - /* - * Multiply by L' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_complex[i+1]; - ae_v_caddc(&tmp.ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i), v); - } - ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); - ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); - - /* - * Multiply by L - */ - for(i=n; i>=1; i--) - { - v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-1)); - ex.ptr.p_complex[i] = v; - } - ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); - } - } - } - - /* - * Quick return if possible - * After this block we assume that ANORM<>0 - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - - /* - * Estimate the norm of inv(A). - */ - ainvnm = 0; - kase = 0; - for(;;) - { - rcond_cmatrixestimatenorm(n, &ev, &ex, &ainvnm, &kase, &isave, &rsave, _state); - if( kase==0 ) - { - break; - } - for(i=0; i<=n-1; i++) - { - ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; - } - if( isupper ) - { - - /* - * Multiply by inv(U'). - */ - if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(U). - */ - if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * Multiply by inv(L). - */ - if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(L'). - */ - if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - for(i=n-1; i>=0; i--) - { - ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - *rc = 1/ainvnm; - *rc = *rc/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine for condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static void rcond_rmatrixrcondluinternal(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_bool onenorm, - ae_bool isanormprovided, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector ex; - ae_vector ev; - ae_vector iwork; - ae_vector tmp; - double v; - ae_int_t i; - ae_int_t j; - ae_int_t kase; - ae_int_t kase1; - double ainvnm; - double maxgrowth; - double su; - double sl; - ae_bool mupper; - ae_bool munit; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); - ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - - - /* - * RC=0 if something happens - */ - *rc = 0; - - /* - * init - */ - if( onenorm ) - { - kase1 = 1; - } - else - { - kase1 = 2; - } - mupper = ae_true; - munit = ae_true; - ae_vector_set_length(&iwork, n+1, _state); - ae_vector_set_length(&tmp, n, _state); - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - su = 0; - sl = 1; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - sl = ae_maxreal(sl, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); - } - for(j=i; j<=n-1; j++) - { - su = ae_maxreal(su, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(su,0) ) - { - su = 1; - } - su = 1/su; - sl = 1/sl; - - /* - * Estimate the norm of A. - */ - if( !isanormprovided ) - { - kase = 0; - anorm = 0; - for(;;) - { - rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); - if( kase==0 ) - { - break; - } - if( kase==kase1 ) - { - - /* - * Multiply by U - */ - for(i=1; i<=n; i++) - { - v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); - ex.ptr.p_double[i] = v; - } - - /* - * Multiply by L - */ - for(i=n; i>=1; i--) - { - if( i>1 ) - { - v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-2)); - } - else - { - v = 0; - } - ex.ptr.p_double[i] = ex.ptr.p_double[i]+v; - } - } - else - { - - /* - * Multiply by L' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_double[i+1]; - if( i>=1 ) - { - ae_v_addd(&tmp.ptr.p_double[0], 1, &lua->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v); - } - tmp.ptr.p_double[i] = tmp.ptr.p_double[i]+v; - } - ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); - - /* - * Multiply by U' - */ - for(i=0; i<=n-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=n-1; i++) - { - v = ex.ptr.p_double[i+1]; - ae_v_addd(&tmp.ptr.p_double[i], 1, &lua->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); - } - ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); - } - } - } - - /* - * Scale according to SU/SL - */ - anorm = anorm*su*sl; - - /* - * Quick return if possible - * We assume that ANORM<>0 after this block - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - if( n==1 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - - /* - * Estimate the norm of inv(A). - */ - ainvnm = 0; - kase = 0; - for(;;) - { - rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); - if( kase==0 ) - { - break; - } - - /* - * from 1-based array to 0-based - */ - for(i=0; i<=n-1; i++) - { - ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; - } - - /* - * multiply by inv(A) or inv(A') - */ - if( kase==kase1 ) - { - - /* - * Multiply by inv(L). - */ - if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 0, munit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(U). - */ - if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 0, !munit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * Multiply by inv(U'). - */ - if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 1, !munit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(L'). - */ - if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 1, munit, maxgrowth, _state) ) - { - ae_frame_leave(_state); - return; - } - } - - /* - * from 0-based array to 1-based - */ - for(i=n-1; i>=0; i--) - { - ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - *rc = 1/ainvnm; - *rc = *rc/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Condition number estimation - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - March 31, 1993 -*************************************************************************/ -static void rcond_cmatrixrcondluinternal(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_bool onenorm, - ae_bool isanormprovided, - double anorm, - double* rc, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector ex; - ae_vector cwork2; - ae_vector cwork3; - ae_vector cwork4; - ae_vector isave; - ae_vector rsave; - ae_int_t kase; - ae_int_t kase1; - double ainvnm; - ae_complex v; - ae_int_t i; - ae_int_t j; - double su; - double sl; - double maxgrowth; - - ae_frame_make(_state, &_frame_block); - *rc = 0; - ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork2, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork3, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&cwork4, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&isave, 0, DT_INT, _state, ae_true); - ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&cwork2, n+1, _state); - *rc = 0; - if( n==0 ) - { - *rc = 1; - ae_frame_leave(_state); - return; - } - - /* - * prepare parameters for triangular solver - */ - maxgrowth = 1/rcondthreshold(_state); - su = 0; - sl = 1; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - sl = ae_maxreal(sl, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); - } - for(j=i; j<=n-1; j++) - { - su = ae_maxreal(su, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(su,0) ) - { - su = 1; - } - su = 1/su; - sl = 1/sl; - - /* - * Estimate the norm of SU*SL*A. - */ - if( !isanormprovided ) - { - anorm = 0; - if( onenorm ) - { - kase1 = 1; - } - else - { - kase1 = 2; - } - kase = 0; - do - { - rcond_cmatrixestimatenorm(n, &cwork4, &ex, &anorm, &kase, &isave, &rsave, _state); - if( kase!=0 ) - { - if( kase==kase1 ) - { - - /* - * Multiply by U - */ - for(i=1; i<=n; i++) - { - v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); - ex.ptr.p_complex[i] = v; - } - - /* - * Multiply by L - */ - for(i=n; i>=1; i--) - { - v = ae_complex_from_d(0); - if( i>1 ) - { - v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-2)); - } - ex.ptr.p_complex[i] = ae_c_add(v,ex.ptr.p_complex[i]); - } - } - else - { - - /* - * Multiply by L' - */ - for(i=1; i<=n; i++) - { - cwork2.ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=1; i<=n; i++) - { - v = ex.ptr.p_complex[i]; - if( i>1 ) - { - ae_v_caddc(&cwork2.ptr.p_complex[1], 1, &lua->ptr.pp_complex[i-1][0], 1, "Conj", ae_v_len(1,i-1), v); - } - cwork2.ptr.p_complex[i] = ae_c_add(cwork2.ptr.p_complex[i],v); - } - - /* - * Multiply by U' - */ - for(i=1; i<=n; i++) - { - ex.ptr.p_complex[i] = ae_complex_from_d(0); - } - for(i=1; i<=n; i++) - { - v = cwork2.ptr.p_complex[i]; - ae_v_caddc(&ex.ptr.p_complex[i], 1, &lua->ptr.pp_complex[i-1][i-1], 1, "Conj", ae_v_len(i,n), v); - } - } - } - } - while(kase!=0); - } - - /* - * Scale according to SU/SL - */ - anorm = anorm*su*sl; - - /* - * Quick return if possible - */ - if( ae_fp_eq(anorm,0) ) - { - ae_frame_leave(_state); - return; - } - - /* - * Estimate the norm of inv(A). - */ - ainvnm = 0; - if( onenorm ) - { - kase1 = 1; - } - else - { - kase1 = 2; - } - kase = 0; - for(;;) - { - rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); - if( kase==0 ) - { - break; - } - - /* - * From 1-based to 0-based - */ - for(i=0; i<=n-1; i++) - { - ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; - } - - /* - * multiply by inv(A) or inv(A') - */ - if( kase==kase1 ) - { - - /* - * Multiply by inv(L). - */ - if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 0, ae_true, maxgrowth, _state) ) - { - *rc = 0; - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(U). - */ - if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 0, ae_false, maxgrowth, _state) ) - { - *rc = 0; - ae_frame_leave(_state); - return; - } - } - else - { - - /* - * Multiply by inv(U'). - */ - if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 2, ae_false, maxgrowth, _state) ) - { - *rc = 0; - ae_frame_leave(_state); - return; - } - - /* - * Multiply by inv(L'). - */ - if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 2, ae_true, maxgrowth, _state) ) - { - *rc = 0; - ae_frame_leave(_state); - return; - } - } - - /* - * from 0-based to 1-based - */ - for(i=n-1; i>=0; i--) - { - ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; - } - } - - /* - * Compute the estimate of the reciprocal condition number. - */ - if( ae_fp_neq(ainvnm,0) ) - { - *rc = 1/ainvnm; - *rc = *rc/anorm; - if( ae_fp_less(*rc,rcondthreshold(_state)) ) - { - *rc = 0; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine for matrix norm estimation - - -- LAPACK auxiliary routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992 -*************************************************************************/ -static void rcond_rmatrixestimatenorm(ae_int_t n, - /* Real */ ae_vector* v, - /* Real */ ae_vector* x, - /* Integer */ ae_vector* isgn, - double* est, - ae_int_t* kase, - ae_state *_state) -{ - ae_int_t itmax; - ae_int_t i; - double t; - ae_bool flg; - ae_int_t positer; - ae_int_t posj; - ae_int_t posjlast; - ae_int_t posjump; - ae_int_t posaltsgn; - ae_int_t posestold; - ae_int_t postemp; - - - itmax = 5; - posaltsgn = n+1; - posestold = n+2; - postemp = n+3; - positer = n+1; - posj = n+2; - posjlast = n+3; - posjump = n+4; - if( *kase==0 ) - { - ae_vector_set_length(v, n+4, _state); - ae_vector_set_length(x, n+1, _state); - ae_vector_set_length(isgn, n+5, _state); - t = (double)1/(double)n; - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = t; - } - *kase = 1; - isgn->ptr.p_int[posjump] = 1; - return; - } - - /* - * ................ ENTRY (JUMP = 1) - * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. - */ - if( isgn->ptr.p_int[posjump]==1 ) - { - if( n==1 ) - { - v->ptr.p_double[1] = x->ptr.p_double[1]; - *est = ae_fabs(v->ptr.p_double[1], _state); - *kase = 0; - return; - } - *est = 0; - for(i=1; i<=n; i++) - { - *est = *est+ae_fabs(x->ptr.p_double[i], _state); - } - for(i=1; i<=n; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],0) ) - { - x->ptr.p_double[i] = 1; - } - else - { - x->ptr.p_double[i] = -1; - } - isgn->ptr.p_int[i] = ae_sign(x->ptr.p_double[i], _state); - } - *kase = 2; - isgn->ptr.p_int[posjump] = 2; - return; - } - - /* - * ................ ENTRY (JUMP = 2) - * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. - */ - if( isgn->ptr.p_int[posjump]==2 ) - { - isgn->ptr.p_int[posj] = 1; - for(i=2; i<=n; i++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) - { - isgn->ptr.p_int[posj] = i; - } - } - isgn->ptr.p_int[positer] = 2; - - /* - * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. - */ - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = 0; - } - x->ptr.p_double[isgn->ptr.p_int[posj]] = 1; - *kase = 1; - isgn->ptr.p_int[posjump] = 3; - return; - } - - /* - * ................ ENTRY (JUMP = 3) - * X HAS BEEN OVERWRITTEN BY A*X. - */ - if( isgn->ptr.p_int[posjump]==3 ) - { - ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); - v->ptr.p_double[posestold] = *est; - *est = 0; - for(i=1; i<=n; i++) - { - *est = *est+ae_fabs(v->ptr.p_double[i], _state); - } - flg = ae_false; - for(i=1; i<=n; i++) - { - if( (ae_fp_greater_eq(x->ptr.p_double[i],0)&&isgn->ptr.p_int[i]<0)||(ae_fp_less(x->ptr.p_double[i],0)&&isgn->ptr.p_int[i]>=0) ) - { - flg = ae_true; - } - } - - /* - * REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. - * OR MAY BE CYCLING. - */ - if( !flg||ae_fp_less_eq(*est,v->ptr.p_double[posestold]) ) - { - v->ptr.p_double[posaltsgn] = 1; - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*(1+(double)(i-1)/(double)(n-1)); - v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; - } - *kase = 1; - isgn->ptr.p_int[posjump] = 5; - return; - } - for(i=1; i<=n; i++) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],0) ) - { - x->ptr.p_double[i] = 1; - isgn->ptr.p_int[i] = 1; - } - else - { - x->ptr.p_double[i] = -1; - isgn->ptr.p_int[i] = -1; - } - } - *kase = 2; - isgn->ptr.p_int[posjump] = 4; - return; - } - - /* - * ................ ENTRY (JUMP = 4) - * X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. - */ - if( isgn->ptr.p_int[posjump]==4 ) - { - isgn->ptr.p_int[posjlast] = isgn->ptr.p_int[posj]; - isgn->ptr.p_int[posj] = 1; - for(i=2; i<=n; i++) - { - if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) - { - isgn->ptr.p_int[posj] = i; - } - } - if( ae_fp_neq(x->ptr.p_double[isgn->ptr.p_int[posjlast]],ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state))&&isgn->ptr.p_int[positer]ptr.p_int[positer] = isgn->ptr.p_int[positer]+1; - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = 0; - } - x->ptr.p_double[isgn->ptr.p_int[posj]] = 1; - *kase = 1; - isgn->ptr.p_int[posjump] = 3; - return; - } - - /* - * ITERATION COMPLETE. FINAL STAGE. - */ - v->ptr.p_double[posaltsgn] = 1; - for(i=1; i<=n; i++) - { - x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*(1+(double)(i-1)/(double)(n-1)); - v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; - } - *kase = 1; - isgn->ptr.p_int[posjump] = 5; - return; - } - - /* - * ................ ENTRY (JUMP = 5) - * X HAS BEEN OVERWRITTEN BY A*X. - */ - if( isgn->ptr.p_int[posjump]==5 ) - { - v->ptr.p_double[postemp] = 0; - for(i=1; i<=n; i++) - { - v->ptr.p_double[postemp] = v->ptr.p_double[postemp]+ae_fabs(x->ptr.p_double[i], _state); - } - v->ptr.p_double[postemp] = 2*v->ptr.p_double[postemp]/(3*n); - if( ae_fp_greater(v->ptr.p_double[postemp],*est) ) - { - ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); - *est = v->ptr.p_double[postemp]; - } - *kase = 0; - return; - } -} - - -static void rcond_cmatrixestimatenorm(ae_int_t n, - /* Complex */ ae_vector* v, - /* Complex */ ae_vector* x, - double* est, - ae_int_t* kase, - /* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_state *_state) -{ - ae_int_t itmax; - ae_int_t i; - ae_int_t iter; - ae_int_t j; - ae_int_t jlast; - ae_int_t jump; - double absxi; - double altsgn; - double estold; - double safmin; - double temp; - - - - /* - *Executable Statements .. - */ - itmax = 5; - safmin = ae_minrealnumber; - if( *kase==0 ) - { - ae_vector_set_length(v, n+1, _state); - ae_vector_set_length(x, n+1, _state); - ae_vector_set_length(isave, 5, _state); - ae_vector_set_length(rsave, 4, _state); - for(i=1; i<=n; i++) - { - x->ptr.p_complex[i] = ae_complex_from_d((double)1/(double)n); - } - *kase = 1; - jump = 1; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - rcond_internalcomplexrcondloadall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - - /* - * ENTRY (JUMP = 1) - * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. - */ - if( jump==1 ) - { - if( n==1 ) - { - v->ptr.p_complex[1] = x->ptr.p_complex[1]; - *est = ae_c_abs(v->ptr.p_complex[1], _state); - *kase = 0; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - *est = rcond_internalcomplexrcondscsum1(x, n, _state); - for(i=1; i<=n; i++) - { - absxi = ae_c_abs(x->ptr.p_complex[i], _state); - if( ae_fp_greater(absxi,safmin) ) - { - x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); - } - else - { - x->ptr.p_complex[i] = ae_complex_from_d(1); - } - } - *kase = 2; - jump = 2; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - - /* - * ENTRY (JUMP = 2) - * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. - */ - if( jump==2 ) - { - j = rcond_internalcomplexrcondicmax1(x, n, _state); - iter = 2; - - /* - * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. - */ - for(i=1; i<=n; i++) - { - x->ptr.p_complex[i] = ae_complex_from_d(0); - } - x->ptr.p_complex[j] = ae_complex_from_d(1); - *kase = 1; - jump = 3; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - - /* - * ENTRY (JUMP = 3) - * X HAS BEEN OVERWRITTEN BY A*X. - */ - if( jump==3 ) - { - ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); - estold = *est; - *est = rcond_internalcomplexrcondscsum1(v, n, _state); - - /* - * TEST FOR CYCLING. - */ - if( ae_fp_less_eq(*est,estold) ) - { - - /* - * ITERATION COMPLETE. FINAL STAGE. - */ - altsgn = 1; - for(i=1; i<=n; i++) - { - x->ptr.p_complex[i] = ae_complex_from_d(altsgn*(1+(double)(i-1)/(double)(n-1))); - altsgn = -altsgn; - } - *kase = 1; - jump = 5; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - for(i=1; i<=n; i++) - { - absxi = ae_c_abs(x->ptr.p_complex[i], _state); - if( ae_fp_greater(absxi,safmin) ) - { - x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); - } - else - { - x->ptr.p_complex[i] = ae_complex_from_d(1); - } - } - *kase = 2; - jump = 4; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - - /* - * ENTRY (JUMP = 4) - * X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. - */ - if( jump==4 ) - { - jlast = j; - j = rcond_internalcomplexrcondicmax1(x, n, _state); - if( ae_fp_neq(ae_c_abs(x->ptr.p_complex[jlast], _state),ae_c_abs(x->ptr.p_complex[j], _state))&&iterptr.p_complex[i] = ae_complex_from_d(0); - } - x->ptr.p_complex[j] = ae_complex_from_d(1); - *kase = 1; - jump = 3; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - - /* - * ITERATION COMPLETE. FINAL STAGE. - */ - altsgn = 1; - for(i=1; i<=n; i++) - { - x->ptr.p_complex[i] = ae_complex_from_d(altsgn*(1+(double)(i-1)/(double)(n-1))); - altsgn = -altsgn; - } - *kase = 1; - jump = 5; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } - - /* - * ENTRY (JUMP = 5) - * X HAS BEEN OVERWRITTEN BY A*X. - */ - if( jump==5 ) - { - temp = 2*(rcond_internalcomplexrcondscsum1(x, n, _state)/(3*n)); - if( ae_fp_greater(temp,*est) ) - { - ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); - *est = temp; - } - *kase = 0; - rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); - return; - } -} - - -static double rcond_internalcomplexrcondscsum1(/* Complex */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - double result; - - - result = 0; - for(i=1; i<=n; i++) - { - result = result+ae_c_abs(x->ptr.p_complex[i], _state); - } - return result; -} - - -static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - double m; - ae_int_t result; - - - result = 1; - m = ae_c_abs(x->ptr.p_complex[1], _state); - for(i=2; i<=n; i++) - { - if( ae_fp_greater(ae_c_abs(x->ptr.p_complex[i], _state),m) ) - { - result = i; - m = ae_c_abs(x->ptr.p_complex[i], _state); - } - } - return result; -} - - -static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_int_t* i, - ae_int_t* iter, - ae_int_t* j, - ae_int_t* jlast, - ae_int_t* jump, - double* absxi, - double* altsgn, - double* estold, - double* temp, - ae_state *_state) -{ - - - isave->ptr.p_int[0] = *i; - isave->ptr.p_int[1] = *iter; - isave->ptr.p_int[2] = *j; - isave->ptr.p_int[3] = *jlast; - isave->ptr.p_int[4] = *jump; - rsave->ptr.p_double[0] = *absxi; - rsave->ptr.p_double[1] = *altsgn; - rsave->ptr.p_double[2] = *estold; - rsave->ptr.p_double[3] = *temp; -} - - -static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, - /* Real */ ae_vector* rsave, - ae_int_t* i, - ae_int_t* iter, - ae_int_t* j, - ae_int_t* jlast, - ae_int_t* jump, - double* absxi, - double* altsgn, - double* estold, - double* temp, - ae_state *_state) -{ - - - *i = isave->ptr.p_int[0]; - *iter = isave->ptr.p_int[1]; - *j = isave->ptr.p_int[2]; - *jlast = isave->ptr.p_int[3]; - *jump = isave->ptr.p_int[4]; - *absxi = rsave->ptr.p_double[0]; - *altsgn = rsave->ptr.p_double[1]; - *estold = rsave->ptr.p_double[2]; - *temp = rsave->ptr.p_double[3]; -} - - - - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of RMatrixLU subroutine). - Pivots - table of permutations - (the output of RMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code: - * -3 A is singular, or VERY close to singular. - it is filled by zeros in such cases. - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - A - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixluinverse(/* Real */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector work; - ae_int_t i; - ae_int_t j; - ae_int_t k; - double v; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _matinvreport_clear(rep); - ae_vector_init(&work, 0, DT_REAL, _state, ae_true); - - ae_assert(n>0, "RMatrixLUInverse: N<=0!", _state); - ae_assert(a->cols>=n, "RMatrixLUInverse: cols(A)rows>=n, "RMatrixLUInverse: rows(A)cnt>=n, "RMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]0, "RMatrixLUInverse: incorrect Pivots array!", _state); - - /* - * calculate condition numbers - */ - rep->r1 = rmatrixlurcond1(a, n, _state); - rep->rinf = rmatrixlurcondinf(a, n, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Call cache-oblivious code - */ - ae_vector_set_length(&work, n, _state); - matinv_rmatrixluinverserec(a, 0, n, &work, info, rep, _state); - - /* - * apply permutations - */ - for(i=0; i<=n-1; i++) - { - for(j=n-2; j>=0; j--) - { - k = pivots->ptr.p_int[j]; - v = a->ptr.pp_double[i][j]; - a->ptr.pp_double[i][j] = a->ptr.pp_double[i][k]; - a->ptr.pp_double[i][k] = v; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - -Result: - True, if the matrix is not singular. - False, if the matrix is singular. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector pivots; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _matinvreport_clear(rep); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>0, "RMatrixInverse: N<=0!", _state); - ae_assert(a->cols>=n, "RMatrixInverse: cols(A)rows>=n, "RMatrixInverse: rows(A)0, "CMatrixLUInverse: N<=0!", _state); - ae_assert(a->cols>=n, "CMatrixLUInverse: cols(A)rows>=n, "CMatrixLUInverse: rows(A)cnt>=n, "CMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]0, "CMatrixLUInverse: incorrect Pivots array!", _state); - - /* - * calculate condition numbers - */ - rep->r1 = cmatrixlurcond1(a, n, _state); - rep->rinf = cmatrixlurcondinf(a, n, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Call cache-oblivious code - */ - ae_vector_set_length(&work, n, _state); - matinv_cmatrixluinverserec(a, 0, n, &work, info, rep, _state); - - /* - * apply permutations - */ - for(i=0; i<=n-1; i++) - { - for(j=n-2; j>=0; j--) - { - k = pivots->ptr.p_int[j]; - v = a->ptr.pp_complex[i][j]; - a->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][k]; - a->ptr.pp_complex[i][k] = v; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void cmatrixinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector pivots; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _matinvreport_clear(rep); - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>0, "CRMatrixInverse: N<=0!", _state); - ae_assert(a->cols>=n, "CRMatrixInverse: cols(A)rows>=n, "CRMatrixInverse: rows(A)0, "SPDMatrixCholeskyInverse: N<=0!", _state); - ae_assert(a->cols>=n, "SPDMatrixCholeskyInverse: cols(A)rows>=n, "SPDMatrixCholeskyInverse: rows(A)ptr.pp_double[i][i], _state); - } - ae_assert(f, "SPDMatrixCholeskyInverse: A contains infinite or NaN values!", _state); - - /* - * calculate condition numbers - */ - rep->r1 = spdmatrixcholeskyrcond(a, n, isupper, _state); - rep->rinf = rep->r1; - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - if( isupper ) - { - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Inverse - */ - ae_vector_set_length(&tmp, n, _state); - matinv_spdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Inversion of a symmetric positive definite matrix. - -Given an upper or lower triangle of a symmetric positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - - *info = 0; - _matinvreport_clear(rep); - - ae_assert(n>0, "SPDMatrixInverse: N<=0!", _state); - ae_assert(a->cols>=n, "SPDMatrixInverse: cols(A)rows>=n, "SPDMatrixInverse: rows(A)0, "HPDMatrixCholeskyInverse: N<=0!", _state); - ae_assert(a->cols>=n, "HPDMatrixCholeskyInverse: cols(A)rows>=n, "HPDMatrixCholeskyInverse: rows(A)ptr.pp_complex[i][i].x, _state))&&ae_isfinite(a->ptr.pp_complex[i][i].y, _state); - } - ae_assert(f, "HPDMatrixCholeskyInverse: A contains infinite or NaN values!", _state); - *info = 1; - - /* - * calculate condition numbers - */ - rep->r1 = hpdmatrixcholeskyrcond(a, n, isupper, _state); - rep->rinf = rep->r1; - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - if( isupper ) - { - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Inverse - */ - ae_vector_set_length(&tmp, n, _state); - matinv_hpdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Inversion of a Hermitian positive definite matrix. - -Given an upper or lower triangle of a Hermitian positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - - *info = 0; - _matinvreport_clear(rep); - - ae_assert(n>0, "HPDMatrixInverse: N<=0!", _state); - ae_assert(a->cols>=n, "HPDMatrixInverse: cols(A)rows>=n, "HPDMatrixInverse: rows(A)0, "RMatrixTRInverse: N<=0!", _state); - ae_assert(a->cols>=n, "RMatrixTRInverse: cols(A)rows>=n, "RMatrixTRInverse: rows(A)r1 = rmatrixtrrcond1(a, n, isupper, isunit, _state); - rep->rinf = rmatrixtrrcondinf(a, n, isupper, isunit, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_double[i][j] = 0; - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Invert - */ - ae_vector_set_length(&tmp, n, _state); - matinv_rmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, info, rep, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Triangular matrix inverse (complex) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixtrinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_vector tmp; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _matinvreport_clear(rep); - ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(n>0, "CMatrixTRInverse: N<=0!", _state); - ae_assert(a->cols>=n, "CMatrixTRInverse: cols(A)rows>=n, "CMatrixTRInverse: rows(A)r1 = cmatrixtrrcond1(a, n, isupper, isunit, _state); - rep->rinf = cmatrixtrrcondinf(a, n, isupper, isunit, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - a->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - - /* - * Invert - */ - ae_vector_set_length(&tmp, n, _state); - matinv_cmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, info, rep, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Triangular matrix inversion, recursive subroutine - - -- ALGLIB -- - 05.02.2010, Bochkanov Sergey. - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992. -*************************************************************************/ -static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - /* Real */ ae_vector* tmp, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_int_t n1; - ae_int_t n2; - ae_int_t i; - ae_int_t j; - double v; - double ajj; - - - if( n<1 ) - { - *info = -1; - return; - } - - /* - * Base case - */ - if( n<=ablasblocksize(a, _state) ) - { - if( isupper ) - { - - /* - * Compute inverse of upper triangular matrix. - */ - for(j=0; j<=n-1; j++) - { - if( !isunit ) - { - if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],0) ) - { - *info = -3; - return; - } - a->ptr.pp_double[offs+j][offs+j] = 1/a->ptr.pp_double[offs+j][offs+j]; - ajj = -a->ptr.pp_double[offs+j][offs+j]; - } - else - { - ajj = -1; - } - - /* - * Compute elements 1:j-1 of j-th column. - */ - if( j>0 ) - { - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(0,j-1)); - for(i=0; i<=j-1; i++) - { - if( iptr.pp_double[offs+i][offs+i+1], 1, &tmp->ptr.p_double[i+1], 1, ae_v_len(offs+i+1,offs+j-1)); - } - else - { - v = 0; - } - if( !isunit ) - { - a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[i]; - } - else - { - a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[i]; - } - } - ae_v_muld(&a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); - } - } - } - else - { - - /* - * Compute inverse of lower triangular matrix. - */ - for(j=n-1; j>=0; j--) - { - if( !isunit ) - { - if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],0) ) - { - *info = -3; - return; - } - a->ptr.pp_double[offs+j][offs+j] = 1/a->ptr.pp_double[offs+j][offs+j]; - ajj = -a->ptr.pp_double[offs+j][offs+j]; - } - else - { - ajj = -1; - } - if( jptr.p_double[j+1], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(j+1,n-1)); - for(i=j+1; i<=n-1; i++) - { - if( i>j+1 ) - { - v = ae_v_dotproduct(&a->ptr.pp_double[offs+i][offs+j+1], 1, &tmp->ptr.p_double[j+1], 1, ae_v_len(offs+j+1,offs+i-1)); - } - else - { - v = 0; - } - if( !isunit ) - { - a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[i]; - } - else - { - a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[i]; - } - } - ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); - } - } - } - return; - } - - /* - * Recursive case - */ - ablassplitlength(a, n, &n1, &n2, _state); - if( n2>0 ) - { - if( isupper ) - { - for(i=0; i<=n1-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); - rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); - } - else - { - for(i=0; i<=n2-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); - rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); - } - matinv_rmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, info, rep, _state); - } - matinv_rmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, info, rep, _state); -} - - -/************************************************************************* -Triangular matrix inversion, recursive subroutine - - -- ALGLIB -- - 05.02.2010, Bochkanov Sergey. - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - February 29, 1992. -*************************************************************************/ -static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - /* Complex */ ae_vector* tmp, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_int_t n1; - ae_int_t n2; - ae_int_t i; - ae_int_t j; - ae_complex v; - ae_complex ajj; - - - if( n<1 ) - { - *info = -1; - return; - } - - /* - * Base case - */ - if( n<=ablascomplexblocksize(a, _state) ) - { - if( isupper ) - { - - /* - * Compute inverse of upper triangular matrix. - */ - for(j=0; j<=n-1; j++) - { - if( !isunit ) - { - if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],0) ) - { - *info = -3; - return; - } - a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); - ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); - } - else - { - ajj = ae_complex_from_d(-1); - } - - /* - * Compute elements 1:j-1 of j-th column. - */ - if( j>0 ) - { - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+0][offs+j], a->stride, "N", ae_v_len(0,j-1)); - for(i=0; i<=j-1; i++) - { - if( iptr.pp_complex[offs+i][offs+i+1], 1, "N", &tmp->ptr.p_complex[i+1], 1, "N", ae_v_len(offs+i+1,offs+j-1)); - } - else - { - v = ae_complex_from_d(0); - } - if( !isunit ) - { - a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[i])); - } - else - { - a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[i]); - } - } - ae_v_cmulc(&a->ptr.pp_complex[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); - } - } - } - else - { - - /* - * Compute inverse of lower triangular matrix. - */ - for(j=n-1; j>=0; j--) - { - if( !isunit ) - { - if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],0) ) - { - *info = -3; - return; - } - a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div(1,a->ptr.pp_complex[offs+j][offs+j]); - ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); - } - else - { - ajj = ae_complex_from_d(-1); - } - if( jptr.p_complex[j+1], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(j+1,n-1)); - for(i=j+1; i<=n-1; i++) - { - if( i>j+1 ) - { - v = ae_v_cdotproduct(&a->ptr.pp_complex[offs+i][offs+j+1], 1, "N", &tmp->ptr.p_complex[j+1], 1, "N", ae_v_len(offs+j+1,offs+i-1)); - } - else - { - v = ae_complex_from_d(0); - } - if( !isunit ) - { - a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[i])); - } - else - { - a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[i]); - } - } - ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); - } - } - } - return; - } - - /* - * Recursive case - */ - ablascomplexsplitlength(a, n, &n1, &n2, _state); - if( n2>0 ) - { - if( isupper ) - { - for(i=0; i<=n1-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); - cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); - } - else - { - for(i=0; i<=n2-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); - cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); - } - matinv_cmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, info, rep, _state); - } - matinv_cmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, info, rep, _state); -} - - -static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - /* Real */ ae_vector* work, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - ae_int_t n1; - ae_int_t n2; - - - if( n<1 ) - { - *info = -1; - return; - } - - /* - * Base case - */ - if( n<=ablasblocksize(a, _state) ) - { - - /* - * Form inv(U) - */ - matinv_rmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, info, rep, _state); - if( *info<=0 ) - { - return; - } - - /* - * Solve the equation inv(A)*L = inv(U) for inv(A). - */ - for(j=n-1; j>=0; j--) - { - - /* - * Copy current column of L to WORK and replace with zeros. - */ - for(i=j+1; i<=n-1; i++) - { - work->ptr.p_double[i] = a->ptr.pp_double[offs+i][offs+j]; - a->ptr.pp_double[offs+i][offs+j] = 0; - } - - /* - * Compute current column of inv(A). - */ - if( jptr.pp_double[offs+i][offs+j+1], 1, &work->ptr.p_double[j+1], 1, ae_v_len(offs+j+1,offs+n-1)); - a->ptr.pp_double[offs+i][offs+j] = a->ptr.pp_double[offs+i][offs+j]-v; - } - } - } - return; - } - - /* - * Recursive code: - * - * ( L1 ) ( U1 U12 ) - * A = ( ) * ( ) - * ( L12 L2 ) ( U2 ) - * - * ( W X ) - * A^-1 = ( ) - * ( Y Z ) - */ - ablassplitlength(a, n, &n1, &n2, _state); - ae_assert(n2>0, "LUInverseRec: internal error!", _state); - - /* - * X := inv(U1)*U12*inv(U2) - */ - rmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); - rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); - - /* - * Y := inv(L2)*L12*inv(L1) - */ - rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); - rmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); - - /* - * W := inv(L1*U1)+X*Y - */ - matinv_rmatrixluinverserec(a, offs, n1, work, info, rep, _state); - if( *info<=0 ) - { - return; - } - rmatrixgemm(n1, n1, n2, 1.0, a, offs, offs+n1, 0, a, offs+n1, offs, 0, 1.0, a, offs, offs, _state); - - /* - * X := -X*inv(L2) - * Y := -inv(U2)*Y - */ - rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); - for(i=0; i<=n1-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); - for(i=0; i<=n2-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - - /* - * Z := inv(L2*U2) - */ - matinv_rmatrixluinverserec(a, offs+n1, n2, work, info, rep, _state); -} - - -static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - /* Complex */ ae_vector* work, - ae_int_t* info, - matinvreport* rep, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_complex v; - ae_int_t n1; - ae_int_t n2; - - - if( n<1 ) - { - *info = -1; - return; - } - - /* - * Base case - */ - if( n<=ablascomplexblocksize(a, _state) ) - { - - /* - * Form inv(U) - */ - matinv_cmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, info, rep, _state); - if( *info<=0 ) - { - return; - } - - /* - * Solve the equation inv(A)*L = inv(U) for inv(A). - */ - for(j=n-1; j>=0; j--) - { - - /* - * Copy current column of L to WORK and replace with zeros. - */ - for(i=j+1; i<=n-1; i++) - { - work->ptr.p_complex[i] = a->ptr.pp_complex[offs+i][offs+j]; - a->ptr.pp_complex[offs+i][offs+j] = ae_complex_from_d(0); - } - - /* - * Compute current column of inv(A). - */ - if( jptr.pp_complex[offs+i][offs+j+1], 1, "N", &work->ptr.p_complex[j+1], 1, "N", ae_v_len(offs+j+1,offs+n-1)); - a->ptr.pp_complex[offs+i][offs+j] = ae_c_sub(a->ptr.pp_complex[offs+i][offs+j],v); - } - } - } - return; - } - - /* - * Recursive code: - * - * ( L1 ) ( U1 U12 ) - * A = ( ) * ( ) - * ( L12 L2 ) ( U2 ) - * - * ( W X ) - * A^-1 = ( ) - * ( Y Z ) - */ - ablascomplexsplitlength(a, n, &n1, &n2, _state); - ae_assert(n2>0, "LUInverseRec: internal error!", _state); - - /* - * X := inv(U1)*U12*inv(U2) - */ - cmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); - cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); - - /* - * Y := inv(L2)*L12*inv(L1) - */ - cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); - cmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); - - /* - * W := inv(L1*U1)+X*Y - */ - matinv_cmatrixluinverserec(a, offs, n1, work, info, rep, _state); - if( *info<=0 ) - { - return; - } - cmatrixgemm(n1, n1, n2, ae_complex_from_d(1.0), a, offs, offs+n1, 0, a, offs+n1, offs, 0, ae_complex_from_d(1.0), a, offs, offs, _state); - - /* - * X := -X*inv(L2) - * Y := -inv(U2)*Y - */ - cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); - for(i=0; i<=n1-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); - for(i=0; i<=n2-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - - /* - * Z := inv(L2*U2) - */ - matinv_cmatrixluinverserec(a, offs+n1, n2, work, info, rep, _state); -} - - -/************************************************************************* -Recursive subroutine for SPD inversion. - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -static void matinv_spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - ae_int_t n1; - ae_int_t n2; - ae_int_t info2; - matinvreport rep2; - - ae_frame_make(_state, &_frame_block); - _matinvreport_init(&rep2, _state, ae_true); - - if( n<1 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Base case - */ - if( n<=ablasblocksize(a, _state) ) - { - matinv_rmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, &info2, &rep2, _state); - if( isupper ) - { - - /* - * Compute the product U * U'. - * NOTE: we never assume that diagonal of U is real - */ - for(i=0; i<=n-1; i++) - { - if( i==0 ) - { - - /* - * 1x1 matrix - */ - a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); - } - else - { - - /* - * (I+1)x(I+1) matrix, - * - * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) - * ( ) * ( ) = ( ) - * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) - * - * A11 is IxI, A22 is 1x1. - */ - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(0,i-1)); - for(j=0; j<=i-1; j++) - { - v = a->ptr.pp_double[offs+j][offs+i]; - ae_v_addd(&a->ptr.pp_double[offs+j][offs+j], 1, &tmp->ptr.p_double[j], 1, ae_v_len(offs+j,offs+i-1), v); - } - v = a->ptr.pp_double[offs+i][offs+i]; - ae_v_muld(&a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); - a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); - } - } - } - else - { - - /* - * Compute the product L' * L - * NOTE: we never assume that diagonal of L is real - */ - for(i=0; i<=n-1; i++) - { - if( i==0 ) - { - - /* - * 1x1 matrix - */ - a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); - } - else - { - - /* - * (I+1)x(I+1) matrix, - * - * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) - * ( ) * ( ) = ( ) - * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) - * - * A11 is IxI, A22 is 1x1. - */ - ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs], 1, ae_v_len(0,i-1)); - for(j=0; j<=i-1; j++) - { - v = a->ptr.pp_double[offs+i][offs+j]; - ae_v_addd(&a->ptr.pp_double[offs+j][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+j), v); - } - v = a->ptr.pp_double[offs+i][offs+i]; - ae_v_muld(&a->ptr.pp_double[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); - a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * Recursive code: triangular factor inversion merged with - * UU' or L'L multiplication - */ - ablassplitlength(a, n, &n1, &n2, _state); - - /* - * form off-diagonal block of trangular inverse - */ - if( isupper ) - { - for(i=0; i<=n1-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); - rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); - } - else - { - for(i=0; i<=n2-1; i++) - { - ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); - rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); - } - - /* - * invert first diagonal block - */ - matinv_spdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, _state); - - /* - * update first diagonal block with off-diagonal block, - * update off-diagonal block - */ - if( isupper ) - { - rmatrixsyrk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); - rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs, offs+n1, _state); - } - else - { - rmatrixsyrk(n1, n2, 1.0, a, offs+n1, offs, 1, 1.0, a, offs, offs, isupper, _state); - rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs+n1, offs, _state); - } - - /* - * invert second diagonal block - */ - matinv_spdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Recursive subroutine for HPD inversion. - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_complex v; - ae_int_t n1; - ae_int_t n2; - ae_int_t info2; - matinvreport rep2; - - ae_frame_make(_state, &_frame_block); - _matinvreport_init(&rep2, _state, ae_true); - - if( n<1 ) - { - ae_frame_leave(_state); - return; - } - - /* - * Base case - */ - if( n<=ablascomplexblocksize(a, _state) ) - { - matinv_cmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, &info2, &rep2, _state); - if( isupper ) - { - - /* - * Compute the product U * U'. - * NOTE: we never assume that diagonal of U is real - */ - for(i=0; i<=n-1; i++) - { - if( i==0 ) - { - - /* - * 1x1 matrix - */ - a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); - } - else - { - - /* - * (I+1)x(I+1) matrix, - * - * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) - * ( ) * ( ) = ( ) - * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) - * - * A11 is IxI, A22 is 1x1. - */ - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+i], a->stride, "Conj", ae_v_len(0,i-1)); - for(j=0; j<=i-1; j++) - { - v = a->ptr.pp_complex[offs+j][offs+i]; - ae_v_caddc(&a->ptr.pp_complex[offs+j][offs+j], 1, &tmp->ptr.p_complex[j], 1, "N", ae_v_len(offs+j,offs+i-1), v); - } - v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); - ae_v_cmulc(&a->ptr.pp_complex[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); - a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); - } - } - } - else - { - - /* - * Compute the product L' * L - * NOTE: we never assume that diagonal of L is real - */ - for(i=0; i<=n-1; i++) - { - if( i==0 ) - { - - /* - * 1x1 matrix - */ - a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); - } - else - { - - /* - * (I+1)x(I+1) matrix, - * - * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) - * ( ) * ( ) = ( ) - * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) - * - * A11 is IxI, A22 is 1x1. - */ - ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs], 1, "N", ae_v_len(0,i-1)); - for(j=0; j<=i-1; j++) - { - v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+j], _state); - ae_v_caddc(&a->ptr.pp_complex[offs+j][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+j), v); - } - v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); - ae_v_cmulc(&a->ptr.pp_complex[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); - a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); - } - } - } - ae_frame_leave(_state); - return; - } - - /* - * Recursive code: triangular factor inversion merged with - * UU' or L'L multiplication - */ - ablascomplexsplitlength(a, n, &n1, &n2, _state); - - /* - * form off-diagonal block of trangular inverse - */ - if( isupper ) - { - for(i=0; i<=n1-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1); - } - cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); - cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); - } - else - { - for(i=0; i<=n2-1; i++) - { - ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1); - } - cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); - cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); - } - - /* - * invert first diagonal block - */ - matinv_hpdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, _state); - - /* - * update first diagonal block with off-diagonal block, - * update off-diagonal block - */ - if( isupper ) - { - cmatrixsyrk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); - cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs, offs+n1, _state); - } - else - { - cmatrixsyrk(n1, n2, 1.0, a, offs+n1, offs, 2, 1.0, a, offs, offs, isupper, _state); - cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs+n1, offs, _state); - } - - /* - * invert second diagonal block - */ - matinv_hpdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, _state); - ae_frame_leave(_state); -} - - -ae_bool _matinvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - matinvreport *p = (matinvreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _matinvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - matinvreport *dst = (matinvreport*)_dst; - matinvreport *src = (matinvreport*)_src; - dst->r1 = src->r1; - dst->rinf = src->rinf; - return ae_true; -} - - -void _matinvreport_clear(void* _p) -{ - matinvreport *p = (matinvreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _matinvreport_destroy(void* _p) -{ - matinvreport *p = (matinvreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -This function creates sparse matrix in a Hash-Table format. - -This function creates Hast-Table matrix, which can be converted to CRS -format after its initialization is over. Typical usage scenario for a -sparse matrix is: -1. creation in a Hash-Table format -2. insertion of the matrix elements -3. conversion to the CRS representation -4. matrix is passed to some linear algebra algorithm - -Some information about different matrix formats can be found below, in -the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - K - K>=0, expected number of non-zero elements in a matrix. - K can be inexact approximation, can be less than actual - number of elements (table will grow when needed) or - even zero). - It is important to understand that although hash-table - may grow automatically, it is better to provide good - estimate of data size. - -OUTPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - All elements of the matrix are zero. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreate(ae_int_t m, - ae_int_t n, - ae_int_t k, - sparsematrix* s, - ae_state *_state) -{ - ae_int_t i; - ae_int_t sz; - - _sparsematrix_clear(s); - - ae_assert(m>0, "SparseCreate: M<=0", _state); - ae_assert(n>0, "SparseCreate: N<=0", _state); - ae_assert(k>=0, "SparseCreate: K<0", _state); - sz = ae_round(k/sparse_desiredloadfactor+sparse_additional, _state); - s->matrixtype = 0; - s->m = m; - s->n = n; - s->nfree = sz; - ae_vector_set_length(&s->vals, sz, _state); - ae_vector_set_length(&s->idx, 2*sz, _state); - for(i=0; i<=sz-1; i++) - { - s->idx.ptr.p_int[2*i] = -1; - } -} - - -/************************************************************************* -This function creates sparse matrix in a CRS format (expert function for -situations when you are running out of memory). - -This function creates CRS matrix. Typical usage scenario for a CRS matrix -is: -1. creation (you have to tell number of non-zero elements at each row at - this moment) -2. insertion of the matrix elements (row by row, from left to right) -3. matrix is passed to some linear algebra algorithm - -This function is a memory-efficient alternative to SparseCreate(), but it -is more complex because it requires you to know in advance how large your -matrix is. Some information about different matrix formats can be found -below, in the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - NER - number of elements at each row, array[M], NER[I]>=0 - -OUTPUT PARAMETERS - S - sparse M*N matrix in CRS representation. - You have to fill ALL non-zero elements by calling - SparseSet() BEFORE you try to use this matrix. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreatecrs(ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* ner, - sparsematrix* s, - ae_state *_state) -{ - ae_int_t i; - ae_int_t noe; - - _sparsematrix_clear(s); - - ae_assert(m>0, "SparseCreateCRS: M<=0", _state); - ae_assert(n>0, "SparseCreateCRS: N<=0", _state); - ae_assert(ner->cnt>=m, "SparseCreateCRS: Length(NER)matrixtype = 1; - s->ninitialized = 0; - s->m = m; - s->n = n; - ae_vector_set_length(&s->ridx, s->m+1, _state); - s->ridx.ptr.p_int[0] = 0; - for(i=0; i<=s->m-1; i++) - { - ae_assert(ner->ptr.p_int[i]>=0, "SparseCreateCRS: NER[] contains negative elements", _state); - noe = noe+ner->ptr.p_int[i]; - s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+ner->ptr.p_int[i]; - } - ae_vector_set_length(&s->vals, noe, _state); - ae_vector_set_length(&s->idx, noe, _state); - if( noe==0 ) - { - sparse_sparseinitduidx(s, _state); - } -} - - -/************************************************************************* -This function copies S0 to S1. - -NOTE: this function does not verify its arguments, it just copies all -fields of the structure. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecopy(sparsematrix* s0, sparsematrix* s1, ae_state *_state) -{ - ae_int_t l; - ae_int_t i; - - _sparsematrix_clear(s1); - - s1->matrixtype = s0->matrixtype; - s1->m = s0->m; - s1->n = s0->n; - s1->nfree = s0->nfree; - s1->ninitialized = s0->ninitialized; - - /* - * Initialization for arrays - */ - l = s0->vals.cnt; - ae_vector_set_length(&s1->vals, l, _state); - for(i=0; i<=l-1; i++) - { - s1->vals.ptr.p_double[i] = s0->vals.ptr.p_double[i]; - } - l = s0->ridx.cnt; - ae_vector_set_length(&s1->ridx, l, _state); - for(i=0; i<=l-1; i++) - { - s1->ridx.ptr.p_int[i] = s0->ridx.ptr.p_int[i]; - } - l = s0->idx.cnt; - ae_vector_set_length(&s1->idx, l, _state); - for(i=0; i<=l-1; i++) - { - s1->idx.ptr.p_int[i] = s0->idx.ptr.p_int[i]; - } - - /* - * Initialization for CRS-parameters - */ - l = s0->uidx.cnt; - ae_vector_set_length(&s1->uidx, l, _state); - for(i=0; i<=l-1; i++) - { - s1->uidx.ptr.p_int[i] = s0->uidx.ptr.p_int[i]; - } - l = s0->didx.cnt; - ae_vector_set_length(&s1->didx, l, _state); - for(i=0; i<=l-1; i++) - { - s1->didx.ptr.p_int[i] = s0->didx.ptr.p_int[i]; - } -} - - -/************************************************************************* -This function adds value to S[i,j] - element of the sparse matrix. Matrix -must be in a Hash-Table mode. - -In case S[i,j] already exists in the table, V i added to its value. In -case S[i,j] is non-existent, it is inserted in the table. Table -automatically grows when necessary. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - row index of the element to modify, 0<=Imatrixtype==0, "SparseAdd: matrix must be in the Hash-Table mode to do this operation", _state); - ae_assert(i>=0, "SparseAdd: I<0", _state); - ae_assert(im, "SparseAdd: I>=M", _state); - ae_assert(j>=0, "SparseAdd: J<0", _state); - ae_assert(jn, "SparseAdd: J>=N", _state); - ae_assert(ae_isfinite(v, _state), "SparseAdd: V is not finite number", _state); - if( ae_fp_eq(v,0) ) - { - return; - } - tcode = -1; - k = s->vals.cnt; - if( ae_fp_greater_eq((1-sparse_maxloadfactor)*k,s->nfree) ) - { - sparseresizematrix(s, _state); - k = s->vals.cnt; - } - hashcode = sparse_hash(i, j, k, _state); - for(;;) - { - if( s->idx.ptr.p_int[2*hashcode]==-1 ) - { - if( tcode!=-1 ) - { - hashcode = tcode; - } - s->vals.ptr.p_double[hashcode] = v; - s->idx.ptr.p_int[2*hashcode] = i; - s->idx.ptr.p_int[2*hashcode+1] = j; - if( tcode==-1 ) - { - s->nfree = s->nfree-1; - } - return; - } - else - { - if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) - { - s->vals.ptr.p_double[hashcode] = s->vals.ptr.p_double[hashcode]+v; - if( ae_fp_eq(s->vals.ptr.p_double[hashcode],0) ) - { - s->idx.ptr.p_int[2*hashcode] = -2; - } - return; - } - - /* - * Is it deleted element? - */ - if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) - { - tcode = hashcode; - } - - /* - * Next step - */ - hashcode = (hashcode+1)%k; - } - } -} - - -/************************************************************************* -This function modifies S[i,j] - element of the sparse matrix. - -For Hash-based storage format: -* new value can be zero or non-zero. In case new value of S[i,j] is zero, - this element is deleted from the table. -* this function has no effect when called with zero V for non-existent - element. - -For CRS-bases storage format: -* new value MUST be non-zero. Exception will be thrown for zero V. -* elements must be initialized in correct order - from top row to bottom, - within row - from left to right. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - I - row index of the element to modify, 0<=I=0, "SparseSet: I<0", _state); - ae_assert(im, "SparseSet: I>=M", _state); - ae_assert(j>=0, "SparseSet: J<0", _state); - ae_assert(jn, "SparseSet: J>=N", _state); - ae_assert(ae_isfinite(v, _state), "SparseSet: V is not finite number", _state); - - /* - * Hash-table matrix - */ - if( s->matrixtype==0 ) - { - tcode = -1; - k = s->vals.cnt; - if( ae_fp_greater_eq((1-sparse_maxloadfactor)*k,s->nfree) ) - { - sparseresizematrix(s, _state); - k = s->vals.cnt; - } - hashcode = sparse_hash(i, j, k, _state); - for(;;) - { - if( s->idx.ptr.p_int[2*hashcode]==-1 ) - { - if( ae_fp_neq(v,0) ) - { - if( tcode!=-1 ) - { - hashcode = tcode; - } - s->vals.ptr.p_double[hashcode] = v; - s->idx.ptr.p_int[2*hashcode] = i; - s->idx.ptr.p_int[2*hashcode+1] = j; - if( tcode==-1 ) - { - s->nfree = s->nfree-1; - } - } - return; - } - else - { - if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) - { - if( ae_fp_eq(v,0) ) - { - s->idx.ptr.p_int[2*hashcode] = -2; - } - else - { - s->vals.ptr.p_double[hashcode] = v; - } - return; - } - if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) - { - tcode = hashcode; - } - - /* - * Next step - */ - hashcode = (hashcode+1)%k; - } - } - } - - /* - * CRS matrix - */ - if( s->matrixtype==1 ) - { - ae_assert(ae_fp_neq(v,0), "SparseSet: CRS format does not allow you to write zero elements", _state); - ae_assert(s->ridx.ptr.p_int[i]<=s->ninitialized, "SparseSet: too few initialized elements at some row (you have promised more when called SparceCreateCRS)", _state); - ae_assert(s->ridx.ptr.p_int[i+1]>s->ninitialized, "SparseSet: too many initialized elements at some row (you have promised less when called SparceCreateCRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[i]||s->idx.ptr.p_int[s->ninitialized-1]vals.ptr.p_double[s->ninitialized] = v; - s->idx.ptr.p_int[s->ninitialized] = j; - s->ninitialized = s->ninitialized+1; - - /* - * If matrix has been created then - * initiale 'S.UIdx' and 'S.DIdx' - */ - if( s->ninitialized==s->ridx.ptr.p_int[s->m] ) - { - sparse_sparseinitduidx(s, _state); - } - } -} - - -/************************************************************************* -This function returns S[i,j] - element of the sparse matrix. Matrix can -be in any mode (Hash-Table or CRS), but this function is less efficient -for CRS matrices. Hash-Table matrices can find element in O(1) time, -while CRS matrices need O(log(RS)) time, where RS is an number of non- -zero elements in a row. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - row index of the element to modify, 0<=I=0, "SparseGet: I<0", _state); - ae_assert(im, "SparseGet: I>=M", _state); - ae_assert(j>=0, "SparseGet: J<0", _state); - ae_assert(jn, "SparseGet: J>=N", _state); - k = s->vals.cnt; - result = 0; - if( s->matrixtype==0 ) - { - hashcode = sparse_hash(i, j, k, _state); - for(;;) - { - if( s->idx.ptr.p_int[2*hashcode]==-1 ) - { - return result; - } - if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) - { - result = s->vals.ptr.p_double[hashcode]; - return result; - } - hashcode = (hashcode+1)%k; - } - } - if( s->matrixtype==1 ) - { - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGet: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - k0 = s->ridx.ptr.p_int[i]; - k1 = s->ridx.ptr.p_int[i+1]-1; - while(k0<=k1) - { - k = (k0+k1)/2; - if( s->idx.ptr.p_int[k]==j ) - { - result = s->vals.ptr.p_double[k]; - return result; - } - if( s->idx.ptr.p_int[k]=0, "SparseGetDiagonal: I<0", _state); - ae_assert(im, "SparseGetDiagonal: I>=M", _state); - ae_assert(in, "SparseGetDiagonal: I>=N", _state); - result = 0; - if( s->matrixtype==0 ) - { - result = sparseget(s, i, i, _state); - return result; - } - if( s->matrixtype==1 ) - { - if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) - { - result = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; - } - return result; - } - return result; -} - - -/************************************************************************* -This function converts matrix to CRS format. - -Some algorithms (linear algebra ones, for example) require matrices in -CRS format. - -INPUT PARAMETERS - S - sparse M*N matrix in any format - -OUTPUT PARAMETERS - S - matrix in CRS format - -NOTE: this function has no effect when called with matrix which is -already in CRS mode. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparseconverttocrs(sparsematrix* s, ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_vector tvals; - ae_vector tidx; - ae_vector temp; - ae_int_t nonne; - ae_int_t k; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); - ae_vector_init(&temp, 0, DT_INT, _state, ae_true); - - ae_assert(s->matrixtype==0||s->matrixtype==1, "SparseConvertToCRS: invalid matrix type", _state); - if( s->matrixtype==1 ) - { - ae_frame_leave(_state); - return; - } - s->matrixtype = 1; - nonne = 0; - k = s->vals.cnt; - ae_swap_vectors(&s->vals, &tvals); - ae_swap_vectors(&s->idx, &tidx); - ae_vector_set_length(&s->ridx, s->m+1, _state); - for(i=0; i<=s->m; i++) - { - s->ridx.ptr.p_int[i] = 0; - } - ae_vector_set_length(&temp, s->m, _state); - for(i=0; i<=s->m-1; i++) - { - temp.ptr.p_int[i] = 0; - } - - /* - * Number of elements per row - */ - for(i=0; i<=k-1; i++) - { - if( tidx.ptr.p_int[2*i]>=0 ) - { - s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1] = s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]+1]+1; - nonne = nonne+1; - } - } - - /* - * Fill RIdx (offsets of rows) - */ - for(i=0; i<=s->m-1; i++) - { - s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; - } - - /* - * Allocate memory - */ - ae_vector_set_length(&s->vals, nonne, _state); - ae_vector_set_length(&s->idx, nonne, _state); - for(i=0; i<=k-1; i++) - { - if( tidx.ptr.p_int[2*i]>=0 ) - { - s->vals.ptr.p_double[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tvals.ptr.p_double[i]; - s->idx.ptr.p_int[s->ridx.ptr.p_int[tidx.ptr.p_int[2*i]]+temp.ptr.p_int[tidx.ptr.p_int[2*i]]] = tidx.ptr.p_int[2*i+1]; - temp.ptr.p_int[tidx.ptr.p_int[2*i]] = temp.ptr.p_int[tidx.ptr.p_int[2*i]]+1; - } - } - - /* - * Set NInitialized - */ - s->ninitialized = s->ridx.ptr.p_int[s->m]; - - /* - * Sorting of elements - */ - for(i=0; i<=s->m-1; i++) - { - tagsortmiddleir(&s->idx, &s->vals, s->ridx.ptr.p_int[i], s->ridx.ptr.p_int[i+1]-s->ridx.ptr.p_int[i], _state); - } - - /* - * Initialization 'S.UIdx' and 'S.DIdx' - */ - sparse_sparseinitduidx(s, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This function calculates matrix-vector product S*x. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[M], S*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemv(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - double tval; - ae_int_t i; - ae_int_t j; - ae_int_t lt; - ae_int_t rt; - - - ae_assert(s->matrixtype==1, "SparseMV: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(x->cnt>=s->n, "SparseMV: length(X)m, _state); - for(i=0; i<=s->m-1; i++) - { - tval = 0; - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - tval = tval+x->ptr.p_double[s->idx.ptr.p_int[j]]*s->vals.ptr.p_double[j]; - } - y->ptr.p_double[i] = tval; - } -} - - -/************************************************************************* -This function calculates matrix-vector product S^T*x. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[M], input vector. For performance reasons we - make only quick checks - we check that array size is - at least M, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[N], S^T*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemtv(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t lt; - ae_int_t rt; - ae_int_t ct; - double v; - - - ae_assert(s->matrixtype==1, "SparseMTV: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMTV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(x->cnt>=s->m, "SparseMTV: Length(X)n, _state); - for(i=0; i<=s->n-1; i++) - { - y->ptr.p_double[i] = 0; - } - for(i=0; i<=s->m-1; i++) - { - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - v = x->ptr.p_double[i]; - for(j=lt; j<=rt-1; j++) - { - ct = s->idx.ptr.p_int[j]; - y->ptr.p_double[ct] = y->ptr.p_double[ct]+v*s->vals.ptr.p_double[j]; - } - } -} - - -/************************************************************************* -This function simultaneously calculates two matrix-vector products: - S*x and S^T*x. -S must be square (non-rectangular) matrix stored in CRS format (exception -will be thrown otherwise). - -INPUT PARAMETERS - S - sparse N*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y0 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - Y1 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y0 - array[N], S*x - Y1 - array[N], S^T*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. It also throws exception when S is non-square. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemv2(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y0, - /* Real */ ae_vector* y1, - ae_state *_state) -{ - ae_int_t l; - double tval; - ae_int_t i; - ae_int_t j; - double vx; - double vs; - ae_int_t vi; - ae_int_t j0; - ae_int_t j1; - - - ae_assert(s->matrixtype==1, "SparseMV2: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(s->m==s->n, "SparseMV2: matrix is non-square", _state); - l = x->cnt; - ae_assert(l>=s->n, "SparseMV2: Length(X)n-1; i++) - { - y1->ptr.p_double[i] = 0; - } - for(i=0; i<=s->m-1; i++) - { - tval = 0; - vx = x->ptr.p_double[i]; - j0 = s->ridx.ptr.p_int[i]; - j1 = s->ridx.ptr.p_int[i+1]-1; - for(j=j0; j<=j1; j++) - { - vi = s->idx.ptr.p_int[j]; - vs = s->vals.ptr.p_double[j]; - tval = tval+x->ptr.p_double[vi]*vs; - y1->ptr.p_double[vi] = y1->ptr.p_double[vi]+vx*vs; - } - y0->ptr.p_double[i] = tval; - } -} - - -/************************************************************************* -This function calculates matrix-vector product S*x, when S is symmetric -matrix. Matrix S must be stored in CRS format (exception will be -thrown otherwise). - -INPUT PARAMETERS - S - sparse M*M matrix in CRS format (you MUST convert it - to CRS before calling this function). - IsUpper - whether upper or lower triangle of S is given: - * if upper triangle is given, only S[i,j] for j>=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[M], S*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmv(sparsematrix* s, - ae_bool isupper, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t id; - ae_int_t lt; - ae_int_t rt; - double v; - double vy; - double vx; - - - ae_assert(s->matrixtype==1, "SparseSMV: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(x->cnt>=s->n, "SparseSMV: length(X)m==s->n, "SparseSMV: non-square matrix", _state); - rvectorsetlengthatleast(y, s->m, _state); - for(i=0; i<=s->m-1; i++) - { - y->ptr.p_double[i] = 0; - } - for(i=0; i<=s->m-1; i++) - { - if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) - { - y->ptr.p_double[i] = y->ptr.p_double[i]+s->vals.ptr.p_double[s->didx.ptr.p_int[i]]*x->ptr.p_double[s->idx.ptr.p_int[s->didx.ptr.p_int[i]]]; - } - if( isupper ) - { - lt = s->uidx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - vy = 0; - vx = x->ptr.p_double[i]; - for(j=lt; j<=rt-1; j++) - { - id = s->idx.ptr.p_int[j]; - v = s->vals.ptr.p_double[j]; - vy = vy+x->ptr.p_double[id]*v; - y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; - } - y->ptr.p_double[i] = y->ptr.p_double[i]+vy; - } - else - { - lt = s->ridx.ptr.p_int[i]; - rt = s->didx.ptr.p_int[i]; - vy = 0; - vx = x->ptr.p_double[i]; - for(j=lt; j<=rt-1; j++) - { - id = s->idx.ptr.p_int[j]; - v = s->vals.ptr.p_double[j]; - vy = vy+x->ptr.p_double[id]*v; - y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; - } - y->ptr.p_double[i] = y->ptr.p_double[i]+vy; - } - } -} - - -/************************************************************************* -This function calculates matrix-matrix product S*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size - is at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state) -{ - double tval; - double v; - ae_int_t id; - ae_int_t i; - ae_int_t j; - ae_int_t k0; - ae_int_t lt; - ae_int_t rt; - - - ae_assert(s->matrixtype==1, "SparseMV: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(a->rows>=s->n, "SparseMV: Rows(A)0, "SparseMV: K<=0", _state); - rmatrixsetlengthatleast(b, s->m, k, _state); - if( km-1; i++) - { - for(j=0; j<=k-1; j++) - { - tval = 0; - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(k0=lt; k0<=rt-1; k0++) - { - tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[s->idx.ptr.p_int[k0]][j]; - } - b->ptr.pp_double[i][j] = tval; - } - } - } - else - { - for(i=0; i<=s->m-1; i++) - { - for(j=0; j<=k-1; j++) - { - b->ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=s->m-1; i++) - { - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - id = s->idx.ptr.p_int[j]; - v = s->vals.ptr.p_double[j]; - ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); - } - } - } -} - - -/************************************************************************* -This function calculates matrix-matrix product S^T*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[M][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least M, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemtm(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k0; - ae_int_t lt; - ae_int_t rt; - ae_int_t ct; - double v; - - - ae_assert(s->matrixtype==1, "SparseMTM: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMTM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(a->rows>=s->m, "SparseMTM: Rows(A)0, "SparseMTM: K<=0", _state); - rmatrixsetlengthatleast(b, s->n, k, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=k-1; j++) - { - b->ptr.pp_double[i][j] = 0; - } - } - if( km-1; i++) - { - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(k0=lt; k0<=rt-1; k0++) - { - v = s->vals.ptr.p_double[k0]; - ct = s->idx.ptr.p_int[k0]; - for(j=0; j<=k-1; j++) - { - b->ptr.pp_double[ct][j] = b->ptr.pp_double[ct][j]+v*a->ptr.pp_double[i][j]; - } - } - } - } - else - { - for(i=0; i<=s->m-1; i++) - { - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - v = s->vals.ptr.p_double[j]; - ct = s->idx.ptr.p_int[j]; - ae_v_addd(&b->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); - } - } - } -} - - -/************************************************************************* -This function simultaneously calculates two matrix-matrix products: - S*A and S^T*A. -S must be square (non-rectangular) matrix stored in CRS format (exception -will be thrown otherwise). - -INPUT PARAMETERS - S - sparse N*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B0 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - B1 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B0 - array[N][K], S*A - B1 - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. It also throws exception when S is non-square. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm2(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b0, - /* Real */ ae_matrix* b1, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k0; - ae_int_t lt; - ae_int_t rt; - ae_int_t ct; - double v; - double tval; - - - ae_assert(s->matrixtype==1, "SparseMM2: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMM2: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(s->m==s->n, "SparseMM2: matrix is non-square", _state); - ae_assert(a->rows>=s->n, "SparseMM2: Rows(A)0, "SparseMM2: K<=0", _state); - rmatrixsetlengthatleast(b0, s->m, k, _state); - rmatrixsetlengthatleast(b1, s->n, k, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=0; j<=k-1; j++) - { - b1->ptr.pp_double[i][j] = 0; - } - } - if( km-1; i++) - { - for(j=0; j<=k-1; j++) - { - tval = 0; - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - v = a->ptr.pp_double[i][j]; - for(k0=lt; k0<=rt-1; k0++) - { - ct = s->idx.ptr.p_int[k0]; - b1->ptr.pp_double[ct][j] = b1->ptr.pp_double[ct][j]+s->vals.ptr.p_double[k0]*v; - tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[ct][j]; - } - b0->ptr.pp_double[i][j] = tval; - } - } - } - else - { - for(i=0; i<=s->m-1; i++) - { - for(j=0; j<=k-1; j++) - { - b0->ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=s->m-1; i++) - { - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - v = s->vals.ptr.p_double[j]; - ct = s->idx.ptr.p_int[j]; - ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[ct][0], 1, ae_v_len(0,k-1), v); - ae_v_addd(&b1->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); - } - } - } -} - - -/************************************************************************* -This function calculates matrix-matrix product S*A, when S is symmetric -matrix. Matrix S must be stored in CRS format (exception will be -thrown otherwise). - -INPUT PARAMETERS - S - sparse M*M matrix in CRS format (you MUST convert it - to CRS before calling this function). - IsUpper - whether upper or lower triangle of S is given: - * if upper triangle is given, only S[i,j] for j>=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmm(sparsematrix* s, - ae_bool isupper, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t k0; - ae_int_t id; - ae_int_t lt; - ae_int_t rt; - double v; - double vb; - double va; - - - ae_assert(s->matrixtype==1, "SparseSMM: incorrect matrix type (convert your matrix to CRS)", _state); - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - ae_assert(a->rows>=s->n, "SparseSMM: Rows(X)m==s->n, "SparseSMM: matrix is non-square", _state); - rmatrixsetlengthatleast(b, s->m, k, _state); - for(i=0; i<=s->m-1; i++) - { - for(j=0; j<=k-1; j++) - { - b->ptr.pp_double[i][j] = 0; - } - } - if( k>sparse_linalgswitch ) - { - for(i=0; i<=s->m-1; i++) - { - for(j=0; j<=k-1; j++) - { - if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) - { - id = s->didx.ptr.p_int[i]; - b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+s->vals.ptr.p_double[id]*a->ptr.pp_double[s->idx.ptr.p_int[id]][j]; - } - if( isupper ) - { - lt = s->uidx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - vb = 0; - va = a->ptr.pp_double[i][j]; - for(k0=lt; k0<=rt-1; k0++) - { - id = s->idx.ptr.p_int[k0]; - v = s->vals.ptr.p_double[k0]; - vb = vb+a->ptr.pp_double[id][j]*v; - b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; - } - b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; - } - else - { - lt = s->ridx.ptr.p_int[i]; - rt = s->didx.ptr.p_int[i]; - vb = 0; - va = a->ptr.pp_double[i][j]; - for(k0=lt; k0<=rt-1; k0++) - { - id = s->idx.ptr.p_int[k0]; - v = s->vals.ptr.p_double[k0]; - vb = vb+a->ptr.pp_double[id][j]*v; - b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; - } - b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; - } - } - } - } - else - { - for(i=0; i<=s->m-1; i++) - { - if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) - { - id = s->didx.ptr.p_int[i]; - v = s->vals.ptr.p_double[id]; - ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[s->idx.ptr.p_int[id]][0], 1, ae_v_len(0,k-1), v); - } - if( isupper ) - { - lt = s->uidx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - id = s->idx.ptr.p_int[j]; - v = s->vals.ptr.p_double[j]; - ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); - ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); - } - } - else - { - lt = s->ridx.ptr.p_int[i]; - rt = s->didx.ptr.p_int[i]; - for(j=lt; j<=rt-1; j++) - { - id = s->idx.ptr.p_int[j]; - v = s->vals.ptr.p_double[j]; - ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); - ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); - } - } - } - } -} - - -/************************************************************************* -This procedure resizes Hash-Table matrix. It can be called when you have -deleted too many elements from the matrix, and you want to free unneeded -memory. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparseresizematrix(sparsematrix* s, ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t k; - ae_int_t k1; - ae_int_t i; - ae_vector tvals; - ae_vector tidx; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); - - ae_assert(s->matrixtype==0, "SparseResizeMatrix: incorrect matrix type", _state); - - /* - * Initialization for length and number of non-null elementd - */ - k = s->vals.cnt; - k1 = 0; - - /* - * Calculating number of non-null elements - */ - for(i=0; i<=k-1; i++) - { - if( s->idx.ptr.p_int[2*i]>=0 ) - { - k1 = k1+1; - } - } - - /* - * Initialization value for free space - */ - s->nfree = ae_round(k1/sparse_desiredloadfactor*sparse_growfactor+sparse_additional, _state)-k1; - ae_vector_set_length(&tvals, s->nfree+k1, _state); - ae_vector_set_length(&tidx, 2*(s->nfree+k1), _state); - ae_swap_vectors(&s->vals, &tvals); - ae_swap_vectors(&s->idx, &tidx); - for(i=0; i<=s->nfree+k1-1; i++) - { - s->idx.ptr.p_int[2*i] = -1; - } - for(i=0; i<=k-1; i++) - { - if( tidx.ptr.p_int[2*i]>=0 ) - { - sparseset(s, tidx.ptr.p_int[2*i], tidx.ptr.p_int[2*i+1], tvals.ptr.p_double[i], _state); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function return average length of chain at hash-table. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -double sparsegetaveragelengthofchain(sparsematrix* s, ae_state *_state) -{ - ae_int_t nchains; - ae_int_t talc; - ae_int_t l; - ae_int_t i; - ae_int_t ind0; - ae_int_t ind1; - ae_int_t hashcode; - double result; - - - - /* - * If matrix represent in CRS then return zero and exit - */ - if( s->matrixtype==1 ) - { - result = 0; - return result; - } - nchains = 0; - talc = 0; - l = s->vals.cnt; - for(i=0; i<=l-1; i++) - { - ind0 = 2*i; - if( s->idx.ptr.p_int[ind0]!=-1 ) - { - nchains = nchains+1; - hashcode = sparse_hash(s->idx.ptr.p_int[ind0], s->idx.ptr.p_int[ind0+1], l, _state); - for(;;) - { - talc = talc+1; - ind1 = 2*hashcode; - if( s->idx.ptr.p_int[ind0]==s->idx.ptr.p_int[ind1]&&s->idx.ptr.p_int[ind0+1]==s->idx.ptr.p_int[ind1+1] ) - { - break; - } - hashcode = (hashcode+1)%l; - } - } - } - if( nchains==0 ) - { - result = 0; - } - else - { - result = (double)talc/(double)nchains; - } - return result; -} - - -/************************************************************************* -This function is used to enumerate all elements of the sparse matrix. -Before first call user initializes T0 and T1 counters by zero. These -counters are used to remember current position in a matrix; after each -call they are updated by the function. - -Subsequent calls to this function return non-zero elements of the sparse -matrix, one by one. If you enumerate CRS matrix, matrix is traversed from -left to right, from top to bottom. In case you enumerate matrix stored as -Hash table, elements are returned in random order. - -EXAMPLE - > T0=0 - > T1=0 - > while SparseEnumerate(S,T0,T1,I,J,V) do - > ....do something with I,J,V - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - T0 - internal counter - T1 - internal counter - -OUTPUT PARAMETERS - T0 - new value of the internal counter - T1 - new value of the internal counter - I - row index of non-zero element, 0<=Imatrixtype==1&&*t1<0) ) - { - result = ae_false; - return result; - } - - /* - * Hash-table matrix - */ - if( s->matrixtype==0 ) - { - sz = s->vals.cnt; - for(i0=*t0; i0<=sz-1; i0++) - { - if( s->idx.ptr.p_int[2*i0]==-1||s->idx.ptr.p_int[2*i0]==-2 ) - { - continue; - } - else - { - *i = s->idx.ptr.p_int[2*i0]; - *j = s->idx.ptr.p_int[2*i0+1]; - *v = s->vals.ptr.p_double[i0]; - *t0 = i0+1; - result = ae_true; - return result; - } - } - *t0 = 0; - result = ae_false; - return result; - } - - /* - * CRS matrix - */ - if( s->matrixtype==1&&*t0ninitialized ) - { - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseEnumerate: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - while(*t0>s->ridx.ptr.p_int[*t1+1]-1&&*t1m) - { - *t1 = *t1+1; - } - *i = *t1; - *j = s->idx.ptr.p_int[*t0]; - *v = s->vals.ptr.p_double[*t0]; - *t0 = *t0+1; - result = ae_true; - return result; - } - *t0 = 0; - *t1 = 0; - result = ae_false; - return result; -} - - -/************************************************************************* -This function rewrites existing (non-zero) element. It returns True if -element exists or False, when it is called for non-existing (zero) -element. - -The purpose of this function is to provide convenient thread-safe way to -modify sparse matrix. Such modification (already existing element is -rewritten) is guaranteed to be thread-safe without any synchronization, as -long as different threads modify different elements. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - I - row index of non-zero element to modify, 0<=Im, "SparseRewriteExisting: invalid argument I(either I<0 or I>=S.M)", _state); - ae_assert(0<=j&&jn, "SparseRewriteExisting: invalid argument J(either J<0 or J>=S.N)", _state); - ae_assert(ae_isfinite(v, _state), "SparseRewriteExisting: invalid argument V(either V is infinite or V is NaN)", _state); - result = ae_false; - - /* - * Hash-table matrix - */ - if( s->matrixtype==0 ) - { - k = s->vals.cnt; - hashcode = sparse_hash(i, j, k, _state); - for(;;) - { - if( s->idx.ptr.p_int[2*hashcode]==-1 ) - { - return result; - } - if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) - { - s->vals.ptr.p_double[hashcode] = v; - result = ae_true; - return result; - } - hashcode = (hashcode+1)%k; - } - } - - /* - * CRS matrix - */ - if( s->matrixtype==1 ) - { - ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseRewriteExisting: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); - k0 = s->ridx.ptr.p_int[i]; - k1 = s->ridx.ptr.p_int[i+1]-1; - while(k0<=k1) - { - k = (k0+k1)/2; - if( s->idx.ptr.p_int[k]==j ) - { - s->vals.ptr.p_double[k] = v; - result = ae_true; - return result; - } - if( s->idx.ptr.p_int[k]matrixtype==1, "SparseGetRow: S must be CRS-based matrix", _state); - ae_assert(i>=0&&im, "SparseGetRow: I<0 or I>=M", _state); - rvectorsetlengthatleast(irow, s->n, _state); - for(i0=0; i0<=s->n-1; i0++) - { - irow->ptr.p_double[i0] = 0; - } - for(i0=s->ridx.ptr.p_int[i]; i0<=s->ridx.ptr.p_int[i+1]-1; i0++) - { - irow->ptr.p_double[s->idx.ptr.p_int[i0]] = s->vals.ptr.p_double[i0]; - } -} - - -/************************************************************************* -This function performs in-place conversion from CRS format to Hash table -storage. - -INPUT PARAMETERS - S - sparse matrix in CRS format. - -OUTPUT PARAMETERS - S - sparse matrix in Hash table format. - -NOTE: this function has no effect when called with matrix which is -already in Hash table mode. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparseconverttohash(sparsematrix* s, ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tidx; - ae_vector tridx; - ae_vector tvals; - ae_int_t tn; - ae_int_t tm; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); - ae_vector_init(&tridx, 0, DT_INT, _state, ae_true); - ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); - - ae_assert(s->matrixtype==0||s->matrixtype==1, "SparseConvertToHash: invalid matrix type", _state); - if( s->matrixtype==0 ) - { - ae_frame_leave(_state); - return; - } - s->matrixtype = 0; - tm = s->m; - tn = s->n; - ae_swap_vectors(&s->idx, &tidx); - ae_swap_vectors(&s->ridx, &tridx); - ae_swap_vectors(&s->vals, &tvals); - - /* - * Delete RIdx - */ - ae_vector_set_length(&s->ridx, 0, _state); - sparsecreate(tm, tn, tridx.ptr.p_int[tm], s, _state); - - /* - * Fill the matrix - */ - for(i=0; i<=tm-1; i++) - { - for(j=tridx.ptr.p_int[i]; j<=tridx.ptr.p_int[i+1]-1; j++) - { - sparseset(s, i, tidx.ptr.p_int[j], tvals.ptr.p_double[j], _state); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function performs out-of-place conversion to Hash table storage -format. S0 is copied to S1 and converted on-the-fly. - -INPUT PARAMETERS - S0 - sparse matrix in any format. - -OUTPUT PARAMETERS - S1 - sparse matrix in Hash table format. - -NOTE: if S0 is stored as Hash-table, it is just copied without conversion. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsecopytohash(sparsematrix* s0, - sparsematrix* s1, - ae_state *_state) -{ - double val; - ae_int_t t0; - ae_int_t t1; - ae_int_t i; - ae_int_t j; - - _sparsematrix_clear(s1); - - ae_assert(s0->matrixtype==0||s0->matrixtype==1, "SparseCopyToHash: invalid matrix type", _state); - if( s0->matrixtype==0 ) - { - sparsecopy(s0, s1, _state); - } - else - { - t0 = 0; - t1 = 0; - sparsecreate(s0->m, s0->n, s0->ridx.ptr.p_int[s0->m], s1, _state); - while(sparseenumerate(s0, &t0, &t1, &i, &j, &val, _state)) - { - sparseset(s1, i, j, val, _state); - } - } -} - - -/************************************************************************* -This function performs out-of-place conversion to CRS format. S0 is -copied to S1 and converted on-the-fly. - -INPUT PARAMETERS - S0 - sparse matrix in any format. - -OUTPUT PARAMETERS - S1 - sparse matrix in CRS format. - -NOTE: if S0 is stored as CRS, it is just copied without conversion. - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsecopytocrs(sparsematrix* s0, sparsematrix* s1, ae_state *_state) -{ - ae_frame _frame_block; - ae_vector temp; - ae_int_t nonne; - ae_int_t i; - ae_int_t k; - - ae_frame_make(_state, &_frame_block); - _sparsematrix_clear(s1); - ae_vector_init(&temp, 0, DT_INT, _state, ae_true); - - ae_assert(s0->matrixtype==0||s0->matrixtype==1, "SparseCopyToCRS: invalid matrix type", _state); - if( s0->matrixtype==1 ) - { - sparsecopy(s0, s1, _state); - } - else - { - - /* - * Done like ConvertToCRS function - */ - s1->matrixtype = 1; - s1->m = s0->m; - s1->n = s0->n; - s1->nfree = s0->nfree; - nonne = 0; - k = s0->vals.cnt; - ae_vector_set_length(&s1->ridx, s1->m+1, _state); - for(i=0; i<=s1->m; i++) - { - s1->ridx.ptr.p_int[i] = 0; - } - ae_vector_set_length(&temp, s1->m, _state); - for(i=0; i<=s1->m-1; i++) - { - temp.ptr.p_int[i] = 0; - } - - /* - * Number of elements per row - */ - for(i=0; i<=k-1; i++) - { - if( s0->idx.ptr.p_int[2*i]>=0 ) - { - s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1] = s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]+1]+1; - nonne = nonne+1; - } - } - - /* - * Fill RIdx (offsets of rows) - */ - for(i=0; i<=s1->m-1; i++) - { - s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; - } - - /* - * Allocate memory - */ - ae_vector_set_length(&s1->vals, nonne, _state); - ae_vector_set_length(&s1->idx, nonne, _state); - for(i=0; i<=k-1; i++) - { - if( s0->idx.ptr.p_int[2*i]>=0 ) - { - s1->vals.ptr.p_double[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->vals.ptr.p_double[i]; - s1->idx.ptr.p_int[s1->ridx.ptr.p_int[s0->idx.ptr.p_int[2*i]]+temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]] = s0->idx.ptr.p_int[2*i+1]; - temp.ptr.p_int[s0->idx.ptr.p_int[2*i]] = temp.ptr.p_int[s0->idx.ptr.p_int[2*i]]+1; - } - } - - /* - * Set NInitialized - */ - s1->ninitialized = s1->ridx.ptr.p_int[s1->m]; - - /* - * Sorting of elements - */ - for(i=0; i<=s1->m-1; i++) - { - tagsortmiddleir(&s1->idx, &s1->vals, s1->ridx.ptr.p_int[i], s1->ridx.ptr.p_int[i+1]-s1->ridx.ptr.p_int[i], _state); - } - - /* - * Initialization 'S.UIdx' and 'S.DIdx' - */ - sparse_sparseinitduidx(s1, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function returns type of the matrix storage format. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - sparse storage format used by matrix: - 0 - Hash-table - 1 - CRS-format - -NOTE: future versions of ALGLIB may include additional sparse storage - formats. - - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetmatrixtype(sparsematrix* s, ae_state *_state) -{ - ae_int_t result; - - - ae_assert(s->matrixtype==0||s->matrixtype==1, "SparseGetMatrixType: invalid matrix type", _state); - result = s->matrixtype; - return result; -} - - -/************************************************************************* -This function checks matrix storage format and returns True when matrix is -stored using Hash table representation. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - True if matrix type is Hash table - False if matrix type is not Hash table - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool sparseishash(sparsematrix* s, ae_state *_state) -{ - ae_bool result; - - - ae_assert(s->matrixtype==0||s->matrixtype==1, "SparseIsHash: invalid matrix type", _state); - result = s->matrixtype==0; - return result; -} - - -/************************************************************************* -This function checks matrix storage format and returns True when matrix is -stored using CRS representation. - -INPUT PARAMETERS: - S - sparse matrix. - -RESULT: - True if matrix type is CRS - False if matrix type is not CRS - - -- ALGLIB PROJECT -- - Copyright 20.07.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool sparseiscrs(sparsematrix* s, ae_state *_state) -{ - ae_bool result; - - - ae_assert(s->matrixtype==0||s->matrixtype==1, "SparseIsCRS: invalid matrix type", _state); - result = s->matrixtype==1; - return result; -} - - -/************************************************************************* -The function frees all memory occupied by sparse matrix. Sparse matrix -structure becomes unusable after this call. - -OUTPUT PARAMETERS - S - sparse matrix to delete - - -- ALGLIB PROJECT -- - Copyright 24.07.2012 by Bochkanov Sergey -*************************************************************************/ -void sparsefree(sparsematrix* s, ae_state *_state) -{ - - _sparsematrix_clear(s); - - s->matrixtype = -1; - s->m = 0; - s->n = 0; - s->nfree = 0; - s->ninitialized = 0; -} - - -/************************************************************************* -The function returns number of rows of a sparse matrix. - -RESULT: number of rows of a sparse matrix. - - -- ALGLIB PROJECT -- - Copyright 23.08.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetnrows(sparsematrix* s, ae_state *_state) -{ - ae_int_t result; - - - result = s->m; - return result; -} - - -/************************************************************************* -The function returns number of columns of a sparse matrix. - -RESULT: number of columns of a sparse matrix. - - -- ALGLIB PROJECT -- - Copyright 23.08.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sparsegetncols(sparsematrix* s, ae_state *_state) -{ - ae_int_t result; - - - result = s->n; - return result; -} - - -/************************************************************************* -Procedure for initialization 'S.DIdx' and 'S.UIdx' - - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -static void sparse_sparseinitduidx(sparsematrix* s, ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t lt; - ae_int_t rt; - - - ae_vector_set_length(&s->didx, s->m, _state); - ae_vector_set_length(&s->uidx, s->m, _state); - for(i=0; i<=s->m-1; i++) - { - s->uidx.ptr.p_int[i] = -1; - s->didx.ptr.p_int[i] = -1; - lt = s->ridx.ptr.p_int[i]; - rt = s->ridx.ptr.p_int[i+1]; - for(j=lt; j<=rt-1; j++) - { - if( iidx.ptr.p_int[j]&&s->uidx.ptr.p_int[i]==-1 ) - { - s->uidx.ptr.p_int[i] = j; - break; - } - else - { - if( i==s->idx.ptr.p_int[j] ) - { - s->didx.ptr.p_int[i] = j; - } - } - } - if( s->uidx.ptr.p_int[i]==-1 ) - { - s->uidx.ptr.p_int[i] = s->ridx.ptr.p_int[i+1]; - } - if( s->didx.ptr.p_int[i]==-1 ) - { - s->didx.ptr.p_int[i] = s->uidx.ptr.p_int[i]; - } - } -} - - -/************************************************************************* -This is hash function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -static ae_int_t sparse_hash(ae_int_t i, - ae_int_t j, - ae_int_t tabsize, - ae_state *_state) -{ - ae_frame _frame_block; - hqrndstate r; - ae_int_t result; - - ae_frame_make(_state, &_frame_block); - _hqrndstate_init(&r, _state, ae_true); - - hqrndseed(i, j, &r, _state); - result = hqrnduniformi(&r, tabsize, _state); - ae_frame_leave(_state); - return result; -} - - -ae_bool _sparsematrix_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sparsematrix *p = (sparsematrix*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->vals, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ridx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->didx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->uidx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _sparsematrix_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sparsematrix *dst = (sparsematrix*)_dst; - sparsematrix *src = (sparsematrix*)_src; - if( !ae_vector_init_copy(&dst->vals, &src->vals, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ridx, &src->ridx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->didx, &src->didx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->uidx, &src->uidx, _state, make_automatic) ) - return ae_false; - dst->matrixtype = src->matrixtype; - dst->m = src->m; - dst->n = src->n; - dst->nfree = src->nfree; - dst->ninitialized = src->ninitialized; - return ae_true; -} - - -void _sparsematrix_clear(void* _p) -{ - sparsematrix *p = (sparsematrix*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->vals); - ae_vector_clear(&p->idx); - ae_vector_clear(&p->ridx); - ae_vector_clear(&p->didx); - ae_vector_clear(&p->uidx); -} - - -void _sparsematrix_destroy(void* _p) -{ - sparsematrix *p = (sparsematrix*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->vals); - ae_vector_destroy(&p->idx); - ae_vector_destroy(&p->ridx); - ae_vector_destroy(&p->didx); - ae_vector_destroy(&p->uidx); -} - - - - -/************************************************************************* -Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. - -This subroutine assumes that: -* A*ScaleA is well scaled -* A is well-conditioned, so no zero divisions or overflow may occur - -INPUT PARAMETERS: - CHA - Cholesky decomposition of A - SqrtScaleA- square root of scale factor ScaleA - N - matrix size, N>=0. - IsUpper - storage type - XB - right part - Tmp - buffer; function automatically allocates it, if it is too - small. It can be reused if function is called several - times. - -OUTPUT PARAMETERS: - XB - solution - -NOTE 1: no assertion or tests are done during algorithm operation -NOTE 2: N=0 will force algorithm to silently return - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void fblscholeskysolve(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - double v; - - - if( n==0 ) - { - return; - } - if( tmp->cntptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - if( iptr.p_double[i]; - ae_v_moved(&tmp->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); - ae_v_subd(&xb->ptr.p_double[i+1], 1, &tmp->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), v); - } - } - - /* - * Solve U*x=y then. - */ - for(i=n-1; i>=0; i--) - { - if( iptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); - v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); - xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; - } - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - } - } - else - { - - /* - * Solve L*y=b first - */ - for(i=0; i<=n-1; i++) - { - if( i>0 ) - { - ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); - v = ae_v_dotproduct(&tmp->ptr.p_double[0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); - xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; - } - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - } - - /* - * Solve L'*x=y then. - */ - for(i=n-1; i>=0; i--) - { - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - if( i>0 ) - { - v = xb->ptr.p_double[i]; - ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); - ae_v_subd(&xb->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,i-1), v); - } - } - } -} - - -/************************************************************************* -Fast basic linear solver: linear SPD CG - -Solves (A^T*A + alpha*I)*x = b where: -* A is MxN matrix -* alpha>0 is a scalar -* I is NxN identity matrix -* b is Nx1 vector -* X is Nx1 unknown vector. - -N iterations of linear conjugate gradient are used to solve problem. - -INPUT PARAMETERS: - A - array[M,N], matrix - M - number of rows - N - number of unknowns - B - array[N], right part - X - initial approxumation, array[N] - Buf - buffer; function automatically allocates it, if it is too - small. It can be reused if function is called several times - with same M and N. - -OUTPUT PARAMETERS: - X - improved solution - -NOTES: -* solver checks quality of improved solution. If (because of problem - condition number, numerical noise, etc.) new solution is WORSE than - original approximation, then original approximation is returned. -* solver assumes that both A, B, Alpha are well scaled (i.e. they are - less than sqrt(overflow) and greater than sqrt(underflow)). - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void fblssolvecgx(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - double alpha, - /* Real */ ae_vector* b, - /* Real */ ae_vector* x, - /* Real */ ae_vector* buf, - ae_state *_state) -{ - ae_int_t k; - ae_int_t offsrk; - ae_int_t offsrk1; - ae_int_t offsxk; - ae_int_t offsxk1; - ae_int_t offspk; - ae_int_t offspk1; - ae_int_t offstmp1; - ae_int_t offstmp2; - ae_int_t bs; - double e1; - double e2; - double rk2; - double rk12; - double pap; - double s; - double betak; - double v1; - double v2; - - - - /* - * Test for special case: B=0 - */ - v1 = ae_v_dotproduct(&b->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_eq(v1,0) ) - { - for(k=0; k<=n-1; k++) - { - x->ptr.p_double[k] = 0; - } - return; - } - - /* - * Offsets inside Buf for: - * * R[K], R[K+1] - * * X[K], X[K+1] - * * P[K], P[K+1] - * * Tmp1 - array[M], Tmp2 - array[N] - */ - offsrk = 0; - offsrk1 = offsrk+n; - offsxk = offsrk1+n; - offsxk1 = offsxk+n; - offspk = offsxk1+n; - offspk1 = offspk+n; - offstmp1 = offspk1+n; - offstmp2 = offstmp1+m; - bs = offstmp2+n; - if( buf->cntptr.p_double[offsxk], 1, &x->ptr.p_double[0], 1, ae_v_len(offsxk,offsxk+n-1)); - - /* - * r(0) = b-A*x(0) - * RK2 = r(0)'*r(0) - */ - rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); - rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); - ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); - ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); - ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); - rk2 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); - ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offspk,offspk+n-1)); - e1 = ae_sqrt(rk2, _state); - - /* - * Cycle - */ - for(k=0; k<=n-1; k++) - { - - /* - * Calculate A*p(k) - store in Buf[OffsTmp2:OffsTmp2+N-1] - * and p(k)'*A*p(k) - store in PAP - * - * If PAP=0, break (iteration is over) - */ - rmatrixmv(m, n, a, 0, 0, 0, buf, offspk, buf, offstmp1, _state); - v1 = ae_v_dotproduct(&buf->ptr.p_double[offstmp1], 1, &buf->ptr.p_double[offstmp1], 1, ae_v_len(offstmp1,offstmp1+m-1)); - v2 = ae_v_dotproduct(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk,offspk+n-1)); - pap = v1+alpha*v2; - rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); - ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); - if( ae_fp_eq(pap,0) ) - { - break; - } - - /* - * S = (r(k)'*r(k))/(p(k)'*A*p(k)) - */ - s = rk2/pap; - - /* - * x(k+1) = x(k) + S*p(k) - */ - ae_v_move(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offsxk1,offsxk1+n-1)); - ae_v_addd(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offsxk1,offsxk1+n-1), s); - - /* - * r(k+1) = r(k) - S*A*p(k) - * RK12 = r(k+1)'*r(k+1) - * - * Break if r(k+1) small enough (when compared to r(k)) - */ - ae_v_move(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk1,offsrk1+n-1)); - ae_v_subd(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk1,offsrk1+n-1), s); - rk12 = ae_v_dotproduct(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk1,offsrk1+n-1)); - if( ae_fp_less_eq(ae_sqrt(rk12, _state),100*ae_machineepsilon*ae_sqrt(rk2, _state)) ) - { - - /* - * X(k) = x(k+1) before exit - - * - because we expect to find solution at x(k) - */ - ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); - break; - } - - /* - * BetaK = RK12/RK2 - * p(k+1) = r(k+1)+betak*p(k) - */ - betak = rk12/rk2; - ae_v_move(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offspk1,offspk1+n-1)); - ae_v_addd(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk1,offspk1+n-1), betak); - - /* - * r(k) := r(k+1) - * x(k) := x(k+1) - * p(k) := p(k+1) - */ - ae_v_move(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk,offsrk+n-1)); - ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); - ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk1], 1, ae_v_len(offspk,offspk+n-1)); - rk2 = rk12; - } - - /* - * Calculate E2 - */ - rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); - rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); - ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); - ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); - ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); - v1 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); - e2 = ae_sqrt(v1, _state); - - /* - * Output result (if it was improved) - */ - if( ae_fp_less(e2,e1) ) - { - ae_v_move(&x->ptr.p_double[0], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(0,n-1)); - } -} - - -/************************************************************************* -Construction of linear conjugate gradient solver. - -State parameter passed using "var" semantics (i.e. previous state is NOT -erased). When it is already initialized, we can reause prevously allocated -memory. - -INPUT PARAMETERS: - X - initial solution - B - right part - N - system size - State - structure; may be preallocated, if we want to reuse memory - -OUTPUT PARAMETERS: - State - structure which is used by FBLSCGIteration() to store - algorithm state between subsequent calls. - -NOTE: no error checking is done; caller must check all parameters, prevent - overflows, and so on. - - -- ALGLIB -- - Copyright 22.10.2009 by Bochkanov Sergey -*************************************************************************/ -void fblscgcreate(/* Real */ ae_vector* x, - /* Real */ ae_vector* b, - ae_int_t n, - fblslincgstate* state, - ae_state *_state) -{ - - - if( state->b.cntb, n, _state); - } - if( state->rk.cntrk, n, _state); - } - if( state->rk1.cntrk1, n, _state); - } - if( state->xk.cntxk, n, _state); - } - if( state->xk1.cntxk1, n, _state); - } - if( state->pk.cntpk, n, _state); - } - if( state->pk1.cntpk1, n, _state); - } - if( state->tmp2.cnttmp2, n, _state); - } - if( state->x.cntx, n, _state); - } - if( state->ax.cntax, n, _state); - } - state->n = n; - ae_v_move(&state->xk.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_vector_set_length(&state->rstate.ia, 1+1, _state); - ae_vector_set_length(&state->rstate.ra, 6+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -Linear CG solver, function relying on reverse communication to calculate -matrix-vector products. - -See comments for FBLSLinCGState structure for more info. - - -- ALGLIB -- - Copyright 22.10.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t k; - double rk2; - double rk12; - double pap; - double s; - double betak; - double v1; - double v2; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - k = state->rstate.ia.ptr.p_int[1]; - rk2 = state->rstate.ra.ptr.p_double[0]; - rk12 = state->rstate.ra.ptr.p_double[1]; - pap = state->rstate.ra.ptr.p_double[2]; - s = state->rstate.ra.ptr.p_double[3]; - betak = state->rstate.ra.ptr.p_double[4]; - v1 = state->rstate.ra.ptr.p_double[5]; - v2 = state->rstate.ra.ptr.p_double[6]; - } - else - { - n = -983; - k = -989; - rk2 = -834; - rk12 = 900; - pap = -287; - s = 364; - betak = 214; - v1 = -338; - v2 = -686; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - - /* - * Routine body - */ - - /* - * prepare locals - */ - n = state->n; - - /* - * Test for special case: B=0 - */ - v1 = ae_v_dotproduct(&state->b.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_eq(v1,0) ) - { - for(k=0; k<=n-1; k++) - { - state->xk.ptr.p_double[k] = 0; - } - result = ae_false; - return result; - } - - /* - * r(0) = b-A*x(0) - * RK2 = r(0)'*r(0) - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - rk2 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->pk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->e1 = ae_sqrt(rk2, _state); - - /* - * Cycle - */ - k = 0; -lbl_3: - if( k>n-1 ) - { - goto lbl_5; - } - - /* - * Calculate A*p(k) - store in State.Tmp2 - * and p(k)'*A*p(k) - store in PAP - * - * If PAP=0, break (iteration is over) - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - ae_v_move(&state->tmp2.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - pap = state->xax; - if( !ae_isfinite(pap, _state) ) - { - goto lbl_5; - } - if( ae_fp_less_eq(pap,0) ) - { - goto lbl_5; - } - - /* - * S = (r(k)'*r(k))/(p(k)'*A*p(k)) - */ - s = rk2/pap; - - /* - * x(k+1) = x(k) + S*p(k) - */ - ae_v_move(&state->xk1.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->xk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), s); - - /* - * r(k+1) = r(k) - S*A*p(k) - * RK12 = r(k+1)'*r(k+1) - * - * Break if r(k+1) small enough (when compared to r(k)) - */ - ae_v_move(&state->rk1.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_subd(&state->rk1.ptr.p_double[0], 1, &state->tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1), s); - rk12 = ae_v_dotproduct(&state->rk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_less_eq(ae_sqrt(rk12, _state),100*ae_machineepsilon*state->e1) ) - { - - /* - * X(k) = x(k+1) before exit - - * - because we expect to find solution at x(k) - */ - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - goto lbl_5; - } - - /* - * BetaK = RK12/RK2 - * p(k+1) = r(k+1)+betak*p(k) - * - * NOTE: we expect that BetaK won't overflow because of - * "Sqrt(RK12)<=100*MachineEpsilon*E1" test above. - */ - betak = rk12/rk2; - ae_v_move(&state->pk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->pk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); - - /* - * r(k) := r(k+1) - * x(k) := x(k+1) - * p(k) := p(k+1) - */ - ae_v_move(&state->rk.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->pk.ptr.p_double[0], 1, &state->pk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - rk2 = rk12; - k = k+1; - goto lbl_3; -lbl_5: - - /* - * Calculate E2 - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v1 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->e2 = ae_sqrt(v1, _state); - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = k; - state->rstate.ra.ptr.p_double[0] = rk2; - state->rstate.ra.ptr.p_double[1] = rk12; - state->rstate.ra.ptr.p_double[2] = pap; - state->rstate.ra.ptr.p_double[3] = s; - state->rstate.ra.ptr.p_double[4] = betak; - state->rstate.ra.ptr.p_double[5] = v1; - state->rstate.ra.ptr.p_double[6] = v2; - return result; -} - - -/************************************************************************* -Fast least squares solver, solves well conditioned system without -performing any checks for degeneracy, and using user-provided buffers -(which are automatically reallocated if too small). - -This function is intended for solution of moderately sized systems. It -uses factorization algorithms based on Level 2 BLAS operations, thus it -won't work efficiently on large scale systems. - -INPUT PARAMETERS: - A - array[M,N], system matrix. - Contents of A is destroyed during solution. - B - array[M], right part - M - number of equations - N - number of variables, N<=M - Tmp0, Tmp1, Tmp2- - buffers; function automatically allocates them, if they are - too small. They can be reused if function is called - several times. - -OUTPUT PARAMETERS: - B - solution (first N components, next M-N are zero) - - -- ALGLIB -- - Copyright 20.01.2012 by Bochkanov Sergey -*************************************************************************/ -void fblssolvels(/* Real */ ae_matrix* a, - /* Real */ ae_vector* b, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tmp0, - /* Real */ ae_vector* tmp1, - /* Real */ ae_vector* tmp2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - double v; - - - ae_assert(n>0, "FBLSSolveLS: N<=0", _state); - ae_assert(m>=n, "FBLSSolveLS: Mrows>=m, "FBLSSolveLS: Rows(A)cols>=n, "FBLSSolveLS: Cols(A)cnt>=m, "FBLSSolveLS: Length(B)ptr.p_double[i] = 0; - } - ae_v_move(&tmp0->ptr.p_double[k], 1, &a->ptr.pp_double[k][k], a->stride, ae_v_len(k,m-1)); - tmp0->ptr.p_double[k] = 1; - v = ae_v_dotproduct(&tmp0->ptr.p_double[k], 1, &b->ptr.p_double[k], 1, ae_v_len(k,m-1)); - v = v*tmp2->ptr.p_double[k]; - ae_v_subd(&b->ptr.p_double[k], 1, &tmp0->ptr.p_double[k], 1, ae_v_len(k,m-1), v); - } - - /* - * Solve triangular system - */ - b->ptr.p_double[n-1] = b->ptr.p_double[n-1]/a->ptr.pp_double[n-1][n-1]; - for(i=n-2; i>=0; i--) - { - v = ae_v_dotproduct(&a->ptr.pp_double[i][i+1], 1, &b->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); - b->ptr.p_double[i] = (b->ptr.p_double[i]-v)/a->ptr.pp_double[i][i]; - } - for(i=n; i<=m-1; i++) - { - b->ptr.p_double[i] = 0.0; - } -} - - -ae_bool _fblslincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - fblslincgstate *p = (fblslincgstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ax, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rk1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xk1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->pk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->pk1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _fblslincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - fblslincgstate *dst = (fblslincgstate*)_dst; - fblslincgstate *src = (fblslincgstate*)_src; - dst->e1 = src->e1; - dst->e2 = src->e2; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ax, &src->ax, _state, make_automatic) ) - return ae_false; - dst->xax = src->xax; - dst->n = src->n; - if( !ae_vector_init_copy(&dst->rk, &src->rk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rk1, &src->rk1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xk1, &src->xk1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->pk, &src->pk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->pk1, &src->pk1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _fblslincgstate_clear(void* _p) -{ - fblslincgstate *p = (fblslincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->ax); - ae_vector_clear(&p->rk); - ae_vector_clear(&p->rk1); - ae_vector_clear(&p->xk); - ae_vector_clear(&p->xk1); - ae_vector_clear(&p->pk); - ae_vector_clear(&p->pk1); - ae_vector_clear(&p->b); - _rcommstate_clear(&p->rstate); - ae_vector_clear(&p->tmp2); -} - - -void _fblslincgstate_destroy(void* _p) -{ - fblslincgstate *p = (fblslincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->ax); - ae_vector_destroy(&p->rk); - ae_vector_destroy(&p->rk1); - ae_vector_destroy(&p->xk); - ae_vector_destroy(&p->xk1); - ae_vector_destroy(&p->pk); - ae_vector_destroy(&p->pk1); - ae_vector_destroy(&p->b); - _rcommstate_destroy(&p->rstate); - ae_vector_destroy(&p->tmp2); -} - - - - -/************************************************************************* -This procedure initializes matrix norm estimator. - -USAGE: -1. User initializes algorithm state with NormEstimatorCreate() call -2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) -3. User calls NormEstimatorResults() to get solution. - -INPUT PARAMETERS: - M - number of rows in the matrix being estimated, M>0 - N - number of columns in the matrix being estimated, N>0 - NStart - number of random starting vectors - recommended value - at least 5. - NIts - number of iterations to do with best starting vector - recommended value - at least 5. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTE: this algorithm is effectively deterministic, i.e. it always returns -same result when repeatedly called for the same matrix. In fact, algorithm -uses randomized starting vectors, but internal random numbers generator -always generates same sequence of the random values (it is a feature, not -bug). - -Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorcreate(ae_int_t m, - ae_int_t n, - ae_int_t nstart, - ae_int_t nits, - normestimatorstate* state, - ae_state *_state) -{ - - _normestimatorstate_clear(state); - - ae_assert(m>0, "NormEstimatorCreate: M<=0", _state); - ae_assert(n>0, "NormEstimatorCreate: N<=0", _state); - ae_assert(nstart>0, "NormEstimatorCreate: NStart<=0", _state); - ae_assert(nits>0, "NormEstimatorCreate: NIts<=0", _state); - state->m = m; - state->n = n; - state->nstart = nstart; - state->nits = nits; - state->seedval = 11; - hqrndrandomize(&state->r, _state); - ae_vector_set_length(&state->x0, state->n, _state); - ae_vector_set_length(&state->t, state->m, _state); - ae_vector_set_length(&state->x1, state->n, _state); - ae_vector_set_length(&state->xbest, state->n, _state); - ae_vector_set_length(&state->x, ae_maxint(state->n, state->m, _state), _state); - ae_vector_set_length(&state->mv, state->m, _state); - ae_vector_set_length(&state->mtv, state->n, _state); - ae_vector_set_length(&state->rstate.ia, 3+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -This function changes seed value used by algorithm. In some cases we need -deterministic processing, i.e. subsequent calls must return equal results, -in other cases we need non-deterministic algorithm which returns different -results for the same matrix on every pass. - -Setting zero seed will lead to non-deterministic algorithm, while non-zero -value will make our algorithm deterministic. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - SeedVal - seed value, >=0. Zero value = non-deterministic algo. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorsetseed(normestimatorstate* state, - ae_int_t seedval, - ae_state *_state) -{ - - - ae_assert(seedval>=0, "NormEstimatorSetSeed: SeedVal<0", _state); - state->seedval = seedval; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -ae_bool normestimatoriteration(normestimatorstate* state, - ae_state *_state) -{ - ae_int_t n; - ae_int_t m; - ae_int_t i; - ae_int_t itcnt; - double v; - double growth; - double bestgrowth; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - i = state->rstate.ia.ptr.p_int[2]; - itcnt = state->rstate.ia.ptr.p_int[3]; - v = state->rstate.ra.ptr.p_double[0]; - growth = state->rstate.ra.ptr.p_double[1]; - bestgrowth = state->rstate.ra.ptr.p_double[2]; - } - else - { - n = -983; - m = -989; - i = -834; - itcnt = 900; - v = -287; - growth = 364; - bestgrowth = 214; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - - /* - * Routine body - */ - n = state->n; - m = state->m; - if( state->seedval>0 ) - { - hqrndseed(state->seedval, state->seedval+2, &state->r, _state); - } - bestgrowth = 0; - state->xbest.ptr.p_double[0] = 1; - for(i=1; i<=n-1; i++) - { - state->xbest.ptr.p_double[i] = 0; - } - itcnt = 0; -lbl_4: - if( itcnt>state->nstart-1 ) - { - goto lbl_6; - } - do - { - v = 0; - for(i=0; i<=n-1; i++) - { - state->x0.ptr.p_double[i] = hqrndnormal(&state->r, _state); - v = v+ae_sqr(state->x0.ptr.p_double[i], _state); - } - } - while(ae_fp_eq(v,0)); - v = 1/ae_sqrt(v, _state); - ae_v_muld(&state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->needmv = ae_true; - state->needmtv = ae_false; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->needmv = ae_false; - state->needmtv = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->x1.ptr.p_double[i], _state); - } - growth = ae_sqrt(ae_sqrt(v, _state), _state); - if( ae_fp_greater(growth,bestgrowth) ) - { - v = 1/ae_sqrt(v, _state); - ae_v_moved(&state->xbest.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - bestgrowth = growth; - } - itcnt = itcnt+1; - goto lbl_4; -lbl_6: - ae_v_move(&state->x0.ptr.p_double[0], 1, &state->xbest.ptr.p_double[0], 1, ae_v_len(0,n-1)); - itcnt = 0; -lbl_7: - if( itcnt>state->nits-1 ) - { - goto lbl_9; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->needmv = ae_true; - state->needmtv = ae_false; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->needmv = ae_false; - state->needmtv = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->x1.ptr.p_double[i], _state); - } - state->repnorm = ae_sqrt(ae_sqrt(v, _state), _state); - if( ae_fp_neq(v,0) ) - { - v = 1/ae_sqrt(v, _state); - ae_v_moved(&state->x0.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - itcnt = itcnt+1; - goto lbl_7; -lbl_9: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = i; - state->rstate.ia.ptr.p_int[3] = itcnt; - state->rstate.ra.ptr.p_double[0] = v; - state->rstate.ra.ptr.p_double[1] = growth; - state->rstate.ra.ptr.p_double[2] = bestgrowth; - return result; -} - - -/************************************************************************* -This function estimates norm of the sparse M*N matrix A. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - A - sparse M*N matrix, must be converted to CRS format - prior to calling this function. - -After this function is over you can call NormEstimatorResults() to get -estimate of the norm(A). - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorestimatesparse(normestimatorstate* state, - sparsematrix* a, - ae_state *_state) -{ - - - normestimatorrestart(state, _state); - while(normestimatoriteration(state, _state)) - { - if( state->needmv ) - { - sparsemv(a, &state->x, &state->mv, _state); - continue; - } - if( state->needmtv ) - { - sparsemtv(a, &state->x, &state->mtv, _state); - continue; - } - } -} - - -/************************************************************************* -Matrix norm estimation results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Nrm - estimate of the matrix norm, Nrm>=0 - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorresults(normestimatorstate* state, - double* nrm, - ae_state *_state) -{ - - *nrm = 0; - - *nrm = state->repnorm; -} - - -/************************************************************************* -This function restarts estimator and prepares it for the next estimation -round. - -INPUT PARAMETERS: - State - algorithm state - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorrestart(normestimatorstate* state, ae_state *_state) -{ - - - ae_vector_set_length(&state->rstate.ia, 3+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; -} - - -ae_bool _normestimatorstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - normestimatorstate *p = (normestimatorstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->t, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xbest, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_hqrndstate_init(&p->r, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mtv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _normestimatorstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - normestimatorstate *dst = (normestimatorstate*)_dst; - normestimatorstate *src = (normestimatorstate*)_src; - dst->n = src->n; - dst->m = src->m; - dst->nstart = src->nstart; - dst->nits = src->nits; - dst->seedval = src->seedval; - if( !ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x1, &src->x1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->t, &src->t, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xbest, &src->xbest, _state, make_automatic) ) - return ae_false; - if( !_hqrndstate_init_copy(&dst->r, &src->r, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mtv, &src->mtv, _state, make_automatic) ) - return ae_false; - dst->needmv = src->needmv; - dst->needmtv = src->needmtv; - dst->repnorm = src->repnorm; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _normestimatorstate_clear(void* _p) -{ - normestimatorstate *p = (normestimatorstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x0); - ae_vector_clear(&p->x1); - ae_vector_clear(&p->t); - ae_vector_clear(&p->xbest); - _hqrndstate_clear(&p->r); - ae_vector_clear(&p->x); - ae_vector_clear(&p->mv); - ae_vector_clear(&p->mtv); - _rcommstate_clear(&p->rstate); -} - - -void _normestimatorstate_destroy(void* _p) -{ - normestimatorstate *p = (normestimatorstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x0); - ae_vector_destroy(&p->x1); - ae_vector_destroy(&p->t); - ae_vector_destroy(&p->xbest); - _hqrndstate_destroy(&p->r); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->mv); - ae_vector_destroy(&p->mtv); - _rcommstate_destroy(&p->rstate); -} - - - - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixludet(/* Real */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t s; - double result; - - - ae_assert(n>=1, "RMatrixLUDet: N<1!", _state); - ae_assert(pivots->cnt>=n, "RMatrixLUDet: Pivots array is too short!", _state); - ae_assert(a->rows>=n, "RMatrixLUDet: rows(A)cols>=n, "RMatrixLUDet: cols(A)ptr.pp_double[i][i]; - if( pivots->ptr.p_int[i]!=i ) - { - s = -s; - } - } - result = result*s; - return result; -} - - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixdet(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector pivots; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "RMatrixDet: N<1!", _state); - ae_assert(a->rows>=n, "RMatrixDet: rows(A)cols>=n, "RMatrixDet: cols(A)=1, "CMatrixLUDet: N<1!", _state); - ae_assert(pivots->cnt>=n, "CMatrixLUDet: Pivots array is too short!", _state); - ae_assert(a->rows>=n, "CMatrixLUDet: rows(A)cols>=n, "CMatrixLUDet: cols(A)ptr.pp_complex[i][i]); - if( pivots->ptr.p_int[i]!=i ) - { - s = -s; - } - } - result = ae_c_mul_d(result,s); - return result; -} - - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -ae_complex cmatrixdet(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_vector pivots; - ae_complex result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "CMatrixDet: N<1!", _state); - ae_assert(a->rows>=n, "CMatrixDet: rows(A)cols>=n, "CMatrixDet: cols(A)=1, "SPDMatrixCholeskyDet: N<1!", _state); - ae_assert(a->rows>=n, "SPDMatrixCholeskyDet: rows(A)cols>=n, "SPDMatrixCholeskyDet: cols(A)ptr.pp_double[i][i], _state); - } - ae_assert(f, "SPDMatrixCholeskyDet: A contains infinite or NaN values!", _state); - result = 1; - for(i=0; i<=n-1; i++) - { - result = result*ae_sqr(a->ptr.pp_double[i][i], _state); - } - return result; -} - - -/************************************************************************* -Determinant calculation of the symmetric positive definite matrix. - -Input parameters: - A - matrix. Array with elements [0..N-1, 0..N-1]. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Result: - determinant of matrix A. - If matrix A is not positive definite, exception is thrown. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixdet(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _a; - ae_bool b; - double result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_a, a, _state, ae_true); - a = &_a; - - ae_assert(n>=1, "SPDMatrixDet: N<1!", _state); - ae_assert(a->rows>=n, "SPDMatrixDet: rows(A)cols>=n, "SPDMatrixDet: cols(A)ptr.pp_double[0][j] = 0.0; - } - for(i=1; i<=n-1; i++) - { - ae_v_move(&z->ptr.pp_double[i][0], 1, &z->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); - } - - /* - * Setup R properties - */ - if( isupperr ) - { - j1 = 0; - j2 = n-1; - j1inc = 1; - j2inc = 0; - } - else - { - j1 = 0; - j2 = 0; - j1inc = 0; - j2inc = 1; - } - - /* - * Calculate R*Z - */ - for(i=0; i<=n-1; i++) - { - for(j=j1; j<=j2; j++) - { - v = r.ptr.pp_double[i][j]; - ae_v_addd(&z->ptr.pp_double[i][0], 1, &t.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); - } - j1 = j1+j1inc; - j2 = j2+j2inc; - } - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* -Algorithm for reduction of the following generalized symmetric positive- -definite eigenvalue problem: - A*x = lambda*B*x (1) or - A*B*x = lambda*x (2) or - B*A*x = lambda*x (3) -to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and -the given problems are the same, and the eigenvectors of the given problem -could be obtained by multiplying the obtained eigenvectors by the -transformation matrix x = R*y). - -Here A is a symmetric matrix, B - symmetric positive-definite matrix. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrices A and B. - IsUpperA - storage format of matrix A. - B - symmetric positive-definite matrix which is given by - its upper or lower triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperB - storage format of matrix B. - ProblemType - if ProblemType is equal to: - * 1, the following problem is solved: A*x = lambda*B*x; - * 2, the following problem is solved: A*B*x = lambda*x; - * 3, the following problem is solved: B*A*x = lambda*x. - -Output parameters: - A - symmetric matrix which is given by its upper or lower - triangle depending on IsUpperA. Contains matrix C. - Array whose indexes range within [0..N-1, 0..N-1]. - R - upper triangular or low triangular transformation matrix - which is used to obtain the eigenvectors of a given problem - as the product of eigenvectors of C (from the right) and - matrix R (from the left). If the matrix is upper - triangular, the elements below the main diagonal - are equal to 0 (and vice versa). Thus, we can perform - the multiplication without taking into account the - internal structure (which is an easier though less - effective way). - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperR - type of matrix R (upper or lower triangular). - -Result: - True, if the problem was reduced successfully. - False, if the error occurred during the Cholesky decomposition of - matrix B (the matrix is not positive-definite). - - -- ALGLIB -- - Copyright 1.28.2006 by Bochkanov Sergey -*************************************************************************/ -ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isuppera, - /* Real */ ae_matrix* b, - ae_bool isupperb, - ae_int_t problemtype, - /* Real */ ae_matrix* r, - ae_bool* isupperr, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix t; - ae_vector w1; - ae_vector w2; - ae_vector w3; - ae_int_t i; - ae_int_t j; - double v; - matinvreport rep; - ae_int_t info; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(r); - *isupperr = ae_false; - ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w3, 0, DT_REAL, _state, ae_true); - _matinvreport_init(&rep, _state, ae_true); - - ae_assert(n>0, "SMatrixGEVDReduce: N<=0!", _state); - ae_assert((problemtype==1||problemtype==2)||problemtype==3, "SMatrixGEVDReduce: incorrect ProblemType!", _state); - result = ae_true; - - /* - * Problem 1: A*x = lambda*B*x - * - * Reducing to: - * C*y = lambda*y - * C = L^(-1) * A * L^(-T) - * x = L^(-T) * y - */ - if( problemtype==1 ) - { - - /* - * Factorize B in T: B = LL' - */ - ae_matrix_set_length(&t, n-1+1, n-1+1, _state); - if( isupperb ) - { - for(i=0; i<=n-1; i++) - { - ae_v_move(&t.ptr.pp_double[i][i], t.stride, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); - } - } - else - { - for(i=0; i<=n-1; i++) - { - ae_v_move(&t.ptr.pp_double[i][0], 1, &b->ptr.pp_double[i][0], 1, ae_v_len(0,i)); - } - } - if( !spdmatrixcholesky(&t, n, ae_false, _state) ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Invert L in T - */ - rmatrixtrinverse(&t, n, ae_false, ae_false, &info, &rep, _state); - if( info<=0 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Build L^(-1) * A * L^(-T) in R - */ - ae_vector_set_length(&w1, n+1, _state); - ae_vector_set_length(&w2, n+1, _state); - ae_matrix_set_length(r, n-1+1, n-1+1, _state); - for(j=1; j<=n; j++) - { - - /* - * Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T)) - */ - ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][0], 1, ae_v_len(1,j)); - symmetricmatrixvectormultiply(a, isuppera, 0, j-1, &w1, 1.0, &w2, _state); - if( isuppera ) - { - matrixvectormultiply(a, 0, j-1, j, n-1, ae_true, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); - } - else - { - matrixvectormultiply(a, j, n-1, 0, j-1, ae_false, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); - } - - /* - * Form l(i)*w2 (here l(i) is i-th row of L^(-1)) - */ - for(i=1; i<=n; i++) - { - v = ae_v_dotproduct(&t.ptr.pp_double[i-1][0], 1, &w2.ptr.p_double[1], 1, ae_v_len(0,i-1)); - r->ptr.pp_double[i-1][j-1] = v; - } - } - - /* - * Copy R to A - */ - for(i=0; i<=n-1; i++) - { - ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - } - - /* - * Copy L^(-1) from T to R and transpose - */ - *isupperr = ae_true; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - r->ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=n-1; i++) - { - ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], t.stride, ae_v_len(i,n-1)); - } - ae_frame_leave(_state); - return result; - } - - /* - * Problem 2: A*B*x = lambda*x - * or - * problem 3: B*A*x = lambda*x - * - * Reducing to: - * C*y = lambda*y - * C = U * A * U' - * B = U'* U - */ - if( problemtype==2||problemtype==3 ) - { - - /* - * Factorize B in T: B = U'*U - */ - ae_matrix_set_length(&t, n-1+1, n-1+1, _state); - if( isupperb ) - { - for(i=0; i<=n-1; i++) - { - ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); - } - } - else - { - for(i=0; i<=n-1; i++) - { - ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], b->stride, ae_v_len(i,n-1)); - } - } - if( !spdmatrixcholesky(&t, n, ae_true, _state) ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Build U * A * U' in R - */ - ae_vector_set_length(&w1, n+1, _state); - ae_vector_set_length(&w2, n+1, _state); - ae_vector_set_length(&w3, n+1, _state); - ae_matrix_set_length(r, n-1+1, n-1+1, _state); - for(j=1; j<=n; j++) - { - - /* - * Form w2 = A * u'(j) (here u'(j) is j-th column of U') - */ - ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(1,n-j+1)); - symmetricmatrixvectormultiply(a, isuppera, j-1, n-1, &w1, 1.0, &w3, _state); - ae_v_move(&w2.ptr.p_double[j], 1, &w3.ptr.p_double[1], 1, ae_v_len(j,n)); - ae_v_move(&w1.ptr.p_double[j], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(j,n)); - if( isuppera ) - { - matrixvectormultiply(a, 0, j-2, j-1, n-1, ae_false, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); - } - else - { - matrixvectormultiply(a, j-1, n-1, 0, j-2, ae_true, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); - } - - /* - * Form u(i)*w2 (here u(i) is i-th row of U) - */ - for(i=1; i<=n; i++) - { - v = ae_v_dotproduct(&t.ptr.pp_double[i-1][i-1], 1, &w2.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); - r->ptr.pp_double[i-1][j-1] = v; - } - } - - /* - * Copy R to A - */ - for(i=0; i<=n-1; i++) - { - ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - } - if( problemtype==2 ) - { - - /* - * Invert U in T - */ - rmatrixtrinverse(&t, n, ae_true, ae_false, &info, &rep, _state); - if( info<=0 ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - - /* - * Copy U^-1 from T to R - */ - *isupperr = ae_true; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=i-1; j++) - { - r->ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=n-1; i++) - { - ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); - } - } - else - { - - /* - * Copy U from T to R and transpose - */ - *isupperr = ae_false; - for(i=0; i<=n-1; i++) - { - for(j=i+1; j<=n-1; j++) - { - r->ptr.pp_double[i][j] = 0; - } - } - for(i=0; i<=n-1; i++) - { - ae_v_move(&r->ptr.pp_double[i][i], r->stride, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); - } - } - } - ae_frame_leave(_state); - return result; -} - - - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a number to an element -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - row where the element to be updated is stored. - UpdColumn - column where the element to be updated is stored. - UpdVal - a number to be added to the element. - - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updrow, - ae_int_t updcolumn, - double updval, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector t1; - ae_vector t2; - ae_int_t i; - double lambdav; - double vt; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); - - ae_assert(updrow>=0&&updrow=0&&updcolumnptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); - - /* - * T2 = v*InvA - */ - ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); - - /* - * Lambda = v * InvA * U - */ - lambdav = updval*inva->ptr.pp_double[updcolumn][updrow]; - - /* - * InvA = InvA - correction - */ - for(i=0; i<=n-1; i++) - { - vt = updval*t1.ptr.p_double[i]; - vt = vt/(1+lambdav); - ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a row -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - the row of A whose vector V was added. - 0 <= Row <= N-1 - V - the vector to be added to a row. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updrow, - /* Real */ ae_vector* v, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector t1; - ae_vector t2; - ae_int_t i; - ae_int_t j; - double lambdav; - double vt; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&t1, n-1+1, _state); - ae_vector_set_length(&t2, n-1+1, _state); - - /* - * T1 = InvA * U - */ - ae_v_move(&t1.ptr.p_double[0], 1, &inva->ptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); - - /* - * T2 = v*InvA - * Lambda = v * InvA * U - */ - for(j=0; j<=n-1; j++) - { - vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); - t2.ptr.p_double[j] = vt; - } - lambdav = t2.ptr.p_double[updrow]; - - /* - * InvA = InvA - correction - */ - for(i=0; i<=n-1; i++) - { - vt = t1.ptr.p_double[i]/(1+lambdav); - ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a column -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdColumn - the column of A whose vector U was added. - 0 <= UpdColumn <= N-1 - U - the vector to be added to a column. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updcolumn, - /* Real */ ae_vector* u, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector t1; - ae_vector t2; - ae_int_t i; - double lambdav; - double vt; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&t1, n-1+1, _state); - ae_vector_set_length(&t2, n-1+1, _state); - - /* - * T1 = InvA * U - * Lambda = v * InvA * U - */ - for(i=0; i<=n-1; i++) - { - vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); - t1.ptr.p_double[i] = vt; - } - lambdav = t1.ptr.p_double[updcolumn]; - - /* - * T2 = v*InvA - */ - ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); - - /* - * InvA = InvA - correction - */ - for(i=0; i<=n-1; i++) - { - vt = t1.ptr.p_double[i]/(1+lambdav); - ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm computes the inverse of matrix A+u*v’ by using the given matrix -A^-1 and the vectors u and v. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - U - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - V - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of matrix A + u*v'. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, - ae_int_t n, - /* Real */ ae_vector* u, - /* Real */ ae_vector* v, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector t1; - ae_vector t2; - ae_int_t i; - ae_int_t j; - double lambdav; - double vt; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); - - ae_vector_set_length(&t1, n-1+1, _state); - ae_vector_set_length(&t2, n-1+1, _state); - - /* - * T1 = InvA * U - * Lambda = v * T1 - */ - for(i=0; i<=n-1; i++) - { - vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); - t1.ptr.p_double[i] = vt; - } - lambdav = ae_v_dotproduct(&v->ptr.p_double[0], 1, &t1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * T2 = v*InvA - */ - for(j=0; j<=n-1; j++) - { - vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); - t2.ptr.p_double[j] = vt; - } - - /* - * InvA = InvA - correction - */ - for(i=0; i<=n-1; i++) - { - vt = t1.ptr.p_double[i]/(1+lambdav); - ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); - } - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Subroutine performing the Schur decomposition of a general matrix by using -the QR algorithm with multiple shifts. - -The source matrix A is represented as S'*A*S = T, where S is an orthogonal -matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of -sizes 1x1 and 2x2 on the main diagonal). - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of A, N>=0. - - -Output parameters: - A - contains matrix T. - Array whose indexes range within [0..N-1, 0..N-1]. - S - contains Schur vectors. - Array whose indexes range within [0..N-1, 0..N-1]. - -Note 1: - The block structure of matrix T can be easily recognized: since all - the elements below the blocks are zeros, the elements a[i+1,i] which - are equal to 0 show the block border. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms in linear algebra). If you require maximum performance on - your machine, it is recommended to adjust this parameter manually. - -Result: - True, - if the algorithm has converged and parameters A and S contain the result. - False, - if the algorithm has not converged. - -Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). -*************************************************************************/ -ae_bool rmatrixschur(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* s, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector tau; - ae_vector wi; - ae_vector wr; - ae_matrix a1; - ae_matrix s1; - ae_int_t info; - ae_int_t i; - ae_int_t j; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(s); - ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wi, 0, DT_REAL, _state, ae_true); - ae_vector_init(&wr, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a1, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&s1, 0, 0, DT_REAL, _state, ae_true); - - - /* - * Upper Hessenberg form of the 0-based matrix - */ - rmatrixhessenberg(a, n, &tau, _state); - rmatrixhessenbergunpackq(a, n, &tau, s, _state); - - /* - * Convert from 0-based arrays to 1-based, - * then call InternalSchurDecomposition - * Awkward, of course, but Schur decompisiton subroutine - * is too complex to fix it. - * - */ - ae_matrix_set_length(&a1, n+1, n+1, _state); - ae_matrix_set_length(&s1, n+1, n+1, _state); - for(i=1; i<=n; i++) - { - for(j=1; j<=n; j++) - { - a1.ptr.pp_double[i][j] = a->ptr.pp_double[i-1][j-1]; - s1.ptr.pp_double[i][j] = s->ptr.pp_double[i-1][j-1]; - } - } - internalschurdecomposition(&a1, n, 1, 1, &wr, &wi, &s1, &info, _state); - result = info==0; - - /* - * convert from 1-based arrays to -based - */ - for(i=1; i<=n; i++) - { - for(j=1; j<=n; j++) - { - a->ptr.pp_double[i-1][j-1] = a1.ptr.pp_double[i][j]; - s->ptr.pp_double[i-1][j-1] = s1.ptr.pp_double[i][j]; - } - } - ae_frame_leave(_state); - return result; -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "linalg.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Cache-oblivous complex "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixtranspose(m, n, a.c_ptr(), ia, ja, b.c_ptr(), ib, jb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Cache-oblivous real "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixtranspose(m, n, a.c_ptr(), ia, ja, b.c_ptr(), ib, jb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This code enforces symmetricy of the matrix by copying Upper part to lower +one (or vice versa). + +INPUT PARAMETERS: + A - matrix + N - number of rows/columns + IsUpper - whether we want to copy upper triangle to lower one (True) + or vice versa (False). +*************************************************************************/ +void rmatrixenforcesymmetricity(real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixenforcesymmetricity(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixcopy(m, n, a.c_ptr(), ia, ja, b.c_ptr(), ib, jb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Copy + +Input parameters: + N - subvector size + A - source vector, N elements are copied + IA - source offset (first element index) + B - destination vector, must be large enough to store result + IB - destination offset (first element index) +*************************************************************************/ +void rvectorcopy(const ae_int_t n, const real_1d_array &a, const ae_int_t ia, real_1d_array &b, const ae_int_t ib, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rvectorcopy(n, a.c_ptr(), ia, b.c_ptr(), ib, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixcopy(m, n, a.c_ptr(), ia, ja, b.c_ptr(), ib, jb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Performs generalized copy: B := Beta*B + Alpha*A. + +If Beta=0, then previous contents of B is simply ignored. If Alpha=0, then +A is ignored and not referenced. If both Alpha and Beta are zero, B is +filled by zeros. + +Input parameters: + M - number of rows + N - number of columns + Alpha- coefficient + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Beta- coefficient + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixgencopy(const ae_int_t m, const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const double beta, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixgencopy(m, n, alpha, a.c_ptr(), ia, ja, beta, b.c_ptr(), ib, jb, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Rank-1 correction: A := A + alpha*u*v' + +NOTE: this function expects A to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, u, v. + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Alpha- coefficient + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset + + + -- ALGLIB routine -- + + 16.10.2017 + Bochkanov Sergey +*************************************************************************/ +void rmatrixger(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const double alpha, const real_1d_array &u, const ae_int_t iu, const real_1d_array &v, const ae_int_t iv, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixger(m, n, a.c_ptr(), ia, ja, alpha, u.c_ptr(), iu, v.c_ptr(), iv, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const complex_1d_array &u, const ae_int_t iu, const complex_1d_array &v, const ae_int_t iv, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrank1(m, n, a.c_ptr(), ia, ja, u.c_ptr(), iu, v.c_ptr(), iv, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGER() + which is more generic version of this function. + +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const real_1d_array &u, const ae_int_t iu, const real_1d_array &v, const ae_int_t iv, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrank1(m, n, a.c_ptr(), ia, ja, u.c_ptr(), iu, v.c_ptr(), iv, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + +*************************************************************************/ +void rmatrixgemv(const ae_int_t m, const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixgemv(m, n, alpha, a.c_ptr(), ia, ja, opa, x.c_ptr(), ix, beta, y.c_ptr(), iy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + M>=0 + N - number of columns of op(A) + N>=0 + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + * OpA=2 => op(A) = A^H + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixmv(m, n, a.c_ptr(), ia, ja, opa, x.c_ptr(), ix, y.c_ptr(), iy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGEMV() + which is more generic version of this function. + +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixmv(m, n, a.c_ptr(), ia, ja, opa, x.c_ptr(), ix, y.c_ptr(), iy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + +*************************************************************************/ +void rmatrixsymv(const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsymv(n, alpha, a.c_ptr(), ia, ja, isupper, x.c_ptr(), ix, beta, y.c_ptr(), iy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + +*************************************************************************/ +double rmatrixsyvmv(const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const real_1d_array &x, const ae_int_t ix, real_1d_array &tmp, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixsyvmv(n, a.c_ptr(), ia, ja, isupper, x.c_ptr(), ix, tmp.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This subroutine solves linear system op(A)*x=b where: +* A is NxN upper/lower triangular/unitriangular matrix +* X and B are Nx1 vectors +* "op" may be identity transformation or transposition + +Solution replaces X. + +IMPORTANT: * no overflow/underflow/denegeracy tests is performed. + * no integrity checks for operand sizes, out-of-bounds accesses + and so on is performed + +INPUT PARAMETERS + N - matrix size, N>=0 + A - matrix, actial matrix is stored in A[IA:IA+N-1,JA:JA+N-1] + IA - submatrix offset + JA - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - right part, actual vector is stored in X[IX:IX+N-1] + IX - offset + +OUTPUT PARAMETERS + X - solution replaces elements X[IX:IX+N-1] + + -- ALGLIB routine / remastering of LAPACK's DTRSV -- + (c) 2017 Bochkanov Sergey - converted to ALGLIB + (c) 2016 Reference BLAS level1 routine (LAPACK version 3.7.0) + Reference BLAS is a software package provided by Univ. of Tennessee, + Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd. +*************************************************************************/ +void rmatrixtrsv(const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, const ae_int_t ix, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixtrsv(n, a.c_ptr(), ia, ja, isupper, isunit, optype, x.c_ptr(), ix, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 20.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, complex_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrighttrsm(m, n, a.c_ptr(), i1, j1, isupper, isunit, optype, x.c_ptr(), i2, j2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, complex_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlefttrsm(m, n, a.c_ptr(), i1, j1, isupper, isunit, optype, x.c_ptr(), i2, j2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, real_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrighttrsm(m, n, a.c_ptr(), i1, j1, isupper, isunit, optype, x.c_ptr(), i2, j2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, real_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlefttrsm(m, n, a.c_ptr(), i1, j1, isupper, isunit, optype, x.c_ptr(), i2, j2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C +where: +* C is NxN Hermitian matrix given by its upper/lower triangle +* A is NxK matrix when A*A^H is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^H is calculated + * 2 - A^H*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether upper or lower triangle of C is updated; + this function updates only one half of C, leaving + other half unchanged (not referenced at all). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixherk(n, k, alpha, a.c_ptr(), ia, ja, optypea, beta, c.c_ptr(), ic, jc, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C +where: +* C is NxN symmetric matrix given by its upper/lower triangle +* A is NxK matrix when A*A^T is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^T is calculated + * 2 - A^T*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether C is upper triangular or lower triangular + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsyrk(n, k, alpha, a.c_ptr(), ia, ja, optypea, beta, c.c_ptr(), ic, jc, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition, conjugate transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + Beta - coefficient + C - matrix (PREALLOCATED, large enough to store result) + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixgemm(m, n, k, *alpha.c_ptr(), a.c_ptr(), ia, ja, optypea, b.c_ptr(), ib, jb, optypeb, *beta.c_ptr(), c.c_ptr(), ic, jc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + Beta - coefficient + C - PREALLOCATED output matrix, large enough to store result + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixgemm(m, n, k, alpha, a.c_ptr(), ia, ja, optypea, b.c_ptr(), ib, jb, optypeb, beta, c.c_ptr(), ic, jc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine is an older version of CMatrixHERK(), one with wrong name +(it is HErmitian update, not SYmmetric). It is left here for backward +compatibility. + + -- ALGLIB routine -- + 16.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixsyrk(n, k, alpha, a.c_ptr(), ia, ja, optypea, beta, c.c_ptr(), ic, jc, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +QR decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form (see below). + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. + +The elements of matrix R are located on and above the main diagonal of +matrix A. The elements which are located in Tau array and below the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(k-1), + +where k = min(m,n), and each H(i) is in the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, +so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixqr(a.c_ptr(), m, n, tau.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LQ decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices L and Q in compact form (see below) + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0..Min(M,N)-1]. + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. + +The elements of matrix L are located on and below the main diagonal of +matrix A. The elements which are located in Tau array and above the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(k-1)*H(k-2)*...*H(1)*H(0), + +where k = min(m,n), and each H(i) is of the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, +v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlq(a.c_ptr(), m, n, tau.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +QR decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixqr(a.c_ptr(), m, n, tau.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LQ decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and L in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlq(a.c_ptr(), m, n, tau.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Partial unpacking of matrix Q from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixQR subroutine. + QColumns - required number of columns of matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose indexes range within [0..M-1, 0..QColumns-1]. + If QColumns=0, the array remains unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixqrunpackq(a.c_ptr(), m, n, tau.c_ptr(), qcolumns, q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixqrunpackr(a.c_ptr(), m, n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Partial unpacking of matrix Q from the LQ decomposition of a matrix A + +Input parameters: + A - matrices L and Q in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixLQ subroutine. + QRows - required number of rows in matrix Q. N>=QRows>=0. + +Output parameters: + Q - first QRows rows of matrix Q. Array whose indexes range + within [0..QRows-1, 0..N-1]. If QRows=0, the array remains + unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlqunpackq(a.c_ptr(), m, n, tau.c_ptr(), qrows, q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlqunpackl(a.c_ptr(), m, n, l.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Partial unpacking of matrix Q from QR decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixQR subroutine . + QColumns - required number of columns in matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose index ranges within [0..M-1, 0..QColumns-1]. + If QColumns=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixqrunpackq(a.c_ptr(), m, n, tau.c_ptr(), qcolumns, q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixqrunpackr(a.c_ptr(), m, n, r.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixLQ subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixLQ subroutine . + QRows - required number of rows in matrix Q. N>=QColumns>=0. + +Output parameters: + Q - first QRows rows of matrix Q. + Array whose index ranges within [0..QRows-1, 0..N-1]. + If QRows=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlqunpackq(a.c_ptr(), m, n, tau.c_ptr(), qrows, q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of CMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlqunpackl(a.c_ptr(), m, n, l.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Reduction of a rectangular matrix to bidiagonal form + +The algorithm reduces the rectangular matrix A to bidiagonal form by +orthogonal transformations P and Q: A = Q*B*(P^T). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - source matrix. array[0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q, B, P in compact form (see below). + TauQ - scalar factors which are used to form matrix Q. + TauP - scalar factors which are used to form matrix P. + +The main diagonal and one of the secondary diagonals of matrix A are +replaced with bidiagonal matrix B. Other elements contain elementary +reflections which form MxM matrix Q and NxN matrix P, respectively. + +If M>=N, B is the upper bidiagonal MxN matrix and is stored in the +corresponding elements of matrix A. Matrix Q is represented as a +product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where +H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and +vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is +stored in elements A(i+1:m-1,i). Matrix P is as follows: P = +G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], +u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). + +If M n): m=5, n=6 (m < n): + +( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) +( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) +( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) +( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) +( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) +( v1 v2 v3 v4 v5 ) + +Here vi and ui are vectors which form H(i) and G(i), and d and e - +are the diagonal and off-diagonal elements of matrix B. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbd(a.c_ptr(), m, n, tauq.c_ptr(), taup.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix Q which reduces a matrix to bidiagonal form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + QColumns - required number of columns in matrix Q. + M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array[0..M-1, 0..QColumns-1] + If QColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbdunpackq(qp.c_ptr(), m, n, tauq.c_ptr(), qcolumns, q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication by matrix Q which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by Q or Q'. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + Z - multiplied matrix. + array[0..ZRows-1,0..ZColumns-1] + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=M, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=M, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by Q or Q'. + +Output parameters: + Z - product of Z and Q. + Array[0..ZRows-1,0..ZColumns-1] + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbdmultiplybyq(qp.c_ptr(), m, n, tauq.c_ptr(), z.c_ptr(), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix P which reduces matrix A to bidiagonal form. +The subroutine returns transposed matrix P. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of ToBidiagonal subroutine. + PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. + +Output parameters: + PT - first PTRows columns of matrix P^T + Array[0..PTRows-1, 0..N-1] + If PTRows=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbdunpackpt(qp.c_ptr(), m, n, taup.c_ptr(), ptrows, pt.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication by matrix P which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by P or P'. + +Input parameters: + QP - matrices Q and P in compact form. + Output of RMatrixBD subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of RMatrixBD subroutine. + Z - multiplied matrix. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=N, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=N, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by P or P'. + +Output parameters: + Z - product of Z and P. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbdmultiplybyp(qp.c_ptr(), m, n, taup.c_ptr(), z.c_ptr(), zrows, zcolumns, fromtheright, dotranspose, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking of the main and secondary diagonals of bidiagonal decomposition +of matrix A. + +Input parameters: + B - output of RMatrixBD subroutine. + M - number of rows in matrix B. + N - number of columns in matrix B. + +Output parameters: + IsUpper - True, if the matrix is upper bidiagonal. + otherwise IsUpper is False. + D - the main diagonal. + Array whose index ranges within [0..Min(M,N)-1]. + E - the secondary diagonal (upper or lower, depending on + the value of IsUpper). + Array index ranges within [0..Min(M,N)-1], the last + element is not used. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixbdunpackdiagonals(b.c_ptr(), m, n, &isupper, d.c_ptr(), e.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, +where Q is an orthogonal matrix, H - Hessenberg matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix A with elements [0..N-1, 0..N-1] + N - size of matrix A. + +Output parameters: + A - matrices Q and P in compact form (see below). + Tau - array of scalar factors which are used to form matrix Q. + Array whose index ranges within [0..N-2] + +Matrix H is located on the main diagonal, on the lower secondary diagonal +and above the main diagonal of matrix A. The elements which are used to +form matrix Q are situated in array Tau and below the lower secondary +diagonal of matrix A as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(n-2), + +where each H(i) is given by + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - is a real vector, +so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixhessenberg(a.c_ptr(), n, tau.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix Q which reduces matrix A to upper Hessenberg form + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + Tau - scalar factors which are used to form Q. + Output of RMatrixHessenberg subroutine. + +Output parameters: + Q - matrix Q. + Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixhessenbergunpackq(a.c_ptr(), n, tau.c_ptr(), q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + +Output parameters: + H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixhessenbergunpackh(a.c_ptr(), n, h.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Reduction of a symmetric matrix which is given by its higher or lower +triangular part to a tridiagonal matrix using orthogonal similarity +transformation: Q'*A*Q=T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::smatrixtd(a.c_ptr(), n, isupper, tau.c_ptr(), d.c_ptr(), e.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix Q which reduces symmetric matrix to a tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a SMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of SMatrixTD subroutine) + Tau - the result of a SMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::smatrixtdunpackq(a.c_ptr(), n, isupper, tau.c_ptr(), q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Reduction of a Hermitian matrix which is given by its higher or lower +triangular part to a real tridiagonal matrix using unitary similarity +transformation: Q'*A*Q = T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of real symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of real symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + +where d and e denote diagonal and off-diagonal elements of T, and vi +denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hmatrixtd(a.c_ptr(), n, isupper, tau.c_ptr(), d.c_ptr(), e.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a HMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of HMatrixTD subroutine) + Tau - the result of a HMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hmatrixtdunpackq(a.c_ptr(), n, isupper, tau.c_ptr(), q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Generation of a random uniformly distributed (Haar) orthogonal matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrndorthogonal(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN matrix with given condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of a random Haar distributed orthogonal complex matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrndorthogonal(n, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN complex matrix with given condition number C and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN symmetric matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::smatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN symmetric positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random SPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN Hermitian matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hmatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Generation of random NxN Hermitian positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random HPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixrndcond(n, c, a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrndorthogonalfromtheright(a.c_ptr(), m, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixrndorthogonalfromtheleft(a.c_ptr(), m, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication of MxN complex matrix by NxN random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrndorthogonalfromtheright(a.c_ptr(), m, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Multiplication of MxN complex matrix by MxM random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixrndorthogonalfromtheleft(a.c_ptr(), m, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Symmetric multiplication of NxN matrix by random Haar distributed +orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q'*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndmultiply(real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::smatrixrndmultiply(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Hermitian multiplication of NxN matrix by random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q^H*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hmatrixrndmultiply(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void sparseserialize(const sparsematrix &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::sparsealloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::sparseserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void sparseserialize(const sparsematrix &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::sparsealloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::sparseserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void sparseunserialize(const std::string &s_in, sparsematrix &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::sparseunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void sparseunserialize(const std::istream &s_in, sparsematrix &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::sparseunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +This function creates sparse matrix in a Hash-Table format. + +This function creates Hast-Table matrix, which can be converted to CRS +format after its initialization is over. Typical usage scenario for a +sparse matrix is: +1. creation in a Hash-Table format +2. insertion of the matrix elements +3. conversion to the CRS representation +4. matrix is passed to some linear algebra algorithm + +Some information about different matrix formats can be found below, in +the "NOTES" section. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + +NOTE 1 + +Hash-tables use memory inefficiently, and they have to keep some amount +of the "spare memory" in order to have good performance. Hash table for +matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, +where C is a small constant, about 1.5-2 in magnitude. + +CRS storage, from the other side, is more memory-efficient, and needs +just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows +in a matrix. + +When you convert from the Hash-Table to CRS representation, all unneeded +memory will be freed. + +NOTE 2 + +Comments of SparseMatrix structure outline information about different +sparse storage formats. We recommend you to read them before starting to +use ALGLIB sparse matrices. + +NOTE 3 + +This function completely overwrites S with new sparse matrix. Previously +allocated storage is NOT reused. If you want to reuse already allocated +memory, call SparseCreateBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreate(m, n, k, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates sparse matrix in a Hash-Table format. + +This function creates Hast-Table matrix, which can be converted to CRS +format after its initialization is over. Typical usage scenario for a +sparse matrix is: +1. creation in a Hash-Table format +2. insertion of the matrix elements +3. conversion to the CRS representation +4. matrix is passed to some linear algebra algorithm + +Some information about different matrix formats can be found below, in +the "NOTES" section. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + +NOTE 1 + +Hash-tables use memory inefficiently, and they have to keep some amount +of the "spare memory" in order to have good performance. Hash table for +matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, +where C is a small constant, about 1.5-2 in magnitude. + +CRS storage, from the other side, is more memory-efficient, and needs +just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows +in a matrix. + +When you convert from the Hash-Table to CRS representation, all unneeded +memory will be freed. + +NOTE 2 + +Comments of SparseMatrix structure outline information about different +sparse storage formats. We recommend you to read them before starting to +use ALGLIB sparse matrices. + +NOTE 3 + +This function completely overwrites S with new sparse matrix. Previously +allocated storage is NOT reused. If you want to reuse already allocated +memory, call SparseCreateBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + + k = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreate(m, n, k, s.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This version of SparseCreate function creates sparse matrix in Hash-Table +format, reusing previously allocated storage as much as possible. Read +comments for SparseCreate() for more information. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + S - SparseMatrix structure which MAY contain some already + allocated storage. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + Previously allocated storage is reused, if its size + is compatible with expected number of non-zeros K. + + -- ALGLIB PROJECT -- + Copyright 14.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatebuf(m, n, k, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This version of SparseCreate function creates sparse matrix in Hash-Table +format, reusing previously allocated storage as much as possible. Read +comments for SparseCreate() for more information. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + S - SparseMatrix structure which MAY contain some already + allocated storage. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + Previously allocated storage is reused, if its size + is compatible with expected number of non-zeros K. + + -- ALGLIB PROJECT -- + Copyright 14.01.2014 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsecreatebuf(const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + + k = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatebuf(m, n, k, s.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function creates sparse matrix in a CRS format - the least flexible +but the most efficient format implemented in ALGLIB. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell the number of non-zero elements at each row + at this moment) +2. initialization of the matrix elements (row by row, from left to right) +3. the matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrs(m, n, ner.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates sparse matrix in a CRS format (expert function for +situations when you are running out of memory). This version of CRS +matrix creation function may reuse memory already allocated in S. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell number of non-zero elements at each row at + this moment) +2. insertion of the matrix elements (row by row, from left to right) +3. matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices.. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + S - sparse matrix structure with possibly preallocated + memory. + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsbuf(m, n, ner.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. + +The empty matrix is a degenerate 0*N-dimensional matrix which can be used +ONLY for: +* appending rows with sparseappendcompressedrow() +* appending non-degenerate CRS matrices with sparseappendmatrix() +Before the first row is appended, the matrix is in a special intermediate +state. After the first append it becomes a standard CRS matrix. + +The main purpose of this function is to simplify step-by-step initialization +of CRS matrices. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSEmptyBuf function. + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsempty(const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsempty(n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +This function creates an EMPTY sparse matrix stored in the CRS format. It +is a buffered version of the function which reuses previosly allocated +space as much as possible. + +INPUT PARAMETERS + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse 0*N matrix in a partially initialized state + + -- ALGLIB PROJECT -- + Copyright 20.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsemptybuf(const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsemptybuf(n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdense(const real_2d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdense(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsecreatecrsfromdense(const real_2d_array &a, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t m; + ae_int_t n; + + m = a.rows(); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdense(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. +A buffered version which reused memory already allocated in S as much as +possible. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensebuf(const real_2d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdensebuf(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. +A buffered version which reused memory already allocated in S as much as +possible. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsecreatecrsfromdensebuf(const real_2d_array &a, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t m; + ae_int_t n; + + m = a.rows(); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdensebuf(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function creates a CRS-based sparse matrix from a dense vector +which stores a dense 1-dimensional representation of a dense M*N matrix. + +This function is intended for situations when you already have a dense +vector and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M*N]. If larger, only leading M*N elements + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensev(const real_1d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdensev(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates a CRS-based sparse matrix from a dense vector +which stores a dense 1-dimensional representation of a dense M*N matrix. +A buffered version which reused memory already allocated in S as much as +possible. + +This function is intended for situations when you already have a dense +vector and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M*N]. If larger, only leading M*N elements + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensevbuf(const real_1d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromdensevbuf(a.c_ptr(), m, n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +This function creates a sparse CRS-based matrix from subset of rows of +another CRS-based matrix. Memory already present in Dst is reused as much +as possible. + +INPUT PARAMETERS: + Src - sparse M*N matrix in CRS format. + R0, R1 - half-range of rows to use, [R0,R1) + +OUTPUT PARAMETERS: + Dst - (R1-R0)*N matrix in the CRS format, subset of Src + + -- ALGLIB PROJECT -- + Copyright 2024.03.23 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromcrsrangebuf(const sparsematrix &src, const ae_int_t r0, const ae_int_t r1, sparsematrix &dst, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatecrsfromcrsrangebuf(src.c_ptr(), r0, r1, dst.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], D[I]>=0. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], U[I]>=0. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateSKSBuf function. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesks(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatesks(m, n, d.c_ptr(), u.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is "buffered" version of SparseCreateSKS() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], 0<=D[I]<=I. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], 0<=U[I]<=I. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatesksbuf(m, n, d.c_ptr(), u.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). Unlike more general sparsecreatesks(), this function creates +sparse matrix with constant bandwidth. + +You may want to use this function instead of sparsecreatesks() when your +matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - matrix bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call sparsecreatesksbandbuf function. + + -- ALGLIB PROJECT -- + Copyright 25.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksband(const ae_int_t m, const ae_int_t n, const ae_int_t bw, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatesksband(m, n, bw, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is "buffered" version of sparsecreatesksband() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +You may want to use this function instead of sparsecreatesksbuf() when +your matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbandbuf(const ae_int_t m, const ae_int_t n, const ae_int_t bw, sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecreatesksbandbuf(m, n, bw, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function copies S0 to S1. +This function completely deallocates memory owned by S1 before creating a +copy of S0. If you want to reuse memory, use SparseCopyBuf. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopy(const sparsematrix &s0, sparsematrix &s1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecopy(s0.c_ptr(), s1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +This function copies S0 to S1. +Memory already allocated in S1 is reused as much as possible. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopybuf(const sparsematrix &s0, sparsematrix &s1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecopybuf(s0.c_ptr(), s1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function efficiently swaps contents of S0 and S1. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparseswap(sparsematrix &s0, sparsematrix &s1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparseswap(s0.c_ptr(), s1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function adds value to S[i,j] - element of the sparse matrix. Matrix +must be in a Hash-Table mode. + +In case S[i,j] already exists in the table, V i added to its value. In +case S[i,j] is non-existent, it is inserted in the table. Table +automatically grows when necessary. + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + Exception will be thrown for CRS matrix. + I - row index of the element to modify, 0<=I op(S) = S + * OpS=1 => op(S) = S^T + X - input vector, must have at least Cols(op(S))+IX elements + IX - subvector offset + Beta - destination coefficient + Y - preallocated output array, must have at least Rows(op(S))+IY elements + IY - subvector offset + +OUTPUT PARAMETERS + Y - elements [IY...IY+Rows(op(S))-1] are replaced by result, + other elements are not modified + +HANDLING OF SPECIAL CASES: +* below M=Rows(op(S)) and N=Cols(op(S)). Although current ALGLIB version + does not allow you to create zero-sized sparse matrices, internally + ALGLIB can deal with such matrices. So, comments for M or N equal to + zero are for internal use only. +* if M=0, then subroutine does nothing. It does not even touch arrays. +* if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. S and X are not referenced at + all. Initial values of Y are ignored (we do not multiply Y by zero, + we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y +* if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by alpha*op(S)*x + initial state of Y is ignored (rewritten without initial multiplication + by zeros). + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 10.12.2019 by Bochkanov Sergey +*************************************************************************/ +void sparsegemv(const sparsematrix &s, const double alpha, const ae_int_t ops, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsegemv(s.c_ptr(), alpha, ops, x.c_ptr(), ix, beta, y.c_ptr(), iy, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function simultaneously calculates two matrix-vector products: + S*x and S^T*x. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + Y1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y0 - array[N], S*x + Y1 - array[N], S^T*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemv2(const sparsematrix &s, const real_1d_array &x, real_1d_array &y0, real_1d_array &y1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemv2(s.c_ptr(), x.c_ptr(), y0.c_ptr(), y1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates matrix-vector product S*x, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y - array[M], S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesmv(s.c_ptr(), isupper, x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function perform in-place multiplication of the matrix columns by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[N], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplycolsby(sparsematrix &s, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemultiplycolsby(s.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function perform in-place multiplication of the matrix rows by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowsby(sparsematrix &s, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemultiplyrowsby(s.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function perform in-place multiplication of the matrix rows and cols +by user-supplied vectors X and Y. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], row multipliers + Y - array[N], column multipliers + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left, and by + diag(Y) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowscolsby(sparsematrix &s, const real_1d_array &x, const real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemultiplyrowscolsby(s.c_ptr(), x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates vector-matrix-vector product x'*S*x, where S is +symmetric matrix. Matrix S must be stored in CRS or SKS format (exception +will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + +RESULT + x'*S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 27.01.2014 by Bochkanov Sergey +*************************************************************************/ +double sparsevsmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::sparsevsmv(s.c_ptr(), isupper, x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +This function calculates matrix-matrix product S*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size + is at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemm(s.c_ptr(), a.c_ptr(), k, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates matrix-matrix product S^T*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[M][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least M, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemtm(s.c_ptr(), a.c_ptr(), k, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function simultaneously calculates two matrix-matrix products: + S*A and S^T*A. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + B1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B0 - array[N][K], S*A + B1 - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemm2(s.c_ptr(), a.c_ptr(), k, b0.c_ptr(), b1.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates matrix-matrix product S*A, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesmm(s.c_ptr(), isupper, a.c_ptr(), k, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function calculates matrix-vector product op(S)*x, when x is vector, +S is symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + Y - possibly preallocated input buffer. Automatically + resized if its size is too small. + +OUTPUT PARAMETERS + Y - array[N], op(S)*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrmv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsetrmv(s.c_ptr(), isupper, isunit, optype, x.c_ptr(), y.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves linear system op(S)*y=x where x is vector, S is +symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used. It is your + responsibility to make sure that diagonal is + non-zero. + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + +OUTPUT PARAMETERS + X - array[N], inv(op(S))*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. + You must convert your matrix with SparseConvertToCRS/SKS() before + using this function. + +NOTE: no assertion or tests are done during algorithm operation. It is + your responsibility to provide invertible matrix to algorithm. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrsv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsetrsv(s.c_ptr(), isupper, isunit, optype, x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblBuf() if you want to reuse already allocated structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbl(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesymmpermtbl(a.c_ptr(), isupper, p.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblTransposeBuf() if you want to reuse an already allocated +structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltranspose(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesymmpermtbltranspose(a.c_ptr(), isupper, p.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is a buffered version of SparseSymmPermTbl() that reuses +previously allocated storage in B as much as possible. + +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtblbuf(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesymmpermtblbuf(a.c_ptr(), isupper, p.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function reuses memory already allocated in B as much as possible. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltransposebuf(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesymmpermtbltransposebuf(a.c_ptr(), isupper, p.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This procedure resizes Hash-Table matrix. It can be called when you have +deleted too many elements from the matrix, and you want to free unneeded +memory. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseresizematrix(sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparseresizematrix(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to enumerate all elements of the sparse matrix. +Before first call user initializes T0 and T1 counters by zero. These +counters are used to remember current position in a matrix; after each +call they are updated by the function. + +Subsequent calls to this function return non-zero elements of the sparse +matrix, one by one. If you enumerate CRS matrix, matrix is traversed from +left to right, from top to bottom. In case you enumerate matrix stored as +Hash table, elements are returned in random order. + +EXAMPLE + > T0=0 + > T1=0 + > while SparseEnumerate(S,T0,T1,I,J,V) do + > ....do something with I,J,V + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table or CRS representation. + T0 - internal counter + T1 - internal counter + +OUTPUT PARAMETERS + T0 - new value of the internal counter + T1 - new value of the internal counter + I - row index of non-zero element, 0<=I=0. Both ColIdx[] and Vals[] can + be longer than NZ, in which case only leading NZ + elements are used. + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + +NOTE: this function has amortized O(NZ*logNZ) cost. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendcompressedrow(sparsematrix &s, const integer_1d_array &colidx, const real_1d_array &vals, const ae_int_t nz, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparseappendcompressedrow(s.c_ptr(), colidx.c_ptr(), vals.c_ptr(), nz, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends an empty row to a CRS matrix, increasing its rows +count by 1. The newly added row can be modified with sparseappendelement(). +The matrix is a valid CRS matrix at any moment of the process. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format, including one created + with sparsecreatecrsempty(). + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendemptyrow(sparsematrix &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparseappendemptyrow(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends an element to the last row of a CRS matrix. New +elements can be added ONLY from left to right (column indexes are strictly +increasing). + +INPUT PARAMETERS: + S - a fully initialized sparse M*N matrix in CRS format, M>0 + K - column index, 0<=K0 + C - array[N], col scales, C[i]>0 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. + +NOTE: this function works with general (nonsymmetric) matrices. See + sparsesymmscale() for a symmetric version. See sparsescalebuf() for + a version which reuses space already present in output arrays R/C. + +NOTE: if both ScaleRows=False and ScaleCols=False, this function returns + an identity scaling. + +NOTE: R[] and C[] are guaranteed to be strictly positive. When the matrix + has zero rows/cols, corresponding elements of R/C are set to 1. + + -- ALGLIB PROJECT -- + Copyright 12.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsescale(sparsematrix &s, const ae_int_t scltype, const bool scalerows, const bool scalecols, const bool colsfirst, real_1d_array &r, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsescale(s.c_ptr(), scltype, scalerows, scalecols, colsfirst, r.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tries to gather values from Src to Dst, zeroing out elements +of Dst not present in Src. + +Both matrices must be in the CRS format and must have exactly the same +size. The sparsity pattern of Src must be a subset of that of Dst. + +If Src contains non-zero elements not present in Dst, gather operation is +stopped in the middle (leaving Dst values partially changed but otherwise +fully functional) and False is returned. + +INPUT PARAMETERS + Dst - sparse M*N destination matrix in CRS format. + Src - sparse M*N source matrix in CRS format. + +OUTPUT PARAMETERS + Dst - if True is returned, contains elements of Src and + zeros in other positions. If False is returned, its + values are only partially initialized. + +RESULT: + True if successful. False if the sparsity pattern of Src is not a + subset of that of Dst. + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +bool sparsetrygatherclear(sparsematrix &dst, const sparsematrix &src, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsetrygatherclear(dst.c_ptr(), src.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +This function merges sparsity patterns of S1 and S2 and stores result into +Dst, reusing previously allocated memory as much as possible. + +Both matrices must be in the CRS format and must have exactly the same +size. + +INPUT PARAMETERS + S1, S2 - sparse M*N source matrices in CRS format. + Dst - previously allocated sparse matrix structure in any + storage format and of any size. + +OUTPUT PARAMETERS + Dst - sparse M*N matrix in CRS format, zero-initialized, has + sparsity pattern equal to union of S1 and S2 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +void sparsemergepatterns(const sparsematrix &s1, const sparsematrix &s2, sparsematrix &dst, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsemergepatterns(s1.c_ptr(), s2.c_ptr(), dst.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Sparse matrix structure. + +You should use ALGLIB functions to work with sparse matrix. Never try to +access its fields directly! + +NOTES ON THE SPARSE STORAGE FORMATS + +Sparse matrices can be stored using several formats: +* Hash-Table representation +* Compressed Row Storage (CRS) +* Skyline matrix storage (SKS) + +Each of the formats has benefits and drawbacks: +* Hash-table is good for dynamic operations (insertion of new elements), + but does not support linear algebra operations +* CRS is good for operations like matrix-vector or matrix-matrix products, + but its initialization is less convenient - you have to tell row sizes + at the initialization, and you have to fill matrix only row by row, + from left to right. +* SKS is a special format which is used to store triangular factors from + Cholesky factorization. It does not support dynamic modification, and + support for linear algebra operations is very limited. + +Tables below outline information about these two formats: + + OPERATIONS WITH MATRIX HASH CRS SKS + creation + + + + SparseGet + + + + SparseExists + + + + SparseRewriteExisting + + + + SparseSet + + + + SparseAdd + + SparseGetRow + + + SparseGetCompressedRow + + + SparseAppendCompressedRow + + sparse-dense linear algebra + + +*************************************************************************/ +_sparsematrix_owner::_sparsematrix_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsematrix_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsematrix)); + alglib_impl::_sparsematrix_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsematrix_owner::_sparsematrix_owner(alglib_impl::sparsematrix *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_sparsematrix_owner::_sparsematrix_owner(const _sparsematrix_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsematrix_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsematrix copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::sparsematrix*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsematrix), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsematrix)); + alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsematrix_owner& _sparsematrix_owner::operator=(const _sparsematrix_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: sparsematrix assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsematrix assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: sparsematrix assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_sparsematrix_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::sparsematrix)); + alglib_impl::_sparsematrix_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_sparsematrix_owner::~_sparsematrix_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_sparsematrix_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::sparsematrix* _sparsematrix_owner::c_ptr() const +{ + return p_struct; +} +sparsematrix::sparsematrix() : _sparsematrix_owner() +{ +} + +sparsematrix::sparsematrix(alglib_impl::sparsematrix *attach_to):_sparsematrix_owner(attach_to) +{ +} + +sparsematrix::sparsematrix(const sparsematrix &rhs):_sparsematrix_owner(rhs) +{ +} + +sparsematrix& sparsematrix::operator=(const sparsematrix &rhs) +{ + if( this==&rhs ) + return *this; + _sparsematrix_owner::operator=(rhs); + return *this; +} + +sparsematrix::~sparsematrix() +{ +} + + + + +/************************************************************************* +Temporary buffers for sparse matrix operations. + +You should pass an instance of this structure to factorization functions. +It allows to reuse memory during repeated sparse factorizations. You do +not have to call some initialization function - simply passing an instance +to factorization function is enough. +*************************************************************************/ +_sparsebuffers_owner::_sparsebuffers_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsebuffers_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::sparsebuffers*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsebuffers), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsebuffers)); + alglib_impl::_sparsebuffers_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsebuffers_owner::_sparsebuffers_owner(alglib_impl::sparsebuffers *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_sparsebuffers_owner::_sparsebuffers_owner(const _sparsebuffers_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsebuffers_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsebuffers copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::sparsebuffers*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsebuffers), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsebuffers)); + alglib_impl::_sparsebuffers_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsebuffers_owner& _sparsebuffers_owner::operator=(const _sparsebuffers_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: sparsebuffers assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsebuffers assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: sparsebuffers assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_sparsebuffers_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::sparsebuffers)); + alglib_impl::_sparsebuffers_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_sparsebuffers_owner::~_sparsebuffers_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_sparsebuffers_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::sparsebuffers* _sparsebuffers_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::sparsebuffers* _sparsebuffers_owner::c_ptr() const +{ + return p_struct; +} +sparsebuffers::sparsebuffers() : _sparsebuffers_owner() +{ +} + +sparsebuffers::sparsebuffers(alglib_impl::sparsebuffers *attach_to):_sparsebuffers_owner(attach_to) +{ +} + +sparsebuffers::sparsebuffers(const sparsebuffers &rhs):_sparsebuffers_owner(rhs) +{ +} + +sparsebuffers& sparsebuffers::operator=(const sparsebuffers &rhs) +{ + if( this==&rhs ) + return *this; + _sparsebuffers_owner::operator=(rhs); + return *this; +} + +sparsebuffers::~sparsebuffers() +{ +} +#endif + +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes subspace iteration solver. This solver is used +to solve symmetric real eigenproblems where just a few (top K) eigenvalues +and corresponding eigenvectors is required. + +This solver can be significantly faster than complete EVD decomposition +in the following case: +* when only just a small fraction of top eigenpairs of dense matrix is + required. When K approaches N, this solver is slower than complete dense + EVD +* when problem matrix is sparse (and/or is not known explicitly, i.e. only + matrix-matrix product can be performed) + +USAGE (explicit dense/sparse matrix): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User calls eigsubspacesolvedense() or eigsubspacesolvesparse() methods, + which take algorithm state and 2D array or alglib.sparsematrix object. + +USAGE (out-of-core mode): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User activates out-of-core mode of the solver and repeatedly calls + communication functions in a loop like below: + > alglib.eigsubspaceoocstart(state) + > while alglib.eigsubspaceooccontinue(state) do + > alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) + > alglib.eigsubspaceoocgetrequestdata(state, out X) + > [calculate Y=A*X, with X=R^NxM] + > alglib.eigsubspaceoocsendresult(state, in Y) + > alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + N - problem dimensionality, N>0 + K - number of top eigenvector to calculate, 0=0, with non-zero value used to tell solver that + it can stop after all eigenvalues converged with + error roughly proportional to eps*MAX(LAMBDA_MAX), + where LAMBDA_MAX is a maximum eigenvalue. + Zero value means that no check for precision is + performed. + MaxIts - maxits>=0, with non-zero value used to tell solver + that it can stop after maxits steps (no matter how + precise current estimate is) + +NOTE: passing eps=0 and maxits=0 results in automatic selection of + moderate eps as stopping criteria (1.0E-6 in current implementation, + but it may change without notice). + +NOTE: very small values of eps are possible (say, 1.0E-12), although the + larger problem you solve (N and/or K), the harder it is to find + precise eigenvectors because rounding errors tend to accumulate. + +NOTE: passing non-zero eps results in some performance penalty, roughly + equal to 2N*(2K)^2 FLOPs per iteration. These additional computations + are required in order to estimate current error in eigenvalues via + Rayleigh-Ritz process. + Most of this additional time is spent in construction of ~2Kx2K + symmetric subproblem whose eigenvalues are checked with exact + eigensolver. + This additional time is negligible if you search for eigenvalues of + the large dense matrix, but may become noticeable on highly sparse + EVD problems, where cost of matrix-matrix product is low. + If you set eps to exactly zero, Rayleigh-Ritz phase is completely + turned off. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetcond(eigsubspacestate &state, const double eps, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspacesetcond(state.c_ptr(), eps, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets warm-start mode of the solver: next call to the solver +will reuse previous subspace as warm-start point. It can significantly +speed-up convergence when you solve many similar eigenproblems. + +INPUT PARAMETERS: + State - solver structure + UseWarmStart- either True or False + + -- ALGLIB -- + Copyright 12.11.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetwarmstart(eigsubspacestate &state, const bool usewarmstart, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspacesetwarmstart(state.c_ptr(), usewarmstart, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initiates out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver object + MType - matrix type and solver mode: + + * 0 = real symmetric matrix A, products of the form + A*X are computed. At every step the basis of + the invariant subspace is reorthogonalized + with LQ decomposition which makes the algo + more robust. + + The first mode introduced in ALGLIB, the most + precise and robust. However, it is suboptimal + for easy problems which can be solved in 3-5 + iterations without LQ step. + + * 1 = real symmetric matrix A, products of the form + A*X are computed. The invariant subspace is + NOT reorthogonalized, no error checks. The + solver stops after specified number of + iterations which should be small, 5 at most. + + This mode is intended for easy problems with + extremely fast convergence. + + Future versions of ALGLIB may introduce support for + other matrix types; for now, only symmetric + eigenproblems are supported. + + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstart(eigsubspacestate &state, const ae_int_t mtype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspaceoocstart(state.c_ptr(), mtype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function performs subspace iteration in the out-of-core mode. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +bool eigsubspaceooccontinue(eigsubspacestate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::eigsubspaceooccontinue(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: request type (current version of the solver +sends only requests for matrix-matrix products) and request size (size of +the matrices being multiplied). + +This function returns just request metrics; in order to get contents of +the matrices being multiplied, use eigsubspaceoocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 - for matrix-matrix product A*X, with A being + NxN matrix whose eigenvalues/vectors are needed, + and X being NxREQUESTSIZE one which is returned + by the eigsubspaceoocgetrequestdata(). + RequestSize - size of the X matrix (number of columns), usually + it is several times larger than number of vectors + K requested by user. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestinfo(eigsubspacestate &state, ae_int_t &requesttype, ae_int_t &requestsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspaceoocgetrequestinfo(state.c_ptr(), &requesttype, &requestsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: matrix X (array[N,RequestSize) which have to +be multiplied by out-of-core matrix A in a product A*X. + +This function returns just request data; in order to get size of the data +prior to processing requestm, use eigsubspaceoocgetrequestinfo(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N,RequestSize] or larger, leading rectangle + is filled with dense matrix X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestdata(eigsubspacestate &state, real_2d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspaceoocgetrequestdata(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +solver. Usually it is product A*X for returned by solver matrix X. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N,RequestSize] or larger, leading rectangle + is filled with product A*X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocsendresult(eigsubspacestate &state, const real_2d_array &ax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspaceoocsendresult(state.c_ptr(), ax.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function finalizes out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + W - array[K], depending on solver settings: + * top K eigenvalues ordered by descending - if + eigenvectors are returned in Z + * zeros - if invariant subspace is returned in Z + Z - array[N,K], depending on solver settings either: + * matrix of eigenvectors found + * orthogonal basis of K-dimensional invariant subspace + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstop(eigsubspacestate &state, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspaceoocstop(state.c_ptr(), w.c_ptr(), z.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function runs subspace eigensolver for dense NxN symmetric matrix A, +given by its upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - array[N,N], symmetric NxN matrix given by one of its + triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + +NOTE: internally this function allocates a copy of NxN dense A. You should + take it into account when working with very large matrices occupying + almost all RAM. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvedenses(eigsubspacestate &state, const real_2d_array &a, const bool isupper, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspacesolvedenses(state.c_ptr(), a.c_ptr(), isupper, w.c_ptr(), z.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function runs eigensolver for dense NxN symmetric matrix A, given by +upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - NxN symmetric matrix given by one of its triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvesparses(eigsubspacestate &state, const sparsematrix &a, const bool isupper, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::eigsubspacesolvesparses(state.c_ptr(), a.c_ptr(), isupper, w.c_ptr(), z.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a symmetric matrix + +The algorithm finds eigen pairs of a symmetric matrix by reducing it to +tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpper - storage format. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixevd(a.c_ptr(), n, zneeded, isupper, d.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric +matrix in a given half open interval (A, B] by using a bisection and +inverse iteration + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half open interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval (M>=0). + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, + M is equal to 0. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixevdr(a.c_ptr(), n, zneeded, isupper, b1, b2, &m, w.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a symmetric +matrix with given indexes by using bisection and inverse iteration methods. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixevdi(a.c_ptr(), n, zneeded, isupper, i1, i2, w.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a Hermitian matrix + +The algorithm finds eigen pairs of a Hermitian matrix by reducing it to +real tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +Note: + eigenvectors of Hermitian matrix are defined up to multiplication by + a complex number L, such that |L|=1. + + -- ALGLIB -- + Copyright 2005, 23 March 2007 by Bochkanov Sergey +*************************************************************************/ +bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hmatrixevd(a.c_ptr(), n, zneeded, isupper, d.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian +matrix in a given half-interval (A, B] by using a bisection and inverse +iteration + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. Array whose indexes range within + [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half-interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval, M>=0 + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, M is + equal to 0. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hmatrixevdr(a.c_ptr(), n, zneeded, isupper, b1, b2, &m, w.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a Hermitian +matrix with given indexes by using bisection and inverse iteration methods + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix + columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hmatrixevdi(a.c_ptr(), n, zneeded, isupper, i1, i2, w.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix + +The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by +using an QL/QR algorithm with implicit shifts. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix + are multiplied by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity + transformation of a symmetric matrix; + * 2, the eigenvectors of a tridiagonal matrix replace the + square matrix Z; + * 3, matrix Z contains the first row of the eigenvectors + matrix. + Z - if ZNeeded=1, Z contains the square matrix by which the + eigenvectors are multiplied. + Array whose indexes range within [0..N-1, 0..N-1]. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the product of a given matrix (from the left) + and the eigenvectors matrix (from the right); + * 2, Z contains the eigenvectors. + * 3, Z contains the first row of the eigenvectors matrix. + If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. + In that case, the eigenvectors are stored in the matrix columns. + If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixtdevd(d.c_ptr(), e.c_ptr(), n, zneeded, z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a +given half-interval (A, B] by using bisection and inverse iteration. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix, N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the tridiagonal + matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. + A, B - half-interval (A, B] to search eigenvalues in. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range + within [0..N-1, 0..N-1]) which reduces the given symmetric + matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + M - number of eigenvalues found in the given half-interval (M>=0). + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the + left) and NxM matrix of the eigenvectors found (from the + right). Array whose indexes range within [0..N-1, 0..M-1]. + * 2, contains the matrix of the eigenvectors found. + Array whose indexes range within [0..N-1, 0..M-1]. + +Result: + + True, if successful. In that case, M contains the number of eigenvalues + in the given half-interval (could be equal to 0), D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. In that case, + the eigenvalues and eigenvectors are not returned, M is equal to 0. + + -- ALGLIB -- + Copyright 31.03.2008 by Bochkanov Sergey +*************************************************************************/ +bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixtdevdr(d.c_ptr(), e.c_ptr(), n, zneeded, a, b, &m, z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Subroutine for finding tridiagonal matrix eigenvalues/vectors with given +indexes (in ascending order) by using the bisection and inverse iteraion. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix. N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace + matrix Z. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) + which reduces the given symmetric matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the left) and + Nx(I2-I1) matrix of the eigenvectors found (from the right). + Array whose indexes range within [0..N-1, 0..I2-I1]. + * 2, contains the matrix of the eigenvalues found. + Array whose indexes range within [0..N-1, 0..I2-I1]. + + +Result: + + True, if successful. In that case, D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the eigenvalues + in the given interval or if the inverse iteration subroutine wasn't able + to find all the corresponding eigenvectors. In that case, the eigenvalues + and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 25.12.2005 by Bochkanov Sergey +*************************************************************************/ +bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixtdevdi(d.c_ptr(), e.c_ptr(), n, zneeded, i1, i2, z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm finds eigenvalues and eigenvectors of a general matrix by +using the QR algorithm with multiple shifts. The algorithm can find +eigenvalues and both left and right eigenvectors. + +The right eigenvector is a vector x such that A*x = w*x, and the left +eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex +conjugate transposition of vector y). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + VNeeded - flag controlling whether eigenvectors are needed or not. + If VNeeded is equal to: + * 0, eigenvectors are not returned; + * 1, right eigenvectors are returned; + * 2, left eigenvectors are returned; + * 3, both left and right eigenvectors are returned. + +Output parameters: + WR - real parts of eigenvalues. + Array whose index ranges within [0..N-1]. + WR - imaginary parts of eigenvalues. + Array whose index ranges within [0..N-1]. + VL, VR - arrays of left and right eigenvectors (if they are needed). + If WI[i]=0, the respective eigenvalue is a real number, + and it corresponds to the column number I of matrices VL/VR. + If WI[i]>0, we have a pair of complex conjugate numbers with + positive and negative imaginary parts: + the first eigenvalue WR[i] + sqrt(-1)*WI[i]; + the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; + WI[i]>0 + WI[i+1] = -WI[i] < 0 + In that case, the eigenvector corresponding to the first + eigenvalue is located in i and i+1 columns of matrices + VL/VR (the column number i contains the real part, and the + column number i+1 contains the imaginary part), and the vector + corresponding to the second eigenvalue is a complex conjugate to + the first vector. + Arrays whose indexes range within [0..N-1, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm has not converged. + +Note 1: + Some users may ask the following question: what if WI[N-1]>0? + WI[N] must contain an eigenvalue which is complex conjugate to the + N-th eigenvalue, but the array has only size N? + The answer is as follows: such a situation cannot occur because the + algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is + strictly less than N-1. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms of linear algebra). If you require maximum performance + on your machine, it is recommended to adjust this parameter manually. + + +See also the InternalTREVC subroutine. + +The algorithm is based on the LAPACK 3.0 library. +*************************************************************************/ +bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixevd(a.c_ptr(), n, vneeded, wr.c_ptr(), wi.c_ptr(), vl.c_ptr(), vr.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +/************************************************************************* +This object stores state of the subspace iteration algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_eigsubspacestate_owner::_eigsubspacestate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_eigsubspacestate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::eigsubspacestate*)alglib_impl::ae_malloc(sizeof(alglib_impl::eigsubspacestate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacestate)); + alglib_impl::_eigsubspacestate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_eigsubspacestate_owner::_eigsubspacestate_owner(alglib_impl::eigsubspacestate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_eigsubspacestate_owner::_eigsubspacestate_owner(const _eigsubspacestate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_eigsubspacestate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: eigsubspacestate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::eigsubspacestate*)alglib_impl::ae_malloc(sizeof(alglib_impl::eigsubspacestate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacestate)); + alglib_impl::_eigsubspacestate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_eigsubspacestate_owner& _eigsubspacestate_owner::operator=(const _eigsubspacestate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: eigsubspacestate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: eigsubspacestate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: eigsubspacestate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_eigsubspacestate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacestate)); + alglib_impl::_eigsubspacestate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_eigsubspacestate_owner::~_eigsubspacestate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_eigsubspacestate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::eigsubspacestate* _eigsubspacestate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::eigsubspacestate* _eigsubspacestate_owner::c_ptr() const +{ + return p_struct; +} +eigsubspacestate::eigsubspacestate() : _eigsubspacestate_owner() +{ +} + +eigsubspacestate::eigsubspacestate(alglib_impl::eigsubspacestate *attach_to):_eigsubspacestate_owner(attach_to) +{ +} + +eigsubspacestate::eigsubspacestate(const eigsubspacestate &rhs):_eigsubspacestate_owner(rhs) +{ +} + +eigsubspacestate& eigsubspacestate::operator=(const eigsubspacestate &rhs) +{ + if( this==&rhs ) + return *this; + _eigsubspacestate_owner::operator=(rhs); + return *this; +} + +eigsubspacestate::~eigsubspacestate() +{ +} + + + + +/************************************************************************* +This object stores state of the subspace iteration algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_eigsubspacereport_owner::_eigsubspacereport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_eigsubspacereport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::eigsubspacereport*)alglib_impl::ae_malloc(sizeof(alglib_impl::eigsubspacereport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacereport)); + alglib_impl::_eigsubspacereport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_eigsubspacereport_owner::_eigsubspacereport_owner(alglib_impl::eigsubspacereport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_eigsubspacereport_owner::_eigsubspacereport_owner(const _eigsubspacereport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_eigsubspacereport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: eigsubspacereport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::eigsubspacereport*)alglib_impl::ae_malloc(sizeof(alglib_impl::eigsubspacereport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacereport)); + alglib_impl::_eigsubspacereport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_eigsubspacereport_owner& _eigsubspacereport_owner::operator=(const _eigsubspacereport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: eigsubspacereport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: eigsubspacereport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: eigsubspacereport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_eigsubspacereport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::eigsubspacereport)); + alglib_impl::_eigsubspacereport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_eigsubspacereport_owner::~_eigsubspacereport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_eigsubspacereport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::eigsubspacereport* _eigsubspacereport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::eigsubspacereport* _eigsubspacereport_owner::c_ptr() const +{ + return p_struct; +} +eigsubspacereport::eigsubspacereport() : _eigsubspacereport_owner() ,iterationscount(p_struct->iterationscount) +{ +} + +eigsubspacereport::eigsubspacereport(alglib_impl::eigsubspacereport *attach_to):_eigsubspacereport_owner(attach_to) ,iterationscount(p_struct->iterationscount) +{ +} + +eigsubspacereport::eigsubspacereport(const eigsubspacereport &rhs):_eigsubspacereport_owner(rhs) ,iterationscount(p_struct->iterationscount) +{ +} + +eigsubspacereport& eigsubspacereport::operator=(const eigsubspacereport &rhs) +{ + if( this==&rhs ) + return *this; + _eigsubspacereport_owner::operator=(rhs); + return *this; +} + +eigsubspacereport::~eigsubspacereport() +{ +} +#endif + +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +LU decomposition of a general real matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlu(a.c_ptr(), m, n, pivots.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LU decomposition of a general real matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixlu(real_2d_array &a, integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t m; + ae_int_t n; + + m = a.rows(); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlu(a.c_ptr(), m, n, pivots.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +LU decomposition of a general complex matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlu(a.c_ptr(), m, n, pivots.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LU decomposition of a general complex matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixlu(complex_2d_array &a, integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t m; + ae_int_t n; + + m = a.rows(); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlu(a.c_ptr(), m, n, pivots.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a Hermitian positive- +definite matrix. The result of an algorithm is a representation of A as +A=U'*U or A=L*L' (here X' denotes conj(X^T)). + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U'*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholesky(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a Hermitian positive- +definite matrix. The result of an algorithm is a representation of A as +A=U'*U or A=L*L' (here X' denotes conj(X^T)). + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U'*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool hpdmatrixcholesky(complex_2d_array &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholesky': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholesky(a.c_ptr(), n, isupper, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite matrix. The result of an algorithm is a representation of A as +A=U^T*U or A=L*L^T + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U^T*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholesky(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite matrix. The result of an algorithm is a representation of A as +A=U^T*U or A=L*L^T + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U^T*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool spdmatrixcholesky(real_2d_array &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholesky': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholesky(a.c_ptr(), n, isupper, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Update of Cholesky decomposition: rank-1 update to original A. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateAdd1Buf(). + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1(real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdateadd1(a.c_ptr(), n, isupper, u.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Update of Cholesky decomposition: rank-1 update to original A. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateAdd1Buf(). + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixcholeskyupdateadd1(real_2d_array &a, const bool isupper, const real_1d_array &u, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=u.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskyupdateadd1': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdateadd1(a.c_ptr(), n, isupper, u.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateFixBuf(). + +"FIXING" EXPLAINED: + + Suppose we have N*N positive definite matrix A. "Fixing" some variable + means filling corresponding row/column of A by zeros, and setting + diagonal element to 1. + + For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: + + ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) + ( A10 A11 A12 A13 ) ( 0 1 0 0 ) + ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) + ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) + + If we have Cholesky decomposition of A, it must be recalculated after + variables were fixed. However, it is possible to use efficient + algorithm, which needs O(K*N^2) time to "fix" K variables, given + Cholesky decomposition of original, "unfixed" A. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + +NOTE: this function is efficient only for moderate amount of updated + variables - say, 0.1*N or 0.3*N. For larger amount of variables it + will still work, but you may get better performance with + straightforward Cholesky. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefix(real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdatefix(a.c_ptr(), n, isupper, fix.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateFixBuf(). + +"FIXING" EXPLAINED: + + Suppose we have N*N positive definite matrix A. "Fixing" some variable + means filling corresponding row/column of A by zeros, and setting + diagonal element to 1. + + For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: + + ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) + ( A10 A11 A12 A13 ) ( 0 1 0 0 ) + ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) + ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) + + If we have Cholesky decomposition of A, it must be recalculated after + variables were fixed. However, it is possible to use efficient + algorithm, which needs O(K*N^2) time to "fix" K variables, given + Cholesky decomposition of original, "unfixed" A. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + +NOTE: this function is efficient only for moderate amount of updated + variables - say, 0.1*N or 0.3*N. For larger amount of variables it + will still work, but you may get better performance with + straightforward Cholesky. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixcholeskyupdatefix(real_2d_array &a, const bool isupper, const boolean_1d_array &fix, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=fix.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskyupdatefix': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdatefix(a.c_ptr(), n, isupper, fix.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Update of Cholesky decomposition: rank-1 update to original A. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +See comments for SPDMatrixCholeskyUpdateAdd1() for more information. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1buf(real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, real_1d_array &bufr, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdateadd1buf(a.c_ptr(), n, isupper, u.c_ptr(), bufr.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +See comments for SPDMatrixCholeskyUpdateFix() for more information. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefixbuf(real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, real_1d_array &bufr, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyupdatefixbuf(a.c_ptr(), n, isupper, fix.c_ptr(), bufr.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse LU decomposition with column pivoting for sparsity and row pivoting +for stability. Input must be square sparse matrix stored in CRS format. + +The algorithm computes LU decomposition of a general square matrix +(rectangular ones are not supported). The result of an algorithm is a +representation of A as A = P*L*U*Q, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=N-1, Pi - permutation matrix for I and P[I] +* Q = QK*...*Q1*Q0, K=N-1, Qi - permutation matrix for I and Q[I] + +This function pivots columns for higher sparsity, and then pivots rows for +stability (larger element at the diagonal). + +INPUT PARAMETERS: + A - sparse NxN matrix in CRS format. An exception is generated + if matrix is non-CRS or non-square. + PivotType- pivoting strategy: + * 0 for best pivoting available (2 in current version) + * 1 for row-only pivoting (NOT RECOMMENDED) + * 2 for complete pivoting which produces most sparse outputs + +OUTPUT PARAMETERS: + A - the result of factorization, matrices L and U stored in + compact form using CRS sparse storage format: + * lower unitriangular L is stored strictly under main diagonal + * upper triangilar U is stored ON and ABOVE main diagonal + P - row permutation matrix in compact form, array[N] + Q - col permutation matrix in compact form, array[N] + +This function always succeeds, i.e. it ALWAYS returns valid factorization, +but for your convenience it also returns boolean value which helps to +detect symbolically degenerate matrices: +* function returns TRUE, if the matrix was factorized AND symbolically + non-degenerate +* function returns FALSE, if the matrix was factorized but U has strictly + zero elements at the diagonal (the factorization is returned anyway). + + + -- ALGLIB routine -- + 03.09.2018 + Bochkanov Sergey +*************************************************************************/ +bool sparselu(sparsematrix &a, const ae_int_t pivottype, integer_1d_array &p, integer_1d_array &q, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparselu(a.c_ptr(), pivottype, p.c_ptr(), q.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky decomposition for skyline matrixm using in-place algorithm +without allocating additional storage. + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite sparse matrix. The result of an algorithm is a representation of +A as A=U^T*U or A=L*L^T + +This function allows to perform very efficient decomposition of low-profile +matrices (average bandwidth is ~5-10 elements). For larger matrices it is +recommended to use supernodal Cholesky decomposition: SparseCholeskyP() or +SparseCholeskyAnalyze()/SparseCholeskyFactorize(). + +INPUT PARAMETERS: + A - sparse matrix in skyline storage (SKS) format. + N - size of matrix A (can be smaller than actual size of A) + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored (it may contant some + data, but it is not changed). + + +OUTPUT PARAMETERS: + A - the result of factorization, stored in SKS. If IsUpper=True, + then the upper triangle contains matrix U, such that + A = U^T*U. Lower triangle is not changed. + Similarly, if IsUpper = False. In this case L is returned, + and we have A = L*(L^T). + Note that THIS function does not perform permutation of + rows to reduce bandwidth. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.01.2014 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyskyline(sparsematrix &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsecholeskyskyline(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage, +without rows/cols permutation. + +This function is the most convenient (less parameters to specify) although +the less efficient, version of sparse Cholesky. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +Internally it: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with no permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization + +Following alternatives may result in better performance: +* using SparseCholeskyP(), which selects best pivoting available, which + almost always results in improved sparsity and cache locality +* using SparseCholeskyAnalyze() and SparseCholeskyFactorize() functions + directly, which may improve performance of repetitive factorizations + with same sparsity patterns. + +The latter also allows one to perform LDLT factorization of indefinite +matrix (one with strictly diagonal D, which is known to be stable only +in few special cases, like quasi-definite matrices). + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + Note that THIS function does not perform permutation of + the rows to reduce fill-in. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholesky(sparsematrix &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsecholesky(a.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage +format, with performance-enhancing permutation of rows/cols. + +Present version is configured to perform supernodal permutation with +a sparsity reducing ordering. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a wrapper around generic sparse decomposition functions +that internally: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with best available permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization. + +NOTE: using SparseCholeskyAnalyze() and SparseCholeskyFactorize() directly + may improve performance of repetitive factorizations with same + sparsity patterns. It also allows one to perform LDLT factorization + of indefinite matrix - a factorization with strictly diagonal D, + which is known to be stable only in few special cases, like quasi- + definite matrices. + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + P - a row/column permutation, a product of P0*P1*...*Pk, k=N-1, + with Pi being permutation of rows/cols I and P[I] + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyp(sparsematrix &a, const bool isupper, integer_1d_array &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsecholeskyp(a.c_ptr(), isupper, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky/LDLT decomposition: symbolic analysis phase. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function performs preliminary analysis of the Cholesky/LDLT +factorization. It allows to choose different permutation types and to +choose between classic Cholesky and indefinite LDLT factorization (the +latter is computed with strictly diagonal D, i.e. without Bunch-Kauffman +pivoting). + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + A - sparse square matrix in any sparse storage format. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + FactType - factorization type: + * 0 for traditional Cholesky of SPD matrix + * 1 for LDLT decomposition with strictly diagonal D, + which may have non-positive entries. + PermType - permutation type: + *-1 for absence of permutation + * 0 for best fill-in reducing permutation available, + which is 3 in the current version + * 1 for supernodal ordering (improves locality and + performance, does NOT change fill-in factor) + * 2 for original AMD ordering + * 3 for improved AMD (approximate minimum degree) + ordering with better handling of matrices with + dense rows/columns + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + +This function fails if and only if the matrix A is symbolically degenerate +i.e. has diagonal element which is exactly zero. In such case False is +returned, contents of Analysis object is undefined. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyanalyze(const sparsematrix &a, const bool isupper, const ae_int_t facttype, const ae_int_t permtype, sparsedecompositionanalysis &analysis, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsecholeskyanalyze(a.c_ptr(), isupper, facttype, permtype, analysis.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky decomposition: numerical analysis phase. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +Depending on settings specified during SparseCholeskyAnalyze() call it may +produce classic Cholesky or L*D*LT decomposition (with strictly diagonal +D), without permutation or with performance-enhancing permutation P. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix, and lower triangular output + is requested. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +INPUT PARAMETERS: + Analysis - prior analysis with internally stored matrix which will + be factorized + NeedUpper - whether upper triangular or lower triangular output is + needed + +OUTPUT PARAMETERS: + A - Cholesky decomposition of A stored in lower triangular + CRS format, i.e. A=L*L' (or upper triangular CRS, with + A=U'*U, depending on NeedUpper parameter). + D - array[N], diagonal factor. If no diagonal factor was + required during analysis phase, still returned but + filled with 1's + P - array[N], pivots. Permutation matrix P is a product of + P(0)*P(1)*...*P(N-1), where P(i) is a permutation of + row/col I and P[I] (with P[I]>=I). + If no permutation was requested during analysis phase, + still returned but filled with identity permutation. + +The function returns True when factorization resulted in nondegenerate +matrix. False is returned when factorization fails (Cholesky factorization +of indefinite matrix) or LDLT factorization has exactly zero elements at +the diagonal. In the latter case contents of A, D and P is undefined. + +The analysis object is not changed during the factorization. Subsequent +calls to SparseCholeskyFactorize() will result in same factorization being +performed one more time. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyfactorize(sparsedecompositionanalysis &analysis, const bool needupper, sparsematrix &a, real_1d_array &d, integer_1d_array &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsecholeskyfactorize(analysis.c_ptr(), needupper, a.c_ptr(), d.c_ptr(), p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Sparse Cholesky decomposition: update internally stored matrix with +another one with exactly same sparsity pattern. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function replaces internally stored numerical values with +ones from another sparse matrix (but having exactly same sparsity pattern +as one that was used for initial SparseCholeskyAnalyze() call). + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + Analysis - analysis object + A - sparse square matrix in any sparse storage format. It + MUST have exactly same sparsity pattern as that of the + matrix that was passed to SparseCholeskyAnalyze(). + Any difference (missing elements or additional elements) + may result in unpredictable and undefined behavior - + an algorithm may fail due to memory access violation. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void sparsecholeskyreload(sparsedecompositionanalysis &analysis, const sparsematrix &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsecholeskyreload(analysis.c_ptr(), a.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +An analysis of the sparse matrix decomposition, performed prior to actual +numerical factorization. You should not directly access fields of this +object - use appropriate ALGLIB functions to work with this object. +*************************************************************************/ +_sparsedecompositionanalysis_owner::_sparsedecompositionanalysis_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsedecompositionanalysis_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::sparsedecompositionanalysis*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsedecompositionanalysis), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsedecompositionanalysis)); + alglib_impl::_sparsedecompositionanalysis_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsedecompositionanalysis_owner::_sparsedecompositionanalysis_owner(alglib_impl::sparsedecompositionanalysis *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_sparsedecompositionanalysis_owner::_sparsedecompositionanalysis_owner(const _sparsedecompositionanalysis_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsedecompositionanalysis_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsedecompositionanalysis copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::sparsedecompositionanalysis*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsedecompositionanalysis), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsedecompositionanalysis)); + alglib_impl::_sparsedecompositionanalysis_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsedecompositionanalysis_owner& _sparsedecompositionanalysis_owner::operator=(const _sparsedecompositionanalysis_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: sparsedecompositionanalysis assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsedecompositionanalysis assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: sparsedecompositionanalysis assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_sparsedecompositionanalysis_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::sparsedecompositionanalysis)); + alglib_impl::_sparsedecompositionanalysis_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_sparsedecompositionanalysis_owner::~_sparsedecompositionanalysis_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_sparsedecompositionanalysis_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::sparsedecompositionanalysis* _sparsedecompositionanalysis_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::sparsedecompositionanalysis* _sparsedecompositionanalysis_owner::c_ptr() const +{ + return p_struct; +} +sparsedecompositionanalysis::sparsedecompositionanalysis() : _sparsedecompositionanalysis_owner() +{ +} + +sparsedecompositionanalysis::sparsedecompositionanalysis(alglib_impl::sparsedecompositionanalysis *attach_to):_sparsedecompositionanalysis_owner(attach_to) +{ +} + +sparsedecompositionanalysis::sparsedecompositionanalysis(const sparsedecompositionanalysis &rhs):_sparsedecompositionanalysis_owner(rhs) +{ +} + +sparsedecompositionanalysis& sparsedecompositionanalysis::operator=(const sparsedecompositionanalysis &rhs) +{ + if( this==&rhs ) + return *this; + _sparsedecompositionanalysis_owner::operator=(rhs); + return *this; +} + +sparsedecompositionanalysis::~sparsedecompositionanalysis() +{ +} +#endif + +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Singular value decomposition of a bidiagonal matrix (extended algorithm) + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (Intel MKL support on x64, other + ! libraries on other platforms) + ! + ! Vendor libraries give approximately constant with respect to the + ! number of worker threads) acceleration factor which depends on the CPU + ! being used, problem size and "baseline" ALGLIB edition which is + ! used for comparison. + ! + ! Generally, commercial ALGLIB is several times faster than open-source + ! generic C edition, and many times faster than open-source C# edition. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm performs the singular value decomposition of a bidiagonal +matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - +orthogonal matrices, S - diagonal matrix with non-negative elements on the +main diagonal, in descending order. + +The algorithm finds singular values. In addition, the algorithm can +calculate matrices Q and P (more precisely, not the matrices, but their +product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, +matrices U and VT can be of any type, including identity. Furthermore, the +algorithm can calculate Q'*C (this product is calculated more effectively +than U*Q, because this calculation operates with rows instead of matrix +columns). + +The feature of the algorithm is its ability to find all singular values +including those which are arbitrarily close to 0 with relative accuracy +close to machine precision. If the parameter IsFractionalAccuracyRequired +is set to True, all singular values will have high relative accuracy close +to machine precision. If the parameter is set to False, only the biggest +singular value will have relative accuracy close to machine precision. +The absolute error of other singular values is equal to the absolute error +of the biggest singular value. + +Input parameters: + D - main diagonal of matrix B. + Array whose index ranges within [0..N-1]. + E - superdiagonal (or subdiagonal) of matrix B. + Array whose index ranges within [0..N-2]. + N - size of matrix B. + IsUpper - True, if the matrix is upper bidiagonal. + IsFractionalAccuracyRequired - + THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 + SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. + U - matrix to be multiplied by Q. + Array whose indexes range within [0..NRU-1, 0..N-1]. + The matrix can be bigger, in that case only the submatrix + [0..NRU-1, 0..N-1] will be multiplied by Q. + NRU - number of rows in matrix U. + C - matrix to be multiplied by Q'. + Array whose indexes range within [0..N-1, 0..NCC-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCC-1] will be multiplied by Q'. + NCC - number of columns in matrix C. + VT - matrix to be multiplied by P^T. + Array whose indexes range within [0..N-1, 0..NCVT-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCVT-1] will be multiplied by P^T. + NCVT - number of columns in matrix VT. + +Output parameters: + D - singular values of matrix B in descending order. + U - if NRU>0, contains matrix U*Q. + VT - if NCVT>0, contains matrix (P^T)*VT. + C - if NCC>0, contains matrix Q'*C. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +NOTE: multiplication U*Q is performed by means of transposition to internal + buffer, multiplication and backward transposition. It helps to avoid + costly columnwise operations and speed-up algorithm. + +Additional information: + The type of convergence is controlled by the internal parameter TOL. + If the parameter is greater than 0, the singular values will have + relative accuracy TOL. If TOL<0, the singular values will have + absolute accuracy ABS(TOL)*norm(B). + By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, + where Epsilon is the machine precision. It is not recommended to use + TOL less than 10*Epsilon since this will considerably slow down the + algorithm and may not lead to error decreasing. + +History: + * 31 March, 2007. + changed MAXITR from 6 to 12. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1999. +*************************************************************************/ +bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixbdsvd(d.c_ptr(), e.c_ptr(), n, isupper, isfractionalaccuracyrequired, u.c_ptr(), nru, c.c_ptr(), ncc, vt.c_ptr(), ncvt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} +#endif + +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Singular value decomposition of a rectangular matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm calculates the singular value decomposition of a matrix of +size MxN: A = U * S * V^T + +The algorithm finds the singular values and, optionally, matrices U and V^T. +The algorithm can find both first min(M,N) columns of matrix U and rows of +matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM +and NxN respectively). + +Take into account that the subroutine does not return matrix V but V^T. + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + UNeeded - 0, 1 or 2. See the description of the parameter U. + VTNeeded - 0, 1 or 2. See the description of the parameter VT. + AdditionalMemory - + If the parameter: + * equals 0, the algorithm doesn't use additional + memory (lower requirements, lower performance). + * equals 1, the algorithm uses additional + memory of size min(M,N)*min(M,N) of real numbers. + It often speeds up the algorithm. + * equals 2, the algorithm uses additional + memory of size M*min(M,N) of real numbers. + It allows to get a maximum performance. + The recommended value of the parameter is 2. + +Output parameters: + W - contains singular values in descending order. + U - if UNeeded=0, U isn't changed, the left singular vectors + are not calculated. + if Uneeded=1, U contains left singular vectors (first + min(M,N) columns of matrix U). Array whose indexes range + within [0..M-1, 0..Min(M,N)-1]. + if UNeeded=2, U contains matrix U wholly. Array whose + indexes range within [0..M-1, 0..M-1]. + VT - if VTNeeded=0, VT isn't changed, the right singular vectors + are not calculated. + if VTNeeded=1, VT contains right singular vectors (first + min(M,N) rows of matrix V^T). Array whose indexes range + within [0..min(M,N)-1, 0..N-1]. + if VTNeeded=2, VT contains matrix V^T wholly. Array whose + indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixsvd(a.c_ptr(), m, n, uneeded, vtneeded, additionalmemory, w.c_ptr(), u.c_ptr(), vt.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} +#endif + +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond1(const real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixrcond1(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of a matrix condition number (2-norm) + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then the matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2(const real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixrcond2(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of a matrix condition number (2-norm) for a rectangular matrix. + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array[M,N] + M, N- rows and columns count, >=1 + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2rect(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixrcond2rect(a.c_ptr(), m, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixrcondinf(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixrcond(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +2-norm condition number of a symmetric positive definite matrix using EVD. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array[N,N] + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/cond(A), if matrix A is positive definite, + 0, if matrix A is not positive definite + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond2(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixrcond2(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixtrrcond1(a.c_ptr(), n, isupper, isunit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Triangular matrix: reciprocal 2-norm condition number + +The algorithm calculates a reciprocal 2-norm condition number using SVD. + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/cond(A) + +NOTE: + if k(A) is very large, then matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond2(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixtrrcond2(a.c_ptr(), n, isupper, isunit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixtrrcondinf(a.c_ptr(), n, isupper, isunit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - Hermitian positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hpdmatrixrcond(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixrcond1(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixrcondinf(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixlurcond1(lua.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixlurcondinf(lua.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixcholeskyrcond(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hpdmatrixcholeskyrcond(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixlurcond1(lua.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixlurcondinf(lua.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixtrrcond1(a.c_ptr(), n, isupper, isunit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cmatrixtrrcondinf(a.c_ptr(), n, isupper, isunit, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This procedure initializes matrix norm estimator. + +USAGE: +1. User initializes algorithm state with NormEstimatorCreate() call +2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) +3. User calls NormEstimatorResults() to get solution. + +INPUT PARAMETERS: + M - number of rows in the matrix being estimated, M>0 + N - number of columns in the matrix being estimated, N>0 + NStart - number of random starting vectors + recommended value - at least 5. + NIts - number of iterations to do with best starting vector + recommended value - at least 5. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTE: this algorithm is effectively deterministic, i.e. it always returns +same result when repeatedly called for the same matrix. In fact, algorithm +uses randomized starting vectors, but internal random numbers generator +always generates same sequence of the random values (it is a feature, not +bug). + +Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::normestimatorcreate(m, n, nstart, nits, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes seed value used by algorithm. In some cases we need +deterministic processing, i.e. subsequent calls must return equal results, +in other cases we need non-deterministic algorithm which returns different +results for the same matrix on every pass. + +Setting zero seed will lead to non-deterministic algorithm, while non-zero +value will make our algorithm deterministic. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + SeedVal - seed value, >=0. Zero value = non-deterministic algo. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorsetseed(normestimatorstate &state, const ae_int_t seedval, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::normestimatorsetseed(state.c_ptr(), seedval, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function estimates norm of the sparse M*N matrix A. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + A - sparse M*N matrix, must be converted to CRS format + prior to calling this function. + +After this function is over you can call NormEstimatorResults() to get +estimate of the norm(A). + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorestimatesparse(normestimatorstate &state, const sparsematrix &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::normestimatorestimatesparse(state.c_ptr(), a.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Matrix norm estimation results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + Nrm - estimate of the matrix norm, Nrm>=0 + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorresults(const normestimatorstate &state, double &nrm, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::normestimatorresults(state.c_ptr(), &nrm, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores state of the iterative norm estimation algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_normestimatorstate_owner::_normestimatorstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_normestimatorstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::normestimatorstate)); + alglib_impl::_normestimatorstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_normestimatorstate_owner::_normestimatorstate_owner(alglib_impl::normestimatorstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_normestimatorstate_owner::_normestimatorstate_owner(const _normestimatorstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_normestimatorstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: normestimatorstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::normestimatorstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::normestimatorstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::normestimatorstate)); + alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_normestimatorstate_owner& _normestimatorstate_owner::operator=(const _normestimatorstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: normestimatorstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: normestimatorstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: normestimatorstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_normestimatorstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::normestimatorstate)); + alglib_impl::_normestimatorstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_normestimatorstate_owner::~_normestimatorstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_normestimatorstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::normestimatorstate* _normestimatorstate_owner::c_ptr() const +{ + return p_struct; +} +normestimatorstate::normestimatorstate() : _normestimatorstate_owner() +{ +} + +normestimatorstate::normestimatorstate(alglib_impl::normestimatorstate *attach_to):_normestimatorstate_owner(attach_to) +{ +} + +normestimatorstate::normestimatorstate(const normestimatorstate &rhs):_normestimatorstate_owner(rhs) +{ +} + +normestimatorstate& normestimatorstate::operator=(const normestimatorstate &rhs) +{ + if( this==&rhs ) + return *this; + _normestimatorstate_owner::operator=(rhs); + return *this; +} + +normestimatorstate::~normestimatorstate() +{ +} +#endif + +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of RMatrixLU subroutine). + Pivots - table of permutations + (the output of RMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixluinverse(a.c_ptr(), pivots.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of RMatrixLU subroutine). + Pivots - table of permutations + (the output of RMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixluinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixluinverse(a.c_ptr(), pivots.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a general matrix. + +INPUT PARAMETERS: + A - matrix. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinverse(real_2d_array &a, const ae_int_t n, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinverse(a.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a general matrix. + +INPUT PARAMETERS: + A - matrix. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixinverse(real_2d_array &a, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinverse(a.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of CMatrixLU subroutine). + Pivots - table of permutations + (the output of CMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixluinverse(a.c_ptr(), pivots.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of CMatrixLU subroutine). + Pivots - table of permutations + (the output of CMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows()) || (a.cols()!=pivots.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixluinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixluinverse(a.c_ptr(), pivots.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a general matrix. + +Input parameters: + A - matrix + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +Output parameters: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void cmatrixinverse(complex_2d_array &a, const ae_int_t n, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixinverse(a.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a general matrix. + +Input parameters: + A - matrix + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +Output parameters: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixinverse(complex_2d_array &a, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixinverse(a.c_ptr(), n, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a symmetric positive definite matrix which is given +by Cholesky decomposition. + +INPUT PARAMETERS: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of SPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, the symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + the function + * if False, the symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + the function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, corresponding triangle + contains inverse matrix, the other triangle is not + modified. + * for rep.terminationtype<0, corresponding triangle is + zero-filled; the other triangle is not modified. + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a symmetric positive definite matrix which is given +by Cholesky decomposition. + +INPUT PARAMETERS: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of SPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, the symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + the function + * if False, the symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + the function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, corresponding triangle + contains inverse matrix, the other triangle is not + modified. + * for rep.terminationtype<0, corresponding triangle is + zero-filled; the other triangle is not modified. + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixcholeskyinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskyinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskyinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a symmetric positive definite matrix. + +Given an upper or lower triangle of a symmetric positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a symmetric positive definite matrix. + +Given an upper or lower triangle of a symmetric positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a Hermitian positive definite matrix which is given +by Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of HPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskyinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a Hermitian positive definite matrix which is given +by Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of HPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixcholeskyinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholeskyinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskyinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Inversion of a Hermitian positive definite matrix. + +Given an upper or lower triangle of a Hermitian positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inversion of a Hermitian positive definite matrix. + +Given an upper or lower triangle of a Hermitian positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixinverse': looks like one of arguments has wrong size"); + n = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixinverse(a.c_ptr(), n, isupper, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Triangular matrix inverse (real) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixtrinverse(a.c_ptr(), n, isupper, isunit, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Triangular matrix inverse (real) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixtrinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + bool isunit; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixtrinverse': looks like one of arguments has wrong size"); + n = a.cols(); + isunit = false; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixtrinverse(a.c_ptr(), n, isupper, isunit, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Triangular matrix inverse (complex) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixtrinverse(a.c_ptr(), n, isupper, isunit, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Triangular matrix inverse (complex) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixtrinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + bool isunit; + if( (a.cols()!=a.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixtrinverse': looks like one of arguments has wrong size"); + n = a.cols(); + isunit = false; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixtrinverse(a.c_ptr(), n, isupper, isunit, rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + + +/************************************************************************* +Matrix inverse report: +* terminationtype completion code: + * 1 for success + * -3 for failure due to the matrix being singular or + nearly-singular +* r1 reciprocal of condition number in 1-norm +* rinf reciprocal of condition number in inf-norm +*************************************************************************/ +_matinvreport_owner::_matinvreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_matinvreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::matinvreport)); + alglib_impl::_matinvreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_matinvreport_owner::_matinvreport_owner(alglib_impl::matinvreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_matinvreport_owner::_matinvreport_owner(const _matinvreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_matinvreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: matinvreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::matinvreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::matinvreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::matinvreport)); + alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_matinvreport_owner& _matinvreport_owner::operator=(const _matinvreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: matinvreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: matinvreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: matinvreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_matinvreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::matinvreport)); + alglib_impl::_matinvreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_matinvreport_owner::~_matinvreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_matinvreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::matinvreport* _matinvreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::matinvreport* _matinvreport_owner::c_ptr() const +{ + return p_struct; +} +matinvreport::matinvreport() : _matinvreport_owner() ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +matinvreport::matinvreport(alglib_impl::matinvreport *attach_to):_matinvreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +matinvreport::matinvreport(const matinvreport &rhs):_matinvreport_owner(rhs) ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +matinvreport& matinvreport::operator=(const matinvreport &rhs) +{ + if( this==&rhs ) + return *this; + _matinvreport_owner::operator=(rhs); + return *this; +} + +matinvreport::~matinvreport() +{ +} +#endif + +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a number to an element +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - row where the element to be updated is stored. + UpdColumn - column where the element to be updated is stored. + UpdVal - a number to be added to the element. + + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinvupdatesimple(inva.c_ptr(), n, updrow, updcolumn, updval, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a row +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - the row of A whose vector V was added. + 0 <= Row <= N-1 + V - the vector to be added to a row. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinvupdaterow(inva.c_ptr(), n, updrow, v.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a column +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdColumn - the column of A whose vector U was added. + 0 <= UpdColumn <= N-1 + U - the vector to be added to a column. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinvupdatecolumn(inva.c_ptr(), n, updcolumn, u.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm computes the inverse of matrix A+u*v' by using the given matrix +A^-1 and the vectors u and v. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + U - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + V - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of matrix A + u*v'. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixinvupdateuv(inva.c_ptr(), n, u.c_ptr(), v.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Subroutine performing the Schur decomposition of a general matrix by using +the QR algorithm with multiple shifts. + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (lightweight Intel MKL is shipped + ! with ALGLIB for x64, other libs for other platforms) + ! + ! Vendor libs give approximately constant (with respect to number of + ! worker threads) acceleration factor which depends on CPU being used, + ! problem size and "baseline" ALGLIB edition which is used for + ! comparison. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The source matrix A is represented as S'*A*S = T, where S is an orthogonal +matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of +sizes 1x1 and 2x2 on the main diagonal). + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of A, N>=0. + + +Output parameters: + A - contains matrix T. + Array whose indexes range within [0..N-1, 0..N-1]. + S - contains Schur vectors. + Array whose indexes range within [0..N-1, 0..N-1]. + +Note 1: + The block structure of matrix T can be easily recognized: since all + the elements below the blocks are zeros, the elements a[i+1,i] which + are equal to 0 show the block border. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms in linear algebra). If you require maximum performance on + your machine, it is recommended to adjust this parameter manually. + +Result: + True, + if the algorithm has converged and parameters A and S contain the result. + False, + if the algorithm has not converged. + +Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). +*************************************************************************/ +bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixschur(a.c_ptr(), n, s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} +#endif + +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Algorithm for solving the following generalized symmetric positive-definite +eigenproblem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3). +where A is a symmetric matrix, B - symmetric positive-definite matrix. +The problem is solved by reducing it to an ordinary symmetric eigenvalue +problem. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ZNeeded - if ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in matrix columns. It should + be noted that the eigenvectors in such problems do not + form an orthogonal system. + +Result: + True, if the problem was solved successfully. + False, if the error occurred during the Cholesky decomposition of matrix + B (the matrix isn't positive-definite) or during the work of the iterative + algorithm for solving the symmetric eigenproblem. + +See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixgevd(a.c_ptr(), n, isuppera, b.c_ptr(), isupperb, zneeded, problemtype, d.c_ptr(), z.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Algorithm for reduction of the following generalized symmetric positive- +definite eigenvalue problem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3) +to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and +the given problems are the same, and the eigenvectors of the given problem +could be obtained by multiplying the obtained eigenvectors by the +transformation matrix x = R*y). + +Here A is a symmetric matrix, B - symmetric positive-definite matrix. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + A - symmetric matrix which is given by its upper or lower + triangle depending on IsUpperA. Contains matrix C. + Array whose indexes range within [0..N-1, 0..N-1]. + R - upper triangular or low triangular transformation matrix + which is used to obtain the eigenvectors of a given problem + as the product of eigenvectors of C (from the right) and + matrix R (from the left). If the matrix is upper + triangular, the elements below the main diagonal + are equal to 0 (and vice versa). Thus, we can perform + the multiplication without taking into account the + internal structure (which is an easier though less + effective way). + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperR - type of matrix R (upper or lower triangular). + +Result: + True, if the problem was reduced successfully. + False, if the error occurred during the Cholesky decomposition of + matrix B (the matrix is not positive-definite). + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::smatrixgevdreduce(a.c_ptr(), n, isuppera, b.c_ptr(), isupperb, problemtype, r.c_ptr(), &isupperr, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} +#endif + +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixludet(a.c_ptr(), pivots.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixludet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixludet(a.c_ptr(), pivots.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixdet(const real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixdet(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double rmatrixdet(const real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixdet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::rmatrixdet(a.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::cmatrixludet(a.c_ptr(), pivots.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return alglib::complex(result); +} + +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=pivots.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixludet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::cmatrixludet(a.c_ptr(), pivots.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::cmatrixdet(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return alglib::complex(result); +} + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +alglib::complex cmatrixdet(const complex_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixdet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_complex result = alglib_impl::cmatrixdet(a.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Determinant calculation of the matrix given by the Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition, + output of SMatrixCholesky subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +As the determinant is equal to the product of squares of diagonal elements, +it's not necessary to specify which triangle - lower or upper - the matrix +is stored in. + +Result: + matrix determinant. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixcholeskydet(a.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Determinant calculation of the matrix given by the Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition, + output of SMatrixCholesky subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +As the determinant is equal to the product of squares of diagonal elements, +it's not necessary to specify which triangle - lower or upper - the matrix +is stored in. + +Result: + matrix determinant. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double spdmatrixcholeskydet(const real_2d_array &a, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskydet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixcholeskydet(a.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Determinant calculation of the symmetric positive definite matrix. + +Input parameters: + A - matrix, array[N,N] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +Result: + determinant of matrix A. + If matrix A is not positive definite, an exception is generated. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixdet(a.c_ptr(), n, isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Determinant calculation of the symmetric positive definite matrix. + +Input parameters: + A - matrix, array[N,N] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +Result: + determinant of matrix A. + If matrix A is not positive definite, an exception is generated. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double spdmatrixdet(const real_2d_array &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixdet': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spdmatrixdet(a.c_ptr(), n, isupper, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) +static ae_int_t ablas_blas2minvendorkernelsize = 8; +static void ablas_ablasinternalsplitlength(ae_int_t n, + ae_int_t nb, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state); +static void ablas_cmatrixrighttrsm2(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +static void ablas_cmatrixlefttrsm2(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +static void ablas_rmatrixrighttrsm2(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +static void ablas_rmatrixlefttrsm2(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +static void ablas_cmatrixherk2(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +static void ablas_rmatrixsyrk2(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +static void ablas_cmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool _trypexec_ablas_cmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, ae_state *_state); +static void ablas_rmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool _trypexec_ablas_rmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) +static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* work, + /* Complex */ ae_vector* t, + /* Complex */ ae_vector* tau, + ae_state *_state); +static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* work, + /* Complex */ ae_vector* t, + /* Complex */ ae_vector* tau, + ae_state *_state); +static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, + /* Real */ ae_vector* tau, + ae_bool columnwisea, + ae_int_t lengtha, + ae_int_t blocksize, + /* Real */ ae_matrix* t, + /* Real */ ae_vector* work, + ae_state *_state); +static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, + /* Complex */ ae_vector* tau, + ae_bool columnwisea, + ae_int_t lengtha, + ae_int_t blocksize, + /* Complex */ ae_matrix* t, + /* Complex */ ae_vector* work, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +static double sparse_desiredloadfactor = 0.66; +static double sparse_maxloadfactor = 0.75; +static double sparse_growfactor = 2.00; +static ae_int_t sparse_additional = 10; +static ae_int_t sparse_linalgswitch = 16; +static ae_int_t sparse_hash(ae_int_t i, + ae_int_t j, + ae_int_t tabsize, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) +static void hsschur_internalauxschur(ae_bool wantt, + ae_bool wantz, + ae_int_t n, + ae_int_t ilo, + ae_int_t ihi, + /* Real */ ae_matrix* h, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + ae_int_t iloz, + ae_int_t ihiz, + /* Real */ ae_matrix* z, + /* Real */ ae_vector* work, + /* Real */ ae_vector* workv3, + /* Real */ ae_vector* workc1, + /* Real */ ae_vector* works1, + ae_int_t* info, + ae_state *_state); +static void hsschur_aux2x2schur(double* a, + double* b, + double* c, + double* d, + double* rt1r, + double* rt1i, + double* rt2r, + double* rt2i, + double* cs, + double* sn, + ae_state *_state); +static double hsschur_extschursign(double a, double b, ae_state *_state); +static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +static ae_int_t evd_stepswithintol = 2; +static void evd_clearrfields(eigsubspacestate* state, ae_state *_state); +static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_state *_state); +static void evd_tdevde2(double a, + double b, + double c, + double* rt1, + double* rt2, + ae_state *_state); +static void evd_tdevdev2(double a, + double b, + double c, + double* rt1, + double* rt2, + double* cs1, + double* sn1, + ae_state *_state); +static double evd_tdevdpythag(double a, double b, ae_state *_state); +static double evd_tdevdextsign(double a, double b, ae_state *_state); +static ae_bool evd_internalbisectioneigenvalues(/* Real */ const ae_vector* _d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t irange, + ae_int_t iorder, + double vl, + double vu, + ae_int_t il, + ae_int_t iu, + double abstol, + /* Real */ ae_vector* w, + ae_int_t* m, + ae_int_t* nsplit, + /* Integer */ ae_vector* iblock, + /* Integer */ ae_vector* isplit, + ae_int_t* errorcode, + ae_state *_state); +static void evd_internaldstein(ae_int_t n, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t m, + /* Real */ const ae_vector* _w, + /* Integer */ const ae_vector* iblock, + /* Integer */ const ae_vector* isplit, + /* Real */ ae_matrix* z, + /* Integer */ ae_vector* ifail, + ae_int_t* info, + ae_state *_state); +static void evd_tdininternaldlagtf(ae_int_t n, + /* Real */ ae_vector* a, + double lambdav, + /* Real */ ae_vector* b, + /* Real */ ae_vector* c, + double tol, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* iin, + ae_int_t* info, + ae_state *_state); +static void evd_tdininternaldlagts(ae_int_t n, + /* Real */ const ae_vector* a, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* d, + /* Integer */ const ae_vector* iin, + /* Real */ ae_vector* y, + double* tol, + ae_int_t* info, + ae_state *_state); +static void evd_internaldlaebz(ae_int_t ijob, + ae_int_t nitmax, + ae_int_t n, + ae_int_t mmax, + ae_int_t minp, + double abstol, + double reltol, + double pivmin, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* e, + /* Real */ const ae_vector* e2, + /* Integer */ ae_vector* nval, + /* Real */ ae_matrix* ab, + /* Real */ ae_vector* c, + ae_int_t* mout, + /* Integer */ ae_matrix* nab, + /* Real */ ae_vector* work, + /* Integer */ ae_vector* iwork, + ae_int_t* info, + ae_state *_state); +static void evd_rmatrixinternaltrevc(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Boolean */ const ae_vector* _vselect, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state); +static void evd_internaltrevc(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Boolean */ const ae_vector* _vselect, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state); +static void evd_internalhsevdlaln2(ae_bool ltrans, + ae_int_t na, + ae_int_t nw, + double smin, + double ca, + /* Real */ const ae_matrix* a, + double d1, + double d2, + /* Real */ const ae_matrix* b, + double wr, + double wi, + /* Boolean */ ae_vector* rswap4, + /* Boolean */ ae_vector* zswap4, + /* Integer */ ae_matrix* ipivot44, + /* Real */ ae_vector* civ4, + /* Real */ ae_vector* crv4, + /* Real */ ae_matrix* x, + double* scl, + double* xnorm, + ae_int_t* info, + ae_state *_state); +static void evd_internalhsevdladiv(double a, + double b, + double c, + double d, + double* p, + double* q, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) +static void dlu_cmatrixlup2(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state); +static void dlu_rmatrixlup2(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state); +static void dlu_cmatrixplu2(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state); +static void dlu_rmatrixplu2(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) +static double sptrf_densebnd = 0.10; +static ae_int_t sptrf_slswidth = 8; +static void sptrf_sluv2list1init(ae_int_t n, + sluv2list1matrix* a, + ae_state *_state); +static void sptrf_sluv2list1swap(sluv2list1matrix* a, + ae_int_t i, + ae_int_t j, + ae_state *_state); +static void sptrf_sluv2list1dropsequence(sluv2list1matrix* a, + ae_int_t i, + ae_state *_state); +static void sptrf_sluv2list1appendsequencetomatrix(const sluv2list1matrix* a, + ae_int_t src, + ae_bool hasdiagonal, + double d, + ae_int_t nzmax, + sparsematrix* s, + ae_int_t dst, + ae_state *_state); +static void sptrf_sluv2list1pushsparsevector(sluv2list1matrix* a, + /* Integer */ const ae_vector* si, + /* Real */ const ae_vector* sv, + ae_int_t nz, + ae_state *_state); +static void sptrf_densetrailinit(sluv2densetrail* d, + ae_int_t n, + ae_state *_state); +static void sptrf_densetrailappendcolumn(sluv2densetrail* d, + /* Real */ const ae_vector* x, + ae_int_t id, + ae_state *_state); +static void sptrf_sparsetrailinit(const sparsematrix* s, + sluv2sparsetrail* a, + ae_state *_state); +static ae_bool sptrf_sparsetrailfindpivot(sluv2sparsetrail* a, + ae_int_t pivottype, + ae_int_t* ipiv, + ae_int_t* jpiv, + ae_state *_state); +static void sptrf_sparsetrailpivotout(sluv2sparsetrail* a, + ae_int_t ipiv, + ae_int_t jpiv, + double* uu, + /* Integer */ ae_vector* v0i, + /* Real */ ae_vector* v0r, + ae_int_t* nz0, + /* Integer */ ae_vector* v1i, + /* Real */ ae_vector* v1r, + ae_int_t* nz1, + ae_state *_state); +static void sptrf_sparsetraildensify(sluv2sparsetrail* a, + ae_int_t i1, + sluv2list1matrix* bupper, + sluv2densetrail* dtrail, + ae_state *_state); +static void sptrf_sparsetrailupdate(sluv2sparsetrail* a, + /* Integer */ ae_vector* v0i, + /* Real */ ae_vector* v0r, + ae_int_t nz0, + /* Integer */ const ae_vector* v1i, + /* Real */ const ae_vector* v1r, + ae_int_t nz1, + sluv2list1matrix* bupper, + sluv2densetrail* dtrail, + ae_bool densificationsupported, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) +static ae_int_t amdordering_knsheadersize = 2; +static ae_int_t amdordering_llmentrysize = 6; +static void amdordering_nsaddkth(niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state); +static void amdordering_nssubtractkth(niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_nscountnotkth(const niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_nscountandkth(const niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state); +static void amdordering_knscompressstorage(amdknset* sa, ae_state *_state); +static void amdordering_knsreallocate(amdknset* sa, + ae_int_t setidx, + ae_int_t newallocated, + ae_state *_state); +static void amdordering_knsinit(ae_int_t k, + ae_int_t n, + ae_int_t kprealloc, + amdknset* sa, + ae_state *_state); +static void amdordering_knsinitfroma(const sparsematrix* a, + ae_int_t n, + ae_bool ignorediagonal, + amdknset* sa, + ae_state *_state); +static void amdordering_knsstartenumeration(amdknset* sa, + ae_int_t i, + ae_state *_state); +static ae_bool amdordering_knsenumerate(amdknset* sa, + ae_int_t* i, + ae_state *_state); +static void amdordering_knsdirectaccess(const amdknset* sa, + ae_int_t k, + ae_int_t* idxbegin, + ae_int_t* idxend, + ae_state *_state); +static void amdordering_knsaddnewelement(amdknset* sa, + ae_int_t i, + ae_int_t k, + ae_state *_state); +static void amdordering_knssubtract1(amdknset* sa, + ae_int_t i, + const niset* src, + ae_state *_state); +static void amdordering_knsaddkthdistinct(amdknset* sa, + ae_int_t i, + const amdknset* src, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_knscountkth(const amdknset* s0, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_knscountnot(amdknset* s0, + ae_int_t i, + const niset* s1, + ae_state *_state); +static ae_int_t amdordering_knscountnotkth(amdknset* s0, + ae_int_t i, + const amdknset* s1, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_knscountandkth(amdknset* s0, + ae_int_t i, + const amdknset* s1, + ae_int_t k, + ae_state *_state); +static ae_int_t amdordering_knssumkth(const amdknset* s0, + ae_int_t i, + ae_state *_state); +static void amdordering_knsclearkthnoreclaim(amdknset* sa, + ae_int_t k, + ae_state *_state); +static void amdordering_knsclearkthreclaim(amdknset* sa, + ae_int_t k, + ae_state *_state); +static void amdordering_mtxinit(ae_int_t n, + amdllmatrix* a, + ae_state *_state); +static void amdordering_mtxaddcolumnto(const amdllmatrix* a, + ae_int_t j, + niset* s, + ae_state *_state); +static void amdordering_mtxinsertnewelement(amdllmatrix* a, + ae_int_t i, + ae_int_t j, + ae_state *_state); +static ae_int_t amdordering_mtxcountcolumnnot(const amdllmatrix* a, + ae_int_t j, + const niset* s, + ae_state *_state); +static ae_int_t amdordering_mtxcountcolumn(const amdllmatrix* a, + ae_int_t j, + ae_state *_state); +static void amdordering_mtxclearx(amdllmatrix* a, + ae_int_t k, + ae_bool iscol, + ae_state *_state); +static void amdordering_mtxclearcolumn(amdllmatrix* a, + ae_int_t j, + ae_state *_state); +static void amdordering_mtxclearrow(amdllmatrix* a, + ae_int_t j, + ae_state *_state); +static void amdordering_vtxinit(const sparsematrix* a, + ae_int_t n, + /* Boolean */ const ae_vector* eligible, + ae_bool haseligible, + ae_bool checkexactdegrees, + amdvertexset* s, + ae_state *_state); +static void amdordering_vtxremovevertex(amdvertexset* s, + ae_int_t p, + ae_state *_state); +static ae_int_t amdordering_vtxgetapprox(const amdvertexset* s, + ae_int_t p, + ae_state *_state); +static ae_int_t amdordering_vtxgetexact(const amdvertexset* s, + ae_int_t p, + ae_state *_state); +static ae_int_t amdordering_vtxgetapproxmindegree(amdvertexset* s, + ae_state *_state); +static void amdordering_vtxupdateapproximatedegree(amdvertexset* s, + ae_int_t p, + ae_int_t dnew, + ae_state *_state); +static void amdordering_vtxupdateexactdegree(amdvertexset* s, + ae_int_t p, + ae_int_t d, + ae_state *_state); +static void amdordering_amdselectpivotelement(amdbuffer* buf, + ae_int_t k, + ae_int_t* p, + ae_int_t* nodesize, + ae_state *_state); +static void amdordering_amdcomputelp(amdbuffer* buf, + ae_int_t p, + ae_state *_state); +static void amdordering_amdmasselimination(amdbuffer* buf, + ae_int_t p, + ae_int_t k, + ae_int_t tau, + ae_state *_state); +static void amdordering_amddetectsupernodes(amdbuffer* buf, + ae_state *_state); +static void amdordering_amdmovetoquasidense(amdbuffer* buf, + niset* cand, + ae_int_t p, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) +static ae_int_t spchol_maxsupernode = 4; +static double spchol_maxmergeinefficiency = 0.25; +static ae_int_t spchol_smallfakestolerance = 2; +static ae_int_t spchol_maxfastkernel = 4; +static ae_bool spchol_relaxedsupernodes = ae_true; +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_int_t spchol_spsymmgetmaxsimd(ae_state *_state); +#endif +static ae_bool spchol_spsymmpblsetup(spcholanalysis* analysis, + const sparsematrix* a, + /* Integer */ const ae_vector* priorities, + ae_int_t facttype, + ae_int_t permtype, + ae_state *_state); +static ae_bool spchol_spsymmpblhasdss(ae_state *_state); +static ae_bool spchol_spsymmpblsetupdss(ae_opaque_object* pbl, + sparsematrix* tmpat, + ae_int_t n, + /* Integer */ ae_vector* priorities, + ae_int_t facttype, + ae_int_t permtype, + ae_bool dotrace, + ae_state *_state); +static ae_bool spchol_spsymmpblfactorize(ae_opaque_object* pbl, + sparsematrix* a, + ae_bool achanged, + ae_state *_state); +static ae_bool spchol_spsymmpblsolve(ae_opaque_object* pbl, + sparsematrix* a, + /* Real */ ae_vector* b, + ae_state *_state); +static void spchol_spsymmpbldiagerr(ae_opaque_object* pbl, + double* sumsq, + double* errsq, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +static void spchol_propagatefwd(/* Real */ const ae_vector* x, + ae_int_t cols0, + ae_int_t blocksize, + /* Integer */ const ae_vector* superrowidx, + ae_int_t rbase, + ae_int_t offdiagsize, + /* Real */ const ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sstride, + /* Real */ ae_vector* simdbuf, + ae_int_t simdwidth, + ae_state *_state); +#endif +static void spchol_generatedbgpermutation(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + ae_state *_state); +static void spchol_buildunorderedetree(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* parent, + /* Integer */ ae_vector* tabove, + ae_state *_state); +static void spchol_fromparenttochildren(/* Integer */ const ae_vector* parent, + ae_int_t n, + /* Integer */ ae_vector* childrenr, + /* Integer */ ae_vector* childreni, + /* Integer */ ae_vector* ttmp0, + ae_state *_state); +static void spchol_buildorderedetree(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* parent, + /* Integer */ ae_vector* supernodalpermutation, + /* Integer */ ae_vector* invsupernodalpermutation, + /* Integer */ ae_vector* trawparentofrawnode, + /* Integer */ ae_vector* trawparentofreorderednode, + /* Integer */ ae_vector* ttmp, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state); +static void spchol_createsupernodalstructure(const sparsematrix* at, + /* Integer */ const ae_vector* parent, + ae_int_t n, + spcholanalysis* analysis, + /* Integer */ ae_vector* node2supernode, + /* Integer */ ae_vector* tchildrenr, + /* Integer */ ae_vector* tchildreni, + /* Integer */ ae_vector* tparentnodeofsupernode, + /* Integer */ ae_vector* tfakenonzeros, + /* Integer */ ae_vector* ttmp0, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state); +static void spchol_analyzesupernodaldependencies(spcholanalysis* analysis, + const sparsematrix* rawa, + /* Integer */ const ae_vector* node2supernode, + ae_int_t n, + /* Integer */ ae_vector* ttmp0, + /* Integer */ ae_vector* ttmp1, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state); +static void spchol_loadmatrix(spcholanalysis* analysis, + const sparsematrix* at, + ae_state *_state); +static void spchol_extractmatrix(const spcholanalysis* analysis, + /* Integer */ const ae_vector* offsets, + /* Integer */ const ae_vector* strides, + /* Real */ const ae_vector* rowstorage, + /* Real */ const ae_vector* diagd, + ae_int_t n, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + /* Integer */ ae_vector* tmpp, + ae_state *_state); +static void spchol_partialcholeskypattern(const sparsematrix* a, + ae_int_t head, + ae_int_t tail, + sparsematrix* atail, + ae_nxpool* n1ipool, + ae_nxpool* n1bpool, + sparsematrix* tmpbottomt, + sparsematrix* tmpupdatet, + sparsematrix* tmpupdate, + sparsematrix* tmpnewtailt, + ae_state *_state); +static void spchol_topologicalpermutation(const sparsematrix* a, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +static ae_int_t spchol_computenonzeropattern(const sparsematrix* wrkat, + ae_int_t columnidx, + ae_int_t n, + /* Integer */ const ae_vector* superrowridx, + /* Integer */ ae_vector* superrowidx, + ae_int_t nsuper, + /* Integer */ const ae_vector* childrennodesr, + /* Integer */ const ae_vector* childrennodesi, + /* Integer */ const ae_vector* node2supernode, + /* Boolean */ ae_vector* truearray, + /* Integer */ ae_vector* tmp0, + ae_state *_state); +static void spchol_updatesupernode(spcholanalysis* analysis, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + /* Integer */ const ae_vector* raw2smap, + ae_int_t ladjidx0, + ae_int_t ladjidx1, + /* Real */ const ae_vector* diagd, + ae_state *_state); +static void spchol_updatesupernodegeneric(spcholanalysis* analysis, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + /* Integer */ const ae_vector* raw2smap, + ae_int_t ladjidx, + /* Real */ const ae_vector* diagd, + ae_state *_state); +static ae_bool spchol_factorizesupernode(spcholanalysis* analysis, + ae_int_t sidx, + ae_state *_state); +static ae_bool spchol_factorizesupernodeheadldlt(/* Real */ ae_vector* outputstorage, + /* Real */ ae_vector* diagd, + /* Real */ const ae_vector* rpivotsigns, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + ae_int_t sstride, + ae_int_t modtype, + double modparam0, + double modparam1, + ae_state *_state); +static void spchol_factorizesupernodetail(spcholanalysis* analysis, + ae_int_t sidx, + ae_state *_state); +static ae_int_t spchol_recommendedstridefor(ae_int_t rowsize, + ae_state *_state); +static ae_int_t spchol_alignpositioninarray(ae_int_t offs, + ae_state *_state); +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_bool spchol_updatekernel4444(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state); +#endif +#ifdef ALGLIB_NO_FAST_KERNELS +static ae_bool spchol_updatekernelabc4(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t urank, + ae_int_t urowstride, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state); +#endif +static ae_bool spchol_updatekernelrank1(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t trowstride, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state); +static ae_bool spchol_updatekernelrank2(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t trowstride, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state); +static void spchol_generatepriorityamdpermutation(sparsematrix* wrka, + /* Integer */ ae_vector* wrkpriorities, + double promoteabove, + ae_int_t promoteto, + ae_bool debugordering, + ae_bool dotrace, + ae_nxpool* n1bpool, + ae_nxpool* n1ipool, + priorityamdbuffers* buf, + ae_bool userbuffers, + /* Integer */ ae_vector* fillinperm, + /* Integer */ ae_vector* invfillinperm, + ae_state *_state); +static void spchol_permtransposeunsorted(const sparsematrix* a, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +static void spchol_fillraw2smap(/* Integer */ const ae_vector* superrowidx, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t ridx0, + ae_int_t ridx1, + ae_int_t blocksize, + /* Integer */ ae_vector* raw2smap, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + ae_state *_state); +static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + ae_state *_state); +static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) +static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* uu, + ae_int_t ustart, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t cstart, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t vstart, + ae_int_t ncvt, + ae_state *_state); +static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state); +static void bdsvd_svd2x2(double f, + double g, + double h, + double* ssmin, + double* ssmax, + ae_state *_state); +static void bdsvd_svdv2x2(double f, + double g, + double h, + double* ssmin, + double* ssmax, + double* snr, + double* csr, + double* snl, + double* csl, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) +static void rcond_rmatrixrcondtrinternal(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_bool onenorm, + double anorm, + double* rc, + ae_state *_state); +static void rcond_cmatrixrcondtrinternal(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_bool onenorm, + double anorm, + double* rc, + ae_state *_state); +static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + ae_bool isnormprovided, + double anorm, + double* rc, + ae_state *_state); +static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + ae_bool isnormprovided, + double anorm, + double* rc, + ae_state *_state); +static void rcond_rmatrixrcondluinternal(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_bool onenorm, + ae_bool isanormprovided, + double anorm, + double* rc, + ae_state *_state); +static void rcond_cmatrixrcondluinternal(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_bool onenorm, + ae_bool isanormprovided, + double anorm, + double* rc, + ae_state *_state); +static void rcond_rmatrixestimatenorm(ae_int_t n, + /* Real */ ae_vector* v, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* isgn, + double* est, + ae_int_t* kase, + ae_state *_state); +static void rcond_cmatrixestimatenorm(ae_int_t n, + /* Complex */ ae_vector* v, + /* Complex */ ae_vector* x, + double* est, + ae_int_t* kase, + /* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_state *_state); +static double rcond_internalcomplexrcondscsum1(/* Complex */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_int_t* i, + ae_int_t* iter, + ae_int_t* j, + ae_int_t* jlast, + ae_int_t* jump, + double* absxi, + double* altsgn, + double* estold, + double* temp, + ae_state *_state); +static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_int_t* i, + ae_int_t* iter, + ae_int_t* j, + ae_int_t* jlast, + ae_int_t* jump, + double* absxi, + double* altsgn, + double* estold, + double* temp, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state); +ae_bool _trypexec_matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Real */ ae_vector* tmp, + matinvreport* rep, ae_state *_state); +static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Complex */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state); +ae_bool _trypexec_matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Complex */ ae_vector* tmp, + matinvreport* rep, ae_state *_state); +static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Real */ ae_vector* work, + matinvreport* rep, + ae_state *_state); +ae_bool _trypexec_matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Real */ ae_vector* work, + matinvreport* rep, ae_state *_state); +static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Complex */ ae_vector* work, + matinvreport* rep, + ae_state *_state); +ae_bool _trypexec_matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Complex */ ae_vector* work, + matinvreport* rep, ae_state *_state); +static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) + + +#endif + +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Splits matrix length in two parts, left part should match ABLAS block size + +INPUT PARAMETERS + A - real matrix, is passed to ensure that we didn't split + complex matrix using real splitting subroutine. + matrix itself is not changed. + N - length, N>0 + +OUTPUT PARAMETERS + N1 - length + N2 - length + +N1+N2=N, N1>=N2, N2 may be zero + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +void ablassplitlength(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state) +{ + + *n1 = 0; + *n2 = 0; + + if( n>ablasblocksize(a, _state) ) + { + ablas_ablasinternalsplitlength(n, ablasblocksize(a, _state), n1, n2, _state); + } + else + { + ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); + } +} + + +/************************************************************************* +Complex ABLASSplitLength + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +void ablascomplexsplitlength(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state) +{ + + *n1 = 0; + *n2 = 0; + + if( n>ablascomplexblocksize(a, _state) ) + { + ablas_ablasinternalsplitlength(n, ablascomplexblocksize(a, _state), n1, n2, _state); + } + else + { + ablas_ablasinternalsplitlength(n, ablasmicroblocksize(_state), n1, n2, _state); + } +} + + +/************************************************************************* +Returns switch point for parallelism. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +ae_int_t gemmparallelsize(ae_state *_state) +{ + ae_int_t result; + + + result = 64; + return result; +} + + +/************************************************************************* +Returns block size - subdivision size where cache-oblivious soubroutines +switch to the optimized kernel. + +INPUT PARAMETERS + A - real matrix, is passed to ensure that we didn't split + complex matrix using real splitting subroutine. + matrix itself is not changed. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +ae_int_t ablasblocksize(/* Real */ const ae_matrix* a, + ae_state *_state) +{ + ae_int_t result; + + + result = 32; + return result; +} + + +/************************************************************************* +Block size for complex subroutines. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +ae_int_t ablascomplexblocksize(/* Complex */ const ae_matrix* a, + ae_state *_state) +{ + ae_int_t result; + + + result = 24; + return result; +} + + +/************************************************************************* +Microblock size + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +ae_int_t ablasmicroblocksize(ae_state *_state) +{ + ae_int_t result; + + + result = 8; + return result; +} + + +/************************************************************************* +Generation of an elementary reflection transformation + +The subroutine generates elementary reflection H of order N, so that, for +a given X, the following equality holds true: + + ( X(1) ) ( Beta ) +H * ( .. ) = ( 0 ) + ( X(n) ) ( 0 ) + +where + ( V(1) ) +H = 1 - Tau * ( .. ) * ( V(1), ..., V(n) ) + ( V(n) ) + +where the first component of vector V equals 1. + +Input parameters: + X - vector. Array whose index ranges within [1..N]. + N - reflection order. + +Output parameters: + X - components from 2 to N are replaced with vector V. + The first component is replaced with parameter Beta. + Tau - scalar value Tau. If X is a null vector, Tau equals 0, + otherwise 1 <= Tau <= 2. + +This subroutine is the modification of the DLARFG subroutines from +the LAPACK library. + +MODIFICATIONS: + 24.12.2005 sign(Alpha) was replaced with an analogous to the Fortran SIGN code. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void generatereflection(/* Real */ ae_vector* x, + ae_int_t n, + double* tau, + ae_state *_state) +{ + ae_int_t j; + double alpha; + double xnorm; + double v; + double beta; + double mx; + double s; + + *tau = 0.0; + + if( n<=1 ) + { + *tau = (double)(0); + return; + } + + /* + * Scale if needed (to avoid overflow/underflow during intermediate + * calculations). + */ + mx = (double)(0); + for(j=1; j<=n; j++) + { + mx = ae_maxreal(ae_fabs(x->ptr.p_double[j], _state), mx, _state); + } + s = (double)(1); + if( ae_fp_neq(mx,(double)(0)) ) + { + if( ae_fp_less_eq(mx,ae_minrealnumber/ae_machineepsilon) ) + { + s = ae_minrealnumber/ae_machineepsilon; + v = (double)1/s; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); + mx = mx*v; + } + else + { + if( ae_fp_greater_eq(mx,ae_maxrealnumber*ae_machineepsilon) ) + { + s = ae_maxrealnumber*ae_machineepsilon; + v = (double)1/s; + ae_v_muld(&x->ptr.p_double[1], 1, ae_v_len(1,n), v); + mx = mx*v; + } + } + } + + /* + * XNORM = DNRM2( N-1, X, INCX ) + */ + alpha = x->ptr.p_double[1]; + xnorm = (double)(0); + if( ae_fp_neq(mx,(double)(0)) ) + { + for(j=2; j<=n; j++) + { + xnorm = xnorm+ae_sqr(x->ptr.p_double[j]/mx, _state); + } + xnorm = ae_sqrt(xnorm, _state)*mx; + } + if( ae_fp_eq(xnorm,(double)(0)) ) + { + + /* + * H = I + */ + *tau = (double)(0); + x->ptr.p_double[1] = x->ptr.p_double[1]*s; + return; + } + + /* + * general case + */ + mx = ae_maxreal(ae_fabs(alpha, _state), ae_fabs(xnorm, _state), _state); + beta = -mx*ae_sqrt(ae_sqr(alpha/mx, _state)+ae_sqr(xnorm/mx, _state), _state); + if( ae_fp_less(alpha,(double)(0)) ) + { + beta = -beta; + } + *tau = (beta-alpha)/beta; + v = (double)1/(alpha-beta); + ae_v_muld(&x->ptr.p_double[2], 1, ae_v_len(2,n), v); + x->ptr.p_double[1] = beta; + + /* + * Scale back outputs + */ + x->ptr.p_double[1] = x->ptr.p_double[1]*s; +} + + +/************************************************************************* +Application of an elementary reflection to a rectangular matrix of size MxN + +The algorithm pre-multiplies the matrix by an elementary reflection transformation +which is given by column V and scalar Tau (see the description of the +GenerateReflection procedure). Not the whole matrix but only a part of it +is transformed (rows from M1 to M2, columns from N1 to N2). Only the elements +of this submatrix are changed. + +Input parameters: + C - matrix to be transformed. + Tau - scalar defining the transformation. + V - column defining the transformation. + Array whose index ranges within [1..M2-M1+1]. + M1, M2 - range of rows to be transformed. + N1, N2 - range of columns to be transformed. + WORK - working array whose indexes goes from N1 to N2. + +Output parameters: + C - the result of multiplying the input matrix C by the + transformation matrix which is given by Tau and V. + If N1>N2 or M1>M2, C is not modified. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void applyreflectionfromtheleft(/* Real */ ae_matrix* c, + double tau, + /* Real */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ ae_vector* work, + ae_state *_state) +{ + + + if( (ae_fp_eq(tau,(double)(0))||n1>n2)||m1>m2 ) + { + return; + } + rvectorsetlengthatleast(work, n2-n1+1, _state); + rmatrixgemv(n2-n1+1, m2-m1+1, 1.0, c, m1, n1, 1, v, 1, 0.0, work, 0, _state); + rmatrixger(m2-m1+1, n2-n1+1, c, m1, n1, -tau, v, 1, work, 0, _state); +} + + +/************************************************************************* +Application of an elementary reflection to a rectangular matrix of size MxN + +The algorithm post-multiplies the matrix by an elementary reflection transformation +which is given by column V and scalar Tau (see the description of the +GenerateReflection procedure). Not the whole matrix but only a part of it +is transformed (rows from M1 to M2, columns from N1 to N2). Only the +elements of this submatrix are changed. + +Input parameters: + C - matrix to be transformed. + Tau - scalar defining the transformation. + V - column defining the transformation. + Array whose index ranges within [1..N2-N1+1]. + M1, M2 - range of rows to be transformed. + N1, N2 - range of columns to be transformed. + WORK - working array whose indexes goes from M1 to M2. + +Output parameters: + C - the result of multiplying the input matrix C by the + transformation matrix which is given by Tau and V. + If N1>N2 or M1>M2, C is not modified. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void applyreflectionfromtheright(/* Real */ ae_matrix* c, + double tau, + /* Real */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ ae_vector* work, + ae_state *_state) +{ + + + if( (ae_fp_eq(tau,(double)(0))||n1>n2)||m1>m2 ) + { + return; + } + rvectorsetlengthatleast(work, m2-m1+1, _state); + rmatrixgemv(m2-m1+1, n2-n1+1, 1.0, c, m1, n1, 0, v, 1, 0.0, work, 0, _state); + rmatrixger(m2-m1+1, n2-n1+1, c, m1, n1, -tau, work, 0, v, 1, _state); +} + + +/************************************************************************* +Cache-oblivous complex "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixtranspose(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state) +{ + ae_int_t i; + ae_int_t s1; + ae_int_t s2; + + + if( m<=2*ablascomplexblocksize(a, _state)&&n<=2*ablascomplexblocksize(a, _state) ) + { + + /* + * base case + */ + for(i=0; i<=m-1; i++) + { + ae_v_cmove(&b->ptr.pp_complex[ib][jb+i], b->stride, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(ib,ib+n-1)); + } + } + else + { + + /* + * Cache-oblivious recursion + */ + if( m>n ) + { + ablascomplexsplitlength(a, m, &s1, &s2, _state); + cmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); + cmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); + } + else + { + ablascomplexsplitlength(a, n, &s1, &s2, _state); + cmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); + cmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); + } + } +} + + +/************************************************************************* +Cache-oblivous real "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixtranspose(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state) +{ + ae_int_t i; + ae_int_t s1; + ae_int_t s2; + + + if( m<=2*ablasblocksize(a, _state)&&n<=2*ablasblocksize(a, _state) ) + { + + /* + * base case + */ + for(i=0; i<=m-1; i++) + { + ae_v_move(&b->ptr.pp_double[ib][jb+i], b->stride, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(ib,ib+n-1)); + } + } + else + { + + /* + * Cache-oblivious recursion + */ + if( m>n ) + { + ablassplitlength(a, m, &s1, &s2, _state); + rmatrixtranspose(s1, n, a, ia, ja, b, ib, jb, _state); + rmatrixtranspose(s2, n, a, ia+s1, ja, b, ib, jb+s1, _state); + } + else + { + ablassplitlength(a, n, &s1, &s2, _state); + rmatrixtranspose(m, s1, a, ia, ja, b, ib, jb, _state); + rmatrixtranspose(m, s2, a, ia, ja+s1, b, ib+s1, jb, _state); + } + } +} + + +/************************************************************************* +This code enforces symmetricy of the matrix by copying Upper part to lower +one (or vice versa). + +INPUT PARAMETERS: + A - matrix + N - number of rows/columns + IsUpper - whether we want to copy upper triangle to lower one (True) + or vice versa (False). +*************************************************************************/ +void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i+1; j<=n-1; j++) + { + a->ptr.pp_double[j][i] = a->ptr.pp_double[i][j]; + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=i+1; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = a->ptr.pp_double[j][i]; + } + } + } +} + + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixcopy(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state) +{ + ae_int_t i; + + + if( m==0||n==0 ) + { + return; + } + for(i=0; i<=m-1; i++) + { + ae_v_cmove(&b->ptr.pp_complex[ib+i][jb], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(jb,jb+n-1)); + } +} + + +/************************************************************************* +Copy + +Input parameters: + N - subvector size + A - source vector, N elements are copied + IA - source offset (first element index) + B - destination vector, must be large enough to store result + IB - destination offset (first element index) +*************************************************************************/ +void rvectorcopy(ae_int_t n, + /* Real */ const ae_vector* a, + ae_int_t ia, + /* Real */ ae_vector* b, + ae_int_t ib, + ae_state *_state) +{ + + + if( n==0 ) + { + return; + } + if( ia==0&&ib==0 ) + { + rcopyv(n, a, b, _state); + } + else + { + rcopyvx(n, a, ia, b, ib, _state); + } +} + + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixcopy(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state) +{ + ae_int_t i; + + + if( m==0||n==0 ) + { + return; + } + for(i=0; i<=m-1; i++) + { + ae_v_move(&b->ptr.pp_double[ib+i][jb], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(jb,jb+n-1)); + } +} + + +/************************************************************************* +Performs generalized copy: B := Beta*B + Alpha*A. + +If Beta=0, then previous contents of B is simply ignored. If Alpha=0, then +A is ignored and not referenced. If both Alpha and Beta are zero, B is +filled by zeros. + +Input parameters: + M - number of rows + N - number of columns + Alpha- coefficient + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Beta- coefficient + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixgencopy(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double beta, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( m==0||n==0 ) + { + return; + } + + /* + * Zero-fill + */ + if( ae_fp_eq(alpha,(double)(0))&&ae_fp_eq(beta,(double)(0)) ) + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[ib+i][jb+j] = (double)(0); + } + } + return; + } + + /* + * Inplace multiply + */ + if( ae_fp_eq(alpha,(double)(0)) ) + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[ib+i][jb+j] = beta*b->ptr.pp_double[ib+i][jb+j]; + } + } + return; + } + + /* + * Multiply and copy + */ + if( ae_fp_eq(beta,(double)(0)) ) + { + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[ib+i][jb+j] = alpha*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + + /* + * Generic + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + b->ptr.pp_double[ib+i][jb+j] = alpha*a->ptr.pp_double[ia+i][ja+j]+beta*b->ptr.pp_double[ib+i][jb+j]; + } + } +} + + +/************************************************************************* +Rank-1 correction: A := A + alpha*u*v' + +NOTE: this function expects A to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, u, v. + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Alpha- coefficient + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset + + + -- ALGLIB routine -- + + 16.10.2017 + Bochkanov Sergey +*************************************************************************/ +void rmatrixger(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double alpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_int_t i; + double s; + + + + /* + * Quick exit + */ + if( m<=0||n<=0 ) + { + return; + } + + /* + * Try fast kernels: + * * vendor kernel + * * internal kernel + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel first + */ + if( rmatrixgerpbl(m, n, a, ia, ja, alpha, u, iu, v, iv, _state) ) + { + return; + } + } + if( rmatrixgerf(m, n, a, ia, ja, alpha, u, iu, v, iv, _state) ) + { + return; + } + + /* + * Generic code + */ + for(i=0; i<=m-1; i++) + { + s = alpha*u->ptr.p_double[iu+i]; + ae_v_addd(&a->ptr.pp_double[ia+i][ja], 1, &v->ptr.p_double[iv], 1, ae_v_len(ja,ja+n-1), s); + } +} + + +/************************************************************************* +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void cmatrixrank1(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_int_t i; + ae_complex s; + + + + /* + * Quick exit + */ + if( m<=0||n<=0 ) + { + return; + } + + /* + * Try fast kernels: + * * vendor kernel + * * internal kernel + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel first + */ + if( cmatrixrank1pbl(m, n, a, ia, ja, u, iu, v, iv, _state) ) + { + return; + } + } + if( cmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) + { + return; + } + + /* + * Generic code + */ + for(i=0; i<=m-1; i++) + { + s = u->ptr.p_complex[iu+i]; + ae_v_caddc(&a->ptr.pp_complex[ia+i][ja], 1, &v->ptr.p_complex[iv], 1, "N", ae_v_len(ja,ja+n-1), s); + } +} + + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGER() + which is more generic version of this function. + +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void rmatrixrank1(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state) +{ + ae_int_t i; + double s; + + + + /* + * Quick exit + */ + if( m<=0||n<=0 ) + { + return; + } + + /* + * Try fast kernels: + * * vendor kernel + * * internal kernel + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel first + */ + if( rmatrixrank1pbl(m, n, a, ia, ja, u, iu, v, iv, _state) ) + { + return; + } + } + if( rmatrixrank1f(m, n, a, ia, ja, u, iu, v, iv, _state) ) + { + return; + } + + /* + * Generic code + */ + for(i=0; i<=m-1; i++) + { + s = u->ptr.p_double[iu+i]; + ae_v_addd(&a->ptr.pp_double[ia+i][ja], 1, &v->ptr.p_double[iv], 1, ae_v_len(ja,ja+n-1), s); + } +} + + +void rmatrixgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + + + + /* + * Quick exit for M=0, N=0 or Alpha=0. + * + * After this block we have M>0, N>0, Alpha<>0. + */ + if( m<=0 ) + { + return; + } + if( n<=0||ae_fp_eq(alpha,0.0) ) + { + if( ae_fp_neq(beta,(double)(0)) ) + { + rmulvx(m, beta, y, iy, _state); + } + else + { + rsetvx(m, 0.0, y, iy, _state); + } + return; + } + + /* + * Try fast kernels + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel + */ + if( rmatrixgemvpbl(m, n, alpha, a, ia, ja, opa, x, ix, beta, y, iy, _state) ) + { + return; + } + } + if( ia+ja+ix+iy==0 ) + { + rgemv(m, n, alpha, a, opa, x, beta, y, _state); + } + else + { + rgemvx(m, n, alpha, a, ia, ja, opa, x, ix, beta, y, iy, _state); + } +} + + +/************************************************************************* +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + M>=0 + N - number of columns of op(A) + N>=0 + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + * OpA=2 => op(A) = A^H + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixmv(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Complex */ const ae_vector* x, + ae_int_t ix, + /* Complex */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t i; + ae_complex v; + + + + /* + * Quick exit + */ + if( m==0 ) + { + return; + } + if( n==0 ) + { + for(i=0; i<=m-1; i++) + { + y->ptr.p_complex[iy+i] = ae_complex_from_i(0); + } + return; + } + + /* + * Try fast kernels + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel + */ + if( cmatrixmvpbl(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) + { + return; + } + } + + /* + * Generic code + */ + if( opa==0 ) + { + + /* + * y = A*x + */ + for(i=0; i<=m-1; i++) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &x->ptr.p_complex[ix], 1, "N", ae_v_len(ja,ja+n-1)); + y->ptr.p_complex[iy+i] = v; + } + return; + } + if( opa==1 ) + { + + /* + * y = A^T*x + */ + for(i=0; i<=m-1; i++) + { + y->ptr.p_complex[iy+i] = ae_complex_from_i(0); + } + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_complex[ix+i]; + ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "N", ae_v_len(iy,iy+m-1), v); + } + return; + } + if( opa==2 ) + { + + /* + * y = A^H*x + */ + for(i=0; i<=m-1; i++) + { + y->ptr.p_complex[iy+i] = ae_complex_from_i(0); + } + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_complex[ix+i]; + ae_v_caddc(&y->ptr.p_complex[iy], 1, &a->ptr.pp_complex[ia+i][ja], 1, "Conj", ae_v_len(iy,iy+m-1), v); + } + return; + } +} + + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGEMV() + which is more generic version of this function. + +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixmv(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t i; + double v; + + + + /* + * Quick exit + */ + if( m==0 ) + { + return; + } + if( n==0 ) + { + for(i=0; i<=m-1; i++) + { + y->ptr.p_double[iy+i] = (double)(0); + } + return; + } + + /* + * Try fast kernels + */ + if( m>ablas_blas2minvendorkernelsize&&n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel + */ + if( rmatrixmvpbl(m, n, a, ia, ja, opa, x, ix, y, iy, _state) ) + { + return; + } + } + + /* + * Generic code + */ + if( opa==0 ) + { + + /* + * y = A*x + */ + for(i=0; i<=m-1; i++) + { + v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &x->ptr.p_double[ix], 1, ae_v_len(ja,ja+n-1)); + y->ptr.p_double[iy+i] = v; + } + return; + } + if( opa==1 ) + { + + /* + * y = A^T*x + */ + for(i=0; i<=m-1; i++) + { + y->ptr.p_double[iy+i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + ae_v_addd(&y->ptr.p_double[iy], 1, &a->ptr.pp_double[ia+i][ja], 1, ae_v_len(iy,iy+m-1), v); + } + return; + } +} + + +void rmatrixsymv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double vr; + double vx; + + + + /* + * Quick exit for M=0, N=0 or Alpha=0. + * + * After this block we have M>0, N>0, Alpha<>0. + */ + if( n<=0 ) + { + return; + } + if( ae_fp_eq(alpha,0.0) ) + { + if( ae_fp_neq(beta,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[iy+i] = beta*y->ptr.p_double[iy+i]; + } + } + else + { + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[iy+i] = 0.0; + } + } + return; + } + + /* + * Try fast kernels + */ + if( n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel + */ + if( rmatrixsymvpbl(n, alpha, a, ia, ja, isupper, x, ix, beta, y, iy, _state) ) + { + return; + } + } + + /* + * Generic code + */ + if( ae_fp_neq(beta,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[iy+i] = beta*y->ptr.p_double[iy+i]; + } + } + else + { + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[iy+i] = 0.0; + } + } + if( isupper ) + { + + /* + * Upper triangle of A is stored + */ + for(i=0; i<=n-1; i++) + { + + /* + * Process diagonal element + */ + v = alpha*a->ptr.pp_double[ia+i][ja+i]; + y->ptr.p_double[iy+i] = y->ptr.p_double[iy+i]+v*x->ptr.p_double[ix+i]; + + /* + * Process off-diagonal elements + */ + vr = 0.0; + vx = x->ptr.p_double[ix+i]; + for(j=i+1; j<=n-1; j++) + { + v = alpha*a->ptr.pp_double[ia+i][ja+j]; + y->ptr.p_double[iy+j] = y->ptr.p_double[iy+j]+v*vx; + vr = vr+v*x->ptr.p_double[ix+j]; + } + y->ptr.p_double[iy+i] = y->ptr.p_double[iy+i]+vr; + } + } + else + { + + /* + * Lower triangle of A is stored + */ + for(i=0; i<=n-1; i++) + { + + /* + * Process diagonal element + */ + v = alpha*a->ptr.pp_double[ia+i][ja+i]; + y->ptr.p_double[iy+i] = y->ptr.p_double[iy+i]+v*x->ptr.p_double[ix+i]; + + /* + * Process off-diagonal elements + */ + vr = 0.0; + vx = x->ptr.p_double[ix+i]; + for(j=0; j<=i-1; j++) + { + v = alpha*a->ptr.pp_double[ia+i][ja+j]; + y->ptr.p_double[iy+j] = y->ptr.p_double[iy+j]+v*vx; + vr = vr+v*x->ptr.p_double[ix+j]; + } + y->ptr.p_double[iy+i] = y->ptr.p_double[iy+i]+vr; + } + } +} + + +double rmatrixsyvmv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + double result; + + + + /* + * Quick exit for N=0 + */ + if( n<=0 ) + { + result = (double)(0); + return result; + } + + /* + * Generic code + */ + rmatrixsymv(n, 1.0, a, ia, ja, isupper, x, ix, 0.0, tmp, 0, _state); + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[ix+i]*tmp->ptr.p_double[i]; + } + return result; +} + + +/************************************************************************* +This subroutine solves linear system op(A)*x=b where: +* A is NxN upper/lower triangular/unitriangular matrix +* X and B are Nx1 vectors +* "op" may be identity transformation or transposition + +Solution replaces X. + +IMPORTANT: * no overflow/underflow/denegeracy tests is performed. + * no integrity checks for operand sizes, out-of-bounds accesses + and so on is performed + +INPUT PARAMETERS + N - matrix size, N>=0 + A - matrix, actial matrix is stored in A[IA:IA+N-1,JA:JA+N-1] + IA - submatrix offset + JA - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - right part, actual vector is stored in X[IX:IX+N-1] + IX - offset + +OUTPUT PARAMETERS + X - solution replaces elements X[IX:IX+N-1] + + -- ALGLIB routine / remastering of LAPACK's DTRSV -- + (c) 2017 Bochkanov Sergey - converted to ALGLIB + (c) 2016 Reference BLAS level1 routine (LAPACK version 3.7.0) + Reference BLAS is a software package provided by Univ. of Tennessee, + Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd. +*************************************************************************/ +void rmatrixtrsv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Quick exit + */ + if( n<=0 ) + { + return; + } + + /* + * Try fast kernels + */ + if( n>ablas_blas2minvendorkernelsize ) + { + + /* + * Try PBL kernel + */ + if( rmatrixtrsvpbl(n, a, ia, ja, isupper, isunit, optype, x, ix, _state) ) + { + return; + } + } + + /* + * Generic code + */ + if( optype==0&&isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + for(j=i+1; j<=n-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==0&&!isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + for(j=0; j<=i-1; j++) + { + v = v-a->ptr.pp_double[ia+i][ja+j]*x->ptr.p_double[ix+j]; + } + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + } + return; + } + if( optype==1&&isupper ) + { + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==(double)0 ) + { + continue; + } + for(j=i+1; j<=n-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + if( optype==1&&!isupper ) + { + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[ix+i]; + if( !isunit ) + { + v = v/a->ptr.pp_double[ia+i][ja+i]; + } + x->ptr.p_double[ix+i] = v; + if( v==(double)0 ) + { + continue; + } + for(j=0; j<=i-1; j++) + { + x->ptr.p_double[ix+j] = x->ptr.p_double[ix+j]-v*a->ptr.pp_double[ia+i][ja+j]; + } + } + return; + } + ae_assert(ae_false, "RMatrixTRSV: unexpected operation type", _state); +} + + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 20.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(m, n, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "CMatrixRightTRSM: integrity check failed", _state); + + /* + * Upper level parallelization: + * * decide whether it is feasible to activate multithreading + * * perform optionally parallelized splits on M + */ + if( m>=2*tsb&&ae_fp_greater_eq((double)4*rmul3((double)(m), (double)(n), (double)(n), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_cmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state) ) + { + return; + } + } + if( m>=2*tsb ) + { + + /* + * Split X: X*A = (X1 X2)^T*A + */ + tiledsplit(m, tsb, &s1, &s2, _state); + cmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); + return; + } + + /* + * Basecase: either PBL-supported code or ALGLIB basecase code + */ + if( imax2(m, n, _state)<=tsb ) + { + if( cmatrixrighttrsmpbl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + } + if( imax2(m, n, _state)<=tsa ) + { + ablas_cmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Recursive subdivision + */ + if( m>=n ) + { + + /* + * Split X: X*A = (X1 X2)^T*A + */ + tiledsplit(m, tscur, &s1, &s2, _state); + cmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + else + { + + /* + * Split A: + * (A1 A12) + * X*op(A) = X*op( ) + * ( A2) + * + * Different variants depending on + * IsUpper/OpType combinations + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( isupper&&optype==0 ) + { + + /* + * (A1 A12)-1 + * X*A^-1 = (X1 X2)*( ) + * ( A2) + */ + cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1, j1+s1, 0, ae_complex_from_d(1.0), x, i2, j2+s1, _state); + cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + if( isupper&&optype!=0 ) + { + + /* + * (A1' )-1 + * X*A^-1 = (X1 X2)*( ) + * (A12' A2') + */ + cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1, j1+s1, optype, ae_complex_from_d(1.0), x, i2, j2, _state); + cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( !isupper&&optype==0 ) + { + + /* + * (A1 )-1 + * X*A^-1 = (X1 X2)*( ) + * (A21 A2) + */ + cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + cmatrixgemm(m, s1, s2, ae_complex_from_d(-1.0), x, i2, j2+s1, 0, a, i1+s1, j1, 0, ae_complex_from_d(1.0), x, i2, j2, _state); + cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( !isupper&&optype!=0 ) + { + + /* + * (A1' A21')-1 + * X*A^-1 = (X1 X2)*( ) + * ( A2') + */ + cmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixgemm(m, s2, s1, ae_complex_from_d(-1.0), x, i2, j2, 0, a, i1+s1, j1, optype, ae_complex_from_d(1.0), x, i2, j2+s1, _state); + cmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_cmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(m, n, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "CMatrixLeftTRSM: integrity check failed", _state); + + /* + * Upper level parallelization: + * * decide whether it is feasible to activate multithreading + * * perform optionally parallelized splits on N + */ + if( n>=2*tsb&&ae_fp_greater_eq((double)4*rmul3((double)(n), (double)(m), (double)(m), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_cmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state) ) + { + return; + } + } + if( n>=2*tsb ) + { + tiledsplit(n, tscur, &s1, &s2, _state); + cmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); + cmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Basecase: either PBL-supported code or ALGLIB basecase code + */ + if( imax2(m, n, _state)<=tsb ) + { + if( cmatrixlefttrsmpbl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + } + if( imax2(m, n, _state)<=tsa ) + { + ablas_cmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Recursive subdivision + */ + if( n>=m ) + { + + /* + * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) + */ + tiledsplit(n, tscur, &s1, &s2, _state); + cmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + else + { + + /* + * Split A + */ + tiledsplit(m, tscur, &s1, &s2, _state); + if( isupper&&optype==0 ) + { + + /* + * (A1 A12)-1 ( X1 ) + * A^-1*X* = ( ) *( ) + * ( A2) ( X2 ) + */ + cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1, j1+s1, 0, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); + cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( isupper&&optype!=0 ) + { + + /* + * (A1' )-1 ( X1 ) + * A^-1*X = ( ) *( ) + * (A12' A2') ( X2 ) + */ + cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1, j1+s1, optype, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); + cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + if( !isupper&&optype==0 ) + { + + /* + * (A1 )-1 ( X1 ) + * A^-1*X = ( ) *( ) + * (A21 A2) ( X2 ) + */ + cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + cmatrixgemm(s2, n, s1, ae_complex_from_d(-1.0), a, i1+s1, j1, 0, x, i2, j2, 0, ae_complex_from_d(1.0), x, i2+s1, j2, _state); + cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + if( !isupper&&optype!=0 ) + { + + /* + * (A1' A21')-1 ( X1 ) + * A^-1*X = ( ) *( ) + * ( A2') ( X2 ) + */ + cmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + cmatrixgemm(s1, n, s2, ae_complex_from_d(-1.0), a, i1+s1, j1, optype, x, i2+s1, j2, 0, ae_complex_from_d(1.0), x, i2, j2, _state); + cmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_cmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(m, n, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "RMatrixRightTRSM: integrity check failed", _state); + + /* + * Upper level parallelization: + * * decide whether it is feasible to activate multithreading + * * perform optionally parallelized splits on M + */ + if( m>=2*tsb&&ae_fp_greater_eq(rmul3((double)(m), (double)(n), (double)(n), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_rmatrixrighttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state) ) + { + return; + } + } + if( m>=2*tsb ) + { + + /* + * Split X: X*A = (X1 X2)^T*A + */ + tiledsplit(m, tsb, &s1, &s2, _state); + rmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); + return; + } + + /* + * Basecase: PBL or ALGLIB code + */ + if( imax2(m, n, _state)<=tsb ) + { + if( rmatrixrighttrsmpbl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + } + if( imax2(m, n, _state)<=tsa ) + { + ablas_rmatrixrighttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Recursive subdivision + */ + if( m>=n ) + { + + /* + * Split X: X*A = (X1 X2)^T*A + */ + tiledsplit(m, tscur, &s1, &s2, _state); + rmatrixrighttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixrighttrsm(s2, n, a, i1, j1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + else + { + + /* + * Split A: + * (A1 A12) + * X*op(A) = X*op( ) + * ( A2) + * + * Different variants depending on + * IsUpper/OpType combinations + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( isupper&&optype==0 ) + { + + /* + * (A1 A12)-1 + * X*A^-1 = (X1 X2)*( ) + * ( A2) + */ + rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1, j1+s1, 0, 1.0, x, i2, j2+s1, _state); + rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + if( isupper&&optype!=0 ) + { + + /* + * (A1' )-1 + * X*A^-1 = (X1 X2)*( ) + * (A12' A2') + */ + rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1, j1+s1, optype, 1.0, x, i2, j2, _state); + rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( !isupper&&optype==0 ) + { + + /* + * (A1 )-1 + * X*A^-1 = (X1 X2)*( ) + * (A21 A2) + */ + rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + rmatrixgemm(m, s1, s2, -1.0, x, i2, j2+s1, 0, a, i1+s1, j1, 0, 1.0, x, i2, j2, _state); + rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( !isupper&&optype!=0 ) + { + + /* + * (A1' A21')-1 + * X*A^-1 = (X1 X2)*( ) + * ( A2') + */ + rmatrixrighttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixgemm(m, s2, s1, -1.0, x, i2, j2, 0, a, i1+s1, j1, optype, 1.0, x, i2, j2+s1, _state); + rmatrixrighttrsm(m, s2, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(m, n, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "RMatrixLeftTRSMRec: integrity check failed", _state); + + /* + * Upper level parallelization: + * * decide whether it is feasible to activate multithreading + * * perform optionally parallelized splits on N + */ + if( n>=2*tsb&&ae_fp_greater_eq(rmul3((double)(n), (double)(m), (double)(m), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_rmatrixlefttrsm(m,n,a,i1,j1,isupper,isunit,optype,x,i2,j2, _state) ) + { + return; + } + } + if( n>=2*tsb ) + { + tiledsplit(n, tscur, &s1, &s2, _state); + rmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); + rmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Basecase: PBL or ALGLIB code + */ + if( imax2(m, n, _state)<=tsb ) + { + if( rmatrixlefttrsmpbl(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + } + if( imax2(m, n, _state)<=tsa ) + { + ablas_rmatrixlefttrsm2(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + return; + } + + /* + * Recursive subdivision + */ + if( n>=m ) + { + + /* + * Split X: op(A)^-1*X = op(A)^-1*(X1 X2) + */ + tiledsplit(n, tscur, &s1, &s2, _state); + rmatrixlefttrsm(m, s1, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixlefttrsm(m, s2, a, i1, j1, isupper, isunit, optype, x, i2, j2+s1, _state); + } + else + { + + /* + * Split A + */ + tiledsplit(m, tscur, &s1, &s2, _state); + if( isupper&&optype==0 ) + { + + /* + * (A1 A12)-1 ( X1 ) + * A^-1*X* = ( ) *( ) + * ( A2) ( X2 ) + */ + rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + rmatrixgemm(s1, n, s2, -1.0, a, i1, j1+s1, 0, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); + rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + if( isupper&&optype!=0 ) + { + + /* + * (A1' )-1 ( X1 ) + * A^-1*X = ( ) *( ) + * (A12' A2') ( X2 ) + */ + rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixgemm(s2, n, s1, -1.0, a, i1, j1+s1, optype, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); + rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + if( !isupper&&optype==0 ) + { + + /* + * (A1 )-1 ( X1 ) + * A^-1*X = ( ) *( ) + * (A21 A2) ( X2 ) + */ + rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + rmatrixgemm(s2, n, s1, -1.0, a, i1+s1, j1, 0, x, i2, j2, 0, 1.0, x, i2+s1, j2, _state); + rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + } + if( !isupper&&optype!=0 ) + { + + /* + * (A1' A21')-1 ( X1 ) + * A^-1*X = ( ) *( ) + * ( A2') ( X2 ) + */ + rmatrixlefttrsm(s2, n, a, i1+s1, j1+s1, isupper, isunit, optype, x, i2+s1, j2, _state); + rmatrixgemm(s1, n, s2, -1.0, a, i1+s1, j1, optype, x, i2+s1, j2, 0, 1.0, x, i2, j2, _state); + rmatrixlefttrsm(s1, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C +where: +* C is NxN Hermitian matrix given by its upper/lower triangle +* A is NxK matrix when A*A^H is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^H is calculated + * 2 - A^H*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether upper or lower triangle of C is updated; + this function updates only one half of C, leaving + other half unchanged (not referenced at all). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixherk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(n, k, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "CMatrixHERK: integrity check failed", _state); + + /* + * Decide whether it is feasible to activate multithreading + */ + if( n>=2*tsb&&ae_fp_greater_eq((double)8*rmul3((double)(k), (double)(n), (double)(n), _state)/(double)2,smpactivationlevel(_state)) ) + { + if( _trypexec_cmatrixherk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state) ) + { + return; + } + } + + /* + * Use PBL or ALGLIB basecase code + */ + if( imax2(n, k, _state)<=tsb ) + { + if( cmatrixherkpbl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) + { + return; + } + } + if( imax2(n, k, _state)<=tsa ) + { + ablas_cmatrixherk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + return; + } + + /* + * Recursive division of the problem + */ + if( k>=n ) + { + + /* + * Split K + */ + tiledsplit(k, tscur, &s1, &s2, _state); + if( optypea==0 ) + { + cmatrixherk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); + } + else + { + cmatrixherk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); + } + } + else + { + + /* + * Split N + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( optypea==0&&isupper ) + { + cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 0, a, ia+s1, ja, 2, ae_complex_from_d(beta), c, ic, jc+s1, _state); + } + if( optypea==0&&!isupper ) + { + cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia+s1, ja, 0, a, ia, ja, 2, ae_complex_from_d(beta), c, ic+s1, jc, _state); + } + if( optypea!=0&&isupper ) + { + cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + cmatrixgemm(s1, s2, k, ae_complex_from_d(alpha), a, ia, ja, 2, a, ia, ja+s1, 0, ae_complex_from_d(beta), c, ic, jc+s1, _state); + } + if( optypea!=0&&!isupper ) + { + cmatrixherk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + cmatrixherk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + cmatrixgemm(s2, s1, k, ae_complex_from_d(alpha), a, ia, ja+s1, 2, a, ia, ja, 0, ae_complex_from_d(beta), c, ic+s1, jc, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_cmatrixherk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C +where: +* C is NxN symmetric matrix given by its upper/lower triangle +* A is NxK matrix when A*A^T is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^T is calculated + * 2 - A^T*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether C is upper triangular or lower triangular + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax2(n, k, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "RMatrixSYRK: integrity check failed", _state); + + /* + * Decide whether it is feasible to activate multithreading + */ + if( n>=2*tsb&&ae_fp_greater_eq((double)2*rmul3((double)(k), (double)(n), (double)(n), _state)/(double)2,smpactivationlevel(_state)) ) + { + if( _trypexec_rmatrixsyrk(n,k,alpha,a,ia,ja,optypea,beta,c,ic,jc,isupper, _state) ) + { + return; + } + } + + /* + * Use PBL or generic basecase code + */ + if( imax2(n, k, _state)<=tsb ) + { + if( rmatrixsyrkpbl(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) + { + return; + } + } + if( imax2(n, k, _state)<=tsa ) + { + ablas_rmatrixsyrk2(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + return; + } + + /* + * Recursive subdivision of the problem + */ + if( k>=n ) + { + + /* + * Split K + */ + tiledsplit(k, tscur, &s1, &s2, _state); + if( optypea==0 ) + { + rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(n, s2, alpha, a, ia, ja+s1, optypea, 1.0, c, ic, jc, isupper, _state); + } + else + { + rmatrixsyrk(n, s1, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(n, s2, alpha, a, ia+s1, ja, optypea, 1.0, c, ic, jc, isupper, _state); + } + } + else + { + + /* + * Split N + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( optypea==0&&isupper ) + { + rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 0, a, ia+s1, ja, 1, beta, c, ic, jc+s1, _state); + } + if( optypea==0&&!isupper ) + { + rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(s2, k, alpha, a, ia+s1, ja, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + rmatrixgemm(s2, s1, k, alpha, a, ia+s1, ja, 0, a, ia, ja, 1, beta, c, ic+s1, jc, _state); + } + if( optypea!=0&&isupper ) + { + rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + rmatrixgemm(s1, s2, k, alpha, a, ia, ja, 1, a, ia, ja+s1, 0, beta, c, ic, jc+s1, _state); + } + if( optypea!=0&&!isupper ) + { + rmatrixsyrk(s1, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); + rmatrixsyrk(s2, k, alpha, a, ia, ja+s1, optypea, beta, c, ic+s1, jc+s1, isupper, _state); + rmatrixgemm(s2, s1, k, alpha, a, ia, ja+s1, 1, a, ia, ja, 0, beta, c, ic+s1, jc, _state); + } + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition, conjugate transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + Beta - coefficient + C - matrix (PREALLOCATED, large enough to store result) + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void cmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t ts; + + + ts = matrixtilesizeb(_state); + + /* + * Check input sizes for correctness + */ + ae_assert((optypea==0||optypea==1)||optypea==2, "CMatrixGEMM: incorrect OpTypeA (must be 0 or 1 or 2)", _state); + ae_assert((optypeb==0||optypeb==1)||optypeb==2, "CMatrixGEMM: incorrect OpTypeB (must be 0 or 1 or 2)", _state); + ae_assert(ic+m<=c->rows, "CMatrixGEMM: incorect size of output matrix C", _state); + ae_assert(jc+n<=c->cols, "CMatrixGEMM: incorect size of output matrix C", _state); + + /* + * Decide whether it is feasible to activate multithreading + */ + if( (m>=2*ts||n>=2*ts)&&ae_fp_greater_eq((double)8*rmul3((double)(m), (double)(n), (double)(k), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_cmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state) ) + { + return; + } + } + + /* + * Start actual work + */ + ablas_cmatrixgemmrec(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_cmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + Beta - coefficient + C - PREALLOCATED output matrix, large enough to store result + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t ts; + + + ts = matrixtilesizeb(_state); + + /* + * Check input sizes for correctness + */ + ae_assert(optypea==0||optypea==1, "RMatrixGEMM: incorrect OpTypeA (must be 0 or 1)", _state); + ae_assert(optypeb==0||optypeb==1, "RMatrixGEMM: incorrect OpTypeB (must be 0 or 1)", _state); + ae_assert(ic+m<=c->rows, "RMatrixGEMM: incorect size of output matrix C", _state); + ae_assert(jc+n<=c->cols, "RMatrixGEMM: incorect size of output matrix C", _state); + + /* + * Decide whether it is feasible to activate multithreading + */ + if( (m>=2*ts||n>=2*ts)&&ae_fp_greater_eq((double)2*rmul3((double)(m), (double)(n), (double)(k), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_rmatrixgemm(m,n,k,alpha,a,ia,ja,optypea,b,ib,jb,optypeb,beta,c,ic,jc, _state) ) + { + return; + } + } + + /* + * Start actual work + */ + ablas_rmatrixgemmrec(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_rmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine is an older version of CMatrixHERK(), one with wrong name +(it is HErmitian update, not SYmmetric). It is left here for backward +compatibility. + + -- ALGLIB routine -- + 16.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + + + cmatrixherk(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state); +} + + +/************************************************************************* +Performs one step of stable Gram-Schmidt process on vector X[] using +set of orthonormal rows Q[]. + +INPUT PARAMETERS: + Q - array[M,N], matrix with orthonormal rows + M, N - rows/cols + X - array[N], vector to process + NeedQX - whether we need QX or not + +OUTPUT PARAMETERS: + X - stores X - Q'*(Q*X) + QX - if NeedQX is True, array[M] filled with elements of Q*X, + reallocated if length is less than M. + Ignored otherwise. + +NOTE: this function silently exits when M=0, doing nothing + + -- ALGLIB -- + Copyright 20.01.2020 by Bochkanov Sergey +*************************************************************************/ +void rowwisegramschmidt(/* Real */ const ae_matrix* q, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* qx, + ae_bool needqx, + ae_state *_state) +{ + ae_int_t i; + double v; + + + if( m==0 ) + { + return; + } + if( needqx ) + { + rvectorsetlengthatleast(qx, m, _state); + } + for(i=0; i<=m-1; i++) + { + v = rdotvr(n, x, q, i, _state); + raddrv(n, -v, q, i, x, _state); + if( needqx ) + { + qx->ptr.p_double[i] = v; + } + } +} + + +/************************************************************************* +Complex ABLASSplitLength + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +static void ablas_ablasinternalsplitlength(ae_int_t n, + ae_int_t nb, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state) +{ + ae_int_t r; + + *n1 = 0; + *n2 = 0; + + if( n<=nb ) + { + + /* + * Block size, no further splitting + */ + *n1 = n; + *n2 = 0; + } + else + { + + /* + * Greater than block size + */ + if( n%nb!=0 ) + { + + /* + * Split remainder + */ + *n2 = n%nb; + *n1 = n-(*n2); + } + else + { + + /* + * Split on block boundaries + */ + *n2 = n/2; + *n1 = n-(*n2); + if( *n1%nb==0 ) + { + return; + } + r = nb-*n1%nb; + *n1 = *n1+r; + *n2 = *n2-r; + } + } +} + + +/************************************************************************* +Level 2 variant of CMatrixRightTRSM +*************************************************************************/ +static void ablas_cmatrixrighttrsm2(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex vc; + ae_complex vd; + + + + /* + * Special case + */ + if( n*m==0 ) + { + return; + } + + /* + * Try to call fast TRSM + */ + if( cmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + + /* + * General case + */ + if( isupper ) + { + + /* + * Upper triangular matrix + */ + if( optype==0 ) + { + + /* + * X*A^(-1) + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = a->ptr.pp_complex[i1+j][j1+j]; + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); + if( jptr.pp_complex[i2+i][j2+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+i][j2+j+1], 1, &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1), vc); + } + } + } + return; + } + if( optype==1 ) + { + + /* + * X*A^(-T) + */ + for(i=0; i<=m-1; i++) + { + for(j=n-1; j>=0; j--) + { + vc = ae_complex_from_i(0); + vd = ae_complex_from_i(1); + if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "N", ae_v_len(j2+j+1,j2+n-1)); + } + if( !isunit ) + { + vd = a->ptr.pp_complex[i1+j][j1+j]; + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); + } + } + return; + } + if( optype==2 ) + { + + /* + * X*A^(-H) + */ + for(i=0; i<=m-1; i++) + { + for(j=n-1; j>=0; j--) + { + vc = ae_complex_from_i(0); + vd = ae_complex_from_i(1); + if( jptr.pp_complex[i2+i][j2+j+1], 1, "N", &a->ptr.pp_complex[i1+j][j1+j+1], 1, "Conj", ae_v_len(j2+j+1,j2+n-1)); + } + if( !isunit ) + { + vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); + } + } + return; + } + } + else + { + + /* + * Lower triangular matrix + */ + if( optype==0 ) + { + + /* + * X*A^(-1) + */ + for(i=0; i<=m-1; i++) + { + for(j=n-1; j>=0; j--) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = a->ptr.pp_complex[i1+j][j1+j]; + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(x->ptr.pp_complex[i2+i][j2+j],vd); + if( j>0 ) + { + vc = x->ptr.pp_complex[i2+i][j2+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1), vc); + } + } + } + return; + } + if( optype==1 ) + { + + /* + * X*A^(-T) + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + vc = ae_complex_from_i(0); + vd = ae_complex_from_i(1); + if( j>0 ) + { + vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "N", ae_v_len(j2,j2+j-1)); + } + if( !isunit ) + { + vd = a->ptr.pp_complex[i1+j][j1+j]; + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); + } + } + return; + } + if( optype==2 ) + { + + /* + * X*A^(-H) + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + vc = ae_complex_from_i(0); + vd = ae_complex_from_i(1); + if( j>0 ) + { + vc = ae_v_cdotproduct(&x->ptr.pp_complex[i2+i][j2], 1, "N", &a->ptr.pp_complex[i1+j][j1], 1, "Conj", ae_v_len(j2,j2+j-1)); + } + if( !isunit ) + { + vd = ae_c_conj(a->ptr.pp_complex[i1+j][j1+j], _state); + } + x->ptr.pp_complex[i2+i][j2+j] = ae_c_div(ae_c_sub(x->ptr.pp_complex[i2+i][j2+j],vc),vd); + } + } + return; + } + } +} + + +/************************************************************************* +Level-2 subroutine +*************************************************************************/ +static void ablas_cmatrixlefttrsm2(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex vc; + ae_complex vd; + + + + /* + * Special case + */ + if( n*m==0 ) + { + return; + } + + /* + * Try to call fast TRSM + */ + if( cmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + + /* + * General case + */ + if( isupper ) + { + + /* + * Upper triangular matrix + */ + if( optype==0 ) + { + + /* + * A^(-1)*X + */ + for(i=m-1; i>=0; i--) + { + for(j=i+1; j<=m-1; j++) + { + vc = a->ptr.pp_complex[i1+i][j1+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + if( !isunit ) + { + vd = ae_c_d_div((double)(1),a->ptr.pp_complex[i1+i][j1+i]); + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + } + } + return; + } + if( optype==1 ) + { + + /* + * A^(-T)*X + */ + for(i=0; i<=m-1; i++) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = ae_c_d_div((double)(1),a->ptr.pp_complex[i1+i][j1+i]); + } + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i+1; j<=m-1; j++) + { + vc = a->ptr.pp_complex[i1+i][j1+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + } + return; + } + if( optype==2 ) + { + + /* + * A^(-H)*X + */ + for(i=0; i<=m-1; i++) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = ae_c_d_div((double)(1),ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); + } + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i+1; j<=m-1; j++) + { + vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); + ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + } + return; + } + } + else + { + + /* + * Lower triangular matrix + */ + if( optype==0 ) + { + + /* + * A^(-1)*X + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=i-1; j++) + { + vc = a->ptr.pp_complex[i1+i][j1+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+i][j2], 1, &x->ptr.pp_complex[i2+j][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = ae_c_d_div((double)(1),a->ptr.pp_complex[i1+j][j1+j]); + } + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + } + return; + } + if( optype==1 ) + { + + /* + * A^(-T)*X + */ + for(i=m-1; i>=0; i--) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = ae_c_d_div((double)(1),a->ptr.pp_complex[i1+i][j1+i]); + } + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i-1; j>=0; j--) + { + vc = a->ptr.pp_complex[i1+i][j1+j]; + ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + } + return; + } + if( optype==2 ) + { + + /* + * A^(-H)*X + */ + for(i=m-1; i>=0; i--) + { + if( isunit ) + { + vd = ae_complex_from_i(1); + } + else + { + vd = ae_c_d_div((double)(1),ae_c_conj(a->ptr.pp_complex[i1+i][j1+i], _state)); + } + ae_v_cmulc(&x->ptr.pp_complex[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i-1; j>=0; j--) + { + vc = ae_c_conj(a->ptr.pp_complex[i1+i][j1+j], _state); + ae_v_csubc(&x->ptr.pp_complex[i2+j][j2], 1, &x->ptr.pp_complex[i2+i][j2], 1, "N", ae_v_len(j2,j2+n-1), vc); + } + } + return; + } + } +} + + +/************************************************************************* +Level 2 subroutine + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +static void ablas_rmatrixrighttrsm2(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double vr; + double vd; + + + + /* + * Special case + */ + if( n*m==0 ) + { + return; + } + + /* + * Try to use "fast" code + */ + if( rmatrixrighttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + + /* + * General case + */ + if( isupper ) + { + + /* + * Upper triangular matrix + */ + if( optype==0 ) + { + + /* + * X*A^(-1) + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = a->ptr.pp_double[i1+j][j1+j]; + } + x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; + if( jptr.pp_double[i2+i][j2+j]; + ae_v_subd(&x->ptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1), vr); + } + } + } + return; + } + if( optype==1 ) + { + + /* + * X*A^(-T) + */ + for(i=0; i<=m-1; i++) + { + for(j=n-1; j>=0; j--) + { + vr = (double)(0); + vd = (double)(1); + if( jptr.pp_double[i2+i][j2+j+1], 1, &a->ptr.pp_double[i1+j][j1+j+1], 1, ae_v_len(j2+j+1,j2+n-1)); + } + if( !isunit ) + { + vd = a->ptr.pp_double[i1+j][j1+j]; + } + x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; + } + } + return; + } + } + else + { + + /* + * Lower triangular matrix + */ + if( optype==0 ) + { + + /* + * X*A^(-1) + */ + for(i=0; i<=m-1; i++) + { + for(j=n-1; j>=0; j--) + { + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = a->ptr.pp_double[i1+j][j1+j]; + } + x->ptr.pp_double[i2+i][j2+j] = x->ptr.pp_double[i2+i][j2+j]/vd; + if( j>0 ) + { + vr = x->ptr.pp_double[i2+i][j2+j]; + ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1), vr); + } + } + } + return; + } + if( optype==1 ) + { + + /* + * X*A^(-T) + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + vr = (double)(0); + vd = (double)(1); + if( j>0 ) + { + vr = ae_v_dotproduct(&x->ptr.pp_double[i2+i][j2], 1, &a->ptr.pp_double[i1+j][j1], 1, ae_v_len(j2,j2+j-1)); + } + if( !isunit ) + { + vd = a->ptr.pp_double[i1+j][j1+j]; + } + x->ptr.pp_double[i2+i][j2+j] = (x->ptr.pp_double[i2+i][j2+j]-vr)/vd; + } + } + return; + } + } +} + + +/************************************************************************* +Level 2 subroutine +*************************************************************************/ +static void ablas_rmatrixlefttrsm2(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double vr; + double vd; + + + + /* + * Special case + */ + if( n==0||m==0 ) + { + return; + } + + /* + * Try fast code + */ + if( rmatrixlefttrsmf(m, n, a, i1, j1, isupper, isunit, optype, x, i2, j2, _state) ) + { + return; + } + + /* + * General case + */ + if( isupper ) + { + + /* + * Upper triangular matrix + */ + if( optype==0 ) + { + + /* + * A^(-1)*X + */ + for(i=m-1; i>=0; i--) + { + for(j=i+1; j<=m-1; j++) + { + vr = a->ptr.pp_double[i1+i][j1+j]; + ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); + } + if( !isunit ) + { + vd = (double)1/a->ptr.pp_double[i1+i][j1+i]; + ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + } + } + return; + } + if( optype==1 ) + { + + /* + * A^(-T)*X + */ + for(i=0; i<=m-1; i++) + { + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = (double)1/a->ptr.pp_double[i1+i][j1+i]; + } + ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i+1; j<=m-1; j++) + { + vr = a->ptr.pp_double[i1+i][j1+j]; + ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); + } + } + return; + } + } + else + { + + /* + * Lower triangular matrix + */ + if( optype==0 ) + { + + /* + * A^(-1)*X + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=i-1; j++) + { + vr = a->ptr.pp_double[i1+i][j1+j]; + ae_v_subd(&x->ptr.pp_double[i2+i][j2], 1, &x->ptr.pp_double[i2+j][j2], 1, ae_v_len(j2,j2+n-1), vr); + } + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = (double)1/a->ptr.pp_double[i1+j][j1+j]; + } + ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + } + return; + } + if( optype==1 ) + { + + /* + * A^(-T)*X + */ + for(i=m-1; i>=0; i--) + { + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = (double)1/a->ptr.pp_double[i1+i][j1+i]; + } + ae_v_muld(&x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vd); + for(j=i-1; j>=0; j--) + { + vr = a->ptr.pp_double[i1+i][j1+j]; + ae_v_subd(&x->ptr.pp_double[i2+j][j2], 1, &x->ptr.pp_double[i2+i][j2], 1, ae_v_len(j2,j2+n-1), vr); + } + } + return; + } + } +} + + +/************************************************************************* +Level 2 subroutine +*************************************************************************/ +static void ablas_cmatrixherk2(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + ae_complex v; + + + + /* + * Fast exit (nothing to be done) + */ + if( (ae_fp_eq(alpha,(double)(0))||k==0)&&ae_fp_eq(beta,(double)(1)) ) + { + return; + } + + /* + * Try to call fast SYRK + */ + if( cmatrixherkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) + { + return; + } + + /* + * SYRK + */ + if( optypea==0 ) + { + + /* + * C=alpha*A*A^H+beta*C + */ + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( ae_fp_neq(alpha,(double)(0))&&k>0 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[ia+i][ja], 1, "N", &a->ptr.pp_complex[ia+j][ja], 1, "Conj", ae_v_len(ja,ja+k-1)); + } + else + { + v = ae_complex_from_i(0); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_complex[ic+i][jc+j] = ae_c_mul_d(v,alpha); + } + else + { + c->ptr.pp_complex[ic+i][jc+j] = ae_c_add(ae_c_mul_d(c->ptr.pp_complex[ic+i][jc+j],beta),ae_c_mul_d(v,alpha)); + } + } + } + return; + } + else + { + + /* + * C=alpha*A^H*A+beta*C + */ + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + for(j=j1; j<=j2; j++) + { + c->ptr.pp_complex[ic+i][jc+j] = ae_complex_from_i(0); + } + } + else + { + ae_v_cmuld(&c->ptr.pp_complex[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); + } + } + if( ae_fp_neq(alpha,(double)(0))&&k>0 ) + { + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( isupper ) + { + j1 = j; + j2 = n-1; + } + else + { + j1 = 0; + j2 = j; + } + v = ae_c_mul_d(ae_c_conj(a->ptr.pp_complex[ia+i][ja+j], _state),alpha); + ae_v_caddc(&c->ptr.pp_complex[ic+j][jc+j1], 1, &a->ptr.pp_complex[ia+i][ja+j1], 1, "N", ae_v_len(jc+j1,jc+j2), v); + } + } + } + return; + } +} + + +/************************************************************************* +Level 2 subrotuine +*************************************************************************/ +static void ablas_rmatrixsyrk2(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + double v; + + + + /* + * Fast exit (nothing to be done) + */ + if( (ae_fp_eq(alpha,(double)(0))||k==0)&&ae_fp_eq(beta,(double)(1)) ) + { + return; + } + + /* + * Try to call fast SYRK + */ + if( rmatrixsyrkf(n, k, alpha, a, ia, ja, optypea, beta, c, ic, jc, isupper, _state) ) + { + return; + } + + /* + * SYRK + */ + if( optypea==0 ) + { + + /* + * C=alpha*A*A^H+beta*C + */ + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( ae_fp_neq(alpha,(double)(0))&&k>0 ) + { + v = ae_v_dotproduct(&a->ptr.pp_double[ia+i][ja], 1, &a->ptr.pp_double[ia+j][ja], 1, ae_v_len(ja,ja+k-1)); + } + else + { + v = (double)(0); + } + if( ae_fp_eq(beta,(double)(0)) ) + { + c->ptr.pp_double[ic+i][jc+j] = alpha*v; + } + else + { + c->ptr.pp_double[ic+i][jc+j] = beta*c->ptr.pp_double[ic+i][jc+j]+alpha*v; + } + } + } + return; + } + else + { + + /* + * C=alpha*A^H*A+beta*C + */ + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + if( ae_fp_eq(beta,(double)(0)) ) + { + for(j=j1; j<=j2; j++) + { + c->ptr.pp_double[ic+i][jc+j] = (double)(0); + } + } + else + { + ae_v_muld(&c->ptr.pp_double[ic+i][jc+j1], 1, ae_v_len(jc+j1,jc+j2), beta); + } + } + if( ae_fp_neq(alpha,(double)(0))&&k>0 ) + { + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( isupper ) + { + j1 = j; + j2 = n-1; + } + else + { + j1 = 0; + j2 = j; + } + v = alpha*a->ptr.pp_double[ia+i][ja+j]; + ae_v_addd(&c->ptr.pp_double[ic+j][jc+j1], 1, &a->ptr.pp_double[ia+i][ja+j1], 1, ae_v_len(jc+j1,jc+j2), v); + } + } + } + return; + } +} + + +/************************************************************************* +This subroutine is an actual implementation of CMatrixGEMM. It does not +perform some integrity checks performed in the driver function, and it +does not activate multithreading framework (driver decides whether to +activate workers or not). + + -- ALGLIB routine -- + 10.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void ablas_cmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + + /* + * Tile hierarchy: B -> A -> A/2 + */ + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax3(m, n, k, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "CMatrixGEMMRec: integrity check failed", _state); + + /* + * Use PBL or ALGLIB basecase code + */ + if( imax3(m, n, k, _state)<=tsb ) + { + if( cmatrixgemmpbl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) + { + return; + } + } + if( imax3(m, n, k, _state)<=tsa ) + { + cmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + return; + } + + /* + * Recursive algorithm: parallel splitting on M/N + */ + if( m>=n&&m>=k ) + { + + /* + * A*B = (A1 A2)^T*B + */ + tiledsplit(m, tscur, &s1, &s2, _state); + ablas_cmatrixgemmrec(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + if( optypea==0 ) + { + ablas_cmatrixgemmrec(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); + } + else + { + ablas_cmatrixgemmrec(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); + } + return; + } + if( n>=m&&n>=k ) + { + + /* + * A*B = A*(B1 B2) + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( optypeb==0 ) + { + ablas_cmatrixgemmrec(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); + } + else + { + ablas_cmatrixgemmrec(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); + } + return; + } + + /* + * Recursive algorithm: serial splitting on K + */ + + /* + * A*B = (A1 A2)*(B1 B2)^T + */ + tiledsplit(k, tscur, &s1, &s2, _state); + if( optypea==0&&optypeb==0 ) + { + ablas_cmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); + } + if( optypea==0&&optypeb!=0 ) + { + ablas_cmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); + } + if( optypea!=0&&optypeb==0 ) + { + ablas_cmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); + } + if( optypea!=0&&optypeb!=0 ) + { + ablas_cmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_cmatrixgemmrec(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, ae_complex_from_d(1.0), c, ic, jc, _state); + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_ablas_cmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +This subroutine is an actual implementation of RMatrixGEMM. It does not +perform some integrity checks performed in the driver function, and it +does not activate multithreading framework (driver decides whether to +activate workers or not). + + -- ALGLIB routine -- + 10.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void ablas_rmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + ae_int_t s1; + ae_int_t s2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( imax3(m, n, k, _state)<=tsb ) + { + tscur = tsa; + } + ae_assert(tscur>=1, "RMatrixGEMMRec: integrity check failed", _state); + + /* + * Use PBL or ALGLIB basecase code + */ + if( (m<=tsb&&n<=tsb)&&k<=tsb ) + { + if( rmatrixgemmpbl(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state) ) + { + return; + } + } + if( (m<=tsa&&n<=tsa)&&k<=tsa ) + { + rmatrixgemmk(m, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + return; + } + + /* + * Recursive algorithm: split on M or N + */ + if( m>=n&&m>=k ) + { + + /* + * A*B = (A1 A2)^T*B + */ + tiledsplit(m, tscur, &s1, &s2, _state); + if( optypea==0 ) + { + ablas_rmatrixgemmrec(s2, n, k, alpha, a, ia+s1, ja, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); + ablas_rmatrixgemmrec(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + } + else + { + ablas_rmatrixgemmrec(s2, n, k, alpha, a, ia, ja+s1, optypea, b, ib, jb, optypeb, beta, c, ic+s1, jc, _state); + ablas_rmatrixgemmrec(s1, n, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + } + return; + } + if( n>=m&&n>=k ) + { + + /* + * A*B = A*(B1 B2) + */ + tiledsplit(n, tscur, &s1, &s2, _state); + if( optypeb==0 ) + { + ablas_rmatrixgemmrec(m, s2, k, alpha, a, ia, ja, optypea, b, ib, jb+s1, optypeb, beta, c, ic, jc+s1, _state); + ablas_rmatrixgemmrec(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + } + else + { + ablas_rmatrixgemmrec(m, s2, k, alpha, a, ia, ja, optypea, b, ib+s1, jb, optypeb, beta, c, ic, jc+s1, _state); + ablas_rmatrixgemmrec(m, s1, k, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + } + return; + } + + /* + * Recursive algorithm: split on K + */ + + /* + * A*B = (A1 A2)*(B1 B2)^T + */ + tiledsplit(k, tscur, &s1, &s2, _state); + if( optypea==0&&optypeb==0 ) + { + ablas_rmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_rmatrixgemmrec(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); + } + if( optypea==0&&optypeb!=0 ) + { + ablas_rmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_rmatrixgemmrec(m, n, s2, alpha, a, ia, ja+s1, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); + } + if( optypea!=0&&optypeb==0 ) + { + ablas_rmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_rmatrixgemmrec(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib+s1, jb, optypeb, 1.0, c, ic, jc, _state); + } + if( optypea!=0&&optypeb!=0 ) + { + ablas_rmatrixgemmrec(m, n, s1, alpha, a, ia, ja, optypea, b, ib, jb, optypeb, beta, c, ic, jc, _state); + ablas_rmatrixgemmrec(m, n, s2, alpha, a, ia+s1, ja, optypea, b, ib, jb+s1, optypeb, 1.0, c, ic, jc, _state); + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_ablas_rmatrixgemmrec(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state) +{ + return ae_false; +} + + +#endif +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +QR decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form (see below). + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. + +The elements of matrix R are located on and above the main diagonal of +matrix A. The elements which are located in Tau array and below the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(k-1), + +where k = min(m,n), and each H(i) is in the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, +so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqr(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t rowscount; + ae_int_t i; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_vector_clear(tau); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); + + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + minmn = ae_minint(m, n, _state); + ts = matrixtilesizeb(_state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(tau, minmn, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, m, ts, _state); + ae_matrix_set_length(&tmpt, ts, 2*ts, _state); + ae_matrix_set_length(&tmpr, 2*ts, n, _state); + + /* + * Blocked code + */ + blockstart = 0; + while(blockstart!=minmn) + { + + /* + * Determine block size + */ + blocksize = minmn-blockstart; + if( blocksize>ts ) + { + blocksize = ts; + } + rowscount = m-blockstart; + + /* + * QR decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); + rmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); + rmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); + ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); + + /* + * Update the rest, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( blockstart+blocksize<=n-1 ) + { + if( n-blockstart-blocksize>=2*ts||rowscount>=4*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q'. + * + * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' + * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' + */ + rmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, 1.0, &tmpa, 0, 0, 1, a, blockstart, blockstart+blocksize, 0, 0.0, &tmpr, 0, 0, _state); + rmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, 1.0, &tmpt, 0, 0, 1, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); + rmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, a, blockstart, blockstart+blocksize, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=0; i<=blocksize-1; i++) + { + ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); + t.ptr.p_double[1] = (double)(1); + applyreflectionfromtheleft(a, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart+blocksize; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +LQ decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices L and Q in compact form (see below) + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0..Min(M,N)-1]. + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. + +The elements of matrix L are located on and below the main diagonal of +matrix A. The elements which are located in Tau array and above the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(k-1)*H(k-2)*...*H(1)*H(0), + +where k = min(m,n), and each H(i) is of the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, +v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlq(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t columnscount; + ae_int_t i; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_vector_clear(tau); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); + + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + minmn = ae_minint(m, n, _state); + ts = matrixtilesizeb(_state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(tau, minmn, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, ts, n, _state); + ae_matrix_set_length(&tmpt, ts, 2*ts, _state); + ae_matrix_set_length(&tmpr, m, 2*ts, _state); + + /* + * Blocked code + */ + blockstart = 0; + while(blockstart!=minmn) + { + + /* + * Determine block size + */ + blocksize = minmn-blockstart; + if( blocksize>ts ) + { + blocksize = ts; + } + columnscount = n-blockstart; + + /* + * LQ decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); + rmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); + rmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); + ae_v_move(&tau->ptr.p_double[blockstart], 1, &taubuf.ptr.p_double[0], 1, ae_v_len(blockstart,blockstart+blocksize-1)); + + /* + * Update the rest, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( blockstart+blocksize<=m-1 ) + { + if( m-blockstart-blocksize>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q. + * + * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA + */ + rmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, 1.0, a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); + rmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, 0.0, &tmpr, 0, blocksize, _state); + rmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, a, blockstart+blocksize, blockstart, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=0; i<=blocksize-1; i++) + { + ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); + t.ptr.p_double[1] = (double)(1); + applyreflectionfromtheright(a, taubuf.ptr.p_double[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart+blocksize; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +QR decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixqr(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* tau, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t rowscount; + ae_int_t i; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_vector_clear(tau); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); + + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + ts = matrixtilesizeb(_state)/2; + minmn = ae_minint(m, n, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(tau, minmn, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, m, ts, _state); + ae_matrix_set_length(&tmpt, ts, ts, _state); + ae_matrix_set_length(&tmpr, 2*ts, n, _state); + + /* + * Blocked code + */ + blockstart = 0; + while(blockstart!=minmn) + { + + /* + * Determine block size + */ + blocksize = minmn-blockstart; + if( blocksize>ts ) + { + blocksize = ts; + } + rowscount = m-blockstart; + + /* + * QR decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ortfac_cmatrixqrbasecase(&tmpa, rowscount, blocksize, &work, &t, &taubuf, _state); + cmatrixcopy(rowscount, blocksize, &tmpa, 0, 0, a, blockstart, blockstart, _state); + ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); + + /* + * Update the rest, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( blockstart+blocksize<=n-1 ) + { + if( n-blockstart-blocksize>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q'. + * + * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' + * Q' = E + Y*T'*Y' = E + TmpA*TmpT'*TmpA' + */ + cmatrixgemm(blocksize, n-blockstart-blocksize, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, a, blockstart, blockstart+blocksize, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); + cmatrixgemm(blocksize, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 2, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); + cmatrixgemm(rowscount, n-blockstart-blocksize, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), a, blockstart, blockstart+blocksize, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=0; i<=blocksize-1; i++) + { + ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); + t.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheleft(a, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, blockstart+i, m-1, blockstart+blocksize, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart+blocksize; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +LQ decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and L in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixlq(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* tau, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t columnscount; + ae_int_t i; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_vector_clear(tau); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); + + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + ts = matrixtilesizeb(_state)/2; + minmn = ae_minint(m, n, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(tau, minmn, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, ts, n, _state); + ae_matrix_set_length(&tmpt, ts, ts, _state); + ae_matrix_set_length(&tmpr, m, 2*ts, _state); + + /* + * Blocked code + */ + blockstart = 0; + while(blockstart!=minmn) + { + + /* + * Determine block size + */ + blocksize = minmn-blockstart; + if( blocksize>ts ) + { + blocksize = ts; + } + columnscount = n-blockstart; + + /* + * LQ decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ortfac_cmatrixlqbasecase(&tmpa, blocksize, columnscount, &work, &t, &taubuf, _state); + cmatrixcopy(blocksize, columnscount, &tmpa, 0, 0, a, blockstart, blockstart, _state); + ae_v_cmove(&tau->ptr.p_complex[blockstart], 1, &taubuf.ptr.p_complex[0], 1, "N", ae_v_len(blockstart,blockstart+blocksize-1)); + + /* + * Update the rest, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( blockstart+blocksize<=m-1 ) + { + if( m-blockstart-blocksize>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q. + * + * Q = E + Y*T*Y' = E + TmpA'*TmpT*TmpA + */ + cmatrixgemm(m-blockstart-blocksize, blocksize, columnscount, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); + cmatrixgemm(m-blockstart-blocksize, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); + cmatrixgemm(m-blockstart-blocksize, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), a, blockstart+blocksize, blockstart, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=0; i<=blocksize-1; i++) + { + ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); + t.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheright(a, taubuf.ptr.p_complex[i], &t, blockstart+blocksize, m-1, blockstart+i, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart+blocksize; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Partial unpacking of matrix Q from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixQR subroutine. + QColumns - required number of columns of matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose indexes range within [0..M-1, 0..QColumns-1]. + If QColumns=0, the array remains unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackq(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tau, + ae_int_t qcolumns, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_int_t refcnt; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t rowscount; + ae_int_t i; + ae_int_t j; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_matrix_clear(q); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); + if( (m<=0||n<=0)||qcolumns<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ts = matrixtilesizeb(_state); + minmn = ae_minint(m, n, _state); + refcnt = ae_minint(minmn, qcolumns, _state); + ae_matrix_set_length(q, m, qcolumns, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=qcolumns-1; j++) + { + if( i==j ) + { + q->ptr.pp_double[i][j] = (double)(1); + } + else + { + q->ptr.pp_double[i][j] = (double)(0); + } + } + } + ae_vector_set_length(&work, ae_maxint(m, qcolumns, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, qcolumns, _state)+1, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, m, ts, _state); + ae_matrix_set_length(&tmpt, ts, 2*ts, _state); + ae_matrix_set_length(&tmpr, 2*ts, qcolumns, _state); + + /* + * Blocked code + */ + blockstart = ts*(refcnt/ts); + blocksize = refcnt-blockstart; + while(blockstart>=0) + { + rowscount = m-blockstart; + if( blocksize>0 ) + { + + /* + * Copy current block + */ + rmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); + + /* + * Update, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( qcolumns>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply matrix by Q. + * + * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' + */ + rmatrixgemm(blocksize, qcolumns, rowscount, 1.0, &tmpa, 0, 0, 1, q, blockstart, 0, 0, 0.0, &tmpr, 0, 0, _state); + rmatrixgemm(blocksize, qcolumns, blocksize, 1.0, &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, 0.0, &tmpr, blocksize, 0, _state); + rmatrixgemm(rowscount, qcolumns, blocksize, 1.0, &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, 1.0, q, blockstart, 0, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=blocksize-1; i>=0; i--) + { + ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], tmpa.stride, ae_v_len(1,rowscount-i)); + t.ptr.p_double[1] = (double)(1); + applyreflectionfromtheleft(q, taubuf.ptr.p_double[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart-ts; + blocksize = ts; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackr(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* r, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + ae_matrix_clear(r); + + if( m<=0||n<=0 ) + { + return; + } + k = ae_minint(m, n, _state); + ae_matrix_set_length(r, m, n, _state); + for(i=0; i<=n-1; i++) + { + r->ptr.pp_double[0][i] = (double)(0); + } + for(i=1; i<=m-1; i++) + { + ae_v_move(&r->ptr.pp_double[i][0], 1, &r->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); + } + for(i=0; i<=k-1; i++) + { + ae_v_move(&r->ptr.pp_double[i][i], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); + } +} + + +/************************************************************************* +Partial unpacking of matrix Q from the LQ decomposition of a matrix A + +Input parameters: + A - matrices L and Q in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixLQ subroutine. + QRows - required number of rows in matrix Q. N>=QRows>=0. + +Output parameters: + Q - first QRows rows of matrix Q. Array whose indexes range + within [0..QRows-1, 0..N-1]. If QRows=0, the array remains + unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackq(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tau, + ae_int_t qrows, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_int_t refcnt; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t columnscount; + ae_int_t i; + ae_int_t j; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_matrix_clear(q); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(qrows<=n, "RMatrixLQUnpackQ: QRows>N!", _state); + if( (m<=0||n<=0)||qrows<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ts = matrixtilesizeb(_state); + minmn = ae_minint(m, n, _state); + refcnt = ae_minint(minmn, qrows, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, ts, n, _state); + ae_matrix_set_length(&tmpt, ts, 2*ts, _state); + ae_matrix_set_length(&tmpr, qrows, 2*ts, _state); + ae_matrix_set_length(q, qrows, n, _state); + for(i=0; i<=qrows-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + q->ptr.pp_double[i][j] = (double)(1); + } + else + { + q->ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * Blocked code + */ + blockstart = ts*(refcnt/ts); + blocksize = refcnt-blockstart; + while(blockstart>=0) + { + columnscount = n-blockstart; + if( blocksize>0 ) + { + + /* + * Copy submatrix + */ + rmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ae_v_move(&taubuf.ptr.p_double[0], 1, &tau->ptr.p_double[blockstart], 1, ae_v_len(0,blocksize-1)); + + /* + * Update matrix, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( qrows>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_rmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q'. + * + * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA + */ + rmatrixgemm(qrows, blocksize, columnscount, 1.0, q, 0, blockstart, 0, &tmpa, 0, 0, 1, 0.0, &tmpr, 0, 0, _state); + rmatrixgemm(qrows, blocksize, blocksize, 1.0, &tmpr, 0, 0, 0, &tmpt, 0, 0, 1, 0.0, &tmpr, 0, blocksize, _state); + rmatrixgemm(qrows, columnscount, blocksize, 1.0, &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, 1.0, q, 0, blockstart, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=blocksize-1; i>=0; i--) + { + ae_v_move(&t.ptr.p_double[1], 1, &tmpa.ptr.pp_double[i][i], 1, ae_v_len(1,columnscount-i)); + t.ptr.p_double[1] = (double)(1); + applyreflectionfromtheright(q, taubuf.ptr.p_double[i], &t, 0, qrows-1, blockstart+i, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart-ts; + blocksize = ts; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackl(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* l, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + ae_matrix_clear(l); + + if( m<=0||n<=0 ) + { + return; + } + ae_matrix_set_length(l, m, n, _state); + for(i=0; i<=n-1; i++) + { + l->ptr.pp_double[0][i] = (double)(0); + } + for(i=1; i<=m-1; i++) + { + ae_v_move(&l->ptr.pp_double[i][0], 1, &l->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); + } + for(i=0; i<=m-1; i++) + { + k = ae_minint(i, n-1, _state); + ae_v_move(&l->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k)); + } +} + + +/************************************************************************* +Partial unpacking of matrix Q from QR decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixQR subroutine . + QColumns - required number of columns in matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose index ranges within [0..M-1, 0..QColumns-1]. + If QColumns=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackq(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ const ae_vector* tau, + ae_int_t qcolumns, + /* Complex */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_int_t refcnt; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t rowscount; + ae_int_t i; + ae_int_t j; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_matrix_clear(q); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(qcolumns<=m, "UnpackQFromQR: QColumns>M!", _state); + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ts = matrixtilesizeb(_state)/2; + minmn = ae_minint(m, n, _state); + refcnt = ae_minint(minmn, qcolumns, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, m, ts, _state); + ae_matrix_set_length(&tmpt, ts, ts, _state); + ae_matrix_set_length(&tmpr, 2*ts, qcolumns, _state); + ae_matrix_set_length(q, m, qcolumns, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=qcolumns-1; j++) + { + if( i==j ) + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(1); + } + else + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + + /* + * Blocked code + */ + blockstart = ts*(refcnt/ts); + blocksize = refcnt-blockstart; + while(blockstart>=0) + { + rowscount = m-blockstart; + if( blocksize>0 ) + { + + /* + * QR decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + cmatrixcopy(rowscount, blocksize, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); + + /* + * Update matrix, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( qcolumns>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_true, rowscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q. + * + * Q = E + Y*T*Y' = E + TmpA*TmpT*TmpA' + */ + cmatrixgemm(blocksize, qcolumns, rowscount, ae_complex_from_d(1.0), &tmpa, 0, 0, 2, q, blockstart, 0, 0, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); + cmatrixgemm(blocksize, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpt, 0, 0, 0, &tmpr, 0, 0, 0, ae_complex_from_d(0.0), &tmpr, blocksize, 0, _state); + cmatrixgemm(rowscount, qcolumns, blocksize, ae_complex_from_d(1.0), &tmpa, 0, 0, 0, &tmpr, blocksize, 0, 0, ae_complex_from_d(1.0), q, blockstart, 0, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=blocksize-1; i>=0; i--) + { + ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], tmpa.stride, "N", ae_v_len(1,rowscount-i)); + t.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheleft(q, taubuf.ptr.p_complex[i], &t, blockstart+i, m-1, 0, qcolumns-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart-ts; + blocksize = ts; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackr(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* r, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + ae_matrix_clear(r); + + if( m<=0||n<=0 ) + { + return; + } + k = ae_minint(m, n, _state); + ae_matrix_set_length(r, m, n, _state); + for(i=0; i<=n-1; i++) + { + r->ptr.pp_complex[0][i] = ae_complex_from_i(0); + } + for(i=1; i<=m-1; i++) + { + ae_v_cmove(&r->ptr.pp_complex[i][0], 1, &r->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); + } + for(i=0; i<=k-1; i++) + { + ae_v_cmove(&r->ptr.pp_complex[i][i], 1, &a->ptr.pp_complex[i][i], 1, "N", ae_v_len(i,n-1)); + } +} + + +/************************************************************************* +Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixLQ subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixLQ subroutine . + QRows - required number of rows in matrix Q. N>=QColumns>=0. + +Output parameters: + Q - first QRows rows of matrix Q. + Array whose index ranges within [0..QRows-1, 0..N-1]. + If QRows=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackq(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ const ae_vector* tau, + ae_int_t qrows, + /* Complex */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_vector taubuf; + ae_int_t minmn; + ae_int_t refcnt; + ae_matrix tmpa; + ae_matrix tmpt; + ae_matrix tmpr; + ae_int_t blockstart; + ae_int_t blocksize; + ae_int_t columnscount; + ae_int_t i; + ae_int_t j; + ae_int_t ts; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + memset(&taubuf, 0, sizeof(taubuf)); + memset(&tmpa, 0, sizeof(tmpa)); + memset(&tmpt, 0, sizeof(tmpt)); + memset(&tmpr, 0, sizeof(tmpr)); + ae_matrix_clear(q); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&taubuf, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpa, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpt, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&tmpr, 0, 0, DT_COMPLEX, _state, ae_true); + + if( m<=0||n<=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Init + */ + ts = matrixtilesizeb(_state)/2; + minmn = ae_minint(m, n, _state); + refcnt = ae_minint(minmn, qrows, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&t, ae_maxint(m, n, _state)+1, _state); + ae_vector_set_length(&taubuf, minmn, _state); + ae_matrix_set_length(&tmpa, ts, n, _state); + ae_matrix_set_length(&tmpt, ts, ts, _state); + ae_matrix_set_length(&tmpr, qrows, 2*ts, _state); + ae_matrix_set_length(q, qrows, n, _state); + for(i=0; i<=qrows-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(1); + } + else + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + + /* + * Blocked code + */ + blockstart = ts*(refcnt/ts); + blocksize = refcnt-blockstart; + while(blockstart>=0) + { + columnscount = n-blockstart; + if( blocksize>0 ) + { + + /* + * LQ decomposition of submatrix. + * Matrix is copied to temporary storage to solve + * some TLB issues arising from non-contiguous memory + * access pattern. + */ + cmatrixcopy(blocksize, columnscount, a, blockstart, blockstart, &tmpa, 0, 0, _state); + ae_v_cmove(&taubuf.ptr.p_complex[0], 1, &tau->ptr.p_complex[blockstart], 1, "N", ae_v_len(0,blocksize-1)); + + /* + * Update matrix, choose between: + * a) Level 2 algorithm (when the rest of the matrix is small enough) + * b) blocked algorithm, see algorithm 5 from 'A storage efficient WY + * representation for products of Householder transformations', + * by R. Schreiber and C. Van Loan. + */ + if( qrows>=2*ts ) + { + + /* + * Prepare block reflector + */ + ortfac_cmatrixblockreflector(&tmpa, &taubuf, ae_false, columnscount, blocksize, &tmpt, &work, _state); + + /* + * Multiply the rest of A by Q'. + * + * Q' = E + Y*T'*Y' = E + TmpA'*TmpT'*TmpA + */ + cmatrixgemm(qrows, blocksize, columnscount, ae_complex_from_d(1.0), q, 0, blockstart, 0, &tmpa, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, 0, _state); + cmatrixgemm(qrows, blocksize, blocksize, ae_complex_from_d(1.0), &tmpr, 0, 0, 0, &tmpt, 0, 0, 2, ae_complex_from_d(0.0), &tmpr, 0, blocksize, _state); + cmatrixgemm(qrows, columnscount, blocksize, ae_complex_from_d(1.0), &tmpr, 0, blocksize, 0, &tmpa, 0, 0, 0, ae_complex_from_d(1.0), q, 0, blockstart, _state); + } + else + { + + /* + * Level 2 algorithm + */ + for(i=blocksize-1; i>=0; i--) + { + ae_v_cmove(&t.ptr.p_complex[1], 1, &tmpa.ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,columnscount-i)); + t.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheright(q, ae_c_conj(taubuf.ptr.p_complex[i], _state), &t, 0, qrows-1, blockstart+i, n-1, &work, _state); + } + } + } + + /* + * Advance + */ + blockstart = blockstart-ts; + blocksize = ts; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of CMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackl(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* l, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + ae_matrix_clear(l); + + if( m<=0||n<=0 ) + { + return; + } + ae_matrix_set_length(l, m, n, _state); + for(i=0; i<=n-1; i++) + { + l->ptr.pp_complex[0][i] = ae_complex_from_i(0); + } + for(i=1; i<=m-1; i++) + { + ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &l->ptr.pp_complex[0][0], 1, "N", ae_v_len(0,n-1)); + } + for(i=0; i<=m-1; i++) + { + k = ae_minint(i, n-1, _state); + ae_v_cmove(&l->ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,k)); + } +} + + +/************************************************************************* +Base case for real QR + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +void rmatrixqrbasecase(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* work, + /* Real */ ae_vector* t, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t minmn; + double tmp; + + + minmn = ae_minint(m, n, _state); + + /* + * Test the input arguments + */ + k = minmn; + for(i=0; i<=k-1; i++) + { + + /* + * Generate elementary reflector H(i) to annihilate A(i+1:m,i) + */ + ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); + generatereflection(t, m-i, &tmp, _state); + tau->ptr.p_double[i] = tmp; + ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t->ptr.p_double[1], 1, ae_v_len(i,m-1)); + t->ptr.p_double[1] = (double)(1); + if( iptr.p_double[i], t, i, m-1, i+1, n-1, work, _state); + } + } +} + + +/************************************************************************* +Base case for real LQ + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +void rmatrixlqbasecase(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* work, + /* Real */ ae_vector* t, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double tmp; + + + k = ae_minint(m, n, _state); + for(i=0; i<=k-1; i++) + { + + /* + * Generate elementary reflector H(i) to annihilate A(i,i+1:n-1) + */ + ae_v_move(&t->ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); + generatereflection(t, n-i, &tmp, _state); + tau->ptr.p_double[i] = tmp; + ae_v_move(&a->ptr.pp_double[i][i], 1, &t->ptr.p_double[1], 1, ae_v_len(i,n-1)); + t->ptr.p_double[1] = (double)(1); + if( iptr.p_double[i], t, i+1, m-1, i, n-1, work, _state); + } + } +} + + +/************************************************************************* +Reduction of a rectangular matrix to bidiagonal form + +The algorithm reduces the rectangular matrix A to bidiagonal form by +orthogonal transformations P and Q: A = Q*B*(P^T). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - source matrix. array[0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q, B, P in compact form (see below). + TauQ - scalar factors which are used to form matrix Q. + TauP - scalar factors which are used to form matrix P. + +The main diagonal and one of the secondary diagonals of matrix A are +replaced with bidiagonal matrix B. Other elements contain elementary +reflections which form MxM matrix Q and NxN matrix P, respectively. + +If M>=N, B is the upper bidiagonal MxN matrix and is stored in the +corresponding elements of matrix A. Matrix Q is represented as a +product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where +H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and +vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is +stored in elements A(i+1:m-1,i). Matrix P is as follows: P = +G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], +u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). + +If M n): m=5, n=6 (m < n): + +( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) +( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) +( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) +( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) +( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) +( v1 v2 v3 v4 v5 ) + +Here vi and ui are vectors which form H(i) and G(i), and d and e - +are the diagonal and off-diagonal elements of matrix B. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +void rmatrixbd(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tauq, + /* Real */ ae_vector* taup, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_vector t; + ae_int_t maxmn; + ae_int_t i; + double ltau; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&t, 0, sizeof(t)); + ae_vector_clear(tauq); + ae_vector_clear(taup); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + + /* + * Prepare + */ + if( n<=0||m<=0 ) + { + ae_frame_leave(_state); + return; + } + maxmn = ae_maxint(m, n, _state); + ae_vector_set_length(&work, maxmn+1, _state); + ae_vector_set_length(&t, maxmn+1, _state); + if( m>=n ) + { + ae_vector_set_length(tauq, n, _state); + ae_vector_set_length(taup, n, _state); + for(i=0; i<=n-1; i++) + { + tauq->ptr.p_double[i] = 0.0; + taup->ptr.p_double[i] = 0.0; + } + } + else + { + ae_vector_set_length(tauq, m, _state); + ae_vector_set_length(taup, m, _state); + for(i=0; i<=m-1; i++) + { + tauq->ptr.p_double[i] = 0.0; + taup->ptr.p_double[i] = 0.0; + } + } + + /* + * Try to use PBL code + * + * NOTE: buffers Work[] and T[] are used for temporary storage of diagonals; + * because they are present in A[], we do not use them. + */ + if( rmatrixbdpbl(a, m, n, &work, &t, tauq, taup, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB code + */ + if( m>=n ) + { + + /* + * Reduce to upper bidiagonal form + */ + for(i=0; i<=n-1; i++) + { + + /* + * Generate elementary reflector H(i) to annihilate A(i+1:m-1,i) + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], a->stride, ae_v_len(1,m-i)); + generatereflection(&t, m-i, <au, _state); + tauq->ptr.p_double[i] = ltau; + ae_v_move(&a->ptr.pp_double[i][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i,m-1)); + t.ptr.p_double[1] = (double)(1); + + /* + * Apply H(i) to A(i:m-1,i+1:n-1) from the left + */ + applyreflectionfromtheleft(a, ltau, &t, i, m-1, i+1, n-1, &work, _state); + if( iptr.pp_double[i][i+1], 1, ae_v_len(1,n-i-1)); + generatereflection(&t, n-1-i, <au, _state); + taup->ptr.p_double[i] = ltau; + ae_v_move(&a->ptr.pp_double[i][i+1], 1, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); + t.ptr.p_double[1] = (double)(1); + + /* + * Apply G(i) to A(i+1:m-1,i+1:n-1) from the right + */ + applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); + } + else + { + taup->ptr.p_double[i] = (double)(0); + } + } + } + else + { + + /* + * Reduce to lower bidiagonal form + */ + for(i=0; i<=m-1; i++) + { + + /* + * Generate elementary reflector G(i) to annihilate A(i,i+1:n-1) + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); + generatereflection(&t, n-i, <au, _state); + taup->ptr.p_double[i] = ltau; + ae_v_move(&a->ptr.pp_double[i][i], 1, &t.ptr.p_double[1], 1, ae_v_len(i,n-1)); + t.ptr.p_double[1] = (double)(1); + + /* + * Apply G(i) to A(i+1:m-1,i:n-1) from the right + */ + applyreflectionfromtheright(a, ltau, &t, i+1, m-1, i, n-1, &work, _state); + if( iptr.pp_double[i+1][i], a->stride, ae_v_len(1,m-1-i)); + generatereflection(&t, m-1-i, <au, _state); + tauq->ptr.p_double[i] = ltau; + ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,m-1)); + t.ptr.p_double[1] = (double)(1); + + /* + * Apply H(i) to A(i+1:m-1,i+1:n-1) from the left + */ + applyreflectionfromtheleft(a, ltau, &t, i+1, m-1, i+1, n-1, &work, _state); + } + else + { + tauq->ptr.p_double[i] = (double)(0); + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix Q which reduces a matrix to bidiagonal form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + QColumns - required number of columns in matrix Q. + M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array[0..M-1, 0..QColumns-1] + If QColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackq(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + ae_int_t qcolumns, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(q); + + ae_assert(qcolumns<=m, "RMatrixBDUnpackQ: QColumns>M!", _state); + ae_assert(qcolumns>=0, "RMatrixBDUnpackQ: QColumns<0!", _state); + if( (m==0||n==0)||qcolumns==0 ) + { + return; + } + + /* + * prepare Q + */ + ae_matrix_set_length(q, m, qcolumns, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=qcolumns-1; j++) + { + if( i==j ) + { + q->ptr.pp_double[i][j] = (double)(1); + } + else + { + q->ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * Calculate + */ + rmatrixbdmultiplybyq(qp, m, n, tauq, q, m, qcolumns, ae_false, ae_false, _state); +} + + +/************************************************************************* +Multiplication by matrix Q which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by Q or Q'. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + Z - multiplied matrix. + array[0..ZRows-1,0..ZColumns-1] + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=M, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=M, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by Q or Q'. + +Output parameters: + Z - product of Z and Q. + Array[0..ZRows-1,0..ZColumns-1] + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyq(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t i1; + ae_int_t i2; + ae_int_t istep; + ae_vector v; + ae_vector work; + ae_vector dummy; + ae_int_t mx; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummy, 0, DT_REAL, _state, ae_true); + + if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) + { + ae_frame_leave(_state); + return; + } + ae_assert((fromtheright&&zcolumns==m)||(!fromtheright&&zrows==m), "RMatrixBDMultiplyByQ: incorrect Z size!", _state); + + /* + * Try to use PBL code + */ + if( rmatrixbdmultiplybypbl(qp, m, n, tauq, &dummy, z, zrows, zcolumns, ae_true, fromtheright, dotranspose, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + mx = ae_maxint(m, n, _state); + mx = ae_maxint(mx, zrows, _state); + mx = ae_maxint(mx, zcolumns, _state); + ae_vector_set_length(&v, mx+1, _state); + ae_vector_set_length(&work, mx+1, _state); + if( m>=n ) + { + + /* + * setup + */ + if( fromtheright ) + { + i1 = 0; + i2 = n-1; + istep = 1; + } + else + { + i1 = n-1; + i2 = 0; + istep = -1; + } + if( dotranspose ) + { + i = i1; + i1 = i2; + i2 = i; + istep = -istep; + } + + /* + * Process + */ + i = i1; + do + { + ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], qp->stride, ae_v_len(1,m-i)); + v.ptr.p_double[1] = (double)(1); + if( fromtheright ) + { + applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i, m-1, &work, _state); + } + else + { + applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i, m-1, 0, zcolumns-1, &work, _state); + } + i = i+istep; + } + while(i!=i2+istep); + } + else + { + + /* + * setup + */ + if( fromtheright ) + { + i1 = 0; + i2 = m-2; + istep = 1; + } + else + { + i1 = m-2; + i2 = 0; + istep = -1; + } + if( dotranspose ) + { + i = i1; + i1 = i2; + i2 = i; + istep = -istep; + } + + /* + * Process + */ + if( m-1>0 ) + { + i = i1; + do + { + ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i+1][i], qp->stride, ae_v_len(1,m-i-1)); + v.ptr.p_double[1] = (double)(1); + if( fromtheright ) + { + applyreflectionfromtheright(z, tauq->ptr.p_double[i], &v, 0, zrows-1, i+1, m-1, &work, _state); + } + else + { + applyreflectionfromtheleft(z, tauq->ptr.p_double[i], &v, i+1, m-1, 0, zcolumns-1, &work, _state); + } + i = i+istep; + } + while(i!=i2+istep); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix P which reduces matrix A to bidiagonal form. +The subroutine returns transposed matrix P. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of ToBidiagonal subroutine. + PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. + +Output parameters: + PT - first PTRows columns of matrix P^T + Array[0..PTRows-1, 0..N-1] + If PTRows=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackpt(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* taup, + ae_int_t ptrows, + /* Real */ ae_matrix* pt, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(pt); + + ae_assert(ptrows<=n, "RMatrixBDUnpackPT: PTRows>N!", _state); + ae_assert(ptrows>=0, "RMatrixBDUnpackPT: PTRows<0!", _state); + if( (m==0||n==0)||ptrows==0 ) + { + return; + } + + /* + * prepare PT + */ + ae_matrix_set_length(pt, ptrows, n, _state); + for(i=0; i<=ptrows-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + pt->ptr.pp_double[i][j] = (double)(1); + } + else + { + pt->ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * Calculate + */ + rmatrixbdmultiplybyp(qp, m, n, taup, pt, ptrows, n, ae_true, ae_true, _state); +} + + +/************************************************************************* +Multiplication by matrix P which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by P or P'. + +Input parameters: + QP - matrices Q and P in compact form. + Output of RMatrixBD subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of RMatrixBD subroutine. + Z - multiplied matrix. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=N, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=N, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by P or P'. + +Output parameters: + Z - product of Z and P. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyp(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* taup, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_vector v; + ae_vector work; + ae_vector dummy; + ae_int_t mx; + ae_int_t i1; + ae_int_t i2; + ae_int_t istep; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummy, 0, DT_REAL, _state, ae_true); + + if( ((m<=0||n<=0)||zrows<=0)||zcolumns<=0 ) + { + ae_frame_leave(_state); + return; + } + ae_assert((fromtheright&&zcolumns==n)||(!fromtheright&&zrows==n), "RMatrixBDMultiplyByP: incorrect Z size!", _state); + + /* + * init + */ + mx = ae_maxint(m, n, _state); + mx = ae_maxint(mx, zrows, _state); + mx = ae_maxint(mx, zcolumns, _state); + ae_vector_set_length(&v, mx+1, _state); + ae_vector_set_length(&work, mx+1, _state); + if( m>=n ) + { + + /* + * setup + */ + if( fromtheright ) + { + i1 = n-2; + i2 = 0; + istep = -1; + } + else + { + i1 = 0; + i2 = n-2; + istep = 1; + } + if( !dotranspose ) + { + i = i1; + i1 = i2; + i2 = i; + istep = -istep; + } + + /* + * Process + */ + if( n-1>0 ) + { + i = i1; + do + { + ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i+1], 1, ae_v_len(1,n-1-i)); + v.ptr.p_double[1] = (double)(1); + if( fromtheright ) + { + applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i+1, n-1, &work, _state); + } + else + { + applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i+1, n-1, 0, zcolumns-1, &work, _state); + } + i = i+istep; + } + while(i!=i2+istep); + } + } + else + { + + /* + * setup + */ + if( fromtheright ) + { + i1 = m-1; + i2 = 0; + istep = -1; + } + else + { + i1 = 0; + i2 = m-1; + istep = 1; + } + if( !dotranspose ) + { + i = i1; + i1 = i2; + i2 = i; + istep = -istep; + } + + /* + * Process + */ + i = i1; + do + { + ae_v_move(&v.ptr.p_double[1], 1, &qp->ptr.pp_double[i][i], 1, ae_v_len(1,n-i)); + v.ptr.p_double[1] = (double)(1); + if( fromtheright ) + { + applyreflectionfromtheright(z, taup->ptr.p_double[i], &v, 0, zrows-1, i, n-1, &work, _state); + } + else + { + applyreflectionfromtheleft(z, taup->ptr.p_double[i], &v, i, n-1, 0, zcolumns-1, &work, _state); + } + i = i+istep; + } + while(i!=i2+istep); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking of the main and secondary diagonals of bidiagonal decomposition +of matrix A. + +Input parameters: + B - output of RMatrixBD subroutine. + M - number of rows in matrix B. + N - number of columns in matrix B. + +Output parameters: + IsUpper - True, if the matrix is upper bidiagonal. + otherwise IsUpper is False. + D - the main diagonal. + Array whose index ranges within [0..Min(M,N)-1]. + E - the secondary diagonal (upper or lower, depending on + the value of IsUpper). + Array index ranges within [0..Min(M,N)-1], the last + element is not used. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackdiagonals(/* Real */ const ae_matrix* b, + ae_int_t m, + ae_int_t n, + ae_bool* isupper, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state) +{ + ae_int_t i; + + *isupper = ae_false; + ae_vector_clear(d); + ae_vector_clear(e); + + *isupper = m>=n; + if( m<=0||n<=0 ) + { + return; + } + if( *isupper ) + { + ae_vector_set_length(d, n, _state); + ae_vector_set_length(e, n, _state); + for(i=0; i<=n-2; i++) + { + d->ptr.p_double[i] = b->ptr.pp_double[i][i]; + e->ptr.p_double[i] = b->ptr.pp_double[i][i+1]; + } + d->ptr.p_double[n-1] = b->ptr.pp_double[n-1][n-1]; + } + else + { + ae_vector_set_length(d, m, _state); + ae_vector_set_length(e, m, _state); + for(i=0; i<=m-2; i++) + { + d->ptr.p_double[i] = b->ptr.pp_double[i][i]; + e->ptr.p_double[i] = b->ptr.pp_double[i+1][i]; + } + d->ptr.p_double[m-1] = b->ptr.pp_double[m-1][m-1]; + } +} + + +/************************************************************************* +Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, +where Q is an orthogonal matrix, H - Hessenberg matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix A with elements [0..N-1, 0..N-1] + N - size of matrix A. + +Output parameters: + A - matrices Q and P in compact form (see below). + Tau - array of scalar factors which are used to form matrix Q. + Array whose index ranges within [0..N-2] + +Matrix H is located on the main diagonal, on the lower secondary diagonal +and above the main diagonal of matrix A. The elements which are used to +form matrix Q are situated in array Tau and below the lower secondary +diagonal of matrix A as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(n-2), + +where each H(i) is given by + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - is a real vector, +so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void rmatrixhessenberg(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + double v; + ae_vector t; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + memset(&work, 0, sizeof(work)); + ae_vector_clear(tau); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "RMatrixHessenberg: incorrect N!", _state); + + /* + * Quick return if possible + */ + if( n<=1 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Allocate place + */ + ae_vector_set_length(tau, n-2+1, _state); + ae_vector_set_length(&t, n+1, _state); + ae_vector_set_length(&work, n-1+1, _state); + + /* + * PBL version + */ + if( rmatrixhessenbergpbl(a, n, tau, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + for(i=0; i<=n-2; i++) + { + + /* + * Compute elementary reflector H(i) to annihilate A(i+2:ihi,i) + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + generatereflection(&t, n-i-1, &v, _state); + ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); + tau->ptr.p_double[i] = v; + t.ptr.p_double[1] = (double)(1); + + /* + * Apply H(i) to A(1:ihi,i+1:ihi) from the right + */ + applyreflectionfromtheright(a, v, &t, 0, n-1, i+1, n-1, &work, _state); + + /* + * Apply H(i) to A(i+1:ihi,i+1:n) from the left + */ + applyreflectionfromtheleft(a, v, &t, i+1, n-1, i+1, n-1, &work, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix Q which reduces matrix A to upper Hessenberg form + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + Tau - scalar factors which are used to form Q. + Output of RMatrixHessenberg subroutine. + +Output parameters: + Q - matrix Q. + Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackq(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector v; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + ae_matrix_clear(q); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ae_matrix_set_length(q, n-1+1, n-1+1, _state); + ae_vector_set_length(&v, n-1+1, _state); + ae_vector_set_length(&work, n-1+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + q->ptr.pp_double[i][j] = (double)(1); + } + else + { + q->ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * PBL version + */ + if( rmatrixhessenbergunpackqpbl(a, n, tau, q, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version: unpack Q + */ + for(i=0; i<=n-2; i++) + { + + /* + * Apply H(i) + */ + ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + v.ptr.p_double[1] = (double)(1); + applyreflectionfromtheright(q, tau->ptr.p_double[i], &v, 0, n-1, i+1, n-1, &work, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + +Output parameters: + H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackh(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector v; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + ae_matrix_clear(h); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(h, n-1+1, n-1+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-2; j++) + { + h->ptr.pp_double[i][j] = (double)(0); + } + j = ae_maxint(0, i-1, _state); + ae_v_move(&h->ptr.pp_double[i][j], 1, &a->ptr.pp_double[i][j], 1, ae_v_len(j,n-1)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Reduction of a symmetric matrix which is given by its higher or lower +triangular part to a tridiagonal matrix using orthogonal similarity +transformation: Q'*A*Q=T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void smatrixtd(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + double alpha; + double taui; + double v; + ae_vector t; + ae_vector t2; + ae_vector t3; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + memset(&t2, 0, sizeof(t2)); + memset(&t3, 0, sizeof(t3)); + ae_vector_clear(tau); + ae_vector_clear(d); + ae_vector_clear(e); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t3, 0, DT_REAL, _state, ae_true); + + if( n<=0 ) + { + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&t, n+1, _state); + ae_vector_set_length(&t2, n+1, _state); + ae_vector_set_length(&t3, n+1, _state); + if( n>1 ) + { + ae_vector_set_length(tau, n-2+1, _state); + } + ae_vector_set_length(d, n-1+1, _state); + if( n>1 ) + { + ae_vector_set_length(e, n-2+1, _state); + } + + /* + * Try to use PBL + */ + if( smatrixtdpbl(a, n, isupper, tau, d, e, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + if( isupper ) + { + + /* + * Reduce the upper triangle of A + */ + for(i=n-2; i>=0; i--) + { + + /* + * Generate elementary reflector H() = E - tau * v * v' + */ + if( i>=1 ) + { + ae_v_move(&t.ptr.p_double[2], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(2,i+1)); + } + t.ptr.p_double[1] = a->ptr.pp_double[i][i+1]; + generatereflection(&t, i+1, &taui, _state); + if( i>=1 ) + { + ae_v_move(&a->ptr.pp_double[0][i+1], a->stride, &t.ptr.p_double[2], 1, ae_v_len(0,i-1)); + } + a->ptr.pp_double[i][i+1] = t.ptr.p_double[1]; + e->ptr.p_double[i] = a->ptr.pp_double[i][i+1]; + if( ae_fp_neq(taui,(double)(0)) ) + { + + /* + * Apply H from both sides to A + */ + a->ptr.pp_double[i][i+1] = (double)(1); + + /* + * Compute x := tau * A * v storing x in TAU + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); + symmetricmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t3, _state); + ae_v_move(&tau->ptr.p_double[0], 1, &t3.ptr.p_double[1], 1, ae_v_len(0,i)); + + /* + * Compute w := x - 1/2 * tau * (x'*v) * v + */ + v = ae_v_dotproduct(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i)); + alpha = -0.5*taui*v; + ae_v_addd(&tau->ptr.p_double[0], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(0,i), alpha); + + /* + * Apply the transformation as a rank-2 update: + * A := A - v * w' - w * v' + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); + ae_v_move(&t3.ptr.p_double[1], 1, &tau->ptr.p_double[0], 1, ae_v_len(1,i+1)); + symmetricrank2update(a, isupper, 0, i, &t, &t3, &t2, (double)(-1), _state); + a->ptr.pp_double[i][i+1] = e->ptr.p_double[i]; + } + d->ptr.p_double[i+1] = a->ptr.pp_double[i+1][i+1]; + tau->ptr.p_double[i] = taui; + } + d->ptr.p_double[0] = a->ptr.pp_double[0][0]; + } + else + { + + /* + * Reduce the lower triangle of A + */ + for(i=0; i<=n-2; i++) + { + + /* + * Generate elementary reflector H = E - tau * v * v' + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + generatereflection(&t, n-i-1, &taui, _state); + ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &t.ptr.p_double[1], 1, ae_v_len(i+1,n-1)); + e->ptr.p_double[i] = a->ptr.pp_double[i+1][i]; + if( ae_fp_neq(taui,(double)(0)) ) + { + + /* + * Apply H from both sides to A + */ + a->ptr.pp_double[i+1][i] = (double)(1); + + /* + * Compute x := tau * A * v storing y in TAU + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + symmetricmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); + ae_v_move(&tau->ptr.p_double[i], 1, &t2.ptr.p_double[1], 1, ae_v_len(i,n-2)); + + /* + * Compute w := x - 1/2 * tau * (x'*v) * v + */ + v = ae_v_dotproduct(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2)); + alpha = -0.5*taui*v; + ae_v_addd(&tau->ptr.p_double[i], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(i,n-2), alpha); + + /* + * Apply the transformation as a rank-2 update: + * A := A - v * w' - w * v' + * + */ + ae_v_move(&t.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + ae_v_move(&t2.ptr.p_double[1], 1, &tau->ptr.p_double[i], 1, ae_v_len(1,n-i-1)); + symmetricrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, (double)(-1), _state); + a->ptr.pp_double[i+1][i] = e->ptr.p_double[i]; + } + d->ptr.p_double[i] = a->ptr.pp_double[i][i]; + tau->ptr.p_double[i] = taui; + } + d->ptr.p_double[n-1] = a->ptr.pp_double[n-1][n-1]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix Q which reduces symmetric matrix to a tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a SMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of SMatrixTD subroutine) + Tau - the result of a SMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void smatrixtdunpackq(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector v; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + ae_matrix_clear(q); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ae_matrix_set_length(q, n-1+1, n-1+1, _state); + ae_vector_set_length(&v, n+1, _state); + ae_vector_set_length(&work, n-1+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + q->ptr.pp_double[i][j] = (double)(1); + } + else + { + q->ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * PBL version + */ + if( smatrixtdunpackqpbl(a, n, isupper, tau, q, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version: unpack Q + */ + if( isupper ) + { + for(i=0; i<=n-2; i++) + { + + /* + * Apply H(i) + */ + ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[0][i+1], a->stride, ae_v_len(1,i+1)); + v.ptr.p_double[i+1] = (double)(1); + applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, 0, i, 0, n-1, &work, _state); + } + } + else + { + for(i=n-2; i>=0; i--) + { + + /* + * Apply H(i) + */ + ae_v_move(&v.ptr.p_double[1], 1, &a->ptr.pp_double[i+1][i], a->stride, ae_v_len(1,n-i-1)); + v.ptr.p_double[1] = (double)(1); + applyreflectionfromtheleft(q, tau->ptr.p_double[i], &v, i+1, n-1, 0, n-1, &work, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Reduction of a Hermitian matrix which is given by its higher or lower +triangular part to a real tridiagonal matrix using unitary similarity +transformation: Q'*A*Q = T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of real symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of real symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + +where d and e denote diagonal and off-diagonal elements of T, and vi +denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void hmatrixtd(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_complex alpha; + ae_complex taui; + ae_complex v; + ae_vector t; + ae_vector t2; + ae_vector t3; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + memset(&t2, 0, sizeof(t2)); + memset(&t3, 0, sizeof(t3)); + ae_vector_clear(tau); + ae_vector_clear(d); + ae_vector_clear(e); + ae_vector_init(&t, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t2, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&t3, 0, DT_COMPLEX, _state, ae_true); + + + /* + * Init and test + */ + if( n<=0 ) + { + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_eq(a->ptr.pp_complex[i][i].y,(double)(0)), "Assertion failed", _state); + } + if( n>1 ) + { + ae_vector_set_length(tau, n-2+1, _state); + ae_vector_set_length(e, n-2+1, _state); + } + ae_vector_set_length(d, n-1+1, _state); + ae_vector_set_length(&t, n-1+1, _state); + ae_vector_set_length(&t2, n-1+1, _state); + ae_vector_set_length(&t3, n-1+1, _state); + + /* + * PBL version + */ + if( hmatrixtdpbl(a, n, isupper, tau, d, e, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + if( isupper ) + { + + /* + * Reduce the upper triangle of A + */ + a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(a->ptr.pp_complex[n-1][n-1].x); + for(i=n-2; i>=0; i--) + { + + /* + * Generate elementary reflector H = I+1 - tau * v * v' + */ + alpha = a->ptr.pp_complex[i][i+1]; + t.ptr.p_complex[1] = alpha; + if( i>=1 ) + { + ae_v_cmove(&t.ptr.p_complex[2], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(2,i+1)); + } + complexgeneratereflection(&t, i+1, &taui, _state); + if( i>=1 ) + { + ae_v_cmove(&a->ptr.pp_complex[0][i+1], a->stride, &t.ptr.p_complex[2], 1, "N", ae_v_len(0,i-1)); + } + alpha = t.ptr.p_complex[1]; + e->ptr.p_double[i] = alpha.x; + if( ae_c_neq_d(taui,(double)(0)) ) + { + + /* + * Apply H(I+1) from both sides to A + */ + a->ptr.pp_complex[i][i+1] = ae_complex_from_i(1); + + /* + * Compute x := tau * A * v storing x in TAU + */ + ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); + hermitianmatrixvectormultiply(a, isupper, 0, i, &t, taui, &t2, _state); + ae_v_cmove(&tau->ptr.p_complex[0], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(0,i)); + + /* + * Compute w := x - 1/2 * tau * (x'*v) * v + */ + v = ae_v_cdotproduct(&tau->ptr.p_complex[0], 1, "Conj", &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i)); + alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); + ae_v_caddc(&tau->ptr.p_complex[0], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(0,i), alpha); + + /* + * Apply the transformation as a rank-2 update: + * A := A - v * w' - w * v' + */ + ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); + ae_v_cmove(&t3.ptr.p_complex[1], 1, &tau->ptr.p_complex[0], 1, "N", ae_v_len(1,i+1)); + hermitianrank2update(a, isupper, 0, i, &t, &t3, &t2, ae_complex_from_i(-1), _state); + } + else + { + a->ptr.pp_complex[i][i] = ae_complex_from_d(a->ptr.pp_complex[i][i].x); + } + a->ptr.pp_complex[i][i+1] = ae_complex_from_d(e->ptr.p_double[i]); + d->ptr.p_double[i+1] = a->ptr.pp_complex[i+1][i+1].x; + tau->ptr.p_complex[i] = taui; + } + d->ptr.p_double[0] = a->ptr.pp_complex[0][0].x; + } + else + { + + /* + * Reduce the lower triangle of A + */ + a->ptr.pp_complex[0][0] = ae_complex_from_d(a->ptr.pp_complex[0][0].x); + for(i=0; i<=n-2; i++) + { + + /* + * Generate elementary reflector H = I - tau * v * v' + */ + ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); + complexgeneratereflection(&t, n-i-1, &taui, _state); + ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &t.ptr.p_complex[1], 1, "N", ae_v_len(i+1,n-1)); + e->ptr.p_double[i] = a->ptr.pp_complex[i+1][i].x; + if( ae_c_neq_d(taui,(double)(0)) ) + { + + /* + * Apply H(i) from both sides to A(i+1:n,i+1:n) + */ + a->ptr.pp_complex[i+1][i] = ae_complex_from_i(1); + + /* + * Compute x := tau * A * v storing y in TAU + */ + ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); + hermitianmatrixvectormultiply(a, isupper, i+1, n-1, &t, taui, &t2, _state); + ae_v_cmove(&tau->ptr.p_complex[i], 1, &t2.ptr.p_complex[1], 1, "N", ae_v_len(i,n-2)); + + /* + * Compute w := x - 1/2 * tau * (x'*v) * v + */ + v = ae_v_cdotproduct(&tau->ptr.p_complex[i], 1, "Conj", &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2)); + alpha = ae_c_neg(ae_c_mul(ae_c_mul_d(taui,0.5),v)); + ae_v_caddc(&tau->ptr.p_complex[i], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(i,n-2), alpha); + + /* + * Apply the transformation as a rank-2 update: + * A := A - v * w' - w * v' + */ + ae_v_cmove(&t.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); + ae_v_cmove(&t2.ptr.p_complex[1], 1, &tau->ptr.p_complex[i], 1, "N", ae_v_len(1,n-i-1)); + hermitianrank2update(a, isupper, i+1, n-1, &t, &t2, &t3, ae_complex_from_i(-1), _state); + } + else + { + a->ptr.pp_complex[i+1][i+1] = ae_complex_from_d(a->ptr.pp_complex[i+1][i+1].x); + } + a->ptr.pp_complex[i+1][i] = ae_complex_from_d(e->ptr.p_double[i]); + d->ptr.p_double[i] = a->ptr.pp_complex[i][i].x; + tau->ptr.p_complex[i] = taui; + } + d->ptr.p_double[n-1] = a->ptr.pp_complex[n-1][n-1].x; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a HMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of HMatrixTD subroutine) + Tau - the result of a HMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void hmatrixtdunpackq(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* tau, + /* Complex */ ae_matrix* q, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector v; + ae_vector work; + + ae_frame_make(_state, &_frame_block); + memset(&v, 0, sizeof(v)); + memset(&work, 0, sizeof(work)); + ae_matrix_clear(q); + ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * init + */ + ae_matrix_set_length(q, n-1+1, n-1+1, _state); + ae_vector_set_length(&v, n+1, _state); + ae_vector_set_length(&work, n-1+1, _state); + + /* + * PBL version + */ + if( hmatrixtdunpackqpbl(a, n, isupper, tau, q, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(1); + } + else + { + q->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + if( isupper ) + { + for(i=0; i<=n-2; i++) + { + + /* + * Apply H(i) + */ + ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[0][i+1], a->stride, "N", ae_v_len(1,i+1)); + v.ptr.p_complex[i+1] = ae_complex_from_i(1); + complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, 0, i, 0, n-1, &work, _state); + } + } + else + { + for(i=n-2; i>=0; i--) + { + + /* + * Apply H(i) + */ + ae_v_cmove(&v.ptr.p_complex[1], 1, &a->ptr.pp_complex[i+1][i], a->stride, "N", ae_v_len(1,n-i-1)); + v.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheleft(q, tau->ptr.p_complex[i], &v, i+1, n-1, 0, n-1, &work, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Base case for complex QR + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +static void ortfac_cmatrixqrbasecase(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* work, + /* Complex */ ae_vector* t, + /* Complex */ ae_vector* tau, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t mmi; + ae_int_t minmn; + ae_complex tmp; + + + minmn = ae_minint(m, n, _state); + if( minmn<=0 ) + { + return; + } + + /* + * Test the input arguments + */ + k = ae_minint(m, n, _state); + for(i=0; i<=k-1; i++) + { + + /* + * Generate elementary reflector H(i) to annihilate A(i+1:m,i) + */ + mmi = m-i; + ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], a->stride, "N", ae_v_len(1,mmi)); + complexgeneratereflection(t, mmi, &tmp, _state); + tau->ptr.p_complex[i] = tmp; + ae_v_cmove(&a->ptr.pp_complex[i][i], a->stride, &t->ptr.p_complex[1], 1, "N", ae_v_len(i,m-1)); + t->ptr.p_complex[1] = ae_complex_from_i(1); + if( iptr.p_complex[i], _state), t, i, m-1, i+1, n-1, work, _state); + } + } +} + + +/************************************************************************* +Base case for complex LQ + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +static void ortfac_cmatrixlqbasecase(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* work, + /* Complex */ ae_vector* t, + /* Complex */ ae_vector* tau, + ae_state *_state) +{ + ae_int_t i; + ae_int_t minmn; + ae_complex tmp; + + + minmn = ae_minint(m, n, _state); + if( minmn<=0 ) + { + return; + } + + /* + * Test the input arguments + */ + for(i=0; i<=minmn-1; i++) + { + + /* + * Generate elementary reflector H(i) + * + * NOTE: ComplexGenerateReflection() generates left reflector, + * i.e. H which reduces x by applyiong from the left, but we + * need RIGHT reflector. So we replace H=E-tau*v*v' by H^H, + * which changes v to conj(v). + */ + ae_v_cmove(&t->ptr.p_complex[1], 1, &a->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(1,n-i)); + complexgeneratereflection(t, n-i, &tmp, _state); + tau->ptr.p_complex[i] = tmp; + ae_v_cmove(&a->ptr.pp_complex[i][i], 1, &t->ptr.p_complex[1], 1, "Conj", ae_v_len(i,n-1)); + t->ptr.p_complex[1] = ae_complex_from_i(1); + if( iptr.p_complex[i], t, i+1, m-1, i, n-1, work, _state); + } + } +} + + +/************************************************************************* +Generate block reflector: +* fill unused parts of reflectors matrix by zeros +* fill diagonal of reflectors matrix by ones +* generate triangular factor T + +PARAMETERS: + A - either LengthA*BlockSize (if ColumnwiseA) or + BlockSize*LengthA (if not ColumnwiseA) matrix of + elementary reflectors. + Modified on exit. + Tau - scalar factors + ColumnwiseA - reflectors are stored in rows or in columns + LengthA - length of largest reflector + BlockSize - number of reflectors + T - array[BlockSize,2*BlockSize]. Left BlockSize*BlockSize + submatrix stores triangular factor on exit. + WORK - array[BlockSize] + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +static void ortfac_rmatrixblockreflector(/* Real */ ae_matrix* a, + /* Real */ ae_vector* tau, + ae_bool columnwisea, + ae_int_t lengtha, + ae_int_t blocksize, + /* Real */ ae_matrix* t, + /* Real */ ae_vector* work, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + + + + /* + * fill beginning of new column with zeros, + * load 1.0 in the first non-zero element + */ + for(k=0; k<=blocksize-1; k++) + { + if( columnwisea ) + { + for(i=0; i<=k-1; i++) + { + a->ptr.pp_double[i][k] = (double)(0); + } + } + else + { + for(i=0; i<=k-1; i++) + { + a->ptr.pp_double[k][i] = (double)(0); + } + } + a->ptr.pp_double[k][k] = (double)(1); + } + + /* + * Calculate Gram matrix of A + */ + for(i=0; i<=blocksize-1; i++) + { + for(j=0; j<=blocksize-1; j++) + { + t->ptr.pp_double[i][blocksize+j] = (double)(0); + } + } + for(k=0; k<=lengtha-1; k++) + { + for(j=1; j<=blocksize-1; j++) + { + if( columnwisea ) + { + v = a->ptr.pp_double[k][j]; + if( ae_fp_neq(v,(double)(0)) ) + { + ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[k][0], 1, ae_v_len(blocksize,blocksize+j-1), v); + } + } + else + { + v = a->ptr.pp_double[j][k]; + if( ae_fp_neq(v,(double)(0)) ) + { + ae_v_addd(&t->ptr.pp_double[j][blocksize], 1, &a->ptr.pp_double[0][k], a->stride, ae_v_len(blocksize,blocksize+j-1), v); + } + } + } + } + + /* + * Prepare Y (stored in TmpA) and T (stored in TmpT) + */ + for(k=0; k<=blocksize-1; k++) + { + + /* + * fill non-zero part of T, use pre-calculated Gram matrix + */ + ae_v_move(&work->ptr.p_double[0], 1, &t->ptr.pp_double[k][blocksize], 1, ae_v_len(0,k-1)); + for(i=0; i<=k-1; i++) + { + v = ae_v_dotproduct(&t->ptr.pp_double[i][i], 1, &work->ptr.p_double[i], 1, ae_v_len(i,k-1)); + t->ptr.pp_double[i][k] = -tau->ptr.p_double[k]*v; + } + t->ptr.pp_double[k][k] = -tau->ptr.p_double[k]; + + /* + * Rest of T is filled by zeros + */ + for(i=k+1; i<=blocksize-1; i++) + { + t->ptr.pp_double[i][k] = (double)(0); + } + } +} + + +/************************************************************************* +Generate block reflector (complex): +* fill unused parts of reflectors matrix by zeros +* fill diagonal of reflectors matrix by ones +* generate triangular factor T + + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +static void ortfac_cmatrixblockreflector(/* Complex */ ae_matrix* a, + /* Complex */ ae_vector* tau, + ae_bool columnwisea, + ae_int_t lengtha, + ae_int_t blocksize, + /* Complex */ ae_matrix* t, + /* Complex */ ae_vector* work, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_complex v; + + + + /* + * Prepare Y (stored in TmpA) and T (stored in TmpT) + */ + for(k=0; k<=blocksize-1; k++) + { + + /* + * fill beginning of new column with zeros, + * load 1.0 in the first non-zero element + */ + if( columnwisea ) + { + for(i=0; i<=k-1; i++) + { + a->ptr.pp_complex[i][k] = ae_complex_from_i(0); + } + } + else + { + for(i=0; i<=k-1; i++) + { + a->ptr.pp_complex[k][i] = ae_complex_from_i(0); + } + } + a->ptr.pp_complex[k][k] = ae_complex_from_i(1); + + /* + * fill non-zero part of T, + */ + for(i=0; i<=k-1; i++) + { + if( columnwisea ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[k][i], a->stride, "Conj", &a->ptr.pp_complex[k][k], a->stride, "N", ae_v_len(k,lengtha-1)); + } + else + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[i][k], 1, "N", &a->ptr.pp_complex[k][k], 1, "Conj", ae_v_len(k,lengtha-1)); + } + work->ptr.p_complex[i] = v; + } + for(i=0; i<=k-1; i++) + { + v = ae_v_cdotproduct(&t->ptr.pp_complex[i][i], 1, "N", &work->ptr.p_complex[i], 1, "N", ae_v_len(i,k-1)); + t->ptr.pp_complex[i][k] = ae_c_neg(ae_c_mul(tau->ptr.p_complex[k],v)); + } + t->ptr.pp_complex[k][k] = ae_c_neg(tau->ptr.p_complex[k]); + + /* + * Rest of T is filled by zeros + */ + for(i=k+1; i<=blocksize-1; i++) + { + t->ptr.pp_complex[i][k] = ae_complex_from_i(0); + } + } +} + + +#endif +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Generation of a random uniformly distributed (Haar) orthogonal matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonal(ae_int_t n, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_assert(n>=1, "RMatrixRndOrthogonal: N<1!", _state); + ae_matrix_set_length(a, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + a->ptr.pp_double[i][j] = (double)(1); + } + else + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + } + rmatrixrndorthogonalfromtheright(a, n, n, _state); +} + + +/************************************************************************* +Generation of random NxN matrix with given condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_matrix_clear(a); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "RMatrixRndCond: N<1 or C<1!", _state); + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + + /* + * special case + */ + a->ptr.pp_double[0][0] = (double)(2*ae_randominteger(2, _state)-1); + ae_frame_leave(_state); + return; + } + hqrndrandomize(&rs, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + a->ptr.pp_double[0][0] = ae_exp(l1, _state); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); + } + a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); + rmatrixrndorthogonalfromtheleft(a, n, n, _state); + rmatrixrndorthogonalfromtheright(a, n, n, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Generation of a random Haar distributed orthogonal complex matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonal(ae_int_t n, + /* Complex */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(a); + + ae_assert(n>=1, "CMatrixRndOrthogonal: N<1!", _state); + ae_matrix_set_length(a, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( i==j ) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(1); + } + else + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + cmatrixrndorthogonalfromtheright(a, n, n, _state); +} + + +/************************************************************************* +Generation of random NxN complex matrix with given condition number C and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate state; + ae_complex v; + + ae_frame_make(_state, &_frame_block); + memset(&state, 0, sizeof(state)); + ae_matrix_clear(a); + _hqrndstate_init(&state, _state, ae_true); + + ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "CMatrixRndCond: N<1 or C<1!", _state); + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + + /* + * special case + */ + hqrndrandomize(&state, _state); + hqrndunit2(&state, &v.x, &v.y, _state); + a->ptr.pp_complex[0][0] = v; + ae_frame_leave(_state); + return; + } + hqrndrandomize(&state, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&state, _state)*(l2-l1)+l1, _state)); + } + a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); + cmatrixrndorthogonalfromtheleft(a, n, n, _state); + cmatrixrndorthogonalfromtheright(a, n, n, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Generation of random NxN symmetric matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_matrix_clear(a); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "SMatrixRndCond: N<1 or C<1!", _state); + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + + /* + * special case + */ + a->ptr.pp_double[0][0] = (double)(2*ae_randominteger(2, _state)-1); + ae_frame_leave(_state); + return; + } + + /* + * Prepare matrix + */ + hqrndrandomize(&rs, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + a->ptr.pp_double[0][0] = ae_exp(l1, _state); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_double[i][i] = (double)(2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); + } + a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); + + /* + * Multiply + */ + smatrixrndmultiply(a, n, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Generation of random NxN symmetric positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random SPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_matrix_clear(a); + _hqrndstate_init(&rs, _state, ae_true); + + + /* + * Special cases + */ + if( n<=0||ae_fp_less(c,(double)(1)) ) + { + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + a->ptr.pp_double[0][0] = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Prepare matrix + */ + hqrndrandomize(&rs, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + a->ptr.pp_double[0][0] = ae_exp(l1, _state); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_double[i][i] = ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state); + } + a->ptr.pp_double[n-1][n-1] = ae_exp(l2, _state); + + /* + * Multiply + */ + smatrixrndmultiply(a, n, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Generation of random NxN Hermitian matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_matrix_clear(a); + _hqrndstate_init(&rs, _state, ae_true); + + ae_assert(n>=1&&ae_fp_greater_eq(c,(double)(1)), "HMatrixRndCond: N<1 or C<1!", _state); + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + + /* + * special case + */ + a->ptr.pp_complex[0][0] = ae_complex_from_i(2*ae_randominteger(2, _state)-1); + ae_frame_leave(_state); + return; + } + + /* + * Prepare matrix + */ + hqrndrandomize(&rs, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_complex[i][i] = ae_complex_from_d((double)(2*hqrnduniformi(&rs, 2, _state)-1)*ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); + } + a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); + + /* + * Multiply + */ + hmatrixrndmultiply(a, n, _state); + + /* + * post-process to ensure that matrix diagonal is real + */ + for(i=0; i<=n-1; i++) + { + a->ptr.pp_complex[i][i].y = (double)(0); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Generation of random NxN Hermitian positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random HPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double l1; + double l2; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + ae_matrix_clear(a); + _hqrndstate_init(&rs, _state, ae_true); + + + /* + * Special cases + */ + if( n<=0||ae_fp_less(c,(double)(1)) ) + { + ae_frame_leave(_state); + return; + } + ae_matrix_set_length(a, n, n, _state); + if( n==1 ) + { + a->ptr.pp_complex[0][0] = ae_complex_from_i(1); + ae_frame_leave(_state); + return; + } + + /* + * Prepare matrix + */ + hqrndrandomize(&rs, _state); + l1 = (double)(0); + l2 = ae_log((double)1/c, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + a->ptr.pp_complex[0][0] = ae_complex_from_d(ae_exp(l1, _state)); + for(i=1; i<=n-2; i++) + { + a->ptr.pp_complex[i][i] = ae_complex_from_d(ae_exp(hqrnduniformr(&rs, _state)*(l2-l1)+l1, _state)); + } + a->ptr.pp_complex[n-1][n-1] = ae_complex_from_d(ae_exp(l2, _state)); + + /* + * Multiply + */ + hmatrixrndmultiply(a, n, _state); + + /* + * post-process to ensure that matrix diagonal is real + */ + for(i=0; i<=n-1; i++) + { + a->ptr.pp_complex[i][i].y = (double)(0); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + double tau; + double lambdav; + ae_int_t s; + ae_int_t i; + double u1; + double u2; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); + if( n==1 ) + { + + /* + * Special case + */ + tau = (double)(2*ae_randominteger(2, _state)-1); + for(i=0; i<=m-1; i++) + { + a->ptr.pp_double[i][0] = a->ptr.pp_double[i][0]*tau; + } + ae_frame_leave(_state); + return; + } + + /* + * General case. + * First pass. + */ + ae_vector_set_length(&w, m, _state); + ae_vector_set_length(&v, n+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=n; s++) + { + + /* + * Prepare random normal v + */ + do + { + i = 1; + while(i<=s) + { + hqrndnormal2(&state, &u1, &u2, _state); + v.ptr.p_double[i] = u1; + if( i+1<=s ) + { + v.ptr.p_double[i+1] = u2; + } + i = i+2; + } + lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); + } + while(ae_fp_eq(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + generatereflection(&v, s, &tau, _state); + v.ptr.p_double[1] = (double)(1); + applyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=n-1; i++) + { + tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); + ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,m-1), tau); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + double tau; + double lambdav; + ae_int_t s; + ae_int_t i; + ae_int_t j; + double u1; + double u2; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + ae_assert(n>=1&&m>=1, "RMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); + if( m==1 ) + { + + /* + * special case + */ + tau = (double)(2*ae_randominteger(2, _state)-1); + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[0][j] = a->ptr.pp_double[0][j]*tau; + } + ae_frame_leave(_state); + return; + } + + /* + * General case. + * First pass. + */ + ae_vector_set_length(&w, n, _state); + ae_vector_set_length(&v, m+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=m; s++) + { + + /* + * Prepare random normal v + */ + do + { + i = 1; + while(i<=s) + { + hqrndnormal2(&state, &u1, &u2, _state); + v.ptr.p_double[i] = u1; + if( i+1<=s ) + { + v.ptr.p_double[i+1] = u2; + } + i = i+2; + } + lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); + } + while(ae_fp_eq(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + generatereflection(&v, s, &tau, _state); + v.ptr.p_double[1] = (double)(1); + applyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=m-1; i++) + { + tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); + ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Multiplication of MxN complex matrix by NxN random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_complex lambdav; + ae_complex tau; + ae_int_t s; + ae_int_t i; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); + if( n==1 ) + { + + /* + * Special case + */ + hqrndrandomize(&state, _state); + hqrndunit2(&state, &tau.x, &tau.y, _state); + for(i=0; i<=m-1; i++) + { + a->ptr.pp_complex[i][0] = ae_c_mul(a->ptr.pp_complex[i][0],tau); + } + ae_frame_leave(_state); + return; + } + + /* + * General case. + * First pass. + */ + ae_vector_set_length(&w, m, _state); + ae_vector_set_length(&v, n+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=n; s++) + { + + /* + * Prepare random normal v + */ + do + { + for(i=1; i<=s; i++) + { + hqrndnormal2(&state, &tau.x, &tau.y, _state); + v.ptr.p_complex[i] = tau; + } + lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); + } + while(ae_c_eq_d(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + complexgeneratereflection(&v, s, &tau, _state); + v.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheright(a, tau, &v, 0, m-1, n-s, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=n-1; i++) + { + hqrndunit2(&state, &tau.x, &tau.y, _state); + ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,m-1), tau); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Multiplication of MxN complex matrix by MxM random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_complex tau; + ae_complex lambdav; + ae_int_t s; + ae_int_t i; + ae_int_t j; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + ae_assert(n>=1&&m>=1, "CMatrixRndOrthogonalFromTheRight: N<1 or M<1!", _state); + if( m==1 ) + { + + /* + * special case + */ + hqrndrandomize(&state, _state); + hqrndunit2(&state, &tau.x, &tau.y, _state); + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[0][j] = ae_c_mul(a->ptr.pp_complex[0][j],tau); + } + ae_frame_leave(_state); + return; + } + + /* + * General case. + * First pass. + */ + ae_vector_set_length(&w, n, _state); + ae_vector_set_length(&v, m+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=m; s++) + { + + /* + * Prepare random normal v + */ + do + { + for(i=1; i<=s; i++) + { + hqrndnormal2(&state, &tau.x, &tau.y, _state); + v.ptr.p_complex[i] = tau; + } + lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); + } + while(ae_c_eq_d(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + complexgeneratereflection(&v, s, &tau, _state); + v.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheleft(a, tau, &v, m-s, m-1, 0, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=m-1; i++) + { + hqrndunit2(&state, &tau.x, &tau.y, _state); + ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Symmetric multiplication of NxN matrix by random Haar distributed +orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q'*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndmultiply(/* Real */ ae_matrix* a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + double tau; + double lambdav; + ae_int_t s; + ae_int_t i; + double u1; + double u2; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + + /* + * General case. + */ + ae_vector_set_length(&w, n, _state); + ae_vector_set_length(&v, n+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=n; s++) + { + + /* + * Prepare random normal v + */ + do + { + i = 1; + while(i<=s) + { + hqrndnormal2(&state, &u1, &u2, _state); + v.ptr.p_double[i] = u1; + if( i+1<=s ) + { + v.ptr.p_double[i+1] = u2; + } + i = i+2; + } + lambdav = ae_v_dotproduct(&v.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,s)); + } + while(ae_fp_eq(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + generatereflection(&v, s, &tau, _state); + v.ptr.p_double[1] = (double)(1); + applyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); + applyreflectionfromtheleft(a, tau, &v, n-s, n-1, 0, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=n-1; i++) + { + tau = (double)(2*hqrnduniformi(&state, 2, _state)-1); + ae_v_muld(&a->ptr.pp_double[0][i], a->stride, ae_v_len(0,n-1), tau); + ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), tau); + } + + /* + * Copy upper triangle to lower + */ + for(i=0; i<=n-2; i++) + { + ae_v_move(&a->ptr.pp_double[i+1][i], a->stride, &a->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Hermitian multiplication of NxN matrix by random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q^H*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndmultiply(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_complex tau; + ae_complex lambdav; + ae_int_t s; + ae_int_t i; + ae_vector w; + ae_vector v; + hqrndstate state; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&v, 0, sizeof(v)); + memset(&state, 0, sizeof(state)); + ae_vector_init(&w, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&v, 0, DT_COMPLEX, _state, ae_true); + _hqrndstate_init(&state, _state, ae_true); + + + /* + * General case. + */ + ae_vector_set_length(&w, n, _state); + ae_vector_set_length(&v, n+1, _state); + hqrndrandomize(&state, _state); + for(s=2; s<=n; s++) + { + + /* + * Prepare random normal v + */ + do + { + for(i=1; i<=s; i++) + { + hqrndnormal2(&state, &tau.x, &tau.y, _state); + v.ptr.p_complex[i] = tau; + } + lambdav = ae_v_cdotproduct(&v.ptr.p_complex[1], 1, "N", &v.ptr.p_complex[1], 1, "Conj", ae_v_len(1,s)); + } + while(ae_c_eq_d(lambdav,(double)(0))); + + /* + * Prepare and apply reflection + */ + complexgeneratereflection(&v, s, &tau, _state); + v.ptr.p_complex[1] = ae_complex_from_i(1); + complexapplyreflectionfromtheright(a, tau, &v, 0, n-1, n-s, n-1, &w, _state); + complexapplyreflectionfromtheleft(a, ae_c_conj(tau, _state), &v, n-s, n-1, 0, n-1, &w, _state); + } + + /* + * Second pass. + */ + for(i=0; i<=n-1; i++) + { + hqrndunit2(&state, &tau.x, &tau.y, _state); + ae_v_cmulc(&a->ptr.pp_complex[0][i], a->stride, ae_v_len(0,n-1), tau); + tau = ae_c_conj(tau, _state); + ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), tau); + } + + /* + * Change all values from lower triangle by complex-conjugate values + * from upper one + */ + for(i=0; i<=n-2; i++) + { + ae_v_cmove(&a->ptr.pp_complex[i+1][i], a->stride, &a->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1)); + } + for(s=0; s<=n-2; s++) + { + for(i=s+1; i<=n-1; i++) + { + a->ptr.pp_complex[i][s].y = -a->ptr.pp_complex[i][s].y; + } + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function creates sparse matrix in a Hash-Table format. + +This function creates Hast-Table matrix, which can be converted to CRS +format after its initialization is over. Typical usage scenario for a +sparse matrix is: +1. creation in a Hash-Table format +2. insertion of the matrix elements +3. conversion to the CRS representation +4. matrix is passed to some linear algebra algorithm + +Some information about different matrix formats can be found below, in +the "NOTES" section. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + +NOTE 1 + +Hash-tables use memory inefficiently, and they have to keep some amount +of the "spare memory" in order to have good performance. Hash table for +matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, +where C is a small constant, about 1.5-2 in magnitude. + +CRS storage, from the other side, is more memory-efficient, and needs +just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows +in a matrix. + +When you convert from the Hash-Table to CRS representation, all unneeded +memory will be freed. + +NOTE 2 + +Comments of SparseMatrix structure outline information about different +sparse storage formats. We recommend you to read them before starting to +use ALGLIB sparse matrices. + +NOTE 3 + +This function completely overwrites S with new sparse matrix. Previously +allocated storage is NOT reused. If you want to reuse already allocated +memory, call SparseCreateBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreate(ae_int_t m, + ae_int_t n, + ae_int_t k, + sparsematrix* s, + ae_state *_state) +{ + + _sparsematrix_clear(s); + + sparsecreatebuf(m, n, k, s, _state); +} + + +/************************************************************************* +This version of SparseCreate function creates sparse matrix in Hash-Table +format, reusing previously allocated storage as much as possible. Read +comments for SparseCreate() for more information. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + S - SparseMatrix structure which MAY contain some already + allocated storage. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + Previously allocated storage is reused, if its size + is compatible with expected number of non-zeros K. + + -- ALGLIB PROJECT -- + Copyright 14.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatebuf(ae_int_t m, + ae_int_t n, + ae_int_t k, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(m>0, "SparseCreateBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateBuf: N<=0", _state); + ae_assert(k>=0, "SparseCreateBuf: K<0", _state); + + /* + * Hash-table size is max(existing_size,requested_size) + * + * NOTE: it is important to use ALL available memory for hash table + * because it is impossible to efficiently reallocate table + * without temporary storage. So, if we want table with up to + * 1.000.000 elements, we have to create such table from the + * very beginning. Otherwise, the very idea of memory reuse + * will be compromised. + */ + s->tablesize = ae_round((double)k/sparse_desiredloadfactor+(double)sparse_additional, _state); + rallocv(s->tablesize, &s->vals, _state); + s->tablesize = s->vals.cnt; + + /* + * Initialize other fields + */ + s->matrixtype = 0; + s->m = m; + s->n = n; + s->nfree = s->tablesize; + iallocv(2*s->tablesize, &s->idx, _state); + for(i=0; i<=s->tablesize-1; i++) + { + s->idx.ptr.p_int[2*i] = -1; + } +} + + +/************************************************************************* +This function creates sparse matrix in a CRS format - the least flexible +but the most efficient format implemented in ALGLIB. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell the number of non-zero elements at each row + at this moment) +2. initialization of the matrix elements (row by row, from left to right) +3. the matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrs(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* ner, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + + _sparsematrix_clear(s); + + ae_assert(m>0, "SparseCreateCRS: M<=0", _state); + ae_assert(n>0, "SparseCreateCRS: N<=0", _state); + ae_assert(ner->cnt>=m, "SparseCreateCRS: Length(NER)ptr.p_int[i]>=0, "SparseCreateCRS: NER[] contains negative elements", _state); + } + sparsecreatecrsbuf(m, n, ner, s, _state); +} + + +/************************************************************************* +This function creates sparse matrix in a CRS format (expert function for +situations when you are running out of memory). This version of CRS +matrix creation function may reuse memory already allocated in S. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell number of non-zero elements at each row at + this moment) +2. insertion of the matrix elements (row by row, from left to right) +3. matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices.. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + S - sparse matrix structure with possibly preallocated + memory. + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsbuf(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* ner, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t noe; + + + ae_assert(m>0, "SparseCreateCRSBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateCRSBuf: N<=0", _state); + ae_assert(ner->cnt>=m, "SparseCreateCRSBuf: Length(NER)matrixtype = 1; + s->ninitialized = 0; + s->m = m; + s->n = n; + ivectorsetlengthatleast(&s->ridx, s->m+1, _state); + s->ridx.ptr.p_int[0] = 0; + for(i=0; i<=s->m-1; i++) + { + ae_assert(ner->ptr.p_int[i]>=0, "SparseCreateCRSBuf: NER[] contains negative elements", _state); + noe = noe+ner->ptr.p_int[i]; + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+ner->ptr.p_int[i]; + } + rvectorsetlengthatleast(&s->vals, noe, _state); + ivectorsetlengthatleast(&s->idx, noe, _state); + if( noe==0 ) + { + sparseinitduidx(s, _state); + } +} + + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdense(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + + _sparsematrix_clear(s); + + ae_assert(m>0, "SparseCreateCRSFromDense: M<=0", _state); + ae_assert(n>0, "SparseCreateCRSFromDense: N<=0", _state); + ae_assert(a->rows>=m, "SparseCreateCRSFromDense: rows(A)cols>=n, "SparseCreateCRSFromDense: cols(A)=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensebuf(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nnz; + ae_int_t offs; + + + ae_assert(m>0, "SparseCreateCRSFromDenseBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateCRSFromDenseBuf: N<=0", _state); + ae_assert(a->rows>=m, "SparseCreateCRSFromDenseBuf: rows(A)cols>=n, "SparseCreateCRSFromDenseBuf: cols(A)ptr.pp_double[i][j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + s->matrixtype = 1; + s->ninitialized = nnz; + s->m = m; + s->n = n; + iallocv(m+1, &s->ridx, _state); + iallocv(nnz, &s->idx, _state); + rallocv(nnz, &s->vals, _state); + s->ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( a->ptr.pp_double[i][j]!=0.0 ) + { + s->idx.ptr.p_int[offs] = j; + s->vals.ptr.p_double[offs] = a->ptr.pp_double[i][j]; + offs = offs+1; + } + } + s->ridx.ptr.p_int[i+1] = offs; + } + ae_assert(offs==nnz, "SparseCreateCRSFromDenseBuf: integrity check 6447 failed", _state); + sparseinitduidx(s, _state); +} + + +/************************************************************************* +This function creates a CRS-based sparse matrix from a dense vector +which stores a dense 1-dimensional representation of a dense M*N matrix. + +This function is intended for situations when you already have a dense +vector and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M*N]. If larger, only leading M*N elements + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensev(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + + _sparsematrix_clear(s); + + ae_assert(m>0, "SparseCreateCRSFromDenseV: M<=0", _state); + ae_assert(n>0, "SparseCreateCRSFromDenseV: N<=0", _state); + ae_assert(a->cnt>=m*n, "SparseCreateCRSFromDenseV: length(A)=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensevbuf(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nnz; + ae_int_t offs; + + + ae_assert(m>0, "SparseCreateCRSFromDenseVBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateCRSFromDenseVBuf: N<=0", _state); + ae_assert(a->cnt>=m*n, "SparseCreateCRSFromDenseVBuf: length(A)ptr.p_double[i*n+j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + s->matrixtype = 1; + s->ninitialized = nnz; + s->m = m; + s->n = n; + iallocv(m+1, &s->ridx, _state); + iallocv(nnz, &s->idx, _state); + rallocv(nnz, &s->vals, _state); + s->ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( a->ptr.p_double[i*n+j]!=0.0 ) + { + s->idx.ptr.p_int[offs] = j; + s->vals.ptr.p_double[offs] = a->ptr.p_double[i*n+j]; + offs = offs+1; + } + } + s->ridx.ptr.p_int[i+1] = offs; + } + ae_assert(offs==nnz, "SparseCreateCRSFromDenseVBuf: integrity check 6447 failed", _state); + sparseinitduidx(s, _state); +} + + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], D[I]>=0. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], U[I]>=0. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateSKSBuf function. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesks(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* d, + /* Integer */ const ae_vector* u, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + + _sparsematrix_clear(s); + + ae_assert(m>0, "SparseCreateSKS: M<=0", _state); + ae_assert(n>0, "SparseCreateSKS: N<=0", _state); + ae_assert(m==n, "SparseCreateSKS: M<>N", _state); + ae_assert(d->cnt>=m, "SparseCreateSKS: Length(D)cnt>=n, "SparseCreateSKS: Length(U)ptr.p_int[i]>=0, "SparseCreateSKS: D[] contains negative elements", _state); + ae_assert(d->ptr.p_int[i]<=i, "SparseCreateSKS: D[I]>I for some I", _state); + } + for(i=0; i<=n-1; i++) + { + ae_assert(u->ptr.p_int[i]>=0, "SparseCreateSKS: U[] contains negative elements", _state); + ae_assert(u->ptr.p_int[i]<=i, "SparseCreateSKS: U[I]>I for some I", _state); + } + sparsecreatesksbuf(m, n, d, u, s, _state); +} + + +/************************************************************************* +This is "buffered" version of SparseCreateSKS() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], 0<=D[I]<=I. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], 0<=U[I]<=I. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbuf(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* d, + /* Integer */ const ae_vector* u, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t minmn; + ae_int_t nz; + ae_int_t mxd; + ae_int_t mxu; + + + ae_assert(m>0, "SparseCreateSKSBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateSKSBuf: N<=0", _state); + ae_assert(m==n, "SparseCreateSKSBuf: M<>N", _state); + ae_assert(d->cnt>=m, "SparseCreateSKSBuf: Length(D)cnt>=n, "SparseCreateSKSBuf: Length(U)ptr.p_int[i]>=0, "SparseCreateSKSBuf: D[] contains negative elements", _state); + ae_assert(d->ptr.p_int[i]<=i, "SparseCreateSKSBuf: D[I]>I for some I", _state); + } + for(i=0; i<=n-1; i++) + { + ae_assert(u->ptr.p_int[i]>=0, "SparseCreateSKSBuf: U[] contains negative elements", _state); + ae_assert(u->ptr.p_int[i]<=i, "SparseCreateSKSBuf: U[I]>I for some I", _state); + } + minmn = ae_minint(m, n, _state); + s->matrixtype = 2; + s->ninitialized = 0; + s->m = m; + s->n = n; + ivectorsetlengthatleast(&s->ridx, minmn+1, _state); + s->ridx.ptr.p_int[0] = 0; + nz = 0; + for(i=0; i<=minmn-1; i++) + { + nz = nz+1+d->ptr.p_int[i]+u->ptr.p_int[i]; + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+1+d->ptr.p_int[i]+u->ptr.p_int[i]; + } + rvectorsetlengthatleast(&s->vals, nz, _state); + for(i=0; i<=nz-1; i++) + { + s->vals.ptr.p_double[i] = 0.0; + } + ivectorsetlengthatleast(&s->didx, m+1, _state); + mxd = 0; + for(i=0; i<=m-1; i++) + { + s->didx.ptr.p_int[i] = d->ptr.p_int[i]; + mxd = ae_maxint(mxd, d->ptr.p_int[i], _state); + } + s->didx.ptr.p_int[m] = mxd; + ivectorsetlengthatleast(&s->uidx, n+1, _state); + mxu = 0; + for(i=0; i<=n-1; i++) + { + s->uidx.ptr.p_int[i] = u->ptr.p_int[i]; + mxu = ae_maxint(mxu, u->ptr.p_int[i], _state); + } + s->uidx.ptr.p_int[n] = mxu; +} + + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). Unlike more general sparsecreatesks(), this function creates +sparse matrix with constant bandwidth. + +You may want to use this function instead of sparsecreatesks() when your +matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - matrix bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call sparsecreatesksbandbuf function. + + -- ALGLIB PROJECT -- + Copyright 25.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksband(ae_int_t m, + ae_int_t n, + ae_int_t bw, + sparsematrix* s, + ae_state *_state) +{ + + _sparsematrix_clear(s); + + ae_assert(m>0, "SparseCreateSKSBand: M<=0", _state); + ae_assert(n>0, "SparseCreateSKSBand: N<=0", _state); + ae_assert(bw>=0, "SparseCreateSKSBand: BW<0", _state); + ae_assert(m==n, "SparseCreateSKSBand: M!=N", _state); + sparsecreatesksbandbuf(m, n, bw, s, _state); +} + + +/************************************************************************* +This is "buffered" version of sparsecreatesksband() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +You may want to use this function instead of sparsecreatesksbuf() when +your matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbandbuf(ae_int_t m, + ae_int_t n, + ae_int_t bw, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t minmn; + ae_int_t nz; + ae_int_t mxd; + ae_int_t mxu; + ae_int_t dui; + + + ae_assert(m>0, "SparseCreateSKSBandBuf: M<=0", _state); + ae_assert(n>0, "SparseCreateSKSBandBuf: N<=0", _state); + ae_assert(m==n, "SparseCreateSKSBandBuf: M!=N", _state); + ae_assert(bw>=0, "SparseCreateSKSBandBuf: BW<0", _state); + minmn = ae_minint(m, n, _state); + s->matrixtype = 2; + s->ninitialized = 0; + s->m = m; + s->n = n; + ivectorsetlengthatleast(&s->ridx, minmn+1, _state); + s->ridx.ptr.p_int[0] = 0; + nz = 0; + for(i=0; i<=minmn-1; i++) + { + dui = ae_minint(i, bw, _state); + nz = nz+1+2*dui; + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i]+1+2*dui; + } + rvectorsetlengthatleast(&s->vals, nz, _state); + for(i=0; i<=nz-1; i++) + { + s->vals.ptr.p_double[i] = 0.0; + } + ivectorsetlengthatleast(&s->didx, m+1, _state); + mxd = 0; + for(i=0; i<=m-1; i++) + { + dui = ae_minint(i, bw, _state); + s->didx.ptr.p_int[i] = dui; + mxd = ae_maxint(mxd, dui, _state); + } + s->didx.ptr.p_int[m] = mxd; + ivectorsetlengthatleast(&s->uidx, n+1, _state); + mxu = 0; + for(i=0; i<=n-1; i++) + { + dui = ae_minint(i, bw, _state); + s->uidx.ptr.p_int[i] = dui; + mxu = ae_maxint(mxu, dui, _state); + } + s->uidx.ptr.p_int[n] = mxu; +} + + +/************************************************************************* +This function copies S0 to S1. +This function completely deallocates memory owned by S1 before creating a +copy of S0. If you want to reuse memory, use SparseCopyBuf. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopy(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + _sparsematrix_clear(s1); + + sparsecopybuf(s0, s1, _state); +} + + +/************************************************************************* +This function efficiently swaps contents of S0 and S1. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparseswap(sparsematrix* s0, sparsematrix* s1, ae_state *_state) +{ + + + swapi(&s1->matrixtype, &s0->matrixtype, _state); + swapi(&s1->m, &s0->m, _state); + swapi(&s1->n, &s0->n, _state); + swapi(&s1->nfree, &s0->nfree, _state); + swapi(&s1->ninitialized, &s0->ninitialized, _state); + swapi(&s1->tablesize, &s0->tablesize, _state); + ae_swap_vectors(&s1->vals, &s0->vals); + ae_swap_vectors(&s1->ridx, &s0->ridx); + ae_swap_vectors(&s1->idx, &s0->idx); + ae_swap_vectors(&s1->uidx, &s0->uidx); + ae_swap_vectors(&s1->didx, &s0->didx); +} + + +/************************************************************************* +This function adds value to S[i,j] - element of the sparse matrix. Matrix +must be in a Hash-Table mode. + +In case S[i,j] already exists in the table, V i added to its value. In +case S[i,j] is non-existent, it is inserted in the table. Table +automatically grows when necessary. + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + Exception will be thrown for CRS matrix. + I - row index of the element to modify, 0<=Imatrixtype==0, "SparseAdd: matrix must be in the Hash-Table mode to do this operation", _state); + ae_assert(i>=0, "SparseAdd: I<0", _state); + ae_assert(im, "SparseAdd: I>=M", _state); + ae_assert(j>=0, "SparseAdd: J<0", _state); + ae_assert(jn, "SparseAdd: J>=N", _state); + ae_assert(ae_isfinite(v, _state), "SparseAdd: V is not finite number", _state); + if( ae_fp_eq(v,(double)(0)) ) + { + return; + } + tcode = -1; + k = s->tablesize; + if( ae_fp_greater_eq(((double)1-sparse_maxloadfactor)*(double)k,(double)(s->nfree)) ) + { + sparseresizematrix(s, _state); + k = s->tablesize; + } + hashcode = sparse_hash(i, j, k, _state); + for(;;) + { + if( s->idx.ptr.p_int[2*hashcode]==-1 ) + { + if( tcode!=-1 ) + { + hashcode = tcode; + } + s->vals.ptr.p_double[hashcode] = v; + s->idx.ptr.p_int[2*hashcode] = i; + s->idx.ptr.p_int[2*hashcode+1] = j; + if( tcode==-1 ) + { + s->nfree = s->nfree-1; + } + return; + } + else + { + if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) + { + s->vals.ptr.p_double[hashcode] = s->vals.ptr.p_double[hashcode]+v; + if( ae_fp_eq(s->vals.ptr.p_double[hashcode],(double)(0)) ) + { + s->idx.ptr.p_int[2*hashcode] = -2; + } + return; + } + + /* + * Is it deleted element? + */ + if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) + { + tcode = hashcode; + } + + /* + * Next step + */ + hashcode = (hashcode+1)%k; + } + } +} + + +/************************************************************************* +This function modifies S[i,j] - element of the sparse matrix. + +For Hash-based storage format: +* this function can be called at any moment - during matrix initialization + or later +* new value can be zero or non-zero. In case new value of S[i,j] is zero, + this element is deleted from the table. +* this function has no effect when called with zero V for non-existent + element. + +For CRS-bases storage format: +* this function can be called ONLY DURING MATRIX INITIALIZATION +* zero values are stored in the matrix similarly to non-zero ones +* elements must be initialized in correct order - from top row to bottom, + within row - from left to right. + +For SKS storage: +* this function can be called at any moment - during matrix initialization + or later +* zero values are stored in the matrix similarly to non-zero ones +* this function CAN NOT be called for non-existent (outside of the band + specified during SKS matrix creation) elements. Say, if you created SKS + matrix with bandwidth=2 and tried to call sparseset(s,0,10,VAL), an + exception will be generated. + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table, SKS or CRS format. + I - row index of the element to modify, 0<=Imatrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseSet: unsupported matrix storage format", _state); + ae_assert(i>=0, "SparseSet: I<0", _state); + ae_assert(im, "SparseSet: I>=M", _state); + ae_assert(j>=0, "SparseSet: J<0", _state); + ae_assert(jn, "SparseSet: J>=N", _state); + ae_assert(ae_isfinite(v, _state), "SparseSet: V is not finite number", _state); + + /* + * Hash-table matrix + */ + if( s->matrixtype==0 ) + { + tcode = -1; + k = s->tablesize; + if( ae_fp_greater_eq(((double)1-sparse_maxloadfactor)*(double)k,(double)(s->nfree)) ) + { + sparseresizematrix(s, _state); + k = s->tablesize; + } + hashcode = sparse_hash(i, j, k, _state); + for(;;) + { + if( s->idx.ptr.p_int[2*hashcode]==-1 ) + { + if( ae_fp_neq(v,(double)(0)) ) + { + if( tcode!=-1 ) + { + hashcode = tcode; + } + s->vals.ptr.p_double[hashcode] = v; + s->idx.ptr.p_int[2*hashcode] = i; + s->idx.ptr.p_int[2*hashcode+1] = j; + if( tcode==-1 ) + { + s->nfree = s->nfree-1; + } + } + return; + } + else + { + if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) + { + if( ae_fp_eq(v,(double)(0)) ) + { + s->idx.ptr.p_int[2*hashcode] = -2; + } + else + { + s->vals.ptr.p_double[hashcode] = v; + } + return; + } + if( tcode==-1&&s->idx.ptr.p_int[2*hashcode]==-2 ) + { + tcode = hashcode; + } + + /* + * Next step + */ + hashcode = (hashcode+1)%k; + } + } + } + + /* + * CRS matrix + */ + if( s->matrixtype==1 ) + { + ae_assert(s->ridx.ptr.p_int[i]<=s->ninitialized, "SparseSet: too few initialized elements at some row (you have promised more when called SparceCreateCRS)", _state); + ae_assert(s->ridx.ptr.p_int[i+1]>s->ninitialized, "SparseSet: too many initialized elements at some row (you have promised less when called SparceCreateCRS)", _state); + ae_assert(s->ninitialized==s->ridx.ptr.p_int[i]||s->idx.ptr.p_int[s->ninitialized-1]vals.ptr.p_double[s->ninitialized] = v; + s->idx.ptr.p_int[s->ninitialized] = j; + s->ninitialized = s->ninitialized+1; + + /* + * If matrix has been created then + * initiale 'S.UIdx' and 'S.DIdx' + */ + if( s->ninitialized==s->ridx.ptr.p_int[s->m] ) + { + sparseinitduidx(s, _state); + } + return; + } + + /* + * SKS matrix + */ + if( s->matrixtype==2 ) + { + b = sparserewriteexisting(s, i, j, v, _state); + ae_assert(b, "SparseSet: an attempt to initialize out-of-band element of the SKS matrix", _state); + return; + } +} + + +/************************************************************************* +This function returns S[i,j] - element of the sparse matrix. Matrix can +be in any mode (Hash-Table, CRS, SKS), but this function is less efficient +for CRS matrices. Hash-Table and SKS matrices can find element in O(1) +time, while CRS matrices need O(log(RS)) time, where RS is an number of +non-zero elements in a row. + +INPUT PARAMETERS + S - sparse M*N matrix + I - row index of the element to modify, 0<=I=0, "SparseGet: I<0", _state); + ae_assert(im, "SparseGet: I>=M", _state); + ae_assert(j>=0, "SparseGet: J<0", _state); + ae_assert(jn, "SparseGet: J>=N", _state); + result = 0.0; + if( s->matrixtype==0 ) + { + + /* + * Hash-based storage + */ + result = (double)(0); + k = s->tablesize; + hashcode = sparse_hash(i, j, k, _state); + for(;;) + { + if( s->idx.ptr.p_int[2*hashcode]==-1 ) + { + return result; + } + if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) + { + result = s->vals.ptr.p_double[hashcode]; + return result; + } + hashcode = (hashcode+1)%k; + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGet: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + k0 = s->ridx.ptr.p_int[i]; + k1 = s->ridx.ptr.p_int[i+1]-1; + result = (double)(0); + while(k0<=k1) + { + k = (k0+k1)/2; + if( s->idx.ptr.p_int[k]==j ) + { + result = s->vals.ptr.p_double[k]; + return result; + } + if( s->idx.ptr.p_int[k]matrixtype==2 ) + { + + /* + * SKS + */ + ae_assert(s->m==s->n, "SparseGet: non-square SKS matrix not supported", _state); + result = (double)(0); + if( i==j ) + { + + /* + * Return diagonal element + */ + result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]]; + return result; + } + if( jdidx.ptr.p_int[i]; + if( i-j<=k ) + { + result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+k+j-i]; + } + } + else + { + + /* + * Return superdiagonal element at J-th "skyline block" + */ + k = s->uidx.ptr.p_int[j]; + if( j-i<=k ) + { + result = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; + } + return result; + } + return result; + } + ae_assert(ae_false, "SparseGet: unexpected matrix type", _state); + return result; +} + + +/************************************************************************* +This function checks whether S[i,j] is present in the sparse matrix. It +returns True even for elements that are numerically zero (but still +have place allocated for them). + +The matrix can be in any mode (Hash-Table, CRS, SKS), but this function +is less efficient for CRS matrices. Hash-Table and SKS matrices can find +element in O(1) time, while CRS matrices need O(log(RS)) time, where RS +is an number of non-zero elements in a row. + +INPUT PARAMETERS + S - sparse M*N matrix + I - row index of the element to modify, 0<=I=0, "SparseExists: I<0", _state); + ae_assert(im, "SparseExists: I>=M", _state); + ae_assert(j>=0, "SparseExists: J<0", _state); + ae_assert(jn, "SparseExists: J>=N", _state); + result = ae_false; + if( s->matrixtype==0 ) + { + + /* + * Hash-based storage + */ + k = s->tablesize; + hashcode = sparse_hash(i, j, k, _state); + for(;;) + { + if( s->idx.ptr.p_int[2*hashcode]==-1 ) + { + return result; + } + if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) + { + result = ae_true; + return result; + } + hashcode = (hashcode+1)%k; + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseExists: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + k0 = s->ridx.ptr.p_int[i]; + k1 = s->ridx.ptr.p_int[i+1]-1; + while(k0<=k1) + { + k = (k0+k1)/2; + if( s->idx.ptr.p_int[k]==j ) + { + result = ae_true; + return result; + } + if( s->idx.ptr.p_int[k]matrixtype==2 ) + { + + /* + * SKS + */ + ae_assert(s->m==s->n, "SparseExists: non-square SKS matrix not supported", _state); + if( i==j ) + { + + /* + * Return diagonal element + */ + result = ae_true; + return result; + } + if( jdidx.ptr.p_int[i] ) + { + result = ae_true; + } + } + else + { + + /* + * Return superdiagonal element at J-th "skyline block" + */ + if( j-i<=s->uidx.ptr.p_int[j] ) + { + result = ae_true; + } + return result; + } + return result; + } + ae_assert(ae_false, "SparseExists: unexpected matrix type", _state); + return result; +} + + +/************************************************************************* +This function returns I-th diagonal element of the sparse matrix. + +Matrix can be in any mode (Hash-Table or CRS storage), but this function +is most efficient for CRS matrices - it requires less than 50 CPU cycles +to extract diagonal element. For Hash-Table matrices we still have O(1) +query time, but function is many times slower. + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + Exception will be thrown for CRS matrix. + I - index of the element to read, 0<=I=0, "SparseGetDiagonal: I<0", _state); + ae_assert(im, "SparseGetDiagonal: I>=M", _state); + ae_assert(in, "SparseGetDiagonal: I>=N", _state); + result = (double)(0); + if( s->matrixtype==0 ) + { + result = sparseget(s, i, i, _state); + return result; + } + if( s->matrixtype==1 ) + { + if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) + { + result = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; + } + return result; + } + if( s->matrixtype==2 ) + { + ae_assert(s->m==s->n, "SparseGetDiagonal: non-square SKS matrix not supported", _state); + result = s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]]; + return result; + } + ae_assert(ae_false, "SparseGetDiagonal: unexpected matrix type", _state); + return result; +} + + +/************************************************************************* +This function calculates matrix-vector product S*x. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y - array[M], S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemv(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + double tval; + double v; + double vv; + ae_int_t i; + ae_int_t j; + ae_int_t lt; + ae_int_t rt; + ae_int_t lt1; + ae_int_t rt1; + ae_int_t n; + ae_int_t m; + ae_int_t d; + ae_int_t u; + ae_int_t ri; + ae_int_t ri1; + + + ae_assert(x->cnt>=s->n, "SparseMV: length(X)matrixtype==1||s->matrixtype==2, "SparseMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + rvectorsetlengthatleast(y, s->m, _state); + n = s->n; + m = s->m; + if( s->matrixtype==1 ) + { + + /* + * CRS format. + * Perform integrity check. + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + + /* + * Try vendor kernels + */ + if( sparsegemvcrspbl(0, s->m, s->n, 1.0, &s->vals, &s->idx, &s->ridx, x, 0, 0.0, y, 0, _state) ) + { + return; + } + + /* + * Our own implementation + */ + for(i=0; i<=m-1; i++) + { + tval = (double)(0); + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]-1; + for(j=lt; j<=rt; j++) + { + tval = tval+x->ptr.p_double[s->idx.ptr.p_int[j]]*s->vals.ptr.p_double[j]; + } + y->ptr.p_double[i] = tval; + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseMV: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + v = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; + if( d>0 ) + { + lt = ri; + rt = ri+d-1; + lt1 = i-d; + rt1 = i-1; + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + v = v+vv; + } + y->ptr.p_double[i] = v; + if( u>0 ) + { + raddvx(u, x->ptr.p_double[i], &s->vals, ri1-u, y, i-u, _state); + } + } + touchint(&rt1, _state); + return; + } +} + + +/************************************************************************* +This function calculates matrix-vector product S^T*x. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + X - array[M], input vector. For performance reasons we + make only quick checks - we check that array size is + at least M, but we do not check for NAN's or INF's. + Y - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y - array[N], S^T*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemtv(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t lt; + ae_int_t rt; + ae_int_t ct; + ae_int_t lt1; + ae_int_t rt1; + double v; + double vv; + ae_int_t n; + ae_int_t m; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMTV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->m, "SparseMTV: Length(X)n; + m = s->m; + rvectorsetlengthatleast(y, n, _state); + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + * Perform integrity check. + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMTV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + + /* + * Try vendor kernels + */ + if( sparsegemvcrspbl(1, s->m, s->n, 1.0, &s->vals, &s->idx, &s->ridx, x, 0, 0.0, y, 0, _state) ) + { + return; + } + + /* + * Our own implementation + */ + for(i=0; i<=m-1; i++) + { + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + v = x->ptr.p_double[i]; + for(j=lt; j<=rt-1; j++) + { + ct = s->idx.ptr.p_int[j]; + y->ptr.p_double[ct] = y->ptr.p_double[ct]+v*s->vals.ptr.p_double[j]; + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseMV: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0 ) + { + lt = ri; + lt1 = i-d; + v = x->ptr.p_double[i]; + raddvx(d, v, &s->vals, lt, y, lt1, _state); + } + v = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; + if( u>0 ) + { + lt = ri1-u; + rt = ri1-1; + lt1 = i-u; + rt1 = i-1; + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + v = v+vv; + } + y->ptr.p_double[i] = v; + } + touchint(&rt1, _state); + return; + } +} + + +/************************************************************************* +This function calculates generalized sparse matrix-vector product + + y := alpha*op(S)*x + beta*y + +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). op(S) can be either S or S^T. + +NOTE: this function expects Y to be large enough to store result. No + automatic preallocation happens for smaller arrays. + +INPUT PARAMETERS + S - sparse matrix in CRS or SKS format. + Alpha - source coefficient + OpS - operation type: + * OpS=0 => op(S) = S + * OpS=1 => op(S) = S^T + X - input vector, must have at least Cols(op(S))+IX elements + IX - subvector offset + Beta - destination coefficient + Y - preallocated output array, must have at least Rows(op(S))+IY elements + IY - subvector offset + +OUTPUT PARAMETERS + Y - elements [IY...IY+Rows(op(S))-1] are replaced by result, + other elements are not modified + +HANDLING OF SPECIAL CASES: +* below M=Rows(op(S)) and N=Cols(op(S)). Although current ALGLIB version + does not allow you to create zero-sized sparse matrices, internally + ALGLIB can deal with such matrices. So, comments for M or N equal to + zero are for internal use only. +* if M=0, then subroutine does nothing. It does not even touch arrays. +* if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. S and X are not referenced at + all. Initial values of Y are ignored (we do not multiply Y by zero, + we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y +* if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by alpha*op(S)*x + initial state of Y is ignored (rewritten without initial multiplication + by zeros). + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 10.12.2019 by Bochkanov Sergey +*************************************************************************/ +void sparsegemv(const sparsematrix* s, + double alpha, + ae_int_t ops, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state) +{ + ae_int_t opm; + ae_int_t opn; + ae_int_t rawm; + ae_int_t rawn; + ae_int_t i; + ae_int_t j; + double tval; + ae_int_t lt; + ae_int_t rt; + ae_int_t ct; + ae_int_t d; + ae_int_t u; + ae_int_t ri; + ae_int_t ri1; + double v; + double vv; + ae_int_t lt1; + ae_int_t rt1; + + + ae_assert(ops==0||ops==1, "SparseGEMV: incorrect OpS", _state); + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseGEMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + if( ops==0 ) + { + opm = s->m; + opn = s->n; + } + else + { + opm = s->n; + opn = s->m; + } + ae_assert(opm>=0&&opn>=0, "SparseGEMV: op(S) has negative size", _state); + ae_assert(opn==0||x->cnt+ix>=opn, "SparseGEMV: X is too short", _state); + ae_assert(opm==0||y->cnt+iy>=opm, "SparseGEMV: X is too short", _state); + rawm = s->m; + rawn = s->n; + + /* + * Quick exit strategies + */ + if( opm==0 ) + { + return; + } + if( ae_fp_neq(beta,(double)(0)) ) + { + for(i=0; i<=opm-1; i++) + { + y->ptr.p_double[iy+i] = beta*y->ptr.p_double[iy+i]; + } + } + else + { + for(i=0; i<=opm-1; i++) + { + y->ptr.p_double[iy+i] = 0.0; + } + } + if( opn==0||ae_fp_eq(alpha,(double)(0)) ) + { + return; + } + + /* + * Now we have OpM>=1, OpN>=1, Alpha<>0 + */ + if( ops==0 ) + { + + /* + * Compute generalized product y := alpha*S*x + beta*y + * (with "beta*y" part already computed). + */ + if( s->matrixtype==1 ) + { + + /* + * CRS format. + * Perform integrity check. + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGEMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + + /* + * Try vendor kernels + */ + if( sparsegemvcrspbl(0, s->m, s->n, alpha, &s->vals, &s->idx, &s->ridx, x, ix, 1.0, y, iy, _state) ) + { + return; + } + + /* + * Our own implementation + */ + for(i=0; i<=rawm-1; i++) + { + tval = (double)(0); + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]-1; + for(j=lt; j<=rt; j++) + { + tval = tval+x->ptr.p_double[s->idx.ptr.p_int[j]+ix]*s->vals.ptr.p_double[j]; + } + y->ptr.p_double[i+iy] = alpha*tval+y->ptr.p_double[i+iy]; + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseMV: non-square SKS matrices are not supported", _state); + for(i=0; i<=rawn-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + v = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i+ix]; + if( d>0 ) + { + lt = ri; + rt = ri+d-1; + lt1 = i-d+ix; + rt1 = i-1+ix; + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + v = v+vv; + } + y->ptr.p_double[i+iy] = alpha*v+y->ptr.p_double[i+iy]; + if( u>0 ) + { + raddvx(u, alpha*x->ptr.p_double[i+ix], &s->vals, ri1-u, y, i-u+iy, _state); + } + } + touchint(&rt1, _state); + return; + } + } + else + { + + /* + * Compute generalized product y := alpha*S^T*x + beta*y + * (with "beta*y" part already computed). + */ + if( s->matrixtype==1 ) + { + + /* + * CRS format + * Perform integrity check. + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGEMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + + /* + * Try vendor kernels + */ + if( sparsegemvcrspbl(1, s->m, s->n, alpha, &s->vals, &s->idx, &s->ridx, x, ix, 1.0, y, iy, _state) ) + { + return; + } + + /* + * Our own implementation + */ + for(i=0; i<=rawm-1; i++) + { + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + v = alpha*x->ptr.p_double[i+ix]; + for(j=lt; j<=rt-1; j++) + { + ct = s->idx.ptr.p_int[j]+iy; + y->ptr.p_double[ct] = y->ptr.p_double[ct]+v*s->vals.ptr.p_double[j]; + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseGEMV: non-square SKS matrices are not supported", _state); + for(i=0; i<=rawn-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0 ) + { + raddvx(d, alpha*x->ptr.p_double[i+ix], &s->vals, ri, y, i-d+iy, _state); + } + v = alpha*s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i+ix]; + if( u>0 ) + { + lt = ri1-u; + rt = ri1-1; + lt1 = i-u+ix; + rt1 = i-1+ix; + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + v = v+alpha*vv; + } + y->ptr.p_double[i+iy] = v+y->ptr.p_double[i+iy]; + } + touchint(&rt1, _state); + return; + } + } +} + + +/************************************************************************* +This function simultaneously calculates two matrix-vector products: + S*x and S^T*x. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + Y1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y0 - array[N], S*x + Y1 - array[N], S^T*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemv2(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y0, + /* Real */ ae_vector* y1, + ae_state *_state) +{ + ae_int_t l; + double tval; + ae_int_t i; + ae_int_t j; + double vx; + double vs; + double v; + double vv; + double vd0; + double vd1; + ae_int_t vi; + ae_int_t j0; + ae_int_t j1; + ae_int_t n; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + ae_int_t lt; + ae_int_t rt; + ae_int_t lt1; + ae_int_t rt1; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMV2: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(s->m==s->n, "SparseMV2: matrix is non-square", _state); + l = x->cnt; + ae_assert(l>=s->n, "SparseMV2: Length(X)n; + rvectorsetlengthatleast(y0, l, _state); + rvectorsetlengthatleast(y1, l, _state); + for(i=0; i<=n-1; i++) + { + y0->ptr.p_double[i] = (double)(0); + y1->ptr.p_double[i] = (double)(0); + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMV2: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=s->m-1; i++) + { + tval = (double)(0); + vx = x->ptr.p_double[i]; + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + vi = s->idx.ptr.p_int[j]; + vs = s->vals.ptr.p_double[j]; + tval = tval+x->ptr.p_double[vi]*vs; + y1->ptr.p_double[vi] = y1->ptr.p_double[vi]+vx*vs; + } + y0->ptr.p_double[i] = tval; + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + vd0 = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; + vd1 = vd0; + if( d>0 ) + { + lt = ri; + rt = ri+d-1; + lt1 = i-d; + rt1 = i-1; + v = x->ptr.p_double[i]; + ae_v_addd(&y1->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + vd0 = vd0+vv; + } + if( u>0 ) + { + lt = ri1-u; + rt = ri1-1; + lt1 = i-u; + rt1 = i-1; + v = x->ptr.p_double[i]; + ae_v_addd(&y0->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + vd1 = vd1+vv; + } + y0->ptr.p_double[i] = vd0; + y1->ptr.p_double[i] = vd1; + } + return; + } +} + + +/************************************************************************* +This function calculates matrix-vector product S*x, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y - array[M], S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmv(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t id; + ae_int_t lt; + ae_int_t rt; + double v; + double vv; + double vy; + double vx; + double vd; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + ae_int_t lt1; + ae_int_t rt1; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseSMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->n, "SparseSMV: length(X)m==s->n, "SparseSMV: non-square matrix", _state); + n = s->n; + rvectorsetlengthatleast(y, n, _state); + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=n-1; i++) + { + if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->vals.ptr.p_double[s->didx.ptr.p_int[i]]*x->ptr.p_double[s->idx.ptr.p_int[s->didx.ptr.p_int[i]]]; + } + if( isupper ) + { + lt = s->uidx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + vy = (double)(0); + vx = x->ptr.p_double[i]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v = s->vals.ptr.p_double[j]; + vy = vy+x->ptr.p_double[id]*v; + y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; + } + y->ptr.p_double[i] = y->ptr.p_double[i]+vy; + } + else + { + lt = s->ridx.ptr.p_int[i]; + rt = s->didx.ptr.p_int[i]; + vy = (double)(0); + vx = x->ptr.p_double[i]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v = s->vals.ptr.p_double[j]; + vy = vy+x->ptr.p_double[id]*v; + y->ptr.p_double[id] = y->ptr.p_double[id]+vx*v; + } + y->ptr.p_double[i] = y->ptr.p_double[i]+vy; + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + vd = s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; + if( d>0&&!isupper ) + { + lt = ri; + rt = ri+d-1; + lt1 = i-d; + rt1 = i-1; + v = x->ptr.p_double[i]; + ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + vd = vd+vv; + } + if( u>0&&isupper ) + { + lt = ri1-u; + rt = ri1-1; + lt1 = i-u; + rt1 = i-1; + v = x->ptr.p_double[i]; + ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + vv = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + vd = vd+vv; + } + y->ptr.p_double[i] = vd; + } + return; + } +} + + +/************************************************************************* +This function perform in-place multiplication of the matrix columns by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[N], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplycolsby(sparsematrix* s, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + + + ae_assert(s->matrixtype==1, "SparseMultiplyColsBy: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->n, "SparseMultiplyColsBy: length(X)ninitialized==s->ridx.ptr.p_int[s->m], "SparseMultiplyColsBy: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=s->m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + s->vals.ptr.p_double[jj] = s->vals.ptr.p_double[jj]*x->ptr.p_double[s->idx.ptr.p_int[jj]]; + } + } +} + + +/************************************************************************* +This function perform in-place multiplication of the matrix rows by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowsby(sparsematrix* s, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + + + ae_assert(s->matrixtype==1, "SparseMultiplyColsBy: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->m, "SparseMultiplyColsBy: length(X)ninitialized==s->ridx.ptr.p_int[s->m], "SparseMultiplyColsBy: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=s->m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + s->vals.ptr.p_double[jj] = s->vals.ptr.p_double[jj]*x->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function perform in-place multiplication of the matrix rows and cols +by user-supplied vectors X and Y. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], row multipliers + Y - array[N], column multipliers + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left, and by + diag(Y) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowscolsby(sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + double v; + + + ae_assert(s->matrixtype==1, "SparseMultiplyRowsColsBy: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->m, "SparseMultiplyRowsColsBy: length(X)cnt>=s->n, "SparseMultiplyRowsColsBy: length(Y)ninitialized==s->ridx.ptr.p_int[s->m], "SparseMultiplyRowsColsBy: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=s->m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + v = x->ptr.p_double[i]; + for(jj=j0; jj<=j1; jj++) + { + s->vals.ptr.p_double[jj] = s->vals.ptr.p_double[jj]*v*y->ptr.p_double[s->idx.ptr.p_int[jj]]; + } + } +} + + +/************************************************************************* +This function calculates vector-matrix-vector product x'*S*x, where S is +symmetric matrix. Matrix S must be stored in CRS or SKS format (exception +will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + +RESULT + x'*S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 27.01.2014 by Bochkanov Sergey +*************************************************************************/ +double sparsevsmv(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t id; + ae_int_t lt; + ae_int_t rt; + double v; + double v0; + double v1; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + ae_int_t lt1; + double result; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseVSMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(x->cnt>=s->n, "SparseVSMV: length(X)m==s->n, "SparseVSMV: non-square matrix", _state); + n = s->n; + result = 0.0; + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseVSMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=n-1; i++) + { + if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) + { + v = x->ptr.p_double[s->idx.ptr.p_int[s->didx.ptr.p_int[i]]]; + result = result+v*s->vals.ptr.p_double[s->didx.ptr.p_int[i]]*v; + } + if( isupper ) + { + lt = s->uidx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + } + else + { + lt = s->ridx.ptr.p_int[i]; + rt = s->didx.ptr.p_int[i]; + } + v0 = x->ptr.p_double[i]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v1 = x->ptr.p_double[id]; + v = s->vals.ptr.p_double[j]; + result = result+(double)2*v0*v1*v; + } + } + return result; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + v = x->ptr.p_double[i]; + result = result+v*s->vals.ptr.p_double[ri+d]*v; + if( d>0&&!isupper ) + { + lt = ri; + lt1 = i-d; + k = d-1; + v0 = x->ptr.p_double[i]; + v = 0.0; + for(j=0; j<=k; j++) + { + v = v+x->ptr.p_double[lt1+j]*s->vals.ptr.p_double[lt+j]; + } + result = result+2.0*v0*v; + } + if( u>0&&isupper ) + { + lt = ri1-u; + lt1 = i-u; + k = u-1; + v0 = x->ptr.p_double[i]; + v = 0.0; + for(j=0; j<=k; j++) + { + v = v+x->ptr.p_double[lt1+j]*s->vals.ptr.p_double[lt+j]; + } + result = result+2.0*v0*v; + } + } + return result; + } + return result; +} + + +/************************************************************************* +This function calculates matrix-matrix product S*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size + is at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state) +{ + double tval; + double v; + ae_int_t id; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t lt; + ae_int_t rt; + ae_int_t m; + ae_int_t n; + ae_int_t ri; + ae_int_t ri1; + ae_int_t lt1; + ae_int_t rt1; + ae_int_t d; + ae_int_t u; + double vd; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(a->rows>=s->n, "SparseMM: Rows(A)0, "SparseMM: K<=0", _state); + m = s->m; + n = s->n; + k1 = k-1; + rmatrixsetlengthatleast(b, m, k, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=k-1; j++) + { + b->ptr.pp_double[i][j] = (double)(0); + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( kridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(k0=lt; k0<=rt-1; k0++) + { + tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[s->idx.ptr.p_int[k0]][j]; + } + b->ptr.pp_double[i][j] = tval; + } + } + } + else + { + for(i=0; i<=m-1; i++) + { + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v = s->vals.ptr.p_double[j]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); + } + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(m==n, "SparseMM: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0 ) + { + lt = ri; + lt1 = i-d; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + } + } + } + if( u>0 ) + { + lt = ri1-u; + lt1 = i-u; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + vd = s->vals.ptr.p_double[ri+d]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), vd); + } + return; + } +} + + +/************************************************************************* +This function calculates matrix-matrix product S^T*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[M][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least M, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemtm(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t lt; + ae_int_t rt; + ae_int_t ct; + double v; + ae_int_t m; + ae_int_t n; + ae_int_t ri; + ae_int_t ri1; + ae_int_t lt1; + ae_int_t rt1; + ae_int_t d; + ae_int_t u; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMTM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(a->rows>=s->m, "SparseMTM: Rows(A)0, "SparseMTM: K<=0", _state); + m = s->m; + n = s->n; + k1 = k-1; + rmatrixsetlengthatleast(b, n, k, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + b->ptr.pp_double[i][j] = (double)(0); + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[m], "SparseMTM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( kridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(k0=lt; k0<=rt-1; k0++) + { + v = s->vals.ptr.p_double[k0]; + ct = s->idx.ptr.p_int[k0]; + for(j=0; j<=k-1; j++) + { + b->ptr.pp_double[ct][j] = b->ptr.pp_double[ct][j]+v*a->ptr.pp_double[i][j]; + } + } + } + } + else + { + for(i=0; i<=m-1; i++) + { + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(j=lt; j<=rt-1; j++) + { + v = s->vals.ptr.p_double[j]; + ct = s->idx.ptr.p_int[j]; + ae_v_addd(&b->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(m==n, "SparseMTM: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0 ) + { + lt = ri; + lt1 = i-d; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + if( u>0 ) + { + lt = ri1-u; + lt1 = i-u; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + } + } + } + v = s->vals.ptr.p_double[ri+d]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + return; + } +} + + +/************************************************************************* +This function simultaneously calculates two matrix-matrix products: + S*A and S^T*A. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + B1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B0 - array[N][K], S*A + B1 - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm2(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b0, + /* Real */ ae_matrix* b1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t lt; + ae_int_t rt; + ae_int_t ct; + double v; + double tval; + ae_int_t n; + ae_int_t k1; + ae_int_t ri; + ae_int_t ri1; + ae_int_t lt1; + ae_int_t rt1; + ae_int_t d; + ae_int_t u; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseMM2: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(s->m==s->n, "SparseMM2: matrix is non-square", _state); + ae_assert(a->rows>=s->n, "SparseMM2: Rows(A)0, "SparseMM2: K<=0", _state); + n = s->n; + k1 = k-1; + rmatrixsetlengthatleast(b0, n, k, _state); + rmatrixsetlengthatleast(b1, n, k, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + b1->ptr.pp_double[i][j] = (double)(0); + b0->ptr.pp_double[i][j] = (double)(0); + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseMM2: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( kridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + v = a->ptr.pp_double[i][j]; + for(k0=lt; k0<=rt-1; k0++) + { + ct = s->idx.ptr.p_int[k0]; + b1->ptr.pp_double[ct][j] = b1->ptr.pp_double[ct][j]+s->vals.ptr.p_double[k0]*v; + tval = tval+s->vals.ptr.p_double[k0]*a->ptr.pp_double[ct][j]; + } + b0->ptr.pp_double[i][j] = tval; + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + lt = s->ridx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(j=lt; j<=rt-1; j++) + { + v = s->vals.ptr.p_double[j]; + ct = s->idx.ptr.p_int[j]; + ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[ct][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b1->ptr.pp_double[ct][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseMM2: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0 ) + { + lt = ri; + lt1 = i-d; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[i][k0] = b0->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + b1->ptr.pp_double[j][k0] = b1->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b1->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + if( u>0 ) + { + lt = ri1-u; + lt1 = i-u; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[j][k0] = b0->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + b1->ptr.pp_double[i][k0] = b1->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b0->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b1->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + } + } + } + v = s->vals.ptr.p_double[ri+d]; + ae_v_addd(&b0->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b1->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + return; + } +} + + +/************************************************************************* +This function calculates matrix-matrix product S*A, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmm(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t id; + ae_int_t k1; + ae_int_t lt; + ae_int_t rt; + double v; + double vb; + double va; + ae_int_t n; + ae_int_t ri; + ae_int_t ri1; + ae_int_t lt1; + ae_int_t rt1; + ae_int_t d; + ae_int_t u; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseSMM: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(a->rows>=s->n, "SparseSMM: Rows(X)m==s->n, "SparseSMM: matrix is non-square", _state); + n = s->n; + k1 = k-1; + rmatrixsetlengthatleast(b, n, k, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + b->ptr.pp_double[i][j] = (double)(0); + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseSMM: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( k>sparse_linalgswitch ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) + { + id = s->didx.ptr.p_int[i]; + b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+s->vals.ptr.p_double[id]*a->ptr.pp_double[s->idx.ptr.p_int[id]][j]; + } + if( isupper ) + { + lt = s->uidx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + vb = (double)(0); + va = a->ptr.pp_double[i][j]; + for(k0=lt; k0<=rt-1; k0++) + { + id = s->idx.ptr.p_int[k0]; + v = s->vals.ptr.p_double[k0]; + vb = vb+a->ptr.pp_double[id][j]*v; + b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; + } + b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; + } + else + { + lt = s->ridx.ptr.p_int[i]; + rt = s->didx.ptr.p_int[i]; + vb = (double)(0); + va = a->ptr.pp_double[i][j]; + for(k0=lt; k0<=rt-1; k0++) + { + id = s->idx.ptr.p_int[k0]; + v = s->vals.ptr.p_double[k0]; + vb = vb+a->ptr.pp_double[id][j]*v; + b->ptr.pp_double[id][j] = b->ptr.pp_double[id][j]+va*v; + } + b->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]+vb; + } + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + if( s->didx.ptr.p_int[i]!=s->uidx.ptr.p_int[i] ) + { + id = s->didx.ptr.p_int[i]; + v = s->vals.ptr.p_double[id]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[s->idx.ptr.p_int[id]][0], 1, ae_v_len(0,k-1), v); + } + if( isupper ) + { + lt = s->uidx.ptr.p_int[i]; + rt = s->ridx.ptr.p_int[i+1]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v = s->vals.ptr.p_double[j]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + else + { + lt = s->ridx.ptr.p_int[i]; + rt = s->didx.ptr.p_int[i]; + for(j=lt; j<=rt-1; j++) + { + id = s->idx.ptr.p_int[j]; + v = s->vals.ptr.p_double[j]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[id][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b->ptr.pp_double[id][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseMM2: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( d>0&&!isupper ) + { + lt = ri; + lt1 = i-d; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + b->ptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + } + } + if( u>0&&isupper ) + { + lt = ri1-u; + lt1 = i-u; + rt1 = i-1; + for(j=lt1; j<=rt1; j++) + { + v = s->vals.ptr.p_double[lt+(j-lt1)]; + if( kptr.pp_double[j][k0] = b->ptr.pp_double[j][k0]+v*a->ptr.pp_double[i][k0]; + b->ptr.pp_double[i][k0] = b->ptr.pp_double[i][k0]+v*a->ptr.pp_double[j][k0]; + } + } + else + { + + /* + * Use vector operation + */ + ae_v_addd(&b->ptr.pp_double[j][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v); + } + } + } + v = s->vals.ptr.p_double[ri+d]; + ae_v_addd(&b->ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v); + } + return; + } +} + + +/************************************************************************* +This function calculates matrix-vector product op(S)*x, when x is vector, +S is symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + Y - possibly preallocated input buffer. Automatically + resized if its size is too small. + +OUTPUT PARAMETERS + Y - array[N], op(S)*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrmv(const sparsematrix* s, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + ae_int_t lt; + ae_int_t rt; + ae_int_t lt1; + ae_int_t rt1; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseTRMV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(optype==0||optype==1, "SparseTRMV: incorrect operation type (must be 0 or 1)", _state); + ae_assert(x->cnt>=s->n, "SparseTRMV: Length(X)m==s->n, "SparseTRMV: matrix is non-square", _state); + n = s->n; + rvectorsetlengthatleast(y, n, _state); + if( isunit ) + { + + /* + * Set initial value of y to x + */ + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = x->ptr.p_double[i]; + } + } + else + { + + /* + * Set initial value of y to 0 + */ + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + } + if( s->matrixtype==1 ) + { + + /* + * CRS format + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseTRMV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + for(i=0; i<=n-1; i++) + { + + /* + * Depending on IsUpper/IsUnit, select range of indexes to process + */ + if( isupper ) + { + if( isunit||s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) + { + j0 = s->uidx.ptr.p_int[i]; + } + else + { + j0 = s->didx.ptr.p_int[i]; + } + j1 = s->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = s->ridx.ptr.p_int[i]; + if( isunit||s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) + { + j1 = s->didx.ptr.p_int[i]-1; + } + else + { + j1 = s->didx.ptr.p_int[i]; + } + } + + /* + * Depending on OpType, process subset of I-th row of input matrix + */ + if( optype==0 ) + { + v = 0.0; + for(j=j0; j<=j1; j++) + { + v = v+s->vals.ptr.p_double[j]*x->ptr.p_double[s->idx.ptr.p_int[j]]; + } + y->ptr.p_double[i] = y->ptr.p_double[i]+v; + } + else + { + v = x->ptr.p_double[i]; + for(j=j0; j<=j1; j++) + { + k = s->idx.ptr.p_int[j]; + y->ptr.p_double[k] = y->ptr.p_double[k]+v*s->vals.ptr.p_double[j]; + } + } + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseTRMV: non-square SKS matrices are not supported", _state); + for(i=0; i<=n-1; i++) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( !isunit ) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+s->vals.ptr.p_double[ri+d]*x->ptr.p_double[i]; + } + if( d>0&&!isupper ) + { + lt = ri; + rt = ri+d-1; + lt1 = i-d; + rt1 = i-1; + if( optype==0 ) + { + v = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + y->ptr.p_double[i] = y->ptr.p_double[i]+v; + } + else + { + v = x->ptr.p_double[i]; + ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + } + } + if( u>0&&isupper ) + { + lt = ri1-u; + rt = ri1-1; + lt1 = i-u; + rt1 = i-1; + if( optype==0 ) + { + v = x->ptr.p_double[i]; + ae_v_addd(&y->ptr.p_double[lt1], 1, &s->vals.ptr.p_double[lt], 1, ae_v_len(lt1,rt1), v); + } + else + { + v = ae_v_dotproduct(&s->vals.ptr.p_double[lt], 1, &x->ptr.p_double[lt1], 1, ae_v_len(lt,rt)); + y->ptr.p_double[i] = y->ptr.p_double[i]+v; + } + } + } + return; + } +} + + +/************************************************************************* +This function solves linear system op(S)*y=x where x is vector, S is +symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used. It is your + responsibility to make sure that diagonal is + non-zero. + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + +OUTPUT PARAMETERS + X - array[N], inv(op(S))*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. + You must convert your matrix with SparseConvertToCRS/SKS() before + using this function. + +NOTE: no assertion or tests are done during algorithm operation. It is + your responsibility to provide invertible matrix to algorithm. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrsv(const sparsematrix* s, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t fst; + ae_int_t lst; + ae_int_t stp; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vd; + double v0; + ae_int_t j0; + ae_int_t j1; + ae_int_t ri; + ae_int_t ri1; + ae_int_t d; + ae_int_t u; + ae_int_t lt; + ae_int_t lt1; + + + ae_assert(s->matrixtype==1||s->matrixtype==2, "SparseTRSV: incorrect matrix type (convert your matrix to CRS/SKS)", _state); + ae_assert(optype==0||optype==1, "SparseTRSV: incorrect operation type (must be 0 or 1)", _state); + ae_assert(x->cnt>=s->n, "SparseTRSV: Length(X)m==s->n, "SparseTRSV: matrix is non-square", _state); + n = s->n; + if( s->matrixtype==1 ) + { + + /* + * CRS format. + * + * Several branches for different combinations of IsUpper and OpType + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseTRSV: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( optype==0 ) + { + + /* + * No transposition. + * + * S*x=y with upper or lower triangular S. + */ + v0 = (double)(0); + if( isupper ) + { + fst = n-1; + lst = 0; + stp = -1; + } + else + { + fst = 0; + lst = n-1; + stp = 1; + } + i = fst; + while((stp>0&&i<=lst)||(stp<0&&i>=lst)) + { + + /* + * Select range of indexes to process + */ + if( isupper ) + { + j0 = s->uidx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->didx.ptr.p_int[i]-1; + } + + /* + * Calculate X[I] + */ + v = 0.0; + for(j=j0; j<=j1; j++) + { + v = v+s->vals.ptr.p_double[j]*x->ptr.p_double[s->idx.ptr.p_int[j]]; + } + if( !isunit ) + { + if( s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) + { + vd = (double)(0); + } + else + { + vd = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; + } + } + else + { + vd = 1.0; + } + v = (x->ptr.p_double[i]-v)/vd; + x->ptr.p_double[i] = v; + v0 = 0.25*v0+v; + + /* + * Next I + */ + i = i+stp; + } + ae_assert(ae_isfinite(v0, _state), "SparseTRSV: overflow or division by exact zero", _state); + return; + } + if( optype==1 ) + { + + /* + * Transposition. + * + * (S^T)*x=y with upper or lower triangular S. + */ + if( isupper ) + { + fst = 0; + lst = n-1; + stp = 1; + } + else + { + fst = n-1; + lst = 0; + stp = -1; + } + i = fst; + v0 = (double)(0); + while((stp>0&&i<=lst)||(stp<0&&i>=lst)) + { + v = x->ptr.p_double[i]; + if( v!=0.0 ) + { + + /* + * X[i] already stores A[i,i]*Y[i], the only thing left + * is to divide by diagonal element. + */ + if( !isunit ) + { + if( s->didx.ptr.p_int[i]==s->uidx.ptr.p_int[i] ) + { + vd = (double)(0); + } + else + { + vd = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; + } + } + else + { + vd = 1.0; + } + v = v/vd; + x->ptr.p_double[i] = v; + v0 = 0.25*v0+v; + + /* + * For upper triangular case: + * subtract X[i]*Ai from X[i+1:N-1] + * + * For lower triangular case: + * subtract X[i]*Ai from X[0:i-1] + * + * (here Ai is I-th row of original, untransposed A). + */ + if( isupper ) + { + j0 = s->uidx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->didx.ptr.p_int[i]-1; + } + for(j=j0; j<=j1; j++) + { + k = s->idx.ptr.p_int[j]; + x->ptr.p_double[k] = x->ptr.p_double[k]-s->vals.ptr.p_double[j]*v; + } + } + + /* + * Next I + */ + i = i+stp; + } + ae_assert(ae_isfinite(v0, _state), "SparseTRSV: overflow or division by exact zero", _state); + return; + } + ae_assert(ae_false, "SparseTRSV: internal error", _state); + } + if( s->matrixtype==2 ) + { + + /* + * SKS format + */ + ae_assert(s->m==s->n, "SparseTRSV: non-square SKS matrices are not supported", _state); + if( (optype==0&&!isupper)||(optype==1&&isupper) ) + { + + /* + * Lower triangular op(S) (matrix itself can be upper triangular). + */ + v0 = (double)(0); + for(i=0; i<=n-1; i++) + { + + /* + * Select range of indexes to process + */ + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + if( isupper ) + { + lt = i-u; + lt1 = ri1-u; + k = u-1; + } + else + { + lt = i-d; + lt1 = ri; + k = d-1; + } + + /* + * Calculate X[I] + */ + v = 0.0; + for(j=0; j<=k; j++) + { + v = v+s->vals.ptr.p_double[lt1+j]*x->ptr.p_double[lt+j]; + } + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = s->vals.ptr.p_double[ri+d]; + } + v = (x->ptr.p_double[i]-v)/vd; + x->ptr.p_double[i] = v; + v0 = 0.25*v0+v; + } + ae_assert(ae_isfinite(v0, _state), "SparseTRSV: overflow or division by exact zero", _state); + return; + } + if( (optype==1&&!isupper)||(optype==0&&isupper) ) + { + + /* + * Upper triangular op(S) (matrix itself can be lower triangular). + */ + v0 = (double)(0); + for(i=n-1; i>=0; i--) + { + ri = s->ridx.ptr.p_int[i]; + ri1 = s->ridx.ptr.p_int[i+1]; + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + + /* + * X[i] already stores A[i,i]*Y[i], the only thing left + * is to divide by diagonal element. + */ + if( isunit ) + { + vd = (double)(1); + } + else + { + vd = s->vals.ptr.p_double[ri+d]; + } + v = x->ptr.p_double[i]/vd; + x->ptr.p_double[i] = v; + v0 = 0.25*v0+v; + + /* + * Subtract product of X[i] and I-th column of "effective" A from + * unprocessed variables. + */ + v = x->ptr.p_double[i]; + if( isupper ) + { + lt = i-u; + lt1 = ri1-u; + k = u-1; + } + else + { + lt = i-d; + lt1 = ri; + k = d-1; + } + for(j=0; j<=k; j++) + { + x->ptr.p_double[lt+j] = x->ptr.p_double[lt+j]-v*s->vals.ptr.p_double[lt1+j]; + } + } + ae_assert(ae_isfinite(v0, _state), "SparseTRSV: overflow or division by exact zero", _state); + return; + } + ae_assert(ae_false, "SparseTRSV: internal error", _state); + } + ae_assert(ae_false, "SparseTRSV: internal error", _state); +} + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblBuf() if you want to reuse already allocated structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbl(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + + _sparsematrix_clear(b); + + sparsesymmpermtblbuf(a, isupper, p, b, _state); +} + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblTransposeBuf() if you want to reuse an already allocated +structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltranspose(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + + _sparsematrix_clear(b); + + sparsesymmpermtbltransposebuf(a, isupper, p, b, _state); +} + + +/************************************************************************* +This function is a buffered version of SparseSymmPermTbl() that reuses +previously allocated storage in B as much as possible. + +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtblbuf(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k0; + ae_int_t k1; + ae_int_t kk; + ae_int_t n; + ae_int_t dst; + ae_bool bflag; + + + ae_assert(a->matrixtype==1, "SparseSymmPermTblBuf: incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(p->cnt>=a->n, "SparseSymmPermTblBuf: Length(P)m==a->n, "SparseSymmPermTblBuf: matrix is non-square", _state); + bflag = ae_true; + for(i=0; i<=a->n-1; i++) + { + bflag = (bflag&&p->ptr.p_int[i]>=0)&&p->ptr.p_int[i]n; + } + ae_assert(bflag, "SparseSymmPermTblBuf: P[] contains values outside of [0,N) range", _state); + n = a->n; + + /* + * Prepare output + */ + ae_assert(a->ninitialized==a->ridx.ptr.p_int[n], "SparseSymmPermTblBuf: integrity check failed", _state); + b->matrixtype = 1; + b->n = n; + b->m = n; + ivectorsetlengthatleast(&b->didx, n, _state); + ivectorsetlengthatleast(&b->uidx, n, _state); + + /* + * Determine row sizes (temporary stored in DIdx) and ranges + */ + isetv(n, 0, &b->didx, _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = a->didx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + k0 = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + k1 = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + if( k1didx.ptr.p_int[k1] = b->didx.ptr.p_int[k1]+1; + } + else + { + b->didx.ptr.p_int[k0] = b->didx.ptr.p_int[k0]+1; + } + } + } + else + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + k0 = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + k1 = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + if( k1>k0 ) + { + b->didx.ptr.p_int[k1] = b->didx.ptr.p_int[k1]+1; + } + else + { + b->didx.ptr.p_int[k0] = b->didx.ptr.p_int[k0]+1; + } + } + } + } + ivectorsetlengthatleast(&b->ridx, n+1, _state); + b->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + b->ridx.ptr.p_int[i+1] = b->ridx.ptr.p_int[i]+b->didx.ptr.p_int[i]; + } + b->ninitialized = b->ridx.ptr.p_int[n]; + ivectorsetlengthatleast(&b->idx, b->ninitialized, _state); + rvectorsetlengthatleast(&b->vals, b->ninitialized, _state); + + /* + * Process matrix + */ + for(i=0; i<=n-1; i++) + { + b->uidx.ptr.p_int[i] = b->ridx.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = a->didx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + k0 = p->ptr.p_int[i]; + k1 = p->ptr.p_int[j]; + if( k1uidx.ptr.p_int[k0]; + b->idx.ptr.p_int[dst] = k1; + b->vals.ptr.p_double[dst] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[k0] = dst+1; + } + } + else + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + k0 = p->ptr.p_int[i]; + k1 = p->ptr.p_int[j]; + if( k1>k0 ) + { + kk = k0; + k0 = k1; + k1 = kk; + } + dst = b->uidx.ptr.p_int[k0]; + b->idx.ptr.p_int[dst] = k1; + b->vals.ptr.p_double[dst] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[k0] = dst+1; + } + } + } + + /* + * Finalize matrix + */ + for(i=0; i<=n-1; i++) + { + tagsortmiddleir(&b->idx, &b->vals, b->ridx.ptr.p_int[i], b->ridx.ptr.p_int[i+1]-b->ridx.ptr.p_int[i], _state); + } + sparseinitduidx(b, _state); +} + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function reuses memory already allocated in B as much as possible. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltransposebuf(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k0; + ae_int_t k1; + ae_int_t kk; + ae_int_t n; + ae_int_t dst; + ae_bool bflag; + + + ae_assert(a->matrixtype==1, "SparseSymmPermTblBuf: incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(p->cnt>=a->n, "SparseSymmPermTblBuf: Length(P)m==a->n, "SparseSymmPermTblBuf: matrix is non-square", _state); + bflag = ae_true; + for(i=0; i<=a->n-1; i++) + { + bflag = (bflag&&p->ptr.p_int[i]>=0)&&p->ptr.p_int[i]n; + } + ae_assert(bflag, "SparseSymmPermTblBuf: P[] contains values outside of [0,N) range", _state); + n = a->n; + + /* + * Prepare output + */ + ae_assert(a->ninitialized==a->ridx.ptr.p_int[n], "SparseSymmPermTblBuf: integrity check failed", _state); + b->matrixtype = 1; + b->n = n; + b->m = n; + ivectorsetlengthatleast(&b->didx, n, _state); + ivectorsetlengthatleast(&b->uidx, n, _state); + + /* + * Determine row sizes (temporary stored in DIdx) and ranges + */ + isetv(n, 0, &b->didx, _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = a->didx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + k0 = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + k1 = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + if( k1>k0 ) + { + b->didx.ptr.p_int[k1] = b->didx.ptr.p_int[k1]+1; + } + else + { + b->didx.ptr.p_int[k0] = b->didx.ptr.p_int[k0]+1; + } + } + } + else + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + k0 = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + k1 = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + if( k1didx.ptr.p_int[k1] = b->didx.ptr.p_int[k1]+1; + } + else + { + b->didx.ptr.p_int[k0] = b->didx.ptr.p_int[k0]+1; + } + } + } + } + ivectorsetlengthatleast(&b->ridx, n+1, _state); + b->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + b->ridx.ptr.p_int[i+1] = b->ridx.ptr.p_int[i]+b->didx.ptr.p_int[i]; + } + b->ninitialized = b->ridx.ptr.p_int[n]; + ivectorsetlengthatleast(&b->idx, b->ninitialized, _state); + rvectorsetlengthatleast(&b->vals, b->ninitialized, _state); + + /* + * Process the matrix + */ + for(i=0; i<=n-1; i++) + { + b->uidx.ptr.p_int[i] = b->ridx.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = a->didx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + k0 = p->ptr.p_int[i]; + k1 = p->ptr.p_int[j]; + if( k1>k0 ) + { + kk = k0; + k0 = k1; + k1 = kk; + } + dst = b->uidx.ptr.p_int[k0]; + b->idx.ptr.p_int[dst] = k1; + b->vals.ptr.p_double[dst] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[k0] = dst+1; + } + } + else + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + k0 = p->ptr.p_int[i]; + k1 = p->ptr.p_int[j]; + if( k1uidx.ptr.p_int[k0]; + b->idx.ptr.p_int[dst] = k1; + b->vals.ptr.p_double[dst] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[k0] = dst+1; + } + } + } + + /* + * Finalize matrix + */ + for(i=0; i<=n-1; i++) + { + tagsortmiddleir(&b->idx, &b->vals, b->ridx.ptr.p_int[i], b->ridx.ptr.p_int[i+1]-b->ridx.ptr.p_int[i], _state); + } + sparseinitduidx(b, _state); +} + + +/************************************************************************* +This procedure resizes Hash-Table matrix. It can be called when you have +deleted too many elements from the matrix, and you want to free unneeded +memory. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseresizematrix(sparsematrix* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t k; + ae_int_t k1; + ae_int_t i; + ae_vector tvals; + ae_vector tidx; + + ae_frame_make(_state, &_frame_block); + memset(&tvals, 0, sizeof(tvals)); + memset(&tidx, 0, sizeof(tidx)); + ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); + + ae_assert(s->matrixtype==0, "SparseResizeMatrix: incorrect matrix type", _state); + + /* + * Initialization for length and number of non-null elementd + */ + k = s->tablesize; + k1 = 0; + + /* + * Calculating number of non-null elements + */ + for(i=0; i<=k-1; i++) + { + if( s->idx.ptr.p_int[2*i]>=0 ) + { + k1 = k1+1; + } + } + + /* + * Initialization value for free space + */ + s->tablesize = ae_round((double)k1/sparse_desiredloadfactor*sparse_growfactor+(double)sparse_additional, _state); + s->nfree = s->tablesize-k1; + ae_vector_set_length(&tvals, s->tablesize, _state); + ae_vector_set_length(&tidx, 2*s->tablesize, _state); + ae_swap_vectors(&s->vals, &tvals); + ae_swap_vectors(&s->idx, &tidx); + for(i=0; i<=s->tablesize-1; i++) + { + s->idx.ptr.p_int[2*i] = -1; + } + for(i=0; i<=k-1; i++) + { + if( tidx.ptr.p_int[2*i]>=0 ) + { + sparseset(s, tidx.ptr.p_int[2*i], tidx.ptr.p_int[2*i+1], tvals.ptr.p_double[i], _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function return average length of chain at hash-table. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +double sparsegetaveragelengthofchain(const sparsematrix* s, + ae_state *_state) +{ + ae_int_t nchains; + ae_int_t talc; + ae_int_t l; + ae_int_t i; + ae_int_t ind0; + ae_int_t ind1; + ae_int_t hashcode; + double result; + + + + /* + * If matrix represent in CRS then return zero and exit + */ + if( s->matrixtype!=0 ) + { + result = (double)(0); + return result; + } + nchains = 0; + talc = 0; + l = s->tablesize; + for(i=0; i<=l-1; i++) + { + ind0 = 2*i; + if( s->idx.ptr.p_int[ind0]!=-1 ) + { + nchains = nchains+1; + hashcode = sparse_hash(s->idx.ptr.p_int[ind0], s->idx.ptr.p_int[ind0+1], l, _state); + for(;;) + { + talc = talc+1; + ind1 = 2*hashcode; + if( s->idx.ptr.p_int[ind0]==s->idx.ptr.p_int[ind1]&&s->idx.ptr.p_int[ind0+1]==s->idx.ptr.p_int[ind1+1] ) + { + break; + } + hashcode = (hashcode+1)%l; + } + } + } + if( nchains==0 ) + { + result = (double)(0); + } + else + { + result = (double)talc/(double)nchains; + } + return result; +} + + +/************************************************************************* +This function is used to enumerate all elements of the sparse matrix. +Before first call user initializes T0 and T1 counters by zero. These +counters are used to remember current position in a matrix; after each +call they are updated by the function. + +Subsequent calls to this function return non-zero elements of the sparse +matrix, one by one. If you enumerate CRS matrix, matrix is traversed from +left to right, from top to bottom. In case you enumerate matrix stored as +Hash table, elements are returned in random order. + +EXAMPLE + > T0=0 + > T1=0 + > while SparseEnumerate(S,T0,T1,I,J,V) do + > ....do something with I,J,V + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table or CRS representation. + T0 - internal counter + T1 - internal counter + +OUTPUT PARAMETERS + T0 - new value of the internal counter + T1 - new value of the internal counter + I - row index of non-zero element, 0<=Imatrixtype!=0&&*t1<0) ) + { + + /* + * Incorrect T0/T1, terminate enumeration + */ + result = ae_false; + return result; + } + if( s->matrixtype==0 ) + { + + /* + * Hash-table matrix + */ + sz = s->tablesize; + for(i0=*t0; i0<=sz-1; i0++) + { + if( s->idx.ptr.p_int[2*i0]==-1||s->idx.ptr.p_int[2*i0]==-2 ) + { + continue; + } + else + { + *i = s->idx.ptr.p_int[2*i0]; + *j = s->idx.ptr.p_int[2*i0+1]; + *v = s->vals.ptr.p_double[i0]; + *t0 = i0+1; + result = ae_true; + return result; + } + } + *t0 = 0; + *t1 = 0; + result = ae_false; + return result; + } + if( s->matrixtype==1 ) + { + + /* + * CRS matrix + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseEnumerate: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + if( *t0>=s->ninitialized ) + { + *t0 = 0; + *t1 = 0; + result = ae_false; + return result; + } + while(*t0>s->ridx.ptr.p_int[*t1+1]-1&&*t1m) + { + *t1 = *t1+1; + } + *i = *t1; + *j = s->idx.ptr.p_int[*t0]; + *v = s->vals.ptr.p_double[*t0]; + *t0 = *t0+1; + result = ae_true; + return result; + } + if( s->matrixtype==2 ) + { + + /* + * SKS matrix: + * * T0 stores current offset in Vals[] array + * * T1 stores index of the diagonal block + */ + ae_assert(s->m==s->n, "SparseEnumerate: non-square SKS matrices are not supported", _state); + if( *t0>=s->ridx.ptr.p_int[s->m] ) + { + *t0 = 0; + *t1 = 0; + result = ae_false; + return result; + } + while(*t0>s->ridx.ptr.p_int[*t1+1]-1&&*t1m) + { + *t1 = *t1+1; + } + i0 = *t0-s->ridx.ptr.p_int[*t1]; + if( i0didx.ptr.p_int[*t1]+1 ) + { + + /* + * subdiagonal or diagonal element, row index is T1. + */ + *i = *t1; + *j = *t1-s->didx.ptr.p_int[*t1]+i0; + } + else + { + + /* + * superdiagonal element, column index is T1. + */ + *i = *t1-(s->ridx.ptr.p_int[*t1+1]-(*t0)); + *j = *t1; + } + *v = s->vals.ptr.p_double[*t0]; + *t0 = *t0+1; + result = ae_true; + return result; + } + ae_assert(ae_false, "SparseEnumerate: unexpected matrix type", _state); + return result; +} + + +/************************************************************************* +This function rewrites existing (non-zero) element. It returns True if +element exists or False, when it is called for non-existing (zero) +element. + +This function works with any kind of the matrix. + +The purpose of this function is to provide convenient thread-safe way to +modify sparse matrix. Such modification (already existing element is +rewritten) is guaranteed to be thread-safe without any synchronization, as +long as different threads modify different elements. + +INPUT PARAMETERS + S - sparse M*N matrix in any kind of representation + (Hash, SKS, CRS). + I - row index of non-zero element to modify, 0<=Im, "SparseRewriteExisting: invalid argument I(either I<0 or I>=S.M)", _state); + ae_assert(0<=j&&jn, "SparseRewriteExisting: invalid argument J(either J<0 or J>=S.N)", _state); + ae_assert(ae_isfinite(v, _state), "SparseRewriteExisting: invalid argument V(either V is infinite or V is NaN)", _state); + result = ae_false; + + /* + * Hash-table matrix + */ + if( s->matrixtype==0 ) + { + k = s->tablesize; + hashcode = sparse_hash(i, j, k, _state); + for(;;) + { + if( s->idx.ptr.p_int[2*hashcode]==-1 ) + { + return result; + } + if( s->idx.ptr.p_int[2*hashcode]==i&&s->idx.ptr.p_int[2*hashcode+1]==j ) + { + s->vals.ptr.p_double[hashcode] = v; + result = ae_true; + return result; + } + hashcode = (hashcode+1)%k; + } + } + + /* + * CRS matrix + */ + if( s->matrixtype==1 ) + { + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseRewriteExisting: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + k0 = s->ridx.ptr.p_int[i]; + k1 = s->ridx.ptr.p_int[i+1]-1; + while(k0<=k1) + { + k = (k0+k1)/2; + if( s->idx.ptr.p_int[k]==j ) + { + s->vals.ptr.p_double[k] = v; + result = ae_true; + return result; + } + if( s->idx.ptr.p_int[k]matrixtype==2 ) + { + ae_assert(s->m==s->n, "SparseRewriteExisting: non-square SKS matrix not supported", _state); + if( i==j ) + { + + /* + * Rewrite diagonal element + */ + result = ae_true; + s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+s->didx.ptr.p_int[i]] = v; + return result; + } + if( jdidx.ptr.p_int[i]; + if( i-j<=k ) + { + s->vals.ptr.p_double[s->ridx.ptr.p_int[i]+k+j-i] = v; + result = ae_true; + } + } + else + { + + /* + * Return superdiagonal element at J-th "skyline block" + */ + k = s->uidx.ptr.p_int[j]; + if( j-i<=k ) + { + s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)] = v; + result = ae_true; + } + } + return result; + } + return result; +} + + +/************************************************************************* +This function returns I-th row of the sparse matrix. Matrix must be stored +in CRS or SKS format. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format + I - row index, 0<=Imatrixtype==1||s->matrixtype==2, "SparseGetRow: S must be CRS/SKS-based matrix", _state); + ae_assert(i>=0&&im, "SparseGetRow: I<0 or I>=M", _state); + + /* + * Prepare output buffer + */ + rvectorsetlengthatleast(irow, s->n, _state); + for(i0=0; i0<=s->n-1; i0++) + { + irow->ptr.p_double[i0] = (double)(0); + } + + /* + * Output + */ + if( s->matrixtype==1 ) + { + for(i0=s->ridx.ptr.p_int[i]; i0<=s->ridx.ptr.p_int[i+1]-1; i0++) + { + irow->ptr.p_double[s->idx.ptr.p_int[i0]] = s->vals.ptr.p_double[i0]; + } + return; + } + if( s->matrixtype==2 ) + { + + /* + * Copy subdiagonal and diagonal parts + */ + ae_assert(s->n==s->m, "SparseGetRow: non-square SKS matrices are not supported", _state); + j0 = i-s->didx.ptr.p_int[i]; + i0 = -j0+s->ridx.ptr.p_int[i]; + for(j=j0; j<=i; j++) + { + irow->ptr.p_double[j] = s->vals.ptr.p_double[j+i0]; + } + + /* + * Copy superdiagonal part + */ + upperprofile = s->uidx.ptr.p_int[s->n]; + j0 = i+1; + j1 = ae_minint(s->n-1, i+upperprofile, _state); + for(j=j0; j<=j1; j++) + { + if( j-i<=s->uidx.ptr.p_int[j] ) + { + irow->ptr.p_double[j] = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; + } + } + return; + } +} + + +/************************************************************************* +This function returns I-th row of the sparse matrix IN COMPRESSED FORMAT - +only non-zero elements are returned (with their indexes). Matrix must be +stored in CRS or SKS format. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format + I - row index, 0<=Imatrixtype==1||s->matrixtype==2, "SparseGetRow: S must be CRS/SKS-based matrix", _state); + ae_assert(i>=0&&im, "SparseGetRow: I<0 or I>=M", _state); + + /* + * Initialize NZCnt + */ + *nzcnt = 0; + + /* + * CRS matrix - just copy data + */ + if( s->matrixtype==1 ) + { + *nzcnt = s->ridx.ptr.p_int[i+1]-s->ridx.ptr.p_int[i]; + ivectorsetlengthatleast(colidx, *nzcnt, _state); + rvectorsetlengthatleast(vals, *nzcnt, _state); + k0 = s->ridx.ptr.p_int[i]; + for(k=0; k<=*nzcnt-1; k++) + { + colidx->ptr.p_int[k] = s->idx.ptr.p_int[k0+k]; + vals->ptr.p_double[k] = s->vals.ptr.p_double[k0+k]; + } + return; + } + + /* + * SKS matrix - a bit more complex sequence + */ + if( s->matrixtype==2 ) + { + ae_assert(s->n==s->m, "SparseGetCompressedRow: non-square SKS matrices are not supported", _state); + + /* + * Allocate enough place for storage + */ + upperprofile = s->uidx.ptr.p_int[s->n]; + ivectorsetlengthatleast(colidx, s->didx.ptr.p_int[i]+1+upperprofile, _state); + rvectorsetlengthatleast(vals, s->didx.ptr.p_int[i]+1+upperprofile, _state); + + /* + * Copy subdiagonal and diagonal parts + */ + j0 = i-s->didx.ptr.p_int[i]; + i0 = -j0+s->ridx.ptr.p_int[i]; + for(j=j0; j<=i; j++) + { + colidx->ptr.p_int[*nzcnt] = j; + vals->ptr.p_double[*nzcnt] = s->vals.ptr.p_double[j+i0]; + *nzcnt = *nzcnt+1; + } + + /* + * Copy superdiagonal part + */ + j0 = i+1; + j1 = ae_minint(s->n-1, i+upperprofile, _state); + for(j=j0; j<=j1; j++) + { + if( j-i<=s->uidx.ptr.p_int[j] ) + { + colidx->ptr.p_int[*nzcnt] = j; + vals->ptr.p_double[*nzcnt] = s->vals.ptr.p_double[s->ridx.ptr.p_int[j+1]-(j-i)]; + *nzcnt = *nzcnt+1; + } + } + return; + } +} + + +/************************************************************************* +This function appends a compressed sparse row to a CRS matrix, increasing +its row count by 1. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format, including one created + with sparsecreatecrsempty(). + ColIdx - array[NZ], column indexes, values in [0,N-1] range. + ColIdx[] can store non-distinct values; elements of + Vals[] corresponding to duplicate column indexes will + be summed up. + Vals - array[NZ], element values. + NZ - nonzeros count, NZ>=0. Both ColIdx[] and Vals[] can + be longer than NZ, in which case only leading NZ + elements are used. + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + +NOTE: this function has amortized O(NZ*logNZ) cost. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendcompressedrow(sparsematrix* s, + /* Integer */ const ae_vector* colidx, + /* Real */ const ae_vector* vals, + ae_int_t nz, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs; + ae_int_t offsdst; + ae_int_t didx; + ae_int_t uidx; + + + ae_assert(s->matrixtype==1||s->matrixtype==-10083, "SparseAppendCompressedRow: S must be CRS-based matrix", _state); + ae_assert(nz>=0, "SparseAppendCompressedRow: NZ<0", _state); + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseAppendCompressedRow: the CRS matrix is not completely initialized", _state); + s->matrixtype = 1; + m = s->m; + offs = s->ridx.ptr.p_int[m]; + igrowv(m+1, &s->didx, _state); + igrowv(m+1, &s->uidx, _state); + igrowv(m+2, &s->ridx, _state); + igrowv(s->ridx.ptr.p_int[m]+nz, &s->idx, _state); + rgrowv(s->ridx.ptr.p_int[m]+nz, &s->vals, _state); + if( nz==0 ) + { + s->didx.ptr.p_int[m] = s->ridx.ptr.p_int[m]; + s->uidx.ptr.p_int[m] = s->ridx.ptr.p_int[m]; + s->ridx.ptr.p_int[m+1] = s->ridx.ptr.p_int[m]; + s->m = m+1; + return; + } + for(i=0; i<=nz-1; i++) + { + if( colidx->ptr.p_int[i]<0||colidx->ptr.p_int[i]>=s->n ) + { + ae_assert(ae_false, "SparseAppendCompressedRow: ColIdx[] contains elements outside of [0,N-1] range", _state); + } + s->idx.ptr.p_int[offs+i] = colidx->ptr.p_int[i]; + s->vals.ptr.p_double[offs+i] = vals->ptr.p_double[i]; + } + tagsortmiddleir(&s->idx, &s->vals, offs, nz, _state); + offsdst = offs; + for(i=1; i<=nz-1; i++) + { + if( s->idx.ptr.p_int[offsdst]!=s->idx.ptr.p_int[offs+i] ) + { + offsdst = offsdst+1; + s->idx.ptr.p_int[offsdst] = s->idx.ptr.p_int[offs+i]; + s->vals.ptr.p_double[offsdst] = s->vals.ptr.p_double[offs+i]; + } + else + { + s->vals.ptr.p_double[offsdst] = s->vals.ptr.p_double[offsdst]+s->vals.ptr.p_double[offs+i]; + } + } + nz = offsdst-offs+1; + uidx = -1; + didx = -1; + for(j=offs; j<=offsdst; j++) + { + k = s->idx.ptr.p_int[j]; + if( k==m ) + { + didx = j; + } + else + { + if( k>m&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offsdst+1; + } + if( didx==-1 ) + { + didx = uidx; + } + s->didx.ptr.p_int[m] = didx; + s->uidx.ptr.p_int[m] = uidx; + s->ridx.ptr.p_int[m+1] = offsdst+1; + s->ninitialized = s->ridx.ptr.p_int[m+1]; + s->m = m+1; +} + + +/************************************************************************* +This function appends an empty row to a CRS matrix, increasing its rows +count by 1. The newly added row can be modified with sparseappendelement(). +The matrix is a valid CRS matrix at any moment of the process. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format, including one created + with sparsecreatecrsempty(). + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendemptyrow(sparsematrix* s, ae_state *_state) +{ + ae_int_t m; + ae_int_t offs; + + + ae_assert(s->matrixtype==1||s->matrixtype==-10083, "SparseAppendEmptyRow: S must be CRS-based matrix", _state); + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseAppendEmptyRow: the CRS matrix is not completely initialized", _state); + m = s->m; + offs = s->ridx.ptr.p_int[m]; + s->matrixtype = 1; + igrowv(m+1, &s->didx, _state); + igrowv(m+1, &s->uidx, _state); + igrowv(m+2, &s->ridx, _state); + s->didx.ptr.p_int[m] = offs; + s->uidx.ptr.p_int[m] = offs; + s->ridx.ptr.p_int[m+1] = offs; + s->m = s->m+1; +} + + +/************************************************************************* +This function appends an element to the last row of a CRS matrix. New +elements can be added ONLY from left to right (column indexes are strictly +increasing). + +INPUT PARAMETERS: + S - a fully initialized sparse M*N matrix in CRS format, M>0 + K - column index, 0<=Kmatrixtype==1, "SparseAppendElement: S must be CRS-based matrix", _state); + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseAppendElement: the CRS matrix is not completely initialized", _state); + ae_assert(k>=0&&kn, "SparseAppendElement: K is outside of [0,N) range", _state); + ae_assert(s->ridx.ptr.p_int[s->m]==s->ridx.ptr.p_int[s->m-1]||k>s->idx.ptr.p_int[s->ridx.ptr.p_int[s->m]-1], "SparseAppendElement: elements must be added from left to right (column indexes must increase)", _state); + ae_assert(ae_isfinite(v, _state), "SparseAppendElement: V is not a finite number", _state); + m = s->m; + offs = s->ridx.ptr.p_int[m]; + igrowv(offs+1, &s->idx, _state); + rgrowv(offs+1, &s->vals, _state); + s->idx.ptr.p_int[offs] = k; + s->vals.ptr.p_double[offs] = v; + if( kdidx.ptr.p_int[m-1] = offs; + s->uidx.ptr.p_int[m-1] = offs; + } + if( k==m-1 ) + { + s->didx.ptr.p_int[m-1] = offs; + s->uidx.ptr.p_int[m-1] = offs+1; + } + if( k>m-1&&(offs==s->ridx.ptr.p_int[m-1]||s->idx.ptr.p_int[offs-1]didx.ptr.p_int[m-1] = offs; + s->uidx.ptr.p_int[m-1] = offs; + } + s->ridx.ptr.p_int[m] = offs+1; + s->ninitialized = s->ninitialized+1; +} + + +/************************************************************************* +This function performs efficient in-place transpose of SKS matrix. No +additional memory is allocated during transposition. + +This function supports only skyline storage format (SKS). + +INPUT PARAMETERS + S - sparse matrix in SKS format. + +OUTPUT PARAMETERS + S - sparse matrix, transposed. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetransposesks(sparsematrix* s, ae_state *_state) +{ + ae_int_t n; + ae_int_t d; + ae_int_t u; + ae_int_t i; + ae_int_t k; + ae_int_t t0; + ae_int_t t1; + double v; + + + ae_assert(s->matrixtype==2, "SparseTransposeSKS: only SKS matrices are supported", _state); + ae_assert(s->m==s->n, "SparseTransposeSKS: non-square SKS matrices are not supported", _state); + n = s->n; + for(i=1; i<=n-1; i++) + { + d = s->didx.ptr.p_int[i]; + u = s->uidx.ptr.p_int[i]; + k = s->uidx.ptr.p_int[i]; + s->uidx.ptr.p_int[i] = s->didx.ptr.p_int[i]; + s->didx.ptr.p_int[i] = k; + if( d==u ) + { + + /* + * Upper skyline height equal to lower skyline height, + * simple exchange is needed for transposition + */ + t0 = s->ridx.ptr.p_int[i]; + for(k=0; k<=d-1; k++) + { + v = s->vals.ptr.p_double[t0+k]; + s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t0+d+1+k]; + s->vals.ptr.p_double[t0+d+1+k] = v; + } + } + if( d>u ) + { + + /* + * Upper skyline height is less than lower skyline height. + * + * Transposition becomes a bit tricky: we have to rearrange + * "L0 L1 D U" to "U D L0 L1", where |L0|=|U|=u, |L1|=d-u. + * + * In order to do this we perform a sequence of swaps and + * in-place reversals: + * * swap(L0,U) => "U L1 D L0" + * * reverse("L1 D L0") => "U L0~ D L1~" (where X~ is a reverse of X) + * * reverse("L0~ D") => "U D L0 L1~" + * * reverse("L1") => "U D L0 L1" + */ + t0 = s->ridx.ptr.p_int[i]; + t1 = s->ridx.ptr.p_int[i]+d+1; + for(k=0; k<=u-1; k++) + { + v = s->vals.ptr.p_double[t0+k]; + s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t1+k]; + s->vals.ptr.p_double[t1+k] = v; + } + t0 = s->ridx.ptr.p_int[i]+u; + t1 = s->ridx.ptr.p_int[i+1]-1; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + t0 = s->ridx.ptr.p_int[i]+u; + t1 = s->ridx.ptr.p_int[i]+u+u; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + t0 = s->ridx.ptr.p_int[i+1]-(d-u); + t1 = s->ridx.ptr.p_int[i+1]-1; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + } + if( d "U1 D U0 L" + * * reverse("U1 D U0") => "U0~ D U1~ L" (where X~ is a reverse of X) + * * reverse("U0~") => "U0 D U1~ L" + * * reverse("D U1~") => "U0 U1 D L" + */ + t0 = s->ridx.ptr.p_int[i]; + t1 = s->ridx.ptr.p_int[i+1]-d; + for(k=0; k<=d-1; k++) + { + v = s->vals.ptr.p_double[t0+k]; + s->vals.ptr.p_double[t0+k] = s->vals.ptr.p_double[t1+k]; + s->vals.ptr.p_double[t1+k] = v; + } + t0 = s->ridx.ptr.p_int[i]; + t1 = s->ridx.ptr.p_int[i]+u; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + t0 = s->ridx.ptr.p_int[i]; + t1 = s->ridx.ptr.p_int[i]+u-d-1; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + t0 = s->ridx.ptr.p_int[i]+u-d; + t1 = s->ridx.ptr.p_int[i+1]-d-1; + while(t1>t0) + { + v = s->vals.ptr.p_double[t0]; + s->vals.ptr.p_double[t0] = s->vals.ptr.p_double[t1]; + s->vals.ptr.p_double[t1] = v; + t0 = t0+1; + t1 = t1-1; + } + } + } + k = s->uidx.ptr.p_int[n]; + s->uidx.ptr.p_int[n] = s->didx.ptr.p_int[n]; + s->didx.ptr.p_int[n] = k; +} + + +/************************************************************************* +This function performs transpose of CRS matrix. + +INPUT PARAMETERS + S - sparse matrix in CRS format. + +OUTPUT PARAMETERS + S - sparse matrix, transposed. + +NOTE: internal temporary copy is allocated for the purposes of + transposition. It is deallocated after transposition. + + -- ALGLIB PROJECT -- + Copyright 30.01.2018 by Bochkanov Sergey +*************************************************************************/ +void sparsetransposecrs(sparsematrix* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_vector oldvals; + ae_vector oldidx; + ae_vector oldridx; + ae_int_t oldn; + ae_int_t oldm; + ae_int_t newn; + ae_int_t newm; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nonne; + ae_vector counts; + + ae_frame_make(_state, &_frame_block); + memset(&oldvals, 0, sizeof(oldvals)); + memset(&oldidx, 0, sizeof(oldidx)); + memset(&oldridx, 0, sizeof(oldridx)); + memset(&counts, 0, sizeof(counts)); + ae_vector_init(&oldvals, 0, DT_REAL, _state, ae_true); + ae_vector_init(&oldidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&oldridx, 0, DT_INT, _state, ae_true); + ae_vector_init(&counts, 0, DT_INT, _state, ae_true); + + ae_assert(s->matrixtype==1, "SparseTransposeCRS: only CRS matrices are supported", _state); + ae_swap_vectors(&s->vals, &oldvals); + ae_swap_vectors(&s->idx, &oldidx); + ae_swap_vectors(&s->ridx, &oldridx); + oldn = s->n; + oldm = s->m; + newn = oldm; + newm = oldn; + + /* + * Update matrix size + */ + s->n = newn; + s->m = newm; + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + nonne = 0; + ivectorsetlengthatleast(&s->ridx, newm+1, _state); + for(i=0; i<=newm; i++) + { + s->ridx.ptr.p_int[i] = 0; + } + for(i=0; i<=oldm-1; i++) + { + for(j=oldridx.ptr.p_int[i]; j<=oldridx.ptr.p_int[i+1]-1; j++) + { + k = oldidx.ptr.p_int[j]+1; + s->ridx.ptr.p_int[k] = s->ridx.ptr.p_int[k]+1; + nonne = nonne+1; + } + } + for(i=0; i<=newm-1; i++) + { + s->ridx.ptr.p_int[i+1] = s->ridx.ptr.p_int[i+1]+s->ridx.ptr.p_int[i]; + } + s->ninitialized = s->ridx.ptr.p_int[newm]; + + /* + * Allocate memory and move elements to Vals/Idx. + */ + ae_vector_set_length(&counts, newm, _state); + for(i=0; i<=newm-1; i++) + { + counts.ptr.p_int[i] = 0; + } + rvectorsetlengthatleast(&s->vals, nonne, _state); + ivectorsetlengthatleast(&s->idx, nonne, _state); + for(i=0; i<=oldm-1; i++) + { + for(j=oldridx.ptr.p_int[i]; j<=oldridx.ptr.p_int[i+1]-1; j++) + { + k = oldidx.ptr.p_int[j]; + k = s->ridx.ptr.p_int[k]+counts.ptr.p_int[k]; + s->idx.ptr.p_int[k] = i; + s->vals.ptr.p_double[k] = oldvals.ptr.p_double[j]; + k = oldidx.ptr.p_int[j]; + counts.ptr.p_int[k] = counts.ptr.p_int[k]+1; + } + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs copying with transposition of CRS matrix. + +INPUT PARAMETERS + S0 - sparse matrix in CRS format. + +OUTPUT PARAMETERS + S1 - sparse matrix, transposed + + -- ALGLIB PROJECT -- + Copyright 23.07.2018 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytransposecrs(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + _sparsematrix_clear(s1); + + sparsecopytransposecrsbuf(s0, s1, _state); +} + + +/************************************************************************* +This function performs copying with transposition of CRS matrix (buffered +version which reuses memory already allocated by the target as much as +possible). + +INPUT PARAMETERS + S0 - sparse matrix in CRS format. + +OUTPUT PARAMETERS + S1 - sparse matrix, transposed; previously allocated memory is + reused if possible. + + -- ALGLIB PROJECT -- + Copyright 23.07.2018 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytransposecrsbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + ae_int_t oldn; + ae_int_t oldm; + ae_int_t newn; + ae_int_t newm; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t kk; + ae_int_t j0; + ae_int_t j1; + + + ae_assert(s0->matrixtype==1, "SparseCopyTransposeCRSBuf: only CRS matrices are supported", _state); + oldn = s0->n; + oldm = s0->m; + newn = oldm; + newm = oldn; + + /* + * Update matrix size + */ + s1->matrixtype = 1; + s1->n = newn; + s1->m = newm; + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + isetallocv(newm+1, 0, &s1->ridx, _state); + for(i=0; i<=oldm-1; i++) + { + j0 = s0->ridx.ptr.p_int[i]; + j1 = s0->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + k = s0->idx.ptr.p_int[j]+1; + s1->ridx.ptr.p_int[k] = s1->ridx.ptr.p_int[k]+1; + } + } + for(i=0; i<=newm-1; i++) + { + s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; + } + s1->ninitialized = s1->ridx.ptr.p_int[newm]; + + /* + * Allocate memory and move elements to Vals/Idx. + */ + ivectorsetlengthatleast(&s1->didx, newm, _state); + for(i=0; i<=newm-1; i++) + { + s1->didx.ptr.p_int[i] = s1->ridx.ptr.p_int[i]; + } + rvectorsetlengthatleast(&s1->vals, s1->ninitialized, _state); + ivectorsetlengthatleast(&s1->idx, s1->ninitialized, _state); + for(i=0; i<=oldm-1; i++) + { + j0 = s0->ridx.ptr.p_int[i]; + j1 = s0->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + kk = s0->idx.ptr.p_int[j]; + k = s1->didx.ptr.p_int[kk]; + s1->idx.ptr.p_int[k] = i; + s1->vals.ptr.p_double[k] = s0->vals.ptr.p_double[j]; + s1->didx.ptr.p_int[kk] = k+1; + } + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s1, _state); +} + + +/************************************************************************* +This function performs copying with transposition of CRS matrix (buffered +version which reuses memory already allocated by the target as much as +possible). + +Unlike SparseCopyTransposeCRSBuf() it can copy/transpose only lower or +upper triangle or both, depending on Triangle parameter + +INPUT PARAMETERS + S0 - sparse matrix in CRS format. + Triangle- triangle to copy: + * -1 the lower triangle and diagonal are transposed, + S1 is upper triangular + * 0 both triangles are copied + * +1 the upper triangle and diagonal are transposed, + S1 is lower triangular + +OUTPUT PARAMETERS + S1 - sparse matrix, transposed; previously allocated memory is + reused if possible. + + -- ALGLIB PROJECT -- + Copyright 23.07.2018 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytransposecrsxbuf(const sparsematrix* s0, + ae_int_t triangle, + sparsematrix* s1, + ae_state *_state) +{ + ae_int_t oldn; + ae_int_t oldm; + ae_int_t newn; + ae_int_t newm; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t kk; + ae_int_t j0; + ae_int_t j1; + + + ae_assert(s0->matrixtype==1, "SparseCopyTransposeCRSXBuf: only CRS matrices are supported", _state); + ae_assert((triangle==-1||triangle==0)||triangle==1, "SparseCopyTransposeCRSXBuf: Triangle parameter must be -1, 0 or +1", _state); + if( triangle==0 ) + { + sparsecopytransposecrsbuf(s0, s1, _state); + return; + } + oldn = s0->n; + oldm = s0->m; + newn = oldm; + newm = oldn; + + /* + * Update matrix size + */ + s1->matrixtype = 1; + s1->n = newn; + s1->m = newm; + + /* + * Fill RIdx by number of elements per row: + * RIdx[I+1] stores number of elements in I-th row. + * + * Convert RIdx from row sizes to row offsets. + * Set NInitialized + */ + isetallocv(newm+1, 0, &s1->ridx, _state); + for(i=0; i<=oldm-1; i++) + { + if( triangle>0 ) + { + j0 = s0->didx.ptr.p_int[i]; + j1 = s0->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = s0->ridx.ptr.p_int[i]; + j1 = s0->uidx.ptr.p_int[i]-1; + } + for(j=j0; j<=j1; j++) + { + k = s0->idx.ptr.p_int[j]+1; + s1->ridx.ptr.p_int[k] = s1->ridx.ptr.p_int[k]+1; + } + } + for(i=0; i<=newm-1; i++) + { + s1->ridx.ptr.p_int[i+1] = s1->ridx.ptr.p_int[i+1]+s1->ridx.ptr.p_int[i]; + } + s1->ninitialized = s1->ridx.ptr.p_int[newm]; + + /* + * Allocate memory and move elements to Vals/Idx. + */ + ivectorsetlengthatleast(&s1->didx, newm, _state); + for(i=0; i<=newm-1; i++) + { + s1->didx.ptr.p_int[i] = s1->ridx.ptr.p_int[i]; + } + rvectorsetlengthatleast(&s1->vals, s1->ninitialized, _state); + ivectorsetlengthatleast(&s1->idx, s1->ninitialized, _state); + for(i=0; i<=oldm-1; i++) + { + if( triangle>0 ) + { + j0 = s0->didx.ptr.p_int[i]; + j1 = s0->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = s0->ridx.ptr.p_int[i]; + j1 = s0->uidx.ptr.p_int[i]-1; + } + for(j=j0; j<=j1; j++) + { + kk = s0->idx.ptr.p_int[j]; + k = s1->didx.ptr.p_int[kk]; + s1->idx.ptr.p_int[k] = i; + s1->vals.ptr.p_double[k] = s0->vals.ptr.p_double[j]; + s1->didx.ptr.p_int[kk] = k+1; + } + } + + /* + * Initialization 'S.UIdx' and 'S.DIdx' + */ + sparseinitduidx(s1, _state); +} + + +/************************************************************************* +This function performs in-place conversion to desired sparse storage +format. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + Fmt - desired storage format of the output, as returned by + SparseGetMatrixType() function: + * 0 for hash-based storage + * 1 for CRS + * 2 for SKS + +OUTPUT PARAMETERS + S0 - sparse matrix in requested format. + +NOTE: in-place conversion wastes a lot of memory which is used to store + temporaries. If you perform a lot of repeated conversions, we + recommend to use out-of-place buffered conversion functions, like + SparseCopyToBuf(), which can reuse already allocated memory. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparseconvertto(sparsematrix* s0, ae_int_t fmt, ae_state *_state) +{ + + + ae_assert((fmt==0||fmt==1)||fmt==2, "SparseConvertTo: invalid fmt parameter", _state); + if( fmt==0 ) + { + sparseconverttohash(s0, _state); + return; + } + if( fmt==1 ) + { + sparseconverttocrs(s0, _state); + return; + } + if( fmt==2 ) + { + sparseconverttosks(s0, _state); + return; + } + ae_assert(ae_false, "SparseConvertTo: invalid matrix type", _state); +} + + +/************************************************************************* +This function performs out-of-place conversion to desired sparse storage +format. S0 is copied to S1 and converted on-the-fly. Memory allocated in +S1 is reused to maximum extent possible. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + Fmt - desired storage format of the output, as returned by + SparseGetMatrixType() function: + * 0 for hash-based storage + * 1 for CRS + * 2 for SKS + +OUTPUT PARAMETERS + S1 - sparse matrix in requested format. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytobuf(const sparsematrix* s0, + ae_int_t fmt, + sparsematrix* s1, + ae_state *_state) +{ + + + ae_assert((fmt==0||fmt==1)||fmt==2, "SparseCopyToBuf: invalid fmt parameter", _state); + if( fmt==0 ) + { + sparsecopytohashbuf(s0, s1, _state); + return; + } + if( fmt==1 ) + { + sparsecopytocrsbuf(s0, s1, _state); + return; + } + if( fmt==2 ) + { + sparsecopytosksbuf(s0, s1, _state); + return; + } + ae_assert(ae_false, "SparseCopyToBuf: invalid matrix type", _state); +} + + +/************************************************************************* +This function performs in-place conversion to Hash table storage. + +INPUT PARAMETERS + S - sparse matrix in CRS format. + +OUTPUT PARAMETERS + S - sparse matrix in Hash table format. + +NOTE: this function has no effect when called with matrix which is + already in Hash table mode. + +NOTE: in-place conversion involves allocation of temporary arrays. If you + perform a lot of repeated in- place conversions, it may lead to + memory fragmentation. Consider using out-of-place SparseCopyToHashBuf() + function in this case. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparseconverttohash(sparsematrix* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tidx; + ae_vector tridx; + ae_vector tdidx; + ae_vector tuidx; + ae_vector tvals; + ae_int_t n; + ae_int_t m; + ae_int_t offs0; + ae_int_t i; + ae_int_t j; + ae_int_t k; + + ae_frame_make(_state, &_frame_block); + memset(&tidx, 0, sizeof(tidx)); + memset(&tridx, 0, sizeof(tridx)); + memset(&tdidx, 0, sizeof(tdidx)); + memset(&tuidx, 0, sizeof(tuidx)); + memset(&tvals, 0, sizeof(tvals)); + ae_vector_init(&tidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tridx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tdidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tuidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); + + ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseConvertToHash: invalid matrix type", _state); + if( s->matrixtype==0 ) + { + + /* + * Already in Hash mode + */ + ae_frame_leave(_state); + return; + } + if( s->matrixtype==1 ) + { + + /* + * From CRS to Hash + */ + s->matrixtype = 0; + m = s->m; + n = s->n; + ae_swap_vectors(&s->idx, &tidx); + ae_swap_vectors(&s->ridx, &tridx); + ae_swap_vectors(&s->vals, &tvals); + sparsecreatebuf(m, n, tridx.ptr.p_int[m], s, _state); + for(i=0; i<=m-1; i++) + { + for(j=tridx.ptr.p_int[i]; j<=tridx.ptr.p_int[i+1]-1; j++) + { + sparseset(s, i, tidx.ptr.p_int[j], tvals.ptr.p_double[j], _state); + } + } + ae_frame_leave(_state); + return; + } + if( s->matrixtype==2 ) + { + + /* + * From SKS to Hash + */ + s->matrixtype = 0; + m = s->m; + n = s->n; + ae_swap_vectors(&s->ridx, &tridx); + ae_swap_vectors(&s->didx, &tdidx); + ae_swap_vectors(&s->uidx, &tuidx); + ae_swap_vectors(&s->vals, &tvals); + sparsecreatebuf(m, n, tridx.ptr.p_int[m], s, _state); + for(i=0; i<=m-1; i++) + { + + /* + * copy subdiagonal and diagonal parts of I-th block + */ + offs0 = tridx.ptr.p_int[i]; + k = tdidx.ptr.p_int[i]+1; + for(j=0; j<=k-1; j++) + { + sparseset(s, i, i-tdidx.ptr.p_int[i]+j, tvals.ptr.p_double[offs0+j], _state); + } + + /* + * Copy superdiagonal part of I-th block + */ + offs0 = tridx.ptr.p_int[i]+tdidx.ptr.p_int[i]+1; + k = tuidx.ptr.p_int[i]; + for(j=0; j<=k-1; j++) + { + sparseset(s, i-k+j, i, tvals.ptr.p_double[offs0+j], _state); + } + } + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "SparseConvertToHash: invalid matrix type", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs out-of-place conversion to Hash table storage +format. S0 is copied to S1 and converted on-the-fly. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + +OUTPUT PARAMETERS + S1 - sparse matrix in Hash table format. + +NOTE: if S0 is stored as Hash-table, it is just copied without conversion. + +NOTE: this function de-allocates memory occupied by S1 before starting + conversion. If you perform a lot of repeated conversions, it may + lead to memory fragmentation. In this case we recommend you to use + SparseCopyToHashBuf() function which re-uses memory in S1 as much as + possible. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytohash(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + _sparsematrix_clear(s1); + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToHash: invalid matrix type", _state); + sparsecopytohashbuf(s0, s1, _state); +} + + +/************************************************************************* +This function performs out-of-place conversion to Hash table storage +format. S0 is copied to S1 and converted on-the-fly. Memory allocated in +S1 is reused to maximum extent possible. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + +OUTPUT PARAMETERS + S1 - sparse matrix in Hash table format. + +NOTE: if S0 is stored as Hash-table, it is just copied without conversion. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytohashbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + double val; + ae_int_t t0; + ae_int_t t1; + ae_int_t i; + ae_int_t j; + + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToHashBuf: invalid matrix type", _state); + if( s0->matrixtype==0 ) + { + + /* + * Already hash, just copy + */ + sparsecopybuf(s0, s1, _state); + return; + } + if( s0->matrixtype==1 ) + { + + /* + * CRS storage + */ + t0 = 0; + t1 = 0; + sparsecreatebuf(s0->m, s0->n, s0->ridx.ptr.p_int[s0->m], s1, _state); + while(sparseenumerate(s0, &t0, &t1, &i, &j, &val, _state)) + { + sparseset(s1, i, j, val, _state); + } + return; + } + if( s0->matrixtype==2 ) + { + + /* + * SKS storage + */ + t0 = 0; + t1 = 0; + sparsecreatebuf(s0->m, s0->n, s0->ridx.ptr.p_int[s0->m], s1, _state); + while(sparseenumerate(s0, &t0, &t1, &i, &j, &val, _state)) + { + sparseset(s1, i, j, val, _state); + } + return; + } + ae_assert(ae_false, "SparseCopyToHashBuf: invalid matrix type", _state); +} + + +/************************************************************************* +This function performs out-of-place conversion to CRS format. S0 is +copied to S1 and converted on-the-fly. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + +OUTPUT PARAMETERS + S1 - sparse matrix in CRS format. + +NOTE: if S0 is stored as CRS, it is just copied without conversion. + +NOTE: this function de-allocates memory occupied by S1 before starting CRS + conversion. If you perform a lot of repeated CRS conversions, it may + lead to memory fragmentation. In this case we recommend you to use + SparseCopyToCRSBuf() function which re-uses memory in S1 as much as + possible. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytocrs(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + _sparsematrix_clear(s1); + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToCRS: invalid matrix type", _state); + sparsecopytocrsbuf(s0, s1, _state); +} + + +/************************************************************************* +This function performs in-place conversion to SKS format. + +INPUT PARAMETERS + S - sparse matrix in any format. + +OUTPUT PARAMETERS + S - sparse matrix in SKS format. + +NOTE: this function has no effect when called with matrix which is + already in SKS mode. + +NOTE: in-place conversion involves allocation of temporary arrays. If you + perform a lot of repeated in- place conversions, it may lead to + memory fragmentation. Consider using out-of-place SparseCopyToSKSBuf() + function in this case. + + -- ALGLIB PROJECT -- + Copyright 15.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparseconverttosks(sparsematrix* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tridx; + ae_vector tdidx; + ae_vector tuidx; + ae_vector tvals; + ae_int_t n; + ae_int_t t0; + ae_int_t t1; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&tridx, 0, sizeof(tridx)); + memset(&tdidx, 0, sizeof(tdidx)); + memset(&tuidx, 0, sizeof(tuidx)); + memset(&tvals, 0, sizeof(tvals)); + ae_vector_init(&tridx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tdidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tuidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&tvals, 0, DT_REAL, _state, ae_true); + + ae_assert((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2, "SparseConvertToSKS: invalid matrix type", _state); + ae_assert(s->m==s->n, "SparseConvertToSKS: rectangular matrices are not supported", _state); + n = s->n; + if( s->matrixtype==2 ) + { + + /* + * Already in SKS mode + */ + ae_frame_leave(_state); + return; + } + + /* + * Generate internal copy of SKS matrix + */ + ivectorsetlengthatleast(&tdidx, n+1, _state); + ivectorsetlengthatleast(&tuidx, n+1, _state); + for(i=0; i<=n; i++) + { + tdidx.ptr.p_int[i] = 0; + tuidx.ptr.p_int[i] = 0; + } + t0 = 0; + t1 = 0; + while(sparseenumerate(s, &t0, &t1, &i, &j, &v, _state)) + { + if( jmatrixtype = 2; + s->ninitialized = 0; + s->nfree = 0; + s->m = n; + s->n = n; + ae_swap_vectors(&s->didx, &tdidx); + ae_swap_vectors(&s->uidx, &tuidx); + ae_swap_vectors(&s->ridx, &tridx); + ae_swap_vectors(&s->vals, &tvals); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs out-of-place conversion to SKS storage format. +S0 is copied to S1 and converted on-the-fly. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + +OUTPUT PARAMETERS + S1 - sparse matrix in SKS format. + +NOTE: if S0 is stored as SKS, it is just copied without conversion. + +NOTE: this function de-allocates memory occupied by S1 before starting + conversion. If you perform a lot of repeated conversions, it may + lead to memory fragmentation. In this case we recommend you to use + SparseCopyToSKSBuf() function which re-uses memory in S1 as much as + possible. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytosks(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + + _sparsematrix_clear(s1); + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToSKS: invalid matrix type", _state); + sparsecopytosksbuf(s0, s1, _state); +} + + +/************************************************************************* +This function performs out-of-place conversion to SKS format. S0 is +copied to S1 and converted on-the-fly. Memory allocated in S1 is reused +to maximum extent possible. + +INPUT PARAMETERS + S0 - sparse matrix in any format. + +OUTPUT PARAMETERS + S1 - sparse matrix in SKS format. + +NOTE: if S0 is stored as SKS, it is just copied without conversion. + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsecopytosksbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state) +{ + double v; + ae_int_t n; + ae_int_t t0; + ae_int_t t1; + ae_int_t i; + ae_int_t j; + ae_int_t k; + + + ae_assert((s0->matrixtype==0||s0->matrixtype==1)||s0->matrixtype==2, "SparseCopyToSKSBuf: invalid matrix type", _state); + ae_assert(s0->m==s0->n, "SparseCopyToSKSBuf: rectangular matrices are not supported", _state); + n = s0->n; + if( s0->matrixtype==2 ) + { + + /* + * Already SKS, just copy + */ + sparsecopybuf(s0, s1, _state); + return; + } + + /* + * Generate copy of matrix in the SKS format + */ + ivectorsetlengthatleast(&s1->didx, n+1, _state); + ivectorsetlengthatleast(&s1->uidx, n+1, _state); + for(i=0; i<=n; i++) + { + s1->didx.ptr.p_int[i] = 0; + s1->uidx.ptr.p_int[i] = 0; + } + t0 = 0; + t1 = 0; + while(sparseenumerate(s0, &t0, &t1, &i, &j, &v, _state)) + { + if( jdidx.ptr.p_int[i] = ae_maxint(s1->didx.ptr.p_int[i], i-j, _state); + } + else + { + s1->uidx.ptr.p_int[j] = ae_maxint(s1->uidx.ptr.p_int[j], j-i, _state); + } + } + ivectorsetlengthatleast(&s1->ridx, n+1, _state); + s1->ridx.ptr.p_int[0] = 0; + for(i=1; i<=n; i++) + { + s1->ridx.ptr.p_int[i] = s1->ridx.ptr.p_int[i-1]+s1->didx.ptr.p_int[i-1]+1+s1->uidx.ptr.p_int[i-1]; + } + rvectorsetlengthatleast(&s1->vals, s1->ridx.ptr.p_int[n], _state); + k = s1->ridx.ptr.p_int[n]; + for(i=0; i<=k-1; i++) + { + s1->vals.ptr.p_double[i] = 0.0; + } + t0 = 0; + t1 = 0; + while(sparseenumerate(s0, &t0, &t1, &i, &j, &v, _state)) + { + if( j<=i ) + { + s1->vals.ptr.p_double[s1->ridx.ptr.p_int[i]+s1->didx.ptr.p_int[i]-(i-j)] = v; + } + else + { + s1->vals.ptr.p_double[s1->ridx.ptr.p_int[j+1]-(j-i)] = v; + } + } + for(i=0; i<=n-1; i++) + { + s1->didx.ptr.p_int[n] = ae_maxint(s1->didx.ptr.p_int[n], s1->didx.ptr.p_int[i], _state); + s1->uidx.ptr.p_int[n] = ae_maxint(s1->uidx.ptr.p_int[n], s1->uidx.ptr.p_int[i], _state); + } + s1->matrixtype = 2; + s1->ninitialized = 0; + s1->nfree = 0; + s1->m = n; + s1->n = n; +} + + +/************************************************************************* +This non-accessible to user function performs in-place creation of CRS +matrix. It is expected that: +* S.M and S.N are initialized +* S.RIdx, S.Idx and S.Vals are loaded with values in CRS format used by + ALGLIB, with elements of S.Idx/S.Vals possibly being unsorted within + each row (this constructor function may post-sort matrix, assuming that + it is sorted by rows). + +Only 5 fields should be set by caller. Other fields will be rewritten by +this constructor function. + +This function performs integrity check on user-specified values, with the +only exception being Vals[] array: +* it does not require values to be non-zero +* it does not check for elements of Vals[] being finite IEEE-754 values + +INPUT PARAMETERS + S - sparse matrix with corresponding fields set by caller + +OUTPUT PARAMETERS + S - sparse matrix in CRS format. + + -- ALGLIB PROJECT -- + Copyright 20.08.2016 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsinplace(sparsematrix* s, ae_state *_state) +{ + ae_int_t m; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + + + m = s->m; + n = s->n; + + /* + * Quick exit for M=0 or N=0 + */ + ae_assert(s->m>=0, "SparseCreateCRSInplace: integrity check failed", _state); + ae_assert(s->n>=0, "SparseCreateCRSInplace: integrity check failed", _state); + if( m==0||n==0 ) + { + s->matrixtype = 1; + s->ninitialized = 0; + ivectorsetlengthatleast(&s->ridx, s->m+1, _state); + ivectorsetlengthatleast(&s->didx, s->m, _state); + ivectorsetlengthatleast(&s->uidx, s->m, _state); + for(i=0; i<=s->m-1; i++) + { + s->ridx.ptr.p_int[i] = 0; + s->uidx.ptr.p_int[i] = 0; + s->didx.ptr.p_int[i] = 0; + } + s->ridx.ptr.p_int[s->m] = 0; + return; + } + + /* + * Perform integrity check + */ + ae_assert(s->m>0, "SparseCreateCRSInplace: integrity check failed", _state); + ae_assert(s->n>0, "SparseCreateCRSInplace: integrity check failed", _state); + ae_assert(s->ridx.cnt>=m+1, "SparseCreateCRSInplace: integrity check failed", _state); + for(i=0; i<=m-1; i++) + { + ae_assert(s->ridx.ptr.p_int[i]>=0&&s->ridx.ptr.p_int[i]<=s->ridx.ptr.p_int[i+1], "SparseCreateCRSInplace: integrity check failed", _state); + } + ae_assert(s->ridx.ptr.p_int[m]<=s->idx.cnt, "SparseCreateCRSInplace: integrity check failed", _state); + ae_assert(s->ridx.ptr.p_int[m]<=s->vals.cnt, "SparseCreateCRSInplace: integrity check failed", _state); + + /* + * Initialize + */ + s->matrixtype = 1; + s->ninitialized = s->ridx.ptr.p_int[m]; + for(i=0; i<=m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]; + for(j=j0; j<=j1-2; j++) + { + if( s->idx.ptr.p_int[j]>s->idx.ptr.p_int[j+1] ) + { + + /* + * Unsorted sequence, needs sorting + */ + tagsortmiddleir(&s->idx, &s->vals, j0, j1-j0, _state); + break; + } + } + if( j1>j0 ) + { + ae_assert(s->idx.ptr.p_int[j0]>=0&&s->idx.ptr.p_int[j1-1]matrixtype==0||s->matrixtype==1)||s->matrixtype==2)||s->matrixtype==-10081)||s->matrixtype==-10082, "SparseGetMatrixType: invalid matrix type", _state); + result = s->matrixtype; + return result; +} + + +/************************************************************************* +This function checks matrix storage format and returns True when matrix is +stored using Hash table representation. + +INPUT PARAMETERS: + S - sparse matrix. + +RESULT: + True if matrix type is Hash table + False if matrix type is not Hash table + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool sparseishash(const sparsematrix* s, ae_state *_state) +{ + ae_bool result; + + + ae_assert((((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2)||s->matrixtype==-10081)||s->matrixtype==-10082, "SparseIsHash: invalid matrix type", _state); + result = s->matrixtype==0; + return result; +} + + +/************************************************************************* +This function checks matrix storage format and returns True when matrix is +stored using SKS representation. + +INPUT PARAMETERS: + S - sparse matrix. + +RESULT: + True if matrix type is SKS + False if matrix type is not SKS + + -- ALGLIB PROJECT -- + Copyright 20.07.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool sparseissks(const sparsematrix* s, ae_state *_state) +{ + ae_bool result; + + + ae_assert((((s->matrixtype==0||s->matrixtype==1)||s->matrixtype==2)||s->matrixtype==-10081)||s->matrixtype==-10082, "SparseIsSKS: invalid matrix type", _state); + result = s->matrixtype==2; + return result; +} + + +/************************************************************************* +The function frees all memory occupied by sparse matrix. Sparse matrix +structure becomes unusable after this call. + +OUTPUT PARAMETERS + S - sparse matrix to delete + + -- ALGLIB PROJECT -- + Copyright 24.07.2012 by Bochkanov Sergey +*************************************************************************/ +void sparsefree(sparsematrix* s, ae_state *_state) +{ + + _sparsematrix_clear(s); + + s->matrixtype = -1; + s->m = 0; + s->n = 0; + s->nfree = 0; + s->ninitialized = 0; + s->tablesize = 0; +} + + +/************************************************************************* +The function returns number of strictly upper triangular non-zero elements +in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries +in the sparse matrix data structure. If some element has zero numerical +value, it is still counted. + +This function has different cost for different types of matrices: +* for hash-based matrices it involves complete pass over entire hash-table + with O(NNZ) cost, where NNZ is number of non-zero elements +* for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). + +RESULT: number of non-zero elements strictly above main diagonal + + -- ALGLIB PROJECT -- + Copyright 12.02.2014 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetuppercount(const sparsematrix* s, ae_state *_state) +{ + ae_int_t sz; + ae_int_t i0; + ae_int_t i; + ae_int_t result; + + + result = -1; + if( s->matrixtype==0 ) + { + + /* + * Hash-table matrix + */ + result = 0; + sz = s->tablesize; + for(i0=0; i0<=sz-1; i0++) + { + i = s->idx.ptr.p_int[2*i0]; + if( i>=0&&s->idx.ptr.p_int[2*i0+1]>i ) + { + result = result+1; + } + } + return result; + } + if( s->matrixtype==1 ) + { + + /* + * CRS matrix + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGetUpperCount: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + result = 0; + sz = s->m; + for(i=0; i<=sz-1; i++) + { + result = result+(s->ridx.ptr.p_int[i+1]-s->uidx.ptr.p_int[i]); + } + return result; + } + if( s->matrixtype==2 ) + { + + /* + * SKS matrix + */ + ae_assert(s->m==s->n, "SparseGetUpperCount: non-square SKS matrices are not supported", _state); + result = 0; + sz = s->m; + for(i=0; i<=sz-1; i++) + { + result = result+s->uidx.ptr.p_int[i]; + } + return result; + } + ae_assert(ae_false, "SparseGetUpperCount: internal error", _state); + return result; +} + + +/************************************************************************* +The function returns number of strictly lower triangular non-zero elements +in the matrix. It counts SYMBOLICALLY non-zero elements, i.e. entries +in the sparse matrix data structure. If some element has zero numerical +value, it is still counted. + +This function has different cost for different types of matrices: +* for hash-based matrices it involves complete pass over entire hash-table + with O(NNZ) cost, where NNZ is number of non-zero elements +* for CRS and SKS matrix types cost of counting is O(N) (N - matrix size). + +RESULT: number of non-zero elements strictly below main diagonal + + -- ALGLIB PROJECT -- + Copyright 12.02.2014 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sparsegetlowercount(const sparsematrix* s, ae_state *_state) +{ + ae_int_t sz; + ae_int_t i0; + ae_int_t i; + ae_int_t result; + + + result = -1; + if( s->matrixtype==0 ) + { + + /* + * Hash-table matrix + */ + result = 0; + sz = s->tablesize; + for(i0=0; i0<=sz-1; i0++) + { + i = s->idx.ptr.p_int[2*i0]; + if( i>=0&&s->idx.ptr.p_int[2*i0+1]matrixtype==1 ) + { + + /* + * CRS matrix + */ + ae_assert(s->ninitialized==s->ridx.ptr.p_int[s->m], "SparseGetUpperCount: some rows/elements of the CRS matrix were not initialized (you must initialize everything you promised to SparseCreateCRS)", _state); + result = 0; + sz = s->m; + for(i=0; i<=sz-1; i++) + { + result = result+(s->didx.ptr.p_int[i]-s->ridx.ptr.p_int[i]); + } + return result; + } + if( s->matrixtype==2 ) + { + + /* + * SKS matrix + */ + ae_assert(s->m==s->n, "SparseGetUpperCount: non-square SKS matrices are not supported", _state); + result = 0; + sz = s->m; + for(i=0; i<=sz-1; i++) + { + result = result+s->didx.ptr.p_int[i]; + } + return result; + } + ae_assert(ae_false, "SparseGetUpperCount: internal error", _state); + return result; +} + + +/************************************************************************* +This function performs an in-place matrix conditioning scaling such that + + A = R*Z*C + +where A is an original matrix, R and C are diagonal scaling matrices, and +Z is a scaled matrix. Z replaces A, R and C are returned as 1D arrays. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + SclType - scaling type: + * 0 for automatically chosen scaling + * 1 for equilibration scaling + ScaleRows - if False, rows are not scaled (R=identity) + ScaleCols - if False, cols are not scaled (C=identity) + ColsFirst - scale columns first. If False, rows are scaled prior + to scaling columns. Ignored for ScaleCols=False. + +OUTPUT PARAMETERS + R - array[M], row scales, R[i]>0 + C - array[N], col scales, C[i]>0 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. + +NOTE: this function works with general (nonsymmetric) matrices. See + sparsesymmscale() for a symmetric version. See sparsescalebuf() for + a version which reuses space already present in output arrays R/C. + +NOTE: if both ScaleRows=False and ScaleCols=False, this function returns + an identity scaling. + +NOTE: R[] and C[] are guaranteed to be strictly positive. When the matrix + has zero rows/cols, corresponding elements of R/C are set to 1. + + -- ALGLIB PROJECT -- + Copyright 12.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsescale(sparsematrix* s, + ae_int_t scltype, + ae_bool scalerows, + ae_bool scalecols, + ae_bool colsfirst, + /* Real */ ae_vector* r, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + ae_int_t axis; + ae_vector tmp0; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&tmp0, 0, sizeof(tmp0)); + ae_vector_clear(r); + ae_vector_clear(c); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + + ae_assert(s->matrixtype==1, "SparseScale: incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(scltype==0||scltype==1, "SparseScale: incorrect matrix type (convert your matrix to CRS)", _state); + + /* + * Initialization and quick exit + */ + n = s->n; + m = s->m; + if( scltype==0 ) + { + scltype = 1; + } + rsetallocv(m, 1.0, r, _state); + rsetallocv(n, 1.0, c, _state); + if( !scalerows&&!scalecols ) + { + ae_frame_leave(_state); + return; + } + + /* + * Equilibration scaling + */ + if( scltype==1 ) + { + for(axis=0; axis<=1; axis++) + { + if( (colsfirst&&axis==0)||(!colsfirst&&axis==1) ) + { + + /* + * Scale columns + */ + if( scalecols ) + { + rallocv(n, &tmp0, _state); + rsetv(n, 0.0, c, _state); + for(i=0; i<=m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = s->idx.ptr.p_int[jj]; + v = s->vals.ptr.p_double[jj]; + c->ptr.p_double[j] = ae_maxreal(c->ptr.p_double[j], ae_fabs(v, _state), _state); + } + } + for(j=0; j<=n-1; j++) + { + if( ae_fp_eq(c->ptr.p_double[j],(double)(0)) ) + { + c->ptr.p_double[j] = (double)(1); + } + tmp0.ptr.p_double[j] = (double)1/c->ptr.p_double[j]; + } + for(i=0; i<=m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + s->vals.ptr.p_double[jj] = tmp0.ptr.p_double[s->idx.ptr.p_int[jj]]*s->vals.ptr.p_double[jj]; + } + } + } + } + else + { + + /* + * Scale rows + */ + if( scalerows ) + { + for(i=0; i<=m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + v = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + v = ae_maxreal(v, ae_fabs(s->vals.ptr.p_double[jj], _state), _state); + } + if( ae_fp_eq(v,(double)(0)) ) + { + v = (double)(1); + } + r->ptr.p_double[i] = v; + v = (double)1/v; + for(jj=j0; jj<=j1; jj++) + { + s->vals.ptr.p_double[jj] = v*s->vals.ptr.p_double[jj]; + } + } + } + } + } + ae_frame_leave(_state); + return; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function appends an empty column to a CRS matrix. + + -- ALGLIB PROJECT -- + Copyright 04.01.2025 by Bochkanov Sergey +*************************************************************************/ +void sparseappendcoltocrs(sparsematrix* s, ae_state *_state) +{ + + + ae_assert(s->matrixtype==1, "SparseScale: incorrect matrix type (convert your matrix to CRS)", _state); + s->n = s->n+1; +} + + +/************************************************************************* +This function tries to gather values from Src to Dst, zeroing out elements +of Dst not present in Src. + +Both matrices must be in the CRS format and must have exactly the same +size. The sparsity pattern of Src must be a subset of that of Dst. + +If Src contains non-zero elements not present in Dst, gather operation is +stopped in the middle (leaving Dst values partially changed but otherwise +fully functional) and False is returned. + +INPUT PARAMETERS + Dst - sparse M*N destination matrix in CRS format. + Src - sparse M*N source matrix in CRS format. + +OUTPUT PARAMETERS + Dst - if True is returned, contains elements of Src and + zeros in other positions. If False is returned, its + values are only partially initialized. + +RESULT: + True if successful. False if the sparsity pattern of Src is not a + subset of that of Dst. + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool sparsetrygatherclear(sparsematrix* dst, + const sparsematrix* src, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t jj; + ae_int_t kk; + ae_int_t j1; + ae_int_t k1; + ae_bool result; + + + ae_assert(dst->matrixtype==1, "SparseTryGatherClear: Dst has incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(src->matrixtype==1, "SparseTryGatherClear: Src has incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(dst->m==src->m, "SparseTryGatherClear: Dst and Src have different row counts", _state); + ae_assert(dst->n==src->n, "SparseTryGatherClear: Dst and Src have different column counts", _state); + + /* + * Analyze and gather + */ + result = ae_true; + m = dst->m; + for(i=0; i<=m-1; i++) + { + jj = dst->ridx.ptr.p_int[i]; + kk = src->ridx.ptr.p_int[i]; + j1 = dst->ridx.ptr.p_int[i+1]-1; + k1 = src->ridx.ptr.p_int[i+1]-1; + while(jj<=j1&&kk<=k1) + { + if( dst->idx.ptr.p_int[jj]==src->idx.ptr.p_int[kk] ) + { + dst->vals.ptr.p_double[jj] = src->vals.ptr.p_double[kk]; + jj = jj+1; + kk = kk+1; + continue; + } + if( dst->idx.ptr.p_int[jj]idx.ptr.p_int[kk] ) + { + dst->vals.ptr.p_double[jj] = 0.0; + jj = jj+1; + continue; + } + result = ae_false; + return result; + } + if( kk<=k1 ) + { + result = ae_false; + return result; + } + while(jj<=j1) + { + dst->vals.ptr.p_double[jj] = 0.0; + jj = jj+1; + } + } + return result; +} + + +/************************************************************************* +This function merges sparsity patterns of S1 and S2 and stores result into +Dst, reusing previously allocated memory as much as possible. + +Both matrices must be in the CRS format and must have exactly the same +size. + +INPUT PARAMETERS + S1, S2 - sparse M*N source matrices in CRS format. + Dst - previously allocated sparse matrix structure in any + storage format and of any size. + +OUTPUT PARAMETERS + Dst - sparse M*N matrix in CRS format, zero-initialized, has + sparsity pattern equal to union of S1 and S2 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +void sparsemergepatterns(const sparsematrix* s1, + const sparsematrix* s2, + sparsematrix* dst, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t jj; + ae_int_t kk; + ae_int_t j1; + ae_int_t k1; + ae_int_t offs; + + + ae_assert(s1->matrixtype==1, "SparseMergePatterns: S1 has incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(s2->matrixtype==1, "SparseMergePatterns: S2 has incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(s1->m==s2->m, "SparseMergePatterns: S1 and S2 have different row counts", _state); + ae_assert(s1->n==s2->n, "SparseMergePatterns: S1 and S2 have different column counts", _state); + + /* + * Combine + */ + n = s1->n; + m = s1->m; + dst->matrixtype = 1; + dst->m = m; + dst->n = n; + iallocv(m+1, &dst->ridx, _state); + dst->ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=m-1; i++) + { + igrowv(offs+n, &dst->idx, _state); + jj = s1->ridx.ptr.p_int[i]; + kk = s2->ridx.ptr.p_int[i]; + j1 = s1->ridx.ptr.p_int[i+1]-1; + k1 = s2->ridx.ptr.p_int[i+1]-1; + while(jj<=j1&&kk<=k1) + { + if( s1->idx.ptr.p_int[jj]==s2->idx.ptr.p_int[kk] ) + { + dst->idx.ptr.p_int[offs] = s1->idx.ptr.p_int[jj]; + jj = jj+1; + kk = kk+1; + offs = offs+1; + continue; + } + if( s1->idx.ptr.p_int[jj]idx.ptr.p_int[kk] ) + { + dst->idx.ptr.p_int[offs] = s1->idx.ptr.p_int[jj]; + jj = jj+1; + offs = offs+1; + continue; + } + if( s1->idx.ptr.p_int[jj]>s2->idx.ptr.p_int[kk] ) + { + dst->idx.ptr.p_int[offs] = s2->idx.ptr.p_int[kk]; + kk = kk+1; + offs = offs+1; + continue; + } + } + while(jj<=j1) + { + dst->idx.ptr.p_int[offs] = s1->idx.ptr.p_int[jj]; + jj = jj+1; + offs = offs+1; + } + while(kk<=k1) + { + dst->idx.ptr.p_int[offs] = s2->idx.ptr.p_int[kk]; + kk = kk+1; + offs = offs+1; + } + dst->ridx.ptr.p_int[i+1] = offs; + } + rsetallocv(offs, 0.0, &dst->vals, _state); + dst->ninitialized = dst->ridx.ptr.p_int[dst->m]; + sparseinitduidx(dst, _state); +} + + +/************************************************************************* +Serializer: allocation. + +INTERNAL-ONLY FUNCTION, SUPPORTS ONLY CRS MATRICES + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsealloc(ae_serializer* s, + const sparsematrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nused; + + + ae_assert((a->matrixtype==0||a->matrixtype==1)||a->matrixtype==2, "SparseAlloc: only CRS/SKS matrices are supported", _state); + + /* + * Header + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + + /* + * Alloc other parameters + */ + if( a->matrixtype==0 ) + { + + /* + * Alloc Hash + */ + nused = 0; + for(i=0; i<=a->tablesize-1; i++) + { + if( a->idx.ptr.p_int[2*i+0]>=0 ) + { + nused = nused+1; + } + } + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + for(i=0; i<=a->tablesize-1; i++) + { + if( a->idx.ptr.p_int[2*i+0]>=0 ) + { + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + } + } + } + if( a->matrixtype==1 ) + { + + /* + * Alloc CRS + */ + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocintegerarray(s, &a->ridx, a->m+1, _state); + allocintegerarray(s, &a->idx, a->ridx.ptr.p_int[a->m], _state); + allocrealarray(s, &a->vals, a->ridx.ptr.p_int[a->m], _state); + } + if( a->matrixtype==2 ) + { + + /* + * Alloc SKS + */ + ae_assert(a->m==a->n, "SparseAlloc: rectangular SKS serialization is not supported", _state); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocintegerarray(s, &a->ridx, a->m+1, _state); + allocintegerarray(s, &a->didx, a->n+1, _state); + allocintegerarray(s, &a->uidx, a->n+1, _state); + allocrealarray(s, &a->vals, a->ridx.ptr.p_int[a->m], _state); + } + + /* + * End of stream + */ + ae_serializer_alloc_entry(s); +} + + +/************************************************************************* +Serializer: serialization + +INTERNAL-ONLY FUNCTION, SUPPORTS ONLY CRS MATRICES + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void sparseserialize(ae_serializer* s, + const sparsematrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nused; + + + ae_assert((a->matrixtype==0||a->matrixtype==1)||a->matrixtype==2, "SparseSerialize: only CRS/SKS matrices are supported", _state); + + /* + * Header + */ + ae_serializer_serialize_int(s, getsparsematrixserializationcode(_state), _state); + ae_serializer_serialize_int(s, a->matrixtype, _state); + ae_serializer_serialize_int(s, 0, _state); + + /* + * Serialize other parameters + */ + if( a->matrixtype==0 ) + { + + /* + * Serialize Hash + */ + nused = 0; + for(i=0; i<=a->tablesize-1; i++) + { + if( a->idx.ptr.p_int[2*i+0]>=0 ) + { + nused = nused+1; + } + } + ae_serializer_serialize_int(s, a->m, _state); + ae_serializer_serialize_int(s, a->n, _state); + ae_serializer_serialize_int(s, nused, _state); + for(i=0; i<=a->tablesize-1; i++) + { + if( a->idx.ptr.p_int[2*i+0]>=0 ) + { + ae_serializer_serialize_int(s, a->idx.ptr.p_int[2*i+0], _state); + ae_serializer_serialize_int(s, a->idx.ptr.p_int[2*i+1], _state); + ae_serializer_serialize_double(s, a->vals.ptr.p_double[i], _state); + } + } + } + if( a->matrixtype==1 ) + { + + /* + * Serialize CRS + */ + ae_serializer_serialize_int(s, a->m, _state); + ae_serializer_serialize_int(s, a->n, _state); + ae_serializer_serialize_int(s, a->ninitialized, _state); + serializeintegerarray(s, &a->ridx, a->m+1, _state); + serializeintegerarray(s, &a->idx, a->ridx.ptr.p_int[a->m], _state); + serializerealarray(s, &a->vals, a->ridx.ptr.p_int[a->m], _state); + } + if( a->matrixtype==2 ) + { + + /* + * Serialize SKS + */ + ae_assert(a->m==a->n, "SparseSerialize: rectangular SKS serialization is not supported", _state); + ae_serializer_serialize_int(s, a->m, _state); + ae_serializer_serialize_int(s, a->n, _state); + serializeintegerarray(s, &a->ridx, a->m+1, _state); + serializeintegerarray(s, &a->didx, a->n+1, _state); + serializeintegerarray(s, &a->uidx, a->n+1, _state); + serializerealarray(s, &a->vals, a->ridx.ptr.p_int[a->m], _state); + } + + /* + * End of stream + */ + ae_serializer_serialize_int(s, 117, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void sparseunserialize(ae_serializer* s, + sparsematrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t i0; + ae_int_t i1; + ae_int_t m; + ae_int_t n; + ae_int_t nused; + ae_int_t k; + double v; + + _sparsematrix_clear(a); + + + /* + * Check stream header: scode, matrix type, version type + */ + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==getsparsematrixserializationcode(_state), "SparseUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &a->matrixtype, _state); + ae_assert((a->matrixtype==0||a->matrixtype==1)||a->matrixtype==2, "SparseUnserialize: unexpected matrix type", _state); + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==0, "SparseUnserialize: stream header corrupted", _state); + + /* + * Unserialize other parameters + */ + if( a->matrixtype==0 ) + { + + /* + * Unerialize Hash + */ + ae_serializer_unserialize_int(s, &m, _state); + ae_serializer_unserialize_int(s, &n, _state); + ae_serializer_unserialize_int(s, &nused, _state); + sparsecreate(m, n, nused, a, _state); + for(i=0; i<=nused-1; i++) + { + ae_serializer_unserialize_int(s, &i0, _state); + ae_serializer_unserialize_int(s, &i1, _state); + ae_serializer_unserialize_double(s, &v, _state); + sparseset(a, i0, i1, v, _state); + } + } + if( a->matrixtype==1 ) + { + + /* + * Unserialize CRS + */ + ae_serializer_unserialize_int(s, &a->m, _state); + ae_serializer_unserialize_int(s, &a->n, _state); + ae_serializer_unserialize_int(s, &a->ninitialized, _state); + unserializeintegerarray(s, &a->ridx, _state); + unserializeintegerarray(s, &a->idx, _state); + unserializerealarray(s, &a->vals, _state); + sparseinitduidx(a, _state); + } + if( a->matrixtype==2 ) + { + + /* + * Unserialize SKS + */ + ae_serializer_unserialize_int(s, &a->m, _state); + ae_serializer_unserialize_int(s, &a->n, _state); + ae_assert(a->m==a->n, "SparseUnserialize: rectangular SKS unserialization is not supported", _state); + unserializeintegerarray(s, &a->ridx, _state); + unserializeintegerarray(s, &a->didx, _state); + unserializeintegerarray(s, &a->uidx, _state); + unserializerealarray(s, &a->vals, _state); + } + + /* + * End of stream + */ + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==117, "SparseMatrixUnserialize: end-of-stream marker not found", _state); +} + + +/************************************************************************* +dot product of a dense vector with the matrix row +*************************************************************************/ +double spdotvr(/* Real */ const ae_vector* x, + const sparsematrix* s, + ae_int_t r, + ae_state *_state) +{ + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double result; + + + ae_assert((s->matrixtype==1&&s->m>=1)&&s->n>=1, "SQP: integrity check 5541 failed", _state); + result = 0.0; + j0 = s->ridx.ptr.p_int[r]; + j1 = s->ridx.ptr.p_int[r+1]-1; + for(jj=j0; jj<=j1; jj++) + { + result = result+x->ptr.p_double[s->idx.ptr.p_int[jj]]*s->vals.ptr.p_double[jj]; + } + return result; +} + + +/************************************************************************* +dot product of a dense vector with the matrix row +*************************************************************************/ +double spdotr2(const sparsematrix* s, ae_int_t r, ae_state *_state) +{ + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double result; + + + ae_assert((s->matrixtype==1&&s->m>=1)&&s->n>=1, "SQP: integrity check 5541 failed", _state); + result = 0.0; + j0 = s->ridx.ptr.p_int[r]; + j1 = s->ridx.ptr.p_int[r+1]-1; + for(jj=j0; jj<=j1; jj++) + { + result = result+s->vals.ptr.p_double[jj]*s->vals.ptr.p_double[jj]; + } + return result; +} + + +/************************************************************************* +This is hash function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t sparse_hash(ae_int_t i, + ae_int_t j, + ae_int_t tabsize, + ae_state *_state) +{ + ae_frame _frame_block; + hqrndstate r; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&r, 0, sizeof(r)); + _hqrndstate_init(&r, _state, ae_true); + + hqrndseed(i, j, &r, _state); + result = hqrnduniformi(&r, tabsize, _state); + ae_frame_leave(_state); + return result; +} + + +void _sparsebuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sparsebuffers *p = (sparsebuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->d, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->u, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->s, _state, make_automatic); +} + + +void _sparsebuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sparsebuffers *dst = (sparsebuffers*)_dst; + const sparsebuffers *src = (const sparsebuffers*)_src; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->u, &src->u, _state, make_automatic); + _sparsematrix_init_copy(&dst->s, &src->s, _state, make_automatic); +} + + +void _sparsebuffers_clear(void* _p) +{ + sparsebuffers *p = (sparsebuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->d); + ae_vector_clear(&p->u); + _sparsematrix_clear(&p->s); +} + + +void _sparsebuffers_destroy(void* _p) +{ + sparsebuffers *p = (sparsebuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->u); + _sparsematrix_destroy(&p->s); +} + + +#endif +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) + + +void rmatrixinternalschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_matrix h1; + ae_matrix z1; + ae_vector wr1; + ae_vector wi1; + + ae_frame_make(_state, &_frame_block); + memset(&h1, 0, sizeof(h1)); + memset(&z1, 0, sizeof(z1)); + memset(&wr1, 0, sizeof(wr1)); + memset(&wi1, 0, sizeof(wi1)); + ae_vector_clear(wr); + ae_vector_clear(wi); + *info = 0; + ae_matrix_init(&h1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z1, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wr1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wi1, 0, DT_REAL, _state, ae_true); + + + /* + * Allocate space + */ + ae_vector_set_length(wr, n, _state); + ae_vector_set_length(wi, n, _state); + if( zneeded==2 ) + { + rmatrixsetlengthatleast(z, n, n, _state); + } + + /* + * PBL version + */ + if( rmatrixinternalschurdecompositionpbl(h, n, tneeded, zneeded, wr, wi, z, info, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + ae_matrix_set_length(&h1, n+1, n+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + h1.ptr.pp_double[1+i][1+j] = h->ptr.pp_double[i][j]; + } + } + if( zneeded==1 ) + { + ae_matrix_set_length(&z1, n+1, n+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + z1.ptr.pp_double[1+i][1+j] = z->ptr.pp_double[i][j]; + } + } + } + internalschurdecomposition(&h1, n, tneeded, zneeded, &wr1, &wi1, &z1, info, _state); + for(i=0; i<=n-1; i++) + { + wr->ptr.p_double[i] = wr1.ptr.p_double[i+1]; + wi->ptr.p_double[i] = wi1.ptr.p_double[i+1]; + } + if( tneeded!=0 ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + h->ptr.pp_double[i][j] = h1.ptr.pp_double[1+i][1+j]; + } + } + } + if( zneeded!=0 ) + { + rmatrixsetlengthatleast(z, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + z->ptr.pp_double[i][j] = z1.ptr.pp_double[1+i][1+j]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Subroutine performing the Schur decomposition of a matrix in upper +Hessenberg form using the QR algorithm with multiple shifts. + +The source matrix H is represented as S'*H*S = T, where H - matrix in +upper Hessenberg form, S - orthogonal matrix (Schur vectors), T - upper +quasi-triangular matrix (with blocks of sizes 1x1 and 2x2 on the main +diagonal). + +Input parameters: + H - matrix to be decomposed. + Array whose indexes range within [1..N, 1..N]. + N - size of H, N>=0. + + +Output parameters: + H - contains the matrix T. + Array whose indexes range within [1..N, 1..N]. + All elements below the blocks on the main diagonal are equal + to 0. + S - contains Schur vectors. + Array whose indexes range within [1..N, 1..N]. + +Note 1: + The block structure of matrix T could be easily recognized: since all + the elements below the blocks are zeros, the elements a[i+1,i] which + are equal to 0 show the block border. + +Note 2: + the algorithm performance depends on the value of the internal + parameter NS of InternalSchurDecomposition subroutine which defines + the number of shifts in the QR algorithm (analog of the block width + in block matrix algorithms in linear algebra). If you require maximum + performance on your machine, it is recommended to adjust this + parameter manually. + +Result: + True, if the algorithm has converged and the parameters H and S contain + the result. + False, if the algorithm has not converged. + +Algorithm implemented on the basis of subroutine DHSEQR (LAPACK 3.0 library). +*************************************************************************/ +ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + /* Real */ ae_matrix* s, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector wi; + ae_vector wr; + ae_int_t info; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&wi, 0, sizeof(wi)); + memset(&wr, 0, sizeof(wr)); + ae_matrix_clear(s); + ae_vector_init(&wi, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wr, 0, DT_REAL, _state, ae_true); + + internalschurdecomposition(h, n, 1, 2, &wr, &wi, s, &info, _state); + result = info==0; + ae_frame_leave(_state); + return result; +} + + +void internalschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_int_t i; + ae_int_t i1; + ae_int_t i2; + ae_int_t ierr; + ae_int_t ii; + ae_int_t itemp; + ae_int_t itn; + ae_int_t its; + ae_int_t j; + ae_int_t k; + ae_int_t l; + ae_int_t maxb; + ae_int_t nr; + ae_int_t ns; + ae_int_t nv; + double absw; + double smlnum; + double tau; + double temp; + double tst1; + double ulp; + double unfl; + ae_matrix s; + ae_vector v; + ae_vector vv; + ae_vector workc1; + ae_vector works1; + ae_vector workv3; + ae_vector tmpwr; + ae_vector tmpwi; + ae_bool initz; + ae_bool wantt; + ae_bool wantz; + double cnst; + ae_bool failflag; + ae_int_t p1; + ae_int_t p2; + double vt; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + memset(&s, 0, sizeof(s)); + memset(&v, 0, sizeof(v)); + memset(&vv, 0, sizeof(vv)); + memset(&workc1, 0, sizeof(workc1)); + memset(&works1, 0, sizeof(works1)); + memset(&workv3, 0, sizeof(workv3)); + memset(&tmpwr, 0, sizeof(tmpwr)); + memset(&tmpwi, 0, sizeof(tmpwi)); + ae_vector_clear(wr); + ae_vector_clear(wi); + *info = 0; + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&s, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&v, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vv, 0, DT_REAL, _state, ae_true); + ae_vector_init(&workc1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&works1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&workv3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpwr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpwi, 0, DT_REAL, _state, ae_true); + + + /* + * Set the order of the multi-shift QR algorithm to be used. + * If you want to tune algorithm, change this values + */ + ns = 12; + maxb = 50; + + /* + * Now 2 < NS <= MAXB < NH. + */ + maxb = ae_maxint(3, maxb, _state); + ns = ae_minint(maxb, ns, _state); + + /* + * Initialize + */ + cnst = 1.5; + ae_vector_set_length(&work, ae_maxint(n, 1, _state)+1, _state); + ae_matrix_set_length(&s, ns+1, ns+1, _state); + ae_vector_set_length(&v, ns+1+1, _state); + ae_vector_set_length(&vv, ns+1+1, _state); + ae_vector_set_length(wr, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(wi, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&workc1, 1+1, _state); + ae_vector_set_length(&works1, 1+1, _state); + ae_vector_set_length(&workv3, 3+1, _state); + ae_vector_set_length(&tmpwr, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&tmpwi, ae_maxint(n, 1, _state)+1, _state); + ae_assert(n>=0, "InternalSchurDecomposition: incorrect N!", _state); + ae_assert(tneeded==0||tneeded==1, "InternalSchurDecomposition: incorrect TNeeded!", _state); + ae_assert((zneeded==0||zneeded==1)||zneeded==2, "InternalSchurDecomposition: incorrect ZNeeded!", _state); + wantt = tneeded==1; + initz = zneeded==2; + wantz = zneeded!=0; + *info = 0; + + /* + * Initialize Z, if necessary + */ + if( initz ) + { + rmatrixsetlengthatleast(z, n+1, n+1, _state); + for(i=1; i<=n; i++) + { + for(j=1; j<=n; j++) + { + if( i==j ) + { + z->ptr.pp_double[i][j] = (double)(1); + } + else + { + z->ptr.pp_double[i][j] = (double)(0); + } + } + } + } + + /* + * Quick return if possible + */ + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + wr->ptr.p_double[1] = h->ptr.pp_double[1][1]; + wi->ptr.p_double[1] = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Set rows and columns 1 to N to zero below the first + * subdiagonal. + */ + for(j=1; j<=n-2; j++) + { + for(i=j+2; i<=n; i++) + { + h->ptr.pp_double[i][j] = (double)(0); + } + } + + /* + * Test if N is sufficiently small + */ + if( (ns<=2||ns>n)||maxb>=n ) + { + + /* + * Use the standard double-shift algorithm + */ + hsschur_internalauxschur(wantt, wantz, n, 1, n, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); + + /* + * fill entries under diagonal blocks of T with zeros + */ + if( wantt ) + { + j = 1; + while(j<=n) + { + if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) + { + for(i=j+1; i<=n; i++) + { + h->ptr.pp_double[i][j] = (double)(0); + } + j = j+1; + } + else + { + for(i=j+2; i<=n; i++) + { + h->ptr.pp_double[i][j] = (double)(0); + h->ptr.pp_double[i][j+1] = (double)(0); + } + j = j+2; + } + } + } + ae_frame_leave(_state); + return; + } + unfl = ae_minrealnumber; + ulp = (double)2*ae_machineepsilon; + smlnum = unfl*((double)n/ulp); + + /* + * I1 and I2 are the indices of the first row and last column of H + * to which transformations must be applied. If eigenvalues only are + * being computed, I1 and I2 are set inside the main loop. + */ + i1 = 1; + i2 = n; + + /* + * ITN is the total number of multiple-shift QR iterations allowed. + */ + itn = 30*n; + + /* + * The main loop begins here. I is the loop index and decreases from + * IHI to ILO in steps of at most MAXB. Each iteration of the loop + * works with the active submatrix in rows and columns L to I. + * Eigenvalues I+1 to IHI have already converged. Either L = ILO or + * H(L,L-1) is negligible so that the matrix splits. + */ + i = n; + for(;;) + { + l = 1; + if( i<1 ) + { + + /* + * fill entries under diagonal blocks of T with zeros + */ + if( wantt ) + { + j = 1; + while(j<=n) + { + if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) + { + for(i=j+1; i<=n; i++) + { + h->ptr.pp_double[i][j] = (double)(0); + } + j = j+1; + } + else + { + for(i=j+2; i<=n; i++) + { + h->ptr.pp_double[i][j] = (double)(0); + h->ptr.pp_double[i][j+1] = (double)(0); + } + j = j+2; + } + } + } + + /* + * Exit + */ + ae_frame_leave(_state); + return; + } + + /* + * Perform multiple-shift QR iterations on rows and columns ILO to I + * until a submatrix of order at most MAXB splits off at the bottom + * because a subdiagonal element has become negligible. + */ + failflag = ae_true; + for(its=0; its<=itn; its++) + { + + /* + * Look for a single small subdiagonal element. + */ + for(k=i; k>=l+1; k--) + { + tst1 = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); + if( ae_fp_eq(tst1,(double)(0)) ) + { + tst1 = upperhessenberg1norm(h, l, i, l, i, &work, _state); + } + if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ae_maxreal(ulp*tst1, smlnum, _state)) ) + { + break; + } + } + l = k; + if( l>1 ) + { + + /* + * H(L,L-1) is negligible. + */ + h->ptr.pp_double[l][l-1] = (double)(0); + } + + /* + * Exit from loop if a submatrix of order <= MAXB has split off. + */ + if( l>=i-maxb+1 ) + { + failflag = ae_false; + break; + } + + /* + * Now the active submatrix is in rows and columns L to I. If + * eigenvalues only are being computed, only the active submatrix + * need be transformed. + */ + if( its==20||its==30 ) + { + + /* + * Exceptional shifts. + */ + for(ii=i-ns+1; ii<=i; ii++) + { + wr->ptr.p_double[ii] = cnst*(ae_fabs(h->ptr.pp_double[ii][ii-1], _state)+ae_fabs(h->ptr.pp_double[ii][ii], _state)); + wi->ptr.p_double[ii] = (double)(0); + } + } + else + { + + /* + * Use eigenvalues of trailing submatrix of order NS as shifts. + */ + copymatrix(h, i-ns+1, i, i-ns+1, i, &s, 1, ns, 1, ns, _state); + hsschur_internalauxschur(ae_false, ae_false, ns, 1, ns, &s, &tmpwr, &tmpwi, 1, ns, z, &work, &workv3, &workc1, &works1, &ierr, _state); + for(p1=1; p1<=ns; p1++) + { + wr->ptr.p_double[i-ns+p1] = tmpwr.ptr.p_double[p1]; + wi->ptr.p_double[i-ns+p1] = tmpwi.ptr.p_double[p1]; + } + if( ierr>0 ) + { + + /* + * If DLAHQR failed to compute all NS eigenvalues, use the + * unconverged diagonal elements as the remaining shifts. + */ + for(ii=1; ii<=ierr; ii++) + { + wr->ptr.p_double[i-ns+ii] = s.ptr.pp_double[ii][ii]; + wi->ptr.p_double[i-ns+ii] = (double)(0); + } + } + } + + /* + * Form the first column of (G-w(1)) (G-w(2)) . . . (G-w(ns)) + * where G is the Hessenberg submatrix H(L:I,L:I) and w is + * the vector of shifts (stored in WR and WI). The result is + * stored in the local array V. + */ + v.ptr.p_double[1] = (double)(1); + for(ii=2; ii<=ns+1; ii++) + { + v.ptr.p_double[ii] = (double)(0); + } + nv = 1; + for(j=i-ns+1; j<=i; j++) + { + if( ae_fp_greater_eq(wi->ptr.p_double[j],(double)(0)) ) + { + if( ae_fp_eq(wi->ptr.p_double[j],(double)(0)) ) + { + + /* + * real shift + */ + p1 = nv+1; + ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); + matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &vv, 1, nv, 1.0, &v, 1, nv+1, -wr->ptr.p_double[j], _state); + nv = nv+1; + } + else + { + if( ae_fp_greater(wi->ptr.p_double[j],(double)(0)) ) + { + + /* + * complex conjugate pair of shifts + */ + p1 = nv+1; + ae_v_move(&vv.ptr.p_double[1], 1, &v.ptr.p_double[1], 1, ae_v_len(1,p1)); + matrixvectormultiply(h, l, l+nv, l, l+nv-1, ae_false, &v, 1, nv, 1.0, &vv, 1, nv+1, -(double)2*wr->ptr.p_double[j], _state); + itemp = vectoridxabsmax(&vv, 1, nv+1, _state); + temp = (double)1/ae_maxreal(ae_fabs(vv.ptr.p_double[itemp], _state), smlnum, _state); + p1 = nv+1; + ae_v_muld(&vv.ptr.p_double[1], 1, ae_v_len(1,p1), temp); + absw = pythag2(wr->ptr.p_double[j], wi->ptr.p_double[j], _state); + temp = temp*absw*absw; + matrixvectormultiply(h, l, l+nv+1, l, l+nv, ae_false, &vv, 1, nv+1, 1.0, &v, 1, nv+2, temp, _state); + nv = nv+2; + } + } + + /* + * Scale V(1:NV) so that max(abs(V(i))) = 1. If V is zero, + * reset it to the unit vector. + */ + itemp = vectoridxabsmax(&v, 1, nv, _state); + temp = ae_fabs(v.ptr.p_double[itemp], _state); + if( ae_fp_eq(temp,(double)(0)) ) + { + v.ptr.p_double[1] = (double)(1); + for(ii=2; ii<=nv; ii++) + { + v.ptr.p_double[ii] = (double)(0); + } + } + else + { + temp = ae_maxreal(temp, smlnum, _state); + vt = (double)1/temp; + ae_v_muld(&v.ptr.p_double[1], 1, ae_v_len(1,nv), vt); + } + } + } + + /* + * Multiple-shift QR step + */ + for(k=l; k<=i-1; k++) + { + + /* + * The first iteration of this loop determines a reflection G + * from the vector V and applies it from left and right to H, + * thus creating a nonzero bulge below the subdiagonal. + * + * Each subsequent iteration determines a reflection G to + * restore the Hessenberg form in the (K-1)th column, and thus + * chases the bulge one step toward the bottom of the active + * submatrix. NR is the order of G. + */ + nr = ae_minint(ns+1, i-k+1, _state); + if( k>l ) + { + p1 = k-1; + p2 = k+nr-1; + ae_v_move(&v.ptr.p_double[1], 1, &h->ptr.pp_double[k][p1], h->stride, ae_v_len(1,nr)); + touchint(&p2, _state); + } + generatereflection(&v, nr, &tau, _state); + if( k>l ) + { + h->ptr.pp_double[k][k-1] = v.ptr.p_double[1]; + for(ii=k+1; ii<=i; ii++) + { + h->ptr.pp_double[ii][k-1] = (double)(0); + } + } + v.ptr.p_double[1] = (double)(1); + + /* + * Apply G from the left to transform the rows of the matrix in + * columns K to I2. + */ + applyreflectionfromtheleft(h, tau, &v, k, k+nr-1, k, i2, &work, _state); + + /* + * Apply G from the right to transform the columns of the + * matrix in rows I1 to min(K+NR,I). + */ + applyreflectionfromtheright(h, tau, &v, i1, ae_minint(k+nr, i, _state), k, k+nr-1, &work, _state); + if( wantz ) + { + + /* + * Accumulate transformations in the matrix Z + */ + applyreflectionfromtheright(z, tau, &v, 1, n, k, k+nr-1, &work, _state); + } + } + } + + /* + * Failure to converge in remaining number of iterations + */ + if( failflag ) + { + *info = i; + ae_frame_leave(_state); + return; + } + + /* + * A submatrix of order <= MAXB in rows and columns L to I has split + * off. Use the double-shift QR algorithm to handle it. + */ + hsschur_internalauxschur(wantt, wantz, n, l, i, h, wr, wi, 1, n, z, &work, &workv3, &workc1, &works1, info, _state); + if( *info>0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Decrement number of remaining iterations, and return to start of + * the main loop with a new value of I. + */ + itn = itn-its; + i = l-1; + + /* + * Block below is never executed; it is necessary just to avoid + * "unreachable code" warning about automatically generated code. + * + * We just need a way to transfer control to the end of the function, + * even a fake way which is never actually traversed. + */ + if( alwaysfalse(_state) ) + { + ae_assert(ae_false, "Assertion failed", _state); + break; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Translation of DLAHQR from LAPACK. +*************************************************************************/ +static void hsschur_internalauxschur(ae_bool wantt, + ae_bool wantz, + ae_int_t n, + ae_int_t ilo, + ae_int_t ihi, + /* Real */ ae_matrix* h, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + ae_int_t iloz, + ae_int_t ihiz, + /* Real */ ae_matrix* z, + /* Real */ ae_vector* work, + /* Real */ ae_vector* workv3, + /* Real */ ae_vector* workc1, + /* Real */ ae_vector* works1, + ae_int_t* info, + ae_state *_state) +{ + double safmin; + double tst; + double ab; + double ba; + double aa; + double bb; + double rt1r; + double rt1i; + double rt2r; + double rt2i; + double tr; + double det; + double rtdisc; + double h21s; + ae_int_t i; + ae_int_t i1; + ae_int_t i2; + ae_int_t itmax; + ae_int_t its; + ae_int_t j; + ae_int_t k; + ae_int_t l; + ae_int_t m; + ae_int_t nh; + ae_int_t nr; + ae_int_t nz; + double cs; + double h11; + double h12; + double h21; + double h22; + double s; + double smlnum; + double sn; + double sum; + double t1; + double t2; + double t3; + double v2; + double v3; + ae_bool failflag; + double dat1; + double dat2; + ae_int_t p1; + double him1im1; + double him1i; + double hiim1; + double hii; + double wrim1; + double wri; + double wiim1; + double wii; + double ulp; + + *info = 0; + + *info = 0; + dat1 = 0.75; + dat2 = -0.4375; + + /* + * Quick return if possible + */ + if( n==0 ) + { + return; + } + if( ilo==ihi ) + { + wr->ptr.p_double[ilo] = h->ptr.pp_double[ilo][ilo]; + wi->ptr.p_double[ilo] = (double)(0); + return; + } + + /* + * ==== clear out the trash ==== + */ + for(j=ilo; j<=ihi-3; j++) + { + h->ptr.pp_double[j+2][j] = (double)(0); + h->ptr.pp_double[j+3][j] = (double)(0); + } + if( ilo<=ihi-2 ) + { + h->ptr.pp_double[ihi][ihi-2] = (double)(0); + } + nh = ihi-ilo+1; + nz = ihiz-iloz+1; + + /* + * Set machine-dependent constants for the stopping criterion. + */ + safmin = ae_minrealnumber; + ulp = ae_machineepsilon; + smlnum = safmin*((double)nh/ulp); + + /* + * I1 and I2 are the indices of the first row and last column of H + * to which transformations must be applied. If eigenvalues only are + * being computed, I1 and I2 are set inside the main loop. + * + * Setting them to large negative value helps to debug possible errors + * due to uninitialized variables; also it helps to avoid compiler + * warnings. + */ + i1 = -99999; + i2 = -99999; + if( wantt ) + { + i1 = 1; + i2 = n; + } + + /* + * ITMAX is the total number of QR iterations allowed. + */ + itmax = 30*ae_maxint(10, nh, _state); + + /* + * The main loop begins here. I is the loop index and decreases from + * IHI to ILO in steps of 1 or 2. Each iteration of the loop works + * with the active submatrix in rows and columns L to I. + * Eigenvalues I+1 to IHI have already converged. Either L = ILO or + * H(L,L-1) is negligible so that the matrix splits. + */ + i = ihi; + for(;;) + { + l = ilo; + if( i=l+1; k--) + { + if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),smlnum) ) + { + break; + } + tst = ae_fabs(h->ptr.pp_double[k-1][k-1], _state)+ae_fabs(h->ptr.pp_double[k][k], _state); + if( ae_fp_eq(tst,(double)(0)) ) + { + if( k-2>=ilo ) + { + tst = tst+ae_fabs(h->ptr.pp_double[k-1][k-2], _state); + } + if( k+1<=ihi ) + { + tst = tst+ae_fabs(h->ptr.pp_double[k+1][k], _state); + } + } + + /* + * ==== The following is a conservative small subdiagonal + * . deflation criterion due to Ahues & Tisseur (LAWN 122, + * . 1997). It has better mathematical foundation and + * . improves accuracy in some cases. ==== + */ + if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[k][k-1], _state),ulp*tst) ) + { + ab = ae_maxreal(ae_fabs(h->ptr.pp_double[k][k-1], _state), ae_fabs(h->ptr.pp_double[k-1][k], _state), _state); + ba = ae_minreal(ae_fabs(h->ptr.pp_double[k][k-1], _state), ae_fabs(h->ptr.pp_double[k-1][k], _state), _state); + aa = ae_maxreal(ae_fabs(h->ptr.pp_double[k][k], _state), ae_fabs(h->ptr.pp_double[k-1][k-1]-h->ptr.pp_double[k][k], _state), _state); + bb = ae_minreal(ae_fabs(h->ptr.pp_double[k][k], _state), ae_fabs(h->ptr.pp_double[k-1][k-1]-h->ptr.pp_double[k][k], _state), _state); + s = aa+ab; + if( ae_fp_less_eq(ba*(ab/s),ae_maxreal(smlnum, ulp*(bb*(aa/s)), _state)) ) + { + break; + } + } + } + l = k; + if( l>ilo ) + { + + /* + * H(L,L-1) is negligible + */ + h->ptr.pp_double[l][l-1] = (double)(0); + } + + /* + * Exit from loop if a submatrix of order 1 or 2 has split off. + */ + if( l>=i-1 ) + { + failflag = ae_false; + break; + } + + /* + * Now the active submatrix is in rows and columns L to I. If + * eigenvalues only are being computed, only the active submatrix + * need be transformed. + */ + if( !wantt ) + { + i1 = l; + i2 = i; + } + + /* + * Shifts + */ + if( its==10 ) + { + + /* + * Exceptional shift. + */ + s = ae_fabs(h->ptr.pp_double[l+1][l], _state)+ae_fabs(h->ptr.pp_double[l+2][l+1], _state); + h11 = dat1*s+h->ptr.pp_double[l][l]; + h12 = dat2*s; + h21 = s; + h22 = h11; + } + else + { + if( its==20 ) + { + + /* + * Exceptional shift. + */ + s = ae_fabs(h->ptr.pp_double[i][i-1], _state)+ae_fabs(h->ptr.pp_double[i-1][i-2], _state); + h11 = dat1*s+h->ptr.pp_double[i][i]; + h12 = dat2*s; + h21 = s; + h22 = h11; + } + else + { + + /* + * Prepare to use Francis' double shift + * (i.e. 2nd degree generalized Rayleigh quotient) + */ + h11 = h->ptr.pp_double[i-1][i-1]; + h21 = h->ptr.pp_double[i][i-1]; + h12 = h->ptr.pp_double[i-1][i]; + h22 = h->ptr.pp_double[i][i]; + } + } + s = ae_fabs(h11, _state)+ae_fabs(h12, _state)+ae_fabs(h21, _state)+ae_fabs(h22, _state); + if( ae_fp_eq(s,(double)(0)) ) + { + rt1r = (double)(0); + rt1i = (double)(0); + rt2r = (double)(0); + rt2i = (double)(0); + } + else + { + h11 = h11/s; + h21 = h21/s; + h12 = h12/s; + h22 = h22/s; + tr = (h11+h22)/(double)2; + det = (h11-tr)*(h22-tr)-h12*h21; + rtdisc = ae_sqrt(ae_fabs(det, _state), _state); + if( ae_fp_greater_eq(det,(double)(0)) ) + { + + /* + * ==== complex conjugate shifts ==== + */ + rt1r = tr*s; + rt2r = rt1r; + rt1i = rtdisc*s; + rt2i = -rt1i; + } + else + { + + /* + * ==== real shifts (use only one of them) ==== + */ + rt1r = tr+rtdisc; + rt2r = tr-rtdisc; + if( ae_fp_less_eq(ae_fabs(rt1r-h22, _state),ae_fabs(rt2r-h22, _state)) ) + { + rt1r = rt1r*s; + rt2r = rt1r; + } + else + { + rt2r = rt2r*s; + rt1r = rt2r; + } + rt1i = (double)(0); + rt2i = (double)(0); + } + } + + /* + * Look for two consecutive small subdiagonal elements. + */ + for(m=i-2; m>=l; m--) + { + + /* + * Determine the effect of starting the double-shift QR + * iteration at row M, and see if this would make H(M,M-1) + * negligible. (The following uses scaling to avoid + * overflows and most underflows.) + */ + h21s = h->ptr.pp_double[m+1][m]; + s = ae_fabs(h->ptr.pp_double[m][m]-rt2r, _state)+ae_fabs(rt2i, _state)+ae_fabs(h21s, _state); + h21s = h->ptr.pp_double[m+1][m]/s; + workv3->ptr.p_double[1] = h21s*h->ptr.pp_double[m][m+1]+(h->ptr.pp_double[m][m]-rt1r)*((h->ptr.pp_double[m][m]-rt2r)/s)-rt1i*(rt2i/s); + workv3->ptr.p_double[2] = h21s*(h->ptr.pp_double[m][m]+h->ptr.pp_double[m+1][m+1]-rt1r-rt2r); + workv3->ptr.p_double[3] = h21s*h->ptr.pp_double[m+2][m+1]; + s = ae_fabs(workv3->ptr.p_double[1], _state)+ae_fabs(workv3->ptr.p_double[2], _state)+ae_fabs(workv3->ptr.p_double[3], _state); + workv3->ptr.p_double[1] = workv3->ptr.p_double[1]/s; + workv3->ptr.p_double[2] = workv3->ptr.p_double[2]/s; + workv3->ptr.p_double[3] = workv3->ptr.p_double[3]/s; + if( m==l ) + { + break; + } + if( ae_fp_less_eq(ae_fabs(h->ptr.pp_double[m][m-1], _state)*(ae_fabs(workv3->ptr.p_double[2], _state)+ae_fabs(workv3->ptr.p_double[3], _state)),ulp*ae_fabs(workv3->ptr.p_double[1], _state)*(ae_fabs(h->ptr.pp_double[m-1][m-1], _state)+ae_fabs(h->ptr.pp_double[m][m], _state)+ae_fabs(h->ptr.pp_double[m+1][m+1], _state))) ) + { + break; + } + } + + /* + * Double-shift QR step + */ + for(k=m; k<=i-1; k++) + { + + /* + * The first iteration of this loop determines a reflection G + * from the vector V and applies it from left and right to H, + * thus creating a nonzero bulge below the subdiagonal. + * + * Each subsequent iteration determines a reflection G to + * restore the Hessenberg form in the (K-1)th column, and thus + * chases the bulge one step toward the bottom of the active + * submatrix. NR is the order of G. + */ + nr = ae_minint(3, i-k+1, _state); + if( k>m ) + { + for(p1=1; p1<=nr; p1++) + { + workv3->ptr.p_double[p1] = h->ptr.pp_double[k+p1-1][k-1]; + } + } + generatereflection(workv3, nr, &t1, _state); + if( k>m ) + { + h->ptr.pp_double[k][k-1] = workv3->ptr.p_double[1]; + h->ptr.pp_double[k+1][k-1] = (double)(0); + if( kptr.pp_double[k+2][k-1] = (double)(0); + } + } + else + { + if( m>l ) + { + + /* + * ==== Use the following instead of + * H( K, K-1 ) = -H( K, K-1 ) to + * avoid a bug when v(2) and v(3) + * underflow. ==== + */ + h->ptr.pp_double[k][k-1] = h->ptr.pp_double[k][k-1]*((double)1-t1); + } + } + v2 = workv3->ptr.p_double[2]; + t2 = t1*v2; + if( nr==3 ) + { + v3 = workv3->ptr.p_double[3]; + t3 = t1*v3; + + /* + * Apply G from the left to transform the rows of the matrix + * in columns K to I2. + */ + for(j=k; j<=i2; j++) + { + sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]+v3*h->ptr.pp_double[k+2][j]; + h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; + h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; + h->ptr.pp_double[k+2][j] = h->ptr.pp_double[k+2][j]-sum*t3; + } + + /* + * Apply G from the right to transform the columns of the + * matrix in rows I1 to min(K+3,I). + */ + for(j=i1; j<=ae_minint(k+3, i, _state); j++) + { + sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]+v3*h->ptr.pp_double[j][k+2]; + h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; + h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; + h->ptr.pp_double[j][k+2] = h->ptr.pp_double[j][k+2]-sum*t3; + } + if( wantz ) + { + + /* + * Accumulate transformations in the matrix Z + */ + for(j=iloz; j<=ihiz; j++) + { + sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]+v3*z->ptr.pp_double[j][k+2]; + z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; + z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; + z->ptr.pp_double[j][k+2] = z->ptr.pp_double[j][k+2]-sum*t3; + } + } + } + else + { + if( nr==2 ) + { + + /* + * Apply G from the left to transform the rows of the matrix + * in columns K to I2. + */ + for(j=k; j<=i2; j++) + { + sum = h->ptr.pp_double[k][j]+v2*h->ptr.pp_double[k+1][j]; + h->ptr.pp_double[k][j] = h->ptr.pp_double[k][j]-sum*t1; + h->ptr.pp_double[k+1][j] = h->ptr.pp_double[k+1][j]-sum*t2; + } + + /* + * Apply G from the right to transform the columns of the + * matrix in rows I1 to min(K+3,I). + */ + for(j=i1; j<=i; j++) + { + sum = h->ptr.pp_double[j][k]+v2*h->ptr.pp_double[j][k+1]; + h->ptr.pp_double[j][k] = h->ptr.pp_double[j][k]-sum*t1; + h->ptr.pp_double[j][k+1] = h->ptr.pp_double[j][k+1]-sum*t2; + } + if( wantz ) + { + + /* + * Accumulate transformations in the matrix Z + */ + for(j=iloz; j<=ihiz; j++) + { + sum = z->ptr.pp_double[j][k]+v2*z->ptr.pp_double[j][k+1]; + z->ptr.pp_double[j][k] = z->ptr.pp_double[j][k]-sum*t1; + z->ptr.pp_double[j][k+1] = z->ptr.pp_double[j][k+1]-sum*t2; + } + } + } + } + } + } + + /* + * Failure to converge in remaining number of iterations + */ + if( failflag ) + { + *info = i; + return; + } + + /* + * Convergence + */ + if( l==i ) + { + + /* + * H(I,I-1) is negligible: one eigenvalue has converged. + */ + wr->ptr.p_double[i] = h->ptr.pp_double[i][i]; + wi->ptr.p_double[i] = (double)(0); + } + else + { + if( l==i-1 ) + { + + /* + * H(I-1,I-2) is negligible: a pair of eigenvalues have converged. + * + * Transform the 2-by-2 submatrix to standard Schur form, + * and compute and store the eigenvalues. + */ + him1im1 = h->ptr.pp_double[i-1][i-1]; + him1i = h->ptr.pp_double[i-1][i]; + hiim1 = h->ptr.pp_double[i][i-1]; + hii = h->ptr.pp_double[i][i]; + hsschur_aux2x2schur(&him1im1, &him1i, &hiim1, &hii, &wrim1, &wiim1, &wri, &wii, &cs, &sn, _state); + wr->ptr.p_double[i-1] = wrim1; + wi->ptr.p_double[i-1] = wiim1; + wr->ptr.p_double[i] = wri; + wi->ptr.p_double[i] = wii; + h->ptr.pp_double[i-1][i-1] = him1im1; + h->ptr.pp_double[i-1][i] = him1i; + h->ptr.pp_double[i][i-1] = hiim1; + h->ptr.pp_double[i][i] = hii; + if( wantt ) + { + + /* + * Apply the transformation to the rest of H. + */ + if( i2>i ) + { + workc1->ptr.p_double[1] = cs; + works1->ptr.p_double[1] = sn; + applyrotationsfromtheleft(ae_true, i-1, i, i+1, i2, workc1, works1, h, work, _state); + } + workc1->ptr.p_double[1] = cs; + works1->ptr.p_double[1] = sn; + applyrotationsfromtheright(ae_true, i1, i-2, i-1, i, workc1, works1, h, work, _state); + } + if( wantz ) + { + + /* + * Apply the transformation to Z. + */ + workc1->ptr.p_double[1] = cs; + works1->ptr.p_double[1] = sn; + applyrotationsfromtheright(ae_true, iloz, iloz+nz-1, i-1, i, workc1, works1, z, work, _state); + } + } + } + + /* + * return to start of the main loop with new value of I. + */ + i = l-1; + } +} + + +static void hsschur_aux2x2schur(double* a, + double* b, + double* c, + double* d, + double* rt1r, + double* rt1i, + double* rt2r, + double* rt2i, + double* cs, + double* sn, + ae_state *_state) +{ + double multpl; + double aa; + double bb; + double bcmax; + double bcmis; + double cc; + double cs1; + double dd; + double eps; + double p; + double sab; + double sac; + double scl; + double sigma; + double sn1; + double tau; + double temp; + double z; + + *rt1r = 0.0; + *rt1i = 0.0; + *rt2r = 0.0; + *rt2i = 0.0; + *cs = 0.0; + *sn = 0.0; + + multpl = 4.0; + eps = ae_machineepsilon; + if( ae_fp_eq(*c,(double)(0)) ) + { + *cs = (double)(1); + *sn = (double)(0); + } + else + { + if( ae_fp_eq(*b,(double)(0)) ) + { + + /* + * Swap rows and columns + */ + *cs = (double)(0); + *sn = (double)(1); + temp = *d; + *d = *a; + *a = temp; + *b = -*c; + *c = (double)(0); + } + else + { + if( ae_fp_eq(*a-(*d),(double)(0))&&hsschur_extschursigntoone(*b, _state)!=hsschur_extschursigntoone(*c, _state) ) + { + *cs = (double)(1); + *sn = (double)(0); + } + else + { + temp = *a-(*d); + p = 0.5*temp; + bcmax = ae_maxreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state); + bcmis = ae_minreal(ae_fabs(*b, _state), ae_fabs(*c, _state), _state)*(double)hsschur_extschursigntoone(*b, _state)*(double)hsschur_extschursigntoone(*c, _state); + scl = ae_maxreal(ae_fabs(p, _state), bcmax, _state); + z = p/scl*p+bcmax/scl*bcmis; + + /* + * If Z is of the order of the machine accuracy, postpone the + * decision on the nature of eigenvalues + */ + if( ae_fp_greater_eq(z,multpl*eps) ) + { + + /* + * Real eigenvalues. Compute A and D. + */ + z = p+hsschur_extschursign(ae_sqrt(scl, _state)*ae_sqrt(z, _state), p, _state); + *a = *d+z; + *d = *d-bcmax/z*bcmis; + + /* + * Compute B and the rotation matrix + */ + tau = pythag2(*c, z, _state); + *cs = z/tau; + *sn = *c/tau; + *b = *b-(*c); + *c = (double)(0); + } + else + { + + /* + * Complex eigenvalues, or real (almost) equal eigenvalues. + * Make diagonal elements equal. + */ + sigma = *b+(*c); + tau = pythag2(sigma, temp, _state); + *cs = ae_sqrt(0.5*((double)1+ae_fabs(sigma, _state)/tau), _state); + *sn = -p/(tau*(*cs))*hsschur_extschursign((double)(1), sigma, _state); + + /* + * Compute [ AA BB ] = [ A B ] [ CS -SN ] + * [ CC DD ] [ C D ] [ SN CS ] + */ + aa = *a*(*cs)+*b*(*sn); + bb = -*a*(*sn)+*b*(*cs); + cc = *c*(*cs)+*d*(*sn); + dd = -*c*(*sn)+*d*(*cs); + + /* + * Compute [ A B ] = [ CS SN ] [ AA BB ] + * [ C D ] [-SN CS ] [ CC DD ] + */ + *a = aa*(*cs)+cc*(*sn); + *b = bb*(*cs)+dd*(*sn); + *c = -aa*(*sn)+cc*(*cs); + *d = -bb*(*sn)+dd*(*cs); + temp = 0.5*(*a+(*d)); + *a = temp; + *d = temp; + if( ae_fp_neq(*c,(double)(0)) ) + { + if( ae_fp_neq(*b,(double)(0)) ) + { + if( hsschur_extschursigntoone(*b, _state)==hsschur_extschursigntoone(*c, _state) ) + { + + /* + * Real eigenvalues: reduce to upper triangular form + */ + sab = ae_sqrt(ae_fabs(*b, _state), _state); + sac = ae_sqrt(ae_fabs(*c, _state), _state); + p = hsschur_extschursign(sab*sac, *c, _state); + tau = (double)1/ae_sqrt(ae_fabs(*b+(*c), _state), _state); + *a = temp+p; + *d = temp-p; + *b = *b-(*c); + *c = (double)(0); + cs1 = sab*tau; + sn1 = sac*tau; + temp = *cs*cs1-*sn*sn1; + *sn = *cs*sn1+*sn*cs1; + *cs = temp; + } + } + else + { + *b = -*c; + *c = (double)(0); + temp = *cs; + *cs = -*sn; + *sn = temp; + } + } + } + } + } + } + + /* + * Store eigenvalues in (RT1R,RT1I) and (RT2R,RT2I). + */ + *rt1r = *a; + *rt2r = *d; + if( ae_fp_eq(*c,(double)(0)) ) + { + *rt1i = (double)(0); + *rt2i = (double)(0); + } + else + { + *rt1i = ae_sqrt(ae_fabs(*b, _state), _state)*ae_sqrt(ae_fabs(*c, _state), _state); + *rt2i = -*rt1i; + } +} + + +static double hsschur_extschursign(double a, double b, ae_state *_state) +{ + double result; + + + if( ae_fp_greater_eq(b,(double)(0)) ) + { + result = ae_fabs(a, _state); + } + else + { + result = -ae_fabs(a, _state); + } + return result; +} + + +static ae_int_t hsschur_extschursigntoone(double b, ae_state *_state) +{ + ae_int_t result; + + + if( ae_fp_greater_eq(b,(double)(0)) ) + { + result = 1; + } + else + { + result = -1; + } + return result; +} + + +#endif +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes subspace iteration solver. This solver is used +to solve symmetric real eigenproblems where just a few (top K) eigenvalues +and corresponding eigenvectors is required. + +This solver can be significantly faster than complete EVD decomposition +in the following case: +* when only just a small fraction of top eigenpairs of dense matrix is + required. When K approaches N, this solver is slower than complete dense + EVD +* when problem matrix is sparse (and/or is not known explicitly, i.e. only + matrix-matrix product can be performed) + +USAGE (explicit dense/sparse matrix): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User calls eigsubspacesolvedense() or eigsubspacesolvesparse() methods, + which take algorithm state and 2D array or alglib.sparsematrix object. + +USAGE (out-of-core mode): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User activates out-of-core mode of the solver and repeatedly calls + communication functions in a loop like below: + > alglib.eigsubspaceoocstart(state) + > while alglib.eigsubspaceooccontinue(state) do + > alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) + > alglib.eigsubspaceoocgetrequestdata(state, out X) + > [calculate Y=A*X, with X=R^NxM] + > alglib.eigsubspaceoocsendresult(state, in Y) + > alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + N - problem dimensionality, N>0 + K - number of top eigenvector to calculate, 00, "EigSubspaceCreate: N<=0", _state); + ae_assert(k>0, "EigSubspaceCreate: K<=0", _state); + ae_assert(k<=n, "EigSubspaceCreate: K>N", _state); + eigsubspacecreatebuf(n, k, state, _state); +} + + +/************************************************************************* +Buffered version of constructor which aims to reuse previously allocated +memory as much as possible. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacecreatebuf(ae_int_t n, + ae_int_t k, + eigsubspacestate* state, + ae_state *_state) +{ + + + ae_assert(n>0, "EigSubspaceCreate: N<=0", _state); + ae_assert(k>0, "EigSubspaceCreate: K<=0", _state); + ae_assert(k<=n, "EigSubspaceCreate: K>N", _state); + + /* + * Initialize algorithm parameters + */ + state->running = ae_false; + state->n = n; + state->k = k; + state->nwork = ae_minint(ae_maxint(2*k, 8, _state), n, _state); + state->eigenvectorsneeded = 1; + state->usewarmstart = ae_false; + state->firstcall = ae_true; + eigsubspacesetcond(state, 0.0, 0, _state); + + /* + * Allocate temporaries + */ + rmatrixsetlengthatleast(&state->x, state->n, state->nwork, _state); + rmatrixsetlengthatleast(&state->ax, state->n, state->nwork, _state); +} + + +/************************************************************************* +This function sets stopping critera for the solver: +* error in eigenvector/value allowed by solver +* maximum number of iterations to perform + +INPUT PARAMETERS: + State - solver structure + Eps - eps>=0, with non-zero value used to tell solver that + it can stop after all eigenvalues converged with + error roughly proportional to eps*MAX(LAMBDA_MAX), + where LAMBDA_MAX is a maximum eigenvalue. + Zero value means that no check for precision is + performed. + MaxIts - maxits>=0, with non-zero value used to tell solver + that it can stop after maxits steps (no matter how + precise current estimate is) + +NOTE: passing eps=0 and maxits=0 results in automatic selection of + moderate eps as stopping criteria (1.0E-6 in current implementation, + but it may change without notice). + +NOTE: very small values of eps are possible (say, 1.0E-12), although the + larger problem you solve (N and/or K), the harder it is to find + precise eigenvectors because rounding errors tend to accumulate. + +NOTE: passing non-zero eps results in some performance penalty, roughly + equal to 2N*(2K)^2 FLOPs per iteration. These additional computations + are required in order to estimate current error in eigenvalues via + Rayleigh-Ritz process. + Most of this additional time is spent in construction of ~2Kx2K + symmetric subproblem whose eigenvalues are checked with exact + eigensolver. + This additional time is negligible if you search for eigenvalues of + the large dense matrix, but may become noticeable on highly sparse + EVD problems, where cost of matrix-matrix product is low. + If you set eps to exactly zero, Rayleigh-Ritz phase is completely + turned off. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetcond(eigsubspacestate* state, + double eps, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(!state->running, "EigSubspaceSetCond: solver is already running", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "EigSubspaceSetCond: Eps<0 or NAN/INF", _state); + ae_assert(maxits>=0, "EigSubspaceSetCond: MaxIts<0", _state); + if( ae_fp_eq(eps,(double)(0))&&maxits==0 ) + { + eps = 1.0E-6; + } + state->eps = eps; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets warm-start mode of the solver: next call to the solver +will reuse previous subspace as warm-start point. It can significantly +speed-up convergence when you solve many similar eigenproblems. + +INPUT PARAMETERS: + State - solver structure + UseWarmStart- either True or False + + -- ALGLIB -- + Copyright 12.11.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetwarmstart(eigsubspacestate* state, + ae_bool usewarmstart, + ae_state *_state) +{ + + + ae_assert(!state->running, "EigSubspaceSetWarmStart: solver is already running", _state); + state->usewarmstart = usewarmstart; +} + + +/************************************************************************* +This function initiates out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver object + MType - matrix type and solver mode: + + * 0 = real symmetric matrix A, products of the form + A*X are computed. At every step the basis of + the invariant subspace is reorthogonalized + with LQ decomposition which makes the algo + more robust. + + The first mode introduced in ALGLIB, the most + precise and robust. However, it is suboptimal + for easy problems which can be solved in 3-5 + iterations without LQ step. + + * 1 = real symmetric matrix A, products of the form + A*X are computed. The invariant subspace is + NOT reorthogonalized, no error checks. The + solver stops after specified number of + iterations which should be small, 5 at most. + + This mode is intended for easy problems with + extremely fast convergence. + + Future versions of ALGLIB may introduce support for + other matrix types; for now, only symmetric + eigenproblems are supported. + + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstart(eigsubspacestate* state, + ae_int_t mtype, + ae_state *_state) +{ + + + ae_assert(!state->running, "EigSubspaceStart: solver is already running", _state); + ae_assert(mtype==0||mtype==1, "EigSubspaceStart: incorrect mtype parameter", _state); + ae_vector_set_length(&state->rstate.ia, 8+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; + evd_clearrfields(state, _state); + state->running = ae_true; + state->solvermode = mtype; +} + + +/************************************************************************* +This function performs subspace iteration in the out-of-core mode. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +ae_bool eigsubspaceooccontinue(eigsubspacestate* state, ae_state *_state) +{ + ae_bool result; + + + ae_assert(state->running, "EigSubspaceContinue: solver is not running", _state); + result = eigsubspaceiteration(state, _state); + state->running = result; + return result; +} + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: request type (current version of the solver +sends only requests for matrix-matrix products) and request size (size of +the matrices being multiplied). + +This function returns just request metrics; in order to get contents of +the matrices being multiplied, use eigsubspaceoocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 - for matrix-matrix product A*X, with A being + NxN matrix whose eigenvalues/vectors are needed, + and X being NxREQUESTSIZE one which is returned + by the eigsubspaceoocgetrequestdata(). + RequestSize - size of the X matrix (number of columns), usually + it is several times larger than number of vectors + K requested by user. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestinfo(eigsubspacestate* state, + ae_int_t* requesttype, + ae_int_t* requestsize, + ae_state *_state) +{ + + *requesttype = 0; + *requestsize = 0; + + ae_assert(state->running, "EigSubspaceOOCGetRequestInfo: solver is not running", _state); + *requesttype = state->requesttype; + *requestsize = state->requestsize; +} + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: matrix X (array[N,RequestSize) which have to +be multiplied by out-of-core matrix A in a product A*X. + +This function returns just request data; in order to get size of the data +prior to processing requestm, use eigsubspaceoocgetrequestinfo(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N,RequestSize] or larger, leading rectangle + is filled with dense matrix X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestdata(eigsubspacestate* state, + /* Real */ ae_matrix* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(state->running, "EigSubspaceOOCGetRequestInfo: solver is not running", _state); + rmatrixsetlengthatleast(x, state->n, state->requestsize, _state); + for(i=0; i<=state->n-1; i++) + { + for(j=0; j<=state->requestsize-1; j++) + { + x->ptr.pp_double[i][j] = state->x.ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +solver. Usually it is product A*X for returned by solver matrix X. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N,RequestSize] or larger, leading rectangle + is filled with product A*X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocsendresult(eigsubspacestate* state, + /* Real */ const ae_matrix* ax, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(state->running, "EigSubspaceOOCGetRequestInfo: solver is not running", _state); + for(i=0; i<=state->n-1; i++) + { + for(j=0; j<=state->requestsize-1; j++) + { + state->ax.ptr.pp_double[i][j] = ax->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function finalizes out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + W - array[K], depending on solver settings: + * top K eigenvalues ordered by descending - if + eigenvectors are returned in Z + * zeros - if invariant subspace is returned in Z + Z - array[N,K], depending on solver settings either: + * matrix of eigenvectors found + * orthogonal basis of K-dimensional invariant subspace + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstop(eigsubspacestate* state, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + + ae_vector_clear(w); + ae_matrix_clear(z); + _eigsubspacereport_clear(rep); + + ae_assert(!state->running, "EigSubspaceStop: solver is still running", _state); + n = state->n; + k = state->k; + ae_vector_set_length(w, k, _state); + ae_matrix_set_length(z, n, k, _state); + for(i=0; i<=k-1; i++) + { + w->ptr.p_double[i] = state->rw.ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + z->ptr.pp_double[i][j] = state->rq.ptr.pp_double[i][j]; + } + } + rep->iterationscount = state->repiterationscount; +} + + +/************************************************************************* +This function runs subspace eigensolver for dense NxN symmetric matrix A, +given by its upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - array[N,N], symmetric NxN matrix given by one of its + triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + +NOTE: internally this function allocates a copy of NxN dense A. You should + take it into account when working with very large matrices occupying + almost all RAM. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvedenses(eigsubspacestate* state, + /* Real */ const ae_matrix* a, + ae_bool isupper, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_int_t prevmode; + ae_matrix acopy; + + ae_frame_make(_state, &_frame_block); + memset(&acopy, 0, sizeof(acopy)); + ae_vector_clear(w); + ae_matrix_clear(z); + _eigsubspacereport_clear(rep); + ae_matrix_init(&acopy, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(!state->running, "EigSubspaceSolveDenseS: solver is still running", _state); + n = state->n; + + /* + * Allocate copy of A, copy one triangle to another + */ + ae_matrix_set_length(&acopy, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + if( isupper ) + { + v = a->ptr.pp_double[i][j]; + } + else + { + v = a->ptr.pp_double[j][i]; + } + acopy.ptr.pp_double[i][j] = v; + acopy.ptr.pp_double[j][i] = v; + } + } + + /* + * Start iterations + */ + prevmode = state->solvermode; + state->solvermode = 0; + ae_vector_set_length(&state->rstate.ia, 8+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; + evd_clearrfields(state, _state); + while(eigsubspaceiteration(state, _state)) + { + + /* + * Calculate A*X with RMatrixGEMM + */ + ae_assert(state->requesttype==0, "EigSubspaceSolveDense: integrity check failed", _state); + ae_assert(state->requestsize>0, "EigSubspaceSolveDense: integrity check failed", _state); + m = state->requestsize; + rmatrixgemm(n, m, n, 1.0, &acopy, 0, 0, 0, &state->x, 0, 0, 0, 0.0, &state->ax, 0, 0, _state); + } + state->solvermode = prevmode; + k = state->k; + ae_vector_set_length(w, k, _state); + ae_matrix_set_length(z, n, k, _state); + for(i=0; i<=k-1; i++) + { + w->ptr.p_double[i] = state->rw.ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + z->ptr.pp_double[i][j] = state->rq.ptr.pp_double[i][j]; + } + } + rep->iterationscount = state->repiterationscount; + ae_frame_leave(_state); +} + + +/************************************************************************* +This function runs eigensolver for dense NxN symmetric matrix A, given by +upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - NxN symmetric matrix given by one of its triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvesparses(eigsubspacestate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t prevmode; + + ae_vector_clear(w); + ae_matrix_clear(z); + _eigsubspacereport_clear(rep); + + ae_assert(!state->running, "EigSubspaceSolveSparseS: solver is still running", _state); + n = state->n; + prevmode = state->solvermode; + state->solvermode = 0; + ae_vector_set_length(&state->rstate.ia, 8+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; + evd_clearrfields(state, _state); + while(eigsubspaceiteration(state, _state)) + { + ae_assert(state->requesttype==0, "EigSubspaceSolveDense: integrity check failed", _state); + ae_assert(state->requestsize>0, "EigSubspaceSolveDense: integrity check failed", _state); + sparsesmm(a, isupper, &state->x, state->requestsize, &state->ax, _state); + } + state->solvermode = prevmode; + k = state->k; + ae_vector_set_length(w, k, _state); + ae_matrix_set_length(z, n, k, _state); + for(i=0; i<=k-1; i++) + { + w->ptr.p_double[i] = state->rw.ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=k-1; j++) + { + z->ptr.pp_double[i][j] = state->rq.ptr.pp_double[i][j]; + } + } + rep->iterationscount = state->repiterationscount; +} + + +/************************************************************************* +Internal r-comm function. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +ae_bool eigsubspaceiteration(eigsubspacestate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t nwork; + ae_int_t k; + ae_int_t cnt; + ae_int_t i; + ae_int_t i1; + ae_int_t j; + double vv; + double v; + ae_int_t convcnt; + ae_int_t iterationtype; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + nwork = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + cnt = state->rstate.ia.ptr.p_int[3]; + i = state->rstate.ia.ptr.p_int[4]; + i1 = state->rstate.ia.ptr.p_int[5]; + j = state->rstate.ia.ptr.p_int[6]; + convcnt = state->rstate.ia.ptr.p_int[7]; + iterationtype = state->rstate.ia.ptr.p_int[8]; + vv = state->rstate.ra.ptr.p_double[0]; + v = state->rstate.ra.ptr.p_double[1]; + } + else + { + n = 359; + nwork = -58; + k = -919; + cnt = -909; + i = 81; + i1 = 255; + j = 74; + convcnt = -788; + iterationtype = 809; + vv = 205.0; + v = -838.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + n = state->n; + k = state->k; + nwork = state->nwork; + + /* + * Initialize RNG. Deterministic initialization (with fixed + * seed) is required because we need deterministic behavior + * of the entire solver. + */ + hqrndseed(453, 463664, &state->rs, _state); + + /* + * Analyze solver mode. + * + * IterationType: + * * 0 for LQ-based reorthogonalization with checks + * * 1 for a quick algo without checks or reorthogonalizations + */ + ae_assert(state->solvermode==0||state->solvermode==1, "EigSubspaceIteration: unexpected MatrixType", _state); + iterationtype = 0; + if( state->solvermode==1 ) + { + iterationtype = 1; + } + + /* + * Prepare iteration + * Initialize QNew with random orthogonal matrix (or reuse its previous value). + */ + state->repiterationscount = 0; + rmatrixsetlengthatleast(&state->qcur, nwork, n, _state); + rmatrixsetlengthatleast(&state->qnew, nwork, n, _state); + rmatrixsetlengthatleast(&state->znew, nwork, n, _state); + rvectorsetlengthatleast(&state->wcur, nwork, _state); + rvectorsetlengthatleast(&state->wprev, nwork, _state); + rvectorsetlengthatleast(&state->wrank, nwork, _state); + rmatrixsetlengthatleast(&state->x, n, nwork, _state); + rmatrixsetlengthatleast(&state->ax, n, nwork, _state); + rmatrixsetlengthatleast(&state->rq, n, k, _state); + rvectorsetlengthatleast(&state->rw, k, _state); + rmatrixsetlengthatleast(&state->rz, nwork, k, _state); + rmatrixsetlengthatleast(&state->r, nwork, nwork, _state); + for(i=0; i<=nwork-1; i++) + { + state->wprev.ptr.p_double[i] = -1.0; + } + if( !state->usewarmstart||state->firstcall ) + { + + /* + * Use Q0 (either no warm start request, or warm start was + * requested by user - but it is first call). + * + */ + if( state->firstcall ) + { + + /* + * First call, generate Q0 + */ + for(i=0; i<=nwork-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->znew.ptr.pp_double[i][j] = hqrnduniformr(&state->rs, _state)-0.5; + } + } + rmatrixlq(&state->znew, nwork, n, &state->tau, _state); + rmatrixlqunpackq(&state->znew, nwork, n, &state->tau, nwork, &state->q0, _state); + state->firstcall = ae_false; + } + rmatrixcopy(nwork, n, &state->q0, 0, 0, &state->qnew, 0, 0, _state); + } + + /* + * Start iteration + */ + state->repiterationscount = 0; + if( iterationtype!=0 ) + { + goto lbl_3; + } + + /* + * Iterations with reorthogonalization and quick checks + */ + convcnt = 0; +lbl_5: + if( !((state->maxits==0||state->repiterationscountmaxits)&&convcntqnew, 0, 0, &state->qcur, 0, 0, _state); + rmatrixtranspose(nwork, n, &state->qcur, 0, 0, &state->x, 0, 0, _state); + evd_clearrfields(state, _state); + state->requesttype = 0; + state->requestsize = nwork; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + + /* + * Perform Rayleigh-Ritz step to estimate convergence of diagonal eigenvalues + */ + if( ae_fp_greater(state->eps,(double)(0)) ) + { + ae_assert(state->solvermode==0, "EigSubspace: integrity check failed", _state); + rmatrixsetlengthatleast(&state->r, nwork, nwork, _state); + rmatrixgemm(nwork, nwork, n, 1.0, &state->qcur, 0, 0, 0, &state->ax, 0, 0, 0, 0.0, &state->r, 0, 0, _state); + if( !smatrixevd(&state->r, nwork, 0, ae_true, &state->wcur, &state->dummy, _state) ) + { + ae_assert(ae_false, "EigSubspace: direct eigensolver failed to converge", _state); + } + for(j=0; j<=nwork-1; j++) + { + state->wrank.ptr.p_double[j] = ae_fabs(state->wcur.ptr.p_double[j], _state); + } + rankxuntied(&state->wrank, nwork, &state->buf, _state); + v = (double)(0); + vv = (double)(0); + for(j=0; j<=nwork-1; j++) + { + if( ae_fp_greater_eq(state->wrank.ptr.p_double[j],(double)(nwork-k)) ) + { + v = ae_maxreal(v, ae_fabs(state->wcur.ptr.p_double[j]-state->wprev.ptr.p_double[j], _state), _state); + vv = ae_maxreal(vv, ae_fabs(state->wcur.ptr.p_double[j], _state), _state); + } + } + if( ae_fp_eq(vv,(double)(0)) ) + { + vv = (double)(1); + } + if( ae_fp_less_eq(v,state->eps*vv) ) + { + inc(&convcnt, _state); + } + else + { + convcnt = 0; + } + for(j=0; j<=nwork-1; j++) + { + state->wprev.ptr.p_double[j] = state->wcur.ptr.p_double[j]; + } + } + + /* + * QR renormalization and update of QNew + */ + rmatrixtranspose(n, nwork, &state->ax, 0, 0, &state->znew, 0, 0, _state); + rmatrixlq(&state->znew, nwork, n, &state->tau, _state); + rmatrixlqunpackq(&state->znew, nwork, n, &state->tau, nwork, &state->qnew, _state); + + /* + * Update iteration index + */ + state->repiterationscount = state->repiterationscount+1; + goto lbl_5; +lbl_6: +lbl_3: + if( iterationtype!=1 ) + { + goto lbl_7; + } + + /* + * Quick iterations without reorthogonalization, stopping after prescribed amount of its, no checks. + * + * First, we perform CNT-1 iterations without any reorthogonalization + */ +lbl_9: + if( ae_fp_greater_eq((double)(state->repiterationscount),coalesce((double)(state->maxits), (double)(5), _state)-(double)1) ) + { + goto lbl_10; + } + + /* + * Update QCur := QNew + * + * Calculate A*Q', store to QNew + */ + rmatrixtranspose(nwork, n, &state->qnew, 0, 0, &state->x, 0, 0, _state); + evd_clearrfields(state, _state); + state->requesttype = 0; + state->requestsize = nwork; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rmatrixtranspose(n, nwork, &state->ax, 0, 0, &state->qnew, 0, 0, _state); + state->repiterationscount = state->repiterationscount+1; + goto lbl_9; +lbl_10: + + /* + * Perform one iteration with reorthogonalization at the end + */ + rallocv(n, &state->tmprow, _state); + for(i=0; i<=nwork-1; i++) + { + rcopyrv(n, &state->qnew, i, &state->tmprow, _state); + v = ae_sqrt(rdotv2(n, &state->tmprow, _state), _state); + rowwisegramschmidt(&state->qnew, i, n, &state->tmprow, &state->tmprow, ae_false, _state); + vv = ae_sqrt(rdotv2(n, &state->tmprow, _state), _state); + while(ae_fp_eq(v,(double)(0))||ae_fp_less_eq(vv,(double)1000*ae_machineepsilon*v)) + { + for(j=0; j<=n-1; j++) + { + state->tmprow.ptr.p_double[j] = hqrnduniformr(&state->rs, _state)-0.5; + } + v = ae_sqrt(rdotv2(n, &state->tmprow, _state), _state); + rowwisegramschmidt(&state->qnew, i, n, &state->tmprow, &state->tmprow, ae_false, _state); + vv = ae_sqrt(rdotv2(n, &state->tmprow, _state), _state); + } + rmulv(n, (double)1/vv, &state->tmprow, _state); + rcopyvr(n, &state->tmprow, &state->qnew, i, _state); + } + rmatrixcopy(nwork, n, &state->qnew, 0, 0, &state->qcur, 0, 0, _state); + rmatrixtranspose(nwork, n, &state->qcur, 0, 0, &state->x, 0, 0, _state); + evd_clearrfields(state, _state); + state->requesttype = 0; + state->requestsize = nwork; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->repiterationscount = state->repiterationscount+1; +lbl_7: + + /* + * Perform Rayleigh-Ritz step: find true eigenpairs in NWork-dimensional + * subspace. + */ + ae_assert(state->eigenvectorsneeded==1, "Assertion failed", _state); + rmatrixgemm(nwork, nwork, n, 1.0, &state->qcur, 0, 0, 0, &state->ax, 0, 0, 0, 0.0, &state->r, 0, 0, _state); + if( !smatrixevd(&state->r, nwork, 1, ae_true, &state->tw, &state->tz, _state) ) + { + ae_assert(ae_false, "EigSubspace: direct eigensolver failed to converge", _state); + } + + /* + * Reorder eigenpairs according to their absolute magnitude, select + * K top ones. This reordering algorithm is very inefficient and has + * O(NWork*K) running time, but it is still faster than other parts + * of the solver, so we may use it. + * + * Then, we transform RZ to RQ (full N-dimensional representation). + * After this part is done, RW and RQ contain solution. + */ + for(j=0; j<=nwork-1; j++) + { + state->wrank.ptr.p_double[j] = ae_fabs(state->tw.ptr.p_double[j], _state); + } + rankxuntied(&state->wrank, nwork, &state->buf, _state); + cnt = 0; + for(i=nwork-1; i>=nwork-k; i--) + { + for(i1=0; i1<=nwork-1; i1++) + { + if( ae_fp_eq(state->wrank.ptr.p_double[i1],(double)(i)) ) + { + ae_assert(cntrw.ptr.p_double[cnt] = state->tw.ptr.p_double[i1]; + for(j=0; j<=nwork-1; j++) + { + state->rz.ptr.pp_double[j][cnt] = state->tz.ptr.pp_double[j][i1]; + } + cnt = cnt+1; + } + } + } + ae_assert(cnt==k, "EigSubspace: integrity check failed", _state); + rmatrixgemm(n, k, nwork, 1.0, &state->qcur, 0, 0, 1, &state->rz, 0, 0, 0, 0.0, &state->rq, 0, 0, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = nwork; + state->rstate.ia.ptr.p_int[2] = k; + state->rstate.ia.ptr.p_int[3] = cnt; + state->rstate.ia.ptr.p_int[4] = i; + state->rstate.ia.ptr.p_int[5] = i1; + state->rstate.ia.ptr.p_int[6] = j; + state->rstate.ia.ptr.p_int[7] = convcnt; + state->rstate.ia.ptr.p_int[8] = iterationtype; + state->rstate.ra.ptr.p_double[0] = vv; + state->rstate.ra.ptr.p_double[1] = v; + return result; +} + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a symmetric matrix + +The algorithm finds eigen pairs of a symmetric matrix by reducing it to +tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpper - storage format. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector tau; + ae_vector e; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(d); + ae_matrix_clear(z); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "SMatrixEVD: incorrect ZNeeded", _state); + smatrixtd(&a, n, isupper, &tau, d, &e, _state); + if( zneeded==1 ) + { + smatrixtdunpackq(&a, n, isupper, &tau, z, _state); + } + result = smatrixtdevd(d, &e, n, zneeded, z, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric +matrix in a given half open interval (A, B] by using a bisection and +inverse iteration + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half open interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval (M>=0). + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, + M is equal to 0. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixevdr(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + double b1, + double b2, + ae_int_t* m, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector tau; + ae_vector e; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + *m = 0; + ae_vector_clear(w); + ae_matrix_clear(z); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "SMatrixTDEVDR: incorrect ZNeeded", _state); + smatrixtd(&a, n, isupper, &tau, w, &e, _state); + if( zneeded==1 ) + { + smatrixtdunpackq(&a, n, isupper, &tau, z, _state); + } + result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, z, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a symmetric +matrix with given indexes by using bisection and inverse iteration methods. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixevdi(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector tau; + ae_vector e; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(w); + ae_matrix_clear(z); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "SMatrixEVDI: incorrect ZNeeded", _state); + smatrixtd(&a, n, isupper, &tau, w, &e, _state); + if( zneeded==1 ) + { + smatrixtdunpackq(&a, n, isupper, &tau, z, _state); + } + result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, z, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a Hermitian matrix + +The algorithm finds eigen pairs of a Hermitian matrix by reducing it to +real tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +Note: + eigenvectors of Hermitian matrix are defined up to multiplication by + a complex number L, such that |L|=1. + + -- ALGLIB -- + Copyright 2005, 23 March 2007 by Bochkanov Sergey +*************************************************************************/ +ae_bool hmatrixevd(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + /* Real */ ae_vector* d, + /* Complex */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector tau; + ae_vector e; + ae_matrix t; + ae_matrix qz; + ae_matrix q; + ae_int_t i; + ae_int_t j; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + memset(&t, 0, sizeof(t)); + memset(&qz, 0, sizeof(qz)); + memset(&q, 0, sizeof(q)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(d); + ae_matrix_clear(z); + ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&qz, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "HermitianEVD: incorrect ZNeeded", _state); + + /* + * Reduce to tridiagonal form + */ + hmatrixtd(&a, n, isupper, &tau, d, &e, _state); + if( zneeded==1 ) + { + hmatrixtdunpackq(&a, n, isupper, &tau, &q, _state); + zneeded = 2; + } + + /* + * TDEVD + */ + result = smatrixtdevd(d, &e, n, zneeded, &t, _state); + + /* + * Eigenvectors are needed + * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T + */ + if( result&&zneeded!=0 ) + { + ae_matrix_set_length(z, n, n, _state); + ae_matrix_set_length(&qz, n, 2*n, _state); + + /* + * Calculate Re(Q)*T + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + qz.ptr.pp_double[i][j] = q.ptr.pp_complex[i][j].x; + } + } + rmatrixgemm(n, n, n, 1.0, &qz, 0, 0, 0, &t, 0, 0, 0, 0.0, &qz, 0, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + z->ptr.pp_complex[i][j].x = qz.ptr.pp_double[i][n+j]; + } + } + + /* + * Calculate Im(Q)*T + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + qz.ptr.pp_double[i][j] = q.ptr.pp_complex[i][j].y; + } + } + rmatrixgemm(n, n, n, 1.0, &qz, 0, 0, 0, &t, 0, 0, 0, 0.0, &qz, 0, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + z->ptr.pp_complex[i][j].y = qz.ptr.pp_double[i][n+j]; + } + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian +matrix in a given half-interval (A, B] by using a bisection and inverse +iteration + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. Array whose indexes range within + [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half-interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval, M>=0 + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, M is + equal to 0. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +ae_bool hmatrixevdr(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + double b1, + double b2, + ae_int_t* m, + /* Real */ ae_vector* w, + /* Complex */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix q; + ae_matrix t; + ae_vector tau; + ae_vector e; + ae_vector work; + ae_int_t i; + ae_int_t k; + double v; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&q, 0, sizeof(q)); + memset(&t, 0, sizeof(t)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + memset(&work, 0, sizeof(work)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + *m = 0; + ae_vector_clear(w); + ae_matrix_clear(z); + ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsInInterval: incorrect ZNeeded", _state); + + /* + * Reduce to tridiagonal form + */ + hmatrixtd(&a, n, isupper, &tau, w, &e, _state); + if( zneeded==1 ) + { + hmatrixtdunpackq(&a, n, isupper, &tau, &q, _state); + zneeded = 2; + } + + /* + * Bisection and inverse iteration + */ + result = smatrixtdevdr(w, &e, n, zneeded, b1, b2, m, &t, _state); + + /* + * Eigenvectors are needed + * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T + */ + if( (result&&zneeded!=0)&&*m!=0 ) + { + ae_vector_set_length(&work, *m-1+1, _state); + ae_matrix_set_length(z, n-1+1, *m-1+1, _state); + for(i=0; i<=n-1; i++) + { + + /* + * Calculate real part + */ + for(k=0; k<=*m-1; k++) + { + work.ptr.p_double[k] = (double)(0); + } + for(k=0; k<=n-1; k++) + { + v = q.ptr.pp_complex[i][k].x; + ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); + } + for(k=0; k<=*m-1; k++) + { + z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; + } + + /* + * Calculate imaginary part + */ + for(k=0; k<=*m-1; k++) + { + work.ptr.p_double[k] = (double)(0); + } + for(k=0; k<=n-1; k++) + { + v = q.ptr.pp_complex[i][k].y; + ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,*m-1), v); + } + for(k=0; k<=*m-1; k++) + { + z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; + } + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a Hermitian +matrix with given indexes by using bisection and inverse iteration methods + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix + columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +ae_bool hmatrixevdi(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_vector* w, + /* Complex */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix q; + ae_matrix t; + ae_vector tau; + ae_vector e; + ae_vector work; + ae_int_t i; + ae_int_t k; + double v; + ae_int_t m; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&q, 0, sizeof(q)); + memset(&t, 0, sizeof(t)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + memset(&work, 0, sizeof(work)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(w); + ae_matrix_clear(z); + ae_matrix_init(&q, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded==0||zneeded==1, "HermitianEigenValuesAndVectorsByIndexes: incorrect ZNeeded", _state); + + /* + * Reduce to tridiagonal form + */ + hmatrixtd(&a, n, isupper, &tau, w, &e, _state); + if( zneeded==1 ) + { + hmatrixtdunpackq(&a, n, isupper, &tau, &q, _state); + zneeded = 2; + } + + /* + * Bisection and inverse iteration + */ + result = smatrixtdevdi(w, &e, n, zneeded, i1, i2, &t, _state); + + /* + * Eigenvectors are needed + * Calculate Z = Q*T = Re(Q)*T + i*Im(Q)*T + */ + m = i2-i1+1; + if( result&&zneeded!=0 ) + { + ae_vector_set_length(&work, m-1+1, _state); + ae_matrix_set_length(z, n-1+1, m-1+1, _state); + for(i=0; i<=n-1; i++) + { + + /* + * Calculate real part + */ + for(k=0; k<=m-1; k++) + { + work.ptr.p_double[k] = (double)(0); + } + for(k=0; k<=n-1; k++) + { + v = q.ptr.pp_complex[i][k].x; + ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); + } + for(k=0; k<=m-1; k++) + { + z->ptr.pp_complex[i][k].x = work.ptr.p_double[k]; + } + + /* + * Calculate imaginary part + */ + for(k=0; k<=m-1; k++) + { + work.ptr.p_double[k] = (double)(0); + } + for(k=0; k<=n-1; k++) + { + v = q.ptr.pp_complex[i][k].y; + ae_v_addd(&work.ptr.p_double[0], 1, &t.ptr.pp_double[k][0], 1, ae_v_len(0,m-1), v); + } + for(k=0; k<=m-1; k++) + { + z->ptr.pp_complex[i][k].y = work.ptr.p_double[k]; + } + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix + +The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by +using an QL/QR algorithm with implicit shifts. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix + are multiplied by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity + transformation of a symmetric matrix; + * 2, the eigenvectors of a tridiagonal matrix replace the + square matrix Z; + * 3, matrix Z contains the first row of the eigenvectors + matrix. + Z - if ZNeeded=1, Z contains the square matrix by which the + eigenvectors are multiplied. + Array whose indexes range within [0..N-1, 0..N-1]. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the product of a given matrix (from the left) + and the eigenvectors matrix (from the right); + * 2, Z contains the eigenvectors. + * 3, Z contains the first row of the eigenvectors matrix. + If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. + In that case, the eigenvectors are stored in the matrix columns. + If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +ae_bool smatrixtdevd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_vector d1; + ae_vector e1; + ae_vector ex; + ae_matrix z1; + ae_int_t i; + ae_int_t j; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + memset(&d1, 0, sizeof(d1)); + memset(&e1, 0, sizeof(e1)); + memset(&ex, 0, sizeof(ex)); + memset(&z1, 0, sizeof(z1)); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z1, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "SMatrixTDEVD: N<=0", _state); + ae_assert(zneeded>=0&&zneeded<=3, "SMatrixTDEVD: incorrect ZNeeded", _state); + result = ae_false; + + /* + * Preprocess Z: make ZNeeded equal to 0, 1 or 3. + * Ensure that memory for Z is allocated. + */ + if( zneeded==2 ) + { + + /* + * Load identity to Z + */ + rmatrixsetlengthatleast(z, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + z->ptr.pp_double[i][j] = 0.0; + } + z->ptr.pp_double[i][i] = 1.0; + } + zneeded = 1; + } + if( zneeded==3 ) + { + + /* + * Allocate memory + */ + rmatrixsetlengthatleast(z, 1, n, _state); + } + + /* + * Try to solve problem with PBL + */ + ae_vector_set_length(&ex, n, _state); + for(i=0; i<=n-2; i++) + { + ex.ptr.p_double[i] = e.ptr.p_double[i]; + } + if( smatrixtdevdpbl(d, &ex, n, zneeded, z, &result, _state) ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Prepare 1-based task + */ + ae_vector_set_length(&d1, n+1, _state); + ae_vector_set_length(&e1, n+1, _state); + ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); + if( n>1 ) + { + ae_v_move(&e1.ptr.p_double[1], 1, &e.ptr.p_double[0], 1, ae_v_len(1,n-1)); + } + if( zneeded==1 ) + { + ae_matrix_set_length(&z1, n+1, n+1, _state); + for(i=1; i<=n; i++) + { + ae_v_move(&z1.ptr.pp_double[i][1], 1, &z->ptr.pp_double[i-1][0], 1, ae_v_len(1,n)); + } + } + + /* + * Solve 1-based task + */ + result = evd_tridiagonalevd(&d1, &e1, n, zneeded, &z1, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Convert back to 0-based result + */ + ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); + if( zneeded!=0 ) + { + if( zneeded==1 ) + { + for(i=1; i<=n; i++) + { + ae_v_move(&z->ptr.pp_double[i-1][0], 1, &z1.ptr.pp_double[i][1], 1, ae_v_len(0,n-1)); + } + ae_frame_leave(_state); + return result; + } + if( zneeded==3 ) + { + ae_matrix_set_length(z, 0+1, n-1+1, _state); + ae_v_move(&z->ptr.pp_double[0][0], 1, &z1.ptr.pp_double[1][1], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); + return result; + } + ae_assert(ae_false, "SMatrixTDEVD: Incorrect ZNeeded!", _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a +given half-interval (A, B] by using bisection and inverse iteration. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix, N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the tridiagonal + matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. + A, B - half-interval (A, B] to search eigenvalues in. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range + within [0..N-1, 0..N-1]) which reduces the given symmetric + matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + M - number of eigenvalues found in the given half-interval (M>=0). + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the + left) and NxM matrix of the eigenvectors found (from the + right). Array whose indexes range within [0..N-1, 0..M-1]. + * 2, contains the matrix of the eigenvectors found. + Array whose indexes range within [0..N-1, 0..M-1]. + +Result: + + True, if successful. In that case, M contains the number of eigenvalues + in the given half-interval (could be equal to 0), D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. In that case, + the eigenvalues and eigenvectors are not returned, M is equal to 0. + + -- ALGLIB -- + Copyright 31.03.2008 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixtdevdr(/* Real */ ae_vector* d, + /* Real */ const ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + double a, + double b, + ae_int_t* m, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t errorcode; + ae_int_t nsplit; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cr; + ae_vector iblock; + ae_vector isplit; + ae_vector ifail; + ae_vector d1; + ae_vector e1; + ae_vector w; + ae_matrix z2; + ae_matrix z3; + double v; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&iblock, 0, sizeof(iblock)); + memset(&isplit, 0, sizeof(isplit)); + memset(&ifail, 0, sizeof(ifail)); + memset(&d1, 0, sizeof(d1)); + memset(&e1, 0, sizeof(e1)); + memset(&w, 0, sizeof(w)); + memset(&z2, 0, sizeof(z2)); + memset(&z3, 0, sizeof(z3)); + *m = 0; + ae_vector_init(&iblock, 0, DT_INT, _state, ae_true); + ae_vector_init(&isplit, 0, DT_INT, _state, ae_true); + ae_vector_init(&ifail, 0, DT_INT, _state, ae_true); + ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z3, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded>=0&&zneeded<=2, "SMatrixTDEVDR: incorrect ZNeeded!", _state); + + /* + * Special cases + */ + if( ae_fp_less_eq(b,a) ) + { + *m = 0; + result = ae_true; + ae_frame_leave(_state); + return result; + } + if( n<=0 ) + { + *m = 0; + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Copy D,E to D1, E1 + */ + ae_vector_set_length(&d1, n+1, _state); + ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); + if( n>1 ) + { + ae_vector_set_length(&e1, n-1+1, _state); + ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); + } + + /* + * No eigen vectors + */ + if( zneeded==0 ) + { + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 1, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result||*m==0 ) + { + *m = 0; + ae_frame_leave(_state); + return result; + } + ae_vector_set_length(d, *m-1+1, _state); + ae_v_move(&d->ptr.p_double[0], 1, &w.ptr.p_double[1], 1, ae_v_len(0,*m-1)); + ae_frame_leave(_state); + return result; + } + + /* + * Eigen vectors are multiplied by Z + */ + if( zneeded==1 ) + { + + /* + * Find eigen pairs + */ + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result||*m==0 ) + { + *m = 0; + ae_frame_leave(_state); + return result; + } + evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); + if( cr!=0 ) + { + *m = 0; + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Sort eigen values and vectors + */ + for(i=1; i<=*m; i++) + { + k = i; + for(j=i; j<=*m; j++) + { + if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) + { + k = j; + } + } + v = w.ptr.p_double[i]; + w.ptr.p_double[i] = w.ptr.p_double[k]; + w.ptr.p_double[k] = v; + for(j=1; j<=n; j++) + { + v = z2.ptr.pp_double[j][i]; + z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; + z2.ptr.pp_double[j][k] = v; + } + } + + /* + * Transform Z2 and overwrite Z + */ + ae_matrix_set_length(&z3, *m+1, n+1, _state); + for(i=1; i<=*m; i++) + { + ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); + } + for(i=1; i<=n; i++) + { + for(j=1; j<=*m; j++) + { + v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); + z2.ptr.pp_double[i][j] = v; + } + } + ae_matrix_set_length(z, n-1+1, *m-1+1, _state); + for(i=1; i<=*m; i++) + { + ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); + } + + /* + * Store W + */ + ae_vector_set_length(d, *m-1+1, _state); + for(i=1; i<=*m; i++) + { + d->ptr.p_double[i-1] = w.ptr.p_double[i]; + } + ae_frame_leave(_state); + return result; + } + + /* + * Eigen vectors are stored in Z + */ + if( zneeded==2 ) + { + + /* + * Find eigen pairs + */ + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 2, 2, a, b, 0, 0, (double)(-1), &w, m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result||*m==0 ) + { + *m = 0; + ae_frame_leave(_state); + return result; + } + evd_internaldstein(n, &d1, &e1, *m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); + if( cr!=0 ) + { + *m = 0; + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Sort eigen values and vectors + */ + for(i=1; i<=*m; i++) + { + k = i; + for(j=i; j<=*m; j++) + { + if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) + { + k = j; + } + } + v = w.ptr.p_double[i]; + w.ptr.p_double[i] = w.ptr.p_double[k]; + w.ptr.p_double[k] = v; + for(j=1; j<=n; j++) + { + v = z2.ptr.pp_double[j][i]; + z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; + z2.ptr.pp_double[j][k] = v; + } + } + + /* + * Store W + */ + ae_vector_set_length(d, *m-1+1, _state); + for(i=1; i<=*m; i++) + { + d->ptr.p_double[i-1] = w.ptr.p_double[i]; + } + ae_matrix_set_length(z, n-1+1, *m-1+1, _state); + for(i=1; i<=*m; i++) + { + ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); + } + ae_frame_leave(_state); + return result; + } + result = ae_false; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Subroutine for finding tridiagonal matrix eigenvalues/vectors with given +indexes (in ascending order) by using the bisection and inverse iteraion. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix. N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace + matrix Z. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) + which reduces the given symmetric matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the left) and + Nx(I2-I1) matrix of the eigenvectors found (from the right). + Array whose indexes range within [0..N-1, 0..I2-I1]. + * 2, contains the matrix of the eigenvalues found. + Array whose indexes range within [0..N-1, 0..I2-I1]. + + +Result: + + True, if successful. In that case, D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the eigenvalues + in the given interval or if the inverse iteration subroutine wasn't able + to find all the corresponding eigenvectors. In that case, the eigenvalues + and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 25.12.2005 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixtdevdi(/* Real */ ae_vector* d, + /* Real */ const ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t errorcode; + ae_int_t nsplit; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t m; + ae_int_t cr; + ae_vector iblock; + ae_vector isplit; + ae_vector ifail; + ae_vector w; + ae_vector d1; + ae_vector e1; + ae_matrix z2; + ae_matrix z3; + double v; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&iblock, 0, sizeof(iblock)); + memset(&isplit, 0, sizeof(isplit)); + memset(&ifail, 0, sizeof(ifail)); + memset(&w, 0, sizeof(w)); + memset(&d1, 0, sizeof(d1)); + memset(&e1, 0, sizeof(e1)); + memset(&z2, 0, sizeof(z2)); + memset(&z3, 0, sizeof(z3)); + ae_vector_init(&iblock, 0, DT_INT, _state, ae_true); + ae_vector_init(&isplit, 0, DT_INT, _state, ae_true); + ae_vector_init(&ifail, 0, DT_INT, _state, ae_true); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z3, 0, 0, DT_REAL, _state, ae_true); + + ae_assert((0<=i1&&i1<=i2)&&i2ptr.p_double[0], 1, ae_v_len(1,n)); + if( n>1 ) + { + ae_vector_set_length(&e1, n-1+1, _state); + ae_v_move(&e1.ptr.p_double[1], 1, &e->ptr.p_double[0], 1, ae_v_len(1,n-1)); + } + + /* + * No eigen vectors + */ + if( zneeded==0 ) + { + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 1, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( m!=i2-i1+1 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + ae_vector_set_length(d, m-1+1, _state); + for(i=1; i<=m; i++) + { + d->ptr.p_double[i-1] = w.ptr.p_double[i]; + } + ae_frame_leave(_state); + return result; + } + + /* + * Eigen vectors are multiplied by Z + */ + if( zneeded==1 ) + { + + /* + * Find eigen pairs + */ + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( m!=i2-i1+1 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); + if( cr!=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Sort eigen values and vectors + */ + for(i=1; i<=m; i++) + { + k = i; + for(j=i; j<=m; j++) + { + if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) + { + k = j; + } + } + v = w.ptr.p_double[i]; + w.ptr.p_double[i] = w.ptr.p_double[k]; + w.ptr.p_double[k] = v; + for(j=1; j<=n; j++) + { + v = z2.ptr.pp_double[j][i]; + z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; + z2.ptr.pp_double[j][k] = v; + } + } + + /* + * Transform Z2 and overwrite Z + */ + ae_matrix_set_length(&z3, m+1, n+1, _state); + for(i=1; i<=m; i++) + { + ae_v_move(&z3.ptr.pp_double[i][1], 1, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(1,n)); + } + for(i=1; i<=n; i++) + { + for(j=1; j<=m; j++) + { + v = ae_v_dotproduct(&z->ptr.pp_double[i-1][0], 1, &z3.ptr.pp_double[j][1], 1, ae_v_len(0,n-1)); + z2.ptr.pp_double[i][j] = v; + } + } + ae_matrix_set_length(z, n-1+1, m-1+1, _state); + for(i=1; i<=m; i++) + { + ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); + } + + /* + * Store W + */ + ae_vector_set_length(d, m-1+1, _state); + for(i=1; i<=m; i++) + { + d->ptr.p_double[i-1] = w.ptr.p_double[i]; + } + ae_frame_leave(_state); + return result; + } + + /* + * Eigen vectors are stored in Z + */ + if( zneeded==2 ) + { + + /* + * Find eigen pairs + */ + result = evd_internalbisectioneigenvalues(&d1, &e1, n, 3, 2, (double)(0), (double)(0), i1+1, i2+1, (double)(-1), &w, &m, &nsplit, &iblock, &isplit, &errorcode, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( m!=i2-i1+1 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + evd_internaldstein(n, &d1, &e1, m, &w, &iblock, &isplit, &z2, &ifail, &cr, _state); + if( cr!=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Sort eigen values and vectors + */ + for(i=1; i<=m; i++) + { + k = i; + for(j=i; j<=m; j++) + { + if( ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[k]) ) + { + k = j; + } + } + v = w.ptr.p_double[i]; + w.ptr.p_double[i] = w.ptr.p_double[k]; + w.ptr.p_double[k] = v; + for(j=1; j<=n; j++) + { + v = z2.ptr.pp_double[j][i]; + z2.ptr.pp_double[j][i] = z2.ptr.pp_double[j][k]; + z2.ptr.pp_double[j][k] = v; + } + } + + /* + * Store Z + */ + ae_matrix_set_length(z, n-1+1, m-1+1, _state); + for(i=1; i<=m; i++) + { + ae_v_move(&z->ptr.pp_double[0][i-1], z->stride, &z2.ptr.pp_double[1][i], z2.stride, ae_v_len(0,n-1)); + } + + /* + * Store W + */ + ae_vector_set_length(d, m-1+1, _state); + for(i=1; i<=m; i++) + { + d->ptr.p_double[i-1] = w.ptr.p_double[i]; + } + ae_frame_leave(_state); + return result; + } + result = ae_false; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm finds eigenvalues and eigenvectors of a general matrix by +using the QR algorithm with multiple shifts. The algorithm can find +eigenvalues and both left and right eigenvectors. + +The right eigenvector is a vector x such that A*x = w*x, and the left +eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex +conjugate transposition of vector y). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + VNeeded - flag controlling whether eigenvectors are needed or not. + If VNeeded is equal to: + * 0, eigenvectors are not returned; + * 1, right eigenvectors are returned; + * 2, left eigenvectors are returned; + * 3, both left and right eigenvectors are returned. + +Output parameters: + WR - real parts of eigenvalues. + Array whose index ranges within [0..N-1]. + WR - imaginary parts of eigenvalues. + Array whose index ranges within [0..N-1]. + VL, VR - arrays of left and right eigenvectors (if they are needed). + If WI[i]=0, the respective eigenvalue is a real number, + and it corresponds to the column number I of matrices VL/VR. + If WI[i]>0, we have a pair of complex conjugate numbers with + positive and negative imaginary parts: + the first eigenvalue WR[i] + sqrt(-1)*WI[i]; + the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; + WI[i]>0 + WI[i+1] = -WI[i] < 0 + In that case, the eigenvector corresponding to the first + eigenvalue is located in i and i+1 columns of matrices + VL/VR (the column number i contains the real part, and the + column number i+1 contains the imaginary part), and the vector + corresponding to the second eigenvalue is a complex conjugate to + the first vector. + Arrays whose indexes range within [0..N-1, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm has not converged. + +Note 1: + Some users may ask the following question: what if WI[N-1]>0? + WI[N] must contain an eigenvalue which is complex conjugate to the + N-th eigenvalue, but the array has only size N? + The answer is as follows: such a situation cannot occur because the + algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is + strictly less than N-1. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms of linear algebra). If you require maximum performance + on your machine, it is recommended to adjust this parameter manually. + + +See also the InternalTREVC subroutine. + +The algorithm is based on the LAPACK 3.0 library. +*************************************************************************/ +ae_bool rmatrixevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t vneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix a1; + ae_matrix vl1; + ae_matrix vr1; + ae_matrix s1; + ae_matrix s; + ae_matrix dummy; + ae_vector wr1; + ae_vector wi1; + ae_vector tau; + ae_int_t i; + ae_int_t info; + ae_vector sel1; + ae_int_t m1; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&a1, 0, sizeof(a1)); + memset(&vl1, 0, sizeof(vl1)); + memset(&vr1, 0, sizeof(vr1)); + memset(&s1, 0, sizeof(s1)); + memset(&s, 0, sizeof(s)); + memset(&dummy, 0, sizeof(dummy)); + memset(&wr1, 0, sizeof(wr1)); + memset(&wi1, 0, sizeof(wi1)); + memset(&tau, 0, sizeof(tau)); + memset(&sel1, 0, sizeof(sel1)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(wr); + ae_vector_clear(wi); + ae_matrix_clear(vl); + ae_matrix_clear(vr); + ae_matrix_init(&a1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vl1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vr1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&s1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&s, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wr1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wi1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sel1, 0, DT_BOOL, _state, ae_true); + + ae_assert(vneeded>=0&&vneeded<=3, "RMatrixEVD: incorrect VNeeded!", _state); + if( vneeded==0 ) + { + + /* + * Eigen values only + */ + rmatrixhessenberg(&a, n, &tau, _state); + rmatrixinternalschurdecomposition(&a, n, 0, 0, wr, wi, &dummy, &info, _state); + result = info==0; + ae_frame_leave(_state); + return result; + } + + /* + * Eigen values and vectors + */ + rmatrixhessenberg(&a, n, &tau, _state); + rmatrixhessenbergunpackq(&a, n, &tau, &s, _state); + rmatrixinternalschurdecomposition(&a, n, 1, 1, wr, wi, &s, &info, _state); + result = info==0; + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( vneeded==1||vneeded==3 ) + { + ae_matrix_set_length(vr, n, n, _state); + for(i=0; i<=n-1; i++) + { + ae_v_move(&vr->ptr.pp_double[i][0], 1, &s.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + } + if( vneeded==2||vneeded==3 ) + { + ae_matrix_set_length(vl, n, n, _state); + for(i=0; i<=n-1; i++) + { + ae_v_move(&vl->ptr.pp_double[i][0], 1, &s.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + } + evd_rmatrixinternaltrevc(&a, n, vneeded, 1, &sel1, vl, vr, &m1, &info, _state); + result = info==0; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void evd_clearrfields(eigsubspacestate* state, ae_state *_state) +{ + + + state->requesttype = -1; + state->requestsize = -1; +} + + +static ae_bool evd_tridiagonalevd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_int_t maxit; + ae_int_t i; + ae_int_t ii; + ae_int_t iscale; + ae_int_t j; + ae_int_t jtot; + ae_int_t k; + ae_int_t t; + ae_int_t l; + ae_int_t l1; + ae_int_t lend; + ae_int_t lendm1; + ae_int_t lendp1; + ae_int_t lendsv; + ae_int_t lm1; + ae_int_t lsv; + ae_int_t m; + ae_int_t mm1; + ae_int_t nm1; + ae_int_t nmaxit; + ae_int_t tmpint; + double anorm; + double b; + double c; + double eps; + double eps2; + double f; + double g; + double p; + double r; + double rt1; + double rt2; + double s; + double safmax; + double safmin; + double ssfmax; + double ssfmin; + double tst; + double tmp; + ae_vector work1; + ae_vector work2; + ae_vector workc; + ae_vector works; + ae_vector wtemp; + ae_bool gotoflag; + ae_int_t zrows; + ae_bool wastranspose; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + memset(&work1, 0, sizeof(work1)); + memset(&work2, 0, sizeof(work2)); + memset(&workc, 0, sizeof(workc)); + memset(&works, 0, sizeof(works)); + memset(&wtemp, 0, sizeof(wtemp)); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&workc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&works, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true); + + ae_assert(zneeded>=0&&zneeded<=3, "TridiagonalEVD: Incorrent ZNeeded", _state); + + /* + * Quick return if possible + */ + if( zneeded<0||zneeded>3 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + result = ae_true; + if( n==0 ) + { + ae_frame_leave(_state); + return result; + } + if( n==1 ) + { + if( zneeded==2||zneeded==3 ) + { + ae_matrix_set_length(z, 1+1, 1+1, _state); + z->ptr.pp_double[1][1] = (double)(1); + } + ae_frame_leave(_state); + return result; + } + maxit = 30; + + /* + * Initialize arrays + */ + ae_vector_set_length(&wtemp, n+1, _state); + ae_vector_set_length(&work1, n-1+1, _state); + ae_vector_set_length(&work2, n-1+1, _state); + ae_vector_set_length(&workc, n+1, _state); + ae_vector_set_length(&works, n+1, _state); + + /* + * Determine the unit roundoff and over/underflow thresholds. + */ + eps = ae_machineepsilon; + eps2 = ae_sqr(eps, _state); + safmin = ae_minrealnumber; + safmax = ae_maxrealnumber; + ssfmax = ae_sqrt(safmax, _state)/(double)3; + ssfmin = ae_sqrt(safmin, _state)/eps2; + + /* + * Prepare Z + * + * Here we are using transposition to get rid of column operations + * + */ + wastranspose = ae_false; + zrows = 0; + if( zneeded==1 ) + { + zrows = n; + } + if( zneeded==2 ) + { + zrows = n; + } + if( zneeded==3 ) + { + zrows = 1; + } + if( zneeded==1 ) + { + wastranspose = ae_true; + inplacetranspose(z, 1, n, 1, n, &wtemp, _state); + } + if( zneeded==2 ) + { + wastranspose = ae_true; + ae_matrix_set_length(z, n+1, n+1, _state); + for(i=1; i<=n; i++) + { + for(j=1; j<=n; j++) + { + if( i==j ) + { + z->ptr.pp_double[i][j] = (double)(1); + } + else + { + z->ptr.pp_double[i][j] = (double)(0); + } + } + } + } + if( zneeded==3 ) + { + wastranspose = ae_false; + ae_matrix_set_length(z, 1+1, n+1, _state); + for(j=1; j<=n; j++) + { + if( j==1 ) + { + z->ptr.pp_double[1][j] = (double)(1); + } + else + { + z->ptr.pp_double[1][j] = (double)(0); + } + } + } + nmaxit = n*maxit; + jtot = 0; + + /* + * Determine where the matrix splits and choose QL or QR iteration + * for each block, according to whether top or bottom diagonal + * element is smaller. + */ + l1 = 1; + nm1 = n-1; + for(;;) + { + if( l1>n ) + { + break; + } + if( l1>1 ) + { + e.ptr.p_double[l1-1] = (double)(0); + } + gotoflag = ae_false; + m = l1; + if( l1<=nm1 ) + { + for(m=l1; m<=nm1; m++) + { + tst = ae_fabs(e.ptr.p_double[m], _state); + if( ae_fp_eq(tst,(double)(0)) ) + { + gotoflag = ae_true; + break; + } + if( ae_fp_less_eq(tst,ae_sqrt(ae_fabs(d->ptr.p_double[m], _state), _state)*ae_sqrt(ae_fabs(d->ptr.p_double[m+1], _state), _state)*eps) ) + { + e.ptr.p_double[m] = (double)(0); + gotoflag = ae_true; + break; + } + } + } + if( !gotoflag ) + { + m = n; + } + + /* + * label 30: + */ + l = l1; + lsv = l; + lend = m; + lendsv = lend; + l1 = m+1; + if( lend==l ) + { + continue; + } + + /* + * Scale submatrix in rows and columns L to LEND + */ + if( l==lend ) + { + anorm = ae_fabs(d->ptr.p_double[l], _state); + } + else + { + anorm = ae_maxreal(ae_fabs(d->ptr.p_double[l], _state)+ae_fabs(e.ptr.p_double[l], _state), ae_fabs(e.ptr.p_double[lend-1], _state)+ae_fabs(d->ptr.p_double[lend], _state), _state); + for(i=l+1; i<=lend-1; i++) + { + anorm = ae_maxreal(anorm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e.ptr.p_double[i], _state)+ae_fabs(e.ptr.p_double[i-1], _state), _state); + } + } + iscale = 0; + if( ae_fp_eq(anorm,(double)(0)) ) + { + continue; + } + if( ae_fp_greater(anorm,ssfmax) ) + { + iscale = 1; + tmp = ssfmax/anorm; + tmpint = lend-1; + ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); + ae_v_muld(&e.ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); + } + if( ae_fp_less(anorm,ssfmin) ) + { + iscale = 2; + tmp = ssfmin/anorm; + tmpint = lend-1; + ae_v_muld(&d->ptr.p_double[l], 1, ae_v_len(l,lend), tmp); + ae_v_muld(&e.ptr.p_double[l], 1, ae_v_len(l,tmpint), tmp); + } + + /* + * Choose between QL and QR iteration + */ + if( ae_fp_less(ae_fabs(d->ptr.p_double[lend], _state),ae_fabs(d->ptr.p_double[l], _state)) ) + { + lend = lsv; + l = lendsv; + } + if( lend>l ) + { + + /* + * QL Iteration + * + * Look for small subdiagonal element. + */ + for(;;) + { + gotoflag = ae_false; + if( l!=lend ) + { + lendm1 = lend-1; + for(m=l; m<=lendm1; m++) + { + tst = ae_sqr(ae_fabs(e.ptr.p_double[m], _state), _state); + if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m+1], _state)+safmin) ) + { + gotoflag = ae_true; + break; + } + } + } + if( !gotoflag ) + { + m = lend; + } + if( mptr.p_double[l]; + if( m!=l ) + { + + /* + * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + * to compute its eigensystem. + */ + if( m==l+1 ) + { + if( zneeded>0 ) + { + evd_tdevdev2(d->ptr.p_double[l], e.ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, &c, &s, _state); + work1.ptr.p_double[l] = c; + work2.ptr.p_double[l] = s; + workc.ptr.p_double[1] = work1.ptr.p_double[l]; + works.ptr.p_double[1] = work2.ptr.p_double[l]; + if( !wastranspose ) + { + applyrotationsfromtheright(ae_false, 1, zrows, l, l+1, &workc, &works, z, &wtemp, _state); + } + else + { + applyrotationsfromtheleft(ae_false, l, l+1, 1, zrows, &workc, &works, z, &wtemp, _state); + } + } + else + { + evd_tdevde2(d->ptr.p_double[l], e.ptr.p_double[l], d->ptr.p_double[l+1], &rt1, &rt2, _state); + } + d->ptr.p_double[l] = rt1; + d->ptr.p_double[l+1] = rt2; + e.ptr.p_double[l] = (double)(0); + l = l+2; + if( l<=lend ) + { + continue; + } + + /* + * GOTO 140 + */ + break; + } + if( jtot==nmaxit ) + { + + /* + * GOTO 140 + */ + break; + } + jtot = jtot+1; + + /* + * Form shift. + */ + g = (d->ptr.p_double[l+1]-p)/((double)2*e.ptr.p_double[l]); + r = evd_tdevdpythag(g, (double)(1), _state); + g = d->ptr.p_double[m]-p+e.ptr.p_double[l]/(g+evd_tdevdextsign(r, g, _state)); + s = (double)(1); + c = (double)(1); + p = (double)(0); + + /* + * Inner loop + */ + mm1 = m-1; + for(i=mm1; i>=l; i--) + { + f = s*e.ptr.p_double[i]; + b = c*e.ptr.p_double[i]; + generaterotation(g, f, &c, &s, &r, _state); + if( i!=m-1 ) + { + e.ptr.p_double[i+1] = r; + } + g = d->ptr.p_double[i+1]-p; + r = (d->ptr.p_double[i]-g)*s+(double)2*c*b; + p = s*r; + d->ptr.p_double[i+1] = g+p; + g = c*r-b; + + /* + * If eigenvectors are desired, then save rotations. + */ + if( zneeded>0 ) + { + work1.ptr.p_double[i] = c; + work2.ptr.p_double[i] = -s; + } + } + + /* + * If eigenvectors are desired, then apply saved rotations. + */ + if( zneeded>0 ) + { + for(i=l; i<=m-1; i++) + { + workc.ptr.p_double[i-l+1] = work1.ptr.p_double[i]; + works.ptr.p_double[i-l+1] = work2.ptr.p_double[i]; + } + if( !wastranspose ) + { + applyrotationsfromtheright(ae_false, 1, zrows, l, m, &workc, &works, z, &wtemp, _state); + } + else + { + applyrotationsfromtheleft(ae_false, l, m, 1, zrows, &workc, &works, z, &wtemp, _state); + } + } + d->ptr.p_double[l] = d->ptr.p_double[l]-p; + e.ptr.p_double[l] = g; + continue; + } + + /* + * Eigenvalue found. + */ + d->ptr.p_double[l] = p; + l = l+1; + if( l<=lend ) + { + continue; + } + break; + } + } + else + { + + /* + * QR Iteration + * + * Look for small superdiagonal element. + */ + for(;;) + { + gotoflag = ae_false; + if( l!=lend ) + { + lendp1 = lend+1; + for(m=l; m>=lendp1; m--) + { + tst = ae_sqr(ae_fabs(e.ptr.p_double[m-1], _state), _state); + if( ae_fp_less_eq(tst,eps2*ae_fabs(d->ptr.p_double[m], _state)*ae_fabs(d->ptr.p_double[m-1], _state)+safmin) ) + { + gotoflag = ae_true; + break; + } + } + } + if( !gotoflag ) + { + m = lend; + } + if( m>lend ) + { + e.ptr.p_double[m-1] = (double)(0); + } + p = d->ptr.p_double[l]; + if( m!=l ) + { + + /* + * If remaining matrix is 2-by-2, use DLAE2 or SLAEV2 + * to compute its eigensystem. + */ + if( m==l-1 ) + { + if( zneeded>0 ) + { + evd_tdevdev2(d->ptr.p_double[l-1], e.ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, &c, &s, _state); + work1.ptr.p_double[m] = c; + work2.ptr.p_double[m] = s; + workc.ptr.p_double[1] = c; + works.ptr.p_double[1] = s; + if( !wastranspose ) + { + applyrotationsfromtheright(ae_true, 1, zrows, l-1, l, &workc, &works, z, &wtemp, _state); + } + else + { + applyrotationsfromtheleft(ae_true, l-1, l, 1, zrows, &workc, &works, z, &wtemp, _state); + } + } + else + { + evd_tdevde2(d->ptr.p_double[l-1], e.ptr.p_double[l-1], d->ptr.p_double[l], &rt1, &rt2, _state); + } + d->ptr.p_double[l-1] = rt1; + d->ptr.p_double[l] = rt2; + e.ptr.p_double[l-1] = (double)(0); + l = l-2; + if( l>=lend ) + { + continue; + } + break; + } + if( jtot==nmaxit ) + { + break; + } + jtot = jtot+1; + + /* + * Form shift. + */ + g = (d->ptr.p_double[l-1]-p)/((double)2*e.ptr.p_double[l-1]); + r = evd_tdevdpythag(g, (double)(1), _state); + g = d->ptr.p_double[m]-p+e.ptr.p_double[l-1]/(g+evd_tdevdextsign(r, g, _state)); + s = (double)(1); + c = (double)(1); + p = (double)(0); + + /* + * Inner loop + */ + lm1 = l-1; + for(i=m; i<=lm1; i++) + { + f = s*e.ptr.p_double[i]; + b = c*e.ptr.p_double[i]; + generaterotation(g, f, &c, &s, &r, _state); + if( i!=m ) + { + e.ptr.p_double[i-1] = r; + } + g = d->ptr.p_double[i]-p; + r = (d->ptr.p_double[i+1]-g)*s+(double)2*c*b; + p = s*r; + d->ptr.p_double[i] = g+p; + g = c*r-b; + + /* + * If eigenvectors are desired, then save rotations. + */ + if( zneeded>0 ) + { + work1.ptr.p_double[i] = c; + work2.ptr.p_double[i] = s; + } + } + + /* + * If eigenvectors are desired, then apply saved rotations. + */ + if( zneeded>0 ) + { + for(i=m; i<=l-1; i++) + { + workc.ptr.p_double[i-m+1] = work1.ptr.p_double[i]; + works.ptr.p_double[i-m+1] = work2.ptr.p_double[i]; + } + if( !wastranspose ) + { + applyrotationsfromtheright(ae_true, 1, zrows, m, l, &workc, &works, z, &wtemp, _state); + } + else + { + applyrotationsfromtheleft(ae_true, m, l, 1, zrows, &workc, &works, z, &wtemp, _state); + } + } + d->ptr.p_double[l] = d->ptr.p_double[l]-p; + e.ptr.p_double[lm1] = g; + continue; + } + + /* + * Eigenvalue found. + */ + d->ptr.p_double[l] = p; + l = l-1; + if( l>=lend ) + { + continue; + } + break; + } + } + + /* + * Undo scaling if necessary + */ + if( iscale==1 ) + { + tmp = anorm/ssfmax; + tmpint = lendsv-1; + ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); + ae_v_muld(&e.ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); + } + if( iscale==2 ) + { + tmp = anorm/ssfmin; + tmpint = lendsv-1; + ae_v_muld(&d->ptr.p_double[lsv], 1, ae_v_len(lsv,lendsv), tmp); + ae_v_muld(&e.ptr.p_double[lsv], 1, ae_v_len(lsv,tmpint), tmp); + } + + /* + * Check for no convergence to an eigenvalue after a total + * of N*MAXIT iterations. + */ + if( jtot>=nmaxit ) + { + result = ae_false; + if( wastranspose ) + { + inplacetranspose(z, 1, n, 1, n, &wtemp, _state); + } + ae_frame_leave(_state); + return result; + } + } + + /* + * Order eigenvalues and eigenvectors. + */ + if( zneeded==0 ) + { + + /* + * Sort + */ + if( n==1 ) + { + ae_frame_leave(_state); + return result; + } + if( n==2 ) + { + if( ae_fp_greater(d->ptr.p_double[1],d->ptr.p_double[2]) ) + { + tmp = d->ptr.p_double[1]; + d->ptr.p_double[1] = d->ptr.p_double[2]; + d->ptr.p_double[2] = tmp; + } + ae_frame_leave(_state); + return result; + } + i = 2; + do + { + t = i; + while(t!=1) + { + k = t/2; + if( ae_fp_greater_eq(d->ptr.p_double[k],d->ptr.p_double[t]) ) + { + t = 1; + } + else + { + tmp = d->ptr.p_double[k]; + d->ptr.p_double[k] = d->ptr.p_double[t]; + d->ptr.p_double[t] = tmp; + t = k; + } + } + i = i+1; + } + while(i<=n); + i = n-1; + do + { + tmp = d->ptr.p_double[i+1]; + d->ptr.p_double[i+1] = d->ptr.p_double[1]; + d->ptr.p_double[1] = tmp; + t = 1; + while(t!=0) + { + k = 2*t; + if( k>i ) + { + t = 0; + } + else + { + if( kptr.p_double[k+1],d->ptr.p_double[k]) ) + { + k = k+1; + } + } + if( ae_fp_greater_eq(d->ptr.p_double[t],d->ptr.p_double[k]) ) + { + t = 0; + } + else + { + tmp = d->ptr.p_double[k]; + d->ptr.p_double[k] = d->ptr.p_double[t]; + d->ptr.p_double[t] = tmp; + t = k; + } + } + } + i = i-1; + } + while(i>=1); + } + else + { + + /* + * Use Selection Sort to minimize swaps of eigenvectors + */ + for(ii=2; ii<=n; ii++) + { + i = ii-1; + k = i; + p = d->ptr.p_double[i]; + for(j=ii; j<=n; j++) + { + if( ae_fp_less(d->ptr.p_double[j],p) ) + { + k = j; + p = d->ptr.p_double[j]; + } + } + if( k!=i ) + { + d->ptr.p_double[k] = d->ptr.p_double[i]; + d->ptr.p_double[i] = p; + if( wastranspose ) + { + ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[i][1], 1, ae_v_len(1,n)); + ae_v_move(&z->ptr.pp_double[i][1], 1, &z->ptr.pp_double[k][1], 1, ae_v_len(1,n)); + ae_v_move(&z->ptr.pp_double[k][1], 1, &wtemp.ptr.p_double[1], 1, ae_v_len(1,n)); + } + else + { + ae_v_move(&wtemp.ptr.p_double[1], 1, &z->ptr.pp_double[1][i], z->stride, ae_v_len(1,zrows)); + ae_v_move(&z->ptr.pp_double[1][i], z->stride, &z->ptr.pp_double[1][k], z->stride, ae_v_len(1,zrows)); + ae_v_move(&z->ptr.pp_double[1][k], z->stride, &wtemp.ptr.p_double[1], 1, ae_v_len(1,zrows)); + } + } + } + if( wastranspose ) + { + inplacetranspose(z, 1, n, 1, n, &wtemp, _state); + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix + [ A B ] + [ B C ]. +On return, RT1 is the eigenvalue of larger absolute value, and RT2 +is the eigenvalue of smaller absolute value. + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +static void evd_tdevde2(double a, + double b, + double c, + double* rt1, + double* rt2, + ae_state *_state) +{ + double ab; + double acmn; + double acmx; + double adf; + double df; + double rt; + double sm; + double tb; + + *rt1 = 0.0; + *rt2 = 0.0; + + sm = a+c; + df = a-c; + adf = ae_fabs(df, _state); + tb = b+b; + ab = ae_fabs(tb, _state); + if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) + { + acmx = a; + acmn = c; + } + else + { + acmx = c; + acmn = a; + } + if( ae_fp_greater(adf,ab) ) + { + rt = adf*ae_sqrt((double)1+ae_sqr(ab/adf, _state), _state); + } + else + { + if( ae_fp_less(adf,ab) ) + { + rt = ab*ae_sqrt((double)1+ae_sqr(adf/ab, _state), _state); + } + else + { + + /* + * Includes case AB=ADF=0 + */ + rt = ab*ae_sqrt((double)(2), _state); + } + } + if( ae_fp_less(sm,(double)(0)) ) + { + *rt1 = 0.5*(sm-rt); + + /* + * Order of execution important. + * To get fully accurate smaller eigenvalue, + * next line needs to be executed in higher precision. + */ + *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; + } + else + { + if( ae_fp_greater(sm,(double)(0)) ) + { + *rt1 = 0.5*(sm+rt); + + /* + * Order of execution important. + * To get fully accurate smaller eigenvalue, + * next line needs to be executed in higher precision. + */ + *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; + } + else + { + + /* + * Includes case RT1 = RT2 = 0 + */ + *rt1 = 0.5*rt; + *rt2 = -0.5*rt; + } + } +} + + +/************************************************************************* +DLAEV2 computes the eigendecomposition of a 2-by-2 symmetric matrix + + [ A B ] + [ B C ]. + +On return, RT1 is the eigenvalue of larger absolute value, RT2 is the +eigenvalue of smaller absolute value, and (CS1,SN1) is the unit right +eigenvector for RT1, giving the decomposition + + [ CS1 SN1 ] [ A B ] [ CS1 -SN1 ] = [ RT1 0 ] + [-SN1 CS1 ] [ B C ] [ SN1 CS1 ] [ 0 RT2 ]. + + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +static void evd_tdevdev2(double a, + double b, + double c, + double* rt1, + double* rt2, + double* cs1, + double* sn1, + ae_state *_state) +{ + ae_int_t sgn1; + ae_int_t sgn2; + double ab; + double acmn; + double acmx; + double acs; + double adf; + double cs; + double ct; + double df; + double rt; + double sm; + double tb; + double tn; + + *rt1 = 0.0; + *rt2 = 0.0; + *cs1 = 0.0; + *sn1 = 0.0; + + + /* + * Compute the eigenvalues + */ + sm = a+c; + df = a-c; + adf = ae_fabs(df, _state); + tb = b+b; + ab = ae_fabs(tb, _state); + if( ae_fp_greater(ae_fabs(a, _state),ae_fabs(c, _state)) ) + { + acmx = a; + acmn = c; + } + else + { + acmx = c; + acmn = a; + } + if( ae_fp_greater(adf,ab) ) + { + rt = adf*ae_sqrt((double)1+ae_sqr(ab/adf, _state), _state); + } + else + { + if( ae_fp_less(adf,ab) ) + { + rt = ab*ae_sqrt((double)1+ae_sqr(adf/ab, _state), _state); + } + else + { + + /* + * Includes case AB=ADF=0 + */ + rt = ab*ae_sqrt((double)(2), _state); + } + } + if( ae_fp_less(sm,(double)(0)) ) + { + *rt1 = 0.5*(sm-rt); + sgn1 = -1; + + /* + * Order of execution important. + * To get fully accurate smaller eigenvalue, + * next line needs to be executed in higher precision. + */ + *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; + } + else + { + if( ae_fp_greater(sm,(double)(0)) ) + { + *rt1 = 0.5*(sm+rt); + sgn1 = 1; + + /* + * Order of execution important. + * To get fully accurate smaller eigenvalue, + * next line needs to be executed in higher precision. + */ + *rt2 = acmx/(*rt1)*acmn-b/(*rt1)*b; + } + else + { + + /* + * Includes case RT1 = RT2 = 0 + */ + *rt1 = 0.5*rt; + *rt2 = -0.5*rt; + sgn1 = 1; + } + } + + /* + * Compute the eigenvector + */ + if( ae_fp_greater_eq(df,(double)(0)) ) + { + cs = df+rt; + sgn2 = 1; + } + else + { + cs = df-rt; + sgn2 = -1; + } + acs = ae_fabs(cs, _state); + if( ae_fp_greater(acs,ab) ) + { + ct = -tb/cs; + *sn1 = (double)1/ae_sqrt((double)1+ct*ct, _state); + *cs1 = ct*(*sn1); + } + else + { + if( ae_fp_eq(ab,(double)(0)) ) + { + *cs1 = (double)(1); + *sn1 = (double)(0); + } + else + { + tn = -cs/tb; + *cs1 = (double)1/ae_sqrt((double)1+tn*tn, _state); + *sn1 = tn*(*cs1); + } + } + if( sgn1==sgn2 ) + { + tn = *cs1; + *cs1 = -*sn1; + *sn1 = tn; + } +} + + +/************************************************************************* +Internal routine +*************************************************************************/ +static double evd_tdevdpythag(double a, double b, ae_state *_state) +{ + double result; + + + if( ae_fp_less(ae_fabs(a, _state),ae_fabs(b, _state)) ) + { + result = ae_fabs(b, _state)*ae_sqrt((double)1+ae_sqr(a/b, _state), _state); + } + else + { + result = ae_fabs(a, _state)*ae_sqrt((double)1+ae_sqr(b/a, _state), _state); + } + return result; +} + + +/************************************************************************* +Internal routine +*************************************************************************/ +static double evd_tdevdextsign(double a, double b, ae_state *_state) +{ + double result; + + + if( ae_fp_greater_eq(b,(double)(0)) ) + { + result = ae_fabs(a, _state); + } + else + { + result = -ae_fabs(a, _state); + } + return result; +} + + +static ae_bool evd_internalbisectioneigenvalues(/* Real */ const ae_vector* _d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t irange, + ae_int_t iorder, + double vl, + double vu, + ae_int_t il, + ae_int_t iu, + double abstol, + /* Real */ ae_vector* w, + ae_int_t* m, + ae_int_t* nsplit, + /* Integer */ ae_vector* iblock, + /* Integer */ ae_vector* isplit, + ae_int_t* errorcode, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector d; + ae_vector e; + double fudge; + double relfac; + ae_bool ncnvrg; + ae_bool toofew; + ae_int_t ib; + ae_int_t ibegin; + ae_int_t idiscl; + ae_int_t idiscu; + ae_int_t ie; + ae_int_t iend; + ae_int_t iinfo; + ae_int_t im; + ae_int_t iin; + ae_int_t ioff; + ae_int_t iout; + ae_int_t itmax; + ae_int_t iw; + ae_int_t iwoff; + ae_int_t j; + ae_int_t itmp1; + ae_int_t jb; + ae_int_t jdisc; + ae_int_t je; + ae_int_t nwl; + ae_int_t nwu; + double atoli; + double bnorm; + double gl; + double gu; + double pivmin; + double rtoli; + double safemn; + double tmp1; + double tmp2; + double tnorm; + double ulp; + double wkill; + double wl; + double wlu; + double wu; + double wul; + double scalefactor; + double t; + ae_vector idumma; + ae_vector work; + ae_vector iwork; + ae_vector ia1s2; + ae_vector ra1s2; + ae_matrix ra1s2x2; + ae_matrix ia1s2x2; + ae_vector ra1siin; + ae_vector ra2siin; + ae_vector ra3siin; + ae_vector ra4siin; + ae_matrix ra1siinx2; + ae_matrix ia1siinx2; + ae_vector iworkspace; + ae_vector rworkspace; + ae_int_t tmpi; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&d, 0, sizeof(d)); + memset(&e, 0, sizeof(e)); + memset(&idumma, 0, sizeof(idumma)); + memset(&work, 0, sizeof(work)); + memset(&iwork, 0, sizeof(iwork)); + memset(&ia1s2, 0, sizeof(ia1s2)); + memset(&ra1s2, 0, sizeof(ra1s2)); + memset(&ra1s2x2, 0, sizeof(ra1s2x2)); + memset(&ia1s2x2, 0, sizeof(ia1s2x2)); + memset(&ra1siin, 0, sizeof(ra1siin)); + memset(&ra2siin, 0, sizeof(ra2siin)); + memset(&ra3siin, 0, sizeof(ra3siin)); + memset(&ra4siin, 0, sizeof(ra4siin)); + memset(&ra1siinx2, 0, sizeof(ra1siinx2)); + memset(&ia1siinx2, 0, sizeof(ia1siinx2)); + memset(&iworkspace, 0, sizeof(iworkspace)); + memset(&rworkspace, 0, sizeof(rworkspace)); + ae_vector_init_copy(&d, _d, _state, ae_true); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_clear(w); + *m = 0; + *nsplit = 0; + ae_vector_clear(iblock); + ae_vector_clear(isplit); + *errorcode = 0; + ae_vector_init(&idumma, 0, DT_INT, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); + ae_vector_init(&ia1s2, 0, DT_INT, _state, ae_true); + ae_vector_init(&ra1s2, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ra1s2x2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ia1s2x2, 0, 0, DT_INT, _state, ae_true); + ae_vector_init(&ra1siin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ra2siin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ra3siin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ra4siin, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ra1siinx2, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ia1siinx2, 0, 0, DT_INT, _state, ae_true); + ae_vector_init(&iworkspace, 0, DT_INT, _state, ae_true); + ae_vector_init(&rworkspace, 0, DT_REAL, _state, ae_true); + + + /* + * Quick return if possible + */ + *m = 0; + if( n==0 ) + { + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Get machine constants + * NB is the minimum vector length for vector bisection, or 0 + * if only scalar is to be done. + */ + fudge = (double)(2); + relfac = (double)(2); + safemn = ae_minrealnumber; + ulp = (double)2*ae_machineepsilon; + rtoli = ulp*relfac; + ae_vector_set_length(&idumma, 1+1, _state); + ae_vector_set_length(&work, 4*n+1, _state); + ae_vector_set_length(&iwork, 3*n+1, _state); + ae_vector_set_length(w, n+1, _state); + ae_vector_set_length(iblock, n+1, _state); + ae_vector_set_length(isplit, n+1, _state); + ae_vector_set_length(&ia1s2, 2+1, _state); + ae_vector_set_length(&ra1s2, 2+1, _state); + ae_matrix_set_length(&ra1s2x2, 2+1, 2+1, _state); + ae_matrix_set_length(&ia1s2x2, 2+1, 2+1, _state); + ae_vector_set_length(&ra1siin, n+1, _state); + ae_vector_set_length(&ra2siin, n+1, _state); + ae_vector_set_length(&ra3siin, n+1, _state); + ae_vector_set_length(&ra4siin, n+1, _state); + ae_matrix_set_length(&ra1siinx2, n+1, 2+1, _state); + ae_matrix_set_length(&ia1siinx2, n+1, 2+1, _state); + ae_vector_set_length(&iworkspace, n+1, _state); + ae_vector_set_length(&rworkspace, n+1, _state); + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + wlu = (double)(0); + wul = (double)(0); + + /* + * Check for Errors + */ + result = ae_false; + *errorcode = 0; + if( irange<=0||irange>=4 ) + { + *errorcode = -4; + } + if( iorder<=0||iorder>=3 ) + { + *errorcode = -5; + } + if( n<0 ) + { + *errorcode = -3; + } + if( irange==2&&ae_fp_greater_eq(vl,vu) ) + { + *errorcode = -6; + } + if( irange==3&&(il<1||il>ae_maxint(1, n, _state)) ) + { + *errorcode = -8; + } + if( irange==3&&(iun) ) + { + *errorcode = -9; + } + if( *errorcode!=0 ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Initialize error flags + */ + ncnvrg = ae_false; + toofew = ae_false; + + /* + * Simplifications: + */ + if( (irange==3&&il==1)&&iu==n ) + { + irange = 1; + } + + /* + * Special Case when N=1 + */ + if( n==1 ) + { + *nsplit = 1; + isplit->ptr.p_int[1] = 1; + if( irange==2&&(ae_fp_greater_eq(vl,d.ptr.p_double[1])||ae_fp_less(vu,d.ptr.p_double[1])) ) + { + *m = 0; + } + else + { + w->ptr.p_double[1] = d.ptr.p_double[1]; + iblock->ptr.p_int[1] = 1; + *m = 1; + } + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Scaling + */ + t = ae_fabs(d.ptr.p_double[n], _state); + for(j=1; j<=n-1; j++) + { + t = ae_maxreal(t, ae_fabs(d.ptr.p_double[j], _state), _state); + t = ae_maxreal(t, ae_fabs(e.ptr.p_double[j], _state), _state); + } + scalefactor = (double)(1); + if( ae_fp_neq(t,(double)(0)) ) + { + if( ae_fp_greater(t,ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state)*ae_sqrt(ae_maxrealnumber, _state)) ) + { + scalefactor = t; + } + if( ae_fp_less(t,ae_sqrt(ae_sqrt(ae_maxrealnumber, _state), _state)*ae_sqrt(ae_minrealnumber, _state)) ) + { + scalefactor = t; + } + for(j=1; j<=n-1; j++) + { + d.ptr.p_double[j] = d.ptr.p_double[j]/scalefactor; + e.ptr.p_double[j] = e.ptr.p_double[j]/scalefactor; + } + d.ptr.p_double[n] = d.ptr.p_double[n]/scalefactor; + } + + /* + * Compute Splitting Points + */ + *nsplit = 1; + work.ptr.p_double[n] = (double)(0); + pivmin = (double)(1); + for(j=2; j<=n; j++) + { + tmp1 = ae_sqr(e.ptr.p_double[j-1], _state); + if( ae_fp_greater(ae_fabs(d.ptr.p_double[j]*d.ptr.p_double[j-1], _state)*ae_sqr(ulp, _state)+safemn,tmp1) ) + { + isplit->ptr.p_int[*nsplit] = j-1; + *nsplit = *nsplit+1; + work.ptr.p_double[j-1] = (double)(0); + } + else + { + work.ptr.p_double[j-1] = tmp1; + pivmin = ae_maxreal(pivmin, tmp1, _state); + } + } + isplit->ptr.p_int[*nsplit] = n; + pivmin = pivmin*safemn; + + /* + * Compute Interval and ATOLI + */ + if( irange==3 ) + { + + /* + * RANGE='I': Compute the interval containing eigenvalues + * IL through IU. + * + * Compute Gershgorin interval for entire (split) matrix + * and use it as the initial interval + */ + gu = d.ptr.p_double[1]; + gl = d.ptr.p_double[1]; + tmp1 = (double)(0); + for(j=1; j<=n-1; j++) + { + tmp2 = ae_sqrt(work.ptr.p_double[j], _state); + gu = ae_maxreal(gu, d.ptr.p_double[j]+tmp1+tmp2, _state); + gl = ae_minreal(gl, d.ptr.p_double[j]-tmp1-tmp2, _state); + tmp1 = tmp2; + } + gu = ae_maxreal(gu, d.ptr.p_double[n]+tmp1, _state); + gl = ae_minreal(gl, d.ptr.p_double[n]-tmp1, _state); + tnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); + gl = gl-fudge*tnorm*ulp*(double)n-fudge*(double)2*pivmin; + gu = gu+fudge*tnorm*ulp*(double)n+fudge*pivmin; + + /* + * Compute Iteration parameters + */ + itmax = ae_iceil((ae_log(tnorm+pivmin, _state)-ae_log(pivmin, _state))/ae_log((double)(2), _state), _state)+2; + if( ae_fp_less_eq(abstol,(double)(0)) ) + { + atoli = ulp*tnorm; + } + else + { + atoli = abstol; + } + work.ptr.p_double[n+1] = gl; + work.ptr.p_double[n+2] = gl; + work.ptr.p_double[n+3] = gu; + work.ptr.p_double[n+4] = gu; + work.ptr.p_double[n+5] = gl; + work.ptr.p_double[n+6] = gu; + iwork.ptr.p_int[1] = -1; + iwork.ptr.p_int[2] = -1; + iwork.ptr.p_int[3] = n+1; + iwork.ptr.p_int[4] = n+1; + iwork.ptr.p_int[5] = il-1; + iwork.ptr.p_int[6] = iu; + + /* + * Calling DLAEBZ + * + * DLAEBZ( 3, ITMAX, N, 2, 2, NB, ATOLI, RTOLI, PIVMIN, D, E, + * WORK, IWORK( 5 ), WORK( N+1 ), WORK( N+5 ), IOUT, + * IWORK, W, IBLOCK, IINFO ) + */ + ia1s2.ptr.p_int[1] = iwork.ptr.p_int[5]; + ia1s2.ptr.p_int[2] = iwork.ptr.p_int[6]; + ra1s2.ptr.p_double[1] = work.ptr.p_double[n+5]; + ra1s2.ptr.p_double[2] = work.ptr.p_double[n+6]; + ra1s2x2.ptr.pp_double[1][1] = work.ptr.p_double[n+1]; + ra1s2x2.ptr.pp_double[2][1] = work.ptr.p_double[n+2]; + ra1s2x2.ptr.pp_double[1][2] = work.ptr.p_double[n+3]; + ra1s2x2.ptr.pp_double[2][2] = work.ptr.p_double[n+4]; + ia1s2x2.ptr.pp_int[1][1] = iwork.ptr.p_int[1]; + ia1s2x2.ptr.pp_int[2][1] = iwork.ptr.p_int[2]; + ia1s2x2.ptr.pp_int[1][2] = iwork.ptr.p_int[3]; + ia1s2x2.ptr.pp_int[2][2] = iwork.ptr.p_int[4]; + evd_internaldlaebz(3, itmax, n, 2, 2, atoli, rtoli, pivmin, &d, &e, &work, &ia1s2, &ra1s2x2, &ra1s2, &iout, &ia1s2x2, w, iblock, &iinfo, _state); + iwork.ptr.p_int[5] = ia1s2.ptr.p_int[1]; + iwork.ptr.p_int[6] = ia1s2.ptr.p_int[2]; + work.ptr.p_double[n+5] = ra1s2.ptr.p_double[1]; + work.ptr.p_double[n+6] = ra1s2.ptr.p_double[2]; + work.ptr.p_double[n+1] = ra1s2x2.ptr.pp_double[1][1]; + work.ptr.p_double[n+2] = ra1s2x2.ptr.pp_double[2][1]; + work.ptr.p_double[n+3] = ra1s2x2.ptr.pp_double[1][2]; + work.ptr.p_double[n+4] = ra1s2x2.ptr.pp_double[2][2]; + iwork.ptr.p_int[1] = ia1s2x2.ptr.pp_int[1][1]; + iwork.ptr.p_int[2] = ia1s2x2.ptr.pp_int[2][1]; + iwork.ptr.p_int[3] = ia1s2x2.ptr.pp_int[1][2]; + iwork.ptr.p_int[4] = ia1s2x2.ptr.pp_int[2][2]; + if( iwork.ptr.p_int[6]==iu ) + { + wl = work.ptr.p_double[n+1]; + wlu = work.ptr.p_double[n+3]; + nwl = iwork.ptr.p_int[1]; + wu = work.ptr.p_double[n+4]; + wul = work.ptr.p_double[n+2]; + nwu = iwork.ptr.p_int[4]; + } + else + { + wl = work.ptr.p_double[n+2]; + wlu = work.ptr.p_double[n+4]; + nwl = iwork.ptr.p_int[2]; + wu = work.ptr.p_double[n+3]; + wul = work.ptr.p_double[n+1]; + nwu = iwork.ptr.p_int[3]; + } + if( ((nwl<0||nwl>=n)||nwu<1)||nwu>n ) + { + *errorcode = 4; + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + else + { + + /* + * RANGE='A' or 'V' -- Set ATOLI + */ + tnorm = ae_maxreal(ae_fabs(d.ptr.p_double[1], _state)+ae_fabs(e.ptr.p_double[1], _state), ae_fabs(d.ptr.p_double[n], _state)+ae_fabs(e.ptr.p_double[n-1], _state), _state); + for(j=2; j<=n-1; j++) + { + tnorm = ae_maxreal(tnorm, ae_fabs(d.ptr.p_double[j], _state)+ae_fabs(e.ptr.p_double[j-1], _state)+ae_fabs(e.ptr.p_double[j], _state), _state); + } + if( ae_fp_less_eq(abstol,(double)(0)) ) + { + atoli = ulp*tnorm; + } + else + { + atoli = abstol; + } + if( irange==2 ) + { + wl = vl; + wu = vu; + } + else + { + wl = (double)(0); + wu = (double)(0); + } + } + + /* + * Find Eigenvalues -- Loop Over Blocks and recompute NWL and NWU. + * NWL accumulates the number of eigenvalues .le. WL, + * NWU accumulates the number of eigenvalues .le. WU + */ + *m = 0; + iend = 0; + *errorcode = 0; + nwl = 0; + nwu = 0; + for(jb=1; jb<=*nsplit; jb++) + { + ioff = iend; + ibegin = ioff+1; + iend = isplit->ptr.p_int[jb]; + iin = iend-ioff; + if( iin==1 ) + { + + /* + * Special Case -- IIN=1 + */ + if( irange==1||ae_fp_greater_eq(wl,d.ptr.p_double[ibegin]-pivmin) ) + { + nwl = nwl+1; + } + if( irange==1||ae_fp_greater_eq(wu,d.ptr.p_double[ibegin]-pivmin) ) + { + nwu = nwu+1; + } + if( irange==1||(ae_fp_less(wl,d.ptr.p_double[ibegin]-pivmin)&&ae_fp_greater_eq(wu,d.ptr.p_double[ibegin]-pivmin)) ) + { + *m = *m+1; + w->ptr.p_double[*m] = d.ptr.p_double[ibegin]; + iblock->ptr.p_int[*m] = jb; + } + } + else + { + + /* + * General Case -- IIN > 1 + * + * Compute Gershgorin Interval + * and use it as the initial interval + */ + gu = d.ptr.p_double[ibegin]; + gl = d.ptr.p_double[ibegin]; + tmp1 = (double)(0); + for(j=ibegin; j<=iend-1; j++) + { + tmp2 = ae_fabs(e.ptr.p_double[j], _state); + gu = ae_maxreal(gu, d.ptr.p_double[j]+tmp1+tmp2, _state); + gl = ae_minreal(gl, d.ptr.p_double[j]-tmp1-tmp2, _state); + tmp1 = tmp2; + } + gu = ae_maxreal(gu, d.ptr.p_double[iend]+tmp1, _state); + gl = ae_minreal(gl, d.ptr.p_double[iend]-tmp1, _state); + bnorm = ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); + gl = gl-fudge*bnorm*ulp*(double)iin-fudge*pivmin; + gu = gu+fudge*bnorm*ulp*(double)iin+fudge*pivmin; + + /* + * Compute ATOLI for the current submatrix + */ + if( ae_fp_less_eq(abstol,(double)(0)) ) + { + atoli = ulp*ae_maxreal(ae_fabs(gl, _state), ae_fabs(gu, _state), _state); + } + else + { + atoli = abstol; + } + if( irange>1 ) + { + if( ae_fp_less(gu,wl) ) + { + nwl = nwl+iin; + nwu = nwu+iin; + continue; + } + gl = ae_maxreal(gl, wl, _state); + gu = ae_minreal(gu, wu, _state); + if( ae_fp_greater_eq(gl,gu) ) + { + continue; + } + } + + /* + * Set Up Initial Interval + */ + work.ptr.p_double[n+1] = gl; + work.ptr.p_double[n+iin+1] = gu; + + /* + * Calling DLAEBZ + * + * CALL DLAEBZ( 1, 0, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, + * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), + * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IM, + * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) + */ + for(tmpi=1; tmpi<=iin; tmpi++) + { + ra1siin.ptr.p_double[tmpi] = d.ptr.p_double[ibegin-1+tmpi]; + if( ibegin-1+tmpiptr.p_double[*m+tmpi]; + iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; + ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; + ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; + } + evd_internaldlaebz(1, 0, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &im, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); + for(tmpi=1; tmpi<=iin; tmpi++) + { + work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; + work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; + work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; + w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; + iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; + iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; + iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; + } + nwl = nwl+iwork.ptr.p_int[1]; + nwu = nwu+iwork.ptr.p_int[iin+1]; + iwoff = *m-iwork.ptr.p_int[1]; + + /* + * Compute Eigenvalues + */ + itmax = ae_iceil((ae_log(gu-gl+pivmin, _state)-ae_log(pivmin, _state))/ae_log((double)(2), _state), _state)+2; + + /* + * Calling DLAEBZ + * + *CALL DLAEBZ( 2, ITMAX, IN, IN, 1, NB, ATOLI, RTOLI, PIVMIN, + * D( IBEGIN ), E( IBEGIN ), WORK( IBEGIN ), + * IDUMMA, WORK( N+1 ), WORK( N+2*IN+1 ), IOUT, + * IWORK, W( M+1 ), IBLOCK( M+1 ), IINFO ) + */ + for(tmpi=1; tmpi<=iin; tmpi++) + { + ra1siin.ptr.p_double[tmpi] = d.ptr.p_double[ibegin-1+tmpi]; + if( ibegin-1+tmpiptr.p_double[*m+tmpi]; + iworkspace.ptr.p_int[tmpi] = iblock->ptr.p_int[*m+tmpi]; + ia1siinx2.ptr.pp_int[tmpi][1] = iwork.ptr.p_int[tmpi]; + ia1siinx2.ptr.pp_int[tmpi][2] = iwork.ptr.p_int[tmpi+iin]; + } + evd_internaldlaebz(2, itmax, iin, iin, 1, atoli, rtoli, pivmin, &ra1siin, &ra2siin, &ra3siin, &idumma, &ra1siinx2, &ra4siin, &iout, &ia1siinx2, &rworkspace, &iworkspace, &iinfo, _state); + for(tmpi=1; tmpi<=iin; tmpi++) + { + work.ptr.p_double[n+tmpi] = ra1siinx2.ptr.pp_double[tmpi][1]; + work.ptr.p_double[n+tmpi+iin] = ra1siinx2.ptr.pp_double[tmpi][2]; + work.ptr.p_double[n+2*iin+tmpi] = ra4siin.ptr.p_double[tmpi]; + w->ptr.p_double[*m+tmpi] = rworkspace.ptr.p_double[tmpi]; + iblock->ptr.p_int[*m+tmpi] = iworkspace.ptr.p_int[tmpi]; + iwork.ptr.p_int[tmpi] = ia1siinx2.ptr.pp_int[tmpi][1]; + iwork.ptr.p_int[tmpi+iin] = ia1siinx2.ptr.pp_int[tmpi][2]; + } + + /* + * Copy Eigenvalues Into W and IBLOCK + * Use -JB for block number for unconverged eigenvalues. + */ + for(j=1; j<=iout; j++) + { + tmp1 = 0.5*(work.ptr.p_double[j+n]+work.ptr.p_double[j+iin+n]); + + /* + * Flag non-convergence. + */ + if( j>iout-iinfo ) + { + ncnvrg = ae_true; + ib = -jb; + } + else + { + ib = jb; + } + for(je=iwork.ptr.p_int[j]+1+iwoff; je<=iwork.ptr.p_int[j+iin]+iwoff; je++) + { + w->ptr.p_double[je] = tmp1; + iblock->ptr.p_int[je] = ib; + } + } + *m = *m+im; + } + } + + /* + * If RANGE='I', then (WL,WU) contains eigenvalues NWL+1,...,NWU + * If NWL+1 < IL or NWU > IU, discard extra eigenvalues. + */ + if( irange==3 ) + { + im = 0; + idiscl = il-1-nwl; + idiscu = nwu-iu; + if( idiscl>0||idiscu>0 ) + { + for(je=1; je<=*m; je++) + { + if( ae_fp_less_eq(w->ptr.p_double[je],wlu)&&idiscl>0 ) + { + idiscl = idiscl-1; + } + else + { + if( ae_fp_greater_eq(w->ptr.p_double[je],wul)&&idiscu>0 ) + { + idiscu = idiscu-1; + } + else + { + im = im+1; + w->ptr.p_double[im] = w->ptr.p_double[je]; + iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; + } + } + } + *m = im; + } + if( idiscl>0||idiscu>0 ) + { + + /* + * Code to deal with effects of bad arithmetic: + * Some low eigenvalues to be discarded are not in (WL,WLU], + * or high eigenvalues to be discarded are not in (WUL,WU] + * so just kill off the smallest IDISCL/largest IDISCU + * eigenvalues, by simply finding the smallest/largest + * eigenvalue(s). + * + * (If N(w) is monotone non-decreasing, this should never + * happen.) + */ + if( idiscl>0 ) + { + wkill = wu; + for(jdisc=1; jdisc<=idiscl; jdisc++) + { + iw = 0; + for(je=1; je<=*m; je++) + { + if( iblock->ptr.p_int[je]!=0&&(ae_fp_less(w->ptr.p_double[je],wkill)||iw==0) ) + { + iw = je; + wkill = w->ptr.p_double[je]; + } + } + iblock->ptr.p_int[iw] = 0; + } + } + if( idiscu>0 ) + { + wkill = wl; + for(jdisc=1; jdisc<=idiscu; jdisc++) + { + iw = 0; + for(je=1; je<=*m; je++) + { + if( iblock->ptr.p_int[je]!=0&&(ae_fp_greater(w->ptr.p_double[je],wkill)||iw==0) ) + { + iw = je; + wkill = w->ptr.p_double[je]; + } + } + iblock->ptr.p_int[iw] = 0; + } + } + im = 0; + for(je=1; je<=*m; je++) + { + if( iblock->ptr.p_int[je]!=0 ) + { + im = im+1; + w->ptr.p_double[im] = w->ptr.p_double[je]; + iblock->ptr.p_int[im] = iblock->ptr.p_int[je]; + } + } + *m = im; + } + if( idiscl<0||idiscu<0 ) + { + toofew = ae_true; + } + } + + /* + * If ORDER='B', do nothing -- the eigenvalues are already sorted + * by block. + * If ORDER='E', sort the eigenvalues from smallest to largest + */ + if( iorder==1&&*nsplit>1 ) + { + for(je=1; je<=*m-1; je++) + { + ie = 0; + tmp1 = w->ptr.p_double[je]; + for(j=je+1; j<=*m; j++) + { + if( ae_fp_less(w->ptr.p_double[j],tmp1) ) + { + ie = j; + tmp1 = w->ptr.p_double[j]; + } + } + if( ie!=0 ) + { + itmp1 = iblock->ptr.p_int[ie]; + w->ptr.p_double[ie] = w->ptr.p_double[je]; + iblock->ptr.p_int[ie] = iblock->ptr.p_int[je]; + w->ptr.p_double[je] = tmp1; + iblock->ptr.p_int[je] = itmp1; + } + } + } + for(j=1; j<=*m; j++) + { + w->ptr.p_double[j] = w->ptr.p_double[j]*scalefactor; + } + *errorcode = 0; + if( ncnvrg ) + { + *errorcode = *errorcode+1; + } + if( toofew ) + { + *errorcode = *errorcode+2; + } + result = *errorcode==0; + ae_frame_leave(_state); + return result; +} + + +static void evd_internaldstein(ae_int_t n, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t m, + /* Real */ const ae_vector* _w, + /* Integer */ const ae_vector* iblock, + /* Integer */ const ae_vector* isplit, + /* Real */ ae_matrix* z, + /* Integer */ ae_vector* ifail, + ae_int_t* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_vector w; + ae_int_t maxits; + ae_int_t extra; + ae_int_t b1; + ae_int_t blksiz; + ae_int_t bn; + ae_int_t gpind; + ae_int_t i; + ae_int_t iinfo; + ae_int_t its; + ae_int_t j; + ae_int_t j1; + ae_int_t jblk; + ae_int_t jmax; + ae_int_t nblk; + ae_int_t nrmchk; + double dtpcrt; + double eps; + double eps1; + double nrm; + double onenrm; + double ortol; + double pertol; + double scl; + double sep; + double tol; + double xj; + double xjm; + double ztr; + ae_vector work1; + ae_vector work2; + ae_vector work3; + ae_vector work4; + ae_vector work5; + ae_vector iwork; + ae_bool tmpcriterion; + ae_int_t ti; + ae_int_t i1; + ae_int_t i2; + double v; + hqrndstate rs; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + memset(&w, 0, sizeof(w)); + memset(&work1, 0, sizeof(work1)); + memset(&work2, 0, sizeof(work2)); + memset(&work3, 0, sizeof(work3)); + memset(&work4, 0, sizeof(work4)); + memset(&work5, 0, sizeof(work5)); + memset(&iwork, 0, sizeof(iwork)); + memset(&rs, 0, sizeof(rs)); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_init_copy(&w, _w, _state, ae_true); + ae_matrix_clear(z); + ae_vector_clear(ifail); + *info = 0; + ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work4, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work5, 0, DT_REAL, _state, ae_true); + ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); + _hqrndstate_init(&rs, _state, ae_true); + + hqrndseed(346436, 2434, &rs, _state); + maxits = 5; + extra = 2; + ae_vector_set_length(&work1, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&work2, ae_maxint(n-1, 1, _state)+1, _state); + ae_vector_set_length(&work3, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&work4, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&work5, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(&iwork, ae_maxint(n, 1, _state)+1, _state); + ae_vector_set_length(ifail, ae_maxint(m, 1, _state)+1, _state); + ae_matrix_set_length(z, ae_maxint(n, 1, _state)+1, ae_maxint(m, 1, _state)+1, _state); + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + gpind = 0; + onenrm = (double)(0); + ortol = (double)(0); + dtpcrt = (double)(0); + xjm = (double)(0); + + /* + * Test the input parameters. + */ + *info = 0; + for(i=1; i<=m; i++) + { + ifail->ptr.p_int[i] = 0; + } + if( n<0 ) + { + *info = -1; + ae_frame_leave(_state); + return; + } + if( m<0||m>n ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + for(j=2; j<=m; j++) + { + if( iblock->ptr.p_int[j]ptr.p_int[j-1] ) + { + *info = -6; + break; + } + if( iblock->ptr.p_int[j]==iblock->ptr.p_int[j-1]&&ae_fp_less(w.ptr.p_double[j],w.ptr.p_double[j-1]) ) + { + *info = -5; + break; + } + } + if( *info!=0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Quick return if possible + */ + if( n==0||m==0 ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + z->ptr.pp_double[1][1] = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Some preparations + */ + ti = n-1; + ae_v_move(&work1.ptr.p_double[1], 1, &e.ptr.p_double[1], 1, ae_v_len(1,ti)); + ae_vector_set_length(&e, n+1, _state); + ae_v_move(&e.ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,ti)); + ae_v_move(&work1.ptr.p_double[1], 1, &w.ptr.p_double[1], 1, ae_v_len(1,m)); + ae_vector_set_length(&w, n+1, _state); + ae_v_move(&w.ptr.p_double[1], 1, &work1.ptr.p_double[1], 1, ae_v_len(1,m)); + + /* + * Get machine constants. + */ + eps = ae_machineepsilon; + + /* + * Compute eigenvectors of matrix blocks. + */ + j1 = 1; + for(nblk=1; nblk<=iblock->ptr.p_int[m]; nblk++) + { + + /* + * Find starting and ending indices of block nblk. + */ + if( nblk==1 ) + { + b1 = 1; + } + else + { + b1 = isplit->ptr.p_int[nblk-1]+1; + } + bn = isplit->ptr.p_int[nblk]; + blksiz = bn-b1+1; + if( blksiz!=1 ) + { + + /* + * Compute reorthogonalization criterion and stopping criterion. + */ + gpind = b1; + onenrm = ae_fabs(d->ptr.p_double[b1], _state)+ae_fabs(e.ptr.p_double[b1], _state); + onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[bn], _state)+ae_fabs(e.ptr.p_double[bn-1], _state), _state); + for(i=b1+1; i<=bn-1; i++) + { + onenrm = ae_maxreal(onenrm, ae_fabs(d->ptr.p_double[i], _state)+ae_fabs(e.ptr.p_double[i-1], _state)+ae_fabs(e.ptr.p_double[i], _state), _state); + } + ortol = 0.001*onenrm; + dtpcrt = ae_sqrt(0.1/(double)blksiz, _state); + } + + /* + * Loop through eigenvalues of block nblk. + */ + jblk = 0; + for(j=j1; j<=m; j++) + { + if( iblock->ptr.p_int[j]!=nblk ) + { + j1 = j; + break; + } + jblk = jblk+1; + xj = w.ptr.p_double[j]; + if( blksiz==1 ) + { + + /* + * Skip all the work if the block size is one. + */ + work1.ptr.p_double[1] = (double)(1); + } + else + { + + /* + * If eigenvalues j and j-1 are too close, add a relatively + * small perturbation. + */ + if( jblk>1 ) + { + eps1 = ae_fabs(eps*xj, _state); + pertol = (double)10*eps1; + sep = xj-xjm; + if( ae_fp_less(sep,pertol) ) + { + xj = xjm+pertol; + } + } + its = 0; + nrmchk = 0; + + /* + * Get random starting vector. + */ + for(ti=1; ti<=blksiz; ti++) + { + work1.ptr.p_double[ti] = (double)2*hqrnduniformr(&rs, _state)-(double)1; + } + + /* + * Copy the matrix T so it won't be destroyed in factorization. + */ + for(ti=1; ti<=blksiz-1; ti++) + { + work2.ptr.p_double[ti] = e.ptr.p_double[b1+ti-1]; + work3.ptr.p_double[ti] = e.ptr.p_double[b1+ti-1]; + work4.ptr.p_double[ti] = d->ptr.p_double[b1+ti-1]; + } + work4.ptr.p_double[blksiz] = d->ptr.p_double[b1+blksiz-1]; + + /* + * Compute LU factors with partial pivoting ( PT = LU ) + */ + tol = (double)(0); + evd_tdininternaldlagtf(blksiz, &work4, xj, &work2, &work3, tol, &work5, &iwork, &iinfo, _state); + + /* + * Update iteration count. + */ + do + { + its = its+1; + if( its>maxits ) + { + + /* + * If stopping criterion was not satisfied, update info and + * store eigenvector number in array ifail. + */ + *info = *info+1; + ifail->ptr.p_int[*info] = j; + break; + } + + /* + * Normalize and scale the righthand side vector Pb. + */ + v = (double)(0); + for(ti=1; ti<=blksiz; ti++) + { + v = v+ae_fabs(work1.ptr.p_double[ti], _state); + } + scl = (double)blksiz*onenrm*ae_maxreal(eps, ae_fabs(work4.ptr.p_double[blksiz], _state), _state)/v; + ae_v_muld(&work1.ptr.p_double[1], 1, ae_v_len(1,blksiz), scl); + + /* + * Solve the system LU = Pb. + */ + evd_tdininternaldlagts(blksiz, &work4, &work2, &work3, &work5, &iwork, &work1, &tol, &iinfo, _state); + + /* + * Reorthogonalize by modified Gram-Schmidt if eigenvalues are + * close enough. + */ + if( jblk!=1 ) + { + if( ae_fp_greater(ae_fabs(xj-xjm, _state),ortol) ) + { + gpind = j; + } + if( gpind!=j ) + { + for(i=gpind; i<=j-1; i++) + { + i1 = b1; + i2 = b1+blksiz-1; + ztr = ae_v_dotproduct(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz)); + ae_v_subd(&work1.ptr.p_double[1], 1, &z->ptr.pp_double[i1][i], z->stride, ae_v_len(1,blksiz), ztr); + touchint(&i2, _state); + } + } + } + + /* + * Check the infinity norm of the iterate. + */ + jmax = vectoridxabsmax(&work1, 1, blksiz, _state); + nrm = ae_fabs(work1.ptr.p_double[jmax], _state); + + /* + * Continue for additional iterations after norm reaches + * stopping criterion. + */ + tmpcriterion = ae_false; + if( ae_fp_less(nrm,dtpcrt) ) + { + tmpcriterion = ae_true; + } + else + { + nrmchk = nrmchk+1; + if( nrmchkptr.pp_double[i][j] = (double)(0); + } + for(i=1; i<=blksiz; i++) + { + z->ptr.pp_double[b1+i-1][j] = work1.ptr.p_double[i]; + } + + /* + * Save the shift to check eigenvalue spacing at next + * iteration. + */ + xjm = xj; + } + } + ae_frame_leave(_state); +} + + +static void evd_tdininternaldlagtf(ae_int_t n, + /* Real */ ae_vector* a, + double lambdav, + /* Real */ ae_vector* b, + /* Real */ ae_vector* c, + double tol, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* iin, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t k; + double eps; + double mult; + double piv1; + double piv2; + double scale1; + double scale2; + double temp; + double tl; + + *info = 0; + + *info = 0; + if( n<0 ) + { + *info = -1; + return; + } + if( n==0 ) + { + return; + } + a->ptr.p_double[1] = a->ptr.p_double[1]-lambdav; + iin->ptr.p_int[n] = 0; + if( n==1 ) + { + if( ae_fp_eq(a->ptr.p_double[1],(double)(0)) ) + { + iin->ptr.p_int[1] = 1; + } + return; + } + eps = ae_machineepsilon; + tl = ae_maxreal(tol, eps, _state); + scale1 = ae_fabs(a->ptr.p_double[1], _state)+ae_fabs(b->ptr.p_double[1], _state); + for(k=1; k<=n-1; k++) + { + a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-lambdav; + scale2 = ae_fabs(c->ptr.p_double[k], _state)+ae_fabs(a->ptr.p_double[k+1], _state); + if( kptr.p_double[k+1], _state); + } + if( ae_fp_eq(a->ptr.p_double[k],(double)(0)) ) + { + piv1 = (double)(0); + } + else + { + piv1 = ae_fabs(a->ptr.p_double[k], _state)/scale1; + } + if( ae_fp_eq(c->ptr.p_double[k],(double)(0)) ) + { + iin->ptr.p_int[k] = 0; + piv2 = (double)(0); + scale1 = scale2; + if( kptr.p_double[k] = (double)(0); + } + } + else + { + piv2 = ae_fabs(c->ptr.p_double[k], _state)/scale2; + if( ae_fp_less_eq(piv2,piv1) ) + { + iin->ptr.p_int[k] = 0; + scale1 = scale2; + c->ptr.p_double[k] = c->ptr.p_double[k]/a->ptr.p_double[k]; + a->ptr.p_double[k+1] = a->ptr.p_double[k+1]-c->ptr.p_double[k]*b->ptr.p_double[k]; + if( kptr.p_double[k] = (double)(0); + } + } + else + { + iin->ptr.p_int[k] = 1; + mult = a->ptr.p_double[k]/c->ptr.p_double[k]; + a->ptr.p_double[k] = c->ptr.p_double[k]; + temp = a->ptr.p_double[k+1]; + a->ptr.p_double[k+1] = b->ptr.p_double[k]-mult*temp; + if( kptr.p_double[k] = b->ptr.p_double[k+1]; + b->ptr.p_double[k+1] = -mult*d->ptr.p_double[k]; + } + b->ptr.p_double[k] = temp; + c->ptr.p_double[k] = mult; + } + } + if( ae_fp_less_eq(ae_maxreal(piv1, piv2, _state),tl)&&iin->ptr.p_int[n]==0 ) + { + iin->ptr.p_int[n] = k; + } + } + if( ae_fp_less_eq(ae_fabs(a->ptr.p_double[n], _state),scale1*tl)&&iin->ptr.p_int[n]==0 ) + { + iin->ptr.p_int[n] = n; + } +} + + +static void evd_tdininternaldlagts(ae_int_t n, + /* Real */ const ae_vector* a, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* d, + /* Integer */ const ae_vector* iin, + /* Real */ ae_vector* y, + double* tol, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t k; + double absak; + double ak; + double bignum; + double eps; + double pert; + double sfmin; + double temp; + + *info = 0; + + *info = 0; + if( n<0 ) + { + *info = -1; + return; + } + if( n==0 ) + { + return; + } + eps = ae_machineepsilon; + sfmin = ae_minrealnumber; + bignum = (double)1/sfmin; + if( ae_fp_less_eq(*tol,(double)(0)) ) + { + *tol = ae_fabs(a->ptr.p_double[1], _state); + if( n>1 ) + { + *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[2], _state), ae_fabs(b->ptr.p_double[1], _state), _state), _state); + } + for(k=3; k<=n; k++) + { + *tol = ae_maxreal(*tol, ae_maxreal(ae_fabs(a->ptr.p_double[k], _state), ae_maxreal(ae_fabs(b->ptr.p_double[k-1], _state), ae_fabs(d->ptr.p_double[k-2], _state), _state), _state), _state); + } + *tol = *tol*eps; + if( ae_fp_eq(*tol,(double)(0)) ) + { + *tol = eps; + } + } + for(k=2; k<=n; k++) + { + if( iin->ptr.p_int[k-1]==0 ) + { + y->ptr.p_double[k] = y->ptr.p_double[k]-c->ptr.p_double[k-1]*y->ptr.p_double[k-1]; + } + else + { + temp = y->ptr.p_double[k-1]; + y->ptr.p_double[k-1] = y->ptr.p_double[k]; + y->ptr.p_double[k] = temp-c->ptr.p_double[k-1]*y->ptr.p_double[k]; + } + } + for(k=n; k>=1; k--) + { + if( k<=n-2 ) + { + temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]-d->ptr.p_double[k]*y->ptr.p_double[k+2]; + } + else + { + if( k==n-1 ) + { + temp = y->ptr.p_double[k]-b->ptr.p_double[k]*y->ptr.p_double[k+1]; + } + else + { + temp = y->ptr.p_double[k]; + } + } + ak = a->ptr.p_double[k]; + pert = ae_fabs(*tol, _state); + if( ae_fp_less(ak,(double)(0)) ) + { + pert = -pert; + } + for(;;) + { + absak = ae_fabs(ak, _state); + if( ae_fp_less(absak,(double)(1)) ) + { + if( ae_fp_less(absak,sfmin) ) + { + if( ae_fp_eq(absak,(double)(0))||ae_fp_greater(ae_fabs(temp, _state)*sfmin,absak) ) + { + ak = ak+pert; + pert = (double)2*pert; + continue; + } + else + { + temp = temp*bignum; + ak = ak*bignum; + } + } + else + { + if( ae_fp_greater(ae_fabs(temp, _state),absak*bignum) ) + { + ak = ak+pert; + pert = (double)2*pert; + continue; + } + } + } + break; + } + y->ptr.p_double[k] = temp/ak; + } +} + + +static void evd_internaldlaebz(ae_int_t ijob, + ae_int_t nitmax, + ae_int_t n, + ae_int_t mmax, + ae_int_t minp, + double abstol, + double reltol, + double pivmin, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* e, + /* Real */ const ae_vector* e2, + /* Integer */ ae_vector* nval, + /* Real */ ae_matrix* ab, + /* Real */ ae_vector* c, + ae_int_t* mout, + /* Integer */ ae_matrix* nab, + /* Real */ ae_vector* work, + /* Integer */ ae_vector* iwork, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t itmp1; + ae_int_t itmp2; + ae_int_t j; + ae_int_t ji; + ae_int_t jit; + ae_int_t jp; + ae_int_t kf; + ae_int_t kfnew; + ae_int_t kl; + ae_int_t klnew; + double tmp1; + double tmp2; + + *mout = 0; + *info = 0; + + *info = 0; + if( ijob<1||ijob>3 ) + { + *info = -1; + return; + } + + /* + * Initialize NAB + */ + if( ijob==1 ) + { + + /* + * Compute the number of eigenvalues in the initial intervals. + */ + *mout = 0; + + /* + *DIR$ NOVECTOR + */ + for(ji=1; ji<=minp; ji++) + { + for(jp=1; jp<=2; jp++) + { + tmp1 = d->ptr.p_double[1]-ab->ptr.pp_double[ji][jp]; + if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) + { + tmp1 = -pivmin; + } + nab->ptr.pp_int[ji][jp] = 0; + if( ae_fp_less_eq(tmp1,(double)(0)) ) + { + nab->ptr.pp_int[ji][jp] = 1; + } + for(j=2; j<=n; j++) + { + tmp1 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp1-ab->ptr.pp_double[ji][jp]; + if( ae_fp_less(ae_fabs(tmp1, _state),pivmin) ) + { + tmp1 = -pivmin; + } + if( ae_fp_less_eq(tmp1,(double)(0)) ) + { + nab->ptr.pp_int[ji][jp] = nab->ptr.pp_int[ji][jp]+1; + } + } + } + *mout = *mout+nab->ptr.pp_int[ji][2]-nab->ptr.pp_int[ji][1]; + } + return; + } + + /* + * Initialize for loop + * + * KF and KL have the following meaning: + * Intervals 1,...,KF-1 have converged. + * Intervals KF,...,KL still need to be refined. + */ + kf = 1; + kl = minp; + + /* + * If IJOB=2, initialize C. + * If IJOB=3, use the user-supplied starting point. + */ + if( ijob==2 ) + { + for(ji=1; ji<=minp; ji++) + { + c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); + } + } + + /* + * Iteration loop + */ + for(jit=1; jit<=nitmax; jit++) + { + + /* + * Loop over intervals + * + * + * Serial Version of the loop + */ + klnew = kl; + for(ji=kf; ji<=kl; ji++) + { + + /* + * Compute N(w), the number of eigenvalues less than w + */ + tmp1 = c->ptr.p_double[ji]; + tmp2 = d->ptr.p_double[1]-tmp1; + itmp1 = 0; + if( ae_fp_less_eq(tmp2,pivmin) ) + { + itmp1 = 1; + tmp2 = ae_minreal(tmp2, -pivmin, _state); + } + + /* + * A series of compiler directives to defeat vectorization + * for the next loop + * + **$PL$ CMCHAR=' ' + *CDIR$ NEXTSCALAR + *C$DIR SCALAR + *CDIR$ NEXT SCALAR + *CVD$L NOVECTOR + *CDEC$ NOVECTOR + *CVD$ NOVECTOR + **VDIR NOVECTOR + **VOCL LOOP,SCALAR + *CIBM PREFER SCALAR + **$PL$ CMCHAR='*' + */ + for(j=2; j<=n; j++) + { + tmp2 = d->ptr.p_double[j]-e2->ptr.p_double[j-1]/tmp2-tmp1; + if( ae_fp_less_eq(tmp2,pivmin) ) + { + itmp1 = itmp1+1; + tmp2 = ae_minreal(tmp2, -pivmin, _state); + } + } + if( ijob<=2 ) + { + + /* + * IJOB=2: Choose all intervals containing eigenvalues. + * + * Insure that N(w) is monotone + */ + itmp1 = ae_minint(nab->ptr.pp_int[ji][2], ae_maxint(nab->ptr.pp_int[ji][1], itmp1, _state), _state); + + /* + * Update the Queue -- add intervals if both halves + * contain eigenvalues. + */ + if( itmp1==nab->ptr.pp_int[ji][2] ) + { + + /* + * No eigenvalue in the upper interval: + * just use the lower interval. + */ + ab->ptr.pp_double[ji][2] = tmp1; + } + else + { + if( itmp1==nab->ptr.pp_int[ji][1] ) + { + + /* + * No eigenvalue in the lower interval: + * just use the upper interval. + */ + ab->ptr.pp_double[ji][1] = tmp1; + } + else + { + if( klnewptr.pp_double[klnew][2] = ab->ptr.pp_double[ji][2]; + nab->ptr.pp_int[klnew][2] = nab->ptr.pp_int[ji][2]; + ab->ptr.pp_double[klnew][1] = tmp1; + nab->ptr.pp_int[klnew][1] = itmp1; + ab->ptr.pp_double[ji][2] = tmp1; + nab->ptr.pp_int[ji][2] = itmp1; + } + else + { + *info = mmax+1; + return; + } + } + } + } + else + { + + /* + * IJOB=3: Binary search. Keep only the interval + * containing w s.t. N(w) = NVAL + */ + if( itmp1<=nval->ptr.p_int[ji] ) + { + ab->ptr.pp_double[ji][1] = tmp1; + nab->ptr.pp_int[ji][1] = itmp1; + } + if( itmp1>=nval->ptr.p_int[ji] ) + { + ab->ptr.pp_double[ji][2] = tmp1; + nab->ptr.pp_int[ji][2] = itmp1; + } + } + } + kl = klnew; + + /* + * Check for convergence + */ + kfnew = kf; + for(ji=kf; ji<=kl; ji++) + { + tmp1 = ae_fabs(ab->ptr.pp_double[ji][2]-ab->ptr.pp_double[ji][1], _state); + tmp2 = ae_maxreal(ae_fabs(ab->ptr.pp_double[ji][2], _state), ae_fabs(ab->ptr.pp_double[ji][1], _state), _state); + if( ae_fp_less(tmp1,ae_maxreal(abstol, ae_maxreal(pivmin, reltol*tmp2, _state), _state))||nab->ptr.pp_int[ji][1]>=nab->ptr.pp_int[ji][2] ) + { + + /* + * Converged -- Swap with position KFNEW, + * then increment KFNEW + */ + if( ji>kfnew ) + { + tmp1 = ab->ptr.pp_double[ji][1]; + tmp2 = ab->ptr.pp_double[ji][2]; + itmp1 = nab->ptr.pp_int[ji][1]; + itmp2 = nab->ptr.pp_int[ji][2]; + ab->ptr.pp_double[ji][1] = ab->ptr.pp_double[kfnew][1]; + ab->ptr.pp_double[ji][2] = ab->ptr.pp_double[kfnew][2]; + nab->ptr.pp_int[ji][1] = nab->ptr.pp_int[kfnew][1]; + nab->ptr.pp_int[ji][2] = nab->ptr.pp_int[kfnew][2]; + ab->ptr.pp_double[kfnew][1] = tmp1; + ab->ptr.pp_double[kfnew][2] = tmp2; + nab->ptr.pp_int[kfnew][1] = itmp1; + nab->ptr.pp_int[kfnew][2] = itmp2; + if( ijob==3 ) + { + itmp1 = nval->ptr.p_int[ji]; + nval->ptr.p_int[ji] = nval->ptr.p_int[kfnew]; + nval->ptr.p_int[kfnew] = itmp1; + } + } + kfnew = kfnew+1; + } + } + kf = kfnew; + + /* + * Choose Midpoints + */ + for(ji=kf; ji<=kl; ji++) + { + c->ptr.p_double[ji] = 0.5*(ab->ptr.pp_double[ji][1]+ab->ptr.pp_double[ji][2]); + } + + /* + * If no more intervals to refine, quit. + */ + if( kf>kl ) + { + break; + } + } + + /* + * Converged + */ + *info = ae_maxint(kl+1-kf, 0, _state); + *mout = kl; +} + + +/************************************************************************* +Internal subroutine + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1999 +*************************************************************************/ +static void evd_rmatrixinternaltrevc(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Boolean */ const ae_vector* _vselect, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector vselect; + ae_int_t i; + ae_int_t j; + ae_matrix t1; + ae_matrix vl1; + ae_matrix vr1; + ae_vector vselect1; + + ae_frame_make(_state, &_frame_block); + memset(&vselect, 0, sizeof(vselect)); + memset(&t1, 0, sizeof(t1)); + memset(&vl1, 0, sizeof(vl1)); + memset(&vr1, 0, sizeof(vr1)); + memset(&vselect1, 0, sizeof(vselect1)); + ae_vector_init_copy(&vselect, _vselect, _state, ae_true); + *m = 0; + *info = 0; + ae_matrix_init(&t1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vl1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vr1, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vselect1, 0, DT_BOOL, _state, ae_true); + + + /* + * Allocate VL/VR, if needed + */ + if( howmny==2||howmny==3 ) + { + if( side==1||side==3 ) + { + rmatrixsetlengthatleast(vr, n, n, _state); + } + if( side==2||side==3 ) + { + rmatrixsetlengthatleast(vl, n, n, _state); + } + } + + /* + * Try to use PBL kernel + */ + if( rmatrixinternaltrevcpbl(t, n, side, howmny, vl, vr, m, info, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * ALGLIB version + */ + ae_matrix_set_length(&t1, n+1, n+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + t1.ptr.pp_double[i+1][j+1] = t->ptr.pp_double[i][j]; + } + } + if( howmny==3 ) + { + ae_vector_set_length(&vselect1, n+1, _state); + for(i=0; i<=n-1; i++) + { + vselect1.ptr.p_bool[1+i] = vselect.ptr.p_bool[i]; + } + } + if( (side==2||side==3)&&howmny==1 ) + { + ae_matrix_set_length(&vl1, n+1, n+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + vl1.ptr.pp_double[i+1][j+1] = vl->ptr.pp_double[i][j]; + } + } + } + if( (side==1||side==3)&&howmny==1 ) + { + ae_matrix_set_length(&vr1, n+1, n+1, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + vr1.ptr.pp_double[i+1][j+1] = vr->ptr.pp_double[i][j]; + } + } + } + evd_internaltrevc(&t1, n, side, howmny, &vselect1, &vl1, &vr1, m, info, _state); + if( side!=1 ) + { + rmatrixsetlengthatleast(vl, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + vl->ptr.pp_double[i][j] = vl1.ptr.pp_double[i+1][j+1]; + } + } + } + if( side!=2 ) + { + rmatrixsetlengthatleast(vr, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + vr->ptr.pp_double[i][j] = vr1.ptr.pp_double[i+1][j+1]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1999 +*************************************************************************/ +static void evd_internaltrevc(/* Real */ const ae_matrix* t, + ae_int_t n, + ae_int_t side, + ae_int_t howmny, + /* Boolean */ const ae_vector* _vselect, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_int_t* m, + ae_int_t* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector vselect; + ae_bool allv; + ae_bool bothv; + ae_bool leftv; + ae_bool over; + ae_bool pair; + ae_bool rightv; + ae_bool somev; + ae_int_t i; + ae_int_t ierr; + ae_int_t ii; + ae_int_t ip; + ae_int_t iis; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + ae_int_t jnxt; + ae_int_t k; + ae_int_t ki; + ae_int_t n2; + double beta; + double bignum; + double emax; + double rec; + double remax; + double scl; + double smin; + double smlnum; + double ulp; + double unfl; + double vcrit; + double vmax; + double wi; + double wr; + double xnorm; + ae_matrix x; + ae_vector work; + ae_vector temp; + ae_matrix temp11; + ae_matrix temp22; + ae_matrix temp11b; + ae_matrix temp21b; + ae_matrix temp12b; + ae_matrix temp22b; + ae_bool skipflag; + ae_int_t k1; + ae_int_t k2; + ae_int_t k3; + ae_int_t k4; + double vt; + ae_vector rswap4; + ae_vector zswap4; + ae_matrix ipivot44; + ae_vector civ4; + ae_vector crv4; + + ae_frame_make(_state, &_frame_block); + memset(&vselect, 0, sizeof(vselect)); + memset(&x, 0, sizeof(x)); + memset(&work, 0, sizeof(work)); + memset(&temp, 0, sizeof(temp)); + memset(&temp11, 0, sizeof(temp11)); + memset(&temp22, 0, sizeof(temp22)); + memset(&temp11b, 0, sizeof(temp11b)); + memset(&temp21b, 0, sizeof(temp21b)); + memset(&temp12b, 0, sizeof(temp12b)); + memset(&temp22b, 0, sizeof(temp22b)); + memset(&rswap4, 0, sizeof(rswap4)); + memset(&zswap4, 0, sizeof(zswap4)); + memset(&ipivot44, 0, sizeof(ipivot44)); + memset(&civ4, 0, sizeof(civ4)); + memset(&crv4, 0, sizeof(crv4)); + ae_vector_init_copy(&vselect, _vselect, _state, ae_true); + *m = 0; + *info = 0; + ae_matrix_init(&x, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_vector_init(&temp, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp11, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp22, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp11b, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp21b, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp12b, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&temp22b, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rswap4, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&zswap4, 0, DT_BOOL, _state, ae_true); + ae_matrix_init(&ipivot44, 0, 0, DT_INT, _state, ae_true); + ae_vector_init(&civ4, 0, DT_REAL, _state, ae_true); + ae_vector_init(&crv4, 0, DT_REAL, _state, ae_true); + + ae_matrix_set_length(&x, 2+1, 2+1, _state); + ae_matrix_set_length(&temp11, 1+1, 1+1, _state); + ae_matrix_set_length(&temp11b, 1+1, 1+1, _state); + ae_matrix_set_length(&temp21b, 2+1, 1+1, _state); + ae_matrix_set_length(&temp12b, 1+1, 2+1, _state); + ae_matrix_set_length(&temp22b, 2+1, 2+1, _state); + ae_matrix_set_length(&temp22, 2+1, 2+1, _state); + ae_vector_set_length(&work, 3*n+1, _state); + ae_vector_set_length(&temp, n+1, _state); + ae_vector_set_length(&rswap4, 4+1, _state); + ae_vector_set_length(&zswap4, 4+1, _state); + ae_matrix_set_length(&ipivot44, 4+1, 4+1, _state); + ae_vector_set_length(&civ4, 4+1, _state); + ae_vector_set_length(&crv4, 4+1, _state); + if( howmny!=1 ) + { + if( side==1||side==3 ) + { + ae_matrix_set_length(vr, n+1, n+1, _state); + } + if( side==2||side==3 ) + { + ae_matrix_set_length(vl, n+1, n+1, _state); + } + } + + /* + * Decode and test the input parameters + */ + bothv = side==3; + rightv = side==1||bothv; + leftv = side==2||bothv; + allv = howmny==2; + over = howmny==1; + somev = howmny==3; + *info = 0; + if( n<0 ) + { + *info = -2; + ae_frame_leave(_state); + return; + } + if( !rightv&&!leftv ) + { + *info = -3; + ae_frame_leave(_state); + return; + } + if( (!allv&&!over)&&!somev ) + { + *info = -4; + ae_frame_leave(_state); + return; + } + + /* + * Set M to the number of columns required to store the selected + * eigenvectors, standardize the array SELECT if necessary, and + * test MM. + */ + if( somev ) + { + *m = 0; + pair = ae_false; + for(j=1; j<=n; j++) + { + if( pair ) + { + pair = ae_false; + vselect.ptr.p_bool[j] = ae_false; + } + else + { + if( jptr.pp_double[j+1][j],(double)(0)) ) + { + if( vselect.ptr.p_bool[j] ) + { + *m = *m+1; + } + } + else + { + pair = ae_true; + if( vselect.ptr.p_bool[j]||vselect.ptr.p_bool[j+1] ) + { + vselect.ptr.p_bool[j] = ae_true; + *m = *m+2; + } + } + } + else + { + if( vselect.ptr.p_bool[n] ) + { + *m = *m+1; + } + } + } + } + } + else + { + *m = n; + } + + /* + * Quick return if possible. + */ + if( n==0 ) + { + ae_frame_leave(_state); + return; + } + + /* + * Set the constants to control overflow. + */ + unfl = ae_minrealnumber; + ulp = ae_machineepsilon; + smlnum = unfl*((double)n/ulp); + bignum = ((double)1-ulp)/smlnum; + + /* + * Compute 1-norm of each column of strictly upper triangular + * part of T to control overflow in triangular solver. + */ + work.ptr.p_double[1] = (double)(0); + for(j=2; j<=n; j++) + { + work.ptr.p_double[j] = (double)(0); + for(i=1; i<=j-1; i++) + { + work.ptr.p_double[j] = work.ptr.p_double[j]+ae_fabs(t->ptr.pp_double[i][j], _state); + } + } + + /* + * Index IP is used to specify the real or complex eigenvalue: + * IP = 0, real eigenvalue, + * 1, first of conjugate complex pair: (wr,wi) + * -1, second of conjugate complex pair: (wr,wi) + */ + n2 = 2*n; + if( rightv ) + { + + /* + * Compute right eigenvectors. + */ + ip = 0; + iis = *m; + for(ki=n; ki>=1; ki--) + { + skipflag = ae_false; + if( ip==1 ) + { + skipflag = ae_true; + } + else + { + if( ki!=1 ) + { + if( ae_fp_neq(t->ptr.pp_double[ki][ki-1],(double)(0)) ) + { + ip = -1; + } + } + if( somev ) + { + if( ip==0 ) + { + if( !vselect.ptr.p_bool[ki] ) + { + skipflag = ae_true; + } + } + else + { + if( !vselect.ptr.p_bool[ki-1] ) + { + skipflag = ae_true; + } + } + } + } + if( !skipflag ) + { + + /* + * Compute the KI-th eigenvalue (WR,WI). + */ + wr = t->ptr.pp_double[ki][ki]; + wi = (double)(0); + if( ip!=0 ) + { + wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki-1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki-1][ki], _state), _state); + } + smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); + if( ip==0 ) + { + + /* + * Real right eigenvector + */ + work.ptr.p_double[ki+n] = (double)(1); + + /* + * Form right-hand side + */ + for(k=1; k<=ki-1; k++) + { + work.ptr.p_double[k+n] = -t->ptr.pp_double[k][ki]; + } + + /* + * Solve the upper quasi-triangular system: + * (T(1:KI-1,1:KI-1) - WR)*X = SCALE*WORK. + */ + jnxt = ki-1; + for(j=ki-1; j>=1; j--) + { + if( j>jnxt ) + { + continue; + } + j1 = j; + j2 = j; + jnxt = j-1; + if( j>1 ) + { + if( ae_fp_neq(t->ptr.pp_double[j][j-1],(double)(0)) ) + { + j1 = j-1; + jnxt = j-2; + } + } + if( j1==j2 ) + { + + /* + * 1-by-1 diagonal block + */ + temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + evd_internalhsevdlaln2(ae_false, 1, 1, smin, (double)(1), &temp11, 1.0, 1.0, &temp11b, wr, 0.0, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale X(1,1) to avoid overflow when updating + * the right-hand side. + */ + if( ae_fp_greater(xnorm,(double)(1)) ) + { + if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) + { + x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; + scl = scl/xnorm; + } + } + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + k1 = n+1; + k2 = n+ki; + ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + + /* + * Update right-hand side + */ + k1 = 1+n; + k2 = j-1+n; + k3 = j-1; + vt = -x.ptr.pp_double[1][1]; + ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); + } + else + { + + /* + * 2-by-2 diagonal block + */ + temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; + temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; + temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; + temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; + temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; + temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; + evd_internalhsevdlaln2(ae_false, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale X(1,1) and X(2,1) to avoid overflow when + * updating the right-hand side. + */ + if( ae_fp_greater(xnorm,(double)(1)) ) + { + beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); + if( ae_fp_greater(beta,bignum/xnorm) ) + { + x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; + x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]/xnorm; + scl = scl/xnorm; + } + } + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + k1 = 1+n; + k2 = ki+n; + ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); + } + work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; + + /* + * Update right-hand side + */ + k1 = 1+n; + k2 = j-2+n; + k3 = j-2; + k4 = j-1; + vt = -x.ptr.pp_double[1][1]; + ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][k4], t->stride, ae_v_len(k1,k2), vt); + vt = -x.ptr.pp_double[2][1]; + ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(k1,k2), vt); + } + } + + /* + * Copy the vector x or Q*x to VR and normalize. + */ + if( !over ) + { + k1 = 1+n; + k2 = ki+n; + ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[k1], 1, ae_v_len(1,ki)); + ii = columnidxabsmax(vr, 1, ki, iis, _state); + remax = (double)1/ae_fabs(vr->ptr.pp_double[ii][iis], _state); + ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); + for(k=ki+1; k<=n; k++) + { + vr->ptr.pp_double[k][iis] = (double)(0); + } + } + else + { + if( ki>1 ) + { + ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); + matrixvectormultiply(vr, 1, n, 1, ki-1, ae_false, &work, 1+n, ki-1+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); + ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + } + ii = columnidxabsmax(vr, 1, n, ki, _state); + remax = (double)1/ae_fabs(vr->ptr.pp_double[ii][ki], _state); + ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); + } + } + else + { + + /* + * Complex right eigenvector. + * + * Initial solve + * [ (T(KI-1,KI-1) T(KI-1,KI) ) - (WR + I* WI)]*X = 0. + * [ (T(KI,KI-1) T(KI,KI) ) ] + */ + if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki-1][ki], _state),ae_fabs(t->ptr.pp_double[ki][ki-1], _state)) ) + { + work.ptr.p_double[ki-1+n] = (double)(1); + work.ptr.p_double[ki+n2] = wi/t->ptr.pp_double[ki-1][ki]; + } + else + { + work.ptr.p_double[ki-1+n] = -wi/t->ptr.pp_double[ki][ki-1]; + work.ptr.p_double[ki+n2] = (double)(1); + } + work.ptr.p_double[ki+n] = (double)(0); + work.ptr.p_double[ki-1+n2] = (double)(0); + + /* + * Form right-hand side + */ + for(k=1; k<=ki-2; k++) + { + work.ptr.p_double[k+n] = -work.ptr.p_double[ki-1+n]*t->ptr.pp_double[k][ki-1]; + work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+n2]*t->ptr.pp_double[k][ki]; + } + + /* + * Solve upper quasi-triangular system: + * (T(1:KI-2,1:KI-2) - (WR+i*WI))*X = SCALE*(WORK+i*WORK2) + */ + jnxt = ki-2; + for(j=ki-2; j>=1; j--) + { + if( j>jnxt ) + { + continue; + } + j1 = j; + j2 = j; + jnxt = j-1; + if( j>1 ) + { + if( ae_fp_neq(t->ptr.pp_double[j][j-1],(double)(0)) ) + { + j1 = j-1; + jnxt = j-2; + } + } + if( j1==j2 ) + { + + /* + * 1-by-1 diagonal block + */ + temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; + evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale X(1,1) and X(1,2) to avoid overflow when + * updating the right-hand side. + */ + if( ae_fp_greater(xnorm,(double)(1)) ) + { + if( ae_fp_greater(work.ptr.p_double[j],bignum/xnorm) ) + { + x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]/xnorm; + x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]/xnorm; + scl = scl/xnorm; + } + } + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + k1 = 1+n; + k2 = ki+n; + ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); + k1 = 1+n2; + k2 = ki+n2; + ae_v_muld(&work.ptr.p_double[k1], 1, ae_v_len(k1,k2), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; + + /* + * Update the right-hand side + */ + k1 = 1+n; + k2 = j-1+n; + k3 = 1; + k4 = j-1; + vt = -x.ptr.pp_double[1][1]; + ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); + k1 = 1+n2; + k2 = j-1+n2; + k3 = 1; + k4 = j-1; + vt = -x.ptr.pp_double[1][2]; + ae_v_addd(&work.ptr.p_double[k1], 1, &t->ptr.pp_double[k3][j], t->stride, ae_v_len(k1,k2), vt); + } + else + { + + /* + * 2-by-2 diagonal block + */ + temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j-1][j-1]; + temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j-1][j]; + temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j][j-1]; + temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j][j]; + temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j-1+n]; + temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j-1+n+n]; + temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+n]; + temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+n+n]; + evd_internalhsevdlaln2(ae_false, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale X to avoid overflow when updating + * the right-hand side. + */ + if( ae_fp_greater(xnorm,(double)(1)) ) + { + beta = ae_maxreal(work.ptr.p_double[j-1], work.ptr.p_double[j], _state); + if( ae_fp_greater(beta,bignum/xnorm) ) + { + rec = (double)1/xnorm; + x.ptr.pp_double[1][1] = x.ptr.pp_double[1][1]*rec; + x.ptr.pp_double[1][2] = x.ptr.pp_double[1][2]*rec; + x.ptr.pp_double[2][1] = x.ptr.pp_double[2][1]*rec; + x.ptr.pp_double[2][2] = x.ptr.pp_double[2][2]*rec; + scl = scl*rec; + } + } + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + ae_v_muld(&work.ptr.p_double[1+n], 1, ae_v_len(1+n,ki+n), scl); + ae_v_muld(&work.ptr.p_double[1+n2], 1, ae_v_len(1+n2,ki+n2), scl); + } + work.ptr.p_double[j-1+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+n] = x.ptr.pp_double[2][1]; + work.ptr.p_double[j-1+n2] = x.ptr.pp_double[1][2]; + work.ptr.p_double[j+n2] = x.ptr.pp_double[2][2]; + + /* + * Update the right-hand side + */ + vt = -x.ptr.pp_double[1][1]; + ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n+1,n+j-2), vt); + vt = -x.ptr.pp_double[2][1]; + ae_v_addd(&work.ptr.p_double[n+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n+1,n+j-2), vt); + vt = -x.ptr.pp_double[1][2]; + ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j-1], t->stride, ae_v_len(n2+1,n2+j-2), vt); + vt = -x.ptr.pp_double[2][2]; + ae_v_addd(&work.ptr.p_double[n2+1], 1, &t->ptr.pp_double[1][j], t->stride, ae_v_len(n2+1,n2+j-2), vt); + } + } + + /* + * Copy the vector x or Q*x to VR and normalize. + */ + if( !over ) + { + ae_v_move(&vr->ptr.pp_double[1][iis-1], vr->stride, &work.ptr.p_double[n+1], 1, ae_v_len(1,ki)); + ae_v_move(&vr->ptr.pp_double[1][iis], vr->stride, &work.ptr.p_double[n2+1], 1, ae_v_len(1,ki)); + emax = (double)(0); + for(k=1; k<=ki; k++) + { + emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][iis-1], _state)+ae_fabs(vr->ptr.pp_double[k][iis], _state), _state); + } + remax = (double)1/emax; + ae_v_muld(&vr->ptr.pp_double[1][iis-1], vr->stride, ae_v_len(1,ki), remax); + ae_v_muld(&vr->ptr.pp_double[1][iis], vr->stride, ae_v_len(1,ki), remax); + for(k=ki+1; k<=n; k++) + { + vr->ptr.pp_double[k][iis-1] = (double)(0); + vr->ptr.pp_double[k][iis] = (double)(0); + } + } + else + { + if( ki>2 ) + { + ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n)); + matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n, ki-2+n, 1.0, &temp, 1, n, work.ptr.p_double[ki-1+n], _state); + ae_v_move(&vr->ptr.pp_double[1][ki-1], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + ae_v_move(&temp.ptr.p_double[1], 1, &vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n)); + matrixvectormultiply(vr, 1, n, 1, ki-2, ae_false, &work, 1+n2, ki-2+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+n2], _state); + ae_v_move(&vr->ptr.pp_double[1][ki], vr->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + } + else + { + vt = work.ptr.p_double[ki-1+n]; + ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), vt); + vt = work.ptr.p_double[ki+n2]; + ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), vt); + } + emax = (double)(0); + for(k=1; k<=n; k++) + { + emax = ae_maxreal(emax, ae_fabs(vr->ptr.pp_double[k][ki-1], _state)+ae_fabs(vr->ptr.pp_double[k][ki], _state), _state); + } + remax = (double)1/emax; + ae_v_muld(&vr->ptr.pp_double[1][ki-1], vr->stride, ae_v_len(1,n), remax); + ae_v_muld(&vr->ptr.pp_double[1][ki], vr->stride, ae_v_len(1,n), remax); + } + } + iis = iis-1; + if( ip!=0 ) + { + iis = iis-1; + } + } + if( ip==1 ) + { + ip = 0; + } + if( ip==-1 ) + { + ip = 1; + } + } + } + if( leftv ) + { + + /* + * Compute left eigenvectors. + */ + ip = 0; + iis = 1; + for(ki=1; ki<=n; ki++) + { + skipflag = ae_false; + if( ip==-1 ) + { + skipflag = ae_true; + } + else + { + if( ki!=n ) + { + if( ae_fp_neq(t->ptr.pp_double[ki+1][ki],(double)(0)) ) + { + ip = 1; + } + } + if( somev ) + { + if( !vselect.ptr.p_bool[ki] ) + { + skipflag = ae_true; + } + } + } + if( !skipflag ) + { + + /* + * Compute the KI-th eigenvalue (WR,WI). + */ + wr = t->ptr.pp_double[ki][ki]; + wi = (double)(0); + if( ip!=0 ) + { + wi = ae_sqrt(ae_fabs(t->ptr.pp_double[ki][ki+1], _state), _state)*ae_sqrt(ae_fabs(t->ptr.pp_double[ki+1][ki], _state), _state); + } + smin = ae_maxreal(ulp*(ae_fabs(wr, _state)+ae_fabs(wi, _state)), smlnum, _state); + if( ip==0 ) + { + + /* + * Real left eigenvector. + */ + work.ptr.p_double[ki+n] = (double)(1); + + /* + * Form right-hand side + */ + for(k=ki+1; k<=n; k++) + { + work.ptr.p_double[k+n] = -t->ptr.pp_double[ki][k]; + } + + /* + * Solve the quasi-triangular system: + * (T(KI+1:N,KI+1:N) - WR)'*X = SCALE*WORK + */ + vmax = (double)(1); + vcrit = bignum; + jnxt = ki+1; + for(j=ki+1; j<=n; j++) + { + if( jptr.pp_double[j+1][j],(double)(0)) ) + { + j2 = j+1; + jnxt = j+2; + } + } + if( j1==j2 ) + { + + /* + * 1-by-1 diagonal block + * + * Scale if necessary to avoid overflow when forming + * the right-hand side. + */ + if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) + { + rec = (double)1/vmax; + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); + vmax = (double)(1); + vcrit = bignum; + } + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); + work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; + + /* + * Solve (T(J,J)-WR)'*X = WORK + */ + temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp11b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + evd_internalhsevdlaln2(ae_false, 1, 1, smin, 1.0, &temp11, 1.0, 1.0, &temp11b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), vmax, _state); + vcrit = bignum/vmax; + } + else + { + + /* + * 2-by-2 diagonal block + * + * Scale if necessary to avoid overflow when forming + * the right-hand side. + */ + beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); + if( ae_fp_greater(beta,vcrit) ) + { + rec = (double)1/vmax; + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); + vmax = (double)(1); + vcrit = bignum; + } + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); + work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+1][j+1], t->stride, &work.ptr.p_double[ki+1+n], 1, ae_v_len(ki+1,j-1)); + work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; + + /* + * Solve + * [T(J,J)-WR T(J,J+1) ]'* X = SCALE*( WORK1 ) + * [T(J+1,J) T(J+1,J+1)-WR] ( WORK2 ) + */ + temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; + temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; + temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; + temp21b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + temp21b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; + evd_internalhsevdlaln2(ae_true, 2, 1, smin, 1.0, &temp22, 1.0, 1.0, &temp21b, wr, (double)(0), &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; + vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+1+n], _state), vmax, _state), _state); + vcrit = bignum/vmax; + } + } + + /* + * Copy the vector x or Q*x to VL and normalize. + */ + if( !over ) + { + ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); + ii = columnidxabsmax(vl, ki, n, iis, _state); + remax = (double)1/ae_fabs(vl->ptr.pp_double[ii][iis], _state); + ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); + for(k=1; k<=ki-1; k++) + { + vl->ptr.pp_double[k][iis] = (double)(0); + } + } + else + { + if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); + matrixvectormultiply(vl, 1, n, ki+1, n, ae_false, &work, ki+1+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); + ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + } + ii = columnidxabsmax(vl, 1, n, ki, _state); + remax = (double)1/ae_fabs(vl->ptr.pp_double[ii][ki], _state); + ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); + } + } + else + { + + /* + * Complex left eigenvector. + * + * Initial solve: + * ((T(KI,KI) T(KI,KI+1) )' - (WR - I* WI))*X = 0. + * ((T(KI+1,KI) T(KI+1,KI+1)) ) + */ + if( ae_fp_greater_eq(ae_fabs(t->ptr.pp_double[ki][ki+1], _state),ae_fabs(t->ptr.pp_double[ki+1][ki], _state)) ) + { + work.ptr.p_double[ki+n] = wi/t->ptr.pp_double[ki][ki+1]; + work.ptr.p_double[ki+1+n2] = (double)(1); + } + else + { + work.ptr.p_double[ki+n] = (double)(1); + work.ptr.p_double[ki+1+n2] = -wi/t->ptr.pp_double[ki+1][ki]; + } + work.ptr.p_double[ki+1+n] = (double)(0); + work.ptr.p_double[ki+n2] = (double)(0); + + /* + * Form right-hand side + */ + for(k=ki+2; k<=n; k++) + { + work.ptr.p_double[k+n] = -work.ptr.p_double[ki+n]*t->ptr.pp_double[ki][k]; + work.ptr.p_double[k+n2] = -work.ptr.p_double[ki+1+n2]*t->ptr.pp_double[ki+1][k]; + } + + /* + * Solve complex quasi-triangular system: + * ( T(KI+2,N:KI+2,N) - (WR-i*WI) )*X = WORK1+i*WORK2 + */ + vmax = (double)(1); + vcrit = bignum; + jnxt = ki+2; + for(j=ki+2; j<=n; j++) + { + if( jptr.pp_double[j+1][j],(double)(0)) ) + { + j2 = j+1; + jnxt = j+2; + } + } + if( j1==j2 ) + { + + /* + * 1-by-1 diagonal block + * + * Scale if necessary to avoid overflow when + * forming the right-hand side elements. + */ + if( ae_fp_greater(work.ptr.p_double[j],vcrit) ) + { + rec = (double)1/vmax; + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); + ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); + vmax = (double)(1); + vcrit = bignum; + } + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; + + /* + * Solve (T(J,J)-(WR-i*WI))*(X11+i*X12)= WK+I*WK2 + */ + temp11.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp12b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + temp12b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; + evd_internalhsevdlaln2(ae_false, 1, 2, smin, 1.0, &temp11, 1.0, 1.0, &temp12b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); + ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; + vmax = ae_maxreal(ae_fabs(work.ptr.p_double[j+n], _state), ae_maxreal(ae_fabs(work.ptr.p_double[j+n2], _state), vmax, _state), _state); + vcrit = bignum/vmax; + } + else + { + + /* + * 2-by-2 diagonal block + * + * Scale if necessary to avoid overflow when forming + * the right-hand side elements. + */ + beta = ae_maxreal(work.ptr.p_double[j], work.ptr.p_double[j+1], _state); + if( ae_fp_greater(beta,vcrit) ) + { + rec = (double)1/vmax; + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), rec); + ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), rec); + vmax = (double)(1); + vcrit = bignum; + } + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+n] = work.ptr.p_double[j+n]-vt; + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+n2] = work.ptr.p_double[j+n2]-vt; + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+1+n] = work.ptr.p_double[j+1+n]-vt; + vt = ae_v_dotproduct(&t->ptr.pp_double[ki+2][j+1], t->stride, &work.ptr.p_double[ki+2+n2], 1, ae_v_len(ki+2,j-1)); + work.ptr.p_double[j+1+n2] = work.ptr.p_double[j+1+n2]-vt; + + /* + * Solve 2-by-2 complex linear equation + * ([T(j,j) T(j,j+1) ]'-(wr-i*wi)*I)*X = SCALE*B + * ([T(j+1,j) T(j+1,j+1)] ) + */ + temp22.ptr.pp_double[1][1] = t->ptr.pp_double[j][j]; + temp22.ptr.pp_double[1][2] = t->ptr.pp_double[j][j+1]; + temp22.ptr.pp_double[2][1] = t->ptr.pp_double[j+1][j]; + temp22.ptr.pp_double[2][2] = t->ptr.pp_double[j+1][j+1]; + temp22b.ptr.pp_double[1][1] = work.ptr.p_double[j+n]; + temp22b.ptr.pp_double[1][2] = work.ptr.p_double[j+n+n]; + temp22b.ptr.pp_double[2][1] = work.ptr.p_double[j+1+n]; + temp22b.ptr.pp_double[2][2] = work.ptr.p_double[j+1+n+n]; + evd_internalhsevdlaln2(ae_true, 2, 2, smin, 1.0, &temp22, 1.0, 1.0, &temp22b, wr, -wi, &rswap4, &zswap4, &ipivot44, &civ4, &crv4, &x, &scl, &xnorm, &ierr, _state); + + /* + * Scale if necessary + */ + if( ae_fp_neq(scl,(double)(1)) ) + { + ae_v_muld(&work.ptr.p_double[ki+n], 1, ae_v_len(ki+n,n+n), scl); + ae_v_muld(&work.ptr.p_double[ki+n2], 1, ae_v_len(ki+n2,n+n2), scl); + } + work.ptr.p_double[j+n] = x.ptr.pp_double[1][1]; + work.ptr.p_double[j+n2] = x.ptr.pp_double[1][2]; + work.ptr.p_double[j+1+n] = x.ptr.pp_double[2][1]; + work.ptr.p_double[j+1+n2] = x.ptr.pp_double[2][2]; + vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][1], _state), vmax, _state); + vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[1][2], _state), vmax, _state); + vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][1], _state), vmax, _state); + vmax = ae_maxreal(ae_fabs(x.ptr.pp_double[2][2], _state), vmax, _state); + vcrit = bignum/vmax; + } + } + + /* + * Copy the vector x or Q*x to VL and normalize. + */ + if( !over ) + { + ae_v_move(&vl->ptr.pp_double[ki][iis], vl->stride, &work.ptr.p_double[ki+n], 1, ae_v_len(ki,n)); + ae_v_move(&vl->ptr.pp_double[ki][iis+1], vl->stride, &work.ptr.p_double[ki+n2], 1, ae_v_len(ki,n)); + emax = (double)(0); + for(k=ki; k<=n; k++) + { + emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][iis], _state)+ae_fabs(vl->ptr.pp_double[k][iis+1], _state), _state); + } + remax = (double)1/emax; + ae_v_muld(&vl->ptr.pp_double[ki][iis], vl->stride, ae_v_len(ki,n), remax); + ae_v_muld(&vl->ptr.pp_double[ki][iis+1], vl->stride, ae_v_len(ki,n), remax); + for(k=1; k<=ki-1; k++) + { + vl->ptr.pp_double[k][iis] = (double)(0); + vl->ptr.pp_double[k][iis+1] = (double)(0); + } + } + else + { + if( kiptr.pp_double[1][ki], vl->stride, ae_v_len(1,n)); + matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n, n+n, 1.0, &temp, 1, n, work.ptr.p_double[ki+n], _state); + ae_v_move(&vl->ptr.pp_double[1][ki], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + ae_v_move(&temp.ptr.p_double[1], 1, &vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n)); + matrixvectormultiply(vl, 1, n, ki+2, n, ae_false, &work, ki+2+n2, n+n2, 1.0, &temp, 1, n, work.ptr.p_double[ki+1+n2], _state); + ae_v_move(&vl->ptr.pp_double[1][ki+1], vl->stride, &temp.ptr.p_double[1], 1, ae_v_len(1,n)); + } + else + { + vt = work.ptr.p_double[ki+n]; + ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), vt); + vt = work.ptr.p_double[ki+1+n2]; + ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), vt); + } + emax = (double)(0); + for(k=1; k<=n; k++) + { + emax = ae_maxreal(emax, ae_fabs(vl->ptr.pp_double[k][ki], _state)+ae_fabs(vl->ptr.pp_double[k][ki+1], _state), _state); + } + remax = (double)1/emax; + ae_v_muld(&vl->ptr.pp_double[1][ki], vl->stride, ae_v_len(1,n), remax); + ae_v_muld(&vl->ptr.pp_double[1][ki+1], vl->stride, ae_v_len(1,n), remax); + } + } + iis = iis+1; + if( ip!=0 ) + { + iis = iis+1; + } + } + if( ip==-1 ) + { + ip = 0; + } + if( ip==1 ) + { + ip = -1; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +DLALN2 solves a system of the form (ca A - w D ) X = s B +or (ca A' - w D) X = s B with possible scaling ("s") and +perturbation of A. (A' means A-transpose.) + +A is an NA x NA real matrix, ca is a real scalar, D is an NA x NA +real diagonal matrix, w is a real or complex value, and X and B are +NA x 1 matrices -- real if w is real, complex if w is complex. NA +may be 1 or 2. + +If w is complex, X and B are represented as NA x 2 matrices, +the first column of each being the real part and the second +being the imaginary part. + +"s" is a scaling factor (.LE. 1), computed by DLALN2, which is +so chosen that X can be computed without overflow. X is further +scaled if necessary to assure that norm(ca A - w D)*norm(X) is less +than overflow. + +If both singular values of (ca A - w D) are less than SMIN, +SMIN*identity will be used instead of (ca A - w D). If only one +singular value is less than SMIN, one element of (ca A - w D) will be +perturbed enough to make the smallest singular value roughly SMIN. +If both singular values are at least SMIN, (ca A - w D) will not be +perturbed. In any case, the perturbation will be at most some small +multiple of max( SMIN, ulp*norm(ca A - w D) ). The singular values +are computed by infinity-norm approximations, and thus will only be +correct to a factor of 2 or so. + +Note: all input quantities are assumed to be smaller than overflow +by a reasonable factor. (See BIGNUM.) + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +static void evd_internalhsevdlaln2(ae_bool ltrans, + ae_int_t na, + ae_int_t nw, + double smin, + double ca, + /* Real */ const ae_matrix* a, + double d1, + double d2, + /* Real */ const ae_matrix* b, + double wr, + double wi, + /* Boolean */ ae_vector* rswap4, + /* Boolean */ ae_vector* zswap4, + /* Integer */ ae_matrix* ipivot44, + /* Real */ ae_vector* civ4, + /* Real */ ae_vector* crv4, + /* Real */ ae_matrix* x, + double* scl, + double* xnorm, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t icmax; + ae_int_t j; + double bbnd; + double bi1; + double bi2; + double bignum; + double bnorm; + double br1; + double br2; + double ci21; + double ci22; + double cmax; + double cnorm; + double cr21; + double cr22; + double csi; + double csr; + double li21; + double lr21; + double smini; + double smlnum; + double temp; + double u22abs; + double ui11; + double ui11r; + double ui12; + double ui12s; + double ui22; + double ur11; + double ur11r; + double ur12; + double ur12s; + double ur22; + double xi1; + double xi2; + double xr1; + double xr2; + double tmp1; + double tmp2; + + *scl = 0.0; + *xnorm = 0.0; + *info = 0; + + zswap4->ptr.p_bool[1] = ae_false; + zswap4->ptr.p_bool[2] = ae_false; + zswap4->ptr.p_bool[3] = ae_true; + zswap4->ptr.p_bool[4] = ae_true; + rswap4->ptr.p_bool[1] = ae_false; + rswap4->ptr.p_bool[2] = ae_true; + rswap4->ptr.p_bool[3] = ae_false; + rswap4->ptr.p_bool[4] = ae_true; + ipivot44->ptr.pp_int[1][1] = 1; + ipivot44->ptr.pp_int[2][1] = 2; + ipivot44->ptr.pp_int[3][1] = 3; + ipivot44->ptr.pp_int[4][1] = 4; + ipivot44->ptr.pp_int[1][2] = 2; + ipivot44->ptr.pp_int[2][2] = 1; + ipivot44->ptr.pp_int[3][2] = 4; + ipivot44->ptr.pp_int[4][2] = 3; + ipivot44->ptr.pp_int[1][3] = 3; + ipivot44->ptr.pp_int[2][3] = 4; + ipivot44->ptr.pp_int[3][3] = 1; + ipivot44->ptr.pp_int[4][3] = 2; + ipivot44->ptr.pp_int[1][4] = 4; + ipivot44->ptr.pp_int[2][4] = 3; + ipivot44->ptr.pp_int[3][4] = 2; + ipivot44->ptr.pp_int[4][4] = 1; + smlnum = (double)2*ae_minrealnumber; + bignum = (double)1/smlnum; + smini = ae_maxreal(smin, smlnum, _state); + + /* + * Don't check for input errors + */ + *info = 0; + + /* + * Standard Initializations + */ + *scl = (double)(1); + if( na==1 ) + { + + /* + * 1 x 1 (i.e., scalar) system C X = B + */ + if( nw==1 ) + { + + /* + * Real 1x1 system. + * + * C = ca A - w D + */ + csr = ca*a->ptr.pp_double[1][1]-wr*d1; + cnorm = ae_fabs(csr, _state); + + /* + * If | C | < SMINI, use C = SMINI + */ + if( ae_fp_less(cnorm,smini) ) + { + csr = smini; + cnorm = smini; + *info = 1; + } + + /* + * Check scaling for X = B / C + */ + bnorm = ae_fabs(b->ptr.pp_double[1][1], _state); + if( ae_fp_less(cnorm,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) + { + if( ae_fp_greater(bnorm,bignum*cnorm) ) + { + *scl = (double)1/bnorm; + } + } + + /* + * Compute X + */ + x->ptr.pp_double[1][1] = b->ptr.pp_double[1][1]*(*scl)/csr; + *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state); + } + else + { + + /* + * Complex 1x1 system (w is complex) + * + * C = ca A - w D + */ + csr = ca*a->ptr.pp_double[1][1]-wr*d1; + csi = -wi*d1; + cnorm = ae_fabs(csr, _state)+ae_fabs(csi, _state); + + /* + * If | C | < SMINI, use C = SMINI + */ + if( ae_fp_less(cnorm,smini) ) + { + csr = smini; + csi = (double)(0); + cnorm = smini; + *info = 1; + } + + /* + * Check scaling for X = B / C + */ + bnorm = ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state); + if( ae_fp_less(cnorm,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) + { + if( ae_fp_greater(bnorm,bignum*cnorm) ) + { + *scl = (double)1/bnorm; + } + } + + /* + * Compute X + */ + evd_internalhsevdladiv(*scl*b->ptr.pp_double[1][1], *scl*b->ptr.pp_double[1][2], csr, csi, &tmp1, &tmp2, _state); + x->ptr.pp_double[1][1] = tmp1; + x->ptr.pp_double[1][2] = tmp2; + *xnorm = ae_fabs(x->ptr.pp_double[1][1], _state)+ae_fabs(x->ptr.pp_double[1][2], _state); + } + } + else + { + + /* + * 2x2 System + * + * Compute the real part of C = ca A - w D (or ca A' - w D ) + */ + crv4->ptr.p_double[1+0] = ca*a->ptr.pp_double[1][1]-wr*d1; + crv4->ptr.p_double[2+2] = ca*a->ptr.pp_double[2][2]-wr*d2; + if( ltrans ) + { + crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[2][1]; + crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[1][2]; + } + else + { + crv4->ptr.p_double[2+0] = ca*a->ptr.pp_double[2][1]; + crv4->ptr.p_double[1+2] = ca*a->ptr.pp_double[1][2]; + } + if( nw==1 ) + { + + /* + * Real 2x2 system (w is real) + * + * Find the largest element in C + */ + cmax = (double)(0); + icmax = 0; + for(j=1; j<=4; j++) + { + if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state),cmax) ) + { + cmax = ae_fabs(crv4->ptr.p_double[j], _state); + icmax = j; + } + } + + /* + * If norm(C) < SMINI, use SMINI*identity. + */ + if( ae_fp_less(cmax,smini) ) + { + bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state), ae_fabs(b->ptr.pp_double[2][1], _state), _state); + if( ae_fp_less(smini,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) + { + if( ae_fp_greater(bnorm,bignum*smini) ) + { + *scl = (double)1/bnorm; + } + } + temp = *scl/smini; + x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; + x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; + *xnorm = temp*bnorm; + *info = 1; + return; + } + + /* + * Gaussian elimination with complete pivoting. + */ + ur11 = crv4->ptr.p_double[icmax]; + cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; + ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; + cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; + ur11r = (double)1/ur11; + lr21 = ur11r*cr21; + ur22 = cr22-ur12*lr21; + + /* + * If smaller pivot < SMINI, use SMINI + */ + if( ae_fp_less(ae_fabs(ur22, _state),smini) ) + { + ur22 = smini; + *info = 1; + } + if( rswap4->ptr.p_bool[icmax] ) + { + br1 = b->ptr.pp_double[2][1]; + br2 = b->ptr.pp_double[1][1]; + } + else + { + br1 = b->ptr.pp_double[1][1]; + br2 = b->ptr.pp_double[2][1]; + } + br2 = br2-lr21*br1; + bbnd = ae_maxreal(ae_fabs(br1*(ur22*ur11r), _state), ae_fabs(br2, _state), _state); + if( ae_fp_greater(bbnd,(double)(1))&&ae_fp_less(ae_fabs(ur22, _state),(double)(1)) ) + { + if( ae_fp_greater_eq(bbnd,bignum*ae_fabs(ur22, _state)) ) + { + *scl = (double)1/bbnd; + } + } + xr2 = br2*(*scl)/ur22; + xr1 = *scl*br1*ur11r-xr2*(ur11r*ur12); + if( zswap4->ptr.p_bool[icmax] ) + { + x->ptr.pp_double[1][1] = xr2; + x->ptr.pp_double[2][1] = xr1; + } + else + { + x->ptr.pp_double[1][1] = xr1; + x->ptr.pp_double[2][1] = xr2; + } + *xnorm = ae_maxreal(ae_fabs(xr1, _state), ae_fabs(xr2, _state), _state); + + /* + * Further scaling if norm(A) norm(X) > overflow + */ + if( ae_fp_greater(*xnorm,(double)(1))&&ae_fp_greater(cmax,(double)(1)) ) + { + if( ae_fp_greater(*xnorm,bignum/cmax) ) + { + temp = cmax/bignum; + x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; + x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; + *xnorm = temp*(*xnorm); + *scl = temp*(*scl); + } + } + } + else + { + + /* + * Complex 2x2 system (w is complex) + * + * Find the largest element in C + */ + civ4->ptr.p_double[1+0] = -wi*d1; + civ4->ptr.p_double[2+0] = (double)(0); + civ4->ptr.p_double[1+2] = (double)(0); + civ4->ptr.p_double[2+2] = -wi*d2; + cmax = (double)(0); + icmax = 0; + for(j=1; j<=4; j++) + { + if( ae_fp_greater(ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state),cmax) ) + { + cmax = ae_fabs(crv4->ptr.p_double[j], _state)+ae_fabs(civ4->ptr.p_double[j], _state); + icmax = j; + } + } + + /* + * If norm(C) < SMINI, use SMINI*identity. + */ + if( ae_fp_less(cmax,smini) ) + { + bnorm = ae_maxreal(ae_fabs(b->ptr.pp_double[1][1], _state)+ae_fabs(b->ptr.pp_double[1][2], _state), ae_fabs(b->ptr.pp_double[2][1], _state)+ae_fabs(b->ptr.pp_double[2][2], _state), _state); + if( ae_fp_less(smini,(double)(1))&&ae_fp_greater(bnorm,(double)(1)) ) + { + if( ae_fp_greater(bnorm,bignum*smini) ) + { + *scl = (double)1/bnorm; + } + } + temp = *scl/smini; + x->ptr.pp_double[1][1] = temp*b->ptr.pp_double[1][1]; + x->ptr.pp_double[2][1] = temp*b->ptr.pp_double[2][1]; + x->ptr.pp_double[1][2] = temp*b->ptr.pp_double[1][2]; + x->ptr.pp_double[2][2] = temp*b->ptr.pp_double[2][2]; + *xnorm = temp*bnorm; + *info = 1; + return; + } + + /* + * Gaussian elimination with complete pivoting. + */ + ur11 = crv4->ptr.p_double[icmax]; + ui11 = civ4->ptr.p_double[icmax]; + cr21 = crv4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; + ci21 = civ4->ptr.p_double[ipivot44->ptr.pp_int[2][icmax]]; + ur12 = crv4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; + ui12 = civ4->ptr.p_double[ipivot44->ptr.pp_int[3][icmax]]; + cr22 = crv4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; + ci22 = civ4->ptr.p_double[ipivot44->ptr.pp_int[4][icmax]]; + if( icmax==1||icmax==4 ) + { + + /* + * Code when off-diagonals of pivoted C are real + */ + if( ae_fp_greater(ae_fabs(ur11, _state),ae_fabs(ui11, _state)) ) + { + temp = ui11/ur11; + ur11r = (double)1/(ur11*((double)1+ae_sqr(temp, _state))); + ui11r = -temp*ur11r; + } + else + { + temp = ur11/ui11; + ui11r = -(double)1/(ui11*((double)1+ae_sqr(temp, _state))); + ur11r = -temp*ui11r; + } + lr21 = cr21*ur11r; + li21 = cr21*ui11r; + ur12s = ur12*ur11r; + ui12s = ur12*ui11r; + ur22 = cr22-ur12*lr21; + ui22 = ci22-ur12*li21; + } + else + { + + /* + * Code when diagonals of pivoted C are real + */ + ur11r = (double)1/ur11; + ui11r = (double)(0); + lr21 = cr21*ur11r; + li21 = ci21*ur11r; + ur12s = ur12*ur11r; + ui12s = ui12*ur11r; + ur22 = cr22-ur12*lr21+ui12*li21; + ui22 = -ur12*li21-ui12*lr21; + } + u22abs = ae_fabs(ur22, _state)+ae_fabs(ui22, _state); + + /* + * If smaller pivot < SMINI, use SMINI + */ + if( ae_fp_less(u22abs,smini) ) + { + ur22 = smini; + ui22 = (double)(0); + *info = 1; + } + if( rswap4->ptr.p_bool[icmax] ) + { + br2 = b->ptr.pp_double[1][1]; + br1 = b->ptr.pp_double[2][1]; + bi2 = b->ptr.pp_double[1][2]; + bi1 = b->ptr.pp_double[2][2]; + } + else + { + br1 = b->ptr.pp_double[1][1]; + br2 = b->ptr.pp_double[2][1]; + bi1 = b->ptr.pp_double[1][2]; + bi2 = b->ptr.pp_double[2][2]; + } + br2 = br2-lr21*br1+li21*bi1; + bi2 = bi2-li21*br1-lr21*bi1; + bbnd = ae_maxreal((ae_fabs(br1, _state)+ae_fabs(bi1, _state))*(u22abs*(ae_fabs(ur11r, _state)+ae_fabs(ui11r, _state))), ae_fabs(br2, _state)+ae_fabs(bi2, _state), _state); + if( ae_fp_greater(bbnd,(double)(1))&&ae_fp_less(u22abs,(double)(1)) ) + { + if( ae_fp_greater_eq(bbnd,bignum*u22abs) ) + { + *scl = (double)1/bbnd; + br1 = *scl*br1; + bi1 = *scl*bi1; + br2 = *scl*br2; + bi2 = *scl*bi2; + } + } + evd_internalhsevdladiv(br2, bi2, ur22, ui22, &xr2, &xi2, _state); + xr1 = ur11r*br1-ui11r*bi1-ur12s*xr2+ui12s*xi2; + xi1 = ui11r*br1+ur11r*bi1-ui12s*xr2-ur12s*xi2; + if( zswap4->ptr.p_bool[icmax] ) + { + x->ptr.pp_double[1][1] = xr2; + x->ptr.pp_double[2][1] = xr1; + x->ptr.pp_double[1][2] = xi2; + x->ptr.pp_double[2][2] = xi1; + } + else + { + x->ptr.pp_double[1][1] = xr1; + x->ptr.pp_double[2][1] = xr2; + x->ptr.pp_double[1][2] = xi1; + x->ptr.pp_double[2][2] = xi2; + } + *xnorm = ae_maxreal(ae_fabs(xr1, _state)+ae_fabs(xi1, _state), ae_fabs(xr2, _state)+ae_fabs(xi2, _state), _state); + + /* + * Further scaling if norm(A) norm(X) > overflow + */ + if( ae_fp_greater(*xnorm,(double)(1))&&ae_fp_greater(cmax,(double)(1)) ) + { + if( ae_fp_greater(*xnorm,bignum/cmax) ) + { + temp = cmax/bignum; + x->ptr.pp_double[1][1] = temp*x->ptr.pp_double[1][1]; + x->ptr.pp_double[2][1] = temp*x->ptr.pp_double[2][1]; + x->ptr.pp_double[1][2] = temp*x->ptr.pp_double[1][2]; + x->ptr.pp_double[2][2] = temp*x->ptr.pp_double[2][2]; + *xnorm = temp*(*xnorm); + *scl = temp*(*scl); + } + } + } + } +} + + +/************************************************************************* +performs complex division in real arithmetic + + a + i*b + p + i*q = --------- + c + i*d + +The algorithm is due to Robert L. Smith and can be found +in D. Knuth, The art of Computer Programming, Vol.2, p.195 + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +static void evd_internalhsevdladiv(double a, + double b, + double c, + double d, + double* p, + double* q, + ae_state *_state) +{ + double e; + double f; + + *p = 0.0; + *q = 0.0; + + if( ae_fp_less(ae_fabs(d, _state),ae_fabs(c, _state)) ) + { + e = d/c; + f = c+d*e; + *p = (a+b*e)/f; + *q = (b-a*e)/f; + } + else + { + e = c/d; + f = d+c*e; + *p = (b+a*e)/f; + *q = (-a+b*e)/f; + } +} + + +void _eigsubspacestate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + eigsubspacestate *p = (eigsubspacestate*)_p; + ae_touch_ptr((void*)p); + _hqrndstate_init(&p->rs, _state, make_automatic); + ae_vector_init(&p->tau, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q0, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->qcur, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->qnew, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->znew, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->r, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rz, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tz, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummy, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmprow, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wprev, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrank, 0, DT_REAL, _state, make_automatic); + _apbuffers_init(&p->buf, _state, make_automatic); + ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ax, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _eigsubspacestate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + eigsubspacestate *dst = (eigsubspacestate*)_dst; + const eigsubspacestate *src = (const eigsubspacestate*)_src; + dst->n = src->n; + dst->k = src->k; + dst->nwork = src->nwork; + dst->maxits = src->maxits; + dst->eps = src->eps; + dst->eigenvectorsneeded = src->eigenvectorsneeded; + dst->solvermode = src->solvermode; + dst->usewarmstart = src->usewarmstart; + dst->firstcall = src->firstcall; + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + dst->running = src->running; + ae_vector_init_copy(&dst->tau, &src->tau, _state, make_automatic); + ae_matrix_init_copy(&dst->q0, &src->q0, _state, make_automatic); + ae_matrix_init_copy(&dst->qcur, &src->qcur, _state, make_automatic); + ae_matrix_init_copy(&dst->qnew, &src->qnew, _state, make_automatic); + ae_matrix_init_copy(&dst->znew, &src->znew, _state, make_automatic); + ae_matrix_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_matrix_init_copy(&dst->rz, &src->rz, _state, make_automatic); + ae_matrix_init_copy(&dst->tz, &src->tz, _state, make_automatic); + ae_matrix_init_copy(&dst->rq, &src->rq, _state, make_automatic); + ae_matrix_init_copy(&dst->dummy, &src->dummy, _state, make_automatic); + ae_vector_init_copy(&dst->rw, &src->rw, _state, make_automatic); + ae_vector_init_copy(&dst->tw, &src->tw, _state, make_automatic); + ae_vector_init_copy(&dst->tmprow, &src->tmprow, _state, make_automatic); + ae_vector_init_copy(&dst->wcur, &src->wcur, _state, make_automatic); + ae_vector_init_copy(&dst->wprev, &src->wprev, _state, make_automatic); + ae_vector_init_copy(&dst->wrank, &src->wrank, _state, make_automatic); + _apbuffers_init_copy(&dst->buf, &src->buf, _state, make_automatic); + ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_matrix_init_copy(&dst->ax, &src->ax, _state, make_automatic); + dst->requesttype = src->requesttype; + dst->requestsize = src->requestsize; + dst->repiterationscount = src->repiterationscount; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _eigsubspacestate_clear(void* _p) +{ + eigsubspacestate *p = (eigsubspacestate*)_p; + ae_touch_ptr((void*)p); + _hqrndstate_clear(&p->rs); + ae_vector_clear(&p->tau); + ae_matrix_clear(&p->q0); + ae_matrix_clear(&p->qcur); + ae_matrix_clear(&p->qnew); + ae_matrix_clear(&p->znew); + ae_matrix_clear(&p->r); + ae_matrix_clear(&p->rz); + ae_matrix_clear(&p->tz); + ae_matrix_clear(&p->rq); + ae_matrix_clear(&p->dummy); + ae_vector_clear(&p->rw); + ae_vector_clear(&p->tw); + ae_vector_clear(&p->tmprow); + ae_vector_clear(&p->wcur); + ae_vector_clear(&p->wprev); + ae_vector_clear(&p->wrank); + _apbuffers_clear(&p->buf); + ae_matrix_clear(&p->x); + ae_matrix_clear(&p->ax); + _rcommstate_clear(&p->rstate); +} + + +void _eigsubspacestate_destroy(void* _p) +{ + eigsubspacestate *p = (eigsubspacestate*)_p; + ae_touch_ptr((void*)p); + _hqrndstate_destroy(&p->rs); + ae_vector_destroy(&p->tau); + ae_matrix_destroy(&p->q0); + ae_matrix_destroy(&p->qcur); + ae_matrix_destroy(&p->qnew); + ae_matrix_destroy(&p->znew); + ae_matrix_destroy(&p->r); + ae_matrix_destroy(&p->rz); + ae_matrix_destroy(&p->tz); + ae_matrix_destroy(&p->rq); + ae_matrix_destroy(&p->dummy); + ae_vector_destroy(&p->rw); + ae_vector_destroy(&p->tw); + ae_vector_destroy(&p->tmprow); + ae_vector_destroy(&p->wcur); + ae_vector_destroy(&p->wprev); + ae_vector_destroy(&p->wrank); + _apbuffers_destroy(&p->buf); + ae_matrix_destroy(&p->x); + ae_matrix_destroy(&p->ax); + _rcommstate_destroy(&p->rstate); +} + + +void _eigsubspacereport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + eigsubspacereport *p = (eigsubspacereport*)_p; + ae_touch_ptr((void*)p); +} + + +void _eigsubspacereport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + eigsubspacereport *dst = (eigsubspacereport*)_dst; + const eigsubspacereport *src = (const eigsubspacereport*)_src; + dst->iterationscount = src->iterationscount; +} + + +void _eigsubspacereport_clear(void* _p) +{ + eigsubspacereport *p = (eigsubspacereport*)_p; + ae_touch_ptr((void*)p); +} + + +void _eigsubspacereport_destroy(void* _p) +{ + eigsubspacereport *p = (eigsubspacereport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Recurrent complex LU subroutine. +Never call it directly. + + -- ALGLIB routine -- + 04.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixluprec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t m1; + ae_int_t m2; + + + if( ae_minint(m, n, _state)<=ablascomplexblocksize(a, _state) ) + { + dlu_cmatrixlup2(a, offs, m, n, pivots, tmp, _state); + return; + } + if( m>n ) + { + cmatrixluprec(a, offs, n, n, pivots, tmp, _state); + for(i=0; i<=n-1; i++) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n][offs+i], a->stride, "N", ae_v_len(0,m-n-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+n][offs+i], a->stride, &a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+n,offs+m-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n,offs+m-1)); + } + cmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); + return; + } + ablascomplexsplitlength(a, m, &m1, &m2, _state); + cmatrixluprec(a, offs, m1, n, pivots, tmp, _state); + if( m2>0 ) + { + for(i=0; i<=m1-1; i++) + { + if( offs+i!=pivots->ptr.p_int[offs+i] ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+m1][offs+i], a->stride, "N", ae_v_len(0,m2-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+m1][offs+i], a->stride, &a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, "N", ae_v_len(offs+m1,offs+m-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m1,offs+m-1)); + } + } + cmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); + cmatrixgemm(m-m1, n-m1, m1, ae_complex_from_d(-1.0), a, offs+m1, offs, 0, a, offs, offs+m1, 0, ae_complex_from_d(1.0), a, offs+m1, offs+m1, _state); + cmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); + for(i=0; i<=m2-1; i++) + { + if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+m1+i], a->stride, "N", ae_v_len(0,m1-1)); + ae_v_cmove(&a->ptr.pp_complex[offs][offs+m1+i], a->stride, &a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, "N", ae_v_len(offs,offs+m1-1)); + ae_v_cmove(&a->ptr.pp_complex[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m1-1)); + } + } + } +} + + +/************************************************************************* +Recurrent real LU subroutine. +Never call it directly. + + -- ALGLIB routine -- + 04.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixluprec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t m1; + ae_int_t m2; + + + if( ae_minint(m, n, _state)<=ablasblocksize(a, _state) ) + { + dlu_rmatrixlup2(a, offs, m, n, pivots, tmp, _state); + return; + } + if( m>n ) + { + rmatrixluprec(a, offs, n, n, pivots, tmp, _state); + for(i=0; i<=n-1; i++) + { + if( offs+i!=pivots->ptr.p_int[offs+i] ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n][offs+i], a->stride, ae_v_len(0,m-n-1)); + ae_v_move(&a->ptr.pp_double[offs+n][offs+i], a->stride, &a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+n,offs+m-1)); + ae_v_move(&a->ptr.pp_double[offs+n][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n,offs+m-1)); + } + } + rmatrixrighttrsm(m-n, n, a, offs, offs, ae_true, ae_true, 0, a, offs+n, offs, _state); + return; + } + ablassplitlength(a, m, &m1, &m2, _state); + rmatrixluprec(a, offs, m1, n, pivots, tmp, _state); + if( m2>0 ) + { + for(i=0; i<=m1-1; i++) + { + if( offs+i!=pivots->ptr.p_int[offs+i] ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+m1][offs+i], a->stride, ae_v_len(0,m2-1)); + ae_v_move(&a->ptr.pp_double[offs+m1][offs+i], a->stride, &a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, ae_v_len(offs+m1,offs+m-1)); + ae_v_move(&a->ptr.pp_double[offs+m1][pivots->ptr.p_int[offs+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m1,offs+m-1)); + } + } + rmatrixrighttrsm(m2, m1, a, offs, offs, ae_true, ae_true, 0, a, offs+m1, offs, _state); + rmatrixgemm(m-m1, n-m1, m1, -1.0, a, offs+m1, offs, 0, a, offs, offs+m1, 0, 1.0, a, offs+m1, offs+m1, _state); + rmatrixluprec(a, offs+m1, m-m1, n-m1, pivots, tmp, _state); + for(i=0; i<=m2-1; i++) + { + if( offs+m1+i!=pivots->ptr.p_int[offs+m1+i] ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+m1+i], a->stride, ae_v_len(0,m1-1)); + ae_v_move(&a->ptr.pp_double[offs][offs+m1+i], a->stride, &a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, ae_v_len(offs,offs+m1-1)); + ae_v_move(&a->ptr.pp_double[offs][pivots->ptr.p_int[offs+m1+i]], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m1-1)); + } + } + } +} + + +/************************************************************************* +Recurrent complex LU subroutine. +Never call it directly. + + -- ALGLIB routine -- + 04.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixplurec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + if( n<=tsa ) + { + dlu_cmatrixplu2(a, offs, m, n, pivots, tmp, _state); + return; + } + if( n>m ) + { + cmatrixplurec(a, offs, m, m, pivots, tmp, _state); + for(i=0; i<=m-1; i++) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+m], 1, "N", ae_v_len(0,n-m-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+m], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, "N", ae_v_len(offs+m,offs+n-1)); + ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+m,offs+n-1)); + } + cmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); + return; + } + if( n>tsb ) + { + n1 = tsb; + n2 = n-n1; + } + else + { + tiledsplit(n, tsa, &n1, &n2, _state); + } + cmatrixplurec(a, offs, m, n1, pivots, tmp, _state); + if( n2>0 ) + { + for(i=0; i<=n1-1; i++) + { + if( offs+i!=pivots->ptr.p_int[offs+i] ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs+n1], 1, "N", ae_v_len(0,n2-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+i][offs+n1], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, "N", ae_v_len(offs+n1,offs+n-1)); + ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs+n1,offs+n-1)); + } + } + cmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); + cmatrixgemm(m-n1, n-n1, n1, ae_complex_from_d(-1.0), a, offs+n1, offs, 0, a, offs, offs+n1, 0, ae_complex_from_d(1.0), a, offs+n1, offs+n1, _state); + cmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); + for(i=0; i<=n2-1; i++) + { + if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+n1+i][offs], 1, "N", ae_v_len(0,n1-1)); + ae_v_cmove(&a->ptr.pp_complex[offs+n1+i][offs], 1, &a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, "N", ae_v_len(offs,offs+n1-1)); + ae_v_cmove(&a->ptr.pp_complex[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+n1-1)); + } + } + } +} + + +/************************************************************************* +Recurrent real LU subroutine. +Never call it directly. + + -- ALGLIB routine -- + 04.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixplurec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + if( n<=tsb ) + { + if( rmatrixplupbl(a, offs, m, n, pivots, _state) ) + { + return; + } + } + if( n<=tsa ) + { + dlu_rmatrixplu2(a, offs, m, n, pivots, tmp, _state); + return; + } + if( n>m ) + { + rmatrixplurec(a, offs, m, m, pivots, tmp, _state); + for(i=0; i<=m-1; i++) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+m], 1, ae_v_len(0,n-m-1)); + ae_v_move(&a->ptr.pp_double[offs+i][offs+m], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, ae_v_len(offs+m,offs+n-1)); + ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+m], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+m,offs+n-1)); + } + rmatrixlefttrsm(m, n-m, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+m, _state); + return; + } + if( n>tsb ) + { + n1 = tsb; + n2 = n-n1; + } + else + { + tiledsplit(n, tsa, &n1, &n2, _state); + } + rmatrixplurec(a, offs, m, n1, pivots, tmp, _state); + if( n2>0 ) + { + for(i=0; i<=n1-1; i++) + { + if( offs+i!=pivots->ptr.p_int[offs+i] ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(0,n2-1)); + ae_v_move(&a->ptr.pp_double[offs+i][offs+n1], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, ae_v_len(offs+n1,offs+n-1)); + ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+i]][offs+n1], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs+n1,offs+n-1)); + } + } + rmatrixlefttrsm(n1, n2, a, offs, offs, ae_false, ae_true, 0, a, offs, offs+n1, _state); + rmatrixgemm(m-n1, n-n1, n1, -1.0, a, offs+n1, offs, 0, a, offs, offs+n1, 0, 1.0, a, offs+n1, offs+n1, _state); + rmatrixplurec(a, offs+n1, m-n1, n-n1, pivots, tmp, _state); + for(i=0; i<=n2-1; i++) + { + if( offs+n1+i!=pivots->ptr.p_int[offs+n1+i] ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(0,n1-1)); + ae_v_move(&a->ptr.pp_double[offs+n1+i][offs], 1, &a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, ae_v_len(offs,offs+n1-1)); + ae_v_move(&a->ptr.pp_double[pivots->ptr.p_int[offs+n1+i]][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+n1-1)); + } + } + } +} + + +/************************************************************************* +Complex LUP kernel + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +static void dlu_cmatrixlup2(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jp; + ae_complex s; + + + if( m==0||n==0 ) + { + return; + } + for(j=0; j<=ae_minint(m-1, n-1, _state); j++) + { + jp = j; + for(i=j+1; i<=n-1; i++) + { + if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+j][offs+i], _state),ae_c_abs(a->ptr.pp_complex[offs+j][offs+jp], _state)) ) + { + jp = i; + } + } + pivots->ptr.p_int[offs+j] = offs+jp; + if( jp!=j ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+j], a->stride, "N", ae_v_len(0,m-1)); + ae_v_cmove(&a->ptr.pp_complex[offs][offs+j], a->stride, &a->ptr.pp_complex[offs][offs+jp], a->stride, "N", ae_v_len(offs,offs+m-1)); + ae_v_cmove(&a->ptr.pp_complex[offs][offs+jp], a->stride, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+m-1)); + } + if( ae_c_neq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0))&&j+1<=n-1 ) + { + s = ae_c_d_div((double)(1),a->ptr.pp_complex[offs+j][offs+j]); + ae_v_cmulc(&a->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); + } + if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); + ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); + cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); + } + } +} + + +/************************************************************************* +Real LUP kernel + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +static void dlu_rmatrixlup2(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jp; + double s; + + + if( m==0||n==0 ) + { + return; + } + for(j=0; j<=ae_minint(m-1, n-1, _state); j++) + { + jp = j; + for(i=j+1; i<=n-1; i++) + { + if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+j][offs+i], _state),ae_fabs(a->ptr.pp_double[offs+j][offs+jp], _state)) ) + { + jp = i; + } + } + pivots->ptr.p_int[offs+j] = offs+jp; + if( jp!=j ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+j], a->stride, ae_v_len(0,m-1)); + ae_v_move(&a->ptr.pp_double[offs][offs+j], a->stride, &a->ptr.pp_double[offs][offs+jp], a->stride, ae_v_len(offs,offs+m-1)); + ae_v_move(&a->ptr.pp_double[offs][offs+jp], a->stride, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+m-1)); + } + if( ae_fp_neq(a->ptr.pp_double[offs+j][offs+j],(double)(0))&&j+1<=n-1 ) + { + s = (double)1/a->ptr.pp_double[offs+j][offs+j]; + ae_v_muld(&a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), s); + } + if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); + ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); + rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); + } + } +} + + +/************************************************************************* +Complex PLU kernel + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1992 +*************************************************************************/ +static void dlu_cmatrixplu2(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jp; + ae_complex s; + + + if( m==0||n==0 ) + { + return; + } + for(j=0; j<=ae_minint(m-1, n-1, _state); j++) + { + jp = j; + for(i=j+1; i<=m-1; i++) + { + if( ae_fp_greater(ae_c_abs(a->ptr.pp_complex[offs+i][offs+j], _state),ae_c_abs(a->ptr.pp_complex[offs+jp][offs+j], _state)) ) + { + jp = i; + } + } + pivots->ptr.p_int[offs+j] = offs+jp; + if( ae_c_neq_d(a->ptr.pp_complex[offs+jp][offs+j],(double)(0)) ) + { + if( jp!=j ) + { + for(i=0; i<=n-1; i++) + { + s = a->ptr.pp_complex[offs+j][offs+i]; + a->ptr.pp_complex[offs+j][offs+i] = a->ptr.pp_complex[offs+jp][offs+i]; + a->ptr.pp_complex[offs+jp][offs+i] = s; + } + } + if( j+1<=m-1 ) + { + s = ae_c_d_div((double)(1),a->ptr.pp_complex[offs+j][offs+j]); + ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); + } + } + if( jptr.p_complex[0], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(0,m-j-2)); + ae_v_cmoveneg(&tmp->ptr.p_complex[m], 1, &a->ptr.pp_complex[offs+j][offs+j+1], 1, "N", ae_v_len(m,m+n-j-2)); + cmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); + } + } +} + + +/************************************************************************* +Real PLU kernel + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + June 30, 1992 +*************************************************************************/ +static void dlu_rmatrixplu2(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jp; + double s; + + + if( m==0||n==0 ) + { + return; + } + for(j=0; j<=ae_minint(m-1, n-1, _state); j++) + { + jp = j; + for(i=j+1; i<=m-1; i++) + { + if( ae_fp_greater(ae_fabs(a->ptr.pp_double[offs+i][offs+j], _state),ae_fabs(a->ptr.pp_double[offs+jp][offs+j], _state)) ) + { + jp = i; + } + } + pivots->ptr.p_int[offs+j] = offs+jp; + if( ae_fp_neq(a->ptr.pp_double[offs+jp][offs+j],(double)(0)) ) + { + if( jp!=j ) + { + for(i=0; i<=n-1; i++) + { + s = a->ptr.pp_double[offs+j][offs+i]; + a->ptr.pp_double[offs+j][offs+i] = a->ptr.pp_double[offs+jp][offs+i]; + a->ptr.pp_double[offs+jp][offs+i] = s; + } + } + if( j+1<=m-1 ) + { + s = (double)1/a->ptr.pp_double[offs+j][offs+j]; + ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+m-1), s); + } + } + if( jptr.p_double[0], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(0,m-j-2)); + ae_v_moveneg(&tmp->ptr.p_double[m], 1, &a->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(m,m+n-j-2)); + rmatrixrank1(m-j-1, n-j-1, a, offs+j+1, offs+j+1, tmp, 0, tmp, m, _state); + } + } +} + + +#endif +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Sparse LU for square NxN CRS matrix with both row and column permutations. + +Represents A as Pr*L*U*Pc, where: +* Pr is a product of row permutations Pr=Pr(0)*Pr(1)*...*Pr(n-2)*Pr(n-1) +* Pc is a product of col permutations Pc=Pc(n-1)*Pc(n-2)*...*Pc(1)*Pc(0) +* L is lower unitriangular +* U is upper triangular + +INPUT PARAMETERS: + A - sparse square matrix in CRS format + PivotType - pivot type: + * 0 - for best pivoting available + * 1 - row-only pivoting + * 2 - row and column greedy pivoting algorithm (most + sparse pivot column is selected from the trailing + matrix at each step) + Buf - temporary buffer, previously allocated memory is + reused as much as possible + +OUTPUT PARAMETERS: + A - LU decomposition of A + PR - array[N], row pivots + PC - array[N], column pivots + Buf - following fields of Buf are set: + * Buf.RowPermRawIdx[] - contains row permutation, with + RawIdx[I]=J meaning that J-th row of the original + input matrix was moved to Ith position of the output + factorization + +This function always succeeds i.e. it ALWAYS returns valid factorization, +but for your convenience it also returns boolean value which helps to +detect symbolically degenerate matrix: +* function returns TRUE if the matrix was factorized AND symbolically + non-degenerate +* function returns FALSE if the matrix was factorized but U has strictly + zero elements at the diagonal (the factorization is returned anyway). + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +ae_bool sptrflu(sparsematrix* a, + ae_int_t pivottype, + /* Integer */ ae_vector* pr, + /* Integer */ ae_vector* pc, + sluv2buffer* buf, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t jp; + ae_int_t i0; + ae_int_t i1; + ae_int_t ibest; + ae_int_t jbest; + double v; + double v0; + ae_int_t nz0; + ae_int_t nz1; + double uu; + ae_int_t offs; + ae_int_t tmpndense; + ae_bool densificationsupported; + ae_int_t densifyabove; + ae_bool result; + + + ae_assert(sparseiscrs(a, _state), "SparseLU: A is not stored in CRS format", _state); + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseLU: non-square A", _state); + ae_assert((pivottype==0||pivottype==1)||pivottype==2, "SparseLU: unexpected pivot type", _state); + result = ae_true; + n = sparsegetnrows(a, _state); + if( pivottype==0 ) + { + pivottype = 2; + } + densificationsupported = pivottype==2; + + /* + * + */ + buf->n = n; + ivectorsetlengthatleast(&buf->rowpermrawidx, n, _state); + for(i=0; i<=n-1; i++) + { + buf->rowpermrawidx.ptr.p_int[i] = i; + } + + /* + * Allocate storage for sparse L and U factors + * + * NOTE: SparseMatrix structure for these factors is only + * partially initialized; we use it just as a temporary + * storage and do not intend to use facilities of the + * 'sparse' subpackage to work with these objects. + */ + buf->sparsel.matrixtype = 1; + buf->sparsel.m = n; + buf->sparsel.n = n; + ivectorsetlengthatleast(&buf->sparsel.ridx, n+1, _state); + buf->sparsel.ridx.ptr.p_int[0] = 0; + buf->sparseut.matrixtype = 1; + buf->sparseut.m = n; + buf->sparseut.n = n; + ivectorsetlengthatleast(&buf->sparseut.ridx, n+1, _state); + buf->sparseut.ridx.ptr.p_int[0] = 0; + + /* + * Allocate unprocessed yet part of the matrix, + * two submatrices: + * * BU, upper J rows of columns [J,N), upper submatrix + * * BL, left J cols of rows [J,N), left submatrix + * * B1, (N-J)*(N-J) square submatrix + */ + sptrf_sluv2list1init(n, &buf->bleft, _state); + sptrf_sluv2list1init(n, &buf->bupper, _state); + ivectorsetlengthatleast(pr, n, _state); + ivectorsetlengthatleast(pc, n, _state); + ivectorsetlengthatleast(&buf->v0i, n, _state); + ivectorsetlengthatleast(&buf->v1i, n, _state); + rvectorsetlengthatleast(&buf->v0r, n, _state); + rvectorsetlengthatleast(&buf->v1r, n, _state); + sptrf_sparsetrailinit(a, &buf->strail, _state); + + /* + * Prepare dense trail, initial densification + */ + sptrf_densetrailinit(&buf->dtrail, n, _state); + densifyabove = ae_round(sptrf_densebnd*(double)n, _state)+1; + if( densificationsupported ) + { + for(i=0; i<=n-1; i++) + { + if( buf->strail.nzc.ptr.p_int[i]>densifyabove ) + { + sptrf_sparsetraildensify(&buf->strail, i, &buf->bupper, &buf->dtrail, _state); + } + } + } + + /* + * Process sparse part + */ + for(k=0; k<=n-1; k++) + { + + /* + * Find pivot column and pivot row + */ + if( !sptrf_sparsetrailfindpivot(&buf->strail, pivottype, &ibest, &jbest, _state) ) + { + + /* + * Only densified columns are left, break sparse iteration + */ + ae_assert(buf->dtrail.ndense+k==n, "SPTRF: integrity check failed (35741)", _state); + break; + } + pc->ptr.p_int[k] = jbest; + pr->ptr.p_int[k] = ibest; + j = buf->rowpermrawidx.ptr.p_int[k]; + buf->rowpermrawidx.ptr.p_int[k] = buf->rowpermrawidx.ptr.p_int[ibest]; + buf->rowpermrawidx.ptr.p_int[ibest] = j; + + /* + * Apply pivoting to BL and BU + */ + sptrf_sluv2list1swap(&buf->bleft, k, ibest, _state); + sptrf_sluv2list1swap(&buf->bupper, k, jbest, _state); + + /* + * Apply pivoting to sparse trail, pivot out + */ + sptrf_sparsetrailpivotout(&buf->strail, ibest, jbest, &uu, &buf->v0i, &buf->v0r, &nz0, &buf->v1i, &buf->v1r, &nz1, _state); + result = result&&uu!=(double)0; + + /* + * Pivot dense trail + */ + tmpndense = buf->dtrail.ndense; + for(i=0; i<=tmpndense-1; i++) + { + v = buf->dtrail.d.ptr.pp_double[k][i]; + buf->dtrail.d.ptr.pp_double[k][i] = buf->dtrail.d.ptr.pp_double[ibest][i]; + buf->dtrail.d.ptr.pp_double[ibest][i] = v; + } + + /* + * Output to LU matrix + */ + sptrf_sluv2list1appendsequencetomatrix(&buf->bupper, k, ae_true, uu, n, &buf->sparseut, k, _state); + sptrf_sluv2list1appendsequencetomatrix(&buf->bleft, k, ae_false, 0.0, n, &buf->sparsel, k, _state); + + /* + * Extract K-th col/row of B1, generate K-th col/row of BL/BU, update NZC + */ + sptrf_sluv2list1pushsparsevector(&buf->bleft, &buf->v0i, &buf->v0r, nz0, _state); + sptrf_sluv2list1pushsparsevector(&buf->bupper, &buf->v1i, &buf->v1r, nz1, _state); + + /* + * Update the rest of the matrix + */ + if( nz0*(nz1+buf->dtrail.ndense)>0 ) + { + + /* + * Update dense trail + * + * NOTE: this update MUST be performed before we update sparse trail, + * because sparse update may move columns to dense storage after + * update is performed on them. Thus, we have to avoid applying + * same update twice. + */ + if( buf->dtrail.ndense>0 ) + { + tmpndense = buf->dtrail.ndense; + for(i=0; i<=nz0-1; i++) + { + i0 = buf->v0i.ptr.p_int[i]; + v0 = buf->v0r.ptr.p_double[i]; + for(j=0; j<=tmpndense-1; j++) + { + buf->dtrail.d.ptr.pp_double[i0][j] = buf->dtrail.d.ptr.pp_double[i0][j]-v0*buf->dtrail.d.ptr.pp_double[k][j]; + } + } + } + + /* + * Update sparse trail + */ + sptrf_sparsetrailupdate(&buf->strail, &buf->v0i, &buf->v0r, nz0, &buf->v1i, &buf->v1r, nz1, &buf->bupper, &buf->dtrail, densificationsupported, _state); + } + } + + /* + * Process densified trail + */ + if( buf->dtrail.ndense>0 ) + { + tmpndense = buf->dtrail.ndense; + + /* + * Generate column pivots to bring actual order of columns in the + * working part of the matrix to one used for dense storage + */ + for(i=n-tmpndense; i<=n-1; i++) + { + k = buf->dtrail.did.ptr.p_int[i-(n-tmpndense)]; + jp = -1; + for(j=i; j<=n-1; j++) + { + if( buf->strail.colid.ptr.p_int[j]==k ) + { + jp = j; + break; + } + } + ae_assert(jp>=0, "SPTRF: integrity check failed during reordering", _state); + k = buf->strail.colid.ptr.p_int[i]; + buf->strail.colid.ptr.p_int[i] = buf->strail.colid.ptr.p_int[jp]; + buf->strail.colid.ptr.p_int[jp] = k; + pc->ptr.p_int[i] = jp; + } + + /* + * Perform dense LU decomposition on dense trail + */ + rmatrixsetlengthatleast(&buf->dbuf, buf->dtrail.ndense, buf->dtrail.ndense, _state); + for(i=0; i<=tmpndense-1; i++) + { + for(j=0; j<=tmpndense-1; j++) + { + buf->dbuf.ptr.pp_double[i][j] = buf->dtrail.d.ptr.pp_double[i+(n-tmpndense)][j]; + } + } + rvectorsetlengthatleast(&buf->tmp0, 2*n, _state); + ivectorsetlengthatleast(&buf->tmpp, n, _state); + rmatrixplurec(&buf->dbuf, 0, tmpndense, tmpndense, &buf->tmpp, &buf->tmp0, _state); + + /* + * Convert indexes of rows pivots, swap elements of BLeft + */ + for(i=0; i<=tmpndense-1; i++) + { + pr->ptr.p_int[i+(n-tmpndense)] = buf->tmpp.ptr.p_int[i]+(n-tmpndense); + sptrf_sluv2list1swap(&buf->bleft, i+(n-tmpndense), pr->ptr.p_int[i+(n-tmpndense)], _state); + j = buf->rowpermrawidx.ptr.p_int[i+(n-tmpndense)]; + buf->rowpermrawidx.ptr.p_int[i+(n-tmpndense)] = buf->rowpermrawidx.ptr.p_int[pr->ptr.p_int[i+(n-tmpndense)]]; + buf->rowpermrawidx.ptr.p_int[pr->ptr.p_int[i+(n-tmpndense)]] = j; + } + + /* + * Convert U-factor + */ + ivectorgrowto(&buf->sparseut.idx, buf->sparseut.ridx.ptr.p_int[n-tmpndense]+n*tmpndense, _state); + rvectorgrowto(&buf->sparseut.vals, buf->sparseut.ridx.ptr.p_int[n-tmpndense]+n*tmpndense, _state); + for(j=0; j<=tmpndense-1; j++) + { + offs = buf->sparseut.ridx.ptr.p_int[j+(n-tmpndense)]; + k = n-tmpndense; + + /* + * Convert leading N-NDense columns + */ + for(i=0; i<=k-1; i++) + { + v = buf->dtrail.d.ptr.pp_double[i][j]; + if( v!=(double)0 ) + { + buf->sparseut.idx.ptr.p_int[offs] = i; + buf->sparseut.vals.ptr.p_double[offs] = v; + offs = offs+1; + } + } + + /* + * Convert upper diagonal elements + */ + for(i=0; i<=j-1; i++) + { + v = buf->dbuf.ptr.pp_double[i][j]; + if( v!=(double)0 ) + { + buf->sparseut.idx.ptr.p_int[offs] = i+(n-tmpndense); + buf->sparseut.vals.ptr.p_double[offs] = v; + offs = offs+1; + } + } + + /* + * Convert diagonal element (always stored) + */ + v = buf->dbuf.ptr.pp_double[j][j]; + buf->sparseut.idx.ptr.p_int[offs] = j+(n-tmpndense); + buf->sparseut.vals.ptr.p_double[offs] = v; + offs = offs+1; + result = result&&v!=(double)0; + + /* + * Column is done + */ + buf->sparseut.ridx.ptr.p_int[j+(n-tmpndense)+1] = offs; + } + + /* + * Convert L-factor + */ + ivectorgrowto(&buf->sparsel.idx, buf->sparsel.ridx.ptr.p_int[n-tmpndense]+n*tmpndense, _state); + rvectorgrowto(&buf->sparsel.vals, buf->sparsel.ridx.ptr.p_int[n-tmpndense]+n*tmpndense, _state); + for(i=0; i<=tmpndense-1; i++) + { + sptrf_sluv2list1appendsequencetomatrix(&buf->bleft, i+(n-tmpndense), ae_false, 0.0, n, &buf->sparsel, i+(n-tmpndense), _state); + offs = buf->sparsel.ridx.ptr.p_int[i+(n-tmpndense)+1]; + for(j=0; j<=i-1; j++) + { + v = buf->dbuf.ptr.pp_double[i][j]; + if( v!=(double)0 ) + { + buf->sparsel.idx.ptr.p_int[offs] = j+(n-tmpndense); + buf->sparsel.vals.ptr.p_double[offs] = v; + offs = offs+1; + } + } + buf->sparsel.ridx.ptr.p_int[i+(n-tmpndense)+1] = offs; + } + } + + /* + * Allocate output + */ + ivectorsetlengthatleast(&buf->tmpi, n, _state); + for(i=0; i<=n-1; i++) + { + buf->tmpi.ptr.p_int[i] = buf->sparsel.ridx.ptr.p_int[i+1]-buf->sparsel.ridx.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + i0 = buf->sparseut.ridx.ptr.p_int[i]; + i1 = buf->sparseut.ridx.ptr.p_int[i+1]-1; + for(j=i0; j<=i1; j++) + { + k = buf->sparseut.idx.ptr.p_int[j]; + buf->tmpi.ptr.p_int[k] = buf->tmpi.ptr.p_int[k]+1; + } + } + a->matrixtype = 1; + a->ninitialized = buf->sparsel.ridx.ptr.p_int[n]+buf->sparseut.ridx.ptr.p_int[n]; + a->m = n; + a->n = n; + ivectorsetlengthatleast(&a->ridx, n+1, _state); + ivectorsetlengthatleast(&a->idx, a->ninitialized, _state); + rvectorsetlengthatleast(&a->vals, a->ninitialized, _state); + a->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + a->ridx.ptr.p_int[i+1] = a->ridx.ptr.p_int[i]+buf->tmpi.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + i0 = buf->sparsel.ridx.ptr.p_int[i]; + i1 = buf->sparsel.ridx.ptr.p_int[i+1]-1; + jp = a->ridx.ptr.p_int[i]; + for(j=i0; j<=i1; j++) + { + a->idx.ptr.p_int[jp+(j-i0)] = buf->sparsel.idx.ptr.p_int[j]; + a->vals.ptr.p_double[jp+(j-i0)] = buf->sparsel.vals.ptr.p_double[j]; + } + buf->tmpi.ptr.p_int[i] = buf->sparsel.ridx.ptr.p_int[i+1]-buf->sparsel.ridx.ptr.p_int[i]; + } + ivectorsetlengthatleast(&a->didx, n, _state); + ivectorsetlengthatleast(&a->uidx, n, _state); + for(i=0; i<=n-1; i++) + { + a->didx.ptr.p_int[i] = a->ridx.ptr.p_int[i]+buf->tmpi.ptr.p_int[i]; + a->uidx.ptr.p_int[i] = a->didx.ptr.p_int[i]+1; + buf->tmpi.ptr.p_int[i] = a->didx.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + i0 = buf->sparseut.ridx.ptr.p_int[i]; + i1 = buf->sparseut.ridx.ptr.p_int[i+1]-1; + for(j=i0; j<=i1; j++) + { + k = buf->sparseut.idx.ptr.p_int[j]; + offs = buf->tmpi.ptr.p_int[k]; + a->idx.ptr.p_int[offs] = i; + a->vals.ptr.p_double[offs] = buf->sparseut.vals.ptr.p_double[j]; + buf->tmpi.ptr.p_int[k] = offs+1; + } + } + return result; +} + + +/************************************************************************* +This function initialized rectangular submatrix structure. + +After initialization this structure stores matrix[N,0], which contains N +rows (sequences), stored as single-linked lists. + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sluv2list1init(ae_int_t n, + sluv2list1matrix* a, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>=1, "SLUV2List1Init: N<1", _state); + a->nfixed = n; + a->ndynamic = 0; + a->nallocated = n; + a->nused = 0; + ivectorgrowto(&a->idxfirst, n, _state); + ivectorgrowto(&a->strgidx, 2*a->nallocated, _state); + rvectorgrowto(&a->strgval, a->nallocated, _state); + for(i=0; i<=n-1; i++) + { + a->idxfirst.ptr.p_int[i] = -1; + } +} + + +/************************************************************************* +This function swaps sequences #I and #J stored by the structure + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sluv2list1swap(sluv2list1matrix* a, + ae_int_t i, + ae_int_t j, + ae_state *_state) +{ + ae_int_t k; + + + k = a->idxfirst.ptr.p_int[i]; + a->idxfirst.ptr.p_int[i] = a->idxfirst.ptr.p_int[j]; + a->idxfirst.ptr.p_int[j] = k; +} + + +/************************************************************************* +This function drops sequence #I from the structure + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sluv2list1dropsequence(sluv2list1matrix* a, + ae_int_t i, + ae_state *_state) +{ + + + a->idxfirst.ptr.p_int[i] = -1; +} + + +/************************************************************************* +This function appends sequence from the structure to the sparse matrix. + +It is assumed that S is a lower triangular matrix, and A stores strictly +lower triangular elements (no diagonal ones!). You can explicitly control +whether you want to add diagonal elements or not. + +Output matrix is assumed to be stored in CRS format and to be partially +initialized (up to, but not including, Dst-th row). DIdx and UIdx are NOT +updated by this function as well as NInitialized. + +INPUT PARAMETERS: + A - rectangular matrix structure + Src - sequence (row or column) index in the structure + HasDiagonal - whether we want to add diagonal element + D - diagonal element, if HasDiagonal=True + NZMAX - maximum estimated number of non-zeros in the row, + this function will preallocate storage in the output + matrix. + S - destination matrix in CRS format, partially initialized + Dst - destination row index + + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sluv2list1appendsequencetomatrix(const sluv2list1matrix* a, + ae_int_t src, + ae_bool hasdiagonal, + double d, + ae_int_t nzmax, + sparsematrix* s, + ae_int_t dst, + ae_state *_state) +{ + ae_int_t i; + ae_int_t i0; + ae_int_t i1; + ae_int_t jp; + ae_int_t nnz; + + + i0 = s->ridx.ptr.p_int[dst]; + ivectorgrowto(&s->idx, i0+nzmax, _state); + rvectorgrowto(&s->vals, i0+nzmax, _state); + if( hasdiagonal ) + { + i1 = i0+nzmax-1; + s->idx.ptr.p_int[i1] = dst; + s->vals.ptr.p_double[i1] = d; + nnz = 1; + } + else + { + i1 = i0+nzmax; + nnz = 0; + } + jp = a->idxfirst.ptr.p_int[src]; + while(jp>=0) + { + i1 = i1-1; + s->idx.ptr.p_int[i1] = a->strgidx.ptr.p_int[2*jp+1]; + s->vals.ptr.p_double[i1] = a->strgval.ptr.p_double[jp]; + nnz = nnz+1; + jp = a->strgidx.ptr.p_int[2*jp+0]; + } + for(i=0; i<=nnz-1; i++) + { + s->idx.ptr.p_int[i0+i] = s->idx.ptr.p_int[i1+i]; + s->vals.ptr.p_double[i0+i] = s->vals.ptr.p_double[i1+i]; + } + s->ridx.ptr.p_int[dst+1] = s->ridx.ptr.p_int[dst]+nnz; +} + + +/************************************************************************* +This function appends sparse column to the matrix, increasing its size +from [N,K] to [N,K+1] + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sluv2list1pushsparsevector(sluv2list1matrix* a, + /* Integer */ const ae_vector* si, + /* Real */ const ae_vector* sv, + ae_int_t nz, + ae_state *_state) +{ + ae_int_t idx; + ae_int_t i; + ae_int_t k; + ae_int_t nused; + double v; + + + + /* + * Fetch matrix size, increase + */ + k = a->ndynamic; + ae_assert(knfixed, "Assertion failed", _state); + a->ndynamic = k+1; + + /* + * Allocate new storage if needed + */ + nused = a->nused; + a->nallocated = ae_maxint(a->nallocated, nused+nz, _state); + ivectorgrowto(&a->strgidx, 2*a->nallocated, _state); + rvectorgrowto(&a->strgval, a->nallocated, _state); + + /* + * Append to list + */ + for(idx=0; idx<=nz-1; idx++) + { + i = si->ptr.p_int[idx]; + v = sv->ptr.p_double[idx]; + a->strgidx.ptr.p_int[2*nused+0] = a->idxfirst.ptr.p_int[i]; + a->strgidx.ptr.p_int[2*nused+1] = k; + a->strgval.ptr.p_double[nused] = v; + a->idxfirst.ptr.p_int[i] = nused; + nused = nused+1; + } + a->nused = nused; +} + + +/************************************************************************* +This function initializes dense trail, by default it is matrix[N,0] + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_densetrailinit(sluv2densetrail* d, + ae_int_t n, + ae_state *_state) +{ + ae_int_t excessivesize; + + + + /* + * Note: excessive rows are allocated to accomodate for situation when + * this buffer is used to solve successive problems with increasing + * sizes. + */ + excessivesize = ae_maxint(ae_round(1.333*(double)n, _state), n, _state); + d->n = n; + d->ndense = 0; + ivectorsetlengthatleast(&d->did, n, _state); + if( d->d.rows<=excessivesize ) + { + rmatrixsetlengthatleast(&d->d, n, 1, _state); + } + else + { + ae_matrix_set_length(&d->d, excessivesize, 1, _state); + } +} + + +/************************************************************************* +This function appends column with id=ID to the dense trail (column IDs are +integer numbers in [0,N) which can be used to track column permutations). + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_densetrailappendcolumn(sluv2densetrail* d, + /* Real */ const ae_vector* x, + ae_int_t id, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t targetidx; + + + n = d->n; + + /* + * Reallocate storage + */ + rmatrixgrowcolsto(&d->d, d->ndense+1, n, _state); + + /* + * Copy to dense storage: + * * BUpper + * * BTrail + * Remove from sparse storage + */ + targetidx = d->ndense; + for(i=0; i<=n-1; i++) + { + d->d.ptr.pp_double[i][targetidx] = x->ptr.p_double[i]; + } + d->did.ptr.p_int[targetidx] = id; + d->ndense = targetidx+1; +} + + +/************************************************************************* +This function initializes sparse trail from the sparse matrix. By default, +sparse trail spans columns and rows in [0,N) range. Subsequent pivoting +out of rows/columns changes its range to [K,N), [K+1,N) and so on. + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sparsetrailinit(const sparsematrix* s, + sluv2sparsetrail* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t p; + ae_int_t slsused; + + + ae_assert(s->m==s->n, "SparseTrailInit: M<>N", _state); + ae_assert(s->matrixtype==1, "SparseTrailInit: non-CRS input", _state); + n = s->n; + a->n = s->n; + a->k = 0; + ivectorsetlengthatleast(&a->nzc, n, _state); + ivectorsetlengthatleast(&a->colid, n, _state); + rvectorsetlengthatleast(&a->tmp0, n, _state); + for(i=0; i<=n-1; i++) + { + a->colid.ptr.p_int[i] = i; + } + bvectorsetlengthatleast(&a->isdensified, n, _state); + for(i=0; i<=n-1; i++) + { + a->isdensified.ptr.p_bool[i] = ae_false; + } + + /* + * Working set of columns + */ + a->maxwrkcnt = iboundval(ae_round((double)1+(double)n/(double)3, _state), 1, ae_minint(n, 50, _state), _state); + a->wrkcnt = 0; + ivectorsetlengthatleast(&a->wrkset, a->maxwrkcnt, _state); + + /* + * Sparse linked storage (SLS). Store CRS matrix to SLS format, + * row by row, starting from the last one. + */ + ivectorsetlengthatleast(&a->slscolptr, n, _state); + ivectorsetlengthatleast(&a->slsrowptr, n, _state); + ivectorsetlengthatleast(&a->slsidx, s->ridx.ptr.p_int[n]*sptrf_slswidth, _state); + rvectorsetlengthatleast(&a->slsval, s->ridx.ptr.p_int[n], _state); + for(i=0; i<=n-1; i++) + { + a->nzc.ptr.p_int[i] = 0; + } + for(i=0; i<=n-1; i++) + { + a->slscolptr.ptr.p_int[i] = -1; + a->slsrowptr.ptr.p_int[i] = -1; + } + slsused = 0; + for(i=n-1; i>=0; i--) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j1; jj>=j0; jj--) + { + j = s->idx.ptr.p_int[jj]; + + /* + * Update non-zero counts for columns + */ + a->nzc.ptr.p_int[j] = a->nzc.ptr.p_int[j]+1; + + /* + * Insert into column list + */ + p = a->slscolptr.ptr.p_int[j]; + if( p>=0 ) + { + a->slsidx.ptr.p_int[p*sptrf_slswidth+0] = slsused; + } + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+0] = -1; + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+1] = p; + a->slscolptr.ptr.p_int[j] = slsused; + + /* + * Insert into row list + */ + p = a->slsrowptr.ptr.p_int[i]; + if( p>=0 ) + { + a->slsidx.ptr.p_int[p*sptrf_slswidth+2] = slsused; + } + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+2] = -1; + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+3] = p; + a->slsrowptr.ptr.p_int[i] = slsused; + + /* + * Store index and value + */ + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+4] = i; + a->slsidx.ptr.p_int[slsused*sptrf_slswidth+5] = j; + a->slsval.ptr.p_double[slsused] = s->vals.ptr.p_double[jj]; + slsused = slsused+1; + } + } + a->slsused = slsused; +} + + +/************************************************************************* +This function searches for a appropriate pivot column/row. + +If there exists non-densified column, it returns indexes of pivot column +and row, with most sparse column selected for column pivoting, and largest +element selected for row pivoting. Function result is True. + +PivotType=1 means that no column pivoting is performed +PivotType=2 means that both column and row pivoting are supported + +If all columns were densified, False is returned. + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static ae_bool sptrf_sparsetrailfindpivot(sluv2sparsetrail* a, + ae_int_t pivottype, + ae_int_t* ipiv, + ae_int_t* jpiv, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t j; + ae_int_t jp; + ae_int_t entry; + ae_int_t nz; + ae_int_t maxwrknz; + ae_int_t nnzbest; + double s; + double bbest; + ae_int_t wrk0; + ae_int_t wrk1; + ae_bool result; + + *ipiv = 0; + *jpiv = 0; + + n = a->n; + k = a->k; + nnzbest = n+1; + *jpiv = -1; + *ipiv = -1; + result = ae_true; + + /* + * Select pivot column + */ + if( pivottype==1 ) + { + + /* + * No column pivoting + */ + ae_assert(!a->isdensified.ptr.p_bool[k], "SparseTrailFindPivot: integrity check failed", _state); + *jpiv = k; + } + else + { + + /* + * Find pivot column + */ + for(;;) + { + + /* + * Scan working set (if non-empty) for good columns + */ + maxwrknz = a->maxwrknz; + for(j=0; j<=a->wrkcnt-1; j++) + { + jp = a->wrkset.ptr.p_int[j]; + if( jpisdensified.ptr.p_bool[jp] ) + { + continue; + } + nz = a->nzc.ptr.p_int[jp]; + if( nz>maxwrknz ) + { + continue; + } + if( *jpiv<0||nz=0 ) + { + break; + } + + /* + * Well, nothing found. Recompute working set: + * * determine most sparse unprocessed yet column + * * gather all columns with density in [Wrk0,Wrk1) range, + * increase range, repeat, until working set is full + */ + a->wrkcnt = 0; + a->maxwrknz = 0; + wrk0 = n+1; + for(jp=k; jp<=n-1; jp++) + { + if( !a->isdensified.ptr.p_bool[jp]&&a->nzc.ptr.p_int[jp]nzc.ptr.p_int[jp]; + } + } + if( wrk0>n ) + { + + /* + * Only densified columns are present, exit. + */ + result = ae_false; + return result; + } + wrk1 = wrk0+1; + while(a->wrkcntmaxwrkcnt&&wrk0<=n) + { + + /* + * Find columns with non-zero count in [Wrk0,Wrk1) range + */ + for(jp=k; jp<=n-1; jp++) + { + if( a->wrkcnt==a->maxwrkcnt ) + { + break; + } + if( a->isdensified.ptr.p_bool[jp] ) + { + continue; + } + if( a->nzc.ptr.p_int[jp]>=wrk0&&a->nzc.ptr.p_int[jp]wrkset.ptr.p_int[a->wrkcnt] = jp; + a->wrkcnt = a->wrkcnt+1; + a->maxwrknz = ae_maxint(a->maxwrknz, a->nzc.ptr.p_int[jp], _state); + } + } + + /* + * Advance scan range + */ + jp = ae_round(1.41*(double)(wrk1-wrk0), _state)+1; + wrk0 = wrk1; + wrk1 = wrk0+jp; + } + } + } + + /* + * Select pivot row + */ + bbest = (double)(0); + entry = a->slscolptr.ptr.p_int[*jpiv]; + while(entry>=0) + { + s = ae_fabs(a->slsval.ptr.p_double[entry], _state); + if( *ipiv<0||ae_fp_greater(s,bbest) ) + { + bbest = s; + *ipiv = a->slsidx.ptr.p_int[entry*sptrf_slswidth+4]; + } + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + } + if( *ipiv<0 ) + { + *ipiv = k; + } + return result; +} + + +/************************************************************************* +This function pivots out specified row and column. + +Sparse trail range changes from [K,N) to [K+1,N). + +V0I, V0R, V1I, V1R must be preallocated arrays[N]. + +Following data are returned: +* UU - diagonal element (pivoted out), can be zero +* V0I, V0R, NZ0 - sparse column pivoted out to the left (after permutation + is applied to its elements) and divided by UU. + V0I is array[NZ0] which stores row indexes in [K+1,N) range, V0R stores + values. +* V1I, V1R, NZ1 - sparse row pivoted out to the top. + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sparsetrailpivotout(sluv2sparsetrail* a, + ae_int_t ipiv, + ae_int_t jpiv, + double* uu, + /* Integer */ ae_vector* v0i, + /* Real */ ae_vector* v0r, + ae_int_t* nz0, + /* Integer */ ae_vector* v1i, + /* Real */ ae_vector* v1r, + ae_int_t* nz1, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t entry; + double v; + double s; + ae_bool vb; + ae_int_t pos0k; + ae_int_t pos0piv; + ae_int_t pprev; + ae_int_t pnext; + ae_int_t pnextnext; + + *uu = 0.0; + *nz0 = 0; + *nz1 = 0; + + n = a->n; + k = a->k; + ae_assert(kJPiv + * + * NOTE: this code leaves V0I/V0R/NZ0 in the unfinalized state, + * i.e. these arrays do not account for pivoting performed + * on rows. They will be post-processed later. + */ + *nz0 = 0; + pos0k = -1; + pos0piv = -1; + entry = a->slscolptr.ptr.p_int[jpiv]; + while(entry>=0) + { + + /* + * Offload element + */ + i = a->slsidx.ptr.p_int[entry*sptrf_slswidth+4]; + v0i->ptr.p_int[*nz0] = i; + v0r->ptr.p_double[*nz0] = a->slsval.ptr.p_double[entry]; + if( i==k ) + { + pos0k = *nz0; + } + if( i==ipiv ) + { + pos0piv = *nz0; + } + *nz0 = *nz0+1; + + /* + * Remove element from the row list + */ + pprev = a->slsidx.ptr.p_int[entry*sptrf_slswidth+2]; + pnext = a->slsidx.ptr.p_int[entry*sptrf_slswidth+3]; + if( pprev>=0 ) + { + a->slsidx.ptr.p_int[pprev*sptrf_slswidth+3] = pnext; + } + else + { + a->slsrowptr.ptr.p_int[i] = pnext; + } + if( pnext>=0 ) + { + a->slsidx.ptr.p_int[pnext*sptrf_slswidth+2] = pprev; + } + + /* + * Select next entry + */ + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + } + entry = a->slscolptr.ptr.p_int[k]; + a->slscolptr.ptr.p_int[jpiv] = entry; + while(entry>=0) + { + + /* + * Change column index + */ + a->slsidx.ptr.p_int[entry*sptrf_slswidth+5] = jpiv; + + /* + * Next entry + */ + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + } + + /* + * Post-process V0, account for pivoting. + * Compute diagonal element UU. + */ + *uu = (double)(0); + if( pos0k>=0||pos0piv>=0 ) + { + + /* + * Apply permutation to rows of pivoted out column, specific + * implementation depends on the sparsity at locations #Pos0K + * and #Pos0Piv of the V0 array. + */ + if( pos0k>=0&&pos0piv>=0 ) + { + + /* + * Obtain diagonal element + */ + *uu = v0r->ptr.p_double[pos0piv]; + if( *uu!=(double)0 ) + { + s = (double)1/(*uu); + } + else + { + s = (double)(1); + } + + /* + * Move pivoted out element, shift array by one in order + * to remove heading diagonal element (not needed here + * anymore). + */ + v0r->ptr.p_double[pos0piv] = v0r->ptr.p_double[pos0k]; + for(i=0; i<=*nz0-2; i++) + { + v0i->ptr.p_int[i] = v0i->ptr.p_int[i+1]; + v0r->ptr.p_double[i] = v0r->ptr.p_double[i+1]*s; + } + *nz0 = *nz0-1; + } + if( pos0k>=0&&pos0piv<0 ) + { + + /* + * Diagonal element is zero + */ + *uu = (double)(0); + + /* + * Pivot out element, reorder array + */ + v0i->ptr.p_int[pos0k] = ipiv; + for(i=pos0k; i<=*nz0-2; i++) + { + if( v0i->ptr.p_int[i]ptr.p_int[i+1] ) + { + break; + } + j = v0i->ptr.p_int[i]; + v0i->ptr.p_int[i] = v0i->ptr.p_int[i+1]; + v0i->ptr.p_int[i+1] = j; + v = v0r->ptr.p_double[i]; + v0r->ptr.p_double[i] = v0r->ptr.p_double[i+1]; + v0r->ptr.p_double[i+1] = v; + } + } + if( pos0k<0&&pos0piv>=0 ) + { + + /* + * Get diagonal element + */ + *uu = v0r->ptr.p_double[pos0piv]; + if( *uu!=(double)0 ) + { + s = (double)1/(*uu); + } + else + { + s = (double)(1); + } + + /* + * Shift array past the pivoted in element by one + * in order to remove pivot + */ + for(i=0; i<=pos0piv-1; i++) + { + v0r->ptr.p_double[i] = v0r->ptr.p_double[i]*s; + } + for(i=pos0piv; i<=*nz0-2; i++) + { + v0i->ptr.p_int[i] = v0i->ptr.p_int[i+1]; + v0r->ptr.p_double[i] = v0r->ptr.p_double[i+1]*s; + } + *nz0 = *nz0-1; + } + } + + /* + * Pivot out row IPiv from the sparse linked storage: + * * remove row IPiv from the matrix + * * reindex elements of row K after it is permuted to IPiv + * * apply permutation to the cols of the pivoted out row, + * resort columns + */ + *nz1 = 0; + entry = a->slsrowptr.ptr.p_int[ipiv]; + while(entry>=0) + { + + /* + * Offload element + */ + j = a->slsidx.ptr.p_int[entry*sptrf_slswidth+5]; + v1i->ptr.p_int[*nz1] = j; + v1r->ptr.p_double[*nz1] = a->slsval.ptr.p_double[entry]; + *nz1 = *nz1+1; + + /* + * Remove element from the column list + */ + pprev = a->slsidx.ptr.p_int[entry*sptrf_slswidth+0]; + pnext = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + if( pprev>=0 ) + { + a->slsidx.ptr.p_int[pprev*sptrf_slswidth+1] = pnext; + } + else + { + a->slscolptr.ptr.p_int[j] = pnext; + } + if( pnext>=0 ) + { + a->slsidx.ptr.p_int[pnext*sptrf_slswidth+0] = pprev; + } + + /* + * Select next entry + */ + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+3]; + } + a->slsrowptr.ptr.p_int[ipiv] = a->slsrowptr.ptr.p_int[k]; + entry = a->slsrowptr.ptr.p_int[ipiv]; + while(entry>=0) + { + + /* + * Change row index + */ + a->slsidx.ptr.p_int[entry*sptrf_slswidth+4] = ipiv; + + /* + * Resort column affected by row pivoting + */ + j = a->slsidx.ptr.p_int[entry*sptrf_slswidth+5]; + pprev = a->slsidx.ptr.p_int[entry*sptrf_slswidth+0]; + pnext = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + while(pnext>=0&&a->slsidx.ptr.p_int[pnext*sptrf_slswidth+4]slsidx.ptr.p_int[pnext*sptrf_slswidth+1]; + + /* + * prev->next + */ + if( pprev>=0 ) + { + a->slsidx.ptr.p_int[pprev*sptrf_slswidth+1] = pnext; + } + else + { + a->slscolptr.ptr.p_int[j] = pnext; + } + + /* + * entry->prev, entry->next + */ + a->slsidx.ptr.p_int[entry*sptrf_slswidth+0] = pnext; + a->slsidx.ptr.p_int[entry*sptrf_slswidth+1] = pnextnext; + + /* + * next->prev, next->next + */ + a->slsidx.ptr.p_int[pnext*sptrf_slswidth+0] = pprev; + a->slsidx.ptr.p_int[pnext*sptrf_slswidth+1] = entry; + + /* + * nextnext->prev + */ + if( pnextnext>=0 ) + { + a->slsidx.ptr.p_int[pnextnext*sptrf_slswidth+0] = entry; + } + + /* + * PPrev, Item, PNext + */ + pprev = pnext; + pnext = pnextnext; + } + + /* + * Next entry + */ + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+3]; + } + + /* + * Reorder other structures + */ + i = a->nzc.ptr.p_int[k]; + a->nzc.ptr.p_int[k] = a->nzc.ptr.p_int[jpiv]; + a->nzc.ptr.p_int[jpiv] = i; + i = a->colid.ptr.p_int[k]; + a->colid.ptr.p_int[k] = a->colid.ptr.p_int[jpiv]; + a->colid.ptr.p_int[jpiv] = i; + vb = a->isdensified.ptr.p_bool[k]; + a->isdensified.ptr.p_bool[k] = a->isdensified.ptr.p_bool[jpiv]; + a->isdensified.ptr.p_bool[jpiv] = vb; + + /* + * Handle removal of col/row #K + */ + for(i=0; i<=*nz1-1; i++) + { + j = v1i->ptr.p_int[i]; + a->nzc.ptr.p_int[j] = a->nzc.ptr.p_int[j]-1; + } + a->k = a->k+1; +} + + +/************************************************************************* +This function densifies I1-th column of the sparse trail. + +PARAMETERS: + A - sparse trail + I1 - column index + BUpper - upper rectangular submatrix, updated during densification + of the columns (densified columns are removed) + DTrail - dense trail, receives densified columns from sparse + trail and BUpper + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sparsetraildensify(sluv2sparsetrail* a, + ae_int_t i1, + sluv2list1matrix* bupper, + sluv2densetrail* dtrail, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t jp; + ae_int_t entry; + ae_int_t pprev; + ae_int_t pnext; + + + n = a->n; + k = a->k; + ae_assert(kisdensified.ptr.p_bool[i1], "SparseTrailDensify: integrity check failed", _state); + + /* + * Offload items [0,K) of densified column from BUpper + */ + for(i=0; i<=n-1; i++) + { + a->tmp0.ptr.p_double[i] = (double)(0); + } + jp = bupper->idxfirst.ptr.p_int[i1]; + while(jp>=0) + { + a->tmp0.ptr.p_double[bupper->strgidx.ptr.p_int[2*jp+1]] = bupper->strgval.ptr.p_double[jp]; + jp = bupper->strgidx.ptr.p_int[2*jp+0]; + } + sptrf_sluv2list1dropsequence(bupper, i1, _state); + + /* + * Offload items [K,N) of densified column from BLeft + */ + entry = a->slscolptr.ptr.p_int[i1]; + while(entry>=0) + { + + /* + * Offload element + */ + i = a->slsidx.ptr.p_int[entry*sptrf_slswidth+4]; + a->tmp0.ptr.p_double[i] = a->slsval.ptr.p_double[entry]; + + /* + * Remove element from the row list + */ + pprev = a->slsidx.ptr.p_int[entry*sptrf_slswidth+2]; + pnext = a->slsidx.ptr.p_int[entry*sptrf_slswidth+3]; + if( pprev>=0 ) + { + a->slsidx.ptr.p_int[pprev*sptrf_slswidth+3] = pnext; + } + else + { + a->slsrowptr.ptr.p_int[i] = pnext; + } + if( pnext>=0 ) + { + a->slsidx.ptr.p_int[pnext*sptrf_slswidth+2] = pprev; + } + + /* + * Select next entry + */ + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + } + + /* + * Densify + */ + a->nzc.ptr.p_int[i1] = 0; + a->isdensified.ptr.p_bool[i1] = ae_true; + a->slscolptr.ptr.p_int[i1] = -1; + sptrf_densetrailappendcolumn(dtrail, &a->tmp0, a->colid.ptr.p_int[i1], _state); +} + + +/************************************************************************* +This function appends rank-1 update to the sparse trail. Dense trail is +not updated here, but we may move some columns to dense trail during +update (i.e. densify them). Thus, you have to update dense trail BEFORE +you start updating sparse one (otherwise, recently densified columns will +be updated twice). + +PARAMETERS: + A - sparse trail + V0I, V0R - update column returned by SparseTrailPivotOut (MUST be + array[N] independently of the NZ0). + NZ0 - non-zero count for update column + V1I, V1R - update row returned by SparseTrailPivotOut + NZ1 - non-zero count for update row + BUpper - upper rectangular submatrix, updated during densification + of the columns (densified columns are removed) + DTrail - dense trail, receives densified columns from sparse + trail and BUpper + DensificationSupported- if False, no densification is performed + + -- ALGLIB routine -- + 15.01.2019 + Bochkanov Sergey +*************************************************************************/ +static void sptrf_sparsetrailupdate(sluv2sparsetrail* a, + /* Integer */ ae_vector* v0i, + /* Real */ ae_vector* v0r, + ae_int_t nz0, + /* Integer */ const ae_vector* v1i, + /* Real */ const ae_vector* v1r, + ae_int_t nz1, + sluv2list1matrix* bupper, + sluv2densetrail* dtrail, + ae_bool densificationsupported, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t i0; + ae_int_t i1; + double v1; + ae_int_t densifyabove; + ae_int_t nnz; + ae_int_t entry; + ae_int_t newentry; + ae_int_t pprev; + ae_int_t pnext; + ae_int_t p; + ae_int_t nexti; + ae_int_t newoffs; + + + n = a->n; + k = a->k; + ae_assert(kcnt>=nz0+1, "SparseTrailUpdate: integrity check failed", _state); + ae_assert(v0r->cnt>=nz0+1, "SparseTrailUpdate: integrity check failed", _state); + v0i->ptr.p_int[nz0] = -1; + v0r->ptr.p_double[nz0] = (double)(0); + + /* + * Update sparse representation + */ + ivectorgrowto(&a->slsidx, (a->slsused+nz0*nz1)*sptrf_slswidth, _state); + rvectorgrowto(&a->slsval, a->slsused+nz0*nz1, _state); + for(j=0; j<=nz1-1; j++) + { + if( nz0==0 ) + { + continue; + } + i1 = v1i->ptr.p_int[j]; + v1 = v1r->ptr.p_double[j]; + + /* + * Update column #I1 + */ + nnz = a->nzc.ptr.p_int[i1]; + i = 0; + i0 = v0i->ptr.p_int[i]; + entry = a->slscolptr.ptr.p_int[i1]; + pprev = -1; + while(i=0 ) + { + nexti = a->slsidx.ptr.p_int[entry*sptrf_slswidth+4]; + } + else + { + nexti = n+1; + } + while(i=nexti ) + { + break; + } + + /* + * Allocate new entry, store column/row/value + */ + newentry = a->slsused; + a->slsused = newentry+1; + nnz = nnz+1; + newoffs = newentry*sptrf_slswidth; + a->slsidx.ptr.p_int[newoffs+4] = i0; + a->slsidx.ptr.p_int[newoffs+5] = i1; + a->slsval.ptr.p_double[newentry] = -v1*v0r->ptr.p_double[i]; + + /* + * Insert entry into column list + */ + a->slsidx.ptr.p_int[newoffs+0] = pprev; + a->slsidx.ptr.p_int[newoffs+1] = pnext; + if( pprev>=0 ) + { + a->slsidx.ptr.p_int[pprev*sptrf_slswidth+1] = newentry; + } + else + { + a->slscolptr.ptr.p_int[i1] = newentry; + } + if( entry>=0 ) + { + a->slsidx.ptr.p_int[entry*sptrf_slswidth+0] = newentry; + } + + /* + * Insert entry into row list + */ + p = a->slsrowptr.ptr.p_int[i0]; + a->slsidx.ptr.p_int[newoffs+2] = -1; + a->slsidx.ptr.p_int[newoffs+3] = p; + if( p>=0 ) + { + a->slsidx.ptr.p_int[p*sptrf_slswidth+2] = newentry; + } + a->slsrowptr.ptr.p_int[i0] = newentry; + + /* + * Advance pointers + */ + pprev = newentry; + i = i+1; + i0 = v0i->ptr.p_int[i]; + } + if( i>=nz0 ) + { + break; + } + + /* + * Update already existing entry of the column list, if needed + */ + if( entry>=0 ) + { + if( i0==nexti ) + { + a->slsval.ptr.p_double[entry] = a->slsval.ptr.p_double[entry]-v1*v0r->ptr.p_double[i]; + i = i+1; + i0 = v0i->ptr.p_int[i]; + } + pprev = entry; + } + + /* + * Advance to the next pre-existing entry (if present) + */ + if( entry>=0 ) + { + entry = a->slsidx.ptr.p_int[entry*sptrf_slswidth+1]; + } + } + a->nzc.ptr.p_int[i1] = nnz; + + /* + * Densify column if needed + */ + if( (densificationsupported&&nnz>densifyabove)&&!a->isdensified.ptr.p_bool[i1] ) + { + sptrf_sparsetraildensify(a, i1, bupper, dtrail, _state); + } + } +} + + +void _sluv2list1matrix_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sluv2list1matrix *p = (sluv2list1matrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->idxfirst, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->strgidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->strgval, 0, DT_REAL, _state, make_automatic); +} + + +void _sluv2list1matrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sluv2list1matrix *dst = (sluv2list1matrix*)_dst; + const sluv2list1matrix *src = (const sluv2list1matrix*)_src; + dst->nfixed = src->nfixed; + dst->ndynamic = src->ndynamic; + ae_vector_init_copy(&dst->idxfirst, &src->idxfirst, _state, make_automatic); + ae_vector_init_copy(&dst->strgidx, &src->strgidx, _state, make_automatic); + ae_vector_init_copy(&dst->strgval, &src->strgval, _state, make_automatic); + dst->nallocated = src->nallocated; + dst->nused = src->nused; +} + + +void _sluv2list1matrix_clear(void* _p) +{ + sluv2list1matrix *p = (sluv2list1matrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->idxfirst); + ae_vector_clear(&p->strgidx); + ae_vector_clear(&p->strgval); +} + + +void _sluv2list1matrix_destroy(void* _p) +{ + sluv2list1matrix *p = (sluv2list1matrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->idxfirst); + ae_vector_destroy(&p->strgidx); + ae_vector_destroy(&p->strgval); +} + + +void _sluv2sparsetrail_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sluv2sparsetrail *p = (sluv2sparsetrail*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->nzc, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->wrkset, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->colid, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->isdensified, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->slscolptr, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->slsrowptr, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->slsidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->slsval, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); +} + + +void _sluv2sparsetrail_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sluv2sparsetrail *dst = (sluv2sparsetrail*)_dst; + const sluv2sparsetrail *src = (const sluv2sparsetrail*)_src; + dst->n = src->n; + dst->k = src->k; + ae_vector_init_copy(&dst->nzc, &src->nzc, _state, make_automatic); + dst->maxwrkcnt = src->maxwrkcnt; + dst->maxwrknz = src->maxwrknz; + dst->wrkcnt = src->wrkcnt; + ae_vector_init_copy(&dst->wrkset, &src->wrkset, _state, make_automatic); + ae_vector_init_copy(&dst->colid, &src->colid, _state, make_automatic); + ae_vector_init_copy(&dst->isdensified, &src->isdensified, _state, make_automatic); + ae_vector_init_copy(&dst->slscolptr, &src->slscolptr, _state, make_automatic); + ae_vector_init_copy(&dst->slsrowptr, &src->slsrowptr, _state, make_automatic); + ae_vector_init_copy(&dst->slsidx, &src->slsidx, _state, make_automatic); + ae_vector_init_copy(&dst->slsval, &src->slsval, _state, make_automatic); + dst->slsused = src->slsused; + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); +} + + +void _sluv2sparsetrail_clear(void* _p) +{ + sluv2sparsetrail *p = (sluv2sparsetrail*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->nzc); + ae_vector_clear(&p->wrkset); + ae_vector_clear(&p->colid); + ae_vector_clear(&p->isdensified); + ae_vector_clear(&p->slscolptr); + ae_vector_clear(&p->slsrowptr); + ae_vector_clear(&p->slsidx); + ae_vector_clear(&p->slsval); + ae_vector_clear(&p->tmp0); +} + + +void _sluv2sparsetrail_destroy(void* _p) +{ + sluv2sparsetrail *p = (sluv2sparsetrail*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->nzc); + ae_vector_destroy(&p->wrkset); + ae_vector_destroy(&p->colid); + ae_vector_destroy(&p->isdensified); + ae_vector_destroy(&p->slscolptr); + ae_vector_destroy(&p->slsrowptr); + ae_vector_destroy(&p->slsidx); + ae_vector_destroy(&p->slsval); + ae_vector_destroy(&p->tmp0); +} + + +void _sluv2densetrail_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sluv2densetrail *p = (sluv2densetrail*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->d, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->did, 0, DT_INT, _state, make_automatic); +} + + +void _sluv2densetrail_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sluv2densetrail *dst = (sluv2densetrail*)_dst; + const sluv2densetrail *src = (const sluv2densetrail*)_src; + dst->n = src->n; + dst->ndense = src->ndense; + ae_matrix_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->did, &src->did, _state, make_automatic); +} + + +void _sluv2densetrail_clear(void* _p) +{ + sluv2densetrail *p = (sluv2densetrail*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->d); + ae_vector_clear(&p->did); +} + + +void _sluv2densetrail_destroy(void* _p) +{ + sluv2densetrail *p = (sluv2densetrail*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->d); + ae_vector_destroy(&p->did); +} + + +void _sluv2buffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sluv2buffer *p = (sluv2buffer*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_init(&p->sparsel, _state, make_automatic); + _sparsematrix_init(&p->sparseut, _state, make_automatic); + _sluv2list1matrix_init(&p->bleft, _state, make_automatic); + _sluv2list1matrix_init(&p->bupper, _state, make_automatic); + _sluv2sparsetrail_init(&p->strail, _state, make_automatic); + _sluv2densetrail_init(&p->dtrail, _state, make_automatic); + ae_vector_init(&p->rowpermrawidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->dbuf, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->v0i, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->v1i, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->v0r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->v1r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpp, 0, DT_INT, _state, make_automatic); +} + + +void _sluv2buffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sluv2buffer *dst = (sluv2buffer*)_dst; + const sluv2buffer *src = (const sluv2buffer*)_src; + dst->n = src->n; + _sparsematrix_init_copy(&dst->sparsel, &src->sparsel, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseut, &src->sparseut, _state, make_automatic); + _sluv2list1matrix_init_copy(&dst->bleft, &src->bleft, _state, make_automatic); + _sluv2list1matrix_init_copy(&dst->bupper, &src->bupper, _state, make_automatic); + _sluv2sparsetrail_init_copy(&dst->strail, &src->strail, _state, make_automatic); + _sluv2densetrail_init_copy(&dst->dtrail, &src->dtrail, _state, make_automatic); + ae_vector_init_copy(&dst->rowpermrawidx, &src->rowpermrawidx, _state, make_automatic); + ae_matrix_init_copy(&dst->dbuf, &src->dbuf, _state, make_automatic); + ae_vector_init_copy(&dst->v0i, &src->v0i, _state, make_automatic); + ae_vector_init_copy(&dst->v1i, &src->v1i, _state, make_automatic); + ae_vector_init_copy(&dst->v0r, &src->v0r, _state, make_automatic); + ae_vector_init_copy(&dst->v1r, &src->v1r, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_vector_init_copy(&dst->tmpp, &src->tmpp, _state, make_automatic); +} + + +void _sluv2buffer_clear(void* _p) +{ + sluv2buffer *p = (sluv2buffer*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_clear(&p->sparsel); + _sparsematrix_clear(&p->sparseut); + _sluv2list1matrix_clear(&p->bleft); + _sluv2list1matrix_clear(&p->bupper); + _sluv2sparsetrail_clear(&p->strail); + _sluv2densetrail_clear(&p->dtrail); + ae_vector_clear(&p->rowpermrawidx); + ae_matrix_clear(&p->dbuf); + ae_vector_clear(&p->v0i); + ae_vector_clear(&p->v1i); + ae_vector_clear(&p->v0r); + ae_vector_clear(&p->v1r); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmpi); + ae_vector_clear(&p->tmpp); +} + + +void _sluv2buffer_destroy(void* _p) +{ + sluv2buffer *p = (sluv2buffer*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_destroy(&p->sparsel); + _sparsematrix_destroy(&p->sparseut); + _sluv2list1matrix_destroy(&p->bleft); + _sluv2list1matrix_destroy(&p->bupper); + _sluv2sparsetrail_destroy(&p->strail); + _sluv2densetrail_destroy(&p->dtrail); + ae_vector_destroy(&p->rowpermrawidx); + ae_matrix_destroy(&p->dbuf); + ae_vector_destroy(&p->v0i); + ae_vector_destroy(&p->v1i); + ae_vector_destroy(&p->v0r); + ae_vector_destroy(&p->v1r); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmpi); + ae_vector_destroy(&p->tmpp); +} + + +#endif +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function generates approximate minimum degree ordering + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format. Only + sparsity structure (as given by Idx[] field) matters, + specific values of matrix elements are ignored. + N - problem size + Buf - reusable buffer object, does not need special initialization + +OUTPUT PARAMETERS + Perm - array[N], maps original indexes I to permuted indexes + InvPerm - array[N], maps permuted indexes I to original indexes + +NOTE: definite 'DEBUG.SLOW' trace tag will activate extra-slow (roughly + N^3 ops) integrity checks, in addition to cheap O(1) ones. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void generateamdpermutation(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + amdbuffer* buf, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t r; + ae_vector dummy; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true); + + r = generateamdpermutationx(a, &dummy, n, 0.0, perm, invperm, 0, buf, _state); + ae_assert(r==n, "GenerateAMDPermutation: integrity check failed, the matrix is only partially processed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function generates approximate minimum degree ordering, either +classic or improved with better support for dense rows: +* the classic version processed entire matrix and returns N as result. The + problem with classic version is that it may be slow for matrices with + dense or nearly dense rows +* the improved version processes K most sparse rows, and moves other N-K + ones to the end. The number of sparse rows K is returned. The tail, + which is now a (N-K)*(N-K) matrix, should be repeatedly processed by the + same function until zero is returned. + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format + Eligible - array[N], set of boolean flags that mark columns of A + as eligible for ordering. Columns that are not eligible + are postponed (moved to the end) by the improved AMD + algorithm. This array is ignored (not referenced at + all) when AMDType=0. + N - problem size + PromoteAbove- columns with degrees higher than PromoteAbove*max(MEAN(Degree),1) + may be postponed. Ignored for AMDType<>1. + This parameter controls postponement of dense columns + (and algorithm ability to efficiently handle them): + * big PromoteAbove (N or more) effectively means that + no eligible columns are postponed. Better to combine + with your own heuristic to choose eligible columns, + otherwise algorithm will have hard time on problems + with dense columns in the eligible set. + * values between 2 and 10 are usually a good choice + for manual control + * zero value means that appropriate value is + automatically chosen. Specific value may change in + future ALGLIB versions. Recommended. + AMDType - ordering type: + * 0 for the classic AMD + * 1 for the improved AMD + Buf - reusable buffer object, does not need special initialization + +OUTPUT PARAMETERS + Perm - array[N], maps original indexes I to permuted indexes + InvPerm - array[N], maps permuted indexes I to original indexes + +RESULT: + number of successfully ordered rows/cols; + for AMDType=0: Result=N + for AMDType=1: 0<=Result<=N. Result=0 is returned only when there are + no columns that are both sparse enough and eligible. + +NOTE: defining 'DEBUG.SLOW' trace tag will activate extra-slow (roughly + N^3 ops) integrity checks, in addition to cheap O(1) ones. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +ae_int_t generateamdpermutationx(const sparsematrix* a, + /* Boolean */ const ae_vector* eligible, + ae_int_t n, + double promoteabove, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + ae_int_t amdtype, + amdbuffer* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t p; + ae_int_t setprealloc; + ae_int_t inithashbucketsize; + ae_bool extendeddebug; + ae_int_t nodesize; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t tau; + double meand; + ae_int_t neligible; + ae_int_t d; + ae_int_t result; + + + ae_assert(amdtype==0||amdtype==1, "GenerateAMDPermutationX: unexpected ordering type", _state); + ae_assert(amdtype==0||(ae_isfinite(promoteabove, _state)&&ae_fp_greater_eq(promoteabove,(double)(0))), "GenerateAMDPermutationX: unexpected PromoteAbove - infinite or negative", _state); + setprealloc = 3; + inithashbucketsize = 16; + extendeddebug = ae_is_trace_enabled("DEBUG.SLOW")&&n<=100; + result = n; + buf->n = n; + buf->checkexactdegrees = extendeddebug; + buf->extendeddebug = extendeddebug; + amdordering_mtxinit(n, &buf->mtxl, _state); + amdordering_knsinitfroma(a, n, ae_true, &buf->seta, _state); + amdordering_knsinit(n, n, setprealloc, &buf->setsuper, _state); + for(i=0; i<=n-1; i++) + { + amdordering_knsaddnewelement(&buf->setsuper, i, i, _state); + } + amdordering_knsinit(n, n, setprealloc, &buf->sete, _state); + amdordering_knsinit(n, n, inithashbucketsize, &buf->hashbuckets, _state); + nisinitemptyslow(n, &buf->nonemptybuckets, _state); + ivectorsetlengthatleast(&buf->perm, n, _state); + ivectorsetlengthatleast(&buf->invperm, n, _state); + ivectorsetlengthatleast(&buf->columnswaps, n, _state); + for(i=0; i<=n-1; i++) + { + buf->perm.ptr.p_int[i] = i; + buf->invperm.ptr.p_int[i] = i; + buf->columnswaps.ptr.p_int[i] = i; + } + bsetallocv(n, ae_true, &buf->iseligible, _state); + if( amdtype==1 ) + { + bcopyv(n, eligible, &buf->iseligible, _state); + } + amdordering_vtxinit(a, n, &buf->iseligible, ae_true, buf->checkexactdegrees, &buf->vertexdegrees, _state); + bsetallocv(n, ae_true, &buf->issupernode, _state); + bsetallocv(n, ae_false, &buf->iseliminated, _state); + isetallocv(n, -1, &buf->arrwe, _state); + iallocv(n, &buf->ls, _state); + nisinitemptyslow(n, &buf->setp, _state); + nisinitemptyslow(n, &buf->lp, _state); + nisinitemptyslow(n, &buf->setrp, _state); + nisinitemptyslow(n, &buf->ep, _state); + nisinitemptyslow(n, &buf->exactdegreetmp0, _state); + nisinitemptyslow(n, &buf->adji, _state); + nisinitemptyslow(n, &buf->adjj, _state); + nisinitemptyslow(n, &buf->setq, _state); + nisinitemptyslow(n, &buf->setqsupercand, _state); + if( extendeddebug ) + { + ae_matrix_set_length(&buf->dbga, n, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( (j<=i&&sparseexists(a, i, j, _state))||(j>=i&&sparseexists(a, j, i, _state)) ) + { + buf->dbga.ptr.pp_double[i][j] = 0.1/(double)n*(ae_sin((double)i+0.17, _state)+ae_cos(ae_sqrt((double)j+0.65, _state), _state)); + } + else + { + buf->dbga.ptr.pp_double[i][j] = (double)(0); + } + } + } + for(i=0; i<=n-1; i++) + { + buf->dbga.ptr.pp_double[i][i] = (double)(1); + } + } + neligible = n; + tau = 0; + if( amdtype==1 ) + { + ae_assert(eligible->cnt>=n, "GenerateAMDPermutationX: length(Eligible)ptr.p_bool[i] ) + { + d = amdordering_vtxgetapprox(&buf->vertexdegrees, i, _state); + meand = meand+(double)d; + neligible = neligible+1; + } + } + meand = meand/coalesce((double)(neligible), (double)(1), _state); + tau = ae_round(rcase2(ae_fp_greater(promoteabove,(double)(0)), ae_maxreal(promoteabove, (double)(1), _state), (double)(10), _state)*ae_maxreal(meand, (double)(1), _state), _state); + tau = ae_maxint(tau, 1, _state); + for(i=0; i<=n-1; i++) + { + if( amdordering_vtxgetapprox(&buf->vertexdegrees, i, _state)>tau ) + { + nisaddelement(&buf->setqsupercand, i, _state); + } + } + amdordering_amdmovetoquasidense(buf, &buf->setqsupercand, -1, _state); + } + k = 0; + while(ksetq, _state)) + { + amdordering_amdselectpivotelement(buf, k, &p, &nodesize, _state); + if( p<0 ) + { + break; + } + amdordering_amdcomputelp(buf, p, _state); + amdordering_amdmasselimination(buf, p, k, tau, _state); + amdordering_amdmovetoquasidense(buf, &buf->setqsupercand, p, _state); + amdordering_amddetectsupernodes(buf, _state); + if( extendeddebug ) + { + ae_assert(buf->checkexactdegrees, "AMD: extended debug needs exact degrees", _state); + for(i=k; i<=k+nodesize-1; i++) + { + if( buf->columnswaps.ptr.p_int[i]!=i ) + { + swaprows(&buf->dbga, i, buf->columnswaps.ptr.p_int[i], n, _state); + swapcols(&buf->dbga, i, buf->columnswaps.ptr.p_int[i], n, _state); + } + } + for(i=0; i<=nodesize-1; i++) + { + rmatrixgemm(n-k-i, n-k-i, k+i, -1.0, &buf->dbga, k+i, 0, 0, &buf->dbga, 0, k+i, 0, 1.0, &buf->dbga, k+i, k+i, _state); + } + cnt0 = niscount(&buf->lp, _state); + cnt1 = 0; + for(i=k+1; i<=n-1; i++) + { + if( ae_fp_neq(buf->dbga.ptr.pp_double[i][k],(double)(0)) ) + { + inc(&cnt1, _state); + } + } + ae_assert(cnt0+nodesize-1==cnt1, "AMD: integrity check 7344 failed", _state); + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, p, _state)>=amdordering_vtxgetexact(&buf->vertexdegrees, p, _state), "AMD: integrity check for ApproxD failed", _state); + ae_assert(amdordering_vtxgetexact(&buf->vertexdegrees, p, _state)==cnt0, "AMD: integrity check for ExactD failed", _state); + } + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, p, _state)>=niscount(&buf->lp, _state), "AMD: integrity check 7956 failed", _state); + ae_assert((amdordering_knscountkth(&buf->sete, p, _state)>2||niscount(&buf->setq, _state)>0)||amdordering_vtxgetapprox(&buf->vertexdegrees, p, _state)==niscount(&buf->lp, _state), "AMD: integrity check 7295 failed", _state); + amdordering_knsstartenumeration(&buf->sete, p, _state); + while(amdordering_knsenumerate(&buf->sete, &j, _state)) + { + amdordering_mtxclearcolumn(&buf->mtxl, j, _state); + } + amdordering_knsstartenumeration(&buf->setsuper, p, _state); + while(amdordering_knsenumerate(&buf->setsuper, &j, _state)) + { + buf->iseliminated.ptr.p_bool[j] = ae_true; + amdordering_mtxclearrow(&buf->mtxl, j, _state); + } + amdordering_knsclearkthreclaim(&buf->seta, p, _state); + amdordering_knsclearkthreclaim(&buf->sete, p, _state); + buf->issupernode.ptr.p_bool[p] = ae_false; + amdordering_vtxremovevertex(&buf->vertexdegrees, p, _state); + k = k+nodesize; + } + ae_assert(k>0||amdtype==1, "AMD: integrity check 9463 failed", _state); + result = k; + ivectorsetlengthatleast(perm, n, _state); + ivectorsetlengthatleast(invperm, n, _state); + for(i=0; i<=n-1; i++) + { + perm->ptr.p_int[i] = buf->perm.ptr.p_int[i]; + invperm->ptr.p_int[i] = buf->invperm.ptr.p_int[i]; + } + return result; +} + + +/************************************************************************* +Add K-th set from the source kn-set + +INPUT PARAMETERS + SA - set + Src, K - source kn-set and set index K + +OUTPUT PARAMETERS + SA - modified SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_nsaddkth(niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t j; + ae_int_t ns; + + + idxbegin = src->vbegin.ptr.p_int[k]; + idxend = idxbegin+src->vcnt.ptr.p_int[k]; + ns = sa->nstored; + while(idxbegindata.ptr.p_int[idxbegin]; + if( sa->locationof.ptr.p_int[j]<0 ) + { + sa->locationof.ptr.p_int[j] = ns; + sa->items.ptr.p_int[ns] = j; + ns = ns+1; + } + idxbegin = idxbegin+1; + } + sa->nstored = ns; +} + + +/************************************************************************* +Subtracts K-th set from the source structure + +INPUT PARAMETERS + SA - set + Src, K - source kn-set and set index K + +OUTPUT PARAMETERS + SA - modified SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_nssubtractkth(niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t j; + ae_int_t loc; + ae_int_t ns; + ae_int_t item; + + + idxbegin = src->vbegin.ptr.p_int[k]; + idxend = idxbegin+src->vcnt.ptr.p_int[k]; + ns = sa->nstored; + while(idxbegindata.ptr.p_int[idxbegin]; + loc = sa->locationof.ptr.p_int[j]; + if( loc>=0 ) + { + item = sa->items.ptr.p_int[ns-1]; + sa->items.ptr.p_int[loc] = item; + sa->locationof.ptr.p_int[item] = loc; + sa->locationof.ptr.p_int[j] = -1; + ns = ns-1; + } + idxbegin = idxbegin+1; + } + sa->nstored = ns; +} + + +/************************************************************************* +Counts set elements not present in the K-th set of the source structure + +INPUT PARAMETERS + SA - set + Src, K - source kn-set and set index K + +RESULT + number of elements in SA not present in Src[K] + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_nscountnotkth(const niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t intersectcnt; + ae_int_t result; + + + idxbegin = src->vbegin.ptr.p_int[k]; + idxend = idxbegin+src->vcnt.ptr.p_int[k]; + intersectcnt = 0; + while(idxbeginlocationof.ptr.p_int[src->data.ptr.p_int[idxbegin]]>=0 ) + { + intersectcnt = intersectcnt+1; + } + idxbegin = idxbegin+1; + } + result = sa->nstored-intersectcnt; + return result; +} + + +/************************************************************************* +Counts set elements also present in the K-th set of the source structure + +INPUT PARAMETERS + SA - set + Src, K - source kn-set and set index K + +RESULT + number of elements in SA also present in Src[K] + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_nscountandkth(const niset* sa, + const amdknset* src, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t result; + + + idxbegin = src->vbegin.ptr.p_int[k]; + idxend = idxbegin+src->vcnt.ptr.p_int[k]; + result = 0; + while(idxbeginlocationof.ptr.p_int[src->data.ptr.p_int[idxbegin]]>=0 ) + { + result = result+1; + } + idxbegin = idxbegin+1; + } + return result; +} + + +/************************************************************************* +Compresses internal storage, reclaiming previously dropped blocks. To be +used internally by kn-set modification functions. + +INPUT PARAMETERS + SA - kn-set to compress + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knscompressstorage(amdknset* sa, ae_state *_state) +{ + ae_int_t i; + ae_int_t blocklen; + ae_int_t setidx; + ae_int_t srcoffs; + ae_int_t dstoffs; + + + srcoffs = 0; + dstoffs = 0; + while(srcoffsdataused) + { + blocklen = sa->data.ptr.p_int[srcoffs+0]; + setidx = sa->data.ptr.p_int[srcoffs+1]; + ae_assert(blocklen>=amdordering_knsheadersize, "knsCompressStorage: integrity check 6385 failed", _state); + if( setidx<0 ) + { + srcoffs = srcoffs+blocklen; + continue; + } + if( srcoffs!=dstoffs ) + { + for(i=0; i<=blocklen-1; i++) + { + sa->data.ptr.p_int[dstoffs+i] = sa->data.ptr.p_int[srcoffs+i]; + } + sa->vbegin.ptr.p_int[setidx] = dstoffs+amdordering_knsheadersize; + } + dstoffs = dstoffs+blocklen; + srcoffs = srcoffs+blocklen; + } + ae_assert(srcoffs==sa->dataused, "knsCompressStorage: integrity check 9464 failed", _state); + sa->dataused = dstoffs; +} + + +/************************************************************************* +Reallocates internal storage for set #SetIdx, increasing its capacity to +NewAllocated exactly. This function may invalidate internal pointers for +ALL sets in the kn-set structure because it may perform storage +compression in order to reclaim previously freed space. + +INPUT PARAMETERS + SA - kn-set structure + SetIdx - set to reallocate + NewAllocated - new size for the set, must be at least equal to already + allocated + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsreallocate(amdknset* sa, + ae_int_t setidx, + ae_int_t newallocated, + ae_state *_state) +{ + ae_int_t oldbegin; + ae_int_t oldcnt; + ae_int_t newbegin; + ae_int_t j; + + + if( sa->data.cntdataused+amdordering_knsheadersize+newallocated ) + { + amdordering_knscompressstorage(sa, _state); + if( sa->data.cntdataused+amdordering_knsheadersize+newallocated ) + { + ivectorgrowto(&sa->data, sa->dataused+amdordering_knsheadersize+newallocated, _state); + } + } + oldbegin = sa->vbegin.ptr.p_int[setidx]; + oldcnt = sa->vcnt.ptr.p_int[setidx]; + newbegin = sa->dataused+amdordering_knsheadersize; + sa->vbegin.ptr.p_int[setidx] = newbegin; + sa->vallocated.ptr.p_int[setidx] = newallocated; + sa->data.ptr.p_int[oldbegin-1] = -1; + sa->data.ptr.p_int[newbegin-2] = amdordering_knsheadersize+newallocated; + sa->data.ptr.p_int[newbegin-1] = setidx; + sa->dataused = sa->dataused+sa->data.ptr.p_int[newbegin-2]; + for(j=0; j<=oldcnt-1; j++) + { + sa->data.ptr.p_int[newbegin+j] = sa->data.ptr.p_int[oldbegin+j]; + } +} + + +/************************************************************************* +Initialize kn-set + +INPUT PARAMETERS + K - sets count + N - set size + kPrealloc - preallocate place per set (can be zero) + +OUTPUT PARAMETERS + SA - K sets of N elements, initially empty + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsinit(ae_int_t k, + ae_int_t n, + ae_int_t kprealloc, + amdknset* sa, + ae_state *_state) +{ + ae_int_t i; + + + sa->k = k; + sa->n = n; + isetallocv(n, -1, &sa->flagarray, _state); + isetallocv(n, kprealloc, &sa->vallocated, _state); + ivectorsetlengthatleast(&sa->vbegin, n, _state); + sa->vbegin.ptr.p_int[0] = amdordering_knsheadersize; + for(i=1; i<=n-1; i++) + { + sa->vbegin.ptr.p_int[i] = sa->vbegin.ptr.p_int[i-1]+sa->vallocated.ptr.p_int[i-1]+amdordering_knsheadersize; + } + sa->dataused = sa->vbegin.ptr.p_int[n-1]+sa->vallocated.ptr.p_int[n-1]; + ivectorsetlengthatleast(&sa->data, sa->dataused, _state); + for(i=0; i<=n-1; i++) + { + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-2] = amdordering_knsheadersize+sa->vallocated.ptr.p_int[i]; + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-1] = i; + } + isetallocv(n, 0, &sa->vcnt, _state); +} + + +/************************************************************************* +Initialize kn-set from lower triangle of symmetric A + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format + N - problem size + IgnoreDiagonal- if True, diagonal elements are not included into kn-set + +OUTPUT PARAMETERS + SA - N sets of N elements, reproducing both lower and upper + triangles of A + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsinitfroma(const sparsematrix* a, + ae_int_t n, + ae_bool ignorediagonal, + amdknset* sa, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + + sa->k = n; + sa->n = n; + isetallocv(n, -1, &sa->flagarray, _state); + ivectorsetlengthatleast(&sa->vallocated, n, _state); + for(i=0; i<=n-1; i++) + { + ae_assert(a->didx.ptr.p_int[i]uidx.ptr.p_int[i], "knsInitFromA: integrity check for diagonal of A failed", _state); + j0 = a->ridx.ptr.p_int[i]; + j1 = a->didx.ptr.p_int[i]-1; + sa->vallocated.ptr.p_int[i] = j1-j0+1; + if( !ignorediagonal ) + { + sa->vallocated.ptr.p_int[i] = sa->vallocated.ptr.p_int[i]+1; + } + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + sa->vallocated.ptr.p_int[j] = sa->vallocated.ptr.p_int[j]+1; + } + } + ivectorsetlengthatleast(&sa->vbegin, n, _state); + sa->vbegin.ptr.p_int[0] = amdordering_knsheadersize; + for(i=1; i<=n-1; i++) + { + sa->vbegin.ptr.p_int[i] = sa->vbegin.ptr.p_int[i-1]+sa->vallocated.ptr.p_int[i-1]+amdordering_knsheadersize; + } + sa->dataused = sa->vbegin.ptr.p_int[n-1]+sa->vallocated.ptr.p_int[n-1]; + ivectorsetlengthatleast(&sa->data, sa->dataused, _state); + for(i=0; i<=n-1; i++) + { + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-2] = amdordering_knsheadersize+sa->vallocated.ptr.p_int[i]; + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]-1] = i; + } + isetallocv(n, 0, &sa->vcnt, _state); + for(i=0; i<=n-1; i++) + { + if( !ignorediagonal ) + { + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]+sa->vcnt.ptr.p_int[i]] = i; + sa->vcnt.ptr.p_int[i] = sa->vcnt.ptr.p_int[i]+1; + } + j0 = a->ridx.ptr.p_int[i]; + j1 = a->didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]+sa->vcnt.ptr.p_int[i]] = j; + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[j]+sa->vcnt.ptr.p_int[j]] = i; + sa->vcnt.ptr.p_int[i] = sa->vcnt.ptr.p_int[i]+1; + sa->vcnt.ptr.p_int[j] = sa->vcnt.ptr.p_int[j]+1; + } + } +} + + +/************************************************************************* +Prepares iteration over I-th set + +INPUT PARAMETERS + SA - kn-set + I - set index + +OUTPUT PARAMETERS + SA - SA ready for repeated calls of knsEnumerate() + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsstartenumeration(amdknset* sa, + ae_int_t i, + ae_state *_state) +{ + + + sa->iterrow = i; + sa->iteridx = 0; +} + + +/************************************************************************* +Iterates over I-th set (as specified during recent knsStartEnumeration call). +Subsequent calls return True and set J to new set item until iteration +stops and False is returned. + +INPUT PARAMETERS + SA - kn-set + +OUTPUT PARAMETERS + J - if: + * Result=True - index of element in the set + * Result=False - not set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_bool amdordering_knsenumerate(amdknset* sa, + ae_int_t* i, + ae_state *_state) +{ + ae_bool result; + + *i = 0; + + if( sa->iteridxvcnt.ptr.p_int[sa->iterrow] ) + { + *i = sa->data.ptr.p_int[sa->vbegin.ptr.p_int[sa->iterrow]+sa->iteridx]; + sa->iteridx = sa->iteridx+1; + result = ae_true; + } + else + { + result = ae_false; + } + return result; +} + + +/************************************************************************* +Allows direct access to internal storage of kn-set structure - returns +range of elements SA.Data[idxBegin...idxEnd-1] used to store K-th set + +INPUT PARAMETERS + SA - kn-set + K - set index + +OUTPUT PARAMETERS + idxBegin, + idxEnd - half-range [idxBegin,idxEnd) of SA.Data that stores + K-th set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsdirectaccess(const amdknset* sa, + ae_int_t k, + ae_int_t* idxbegin, + ae_int_t* idxend, + ae_state *_state) +{ + + *idxbegin = 0; + *idxend = 0; + + *idxbegin = sa->vbegin.ptr.p_int[k]; + *idxend = *idxbegin+sa->vcnt.ptr.p_int[k]; +} + + +/************************************************************************* +Add K-th element to I-th set. The caller guarantees that the element is +not present in the target set. + +INPUT PARAMETERS + SA - kn-set + I - set index + K - element to add + +OUTPUT PARAMETERS + SA - modified SA + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsaddnewelement(amdknset* sa, + ae_int_t i, + ae_int_t k, + ae_state *_state) +{ + ae_int_t cnt; + + + cnt = sa->vcnt.ptr.p_int[i]; + if( cnt==sa->vallocated.ptr.p_int[i] ) + { + amdordering_knsreallocate(sa, i, 2*sa->vallocated.ptr.p_int[i]+1, _state); + } + sa->data.ptr.p_int[sa->vbegin.ptr.p_int[i]+cnt] = k; + sa->vcnt.ptr.p_int[i] = cnt+1; +} + + +/************************************************************************* +Subtracts source n-set from the I-th set of the destination kn-set. + +INPUT PARAMETERS + SA - destination kn-set structure + I - set index in the structure + Src - source n-set + +OUTPUT PARAMETERS + SA - I-th set except for elements in Src + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knssubtract1(amdknset* sa, + ae_int_t i, + const niset* src, + ae_state *_state) +{ + ae_int_t j; + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t cnt; + + + cnt = sa->vcnt.ptr.p_int[i]; + idxbegin = sa->vbegin.ptr.p_int[i]; + idxend = idxbegin+cnt; + while(idxbegindata.ptr.p_int[idxbegin]; + if( src->locationof.ptr.p_int[j]>=0 ) + { + sa->data.ptr.p_int[idxbegin] = sa->data.ptr.p_int[idxend-1]; + idxend = idxend-1; + cnt = cnt-1; + } + else + { + idxbegin = idxbegin+1; + } + } + sa->vcnt.ptr.p_int[i] = cnt; +} + + +/************************************************************************* +Adds Kth set of the source kn-set to the I-th destination set. The caller +guarantees that SA[I] and Src[J] do NOT intersect, i.e. do not have shared +elements - it allows to use faster algorithms. + +INPUT PARAMETERS + SA - destination kn-set structure + I - set index in the structure + Src - source kn-set + K - set index + +OUTPUT PARAMETERS + SA - I-th set plus for elements in K-th set of Src + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsaddkthdistinct(amdknset* sa, + ae_int_t i, + const amdknset* src, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxdst; + ae_int_t idxsrcbegin; + ae_int_t cnt; + ae_int_t srccnt; + ae_int_t j; + + + cnt = sa->vcnt.ptr.p_int[i]; + srccnt = src->vcnt.ptr.p_int[k]; + if( cnt+srccnt>sa->vallocated.ptr.p_int[i] ) + { + amdordering_knsreallocate(sa, i, 2*(cnt+srccnt)+1, _state); + } + idxsrcbegin = src->vbegin.ptr.p_int[k]; + idxdst = sa->vbegin.ptr.p_int[i]+cnt; + for(j=0; j<=srccnt-1; j++) + { + sa->data.ptr.p_int[idxdst] = src->data.ptr.p_int[idxsrcbegin+j]; + idxdst = idxdst+1; + } + sa->vcnt.ptr.p_int[i] = cnt+srccnt; +} + + +/************************************************************************* +Counts elements of K-th set of S0 + +INPUT PARAMETERS + S0 - kn-set structure + K - set index in the structure S0 + +RESULT + K-th set element count + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_knscountkth(const amdknset* s0, + ae_int_t k, + ae_state *_state) +{ + ae_int_t result; + + + result = s0->vcnt.ptr.p_int[k]; + return result; +} + + +/************************************************************************* +Counts elements of I-th set of S0 not present in S1 + +INPUT PARAMETERS + S0 - kn-set structure + I - set index in the structure S0 + S1 - kn-set to compare against + +RESULT + count + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_knscountnot(amdknset* s0, + ae_int_t i, + const niset* s1, + ae_state *_state) +{ + ae_int_t idxbegin0; + ae_int_t cnt0; + ae_int_t j; + ae_int_t result; + + + cnt0 = s0->vcnt.ptr.p_int[i]; + idxbegin0 = s0->vbegin.ptr.p_int[i]; + result = 0; + for(j=0; j<=cnt0-1; j++) + { + if( s1->locationof.ptr.p_int[s0->data.ptr.p_int[idxbegin0+j]]<0 ) + { + result = result+1; + } + } + return result; +} + + +/************************************************************************* +Counts elements of I-th set of S0 not present in K-th set of S1 + +INPUT PARAMETERS + S0 - kn-set structure + I - set index in the structure S0 + S1 - kn-set to compare against + K - set index in the structure S1 + +RESULT + count + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_knscountnotkth(amdknset* s0, + ae_int_t i, + const amdknset* s1, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin0; + ae_int_t idxbegin1; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t j; + ae_int_t result; + + + cnt0 = s0->vcnt.ptr.p_int[i]; + cnt1 = s1->vcnt.ptr.p_int[k]; + idxbegin0 = s0->vbegin.ptr.p_int[i]; + idxbegin1 = s1->vbegin.ptr.p_int[k]; + for(j=0; j<=cnt1-1; j++) + { + s0->flagarray.ptr.p_int[s1->data.ptr.p_int[idxbegin1+j]] = 1; + } + result = 0; + for(j=0; j<=cnt0-1; j++) + { + if( s0->flagarray.ptr.p_int[s0->data.ptr.p_int[idxbegin0+j]]<0 ) + { + result = result+1; + } + } + for(j=0; j<=cnt1-1; j++) + { + s0->flagarray.ptr.p_int[s1->data.ptr.p_int[idxbegin1+j]] = -1; + } + return result; +} + + +/************************************************************************* +Counts elements of I-th set of S0 that are also present in K-th set of S1 + +INPUT PARAMETERS + S0 - kn-set structure + I - set index in the structure S0 + S1 - kn-set to compare against + K - set index in the structure S1 + +RESULT + count + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_knscountandkth(amdknset* s0, + ae_int_t i, + const amdknset* s1, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin0; + ae_int_t idxbegin1; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t j; + ae_int_t result; + + + cnt0 = s0->vcnt.ptr.p_int[i]; + cnt1 = s1->vcnt.ptr.p_int[k]; + idxbegin0 = s0->vbegin.ptr.p_int[i]; + idxbegin1 = s1->vbegin.ptr.p_int[k]; + for(j=0; j<=cnt1-1; j++) + { + s0->flagarray.ptr.p_int[s1->data.ptr.p_int[idxbegin1+j]] = 1; + } + result = 0; + for(j=0; j<=cnt0-1; j++) + { + if( s0->flagarray.ptr.p_int[s0->data.ptr.p_int[idxbegin0+j]]>0 ) + { + result = result+1; + } + } + for(j=0; j<=cnt1-1; j++) + { + s0->flagarray.ptr.p_int[s1->data.ptr.p_int[idxbegin1+j]] = -1; + } + return result; +} + + +/************************************************************************* +Sums elements in I-th set of S0, returns sum. + +INPUT PARAMETERS + S0 - kn-set structure + I - set index in the structure S0 + +RESULT + sum + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_knssumkth(const amdknset* s0, + ae_int_t i, + ae_state *_state) +{ + ae_int_t idxbegin0; + ae_int_t cnt0; + ae_int_t j; + ae_int_t result; + + + cnt0 = s0->vcnt.ptr.p_int[i]; + idxbegin0 = s0->vbegin.ptr.p_int[i]; + result = 0; + for(j=0; j<=cnt0-1; j++) + { + result = result+s0->data.ptr.p_int[idxbegin0+j]; + } + return result; +} + + +/************************************************************************* +Clear k-th kn-set in collection. + +Freed memory is NOT reclaimed for future garbage collection. + +INPUT PARAMETERS + SA - kn-set structure + K - set index + +OUTPUT PARAMETERS + SA - K-th set was cleared + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsclearkthnoreclaim(amdknset* sa, + ae_int_t k, + ae_state *_state) +{ + + + sa->vcnt.ptr.p_int[k] = 0; +} + + +/************************************************************************* +Clear k-th kn-set in collection. + +Freed memory is reclaimed for future garbage collection. This function is +NOT recommended if you intend to add elements to this set in some future, +because every addition will result in reallocation of previously freed +memory. Use knsClearKthNoReclaim(). + +INPUT PARAMETERS + SA - kn-set structure + K - set index + +OUTPUT PARAMETERS + SA - K-th set was cleared + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_knsclearkthreclaim(amdknset* sa, + ae_int_t k, + ae_state *_state) +{ + ae_int_t idxbegin; + ae_int_t allocated; + + + idxbegin = sa->vbegin.ptr.p_int[k]; + allocated = sa->vallocated.ptr.p_int[k]; + sa->vcnt.ptr.p_int[k] = 0; + if( allocated>=amdordering_knsheadersize ) + { + sa->data.ptr.p_int[idxbegin-2] = 2; + sa->data.ptr.p_int[idxbegin+0] = allocated; + sa->data.ptr.p_int[idxbegin+1] = -1; + sa->vallocated.ptr.p_int[k] = 0; + } +} + + +/************************************************************************* +Initialize linked list matrix + +INPUT PARAMETERS + N - matrix size + +OUTPUT PARAMETERS + A - NxN linked list matrix + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxinit(ae_int_t n, + amdllmatrix* a, + ae_state *_state) +{ + + + a->n = n; + isetallocv(2*n+1, -1, &a->vbegin, _state); + isetallocv(n, 0, &a->vcolcnt, _state); + a->entriesinitialized = 0; +} + + +/************************************************************************* +Adds column from matrix to n-set + +INPUT PARAMETERS + A - NxN linked list matrix + J - column index to add + S - target n-set + +OUTPUT PARAMETERS + S - elements from J-th column are added to S + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxaddcolumnto(const amdllmatrix* a, + ae_int_t j, + niset* s, + ae_state *_state) +{ + ae_int_t n; + ae_int_t eidx; + + + n = a->n; + eidx = a->vbegin.ptr.p_int[n+j]; + while(eidx>=0) + { + nisaddelement(s, a->entries.ptr.p_int[eidx*amdordering_llmentrysize+4], _state); + eidx = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+3]; + } +} + + +/************************************************************************* +Inserts new element into column J, row I. The caller guarantees that the +element being inserted is NOT already present in the matrix. + +INPUT PARAMETERS + A - NxN linked list matrix + I - row index + J - column index + +OUTPUT PARAMETERS + A - element (I,J) added to the list. + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxinsertnewelement(amdllmatrix* a, + ae_int_t i, + ae_int_t j, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t newsize; + ae_int_t eidx; + ae_int_t offs; + + + n = a->n; + if( a->vbegin.ptr.p_int[2*n]<0 ) + { + newsize = 2*a->entriesinitialized+1; + ivectorresize(&a->entries, newsize*amdordering_llmentrysize, _state); + for(k=a->entriesinitialized; k<=newsize-2; k++) + { + a->entries.ptr.p_int[k*amdordering_llmentrysize+0] = k+1; + } + a->entries.ptr.p_int[(newsize-1)*amdordering_llmentrysize+0] = a->vbegin.ptr.p_int[2*n]; + a->vbegin.ptr.p_int[2*n] = a->entriesinitialized; + a->entriesinitialized = newsize; + } + eidx = a->vbegin.ptr.p_int[2*n]; + offs = eidx*amdordering_llmentrysize; + a->vbegin.ptr.p_int[2*n] = a->entries.ptr.p_int[offs+0]; + a->entries.ptr.p_int[offs+0] = -1; + a->entries.ptr.p_int[offs+1] = a->vbegin.ptr.p_int[i]; + if( a->vbegin.ptr.p_int[i]>=0 ) + { + a->entries.ptr.p_int[a->vbegin.ptr.p_int[i]*amdordering_llmentrysize+0] = eidx; + } + a->entries.ptr.p_int[offs+2] = -1; + a->entries.ptr.p_int[offs+3] = a->vbegin.ptr.p_int[j+n]; + if( a->vbegin.ptr.p_int[j+n]>=0 ) + { + a->entries.ptr.p_int[a->vbegin.ptr.p_int[j+n]*amdordering_llmentrysize+2] = eidx; + } + a->entries.ptr.p_int[offs+4] = i; + a->entries.ptr.p_int[offs+5] = j; + a->vbegin.ptr.p_int[i] = eidx; + a->vbegin.ptr.p_int[j+n] = eidx; + a->vcolcnt.ptr.p_int[j] = a->vcolcnt.ptr.p_int[j]+1; +} + + +/************************************************************************* +Counts elements in J-th column that are not present in n-set S + +INPUT PARAMETERS + A - NxN linked list matrix + J - column index + S - n-set to compare against + +RESULT + element count + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_mtxcountcolumnnot(const amdllmatrix* a, + ae_int_t j, + const niset* s, + ae_state *_state) +{ + ae_int_t n; + ae_int_t eidx; + ae_int_t result; + + + n = a->n; + result = 0; + eidx = a->vbegin.ptr.p_int[n+j]; + while(eidx>=0) + { + if( s->locationof.ptr.p_int[a->entries.ptr.p_int[eidx*amdordering_llmentrysize+4]]<0 ) + { + result = result+1; + } + eidx = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+3]; + } + return result; +} + + +/************************************************************************* +Counts elements in J-th column + +INPUT PARAMETERS + A - NxN linked list matrix + J - column index + +RESULT + element count + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_mtxcountcolumn(const amdllmatrix* a, + ae_int_t j, + ae_state *_state) +{ + ae_int_t result; + + + result = a->vcolcnt.ptr.p_int[j]; + return result; +} + + +/************************************************************************* +Clears K-th column or row + +INPUT PARAMETERS + A - NxN linked list matrix + K - column/row index to clear + IsCol - whether we want to clear row or column + +OUTPUT PARAMETERS + A - K-th column or row is empty + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxclearx(amdllmatrix* a, + ae_int_t k, + ae_bool iscol, + ae_state *_state) +{ + ae_int_t n; + ae_int_t eidx; + ae_int_t enext; + ae_int_t idxprev; + ae_int_t idxnext; + ae_int_t idxr; + ae_int_t idxc; + + + n = a->n; + if( iscol ) + { + eidx = a->vbegin.ptr.p_int[n+k]; + } + else + { + eidx = a->vbegin.ptr.p_int[k]; + } + while(eidx>=0) + { + idxr = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+4]; + idxc = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+5]; + if( iscol ) + { + enext = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+3]; + } + else + { + enext = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+1]; + } + idxprev = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+0]; + idxnext = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+1]; + if( idxprev>=0 ) + { + a->entries.ptr.p_int[idxprev*amdordering_llmentrysize+1] = idxnext; + } + else + { + a->vbegin.ptr.p_int[idxr] = idxnext; + } + if( idxnext>=0 ) + { + a->entries.ptr.p_int[idxnext*amdordering_llmentrysize+0] = idxprev; + } + idxprev = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+2]; + idxnext = a->entries.ptr.p_int[eidx*amdordering_llmentrysize+3]; + if( idxprev>=0 ) + { + a->entries.ptr.p_int[idxprev*amdordering_llmentrysize+3] = idxnext; + } + else + { + a->vbegin.ptr.p_int[idxc+n] = idxnext; + } + if( idxnext>=0 ) + { + a->entries.ptr.p_int[idxnext*amdordering_llmentrysize+2] = idxprev; + } + a->entries.ptr.p_int[eidx*amdordering_llmentrysize+0] = a->vbegin.ptr.p_int[2*n]; + a->vbegin.ptr.p_int[2*n] = eidx; + eidx = enext; + if( !iscol ) + { + a->vcolcnt.ptr.p_int[idxc] = a->vcolcnt.ptr.p_int[idxc]-1; + } + } + if( iscol ) + { + a->vcolcnt.ptr.p_int[k] = 0; + } +} + + +/************************************************************************* +Clears J-th column + +INPUT PARAMETERS + A - NxN linked list matrix + J - column index to clear + +OUTPUT PARAMETERS + A - J-th column is empty + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxclearcolumn(amdllmatrix* a, + ae_int_t j, + ae_state *_state) +{ + + + amdordering_mtxclearx(a, j, ae_true, _state); +} + + +/************************************************************************* +Clears J-th row + +INPUT PARAMETERS + A - NxN linked list matrix + J - row index to clear + +OUTPUT PARAMETERS + A - J-th row is empty + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_mtxclearrow(amdllmatrix* a, + ae_int_t j, + ae_state *_state) +{ + + + amdordering_mtxclearx(a, j, ae_false, _state); +} + + +/************************************************************************* +Initialize vertex storage using A to estimate initial degrees + +INPUT PARAMETERS + A - NxN lower triangular sparse CRS matrix + N - problem size + Eligible - array[N], only eligible vertices can be extracted + with vtxGetApproxMinDegree() + HasEligible - if False, Eligible is ignored + CheckExactDegrees- + whether we want to maintain additional exact degress + (the search is still done using approximate ones) + +OUTPUT PARAMETERS + S - vertex set + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_vtxinit(const sparsematrix* a, + ae_int_t n, + /* Boolean */ const ae_vector* eligible, + ae_bool haseligible, + ae_bool checkexactdegrees, + amdvertexset* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + _amdvertexset_clear(s); + + s->n = n; + s->checkexactdegrees = checkexactdegrees; + s->smallestdegree = 0; + bsetallocv(n, ae_true, &s->isvertex, _state); + if( haseligible ) + { + bcopyallocv(n, eligible, &s->eligible, _state); + } + else + { + bsetallocv(n, ae_true, &s->eligible, _state); + } + isetallocv(n, 0, &s->approxd, _state); + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->didx.ptr.p_int[i]-1; + s->approxd.ptr.p_int[i] = j1-j0+1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + s->approxd.ptr.p_int[j] = s->approxd.ptr.p_int[j]+1; + } + } + if( checkexactdegrees ) + { + icopyallocv(n, &s->approxd, &s->optionalexactd, _state); + } + isetallocv(n, -1, &s->vbegin, _state); + isetallocv(n, -1, &s->vprev, _state); + isetallocv(n, -1, &s->vnext, _state); + for(i=0; i<=n-1; i++) + { + if( s->eligible.ptr.p_bool[i] ) + { + j = s->approxd.ptr.p_int[i]; + j0 = s->vbegin.ptr.p_int[j]; + s->vbegin.ptr.p_int[j] = i; + s->vnext.ptr.p_int[i] = j0; + s->vprev.ptr.p_int[i] = -1; + if( j0>=0 ) + { + s->vprev.ptr.p_int[j0] = i; + } + } + } +} + + +/************************************************************************* +Removes vertex from the storage + +INPUT PARAMETERS + S - vertex set + P - vertex to be removed + +OUTPUT PARAMETERS + S - modified + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_vtxremovevertex(amdvertexset* s, + ae_int_t p, + ae_state *_state) +{ + ae_int_t d; + ae_int_t idxprev; + ae_int_t idxnext; + + + ae_assert(s->isvertex.ptr.p_bool[p], "AMD: trying to remove already removed vertex", _state); + if( s->eligible.ptr.p_bool[p] ) + { + d = s->approxd.ptr.p_int[p]; + idxprev = s->vprev.ptr.p_int[p]; + idxnext = s->vnext.ptr.p_int[p]; + if( idxprev>=0 ) + { + s->vnext.ptr.p_int[idxprev] = idxnext; + } + else + { + s->vbegin.ptr.p_int[d] = idxnext; + } + if( idxnext>=0 ) + { + s->vprev.ptr.p_int[idxnext] = idxprev; + } + } + s->eligible.ptr.p_bool[p] = ae_false; + s->isvertex.ptr.p_bool[p] = ae_false; + s->approxd.ptr.p_int[p] = -9999999; + if( s->checkexactdegrees ) + { + s->optionalexactd.ptr.p_int[p] = -9999999; + } +} + + +/************************************************************************* +Get approximate degree. + +Fails for removed or non-eligible vertexes. + +INPUT PARAMETERS + S - vertex set + P - vertex index + +RESULT + vertex degree + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_vtxgetapprox(const amdvertexset* s, + ae_int_t p, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(s->isvertex.ptr.p_bool[p], "AMD: trying to call vtxGetApprox() for removed vertex", _state); + result = s->approxd.ptr.p_int[p]; + return result; +} + + +/************************************************************************* +Get exact degree (or 0, if not supported). Result is undefined for +removed vertexes. + +INPUT PARAMETERS + S - vertex set + P - vertex index + +RESULT + vertex degree + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_vtxgetexact(const amdvertexset* s, + ae_int_t p, + ae_state *_state) +{ + ae_int_t result; + + + if( s->checkexactdegrees ) + { + result = s->optionalexactd.ptr.p_int[p]; + } + else + { + result = 0; + } + return result; +} + + +/************************************************************************* +Returns index of vertex with minimum approximate degree, or -1 when there +is no vertex. + +INPUT PARAMETERS + S - vertex set + +RESULT + vertex index, or -1 + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static ae_int_t amdordering_vtxgetapproxmindegree(amdvertexset* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t result; + + + n = s->n; + result = -1; + for(i=s->smallestdegree; i<=n-1; i++) + { + if( s->vbegin.ptr.p_int[i]>=0 ) + { + s->smallestdegree = i; + result = s->vbegin.ptr.p_int[i]; + return result; + } + } + return result; +} + + +/************************************************************************* +Update approximate degree + +INPUT PARAMETERS + S - vertex set + P - vertex to be updated + DNew - new degree + +OUTPUT PARAMETERS + S - modified + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_vtxupdateapproximatedegree(amdvertexset* s, + ae_int_t p, + ae_int_t dnew, + ae_state *_state) +{ + ae_int_t dold; + ae_int_t idxprev; + ae_int_t idxnext; + ae_int_t oldbegin; + + + ae_assert(s->isvertex.ptr.p_bool[p], "AMD: trying to call vtxUpdateApproximateDegree() for removed vertex", _state); + dold = s->approxd.ptr.p_int[p]; + if( dold==dnew ) + { + return; + } + s->approxd.ptr.p_int[p] = dnew; + if( s->eligible.ptr.p_bool[p] ) + { + idxprev = s->vprev.ptr.p_int[p]; + idxnext = s->vnext.ptr.p_int[p]; + if( idxprev>=0 ) + { + s->vnext.ptr.p_int[idxprev] = idxnext; + } + else + { + s->vbegin.ptr.p_int[dold] = idxnext; + } + if( idxnext>=0 ) + { + s->vprev.ptr.p_int[idxnext] = idxprev; + } + oldbegin = s->vbegin.ptr.p_int[dnew]; + s->vbegin.ptr.p_int[dnew] = p; + s->vnext.ptr.p_int[p] = oldbegin; + s->vprev.ptr.p_int[p] = -1; + if( oldbegin>=0 ) + { + s->vprev.ptr.p_int[oldbegin] = p; + } + if( dnewsmallestdegree ) + { + s->smallestdegree = dnew; + } + } +} + + +/************************************************************************* +Update optional exact degree. Silently returns if vertex set does not store +exact degrees. + +INPUT PARAMETERS + S - vertex set + P - vertex to be updated + D - new degree + +OUTPUT PARAMETERS + S - modified + + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_vtxupdateexactdegree(amdvertexset* s, + ae_int_t p, + ae_int_t d, + ae_state *_state) +{ + + + if( !s->checkexactdegrees ) + { + return; + } + s->optionalexactd.ptr.p_int[p] = d; +} + + +/************************************************************************* +This function selects K-th pivot with minimum approximate degree and +generates permutation that reorders variable to the K-th position in the +matrix. + +Due to supernodal structure of the matrix more than one pivot variable can +be selected and moved to the beginning. The actual count of pivots selected +is returned in NodeSize. + +INPUT PARAMETERS + Buf - properly initialized buffer object + K - pivot index + +OUTPUT PARAMETERS + Buf.Perm - entries [K,K+NodeSize) are initialized by permutation + Buf.InvPerm - entries [K,K+NodeSize) are initialized by permutation + Buf.ColumnSwaps-entries [K,K+NodeSize) are initialized by permutation + P - pivot supervariable + NodeSize - supernode size + +If P<0, then we exhausted all eligible vertices, nothing is returned. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_amdselectpivotelement(amdbuffer* buf, + ae_int_t k, + ae_int_t* p, + ae_int_t* nodesize, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + *p = 0; + *nodesize = 0; + + *p = amdordering_vtxgetapproxmindegree(&buf->vertexdegrees, _state); + if( *p<0 ) + { + return; + } + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, *p, _state)>=0, "integrity check RDFD2 failed", _state); + *nodesize = 0; + amdordering_knsstartenumeration(&buf->setsuper, *p, _state); + while(amdordering_knsenumerate(&buf->setsuper, &j, _state)) + { + i = buf->perm.ptr.p_int[j]; + buf->columnswaps.ptr.p_int[k+(*nodesize)] = i; + buf->invperm.ptr.p_int[i] = buf->invperm.ptr.p_int[k+(*nodesize)]; + buf->invperm.ptr.p_int[k+(*nodesize)] = j; + buf->perm.ptr.p_int[buf->invperm.ptr.p_int[i]] = i; + buf->perm.ptr.p_int[buf->invperm.ptr.p_int[k+(*nodesize)]] = k+(*nodesize); + inc(nodesize, _state); + } + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, *p, _state)>=0&&(!buf->checkexactdegrees||amdordering_vtxgetexact(&buf->vertexdegrees, *p, _state)>=0), "AMD: integrity check RDFD failed", _state); +} + + +/************************************************************************* +This function computes nonzero pattern of Lp, the column that is added to +the lower triangular Cholesky factor. + +INPUT PARAMETERS + Buf - properly initialized buffer object + P - pivot column + +OUTPUT PARAMETERS + Buf.setP - initialized with setSuper[P] + Buf.Lp - initialized with Lp\P + Buf.setRp - initialized with Lp\{P+Q} + Buf.Ep - initialized with setE[P] + Buf.mtxL - L := L+Lp + Buf.Ls - first Buf.LSCnt elements contain subset of Lp elements + that are principal nodes in supervariables. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_amdcomputelp(amdbuffer* buf, + ae_int_t p, + ae_state *_state) +{ + ae_int_t i; + + + nisclear(&buf->setp, _state); + amdordering_nsaddkth(&buf->setp, &buf->setsuper, p, _state); + nisclear(&buf->lp, _state); + amdordering_nsaddkth(&buf->lp, &buf->seta, p, _state); + amdordering_knsstartenumeration(&buf->sete, p, _state); + while(amdordering_knsenumerate(&buf->sete, &i, _state)) + { + amdordering_mtxaddcolumnto(&buf->mtxl, i, &buf->lp, _state); + } + amdordering_nssubtractkth(&buf->lp, &buf->setsuper, p, _state); + niscopy(&buf->lp, &buf->setrp, _state); + nissubtract1(&buf->setrp, &buf->setq, _state); + buf->lscnt = 0; + nisstartenumeration(&buf->lp, _state); + while(nisenumerate(&buf->lp, &i, _state)) + { + ae_assert(!buf->iseliminated.ptr.p_bool[i], "AMD: integrity check 0740 failed", _state); + amdordering_mtxinsertnewelement(&buf->mtxl, i, p, _state); + if( buf->issupernode.ptr.p_bool[i] ) + { + buf->ls.ptr.p_int[buf->lscnt] = i; + buf->lscnt = buf->lscnt+1; + } + } + nisclear(&buf->ep, _state); + amdordering_nsaddkth(&buf->ep, &buf->sete, p, _state); +} + + +/************************************************************************* +Having output of AMDComputeLp() in the Buf object, this function performs +mass elimination in the quotient graph. + +INPUT PARAMETERS + Buf - properly initialized buffer object + P - pivot column + K - number of already eliminated columns (P-th is not counted) + Tau - variables with degrees higher than Tau will be classified + as quasidense + +OUTPUT PARAMETERS + Buf.setA - Lp is eliminated from setA + Buf.setE - Ep is eliminated from setE, P is added + approxD - updated + Buf.setQSuperCand- contains candidates for quasidense status assignment + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_amdmasselimination(amdbuffer* buf, + ae_int_t p, + ae_int_t k, + ae_int_t tau, + ae_state *_state) +{ + ae_int_t n; + ae_int_t lidx; + ae_int_t lpi; + ae_int_t cntsuperi; + ae_int_t cntq; + ae_int_t cntainoti; + ae_int_t cntainotqi; + ae_int_t cntlpnoti; + ae_int_t cntlpnotqi; + ae_int_t cc; + ae_int_t j; + ae_int_t e; + ae_int_t we; + ae_int_t cnttoclean; + ae_int_t idxbegin; + ae_int_t idxend; + ae_int_t jj; + ae_int_t bnd0; + ae_int_t bnd1; + ae_int_t bnd2; + ae_int_t d; + + + n = buf->n; + ivectorsetlengthatleast(&buf->tmp0, n, _state); + cnttoclean = 0; + for(lidx=0; lidx<=buf->lscnt-1; lidx++) + { + if( buf->setq.locationof.ptr.p_int[buf->ls.ptr.p_int[lidx]]<0 ) + { + lpi = buf->ls.ptr.p_int[lidx]; + cntsuperi = amdordering_knscountkth(&buf->setsuper, lpi, _state); + amdordering_knsdirectaccess(&buf->sete, lpi, &idxbegin, &idxend, _state); + for(jj=idxbegin; jj<=idxend-1; jj++) + { + e = buf->sete.data.ptr.p_int[jj]; + we = buf->arrwe.ptr.p_int[e]; + if( we<0 ) + { + we = amdordering_mtxcountcolumnnot(&buf->mtxl, e, &buf->setq, _state); + buf->tmp0.ptr.p_int[cnttoclean] = e; + cnttoclean = cnttoclean+1; + } + buf->arrwe.ptr.p_int[e] = we-cntsuperi; + } + } + } + nisclear(&buf->setqsupercand, _state); + for(lidx=0; lidx<=buf->lscnt-1; lidx++) + { + if( buf->setq.locationof.ptr.p_int[buf->ls.ptr.p_int[lidx]]<0 ) + { + lpi = buf->ls.ptr.p_int[lidx]; + amdordering_knssubtract1(&buf->seta, lpi, &buf->lp, _state); + amdordering_knssubtract1(&buf->seta, lpi, &buf->setp, _state); + amdordering_knssubtract1(&buf->sete, lpi, &buf->ep, _state); + amdordering_knsaddnewelement(&buf->sete, lpi, p, _state); + if( buf->extendeddebug ) + { + ae_assert(amdordering_knscountnotkth(&buf->seta, lpi, &buf->setsuper, lpi, _state)==amdordering_knscountkth(&buf->seta, lpi, _state), "AMD: integrity check 454F failed", _state); + ae_assert(amdordering_knscountandkth(&buf->seta, lpi, &buf->setsuper, lpi, _state)==0, "AMD: integrity check kl5nv failed", _state); + ae_assert(amdordering_nscountandkth(&buf->lp, &buf->setsuper, lpi, _state)==amdordering_knscountkth(&buf->setsuper, lpi, _state), "AMD: integrity check 8463 failed", _state); + } + cntq = niscount(&buf->setq, _state); + cntsuperi = amdordering_knscountkth(&buf->setsuper, lpi, _state); + cntainoti = amdordering_knscountkth(&buf->seta, lpi, _state); + if( cntq>0 ) + { + cntainotqi = amdordering_knscountnot(&buf->seta, lpi, &buf->setq, _state); + } + else + { + cntainotqi = cntainoti; + } + cntlpnoti = niscount(&buf->lp, _state)-cntsuperi; + cntlpnotqi = niscount(&buf->setrp, _state)-cntsuperi; + cc = 0; + amdordering_knsdirectaccess(&buf->sete, lpi, &idxbegin, &idxend, _state); + for(jj=idxbegin; jj<=idxend-1; jj++) + { + j = buf->sete.data.ptr.p_int[jj]; + if( j==p ) + { + continue; + } + e = buf->arrwe.ptr.p_int[j]; + if( e<0 ) + { + if( cntq>0 ) + { + e = amdordering_mtxcountcolumnnot(&buf->mtxl, j, &buf->setq, _state); + } + else + { + e = amdordering_mtxcountcolumn(&buf->mtxl, j, _state); + } + } + cc = cc+e; + } + bnd0 = n-k-niscount(&buf->setp, _state); + bnd1 = amdordering_vtxgetapprox(&buf->vertexdegrees, lpi, _state)+cntlpnoti; + bnd2 = cntq+cntainotqi+cntlpnotqi+cc; + d = imin3(bnd0, bnd1, bnd2, _state); + amdordering_vtxupdateapproximatedegree(&buf->vertexdegrees, lpi, d, _state); + if( tau>0&&d+cntsuperi>tau ) + { + nisaddelement(&buf->setqsupercand, lpi, _state); + } + if( buf->checkexactdegrees ) + { + nisclear(&buf->exactdegreetmp0, _state); + amdordering_knsstartenumeration(&buf->sete, lpi, _state); + while(amdordering_knsenumerate(&buf->sete, &j, _state)) + { + amdordering_mtxaddcolumnto(&buf->mtxl, j, &buf->exactdegreetmp0, _state); + } + amdordering_vtxupdateexactdegree(&buf->vertexdegrees, lpi, cntainoti+amdordering_nscountnotkth(&buf->exactdegreetmp0, &buf->setsuper, lpi, _state), _state); + ae_assert((amdordering_knscountkth(&buf->sete, lpi, _state)>2||cntq>0)||amdordering_vtxgetapprox(&buf->vertexdegrees, lpi, _state)==amdordering_vtxgetexact(&buf->vertexdegrees, lpi, _state), "AMD: integrity check 7206 failed", _state); + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, lpi, _state)>=amdordering_vtxgetexact(&buf->vertexdegrees, lpi, _state), "AMD: integrity check 8206 failed", _state); + } + } + } + for(j=0; j<=cnttoclean-1; j++) + { + buf->arrwe.ptr.p_int[buf->tmp0.ptr.p_int[j]] = -1; + } +} + + +/************************************************************************* +After mass elimination, but before removal of vertex P, we may perform +supernode detection. Only variables/supernodes in Lp (P itself is NOT +included) can be merged into larger supernodes. + +INPUT PARAMETERS + Buf - properly initialized buffer object + +OUTPUT PARAMETERS + Buf - following fields of Buf may be modified: + * Buf.setSuper + * Buf.setA + * Buf.setE + * Buf.IsSupernode + * ApproxD and ExactD + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_amddetectsupernodes(amdbuffer* buf, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t cnt; + ae_int_t lpi; + ae_int_t lpj; + ae_int_t nj; + ae_int_t hashi; + + + n = buf->n; + ivectorsetlengthatleast(&buf->sncandidates, n, _state); + if( buf->lscnt<2 ) + { + return; + } + for(i=0; i<=buf->lscnt-1; i++) + { + if( buf->setq.locationof.ptr.p_int[buf->ls.ptr.p_int[i]]<0 ) + { + lpi = buf->ls.ptr.p_int[i]; + hashi = (amdordering_knssumkth(&buf->seta, lpi, _state)+amdordering_knssumkth(&buf->sete, lpi, _state))%n; + nisaddelement(&buf->nonemptybuckets, hashi, _state); + amdordering_knsaddnewelement(&buf->hashbuckets, hashi, lpi, _state); + } + } + nisstartenumeration(&buf->nonemptybuckets, _state); + while(nisenumerate(&buf->nonemptybuckets, &hashi, _state)) + { + if( amdordering_knscountkth(&buf->hashbuckets, hashi, _state)>=2 ) + { + cnt = 0; + amdordering_knsstartenumeration(&buf->hashbuckets, hashi, _state); + while(amdordering_knsenumerate(&buf->hashbuckets, &i, _state)) + { + buf->sncandidates.ptr.p_int[cnt] = i; + cnt = cnt+1; + } + for(i=cnt-1; i>=0; i--) + { + for(j=cnt-1; j>=i+1; j--) + { + if( buf->issupernode.ptr.p_bool[buf->sncandidates.ptr.p_int[i]]&&buf->issupernode.ptr.p_bool[buf->sncandidates.ptr.p_int[j]] ) + { + lpi = buf->sncandidates.ptr.p_int[i]; + lpj = buf->sncandidates.ptr.p_int[j]; + if( buf->iseligible.ptr.p_bool[buf->sncandidates.ptr.p_int[i]]&&!buf->iseligible.ptr.p_bool[buf->sncandidates.ptr.p_int[j]] ) + { + continue; + } + if( !buf->iseligible.ptr.p_bool[buf->sncandidates.ptr.p_int[i]]&&buf->iseligible.ptr.p_bool[buf->sncandidates.ptr.p_int[j]] ) + { + continue; + } + nisclear(&buf->adji, _state); + nisclear(&buf->adjj, _state); + amdordering_nsaddkth(&buf->adji, &buf->seta, lpi, _state); + amdordering_nsaddkth(&buf->adjj, &buf->seta, lpj, _state); + amdordering_nsaddkth(&buf->adji, &buf->sete, lpi, _state); + amdordering_nsaddkth(&buf->adjj, &buf->sete, lpj, _state); + nisaddelement(&buf->adji, lpi, _state); + nisaddelement(&buf->adji, lpj, _state); + nisaddelement(&buf->adjj, lpi, _state); + nisaddelement(&buf->adjj, lpj, _state); + if( !nisequal(&buf->adji, &buf->adjj, _state) ) + { + continue; + } + if( buf->extendeddebug ) + { + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, lpi, _state)>=1&&(!buf->checkexactdegrees||amdordering_vtxgetexact(&buf->vertexdegrees, lpi, _state)>=1), "AMD: integrity check &GBFF1 failed", _state); + ae_assert(amdordering_vtxgetapprox(&buf->vertexdegrees, lpj, _state)>=1&&(!buf->checkexactdegrees||amdordering_vtxgetexact(&buf->vertexdegrees, lpj, _state)>=1), "AMD: integrity check &GBFF2 failed", _state); + ae_assert(amdordering_knscountandkth(&buf->setsuper, lpi, &buf->setsuper, lpj, _state)==0, "AMD: integrity check &GBFF3 failed", _state); + } + nj = amdordering_knscountkth(&buf->setsuper, lpj, _state); + amdordering_knsaddkthdistinct(&buf->setsuper, lpi, &buf->setsuper, lpj, _state); + amdordering_knsclearkthreclaim(&buf->setsuper, lpj, _state); + amdordering_knsclearkthreclaim(&buf->seta, lpj, _state); + amdordering_knsclearkthreclaim(&buf->sete, lpj, _state); + buf->issupernode.ptr.p_bool[lpj] = ae_false; + amdordering_vtxremovevertex(&buf->vertexdegrees, lpj, _state); + amdordering_vtxupdateapproximatedegree(&buf->vertexdegrees, lpi, amdordering_vtxgetapprox(&buf->vertexdegrees, lpi, _state)-nj, _state); + if( buf->checkexactdegrees ) + { + amdordering_vtxupdateexactdegree(&buf->vertexdegrees, lpi, amdordering_vtxgetexact(&buf->vertexdegrees, lpi, _state)-nj, _state); + } + } + } + } + } + amdordering_knsclearkthnoreclaim(&buf->hashbuckets, hashi, _state); + } + nisclear(&buf->nonemptybuckets, _state); +} + + +/************************************************************************* +Assign quasidense status to proposed supervars, perform all the necessary +cleanup (remove vertices, etc) + +INPUT PARAMETERS + Buf - properly initialized buffer object + Cand - supervariables to be moved to quasidense status + P - current pivot element (used for integrity checks) + or -1, when this function is used for initial status + assignment. + +OUTPUT PARAMETERS + Buf - variables belonging to supervariables in cand are + added to SetQ. Supervariables are removed from all lists + + -- ALGLIB PROJECT -- + Copyright 15.11.2021 by Bochkanov Sergey. +*************************************************************************/ +static void amdordering_amdmovetoquasidense(amdbuffer* buf, + niset* cand, + ae_int_t p, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + nisstartenumeration(cand, _state); + while(nisenumerate(cand, &j, _state)) + { + ae_assert(j!=p, "AMD: integrity check 9464 failed", _state); + ae_assert(buf->issupernode.ptr.p_bool[j], "AMD: integrity check 6284 failed", _state); + ae_assert(!buf->iseliminated.ptr.p_bool[j], "AMD: integrity check 3858 failed", _state); + amdordering_knsstartenumeration(&buf->setsuper, j, _state); + while(amdordering_knsenumerate(&buf->setsuper, &i, _state)) + { + nisaddelement(&buf->setq, i, _state); + } + amdordering_knsclearkthreclaim(&buf->seta, j, _state); + amdordering_knsclearkthreclaim(&buf->sete, j, _state); + buf->issupernode.ptr.p_bool[j] = ae_false; + amdordering_vtxremovevertex(&buf->vertexdegrees, j, _state); + } +} + + +void _amdknset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + amdknset *p = (amdknset*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->flagarray, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vallocated, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vcnt, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->data, 0, DT_INT, _state, make_automatic); +} + + +void _amdknset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + amdknset *dst = (amdknset*)_dst; + const amdknset *src = (const amdknset*)_src; + dst->k = src->k; + dst->n = src->n; + ae_vector_init_copy(&dst->flagarray, &src->flagarray, _state, make_automatic); + ae_vector_init_copy(&dst->vbegin, &src->vbegin, _state, make_automatic); + ae_vector_init_copy(&dst->vallocated, &src->vallocated, _state, make_automatic); + ae_vector_init_copy(&dst->vcnt, &src->vcnt, _state, make_automatic); + ae_vector_init_copy(&dst->data, &src->data, _state, make_automatic); + dst->dataused = src->dataused; + dst->iterrow = src->iterrow; + dst->iteridx = src->iteridx; +} + + +void _amdknset_clear(void* _p) +{ + amdknset *p = (amdknset*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->flagarray); + ae_vector_clear(&p->vbegin); + ae_vector_clear(&p->vallocated); + ae_vector_clear(&p->vcnt); + ae_vector_clear(&p->data); +} + + +void _amdknset_destroy(void* _p) +{ + amdknset *p = (amdknset*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->flagarray); + ae_vector_destroy(&p->vbegin); + ae_vector_destroy(&p->vallocated); + ae_vector_destroy(&p->vcnt); + ae_vector_destroy(&p->data); +} + + +void _amdvertexset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + amdvertexset *p = (amdvertexset*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->approxd, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->optionalexactd, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->isvertex, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->eligible, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->vbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vprev, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vnext, 0, DT_INT, _state, make_automatic); +} + + +void _amdvertexset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + amdvertexset *dst = (amdvertexset*)_dst; + const amdvertexset *src = (const amdvertexset*)_src; + dst->n = src->n; + dst->checkexactdegrees = src->checkexactdegrees; + dst->smallestdegree = src->smallestdegree; + ae_vector_init_copy(&dst->approxd, &src->approxd, _state, make_automatic); + ae_vector_init_copy(&dst->optionalexactd, &src->optionalexactd, _state, make_automatic); + ae_vector_init_copy(&dst->isvertex, &src->isvertex, _state, make_automatic); + ae_vector_init_copy(&dst->eligible, &src->eligible, _state, make_automatic); + ae_vector_init_copy(&dst->vbegin, &src->vbegin, _state, make_automatic); + ae_vector_init_copy(&dst->vprev, &src->vprev, _state, make_automatic); + ae_vector_init_copy(&dst->vnext, &src->vnext, _state, make_automatic); +} + + +void _amdvertexset_clear(void* _p) +{ + amdvertexset *p = (amdvertexset*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->approxd); + ae_vector_clear(&p->optionalexactd); + ae_vector_clear(&p->isvertex); + ae_vector_clear(&p->eligible); + ae_vector_clear(&p->vbegin); + ae_vector_clear(&p->vprev); + ae_vector_clear(&p->vnext); +} + + +void _amdvertexset_destroy(void* _p) +{ + amdvertexset *p = (amdvertexset*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->approxd); + ae_vector_destroy(&p->optionalexactd); + ae_vector_destroy(&p->isvertex); + ae_vector_destroy(&p->eligible); + ae_vector_destroy(&p->vbegin); + ae_vector_destroy(&p->vprev); + ae_vector_destroy(&p->vnext); +} + + +void _amdllmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + amdllmatrix *p = (amdllmatrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->vbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vcolcnt, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->entries, 0, DT_INT, _state, make_automatic); +} + + +void _amdllmatrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + amdllmatrix *dst = (amdllmatrix*)_dst; + const amdllmatrix *src = (const amdllmatrix*)_src; + dst->n = src->n; + ae_vector_init_copy(&dst->vbegin, &src->vbegin, _state, make_automatic); + ae_vector_init_copy(&dst->vcolcnt, &src->vcolcnt, _state, make_automatic); + ae_vector_init_copy(&dst->entries, &src->entries, _state, make_automatic); + dst->entriesinitialized = src->entriesinitialized; +} + + +void _amdllmatrix_clear(void* _p) +{ + amdllmatrix *p = (amdllmatrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->vbegin); + ae_vector_clear(&p->vcolcnt); + ae_vector_clear(&p->entries); +} + + +void _amdllmatrix_destroy(void* _p) +{ + amdllmatrix *p = (amdllmatrix*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->vbegin); + ae_vector_destroy(&p->vcolcnt); + ae_vector_destroy(&p->entries); +} + + +void _amdbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + amdbuffer *p = (amdbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->iseliminated, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->issupernode, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->iseligible, 0, DT_BOOL, _state, make_automatic); + _amdknset_init(&p->setsuper, _state, make_automatic); + _amdknset_init(&p->seta, _state, make_automatic); + _amdknset_init(&p->sete, _state, make_automatic); + _amdllmatrix_init(&p->mtxl, _state, make_automatic); + _amdvertexset_init(&p->vertexdegrees, _state, make_automatic); + _niset_init(&p->setq, _state, make_automatic); + ae_vector_init(&p->perm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->invperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->columnswaps, 0, DT_INT, _state, make_automatic); + _niset_init(&p->setp, _state, make_automatic); + _niset_init(&p->lp, _state, make_automatic); + _niset_init(&p->setrp, _state, make_automatic); + _niset_init(&p->ep, _state, make_automatic); + _niset_init(&p->adji, _state, make_automatic); + _niset_init(&p->adjj, _state, make_automatic); + ae_vector_init(&p->ls, 0, DT_INT, _state, make_automatic); + _niset_init(&p->setqsupercand, _state, make_automatic); + _niset_init(&p->exactdegreetmp0, _state, make_automatic); + _amdknset_init(&p->hashbuckets, _state, make_automatic); + _niset_init(&p->nonemptybuckets, _state, make_automatic); + ae_vector_init(&p->sncandidates, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->arrwe, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->dbga, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _amdbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + amdbuffer *dst = (amdbuffer*)_dst; + const amdbuffer *src = (const amdbuffer*)_src; + dst->n = src->n; + dst->extendeddebug = src->extendeddebug; + dst->checkexactdegrees = src->checkexactdegrees; + ae_vector_init_copy(&dst->iseliminated, &src->iseliminated, _state, make_automatic); + ae_vector_init_copy(&dst->issupernode, &src->issupernode, _state, make_automatic); + ae_vector_init_copy(&dst->iseligible, &src->iseligible, _state, make_automatic); + _amdknset_init_copy(&dst->setsuper, &src->setsuper, _state, make_automatic); + _amdknset_init_copy(&dst->seta, &src->seta, _state, make_automatic); + _amdknset_init_copy(&dst->sete, &src->sete, _state, make_automatic); + _amdllmatrix_init_copy(&dst->mtxl, &src->mtxl, _state, make_automatic); + _amdvertexset_init_copy(&dst->vertexdegrees, &src->vertexdegrees, _state, make_automatic); + _niset_init_copy(&dst->setq, &src->setq, _state, make_automatic); + ae_vector_init_copy(&dst->perm, &src->perm, _state, make_automatic); + ae_vector_init_copy(&dst->invperm, &src->invperm, _state, make_automatic); + ae_vector_init_copy(&dst->columnswaps, &src->columnswaps, _state, make_automatic); + _niset_init_copy(&dst->setp, &src->setp, _state, make_automatic); + _niset_init_copy(&dst->lp, &src->lp, _state, make_automatic); + _niset_init_copy(&dst->setrp, &src->setrp, _state, make_automatic); + _niset_init_copy(&dst->ep, &src->ep, _state, make_automatic); + _niset_init_copy(&dst->adji, &src->adji, _state, make_automatic); + _niset_init_copy(&dst->adjj, &src->adjj, _state, make_automatic); + ae_vector_init_copy(&dst->ls, &src->ls, _state, make_automatic); + dst->lscnt = src->lscnt; + _niset_init_copy(&dst->setqsupercand, &src->setqsupercand, _state, make_automatic); + _niset_init_copy(&dst->exactdegreetmp0, &src->exactdegreetmp0, _state, make_automatic); + _amdknset_init_copy(&dst->hashbuckets, &src->hashbuckets, _state, make_automatic); + _niset_init_copy(&dst->nonemptybuckets, &src->nonemptybuckets, _state, make_automatic); + ae_vector_init_copy(&dst->sncandidates, &src->sncandidates, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->arrwe, &src->arrwe, _state, make_automatic); + ae_matrix_init_copy(&dst->dbga, &src->dbga, _state, make_automatic); +} + + +void _amdbuffer_clear(void* _p) +{ + amdbuffer *p = (amdbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->iseliminated); + ae_vector_clear(&p->issupernode); + ae_vector_clear(&p->iseligible); + _amdknset_clear(&p->setsuper); + _amdknset_clear(&p->seta); + _amdknset_clear(&p->sete); + _amdllmatrix_clear(&p->mtxl); + _amdvertexset_clear(&p->vertexdegrees); + _niset_clear(&p->setq); + ae_vector_clear(&p->perm); + ae_vector_clear(&p->invperm); + ae_vector_clear(&p->columnswaps); + _niset_clear(&p->setp); + _niset_clear(&p->lp); + _niset_clear(&p->setrp); + _niset_clear(&p->ep); + _niset_clear(&p->adji); + _niset_clear(&p->adjj); + ae_vector_clear(&p->ls); + _niset_clear(&p->setqsupercand); + _niset_clear(&p->exactdegreetmp0); + _amdknset_clear(&p->hashbuckets); + _niset_clear(&p->nonemptybuckets); + ae_vector_clear(&p->sncandidates); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->arrwe); + ae_matrix_clear(&p->dbga); +} + + +void _amdbuffer_destroy(void* _p) +{ + amdbuffer *p = (amdbuffer*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->iseliminated); + ae_vector_destroy(&p->issupernode); + ae_vector_destroy(&p->iseligible); + _amdknset_destroy(&p->setsuper); + _amdknset_destroy(&p->seta); + _amdknset_destroy(&p->sete); + _amdllmatrix_destroy(&p->mtxl); + _amdvertexset_destroy(&p->vertexdegrees); + _niset_destroy(&p->setq); + ae_vector_destroy(&p->perm); + ae_vector_destroy(&p->invperm); + ae_vector_destroy(&p->columnswaps); + _niset_destroy(&p->setp); + _niset_destroy(&p->lp); + _niset_destroy(&p->setrp); + _niset_destroy(&p->ep); + _niset_destroy(&p->adji); + _niset_destroy(&p->adjj); + ae_vector_destroy(&p->ls); + _niset_destroy(&p->setqsupercand); + _niset_destroy(&p->exactdegreetmp0); + _amdknset_destroy(&p->hashbuckets); + _niset_destroy(&p->nonemptybuckets); + ae_vector_destroy(&p->sncandidates); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->arrwe); + ae_matrix_destroy(&p->dbga); +} + + +#endif +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Informational function, useful for debugging +*************************************************************************/ +ae_int_t spsymmgetmaxfastkernel(ae_state *_state) +{ + ae_int_t result; + + + result = spchol_maxfastkernel; + return result; +} + + +/************************************************************************* +Symbolic phase of Cholesky decomposition. + +Performs preliminary analysis of Cholesky/LDLT factorization. The latter +is computed with strictly diagonal D (no Bunch-Kauffman pivoting). + +The analysis object produced by this function will be used later to guide +actual decomposition. + +Depending on settings specified during factorization, may produce vanilla +Cholesky or L*D*LT decomposition (with strictly diagonal D), without +permutation or with permutation P (being either topological ordering or +sparsity preserving ordering). + +Thus, A is represented as either L*LT or L*D*LT or P*L*LT*PT or P*L*D*LT*PT. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +INPUT PARAMETERS: + A - sparse square matrix in CRS format, with LOWER triangle + being used to store the matrix. + Priorities - array[N], optional priorities: + * ignored for PermType not in [-4,-3,3] (not referenced at + all) + * for PermType=3 or PermType=-3 this array stores + nonnegative column elimination priorities. Columns + with lower priorities are eliminated first. At least + max(Priorities[])+1 internal AMD rounds will be + performed, so avoid specifying too large values here. + Ideally, 0<=Priorities[I]<5. + * for PermType=-4 this array stores user-requested + ordering, one that maps original row/col indexes into + permuted ones (as in Analysis.FillInPerm[]). + PromoteAbove- columns with degrees higher than PromoteAbove*max(MEAN(Degree),1) + may be promoted to the next priority group. Ignored for + PermType<>3 and PermType<>-3. + This parameter can be used to make priorities a hard + requirement, a non-binding suggestion, or something + in-between: + * big PromoteAbove (N or more) effectively means that + priorities are hard + * values between 2 and 10 are usually a good choice for + soft priorities + * zero value means that appropriate value for a soft + priority (between 2 and 5) is automatically chosen. + Specific value may change in future ALGLIB versions. + PromoteTo - controls column promotion: + * columns which will be postponed due to being too dense + will be promoted to the priority group #PromoteTo + instead of the next group. + * Ignored for PermType<>3 and PermType<>-3. + * If column already belongs to a priority group #PromoteTo + or higher, it will be promoted to the next priority group. + * Can be zero (means default way of promoting columns). + * Avoid specifying too large values (above 10) because + algorithm will perform at least (PromoteTo+1) elimination rounds. + FactType - factorization type: + * 0 for traditional Cholesky + * 1 for LDLT decomposition with strictly diagonal D + * 20/21 for a quasi-definite LLT or LDLT decomposition performed by + a Performance Backend Library (PBL), if available. + This option comes with the restriction that A is guaranteed + to be quasi-definite, with no ability to SPSymmExtract() the matrix, + but with the ability to call SPSymmSolve() and SPSymmReload() + and some other functions. + Depending on the specific library being used, Priorities[], + PromoteAbove[], PromoteTo[], PermType and MemReuse can be + ignored by the library. + If no PBL is available, decomposition is performed according + to FactType=1, using Priorities[], PromoteAbove[], PromoteTo[], + PermType and MemReuse to guide the factorization. But still + limitations above apply. + See below for more comments on PBL for sparse factorizations. + PermType - permutation type: + *-4 for user permutation given by Priorities[] + *-3 for debug improved AMD which debugs AMD itself, parallel + block supernodal code and advanced memory management: + * AMD is debugged by generating a sequence of decreasing + tail sizes, ~logN in total, even if ordering can be + done with just one round of AMD. This ordering is + used to test correctness of multiple AMD rounds. + * parallel block supernodal code is debugged by + partitioning problems into smallest possible chunks, + ignoring thresholds set by SMPActivationLevel() + and SpawnLevel(). + * memory management is debugged by randomly switching + MemReuse between +1 and -1, ignoring its original value + *-2 for column count ordering (NOT RECOMMENDED!) + *-1 for absence of permutation + * 0 for best permutation available + * 1 for supernodal ordering (improves locality and + performance, but does NOT change fill-in pattern) + * 2 for supernodal AMD ordering (improves fill-in) + * 3 for improved AMD (approximate minimum degree) + ordering with better handling of matrices with + dense rows/columns and ability to perform priority + ordering + MemReuse - the memory management strategy: + * +1 means that the internally allocated memory is reused + as much as possible. What was once allocated is not + freed as long as SPCholAnalysis structure is alive. + Ideal for many small and medium-sized repeated + factorization problems. + * -1 means that some potentially large memory blocks + are freed as soon as they are not needed. Whilst + some limited amount of dynamically allocated memory + is still reused, the largest block are not. + Ideal for large-scale problems that occupy almost + all available RAM. + Analysis - can be uninitialized instance, or previous analysis + results. Previously allocated memory is reused as much + as possible. + Buf - buffer; may be completely uninitialized, or one remained + from previous calls (including ones with completely + different matrices). Previously allocated temporary + space will be reused. + +OUTPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. The + numerical values are stored internally in the structure, + but you have to run factorization phase explicitly + with SPSymmFactorize(). You can also reload another + matrix with same sparsity pattern with SPSymmReload() + or rewrite its diagonal with SPSymmReloadDiagonal(). + +This function fails if and only if the matrix A is symbolically degenerate +i.e. has diagonal element which is exactly zero. In such case False is +returned. + +NOTE: defining 'SCHOLESKY' trace tag will activate tracing. + defining 'SCHOLESKY.SS' trace tag will activate detailed tracing of + the supernodal structure. + +NOTE: defining 'DEBUG.SLOW' trace tag will activate extra-slow (roughly + N^3 ops) integrity checks, in addition to cheap O(1) ones. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool spsymmanalyze(const sparsematrix* a, + /* Integer */ const ae_vector* priorities, + double promoteabove, + ae_int_t promoteto, + ae_int_t facttype, + ae_int_t permtype, + ae_int_t memreuse, + spcholanalysis* analysis, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t k; + ae_bool permready; + ae_bool result; + + + ae_assert(ae_isfinite(promoteabove, _state)&&ae_fp_greater_eq(promoteabove,(double)(0)), "SPSymmAnalyze: PromoteAbove is negative or infinite", _state); + ae_assert(promoteto>=0, "SPSymmAnalyze: PromoteTo is negative", _state); + ae_assert(sparseiscrs(a, _state), "SPSymmAnalyze: A is not stored in CRS format", _state); + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SPSymmAnalyze: non-square A", _state); + ae_assert(((facttype==0||facttype==1)||facttype==20)||facttype==21, "SPSymmAnalyze: unexpected FactType", _state); + ae_assert(((((((permtype==0||permtype==1)||permtype==2)||permtype==3)||permtype==-1)||permtype==-2)||permtype==-3)||permtype==-4, "SPSymmAnalyze: unexpected PermType", _state); + ae_assert(memreuse==-1||memreuse==1, "SPSymmAnalyze: unexpected MemType", _state); + ae_assert((permtype!=3&&permtype!=-3)||(ae_isfinite(promoteabove, _state)&&ae_fp_greater_eq(promoteabove,(double)(0))), "SPSymmAnalyze: unexpected PromoteAbove - infinite or negative", _state); + n = sparsegetnrows(a, _state); + result = ae_true; + + /* + * Analysis parameters that are always set, independently of whether we have platform-specific libraries or not + */ + analysis->tasktype = 0; + analysis->n = n; + analysis->unitd = facttype==0||facttype==20; + analysis->pblrequested = facttype==20||facttype==21; + analysis->pblused = ae_false; + analysis->dotrace = ae_is_trace_enabled("SCHOLESKY"); + analysis->dotracescheduler = analysis->dotrace&&ae_is_trace_enabled("SCHOLESKY.SCHEDULER"); + analysis->dotracesupernodalstructure = analysis->dotrace&&ae_is_trace_enabled("SCHOLESKY.SS"); + if( analysis->dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// SPARSE CHOLESKY ANALYSIS STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Try to setup PBL + */ + if( (facttype==20||facttype==21)&&spchol_spsymmpblsetup(analysis, a, priorities, facttype, permtype, _state) ) + { + return result; + } + + /* + * Analysis parameters that are set only when no PBL intercepts the factorization. + */ + if( permtype==-3||permtype==3 ) + { + ae_assert(priorities->cnt>=n, "SPSymmAnalyze: length(Priorities)curpriorities, _state); + } + if( permtype==0 ) + { + isetallocv(n, 0, &analysis->curpriorities, _state); + permtype = 3; + promoteabove = 0.0; + promoteto = 0; + } + analysis->permtype = permtype; + analysis->debugblocksupernodal = permtype==-3; + analysis->extendeddebug = ae_is_trace_enabled("DEBUG.SLOW")&&n<=100; + analysis->istopologicalordering = permtype==-1||permtype==1; + analysis->applypermutationtooutput = permtype==-1; + analysis->modtype = 0; + analysis->modparam0 = 0.0; + analysis->modparam1 = 0.0; + analysis->modparam2 = 0.0; + analysis->modparam3 = 0.0; + analysis->useparallelism = ae_false; + + /* + * Allocate temporaries + */ + ivectorsetlengthatleast(&analysis->tmpparent, n+1, _state); + ivectorsetlengthatleast(&analysis->tmp0, n+1, _state); + ivectorsetlengthatleast(&analysis->tmp1, n+1, _state); + ivectorsetlengthatleast(&analysis->tmp2, n+1, _state); + ivectorsetlengthatleast(&analysis->tmp3, n+1, _state); + ivectorsetlengthatleast(&analysis->tmp4, n+1, _state); + bvectorsetlengthatleast(&analysis->flagarray, n+1, _state); + ae_nxpool_alloc(&analysis->n1booleanpool, n+1, _state); + ae_nxpool_alloc(&analysis->n1integerpool, n+1, _state); + ae_nxpool_alloc(&analysis->nrealpool, n, _state); + + /* + * Continue trace message + */ + if( analysis->dotrace ) + { + + /* + * Nonzeros count of the original matrix + */ + k = 0; + for(i=0; i<=n-1; i++) + { + k = k+(a->didx.ptr.p_int[i]-a->ridx.ptr.p_int[i])+1; + } + ae_trace("NZ(A) = %0d\n", + (int)(k)); + + /* + * Analyze row statistics + */ + ae_trace("=== ANALYZING ROW STATISTICS =======================================================================\n"); + ae_trace("row size is:\n"); + isetv(n, 1, &analysis->tmp0, _state); + for(i=0; i<=n-1; i++) + { + for(jj=a->ridx.ptr.p_int[i]; jj<=a->didx.ptr.p_int[i]-1; jj++) + { + j = a->idx.ptr.p_int[jj]; + analysis->tmp0.ptr.p_int[i] = analysis->tmp0.ptr.p_int[i]+1; + analysis->tmp0.ptr.p_int[j] = analysis->tmp0.ptr.p_int[j]+1; + } + } + k = 1; + while(k<=n) + { + j = 0; + for(i=0; i<=n-1; i++) + { + if( analysis->tmp0.ptr.p_int[i]>=k&&analysis->tmp0.ptr.p_int[i]<2*k ) + { + j = j+1; + } + } + ae_trace("* [%6d..%6d) elements: %6d rows\n", + (int)(k), + (int)(2*k), + (int)(j)); + k = k*2; + } + } + + /* + * Initial integrity check - diagonal MUST be symbolically nonzero + */ + for(i=0; i<=n-1; i++) + { + if( a->didx.ptr.p_int[i]==a->uidx.ptr.p_int[i] ) + { + if( analysis->dotrace ) + { + ae_trace("> the matrix diagonal is symbolically zero, stopping"); + } + result = ae_false; + return result; + } + } + + /* + * What type of permutation do we have? + */ + if( analysis->istopologicalordering ) + { + ae_assert(permtype==-1||permtype==1, "SPSymmAnalyze: integrity check failed (ihebd)", _state); + + /* + * Build topologically ordered elimination tree + */ + spchol_buildorderedetree(a, n, &analysis->tmpparent, &analysis->superperm, &analysis->invsuperperm, &analysis->tmp0, &analysis->tmp1, &analysis->tmp2, &analysis->flagarray, _state); + ivectorsetlengthatleast(&analysis->fillinperm, n, _state); + ivectorsetlengthatleast(&analysis->invfillinperm, n, _state); + ivectorsetlengthatleast(&analysis->effectiveperm, n, _state); + ivectorsetlengthatleast(&analysis->inveffectiveperm, n, _state); + for(i=0; i<=n-1; i++) + { + analysis->fillinperm.ptr.p_int[i] = i; + analysis->invfillinperm.ptr.p_int[i] = i; + analysis->effectiveperm.ptr.p_int[i] = analysis->superperm.ptr.p_int[i]; + analysis->inveffectiveperm.ptr.p_int[i] = analysis->invsuperperm.ptr.p_int[i]; + } + + /* + * Reorder input matrix + */ + spchol_topologicalpermutation(a, &analysis->superperm, &analysis->tmpat, _state); + + /* + * Analyze etree, build supernodal structure + */ + spchol_createsupernodalstructure(&analysis->tmpat, &analysis->tmpparent, n, analysis, &analysis->node2supernode, &analysis->tmp0, &analysis->tmp1, &analysis->tmp2, &analysis->tmp3, &analysis->tmp4, &analysis->flagarray, _state); + + /* + * Having fully initialized supernodal structure, analyze dependencies + */ + spchol_analyzesupernodaldependencies(analysis, a, &analysis->node2supernode, n, &analysis->tmp0, &analysis->tmp1, &analysis->flagarray, _state); + } + else + { + + /* + * Generate fill-in reducing permutation + */ + permready = ae_false; + if( permtype==-2 ) + { + spchol_generatedbgpermutation(a, n, &analysis->fillinperm, &analysis->invfillinperm, _state); + permready = ae_true; + } + if( permtype==2 ) + { + if( !(analysis->ptramdtmp!=NULL) ) + { + analysis->ptramdtmp = (amdbuffer*)ae_malloc(sizeof(amdbuffer), _state); /* note: using analysis->ptramdtmp as a temporary prior to assigning its value to _analysis->ptramdtmp */ + memset(analysis->ptramdtmp, 0, sizeof(amdbuffer)); + _amdbuffer_init(analysis->ptramdtmp, _state, ae_false); + ae_smart_ptr_assign(&analysis->_ptramdtmp, analysis->ptramdtmp, ae_true, ae_true, (ae_int_t)sizeof(amdbuffer), _amdbuffer_init_copy, _amdbuffer_destroy); + } + generateamdpermutation(a, n, &analysis->fillinperm, &analysis->invfillinperm, analysis->ptramdtmp, _state); + permready = ae_true; + } + if( permtype==3||permtype==-3 ) + { + if( !(analysis->ptrpamdtmp!=NULL) ) + { + analysis->ptrpamdtmp = (priorityamdbuffers*)ae_malloc(sizeof(priorityamdbuffers), _state); /* note: using analysis->ptrpamdtmp as a temporary prior to assigning its value to _analysis->ptrpamdtmp */ + memset(analysis->ptrpamdtmp, 0, sizeof(priorityamdbuffers)); + _priorityamdbuffers_init(analysis->ptrpamdtmp, _state, ae_false); + ae_smart_ptr_assign(&analysis->_ptrpamdtmp, analysis->ptrpamdtmp, ae_true, ae_true, (ae_int_t)sizeof(priorityamdbuffers), _priorityamdbuffers_init_copy, _priorityamdbuffers_destroy); + } + sparsecopybuf(a, &analysis->tmpa, _state); + spchol_generatepriorityamdpermutation(&analysis->tmpa, &analysis->curpriorities, promoteabove, promoteto, permtype==-3&&ae_randominteger(100, _state)>50, analysis->dotrace, &analysis->n1booleanpool, &analysis->n1integerpool, analysis->ptrpamdtmp, memreuse>0, &analysis->fillinperm, &analysis->invfillinperm, _state); + permready = ae_true; + } + if( permtype==-4 ) + { + icopyallocv(n, priorities, &analysis->fillinperm, _state); + isetallocv(n, -1, &analysis->invfillinperm, _state); + for(i=0; i<=n-1; i++) + { + j = analysis->fillinperm.ptr.p_int[i]; + if( j<0||j>=n ) + { + ae_assert(ae_false, "SPSymmAnalyze: input permutation has indexes outside of [0,N) range", _state); + } + if( analysis->invfillinperm.ptr.p_int[j]>=0 ) + { + ae_assert(ae_false, "SPSymmAnalyze: input permutation has non-distinct indexes", _state); + } + analysis->invfillinperm.ptr.p_int[j] = i; + } + permready = ae_true; + } + ae_assert(permready, "SPSymmAnalyze: integrity check failed (pp4td)", _state); + + /* + * Apply permutation to the matrix, perform analysis on the initially reordered matrix + * (we may need one more reordering, now topological one, due to supernodal analysis). + * Build topologically ordered elimination tree + */ + sparsesymmpermtblbuf(a, ae_false, &analysis->fillinperm, &analysis->tmpa, _state); + spchol_buildorderedetree(&analysis->tmpa, n, &analysis->tmpparent, &analysis->superperm, &analysis->invsuperperm, &analysis->tmp0, &analysis->tmp1, &analysis->tmp2, &analysis->flagarray, _state); + ivectorsetlengthatleast(&analysis->effectiveperm, n, _state); + ivectorsetlengthatleast(&analysis->inveffectiveperm, n, _state); + for(i=0; i<=n-1; i++) + { + analysis->effectiveperm.ptr.p_int[i] = analysis->superperm.ptr.p_int[analysis->fillinperm.ptr.p_int[i]]; + analysis->inveffectiveperm.ptr.p_int[analysis->effectiveperm.ptr.p_int[i]] = i; + } + + /* + * Reorder input matrix + */ + spchol_topologicalpermutation(&analysis->tmpa, &analysis->superperm, &analysis->tmpat, _state); + + /* + * Analyze etree, build supernodal structure + */ + spchol_createsupernodalstructure(&analysis->tmpat, &analysis->tmpparent, n, analysis, &analysis->node2supernode, &analysis->tmp0, &analysis->tmp1, &analysis->tmp2, &analysis->tmp3, &analysis->tmp4, &analysis->flagarray, _state); + + /* + * Having fully initialized supernodal structure, analyze dependencies + */ + spchol_analyzesupernodaldependencies(analysis, &analysis->tmpa, &analysis->node2supernode, n, &analysis->tmp0, &analysis->tmp1, &analysis->flagarray, _state); + } + + /* + * Save information for integrity checks + */ + icopyallocv(n+1, &analysis->tmpat.ridx, &analysis->referenceridx, _state); + + /* + * Load matrix into the supernodal storage + */ + spchol_loadmatrix(analysis, &analysis->tmpat, _state); + return result; +} + + +/************************************************************************* +Sets modified Cholesky type. + +This function can be ignored by Performance Backend Libraries. + +INPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure + ModStrategy - modification type: + * 0 for traditional Cholesky/LDLT (Cholesky fails when + encounters nonpositive pivot, LDLT fails when zero + pivot is encountered, no stability checks for + overflows/underflows) + * 1 for modified Cholesky with additional checks: + * pivots less than ModParam0 are increased; (similar + procedure with proper generalization is applied to + LDLT) + * if, at some moment, sum of absolute values of + elements in column J will become greater than + ModParam1, Cholesky/LDLT will treat it as failure + and will stop immediately + * if ModParam0 is zero, no pivot modification is applied + * if ModParam1 is zero, no overflow check is performed + * 2 for modified Cholesky/LDLT which handles pivots + smaller than ModParam0 in the following way: + * a diagonal element is set to a very large value + * offdiagonal elements are zeroed + P0, P1, P2,P3 - modification parameters #0 #1, #2 and #3. + Params #2 and #3 are ignored in current version. + +OUTPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure, new strategy + (results will be seen with next SPSymmFactorize() call) + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void spsymmsetmodificationstrategy(spcholanalysis* analysis, + ae_int_t modstrategy, + double p0, + double p1, + double p2, + double p3, + ae_state *_state) +{ + + + ae_assert((modstrategy==0||modstrategy==1)||modstrategy==2, "SPSymmSetModificationStrategy: unexpected ModStrategy", _state); + ae_assert(ae_isfinite(p0, _state)&&ae_fp_greater_eq(p0,(double)(0)), "SPSymmSetModificationStrategy: bad P0", _state); + ae_assert(ae_isfinite(p1, _state), "SPSymmSetModificationStrategy: bad P1", _state); + ae_assert(ae_isfinite(p2, _state), "SPSymmSetModificationStrategy: bad P2", _state); + ae_assert(ae_isfinite(p3, _state), "SPSymmSetModificationStrategy: bad P3", _state); + analysis->modtype = modstrategy; + analysis->modparam0 = p0; + analysis->modparam1 = p1; + analysis->modparam2 = p2; + analysis->modparam3 = p3; +} + + +/************************************************************************* +Sets sign control strategy for the LDLT factorization: requires diagonal +elements to have proper sign (being strictly greater than +EPS for one set +of elements, being strictly less than -EPS for another set of elements). + +The factorization fails if this property is not satisfied. + +This function can be ignored by Performance Backend Libraries. + +INPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure + IsPositive - array[N], True if an element is required to be strictly + greater than +EPS, False if it is required to be + less than -EPS. + Eps - Eps>=0, parameter + + -- ALGLIB routine -- + 20.08.2024 + Bochkanov Sergey +*************************************************************************/ +void spsymmcontrolsign(spcholanalysis* analysis, + /* Boolean */ const ae_vector* ispositive, + double eps, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(ispositive->cnt>=analysis->n, "SPSymmControlSign: len(IsPositive)modtype = 3; + analysis->modparam0 = eps; + ballocv(analysis->n, &analysis->bsigns, _state); + for(i=0; i<=analysis->n-1; i++) + { + analysis->bsigns.ptr.p_bool[analysis->effectiveperm.ptr.p_int[i]] = ispositive->ptr.p_bool[i]; + } +} + + +/************************************************************************* +Updates symmetric matrix internally stored in previously initialized +Analysis object. + +You can use this function to perform multiple factorizations with same +sparsity patterns: perform symbolic analysis once with SPSymmAnalyze(), +then update internal matrix with SPSymmReload() and call SPSymmFactorize(). + +INPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure + A - sparse square matrix in CRS format with LOWER triangle + being used to store the matrix. The matrix MUST have + sparsity pattern exactly same as one used to + initialize the Analysis object. + The algorithm will fail in an unpredictable way if + something different was passed. + +OUTPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. The + numerical values are stored internally in the structure, + but you have to run factorization phase explicitly + with SPSymmAnalyze(). You can also reload another + matrix with same sparsity pattern with SPSymmReload(). + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void spsymmreload(spcholanalysis* analysis, + const sparsematrix* a, + ae_state *_state) +{ + + + ae_assert(sparseiscrs(a, _state), "SPSymmReload: A is not stored in CRS format", _state); + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SPSymmReload: non-square A", _state); + if( analysis->pblused ) + { + if( analysis->pblneedsl ) + { + sparsecopybuf(a, &analysis->pbla, _state); + } + else + { + sparsecopytransposecrsxbuf(a, -1, &analysis->pbla, _state); + } + analysis->pblachanged = ae_true; + return; + } + if( analysis->istopologicalordering ) + { + + /* + * Topological (fill-in preserving) ordering is used, we can copy + * A directly into WrkAT using joint permute+transpose + */ + spchol_topologicalpermutation(a, &analysis->effectiveperm, &analysis->tmpat, _state); + spchol_loadmatrix(analysis, &analysis->tmpat, _state); + } + else + { + + /* + * Non-topological permutation; first we perform generic symmetric + * permutation, then transpose result + */ + spchol_permtransposeunsorted(a, &analysis->effectiveperm, &analysis->tmpat, _state); + spchol_loadmatrix(analysis, &analysis->tmpat, _state); + } +} + + +/************************************************************************* +Updates diagonal of the symmetric matrix internally stored in the +previously initialized Analysis object. + +When only diagonal of the matrix has changed, this function is more +efficient than SPSymmReload() that has to perform costly permutation of +the entire matrix. + +You can use this function to perform multiple factorizations with same +off-diagonal elements: perform symbolic analysis once with SPSymmAnalyze(), +then update diagonal with SPSymmReloadDiagonal() and call SPSymmFactorize(). + +INPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure + D - array[N], diagonal factor + +OUTPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. The + numerical values are stored internally in the structure, + but you have to run factorization phase explicitly + with SPSymmAnalyze(). You can also reload another + matrix with same sparsity pattern with SPSymmReload(). + + -- ALGLIB routine -- + 05.09.2021 + Bochkanov Sergey +*************************************************************************/ +void spsymmreloaddiagonal(spcholanalysis* analysis, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t sidx; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t sstride; + ae_int_t j; + + + ae_assert(d->cnt>=analysis->n, "SPSymmReloadDiagonal: length(D)pblused ) + { + for(j=0; j<=analysis->n-1; j++) + { + if( analysis->pbla.uidx.ptr.p_int[j]!=analysis->pbla.didx.ptr.p_int[j]+1 ) + { + ae_assert(ae_false, "SPSymmReloadDiagonal: integrity check 031154 failed", _state); + } + analysis->pbla.vals.ptr.p_double[analysis->pbla.didx.ptr.p_int[j]] = d->ptr.p_double[j]; + } + analysis->pblachanged = ae_true; + return; + } + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + for(j=cols0; j<=cols1-1; j++) + { + analysis->inputstorage.ptr.p_double[offss+(j-cols0)*sstride+(j-cols0)] = d->ptr.p_double[analysis->inveffectiveperm.ptr.p_int[j]]; + } + } +} + + +/************************************************************************* +Sparse Cholesky factorization of symmetric matrix stored in CRS format, +using precomputed analysis of the sparsity pattern stored in the Analysis +object and specific numeric values that are presently loaded into the +Analysis. + +The factorization can be retrieved with SPSymmExtract(). Alternatively, +one can perform some operations without offloading the matrix (somewhat +faster due to itilization of SIMD-friendly supernodal data structures), +most importantly - linear system solution with SPSymmSolve(). + +Depending on settings specified during factorization, may produce vanilla +Cholesky or L*D*LT decomposition (with strictly diagonal D), without +permutation or with permutation P (being either topological ordering or +sparsity preserving ordering). + +Thus, A is represented as either L*LT or L*D*LT or P*L*LT*PT or P*L*D*LT*PT. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +INPUT PARAMETERS: + Analysis - prior analysis performed on some sparse matrix, with + matrix being stored in Analysis. + +OUTPUT PARAMETERS: + Analysis - contains factorization results + +The function returns True when factorization resulted in nondegenerate +matrix. False is returned when factorization fails (Cholesky factorization +of indefinite matrix) or LDLT factorization has exactly zero elements at +the diagonal. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool spsymmfactorize(spcholanalysis* analysis, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t sidx; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t blocksize; + ae_int_t sstride; + ae_int_t offss; + ae_int_t i; + ae_int_t k; + ae_int_t n; + ae_vector raw2smap; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&raw2smap, 0, sizeof(raw2smap)); + ae_vector_init(&raw2smap, 0, DT_INT, _state, ae_true); + + ae_assert(analysis->tasktype==0, "SPCholFactorize: Analysis type does not match current task", _state); + n = analysis->n; + + /* + * Invoke Performance Backend Library, if present + */ + if( analysis->pblused ) + { + if( analysis->modtype==3 ) + { + + /* + * Sign control: PBL controls that sign of diagonal elements of the factorized matrix matches + * that of the original matrix. Additionally, we control outside of PBL that the original matrix + * has correct signs. + */ + for(i=0; i<=analysis->n-1; i++) + { + if( ae_fp_less_eq(rcase2(analysis->bsigns.ptr.p_bool[analysis->effectiveperm.ptr.p_int[i]], (double)(1), (double)(-1), _state)*analysis->pbla.vals.ptr.p_double[analysis->pbla.didx.ptr.p_int[i]],0.0) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + } + result = spchol_spsymmpblfactorize(&analysis->pbl, &analysis->pbla, analysis->pblachanged, _state); + ae_frame_leave(_state); + return result; + } + + /* + * Allocate temporaries + */ + ivectorsetlengthatleast(&analysis->tmp0, n+1, _state); + rsetallocv(n, 0.0, &analysis->diagd, _state); + rcopyallocv(analysis->rowoffsets.ptr.p_int[analysis->nsuper], &analysis->inputstorage, &analysis->outputstorage, _state); + icopyallocv(analysis->nsuper, &analysis->ladj.rowbegin, &analysis->curladjrowbegin, _state); + + /* + * Prepare expected pivot signs (presently only for LDLT) + */ + if( analysis->modtype!=0&&!analysis->unitd ) + { + ae_assert((analysis->modtype==1||analysis->modtype==2)||analysis->modtype==3, "SPSymmFactorize: integrity check 957417 failed", _state); + if( analysis->modtype==1||analysis->modtype==2 ) + { + rallocv(n, &analysis->rpivotsigns, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + blocksize = cols1-cols0; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + for(k=0; k<=blocksize-1; k++) + { + analysis->rpivotsigns.ptr.p_double[cols0+k] = possign(analysis->inputstorage.ptr.p_double[offss+k*sstride+k], _state); + } + } + } + if( analysis->modtype==3 ) + { + rallocv(n, &analysis->rpivotsigns, _state); + for(i=0; i<=analysis->n-1; i++) + { + if( analysis->bsigns.ptr.p_bool[i] ) + { + analysis->rpivotsigns.ptr.p_double[i] = (double)(1); + } + else + { + analysis->rpivotsigns.ptr.p_double[i] = (double)(-1); + } + } + } + } + + /* + * Factorize + */ + ae_nxpool_retrieve(&analysis->n1integerpool, &raw2smap, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + + /* + * Prepare mapping of raw (range 0...N-1) indexes into internal (range 0...BlockSize+OffdiagSize-1) ones + */ + spchol_fillraw2smap(&analysis->superrowidx, sidx, cols0, cols1, analysis->superrowridx.ptr.p_int[sidx], analysis->superrowridx.ptr.p_int[sidx+1], blocksize, &raw2smap, _state); + + /* + * Update current supernode with remaining updates. + */ + spchol_updatesupernode(analysis, sidx, cols0, cols1, offss, &raw2smap, analysis->curladjrowbegin.ptr.p_int[sidx], analysis->ladj.rowend.ptr.p_int[sidx], &analysis->diagd, _state); + analysis->curladjrowbegin.ptr.p_int[sidx] = analysis->ladj.rowend.ptr.p_int[sidx]; + + /* + * Factorize current supernode + */ + if( !spchol_factorizesupernode(analysis, sidx, _state) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + ae_nxpool_recycle(&analysis->n1integerpool, &raw2smap, _state); + result = ae_true; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Enforces parallelism independently from the settings and problem size. + + -- ALGLIB routine -- + 28.01.2024 + Bochkanov Sergey +*************************************************************************/ +void spsymmenforceparallelism(spcholanalysis* analysis, ae_state *_state) +{ + + + analysis->useparallelism = ae_true; +} + + +/************************************************************************* +Extracts result of the last Cholesky/LDLT factorization performed on the +Analysis object. + +Following calls will result in the undefined behavior: +* calling for Analysis that was not factorized with SPSymmFactorize() +* calling after SPSymmFactorize() returned False + +This function is NOT supported when FactType suggests using Performance +Backend Libraries (e.g. FactType=20 or FactType=21), whether these libraries +were actually activated or not. + +INPUT PARAMETERS: + Analysis - prior factorization performed on some sparse matrix + D, P - possibly preallocated buffers + +OUTPUT PARAMETERS: + A - Cholesky/LDLT decomposition of A stored in CRS format + in LOWER triangle. + D - array[N], diagonal factor. If no diagonal factor was + required during analysis phase, still returned but + filled with units. + P - array[N], pivots. Permutation matrix P is a product of + P(0)*P(1)*...*P(N-1), where P(i) is a permutation of + row/col I and P[I] (with P[I]>=I). + If no permutation was requested during analysis phase, + still returned but filled with unit elements. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void spsymmextract(spcholanalysis* analysis, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + ae_state *_state) +{ + + + ae_assert(!analysis->pblrequested, "SPSymmExtract: not supported when Performance Backend was requested", _state); + spchol_extractmatrix(analysis, &analysis->rowoffsets, &analysis->rowstrides, &analysis->outputstorage, &analysis->diagd, analysis->n, a, d, p, &analysis->tmp0, _state); +} + + +/************************************************************************* +Solve linear system A*x=b, using internally stored factorization of the +matrix A. + +Works faster than extracting the matrix and solving with SparseTRSV() due +to SIMD-friendly supernodal data structures being used. + +INPUT PARAMETERS: + Analysis - prior factorization performed on some sparse matrix + B - array[N], right-hand side + +OUTPUT PARAMETERS: + B - overwritten by X + + -- ALGLIB routine -- + 08.09.2021 + Bochkanov Sergey +*************************************************************************/ +void spsymmsolve(spcholanalysis* analysis, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_int_t baseoffs; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t sstride; + ae_int_t sidx; + ae_int_t blocksize; + ae_int_t rbase; + ae_int_t offdiagsize; + double x0; + double x1; + double x2; + double x3; + + + + /* + * Invoke Performance Backend Library, if present + */ + if( analysis->pblused ) + { + if( !spchol_spsymmpblsolve(&analysis->pbl, &analysis->pbla, b, _state) ) + { + ae_assert(ae_false, "SPSymmSolve: Performance Backend solve unexpectedly failed", _state); + } + return; + } + + /* + * Our own implementation + */ + n = analysis->n; + rsetallocv(n, 0.0, &analysis->tmpx, _state); + x0 = (double)(0); + x1 = (double)(0); + x2 = (double)(0); + x3 = (double)(0); + + /* + * Handle left-hand side permutation, convert data to internal SIMD-friendly format + */ + for(i=0; i<=n-1; i++) + { + analysis->tmpx.ptr.p_double[i] = b->ptr.p_double[analysis->inveffectiveperm.ptr.p_int[i]]; + } + + /* + * Solve for L*tmp_x=rhs. + */ + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + rbase = analysis->superrowridx.ptr.p_int[sidx]; + offdiagsize = analysis->superrowridx.ptr.p_int[sidx+1]-rbase; + + /* + * Solve for variables in the supernode, + * fetch vars to locals (when supernode is small enough) + */ + if( blocksize==1 ) + { + + /* + * One column, fetch to X0 + */ + x0 = analysis->tmpx.ptr.p_double[cols0]/analysis->outputstorage.ptr.p_double[offss]; + analysis->tmpx.ptr.p_double[cols0] = x0; + } + else + { + if( blocksize==2 ) + { + + /* + * Two columns, fetch to X0 and X1 + */ + for(i=cols0; i<=cols1-1; i++) + { + baseoffs = offss+(i-cols0)*sstride+(-cols0); + v = analysis->tmpx.ptr.p_double[i]; + for(j=cols0; j<=i-1; j++) + { + v = v-analysis->outputstorage.ptr.p_double[baseoffs+j]*analysis->tmpx.ptr.p_double[j]; + } + analysis->tmpx.ptr.p_double[i] = v/analysis->outputstorage.ptr.p_double[baseoffs+i]; + } + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + } + else + { + if( blocksize==3 ) + { + + /* + * Three columns, fetch to X0, X1 and X2 + */ + for(i=cols0; i<=cols1-1; i++) + { + baseoffs = offss+(i-cols0)*sstride+(-cols0); + v = analysis->tmpx.ptr.p_double[i]; + for(j=cols0; j<=i-1; j++) + { + v = v-analysis->outputstorage.ptr.p_double[baseoffs+j]*analysis->tmpx.ptr.p_double[j]; + } + analysis->tmpx.ptr.p_double[i] = v/analysis->outputstorage.ptr.p_double[baseoffs+i]; + } + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + x2 = analysis->tmpx.ptr.p_double[cols0+2]; + } + else + { + if( blocksize==4 ) + { + + /* + * Four columns, fetch to X0, X1, X2, X3 + */ + for(i=cols0; i<=cols1-1; i++) + { + baseoffs = offss+(i-cols0)*sstride+(-cols0); + v = analysis->tmpx.ptr.p_double[i]; + for(j=cols0; j<=i-1; j++) + { + v = v-analysis->outputstorage.ptr.p_double[baseoffs+j]*analysis->tmpx.ptr.p_double[j]; + } + analysis->tmpx.ptr.p_double[i] = v/analysis->outputstorage.ptr.p_double[baseoffs+i]; + } + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + x2 = analysis->tmpx.ptr.p_double[cols0+2]; + x3 = analysis->tmpx.ptr.p_double[cols0+3]; + } + else + { + + /* + * Generic case + */ + for(i=cols0; i<=cols1-1; i++) + { + baseoffs = offss+(i-cols0)*sstride+(-cols0); + v = analysis->tmpx.ptr.p_double[i]; + for(j=cols0; j<=i-1; j++) + { + v = v-analysis->outputstorage.ptr.p_double[baseoffs+j]*analysis->tmpx.ptr.p_double[j]; + } + analysis->tmpx.ptr.p_double[i] = v/analysis->outputstorage.ptr.p_double[baseoffs+i]; + } + } + } + } + } + + /* + * Propagate update to other variables + */ + if( blocksize==1 ) + { + + /* + * Special case: single column + */ + baseoffs = offss+1; + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + analysis->tmpx.ptr.p_double[i] = analysis->tmpx.ptr.p_double[i]-analysis->outputstorage.ptr.p_double[baseoffs]*x0; + baseoffs = baseoffs+1; + } + } + else + { + if( blocksize==2 ) + { + + /* + * Two columns + */ + baseoffs = offss+4; + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + analysis->tmpx.ptr.p_double[i] = analysis->tmpx.ptr.p_double[i]-analysis->outputstorage.ptr.p_double[baseoffs]*x0-analysis->outputstorage.ptr.p_double[baseoffs+1]*x1; + baseoffs = baseoffs+2; + } + } + else + { + if( blocksize==3 ) + { + + /* + * Three columns + */ + baseoffs = offss+12; + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + analysis->tmpx.ptr.p_double[i] = analysis->tmpx.ptr.p_double[i]-analysis->outputstorage.ptr.p_double[baseoffs]*x0-analysis->outputstorage.ptr.p_double[baseoffs+1]*x1-analysis->outputstorage.ptr.p_double[baseoffs+2]*x2; + baseoffs = baseoffs+4; + } + } + else + { + if( blocksize==4 ) + { + + /* + * Four columns + */ + baseoffs = offss+16; + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + analysis->tmpx.ptr.p_double[i] = analysis->tmpx.ptr.p_double[i]-analysis->outputstorage.ptr.p_double[baseoffs]*x0-analysis->outputstorage.ptr.p_double[baseoffs+1]*x1-analysis->outputstorage.ptr.p_double[baseoffs+2]*x2-analysis->outputstorage.ptr.p_double[baseoffs+3]*x3; + baseoffs = baseoffs+4; + } + } + else + { + + /* + * Generic propagate + */ + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + baseoffs = offss+(k+blocksize)*sstride; + v = analysis->tmpx.ptr.p_double[i]; + for(j=0; j<=blocksize-1; j++) + { + v = v-analysis->outputstorage.ptr.p_double[baseoffs+j]*analysis->tmpx.ptr.p_double[cols0+j]; + } + analysis->tmpx.ptr.p_double[i] = v; + } + } + } + } + } + } + + /* + * Solve for D*tmp_x=rhs. + */ + for(i=0; i<=n-1; i++) + { + if( analysis->diagd.ptr.p_double[i]!=0.0 ) + { + analysis->tmpx.ptr.p_double[i] = analysis->tmpx.ptr.p_double[i]/analysis->diagd.ptr.p_double[i]; + } + else + { + analysis->tmpx.ptr.p_double[i] = 0.0; + } + } + + /* + * Solve for L'*tmp_x=rhs + * + */ + for(sidx=analysis->nsuper-1; sidx>=0; sidx--) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + rbase = analysis->superrowridx.ptr.p_int[sidx]; + offdiagsize = analysis->superrowridx.ptr.p_int[sidx+1]-rbase; + + /* + * Subtract already computed variables + */ + if( blocksize==1 ) + { + + /* + * Single column, use value fetched in X0 + */ + x0 = analysis->tmpx.ptr.p_double[cols0]; + baseoffs = offss+1; + for(k=0; k<=offdiagsize-1; k++) + { + x0 = x0-analysis->outputstorage.ptr.p_double[baseoffs]*analysis->tmpx.ptr.p_double[analysis->superrowidx.ptr.p_int[rbase+k]]; + baseoffs = baseoffs+1; + } + analysis->tmpx.ptr.p_double[cols0] = x0; + } + else + { + if( blocksize==2 ) + { + + /* + * Two columns, use values fetched in X0, X1 + */ + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + baseoffs = offss+4; + for(k=0; k<=offdiagsize-1; k++) + { + v = analysis->tmpx.ptr.p_double[analysis->superrowidx.ptr.p_int[rbase+k]]; + x0 = x0-analysis->outputstorage.ptr.p_double[baseoffs]*v; + x1 = x1-analysis->outputstorage.ptr.p_double[baseoffs+1]*v; + baseoffs = baseoffs+2; + } + analysis->tmpx.ptr.p_double[cols0] = x0; + analysis->tmpx.ptr.p_double[cols0+1] = x1; + } + else + { + if( blocksize==3 ) + { + + /* + * Three columns, use values fetched in X0, X1, X2 + */ + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + x2 = analysis->tmpx.ptr.p_double[cols0+2]; + baseoffs = offss+12; + for(k=0; k<=offdiagsize-1; k++) + { + v = analysis->tmpx.ptr.p_double[analysis->superrowidx.ptr.p_int[rbase+k]]; + x0 = x0-analysis->outputstorage.ptr.p_double[baseoffs]*v; + x1 = x1-analysis->outputstorage.ptr.p_double[baseoffs+1]*v; + x2 = x2-analysis->outputstorage.ptr.p_double[baseoffs+2]*v; + baseoffs = baseoffs+4; + } + analysis->tmpx.ptr.p_double[cols0] = x0; + analysis->tmpx.ptr.p_double[cols0+1] = x1; + analysis->tmpx.ptr.p_double[cols0+2] = x2; + } + else + { + if( blocksize==4 ) + { + + /* + * Four columns, use values fetched in X0, X1, X2, X3 + */ + x0 = analysis->tmpx.ptr.p_double[cols0]; + x1 = analysis->tmpx.ptr.p_double[cols0+1]; + x2 = analysis->tmpx.ptr.p_double[cols0+2]; + x3 = analysis->tmpx.ptr.p_double[cols0+3]; + baseoffs = offss+16; + for(k=0; k<=offdiagsize-1; k++) + { + v = analysis->tmpx.ptr.p_double[analysis->superrowidx.ptr.p_int[rbase+k]]; + x0 = x0-analysis->outputstorage.ptr.p_double[baseoffs]*v; + x1 = x1-analysis->outputstorage.ptr.p_double[baseoffs+1]*v; + x2 = x2-analysis->outputstorage.ptr.p_double[baseoffs+2]*v; + x3 = x3-analysis->outputstorage.ptr.p_double[baseoffs+3]*v; + baseoffs = baseoffs+4; + } + analysis->tmpx.ptr.p_double[cols0] = x0; + analysis->tmpx.ptr.p_double[cols0+1] = x1; + analysis->tmpx.ptr.p_double[cols0+2] = x2; + analysis->tmpx.ptr.p_double[cols0+3] = x3; + } + else + { + + /* + * Generic case + */ + for(k=0; k<=offdiagsize-1; k++) + { + baseoffs = offss+(k+blocksize)*sstride; + v = analysis->tmpx.ptr.p_double[analysis->superrowidx.ptr.p_int[rbase+k]]; + for(j=0; j<=blocksize-1; j++) + { + analysis->tmpx.ptr.p_double[cols0+j] = analysis->tmpx.ptr.p_double[cols0+j]-analysis->outputstorage.ptr.p_double[baseoffs+j]*v; + } + } + } + } + } + } + + /* + * Solve for variables in the supernode + */ + for(i=blocksize-1; i>=0; i--) + { + baseoffs = offss+i*sstride; + v = analysis->tmpx.ptr.p_double[cols0+i]/analysis->outputstorage.ptr.p_double[baseoffs+i]; + for(j=0; j<=i-1; j++) + { + analysis->tmpx.ptr.p_double[cols0+j] = analysis->tmpx.ptr.p_double[cols0+j]-v*analysis->outputstorage.ptr.p_double[baseoffs+j]; + } + analysis->tmpx.ptr.p_double[cols0+i] = v; + } + } + + /* + * Handle right-hand side permutation, convert data to internal SIMD-friendly format + */ + for(i=0; i<=n-1; i++) + { + b->ptr.p_double[i] = analysis->tmpx.ptr.p_double[analysis->effectiveperm.ptr.p_int[i]]; + } +} + + +/************************************************************************* +Compares diag(L*L') with that of the original A and returns two metrics: +* SumSq - sum of squares of diag(A) +* ErrSq - sum of squared errors, i.e. Frobenius norm of diag(L*L')-diag(A) + +These metrics can be used to check accuracy of the factorization. + +INPUT PARAMETERS: + Analysis - prior factorization performed on some sparse matrix + +OUTPUT PARAMETERS: + SumSq, ErrSq- diagonal magnitude and absolute diagonal error + +NOTE: this function can be unsupported by some Performance Backends, + in which case both ErrSq and SumSq will be exactly zero. + + -- ALGLIB routine -- + 08.09.2021 + Bochkanov Sergey +*************************************************************************/ +void spsymmdiagerr(spcholanalysis* analysis, + double* sumsq, + double* errsq, + ae_state *_state) +{ + ae_int_t n; + double v; + double vv; + ae_int_t simdwidth; + ae_int_t baseoffs; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t sstride; + ae_int_t sidx; + ae_int_t blocksize; + ae_int_t rbase; + ae_int_t offdiagsize; + ae_int_t i; + ae_int_t j; + ae_int_t k; + + *sumsq = 0.0; + *errsq = 0.0; + + n = analysis->n; + simdwidth = 1; + + /* + * Invoke Performance Backend Library, if present + */ + if( analysis->pblused ) + { + spchol_spsymmpbldiagerr(&analysis->pbl, sumsq, errsq, _state); + return; + } + + /* + * Scan L, compute diag(L*L') + */ + rsetallocv(simdwidth*n, 0.0, &analysis->simdbuf, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + rbase = analysis->superrowridx.ptr.p_int[sidx]; + offdiagsize = analysis->superrowridx.ptr.p_int[sidx+1]-rbase; + + /* + * Handle triangular diagonal block + */ + for(i=cols0; i<=cols1-1; i++) + { + baseoffs = offss+(i-cols0)*sstride+(-cols0); + v = (double)(0); + for(j=0; j<=simdwidth-1; j++) + { + v = v+analysis->simdbuf.ptr.p_double[i*simdwidth+j]; + } + for(j=cols0; j<=i; j++) + { + vv = analysis->outputstorage.ptr.p_double[baseoffs+j]; + v = v+vv*vv*analysis->diagd.ptr.p_double[j]; + } + *sumsq = *sumsq+ae_sqr(analysis->inputstorage.ptr.p_double[baseoffs+i], _state); + *errsq = *errsq+ae_sqr(analysis->inputstorage.ptr.p_double[baseoffs+i]-v, _state); + } + + /* + * Accumulate entries below triangular diagonal block + */ + for(k=0; k<=offdiagsize-1; k++) + { + i = analysis->superrowidx.ptr.p_int[rbase+k]; + baseoffs = offss+(k+blocksize)*sstride; + v = analysis->simdbuf.ptr.p_double[i*simdwidth]; + for(j=0; j<=blocksize-1; j++) + { + vv = analysis->outputstorage.ptr.p_double[baseoffs+j]; + v = v+vv*vv*analysis->diagd.ptr.p_double[cols0+j]; + } + analysis->simdbuf.ptr.p_double[i*simdwidth] = v; + } + } +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Informational function, useful for debugging +*************************************************************************/ +static ae_int_t spchol_spsymmgetmaxsimd(ae_state *_state) +{ + ae_int_t result; + + + result = 1; + return result; +} +#endif + + +/************************************************************************* +Tries to setup Performance Backend Library (PBL) for sparse factorizations. + +Returns True on success, False on failure to setup the library (due to the +library being unavailable or problem size being too small). Also sets +Analysis.PBLUsed to the value returned. + +This function assumes than Analysis is partially initialized, with the +following fields being set: +* Analysis.TaskType +* Analysis.N +* Analysis.UnitD +* Analysis.PBLUsed=False +* Analysis.DoTrace + +If False is returned, the caller is responsible for the continuation of +the factorization. + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_spsymmpblsetup(spcholanalysis* analysis, + const sparsematrix* a, + /* Integer */ const ae_vector* priorities, + ae_int_t facttype, + ae_int_t permtype, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_bool result; + + + ae_assert(((((((permtype==0||permtype==1)||permtype==2)||permtype==3)||permtype==-1)||permtype==-2)||permtype==-3)||permtype==-4, "SPSymmPBLSetup: unexpected PermType", _state); + ae_assert(facttype==20||facttype==21, "SPSymmPBLSetup: unexpected FactType", _state); + n = analysis->n; + analysis->pblused = ae_false; + result = ae_false; + if( spchol_spsymmpblhasdss(_state) ) + { + if( analysis->dotrace ) + { + ae_trace("> detected support for DSS in a Performance Backend Library, trying to initialize the library\n"); + } + sparsecopytransposecrsxbuf(a, -1, &analysis->pbla, _state); + if( (permtype==-4||permtype==-3)||permtype==3 ) + { + icopyallocv(analysis->n, priorities, &analysis->curpriorities, _state); + } + else + { + isetallocv(analysis->n, 0, &analysis->curpriorities, _state); + } + if( !spchol_spsymmpblsetupdss(&analysis->pbl, &analysis->pbla, analysis->n, &analysis->curpriorities, facttype, permtype, analysis->dotrace, _state) ) + { + return result; + } + icopyallocv(n, &analysis->curpriorities, &analysis->fillinperm, _state); + isetallocv(n, -1, &analysis->invfillinperm, _state); + for(i=0; i<=n-1; i++) + { + j = analysis->fillinperm.ptr.p_int[i]; + if( j<0||j>=n ) + { + ae_assert(ae_false, "SPSymmAnalyze: permutation passed to / returned by PBL has indexes outside of [0,N) range", _state); + } + if( analysis->invfillinperm.ptr.p_int[j]>=0 ) + { + ae_assert(ae_false, "SPSymmAnalyze: permutation passed to / returned by PBL has non-distinct indexes", _state); + } + analysis->invfillinperm.ptr.p_int[j] = i; + } + icopyallocv(n, &analysis->fillinperm, &analysis->effectiveperm, _state); + icopyallocv(n, &analysis->invfillinperm, &analysis->inveffectiveperm, _state); + analysis->pblneedsl = ae_false; + analysis->pblachanged = ae_false; + analysis->pblused = ae_true; + result = ae_true; + return result; + } + return result; +} + + +/************************************************************************* +This function detects DSS backend support. + +It can return False if: +* no DSS backend is linked +* a DSS backend is linked but signaled that it is not ready to provide + services. +* a DSS backend is linked and ready to run, but current ALGLIB flags + prohibit external DSS activation. The result of this function depends + on both call-local and global flags. The latter ones can change at + any moment. + +This function is allowed to return different values at different moments, +so code using it should not rely on the same value being always returned. + +This function should be used as a relatively inexpensive gatekeeper for +SPSymmPBLSetupDSS(). + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_spsymmpblhasdss(ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +This function tries to setup a direct sparse solver (DSS). + +It may return False: +* if no DSS backend is linked +* if a DSS backend is linked, but not ready to run +* if ALGLIB flags prohibit DSS backend usage +* even if previous call to SPSymmPBLHasDSS() returned True + +The code using this function should be ready to handle False value returned. + +If it returned True, the DSS opaque object can be used for the rest of its +life (even if ALGLIB flags started to prohibit usage of a DSS backend). + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_spsymmpblsetupdss(ae_opaque_object* pbl, + sparsematrix* tmpat, + ae_int_t n, + /* Integer */ ae_vector* priorities, + ae_int_t facttype, + ae_int_t permtype, + ae_bool dotrace, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +Stub for PBL factorizer call + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_spsymmpblfactorize(ae_opaque_object* pbl, + sparsematrix* a, + ae_bool achanged, + ae_state *_state) +{ + ae_bool result; + + + ae_assert(ae_false, "SPSymmPBLFactorize: no PBL support is enabled, but stub was called", _state); + result = ae_false; + return result; +} + + +/************************************************************************* +Stub for PBL solver call + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_spsymmpblsolve(ae_opaque_object* pbl, + sparsematrix* a, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + ae_assert(ae_false, "SPSymmPBLSolve: no PBL support is enabled, but stub was called", _state); + return result; +} + + +/************************************************************************* +Stub for PBL diagonal error call + + -- ALGLIB routine -- + 20.10.2025 + Bochkanov Sergey +*************************************************************************/ +static void spchol_spsymmpbldiagerr(ae_opaque_object* pbl, + double* sumsq, + double* errsq, + ae_state *_state) +{ + + *sumsq = 0.0; + *errsq = 0.0; + + *sumsq = (double)(0); + *errsq = (double)(0); + ae_assert(ae_false, "SPSymmPBLDiagErr: no PBL support is enabled, but stub was called", _state); +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Solving linear system: propagating computed supernode. + +Propagates computed supernode to the rest of the RHS using SIMD-friendly +RHS storage format. + +INPUT PARAMETERS: + +OUTPUT PARAMETERS: + + -- ALGLIB routine -- + 08.09.2021 + Bochkanov Sergey +*************************************************************************/ +static void spchol_propagatefwd(/* Real */ const ae_vector* x, + ae_int_t cols0, + ae_int_t blocksize, + /* Integer */ const ae_vector* superrowidx, + ae_int_t rbase, + ae_int_t offdiagsize, + /* Real */ const ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sstride, + /* Real */ ae_vector* simdbuf, + ae_int_t simdwidth, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t baseoffs; + double v; + + + for(k=0; k<=offdiagsize-1; k++) + { + i = superrowidx->ptr.p_int[rbase+k]; + baseoffs = offss+(k+blocksize)*sstride; + v = simdbuf->ptr.p_double[i*simdwidth]; + for(j=0; j<=blocksize-1; j++) + { + v = v-rowstorage->ptr.p_double[baseoffs+j]*x->ptr.p_double[cols0+j]; + } + simdbuf->ptr.p_double[i*simdwidth] = v; + } +} +#endif + + +/************************************************************************* +This function generates test reodering used for debug purposes only + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format + N - problem size + +OUTPUT PARAMETERS + Perm - array[N], maps original indexes I to permuted indexes + InvPerm - array[N], maps permuted indexes I to original indexes + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_generatedbgpermutation(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_vector d; + ae_vector tmpr; + ae_vector tmpperm; + + ae_frame_make(_state, &_frame_block); + memset(&d, 0, sizeof(d)); + memset(&tmpr, 0, sizeof(tmpr)); + memset(&tmpperm, 0, sizeof(tmpperm)); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpperm, 0, DT_INT, _state, ae_true); + + + /* + * Initialize D by vertex degrees + */ + rsetallocv(n, (double)(0), &d, _state); + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->didx.ptr.p_int[i]-1; + d.ptr.p_double[i] = (double)(j1-j0+1); + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + d.ptr.p_double[j] = d.ptr.p_double[j]+(double)1; + } + } + + /* + * Prepare permutation that orders vertices by degrees + */ + iallocv(n, invperm, _state); + for(i=0; i<=n-1; i++) + { + invperm->ptr.p_int[i] = i; + } + tagsortfasti(&d, invperm, &tmpr, &tmpperm, n, _state); + iallocv(n, perm, _state); + for(i=0; i<=n-1; i++) + { + perm->ptr.p_int[invperm->ptr.p_int[i]] = i; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function builds elimination tree in the original column order + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format + N - problem size + Parent, + tAbove - preallocated temporary array, length at least N+1, no + meaningful output is provided in these variables + +OUTPUT PARAMETERS + Parent - array[N], Parent[I] contains index of parent of I-th + column. -1 is used to denote column with no parents. + + -- ALGLIB PROJECT -- + Copyright 15.08.2021 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_buildunorderedetree(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* parent, + /* Integer */ ae_vector* tabove, + ae_state *_state) +{ + ae_int_t r; + ae_int_t abover; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + + + ae_assert(parent->cnt>=n+1, "BuildUnorderedETree: input buffer Parent is too short", _state); + ae_assert(tabove->cnt>=n+1, "BuildUnorderedETree: input buffer tAbove is too short", _state); + + /* + * Build elimination tree using Liu's algorithm with path compression + */ + for(j=0; j<=n-1; j++) + { + parent->ptr.p_int[j] = n; + tabove->ptr.p_int[j] = n; + j0 = a->ridx.ptr.p_int[j]; + j1 = a->didx.ptr.p_int[j]-1; + for(jj=j0; jj<=j1; jj++) + { + r = a->idx.ptr.p_int[jj]; + abover = tabove->ptr.p_int[r]; + while(aboverptr.p_int[r] = j; + r = k; + abover = tabove->ptr.p_int[r]; + } + if( abover==n ) + { + tabove->ptr.p_int[r] = j; + parent->ptr.p_int[r] = j; + } + } + } + + /* + * Convert to external format + */ + for(i=0; i<=n-1; i++) + { + if( parent->ptr.p_int[i]==n ) + { + parent->ptr.p_int[i] = -1; + } + } +} + + +/************************************************************************* +This function analyzes elimination tree stored using 'parent-of-node' +format and converts it to the 'childrens-of-node' format. + +INPUT PARAMETERS + Parent - array[N], supernodal etree + N - problem size + ChildrenR, + ChildrenI, + tTmp0 - preallocated arrays, length at least N+1 + +OUTPUT PARAMETERS + ChildrenR - array[N+1], children range (see below) + ChildrenI - array[N+1], childrens of K-th node are stored in the + elements ChildrenI[ChildrenR[K]...ChildrenR[K+1]-1] + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_fromparenttochildren(/* Integer */ const ae_vector* parent, + ae_int_t n, + /* Integer */ ae_vector* childrenr, + /* Integer */ ae_vector* childreni, + /* Integer */ ae_vector* ttmp0, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t nodeidx; + + + ae_assert(ttmp0->cnt>=n+1, "FromParentToChildren: input buffer tTmp0 is too short", _state); + ae_assert(childrenr->cnt>=n+1, "FromParentToChildren: input buffer ChildrenR is too short", _state); + ae_assert(childreni->cnt>=n+1, "FromParentToChildren: input buffer ChildrenI is too short", _state); + + /* + * Convert etree from per-column parent array to per-column children list + */ + isetv(n, 0, ttmp0, _state); + for(i=0; i<=n-1; i++) + { + nodeidx = parent->ptr.p_int[i]; + if( nodeidx>=0 ) + { + ttmp0->ptr.p_int[nodeidx] = ttmp0->ptr.p_int[nodeidx]+1; + } + } + childrenr->ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + childrenr->ptr.p_int[i+1] = childrenr->ptr.p_int[i]+ttmp0->ptr.p_int[i]; + } + isetv(n, 0, ttmp0, _state); + for(i=0; i<=n-1; i++) + { + k = parent->ptr.p_int[i]; + if( k>=0 ) + { + childreni->ptr.p_int[childrenr->ptr.p_int[k]+ttmp0->ptr.p_int[k]] = i; + ttmp0->ptr.p_int[k] = ttmp0->ptr.p_int[k]+1; + } + } +} + + +/************************************************************************* +This function builds elimination tree and reorders it according to the +topological post-ordering. + +INPUT PARAMETERS + A - lower triangular sparse matrix in CRS format + N - problem size + + tRawParentOfRawNode, + tRawParentOfReorderedNode, + tTmp, + tFlagArray - preallocated temporary arrays, length at least N+1, no + meaningful output is provided in these variables + +OUTPUT PARAMETERS + Parent - array[N], Parent[I] contains index of parent of I-th + column (after topological reordering). -1 is used to + denote column with no parents. + SupernodalPermutation + - array[N], maps original indexes I to permuted indexes + InvSupernodalPermutation + - array[N], maps permuted indexes I to original indexes + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_buildorderedetree(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* parent, + /* Integer */ ae_vector* supernodalpermutation, + /* Integer */ ae_vector* invsupernodalpermutation, + /* Integer */ ae_vector* trawparentofrawnode, + /* Integer */ ae_vector* trawparentofreorderednode, + /* Integer */ ae_vector* ttmp, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t sidx; + ae_int_t unprocessedchildrencnt; + + + ae_assert(trawparentofrawnode->cnt>=n+1, "BuildOrderedETree: input buffer tRawParentOfRawNode is too short", _state); + ae_assert(ttmp->cnt>=n+1, "BuildOrderedETree: input buffer tTmp is too short", _state); + ae_assert(trawparentofreorderednode->cnt>=n+1, "BuildOrderedETree: input buffer tRawParentOfReorderedNode is too short", _state); + ae_assert(tflagarray->cnt>=n+1, "BuildOrderedETree: input buffer tFlagArray is too short", _state); + + /* + * Avoid spurious compiler warnings + */ + unprocessedchildrencnt = 0; + + /* + * Build elimination tree with original column order + */ + spchol_buildunorderedetree(a, n, trawparentofrawnode, ttmp, _state); + + /* + * Compute topological ordering of the elimination tree, produce: + * * direct and inverse permutations + * * reordered etree stored in Parent[] + */ + isetallocv(n, -1, invsupernodalpermutation, _state); + isetallocv(n, -1, supernodalpermutation, _state); + isetallocv(n, -1, parent, _state); + isetv(n, -1, trawparentofreorderednode, _state); + isetv(n, 0, ttmp, _state); + for(i=0; i<=n-1; i++) + { + k = trawparentofrawnode->ptr.p_int[i]; + if( k>=0 ) + { + ttmp->ptr.p_int[k] = ttmp->ptr.p_int[k]+1; + } + } + bsetv(n, ae_true, tflagarray, _state); + sidx = 0; + for(i=0; i<=n-1; i++) + { + if( tflagarray->ptr.p_bool[i] ) + { + + /* + * Move column I to position SIdx, decrease unprocessed children count + */ + supernodalpermutation->ptr.p_int[i] = sidx; + invsupernodalpermutation->ptr.p_int[sidx] = i; + tflagarray->ptr.p_bool[i] = ae_false; + k = trawparentofrawnode->ptr.p_int[i]; + trawparentofreorderednode->ptr.p_int[sidx] = k; + if( k>=0 ) + { + unprocessedchildrencnt = ttmp->ptr.p_int[k]-1; + ttmp->ptr.p_int[k] = unprocessedchildrencnt; + } + sidx = sidx+1; + + /* + * Add parents (as long as parent has no unprocessed children) + */ + while(k>=0&&unprocessedchildrencnt==0) + { + supernodalpermutation->ptr.p_int[k] = sidx; + invsupernodalpermutation->ptr.p_int[sidx] = k; + tflagarray->ptr.p_bool[k] = ae_false; + k = trawparentofrawnode->ptr.p_int[k]; + trawparentofreorderednode->ptr.p_int[sidx] = k; + if( k>=0 ) + { + unprocessedchildrencnt = ttmp->ptr.p_int[k]-1; + ttmp->ptr.p_int[k] = unprocessedchildrencnt; + } + sidx = sidx+1; + } + } + } + for(i=0; i<=n-1; i++) + { + k = trawparentofreorderednode->ptr.p_int[i]; + if( k>=0 ) + { + parent->ptr.p_int[i] = supernodalpermutation->ptr.p_int[k]; + } + } +} + + +/************************************************************************* +This function analyzes postordered elimination tree and creates supernodal +structure in Analysis object. + +INPUT PARAMETERS + AT - upper triangular CRS matrix, transpose and reordering + of the original input matrix A + Parent - array[N], supernodal etree + N - problem size + + tChildrenR, + tChildrenI, + tParentNodeOfSupernode, + tNode2Supernode, + tTmp0, + tFlagArray - temporary arrays, length at least N+1, simply provide + preallocated place. + +OUTPUT PARAMETERS + Analysis - following fields are initialized: + * Analysis.NSuper + * Analysis.SuperColRange + * Analysis.SuperRowRIdx + * Analysis.SuperRowIdx + * Analysis.ParentSupernode + * Analysis.ChildSupernodesRIdx, Analysis.ChildSupernodesIdx + * Analysis.OutRowCounts + * Analysis.NS1BooleanPool + * Analysis.NS1IntegerPool + * Analysis.NS1RealPool + other fields are ignored and not changed. + Node2Supernode- array[N] that maps node indexes to supernode indexes + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_createsupernodalstructure(const sparsematrix* at, + /* Integer */ const ae_vector* parent, + ae_int_t n, + spcholanalysis* analysis, + /* Integer */ ae_vector* node2supernode, + /* Integer */ ae_vector* tchildrenr, + /* Integer */ ae_vector* tchildreni, + /* Integer */ ae_vector* tparentnodeofsupernode, + /* Integer */ ae_vector* tfakenonzeros, + /* Integer */ ae_vector* ttmp0, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state) +{ + ae_int_t nsuper; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t sidx; + ae_int_t i0; + ae_int_t ii; + ae_int_t columnidx; + ae_int_t nodeidx; + ae_int_t rfirst; + ae_int_t rlast; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t blocksize; + ae_bool createsupernode; + ae_int_t colcount; + ae_int_t offdiagcnt; + ae_int_t childcolcount; + ae_int_t childoffdiagcnt; + ae_int_t fakezerosinnewsupernode; + double mergeinefficiency; + ae_bool hastheonlychild; + + + ae_assert(ttmp0->cnt>=n+1, "CreateSupernodalStructure: input buffer tTmp0 is too short", _state); + ae_assert(tchildrenr->cnt>=n+1, "CreateSupernodalStructure: input buffer ChildrenR is too short", _state); + ae_assert(tchildreni->cnt>=n+1, "CreateSupernodalStructure: input buffer ChildrenI is too short", _state); + ae_assert(tparentnodeofsupernode->cnt>=n+1, "CreateSupernodalStructure: input buffer tParentNodeOfSupernode is too short", _state); + ae_assert(tfakenonzeros->cnt>=n+1, "CreateSupernodalStructure: input buffer tFakeNonzeros is too short", _state); + ae_assert(tflagarray->cnt>=n+1, "CreateSupernodalStructure: input buffer tFlagArray is too short", _state); + + /* + * Trace + */ + if( analysis->dotracesupernodalstructure ) + { + ae_trace("=== GENERATING SUPERNODAL STRUCTURE ================================================================\n"); + } + + /* + * Convert etree from per-column parent array to per-column children list + */ + spchol_fromparenttochildren(parent, n, tchildrenr, tchildreni, ttmp0, _state); + + /* + * Analyze supernodal structure: + * * determine children count for each node + * * combine chains of children into supernodes + * * generate direct and inverse supernodal (topological) permutations + * * generate column structure of supernodes (after supernodal permutation) + */ + isetallocv(n, -1, node2supernode, _state); + ivectorsetlengthatleast(&analysis->supercolrange, n+1, _state); + ivectorsetlengthatleast(&analysis->superrowridx, n+1, _state); + isetv(n, n+1, tparentnodeofsupernode, _state); + bsetv(n, ae_true, tflagarray, _state); + nsuper = 0; + analysis->supercolrange.ptr.p_int[0] = 0; + analysis->superrowridx.ptr.p_int[0] = 0; + while(analysis->supercolrange.ptr.p_int[nsuper]supercolrange.ptr.p_int[nsuper]; + + /* + * Compute nonzero pattern of the column, create temporary standalone node + * for possible supernodal merge. Newly created node has just one column + * and no fake nonzeros. + */ + rfirst = analysis->superrowridx.ptr.p_int[nsuper]; + rlast = spchol_computenonzeropattern(at, columnidx, n, &analysis->superrowridx, &analysis->superrowidx, nsuper, tchildrenr, tchildreni, node2supernode, tflagarray, ttmp0, _state); + analysis->supercolrange.ptr.p_int[nsuper+1] = columnidx+1; + analysis->superrowridx.ptr.p_int[nsuper+1] = rlast; + node2supernode->ptr.p_int[columnidx] = nsuper; + tparentnodeofsupernode->ptr.p_int[nsuper] = parent->ptr.p_int[columnidx]; + tfakenonzeros->ptr.p_int[nsuper] = 0; + offdiagcnt = rlast-rfirst; + colcount = 1; + nsuper = nsuper+1; + if( analysis->dotracesupernodalstructure ) + { + ae_trace("> incoming column %0d\n", + (int)(columnidx)); + ae_trace("offdiagnnz = %0d\n", + (int)(rlast-rfirst)); + ae_trace("children = [ "); + for(i=tchildrenr->ptr.p_int[columnidx]; i<=tchildrenr->ptr.p_int[columnidx+1]-1; i++) + { + ae_trace("S%0d ", + (int)(node2supernode->ptr.p_int[tchildreni->ptr.p_int[i]])); + } + ae_trace("]\n"); + } + + /* + * Decide whether to merge column with previous supernode or not + */ + childcolcount = 0; + childoffdiagcnt = 0; + mergeinefficiency = 0.0; + fakezerosinnewsupernode = 0; + createsupernode = ae_false; + hastheonlychild = ae_false; + if( nsuper>=2&&tparentnodeofsupernode->ptr.p_int[nsuper-2]==columnidx ) + { + childcolcount = analysis->supercolrange.ptr.p_int[nsuper-1]-analysis->supercolrange.ptr.p_int[nsuper-2]; + childoffdiagcnt = analysis->superrowridx.ptr.p_int[nsuper-1]-analysis->superrowridx.ptr.p_int[nsuper-2]; + hastheonlychild = tchildrenr->ptr.p_int[columnidx+1]-tchildrenr->ptr.p_int[columnidx]==1; + if( (hastheonlychild||spchol_relaxedsupernodes)&&colcount+childcolcount<=spchol_maxsupernode ) + { + i = colcount+childcolcount; + k = i*(i+1)/2+offdiagcnt*i; + fakezerosinnewsupernode = tfakenonzeros->ptr.p_int[nsuper-2]+tfakenonzeros->ptr.p_int[nsuper-1]+(offdiagcnt-(childoffdiagcnt-1))*childcolcount; + mergeinefficiency = (double)fakezerosinnewsupernode/(double)k; + if( colcount+childcolcount==2&&fakezerosinnewsupernode<=spchol_smallfakestolerance ) + { + createsupernode = ae_true; + } + if( ae_fp_less_eq(mergeinefficiency,spchol_maxmergeinefficiency) ) + { + createsupernode = ae_true; + } + } + } + + /* + * Create supernode if needed + */ + if( createsupernode ) + { + + /* + * Create supernode from nodes NSuper-2 and NSuper-1. + * Because these nodes are in the child-parent relation, we can simply + * copy nonzero pattern from NSuper-1. + */ + ae_assert(tparentnodeofsupernode->ptr.p_int[nsuper-2]==columnidx, "CreateSupernodalStructure: integrity check 9472 failed", _state); + i0 = analysis->superrowridx.ptr.p_int[nsuper-1]; + ii = analysis->superrowridx.ptr.p_int[nsuper]-analysis->superrowridx.ptr.p_int[nsuper-1]; + rfirst = analysis->superrowridx.ptr.p_int[nsuper-2]; + rlast = rfirst+ii; + for(i=0; i<=ii-1; i++) + { + analysis->superrowidx.ptr.p_int[rfirst+i] = analysis->superrowidx.ptr.p_int[i0+i]; + } + analysis->supercolrange.ptr.p_int[nsuper-1] = columnidx+1; + analysis->superrowridx.ptr.p_int[nsuper-1] = rlast; + node2supernode->ptr.p_int[columnidx] = nsuper-2; + tfakenonzeros->ptr.p_int[nsuper-2] = fakezerosinnewsupernode; + tparentnodeofsupernode->ptr.p_int[nsuper-2] = parent->ptr.p_int[columnidx]; + nsuper = nsuper-1; + + /* + * Trace + */ + if( analysis->dotracesupernodalstructure ) + { + ae_trace("> merged with supernode S%0d", + (int)(nsuper-1)); + if( ae_fp_neq(mergeinefficiency,(double)(0)) ) + { + ae_trace(" (%2.0f%% inefficiency)", + (double)(mergeinefficiency*(double)100)); + } + ae_trace("\n*\n"); + } + } + else + { + + /* + * Trace + */ + if( analysis->dotracesupernodalstructure ) + { + ae_trace("> standalone node S%0d created\n*\n", + (int)(nsuper-1)); + } + } + } + analysis->nsuper = nsuper; + ae_assert(analysis->nsuper>=1, "SPSymmAnalyze: integrity check failed (95mgd)", _state); + ae_assert(analysis->supercolrange.ptr.p_int[0]==0, "SPCholFactorize: integrity check failed (f446s)", _state); + ae_assert(analysis->supercolrange.ptr.p_int[nsuper]==n, "SPSymmAnalyze: integrity check failed (04ut4)", _state); + isetallocv(nsuper, -1, &analysis->parentsupernode, _state); + for(sidx=0; sidx<=nsuper-1; sidx++) + { + nodeidx = tparentnodeofsupernode->ptr.p_int[sidx]; + if( nodeidx>=0 ) + { + nodeidx = node2supernode->ptr.p_int[nodeidx]; + analysis->parentsupernode.ptr.p_int[sidx] = nodeidx; + } + } + iallocv(nsuper+2, &analysis->childsupernodesridx, _state); + iallocv(nsuper+1, &analysis->childsupernodesidx, _state); + spchol_fromparenttochildren(&analysis->parentsupernode, nsuper, &analysis->childsupernodesridx, &analysis->childsupernodesidx, ttmp0, _state); + i = analysis->childsupernodesridx.ptr.p_int[nsuper]; + for(sidx=0; sidx<=nsuper-1; sidx++) + { + j = analysis->parentsupernode.ptr.p_int[sidx]; + if( j<0 ) + { + analysis->childsupernodesidx.ptr.p_int[i] = sidx; + i = i+1; + } + } + ae_assert(i==nsuper, "SPSymmAnalyze: integrity check 4dr5 failed", _state); + analysis->childsupernodesridx.ptr.p_int[nsuper+1] = i; + + /* + * Allocate supernodal storage + */ + ivectorsetlengthatleast(&analysis->rowoffsets, analysis->nsuper+1, _state); + ivectorsetlengthatleast(&analysis->rowstrides, analysis->nsuper, _state); + analysis->rowoffsets.ptr.p_int[0] = 0; + for(i=0; i<=analysis->nsuper-1; i++) + { + blocksize = analysis->supercolrange.ptr.p_int[i+1]-analysis->supercolrange.ptr.p_int[i]; + analysis->rowstrides.ptr.p_int[i] = spchol_recommendedstridefor(blocksize, _state); + analysis->rowoffsets.ptr.p_int[i+1] = analysis->rowoffsets.ptr.p_int[i]; + analysis->rowoffsets.ptr.p_int[i+1] = analysis->rowoffsets.ptr.p_int[i+1]+analysis->rowstrides.ptr.p_int[i]*blocksize; + analysis->rowoffsets.ptr.p_int[i+1] = analysis->rowoffsets.ptr.p_int[i+1]+analysis->rowstrides.ptr.p_int[i]*(analysis->superrowridx.ptr.p_int[i+1]-analysis->superrowridx.ptr.p_int[i]); + analysis->rowoffsets.ptr.p_int[i+1] = spchol_alignpositioninarray(analysis->rowoffsets.ptr.p_int[i+1], _state); + } + + /* + * Analyze output structure + */ + isetallocv(n, 0, &analysis->outrowcounts, _state); + for(sidx=0; sidx<=nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + rfirst = analysis->superrowridx.ptr.p_int[sidx]; + rlast = analysis->superrowridx.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + for(j=cols0; j<=cols1-1; j++) + { + analysis->outrowcounts.ptr.p_int[j] = analysis->outrowcounts.ptr.p_int[j]+(j-cols0+1); + } + for(ii=rfirst; ii<=rlast-1; ii++) + { + i0 = analysis->superrowidx.ptr.p_int[ii]; + analysis->outrowcounts.ptr.p_int[i0] = analysis->outrowcounts.ptr.p_int[i0]+blocksize; + } + } + + /* + * Allocate the pool + */ + ae_nxpool_alloc(&analysis->ns1booleanpool, nsuper+1, _state); + ae_nxpool_alloc(&analysis->ns1integerpool, nsuper+1, _state); + ae_nxpool_alloc(&analysis->ns1realpool, nsuper+1, _state); +} + + +/************************************************************************* +This function analyzes supernodal structure and precomputes dependency +matrix LAdj+ + +INPUT PARAMETERS + Analysis - analysis object with completely initialized supernodal + structure + RawA - original (before reordering) input matrix + Node2Supernode- mapping from node to supernode indexes + N - problem size + + tTmp0, + tTmp1, + tFlagArray - temporary arrays, length at least N+1, simply provide + preallocated place. + +OUTPUT PARAMETERS + Analysis - Analysis.LAdj is initialized + Node2Supernode- array[N] that maps node indexes to supernode indexes + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_analyzesupernodaldependencies(spcholanalysis* analysis, + const sparsematrix* rawa, + /* Integer */ const ae_vector* node2supernode, + ae_int_t n, + /* Integer */ ae_vector* ttmp0, + /* Integer */ ae_vector* ttmp1, + /* Boolean */ ae_vector* tflagarray, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t rowidx; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t rfirst; + ae_int_t rlast; + ae_int_t sidx; + ae_int_t uidx; + ae_int_t ladjcnt; + ae_int_t dbgnzl; + ae_int_t dbgrank1nodes; + ae_int_t dbgrank2nodes; + ae_int_t dbgrank3nodes; + ae_int_t dbgrank4nodes; + ae_int_t dbgbignodes; + double dbgtotalflop; + double dbgnoscatterflop; + double dbgnorowscatterflop; + double dbgnocolscatterflop; + double dbgcholeskyflop; + double dbgcholesky4flop; + double dbgrank1flop; + double dbgrank4plusflop; + double dbg444flop; + double dbgxx4flop; + double uflop; + double sflop; + double fflop; + double totalflop; + double longestpath; + ae_int_t wrkrow; + ae_int_t offdiagrow; + ae_int_t lastrow; + ae_int_t uwidth; + ae_int_t uheight; + ae_int_t urank; + ae_int_t theight; + ae_int_t twidth; + ae_vector dbgfastestpath; + ae_vector criticalpath; + + ae_frame_make(_state, &_frame_block); + memset(&dbgfastestpath, 0, sizeof(dbgfastestpath)); + memset(&criticalpath, 0, sizeof(criticalpath)); + ae_vector_init(&dbgfastestpath, 0, DT_REAL, _state, ae_true); + ae_vector_init(&criticalpath, 0, DT_REAL, _state, ae_true); + + ae_assert(ttmp0->cnt>=n+1, "AnalyzeSupernodalDependencies: input buffer tTmp0 is too short", _state); + ae_assert(ttmp1->cnt>=n+1, "AnalyzeSupernodalDependencies: input buffer tTmp1 is too short", _state); + ae_assert(tflagarray->cnt>=n+1, "AnalyzeSupernodalDependencies: input buffer tTmp0 is too short", _state); + ae_assert(sparseiscrs(rawa, _state), "AnalyzeSupernodalDependencies: RawA must be CRS matrix", _state); + + /* + * Determine LAdj - supernodes feeding updates to the SIdx-th one. + * + * Without supernodes we have: K-th row of L (also denoted as ladj+(K)) + * includes original nonzeros from A (also denoted as ladj(K)) as well + * as all elements on paths in elimination tree from ladj(K) to K. + * + * With supernodes: same principle applied. + */ + ae_nxpool_retrieve(&analysis->ns1realpool, &criticalpath, _state); + isetallocv(analysis->nsuper, 0, &analysis->ladj.rowbegin, _state); + isetallocv(analysis->nsuper, 0, &analysis->ladj.rowend, _state); + rsetallocv(analysis->nsuper, (double)(0), &analysis->ladj.nflop, _state); + if( analysis->dotrace ) + { + rsetallocv(analysis->nsuper, (double)(0), &dbgfastestpath, _state); + } + bsetv(n, ae_true, tflagarray, _state); + rsetv(analysis->nsuper, 0.0, &criticalpath, _state); + icopyv(analysis->nsuper, &analysis->superrowridx, ttmp0, _state); + ladjcnt = 0; + totalflop = 0.0; + longestpath = 0.0; + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + + /* + * Generate ordered list of nodes feeding updates to SIdx-th one + */ + igrowv(ladjcnt+analysis->nsuper, &analysis->ladj.idx, _state); + igrowv(ladjcnt+analysis->nsuper, &analysis->ladj.urow0, _state); + igrowv(ladjcnt+analysis->nsuper, &analysis->ladj.uwidth, _state); + rgrowv(ladjcnt+analysis->nsuper, &analysis->ladj.uflop, _state); + rfirst = ladjcnt; + rlast = rfirst; + analysis->ladj.rowbegin.ptr.p_int[sidx] = rfirst; + for(rowidx=analysis->supercolrange.ptr.p_int[sidx]; rowidx<=analysis->supercolrange.ptr.p_int[sidx+1]-1; rowidx++) + { + i = analysis->invsuperperm.ptr.p_int[rowidx]; + j0 = rawa->ridx.ptr.p_int[i]; + j1 = rawa->uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = node2supernode->ptr.p_int[analysis->superperm.ptr.p_int[rawa->idx.ptr.p_int[jj]]]; + + /* + * add supernode and its parents up the chain + */ + while((j>=0&&jptr.p_bool[j]) + { + analysis->ladj.idx.ptr.p_int[rlast] = j; + tflagarray->ptr.p_bool[j] = ae_false; + rlast = rlast+1; + j = analysis->parentsupernode.ptr.p_int[j]; + } + } + } + sortmiddlei(&analysis->ladj.idx, rfirst, rlast-rfirst, _state); + + /* + * Compute update-related information + */ + sflop = (double)(0); + twidth = analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]; + theight = twidth+(analysis->superrowridx.ptr.p_int[sidx+1]-analysis->superrowridx.ptr.p_int[sidx]); + for(i=rfirst; i<=rlast-1; i++) + { + j = analysis->ladj.idx.ptr.p_int[i]; + wrkrow = ttmp0->ptr.p_int[j]; + offdiagrow = wrkrow; + lastrow = analysis->superrowridx.ptr.p_int[j+1]; + while(offdiagrowsuperrowidx.ptr.p_int[offdiagrow]supercolrange.ptr.p_int[sidx+1]) + { + offdiagrow = offdiagrow+1; + } + uflop = (double)((offdiagrow-wrkrow)*(lastrow-wrkrow)*(analysis->supercolrange.ptr.p_int[j+1]-analysis->supercolrange.ptr.p_int[j])); + analysis->ladj.urow0.ptr.p_int[i] = wrkrow; + analysis->ladj.uwidth.ptr.p_int[i] = offdiagrow-wrkrow; + analysis->ladj.uflop.ptr.p_double[i] = uflop; + criticalpath.ptr.p_double[sidx] = ae_maxreal(criticalpath.ptr.p_double[sidx], criticalpath.ptr.p_double[j], _state)+uflop; + sflop = sflop+uflop; + ttmp0->ptr.p_int[j] = offdiagrow; + } + fflop = 0.0; + for(i=0; i<=twidth-1; i++) + { + fflop = fflop+(double)((theight-i)*(twidth-i)); + } + sflop = sflop+fflop; + analysis->ladj.nflop.ptr.p_double[sidx] = sflop; + criticalpath.ptr.p_double[sidx] = criticalpath.ptr.p_double[sidx]+fflop; + longestpath = ae_maxreal(longestpath, criticalpath.ptr.p_double[sidx], _state); + totalflop = totalflop+sflop; + j = analysis->parentsupernode.ptr.p_int[sidx]; + if( analysis->dotrace&&j>=0 ) + { + dbgfastestpath.ptr.p_double[j] = ae_maxreal(dbgfastestpath.ptr.p_double[j], sflop+dbgfastestpath.ptr.p_double[sidx], _state); + } + + /* + * Finalize + */ + for(i=rfirst; i<=rlast-1; i++) + { + tflagarray->ptr.p_bool[analysis->ladj.idx.ptr.p_int[i]] = ae_true; + } + analysis->ladj.rowend.ptr.p_int[sidx] = rlast; + ladjcnt = rlast; + } + analysis->useparallelism = ae_fp_greater(totalflop,smpactivationlevel(_state))&&ae_fp_greater(totalflop/(longestpath+(double)1),minspeedup(_state)); + rcopyallocv(analysis->nsuper, &analysis->ladj.nflop, &analysis->ladj.sflop, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + j = analysis->parentsupernode.ptr.p_int[sidx]; + if( j>=0 ) + { + analysis->ladj.sflop.ptr.p_double[j] = analysis->ladj.sflop.ptr.p_double[j]+analysis->ladj.sflop.ptr.p_double[sidx]; + } + } + if( analysis->dotrace ) + { + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + dbgfastestpath.ptr.p_double[sidx] = dbgfastestpath.ptr.p_double[sidx]+analysis->ladj.nflop.ptr.p_double[sidx]; + } + } + + /* + * Analyze statistics for trace output + */ + if( analysis->dotrace ) + { + ae_trace("=== ANALYZING SUPERNODAL DEPENDENCIES ==============================================================\n"); + dbgnzl = 0; + dbgrank1nodes = 0; + dbgrank2nodes = 0; + dbgrank3nodes = 0; + dbgrank4nodes = 0; + dbgbignodes = 0; + dbgtotalflop = (double)(0); + dbgnoscatterflop = (double)(0); + dbgnorowscatterflop = (double)(0); + dbgnocolscatterflop = (double)(0); + dbgrank1flop = (double)(0); + dbgrank4plusflop = (double)(0); + dbg444flop = (double)(0); + dbgxx4flop = (double)(0); + dbgcholeskyflop = (double)(0); + dbgcholesky4flop = (double)(0); + isetv(analysis->nsuper, 0, ttmp0, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + + /* + * Node sizes + */ + if( analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]==1 ) + { + inc(&dbgrank1nodes, _state); + } + if( analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]==2 ) + { + inc(&dbgrank2nodes, _state); + } + if( analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]==3 ) + { + inc(&dbgrank3nodes, _state); + } + if( analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]==4 ) + { + inc(&dbgrank4nodes, _state); + } + if( analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]>4 ) + { + inc(&dbgbignodes, _state); + } + + /* + * Nonzeros and FLOP counts + */ + twidth = analysis->supercolrange.ptr.p_int[sidx+1]-analysis->supercolrange.ptr.p_int[sidx]; + theight = twidth+(analysis->superrowridx.ptr.p_int[sidx+1]-analysis->superrowridx.ptr.p_int[sidx]); + dbgnzl = dbgnzl+theight*twidth-twidth*(twidth-1)/2; + for(i=analysis->ladj.rowbegin.ptr.p_int[sidx]; i<=analysis->ladj.rowend.ptr.p_int[sidx]-1; i++) + { + + /* + * Determine update width, height, rank + */ + uidx = analysis->ladj.idx.ptr.p_int[i]; + uwidth = analysis->ladj.uwidth.ptr.p_int[i]; + uheight = analysis->superrowridx.ptr.p_int[uidx+1]-analysis->ladj.urow0.ptr.p_int[i]; + urank = analysis->supercolrange.ptr.p_int[uidx+1]-analysis->supercolrange.ptr.p_int[uidx]; + + /* + * Compute update FLOP cost + */ + uflop = analysis->ladj.uflop.ptr.p_double[i]; + dbgtotalflop = dbgtotalflop+uflop; + if( uheight==theight&&uwidth==twidth ) + { + dbgnoscatterflop = dbgnoscatterflop+uflop; + } + if( uheight==theight ) + { + dbgnorowscatterflop = dbgnorowscatterflop+uflop; + } + if( uwidth==twidth ) + { + dbgnocolscatterflop = dbgnocolscatterflop+uflop; + } + if( urank==1 ) + { + dbgrank1flop = dbgrank1flop+uflop; + } + if( urank>=4 ) + { + dbgrank4plusflop = dbgrank4plusflop+uflop; + } + if( (urank==4&&uwidth==4)&&twidth==4 ) + { + dbg444flop = dbg444flop+uflop; + } + if( twidth==4 ) + { + dbgxx4flop = dbgxx4flop+uflop; + } + } + uflop = (double)(0); + for(i=0; i<=twidth-1; i++) + { + uflop = uflop+(double)((theight-i)*i)+(double)(theight-i); + } + dbgtotalflop = dbgtotalflop+uflop; + dbgcholeskyflop = dbgcholeskyflop+uflop; + if( twidth==4 ) + { + dbgcholesky4flop = dbgcholesky4flop+uflop; + } + } + + /* + * Output + */ + ae_trace("> factor size:\n"); + ae_trace("nz(L) = %6d\n", + (int)(dbgnzl)); + ae_trace("> node size statistics:\n"); + ae_trace("rank1 = %6d\n", + (int)(dbgrank1nodes)); + ae_trace("rank2 = %6d\n", + (int)(dbgrank2nodes)); + ae_trace("rank3 = %6d\n", + (int)(dbgrank3nodes)); + ae_trace("rank4 = %6d\n", + (int)(dbgrank4nodes)); + ae_trace("big nodes = %6d\n", + (int)(dbgbignodes)); + ae_trace("> Total FLOP count (fused multiply-adds):\n"); + ae_trace("total = %9.1f MFLOP\n", + (double)(1.0E-6*dbgtotalflop)); + ae_trace("> Analyzing potential parallelism speed-up (assuming infinite parallel resources):\n"); + ae_trace("etree = %6.1fx (elimination tree parallelism, no internal parallelism)\n", + (double)(dbgtotalflop/rmaxv(analysis->nsuper, &dbgfastestpath, _state))); + ae_trace("supernodal = %6.1fx (parallel supernodal algo, no threading overhead)\n", + (double)(totalflop/((double)1+longestpath))); + ae_trace("supernodal.c = %6.1fx (parallel supernodal algo, corrected for threading overhead)\n", + (double)(totalflop/((double)1+longestpath+smpactivationlevel(_state)))); + ae_trace("> Parallelism: "); + if( analysis->useparallelism ) + { + ae_trace("YES\n"); + } + else + { + ae_trace("no\n"); + } + ae_trace("> FLOP counts for updates:\n"); + ae_trace("no-sctr = %9.1f MFLOP (no row scatter, no col scatter, best case)\n", + (double)(1.0E-6*dbgnoscatterflop)); + ae_trace("M4*44->N4 = %9.1f MFLOP (no col scatter, big blocks, good case)\n", + (double)(1.0E-6*dbg444flop)); + ae_trace("no-row-sctr = %9.1f MFLOP (no row scatter, good case for col-wise storage)\n", + (double)(1.0E-6*dbgnorowscatterflop)); + ae_trace("no-col-sctr = %9.1f MFLOP (no col scatter, good case for row-wise storage)\n", + (double)(1.0E-6*dbgnocolscatterflop)); + ae_trace("XX*XX->N4 = %9.1f MFLOP\n", + (double)(1.0E-6*dbgxx4flop)); + ae_trace("rank1 = %9.1f MFLOP\n", + (double)(1.0E-6*dbgrank1flop)); + ae_trace("rank4+ = %9.1f MFLOP\n", + (double)(1.0E-6*dbgrank4plusflop)); + ae_trace("> FLOP counts for Cholesky:\n"); + ae_trace("cholesky = %9.1f MFLOP\n", + (double)(1.0E-6*dbgcholeskyflop)); + ae_trace("cholesky4 = %9.1f MFLOP\n", + (double)(1.0E-6*dbgcholesky4flop)); + } + + /* + * Recycle + */ + ae_nxpool_recycle(&analysis->ns1realpool, &criticalpath, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function loads matrix into the supernodal storage. + +The matrix AT is an upper triangle of the transposed matrix A; it must be +in CRS format, but it can violate some parts of the format (for the +performance reasons): +* elements stored within its rows can be unsorted +* NInitialized, DIdx[] and UIdx[] are ignored + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_loadmatrix(spcholanalysis* analysis, + const sparsematrix* at, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t ii; + ae_int_t i0; + ae_int_t i1; + ae_int_t n; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t sstride; + ae_int_t blocksize; + ae_int_t sidx; + ae_bool rowsizesmatch; + + + n = analysis->n; + + /* + * Perform quick integrity checks + */ + rowsizesmatch = ae_true; + for(i=0; i<=n; i++) + { + rowsizesmatch = rowsizesmatch&&analysis->referenceridx.ptr.p_int[i]==at->ridx.ptr.p_int[i]; + } + ae_assert(rowsizesmatch, "LoadMatrix: sparsity patterns do not match", _state); + + /* + * Load + */ + iallocv(n, &analysis->raw2smap, _state); + rsetallocv(analysis->rowoffsets.ptr.p_int[analysis->nsuper], 0.0, &analysis->inputstorage, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + + /* + * Load supernode #SIdx using Raw2SMap to perform quick transformation between global and local indexing. + */ + for(i=cols0; i<=cols1-1; i++) + { + analysis->raw2smap.ptr.p_int[i] = i-cols0; + } + for(k=analysis->superrowridx.ptr.p_int[sidx]; k<=analysis->superrowridx.ptr.p_int[sidx+1]-1; k++) + { + analysis->raw2smap.ptr.p_int[analysis->superrowidx.ptr.p_int[k]] = blocksize+(k-analysis->superrowridx.ptr.p_int[sidx]); + } + for(j=cols0; j<=cols1-1; j++) + { + i0 = at->ridx.ptr.p_int[j]; + i1 = at->ridx.ptr.p_int[j+1]-1; + for(ii=i0; ii<=i1; ii++) + { + analysis->inputstorage.ptr.p_double[offss+analysis->raw2smap.ptr.p_int[at->idx.ptr.p_int[ii]]*sstride+(j-cols0)] = at->vals.ptr.p_double[ii]; + } + } + } +} + + +/************************************************************************* +This function extracts computed matrix from the supernodal storage. +Depending on settings, a supernodal permutation can be applied to the matrix. + +INPUT PARAMETERS + Analysis - analysis object with completely initialized supernodal + structure + Offsets - offsets for supernodal storage + Strides - row strides for supernodal storage + RowStorage - supernodal storage + DiagD - diagonal factor + N - problem size + + TmpP - preallocated temporary array[N+1] + +OUTPUT PARAMETERS + A - sparse matrix in CRS format: + * for PermType=0, sparse matrix in the original ordering + (i.e. the matrix is reordered prior to output that + may require considerable amount of operations due to + permutation being applied) + * for PermType=1, sparse matrix in the topological + ordering. The least overhead for output. + D - array[N], diagonal + P - output permutation in product form + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_extractmatrix(const spcholanalysis* analysis, + /* Integer */ const ae_vector* offsets, + /* Integer */ const ae_vector* strides, + /* Real */ const ae_vector* rowstorage, + /* Real */ const ae_vector* diagd, + ae_int_t n, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + /* Integer */ ae_vector* tmpp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t sidx; + ae_int_t i0; + ae_int_t ii; + ae_int_t rfirst; + ae_int_t rlast; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t blocksize; + ae_int_t rowstride; + ae_int_t offdiagsize; + ae_int_t offssdiag; + + + ae_assert(tmpp->cnt>=n+1, "ExtractMatrix: preallocated temporary TmpP is too short", _state); + + /* + * Basic initialization + */ + a->matrixtype = 1; + a->n = n; + a->m = n; + + /* + * Various permutation types + */ + if( analysis->applypermutationtooutput ) + { + ae_assert(analysis->istopologicalordering, "ExtractMatrix: critical integrity check failed (attempt to merge in nontopological permutation)", _state); + + /* + * Output matrix is topologically permuted, so we return A=L*L' instead of A=P*L*L'*P'. + * Somewhat inefficient because we have to apply permutation to L returned by supernodal code. + */ + ivectorsetlengthatleast(&a->ridx, n+1, _state); + ivectorsetlengthatleast(&a->didx, n, _state); + a->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + a->ridx.ptr.p_int[i+1] = a->ridx.ptr.p_int[i]+analysis->outrowcounts.ptr.p_int[analysis->effectiveperm.ptr.p_int[i]]; + } + for(i=0; i<=n-1; i++) + { + a->didx.ptr.p_int[i] = a->ridx.ptr.p_int[i]; + } + a->ninitialized = a->ridx.ptr.p_int[n]; + rvectorsetlengthatleast(&a->vals, a->ninitialized, _state); + ivectorsetlengthatleast(&a->idx, a->ninitialized, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + rfirst = analysis->superrowridx.ptr.p_int[sidx]; + rlast = analysis->superrowridx.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offdiagsize = rlast-rfirst; + rowstride = strides->ptr.p_int[sidx]; + offssdiag = offsets->ptr.p_int[sidx]; + for(i=0; i<=blocksize-1; i++) + { + i0 = analysis->inveffectiveperm.ptr.p_int[cols0+i]; + ii = a->didx.ptr.p_int[i0]; + for(j=0; j<=i; j++) + { + a->idx.ptr.p_int[ii] = analysis->inveffectiveperm.ptr.p_int[cols0+j]; + a->vals.ptr.p_double[ii] = rowstorage->ptr.p_double[offssdiag+i*rowstride+j]; + ii = ii+1; + } + a->didx.ptr.p_int[i0] = ii; + } + for(k=0; k<=offdiagsize-1; k++) + { + i0 = analysis->inveffectiveperm.ptr.p_int[analysis->superrowidx.ptr.p_int[k+rfirst]]; + ii = a->didx.ptr.p_int[i0]; + for(j=0; j<=blocksize-1; j++) + { + a->idx.ptr.p_int[ii] = analysis->inveffectiveperm.ptr.p_int[cols0+j]; + a->vals.ptr.p_double[ii] = rowstorage->ptr.p_double[offssdiag+(blocksize+k)*rowstride+j]; + ii = ii+1; + } + a->didx.ptr.p_int[i0] = ii; + } + } + for(i=0; i<=n-1; i++) + { + ae_assert(a->didx.ptr.p_int[i]==a->ridx.ptr.p_int[i+1], "ExtractMatrix: integrity check failed (9473t)", _state); + tagsortmiddleir(&a->idx, &a->vals, a->ridx.ptr.p_int[i], a->ridx.ptr.p_int[i+1]-a->ridx.ptr.p_int[i], _state); + ae_assert(a->idx.ptr.p_int[a->ridx.ptr.p_int[i+1]-1]==i, "ExtractMatrix: integrity check failed (e4tfd)", _state); + } + sparseinitduidx(a, _state); + + /* + * Prepare D[] and P[] + */ + rvectorsetlengthatleast(d, n, _state); + ivectorsetlengthatleast(p, n, _state); + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = diagd->ptr.p_double[analysis->effectiveperm.ptr.p_int[i]]; + p->ptr.p_int[i] = i; + } + } + else + { + + /* + * The permutation is NOT applied to L prior to extraction, + * we return both L and P: A=P*L*L'*P'. + */ + ivectorsetlengthatleast(&a->ridx, n+1, _state); + ivectorsetlengthatleast(&a->didx, n, _state); + a->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + a->ridx.ptr.p_int[i+1] = a->ridx.ptr.p_int[i]+analysis->outrowcounts.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + a->didx.ptr.p_int[i] = a->ridx.ptr.p_int[i]; + } + a->ninitialized = a->ridx.ptr.p_int[n]; + rvectorsetlengthatleast(&a->vals, a->ninitialized, _state); + ivectorsetlengthatleast(&a->idx, a->ninitialized, _state); + for(sidx=0; sidx<=analysis->nsuper-1; sidx++) + { + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + rfirst = analysis->superrowridx.ptr.p_int[sidx]; + rlast = analysis->superrowridx.ptr.p_int[sidx+1]; + blocksize = cols1-cols0; + offdiagsize = rlast-rfirst; + rowstride = strides->ptr.p_int[sidx]; + offssdiag = offsets->ptr.p_int[sidx]; + for(i=0; i<=blocksize-1; i++) + { + i0 = cols0+i; + ii = a->didx.ptr.p_int[i0]; + for(j=0; j<=i; j++) + { + a->idx.ptr.p_int[ii] = cols0+j; + a->vals.ptr.p_double[ii] = rowstorage->ptr.p_double[offssdiag+i*rowstride+j]; + ii = ii+1; + } + a->didx.ptr.p_int[i0] = ii; + } + for(k=0; k<=offdiagsize-1; k++) + { + i0 = analysis->superrowidx.ptr.p_int[k+rfirst]; + ii = a->didx.ptr.p_int[i0]; + for(j=0; j<=blocksize-1; j++) + { + a->idx.ptr.p_int[ii] = cols0+j; + a->vals.ptr.p_double[ii] = rowstorage->ptr.p_double[offssdiag+(blocksize+k)*rowstride+j]; + ii = ii+1; + } + a->didx.ptr.p_int[i0] = ii; + } + } + for(i=0; i<=n-1; i++) + { + ae_assert(a->didx.ptr.p_int[i]==a->ridx.ptr.p_int[i+1], "ExtractMatrix: integrity check failed (34e43)", _state); + ae_assert(a->idx.ptr.p_int[a->ridx.ptr.p_int[i+1]-1]==i, "ExtractMatrix: integrity check failed (k4df5)", _state); + } + sparseinitduidx(a, _state); + + /* + * Extract diagonal + */ + rvectorsetlengthatleast(d, n, _state); + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = diagd->ptr.p_double[i]; + } + + /* + * Convert permutation table into product form + */ + ivectorsetlengthatleast(p, n, _state); + for(i=0; i<=n-1; i++) + { + p->ptr.p_int[i] = i; + tmpp->ptr.p_int[i] = i; + } + for(i=0; i<=n-1; i++) + { + + /* + * We need to move element K to position I. + * J is where K actually stored + */ + k = analysis->inveffectiveperm.ptr.p_int[i]; + j = tmpp->ptr.p_int[k]; + + /* + * Swap elements of P[I:N-1] that is used to store current locations of elements in different way + */ + i0 = p->ptr.p_int[i]; + p->ptr.p_int[i] = p->ptr.p_int[j]; + p->ptr.p_int[j] = i0; + + /* + * record pivoting of positions I and J + */ + p->ptr.p_int[i] = j; + tmpp->ptr.p_int[i0] = j; + } + } +} + + +/************************************************************************* +Sparisity pattern of partial Cholesky. + +This function splits lower triangular L into two parts: leading HEAD cols +and trailing TAIL*TAIL submatrix. Then it computes sparsity pattern of the +Cholesky decomposition of the HEAD, extracts bottom TAIL*HEAD update matrix +U and applies it to the tail: + + pattern(TAIL) += pattern(U*U') + +The pattern(TAIL) is returned. It is important that pattern(TAIL) is not +the sparsity pattern of trailing Cholesky factor, it is the pattern of the +temporary matrix that will be factorized. + +The sparsity pattern of HEAD is NOT returned. + +INPUT PARAMETERS: + A - lower triangular matrix A whose partial sparsity pattern + is needed. Only sparsity structure matters, specific + element values are ignored. + Head,Tail- sizes of the leading/traling submatrices + + tmpParent, + tmpChildrenR, + cmpChildrenI + tmp1, + FlagArray + - preallocated temporary arrays, length at least Head+Tail+1 + tmpBottomT, + tmpUpdateT, + tmpUpdate- temporary sparsematrix instances; previously allocated + space will be reused. + +OUTPUT PARAMETERS: + ATail - sparsity pattern of the lower triangular temporary matrix + computed prior to Cholesky factorization. Matrix elements + are initialized by placeholder values. + + -- ALGLIB PROJECT -- + Copyright 21.08.2021 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_partialcholeskypattern(const sparsematrix* a, + ae_int_t head, + ae_int_t tail, + sparsematrix* atail, + ae_nxpool* n1ipool, + ae_nxpool* n1bpool, + sparsematrix* tmpbottomt, + sparsematrix* tmpupdatet, + sparsematrix* tmpupdate, + sparsematrix* tmpnewtailt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i1; + ae_int_t ii; + ae_int_t j1; + ae_int_t jj; + ae_int_t kb; + ae_int_t cursize; + double v; + ae_vector tmpparent; + ae_vector tmpchildrenr; + ae_vector tmpchildreni; + ae_vector tmp1; + ae_vector flagarray; + + ae_frame_make(_state, &_frame_block); + memset(&tmpparent, 0, sizeof(tmpparent)); + memset(&tmpchildrenr, 0, sizeof(tmpchildrenr)); + memset(&tmpchildreni, 0, sizeof(tmpchildreni)); + memset(&tmp1, 0, sizeof(tmp1)); + memset(&flagarray, 0, sizeof(flagarray)); + ae_vector_init(&tmpparent, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmpchildrenr, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmpchildreni, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmp1, 0, DT_INT, _state, ae_true); + ae_vector_init(&flagarray, 0, DT_BOOL, _state, ae_true); + + ae_assert(a->m==head+tail, "PartialCholeskyPattern: rows(A)!=Head+Tail", _state); + ae_assert(a->n==head+tail, "PartialCholeskyPattern: cols(A)!=Head+Tail", _state); + + /* + * Initialize and retrieve temporary arrays + */ + ae_nxpool_retrieve(n1ipool, &tmpparent, _state); + ae_nxpool_retrieve(n1ipool, &tmpchildrenr, _state); + ae_nxpool_retrieve(n1ipool, &tmpchildreni, _state); + ae_nxpool_retrieve(n1ipool, &tmp1, _state); + ae_nxpool_retrieve(n1bpool, &flagarray, _state); + cursize = head+tail; + v = (double)1/(double)cursize; + ae_assert(tmpparent.cnt>=head+tail+1, "PartialCholeskyPattern: Length(tmpParent)=head+tail+1, "PartialCholeskyPattern: Length(tmpChildrenR)=head+tail+1, "PartialCholeskyPattern: Length(tmpChildrenI)=head+tail+1, "PartialCholeskyPattern: Length(tmp1)=head+tail+1, "PartialCholeskyPattern: Length(tmp1)m = head; + tmpbottomt->n = tail; + iallocv(head+1, &tmpbottomt->ridx, _state); + tmpbottomt->ridx.ptr.p_int[0] = 0; + tmpupdatet->m = head; + tmpupdatet->n = tail; + iallocv(head+1, &tmpupdatet->ridx, _state); + tmpupdatet->ridx.ptr.p_int[0] = 0; + bsetv(tail, ae_false, &flagarray, _state); + for(j=0; j<=head-1; j++) + { + + /* + * Start J-th row of the tmpBottomT + */ + kb = tmpbottomt->ridx.ptr.p_int[j]; + igrowv(kb+tail, &tmpbottomt->idx, _state); + rgrowv(kb+tail, &tmpbottomt->vals, _state); + + /* + * copy sparsity pattern J-th column of the reordered matrix + */ + jj = atail->didx.ptr.p_int[j]; + j1 = atail->ridx.ptr.p_int[j+1]-1; + while(jj<=j1&&atail->idx.ptr.p_int[jj]idx.ptr.p_int[jj]-head; + tmpbottomt->idx.ptr.p_int[kb] = i; + tmpbottomt->vals.ptr.p_double[kb] = v; + flagarray.ptr.p_bool[i] = ae_true; + kb = kb+1; + jj = jj+1; + } + + /* + * Fetch sparsity pattern from the immediate children in the elimination tree + */ + for(jj=tmpchildrenr.ptr.p_int[j]; jj<=tmpchildrenr.ptr.p_int[j+1]-1; jj++) + { + j1 = tmpchildreni.ptr.p_int[jj]; + ii = tmpbottomt->ridx.ptr.p_int[j1]; + i1 = tmpbottomt->ridx.ptr.p_int[j1+1]-1; + while(ii<=i1) + { + i = tmpbottomt->idx.ptr.p_int[ii]; + if( !flagarray.ptr.p_bool[i] ) + { + tmpbottomt->idx.ptr.p_int[kb] = i; + tmpbottomt->vals.ptr.p_double[kb] = v; + flagarray.ptr.p_bool[i] = ae_true; + kb = kb+1; + } + ii = ii+1; + } + } + + /* + * Finalize row of tmpBottomT + */ + for(ii=tmpbottomt->ridx.ptr.p_int[j]; ii<=kb-1; ii++) + { + flagarray.ptr.p_bool[tmpbottomt->idx.ptr.p_int[ii]] = ae_false; + } + tmpbottomt->ridx.ptr.p_int[j+1] = kb; + + /* + * Only columns that forward their sparsity pattern directly into the tail are added to tmpUpdateT + */ + if( tmpparent.ptr.p_int[j]>=head ) + { + + /* + * J-th column of the head forwards its sparsity pattern directly into the tail, save it to tmpUpdateT + */ + k = tmpupdatet->ridx.ptr.p_int[j]; + igrowv(k+tail, &tmpupdatet->idx, _state); + rgrowv(k+tail, &tmpupdatet->vals, _state); + jj = tmpbottomt->ridx.ptr.p_int[j]; + j1 = tmpbottomt->ridx.ptr.p_int[j+1]-1; + while(jj<=j1) + { + i = tmpbottomt->idx.ptr.p_int[jj]; + tmpupdatet->idx.ptr.p_int[k] = i; + tmpupdatet->vals.ptr.p_double[k] = v; + k = k+1; + jj = jj+1; + } + tmpupdatet->ridx.ptr.p_int[j+1] = k; + } + else + { + + /* + * J-th column of the head forwards its sparsity pattern to another column in the head, + * no need to save it to tmpUpdateT. Save empty row. + */ + k = tmpupdatet->ridx.ptr.p_int[j]; + tmpupdatet->ridx.ptr.p_int[j+1] = k; + } + } + sparsecreatecrsinplace(tmpupdatet, _state); + sparsecopytransposecrsbuf(tmpupdatet, tmpupdate, _state); + + /* + * Apply update U*U' to the trailing Tail*Tail matrix and generate new + * residual matrix in tmpNewTailT. Then transpose/copy it to TmpA[]. + */ + bsetv(tail, ae_false, &flagarray, _state); + tmpnewtailt->m = tail; + tmpnewtailt->n = tail; + iallocv(tail+1, &tmpnewtailt->ridx, _state); + tmpnewtailt->ridx.ptr.p_int[0] = 0; + for(j=0; j<=tail-1; j++) + { + k = tmpnewtailt->ridx.ptr.p_int[j]; + igrowv(k+tail, &tmpnewtailt->idx, _state); + rgrowv(k+tail, &tmpnewtailt->vals, _state); + + /* + * Copy row from the reordered/transposed matrix stored in TmpA + */ + tmpnewtailt->idx.ptr.p_int[k] = j; + tmpnewtailt->vals.ptr.p_double[k] = (double)(1); + flagarray.ptr.p_bool[j] = ae_true; + k = k+1; + jj = atail->didx.ptr.p_int[head+j]+1; + j1 = atail->ridx.ptr.p_int[head+j+1]-1; + while(jj<=j1) + { + i = atail->idx.ptr.p_int[jj]-head; + tmpnewtailt->idx.ptr.p_int[k] = i; + tmpnewtailt->vals.ptr.p_double[k] = v; + flagarray.ptr.p_bool[i] = ae_true; + k = k+1; + jj = jj+1; + } + + /* + * Apply update U*U' to J-th column of new tail (J-th row of tmpNewTailT): + * * scan J-th row of U + * * for each nonzero element, append corresponding row of U' (elements from J+1-th) to tmpNewTailT + * * FlagArray[] is used to avoid duplication of nonzero elements + */ + jj = tmpupdate->ridx.ptr.p_int[j]; + j1 = tmpupdate->ridx.ptr.p_int[j+1]-1; + while(jj<=j1) + { + + /* + * Get row of U', skip leading elements up to J-th + */ + ii = tmpupdatet->ridx.ptr.p_int[tmpupdate->idx.ptr.p_int[jj]]; + i1 = tmpupdatet->ridx.ptr.p_int[tmpupdate->idx.ptr.p_int[jj]+1]-1; + while(ii<=i1&&tmpupdatet->idx.ptr.p_int[ii]<=j) + { + ii = ii+1; + } + + /* + * Append the rest of the row to tmpNewTailT + */ + while(ii<=i1) + { + i = tmpupdatet->idx.ptr.p_int[ii]; + if( !flagarray.ptr.p_bool[i] ) + { + tmpnewtailt->idx.ptr.p_int[k] = i; + tmpnewtailt->vals.ptr.p_double[k] = v; + flagarray.ptr.p_bool[i] = ae_true; + k = k+1; + } + ii = ii+1; + } + + /* + * Continue or stop early (if we completely filled output buffer) + */ + if( k-tmpnewtailt->ridx.ptr.p_int[j]==tail-j ) + { + break; + } + jj = jj+1; + } + + /* + * Finalize: + * * clean up FlagArray[] + * * save K to RIdx[] + */ + for(ii=tmpnewtailt->ridx.ptr.p_int[j]; ii<=k-1; ii++) + { + flagarray.ptr.p_bool[tmpnewtailt->idx.ptr.p_int[ii]] = ae_false; + } + tmpnewtailt->ridx.ptr.p_int[j+1] = k; + } + sparsecreatecrsinplace(tmpnewtailt, _state); + sparsecopytransposecrsbuf(tmpnewtailt, atail, _state); + + /* + * Recycle temporaries + */ + ae_nxpool_recycle(n1ipool, &tmpparent, _state); + ae_nxpool_recycle(n1ipool, &tmpchildrenr, _state); + ae_nxpool_recycle(n1ipool, &tmpchildreni, _state); + ae_nxpool_recycle(n1ipool, &tmp1, _state); + ae_nxpool_recycle(n1bpool, &flagarray, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function is a specialized version of SparseSymmPermTbl() that takes +into account specifics of topological reorderings (improves performance) +and additionally transposes its output. + +INPUT PARAMETERS + A - sparse lower triangular matrix in CRS format. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold output. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted and transposed upper triangular matrix in the + special internal CRS-like matrix format (MatrixType=-10082). + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +static void spchol_topologicalpermutation(const sparsematrix* a, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t k0; + ae_int_t n; + ae_bool bflag; + + + ae_assert(a->matrixtype==1, "TopologicalPermutation: incorrect matrix type (convert your matrix to CRS)", _state); + ae_assert(p->cnt>=a->n, "TopologicalPermutation: Length(P)m==a->n, "TopologicalPermutation: matrix is non-square", _state); + ae_assert(a->ninitialized==a->ridx.ptr.p_int[a->n], "TopologicalPermutation: integrity check failed", _state); + bflag = ae_true; + n = a->n; + for(i=0; i<=n-1; i++) + { + j = p->ptr.p_int[i]; + bflag = (bflag&&j>=0)&&jmatrixtype = -10082; + b->n = n; + b->m = n; + ivectorsetlengthatleast(&b->didx, n, _state); + ivectorsetlengthatleast(&b->uidx, n, _state); + + /* + * Determine row sizes (temporary stored in DIdx) and ranges + */ + isetv(n, 0, &b->uidx, _state); + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + b->uidx.ptr.p_int[j] = b->uidx.ptr.p_int[j]+1; + } + } + for(i=0; i<=n-1; i++) + { + b->didx.ptr.p_int[p->ptr.p_int[i]] = b->uidx.ptr.p_int[i]; + } + ivectorsetlengthatleast(&b->ridx, n+1, _state); + b->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + b->ridx.ptr.p_int[i+1] = b->ridx.ptr.p_int[i]+b->didx.ptr.p_int[i]; + b->uidx.ptr.p_int[i] = b->ridx.ptr.p_int[i]; + } + b->ninitialized = b->ridx.ptr.p_int[n]; + ivectorsetlengthatleast(&b->idx, b->ninitialized, _state); + rvectorsetlengthatleast(&b->vals, b->ninitialized, _state); + + /* + * Process matrix + */ + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + k = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + j = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + k0 = b->uidx.ptr.p_int[j]; + b->idx.ptr.p_int[k0] = k; + b->vals.ptr.p_double[k0] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[j] = k0+1; + } + } +} + + +/************************************************************************* +Determine nonzero pattern of the column. + +This function takes as input: +* A^T - transpose of original input matrix +* index of column of L being computed +* SuperRowRIdx[] and SuperRowIdx[] - arrays that store row structure of + supernodes, and NSuper - supernodes count +* ChildrenNodesR[], ChildrenNodesI[] - arrays that store children nodes + for each node +* Node2Supernode[] - array that maps node indexes to supernodes +* TrueArray[] - array[N] that has all of its elements set to True (this + invariant is preserved on output) +* Tmp0[] - array[N], temporary array + +As output, it constructs nonzero pattern (diagonal element not included) +of the column #ColumnIdx on top of SuperRowIdx[] array, starting at +location SuperRowIdx[SuperRowRIdx[NSuper]] and till location +SuperRowIdx[Result-1], where Result is a function result. + +The SuperRowIdx[] array is automatically resized as needed. + +It is important that this function computes nonzero pattern, but it does +NOT change other supernodal structures. The caller still has to finalize +the column (setup supernode ranges, mappings, etc). + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_int_t spchol_computenonzeropattern(const sparsematrix* wrkat, + ae_int_t columnidx, + ae_int_t n, + /* Integer */ const ae_vector* superrowridx, + /* Integer */ ae_vector* superrowidx, + ae_int_t nsuper, + /* Integer */ const ae_vector* childrennodesr, + /* Integer */ const ae_vector* childrennodesi, + /* Integer */ const ae_vector* node2supernode, + /* Boolean */ ae_vector* truearray, + /* Integer */ ae_vector* tmp0, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ii; + ae_int_t jj; + ae_int_t i0; + ae_int_t i1; + ae_int_t j0; + ae_int_t j1; + ae_int_t cidx; + ae_int_t rfirst; + ae_int_t rlast; + ae_int_t tfirst; + ae_int_t tlast; + ae_int_t supernodalchildrencount; + ae_int_t result; + + + ae_assert(truearray->cnt>=n, "ComputeNonzeroPattern: input temporary is too short", _state); + ae_assert(tmp0->cnt>=n, "ComputeNonzeroPattern: input temporary is too short", _state); + + /* + * Determine supernodal children in Tmp0 + */ + supernodalchildrencount = 0; + i0 = childrennodesr->ptr.p_int[columnidx]; + i1 = childrennodesr->ptr.p_int[columnidx+1]-1; + for(ii=i0; ii<=i1; ii++) + { + i = node2supernode->ptr.p_int[childrennodesi->ptr.p_int[ii]]; + if( truearray->ptr.p_bool[i] ) + { + tmp0->ptr.p_int[supernodalchildrencount] = i; + truearray->ptr.p_bool[i] = ae_false; + supernodalchildrencount = supernodalchildrencount+1; + } + } + for(i=0; i<=supernodalchildrencount-1; i++) + { + truearray->ptr.p_bool[tmp0->ptr.p_int[i]] = ae_true; + } + + /* + * Initialized column by nonzero pattern from A + */ + rfirst = superrowridx->ptr.p_int[nsuper]; + tfirst = rfirst+n; + igrowv(rfirst+2*n, superrowidx, _state); + i0 = wrkat->ridx.ptr.p_int[columnidx]+1; + i1 = wrkat->ridx.ptr.p_int[columnidx+1]; + icopyvx(i1-i0, &wrkat->idx, i0, superrowidx, rfirst, _state); + rlast = rfirst+(i1-i0); + + /* + * For column with small number of children use ordered merge algorithm. + * For column with many children it is better to perform unsorted merge, + * and then sort the sequence. + */ + if( supernodalchildrencount<=4 ) + { + + /* + * Ordered merge. The best approach for small number of children, + * but may have O(N^2) running time when O(N) children are present. + */ + for(cidx=0; cidx<=supernodalchildrencount-1; cidx++) + { + + /* + * Skip initial elements that do not contribute to subdiagonal nonzero pattern + */ + i0 = superrowridx->ptr.p_int[tmp0->ptr.p_int[cidx]]; + i1 = superrowridx->ptr.p_int[tmp0->ptr.p_int[cidx]+1]-1; + while(i0<=i1&&superrowidx->ptr.p_int[i0]<=columnidx) + { + i0 = i0+1; + } + j0 = rfirst; + j1 = rlast-1; + + /* + * Handle degenerate cases: empty merge target or empty merge source. + */ + if( j1ptr.p_int[i0]; + jj = superrowidx->ptr.p_int[j0]; + tlast = tfirst; + for(;;) + { + if( iiptr.p_int[tlast] = ii; + tlast = tlast+1; + i0 = i0+1; + if( i0>i1 ) + { + break; + } + ii = superrowidx->ptr.p_int[i0]; + } + if( jjptr.p_int[tlast] = jj; + tlast = tlast+1; + j0 = j0+1; + if( j0>j1 ) + { + break; + } + jj = superrowidx->ptr.p_int[j0]; + } + if( jj==ii ) + { + superrowidx->ptr.p_int[tlast] = ii; + tlast = tlast+1; + i0 = i0+1; + j0 = j0+1; + if( i0>i1 ) + { + break; + } + if( j0>j1 ) + { + break; + } + ii = superrowidx->ptr.p_int[i0]; + jj = superrowidx->ptr.p_int[j0]; + } + } + for(ii=i0; ii<=i1; ii++) + { + superrowidx->ptr.p_int[tlast] = superrowidx->ptr.p_int[ii]; + tlast = tlast+1; + } + for(jj=j0; jj<=j1; jj++) + { + superrowidx->ptr.p_int[tlast] = superrowidx->ptr.p_int[jj]; + tlast = tlast+1; + } + icopyvx(tlast-tfirst, superrowidx, tfirst, superrowidx, rfirst, _state); + rlast = rfirst+(tlast-tfirst); + } + result = rlast; + } + else + { + + /* + * Unordered merge followed by sort. Guaranteed N*logN worst case. + */ + for(ii=rfirst; ii<=rlast-1; ii++) + { + truearray->ptr.p_bool[superrowidx->ptr.p_int[ii]] = ae_false; + } + for(cidx=0; cidx<=supernodalchildrencount-1; cidx++) + { + + /* + * Skip initial elements that do not contribute to subdiagonal nonzero pattern + */ + i0 = superrowridx->ptr.p_int[tmp0->ptr.p_int[cidx]]; + i1 = superrowridx->ptr.p_int[tmp0->ptr.p_int[cidx]+1]-1; + while(i0<=i1&&superrowidx->ptr.p_int[i0]<=columnidx) + { + i0 = i0+1; + } + + /* + * Append elements not present in the sequence + */ + for(ii=i0; ii<=i1; ii++) + { + i = superrowidx->ptr.p_int[ii]; + if( truearray->ptr.p_bool[i] ) + { + superrowidx->ptr.p_int[rlast] = i; + rlast = rlast+1; + truearray->ptr.p_bool[i] = ae_false; + } + } + } + for(ii=rfirst; ii<=rlast-1; ii++) + { + truearray->ptr.p_bool[superrowidx->ptr.p_int[ii]] = ae_true; + } + tagsortmiddlei(superrowidx, rfirst, rlast-rfirst, _state); + result = rlast; + } + return result; +} + + +/************************************************************************* +Update target supernode with data from its children. This operation is a +supernodal equivalent of the column update by all preceding cols in a +left-looking Cholesky. + +This function applies LAdjIdx1-LAdjIdx0 updates, from LAdjidx0 to LAdjIdx1-1 +from child columns. Each update has following form: + + S := S - scatter(U*D*Uc') + +where +* S is an tHeight*tWidth rectangular target matrix that is: + * stored with tStride>=tWidth in RowStorage[OffsS:OffsS+tHeight*tStride-1] + * lower trapezoidal i.e. its leading tWidth*tWidth submatrix is lower + triangular. One may update either entire tWidth*tWidth submatrix or + just its lower part, because upper triangle is not referenced anyway. + * the height of S is not given because it is not actually needed +* U is an uHeight*uRank rectangular update matrix tht is: + * stored with row stride uStride>=uRank in RowStorage[OffsU:OffsU+uHeight*uStride-1]. +* Uc is the leading uWidth*uRank submatrix of U +* D is uRank*uRank diagonal matrix that is: + * stored in DiagD[OffsD:OffsD+uRank-1] + * unit, when Analysis.UnitD=True. In this case it can be ignored, although + DiagD still contains 1's in all of its entries +* uHeight<=tHeight, uWidth<=tWidth, so scatter operation is needed to update + S with smaller update. +* scatter() is an operation that extends smaller uHeight*uWidth update + matrix U*Uc' into larger tHeight*tWidth target matrix by adding zero rows + and columns into U*Uc': + * I-th row of update modifies Raw2SMap[SuperRowIdx[URBase+I]]-th row of + the matrix S + * J-th column of update modifies Raw2SMap[SuperRowIdx[URBase+J]]-th col + of the matrix S + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static void spchol_updatesupernode(spcholanalysis* analysis, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + /* Integer */ const ae_vector* raw2smap, + ae_int_t ladjidx0, + ae_int_t ladjidx1, + /* Real */ const ae_vector* diagd, + ae_state *_state) +{ + ae_int_t i; + ae_int_t uidx; + ae_int_t colu0; + ae_int_t colu1; + ae_int_t urbase; + ae_int_t urlast; + ae_int_t urank; + ae_int_t uwidth; + ae_int_t uheight; + ae_int_t urowstride; + ae_int_t twidth; + ae_int_t theight; + ae_int_t trowstride; + ae_int_t offsu; + ae_int_t wrkrow; + ae_int_t ladjidx; + + + twidth = cols1-cols0; + theight = twidth+(analysis->superrowridx.ptr.p_int[sidx+1]-analysis->superrowridx.ptr.p_int[sidx]); + trowstride = analysis->rowstrides.ptr.p_int[sidx]; + for(ladjidx=ladjidx0; ladjidx<=ladjidx1-1; ladjidx++) + { + uidx = analysis->ladj.idx.ptr.p_int[ladjidx]; + offsu = analysis->rowoffsets.ptr.p_int[uidx]; + colu0 = analysis->supercolrange.ptr.p_int[uidx]; + colu1 = analysis->supercolrange.ptr.p_int[uidx+1]; + urbase = analysis->superrowridx.ptr.p_int[uidx]; + urlast = analysis->superrowridx.ptr.p_int[uidx+1]; + urank = colu1-colu0; + urowstride = analysis->rowstrides.ptr.p_int[uidx]; + wrkrow = analysis->ladj.urow0.ptr.p_int[ladjidx]; + uwidth = analysis->ladj.uwidth.ptr.p_int[ladjidx]; + uheight = urlast-wrkrow; + if( analysis->extendeddebug ) + { + + /* + * Extended integrity check (if requested) + */ + ae_assert(uwidth>0, "SPCholFactorize: integrity check failed (44trg1)", _state); + ae_assert(analysis->superrowidx.ptr.p_int[wrkrow]>=cols0, "SPCholFactorize: integrity check 6378 failed", _state); + ae_assert(analysis->superrowidx.ptr.p_int[wrkrow]ptr.p_int[analysis->superrowidx.ptr.p_int[i]]>=0, "SPCholFactorize: integrity check failed (43t63)", _state); + } + } + + /* + * Skip leading uRank+WrkRow rows of U because they are not used. + */ + offsu = offsu+(urank+(wrkrow-urbase))*urowstride; + + /* + * Handle special cases + */ + if( trowstride==4 ) + { + + /* + * Target is stride-4 column, try several kernels that may work with tWidth=3 and tWidth=4 + */ + if( ((uwidth==4&&twidth==4)&&urank==4)&&urowstride==4 ) + { + if( spchol_updatekernel4444(&analysis->outputstorage, offss, theight, offsu, uheight, &analysis->diagd, colu0, raw2smap, &analysis->superrowidx, wrkrow, _state) ) + { + continue; + } + } + if( spchol_updatekernelabc4(&analysis->outputstorage, offss, twidth, offsu, uheight, urank, urowstride, uwidth, &analysis->diagd, colu0, raw2smap, &analysis->superrowidx, wrkrow, _state) ) + { + continue; + } + } + if( urank==1&&urowstride==1 ) + { + if( spchol_updatekernelrank1(&analysis->outputstorage, offss, twidth, trowstride, offsu, uheight, uwidth, &analysis->diagd, colu0, raw2smap, &analysis->superrowidx, wrkrow, _state) ) + { + continue; + } + } + if( urank==2&&urowstride==2 ) + { + if( spchol_updatekernelrank2(&analysis->outputstorage, offss, twidth, trowstride, offsu, uheight, uwidth, &analysis->diagd, colu0, raw2smap, &analysis->superrowidx, wrkrow, _state) ) + { + continue; + } + } + + /* + * Handle general update with no specialized kernel + */ + spchol_updatesupernodegeneric(analysis, sidx, cols0, cols1, offss, raw2smap, ladjidx, diagd, _state); + } +} + + +/************************************************************************* +Generic supernode update kernel + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static void spchol_updatesupernodegeneric(spcholanalysis* analysis, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + /* Integer */ const ae_vector* raw2smap, + ae_int_t ladjidx, + /* Real */ const ae_vector* diagd, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t uidx; + ae_int_t colu0; + ae_int_t colu1; + ae_int_t urbase; + ae_int_t urlast; + ae_int_t urank; + ae_int_t uwidth; + ae_int_t uheight; + ae_int_t urowstride; + ae_int_t trowstride; + ae_int_t targetrow; + ae_int_t targetcol; + ae_int_t offsu; + ae_int_t offsd; + ae_int_t offs0; + ae_int_t offsj; + ae_int_t offsk; + double v; + ae_int_t wrkrow; + ae_vector u2smap; + + ae_frame_make(_state, &_frame_block); + memset(&u2smap, 0, sizeof(u2smap)); + ae_vector_init(&u2smap, 0, DT_INT, _state, ae_true); + + uidx = analysis->ladj.idx.ptr.p_int[ladjidx]; + offsd = analysis->supercolrange.ptr.p_int[uidx]; + offsu = analysis->rowoffsets.ptr.p_int[uidx]; + colu0 = analysis->supercolrange.ptr.p_int[uidx]; + colu1 = analysis->supercolrange.ptr.p_int[uidx+1]; + urbase = analysis->superrowridx.ptr.p_int[uidx]; + urlast = analysis->superrowridx.ptr.p_int[uidx+1]; + urank = colu1-colu0; + trowstride = analysis->rowstrides.ptr.p_int[sidx]; + urowstride = analysis->rowstrides.ptr.p_int[uidx]; + wrkrow = analysis->ladj.urow0.ptr.p_int[ladjidx]; + uwidth = analysis->ladj.uwidth.ptr.p_int[ladjidx]; + uheight = urlast-wrkrow; + + /* + * Skip leading uRank+WrkRow rows of U because they are not used. + */ + offsu = offsu+(colu1-colu0+(wrkrow-urbase))*urowstride; + + /* + * Handle general update, rerefence code + */ + ae_nxpool_retrieve(&analysis->n1integerpool, &u2smap, _state); + ivectorsetlengthatleast(&u2smap, uheight, _state); + for(i=0; i<=uheight-1; i++) + { + u2smap.ptr.p_int[i] = raw2smap->ptr.p_int[analysis->superrowidx.ptr.p_int[wrkrow+i]]; + } + if( analysis->unitd ) + { + + /* + * Unit D, vanilla Cholesky + */ + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+u2smap.ptr.p_int[k]*trowstride; + for(j=0; j<=uwidth-1; j++) + { + targetcol = u2smap.ptr.p_int[j]; + offsj = offsu+j*urowstride; + offsk = offsu+k*urowstride; + offs0 = targetrow+targetcol; + v = analysis->outputstorage.ptr.p_double[offs0]; + for(i=0; i<=urank-1; i++) + { + v = v-analysis->outputstorage.ptr.p_double[offsj+i]*analysis->outputstorage.ptr.p_double[offsk+i]; + } + analysis->outputstorage.ptr.p_double[offs0] = v; + } + } + } + else + { + + /* + * Non-unit D, LDLT decomposition + */ + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+u2smap.ptr.p_int[k]*trowstride; + for(j=0; j<=uwidth-1; j++) + { + targetcol = u2smap.ptr.p_int[j]; + offsj = offsu+j*urowstride; + offsk = offsu+k*urowstride; + offs0 = targetrow+targetcol; + v = analysis->outputstorage.ptr.p_double[offs0]; + for(i=0; i<=urank-1; i++) + { + v = v-analysis->outputstorage.ptr.p_double[offsj+i]*diagd->ptr.p_double[offsd+i]*analysis->outputstorage.ptr.p_double[offsk+i]; + } + analysis->outputstorage.ptr.p_double[offs0] = v; + } + } + } + ae_nxpool_recycle(&analysis->n1integerpool, &u2smap, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Factorizes target supernode, returns True on success, False on failure. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_factorizesupernode(spcholanalysis* analysis, + ae_int_t sidx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t blocksize; + ae_int_t sstride; + double v; + double vs; + ae_bool controlpivot; + ae_bool controloverflow; + ae_bool result; + + + result = ae_true; + + /* + * Factorize leading BlockSize*BlockSize block + */ + if( analysis->unitd ) + { + + /* + * Classic Cholesky + */ + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + blocksize = cols1-cols0; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + controlpivot = analysis->modtype==1&&ae_fp_greater(analysis->modparam0,(double)(0)); + controloverflow = (analysis->modtype==1||analysis->modtype==2)&&ae_fp_greater(analysis->modparam1,(double)(0)); + for(j=0; j<=blocksize-1; j++) + { + + /* + * Compute J-th column + */ + vs = (double)(0); + for(k=j; k<=blocksize-1; k++) + { + v = analysis->outputstorage.ptr.p_double[offss+k*sstride+j]; + for(i=0; i<=j-1; i++) + { + v = v-analysis->outputstorage.ptr.p_double[offss+k*sstride+i]*analysis->outputstorage.ptr.p_double[offss+j*sstride+i]; + } + analysis->outputstorage.ptr.p_double[offss+k*sstride+j] = v; + vs = vs+ae_fabs(v, _state); + } + if( controloverflow&&vs>analysis->modparam1 ) + { + + /* + * Possible failure due to accumulation of numerical errors + */ + result = ae_false; + return result; + } + + /* + * Handle pivot element + */ + v = analysis->outputstorage.ptr.p_double[offss+j*sstride+j]; + if( controlpivot&&v<=analysis->modparam0 ) + { + + /* + * Basic modified Cholesky + */ + v = ae_sqrt(analysis->modparam0, _state); + analysis->diagd.ptr.p_double[cols0+j] = 1.0; + analysis->outputstorage.ptr.p_double[offss+j*sstride+j] = v; + v = (double)1/v; + for(k=j+1; k<=blocksize-1; k++) + { + analysis->outputstorage.ptr.p_double[offss+k*sstride+j] = v*analysis->outputstorage.ptr.p_double[offss+k*sstride+j]; + } + } + else + { + + /* + * Default case + */ + if( v<=(double)0 ) + { + result = ae_false; + return result; + } + analysis->diagd.ptr.p_double[cols0+j] = 1.0; + v = (double)1/ae_sqrt(v, _state); + for(k=j; k<=blocksize-1; k++) + { + analysis->outputstorage.ptr.p_double[offss+k*sstride+j] = v*analysis->outputstorage.ptr.p_double[offss+k*sstride+j]; + } + } + } + } + else + { + + /* + * LDLT with diagonal D + */ + if( !spchol_factorizesupernodeheadldlt(&analysis->outputstorage, &analysis->diagd, &analysis->rpivotsigns, sidx, analysis->supercolrange.ptr.p_int[sidx], analysis->supercolrange.ptr.p_int[sidx+1], analysis->rowoffsets.ptr.p_int[sidx], analysis->rowstrides.ptr.p_int[sidx], analysis->modtype, analysis->modparam0, analysis->modparam1, _state) ) + { + result = ae_false; + return result; + } + } + + /* + * Factorize tail + */ + spchol_factorizesupernodetail(analysis, sidx, _state); + return result; +} + + +/************************************************************************* +Factorizes supernode head (diagonal block) performing LDLT factorization. +Assumes that Analysis.UnitD is False, but does not check it. + +Returns True on success, False on failure. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_factorizesupernodeheadldlt(/* Real */ ae_vector* outputstorage, + /* Real */ ae_vector* diagd, + /* Real */ const ae_vector* rpivotsigns, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t offss, + ae_int_t sstride, + ae_int_t modtype, + double modparam0, + double modparam1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t blocksize; + double v; + double vs; + ae_bool ismodified; + ae_bool controlsign; + ae_bool controlpivot; + ae_bool droppivot; + ae_bool controloverflow; + ae_bool setfailure; + double modmul; + double modadd; + ae_bool failureflag; + ae_bool result; + + + blocksize = cols1-cols0; + ismodified = modtype!=0; + droppivot = modtype==2&&modparam0>(double)0; + controlpivot = modtype==1&&modparam0>(double)0; + controloverflow = (modtype==1||modtype==2)&&modparam1>(double)0; + controlsign = modtype==3; + result = ae_true; + + /* + * Analyze various modifications applied + */ + setfailure = ae_true; + modmul = (double)(0); + modadd = (double)(0); + if( controlsign ) + { + setfailure = ae_true; + modmul = (double)(0); + modadd = (double)(1); + } + if( controlpivot ) + { + setfailure = ae_false; + modmul = modparam0; + modadd = (double)(0); + } + if( droppivot ) + { + setfailure = ae_false; + modmul = (double)(0); + modadd = 1.0E50; + } + + /* + * LDLT with diagonal D + */ + failureflag = ae_false; + vs = (double)(0); + for(j=0; j<=blocksize-1; j++) + { + + /* + * Compute J-th column + */ + for(k=j; k<=blocksize-1; k++) + { + v = outputstorage->ptr.p_double[offss+k*sstride+j]; + for(i=0; i<=j-1; i++) + { + v = v-outputstorage->ptr.p_double[offss+k*sstride+i]*diagd->ptr.p_double[cols0+i]*outputstorage->ptr.p_double[offss+j*sstride+i]; + } + outputstorage->ptr.p_double[offss+k*sstride+j] = v; + vs = vs+v*v; + } + v = outputstorage->ptr.p_double[offss+j*sstride+j]; + + /* + * Handle pivot element + */ + if( ismodified&&v*rpivotsigns->ptr.p_double[cols0+j]<=modparam0 ) + { + failureflag = failureflag||setfailure; + v = modmul*rpivotsigns->ptr.p_double[cols0+j]+modadd; + } + if( v==(double)0 ) + { + v = (double)(1); + failureflag = ae_true; + } + diagd->ptr.p_double[cols0+j] = v; + v = (double)1/v; + outputstorage->ptr.p_double[offss+j*sstride+j] = (double)(1); + for(k=j+1; k<=blocksize-1; k++) + { + outputstorage->ptr.p_double[offss+k*sstride+j] = v*outputstorage->ptr.p_double[offss+k*sstride+j]; + } + } + if( failureflag ) + { + result = ae_false; + } + if( controloverflow&&(vs>modparam1||!ae_isfinite(vs, _state)) ) + { + result = ae_false; + } + return result; +} + + +/************************************************************************* +Factorizes supernode offdiagonal tail, assumes that the primary block of +the supernode is non-singular, always succeeded. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static void spchol_factorizesupernodetail(spcholanalysis* analysis, + ae_int_t sidx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cols0; + ae_int_t cols1; + ae_int_t offss; + ae_int_t blocksize; + ae_int_t offdiagsize; + ae_int_t sstride; + double v; + double vv; + + + offdiagsize = analysis->superrowridx.ptr.p_int[sidx+1]-analysis->superrowridx.ptr.p_int[sidx]; + if( offdiagsize==0 ) + { + return; + } + cols0 = analysis->supercolrange.ptr.p_int[sidx]; + cols1 = analysis->supercolrange.ptr.p_int[sidx+1]; + offss = analysis->rowoffsets.ptr.p_int[sidx]; + blocksize = cols1-cols0; + sstride = analysis->rowstrides.ptr.p_int[sidx]; + for(j=0; j<=blocksize-1; j++) + { + v = (double)1/(analysis->diagd.ptr.p_double[cols0+j]*analysis->outputstorage.ptr.p_double[offss+j*sstride+j]); + for(k=blocksize; k<=blocksize+offdiagsize-1; k++) + { + vv = analysis->outputstorage.ptr.p_double[offss+k*sstride+j]; + for(i=0; i<=j-1; i++) + { + vv = vv-analysis->outputstorage.ptr.p_double[offss+k*sstride+i]*analysis->diagd.ptr.p_double[cols0+i]*analysis->outputstorage.ptr.p_double[offss+j*sstride+i]; + } + analysis->outputstorage.ptr.p_double[offss+k*sstride+j] = vv*v; + } + } +} + + +/************************************************************************* +This function returns recommended stride for given row size + + -- ALGLIB routine -- + 20.10.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_int_t spchol_recommendedstridefor(ae_int_t rowsize, + ae_state *_state) +{ + ae_int_t result; + + + result = rowsize; + if( rowsize==3 ) + { + result = 4; + } + return result; +} + + +/************************************************************************* +This function aligns position in array in order to better accommodate to +SIMD specifics. + +NOTE: this function aligns position measured in double precision numbers, + not in bits or bytes. If you want to have 256-bit aligned position, + round Offs to nearest multiple of 4 that is not less than Offs. + + -- ALGLIB routine -- + 20.10.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_int_t spchol_alignpositioninarray(ae_int_t offs, + ae_state *_state) +{ + ae_int_t result; + + + result = offs; + if( offs%4!=0 ) + { + result = result+(4-offs%4); + } + return result; +} + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Fast kernels for small supernodal updates: special 4x4x4x4 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs 4x4x4x4 update, i.e.: +* S is a tHeight*4 matrix +* U is a uHeight*4 matrix +* Uc' is a 4*4 matrix +* scatter() scatters rows of U*Uc', but does not scatter columns (they are + densely packed). + +Return value: +* True if update was applied +* False if kernel refused to perform an update. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_updatekernel4444(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t sheight, + ae_int_t offsu, + ae_int_t uheight, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + ae_int_t offsk; + double d0; + double d1; + double d2; + double d3; + double u00; + double u01; + double u02; + double u03; + double u10; + double u11; + double u12; + double u13; + double u20; + double u21; + double u22; + double u23; + double u30; + double u31; + double u32; + double u33; + double uk0; + double uk1; + double uk2; + double uk3; + ae_bool result; + + + d0 = diagd->ptr.p_double[offsd+0]; + d1 = diagd->ptr.p_double[offsd+1]; + d2 = diagd->ptr.p_double[offsd+2]; + d3 = diagd->ptr.p_double[offsd+3]; + u00 = d0*rowstorage->ptr.p_double[offsu+0*4+0]; + u01 = d1*rowstorage->ptr.p_double[offsu+0*4+1]; + u02 = d2*rowstorage->ptr.p_double[offsu+0*4+2]; + u03 = d3*rowstorage->ptr.p_double[offsu+0*4+3]; + u10 = d0*rowstorage->ptr.p_double[offsu+1*4+0]; + u11 = d1*rowstorage->ptr.p_double[offsu+1*4+1]; + u12 = d2*rowstorage->ptr.p_double[offsu+1*4+2]; + u13 = d3*rowstorage->ptr.p_double[offsu+1*4+3]; + u20 = d0*rowstorage->ptr.p_double[offsu+2*4+0]; + u21 = d1*rowstorage->ptr.p_double[offsu+2*4+1]; + u22 = d2*rowstorage->ptr.p_double[offsu+2*4+2]; + u23 = d3*rowstorage->ptr.p_double[offsu+2*4+3]; + u30 = d0*rowstorage->ptr.p_double[offsu+3*4+0]; + u31 = d1*rowstorage->ptr.p_double[offsu+3*4+1]; + u32 = d2*rowstorage->ptr.p_double[offsu+3*4+2]; + u33 = d3*rowstorage->ptr.p_double[offsu+3*4+3]; + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*4; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + uk3 = rowstorage->ptr.p_double[offsk+3]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2-u03*uk3; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2-u13*uk3; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2-u23*uk3; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2-u33*uk3; + } + result = ae_true; + return result; +} +#endif + + +#ifdef ALGLIB_NO_FAST_KERNELS +/************************************************************************* +Fast kernels for small supernodal updates: special 4x4x4x4 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs AxBxCx4 update, i.e.: +* S is a tHeight*A matrix with row stride equal to 4 (usually it means that + it has 3 or 4 columns) +* U is a uHeight*B matrix +* Uc' is a B*C matrix, with C<=A +* scatter() scatters rows and columns of U*Uc' + +Return value: +* True if update was applied +* False if kernel refused to perform an update (quick exit for unsupported + combinations of input sizes) + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_updatekernelabc4(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t urank, + ae_int_t urowstride, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + ae_int_t targetcol; + ae_int_t offsk; + double d0; + double d1; + double d2; + double d3; + double u00; + double u01; + double u02; + double u03; + double u10; + double u11; + double u12; + double u13; + double u20; + double u21; + double u22; + double u23; + double u30; + double u31; + double u32; + double u33; + double uk0; + double uk1; + double uk2; + double uk3; + ae_int_t srccol0; + ae_int_t srccol1; + ae_int_t srccol2; + ae_int_t srccol3; + ae_bool result; + + + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + result = ae_false; + if( twidth<3||twidth>4 ) + { + return result; + } + if( uwidth<3||uwidth>4 ) + { + return result; + } + if( urank>4 ) + { + return result; + } + + /* + * Determine source columns for target columns, -1 if target column + * is not updated. + */ + srccol0 = -1; + srccol1 = -1; + srccol2 = -1; + srccol3 = -1; + for(k=0; k<=uwidth-1; k++) + { + targetcol = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]; + if( targetcol==0 ) + { + srccol0 = k; + } + if( targetcol==1 ) + { + srccol1 = k; + } + if( targetcol==2 ) + { + srccol2 = k; + } + if( targetcol==3 ) + { + srccol3 = k; + } + } + + /* + * Load update matrix into aligned/rearranged 4x4 storage + */ + d0 = (double)(0); + d1 = (double)(0); + d2 = (double)(0); + d3 = (double)(0); + u00 = (double)(0); + u01 = (double)(0); + u02 = (double)(0); + u03 = (double)(0); + u10 = (double)(0); + u11 = (double)(0); + u12 = (double)(0); + u13 = (double)(0); + u20 = (double)(0); + u21 = (double)(0); + u22 = (double)(0); + u23 = (double)(0); + u30 = (double)(0); + u31 = (double)(0); + u32 = (double)(0); + u33 = (double)(0); + if( urank>=1 ) + { + d0 = diagd->ptr.p_double[offsd+0]; + } + if( urank>=2 ) + { + d1 = diagd->ptr.p_double[offsd+1]; + } + if( urank>=3 ) + { + d2 = diagd->ptr.p_double[offsd+2]; + } + if( urank>=4 ) + { + d3 = diagd->ptr.p_double[offsd+3]; + } + if( srccol0>=0 ) + { + if( urank>=1 ) + { + u00 = d0*rowstorage->ptr.p_double[offsu+srccol0*urowstride+0]; + } + if( urank>=2 ) + { + u01 = d1*rowstorage->ptr.p_double[offsu+srccol0*urowstride+1]; + } + if( urank>=3 ) + { + u02 = d2*rowstorage->ptr.p_double[offsu+srccol0*urowstride+2]; + } + if( urank>=4 ) + { + u03 = d3*rowstorage->ptr.p_double[offsu+srccol0*urowstride+3]; + } + } + if( srccol1>=0 ) + { + if( urank>=1 ) + { + u10 = d0*rowstorage->ptr.p_double[offsu+srccol1*urowstride+0]; + } + if( urank>=2 ) + { + u11 = d1*rowstorage->ptr.p_double[offsu+srccol1*urowstride+1]; + } + if( urank>=3 ) + { + u12 = d2*rowstorage->ptr.p_double[offsu+srccol1*urowstride+2]; + } + if( urank>=4 ) + { + u13 = d3*rowstorage->ptr.p_double[offsu+srccol1*urowstride+3]; + } + } + if( srccol2>=0 ) + { + if( urank>=1 ) + { + u20 = d0*rowstorage->ptr.p_double[offsu+srccol2*urowstride+0]; + } + if( urank>=2 ) + { + u21 = d1*rowstorage->ptr.p_double[offsu+srccol2*urowstride+1]; + } + if( urank>=3 ) + { + u22 = d2*rowstorage->ptr.p_double[offsu+srccol2*urowstride+2]; + } + if( urank>=4 ) + { + u23 = d3*rowstorage->ptr.p_double[offsu+srccol2*urowstride+3]; + } + } + if( srccol3>=0 ) + { + if( urank>=1 ) + { + u30 = d0*rowstorage->ptr.p_double[offsu+srccol3*urowstride+0]; + } + if( urank>=2 ) + { + u31 = d1*rowstorage->ptr.p_double[offsu+srccol3*urowstride+1]; + } + if( urank>=3 ) + { + u32 = d2*rowstorage->ptr.p_double[offsu+srccol3*urowstride+2]; + } + if( urank>=4 ) + { + u33 = d3*rowstorage->ptr.p_double[offsu+srccol3*urowstride+3]; + } + } + + /* + * Run update + */ + if( urank==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0; + } + } + if( urank==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1; + } + } + if( urank==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2; + } + } + if( urank==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*4; + offsk = offsu+k*urowstride; + uk0 = rowstorage->ptr.p_double[offsk+0]; + uk1 = rowstorage->ptr.p_double[offsk+1]; + uk2 = rowstorage->ptr.p_double[offsk+2]; + uk3 = rowstorage->ptr.p_double[offsk+3]; + rowstorage->ptr.p_double[targetrow+0] = rowstorage->ptr.p_double[targetrow+0]-u00*uk0-u01*uk1-u02*uk2-u03*uk3; + rowstorage->ptr.p_double[targetrow+1] = rowstorage->ptr.p_double[targetrow+1]-u10*uk0-u11*uk1-u12*uk2-u13*uk3; + rowstorage->ptr.p_double[targetrow+2] = rowstorage->ptr.p_double[targetrow+2]-u20*uk0-u21*uk1-u22*uk2-u23*uk3; + rowstorage->ptr.p_double[targetrow+3] = rowstorage->ptr.p_double[targetrow+3]-u30*uk0-u31*uk1-u32*uk2-u33*uk3; + } + } + result = ae_true; + return result; +} +#endif + + +/************************************************************************* +Fast kernels for small supernodal updates: special rank-1 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs rank-1 update, i.e.: +* S is a tHeight*A matrix, with A<=4 +* U is a uHeight*1 matrix with unit stride +* Uc' is a 1*B matrix, with B<=A +* scatter() scatters rows and columns of U*Uc' + +Return value: +* True if update was applied +* False if kernel refused to perform an update (quick exit for unsupported + combinations of input sizes) + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_updatekernelrank1(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t trowstride, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + double d0; + double u00; + double u10; + double u20; + double u30; + double uk; + ae_int_t col0; + ae_int_t col1; + ae_int_t col2; + ae_int_t col3; + ae_bool result; + + + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + result = ae_false; + if( twidth>4 ) + { + return result; + } + if( uwidth>4 ) + { + return result; + } + + /* + * Determine target columns, load update matrix + */ + d0 = diagd->ptr.p_double[offsd]; + col0 = 0; + col1 = 0; + col2 = 0; + col3 = 0; + u00 = (double)(0); + u10 = (double)(0); + u20 = (double)(0); + u30 = (double)(0); + if( uwidth>=1 ) + { + col0 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+0]]; + u00 = d0*rowstorage->ptr.p_double[offsu+0]; + } + if( uwidth>=2 ) + { + col1 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+1]]; + u10 = d0*rowstorage->ptr.p_double[offsu+1]; + } + if( uwidth>=3 ) + { + col2 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+2]]; + u20 = d0*rowstorage->ptr.p_double[offsu+2]; + } + if( uwidth>=4 ) + { + col3 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+3]]; + u30 = d0*rowstorage->ptr.p_double[offsu+3]; + } + + /* + * Run update + */ + if( uwidth==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk = rowstorage->ptr.p_double[offsu+k]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk; + } + } + if( uwidth==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk = rowstorage->ptr.p_double[offsu+k]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk; + } + } + if( uwidth==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk = rowstorage->ptr.p_double[offsu+k]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk; + rowstorage->ptr.p_double[targetrow+col2] = rowstorage->ptr.p_double[targetrow+col2]-u20*uk; + } + } + if( uwidth==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk = rowstorage->ptr.p_double[offsu+k]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk; + rowstorage->ptr.p_double[targetrow+col2] = rowstorage->ptr.p_double[targetrow+col2]-u20*uk; + rowstorage->ptr.p_double[targetrow+col3] = rowstorage->ptr.p_double[targetrow+col3]-u30*uk; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Fast kernels for small supernodal updates: special rank-2 function. + +! See comments on UpdateSupernode() for information on generic supernodal +! updates, including notation used below. + +The generic update has following form: + + S := S - scatter(U*D*Uc') + +This specialized function performs rank-2 update, i.e.: +* S is a tHeight*A matrix, with A<=4 +* U is a uHeight*2 matrix with row stride equal to 2 +* Uc' is a 2*B matrix, with B<=A +* scatter() scatters rows and columns of U*Uc + +Return value: +* True if update was applied +* False if kernel refused to perform an update (quick exit for unsupported + combinations of input sizes) + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +static ae_bool spchol_updatekernelrank2(/* Real */ ae_vector* rowstorage, + ae_int_t offss, + ae_int_t twidth, + ae_int_t trowstride, + ae_int_t offsu, + ae_int_t uheight, + ae_int_t uwidth, + /* Real */ const ae_vector* diagd, + ae_int_t offsd, + /* Integer */ const ae_vector* raw2smap, + /* Integer */ const ae_vector* superrowidx, + ae_int_t urbase, + ae_state *_state) +{ + ae_int_t k; + ae_int_t targetrow; + double d0; + double d1; + double u00; + double u10; + double u20; + double u30; + double u01; + double u11; + double u21; + double u31; + double uk0; + double uk1; + ae_int_t col0; + ae_int_t col1; + ae_int_t col2; + ae_int_t col3; + ae_bool result; + + + + /* + * Filter out unsupported combinations (ones that are too sparse for the non-SIMD code) + */ + result = ae_false; + if( twidth>4 ) + { + return result; + } + if( uwidth>4 ) + { + return result; + } + + /* + * Determine target columns, load update matrix + */ + d0 = diagd->ptr.p_double[offsd]; + d1 = diagd->ptr.p_double[offsd+1]; + col0 = 0; + col1 = 0; + col2 = 0; + col3 = 0; + u00 = (double)(0); + u01 = (double)(0); + u10 = (double)(0); + u11 = (double)(0); + u20 = (double)(0); + u21 = (double)(0); + u30 = (double)(0); + u31 = (double)(0); + if( uwidth>=1 ) + { + col0 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+0]]; + u00 = d0*rowstorage->ptr.p_double[offsu+0]; + u01 = d1*rowstorage->ptr.p_double[offsu+1]; + } + if( uwidth>=2 ) + { + col1 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+1]]; + u10 = d0*rowstorage->ptr.p_double[offsu+1*2+0]; + u11 = d1*rowstorage->ptr.p_double[offsu+1*2+1]; + } + if( uwidth>=3 ) + { + col2 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+2]]; + u20 = d0*rowstorage->ptr.p_double[offsu+2*2+0]; + u21 = d1*rowstorage->ptr.p_double[offsu+2*2+1]; + } + if( uwidth>=4 ) + { + col3 = raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+3]]; + u30 = d0*rowstorage->ptr.p_double[offsu+3*2+0]; + u31 = d1*rowstorage->ptr.p_double[offsu+3*2+1]; + } + + /* + * Run update + */ + if( uwidth==1 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk0 = rowstorage->ptr.p_double[offsu+2*k+0]; + uk1 = rowstorage->ptr.p_double[offsu+2*k+1]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk0-u01*uk1; + } + } + if( uwidth==2 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk0 = rowstorage->ptr.p_double[offsu+2*k+0]; + uk1 = rowstorage->ptr.p_double[offsu+2*k+1]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk0-u01*uk1; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk0-u11*uk1; + } + } + if( uwidth==3 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk0 = rowstorage->ptr.p_double[offsu+2*k+0]; + uk1 = rowstorage->ptr.p_double[offsu+2*k+1]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk0-u01*uk1; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk0-u11*uk1; + rowstorage->ptr.p_double[targetrow+col2] = rowstorage->ptr.p_double[targetrow+col2]-u20*uk0-u21*uk1; + } + } + if( uwidth==4 ) + { + for(k=0; k<=uheight-1; k++) + { + targetrow = offss+raw2smap->ptr.p_int[superrowidx->ptr.p_int[urbase+k]]*trowstride; + uk0 = rowstorage->ptr.p_double[offsu+2*k+0]; + uk1 = rowstorage->ptr.p_double[offsu+2*k+1]; + rowstorage->ptr.p_double[targetrow+col0] = rowstorage->ptr.p_double[targetrow+col0]-u00*uk0-u01*uk1; + rowstorage->ptr.p_double[targetrow+col1] = rowstorage->ptr.p_double[targetrow+col1]-u10*uk0-u11*uk1; + rowstorage->ptr.p_double[targetrow+col2] = rowstorage->ptr.p_double[targetrow+col2]-u20*uk0-u21*uk1; + rowstorage->ptr.p_double[targetrow+col3] = rowstorage->ptr.p_double[targetrow+col3]-u30*uk0-u31*uk1; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Generates sparsity-reducing permutation using priority AMD ordering + +INPUT PARAMETERS: + Analysis - analysis object + WrkA - matrix being analyzed, destroyed during analysis + Priorities - element priorities, destroyed during analysis + PromoteAbove, + PromoteTo - parameters, see SPSymmAnalyze() for more info + DebugOrdering - whether special debug ordering which tests all + algorithm branches is used. + DoTrace - whether trace is needed + Buf - temporary buffers provided by user + UserBuffers - whether to use buffers provided by user or local + buffers: + * if True, temporaries will be allocated by this + function in Buf and will be retained after the + function is done. Future calls to this function + will reuse previously allocated memory. Good + for many sequential tasks. + * if True, the function will allocate its own + local buffers. All memory allocated by this + function will be freed upon exit. Good for + large-scale one-off problems. + + -- ALGLIB routine -- + 17.11.2023 + Bochkanov Sergey +*************************************************************************/ +static void spchol_generatepriorityamdpermutation(sparsematrix* wrka, + /* Integer */ ae_vector* wrkpriorities, + double promoteabove, + ae_int_t promoteto, + ae_bool debugordering, + ae_bool dotrace, + ae_nxpool* n1bpool, + ae_nxpool* n1ipool, + priorityamdbuffers* buf, + ae_bool userbuffers, + /* Integer */ ae_vector* fillinperm, + /* Integer */ ae_vector* invfillinperm, + ae_state *_state) +{ + ae_frame _frame_block; + priorityamdbuffers *ptrlocalbuf; + ae_smart_ptr _ptrlocalbuf; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t n; + ae_int_t m; + ae_int_t range0; + ae_int_t range1; + ae_int_t newrange0; + ae_int_t promoteoffset; + ae_int_t npostponed; + ae_int_t eligiblecnt; + ae_vector eligible; + ae_vector tmp0; + + ae_frame_make(_state, &_frame_block); + memset(&_ptrlocalbuf, 0, sizeof(_ptrlocalbuf)); + memset(&eligible, 0, sizeof(eligible)); + memset(&tmp0, 0, sizeof(tmp0)); + ae_smart_ptr_init(&_ptrlocalbuf, (void**)&ptrlocalbuf, ae_false, _state, ae_true); + ae_vector_init(&eligible, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&tmp0, 0, DT_INT, _state, ae_true); + + + /* + * If local buffers have to be used, allocate one and run again + */ + if( !userbuffers ) + { + if( !(ptrlocalbuf!=NULL) ) + { + ptrlocalbuf = (priorityamdbuffers*)ae_malloc(sizeof(priorityamdbuffers), _state); /* note: using ptrlocalbuf as a temporary prior to assigning its value to _ptrlocalbuf */ + memset(ptrlocalbuf, 0, sizeof(priorityamdbuffers)); + _priorityamdbuffers_init(ptrlocalbuf, _state, ae_false); + ae_smart_ptr_assign(&_ptrlocalbuf, ptrlocalbuf, ae_true, ae_true, (ae_int_t)sizeof(priorityamdbuffers), _priorityamdbuffers_init_copy, _priorityamdbuffers_destroy); + } + spchol_generatepriorityamdpermutation(wrka, wrkpriorities, promoteabove, promoteto, debugordering, dotrace, n1bpool, n1ipool, ptrlocalbuf, ae_true, fillinperm, invfillinperm, _state); + ae_frame_leave(_state); + return; + } + + /* + * Initialize + */ + n = wrka->n; + ae_assert(wrkpriorities->cnt>=n, "SPSymmAnalyze: integrity check failed (4653)", _state); + + /* + * Retrieve temporary arrays + */ + ae_nxpool_retrieve(n1bpool, &eligible, _state); + ae_nxpool_retrieve(n1ipool, &tmp0, _state); + + /* + * Perform iterative AMD, with nearly-dense columns being postponed to be handled later. + * + * The current (residual) matrix A is divided into two parts: head, with its columns being + * properly ordered, and tail, with its columns being reordered at the next iteration. + * + * After each partial AMD we compute sparsity pattern of the tail, set it as the new residual + * and repeat iteration. + */ + iallocv(n, fillinperm, _state); + iallocv(n, invfillinperm, _state); + iallocv(n, &buf->tmpperm, _state); + iallocv(n, &buf->invtmpperm, _state); + for(i=0; i<=n-1; i++) + { + fillinperm->ptr.p_int[i] = i; + invfillinperm->ptr.p_int[i] = i; + } + range0 = 0; + range1 = n; + promoteoffset = 0; + while(range0ptr.p_int[i]; + if( (j>=range0&&jptr.p_int[i]<=0 ) + { + eligible.ptr.p_bool[j-range0] = ae_true; + eligiblecnt = eligiblecnt+1; + } + } + if( dotrace ) + { + ae_trace("> multiround AMD, column_range=[%7d,%7d] (%7d out of %7d), %5.1f%% eligible", + (int)(range0), + (int)(range1), + (int)(range1-range0), + (int)(n), + (double)((double)(100*eligiblecnt)/(double)m)); + } + newrange0 = range0+generateamdpermutationx(wrka, &eligible, range1-range0, promoteabove, &buf->tmpperm, &buf->invtmpperm, 1, &buf->amdtmp, _state); + if( debugordering ) + { + + /* + * Special debug ordering in order to test correctness of multiple AMD rounds + */ + newrange0 = ae_minint(newrange0, range0+m/2+1, _state); + } + for(i=0; i<=n-1; i++) + { + wrkpriorities->ptr.p_int[i] = wrkpriorities->ptr.p_int[i]-1; + } + promoteto = ae_maxint(promoteto-1, 0, _state); + promoteoffset = promoteoffset+1; + npostponed = 0; + for(i=0; i<=range1-newrange0-1; i++) + { + if( eligible.ptr.p_bool[buf->invtmpperm.ptr.p_int[newrange0-range0+i]] ) + { + + /* + * The column was marked as eligible, but was postponed due to its density. + * Promote column to a higher priority group. + */ + wrkpriorities->ptr.p_int[range0+buf->invtmpperm.ptr.p_int[newrange0-range0+i]] = promoteto; + npostponed = npostponed+1; + } + } + if( dotrace ) + { + if( npostponed>0 ) + { + ae_trace(", %5.1f%% postponed (promoted to elimination group %0d)", + (double)((double)(100*npostponed)/(double)m), + (int)(promoteoffset+promoteto)); + } + ae_trace("\n"); + } + + /* + * If there were columns that both eligible and sparse enough, + * apply permutation and recompute trail. + */ + if( newrange0>range0 ) + { + + /* + * Apply permutation TmpPerm[] to the tail of the permutation FillInPerm[] + */ + for(i=0; i<=m-1; i++) + { + fillinperm->ptr.p_int[invfillinperm->ptr.p_int[range0+buf->invtmpperm.ptr.p_int[i]]] = range0+i; + } + for(i=0; i<=n-1; i++) + { + invfillinperm->ptr.p_int[fillinperm->ptr.p_int[i]] = i; + } + + /* + * Compute partial Cholesky of the trailing submatrix (after applying rank-K update to the + * trailing submatrix but before Cholesky-factorizing it). + */ + if( newrange0tmpperm, &buf->tmpa2, _state); + spchol_partialcholeskypattern(&buf->tmpa2, newrange0-range0, range1-newrange0, wrka, n1ipool, n1bpool, &buf->tmpbottomt, &buf->tmpupdatet, &buf->tmpupdate, &buf->tmpnewtailt, _state); + } + range0 = newrange0; + m = range1-range0; + } + + /* + * Analyze sparsity pattern of the current submatrix (TmpA), manually move completely dense rows to the end. + */ + if( m>0 ) + { + ae_assert((wrka->m==m&&wrka->n==m)&&wrka->ninitialized==wrka->ridx.ptr.p_int[m], "SPSymmAnalyze: integrity check failed (0572)", _state); + isetv(m, 1, &tmp0, _state); + for(i=0; i<=m-1; i++) + { + j0 = wrka->ridx.ptr.p_int[i]; + j1 = wrka->didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = wrka->idx.ptr.p_int[jj]; + tmp0.ptr.p_int[i] = tmp0.ptr.p_int[i]+1; + tmp0.ptr.p_int[j] = tmp0.ptr.p_int[j]+1; + } + } + j = 0; + k = 0; + for(i=0; i<=m-1; i++) + { + if( tmp0.ptr.p_int[i]invtmpperm.ptr.p_int[j] = i; + j = j+1; + } + } + for(i=0; i<=m-1; i++) + { + if( tmp0.ptr.p_int[i]==m ) + { + buf->invtmpperm.ptr.p_int[j] = i; + j = j+1; + k = k+1; + } + } + for(i=0; i<=m-1; i++) + { + buf->tmpperm.ptr.p_int[buf->invtmpperm.ptr.p_int[i]] = i; + } + ae_assert(j==m, "SPSymmAnalyze: integrity check failed (6432)", _state); + if( k>0 ) + { + + /* + * K dense rows are moved to the end + */ + if( kptr.p_int[invfillinperm->ptr.p_int[range0+buf->invtmpperm.ptr.p_int[i]]] = range0+i; + } + for(i=0; i<=n-1; i++) + { + invfillinperm->ptr.p_int[fillinperm->ptr.p_int[i]] = i; + } + sparsesymmpermtblbuf(wrka, ae_false, &buf->tmpperm, &buf->tmpa2, _state); + sparsecopybuf(&buf->tmpa2, wrka, _state); + wrka->m = m-k; + wrka->n = m-k; + wrka->ninitialized = wrka->ridx.ptr.p_int[wrka->m]; + } + range1 = range1-k; + m = range1-range0; + } + } + } + if( dotrace ) + { + ae_trace("> multiround AMD, column_range=[%7d,%7d], stopped\n", + (int)(range0), + (int)(range1)); + } + + /* + * Recycle temporary arrays + */ + ae_nxpool_recycle(n1bpool, &eligible, _state); + ae_nxpool_recycle(n1ipool, &tmp0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +More efficient SparseSymmPermTblTransposeBuf() that does not sort its output +*************************************************************************/ +static void spchol_permtransposeunsorted(const sparsematrix* a, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k0; + ae_int_t k1; + ae_int_t kk; + ae_int_t n; + ae_int_t dst; + + + n = a->n; + + /* + * Prepare output + */ + b->matrixtype = 1; + b->n = n; + b->m = n; + ivectorsetlengthatleast(&b->didx, n, _state); + ivectorsetlengthatleast(&b->uidx, n, _state); + + /* + * Determine row sizes (temporary stored in DIdx) and ranges + */ + isetv(n, 0, &b->didx, _state); + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + k0 = p->ptr.p_int[i]; + for(jj=j0; jj<=j1; jj++) + { + k1 = p->ptr.p_int[a->idx.ptr.p_int[jj]]; + if( k1didx.ptr.p_int[k1] = b->didx.ptr.p_int[k1]+1; + } + else + { + b->didx.ptr.p_int[k0] = b->didx.ptr.p_int[k0]+1; + } + } + } + ivectorsetlengthatleast(&b->ridx, n+1, _state); + b->ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + b->ridx.ptr.p_int[i+1] = b->ridx.ptr.p_int[i]+b->didx.ptr.p_int[i]; + } + b->ninitialized = b->ridx.ptr.p_int[n]; + ivectorsetlengthatleast(&b->idx, b->ninitialized, _state); + rvectorsetlengthatleast(&b->vals, b->ninitialized, _state); + + /* + * Process the matrix + */ + for(i=0; i<=n-1; i++) + { + b->uidx.ptr.p_int[i] = b->ridx.ptr.p_int[i]; + } + for(i=0; i<=n-1; i++) + { + j0 = a->ridx.ptr.p_int[i]; + j1 = a->uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = a->idx.ptr.p_int[jj]; + k0 = p->ptr.p_int[i]; + k1 = p->ptr.p_int[j]; + if( k1uidx.ptr.p_int[k0]; + b->idx.ptr.p_int[dst] = k1; + b->vals.ptr.p_double[dst] = a->vals.ptr.p_double[jj]; + b->uidx.ptr.p_int[k0] = dst+1; + } + } +} + + +/************************************************************************* +Fill Raw2SMap +*************************************************************************/ +static void spchol_fillraw2smap(/* Integer */ const ae_vector* superrowidx, + ae_int_t sidx, + ae_int_t cols0, + ae_int_t cols1, + ae_int_t ridx0, + ae_int_t ridx1, + ae_int_t blocksize, + /* Integer */ ae_vector* raw2smap, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + ridx1 = ridx1-1; + for(i=cols0; i<=cols1-1; i++) + { + raw2smap->ptr.p_int[i] = i-cols0; + } + for(k=ridx0; k<=ridx1; k++) + { + raw2smap->ptr.p_int[superrowidx->ptr.p_int[k]] = blocksize+(k-ridx0); + } +} + + +void _priorityamdbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + priorityamdbuffers *p = (priorityamdbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->tmpperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->invtmpperm, 0, DT_INT, _state, make_automatic); + _amdbuffer_init(&p->amdtmp, _state, make_automatic); + _sparsematrix_init(&p->tmpa2, _state, make_automatic); + _sparsematrix_init(&p->tmpbottomt, _state, make_automatic); + _sparsematrix_init(&p->tmpupdate, _state, make_automatic); + _sparsematrix_init(&p->tmpupdatet, _state, make_automatic); + _sparsematrix_init(&p->tmpnewtailt, _state, make_automatic); +} + + +void _priorityamdbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + priorityamdbuffers *dst = (priorityamdbuffers*)_dst; + const priorityamdbuffers *src = (const priorityamdbuffers*)_src; + ae_vector_init_copy(&dst->tmpperm, &src->tmpperm, _state, make_automatic); + ae_vector_init_copy(&dst->invtmpperm, &src->invtmpperm, _state, make_automatic); + _amdbuffer_init_copy(&dst->amdtmp, &src->amdtmp, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpa2, &src->tmpa2, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpbottomt, &src->tmpbottomt, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpupdate, &src->tmpupdate, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpupdatet, &src->tmpupdatet, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpnewtailt, &src->tmpnewtailt, _state, make_automatic); +} + + +void _priorityamdbuffers_clear(void* _p) +{ + priorityamdbuffers *p = (priorityamdbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->tmpperm); + ae_vector_clear(&p->invtmpperm); + _amdbuffer_clear(&p->amdtmp); + _sparsematrix_clear(&p->tmpa2); + _sparsematrix_clear(&p->tmpbottomt); + _sparsematrix_clear(&p->tmpupdate); + _sparsematrix_clear(&p->tmpupdatet); + _sparsematrix_clear(&p->tmpnewtailt); +} + + +void _priorityamdbuffers_destroy(void* _p) +{ + priorityamdbuffers *p = (priorityamdbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->tmpperm); + ae_vector_destroy(&p->invtmpperm); + _amdbuffer_destroy(&p->amdtmp); + _sparsematrix_destroy(&p->tmpa2); + _sparsematrix_destroy(&p->tmpbottomt); + _sparsematrix_destroy(&p->tmpupdate); + _sparsematrix_destroy(&p->tmpupdatet); + _sparsematrix_destroy(&p->tmpnewtailt); +} + + +void _spcholadj_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spcholadj *p = (spcholadj*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rowbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rowend, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->urow0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->uwidth, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->uflop, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nflop, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sflop, 0, DT_REAL, _state, make_automatic); +} + + +void _spcholadj_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spcholadj *dst = (spcholadj*)_dst; + const spcholadj *src = (const spcholadj*)_src; + ae_vector_init_copy(&dst->rowbegin, &src->rowbegin, _state, make_automatic); + ae_vector_init_copy(&dst->rowend, &src->rowend, _state, make_automatic); + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->urow0, &src->urow0, _state, make_automatic); + ae_vector_init_copy(&dst->uwidth, &src->uwidth, _state, make_automatic); + ae_vector_init_copy(&dst->uflop, &src->uflop, _state, make_automatic); + ae_vector_init_copy(&dst->nflop, &src->nflop, _state, make_automatic); + ae_vector_init_copy(&dst->sflop, &src->sflop, _state, make_automatic); +} + + +void _spcholadj_clear(void* _p) +{ + spcholadj *p = (spcholadj*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rowbegin); + ae_vector_clear(&p->rowend); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->urow0); + ae_vector_clear(&p->uwidth); + ae_vector_clear(&p->uflop); + ae_vector_clear(&p->nflop); + ae_vector_clear(&p->sflop); +} + + +void _spcholadj_destroy(void* _p) +{ + spcholadj *p = (spcholadj*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rowbegin); + ae_vector_destroy(&p->rowend); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->urow0); + ae_vector_destroy(&p->uwidth); + ae_vector_destroy(&p->uflop); + ae_vector_destroy(&p->nflop); + ae_vector_destroy(&p->sflop); +} + + +void _spcholanalysis_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + spcholanalysis *p = (spcholanalysis*)_p; + ae_touch_ptr((void*)p); + ae_opaque_object_init(&p->pbl, _state, make_automatic); + _sparsematrix_init(&p->pbla, _state, make_automatic); + ae_vector_init(&p->fillinperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->invfillinperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->effectiveperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->inveffectiveperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->bsigns, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rpivotsigns, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->referenceridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->parentsupernode, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->childsupernodesridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->childsupernodesidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->supercolrange, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->superrowridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->superrowidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->superperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->invsuperperm, 0, DT_INT, _state, make_automatic); + _spcholadj_init(&p->ladj, _state, make_automatic); + ae_vector_init(&p->outrowcounts, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->inputstorage, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->outputstorage, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rowstrides, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rowoffsets, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->diagd, 0, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->n1booleanpool, DT_BOOL, _state, make_automatic); + ae_nxpool_init(&p->ns1booleanpool, DT_BOOL, _state, make_automatic); + ae_nxpool_init(&p->n1integerpool, DT_INT, _state, make_automatic); + ae_nxpool_init(&p->ns1integerpool, DT_INT, _state, make_automatic); + ae_nxpool_init(&p->nrealpool, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->ns1realpool, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curladjrowbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->flagarray, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->curpriorities, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpparent, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->node2supernode, 0, DT_INT, _state, make_automatic); + ae_smart_ptr_init(&p->_ptramdtmp, (void**)&p->ptramdtmp, ae_true, _state, make_automatic); + ae_smart_ptr_init(&p->_ptrpamdtmp, (void**)&p->ptrpamdtmp, ae_true, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp3, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp4, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->raw2smap, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->tmpa, _state, make_automatic); + _sparsematrix_init(&p->tmpat, _state, make_automatic); + ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->simdbuf, 0, DT_REAL, _state, make_automatic); +} + + +void _spcholanalysis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + spcholanalysis *dst = (spcholanalysis*)_dst; + const spcholanalysis *src = (const spcholanalysis*)_src; + dst->tasktype = src->tasktype; + dst->n = src->n; + dst->unitd = src->unitd; + dst->dotrace = src->dotrace; + dst->pblrequested = src->pblrequested; + dst->pblused = src->pblused; + ae_opaque_object_init_copy(&dst->pbl, &src->pbl, _state, make_automatic); + dst->pblneedsl = src->pblneedsl; + _sparsematrix_init_copy(&dst->pbla, &src->pbla, _state, make_automatic); + dst->pblachanged = src->pblachanged; + ae_vector_init_copy(&dst->fillinperm, &src->fillinperm, _state, make_automatic); + ae_vector_init_copy(&dst->invfillinperm, &src->invfillinperm, _state, make_automatic); + ae_vector_init_copy(&dst->effectiveperm, &src->effectiveperm, _state, make_automatic); + ae_vector_init_copy(&dst->inveffectiveperm, &src->inveffectiveperm, _state, make_automatic); + dst->permtype = src->permtype; + dst->modtype = src->modtype; + dst->modparam0 = src->modparam0; + dst->modparam1 = src->modparam1; + dst->modparam2 = src->modparam2; + dst->modparam3 = src->modparam3; + ae_vector_init_copy(&dst->bsigns, &src->bsigns, _state, make_automatic); + dst->debugblocksupernodal = src->debugblocksupernodal; + dst->extendeddebug = src->extendeddebug; + dst->dotracescheduler = src->dotracescheduler; + dst->dotracesupernodalstructure = src->dotracesupernodalstructure; + ae_vector_init_copy(&dst->rpivotsigns, &src->rpivotsigns, _state, make_automatic); + ae_vector_init_copy(&dst->referenceridx, &src->referenceridx, _state, make_automatic); + dst->nsuper = src->nsuper; + ae_vector_init_copy(&dst->parentsupernode, &src->parentsupernode, _state, make_automatic); + ae_vector_init_copy(&dst->childsupernodesridx, &src->childsupernodesridx, _state, make_automatic); + ae_vector_init_copy(&dst->childsupernodesidx, &src->childsupernodesidx, _state, make_automatic); + ae_vector_init_copy(&dst->supercolrange, &src->supercolrange, _state, make_automatic); + ae_vector_init_copy(&dst->superrowridx, &src->superrowridx, _state, make_automatic); + ae_vector_init_copy(&dst->superrowidx, &src->superrowidx, _state, make_automatic); + dst->useparallelism = src->useparallelism; + ae_vector_init_copy(&dst->superperm, &src->superperm, _state, make_automatic); + ae_vector_init_copy(&dst->invsuperperm, &src->invsuperperm, _state, make_automatic); + dst->istopologicalordering = src->istopologicalordering; + dst->applypermutationtooutput = src->applypermutationtooutput; + _spcholadj_init_copy(&dst->ladj, &src->ladj, _state, make_automatic); + ae_vector_init_copy(&dst->outrowcounts, &src->outrowcounts, _state, make_automatic); + ae_vector_init_copy(&dst->inputstorage, &src->inputstorage, _state, make_automatic); + ae_vector_init_copy(&dst->outputstorage, &src->outputstorage, _state, make_automatic); + ae_vector_init_copy(&dst->rowstrides, &src->rowstrides, _state, make_automatic); + ae_vector_init_copy(&dst->rowoffsets, &src->rowoffsets, _state, make_automatic); + ae_vector_init_copy(&dst->diagd, &src->diagd, _state, make_automatic); + ae_nxpool_init_copy(&dst->n1booleanpool, &src->n1booleanpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->ns1booleanpool, &src->ns1booleanpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->n1integerpool, &src->n1integerpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->ns1integerpool, &src->ns1integerpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->nrealpool, &src->nrealpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->ns1realpool, &src->ns1realpool, _state, make_automatic); + ae_vector_init_copy(&dst->curladjrowbegin, &src->curladjrowbegin, _state, make_automatic); + ae_vector_init_copy(&dst->flagarray, &src->flagarray, _state, make_automatic); + ae_vector_init_copy(&dst->curpriorities, &src->curpriorities, _state, make_automatic); + ae_vector_init_copy(&dst->tmpparent, &src->tmpparent, _state, make_automatic); + ae_vector_init_copy(&dst->node2supernode, &src->node2supernode, _state, make_automatic); + ae_smart_ptr_init(&dst->_ptramdtmp, (void**)&dst->ptramdtmp, ae_true, _state, make_automatic); + if( src->ptramdtmp!=NULL ) + { + dst->ptramdtmp = (amdbuffer*)ae_malloc(sizeof(amdbuffer), _state); /* note: using ptramdtmp as a temporary prior to assigning its value to _ptramdtmp */ + memset(dst->ptramdtmp, 0, sizeof(amdbuffer)); + _amdbuffer_init_copy(dst->ptramdtmp, src->ptramdtmp, _state, ae_false); + ae_smart_ptr_assign(&dst->_ptramdtmp, dst->ptramdtmp, ae_true, ae_true, (ae_int_t)sizeof(amdbuffer), _amdbuffer_init_copy, _amdbuffer_destroy); + } + ae_smart_ptr_init(&dst->_ptrpamdtmp, (void**)&dst->ptrpamdtmp, ae_true, _state, make_automatic); + if( src->ptrpamdtmp!=NULL ) + { + dst->ptrpamdtmp = (priorityamdbuffers*)ae_malloc(sizeof(priorityamdbuffers), _state); /* note: using ptrpamdtmp as a temporary prior to assigning its value to _ptrpamdtmp */ + memset(dst->ptrpamdtmp, 0, sizeof(priorityamdbuffers)); + _priorityamdbuffers_init_copy(dst->ptrpamdtmp, src->ptrpamdtmp, _state, ae_false); + ae_smart_ptr_assign(&dst->_ptrpamdtmp, dst->ptrpamdtmp, ae_true, ae_true, (ae_int_t)sizeof(priorityamdbuffers), _priorityamdbuffers_init_copy, _priorityamdbuffers_destroy); + } + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state, make_automatic); + ae_vector_init_copy(&dst->tmp4, &src->tmp4, _state, make_automatic); + ae_vector_init_copy(&dst->raw2smap, &src->raw2smap, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpa, &src->tmpa, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpat, &src->tmpat, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic); + ae_vector_init_copy(&dst->simdbuf, &src->simdbuf, _state, make_automatic); +} + + +void _spcholanalysis_clear(void* _p) +{ + spcholanalysis *p = (spcholanalysis*)_p; + ae_touch_ptr((void*)p); + ae_opaque_object_clear(&p->pbl); + _sparsematrix_clear(&p->pbla); + ae_vector_clear(&p->fillinperm); + ae_vector_clear(&p->invfillinperm); + ae_vector_clear(&p->effectiveperm); + ae_vector_clear(&p->inveffectiveperm); + ae_vector_clear(&p->bsigns); + ae_vector_clear(&p->rpivotsigns); + ae_vector_clear(&p->referenceridx); + ae_vector_clear(&p->parentsupernode); + ae_vector_clear(&p->childsupernodesridx); + ae_vector_clear(&p->childsupernodesidx); + ae_vector_clear(&p->supercolrange); + ae_vector_clear(&p->superrowridx); + ae_vector_clear(&p->superrowidx); + ae_vector_clear(&p->superperm); + ae_vector_clear(&p->invsuperperm); + _spcholadj_clear(&p->ladj); + ae_vector_clear(&p->outrowcounts); + ae_vector_clear(&p->inputstorage); + ae_vector_clear(&p->outputstorage); + ae_vector_clear(&p->rowstrides); + ae_vector_clear(&p->rowoffsets); + ae_vector_clear(&p->diagd); + ae_nxpool_clear(&p->n1booleanpool); + ae_nxpool_clear(&p->ns1booleanpool); + ae_nxpool_clear(&p->n1integerpool); + ae_nxpool_clear(&p->ns1integerpool); + ae_nxpool_clear(&p->nrealpool); + ae_nxpool_clear(&p->ns1realpool); + ae_vector_clear(&p->curladjrowbegin); + ae_vector_clear(&p->flagarray); + ae_vector_clear(&p->curpriorities); + ae_vector_clear(&p->tmpparent); + ae_vector_clear(&p->node2supernode); + ae_smart_ptr_clear(&p->_ptramdtmp); + ae_smart_ptr_clear(&p->_ptrpamdtmp); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmp3); + ae_vector_clear(&p->tmp4); + ae_vector_clear(&p->raw2smap); + _sparsematrix_clear(&p->tmpa); + _sparsematrix_clear(&p->tmpat); + ae_vector_clear(&p->tmpx); + ae_vector_clear(&p->simdbuf); +} + + +void _spcholanalysis_destroy(void* _p) +{ + spcholanalysis *p = (spcholanalysis*)_p; + ae_touch_ptr((void*)p); + ae_opaque_object_destroy(&p->pbl); + _sparsematrix_destroy(&p->pbla); + ae_vector_destroy(&p->fillinperm); + ae_vector_destroy(&p->invfillinperm); + ae_vector_destroy(&p->effectiveperm); + ae_vector_destroy(&p->inveffectiveperm); + ae_vector_destroy(&p->bsigns); + ae_vector_destroy(&p->rpivotsigns); + ae_vector_destroy(&p->referenceridx); + ae_vector_destroy(&p->parentsupernode); + ae_vector_destroy(&p->childsupernodesridx); + ae_vector_destroy(&p->childsupernodesidx); + ae_vector_destroy(&p->supercolrange); + ae_vector_destroy(&p->superrowridx); + ae_vector_destroy(&p->superrowidx); + ae_vector_destroy(&p->superperm); + ae_vector_destroy(&p->invsuperperm); + _spcholadj_destroy(&p->ladj); + ae_vector_destroy(&p->outrowcounts); + ae_vector_destroy(&p->inputstorage); + ae_vector_destroy(&p->outputstorage); + ae_vector_destroy(&p->rowstrides); + ae_vector_destroy(&p->rowoffsets); + ae_vector_destroy(&p->diagd); + ae_nxpool_destroy(&p->n1booleanpool); + ae_nxpool_destroy(&p->ns1booleanpool); + ae_nxpool_destroy(&p->n1integerpool); + ae_nxpool_destroy(&p->ns1integerpool); + ae_nxpool_destroy(&p->nrealpool); + ae_nxpool_destroy(&p->ns1realpool); + ae_vector_destroy(&p->curladjrowbegin); + ae_vector_destroy(&p->flagarray); + ae_vector_destroy(&p->curpriorities); + ae_vector_destroy(&p->tmpparent); + ae_vector_destroy(&p->node2supernode); + ae_smart_ptr_destroy(&p->_ptramdtmp); + ae_smart_ptr_destroy(&p->_ptrpamdtmp); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmp3); + ae_vector_destroy(&p->tmp4); + ae_vector_destroy(&p->raw2smap); + _sparsematrix_destroy(&p->tmpa); + _sparsematrix_destroy(&p->tmpat); + ae_vector_destroy(&p->tmpx); + ae_vector_destroy(&p->simdbuf); +} + + +#endif +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +LU decomposition of a general real matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlu(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + + ae_vector_clear(pivots); + + ae_assert(m>0, "RMatrixLU: incorrect M!", _state); + ae_assert(n>0, "RMatrixLU: incorrect N!", _state); + ae_assert(a->rows>=m, "RMatrixLU: rows(A)cols>=n, "RMatrixLU: cols(A)0, "CMatrixLU: incorrect M!", _state); + ae_assert(n>0, "CMatrixLU: incorrect N!", _state); + ae_assert(a->rows>=m, "CMatrixLU: rows(A)cols>=n, "CMatrixLU: cols(A)0, "HPDMatrixCholesky: incorrect N!", _state); + ae_assert(a->rows>=n, "HPDMatrixCholesky: rows(A)cols>=n, "HPDMatrixCholesky: cols(A)0, "SPDMatrixCholesky: incorrect N!", _state); + ae_assert(a->rows>=n, "SPDMatrixCholesky: rows(A)cols>=n, "SPDMatrixCholesky: cols(A)0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* u, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector bufr; + + ae_frame_make(_state, &_frame_block); + memset(&bufr, 0, sizeof(bufr)); + ae_vector_init(&bufr, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixCholeskyUpdateAdd1: N<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateAdd1: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateAdd1: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateAdd1: Length(U) ( Af20 0 Af22 Af23 ) + ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) + + If we have Cholesky decomposition of A, it must be recalculated after + variables were fixed. However, it is possible to use efficient + algorithm, which needs O(K*N^2) time to "fix" K variables, given + Cholesky decomposition of original, "unfixed" A. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + +NOTE: this function is efficient only for moderate amount of updated + variables - say, 0.1*N or 0.3*N. For larger amount of variables it + will still work, but you may get better performance with + straightforward Cholesky. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefix(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Boolean */ const ae_vector* fix, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector bufr; + + ae_frame_make(_state, &_frame_block); + memset(&bufr, 0, sizeof(bufr)); + ae_vector_init(&bufr, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixCholeskyUpdateFix: N<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateFix: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateFix: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateFix: Length(Fix)0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1buf(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* u, + /* Real */ ae_vector* bufr, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nz; + double cs; + double sn; + double v; + double vv; + + + ae_assert(n>0, "SPDMatrixCholeskyUpdateAdd1Buf: N<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateAdd1Buf: Length(U)ptr.p_double[i],(double)(0)) ) + { + nz = i; + break; + } + } + if( nz==n ) + { + + /* + * Nothing to update + */ + return; + } + + /* + * If working with upper triangular matrix + */ + if( isupper ) + { + + /* + * Perform a sequence of updates which fix variables one by one. + * This approach is different from one which is used when we work + * with lower triangular matrix. + */ + rvectorsetlengthatleast(bufr, n, _state); + for(j=nz; j<=n-1; j++) + { + bufr->ptr.p_double[j] = u->ptr.p_double[j]; + } + for(i=nz; i<=n-1; i++) + { + if( ae_fp_neq(bufr->ptr.p_double[i],(double)(0)) ) + { + generaterotation(a->ptr.pp_double[i][i], bufr->ptr.p_double[i], &cs, &sn, &v, _state); + a->ptr.pp_double[i][i] = v; + bufr->ptr.p_double[i] = 0.0; + for(j=i+1; j<=n-1; j++) + { + v = a->ptr.pp_double[i][j]; + vv = bufr->ptr.p_double[j]; + a->ptr.pp_double[i][j] = cs*v+sn*vv; + bufr->ptr.p_double[j] = -sn*v+cs*vv; + } + } + } + } + else + { + + /* + * Calculate rows of modified Cholesky factor, row-by-row + * (updates performed during variable fixing are applied + * simultaneously to each row) + */ + rvectorsetlengthatleast(bufr, 3*n, _state); + for(j=nz; j<=n-1; j++) + { + bufr->ptr.p_double[j] = u->ptr.p_double[j]; + } + for(i=nz; i<=n-1; i++) + { + + /* + * Update all previous updates [Idx+1...I-1] to I-th row + */ + vv = bufr->ptr.p_double[i]; + for(j=nz; j<=i-1; j++) + { + cs = bufr->ptr.p_double[n+2*j+0]; + sn = bufr->ptr.p_double[n+2*j+1]; + v = a->ptr.pp_double[i][j]; + a->ptr.pp_double[i][j] = cs*v+sn*vv; + vv = -sn*v+cs*vv; + } + + /* + * generate rotation applied to I-th element of update vector + */ + generaterotation(a->ptr.pp_double[i][i], vv, &cs, &sn, &v, _state); + a->ptr.pp_double[i][i] = v; + bufr->ptr.p_double[n+2*i+0] = cs; + bufr->ptr.p_double[n+2*i+1] = sn; + } + } +} + + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +See comments for SPDMatrixCholeskyUpdateFix() for more information. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefixbuf(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Boolean */ const ae_vector* fix, + /* Real */ ae_vector* bufr, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nfix; + ae_int_t idx; + double cs; + double sn; + double v; + double vv; + + + ae_assert(n>0, "SPDMatrixCholeskyUpdateFixBuf: N<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixCholeskyUpdateFixBuf: Rows(A)cols>=n, "SPDMatrixCholeskyUpdateFixBuf: Cols(A)cnt>=n, "SPDMatrixCholeskyUpdateFixBuf: Length(Fix)ptr.p_bool[i] ) + { + inc(&nfix, _state); + } + } + if( nfix==0 ) + { + + /* + * Nothing to fix + */ + return; + } + if( nfix==n ) + { + + /* + * All variables are fixed. + * Set A to identity and exit. + */ + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + a->ptr.pp_double[i][i] = (double)(1); + for(j=i+1; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + a->ptr.pp_double[i][i] = (double)(1); + } + } + return; + } + + /* + * If working with upper triangular matrix + */ + if( isupper ) + { + + /* + * Perform a sequence of updates which fix variables one by one. + * This approach is different from one which is used when we work + * with lower triangular matrix. + */ + rvectorsetlengthatleast(bufr, n, _state); + for(k=0; k<=n-1; k++) + { + if( fix->ptr.p_bool[k] ) + { + idx = k; + + /* + * Quick exit if it is last variable + */ + if( idx==n-1 ) + { + for(i=0; i<=idx-1; i++) + { + a->ptr.pp_double[i][idx] = 0.0; + } + a->ptr.pp_double[idx][idx] = 1.0; + continue; + } + + /* + * We have Cholesky decomposition of quadratic term in A, + * with upper triangle being stored as given below: + * + * ( U00 u01 U02 ) + * U = ( u11 u12 ) + * ( U22 ) + * + * Here u11 is diagonal element corresponding to variable K. We + * want to fix this variable, and we do so by modifying U as follows: + * + * ( U00 0 U02 ) + * U_mod = ( 1 0 ) + * ( U_m ) + * + * with U_m = CHOLESKY [ (U22^T)*U22 + (u12^T)*u12 ] + * + * Of course, we can calculate U_m by calculating (U22^T)*U22 explicitly, + * modifying it and performing Cholesky decomposition of modified matrix. + * However, we can treat it as follows: + * * we already have CHOLESKY[(U22^T)*U22], which is equal to U22 + * * we have rank-1 update (u12^T)*u12 applied to (U22^T)*U22 + * * thus, we can calculate updated Cholesky with O(N^2) algorithm + * instead of O(N^3) one + */ + for(j=idx+1; j<=n-1; j++) + { + bufr->ptr.p_double[j] = a->ptr.pp_double[idx][j]; + } + for(i=0; i<=idx-1; i++) + { + a->ptr.pp_double[i][idx] = 0.0; + } + a->ptr.pp_double[idx][idx] = 1.0; + for(i=idx+1; i<=n-1; i++) + { + a->ptr.pp_double[idx][i] = 0.0; + } + for(i=idx+1; i<=n-1; i++) + { + if( ae_fp_neq(bufr->ptr.p_double[i],(double)(0)) ) + { + generaterotation(a->ptr.pp_double[i][i], bufr->ptr.p_double[i], &cs, &sn, &v, _state); + a->ptr.pp_double[i][i] = v; + bufr->ptr.p_double[i] = 0.0; + for(j=i+1; j<=n-1; j++) + { + v = a->ptr.pp_double[i][j]; + vv = bufr->ptr.p_double[j]; + a->ptr.pp_double[i][j] = cs*v+sn*vv; + bufr->ptr.p_double[j] = -sn*v+cs*vv; + } + } + } + } + } + } + else + { + + /* + * Calculate rows of modified Cholesky factor, row-by-row + * (updates performed during variable fixing are applied + * simultaneously to each row) + */ + rvectorsetlengthatleast(bufr, 3*n, _state); + for(k=0; k<=n-1; k++) + { + if( fix->ptr.p_bool[k] ) + { + idx = k; + + /* + * Quick exit if it is last variable + */ + if( idx==n-1 ) + { + for(i=0; i<=idx-1; i++) + { + a->ptr.pp_double[idx][i] = 0.0; + } + a->ptr.pp_double[idx][idx] = 1.0; + continue; + } + + /* + * store column to buffer and clear row/column of A + */ + for(j=idx+1; j<=n-1; j++) + { + bufr->ptr.p_double[j] = a->ptr.pp_double[j][idx]; + } + for(i=0; i<=idx-1; i++) + { + a->ptr.pp_double[idx][i] = 0.0; + } + a->ptr.pp_double[idx][idx] = 1.0; + for(i=idx+1; i<=n-1; i++) + { + a->ptr.pp_double[i][idx] = 0.0; + } + + /* + * Apply update to rows of A + */ + for(i=idx+1; i<=n-1; i++) + { + + /* + * Update all previous updates [Idx+1...I-1] to I-th row + */ + vv = bufr->ptr.p_double[i]; + for(j=idx+1; j<=i-1; j++) + { + cs = bufr->ptr.p_double[n+2*j+0]; + sn = bufr->ptr.p_double[n+2*j+1]; + v = a->ptr.pp_double[i][j]; + a->ptr.pp_double[i][j] = cs*v+sn*vv; + vv = -sn*v+cs*vv; + } + + /* + * generate rotation applied to I-th element of update vector + */ + generaterotation(a->ptr.pp_double[i][i], vv, &cs, &sn, &v, _state); + a->ptr.pp_double[i][i] = v; + bufr->ptr.p_double[n+2*i+0] = cs; + bufr->ptr.p_double[n+2*i+1] = sn; + } + } + } + } +} + + +/************************************************************************* +Sparse LU decomposition with column pivoting for sparsity and row pivoting +for stability. Input must be square sparse matrix stored in CRS format. + +The algorithm computes LU decomposition of a general square matrix +(rectangular ones are not supported). The result of an algorithm is a +representation of A as A = P*L*U*Q, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=N-1, Pi - permutation matrix for I and P[I] +* Q = QK*...*Q1*Q0, K=N-1, Qi - permutation matrix for I and Q[I] + +This function pivots columns for higher sparsity, and then pivots rows for +stability (larger element at the diagonal). + +INPUT PARAMETERS: + A - sparse NxN matrix in CRS format. An exception is generated + if matrix is non-CRS or non-square. + PivotType- pivoting strategy: + * 0 for best pivoting available (2 in current version) + * 1 for row-only pivoting (NOT RECOMMENDED) + * 2 for complete pivoting which produces most sparse outputs + +OUTPUT PARAMETERS: + A - the result of factorization, matrices L and U stored in + compact form using CRS sparse storage format: + * lower unitriangular L is stored strictly under main diagonal + * upper triangilar U is stored ON and ABOVE main diagonal + P - row permutation matrix in compact form, array[N] + Q - col permutation matrix in compact form, array[N] + +This function always succeeds, i.e. it ALWAYS returns valid factorization, +but for your convenience it also returns boolean value which helps to +detect symbolically degenerate matrices: +* function returns TRUE, if the matrix was factorized AND symbolically + non-degenerate +* function returns FALSE, if the matrix was factorized but U has strictly + zero elements at the diagonal (the factorization is returned anyway). + + + -- ALGLIB routine -- + 03.09.2018 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparselu(sparsematrix* a, + ae_int_t pivottype, + /* Integer */ ae_vector* p, + /* Integer */ ae_vector* q, + ae_state *_state) +{ + ae_frame _frame_block; + sluv2buffer buf2; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&buf2, 0, sizeof(buf2)); + ae_vector_clear(p); + ae_vector_clear(q); + _sluv2buffer_init(&buf2, _state, ae_true); + + ae_assert((pivottype==0||pivottype==1)||pivottype==2, "SparseLU: unexpected pivot type", _state); + ae_assert(sparseiscrs(a, _state), "SparseLU: A is not stored in CRS format", _state); + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseLU: non-square A", _state); + result = sptrflu(a, pivottype, p, q, &buf2, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Sparse Cholesky decomposition for skyline matrixm using in-place algorithm +without allocating additional storage. + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite sparse matrix. The result of an algorithm is a representation of +A as A=U^T*U or A=L*L^T + +This function allows to perform very efficient decomposition of low-profile +matrices (average bandwidth is ~5-10 elements). For larger matrices it is +recommended to use supernodal Cholesky decomposition: SparseCholeskyP() or +SparseCholeskyAnalyze()/SparseCholeskyFactorize(). + +INPUT PARAMETERS: + A - sparse matrix in skyline storage (SKS) format. + N - size of matrix A (can be smaller than actual size of A) + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored (it may contant some + data, but it is not changed). + + +OUTPUT PARAMETERS: + A - the result of factorization, stored in SKS. If IsUpper=True, + then the upper triangle contains matrix U, such that + A = U^T*U. Lower triangle is not changed. + Similarly, if IsUpper = False. In this case L is returned, + and we have A = L*(L^T). + Note that THIS function does not perform permutation of + rows to reduce bandwidth. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.01.2014 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsecholeskyskyline(sparsematrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jnz; + ae_int_t jnza; + ae_int_t jnzl; + double v; + double vv; + double a12; + ae_int_t nready; + ae_int_t nadd; + ae_int_t banda; + ae_int_t offsa; + ae_int_t offsl; + ae_bool result; + + + ae_assert(n>=0, "SparseCholeskySkyline: N<0", _state); + ae_assert(sparsegetnrows(a, _state)>=n, "SparseCholeskySkyline: rows(A)=n, "SparseCholeskySkyline: cols(A)=BANDWIDTH(A1), I-th equation is reduced from + * L[I,0]*A1[0] + L[I,1]*A1[1] + ... + L[I,I]*A1[I] = A[I] + * to + * L[I,JNZ]*A1[JNZ] + ... + L[I,I]*A1[I] = A[I] + * where JNZ = max(NReady-BANDWIDTH(A1),I-BANDWIDTH(L[i])) + * (JNZ is an index of the firts column where both A and L become + * nonzero). + * + * NOTE: we rely on details of SparseMatrix internal storage format. + * This is allowed by SparseMatrix specification. + */ + a12 = 0.0; + if( a->didx.ptr.p_int[nready]>0 ) + { + banda = a->didx.ptr.p_int[nready]; + for(i=nready-banda; i<=nready-1; i++) + { + + /* + * Elements of A1[0:I-1] were computed: + * * A1[0:NReady-BandA-1] are zero (sparse) + * * A1[NReady-BandA:I-1] replaced corresponding elements of A + * + * Now it is time to get I-th one. + * + * First, we calculate: + * * JNZA - index of the first column where A become nonzero + * * JNZL - index of the first column where L become nonzero + * * JNZ - index of the first column where both A and L become nonzero + * * OffsA - offset of A[JNZ] in A.Vals + * * OffsL - offset of L[I,JNZ] in A.Vals + * + * Then, we solve SUM(A1[j]*L[I,j],j=JNZ..I-1) + A1[I]*L[I,I] = A[I], + * with A1[JNZ..I-1] already known, and A1[I] unknown. + */ + jnza = nready-banda; + jnzl = i-a->didx.ptr.p_int[i]; + jnz = ae_maxint(jnza, jnzl, _state); + offsa = a->ridx.ptr.p_int[nready]+(jnz-jnza); + offsl = a->ridx.ptr.p_int[i]+(jnz-jnzl); + v = 0.0; + k = i-1-jnz; + for(j=0; j<=k; j++) + { + v = v+a->vals.ptr.p_double[offsa+j]*a->vals.ptr.p_double[offsl+j]; + } + vv = (a->vals.ptr.p_double[offsa+k+1]-v)/a->vals.ptr.p_double[offsl+k+1]; + a->vals.ptr.p_double[offsa+k+1] = vv; + a12 = a12+vv*vv; + } + } + + /* + * Calculate CHOLESKY(B-A1*A1') + */ + offsa = a->ridx.ptr.p_int[nready]+a->didx.ptr.p_int[nready]; + v = a->vals.ptr.p_double[offsa]; + if( ae_fp_less_eq(v,a12) ) + { + result = ae_false; + return result; + } + a->vals.ptr.p_double[offsa] = ae_sqrt(v-a12, _state); + + /* + * Increase size of the updated matrix + */ + inc(&nready, _state); + } + + /* + * transpose if needed + */ + if( isupper ) + { + sparsetransposesks(a, _state); + } + result = ae_true; + return result; +} + + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage, +without rows/cols permutation. + +This function is the most convenient (less parameters to specify) although +the less efficient, version of sparse Cholesky. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +Internally it: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with no permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization + +Following alternatives may result in better performance: +* using SparseCholeskyP(), which selects best pivoting available, which + almost always results in improved sparsity and cache locality +* using SparseCholeskyAnalyze() and SparseCholeskyFactorize() functions + directly, which may improve performance of repetitive factorizations + with same sparsity patterns. + +The latter also allows one to perform LDLT factorization of indefinite +matrix (one with strictly diagonal D, which is known to be stable only +in few special cases, like quasi-definite matrices). + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + Note that THIS function does not perform permutation of + the rows to reduce fill-in. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsecholesky(sparsematrix* a, ae_bool isupper, ae_state *_state) +{ + ae_frame _frame_block; + sparsedecompositionanalysis analysis; + ae_int_t facttype; + ae_int_t permtype; + ae_int_t donotreusemem; + ae_vector priorities; + ae_vector dummyd; + ae_vector dummyp; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&analysis, 0, sizeof(analysis)); + memset(&priorities, 0, sizeof(priorities)); + memset(&dummyd, 0, sizeof(dummyd)); + memset(&dummyp, 0, sizeof(dummyp)); + _sparsedecompositionanalysis_init(&analysis, _state, ae_true); + ae_vector_init(&priorities, 0, DT_INT, _state, ae_true); + ae_vector_init(&dummyd, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyp, 0, DT_INT, _state, ae_true); + + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseCholesky: A is not square", _state); + + /* + * Quick exit + */ + if( sparsegetnrows(a, _state)==0 ) + { + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Choose factorization and permutation: vanilla Cholesky and no permutation, + * Priorities[] array is not set. + */ + facttype = 0; + permtype = -1; + donotreusemem = -1; + + /* + * Easy case - CRS matrix in lower triangle, no conversion or transposition is needed + */ + if( sparseiscrs(a, _state)&&!isupper ) + { + result = spsymmanalyze(a, &priorities, 0.0, 0, facttype, permtype, donotreusemem, &analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + result = spsymmfactorize(&analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + spsymmextract(&analysis.analysis, a, &dummyd, &dummyp, _state); + ae_frame_leave(_state); + return result; + } + + /* + * A bit more complex - we need conversion and/or transposition + */ + if( isupper ) + { + sparsecopytocrsbuf(a, &analysis.wrkat, _state); + sparsecopytransposecrsbuf(&analysis.wrkat, &analysis.wrka, _state); + } + else + { + sparsecopytocrsbuf(a, &analysis.wrka, _state); + } + result = spsymmanalyze(&analysis.wrka, &priorities, 0.0, 0, facttype, permtype, donotreusemem, &analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + result = spsymmfactorize(&analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( isupper ) + { + spsymmextract(&analysis.analysis, &analysis.wrka, &dummyd, &dummyp, _state); + sparsecopytransposecrsbuf(&analysis.wrka, a, _state); + } + else + { + spsymmextract(&analysis.analysis, a, &dummyd, &dummyp, _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage +format, with performance-enhancing permutation of rows/cols. + +Present version is configured to perform supernodal permutation with +a sparsity reducing ordering. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a wrapper around generic sparse decomposition functions +that internally: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with best available permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization. + +NOTE: using SparseCholeskyAnalyze() and SparseCholeskyFactorize() directly + may improve performance of repetitive factorizations with same + sparsity patterns. It also allows one to perform LDLT factorization + of indefinite matrix - a factorization with strictly diagonal D, + which is known to be stable only in few special cases, like quasi- + definite matrices. + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + P - a row/column permutation, a product of P0*P1*...*Pk, k=N-1, + with Pi being permutation of rows/cols I and P[I] + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsecholeskyp(sparsematrix* a, + ae_bool isupper, + /* Integer */ ae_vector* p, + ae_state *_state) +{ + ae_frame _frame_block; + sparsedecompositionanalysis analysis; + ae_vector dummyd; + ae_int_t facttype; + ae_int_t permtype; + ae_int_t donotreusemem; + ae_vector priorities; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&analysis, 0, sizeof(analysis)); + memset(&dummyd, 0, sizeof(dummyd)); + memset(&priorities, 0, sizeof(priorities)); + ae_vector_clear(p); + _sparsedecompositionanalysis_init(&analysis, _state, ae_true); + ae_vector_init(&dummyd, 0, DT_REAL, _state, ae_true); + ae_vector_init(&priorities, 0, DT_INT, _state, ae_true); + + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseCholeskyP: A is not square", _state); + + /* + * Quick exit + */ + if( sparsegetnrows(a, _state)==0 ) + { + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Choose factorization and permutation: vanilla Cholesky and best permutation available. + * Priorities[] array is not set. + */ + facttype = 0; + permtype = 0; + donotreusemem = -1; + + /* + * Easy case - CRS matrix in lower triangle, no conversion or transposition is needed + */ + if( sparseiscrs(a, _state)&&!isupper ) + { + result = spsymmanalyze(a, &priorities, 0.0, 0, facttype, permtype, donotreusemem, &analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + result = spsymmfactorize(&analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + spsymmextract(&analysis.analysis, a, &dummyd, p, _state); + ae_frame_leave(_state); + return result; + } + + /* + * A bit more complex - we need conversion and/or transposition + */ + if( isupper ) + { + sparsecopytocrsbuf(a, &analysis.wrkat, _state); + sparsecopytransposecrsbuf(&analysis.wrkat, &analysis.wrka, _state); + } + else + { + sparsecopytocrsbuf(a, &analysis.wrka, _state); + } + result = spsymmanalyze(&analysis.wrka, &priorities, 0.0, 0, facttype, permtype, donotreusemem, &analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + result = spsymmfactorize(&analysis.analysis, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + if( isupper ) + { + spsymmextract(&analysis.analysis, &analysis.wrka, &dummyd, p, _state); + sparsecopytransposecrsbuf(&analysis.wrka, a, _state); + } + else + { + spsymmextract(&analysis.analysis, a, &dummyd, p, _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Sparse Cholesky/LDLT decomposition: symbolic analysis phase. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function performs preliminary analysis of the Cholesky/LDLT +factorization. It allows to choose different permutation types and to +choose between classic Cholesky and indefinite LDLT factorization (the +latter is computed with strictly diagonal D, i.e. without Bunch-Kauffman +pivoting). + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + A - sparse square matrix in any sparse storage format. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + FactType - factorization type: + * 0 for traditional Cholesky of SPD matrix + * 1 for LDLT decomposition with strictly diagonal D, + which may have non-positive entries. + PermType - permutation type: + *-1 for absence of permutation + * 0 for best fill-in reducing permutation available, + which is 3 in the current version + * 1 for supernodal ordering (improves locality and + performance, does NOT change fill-in factor) + * 2 for original AMD ordering + * 3 for improved AMD (approximate minimum degree) + ordering with better handling of matrices with + dense rows/columns + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + +This function fails if and only if the matrix A is symbolically degenerate +i.e. has diagonal element which is exactly zero. In such case False is +returned, contents of Analysis object is undefined. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsecholeskyanalyze(const sparsematrix* a, + ae_bool isupper, + ae_int_t facttype, + ae_int_t permtype, + sparsedecompositionanalysis* analysis, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector priorities; + ae_int_t reusemem; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&priorities, 0, sizeof(priorities)); + _sparsedecompositionanalysis_clear(analysis); + ae_vector_init(&priorities, 0, DT_INT, _state, ae_true); + + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseCholeskyAnalyze: A is not square", _state); + ae_assert(facttype==0||facttype==1, "SparseCholeskyAnalyze: unexpected FactType", _state); + ae_assert((((((permtype==0||permtype==1)||permtype==2)||permtype==3)||permtype==-1)||permtype==-2)||permtype==-3, "SparseCholeskyAnalyze: unexpected PermType", _state); + + /* + * Prepare wrapper object + */ + analysis->n = sparsegetnrows(a, _state); + analysis->facttype = facttype; + analysis->permtype = permtype; + reusemem = 1; + + /* + * Prepare default priorities for the priority ordering + */ + if( permtype==-3||permtype==3 ) + { + isetallocv(analysis->n, 0, &priorities, _state); + } + + /* + * Analyse + */ + if( !sparseiscrs(a, _state) ) + { + + /* + * The matrix is stored in non-CRS format. First, we have to convert + * it to CRS. Then we may need to transpose it in order to get lower + * triangular one (as supported by SPSymmAnalyze). + */ + sparsecopytocrs(a, &analysis->crsa, _state); + if( isupper ) + { + sparsecopytransposecrsbuf(&analysis->crsa, &analysis->crsat, _state); + result = spsymmanalyze(&analysis->crsat, &priorities, 0.0, 0, facttype, permtype, reusemem, &analysis->analysis, _state); + } + else + { + result = spsymmanalyze(&analysis->crsa, &priorities, 0.0, 0, facttype, permtype, reusemem, &analysis->analysis, _state); + } + } + else + { + + /* + * The matrix is stored in CRS format. However we may need to + * transpose it in order to get lower triangular one (as supported + * by SPSymmAnalyze). + */ + if( isupper ) + { + sparsecopytransposecrsbuf(a, &analysis->crsat, _state); + result = spsymmanalyze(&analysis->crsat, &priorities, 0.0, 0, facttype, permtype, reusemem, &analysis->analysis, _state); + } + else + { + result = spsymmanalyze(a, &priorities, 0.0, 0, facttype, permtype, reusemem, &analysis->analysis, _state); + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Allows to control stability-improving modification strategy for sparse +Cholesky/LDLT decompositions. Modified Cholesky is more robust than its +unmodified counterpart. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +INPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure + ModStrategy - modification type: + * 0 for traditional Cholesky/LDLT (Cholesky fails when + encounters nonpositive pivot, LDLT fails when zero + pivot is encountered, no stability checks for + overflows/underflows) + * 1 for modified Cholesky with additional checks: + * pivots less than ModParam0 are increased; (similar + sign-preserving procedure is applied during LDLT) + * if, at some moment, sum of absolute values of + elements in column J will become greater than + ModParam1, Cholesky/LDLT will treat it as failure + and will stop immediately + P0, P1, P2,P3 - modification parameters #0 #1, #2 and #3. + Params #2 and #3 are ignored in current version. + +OUTPUT PARAMETERS: + Analysis - symbolic analysis of the matrix structure, new strategy + Results will be seen with next SparseCholeskyFactorize() + call. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void sparsecholeskysetmodtype(sparsedecompositionanalysis* analysis, + ae_int_t modstrategy, + double p0, + double p1, + double p2, + double p3, + ae_state *_state) +{ + + + spsymmsetmodificationstrategy(&analysis->analysis, modstrategy, p0, p1, p2, p3, _state); +} + + +/************************************************************************* +Sparse Cholesky decomposition: numerical analysis phase. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +Depending on settings specified during SparseCholeskyAnalyze() call it may +produce classic Cholesky or L*D*LT decomposition (with strictly diagonal +D), without permutation or with performance-enhancing permutation P. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix, and lower triangular output + is requested. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +INPUT PARAMETERS: + Analysis - prior analysis with internally stored matrix which will + be factorized + NeedUpper - whether upper triangular or lower triangular output is + needed + +OUTPUT PARAMETERS: + A - Cholesky decomposition of A stored in lower triangular + CRS format, i.e. A=L*L' (or upper triangular CRS, with + A=U'*U, depending on NeedUpper parameter). + D - array[N], diagonal factor. If no diagonal factor was + required during analysis phase, still returned but + filled with 1's + P - array[N], pivots. Permutation matrix P is a product of + P(0)*P(1)*...*P(N-1), where P(i) is a permutation of + row/col I and P[I] (with P[I]>=I). + If no permutation was requested during analysis phase, + still returned but filled with identity permutation. + +The function returns True when factorization resulted in nondegenerate +matrix. False is returned when factorization fails (Cholesky factorization +of indefinite matrix) or LDLT factorization has exactly zero elements at +the diagonal. In the latter case contents of A, D and P is undefined. + +The analysis object is not changed during the factorization. Subsequent +calls to SparseCholeskyFactorize() will result in same factorization being +performed one more time. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +ae_bool sparsecholeskyfactorize(sparsedecompositionanalysis* analysis, + ae_bool needupper, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + ae_state *_state) +{ + ae_bool result; + + _sparsematrix_clear(a); + ae_vector_clear(d); + ae_vector_clear(p); + + if( needupper ) + { + result = spsymmfactorize(&analysis->analysis, _state); + if( !result ) + { + return result; + } + spsymmextract(&analysis->analysis, &analysis->wrka, d, p, _state); + sparsecopytransposecrsbuf(&analysis->wrka, a, _state); + } + else + { + result = spsymmfactorize(&analysis->analysis, _state); + if( !result ) + { + return result; + } + spsymmextract(&analysis->analysis, a, d, p, _state); + } + return result; +} + + +/************************************************************************* +Sparse Cholesky decomposition: update internally stored matrix with +another one with exactly same sparsity pattern. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function replaces internally stored numerical values with +ones from another sparse matrix (but having exactly same sparsity pattern +as one that was used for initial SparseCholeskyAnalyze() call). + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + Analysis - analysis object + A - sparse square matrix in any sparse storage format. It + MUST have exactly same sparsity pattern as that of the + matrix that was passed to SparseCholeskyAnalyze(). + Any difference (missing elements or additional elements) + may result in unpredictable and undefined behavior - + an algorithm may fail due to memory access violation. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void sparsecholeskyreload(sparsedecompositionanalysis* analysis, + const sparsematrix* a, + ae_bool isupper, + ae_state *_state) +{ + + + ae_assert(sparsegetnrows(a, _state)==sparsegetncols(a, _state), "SparseCholeskyReload: A is not square", _state); + ae_assert(sparsegetnrows(a, _state)==analysis->n, "SparseCholeskyReload: size of A does not match that stored in Analysis", _state); + if( !sparseiscrs(a, _state) ) + { + + /* + * The matrix is stored in non-CRS format. First, we have to convert + * it to CRS. Then we may need to transpose it in order to get lower + * triangular one (as supported by SPSymmAnalyze). + */ + sparsecopytocrs(a, &analysis->crsa, _state); + if( isupper ) + { + sparsecopytransposecrsbuf(&analysis->crsa, &analysis->crsat, _state); + spsymmreload(&analysis->analysis, &analysis->crsat, _state); + } + else + { + spsymmreload(&analysis->analysis, &analysis->crsa, _state); + } + } + else + { + + /* + * The matrix is stored in CRS format. However we may need to + * transpose it in order to get lower triangular one (as supported + * by SPSymmAnalyze). + */ + if( isupper ) + { + sparsecopytransposecrsbuf(a, &analysis->crsat, _state); + spsymmreload(&analysis->analysis, &analysis->crsat, _state); + } + else + { + spsymmreload(&analysis->analysis, a, _state); + } + } +} + + +void rmatrixlup(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmp; + ae_int_t i; + ae_int_t j; + double mx; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_clear(pivots); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * Internal LU decomposition subroutine. + * Never call it directly. + */ + ae_assert(m>0, "RMatrixLUP: incorrect M!", _state); + ae_assert(n>0, "RMatrixLUP: incorrect N!", _state); + + /* + * Scale matrix to avoid overflows, + * decompose it, then scale back. + */ + mx = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_neq(mx,(double)(0)) ) + { + v = (double)1/mx; + for(i=0; i<=m-1; i++) + { + ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + } + ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); + ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); + rmatrixluprec(a, 0, m, n, pivots, &tmp, _state); + if( ae_fp_neq(mx,(double)(0)) ) + { + v = mx; + for(i=0; i<=m-1; i++) + { + ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); + } + } + ae_frame_leave(_state); +} + + +void cmatrixlup(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmp; + ae_int_t i; + ae_int_t j; + double mx; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_clear(pivots); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + + /* + * Internal LU decomposition subroutine. + * Never call it directly. + */ + ae_assert(m>0, "CMatrixLUP: incorrect M!", _state); + ae_assert(n>0, "CMatrixLUP: incorrect N!", _state); + + /* + * Scale matrix to avoid overflows, + * decompose it, then scale back. + */ + mx = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_neq(mx,(double)(0)) ) + { + v = (double)1/mx; + for(i=0; i<=m-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); + } + } + ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); + ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); + cmatrixluprec(a, 0, m, n, pivots, &tmp, _state); + if( ae_fp_neq(mx,(double)(0)) ) + { + v = mx; + for(i=0; i<=m-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,ae_minint(i, n-1, _state)), v); + } + } + ae_frame_leave(_state); +} + + +void rmatrixplu(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmp; + ae_int_t i; + ae_int_t j; + double mx; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_clear(pivots); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * Internal LU decomposition subroutine. + * Never call it directly. + */ + ae_assert(m>0, "RMatrixPLU: incorrect M!", _state); + ae_assert(n>0, "RMatrixPLU: incorrect N!", _state); + ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); + ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); + + /* + * Scale matrix to avoid overflows, + * decompose it, then scale back. + */ + mx = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_neq(mx,(double)(0)) ) + { + v = (double)1/mx; + for(i=0; i<=m-1; i++) + { + ae_v_muld(&a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + } + rmatrixplurec(a, 0, m, n, pivots, &tmp, _state); + if( ae_fp_neq(mx,(double)(0)) ) + { + v = mx; + for(i=0; i<=ae_minint(m, n, _state)-1; i++) + { + ae_v_muld(&a->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); + } + } + ae_frame_leave(_state); +} + + +void cmatrixplu(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tmp; + ae_int_t i; + ae_int_t j; + double mx; + ae_complex v; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_clear(pivots); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + + /* + * Internal LU decomposition subroutine. + * Never call it directly. + */ + ae_assert(m>0, "CMatrixPLU: incorrect M!", _state); + ae_assert(n>0, "CMatrixPLU: incorrect N!", _state); + ae_vector_set_length(&tmp, 2*ae_maxint(m, n, _state), _state); + ae_vector_set_length(pivots, ae_minint(m, n, _state), _state); + + /* + * Scale matrix to avoid overflows, + * decompose it, then scale back. + */ + mx = (double)(0); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_neq(mx,(double)(0)) ) + { + v = ae_complex_from_d((double)1/mx); + for(i=0; i<=m-1; i++) + { + ae_v_cmulc(&a->ptr.pp_complex[i][0], 1, ae_v_len(0,n-1), v); + } + } + cmatrixplurec(a, 0, m, n, pivots, &tmp, _state); + if( ae_fp_neq(mx,(double)(0)) ) + { + v = ae_complex_from_d(mx); + for(i=0; i<=ae_minint(m, n, _state)-1; i++) + { + ae_v_cmulc(&a->ptr.pp_complex[i][i], 1, ae_v_len(i,n-1), v); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Advanced interface for SPDMatrixCholesky, performs no temporary allocations. + +INPUT PARAMETERS: + A - matrix given by upper or lower triangle + Offs - offset of diagonal block to decompose + N - diagonal block size + IsUpper - what half is given + Tmp - temporary array; allocated by function, if its size is too + small; can be reused on subsequent calls. + +OUTPUT PARAMETERS: + A - upper (or lower) triangle contains Cholesky decomposition + +RESULT: + True, on success + False, on failure + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + ae_bool result; + + + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + + /* + * Allocate temporaries + */ + if( tmp->cnt<2*n ) + { + ae_vector_set_length(tmp, 2*n, _state); + } + + /* + * Basecases + */ + if( n<1 ) + { + result = ae_false; + return result; + } + if( n==1 ) + { + if( ae_fp_greater(a->ptr.pp_double[offs][offs],(double)(0)) ) + { + a->ptr.pp_double[offs][offs] = ae_sqrt(a->ptr.pp_double[offs][offs], _state); + result = ae_true; + } + else + { + result = ae_false; + } + return result; + } + if( n<=tsb ) + { + if( spdmatrixcholeskypbl(a, offs, n, isupper, &result, _state) ) + { + return result; + } + } + if( n<=tsa ) + { + result = trfac_spdmatrixcholesky2(a, offs, n, isupper, tmp, _state); + return result; + } + + /* + * Split task into smaller ones + */ + if( n>tsb ) + { + + /* + * Split leading B-sized block from the beginning (block-matrix approach) + */ + n1 = tsb; + n2 = n-n1; + } + else + { + + /* + * Smaller than B-size, perform cache-oblivious split + */ + tiledsplit(n, tsa, &n1, &n2, _state); + } + result = spdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); + if( !result ) + { + return result; + } + if( n2>0 ) + { + if( isupper ) + { + rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 1, a, offs, offs+n1, _state); + rmatrixsyrk(n2, n1, -1.0, a, offs, offs+n1, 1, 1.0, a, offs+n1, offs+n1, isupper, _state); + } + else + { + rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 1, a, offs+n1, offs, _state); + rmatrixsyrk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); + } + result = spdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); + if( !result ) + { + return result; + } + } + return result; +} + + +/************************************************************************* +Recursive computational subroutine for HPDMatrixCholesky + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +static ae_bool trfac_hpdmatrixcholeskyrec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + ae_bool result; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + + /* + * check N + */ + if( n<1 ) + { + result = ae_false; + return result; + } + + /* + * Prepare buffer + */ + if( tmp->cnt<2*n ) + { + ae_vector_set_length(tmp, 2*n, _state); + } + + /* + * Basecases + * + * NOTE: we do not use PBL for basecases because their price is only + * minor part of overall running time for N>256. + */ + if( n==1 ) + { + if( ae_fp_greater(a->ptr.pp_complex[offs][offs].x,(double)(0)) ) + { + a->ptr.pp_complex[offs][offs] = ae_complex_from_d(ae_sqrt(a->ptr.pp_complex[offs][offs].x, _state)); + result = ae_true; + } + else + { + result = ae_false; + } + return result; + } + if( n<=tsa ) + { + result = trfac_hpdmatrixcholesky2(a, offs, n, isupper, tmp, _state); + return result; + } + + /* + * Split task into smaller ones + */ + if( n>tsb ) + { + + /* + * Split leading B-sized block from the beginning (block-matrix approach) + */ + n1 = tsb; + n2 = n-n1; + } + else + { + + /* + * Smaller than B-size, perform cache-oblivious split + */ + tiledsplit(n, tsa, &n1, &n2, _state); + } + result = trfac_hpdmatrixcholeskyrec(a, offs, n1, isupper, tmp, _state); + if( !result ) + { + return result; + } + if( n2>0 ) + { + if( isupper ) + { + cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 2, a, offs, offs+n1, _state); + cmatrixherk(n2, n1, -1.0, a, offs, offs+n1, 2, 1.0, a, offs+n1, offs+n1, isupper, _state); + } + else + { + cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 2, a, offs+n1, offs, _state); + cmatrixherk(n2, n1, -1.0, a, offs+n1, offs, 0, 1.0, a, offs+n1, offs+n1, isupper, _state); + } + result = trfac_hpdmatrixcholeskyrec(a, offs+n1, n2, isupper, tmp, _state); + if( !result ) + { + return result; + } + } + return result; +} + + +/************************************************************************* +Level-2 Hermitian Cholesky subroutine. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static ae_bool trfac_hpdmatrixcholesky2(/* Complex */ ae_matrix* aaa, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double ajj; + ae_complex v; + double r; + ae_bool result; + + + result = ae_true; + if( n<0 ) + { + result = ae_false; + return result; + } + + /* + * Quick return if possible + */ + if( n==0 ) + { + return result; + } + if( isupper ) + { + + /* + * Compute the Cholesky factorization A = U'*U. + */ + for(j=0; j<=n-1; j++) + { + + /* + * Compute U(J,J) and test for non-positive-definiteness. + */ + v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "N", ae_v_len(offs,offs+j-1)); + ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; + if( ae_fp_less_eq(ajj,(double)(0)) ) + { + aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); + result = ae_false; + return result; + } + ajj = ae_sqrt(ajj, _state); + aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); + + /* + * Compute elements J+1:N-1 of row J. + */ + if( j0 ) + { + ae_v_cmoveneg(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs][offs+j], aaa->stride, "Conj", ae_v_len(0,j-1)); + cmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); + ae_v_cadd(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, &tmp->ptr.p_complex[n], 1, "N", ae_v_len(offs+j+1,offs+n-1)); + } + r = (double)1/ajj; + ae_v_cmuld(&aaa->ptr.pp_complex[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); + } + } + } + else + { + + /* + * Compute the Cholesky factorization A = L*L'. + */ + for(j=0; j<=n-1; j++) + { + + /* + * Compute L(J+1,J+1) and test for non-positive-definiteness. + */ + v = ae_v_cdotproduct(&aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", &aaa->ptr.pp_complex[offs+j][offs], 1, "N", ae_v_len(offs,offs+j-1)); + ajj = ae_c_sub(aaa->ptr.pp_complex[offs+j][offs+j],v).x; + if( ae_fp_less_eq(ajj,(double)(0)) ) + { + aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); + result = ae_false; + return result; + } + ajj = ae_sqrt(ajj, _state); + aaa->ptr.pp_complex[offs+j][offs+j] = ae_complex_from_d(ajj); + + /* + * Compute elements J+1:N of column J. + */ + if( j0 ) + { + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &aaa->ptr.pp_complex[offs+j][offs], 1, "Conj", ae_v_len(0,j-1)); + cmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); + for(i=0; i<=n-j-2; i++) + { + aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_mul_d(ae_c_sub(aaa->ptr.pp_complex[offs+j+1+i][offs+j],tmp->ptr.p_complex[n+i]),r); + } + } + else + { + for(i=0; i<=n-j-2; i++) + { + aaa->ptr.pp_complex[offs+j+1+i][offs+j] = ae_c_mul_d(aaa->ptr.pp_complex[offs+j+1+i][offs+j],r); + } + } + } + } + } + return result; +} + + +/************************************************************************* +Level-2 Cholesky subroutine + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static ae_bool trfac_spdmatrixcholesky2(/* Real */ ae_matrix* aaa, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double ajj; + double v; + double r; + ae_bool result; + + + result = ae_true; + if( n<0 ) + { + result = ae_false; + return result; + } + + /* + * Quick return if possible + */ + if( n==0 ) + { + return result; + } + if( isupper ) + { + + /* + * Compute the Cholesky factorization A = U'*U. + */ + for(j=0; j<=n-1; j++) + { + + /* + * Compute U(J,J) and test for non-positive-definiteness. + */ + v = ae_v_dotproduct(&aaa->ptr.pp_double[offs][offs+j], aaa->stride, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(offs,offs+j-1)); + ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; + if( ae_fp_less_eq(ajj,(double)(0)) ) + { + aaa->ptr.pp_double[offs+j][offs+j] = ajj; + result = ae_false; + return result; + } + ajj = ae_sqrt(ajj, _state); + aaa->ptr.pp_double[offs+j][offs+j] = ajj; + + /* + * Compute elements J+1:N-1 of row J. + */ + if( j0 ) + { + ae_v_moveneg(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs][offs+j], aaa->stride, ae_v_len(0,j-1)); + rmatrixmv(n-j-1, j, aaa, offs, offs+j+1, 1, tmp, 0, tmp, n, _state); + ae_v_add(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, &tmp->ptr.p_double[n], 1, ae_v_len(offs+j+1,offs+n-1)); + } + r = (double)1/ajj; + ae_v_muld(&aaa->ptr.pp_double[offs+j][offs+j+1], 1, ae_v_len(offs+j+1,offs+n-1), r); + } + } + } + else + { + + /* + * Compute the Cholesky factorization A = L*L'. + */ + for(j=0; j<=n-1; j++) + { + + /* + * Compute L(J+1,J+1) and test for non-positive-definiteness. + */ + v = ae_v_dotproduct(&aaa->ptr.pp_double[offs+j][offs], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(offs,offs+j-1)); + ajj = aaa->ptr.pp_double[offs+j][offs+j]-v; + if( ae_fp_less_eq(ajj,(double)(0)) ) + { + aaa->ptr.pp_double[offs+j][offs+j] = ajj; + result = ae_false; + return result; + } + ajj = ae_sqrt(ajj, _state); + aaa->ptr.pp_double[offs+j][offs+j] = ajj; + + /* + * Compute elements J+1:N of column J. + */ + if( j0 ) + { + ae_v_move(&tmp->ptr.p_double[0], 1, &aaa->ptr.pp_double[offs+j][offs], 1, ae_v_len(0,j-1)); + rmatrixmv(n-j-1, j, aaa, offs+j+1, offs, 0, tmp, 0, tmp, n, _state); + for(i=0; i<=n-j-2; i++) + { + aaa->ptr.pp_double[offs+j+1+i][offs+j] = (aaa->ptr.pp_double[offs+j+1+i][offs+j]-tmp->ptr.p_double[n+i])*r; + } + } + else + { + for(i=0; i<=n-j-2; i++) + { + aaa->ptr.pp_double[offs+j+1+i][offs+j] = aaa->ptr.pp_double[offs+j+1+i][offs+j]*r; + } + } + } + } + } + return result; +} + + +void _sparsedecompositionanalysis_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sparsedecompositionanalysis *p = (sparsedecompositionanalysis*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + _sparsematrix_init(&p->wrka, _state, make_automatic); + _sparsematrix_init(&p->wrkat, _state, make_automatic); + _sparsematrix_init(&p->crsa, _state, make_automatic); + _sparsematrix_init(&p->crsat, _state, make_automatic); +} + + +void _sparsedecompositionanalysis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sparsedecompositionanalysis *dst = (sparsedecompositionanalysis*)_dst; + const sparsedecompositionanalysis *src = (const sparsedecompositionanalysis*)_src; + dst->n = src->n; + dst->facttype = src->facttype; + dst->permtype = src->permtype; + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + _sparsematrix_init_copy(&dst->wrka, &src->wrka, _state, make_automatic); + _sparsematrix_init_copy(&dst->wrkat, &src->wrkat, _state, make_automatic); + _sparsematrix_init_copy(&dst->crsa, &src->crsa, _state, make_automatic); + _sparsematrix_init_copy(&dst->crsat, &src->crsat, _state, make_automatic); +} + + +void _sparsedecompositionanalysis_clear(void* _p) +{ + sparsedecompositionanalysis *p = (sparsedecompositionanalysis*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_clear(&p->analysis); + _sparsematrix_clear(&p->wrka); + _sparsematrix_clear(&p->wrkat); + _sparsematrix_clear(&p->crsa); + _sparsematrix_clear(&p->crsat); +} + + +void _sparsedecompositionanalysis_destroy(void* _p) +{ + sparsedecompositionanalysis *p = (sparsedecompositionanalysis*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_destroy(&p->analysis); + _sparsematrix_destroy(&p->wrka); + _sparsematrix_destroy(&p->wrkat); + _sparsematrix_destroy(&p->crsa); + _sparsematrix_destroy(&p->crsat); +} + + +#endif +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Singular value decomposition of a bidiagonal matrix (extended algorithm) + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (Intel MKL support on x64, other + ! libraries on other platforms) + ! + ! Vendor libraries give approximately constant with respect to the + ! number of worker threads) acceleration factor which depends on the CPU + ! being used, problem size and "baseline" ALGLIB edition which is + ! used for comparison. + ! + ! Generally, commercial ALGLIB is several times faster than open-source + ! generic C edition, and many times faster than open-source C# edition. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm performs the singular value decomposition of a bidiagonal +matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - +orthogonal matrices, S - diagonal matrix with non-negative elements on the +main diagonal, in descending order. + +The algorithm finds singular values. In addition, the algorithm can +calculate matrices Q and P (more precisely, not the matrices, but their +product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, +matrices U and VT can be of any type, including identity. Furthermore, the +algorithm can calculate Q'*C (this product is calculated more effectively +than U*Q, because this calculation operates with rows instead of matrix +columns). + +The feature of the algorithm is its ability to find all singular values +including those which are arbitrarily close to 0 with relative accuracy +close to machine precision. If the parameter IsFractionalAccuracyRequired +is set to True, all singular values will have high relative accuracy close +to machine precision. If the parameter is set to False, only the biggest +singular value will have relative accuracy close to machine precision. +The absolute error of other singular values is equal to the absolute error +of the biggest singular value. + +Input parameters: + D - main diagonal of matrix B. + Array whose index ranges within [0..N-1]. + E - superdiagonal (or subdiagonal) of matrix B. + Array whose index ranges within [0..N-2]. + N - size of matrix B. + IsUpper - True, if the matrix is upper bidiagonal. + IsFractionalAccuracyRequired - + THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 + SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. + U - matrix to be multiplied by Q. + Array whose indexes range within [0..NRU-1, 0..N-1]. + The matrix can be bigger, in that case only the submatrix + [0..NRU-1, 0..N-1] will be multiplied by Q. + NRU - number of rows in matrix U. + C - matrix to be multiplied by Q'. + Array whose indexes range within [0..N-1, 0..NCC-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCC-1] will be multiplied by Q'. + NCC - number of columns in matrix C. + VT - matrix to be multiplied by P^T. + Array whose indexes range within [0..N-1, 0..NCVT-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCVT-1] will be multiplied by P^T. + NCVT - number of columns in matrix VT. + +Output parameters: + D - singular values of matrix B in descending order. + U - if NRU>0, contains matrix U*Q. + VT - if NCVT>0, contains matrix (P^T)*VT. + C - if NCC>0, contains matrix Q'*C. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +NOTE: multiplication U*Q is performed by means of transposition to internal + buffer, multiplication and backward transposition. It helps to avoid + costly columnwise operations and speed-up algorithm. + +Additional information: + The type of convergence is controlled by the internal parameter TOL. + If the parameter is greater than 0, the singular values will have + relative accuracy TOL. If TOL<0, the singular values will have + absolute accuracy ABS(TOL)*norm(B). + By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, + where Epsilon is the machine precision. It is not recommended to use + TOL less than 10*Epsilon since this will considerably slow down the + algorithm and may not lead to error decreasing. + +History: + * 31 March, 2007. + changed MAXITR from 6 to 12. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1999. +*************************************************************************/ +ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_int_t i; + ae_vector en; + ae_vector d1; + ae_vector e1; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + memset(&en, 0, sizeof(en)); + memset(&d1, 0, sizeof(d1)); + memset(&e1, 0, sizeof(e1)); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_init(&en, 0, DT_REAL, _state, ae_true); + ae_vector_init(&d1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e1, 0, DT_REAL, _state, ae_true); + + result = ae_false; + + /* + * Try to use PBL + */ + ae_vector_set_length(&en, n, _state); + for(i=0; i<=n-2; i++) + { + en.ptr.p_double[i] = e.ptr.p_double[i]; + } + en.ptr.p_double[n-1] = 0.0; + if( rmatrixbdsvdpbl(d, &en, n, isupper, u, nru, c, ncc, vt, ncvt, &result, _state) ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Use ALGLIB code + */ + ae_vector_set_length(&d1, n+1, _state); + ae_v_move(&d1.ptr.p_double[1], 1, &d->ptr.p_double[0], 1, ae_v_len(1,n)); + if( n>1 ) + { + ae_vector_set_length(&e1, n-1+1, _state); + ae_v_move(&e1.ptr.p_double[1], 1, &e.ptr.p_double[0], 1, ae_v_len(1,n-1)); + } + result = bdsvd_bidiagonalsvddecompositioninternal(&d1, &e1, n, isupper, isfractionalaccuracyrequired, u, 0, nru, c, 0, ncc, vt, 0, ncvt, _state); + ae_v_move(&d->ptr.p_double[0], 1, &d1.ptr.p_double[1], 1, ae_v_len(0,n-1)); + ae_frame_leave(_state); + return result; +} + + +ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + ae_vector_init_copy(&e, _e, _state, ae_true); + + result = bdsvd_bidiagonalsvddecompositioninternal(d, &e, n, isupper, isfractionalaccuracyrequired, u, 1, nru, c, 1, ncc, vt, 1, ncvt, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Internal working subroutine for bidiagonal decomposition +*************************************************************************/ +static ae_bool bdsvd_bidiagonalsvddecompositioninternal(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* uu, + ae_int_t ustart, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t cstart, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t vstart, + ae_int_t ncvt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector e; + ae_int_t i; + ae_int_t idir; + ae_int_t isub; + ae_int_t iter; + ae_int_t j; + ae_int_t ll; + ae_int_t lll; + ae_int_t m; + ae_int_t maxit; + ae_int_t oldll; + ae_int_t oldm; + double abse; + double abss; + double cosl; + double cosr; + double cs; + double eps; + double f; + double g; + double h; + double mu; + double oldcs; + double oldsn; + double r; + double shift; + double sigmn; + double sigmx; + double sinl; + double sinr; + double sll; + double smax; + double smin; + double sminl; + double sminoa; + double sn; + double thresh; + double tol; + double tolmul; + double unfl; + ae_vector work0; + ae_vector work1; + ae_vector work2; + ae_vector work3; + ae_int_t maxitr; + ae_bool matrixsplitflag; + ae_bool iterflag; + ae_vector utemp; + ae_vector vttemp; + ae_vector ctemp; + ae_vector etemp; + ae_matrix ut; + ae_bool fwddir; + double tmp; + ae_int_t mm1; + ae_int_t mm0; + ae_bool bchangedir; + ae_int_t uend; + ae_int_t cend; + ae_int_t vend; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&e, 0, sizeof(e)); + memset(&work0, 0, sizeof(work0)); + memset(&work1, 0, sizeof(work1)); + memset(&work2, 0, sizeof(work2)); + memset(&work3, 0, sizeof(work3)); + memset(&utemp, 0, sizeof(utemp)); + memset(&vttemp, 0, sizeof(vttemp)); + memset(&ctemp, 0, sizeof(ctemp)); + memset(&etemp, 0, sizeof(etemp)); + memset(&ut, 0, sizeof(ut)); + ae_vector_init_copy(&e, _e, _state, ae_true); + ae_vector_init(&work0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work3, 0, DT_REAL, _state, ae_true); + ae_vector_init(&utemp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vttemp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ctemp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&etemp, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ut, 0, 0, DT_REAL, _state, ae_true); + + result = ae_true; + if( n==0 ) + { + ae_frame_leave(_state); + return result; + } + if( n==1 ) + { + if( ae_fp_less(d->ptr.p_double[1],(double)(0)) ) + { + d->ptr.p_double[1] = -d->ptr.p_double[1]; + if( ncvt>0 ) + { + ae_v_muld(&vt->ptr.pp_double[vstart][vstart], 1, ae_v_len(vstart,vstart+ncvt-1), -1.0); + } + } + ae_frame_leave(_state); + return result; + } + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + ll = 0; + oldsn = (double)(0); + + /* + * init + */ + ae_vector_set_length(&work0, n-1+1, _state); + ae_vector_set_length(&work1, n-1+1, _state); + ae_vector_set_length(&work2, n-1+1, _state); + ae_vector_set_length(&work3, n-1+1, _state); + uend = ustart+ae_maxint(nru-1, 0, _state); + vend = vstart+ae_maxint(ncvt-1, 0, _state); + cend = cstart+ae_maxint(ncc-1, 0, _state); + ae_vector_set_length(&utemp, uend+1, _state); + ae_vector_set_length(&vttemp, vend+1, _state); + ae_vector_set_length(&ctemp, cend+1, _state); + maxitr = 12; + fwddir = ae_true; + if( nru>0 ) + { + ae_matrix_set_length(&ut, ustart+n, ustart+nru, _state); + rmatrixtranspose(nru, n, uu, ustart, ustart, &ut, ustart, ustart, _state); + } + + /* + * resize E from N-1 to N + */ + ae_vector_set_length(&etemp, n+1, _state); + for(i=1; i<=n-1; i++) + { + etemp.ptr.p_double[i] = e.ptr.p_double[i]; + } + ae_vector_set_length(&e, n+1, _state); + for(i=1; i<=n-1; i++) + { + e.ptr.p_double[i] = etemp.ptr.p_double[i]; + } + e.ptr.p_double[n] = (double)(0); + idir = 0; + + /* + * Get machine constants + */ + eps = ae_machineepsilon; + unfl = ae_minrealnumber; + + /* + * If matrix lower bidiagonal, rotate to be upper bidiagonal + * by applying Givens rotations on the left + */ + if( !isupper ) + { + for(i=1; i<=n-1; i++) + { + generaterotation(d->ptr.p_double[i], e.ptr.p_double[i], &cs, &sn, &r, _state); + d->ptr.p_double[i] = r; + e.ptr.p_double[i] = sn*d->ptr.p_double[i+1]; + d->ptr.p_double[i+1] = cs*d->ptr.p_double[i+1]; + work0.ptr.p_double[i] = cs; + work1.ptr.p_double[i] = sn; + } + + /* + * Update singular vectors if desired + */ + if( nru>0 ) + { + applyrotationsfromtheleft(fwddir, 1+ustart-1, n+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); + } + if( ncc>0 ) + { + applyrotationsfromtheleft(fwddir, 1+cstart-1, n+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); + } + } + + /* + * Compute singular values to relative accuracy TOL + * (By setting TOL to be negative, algorithm will compute + * singular values to absolute accuracy ABS(TOL)*norm(input matrix)) + */ + tolmul = ae_maxreal((double)(10), ae_minreal((double)(100), ae_pow(eps, -0.125, _state), _state), _state); + tol = tolmul*eps; + + /* + * Compute approximate maximum, minimum singular values + */ + smax = (double)(0); + for(i=1; i<=n; i++) + { + smax = ae_maxreal(smax, ae_fabs(d->ptr.p_double[i], _state), _state); + } + for(i=1; i<=n-1; i++) + { + smax = ae_maxreal(smax, ae_fabs(e.ptr.p_double[i], _state), _state); + } + sminl = (double)(0); + if( ae_fp_greater_eq(tol,(double)(0)) ) + { + + /* + * Relative accuracy desired + */ + sminoa = ae_fabs(d->ptr.p_double[1], _state); + if( ae_fp_neq(sminoa,(double)(0)) ) + { + mu = sminoa; + for(i=2; i<=n; i++) + { + mu = ae_fabs(d->ptr.p_double[i], _state)*(mu/(mu+ae_fabs(e.ptr.p_double[i-1], _state))); + sminoa = ae_minreal(sminoa, mu, _state); + if( ae_fp_eq(sminoa,(double)(0)) ) + { + break; + } + } + } + sminoa = sminoa/ae_sqrt((double)(n), _state); + thresh = ae_maxreal(tol*sminoa, (double)(maxitr*n*n)*unfl, _state); + } + else + { + + /* + * Absolute accuracy desired + */ + thresh = ae_maxreal(ae_fabs(tol, _state)*smax, (double)(maxitr*n*n)*unfl, _state); + } + + /* + * Prepare for main iteration loop for the singular values + * (MAXIT is the maximum number of passes through the inner + * loop permitted before nonconvergence signalled.) + */ + maxit = maxitr*n*n; + iter = 0; + oldll = -1; + oldm = -1; + + /* + * M points to last element of unconverged part of matrix + */ + m = n; + + /* + * Begin main iteration loop + */ + for(;;) + { + + /* + * Check for convergence or exceeding iteration count + */ + if( m<=1 ) + { + break; + } + if( iter>maxit ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Find diagonal block of matrix to work on + */ + if( ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[m], _state),thresh) ) + { + d->ptr.p_double[m] = (double)(0); + } + smax = ae_fabs(d->ptr.p_double[m], _state); + smin = smax; + matrixsplitflag = ae_false; + for(lll=1; lll<=m-1; lll++) + { + ll = m-lll; + abss = ae_fabs(d->ptr.p_double[ll], _state); + abse = ae_fabs(e.ptr.p_double[ll], _state); + if( ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(abss,thresh) ) + { + d->ptr.p_double[ll] = (double)(0); + } + if( ae_fp_less_eq(abse,thresh) ) + { + matrixsplitflag = ae_true; + break; + } + smin = ae_minreal(smin, abss, _state); + smax = ae_maxreal(smax, ae_maxreal(abss, abse, _state), _state); + } + if( !matrixsplitflag ) + { + ll = 0; + } + else + { + + /* + * Matrix splits since E(LL) = 0 + */ + e.ptr.p_double[ll] = (double)(0); + if( ll==m-1 ) + { + + /* + * Convergence of bottom singular value, return to top of loop + */ + m = m-1; + continue; + } + } + ll = ll+1; + + /* + * E(LL) through E(M-1) are nonzero, E(LL-1) is zero + */ + if( ll==m-1 ) + { + + /* + * 2 by 2 block, handle separately + */ + bdsvd_svdv2x2(d->ptr.p_double[m-1], e.ptr.p_double[m-1], d->ptr.p_double[m], &sigmn, &sigmx, &sinr, &cosr, &sinl, &cosl, _state); + d->ptr.p_double[m-1] = sigmx; + e.ptr.p_double[m-1] = (double)(0); + d->ptr.p_double[m] = sigmn; + + /* + * Compute singular vectors, if desired + */ + if( ncvt>0 ) + { + mm0 = m+(vstart-1); + mm1 = m-1+(vstart-1); + ae_v_moved(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), cosr); + ae_v_addd(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), sinr); + ae_v_muld(&vt->ptr.pp_double[mm0][vstart], 1, ae_v_len(vstart,vend), cosr); + ae_v_subd(&vt->ptr.pp_double[mm0][vstart], 1, &vt->ptr.pp_double[mm1][vstart], 1, ae_v_len(vstart,vend), sinr); + ae_v_move(&vt->ptr.pp_double[mm1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); + } + if( nru>0 ) + { + mm0 = m+ustart-1; + mm1 = m-1+ustart-1; + ae_v_moved(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[mm1][ustart], 1, ae_v_len(ustart,uend), cosl); + ae_v_addd(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[mm0][ustart], 1, ae_v_len(ustart,uend), sinl); + ae_v_muld(&ut.ptr.pp_double[mm0][ustart], 1, ae_v_len(ustart,uend), cosl); + ae_v_subd(&ut.ptr.pp_double[mm0][ustart], 1, &ut.ptr.pp_double[mm1][ustart], 1, ae_v_len(ustart,uend), sinl); + ae_v_move(&ut.ptr.pp_double[mm1][ustart], 1, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); + } + if( ncc>0 ) + { + mm0 = m+cstart-1; + mm1 = m-1+cstart-1; + ae_v_moved(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), cosl); + ae_v_addd(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), sinl); + ae_v_muld(&c->ptr.pp_double[mm0][cstart], 1, ae_v_len(cstart,cend), cosl); + ae_v_subd(&c->ptr.pp_double[mm0][cstart], 1, &c->ptr.pp_double[mm1][cstart], 1, ae_v_len(cstart,cend), sinl); + ae_v_move(&c->ptr.pp_double[mm1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); + } + m = m-2; + continue; + } + + /* + * If working on new submatrix, choose shift direction + * (from larger end diagonal element towards smaller) + * + * Previously was + * "if (LL>OLDM) or (M + * Very strange that LAPACK still contains it. + */ + bchangedir = ae_false; + if( idir==1&&ae_fp_less(ae_fabs(d->ptr.p_double[ll], _state),1.0E-3*ae_fabs(d->ptr.p_double[m], _state)) ) + { + bchangedir = ae_true; + } + if( idir==2&&ae_fp_less(ae_fabs(d->ptr.p_double[m], _state),1.0E-3*ae_fabs(d->ptr.p_double[ll], _state)) ) + { + bchangedir = ae_true; + } + if( (ll!=oldll||m!=oldm)||bchangedir ) + { + if( ae_fp_greater_eq(ae_fabs(d->ptr.p_double[ll], _state),ae_fabs(d->ptr.p_double[m], _state)) ) + { + + /* + * Chase bulge from top (big end) to bottom (small end) + */ + idir = 1; + } + else + { + + /* + * Chase bulge from bottom (big end) to top (small end) + */ + idir = 2; + } + } + + /* + * Apply convergence tests + */ + if( idir==1 ) + { + + /* + * Run convergence test in forward direction + * First apply standard test to bottom of matrix + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[m-1], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[m], _state))||(ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(e.ptr.p_double[m-1], _state),thresh)) ) + { + e.ptr.p_double[m-1] = (double)(0); + continue; + } + if( ae_fp_greater_eq(tol,(double)(0)) ) + { + + /* + * If relative accuracy desired, + * apply convergence criterion forward + */ + mu = ae_fabs(d->ptr.p_double[ll], _state); + sminl = mu; + iterflag = ae_false; + for(lll=ll; lll<=m-1; lll++) + { + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[lll], _state),tol*mu) ) + { + e.ptr.p_double[lll] = (double)(0); + iterflag = ae_true; + break; + } + mu = ae_fabs(d->ptr.p_double[lll+1], _state)*(mu/(mu+ae_fabs(e.ptr.p_double[lll], _state))); + sminl = ae_minreal(sminl, mu, _state); + } + if( iterflag ) + { + continue; + } + } + } + else + { + + /* + * Run convergence test in backward direction + * First apply standard test to top of matrix + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[ll], _state),ae_fabs(tol, _state)*ae_fabs(d->ptr.p_double[ll], _state))||(ae_fp_less(tol,(double)(0))&&ae_fp_less_eq(ae_fabs(e.ptr.p_double[ll], _state),thresh)) ) + { + e.ptr.p_double[ll] = (double)(0); + continue; + } + if( ae_fp_greater_eq(tol,(double)(0)) ) + { + + /* + * If relative accuracy desired, + * apply convergence criterion backward + */ + mu = ae_fabs(d->ptr.p_double[m], _state); + sminl = mu; + iterflag = ae_false; + for(lll=m-1; lll>=ll; lll--) + { + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[lll], _state),tol*mu) ) + { + e.ptr.p_double[lll] = (double)(0); + iterflag = ae_true; + break; + } + mu = ae_fabs(d->ptr.p_double[lll], _state)*(mu/(mu+ae_fabs(e.ptr.p_double[lll], _state))); + sminl = ae_minreal(sminl, mu, _state); + } + if( iterflag ) + { + continue; + } + } + } + oldll = ll; + oldm = m; + + /* + * Compute shift. First, test if shifting would ruin relative + * accuracy, and if so set the shift to zero. + */ + if( ae_fp_greater_eq(tol,(double)(0))&&ae_fp_less_eq((double)n*tol*(sminl/smax),ae_maxreal(eps, 0.01*tol, _state)) ) + { + + /* + * Use a zero shift to avoid loss of relative accuracy + */ + shift = (double)(0); + } + else + { + + /* + * Compute the shift from 2-by-2 block at end of matrix + */ + if( idir==1 ) + { + sll = ae_fabs(d->ptr.p_double[ll], _state); + bdsvd_svd2x2(d->ptr.p_double[m-1], e.ptr.p_double[m-1], d->ptr.p_double[m], &shift, &r, _state); + } + else + { + sll = ae_fabs(d->ptr.p_double[m], _state); + bdsvd_svd2x2(d->ptr.p_double[ll], e.ptr.p_double[ll], d->ptr.p_double[ll+1], &shift, &r, _state); + } + + /* + * Test if shift negligible, and if so set to zero + */ + if( ae_fp_greater(sll,(double)(0)) ) + { + if( ae_fp_less(ae_sqr(shift/sll, _state),eps) ) + { + shift = (double)(0); + } + } + } + + /* + * Increment iteration count + */ + iter = iter+m-ll; + + /* + * If SHIFT = 0, do simplified QR iteration + */ + if( ae_fp_eq(shift,(double)(0)) ) + { + if( idir==1 ) + { + + /* + * Chase bulge from top to bottom + * Save cosines and sines for later singular vector updates + */ + cs = (double)(1); + oldcs = (double)(1); + for(i=ll; i<=m-1; i++) + { + generaterotation(d->ptr.p_double[i]*cs, e.ptr.p_double[i], &cs, &sn, &r, _state); + if( i>ll ) + { + e.ptr.p_double[i-1] = oldsn*r; + } + generaterotation(oldcs*r, d->ptr.p_double[i+1]*sn, &oldcs, &oldsn, &tmp, _state); + d->ptr.p_double[i] = tmp; + work0.ptr.p_double[i-ll+1] = cs; + work1.ptr.p_double[i-ll+1] = sn; + work2.ptr.p_double[i-ll+1] = oldcs; + work3.ptr.p_double[i-ll+1] = oldsn; + } + h = d->ptr.p_double[m]*cs; + d->ptr.p_double[m] = h*oldcs; + e.ptr.p_double[m-1] = h*oldsn; + + /* + * Update singular vectors + */ + if( ncvt>0 ) + { + applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); + } + if( nru>0 ) + { + applyrotationsfromtheleft(fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work2, &work3, &ut, &utemp, _state); + } + if( ncc>0 ) + { + applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); + } + + /* + * Test convergence + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[m-1], _state),thresh) ) + { + e.ptr.p_double[m-1] = (double)(0); + } + } + else + { + + /* + * Chase bulge from bottom to top + * Save cosines and sines for later singular vector updates + */ + cs = (double)(1); + oldcs = (double)(1); + for(i=m; i>=ll+1; i--) + { + generaterotation(d->ptr.p_double[i]*cs, e.ptr.p_double[i-1], &cs, &sn, &r, _state); + if( iptr.p_double[i-1]*sn, &oldcs, &oldsn, &tmp, _state); + d->ptr.p_double[i] = tmp; + work0.ptr.p_double[i-ll] = cs; + work1.ptr.p_double[i-ll] = -sn; + work2.ptr.p_double[i-ll] = oldcs; + work3.ptr.p_double[i-ll] = -oldsn; + } + h = d->ptr.p_double[ll]*cs; + d->ptr.p_double[ll] = h*oldcs; + e.ptr.p_double[ll] = h*oldsn; + + /* + * Update singular vectors + */ + if( ncvt>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); + } + if( nru>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); + } + if( ncc>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); + } + + /* + * Test convergence + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[ll], _state),thresh) ) + { + e.ptr.p_double[ll] = (double)(0); + } + } + } + else + { + + /* + * Use nonzero shift + */ + if( idir==1 ) + { + + /* + * Chase bulge from top to bottom + * Save cosines and sines for later singular vector updates + */ + f = (ae_fabs(d->ptr.p_double[ll], _state)-shift)*(bdsvd_extsignbdsqr((double)(1), d->ptr.p_double[ll], _state)+shift/d->ptr.p_double[ll]); + g = e.ptr.p_double[ll]; + for(i=ll; i<=m-1; i++) + { + generaterotation(f, g, &cosr, &sinr, &r, _state); + if( i>ll ) + { + e.ptr.p_double[i-1] = r; + } + f = cosr*d->ptr.p_double[i]+sinr*e.ptr.p_double[i]; + e.ptr.p_double[i] = cosr*e.ptr.p_double[i]-sinr*d->ptr.p_double[i]; + g = sinr*d->ptr.p_double[i+1]; + d->ptr.p_double[i+1] = cosr*d->ptr.p_double[i+1]; + generaterotation(f, g, &cosl, &sinl, &r, _state); + d->ptr.p_double[i] = r; + f = cosl*e.ptr.p_double[i]+sinl*d->ptr.p_double[i+1]; + d->ptr.p_double[i+1] = cosl*d->ptr.p_double[i+1]-sinl*e.ptr.p_double[i]; + if( i0 ) + { + applyrotationsfromtheleft(fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work0, &work1, vt, &vttemp, _state); + } + if( nru>0 ) + { + applyrotationsfromtheleft(fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work2, &work3, &ut, &utemp, _state); + } + if( ncc>0 ) + { + applyrotationsfromtheleft(fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work2, &work3, c, &ctemp, _state); + } + + /* + * Test convergence + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[m-1], _state),thresh) ) + { + e.ptr.p_double[m-1] = (double)(0); + } + } + else + { + + /* + * Chase bulge from bottom to top + * Save cosines and sines for later singular vector updates + */ + f = (ae_fabs(d->ptr.p_double[m], _state)-shift)*(bdsvd_extsignbdsqr((double)(1), d->ptr.p_double[m], _state)+shift/d->ptr.p_double[m]); + g = e.ptr.p_double[m-1]; + for(i=m; i>=ll+1; i--) + { + generaterotation(f, g, &cosr, &sinr, &r, _state); + if( iptr.p_double[i]+sinr*e.ptr.p_double[i-1]; + e.ptr.p_double[i-1] = cosr*e.ptr.p_double[i-1]-sinr*d->ptr.p_double[i]; + g = sinr*d->ptr.p_double[i-1]; + d->ptr.p_double[i-1] = cosr*d->ptr.p_double[i-1]; + generaterotation(f, g, &cosl, &sinl, &r, _state); + d->ptr.p_double[i] = r; + f = cosl*e.ptr.p_double[i-1]+sinl*d->ptr.p_double[i-1]; + d->ptr.p_double[i-1] = cosl*d->ptr.p_double[i-1]-sinl*e.ptr.p_double[i-1]; + if( i>ll+1 ) + { + g = sinl*e.ptr.p_double[i-2]; + e.ptr.p_double[i-2] = cosl*e.ptr.p_double[i-2]; + } + work0.ptr.p_double[i-ll] = cosr; + work1.ptr.p_double[i-ll] = -sinr; + work2.ptr.p_double[i-ll] = cosl; + work3.ptr.p_double[i-ll] = -sinl; + } + e.ptr.p_double[ll] = f; + + /* + * Test convergence + */ + if( ae_fp_less_eq(ae_fabs(e.ptr.p_double[ll], _state),thresh) ) + { + e.ptr.p_double[ll] = (double)(0); + } + + /* + * Update singular vectors if desired + */ + if( ncvt>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+vstart-1, m+vstart-1, vstart, vend, &work2, &work3, vt, &vttemp, _state); + } + if( nru>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+ustart-1, m+ustart-1, ustart, uend, &work0, &work1, &ut, &utemp, _state); + } + if( ncc>0 ) + { + applyrotationsfromtheleft(!fwddir, ll+cstart-1, m+cstart-1, cstart, cend, &work0, &work1, c, &ctemp, _state); + } + } + } + + /* + * QR iteration finished, go back and check convergence + */ + continue; + } + + /* + * All singular values converged, so make them positive + */ + for(i=1; i<=n; i++) + { + if( ae_fp_less(d->ptr.p_double[i],(double)(0)) ) + { + d->ptr.p_double[i] = -d->ptr.p_double[i]; + + /* + * Change sign of singular vectors, if desired + */ + if( ncvt>0 ) + { + ae_v_muld(&vt->ptr.pp_double[i+vstart-1][vstart], 1, ae_v_len(vstart,vend), -1.0); + } + } + } + + /* + * Sort the singular values into decreasing order (insertion sort on + * singular values, but only one transposition per singular vector) + */ + for(i=1; i<=n-1; i++) + { + + /* + * Scan for smallest D(I) + */ + isub = 1; + smin = d->ptr.p_double[1]; + for(j=2; j<=n+1-i; j++) + { + if( ae_fp_less_eq(d->ptr.p_double[j],smin) ) + { + isub = j; + smin = d->ptr.p_double[j]; + } + } + if( isub!=n+1-i ) + { + + /* + * Swap singular values and vectors + */ + d->ptr.p_double[isub] = d->ptr.p_double[n+1-i]; + d->ptr.p_double[n+1-i] = smin; + if( ncvt>0 ) + { + j = n+1-i; + ae_v_move(&vttemp.ptr.p_double[vstart], 1, &vt->ptr.pp_double[isub+vstart-1][vstart], 1, ae_v_len(vstart,vend)); + ae_v_move(&vt->ptr.pp_double[isub+vstart-1][vstart], 1, &vt->ptr.pp_double[j+vstart-1][vstart], 1, ae_v_len(vstart,vend)); + ae_v_move(&vt->ptr.pp_double[j+vstart-1][vstart], 1, &vttemp.ptr.p_double[vstart], 1, ae_v_len(vstart,vend)); + } + if( nru>0 ) + { + j = n+1-i; + ae_v_move(&utemp.ptr.p_double[ustart], 1, &ut.ptr.pp_double[isub+ustart-1][ustart], 1, ae_v_len(ustart,uend)); + ae_v_move(&ut.ptr.pp_double[isub+ustart-1][ustart], 1, &ut.ptr.pp_double[j+ustart-1][ustart], 1, ae_v_len(ustart,uend)); + ae_v_move(&ut.ptr.pp_double[j+ustart-1][ustart], 1, &utemp.ptr.p_double[ustart], 1, ae_v_len(ustart,uend)); + } + if( ncc>0 ) + { + j = n+1-i; + ae_v_move(&ctemp.ptr.p_double[cstart], 1, &c->ptr.pp_double[isub+cstart-1][cstart], 1, ae_v_len(cstart,cend)); + ae_v_move(&c->ptr.pp_double[isub+cstart-1][cstart], 1, &c->ptr.pp_double[j+cstart-1][cstart], 1, ae_v_len(cstart,cend)); + ae_v_move(&c->ptr.pp_double[j+cstart-1][cstart], 1, &ctemp.ptr.p_double[cstart], 1, ae_v_len(cstart,cend)); + } + } + } + + /* + * Copy U back from temporary storage + */ + if( nru>0 ) + { + rmatrixtranspose(n, nru, &ut, ustart, ustart, uu, ustart, ustart, _state); + } + ae_frame_leave(_state); + return result; +} + + +static double bdsvd_extsignbdsqr(double a, double b, ae_state *_state) +{ + double result; + + + if( ae_fp_greater_eq(b,(double)(0)) ) + { + result = ae_fabs(a, _state); + } + else + { + result = -ae_fabs(a, _state); + } + return result; +} + + +static void bdsvd_svd2x2(double f, + double g, + double h, + double* ssmin, + double* ssmax, + ae_state *_state) +{ + double aas; + double at; + double au; + double c; + double fa; + double fhmn; + double fhmx; + double ga; + double ha; + + *ssmin = 0.0; + *ssmax = 0.0; + + fa = ae_fabs(f, _state); + ga = ae_fabs(g, _state); + ha = ae_fabs(h, _state); + fhmn = ae_minreal(fa, ha, _state); + fhmx = ae_maxreal(fa, ha, _state); + if( ae_fp_eq(fhmn,(double)(0)) ) + { + *ssmin = (double)(0); + if( ae_fp_eq(fhmx,(double)(0)) ) + { + *ssmax = ga; + } + else + { + *ssmax = ae_maxreal(fhmx, ga, _state)*ae_sqrt((double)1+ae_sqr(ae_minreal(fhmx, ga, _state)/ae_maxreal(fhmx, ga, _state), _state), _state); + } + } + else + { + if( ae_fp_less(ga,fhmx) ) + { + aas = (double)1+fhmn/fhmx; + at = (fhmx-fhmn)/fhmx; + au = ae_sqr(ga/fhmx, _state); + c = (double)2/(ae_sqrt(aas*aas+au, _state)+ae_sqrt(at*at+au, _state)); + *ssmin = fhmn*c; + *ssmax = fhmx/c; + } + else + { + au = fhmx/ga; + if( ae_fp_eq(au,(double)(0)) ) + { + + /* + * Avoid possible harmful underflow if exponent range + * asymmetric (true SSMIN may not underflow even if + * AU underflows) + */ + *ssmin = fhmn*fhmx/ga; + *ssmax = ga; + } + else + { + aas = (double)1+fhmn/fhmx; + at = (fhmx-fhmn)/fhmx; + c = (double)1/(ae_sqrt((double)1+ae_sqr(aas*au, _state), _state)+ae_sqrt((double)1+ae_sqr(at*au, _state), _state)); + *ssmin = fhmn*c*au; + *ssmin = *ssmin+(*ssmin); + *ssmax = ga/(c+c); + } + } + } +} + + +static void bdsvd_svdv2x2(double f, + double g, + double h, + double* ssmin, + double* ssmax, + double* snr, + double* csr, + double* snl, + double* csl, + ae_state *_state) +{ + ae_bool gasmal; + ae_bool swp; + ae_int_t pmax; + double a; + double clt; + double crt; + double d; + double fa; + double ft; + double ga; + double gt; + double ha; + double ht; + double l; + double m; + double mm; + double r; + double s; + double slt; + double srt; + double t; + double temp; + double tsign; + double tt; + double v; + + *ssmin = 0.0; + *ssmax = 0.0; + *snr = 0.0; + *csr = 0.0; + *snl = 0.0; + *csl = 0.0; + + ft = f; + fa = ae_fabs(ft, _state); + ht = h; + ha = ae_fabs(h, _state); + + /* + * these initializers are not really necessary, + * but without them compiler complains about uninitialized locals + */ + clt = (double)(0); + crt = (double)(0); + slt = (double)(0); + srt = (double)(0); + tsign = (double)(0); + + /* + * PMAX points to the maximum absolute element of matrix + * PMAX = 1 if F largest in absolute values + * PMAX = 2 if G largest in absolute values + * PMAX = 3 if H largest in absolute values + */ + pmax = 1; + swp = ae_fp_greater(ha,fa); + if( swp ) + { + + /* + * Now FA .ge. HA + */ + pmax = 3; + temp = ft; + ft = ht; + ht = temp; + temp = fa; + fa = ha; + ha = temp; + } + gt = g; + ga = ae_fabs(gt, _state); + if( ae_fp_eq(ga,(double)(0)) ) + { + + /* + * Diagonal matrix + */ + *ssmin = ha; + *ssmax = fa; + clt = (double)(1); + crt = (double)(1); + slt = (double)(0); + srt = (double)(0); + } + else + { + gasmal = ae_true; + if( ae_fp_greater(ga,fa) ) + { + pmax = 2; + if( ae_fp_less(fa/ga,ae_machineepsilon) ) + { + + /* + * Case of very large GA + */ + gasmal = ae_false; + *ssmax = ga; + if( ae_fp_greater(ha,(double)(1)) ) + { + v = ga/ha; + *ssmin = fa/v; + } + else + { + v = fa/ga; + *ssmin = v*ha; + } + clt = (double)(1); + slt = ht/gt; + srt = (double)(1); + crt = ft/gt; + } + } + if( gasmal ) + { + + /* + * Normal case + */ + d = fa-ha; + if( ae_fp_eq(d,fa) ) + { + l = (double)(1); + } + else + { + l = d/fa; + } + m = gt/ft; + t = (double)2-l; + mm = m*m; + tt = t*t; + s = ae_sqrt(tt+mm, _state); + if( ae_fp_eq(l,(double)(0)) ) + { + r = ae_fabs(m, _state); + } + else + { + r = ae_sqrt(l*l+mm, _state); + } + a = 0.5*(s+r); + *ssmin = ha/a; + *ssmax = fa*a; + if( ae_fp_eq(mm,(double)(0)) ) + { + + /* + * Note that M is very tiny + */ + if( ae_fp_eq(l,(double)(0)) ) + { + t = bdsvd_extsignbdsqr((double)(2), ft, _state)*bdsvd_extsignbdsqr((double)(1), gt, _state); + } + else + { + t = gt/bdsvd_extsignbdsqr(d, ft, _state)+m/t; + } + } + else + { + t = (m/(s+t)+m/(r+l))*((double)1+a); + } + l = ae_sqrt(t*t+(double)4, _state); + crt = (double)2/l; + srt = t/l; + clt = (crt+srt*m)/a; + v = ht/ft; + slt = v*srt/a; + } + } + if( swp ) + { + *csl = srt; + *snl = crt; + *csr = slt; + *snr = clt; + } + else + { + *csl = clt; + *snl = slt; + *csr = crt; + *snr = srt; + } + + /* + * Correct signs of SSMAX and SSMIN + */ + if( pmax==1 ) + { + tsign = bdsvd_extsignbdsqr((double)(1), *csr, _state)*bdsvd_extsignbdsqr((double)(1), *csl, _state)*bdsvd_extsignbdsqr((double)(1), f, _state); + } + if( pmax==2 ) + { + tsign = bdsvd_extsignbdsqr((double)(1), *snr, _state)*bdsvd_extsignbdsqr((double)(1), *csl, _state)*bdsvd_extsignbdsqr((double)(1), g, _state); + } + if( pmax==3 ) + { + tsign = bdsvd_extsignbdsqr((double)(1), *snr, _state)*bdsvd_extsignbdsqr((double)(1), *snl, _state)*bdsvd_extsignbdsqr((double)(1), h, _state); + } + *ssmax = bdsvd_extsignbdsqr(*ssmax, tsign, _state); + *ssmin = bdsvd_extsignbdsqr(*ssmin, tsign*bdsvd_extsignbdsqr((double)(1), f, _state)*bdsvd_extsignbdsqr((double)(1), h, _state), _state); +} + + +#endif +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Singular value decomposition of a rectangular matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm calculates the singular value decomposition of a matrix of +size MxN: A = U * S * V^T + +The algorithm finds the singular values and, optionally, matrices U and V^T. +The algorithm can find both first min(M,N) columns of matrix U and rows of +matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM +and NxN respectively). + +Take into account that the subroutine does not return matrix V but V^T. + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + UNeeded - 0, 1 or 2. See the description of the parameter U. + VTNeeded - 0, 1 or 2. See the description of the parameter VT. + AdditionalMemory - + If the parameter: + * equals 0, the algorithm doesn't use additional + memory (lower requirements, lower performance). + * equals 1, the algorithm uses additional + memory of size min(M,N)*min(M,N) of real numbers. + It often speeds up the algorithm. + * equals 2, the algorithm uses additional + memory of size M*min(M,N) of real numbers. + It allows to get a maximum performance. + The recommended value of the parameter is 2. + +Output parameters: + W - contains singular values in descending order. + U - if UNeeded=0, U isn't changed, the left singular vectors + are not calculated. + if Uneeded=1, U contains left singular vectors (first + min(M,N) columns of matrix U). Array whose indexes range + within [0..M-1, 0..Min(M,N)-1]. + if UNeeded=2, U contains matrix U wholly. Array whose + indexes range within [0..M-1, 0..M-1]. + VT - if VTNeeded=0, VT isn't changed, the right singular vectors + are not calculated. + if VTNeeded=1, VT contains right singular vectors (first + min(M,N) rows of matrix V^T). Array whose indexes range + within [0..min(M,N)-1, 0..N-1]. + if VTNeeded=2, VT contains matrix V^T wholly. Array whose + indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsvd(/* Real */ const ae_matrix* _a, + ae_int_t m, + ae_int_t n, + ae_int_t uneeded, + ae_int_t vtneeded, + ae_int_t additionalmemory, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* u, + /* Real */ ae_matrix* vt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector tauq; + ae_vector taup; + ae_vector tau; + ae_vector e; + ae_vector work; + ae_matrix t2; + ae_bool isupper; + ae_int_t minmn; + ae_int_t ncu; + ae_int_t nrvt; + ae_int_t nru; + ae_int_t ncvt; + ae_int_t i; + ae_int_t j; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&tauq, 0, sizeof(tauq)); + memset(&taup, 0, sizeof(taup)); + memset(&tau, 0, sizeof(tau)); + memset(&e, 0, sizeof(e)); + memset(&work, 0, sizeof(work)); + memset(&t2, 0, sizeof(t2)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(w); + ae_matrix_clear(u); + ae_matrix_clear(vt); + ae_vector_init(&tauq, 0, DT_REAL, _state, ae_true); + ae_vector_init(&taup, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&e, 0, DT_REAL, _state, ae_true); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&t2, 0, 0, DT_REAL, _state, ae_true); + + result = ae_true; + if( m==0||n==0 ) + { + ae_frame_leave(_state); + return result; + } + ae_assert(uneeded>=0&&uneeded<=2, "SVDDecomposition: wrong parameters!", _state); + ae_assert(vtneeded>=0&&vtneeded<=2, "SVDDecomposition: wrong parameters!", _state); + ae_assert(additionalmemory>=0&&additionalmemory<=2, "SVDDecomposition: wrong parameters!", _state); + + /* + * initialize + */ + minmn = ae_minint(m, n, _state); + ae_vector_set_length(w, minmn+1, _state); + ncu = 0; + nru = 0; + if( uneeded==1 ) + { + nru = m; + ncu = minmn; + ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); + } + if( uneeded==2 ) + { + nru = m; + ncu = m; + ae_matrix_set_length(u, nru-1+1, ncu-1+1, _state); + } + nrvt = 0; + ncvt = 0; + if( vtneeded==1 ) + { + nrvt = minmn; + ncvt = n; + ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); + } + if( vtneeded==2 ) + { + nrvt = n; + ncvt = n; + ae_matrix_set_length(vt, nrvt-1+1, ncvt-1+1, _state); + } + + /* + * M much larger than N + * Use bidiagonal reduction with QR-decomposition + */ + if( ae_fp_greater((double)(m),1.6*(double)n) ) + { + if( uneeded==0 ) + { + + /* + * No left singular vectors to be computed + */ + rmatrixqr(&a, m, n, &tau, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + } + rmatrixbd(&a, n, n, &tauq, &taup, _state); + rmatrixbdunpackpt(&a, n, n, &taup, nrvt, vt, _state); + rmatrixbdunpackdiagonals(&a, n, n, &isupper, w, &e, _state); + result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, &a, 0, vt, ncvt, _state); + ae_frame_leave(_state); + return result; + } + else + { + + /* + * Left singular vectors (may be full matrix U) to be computed + */ + rmatrixqr(&a, m, n, &tau, _state); + rmatrixqrunpackq(&a, m, n, &tau, ncu, u, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + } + rmatrixbd(&a, n, n, &tauq, &taup, _state); + rmatrixbdunpackpt(&a, n, n, &taup, nrvt, vt, _state); + rmatrixbdunpackdiagonals(&a, n, n, &isupper, w, &e, _state); + if( additionalmemory<1 ) + { + + /* + * No additional memory can be used + */ + rmatrixbdmultiplybyq(&a, n, n, &tauq, u, m, n, ae_true, ae_false, _state); + result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, m, &a, 0, vt, ncvt, _state); + } + else + { + + /* + * Large U. Transforming intermediate matrix T2 + */ + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + rmatrixbdunpackq(&a, n, n, &tauq, n, &t2, _state); + copymatrix(u, 0, m-1, 0, n-1, &a, 0, m-1, 0, n-1, _state); + inplacetranspose(&t2, 0, n-1, 0, n-1, &work, _state); + result = rmatrixbdsvd(w, &e, n, isupper, ae_false, u, 0, &t2, n, vt, ncvt, _state); + rmatrixgemm(m, n, n, 1.0, &a, 0, 0, 0, &t2, 0, 0, 1, 0.0, u, 0, 0, _state); + } + ae_frame_leave(_state); + return result; + } + } + + /* + * N much larger than M + * Use bidiagonal reduction with LQ-decomposition + */ + if( ae_fp_greater((double)(n),1.6*(double)m) ) + { + if( vtneeded==0 ) + { + + /* + * No right singular vectors to be computed + */ + rmatrixlq(&a, m, n, &tau, _state); + for(i=0; i<=m-1; i++) + { + for(j=i+1; j<=m-1; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + } + rmatrixbd(&a, m, m, &tauq, &taup, _state); + rmatrixbdunpackq(&a, m, m, &tauq, ncu, u, _state); + rmatrixbdunpackdiagonals(&a, m, m, &isupper, w, &e, _state); + ae_vector_set_length(&work, m+1, _state); + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + result = rmatrixbdsvd(w, &e, m, isupper, ae_false, &a, 0, u, nru, vt, 0, _state); + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + ae_frame_leave(_state); + return result; + } + else + { + + /* + * Right singular vectors (may be full matrix VT) to be computed + */ + rmatrixlq(&a, m, n, &tau, _state); + rmatrixlqunpackq(&a, m, n, &tau, nrvt, vt, _state); + for(i=0; i<=m-1; i++) + { + for(j=i+1; j<=m-1; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + } + rmatrixbd(&a, m, m, &tauq, &taup, _state); + rmatrixbdunpackq(&a, m, m, &tauq, ncu, u, _state); + rmatrixbdunpackdiagonals(&a, m, m, &isupper, w, &e, _state); + ae_vector_set_length(&work, ae_maxint(m, n, _state)+1, _state); + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + if( additionalmemory<1 ) + { + + /* + * No additional memory available + */ + rmatrixbdmultiplybyp(&a, m, m, &taup, vt, m, n, ae_false, ae_true, _state); + result = rmatrixbdsvd(w, &e, m, isupper, ae_false, &a, 0, u, nru, vt, n, _state); + } + else + { + + /* + * Large VT. Transforming intermediate matrix T2 + */ + rmatrixbdunpackpt(&a, m, m, &taup, m, &t2, _state); + result = rmatrixbdsvd(w, &e, m, isupper, ae_false, &a, 0, u, nru, &t2, m, _state); + copymatrix(vt, 0, m-1, 0, n-1, &a, 0, m-1, 0, n-1, _state); + rmatrixgemm(m, n, m, 1.0, &t2, 0, 0, 0, &a, 0, 0, 0, 0.0, vt, 0, 0, _state); + } + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + ae_frame_leave(_state); + return result; + } + } + + /* + * M<=N + * We can use inplace transposition of U to get rid of columnwise operations + */ + if( m<=n ) + { + rmatrixbd(&a, m, n, &tauq, &taup, _state); + rmatrixbdunpackq(&a, m, n, &tauq, ncu, u, _state); + rmatrixbdunpackpt(&a, m, n, &taup, nrvt, vt, _state); + rmatrixbdunpackdiagonals(&a, m, n, &isupper, w, &e, _state); + ae_vector_set_length(&work, m+1, _state); + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, &a, 0, u, nru, vt, ncvt, _state); + inplacetranspose(u, 0, nru-1, 0, ncu-1, &work, _state); + ae_frame_leave(_state); + return result; + } + + /* + * Simple bidiagonal reduction + */ + rmatrixbd(&a, m, n, &tauq, &taup, _state); + rmatrixbdunpackq(&a, m, n, &tauq, ncu, u, _state); + rmatrixbdunpackpt(&a, m, n, &taup, nrvt, vt, _state); + rmatrixbdunpackdiagonals(&a, m, n, &isupper, w, &e, _state); + if( additionalmemory<2||uneeded==0 ) + { + + /* + * We cant use additional memory or there is no need in such operations + */ + result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, nru, &a, 0, vt, ncvt, _state); + } + else + { + + /* + * We can use additional memory + */ + ae_matrix_set_length(&t2, minmn-1+1, m-1+1, _state); + copyandtranspose(u, 0, m-1, 0, minmn-1, &t2, 0, minmn-1, 0, m-1, _state); + result = rmatrixbdsvd(w, &e, minmn, isupper, ae_false, u, 0, &t2, m, vt, ncvt, _state); + copyandtranspose(&t2, 0, minmn-1, 0, m-1, u, 0, m-1, 0, minmn-1, _state); + } + ae_frame_leave(_state); + return result; +} + + +#endif +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond1(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_vector t; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + memset(&t, 0, sizeof(t)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RMatrixRCond1: N<1!", _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a.ptr.pp_double[i][j], _state); + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + rmatrixlu(&a, n, n, &pivots, _state); + rcond_rmatrixrcondluinternal(&a, n, ae_true, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of a matrix condition number (2-norm) + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then the matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector w; + ae_matrix u; + ae_matrix vt; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RMatrixRCond2: N<1!", _state); + if( !rmatrixsvd(a, n, n, 0, 0, 0, &w, &u, &vt, _state) ) + { + ae_assert(ae_false, "RMatrixRCond2: SVD solver failure", _state); + } + result = (double)(0); + if( ae_fp_neq(w.ptr.p_double[0],(double)(0)) ) + { + result = w.ptr.p_double[n-1]/w.ptr.p_double[0]; + } + if( ae_fp_less(result,(double)10*ae_machineepsilon) ) + { + result = (double)(0); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of a matrix condition number (2-norm) for a rectangular matrix. + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array[M,N] + M, N- rows and columns count, >=1 + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2rect(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector w; + ae_matrix u; + ae_matrix vt; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&w, 0, sizeof(w)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(m>=1, "RMatrixRCond2Rect: M<1!", _state); + ae_assert(n>=1, "RMatrixRCond2Rect: N<1!", _state); + if( !rmatrixsvd(a, m, n, 0, 0, 0, &w, &u, &vt, _state) ) + { + ae_assert(ae_false, "RMatrixRCond2Rect: SVD solver failure", _state); + } + result = (double)(0); + if( ae_fp_neq(w.ptr.p_double[0],(double)(0)) ) + { + result = w.ptr.p_double[ae_minint(m, n, _state)-1]/w.ptr.p_double[0]; + } + if( ae_fp_less(result,(double)10*ae_machineepsilon) ) + { + result = (double)(0); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcondinf(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "RMatrixRCondInf: N<1!", _state); + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+ae_fabs(a.ptr.pp_double[i][j], _state); + } + nrm = ae_maxreal(nrm, v, _state); + } + rmatrixlu(&a, n, n, &pivots, _state); + rcond_rmatrixrcondluinternal(&a, n, ae_false, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + double v; + double nrm; + ae_vector t; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&t, 0, sizeof(t)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( i==j ) + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a.ptr.pp_double[i][i], _state); + } + else + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a.ptr.pp_double[i][j], _state); + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a.ptr.pp_double[i][j], _state); + } + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + if( spdmatrixcholesky(&a, n, isupper, _state) ) + { + rcond_spdmatrixrcondcholeskyinternal(&a, n, isupper, ae_true, nrm, &v, _state); + result = v; + } + else + { + result = (double)(-1); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +2-norm condition number of a symmetric positive definite matrix using EVD. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array[N,N] + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/cond(A), if matrix A is positive definite, + 0, if matrix A is not positive definite + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond2(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector d; + ae_matrix z; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&d, 0, sizeof(d)); + memset(&z, 0, sizeof(z)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&d, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true); + + if( !smatrixevd(&a, n, 0, isupper, &d, &z, _state) ) + { + ae_assert(ae_false, "SPDMatrixRCond2: EVD solver failure", _state); + } + result = (double)(0); + if( ae_fp_greater(d.ptr.p_double[n-1],(double)(0)) ) + { + result = d.ptr.p_double[0]/d.ptr.p_double[n-1]; + } + if( ae_fp_less(result,(double)10*ae_machineepsilon) ) + { + result = (double)(0); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond1(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_vector t; + ae_int_t j1; + ae_int_t j2; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + memset(&t, 0, sizeof(t)); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + for(j=j1; j<=j2; j++) + { + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_fabs(a->ptr.pp_double[i][j], _state); + } + if( isunit ) + { + t.ptr.p_double[i] = t.ptr.p_double[i]+(double)1; + } + else + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_fabs(a->ptr.pp_double[i][i], _state); + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Triangular matrix: reciprocal 2-norm condition number + +The algorithm calculates a reciprocal 2-norm condition number using SVD. + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/cond(A) + +NOTE: + if k(A) is very large, then matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond2(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>=1, "RMatrixTRRCond2: N<1!", _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = 0; + j2 = i-1; + } + else + { + j1 = i+1; + j2 = n-1; + } + for(j=j1; j<=j2; j++) + { + a.ptr.pp_double[i][j] = (double)(0); + } + if( isunit ) + { + a.ptr.pp_double[i][i] = (double)(1); + } + } + result = rmatrixrcond2(&a, n, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcondinf(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_int_t j1; + ae_int_t j2; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + v = (double)(0); + for(j=j1; j<=j2; j++) + { + v = v+ae_fabs(a->ptr.pp_double[i][j], _state); + } + if( isunit ) + { + v = v+(double)1; + } + else + { + v = v+ae_fabs(a->ptr.pp_double[i][i], _state); + } + nrm = ae_maxreal(nrm, v, _state); + } + rcond_rmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - Hermitian positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixrcond(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + double v; + double nrm; + ae_vector t; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&t, 0, sizeof(t)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i; + } + for(j=j1; j<=j2; j++) + { + if( i==j ) + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a.ptr.pp_complex[i][i], _state); + } + else + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a.ptr.pp_complex[i][j], _state); + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a.ptr.pp_complex[i][j], _state); + } + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + if( hpdmatrixcholesky(&a, n, isupper, _state) ) + { + rcond_hpdmatrixrcondcholeskyinternal(&a, n, isupper, ae_true, nrm, &v, _state); + result = v; + } + else + { + result = (double)(-1); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcond1(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_vector t; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + memset(&t, 0, sizeof(t)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "CMatrixRCond1: N<1!", _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a.ptr.pp_complex[i][j], _state); + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + cmatrixlu(&a, n, n, &pivots, _state); + rcond_cmatrixrcondluinternal(&a, n, ae_true, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcondinf(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "CMatrixRCondInf: N<1!", _state); + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+ae_c_abs(a.ptr.pp_complex[i][j], _state); + } + nrm = ae_maxreal(nrm, v, _state); + } + cmatrixlu(&a, n, n, &pivots, _state); + rcond_cmatrixrcondluinternal(&a, n, ae_false, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcond1(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state) +{ + double v; + double result; + + + rcond_rmatrixrcondluinternal(lua, n, ae_true, ae_false, (double)(0), &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcondinf(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state) +{ + double v; + double result; + + + rcond_rmatrixrcondluinternal(lua, n, ae_false, ae_false, (double)(0), &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixcholeskyrcond(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + double v; + double result; + + + rcond_spdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, (double)(0), &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixcholeskyrcond(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + double v; + double result; + + + rcond_hpdmatrixrcondcholeskyinternal(a, n, isupper, ae_false, (double)(0), &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcond1(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state) +{ + double v; + double result; + + + ae_assert(n>=1, "CMatrixLURCond1: N<1!", _state); + rcond_cmatrixrcondluinternal(lua, n, ae_true, ae_false, 0.0, &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcondinf(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state) +{ + double v; + double result; + + + ae_assert(n>=1, "CMatrixLURCondInf: N<1!", _state); + rcond_cmatrixrcondluinternal(lua, n, ae_false, ae_false, 0.0, &v, _state); + result = v; + return result; +} + + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcond1(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_vector t; + ae_int_t j1; + ae_int_t j2; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + memset(&t, 0, sizeof(t)); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=1, "RMatrixTRRCond1: N<1!", _state); + ae_vector_set_length(&t, n, _state); + for(i=0; i<=n-1; i++) + { + t.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + for(j=j1; j<=j2; j++) + { + t.ptr.p_double[j] = t.ptr.p_double[j]+ae_c_abs(a->ptr.pp_complex[i][j], _state); + } + if( isunit ) + { + t.ptr.p_double[i] = t.ptr.p_double[i]+(double)1; + } + else + { + t.ptr.p_double[i] = t.ptr.p_double[i]+ae_c_abs(a->ptr.pp_complex[i][i], _state); + } + } + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = ae_maxreal(nrm, t.ptr.p_double[i], _state); + } + rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_true, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcondinf(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double nrm; + ae_vector pivots; + ae_int_t j1; + ae_int_t j2; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "RMatrixTRRCondInf: N<1!", _state); + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + v = (double)(0); + for(j=j1; j<=j2; j++) + { + v = v+ae_c_abs(a->ptr.pp_complex[i][j], _state); + } + if( isunit ) + { + v = v+(double)1; + } + else + { + v = v+ae_c_abs(a->ptr.pp_complex[i][i], _state); + } + nrm = ae_maxreal(nrm, v, _state); + } + rcond_cmatrixrcondtrinternal(a, n, isupper, isunit, ae_false, nrm, &v, _state); + result = v; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Threshold for rcond: matrices with condition number beyond this threshold +are considered singular. + +Threshold must be far enough from underflow, at least Sqr(Threshold) must +be greater than underflow. +*************************************************************************/ +double rcondthreshold(ae_state *_state) +{ + double result; + + + result = ae_sqrt(ae_sqrt(ae_minrealnumber, _state), _state); + return result; +} + + +/************************************************************************* +Internal subroutine for condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static void rcond_rmatrixrcondtrinternal(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_bool onenorm, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector ex; + ae_vector ev; + ae_vector iwork; + ae_vector tmp; + ae_int_t i; + ae_int_t j; + ae_int_t kase; + ae_int_t kase1; + ae_int_t j1; + ae_int_t j2; + double ainvnm; + double maxgrowth; + double s; + + ae_frame_make(_state, &_frame_block); + memset(&ex, 0, sizeof(ex)); + memset(&ev, 0, sizeof(ev)); + memset(&iwork, 0, sizeof(iwork)); + memset(&tmp, 0, sizeof(tmp)); + *rc = 0.0; + ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); + ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * RC=0 if something happens + */ + *rc = (double)(0); + + /* + * init + */ + if( onenorm ) + { + kase1 = 1; + } + else + { + kase1 = 2; + } + ae_vector_set_length(&iwork, n+1, _state); + ae_vector_set_length(&tmp, n, _state); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + s = (double)(0); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + for(j=j1; j<=j2; j++) + { + s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][j], _state), _state); + } + if( isunit ) + { + s = ae_maxreal(s, (double)(1), _state); + } + else + { + s = ae_maxreal(s, ae_fabs(a->ptr.pp_double[i][i], _state), _state); + } + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(1); + } + s = (double)1/s; + + /* + * Scale according to S + */ + anorm = anorm*s; + + /* + * Quick return if possible + * We assume that ANORM<>0 after this block + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Estimate the norm of inv(A). + */ + ainvnm = (double)(0); + kase = 0; + for(;;) + { + rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); + if( kase==0 ) + { + break; + } + + /* + * from 1-based array to 0-based + */ + for(i=0; i<=n-1; i++) + { + ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; + } + + /* + * multiply by inv(A) or inv(A') + */ + if( kase==kase1 ) + { + + /* + * multiply by inv(A) + */ + if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * multiply by inv(A') + */ + if( !rmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 1, isunit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * from 0-based array to 1-based + */ + for(i=n-1; i>=0; i--) + { + ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + *rc = (double)1/ainvnm; + *rc = *rc/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 +*************************************************************************/ +static void rcond_cmatrixrcondtrinternal(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_bool onenorm, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector ex; + ae_vector cwork2; + ae_vector cwork3; + ae_vector cwork4; + ae_vector isave; + ae_vector rsave; + ae_int_t kase; + ae_int_t kase1; + double ainvnm; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + double s; + double maxgrowth; + + ae_frame_make(_state, &_frame_block); + memset(&ex, 0, sizeof(ex)); + memset(&cwork2, 0, sizeof(cwork2)); + memset(&cwork3, 0, sizeof(cwork3)); + memset(&cwork4, 0, sizeof(cwork4)); + memset(&isave, 0, sizeof(isave)); + memset(&rsave, 0, sizeof(rsave)); + *rc = 0.0; + ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork2, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork3, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork4, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&isave, 0, DT_INT, _state, ae_true); + ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); + + + /* + * RC=0 if something happens + */ + *rc = (double)(0); + + /* + * init + */ + if( n<0 ) + { + ae_frame_leave(_state); + return; + } + if( n==0 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&cwork2, n+1, _state); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + s = (double)(0); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j1 = i+1; + j2 = n-1; + } + else + { + j1 = 0; + j2 = i-1; + } + for(j=j1; j<=j2; j++) + { + s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); + } + if( isunit ) + { + s = ae_maxreal(s, (double)(1), _state); + } + else + { + s = ae_maxreal(s, ae_c_abs(a->ptr.pp_complex[i][i], _state), _state); + } + } + if( ae_fp_eq(s,(double)(0)) ) + { + s = (double)(1); + } + s = (double)1/s; + + /* + * Scale according to S + */ + anorm = anorm*s; + + /* + * Quick return if possible + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Estimate the norm of inv(A). + */ + ainvnm = (double)(0); + if( onenorm ) + { + kase1 = 1; + } + else + { + kase1 = 2; + } + kase = 0; + for(;;) + { + rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); + if( kase==0 ) + { + break; + } + + /* + * From 1-based to 0-based + */ + for(i=0; i<=n-1; i++) + { + ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; + } + + /* + * multiply by inv(A) or inv(A') + */ + if( kase==kase1 ) + { + + /* + * multiply by inv(A) + */ + if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 0, isunit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * multiply by inv(A') + */ + if( !cmatrixscaledtrsafesolve(a, s, n, &ex, isupper, 2, isunit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * from 0-based to 1-based + */ + for(i=n-1; i>=0; i--) + { + ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + *rc = (double)1/ainvnm; + *rc = *rc/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine for condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static void rcond_spdmatrixrcondcholeskyinternal(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + ae_bool isnormprovided, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t kase; + double ainvnm; + ae_vector ex; + ae_vector ev; + ae_vector tmp; + ae_vector iwork; + double sa; + double v; + double maxgrowth; + + ae_frame_make(_state, &_frame_block); + memset(&ex, 0, sizeof(ex)); + memset(&ev, 0, sizeof(ev)); + memset(&tmp, 0, sizeof(tmp)); + memset(&iwork, 0, sizeof(iwork)); + *rc = 0.0; + ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "Assertion failed", _state); + ae_vector_set_length(&tmp, n, _state); + + /* + * RC=0 if something happens + */ + *rc = (double)(0); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + sa = (double)(0); + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i; j++) + { + sa = ae_maxreal(sa, ae_c_abs(ae_complex_from_d(cha->ptr.pp_double[i][j]), _state), _state); + } + } + } + if( ae_fp_eq(sa,(double)(0)) ) + { + sa = (double)(1); + } + sa = (double)1/sa; + + /* + * Estimate the norm of A. + */ + if( !isnormprovided ) + { + kase = 0; + anorm = (double)(0); + for(;;) + { + rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); + if( kase==0 ) + { + break; + } + if( isupper ) + { + + /* + * Multiply by U + */ + for(i=1; i<=n; i++) + { + v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); + ex.ptr.p_double[i] = v; + } + ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); + + /* + * Multiply by U' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_double[i+1]; + ae_v_addd(&tmp.ptr.p_double[i], 1, &cha->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); + } + ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); + ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); + } + else + { + + /* + * Multiply by L' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_double[i+1]; + ae_v_addd(&tmp.ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i), v); + } + ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); + ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); + + /* + * Multiply by L + */ + for(i=n; i>=1; i--) + { + v = ae_v_dotproduct(&cha->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-1)); + ex.ptr.p_double[i] = v; + } + ae_v_muld(&ex.ptr.p_double[1], 1, ae_v_len(1,n), sa); + } + } + } + + /* + * Quick return if possible + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Estimate the 1-norm of inv(A). + */ + kase = 0; + for(;;) + { + rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); + if( kase==0 ) + { + break; + } + for(i=0; i<=n-1; i++) + { + ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; + } + if( isupper ) + { + + /* + * Multiply by inv(U'). + */ + if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(U). + */ + if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * Multiply by inv(L). + */ + if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(L'). + */ + if( !rmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 1, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + for(i=n-1; i>=0; i--) + { + ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + v = (double)1/ainvnm; + *rc = v/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine for condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static void rcond_hpdmatrixrcondcholeskyinternal(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + ae_bool isnormprovided, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector isave; + ae_vector rsave; + ae_vector ex; + ae_vector ev; + ae_vector tmp; + ae_int_t kase; + double ainvnm; + ae_complex v; + ae_int_t i; + ae_int_t j; + double sa; + double maxgrowth; + + ae_frame_make(_state, &_frame_block); + memset(&isave, 0, sizeof(isave)); + memset(&rsave, 0, sizeof(rsave)); + memset(&ex, 0, sizeof(ex)); + memset(&ev, 0, sizeof(ev)); + memset(&tmp, 0, sizeof(tmp)); + *rc = 0.0; + ae_vector_init(&isave, 0, DT_INT, _state, ae_true); + ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&ev, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>=1, "Assertion failed", _state); + ae_vector_set_length(&tmp, n, _state); + + /* + * RC=0 if something happens + */ + *rc = (double)(0); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + sa = (double)(0); + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i; j++) + { + sa = ae_maxreal(sa, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); + } + } + } + if( ae_fp_eq(sa,(double)(0)) ) + { + sa = (double)(1); + } + sa = (double)1/sa; + + /* + * Estimate the norm of A + */ + if( !isnormprovided ) + { + anorm = (double)(0); + kase = 0; + for(;;) + { + rcond_cmatrixestimatenorm(n, &ev, &ex, &anorm, &kase, &isave, &rsave, _state); + if( kase==0 ) + { + break; + } + if( isupper ) + { + + /* + * Multiply by U + */ + for(i=1; i<=n; i++) + { + v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); + ex.ptr.p_complex[i] = v; + } + ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); + + /* + * Multiply by U' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_complex[i+1]; + ae_v_caddc(&tmp.ptr.p_complex[i], 1, &cha->ptr.pp_complex[i][i], 1, "Conj", ae_v_len(i,n-1), v); + } + ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); + ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); + } + else + { + + /* + * Multiply by L' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_complex[i+1]; + ae_v_caddc(&tmp.ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i), v); + } + ae_v_cmove(&ex.ptr.p_complex[1], 1, &tmp.ptr.p_complex[0], 1, "N", ae_v_len(1,n)); + ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); + + /* + * Multiply by L + */ + for(i=n; i>=1; i--) + { + v = ae_v_cdotproduct(&cha->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-1)); + ex.ptr.p_complex[i] = v; + } + ae_v_cmuld(&ex.ptr.p_complex[1], 1, ae_v_len(1,n), sa); + } + } + } + + /* + * Quick return if possible + * After this block we assume that ANORM<>0 + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Estimate the norm of inv(A). + */ + ainvnm = (double)(0); + kase = 0; + for(;;) + { + rcond_cmatrixestimatenorm(n, &ev, &ex, &ainvnm, &kase, &isave, &rsave, _state); + if( kase==0 ) + { + break; + } + for(i=0; i<=n-1; i++) + { + ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; + } + if( isupper ) + { + + /* + * Multiply by inv(U'). + */ + if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(U). + */ + if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * Multiply by inv(L). + */ + if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 0, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(L'). + */ + if( !cmatrixscaledtrsafesolve(cha, sa, n, &ex, isupper, 2, ae_false, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + for(i=n-1; i>=0; i--) + { + ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + *rc = (double)1/ainvnm; + *rc = *rc/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine for condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static void rcond_rmatrixrcondluinternal(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_bool onenorm, + ae_bool isanormprovided, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector ex; + ae_vector ev; + ae_vector iwork; + ae_vector tmp; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t kase; + ae_int_t kase1; + double ainvnm; + double maxgrowth; + double su; + double sl; + ae_bool mupper; + ae_bool munit; + + ae_frame_make(_state, &_frame_block); + memset(&ex, 0, sizeof(ex)); + memset(&ev, 0, sizeof(ev)); + memset(&iwork, 0, sizeof(iwork)); + memset(&tmp, 0, sizeof(tmp)); + *rc = 0.0; + ae_vector_init(&ex, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ev, 0, DT_REAL, _state, ae_true); + ae_vector_init(&iwork, 0, DT_INT, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + + /* + * RC=0 if something happens + */ + *rc = (double)(0); + + /* + * init + */ + if( onenorm ) + { + kase1 = 1; + } + else + { + kase1 = 2; + } + mupper = ae_true; + munit = ae_true; + ae_vector_set_length(&iwork, n+1, _state); + ae_vector_set_length(&tmp, n, _state); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + su = (double)(0); + sl = (double)(1); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + sl = ae_maxreal(sl, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); + } + for(j=i; j<=n-1; j++) + { + su = ae_maxreal(su, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); + } + } + if( ae_fp_eq(su,(double)(0)) ) + { + su = (double)(1); + } + su = (double)1/su; + sl = (double)1/sl; + + /* + * Estimate the norm of A. + */ + if( !isanormprovided ) + { + kase = 0; + anorm = (double)(0); + for(;;) + { + rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &anorm, &kase, _state); + if( kase==0 ) + { + break; + } + if( kase==kase1 ) + { + + /* + * Multiply by U + */ + for(i=1; i<=n; i++) + { + v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][i-1], 1, &ex.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); + ex.ptr.p_double[i] = v; + } + + /* + * Multiply by L + */ + for(i=n; i>=1; i--) + { + if( i>1 ) + { + v = ae_v_dotproduct(&lua->ptr.pp_double[i-1][0], 1, &ex.ptr.p_double[1], 1, ae_v_len(0,i-2)); + } + else + { + v = (double)(0); + } + ex.ptr.p_double[i] = ex.ptr.p_double[i]+v; + } + } + else + { + + /* + * Multiply by L' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_double[i+1]; + if( i>=1 ) + { + ae_v_addd(&tmp.ptr.p_double[0], 1, &lua->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v); + } + tmp.ptr.p_double[i] = tmp.ptr.p_double[i]+v; + } + ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); + + /* + * Multiply by U' + */ + for(i=0; i<=n-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + v = ex.ptr.p_double[i+1]; + ae_v_addd(&tmp.ptr.p_double[i], 1, &lua->ptr.pp_double[i][i], 1, ae_v_len(i,n-1), v); + } + ae_v_move(&ex.ptr.p_double[1], 1, &tmp.ptr.p_double[0], 1, ae_v_len(1,n)); + } + } + } + + /* + * Scale according to SU/SL + */ + anorm = anorm*su*sl; + + /* + * Quick return if possible + * We assume that ANORM<>0 after this block + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + if( n==1 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + + /* + * Estimate the norm of inv(A). + */ + ainvnm = (double)(0); + kase = 0; + for(;;) + { + rcond_rmatrixestimatenorm(n, &ev, &ex, &iwork, &ainvnm, &kase, _state); + if( kase==0 ) + { + break; + } + + /* + * from 1-based array to 0-based + */ + for(i=0; i<=n-1; i++) + { + ex.ptr.p_double[i] = ex.ptr.p_double[i+1]; + } + + /* + * multiply by inv(A) or inv(A') + */ + if( kase==kase1 ) + { + + /* + * Multiply by inv(L). + */ + if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 0, munit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(U). + */ + if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 0, !munit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * Multiply by inv(U'). + */ + if( !rmatrixscaledtrsafesolve(lua, su, n, &ex, mupper, 1, !munit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(L'). + */ + if( !rmatrixscaledtrsafesolve(lua, sl, n, &ex, !mupper, 1, munit, maxgrowth, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * from 0-based array to 1-based + */ + for(i=n-1; i>=0; i--) + { + ex.ptr.p_double[i+1] = ex.ptr.p_double[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + *rc = (double)1/ainvnm; + *rc = *rc/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Condition number estimation + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + March 31, 1993 +*************************************************************************/ +static void rcond_cmatrixrcondluinternal(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_bool onenorm, + ae_bool isanormprovided, + double anorm, + double* rc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector ex; + ae_vector cwork2; + ae_vector cwork3; + ae_vector cwork4; + ae_vector isave; + ae_vector rsave; + ae_int_t kase; + ae_int_t kase1; + double ainvnm; + ae_complex v; + ae_int_t i; + ae_int_t j; + double su; + double sl; + double maxgrowth; + + ae_frame_make(_state, &_frame_block); + memset(&ex, 0, sizeof(ex)); + memset(&cwork2, 0, sizeof(cwork2)); + memset(&cwork3, 0, sizeof(cwork3)); + memset(&cwork4, 0, sizeof(cwork4)); + memset(&isave, 0, sizeof(isave)); + memset(&rsave, 0, sizeof(rsave)); + *rc = 0.0; + ae_vector_init(&ex, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork2, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork3, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&cwork4, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&isave, 0, DT_INT, _state, ae_true); + ae_vector_init(&rsave, 0, DT_REAL, _state, ae_true); + + *rc = (double)(0); + if( n<0 ) + { + ae_frame_leave(_state); + return; + } + if( n==0 ) + { + *rc = (double)(1); + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&cwork2, n+1, _state); + + /* + * prepare parameters for triangular solver + */ + maxgrowth = (double)1/rcondthreshold(_state); + su = (double)(0); + sl = (double)(1); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + sl = ae_maxreal(sl, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); + } + for(j=i; j<=n-1; j++) + { + su = ae_maxreal(su, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); + } + } + if( ae_fp_eq(su,(double)(0)) ) + { + su = (double)(1); + } + su = (double)1/su; + sl = (double)1/sl; + + /* + * Estimate the norm of SU*SL*A. + */ + if( !isanormprovided ) + { + anorm = (double)(0); + if( onenorm ) + { + kase1 = 1; + } + else + { + kase1 = 2; + } + kase = 0; + do + { + rcond_cmatrixestimatenorm(n, &cwork4, &ex, &anorm, &kase, &isave, &rsave, _state); + if( kase!=0 ) + { + if( kase==kase1 ) + { + + /* + * Multiply by U + */ + for(i=1; i<=n; i++) + { + v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][i-1], 1, "N", &ex.ptr.p_complex[i], 1, "N", ae_v_len(i-1,n-1)); + ex.ptr.p_complex[i] = v; + } + + /* + * Multiply by L + */ + for(i=n; i>=1; i--) + { + v = ae_complex_from_i(0); + if( i>1 ) + { + v = ae_v_cdotproduct(&lua->ptr.pp_complex[i-1][0], 1, "N", &ex.ptr.p_complex[1], 1, "N", ae_v_len(0,i-2)); + } + ex.ptr.p_complex[i] = ae_c_add(v,ex.ptr.p_complex[i]); + } + } + else + { + + /* + * Multiply by L' + */ + for(i=1; i<=n; i++) + { + cwork2.ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=1; i<=n; i++) + { + v = ex.ptr.p_complex[i]; + if( i>1 ) + { + ae_v_caddc(&cwork2.ptr.p_complex[1], 1, &lua->ptr.pp_complex[i-1][0], 1, "Conj", ae_v_len(1,i-1), v); + } + cwork2.ptr.p_complex[i] = ae_c_add(cwork2.ptr.p_complex[i],v); + } + + /* + * Multiply by U' + */ + for(i=1; i<=n; i++) + { + ex.ptr.p_complex[i] = ae_complex_from_i(0); + } + for(i=1; i<=n; i++) + { + v = cwork2.ptr.p_complex[i]; + ae_v_caddc(&ex.ptr.p_complex[i], 1, &lua->ptr.pp_complex[i-1][i-1], 1, "Conj", ae_v_len(i,n), v); + } + } + } + } + while(kase!=0); + } + + /* + * Scale according to SU/SL + */ + anorm = anorm*su*sl; + + /* + * Quick return if possible + */ + if( ae_fp_eq(anorm,(double)(0)) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Estimate the norm of inv(A). + */ + ainvnm = (double)(0); + if( onenorm ) + { + kase1 = 1; + } + else + { + kase1 = 2; + } + kase = 0; + for(;;) + { + rcond_cmatrixestimatenorm(n, &cwork4, &ex, &ainvnm, &kase, &isave, &rsave, _state); + if( kase==0 ) + { + break; + } + + /* + * From 1-based to 0-based + */ + for(i=0; i<=n-1; i++) + { + ex.ptr.p_complex[i] = ex.ptr.p_complex[i+1]; + } + + /* + * multiply by inv(A) or inv(A') + */ + if( kase==kase1 ) + { + + /* + * Multiply by inv(L). + */ + if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 0, ae_true, maxgrowth, _state) ) + { + *rc = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(U). + */ + if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 0, ae_false, maxgrowth, _state) ) + { + *rc = (double)(0); + ae_frame_leave(_state); + return; + } + } + else + { + + /* + * Multiply by inv(U'). + */ + if( !cmatrixscaledtrsafesolve(lua, su, n, &ex, ae_true, 2, ae_false, maxgrowth, _state) ) + { + *rc = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Multiply by inv(L'). + */ + if( !cmatrixscaledtrsafesolve(lua, sl, n, &ex, ae_false, 2, ae_true, maxgrowth, _state) ) + { + *rc = (double)(0); + ae_frame_leave(_state); + return; + } + } + + /* + * from 0-based to 1-based + */ + for(i=n-1; i>=0; i--) + { + ex.ptr.p_complex[i+1] = ex.ptr.p_complex[i]; + } + } + + /* + * Compute the estimate of the reciprocal condition number. + */ + if( ae_fp_neq(ainvnm,(double)(0)) ) + { + *rc = (double)1/ainvnm; + *rc = *rc/anorm; + if( ae_fp_less(*rc,rcondthreshold(_state)) ) + { + *rc = (double)(0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine for matrix norm estimation + + -- LAPACK auxiliary routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992 +*************************************************************************/ +static void rcond_rmatrixestimatenorm(ae_int_t n, + /* Real */ ae_vector* v, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* isgn, + double* est, + ae_int_t* kase, + ae_state *_state) +{ + ae_int_t itmax; + ae_int_t i; + double t; + ae_bool flg; + ae_int_t positer; + ae_int_t posj; + ae_int_t posjlast; + ae_int_t posjump; + ae_int_t posaltsgn; + ae_int_t posestold; + ae_int_t postemp; + + + itmax = 5; + posaltsgn = n+1; + posestold = n+2; + postemp = n+3; + positer = n+1; + posj = n+2; + posjlast = n+3; + posjump = n+4; + if( *kase==0 ) + { + ae_vector_set_length(v, n+4, _state); + ae_vector_set_length(x, n+1, _state); + ae_vector_set_length(isgn, n+5, _state); + t = (double)1/(double)n; + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = t; + } + *kase = 1; + isgn->ptr.p_int[posjump] = 1; + return; + } + + /* + * ................ ENTRY (JUMP = 1) + * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. + */ + if( isgn->ptr.p_int[posjump]==1 ) + { + if( n==1 ) + { + v->ptr.p_double[1] = x->ptr.p_double[1]; + *est = ae_fabs(v->ptr.p_double[1], _state); + *kase = 0; + return; + } + *est = (double)(0); + for(i=1; i<=n; i++) + { + *est = *est+ae_fabs(x->ptr.p_double[i], _state); + } + for(i=1; i<=n; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)) ) + { + x->ptr.p_double[i] = (double)(1); + } + else + { + x->ptr.p_double[i] = (double)(-1); + } + isgn->ptr.p_int[i] = ae_sign(x->ptr.p_double[i], _state); + } + *kase = 2; + isgn->ptr.p_int[posjump] = 2; + return; + } + + /* + * ................ ENTRY (JUMP = 2) + * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. + */ + if( isgn->ptr.p_int[posjump]==2 ) + { + isgn->ptr.p_int[posj] = 1; + for(i=2; i<=n; i++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) + { + isgn->ptr.p_int[posj] = i; + } + } + isgn->ptr.p_int[positer] = 2; + + /* + * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. + */ + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = (double)(0); + } + x->ptr.p_double[isgn->ptr.p_int[posj]] = (double)(1); + *kase = 1; + isgn->ptr.p_int[posjump] = 3; + return; + } + + /* + * ................ ENTRY (JUMP = 3) + * X HAS BEEN OVERWRITTEN BY A*X. + */ + if( isgn->ptr.p_int[posjump]==3 ) + { + ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); + v->ptr.p_double[posestold] = *est; + *est = (double)(0); + for(i=1; i<=n; i++) + { + *est = *est+ae_fabs(v->ptr.p_double[i], _state); + } + flg = ae_false; + for(i=1; i<=n; i++) + { + if( (ae_fp_greater_eq(x->ptr.p_double[i],(double)(0))&&isgn->ptr.p_int[i]<0)||(ae_fp_less(x->ptr.p_double[i],(double)(0))&&isgn->ptr.p_int[i]>=0) ) + { + flg = ae_true; + } + } + + /* + * REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. + * OR MAY BE CYCLING. + */ + if( !flg||ae_fp_less_eq(*est,v->ptr.p_double[posestold]) ) + { + v->ptr.p_double[posaltsgn] = (double)(1); + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*((double)1+(double)(i-1)/(double)(n-1)); + v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; + } + *kase = 1; + isgn->ptr.p_int[posjump] = 5; + return; + } + for(i=1; i<=n; i++) + { + if( ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)) ) + { + x->ptr.p_double[i] = (double)(1); + isgn->ptr.p_int[i] = 1; + } + else + { + x->ptr.p_double[i] = (double)(-1); + isgn->ptr.p_int[i] = -1; + } + } + *kase = 2; + isgn->ptr.p_int[posjump] = 4; + return; + } + + /* + * ................ ENTRY (JUMP = 4) + * X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. + */ + if( isgn->ptr.p_int[posjump]==4 ) + { + isgn->ptr.p_int[posjlast] = isgn->ptr.p_int[posj]; + isgn->ptr.p_int[posj] = 1; + for(i=2; i<=n; i++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state)) ) + { + isgn->ptr.p_int[posj] = i; + } + } + if( ae_fp_neq(x->ptr.p_double[isgn->ptr.p_int[posjlast]],ae_fabs(x->ptr.p_double[isgn->ptr.p_int[posj]], _state))&&isgn->ptr.p_int[positer]ptr.p_int[positer] = isgn->ptr.p_int[positer]+1; + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = (double)(0); + } + x->ptr.p_double[isgn->ptr.p_int[posj]] = (double)(1); + *kase = 1; + isgn->ptr.p_int[posjump] = 3; + return; + } + + /* + * ITERATION COMPLETE. FINAL STAGE. + */ + v->ptr.p_double[posaltsgn] = (double)(1); + for(i=1; i<=n; i++) + { + x->ptr.p_double[i] = v->ptr.p_double[posaltsgn]*((double)1+(double)(i-1)/(double)(n-1)); + v->ptr.p_double[posaltsgn] = -v->ptr.p_double[posaltsgn]; + } + *kase = 1; + isgn->ptr.p_int[posjump] = 5; + return; + } + + /* + * ................ ENTRY (JUMP = 5) + * X HAS BEEN OVERWRITTEN BY A*X. + */ + if( isgn->ptr.p_int[posjump]==5 ) + { + v->ptr.p_double[postemp] = (double)(0); + for(i=1; i<=n; i++) + { + v->ptr.p_double[postemp] = v->ptr.p_double[postemp]+ae_fabs(x->ptr.p_double[i], _state); + } + v->ptr.p_double[postemp] = (double)2*v->ptr.p_double[postemp]/(double)(3*n); + if( ae_fp_greater(v->ptr.p_double[postemp],*est) ) + { + ae_v_move(&v->ptr.p_double[1], 1, &x->ptr.p_double[1], 1, ae_v_len(1,n)); + *est = v->ptr.p_double[postemp]; + } + *kase = 0; + return; + } +} + + +static void rcond_cmatrixestimatenorm(ae_int_t n, + /* Complex */ ae_vector* v, + /* Complex */ ae_vector* x, + double* est, + ae_int_t* kase, + /* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_state *_state) +{ + ae_int_t itmax; + ae_int_t i; + ae_int_t iter; + ae_int_t j; + ae_int_t jlast; + ae_int_t jump; + double absxi; + double altsgn; + double estold; + double safmin; + double temp; + + + + /* + *Executable Statements .. + */ + itmax = 5; + safmin = ae_minrealnumber; + if( *kase==0 ) + { + ae_vector_set_length(v, n+1, _state); + ae_vector_set_length(x, n+1, _state); + ae_vector_set_length(isave, 5, _state); + ae_vector_set_length(rsave, 4, _state); + for(i=1; i<=n; i++) + { + x->ptr.p_complex[i] = ae_complex_from_d((double)1/(double)n); + } + *kase = 1; + jump = 1; + iter = -999999; + j = -999999; + jlast = -999999; + absxi = -888888.0; + altsgn = -888888.0; + estold = -888888.0; + temp = -888888.0; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + rcond_internalcomplexrcondloadall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + + /* + * ENTRY (JUMP = 1) + * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. + */ + if( jump==1 ) + { + if( n==1 ) + { + v->ptr.p_complex[1] = x->ptr.p_complex[1]; + *est = ae_c_abs(v->ptr.p_complex[1], _state); + *kase = 0; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + *est = rcond_internalcomplexrcondscsum1(x, n, _state); + for(i=1; i<=n; i++) + { + absxi = ae_c_abs(x->ptr.p_complex[i], _state); + if( ae_fp_greater(absxi,safmin) ) + { + x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); + } + else + { + x->ptr.p_complex[i] = ae_complex_from_i(1); + } + } + *kase = 2; + jump = 2; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + + /* + * ENTRY (JUMP = 2) + * FIRST ITERATION. X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. + */ + if( jump==2 ) + { + j = rcond_internalcomplexrcondicmax1(x, n, _state); + iter = 2; + + /* + * MAIN LOOP - ITERATIONS 2,3,...,ITMAX. + */ + for(i=1; i<=n; i++) + { + x->ptr.p_complex[i] = ae_complex_from_i(0); + } + x->ptr.p_complex[j] = ae_complex_from_i(1); + *kase = 1; + jump = 3; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + + /* + * ENTRY (JUMP = 3) + * X HAS BEEN OVERWRITTEN BY A*X. + */ + if( jump==3 ) + { + ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); + estold = *est; + *est = rcond_internalcomplexrcondscsum1(v, n, _state); + + /* + * TEST FOR CYCLING. + */ + if( ae_fp_less_eq(*est,estold) ) + { + + /* + * ITERATION COMPLETE. FINAL STAGE. + */ + altsgn = (double)(1); + for(i=1; i<=n; i++) + { + x->ptr.p_complex[i] = ae_complex_from_d(altsgn*((double)1+(double)(i-1)/(double)(n-1))); + altsgn = -altsgn; + } + *kase = 1; + jump = 5; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + for(i=1; i<=n; i++) + { + absxi = ae_c_abs(x->ptr.p_complex[i], _state); + if( ae_fp_greater(absxi,safmin) ) + { + x->ptr.p_complex[i] = ae_c_div_d(x->ptr.p_complex[i],absxi); + } + else + { + x->ptr.p_complex[i] = ae_complex_from_i(1); + } + } + *kase = 2; + jump = 4; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + + /* + * ENTRY (JUMP = 4) + * X HAS BEEN OVERWRITTEN BY CTRANS(A)*X. + */ + if( jump==4 ) + { + jlast = j; + j = rcond_internalcomplexrcondicmax1(x, n, _state); + if( ae_fp_neq(ae_c_abs(x->ptr.p_complex[jlast], _state),ae_c_abs(x->ptr.p_complex[j], _state))&&iterptr.p_complex[i] = ae_complex_from_i(0); + } + x->ptr.p_complex[j] = ae_complex_from_i(1); + *kase = 1; + jump = 3; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + + /* + * ITERATION COMPLETE. FINAL STAGE. + */ + altsgn = (double)(1); + for(i=1; i<=n; i++) + { + x->ptr.p_complex[i] = ae_complex_from_d(altsgn*((double)1+(double)(i-1)/(double)(n-1))); + altsgn = -altsgn; + } + *kase = 1; + jump = 5; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } + + /* + * ENTRY (JUMP = 5) + * X HAS BEEN OVERWRITTEN BY A*X. + */ + if( jump==5 ) + { + temp = (double)2*(rcond_internalcomplexrcondscsum1(x, n, _state)/(double)(3*n)); + if( ae_fp_greater(temp,*est) ) + { + ae_v_cmove(&v->ptr.p_complex[1], 1, &x->ptr.p_complex[1], 1, "N", ae_v_len(1,n)); + *est = temp; + } + *kase = 0; + rcond_internalcomplexrcondsaveall(isave, rsave, &i, &iter, &j, &jlast, &jump, &absxi, &altsgn, &estold, &temp, _state); + return; + } +} + + +static double rcond_internalcomplexrcondscsum1(/* Complex */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=1; i<=n; i++) + { + result = result+ae_c_abs(x->ptr.p_complex[i], _state); + } + return result; +} + + +static ae_int_t rcond_internalcomplexrcondicmax1(/* Complex */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double m; + ae_int_t result; + + + result = 1; + m = ae_c_abs(x->ptr.p_complex[1], _state); + for(i=2; i<=n; i++) + { + if( ae_fp_greater(ae_c_abs(x->ptr.p_complex[i], _state),m) ) + { + result = i; + m = ae_c_abs(x->ptr.p_complex[i], _state); + } + } + return result; +} + + +static void rcond_internalcomplexrcondsaveall(/* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_int_t* i, + ae_int_t* iter, + ae_int_t* j, + ae_int_t* jlast, + ae_int_t* jump, + double* absxi, + double* altsgn, + double* estold, + double* temp, + ae_state *_state) +{ + + + isave->ptr.p_int[0] = *i; + isave->ptr.p_int[1] = *iter; + isave->ptr.p_int[2] = *j; + isave->ptr.p_int[3] = *jlast; + isave->ptr.p_int[4] = *jump; + rsave->ptr.p_double[0] = *absxi; + rsave->ptr.p_double[1] = *altsgn; + rsave->ptr.p_double[2] = *estold; + rsave->ptr.p_double[3] = *temp; +} + + +static void rcond_internalcomplexrcondloadall(/* Integer */ ae_vector* isave, + /* Real */ ae_vector* rsave, + ae_int_t* i, + ae_int_t* iter, + ae_int_t* j, + ae_int_t* jlast, + ae_int_t* jump, + double* absxi, + double* altsgn, + double* estold, + double* temp, + ae_state *_state) +{ + + + *i = isave->ptr.p_int[0]; + *iter = isave->ptr.p_int[1]; + *j = isave->ptr.p_int[2]; + *jlast = isave->ptr.p_int[3]; + *jump = isave->ptr.p_int[4]; + *absxi = rsave->ptr.p_double[0]; + *altsgn = rsave->ptr.p_double[1]; + *estold = rsave->ptr.p_double[2]; + *temp = rsave->ptr.p_double[3]; +} + + +#endif +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. + +This subroutine assumes that: +* A*ScaleA is well scaled +* A is well-conditioned, so no zero divisions or overflow may occur + +INPUT PARAMETERS: + CHA - Cholesky decomposition of A + SqrtScaleA- square root of scale factor ScaleA + N - matrix size, N>=0. + IsUpper - storage type + XB - right part + Tmp - buffer; function automatically allocates it, if it is too + small. It can be reused if function is called several + times. + +OUTPUT PARAMETERS: + XB - solution + +NOTE 1: no assertion or tests are done during algorithm operation +NOTE 2: N=0 will force algorithm to silently return + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void fblscholeskysolve(/* Real */ const ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + double v; + + + if( n<=0 ) + { + return; + } + if( tmp->cntptr.p_double[0], 1, ae_v_len(0,n-1), v); + + /* + * Solve A = L*L' or A=U'*U + */ + if( isupper ) + { + + /* + * Solve U'*y=b first. + */ + rmatrixtrsv(n, cha, 0, 0, ae_true, ae_false, 1, xb, 0, _state); + + /* + * Solve U*x=y then. + */ + rmatrixtrsv(n, cha, 0, 0, ae_true, ae_false, 0, xb, 0, _state); + } + else + { + + /* + * Solve L*y=b first + */ + rmatrixtrsv(n, cha, 0, 0, ae_false, ae_false, 0, xb, 0, _state); + + /* + * Solve L'*x=y then. + */ + rmatrixtrsv(n, cha, 0, 0, ae_false, ae_false, 1, xb, 0, _state); + } +} + + +/************************************************************************* +Fast basic linear solver: linear SPD CG + +Solves (A^T*A + alpha*I)*x = b where: +* A is MxN matrix +* alpha>0 is a scalar +* I is NxN identity matrix +* b is Nx1 vector +* X is Nx1 unknown vector. + +N iterations of linear conjugate gradient are used to solve problem. + +INPUT PARAMETERS: + A - array[M,N], matrix + M - number of rows + N - number of unknowns + B - array[N], right part + X - initial approxumation, array[N] + Buf - buffer; function automatically allocates it, if it is too + small. It can be reused if function is called several times + with same M and N. + +OUTPUT PARAMETERS: + X - improved solution + +NOTES: +* solver checks quality of improved solution. If (because of problem + condition number, numerical noise, etc.) new solution is WORSE than + original approximation, then original approximation is returned. +* solver assumes that both A, B, Alpha are well scaled (i.e. they are + less than sqrt(overflow) and greater than sqrt(underflow)). + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void fblssolvecgx(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + /* Real */ ae_vector* buf, + ae_state *_state) +{ + ae_int_t k; + ae_int_t offsrk; + ae_int_t offsrk1; + ae_int_t offsxk; + ae_int_t offsxk1; + ae_int_t offspk; + ae_int_t offspk1; + ae_int_t offstmp1; + ae_int_t offstmp2; + ae_int_t bs; + double e1; + double e2; + double rk2; + double rk12; + double pap; + double s; + double betak; + double v1; + double v2; + + + + /* + * Test for special case: B=0 + */ + v1 = ae_v_dotproduct(&b->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_eq(v1,(double)(0)) ) + { + for(k=0; k<=n-1; k++) + { + x->ptr.p_double[k] = (double)(0); + } + return; + } + + /* + * Offsets inside Buf for: + * * R[K], R[K+1] + * * X[K], X[K+1] + * * P[K], P[K+1] + * * Tmp1 - array[M], Tmp2 - array[N] + */ + offsrk = 0; + offsrk1 = offsrk+n; + offsxk = offsrk1+n; + offsxk1 = offsxk+n; + offspk = offsxk1+n; + offspk1 = offspk+n; + offstmp1 = offspk1+n; + offstmp2 = offstmp1+m; + bs = offstmp2+n; + if( buf->cntptr.p_double[offsxk], 1, &x->ptr.p_double[0], 1, ae_v_len(offsxk,offsxk+n-1)); + + /* + * r(0) = b-A*x(0) + * RK2 = r(0)'*r(0) + */ + rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); + rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); + ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); + ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); + ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); + rk2 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); + ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offspk,offspk+n-1)); + e1 = ae_sqrt(rk2, _state); + + /* + * Cycle + */ + for(k=0; k<=n-1; k++) + { + + /* + * Calculate A*p(k) - store in Buf[OffsTmp2:OffsTmp2+N-1] + * and p(k)'*A*p(k) - store in PAP + * + * If PAP=0, break (iteration is over) + */ + rmatrixmv(m, n, a, 0, 0, 0, buf, offspk, buf, offstmp1, _state); + v1 = ae_v_dotproduct(&buf->ptr.p_double[offstmp1], 1, &buf->ptr.p_double[offstmp1], 1, ae_v_len(offstmp1,offstmp1+m-1)); + v2 = ae_v_dotproduct(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk,offspk+n-1)); + pap = v1+alpha*v2; + rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); + ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); + if( ae_fp_eq(pap,(double)(0)) ) + { + break; + } + + /* + * S = (r(k)'*r(k))/(p(k)'*A*p(k)) + */ + s = rk2/pap; + + /* + * x(k+1) = x(k) + S*p(k) + */ + ae_v_move(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offsxk1,offsxk1+n-1)); + ae_v_addd(&buf->ptr.p_double[offsxk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offsxk1,offsxk1+n-1), s); + + /* + * r(k+1) = r(k) - S*A*p(k) + * RK12 = r(k+1)'*r(k+1) + * + * Break if r(k+1) small enough (when compared to r(k)) + */ + ae_v_move(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk1,offsrk1+n-1)); + ae_v_subd(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk1,offsrk1+n-1), s); + rk12 = ae_v_dotproduct(&buf->ptr.p_double[offsrk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk1,offsrk1+n-1)); + if( ae_fp_less_eq(ae_sqrt(rk12, _state),(double)100*ae_machineepsilon*ae_sqrt(rk2, _state)) ) + { + + /* + * X(k) = x(k+1) before exit - + * - because we expect to find solution at x(k) + */ + ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); + break; + } + + /* + * BetaK = RK12/RK2 + * p(k+1) = r(k+1)+betak*p(k) + */ + betak = rk12/rk2; + ae_v_move(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offspk1,offspk1+n-1)); + ae_v_addd(&buf->ptr.p_double[offspk1], 1, &buf->ptr.p_double[offspk], 1, ae_v_len(offspk1,offspk1+n-1), betak); + + /* + * r(k) := r(k+1) + * x(k) := x(k+1) + * p(k) := p(k+1) + */ + ae_v_move(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk1], 1, ae_v_len(offsrk,offsrk+n-1)); + ae_v_move(&buf->ptr.p_double[offsxk], 1, &buf->ptr.p_double[offsxk1], 1, ae_v_len(offsxk,offsxk+n-1)); + ae_v_move(&buf->ptr.p_double[offspk], 1, &buf->ptr.p_double[offspk1], 1, ae_v_len(offspk,offspk+n-1)); + rk2 = rk12; + } + + /* + * Calculate E2 + */ + rmatrixmv(m, n, a, 0, 0, 0, buf, offsxk, buf, offstmp1, _state); + rmatrixmv(n, m, a, 0, 0, 1, buf, offstmp1, buf, offstmp2, _state); + ae_v_addd(&buf->ptr.p_double[offstmp2], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(offstmp2,offstmp2+n-1), alpha); + ae_v_move(&buf->ptr.p_double[offsrk], 1, &b->ptr.p_double[0], 1, ae_v_len(offsrk,offsrk+n-1)); + ae_v_sub(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offstmp2], 1, ae_v_len(offsrk,offsrk+n-1)); + v1 = ae_v_dotproduct(&buf->ptr.p_double[offsrk], 1, &buf->ptr.p_double[offsrk], 1, ae_v_len(offsrk,offsrk+n-1)); + e2 = ae_sqrt(v1, _state); + + /* + * Output result (if it was improved) + */ + if( ae_fp_less(e2,e1) ) + { + ae_v_move(&x->ptr.p_double[0], 1, &buf->ptr.p_double[offsxk], 1, ae_v_len(0,n-1)); + } +} + + +/************************************************************************* +Construction of linear conjugate gradient solver. + +State parameter passed using "shared" semantics (i.e. previous state is NOT +erased). When it is already initialized, we can reause prevously allocated +memory. + +INPUT PARAMETERS: + X - initial solution + B - right part + N - system size + State - structure; may be preallocated, if we want to reuse memory + +OUTPUT PARAMETERS: + State - structure which is used by FBLSCGIteration() to store + algorithm state between subsequent calls. + +NOTE: no error checking is done; caller must check all parameters, prevent + overflows, and so on. + + -- ALGLIB -- + Copyright 22.10.2009 by Bochkanov Sergey +*************************************************************************/ +void fblscgcreate(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* b, + ae_int_t n, + fblslincgstate* state, + ae_state *_state) +{ + + + if( state->b.cntb, n, _state); + } + if( state->rk.cntrk, n, _state); + } + if( state->rk1.cntrk1, n, _state); + } + if( state->xk.cntxk, n, _state); + } + if( state->xk1.cntxk1, n, _state); + } + if( state->pk.cntpk, n, _state); + } + if( state->pk1.cntpk1, n, _state); + } + if( state->tmp2.cnttmp2, n, _state); + } + if( state->x.cntx, n, _state); + } + if( state->ax.cntax, n, _state); + } + state->n = n; + ae_v_move(&state->xk.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_vector_set_length(&state->rstate.ia, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 6+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Linear CG solver, function relying on reverse communication to calculate +matrix-vector products. + +See comments for FBLSLinCGState structure for more info. + + -- ALGLIB -- + Copyright 22.10.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + double rk2; + double rk12; + double pap; + double s; + double betak; + double v1; + double v2; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + k = state->rstate.ia.ptr.p_int[1]; + rk2 = state->rstate.ra.ptr.p_double[0]; + rk12 = state->rstate.ra.ptr.p_double[1]; + pap = state->rstate.ra.ptr.p_double[2]; + s = state->rstate.ra.ptr.p_double[3]; + betak = state->rstate.ra.ptr.p_double[4]; + v1 = state->rstate.ra.ptr.p_double[5]; + v2 = state->rstate.ra.ptr.p_double[6]; + } + else + { + n = 359; + k = -58; + rk2 = -919.0; + rk12 = -909.0; + pap = 81.0; + s = 255.0; + betak = 74.0; + v1 = -788.0; + v2 = 809.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + + /* + * prepare locals + */ + n = state->n; + + /* + * Test for special case: B=0 + */ + v1 = ae_v_dotproduct(&state->b.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_eq(v1,(double)(0)) ) + { + for(k=0; k<=n-1; k++) + { + state->xk.ptr.p_double[k] = (double)(0); + } + result = ae_false; + return result; + } + + /* + * r(0) = b-A*x(0) + * RK2 = r(0)'*r(0) + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); + rk2 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->pk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->e1 = ae_sqrt(rk2, _state); + + /* + * Cycle + */ + k = 0; +lbl_3: + if( k>n-1 ) + { + goto lbl_5; + } + + /* + * Calculate A*p(k) - store in State.Tmp2 + * and p(k)'*A*p(k) - store in PAP + * + * If PAP=0, break (iteration is over) + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + ae_v_move(&state->tmp2.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); + pap = state->xax; + if( !ae_isfinite(pap, _state) ) + { + goto lbl_5; + } + if( ae_fp_less_eq(pap,(double)(0)) ) + { + goto lbl_5; + } + + /* + * S = (r(k)'*r(k))/(p(k)'*A*p(k)) + */ + s = rk2/pap; + + /* + * x(k+1) = x(k) + S*p(k) + */ + ae_v_move(&state->xk1.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->xk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), s); + + /* + * r(k+1) = r(k) - S*A*p(k) + * RK12 = r(k+1)'*r(k+1) + * + * Break if r(k+1) small enough (when compared to r(k)) + */ + ae_v_move(&state->rk1.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_subd(&state->rk1.ptr.p_double[0], 1, &state->tmp2.ptr.p_double[0], 1, ae_v_len(0,n-1), s); + rk12 = ae_v_dotproduct(&state->rk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_less_eq(ae_sqrt(rk12, _state),(double)100*ae_machineepsilon*state->e1) ) + { + + /* + * X(k) = x(k+1) before exit - + * - because we expect to find solution at x(k) + */ + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + goto lbl_5; + } + + /* + * BetaK = RK12/RK2 + * p(k+1) = r(k+1)+betak*p(k) + * + * NOTE: we expect that BetaK won't overflow because of + * "Sqrt(RK12)<=100*MachineEpsilon*E1" test above. + */ + betak = rk12/rk2; + ae_v_move(&state->pk1.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->pk1.ptr.p_double[0], 1, &state->pk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); + + /* + * r(k) := r(k+1) + * x(k) := x(k+1) + * p(k) := p(k+1) + */ + ae_v_move(&state->rk.ptr.p_double[0], 1, &state->rk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->pk.ptr.p_double[0], 1, &state->pk1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + rk2 = rk12; + k = k+1; + goto lbl_3; +lbl_5: + + /* + * Calculate E2 + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + ae_v_move(&state->rk.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_sub(&state->rk.ptr.p_double[0], 1, &state->ax.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v1 = ae_v_dotproduct(&state->rk.ptr.p_double[0], 1, &state->rk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->e2 = ae_sqrt(v1, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = k; + state->rstate.ra.ptr.p_double[0] = rk2; + state->rstate.ra.ptr.p_double[1] = rk12; + state->rstate.ra.ptr.p_double[2] = pap; + state->rstate.ra.ptr.p_double[3] = s; + state->rstate.ra.ptr.p_double[4] = betak; + state->rstate.ra.ptr.p_double[5] = v1; + state->rstate.ra.ptr.p_double[6] = v2; + return result; +} + + +/************************************************************************* +Construction of GMRES(k) solver. + +State parameter passed using "shared" semantics (i.e. previous state is NOT +erased). When it is already initialized, we can reause prevously allocated +memory. + +After (but not before!) initialization you can tweak following fields (they +are initialized by default values, but you can change it): +* State.EpsOrt - stop if norm of new candidate for orthogonalization is below EpsOrt +* State.EpsRes - stop of residual decreased below EpsRes*|B| +* State.EpsRed - stop if relative reduction of residual |R(k+1)|/|R(k)|>EpsRed + +INPUT PARAMETERS: + B - right part + N - system size + K - iterations count, K>=1 + State - structure; may be preallocated, if we want to reuse memory + +OUTPUT PARAMETERS: + State - structure which is used by FBLSGMRESIteration() to store + algorithm state between subsequent calls. + +NOTE: no error checking is done; caller must check all parameters, prevent + overflows, and so on. + + -- ALGLIB -- + Copyright 18.11.2020 by Bochkanov Sergey +*************************************************************************/ +void fblsgmrescreate(/* Real */ const ae_vector* b, + ae_int_t n, + ae_int_t k, + fblsgmresstate* state, + ae_state *_state) +{ + + + ae_assert((n>0&&k>0)&&k<=n, "FBLSGMRESCreate: incorrect params", _state); + state->n = n; + state->itscnt = k; + state->epsort = ((double)1000+ae_sqrt((double)(n), _state))*ae_machineepsilon; + state->epsres = ((double)1000+ae_sqrt((double)(n), _state))*ae_machineepsilon; + state->epsred = 1.0; + state->epsdiag = (double)(10000+n)*ae_machineepsilon; + state->itsperformed = 0; + state->retcode = 0; + rcopyallocv(n, b, &state->b, _state); + rallocv(n, &state->x, _state); + rallocv(n, &state->ax, _state); + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ra, 10+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Linear CG solver, function relying on reverse communication to calculate +matrix-vector products. + +See comments for FBLSLinCGState structure for more info. + + -- ALGLIB -- + Copyright 22.10.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool fblsgmresiteration(fblsgmresstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t itidx; + ae_int_t kdim; + double rmax; + double rmindiag; + double cs; + double sn; + double v; + double vv; + double anrm; + double qnrm; + double bnrm; + double resnrm; + double prevresnrm; + ae_int_t i; + ae_int_t j; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + itidx = state->rstate.ia.ptr.p_int[1]; + kdim = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + j = state->rstate.ia.ptr.p_int[4]; + rmax = state->rstate.ra.ptr.p_double[0]; + rmindiag = state->rstate.ra.ptr.p_double[1]; + cs = state->rstate.ra.ptr.p_double[2]; + sn = state->rstate.ra.ptr.p_double[3]; + v = state->rstate.ra.ptr.p_double[4]; + vv = state->rstate.ra.ptr.p_double[5]; + anrm = state->rstate.ra.ptr.p_double[6]; + qnrm = state->rstate.ra.ptr.p_double[7]; + bnrm = state->rstate.ra.ptr.p_double[8]; + resnrm = state->rstate.ra.ptr.p_double[9]; + prevresnrm = state->rstate.ra.ptr.p_double[10]; + } + else + { + n = 205; + itidx = -838; + kdim = 939; + i = -526; + j = 763; + rmax = -541.0; + rmindiag = -698.0; + cs = -900.0; + sn = -318.0; + v = -940.0; + vv = 1016.0; + anrm = -229.0; + qnrm = -536.0; + bnrm = 487.0; + resnrm = -115.0; + prevresnrm = 886.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + n = state->n; + state->retcode = 1; + + /* + * Set up Q0 + */ + rsetallocv(n, 0.0, &state->xs, _state); + bnrm = ae_sqrt(rdotv2(n, &state->b, _state), _state); + if( ae_fp_eq(bnrm,(double)(0)) ) + { + state->reprelres = (double)(0); + result = ae_false; + return result; + } + rallocm(state->itscnt+1, n, &state->qi, _state); + rallocm(state->itscnt, n, &state->aqi, _state); + rcopymulvr(n, (double)1/bnrm, &state->b, &state->qi, 0, _state); + rsetallocm(state->itscnt+1, state->itscnt, 0.0, &state->h, _state); + rsetallocm(state->itscnt+1, state->itscnt, 0.0, &state->hr, _state); + rsetallocm(state->itscnt+1, state->itscnt+1, 0.0, &state->hq, _state); + for(i=0; i<=state->itscnt; i++) + { + state->hq.ptr.pp_double[i][i] = (double)(1); + } + rsetallocv(state->itscnt+1, 0.0, &state->hqb, _state); + state->hqb.ptr.p_double[0] = bnrm; + + /* + * Perform iteration + */ + resnrm = bnrm; + kdim = 0; + rmax = (double)(0); + rmindiag = 1.0E99; + rsetallocv(state->itscnt, 0.0, &state->ys, _state); + rallocv(ae_maxint(n, state->itscnt+2, _state), &state->tmp0, _state); + rallocv(ae_maxint(n, state->itscnt+2, _state), &state->tmp1, _state); + itidx = 0; +lbl_1: + if( itidx>state->itscnt-1 ) + { + goto lbl_3; + } + prevresnrm = resnrm; + state->reprelres = resnrm/bnrm; + + /* + * Compute A*Qi[ItIdx], then compute Qi[ItIdx+1] + */ + rcopyrv(n, &state->qi, itidx, &state->x, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + rcopyvr(n, &state->ax, &state->aqi, itidx, _state); + anrm = ae_sqrt(rdotv2(n, &state->ax, _state), _state); + if( ae_fp_eq(anrm,(double)(0)) ) + { + state->retcode = 2; + goto lbl_3; + } + rowwisegramschmidt(&state->qi, itidx+1, n, &state->ax, &state->tmp0, ae_true, _state); + rowwisegramschmidt(&state->qi, itidx+1, n, &state->ax, &state->tmp1, ae_true, _state); + raddvc(itidx+1, 1.0, &state->tmp0, &state->h, itidx, _state); + raddvc(itidx+1, 1.0, &state->tmp1, &state->h, itidx, _state); + qnrm = ae_sqrt(rdotv2(n, &state->ax, _state), _state); + state->h.ptr.pp_double[itidx+1][itidx] = qnrm; + rmulv(n, (double)1/coalesce(qnrm, (double)(1), _state), &state->ax, _state); + rcopyvr(n, &state->ax, &state->qi, itidx+1, _state); + + /* + * We have QR decomposition of H from the previous iteration: + * * (ItIdx+1)*(ItIdx+1) orthogonal HQ embedded into larger (ItIdx+2)*(ItIdx+2) identity matrix + * * (ItIdx+1)*ItIdx triangular HR embedded into larger (ItIdx+2)*(ItIdx+1) zero matrix + * + * We just have to update QR decomposition after one more column is added to H: + * * multiply this column by HQ to obtain (ItIdx+2)-dimensional vector X + * * generate rotation to nullify last element of X to obtain (ItIdx+1)-dimensional vector Y + * that is copied into (ItIdx+1)-th column of HR + * * apply same rotation to HQ + * * apply same rotation to HQB - current right-hand side + */ + rcopycv(itidx+2, &state->h, itidx, &state->tmp0, _state); + rmatrixgemv(itidx+2, itidx+2, 1.0, &state->hq, 0, 0, 0, &state->tmp0, 0, 0.0, &state->tmp1, 0, _state); + generaterotation(state->tmp1.ptr.p_double[itidx], state->tmp1.ptr.p_double[itidx+1], &cs, &sn, &v, _state); + state->tmp1.ptr.p_double[itidx] = v; + state->tmp1.ptr.p_double[itidx+1] = (double)(0); + rmax = ae_maxreal(rmax, rmaxabsv(itidx+2, &state->tmp1, _state), _state); + rmindiag = ae_minreal(rmindiag, ae_fabs(v, _state), _state); + if( ae_fp_less_eq(rmindiag,rmax*state->epsdiag) ) + { + state->retcode = 3; + goto lbl_3; + } + rcopyvc(itidx+2, &state->tmp1, &state->hr, itidx, _state); + for(j=0; j<=itidx+1; j++) + { + v = state->hq.ptr.pp_double[itidx+0][j]; + vv = state->hq.ptr.pp_double[itidx+1][j]; + state->hq.ptr.pp_double[itidx+0][j] = cs*v+sn*vv; + state->hq.ptr.pp_double[itidx+1][j] = -sn*v+cs*vv; + } + v = state->hqb.ptr.p_double[itidx+0]; + vv = state->hqb.ptr.p_double[itidx+1]; + state->hqb.ptr.p_double[itidx+0] = cs*v+sn*vv; + state->hqb.ptr.p_double[itidx+1] = -sn*v+cs*vv; + resnrm = ae_fabs(state->hqb.ptr.p_double[itidx+1], _state); + state->reprelres = resnrm/bnrm; + + /* + * Previous attempt to extend R was successful (no small diagonal elements). + * Increase Krylov subspace dimensionality. + */ + kdim = kdim+1; + + /* + * Iteration is over. + * Terminate if: + * * last Qi was nearly zero after orthogonalization. + * * sufficient decrease of residual + * * stagnation of residual + */ + state->itsperformed = state->itsperformed+1; + if( ae_fp_less_eq(qnrm,state->epsort*anrm)||ae_fp_eq(qnrm,(double)(0)) ) + { + state->retcode = 4; + goto lbl_3; + } + if( ae_fp_less_eq(resnrm,state->epsres*bnrm) ) + { + state->retcode = 5; + goto lbl_3; + } + if( ae_fp_greater(resnrm/prevresnrm,state->epsred) ) + { + state->retcode = 6; + goto lbl_3; + } + itidx = itidx+1; + goto lbl_1; +lbl_3: + + /* + * Post-solve + */ + if( kdim>0 ) + { + rcopyv(kdim, &state->hqb, &state->ys, _state); + rmatrixtrsv(kdim, &state->hr, 0, 0, ae_true, ae_false, 0, &state->ys, 0, _state); + rmatrixmv(n, kdim, &state->qi, 0, 0, 1, &state->ys, 0, &state->xs, 0, _state); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = itidx; + state->rstate.ia.ptr.p_int[2] = kdim; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = j; + state->rstate.ra.ptr.p_double[0] = rmax; + state->rstate.ra.ptr.p_double[1] = rmindiag; + state->rstate.ra.ptr.p_double[2] = cs; + state->rstate.ra.ptr.p_double[3] = sn; + state->rstate.ra.ptr.p_double[4] = v; + state->rstate.ra.ptr.p_double[5] = vv; + state->rstate.ra.ptr.p_double[6] = anrm; + state->rstate.ra.ptr.p_double[7] = qnrm; + state->rstate.ra.ptr.p_double[8] = bnrm; + state->rstate.ra.ptr.p_double[9] = resnrm; + state->rstate.ra.ptr.p_double[10] = prevresnrm; + return result; +} + + +/************************************************************************* +Fast least squares solver, solves well conditioned system without +performing any checks for degeneracy, and using user-provided buffers +(which are automatically reallocated if too small). + +This function is intended for solution of moderately sized systems. It +uses factorization algorithms based on Level 2 BLAS operations, thus it +won't work efficiently on large scale systems. + +INPUT PARAMETERS: + A - array[M,N], system matrix. + Contents of A is destroyed during solution. + B - array[M], right part + M - number of equations + N - number of variables, N<=M + Tmp0, Tmp1, Tmp2- + buffers; function automatically allocates them, if they are + too small. They can be reused if function is called + several times. + +OUTPUT PARAMETERS: + B - solution (first N components, next M-N are zero) + + -- ALGLIB -- + Copyright 20.01.2012 by Bochkanov Sergey +*************************************************************************/ +void fblssolvels(/* Real */ ae_matrix* a, + /* Real */ ae_vector* b, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + /* Real */ ae_vector* tmp2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double v; + + + ae_assert(n>0, "FBLSSolveLS: N<=0", _state); + ae_assert(m>=n, "FBLSSolveLS: Mrows>=m, "FBLSSolveLS: Rows(A)cols>=n, "FBLSSolveLS: Cols(A)cnt>=m, "FBLSSolveLS: Length(B)ptr.p_double[i] = (double)(0); + } + ae_v_move(&tmp0->ptr.p_double[k], 1, &a->ptr.pp_double[k][k], a->stride, ae_v_len(k,m-1)); + tmp0->ptr.p_double[k] = (double)(1); + v = ae_v_dotproduct(&tmp0->ptr.p_double[k], 1, &b->ptr.p_double[k], 1, ae_v_len(k,m-1)); + v = v*tmp2->ptr.p_double[k]; + ae_v_subd(&b->ptr.p_double[k], 1, &tmp0->ptr.p_double[k], 1, ae_v_len(k,m-1), v); + } + + /* + * Solve triangular system + */ + b->ptr.p_double[n-1] = b->ptr.p_double[n-1]/a->ptr.pp_double[n-1][n-1]; + for(i=n-2; i>=0; i--) + { + v = ae_v_dotproduct(&a->ptr.pp_double[i][i+1], 1, &b->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + b->ptr.p_double[i] = (b->ptr.p_double[i]-v)/a->ptr.pp_double[i][i]; + } + for(i=n; i<=m-1; i++) + { + b->ptr.p_double[i] = 0.0; + } +} + + +void _fblslincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + fblslincgstate *p = (fblslincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rk1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xk1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pk1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); +} + + +void _fblslincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + fblslincgstate *dst = (fblslincgstate*)_dst; + const fblslincgstate *src = (const fblslincgstate*)_src; + dst->e1 = src->e1; + dst->e2 = src->e2; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->ax, &src->ax, _state, make_automatic); + dst->xax = src->xax; + dst->n = src->n; + ae_vector_init_copy(&dst->rk, &src->rk, _state, make_automatic); + ae_vector_init_copy(&dst->rk1, &src->rk1, _state, make_automatic); + ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic); + ae_vector_init_copy(&dst->xk1, &src->xk1, _state, make_automatic); + ae_vector_init_copy(&dst->pk, &src->pk, _state, make_automatic); + ae_vector_init_copy(&dst->pk1, &src->pk1, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); +} + + +void _fblslincgstate_clear(void* _p) +{ + fblslincgstate *p = (fblslincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->ax); + ae_vector_clear(&p->rk); + ae_vector_clear(&p->rk1); + ae_vector_clear(&p->xk); + ae_vector_clear(&p->xk1); + ae_vector_clear(&p->pk); + ae_vector_clear(&p->pk1); + ae_vector_clear(&p->b); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->tmp2); +} + + +void _fblslincgstate_destroy(void* _p) +{ + fblslincgstate *p = (fblslincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->ax); + ae_vector_destroy(&p->rk); + ae_vector_destroy(&p->rk1); + ae_vector_destroy(&p->xk); + ae_vector_destroy(&p->xk1); + ae_vector_destroy(&p->pk); + ae_vector_destroy(&p->pk1); + ae_vector_destroy(&p->b); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->tmp2); +} + + +void _fblsgmresstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + fblsgmresstate *p = (fblsgmresstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->qi, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->aqi, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hr, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hqb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ys, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _fblsgmresstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + fblsgmresstate *dst = (fblsgmresstate*)_dst; + const fblsgmresstate *src = (const fblsgmresstate*)_src; + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->ax, &src->ax, _state, make_automatic); + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + ae_matrix_init_copy(&dst->qi, &src->qi, _state, make_automatic); + ae_matrix_init_copy(&dst->aqi, &src->aqi, _state, make_automatic); + ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic); + ae_matrix_init_copy(&dst->hq, &src->hq, _state, make_automatic); + ae_matrix_init_copy(&dst->hr, &src->hr, _state, make_automatic); + ae_vector_init_copy(&dst->hqb, &src->hqb, _state, make_automatic); + ae_vector_init_copy(&dst->ys, &src->ys, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + dst->n = src->n; + dst->itscnt = src->itscnt; + dst->epsort = src->epsort; + dst->epsres = src->epsres; + dst->epsred = src->epsred; + dst->epsdiag = src->epsdiag; + dst->itsperformed = src->itsperformed; + dst->retcode = src->retcode; + dst->reprelres = src->reprelres; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _fblsgmresstate_clear(void* _p) +{ + fblsgmresstate *p = (fblsgmresstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->b); + ae_vector_clear(&p->x); + ae_vector_clear(&p->ax); + ae_vector_clear(&p->xs); + ae_matrix_clear(&p->qi); + ae_matrix_clear(&p->aqi); + ae_matrix_clear(&p->h); + ae_matrix_clear(&p->hq); + ae_matrix_clear(&p->hr); + ae_vector_clear(&p->hqb); + ae_vector_clear(&p->ys); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + _rcommstate_clear(&p->rstate); +} + + +void _fblsgmresstate_destroy(void* _p) +{ + fblsgmresstate *p = (fblsgmresstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->ax); + ae_vector_destroy(&p->xs); + ae_matrix_destroy(&p->qi); + ae_matrix_destroy(&p->aqi); + ae_matrix_destroy(&p->h); + ae_matrix_destroy(&p->hq); + ae_matrix_destroy(&p->hr); + ae_vector_destroy(&p->hqb); + ae_vector_destroy(&p->ys); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This procedure initializes matrix norm estimator. + +USAGE: +1. User initializes algorithm state with NormEstimatorCreate() call +2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) +3. User calls NormEstimatorResults() to get solution. + +INPUT PARAMETERS: + M - number of rows in the matrix being estimated, M>0 + N - number of columns in the matrix being estimated, N>0 + NStart - number of random starting vectors + recommended value - at least 5. + NIts - number of iterations to do with best starting vector + recommended value - at least 5. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTE: this algorithm is effectively deterministic, i.e. it always returns +same result when repeatedly called for the same matrix. In fact, algorithm +uses randomized starting vectors, but internal random numbers generator +always generates same sequence of the random values (it is a feature, not +bug). + +Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorcreate(ae_int_t m, + ae_int_t n, + ae_int_t nstart, + ae_int_t nits, + normestimatorstate* state, + ae_state *_state) +{ + + _normestimatorstate_clear(state); + + ae_assert(m>0, "NormEstimatorCreate: M<=0", _state); + ae_assert(n>0, "NormEstimatorCreate: N<=0", _state); + ae_assert(nstart>0, "NormEstimatorCreate: NStart<=0", _state); + ae_assert(nits>0, "NormEstimatorCreate: NIts<=0", _state); + state->m = m; + state->n = n; + state->nstart = nstart; + state->nits = nits; + state->seedval = 11; + hqrndrandomize(&state->r, _state); + ae_vector_set_length(&state->x0, state->n, _state); + ae_vector_set_length(&state->t, state->m, _state); + ae_vector_set_length(&state->x1, state->n, _state); + ae_vector_set_length(&state->xbest, state->n, _state); + ae_vector_set_length(&state->x, ae_maxint(state->n, state->m, _state), _state); + ae_vector_set_length(&state->mv, state->m, _state); + ae_vector_set_length(&state->mtv, state->n, _state); + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function changes seed value used by algorithm. In some cases we need +deterministic processing, i.e. subsequent calls must return equal results, +in other cases we need non-deterministic algorithm which returns different +results for the same matrix on every pass. + +Setting zero seed will lead to non-deterministic algorithm, while non-zero +value will make our algorithm deterministic. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + SeedVal - seed value, >=0. Zero value = non-deterministic algo. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorsetseed(normestimatorstate* state, + ae_int_t seedval, + ae_state *_state) +{ + + + ae_assert(seedval>=0, "NormEstimatorSetSeed: SeedVal<0", _state); + state->seedval = seedval; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +ae_bool normestimatoriteration(normestimatorstate* state, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t itcnt; + double v; + double growth; + double bestgrowth; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + itcnt = state->rstate.ia.ptr.p_int[3]; + v = state->rstate.ra.ptr.p_double[0]; + growth = state->rstate.ra.ptr.p_double[1]; + bestgrowth = state->rstate.ra.ptr.p_double[2]; + } + else + { + n = 359; + m = -58; + i = -919; + itcnt = -909; + v = 81.0; + growth = 255.0; + bestgrowth = 74.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + if( state->seedval>0 ) + { + hqrndseed(state->seedval, state->seedval+2, &state->r, _state); + } + bestgrowth = (double)(0); + state->xbest.ptr.p_double[0] = (double)(1); + for(i=1; i<=n-1; i++) + { + state->xbest.ptr.p_double[i] = (double)(0); + } + itcnt = 0; +lbl_4: + if( itcnt>state->nstart-1 ) + { + goto lbl_6; + } + do + { + v = (double)(0); + for(i=0; i<=n-1; i++) + { + state->x0.ptr.p_double[i] = hqrndnormal(&state->r, _state); + v = v+ae_sqr(state->x0.ptr.p_double[i], _state); + } + } + while(ae_fp_eq(v,(double)(0))); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->needmv = ae_true; + state->needmtv = ae_false; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); + state->needmv = ae_false; + state->needmtv = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->x1.ptr.p_double[i], _state); + } + growth = ae_sqrt(ae_sqrt(v, _state), _state); + if( ae_fp_greater(growth,bestgrowth) ) + { + v = (double)1/ae_sqrt(v, _state); + ae_v_moved(&state->xbest.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + bestgrowth = growth; + } + itcnt = itcnt+1; + goto lbl_4; +lbl_6: + ae_v_move(&state->x0.ptr.p_double[0], 1, &state->xbest.ptr.p_double[0], 1, ae_v_len(0,n-1)); + itcnt = 0; +lbl_7: + if( itcnt>state->nits-1 ) + { + goto lbl_9; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->x0.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->needmv = ae_true; + state->needmtv = ae_false; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + ae_v_move(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,m-1)); + state->needmv = ae_false; + state->needmtv = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + ae_v_move(&state->x1.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->x1.ptr.p_double[i], _state); + } + state->repnorm = ae_sqrt(ae_sqrt(v, _state), _state); + if( ae_fp_neq(v,(double)(0)) ) + { + v = (double)1/ae_sqrt(v, _state); + ae_v_moved(&state->x0.ptr.p_double[0], 1, &state->x1.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + } + itcnt = itcnt+1; + goto lbl_7; +lbl_9: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = itcnt; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = growth; + state->rstate.ra.ptr.p_double[2] = bestgrowth; + return result; +} + + +/************************************************************************* +This function estimates norm of the sparse M*N matrix A. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + A - sparse M*N matrix, must be converted to CRS format + prior to calling this function. + +After this function is over you can call NormEstimatorResults() to get +estimate of the norm(A). + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorestimatesparse(normestimatorstate* state, + const sparsematrix* a, + ae_state *_state) +{ + + + normestimatorrestart(state, _state); + while(normestimatoriteration(state, _state)) + { + if( state->needmv ) + { + sparsemv(a, &state->x, &state->mv, _state); + continue; + } + if( state->needmtv ) + { + sparsemtv(a, &state->x, &state->mtv, _state); + continue; + } + } +} + + +/************************************************************************* +Matrix norm estimation results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + Nrm - estimate of the matrix norm, Nrm>=0 + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorresults(const normestimatorstate* state, + double* nrm, + ae_state *_state) +{ + + *nrm = 0.0; + + *nrm = state->repnorm; +} + + +/************************************************************************* +This function restarts estimator and prepares it for the next estimation +round. + +INPUT PARAMETERS: + State - algorithm state + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorrestart(normestimatorstate* state, ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +void _normestimatorstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + normestimatorstate *p = (normestimatorstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbest, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->r, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mtv, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _normestimatorstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + normestimatorstate *dst = (normestimatorstate*)_dst; + const normestimatorstate *src = (const normestimatorstate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->nstart = src->nstart; + dst->nits = src->nits; + dst->seedval = src->seedval; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->x1, &src->x1, _state, make_automatic); + ae_vector_init_copy(&dst->t, &src->t, _state, make_automatic); + ae_vector_init_copy(&dst->xbest, &src->xbest, _state, make_automatic); + _hqrndstate_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic); + ae_vector_init_copy(&dst->mtv, &src->mtv, _state, make_automatic); + dst->needmv = src->needmv; + dst->needmtv = src->needmtv; + dst->repnorm = src->repnorm; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _normestimatorstate_clear(void* _p) +{ + normestimatorstate *p = (normestimatorstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->x1); + ae_vector_clear(&p->t); + ae_vector_clear(&p->xbest); + _hqrndstate_clear(&p->r); + ae_vector_clear(&p->x); + ae_vector_clear(&p->mv); + ae_vector_clear(&p->mtv); + _rcommstate_clear(&p->rstate); +} + + +void _normestimatorstate_destroy(void* _p) +{ + normestimatorstate *p = (normestimatorstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->x1); + ae_vector_destroy(&p->t); + ae_vector_destroy(&p->xbest); + _hqrndstate_destroy(&p->r); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->mv); + ae_vector_destroy(&p->mtv); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of RMatrixLU subroutine). + Pivots - table of permutations + (the output of RMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixluinverse(/* Real */ ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + _matinvreport_clear(rep); + ae_vector_init(&work, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixLUInverse: N<=0!", _state); + ae_assert(a->cols>=n, "RMatrixLUInverse: cols(A)rows>=n, "RMatrixLUInverse: rows(A)cnt>=n, "RMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]<0 ) + { + ae_assert(ae_false, "RMatrixLUInverse: incorrect Pivots array!", _state); + } + } + + /* + * calculate condition numbers + */ + rep->terminationtype = 1; + rep->r1 = rmatrixlurcond1(a, n, _state); + rep->rinf = rmatrixlurcondinf(a, n, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + rep->terminationtype = -3; + rep->r1 = (double)(0); + rep->rinf = (double)(0); + ae_frame_leave(_state); + return; + } + + /* + * Call cache-oblivious code + */ + ae_vector_set_length(&work, n, _state); + matinv_rmatrixluinverserec(a, 0, n, &work, rep, _state); + + /* + * apply permutations + */ + for(i=0; i<=n-1; i++) + { + for(j=n-2; j>=0; j--) + { + k = pivots->ptr.p_int[j]; + v = a->ptr.pp_double[i][j]; + a->ptr.pp_double[i][j] = a->ptr.pp_double[i][k]; + a->ptr.pp_double[i][k] = v; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Inversion of a general matrix. + +INPUT PARAMETERS: + A - matrix. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinverse(/* Real */ ae_matrix* a, + ae_int_t n, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector pivots; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + _matinvreport_clear(rep); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "RMatrixInverse: N<=0!", _state); + ae_assert(a->cols>=n, "RMatrixInverse: cols(A)rows>=n, "RMatrixInverse: rows(A)0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixluinverse(/* Complex */ ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector work; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_complex v; + + ae_frame_make(_state, &_frame_block); + memset(&work, 0, sizeof(work)); + _matinvreport_clear(rep); + ae_vector_init(&work, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixLUInverse: N<=0!", _state); + ae_assert(a->cols>=n, "CMatrixLUInverse: cols(A)rows>=n, "CMatrixLUInverse: rows(A)cnt>=n, "CMatrixLUInverse: len(Pivots)ptr.p_int[i]>n-1||pivots->ptr.p_int[i]<0 ) + { + ae_assert(ae_false, "CMatrixLUInverse: incorrect Pivots array!", _state); + } + } + + /* + * calculate condition numbers + */ + rep->terminationtype = 1; + rep->r1 = cmatrixlurcond1(a, n, _state); + rep->rinf = cmatrixlurcondinf(a, n, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Call cache-oblivious code + */ + ae_vector_set_length(&work, n, _state); + matinv_cmatrixluinverserec(a, 0, n, &work, rep, _state); + + /* + * apply permutations + */ + for(i=0; i<=n-1; i++) + { + for(j=n-2; j>=0; j--) + { + k = pivots->ptr.p_int[j]; + v = a->ptr.pp_complex[i][j]; + a->ptr.pp_complex[i][j] = a->ptr.pp_complex[i][k]; + a->ptr.pp_complex[i][k] = v; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Inversion of a general matrix. + +Input parameters: + A - matrix + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +Output parameters: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void cmatrixinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector pivots; + + ae_frame_make(_state, &_frame_block); + memset(&pivots, 0, sizeof(pivots)); + _matinvreport_clear(rep); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "CRMatrixInverse: N<=0!", _state); + ae_assert(a->cols>=n, "CRMatrixInverse: cols(A)rows>=n, "CRMatrixInverse: rows(A)0, corresponding triangle + contains inverse matrix, the other triangle is not + modified. + * for rep.terminationtype<0, corresponding triangle is + zero-filled; the other triangle is not modified. + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + _matinvreport_clear(rep); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixCholeskyInverse: N<=0!", _state); + ae_assert(a->cols>=n, "SPDMatrixCholeskyInverse: cols(A)rows>=n, "SPDMatrixCholeskyInverse: rows(A)terminationtype = 1; + rep->r1 = spdmatrixcholeskyrcond(a, n, isupper, _state); + rep->rinf = rep->r1; + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Inverse + */ + ae_vector_set_length(&tmp, n, _state); + spdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Inversion of a symmetric positive definite matrix. + +Given an upper or lower triangle of a symmetric positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state) +{ + + _matinvreport_clear(rep); + + ae_assert(n>0, "SPDMatrixInverse: N<=0!", _state); + ae_assert(a->cols>=n, "SPDMatrixInverse: cols(A)rows>=n, "SPDMatrixInverse: rows(A)r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + if( !spdmatrixcholesky(a, n, isupper, _state) ) + { + return; + } + spdmatrixcholeskyinverse(a, n, isupper, rep, _state); +} + + +/************************************************************************* +Inversion of a Hermitian positive definite matrix which is given +by Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of HPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + _matinvreport_clear(rep); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "HPDMatrixCholeskyInverse: N<=0!", _state); + ae_assert(a->cols>=n, "HPDMatrixCholeskyInverse: cols(A)rows>=n, "HPDMatrixCholeskyInverse: rows(A)terminationtype = 1; + rep->r1 = hpdmatrixcholeskyrcond(a, n, isupper, _state); + rep->rinf = rep->r1; + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Inverse + */ + ae_vector_set_length(&tmp, n, _state); + matinv_hpdmatrixcholeskyinverserec(a, 0, n, isupper, &tmp, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Inversion of a Hermitian positive definite matrix. + +Given an upper or lower triangle of a Hermitian positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state) +{ + + _matinvreport_clear(rep); + + ae_assert(n>0, "HPDMatrixInverse: N<=0!", _state); + ae_assert(a->cols>=n, "HPDMatrixInverse: cols(A)rows>=n, "HPDMatrixInverse: rows(A)r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + if( !hpdmatrixcholesky(a, n, isupper, _state) ) + { + return; + } + hpdmatrixcholeskyinverse(a, n, isupper, rep, _state); +} + + +/************************************************************************* +Triangular matrix inverse (real) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixtrinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + _matinvreport_clear(rep); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixTRInverse: N<=0!", _state); + ae_assert(a->cols>=n, "RMatrixTRInverse: cols(A)rows>=n, "RMatrixTRInverse: rows(A)terminationtype = 1; + rep->r1 = rmatrixtrrcond1(a, n, isupper, isunit, _state); + rep->rinf = rmatrixtrrcondinf(a, n, isupper, isunit, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = (double)(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Invert + */ + ae_vector_set_length(&tmp, n, _state); + matinv_rmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Triangular matrix inverse (complex) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixtrinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + matinvreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector tmp; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + _matinvreport_clear(rep); + ae_vector_init(&tmp, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixTRInverse: N<=0!", _state); + ae_assert(a->cols>=n, "CMatrixTRInverse: cols(A)rows>=n, "CMatrixTRInverse: rows(A)terminationtype = 1; + rep->r1 = cmatrixtrrcond1(a, n, isupper, isunit, _state); + rep->rinf = cmatrixtrrcondinf(a, n, isupper, isunit, _state); + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * Invert + */ + ae_vector_set_length(&tmp, n, _state); + matinv_cmatrixtrinverserec(a, 0, n, isupper, isunit, &tmp, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Recursive subroutine for SPD inversion. + +NOTE: this function expects that matris is strictly positive-definite. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + if( n<1 ) + { + return; + } + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Base case + */ + if( n<=tsa ) + { + matinv_rmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, rep, _state); + ae_assert(rep->terminationtype>0, "SPDMatrixCholeskyInverseRec: integrity check failed", _state); + if( isupper ) + { + + /* + * Compute the product U * U'. + * NOTE: we never assume that diagonal of U is real + */ + for(i=0; i<=n-1; i++) + { + if( i==0 ) + { + + /* + * 1x1 matrix + */ + a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); + } + else + { + + /* + * (I+1)x(I+1) matrix, + * + * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) + * ( ) * ( ) = ( ) + * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) + * + * A11 is IxI, A22 is 1x1. + */ + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(0,i-1)); + for(j=0; j<=i-1; j++) + { + v = a->ptr.pp_double[offs+j][offs+i]; + ae_v_addd(&a->ptr.pp_double[offs+j][offs+j], 1, &tmp->ptr.p_double[j], 1, ae_v_len(offs+j,offs+i-1), v); + } + v = a->ptr.pp_double[offs+i][offs+i]; + ae_v_muld(&a->ptr.pp_double[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); + a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); + } + } + } + else + { + + /* + * Compute the product L' * L + * NOTE: we never assume that diagonal of L is real + */ + for(i=0; i<=n-1; i++) + { + if( i==0 ) + { + + /* + * 1x1 matrix + */ + a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); + } + else + { + + /* + * (I+1)x(I+1) matrix, + * + * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) + * ( ) * ( ) = ( ) + * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) + * + * A11 is IxI, A22 is 1x1. + */ + ae_v_move(&tmp->ptr.p_double[0], 1, &a->ptr.pp_double[offs+i][offs], 1, ae_v_len(0,i-1)); + for(j=0; j<=i-1; j++) + { + v = a->ptr.pp_double[offs+i][offs+j]; + ae_v_addd(&a->ptr.pp_double[offs+j][offs], 1, &tmp->ptr.p_double[0], 1, ae_v_len(offs,offs+j), v); + } + v = a->ptr.pp_double[offs+i][offs+i]; + ae_v_muld(&a->ptr.pp_double[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); + a->ptr.pp_double[offs+i][offs+i] = ae_sqr(a->ptr.pp_double[offs+i][offs+i], _state); + } + } + } + return; + } + + /* + * Recursive code: triangular factor inversion merged with + * UU' or L'L multiplication + */ + tiledsplit(n, tscur, &n1, &n2, _state); + + /* + * form off-diagonal block of trangular inverse + */ + if( isupper ) + { + for(i=0; i<=n1-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); + rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); + } + else + { + for(i=0; i<=n2-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); + rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); + } + + /* + * invert first diagonal block + */ + spdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, rep, _state); + + /* + * update first diagonal block with off-diagonal block, + * update off-diagonal block + */ + if( isupper ) + { + rmatrixsyrk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); + rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs, offs+n1, _state); + } + else + { + rmatrixsyrk(n1, n2, 1.0, a, offs+n1, offs, 1, 1.0, a, offs, offs, isupper, _state); + rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 1, a, offs+n1, offs, _state); + } + + /* + * invert second diagonal block + */ + spdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, rep, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Triangular matrix inversion, recursive subroutine + +NOTE: this function sets Rep.TermiantionType on failure, leaves it unchanged on success. + +NOTE: only Tmp[Offs:Offs+N-1] is modified, other entries of the temporary array are not modified + + -- ALGLIB -- + 05.02.2010, Bochkanov Sergey. + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992. +*************************************************************************/ +static void matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t n1; + ae_int_t n2; + ae_int_t mn; + ae_int_t i; + ae_int_t j; + double v; + double ajj; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + ae_assert(n>=1, "MATINV: integrity check 6755 failed", _state); + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Try to activate parallelism + */ + if( n>=2*tsb&&ae_fp_greater_eq(rmul3((double)(n), (double)(n), (double)(n), _state)*((double)1/(double)3),smpactivationlevel(_state)) ) + { + if( _trypexec_matinv_rmatrixtrinverserec(a,offs,n,isupper,isunit,tmp,rep, _state) ) + { + return; + } + } + + /* + * Base case + */ + if( n<=tsa ) + { + if( isupper ) + { + + /* + * Compute inverse of upper triangular matrix. + */ + for(j=0; j<=n-1; j++) + { + if( !isunit ) + { + if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],(double)(0)) ) + { + rep->terminationtype = -3; + return; + } + a->ptr.pp_double[offs+j][offs+j] = (double)1/a->ptr.pp_double[offs+j][offs+j]; + ajj = -a->ptr.pp_double[offs+j][offs+j]; + } + else + { + ajj = (double)(-1); + } + + /* + * Compute elements 1:j-1 of j-th column. + */ + if( j>0 ) + { + ae_v_move(&tmp->ptr.p_double[offs+0], 1, &a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1)); + for(i=0; i<=j-1; i++) + { + if( iptr.pp_double[offs+i][offs+i+1], 1, &tmp->ptr.p_double[offs+i+1], 1, ae_v_len(offs+i+1,offs+j-1)); + } + else + { + v = (double)(0); + } + if( !isunit ) + { + a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[offs+i]; + } + else + { + a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[offs+i]; + } + } + ae_v_muld(&a->ptr.pp_double[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); + } + } + } + else + { + + /* + * Compute inverse of lower triangular matrix. + */ + for(j=n-1; j>=0; j--) + { + if( !isunit ) + { + if( ae_fp_eq(a->ptr.pp_double[offs+j][offs+j],(double)(0)) ) + { + rep->terminationtype = -3; + return; + } + a->ptr.pp_double[offs+j][offs+j] = (double)1/a->ptr.pp_double[offs+j][offs+j]; + ajj = -a->ptr.pp_double[offs+j][offs+j]; + } + else + { + ajj = (double)(-1); + } + if( jptr.p_double[offs+j+1], 1, &a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1)); + for(i=j+1; i<=n-1; i++) + { + if( i>j+1 ) + { + v = ae_v_dotproduct(&a->ptr.pp_double[offs+i][offs+j+1], 1, &tmp->ptr.p_double[offs+j+1], 1, ae_v_len(offs+j+1,offs+i-1)); + } + else + { + v = (double)(0); + } + if( !isunit ) + { + a->ptr.pp_double[offs+i][offs+j] = v+a->ptr.pp_double[offs+i][offs+i]*tmp->ptr.p_double[offs+i]; + } + else + { + a->ptr.pp_double[offs+i][offs+j] = v+tmp->ptr.p_double[offs+i]; + } + } + ae_v_muld(&a->ptr.pp_double[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); + } + } + } + return; + } + + /* + * Recursive case + */ + tiledsplit(n, tscur, &n1, &n2, _state); + mn = imin2(n1, n2, _state); + touchint(&mn, _state); + if( n2>0 ) + { + if( isupper ) + { + for(i=0; i<=n1-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); + matinv_rmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, rep, _state); + rmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); + } + else + { + for(i=0; i<=n2-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); + matinv_rmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, rep, _state); + rmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); + } + } + matinv_rmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, rep, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_matinv_rmatrixtrinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Triangular matrix inversion, recursive subroutine. + +Rep.TerminationType is modified on failure, left unchanged on success. + + -- ALGLIB -- + 05.02.2010, Bochkanov Sergey. + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + February 29, 1992. +*************************************************************************/ +static void matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Complex */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t n1; + ae_int_t n2; + ae_int_t i; + ae_int_t j; + ae_complex v; + ae_complex ajj; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + ae_int_t mn; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Try to activate parallelism + */ + if( n>=2*tsb&&ae_fp_greater_eq(rmul3((double)(n), (double)(n), (double)(n), _state)*((double)4/(double)3),smpactivationlevel(_state)) ) + { + if( _trypexec_matinv_cmatrixtrinverserec(a,offs,n,isupper,isunit,tmp,rep, _state) ) + { + return; + } + } + + /* + * Base case + */ + if( n<=tsa ) + { + if( isupper ) + { + + /* + * Compute inverse of upper triangular matrix. + */ + for(j=0; j<=n-1; j++) + { + if( !isunit ) + { + if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0)) ) + { + rep->terminationtype = -3; + return; + } + a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div((double)(1),a->ptr.pp_complex[offs+j][offs+j]); + ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); + } + else + { + ajj = ae_complex_from_i(-1); + } + + /* + * Compute elements 1:j-1 of j-th column. + */ + if( j>0 ) + { + ae_v_cmove(&tmp->ptr.p_complex[offs+0], 1, &a->ptr.pp_complex[offs+0][offs+j], a->stride, "N", ae_v_len(offs+0,offs+j-1)); + for(i=0; i<=j-1; i++) + { + if( iptr.pp_complex[offs+i][offs+i+1], 1, "N", &tmp->ptr.p_complex[offs+i+1], 1, "N", ae_v_len(offs+i+1,offs+j-1)); + } + else + { + v = ae_complex_from_i(0); + } + if( !isunit ) + { + a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[offs+i])); + } + else + { + a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[offs+i]); + } + } + ae_v_cmulc(&a->ptr.pp_complex[offs+0][offs+j], a->stride, ae_v_len(offs+0,offs+j-1), ajj); + } + } + } + else + { + + /* + * Compute inverse of lower triangular matrix. + */ + for(j=n-1; j>=0; j--) + { + if( !isunit ) + { + if( ae_c_eq_d(a->ptr.pp_complex[offs+j][offs+j],(double)(0)) ) + { + rep->terminationtype = -3; + return; + } + a->ptr.pp_complex[offs+j][offs+j] = ae_c_d_div((double)(1),a->ptr.pp_complex[offs+j][offs+j]); + ajj = ae_c_neg(a->ptr.pp_complex[offs+j][offs+j]); + } + else + { + ajj = ae_complex_from_i(-1); + } + if( jptr.p_complex[offs+j+1], 1, &a->ptr.pp_complex[offs+j+1][offs+j], a->stride, "N", ae_v_len(offs+j+1,offs+n-1)); + for(i=j+1; i<=n-1; i++) + { + if( i>j+1 ) + { + v = ae_v_cdotproduct(&a->ptr.pp_complex[offs+i][offs+j+1], 1, "N", &tmp->ptr.p_complex[offs+j+1], 1, "N", ae_v_len(offs+j+1,offs+i-1)); + } + else + { + v = ae_complex_from_i(0); + } + if( !isunit ) + { + a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,ae_c_mul(a->ptr.pp_complex[offs+i][offs+i],tmp->ptr.p_complex[offs+i])); + } + else + { + a->ptr.pp_complex[offs+i][offs+j] = ae_c_add(v,tmp->ptr.p_complex[offs+i]); + } + } + ae_v_cmulc(&a->ptr.pp_complex[offs+j+1][offs+j], a->stride, ae_v_len(offs+j+1,offs+n-1), ajj); + } + } + } + return; + } + + /* + * Recursive case + */ + tiledsplit(n, tscur, &n1, &n2, _state); + mn = imin2(n1, n2, _state); + touchint(&mn, _state); + if( n2>0 ) + { + if( isupper ) + { + for(i=0; i<=n1-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs, offs+n1, _state); + matinv_cmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, rep, _state); + cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, isunit, 0, a, offs, offs+n1, _state); + } + else + { + for(i=0; i<=n2-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, isunit, 0, a, offs+n1, offs, _state); + matinv_cmatrixtrinverserec(a, offs+n1, n2, isupper, isunit, tmp, rep, _state); + cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, isunit, 0, a, offs+n1, offs, _state); + } + } + matinv_cmatrixtrinverserec(a, offs, n1, isupper, isunit, tmp, rep, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_matinv_cmatrixtrinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + /* Complex */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +static void matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Real */ ae_vector* work, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + ae_int_t mn; + + + ae_assert(n>=1, "MATINV: integrity check 2553 failed", _state); + tsa = matrixtilesizea(_state); + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Try parallelism + */ + if( n>=2*tsb&&ae_fp_greater_eq((double)8/(double)6*rmul3((double)(n), (double)(n), (double)(n), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_matinv_rmatrixluinverserec(a,offs,n,work,rep, _state) ) + { + return; + } + } + + /* + * Base case + */ + if( n<=tsa ) + { + + /* + * Form inv(U) + */ + matinv_rmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, rep, _state); + + /* + * Solve the equation inv(A)*L = inv(U) for inv(A). + */ + for(j=n-1; j>=0; j--) + { + + /* + * Copy current column of L to WORK and replace with zeros. + */ + for(i=j+1; i<=n-1; i++) + { + work->ptr.p_double[i] = a->ptr.pp_double[offs+i][offs+j]; + a->ptr.pp_double[offs+i][offs+j] = (double)(0); + } + + /* + * Compute current column of inv(A). + */ + if( jptr.pp_double[offs+i][offs+j+1], 1, &work->ptr.p_double[j+1], 1, ae_v_len(offs+j+1,offs+n-1)); + a->ptr.pp_double[offs+i][offs+j] = a->ptr.pp_double[offs+i][offs+j]-v; + } + } + } + return; + } + + /* + * Recursive code: + * + * ( L1 ) ( U1 U12 ) + * A = ( ) * ( ) + * ( L12 L2 ) ( U2 ) + * + * ( W X ) + * A^-1 = ( ) + * ( Y Z ) + * + * In-place calculation can be done as follows: + * * X := inv(U1)*U12*inv(U2) + * * Y := inv(L2)*L12*inv(L1) + * * W := inv(L1*U1)+X*Y + * * X := -X*inv(L2) + * * Y := -inv(U2)*Y + * * Z := inv(L2*U2) + * + * Reordering w.r.t. interdependencies gives us: + * + * * X := inv(U1)*U12 \ suitable for parallel execution + * * Y := L12*inv(L1) / + * + * * X := X*inv(U2) \ + * * Y := inv(L2)*Y | suitable for parallel execution + * * W := inv(L1*U1) / + * + * * W := W+X*Y + * + * * X := -X*inv(L2) \ suitable for parallel execution + * * Y := -inv(U2)*Y / + * + * * Z := inv(L2*U2) + */ + tiledsplit(n, tscur, &n1, &n2, _state); + mn = imin2(n1, n2, _state); + touchint(&mn, _state); + ae_assert(n2>0, "LUInverseRec: internal error!", _state); + + /* + * X := inv(U1)*U12 + * Y := L12*inv(L1) + */ + rmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); + rmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); + + /* + * X := X*inv(U2) + * Y := inv(L2)*Y + * W := inv(L1*U1) + */ + rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); + rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); + matinv_rmatrixluinverserec(a, offs, n1, work, rep, _state); + if( rep->terminationtype<=0 ) + { + return; + } + + /* + * W := W+X*Y + */ + rmatrixgemm(n1, n1, n2, 1.0, a, offs, offs+n1, 0, a, offs+n1, offs, 0, 1.0, a, offs, offs, _state); + + /* + * X := -X*inv(L2) + * Y := -inv(U2)*Y + */ + rmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); + rmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); + for(i=0; i<=n1-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + for(i=0; i<=n2-1; i++) + { + ae_v_muld(&a->ptr.pp_double[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + + /* + * Z := inv(L2*U2) + */ + matinv_rmatrixluinverserec(a, offs+n1, n2, work, rep, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_matinv_rmatrixluinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Real */ ae_vector* work, + matinvreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +static void matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Complex */ ae_vector* work, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex v; + ae_int_t n1; + ae_int_t n2; + ae_int_t mn; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Try parallelism + */ + if( n>=2*tsb&&ae_fp_greater_eq((double)32/(double)6*rmul3((double)(n), (double)(n), (double)(n), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_matinv_cmatrixluinverserec(a,offs,n,work,rep, _state) ) + { + return; + } + } + + /* + * Base case + */ + if( n<=tsa ) + { + + /* + * Form inv(U) + */ + matinv_cmatrixtrinverserec(a, offs, n, ae_true, ae_false, work, rep, _state); + if( rep->terminationtype<=0 ) + { + return; + } + + /* + * Solve the equation inv(A)*L = inv(U) for inv(A). + */ + for(j=n-1; j>=0; j--) + { + + /* + * Copy current column of L to WORK and replace with zeros. + */ + for(i=j+1; i<=n-1; i++) + { + work->ptr.p_complex[i] = a->ptr.pp_complex[offs+i][offs+j]; + a->ptr.pp_complex[offs+i][offs+j] = ae_complex_from_i(0); + } + + /* + * Compute current column of inv(A). + */ + if( jptr.pp_complex[offs+i][offs+j+1], 1, "N", &work->ptr.p_complex[j+1], 1, "N", ae_v_len(offs+j+1,offs+n-1)); + a->ptr.pp_complex[offs+i][offs+j] = ae_c_sub(a->ptr.pp_complex[offs+i][offs+j],v); + } + } + } + return; + } + + /* + * Recursive code: + * + * ( L1 ) ( U1 U12 ) + * A = ( ) * ( ) + * ( L12 L2 ) ( U2 ) + * + * ( W X ) + * A^-1 = ( ) + * ( Y Z ) + * + * In-place calculation can be done as follows: + * * X := inv(U1)*U12*inv(U2) + * * Y := inv(L2)*L12*inv(L1) + * * W := inv(L1*U1)+X*Y + * * X := -X*inv(L2) + * * Y := -inv(U2)*Y + * * Z := inv(L2*U2) + * + * Reordering w.r.t. interdependencies gives us: + * + * * X := inv(U1)*U12 \ suitable for parallel execution + * * Y := L12*inv(L1) / + * + * * X := X*inv(U2) \ + * * Y := inv(L2)*Y | suitable for parallel execution + * * W := inv(L1*U1) / + * + * * W := W+X*Y + * + * * X := -X*inv(L2) \ suitable for parallel execution + * * Y := -inv(U2)*Y / + * + * * Z := inv(L2*U2) + */ + tiledsplit(n, tscur, &n1, &n2, _state); + mn = imin2(n1, n2, _state); + touchint(&mn, _state); + ae_assert(n2>0, "LUInverseRec: internal error!", _state); + + /* + * X := inv(U1)*U12 + * Y := L12*inv(L1) + */ + cmatrixlefttrsm(n1, n2, a, offs, offs, ae_true, ae_false, 0, a, offs, offs+n1, _state); + cmatrixrighttrsm(n2, n1, a, offs, offs, ae_false, ae_true, 0, a, offs+n1, offs, _state); + + /* + * X := X*inv(U2) + * Y := inv(L2)*Y + * W := inv(L1*U1) + */ + cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs, offs+n1, _state); + cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs+n1, offs, _state); + matinv_cmatrixluinverserec(a, offs, n1, work, rep, _state); + if( rep->terminationtype<=0 ) + { + return; + } + + /* + * W := W+X*Y + */ + cmatrixgemm(n1, n1, n2, ae_complex_from_d(1.0), a, offs, offs+n1, 0, a, offs+n1, offs, 0, ae_complex_from_d(1.0), a, offs, offs, _state); + + /* + * X := -X*inv(L2) + * Y := -inv(U2)*Y + */ + cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, ae_false, ae_true, 0, a, offs, offs+n1, _state); + cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, ae_true, ae_false, 0, a, offs+n1, offs, _state); + for(i=0; i<=n1-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + for(i=0; i<=n2-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + + /* + * Z := inv(L2*U2) + */ + matinv_cmatrixluinverserec(a, offs+n1, n2, work, rep, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_matinv_cmatrixluinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + /* Complex */ ae_vector* work, + matinvreport* rep, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Recursive subroutine for HPD inversion. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +static void matinv_hpdmatrixcholeskyinverserec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_complex v; + ae_int_t n1; + ae_int_t n2; + ae_int_t tsa; + ae_int_t tsb; + ae_int_t tscur; + + + if( n<1 ) + { + return; + } + tsa = matrixtilesizea(_state)/2; + tsb = matrixtilesizeb(_state); + tscur = tsb; + if( n<=tsb ) + { + tscur = tsa; + } + + /* + * Base case + */ + if( n<=tsa ) + { + matinv_cmatrixtrinverserec(a, offs, n, isupper, ae_false, tmp, rep, _state); + ae_assert(rep->terminationtype>0, "HPDMatrixCholeskyInverseRec: integrity check failed", _state); + if( isupper ) + { + + /* + * Compute the product U * U'. + * NOTE: we never assume that diagonal of U is real + */ + for(i=0; i<=n-1; i++) + { + if( i==0 ) + { + + /* + * 1x1 matrix + */ + a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); + } + else + { + + /* + * (I+1)x(I+1) matrix, + * + * ( A11 A12 ) ( A11^H ) ( A11*A11^H+A12*A12^H A12*A22^H ) + * ( ) * ( ) = ( ) + * ( A22 ) ( A12^H A22^H ) ( A22*A12^H A22*A22^H ) + * + * A11 is IxI, A22 is 1x1. + */ + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs][offs+i], a->stride, "Conj", ae_v_len(0,i-1)); + for(j=0; j<=i-1; j++) + { + v = a->ptr.pp_complex[offs+j][offs+i]; + ae_v_caddc(&a->ptr.pp_complex[offs+j][offs+j], 1, &tmp->ptr.p_complex[j], 1, "N", ae_v_len(offs+j,offs+i-1), v); + } + v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); + ae_v_cmulc(&a->ptr.pp_complex[offs][offs+i], a->stride, ae_v_len(offs,offs+i-1), v); + a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); + } + } + } + else + { + + /* + * Compute the product L' * L + * NOTE: we never assume that diagonal of L is real + */ + for(i=0; i<=n-1; i++) + { + if( i==0 ) + { + + /* + * 1x1 matrix + */ + a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); + } + else + { + + /* + * (I+1)x(I+1) matrix, + * + * ( A11^H A21^H ) ( A11 ) ( A11^H*A11+A21^H*A21 A21^H*A22 ) + * ( ) * ( ) = ( ) + * ( A22^H ) ( A21 A22 ) ( A22^H*A21 A22^H*A22 ) + * + * A11 is IxI, A22 is 1x1. + */ + ae_v_cmove(&tmp->ptr.p_complex[0], 1, &a->ptr.pp_complex[offs+i][offs], 1, "N", ae_v_len(0,i-1)); + for(j=0; j<=i-1; j++) + { + v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+j], _state); + ae_v_caddc(&a->ptr.pp_complex[offs+j][offs], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(offs,offs+j), v); + } + v = ae_c_conj(a->ptr.pp_complex[offs+i][offs+i], _state); + ae_v_cmulc(&a->ptr.pp_complex[offs+i][offs], 1, ae_v_len(offs,offs+i-1), v); + a->ptr.pp_complex[offs+i][offs+i] = ae_complex_from_d(ae_sqr(a->ptr.pp_complex[offs+i][offs+i].x, _state)+ae_sqr(a->ptr.pp_complex[offs+i][offs+i].y, _state)); + } + } + } + return; + } + + /* + * Recursive code: triangular factor inversion merged with + * UU' or L'L multiplication + */ + tiledsplit(n, tscur, &n1, &n2, _state); + + /* + * form off-diagonal block of trangular inverse + */ + if( isupper ) + { + for(i=0; i<=n1-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+i][offs+n1], 1, ae_v_len(offs+n1,offs+n-1), -1.0); + } + cmatrixlefttrsm(n1, n2, a, offs, offs, isupper, ae_false, 0, a, offs, offs+n1, _state); + cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs, offs+n1, _state); + } + else + { + for(i=0; i<=n2-1; i++) + { + ae_v_cmuld(&a->ptr.pp_complex[offs+n1+i][offs], 1, ae_v_len(offs,offs+n1-1), -1.0); + } + cmatrixrighttrsm(n2, n1, a, offs, offs, isupper, ae_false, 0, a, offs+n1, offs, _state); + cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 0, a, offs+n1, offs, _state); + } + + /* + * invert first diagonal block + */ + matinv_hpdmatrixcholeskyinverserec(a, offs, n1, isupper, tmp, rep, _state); + + /* + * update first diagonal block with off-diagonal block, + * update off-diagonal block + */ + if( isupper ) + { + cmatrixherk(n1, n2, 1.0, a, offs, offs+n1, 0, 1.0, a, offs, offs, isupper, _state); + cmatrixrighttrsm(n1, n2, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs, offs+n1, _state); + } + else + { + cmatrixherk(n1, n2, 1.0, a, offs+n1, offs, 2, 1.0, a, offs, offs, isupper, _state); + cmatrixlefttrsm(n2, n1, a, offs+n1, offs+n1, isupper, ae_false, 2, a, offs+n1, offs, _state); + } + + /* + * invert second diagonal block + */ + matinv_hpdmatrixcholeskyinverserec(a, offs+n1, n2, isupper, tmp, rep, _state); +} + + +void _matinvreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + matinvreport *p = (matinvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _matinvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + matinvreport *dst = (matinvreport*)_dst; + const matinvreport *src = (const matinvreport*)_src; + dst->terminationtype = src->terminationtype; + dst->r1 = src->r1; + dst->rinf = src->rinf; +} + + +void _matinvreport_clear(void* _p) +{ + matinvreport *p = (matinvreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _matinvreport_destroy(void* _p) +{ + matinvreport *p = (matinvreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a number to an element +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - row where the element to be updated is stored. + UpdColumn - column where the element to be updated is stored. + UpdVal - a number to be added to the element. + + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updrow, + ae_int_t updcolumn, + double updval, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector t1; + ae_vector t2; + ae_int_t i; + double lambdav; + double vt; + + ae_frame_make(_state, &_frame_block); + memset(&t1, 0, sizeof(t1)); + memset(&t2, 0, sizeof(t2)); + ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); + + ae_assert(updrow>=0&&updrow=0&&updcolumnptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); + + /* + * T2 = v*InvA + */ + ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); + + /* + * Lambda = v * InvA * U + */ + lambdav = updval*inva->ptr.pp_double[updcolumn][updrow]; + + /* + * InvA = InvA - correction + */ + for(i=0; i<=n-1; i++) + { + vt = updval*t1.ptr.p_double[i]; + vt = vt/((double)1+lambdav); + ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a row +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - the row of A whose vector V was added. + 0 <= Row <= N-1 + V - the vector to be added to a row. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updrow, + /* Real */ const ae_vector* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector t1; + ae_vector t2; + ae_int_t i; + ae_int_t j; + double lambdav; + double vt; + + ae_frame_make(_state, &_frame_block); + memset(&t1, 0, sizeof(t1)); + memset(&t2, 0, sizeof(t2)); + ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&t1, n-1+1, _state); + ae_vector_set_length(&t2, n-1+1, _state); + + /* + * T1 = InvA * U + */ + ae_v_move(&t1.ptr.p_double[0], 1, &inva->ptr.pp_double[0][updrow], inva->stride, ae_v_len(0,n-1)); + + /* + * T2 = v*InvA + * Lambda = v * InvA * U + */ + for(j=0; j<=n-1; j++) + { + vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); + t2.ptr.p_double[j] = vt; + } + lambdav = t2.ptr.p_double[updrow]; + + /* + * InvA = InvA - correction + */ + for(i=0; i<=n-1; i++) + { + vt = t1.ptr.p_double[i]/((double)1+lambdav); + ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a column +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdColumn - the column of A whose vector U was added. + 0 <= UpdColumn <= N-1 + U - the vector to be added to a column. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updcolumn, + /* Real */ const ae_vector* u, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector t1; + ae_vector t2; + ae_int_t i; + double lambdav; + double vt; + + ae_frame_make(_state, &_frame_block); + memset(&t1, 0, sizeof(t1)); + memset(&t2, 0, sizeof(t2)); + ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&t1, n-1+1, _state); + ae_vector_set_length(&t2, n-1+1, _state); + + /* + * T1 = InvA * U + * Lambda = v * InvA * U + */ + for(i=0; i<=n-1; i++) + { + vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); + t1.ptr.p_double[i] = vt; + } + lambdav = t1.ptr.p_double[updcolumn]; + + /* + * T2 = v*InvA + */ + ae_v_move(&t2.ptr.p_double[0], 1, &inva->ptr.pp_double[updcolumn][0], 1, ae_v_len(0,n-1)); + + /* + * InvA = InvA - correction + */ + for(i=0; i<=n-1; i++) + { + vt = t1.ptr.p_double[i]/((double)1+lambdav); + ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm computes the inverse of matrix A+u*v' by using the given matrix +A^-1 and the vectors u and v. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + U - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + V - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of matrix A + u*v'. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, + ae_int_t n, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector t1; + ae_vector t2; + ae_int_t i; + ae_int_t j; + double lambdav; + double vt; + + ae_frame_make(_state, &_frame_block); + memset(&t1, 0, sizeof(t1)); + memset(&t2, 0, sizeof(t2)); + ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t2, 0, DT_REAL, _state, ae_true); + + ae_vector_set_length(&t1, n-1+1, _state); + ae_vector_set_length(&t2, n-1+1, _state); + + /* + * T1 = InvA * U + * Lambda = v * T1 + */ + for(i=0; i<=n-1; i++) + { + vt = ae_v_dotproduct(&inva->ptr.pp_double[i][0], 1, &u->ptr.p_double[0], 1, ae_v_len(0,n-1)); + t1.ptr.p_double[i] = vt; + } + lambdav = ae_v_dotproduct(&v->ptr.p_double[0], 1, &t1.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * T2 = v*InvA + */ + for(j=0; j<=n-1; j++) + { + vt = ae_v_dotproduct(&v->ptr.p_double[0], 1, &inva->ptr.pp_double[0][j], inva->stride, ae_v_len(0,n-1)); + t2.ptr.p_double[j] = vt; + } + + /* + * InvA = InvA - correction + */ + for(i=0; i<=n-1; i++) + { + vt = t1.ptr.p_double[i]/((double)1+lambdav); + ae_v_subd(&inva->ptr.pp_double[i][0], 1, &t2.ptr.p_double[0], 1, ae_v_len(0,n-1), vt); + } + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Subroutine performing the Schur decomposition of a general matrix by using +the QR algorithm with multiple shifts. + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (lightweight Intel MKL is shipped + ! with ALGLIB for x64, other libs for other platforms) + ! + ! Vendor libs give approximately constant (with respect to number of + ! worker threads) acceleration factor which depends on CPU being used, + ! problem size and "baseline" ALGLIB edition which is used for + ! comparison. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The source matrix A is represented as S'*A*S = T, where S is an orthogonal +matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of +sizes 1x1 and 2x2 on the main diagonal). + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of A, N>=0. + + +Output parameters: + A - contains matrix T. + Array whose indexes range within [0..N-1, 0..N-1]. + S - contains Schur vectors. + Array whose indexes range within [0..N-1, 0..N-1]. + +Note 1: + The block structure of matrix T can be easily recognized: since all + the elements below the blocks are zeros, the elements a[i+1,i] which + are equal to 0 show the block border. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms in linear algebra). If you require maximum performance on + your machine, it is recommended to adjust this parameter manually. + +Result: + True, + if the algorithm has converged and parameters A and S contain the result. + False, + if the algorithm has not converged. + +Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). +*************************************************************************/ +ae_bool rmatrixschur(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* s, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector tau; + ae_vector wi; + ae_vector wr; + ae_int_t info; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&tau, 0, sizeof(tau)); + memset(&wi, 0, sizeof(wi)); + memset(&wr, 0, sizeof(wr)); + ae_matrix_clear(s); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wi, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wr, 0, DT_REAL, _state, ae_true); + + + /* + * Upper Hessenberg form of the 0-based matrix + */ + rmatrixhessenberg(a, n, &tau, _state); + rmatrixhessenbergunpackq(a, n, &tau, s, _state); + + /* + * Schur decomposition + */ + rmatrixinternalschurdecomposition(a, n, 1, 1, &wr, &wi, s, &info, _state); + result = info==0; + ae_frame_leave(_state); + return result; +} + + +#endif +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Algorithm for solving the following generalized symmetric positive-definite +eigenproblem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3). +where A is a symmetric matrix, B - symmetric positive-definite matrix. +The problem is solved by reducing it to an ordinary symmetric eigenvalue +problem. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ZNeeded - if ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in matrix columns. It should + be noted that the eigenvectors in such problems do not + form an orthogonal system. + +Result: + True, if the problem was solved successfully. + False, if the error occurred during the Cholesky decomposition of matrix + B (the matrix isn't positive-definite) or during the work of the iterative + algorithm for solving the symmetric eigenproblem. + +See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixgevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isuppera, + /* Real */ const ae_matrix* b, + ae_bool isupperb, + ae_int_t zneeded, + ae_int_t problemtype, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* z, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_matrix r; + ae_matrix t; + ae_bool isupperr; + ae_int_t j1; + ae_int_t j2; + ae_int_t j1inc; + ae_int_t j2inc; + ae_int_t i; + ae_int_t j; + double v; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&r, 0, sizeof(r)); + memset(&t, 0, sizeof(t)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(d); + ae_matrix_clear(z); + ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); + + + /* + * Reduce and solve + */ + result = smatrixgevdreduce(&a, n, isuppera, b, isupperb, problemtype, &r, &isupperr, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + result = smatrixevd(&a, n, zneeded, isuppera, d, &t, _state); + if( !result ) + { + ae_frame_leave(_state); + return result; + } + + /* + * Transform eigenvectors if needed + */ + if( zneeded!=0 ) + { + + /* + * fill Z with zeros + */ + ae_matrix_set_length(z, n-1+1, n-1+1, _state); + for(j=0; j<=n-1; j++) + { + z->ptr.pp_double[0][j] = 0.0; + } + for(i=1; i<=n-1; i++) + { + ae_v_move(&z->ptr.pp_double[i][0], 1, &z->ptr.pp_double[0][0], 1, ae_v_len(0,n-1)); + } + + /* + * Setup R properties + */ + if( isupperr ) + { + j1 = 0; + j2 = n-1; + j1inc = 1; + j2inc = 0; + } + else + { + j1 = 0; + j2 = 0; + j1inc = 0; + j2inc = 1; + } + + /* + * Calculate R*Z + */ + for(i=0; i<=n-1; i++) + { + for(j=j1; j<=j2; j++) + { + v = r.ptr.pp_double[i][j]; + ae_v_addd(&z->ptr.pp_double[i][0], 1, &t.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), v); + } + j1 = j1+j1inc; + j2 = j2+j2inc; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Algorithm for reduction of the following generalized symmetric positive- +definite eigenvalue problem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3) +to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and +the given problems are the same, and the eigenvectors of the given problem +could be obtained by multiplying the obtained eigenvectors by the +transformation matrix x = R*y). + +Here A is a symmetric matrix, B - symmetric positive-definite matrix. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + A - symmetric matrix which is given by its upper or lower + triangle depending on IsUpperA. Contains matrix C. + Array whose indexes range within [0..N-1, 0..N-1]. + R - upper triangular or low triangular transformation matrix + which is used to obtain the eigenvectors of a given problem + as the product of eigenvectors of C (from the right) and + matrix R (from the left). If the matrix is upper + triangular, the elements below the main diagonal + are equal to 0 (and vice versa). Thus, we can perform + the multiplication without taking into account the + internal structure (which is an easier though less + effective way). + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperR - type of matrix R (upper or lower triangular). + +Result: + True, if the problem was reduced successfully. + False, if the error occurred during the Cholesky decomposition of + matrix B (the matrix is not positive-definite). + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isuppera, + /* Real */ const ae_matrix* b, + ae_bool isupperb, + ae_int_t problemtype, + /* Real */ ae_matrix* r, + ae_bool* isupperr, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix t; + ae_vector w1; + ae_vector w2; + ae_vector w3; + ae_int_t i; + ae_int_t j; + double v; + matinvreport rep; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + memset(&w1, 0, sizeof(w1)); + memset(&w2, 0, sizeof(w2)); + memset(&w3, 0, sizeof(w3)); + memset(&rep, 0, sizeof(rep)); + ae_matrix_clear(r); + *isupperr = ae_false; + ae_matrix_init(&t, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w3, 0, DT_REAL, _state, ae_true); + _matinvreport_init(&rep, _state, ae_true); + + ae_assert(n>0, "SMatrixGEVDReduce: N<=0!", _state); + ae_assert((problemtype==1||problemtype==2)||problemtype==3, "SMatrixGEVDReduce: incorrect ProblemType!", _state); + result = ae_true; + + /* + * Problem 1: A*x = lambda*B*x + * + * Reducing to: + * C*y = lambda*y + * C = L^(-1) * A * L^(-T) + * x = L^(-T) * y + */ + if( problemtype==1 ) + { + + /* + * Factorize B in T: B = LL' + */ + ae_matrix_set_length(&t, n-1+1, n-1+1, _state); + if( isupperb ) + { + for(i=0; i<=n-1; i++) + { + ae_v_move(&t.ptr.pp_double[i][i], t.stride, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); + } + } + else + { + for(i=0; i<=n-1; i++) + { + ae_v_move(&t.ptr.pp_double[i][0], 1, &b->ptr.pp_double[i][0], 1, ae_v_len(0,i)); + } + } + if( !spdmatrixcholesky(&t, n, ae_false, _state) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Invert L in T + */ + rmatrixtrinverse(&t, n, ae_false, ae_false, &rep, _state); + if( rep.terminationtype<=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Build L^(-1) * A * L^(-T) in R + */ + ae_vector_set_length(&w1, n+1, _state); + ae_vector_set_length(&w2, n+1, _state); + ae_matrix_set_length(r, n-1+1, n-1+1, _state); + for(j=1; j<=n; j++) + { + + /* + * Form w2 = A * l'(j) (here l'(j) is j-th column of L^(-T)) + */ + ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][0], 1, ae_v_len(1,j)); + symmetricmatrixvectormultiply(a, isuppera, 0, j-1, &w1, 1.0, &w2, _state); + if( isuppera ) + { + matrixvectormultiply(a, 0, j-1, j, n-1, ae_true, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); + } + else + { + matrixvectormultiply(a, j, n-1, 0, j-1, ae_false, &w1, 1, j, 1.0, &w2, j+1, n, 0.0, _state); + } + + /* + * Form l(i)*w2 (here l(i) is i-th row of L^(-1)) + */ + for(i=1; i<=n; i++) + { + v = ae_v_dotproduct(&t.ptr.pp_double[i-1][0], 1, &w2.ptr.p_double[1], 1, ae_v_len(0,i-1)); + r->ptr.pp_double[i-1][j-1] = v; + } + } + + /* + * Copy R to A + */ + for(i=0; i<=n-1; i++) + { + ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + + /* + * Copy L^(-1) from T to R and transpose + */ + *isupperr = ae_true; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + r->ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], t.stride, ae_v_len(i,n-1)); + } + ae_frame_leave(_state); + return result; + } + + /* + * Problem 2: A*B*x = lambda*x + * or + * problem 3: B*A*x = lambda*x + * + * Reducing to: + * C*y = lambda*y + * C = U * A * U' + * B = U'* U + */ + if( problemtype==2||problemtype==3 ) + { + + /* + * Factorize B in T: B = U'*U + */ + ae_matrix_set_length(&t, n-1+1, n-1+1, _state); + if( isupperb ) + { + for(i=0; i<=n-1; i++) + { + ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); + } + } + else + { + for(i=0; i<=n-1; i++) + { + ae_v_move(&t.ptr.pp_double[i][i], 1, &b->ptr.pp_double[i][i], b->stride, ae_v_len(i,n-1)); + } + } + if( !spdmatrixcholesky(&t, n, ae_true, _state) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Build U * A * U' in R + */ + ae_vector_set_length(&w1, n+1, _state); + ae_vector_set_length(&w2, n+1, _state); + ae_vector_set_length(&w3, n+1, _state); + ae_matrix_set_length(r, n-1+1, n-1+1, _state); + for(j=1; j<=n; j++) + { + + /* + * Form w2 = A * u'(j) (here u'(j) is j-th column of U') + */ + ae_v_move(&w1.ptr.p_double[1], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(1,n-j+1)); + symmetricmatrixvectormultiply(a, isuppera, j-1, n-1, &w1, 1.0, &w3, _state); + ae_v_move(&w2.ptr.p_double[j], 1, &w3.ptr.p_double[1], 1, ae_v_len(j,n)); + ae_v_move(&w1.ptr.p_double[j], 1, &t.ptr.pp_double[j-1][j-1], 1, ae_v_len(j,n)); + if( isuppera ) + { + matrixvectormultiply(a, 0, j-2, j-1, n-1, ae_false, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); + } + else + { + matrixvectormultiply(a, j-1, n-1, 0, j-2, ae_true, &w1, j, n, 1.0, &w2, 1, j-1, 0.0, _state); + } + + /* + * Form u(i)*w2 (here u(i) is i-th row of U) + */ + for(i=1; i<=n; i++) + { + v = ae_v_dotproduct(&t.ptr.pp_double[i-1][i-1], 1, &w2.ptr.p_double[i], 1, ae_v_len(i-1,n-1)); + r->ptr.pp_double[i-1][j-1] = v; + } + } + + /* + * Copy R to A + */ + for(i=0; i<=n-1; i++) + { + ae_v_move(&a->ptr.pp_double[i][0], 1, &r->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + if( problemtype==2 ) + { + + /* + * Invert U in T + */ + rmatrixtrinverse(&t, n, ae_true, ae_false, &rep, _state); + if( rep.terminationtype<=0 ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Copy U^-1 from T to R + */ + *isupperr = ae_true; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i-1; j++) + { + r->ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_move(&r->ptr.pp_double[i][i], 1, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); + } + } + else + { + + /* + * Copy U from T to R and transpose + */ + *isupperr = ae_false; + for(i=0; i<=n-1; i++) + { + for(j=i+1; j<=n-1; j++) + { + r->ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_move(&r->ptr.pp_double[i][i], r->stride, &t.ptr.pp_double[i][i], 1, ae_v_len(i,n-1)); + } + } + } + ae_frame_leave(_state); + return result; +} + + +#endif +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixludet(/* Real */ const ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t s; + double result; + + + ae_assert(n>=1, "RMatrixLUDet: N<1!", _state); + ae_assert(pivots->cnt>=n, "RMatrixLUDet: Pivots array is too short!", _state); + ae_assert(a->rows>=n, "RMatrixLUDet: rows(A)cols>=n, "RMatrixLUDet: cols(A)ptr.pp_double[i][i]; + if( pivots->ptr.p_int[i]!=i ) + { + s = -s; + } + } + result = result*(double)s; + return result; +} + + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixdet(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector pivots; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "RMatrixDet: N<1!", _state); + ae_assert(a.rows>=n, "RMatrixDet: rows(A)=n, "RMatrixDet: cols(A)=1, "CMatrixLUDet: N<1!", _state); + ae_assert(pivots->cnt>=n, "CMatrixLUDet: Pivots array is too short!", _state); + ae_assert(a->rows>=n, "CMatrixLUDet: rows(A)cols>=n, "CMatrixLUDet: cols(A)ptr.pp_complex[i][i]); + if( pivots->ptr.p_int[i]!=i ) + { + s = -s; + } + } + result = ae_c_mul_d(result,(double)(s)); + return result; +} + + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +ae_complex cmatrixdet(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_vector pivots; + ae_complex result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&pivots, 0, sizeof(pivots)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&pivots, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "CMatrixDet: N<1!", _state); + ae_assert(a.rows>=n, "CMatrixDet: rows(A)=n, "CMatrixDet: cols(A)=1, "SPDMatrixCholeskyDet: N<1!", _state); + ae_assert(a->rows>=n, "SPDMatrixCholeskyDet: rows(A)cols>=n, "SPDMatrixCholeskyDet: cols(A)ptr.pp_double[i][i], _state); + } + ae_assert(f, "SPDMatrixCholeskyDet: A contains infinite or NaN values!", _state); + result = (double)(1); + for(i=0; i<=n-1; i++) + { + result = result*ae_sqr(a->ptr.pp_double[i][i], _state); + } + return result; +} + + +/************************************************************************* +Determinant calculation of the symmetric positive definite matrix. + +Input parameters: + A - matrix, array[N,N] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +Result: + determinant of matrix A. + If matrix A is not positive definite, an exception is generated. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +double spdmatrixdet(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_bool b; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>=1, "SPDMatrixDet: N<1!", _state); + ae_assert(a.rows>=n, "SPDMatrixDet: rows(A)=n, "SPDMatrixDet: cols(A)>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _linalg_pkg_h -#define _linalg_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "alglibmisc.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - double r1; - double rinf; -} matinvreport; -typedef struct -{ - ae_vector vals; - ae_vector idx; - ae_vector ridx; - ae_vector didx; - ae_vector uidx; - ae_int_t matrixtype; - ae_int_t m; - ae_int_t n; - ae_int_t nfree; - ae_int_t ninitialized; -} sparsematrix; -typedef struct -{ - double e1; - double e2; - ae_vector x; - ae_vector ax; - double xax; - ae_int_t n; - ae_vector rk; - ae_vector rk1; - ae_vector xk; - ae_vector xk1; - ae_vector pk; - ae_vector pk1; - ae_vector b; - rcommstate rstate; - ae_vector tmp2; -} fblslincgstate; -typedef struct -{ - ae_int_t n; - ae_int_t m; - ae_int_t nstart; - ae_int_t nits; - ae_int_t seedval; - ae_vector x0; - ae_vector x1; - ae_vector t; - ae_vector xbest; - hqrndstate r; - ae_vector x; - ae_vector mv; - ae_vector mtv; - ae_bool needmv; - ae_bool needmtv; - double repnorm; - rcommstate rstate; -} normestimatorstate; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - - - - - - - - - - - - - - - - -/************************************************************************* -Matrix inverse report: -* R1 reciprocal of condition number in 1-norm -* RInf reciprocal of condition number in inf-norm -*************************************************************************/ -class _matinvreport_owner -{ -public: - _matinvreport_owner(); - _matinvreport_owner(const _matinvreport_owner &rhs); - _matinvreport_owner& operator=(const _matinvreport_owner &rhs); - virtual ~_matinvreport_owner(); - alglib_impl::matinvreport* c_ptr(); - alglib_impl::matinvreport* c_ptr() const; -protected: - alglib_impl::matinvreport *p_struct; -}; -class matinvreport : public _matinvreport_owner -{ -public: - matinvreport(); - matinvreport(const matinvreport &rhs); - matinvreport& operator=(const matinvreport &rhs); - virtual ~matinvreport(); - double &r1; - double &rinf; - -}; - -/************************************************************************* -Sparse matrix - -You should use ALGLIB functions to work with sparse matrix. -Never try to access its fields directly! -*************************************************************************/ -class _sparsematrix_owner -{ -public: - _sparsematrix_owner(); - _sparsematrix_owner(const _sparsematrix_owner &rhs); - _sparsematrix_owner& operator=(const _sparsematrix_owner &rhs); - virtual ~_sparsematrix_owner(); - alglib_impl::sparsematrix* c_ptr(); - alglib_impl::sparsematrix* c_ptr() const; -protected: - alglib_impl::sparsematrix *p_struct; -}; -class sparsematrix : public _sparsematrix_owner -{ -public: - sparsematrix(); - sparsematrix(const sparsematrix &rhs); - sparsematrix& operator=(const sparsematrix &rhs); - virtual ~sparsematrix(); - -}; - - - -/************************************************************************* -This object stores state of the iterative norm estimation algorithm. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -class _normestimatorstate_owner -{ -public: - _normestimatorstate_owner(); - _normestimatorstate_owner(const _normestimatorstate_owner &rhs); - _normestimatorstate_owner& operator=(const _normestimatorstate_owner &rhs); - virtual ~_normestimatorstate_owner(); - alglib_impl::normestimatorstate* c_ptr(); - alglib_impl::normestimatorstate* c_ptr() const; -protected: - alglib_impl::normestimatorstate *p_struct; -}; -class normestimatorstate : public _normestimatorstate_owner -{ -public: - normestimatorstate(); - normestimatorstate(const normestimatorstate &rhs); - normestimatorstate& operator=(const normestimatorstate &rhs); - virtual ~normestimatorstate(); - -}; - -/************************************************************************* -Cache-oblivous complex "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb); - - -/************************************************************************* -Cache-oblivous real "copy-and-transpose" - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb); - - -/************************************************************************* -This code enforces symmetricy of the matrix by copying Upper part to lower -one (or vice versa). - -INPUT PARAMETERS: - A - matrix - N - number of rows/columns - IsUpper - whether we want to copy upper triangle to lower one (True) - or vice versa (False). -*************************************************************************/ -void rmatrixenforcesymmetricity(const real_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb); - - -/************************************************************************* -Copy - -Input parameters: - M - number of rows - N - number of columns - A - source matrix, MxN submatrix is copied and transposed - IA - submatrix offset (row index) - JA - submatrix offset (column index) - B - destination matrix, must be large enough to store result - IB - submatrix offset (row index) - JB - submatrix offset (column index) -*************************************************************************/ -void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb); - - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_1d_array &u, const ae_int_t iu, complex_1d_array &v, const ae_int_t iv); - - -/************************************************************************* -Rank-1 correction: A := A + u*v' - -INPUT PARAMETERS: - M - number of rows - N - number of columns - A - target matrix, MxN submatrix is updated - IA - submatrix offset (row index) - JA - submatrix offset (column index) - U - vector #1 - IU - subvector offset - V - vector #2 - IV - subvector offset -*************************************************************************/ -void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_1d_array &u, const ae_int_t iu, real_1d_array &v, const ae_int_t iv); - - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - M>=0 - N - number of columns of op(A) - N>=0 - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - * OpA=2 => op(A) = A^H - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy); - - -/************************************************************************* -Matrix-vector product: y := op(A)*x - -INPUT PARAMETERS: - M - number of rows of op(A) - N - number of columns of op(A) - A - target matrix - IA - submatrix offset (row index) - JA - submatrix offset (column index) - OpA - operation type: - * OpA=0 => op(A) = A - * OpA=1 => op(A) = A^T - X - input vector - IX - subvector offset - IY - subvector offset - Y - preallocated matrix, must be large enough to store result - -OUTPUT PARAMETERS: - Y - vector which stores result - -if M=0, then subroutine does nothing. -if N=0, Y is filled by zeros. - - - -- ALGLIB routine -- - - 28.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy); - - -/************************************************************************* - -*************************************************************************/ -void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); -void smp_cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); - - -/************************************************************************* - -*************************************************************************/ -void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); -void smp_cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const complex_2d_array &x, const ae_int_t i2, const ae_int_t j2); - - -/************************************************************************* - -*************************************************************************/ -void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); -void smp_rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); - - -/************************************************************************* - -*************************************************************************/ -void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); -void smp_rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, const real_2d_array &x, const ae_int_t i2, const ae_int_t j2); - - -/************************************************************************* - -*************************************************************************/ -void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); -void smp_cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); - - -/************************************************************************* - -*************************************************************************/ -void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); -void smp_rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper); - - -/************************************************************************* - -*************************************************************************/ -void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc); -void smp_cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, const complex_2d_array &c, const ae_int_t ic, const ae_int_t jc); - - -/************************************************************************* - -*************************************************************************/ -void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc); -void smp_rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, const real_2d_array &c, const ae_int_t ic, const ae_int_t jc); - -/************************************************************************* -QR decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form (see below). - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. - -The elements of matrix R are located on and above the main diagonal of -matrix A. The elements which are located in Tau array and below the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(k-1), - -where k = min(m,n), and each H(i) is in the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, -so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); - - -/************************************************************************* -LQ decomposition of a rectangular matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices L and Q in compact form (see below) - Tau - array of scalar factors which are used to form - matrix Q. Array whose index ranges within [0..Min(M,N)-1]. - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. - -The elements of matrix L are located on and below the main diagonal of -matrix A. The elements which are located in Tau array and above the main -diagonal of matrix A are used to form matrix Q as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(k-1)*H(k-2)*...*H(1)*H(0), - -where k = min(m,n), and each H(i) is of the form - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, -v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau); - - -/************************************************************************* -QR decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and R in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = QR, where Q is an orthogonal matrix of size -MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); - - -/************************************************************************* -LQ decomposition of a rectangular complex matrix of size MxN - -Input parameters: - A - matrix A whose indexes range within [0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q and L in compact form - Tau - array of scalar factors which are used to form matrix Q. Array - whose indexes range within [0.. Min(M,N)-1] - -Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size -MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau); - - -/************************************************************************* -Partial unpacking of matrix Q from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixQR subroutine. - QColumns - required number of columns of matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose indexes range within [0..M-1, 0..QColumns-1]. - If QColumns=0, the array remains unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q); - - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of RMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r); - - -/************************************************************************* -Partial unpacking of matrix Q from the LQ decomposition of a matrix A - -Input parameters: - A - matrices L and Q in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of the RMatrixLQ subroutine. - QRows - required number of rows in matrix Q. N>=QRows>=0. - -Output parameters: - Q - first QRows rows of matrix Q. Array whose indexes range - within [0..QRows-1, 0..N-1]. If QRows=0, the array remains - unchanged. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q); - - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of RMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l); - - -/************************************************************************* -Partial unpacking of matrix Q from QR decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixQR subroutine . - QColumns - required number of columns in matrix Q. M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array whose index ranges within [0..M-1, 0..QColumns-1]. - If QColumns=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q); - - -/************************************************************************* -Unpacking of matrix R from the QR decomposition of a matrix A - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixQR subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - R - matrix R, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r); - - -/************************************************************************* -Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. - -Input parameters: - A - matrices Q and R in compact form. - Output of CMatrixLQ subroutine . - M - number of rows in matrix A. M>=0. - N - number of columns in matrix A. N>=0. - Tau - scalar factors which are used to form Q. - Output of CMatrixLQ subroutine . - QRows - required number of rows in matrix Q. N>=QColumns>=0. - -Output parameters: - Q - first QRows rows of matrix Q. - Array whose index ranges within [0..QRows-1, 0..N-1]. - If QRows=0, array isn't changed. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q); - - -/************************************************************************* -Unpacking of matrix L from the LQ decomposition of a matrix A - -Input parameters: - A - matrices Q and L in compact form. - Output of CMatrixLQ subroutine. - M - number of rows in given matrix A. M>=0. - N - number of columns in given matrix A. N>=0. - -Output parameters: - L - matrix L, array[0..M-1, 0..N-1]. - - -- ALGLIB routine -- - 17.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l); - - -/************************************************************************* -Reduction of a rectangular matrix to bidiagonal form - -The algorithm reduces the rectangular matrix A to bidiagonal form by -orthogonal transformations P and Q: A = Q*B*P. - -Input parameters: - A - source matrix. array[0..M-1, 0..N-1] - M - number of rows in matrix A. - N - number of columns in matrix A. - -Output parameters: - A - matrices Q, B, P in compact form (see below). - TauQ - scalar factors which are used to form matrix Q. - TauP - scalar factors which are used to form matrix P. - -The main diagonal and one of the secondary diagonals of matrix A are -replaced with bidiagonal matrix B. Other elements contain elementary -reflections which form MxM matrix Q and NxN matrix P, respectively. - -If M>=N, B is the upper bidiagonal MxN matrix and is stored in the -corresponding elements of matrix A. Matrix Q is represented as a -product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where -H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and -vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is -stored in elements A(i+1:m-1,i). Matrix P is as follows: P = -G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], -u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). - -If M n): m=5, n=6 (m < n): - -( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) -( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) -( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) -( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) -( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) -( v1 v2 v3 v4 v5 ) - -Here vi and ui are vectors which form H(i) and G(i), and d and e - -are the diagonal and off-diagonal elements of matrix B. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994. - Sergey Bochkanov, ALGLIB project, translation from FORTRAN to - pseudocode, 2007-2010. -*************************************************************************/ -void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup); - - -/************************************************************************* -Unpacking matrix Q which reduces a matrix to bidiagonal form. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - QColumns - required number of columns in matrix Q. - M>=QColumns>=0. - -Output parameters: - Q - first QColumns columns of matrix Q. - Array[0..M-1, 0..QColumns-1] - If QColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q); - - -/************************************************************************* -Multiplication by matrix Q which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by Q or Q'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUQ - scalar factors which are used to form Q. - Output of ToBidiagonal subroutine. - Z - multiplied matrix. - array[0..ZRows-1,0..ZColumns-1] - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=M, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=M, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by Q or Q'. - -Output parameters: - Z - product of Z and Q. - Array[0..ZRows-1,0..ZColumns-1] - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose); - - -/************************************************************************* -Unpacking matrix P which reduces matrix A to bidiagonal form. -The subroutine returns transposed matrix P. - -Input parameters: - QP - matrices Q and P in compact form. - Output of ToBidiagonal subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of ToBidiagonal subroutine. - PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. - -Output parameters: - PT - first PTRows columns of matrix P^T - Array[0..PTRows-1, 0..N-1] - If PTRows=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt); - - -/************************************************************************* -Multiplication by matrix P which reduces matrix A to bidiagonal form. - -The algorithm allows pre- or post-multiply by P or P'. - -Input parameters: - QP - matrices Q and P in compact form. - Output of RMatrixBD subroutine. - M - number of rows in matrix A. - N - number of columns in matrix A. - TAUP - scalar factors which are used to form P. - Output of RMatrixBD subroutine. - Z - multiplied matrix. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - ZRows - number of rows in matrix Z. If FromTheRight=False, - ZRows=N, otherwise ZRows can be arbitrary. - ZColumns - number of columns in matrix Z. If FromTheRight=True, - ZColumns=N, otherwise ZColumns can be arbitrary. - FromTheRight - pre- or post-multiply. - DoTranspose - multiply by P or P'. - -Output parameters: - Z - product of Z and P. - Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. - If ZRows=0 or ZColumns=0, the array is not modified. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose); - - -/************************************************************************* -Unpacking of the main and secondary diagonals of bidiagonal decomposition -of matrix A. - -Input parameters: - B - output of RMatrixBD subroutine. - M - number of rows in matrix B. - N - number of columns in matrix B. - -Output parameters: - IsUpper - True, if the matrix is upper bidiagonal. - otherwise IsUpper is False. - D - the main diagonal. - Array whose index ranges within [0..Min(M,N)-1]. - E - the secondary diagonal (upper or lower, depending on - the value of IsUpper). - Array index ranges within [0..Min(M,N)-1], the last - element is not used. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e); - - -/************************************************************************* -Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, -where Q is an orthogonal matrix, H - Hessenberg matrix. - -Input parameters: - A - matrix A with elements [0..N-1, 0..N-1] - N - size of matrix A. - -Output parameters: - A - matrices Q and P in compact form (see below). - Tau - array of scalar factors which are used to form matrix Q. - Array whose index ranges within [0..N-2] - -Matrix H is located on the main diagonal, on the lower secondary diagonal -and above the main diagonal of matrix A. The elements which are used to -form matrix Q are situated in array Tau and below the lower secondary -diagonal of matrix A as follows: - -Matrix Q is represented as a product of elementary reflections - -Q = H(0)*H(2)*...*H(n-2), - -where each H(i) is given by - -H(i) = 1 - tau * v * (v^T) - -where tau is a scalar stored in Tau[I]; v - is a real vector, -so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau); - - -/************************************************************************* -Unpacking matrix Q which reduces matrix A to upper Hessenberg form - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - Tau - scalar factors which are used to form Q. - Output of RMatrixHessenberg subroutine. - -Output parameters: - Q - matrix Q. - Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q); - - -/************************************************************************* -Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) - -Input parameters: - A - output of RMatrixHessenberg subroutine. - N - size of matrix A. - -Output parameters: - H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - 2005-2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h); - - -/************************************************************************* -Reduction of a symmetric matrix which is given by its higher or lower -triangular part to a tridiagonal matrix using orthogonal similarity -transformation: Q'*A*Q=T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a real scalar, and v is a real vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - - where d and e denote diagonal and off-diagonal elements of T, and vi - denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e); - - -/************************************************************************* -Unpacking matrix Q which reduces symmetric matrix to a tridiagonal -form. - -Input parameters: - A - the result of a SMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of SMatrixTD subroutine) - Tau - the result of a SMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q); - - -/************************************************************************* -Reduction of a Hermitian matrix which is given by its higher or lower -triangular part to a real tridiagonal matrix using unitary similarity -transformation: Q'*A*Q = T. - -Input parameters: - A - matrix to be transformed - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. If IsUpper = True, then matrix A is given - by its upper triangle, and the lower triangle is not used - and not modified by the algorithm, and vice versa - if IsUpper = False. - -Output parameters: - A - matrices T and Q in compact form (see lower) - Tau - array of factors which are forming matrices H(i) - array with elements [0..N-2]. - D - main diagonal of real symmetric matrix T. - array with elements [0..N-1]. - E - secondary diagonal of real symmetric matrix T. - array with elements [0..N-2]. - - - If IsUpper=True, the matrix Q is represented as a product of elementary - reflectors - - Q = H(n-2) . . . H(2) H(0). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in - A(0:i-1,i+1), and tau in TAU(i). - - If IsUpper=False, the matrix Q is represented as a product of elementary - reflectors - - Q = H(0) H(2) . . . H(n-2). - - Each H(i) has the form - - H(i) = I - tau * v * v' - - where tau is a complex scalar, and v is a complex vector with - v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), - and tau in TAU(i). - - The contents of A on exit are illustrated by the following examples - with n = 5: - - if UPLO = 'U': if UPLO = 'L': - - ( d e v1 v2 v3 ) ( d ) - ( d e v2 v3 ) ( e d ) - ( d e v3 ) ( v0 e d ) - ( d e ) ( v0 v1 e d ) - ( d ) ( v0 v1 v2 e d ) - -where d and e denote diagonal and off-diagonal elements of T, and vi -denotes an element of the vector defining H(i). - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1992 -*************************************************************************/ -void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e); - - -/************************************************************************* -Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal -form. - -Input parameters: - A - the result of a HMatrixTD subroutine - N - size of matrix A. - IsUpper - storage format (a parameter of HMatrixTD subroutine) - Tau - the result of a HMatrixTD subroutine - -Output parameters: - Q - transformation matrix. - array with elements [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q); - -/************************************************************************* -Singular value decomposition of a bidiagonal matrix (extended algorithm) - -The algorithm performs the singular value decomposition of a bidiagonal -matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - -orthogonal matrices, S - diagonal matrix with non-negative elements on the -main diagonal, in descending order. - -The algorithm finds singular values. In addition, the algorithm can -calculate matrices Q and P (more precisely, not the matrices, but their -product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, -matrices U and VT can be of any type, including identity. Furthermore, the -algorithm can calculate Q'*C (this product is calculated more effectively -than U*Q, because this calculation operates with rows instead of matrix -columns). - -The feature of the algorithm is its ability to find all singular values -including those which are arbitrarily close to 0 with relative accuracy -close to machine precision. If the parameter IsFractionalAccuracyRequired -is set to True, all singular values will have high relative accuracy close -to machine precision. If the parameter is set to False, only the biggest -singular value will have relative accuracy close to machine precision. -The absolute error of other singular values is equal to the absolute error -of the biggest singular value. - -Input parameters: - D - main diagonal of matrix B. - Array whose index ranges within [0..N-1]. - E - superdiagonal (or subdiagonal) of matrix B. - Array whose index ranges within [0..N-2]. - N - size of matrix B. - IsUpper - True, if the matrix is upper bidiagonal. - IsFractionalAccuracyRequired - - THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 - SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. - U - matrix to be multiplied by Q. - Array whose indexes range within [0..NRU-1, 0..N-1]. - The matrix can be bigger, in that case only the submatrix - [0..NRU-1, 0..N-1] will be multiplied by Q. - NRU - number of rows in matrix U. - C - matrix to be multiplied by Q'. - Array whose indexes range within [0..N-1, 0..NCC-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCC-1] will be multiplied by Q'. - NCC - number of columns in matrix C. - VT - matrix to be multiplied by P^T. - Array whose indexes range within [0..N-1, 0..NCVT-1]. - The matrix can be bigger, in that case only the submatrix - [0..N-1, 0..NCVT-1] will be multiplied by P^T. - NCVT - number of columns in matrix VT. - -Output parameters: - D - singular values of matrix B in descending order. - U - if NRU>0, contains matrix U*Q. - VT - if NCVT>0, contains matrix (P^T)*VT. - C - if NCC>0, contains matrix Q'*C. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Additional information: - The type of convergence is controlled by the internal parameter TOL. - If the parameter is greater than 0, the singular values will have - relative accuracy TOL. If TOL<0, the singular values will have - absolute accuracy ABS(TOL)*norm(B). - By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, - where Epsilon is the machine precision. It is not recommended to use - TOL less than 10*Epsilon since this will considerably slow down the - algorithm and may not lead to error decreasing. -History: - * 31 March, 2007. - changed MAXITR from 6 to 12. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - October 31, 1999. -*************************************************************************/ -bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt); - -/************************************************************************* -Singular value decomposition of a rectangular matrix. - -The algorithm calculates the singular value decomposition of a matrix of -size MxN: A = U * S * V^T - -The algorithm finds the singular values and, optionally, matrices U and V^T. -The algorithm can find both first min(M,N) columns of matrix U and rows of -matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM -and NxN respectively). - -Take into account that the subroutine does not return matrix V but V^T. - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - UNeeded - 0, 1 or 2. See the description of the parameter U. - VTNeeded - 0, 1 or 2. See the description of the parameter VT. - AdditionalMemory - - If the parameter: - * equals 0, the algorithm doesn’t use additional - memory (lower requirements, lower performance). - * equals 1, the algorithm uses additional - memory of size min(M,N)*min(M,N) of real numbers. - It often speeds up the algorithm. - * equals 2, the algorithm uses additional - memory of size M*min(M,N) of real numbers. - It allows to get a maximum performance. - The recommended value of the parameter is 2. - -Output parameters: - W - contains singular values in descending order. - U - if UNeeded=0, U isn't changed, the left singular vectors - are not calculated. - if Uneeded=1, U contains left singular vectors (first - min(M,N) columns of matrix U). Array whose indexes range - within [0..M-1, 0..Min(M,N)-1]. - if UNeeded=2, U contains matrix U wholly. Array whose - indexes range within [0..M-1, 0..M-1]. - VT - if VTNeeded=0, VT isn’t changed, the right singular vectors - are not calculated. - if VTNeeded=1, VT contains right singular vectors (first - min(M,N) rows of matrix V^T). Array whose indexes range - within [0..min(M,N)-1, 0..N-1]. - if VTNeeded=2, VT contains matrix V^T wholly. Array whose - indexes range within [0..N-1, 0..N-1]. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt); - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a symmetric matrix - -The algorithm finds eigen pairs of a symmetric matrix by reducing it to -tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpper - storage format. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z); - - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric -matrix in a given half open interval (A, B] by using a bisection and -inverse iteration - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half open interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval (M>=0). - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, - M is equal to 0. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z); - - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a symmetric -matrix with given indexes by using bisection and inverse iteration methods. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 07.01.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z); - - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a Hermitian matrix - -The algorithm finds eigen pairs of a Hermitian matrix by reducing it to -real tridiagonal form and using the QL/QR algorithm. - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged (rare case). - -Note: - eigenvectors of Hermitian matrix are defined up to multiplication by - a complex number L, such that |L|=1. - - -- ALGLIB -- - Copyright 2005, 23 March 2007 by Bochkanov Sergey -*************************************************************************/ -bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z); - - -/************************************************************************* -Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian -matrix in a given half-interval (A, B] by using a bisection and inverse -iteration - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. Array whose indexes range within - [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - B1, B2 - half-interval (B1, B2] to search eigenvalues in. - -Output parameters: - M - number of eigenvalues found in a given half-interval, M>=0 - W - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..M-1]. - The eigenvectors are stored in the matrix columns. - -Result: - True, if successful. M contains the number of eigenvalues in the given - half-interval (could be equal to 0), W contains the eigenvalues, - Z contains the eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned, M is - equal to 0. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z); - - -/************************************************************************* -Subroutine for finding the eigenvalues and eigenvectors of a Hermitian -matrix with given indexes by using bisection and inverse iteration methods - -Input parameters: - A - Hermitian matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or - not. If ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - IsUpperA - storage format of matrix A. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - -Output parameters: - W - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..I2-I1]. - In that case, the eigenvectors are stored in the matrix - columns. - -Result: - True, if successful. W contains the eigenvalues, Z contains the - eigenvectors (if needed). - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration - subroutine wasn't able to find all the corresponding eigenvectors. - In that case, the eigenvalues and eigenvectors are not returned. - -Note: - eigen vectors of Hermitian matrix are defined up to multiplication by - a complex number L, such as |L|=1. - - -- ALGLIB -- - Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. -*************************************************************************/ -bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z); - - -/************************************************************************* -Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix - -The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by -using an QL/QR algorithm with implicit shifts. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix A. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix - are multiplied by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity - transformation of a symmetric matrix; - * 2, the eigenvectors of a tridiagonal matrix replace the - square matrix Z; - * 3, matrix Z contains the first row of the eigenvectors - matrix. - Z - if ZNeeded=1, Z contains the square matrix by which the - eigenvectors are multiplied. - Array whose indexes range within [0..N-1, 0..N-1]. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains the product of a given matrix (from the left) - and the eigenvectors matrix (from the right); - * 2, Z contains the eigenvectors. - * 3, Z contains the first row of the eigenvectors matrix. - If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. - In that case, the eigenvectors are stored in the matrix columns. - If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm hasn't converged. - - -- LAPACK routine (version 3.0) -- - Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., - Courant Institute, Argonne National Lab, and Rice University - September 30, 1994 -*************************************************************************/ -bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z); - - -/************************************************************************* -Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a -given half-interval (A, B] by using bisection and inverse iteration. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix, N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the tridiagonal - matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. - A, B - half-interval (A, B] to search eigenvalues in. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range - within [0..N-1, 0..N-1]) which reduces the given symmetric - matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..M-1]. - M - number of eigenvalues found in the given half-interval (M>=0). - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the - left) and NxM matrix of the eigenvectors found (from the - right). Array whose indexes range within [0..N-1, 0..M-1]. - * 2, contains the matrix of the eigenvectors found. - Array whose indexes range within [0..N-1, 0..M-1]. - -Result: - - True, if successful. In that case, M contains the number of eigenvalues - in the given half-interval (could be equal to 0), D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the - eigenvalues in the given interval or if the inverse iteration subroutine - wasn't able to find all the corresponding eigenvectors. In that case, - the eigenvalues and eigenvectors are not returned, M is equal to 0. - - -- ALGLIB -- - Copyright 31.03.2008 by Bochkanov Sergey -*************************************************************************/ -bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z); - - -/************************************************************************* -Subroutine for finding tridiagonal matrix eigenvalues/vectors with given -indexes (in ascending order) by using the bisection and inverse iteraion. - -Input parameters: - D - the main diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-1]. - E - the secondary diagonal of a tridiagonal matrix. - Array whose index ranges within [0..N-2]. - N - size of matrix. N>=0. - ZNeeded - flag controlling whether the eigenvectors are needed or not. - If ZNeeded is equal to: - * 0, the eigenvectors are not needed; - * 1, the eigenvectors of a tridiagonal matrix are multiplied - by the square matrix Z. It is used if the - tridiagonal matrix is obtained by the similarity transformation - of a symmetric matrix. - * 2, the eigenvectors of a tridiagonal matrix replace - matrix Z. - I1, I2 - index interval for searching (from I1 to I2). - 0 <= I1 <= I2 <= N-1. - Z - if ZNeeded is equal to: - * 0, Z isn't used and remains unchanged; - * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) - which reduces the given symmetric matrix to tridiagonal form; - * 2, Z isn't used (but changed on the exit). - -Output parameters: - D - array of the eigenvalues found. - Array whose index ranges within [0..I2-I1]. - Z - if ZNeeded is equal to: - * 0, doesn't contain any information; - * 1, contains the product of a given NxN matrix Z (from the left) and - Nx(I2-I1) matrix of the eigenvectors found (from the right). - Array whose indexes range within [0..N-1, 0..I2-I1]. - * 2, contains the matrix of the eigenvalues found. - Array whose indexes range within [0..N-1, 0..I2-I1]. - - -Result: - - True, if successful. In that case, D contains the eigenvalues, - Z contains the eigenvectors (if needed). - It should be noted that the subroutine changes the size of arrays D and Z. - - False, if the bisection method subroutine wasn't able to find the eigenvalues - in the given interval or if the inverse iteration subroutine wasn't able - to find all the corresponding eigenvectors. In that case, the eigenvalues - and eigenvectors are not returned. - - -- ALGLIB -- - Copyright 25.12.2005 by Bochkanov Sergey -*************************************************************************/ -bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z); - - -/************************************************************************* -Finding eigenvalues and eigenvectors of a general matrix - -The algorithm finds eigenvalues and eigenvectors of a general matrix by -using the QR algorithm with multiple shifts. The algorithm can find -eigenvalues and both left and right eigenvectors. - -The right eigenvector is a vector x such that A*x = w*x, and the left -eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex -conjugate transposition of vector y). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - VNeeded - flag controlling whether eigenvectors are needed or not. - If VNeeded is equal to: - * 0, eigenvectors are not returned; - * 1, right eigenvectors are returned; - * 2, left eigenvectors are returned; - * 3, both left and right eigenvectors are returned. - -Output parameters: - WR - real parts of eigenvalues. - Array whose index ranges within [0..N-1]. - WR - imaginary parts of eigenvalues. - Array whose index ranges within [0..N-1]. - VL, VR - arrays of left and right eigenvectors (if they are needed). - If WI[i]=0, the respective eigenvalue is a real number, - and it corresponds to the column number I of matrices VL/VR. - If WI[i]>0, we have a pair of complex conjugate numbers with - positive and negative imaginary parts: - the first eigenvalue WR[i] + sqrt(-1)*WI[i]; - the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; - WI[i]>0 - WI[i+1] = -WI[i] < 0 - In that case, the eigenvector corresponding to the first - eigenvalue is located in i and i+1 columns of matrices - VL/VR (the column number i contains the real part, and the - column number i+1 contains the imaginary part), and the vector - corresponding to the second eigenvalue is a complex conjugate to - the first vector. - Arrays whose indexes range within [0..N-1, 0..N-1]. - -Result: - True, if the algorithm has converged. - False, if the algorithm has not converged. - -Note 1: - Some users may ask the following question: what if WI[N-1]>0? - WI[N] must contain an eigenvalue which is complex conjugate to the - N-th eigenvalue, but the array has only size N? - The answer is as follows: such a situation cannot occur because the - algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is - strictly less than N-1. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms of linear algebra). If you require maximum performance - on your machine, it is recommended to adjust this parameter manually. - - -See also the InternalTREVC subroutine. - -The algorithm is based on the LAPACK 3.0 library. -*************************************************************************/ -bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr); - -/************************************************************************* -Generation of a random uniformly distributed (Haar) orthogonal matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a); - - -/************************************************************************* -Generation of random NxN matrix with given condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); - - -/************************************************************************* -Generation of a random Haar distributed orthogonal complex matrix - -INPUT PARAMETERS: - N - matrix size, N>=1 - -OUTPUT PARAMETERS: - A - orthogonal NxN matrix, array[0..N-1,0..N-1] - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a); - - -/************************************************************************* -Generation of random NxN complex matrix with given condition number C and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); - - -/************************************************************************* -Generation of random NxN symmetric matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); - - -/************************************************************************* -Generation of random NxN symmetric positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random SPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a); - - -/************************************************************************* -Generation of random NxN Hermitian matrix with given condition number and -norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); - - -/************************************************************************* -Generation of random NxN Hermitian positive definite matrix with given -condition number and norm2(A)=1 - -INPUT PARAMETERS: - N - matrix size - C - condition number (in 2-norm) - -OUTPUT PARAMETERS: - A - random HPD matrix with norm2(A)=1 and cond(A)=C - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a); - - -/************************************************************************* -Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n); - - -/************************************************************************* -Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n); - - -/************************************************************************* -Multiplication of MxN complex matrix by NxN random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n); - - -/************************************************************************* -Multiplication of MxN complex matrix by MxM random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..M-1, 0..N-1] - M, N- matrix size - -OUTPUT PARAMETERS: - A - Q*A, where Q is random MxM orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n); - - -/************************************************************************* -Symmetric multiplication of NxN matrix by random Haar distributed -orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q'*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void smatrixrndmultiply(real_2d_array &a, const ae_int_t n); - - -/************************************************************************* -Hermitian multiplication of NxN matrix by random Haar distributed -complex orthogonal matrix - -INPUT PARAMETERS: - A - matrix, array[0..N-1, 0..N-1] - N - matrix size - -OUTPUT PARAMETERS: - A - Q^H*A*Q, where Q is random NxN orthogonal matrix - - -- ALGLIB routine -- - 04.12.2009 - Bochkanov Sergey -*************************************************************************/ -void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n); - -/************************************************************************* -LU decomposition of a general real matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. -It is optimized for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); - - -/************************************************************************* -LU decomposition of a general complex matrix with row pivoting - -A is represented as A = P*L*U, where: -* L is lower unitriangular matrix -* U is upper triangular matrix -* P = P0*P1*...*PK, K=min(M,N)-1, - Pi - permutation matrix for I and Pivots[I] - -This is cache-oblivous implementation of LU decomposition. It is optimized -for square matrices. As for rectangular matrices: -* best case - M>>N -* worst case - N>>M, small M, large N, matrix does not fit in CPU cache - -INPUT PARAMETERS: - A - array[0..M-1, 0..N-1]. - M - number of rows in matrix A. - N - number of columns in matrix A. - - -OUTPUT PARAMETERS: - A - matrices L and U in compact form: - * L is stored under main diagonal - * U is stored on and above main diagonal - Pivots - permutation matrix in compact form. - array[0..Min(M-1,N-1)]. - - -- ALGLIB routine -- - 10.01.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots); - - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a Hermitian positive- -definite matrix. The result of an algorithm is a representation of A as -A=U'*U or A=L*L' (here X' detones conj(X^T)). - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U'*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Cache-oblivious Cholesky decomposition - -The algorithm computes Cholesky decomposition of a symmetric positive- -definite matrix. The result of an algorithm is a representation of A as -A=U^T*U or A=L*L^T - -INPUT PARAMETERS: - A - upper or lower triangle of a factorized matrix. - array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - if IsUpper=True, then A contains an upper triangle of - a symmetric matrix, otherwise A contains a lower one. - -OUTPUT PARAMETERS: - A - the result of factorization. If IsUpper=True, then - the upper triangle contains matrix U, so that A = U^T*U, - and the elements below the main diagonal are not modified. - Similarly, if IsUpper = False. - -RESULT: - If the matrix is positive-definite, the function returns True. - Otherwise, the function returns False. Contents of A is not determined - in such case. - - -- ALGLIB routine -- - 15.12.2009 - Bochkanov Sergey -*************************************************************************/ -bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper); - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcond1(const real_2d_array &a, const ae_int_t n); - - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n); - - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - symmetric positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); - - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); - - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix. - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm of condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - A - Hermitian positive definite matrix which is given by its - upper or lower triangle depending on the value of - IsUpper. Array with elements [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - storage format. - -Result: - 1/LowerBound(cond(A)), if matrix A is positive definite, - -1, if matrix A is not positive definite, and its condition number - could not be found by this algorithm. - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Estimate of a matrix condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n); - - -/************************************************************************* -Estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n); - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n); - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the RMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n); - - -/************************************************************************* -Condition number estimate of a symmetric positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Condition number estimate of a Hermitian positive definite matrix given by -Cholesky decomposition. - -The algorithm calculates a lower bound of the condition number. In this -case, the algorithm does not return a lower bound of the condition number, -but an inverse number (to avoid an overflow in case of a singular matrix). - -It should be noted that 1-norm and inf-norm condition numbers of symmetric -matrices are equal, so the algorithm doesn't take into account the -differences between these types of norms. - -Input parameters: - CD - Cholesky decomposition of matrix A, - output of SMatrixCholesky subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper); - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n); - - -/************************************************************************* -Estimate of the condition number of a matrix given by its LU decomposition -(infinity norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - LUA - LU decomposition of a matrix in compact form. Output of - the CMatrixLU subroutine. - N - size of matrix A. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n); - - -/************************************************************************* -Triangular matrix: estimate of a condition number (1-norm) - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array[0..N-1, 0..N-1]. - N - size of A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); - - -/************************************************************************* -Triangular matrix: estimate of a matrix condition number (infinity-norm). - -The algorithm calculates a lower bound of the condition number. In this case, -the algorithm does not return a lower bound of the condition number, but an -inverse number (to avoid an overflow in case of a singular matrix). - -Input parameters: - A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - IsUpper - True, if the matrix is upper triangular. - IsUnit - True, if the matrix has a unit diagonal. - -Result: 1/LowerBound(cond(A)) - -NOTE: - if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, - 0.0 is returned in such cases. -*************************************************************************/ -double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit); - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of RMatrixLU subroutine). - Pivots - table of permutations - (the output of RMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code: - * -3 A is singular, or VERY close to singular. - it is filled by zeros in such cases. - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - A - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); -void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - -Result: - True, if the matrix is not singular. - False, if the matrix is singular. - - -- ALGLIB -- - Copyright 2005-2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinverse(real_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); -void rmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a matrix given by its LU decomposition. - -INPUT PARAMETERS: - A - LU decomposition of the matrix - (output of CMatrixLU subroutine). - Pivots - table of permutations - (the output of CMatrixLU subroutine). - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -OUTPUT PARAMETERS: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 05.02.2010 - Bochkanov Sergey -*************************************************************************/ -void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, ae_int_t &info, matinvreport &rep); -void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a general matrix. - -Input parameters: - A - matrix - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void cmatrixinverse(complex_2d_array &a, const ae_int_t n, ae_int_t &info, matinvreport &rep); -void cmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a symmetric positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of SPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); -void spdmatrixcholeskyinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a symmetric positive definite matrix. - -Given an upper or lower triangle of a symmetric positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); -void spdmatrixinverse(real_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a Hermitian positive definite matrix which is given -by Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition of the matrix to be inverted: - A=U’*U or A = L*L'. - Output of HPDMatrixCholesky subroutine. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, lower half is used. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); -void hpdmatrixcholeskyinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Inversion of a Hermitian positive definite matrix. - -Given an upper or lower triangle of a Hermitian positive definite matrix, -the algorithm generates matrix A^-1 and saves the upper or lower triangle -depending on the input. - -Input parameters: - A - matrix to be inverted (upper or lower triangle). - Array with elements [0..N-1,0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - storage type (optional): - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Output parameters: - Info - return code, same as in RMatrixLUInverse - Rep - solver report, same as in RMatrixLUInverse - A - inverse of matrix A, same as in RMatrixLUInverse - - -- ALGLIB routine -- - 10.02.2010 - Bochkanov Sergey -*************************************************************************/ -void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, ae_int_t &info, matinvreport &rep); -void hpdmatrixinverse(complex_2d_array &a, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Triangular matrix inverse (real) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); -void rmatrixtrinverse(real_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); - - -/************************************************************************* -Triangular matrix inverse (complex) - -The subroutine inverts the following types of matrices: - * upper triangular - * upper triangular with unit diagonal - * lower triangular - * lower triangular with unit diagonal - -In case of an upper (lower) triangular matrix, the inverse matrix will -also be upper (lower) triangular, and after the end of the algorithm, the -inverse matrix replaces the source matrix. The elements below (above) the -main diagonal are not changed by the algorithm. - -If the matrix has a unit diagonal, the inverse matrix also has a unit -diagonal, and the diagonal elements are not passed to the algorithm. - -Input parameters: - A - matrix, array[0..N-1, 0..N-1]. - N - size of matrix A (optional) : - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, size is automatically determined from - matrix size (A must be square matrix) - IsUpper - True, if the matrix is upper triangular. - IsUnit - diagonal type (optional): - * if True, matrix has unit diagonal (a[i,i] are NOT used) - * if False, matrix diagonal is arbitrary - * if not given, False is assumed - -Output parameters: - Info - same as for RMatrixLUInverse - Rep - same as for RMatrixLUInverse - A - same as for RMatrixLUInverse. - - -- ALGLIB -- - Copyright 05.02.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, ae_int_t &info, matinvreport &rep); -void cmatrixtrinverse(complex_2d_array &a, const bool isupper, ae_int_t &info, matinvreport &rep); - -/************************************************************************* -This function creates sparse matrix in a Hash-Table format. - -This function creates Hast-Table matrix, which can be converted to CRS -format after its initialization is over. Typical usage scenario for a -sparse matrix is: -1. creation in a Hash-Table format -2. insertion of the matrix elements -3. conversion to the CRS representation -4. matrix is passed to some linear algebra algorithm - -Some information about different matrix formats can be found below, in -the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - K - K>=0, expected number of non-zero elements in a matrix. - K can be inexact approximation, can be less than actual - number of elements (table will grow when needed) or - even zero). - It is important to understand that although hash-table - may grow automatically, it is better to provide good - estimate of data size. - -OUTPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - All elements of the matrix are zero. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s); -void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s); - - -/************************************************************************* -This function creates sparse matrix in a CRS format (expert function for -situations when you are running out of memory). - -This function creates CRS matrix. Typical usage scenario for a CRS matrix -is: -1. creation (you have to tell number of non-zero elements at each row at - this moment) -2. insertion of the matrix elements (row by row, from left to right) -3. matrix is passed to some linear algebra algorithm - -This function is a memory-efficient alternative to SparseCreate(), but it -is more complex because it requires you to know in advance how large your -matrix is. Some information about different matrix formats can be found -below, in the "NOTES" section. - -INPUT PARAMETERS - M - number of rows in a matrix, M>=1 - N - number of columns in a matrix, N>=1 - NER - number of elements at each row, array[M], NER[I]>=0 - -OUTPUT PARAMETERS - S - sparse M*N matrix in CRS representation. - You have to fill ALL non-zero elements by calling - SparseSet() BEFORE you try to use this matrix. - -NOTE 1. - -Sparse matrices can be stored using either Hash-Table representation or -Compressed Row Storage representation. Hast-table is better suited for -querying and dynamic operations (thus, it is used for matrix -initialization), but it is inefficient when you want to make some linear -algebra operations. - -From the other side, CRS is better suited for linear algebra operations, -but initialization is less convenient - you have to tell row sizes at the -initialization, and you can fill matrix only row by row, from left to -right. CRS is also very inefficient when you want to find matrix element -by its index. - -Thus, Hash-Table representation does not support linear algebra -operations, while CRS format does not support modification of the table. -Tables below outline information about these two formats: - - OPERATIONS WITH MATRIX HASH CRS - create + + - read element + + - modify element + - add value to element + - A*x (dense vector) + - A'*x (dense vector) + - A*X (dense matrix) + - A'*X (dense matrix) + - -NOTE 2. - -Hash-tables use memory inefficiently, and they have to keep some amount -of the "spare memory" in order to have good performance. Hash table for -matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, -where C is a small constant, about 1.5-2 in magnitude. - -CRS storage, from the other side, is more memory-efficient, and needs -just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows -in a matrix. - -When you convert from the Hash-Table to CRS representation, all unneeded -memory will be freed. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s); - - -/************************************************************************* -This function copies S0 to S1. - -NOTE: this function does not verify its arguments, it just copies all -fields of the structure. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsecopy(const sparsematrix &s0, sparsematrix &s1); - - -/************************************************************************* -This function adds value to S[i,j] - element of the sparse matrix. Matrix -must be in a Hash-Table mode. - -In case S[i,j] already exists in the table, V i added to its value. In -case S[i,j] is non-existent, it is inserted in the table. Table -automatically grows when necessary. - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table representation. - Exception will be thrown for CRS matrix. - I - row index of the element to modify, 0<=I=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - X - array[N], input vector. For performance reasons we - make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - Y - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - Y - array[M], S*x - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y); - - -/************************************************************************* -This function calculates matrix-matrix product S*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size - is at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b); - - -/************************************************************************* -This function calculates matrix-matrix product S^T*A. Matrix S must be -stored in CRS format (exception will be thrown otherwise). - -INPUT PARAMETERS - S - sparse M*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[M][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least M, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b); - - -/************************************************************************* -This function simultaneously calculates two matrix-matrix products: - S*A and S^T*A. -S must be square (non-rectangular) matrix stored in CRS format (exception -will be thrown otherwise). - -INPUT PARAMETERS - S - sparse N*N matrix in CRS format (you MUST convert it - to CRS before calling this function). - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B0 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - B1 - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B0 - array[N][K], S*A - B1 - array[N][K], S^T*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. It also throws exception when S is non-square. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1); - - -/************************************************************************* -This function calculates matrix-matrix product S*A, when S is symmetric -matrix. Matrix S must be stored in CRS format (exception will be -thrown otherwise). - -INPUT PARAMETERS - S - sparse M*M matrix in CRS format (you MUST convert it - to CRS before calling this function). - IsUpper - whether upper or lower triangle of S is given: - * if upper triangle is given, only S[i,j] for j>=i - are used, and lower triangle is ignored (it can be - empty - these elements are not referenced at all). - * if lower triangle is given, only S[i,j] for j<=i - are used, and upper triangle is ignored. - A - array[N][K], input dense matrix. For performance reasons - we make only quick checks - we check that array size is - at least N, but we do not check for NAN's or INF's. - K - number of columns of matrix (A). - B - output buffer, possibly preallocated. In case buffer - size is too small to store result, this buffer is - automatically resized. - -OUTPUT PARAMETERS - B - array[M][K], S*A - -NOTE: this function throws exception when called for non-CRS matrix. You -must convert your matrix with SparseConvertToCRS() before using this -function. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b); - - -/************************************************************************* -This procedure resizes Hash-Table matrix. It can be called when you have -deleted too many elements from the matrix, and you want to free unneeded -memory. - - -- ALGLIB PROJECT -- - Copyright 14.10.2011 by Bochkanov Sergey -*************************************************************************/ -void sparseresizematrix(const sparsematrix &s); - - -/************************************************************************* -This function is used to enumerate all elements of the sparse matrix. -Before first call user initializes T0 and T1 counters by zero. These -counters are used to remember current position in a matrix; after each -call they are updated by the function. - -Subsequent calls to this function return non-zero elements of the sparse -matrix, one by one. If you enumerate CRS matrix, matrix is traversed from -left to right, from top to bottom. In case you enumerate matrix stored as -Hash table, elements are returned in random order. - -EXAMPLE - > T0=0 - > T1=0 - > while SparseEnumerate(S,T0,T1,I,J,V) do - > ....do something with I,J,V - -INPUT PARAMETERS - S - sparse M*N matrix in Hash-Table or CRS representation. - T0 - internal counter - T1 - internal counter - -OUTPUT PARAMETERS - T0 - new value of the internal counter - T1 - new value of the internal counter - I - row index of non-zero element, 0<=I0 - N - number of columns in the matrix being estimated, N>0 - NStart - number of random starting vectors - recommended value - at least 5. - NIts - number of iterations to do with best starting vector - recommended value - at least 5. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTE: this algorithm is effectively deterministic, i.e. it always returns -same result when repeatedly called for the same matrix. In fact, algorithm -uses randomized starting vectors, but internal random numbers generator -always generates same sequence of the random values (it is a feature, not -bug). - -Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state); - - -/************************************************************************* -This function changes seed value used by algorithm. In some cases we need -deterministic processing, i.e. subsequent calls must return equal results, -in other cases we need non-deterministic algorithm which returns different -results for the same matrix on every pass. - -Setting zero seed will lead to non-deterministic algorithm, while non-zero -value will make our algorithm deterministic. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - SeedVal - seed value, >=0. Zero value = non-deterministic algo. - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorsetseed(const normestimatorstate &state, const ae_int_t seedval); - - -/************************************************************************* -This function estimates norm of the sparse M*N matrix A. - -INPUT PARAMETERS: - State - norm estimator state, must be initialized with a call - to NormEstimatorCreate() - A - sparse M*N matrix, must be converted to CRS format - prior to calling this function. - -After this function is over you can call NormEstimatorResults() to get -estimate of the norm(A). - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorestimatesparse(const normestimatorstate &state, const sparsematrix &a); - - -/************************************************************************* -Matrix norm estimation results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - Nrm - estimate of the matrix norm, Nrm>=0 - - -- ALGLIB -- - Copyright 06.12.2011 by Bochkanov Sergey -*************************************************************************/ -void normestimatorresults(const normestimatorstate &state, double &nrm); - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n); -double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots); - - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -double rmatrixdet(const real_2d_array &a, const ae_int_t n); -double rmatrixdet(const real_2d_array &a); - - -/************************************************************************* -Determinant calculation of the matrix given by its LU decomposition. - -Input parameters: - A - LU decomposition of the matrix (output of - RMatrixLU subroutine). - Pivots - table of permutations which were made during - the LU decomposition. - Output of RMatrixLU subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: matrix determinant. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n); -alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots); - - -/************************************************************************* -Calculation of the determinant of a general matrix - -Input parameters: - A - matrix, array[0..N-1, 0..N-1] - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -Result: determinant of matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n); -alglib::complex cmatrixdet(const complex_2d_array &a); - - -/************************************************************************* -Determinant calculation of the matrix given by the Cholesky decomposition. - -Input parameters: - A - Cholesky decomposition, - output of SMatrixCholesky subroutine. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - -As the determinant is equal to the product of squares of diagonal elements, -it’s not necessary to specify which triangle - lower or upper - the matrix -is stored in. - -Result: - matrix determinant. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n); -double spdmatrixcholeskydet(const real_2d_array &a); - - -/************************************************************************* -Determinant calculation of the symmetric positive definite matrix. - -Input parameters: - A - matrix. Array with elements [0..N-1, 0..N-1]. - N - (optional) size of matrix A: - * if given, only principal NxN submatrix is processed and - overwritten. other elements are unchanged. - * if not given, automatically determined from matrix size - (A must be square matrix) - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used/changed by - function - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used/changed by - function - * if not given, both lower and upper triangles must be - filled. - -Result: - determinant of matrix A. - If matrix A is not positive definite, exception is thrown. - - -- ALGLIB -- - Copyright 2005-2008 by Bochkanov Sergey -*************************************************************************/ -double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper); -double spdmatrixdet(const real_2d_array &a); - -/************************************************************************* -Algorithm for solving the following generalized symmetric positive-definite -eigenproblem: - A*x = lambda*B*x (1) or - A*B*x = lambda*x (2) or - B*A*x = lambda*x (3). -where A is a symmetric matrix, B - symmetric positive-definite matrix. -The problem is solved by reducing it to an ordinary symmetric eigenvalue -problem. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrices A and B. - IsUpperA - storage format of matrix A. - B - symmetric positive-definite matrix which is given by - its upper or lower triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperB - storage format of matrix B. - ZNeeded - if ZNeeded is equal to: - * 0, the eigenvectors are not returned; - * 1, the eigenvectors are returned. - ProblemType - if ProblemType is equal to: - * 1, the following problem is solved: A*x = lambda*B*x; - * 2, the following problem is solved: A*B*x = lambda*x; - * 3, the following problem is solved: B*A*x = lambda*x. - -Output parameters: - D - eigenvalues in ascending order. - Array whose index ranges within [0..N-1]. - Z - if ZNeeded is equal to: - * 0, Z hasn’t changed; - * 1, Z contains eigenvectors. - Array whose indexes range within [0..N-1, 0..N-1]. - The eigenvectors are stored in matrix columns. It should - be noted that the eigenvectors in such problems do not - form an orthogonal system. - -Result: - True, if the problem was solved successfully. - False, if the error occurred during the Cholesky decomposition of matrix - B (the matrix isn’t positive-definite) or during the work of the iterative - algorithm for solving the symmetric eigenproblem. - -See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. - - -- ALGLIB -- - Copyright 1.28.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z); - - -/************************************************************************* -Algorithm for reduction of the following generalized symmetric positive- -definite eigenvalue problem: - A*x = lambda*B*x (1) or - A*B*x = lambda*x (2) or - B*A*x = lambda*x (3) -to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and -the given problems are the same, and the eigenvectors of the given problem -could be obtained by multiplying the obtained eigenvectors by the -transformation matrix x = R*y). - -Here A is a symmetric matrix, B - symmetric positive-definite matrix. - -Input parameters: - A - symmetric matrix which is given by its upper or lower - triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrices A and B. - IsUpperA - storage format of matrix A. - B - symmetric positive-definite matrix which is given by - its upper or lower triangular part. - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperB - storage format of matrix B. - ProblemType - if ProblemType is equal to: - * 1, the following problem is solved: A*x = lambda*B*x; - * 2, the following problem is solved: A*B*x = lambda*x; - * 3, the following problem is solved: B*A*x = lambda*x. - -Output parameters: - A - symmetric matrix which is given by its upper or lower - triangle depending on IsUpperA. Contains matrix C. - Array whose indexes range within [0..N-1, 0..N-1]. - R - upper triangular or low triangular transformation matrix - which is used to obtain the eigenvectors of a given problem - as the product of eigenvectors of C (from the right) and - matrix R (from the left). If the matrix is upper - triangular, the elements below the main diagonal - are equal to 0 (and vice versa). Thus, we can perform - the multiplication without taking into account the - internal structure (which is an easier though less - effective way). - Array whose indexes range within [0..N-1, 0..N-1]. - IsUpperR - type of matrix R (upper or lower triangular). - -Result: - True, if the problem was reduced successfully. - False, if the error occurred during the Cholesky decomposition of - matrix B (the matrix is not positive-definite). - - -- ALGLIB -- - Copyright 1.28.2006 by Bochkanov Sergey -*************************************************************************/ -bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr); - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a number to an element -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - row where the element to be updated is stored. - UpdColumn - column where the element to be updated is stored. - UpdVal - a number to be added to the element. - - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval); - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a row -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdRow - the row of A whose vector V was added. - 0 <= Row <= N-1 - V - the vector to be added to a row. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v); - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm updates matrix A^-1 when adding a vector to a column -of matrix A. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - UpdColumn - the column of A whose vector U was added. - 0 <= UpdColumn <= N-1 - U - the vector to be added to a column. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of modified matrix A. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u); - - -/************************************************************************* -Inverse matrix update by the Sherman-Morrison formula - -The algorithm computes the inverse of matrix A+u*v’ by using the given matrix -A^-1 and the vectors u and v. - -Input parameters: - InvA - inverse of matrix A. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of matrix A. - U - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - V - the vector modifying the matrix. - Array whose index ranges within [0..N-1]. - -Output parameters: - InvA - inverse of matrix A + u*v'. - - -- ALGLIB -- - Copyright 2005 by Bochkanov Sergey -*************************************************************************/ -void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v); - -/************************************************************************* -Subroutine performing the Schur decomposition of a general matrix by using -the QR algorithm with multiple shifts. - -The source matrix A is represented as S'*A*S = T, where S is an orthogonal -matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of -sizes 1x1 and 2x2 on the main diagonal). - -Input parameters: - A - matrix to be decomposed. - Array whose indexes range within [0..N-1, 0..N-1]. - N - size of A, N>=0. - - -Output parameters: - A - contains matrix T. - Array whose indexes range within [0..N-1, 0..N-1]. - S - contains Schur vectors. - Array whose indexes range within [0..N-1, 0..N-1]. - -Note 1: - The block structure of matrix T can be easily recognized: since all - the elements below the blocks are zeros, the elements a[i+1,i] which - are equal to 0 show the block border. - -Note 2: - The algorithm performance depends on the value of the internal parameter - NS of the InternalSchurDecomposition subroutine which defines the number - of shifts in the QR algorithm (similarly to the block width in block-matrix - algorithms in linear algebra). If you require maximum performance on - your machine, it is recommended to adjust this parameter manually. - -Result: - True, - if the algorithm has converged and parameters A and S contain the result. - False, - if the algorithm has not converged. - -Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). -*************************************************************************/ -bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void ablassplitlength(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state); -void ablascomplexsplitlength(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t* n1, - ae_int_t* n2, - ae_state *_state); -ae_int_t ablasblocksize(/* Real */ ae_matrix* a, ae_state *_state); -ae_int_t ablascomplexblocksize(/* Complex */ ae_matrix* a, - ae_state *_state); -ae_int_t ablasmicroblocksize(ae_state *_state); -void cmatrixtranspose(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state); -void rmatrixtranspose(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state); -void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -void cmatrixcopy(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state); -void rmatrixcopy(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_state *_state); -void cmatrixrank1(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Complex */ ae_vector* u, - ae_int_t iu, - /* Complex */ ae_vector* v, - ae_int_t iv, - ae_state *_state); -void rmatrixrank1(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - /* Real */ ae_vector* u, - ae_int_t iu, - /* Real */ ae_vector* v, - ae_int_t iv, - ae_state *_state); -void cmatrixmv(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Complex */ ae_vector* x, - ae_int_t ix, - /* Complex */ ae_vector* y, - ae_int_t iy, - ae_state *_state); -void rmatrixmv(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t opa, - /* Real */ ae_vector* x, - ae_int_t ix, - /* Real */ ae_vector* y, - ae_int_t iy, - ae_state *_state); -void cmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -void _pexec_cmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state); -void cmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -void _pexec_cmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Complex */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state); -void rmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -void _pexec_rmatrixrighttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state); -void rmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, - ae_state *_state); -void _pexec_rmatrixlefttrsm(ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_int_t i1, - ae_int_t j1, - ae_bool isupper, - ae_bool isunit, - ae_int_t optype, - /* Real */ ae_matrix* x, - ae_int_t i2, - ae_int_t j2, ae_state *_state); -void cmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -void _pexec_cmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, ae_state *_state); -void rmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, - ae_state *_state); -void _pexec_rmatrixsyrk(ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_bool isupper, ae_state *_state); -void cmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void _pexec_cmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - ae_complex alpha, - /* Complex */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Complex */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - ae_complex beta, - /* Complex */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, ae_state *_state); -void rmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, - ae_state *_state); -void _pexec_rmatrixgemm(ae_int_t m, - ae_int_t n, - ae_int_t k, - double alpha, - /* Real */ ae_matrix* a, - ae_int_t ia, - ae_int_t ja, - ae_int_t optypea, - /* Real */ ae_matrix* b, - ae_int_t ib, - ae_int_t jb, - ae_int_t optypeb, - double beta, - /* Real */ ae_matrix* c, - ae_int_t ic, - ae_int_t jc, ae_state *_state); -void rmatrixqr(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state); -void rmatrixlq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state); -void cmatrixqr(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_state *_state); -void cmatrixlq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_state *_state); -void rmatrixqrunpackq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_int_t qcolumns, - /* Real */ ae_matrix* q, - ae_state *_state); -void rmatrixqrunpackr(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* r, - ae_state *_state); -void rmatrixlqunpackq(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_int_t qrows, - /* Real */ ae_matrix* q, - ae_state *_state); -void rmatrixlqunpackl(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_matrix* l, - ae_state *_state); -void cmatrixqrunpackq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_int_t qcolumns, - /* Complex */ ae_matrix* q, - ae_state *_state); -void cmatrixqrunpackr(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* r, - ae_state *_state); -void cmatrixlqunpackq(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_vector* tau, - ae_int_t qrows, - /* Complex */ ae_matrix* q, - ae_state *_state); -void cmatrixlqunpackl(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Complex */ ae_matrix* l, - ae_state *_state); -void rmatrixqrbasecase(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* work, - /* Real */ ae_vector* t, - /* Real */ ae_vector* tau, - ae_state *_state); -void rmatrixlqbasecase(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* work, - /* Real */ ae_vector* t, - /* Real */ ae_vector* tau, - ae_state *_state); -void rmatrixbd(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - /* Real */ ae_vector* taup, - ae_state *_state); -void rmatrixbdunpackq(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - ae_int_t qcolumns, - /* Real */ ae_matrix* q, - ae_state *_state); -void rmatrixbdmultiplybyq(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tauq, - /* Real */ ae_matrix* z, - ae_int_t zrows, - ae_int_t zcolumns, - ae_bool fromtheright, - ae_bool dotranspose, - ae_state *_state); -void rmatrixbdunpackpt(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* taup, - ae_int_t ptrows, - /* Real */ ae_matrix* pt, - ae_state *_state); -void rmatrixbdmultiplybyp(/* Real */ ae_matrix* qp, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* taup, - /* Real */ ae_matrix* z, - ae_int_t zrows, - ae_int_t zcolumns, - ae_bool fromtheright, - ae_bool dotranspose, - ae_state *_state); -void rmatrixbdunpackdiagonals(/* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t n, - ae_bool* isupper, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state); -void rmatrixhessenberg(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - ae_state *_state); -void rmatrixhessenbergunpackq(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state); -void rmatrixhessenbergunpackh(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* h, - ae_state *_state); -void smatrixtd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tau, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state); -void smatrixtdunpackq(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tau, - /* Real */ ae_matrix* q, - ae_state *_state); -void hmatrixtd(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tau, - /* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_state *_state); -void hmatrixtdunpackq(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* tau, - /* Complex */ ae_matrix* q, - ae_state *_state); -ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t ncvt, - ae_state *_state); -ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_bool isupper, - ae_bool isfractionalaccuracyrequired, - /* Real */ ae_matrix* u, - ae_int_t nru, - /* Real */ ae_matrix* c, - ae_int_t ncc, - /* Real */ ae_matrix* vt, - ae_int_t ncvt, - ae_state *_state); -ae_bool rmatrixsvd(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_int_t uneeded, - ae_int_t vtneeded, - ae_int_t additionalmemory, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* u, - /* Real */ ae_matrix* vt, - ae_state *_state); -ae_bool smatrixevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - /* Real */ ae_vector* d, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixevdr(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - double b1, - double b2, - ae_int_t* m, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixevdi(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* w, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool hmatrixevd(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - /* Real */ ae_vector* d, - /* Complex */ ae_matrix* z, - ae_state *_state); -ae_bool hmatrixevdr(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - double b1, - double b2, - ae_int_t* m, - /* Real */ ae_vector* w, - /* Complex */ ae_matrix* z, - ae_state *_state); -ae_bool hmatrixevdi(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t zneeded, - ae_bool isupper, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_vector* w, - /* Complex */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixtdevd(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixtdevdr(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - double a, - double b, - ae_int_t* m, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixtdevdi(/* Real */ ae_vector* d, - /* Real */ ae_vector* e, - ae_int_t n, - ae_int_t zneeded, - ae_int_t i1, - ae_int_t i2, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool rmatrixevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t vneeded, - /* Real */ ae_vector* wr, - /* Real */ ae_vector* wi, - /* Real */ ae_matrix* vl, - /* Real */ ae_matrix* vr, - ae_state *_state); -void rmatrixrndorthogonal(ae_int_t n, - /* Real */ ae_matrix* a, - ae_state *_state); -void rmatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state); -void cmatrixrndorthogonal(ae_int_t n, - /* Complex */ ae_matrix* a, - ae_state *_state); -void cmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state); -void smatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state); -void spdmatrixrndcond(ae_int_t n, - double c, - /* Real */ ae_matrix* a, - ae_state *_state); -void hmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state); -void hpdmatrixrndcond(ae_int_t n, - double c, - /* Complex */ ae_matrix* a, - ae_state *_state); -void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - ae_state *_state); -void smatrixrndmultiply(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -void hmatrixrndmultiply(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -void rmatrixlu(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -void cmatrixlu(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -ae_bool hpdmatrixcholesky(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -ae_bool spdmatrixcholesky(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -void rmatrixlup(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -void cmatrixlup(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -void rmatrixplu(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -void cmatrixplu(/* Complex */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* pivots, - ae_state *_state); -ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, - ae_int_t offs, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* tmp, - ae_state *_state); -double rmatrixrcond1(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double rmatrixrcondinf(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double spdmatrixrcond(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -double rmatrixtrrcond1(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state); -double rmatrixtrrcondinf(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state); -double hpdmatrixrcond(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -double cmatrixrcond1(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double cmatrixrcondinf(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double rmatrixlurcond1(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_state *_state); -double rmatrixlurcondinf(/* Real */ ae_matrix* lua, - ae_int_t n, - ae_state *_state); -double spdmatrixcholeskyrcond(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -double hpdmatrixcholeskyrcond(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -double cmatrixlurcond1(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_state *_state); -double cmatrixlurcondinf(/* Complex */ ae_matrix* lua, - ae_int_t n, - ae_state *_state); -double cmatrixtrrcond1(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state); -double cmatrixtrrcondinf(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_state *_state); -double rcondthreshold(ae_state *_state); -void rmatrixluinverse(/* Real */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void rmatrixinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void cmatrixluinverse(/* Complex */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void cmatrixinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void spdmatrixinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void hpdmatrixinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void rmatrixtrinverse(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -void cmatrixtrinverse(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_bool isunit, - ae_int_t* info, - matinvreport* rep, - ae_state *_state); -ae_bool _matinvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _matinvreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _matinvreport_clear(void* _p); -void _matinvreport_destroy(void* _p); -void sparsecreate(ae_int_t m, - ae_int_t n, - ae_int_t k, - sparsematrix* s, - ae_state *_state); -void sparsecreatecrs(ae_int_t m, - ae_int_t n, - /* Integer */ ae_vector* ner, - sparsematrix* s, - ae_state *_state); -void sparsecopy(sparsematrix* s0, sparsematrix* s1, ae_state *_state); -void sparseadd(sparsematrix* s, - ae_int_t i, - ae_int_t j, - double v, - ae_state *_state); -void sparseset(sparsematrix* s, - ae_int_t i, - ae_int_t j, - double v, - ae_state *_state); -double sparseget(sparsematrix* s, - ae_int_t i, - ae_int_t j, - ae_state *_state); -double sparsegetdiagonal(sparsematrix* s, ae_int_t i, ae_state *_state); -void sparseconverttocrs(sparsematrix* s, ae_state *_state); -void sparsemv(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void sparsemtv(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void sparsemv2(sparsematrix* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y0, - /* Real */ ae_vector* y1, - ae_state *_state); -void sparsesmv(sparsematrix* s, - ae_bool isupper, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -void sparsemm(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state); -void sparsemtm(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state); -void sparsemm2(sparsematrix* s, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b0, - /* Real */ ae_matrix* b1, - ae_state *_state); -void sparsesmm(sparsematrix* s, - ae_bool isupper, - /* Real */ ae_matrix* a, - ae_int_t k, - /* Real */ ae_matrix* b, - ae_state *_state); -void sparseresizematrix(sparsematrix* s, ae_state *_state); -double sparsegetaveragelengthofchain(sparsematrix* s, ae_state *_state); -ae_bool sparseenumerate(sparsematrix* s, - ae_int_t* t0, - ae_int_t* t1, - ae_int_t* i, - ae_int_t* j, - double* v, - ae_state *_state); -ae_bool sparserewriteexisting(sparsematrix* s, - ae_int_t i, - ae_int_t j, - double v, - ae_state *_state); -void sparsegetrow(sparsematrix* s, - ae_int_t i, - /* Real */ ae_vector* irow, - ae_state *_state); -void sparseconverttohash(sparsematrix* s, ae_state *_state); -void sparsecopytohash(sparsematrix* s0, - sparsematrix* s1, - ae_state *_state); -void sparsecopytocrs(sparsematrix* s0, sparsematrix* s1, ae_state *_state); -ae_int_t sparsegetmatrixtype(sparsematrix* s, ae_state *_state); -ae_bool sparseishash(sparsematrix* s, ae_state *_state); -ae_bool sparseiscrs(sparsematrix* s, ae_state *_state); -void sparsefree(sparsematrix* s, ae_state *_state); -ae_int_t sparsegetnrows(sparsematrix* s, ae_state *_state); -ae_int_t sparsegetncols(sparsematrix* s, ae_state *_state); -ae_bool _sparsematrix_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sparsematrix_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sparsematrix_clear(void* _p); -void _sparsematrix_destroy(void* _p); -void fblscholeskysolve(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state); -void fblssolvecgx(/* Real */ ae_matrix* a, - ae_int_t m, - ae_int_t n, - double alpha, - /* Real */ ae_vector* b, - /* Real */ ae_vector* x, - /* Real */ ae_vector* buf, - ae_state *_state); -void fblscgcreate(/* Real */ ae_vector* x, - /* Real */ ae_vector* b, - ae_int_t n, - fblslincgstate* state, - ae_state *_state); -ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state); -void fblssolvels(/* Real */ ae_matrix* a, - /* Real */ ae_vector* b, - ae_int_t m, - ae_int_t n, - /* Real */ ae_vector* tmp0, - /* Real */ ae_vector* tmp1, - /* Real */ ae_vector* tmp2, - ae_state *_state); -ae_bool _fblslincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _fblslincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _fblslincgstate_clear(void* _p); -void _fblslincgstate_destroy(void* _p); -void normestimatorcreate(ae_int_t m, - ae_int_t n, - ae_int_t nstart, - ae_int_t nits, - normestimatorstate* state, - ae_state *_state); -void normestimatorsetseed(normestimatorstate* state, - ae_int_t seedval, - ae_state *_state); -ae_bool normestimatoriteration(normestimatorstate* state, - ae_state *_state); -void normestimatorestimatesparse(normestimatorstate* state, - sparsematrix* a, - ae_state *_state); -void normestimatorresults(normestimatorstate* state, - double* nrm, - ae_state *_state); -void normestimatorrestart(normestimatorstate* state, ae_state *_state); -ae_bool _normestimatorstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _normestimatorstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _normestimatorstate_clear(void* _p); -void _normestimatorstate_destroy(void* _p); -double rmatrixludet(/* Real */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_state *_state); -double rmatrixdet(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -ae_complex cmatrixludet(/* Complex */ ae_matrix* a, - /* Integer */ ae_vector* pivots, - ae_int_t n, - ae_state *_state); -ae_complex cmatrixdet(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double spdmatrixcholeskydet(/* Real */ ae_matrix* a, - ae_int_t n, - ae_state *_state); -double spdmatrixdet(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - ae_state *_state); -ae_bool smatrixgevd(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isuppera, - /* Real */ ae_matrix* b, - ae_bool isupperb, - ae_int_t zneeded, - ae_int_t problemtype, - /* Real */ ae_vector* d, - /* Real */ ae_matrix* z, - ae_state *_state); -ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isuppera, - /* Real */ ae_matrix* b, - ae_bool isupperb, - ae_int_t problemtype, - /* Real */ ae_matrix* r, - ae_bool* isupperr, - ae_state *_state); -void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updrow, - ae_int_t updcolumn, - double updval, - ae_state *_state); -void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updrow, - /* Real */ ae_vector* v, - ae_state *_state); -void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, - ae_int_t n, - ae_int_t updcolumn, - /* Real */ ae_vector* u, - ae_state *_state); -void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, - ae_int_t n, - /* Real */ ae_vector* u, - /* Real */ ae_vector* v, - ae_state *_state); -ae_bool rmatrixschur(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* s, - ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _linalg_pkg_h +#define _linalg_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector d; + ae_vector u; + sparsematrix s; +} sparsebuffers; +#endif +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t k; + ae_int_t nwork; + ae_int_t maxits; + double eps; + ae_int_t eigenvectorsneeded; + ae_int_t solvermode; + ae_bool usewarmstart; + ae_bool firstcall; + hqrndstate rs; + ae_bool running; + ae_vector tau; + ae_matrix q0; + ae_matrix qcur; + ae_matrix qnew; + ae_matrix znew; + ae_matrix r; + ae_matrix rz; + ae_matrix tz; + ae_matrix rq; + ae_matrix dummy; + ae_vector rw; + ae_vector tw; + ae_vector tmprow; + ae_vector wcur; + ae_vector wprev; + ae_vector wrank; + apbuffers buf; + ae_matrix x; + ae_matrix ax; + ae_int_t requesttype; + ae_int_t requestsize; + ae_int_t repiterationscount; + rcommstate rstate; +} eigsubspacestate; +typedef struct +{ + ae_int_t iterationscount; +} eigsubspacereport; +#endif +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t nfixed; + ae_int_t ndynamic; + ae_vector idxfirst; + ae_vector strgidx; + ae_vector strgval; + ae_int_t nallocated; + ae_int_t nused; +} sluv2list1matrix; +typedef struct +{ + ae_int_t n; + ae_int_t k; + ae_vector nzc; + ae_int_t maxwrkcnt; + ae_int_t maxwrknz; + ae_int_t wrkcnt; + ae_vector wrkset; + ae_vector colid; + ae_vector isdensified; + ae_vector slscolptr; + ae_vector slsrowptr; + ae_vector slsidx; + ae_vector slsval; + ae_int_t slsused; + ae_vector tmp0; +} sluv2sparsetrail; +typedef struct +{ + ae_int_t n; + ae_int_t ndense; + ae_matrix d; + ae_vector did; +} sluv2densetrail; +typedef struct +{ + ae_int_t n; + sparsematrix sparsel; + sparsematrix sparseut; + sluv2list1matrix bleft; + sluv2list1matrix bupper; + sluv2sparsetrail strail; + sluv2densetrail dtrail; + ae_vector rowpermrawidx; + ae_matrix dbuf; + ae_vector v0i; + ae_vector v1i; + ae_vector v0r; + ae_vector v1r; + ae_vector tmp0; + ae_vector tmpi; + ae_vector tmpp; +} sluv2buffer; +#endif +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t k; + ae_int_t n; + ae_vector flagarray; + ae_vector vbegin; + ae_vector vallocated; + ae_vector vcnt; + ae_vector data; + ae_int_t dataused; + ae_int_t iterrow; + ae_int_t iteridx; +} amdknset; +typedef struct +{ + ae_int_t n; + ae_bool checkexactdegrees; + ae_int_t smallestdegree; + ae_vector approxd; + ae_vector optionalexactd; + ae_vector isvertex; + ae_vector eligible; + ae_vector vbegin; + ae_vector vprev; + ae_vector vnext; +} amdvertexset; +typedef struct +{ + ae_int_t n; + ae_vector vbegin; + ae_vector vcolcnt; + ae_vector entries; + ae_int_t entriesinitialized; +} amdllmatrix; +typedef struct +{ + ae_int_t n; + ae_bool extendeddebug; + ae_bool checkexactdegrees; + ae_vector iseliminated; + ae_vector issupernode; + ae_vector iseligible; + amdknset setsuper; + amdknset seta; + amdknset sete; + amdllmatrix mtxl; + amdvertexset vertexdegrees; + niset setq; + ae_vector perm; + ae_vector invperm; + ae_vector columnswaps; + niset setp; + niset lp; + niset setrp; + niset ep; + niset adji; + niset adjj; + ae_vector ls; + ae_int_t lscnt; + niset setqsupercand; + niset exactdegreetmp0; + amdknset hashbuckets; + niset nonemptybuckets; + ae_vector sncandidates; + ae_vector tmp0; + ae_vector arrwe; + ae_matrix dbga; +} amdbuffer; +#endif +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector tmpperm; + ae_vector invtmpperm; + amdbuffer amdtmp; + sparsematrix tmpa2; + sparsematrix tmpbottomt; + sparsematrix tmpupdate; + sparsematrix tmpupdatet; + sparsematrix tmpnewtailt; +} priorityamdbuffers; +typedef struct +{ + ae_vector rowbegin; + ae_vector rowend; + ae_vector idx; + ae_vector urow0; + ae_vector uwidth; + ae_vector uflop; + ae_vector nflop; + ae_vector sflop; +} spcholadj; +typedef struct +{ + ae_int_t tasktype; + ae_int_t n; + ae_bool unitd; + ae_bool dotrace; + ae_bool pblrequested; + ae_bool pblused; + ae_opaque_object pbl; + ae_bool pblneedsl; + sparsematrix pbla; + ae_bool pblachanged; + ae_vector fillinperm; + ae_vector invfillinperm; + ae_vector effectiveperm; + ae_vector inveffectiveperm; + ae_int_t permtype; + ae_int_t modtype; + double modparam0; + double modparam1; + double modparam2; + double modparam3; + ae_vector bsigns; + ae_bool debugblocksupernodal; + ae_bool extendeddebug; + ae_bool dotracescheduler; + ae_bool dotracesupernodalstructure; + ae_vector rpivotsigns; + ae_vector referenceridx; + ae_int_t nsuper; + ae_vector parentsupernode; + ae_vector childsupernodesridx; + ae_vector childsupernodesidx; + ae_vector supercolrange; + ae_vector superrowridx; + ae_vector superrowidx; + ae_bool useparallelism; + ae_vector superperm; + ae_vector invsuperperm; + ae_bool istopologicalordering; + ae_bool applypermutationtooutput; + spcholadj ladj; + ae_vector outrowcounts; + ae_vector inputstorage; + ae_vector outputstorage; + ae_vector rowstrides; + ae_vector rowoffsets; + ae_vector diagd; + ae_nxpool n1booleanpool; + ae_nxpool ns1booleanpool; + ae_nxpool n1integerpool; + ae_nxpool ns1integerpool; + ae_nxpool nrealpool; + ae_nxpool ns1realpool; + ae_vector curladjrowbegin; + ae_vector flagarray; + ae_vector curpriorities; + ae_vector tmpparent; + ae_vector node2supernode; + ae_smart_ptr _ptramdtmp; + amdbuffer *ptramdtmp; + ae_smart_ptr _ptrpamdtmp; + priorityamdbuffers *ptrpamdtmp; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmp3; + ae_vector tmp4; + ae_vector raw2smap; + sparsematrix tmpa; + sparsematrix tmpat; + ae_vector tmpx; + ae_vector simdbuf; +} spcholanalysis; +#endif +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t facttype; + ae_int_t permtype; + spcholanalysis analysis; + sparsematrix wrka; + sparsematrix wrkat; + sparsematrix crsa; + sparsematrix crsat; +} sparsedecompositionanalysis; +#endif +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double e1; + double e2; + ae_vector x; + ae_vector ax; + double xax; + ae_int_t n; + ae_vector rk; + ae_vector rk1; + ae_vector xk; + ae_vector xk1; + ae_vector pk; + ae_vector pk1; + ae_vector b; + rcommstate rstate; + ae_vector tmp2; +} fblslincgstate; +typedef struct +{ + ae_vector b; + ae_vector x; + ae_vector ax; + ae_vector xs; + ae_matrix qi; + ae_matrix aqi; + ae_matrix h; + ae_matrix hq; + ae_matrix hr; + ae_vector hqb; + ae_vector ys; + ae_vector tmp0; + ae_vector tmp1; + ae_int_t n; + ae_int_t itscnt; + double epsort; + double epsres; + double epsred; + double epsdiag; + ae_int_t itsperformed; + ae_int_t retcode; + double reprelres; + rcommstate rstate; +} fblsgmresstate; +#endif +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_int_t nstart; + ae_int_t nits; + ae_int_t seedval; + ae_vector x0; + ae_vector x1; + ae_vector t; + ae_vector xbest; + hqrndstate r; + ae_vector x; + ae_vector mv; + ae_vector mtv; + ae_bool needmv; + ae_bool needmtv; + double repnorm; + rcommstate rstate; +} normestimatorstate; +#endif +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t terminationtype; + double r1; + double rinf; +} matinvreport; +#endif +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +class _sparsebuffers_owner; +class sparsebuffers; + + +/************************************************************************* +Temporary buffers for sparse matrix operations. + +You should pass an instance of this structure to factorization functions. +It allows to reuse memory during repeated sparse factorizations. You do +not have to call some initialization function - simply passing an instance +to factorization function is enough. +*************************************************************************/ +class _sparsebuffers_owner +{ +public: + _sparsebuffers_owner(); + _sparsebuffers_owner(alglib_impl::sparsebuffers *attach_to); + _sparsebuffers_owner(const _sparsebuffers_owner &rhs); + _sparsebuffers_owner& operator=(const _sparsebuffers_owner &rhs); + virtual ~_sparsebuffers_owner(); + alglib_impl::sparsebuffers* c_ptr(); + const alglib_impl::sparsebuffers* c_ptr() const; +protected: + alglib_impl::sparsebuffers *p_struct; + bool is_attached; +}; +class sparsebuffers : public _sparsebuffers_owner +{ +public: + sparsebuffers(); + sparsebuffers(alglib_impl::sparsebuffers *attach_to); + sparsebuffers(const sparsebuffers &rhs); + sparsebuffers& operator=(const sparsebuffers &rhs); + virtual ~sparsebuffers(); + + +}; +#endif + +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +class _eigsubspacestate_owner; +class eigsubspacestate; +class _eigsubspacereport_owner; +class eigsubspacereport; + + +/************************************************************************* +This object stores state of the subspace iteration algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _eigsubspacestate_owner +{ +public: + _eigsubspacestate_owner(); + _eigsubspacestate_owner(alglib_impl::eigsubspacestate *attach_to); + _eigsubspacestate_owner(const _eigsubspacestate_owner &rhs); + _eigsubspacestate_owner& operator=(const _eigsubspacestate_owner &rhs); + virtual ~_eigsubspacestate_owner(); + alglib_impl::eigsubspacestate* c_ptr(); + const alglib_impl::eigsubspacestate* c_ptr() const; +protected: + alglib_impl::eigsubspacestate *p_struct; + bool is_attached; +}; +class eigsubspacestate : public _eigsubspacestate_owner +{ +public: + eigsubspacestate(); + eigsubspacestate(alglib_impl::eigsubspacestate *attach_to); + eigsubspacestate(const eigsubspacestate &rhs); + eigsubspacestate& operator=(const eigsubspacestate &rhs); + virtual ~eigsubspacestate(); + + +}; + + +/************************************************************************* +This object stores state of the subspace iteration algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _eigsubspacereport_owner +{ +public: + _eigsubspacereport_owner(); + _eigsubspacereport_owner(alglib_impl::eigsubspacereport *attach_to); + _eigsubspacereport_owner(const _eigsubspacereport_owner &rhs); + _eigsubspacereport_owner& operator=(const _eigsubspacereport_owner &rhs); + virtual ~_eigsubspacereport_owner(); + alglib_impl::eigsubspacereport* c_ptr(); + const alglib_impl::eigsubspacereport* c_ptr() const; +protected: + alglib_impl::eigsubspacereport *p_struct; + bool is_attached; +}; +class eigsubspacereport : public _eigsubspacereport_owner +{ +public: + eigsubspacereport(); + eigsubspacereport(alglib_impl::eigsubspacereport *attach_to); + eigsubspacereport(const eigsubspacereport &rhs); + eigsubspacereport& operator=(const eigsubspacereport &rhs); + virtual ~eigsubspacereport(); + ae_int_t &iterationscount; + + +}; +#endif + +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +class _sparsedecompositionanalysis_owner; +class sparsedecompositionanalysis; + + +/************************************************************************* +An analysis of the sparse matrix decomposition, performed prior to actual +numerical factorization. You should not directly access fields of this +object - use appropriate ALGLIB functions to work with this object. +*************************************************************************/ +class _sparsedecompositionanalysis_owner +{ +public: + _sparsedecompositionanalysis_owner(); + _sparsedecompositionanalysis_owner(alglib_impl::sparsedecompositionanalysis *attach_to); + _sparsedecompositionanalysis_owner(const _sparsedecompositionanalysis_owner &rhs); + _sparsedecompositionanalysis_owner& operator=(const _sparsedecompositionanalysis_owner &rhs); + virtual ~_sparsedecompositionanalysis_owner(); + alglib_impl::sparsedecompositionanalysis* c_ptr(); + const alglib_impl::sparsedecompositionanalysis* c_ptr() const; +protected: + alglib_impl::sparsedecompositionanalysis *p_struct; + bool is_attached; +}; +class sparsedecompositionanalysis : public _sparsedecompositionanalysis_owner +{ +public: + sparsedecompositionanalysis(); + sparsedecompositionanalysis(alglib_impl::sparsedecompositionanalysis *attach_to); + sparsedecompositionanalysis(const sparsedecompositionanalysis &rhs); + sparsedecompositionanalysis& operator=(const sparsedecompositionanalysis &rhs); + virtual ~sparsedecompositionanalysis(); + + +}; +#endif + +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) +class _normestimatorstate_owner; +class normestimatorstate; + + +/************************************************************************* +This object stores state of the iterative norm estimation algorithm. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _normestimatorstate_owner +{ +public: + _normestimatorstate_owner(); + _normestimatorstate_owner(alglib_impl::normestimatorstate *attach_to); + _normestimatorstate_owner(const _normestimatorstate_owner &rhs); + _normestimatorstate_owner& operator=(const _normestimatorstate_owner &rhs); + virtual ~_normestimatorstate_owner(); + alglib_impl::normestimatorstate* c_ptr(); + const alglib_impl::normestimatorstate* c_ptr() const; +protected: + alglib_impl::normestimatorstate *p_struct; + bool is_attached; +}; +class normestimatorstate : public _normestimatorstate_owner +{ +public: + normestimatorstate(); + normestimatorstate(alglib_impl::normestimatorstate *attach_to); + normestimatorstate(const normestimatorstate &rhs); + normestimatorstate& operator=(const normestimatorstate &rhs); + virtual ~normestimatorstate(); + + +}; +#endif + +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +class _matinvreport_owner; +class matinvreport; + + +/************************************************************************* +Matrix inverse report: +* terminationtype completion code: + * 1 for success + * -3 for failure due to the matrix being singular or + nearly-singular +* r1 reciprocal of condition number in 1-norm +* rinf reciprocal of condition number in inf-norm +*************************************************************************/ +class _matinvreport_owner +{ +public: + _matinvreport_owner(); + _matinvreport_owner(alglib_impl::matinvreport *attach_to); + _matinvreport_owner(const _matinvreport_owner &rhs); + _matinvreport_owner& operator=(const _matinvreport_owner &rhs); + virtual ~_matinvreport_owner(); + alglib_impl::matinvreport* c_ptr(); + const alglib_impl::matinvreport* c_ptr() const; +protected: + alglib_impl::matinvreport *p_struct; + bool is_attached; +}; +class matinvreport : public _matinvreport_owner +{ +public: + matinvreport(); + matinvreport(alglib_impl::matinvreport *attach_to); + matinvreport(const matinvreport &rhs); + matinvreport& operator=(const matinvreport &rhs); + virtual ~matinvreport(); + ae_int_t &terminationtype; + double &r1; + double &rinf; + + +}; +#endif + +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Cache-oblivous complex "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixtranspose(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cache-oblivous real "copy-and-transpose" + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied and transposed + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixtranspose(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This code enforces symmetricy of the matrix by copying Upper part to lower +one (or vice versa). + +INPUT PARAMETERS: + A - matrix + N - number of rows/columns + IsUpper - whether we want to copy upper triangle to lower one (True) + or vice versa (False). +*************************************************************************/ +void rmatrixenforcesymmetricity(real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void cmatrixcopy(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Copy + +Input parameters: + N - subvector size + A - source vector, N elements are copied + IA - source offset (first element index) + B - destination vector, must be large enough to store result + IB - destination offset (first element index) +*************************************************************************/ +void rvectorcopy(const ae_int_t n, const real_1d_array &a, const ae_int_t ia, real_1d_array &b, const ae_int_t ib, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Copy + +Input parameters: + M - number of rows + N - number of columns + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixcopy(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Performs generalized copy: B := Beta*B + Alpha*A. + +If Beta=0, then previous contents of B is simply ignored. If Alpha=0, then +A is ignored and not referenced. If both Alpha and Beta are zero, B is +filled by zeros. + +Input parameters: + M - number of rows + N - number of columns + Alpha- coefficient + A - source matrix, MxN submatrix is copied + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Beta- coefficient + B - destination matrix, must be large enough to store result + IB - submatrix offset (row index) + JB - submatrix offset (column index) +*************************************************************************/ +void rmatrixgencopy(const ae_int_t m, const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const double beta, real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Rank-1 correction: A := A + alpha*u*v' + +NOTE: this function expects A to be large enough to store result. No + automatic preallocation happens for smaller arrays. No integrity + checks is performed for sizes of A, u, v. + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + Alpha- coefficient + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset + + + -- ALGLIB routine -- + + 16.10.2017 + Bochkanov Sergey +*************************************************************************/ +void rmatrixger(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const double alpha, const real_1d_array &u, const ae_int_t iu, const real_1d_array &v, const ae_int_t iv, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void cmatrixrank1(const ae_int_t m, const ae_int_t n, complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const complex_1d_array &u, const ae_int_t iu, const complex_1d_array &v, const ae_int_t iv, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGER() + which is more generic version of this function. + +Rank-1 correction: A := A + u*v' + +INPUT PARAMETERS: + M - number of rows + N - number of columns + A - target matrix, MxN submatrix is updated + IA - submatrix offset (row index) + JA - submatrix offset (column index) + U - vector #1 + IU - subvector offset + V - vector #2 + IV - subvector offset +*************************************************************************/ +void rmatrixrank1(const ae_int_t m, const ae_int_t n, real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const real_1d_array &u, const ae_int_t iu, const real_1d_array &v, const ae_int_t iv, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + +*************************************************************************/ +void rmatrixgemv(const ae_int_t m, const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + M>=0 + N - number of columns of op(A) + N>=0 + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + * OpA=2 => op(A) = A^H + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixmv(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const complex_1d_array &x, const ae_int_t ix, complex_1d_array &y, const ae_int_t iy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +IMPORTANT: this function is deprecated since ALGLIB 3.13. Use RMatrixGEMV() + which is more generic version of this function. + +Matrix-vector product: y := op(A)*x + +INPUT PARAMETERS: + M - number of rows of op(A) + N - number of columns of op(A) + A - target matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpA - operation type: + * OpA=0 => op(A) = A + * OpA=1 => op(A) = A^T + X - input vector + IX - subvector offset + IY - subvector offset + Y - preallocated matrix, must be large enough to store result + +OUTPUT PARAMETERS: + Y - vector which stores result + +if M=0, then subroutine does nothing. +if N=0, Y is filled by zeros. + + + -- ALGLIB routine -- + + 28.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixmv(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t opa, const real_1d_array &x, const ae_int_t ix, real_1d_array &y, const ae_int_t iy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + +*************************************************************************/ +void rmatrixsymv(const ae_int_t n, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + +*************************************************************************/ +double rmatrixsyvmv(const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const real_1d_array &x, const ae_int_t ix, real_1d_array &tmp, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine solves linear system op(A)*x=b where: +* A is NxN upper/lower triangular/unitriangular matrix +* X and B are Nx1 vectors +* "op" may be identity transformation or transposition + +Solution replaces X. + +IMPORTANT: * no overflow/underflow/denegeracy tests is performed. + * no integrity checks for operand sizes, out-of-bounds accesses + and so on is performed + +INPUT PARAMETERS + N - matrix size, N>=0 + A - matrix, actial matrix is stored in A[IA:IA+N-1,JA:JA+N-1] + IA - submatrix offset + JA - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - right part, actual vector is stored in X[IX:IX+N-1] + IX - offset + +OUTPUT PARAMETERS + X - solution replaces elements X[IX:IX+N-1] + + -- ALGLIB routine / remastering of LAPACK's DTRSV -- + (c) 2017 Bochkanov Sergey - converted to ALGLIB + (c) 2016 Reference BLAS level1 routine (LAPACK version 3.7.0) + Reference BLAS is a software package provided by Univ. of Tennessee, + Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd. +*************************************************************************/ +void rmatrixtrsv(const ae_int_t n, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, const ae_int_t ix, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 20.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, complex_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition, conjugate transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const complex_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, complex_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates X*op(A^-1) where: +* X is MxN general matrix +* A is NxN upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+N-1,J1:J1+N-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrighttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, real_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates op(A^-1)*X where: +* X is MxN general matrix +* A is MxM upper/lower triangular/unitriangular matrix +* "op" may be identity transformation, transposition +Multiplication result replaces X. + +INPUT PARAMETERS + N - matrix size, N>=0 + M - matrix size, N>=0 + A - matrix, actial matrix is stored in A[I1:I1+M-1,J1:J1+M-1] + I1 - submatrix offset + J1 - submatrix offset + IsUpper - whether matrix is upper triangular + IsUnit - whether matrix is unitriangular + OpType - transformation type: + * 0 - no transformation + * 1 - transposition + X - matrix, actial matrix is stored in X[I2:I2+M-1,J2:J2+N-1] + I2 - submatrix offset + J2 - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlefttrsm(const ae_int_t m, const ae_int_t n, const real_2d_array &a, const ae_int_t i1, const ae_int_t j1, const bool isupper, const bool isunit, const ae_int_t optype, real_2d_array &x, const ae_int_t i2, const ae_int_t j2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates C=alpha*A*A^H+beta*C or C=alpha*A^H*A+beta*C +where: +* C is NxN Hermitian matrix given by its upper/lower triangle +* A is NxK matrix when A*A^H is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^H is calculated + * 2 - A^H*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether upper or lower triangle of C is updated; + this function updates only one half of C, leaving + other half unchanged (not referenced at all). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void cmatrixherk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates C=alpha*A*A^T+beta*C or C=alpha*A^T*A+beta*C +where: +* C is NxN symmetric matrix given by its upper/lower triangle +* A is NxK matrix when A*A^T is calculated, KxN matrix otherwise + +Additional info: +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +INPUT PARAMETERS + N - matrix size, N>=0 + K - matrix size, K>=0 + Alpha - coefficient + A - matrix + IA - submatrix offset (row index) + JA - submatrix offset (column index) + OpTypeA - multiplication type: + * 0 - A*A^T is calculated + * 2 - A^T*A is calculated + Beta - coefficient + C - preallocated input/output matrix + IC - submatrix offset (row index) + JC - submatrix offset (column index) + IsUpper - whether C is upper triangular or lower triangular + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 16.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +void rmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition, conjugate transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + * 2 - conjugate transposition + Beta - coefficient + C - matrix (PREALLOCATED, large enough to store result) + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void cmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const alglib::complex alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const complex_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const alglib::complex beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine calculates C = alpha*op1(A)*op2(B) +beta*C where: +* C is MxN general matrix +* op1(A) is MxK matrix +* op2(B) is KxN matrix +* "op" may be identity transformation, transposition + +Additional info: +* cache-oblivious algorithm is used. +* multiplication result replaces C. If Beta=0, C elements are not used in + calculations (not multiplied by zero - just not referenced) +* if Alpha=0, A is not used (not multiplied by zero - just not referenced) +* if both Beta and Alpha are zero, C is filled by zeros. + +IMPORTANT: + +This function does NOT preallocate output matrix C, it MUST be preallocated +by caller prior to calling this function. In case C does not have enough +space to store result, exception will be generated. + +INPUT PARAMETERS + M - matrix size, M>0 + N - matrix size, N>0 + K - matrix size, K>0 + Alpha - coefficient + A - matrix + IA - submatrix offset + JA - submatrix offset + OpTypeA - transformation type: + * 0 - no transformation + * 1 - transposition + B - matrix + IB - submatrix offset + JB - submatrix offset + OpTypeB - transformation type: + * 0 - no transformation + * 1 - transposition + Beta - coefficient + C - PREALLOCATED output matrix, large enough to store result + IC - submatrix offset + JC - submatrix offset + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 2009-2019 + Bochkanov Sergey +*************************************************************************/ +void rmatrixgemm(const ae_int_t m, const ae_int_t n, const ae_int_t k, const double alpha, const real_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const real_2d_array &b, const ae_int_t ib, const ae_int_t jb, const ae_int_t optypeb, const double beta, real_2d_array &c, const ae_int_t ic, const ae_int_t jc, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine is an older version of CMatrixHERK(), one with wrong name +(it is HErmitian update, not SYmmetric). It is left here for backward +compatibility. + + -- ALGLIB routine -- + 16.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixsyrk(const ae_int_t n, const ae_int_t k, const double alpha, const complex_2d_array &a, const ae_int_t ia, const ae_int_t ja, const ae_int_t optypea, const double beta, complex_2d_array &c, const ae_int_t ic, const ae_int_t jc, const bool isupper, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +QR decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form (see below). + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0.. Min(M-1,N-1)]. + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size M x N. + +The elements of matrix R are located on and above the main diagonal of +matrix A. The elements which are located in Tau array and below the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(k-1), + +where k = min(m,n), and each H(i) is in the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, +so that v(0:i-1) = 0, v(i) = 1, v(i+1:m-1) stored in A(i+1:m-1,i). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqr(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LQ decomposition of a rectangular matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices L and Q in compact form (see below) + Tau - array of scalar factors which are used to form + matrix Q. Array whose index ranges within [0..Min(M,N)-1]. + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size M x N. + +The elements of matrix L are located on and below the main diagonal of +matrix A. The elements which are located in Tau array and above the main +diagonal of matrix A are used to form matrix Q as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(k-1)*H(k-2)*...*H(1)*H(0), + +where k = min(m,n), and each H(i) is of the form + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - real vector, so that v(0:i-1)=0, +v(i) = 1, v(i+1:n-1) stored in A(i,i+1:n-1). + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlq(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +QR decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and R in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = QR, where Q is an orthogonal matrix of size +MxM, R - upper triangular (or upper trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixqr(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LQ decomposition of a rectangular complex matrix of size MxN + +Input parameters: + A - matrix A whose indexes range within [0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q and L in compact form + Tau - array of scalar factors which are used to form matrix Q. Array + whose indexes range within [0.. Min(M,N)-1] + +Matrix A is represented as A = LQ, where Q is an orthogonal matrix of size +MxM, L - lower triangular (or lower trapezoid) matrix of size MxN. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +void cmatrixlq(complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_1d_array &tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Partial unpacking of matrix Q from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixQR subroutine. + QColumns - required number of columns of matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose indexes range within [0..M-1, 0..QColumns-1]. + If QColumns=0, the array remains unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qcolumns, real_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of RMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixqrunpackr(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Partial unpacking of matrix Q from the LQ decomposition of a matrix A + +Input parameters: + A - matrices L and Q in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of the RMatrixLQ subroutine. + QRows - required number of rows in matrix Q. N>=QRows>=0. + +Output parameters: + Q - first QRows rows of matrix Q. Array whose indexes range + within [0..QRows-1, 0..N-1]. If QRows=0, the array remains + unchanged. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackq(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const real_1d_array &tau, const ae_int_t qrows, real_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of RMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlqunpackl(const real_2d_array &a, const ae_int_t m, const ae_int_t n, real_2d_array &l, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Partial unpacking of matrix Q from QR decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixQR subroutine . + QColumns - required number of columns in matrix Q. M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array whose index ranges within [0..M-1, 0..QColumns-1]. + If QColumns=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qcolumns, complex_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking of matrix R from the QR decomposition of a matrix A + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixQR subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + R - matrix R, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixqrunpackr(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &r, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Partial unpacking of matrix Q from LQ decomposition of a complex matrix A. + +Input parameters: + A - matrices Q and R in compact form. + Output of CMatrixLQ subroutine . + M - number of rows in matrix A. M>=0. + N - number of columns in matrix A. N>=0. + Tau - scalar factors which are used to form Q. + Output of CMatrixLQ subroutine . + QRows - required number of rows in matrix Q. N>=QColumns>=0. + +Output parameters: + Q - first QRows rows of matrix Q. + Array whose index ranges within [0..QRows-1, 0..N-1]. + If QRows=0, array isn't changed. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackq(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, const complex_1d_array &tau, const ae_int_t qrows, complex_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking of matrix L from the LQ decomposition of a matrix A + +Input parameters: + A - matrices Q and L in compact form. + Output of CMatrixLQ subroutine. + M - number of rows in given matrix A. M>=0. + N - number of columns in given matrix A. N>=0. + +Output parameters: + L - matrix L, array[0..M-1, 0..N-1]. + + -- ALGLIB routine -- + 17.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlqunpackl(const complex_2d_array &a, const ae_int_t m, const ae_int_t n, complex_2d_array &l, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Reduction of a rectangular matrix to bidiagonal form + +The algorithm reduces the rectangular matrix A to bidiagonal form by +orthogonal transformations P and Q: A = Q*B*(P^T). + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - source matrix. array[0..M-1, 0..N-1] + M - number of rows in matrix A. + N - number of columns in matrix A. + +Output parameters: + A - matrices Q, B, P in compact form (see below). + TauQ - scalar factors which are used to form matrix Q. + TauP - scalar factors which are used to form matrix P. + +The main diagonal and one of the secondary diagonals of matrix A are +replaced with bidiagonal matrix B. Other elements contain elementary +reflections which form MxM matrix Q and NxN matrix P, respectively. + +If M>=N, B is the upper bidiagonal MxN matrix and is stored in the +corresponding elements of matrix A. Matrix Q is represented as a +product of elementary reflections Q = H(0)*H(1)*...*H(n-1), where +H(i) = 1-tau*v*v'. Here tau is a scalar which is stored in TauQ[i], and +vector v has the following structure: v(0:i-1)=0, v(i)=1, v(i+1:m-1) is +stored in elements A(i+1:m-1,i). Matrix P is as follows: P = +G(0)*G(1)*...*G(n-2), where G(i) = 1 - tau*u*u'. Tau is stored in TauP[i], +u(0:i)=0, u(i+1)=1, u(i+2:n-1) is stored in elements A(i,i+2:n-1). + +If M n): m=5, n=6 (m < n): + +( d e u1 u1 u1 ) ( d u1 u1 u1 u1 u1 ) +( v1 d e u2 u2 ) ( e d u2 u2 u2 u2 ) +( v1 v2 d e u3 ) ( v1 e d u3 u3 u3 ) +( v1 v2 v3 d e ) ( v1 v2 e d u4 u4 ) +( v1 v2 v3 v4 d ) ( v1 v2 v3 e d u5 ) +( v1 v2 v3 v4 v5 ) + +Here vi and ui are vectors which form H(i) and G(i), and d and e - +are the diagonal and off-diagonal elements of matrix B. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994. + Sergey Bochkanov, ALGLIB project, translation from FORTRAN to + pseudocode, 2007-2010. +*************************************************************************/ +void rmatrixbd(real_2d_array &a, const ae_int_t m, const ae_int_t n, real_1d_array &tauq, real_1d_array &taup, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix Q which reduces a matrix to bidiagonal form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + QColumns - required number of columns in matrix Q. + M>=QColumns>=0. + +Output parameters: + Q - first QColumns columns of matrix Q. + Array[0..M-1, 0..QColumns-1] + If QColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, const ae_int_t qcolumns, real_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication by matrix Q which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by Q or Q'. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUQ - scalar factors which are used to form Q. + Output of ToBidiagonal subroutine. + Z - multiplied matrix. + array[0..ZRows-1,0..ZColumns-1] + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=M, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=M, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by Q or Q'. + +Output parameters: + Z - product of Z and Q. + Array[0..ZRows-1,0..ZColumns-1] + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyq(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &tauq, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix P which reduces matrix A to bidiagonal form. +The subroutine returns transposed matrix P. + +Input parameters: + QP - matrices Q and P in compact form. + Output of ToBidiagonal subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of ToBidiagonal subroutine. + PTRows - required number of rows of matrix P^T. N >= PTRows >= 0. + +Output parameters: + PT - first PTRows columns of matrix P^T + Array[0..PTRows-1, 0..N-1] + If PTRows=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackpt(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, const ae_int_t ptrows, real_2d_array &pt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication by matrix P which reduces matrix A to bidiagonal form. + +The algorithm allows pre- or post-multiply by P or P'. + +Input parameters: + QP - matrices Q and P in compact form. + Output of RMatrixBD subroutine. + M - number of rows in matrix A. + N - number of columns in matrix A. + TAUP - scalar factors which are used to form P. + Output of RMatrixBD subroutine. + Z - multiplied matrix. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + ZRows - number of rows in matrix Z. If FromTheRight=False, + ZRows=N, otherwise ZRows can be arbitrary. + ZColumns - number of columns in matrix Z. If FromTheRight=True, + ZColumns=N, otherwise ZColumns can be arbitrary. + FromTheRight - pre- or post-multiply. + DoTranspose - multiply by P or P'. + +Output parameters: + Z - product of Z and P. + Array whose indexes range within [0..ZRows-1,0..ZColumns-1]. + If ZRows=0 or ZColumns=0, the array is not modified. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdmultiplybyp(const real_2d_array &qp, const ae_int_t m, const ae_int_t n, const real_1d_array &taup, real_2d_array &z, const ae_int_t zrows, const ae_int_t zcolumns, const bool fromtheright, const bool dotranspose, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking of the main and secondary diagonals of bidiagonal decomposition +of matrix A. + +Input parameters: + B - output of RMatrixBD subroutine. + M - number of rows in matrix B. + N - number of columns in matrix B. + +Output parameters: + IsUpper - True, if the matrix is upper bidiagonal. + otherwise IsUpper is False. + D - the main diagonal. + Array whose index ranges within [0..Min(M,N)-1]. + E - the secondary diagonal (upper or lower, depending on + the value of IsUpper). + Array index ranges within [0..Min(M,N)-1], the last + element is not used. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixbdunpackdiagonals(const real_2d_array &b, const ae_int_t m, const ae_int_t n, bool &isupper, real_1d_array &d, real_1d_array &e, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Reduction of a square matrix to upper Hessenberg form: Q'*A*Q = H, +where Q is an orthogonal matrix, H - Hessenberg matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix A with elements [0..N-1, 0..N-1] + N - size of matrix A. + +Output parameters: + A - matrices Q and P in compact form (see below). + Tau - array of scalar factors which are used to form matrix Q. + Array whose index ranges within [0..N-2] + +Matrix H is located on the main diagonal, on the lower secondary diagonal +and above the main diagonal of matrix A. The elements which are used to +form matrix Q are situated in array Tau and below the lower secondary +diagonal of matrix A as follows: + +Matrix Q is represented as a product of elementary reflections + +Q = H(0)*H(2)*...*H(n-2), + +where each H(i) is given by + +H(i) = 1 - tau * v * (v^T) + +where tau is a scalar stored in Tau[I]; v - is a real vector, +so that v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) stored in A(i+2:n-1,i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void rmatrixhessenberg(real_2d_array &a, const ae_int_t n, real_1d_array &tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix Q which reduces matrix A to upper Hessenberg form + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + Tau - scalar factors which are used to form Q. + Output of RMatrixHessenberg subroutine. + +Output parameters: + Q - matrix Q. + Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackq(const real_2d_array &a, const ae_int_t n, const real_1d_array &tau, real_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix H (the result of matrix A reduction to upper Hessenberg form) + +Input parameters: + A - output of RMatrixHessenberg subroutine. + N - size of matrix A. + +Output parameters: + H - matrix H. Array whose indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + 2005-2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixhessenbergunpackh(const real_2d_array &a, const ae_int_t n, real_2d_array &h, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Reduction of a symmetric matrix which is given by its higher or lower +triangular part to a tridiagonal matrix using orthogonal similarity +transformation: Q'*A*Q=T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a real scalar, and v is a real vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + + where d and e denote diagonal and off-diagonal elements of T, and vi + denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void smatrixtd(real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &tau, real_1d_array &d, real_1d_array &e, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix Q which reduces symmetric matrix to a tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a SMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of SMatrixTD subroutine) + Tau - the result of a SMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void smatrixtdunpackq(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &tau, real_2d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Reduction of a Hermitian matrix which is given by its higher or lower +triangular part to a real tridiagonal matrix using unitary similarity +transformation: Q'*A*Q = T. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - matrix to be transformed + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. If IsUpper = True, then matrix A is given + by its upper triangle, and the lower triangle is not used + and not modified by the algorithm, and vice versa + if IsUpper = False. + +Output parameters: + A - matrices T and Q in compact form (see lower) + Tau - array of factors which are forming matrices H(i) + array with elements [0..N-2]. + D - main diagonal of real symmetric matrix T. + array with elements [0..N-1]. + E - secondary diagonal of real symmetric matrix T. + array with elements [0..N-2]. + + + If IsUpper=True, the matrix Q is represented as a product of elementary + reflectors + + Q = H(n-2) . . . H(2) H(0). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(i+1:n-1) = 0, v(i) = 1, v(0:i-1) is stored on exit in + A(0:i-1,i+1), and tau in TAU(i). + + If IsUpper=False, the matrix Q is represented as a product of elementary + reflectors + + Q = H(0) H(2) . . . H(n-2). + + Each H(i) has the form + + H(i) = I - tau * v * v' + + where tau is a complex scalar, and v is a complex vector with + v(0:i) = 0, v(i+1) = 1, v(i+2:n-1) is stored on exit in A(i+2:n-1,i), + and tau in TAU(i). + + The contents of A on exit are illustrated by the following examples + with n = 5: + + if UPLO = 'U': if UPLO = 'L': + + ( d e v1 v2 v3 ) ( d ) + ( d e v2 v3 ) ( e d ) + ( d e v3 ) ( v0 e d ) + ( d e ) ( v0 v1 e d ) + ( d ) ( v0 v1 v2 e d ) + +where d and e denote diagonal and off-diagonal elements of T, and vi +denotes an element of the vector defining H(i). + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1992 +*************************************************************************/ +void hmatrixtd(complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &tau, real_1d_array &d, real_1d_array &e, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Unpacking matrix Q which reduces a Hermitian matrix to a real tridiagonal +form. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - the result of a HMatrixTD subroutine + N - size of matrix A. + IsUpper - storage format (a parameter of HMatrixTD subroutine) + Tau - the result of a HMatrixTD subroutine + +Output parameters: + Q - transformation matrix. + array with elements [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void hmatrixtdunpackq(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &tau, complex_2d_array &q, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Generation of a random uniformly distributed (Haar) orthogonal matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonal(const ae_int_t n, real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN matrix with given condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of a random Haar distributed orthogonal complex matrix + +INPUT PARAMETERS: + N - matrix size, N>=1 + +OUTPUT PARAMETERS: + A - orthogonal NxN matrix, array[0..N-1,0..N-1] + +NOTE: this function uses algorithm described in Stewart, G. W. (1980), + "The Efficient Generation of Random Orthogonal Matrices with an + Application to Condition Estimators". + + Speaking short, to generate an (N+1)x(N+1) orthogonal matrix, it: + * takes an NxN one + * takes uniformly distributed unit vector of dimension N+1. + * constructs a Householder reflection from the vector, then applies + it to the smaller matrix (embedded in the larger size with a 1 at + the bottom right corner). + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonal(const ae_int_t n, complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN complex matrix with given condition number C and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN symmetric matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN symmetric positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random SPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixrndcond(const ae_int_t n, const double c, real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN Hermitian matrix with given condition number and +norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Generation of random NxN Hermitian positive definite matrix with given +condition number and norm2(A)=1 + +INPUT PARAMETERS: + N - matrix size + C - condition number (in 2-norm) + +OUTPUT PARAMETERS: + A - random HPD matrix with norm2(A)=1 and cond(A)=C + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixrndcond(const ae_int_t n, const double c, complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication of MxN matrix by NxN random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheright(real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication of MxN matrix by MxM random Haar distributed orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void rmatrixrndorthogonalfromtheleft(real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication of MxN complex matrix by NxN random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheright(complex_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Multiplication of MxN complex matrix by MxM random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..M-1, 0..N-1] + M, N- matrix size + +OUTPUT PARAMETERS: + A - Q*A, where Q is random MxM orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void cmatrixrndorthogonalfromtheleft(complex_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Symmetric multiplication of NxN matrix by random Haar distributed +orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q'*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void smatrixrndmultiply(real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Hermitian multiplication of NxN matrix by random Haar distributed +complex orthogonal matrix + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1] + N - matrix size + +OUTPUT PARAMETERS: + A - Q^H*A*Q, where Q is random NxN orthogonal matrix + + -- ALGLIB routine -- + 04.12.2009 + Bochkanov Sergey +*************************************************************************/ +void hmatrixrndmultiply(complex_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void sparseserialize(const sparsematrix &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void sparseserialize(const sparsematrix &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void sparseunserialize(const std::string &s_in, sparsematrix &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void sparseunserialize(const std::istream &s_in, sparsematrix &obj); + + +/************************************************************************* +This function creates sparse matrix in a Hash-Table format. + +This function creates Hast-Table matrix, which can be converted to CRS +format after its initialization is over. Typical usage scenario for a +sparse matrix is: +1. creation in a Hash-Table format +2. insertion of the matrix elements +3. conversion to the CRS representation +4. matrix is passed to some linear algebra algorithm + +Some information about different matrix formats can be found below, in +the "NOTES" section. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + +NOTE 1 + +Hash-tables use memory inefficiently, and they have to keep some amount +of the "spare memory" in order to have good performance. Hash table for +matrix with K non-zero elements will need C*K*(8+2*sizeof(int)) bytes, +where C is a small constant, about 1.5-2 in magnitude. + +CRS storage, from the other side, is more memory-efficient, and needs +just K*(8+sizeof(int))+M*sizeof(int) bytes, where M is a number of rows +in a matrix. + +When you convert from the Hash-Table to CRS representation, all unneeded +memory will be freed. + +NOTE 2 + +Comments of SparseMatrix structure outline information about different +sparse storage formats. We recommend you to read them before starting to +use ALGLIB sparse matrices. + +NOTE 3 + +This function completely overwrites S with new sparse matrix. Previously +allocated storage is NOT reused. If you want to reuse already allocated +memory, call SparseCreateBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreate(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s, const xparams _xparams = alglib::xdefault); +void sparsecreate(const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This version of SparseCreate function creates sparse matrix in Hash-Table +format, reusing previously allocated storage as much as possible. Read +comments for SparseCreate() for more information. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + K - K>=0, expected number of non-zero elements in a matrix. + K can be inexact approximation, can be less than actual + number of elements (table will grow when needed) or + even zero). + It is important to understand that although hash-table + may grow automatically, it is better to provide good + estimate of data size. + S - SparseMatrix structure which MAY contain some already + allocated storage. + +OUTPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + All elements of the matrix are zero. + Previously allocated storage is reused, if its size + is compatible with expected number of non-zeros K. + + -- ALGLIB PROJECT -- + Copyright 14.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatebuf(const ae_int_t m, const ae_int_t n, const ae_int_t k, sparsematrix &s, const xparams _xparams = alglib::xdefault); +void sparsecreatebuf(const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates sparse matrix in a CRS format - the least flexible +but the most efficient format implemented in ALGLIB. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell the number of non-zero elements at each row + at this moment) +2. initialization of the matrix elements (row by row, from left to right) +3. the matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSBuf function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrs(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates sparse matrix in a CRS format (expert function for +situations when you are running out of memory). This version of CRS +matrix creation function may reuse memory already allocated in S. + +This function creates CRS matrix. Typical usage scenario for a CRS matrix +is: +1. creation (you have to tell number of non-zero elements at each row at + this moment) +2. insertion of the matrix elements (row by row, from left to right) +3. matrix is passed to some linear algebra algorithm + +This function is a memory-efficient alternative to SparseCreate(), but it +is more complex because it requires you to know in advance how large your +matrix is. Some information about different matrix formats can be found +in comments on SparseMatrix structure. We recommend you to read them +before starting to use ALGLIB sparse matrices.. + +INPUT PARAMETERS + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + NER - number of elements at each row, array[M], NER[I]>=0 + S - sparse matrix structure with possibly preallocated + memory. + +OUTPUT PARAMETERS + S - sparse M*N matrix in CRS representation. + You have to fill ALL non-zero elements by calling + SparseSet() BEFORE you try to use this matrix. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &ner, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdense(const real_2d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); +void sparsecreatecrsfromdense(const real_2d_array &a, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates a CRS-based sparse matrix from the dense matrix. +A buffered version which reused memory already allocated in S as much as +possible. + +This function is intended for situations when you already have a dense +matrix and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M,N]. If larger, only leading MxN submatrix + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensebuf(const real_2d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); +void sparsecreatecrsfromdensebuf(const real_2d_array &a, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates a CRS-based sparse matrix from a dense vector +which stores a dense 1-dimensional representation of a dense M*N matrix. + +This function is intended for situations when you already have a dense +vector and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M*N]. If larger, only leading M*N elements + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateCRSFromDenseBuf function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensev(const real_1d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates a CRS-based sparse matrix from a dense vector +which stores a dense 1-dimensional representation of a dense M*N matrix. +A buffered version which reused memory already allocated in S as much as +possible. + +This function is intended for situations when you already have a dense +vector and need a convenient way of converting it to the CRS format. + +INPUT PARAMETERS + A - array[M*N]. If larger, only leading M*N elements + will be used. + M - number of rows in a matrix, M>=1 + N - number of columns in a matrix, N>=1 + S - an already allocated structure; if it already has + enough memory to store the matrix, no new memory + will be allocated. + +OUTPUT PARAMETERS + S - sparse M*N matrix A in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 16.06.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatecrsfromdensevbuf(const real_1d_array &a, const ae_int_t m, const ae_int_t n, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], D[I]>=0. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], U[I]>=0. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call SparseCreateSKSBuf function. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesks(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is "buffered" version of SparseCreateSKS() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +This function creates sparse matrix in a SKS format (skyline storage +format). In most cases you do not need this function - CRS format better +suits most use cases. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + D - "bottom" bandwidths, array[M], 0<=D[I]<=I. + I-th element stores number of non-zeros at I-th row, + below the diagonal (diagonal itself is not included) + U - "top" bandwidths, array[N], 0<=U[I]<=I. + I-th element stores number of non-zeros at I-th row, + above the diagonal (diagonal itself is not included) + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbuf(const ae_int_t m, const ae_int_t n, const integer_1d_array &d, const integer_1d_array &u, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function creates sparse matrix in a SKS format (skyline storage +format). Unlike more general sparsecreatesks(), this function creates +sparse matrix with constant bandwidth. + +You may want to use this function instead of sparsecreatesks() when your +matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - matrix bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + +NOTE: this function completely overwrites S with new sparse matrix. + Previously allocated storage is NOT reused. If you want to reuse + already allocated memory, call sparsecreatesksbandbuf function. + + -- ALGLIB PROJECT -- + Copyright 25.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksband(const ae_int_t m, const ae_int_t n, const ae_int_t bw, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is "buffered" version of sparsecreatesksband() which reuses memory +previously allocated in S (of course, memory is reallocated if needed). + +You may want to use this function instead of sparsecreatesksbuf() when +your matrix has constant or nearly-constant bandwidth, and you want to +simplify source code. + +INPUT PARAMETERS + M, N - number of rows(M) and columns (N) in a matrix: + * M=N (as for now, ALGLIB supports only square SKS) + * N>=1 + * M>=1 + BW - bandwidth, BW>=0 + +OUTPUT PARAMETERS + S - sparse M*N matrix in SKS representation. + All elements are filled by zeros. + You may use sparseset() to change their values. + + -- ALGLIB PROJECT -- + Copyright 13.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsecreatesksbandbuf(const ae_int_t m, const ae_int_t n, const ae_int_t bw, sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function copies S0 to S1. +This function completely deallocates memory owned by S1 before creating a +copy of S0. If you want to reuse memory, use SparseCopyBuf. + +NOTE: this function does not verify its arguments, it just copies all +fields of the structure. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsecopy(const sparsematrix &s0, sparsematrix &s1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function efficiently swaps contents of S0 and S1. + + -- ALGLIB PROJECT -- + Copyright 16.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparseswap(sparsematrix &s0, sparsematrix &s1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function adds value to S[i,j] - element of the sparse matrix. Matrix +must be in a Hash-Table mode. + +In case S[i,j] already exists in the table, V i added to its value. In +case S[i,j] is non-existent, it is inserted in the table. Table +automatically grows when necessary. + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table representation. + Exception will be thrown for CRS matrix. + I - row index of the element to modify, 0<=I op(S) = S + * OpS=1 => op(S) = S^T + X - input vector, must have at least Cols(op(S))+IX elements + IX - subvector offset + Beta - destination coefficient + Y - preallocated output array, must have at least Rows(op(S))+IY elements + IY - subvector offset + +OUTPUT PARAMETERS + Y - elements [IY...IY+Rows(op(S))-1] are replaced by result, + other elements are not modified + +HANDLING OF SPECIAL CASES: +* below M=Rows(op(S)) and N=Cols(op(S)). Although current ALGLIB version + does not allow you to create zero-sized sparse matrices, internally + ALGLIB can deal with such matrices. So, comments for M or N equal to + zero are for internal use only. +* if M=0, then subroutine does nothing. It does not even touch arrays. +* if N=0 or Alpha=0.0, then: + * if Beta=0, then Y is filled by zeros. S and X are not referenced at + all. Initial values of Y are ignored (we do not multiply Y by zero, + we just rewrite it by zeros) + * if Beta<>0, then Y is replaced by Beta*Y +* if M>0, N>0, Alpha<>0, but Beta=0, then Y is replaced by alpha*op(S)*x + initial state of Y is ignored (rewritten without initial multiplication + by zeros). + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 10.12.2019 by Bochkanov Sergey +*************************************************************************/ +void sparsegemv(const sparsematrix &s, const double alpha, const ae_int_t ops, const real_1d_array &x, const ae_int_t ix, const double beta, real_1d_array &y, const ae_int_t iy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function simultaneously calculates two matrix-vector products: + S*x and S^T*x. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + Y1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y0 - array[N], S*x + Y1 - array[N], S^T*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemv2(const sparsematrix &s, const real_1d_array &x, real_1d_array &y0, real_1d_array &y1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates matrix-vector product S*x, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + Y - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + Y - array[M], S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function perform in-place multiplication of the matrix columns by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[N], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplycolsby(sparsematrix &s, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function perform in-place multiplication of the matrix rows by a +user-supplied vector X. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], coefficients vector. + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowsby(sparsematrix &s, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function perform in-place multiplication of the matrix rows and cols +by user-supplied vectors X and Y. The matrix S must be stored in CRS format. + +INPUT PARAMETERS + S - sparse M*N matrix in CRS format. + X - array[M], row multipliers + Y - array[N], column multipliers + +OUTPUT PARAMETERS + S - in-place multiplied by diag(X) from the left, and by + diag(Y) from the right + +NOTE: this function throws exception when called for a non-CRS matrix. +You must convert your matrix with SparseConvertToCRS() before using this +function. + + -- ALGLIB PROJECT -- + Copyright 17.02.2024 by Bochkanov Sergey +*************************************************************************/ +void sparsemultiplyrowscolsby(sparsematrix &s, const real_1d_array &x, const real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates vector-matrix-vector product x'*S*x, where S is +symmetric matrix. Matrix S must be stored in CRS or SKS format (exception +will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + X - array[N], input vector. For performance reasons we + make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + +RESULT + x'*S*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 27.01.2014 by Bochkanov Sergey +*************************************************************************/ +double sparsevsmv(const sparsematrix &s, const bool isupper, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates matrix-matrix product S*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size + is at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates matrix-matrix product S^T*A. Matrix S must be +stored in CRS or SKS format (exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse M*N matrix in CRS or SKS format. + A - array[M][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least M, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemtm(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function simultaneously calculates two matrix-matrix products: + S*A and S^T*A. +S must be square (non-rectangular) matrix stored in CRS or SKS format +(exception will be thrown otherwise). + +INPUT PARAMETERS + S - sparse N*N matrix in CRS or SKS format. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B0 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + B1 - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B0 - array[N][K], S*A + B1 - array[N][K], S^T*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsemm2(const sparsematrix &s, const real_2d_array &a, const ae_int_t k, real_2d_array &b0, real_2d_array &b1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates matrix-matrix product S*A, when S is symmetric +matrix. Matrix S must be stored in CRS or SKS format (exception will be +thrown otherwise). + +INPUT PARAMETERS + S - sparse M*M matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is given: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + A - array[N][K], input dense matrix. For performance reasons + we make only quick checks - we check that array size is + at least N, but we do not check for NAN's or INF's. + K - number of columns of matrix (A). + B - output buffer, possibly preallocated. In case buffer + size is too small to store result, this buffer is + automatically resized. + +OUTPUT PARAMETERS + B - array[M][K], S*A + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesmm(const sparsematrix &s, const bool isupper, const real_2d_array &a, const ae_int_t k, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function calculates matrix-vector product op(S)*x, when x is vector, +S is symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + Y - possibly preallocated input buffer. Automatically + resized if its size is too small. + +OUTPUT PARAMETERS + Y - array[N], op(S)*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. +You must convert your matrix with SparseConvertToCRS/SKS() before using +this function. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrmv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves linear system op(S)*y=x where x is vector, S is +symmetric triangular matrix, op(S) is transposition or no operation. +Matrix S must be stored in CRS or SKS format (exception will be thrown +otherwise). + +INPUT PARAMETERS + S - sparse square matrix in CRS or SKS format. + IsUpper - whether upper or lower triangle of S is used: + * if upper triangle is given, only S[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only S[i,j] for j<=i + are used, and upper triangle is ignored. + IsUnit - unit or non-unit diagonal: + * if True, diagonal elements of triangular matrix are + considered equal to 1.0. Actual elements stored in + S are not referenced at all. + * if False, diagonal stored in S is used. It is your + responsibility to make sure that diagonal is + non-zero. + OpType - operation type: + * if 0, S*x is calculated + * if 1, (S^T)*x is calculated (transposition) + X - array[N] which stores input vector. For performance + reasons we make only quick checks - we check that + array size is at least N, but we do not check for + NAN's or INF's. + +OUTPUT PARAMETERS + X - array[N], inv(op(S))*x + +NOTE: this function throws exception when called for non-CRS/SKS matrix. + You must convert your matrix with SparseConvertToCRS/SKS() before + using this function. + +NOTE: no assertion or tests are done during algorithm operation. It is + your responsibility to provide invertible matrix to algorithm. + + -- ALGLIB PROJECT -- + Copyright 20.01.2014 by Bochkanov Sergey +*************************************************************************/ +void sparsetrsv(const sparsematrix &s, const bool isupper, const bool isunit, const ae_int_t optype, real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblBuf() if you want to reuse already allocated structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbl(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function allocates completely new instance of B. Use buffered version +SparseSymmPermTblTransposeBuf() if you want to reuse an already allocated +structure. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltranspose(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is a buffered version of SparseSymmPermTbl() that reuses +previously allocated storage in B as much as possible. + +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only upper or lower triangle (depending + on IsUpper) is stored. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 05.10.2020 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtblbuf(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function applies permutation given by permutation table P (as opposed +to product form of permutation) to sparse symmetric matrix A, given by +either upper or lower triangle: B := P*A*P'. + +It outputs TRANSPOSED matrix, i.e. if A is given by the lower triangle +then B is given by the upper one, and vice versa. + +This function reuses memory already allocated in B as much as possible. + +INPUT PARAMETERS + A - sparse square matrix in CRS format. + IsUpper - whether upper or lower triangle of A is used: + * if upper triangle is given, only A[i,j] for j>=i + are used, and lower triangle is ignored (it can be + empty - these elements are not referenced at all). + * if lower triangle is given, only A[i,j] for j<=i + are used, and upper triangle is ignored. + P - array[N] which stores permutation table; P[I]=J means + that I-th row/column of matrix A is moved to J-th + position. For performance reasons we do NOT check that + P[] is a correct permutation (that there is no + repetitions, just that all its elements are in [0,N) + range. + B - sparse matrix object that will hold the result. + Previously allocated memory will be reused as much as + possible. + +OUTPUT PARAMETERS + B - permuted matrix. Permutation is applied to A from + the both sides, only triangle OPPOSITE to that of A is + returned: a lower one if IsUpper=True, and an upper + one otherwise. + +NOTE: this function throws exception when called for non-CRS matrix. You + must convert your matrix with SparseConvertToCRS() before using this + function. + + -- ALGLIB PROJECT -- + Copyright 24.080.2024 by Bochkanov Sergey. +*************************************************************************/ +void sparsesymmpermtbltransposebuf(const sparsematrix &a, const bool isupper, const integer_1d_array &p, sparsematrix &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This procedure resizes Hash-Table matrix. It can be called when you have +deleted too many elements from the matrix, and you want to free unneeded +memory. + + -- ALGLIB PROJECT -- + Copyright 14.10.2011 by Bochkanov Sergey +*************************************************************************/ +void sparseresizematrix(sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to enumerate all elements of the sparse matrix. +Before first call user initializes T0 and T1 counters by zero. These +counters are used to remember current position in a matrix; after each +call they are updated by the function. + +Subsequent calls to this function return non-zero elements of the sparse +matrix, one by one. If you enumerate CRS matrix, matrix is traversed from +left to right, from top to bottom. In case you enumerate matrix stored as +Hash table, elements are returned in random order. + +EXAMPLE + > T0=0 + > T1=0 + > while SparseEnumerate(S,T0,T1,I,J,V) do + > ....do something with I,J,V + +INPUT PARAMETERS + S - sparse M*N matrix in Hash-Table or CRS representation. + T0 - internal counter + T1 - internal counter + +OUTPUT PARAMETERS + T0 - new value of the internal counter + T1 - new value of the internal counter + I - row index of non-zero element, 0<=I=0. Both ColIdx[] and Vals[] can + be longer than NZ, in which case only leading NZ + elements are used. + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + +NOTE: this function has amortized O(NZ*logNZ) cost. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendcompressedrow(sparsematrix &s, const integer_1d_array &colidx, const real_1d_array &vals, const ae_int_t nz, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends an empty row to a CRS matrix, increasing its rows +count by 1. The newly added row can be modified with sparseappendelement(). +The matrix is a valid CRS matrix at any moment of the process. + +INPUT PARAMETERS: + S - sparse M*N matrix in CRS format, including one created + with sparsecreatecrsempty(). + +OUTPUT PARAMETERS: + S - (M+1)*N matrix in the CRS format. + + -- ALGLIB PROJECT -- + Copyright 2024.02.19 by Bochkanov Sergey +*************************************************************************/ +void sparseappendemptyrow(sparsematrix &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends an element to the last row of a CRS matrix. New +elements can be added ONLY from left to right (column indexes are strictly +increasing). + +INPUT PARAMETERS: + S - a fully initialized sparse M*N matrix in CRS format, M>0 + K - column index, 0<=K0 + C - array[N], col scales, C[i]>0 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. + +NOTE: this function works with general (nonsymmetric) matrices. See + sparsesymmscale() for a symmetric version. See sparsescalebuf() for + a version which reuses space already present in output arrays R/C. + +NOTE: if both ScaleRows=False and ScaleCols=False, this function returns + an identity scaling. + +NOTE: R[] and C[] are guaranteed to be strictly positive. When the matrix + has zero rows/cols, corresponding elements of R/C are set to 1. + + -- ALGLIB PROJECT -- + Copyright 12.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsescale(sparsematrix &s, const ae_int_t scltype, const bool scalerows, const bool scalecols, const bool colsfirst, real_1d_array &r, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tries to gather values from Src to Dst, zeroing out elements +of Dst not present in Src. + +Both matrices must be in the CRS format and must have exactly the same +size. The sparsity pattern of Src must be a subset of that of Dst. + +If Src contains non-zero elements not present in Dst, gather operation is +stopped in the middle (leaving Dst values partially changed but otherwise +fully functional) and False is returned. + +INPUT PARAMETERS + Dst - sparse M*N destination matrix in CRS format. + Src - sparse M*N source matrix in CRS format. + +OUTPUT PARAMETERS + Dst - if True is returned, contains elements of Src and + zeros in other positions. If False is returned, its + values are only partially initialized. + +RESULT: + True if successful. False if the sparsity pattern of Src is not a + subset of that of Dst. + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +bool sparsetrygatherclear(sparsematrix &dst, const sparsematrix &src, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function merges sparsity patterns of S1 and S2 and stores result into +Dst, reusing previously allocated memory as much as possible. + +Both matrices must be in the CRS format and must have exactly the same +size. + +INPUT PARAMETERS + S1, S2 - sparse M*N source matrices in CRS format. + Dst - previously allocated sparse matrix structure in any + storage format and of any size. + +OUTPUT PARAMETERS + Dst - sparse M*N matrix in CRS format, zero-initialized, has + sparsity pattern equal to union of S1 and S2 + +NOTE: this function throws exception when called for a non-CRS matrix. + You must convert your matrix with SparseConvertToCRS() before using + this function. It also throws an exception if matrices have different + sizes. + + + -- ALGLIB PROJECT -- + Copyright 12.04.2025 by Bochkanov Sergey +*************************************************************************/ +void sparsemergepatterns(const sparsematrix &s1, const sparsematrix &s2, sparsematrix &dst, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes subspace iteration solver. This solver is used +to solve symmetric real eigenproblems where just a few (top K) eigenvalues +and corresponding eigenvectors is required. + +This solver can be significantly faster than complete EVD decomposition +in the following case: +* when only just a small fraction of top eigenpairs of dense matrix is + required. When K approaches N, this solver is slower than complete dense + EVD +* when problem matrix is sparse (and/or is not known explicitly, i.e. only + matrix-matrix product can be performed) + +USAGE (explicit dense/sparse matrix): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User calls eigsubspacesolvedense() or eigsubspacesolvesparse() methods, + which take algorithm state and 2D array or alglib.sparsematrix object. + +USAGE (out-of-core mode): +1. User initializes algorithm state with eigsubspacecreate() call +2. [optional] User tunes solver parameters by calling eigsubspacesetcond() + or other functions +3. User activates out-of-core mode of the solver and repeatedly calls + communication functions in a loop like below: + > alglib.eigsubspaceoocstart(state) + > while alglib.eigsubspaceooccontinue(state) do + > alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) + > alglib.eigsubspaceoocgetrequestdata(state, out X) + > [calculate Y=A*X, with X=R^NxM] + > alglib.eigsubspaceoocsendresult(state, in Y) + > alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + N - problem dimensionality, N>0 + K - number of top eigenvector to calculate, 0=0, with non-zero value used to tell solver that + it can stop after all eigenvalues converged with + error roughly proportional to eps*MAX(LAMBDA_MAX), + where LAMBDA_MAX is a maximum eigenvalue. + Zero value means that no check for precision is + performed. + MaxIts - maxits>=0, with non-zero value used to tell solver + that it can stop after maxits steps (no matter how + precise current estimate is) + +NOTE: passing eps=0 and maxits=0 results in automatic selection of + moderate eps as stopping criteria (1.0E-6 in current implementation, + but it may change without notice). + +NOTE: very small values of eps are possible (say, 1.0E-12), although the + larger problem you solve (N and/or K), the harder it is to find + precise eigenvectors because rounding errors tend to accumulate. + +NOTE: passing non-zero eps results in some performance penalty, roughly + equal to 2N*(2K)^2 FLOPs per iteration. These additional computations + are required in order to estimate current error in eigenvalues via + Rayleigh-Ritz process. + Most of this additional time is spent in construction of ~2Kx2K + symmetric subproblem whose eigenvalues are checked with exact + eigensolver. + This additional time is negligible if you search for eigenvalues of + the large dense matrix, but may become noticeable on highly sparse + EVD problems, where cost of matrix-matrix product is low. + If you set eps to exactly zero, Rayleigh-Ritz phase is completely + turned off. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetcond(eigsubspacestate &state, const double eps, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets warm-start mode of the solver: next call to the solver +will reuse previous subspace as warm-start point. It can significantly +speed-up convergence when you solve many similar eigenproblems. + +INPUT PARAMETERS: + State - solver structure + UseWarmStart- either True or False + + -- ALGLIB -- + Copyright 12.11.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesetwarmstart(eigsubspacestate &state, const bool usewarmstart, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function initiates out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver object + MType - matrix type and solver mode: + + * 0 = real symmetric matrix A, products of the form + A*X are computed. At every step the basis of + the invariant subspace is reorthogonalized + with LQ decomposition which makes the algo + more robust. + + The first mode introduced in ALGLIB, the most + precise and robust. However, it is suboptimal + for easy problems which can be solved in 3-5 + iterations without LQ step. + + * 1 = real symmetric matrix A, products of the form + A*X are computed. The invariant subspace is + NOT reorthogonalized, no error checks. The + solver stops after specified number of + iterations which should be small, 5 at most. + + This mode is intended for easy problems with + extremely fast convergence. + + Future versions of ALGLIB may introduce support for + other matrix types; for now, only symmetric + eigenproblems are supported. + + + -- ALGLIB -- + Copyright 07.06.2023 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstart(eigsubspacestate &state, const ae_int_t mtype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function performs subspace iteration in the out-of-core mode. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +bool eigsubspaceooccontinue(eigsubspacestate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: request type (current version of the solver +sends only requests for matrix-matrix products) and request size (size of +the matrices being multiplied). + +This function returns just request metrics; in order to get contents of +the matrices being multiplied, use eigsubspaceoocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 - for matrix-matrix product A*X, with A being + NxN matrix whose eigenvalues/vectors are needed, + and X being NxREQUESTSIZE one which is returned + by the eigsubspaceoocgetrequestdata(). + RequestSize - size of the X matrix (number of columns), usually + it is several times larger than number of vectors + K requested by user. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestinfo(eigsubspacestate &state, ae_int_t &requesttype, ae_int_t &requestsize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by solver to user code: matrix X (array[N,RequestSize) which have to +be multiplied by out-of-core matrix A in a product A*X. + +This function returns just request data; in order to get size of the data +prior to processing requestm, use eigsubspaceoocgetrequestinfo(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N,RequestSize] or larger, leading rectangle + is filled with dense matrix X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocgetrequestdata(eigsubspacestate &state, real_2d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +solver. Usually it is product A*X for returned by solver matrix X. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N,RequestSize] or larger, leading rectangle + is filled with product A*X. + + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocsendresult(eigsubspacestate &state, const real_2d_array &ax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function finalizes out-of-core mode of subspace eigensolver. It +should be used in conjunction with other out-of-core-related functions of +this subspackage in a loop like below: + +> alglib.eigsubspaceoocstart(state) +> while alglib.eigsubspaceooccontinue(state) do +> alglib.eigsubspaceoocgetrequestinfo(state, out RequestType, out M) +> alglib.eigsubspaceoocgetrequestdata(state, out X) +> [calculate Y=A*X, with X=R^NxM] +> alglib.eigsubspaceoocsendresult(state, in Y) +> alglib.eigsubspaceoocstop(state, out W, out Z, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + W - array[K], depending on solver settings: + * top K eigenvalues ordered by descending - if + eigenvectors are returned in Z + * zeros - if invariant subspace is returned in Z + Z - array[N,K], depending on solver settings either: + * matrix of eigenvectors found + * orthogonal basis of K-dimensional invariant subspace + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspaceoocstop(eigsubspacestate &state, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function runs subspace eigensolver for dense NxN symmetric matrix A, +given by its upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - array[N,N], symmetric NxN matrix given by one of its + triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + +NOTE: internally this function allocates a copy of NxN dense A. You should + take it into account when working with very large matrices occupying + almost all RAM. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvedenses(eigsubspacestate &state, const real_2d_array &a, const bool isupper, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function runs eigensolver for dense NxN symmetric matrix A, given by +upper or lower triangle. + +This function can not process nonsymmetric matrices. + +INPUT PARAMETERS: + State - solver state + A - NxN symmetric matrix given by one of its triangles + IsUpper - whether upper or lower triangle of A is given (the + other one is not referenced at all). + +OUTPUT PARAMETERS: + W - array[K], top K eigenvalues ordered by descending + of their absolute values + Z - array[N,K], matrix of eigenvectors found + Rep - report with additional parameters + + -- ALGLIB -- + Copyright 16.01.2017 by Bochkanov Sergey +*************************************************************************/ +void eigsubspacesolvesparses(eigsubspacestate &state, const sparsematrix &a, const bool isupper, real_1d_array &w, real_2d_array &z, eigsubspacereport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a symmetric matrix + +The algorithm finds eigen pairs of a symmetric matrix by reducing it to +tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpper - storage format. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a symmetric +matrix in a given half open interval (A, B] by using a bisection and +inverse iteration + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half open interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval (M>=0). + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, + M is equal to 0. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevdr(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a symmetric +matrix with given indexes by using bisection and inverse iteration methods. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 07.01.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixevdi(const real_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a Hermitian matrix + +The algorithm finds eigen pairs of a Hermitian matrix by reducing it to +real tridiagonal form and using the QL/QR algorithm. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +Note: + eigenvectors of Hermitian matrix are defined up to multiplication by + a complex number L, such that |L|=1. + + -- ALGLIB -- + Copyright 2005, 23 March 2007 by Bochkanov Sergey +*************************************************************************/ +bool hmatrixevd(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, real_1d_array &d, complex_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding the eigenvalues (and eigenvectors) of a Hermitian +matrix in a given half-interval (A, B] by using a bisection and inverse +iteration + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. Array whose indexes range within + [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + B1, B2 - half-interval (B1, B2] to search eigenvalues in. + +Output parameters: + M - number of eigenvalues found in a given half-interval, M>=0 + W - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..M-1]. + The eigenvectors are stored in the matrix columns. + +Result: + True, if successful. M contains the number of eigenvalues in the given + half-interval (could be equal to 0), W contains the eigenvalues, + Z contains the eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned, M is + equal to 0. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +bool hmatrixevdr(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const double b1, const double b2, ae_int_t &m, real_1d_array &w, complex_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding the eigenvalues and eigenvectors of a Hermitian +matrix with given indexes by using bisection and inverse iteration methods + +Input parameters: + A - Hermitian matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or + not. If ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + IsUpperA - storage format of matrix A. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + +Output parameters: + W - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..I2-I1]. + In that case, the eigenvectors are stored in the matrix + columns. + +Result: + True, if successful. W contains the eigenvalues, Z contains the + eigenvectors (if needed). + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration + subroutine wasn't able to find all the corresponding eigenvectors. + In that case, the eigenvalues and eigenvectors are not returned. + +Note: + eigen vectors of Hermitian matrix are defined up to multiplication by + a complex number L, such as |L|=1. + + -- ALGLIB -- + Copyright 07.01.2006, 24.03.2007 by Bochkanov Sergey. +*************************************************************************/ +bool hmatrixevdi(const complex_2d_array &a, const ae_int_t n, const ae_int_t zneeded, const bool isupper, const ae_int_t i1, const ae_int_t i2, real_1d_array &w, complex_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Finding the eigenvalues and eigenvectors of a tridiagonal symmetric matrix + +The algorithm finds the eigen pairs of a tridiagonal symmetric matrix by +using an QL/QR algorithm with implicit shifts. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix A. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix + are multiplied by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity + transformation of a symmetric matrix; + * 2, the eigenvectors of a tridiagonal matrix replace the + square matrix Z; + * 3, matrix Z contains the first row of the eigenvectors + matrix. + Z - if ZNeeded=1, Z contains the square matrix by which the + eigenvectors are multiplied. + Array whose indexes range within [0..N-1, 0..N-1]. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains the product of a given matrix (from the left) + and the eigenvectors matrix (from the right); + * 2, Z contains the eigenvectors. + * 3, Z contains the first row of the eigenvectors matrix. + If ZNeeded<3, Z is the array whose indexes range within [0..N-1, 0..N-1]. + In that case, the eigenvectors are stored in the matrix columns. + If ZNeeded=3, Z is the array whose indexes range within [0..0, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + September 30, 1994 +*************************************************************************/ +bool smatrixtdevd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding the tridiagonal matrix eigenvalues/vectors in a +given half-interval (A, B] by using bisection and inverse iteration. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix, N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the tridiagonal + matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace matrix Z. + A, B - half-interval (A, B] to search eigenvalues in. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range + within [0..N-1, 0..N-1]) which reduces the given symmetric + matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..M-1]. + M - number of eigenvalues found in the given half-interval (M>=0). + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the + left) and NxM matrix of the eigenvectors found (from the + right). Array whose indexes range within [0..N-1, 0..M-1]. + * 2, contains the matrix of the eigenvectors found. + Array whose indexes range within [0..N-1, 0..M-1]. + +Result: + + True, if successful. In that case, M contains the number of eigenvalues + in the given half-interval (could be equal to 0), D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the + eigenvalues in the given interval or if the inverse iteration subroutine + wasn't able to find all the corresponding eigenvectors. In that case, + the eigenvalues and eigenvectors are not returned, M is equal to 0. + + -- ALGLIB -- + Copyright 31.03.2008 by Bochkanov Sergey +*************************************************************************/ +bool smatrixtdevdr(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const double a, const double b, ae_int_t &m, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Subroutine for finding tridiagonal matrix eigenvalues/vectors with given +indexes (in ascending order) by using the bisection and inverse iteraion. + +Input parameters: + D - the main diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-1]. + E - the secondary diagonal of a tridiagonal matrix. + Array whose index ranges within [0..N-2]. + N - size of matrix. N>=0. + ZNeeded - flag controlling whether the eigenvectors are needed or not. + If ZNeeded is equal to: + * 0, the eigenvectors are not needed; + * 1, the eigenvectors of a tridiagonal matrix are multiplied + by the square matrix Z. It is used if the + tridiagonal matrix is obtained by the similarity transformation + of a symmetric matrix. + * 2, the eigenvectors of a tridiagonal matrix replace + matrix Z. + I1, I2 - index interval for searching (from I1 to I2). + 0 <= I1 <= I2 <= N-1. + Z - if ZNeeded is equal to: + * 0, Z isn't used and remains unchanged; + * 1, Z contains the square matrix (array whose indexes range within [0..N-1, 0..N-1]) + which reduces the given symmetric matrix to tridiagonal form; + * 2, Z isn't used (but changed on the exit). + +Output parameters: + D - array of the eigenvalues found. + Array whose index ranges within [0..I2-I1]. + Z - if ZNeeded is equal to: + * 0, doesn't contain any information; + * 1, contains the product of a given NxN matrix Z (from the left) and + Nx(I2-I1) matrix of the eigenvectors found (from the right). + Array whose indexes range within [0..N-1, 0..I2-I1]. + * 2, contains the matrix of the eigenvalues found. + Array whose indexes range within [0..N-1, 0..I2-I1]. + + +Result: + + True, if successful. In that case, D contains the eigenvalues, + Z contains the eigenvectors (if needed). + It should be noted that the subroutine changes the size of arrays D and Z. + + False, if the bisection method subroutine wasn't able to find the eigenvalues + in the given interval or if the inverse iteration subroutine wasn't able + to find all the corresponding eigenvectors. In that case, the eigenvalues + and eigenvectors are not returned. + + -- ALGLIB -- + Copyright 25.12.2005 by Bochkanov Sergey +*************************************************************************/ +bool smatrixtdevdi(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const ae_int_t zneeded, const ae_int_t i1, const ae_int_t i2, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Finding eigenvalues and eigenvectors of a general (unsymmetric) matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm finds eigenvalues and eigenvectors of a general matrix by +using the QR algorithm with multiple shifts. The algorithm can find +eigenvalues and both left and right eigenvectors. + +The right eigenvector is a vector x such that A*x = w*x, and the left +eigenvector is a vector y such that y'*A = w*y' (here y' implies a complex +conjugate transposition of vector y). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + VNeeded - flag controlling whether eigenvectors are needed or not. + If VNeeded is equal to: + * 0, eigenvectors are not returned; + * 1, right eigenvectors are returned; + * 2, left eigenvectors are returned; + * 3, both left and right eigenvectors are returned. + +Output parameters: + WR - real parts of eigenvalues. + Array whose index ranges within [0..N-1]. + WR - imaginary parts of eigenvalues. + Array whose index ranges within [0..N-1]. + VL, VR - arrays of left and right eigenvectors (if they are needed). + If WI[i]=0, the respective eigenvalue is a real number, + and it corresponds to the column number I of matrices VL/VR. + If WI[i]>0, we have a pair of complex conjugate numbers with + positive and negative imaginary parts: + the first eigenvalue WR[i] + sqrt(-1)*WI[i]; + the second eigenvalue WR[i+1] + sqrt(-1)*WI[i+1]; + WI[i]>0 + WI[i+1] = -WI[i] < 0 + In that case, the eigenvector corresponding to the first + eigenvalue is located in i and i+1 columns of matrices + VL/VR (the column number i contains the real part, and the + column number i+1 contains the imaginary part), and the vector + corresponding to the second eigenvalue is a complex conjugate to + the first vector. + Arrays whose indexes range within [0..N-1, 0..N-1]. + +Result: + True, if the algorithm has converged. + False, if the algorithm has not converged. + +Note 1: + Some users may ask the following question: what if WI[N-1]>0? + WI[N] must contain an eigenvalue which is complex conjugate to the + N-th eigenvalue, but the array has only size N? + The answer is as follows: such a situation cannot occur because the + algorithm finds a pairs of eigenvalues, therefore, if WI[i]>0, I is + strictly less than N-1. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms of linear algebra). If you require maximum performance + on your machine, it is recommended to adjust this parameter manually. + + +See also the InternalTREVC subroutine. + +The algorithm is based on the LAPACK 3.0 library. +*************************************************************************/ +bool rmatrixevd(const real_2d_array &a, const ae_int_t n, const ae_int_t vneeded, real_1d_array &wr, real_1d_array &wi, real_2d_array &vl, real_2d_array &vr, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +LU decomposition of a general real matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixlu(real_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); +void rmatrixlu(real_2d_array &a, integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LU decomposition of a general complex matrix with row pivoting + +A is represented as A = P*L*U, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=min(M,N)-1, + Pi - permutation matrix for I and Pivots[I] + +INPUT PARAMETERS: + A - array[0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + + +OUTPUT PARAMETERS: + A - matrices L and U in compact form: + * L is stored under main diagonal + * U is stored on and above main diagonal + Pivots - permutation matrix in compact form. + array[0..Min(M-1,N-1)]. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.01.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixlu(complex_2d_array &a, const ae_int_t m, const ae_int_t n, integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); +void cmatrixlu(complex_2d_array &a, integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a Hermitian positive- +definite matrix. The result of an algorithm is a representation of A as +A=U'*U or A=L*L' (here X' denotes conj(X^T)). + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U'*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009-22.01.2018 + Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholesky(complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); +bool hpdmatrixcholesky(complex_2d_array &a, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cache-oblivious Cholesky decomposition + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite matrix. The result of an algorithm is a representation of A as +A=U^T*U or A=L*L^T + +INPUT PARAMETERS: + A - upper or lower triangle of a factorized matrix. + array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - if IsUpper=True, then A contains an upper triangle of + a symmetric matrix, otherwise A contains a lower one. + +OUTPUT PARAMETERS: + A - the result of factorization. If IsUpper=True, then + the upper triangle contains matrix U, so that A = U^T*U, + and the elements below the main diagonal are not modified. + Similarly, if IsUpper = False. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 15.12.2009 + Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholesky(real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); +bool spdmatrixcholesky(real_2d_array &a, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Update of Cholesky decomposition: rank-1 update to original A. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateAdd1Buf(). + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1(real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, const xparams _xparams = alglib::xdefault); +void spdmatrixcholeskyupdateadd1(real_2d_array &a, const bool isupper, const real_1d_array &u, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. + +This function uses internally allocated buffer which is not saved between +subsequent calls. So, if you perform a lot of subsequent updates, +we recommend you to use "buffered" version of this function: +SPDMatrixCholeskyUpdateFixBuf(). + +"FIXING" EXPLAINED: + + Suppose we have N*N positive definite matrix A. "Fixing" some variable + means filling corresponding row/column of A by zeros, and setting + diagonal element to 1. + + For example, if we fix 2nd variable in 4*4 matrix A, it becomes Af: + + ( A00 A01 A02 A03 ) ( Af00 0 Af02 Af03 ) + ( A10 A11 A12 A13 ) ( 0 1 0 0 ) + ( A20 A21 A22 A23 ) => ( Af20 0 Af22 Af23 ) + ( A30 A31 A32 A33 ) ( Af30 0 Af32 Af33 ) + + If we have Cholesky decomposition of A, it must be recalculated after + variables were fixed. However, it is possible to use efficient + algorithm, which needs O(K*N^2) time to "fix" K variables, given + Cholesky decomposition of original, "unfixed" A. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + +NOTE: this function always succeeds, so it does not return completion code + +NOTE: this function checks sizes of input arrays, but it does NOT checks + for presence of infinities or NAN's. + +NOTE: this function is efficient only for moderate amount of updated + variables - say, 0.1*N or 0.3*N. For larger amount of variables it + will still work, but you may get better performance with + straightforward Cholesky. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefix(real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, const xparams _xparams = alglib::xdefault); +void spdmatrixcholeskyupdatefix(real_2d_array &a, const bool isupper, const boolean_1d_array &fix, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Update of Cholesky decomposition: rank-1 update to original A. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +See comments for SPDMatrixCholeskyUpdateAdd1() for more information. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + U - array[N], rank-1 update to A: A_mod = A + u*u' + Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdateadd1buf(real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &u, real_1d_array &bufr, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Update of Cholesky decomposition: "fixing" some variables. "Buffered" +version which uses preallocated buffer which is saved between subsequent +function calls. + +See comments for SPDMatrixCholeskyUpdateFix() for more information. + +INPUT PARAMETERS: + A - upper or lower Cholesky factor. + array with elements [0..N-1, 0..N-1]. + Exception is thrown if array size is too small. + N - size of matrix A, N>0 + IsUpper - if IsUpper=True, then A contains upper Cholesky factor; + otherwise A contains a lower one. + Fix - array[N], I-th element is True if I-th variable must be + fixed. Exception is thrown if array size is too small. + BufR - possibly preallocated buffer; automatically resized if + needed. It is recommended to reuse this buffer if you + perform a lot of subsequent decompositions. + +OUTPUT PARAMETERS: + A - updated factorization. If IsUpper=True, then the upper + triangle contains matrix U, and the elements below the main + diagonal are not modified. Similarly, if IsUpper = False. + + -- ALGLIB -- + 03.02.2014 + Sergey Bochkanov +*************************************************************************/ +void spdmatrixcholeskyupdatefixbuf(real_2d_array &a, const ae_int_t n, const bool isupper, const boolean_1d_array &fix, real_1d_array &bufr, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse LU decomposition with column pivoting for sparsity and row pivoting +for stability. Input must be square sparse matrix stored in CRS format. + +The algorithm computes LU decomposition of a general square matrix +(rectangular ones are not supported). The result of an algorithm is a +representation of A as A = P*L*U*Q, where: +* L is lower unitriangular matrix +* U is upper triangular matrix +* P = P0*P1*...*PK, K=N-1, Pi - permutation matrix for I and P[I] +* Q = QK*...*Q1*Q0, K=N-1, Qi - permutation matrix for I and Q[I] + +This function pivots columns for higher sparsity, and then pivots rows for +stability (larger element at the diagonal). + +INPUT PARAMETERS: + A - sparse NxN matrix in CRS format. An exception is generated + if matrix is non-CRS or non-square. + PivotType- pivoting strategy: + * 0 for best pivoting available (2 in current version) + * 1 for row-only pivoting (NOT RECOMMENDED) + * 2 for complete pivoting which produces most sparse outputs + +OUTPUT PARAMETERS: + A - the result of factorization, matrices L and U stored in + compact form using CRS sparse storage format: + * lower unitriangular L is stored strictly under main diagonal + * upper triangilar U is stored ON and ABOVE main diagonal + P - row permutation matrix in compact form, array[N] + Q - col permutation matrix in compact form, array[N] + +This function always succeeds, i.e. it ALWAYS returns valid factorization, +but for your convenience it also returns boolean value which helps to +detect symbolically degenerate matrices: +* function returns TRUE, if the matrix was factorized AND symbolically + non-degenerate +* function returns FALSE, if the matrix was factorized but U has strictly + zero elements at the diagonal (the factorization is returned anyway). + + + -- ALGLIB routine -- + 03.09.2018 + Bochkanov Sergey +*************************************************************************/ +bool sparselu(sparsematrix &a, const ae_int_t pivottype, integer_1d_array &p, integer_1d_array &q, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky decomposition for skyline matrixm using in-place algorithm +without allocating additional storage. + +The algorithm computes Cholesky decomposition of a symmetric positive- +definite sparse matrix. The result of an algorithm is a representation of +A as A=U^T*U or A=L*L^T + +This function allows to perform very efficient decomposition of low-profile +matrices (average bandwidth is ~5-10 elements). For larger matrices it is +recommended to use supernodal Cholesky decomposition: SparseCholeskyP() or +SparseCholeskyAnalyze()/SparseCholeskyFactorize(). + +INPUT PARAMETERS: + A - sparse matrix in skyline storage (SKS) format. + N - size of matrix A (can be smaller than actual size of A) + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored (it may contant some + data, but it is not changed). + + +OUTPUT PARAMETERS: + A - the result of factorization, stored in SKS. If IsUpper=True, + then the upper triangle contains matrix U, such that + A = U^T*U. Lower triangle is not changed. + Similarly, if IsUpper = False. In this case L is returned, + and we have A = L*(L^T). + Note that THIS function does not perform permutation of + rows to reduce bandwidth. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is not determined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.01.2014 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyskyline(sparsematrix &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage, +without rows/cols permutation. + +This function is the most convenient (less parameters to specify) although +the less efficient, version of sparse Cholesky. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +Internally it: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with no permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization + +Following alternatives may result in better performance: +* using SparseCholeskyP(), which selects best pivoting available, which + almost always results in improved sparsity and cache locality +* using SparseCholeskyAnalyze() and SparseCholeskyFactorize() functions + directly, which may improve performance of repetitive factorizations + with same sparsity patterns. + +The latter also allows one to perform LDLT factorization of indefinite +matrix (one with strictly diagonal D, which is known to be stable only +in few special cases, like quasi-definite matrices). + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + Note that THIS function does not perform permutation of + the rows to reduce fill-in. + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholesky(sparsematrix &a, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky decomposition for a matrix stored in any sparse storage +format, with performance-enhancing permutation of rows/cols. + +Present version is configured to perform supernodal permutation with +a sparsity reducing ordering. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a wrapper around generic sparse decomposition functions +that internally: +* calls SparseCholeskyAnalyze() function to perform symbolic analysis + phase with best available permutation being configured. +* calls SparseCholeskyFactorize() function to perform numerical phase of + the factorization. + +NOTE: using SparseCholeskyAnalyze() and SparseCholeskyFactorize() directly + may improve performance of repetitive factorizations with same + sparsity patterns. It also allows one to perform LDLT factorization + of indefinite matrix - a factorization with strictly diagonal D, + which is known to be stable only in few special cases, like quasi- + definite matrices. + +INPUT PARAMETERS: + A - a square NxN sparse matrix, stored in any storage format. + IsUpper - if IsUpper=True, then factorization is performed on upper + triangle. Another triangle is ignored on input, dropped + on output. Similarly, if IsUpper=False, the lower triangle + is processed. + +OUTPUT PARAMETERS: + A - the result of factorization, stored in CRS format: + * if IsUpper=True, then the upper triangle contains matrix + U such that A = U^T*U and the lower triangle is empty. + * similarly, if IsUpper=False, then lower triangular L is + returned and we have A = L*(L^T). + P - a row/column permutation, a product of P0*P1*...*Pk, k=N-1, + with Pi being permutation of rows/cols I and P[I] + +RESULT: + If the matrix is positive-definite, the function returns True. + Otherwise, the function returns False. Contents of A is undefined + in such case. + +NOTE: for performance reasons this function does NOT check that input + matrix includes only finite values. It is your responsibility to + make sure that there are no infinite or NAN values in the matrix. + + -- ALGLIB routine -- + 16.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyp(sparsematrix &a, const bool isupper, integer_1d_array &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky/LDLT decomposition: symbolic analysis phase. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function performs preliminary analysis of the Cholesky/LDLT +factorization. It allows to choose different permutation types and to +choose between classic Cholesky and indefinite LDLT factorization (the +latter is computed with strictly diagonal D, i.e. without Bunch-Kauffman +pivoting). + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + A - sparse square matrix in any sparse storage format. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + FactType - factorization type: + * 0 for traditional Cholesky of SPD matrix + * 1 for LDLT decomposition with strictly diagonal D, + which may have non-positive entries. + PermType - permutation type: + *-1 for absence of permutation + * 0 for best fill-in reducing permutation available, + which is 3 in the current version + * 1 for supernodal ordering (improves locality and + performance, does NOT change fill-in factor) + * 2 for original AMD ordering + * 3 for improved AMD (approximate minimum degree) + ordering with better handling of matrices with + dense rows/columns + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + +This function fails if and only if the matrix A is symbolically degenerate +i.e. has diagonal element which is exactly zero. In such case False is +returned, contents of Analysis object is undefined. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyanalyze(const sparsematrix &a, const bool isupper, const ae_int_t facttype, const ae_int_t permtype, sparsedecompositionanalysis &analysis, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky decomposition: numerical analysis phase. + +IMPORTANT: the commercial edition of ALGLIB can parallelize this function. + Specific speed-up due to parallelism heavily depends on a + sparsity pattern, with the following matrix classes being the + easiest ones to parallelize: + * large matrices with many nearly-independent sets of rows/cols + * matrices with large dense blocks on the diagonal + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +Depending on settings specified during SparseCholeskyAnalyze() call it may +produce classic Cholesky or L*D*LT decomposition (with strictly diagonal +D), without permutation or with performance-enhancing permutation P. + +IMPORTANT: if all you need is to solve a linear system A*x=b with positive + definite A, we strongly recommend you to use functions provided + by the DIRECTSPARSESOLVERS subpackage of the SOLVERS package + instead of this function. + + Functions provided by the TRFAC subpackage are designed to + return factorizations, i.e. such L that A=LL' or A=LDL'. Thus, + TRFAC unit can not utilize some performance improvements that + allow to solve Ax=b without returning factors L and D. + + In particular, performance backends, dynamic regularization and + iterative refinement are not supported by TRFAC but can be + included in DIRECTSPARSESOLVERS. + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix, and lower triangular output + is requested. + +NOTE: L*D*LT family of factorization may be used to factorize indefinite + matrices. However, numerical stability is guaranteed ONLY for a class + of quasi-definite matrices. + +INPUT PARAMETERS: + Analysis - prior analysis with internally stored matrix which will + be factorized + NeedUpper - whether upper triangular or lower triangular output is + needed + +OUTPUT PARAMETERS: + A - Cholesky decomposition of A stored in lower triangular + CRS format, i.e. A=L*L' (or upper triangular CRS, with + A=U'*U, depending on NeedUpper parameter). + D - array[N], diagonal factor. If no diagonal factor was + required during analysis phase, still returned but + filled with 1's + P - array[N], pivots. Permutation matrix P is a product of + P(0)*P(1)*...*P(N-1), where P(i) is a permutation of + row/col I and P[I] (with P[I]>=I). + If no permutation was requested during analysis phase, + still returned but filled with identity permutation. + +The function returns True when factorization resulted in nondegenerate +matrix. False is returned when factorization fails (Cholesky factorization +of indefinite matrix) or LDLT factorization has exactly zero elements at +the diagonal. In the latter case contents of A, D and P is undefined. + +The analysis object is not changed during the factorization. Subsequent +calls to SparseCholeskyFactorize() will result in same factorization being +performed one more time. + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +bool sparsecholeskyfactorize(sparsedecompositionanalysis &analysis, const bool needupper, sparsematrix &a, real_1d_array &d, integer_1d_array &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse Cholesky decomposition: update internally stored matrix with +another one with exactly same sparsity pattern. + +This function is a part of the 'expert' sparse Cholesky API: +* SparseCholeskyAnalyze(), that performs symbolic analysis phase and loads + matrix to be factorized into internal storage +* SparseCholeskySetModType(), that allows to use modified Cholesky/LDLT + with lower bounds on pivot magnitudes and additional overflow safeguards +* SparseCholeskyFactorize(), that performs numeric factorization using + precomputed symbolic analysis and internally stored matrix - and outputs + result +* SparseCholeskyReload(), that reloads one more matrix with same sparsity + pattern into internal storage so one may reuse previously allocated + temporaries and previously performed symbolic analysis + +This specific function replaces internally stored numerical values with +ones from another sparse matrix (but having exactly same sparsity pattern +as one that was used for initial SparseCholeskyAnalyze() call). + +NOTE: all internal processing is performed with lower triangular matrices + stored in CRS format. Any other storage formats and/or upper + triangular storage means that one format conversion and/or one + transposition will be performed internally for the analysis and + factorization phases. Thus, highest performance is achieved when + input is a lower triangular CRS matrix. + +INPUT PARAMETERS: + Analysis - analysis object + A - sparse square matrix in any sparse storage format. It + MUST have exactly same sparsity pattern as that of the + matrix that was passed to SparseCholeskyAnalyze(). + Any difference (missing elements or additional elements) + may result in unpredictable and undefined behavior - + an algorithm may fail due to memory access violation. + IsUpper - whether upper or lower triangle is decomposed (the + other one is ignored). + +OUTPUT PARAMETERS: + Analysis - contains: + * symbolic analysis of the matrix structure which will + be used later to guide numerical factorization. + * specific numeric values loaded into internal memory + waiting for the factorization to be performed + + -- ALGLIB routine -- + 20.09.2020 + Bochkanov Sergey +*************************************************************************/ +void sparsecholeskyreload(sparsedecompositionanalysis &analysis, const sparsematrix &a, const bool isupper, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Singular value decomposition of a bidiagonal matrix (extended algorithm) + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (Intel MKL support on x64, other + ! libraries on other platforms) + ! + ! Vendor libraries give approximately constant with respect to the + ! number of worker threads) acceleration factor which depends on the CPU + ! being used, problem size and "baseline" ALGLIB edition which is + ! used for comparison. + ! + ! Generally, commercial ALGLIB is several times faster than open-source + ! generic C edition, and many times faster than open-source C# edition. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm performs the singular value decomposition of a bidiagonal +matrix B (upper or lower) representing it as B = Q*S*P^T, where Q and P - +orthogonal matrices, S - diagonal matrix with non-negative elements on the +main diagonal, in descending order. + +The algorithm finds singular values. In addition, the algorithm can +calculate matrices Q and P (more precisely, not the matrices, but their +product with given matrices U and VT - U*Q and (P^T)*VT)). Of course, +matrices U and VT can be of any type, including identity. Furthermore, the +algorithm can calculate Q'*C (this product is calculated more effectively +than U*Q, because this calculation operates with rows instead of matrix +columns). + +The feature of the algorithm is its ability to find all singular values +including those which are arbitrarily close to 0 with relative accuracy +close to machine precision. If the parameter IsFractionalAccuracyRequired +is set to True, all singular values will have high relative accuracy close +to machine precision. If the parameter is set to False, only the biggest +singular value will have relative accuracy close to machine precision. +The absolute error of other singular values is equal to the absolute error +of the biggest singular value. + +Input parameters: + D - main diagonal of matrix B. + Array whose index ranges within [0..N-1]. + E - superdiagonal (or subdiagonal) of matrix B. + Array whose index ranges within [0..N-2]. + N - size of matrix B. + IsUpper - True, if the matrix is upper bidiagonal. + IsFractionalAccuracyRequired - + THIS PARAMETER IS IGNORED SINCE ALGLIB 3.5.0 + SINGULAR VALUES ARE ALWAYS SEARCHED WITH HIGH ACCURACY. + U - matrix to be multiplied by Q. + Array whose indexes range within [0..NRU-1, 0..N-1]. + The matrix can be bigger, in that case only the submatrix + [0..NRU-1, 0..N-1] will be multiplied by Q. + NRU - number of rows in matrix U. + C - matrix to be multiplied by Q'. + Array whose indexes range within [0..N-1, 0..NCC-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCC-1] will be multiplied by Q'. + NCC - number of columns in matrix C. + VT - matrix to be multiplied by P^T. + Array whose indexes range within [0..N-1, 0..NCVT-1]. + The matrix can be bigger, in that case only the submatrix + [0..N-1, 0..NCVT-1] will be multiplied by P^T. + NCVT - number of columns in matrix VT. + +Output parameters: + D - singular values of matrix B in descending order. + U - if NRU>0, contains matrix U*Q. + VT - if NCVT>0, contains matrix (P^T)*VT. + C - if NCC>0, contains matrix Q'*C. + +Result: + True, if the algorithm has converged. + False, if the algorithm hasn't converged (rare case). + +NOTE: multiplication U*Q is performed by means of transposition to internal + buffer, multiplication and backward transposition. It helps to avoid + costly columnwise operations and speed-up algorithm. + +Additional information: + The type of convergence is controlled by the internal parameter TOL. + If the parameter is greater than 0, the singular values will have + relative accuracy TOL. If TOL<0, the singular values will have + absolute accuracy ABS(TOL)*norm(B). + By default, |TOL| falls within the range of 10*Epsilon and 100*Epsilon, + where Epsilon is the machine precision. It is not recommended to use + TOL less than 10*Epsilon since this will considerably slow down the + algorithm and may not lead to error decreasing. + +History: + * 31 March, 2007. + changed MAXITR from 6 to 12. + + -- LAPACK routine (version 3.0) -- + Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., + Courant Institute, Argonne National Lab, and Rice University + October 31, 1999. +*************************************************************************/ +bool rmatrixbdsvd(real_1d_array &d, const real_1d_array &e, const ae_int_t n, const bool isupper, const bool isfractionalaccuracyrequired, real_2d_array &u, const ae_int_t nru, real_2d_array &c, const ae_int_t ncc, real_2d_array &vt, const ae_int_t ncvt, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Singular value decomposition of a rectangular matrix. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions, x64/ARM platform) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The algorithm calculates the singular value decomposition of a matrix of +size MxN: A = U * S * V^T + +The algorithm finds the singular values and, optionally, matrices U and V^T. +The algorithm can find both first min(M,N) columns of matrix U and rows of +matrix V^T (singular vectors), and matrices U and V^T wholly (of sizes MxM +and NxN respectively). + +Take into account that the subroutine does not return matrix V but V^T. + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..M-1, 0..N-1]. + M - number of rows in matrix A. + N - number of columns in matrix A. + UNeeded - 0, 1 or 2. See the description of the parameter U. + VTNeeded - 0, 1 or 2. See the description of the parameter VT. + AdditionalMemory - + If the parameter: + * equals 0, the algorithm doesn't use additional + memory (lower requirements, lower performance). + * equals 1, the algorithm uses additional + memory of size min(M,N)*min(M,N) of real numbers. + It often speeds up the algorithm. + * equals 2, the algorithm uses additional + memory of size M*min(M,N) of real numbers. + It allows to get a maximum performance. + The recommended value of the parameter is 2. + +Output parameters: + W - contains singular values in descending order. + U - if UNeeded=0, U isn't changed, the left singular vectors + are not calculated. + if Uneeded=1, U contains left singular vectors (first + min(M,N) columns of matrix U). Array whose indexes range + within [0..M-1, 0..Min(M,N)-1]. + if UNeeded=2, U contains matrix U wholly. Array whose + indexes range within [0..M-1, 0..M-1]. + VT - if VTNeeded=0, VT isn't changed, the right singular vectors + are not calculated. + if VTNeeded=1, VT contains right singular vectors (first + min(M,N) rows of matrix V^T). Array whose indexes range + within [0..min(M,N)-1, 0..N-1]. + if VTNeeded=2, VT contains matrix V^T wholly. Array whose + indexes range within [0..N-1, 0..N-1]. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsvd(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const ae_int_t uneeded, const ae_int_t vtneeded, const ae_int_t additionalmemory, real_1d_array &w, real_2d_array &u, real_2d_array &vt, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond1(const real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of a matrix condition number (2-norm) + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then the matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2(const real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of a matrix condition number (2-norm) for a rectangular matrix. + +The algorithm calculates exact 2-norm reciprocal condition number using SVD. + +Input parameters: + A - matrix. Array[M,N] + M, N- rows and columns count, >=1 + +Result: 1/cond2(A) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcond2rect(const real_2d_array &a, const ae_int_t m, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixrcondinf(const real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +2-norm condition number of a symmetric positive definite matrix using EVD. + +Input parameters: + A - symmetric positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array[N,N] + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/cond(A), if matrix A is positive definite, + 0, if matrix A is not positive definite + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixrcond2(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond1(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix: reciprocal 2-norm condition number + +The algorithm calculates a reciprocal 2-norm condition number using SVD. + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/cond(A) + +NOTE: + if k(A) is very large, then matrix is assumed to be degenerate, + k(A)=INF, 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcond2(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixtrrcondinf(const real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix. + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm of condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + A - Hermitian positive definite matrix which is given by its + upper or lower triangle depending on the value of + IsUpper. Array with elements [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - storage format. + +Result: + 1/LowerBound(cond(A)), if matrix A is positive definite, + -1, if matrix A is not positive definite, and its condition number + could not be found by this algorithm. + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of a matrix condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcond1(const complex_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixrcondinf(const complex_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcond1(const real_2d_array &lua, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the RMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double rmatrixlurcondinf(const real_2d_array &lua, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Condition number estimate of a symmetric positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double spdmatrixcholeskyrcond(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Condition number estimate of a Hermitian positive definite matrix given by +Cholesky decomposition. + +The algorithm calculates a lower bound of the condition number. In this +case, the algorithm does not return a lower bound of the condition number, +but an inverse number (to avoid an overflow in case of a singular matrix). + +It should be noted that 1-norm and inf-norm condition numbers of symmetric +matrices are equal, so the algorithm doesn't take into account the +differences between these types of norms. + +Input parameters: + CD - Cholesky decomposition of matrix A, + output of SMatrixCholesky subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double hpdmatrixcholeskyrcond(const complex_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcond1(const complex_2d_array &lua, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Estimate of the condition number of a matrix given by its LU decomposition +(infinity norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + LUA - LU decomposition of a matrix in compact form. Output of + the CMatrixLU subroutine. + N - size of matrix A. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixlurcondinf(const complex_2d_array &lua, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix: estimate of a condition number (1-norm) + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array[0..N-1, 0..N-1]. + N - size of A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcond1(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix: estimate of a matrix condition number (infinity-norm). + +The algorithm calculates a lower bound of the condition number. In this case, +the algorithm does not return a lower bound of the condition number, but an +inverse number (to avoid an overflow in case of a singular matrix). + +Input parameters: + A - matrix. Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + IsUpper - True, if the matrix is upper triangular. + IsUnit - True, if the matrix has a unit diagonal. + +Result: 1/LowerBound(cond(A)) + +NOTE: + if k(A) is very large, then matrix is assumed degenerate, k(A)=INF, + 0.0 is returned in such cases. +*************************************************************************/ +double cmatrixtrrcondinf(const complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This procedure initializes matrix norm estimator. + +USAGE: +1. User initializes algorithm state with NormEstimatorCreate() call +2. User calls NormEstimatorEstimateSparse() (or NormEstimatorIteration()) +3. User calls NormEstimatorResults() to get solution. + +INPUT PARAMETERS: + M - number of rows in the matrix being estimated, M>0 + N - number of columns in the matrix being estimated, N>0 + NStart - number of random starting vectors + recommended value - at least 5. + NIts - number of iterations to do with best starting vector + recommended value - at least 5. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTE: this algorithm is effectively deterministic, i.e. it always returns +same result when repeatedly called for the same matrix. In fact, algorithm +uses randomized starting vectors, but internal random numbers generator +always generates same sequence of the random values (it is a feature, not +bug). + +Algorithm can be made non-deterministic with NormEstimatorSetSeed(0) call. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorcreate(const ae_int_t m, const ae_int_t n, const ae_int_t nstart, const ae_int_t nits, normestimatorstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes seed value used by algorithm. In some cases we need +deterministic processing, i.e. subsequent calls must return equal results, +in other cases we need non-deterministic algorithm which returns different +results for the same matrix on every pass. + +Setting zero seed will lead to non-deterministic algorithm, while non-zero +value will make our algorithm deterministic. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + SeedVal - seed value, >=0. Zero value = non-deterministic algo. + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorsetseed(normestimatorstate &state, const ae_int_t seedval, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function estimates norm of the sparse M*N matrix A. + +INPUT PARAMETERS: + State - norm estimator state, must be initialized with a call + to NormEstimatorCreate() + A - sparse M*N matrix, must be converted to CRS format + prior to calling this function. + +After this function is over you can call NormEstimatorResults() to get +estimate of the norm(A). + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorestimatesparse(normestimatorstate &state, const sparsematrix &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Matrix norm estimation results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + Nrm - estimate of the matrix norm, Nrm>=0 + + -- ALGLIB -- + Copyright 06.12.2011 by Bochkanov Sergey +*************************************************************************/ +void normestimatorresults(const normestimatorstate &state, double &nrm, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of RMatrixLU subroutine). + Pivots - table of permutations + (the output of RMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixluinverse(real_2d_array &a, const integer_1d_array &pivots, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a general matrix. + +INPUT PARAMETERS: + A - matrix. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005-2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinverse(real_2d_array &a, const ae_int_t n, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixinverse(real_2d_array &a, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a matrix given by its LU decomposition. + +INPUT PARAMETERS: + A - LU decomposition of the matrix + (output of CMatrixLU subroutine). + Pivots - table of permutations + (the output of CMatrixLU subroutine). + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 05.02.2010 + Bochkanov Sergey +*************************************************************************/ +void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixluinverse(complex_2d_array &a, const integer_1d_array &pivots, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a general matrix. + +Input parameters: + A - matrix + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + +Output parameters: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void cmatrixinverse(complex_2d_array &a, const ae_int_t n, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixinverse(complex_2d_array &a, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a symmetric positive definite matrix which is given +by Cholesky decomposition. + +INPUT PARAMETERS: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of SPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, the symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + the function + * if False, the symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + the function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, corresponding triangle + contains inverse matrix, the other triangle is not + modified. + * for rep.terminationtype<0, corresponding triangle is + zero-filled; the other triangle is not modified. + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskyinverse(real_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixcholeskyinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a symmetric positive definite matrix. + +Given an upper or lower triangle of a symmetric positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void spdmatrixinverse(real_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a Hermitian positive definite matrix which is given +by Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition of the matrix to be inverted: + A=U'*U or A = L*L'. + Output of HPDMatrixCholesky subroutine. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskyinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixcholeskyinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inversion of a Hermitian positive definite matrix. + +Given an upper or lower triangle of a Hermitian positive definite matrix, +the algorithm generates matrix A^-1 and saves the upper or lower triangle +depending on the input. + +INPUT PARAMETERS: + A - matrix to be inverted (upper or lower triangle), array[N,N] + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB routine -- + 10.02.2010 + Bochkanov Sergey +*************************************************************************/ +void hpdmatrixinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix inverse (real) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixtrinverse(real_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixtrinverse(real_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Triangular matrix inverse (complex) + +The subroutine inverts the following types of matrices: + * upper triangular + * upper triangular with unit diagonal + * lower triangular + * lower triangular with unit diagonal + +In case of an upper (lower) triangular matrix, the inverse matrix will +also be upper (lower) triangular, and after the end of the algorithm, the +inverse matrix replaces the source matrix. The elements below (above) the +main diagonal are not changed by the algorithm. + +If the matrix has a unit diagonal, the inverse matrix also has a unit +diagonal, and the diagonal elements are not passed to the algorithm. + +INPUT PARAMETERS: + A - matrix, array[0..N-1, 0..N-1]. + N - size of the matrix A (optional): + * if given, only principal NxN submatrix is processed and + overwritten. Trailing elements are unchanged. + * if not given, the size is automatically determined from + the matrix size (A must be a square matrix) + IsUpper - True, if the matrix is upper triangular. + IsUnit - diagonal type (optional): + * if True, matrix has unit diagonal (a[i,i] are NOT used) + * if False, matrix diagonal is arbitrary + * if not given, False is assumed + +OUTPUT PARAMETERS: + A - inverse of matrix A, array[N,N]: + * for rep.terminationtype>0, contains matrix inverse + * for rep.terminationtype<0, zero-filled + Rep - solver report: + * rep.terminationtype>0 for success, <0 for failure + * see below for more info + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* terminationtype completion code: + * 1 for success + * -3 for a singular or extremely ill-conditioned matrix +* r1 reciprocal of condition number: 1/cond(A), 1-norm. +* rinf reciprocal of condition number: 1/cond(A), inf-norm. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 05.02.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixtrinverse(complex_2d_array &a, const ae_int_t n, const bool isupper, const bool isunit, matinvreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixtrinverse(complex_2d_array &a, const bool isupper, matinvreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a number to an element +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - row where the element to be updated is stored. + UpdColumn - column where the element to be updated is stored. + UpdVal - a number to be added to the element. + + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatesimple(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const ae_int_t updcolumn, const double updval, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a row +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdRow - the row of A whose vector V was added. + 0 <= Row <= N-1 + V - the vector to be added to a row. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdaterow(real_2d_array &inva, const ae_int_t n, const ae_int_t updrow, const real_1d_array &v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm updates matrix A^-1 when adding a vector to a column +of matrix A. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + UpdColumn - the column of A whose vector U was added. + 0 <= UpdColumn <= N-1 + U - the vector to be added to a column. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of modified matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdatecolumn(real_2d_array &inva, const ae_int_t n, const ae_int_t updcolumn, const real_1d_array &u, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse matrix update by the Sherman-Morrison formula + +The algorithm computes the inverse of matrix A+u*v' by using the given matrix +A^-1 and the vectors u and v. + +Input parameters: + InvA - inverse of matrix A. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrix A. + U - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + V - the vector modifying the matrix. + Array whose index ranges within [0..N-1]. + +Output parameters: + InvA - inverse of matrix A + u*v'. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +void rmatrixinvupdateuv(real_2d_array &inva, const ae_int_t n, const real_1d_array &u, const real_1d_array &v, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Subroutine performing the Schur decomposition of a general matrix by using +the QR algorithm with multiple shifts. + +COMMERCIAL EDITION OF ALGLIB: + + ! Commercial version of ALGLIB includes one important improvement of + ! this function, which can be used from C++ and C#: + ! * Hardware vendor library support (lightweight Intel MKL is shipped + ! with ALGLIB for x64, other libs for other platforms) + ! + ! Vendor libs give approximately constant (with respect to number of + ! worker threads) acceleration factor which depends on CPU being used, + ! problem size and "baseline" ALGLIB edition which is used for + ! comparison. + ! + ! Multithreaded acceleration is NOT supported for this function. + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +The source matrix A is represented as S'*A*S = T, where S is an orthogonal +matrix (Schur vectors), T - upper quasi-triangular matrix (with blocks of +sizes 1x1 and 2x2 on the main diagonal). + +Input parameters: + A - matrix to be decomposed. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of A, N>=0. + + +Output parameters: + A - contains matrix T. + Array whose indexes range within [0..N-1, 0..N-1]. + S - contains Schur vectors. + Array whose indexes range within [0..N-1, 0..N-1]. + +Note 1: + The block structure of matrix T can be easily recognized: since all + the elements below the blocks are zeros, the elements a[i+1,i] which + are equal to 0 show the block border. + +Note 2: + The algorithm performance depends on the value of the internal parameter + NS of the InternalSchurDecomposition subroutine which defines the number + of shifts in the QR algorithm (similarly to the block width in block-matrix + algorithms in linear algebra). If you require maximum performance on + your machine, it is recommended to adjust this parameter manually. + +Result: + True, + if the algorithm has converged and parameters A and S contain the result. + False, + if the algorithm has not converged. + +Algorithm implemented on the basis of the DHSEQR subroutine (LAPACK 3.0 library). +*************************************************************************/ +bool rmatrixschur(real_2d_array &a, const ae_int_t n, real_2d_array &s, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Algorithm for solving the following generalized symmetric positive-definite +eigenproblem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3). +where A is a symmetric matrix, B - symmetric positive-definite matrix. +The problem is solved by reducing it to an ordinary symmetric eigenvalue +problem. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ZNeeded - if ZNeeded is equal to: + * 0, the eigenvectors are not returned; + * 1, the eigenvectors are returned. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + D - eigenvalues in ascending order. + Array whose index ranges within [0..N-1]. + Z - if ZNeeded is equal to: + * 0, Z hasn't changed; + * 1, Z contains eigenvectors. + Array whose indexes range within [0..N-1, 0..N-1]. + The eigenvectors are stored in matrix columns. It should + be noted that the eigenvectors in such problems do not + form an orthogonal system. + +Result: + True, if the problem was solved successfully. + False, if the error occurred during the Cholesky decomposition of matrix + B (the matrix isn't positive-definite) or during the work of the iterative + algorithm for solving the symmetric eigenproblem. + +See also the GeneralizedSymmetricDefiniteEVDReduce subroutine. + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixgevd(const real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t zneeded, const ae_int_t problemtype, real_1d_array &d, real_2d_array &z, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Algorithm for reduction of the following generalized symmetric positive- +definite eigenvalue problem: + A*x = lambda*B*x (1) or + A*B*x = lambda*x (2) or + B*A*x = lambda*x (3) +to the symmetric eigenvalues problem C*y = lambda*y (eigenvalues of this and +the given problems are the same, and the eigenvectors of the given problem +could be obtained by multiplying the obtained eigenvectors by the +transformation matrix x = R*y). + +Here A is a symmetric matrix, B - symmetric positive-definite matrix. + +Input parameters: + A - symmetric matrix which is given by its upper or lower + triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + N - size of matrices A and B. + IsUpperA - storage format of matrix A. + B - symmetric positive-definite matrix which is given by + its upper or lower triangular part. + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperB - storage format of matrix B. + ProblemType - if ProblemType is equal to: + * 1, the following problem is solved: A*x = lambda*B*x; + * 2, the following problem is solved: A*B*x = lambda*x; + * 3, the following problem is solved: B*A*x = lambda*x. + +Output parameters: + A - symmetric matrix which is given by its upper or lower + triangle depending on IsUpperA. Contains matrix C. + Array whose indexes range within [0..N-1, 0..N-1]. + R - upper triangular or low triangular transformation matrix + which is used to obtain the eigenvectors of a given problem + as the product of eigenvectors of C (from the right) and + matrix R (from the left). If the matrix is upper + triangular, the elements below the main diagonal + are equal to 0 (and vice versa). Thus, we can perform + the multiplication without taking into account the + internal structure (which is an easier though less + effective way). + Array whose indexes range within [0..N-1, 0..N-1]. + IsUpperR - type of matrix R (upper or lower triangular). + +Result: + True, if the problem was reduced successfully. + False, if the error occurred during the Cholesky decomposition of + matrix B (the matrix is not positive-definite). + + -- ALGLIB -- + Copyright 1.28.2006 by Bochkanov Sergey +*************************************************************************/ +bool smatrixgevdreduce(real_2d_array &a, const ae_int_t n, const bool isuppera, const real_2d_array &b, const bool isupperb, const ae_int_t problemtype, real_2d_array &r, bool &isupperr, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double rmatrixludet(const real_2d_array &a, const integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +double rmatrixdet(const real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double rmatrixdet(const real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Determinant calculation of the matrix given by its LU decomposition. + +Input parameters: + A - LU decomposition of the matrix (output of + RMatrixLU subroutine). + Pivots - table of permutations which were made during + the LU decomposition. + Output of RMatrixLU subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: matrix determinant. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const ae_int_t n, const xparams _xparams = alglib::xdefault); +alglib::complex cmatrixludet(const complex_2d_array &a, const integer_1d_array &pivots, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the determinant of a general matrix + +Input parameters: + A - matrix, array[0..N-1, 0..N-1] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +Result: determinant of matrix A. + + -- ALGLIB -- + Copyright 2005 by Bochkanov Sergey +*************************************************************************/ +alglib::complex cmatrixdet(const complex_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +alglib::complex cmatrixdet(const complex_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Determinant calculation of the matrix given by the Cholesky decomposition. + +Input parameters: + A - Cholesky decomposition, + output of SMatrixCholesky subroutine. + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + +As the determinant is equal to the product of squares of diagonal elements, +it's not necessary to specify which triangle - lower or upper - the matrix +is stored in. + +Result: + matrix determinant. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +double spdmatrixcholeskydet(const real_2d_array &a, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double spdmatrixcholeskydet(const real_2d_array &a, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Determinant calculation of the symmetric positive definite matrix. + +Input parameters: + A - matrix, array[N,N] + N - (optional) size of matrix A: + * if given, only principal NxN submatrix is processed and + overwritten. other elements are unchanged. + * if not given, automatically determined from matrix size + (A must be square matrix) + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used/changed by + function + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used/changed by + function + +Result: + determinant of matrix A. + If matrix A is not positive definite, an exception is generated. + + -- ALGLIB -- + Copyright 2005-2008 by Bochkanov Sergey +*************************************************************************/ +double spdmatrixdet(const real_2d_array &a, const ae_int_t n, const bool isupper, const xparams _xparams = alglib::xdefault); +double spdmatrixdet(const real_2d_array &a, const bool isupper, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_ABLAS) || !defined(AE_PARTIAL_BUILD) +void ablassplitlength(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state); +void ablascomplexsplitlength(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_int_t* n1, + ae_int_t* n2, + ae_state *_state); +ae_int_t gemmparallelsize(ae_state *_state); +ae_int_t ablasblocksize(/* Real */ const ae_matrix* a, + ae_state *_state); +ae_int_t ablascomplexblocksize(/* Complex */ const ae_matrix* a, + ae_state *_state); +ae_int_t ablasmicroblocksize(ae_state *_state); +void generatereflection(/* Real */ ae_vector* x, + ae_int_t n, + double* tau, + ae_state *_state); +void applyreflectionfromtheleft(/* Real */ ae_matrix* c, + double tau, + /* Real */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ ae_vector* work, + ae_state *_state); +void applyreflectionfromtheright(/* Real */ ae_matrix* c, + double tau, + /* Real */ const ae_vector* v, + ae_int_t m1, + ae_int_t m2, + ae_int_t n1, + ae_int_t n2, + /* Real */ ae_vector* work, + ae_state *_state); +void cmatrixtranspose(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state); +void rmatrixtranspose(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state); +void rmatrixenforcesymmetricity(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +void cmatrixcopy(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state); +void rvectorcopy(ae_int_t n, + /* Real */ const ae_vector* a, + ae_int_t ia, + /* Real */ ae_vector* b, + ae_int_t ib, + ae_state *_state); +void rmatrixcopy(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state); +void rmatrixgencopy(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double beta, + /* Real */ ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_state *_state); +void rmatrixger(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + double alpha, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +void cmatrixrank1(ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Complex */ const ae_vector* u, + ae_int_t iu, + /* Complex */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +void rmatrixrank1(ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + /* Real */ const ae_vector* u, + ae_int_t iu, + /* Real */ const ae_vector* v, + ae_int_t iv, + ae_state *_state); +void rmatrixgemv(ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +void cmatrixmv(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Complex */ const ae_vector* x, + ae_int_t ix, + /* Complex */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +void rmatrixmv(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t opa, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +void rmatrixsymv(ae_int_t n, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +double rmatrixsyvmv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_int_t ix, + /* Real */ ae_vector* tmp, + ae_state *_state); +void rmatrixtrsv(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_int_t ix, + ae_state *_state); +void cmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool _trypexec_cmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, ae_state *_state); +void cmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool _trypexec_cmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Complex */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, ae_state *_state); +void rmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool _trypexec_rmatrixrighttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, ae_state *_state); +void rmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, + ae_state *_state); +ae_bool _trypexec_rmatrixlefttrsm(ae_int_t m, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i1, + ae_int_t j1, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_matrix* x, + ae_int_t i2, + ae_int_t j2, ae_state *_state); +void cmatrixherk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool _trypexec_cmatrixherk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, ae_state *_state); +void rmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +ae_bool _trypexec_rmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, ae_state *_state); +void cmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool _trypexec_cmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + ae_complex alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Complex */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + ae_complex beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, ae_state *_state); +void rmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_state *_state); +ae_bool _trypexec_rmatrixgemm(ae_int_t m, + ae_int_t n, + ae_int_t k, + double alpha, + /* Real */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + /* Real */ const ae_matrix* b, + ae_int_t ib, + ae_int_t jb, + ae_int_t optypeb, + double beta, + /* Real */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, ae_state *_state); +void cmatrixsyrk(ae_int_t n, + ae_int_t k, + double alpha, + /* Complex */ const ae_matrix* a, + ae_int_t ia, + ae_int_t ja, + ae_int_t optypea, + double beta, + /* Complex */ ae_matrix* c, + ae_int_t ic, + ae_int_t jc, + ae_bool isupper, + ae_state *_state); +void rowwisegramschmidt(/* Real */ const ae_matrix* q, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* x, + /* Real */ ae_vector* qx, + ae_bool needqx, + ae_state *_state); +#endif +#if defined(AE_COMPILE_ORTFAC) || !defined(AE_PARTIAL_BUILD) +void rmatrixqr(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state); +void rmatrixlq(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state); +void cmatrixqr(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* tau, + ae_state *_state); +void cmatrixlq(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_vector* tau, + ae_state *_state); +void rmatrixqrunpackq(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tau, + ae_int_t qcolumns, + /* Real */ ae_matrix* q, + ae_state *_state); +void rmatrixqrunpackr(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* r, + ae_state *_state); +void rmatrixlqunpackq(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tau, + ae_int_t qrows, + /* Real */ ae_matrix* q, + ae_state *_state); +void rmatrixlqunpackl(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_matrix* l, + ae_state *_state); +void cmatrixqrunpackq(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ const ae_vector* tau, + ae_int_t qcolumns, + /* Complex */ ae_matrix* q, + ae_state *_state); +void cmatrixqrunpackr(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* r, + ae_state *_state); +void cmatrixlqunpackq(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ const ae_vector* tau, + ae_int_t qrows, + /* Complex */ ae_matrix* q, + ae_state *_state); +void cmatrixlqunpackl(/* Complex */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Complex */ ae_matrix* l, + ae_state *_state); +void rmatrixqrbasecase(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* work, + /* Real */ ae_vector* t, + /* Real */ ae_vector* tau, + ae_state *_state); +void rmatrixlqbasecase(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* work, + /* Real */ ae_vector* t, + /* Real */ ae_vector* tau, + ae_state *_state); +void rmatrixbd(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tauq, + /* Real */ ae_vector* taup, + ae_state *_state); +void rmatrixbdunpackq(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + ae_int_t qcolumns, + /* Real */ ae_matrix* q, + ae_state *_state); +void rmatrixbdmultiplybyq(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* tauq, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state); +void rmatrixbdunpackpt(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* taup, + ae_int_t ptrows, + /* Real */ ae_matrix* pt, + ae_state *_state); +void rmatrixbdmultiplybyp(/* Real */ const ae_matrix* qp, + ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* taup, + /* Real */ ae_matrix* z, + ae_int_t zrows, + ae_int_t zcolumns, + ae_bool fromtheright, + ae_bool dotranspose, + ae_state *_state); +void rmatrixbdunpackdiagonals(/* Real */ const ae_matrix* b, + ae_int_t m, + ae_int_t n, + ae_bool* isupper, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state); +void rmatrixhessenberg(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* tau, + ae_state *_state); +void rmatrixhessenbergunpackq(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state); +void rmatrixhessenbergunpackh(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* h, + ae_state *_state); +void smatrixtd(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state); +void smatrixtdunpackq(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* tau, + /* Real */ ae_matrix* q, + ae_state *_state); +void hmatrixtd(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* tau, + /* Real */ ae_vector* d, + /* Real */ ae_vector* e, + ae_state *_state); +void hmatrixtdunpackq(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* tau, + /* Complex */ ae_matrix* q, + ae_state *_state); +#endif +#if defined(AE_COMPILE_MATGEN) || !defined(AE_PARTIAL_BUILD) +void rmatrixrndorthogonal(ae_int_t n, + /* Real */ ae_matrix* a, + ae_state *_state); +void rmatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state); +void cmatrixrndorthogonal(ae_int_t n, + /* Complex */ ae_matrix* a, + ae_state *_state); +void cmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state); +void smatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state); +void spdmatrixrndcond(ae_int_t n, + double c, + /* Real */ ae_matrix* a, + ae_state *_state); +void hmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state); +void hpdmatrixrndcond(ae_int_t n, + double c, + /* Complex */ ae_matrix* a, + ae_state *_state); +void rmatrixrndorthogonalfromtheright(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void rmatrixrndorthogonalfromtheleft(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void cmatrixrndorthogonalfromtheright(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void cmatrixrndorthogonalfromtheleft(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state); +void smatrixrndmultiply(/* Real */ ae_matrix* a, + ae_int_t n, + ae_state *_state); +void hmatrixrndmultiply(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SPARSE) || !defined(AE_PARTIAL_BUILD) +void sparsecreate(ae_int_t m, + ae_int_t n, + ae_int_t k, + sparsematrix* s, + ae_state *_state); +void sparsecreatebuf(ae_int_t m, + ae_int_t n, + ae_int_t k, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrs(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* ner, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsbuf(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* ner, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsfromdense(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsfromdensebuf(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsfromdensev(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +void sparsecreatecrsfromdensevbuf(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +void sparsecreatesks(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* d, + /* Integer */ const ae_vector* u, + sparsematrix* s, + ae_state *_state); +void sparsecreatesksbuf(ae_int_t m, + ae_int_t n, + /* Integer */ const ae_vector* d, + /* Integer */ const ae_vector* u, + sparsematrix* s, + ae_state *_state); +void sparsecreatesksband(ae_int_t m, + ae_int_t n, + ae_int_t bw, + sparsematrix* s, + ae_state *_state); +void sparsecreatesksbandbuf(ae_int_t m, + ae_int_t n, + ae_int_t bw, + sparsematrix* s, + ae_state *_state); +void sparsecopy(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparseswap(sparsematrix* s0, sparsematrix* s1, ae_state *_state); +void sparseadd(sparsematrix* s, + ae_int_t i, + ae_int_t j, + double v, + ae_state *_state); +void sparseset(sparsematrix* s, + ae_int_t i, + ae_int_t j, + double v, + ae_state *_state); +double sparseget(const sparsematrix* s, + ae_int_t i, + ae_int_t j, + ae_state *_state); +ae_bool sparseexists(const sparsematrix* s, + ae_int_t i, + ae_int_t j, + ae_state *_state); +double sparsegetdiagonal(const sparsematrix* s, + ae_int_t i, + ae_state *_state); +void sparsemv(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void sparsemtv(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void sparsegemv(const sparsematrix* s, + double alpha, + ae_int_t ops, + /* Real */ const ae_vector* x, + ae_int_t ix, + double beta, + /* Real */ ae_vector* y, + ae_int_t iy, + ae_state *_state); +void sparsemv2(const sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y0, + /* Real */ ae_vector* y1, + ae_state *_state); +void sparsesmv(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void sparsemultiplycolsby(sparsematrix* s, + /* Real */ const ae_vector* x, + ae_state *_state); +void sparsemultiplyrowsby(sparsematrix* s, + /* Real */ const ae_vector* x, + ae_state *_state); +void sparsemultiplyrowscolsby(sparsematrix* s, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_state *_state); +double sparsevsmv(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_vector* x, + ae_state *_state); +void sparsemm(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state); +void sparsemtm(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state); +void sparsemm2(const sparsematrix* s, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b0, + /* Real */ ae_matrix* b1, + ae_state *_state); +void sparsesmm(const sparsematrix* s, + ae_bool isupper, + /* Real */ const ae_matrix* a, + ae_int_t k, + /* Real */ ae_matrix* b, + ae_state *_state); +void sparsetrmv(const sparsematrix* s, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +void sparsetrsv(const sparsematrix* s, + ae_bool isupper, + ae_bool isunit, + ae_int_t optype, + /* Real */ ae_vector* x, + ae_state *_state); +void sparsesymmpermtbl(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +void sparsesymmpermtbltranspose(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +void sparsesymmpermtblbuf(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +void sparsesymmpermtbltransposebuf(const sparsematrix* a, + ae_bool isupper, + /* Integer */ const ae_vector* p, + sparsematrix* b, + ae_state *_state); +void sparseresizematrix(sparsematrix* s, ae_state *_state); +double sparsegetaveragelengthofchain(const sparsematrix* s, + ae_state *_state); +ae_bool sparseenumerate(const sparsematrix* s, + ae_int_t* t0, + ae_int_t* t1, + ae_int_t* i, + ae_int_t* j, + double* v, + ae_state *_state); +ae_bool sparserewriteexisting(sparsematrix* s, + ae_int_t i, + ae_int_t j, + double v, + ae_state *_state); +void sparsegetrow(const sparsematrix* s, + ae_int_t i, + /* Real */ ae_vector* irow, + ae_state *_state); +void sparsegetcompressedrow(const sparsematrix* s, + ae_int_t i, + /* Integer */ ae_vector* colidx, + /* Real */ ae_vector* vals, + ae_int_t* nzcnt, + ae_state *_state); +void sparseappendcompressedrow(sparsematrix* s, + /* Integer */ const ae_vector* colidx, + /* Real */ const ae_vector* vals, + ae_int_t nz, + ae_state *_state); +void sparseappendemptyrow(sparsematrix* s, ae_state *_state); +void sparseappendelement(sparsematrix* s, + ae_int_t k, + double v, + ae_state *_state); +void sparsetransposesks(sparsematrix* s, ae_state *_state); +void sparsetransposecrs(sparsematrix* s, ae_state *_state); +void sparsecopytransposecrs(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecopytransposecrsbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecopytransposecrsxbuf(const sparsematrix* s0, + ae_int_t triangle, + sparsematrix* s1, + ae_state *_state); +void sparseconvertto(sparsematrix* s0, ae_int_t fmt, ae_state *_state); +void sparsecopytobuf(const sparsematrix* s0, + ae_int_t fmt, + sparsematrix* s1, + ae_state *_state); +void sparseconverttohash(sparsematrix* s, ae_state *_state); +void sparsecopytohash(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecopytohashbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecopytocrs(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparseconverttosks(sparsematrix* s, ae_state *_state); +void sparsecopytosks(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecopytosksbuf(const sparsematrix* s0, + sparsematrix* s1, + ae_state *_state); +void sparsecreatecrsinplace(sparsematrix* s, ae_state *_state); +ae_int_t sparsegetmatrixtype(const sparsematrix* s, ae_state *_state); +ae_bool sparseishash(const sparsematrix* s, ae_state *_state); +ae_bool sparseissks(const sparsematrix* s, ae_state *_state); +void sparsefree(sparsematrix* s, ae_state *_state); +ae_int_t sparsegetuppercount(const sparsematrix* s, ae_state *_state); +ae_int_t sparsegetlowercount(const sparsematrix* s, ae_state *_state); +void sparsescale(sparsematrix* s, + ae_int_t scltype, + ae_bool scalerows, + ae_bool scalecols, + ae_bool colsfirst, + /* Real */ ae_vector* r, + /* Real */ ae_vector* c, + ae_state *_state); +void sparseappendcoltocrs(sparsematrix* s, ae_state *_state); +ae_bool sparsetrygatherclear(sparsematrix* dst, + const sparsematrix* src, + ae_state *_state); +void sparsemergepatterns(const sparsematrix* s1, + const sparsematrix* s2, + sparsematrix* dst, + ae_state *_state); +void sparsealloc(ae_serializer* s, + const sparsematrix* a, + ae_state *_state); +void sparseserialize(ae_serializer* s, + const sparsematrix* a, + ae_state *_state); +void sparseunserialize(ae_serializer* s, + sparsematrix* a, + ae_state *_state); +double spdotvr(/* Real */ const ae_vector* x, + const sparsematrix* s, + ae_int_t r, + ae_state *_state); +double spdotr2(const sparsematrix* s, ae_int_t r, ae_state *_state); +void _sparsebuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sparsebuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sparsebuffers_clear(void* _p); +void _sparsebuffers_destroy(void* _p); +#endif +#if defined(AE_COMPILE_HSSCHUR) || !defined(AE_PARTIAL_BUILD) +void rmatrixinternalschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state); +ae_bool upperhessenbergschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + /* Real */ ae_matrix* s, + ae_state *_state); +void internalschurdecomposition(/* Real */ ae_matrix* h, + ae_int_t n, + ae_int_t tneeded, + ae_int_t zneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* z, + ae_int_t* info, + ae_state *_state); +#endif +#if defined(AE_COMPILE_EVD) || !defined(AE_PARTIAL_BUILD) +void eigsubspacecreate(ae_int_t n, + ae_int_t k, + eigsubspacestate* state, + ae_state *_state); +void eigsubspacecreatebuf(ae_int_t n, + ae_int_t k, + eigsubspacestate* state, + ae_state *_state); +void eigsubspacesetcond(eigsubspacestate* state, + double eps, + ae_int_t maxits, + ae_state *_state); +void eigsubspacesetwarmstart(eigsubspacestate* state, + ae_bool usewarmstart, + ae_state *_state); +void eigsubspaceoocstart(eigsubspacestate* state, + ae_int_t mtype, + ae_state *_state); +ae_bool eigsubspaceooccontinue(eigsubspacestate* state, ae_state *_state); +void eigsubspaceoocgetrequestinfo(eigsubspacestate* state, + ae_int_t* requesttype, + ae_int_t* requestsize, + ae_state *_state); +void eigsubspaceoocgetrequestdata(eigsubspacestate* state, + /* Real */ ae_matrix* x, + ae_state *_state); +void eigsubspaceoocsendresult(eigsubspacestate* state, + /* Real */ const ae_matrix* ax, + ae_state *_state); +void eigsubspaceoocstop(eigsubspacestate* state, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state); +void eigsubspacesolvedenses(eigsubspacestate* state, + /* Real */ const ae_matrix* a, + ae_bool isupper, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state); +void eigsubspacesolvesparses(eigsubspacestate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + eigsubspacereport* rep, + ae_state *_state); +ae_bool eigsubspaceiteration(eigsubspacestate* state, ae_state *_state); +ae_bool smatrixevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixevdr(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + double b1, + double b2, + ae_int_t* m, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixevdi(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool hmatrixevd(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + /* Real */ ae_vector* d, + /* Complex */ ae_matrix* z, + ae_state *_state); +ae_bool hmatrixevdr(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + double b1, + double b2, + ae_int_t* m, + /* Real */ ae_vector* w, + /* Complex */ ae_matrix* z, + ae_state *_state); +ae_bool hmatrixevdi(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_int_t zneeded, + ae_bool isupper, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_vector* w, + /* Complex */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixtdevd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_int_t zneeded, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixtdevdr(/* Real */ ae_vector* d, + /* Real */ const ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + double a, + double b, + ae_int_t* m, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixtdevdi(/* Real */ ae_vector* d, + /* Real */ const ae_vector* e, + ae_int_t n, + ae_int_t zneeded, + ae_int_t i1, + ae_int_t i2, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool rmatrixevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_int_t vneeded, + /* Real */ ae_vector* wr, + /* Real */ ae_vector* wi, + /* Real */ ae_matrix* vl, + /* Real */ ae_matrix* vr, + ae_state *_state); +void _eigsubspacestate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _eigsubspacestate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _eigsubspacestate_clear(void* _p); +void _eigsubspacestate_destroy(void* _p); +void _eigsubspacereport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _eigsubspacereport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _eigsubspacereport_clear(void* _p); +void _eigsubspacereport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DLU) || !defined(AE_PARTIAL_BUILD) +void cmatrixluprec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state); +void rmatrixluprec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state); +void cmatrixplurec(/* Complex */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Complex */ ae_vector* tmp, + ae_state *_state); +void rmatrixplurec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + /* Real */ ae_vector* tmp, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SPTRF) || !defined(AE_PARTIAL_BUILD) +ae_bool sptrflu(sparsematrix* a, + ae_int_t pivottype, + /* Integer */ ae_vector* pr, + /* Integer */ ae_vector* pc, + sluv2buffer* buf, + ae_state *_state); +void _sluv2list1matrix_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sluv2list1matrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sluv2list1matrix_clear(void* _p); +void _sluv2list1matrix_destroy(void* _p); +void _sluv2sparsetrail_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sluv2sparsetrail_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sluv2sparsetrail_clear(void* _p); +void _sluv2sparsetrail_destroy(void* _p); +void _sluv2densetrail_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sluv2densetrail_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sluv2densetrail_clear(void* _p); +void _sluv2densetrail_destroy(void* _p); +void _sluv2buffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sluv2buffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sluv2buffer_clear(void* _p); +void _sluv2buffer_destroy(void* _p); +#endif +#if defined(AE_COMPILE_AMDORDERING) || !defined(AE_PARTIAL_BUILD) +void generateamdpermutation(const sparsematrix* a, + ae_int_t n, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + amdbuffer* buf, + ae_state *_state); +ae_int_t generateamdpermutationx(const sparsematrix* a, + /* Boolean */ const ae_vector* eligible, + ae_int_t n, + double promoteabove, + /* Integer */ ae_vector* perm, + /* Integer */ ae_vector* invperm, + ae_int_t amdtype, + amdbuffer* buf, + ae_state *_state); +void _amdknset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _amdknset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _amdknset_clear(void* _p); +void _amdknset_destroy(void* _p); +void _amdvertexset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _amdvertexset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _amdvertexset_clear(void* _p); +void _amdvertexset_destroy(void* _p); +void _amdllmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _amdllmatrix_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _amdllmatrix_clear(void* _p); +void _amdllmatrix_destroy(void* _p); +void _amdbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _amdbuffer_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _amdbuffer_clear(void* _p); +void _amdbuffer_destroy(void* _p); +#endif +#if defined(AE_COMPILE_SPCHOL) || !defined(AE_PARTIAL_BUILD) +ae_int_t spsymmgetmaxfastkernel(ae_state *_state); +ae_bool spsymmanalyze(const sparsematrix* a, + /* Integer */ const ae_vector* priorities, + double promoteabove, + ae_int_t promoteto, + ae_int_t facttype, + ae_int_t permtype, + ae_int_t memreuse, + spcholanalysis* analysis, + ae_state *_state); +void spsymmsetmodificationstrategy(spcholanalysis* analysis, + ae_int_t modstrategy, + double p0, + double p1, + double p2, + double p3, + ae_state *_state); +void spsymmcontrolsign(spcholanalysis* analysis, + /* Boolean */ const ae_vector* ispositive, + double eps, + ae_state *_state); +void spsymmreload(spcholanalysis* analysis, + const sparsematrix* a, + ae_state *_state); +void spsymmreloaddiagonal(spcholanalysis* analysis, + /* Real */ const ae_vector* d, + ae_state *_state); +ae_bool spsymmfactorize(spcholanalysis* analysis, ae_state *_state); +void spsymmenforceparallelism(spcholanalysis* analysis, ae_state *_state); +void spsymmextract(spcholanalysis* analysis, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + ae_state *_state); +void spsymmsolve(spcholanalysis* analysis, + /* Real */ ae_vector* b, + ae_state *_state); +void spsymmdiagerr(spcholanalysis* analysis, + double* sumsq, + double* errsq, + ae_state *_state); +void _priorityamdbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _priorityamdbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _priorityamdbuffers_clear(void* _p); +void _priorityamdbuffers_destroy(void* _p); +void _spcholadj_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spcholadj_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spcholadj_clear(void* _p); +void _spcholadj_destroy(void* _p); +void _spcholanalysis_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _spcholanalysis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _spcholanalysis_clear(void* _p); +void _spcholanalysis_destroy(void* _p); +#endif +#if defined(AE_COMPILE_TRFAC) || !defined(AE_PARTIAL_BUILD) +void rmatrixlu(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +void cmatrixlu(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +ae_bool hpdmatrixcholesky(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +ae_bool spdmatrixcholesky(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +void spdmatrixcholeskyupdateadd1(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* u, + ae_state *_state); +void spdmatrixcholeskyupdatefix(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Boolean */ const ae_vector* fix, + ae_state *_state); +void spdmatrixcholeskyupdateadd1buf(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* u, + /* Real */ ae_vector* bufr, + ae_state *_state); +void spdmatrixcholeskyupdatefixbuf(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Boolean */ const ae_vector* fix, + /* Real */ ae_vector* bufr, + ae_state *_state); +ae_bool sparselu(sparsematrix* a, + ae_int_t pivottype, + /* Integer */ ae_vector* p, + /* Integer */ ae_vector* q, + ae_state *_state); +ae_bool sparsecholeskyskyline(sparsematrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +ae_bool sparsecholesky(sparsematrix* a, ae_bool isupper, ae_state *_state); +ae_bool sparsecholeskyp(sparsematrix* a, + ae_bool isupper, + /* Integer */ ae_vector* p, + ae_state *_state); +ae_bool sparsecholeskyanalyze(const sparsematrix* a, + ae_bool isupper, + ae_int_t facttype, + ae_int_t permtype, + sparsedecompositionanalysis* analysis, + ae_state *_state); +void sparsecholeskysetmodtype(sparsedecompositionanalysis* analysis, + ae_int_t modstrategy, + double p0, + double p1, + double p2, + double p3, + ae_state *_state); +ae_bool sparsecholeskyfactorize(sparsedecompositionanalysis* analysis, + ae_bool needupper, + sparsematrix* a, + /* Real */ ae_vector* d, + /* Integer */ ae_vector* p, + ae_state *_state); +void sparsecholeskyreload(sparsedecompositionanalysis* analysis, + const sparsematrix* a, + ae_bool isupper, + ae_state *_state); +void rmatrixlup(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +void cmatrixlup(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +void rmatrixplu(/* Real */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +void cmatrixplu(/* Complex */ ae_matrix* a, + ae_int_t m, + ae_int_t n, + /* Integer */ ae_vector* pivots, + ae_state *_state); +ae_bool spdmatrixcholeskyrec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + ae_state *_state); +void _sparsedecompositionanalysis_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sparsedecompositionanalysis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sparsedecompositionanalysis_clear(void* _p); +void _sparsedecompositionanalysis_destroy(void* _p); +#endif +#if defined(AE_COMPILE_BDSVD) || !defined(AE_PARTIAL_BUILD) +ae_bool rmatrixbdsvd(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_state *_state); +ae_bool bidiagonalsvddecomposition(/* Real */ ae_vector* d, + /* Real */ const ae_vector* _e, + ae_int_t n, + ae_bool isupper, + ae_bool isfractionalaccuracyrequired, + /* Real */ ae_matrix* u, + ae_int_t nru, + /* Real */ ae_matrix* c, + ae_int_t ncc, + /* Real */ ae_matrix* vt, + ae_int_t ncvt, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SVD) || !defined(AE_PARTIAL_BUILD) +ae_bool rmatrixsvd(/* Real */ const ae_matrix* _a, + ae_int_t m, + ae_int_t n, + ae_int_t uneeded, + ae_int_t vtneeded, + ae_int_t additionalmemory, + /* Real */ ae_vector* w, + /* Real */ ae_matrix* u, + /* Real */ ae_matrix* vt, + ae_state *_state); +#endif +#if defined(AE_COMPILE_RCOND) || !defined(AE_PARTIAL_BUILD) +double rmatrixrcond1(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +double rmatrixrcond2(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_state *_state); +double rmatrixrcond2rect(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + ae_state *_state); +double rmatrixrcondinf(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +double spdmatrixrcond(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +double spdmatrixrcond2(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +double rmatrixtrrcond1(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state); +double rmatrixtrrcond2(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state); +double rmatrixtrrcondinf(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state); +double hpdmatrixrcond(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +double cmatrixrcond1(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +double cmatrixrcondinf(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +double rmatrixlurcond1(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state); +double rmatrixlurcondinf(/* Real */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state); +double spdmatrixcholeskyrcond(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +double hpdmatrixcholeskyrcond(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +double cmatrixlurcond1(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state); +double cmatrixlurcondinf(/* Complex */ const ae_matrix* lua, + ae_int_t n, + ae_state *_state); +double cmatrixtrrcond1(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state); +double cmatrixtrrcondinf(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + ae_state *_state); +double rcondthreshold(ae_state *_state); +#endif +#if defined(AE_COMPILE_FBLS) || !defined(AE_PARTIAL_BUILD) +void fblscholeskysolve(/* Real */ const ae_matrix* cha, + double sqrtscalea, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + /* Real */ ae_vector* tmp, + ae_state *_state); +void fblssolvecgx(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + double alpha, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + /* Real */ ae_vector* buf, + ae_state *_state); +void fblscgcreate(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* b, + ae_int_t n, + fblslincgstate* state, + ae_state *_state); +ae_bool fblscgiteration(fblslincgstate* state, ae_state *_state); +void fblsgmrescreate(/* Real */ const ae_vector* b, + ae_int_t n, + ae_int_t k, + fblsgmresstate* state, + ae_state *_state); +ae_bool fblsgmresiteration(fblsgmresstate* state, ae_state *_state); +void fblssolvels(/* Real */ ae_matrix* a, + /* Real */ ae_vector* b, + ae_int_t m, + ae_int_t n, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + /* Real */ ae_vector* tmp2, + ae_state *_state); +void _fblslincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _fblslincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _fblslincgstate_clear(void* _p); +void _fblslincgstate_destroy(void* _p); +void _fblsgmresstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _fblsgmresstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _fblsgmresstate_clear(void* _p); +void _fblsgmresstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NORMESTIMATOR) || !defined(AE_PARTIAL_BUILD) +void normestimatorcreate(ae_int_t m, + ae_int_t n, + ae_int_t nstart, + ae_int_t nits, + normestimatorstate* state, + ae_state *_state); +void normestimatorsetseed(normestimatorstate* state, + ae_int_t seedval, + ae_state *_state); +ae_bool normestimatoriteration(normestimatorstate* state, + ae_state *_state); +void normestimatorestimatesparse(normestimatorstate* state, + const sparsematrix* a, + ae_state *_state); +void normestimatorresults(const normestimatorstate* state, + double* nrm, + ae_state *_state); +void normestimatorrestart(normestimatorstate* state, ae_state *_state); +void _normestimatorstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _normestimatorstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _normestimatorstate_clear(void* _p); +void _normestimatorstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MATINV) || !defined(AE_PARTIAL_BUILD) +void rmatrixluinverse(/* Real */ ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + matinvreport* rep, + ae_state *_state); +void rmatrixinverse(/* Real */ ae_matrix* a, + ae_int_t n, + matinvreport* rep, + ae_state *_state); +void cmatrixluinverse(/* Complex */ ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + matinvreport* rep, + ae_state *_state); +void cmatrixinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + matinvreport* rep, + ae_state *_state); +void spdmatrixcholeskyinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state); +void spdmatrixinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state); +void hpdmatrixcholeskyinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state); +void hpdmatrixinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + matinvreport* rep, + ae_state *_state); +void rmatrixtrinverse(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + matinvreport* rep, + ae_state *_state); +void cmatrixtrinverse(/* Complex */ ae_matrix* a, + ae_int_t n, + ae_bool isupper, + ae_bool isunit, + matinvreport* rep, + ae_state *_state); +void spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + matinvreport* rep, + ae_state *_state); +ae_bool _trypexec_spdmatrixcholeskyinverserec(/* Real */ ae_matrix* a, + ae_int_t offs, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* tmp, + matinvreport* rep, ae_state *_state); +void _matinvreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _matinvreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _matinvreport_clear(void* _p); +void _matinvreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_INVERSEUPDATE) || !defined(AE_PARTIAL_BUILD) +void rmatrixinvupdatesimple(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updrow, + ae_int_t updcolumn, + double updval, + ae_state *_state); +void rmatrixinvupdaterow(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updrow, + /* Real */ const ae_vector* v, + ae_state *_state); +void rmatrixinvupdatecolumn(/* Real */ ae_matrix* inva, + ae_int_t n, + ae_int_t updcolumn, + /* Real */ const ae_vector* u, + ae_state *_state); +void rmatrixinvupdateuv(/* Real */ ae_matrix* inva, + ae_int_t n, + /* Real */ const ae_vector* u, + /* Real */ const ae_vector* v, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SCHUR) || !defined(AE_PARTIAL_BUILD) +ae_bool rmatrixschur(/* Real */ ae_matrix* a, + ae_int_t n, + /* Real */ ae_matrix* s, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SPDGEVD) || !defined(AE_PARTIAL_BUILD) +ae_bool smatrixgevd(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isuppera, + /* Real */ const ae_matrix* b, + ae_bool isupperb, + ae_int_t zneeded, + ae_int_t problemtype, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* z, + ae_state *_state); +ae_bool smatrixgevdreduce(/* Real */ ae_matrix* a, + ae_int_t n, + ae_bool isuppera, + /* Real */ const ae_matrix* b, + ae_bool isupperb, + ae_int_t problemtype, + /* Real */ ae_matrix* r, + ae_bool* isupperr, + ae_state *_state); +#endif +#if defined(AE_COMPILE_MATDET) || !defined(AE_PARTIAL_BUILD) +double rmatrixludet(/* Real */ const ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + ae_state *_state); +double rmatrixdet(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +ae_complex cmatrixludet(/* Complex */ const ae_matrix* a, + /* Integer */ const ae_vector* pivots, + ae_int_t n, + ae_state *_state); +ae_complex cmatrixdet(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_state *_state); +double spdmatrixcholeskydet(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_state *_state); +double spdmatrixdet(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + ae_state *_state); +#endif + +} +#endif + diff --git a/core/alglib/minlp.cpp b/core/alglib/minlp.cpp new file mode 100644 index 00000000..779cde5d --- /dev/null +++ b/core/alglib/minlp.cpp @@ -0,0 +1,15593 @@ +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "minlp.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + MIXED INTEGER NONLINEAR PROGRAMMING SOLVER + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to any +combination of: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU +* integrality constraints on some variables + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercreate(const ae_int_t n, const real_1d_array &x, minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolvercreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + MIXED INTEGER NONLINEAR PROGRAMMING SOLVER + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to any +combination of: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU +* integrality constraints on some variables + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsolvercreate(const real_1d_array &x, minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolvercreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets box constraints for the mixed integer optimizer. + +Box constraints are inactive by default. + +IMPORTANT: box constraints work in parallel with the integrality ones: + * a variable marked as integral is considered having no bounds + until minlpsolversetbc() is called + * a variable with lower and upper bounds set is considered + continuous until marked as integral with the + minlpsolversetintkth() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify a + very small number or -INF, with the latter option being + recommended. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify a + very large number or +INF, with the latter option being + recommended. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th + variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbc(minlpsolverstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2dense(minlpsolverstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsolversetlc2dense(minlpsolverstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minlpsolversetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2(minlpsolverstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetlc2(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2mixed(minlpsolverstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetlc2mixed(state.c_ptr(), sparsea.c_ptr(), ksparse, densea.c_ptr(), kdense, al.c_ptr(), au.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2dense(minlpsolverstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolveraddlc2dense(state.c_ptr(), a.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2(minlpsolverstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolveraddlc2(state.c_ptr(), idxa.c_ptr(), vala.c_ptr(), nnz, al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2sparsefromdense(minlpsolverstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolveraddlc2sparsefromdense(state.c_ptr(), da.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints for MINLP optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MINLPSolverOptimize() method as callbacks. + +MINLPSolverOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetnlc2(minlpsolverstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints for MINLP optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MINLPSolverOptimize() method as callbacks. + +MINLPSolverOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsolversetnlc2(minlpsolverstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nnlc; + if( (nl.length()!=nu.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minlpsolversetnlc2': looks like one of arguments has wrong size"); + nnlc = nl.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list. + +In fact, this function adds constraint bounds. A constraints itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + +NOTE 3: use addnlc2masked() in order to specify variable mask. Masks are + essential for derivative-free optimization because they provide + important information about relevant and irrelevant variables. + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2(minlpsolverstate &state, const double nl, const double nu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolveraddnlc2(state.c_ptr(), nl, nu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list, with +the variable mask being specified as a compressed index array. A +variable mask is a set of variables actually appearing in the constraint. + +----- ABOUT VARIABLE MASKS ----------------------------------------------- + +Variable masks provide crucial information for derivative-free solvers, +greatly accelerating surrogate model construction. This applies to both +continuous and integral variables, with results for binary variables being +more pronounced. + +Up to 2x improvement in convergence speed has been observed for sufficiently +sparse MINLP problems. + +NOTE: In order to unleash the full potential of variable masking, it is + important to provide masks for objective as well as all nonlinear + constraints. + + Even partial information matters, i.e. if you are 100% sure that + your black-box function does not depend on some variables, but + unsure about other ones, mark surely irrelevant variables, and tell + the solver that other ones may be relevant. + +NOTE: the solver is may behave unpredictably if some relevant variable + is not included into the mask. Most likely it will fail to converge, + although it sometimes possible to converge to solution even with + incorrectly specified mask. + +NOTE: minlpsolversetobjectivemask() can be used to set variable mask for + the objective. + +NOTE: Masks are ignored by branch-and-bound-type solvers relying on + analytic gradients. + +----- ABOUT NONLINEAR CONSTRAINTS ---------------------------------------- + +In fact, this function adds constraint bounds. A constraint itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + VarIdx - array[NMSK], with potentially unsorted and non-distinct + indexes (the function will sort and merge duplicates). If + a variable index K appears in the list, it means that the + constraint potentially depends on K-th variable. If a + variable index K does NOT appear in the list, it means + that the constraint does NOT depend on K-th variable. + The array can have more than NMSK elements, in which case + only leading NMSK will be used. + NMSK - NMSK>=0, VarIdx[] size: + * NMSK>0 means that the constraint depends on up to NMSK + variables whose indexes are stored in VarIdx[] + * NMSK=0 means that the constraint is a constant function; + the solver may fail if it is not actually the case. + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2masked(minlpsolverstate &state, const double nl, const double nu, const integer_1d_array &varidx, const ae_int_t nmsk, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolveraddnlc2masked(state.c_ptr(), nl, nu, varidx.c_ptr(), nmsk, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping condition for the branch-and-bound family of +solvers: a solver must when when the gap between primal and dual bounds is +less than PDGap. + +The solver computes relative gap, equal to |Fprim-Fdual|/max(|Fprim|,1). + +This parameter is ignored by other types of solvers, e.g. MIVNS. + +INPUT PARAMETERS: + State - structure stores algorithm state + PDGap - >=0, tolerance. Zero value means that some default value + is automatically selected. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetpdgap(minlpsolverstate &state, const double pdgap, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetpdgap(state.c_ptr(), pdgap, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets BBSYNC profile to "small tree". + +It means that we expect our problem to have a shallow B&B tree with the +number of nodes comparable to the integer variables count, or below. + +BBSYNC solver will run with simplified settings: +* pseudocost branching is used + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilesmalltree(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetbbsyncprofilesmalltree(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets BBSYNC profile to "large tree". + +It means that we expect our problem to have a large B&B tree with much +more than NInt (the integer variables count) nodes. However, we expect it +to be solvable within our computational budget (i.e. that we are able to +explore the entire B&B tree). + +BBSYNC solver will run with heuristics that are costly to power-up, but +greatly improve performance on long distances: +* reliability branching is used + +BBSYNC will not use heuristics that increase chance of finding good +solutions early at the cost of increasing total time to prove optimality. + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilelargetree(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetbbsyncprofilelargetree(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets tolerance for nonlinear constraints; points violating +constraints by no more than CTol are considered feasible. + +Depending on the specific algorithm used, constraint violation may be +checked against internally scaled/normalized constraints (some smooth +solvers renormalize constraints in such a way that they have roughly unit +gradient magnitudes) or against raw constraint values: +* BBSYNC renormalizes constraints prior to comparing them with CTol +* MIRBF-VNS checks violation against raw constraint values + +IMPORTANT: one should be careful when choosing tolerances and stopping + criteria. + + A solver stops as soon as stopping criteria are triggered; + a feasibility check is performed after that. If too loose + stopping criteria are used, the solver may fail to enforce + constraints with sufficient accuracy and fail to recognize + solution as a feasible one. + + For example, stopping with EpsX=0.01 and checking CTol=0.000001 + will almost surely result in problems. Ideally, CTol should be + 1-2 orders of magnitude more relaxed than stopping criteria. + +INPUT PARAMETERS: + State - structure stores algorithm state + CTol - >0, tolerance. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetctol(minlpsolverstate &state, const double ctol, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetctol(state.c_ptr(), ctol, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells MINLP solver to use an objective-based stopping +condition for an underlying subsolver, i.e. to stop subsolver if relative +change in objective between iterations is less than EpsF. + +Too tight EspF, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsF +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if total objective change in last several (between + 5 and 10) steps is less than EpsF. More than one step is used to check + convergence because surrogate model-based solvers usually need more + stringent stopping criteria than SQP. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsF - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsF - >0, stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsf(minlpsolverstate &state, const double epsf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetsubsolverepsf(state.c_ptr(), epsf, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells MINLP solver to use a step-based stopping condition +for an underlying subsolver, i.e. to stop subsolver if typical step size +becomes less than EpsX. + +Too tight EspX, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsX +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if trust radius for a surrogate model optimizer + becomes less than EpsX. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsX - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsX - >=0, stopping condition. Zero value means that some default + value will be used. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsx(minlpsolverstate &state, const double epsx, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetsubsolverepsx(state.c_ptr(), epsx, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to favor parallelism, i.e. utilize +multithreading (when allowed by the user) until statistics prove that +overhead from starting/stopping worker threads is too large. + +This way solver gets the best performance on problems with significant +amount of internal calculations (large QP/MIQP subproblems, lengthy +surrogate model optimization sessions) from the very beginning. The price +is that problems with small solver overhead that does not justify internal +parallelism (<1ms per iteration) will suffer slowdown for several initial +10-20 milliseconds until the solver proves that parallelism makes no sense + +Use MINLPSolver.CautiousInternalParallelism() to avoid slowing down the +solver on easy problems. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverfavorinternalparallelism(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolverfavorinternalparallelism(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations in the single-threaded +mode until statistics prove that iteration cost justified activating +multithreading. + +This way solver does not suffer slow-down on problems with small iteration +overhead (<1ms per iteration), at the cost of spending initial 10-20 ms +in the single-threaded mode even on difficult problems that justify +parallelism usage. + +Use MINLPSolver.FavorInternalParallelism() to use parallelism until it is +proven to be useless. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercautiousinternalparallelism(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolvercautiousinternalparallelism(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations exactly as prescribed by +the user: in the parallel mode when alglib::parallel flag is passed, in +the single-threaded mode otherwise. The solver does not analyze actual +running times to decide whether parallelism is justified or not. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvernoadaptiveinternalparallelism(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolvernoadaptiveinternalparallelism(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function marks K-th variable as an integral one. + +Unless box constraints are set for the variable, it is unconstrained (i.e. +can take positive or negative values). By default all variables are +continuous. + +IMPORTANT: box constraints work in parallel with the integrality ones: + * a variable marked as integral is considered having no bounds + until minlpsolversetbc() is called + * a variable with lower and upper bounds set is considered + continuous until marked as integral with the + minlpsolversetintkth() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + K - 0<=K=1, group size. Up to GroupSize tree nodes can be + processed in the parallel manner. + + Increasing this parameter makes the solver + less efficient serially (it always tries to fill + the batch with nodes, even if there is a chance + that most of them will be discarded later), but + increases its parallel potential. + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + + Recommended value, depending on callback cost and + matrix factorization overhead, can be: + * 1 for 'easy' problems with cheap callbacks and + small dimensions; also for problems with nearly + linear B&B trees. + * 2-3 for problems with sufficiently costly + callbacks (or sufficiently high linear algebra + overhead) that it makes sense to utilize limited + parallelism. + * cores count - for difficult problems with deep + and wide B&B trees and sufficiently costly + callbacks (or sufficiently high linear algebra + overhead). + +NOTES: DETERMINISM + +Running with fixed GroupSize generally produces same results independently +of whether parallelism is used or not. Changing GroupSize parameter may +change results in the following ways: + +* for problems that are solved to optimality but have multiple solutions, + different values of this parameter may result in different solutions + being returned (but still with the same objective value) + +* while operating close to exhausting budget (either timeout or iterations + limit), different GroupSize values may result in different outcomes: a + solution being found, or budget being exhausted + +* finally, on difficult problems that are too hard to solve to optimality + but still allow finding primal feasible solutions changing GroupSize may + result in different primal feasible solutions being returned. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgobbsync(minlpsolverstate &state, const ae_int_t groupsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetalgobbsync(state.c_ptr(), groupsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tell the solver to use MIVNS (Mixed-Integer Variable +Neighborhood Search) solver for derivative-free mixed-integer nonlinear +programming with expensive objective/constraints and non-relaxable integer +variables. + +The solver is intended for moderately-sized problems, typically with tens +of variables. + +The algorithm has the following features: +* it supports all-integer and mixed-integer problems with box, linear and + nonlinear equality and inequality constraints +* it makes no assumptions about problem convexity +* it does not require derivative information. Although it still assumes + that objective/constraints are smooth wrt continuous variables, no such + assumptions are made regarding dependence on integer variables. +* it efficiently uses limited computational budget and scales well with + larger budgets +* it does not evaluate objective/constraints at points violating integrality +* it also respects linear constraints in all intermediate points + +NOTE: In particular, if your task uses integrality+sum-to-one set of + constraints to encode multiple choice options (e.g. [1,0,0], [0,1,0] + or [0,0,1]), you can be sure that the algorithm will not ask for an + objective value at a point with fractional values like [0.1,0.5,0.4] + or at one that is not a correct one-hot encoded value (e.g. [1,1,0] + which has two variables set to 1). + +The algorithm is intended for low-to-medium accuracy solution of otherwise +intractable problems with expensive objective/constraints. + +It can solve any MINLP problem; however, it is optimized for the following +problem classes: +* limited variable count +* expensive objective/constraints +* nonrelaxable integer variables +* no derivative information +* problems where changes in integer variables lead to structural changes + in the entire system. Speaking in other words, on problems where each + integer variable acts as an on/off or "choice" switch that completely + rewires the model - turning constraints, variables, or whole sub-systems + on or off + +INPUT PARAMETERS: + State - structure that stores algorithm state + + Budget - optimization budget (function evaluations). The + solver will not stop immediately after reaching + Budget evaluations, but will stop shortly after + that (usually within 2N+1 evaluations). Zero value + means no limit. + + MaxNeighborhood - stopping condition for the solver. The algorithm + will stop as soon as there are no points better + than the current candidate in a neighborhood whose + size is equal to or exceeds MaxNeighborhood. Zero + means no stopping condition. + + Recommended neighborhood size is proportional to + the difference between integral variables count NI + and the number of linear equality constraints on + integral variables L (such constraints effectively + reduce problem dimensionality). + + The very minimal value for binary problems is NI-L, + which means that the solution can not be improved + by flipping one of variables between 0 and 1. The + very minimal value for non-binary integral vars is + twice as much (because now each point has two + neighbors per variable). However, such minimal + values often result in an early termination. + + It is recommended to set this parameter to 5*N or + 10*N (ignoring LI) and to test how it behaves on + your problem. + + BatchSize >=1, recommended batch size for neighborhood + exploration. Up to BatchSize nodes will be + evaluated at any moment, thus up to BatchSize + objective evaluations can be performed in parallel. + + Increasing this parameter makes the solver + slightly less efficient serially (it always tries + to fill the batch with nodes, even if there is a + chance that most of them will be discarded later), + but greatly increases its parallel potential. + + Recommended values depend on the cores count and + on the limitations of the objective/constraints + callback: + * 1 for serial execution, callback that can not be + called from multiple threads, or highly + parallelized expensive callback that keeps all + cores occupied + * small fixed value like 5 or 10, if you need + reproducible behavior independent from the cores + count + * CORESCOUNT, 2*CORESCOUNT or some other multiple + of CORESCOUNT, if you want to utilize parallelism + to the maximum extent + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + +NOTES: if no stopping criteria is specified (unlimited budget, no timeout, + no neighborhood size limit), then the solver will run until + enumerating all integer solutions. + +===== ALGORITHM DESCRIPTION ============================================== + +A simplified description for an all-integer algorithm, omitting stopping +criteria and various checks: + + MIVNS (ALL-INTEGER): + 1. Input: initial integral point, may be infeasible wrt nonlinear + constraints, but is feasible wrt linear ones. Enforce linear + feasibility, if needed. + 2. Generate initial neighborhood around the current point that is + equal to the point itself. The point is marked as explored. + 3. Scan neighborhood for a better point (one that is less + infeasible or has lower objective); if one is found, make it + current and goto #2 + 4. Scan neighborhood for an unexplored point (one with no objective + computed). If one if found, compute objective, mark the point as + explored, goto #3 + 5. If there are no unexplored or better points in the neighborhood, + expand it: find a point that was not used for expansion, + compute up to 2N its nearest integral neighbors, add them to + the neighborhood and mark as unexplored. Goto #3. + + NOTE: A nearest integral neighbor is a nearest point that differs at + least by +1 or -1 in one of integral variables and that is + feasible with respect to box and linear constraints (ignoring + nonlinear ones). For problems with difficult constraint sets + integral neighbors are found by solving MIQP subproblems. + +The algorithm above systematically scans neighborhood of a point until +either better point is found, an entire integer grid is enumerated, or one +of stopping conditions is met. + +A mixed-integer version of the algorithm is more complex: +* it still sees optimization space as a set of integer nodes, each node + having a subspace of continuous variables associated with it +* after starting to explore a node, the algorithm runs an RBF surrogate- + based subsolver for the node. It manages a dedicated subsolver for each + node in a neighborhood and adaptively divides its computational budget + between subsolvers, switching to a node as soon as its subsolver shows + better results than its competitors. +* the algorithm remembers all previously evaluated points and reuses them + as much as possible + +===== ALGORITHM SCALING WITH VARIABLES COUNT N =========================== + +A 'neighborhood scan' is a minimum number of function evaluations needed +to perform at least minimal evaluation of the immediate neighborhood. For +an N-dimensional problem with NI integer variables and NF continuous ones +we have ~NI nodes in an immediate neighborhood, and each node needs ~NF +evalutations to build at least linear model of the objective. + +Thus, a MIVNS neighborhood scan will need about NI*NF=NI*(N-NI)=NF*(N-NF) +objective evaluations. + +It is important to note that MIVNS does not share information between +nodes because it assumes that objective landscape can drastically change +when jumping from node to node. That's why we need NI*NF instead of NI+NF +objective values. + +In practice, when started not too far away from the minimum, we can expect +to get some improvement in 5-10 scans, and to get significant progress in +50-100 scans. + +For problems with NF being small or NI being small we have scan cost +being proportional to variables count N, which allows us to achieve good +progress using between 5N and 100N objective values. However, when both +NI and NF are close to N/2, a scan needs ~N^2 objective evaluations, +which results in a much worse scaling behavior. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgomivns(minlpsolverstate &state, const ae_int_t budget, const ae_int_t maxneighborhood, const ae_int_t batchsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetalgomivns(state.c_ptr(), budget, maxneighborhood, batchsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates multiple random restarts (performed for each node, +including root and child ones) that help to find global solutions to non- +convex problems. + +This parameter is used by branch-and-bound solvers and is presently +ignored by derivative-free solvers. + +INPUT PARAMETERS: + State - structure that stores algorithm state + NMultistarts - >=1, number of random restarts: + * 1 means that no restarts performed, the solver + assumes convexity + * >=1 means that solver assumes non-convexity and + performs fixed amount of random restarts + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetmultistarts(minlpsolverstate &state, const ae_int_t nmultistarts, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversetmultistarts(state.c_ptr(), nmultistarts, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates timeout feature. The solver finishes after running +for a specified amount of time (in seconds, fractions can be used) with +the best point so far. + +Depending on the situation, the following completion codes can be reported +in rep.terminationtype: +* -33 (failure), if timed out without finding a feasible point +* 5 (partial success), if timed out after finding at least one feasible point + +The solver does not stop immediately after timeout was triggered because +it needs some time for underlying subsolvers to react to timeout signal. +Generally, about one additional subsolver iteration (which is usually far +less than one B&B split) will be performed prior to stopping. + +INPUT PARAMETERS: + State - structure that stores algorithm state + Timeout - >=0, timeout in seconds (floating point number): + * 0 means no timeout + * >=0 means stopping after specified number of + seconds. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversettimeout(minlpsolverstate &state, const double timeout, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsolversettimeout(state.c_ptr(), timeout, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlpsolveriteration(minlpsolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minlpsolveriteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minlpsolveroptimize(minlpsolverstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::minlpsolverstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "minlpsolver"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minlpsolveroptimize()' (fvec is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; + + alglib_impl::minlpsolversetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlpsolveriteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'minlpsolveroptimize()' (jac is NULL)", &_alglib_env_state); +callbacks.jac = jac; + + alglib_impl::minlpsolversetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlpsolveriteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(sjac!=NULL, "ALGLIB: error in 'minlpsolveroptimize()' (sjac is NULL)", &_alglib_env_state); +callbacks.sjac = sjac; + + alglib_impl::minlpsolversetprotocolv2s(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlpsolveriteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==1 ) + { + alglib_impl::sparsecreatecrsemptybuf(request.vars, &state.c_ptr()->replysj, &_alglib_env_state); + for(alglib_impl::ae_int_t qidx=0; qidx(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpsolverstate_owner& _minlpsolverstate_owner::operator=(const _minlpsolverstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlpsolverstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpsolverstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlpsolverstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlpsolverstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlpsolverstate)); + alglib_impl::_minlpsolverstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlpsolverstate_owner::~_minlpsolverstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlpsolverstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlpsolverstate* _minlpsolverstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlpsolverstate* _minlpsolverstate_owner::c_ptr() const +{ + return p_struct; +} +minlpsolverstate::minlpsolverstate() : _minlpsolverstate_owner() +{ +} + +minlpsolverstate::minlpsolverstate(alglib_impl::minlpsolverstate *attach_to):_minlpsolverstate_owner(attach_to) +{ +} + +minlpsolverstate::minlpsolverstate(const minlpsolverstate &rhs):_minlpsolverstate_owner(rhs) +{ +} + +minlpsolverstate& minlpsolverstate::operator=(const minlpsolverstate &rhs) +{ + if( this==&rhs ) + return *this; + _minlpsolverstate_owner::operator=(rhs); + return *this; +} + +minlpsolverstate::~minlpsolverstate() +{ +} + + + + +/************************************************************************* +This structure stores the optimization report. + +The following fields are set by all MINLP solvers: +* f objective value at the solution +* nfev number of value/gradient evaluations +* terminationtype termination type (see below) + +The BBGD solver additionally sets the following fields: +* pdgap final primal-dual gap +* ntreenodes number of B&B tree nodes traversed +* nsubproblems total number of NLP relaxations solved; can be + larger than ntreenodes because of restarts +* nnodesbeforefeasibility number of nodes evaluated before finding first + integer feasible solution + +TERMINATION CODES + +TerminationType field contains completion code, which can be either FAILURE +code or SUCCESS code. + +=== FAILURE CODE === + -33 timed out, failed to find a feasible point within time limit or + iteration budget + -8 internal integrity control detected infinite or NAN values in + function/gradient, recovery was impossible. Abnormal termination + signaled. + -3 integer infeasibility is signaled: + * for convex problems: proved to be infeasible + * for nonconvex problems: a primal feasible point is nonexistent + or too difficult to find + + +=== SUCCESS CODE === + 2 successful solution: + * for BBGD - entire tree was scanned + * for MIVNS - either entire integer grid was scanned, or the + neighborhood size based condition was triggered (in future + versions other criteria may be introduced) + 5 a primal feasible point was found, but time or iteration limit was + exhausted but we failed to find a better one or prove its + optimality; the best point so far is returned. +*************************************************************************/ +_minlpsolverreport_owner::_minlpsolverreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpsolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlpsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpsolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpsolverreport)); + alglib_impl::_minlpsolverreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpsolverreport_owner::_minlpsolverreport_owner(alglib_impl::minlpsolverreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlpsolverreport_owner::_minlpsolverreport_owner(const _minlpsolverreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpsolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpsolverreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlpsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpsolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpsolverreport)); + alglib_impl::_minlpsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpsolverreport_owner& _minlpsolverreport_owner::operator=(const _minlpsolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlpsolverreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpsolverreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlpsolverreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlpsolverreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlpsolverreport)); + alglib_impl::_minlpsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlpsolverreport_owner::~_minlpsolverreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlpsolverreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlpsolverreport* _minlpsolverreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlpsolverreport* _minlpsolverreport_owner::c_ptr() const +{ + return p_struct; +} +minlpsolverreport::minlpsolverreport() : _minlpsolverreport_owner() ,f(p_struct->f),nfev(p_struct->nfev),nsubproblems(p_struct->nsubproblems),ntreenodes(p_struct->ntreenodes),nnodesbeforefeasibility(p_struct->nnodesbeforefeasibility),terminationtype(p_struct->terminationtype),pdgap(p_struct->pdgap) +{ +} + +minlpsolverreport::minlpsolverreport(alglib_impl::minlpsolverreport *attach_to):_minlpsolverreport_owner(attach_to) ,f(p_struct->f),nfev(p_struct->nfev),nsubproblems(p_struct->nsubproblems),ntreenodes(p_struct->ntreenodes),nnodesbeforefeasibility(p_struct->nnodesbeforefeasibility),terminationtype(p_struct->terminationtype),pdgap(p_struct->pdgap) +{ +} + +minlpsolverreport::minlpsolverreport(const minlpsolverreport &rhs):_minlpsolverreport_owner(rhs) ,f(p_struct->f),nfev(p_struct->nfev),nsubproblems(p_struct->nsubproblems),ntreenodes(p_struct->ntreenodes),nnodesbeforefeasibility(p_struct->nnodesbeforefeasibility),terminationtype(p_struct->terminationtype),pdgap(p_struct->pdgap) +{ +} + +minlpsolverreport& minlpsolverreport::operator=(const minlpsolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _minlpsolverreport_owner::operator=(rhs); + return *this; +} + +minlpsolverreport::~minlpsolverreport() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) +static double bbgd_safetyfactor = 0.001; +static ae_int_t bbgd_backtracklimit = 0; +static double bbgd_alphaint = 0.01; +static ae_int_t bbgd_ftundefined = -1; +static ae_int_t bbgd_ftroot = 0; +static ae_int_t bbgd_ftdynamic = 2; +static ae_int_t bbgd_stundefined = -1; +static ae_int_t bbgd_stfrontrunning = 698; +static ae_int_t bbgd_stfrontreadytorun = 699; +static ae_int_t bbgd_streadytorun = 700; +static ae_int_t bbgd_stwaitingforrcomm = 701; +static ae_int_t bbgd_stsolved = 702; +static ae_int_t bbgd_sttimeout = 703; +static ae_int_t bbgd_rqsrcfront = 1; +static ae_int_t bbgd_rqsrcxc = 2; +static ae_int_t bbgd_divenever = 0; +static ae_int_t bbgd_diveuntilprimal = 1; +static ae_int_t bbgd_divealways = 2; +static ae_int_t bbgd_maxipmits = 200; +static ae_int_t bbgd_maxqprfsits = 5; +static void bbgd_clearoutputs(bbgdstate* state, ae_state *_state); +static void bbgd_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + bbgdstate* state, + ae_state *_state); +static void bbgd_reduceandappendrequestto(const minnlcstate* subsolver, + bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state); +static void bbgd_extractextendandforwardreplyto(const bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + ae_int_t* requestidx, + minnlcstate* subsolver, + ae_state *_state); +static void bbgd_subproblemcopy(const bbgdsubproblem* src, + ae_int_t newid, + bbgdsubproblem* dst, + ae_state *_state); +static void bbgd_subproblemcopyasunsolved(const bbgdsubproblem* src, + ae_int_t newid, + bbgdsubproblem* dst, + ae_state *_state); +static void bbgd_subproblemrecomputedualbound(bbgdsubproblem* s, + ae_state *_state); +static void bbgd_subproblemrandomizex0(bbgdsubproblem* p, + bbgdstate* state, + ae_state *_state); +static void bbgd_subproblemappendcopytoarray(const bbgdsubproblem* p, + bbgdstate* state, + ae_bool randomizeinitialpoint, + ae_obj_array* a, + ae_state *_state); +static ae_bool bbgd_subproblemcanfathom(const bbgdsubproblem* subproblem, + const bbgdstate* state, + ae_state *_state); +static void bbgd_frontinitundefined(bbgdfront* front, + bbgdstate* state, + ae_state *_state); +static void bbgd_frontstartroot(bbgdfront* front, + const bbgdsubproblem* r, + bbgdstate* state, + ae_state *_state); +static void bbgd_frontstartdynamic(bbgdfront* front, + bbgdstate* sstate, + ae_state *_state); +static void bbgd_frontrecomputedualbound(bbgdfront* front, + bbgdstate* state, + ae_state *_state); +static ae_bool bbgd_frontrun(bbgdfront* front, + bbgdstate* state, + ae_state *_state); +static ae_bool bbgd_frontruninternal(bbgdfront* front, + bbgdstate* state, + ae_state *_state); +static void bbgd_frontparallelrunentries(bbgdfront* front, + ae_int_t job0, + ae_int_t job1, + ae_bool isrootcall, + bbgdstate* state, + ae_state *_state); +ae_bool _trypexec_bbgd_frontparallelrunentries(bbgdfront* front, + ae_int_t job0, + ae_int_t job1, + ae_bool isrootcall, + bbgdstate* state, ae_state *_state); +static void bbgd_frontrunkthentryjthsubsolver(bbgdfront* front, + ae_int_t k, + ae_int_t j, + bbgdstate* state, + ae_state *_state); +static void bbgd_frontpackqueries(bbgdfront* front, + bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state); +static void bbgd_frontunpackreplies(bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + bbgdfront* front, + ae_state *_state); +static void bbgd_entryprepareroot(bbgdfrontentry* entry, + const bbgdfront* front, + const bbgdsubproblem* rootsubproblem, + bbgdstate* state, + ae_state *_state); +static ae_bool bbgd_entryprepareleafs(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdsubproblem* s, + bbgdstate* state, + ae_state *_state); +static void bbgd_entrypreparex(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdstate* state, + ae_bool isroot, + ae_state *_state); +static void bbgd_entrypreparesubsolver(bbgdstate* state, + bbgdfront* front, + bbgdfrontentry* entry, + const bbgdsubproblem* subproblem, + ae_bool isroot, + bbgdfrontsubsolver* subsolver, + ae_state *_state); +static ae_bool bbgd_subsolverrun(bbgdstate* state, + bbgdfront* front, + bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + ae_state *_state); +static void bbgd_entryaggregateandupdateglobalstats(bbgdfrontentry* entry, + bbgdstate* state, + ae_state *_state); +static void bbgd_entrydecideonfathoming(bbgdfrontentry* entry, + bbgdstate* state, + ae_state *_state); +static void bbgd_entrypushsolution(const bbgdfrontentry* entry, + bbgdstate* state, + ae_bool* setonupdate, + ae_state *_state); +static ae_bool bbgd_entrytrypushanddive(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdstate* state, + ae_state *_state); +static void bbgd_pushsubproblemsolution(const bbgdsubproblem* subproblem, + bbgdstate* state, + ae_bool* setonupdate, + ae_state *_state); +static ae_int_t bbgd_qpquickpresolve(const bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + /* Real */ const ae_vector* raws, + /* Real */ const ae_vector* rawxorigin, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + const sparsematrix* rawa, + ae_bool isupper, + /* Real */ const ae_vector* rawb, + ae_int_t n, + const sparsematrix* rawsparsec, + /* Real */ const ae_vector* rawcl, + /* Real */ const ae_vector* rawcu, + ae_int_t lccnt, + /* Integer */ const ae_vector* qpordering, + double eps, + ae_state *_state); +static void bbgd_solveqpnode(bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + bbgdstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_obj_array* subproblemarray, + ae_int_t itemidx, + ae_bool uselock, + ae_state *_state); +static void bbgd_analyzeqpsolutionandenforceintegrality(bbgdfrontentry* entry, + /* Real */ ae_vector* xsol, + ae_int_t terminationtype, + const bbgdstate* state, + bbgdsubproblem* subproblem, + ae_bool uselock, + ae_bool* isintfeas, + ae_state *_state); +static void bbgd_analyzenlpsolutionandenforceintegrality(bbgdfrontentry* entry, + /* Real */ ae_vector* xsol, + const minnlcreport* rep, + const bbgdstate* state, + ae_obj_array* subproblemarray, + ae_int_t itemidx, + ae_bool uselock, + ae_state *_state); +static void bbgd_growheap(bbgdstate* state, ae_state *_state); +static void bbgd_growheapandpoptop(bbgdstate* state, ae_state *_state); +static ae_int_t bbgd_subproblemheapgrow(ae_obj_array* subproblemheap, + ae_int_t offs, + ae_int_t heapsize, + ae_int_t appendcnt, + ae_state *_state); +static ae_int_t bbgd_subproblemheappoptop(ae_obj_array* subproblemheap, + ae_int_t offs, + ae_int_t heapsize, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) +static ae_int_t mirbfvns_nodeunexplored = 0; +static ae_int_t mirbfvns_nodeinprogress = 1; +static ae_int_t mirbfvns_nodesolved = 2; +static ae_int_t mirbfvns_nodebad = 3; +static ae_int_t mirbfvns_ncolstatus = 0; +static ae_int_t mirbfvns_ncolneighborbegin = 1; +static ae_int_t mirbfvns_ncolneighborend = 2; +static ae_int_t mirbfvns_ncolfbest = 3; +static ae_int_t mirbfvns_ncolhbest = 4; +static ae_int_t mirbfvns_ncolmxbest = 5; +static ae_int_t mirbfvns_ncollastaccepted = 6; +static ae_int_t mirbfvns_maxprimalcandforcut = 10; +static ae_int_t mirbfvns_softmaxnodescoeff = 10; +static ae_int_t mirbfvns_safetyboxforbbgd = 5; +static ae_int_t mirbfvns_rbfcloudsizemultiplier = 4; +static ae_int_t mirbfvns_rbfminimizeitsperphase = 5; +static double mirbfvns_rbfsubsolverepsx = 0.00001; +static double mirbfvns_eta2 = 0.7; +static double mirbfvns_gammadec = 0.5; +static double mirbfvns_gammadec2 = 0.66; +static double mirbfvns_gammadec3 = 0.05; +static double mirbfvns_gammainc = 2.0; +static double mirbfvns_gammainc2 = 4.0; +static double mirbfvns_rbfpointunacceptablyfar = 10.0; +static double mirbfvns_rbfpointtooclose = 0.01; +static double mirbfvns_rbfsktooshort = 0.01; +static double mirbfvns_habovezero = 50.0; +static ae_int_t mirbfvns_maxipmits = 200; +static void mirbfvns_clearoutputs(mirbfvnsstate* state, ae_state *_state); +static void mirbfvns_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + mirbfvnsstate* state, + ae_state *_state); +static ae_bool mirbfvns_prepareinitialpoint(mirbfvnsstate* state, + /* Real */ ae_vector* x, + double* lcerr, + ae_state *_state); +static void mirbfvns_prepareevaluationbatch(mirbfvnsstate* state, + ae_state *_state); +static ae_int_t mirbfvns_expandneighborhood(mirbfvnsstate* state, + ae_state *_state); +static void mirbfvns_computeviolation2(const mirbfvnsstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double* h, + double* mx, + ae_state *_state); +static void mirbfvns_findnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t rowidx, + ae_bool usesafetybox, + ae_state *_state); +static void mirbfvns_findnearestintegralsubjecttocutx(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t rowidx, + ae_bool usesafetybox, + mirbfvnstemporaries* buf, + ae_state *_state); +static void mirbfvns_parallelfindnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t r0, + ae_int_t r1, + ae_bool usesafetybox, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state); +ae_bool _trypexec_mirbfvns_parallelfindnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t r0, + ae_int_t r1, + ae_bool usesafetybox, + ae_bool isroot, + ae_bool tryparallelism, ae_state *_state); +static void mirbfvns_datasetinitempty(mirbfvnsdataset* dataset, + mirbfvnsstate* state, + ae_state *_state); +static ae_int_t mirbfvns_datasetappendpoint(mirbfvnsdataset* dataset, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double h, + double mx, + ae_state *_state); +static ae_int_t mirbfvns_gridcreate(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double h, + double mx, + ae_state *_state); +static void mirbfvns_gridappendpointtolist(mirbfvnsgrid* grid, + ae_int_t pointidx, + ae_int_t nodeidx, + ae_state *_state); +static ae_int_t mirbfvns_gridgetstatus(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static ae_bool mirbfvns_gridneedsevals(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static ae_int_t mirbfvns_gridfindorcreatenode(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +static void mirbfvns_gridfindnodeslike(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + ae_bool putfirst, + /* Boolean */ const ae_vector* varmask, + /* Integer */ ae_vector* nodeslist, + ae_int_t* nodescnt, + ae_state *_state); +static void mirbfvns_gridappendnilsubsolver(mirbfvnsgrid* grid, + ae_state *_state); +static void mirbfvns_gridinitnilsubsolver(mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + double f, + double h, + double mx, + ae_state *_state); +static ae_bool mirbfvns_gridgetbestinneighborhood(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Integer */ const ae_vector* neighbors, + ae_int_t neighborscnt, + double* fbest, + double* hbest, + double* mxbest, + ae_state *_state); +static ae_bool mirbfvns_gridgetbestlastacceptedinunsolvedneighborhood(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Integer */ const ae_vector* neighbors, + ae_int_t neighborscnt, + ae_int_t* nodeidx, + double* fbest, + double* hbest, + double* mxbest, + ae_state *_state); +static void mirbfvns_gridexpandcutgenerateneighbors(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* xcentral, + /* Real */ const ae_vector* nodecut, + /* Integer */ const ae_vector* excludelist, + ae_int_t excludecnt, + /* Integer */ ae_vector* neighbornodes, + /* Real */ ae_matrix* cutsapplied, + /* Real */ ae_matrix* pointsfound, + ae_int_t* nncnt, + /* Boolean */ ae_vector* tmpsuccessflags, + ae_state *_state); +static void mirbfvns_gridparallelproposelocaltrialpoint(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t r0, + ae_int_t r1, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state); +ae_bool _trypexec_mirbfvns_gridparallelproposelocaltrialpoint(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t r0, + ae_int_t r1, + ae_bool isroot, + ae_bool tryparallelism, ae_state *_state); +static void mirbfvns_gridproposelocaltrialpointnomask(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t nodeidx, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state); +static void mirbfvns_gridproposelocaltrialpointmasked(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t nodeidx, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state); +static void mirbfvns_gridproposetrialpointwhenexploringfrom(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t newnodeidx, + ae_int_t explorefromnode, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state); +static void mirbfvns_gridsendtrialpointto(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t centralnodeidx, + ae_int_t nodeidx, + /* Real */ const ae_vector* xtrial, + /* Real */ const ae_vector* replyfi, + ae_state *_state); +static void mirbfvns_gridoffloadbestpoint(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + /* Real */ ae_vector* x, + ae_int_t* pointidx, + double* f, + double* h, + double* mx, + ae_state *_state); +static ae_bool mirbfvns_isbetterpoint(double f0, + double h0, + double mx0, + double f1, + double h1, + double mx1, + double ctol, + ae_state *_state); +static ae_bool mirbfvns_gridisbetter(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t baseidx, + ae_int_t candidx, + ae_state *_state); +static double mirbfvns_gridgetpointscountinnode(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static double mirbfvns_gridgetfbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static double mirbfvns_gridgethbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static double mirbfvns_gridgetmxbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state); +static void mirbfvns_rbfminimizemodel(const mirbfmodel* model, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* trustregion, + double trustradfactor, + double ctol, + ae_int_t maxitsperphase, + ae_bool autoscalemodel, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t n, + rbfmmtemporaries* buf, + /* Real */ ae_vector* xn, + /* Real */ ae_vector* sk, + double* predf, + double* predh, + ae_int_t* subsolverits, + ae_state *_state); +static void mirbfvns_rbfinitmodel(/* Real */ const ae_matrix* xf, + /* Real */ const ae_vector* multscale, + ae_int_t nc, + ae_int_t n, + ae_int_t nf, + mirbfmodel* model, + ae_state *_state); +static void mirbfvns_rbfinitemptysparsemodel(/* Real */ const ae_vector* multscale, + ae_int_t n, + mirbfmodel* model, + ae_state *_state); +static void mirbfvns_rbfappendconstantmodel(mirbfmodel* model, + double v, + ae_state *_state); +static void mirbfvns_rbfappendmodel(mirbfmodel* model, + const mirbfmodel* minimodel, + /* Integer */ const ae_vector* mini2full, + ae_state *_state); +static void mirbfvns_rbfaddlinearterm(mirbfmodel* model, + /* Real */ const ae_matrix* c, + ae_state *_state); +static void mirbfvns_rbfcomputemodel(const mirbfmodel* mmodel, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* f, + ae_bool needf, + /* Real */ ae_vector* g, + ae_bool needg, + ae_state *_state); +static void mirbfvns_rbfsolvecpdm(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* bb, + ae_int_t ncenters, + ae_int_t nrhs, + ae_int_t nx, + double lambdav, + ae_bool iscpd, + /* Real */ ae_matrix* ssol, + ae_state *_state); +static double mirbfvns_rdistinfrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i0, + /* Real */ const ae_matrix* b, + ae_int_t i1, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +static void minlpsolvers_clearoutputs(minlpsolverstate* state, + ae_state *_state); +static void minlpsolvers_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + minlpsolverstate* state, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +BBGD solver initialization. +-------------------------------------------------------------------------- + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdcreatebuf(ae_int_t n, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + /* Boolean */ const ae_vector* isintegral, + /* Boolean */ const ae_vector* isbinary, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t groupsize, + ae_int_t nmultistarts, + ae_int_t timeout, + ae_int_t tracelevel, + bbgdstate* state, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>=1, "BBGDCreateBuf: N<1", _state); + ae_assert(x0->cnt>=n, "BBGDCreateBuf: Length(X0)cnt>=n, "BBGDCreateBuf: Length(BndL)cnt>=n, "BBGDCreateBuf: Length(BndU)cnt>=n, "BBGDCreateBuf: Length(S)cnt>=n, "BBGDCreateBuf: Length(IsIntegral)cnt>=n, "BBGDCreateBuf: Length(IsBinary)=0, "BBGDCreateBuf: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "BBGDCreateBuf: Length(NL)cnt>=nnlc, "BBGDCreateBuf: Length(NU)=1, "BBGDCreateBuf: GroupSize<1", _state); + ae_assert(nmultistarts>=1, "BBGDCreateBuf: NMultistarts<1", _state); + ae_assert(timeout>=0, "BBGDCreateBuf: Timeout<0", _state); + ae_assert((tracelevel==0||tracelevel==1)||tracelevel==2, "BBGDCreateBuf: unexpected trace level", _state); + bbgd_initinternal(n, x0, 0, 0.0, state, _state); + state->forceserial = ae_false; + state->bbgdgroupsize = groupsize; + state->nmultistarts = nmultistarts; + state->timeout = timeout; + state->dotrace = tracelevel==2; + state->dolaconictrace = tracelevel==1; + for(i=0; i<=n-1; i++) + { + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "BBGDCreateBuf: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "BBGDCreateBuf: BndL contains NAN or -INF", _state); + ae_assert(isintegral->ptr.p_bool[i]||!isbinary->ptr.p_bool[i], "BBGDCreateBuf: variable marked as binary but not integral", _state); + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "BBGDCreateBuf: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "BBGDCreateBuf: S contains zero elements", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + state->isintegral.ptr.p_bool[i] = isintegral->ptr.p_bool[i]; + state->isbinary.ptr.p_bool[i] = isbinary->ptr.p_bool[i]; + state->s.ptr.p_double[i] = rcase2(isintegral->ptr.p_bool[i], 1.0, ae_fabs(s->ptr.p_double[i], _state), _state); + } + state->lccnt = lccnt; + if( lccnt>0 ) + { + sparsecopybuf(sparsea, &state->rawa, _state); + rcopyallocv(lccnt, al, &state->rawal, _state); + rcopyallocv(lccnt, au, &state->rawau, _state); + icopyallocv(lccnt, lcsrcidx, &state->lcsrcidx, _state); + } + state->nnlc = nnlc; + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "BBGDCreateBuf: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "BBGDCreateBuf: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + } +} + + +/************************************************************************* +Enforces serial processing (useful when BBGD is called as a part of larger +multithreaded algorithm) + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdforceserial(bbgdstate* state, ae_state *_state) +{ + + + state->forceserial = ae_true; +} + + +/************************************************************************* +Set required primal-dual gap + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetpdgap(bbgdstate* state, double pdgap, ae_state *_state) +{ + + + state->pdgap = pdgap; +} + + +/************************************************************************* +Set tolerance for violation of nonlinear constraints + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetctol(bbgdstate* state, double ctol, ae_state *_state) +{ + + + state->ctol = ctol; +} + + +/************************************************************************* +Set subsolver stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetepsf(bbgdstate* state, double epsf, ae_state *_state) +{ + + + state->epsf = epsf; +} + + +/************************************************************************* +Small tree profile + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetsmalltree(bbgdstate* state, ae_state *_state) +{ + + + state->branchingtype = 1; + state->krel = 1; + state->kevalunreliable = 1; + state->kevalreliable = 1; +} + + +/************************************************************************* +Large tree profile + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetlargetree(bbgdstate* state, ae_state *_state) +{ + + + state->branchingtype = 2; + state->krel = 1; + state->kevalunreliable = state->n; + state->kevalreliable = 1; +} + + +/************************************************************************* +Sets diving strategy: +* 0 for no diving +* 1 for diving until finding first primal solution, then switching to best + first +* 2 for always diving + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetdiving(bbgdstate* state, + ae_int_t divingmode, + ae_state *_state) +{ + + + if( divingmode==0 ) + { + state->dodiving = bbgd_divenever; + return; + } + if( divingmode==1 ) + { + state->dodiving = bbgd_diveuntilprimal; + return; + } + if( divingmode==2 ) + { + state->dodiving = bbgd_divealways; + return; + } + ae_assert(ae_false, "BBGDSetDiving: unexpected diving mode", _state); +} + + +/************************************************************************* +Tells the solver to stop after finding MaxCand primal candidates (integral +solutions that were accepted or fathomed) + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetmaxprimalcandidates(bbgdstate* state, + ae_int_t maxcand, + ae_state *_state) +{ + + + state->maxprimalcandidates = maxcand; +} + + +/************************************************************************* +Set soft max nodes (stop after this amount of nodes, if we have a primal +solution) + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetsoftmaxnodes(bbgdstate* state, + ae_int_t maxnodes, + ae_state *_state) +{ + + + state->softmaxnodes = maxnodes; +} + + +/************************************************************************* +Set hard max nodes (stop after this amount of nodes, no matter primal +solution status) + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsethardmaxnodes(bbgdstate* state, + ae_int_t maxnodes, + ae_state *_state) +{ + + + state->hardmaxnodes = maxnodes; +} + + +/************************************************************************* +Set subsolver stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetepsx(bbgdstate* state, double epsx, ae_state *_state) +{ + + + state->epsx = epsx; +} + + +/************************************************************************* +Sets quadratic objective. If no nonlinear constraints were given, it is +guaranteed that no RCOMM requests will be issued during the optimization. + +The objective has the form 0.5*x'*A*x + b'*x + c0 + +Sparse A can be stored in any format, but presently this function supports +only matrices given by their lower triangle. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void bbgdsetquadraticobjective(bbgdstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + double c0, + ae_state *_state) +{ + + + ae_assert(!isupper, "BBGDSetQuadraticObjective: IsUpper=False is not implemented yet", _state); + state->objtype = 1; + sparsecopytocrs(a, &state->obja, _state); + rcopyallocv(state->n, b, &state->objb, _state); + state->objc0 = c0; +} + + +/************************************************************************* + + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool bbgditeration(bbgdstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t k; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + } + else + { + n = 359; + i = -58; + k = -919; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + + /* + * Init + */ + n = state->n; + bbgd_clearoutputs(state, _state); + ae_obj_array_clear(&state->bbsubproblems); + state->bbsubproblemsheapsize = 0; + state->bbsubproblemsrecentlyadded = 0; + rsetallocv(state->n, 1.0, &state->pseudocostsup, _state); + rsetallocv(state->n, 1.0, &state->pseudocostsdown, _state); + isetallocv(state->n, 0, &state->pseudocostscntup, _state); + isetallocv(state->n, 0, &state->pseudocostscntdown, _state); + state->globalpseudocostup = 1.0; + state->globalpseudocostdown = 1.0; + state->globalpseudocostcntup = 0; + state->globalpseudocostcntdown = 0; + ae_assert(state->objtype==0||state->objtype==1, "BBGD: 661544 failed", _state); + if( state->objtype==1 ) + { + for(i=0; i<=n-1; i++) + { + if( state->obja.ridx.ptr.p_int[i]obja.didx.ptr.p_int[i] ) + { + ae_assert(ae_false, "BBGD: preordering for non-diagonal A is not implemented yet", _state); + } + } + ipm2proposeordering(&state->dummyqpsubsolver, n, ae_true, &state->hasbndl, &state->hasbndu, &state->rawa, &state->rawal, &state->rawau, state->lccnt, &state->qpordering, _state); + } + + /* + * Initialize globally shared information + */ + state->nextleafid = 0; + state->hasprimalsolution = ae_false; + state->fprim = _state->v_posinf; + state->timedout = ae_false; + state->ffdual = _state->v_neginf; + bbgd_frontinitundefined(&state->front, state, _state); + ae_shared_pool_set_seed_if_different(&state->sppool, &state->dummysubproblem, (ae_int_t)sizeof(state->dummysubproblem), (ae_copy_constructor)_bbgdsubproblem_init_copy, (ae_destructor)_bbgdsubproblem_destroy, _state); + ae_shared_pool_set_seed_if_different(&state->subsolverspool, &state->dummysubsolver, (ae_int_t)sizeof(state->dummysubsolver), (ae_copy_constructor)_bbgdfrontsubsolver_init_copy, (ae_destructor)_bbgdfrontsubsolver_destroy, _state); + + /* + * Prepare root subproblem, perform initial feasibility checks, solve it. This part is the + * same for all BB algorithms. + */ + stimerinit(&state->timerglobal, _state); + stimerstart(&state->timerglobal, _state); + state->rootsubproblem.leafid = weakatomicfetchadd(&state->nextleafid, 1, _state); + state->rootsubproblem.branchbucket = -1; + state->rootsubproblem.parentfdual = ae_maxrealnumber; + state->rootsubproblem.n = n; + ae_assert(state->hasx0, "BBGD: integrity check 500655 failed", _state); + rcopyallocv(n, &state->x0, &state->rootsubproblem.x0, _state); + rcopyallocv(n, &state->bndl, &state->rootsubproblem.bndl, _state); + rcopyallocv(n, &state->bndu, &state->rootsubproblem.bndu, _state); + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + if( ae_isfinite(state->rootsubproblem.bndl.ptr.p_double[i], _state) ) + { + state->rootsubproblem.bndl.ptr.p_double[i] = (double)(ae_iceil(state->rootsubproblem.bndl.ptr.p_double[i]-state->ctol, _state)); + } + if( ae_isfinite(state->rootsubproblem.bndu.ptr.p_double[i], _state) ) + { + state->rootsubproblem.bndu.ptr.p_double[i] = (double)(ae_ifloor(state->rootsubproblem.bndu.ptr.p_double[i]+state->ctol, _state)); + } + } + if( state->isbinary.ptr.p_bool[i] ) + { + if( ae_isneginf(state->rootsubproblem.bndl.ptr.p_double[i], _state)||ae_fp_less(state->rootsubproblem.bndl.ptr.p_double[i],(double)(0)) ) + { + state->rootsubproblem.bndl.ptr.p_double[i] = (double)(0); + } + if( ae_isposinf(state->rootsubproblem.bndu.ptr.p_double[i], _state)||ae_fp_greater(state->rootsubproblem.bndu.ptr.p_double[i],(double)(1)) ) + { + state->rootsubproblem.bndu.ptr.p_double[i] = (double)(1); + } + } + } + state->rootsubproblem.hasprimalsolution = ae_false; + state->rootsubproblem.hasdualsolution = ae_false; + state->rootsubproblem.ncuttingplanes = 0; + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(state->rootsubproblem.bndl.ptr.p_double[i], _state)&&ae_isfinite(state->rootsubproblem.bndu.ptr.p_double[i], _state))&&ae_fp_greater(state->rootsubproblem.bndl.ptr.p_double[i],state->rootsubproblem.bndu.ptr.p_double[i]+state->ctol) ) + { + if( state->dotrace ) + { + ae_trace("> a combination of box and integrality constraints is infeasible, stopping\n"); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + } + if( state->dotrace ) + { + ae_trace("> generated root node, starting to solve it\n"); + } + bbgd_frontstartroot(&state->front, &state->rootsubproblem, state, _state); +lbl_3: + if( !bbgd_frontrun(&state->front, state, _state) ) + { + goto lbl_4; + } + state->requestsource = bbgd_rqsrcfront; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + goto lbl_3; +lbl_4: + ae_assert(state->front.frontstatus==bbgd_stsolved||state->front.frontstatus==bbgd_sttimeout, "BBGD: integrity check 184017 failed", _state); + if( state->front.frontstatus!=bbgd_stsolved ) + { + goto lbl_5; + } + if( state->dotrace ) + { + ae_trace("> root subproblem solved in %0.0f ms\n", + (double)(stimergetmsrunning(&state->timerglobal, _state))); + ae_trace(">> primal (upper) bound is %0.12e\n", + (double)(state->fprim)); + ae_trace(">> dual (lower) bound is %0.12e\n", + (double)(state->ffdual)); + } + state->repterminationtype = 1; + bbgd_frontstartdynamic(&state->front, state, _state); +lbl_7: + if( !bbgd_frontrun(&state->front, state, _state) ) + { + goto lbl_8; + } + state->requestsource = bbgd_rqsrcfront; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + goto lbl_7; +lbl_8: + ae_assert(state->front.frontstatus==bbgd_stsolved||state->front.frontstatus==bbgd_sttimeout, "BBGD: integrity check 826253 failed", _state); + if( state->front.frontstatus==bbgd_sttimeout ) + { + if( state->dotrace ) + { + ae_trace("> timeout was signaled, %0.0f ms passed\n", + (double)(stimergetmsrunning(&state->timerglobal, _state))); + } + state->timedout = ae_true; + } + goto lbl_6; +lbl_5: + if( state->dotrace ) + { + ae_trace("> timeout was signaled during solution of the root subproblem, %0.0f ms passed\n", + (double)(stimergetmsrunning(&state->timerglobal, _state))); + } + state->timedout = ae_true; +lbl_6: + + /* + * Write out solution + */ + if( !state->hasprimalsolution ) + { + goto lbl_9; + } + + /* + * A primal solution was found + */ + ae_assert(state->repterminationtype>0, "BBGD: integrity check 080232 failed", _state); + ae_assert(state->objtype==0||state->objtype==1, "BBGD: 778547 failed", _state); + rcopyallocv(n, &state->xprim, &state->xc, _state); + if( state->objtype!=0 ) + { + goto lbl_11; + } + state->requestsource = bbgd_rqsrcxc; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + goto lbl_12; +lbl_11: + state->repf = 0.5*sparsevsmv(&state->obja, ae_false, &state->xc, _state)+rdotv(n, &state->xc, &state->objb, _state)+state->objc0; +lbl_12: + state->reppdgap = ae_maxreal(state->fprim-state->ffdual, (double)(0), _state)/rmaxabs2(state->fprim, (double)(1), _state); + state->repterminationtype = 1; + if( state->timedout ) + { + state->repterminationtype = 5; + } + if( state->dotrace ) + { + ae_trace("> the solution is found: f=%0.9e, relative duality gap is %0.3e\n", + (double)(state->repf), + (double)(state->reppdgap)); + } + goto lbl_10; +lbl_9: + + /* + * The problem is infeasible + */ + ae_assert(state->front.frontstatus==bbgd_stsolved||state->front.frontstatus==bbgd_sttimeout, "BBGD: integrity check 280023 failed", _state); + state->repterminationtype = -3; + if( state->timedout ) + { + state->repterminationtype = -33; + } + if( state->dotrace ) + { + ae_trace("> the problem is infeasible (or feasible point is too difficult to find)\n"); + } +lbl_10: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ia.ptr.p_int[2] = k; + return result; +} + + +/************************************************************************* +Produce RComm request in RCOMM-V2 format, according to the current request +source +*************************************************************************/ +void bbgdoffloadrcommrequest(bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state) +{ + + + if( state->requestsource==bbgd_rqsrcfront ) + { + *requesttype = 0; + bbgd_frontpackqueries(&state->front, state, requesttype, querysize, queryfuncs, queryvars, querydim, queryformulasize, querydata, _state); + ae_assert(*querysize>0, "BBGD: 074812 failed", _state); + state->repnfev = state->repnfev+(*querysize); + return; + } + if( state->requestsource==bbgd_rqsrcxc ) + { + *requesttype = 1; + *querysize = 1; + *queryfuncs = 1+state->nnlc; + *queryvars = state->n; + *querydim = 0; + rcopyallocv(state->n, &state->xc, querydata, _state); + return; + } + ae_assert(ae_false, "BBGD: integrity check 094519 failed", _state); +} + + +/************************************************************************* +Process RComm reply in RCOMM-V2 format, according to the current request +source +*************************************************************************/ +void bbgdloadrcommreply(bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + ae_state *_state) +{ + + + if( state->requestsource==bbgd_rqsrcfront ) + { + bbgd_frontunpackreplies(state, requesttype, querysize, queryfuncs, queryvars, querydim, queryformulasize, replyfi, replydj, replysj, &state->front, _state); + return; + } + if( state->requestsource==bbgd_rqsrcxc ) + { + state->repf = replyfi->ptr.p_double[0]; + return; + } + ae_assert(ae_false, "BBGD: integrity check 118522 failed", _state); +} + + +/************************************************************************* +Clears output fields during initialization +*************************************************************************/ +static void bbgd_clearoutputs(bbgdstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_false; + state->repnfev = 0; + state->repterminationtype = 0; + state->repf = (double)(0); + state->reppdgap = ae_maxrealnumber; + state->repnsubproblems = 0; + state->repntreenodes = 0; + state->repnnodesbeforefeasibility = -1; + state->repnprimalcandidates = 0; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void bbgd_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + state->convexityflag = 0; + + /* + * Initialize other params + */ + critinitdefault(&state->criteria, _state); + state->timeout = 0; + state->pdgap = 1.0E-6; + state->ctol = 1.0E-5; + state->n = n; + state->epsx = 1.0E-7; + state->epsf = 1.0E-7; + state->nonrootmaxitslin = 2; + state->nonrootmaxitsconst = 50; + state->nonrootadditsforfeasibility = 5; + state->nmultistarts = 1; + state->branchingtype = 1; + state->krel = 1; + state->kevalunreliable = 1; + state->kevalreliable = 1; + state->dodiving = bbgd_diveuntilprimal; + state->pseudocostmu = 0.001; + state->pseudocostminfrac = 0.001; + state->pseudocostinfeaspenaly = 25.0; + state->nonconvexitygain = (double)(100); + state->diffstep = diffstep; + state->userterminationneeded = ae_false; + state->maxsubsolvers = 4*maxconcurrency(_state); + state->softmaxnodes = 0; + state->hardmaxnodes = 0; + state->maxprimalcandidates = 0; + bsetallocv(n, ae_false, &state->isintegral, _state); + bsetallocv(n, ae_false, &state->isbinary, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->hasbndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->hasbndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->x0, n, _state); + ae_vector_set_length(&state->xc, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->x0.ptr.p_double[i] = x->ptr.p_double[i]; + state->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + state->hasx0 = ae_true; + + /* + * Objective + */ + state->objtype = 0; + + /* + * Constraints + */ + state->lccnt = 0; + state->nnlc = 0; + + /* + * Report fields + */ + bbgd_clearoutputs(state, _state); + + /* + * Other structures + */ + hqrndseed(8543, 7455, &state->unsafeglobalrng, _state); + + /* + * RComm + */ + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + state->rstate.stage = -1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Appends RComm-V2 request coming from the subsolver to a queue. Performs +dimensional reduction, truncating slack variable. + +On the first call to this function State.RequestType must be zero. +*************************************************************************/ +static void bbgd_reduceandappendrequestto(const minnlcstate* subsolver, + bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state) +{ + ae_int_t localrequesttype; + ae_int_t n; + + + + /* + * If our request is the first one in a queue, initialize aggregated request. + * Otherwise, perform compatibility checks. + */ + localrequesttype = subsolver->requesttype; + ae_assert((((localrequesttype==1||localrequesttype==2)||localrequesttype==3)||localrequesttype==4)||localrequesttype==5, "BBGD: subsolver sends unsupported request", _state); + if( *requesttype==0 ) + { + + /* + * Load query metric and perform integrity checks + */ + *requesttype = localrequesttype; + state->lastrequesttype = localrequesttype; + *querysize = 0; + ae_assert(subsolver->queryfuncs>=1, "BBGD: integrity check 946245 failed", _state); + ae_assert(subsolver->queryvars>=1, "BBGD: integrity check 947246 failed", _state); + ae_assert(subsolver->querydim==0, "BBGD: integrity check 947247 failed", _state); + *queryfuncs = subsolver->queryfuncs; + *queryvars = subsolver->queryvars; + *querydim = 0; + *queryformulasize = subsolver->queryformulasize; + } + ae_assert(*requesttype==localrequesttype, "BBGD: subsolvers send incompatible request types that can not be aggregated", _state); + ae_assert(*queryfuncs==subsolver->queryfuncs, "BBGD: subsolvers send requests that have incompatible sizes and can not be aggregated", _state); + ae_assert(*queryvars==subsolver->queryvars, "BBGD: subsolvers send requests that have incompatible sizes and can not be aggregated", _state); + ae_assert(subsolver->querydim==0, "BBGD: subsolver send request with QueryDim<>0, unexpected", _state); + ae_assert((localrequesttype!=3&&localrequesttype!=5)||*queryformulasize==subsolver->queryformulasize, "BBGD: subsolvers send requests that are incompatible due to different query formula sizes", _state); + n = *queryvars; + + /* + * Handle various request types + */ + if( localrequesttype==1 ) + { + + /* + * Query sparse Jacobian + */ + rgrowv(*querysize*(*queryvars)+subsolver->querysize*(*queryvars), querydata, _state); + rcopyvx(subsolver->querysize*n, &subsolver->querydata, 0, querydata, *querysize*(*queryvars), _state); + *querysize = *querysize+subsolver->querysize; + return; + } + if( localrequesttype==2 ) + { + + /* + * Query dense Jacobian + */ + rgrowv(*querysize*(*queryvars)+subsolver->querysize*(*queryvars), querydata, _state); + rcopyvx(subsolver->querysize*n, &subsolver->querydata, 0, querydata, *querysize*(*queryvars), _state); + *querysize = *querysize+subsolver->querysize; + return; + } + ae_assert(ae_false, "ReduceAndAppendRequestTo: unsupported protocol", _state); +} + + +/************************************************************************* +Extracts Subproblem.QuerySize replies, starting from RequestIdx-th one, +from the aggregated reply, reformulates nonlinear objective as an additional +constraint and extends the problem with a slack variable. +*************************************************************************/ +static void bbgd_extractextendandforwardreplyto(const bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + ae_int_t* requestidx, + minnlcstate* subsolver, + ae_state *_state) +{ + ae_int_t n; + ae_int_t localrequesttype; + ae_int_t fidstoffs; + ae_int_t fisrcoffs; + ae_int_t jacdstoffs; + ae_int_t jacsrcoffs; + + + + /* + * Compatibility checks. + */ + localrequesttype = subsolver->requesttype; + ae_assert(localrequesttype==state->lastrequesttype, "BBGD: integrity check 040003 failed", _state); + ae_assert(subsolver->queryfuncs==queryfuncs, "BBGD: integrity check 041003 failed", _state); + ae_assert(subsolver->queryvars==queryvars, "BBGD: integrity check 042003 failed", _state); + ae_assert(querydim==0, "BBGD: integrity check 043003 failed", _state); + ae_assert(*requestidx+subsolver->querysize<=querysize, "BBGD: integrity check 044003 failed", _state); + n = queryvars; + + /* + * Handle various request types + */ + if( state->lastrequesttype==1 ) + { + + /* + * A sparse Jacobian is retrieved + */ + fidstoffs = 0; + fisrcoffs = *requestidx*queryfuncs; + jacdstoffs = 0; + jacsrcoffs = *requestidx*queryfuncs; + rcopyvx(subsolver->querysize*queryfuncs, replyfi, fisrcoffs, &subsolver->replyfi, fidstoffs, _state); + sparsecreatecrsfromcrsrangebuf(replysj, jacsrcoffs, jacsrcoffs+subsolver->querysize*queryfuncs, &subsolver->replysj, _state); + *requestidx = *requestidx+subsolver->querysize; + return; + } + if( state->lastrequesttype==2 ) + { + + /* + * A dense Jacobian is retrieved + */ + fidstoffs = 0; + fisrcoffs = *requestidx*queryfuncs; + jacdstoffs = 0; + jacsrcoffs = *requestidx*queryvars*queryfuncs; + rcopyvx(subsolver->querysize*queryfuncs, replyfi, fisrcoffs, &subsolver->replyfi, fidstoffs, _state); + rcopyvx(n*subsolver->querysize*queryfuncs, replydj, jacsrcoffs, &subsolver->replydj, jacdstoffs, _state); + *requestidx = *requestidx+subsolver->querysize; + return; + } + ae_assert(ae_false, "ExtractExtendAndForwardReplyTo: unsupported protocol", _state); +} + + +/************************************************************************* +Create a copy of subproblem with new ID (which can be equal to the original +one, though). +*************************************************************************/ +static void bbgd_subproblemcopy(const bbgdsubproblem* src, + ae_int_t newid, + bbgdsubproblem* dst, + ae_state *_state) +{ + + + dst->leafid = newid; + dst->branchbucket = src->branchbucket; + dst->parentfdual = src->parentfdual; + dst->branchvar = src->branchvar; + dst->branchval = src->branchval; + dst->n = src->n; + rcopyallocv(src->n, &src->x0, &dst->x0, _state); + rcopyallocv(src->n, &src->bndl, &dst->bndl, _state); + rcopyallocv(src->n, &src->bndu, &dst->bndu, _state); + ae_assert(src->ncuttingplanes==0, "BBGD: integrity check 346147 failed", _state); + dst->ncuttingplanes = src->ncuttingplanes; + dst->hasprimalsolution = src->hasprimalsolution; + dst->hasdualsolution = src->hasdualsolution; + if( src->hasprimalsolution ) + { + rcopyallocv(src->n, &src->xprim, &dst->xprim, _state); + } + dst->fprim = src->fprim; + dst->hprim = src->hprim; + if( src->hasdualsolution ) + { + rcopyallocv(src->n, &src->bestxdual, &dst->bestxdual, _state); + rcopyallocv(src->n, &src->worstxdual, &dst->worstxdual, _state); + } + dst->bestfdual = src->bestfdual; + dst->besthdual = src->besthdual; + dst->worstfdual = src->worstfdual; + dst->worsthdual = src->worsthdual; + dst->bestdualisintfeas = src->bestdualisintfeas; + dst->dualbound = src->dualbound; +} + + +/************************************************************************* +Create a copy of subproblem with new ID, in an unsolved state +*************************************************************************/ +static void bbgd_subproblemcopyasunsolved(const bbgdsubproblem* src, + ae_int_t newid, + bbgdsubproblem* dst, + ae_state *_state) +{ + + + bbgd_subproblemcopy(src, newid, dst, _state); + dst->hasprimalsolution = ae_false; + dst->hasdualsolution = ae_false; + dst->bestdualisintfeas = ae_false; + dst->fprim = _state->v_posinf; + dst->hprim = _state->v_posinf; + dst->bestfdual = _state->v_posinf; + dst->besthdual = _state->v_posinf; + dst->worstfdual = _state->v_posinf; + dst->worsthdual = _state->v_posinf; + dst->dualbound = _state->v_posinf; +} + + +/************************************************************************* +Computes dual bound having best and worst versions of a dual solution. +Sets it to +INF if no dual solution is present. +*************************************************************************/ +static void bbgd_subproblemrecomputedualbound(bbgdsubproblem* s, + ae_state *_state) +{ + double bestworstspread; + + + s->dualbound = _state->v_posinf; + if( s->hasdualsolution ) + { + bestworstspread = ae_fabs(s->bestfdual-s->worstfdual, _state); + s->dualbound = s->bestfdual-bbgd_safetyfactor*bestworstspread; + } +} + + +/************************************************************************* +Randomize initial point of a subproblem +*************************************************************************/ +static void bbgd_subproblemrandomizex0(bbgdsubproblem* p, + bbgdstate* state, + ae_state *_state) +{ + ae_int_t i; + double vs; + + + ae_assert(p->n==state->n, "BBGD: integrity check 797204 failed", _state); + vs = ae_pow((double)(2), 0.5*hqrndnormal(&state->unsafeglobalrng, _state), _state); + for(i=0; i<=state->n-1; i++) + { + if( ae_isfinite(p->bndl.ptr.p_double[i], _state)&&ae_isfinite(p->bndu.ptr.p_double[i], _state) ) + { + p->x0.ptr.p_double[i] = p->bndl.ptr.p_double[i]+(p->bndu.ptr.p_double[i]-p->bndl.ptr.p_double[i])*hqrnduniformr(&state->unsafeglobalrng, _state); + p->x0.ptr.p_double[i] = ae_maxreal(p->x0.ptr.p_double[i], p->bndl.ptr.p_double[i], _state); + p->x0.ptr.p_double[i] = ae_minreal(p->x0.ptr.p_double[i], p->bndu.ptr.p_double[i], _state); + continue; + } + if( ae_isfinite(p->bndl.ptr.p_double[i], _state) ) + { + p->x0.ptr.p_double[i] = ae_maxreal(p->x0.ptr.p_double[i], p->bndl.ptr.p_double[i], _state)+vs*hqrndnormal(&state->unsafeglobalrng, _state); + p->x0.ptr.p_double[i] = ae_maxreal(p->x0.ptr.p_double[i], p->bndl.ptr.p_double[i], _state); + continue; + } + if( ae_isfinite(p->bndu.ptr.p_double[i], _state) ) + { + p->x0.ptr.p_double[i] = ae_minreal(p->x0.ptr.p_double[i], p->bndu.ptr.p_double[i], _state)+vs*hqrndnormal(&state->unsafeglobalrng, _state); + p->x0.ptr.p_double[i] = ae_minreal(p->x0.ptr.p_double[i], p->bndu.ptr.p_double[i], _state); + continue; + } + p->x0.ptr.p_double[i] = p->x0.ptr.p_double[i]+vs*hqrndnormal(&state->unsafeglobalrng, _state); + } +} + + +/************************************************************************* +Randomize initial point of a subproblem +*************************************************************************/ +static void bbgd_subproblemappendcopytoarray(const bbgdsubproblem* p, + bbgdstate* state, + ae_bool randomizeinitialpoint, + ae_obj_array* a, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdsubproblem *subproblem; + ae_smart_ptr _subproblem; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + + ae_shared_pool_retrieve(&state->sppool, &_subproblem, _state); + bbgd_subproblemcopy(p, p->leafid, subproblem, _state); + if( randomizeinitialpoint ) + { + bbgd_subproblemrandomizex0(subproblem, state, _state); + } + ae_obj_array_append_transfer(a, &_subproblem, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Decides whether subproblem can be fathomed due to: +* infeasibility +* primal bound +*************************************************************************/ +static ae_bool bbgd_subproblemcanfathom(const bbgdsubproblem* subproblem, + const bbgdstate* state, + ae_state *_state) +{ + ae_bool result; + + + if( state->dotrace ) + { + ae_trace(">> analyzing %8dP: ", + (int)(subproblem->leafid)); + } + if( !subproblem->hasdualsolution ) + { + if( state->dotrace ) + { + ae_trace("infeasible (err=%0.2e), fathomed\n", + (double)(subproblem->besthdual)); + } + result = ae_true; + return result; + } + if( state->dotrace ) + { + ae_trace("(bestfdual=%0.12e, dualbound=%0.12e, fprim=%0.12e)", + (double)(subproblem->bestfdual), + (double)(subproblem->dualbound), + (double)(subproblem->fprim)); + } + if( state->hasprimalsolution&&ae_fp_greater_eq(subproblem->dualbound,state->fprim-state->pdgap*rmaxabs2(state->fprim, (double)(1), _state)) ) + { + if( state->dotrace ) + { + ae_trace(", fathomed\n"); + } + result = ae_true; + return result; + } + if( state->dotrace ) + { + ae_trace("\n"); + } + result = ae_false; + return result; +} + + +/************************************************************************* +Initialize front in an undefined state. Ideally, it should be called once +per entire optimization session. +*************************************************************************/ +static void bbgd_frontinitundefined(bbgdfront* front, + bbgdstate* state, + ae_state *_state) +{ + + + ae_obj_array_clear(&front->entries); + front->frontmode = bbgd_ftundefined; + front->frontstatus = bbgd_stundefined; + front->popmostrecent = ae_false; + front->backtrackbudget = bbgd_backtracklimit; + ae_shared_pool_set_seed_if_different(&front->entrypool, &state->dummyentry, (ae_int_t)sizeof(state->dummyentry), (ae_copy_constructor)_bbgdfrontentry_init_copy, (ae_destructor)_bbgdfrontentry_destroy, _state); +} + + +/************************************************************************* +Having an initialized front, configures it to solve a root subproblem. +*************************************************************************/ +static void bbgd_frontstartroot(bbgdfront* front, + const bbgdsubproblem* r, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + + ae_assert(state->nmultistarts>=1, "BBGD: integrity check 832130 failed", _state); + front->frontmode = bbgd_ftroot; + front->frontstatus = bbgd_stfrontreadytorun; + front->frontsize = 1; + while(ae_obj_array_get_length(&front->entries)frontsize) + { + ae_shared_pool_retrieve(&front->entrypool, &_e, _state); + ae_obj_array_append_transfer(&front->entries, &_e, _state); + } + while(ae_obj_array_get_length(&front->entries)>front->frontsize) + { + ae_obj_array_pop_transfer(&front->entries, &_e, _state); + ae_shared_pool_recycle(&front->entrypool, &_e, _state); + } + ae_obj_array_get(&front->entries, 0, &_e, _state); + bbgd_entryprepareroot(e, front, r, state, _state); + front->rstate.stage = -1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Starts synchronous dynamic front. + +Basically, it creates an empty front that will be dynamically populated by +FrontRun(). + +This function always succeedes. +*************************************************************************/ +static void bbgd_frontstartdynamic(bbgdfront* front, + bbgdstate* sstate, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + + front->frontmode = bbgd_ftdynamic; + front->frontstatus = bbgd_stfrontreadytorun; + front->frontsize = 0; + while(ae_obj_array_get_length(&front->entries)>front->frontsize) + { + ae_obj_array_pop_transfer(&front->entries, &_e, _state); + ae_shared_pool_recycle(&front->entrypool, &_e, _state); + } + front->rstate.stage = -1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Recomputes State.FFDual using current heap and front entries being processed. +Works only with dynamic fronts. +*************************************************************************/ +static void bbgd_frontrecomputedualbound(bbgdfront* front, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + bbgdsubproblem *p; + ae_smart_ptr _p; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + memset(&_p, 0, sizeof(_p)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + ae_smart_ptr_init(&_p, (void**)&p, ae_false, _state, ae_true); + + ae_assert(front->frontmode==bbgd_ftroot||front->frontmode==bbgd_ftdynamic, "BBGD: 647012 failed", _state); + state->ffdual = ae_maxrealnumber; + if( state->hasprimalsolution ) + { + state->ffdual = ae_minreal(state->ffdual, state->fprim, _state); + } + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + ae_assert(e->parentsubproblem.hasdualsolution||front->frontmode==bbgd_ftroot, "BBGD: 775356 failed", _state); + if( front->frontmode!=bbgd_ftroot&&e->parentsubproblem.hasdualsolution ) + { + state->ffdual = ae_minreal(state->ffdual, e->parentsubproblem.dualbound, _state); + } + } + if( ae_obj_array_get_length(&state->bbsubproblems)>0 ) + { + bbgd_growheap(state, _state); + ae_obj_array_get(&state->bbsubproblems, 0, &_p, _state); + ae_assert(p->hasdualsolution, "BBGD: integrity check 810337 failed", _state); + state->ffdual = ae_minreal(state->ffdual, p->dualbound, _state); + } + if( ae_fp_eq(state->ffdual,ae_maxrealnumber) ) + { + state->ffdual = -ae_maxrealnumber; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Run front +*************************************************************************/ +static ae_bool bbgd_frontrun(bbgdfront* front, + bbgdstate* state, + ae_state *_state) +{ + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( front->rstate.stage>=0 ) + { + } + else + { + } + if( front->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + ae_assert(front->frontstatus==bbgd_stfrontreadytorun, "BBGD: integrity check 249321 failed", _state); + front->frontstatus = bbgd_stfrontrunning; +lbl_1: + if( ae_false ) + { + goto lbl_2; + } + if( !bbgd_frontruninternal(front, state, _state) ) + { + goto lbl_2; + } + front->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + goto lbl_1; +lbl_2: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + return result; +} + + +/************************************************************************* +Run front (internal function), returns False when the front finished its +job. +*************************************************************************/ +static ae_bool bbgd_frontruninternal(bbgdfront* front, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + bbgdsubproblem *p; + ae_smart_ptr _p; + bbgdfrontsubsolver *subsolver; + ae_smart_ptr _subsolver; + ae_int_t i; + ae_int_t j; + ae_int_t jobscnt; + ae_int_t waitingcnt; + ae_bool bdummy; + ae_bool continuediving; + ae_bool handled; + ae_bool someentriessolved; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + memset(&_p, 0, sizeof(_p)); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + ae_smart_ptr_init(&_p, (void**)&p, ae_false, _state, ae_true); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + result = ae_true; + + /* + * Root front + */ + if( front->frontmode==bbgd_ftroot ) + { + + /* + * Phase 0: integrity check. At the entry the front must have single entry in stReadyToRun or stWaitingForRComm state. + * All subsolvers, if present, must also be stWaitingForRComm + */ + ae_assert(front->frontsize==1&&ae_obj_array_get_length(&state->bbsubproblems)==0, "BBGD: 909109 failed", _state); + ae_obj_array_get(&front->entries, 0, &_e, _state); + waitingcnt = 0; + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + ae_assert(subsolver->subsolverstatus==bbgd_stwaitingforrcomm||subsolver->subsolverstatus==bbgd_streadytorun, "BBGD: 915110 failed", _state); + if( subsolver->subsolverstatus==bbgd_stwaitingforrcomm ) + { + waitingcnt = waitingcnt+1; + } + } + ae_assert((e->entrystatus==bbgd_streadytorun&&waitingcnt==0)||(e->entrystatus==bbgd_stwaitingforrcomm&&waitingcnt>0), "BBGD: 919110 failed", _state); + + /* + * Internal loop: repeat until front size at the end of the loop is non-zero + */ + do + { + + /* + * Prepare + */ + bbgd_frontrecomputedualbound(front, state, _state); + ae_obj_array_get(&front->entries, 0, &_e, _state); + + /* + * Activate subsolvers until we hit MaxSubsolvers limit + */ + while(ae_obj_array_get_length(&e->spqueue)>0&&ae_obj_array_get_length(&e->subsolvers)maxsubsolvers) + { + ae_obj_array_pop_transfer(&e->spqueue, &_p, _state); + ae_shared_pool_retrieve(&state->subsolverspool, &_subsolver, _state); + bbgd_entrypreparesubsolver(state, front, e, p, ae_true, subsolver, _state); + ae_obj_array_append_transfer(&e->subsolvers, &_subsolver, _state); + ae_shared_pool_recycle(&state->sppool, &_p, _state); + } + + /* + * Parallel call to FrontRunKthEntry() + */ + jobscnt = 0; + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + igrowappendv(jobscnt+1, &front->jobs, j, _state); + jobscnt = jobscnt+1; + } + bbgd_frontparallelrunentries(front, 0, jobscnt, ae_true, state, _state); + + /* + * Analyze solution: signal timeout, check that all entries are stSolved or stWaitingForRComm, + * first-phase process solved entries (update global stats). + */ + e->entrystatus = icase2(ae_obj_array_get_length(&e->spqueue)>0, bbgd_streadytorun, bbgd_stsolved, _state); + j = 0; + while(jsubsolvers)) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + if( subsolver->subsolverstatus==bbgd_sttimeout ) + { + e->entrystatus = bbgd_sttimeout; + front->frontstatus = bbgd_sttimeout; + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( subsolver->subsolverstatus==bbgd_stwaitingforrcomm ) + { + e->entrystatus = bbgd_stwaitingforrcomm; + j = j+1; + continue; + } + ae_assert(subsolver->subsolverstatus==bbgd_stsolved, "BBGD: integrity check 976115 failed", _state); + if( j!=ae_obj_array_get_length(&e->subsolvers)-1 ) + { + ae_obj_array_swap(&e->subsolvers, j, ae_obj_array_get_length(&e->subsolvers)-1, _state); + } + ae_obj_array_pop_transfer(&e->subsolvers, &_subsolver, _state); + ae_shared_pool_recycle(&state->subsolverspool, &_subsolver, _state); + } + if( e->entrystatus!=bbgd_streadytorun&&e->entrystatus!=bbgd_stwaitingforrcomm ) + { + ae_assert(e->entrystatus==bbgd_stsolved, "BBGD: integrity check 670157 failed", _state); + bbgd_entryaggregateandupdateglobalstats(e, state, _state); + if( state->hasprimalsolution&&state->repnnodesbeforefeasibility<0 ) + { + state->repnnodesbeforefeasibility = state->repntreenodes; + } + bbgd_entrydecideonfathoming(e, state, _state); + } + + /* + * Push solutions to the heap, check stopping criteria for PDGap, recompute dual bound. + * + * After this phase is done either: + * a) the front is empty (in which case we repeat the loop), or + * b) there are entries, with all of them being stWaitingForRComm or stReadyToRun, + * in which case we exit in order for RComm request to be processed by the caller + */ + if( e->entrystatus!=bbgd_streadytorun&&e->entrystatus!=bbgd_stwaitingforrcomm ) + { + ae_assert(e->entrystatus==bbgd_stsolved, "BBGD: integrity check 000116 failed", _state); + bbgd_entrypushsolution(e, state, &bdummy, _state); + ae_obj_array_pop_transfer(&front->entries, &_e, _state); + ae_shared_pool_recycle(&front->entrypool, &_e, _state); + front->frontsize = front->frontsize-1; + bbgd_frontrecomputedualbound(front, state, _state); + if( state->dotrace ) + { + ae_trace("> root problem solved\n"); + } + result = ae_false; + front->frontstatus = bbgd_stsolved; + ae_frame_leave(_state); + return result; + } + bbgd_frontrecomputedualbound(front, state, _state); + if( state->hasprimalsolution&&ae_fp_greater_eq(state->ffdual,state->fprim-state->pdgap*rmaxabs2(state->fprim, (double)(1), _state)) ) + { + if( state->dotrace ) + { + ae_trace("> relative duality gap decreased below %0.2e, stopping\n", + (double)(state->pdgap)); + } + result = ae_false; + front->frontstatus = bbgd_stsolved; + ae_frame_leave(_state); + return result; + } + if( (state->softmaxnodes>0&&state->hasprimalsolution)&&state->repntreenodes>=state->softmaxnodes ) + { + if( state->dotrace ) + { + ae_trace("> soft max nodes triggered (stop if have primal solution), stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + if( state->hardmaxnodes>0&&state->repntreenodes>=state->hardmaxnodes ) + { + if( state->dotrace ) + { + ae_trace("> hard max nodes triggered (stop independently of primal solution status), stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + if( (state->maxprimalcandidates>0&&state->hasprimalsolution)&&state->repnprimalcandidates>=state->maxprimalcandidates ) + { + if( state->dotrace ) + { + ae_trace("> maximum number of primal candidates tried (more than %0d), stopping\n", + (int)(state->maxprimalcandidates)); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + + /* + * Count entries that wait for RComm; exit if RComm is needed. Continue iteration if all entries are stReadyToRun, + * we will generate RComm requests at the next round. + */ + waitingcnt = icase2(e->entrystatus==bbgd_stwaitingforrcomm, 1, 0, _state); + } + while(waitingcnt<=0); + ae_frame_leave(_state); + return result; + } + + /* + * Dynamic front + */ + if( front->frontmode==bbgd_ftdynamic ) + { + + /* + * Phase 0: integrity check. At the entry the front must have only stReadyToRun or stWaitingForRComm + * entries (or be empty). All subsolvers, if present, must also be stWaitingForRComm + */ + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + waitingcnt = 0; + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + ae_assert(subsolver->subsolverstatus==bbgd_stwaitingforrcomm||subsolver->subsolverstatus==bbgd_streadytorun, "BBGD: 713006 failed", _state); + if( subsolver->subsolverstatus==bbgd_stwaitingforrcomm ) + { + waitingcnt = waitingcnt+1; + } + } + ae_assert((e->entrystatus==bbgd_streadytorun&&waitingcnt==0)||(e->entrystatus==bbgd_stwaitingforrcomm&&waitingcnt>0), "BBGD: 665242 failed", _state); + } + + /* + * Internal loop: repeat until front size at the end of the loop is non-zero + */ + do + { + + /* + * Append entries from the BB heap until the front is full (or the heap is empty). + * If the front is empty after this phase it means that we are done. + */ + while(ae_obj_array_get_length(&state->bbsubproblems)>0&&front->frontsizebbgdgroupsize) + { + bbgd_growheapandpoptop(state, _state); + ae_obj_array_pop_transfer(&state->bbsubproblems, &_p, _state); + ae_assert(p->hasdualsolution, "BBGD: integrity check 687259 failed", _state); + if( state->hasprimalsolution&&ae_fp_greater_eq(p->dualbound,state->fprim-state->pdgap*rmaxabs2(state->fprim, (double)(1), _state)) ) + { + if( state->dotrace ) + { + ae_trace("> fathomed %8dP during tree search (p.bestfdual=%0.2e, p.dual_bound=%0.2e, global.fprim=%0.2e)\n", + (int)(p->leafid), + (double)(p->bestfdual), + (double)(p->dualbound), + (double)(state->fprim)); + } + ae_shared_pool_recycle(&state->sppool, &_p, _state); + continue; + } + ae_shared_pool_retrieve(&front->entrypool, &_e, _state); + if( !bbgd_entryprepareleafs(e, front, p, state, _state) ) + { + + /* + * Looks like the subproblem we extracted does not need splitting. + * Next one, please. + */ + if( state->dotrace ) + { + ae_trace("> subproblem %8dP does not need integral or spatial branching, skipping\n", + (int)(p->leafid)); + } + ae_shared_pool_recycle(&front->entrypool, &_e, _state); + ae_shared_pool_recycle(&state->sppool, &_p, _state); + continue; + } + ae_obj_array_append_transfer(&front->entries, &_e, _state); + front->frontsize = front->frontsize+1; + ae_shared_pool_recycle(&state->sppool, &_p, _state); + } + bbgd_frontrecomputedualbound(front, state, _state); + if( front->frontsize==0 ) + { + if( state->dotrace ) + { + ae_trace("> B&B tree has no subproblems that can be split, stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_stsolved; + ae_frame_leave(_state); + return result; + } + + /* + * Activate subsolvers in each entry until we hit MaxSubsolvers limit + */ + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + while(ae_obj_array_get_length(&e->spqueue)>0&&ae_obj_array_get_length(&e->subsolvers)maxsubsolvers) + { + ae_obj_array_pop_transfer(&e->spqueue, &_p, _state); + ae_shared_pool_retrieve(&state->subsolverspool, &_subsolver, _state); + bbgd_entrypreparesubsolver(state, front, e, p, ae_false, subsolver, _state); + ae_obj_array_append_transfer(&e->subsolvers, &_subsolver, _state); + ae_shared_pool_recycle(&state->sppool, &_p, _state); + } + } + + /* + * Parallel call to FrontRunKthEntry() + */ + jobscnt = 0; + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + igrowappendv(jobscnt+1, &front->jobs, i+j*front->frontsize, _state); + jobscnt = jobscnt+1; + } + } + bbgd_frontparallelrunentries(front, 0, jobscnt, ae_true, state, _state); + + /* + * Analyze solution: signal timeout, check that all entries are stSolved or stWaitingForRComm, + * first-phase process solved entries (update global stats). + */ + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + e->entrystatus = icase2(ae_obj_array_get_length(&e->spqueue)>0, bbgd_streadytorun, bbgd_stsolved, _state); + j = 0; + while(jsubsolvers)) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + if( subsolver->subsolverstatus==bbgd_sttimeout ) + { + e->entrystatus = bbgd_sttimeout; + front->frontstatus = bbgd_sttimeout; + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( subsolver->subsolverstatus==bbgd_stwaitingforrcomm ) + { + e->entrystatus = bbgd_stwaitingforrcomm; + j = j+1; + continue; + } + ae_assert(subsolver->subsolverstatus==bbgd_stsolved, "BBGD: integrity check 840056 failed", _state); + if( j!=ae_obj_array_get_length(&e->subsolvers)-1 ) + { + ae_obj_array_swap(&e->subsolvers, j, ae_obj_array_get_length(&e->subsolvers)-1, _state); + } + ae_obj_array_pop_transfer(&e->subsolvers, &_subsolver, _state); + ae_shared_pool_recycle(&state->subsolverspool, &_subsolver, _state); + } + if( e->entrystatus==bbgd_streadytorun||e->entrystatus==bbgd_stwaitingforrcomm ) + { + continue; + } + ae_assert(e->entrystatus==bbgd_stsolved, "BBGD: integrity check 670157 failed", _state); + bbgd_entryaggregateandupdateglobalstats(e, state, _state); + } + if( state->hasprimalsolution&&state->repnnodesbeforefeasibility<0 ) + { + state->repnnodesbeforefeasibility = state->repntreenodes; + } + + /* + * Push solutions to the heap, check stopping criteria for PDGap, recompute dual bound. + * + * After this phase is done either: + * a) the front is empty (in which case we repeat the loop), or + * b) there are entries, with all of them being stWaitingForRComm or stReadyToRun, + * in which case we exit in order for RComm request to be processed by the caller + */ + i = 0; + someentriessolved = ae_false; + while(ifrontsize) + { + + /* + * Analyze I-th entry, skip if ready to run or waiting for RComm + */ + ae_obj_array_get(&front->entries, i, &_e, _state); + if( e->entrystatus==bbgd_streadytorun||e->entrystatus==bbgd_stwaitingforrcomm ) + { + i = i+1; + continue; + } + ae_assert(e->entrystatus==bbgd_stsolved, "BBGD: integrity check 670158 failed", _state); + someentriessolved = ae_true; + + /* + * Process entry by either pushing both leaves to the heap or by perfoming + * a diving (the better leaf is continued, the worse one is pushed to the heap) + */ + bbgd_entrydecideonfathoming(e, state, _state); + continuediving = ae_false; + handled = ae_false; + if( state->dodiving==bbgd_divealways ) + { + continuediving = bbgd_entrytrypushanddive(e, front, state, _state); + handled = ae_true; + } + if( state->dodiving==bbgd_diveuntilprimal&&!state->hasprimalsolution ) + { + continuediving = bbgd_entrytrypushanddive(e, front, state, _state); + handled = ae_true; + } + if( !handled ) + { + bbgd_entrypushsolution(e, state, &bdummy, _state); + } + if( !continuediving ) + { + + /* + * No diving, push the solution and remove the entry + */ + if( i!=front->frontsize-1 ) + { + ae_obj_array_swap(&front->entries, i, front->frontsize-1, _state); + } + ae_obj_array_pop_transfer(&front->entries, &_e, _state); + front->frontsize = front->frontsize-1; + ae_shared_pool_recycle(&front->entrypool, &_e, _state); + } + } + bbgd_frontrecomputedualbound(front, state, _state); + if( front->frontsize==0&&ae_obj_array_get_length(&state->bbsubproblems)==0 ) + { + if( state->dotrace ) + { + ae_trace("> B&B tree has no subproblems that can be split, stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_stsolved; + ae_frame_leave(_state); + return result; + } + if( someentriessolved&&state->dotrace ) + { + ae_trace(">> global dual bound was recomputed as %0.12e, global primal bound is %0.12e\n", + (double)(state->ffdual), + (double)(state->fprim)); + } + if( state->hasprimalsolution&&ae_fp_greater_eq(state->ffdual,state->fprim-state->pdgap*rmaxabs2(state->fprim, (double)(1), _state)) ) + { + if( state->dotrace ) + { + ae_trace("> relative duality gap decreased below %0.2e, stopping\n", + (double)(state->pdgap)); + } + result = ae_false; + front->frontstatus = bbgd_stsolved; + ae_frame_leave(_state); + return result; + } + if( (state->softmaxnodes>0&&state->hasprimalsolution)&&state->repntreenodes>=state->softmaxnodes ) + { + if( state->dotrace ) + { + ae_trace("> soft max nodes triggered (stop if have primal solution), stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + if( state->hardmaxnodes>0&&state->repntreenodes>=state->hardmaxnodes ) + { + if( state->dotrace ) + { + ae_trace("> hard max nodes triggered (stop independently of primal solution status), stopping\n"); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + if( (state->maxprimalcandidates>0&&state->hasprimalsolution)&&state->repnprimalcandidates>=state->maxprimalcandidates ) + { + if( state->dotrace ) + { + ae_trace("> maximum number of primal candidates tried (more than %0d), stopping\n", + (int)(state->maxprimalcandidates)); + } + result = ae_false; + front->frontstatus = bbgd_sttimeout; + ae_frame_leave(_state); + return result; + } + + /* + * Count entries that wait for RComm; exit if RComm is needed. Continue iteration if all entries are stReadyToRun, + * we will generate RComm requests at the next round. + */ + waitingcnt = 0; + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + if( e->entrystatus==bbgd_stwaitingforrcomm ) + { + waitingcnt = waitingcnt+1; + } + } + } + while(waitingcnt<=0); + ae_frame_leave(_state); + return result; + } + + /* + * Unexpected front type + */ + ae_assert(ae_false, "BBGD: 592133 failed (unexpected front type)", _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Call EntryRun in parallel. + +Job0 and Job1 denote a range [Job0,Job1) in Front.Jobs to process, +IsRootCall must be True when called (used to distinguish recursive calls +from root ones). +*************************************************************************/ +static void bbgd_frontparallelrunentries(bbgdfront* front, + ae_int_t job0, + ae_int_t job1, + ae_bool isrootcall, + bbgdstate* state, + ae_state *_state) +{ + ae_int_t jobmid; + + + ae_assert(job1>job0, "BBGD: 551121 failed", _state); + if( job1-job0==1 ) + { + bbgd_frontrunkthentryjthsubsolver(front, front->jobs.ptr.p_int[job0]%front->frontsize, front->jobs.ptr.p_int[job0]/front->frontsize, state, _state); + return; + } + if( isrootcall&&!state->forceserial ) + { + if( _trypexec_bbgd_frontparallelrunentries(front,job0,job1,isrootcall,state, _state) ) + { + return; + } + } + jobmid = job0+(job1-job0)/2; + bbgd_frontparallelrunentries(front, job0, jobmid, ae_false, state, _state); + bbgd_frontparallelrunentries(front, jobmid, job1, ae_false, state, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_bbgd_frontparallelrunentries(bbgdfront* front, + ae_int_t job0, + ae_int_t job1, + ae_bool isrootcall, + bbgdstate* state, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Run k-th entry of the front. +*************************************************************************/ +static void bbgd_frontrunkthentryjthsubsolver(bbgdfront* front, + ae_int_t k, + ae_int_t j, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + bbgdfrontsubsolver *s; + ae_smart_ptr _s; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + memset(&_s, 0, sizeof(_s)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + ae_smart_ptr_init(&_s, (void**)&s, ae_false, _state, ae_true); + + ae_obj_array_get(&front->entries, k, &_e, _state); + if( front->frontmode==bbgd_ftroot||front->frontmode==bbgd_ftdynamic ) + { + ae_obj_array_get(&e->subsolvers, j, &_s, _state); + ae_assert(s->subsolverstatus==bbgd_streadytorun||s->subsolverstatus==bbgd_stwaitingforrcomm, "BBGD: 979201 failed", _state); + bbgd_subsolverrun(state, front, e, s, _state); + ae_frame_leave(_state); + return; + } + ae_assert(ae_false, "BBGD: 963109 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Pack requests coming from the front elements into the grand RComm request +*************************************************************************/ +static void bbgd_frontpackqueries(bbgdfront* front, + bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdfrontentry *e; + ae_smart_ptr _e; + bbgdfrontsubsolver *subsolver; + ae_smart_ptr _subsolver; + ae_int_t i; + ae_int_t j; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + ae_assert(((e->entrystatus==bbgd_streadytorun||e->entrystatus==bbgd_stwaitingforrcomm)||e->entrystatus==bbgd_stsolved)||e->entrystatus==bbgd_sttimeout, "BBGD: integrity check 304325 failed", _state); + if( e->entrystatus==bbgd_stwaitingforrcomm ) + { + if( front->frontmode==bbgd_ftroot||front->frontmode==bbgd_ftdynamic ) + { + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + ae_assert(subsolver->subsolverstatus==bbgd_stwaitingforrcomm, "BBGD: 021235 failed", _state); + bbgd_reduceandappendrequestto(&subsolver->nlpsubsolver, state, requesttype, querysize, queryfuncs, queryvars, querydim, queryformulasize, querydata, _state); + } + continue; + } + ae_assert(ae_false, "BBGD: 026236 failed", _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Unpack RComm replies and distribute them to front entries +*************************************************************************/ +static void bbgd_frontunpackreplies(bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + bbgdfront* front, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t offs; + bbgdfrontentry *e; + ae_smart_ptr _e; + bbgdfrontsubsolver *subsolver; + ae_smart_ptr _subsolver; + + ae_frame_make(_state, &_frame_block); + memset(&_e, 0, sizeof(_e)); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_e, (void**)&e, ae_false, _state, ae_true); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + offs = 0; + for(i=0; i<=front->frontsize-1; i++) + { + ae_obj_array_get(&front->entries, i, &_e, _state); + ae_assert(((e->entrystatus==bbgd_streadytorun||e->entrystatus==bbgd_stwaitingforrcomm)||e->entrystatus==bbgd_stsolved)||e->entrystatus==bbgd_sttimeout, "BBGD: integrity check 304325 failed", _state); + if( e->entrystatus==bbgd_stwaitingforrcomm ) + { + if( front->frontmode==bbgd_ftroot||front->frontmode==bbgd_ftdynamic ) + { + for(j=0; j<=ae_obj_array_get_length(&e->subsolvers)-1; j++) + { + ae_obj_array_get(&e->subsolvers, j, &_subsolver, _state); + ae_assert(subsolver->subsolverstatus==bbgd_stwaitingforrcomm, "BBGD: 070237 failed", _state); + bbgd_extractextendandforwardreplyto(state, requesttype, querysize, queryfuncs, queryvars, querydim, queryformulasize, replyfi, replydj, replysj, &offs, &subsolver->nlpsubsolver, _state); + } + continue; + } + ae_assert(ae_false, "BBGD: 071236 failed", _state); + } + } + ae_assert(offs==querysize, "BBGD: integrity check 606236 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Prepare subsolver for the front entry. Sets timers if timeout was specified. +*************************************************************************/ +static void bbgd_entryprepareroot(bbgdfrontentry* entry, + const bbgdfront* front, + const bbgdsubproblem* rootsubproblem, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t restartidx; + bbgdsubproblem *subproblem; + ae_smart_ptr _subproblem; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + + bbgd_entrypreparex(entry, front, state, ae_true, _state); + bbgd_subproblemcopyasunsolved(rootsubproblem, rootsubproblem->leafid, &entry->parentsubproblem, _state); + bbgd_subproblemcopyasunsolved(rootsubproblem, rootsubproblem->leafid, &entry->rootproblem, _state); + ae_shared_pool_retrieve(&state->sppool, &_subproblem, _state); + bbgd_subproblemcopyasunsolved(&entry->rootproblem, entry->rootproblem.leafid, subproblem, _state); + ae_obj_array_append_transfer(&entry->solutions, &_subproblem, _state); + for(restartidx=0; restartidx<=state->nmultistarts-1; restartidx++) + { + ae_shared_pool_retrieve(&state->sppool, &_subproblem, _state); + bbgd_subproblemcopyasunsolved(&entry->rootproblem, entry->rootproblem.leafid, subproblem, _state); + if( restartidx>0 ) + { + bbgd_subproblemrandomizex0(subproblem, state, _state); + } + ae_obj_array_append_transfer(&entry->spqueue, &_subproblem, _state); + } + entry->maxsubsolvers = ae_minint(ae_obj_array_get_length(&entry->spqueue), state->maxsubsolvers, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Prepare subsolver for the front entry. Sets timers if timeout was specified. +*************************************************************************/ +static ae_bool bbgd_entryprepareleafs(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdsubproblem* s, + bbgdstate* state, + ae_state *_state) +{ + ae_bool done; + ae_int_t n; + ae_int_t i; + ae_int_t choiceidx; + ae_int_t branchidx; + double v; + double vcostup; + double vcostdown; + double vscore; + double vmid; + double branchscore; + double maxinterr; + ae_int_t leaf0; + ae_int_t leaf1; + ae_int_t restartidx; + ae_int_t cntreliable; + ae_int_t cntunreliable; + ae_int_t cntchosen; + ae_bool isreliable; + ae_bool result; + + + done = ae_false; + n = s->n; + ae_assert(s->hasdualsolution, "BBGD: integrity check 391031 failed", _state); + + /* + * Entry initialization + */ + bbgd_entrypreparex(entry, front, state, ae_false, _state); + bbgd_subproblemcopy(s, s->leafid, &entry->parentsubproblem, _state); + + /* + * Our first attempt to split: split subproblems with significant integrality errors. + */ + if( !done&&!s->bestdualisintfeas ) + { + + /* + * Evaluate variables potential for branching + */ + ae_assert((state->branchingtype==0||state->branchingtype==1)||state->branchingtype==2, "BBGD: 167923 failed", _state); + maxinterr = (double)(0); + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + v = s->bestxdual.ptr.p_double[i]-(double)ae_ifloor(s->bestxdual.ptr.p_double[i], _state); + maxinterr = ae_maxreal(maxinterr, ae_minreal(v, (double)1-v, _state), _state); + } + } + ae_assert(ae_fp_less_eq(bbgd_alphaint,0.95), "BBGD: integrity check 943151 failed", _state); + iallocv(n, &entry->tmpreliablebranchidx, _state); + rallocv(n, &entry->tmpreliablebranchscore, _state); + iallocv(n, &entry->tmpunreliablebranchidx, _state); + rallocv(n, &entry->tmpunreliablebranchscore, _state); + cntreliable = 0; + cntunreliable = 0; + for(i=0; i<=n-1; i++) + { + + /* + * Skip non-integral variables and variables with integrality error below fraction of MaxIntErr + */ + if( !state->isintegral.ptr.p_bool[i] ) + { + continue; + } + v = s->bestxdual.ptr.p_double[i]-(double)ae_ifloor(s->bestxdual.ptr.p_double[i], _state); + if( ae_fp_less(ae_minreal(v, (double)1-v, _state),bbgd_alphaint*maxinterr) ) + { + continue; + } + + /* + * Evaluate variable potential, add to one of lists + */ + vscore = ae_minreal(v, (double)1-v, _state); + isreliable = ae_true; + if( state->branchingtype==1||state->branchingtype==2 ) + { + vcostup = state->globalpseudocostup; + vcostdown = state->globalpseudocostdown; + if( state->pseudocostscntup.ptr.p_int[i]>=state->krel ) + { + vcostup = state->pseudocostsup.ptr.p_double[i]; + } + else + { + isreliable = ae_false; + } + if( state->pseudocostscntdown.ptr.p_int[i]>=state->krel ) + { + vcostdown = state->pseudocostsdown.ptr.p_double[i]; + } + else + { + isreliable = ae_false; + } + vscore = ((double)1-state->pseudocostmu)*ae_minreal(v*vcostdown, ((double)1-v)*vcostup, _state)+state->pseudocostmu*ae_maxreal(v*vcostdown, ((double)1-v)*vcostup, _state); + } + ae_assert(ae_fp_greater_eq(vscore,(double)(0)), "BBGD: 230640 failed", _state); + if( isreliable ) + { + igrowappendv(cntreliable+1, &entry->tmpreliablebranchidx, i, _state); + rgrowappendv(cntreliable+1, &entry->tmpreliablebranchscore, -vscore, _state); + cntreliable = cntreliable+1; + } + else + { + igrowappendv(cntunreliable+1, &entry->tmpunreliablebranchidx, i, _state); + rgrowappendv(cntunreliable+1, &entry->tmpunreliablebranchscore, -vscore, _state); + cntunreliable = cntunreliable+1; + } + } + ae_assert(cntreliable+cntunreliable>0, "BBGD: integrity check 982152 failed", _state); + tagsortmiddleri(&entry->tmpreliablebranchscore, &entry->tmpreliablebranchidx, 0, cntreliable, _state); + tagsortmiddleri(&entry->tmpunreliablebranchscore, &entry->tmpunreliablebranchidx, 0, cntunreliable, _state); + + /* + * Depending on branch strategy, generate a list of candidates for the evaluation + */ + iallocv(n, &entry->tmpchosenbranchidx, _state); + rallocv(n, &entry->tmpchosenbranchscore, _state); + cntchosen = 0; + if( state->branchingtype==0||state->branchingtype==1 ) + { + if( cntreliable>0&&(cntchosen==0||ae_fp_greater(-entry->tmpreliablebranchscore.ptr.p_double[0],entry->tmpchosenbranchscore.ptr.p_double[0])) ) + { + entry->tmpchosenbranchidx.ptr.p_int[0] = entry->tmpreliablebranchidx.ptr.p_int[0]; + entry->tmpchosenbranchscore.ptr.p_double[0] = -entry->tmpreliablebranchscore.ptr.p_double[0]; + cntchosen = 1; + } + if( cntunreliable>0&&(cntchosen==0||ae_fp_greater(-entry->tmpunreliablebranchscore.ptr.p_double[0],entry->tmpchosenbranchscore.ptr.p_double[0])) ) + { + entry->tmpchosenbranchidx.ptr.p_int[0] = entry->tmpunreliablebranchidx.ptr.p_int[0]; + entry->tmpchosenbranchscore.ptr.p_double[0] = -entry->tmpunreliablebranchscore.ptr.p_double[0]; + cntchosen = 1; + } + } + if( state->branchingtype==2 ) + { + for(i=0; i<=ae_minint(cntreliable, state->kevalreliable, _state)-1; i++) + { + igrowappendv(cntchosen+1, &entry->tmpchosenbranchidx, entry->tmpreliablebranchidx.ptr.p_int[i], _state); + rgrowappendv(cntchosen+1, &entry->tmpchosenbranchscore, -entry->tmpreliablebranchscore.ptr.p_double[i], _state); + cntchosen = cntchosen+1; + } + for(i=0; i<=ae_minint(cntunreliable, state->kevalunreliable, _state)-1; i++) + { + igrowappendv(cntchosen+1, &entry->tmpchosenbranchidx, entry->tmpunreliablebranchidx.ptr.p_int[i], _state); + rgrowappendv(cntchosen+1, &entry->tmpchosenbranchscore, -entry->tmpunreliablebranchscore.ptr.p_double[i], _state); + cntchosen = cntchosen+1; + } + } + ae_assert(cntchosen>0, "BBGD: 269713 failed", _state); + + /* + * Append new subproblems to the group + */ + for(choiceidx=0; choiceidx<=cntchosen-1; choiceidx++) + { + branchidx = entry->tmpchosenbranchidx.ptr.p_int[choiceidx]; + leaf0 = weakatomicfetchadd(&state->nextleafid, 1, _state); + leaf1 = weakatomicfetchadd(&state->nextleafid, 1, _state); + if( state->dotrace ) + { + ae_trace("> branching %8dP on var %8d:", + (int)(s->leafid), + (int)(branchidx)); + } + bbgd_subproblemcopyasunsolved(s, leaf0, &entry->tmpsubproblem, _state); + entry->tmpsubproblem.branchbucket = 2*choiceidx+0; + entry->tmpsubproblem.parentfdual = s->bestfdual; + entry->tmpsubproblem.branchvar = branchidx; + entry->tmpsubproblem.branchval = s->bestxdual.ptr.p_double[branchidx]; + rcopyv(n, &s->bestxdual, &entry->tmpsubproblem.x0, _state); + entry->tmpsubproblem.x0.ptr.p_double[branchidx] = (double)(ae_ifloor(s->bestxdual.ptr.p_double[branchidx], _state)); + entry->tmpsubproblem.bndu.ptr.p_double[branchidx] = entry->tmpsubproblem.x0.ptr.p_double[branchidx]; + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, ae_false, &entry->solutions, _state); + for(restartidx=0; restartidx<=state->nmultistarts-1; restartidx++) + { + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, restartidx>0, &entry->spqueue, _state); + } + if( state->dotrace ) + { + ae_trace(" creating %8dP (x<=%0.2e)", + (int)(entry->tmpsubproblem.leafid), + (double)(entry->tmpsubproblem.bndu.ptr.p_double[branchidx])); + } + bbgd_subproblemcopyasunsolved(s, leaf1, &entry->tmpsubproblem, _state); + entry->tmpsubproblem.branchbucket = 2*choiceidx+1; + entry->tmpsubproblem.parentfdual = s->bestfdual; + entry->tmpsubproblem.branchvar = branchidx; + entry->tmpsubproblem.branchval = s->bestxdual.ptr.p_double[branchidx]; + rcopyv(n, &s->bestxdual, &entry->tmpsubproblem.x0, _state); + entry->tmpsubproblem.x0.ptr.p_double[branchidx] = (double)(ae_iceil(s->bestxdual.ptr.p_double[branchidx], _state)); + entry->tmpsubproblem.bndl.ptr.p_double[branchidx] = entry->tmpsubproblem.x0.ptr.p_double[branchidx]; + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, ae_false, &entry->solutions, _state); + for(restartidx=0; restartidx<=state->nmultistarts-1; restartidx++) + { + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, restartidx>0, &entry->spqueue, _state); + } + if( state->dotrace ) + { + ae_trace(" and %8dP (x>=%0.2e)", + (int)(entry->tmpsubproblem.leafid), + (double)(entry->tmpsubproblem.bndl.ptr.p_double[branchidx])); + } + if( state->dotrace ) + { + ae_trace("\n"); + } + } + entry->maxsubsolvers = ae_minint(ae_obj_array_get_length(&entry->spqueue), state->maxsubsolvers, _state); + + /* + * Splitting on integer variable is done. + */ + done = ae_true; + } + + /* + * Another option spatial splitting between worst and dual solutions (used for non-convex problems with multistarts) + */ + if( (!done&&s->hasdualsolution)&&ae_fp_greater(ae_fabs(s->bestfdual-s->worstfdual, _state),state->pdgap*rmaxabs2(state->ffdual, (double)(1), _state)) ) + { + + /* + * Select variable with the highest distance between worst and dual solutions + */ + branchidx = -1; + branchscore = (double)(0); + vmid = (double)(0); + for(i=0; i<=n-1; i++) + { + vscore = ae_fabs(s->bestxdual.ptr.p_double[i]-s->worstxdual.ptr.p_double[i], _state)/state->s.ptr.p_double[i]; + if( branchidx<0||ae_fp_greater(vscore,branchscore) ) + { + branchidx = i; + branchscore = vscore; + vmid = 0.5*(s->bestxdual.ptr.p_double[i]+s->worstxdual.ptr.p_double[i]); + } + } + ae_assert(branchidx>=0, "BBGD: integrity check 137104 failed", _state); + if( ae_fp_greater(branchscore,(double)(0)) ) + { + + /* + * Append new subproblems to the group + */ + if( state->dotrace ) + { + ae_trace("> spatially branching %8dP on var %8d (|x_worst-x_dual|=%0.2e):", + (int)(s->leafid), + (int)(branchidx), + (double)(ae_fabs(s->bestxdual.ptr.p_double[branchidx]-s->worstxdual.ptr.p_double[branchidx], _state))); + } + leaf0 = weakatomicfetchadd(&state->nextleafid, 1, _state); + leaf1 = weakatomicfetchadd(&state->nextleafid, 1, _state); + bbgd_subproblemcopyasunsolved(s, leaf0, &entry->tmpsubproblem, _state); + entry->tmpsubproblem.branchbucket = 0; + entry->tmpsubproblem.parentfdual = s->bestfdual; + entry->tmpsubproblem.branchvar = branchidx; + entry->tmpsubproblem.branchval = vmid; + if( ae_fp_less_eq(s->bestxdual.ptr.p_double[branchidx],vmid) ) + { + rcopyv(n, &s->bestxdual, &entry->tmpsubproblem.x0, _state); + } + else + { + rcopyv(n, &s->worstxdual, &entry->tmpsubproblem.x0, _state); + } + entry->tmpsubproblem.bndu.ptr.p_double[branchidx] = rcase2(state->isintegral.ptr.p_bool[i], (double)(ae_ifloor(vmid, _state)), vmid, _state); + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, ae_false, &entry->solutions, _state); + for(restartidx=0; restartidx<=state->nmultistarts-1; restartidx++) + { + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, restartidx>0, &entry->spqueue, _state); + } + if( state->dotrace ) + { + ae_trace(" creating %8dP (x<=%0.2e)", + (int)(entry->tmpsubproblem.leafid), + (double)(entry->tmpsubproblem.bndu.ptr.p_double[branchidx])); + } + bbgd_subproblemcopyasunsolved(s, leaf1, &entry->tmpsubproblem, _state); + entry->tmpsubproblem.branchbucket = 1; + entry->tmpsubproblem.parentfdual = s->bestfdual; + entry->tmpsubproblem.branchvar = branchidx; + entry->tmpsubproblem.branchval = vmid; + if( ae_fp_greater_eq(s->bestxdual.ptr.p_double[branchidx],vmid) ) + { + rcopyv(n, &s->bestxdual, &entry->tmpsubproblem.x0, _state); + } + else + { + rcopyv(n, &s->worstxdual, &entry->tmpsubproblem.x0, _state); + } + entry->tmpsubproblem.bndl.ptr.p_double[branchidx] = rcase2(state->isintegral.ptr.p_bool[i], (double)(ae_ifloor(vmid, _state)+1), vmid, _state); + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, ae_false, &entry->solutions, _state); + for(restartidx=0; restartidx<=state->nmultistarts-1; restartidx++) + { + bbgd_subproblemappendcopytoarray(&entry->tmpsubproblem, state, restartidx>0, &entry->spqueue, _state); + } + if( state->dotrace ) + { + ae_trace(" and %8dP (x>=%0.2e)\n", + (int)(entry->tmpsubproblem.leafid), + (double)(entry->tmpsubproblem.bndl.ptr.p_double[branchidx])); + } + entry->maxsubsolvers = ae_minint(ae_obj_array_get_length(&entry->spqueue), state->maxsubsolvers, _state); + + /* + * Splitting on integer variable is done. + */ + done = ae_true; + } + } + + /* + * Done or not done + */ + result = done; + return result; +} + + +/************************************************************************* +Prepares the front entry generating ready to run instance with empty +subproblems queue, empty solutions list, and maxsubsolvers=1. + +The caller must generate subproblems as necessary for that node type, set +up initial state of the solutions list and set maxsubsolvers as it sees +fit. + +Sets timers if timeout was specified. +*************************************************************************/ +static void bbgd_entrypreparex(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdstate* state, + ae_bool isroot, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdsubproblem *subproblem; + ae_smart_ptr _subproblem; + bbgdfrontsubsolver *subsolver; + ae_smart_ptr _subsolver; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + ae_assert(front->frontmode==bbgd_ftroot||front->frontmode==bbgd_ftdynamic, "BBGD: 776046 failed", _state); + entry->isrootentry = isroot; + entry->entrystatus = bbgd_streadytorun; + entry->addstatussolutionsaggregated = ae_false; + entry->addstatusdecisionsmade = ae_false; + entry->fathomroot = ae_true; + entry->fathomchild0 = ae_true; + entry->fathomchild1 = ae_true; + ae_weak_store_release(&entry->entrylock, 0); + entry->hastimeout = state->timeout>0; + if( entry->hastimeout ) + { + entry->timeout = ae_round((double)state->timeout-stimergetmsrunning(&state->timerglobal, _state), _state); + stimerinit(&entry->timerlocal, _state); + stimerstart(&entry->timerlocal, _state); + } + + /* + * Generate subproblem queue + */ + while(ae_obj_array_get_length(&entry->spqueue)>0) + { + ae_obj_array_pop_transfer(&entry->spqueue, &_subproblem, _state); + ae_shared_pool_recycle(&state->sppool, &_subproblem, _state); + } + entry->maxsubsolvers = 1; + + /* + * Clear subsolver list + */ + while(ae_obj_array_get_length(&entry->subsolvers)>0) + { + ae_obj_array_pop_transfer(&entry->subsolvers, &_subsolver, _state); + ae_shared_pool_recycle(&state->subsolverspool, &_subsolver, _state); + } + + /* + * Clear solutions list + */ + while(ae_obj_array_get_length(&entry->solutions)>0) + { + ae_obj_array_pop_transfer(&entry->solutions, &_subproblem, _state); + ae_shared_pool_recycle(&state->sppool, &_subproblem, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Prepare subsolver for the front entry and specific subproblem to solve. +*************************************************************************/ +static void bbgd_entrypreparesubsolver(bbgdstate* state, + bbgdfront* front, + bbgdfrontentry* entry, + const bbgdsubproblem* subproblem, + ae_bool isroot, + bbgdfrontsubsolver* subsolver, + ae_state *_state) +{ + + + ae_assert((front->frontmode==bbgd_ftroot&&isroot)||(front->frontmode==bbgd_ftdynamic&&!isroot), "BBGD: 415212 failed", _state); + ae_vector_set_length(&subsolver->rstate.ia, 1+1, _state); + ae_vector_set_length(&subsolver->rstate.ba, 1+1, _state); + subsolver->rstate.stage = -1; + bbgd_subproblemcopy(subproblem, subproblem->leafid, &subsolver->subproblem, _state); + subsolver->subsolverstatus = bbgd_streadytorun; +} + + +/************************************************************************* +Run subproblem solver +*************************************************************************/ +static ae_bool bbgd_subsolverrun(bbgdstate* state, + bbgdfront* front, + bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + ae_state *_state) +{ + ae_int_t i; + ae_int_t terminationtype; + ae_bool uselock; + ae_bool done; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( subsolver->rstate.stage>=0 ) + { + i = subsolver->rstate.ia.ptr.p_int[0]; + terminationtype = subsolver->rstate.ia.ptr.p_int[1]; + uselock = subsolver->rstate.ba.ptr.p_bool[0]; + done = subsolver->rstate.ba.ptr.p_bool[1]; + } + else + { + i = -909; + terminationtype = 81; + uselock = ae_true; + done = ae_false; + } + if( subsolver->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + + /* + * Init + */ + uselock = ae_true; + ae_assert(subsolver->subsolverstatus==bbgd_streadytorun&&((front->frontmode==bbgd_ftdynamic&&subsolver->subproblem.branchbucket>=0)||(front->frontmode==bbgd_ftroot&&subsolver->subproblem.branchbucket==-1)), "BBGD: integrity check 589220 failed", _state); + + /* + * Handle various objective types + */ + done = ae_false; + if( state->objtype==1&&state->nnlc==0 ) + { + bbgd_solveqpnode(entry, subsolver, state, &subsolver->subproblem.x0, &subsolver->subproblem.bndl, &subsolver->subproblem.bndu, &entry->solutions, ae_maxint(subsolver->subproblem.branchbucket, 0, _state), uselock, _state); + if( entry->hastimeout&&ae_fp_greater(stimergetmsrunning(&entry->timerlocal, _state),(double)(entry->timeout)) ) + { + subsolver->subsolverstatus = bbgd_sttimeout; + result = ae_false; + return result; + } + subsolver->subsolverstatus = bbgd_stsolved; + done = ae_true; + } + if( done ) + { + goto lbl_1; + } + + /* + * Generic NLP subproblem is solved. + */ + minnlccreatebuf(subsolver->subproblem.n, &subsolver->subproblem.x0, &subsolver->nlpsubsolver, _state); + minnlcsetscale(&subsolver->nlpsubsolver, &state->s, _state); + minnlcsetbc(&subsolver->nlpsubsolver, &subsolver->subproblem.bndl, &subsolver->subproblem.bndu, _state); + minnlcsetlc2(&subsolver->nlpsubsolver, &state->rawa, &state->rawal, &state->rawau, state->lccnt, _state); + minnlcsetnlc2(&subsolver->nlpsubsolver, &state->nl, &state->nu, state->nnlc, _state); + minnlcsetprotocolv2s(&subsolver->nlpsubsolver, _state); + if( subsolver->subproblem.branchbucket>=0 ) + { + minnlcsetcond3(&subsolver->nlpsubsolver, state->epsf, state->epsx, state->nonrootmaxitsconst+state->nonrootmaxitslin*subsolver->subproblem.n, _state); + minnlcsetfsqpadditsforctol(&subsolver->nlpsubsolver, state->nonrootadditsforfeasibility, state->ctol, _state); + } + + /* + * Solve NLP relaxation + */ +lbl_3: + if( !minnlciteration(&subsolver->nlpsubsolver, _state) ) + { + goto lbl_4; + } + if( subsolver->nlpsubsolver.requesttype==-1 ) + { + goto lbl_5; + } + subsolver->subsolverstatus = bbgd_stwaitingforrcomm; + subsolver->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: +lbl_5: + if( entry->hastimeout&&ae_fp_greater(stimergetmsrunning(&entry->timerlocal, _state),(double)(entry->timeout)) ) + { + subsolver->subsolverstatus = bbgd_sttimeout; + result = ae_false; + return result; + } + goto lbl_3; +lbl_4: + minnlcresultsbuf(&subsolver->nlpsubsolver, &subsolver->xsol, &subsolver->nlprep, _state); + + /* + * Analyze solution + */ + bbgd_analyzenlpsolutionandenforceintegrality(entry, &subsolver->xsol, &subsolver->nlprep, state, &entry->solutions, ae_maxint(subsolver->subproblem.branchbucket, 0, _state), uselock, _state); + subsolver->subsolverstatus = bbgd_stsolved; + done = ae_true; +lbl_1: + ae_assert(done, "BBGD: integrity check 659230 failed", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + subsolver->rstate.ia.ptr.p_int[0] = i; + subsolver->rstate.ia.ptr.p_int[1] = terminationtype; + subsolver->rstate.ba.ptr.p_bool[0] = uselock; + subsolver->rstate.ba.ptr.p_bool[1] = done; + return result; +} + + +/************************************************************************* +Aggregates data from the Solutions[] array into RootProblem or +ChildSubproblem0/ChildSubproblem1, depending on entry type. Updates global +statistics (pseudocosts etc). + + +Uses entry data to update global statistics in State: +* primal bound +* pseudocosts + +This function must be called on all solved entries, prior to calling +EntryDecideOnFathoming() for all solved entries. + +update should be performed prior to feeding data from the entry into +State with EntryPushSolution() or EntryTryPushAndDive(). +*************************************************************************/ +static void bbgd_entryaggregateandupdateglobalstats(bbgdfrontentry* entry, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_int_t solcnt; + double v; + double vfrac; + double vup; + double vdown; + ae_int_t cntsimplebranch; + ae_int_t cnttighten; + ae_int_t infeassolidx; + ae_int_t bestbranch; + ae_int_t besttighten; + ae_int_t bestbranchsolidx; + ae_int_t besttightensolidx; + double bestbranchlowerscore; + double bestbranchscore; + double besttightenlowerscore; + ae_bool isinfeasible; + double vscore; + double vrnddn; + double vrndup; + bbgdsubproblem *sol; + ae_smart_ptr _sol; + bbgdsubproblem *sol0; + ae_smart_ptr _sol0; + bbgdsubproblem *sol1; + ae_smart_ptr _sol1; + + ae_frame_make(_state, &_frame_block); + memset(&_sol, 0, sizeof(_sol)); + memset(&_sol0, 0, sizeof(_sol0)); + memset(&_sol1, 0, sizeof(_sol1)); + ae_smart_ptr_init(&_sol, (void**)&sol, ae_false, _state, ae_true); + ae_smart_ptr_init(&_sol0, (void**)&sol0, ae_false, _state, ae_true); + ae_smart_ptr_init(&_sol1, (void**)&sol1, ae_false, _state, ae_true); + + ae_assert(entry->entrystatus==bbgd_stsolved&&!entry->addstatussolutionsaggregated, "BBGD: integrity check 828957 failed", _state); + solcnt = ae_obj_array_get_length(&entry->solutions); + + /* + * Update primal bound + */ + for(i=0; i<=solcnt-1; i++) + { + ae_obj_array_get(&entry->solutions, i, &_sol, _state); + if( sol->hasprimalsolution ) + { + ae_assert(sol->n==state->n, "BBGD: integrity check 832958 failed", _state); + if( !state->hasprimalsolution||ae_fp_less(sol->fprim,state->fprim) ) + { + rcopyallocv(sol->n, &sol->xprim, &state->xprim, _state); + state->fprim = sol->fprim; + state->hprim = sol->hprim; + state->hasprimalsolution = ae_true; + } + state->repnprimalcandidates = state->repnprimalcandidates+1; + } + } + + /* + * Update pseudocosts: + * * per-variable ones are always updated, for feasible and infeasible problems (in the latter case the global cost times penalty is used) + * * global pseudocosts are updated only when subproblem is feasible (to avoid updating them with their own value times penalty) + */ + if( !entry->isrootentry ) + { + for(i=0; i<=solcnt-1; i++) + { + ae_obj_array_get(&entry->solutions, i, &_sol, _state); + if( state->isintegral.ptr.p_bool[sol->branchvar] ) + { + ae_assert(sol->branchbucket>=0&&sol->branchbucketbranchbucket%2==0 ) + { + k = sol->branchvar; + v = sol->branchval; + vfrac = v-(double)ae_ifloor(v, _state); + vdown = (double)(0); + if( sol->hasdualsolution ) + { + vdown = ae_maxreal(sol->bestfdual-sol->parentfdual, (double)(0), _state)/ae_maxreal(vfrac, ae_machineepsilon, _state); + } + if( !sol->hasdualsolution&&state->globalpseudocostcntdown>0 ) + { + vdown = state->pseudocostinfeaspenaly*state->globalpseudocostdown; + } + if( ae_fp_greater_eq(vdown,(double)(0))&&ae_fp_greater(vfrac,state->pseudocostminfrac) ) + { + state->pseudocostsdown.ptr.p_double[k] = (state->pseudocostsdown.ptr.p_double[k]*(double)state->pseudocostscntdown.ptr.p_int[k]+vdown)/(double)(state->pseudocostscntdown.ptr.p_int[k]+1); + state->pseudocostscntdown.ptr.p_int[k] = state->pseudocostscntdown.ptr.p_int[k]+1; + } + if( (ae_fp_greater_eq(vdown,(double)(0))&&ae_fp_greater(vfrac,state->pseudocostminfrac))&&sol->hasdualsolution ) + { + state->globalpseudocostdown = (state->globalpseudocostdown*(double)state->globalpseudocostcntdown+vdown)/(double)(state->globalpseudocostcntdown+1); + state->globalpseudocostcntdown = state->globalpseudocostcntdown+1; + } + } + if( sol->branchbucket%2==1 ) + { + k = sol->branchvar; + v = sol->branchval; + vfrac = (double)ae_iceil(v, _state)-v; + vup = (double)(0); + if( sol->hasdualsolution ) + { + vup = ae_maxreal(sol->bestfdual-sol->parentfdual, (double)(0), _state)/ae_maxreal(vfrac, ae_machineepsilon, _state); + } + if( !sol->hasdualsolution&&state->globalpseudocostcntup>0 ) + { + vup = state->pseudocostinfeaspenaly*state->globalpseudocostup; + } + if( ae_fp_greater_eq(vup,(double)(0))&&ae_fp_greater(vfrac,state->pseudocostminfrac) ) + { + state->pseudocostsup.ptr.p_double[k] = (state->pseudocostsup.ptr.p_double[k]*(double)state->pseudocostscntup.ptr.p_int[k]+vup)/(double)(state->pseudocostscntup.ptr.p_int[k]+1); + state->pseudocostscntup.ptr.p_int[k] = state->pseudocostscntup.ptr.p_int[k]+1; + } + if( (ae_fp_greater_eq(vup,(double)(0))&&ae_fp_greater(vfrac,state->pseudocostminfrac))&&sol->hasdualsolution ) + { + state->globalpseudocostup = (state->globalpseudocostup*(double)state->globalpseudocostcntup+vup)/(double)(state->globalpseudocostcntup+1); + state->globalpseudocostcntup = state->globalpseudocostcntup+1; + } + } + } + } + } + + /* + * Select the most promising branching across ones proposed. + * Upload to RootProblem/ChildSubproblem0/ChildSubproblem1 + */ + if( entry->isrootentry ) + { + + /* + * Root problem being solved, upload results to RootProblem + */ + ae_assert(solcnt==1, "BBGD: 587200 failed", _state); + ae_obj_array_get(&entry->solutions, 0, &_sol, _state); + bbgd_subproblemcopy(sol, sol->leafid, &entry->rootproblem, _state); + } + else + { + + /* + * Branching is over, analyze results + */ + ae_assert(solcnt%2==0, "BBGD: 599208 failed", _state); + ae_assert(state->convexityflag>=0, "BBGD: 701838 failed", _state); + cntsimplebranch = 0; + cnttighten = 0; + isinfeasible = ae_false; + infeassolidx = -1; + bestbranch = -1; + bestbranchsolidx = -1; + bestbranchscore = (double)(0); + bestbranchlowerscore = (double)(0); + besttighten = -1; + besttightensolidx = -1; + besttightenlowerscore = (double)(0); + for(i=0; i<=solcnt/2-1; i++) + { + ae_obj_array_get(&entry->solutions, 2*i+0, &_sol0, _state); + ae_obj_array_get(&entry->solutions, 2*i+1, &_sol1, _state); + ae_assert(sol0->branchbucket>=0&&sol0->branchbucketbranchbucket==sol0->branchbucket+1, "BBGD: 715532 failed", _state); + ae_assert(sol0->branchvar==sol1->branchvar, "BBGD: 715533 failed", _state); + if( !sol0->hasdualsolution&&!sol1->hasdualsolution ) + { + + /* + * Branching on the variable produced two infeasible problems: good opportunity to prune the entire branch! + */ + infeassolidx = i; + isinfeasible = ae_true; + continue; + } + if( sol0->hasdualsolution&&sol1->hasdualsolution ) + { + + /* + * Both leafs are feasible, compute score for the branching decision. + * + * The score handles both convex problems (Sol0.BestFDual>Sol0.ParentFDual) and non-convex ones, where + * introducing a branching constraint suddenly moves us to a better extremum. Such branchings are given + * higher priority by using NonconvexityGain>1. + */ + vrnddn = ae_maxreal(sol0->bestfdual-sol0->parentfdual, state->nonconvexitygain*(sol0->parentfdual-sol0->bestfdual), _state); + vrndup = ae_maxreal(sol1->bestfdual-sol1->parentfdual, state->nonconvexitygain*(sol1->parentfdual-sol1->bestfdual), _state); + vscore = ((double)1-state->pseudocostmu)*ae_minreal(vrnddn, vrndup, _state)+state->pseudocostmu*ae_maxreal(vrnddn, vrndup, _state); + if( bestbranch<0||ae_fp_greater(vscore,bestbranchscore) ) + { + bestbranch = sol0->branchvar; + bestbranchsolidx = i; + bestbranchscore = vscore; + bestbranchlowerscore = ae_minreal(vrnddn, vrndup, _state); + } + cntsimplebranch = cntsimplebranch+1; + continue; + } + + /* + * Branching produced one feasible and one infeasible problem: we can tighten a variable. + * + * Non-convexity is handled similarly to the 'both leafs are feasible' case. + */ + if( sol0->hasdualsolution ) + { + vscore = ae_maxreal(sol0->bestfdual-sol0->parentfdual, state->nonconvexitygain*(sol0->parentfdual-sol0->bestfdual), _state); + if( besttighten<0||ae_fp_greater(vscore,besttightenlowerscore) ) + { + besttighten = sol0->branchvar; + besttightensolidx = i; + besttightenlowerscore = vscore; + } + } + else + { + vscore = ae_maxreal(sol1->bestfdual-sol1->parentfdual, state->nonconvexitygain*(sol1->parentfdual-sol1->bestfdual), _state); + if( besttighten<0||ae_fp_greater(vscore,besttightenlowerscore) ) + { + besttighten = sol1->branchvar; + besttightensolidx = i; + besttightenlowerscore = vscore; + } + } + cnttighten = cnttighten+1; + } + ae_assert(state->convexityflag>=0, "BBGD: 783600", _state); + if( isinfeasible ) + { + + /* + * The problem is infeasible + */ + ae_obj_array_get(&entry->solutions, 2*infeassolidx+0, &_sol0, _state); + ae_obj_array_get(&entry->solutions, 2*infeassolidx+1, &_sol1, _state); + bbgd_subproblemcopy(sol0, sol0->leafid, &entry->childsubproblem0, _state); + bbgd_subproblemcopy(sol1, sol1->leafid, &entry->childsubproblem1, _state); + } + else + { + if( cnttighten>0 ) + { + + /* + * At least one of variables can be tightened + */ + ae_obj_array_get(&entry->solutions, 2*besttightensolidx+0, &_sol0, _state); + ae_obj_array_get(&entry->solutions, 2*besttightensolidx+1, &_sol1, _state); + bbgd_subproblemcopy(sol0, sol0->leafid, &entry->childsubproblem0, _state); + bbgd_subproblemcopy(sol1, sol1->leafid, &entry->childsubproblem1, _state); + } + else + { + + /* + * Basic split + */ + ae_assert(cntsimplebranch>0, "BBGD: 809607", _state); + ae_obj_array_get(&entry->solutions, 2*bestbranchsolidx+0, &_sol0, _state); + ae_obj_array_get(&entry->solutions, 2*bestbranchsolidx+1, &_sol1, _state); + bbgd_subproblemcopy(sol0, sol0->leafid, &entry->childsubproblem0, _state); + bbgd_subproblemcopy(sol1, sol1->leafid, &entry->childsubproblem1, _state); + } + } + } + entry->addstatussolutionsaggregated = ae_true; + + /* + * Update subproblem counts + */ + state->repnsubproblems = state->repnsubproblems+ae_obj_array_get_length(&entry->solutions)*state->nmultistarts; + state->repntreenodes = state->repntreenodes+icase2(entry->isrootentry, 1, 2, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Decides on fathoming RootSubproblem or Child0/1, depending on IsRootEntry. + +Sets corresponding flags, but does not push solution and does not perform +diving. + +This function must be called on all solved entries after calling +EntryAggregateAndUpdateGlobalStats(), prior to to feeding data from the +entry into State with EntryPushSolution() or EntryTryPushAndDive(). +*************************************************************************/ +static void bbgd_entrydecideonfathoming(bbgdfrontentry* entry, + bbgdstate* state, + ae_state *_state) +{ + + + ae_assert((entry->entrystatus==bbgd_stsolved&&entry->addstatussolutionsaggregated)&&!entry->addstatusdecisionsmade, "BBGD: integrity check 902210 failed", _state); + if( entry->isrootentry ) + { + entry->fathomroot = bbgd_subproblemcanfathom(&entry->rootproblem, state, _state); + } + else + { + entry->fathomchild0 = bbgd_subproblemcanfathom(&entry->childsubproblem0, state, _state); + entry->fathomchild1 = bbgd_subproblemcanfathom(&entry->childsubproblem1, state, _state); + } + entry->addstatusdecisionsmade = ae_true; +} + + +/************************************************************************* +Feeding solution from the entry to the end of the State.bbSubproblems[] +array. This function does not regrow the sorted part of bbSubproblems (heap). + +If at least one subproblem was added, the flag variable is set to true. +It is left unchanged otherwise. + +This function merely adds subproblems to the heap, it is assumed that they +were already scanned for primal solutions, pseudocosts, etc. +*************************************************************************/ +static void bbgd_entrypushsolution(const bbgdfrontentry* entry, + bbgdstate* state, + ae_bool* setonupdate, + ae_state *_state) +{ + + + ae_assert((entry->entrystatus==bbgd_stsolved&&entry->addstatussolutionsaggregated)&&entry->addstatusdecisionsmade, "BBGD: integrity check 863011 failed", _state); + if( entry->isrootentry ) + { + if( !entry->fathomroot ) + { + bbgd_pushsubproblemsolution(&entry->rootproblem, state, setonupdate, _state); + } + } + else + { + if( !entry->fathomchild0 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem0, state, setonupdate, _state); + } + if( !entry->fathomchild1 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem1, state, setonupdate, _state); + } + } +} + + +/************************************************************************* +Tries to perform diving by pushing the worst leaf to the heap (if feasible +and not fathomed) and configuring the entry to process the best leaf. + +If unsuccessful due to both leafs being infeasible/fathomed, returns +False and does not change entry state or the heap. There is no need to call +EntryPushSolution() in this case. + +If successful, the entry status is set to stReadyToRun and True is returned. + +This function merely adds subproblems to the heap, it is assumed that they +were already scanned for primal solutions, pseudocosts, etc. +*************************************************************************/ +static ae_bool bbgd_entrytrypushanddive(bbgdfrontentry* entry, + const bbgdfront* front, + bbgdstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t eligibleleafidx; + double eligibleleafdual; + ae_bool iseligibleleaf; + bbgdsubproblem *eligiblep; + ae_smart_ptr _eligiblep; + ae_bool bdummy; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&_eligiblep, 0, sizeof(_eligiblep)); + ae_smart_ptr_init(&_eligiblep, (void**)&eligiblep, ae_false, _state, ae_true); + + ae_assert(((entry->entrystatus==bbgd_stsolved&&entry->addstatussolutionsaggregated)&&entry->addstatusdecisionsmade)&&!entry->isrootentry, "BBGD: integrity check 905205 failed", _state); + eligibleleafidx = -1; + eligibleleafdual = ae_maxrealnumber; + ae_shared_pool_retrieve(&state->sppool, &_eligiblep, _state); + + /* + * Analyze leaf 0 + */ + iseligibleleaf = !entry->fathomchild0&&(eligibleleafidx<0||ae_fp_less(entry->childsubproblem0.dualbound,eligibleleafdual)); + if( iseligibleleaf ) + { + eligibleleafidx = 0; + eligibleleafdual = entry->childsubproblem0.dualbound; + bbgd_subproblemcopy(&entry->childsubproblem0, entry->childsubproblem0.leafid, eligiblep, _state); + } + + /* + * Analyze leaf 1 + */ + iseligibleleaf = !entry->fathomchild1&&(eligibleleafidx<0||ae_fp_less(entry->childsubproblem1.dualbound,eligibleleafdual)); + if( iseligibleleaf ) + { + eligibleleafidx = 1; + eligibleleafdual = entry->childsubproblem1.dualbound; + bbgd_subproblemcopy(&entry->childsubproblem1, entry->childsubproblem1.leafid, eligiblep, _state); + } + + /* + * Exit if no leaf is eligible + */ + if( eligibleleafidx<0 ) + { + if( !entry->fathomchild0 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem0, state, &bdummy, _state); + } + if( !entry->fathomchild1 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem1, state, &bdummy, _state); + } + if( state->dotrace ) + { + ae_trace("> no eligible leaves to continue diving, retrieving problem from the heap\n"); + } + ae_shared_pool_recycle(&state->sppool, &_eligiblep, _state); + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( state->dotrace ) + { + ae_trace("> diving into leaf %0d (subproblem %8dP)\n", + (int)(eligibleleafidx), + (int)(eligiblep->leafid)); + } + result = ae_true; + + /* + * Process eligible leaf, try to push ineligible one + * + * NOTE: this code has one small inefficiency - if eligible leaf does not + * need splitting (and hence diving), it decides to break the diving + * even if another one could be processed instead. + */ + if( eligibleleafidx==0 ) + { + if( !entry->fathomchild1 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem1, state, &bdummy, _state); + } + } + else + { + if( !entry->fathomchild0 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem0, state, &bdummy, _state); + } + } + if( !bbgd_entryprepareleafs(entry, front, eligiblep, state, _state) ) + { + if( eligibleleafidx==0 ) + { + if( !entry->fathomchild0 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem0, state, &bdummy, _state); + } + } + else + { + if( !entry->fathomchild1 ) + { + bbgd_pushsubproblemsolution(&entry->childsubproblem1, state, &bdummy, _state); + } + } + result = ae_false; + } + ae_shared_pool_recycle(&state->sppool, &_eligiblep, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Feeding solution of the subproblem to the end of the State.bbSubproblems[] +array. This function does not regrow the sorted part of bbSubproblems (heap). + +Intended to be used by EntryPushSolution(). +*************************************************************************/ +static void bbgd_pushsubproblemsolution(const bbgdsubproblem* subproblem, + bbgdstate* state, + ae_bool* setonupdate, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdsubproblem *p; + ae_smart_ptr _p; + + ae_frame_make(_state, &_frame_block); + memset(&_p, 0, sizeof(_p)); + ae_smart_ptr_init(&_p, (void**)&p, ae_false, _state, ae_true); + + ae_assert(subproblem->hasdualsolution, "BBGD: 096224 failed", _state); + ae_shared_pool_retrieve(&state->sppool, &_p, _state); + bbgd_subproblemcopy(subproblem, subproblem->leafid, p, _state); + ae_obj_array_append_transfer(&state->bbsubproblems, &_p, _state); + *setonupdate = ae_true; + ae_frame_leave(_state); +} + + +/************************************************************************* +Quick lightweight presolve for a QP subproblem. Saves presolved problem to +the Entry fields. + +Returns termination type: 0 for success, negative for failure (infeasibility +detected) +*************************************************************************/ +static ae_int_t bbgd_qpquickpresolve(const bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + /* Real */ const ae_vector* raws, + /* Real */ const ae_vector* rawxorigin, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + const sparsematrix* rawa, + ae_bool isupper, + /* Real */ const ae_vector* rawb, + ae_int_t n, + const sparsematrix* rawsparsec, + /* Real */ const ae_vector* rawcl, + /* Real */ const ae_vector* rawcu, + ae_int_t lccnt, + /* Integer */ const ae_vector* qpordering, + double eps, + ae_state *_state) +{ + ae_int_t npsv; + ae_int_t offs; + ae_int_t dstrow; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t ic; + ae_int_t jc; + double v; + double vi; + double vf; + double cmin; + double cmax; + double vscl; + ae_int_t result; + + + ae_assert(!isupper, "QPQuickPresolve: IsUpper=True is not implemented", _state); + result = 0; + + /* + * Copy box constraints to Subsolver.psvRawBndL/U + */ + rcopyallocv(n, rawbndl, &subsolver->psvrawbndl, _state); + rcopyallocv(n, rawbndu, &subsolver->psvrawbndu, _state); + + /* + * Analyze constraints to find forcing ones that fix variables at their bounds + */ + for(i=0; i<=lccnt-1; i++) + { + j0 = rawsparsec->ridx.ptr.p_int[i]; + j1 = rawsparsec->ridx.ptr.p_int[i+1]-1; + + /* + * Compute row normalzation factor for scaled coordinates + */ + vscl = 0.0; + for(jj=j0; jj<=j1; jj++) + { + v = rawsparsec->vals.ptr.p_double[jj]*raws->ptr.p_double[rawsparsec->idx.ptr.p_int[jj]]; + vscl = vscl+v*v; + } + vscl = (double)1/coalesce(ae_sqrt(vscl, _state), (double)(1), _state); + + /* + * Compute minimum and maximum row values + */ + cmin = (double)(0); + cmax = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + j = rawsparsec->idx.ptr.p_int[jj]; + v = rawsparsec->vals.ptr.p_double[jj]; + if( v>0.0 ) + { + cmin = cmin+v*subsolver->psvrawbndl.ptr.p_double[j]; + cmax = cmax+v*subsolver->psvrawbndu.ptr.p_double[j]; + } + if( v<0.0 ) + { + cmin = cmin+v*subsolver->psvrawbndu.ptr.p_double[j]; + cmax = cmax+v*subsolver->psvrawbndl.ptr.p_double[j]; + } + } + if( ae_isfinite(cmax, _state)&&ae_isfinite(rawcl->ptr.p_double[i], _state) ) + { + if( ae_fp_less(cmax,rawcl->ptr.p_double[i]-vscl*eps) ) + { + + /* + * constraint is infeasible beyond Eps + */ + result = -3; + return result; + } + if( ae_fp_less(cmax,rawcl->ptr.p_double[i]+vscl*eps) ) + { + + /* + * Constraint fixes its variables at values maximizing constraint value + */ + for(jj=j0; jj<=j1; jj++) + { + j = rawsparsec->idx.ptr.p_int[jj]; + v = rawsparsec->vals.ptr.p_double[jj]; + if( v>0.0 ) + { + subsolver->psvrawbndl.ptr.p_double[j] = subsolver->psvrawbndu.ptr.p_double[j]; + } + if( v<0.0 ) + { + subsolver->psvrawbndu.ptr.p_double[j] = subsolver->psvrawbndl.ptr.p_double[j]; + } + } + continue; + } + } + if( ae_isfinite(cmin, _state)&&ae_isfinite(rawcu->ptr.p_double[i], _state) ) + { + if( ae_fp_greater(cmin,rawcu->ptr.p_double[i]+vscl*eps) ) + { + + /* + * constraint is infeasible beyond Eps + */ + result = -3; + return result; + } + if( ae_fp_greater(cmin,rawcu->ptr.p_double[i]-vscl*eps) ) + { + + /* + * Constraint fixes its variables at values minimizing constraint value + */ + for(jj=j0; jj<=j1; jj++) + { + j = rawsparsec->idx.ptr.p_int[jj]; + v = rawsparsec->vals.ptr.p_double[jj]; + if( v>0.0 ) + { + subsolver->psvrawbndu.ptr.p_double[j] = subsolver->psvrawbndl.ptr.p_double[j]; + } + if( v<0.0 ) + { + subsolver->psvrawbndl.ptr.p_double[j] = subsolver->psvrawbndu.ptr.p_double[j]; + } + } + continue; + } + } + } + + /* + * Analyze fixed vars, compress S, Origin, variable bounds and linear term + */ + npsv = 0; + isetallocv(n+lccnt, -1, &subsolver->psvpackxyperm, _state); + isetallocv(n+lccnt, -1, &subsolver->psvunpackxyperm, _state); + rallocv(n, &subsolver->psvs, _state); + rallocv(n, &subsolver->psvxorigin, _state); + rallocv(n, &subsolver->psvbndl, _state); + rallocv(n, &subsolver->psvbndu, _state); + rallocv(n, &subsolver->psvb, _state); + rallocv(n, &subsolver->psvfixvals, _state); + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(subsolver->psvrawbndl.ptr.p_double[i], _state)&&ae_isfinite(subsolver->psvrawbndu.ptr.p_double[i], _state))&&subsolver->psvrawbndl.ptr.p_double[i]>subsolver->psvrawbndu.ptr.p_double[i] ) + { + result = -3; + return result; + } + if( (!ae_isfinite(subsolver->psvrawbndl.ptr.p_double[i], _state)||!ae_isfinite(subsolver->psvrawbndu.ptr.p_double[i], _state))||subsolver->psvrawbndl.ptr.p_double[i]psvrawbndu.ptr.p_double[i] ) + { + subsolver->psvunpackxyperm.ptr.p_int[npsv] = i; + subsolver->psvpackxyperm.ptr.p_int[i] = npsv; + subsolver->psvs.ptr.p_double[npsv] = raws->ptr.p_double[i]; + subsolver->psvxorigin.ptr.p_double[npsv] = rawxorigin->ptr.p_double[i]; + subsolver->psvbndl.ptr.p_double[npsv] = subsolver->psvrawbndl.ptr.p_double[i]; + subsolver->psvbndu.ptr.p_double[npsv] = subsolver->psvrawbndu.ptr.p_double[i]; + subsolver->psvb.ptr.p_double[npsv] = rawb->ptr.p_double[i]; + npsv = npsv+1; + } + else + { + subsolver->psvfixvals.ptr.p_double[i] = subsolver->psvrawbndl.ptr.p_double[i]; + } + } + subsolver->npsv = npsv; + if( npsv==0 ) + { + return result; + } + + /* + * Compress quadratic term + */ + subsolver->psva.n = npsv; + subsolver->psva.m = npsv; + iallocv(npsv+1, &subsolver->psva.ridx, _state); + offs = 0; + dstrow = 0; + subsolver->psva.ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + igrowv(offs+npsv, &subsolver->psva.idx, _state); + rgrowv(offs+npsv, &subsolver->psva.vals, _state); + j0 = rawa->ridx.ptr.p_int[i]; + j1 = rawa->uidx.ptr.p_int[i]-1; + ic = subsolver->psvpackxyperm.ptr.p_int[i]; + if( ic<0 ) + { + + /* + * I-th variable is fixed: products with this variable either update the linear term or the constant one (ignored for presolve). + * + * The diagonal term is implicitly ignored (JC>=0 is always evaluated to false). + */ + vi = subsolver->psvfixvals.ptr.p_double[i]-rawxorigin->ptr.p_double[i]; + for(jj=j0; jj<=j1; jj++) + { + j = rawa->idx.ptr.p_int[jj]; + v = rawa->vals.ptr.p_double[jj]; + jc = subsolver->psvpackxyperm.ptr.p_int[j]; + if( jc>=0 ) + { + subsolver->psvb.ptr.p_double[jc] = subsolver->psvb.ptr.p_double[jc]+v*vi; + } + } + } + else + { + + /* + * I-th variable is non-fixed: products with this variable either update the quadratic term or the linear one + */ + for(jj=j0; jj<=j1; jj++) + { + j = rawa->idx.ptr.p_int[jj]; + v = rawa->vals.ptr.p_double[jj]; + jc = subsolver->psvpackxyperm.ptr.p_int[j]; + if( jc>=0 ) + { + subsolver->psva.idx.ptr.p_int[offs] = jc; + subsolver->psva.vals.ptr.p_double[offs] = v; + offs = offs+1; + } + else + { + subsolver->psvb.ptr.p_double[ic] = subsolver->psvb.ptr.p_double[ic]+v*(subsolver->psvfixvals.ptr.p_double[j]-rawxorigin->ptr.p_double[j]); + } + } + subsolver->psva.ridx.ptr.p_int[dstrow+1] = offs; + dstrow = dstrow+1; + } + } + sparsecreatecrsinplace(&subsolver->psva, _state); + + /* + * Compress linear constraints + */ + subsolver->psvlccnt = 0; + if( lccnt>0 ) + { + rsetallocv(lccnt, _state->v_neginf, &subsolver->psvcl, _state); + rsetallocv(lccnt, _state->v_posinf, &subsolver->psvcu, _state); + subsolver->psvsparsec.m = 0; + subsolver->psvsparsec.n = npsv; + iallocv(lccnt+1, &subsolver->psvsparsec.ridx, _state); + subsolver->psvsparsec.ridx.ptr.p_int[0] = 0; + for(i=0; i<=lccnt-1; i++) + { + vf = 0.0; + offs = subsolver->psvsparsec.ridx.ptr.p_int[subsolver->psvlccnt]; + igrowv(offs+npsv, &subsolver->psvsparsec.idx, _state); + rgrowv(offs+npsv, &subsolver->psvsparsec.vals, _state); + j0 = rawsparsec->ridx.ptr.p_int[i]; + j1 = rawsparsec->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = rawsparsec->idx.ptr.p_int[jj]; + v = rawsparsec->vals.ptr.p_double[jj]; + jc = subsolver->psvpackxyperm.ptr.p_int[j]; + if( jc>=0 ) + { + subsolver->psvsparsec.idx.ptr.p_int[offs] = jc; + subsolver->psvsparsec.vals.ptr.p_double[offs] = v; + offs = offs+1; + } + else + { + vf = vf+subsolver->psvfixvals.ptr.p_double[j]*v; + } + } + if( offs==subsolver->psvsparsec.ridx.ptr.p_int[subsolver->psvlccnt] ) + { + continue; + } + subsolver->psvsparsec.ridx.ptr.p_int[subsolver->psvlccnt+1] = offs; + if( ae_isfinite(rawcl->ptr.p_double[i], _state) ) + { + subsolver->psvcl.ptr.p_double[subsolver->psvlccnt] = rawcl->ptr.p_double[i]-vf; + } + if( ae_isfinite(rawcu->ptr.p_double[i], _state) ) + { + subsolver->psvcu.ptr.p_double[subsolver->psvlccnt] = rawcu->ptr.p_double[i]-vf; + } + subsolver->psvpackxyperm.ptr.p_int[n+i] = npsv+subsolver->psvlccnt; + subsolver->psvunpackxyperm.ptr.p_int[npsv+subsolver->psvlccnt] = n+i; + subsolver->psvlccnt = subsolver->psvlccnt+1; + subsolver->psvsparsec.m = subsolver->psvsparsec.m+1; + } + sparsecreatecrsinplace(&subsolver->psvsparsec, _state); + } + + /* + * Compress QP ordering: + * * first, compute inverse of State.qpOrdering[] in Subsolver.tmpI[] + * * map Subsolver.tmpI[] elements to packed indexes Subsolver.psvPackXYPerm[] + * * compress Subsolver.tmpI[], skipping -1's (dropped vars/constraints) + * * invert Subsolver.tmpI[], storing result into Subsolver.psvQPOrdering[] + */ + iallocv(n+lccnt, &subsolver->tmpi, _state); + for(i=0; i<=n+lccnt-1; i++) + { + subsolver->tmpi.ptr.p_int[qpordering->ptr.p_int[i]] = i; + } + for(i=0; i<=n+lccnt-1; i++) + { + subsolver->tmpi.ptr.p_int[i] = subsolver->psvpackxyperm.ptr.p_int[subsolver->tmpi.ptr.p_int[i]]; + } + offs = 0; + for(i=0; i<=n+lccnt-1; i++) + { + if( subsolver->tmpi.ptr.p_int[i]>=0 ) + { + subsolver->tmpi.ptr.p_int[offs] = subsolver->tmpi.ptr.p_int[i]; + offs = offs+1; + } + } + ae_assert(offs==npsv+subsolver->psvlccnt, "BBGD: 534739 failed", _state); + iallocv(npsv+subsolver->psvlccnt, &subsolver->psvqpordering, _state); + for(i=0; i<=npsv+subsolver->psvlccnt-1; i++) + { + subsolver->psvqpordering.ptr.p_int[subsolver->tmpi.ptr.p_int[i]] = i; + } + return result; +} + + +/************************************************************************* +Solve QP subproblem given by its bounds and initial point. Internally +applies iterative refinement to produce highly accurate solutions (essential +for proper functioning of the B&B solver). + +The solution is loaded into SubproblemArray[itemIdx], with the array object +storing instances of BBGDSubproblem. Usual rules of updating competing +solutions (BestXDual, WorstXDual) are followed. + +If UseLock=True, then subproblem is updated by acquiring Entry.EntryLock +*************************************************************************/ +static void bbgd_solveqpnode(bbgdfrontentry* entry, + bbgdfrontsubsolver* subsolver, + bbgdstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_obj_array* subproblemarray, + ae_int_t itemidx, + ae_bool uselock, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t n; + ae_int_t terminationtype; + ae_int_t tmpterminationtype; + ae_int_t k; + ae_int_t maxidx; + double fsol; + double hsol; + double mxsol; + double fcand; + double hcand; + double mxcand; + double stpnrm; + double v; + double trustrad; + ae_bool applytrustrad; + ae_bool isintfeasible; + bbgdsubproblem *subproblemtoupdate; + ae_smart_ptr _subproblemtoupdate; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblemtoupdate, 0, sizeof(_subproblemtoupdate)); + ae_smart_ptr_init(&_subproblemtoupdate, (void**)&subproblemtoupdate, ae_false, _state, ae_true); + + ae_assert(state->objtype==1&&state->nnlc==0, "BBGD: integrity check 330714 failed", _state); + n = state->n; + rallocv(ae_maxint(n, state->lccnt, _state), &subsolver->tmp0, _state); + ae_obj_array_get(subproblemarray, itemidx, &_subproblemtoupdate, _state); + + /* + * Quick exit for infeasible with respect to box constraints + */ + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state))&&ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Initial state: box constrain proposed X0 + */ + rcopyallocv(n, x0, &subsolver->xsol, _state); + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_maxreal(bndl->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_minreal(bndu->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + } + fsol = 0.5*sparsevsmv(&state->obja, ae_false, &subsolver->xsol, _state)+rdotv(n, &subsolver->xsol, &state->objb, _state)+state->objc0; + unscaleandchecklc2violation(&state->s, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, &subsolver->xsol, &hsol, &mxsol, &maxidx, _state); + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + v = ae_maxreal(bndl->ptr.p_double[i]-subsolver->xsol.ptr.p_double[i], 0.0, _state); + hsol = hsol+v; + mxsol = ae_maxreal(mxsol, v, _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + v = ae_maxreal(subsolver->xsol.ptr.p_double[i]-bndu->ptr.p_double[i], 0.0, _state); + hsol = hsol+v; + mxsol = ae_maxreal(mxsol, v, _state); + } + } + + /* + * Perform several refinement iterations, then analyze candidate + */ + terminationtype = 0; + applytrustrad = ae_false; + for(k=0; k<=bbgd_maxqprfsits-1; k++) + { + + /* + * Reformulate raw problem + * + * min[0.5x'Ax+b'x+c] subject to AL<=Ax<=AU, BndL<=x<=BndU + * + * as an SQP-style problem + * + * min[0.5y'Ay+(A*xsol+b)'y+fsol] subject to AL-A*xsol<=Ay<=AU-A*xsol, BndL-xsol<=y<=BndU-xsol + * + * with y=x-xsol. + */ + rcopyallocv(n, bndl, &subsolver->wrkbndl, _state); + rcopyallocv(n, bndu, &subsolver->wrkbndu, _state); + if( applytrustrad ) + { + for(i=0; i<=n-1; i++) + { + subsolver->wrkbndl.ptr.p_double[i] = ae_maxreal(subsolver->wrkbndl.ptr.p_double[i], subsolver->xsol.ptr.p_double[i]-trustrad*state->s.ptr.p_double[i], _state); + subsolver->wrkbndu.ptr.p_double[i] = ae_minreal(subsolver->wrkbndu.ptr.p_double[i], subsolver->xsol.ptr.p_double[i]+trustrad*state->s.ptr.p_double[i], _state); + } + } + sparsesmv(&state->obja, ae_false, &subsolver->xsol, &subsolver->wrkb, _state); + raddv(n, 1.0, &state->objb, &subsolver->wrkb, _state); + rcopyallocv(n, &state->s, &subsolver->wrks, _state); + if( applytrustrad ) + { + rmulv(n, ae_minreal(trustrad, 1.0, _state), &subsolver->wrks, _state); + } + + /* + * Solve SQP subproblem + */ + tmpterminationtype = bbgd_qpquickpresolve(entry, subsolver, &state->s, &subsolver->xsol, &subsolver->wrkbndl, &subsolver->wrkbndu, &state->obja, ae_false, &subsolver->wrkb, n, &state->rawa, &state->rawal, &state->rawau, state->lccnt, &state->qpordering, state->epsx, _state); + if( tmpterminationtype>=0 ) + { + if( subsolver->npsv>0 ) + { + ipm2init(&subsolver->qpsubsolver, &subsolver->psvs, &subsolver->psvxorigin, subsolver->npsv, &state->densedummy2, &subsolver->psva, 1, ae_false, &state->densedummy2, &subsolver->tmp0, 0, &subsolver->psvb, 0.0, &subsolver->psvbndl, &subsolver->psvbndu, &subsolver->psvsparsec, subsolver->psvlccnt, &state->densedummy2, 0, &subsolver->psvcl, &subsolver->psvcu, ae_false, ae_false, _state); + ipm2setcond(&subsolver->qpsubsolver, state->epsx, state->epsx, state->epsx, _state); + ipm2setmaxits(&subsolver->qpsubsolver, bbgd_maxipmits, _state); + ipm2setordering(&subsolver->qpsubsolver, &subsolver->psvqpordering, _state); + ipm2optimize(&subsolver->qpsubsolver, ae_true, &subsolver->tmp1, &subsolver->tmp2, &subsolver->tmp3, &tmpterminationtype, _state); + } + rcopyallocv(n, &subsolver->psvfixvals, &subsolver->tmp0, _state); + for(i=0; i<=subsolver->npsv-1; i++) + { + subsolver->tmp0.ptr.p_double[subsolver->psvunpackxyperm.ptr.p_int[i]] = subsolver->tmp1.ptr.p_double[i]; + } + } + else + { + + /* + * Presolver signalled infeasibility, stop + */ + break; + } + terminationtype = icoalesce(terminationtype, tmpterminationtype, _state); + + /* + * Modify trust radius + */ + rcopyallocv(n, &subsolver->tmp0, &subsolver->tmp1, _state); + raddv(n, -1.0, &subsolver->xsol, &subsolver->tmp1, _state); + stpnrm = rsclnrminf(n, &subsolver->tmp1, &state->s, _state); + if( !applytrustrad ) + { + applytrustrad = ae_true; + trustrad = 1.0E20; + } + trustrad = ae_minreal(trustrad, stpnrm, _state); + + /* + * Evaluate proposed point using Markov filter + */ + fcand = 0.5*sparsevsmv(&state->obja, ae_false, &subsolver->tmp0, _state)+rdotv(n, &subsolver->tmp0, &state->objb, _state)+state->objc0; + unscaleandchecklc2violation(&state->s, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, &subsolver->tmp0, &hcand, &mxcand, &maxidx, _state); + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + v = ae_maxreal(bndl->ptr.p_double[i]-subsolver->tmp0.ptr.p_double[i], 0.0, _state); + hcand = hcand+v; + mxcand = ae_maxreal(mxcand, v, _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + v = ae_maxreal(subsolver->tmp0.ptr.p_double[i]-bndu->ptr.p_double[i], 0.0, _state); + hcand = hcand+v; + mxcand = ae_maxreal(mxcand, v, _state); + } + } + if( ae_fp_greater_eq(fcand,fsol)&&ae_fp_greater_eq(hcand,hsol) ) + { + break; + } + rcopyv(n, &subsolver->tmp0, &subsolver->xsol, _state); + fsol = fcand; + hsol = hcand; + mxsol = mxcand; + terminationtype = tmpterminationtype; + if( ae_fp_less_eq(stpnrm,state->epsx) ) + { + break; + } + } + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_maxreal(bndl->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_minreal(bndu->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + } + rcopyallocv(n, &subsolver->xsol, &subsolver->tmp0, _state); + bbgd_analyzeqpsolutionandenforceintegrality(entry, &subsolver->tmp0, terminationtype, state, subproblemtoupdate, uselock, &isintfeasible, _state); + + /* + * Apply rounding heuristic to solutions that are box/linearly feasible, but not integer feasible + */ + if( !isintfeasible&&ae_fp_less_eq(mxsol,state->ctol) ) + { + + /* + * Round the solution + */ + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + subsolver->xsol.ptr.p_double[i] = (double)(ae_round(subsolver->xsol.ptr.p_double[i], _state)); + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_maxreal(bndl->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + subsolver->xsol.ptr.p_double[i] = ae_minreal(bndu->ptr.p_double[i], subsolver->xsol.ptr.p_double[i], _state); + } + } + } + + /* + * Reformulate raw problem as one centered around XSol and having fixed integer variables + */ + rcopyallocv(n, bndl, &subsolver->wrkbndl, _state); + rcopyallocv(n, bndu, &subsolver->wrkbndu, _state); + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + subsolver->wrkbndl.ptr.p_double[i] = subsolver->xsol.ptr.p_double[i]; + subsolver->wrkbndu.ptr.p_double[i] = subsolver->xsol.ptr.p_double[i]; + } + } + sparsesmv(&state->obja, ae_false, &subsolver->xsol, &subsolver->wrkb, _state); + raddv(n, 1.0, &state->objb, &subsolver->wrkb, _state); + + /* + * Solve SQP subproblem + */ + tmpterminationtype = bbgd_qpquickpresolve(entry, subsolver, &state->s, &subsolver->xsol, &subsolver->wrkbndl, &subsolver->wrkbndu, &state->obja, ae_false, &subsolver->wrkb, n, &state->rawa, &state->rawal, &state->rawau, state->lccnt, &state->qpordering, state->epsx, _state); + if( tmpterminationtype>=0 ) + { + terminationtype = 1; + if( subsolver->npsv>0 ) + { + ipm2init(&subsolver->qpsubsolver, &subsolver->psvs, &subsolver->psvxorigin, subsolver->npsv, &state->densedummy2, &subsolver->psva, 1, ae_false, &state->densedummy2, &subsolver->tmp0, 0, &subsolver->psvb, 0.0, &subsolver->psvbndl, &subsolver->psvbndu, &subsolver->psvsparsec, subsolver->psvlccnt, &state->densedummy2, 0, &subsolver->psvcl, &subsolver->psvcu, ae_false, ae_false, _state); + ipm2setcond(&subsolver->qpsubsolver, state->epsx, state->epsx, state->epsx, _state); + ipm2setmaxits(&subsolver->qpsubsolver, bbgd_maxipmits, _state); + ipm2setordering(&subsolver->qpsubsolver, &subsolver->psvqpordering, _state); + ipm2optimize(&subsolver->qpsubsolver, ae_true, &subsolver->tmp1, &subsolver->tmp2, &subsolver->tmp3, &terminationtype, _state); + } + rcopyallocv(n, &subsolver->psvfixvals, &subsolver->tmp0, _state); + for(i=0; i<=subsolver->npsv-1; i++) + { + subsolver->tmp0.ptr.p_double[subsolver->psvunpackxyperm.ptr.p_int[i]] = subsolver->tmp1.ptr.p_double[i]; + } + if( terminationtype>0 ) + { + bbgd_analyzeqpsolutionandenforceintegrality(entry, &subsolver->tmp0, terminationtype, state, subproblemtoupdate, uselock, &isintfeasible, _state); + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Analyze solution of a QP relaxation, and send it to the subproblem, +updating its best and worst primal/dual solutions. + +Can modify XSol. + +If UseLock=True, then Subproblem is accessed by acquiring Entry.EntryLock +*************************************************************************/ +static void bbgd_analyzeqpsolutionandenforceintegrality(bbgdfrontentry* entry, + /* Real */ ae_vector* xsol, + ae_int_t terminationtype, + const bbgdstate* state, + bbgdsubproblem* subproblem, + ae_bool uselock, + ae_bool* isintfeas, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double sumerr; + double maxerr; + ae_int_t maxidx; + double f; + + *isintfeas = ae_false; + + ae_assert(state->objtype==1, "BBGD: objType<>1 in AnalyzeQPSolutionAndEnforceIntegrality()", _state); + n = subproblem->n; + unscaleandchecklc2violation(&state->s, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, xsol, &sumerr, &maxerr, &maxidx, _state); + maxerr = maxerr/ae_maxreal(rsclnrminf(n, xsol, &state->s, _state), (double)(1), _state); + if( terminationtype>0&&ae_fp_less_eq(maxerr,state->ctol) ) + { + + /* + * Analyze integrality + */ + *isintfeas = ae_true; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + *isintfeas = *isintfeas&&ae_fp_less_eq(ae_fabs(xsol->ptr.p_double[i]-(double)ae_round(xsol->ptr.p_double[i], _state), _state),state->ctol); + } + } + if( *isintfeas ) + { + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + xsol->ptr.p_double[i] = (double)(ae_round(xsol->ptr.p_double[i], _state)); + } + } + } + f = 0.5*sparsevsmv(&state->obja, ae_false, xsol, _state)+rdotv(n, xsol, &state->objb, _state)+state->objc0; + unscaleandchecklc2violation(&state->s, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, xsol, &sumerr, &maxerr, &maxidx, _state); + maxerr = maxerr/ae_maxreal(rsclnrminf(n, xsol, &state->s, _state), (double)(1), _state); + + /* + * Update primal and dual solutions. + * Use locks to protect access. + */ + if( uselock ) + { + weakatomicacquirelock(&entry->entrylock, 0, 1, _state); + } + if( !subproblem->hasdualsolution||ae_fp_less(f,subproblem->bestfdual) ) + { + rcopyallocv(n, xsol, &subproblem->bestxdual, _state); + subproblem->bestfdual = f; + subproblem->besthdual = maxerr; + subproblem->bestdualisintfeas = *isintfeas; + } + if( !subproblem->hasdualsolution||ae_fp_greater(f,subproblem->worstfdual) ) + { + rcopyallocv(n, xsol, &subproblem->worstxdual, _state); + subproblem->worstfdual = f; + subproblem->worsthdual = maxerr; + } + subproblem->hasdualsolution = ae_true; + bbgd_subproblemrecomputedualbound(subproblem, _state); + if( *isintfeas&&(!subproblem->hasprimalsolution||ae_fp_less(f,subproblem->fprim)) ) + { + subproblem->hasprimalsolution = ae_true; + rcopyallocv(n, xsol, &subproblem->xprim, _state); + subproblem->fprim = f; + subproblem->hprim = maxerr; + } + if( uselock ) + { + ae_weak_atomic_release_lock(&entry->entrylock, 1, 0); + } + } + else + { + if( uselock ) + { + weakatomicacquirelock(&entry->entrylock, 0, 1, _state); + } + subproblem->besthdual = ae_minreal(subproblem->besthdual, maxerr, _state); + *isintfeas = ae_false; + if( uselock ) + { + ae_weak_atomic_release_lock(&entry->entrylock, 1, 0); + } + } +} + + +/************************************************************************* +Analyze solution of an NLP relaxation, and send it to the subproblem array. +The solution is loaded into SubproblemArray[itemIdx], with the array object +storing instances of BBGDSubproblem. Usual rules of updating competing +solutions (BestXDual, WorstXDual) are followed. + +Can modify XSol. +*************************************************************************/ +static void bbgd_analyzenlpsolutionandenforceintegrality(bbgdfrontentry* entry, + /* Real */ ae_vector* xsol, + const minnlcreport* rep, + const bbgdstate* state, + ae_obj_array* subproblemarray, + ae_int_t itemidx, + ae_bool uselock, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t n; + ae_bool isintfeas; + bbgdsubproblem *subproblem; + ae_smart_ptr _subproblem; + + ae_frame_make(_state, &_frame_block); + memset(&_subproblem, 0, sizeof(_subproblem)); + ae_smart_ptr_init(&_subproblem, (void**)&subproblem, ae_false, _state, ae_true); + + ae_obj_array_get(subproblemarray, itemidx, &_subproblem, _state); + n = subproblem->n; + if( rep->terminationtype>0&&ae_fp_less_eq(rep->sclfeaserr,state->ctol) ) + { + + /* + * Analyze integrality + */ + isintfeas = ae_true; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + isintfeas = isintfeas&&ae_fp_less_eq(ae_fabs(xsol->ptr.p_double[i]-(double)ae_round(xsol->ptr.p_double[i], _state), _state),state->ctol); + } + } + if( isintfeas ) + { + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + xsol->ptr.p_double[i] = (double)(ae_round(xsol->ptr.p_double[i], _state)); + } + } + } + + /* + * Update primal and dual solutions + * Use locks to protect access. + */ + if( uselock ) + { + weakatomicacquirelock(&entry->entrylock, 0, 1, _state); + } + if( !subproblem->hasdualsolution||ae_fp_less(rep->f,subproblem->bestfdual) ) + { + rcopyallocv(n, xsol, &subproblem->bestxdual, _state); + subproblem->bestfdual = rep->f; + subproblem->besthdual = rep->sclfeaserr; + subproblem->bestdualisintfeas = isintfeas; + } + if( !subproblem->hasdualsolution||ae_fp_greater(rep->f,subproblem->worstfdual) ) + { + rcopyallocv(n, xsol, &subproblem->worstxdual, _state); + subproblem->worstfdual = rep->f; + subproblem->worsthdual = rep->sclfeaserr; + } + subproblem->hasdualsolution = ae_true; + bbgd_subproblemrecomputedualbound(subproblem, _state); + if( isintfeas&&(!subproblem->hasprimalsolution||ae_fp_less(rep->f,subproblem->fprim)) ) + { + subproblem->hasprimalsolution = ae_true; + rcopyallocv(n, xsol, &subproblem->xprim, _state); + subproblem->fprim = rep->f; + subproblem->hprim = rep->sclfeaserr; + } + if( uselock ) + { + ae_weak_atomic_release_lock(&entry->entrylock, 1, 0); + } + } + else + { + + /* + * Bad solution. Use locks to protect access. + */ + if( uselock ) + { + weakatomicacquirelock(&entry->entrylock, 0, 1, _state); + } + subproblem->besthdual = ae_minreal(subproblem->besthdual, rep->sclfeaserr, _state); + if( uselock ) + { + ae_weak_atomic_release_lock(&entry->entrylock, 1, 0); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Add sall subproblems that are outside of the heap to the heap. + +When the function finishes, we have bbSubproblemsHeapSize=len(bbSubproblems)-1. +*************************************************************************/ +static void bbgd_growheap(bbgdstate* state, ae_state *_state) +{ + ae_int_t cnt; + + + cnt = ae_obj_array_get_length(&state->bbsubproblems); + ae_assert(state->bbsubproblemsheapsize>=0&&state->bbsubproblemsheapsize<=cnt, "BBGD: integrity check 181334 failed", _state); + if( cnt>0 ) + { + state->bbsubproblemsheapsize = bbgd_subproblemheapgrow(&state->bbsubproblems, 0, state->bbsubproblemsheapsize, cnt-state->bbsubproblemsheapsize, _state); + } +} + + +/************************************************************************* +Adds all subproblems that are outside of the heap to the heap, then remove +one on top of the heap and move it to the end of the array. The heap is +rebuilt after that. + +When the function finishes, we have bbSubproblemsHeapSize=len(bbSubproblems)-1. +*************************************************************************/ +static void bbgd_growheapandpoptop(bbgdstate* state, ae_state *_state) +{ + ae_int_t cnt; + + + cnt = ae_obj_array_get_length(&state->bbsubproblems); + ae_assert(cnt>0, "BBGD: integrity check 040311 failed", _state); + ae_assert(state->bbsubproblemsheapsize>=0&&state->bbsubproblemsheapsize<=cnt, "BBGD: integrity check 040312 failed", _state); + state->bbsubproblemsheapsize = bbgd_subproblemheapgrow(&state->bbsubproblems, 0, state->bbsubproblemsheapsize, cnt-state->bbsubproblemsheapsize, _state); + state->bbsubproblemsheapsize = bbgd_subproblemheappoptop(&state->bbsubproblems, 0, state->bbsubproblemsheapsize, _state); +} + + +/************************************************************************* +Grows subproblem heap having size HeapSize elements, located starting from +element Offs of the SubproblemHeap array, by adding AppendCnt elements +located immediately after the heap part. + +Returns new heap size. +*************************************************************************/ +static ae_int_t bbgd_subproblemheapgrow(ae_obj_array* subproblemheap, + ae_int_t offs, + ae_int_t heapsize, + ae_int_t appendcnt, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdsubproblem *pchild; + ae_smart_ptr _pchild; + bbgdsubproblem *pparent; + ae_smart_ptr _pparent; + ae_int_t ichild; + ae_int_t iparent; + ae_int_t newheapsize; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&_pchild, 0, sizeof(_pchild)); + memset(&_pparent, 0, sizeof(_pparent)); + ae_smart_ptr_init(&_pchild, (void**)&pchild, ae_false, _state, ae_true); + ae_smart_ptr_init(&_pparent, (void**)&pparent, ae_false, _state, ae_true); + + ae_assert(heapsize>=0&&appendcnt>=0, "BBGD: integrity check 984505 failed", _state); + ae_assert(ae_obj_array_get_length(subproblemheap)>=offs+heapsize+appendcnt, "BBGD: integrity check 985506 failed", _state); + + /* + * Grow heap until all elements are in the heap + */ + newheapsize = heapsize+appendcnt; + while(heapsize0) + { + iparent = (ichild-1)/2; + ae_obj_array_get(subproblemheap, offs+ichild, &_pchild, _state); + ae_obj_array_get(subproblemheap, offs+iparent, &_pparent, _state); + if( ae_fp_less_eq(pparent->dualbound,pchild->dualbound) ) + { + break; + } + ae_obj_array_swap(subproblemheap, offs+ichild, offs+iparent, _state); + ichild = iparent; + } + heapsize = heapsize+1; + } + result = newheapsize; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Removes subproblem on top of the heap having size HeapSize elements, located +starting from the element Offs of the SubproblemHeap array, and moves it +to the end of the array. The heap is resorted. + +Returns new heap size. +*************************************************************************/ +static ae_int_t bbgd_subproblemheappoptop(ae_obj_array* subproblemheap, + ae_int_t offs, + ae_int_t heapsize, + ae_state *_state) +{ + ae_frame _frame_block; + bbgdsubproblem *pchild; + ae_smart_ptr _pchild; + bbgdsubproblem *pchild2; + ae_smart_ptr _pchild2; + bbgdsubproblem *pparent; + ae_smart_ptr _pparent; + ae_int_t ichild; + ae_int_t ichild2; + ae_int_t iparent; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&_pchild, 0, sizeof(_pchild)); + memset(&_pchild2, 0, sizeof(_pchild2)); + memset(&_pparent, 0, sizeof(_pparent)); + ae_smart_ptr_init(&_pchild, (void**)&pchild, ae_false, _state, ae_true); + ae_smart_ptr_init(&_pchild2, (void**)&pchild2, ae_false, _state, ae_true); + ae_smart_ptr_init(&_pparent, (void**)&pparent, ae_false, _state, ae_true); + + ae_assert(heapsize>=1, "BBGD: integrity check 023510 failed", _state); + ae_assert(ae_obj_array_get_length(subproblemheap)>=offs+heapsize, "BBGD: integrity check 024510 failed", _state); + + /* + * Pop top + */ + ae_obj_array_swap(subproblemheap, offs+0, offs+heapsize-1, _state); + heapsize = heapsize-1; + iparent = 0; + ichild = 1; + ichild2 = 2; + while(ichild=heapsize ) + { + if( ae_fp_greater(pparent->dualbound,pchild->dualbound) ) + { + ae_obj_array_swap(subproblemheap, offs+iparent, offs+ichild, _state); + } + break; + } + + /* + * Two children + */ + ae_obj_array_get(subproblemheap, offs+ichild2, &_pchild2, _state); + if( ae_fp_less(pchild->dualbound,pchild2->dualbound) ) + { + if( ae_fp_greater(pparent->dualbound,pchild->dualbound) ) + { + ae_obj_array_swap(subproblemheap, offs+iparent, offs+ichild, _state); + iparent = ichild; + } + else + { + break; + } + } + else + { + if( ae_fp_greater(pparent->dualbound,pchild2->dualbound) ) + { + ae_obj_array_swap(subproblemheap, offs+iparent, offs+ichild2, _state); + iparent = ichild2; + } + else + { + break; + } + } + ichild = 2*iparent+1; + ichild2 = 2*iparent+2; + } + result = heapsize; + ae_frame_leave(_state); + return result; +} + + +void _bbgdsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + bbgdsubproblem *p = (bbgdsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xprim, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bestxdual, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->worstxdual, 0, DT_REAL, _state, make_automatic); +} + + +void _bbgdsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + bbgdsubproblem *dst = (bbgdsubproblem*)_dst; + const bbgdsubproblem *src = (const bbgdsubproblem*)_src; + dst->leafid = src->leafid; + dst->n = src->n; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->branchbucket = src->branchbucket; + dst->parentfdual = src->parentfdual; + dst->branchvar = src->branchvar; + dst->branchval = src->branchval; + dst->ncuttingplanes = src->ncuttingplanes; + dst->hasprimalsolution = src->hasprimalsolution; + ae_vector_init_copy(&dst->xprim, &src->xprim, _state, make_automatic); + dst->fprim = src->fprim; + dst->hprim = src->hprim; + dst->hasdualsolution = src->hasdualsolution; + ae_vector_init_copy(&dst->bestxdual, &src->bestxdual, _state, make_automatic); + dst->bestfdual = src->bestfdual; + dst->besthdual = src->besthdual; + ae_vector_init_copy(&dst->worstxdual, &src->worstxdual, _state, make_automatic); + dst->worstfdual = src->worstfdual; + dst->worsthdual = src->worsthdual; + dst->bestdualisintfeas = src->bestdualisintfeas; + dst->dualbound = src->dualbound; +} + + +void _bbgdsubproblem_clear(void* _p) +{ + bbgdsubproblem *p = (bbgdsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->xprim); + ae_vector_clear(&p->bestxdual); + ae_vector_clear(&p->worstxdual); +} + + +void _bbgdsubproblem_destroy(void* _p) +{ + bbgdsubproblem *p = (bbgdsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->xprim); + ae_vector_destroy(&p->bestxdual); + ae_vector_destroy(&p->worstxdual); +} + + +void _bbgdfrontsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + bbgdfrontsubsolver *p = (bbgdfrontsubsolver*)_p; + ae_touch_ptr((void*)p); + _bbgdsubproblem_init(&p->subproblem, _state, make_automatic); + _minnlcstate_init(&p->nlpsubsolver, _state, make_automatic); + _ipm2state_init(&p->qpsubsolver, _state, make_automatic); + _minnlcreport_init(&p->nlprep, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->xsol, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp3, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->wrks, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvpackxyperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->psvunpackxyperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->psvs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvxorigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvfixvals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvrawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvrawbndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->psva, _state, make_automatic); + _sparsematrix_init(&p->psvsparsec, _state, make_automatic); + ae_vector_init(&p->psvcl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvcu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->psvqpordering, 0, DT_INT, _state, make_automatic); +} + + +void _bbgdfrontsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + bbgdfrontsubsolver *dst = (bbgdfrontsubsolver*)_dst; + const bbgdfrontsubsolver *src = (const bbgdfrontsubsolver*)_src; + dst->subsolverstatus = src->subsolverstatus; + _bbgdsubproblem_init_copy(&dst->subproblem, &src->subproblem, _state, make_automatic); + _minnlcstate_init_copy(&dst->nlpsubsolver, &src->nlpsubsolver, _state, make_automatic); + _ipm2state_init_copy(&dst->qpsubsolver, &src->qpsubsolver, _state, make_automatic); + _minnlcreport_init_copy(&dst->nlprep, &src->nlprep, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->xsol, &src->xsol, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_vector_init_copy(&dst->wrks, &src->wrks, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndl, &src->wrkbndl, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndu, &src->wrkbndu, _state, make_automatic); + ae_vector_init_copy(&dst->wrkb, &src->wrkb, _state, make_automatic); + ae_vector_init_copy(&dst->psvpackxyperm, &src->psvpackxyperm, _state, make_automatic); + ae_vector_init_copy(&dst->psvunpackxyperm, &src->psvunpackxyperm, _state, make_automatic); + ae_vector_init_copy(&dst->psvs, &src->psvs, _state, make_automatic); + ae_vector_init_copy(&dst->psvxorigin, &src->psvxorigin, _state, make_automatic); + ae_vector_init_copy(&dst->psvbndl, &src->psvbndl, _state, make_automatic); + ae_vector_init_copy(&dst->psvbndu, &src->psvbndu, _state, make_automatic); + ae_vector_init_copy(&dst->psvb, &src->psvb, _state, make_automatic); + ae_vector_init_copy(&dst->psvfixvals, &src->psvfixvals, _state, make_automatic); + ae_vector_init_copy(&dst->psvrawbndl, &src->psvrawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->psvrawbndu, &src->psvrawbndu, _state, make_automatic); + dst->npsv = src->npsv; + _sparsematrix_init_copy(&dst->psva, &src->psva, _state, make_automatic); + _sparsematrix_init_copy(&dst->psvsparsec, &src->psvsparsec, _state, make_automatic); + ae_vector_init_copy(&dst->psvcl, &src->psvcl, _state, make_automatic); + ae_vector_init_copy(&dst->psvcu, &src->psvcu, _state, make_automatic); + dst->psvlccnt = src->psvlccnt; + ae_vector_init_copy(&dst->psvqpordering, &src->psvqpordering, _state, make_automatic); +} + + +void _bbgdfrontsubsolver_clear(void* _p) +{ + bbgdfrontsubsolver *p = (bbgdfrontsubsolver*)_p; + ae_touch_ptr((void*)p); + _bbgdsubproblem_clear(&p->subproblem); + _minnlcstate_clear(&p->nlpsubsolver); + _ipm2state_clear(&p->qpsubsolver); + _minnlcreport_clear(&p->nlprep); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->xsol); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmp3); + ae_vector_clear(&p->tmpi); + ae_vector_clear(&p->wrks); + ae_vector_clear(&p->wrkbndl); + ae_vector_clear(&p->wrkbndu); + ae_vector_clear(&p->wrkb); + ae_vector_clear(&p->psvpackxyperm); + ae_vector_clear(&p->psvunpackxyperm); + ae_vector_clear(&p->psvs); + ae_vector_clear(&p->psvxorigin); + ae_vector_clear(&p->psvbndl); + ae_vector_clear(&p->psvbndu); + ae_vector_clear(&p->psvb); + ae_vector_clear(&p->psvfixvals); + ae_vector_clear(&p->psvrawbndl); + ae_vector_clear(&p->psvrawbndu); + _sparsematrix_clear(&p->psva); + _sparsematrix_clear(&p->psvsparsec); + ae_vector_clear(&p->psvcl); + ae_vector_clear(&p->psvcu); + ae_vector_clear(&p->psvqpordering); +} + + +void _bbgdfrontsubsolver_destroy(void* _p) +{ + bbgdfrontsubsolver *p = (bbgdfrontsubsolver*)_p; + ae_touch_ptr((void*)p); + _bbgdsubproblem_destroy(&p->subproblem); + _minnlcstate_destroy(&p->nlpsubsolver); + _ipm2state_destroy(&p->qpsubsolver); + _minnlcreport_destroy(&p->nlprep); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->xsol); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmp3); + ae_vector_destroy(&p->tmpi); + ae_vector_destroy(&p->wrks); + ae_vector_destroy(&p->wrkbndl); + ae_vector_destroy(&p->wrkbndu); + ae_vector_destroy(&p->wrkb); + ae_vector_destroy(&p->psvpackxyperm); + ae_vector_destroy(&p->psvunpackxyperm); + ae_vector_destroy(&p->psvs); + ae_vector_destroy(&p->psvxorigin); + ae_vector_destroy(&p->psvbndl); + ae_vector_destroy(&p->psvbndu); + ae_vector_destroy(&p->psvb); + ae_vector_destroy(&p->psvfixvals); + ae_vector_destroy(&p->psvrawbndl); + ae_vector_destroy(&p->psvrawbndu); + _sparsematrix_destroy(&p->psva); + _sparsematrix_destroy(&p->psvsparsec); + ae_vector_destroy(&p->psvcl); + ae_vector_destroy(&p->psvcu); + ae_vector_destroy(&p->psvqpordering); +} + + +void _bbgdfrontentry_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + bbgdfrontentry *p = (bbgdfrontentry*)_p; + ae_touch_ptr((void*)p); + _stimer_init(&p->timerlocal, _state, make_automatic); + _bbgdsubproblem_init(&p->parentsubproblem, _state, make_automatic); + _bbgdsubproblem_init(&p->rootproblem, _state, make_automatic); + _bbgdsubproblem_init(&p->childsubproblem0, _state, make_automatic); + _bbgdsubproblem_init(&p->childsubproblem1, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_obj_array_init(&p->subsolvers, _state, make_automatic); + ae_obj_array_init(&p->spqueue, _state, make_automatic); + ae_obj_array_init(&p->solutions, _state, make_automatic); + _bbgdsubproblem_init(&p->tmpsubproblem, _state, make_automatic); + ae_vector_init(&p->tmpreliablebranchidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpreliablebranchscore, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpunreliablebranchidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpunreliablebranchscore, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpchosenbranchidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpchosenbranchscore, 0, DT_REAL, _state, make_automatic); +} + + +void _bbgdfrontentry_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + bbgdfrontentry *dst = (bbgdfrontentry*)_dst; + const bbgdfrontentry *src = (const bbgdfrontentry*)_src; + dst->entrystatus = src->entrystatus; + dst->addstatussolutionsaggregated = src->addstatussolutionsaggregated; + dst->addstatusdecisionsmade = src->addstatusdecisionsmade; + dst->entrylock = src->entrylock; + dst->isrootentry = src->isrootentry; + dst->maxsubsolvers = src->maxsubsolvers; + dst->hastimeout = src->hastimeout; + dst->timeout = src->timeout; + _stimer_init_copy(&dst->timerlocal, &src->timerlocal, _state, make_automatic); + _bbgdsubproblem_init_copy(&dst->parentsubproblem, &src->parentsubproblem, _state, make_automatic); + _bbgdsubproblem_init_copy(&dst->rootproblem, &src->rootproblem, _state, make_automatic); + _bbgdsubproblem_init_copy(&dst->childsubproblem0, &src->childsubproblem0, _state, make_automatic); + _bbgdsubproblem_init_copy(&dst->childsubproblem1, &src->childsubproblem1, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->fathomroot = src->fathomroot; + dst->fathomchild0 = src->fathomchild0; + dst->fathomchild1 = src->fathomchild1; + ae_obj_array_init_copy(&dst->subsolvers, &src->subsolvers, _state, make_automatic); + ae_obj_array_init_copy(&dst->spqueue, &src->spqueue, _state, make_automatic); + ae_obj_array_init_copy(&dst->solutions, &src->solutions, _state, make_automatic); + _bbgdsubproblem_init_copy(&dst->tmpsubproblem, &src->tmpsubproblem, _state, make_automatic); + ae_vector_init_copy(&dst->tmpreliablebranchidx, &src->tmpreliablebranchidx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpreliablebranchscore, &src->tmpreliablebranchscore, _state, make_automatic); + ae_vector_init_copy(&dst->tmpunreliablebranchidx, &src->tmpunreliablebranchidx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpunreliablebranchscore, &src->tmpunreliablebranchscore, _state, make_automatic); + ae_vector_init_copy(&dst->tmpchosenbranchidx, &src->tmpchosenbranchidx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpchosenbranchscore, &src->tmpchosenbranchscore, _state, make_automatic); +} + + +void _bbgdfrontentry_clear(void* _p) +{ + bbgdfrontentry *p = (bbgdfrontentry*)_p; + ae_touch_ptr((void*)p); + _stimer_clear(&p->timerlocal); + _bbgdsubproblem_clear(&p->parentsubproblem); + _bbgdsubproblem_clear(&p->rootproblem); + _bbgdsubproblem_clear(&p->childsubproblem0); + _bbgdsubproblem_clear(&p->childsubproblem1); + _rcommstate_clear(&p->rstate); + ae_obj_array_clear(&p->subsolvers); + ae_obj_array_clear(&p->spqueue); + ae_obj_array_clear(&p->solutions); + _bbgdsubproblem_clear(&p->tmpsubproblem); + ae_vector_clear(&p->tmpreliablebranchidx); + ae_vector_clear(&p->tmpreliablebranchscore); + ae_vector_clear(&p->tmpunreliablebranchidx); + ae_vector_clear(&p->tmpunreliablebranchscore); + ae_vector_clear(&p->tmpchosenbranchidx); + ae_vector_clear(&p->tmpchosenbranchscore); +} + + +void _bbgdfrontentry_destroy(void* _p) +{ + bbgdfrontentry *p = (bbgdfrontentry*)_p; + ae_touch_ptr((void*)p); + _stimer_destroy(&p->timerlocal); + _bbgdsubproblem_destroy(&p->parentsubproblem); + _bbgdsubproblem_destroy(&p->rootproblem); + _bbgdsubproblem_destroy(&p->childsubproblem0); + _bbgdsubproblem_destroy(&p->childsubproblem1); + _rcommstate_destroy(&p->rstate); + ae_obj_array_destroy(&p->subsolvers); + ae_obj_array_destroy(&p->spqueue); + ae_obj_array_destroy(&p->solutions); + _bbgdsubproblem_destroy(&p->tmpsubproblem); + ae_vector_destroy(&p->tmpreliablebranchidx); + ae_vector_destroy(&p->tmpreliablebranchscore); + ae_vector_destroy(&p->tmpunreliablebranchidx); + ae_vector_destroy(&p->tmpunreliablebranchscore); + ae_vector_destroy(&p->tmpchosenbranchidx); + ae_vector_destroy(&p->tmpchosenbranchscore); +} + + +void _bbgdfront_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + bbgdfront *p = (bbgdfront*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_init(&p->entries, _state, make_automatic); + ae_shared_pool_init(&p->entrypool, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->jobs, 0, DT_INT, _state, make_automatic); +} + + +void _bbgdfront_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + bbgdfront *dst = (bbgdfront*)_dst; + const bbgdfront *src = (const bbgdfront*)_src; + dst->frontmode = src->frontmode; + dst->frontstatus = src->frontstatus; + dst->popmostrecent = src->popmostrecent; + dst->backtrackbudget = src->backtrackbudget; + dst->frontsize = src->frontsize; + ae_obj_array_init_copy(&dst->entries, &src->entries, _state, make_automatic); + ae_shared_pool_init_copy(&dst->entrypool, &src->entrypool, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->jobs, &src->jobs, _state, make_automatic); +} + + +void _bbgdfront_clear(void* _p) +{ + bbgdfront *p = (bbgdfront*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_clear(&p->entries); + ae_shared_pool_clear(&p->entrypool); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->jobs); +} + + +void _bbgdfront_destroy(void* _p) +{ + bbgdfront *p = (bbgdfront*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_destroy(&p->entries); + ae_shared_pool_destroy(&p->entrypool); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->jobs); +} + + +void _bbgdstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + bbgdstate *p = (bbgdstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isintegral, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isbinary, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->obja, _state, make_automatic); + ae_vector_init(&p->objb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qpordering, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->rawa, _state, make_automatic); + ae_vector_init(&p->rawal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timerglobal, _state, make_automatic); + ae_vector_init(&p->xprim, 0, DT_REAL, _state, make_automatic); + _bbgdsubproblem_init(&p->rootsubproblem, _state, make_automatic); + ae_obj_array_init(&p->bbsubproblems, _state, make_automatic); + _bbgdfront_init(&p->front, _state, make_automatic); + ae_shared_pool_init(&p->sppool, _state, make_automatic); + ae_shared_pool_init(&p->subsolverspool, _state, make_automatic); + ae_vector_init(&p->pseudocostsup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pseudocostsdown, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pseudocostscntup, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->pseudocostscntdown, 0, DT_INT, _state, make_automatic); + _hqrndstate_init(&p->unsafeglobalrng, _state, make_automatic); + _bbgdsubproblem_init(&p->dummysubproblem, _state, make_automatic); + _bbgdfrontsubsolver_init(&p->dummysubsolver, _state, make_automatic); + _ipm2state_init(&p->dummyqpsubsolver, _state, make_automatic); + _bbgdfrontentry_init(&p->dummyentry, _state, make_automatic); + ae_matrix_init(&p->densedummy2, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _bbgdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + bbgdstate *dst = (bbgdstate*)_dst; + const bbgdstate *src = (const bbgdstate*)_src; + dst->n = src->n; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->diffstep = src->diffstep; + dst->convexityflag = src->convexityflag; + dst->nonconvexitygain = src->nonconvexitygain; + dst->pdgap = src->pdgap; + dst->ctol = src->ctol; + dst->epsx = src->epsx; + dst->epsf = src->epsf; + dst->nonrootmaxitslin = src->nonrootmaxitslin; + dst->nonrootmaxitsconst = src->nonrootmaxitsconst; + dst->nonrootadditsforfeasibility = src->nonrootadditsforfeasibility; + dst->pseudocostmu = src->pseudocostmu; + dst->pseudocostminfrac = src->pseudocostminfrac; + dst->pseudocostinfeaspenaly = src->pseudocostinfeaspenaly; + dst->nmultistarts = src->nmultistarts; + dst->branchingtype = src->branchingtype; + dst->krel = src->krel; + dst->kevalunreliable = src->kevalunreliable; + dst->kevalreliable = src->kevalreliable; + dst->dodiving = src->dodiving; + dst->timeout = src->timeout; + dst->bbgdgroupsize = src->bbgdgroupsize; + dst->maxsubsolvers = src->maxsubsolvers; + dst->forceserial = src->forceserial; + dst->softmaxnodes = src->softmaxnodes; + dst->hardmaxnodes = src->hardmaxnodes; + dst->maxprimalcandidates = src->maxprimalcandidates; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->isintegral, &src->isintegral, _state, make_automatic); + ae_vector_init_copy(&dst->isbinary, &src->isbinary, _state, make_automatic); + dst->objtype = src->objtype; + _sparsematrix_init_copy(&dst->obja, &src->obja, _state, make_automatic); + ae_vector_init_copy(&dst->objb, &src->objb, _state, make_automatic); + dst->objc0 = src->objc0; + ae_vector_init_copy(&dst->qpordering, &src->qpordering, _state, make_automatic); + _sparsematrix_init_copy(&dst->rawa, &src->rawa, _state, make_automatic); + ae_vector_init_copy(&dst->rawal, &src->rawal, _state, make_automatic); + ae_vector_init_copy(&dst->rawau, &src->rawau, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + dst->lccnt = src->lccnt; + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->hasx0 = src->hasx0; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + dst->repnfev = src->repnfev; + dst->repnsubproblems = src->repnsubproblems; + dst->repntreenodes = src->repntreenodes; + dst->repnnodesbeforefeasibility = src->repnnodesbeforefeasibility; + dst->repnprimalcandidates = src->repnprimalcandidates; + dst->repterminationtype = src->repterminationtype; + dst->repf = src->repf; + dst->reppdgap = src->reppdgap; + _stimer_init_copy(&dst->timerglobal, &src->timerglobal, _state, make_automatic); + dst->dotrace = src->dotrace; + dst->dolaconictrace = src->dolaconictrace; + dst->nextleafid = src->nextleafid; + dst->hasprimalsolution = src->hasprimalsolution; + ae_vector_init_copy(&dst->xprim, &src->xprim, _state, make_automatic); + dst->fprim = src->fprim; + dst->hprim = src->hprim; + dst->ffdual = src->ffdual; + dst->timedout = src->timedout; + _bbgdsubproblem_init_copy(&dst->rootsubproblem, &src->rootsubproblem, _state, make_automatic); + ae_obj_array_init_copy(&dst->bbsubproblems, &src->bbsubproblems, _state, make_automatic); + dst->bbsubproblemsheapsize = src->bbsubproblemsheapsize; + dst->bbsubproblemsrecentlyadded = src->bbsubproblemsrecentlyadded; + _bbgdfront_init_copy(&dst->front, &src->front, _state, make_automatic); + ae_shared_pool_init_copy(&dst->sppool, &src->sppool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->subsolverspool, &src->subsolverspool, _state, make_automatic); + ae_vector_init_copy(&dst->pseudocostsup, &src->pseudocostsup, _state, make_automatic); + ae_vector_init_copy(&dst->pseudocostsdown, &src->pseudocostsdown, _state, make_automatic); + ae_vector_init_copy(&dst->pseudocostscntup, &src->pseudocostscntup, _state, make_automatic); + ae_vector_init_copy(&dst->pseudocostscntdown, &src->pseudocostscntdown, _state, make_automatic); + dst->globalpseudocostup = src->globalpseudocostup; + dst->globalpseudocostdown = src->globalpseudocostdown; + dst->globalpseudocostcntup = src->globalpseudocostcntup; + dst->globalpseudocostcntdown = src->globalpseudocostcntdown; + _hqrndstate_init_copy(&dst->unsafeglobalrng, &src->unsafeglobalrng, _state, make_automatic); + dst->requestsource = src->requestsource; + dst->lastrequesttype = src->lastrequesttype; + _bbgdsubproblem_init_copy(&dst->dummysubproblem, &src->dummysubproblem, _state, make_automatic); + _bbgdfrontsubsolver_init_copy(&dst->dummysubsolver, &src->dummysubsolver, _state, make_automatic); + _ipm2state_init_copy(&dst->dummyqpsubsolver, &src->dummyqpsubsolver, _state, make_automatic); + _bbgdfrontentry_init_copy(&dst->dummyentry, &src->dummyentry, _state, make_automatic); + ae_matrix_init_copy(&dst->densedummy2, &src->densedummy2, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _bbgdstate_clear(void* _p) +{ + bbgdstate *p = (bbgdstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->isintegral); + ae_vector_clear(&p->isbinary); + _sparsematrix_clear(&p->obja); + ae_vector_clear(&p->objb); + ae_vector_clear(&p->qpordering); + _sparsematrix_clear(&p->rawa); + ae_vector_clear(&p->rawal); + ae_vector_clear(&p->rawau); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->xc); + _stimer_clear(&p->timerglobal); + ae_vector_clear(&p->xprim); + _bbgdsubproblem_clear(&p->rootsubproblem); + ae_obj_array_clear(&p->bbsubproblems); + _bbgdfront_clear(&p->front); + ae_shared_pool_clear(&p->sppool); + ae_shared_pool_clear(&p->subsolverspool); + ae_vector_clear(&p->pseudocostsup); + ae_vector_clear(&p->pseudocostsdown); + ae_vector_clear(&p->pseudocostscntup); + ae_vector_clear(&p->pseudocostscntdown); + _hqrndstate_clear(&p->unsafeglobalrng); + _bbgdsubproblem_clear(&p->dummysubproblem); + _bbgdfrontsubsolver_clear(&p->dummysubsolver); + _ipm2state_clear(&p->dummyqpsubsolver); + _bbgdfrontentry_clear(&p->dummyentry); + ae_matrix_clear(&p->densedummy2); + _rcommstate_clear(&p->rstate); +} + + +void _bbgdstate_destroy(void* _p) +{ + bbgdstate *p = (bbgdstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->isintegral); + ae_vector_destroy(&p->isbinary); + _sparsematrix_destroy(&p->obja); + ae_vector_destroy(&p->objb); + ae_vector_destroy(&p->qpordering); + _sparsematrix_destroy(&p->rawa); + ae_vector_destroy(&p->rawal); + ae_vector_destroy(&p->rawau); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->xc); + _stimer_destroy(&p->timerglobal); + ae_vector_destroy(&p->xprim); + _bbgdsubproblem_destroy(&p->rootsubproblem); + ae_obj_array_destroy(&p->bbsubproblems); + _bbgdfront_destroy(&p->front); + ae_shared_pool_destroy(&p->sppool); + ae_shared_pool_destroy(&p->subsolverspool); + ae_vector_destroy(&p->pseudocostsup); + ae_vector_destroy(&p->pseudocostsdown); + ae_vector_destroy(&p->pseudocostscntup); + ae_vector_destroy(&p->pseudocostscntdown); + _hqrndstate_destroy(&p->unsafeglobalrng); + _bbgdsubproblem_destroy(&p->dummysubproblem); + _bbgdfrontsubsolver_destroy(&p->dummysubsolver); + _ipm2state_destroy(&p->dummyqpsubsolver); + _bbgdfrontentry_destroy(&p->dummyentry); + ae_matrix_destroy(&p->densedummy2); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +MIRBFVNS solver initialization. +-------------------------------------------------------------------------- + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnscreatebuf(ae_int_t n, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + /* Boolean */ const ae_vector* isintegral, + /* Boolean */ const ae_vector* isbinary, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t algomode, + ae_int_t budget, + ae_int_t maxneighborhood, + ae_int_t batchsize, + ae_int_t timeout, + ae_int_t tracelevel, + mirbfvnsstate* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + + + ae_assert(n>=1, "MIRBFVNSCreateBuf: N<1", _state); + ae_assert(x0->cnt>=n, "MIRBFVNSCreateBuf: Length(X0)cnt>=n, "MIRBFVNSCreateBuf: Length(BndL)cnt>=n, "MIRBFVNSCreateBuf: Length(BndU)cnt>=n, "MIRBFVNSCreateBuf: Length(S)cnt>=n, "MIRBFVNSCreateBuf: Length(IsIntegral)cnt>=n, "MIRBFVNSCreateBuf: Length(IsBinary)=0, "MIRBFVNSCreateBuf: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "MIRBFVNSCreateBuf: Length(NL)cnt>=nnlc, "MIRBFVNSCreateBuf: Length(NU)=0, "MIRBFVNSCreateBuf: Length(NU)=0, "MIRBFVNSCreateBuf: Timeout<0", _state); + ae_assert(((tracelevel==0||tracelevel==1)||tracelevel==2)||tracelevel==3, "MIRBFVNSCreateBuf: unexpected trace level", _state); + ae_assert(algomode==0||algomode==1, "MIRBFVNSCreateBuf: unexpected AlgoMode", _state); + mirbfvns_initinternal(n, x0, 0, 0.0, state, _state); + state->algomode = algomode; + state->expandneighborhoodonstart = ae_true; + state->retrylastcut = ae_true; + state->budget = budget; + state->maxneighborhood = maxneighborhood; + state->batchsize = batchsize; + state->timeout = timeout; + state->dotrace = tracelevel>=2; + state->doextratrace = tracelevel>=3; + state->dolaconictrace = tracelevel==1; + state->doanytrace = state->dotrace||state->dolaconictrace; + for(i=0; i<=n-1; i++) + { + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MIRBFVNSCreateBuf: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MIRBFVNSCreateBuf: BndL contains NAN or -INF", _state); + ae_assert(isintegral->ptr.p_bool[i]||!isbinary->ptr.p_bool[i], "MIRBFVNSCreateBuf: variable marked as binary but not integral", _state); + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MIRBFVNSCreateBuf: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MIRBFVNSCreateBuf: S contains zero elements", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + state->isintegral.ptr.p_bool[i] = isintegral->ptr.p_bool[i]; + state->isbinary.ptr.p_bool[i] = isbinary->ptr.p_bool[i]; + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } + state->lccnt = lccnt; + state->haslinearlyconstrainedints = ae_false; + if( lccnt>0 ) + { + sparsecopytocrsbuf(sparsea, &state->rawa, _state); + rcopyallocv(lccnt, al, &state->rawal, _state); + rcopyallocv(lccnt, au, &state->rawau, _state); + icopyallocv(lccnt, lcsrcidx, &state->lcsrcidx, _state); + for(i=0; i<=lccnt-1; i++) + { + j0 = state->rawa.ridx.ptr.p_int[i]; + j1 = state->rawa.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->haslinearlyconstrainedints = state->haslinearlyconstrainedints||isintegral->ptr.p_bool[state->rawa.idx.ptr.p_int[jj]]; + } + } + } + state->nnlc = nnlc; + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "MIRBFVNSCreateBuf: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "MIRBFVNSCreateBuf: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + } +} + + +/************************************************************************* +Set tolerance for violation of nonlinear constraints + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnssetctol(mirbfvnsstate* state, double ctol, ae_state *_state) +{ + + + state->ctol = ctol; +} + + +/************************************************************************* +Set subsolver stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnssetepsf(mirbfvnsstate* state, double epsf, ae_state *_state) +{ + + + state->epsf = epsf; +} + + +/************************************************************************* +Set subsolver stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnssetepsx(mirbfvnsstate* state, double epsx, ae_state *_state) +{ + + + state->epsx = epsx; +} + + +/************************************************************************* +Set variable mask + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnssetvariablemask(mirbfvnsstate* state, + /* Boolean */ const ae_vector* hasmask, + const sparsematrix* mask, + ae_state *_state) +{ + + + state->nomask = ae_false; + bcopyallocv(1+state->nnlc, hasmask, &state->hasmask, _state); + sparsecopybuf(mask, &state->varmask, _state); +} + + +/************************************************************************* +Set adaptive internal parallelism: +* +1 for 'favor parallelism', turn off when proved that serial is better +* 0 for 'cautious parallelism', start serially, use SMP when proved that SMP is better +* -1 for 'no adaptiveness', always start SMP when allowed to do so + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mirbfvnssetadaptiveinternalparallelism(mirbfvnsstate* state, + ae_int_t smpmode, + ae_state *_state) +{ + + + state->adaptiveinternalparallelism = smpmode; +} + + +/************************************************************************* + + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool mirbfvnsiteration(mirbfvnsstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t nnlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t newneighbors; + ae_int_t offs; + double v; + double v0; + double v1; + double lcerr; + ae_bool bflag; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + nnlc = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + j = state->rstate.ia.ptr.p_int[3]; + k = state->rstate.ia.ptr.p_int[4]; + newneighbors = state->rstate.ia.ptr.p_int[5]; + offs = state->rstate.ia.ptr.p_int[6]; + bflag = state->rstate.ba.ptr.p_bool[0]; + v = state->rstate.ra.ptr.p_double[0]; + v0 = state->rstate.ra.ptr.p_double[1]; + v1 = state->rstate.ra.ptr.p_double[2]; + lcerr = state->rstate.ra.ptr.p_double[3]; + } + else + { + n = 359; + nnlc = -58; + i = -919; + j = -909; + k = 81; + newneighbors = 255; + offs = 74; + bflag = ae_false; + v = 809.0; + v0 = 205.0; + v1 = -838.0; + lcerr = 939.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + + /* + * Routine body + */ + n = state->n; + nnlc = state->nnlc; + stimerinit(&state->timerglobal, _state); + stimerinit(&state->timerprepareneighbors, _state); + stimerinit(&state->timerproposetrial, _state); + stimerstart(&state->timerglobal, _state); + mirbfvns_clearoutputs(state, _state); + ae_shared_pool_set_seed(&state->tmppool, &state->dummytmp, (ae_int_t)sizeof(state->dummytmp), (ae_copy_constructor)_mirbfvnstemporaries_init_copy, (ae_destructor)_mirbfvnstemporaries_destroy, _state); + ae_nxpool_alloc(&state->rpool, imax3(n, state->lccnt, 1+nnlc, _state), _state); + rsetallocv(n, 0.0, &state->maskint, _state); + rsetallocv(n, 0.0, &state->maskfrac, _state); + isetallocv(n, -1, &state->idxint, _state); + isetallocv(n, -1, &state->idxfrac, _state); + state->nfrac = 0; + state->nint = 0; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + state->maskint.ptr.p_double[i] = 1.0; + state->idxint.ptr.p_int[state->nint] = i; + state->nint = state->nint+1; + } + else + { + state->maskfrac.ptr.p_double[i] = 1.0; + state->idxfrac.ptr.p_int[state->nfrac] = i; + state->nfrac = state->nfrac+1; + } + } + rcopyallocv(n, &state->x0, &state->xc, _state); + rallocv(n, &state->tmpx1, _state); + rallocv(1+state->nnlc, &state->tmpf1, _state); + state->prepareevaluationbatchparallelism = state->adaptiveinternalparallelism==1||state->adaptiveinternalparallelism==-1; + state->expandcutgenerateneighborsparallelism = state->adaptiveinternalparallelism==1||state->adaptiveinternalparallelism==-1; + if( state->doanytrace ) + { + ae_trace("> preparing initial point\n"); + } + rsetallocv(n, -ae_sqrt(ae_maxrealnumber, _state), &state->finitebndl, _state); + rsetallocv(n, ae_sqrt(ae_maxrealnumber, _state), &state->finitebndu, _state); + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + if( ae_fp_less(state->bndu.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + if( state->doanytrace ) + { + ae_trace(">> error: box constraint %0d is infeasible (bndUrepterminationtype = -3; + result = ae_false; + return result; + } + if( state->isintegral.ptr.p_bool[i]&&ae_fp_less((double)(ae_ifloor(state->bndu.ptr.p_double[i], _state)),state->bndl.ptr.p_double[i]) ) + { + if( state->doanytrace ) + { + ae_trace(">> error: box constraint %0d is incompatible with integrality constraints\n", + (int)(i)); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + } + if( state->isintegral.ptr.p_bool[i] ) + { + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_neq(state->bndl.ptr.p_double[i],(double)(ae_round(state->bndl.ptr.p_double[i], _state))) ) + { + state->bndl.ptr.p_double[i] = (double)(ae_iceil(state->bndl.ptr.p_double[i], _state)); + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_neq(state->bndu.ptr.p_double[i],(double)(ae_round(state->bndu.ptr.p_double[i], _state))) ) + { + state->bndu.ptr.p_double[i] = (double)(ae_ifloor(state->bndu.ptr.p_double[i], _state)); + } + } + if( state->isbinary.ptr.p_bool[i] ) + { + if( ae_isneginf(state->bndl.ptr.p_double[i], _state)||ae_fp_less(state->bndl.ptr.p_double[i],(double)(0)) ) + { + state->bndl.ptr.p_double[i] = (double)(0); + } + if( ae_isposinf(state->bndu.ptr.p_double[i], _state)||ae_fp_greater(state->bndu.ptr.p_double[i],(double)(1)) ) + { + state->bndu.ptr.p_double[i] = (double)(1); + } + } + state->hasbndl.ptr.p_bool[i] = state->hasbndl.ptr.p_bool[i]||ae_isfinite(state->bndl.ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = state->hasbndu.ptr.p_bool[i]||ae_isfinite(state->bndu.ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->finitebndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->finitebndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + bflag = mirbfvns_prepareinitialpoint(state, &state->xc, &lcerr, _state); + if( !bflag||ae_fp_greater(lcerr,state->ctol) ) + { + if( state->doanytrace ) + { + ae_trace(">> error: box, linear and integrality constraints together are inconsistent; declaring infeasibility\n"); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + rcopyallocv(n, &state->xc, &state->querydata, _state); + rallocv(1+nnlc, &state->replyfi, _state); + state->requesttype = 4; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->repnfev = state->repnfev+1; + if( !isfinitevector(&state->replyfi, 1+nnlc, _state) ) + { + if( state->doanytrace ) + { + ae_trace(">> error: the initial point has objective or one of nonlinear constraints equal to NAN/INF\n>> unable to restore, stop\n"); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + state->fc = state->replyfi.ptr.p_double[0]; + mirbfvns_computeviolation2(state, &state->xc, &state->replyfi, &state->hc, &state->mxc, _state); + mirbfvns_datasetinitempty(&state->dataset, state, _state); + state->nodec = mirbfvns_gridcreate(&state->grid, state, &state->xc, &state->replyfi, state->hc, state->mxc, _state); + rsetallocv(n, 0.0, &state->nodecproducedbycut, _state); + if( state->doanytrace ) + { + ae_trace(">> done; the initial grid node N%0d is created\n", + (int)(state->nodec)); + } + state->repterminationtype = 0; + state->outofbudget = ae_false; +lbl_2: + if( ae_false ) + { + goto lbl_3; + } + isetallocv(1, state->nodec, &state->xcneighbors, _state); + isetallocv(1, state->nodec, &state->xcreachedfrom, _state); + bsetallocv(1, ae_false, &state->xcqueryflags, _state); + rgrowrowsfixedcolsm(1, n, &state->xcreachedbycut, _state); + rsetr(n, 0.0, &state->xcreachedbycut, 0, _state); + state->xcneighborscnt = 1; + state->xcpriorityneighborscnt = 1; + if( state->expandneighborhoodonstart ) + { + mirbfvns_expandneighborhood(state, _state); + } + if( state->dotrace ) + { + ae_trace("> starting search from node %0d", + (int)(state->nodec)); + if( state->xcneighborscnt>1 ) + { + ae_trace(" with expanded neighborhood of %0d nodes", + (int)(state->xcneighborscnt-1)); + } + ae_trace(" (F=%0.6e,H=%0.6e)\n", + (double)(mirbfvns_gridgetfbest(&state->grid, state, state->nodec, _state)), + (double)(mirbfvns_gridgethbest(&state->grid, state, state->nodec, _state))); + } +lbl_4: + if( ae_false ) + { + goto lbl_5; + } + k = state->nodec; + j = 0; + for(i=0; i<=state->xcneighborscnt-1; i++) + { + if( mirbfvns_gridisbetter(&state->grid, state, k, state->xcneighbors.ptr.p_int[i], _state) ) + { + k = state->xcneighbors.ptr.p_int[i]; + j = i; + } + } + if( k!=state->nodec ) + { + if( state->dotrace ) + { + ae_trace(">> found better neighbor, switching to node %0d (F=%0.6e,H=%0.6e)\n", + (int)(k), + (double)(mirbfvns_gridgetfbest(&state->grid, state, k, _state)), + (double)(mirbfvns_gridgethbest(&state->grid, state, k, _state))); + } + state->nodec = k; + rcopyrv(n, &state->xcreachedbycut, j, &state->nodecproducedbycut, _state); + goto lbl_5; + } + if( state->budget>0&&state->repnfev>=state->budget ) + { + if( state->doanytrace ) + { + ae_trace("> iteration budget exhausted, stopping\n"); + } + state->repterminationtype = 5; + state->outofbudget = ae_true; + goto lbl_5; + } + if( state->timeout>0&&ae_fp_greater(stimergetmsrunning(&state->timerglobal, _state),(double)(state->timeout)) ) + { + if( state->doanytrace ) + { + ae_trace("> time budget exhausted, stopping\n"); + } + state->repterminationtype = 5; + state->outofbudget = ae_true; + goto lbl_5; + } + mirbfvns_prepareevaluationbatch(state, _state); + if( state->evalbatchsize<=0 ) + { + goto lbl_6; + } + state->requesttype = 4; + state->querysize = state->evalbatchsize; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + rallocv(n*state->evalbatchsize, &state->querydata, _state); + offs = 0; + for(i=0; i<=state->evalbatchsize-1; i++) + { + for(k=0; k<=n-1; k++) + { + state->querydata.ptr.p_double[offs+k] = state->evalbatchpoints.ptr.pp_double[i][k]; + } + offs = offs+n; + } + rallocv((1+nnlc)*state->evalbatchsize, &state->replyfi, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->repnfev = state->repnfev+state->evalbatchsize; + rallocv(n, &state->xtrial, _state); + rallocv(1+nnlc, &state->trialfi, _state); + for(i=0; i<=state->evalbatchsize-1; i++) + { + rcopyrv(n, &state->evalbatchpoints, i, &state->xtrial, _state); + rcopyvx(1+nnlc, &state->replyfi, i*(1+nnlc), &state->trialfi, 0, _state); + mirbfvns_gridsendtrialpointto(&state->grid, state, state->nodec, state->evalbatchnodeidx.ptr.p_int[i], &state->xtrial, &state->trialfi, _state); + } + if( state->dotrace ) + { + if( mirbfvns_gridgetbestlastacceptedinunsolvedneighborhood(&state->grid, state, &state->xcneighbors, state->xcneighborscnt, &k, &v, &v0, &v1, _state) ) + { + ae_trace(">> improving neighborhood, %3d evaluations, best unsolved node is %6d: f=%15.6e, sum(viol)=%0.2e, max(viol)=%0.2e\n", + (int)(state->evalbatchsize), + (int)(k), + (double)(v), + (double)(v0), + (double)(v1)); + } + else + { + mirbfvns_gridgetbestinneighborhood(&state->grid, state, &state->xcneighbors, state->xcneighborscnt, &v, &v0, &v1, _state); + ae_trace(">> improving neighborhood, %3d evaluations, all nodes are solved, best: f=%15.6e, sum(viol)=%0.2e, max(viol)=%0.2e\n", + (int)(state->evalbatchsize), + (double)(v), + (double)(v0), + (double)(v1)); + } + } + if( state->evalbatchsizebatchsize&&(state->maxneighborhood==0||state->xcneighborscnt-1maxneighborhood) ) + { + newneighbors = mirbfvns_expandneighborhood(state, _state); + if( state->dotrace ) + { + ae_trace("> evaluation batch is not fully used (%0d out of %0d), expanding neighborhood: %0d new neighbor(s), |neighborhood|=%0d\n", + (int)(state->evalbatchsize), + (int)(state->batchsize), + (int)(newneighbors), + (int)(state->xcneighborscnt)); + } + } + goto lbl_4; +lbl_6: + if( state->maxneighborhood>0&&state->xcneighborscnt-1>=state->maxneighborhood ) + { + if( state->doanytrace ) + { + ae_trace("> the neighborhood size exceeds limit (%0d+1), stopping\n", + (int)(state->maxneighborhood)); + } + state->repterminationtype = 2; + goto lbl_5; + } + newneighbors = mirbfvns_expandneighborhood(state, _state); + if( newneighbors==0 ) + { + if( state->doanytrace ) + { + ae_trace("> the integer grid was completely scanned, stopping\n"); + } + state->repterminationtype = 1; + goto lbl_5; + } + if( state->dotrace ) + { + ae_trace(">> expanding neighborhood, %0d new neighbor(s), |neighborhood|=%0d\n", + (int)(newneighbors), + (int)(state->xcneighborscnt)); + } + goto lbl_4; +lbl_5: + if( state->repterminationtype!=0 ) + { + goto lbl_3; + } + goto lbl_2; +lbl_3: + mirbfvns_gridoffloadbestpoint(&state->grid, state, state->nodec, &state->xc, &k, &state->fc, &state->hc, &state->mxc, _state); + if( ae_fp_greater(state->mxc,state->ctol) ) + { + state->repterminationtype = icase2(state->outofbudget, -33, -3, _state); + } + stimerstop(&state->timerglobal, _state); + if( state->doanytrace ) + { + ae_trace("\n=== STOPPED ========================================================================================\n"); + ae_trace("raw target: %20.12e\n", + (double)(state->fc)); + ae_trace("max.violation: %20.12e\n", + (double)(state->mxc)); + ae_trace("evaluations: %6d\n", + (int)(state->repnfev)); + ae_trace("subsolver its: %6d\n", + (int)(state->repsubsolverits)); + ae_trace("integral nodes: %6d\n", + (int)(state->grid.nnodes)); + ae_trace("total time: %10.1f ms (wall-clock)\n", + (double)(stimergetms(&state->timerglobal, _state))); + ae_trace("\nDetailed time (wall-clock):\n"); + ae_trace("gen neighbors: %10.1f ms (wall-clock)\n", + (double)(stimergetms(&state->timerprepareneighbors, _state))); + ae_trace("propose trial: %10.1f ms (wall-clock)\n", + (double)(stimergetms(&state->timerproposetrial, _state))); + ae_trace("\nAdvanced statistics:\n"); + ae_trace("> neighborhood-generating cuts:\n"); + ae_trace("avg.time: %0.1f ms\n", + (double)((double)state->cuttimems/(double)ae_maxint(state->cutcnt, 1, _state))); + ae_trace("count: %0d\n", + (int)(state->cutcnt)); + ae_trace(">> sequential and potentially parallel rounds:\n"); + ae_trace("sequential: %0d\n", + (int)(state->dbgsequentialcutrounds)); + ae_trace("parallel: %0d\n", + (int)(state->dbgpotentiallyparallelcutrounds)); + ae_trace("> integer node explorations and continuous subspace searches (callback time not included):\n"); + ae_trace(">> initial exploration:\n"); + ae_trace("avg.time: %0.1f ms\n", + (double)((double)state->explorativetrialtimems/(double)ae_maxint(state->explorativetrialcnt, 1, _state))); + ae_trace("count: %0d\n", + (int)(state->explorativetrialcnt)); + ae_trace(">> random sampling around initial point:\n"); + ae_trace("avg.time: %0.1f ms\n", + (double)((double)state->localtrialsamplingtimems/(double)ae_maxint(state->localtrialsamplingcnt, 1, _state))); + ae_trace("count: %0d\n", + (int)(state->localtrialsamplingcnt)); + ae_trace(">> surrogate model optimizations:\n"); + ae_trace("avg.time: %0.1f ms\n", + (double)((double)state->localtrialrbftimems/(double)ae_maxint(state->localtrialrbfcnt, 1, _state))); + ae_trace("count: %0d\n", + (int)(state->localtrialrbfcnt)); + ae_trace(">> sequential and potentially parallel batches:\n"); + ae_trace("sequential: %0d\n", + (int)(state->dbgsequentialbatches)); + ae_trace("parallel: %0d\n", + (int)(state->dbgpotentiallyparallelbatches)); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = nnlc; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = j; + state->rstate.ia.ptr.p_int[4] = k; + state->rstate.ia.ptr.p_int[5] = newneighbors; + state->rstate.ia.ptr.p_int[6] = offs; + state->rstate.ba.ptr.p_bool[0] = bflag; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = v0; + state->rstate.ra.ptr.p_double[2] = v1; + state->rstate.ra.ptr.p_double[3] = lcerr; + return result; +} + + +/************************************************************************* +Clears output fields during initialization +*************************************************************************/ +static void mirbfvns_clearoutputs(mirbfvnsstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_false; + state->repnfev = 0; + state->repsubsolverits = 0; + state->repiterationscount = 0; + state->repterminationtype = 0; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void mirbfvns_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + mirbfvnsstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + state->convexityflag = 0; + critinitdefault(&state->criteria, _state); + state->adaptiveinternalparallelism = 0; + state->timeout = 0; + state->ctol = 1.0E-5; + state->epsf = 1.0E-5; + state->epsx = 1.0E-5; + state->quickepsf = 0.01; + state->n = n; + state->userterminationneeded = ae_false; + bsetallocv(n, ae_false, &state->isintegral, _state); + bsetallocv(n, ae_false, &state->isbinary, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->hasbndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->hasbndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->x0, n, _state); + ae_vector_set_length(&state->xc, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->x0.ptr.p_double[i] = x->ptr.p_double[i]; + state->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + state->hasx0 = ae_true; + state->lccnt = 0; + state->nnlc = 0; + state->nomask = ae_true; + mirbfvns_clearoutputs(state, _state); + state->explorativetrialcnt = 0; + state->explorativetrialtimems = 0; + state->localtrialsamplingcnt = 0; + state->localtrialsamplingtimems = 0; + state->localtrialrbfcnt = 0; + state->localtrialrbftimems = 0; + state->cutcnt = 0; + state->cuttimems = 0; + state->dbgpotentiallyparallelbatches = 0; + state->dbgsequentialbatches = 0; + state->dbgpotentiallyparallelcutrounds = 0; + state->dbgsequentialcutrounds = 0; + hqrndseed(8543, 7455, &state->unsafeglobalrng, _state); + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 3+1, _state); + state->rstate.stage = -1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Prepare initial point that is feasible with respect to integrality, box +and linear constraints (but may potentially violate nonlinear ones). + +X contains current approximation that is replaced by a point satisfying +constraints. Error in constraints is returned as a result. + +If it is impossible to satisfy box, integrality and linear constraints +simultaneously, an integer+box feasible point is returned, and LCErr is +set to an error at this point. + +Box and integrality constraints are assumed to be compatible. + +Returns True on success, False on failure. +*************************************************************************/ +static ae_bool mirbfvns_prepareinitialpoint(mirbfvnsstate* state, + /* Real */ ae_vector* x, + double* lcerr, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_bool result; + + *lcerr = 0.0; + + n = state->n; + result = ae_true; + *lcerr = (double)(0); + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], state->bndl.ptr.p_double[i], _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = ae_minreal(x->ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + if( state->isintegral.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = (double)(ae_round(x->ptr.p_double[i], _state)); + } + } + if( !state->haslinearlyconstrainedints ) + { + return result; + } + rsetallocm(1, n, 0.0, &state->xucuts, _state); + rsetallocm(1, n, 0.0, &state->xupoints, _state); + bsetallocv(1, ae_false, &state->xuflags, _state); + mirbfvns_findnearestintegralsubjecttocut(state, x, &state->xucuts, &state->xupoints, &state->xuflags, 0, ae_false, _state); + result = state->xuflags.ptr.p_bool[0]; + *lcerr = (double)(0); + if( result ) + { + rcopyrv(n, &state->xupoints, 0, x, _state); + } + return result; +} + + +/************************************************************************* +Given current neighborhood (one stored in State.XCNeighbors[]), prepares +up to State.BatchSize evaluation requests, depending on neighbor priorities, +statuses (unexplored or in progress) and other factors. + +The evaluation batch is stored into: +* EvalBatchSize, >=0 +* EvalBatchPoints, array[EvalBatchSize,N] +* EvalBatchNodeIdx, array[EvalBatchSize], node index in the grid +* EvalBatchNeighborIdx, array[EvalBatchSize], node index in XCNeighbors[] array +*************************************************************************/ +static void mirbfvns_prepareevaluationbatch(mirbfvnsstate* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cntu; + ae_int_t st; + ae_int_t n; + ae_bool addednodec; + ae_int_t expectedexplorationcnt; + ae_int_t expectedsamplingcnt; + ae_int_t expectedrbfcnt; + double avgexplorationtime; + double avgsamplingtime; + double avgrbftime; + double expectedexplorationtime; + double expectedsamplingtime; + double expectedrbftime; + ae_bool sufficienttime; + ae_bool sufficientcount; + + + n = state->n; + state->evalbatchsize = 0; + addednodec = ae_false; + ae_assert(state->nodec==state->xcneighbors.ptr.p_int[0]&&mirbfvns_gridgetstatus(&state->grid, state, state->xcneighbors.ptr.p_int[0], _state)!=mirbfvns_nodeunexplored, "MIRBFVNS: 989642 failed", _state); + for(i=0; i<=state->xcpriorityneighborscnt-1; i++) + { + if( state->evalbatchsizebatchsize&&mirbfvns_gridgetstatus(&state->grid, state, state->xcneighbors.ptr.p_int[i], _state)==mirbfvns_nodeunexplored ) + { + igrowappendv(state->evalbatchsize+1, &state->evalbatchnodeidx, state->xcneighbors.ptr.p_int[i], _state); + igrowappendv(state->evalbatchsize+1, &state->evalbatchneighboridx, i, _state); + state->evalbatchsize = state->evalbatchsize+1; + } + } + if( state->evalbatchsizebatchsize ) + { + cntu = 0; + for(i=state->xcpriorityneighborscnt; i<=state->xcneighborscnt-1; i++) + { + if( mirbfvns_gridgetstatus(&state->grid, state, state->xcneighbors.ptr.p_int[i], _state)==mirbfvns_nodeunexplored ) + { + igrowappendv(cntu+1, &state->tmpeb0, state->xcneighbors.ptr.p_int[i], _state); + igrowappendv(cntu+1, &state->tmpeb2, i, _state); + cntu = cntu+1; + } + } + for(i=0; i<=cntu-2; i++) + { + j = i+hqrnduniformi(&state->unsafeglobalrng, cntu-i, _state); + k = state->tmpeb0.ptr.p_int[i]; + state->tmpeb0.ptr.p_int[i] = state->tmpeb0.ptr.p_int[j]; + state->tmpeb0.ptr.p_int[j] = k; + k = state->tmpeb2.ptr.p_int[i]; + state->tmpeb2.ptr.p_int[i] = state->tmpeb2.ptr.p_int[j]; + state->tmpeb2.ptr.p_int[j] = k; + } + i = 0; + while(state->evalbatchsizebatchsize&&ievalbatchsize+1, &state->evalbatchnodeidx, state->tmpeb0.ptr.p_int[i], _state); + igrowappendv(state->evalbatchsize+1, &state->evalbatchneighboridx, state->tmpeb2.ptr.p_int[i], _state); + state->evalbatchsize = state->evalbatchsize+1; + i = i+1; + } + } + ae_assert(state->nodec==state->xcneighbors.ptr.p_int[0]&&!ilinearsearchispresent(&state->evalbatchnodeidx, 0, state->evalbatchsize, state->nodec, _state), "MIRBFVNS: 023353 failed", _state); + if( mirbfvns_gridgetstatus(&state->grid, state, state->nodec, _state)==mirbfvns_nodeinprogress ) + { + if( state->evalbatchsizebatchsize&&(state->batchsize>1||ae_fp_less(hqrnduniformr(&state->unsafeglobalrng, _state),0.5)) ) + { + igrowappendv(state->evalbatchsize+1, &state->evalbatchnodeidx, state->nodec, _state); + igrowappendv(state->evalbatchsize+1, &state->evalbatchneighboridx, 0, _state); + state->evalbatchsize = state->evalbatchsize+1; + addednodec = ae_true; + } + } + if( state->evalbatchsizebatchsize ) + { + cntu = 0; + for(i=icase2(addednodec, 1, 0, _state); i<=state->xcneighborscnt-1; i++) + { + st = mirbfvns_gridgetstatus(&state->grid, state, state->xcneighbors.ptr.p_int[i], _state); + if( (st==mirbfvns_nodeunexplored||st==mirbfvns_nodesolved)||st==mirbfvns_nodebad ) + { + continue; + } + if( st==mirbfvns_nodeinprogress ) + { + igrowappendv(cntu+1, &state->tmpeb0, state->xcneighbors.ptr.p_int[i], _state); + igrowappendv(cntu+1, &state->tmpeb2, i, _state); + cntu = cntu+1; + continue; + } + ae_assert(ae_false, "MIRBFVNS: 047402 failed", _state); + } + for(i=0; i<=cntu-2; i++) + { + j = i+hqrnduniformi(&state->unsafeglobalrng, cntu-i, _state); + k = state->tmpeb0.ptr.p_int[i]; + state->tmpeb0.ptr.p_int[i] = state->tmpeb0.ptr.p_int[j]; + state->tmpeb0.ptr.p_int[j] = k; + k = state->tmpeb2.ptr.p_int[i]; + state->tmpeb2.ptr.p_int[i] = state->tmpeb2.ptr.p_int[j]; + state->tmpeb2.ptr.p_int[j] = k; + } + i = 0; + while(state->evalbatchsizebatchsize&&ievalbatchsize+1, &state->evalbatchnodeidx, state->tmpeb0.ptr.p_int[i], _state); + igrowappendv(state->evalbatchsize+1, &state->evalbatchneighboridx, state->tmpeb2.ptr.p_int[i], _state); + state->evalbatchsize = state->evalbatchsize+1; + i = i+1; + } + } + if( state->evalbatchsize>0 ) + { + rgrowrowsfixedcolsm(state->evalbatchsize, n, &state->evalbatchpoints, _state); + iallocv(2*state->evalbatchsize, &state->tmpeb0, _state); + avgexplorationtime = (double)state->explorativetrialtimems/coalesce((double)(state->explorativetrialcnt), (double)(1), _state); + avgsamplingtime = (double)state->localtrialsamplingtimems/coalesce((double)(state->localtrialsamplingcnt), (double)(1), _state); + avgrbftime = (double)state->localtrialrbftimems/coalesce((double)(state->localtrialrbfcnt), (double)(1), _state); + expectedexplorationtime = (double)(0); + expectedexplorationcnt = 0; + expectedsamplingtime = (double)(0); + expectedsamplingcnt = 0; + expectedrbftime = (double)(0); + expectedrbfcnt = 0; + for(i=0; i<=state->evalbatchsize-1; i++) + { + ae_assert(state->evalbatchnodeidx.ptr.p_int[i]==state->xcneighbors.ptr.p_int[state->evalbatchneighboridx.ptr.p_int[i]], "MIRBFVNS: 089649", _state); + state->tmpeb0.ptr.p_int[2*i+0] = hqrnduniformi(&state->unsafeglobalrng, 1000000, _state); + state->tmpeb0.ptr.p_int[2*i+1] = hqrnduniformi(&state->unsafeglobalrng, 1000000, _state); + if( mirbfvns_gridgetstatus(&state->grid, state, state->evalbatchnodeidx.ptr.p_int[i], _state)==mirbfvns_nodeunexplored ) + { + expectedexplorationtime = expectedexplorationtime+avgexplorationtime; + expectedexplorationcnt = expectedexplorationcnt+1; + } + else + { + if( ae_fp_less(mirbfvns_gridgetpointscountinnode(&state->grid, state, state->evalbatchnodeidx.ptr.p_int[i], _state),(double)(state->nfrac+1)) ) + { + expectedsamplingtime = expectedsamplingtime+avgsamplingtime; + expectedsamplingcnt = expectedsamplingcnt+1; + } + else + { + expectedrbftime = expectedrbftime+avgrbftime; + expectedrbfcnt = expectedrbfcnt+1; + } + } + } + sufficienttime = ae_fp_greater((double)(state->explorativetrialtimems+state->localtrialsamplingtimems+state->localtrialrbftimems),adaptiveparallelismtimerequired(_state)); + sufficientcount = ae_fp_greater((double)(state->explorativetrialcnt+state->localtrialsamplingcnt+state->localtrialrbfcnt),adaptiveparallelismcountrequired(_state)); + if( state->adaptiveinternalparallelism>=0&&(sufficienttime||sufficientcount) ) + { + state->prepareevaluationbatchparallelism = ae_false; + state->prepareevaluationbatchparallelism = state->prepareevaluationbatchparallelism||(ae_fp_greater_eq(expectedexplorationtime,workerstartthresholdms(_state))&&expectedexplorationcnt>=2); + state->prepareevaluationbatchparallelism = state->prepareevaluationbatchparallelism||(ae_fp_greater_eq(expectedsamplingtime,workerstartthresholdms(_state))&&expectedsamplingcnt>=2); + state->prepareevaluationbatchparallelism = state->prepareevaluationbatchparallelism||(ae_fp_greater_eq(expectedrbftime,workerstartthresholdms(_state))&&expectedrbfcnt>=2); + } + stimerstartcond(&state->timerproposetrial, state->doanytrace, _state); + mirbfvns_gridparallelproposelocaltrialpoint(&state->grid, &state->grid, state, state, 0, state->evalbatchsize, ae_true, state->prepareevaluationbatchparallelism, _state); + stimerstopcond(&state->timerproposetrial, state->doanytrace, _state); + if( state->prepareevaluationbatchparallelism ) + { + state->dbgpotentiallyparallelbatches = state->dbgpotentiallyparallelbatches+1; + } + else + { + state->dbgsequentialbatches = state->dbgsequentialbatches+1; + } + } +} + + +/************************************************************************* +Expands current neighborhood (one stored in State.XCNeighbors[]) with new +neighbors + +The function returns the number of added neighbors. Zero means that the +entire integer grid was scanned. + +Changes XCNeighbors[], XCReachedFrom[], XCNeighborsCnt, XCQueryFlags[]. + +Uses XUNeighbors for temporary storage. +*************************************************************************/ +static ae_int_t mirbfvns_expandneighborhood(mirbfvnsstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t nncnt; + ae_int_t unmarked; + ae_int_t unmarkedi; + ae_int_t unsolvedcnt; + ae_int_t newunsolvedcnt; + ae_int_t st; + ae_vector xc; + ae_vector unmarkedcut; + ae_int_t idummy; + double fc; + double hc; + double mxc; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&xc, 0, sizeof(xc)); + memset(&unmarkedcut, 0, sizeof(unmarkedcut)); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&unmarkedcut, 0, DT_REAL, _state, ae_true); + + n = state->n; + ae_nxpool_retrieve(&state->rpool, &xc, _state); + ae_nxpool_retrieve(&state->rpool, &unmarkedcut, _state); + ae_assert(xc.cnt>=n&&unmarkedcut.cnt>=n, "MIRBFVNS: 944420", _state); + result = 0; + unsolvedcnt = 0; + while(unsolvedcntbatchsize) + { + unmarked = -1; + unmarkedi = -1; + for(i=0; i<=state->xcneighborscnt-1; i++) + { + if( !state->xcqueryflags.ptr.p_bool[i] ) + { + st = mirbfvns_gridgetstatus(&state->grid, state, state->xcneighbors.ptr.p_int[i], _state); + if( st==mirbfvns_nodebad||st==mirbfvns_nodeunexplored ) + { + continue; + } + ae_assert(st==mirbfvns_nodesolved||st==mirbfvns_nodeinprogress, "MIRBFVNS: 964543", _state); + if( unmarked<0||mirbfvns_gridisbetter(&state->grid, state, unmarked, state->xcneighbors.ptr.p_int[i], _state) ) + { + unmarked = state->xcneighbors.ptr.p_int[i]; + unmarkedi = i; + } + } + } + if( unmarked<0 ) + { + break; + } + mirbfvns_gridoffloadbestpoint(&state->grid, state, state->nodec, &xc, &idummy, &fc, &hc, &mxc, _state); + rcopyrv(n, &state->xcreachedbycut, unmarkedi, &unmarkedcut, _state); + mirbfvns_gridexpandcutgenerateneighbors(&state->grid, state, &xc, &unmarkedcut, &state->xcneighbors, state->xcneighborscnt, &state->xuneighbors, &state->xucuts, &state->xupoints, &nncnt, &state->xuflags, _state); + if( nncnt==0 ) + { + state->xcqueryflags.ptr.p_bool[unmarkedi] = ae_true; + continue; + } + newunsolvedcnt = 0; + for(i=0; i<=nncnt-1; i++) + { + if( mirbfvns_gridneedsevals(&state->grid, state, state->xuneighbors.ptr.p_int[i], _state) ) + { + newunsolvedcnt = newunsolvedcnt+1; + } + } + if( result!=0 ) + { + if( state->maxneighborhood>0&&state->xcneighborscnt-1+nncnt>=state->maxneighborhood ) + { + break; + } + } + state->xcqueryflags.ptr.p_bool[unmarkedi] = ae_true; + for(i=0; i<=nncnt-1; i++) + { + igrowappendv(state->xcneighborscnt+1, &state->xcneighbors, state->xuneighbors.ptr.p_int[i], _state); + igrowappendv(state->xcneighborscnt+1, &state->xcreachedfrom, unmarked, _state); + bgrowappendv(state->xcneighborscnt+1, &state->xcqueryflags, ae_false, _state); + rgrowrowsfixedcolsm(state->xcneighborscnt+1, n, &state->xcreachedbycut, _state); + rcopyrr(n, &state->xucuts, i, &state->xcreachedbycut, state->xcneighborscnt, _state); + state->xcneighborscnt = state->xcneighborscnt+1; + } + result = result+nncnt; + unsolvedcnt = unsolvedcnt+newunsolvedcnt; + } + ae_nxpool_recycle(&state->rpool, &xc, _state); + ae_nxpool_recycle(&state->rpool, &unmarkedcut, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Sum of violations of linear and nonlinear constraints. Linear ones are +scaled +*************************************************************************/ +static void mirbfvns_computeviolation2(const mirbfvnsstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double* h, + double* mx, + ae_state *_state) +{ + ae_int_t i; + double v; + double vmx; + double vs; + + *h = 0.0; + *mx = 0.0; + + unscaleandchecklc2violation(&state->s, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, x, &vs, &vmx, &i, _state); + *h = vs; + *mx = vmx; + for(i=0; i<=state->nnlc-1; i++) + { + if( ae_isfinite(state->nl.ptr.p_double[i], _state) ) + { + v = ae_maxreal(state->nl.ptr.p_double[i]-fi->ptr.p_double[1+i], 0.0, _state); + *h = *h+v; + *mx = ae_maxreal(*mx, v, _state); + } + if( ae_isfinite(state->nu.ptr.p_double[i], _state) ) + { + v = ae_maxreal(fi->ptr.p_double[1+i]-state->nu.ptr.p_double[i], 0.0, _state); + *h = *h+v; + *mx = ae_maxreal(*mx, v, _state); + } + } +} + + +/************************************************************************* +Finds integer feasible point satisfying linear constraints that is nearest +to X0, subject to integral cuts given by CutsTable[RowIdx,*]: +* CutsTable[RowIdx,i]>0 means that the lower bound on variable i is set to X0[i]+CutsTable[RowIdx,i] +* CutsTable[RowIdx,i]<0 means that the upper bound on variable i is set to X0[i]+CutsTable[RowIdx,i] +* CutsTable[RowIdx,i]=0 means that bounds on variable i are unchanged. +* CutsTable[RowIdx,i] must be integer and must be zero for fractional variables +X0 is assumed to be feasible with respect to at least box constraints. + +This function does not modify the grid, merely solves MILP subproblem and +returns its solution. If no feasible point satisfying cut can be found, +False is returned and XN is left in an undefined state. + +XN must be preallocated array long enough to store the result +*************************************************************************/ +static void mirbfvns_findnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t rowidx, + ae_bool usesafetybox, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t vidx; + mirbfvnstemporaries *buf; + ae_smart_ptr _buf; + ae_bool updatestats; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + n = state->n; + updatestats = state->doanytrace||state->adaptiveinternalparallelism>=0; + for(vidx=0; vidx<=n-1; vidx++) + { + ae_assert((cutstable->ptr.pp_double[rowidx][vidx]==(double)ae_round(cutstable->ptr.pp_double[rowidx][vidx], _state)&&(state->isintegral.ptr.p_bool[vidx]||cutstable->ptr.pp_double[rowidx][vidx]==(double)0))&&(!state->isintegral.ptr.p_bool[vidx]||x0->ptr.p_double[vidx]==(double)ae_round(x0->ptr.p_double[vidx], _state)), "MIRBFVNS: 075558", _state); + } + successflags->ptr.p_bool[rowidx] = ae_true; + for(vidx=0; vidx<=n-1; vidx++) + { + resultstable->ptr.pp_double[rowidx][vidx] = x0->ptr.p_double[vidx]+cutstable->ptr.pp_double[rowidx][vidx]; + if( (state->hasbndl.ptr.p_bool[vidx]&&cutstable->ptr.pp_double[rowidx][vidx]<(double)0)&&resultstable->ptr.pp_double[rowidx][vidx]bndl.ptr.p_double[vidx] ) + { + successflags->ptr.p_bool[rowidx] = ae_false; + } + if( (state->hasbndu.ptr.p_bool[vidx]&&cutstable->ptr.pp_double[rowidx][vidx]>(double)0)&&resultstable->ptr.pp_double[rowidx][vidx]>state->bndu.ptr.p_double[vidx] ) + { + successflags->ptr.p_bool[rowidx] = ae_false; + } + } + if( successflags->ptr.p_bool[rowidx]&&state->haslinearlyconstrainedints ) + { + ae_shared_pool_retrieve(&state->tmppool, &_buf, _state); + stimerinit(&buf->localtimer, _state); + stimerstartcond(&buf->localtimer, updatestats, _state); + mirbfvns_findnearestintegralsubjecttocutx(state, x0, cutstable, resultstable, successflags, rowidx, usesafetybox, buf, _state); + stimerstopcond(&buf->localtimer, updatestats, _state); + if( updatestats ) + { + weakatomicfetchadd(&state->cutcnt, 1, _state); + weakatomicfetchadd(&state->cuttimems, stimergetmsint(&buf->localtimer, _state), _state); + } + ae_shared_pool_recycle(&state->tmppool, &_buf, _state); + } + else + { + if( updatestats ) + { + weakatomicfetchadd(&state->cutcnt, 1, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +A version of FindNearestIntegralSubjectToCut() internally called by the +function when we have a linearly constrained problem. A workhorse for +diffucult problems. +*************************************************************************/ +static void mirbfvns_findnearestintegralsubjecttocutx(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t rowidx, + ae_bool usesafetybox, + mirbfvnstemporaries* buf, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double v; + ae_int_t bbgdgroupsize; + ae_int_t nmultistarts; + ae_int_t timeout; + double smallcoeff; + + + n = state->n; + rcopyallocv(n, &state->bndl, &buf->wrkbndl, _state); + rcopyallocv(n, &state->bndu, &buf->wrkbndu, _state); + for(i=0; i<=n-1; i++) + { + if( cutstable->ptr.pp_double[rowidx][i]>(double)0 ) + { + buf->wrkbndl.ptr.p_double[i] = x0->ptr.p_double[i]+cutstable->ptr.pp_double[rowidx][i]; + } + if( cutstable->ptr.pp_double[rowidx][i]<(double)0 ) + { + buf->wrkbndu.ptr.p_double[i] = x0->ptr.p_double[i]+cutstable->ptr.pp_double[rowidx][i]; + } + if( state->isintegral.ptr.p_bool[i]&&usesafetybox ) + { + v = x0->ptr.p_double[i]-(double)mirbfvns_safetyboxforbbgd; + if( !ae_isfinite(buf->wrkbndl.ptr.p_double[i], _state)||ae_fp_less(buf->wrkbndl.ptr.p_double[i],v) ) + { + buf->wrkbndl.ptr.p_double[i] = v; + } + v = x0->ptr.p_double[i]+(double)mirbfvns_safetyboxforbbgd; + if( !ae_isfinite(buf->wrkbndu.ptr.p_double[i], _state)||ae_fp_greater(buf->wrkbndu.ptr.p_double[i],v) ) + { + buf->wrkbndu.ptr.p_double[i] = v; + } + } + } + buf->diaga.n = n; + buf->diaga.m = n; + iallocv(n+1, &buf->diaga.ridx, _state); + iallocv(n, &buf->diaga.idx, _state); + rallocv(n, &buf->diaga.vals, _state); + rallocv(n, &buf->linb, _state); + for(i=0; i<=n-1; i++) + { + buf->diaga.ridx.ptr.p_int[i] = i; + buf->diaga.idx.ptr.p_int[i] = i; + if( state->isintegral.ptr.p_bool[i] ) + { + buf->diaga.vals.ptr.p_double[i] = 1.0; + buf->linb.ptr.p_double[i] = -(x0->ptr.p_double[i]+cutstable->ptr.pp_double[rowidx][i]); + } + else + { + smallcoeff = 1.0E-5/ae_maxreal(state->s.ptr.p_double[i]*state->s.ptr.p_double[i], (double)(1), _state); + buf->diaga.vals.ptr.p_double[i] = smallcoeff; + buf->linb.ptr.p_double[i] = -x0->ptr.p_double[i]*smallcoeff; + } + } + buf->diaga.ridx.ptr.p_int[n] = n; + sparsecreatecrsinplace(&buf->diaga, _state); + bbgdgroupsize = 1; + nmultistarts = 1; + timeout = 0; + bbgdcreatebuf(n, &buf->wrkbndl, &buf->wrkbndu, &state->s, x0, &state->isintegral, &state->isbinary, &state->rawa, &state->rawal, &state->rawau, &state->lcsrcidx, state->lccnt, &state->nl, &state->nu, 0, bbgdgroupsize, nmultistarts, timeout, 0, &buf->bbgdsubsolver, _state); + bbgdsetctol(&buf->bbgdsubsolver, state->ctol, _state); + bbgdsetquadraticobjective(&buf->bbgdsubsolver, &buf->diaga, ae_false, &buf->linb, 0.0, _state); + bbgdforceserial(&buf->bbgdsubsolver, _state); + bbgdsetdiving(&buf->bbgdsubsolver, 2, _state); + bbgdsetmaxprimalcandidates(&buf->bbgdsubsolver, mirbfvns_maxprimalcandforcut, _state); + bbgdsetsoftmaxnodes(&buf->bbgdsubsolver, mirbfvns_softmaxnodescoeff*n, _state); + while(bbgditeration(&buf->bbgdsubsolver, _state)) + { + ae_assert(ae_false, "MIRBFVNS: unexpected V2 request by BBGD working in MIQP mode", _state); + } + rcopyvr(n, &buf->bbgdsubsolver.xc, resultstable, rowidx, _state); + successflags->ptr.p_bool[rowidx] = buf->bbgdsubsolver.repterminationtype>0; +} + + +/************************************************************************* +Parallel version of FindNearestIntegralSubjectToCut(). + +The half-range [R0,R1) of cuts from CutsTable[] is processed. + +IsRoot must be true on initial call (recursive calls set it to False). +TryParallelism controls whether parallel processing is used or not. +*************************************************************************/ +static void mirbfvns_parallelfindnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t r0, + ae_int_t r1, + ae_bool usesafetybox, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state) +{ + ae_int_t rmid; + + + if( r1<=r0 ) + { + return; + } + if( (isroot&&tryparallelism)&&r1-r0>=2 ) + { + if( _trypexec_mirbfvns_parallelfindnearestintegralsubjecttocut(state,x0,cutstable,resultstable,successflags,r0,r1,usesafetybox,isroot,tryparallelism, _state) ) + { + return; + } + } + if( r1==r0+1 ) + { + mirbfvns_findnearestintegralsubjecttocut(state, x0, cutstable, resultstable, successflags, r0, usesafetybox, _state); + return; + } + ae_assert(r1>r0+1, "MIRBFVNS: 705014 failed", _state); + rmid = r0+(r1-r0)/2; + mirbfvns_parallelfindnearestintegralsubjecttocut(state, x0, cutstable, resultstable, successflags, r0, rmid, usesafetybox, ae_false, tryparallelism, _state); + mirbfvns_parallelfindnearestintegralsubjecttocut(state, x0, cutstable, resultstable, successflags, rmid, r1, usesafetybox, ae_false, tryparallelism, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mirbfvns_parallelfindnearestintegralsubjecttocut(mirbfvnsstate* state, + /* Real */ const ae_vector* x0, + /* Real */ const ae_matrix* cutstable, + /* Real */ ae_matrix* resultstable, + /* Boolean */ ae_vector* successflags, + ae_int_t r0, + ae_int_t r1, + ae_bool usesafetybox, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Initializes dataset in an empty state +*************************************************************************/ +static void mirbfvns_datasetinitempty(mirbfvnsdataset* dataset, + mirbfvnsstate* state, + ae_state *_state) +{ + + + dataset->npoints = 0; + dataset->nvars = state->n; + dataset->nnlc = state->nnlc; + rgrowrowsfixedcolsm(1, dataset->nvars+1+dataset->nnlc+2, &dataset->pointinfo, _state); +} + + +/************************************************************************* +Appends point to the dataset and returns its index +*************************************************************************/ +static ae_int_t mirbfvns_datasetappendpoint(mirbfvnsdataset* dataset, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double h, + double mx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t nnlc; + ae_int_t rowidx; + ae_int_t result; + + + rgrowrowsfixedcolsm(dataset->npoints+1, dataset->nvars+1+dataset->nnlc+2, &dataset->pointinfo, _state); + rowidx = dataset->npoints; + n = dataset->nvars; + nnlc = dataset->nnlc; + for(i=0; i<=n-1; i++) + { + dataset->pointinfo.ptr.pp_double[rowidx][i] = x->ptr.p_double[i]; + } + for(i=0; i<=nnlc; i++) + { + dataset->pointinfo.ptr.pp_double[rowidx][n+i] = fi->ptr.p_double[i]; + } + dataset->pointinfo.ptr.pp_double[rowidx][n+1+nnlc+0] = h; + dataset->pointinfo.ptr.pp_double[rowidx][n+1+nnlc+1] = mx; + dataset->npoints = dataset->npoints+1; + result = rowidx; + return result; +} + + +/************************************************************************* +Initializes an integer grid using an initial point. Returns a node index, +which is likely to be zero in all implementations. + +Params: + X point + Fi objective/constraints + H sum of constraint violations + MX maximum of constraint violations +*************************************************************************/ +static ae_int_t mirbfvns_gridcreate(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + double h, + double mx, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t pointidx; + ae_int_t result; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i]&&(double)ae_round(x->ptr.p_double[i], _state)!=x->ptr.p_double[i] ) + { + ae_assert(ae_false, "MIRBFVNS: 886456 failed", _state); + } + } + pointidx = mirbfvns_datasetappendpoint(&state->dataset, x, fi, h, mx, _state); + grid->nnodes = 1; + grid->naddcols = 7; + rgrowrowsfixedcolsm(1, n+grid->naddcols, &grid->nodesinfo, _state); + rcopyvr(n, x, &grid->nodesinfo, 0, _state); + rmergemulvr(n, &state->maskint, &grid->nodesinfo, 0, _state); + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolstatus] = (double)(icase2(state->nfrac==0, mirbfvns_nodesolved, mirbfvns_nodeinprogress, _state)); + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolneighborbegin] = (double)(-1); + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolneighborend] = (double)(-1); + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolfbest] = fi->ptr.p_double[0]; + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolhbest] = h; + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncolmxbest] = mx; + grid->nodesinfo.ptr.pp_double[0][n+mirbfvns_ncollastaccepted] = (double)(pointidx); + result = 0; + grid->ptlistlength = 0; + iallocv(2, &grid->ptlistheads, _state); + grid->ptlistheads.ptr.p_int[0] = -1; + grid->ptlistheads.ptr.p_int[1] = 0; + mirbfvns_gridappendpointtolist(grid, pointidx, 0, _state); + ae_obj_array_clear(&grid->subsolvers); + if( state->nfrac>0 ) + { + mirbfvns_gridappendnilsubsolver(grid, _state); + mirbfvns_gridinitnilsubsolver(grid, state, 0, fi->ptr.p_double[0], h, mx, _state); + } + return result; +} + + +/************************************************************************* +Appends point index to the per-node points list +*************************************************************************/ +static void mirbfvns_gridappendpointtolist(mirbfvnsgrid* grid, + ae_int_t pointidx, + ae_int_t nodeidx, + ae_state *_state) +{ + ae_int_t nextentry; + ae_int_t listsize; + + + nextentry = grid->ptlistheads.ptr.p_int[2*nodeidx+0]; + listsize = grid->ptlistheads.ptr.p_int[2*nodeidx+1]; + igrowappendv(2*grid->ptlistlength+1, &grid->ptlistdata, pointidx, _state); + igrowappendv(2*grid->ptlistlength+2, &grid->ptlistdata, nextentry, _state); + grid->ptlistheads.ptr.p_int[2*nodeidx+0] = grid->ptlistlength; + grid->ptlistheads.ptr.p_int[2*nodeidx+1] = listsize+1; + grid->ptlistlength = grid->ptlistlength+1; +} + + +/************************************************************************* +Return node status by its index +*************************************************************************/ +static ae_int_t mirbfvns_gridgetstatus(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + ae_int_t result; + + + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 905114", _state); + result = ae_round(grid->nodesinfo.ptr.pp_double[nodeidx][state->n+mirbfvns_ncolstatus], _state); + return result; +} + + +/************************************************************************* +Return true of the node needs further evaluations (unexplored or in progress). +False is returned when no evaluations are needed (solved or bad). +*************************************************************************/ +static ae_bool mirbfvns_gridneedsevals(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + double k; + ae_bool result; + + + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 039445", _state); + k = grid->nodesinfo.ptr.pp_double[nodeidx][state->n+mirbfvns_ncolstatus]; + ae_assert(((ae_fp_eq(k,(double)(mirbfvns_nodeunexplored))||ae_fp_eq(k,(double)(mirbfvns_nodeinprogress)))||ae_fp_eq(k,(double)(mirbfvns_nodesolved)))||ae_fp_eq(k,(double)(mirbfvns_nodebad)), "MIRBFVNS: 935449", _state); + result = ae_fp_eq(k,(double)(mirbfvns_nodeunexplored))||ae_fp_eq(k,(double)(mirbfvns_nodeinprogress)); + return result; +} + + +/************************************************************************* +Scans integer grid for a node corresponding to a point. If no node is found, +creates a new one in a nodeUnexplored state. +*************************************************************************/ +static ae_int_t mirbfvns_gridfindorcreatenode(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_vector xm; + ae_bool isequal; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&xm, 0, sizeof(xm)); + ae_vector_init(&xm, 0, DT_REAL, _state, ae_true); + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i]&&(double)ae_round(x->ptr.p_double[i], _state)!=x->ptr.p_double[i] ) + { + ae_assert(ae_false, "MIRBFVNS: 932513 failed", _state); + } + } + ae_nxpool_retrieve(&state->rpool, &xm, _state); + ae_assert(xm.cnt>=n, "MIRBFVNS: 932514", _state); + rcopyv(n, x, &xm, _state); + rmergemulv(n, &state->maskint, &xm, _state); + for(i=0; i<=grid->nnodes-1; i++) + { + isequal = ae_true; + for(j=0; j<=n-1; j++) + { + if( !(xm.ptr.p_double[j]==grid->nodesinfo.ptr.pp_double[i][j]) ) + { + isequal = ae_false; + break; + } + } + if( isequal ) + { + result = i; + ae_frame_leave(_state); + return result; + } + } + rgrowrowsfixedcolsm(grid->nnodes+1, n+grid->naddcols, &grid->nodesinfo, _state); + rcopyvr(n, &xm, &grid->nodesinfo, grid->nnodes, _state); + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodeunexplored); + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolneighborbegin] = (double)(-1); + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolneighborend] = (double)(-1); + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolfbest] = ae_maxrealnumber; + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolhbest] = ae_maxrealnumber; + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncolmxbest] = ae_maxrealnumber; + grid->nodesinfo.ptr.pp_double[grid->nnodes][n+mirbfvns_ncollastaccepted] = (double)(-1); + igrowappendv(2*grid->nnodes+1, &grid->ptlistheads, -1, _state); + igrowappendv(2*grid->nnodes+2, &grid->ptlistheads, 0, _state); + grid->nnodes = grid->nnodes+1; + result = grid->nnodes-1; + if( state->nfrac>0 ) + { + mirbfvns_gridappendnilsubsolver(grid, _state); + } + if( state->doextratrace ) + { + ae_trace("[%6d] >>> CREATING NODE: variables mask is [", + (int)(grid->nnodes-1)); + tracerowautoprec(&grid->nodesinfo, grid->nnodes-1, 0, n, _state); + ae_trace("]\n"); + } + ae_nxpool_recycle(&state->rpool, &xm, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Scans integer grid for nodes similar to #NodeIdx. + +Here 'similar' means that: +* there is a mask of relevant variables given by VarMask[], where True + means that the variable is marked as a relevant +* a node has all relevant integer variables equal to that of #NodeIdx + (fractional ones and irrelevant integer ones are ignored) + +If PutFirst is True, then #NodeIdx is output first in the list. + +Node indexes are stored to nodeList[] array that is resized as needed, +results count is stores to nodesCnt +*************************************************************************/ +static void mirbfvns_gridfindnodeslike(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + ae_bool putfirst, + /* Boolean */ const ae_vector* varmask, + /* Integer */ ae_vector* nodeslist, + ae_int_t* nodescnt, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_bool isequal; + + *nodescnt = 0; + + n = state->n; + *nodescnt = 0; + if( putfirst ) + { + igrowappendv(*nodescnt+1, nodeslist, nodeidx, _state); + *nodescnt = *nodescnt+1; + } + for(i=0; i<=grid->nnodes-1; i++) + { + if( putfirst&&i==nodeidx ) + { + continue; + } + isequal = ae_true; + for(j=0; j<=n-1; j++) + { + if( (state->isintegral.ptr.p_bool[j]&&varmask->ptr.p_bool[j])&&!(grid->nodesinfo.ptr.pp_double[nodeidx][j]==grid->nodesinfo.ptr.pp_double[i][j]) ) + { + isequal = ae_false; + break; + } + } + if( isequal ) + { + igrowappendv(*nodescnt+1, nodeslist, i, _state); + *nodescnt = *nodescnt+1; + } + } +} + + +/************************************************************************* +Appends nil subsolver to the end of the subsolver list; no integrity checks, +internal function used by grid. +*************************************************************************/ +static void mirbfvns_gridappendnilsubsolver(mirbfvnsgrid* grid, + ae_state *_state) +{ + ae_frame _frame_block; + mirbfvnsnodesubsolver *dummy; + ae_smart_ptr _dummy; + + ae_frame_make(_state, &_frame_block); + memset(&_dummy, 0, sizeof(_dummy)); + ae_smart_ptr_init(&_dummy, (void**)&dummy, ae_false, _state, ae_true); + + ae_obj_array_append_transfer(&grid->subsolvers, &_dummy, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Replaces nil subsolver with the newly initialized one. Assumes NFrac>0. +No integrity checks, internal function used by grid. +*************************************************************************/ +static void mirbfvns_gridinitnilsubsolver(mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + double f, + double h, + double mx, + ae_state *_state) +{ + ae_frame _frame_block; + mirbfvnsnodesubsolver *subsolver; + ae_smart_ptr _subsolver; + + ae_frame_make(_state, &_frame_block); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + ae_obj_array_get(&grid->subsolvers, nodeidx, &_subsolver, _state); + ae_assert(!(subsolver!=NULL), "MIRBFVNS: 231513", _state); + subsolver = (mirbfvnsnodesubsolver*)ae_malloc(sizeof(mirbfvnsnodesubsolver), _state); /* note: using subsolver as a temporary prior to assigning its value to _subsolver */ + memset(subsolver, 0, sizeof(mirbfvnsnodesubsolver)); + _mirbfvnsnodesubsolver_init(subsolver, _state, ae_false); + ae_smart_ptr_assign(&_subsolver, subsolver, ae_true, ae_true, (ae_int_t)sizeof(mirbfvnsnodesubsolver), _mirbfvnsnodesubsolver_init_copy, _mirbfvnsnodesubsolver_destroy); + subsolver->trustrad = 1.0; + subsolver->sufficientcloudsize = ae_false; + subsolver->maxh = (double)10*ae_maxreal((double)(10), h, _state); + subsolver->historymax = iboundval(state->nfrac+1, 10, 10, _state); + rsetallocv(subsolver->historymax, 1.0E20, &subsolver->successfhistory, _state); + rsetallocv(subsolver->historymax, 1.0E20, &subsolver->successhhistory, _state); + ae_obj_array_set_transfer(&grid->subsolvers, nodeidx, &_subsolver, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns information about best point in a neighborhood. Mostly used for +debug purposes. If no neighbors are present, returns False and dummy values +(MaxRealNumber). + +Returns objective, sum(violation) and max(violation) at the best point. +*************************************************************************/ +static ae_bool mirbfvns_gridgetbestinneighborhood(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Integer */ const ae_vector* neighbors, + ae_int_t neighborscnt, + double* fbest, + double* hbest, + double* mxbest, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t idummy; + ae_vector x0; + double f; + double h; + double mx; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&x0, 0, sizeof(x0)); + *fbest = 0.0; + *hbest = 0.0; + *mxbest = 0.0; + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + + n = state->n; + ae_nxpool_retrieve(&state->rpool, &x0, _state); + ae_assert(x0.cnt>=n, "MIRBFVNS: 212354", _state); + *fbest = ae_maxrealnumber; + *hbest = ae_maxrealnumber; + *mxbest = ae_maxrealnumber; + result = ae_false; + for(i=0; i<=neighborscnt-1; i++) + { + if( mirbfvns_gridgetstatus(grid, state, neighbors->ptr.p_int[i], _state)!=mirbfvns_nodeunexplored ) + { + mirbfvns_gridoffloadbestpoint(grid, state, neighbors->ptr.p_int[i], &x0, &idummy, &f, &h, &mx, _state); + if( !result||mirbfvns_isbetterpoint(*fbest, *hbest, *mxbest, f, h, mx, state->ctol, _state) ) + { + *fbest = f; + *hbest = h; + *mxbest = mx; + result = ae_true; + } + } + } + ae_nxpool_recycle(&state->rpool, &x0, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Returns information about best last accepted point in unsolved nodes in a +neighborhood. + +Mostly used for debug purposes. If no neighbors are present, returns False +and dummy values (MaxRealNumber, -1 for node index). + +Returns objective, sum(violation) and max(violation) at the best point as +well as node index. +*************************************************************************/ +static ae_bool mirbfvns_gridgetbestlastacceptedinunsolvedneighborhood(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Integer */ const ae_vector* neighbors, + ae_int_t neighborscnt, + ae_int_t* nodeidx, + double* fbest, + double* hbest, + double* mxbest, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nnlc; + ae_int_t i; + ae_int_t st; + ae_int_t pointidx; + double f; + double h; + double mx; + ae_bool result; + + *nodeidx = 0; + *fbest = 0.0; + *hbest = 0.0; + *mxbest = 0.0; + + n = state->n; + nnlc = state->nnlc; + *nodeidx = -1; + *fbest = ae_maxrealnumber; + *hbest = ae_maxrealnumber; + *mxbest = ae_maxrealnumber; + result = ae_false; + for(i=0; i<=neighborscnt-1; i++) + { + st = ae_round(grid->nodesinfo.ptr.pp_double[neighbors->ptr.p_int[i]][state->n+mirbfvns_ncolstatus], _state); + ae_assert(((st==mirbfvns_nodeunexplored||st==mirbfvns_nodeinprogress)||st==mirbfvns_nodesolved)||st==mirbfvns_nodebad, "MIRBFVNS: 311248", _state); + if( st!=mirbfvns_nodeinprogress ) + { + continue; + } + pointidx = ae_round(grid->nodesinfo.ptr.pp_double[neighbors->ptr.p_int[i]][n+mirbfvns_ncollastaccepted], _state); + f = state->dataset.pointinfo.ptr.pp_double[pointidx][n]; + h = state->dataset.pointinfo.ptr.pp_double[pointidx][n+1+nnlc+0]; + mx = state->dataset.pointinfo.ptr.pp_double[pointidx][n+1+nnlc+1]; + if( !result||mirbfvns_isbetterpoint(*fbest, *hbest, *mxbest, f, h, mx, state->ctol, _state) ) + { + *fbest = f; + *hbest = h; + *mxbest = mx; + *nodeidx = neighbors->ptr.p_int[i]; + result = ae_true; + } + } + return result; +} + + +/************************************************************************* +Informally speaking, this function returns a list of node indexes that +correspond to up to 2N neighbors of a given node, excluding nodes in a +user-specified list. + +More precisely, the node is given by a central point of a neighborhood plus +a cut that resulted in reaching a node. The actual node is a sum of XCentral +and NodeCut. + +This function 'expands' the cut by generating many derivative cuts, querying +for nearest neighbors corresponding to these cuts, and generating a list +of both cuts and neighbors. + +This function creates new nodes with status=nodeUnexplored, if necessary +*************************************************************************/ +static void mirbfvns_gridexpandcutgenerateneighbors(mirbfvnsgrid* grid, + mirbfvnsstate* state, + /* Real */ const ae_vector* xcentral, + /* Real */ const ae_vector* nodecut, + /* Integer */ const ae_vector* excludelist, + ae_int_t excludecnt, + /* Integer */ ae_vector* neighbornodes, + /* Real */ ae_matrix* cutsapplied, + /* Real */ ae_matrix* pointsfound, + ae_int_t* nncnt, + /* Boolean */ ae_vector* tmpsuccessflags, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t vidx; + ae_int_t sidx; + ae_int_t candcnt; + ae_int_t candidx; + ae_int_t newnodeidx; + double vshift; + ae_vector xm; + ae_bool sufficienttime; + ae_bool sufficientcount; + + ae_frame_make(_state, &_frame_block); + memset(&xm, 0, sizeof(xm)); + ae_vector_init(&xm, 0, DT_REAL, _state, ae_true); + + n = state->n; + ae_nxpool_retrieve(&state->rpool, &xm, _state); + ae_assert(xm.cnt>=n, "MIRBFVNS: 937448", _state); + rgrowrowsfixedcolsm(2*n, n, cutsapplied, _state); + rgrowrowsfixedcolsm(2*n, n, pointsfound, _state); + bsetallocv(2*n, ae_false, tmpsuccessflags, _state); + candcnt = 0; + for(vidx=0; vidx<=n-1; vidx++) + { + if( !state->isintegral.ptr.p_bool[vidx] ) + { + continue; + } + for(sidx=0; sidx<=1; sidx++) + { + vshift = (double)(1-2*sidx); + if( nodecut->ptr.p_double[vidx]>(double)0&&vshift<(double)0 ) + { + continue; + } + if( nodecut->ptr.p_double[vidx]<(double)0&&vshift>(double)0 ) + { + continue; + } + if( state->hasbndl.ptr.p_bool[vidx]&&xcentral->ptr.p_double[vidx]+nodecut->ptr.p_double[vidx]+vshiftbndl.ptr.p_double[vidx] ) + { + continue; + } + if( state->hasbndu.ptr.p_bool[vidx]&&xcentral->ptr.p_double[vidx]+nodecut->ptr.p_double[vidx]+vshift>state->bndu.ptr.p_double[vidx] ) + { + continue; + } + rcopyvr(n, nodecut, cutsapplied, candcnt, _state); + cutsapplied->ptr.pp_double[candcnt][vidx] = cutsapplied->ptr.pp_double[candcnt][vidx]+vshift; + candcnt = candcnt+1; + } + } + sufficienttime = ae_fp_greater_eq((double)(state->cuttimems),adaptiveparallelismtimerequired(_state)); + sufficientcount = ae_fp_greater_eq((double)(state->cutcnt),adaptiveparallelismcountrequired(_state)); + if( state->adaptiveinternalparallelism>=0&&(sufficienttime||sufficientcount) ) + { + state->expandcutgenerateneighborsparallelism = ae_fp_greater_eq((double)state->cuttimems/coalesce((double)(state->cutcnt), (double)(1), _state)*(double)candcnt,workerstartthresholdms(_state))&&candcnt>=2; + } + stimerstartcond(&state->timerprepareneighbors, state->doanytrace, _state); + mirbfvns_parallelfindnearestintegralsubjecttocut(state, xcentral, cutsapplied, pointsfound, tmpsuccessflags, 0, candcnt, ae_true, ae_true, state->expandcutgenerateneighborsparallelism, _state); + stimerstopcond(&state->timerprepareneighbors, state->doanytrace, _state); + if( state->expandcutgenerateneighborsparallelism ) + { + state->dbgpotentiallyparallelcutrounds = state->dbgpotentiallyparallelcutrounds+1; + } + else + { + state->dbgsequentialcutrounds = state->dbgsequentialcutrounds+1; + } + *nncnt = 0; + for(candidx=0; candidx<=candcnt-1; candidx++) + { + if( !tmpsuccessflags->ptr.p_bool[candidx] ) + { + continue; + } + rcopyrv(n, pointsfound, candidx, &xm, _state); + newnodeidx = mirbfvns_gridfindorcreatenode(grid, state, &xm, _state); + if( !ilinearsearchispresent(excludelist, 0, excludecnt, newnodeidx, _state)&&!ilinearsearchispresent(neighbornodes, 0, *nncnt, newnodeidx, _state) ) + { + igrowappendv(*nncnt+1, neighbornodes, newnodeidx, _state); + if( candidx>(*nncnt) ) + { + rcopyrr(n, cutsapplied, candidx, cutsapplied, *nncnt, _state); + rcopyrr(n, pointsfound, candidx, pointsfound, *nncnt, _state); + } + *nncnt = *nncnt+1; + } + } + ae_nxpool_recycle(&state->rpool, &xm, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Parallel version of the gridProposeLocalTrialPoint(). + +For each I in half-range [R0,R1) it loads: +* node index from State.EvalBatchNodeIdx[I] +* seeds from State.tmpEB0[2*I+0] and State.tmpEB0[2*I+1] +and calls gridProposeLocalTrialPoint in parallel manner. + +IsRoot must be true on initial call (recursive calls set it to False). +TryParallelism controls whether parallel processing is used or not. +*************************************************************************/ +static void mirbfvns_gridparallelproposelocaltrialpoint(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t r0, + ae_int_t r1, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state) +{ + ae_int_t rmid; + + + if( r1<=r0 ) + { + return; + } + if( (isroot&&tryparallelism)&&r1-r0>=2 ) + { + if( _trypexec_mirbfvns_gridparallelproposelocaltrialpoint(grid,sharedgrid,state,sharedstate,r0,r1,isroot,tryparallelism, _state) ) + { + return; + } + } + if( r1==r0+1 ) + { + if( mirbfvns_gridgetstatus(&state->grid, state, state->evalbatchnodeidx.ptr.p_int[r0], _state)==mirbfvns_nodeunexplored ) + { + mirbfvns_gridproposetrialpointwhenexploringfrom(grid, sharedgrid, state, sharedstate, state->evalbatchnodeidx.ptr.p_int[r0], state->xcreachedfrom.ptr.p_int[state->evalbatchneighboridx.ptr.p_int[r0]], state->tmpeb0.ptr.p_int[2*r0+0], state->tmpeb0.ptr.p_int[2*r0+1], r0, _state); + return; + } + if( state->nomask ) + { + mirbfvns_gridproposelocaltrialpointnomask(grid, sharedgrid, state, sharedstate, state->evalbatchnodeidx.ptr.p_int[r0], state->tmpeb0.ptr.p_int[2*r0+0], state->tmpeb0.ptr.p_int[2*r0+1], r0, _state); + } + else + { + mirbfvns_gridproposelocaltrialpointmasked(grid, sharedgrid, state, sharedstate, state->evalbatchnodeidx.ptr.p_int[r0], state->tmpeb0.ptr.p_int[2*r0+0], state->tmpeb0.ptr.p_int[2*r0+1], r0, _state); + } + return; + } + ae_assert(r1>r0+1, "MIRBFVNS: 190337 failed", _state); + rmid = r0+(r1-r0)/2; + mirbfvns_gridparallelproposelocaltrialpoint(grid, sharedgrid, state, sharedstate, r0, rmid, ae_false, tryparallelism, _state); + mirbfvns_gridparallelproposelocaltrialpoint(grid, sharedgrid, state, sharedstate, rmid, r1, ae_false, tryparallelism, _state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_mirbfvns_gridparallelproposelocaltrialpoint(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t r0, + ae_int_t r1, + ae_bool isroot, + ae_bool tryparallelism, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Having node with status=nodeInProgress, proposes trial point for the +exploration. Raises an exception for nodes with statuses different from +nodeInProgress, e.g. unexplored. + +Use gridProposeTrialPointWhenExploringFrom() to start exploration of an +unexplored node. + +Grid and State are passed twice: first as a constant reference, second as +a shared one. The idea is to separate potentially thread-unsafe accesses +from read-only ones that are safe to do. + +The result is written into SharedState.EvalBatchPoints[], row EvalBatchIdx. +*************************************************************************/ +static void mirbfvns_gridproposelocaltrialpointnomask(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t nodeidx, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state) +{ + ae_frame _frame_block; + mirbfvnsnodesubsolver *subsolver; + ae_smart_ptr _subsolver; + mirbfvnstemporaries *buf; + ae_smart_ptr _buf; + double f; + double h; + ae_int_t nfrac; + ae_int_t fulln; + ae_int_t nnlc; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t ortbasissize; + ae_int_t nextlistpos; + ae_int_t npoints; + ae_int_t candidx; + ae_int_t lastacceptedidx; + ae_int_t subsolverits; + double v; + double v0; + double v1; + double mindistinf; + double vmax; + ae_bool updatestats; + + ae_frame_make(_state, &_frame_block); + memset(&_subsolver, 0, sizeof(_subsolver)); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + fulln = state->n; + nfrac = state->nfrac; + nnlc = state->nnlc; + updatestats = state->doanytrace||state->adaptiveinternalparallelism>=0; + ae_assert(state->nomask, "MIRBFVNS: 331952 failed", _state); + ae_assert(ae_fp_less_eq(mirbfvns_rbfpointtooclose,mirbfvns_rbfsktooshort)&&ae_fp_greater(mirbfvns_rbfsktooshort,(double)(0)), "MIRBFVNS: integrity check 498747 for control parameters failed", _state); + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 075437", _state); + ae_assert(mirbfvns_gridgetstatus(grid, state, nodeidx, _state)==mirbfvns_nodeinprogress, "MIRBFVNS: 076438", _state); + ae_assert(state->nfrac>0, "MIRBFVNS: 086602", _state); + ae_obj_array_get(&sharedgrid->subsolvers, nodeidx, &_subsolver, _state); + ae_assert(subsolver!=NULL, "MIRBFVNS: 266533", _state); + ae_shared_pool_retrieve(&sharedstate->tmppool, &_buf, _state); + stimerinit(&buf->localtimer, _state); + stimerstartcond(&buf->localtimer, updatestats, _state); + hqrndseed(rngseedtouse0, rngseedtouse1, &buf->localrng, _state); + isetallocv(fulln, -1, &buf->mapfull2compact, _state); + rallocv(nfrac, &buf->glbbndl, _state); + rallocv(nfrac, &buf->glbbndu, _state); + rallocv(nfrac, &buf->glbs, _state); + rsetallocv(nfrac, subsolver->trustrad, &buf->glbvtrustregion, _state); + for(i=0; i<=nfrac-1; i++) + { + j = state->idxfrac.ptr.p_int[i]; + buf->glbs.ptr.p_double[i] = state->s.ptr.p_double[j]; + buf->glbbndl.ptr.p_double[i] = state->bndl.ptr.p_double[j]; + buf->glbbndu.ptr.p_double[i] = state->bndu.ptr.p_double[j]; + buf->glbvtrustregion.ptr.p_double[i] = buf->glbvtrustregion.ptr.p_double[i]*buf->glbs.ptr.p_double[i]; + buf->mapfull2compact.ptr.p_int[j] = i; + } + npoints = 1; + rgrowrowsfixedcolsm(npoints, nfrac+1+nnlc, &buf->glbxf, _state); + rgrowrowsfixedcolsm(npoints, nfrac, &buf->glbsx, _state); + lastacceptedidx = ae_round(grid->nodesinfo.ptr.pp_double[nodeidx][fulln+mirbfvns_ncollastaccepted], _state); + rallocv(nfrac, &buf->glbx0, _state); + for(j=0; j<=nfrac-1; j++) + { + buf->glbx0.ptr.p_double[j] = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][state->idxfrac.ptr.p_int[j]]; + buf->glbxf.ptr.pp_double[0][j] = buf->glbx0.ptr.p_double[j]; + buf->glbsx.ptr.pp_double[0][j] = buf->glbx0.ptr.p_double[j]/buf->glbs.ptr.p_double[j]; + } + for(j=0; j<=nnlc; j++) + { + buf->glbxf.ptr.pp_double[0][nfrac+j] = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln+j]; + } + rallocv(fulln, &buf->fullx0, _state); + rcopyrv(fulln, &state->dataset.pointinfo, lastacceptedidx, &buf->fullx0, _state); + f = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln]; + h = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln+1+nnlc+0]; + subsolver->basef = f; + subsolver->baseh = h; + nextlistpos = grid->ptlistheads.ptr.p_int[2*nodeidx+0]; + ae_assert(nextlistpos>=0&&grid->ptlistheads.ptr.p_int[2*nodeidx+1]>0, "MIRBFVNS: 352426", _state); + while(nextlistpos>=0&&npointsptlistdata.ptr.p_int[2*nextlistpos+0]; + nextlistpos = grid->ptlistdata.ptr.p_int[2*nextlistpos+1]; + if( candidx==lastacceptedidx ) + { + continue; + } + rgrowrowsfixedcolsm(npoints+1, nfrac+1+nnlc, &buf->glbxf, _state); + rgrowrowsfixedcolsm(npoints+1, nfrac, &buf->glbsx, _state); + for(j=0; j<=nfrac-1; j++) + { + buf->glbxf.ptr.pp_double[npoints][j] = state->dataset.pointinfo.ptr.pp_double[candidx][state->idxfrac.ptr.p_int[j]]; + buf->glbsx.ptr.pp_double[npoints][j] = buf->glbxf.ptr.pp_double[npoints][j]/buf->glbs.ptr.p_double[j]; + } + for(j=0; j<=nnlc; j++) + { + buf->glbxf.ptr.pp_double[npoints][nfrac+j] = state->dataset.pointinfo.ptr.pp_double[candidx][fulln+j]; + } + if( ae_fp_greater(mirbfvns_rdistinfrr(nfrac, &buf->glbsx, npoints, &buf->glbsx, 0, _state),mirbfvns_rbfpointunacceptablyfar*subsolver->trustrad) ) + { + continue; + } + mindistinf = ae_maxrealnumber; + for(i=0; i<=npoints-1; i++) + { + mindistinf = ae_minreal(mindistinf, mirbfvns_rdistinfrr(nfrac, &buf->glbsx, npoints, &buf->glbsx, i, _state), _state); + } + if( ae_fp_less(mindistinf,mirbfvns_rbfpointtooclose*subsolver->trustrad) ) + { + continue; + } + npoints = npoints+1; + } + subsolver->sufficientcloudsize = npoints>=nfrac+1; + if( !subsolver->sufficientcloudsize ) + { + rallocv(nfrac, &buf->glbtmp0, _state); + rallocv(nfrac, &buf->glbtmp1, _state); + rallocv(nfrac, &buf->glbtmp2, _state); + rallocm(npoints-1, nfrac, &buf->ortdeltas, _state); + ortbasissize = 0; + for(i=0; i<=npoints-2; i++) + { + rcopyrv(nfrac, &buf->glbxf, i, &buf->glbtmp0, _state); + raddrv(nfrac, (double)(-1), &buf->glbxf, npoints-1, &buf->glbtmp0, _state); + v0 = ae_sqrt(rdotv2(nfrac, &buf->glbtmp0, _state), _state); + if( ae_fp_eq(v0,(double)(0)) ) + { + continue; + } + rowwisegramschmidt(&buf->ortdeltas, ortbasissize, nfrac, &buf->glbtmp0, &buf->glbtmp0, ae_false, _state); + v1 = ae_sqrt(rdotv2(nfrac, &buf->glbtmp0, _state), _state); + if( ae_fp_eq(v1,(double)(0)) ) + { + continue; + } + rmulv(nfrac, (double)1/v1, &buf->glbtmp0, _state); + rcopyvr(nfrac, &buf->glbtmp0, &buf->ortdeltas, ortbasissize, _state); + ortbasissize = ortbasissize+1; + } + rsetv(nfrac, 0.0, &buf->glbtmp1, _state); + vmax = (double)(-1); + for(k=0; k<=4; k++) + { + for(i=0; i<=nfrac-1; i++) + { + v0 = buf->glbx0.ptr.p_double[i]-buf->glbvtrustregion.ptr.p_double[i]; + v1 = buf->glbx0.ptr.p_double[i]+buf->glbvtrustregion.ptr.p_double[i]; + if( ae_isfinite(buf->glbbndl.ptr.p_double[i], _state) ) + { + v0 = ae_maxreal(v0, buf->glbbndl.ptr.p_double[i], _state); + } + if( ae_isfinite(buf->glbbndu.ptr.p_double[i], _state) ) + { + v1 = ae_minreal(v1, buf->glbbndu.ptr.p_double[i], _state); + } + buf->glbtmp0.ptr.p_double[i] = boundval(v0+(v1-v0)*hqrnduniformr(&buf->localrng, _state), v0, v1, _state); + } + rcopyv(nfrac, &buf->glbtmp0, &buf->glbtmp2, _state); + rowwisegramschmidt(&buf->ortdeltas, ortbasissize, nfrac, &buf->glbtmp2, &buf->glbtmp2, ae_false, _state); + v = rdotv2(nfrac, &buf->glbtmp2, _state); + if( ae_fp_greater_eq(v,vmax) ) + { + rcopyv(nfrac, &buf->glbtmp0, &buf->glbtmp1, _state); + vmax = v; + } + } + subsolver->skrellen = (double)(0); + for(i=0; i<=nfrac-1; i++) + { + v = buf->glbtmp1.ptr.p_double[i]; + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxfrac.ptr.p_int[i]] = v; + subsolver->skrellen = ae_maxreal(subsolver->skrellen, ae_fabs(v-buf->glbx0.ptr.p_double[i], _state)/buf->glbvtrustregion.ptr.p_double[i], _state); + } + for(i=0; i<=state->nint-1; i++) + { + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxint.ptr.p_int[i]] = grid->nodesinfo.ptr.pp_double[nodeidx][state->idxint.ptr.p_int[i]]; + } + stimerstopcond(&buf->localtimer, updatestats, _state); + if( updatestats ) + { + weakatomicfetchadd(&sharedstate->localtrialsamplingcnt, 1, _state); + weakatomicfetchadd(&sharedstate->localtrialsamplingtimems, stimergetmsint(&buf->localtimer, _state), _state); + } + } + else + { + hqrndnormalm(&buf->localrng, 1+nnlc, nfrac+1, &buf->glbrandomprior, _state); + for(i=0; i<=nnlc; i++) + { + rmergedivvr(nfrac, &buf->glbs, &buf->glbrandomprior, i, _state); + } + rallocv(1+nnlc, &buf->glbprioratx0, _state); + rgemv(1+nnlc, nfrac, 1.0, &buf->glbrandomprior, 0, &buf->glbx0, 0.0, &buf->glbprioratx0, _state); + rsetc(1+nnlc, 0.0, &buf->glbrandomprior, nfrac, _state); + for(i=0; i<=npoints-1; i++) + { + for(j=0; j<=nnlc; j++) + { + buf->glbxf.ptr.pp_double[i][nfrac+j] = buf->glbxf.ptr.pp_double[i][nfrac+j]-(rdotrr(nfrac, &buf->glbrandomprior, j, &buf->glbxf, i, _state)-buf->glbprioratx0.ptr.p_double[j]); + } + } + if( state->lccnt>0 ) + { + ae_assert(sparseiscrs(&state->rawa, _state), "MIRBFVNS: 095629 failed", _state); + rsetallocv(state->lccnt, _state->v_neginf, &buf->glbal, _state); + rsetallocv(state->lccnt, _state->v_posinf, &buf->glbau, _state); + buf->glba.m = state->lccnt; + buf->glba.n = nfrac; + iallocv(state->lccnt+1, &buf->glba.ridx, _state); + buf->glba.ridx.ptr.p_int[0] = 0; + for(i=0; i<=state->lccnt-1; i++) + { + v = 0.0; + offs = buf->glba.ridx.ptr.p_int[i]; + igrowv(offs+nfrac, &buf->glba.idx, _state); + rgrowv(offs+nfrac, &buf->glba.vals, _state); + j0 = state->rawa.ridx.ptr.p_int[i]; + j1 = state->rawa.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = state->rawa.idx.ptr.p_int[jj]; + if( !state->isintegral.ptr.p_bool[j] ) + { + buf->glba.idx.ptr.p_int[offs] = buf->mapfull2compact.ptr.p_int[j]; + buf->glba.vals.ptr.p_double[offs] = state->rawa.vals.ptr.p_double[jj]; + offs = offs+1; + } + else + { + v = v+buf->fullx0.ptr.p_double[j]*state->rawa.vals.ptr.p_double[jj]; + } + } + buf->glba.ridx.ptr.p_int[i+1] = offs; + if( ae_isfinite(state->rawal.ptr.p_double[i], _state) ) + { + buf->glbal.ptr.p_double[i] = state->rawal.ptr.p_double[i]-v; + } + if( ae_isfinite(state->rawau.ptr.p_double[i], _state) ) + { + buf->glbau.ptr.p_double[i] = state->rawau.ptr.p_double[i]-v; + } + } + sparsecreatecrsinplace(&buf->glba, _state); + } + rsetallocv(nfrac, (double)1/subsolver->trustrad, &buf->glbmultscale, _state); + rmergedivv(nfrac, &buf->glbs, &buf->glbmultscale, _state); + mirbfvns_rbfinitmodel(&buf->glbxf, &buf->glbmultscale, npoints, nfrac, 1+nnlc, &buf->glbmodel, _state); + mirbfvns_rbfaddlinearterm(&buf->glbmodel, &buf->glbrandomprior, _state); + rallocv(nfrac, &buf->glbxtrial, _state); + mirbfvns_rbfminimizemodel(&buf->glbmodel, &buf->glbx0, &buf->glbbndl, &buf->glbbndu, &buf->glbvtrustregion, subsolver->trustrad, state->ctol, mirbfvns_rbfminimizeitsperphase, ae_false, &buf->glba, &buf->glbal, &buf->glbau, state->lccnt, &state->nl, &state->nu, state->nnlc, nfrac, &buf->mmbuf, &buf->glbxtrial, &buf->glbsk, &subsolver->predf, &subsolver->predh, &subsolverits, _state); + subsolver->skrellen = (double)(0); + for(i=0; i<=nfrac-1; i++) + { + subsolver->skrellen = ae_maxreal(subsolver->skrellen, ae_fabs(buf->glbsk.ptr.p_double[i]/buf->glbvtrustregion.ptr.p_double[i], _state), _state); + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxfrac.ptr.p_int[i]] = buf->glbxtrial.ptr.p_double[i]; + } + for(i=0; i<=state->nint-1; i++) + { + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxint.ptr.p_int[i]] = grid->nodesinfo.ptr.pp_double[nodeidx][state->idxint.ptr.p_int[i]]; + } + stimerstopcond(&buf->localtimer, updatestats, _state); + weakatomicfetchadd(&sharedstate->repsubsolverits, subsolverits, _state); + if( updatestats ) + { + weakatomicfetchadd(&sharedstate->localtrialrbfcnt, 1, _state); + weakatomicfetchadd(&sharedstate->localtrialrbftimems, stimergetmsint(&buf->localtimer, _state), _state); + } + } + ae_shared_pool_recycle(&sharedstate->tmppool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Having node with status=nodeInProgress, proposes trial point for the +exploration. Raises an exception for nodes with statuses different from +nodeInProgress, e.g. unexplored. + +Use gridProposeTrialPointWhenExploringFrom() to start exploration of an +unexplored node. + +Grid and State are passed twice: first as a constant reference, second as +a shared one. The idea is to separate potentially thread-unsafe accesses +from read-only ones that are safe to do. + +The result is written into SharedState.EvalBatchPoints[], row EvalBatchIdx. +*************************************************************************/ +static void mirbfvns_gridproposelocaltrialpointmasked(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t nodeidx, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state) +{ + ae_frame _frame_block; + mirbfvnsnodesubsolver *subsolver; + ae_smart_ptr _subsolver; + mirbfvnstemporaries *buf; + ae_smart_ptr _buf; + double f; + double h; + ae_int_t fidx; + ae_int_t curnfrac; + ae_int_t fulln; + ae_int_t nnlc; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t nodescnt; + ae_int_t nextlistpos; + ae_int_t npoints; + ae_int_t candidx; + ae_int_t lastacceptedidx; + ae_int_t subsolverits; + double v; + double v0; + double v1; + double mindistinf; + double prioratx0; + ae_bool updatestats; + + ae_frame_make(_state, &_frame_block); + memset(&_subsolver, 0, sizeof(_subsolver)); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + fulln = state->n; + nnlc = state->nnlc; + updatestats = state->dotrace||state->adaptiveinternalparallelism>=0; + ae_assert(!state->nomask, "MIRBFVNS: 676607 failed", _state); + ae_assert(ae_fp_less_eq(mirbfvns_rbfpointtooclose,mirbfvns_rbfsktooshort)&&ae_fp_greater(mirbfvns_rbfsktooshort,(double)(0)), "MIRBFVNS: integrity check 498747 for control parameters failed", _state); + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 075437", _state); + ae_assert(mirbfvns_gridgetstatus(grid, state, nodeidx, _state)==mirbfvns_nodeinprogress, "MIRBFVNS: 076438", _state); + ae_assert(state->nfrac>0, "MIRBFVNS: 086602", _state); + ae_obj_array_get(&sharedgrid->subsolvers, nodeidx, &_subsolver, _state); + ae_assert(subsolver!=NULL, "MIRBFVNS: 266533", _state); + ae_shared_pool_retrieve(&sharedstate->tmppool, &_buf, _state); + stimerinit(&buf->localtimer, _state); + stimerstartcond(&buf->localtimer, updatestats, _state); + hqrndseed(rngseedtouse0, rngseedtouse1, &buf->localrng, _state); + lastacceptedidx = ae_round(grid->nodesinfo.ptr.pp_double[nodeidx][fulln+mirbfvns_ncollastaccepted], _state); + rallocv(fulln, &buf->fullx0, _state); + rcopyrv(fulln, &state->dataset.pointinfo, lastacceptedidx, &buf->fullx0, _state); + f = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln]; + h = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln+1+nnlc+0]; + subsolver->basef = f; + subsolver->baseh = h; + isetallocv(fulln, -1, &buf->mapfull2compact, _state); + rallocv(state->nfrac, &buf->glbbndl, _state); + rallocv(state->nfrac, &buf->glbbndu, _state); + rallocv(state->nfrac, &buf->glbs, _state); + rallocv(state->nfrac, &buf->glbx0, _state); + rsetallocv(state->nfrac, subsolver->trustrad, &buf->glbvtrustregion, _state); + for(i=0; i<=state->nfrac-1; i++) + { + j = state->idxfrac.ptr.p_int[i]; + buf->glbs.ptr.p_double[i] = state->s.ptr.p_double[j]; + buf->glbbndl.ptr.p_double[i] = state->bndl.ptr.p_double[j]; + buf->glbbndu.ptr.p_double[i] = state->bndu.ptr.p_double[j]; + buf->glbvtrustregion.ptr.p_double[i] = buf->glbvtrustregion.ptr.p_double[i]*buf->glbs.ptr.p_double[i]; + buf->glbx0.ptr.p_double[i] = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][state->idxfrac.ptr.p_int[i]]; + buf->mapfull2compact.ptr.p_int[j] = i; + } + rsetallocv(state->nfrac, (double)1/subsolver->trustrad, &buf->glbmultscale, _state); + rmergedivv(state->nfrac, &buf->glbs, &buf->glbmultscale, _state); + if( state->lccnt>0 ) + { + ae_assert(sparseiscrs(&state->rawa, _state), "MIRBFVNS: 095629 failed", _state); + rsetallocv(state->lccnt, _state->v_neginf, &buf->glbal, _state); + rsetallocv(state->lccnt, _state->v_posinf, &buf->glbau, _state); + buf->glba.m = state->lccnt; + buf->glba.n = state->nfrac; + iallocv(state->lccnt+1, &buf->glba.ridx, _state); + buf->glba.ridx.ptr.p_int[0] = 0; + for(i=0; i<=state->lccnt-1; i++) + { + v = 0.0; + offs = buf->glba.ridx.ptr.p_int[i]; + igrowv(offs+state->nfrac, &buf->glba.idx, _state); + rgrowv(offs+state->nfrac, &buf->glba.vals, _state); + j0 = state->rawa.ridx.ptr.p_int[i]; + j1 = state->rawa.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = state->rawa.idx.ptr.p_int[jj]; + if( !state->isintegral.ptr.p_bool[j] ) + { + buf->glba.idx.ptr.p_int[offs] = buf->mapfull2compact.ptr.p_int[j]; + buf->glba.vals.ptr.p_double[offs] = state->rawa.vals.ptr.p_double[jj]; + offs = offs+1; + } + else + { + v = v+buf->fullx0.ptr.p_double[j]*state->rawa.vals.ptr.p_double[jj]; + } + } + buf->glba.ridx.ptr.p_int[i+1] = offs; + if( ae_isfinite(state->rawal.ptr.p_double[i], _state) ) + { + buf->glbal.ptr.p_double[i] = state->rawal.ptr.p_double[i]-v; + } + if( ae_isfinite(state->rawau.ptr.p_double[i], _state) ) + { + buf->glbau.ptr.p_double[i] = state->rawau.ptr.p_double[i]-v; + } + } + sparsecreatecrsinplace(&buf->glba, _state); + } + mirbfvns_rbfinitemptysparsemodel(&buf->glbmultscale, state->nfrac, &buf->glbmodel, _state); + subsolver->sufficientcloudsize = ae_true; + for(fidx=0; fidx<=nnlc; fidx++) + { + if( state->hasmask.ptr.p_bool[fidx] ) + { + bsetallocv(fulln, ae_false, &buf->glbmask, _state); + j0 = state->varmask.ridx.ptr.p_int[fidx]; + j1 = state->varmask.ridx.ptr.p_int[fidx+1]-1; + for(jj=j0; jj<=j1; jj++) + { + buf->glbmask.ptr.p_bool[state->varmask.idx.ptr.p_int[jj]] = ae_true; + } + } + else + { + bsetallocv(fulln, ae_true, &buf->glbmask, _state); + } + iallocv(state->nfrac, &buf->lclidxfrac, _state); + iallocv(state->nfrac, &buf->lcl2glb, _state); + rallocv(state->nfrac, &buf->lcls, _state); + rallocv(state->nfrac, &buf->lclmultscale, _state); + curnfrac = 0; + for(i=0; i<=state->nfrac-1; i++) + { + if( buf->glbmask.ptr.p_bool[state->idxfrac.ptr.p_int[i]] ) + { + buf->lclidxfrac.ptr.p_int[curnfrac] = state->idxfrac.ptr.p_int[i]; + buf->lcl2glb.ptr.p_int[curnfrac] = i; + buf->lcls.ptr.p_double[curnfrac] = buf->glbs.ptr.p_double[i]; + buf->lclmultscale.ptr.p_double[curnfrac] = buf->glbmultscale.ptr.p_double[i]; + curnfrac = curnfrac+1; + } + } + if( curnfrac==0 ) + { + mirbfvns_rbfappendconstantmodel(&buf->glbmodel, state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln+fidx], _state); + continue; + } + npoints = 1; + rgrowrowsfixedcolsm(npoints, curnfrac+1, &buf->lclxf, _state); + rgrowrowsfixedcolsm(npoints, curnfrac, &buf->lclsx, _state); + for(j=0; j<=curnfrac-1; j++) + { + buf->lclxf.ptr.pp_double[0][j] = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][buf->lclidxfrac.ptr.p_int[j]]; + buf->lclsx.ptr.pp_double[0][j] = buf->lclxf.ptr.pp_double[0][j]/state->s.ptr.p_double[buf->lclidxfrac.ptr.p_int[j]]; + } + buf->lclxf.ptr.pp_double[0][curnfrac] = state->dataset.pointinfo.ptr.pp_double[lastacceptedidx][fulln+fidx]; + mirbfvns_gridfindnodeslike(grid, state, nodeidx, ae_true, &buf->glbmask, &buf->nodeslist, &nodescnt, _state); + ae_assert(nodescnt>=1&&buf->nodeslist.ptr.p_int[0]==nodeidx, "MIRBFVNS: 773613 failed", _state); + for(k=0; k<=nodescnt-1; k++) + { + if( grid->ptlistheads.ptr.p_int[2*buf->nodeslist.ptr.p_int[k]+1]==0 ) + { + continue; + } + nextlistpos = grid->ptlistheads.ptr.p_int[2*buf->nodeslist.ptr.p_int[k]+0]; + ae_assert(nextlistpos>=0&&grid->ptlistheads.ptr.p_int[2*buf->nodeslist.ptr.p_int[k]+1]>0, "MIRBFVNS: 904319", _state); + while(nextlistpos>=0&&npointsptlistdata.ptr.p_int[2*nextlistpos+0]; + nextlistpos = grid->ptlistdata.ptr.p_int[2*nextlistpos+1]; + rgrowrowsfixedcolsm(npoints+1, curnfrac+1, &buf->lclxf, _state); + rgrowrowsfixedcolsm(npoints+1, curnfrac, &buf->lclsx, _state); + for(j=0; j<=curnfrac-1; j++) + { + buf->lclxf.ptr.pp_double[npoints][j] = state->dataset.pointinfo.ptr.pp_double[candidx][buf->lclidxfrac.ptr.p_int[j]]; + buf->lclsx.ptr.pp_double[npoints][j] = buf->lclxf.ptr.pp_double[npoints][j]/state->s.ptr.p_double[buf->lclidxfrac.ptr.p_int[j]]; + } + buf->lclxf.ptr.pp_double[npoints][curnfrac] = state->dataset.pointinfo.ptr.pp_double[candidx][fulln+fidx]; + if( ae_fp_greater(mirbfvns_rdistinfrr(curnfrac, &buf->lclsx, npoints, &buf->lclsx, 0, _state),mirbfvns_rbfpointunacceptablyfar*subsolver->trustrad) ) + { + continue; + } + mindistinf = ae_maxrealnumber; + for(i=0; i<=npoints-1; i++) + { + mindistinf = ae_minreal(mindistinf, mirbfvns_rdistinfrr(curnfrac, &buf->lclsx, npoints, &buf->lclsx, i, _state), _state); + } + if( ae_fp_less(mindistinf,mirbfvns_rbfpointtooclose*subsolver->trustrad) ) + { + continue; + } + npoints = npoints+1; + } + } + subsolver->sufficientcloudsize = subsolver->sufficientcloudsize&&npoints>=curnfrac+1; + hqrndnormalm(&buf->localrng, 1, curnfrac+1, &buf->lclrandomprior, _state); + rmergedivvr(curnfrac, &buf->lcls, &buf->lclrandomprior, 0, _state); + prioratx0 = rdotrr(curnfrac, &buf->lclxf, 0, &buf->lclrandomprior, 0, _state); + buf->lclrandomprior.ptr.pp_double[0][curnfrac] = 0.0; + for(i=0; i<=npoints-1; i++) + { + buf->lclxf.ptr.pp_double[i][curnfrac] = buf->lclxf.ptr.pp_double[i][curnfrac]-(rdotrr(curnfrac, &buf->lclrandomprior, 0, &buf->lclxf, i, _state)-prioratx0); + } + mirbfvns_rbfinitmodel(&buf->lclxf, &buf->lclmultscale, npoints, curnfrac, 1, &buf->tmpmodel, _state); + mirbfvns_rbfaddlinearterm(&buf->tmpmodel, &buf->lclrandomprior, _state); + mirbfvns_rbfappendmodel(&buf->glbmodel, &buf->tmpmodel, &buf->lcl2glb, _state); + } + if( !subsolver->sufficientcloudsize ) + { + subsolver->skrellen = (double)(0); + for(i=0; i<=state->nfrac-1; i++) + { + v0 = buf->glbx0.ptr.p_double[i]-buf->glbvtrustregion.ptr.p_double[i]; + v1 = buf->glbx0.ptr.p_double[i]+buf->glbvtrustregion.ptr.p_double[i]; + if( ae_isfinite(buf->glbbndl.ptr.p_double[i], _state) ) + { + v0 = ae_maxreal(v0, buf->glbbndl.ptr.p_double[i], _state); + } + if( ae_isfinite(buf->glbbndu.ptr.p_double[i], _state) ) + { + v1 = ae_minreal(v1, buf->glbbndu.ptr.p_double[i], _state); + } + v = boundval(v0+(v1-v0)*hqrnduniformr(&buf->localrng, _state), v0, v1, _state); + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxfrac.ptr.p_int[i]] = v; + subsolver->skrellen = ae_maxreal(subsolver->skrellen, ae_fabs(v-buf->glbx0.ptr.p_double[i], _state)/buf->glbvtrustregion.ptr.p_double[i], _state); + } + for(i=0; i<=state->nint-1; i++) + { + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxint.ptr.p_int[i]] = grid->nodesinfo.ptr.pp_double[nodeidx][state->idxint.ptr.p_int[i]]; + } + stimerstopcond(&buf->localtimer, updatestats, _state); + if( updatestats ) + { + weakatomicfetchadd(&sharedstate->localtrialsamplingcnt, 1, _state); + weakatomicfetchadd(&sharedstate->localtrialsamplingtimems, stimergetmsint(&buf->localtimer, _state), _state); + } + } + else + { + rallocv(state->nfrac, &buf->glbxtrial, _state); + mirbfvns_rbfminimizemodel(&buf->glbmodel, &buf->glbx0, &buf->glbbndl, &buf->glbbndu, &buf->glbvtrustregion, subsolver->trustrad, state->ctol, mirbfvns_rbfminimizeitsperphase, ae_false, &buf->glba, &buf->glbal, &buf->glbau, state->lccnt, &state->nl, &state->nu, state->nnlc, state->nfrac, &buf->mmbuf, &buf->glbxtrial, &buf->glbsk, &subsolver->predf, &subsolver->predh, &subsolverits, _state); + subsolver->skrellen = (double)(0); + for(i=0; i<=state->nfrac-1; i++) + { + subsolver->skrellen = ae_maxreal(subsolver->skrellen, ae_fabs(buf->glbsk.ptr.p_double[i]/buf->glbvtrustregion.ptr.p_double[i], _state), _state); + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxfrac.ptr.p_int[i]] = buf->glbxtrial.ptr.p_double[i]; + } + for(i=0; i<=state->nint-1; i++) + { + sharedstate->evalbatchpoints.ptr.pp_double[evalbatchidx][state->idxint.ptr.p_int[i]] = grid->nodesinfo.ptr.pp_double[nodeidx][state->idxint.ptr.p_int[i]]; + } + stimerstopcond(&buf->localtimer, updatestats, _state); + weakatomicfetchadd(&sharedstate->repsubsolverits, subsolverits, _state); + if( updatestats ) + { + weakatomicfetchadd(&sharedstate->localtrialrbfcnt, 1, _state); + weakatomicfetchadd(&sharedstate->localtrialrbftimems, stimergetmsint(&buf->localtimer, _state), _state); + } + } + ae_shared_pool_recycle(&sharedstate->tmppool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Propose initial values of fractional variables that are used to start +exploration of node #NewNodeIdx from #ExploreFromNode. + +The function loads XTrial with fixed and fractional variables. Values of +fractional variables are derived from that at #ExploreFromNode. +*************************************************************************/ +static void mirbfvns_gridproposetrialpointwhenexploringfrom(const mirbfvnsgrid* grid, + mirbfvnsgrid* sharedgrid, + const mirbfvnsstate* state, + mirbfvnsstate* sharedstate, + ae_int_t newnodeidx, + ae_int_t explorefromnode, + ae_int_t rngseedtouse0, + ae_int_t rngseedtouse1, + ae_int_t evalbatchidx, + ae_state *_state) +{ + ae_frame _frame_block; + double f; + double h; + double mx; + ae_int_t fulln; + ae_int_t nfrac; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t bestidx; + double v; + mirbfvnstemporaries *buf; + ae_smart_ptr _buf; + ae_bool updatestats; + ae_int_t terminationtype; + + ae_frame_make(_state, &_frame_block); + memset(&_buf, 0, sizeof(_buf)); + ae_smart_ptr_init(&_buf, (void**)&buf, ae_false, _state, ae_true); + + fulln = state->n; + nfrac = state->nfrac; + updatestats = state->doanytrace||state->adaptiveinternalparallelism>=0; + ae_assert(newnodeidx>=0&&newnodeidxnnodes, "MIRBFVNS: 087602", _state); + ae_assert(explorefromnode>=0&&explorefromnodennodes, "MIRBFVNS: 088602", _state); + ae_shared_pool_retrieve(&sharedstate->tmppool, &_buf, _state); + stimerinit(&buf->localtimer, _state); + stimerstartcond(&buf->localtimer, updatestats, _state); + hqrndseed(rngseedtouse0, rngseedtouse1, &buf->localrng, _state); + if( state->nfrac==0 ) + { + rcopyrr(fulln, &grid->nodesinfo, newnodeidx, &sharedstate->evalbatchpoints, evalbatchidx, _state); + weakatomicfetchadd(&sharedstate->explorativetrialcnt, 1, _state); + ae_shared_pool_recycle(&sharedstate->tmppool, &_buf, _state); + ae_frame_leave(_state); + return; + } + mirbfvns_gridoffloadbestpoint(grid, state, explorefromnode, &buf->fullx0, &bestidx, &f, &h, &mx, _state); + for(j=0; j<=fulln-1; j++) + { + buf->fullx0.ptr.p_double[j] = state->maskfrac.ptr.p_double[j]*buf->fullx0.ptr.p_double[j]+state->maskint.ptr.p_double[j]*grid->nodesinfo.ptr.pp_double[newnodeidx][j]; + } + rcopyvr(fulln, &buf->fullx0, &sharedstate->evalbatchpoints, evalbatchidx, _state); + if( state->lccnt==0 ) + { + ae_shared_pool_recycle(&sharedstate->tmppool, &_buf, _state); + ae_frame_leave(_state); + return; + } + isetallocv(fulln, -1, &buf->mapfull2compact, _state); + rallocv(nfrac, &buf->glbbndl, _state); + rallocv(nfrac, &buf->glbbndu, _state); + rallocv(nfrac, &buf->glbs, _state); + rallocv(nfrac, &buf->glbx0, _state); + for(i=0; i<=nfrac-1; i++) + { + j = state->idxfrac.ptr.p_int[i]; + buf->glbs.ptr.p_double[i] = state->s.ptr.p_double[j]; + buf->glbx0.ptr.p_double[i] = buf->fullx0.ptr.p_double[j]; + buf->glbbndl.ptr.p_double[i] = state->bndl.ptr.p_double[j]; + buf->glbbndu.ptr.p_double[i] = state->bndu.ptr.p_double[j]; + buf->mapfull2compact.ptr.p_int[j] = i; + } + buf->diaga.n = nfrac; + buf->diaga.m = nfrac; + iallocv(nfrac+1, &buf->diaga.ridx, _state); + iallocv(nfrac, &buf->diaga.idx, _state); + rallocv(nfrac, &buf->diaga.vals, _state); + for(i=0; i<=nfrac-1; i++) + { + buf->diaga.ridx.ptr.p_int[i] = i; + buf->diaga.idx.ptr.p_int[i] = i; + buf->diaga.vals.ptr.p_double[i] = 1.0/(state->s.ptr.p_double[i]*state->s.ptr.p_double[i]); + } + buf->diaga.ridx.ptr.p_int[nfrac] = nfrac; + sparsecreatecrsinplace(&buf->diaga, _state); + rsetallocv(nfrac, 0.0, &buf->linb, _state); + ae_assert(sparseiscrs(&state->rawa, _state), "MIRBFVNS: 095629 failed", _state); + rsetallocv(state->lccnt, _state->v_neginf, &buf->glbal, _state); + rsetallocv(state->lccnt, _state->v_posinf, &buf->glbau, _state); + buf->glba.m = state->lccnt; + buf->glba.n = nfrac; + iallocv(state->lccnt+1, &buf->glba.ridx, _state); + buf->glba.ridx.ptr.p_int[0] = 0; + for(i=0; i<=state->lccnt-1; i++) + { + v = 0.0; + offs = buf->glba.ridx.ptr.p_int[i]; + igrowv(offs+nfrac, &buf->glba.idx, _state); + rgrowv(offs+nfrac, &buf->glba.vals, _state); + j0 = state->rawa.ridx.ptr.p_int[i]; + j1 = state->rawa.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = state->rawa.idx.ptr.p_int[jj]; + if( !state->isintegral.ptr.p_bool[j] ) + { + buf->glba.idx.ptr.p_int[offs] = buf->mapfull2compact.ptr.p_int[j]; + buf->glba.vals.ptr.p_double[offs] = state->rawa.vals.ptr.p_double[jj]; + offs = offs+1; + } + else + { + v = v+buf->fullx0.ptr.p_double[j]*state->rawa.vals.ptr.p_double[jj]; + } + } + buf->glba.ridx.ptr.p_int[i+1] = offs; + if( ae_isfinite(state->rawal.ptr.p_double[i], _state) ) + { + buf->glbal.ptr.p_double[i] = state->rawal.ptr.p_double[i]-v; + } + if( ae_isfinite(state->rawau.ptr.p_double[i], _state) ) + { + buf->glbau.ptr.p_double[i] = state->rawau.ptr.p_double[i]-v; + } + } + sparsecreatecrsinplace(&buf->glba, _state); + ipm2init(&buf->qpsubsolver, &buf->glbs, &buf->glbx0, nfrac, &state->densedummy2, &buf->diaga, 1, ae_false, &state->densedummy2, &buf->glbtmp0, 0, &buf->linb, 0.0, &buf->glbbndl, &buf->glbbndu, &buf->glba, state->lccnt, &state->densedummy2, 0, &buf->glbal, &buf->glbau, ae_false, ae_false, _state); + ipm2setcond(&buf->qpsubsolver, state->epsx, state->epsx, state->epsx, _state); + ipm2setmaxits(&buf->qpsubsolver, mirbfvns_maxipmits, _state); + ipm2optimize(&buf->qpsubsolver, ae_true, &buf->glbtmp0, &buf->glbtmp1, &buf->glbtmp2, &terminationtype, _state); + if( terminationtype>0 ) + { + for(i=0; i<=nfrac-1; i++) + { + buf->fullx0.ptr.p_double[state->idxfrac.ptr.p_int[i]] = buf->glbtmp0.ptr.p_double[i]; + } + } + rcopyvr(fulln, &buf->fullx0, &sharedstate->evalbatchpoints, evalbatchidx, _state); + stimerstopcond(&buf->localtimer, updatestats, _state); + if( updatestats ) + { + weakatomicfetchadd(&sharedstate->explorativetrialcnt, 1, _state); + weakatomicfetchadd(&sharedstate->explorativetrialtimems, stimergetmsint(&buf->localtimer, _state), _state); + } + ae_shared_pool_recycle(&sharedstate->tmppool, &_buf, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Having trial point corresponding to node #NodeIdx (it is not checked that +the point actually belongs to the node) and objective/constraint values +at that point, send information about trial to the node. + +Processing may involve updating node status (from unexplored to explored or +solved), but generally does not involve re-running internal subsolver +*************************************************************************/ +static void mirbfvns_gridsendtrialpointto(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t centralnodeidx, + ae_int_t nodeidx, + /* Real */ const ae_vector* xtrial, + /* Real */ const ae_vector* replyfi, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t pointidx; + ae_int_t st; + ae_int_t i; + double h; + double mx; + double v0; + double v1; + double nodefbest; + double nodehbest; + double nodemxbest; + double centralfbest; + double centralhbest; + mirbfvnsnodesubsolver *subsolver; + ae_smart_ptr _subsolver; + double preddeltaf; + double preddeltah; + ae_bool acceptablebymarkovfilter; + ae_bool sufficientdecreasef; + ae_bool sufficientdecreaseh; + + ae_frame_make(_state, &_frame_block); + memset(&_subsolver, 0, sizeof(_subsolver)); + ae_smart_ptr_init(&_subsolver, (void**)&subsolver, ae_false, _state, ae_true); + + n = state->n; + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 116651", _state); + if( !isfinitevector(replyfi, 1+state->nnlc, _state) ) + { + st = mirbfvns_gridgetstatus(grid, state, nodeidx, _state); + if( st==mirbfvns_nodeunexplored ) + { + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodebad); + } + else + { + ae_assert(st==mirbfvns_nodeinprogress&&state->nfrac>0, "MIRBFVNS: 175604", _state); + ae_obj_array_get(&grid->subsolvers, nodeidx, &_subsolver, _state); + ae_assert(subsolver!=NULL, "MIRBFVNS: 412607", _state); + if( state->doextratrace ) + { + ae_trace(">>> infinities detected, decreasing trust radius for node %0d\n", + (int)(nodeidx)); + } + subsolver->trustrad = 0.5*subsolver->trustrad; + if( ae_fp_less_eq(subsolver->trustrad,state->epsx) ) + { + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + } + ae_frame_leave(_state); + return; + } + mirbfvns_computeviolation2(state, xtrial, replyfi, &h, &mx, _state); + pointidx = mirbfvns_datasetappendpoint(&state->dataset, xtrial, replyfi, h, mx, _state); + mirbfvns_gridappendpointtolist(grid, pointidx, nodeidx, _state); + st = mirbfvns_gridgetstatus(grid, state, nodeidx, _state); + if( st==mirbfvns_nodeunexplored ) + { + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(icase2(state->nfrac==0, mirbfvns_nodesolved, mirbfvns_nodeinprogress, _state)); + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolfbest] = replyfi->ptr.p_double[0]; + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolhbest] = h; + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolmxbest] = mx; + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncollastaccepted] = (double)(pointidx); + if( state->nfrac>0 ) + { + mirbfvns_gridinitnilsubsolver(grid, state, nodeidx, replyfi->ptr.p_double[0], h, mx, _state); + } + } + else + { + ae_assert(st==mirbfvns_nodeinprogress&&state->nfrac>0, "MIRBFVNS: 117652", _state); + if( mirbfvns_isbetterpoint(grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolfbest], grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolhbest], grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolmxbest], replyfi->ptr.p_double[0], h, mx, state->ctol, _state) ) + { + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolfbest] = replyfi->ptr.p_double[0]; + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolhbest] = h; + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolmxbest] = mx; + } + ae_obj_array_get(&grid->subsolvers, nodeidx, &_subsolver, _state); + ae_assert(subsolver!=NULL, "MIRBFVNS: 412607", _state); + if( subsolver->sufficientcloudsize ) + { + preddeltaf = subsolver->predf-subsolver->basef; + preddeltah = subsolver->predh-subsolver->baseh; + sufficientdecreasef = ae_fp_less(preddeltaf,(double)(0))&&ae_fp_less(replyfi->ptr.p_double[0],subsolver->basef+mirbfvns_eta2*preddeltaf); + sufficientdecreaseh = ae_fp_less(preddeltah,(double)(0))&&ae_fp_less(h,subsolver->baseh+mirbfvns_eta2*preddeltah); + acceptablebymarkovfilter = ae_fp_less_eq(h,subsolver->maxh); + acceptablebymarkovfilter = acceptablebymarkovfilter&&(ae_fp_less(replyfi->ptr.p_double[0],subsolver->basef)||ae_fp_less(h,subsolver->baseh)); + acceptablebymarkovfilter = acceptablebymarkovfilter&&(sufficientdecreasef||sufficientdecreaseh); + if( acceptablebymarkovfilter ) + { + if( ae_fp_greater(subsolver->skrellen,mirbfvns_rbfsktooshort) ) + { + if( ae_fp_less(subsolver->predf,subsolver->basef) ) + { + if( ae_fp_greater((subsolver->basef-replyfi->ptr.p_double[0])/(subsolver->basef-subsolver->predf),mirbfvns_eta2) ) + { + subsolver->trustrad = ae_minreal(mirbfvns_gammainc*subsolver->trustrad, mirbfvns_gammainc2*(subsolver->skrellen*subsolver->trustrad), _state); + } + else + { + subsolver->trustrad = ae_maxreal(mirbfvns_gammadec, mirbfvns_gammadec2*subsolver->skrellen, _state)*subsolver->trustrad; + } + if( state->doextratrace ) + { + ae_trace("[%6d] >>> acceptable, predicted f-step, predDeltaF=%0.2e ratio=%0.2e predDeltaH=%0.2e ratio=%0.2e, trustRad:=%0.2e\n", + (int)(nodeidx), + (double)(-(subsolver->basef-subsolver->predf)), + (double)((subsolver->basef-replyfi->ptr.p_double[0])/(subsolver->basef-subsolver->predf)), + (double)(-(subsolver->baseh-subsolver->predh)), + (double)((subsolver->baseh-h)/(subsolver->baseh-subsolver->predh)), + (double)(subsolver->trustrad)); + } + } + else + { + if( ae_fp_less(subsolver->predh,subsolver->baseh)&&ae_fp_greater((subsolver->baseh-h)/(subsolver->baseh-subsolver->predh),mirbfvns_eta2) ) + { + subsolver->trustrad = ae_minreal(mirbfvns_gammainc*subsolver->trustrad, mirbfvns_gammainc2*(subsolver->skrellen*subsolver->trustrad), _state); + } + else + { + subsolver->trustrad = ae_maxreal(mirbfvns_gammadec, mirbfvns_gammadec2*subsolver->skrellen, _state)*subsolver->trustrad; + } + if( state->doextratrace ) + { + ae_trace("[%6d] >>> acceptable, predicted h-step, predDeltaF=%0.2e ratio=%0.2e predDeltaH=%0.2e ratio=%0.2e, trustRad:=%0.2e\n", + (int)(nodeidx), + (double)(-(subsolver->basef-subsolver->predf)), + (double)((subsolver->basef-replyfi->ptr.p_double[0])/(subsolver->basef-subsolver->predf)), + (double)(-(subsolver->baseh-subsolver->predh)), + (double)((subsolver->baseh-h)/(subsolver->baseh-subsolver->predh)), + (double)(subsolver->trustrad)); + } + } + } + else + { + subsolver->trustrad = ae_minreal((double)10*mirbfvns_rbfsktooshort, 0.1, _state)*subsolver->trustrad; + if( state->doextratrace ) + { + ae_trace("[%6d] >>> acceptable, Sk is too short, decreasing trustRad:=%0.2e\n", + (int)(nodeidx), + (double)(subsolver->trustrad)); + } + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncollastaccepted] = (double)(pointidx); + for(i=0; i<=subsolver->historymax-2; i++) + { + subsolver->successfhistory.ptr.p_double[i] = subsolver->successfhistory.ptr.p_double[i+1]; + } + subsolver->successfhistory.ptr.p_double[subsolver->historymax-1] = ae_fabs(replyfi->ptr.p_double[0]-subsolver->basef, _state); + for(i=0; i<=subsolver->historymax-2; i++) + { + subsolver->successhhistory.ptr.p_double[i] = subsolver->successhhistory.ptr.p_double[i+1]; + } + subsolver->successhhistory.ptr.p_double[subsolver->historymax-1] = ae_fabs(h-subsolver->baseh, _state); + } + else + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> unacceptable, DeltaF=%0.2e, DeltaH=%0.2e\n", + (int)(nodeidx), + (double)(-(subsolver->basef-replyfi->ptr.p_double[0])), + (double)(-(subsolver->baseh-h))); + } + subsolver->trustrad = ae_maxreal(mirbfvns_gammadec3, mirbfvns_gammadec2*subsolver->skrellen, _state)*subsolver->trustrad; + } + } + centralfbest = mirbfvns_gridgetfbest(grid, state, centralnodeidx, _state); + centralhbest = mirbfvns_gridgethbest(grid, state, centralnodeidx, _state); + nodefbest = mirbfvns_gridgetfbest(grid, state, nodeidx, _state); + nodehbest = mirbfvns_gridgethbest(grid, state, nodeidx, _state); + nodemxbest = mirbfvns_gridgetmxbest(grid, state, nodeidx, _state); + v0 = (double)(0); + v1 = (double)(0); + for(i=0; i<=subsolver->historymax-1; i++) + { + v0 = v0+subsolver->successfhistory.ptr.p_double[i]; + v1 = v1+subsolver->successhhistory.ptr.p_double[i]; + } + if( ae_fp_less_eq(subsolver->trustrad,state->epsx) ) + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> STOP: trust radius is small (%0.2e), marking as solved (fbest=%0.6e,maxv=%0.6e)\n", + (int)(nodeidx), + (double)(subsolver->trustrad), + (double)(nodefbest), + (double)(nodemxbest)); + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + if( ae_fp_less_eq(nodemxbest,state->ctol) ) + { + if( nodeidx==centralnodeidx ) + { + if( ae_fp_less(ae_fabs(v0, _state)*mirbfvns_habovezero,state->epsf*rmaxabs2(nodefbest, 1.0, _state)) ) + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> STOP: central node feasible, objective change is small, marking as solved (fbest=%0.6e,maxv=%0.6e)\n", + (int)(nodeidx), + (double)(nodefbest), + (double)(nodemxbest)); + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + } + else + { + if( ae_fp_greater(nodefbest-ae_fabs(v0, _state)*mirbfvns_habovezero,centralfbest)&&ae_fp_less(ae_fabs(v0, _state)*mirbfvns_habovezero,ae_maxreal(state->quickepsf, (double)2*state->epsf, _state)*rmaxabs2(nodefbest, 1.0, _state)) ) + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> STOP: neighbor node feasible and worse than central one, objective change is small, marking as solved (fbest=%0.6e,maxv=%0.6e)\n", + (int)(nodeidx), + (double)(nodefbest), + (double)(nodemxbest)); + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + } + } + else + { + if( nodeidx==centralnodeidx ) + { + if( ae_fp_greater(nodehbest-ae_fabs(v1, _state)*mirbfvns_habovezero,(double)(0))&&ae_fp_less(ae_fabs(v1, _state)*mirbfvns_habovezero,state->epsf*rmaxabs2(nodehbest, 1.0, _state)) ) + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> STOP: central node infeasible, constraint violation converged, marking as solved (fbest=%0.6e,maxv=%0.6e)\n", + (int)(nodeidx), + (double)(nodefbest), + (double)(nodemxbest)); + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + } + else + { + if( ae_fp_greater(nodehbest-ae_fabs(v1, _state)*mirbfvns_habovezero,centralhbest)&&ae_fp_less(ae_fabs(v1, _state)*mirbfvns_habovezero,ae_maxreal(state->quickepsf, (double)2*state->epsf, _state)*rmaxabs2(nodehbest, 1.0, _state)) ) + { + if( state->doextratrace ) + { + ae_trace("[%6d] >>> STOP: neighbor node infeasible and worse than central one, constraint violation converged, marking as solved (fbest=%0.6e,maxv=%0.6e)\n", + (int)(nodeidx), + (double)(nodefbest), + (double)(nodemxbest)); + } + grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus] = (double)(mirbfvns_nodesolved); + } + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Offloads best point for the grid node +*************************************************************************/ +static void mirbfvns_gridoffloadbestpoint(const mirbfvnsgrid* grid, + const mirbfvnsstate* state, + ae_int_t nodeidx, + /* Real */ ae_vector* x, + ae_int_t* pointidx, + double* f, + double* h, + double* mx, + ae_state *_state) +{ + ae_int_t n; + ae_int_t st; + ae_int_t candidx; + ae_bool firstpoint; + ae_int_t nextlistpos; + double f1; + double h1; + double mx1; + + *pointidx = 0; + *f = 0.0; + *h = 0.0; + *mx = 0.0; + + n = state->n; + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 116651", _state); + st = ae_round(grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolstatus], _state); + ae_assert(st==mirbfvns_nodesolved||st==mirbfvns_nodeinprogress, "MIRBFVNS: 171713", _state); + ae_assert(grid->ptlistheads.ptr.p_int[2*nodeidx+0]>=0&&grid->ptlistheads.ptr.p_int[2*nodeidx+1]>0, "MIRBFVNS: 171714", _state); + rallocv(n, x, _state); + *f = ae_maxrealnumber; + *h = ae_maxrealnumber; + *mx = ae_maxrealnumber; + firstpoint = ae_true; + nextlistpos = grid->ptlistheads.ptr.p_int[2*nodeidx+0]; + *pointidx = -1; + while(nextlistpos>=0) + { + candidx = grid->ptlistdata.ptr.p_int[2*nextlistpos+0]; + nextlistpos = grid->ptlistdata.ptr.p_int[2*nextlistpos+1]; + f1 = state->dataset.pointinfo.ptr.pp_double[candidx][n]; + h1 = state->dataset.pointinfo.ptr.pp_double[candidx][n+1+state->nnlc+0]; + mx1 = state->dataset.pointinfo.ptr.pp_double[candidx][n+1+state->nnlc+1]; + if( firstpoint||mirbfvns_isbetterpoint(*f, *h, *mx, f1, h1, mx1, state->ctol, _state) ) + { + rcopyrv(n, &state->dataset.pointinfo, candidx, x, _state); + *pointidx = candidx; + *f = f1; + *h = h1; + *mx = mx1; + } + firstpoint = ae_false; + } +} + + +/************************************************************************* +Compares two points, with (objective,sumviolation,maxviolation)=(F,H,MX), +and returns true if the second one is better. CTol is used to differentiate +between feasible and infeasible points. + +The base can not be in 'bad' or 'unexplored' state +*************************************************************************/ +static ae_bool mirbfvns_isbetterpoint(double f0, + double h0, + double mx0, + double f1, + double h1, + double mx1, + double ctol, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + if( mx0<=ctol&&mx1<=ctol ) + { + result = ae_fp_less(f1,f0); + } + if( mx0<=ctol&&mx1>ctol ) + { + result = ae_false; + } + if( mx0>ctol&&mx1<=ctol ) + { + result = ae_true; + } + if( mx0>ctol&&mx1>ctol ) + { + result = ae_fp_less(h1,h0-ctol); + } + return result; +} + + +/************************************************************************* +Compares two grid nodes, returns if the second one is better. + +The base can not be in 'bad' or 'unexplored' state +*************************************************************************/ +static ae_bool mirbfvns_gridisbetter(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t baseidx, + ae_int_t candidx, + ae_state *_state) +{ + ae_int_t n; + ae_int_t st0; + ae_int_t st1; + double f0; + double f1; + double h0; + double h1; + double mx0; + double mx1; + ae_bool result; + + + n = state->n; + result = ae_false; + ae_assert(((baseidx>=0&&baseidxnnodes)&&candidx>=0)&&candidxnnodes, "MIRBFVNS: 204716", _state); + st0 = ae_round(grid->nodesinfo.ptr.pp_double[baseidx][n+mirbfvns_ncolstatus], _state); + st1 = ae_round(grid->nodesinfo.ptr.pp_double[candidx][n+mirbfvns_ncolstatus], _state); + ae_assert((((st0==mirbfvns_nodeinprogress||st0==mirbfvns_nodesolved)||st0==mirbfvns_nodebad)||st0==mirbfvns_nodeunexplored)&&(((st1==mirbfvns_nodeinprogress||st1==mirbfvns_nodesolved)||st1==mirbfvns_nodebad)||st1==mirbfvns_nodeunexplored), "MIRBFVNS: 209730", _state); + if( st0==mirbfvns_nodebad||st0==mirbfvns_nodeunexplored ) + { + result = st1!=mirbfvns_nodebad&&st1!=mirbfvns_nodeunexplored; + return result; + } + if( st1==mirbfvns_nodebad||st1==mirbfvns_nodeunexplored ) + { + return result; + } + f0 = grid->nodesinfo.ptr.pp_double[baseidx][n+mirbfvns_ncolfbest]; + f1 = grid->nodesinfo.ptr.pp_double[candidx][n+mirbfvns_ncolfbest]; + h0 = grid->nodesinfo.ptr.pp_double[baseidx][n+mirbfvns_ncolhbest]; + h1 = grid->nodesinfo.ptr.pp_double[candidx][n+mirbfvns_ncolhbest]; + mx0 = grid->nodesinfo.ptr.pp_double[baseidx][n+mirbfvns_ncolmxbest]; + mx1 = grid->nodesinfo.ptr.pp_double[candidx][n+mirbfvns_ncolmxbest]; + result = mirbfvns_isbetterpoint(f0, h0, mx0, f1, h1, mx1, state->ctol, _state); + return result; +} + + +/************************************************************************* +Returns best objective for a node +*************************************************************************/ +static double mirbfvns_gridgetpointscountinnode(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + double result; + + + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 271747", _state); + result = (double)(grid->ptlistheads.ptr.p_int[2*nodeidx+1]); + return result; +} + + +/************************************************************************* +Returns best objective for a node +*************************************************************************/ +static double mirbfvns_gridgetfbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + ae_int_t n; + double result; + + + n = state->n; + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 271747", _state); + result = grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolfbest]; + return result; +} + + +/************************************************************************* +Returns best sum of violations for a node +*************************************************************************/ +static double mirbfvns_gridgethbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + ae_int_t n; + double result; + + + n = state->n; + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 271748", _state); + result = grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolhbest]; + return result; +} + + +/************************************************************************* +Returns best max of violations for a node +*************************************************************************/ +static double mirbfvns_gridgetmxbest(mirbfvnsgrid* grid, + mirbfvnsstate* state, + ae_int_t nodeidx, + ae_state *_state) +{ + ae_int_t n; + double result; + + + n = state->n; + ae_assert(nodeidx>=0&&nodeidxnnodes, "MIRBFVNS: 031236", _state); + result = grid->nodesinfo.ptr.pp_double[nodeidx][n+mirbfvns_ncolmxbest]; + return result; +} + + +/************************************************************************* +This function performs minimization of the RBF model of objective/constraints +and returns minimum as well as predicted values at the minimum + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfminimizemodel(const mirbfmodel* model, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* trustregion, + double trustradfactor, + double ctol, + ae_int_t maxitsperphase, + ae_bool autoscalemodel, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t n, + rbfmmtemporaries* buf, + /* Real */ ae_vector* xn, + /* Real */ ae_vector* sk, + double* predf, + double* predh, + ae_int_t* subsolverits, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t nnz; + ae_int_t nx; + double multiplyby; + double v; + double vax; + double predsum; + ae_bool usedensebfgs; + + *predf = 0.0; + *predh = 0.0; + *subsolverits = 0; + + nx = n+2*lccnt+2*nnlc; + multiplyby = 1.0; + critinitdefault(&buf->crit, _state); + critsetcondv1(&buf->crit, 0.0, mirbfvns_rbfsubsolverepsx, maxitsperphase, _state); + *subsolverits = 0; + rallocv(n, xn, _state); + rallocv(n, sk, _state); + usedensebfgs = ae_false; + rallocv(nx, &buf->bndlx, _state); + rallocv(nx, &buf->bndux, _state); + rallocv(nx, &buf->x0x, _state); + rallocv(nx, &buf->sx, _state); + for(i=0; i<=n-1; i++) + { + buf->bndlx.ptr.p_double[i] = x0->ptr.p_double[i]-trustregion->ptr.p_double[i]; + buf->bndux.ptr.p_double[i] = x0->ptr.p_double[i]+trustregion->ptr.p_double[i]; + if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_fp_greater(bndl->ptr.p_double[i],buf->bndlx.ptr.p_double[i]) ) + { + buf->bndlx.ptr.p_double[i] = bndl->ptr.p_double[i]; + } + if( ae_isfinite(bndu->ptr.p_double[i], _state)&&ae_fp_less(bndu->ptr.p_double[i],buf->bndux.ptr.p_double[i]) ) + { + buf->bndux.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + buf->x0x.ptr.p_double[i] = x0->ptr.p_double[i]; + buf->sx.ptr.p_double[i] = trustregion->ptr.p_double[i]; + } + for(i=n; i<=nx-1; i++) + { + buf->bndlx.ptr.p_double[i] = 0.0; + buf->bndux.ptr.p_double[i] = _state->v_posinf; + buf->sx.ptr.p_double[i] = trustradfactor*multiplyby; + buf->x0x.ptr.p_double[i] = 0.0; + } + rallocv(lccnt+1, &buf->clx, _state); + rallocv(lccnt+1, &buf->cux, _state); + sparsecreatecrsemptybuf(nx, &buf->cx, _state); + iallocv(nx, &buf->tmpi, _state); + rallocv(nx, &buf->tmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + nnz = 0; + vax = (double)(0); + for(jj=c->ridx.ptr.p_int[i]; jj<=c->ridx.ptr.p_int[i+1]-1; jj++) + { + j = c->idx.ptr.p_int[jj]; + v = c->vals.ptr.p_double[jj]; + buf->tmpi.ptr.p_int[nnz] = j; + buf->tmp0.ptr.p_double[nnz] = v; + vax = vax+v*x0->ptr.p_double[j]; + nnz = nnz+1; + } + buf->clx.ptr.p_double[i] = cl->ptr.p_double[i]; + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + buf->tmpi.ptr.p_int[nnz] = n+2*i+0; + buf->tmp0.ptr.p_double[nnz] = 1.0; + buf->x0x.ptr.p_double[n+2*i+0] = ae_maxreal(cl->ptr.p_double[i]-vax, 0.0, _state); + nnz = nnz+1; + } + buf->cux.ptr.p_double[i] = cu->ptr.p_double[i]; + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + buf->tmpi.ptr.p_int[nnz] = n+2*i+1; + buf->tmp0.ptr.p_double[nnz] = -1.0; + buf->x0x.ptr.p_double[n+2*i+1] = ae_maxreal(vax-cu->ptr.p_double[i], 0.0, _state); + nnz = nnz+1; + } + ae_assert(nnz<=nx, "RBF4OPT: integrity check 800519 failed", _state); + sparseappendcompressedrow(&buf->cx, &buf->tmpi, &buf->tmp0, nnz, _state); + } + iallocv(lccnt, &buf->tmpi, _state); + for(i=0; i<=lccnt-1; i++) + { + buf->tmpi.ptr.p_int[i] = i; + } + rallocv(1+nnlc, &buf->tmp0, _state); + rallocv((1+nnlc)*n, &buf->tmp1, _state); + mirbfvns_rbfcomputemodel(model, &buf->x0x, &buf->tmp0, ae_true, &buf->tmp1, ae_true, _state); + rsetallocv(1+nnlc, 1.0, &buf->scalingfactors, _state); + if( autoscalemodel ) + { + for(i=0; i<=nnlc; i++) + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = ae_maxreal(v, ae_fabs(buf->tmp1.ptr.p_double[i*n+j], _state), _state); + } + buf->scalingfactors.ptr.p_double[i] = (double)1/ae_maxreal(v, (double)(1), _state); + } + } + rcopyallocv(nnlc, nl, &buf->tmpnl, _state); + rcopyallocv(nnlc, nu, &buf->tmpnu, _state); + for(i=0; i<=nnlc-1; i++) + { + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + buf->tmpnl.ptr.p_double[i] = buf->tmpnl.ptr.p_double[i]*buf->scalingfactors.ptr.p_double[i+1]; + buf->x0x.ptr.p_double[n+2*lccnt+2*i+0] = ae_maxreal(buf->tmpnl.ptr.p_double[i]-buf->scalingfactors.ptr.p_double[i+1]*buf->tmp0.ptr.p_double[1+i], 0.0, _state); + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + buf->tmpnu.ptr.p_double[i] = buf->tmpnu.ptr.p_double[i]*buf->scalingfactors.ptr.p_double[i+1]; + buf->x0x.ptr.p_double[n+2*lccnt+2*i+1] = ae_maxreal(buf->scalingfactors.ptr.p_double[i+1]*buf->tmp0.ptr.p_double[1+i]-buf->tmpnu.ptr.p_double[i], 0.0, _state); + } + } + predsum = (double)(0); + if( lccnt+nnlc>0 ) + { + minfsqpinitbuf(&buf->bndlx, &buf->bndux, &buf->sx, &buf->x0x, nx, &buf->cx, &buf->clx, &buf->cux, &buf->tmpi, lccnt, &buf->tmpnl, &buf->tmpnu, nnlc, &buf->crit, usedensebfgs, &buf->fsqpsolver, _state); + minfsqpsetinittrustrad(&buf->fsqpsolver, 1.0, _state); + smoothnessmonitorinit(&buf->smonitor, &buf->sx, nx, 1+nnlc, ae_false, _state); + while(minfsqpiteration(&buf->fsqpsolver, &buf->smonitor, ae_false, _state)) + { + if( buf->fsqpsolver.xupdated ) + { + continue; + } + if( buf->fsqpsolver.needfisj ) + { + rallocv(nx, &buf->tmp0, _state); + rallocv((1+nnlc)*n, &buf->tmp1, _state); + rcopyv(nx, &buf->fsqpsolver.x, &buf->tmp0, _state); + rmergemulv(nx, &buf->sx, &buf->tmp0, _state); + rmergemaxv(nx, &buf->bndlx, &buf->tmp0, _state); + rmergeminv(nx, &buf->bndux, &buf->tmp0, _state); + mirbfvns_rbfcomputemodel(model, &buf->tmp0, &buf->fsqpsolver.fi, ae_true, &buf->tmp1, ae_true, _state); + rsetallocv((1+nnlc)*nx, 0.0, &buf->tmp2, _state); + buf->fsqpsolver.fi.ptr.p_double[0] = (double)(0); + for(j=n; j<=nx-1; j++) + { + buf->fsqpsolver.fi.ptr.p_double[0] = buf->fsqpsolver.fi.ptr.p_double[0]+buf->tmp0.ptr.p_double[j]; + buf->tmp2.ptr.p_double[j] = 1.0; + } + for(i=1; i<=nnlc; i++) + { + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]*buf->scalingfactors.ptr.p_double[i]; + rcopyvx(n, &buf->tmp1, i*n, &buf->tmp2, i*nx, _state); + rmulvx(n, buf->scalingfactors.ptr.p_double[i], &buf->tmp2, i*nx, _state); + if( ae_isfinite(nl->ptr.p_double[i-1], _state) ) + { + j = n+2*lccnt+2*(i-1)+0; + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]+buf->tmp0.ptr.p_double[j]; + buf->tmp2.ptr.p_double[i*nx+j] = 1.0; + } + if( ae_isfinite(nu->ptr.p_double[i-1], _state) ) + { + j = n+2*lccnt+2*(i-1)+1; + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]-buf->tmp0.ptr.p_double[j]; + buf->tmp2.ptr.p_double[i*nx+j] = -1.0; + } + } + sparsecreatecrsfromdensev(&buf->tmp2, 1+nnlc, nx, &buf->fsqpsolver.sj, _state); + sparsemultiplycolsby(&buf->fsqpsolver.sj, &buf->sx, _state); + continue; + } + ae_assert(ae_false, "RBF4OPT: integrity check 858514 failed", _state); + } + ae_assert(buf->fsqpsolver.repterminationtype>0, "RBF4OPT: integrity check 860514 failed", _state); + *subsolverits = *subsolverits+buf->fsqpsolver.repiterationscount; + rcopyv(nx, &buf->fsqpsolver.stepk.x, &buf->x0x, _state); + rmergemulv(nx, &buf->sx, &buf->x0x, _state); + rmergemaxv(nx, &buf->bndlx, &buf->x0x, _state); + rmergeminv(nx, &buf->bndux, &buf->x0x, _state); + predsum = (double)(0); + if( lccnt>0 ) + { + sparsemv(c, &buf->x0x, &buf->tmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + predsum = predsum+ae_maxreal(cl->ptr.p_double[i]-buf->tmp0.ptr.p_double[i], 0.0, _state); + } + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + predsum = predsum+ae_maxreal(buf->tmp0.ptr.p_double[i]-cu->ptr.p_double[i], 0.0, _state); + } + } + } + rallocv(1+nnlc, &buf->tmp1, _state); + mirbfvns_rbfcomputemodel(model, &buf->x0x, &buf->tmp1, ae_true, &buf->tmp0, ae_false, _state); + for(i=0; i<=nnlc-1; i++) + { + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + predsum = predsum+ae_maxreal(buf->tmpnl.ptr.p_double[i]-buf->tmp1.ptr.p_double[1+i]*buf->scalingfactors.ptr.p_double[1+i], 0.0, _state); + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + predsum = predsum+ae_maxreal(buf->tmp1.ptr.p_double[1+i]*buf->scalingfactors.ptr.p_double[1+i]-buf->tmpnu.ptr.p_double[i], 0.0, _state); + } + } + } + iallocv(nx, &buf->tmpi, _state); + rallocv(nx, &buf->tmp0, _state); + nnz = 0; + for(i=n; i<=nx-1; i++) + { + buf->tmpi.ptr.p_int[nnz] = i; + buf->tmp0.ptr.p_double[nnz] = 1.0; + nnz = nnz+1; + } + ae_assert(buf->clx.cnt>=lccnt+1&&buf->cux.cnt>=lccnt+1, "RBF4OPT: integrity check 889517 failed", _state); + sparseappendcompressedrow(&buf->cx, &buf->tmpi, &buf->tmp0, nnz, _state); + buf->clx.ptr.p_double[lccnt] = _state->v_neginf; + buf->cux.ptr.p_double[lccnt] = ae_maxreal(predsum, 0.1*ctol, _state); + iallocv(lccnt+1, &buf->tmpi, _state); + for(i=0; i<=lccnt; i++) + { + buf->tmpi.ptr.p_int[i] = i; + } + minfsqpinitbuf(&buf->bndlx, &buf->bndux, &buf->sx, &buf->x0x, nx, &buf->cx, &buf->clx, &buf->cux, &buf->tmpi, lccnt+1, &buf->tmpnl, &buf->tmpnu, nnlc, &buf->crit, usedensebfgs, &buf->fsqpsolver, _state); + minfsqpsetinittrustrad(&buf->fsqpsolver, 1.0, _state); + smoothnessmonitorinit(&buf->smonitor, &buf->sx, nx, 1+nnlc, ae_false, _state); + while(minfsqpiteration(&buf->fsqpsolver, &buf->smonitor, ae_false, _state)) + { + if( buf->fsqpsolver.xupdated ) + { + continue; + } + if( buf->fsqpsolver.needfisj ) + { + rallocv(nx, &buf->tmp0, _state); + rallocv((1+nnlc)*n, &buf->tmp1, _state); + rcopyv(nx, &buf->fsqpsolver.x, &buf->tmp0, _state); + rmergemulv(nx, &buf->sx, &buf->tmp0, _state); + rmergemaxv(nx, &buf->bndlx, &buf->tmp0, _state); + rmergeminv(nx, &buf->bndux, &buf->tmp0, _state); + mirbfvns_rbfcomputemodel(model, &buf->tmp0, &buf->fsqpsolver.fi, ae_true, &buf->tmp1, ae_true, _state); + rsetallocv((1+nnlc)*nx, 0.0, &buf->tmp2, _state); + buf->fsqpsolver.fi.ptr.p_double[0] = buf->fsqpsolver.fi.ptr.p_double[0]*buf->scalingfactors.ptr.p_double[0]; + rcopyvx(n, &buf->tmp1, 0, &buf->tmp2, 0, _state); + rmulvx(n, buf->scalingfactors.ptr.p_double[0], &buf->tmp2, 0, _state); + for(i=1; i<=nnlc; i++) + { + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]*buf->scalingfactors.ptr.p_double[i]; + rcopyvx(n, &buf->tmp1, i*n, &buf->tmp2, i*nx, _state); + rmulvx(n, buf->scalingfactors.ptr.p_double[i], &buf->tmp2, i*nx, _state); + if( ae_isfinite(nl->ptr.p_double[i-1], _state) ) + { + j = n+2*lccnt+2*(i-1)+0; + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]+buf->tmp0.ptr.p_double[j]; + buf->tmp2.ptr.p_double[i*nx+j] = 1.0; + } + if( ae_isfinite(nu->ptr.p_double[i-1], _state) ) + { + j = n+2*lccnt+2*(i-1)+1; + buf->fsqpsolver.fi.ptr.p_double[i] = buf->fsqpsolver.fi.ptr.p_double[i]-buf->tmp0.ptr.p_double[j]; + buf->tmp2.ptr.p_double[i*nx+j] = -1.0; + } + } + sparsecreatecrsfromdensev(&buf->tmp2, 1+nnlc, nx, &buf->fsqpsolver.sj, _state); + sparsemultiplycolsby(&buf->fsqpsolver.sj, &buf->sx, _state); + continue; + } + ae_assert(ae_false, "DFGM: integrity check 261738 failed", _state); + } + *subsolverits = *subsolverits+buf->fsqpsolver.repiterationscount; + rcopyv(n, &buf->fsqpsolver.stepk.x, &buf->x0x, _state); + rmergemulv(nx, &buf->sx, &buf->x0x, _state); + rmergemaxv(nx, &buf->bndlx, &buf->x0x, _state); + rmergeminv(nx, &buf->bndux, &buf->x0x, _state); + rcopyv(n, &buf->x0x, xn, _state); + rallocv(1+nnlc, &buf->tmp1, _state); + rcopyv(n, xn, sk, _state); + raddv(n, -1.0, x0, sk, _state); + mirbfvns_rbfcomputemodel(model, xn, &buf->tmp1, ae_true, &buf->tmp0, ae_false, _state); + *predf = buf->tmp1.ptr.p_double[0]; + *predh = (double)(0); + if( lccnt>0 ) + { + sparsemv(c, xn, &buf->tmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(cl->ptr.p_double[i]-buf->tmp0.ptr.p_double[i], 0.0, _state); + } + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(buf->tmp0.ptr.p_double[i]-cu->ptr.p_double[i], 0.0, _state); + } + } + } + for(i=0; i<=nnlc-1; i++) + { + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(nl->ptr.p_double[i]-buf->tmp1.ptr.p_double[1+i], 0.0, _state); + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(buf->tmp1.ptr.p_double[1+i]-nu->ptr.p_double[i], 0.0, _state); + } + } +} + + +/************************************************************************* +This function performs initial construction of an RBF model. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfinitmodel(/* Real */ const ae_matrix* xf, + /* Real */ const ae_vector* multscale, + ae_int_t nc, + ae_int_t n, + ae_int_t nf, + mirbfmodel* model, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t fidx; + double v; + ae_matrix rbfsys; + ae_vector sol; + ae_vector rhs; + ae_vector sol2; + ae_matrix rrhs; + ae_matrix ssol; + + ae_frame_make(_state, &_frame_block); + memset(&rbfsys, 0, sizeof(rbfsys)); + memset(&sol, 0, sizeof(sol)); + memset(&rhs, 0, sizeof(rhs)); + memset(&sol2, 0, sizeof(sol2)); + memset(&rrhs, 0, sizeof(rrhs)); + memset(&ssol, 0, sizeof(ssol)); + ae_matrix_init(&rbfsys, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sol, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rhs, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sol2, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&rrhs, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ssol, 0, 0, DT_REAL, _state, ae_true); + + ae_assert((nc>=1&&n>=1)&&nf>=1, "RBF4OPT: 234603 failed", _state); + rsetallocm(nc+n+1, nc+n+1, 0.0, &rbfsys, _state); + for(i=0; i<=nc-1; i++) + { + for(j=0; j<=i; j++) + { + v = (double)(0); + for(k=0; k<=n-1; k++) + { + v = v+ae_sqr((xf->ptr.pp_double[i][k]-xf->ptr.pp_double[j][k])*multscale->ptr.p_double[k], _state); + } + v = v*ae_sqrt(v, _state); + rbfsys.ptr.pp_double[i][j] = v; + rbfsys.ptr.pp_double[j][i] = v; + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=nc-1; j++) + { + rbfsys.ptr.pp_double[nc+i][j] = (xf->ptr.pp_double[j][i]-xf->ptr.pp_double[0][i])*multscale->ptr.p_double[i]; + rbfsys.ptr.pp_double[j][nc+i] = rbfsys.ptr.pp_double[nc+i][j]; + } + } + for(j=0; j<=nc-1; j++) + { + rbfsys.ptr.pp_double[nc+n][j] = 1.0; + rbfsys.ptr.pp_double[j][nc+n] = 1.0; + } + rallocv(nf, &model->vmodelbase, _state); + rallocv(nf, &model->vmodelscale, _state); + for(j=0; j<=nf-1; j++) + { + model->vmodelbase.ptr.p_double[j] = xf->ptr.pp_double[0][n+j]; + v = (double)(0); + for(i=0; i<=nc-1; i++) + { + v = v+ae_sqr(xf->ptr.pp_double[i][n+j]-model->vmodelbase.ptr.p_double[j], _state); + } + model->vmodelscale.ptr.p_double[j] = ae_sqrt(coalesce(v, (double)(1), _state)/(double)nc, _state); + } + model->isdense = ae_true; + model->n = n; + model->nc = nc; + model->nf = nf; + rgrowrowsfixedcolsm(nc, n, &model->centers, _state); + rcopym(nc, n, xf, &model->centers, _state); + rallocm(nf, n, &model->mx0, _state); + for(i=0; i<=nf-1; i++) + { + rcopyrr(n, xf, 0, &model->mx0, i, _state); + } + rcopyallocv(n, multscale, &model->multscale, _state); + rsetallocm(nf, nc+n+1, 0.0, &rrhs, _state); + rallocm(nf, nc, &model->crbf, _state); + rallocm(nf, n+1, &model->clinear, _state); + for(fidx=0; fidx<=nf-1; fidx++) + { + for(i=0; i<=nc-1; i++) + { + rrhs.ptr.pp_double[fidx][i] = (xf->ptr.pp_double[i][n+fidx]-model->vmodelbase.ptr.p_double[fidx])/model->vmodelscale.ptr.p_double[fidx]; + } + } + mirbfvns_rbfsolvecpdm(&rbfsys, &rrhs, nc, nf, n, 0.0, ae_true, &ssol, _state); + rcopym(nf, nc, &ssol, &model->crbf, _state); + for(fidx=0; fidx<=nf-1; fidx++) + { + for(i=0; i<=n-1; i++) + { + model->clinear.ptr.pp_double[fidx][i] = ssol.ptr.pp_double[fidx][nc+i]; + } + model->clinear.ptr.pp_double[fidx][n] = ssol.ptr.pp_double[fidx][nc+n]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs initial construction of an empty sparse RBF model. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfinitemptysparsemodel(/* Real */ const ae_vector* multscale, + ae_int_t n, + mirbfmodel* model, + ae_state *_state) +{ + + + ae_assert(n>=1, "RBF4OPT: 980221 failed", _state); + model->isdense = ae_false; + model->n = n; + model->nf = 0; + rcopyallocv(n, multscale, &model->multscale, _state); + igrowappendv(1, &model->cridx, 0, _state); + sparsecreatecrsemptybuf(n, &model->spcenters, _state); +} + + +/************************************************************************* +This function appends a constant model to a sparse RBF model. + +The sparse model is given by Model parameter, the constant model is given +by its value V. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfappendconstantmodel(mirbfmodel* model, + double v, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nf; + ae_int_t offs; + + + nf = model->nf; + n = model->n; + ae_assert(!model->isdense, "RBF4OPT: 102335 failed", _state); + rgrowappendv(nf+1, &model->vmodelbase, v, _state); + rgrowappendv(nf+1, &model->vmodelscale, 0.0, _state); + rgrowrowsfixedcolsm(nf+1, n+1, &model->clinear, _state); + rgrowrowsfixedcolsm(nf+1, n, &model->mx0, _state); + rsetr(n+1, 0.0, &model->clinear, nf, _state); + rsetr(n, 0.0, &model->mx0, nf, _state); + offs = model->cridx.ptr.p_int[model->nf]; + ae_assert(offs==model->spcenters.m, "RBF4OPT: 097316 failed", _state); + igrowappendv(nf+2, &model->cridx, offs, _state); + model->nf = nf+1; +} + + +/************************************************************************* +This function appends a dense RBF model to a potentially larger sparse one. + +The sparse model is given by Model parameter, the dense model is given by +miniModel parameter, with miniModel.N<=Model.N. The mini2full[] array +maps reduced subspace indexes in [0,miniModel.N) to a full space. + +The dense model must have NF=1. + +The function assumes (but does not check) that Model and miniModel have +the same Model.multScale[] + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfappendmodel(mirbfmodel* model, + const mirbfmodel* minimodel, + /* Integer */ const ae_vector* mini2full, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t mn; + ae_int_t nf; + ae_int_t offs; + + + nf = model->nf; + n = model->n; + mn = minimodel->n; + ae_assert(minimodel->isdense&&!model->isdense, "RBF4OPT: 061252 failed", _state); + ae_assert(minimodel->n<=model->n, "RBF4OPT: 061253 failed", _state); + ae_assert(minimodel->nf==1, "RBF4OPT: 061254 failed", _state); + rgrowappendv(nf+1, &model->vmodelbase, minimodel->vmodelbase.ptr.p_double[0], _state); + rgrowappendv(nf+1, &model->vmodelscale, minimodel->vmodelscale.ptr.p_double[0], _state); + rgrowrowsfixedcolsm(nf+1, n+1, &model->clinear, _state); + rgrowrowsfixedcolsm(nf+1, n, &model->mx0, _state); + rsetr(n, 0.0, &model->clinear, nf, _state); + rsetr(n, 0.0, &model->mx0, nf, _state); + for(i=0; i<=mn-1; i++) + { + model->clinear.ptr.pp_double[nf][mini2full->ptr.p_int[i]] = minimodel->clinear.ptr.pp_double[0][i]; + model->mx0.ptr.pp_double[nf][mini2full->ptr.p_int[i]] = minimodel->mx0.ptr.pp_double[0][i]; + } + model->clinear.ptr.pp_double[nf][n] = minimodel->clinear.ptr.pp_double[0][minimodel->n]; + offs = model->cridx.ptr.p_int[model->nf]; + ae_assert(offs==model->spcenters.m, "RBF4OPT: 097316 failed", _state); + for(i=0; i<=minimodel->nc-1; i++) + { + sparseappendemptyrow(&model->spcenters, _state); + for(j=0; j<=mn-1; j++) + { + sparseappendelement(&model->spcenters, mini2full->ptr.p_int[j], minimodel->centers.ptr.pp_double[i][j], _state); + } + rgrowappendv(offs+1, &model->spcoeffs, minimodel->crbf.ptr.pp_double[0][i], _state); + offs = offs+1; + } + igrowappendv(nf+2, &model->cridx, offs, _state); + model->nf = nf+1; +} + + +/************************************************************************* +This function modifies RBF model by adding linear function to its linear +term. + + C array[NF,N+1], one row per function, N columns for coefficients + before the x[i]-x0[i] term, one column for the constant term. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfaddlinearterm(mirbfmodel* model, + /* Real */ const ae_matrix* c, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t fidx; + double v; + + + ae_assert(model->isdense, "RBF4OPT: 133304", _state); + n = model->n; + for(fidx=0; fidx<=model->nf-1; fidx++) + { + for(k=0; k<=n-1; k++) + { + v = model->vmodelscale.ptr.p_double[fidx]*model->multscale.ptr.p_double[k]; + if( v!=(double)0 ) + { + model->clinear.ptr.pp_double[fidx][k] = model->clinear.ptr.pp_double[fidx][k]+c->ptr.pp_double[fidx][k]/v; + } + } + if( model->vmodelscale.ptr.p_double[fidx]!=(double)0 ) + { + model->clinear.ptr.pp_double[fidx][n] = model->clinear.ptr.pp_double[fidx][n]+c->ptr.pp_double[fidx][n]/model->vmodelscale.ptr.p_double[fidx]; + } + } +} + + +/************************************************************************* +This function computes RBF model at the required point. May return model +value and its gradient. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfcomputemodel(const mirbfmodel* mmodel, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* f, + ae_bool needf, + /* Real */ ae_vector* g, + ae_bool needg, + ae_state *_state) +{ + ae_int_t n; + ae_int_t j; + ae_int_t k; + ae_int_t fidx; + ae_int_t cc; + ae_int_t c0; + ae_int_t c1; + ae_int_t kk; + ae_int_t k0; + ae_int_t k1; + double v; + double r; + double vf; + double vc; + + + n = mmodel->n; + ae_assert(!needf||f->cnt>=mmodel->nf, "RBF4OPT: integrity check 419111 failed", _state); + ae_assert(!needg||g->cnt>=mmodel->nf*n, "RBF4OPT: integrity check 419112 failed", _state); + if( needf ) + { + rsetv(mmodel->nf, 0.0, f, _state); + } + if( needg ) + { + rsetv(mmodel->nf*n, 0.0, g, _state); + } + if( mmodel->isdense ) + { + for(fidx=0; fidx<=mmodel->nf-1; fidx++) + { + vf = (double)(0); + for(j=0; j<=mmodel->nc-1; j++) + { + r = (double)(0); + for(k=0; k<=n-1; k++) + { + v = (x->ptr.p_double[k]-mmodel->centers.ptr.pp_double[j][k])*mmodel->multscale.ptr.p_double[k]; + r = r+v*v; + } + r = ae_sqrt(r, _state); + vf = vf+mmodel->crbf.ptr.pp_double[fidx][j]*(r*r*r); + if( needg ) + { + for(k=0; k<=n-1; k++) + { + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+mmodel->crbf.ptr.pp_double[fidx][j]*(double)3*r*(x->ptr.p_double[k]-mmodel->centers.ptr.pp_double[j][k])*mmodel->multscale.ptr.p_double[k]*mmodel->multscale.ptr.p_double[k]; + } + } + } + for(k=0; k<=n-1; k++) + { + vf = vf+mmodel->clinear.ptr.pp_double[fidx][k]*(x->ptr.p_double[k]-mmodel->mx0.ptr.pp_double[fidx][k])*mmodel->multscale.ptr.p_double[k]; + if( needg ) + { + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+mmodel->clinear.ptr.pp_double[fidx][k]*mmodel->multscale.ptr.p_double[k]; + } + } + vf = vf+mmodel->clinear.ptr.pp_double[fidx][n]; + if( needf ) + { + f->ptr.p_double[fidx] = vf*mmodel->vmodelscale.ptr.p_double[fidx]+mmodel->vmodelbase.ptr.p_double[fidx]; + } + if( needg ) + { + rmulvx(n, mmodel->vmodelscale.ptr.p_double[fidx], g, fidx*n, _state); + } + } + } + else + { + for(fidx=0; fidx<=mmodel->nf-1; fidx++) + { + vf = (double)(0); + c0 = mmodel->cridx.ptr.p_int[fidx]; + c1 = mmodel->cridx.ptr.p_int[fidx+1]-1; + for(cc=c0; cc<=c1; cc++) + { + r = (double)(0); + k0 = mmodel->spcenters.ridx.ptr.p_int[cc]; + k1 = mmodel->spcenters.ridx.ptr.p_int[cc+1]-1; + for(kk=k0; kk<=k1; kk++) + { + k = mmodel->spcenters.idx.ptr.p_int[kk]; + v = (x->ptr.p_double[k]-mmodel->spcenters.vals.ptr.p_double[kk])*mmodel->multscale.ptr.p_double[k]; + r = r+v*v; + } + r = ae_sqrt(r, _state); + vc = mmodel->spcoeffs.ptr.p_double[cc]; + vf = vf+vc*(r*r*r); + if( needg ) + { + for(kk=k0; kk<=k1; kk++) + { + k = mmodel->spcenters.idx.ptr.p_int[kk]; + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+vc*(double)3*r*(x->ptr.p_double[k]-mmodel->spcenters.vals.ptr.p_double[kk])*mmodel->multscale.ptr.p_double[k]*mmodel->multscale.ptr.p_double[k]; + } + } + } + for(k=0; k<=n-1; k++) + { + vf = vf+mmodel->clinear.ptr.pp_double[fidx][k]*(x->ptr.p_double[k]-mmodel->mx0.ptr.pp_double[fidx][k])*mmodel->multscale.ptr.p_double[k]; + if( needg ) + { + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+mmodel->clinear.ptr.pp_double[fidx][k]*mmodel->multscale.ptr.p_double[k]; + } + } + vf = vf+mmodel->clinear.ptr.pp_double[fidx][n]; + if( needf ) + { + f->ptr.p_double[fidx] = vf*mmodel->vmodelscale.ptr.p_double[fidx]+mmodel->vmodelbase.ptr.p_double[fidx]; + } + if( needg ) + { + rmulvx(n, mmodel->vmodelscale.ptr.p_double[fidx], g, fidx*n, _state); + } + } + } +} + + +/************************************************************************* +This function solves RBF system using conditionally positive definiteness +if possible. + +INPUT PARAMETERS: + A array[NCenters+NX,NCenters], basis function matrix and + linear polynomial values + B array[NCenters], target values + NCenters centers count + NX space dimensionality + LambdaV smoothing parameter, LambdaV>=0 + isCPD whether basis is conditionally positive definite or not + + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void mirbfvns_rbfsolvecpdm(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* bb, + ae_int_t ncenters, + ae_int_t nrhs, + ae_int_t nx, + double lambdav, + ae_bool iscpd, + /* Real */ ae_matrix* ssol, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t ncoeff; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double mx; + double reg; + ae_int_t ortbasissize; + ae_matrix q; + ae_matrix q1; + ae_matrix r; + ae_vector c; + ae_vector y; + ae_vector z; + ae_vector ortbasismap; + ae_vector choltmp; + + ae_frame_make(_state, &_frame_block); + memset(&q, 0, sizeof(q)); + memset(&q1, 0, sizeof(q1)); + memset(&r, 0, sizeof(r)); + memset(&c, 0, sizeof(c)); + memset(&y, 0, sizeof(y)); + memset(&z, 0, sizeof(z)); + memset(&ortbasismap, 0, sizeof(ortbasismap)); + memset(&choltmp, 0, sizeof(choltmp)); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ortbasismap, 0, DT_INT, _state, ae_true); + ae_vector_init(&choltmp, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "DFGM: integrity check 854519 failed", _state); + ae_assert(iscpd, "DFGM: integrity check 855520 failed", _state); + ncoeff = ncenters+nx+1; + reg = ae_sqrt(ae_machineepsilon, _state); + rallocm(nx+1, nx+1, &r, _state); + rallocm(nx+1, ncenters, &q1, _state); + iallocv(nx+1, &ortbasismap, _state); + rsetr(ncenters, (double)1/ae_sqrt((double)(ncenters), _state), &q1, 0, _state); + r.ptr.pp_double[0][0] = ae_sqrt((double)(ncenters), _state); + ortbasismap.ptr.p_int[0] = nx; + ortbasissize = 1; + rallocv(ncenters, &z, _state); + for(k=0; k<=nx-1; k++) + { + for(j=0; j<=ncenters-1; j++) + { + z.ptr.p_double[j] = a->ptr.pp_double[ncenters+k][j]; + } + v = ae_sqrt(rdotv2(ncenters, &z, _state), _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_true, _state); + vv = ae_sqrt(rdotv2(ncenters, &z, _state), _state); + if( ae_fp_greater(vv,ae_sqrt(ae_machineepsilon, _state)*(v+(double)1)) ) + { + rcopymulvr(ncenters, (double)1/vv, &z, &q1, ortbasissize, _state); + rcopyvc(ortbasissize, &y, &r, ortbasissize, _state); + r.ptr.pp_double[ortbasissize][ortbasissize] = vv; + ortbasismap.ptr.p_int[ortbasissize] = k; + ortbasissize = ortbasissize+1; + } + } + rsetallocm(ncenters, ncenters, 0.0, &q, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrr(ncenters, a, i, &q, i, _state); + } + rallocm(nrhs, ncoeff, ssol, _state); + rcopym(nrhs, ncenters, bb, ssol, _state); + for(i=0; i<=ncenters-1; i++) + { + q.ptr.pp_double[i][i] = q.ptr.pp_double[i][i]+lambdav; + } + rallocv(ncenters, &z, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &q, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvr(ncenters, &z, &q, i, _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopycv(ncenters, &q, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvc(ncenters, &z, &q, i, _state); + } + for(i=0; i<=nrhs-1; i++) + { + rcopyrv(ncenters, ssol, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvr(ncenters, &z, ssol, i, _state); + } + mx = 1.0; + for(i=0; i<=ncenters-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(q.ptr.pp_double[i][i], _state), _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &q, i, &z, _state); + for(j=0; j<=ortbasissize-1; j++) + { + raddrv(ncenters, mx*q1.ptr.pp_double[j][i], &q1, j, &z, _state); + } + rcopyvr(ncenters, &z, &q, i, _state); + } + for(i=0; i<=ncenters-1; i++) + { + q.ptr.pp_double[i][i] = q.ptr.pp_double[i][i]+reg*mx; + } + if( !spdmatrixcholeskyrec(&q, 0, ncenters, ae_false, &choltmp, _state) ) + { + ae_assert(ae_false, "GENMOD: RBF solver failed due to extreme degeneracy", _state); + } + rmatrixrighttrsm(nrhs, ncenters, &q, 0, 0, ae_false, ae_false, 1, ssol, 0, 0, _state); + rmatrixrighttrsm(nrhs, ncenters, &q, 0, 0, ae_false, ae_false, 0, ssol, 0, 0, _state); + rallocv(ncenters, &z, _state); + rallocv(ncenters, &c, _state); + for(i=0; i<=nrhs-1; i++) + { + rcopyrv(ncenters, bb, i, &z, _state); + rcopyrv(ncenters, ssol, i, &c, _state); + rgemv(ncenters, ncenters, -1.0, a, 0, &c, 1.0, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_true, _state); + rmatrixtrsv(ortbasissize, &r, 0, 0, ae_true, ae_false, 0, &y, 0, _state); + for(j=0; j<=nx; j++) + { + ssol->ptr.pp_double[i][ncenters+j] = 0.0; + } + for(j=0; j<=ortbasissize-1; j++) + { + ssol->ptr.pp_double[i][ncenters+ortbasismap.ptr.p_int[j]] = y.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +static double mirbfvns_rdistinfrr(ae_int_t n, + /* Real */ const ae_matrix* a, + ae_int_t i0, + /* Real */ const ae_matrix* b, + ae_int_t i1, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=n-1; i++) + { + v = a->ptr.pp_double[i0][i]-b->ptr.pp_double[i1][i]; + result = ae_maxreal(result, ae_fabs(v, _state), _state); + } + return result; +} + + +void _mirbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfmodel *p = (mirbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->vmodelbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->vmodelscale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->multscale, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->clinear, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->mx0, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->centers, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->crbf, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cridx, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->spcenters, _state, make_automatic); + ae_vector_init(&p->spcoeffs, 0, DT_REAL, _state, make_automatic); +} + + +void _mirbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfmodel *dst = (mirbfmodel*)_dst; + const mirbfmodel *src = (const mirbfmodel*)_src; + dst->isdense = src->isdense; + dst->n = src->n; + dst->nf = src->nf; + ae_vector_init_copy(&dst->vmodelbase, &src->vmodelbase, _state, make_automatic); + ae_vector_init_copy(&dst->vmodelscale, &src->vmodelscale, _state, make_automatic); + ae_vector_init_copy(&dst->multscale, &src->multscale, _state, make_automatic); + ae_matrix_init_copy(&dst->clinear, &src->clinear, _state, make_automatic); + ae_matrix_init_copy(&dst->mx0, &src->mx0, _state, make_automatic); + dst->nc = src->nc; + ae_matrix_init_copy(&dst->centers, &src->centers, _state, make_automatic); + ae_matrix_init_copy(&dst->crbf, &src->crbf, _state, make_automatic); + ae_vector_init_copy(&dst->cridx, &src->cridx, _state, make_automatic); + _sparsematrix_init_copy(&dst->spcenters, &src->spcenters, _state, make_automatic); + ae_vector_init_copy(&dst->spcoeffs, &src->spcoeffs, _state, make_automatic); +} + + +void _mirbfmodel_clear(void* _p) +{ + mirbfmodel *p = (mirbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->vmodelbase); + ae_vector_clear(&p->vmodelscale); + ae_vector_clear(&p->multscale); + ae_matrix_clear(&p->clinear); + ae_matrix_clear(&p->mx0); + ae_matrix_clear(&p->centers); + ae_matrix_clear(&p->crbf); + ae_vector_clear(&p->cridx); + _sparsematrix_clear(&p->spcenters); + ae_vector_clear(&p->spcoeffs); +} + + +void _mirbfmodel_destroy(void* _p) +{ + mirbfmodel *p = (mirbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->vmodelbase); + ae_vector_destroy(&p->vmodelscale); + ae_vector_destroy(&p->multscale); + ae_matrix_destroy(&p->clinear); + ae_matrix_destroy(&p->mx0); + ae_matrix_destroy(&p->centers); + ae_matrix_destroy(&p->crbf); + ae_vector_destroy(&p->cridx); + _sparsematrix_destroy(&p->spcenters); + ae_vector_destroy(&p->spcoeffs); +} + + +void _mirbfvnsnodesubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsnodesubsolver *p = (mirbfvnsnodesubsolver*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->successfhistory, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->successhhistory, 0, DT_REAL, _state, make_automatic); +} + + +void _mirbfvnsnodesubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsnodesubsolver *dst = (mirbfvnsnodesubsolver*)_dst; + const mirbfvnsnodesubsolver *src = (const mirbfvnsnodesubsolver*)_src; + dst->trustrad = src->trustrad; + dst->sufficientcloudsize = src->sufficientcloudsize; + dst->basef = src->basef; + dst->baseh = src->baseh; + dst->predf = src->predf; + dst->predh = src->predh; + dst->skrellen = src->skrellen; + dst->maxh = src->maxh; + ae_vector_init_copy(&dst->successfhistory, &src->successfhistory, _state, make_automatic); + ae_vector_init_copy(&dst->successhhistory, &src->successhhistory, _state, make_automatic); + dst->historymax = src->historymax; +} + + +void _mirbfvnsnodesubsolver_clear(void* _p) +{ + mirbfvnsnodesubsolver *p = (mirbfvnsnodesubsolver*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->successfhistory); + ae_vector_clear(&p->successhhistory); +} + + +void _mirbfvnsnodesubsolver_destroy(void* _p) +{ + mirbfvnsnodesubsolver *p = (mirbfvnsnodesubsolver*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->successfhistory); + ae_vector_destroy(&p->successhhistory); +} + + +void _rbfmmtemporaries_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + rbfmmtemporaries *p = (rbfmmtemporaries*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->crit, _state, make_automatic); + ae_vector_init(&p->bndlx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndux, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scalingfactors, 0, DT_REAL, _state, make_automatic); + _minfsqpstate_init(&p->fsqpsolver, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + _sparsematrix_init(&p->cx, _state, make_automatic); + ae_vector_init(&p->clx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cux, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); +} + + +void _rbfmmtemporaries_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + rbfmmtemporaries *dst = (rbfmmtemporaries*)_dst; + const rbfmmtemporaries *src = (const rbfmmtemporaries*)_src; + _nlpstoppingcriteria_init_copy(&dst->crit, &src->crit, _state, make_automatic); + ae_vector_init_copy(&dst->bndlx, &src->bndlx, _state, make_automatic); + ae_vector_init_copy(&dst->bndux, &src->bndux, _state, make_automatic); + ae_vector_init_copy(&dst->x0x, &src->x0x, _state, make_automatic); + ae_vector_init_copy(&dst->sx, &src->sx, _state, make_automatic); + ae_vector_init_copy(&dst->scalingfactors, &src->scalingfactors, _state, make_automatic); + _minfsqpstate_init_copy(&dst->fsqpsolver, &src->fsqpsolver, _state, make_automatic); + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + _sparsematrix_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->clx, &src->clx, _state, make_automatic); + ae_vector_init_copy(&dst->cux, &src->cux, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpnl, &src->tmpnl, _state, make_automatic); + ae_vector_init_copy(&dst->tmpnu, &src->tmpnu, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); +} + + +void _rbfmmtemporaries_clear(void* _p) +{ + rbfmmtemporaries *p = (rbfmmtemporaries*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->crit); + ae_vector_clear(&p->bndlx); + ae_vector_clear(&p->bndux); + ae_vector_clear(&p->x0x); + ae_vector_clear(&p->sx); + ae_vector_clear(&p->scalingfactors); + _minfsqpstate_clear(&p->fsqpsolver); + _smoothnessmonitor_clear(&p->smonitor); + _sparsematrix_clear(&p->cx); + ae_vector_clear(&p->clx); + ae_vector_clear(&p->cux); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmpnl); + ae_vector_clear(&p->tmpnu); + ae_vector_clear(&p->tmpi); +} + + +void _rbfmmtemporaries_destroy(void* _p) +{ + rbfmmtemporaries *p = (rbfmmtemporaries*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->crit); + ae_vector_destroy(&p->bndlx); + ae_vector_destroy(&p->bndux); + ae_vector_destroy(&p->x0x); + ae_vector_destroy(&p->sx); + ae_vector_destroy(&p->scalingfactors); + _minfsqpstate_destroy(&p->fsqpsolver); + _smoothnessmonitor_destroy(&p->smonitor); + _sparsematrix_destroy(&p->cx); + ae_vector_destroy(&p->clx); + ae_vector_destroy(&p->cux); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmpnl); + ae_vector_destroy(&p->tmpnu); + ae_vector_destroy(&p->tmpi); +} + + +void _mirbfvnstemporaries_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnstemporaries *p = (mirbfvnstemporaries*)_p; + ae_touch_ptr((void*)p); + _stimer_init(&p->localtimer, _state, make_automatic); + _hqrndstate_init(&p->localrng, _state, make_automatic); + ae_vector_init(&p->glbbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fullx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbtmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbtmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbtmp2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->glbxf, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->glbsx, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ortdeltas, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbmultscale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbvtrustregion, 0, DT_REAL, _state, make_automatic); + _mirbfmodel_init(&p->glbmodel, _state, make_automatic); + _rbfmmtemporaries_init(&p->buf, _state, make_automatic); + ae_vector_init(&p->glbsk, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->glbrandomprior, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbprioratx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbxtrial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mapfull2compact, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->glba, _state, make_automatic); + ae_vector_init(&p->glbal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->glbmask, 0, DT_BOOL, _state, make_automatic); + _rbfmmtemporaries_init(&p->mmbuf, _state, make_automatic); + ae_vector_init(&p->lclidxfrac, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->lcl2glb, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->lclxf, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lclsx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nodeslist, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->lclrandomprior, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lclmultscale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcls, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lclx0, 0, DT_REAL, _state, make_automatic); + _mirbfmodel_init(&p->tmpmodel, _state, make_automatic); + _ipm2state_init(&p->qpsubsolver, _state, make_automatic); + _bbgdstate_init(&p->bbgdsubsolver, _state, make_automatic); + ae_vector_init(&p->wrkbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->diaga, _state, make_automatic); + ae_vector_init(&p->linb, 0, DT_REAL, _state, make_automatic); +} + + +void _mirbfvnstemporaries_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnstemporaries *dst = (mirbfvnstemporaries*)_dst; + const mirbfvnstemporaries *src = (const mirbfvnstemporaries*)_src; + _stimer_init_copy(&dst->localtimer, &src->localtimer, _state, make_automatic); + _hqrndstate_init_copy(&dst->localrng, &src->localrng, _state, make_automatic); + ae_vector_init_copy(&dst->glbbndl, &src->glbbndl, _state, make_automatic); + ae_vector_init_copy(&dst->glbbndu, &src->glbbndu, _state, make_automatic); + ae_vector_init_copy(&dst->fullx0, &src->fullx0, _state, make_automatic); + ae_vector_init_copy(&dst->glbx0, &src->glbx0, _state, make_automatic); + ae_vector_init_copy(&dst->glbtmp0, &src->glbtmp0, _state, make_automatic); + ae_vector_init_copy(&dst->glbtmp1, &src->glbtmp1, _state, make_automatic); + ae_vector_init_copy(&dst->glbtmp2, &src->glbtmp2, _state, make_automatic); + ae_matrix_init_copy(&dst->glbxf, &src->glbxf, _state, make_automatic); + ae_matrix_init_copy(&dst->glbsx, &src->glbsx, _state, make_automatic); + ae_matrix_init_copy(&dst->ortdeltas, &src->ortdeltas, _state, make_automatic); + ae_vector_init_copy(&dst->glbmultscale, &src->glbmultscale, _state, make_automatic); + ae_vector_init_copy(&dst->glbvtrustregion, &src->glbvtrustregion, _state, make_automatic); + _mirbfmodel_init_copy(&dst->glbmodel, &src->glbmodel, _state, make_automatic); + _rbfmmtemporaries_init_copy(&dst->buf, &src->buf, _state, make_automatic); + ae_vector_init_copy(&dst->glbsk, &src->glbsk, _state, make_automatic); + ae_matrix_init_copy(&dst->glbrandomprior, &src->glbrandomprior, _state, make_automatic); + ae_vector_init_copy(&dst->glbprioratx0, &src->glbprioratx0, _state, make_automatic); + ae_vector_init_copy(&dst->glbxtrial, &src->glbxtrial, _state, make_automatic); + ae_vector_init_copy(&dst->glbs, &src->glbs, _state, make_automatic); + ae_vector_init_copy(&dst->mapfull2compact, &src->mapfull2compact, _state, make_automatic); + _sparsematrix_init_copy(&dst->glba, &src->glba, _state, make_automatic); + ae_vector_init_copy(&dst->glbal, &src->glbal, _state, make_automatic); + ae_vector_init_copy(&dst->glbau, &src->glbau, _state, make_automatic); + ae_vector_init_copy(&dst->glbmask, &src->glbmask, _state, make_automatic); + _rbfmmtemporaries_init_copy(&dst->mmbuf, &src->mmbuf, _state, make_automatic); + ae_vector_init_copy(&dst->lclidxfrac, &src->lclidxfrac, _state, make_automatic); + ae_vector_init_copy(&dst->lcl2glb, &src->lcl2glb, _state, make_automatic); + ae_matrix_init_copy(&dst->lclxf, &src->lclxf, _state, make_automatic); + ae_matrix_init_copy(&dst->lclsx, &src->lclsx, _state, make_automatic); + ae_vector_init_copy(&dst->nodeslist, &src->nodeslist, _state, make_automatic); + ae_matrix_init_copy(&dst->lclrandomprior, &src->lclrandomprior, _state, make_automatic); + ae_vector_init_copy(&dst->lclmultscale, &src->lclmultscale, _state, make_automatic); + ae_vector_init_copy(&dst->lcls, &src->lcls, _state, make_automatic); + ae_vector_init_copy(&dst->lclx0, &src->lclx0, _state, make_automatic); + _mirbfmodel_init_copy(&dst->tmpmodel, &src->tmpmodel, _state, make_automatic); + _ipm2state_init_copy(&dst->qpsubsolver, &src->qpsubsolver, _state, make_automatic); + _bbgdstate_init_copy(&dst->bbgdsubsolver, &src->bbgdsubsolver, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndl, &src->wrkbndl, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndu, &src->wrkbndu, _state, make_automatic); + _sparsematrix_init_copy(&dst->diaga, &src->diaga, _state, make_automatic); + ae_vector_init_copy(&dst->linb, &src->linb, _state, make_automatic); +} + + +void _mirbfvnstemporaries_clear(void* _p) +{ + mirbfvnstemporaries *p = (mirbfvnstemporaries*)_p; + ae_touch_ptr((void*)p); + _stimer_clear(&p->localtimer); + _hqrndstate_clear(&p->localrng); + ae_vector_clear(&p->glbbndl); + ae_vector_clear(&p->glbbndu); + ae_vector_clear(&p->fullx0); + ae_vector_clear(&p->glbx0); + ae_vector_clear(&p->glbtmp0); + ae_vector_clear(&p->glbtmp1); + ae_vector_clear(&p->glbtmp2); + ae_matrix_clear(&p->glbxf); + ae_matrix_clear(&p->glbsx); + ae_matrix_clear(&p->ortdeltas); + ae_vector_clear(&p->glbmultscale); + ae_vector_clear(&p->glbvtrustregion); + _mirbfmodel_clear(&p->glbmodel); + _rbfmmtemporaries_clear(&p->buf); + ae_vector_clear(&p->glbsk); + ae_matrix_clear(&p->glbrandomprior); + ae_vector_clear(&p->glbprioratx0); + ae_vector_clear(&p->glbxtrial); + ae_vector_clear(&p->glbs); + ae_vector_clear(&p->mapfull2compact); + _sparsematrix_clear(&p->glba); + ae_vector_clear(&p->glbal); + ae_vector_clear(&p->glbau); + ae_vector_clear(&p->glbmask); + _rbfmmtemporaries_clear(&p->mmbuf); + ae_vector_clear(&p->lclidxfrac); + ae_vector_clear(&p->lcl2glb); + ae_matrix_clear(&p->lclxf); + ae_matrix_clear(&p->lclsx); + ae_vector_clear(&p->nodeslist); + ae_matrix_clear(&p->lclrandomprior); + ae_vector_clear(&p->lclmultscale); + ae_vector_clear(&p->lcls); + ae_vector_clear(&p->lclx0); + _mirbfmodel_clear(&p->tmpmodel); + _ipm2state_clear(&p->qpsubsolver); + _bbgdstate_clear(&p->bbgdsubsolver); + ae_vector_clear(&p->wrkbndl); + ae_vector_clear(&p->wrkbndu); + _sparsematrix_clear(&p->diaga); + ae_vector_clear(&p->linb); +} + + +void _mirbfvnstemporaries_destroy(void* _p) +{ + mirbfvnstemporaries *p = (mirbfvnstemporaries*)_p; + ae_touch_ptr((void*)p); + _stimer_destroy(&p->localtimer); + _hqrndstate_destroy(&p->localrng); + ae_vector_destroy(&p->glbbndl); + ae_vector_destroy(&p->glbbndu); + ae_vector_destroy(&p->fullx0); + ae_vector_destroy(&p->glbx0); + ae_vector_destroy(&p->glbtmp0); + ae_vector_destroy(&p->glbtmp1); + ae_vector_destroy(&p->glbtmp2); + ae_matrix_destroy(&p->glbxf); + ae_matrix_destroy(&p->glbsx); + ae_matrix_destroy(&p->ortdeltas); + ae_vector_destroy(&p->glbmultscale); + ae_vector_destroy(&p->glbvtrustregion); + _mirbfmodel_destroy(&p->glbmodel); + _rbfmmtemporaries_destroy(&p->buf); + ae_vector_destroy(&p->glbsk); + ae_matrix_destroy(&p->glbrandomprior); + ae_vector_destroy(&p->glbprioratx0); + ae_vector_destroy(&p->glbxtrial); + ae_vector_destroy(&p->glbs); + ae_vector_destroy(&p->mapfull2compact); + _sparsematrix_destroy(&p->glba); + ae_vector_destroy(&p->glbal); + ae_vector_destroy(&p->glbau); + ae_vector_destroy(&p->glbmask); + _rbfmmtemporaries_destroy(&p->mmbuf); + ae_vector_destroy(&p->lclidxfrac); + ae_vector_destroy(&p->lcl2glb); + ae_matrix_destroy(&p->lclxf); + ae_matrix_destroy(&p->lclsx); + ae_vector_destroy(&p->nodeslist); + ae_matrix_destroy(&p->lclrandomprior); + ae_vector_destroy(&p->lclmultscale); + ae_vector_destroy(&p->lcls); + ae_vector_destroy(&p->lclx0); + _mirbfmodel_destroy(&p->tmpmodel); + _ipm2state_destroy(&p->qpsubsolver); + _bbgdstate_destroy(&p->bbgdsubsolver); + ae_vector_destroy(&p->wrkbndl); + ae_vector_destroy(&p->wrkbndu); + _sparsematrix_destroy(&p->diaga); + ae_vector_destroy(&p->linb); +} + + +void _mirbfvnsgrid_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsgrid *p = (mirbfvnsgrid*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->nodesinfo, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ptlistheads, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->ptlistdata, 0, DT_INT, _state, make_automatic); + ae_obj_array_init(&p->subsolvers, _state, make_automatic); +} + + +void _mirbfvnsgrid_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsgrid *dst = (mirbfvnsgrid*)_dst; + const mirbfvnsgrid *src = (const mirbfvnsgrid*)_src; + dst->nnodes = src->nnodes; + ae_matrix_init_copy(&dst->nodesinfo, &src->nodesinfo, _state, make_automatic); + dst->ptlistlength = src->ptlistlength; + ae_vector_init_copy(&dst->ptlistheads, &src->ptlistheads, _state, make_automatic); + ae_vector_init_copy(&dst->ptlistdata, &src->ptlistdata, _state, make_automatic); + ae_obj_array_init_copy(&dst->subsolvers, &src->subsolvers, _state, make_automatic); + dst->naddcols = src->naddcols; +} + + +void _mirbfvnsgrid_clear(void* _p) +{ + mirbfvnsgrid *p = (mirbfvnsgrid*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->nodesinfo); + ae_vector_clear(&p->ptlistheads); + ae_vector_clear(&p->ptlistdata); + ae_obj_array_clear(&p->subsolvers); +} + + +void _mirbfvnsgrid_destroy(void* _p) +{ + mirbfvnsgrid *p = (mirbfvnsgrid*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->nodesinfo); + ae_vector_destroy(&p->ptlistheads); + ae_vector_destroy(&p->ptlistdata); + ae_obj_array_destroy(&p->subsolvers); +} + + +void _mirbfvnsdataset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsdataset *p = (mirbfvnsdataset*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->pointinfo, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _mirbfvnsdataset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsdataset *dst = (mirbfvnsdataset*)_dst; + const mirbfvnsdataset *src = (const mirbfvnsdataset*)_src; + dst->npoints = src->npoints; + dst->nvars = src->nvars; + dst->nnlc = src->nnlc; + ae_matrix_init_copy(&dst->pointinfo, &src->pointinfo, _state, make_automatic); +} + + +void _mirbfvnsdataset_clear(void* _p) +{ + mirbfvnsdataset *p = (mirbfvnsdataset*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->pointinfo); +} + + +void _mirbfvnsdataset_destroy(void* _p) +{ + mirbfvnsdataset *p = (mirbfvnsdataset*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->pointinfo); +} + + +void _mirbfvnsstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsstate *p = (mirbfvnsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isintegral, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isbinary, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->rawa, _state, make_automatic); + ae_vector_init(&p->rawal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasmask, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->varmask, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + _stimer_init(&p->timerglobal, _state, make_automatic); + _stimer_init(&p->timerprepareneighbors, _state, make_automatic); + _stimer_init(&p->timerproposetrial, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nodecproducedbycut, 0, DT_REAL, _state, make_automatic); + _mirbfvnsgrid_init(&p->grid, _state, make_automatic); + _mirbfvnsdataset_init(&p->dataset, _state, make_automatic); + ae_vector_init(&p->xcneighbors, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xcreachedfrom, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->xcreachedbycut, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xcqueryflags, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->evalbatchpoints, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->evalbatchnodeidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->evalbatchneighboridx, 0, DT_INT, _state, make_automatic); + _hqrndstate_init(&p->unsafeglobalrng, _state, make_automatic); + ae_vector_init(&p->maskint, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->maskfrac, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idxint, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->idxfrac, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xuneighbors, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->xucuts, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xupoints, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xuflags, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->xtrial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->trialfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpeb0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpeb1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpeb2, 0, DT_INT, _state, make_automatic); + _mirbfvnstemporaries_init(&p->dummytmp, _state, make_automatic); + ae_matrix_init(&p->densedummy2, 0, 0, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->rpool, DT_REAL, _state, make_automatic); + ae_shared_pool_init(&p->tmppool, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _mirbfvnsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mirbfvnsstate *dst = (mirbfvnsstate*)_dst; + const mirbfvnsstate *src = (const mirbfvnsstate*)_src; + dst->n = src->n; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->algomode = src->algomode; + dst->budget = src->budget; + dst->maxneighborhood = src->maxneighborhood; + dst->batchsize = src->batchsize; + dst->expandneighborhoodonstart = src->expandneighborhoodonstart; + dst->retrylastcut = src->retrylastcut; + dst->convexityflag = src->convexityflag; + dst->ctol = src->ctol; + dst->epsf = src->epsf; + dst->quickepsf = src->quickepsf; + dst->epsx = src->epsx; + dst->adaptiveinternalparallelism = src->adaptiveinternalparallelism; + dst->timeout = src->timeout; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + ae_vector_init_copy(&dst->isintegral, &src->isintegral, _state, make_automatic); + ae_vector_init_copy(&dst->isbinary, &src->isbinary, _state, make_automatic); + _sparsematrix_init_copy(&dst->rawa, &src->rawa, _state, make_automatic); + ae_vector_init_copy(&dst->rawal, &src->rawal, _state, make_automatic); + ae_vector_init_copy(&dst->rawau, &src->rawau, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + dst->lccnt = src->lccnt; + dst->haslinearlyconstrainedints = src->haslinearlyconstrainedints; + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->nomask = src->nomask; + ae_vector_init_copy(&dst->hasmask, &src->hasmask, _state, make_automatic); + _sparsematrix_init_copy(&dst->varmask, &src->varmask, _state, make_automatic); + dst->hasx0 = src->hasx0; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + dst->userterminationneeded = src->userterminationneeded; + dst->repnfev = src->repnfev; + dst->repsubsolverits = src->repsubsolverits; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + _stimer_init_copy(&dst->timerglobal, &src->timerglobal, _state, make_automatic); + _stimer_init_copy(&dst->timerprepareneighbors, &src->timerprepareneighbors, _state, make_automatic); + _stimer_init_copy(&dst->timerproposetrial, &src->timerproposetrial, _state, make_automatic); + dst->explorativetrialcnt = src->explorativetrialcnt; + dst->explorativetrialtimems = src->explorativetrialtimems; + dst->localtrialsamplingcnt = src->localtrialsamplingcnt; + dst->localtrialsamplingtimems = src->localtrialsamplingtimems; + dst->localtrialrbfcnt = src->localtrialrbfcnt; + dst->localtrialrbftimems = src->localtrialrbftimems; + dst->cutcnt = src->cutcnt; + dst->cuttimems = src->cuttimems; + dst->dbgpotentiallyparallelbatches = src->dbgpotentiallyparallelbatches; + dst->dbgsequentialbatches = src->dbgsequentialbatches; + dst->dbgpotentiallyparallelcutrounds = src->dbgpotentiallyparallelcutrounds; + dst->dbgsequentialcutrounds = src->dbgsequentialcutrounds; + dst->prepareevaluationbatchparallelism = src->prepareevaluationbatchparallelism; + dst->expandcutgenerateneighborsparallelism = src->expandcutgenerateneighborsparallelism; + dst->doanytrace = src->doanytrace; + dst->dotrace = src->dotrace; + dst->doextratrace = src->doextratrace; + dst->dolaconictrace = src->dolaconictrace; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + dst->fc = src->fc; + dst->mxc = src->mxc; + dst->hc = src->hc; + dst->nodec = src->nodec; + ae_vector_init_copy(&dst->nodecproducedbycut, &src->nodecproducedbycut, _state, make_automatic); + _mirbfvnsgrid_init_copy(&dst->grid, &src->grid, _state, make_automatic); + _mirbfvnsdataset_init_copy(&dst->dataset, &src->dataset, _state, make_automatic); + dst->nfrac = src->nfrac; + dst->nint = src->nint; + ae_vector_init_copy(&dst->xcneighbors, &src->xcneighbors, _state, make_automatic); + ae_vector_init_copy(&dst->xcreachedfrom, &src->xcreachedfrom, _state, make_automatic); + ae_matrix_init_copy(&dst->xcreachedbycut, &src->xcreachedbycut, _state, make_automatic); + ae_vector_init_copy(&dst->xcqueryflags, &src->xcqueryflags, _state, make_automatic); + dst->xcneighborscnt = src->xcneighborscnt; + dst->xcpriorityneighborscnt = src->xcpriorityneighborscnt; + dst->evalbatchsize = src->evalbatchsize; + ae_matrix_init_copy(&dst->evalbatchpoints, &src->evalbatchpoints, _state, make_automatic); + ae_vector_init_copy(&dst->evalbatchnodeidx, &src->evalbatchnodeidx, _state, make_automatic); + ae_vector_init_copy(&dst->evalbatchneighboridx, &src->evalbatchneighboridx, _state, make_automatic); + dst->outofbudget = src->outofbudget; + _hqrndstate_init_copy(&dst->unsafeglobalrng, &src->unsafeglobalrng, _state, make_automatic); + ae_vector_init_copy(&dst->maskint, &src->maskint, _state, make_automatic); + ae_vector_init_copy(&dst->maskfrac, &src->maskfrac, _state, make_automatic); + ae_vector_init_copy(&dst->idxint, &src->idxint, _state, make_automatic); + ae_vector_init_copy(&dst->idxfrac, &src->idxfrac, _state, make_automatic); + ae_vector_init_copy(&dst->xuneighbors, &src->xuneighbors, _state, make_automatic); + ae_matrix_init_copy(&dst->xucuts, &src->xucuts, _state, make_automatic); + ae_matrix_init_copy(&dst->xupoints, &src->xupoints, _state, make_automatic); + ae_vector_init_copy(&dst->xuflags, &src->xuflags, _state, make_automatic); + ae_vector_init_copy(&dst->xtrial, &src->xtrial, _state, make_automatic); + ae_vector_init_copy(&dst->trialfi, &src->trialfi, _state, make_automatic); + ae_vector_init_copy(&dst->tmpeb0, &src->tmpeb0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpeb1, &src->tmpeb1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpeb2, &src->tmpeb2, _state, make_automatic); + _mirbfvnstemporaries_init_copy(&dst->dummytmp, &src->dummytmp, _state, make_automatic); + ae_matrix_init_copy(&dst->densedummy2, &src->densedummy2, _state, make_automatic); + ae_nxpool_init_copy(&dst->rpool, &src->rpool, _state, make_automatic); + ae_shared_pool_init_copy(&dst->tmppool, &src->tmppool, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _mirbfvnsstate_clear(void* _p) +{ + mirbfvnsstate *p = (mirbfvnsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + ae_vector_clear(&p->isintegral); + ae_vector_clear(&p->isbinary); + _sparsematrix_clear(&p->rawa); + ae_vector_clear(&p->rawal); + ae_vector_clear(&p->rawau); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->hasmask); + _sparsematrix_clear(&p->varmask); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + _stimer_clear(&p->timerglobal); + _stimer_clear(&p->timerprepareneighbors); + _stimer_clear(&p->timerproposetrial); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->nodecproducedbycut); + _mirbfvnsgrid_clear(&p->grid); + _mirbfvnsdataset_clear(&p->dataset); + ae_vector_clear(&p->xcneighbors); + ae_vector_clear(&p->xcreachedfrom); + ae_matrix_clear(&p->xcreachedbycut); + ae_vector_clear(&p->xcqueryflags); + ae_matrix_clear(&p->evalbatchpoints); + ae_vector_clear(&p->evalbatchnodeidx); + ae_vector_clear(&p->evalbatchneighboridx); + _hqrndstate_clear(&p->unsafeglobalrng); + ae_vector_clear(&p->maskint); + ae_vector_clear(&p->maskfrac); + ae_vector_clear(&p->idxint); + ae_vector_clear(&p->idxfrac); + ae_vector_clear(&p->xuneighbors); + ae_matrix_clear(&p->xucuts); + ae_matrix_clear(&p->xupoints); + ae_vector_clear(&p->xuflags); + ae_vector_clear(&p->xtrial); + ae_vector_clear(&p->trialfi); + ae_vector_clear(&p->tmpeb0); + ae_vector_clear(&p->tmpeb1); + ae_vector_clear(&p->tmpeb2); + _mirbfvnstemporaries_clear(&p->dummytmp); + ae_matrix_clear(&p->densedummy2); + ae_nxpool_clear(&p->rpool); + ae_shared_pool_clear(&p->tmppool); + _rcommstate_clear(&p->rstate); +} + + +void _mirbfvnsstate_destroy(void* _p) +{ + mirbfvnsstate *p = (mirbfvnsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + ae_vector_destroy(&p->isintegral); + ae_vector_destroy(&p->isbinary); + _sparsematrix_destroy(&p->rawa); + ae_vector_destroy(&p->rawal); + ae_vector_destroy(&p->rawau); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->hasmask); + _sparsematrix_destroy(&p->varmask); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + _stimer_destroy(&p->timerglobal); + _stimer_destroy(&p->timerprepareneighbors); + _stimer_destroy(&p->timerproposetrial); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->nodecproducedbycut); + _mirbfvnsgrid_destroy(&p->grid); + _mirbfvnsdataset_destroy(&p->dataset); + ae_vector_destroy(&p->xcneighbors); + ae_vector_destroy(&p->xcreachedfrom); + ae_matrix_destroy(&p->xcreachedbycut); + ae_vector_destroy(&p->xcqueryflags); + ae_matrix_destroy(&p->evalbatchpoints); + ae_vector_destroy(&p->evalbatchnodeidx); + ae_vector_destroy(&p->evalbatchneighboridx); + _hqrndstate_destroy(&p->unsafeglobalrng); + ae_vector_destroy(&p->maskint); + ae_vector_destroy(&p->maskfrac); + ae_vector_destroy(&p->idxint); + ae_vector_destroy(&p->idxfrac); + ae_vector_destroy(&p->xuneighbors); + ae_matrix_destroy(&p->xucuts); + ae_matrix_destroy(&p->xupoints); + ae_vector_destroy(&p->xuflags); + ae_vector_destroy(&p->xtrial); + ae_vector_destroy(&p->trialfi); + ae_vector_destroy(&p->tmpeb0); + ae_vector_destroy(&p->tmpeb1); + ae_vector_destroy(&p->tmpeb2); + _mirbfvnstemporaries_destroy(&p->dummytmp); + ae_matrix_destroy(&p->densedummy2); + ae_nxpool_destroy(&p->rpool); + ae_shared_pool_destroy(&p->tmppool); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + MIXED INTEGER NONLINEAR PROGRAMMING SOLVER + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to any +combination of: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU +* integrality constraints on some variables + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercreate(ae_int_t n, + /* Real */ const ae_vector* x, + minlpsolverstate* state, + ae_state *_state) +{ + + _minlpsolverstate_clear(state); + + ae_assert(n>=1, "MINLPSolverCreate: N<1", _state); + ae_assert(x->cnt>=n, "MINLPSolverCreate: Length(X)n; + ae_assert(bndl->cnt>=n, "MINLPSolverSetBC: Length(BndL)cnt>=n, "MINLPSolverSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MINLPSolverSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MINLPSolverSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2dense(minlpsolverstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, &state->tmps1, 0, a, k, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2(minlpsolverstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, a, k, &state->tmpj1, 0, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2mixed(minlpsolverstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, sparsea, ksparse, densea, kdense, al, au, _state); +} + + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2dense(minlpsolverstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2dense(&state->xlc, a, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2(minlpsolverstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2(&state->xlc, idxa, vala, nnz, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2sparsefromdense(minlpsolverstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2sparsefromdense(&state->xlc, da, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MINLP optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MINLPSolverOptimize() method as callbacks. + +MINLPSolverOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetnlc2(minlpsolverstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nnlc>=0, "MINLPSolverSetNLC2: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "MINLPSolverSetNLC2: Length(NL)cnt>=nnlc, "MINLPSolverSetNLC2: Length(NU)nnlc = nnlc; + bsetallocv(nnlc, ae_false, &state->hasnlcmask, _state); + sparsecreatecrsemptybuf(state->n, &state->nlcmask, _state); + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "MINLPSolverSetNLC2: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "MINLPSolverSetNLC2: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + sparseappendemptyrow(&state->nlcmask, _state); + } +} + + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list. + +In fact, this function adds constraint bounds. A constraints itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + +NOTE 3: use addnlc2masked() in order to specify variable mask. Masks are + essential for derivative-free optimization because they provide + important information about relevant and irrelevant variables. + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2(minlpsolverstate* state, + double nl, + double nu, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(nl, _state)||ae_isneginf(nl, _state), "MINLPSolverAddNLC2: NL is +INF or NAN", _state); + ae_assert(ae_isfinite(nu, _state)||ae_isposinf(nu, _state), "MINLPSolverAddNLC2: NU is -INF or NAN", _state); + rgrowappendv(state->nnlc+1, &state->nl, nl, _state); + rgrowappendv(state->nnlc+1, &state->nu, nu, _state); + bgrowappendv(state->nnlc+1, &state->hasnlcmask, ae_false, _state); + sparseappendemptyrow(&state->nlcmask, _state); + state->nnlc = state->nnlc+1; +} + + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list, with +the variable mask being specified as a compressed index array. A +variable mask is a set of variables actually appearing in the constraint. + +----- ABOUT VARIABLE MASKS ----------------------------------------------- + +Variable masks provide crucial information for derivative-free solvers, +greatly accelerating surrogate model construction. This applies to both +continuous and integral variables, with results for binary variables being +more pronounced. + +Up to 2x improvement in convergence speed has been observed for sufficiently +sparse MINLP problems. + +NOTE: In order to unleash the full potential of variable masking, it is + important to provide masks for objective as well as all nonlinear + constraints. + + Even partial information matters, i.e. if you are 100% sure that + your black-box function does not depend on some variables, but + unsure about other ones, mark surely irrelevant variables, and tell + the solver that other ones may be relevant. + +NOTE: the solver is may behave unpredictably if some relevant variable + is not included into the mask. Most likely it will fail to converge, + although it sometimes possible to converge to solution even with + incorrectly specified mask. + +NOTE: minlpsolversetobjectivemask() can be used to set variable mask for + the objective. + +NOTE: Masks are ignored by branch-and-bound-type solvers relying on + analytic gradients. + +----- ABOUT NONLINEAR CONSTRAINTS ---------------------------------------- + +In fact, this function adds constraint bounds. A constraint itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + VarIdx - array[NMSK], with potentially unsorted and non-distinct + indexes (the function will sort and merge duplicates). If + a variable index K appears in the list, it means that the + constraint potentially depends on K-th variable. If a + variable index K does NOT appear in the list, it means + that the constraint does NOT depend on K-th variable. + The array can have more than NMSK elements, in which case + only leading NMSK will be used. + NMSK - NMSK>=0, VarIdx[] size: + * NMSK>0 means that the constraint depends on up to NMSK + variables whose indexes are stored in VarIdx[] + * NMSK=0 means that the constraint is a constant function; + the solver may fail if it is not actually the case. + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2masked(minlpsolverstate* state, + double nl, + double nu, + /* Integer */ const ae_vector* varidx, + ae_int_t nmsk, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(nl, _state)||ae_isneginf(nl, _state), "MINLPSolverAddNLC2Masked: NL is +INF or NAN", _state); + ae_assert(ae_isfinite(nu, _state)||ae_isposinf(nu, _state), "MINLPSolverAddNLC2Masked: NU is -INF or NAN", _state); + ae_assert(nmsk>=0, "MINLPSolverAddNLC2Masked: NMSK<0", _state); + ae_assert(varidx->cnt>=nmsk, "MINLPSolverAddNLC2Masked: len(VarIdx)nnlc+1, &state->nl, nl, _state); + rgrowappendv(state->nnlc+1, &state->nu, nu, _state); + bgrowappendv(state->nnlc+1, &state->hasnlcmask, ae_true, _state); + rsetallocv(nmsk, 1.0, &state->rdummy, _state); + sparseappendcompressedrow(&state->nlcmask, varidx, &state->rdummy, nmsk, _state); + state->nnlc = state->nnlc+1; +} + + +/************************************************************************* +This function sets stopping condition for the branch-and-bound family of +solvers: a solver must when when the gap between primal and dual bounds is +less than PDGap. + +The solver computes relative gap, equal to |Fprim-Fdual|/max(|Fprim|,1). + +This parameter is ignored by other types of solvers, e.g. MIVNS. + +INPUT PARAMETERS: + State - structure stores algorithm state + PDGap - >=0, tolerance. Zero value means that some default value + is automatically selected. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetpdgap(minlpsolverstate* state, + double pdgap, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(pdgap, _state), "MINLPSolverSetPDGap: PDGap is not finite", _state); + ae_assert(ae_fp_greater_eq(pdgap,(double)(0)), "MINLPSolverSetPDGap: PDGap<0", _state); + state->pdgap = pdgap; +} + + +/************************************************************************* +This function sets BBSYNC profile to "small tree". + +It means that we expect our problem to have a shallow B&B tree with the +number of nodes comparable to the integer variables count, or below. + +BBSYNC solver will run with simplified settings: +* pseudocost branching is used + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilesmalltree(minlpsolverstate* state, + ae_state *_state) +{ + + + state->bbsyncprofile = 0; +} + + +/************************************************************************* +This function sets BBSYNC profile to "large tree". + +It means that we expect our problem to have a large B&B tree with much +more than NInt (the integer variables count) nodes. However, we expect it +to be solvable within our computational budget (i.e. that we are able to +explore the entire B&B tree). + +BBSYNC solver will run with heuristics that are costly to power-up, but +greatly improve performance on long distances: +* reliability branching is used + +BBSYNC will not use heuristics that increase chance of finding good +solutions early at the cost of increasing total time to prove optimality. + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilelargetree(minlpsolverstate* state, + ae_state *_state) +{ + + + state->bbsyncprofile = 1; +} + + +/************************************************************************* +This function sets tolerance for nonlinear constraints; points violating +constraints by no more than CTol are considered feasible. + +Depending on the specific algorithm used, constraint violation may be +checked against internally scaled/normalized constraints (some smooth +solvers renormalize constraints in such a way that they have roughly unit +gradient magnitudes) or against raw constraint values: +* BBSYNC renormalizes constraints prior to comparing them with CTol +* MIRBF-VNS checks violation against raw constraint values + +IMPORTANT: one should be careful when choosing tolerances and stopping + criteria. + + A solver stops as soon as stopping criteria are triggered; + a feasibility check is performed after that. If too loose + stopping criteria are used, the solver may fail to enforce + constraints with sufficient accuracy and fail to recognize + solution as a feasible one. + + For example, stopping with EpsX=0.01 and checking CTol=0.000001 + will almost surely result in problems. Ideally, CTol should be + 1-2 orders of magnitude more relaxed than stopping criteria. + +INPUT PARAMETERS: + State - structure stores algorithm state + CTol - >0, tolerance. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetctol(minlpsolverstate* state, + double ctol, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(ctol, _state), "MINLPSolverSetCTol: CTol is not finite", _state); + ae_assert(ae_fp_greater(ctol,(double)(0)), "MINLPSolverSetCTol: CTol<=0", _state); + state->ctol = ctol; +} + + +/************************************************************************* +This function tells MINLP solver to use an objective-based stopping +condition for an underlying subsolver, i.e. to stop subsolver if relative +change in objective between iterations is less than EpsF. + +Too tight EspF, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsF +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if total objective change in last several (between + 5 and 10) steps is less than EpsF. More than one step is used to check + convergence because surrogate model-based solvers usually need more + stringent stopping criteria than SQP. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsF - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsF - >0, stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsf(minlpsolverstate* state, + double epsf, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "MINLPSolverSetSubsolverEpsF: EpsF is not finite", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MINLPSolverSetSubsolverEpsF: EpsF<0", _state); + state->subsolverepsf = epsf; +} + + +/************************************************************************* +This function tells MINLP solver to use a step-based stopping condition +for an underlying subsolver, i.e. to stop subsolver if typical step size +becomes less than EpsX. + +Too tight EspX, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsX +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if trust radius for a surrogate model optimizer + becomes less than EpsX. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsX - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsX - >=0, stopping condition. Zero value means that some default + value will be used. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsx(minlpsolverstate* state, + double epsx, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "MINLPSolverSetSubsolverEpsX: EpsX is not finite", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MINLPSolverSetSubsolverEpsX: EpsX<0", _state); + state->subsolverepsx = epsx; +} + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to favor parallelism, i.e. utilize +multithreading (when allowed by the user) until statistics prove that +overhead from starting/stopping worker threads is too large. + +This way solver gets the best performance on problems with significant +amount of internal calculations (large QP/MIQP subproblems, lengthy +surrogate model optimization sessions) from the very beginning. The price +is that problems with small solver overhead that does not justify internal +parallelism (<1ms per iteration) will suffer slowdown for several initial +10-20 milliseconds until the solver proves that parallelism makes no sense + +Use MINLPSolver.CautiousInternalParallelism() to avoid slowing down the +solver on easy problems. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverfavorinternalparallelism(minlpsolverstate* state, + ae_state *_state) +{ + + + state->adaptiveinternalparallelism = 1; +} + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations in the single-threaded +mode until statistics prove that iteration cost justified activating +multithreading. + +This way solver does not suffer slow-down on problems with small iteration +overhead (<1ms per iteration), at the cost of spending initial 10-20 ms +in the single-threaded mode even on difficult problems that justify +parallelism usage. + +Use MINLPSolver.FavorInternalParallelism() to use parallelism until it is +proven to be useless. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercautiousinternalparallelism(minlpsolverstate* state, + ae_state *_state) +{ + + + state->adaptiveinternalparallelism = 0; +} + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations exactly as prescribed by +the user: in the parallel mode when alglib::parallel flag is passed, in +the single-threaded mode otherwise. The solver does not analyze actual +running times to decide whether parallelism is justified or not. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvernoadaptiveinternalparallelism(minlpsolverstate* state, + ae_state *_state) +{ + + + state->adaptiveinternalparallelism = -1; +} + + +/************************************************************************* +This function marks K-th variable as an integral one. + +Unless box constraints are set for the variable, it is unconstrained (i.e. +can take positive or negative values). By default all variables are +continuous. + +IMPORTANT: box constraints work in parallel with the integrality ones: + * a variable marked as integral is considered having no bounds + until minlpsolversetbc() is called + * a variable with lower and upper bounds set is considered + continuous until marked as integral with the + minlpsolversetintkth() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + K - 0<=K=0&&kn, "MINLPSolverSetIntKth: K is outside of [0,N)", _state); + state->isintegral.ptr.p_bool[k] = ae_true; + state->isbinary.ptr.p_bool[k] = ae_false; +} + + +/************************************************************************* +This function sets variable mask for the objective. A variable mask is +a set of variables actually appearing in the objective. + +If you want to set variable mask for a nonlinear constraint, use +addnlc2masked() or addnlc2maskeddense() to add a constraint together with +a constraint-specific mask. + +Variable masks provide crucial information for derivative-free solvers, +greatly accelerating surrogate model construction. This applies to both +continuous and integral variables, with results for binary variables being +more pronounced. + +Up to 2x improvement in convergence speed has been observed for sufficiently +sparse MINLP problems. + +NOTE: In order to unleash the full potential of variable masking, it is + important to provide masks for objective as well as all nonlinear + constraints. + + Even partial information matters, i.e. if you are 100% sure that + your black-box function does not depend on some variables, but + unsure about other ones, mark surely irrelevant variables, and tell + the solver that other ones may be relevant. + +NOTE: the solver is may behave unpredictably if some relevant variable + is not included into the mask. Most likely it will fail to converge, + although it sometimes possible to converge to solution even with + incorrectly specified mask. + +NOTE: Masks are ignored by branch-and-bound-type solvers relying on + analytic gradients. + +INPUT PARAMETERS: + State - structure stores algorithm state + ObjMask - array[N], I-th element is False if I-th variable is + irrelevant. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetobjectivemaskdense(minlpsolverstate* state, + /* Boolean */ const ae_vector* _objmask, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector objmask; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&objmask, 0, sizeof(objmask)); + ae_vector_init_copy(&objmask, _objmask, _state, ae_true); + + ae_assert(objmask.cnt>=state->n, "MINLPSolverSetObjectiveMaskDense: len(ObjMask)hasobjmask = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->hasobjmask = state->hasobjmask||!objmask.ptr.p_bool[i]; + } + bcopyallocv(state->n, &objmask, &state->objmask, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets scaling coefficients for the mixed integer optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scales +are also used by the finite difference variant of the optimizer - the step +along I-th axis is equal to DiffStep*S[I]. Finally, variable scales are +used for preconditioning (i.e. to speed up the solver). + +The scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 06.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetscale(minlpsolverstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MINLPSolver: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MINLPSolver: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MINLPSolver: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function tell the solver to use BBSYNC (Branch&Bound with Synchronous +processing) mixed-integer nonlinear programming algorithm. + +The BBSYNC algorithm is an NLP-based branch-and-bound method with integral +and spatial splits, supporting both convex and nonconvex problems. The +algorithm combines parallelism support with deterministic behavior (i.e. +the same branching decisions are performed with every parallel run). + +Non-convex (multiextremal) problems can be solved with multiple restarts +from random points, which are activated by minlpsolversetmultistarts() + +IMPORTANT: contrary to the popular misconception, MINLP is not easily + parallelizable. B&B trees often have profiles unsuitable for + parallel processing (too short and/or too linear). Spatial or + integral splits add some limited degree of parallelism (up to + 2x in the very best case), but in practice it often results in + just a 1.5x speed-up at best due to imbalanced leaf processing + times. Furthermore, determinism is always at odds with + efficiency. + + Achieving good parallel speed-up requires some amount of tuning + and having a 2x-3x speed-up is already a good result. Only + difficult long-running problems (here 'difficult' means that + the value of rep.ntreenodes is at least several larger than the + variables count) have good parallelism properties. + + On the other hand, setups using multiple random restarts are + obviously highly parallelizable. + +IMPORTANT: the commercial edition of ALGLIB can accelerate factorization + phase of this function (this phase takes significant amounts of + time when solving large problems) by using SIMD intrinsics or a + performance backend library (Intel PARDISO or another + platform-specific sparse factorization library). + + Specific speed-up due to performance backend usage heavily + depends on the sparsity pattern of constraints. For some + problem types performance backends provide great speed-up. For + other ones, ALGLIB's own sparse factorization code is the + preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + + +INPUT PARAMETERS: + State - structure that stores algorithm state + + GroupSize - >=1, group size. Up to GroupSize tree nodes can be + processed in the parallel manner. + + Increasing this parameter makes the solver + less efficient serially (it always tries to fill + the batch with nodes, even if there is a chance + that most of them will be discarded later), but + increases its parallel potential. + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + + Recommended value, depending on callback cost and + matrix factorization overhead, can be: + * 1 for 'easy' problems with cheap callbacks and + small dimensions; also for problems with nearly + linear B&B trees. + * 2-3 for problems with sufficiently costly + callbacks (or sufficiently high linear algebra + overhead) that it makes sense to utilize limited + parallelism. + * cores count - for difficult problems with deep + and wide B&B trees and sufficiently costly + callbacks (or sufficiently high linear algebra + overhead). + +NOTES: DETERMINISM + +Running with fixed GroupSize generally produces same results independently +of whether parallelism is used or not. Changing GroupSize parameter may +change results in the following ways: + +* for problems that are solved to optimality but have multiple solutions, + different values of this parameter may result in different solutions + being returned (but still with the same objective value) + +* while operating close to exhausting budget (either timeout or iterations + limit), different GroupSize values may result in different outcomes: a + solution being found, or budget being exhausted + +* finally, on difficult problems that are too hard to solve to optimality + but still allow finding primal feasible solutions changing GroupSize may + result in different primal feasible solutions being returned. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgobbsync(minlpsolverstate* state, + ae_int_t groupsize, + ae_state *_state) +{ + + + ae_assert(groupsize>=1, "MINLPSolverSetAlgoBBSYNC: GroupSize<1", _state); + state->algoidx = 0; + state->bbgdgroupsize = groupsize; +} + + +/************************************************************************* +This function tell the solver to use MIVNS (Mixed-Integer Variable +Neighborhood Search) solver for derivative-free mixed-integer nonlinear +programming with expensive objective/constraints and non-relaxable integer +variables. + +The solver is intended for moderately-sized problems, typically with tens +of variables. + +The algorithm has the following features: +* it supports all-integer and mixed-integer problems with box, linear and + nonlinear equality and inequality constraints +* it makes no assumptions about problem convexity +* it does not require derivative information. Although it still assumes + that objective/constraints are smooth wrt continuous variables, no such + assumptions are made regarding dependence on integer variables. +* it efficiently uses limited computational budget and scales well with + larger budgets +* it does not evaluate objective/constraints at points violating integrality +* it also respects linear constraints in all intermediate points + +NOTE: In particular, if your task uses integrality+sum-to-one set of + constraints to encode multiple choice options (e.g. [1,0,0], [0,1,0] + or [0,0,1]), you can be sure that the algorithm will not ask for an + objective value at a point with fractional values like [0.1,0.5,0.4] + or at one that is not a correct one-hot encoded value (e.g. [1,1,0] + which has two variables set to 1). + +The algorithm is intended for low-to-medium accuracy solution of otherwise +intractable problems with expensive objective/constraints. + +It can solve any MINLP problem; however, it is optimized for the following +problem classes: +* limited variable count +* expensive objective/constraints +* nonrelaxable integer variables +* no derivative information +* problems where changes in integer variables lead to structural changes + in the entire system. Speaking in other words, on problems where each + integer variable acts as an on/off or "choice" switch that completely + rewires the model - turning constraints, variables, or whole sub-systems + on or off + +INPUT PARAMETERS: + State - structure that stores algorithm state + + Budget - optimization budget (function evaluations). The + solver will not stop immediately after reaching + Budget evaluations, but will stop shortly after + that (usually within 2N+1 evaluations). Zero value + means no limit. + + MaxNeighborhood - stopping condition for the solver. The algorithm + will stop as soon as there are no points better + than the current candidate in a neighborhood whose + size is equal to or exceeds MaxNeighborhood. Zero + means no stopping condition. + + Recommended neighborhood size is proportional to + the difference between integral variables count NI + and the number of linear equality constraints on + integral variables L (such constraints effectively + reduce problem dimensionality). + + The very minimal value for binary problems is NI-L, + which means that the solution can not be improved + by flipping one of variables between 0 and 1. The + very minimal value for non-binary integral vars is + twice as much (because now each point has two + neighbors per variable). However, such minimal + values often result in an early termination. + + It is recommended to set this parameter to 5*N or + 10*N (ignoring LI) and to test how it behaves on + your problem. + + BatchSize >=1, recommended batch size for neighborhood + exploration. Up to BatchSize nodes will be + evaluated at any moment, thus up to BatchSize + objective evaluations can be performed in parallel. + + Increasing this parameter makes the solver + slightly less efficient serially (it always tries + to fill the batch with nodes, even if there is a + chance that most of them will be discarded later), + but greatly increases its parallel potential. + + Recommended values depend on the cores count and + on the limitations of the objective/constraints + callback: + * 1 for serial execution, callback that can not be + called from multiple threads, or highly + parallelized expensive callback that keeps all + cores occupied + * small fixed value like 5 or 10, if you need + reproducible behavior independent from the cores + count + * CORESCOUNT, 2*CORESCOUNT or some other multiple + of CORESCOUNT, if you want to utilize parallelism + to the maximum extent + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + +NOTES: if no stopping criteria is specified (unlimited budget, no timeout, + no neighborhood size limit), then the solver will run until + enumerating all integer solutions. + +===== ALGORITHM DESCRIPTION ============================================== + +A simplified description for an all-integer algorithm, omitting stopping +criteria and various checks: + + MIVNS (ALL-INTEGER): + 1. Input: initial integral point, may be infeasible wrt nonlinear + constraints, but is feasible wrt linear ones. Enforce linear + feasibility, if needed. + 2. Generate initial neighborhood around the current point that is + equal to the point itself. The point is marked as explored. + 3. Scan neighborhood for a better point (one that is less + infeasible or has lower objective); if one is found, make it + current and goto #2 + 4. Scan neighborhood for an unexplored point (one with no objective + computed). If one if found, compute objective, mark the point as + explored, goto #3 + 5. If there are no unexplored or better points in the neighborhood, + expand it: find a point that was not used for expansion, + compute up to 2N its nearest integral neighbors, add them to + the neighborhood and mark as unexplored. Goto #3. + + NOTE: A nearest integral neighbor is a nearest point that differs at + least by +1 or -1 in one of integral variables and that is + feasible with respect to box and linear constraints (ignoring + nonlinear ones). For problems with difficult constraint sets + integral neighbors are found by solving MIQP subproblems. + +The algorithm above systematically scans neighborhood of a point until +either better point is found, an entire integer grid is enumerated, or one +of stopping conditions is met. + +A mixed-integer version of the algorithm is more complex: +* it still sees optimization space as a set of integer nodes, each node + having a subspace of continuous variables associated with it +* after starting to explore a node, the algorithm runs an RBF surrogate- + based subsolver for the node. It manages a dedicated subsolver for each + node in a neighborhood and adaptively divides its computational budget + between subsolvers, switching to a node as soon as its subsolver shows + better results than its competitors. +* the algorithm remembers all previously evaluated points and reuses them + as much as possible + +===== ALGORITHM SCALING WITH VARIABLES COUNT N =========================== + +A 'neighborhood scan' is a minimum number of function evaluations needed +to perform at least minimal evaluation of the immediate neighborhood. For +an N-dimensional problem with NI integer variables and NF continuous ones +we have ~NI nodes in an immediate neighborhood, and each node needs ~NF +evalutations to build at least linear model of the objective. + +Thus, a MIVNS neighborhood scan will need about NI*NF=NI*(N-NI)=NF*(N-NF) +objective evaluations. + +It is important to note that MIVNS does not share information between +nodes because it assumes that objective landscape can drastically change +when jumping from node to node. That's why we need NI*NF instead of NI+NF +objective values. + +In practice, when started not too far away from the minimum, we can expect +to get some improvement in 5-10 scans, and to get significant progress in +50-100 scans. + +For problems with NF being small or NI being small we have scan cost +being proportional to variables count N, which allows us to achieve good +progress using between 5N and 100N objective values. However, when both +NI and NF are close to N/2, a scan needs ~N^2 objective evaluations, +which results in a much worse scaling behavior. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgomivns(minlpsolverstate* state, + ae_int_t budget, + ae_int_t maxneighborhood, + ae_int_t batchsize, + ae_state *_state) +{ + + + ae_assert(budget>=0, "MINLPSolverSetAlgoMIVNS: Budget<0", _state); + ae_assert(maxneighborhood>=0, "MINLPSolverSetAlgoMIVNS: MaxNeighborhood<0", _state); + ae_assert(batchsize>=1, "MINLPSolverSetAlgoMIVNS: BatchSize<1", _state); + state->algoidx = 1; + state->mirbfvnsalgo = 0; + state->mirbfvnsbudget = budget; + state->mirbfvnsmaxneighborhood = maxneighborhood; + state->mirbfvnsbatchsize = batchsize; +} + + +/************************************************************************* +This function activates multiple random restarts (performed for each node, +including root and child ones) that help to find global solutions to non- +convex problems. + +This parameter is used by branch-and-bound solvers and is presently +ignored by derivative-free solvers. + +INPUT PARAMETERS: + State - structure that stores algorithm state + NMultistarts - >=1, number of random restarts: + * 1 means that no restarts performed, the solver + assumes convexity + * >=1 means that solver assumes non-convexity and + performs fixed amount of random restarts + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetmultistarts(minlpsolverstate* state, + ae_int_t nmultistarts, + ae_state *_state) +{ + + + ae_assert(nmultistarts>=1, "MINLPSolverSetMultistarts: NMultistarts<1", _state); + state->nmultistarts = nmultistarts; +} + + +/************************************************************************* +This function activates timeout feature. The solver finishes after running +for a specified amount of time (in seconds, fractions can be used) with +the best point so far. + +Depending on the situation, the following completion codes can be reported +in rep.terminationtype: +* -33 (failure), if timed out without finding a feasible point +* 5 (partial success), if timed out after finding at least one feasible point + +The solver does not stop immediately after timeout was triggered because +it needs some time for underlying subsolvers to react to timeout signal. +Generally, about one additional subsolver iteration (which is usually far +less than one B&B split) will be performed prior to stopping. + +INPUT PARAMETERS: + State - structure that stores algorithm state + Timeout - >=0, timeout in seconds (floating point number): + * 0 means no timeout + * >=0 means stopping after specified number of + seconds. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversettimeout(minlpsolverstate* state, + double timeout, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(timeout, _state)&&ae_fp_greater_eq(timeout,(double)(0)), "MINLPSolverSetTimeout: Timeout<0 or is infinite/NAN", _state); + state->timeout = ae_iceil((double)1000*timeout, _state); +} + + +/************************************************************************* + + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool minlpsolveriteration(minlpsolverstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t k; + ae_int_t originalrequesttype; + ae_bool done; + ae_bool densejac; + ae_bool b; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + originalrequesttype = state->rstate.ia.ptr.p_int[3]; + done = state->rstate.ba.ptr.p_bool[0]; + densejac = state->rstate.ba.ptr.p_bool[1]; + b = state->rstate.ba.ptr.p_bool[2]; + } + else + { + n = 359; + i = -58; + k = -919; + originalrequesttype = -909; + done = ae_true; + densejac = ae_true; + b = ae_false; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + + /* + * Routine body + */ + ae_assert(state->hasx0, "MINLPSolver: integrity check 500655 failed", _state); + n = state->n; + minlpsolvers_clearoutputs(state, _state); + xlcconverttosparse(&state->xlc, _state); + state->tracelevel = 0; + if( ae_is_trace_enabled("MINLP") ) + { + state->tracelevel = 2; + } + if( ae_is_trace_enabled("MINLP.LACONIC") ) + { + state->tracelevel = 1; + } + + /* + * Initial trace messages + */ + if( state->tracelevel>0 ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// MINLP SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("cntLC = %6d\n", + (int)(state->xlc.nsparse+state->xlc.ndense)); + ae_trace("cntNLC = %6d\n", + (int)(state->nnlc)); + k = 0; + for(i=0; i<=n-1; i++) + { + if( state->isintegral.ptr.p_bool[i] ) + { + k = k+1; + } + } + ae_trace("nIntegral = %6d vars", + (int)(k)); + k = 0; + for(i=0; i<=n-1; i++) + { + if( state->isbinary.ptr.p_bool[i] ) + { + k = k+1; + } + } + if( k>0 ) + { + ae_trace(" (incl. %0d binary ones)", + (int)(k)); + } + ae_trace("\n"); + if( state->algoidx==0 ) + { + ae_trace("> printing BBSYNC solver parameters:\n"); + ae_trace("GroupSize = %6d\n", + (int)(state->bbgdgroupsize)); + ae_trace("Multistarts = %6d\n", + (int)(state->nmultistarts)); + if( state->timeout>0 ) + { + ae_trace("Timeout = %0.1fs\n", + (double)(0.001*(double)state->timeout)); + } + else + { + ae_trace("Timeout = none\n"); + } + } + if( state->algoidx==1 ) + { + ae_trace("> printing MIVNS solver parameters:\n"); + if( state->mirbfvnsbudget>0 ) + { + ae_trace("Budget = %6d\n", + (int)(state->mirbfvnsbudget)); + } + else + { + ae_trace("Budget = inf\n"); + } + if( state->mirbfvnsmaxneighborhood>0 ) + { + ae_trace("MaxNeighbors = %6d\n", + (int)(state->mirbfvnsmaxneighborhood)); + } + else + { + ae_trace("MaxNeighbors = inf\n"); + } + ae_trace("BatchSize = %6d\n", + (int)(state->mirbfvnsbatchsize)); + if( state->timeout>0 ) + { + ae_trace("Timeout = %0.1fs\n", + (double)(0.001*(double)state->timeout)); + } + else + { + ae_trace("Timeout = none\n"); + } + } + ae_trace("\n"); + } + + /* + * Init the solver + */ + done = ae_false; + if( state->algoidx==0 ) + { + if( !(state->bbgdsubsolver!=NULL) ) + { + state->bbgdsubsolver = (bbgdstate*)ae_malloc(sizeof(bbgdstate), _state); /* note: using state->bbgdsubsolver as a temporary prior to assigning its value to _state->bbgdsubsolver */ + memset(state->bbgdsubsolver, 0, sizeof(bbgdstate)); + _bbgdstate_init(state->bbgdsubsolver, _state, ae_false); + ae_smart_ptr_assign(&state->_bbgdsubsolver, state->bbgdsubsolver, ae_true, ae_true, (ae_int_t)sizeof(bbgdstate), _bbgdstate_init_copy, _bbgdstate_destroy); + } + bbgdcreatebuf(n, &state->bndl, &state->bndu, &state->s, &state->x0, &state->isintegral, &state->isbinary, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->nl, &state->nu, state->nnlc, state->bbgdgroupsize, state->nmultistarts, state->timeout, state->tracelevel, state->bbgdsubsolver, _state); + if( ae_fp_greater(state->pdgap,(double)(0)) ) + { + bbgdsetpdgap(state->bbgdsubsolver, state->pdgap, _state); + } + if( ae_fp_greater(state->ctol,(double)(0)) ) + { + bbgdsetctol(state->bbgdsubsolver, state->ctol, _state); + } + if( ae_fp_greater(state->subsolverepsx,(double)(0)) ) + { + bbgdsetepsx(state->bbgdsubsolver, state->subsolverepsx, _state); + } + if( ae_fp_greater(state->subsolverepsf,(double)(0)) ) + { + bbgdsetepsf(state->bbgdsubsolver, state->subsolverepsf, _state); + } + if( state->bbsyncprofile==0 ) + { + bbgdsetsmalltree(state->bbgdsubsolver, _state); + } + if( state->bbsyncprofile==1 ) + { + bbgdsetlargetree(state->bbgdsubsolver, _state); + } + done = ae_true; + } + if( state->algoidx==1 ) + { + if( !(state->mirbfvnssubsolver!=NULL) ) + { + state->mirbfvnssubsolver = (mirbfvnsstate*)ae_malloc(sizeof(mirbfvnsstate), _state); /* note: using state->mirbfvnssubsolver as a temporary prior to assigning its value to _state->mirbfvnssubsolver */ + memset(state->mirbfvnssubsolver, 0, sizeof(mirbfvnsstate)); + _mirbfvnsstate_init(state->mirbfvnssubsolver, _state, ae_false); + ae_smart_ptr_assign(&state->_mirbfvnssubsolver, state->mirbfvnssubsolver, ae_true, ae_true, (ae_int_t)sizeof(mirbfvnsstate), _mirbfvnsstate_init_copy, _mirbfvnsstate_destroy); + } + mirbfvnscreatebuf(n, &state->bndl, &state->bndu, &state->s, &state->x0, &state->isintegral, &state->isbinary, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->nl, &state->nu, state->nnlc, state->mirbfvnsalgo, state->mirbfvnsbudget, state->mirbfvnsmaxneighborhood, state->mirbfvnsbatchsize, state->timeout, state->tracelevel, state->mirbfvnssubsolver, _state); + mirbfvnssetadaptiveinternalparallelism(state->mirbfvnssubsolver, state->adaptiveinternalparallelism, _state); + if( ae_fp_greater(state->ctol,(double)(0)) ) + { + mirbfvnssetctol(state->mirbfvnssubsolver, state->ctol, _state); + } + if( ae_fp_greater(state->subsolverepsf,(double)(0)) ) + { + mirbfvnssetepsf(state->mirbfvnssubsolver, state->subsolverepsf, _state); + } + if( ae_fp_greater(state->subsolverepsx,(double)(0)) ) + { + mirbfvnssetepsx(state->mirbfvnssubsolver, state->subsolverepsx, _state); + } + b = state->hasobjmask; + for(i=0; i<=state->nnlc-1; i++) + { + b = b||state->hasnlcmask.ptr.p_bool[i]; + } + if( b ) + { + ballocv(1+state->nnlc, &state->tmpb1, _state); + sparsecreatecrsemptybuf(n, &state->tmpsparse, _state); + sparseappendemptyrow(&state->tmpsparse, _state); + state->tmpb1.ptr.p_bool[0] = state->hasobjmask; + if( state->hasobjmask ) + { + for(i=0; i<=n-1; i++) + { + if( state->objmask.ptr.p_bool[i] ) + { + sparseappendelement(&state->tmpsparse, i, 1.0, _state); + } + } + } + if( state->nnlc>0 ) + { + sparseappendmatrix(&state->tmpsparse, &state->nlcmask, _state); + } + for(i=0; i<=state->nnlc-1; i++) + { + state->tmpb1.ptr.p_bool[1+i] = state->hasnlcmask.ptr.p_bool[i]; + } + mirbfvnssetvariablemask(state->mirbfvnssubsolver, &state->tmpb1, &state->tmpsparse, _state); + } + done = ae_true; + } + ae_assert(done, "MINLPSolvers: 891649 failed", _state); + + /* + * Run the solver + */ + done = ae_false; + if( state->algoidx!=0 ) + { + goto lbl_2; + } +lbl_4: + if( !bbgditeration(state->bbgdsubsolver, _state) ) + { + goto lbl_5; + } + + /* + * Offload request + */ + bbgdoffloadrcommrequest(state->bbgdsubsolver, &originalrequesttype, &state->querysize, &state->queryfuncs, &state->queryvars, &state->querydim, &state->queryformulasize, &state->querydata, _state); + ae_assert(originalrequesttype==1, "MINLPSOLVERS: integrity check 328345 failed", _state); + state->requesttype = icase2(state->issuesparserequests, originalrequesttype, 2, _state); + + /* + * Initialize temporaries and prepare place for reply + */ + densejac = (state->requesttype==2||state->requesttype==3)||state->requesttype==5; + rallocv(n, &state->tmpg1, _state); + rallocv(n, &state->tmpx1, _state); + rallocv(1+state->nnlc, &state->tmpf1, _state); + if( densejac ) + { + rallocm(1+state->nnlc, n, &state->tmpj1, _state); + rallocv(state->queryfuncs*state->queryvars*state->querysize, &state->replydj, _state); + } + rallocv(state->queryfuncs*state->querysize, &state->replyfi, _state); + + /* + * RComm and copy back + */ + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( densejac ) + { + sparsecreatecrsfromdensevbuf(&state->replydj, state->querysize*state->queryfuncs, state->queryvars, &state->replysj, _state); + } + bbgdloadrcommreply(state->bbgdsubsolver, originalrequesttype, state->querysize, state->queryfuncs, state->queryvars, state->querydim, state->queryformulasize, &state->replyfi, &state->rdummy, &state->replysj, _state); + goto lbl_4; +lbl_5: + done = ae_true; +lbl_2: + if( state->algoidx!=1 ) + { + goto lbl_6; + } +lbl_8: + if( !mirbfvnsiteration(state->mirbfvnssubsolver, _state) ) + { + goto lbl_9; + } + + /* + * Offload request + */ + ae_assert(state->mirbfvnssubsolver->requesttype==4, "MINLPSOLVERS: 993231 failed", _state); + state->requesttype = state->mirbfvnssubsolver->requesttype; + state->querysize = state->mirbfvnssubsolver->querysize; + state->queryfuncs = state->mirbfvnssubsolver->queryfuncs; + state->queryvars = state->mirbfvnssubsolver->queryvars; + state->querydim = state->mirbfvnssubsolver->querydim; + rcopyallocv(state->querysize*(state->queryvars+state->querydim), &state->mirbfvnssubsolver->querydata, &state->querydata, _state); + + /* + * Initialize temporaries and prepare place for reply + */ + rallocv(n, &state->tmpx1, _state); + rallocv(1+state->nnlc, &state->tmpf1, _state); + rallocv(state->queryfuncs*state->querysize, &state->replyfi, _state); + + /* + * RComm and copy back + */ + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rcopyv(state->querysize*state->queryfuncs, &state->replyfi, &state->mirbfvnssubsolver->replyfi, _state); + goto lbl_8; +lbl_9: + done = ae_true; +lbl_6: + ae_assert(done, "MINLPSolvers: 926649 failed", _state); + + /* + * Save results + */ + done = ae_false; + if( state->algoidx==0 ) + { + rcopyallocv(n, &state->bbgdsubsolver->xc, &state->xc, _state); + state->repnfev = state->bbgdsubsolver->repnfev; + state->repnsubproblems = state->bbgdsubsolver->repnsubproblems; + state->repntreenodes = state->bbgdsubsolver->repntreenodes; + state->repnnodesbeforefeasibility = state->bbgdsubsolver->repnnodesbeforefeasibility; + state->repterminationtype = state->bbgdsubsolver->repterminationtype; + state->repf = state->bbgdsubsolver->repf; + state->reppdgap = state->bbgdsubsolver->reppdgap; + done = ae_true; + } + if( state->algoidx==1 ) + { + rcopyallocv(n, &state->mirbfvnssubsolver->xc, &state->xc, _state); + state->repnfev = state->mirbfvnssubsolver->repnfev; + state->repnsubproblems = 0; + state->repntreenodes = 0; + state->repnnodesbeforefeasibility = 0; + state->repterminationtype = state->mirbfvnssubsolver->repterminationtype; + state->repf = state->mirbfvnssubsolver->fc; + state->reppdgap = (double)(0); + done = ae_true; + } + ae_assert(done, "MINLPSolvers: 944650 failed", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ia.ptr.p_int[2] = k; + state->rstate.ia.ptr.p_int[3] = originalrequesttype; + state->rstate.ba.ptr.p_bool[0] = done; + state->rstate.ba.ptr.p_bool[1] = densejac; + state->rstate.ba.ptr.p_bool[2] = b; + return result; +} + + +/************************************************************************* +This subroutine restarts algorithm from new point. All optimization +parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverrestartfrom(minlpsolverstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MINLPSolverRestartFrom: Length(X)x0, _state); + state->hasx0 = ae_true; + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 2+1, _state); + state->rstate.stage = -1; + minlpsolvers_clearoutputs(state, _state); +} + + +/************************************************************************* +MINLPSolver results: the solution found, completion codes and additional +information. + +INPUT PARAMETERS: + Solver - solver + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + rep.f contains objective value at the solution. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one. + + More information about fields of this structure can be + found in the comments on the minlpsolverreport datatype. + + -- ALGLIB -- + Copyright 18.01.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverresults(const minlpsolverstate* state, + /* Real */ ae_vector* x, + minlpsolverreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minlpsolverreport_clear(rep); + + minlpsolverresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +NLC results + +Buffered implementation of MINLPSolverResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverresultsbuf(const minlpsolverstate* state, + /* Real */ ae_vector* x, + minlpsolverreport* rep, + ae_state *_state) +{ + + + rep->f = state->repf; + rep->nfev = state->repnfev; + rep->nsubproblems = state->repnsubproblems; + rep->ntreenodes = state->repntreenodes; + rep->nnodesbeforefeasibility = state->repnnodesbeforefeasibility; + rep->terminationtype = state->repterminationtype; + rep->pdgap = state->reppdgap; + if( state->repterminationtype>0 ) + { + rcopyallocv(state->n, &state->xc, x, _state); + } + else + { + rsetallocv(state->n, _state->v_nan, x, _state); + } +} + + +/************************************************************************* +Set V2 reverse communication protocol with dense requests +*************************************************************************/ +void minlpsolversetprotocolv2(minlpsolverstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_false; + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol with sparse requests +*************************************************************************/ +void minlpsolversetprotocolv2s(minlpsolverstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_true; + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears output fields during initialization +*************************************************************************/ +static void minlpsolvers_clearoutputs(minlpsolverstate* state, + ae_state *_state) +{ + + + state->userterminationneeded = ae_false; + state->repnfev = 0; + state->repterminationtype = 0; + state->repf = (double)(0); + state->reppdgap = ae_maxrealnumber; + state->repnsubproblems = 0; + state->repntreenodes = 0; + state->repnnodesbeforefeasibility = -1; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void minlpsolvers_initinternal(ae_int_t n, + /* Real */ const ae_vector* x, + ae_int_t solvermode, + double diffstep, + minlpsolverstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + state->protocolversion = 2; + state->issuesparserequests = ae_false; + state->convexityflag = 0; + + /* + * Initialize other params + */ + critinitdefault(&state->criteria, _state); + state->timeout = 0; + state->pdgap = (double)(0); + state->ctol = (double)(0); + state->n = n; + state->subsolverepsx = (double)(0); + state->subsolverepsf = (double)(0); + state->nmultistarts = 1; + state->diffstep = diffstep; + state->userterminationneeded = ae_false; + bsetallocv(n, ae_false, &state->isintegral, _state); + bsetallocv(n, ae_false, &state->isbinary, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->x0, n, _state); + ae_vector_set_length(&state->xc, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->s.ptr.p_double[i] = 1.0; + state->x0.ptr.p_double[i] = x->ptr.p_double[i]; + state->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + state->hasx0 = ae_true; + state->hasobjmask = ae_false; + + /* + * Constraints + */ + xlcinit(n, &state->xlc, _state); + sparsecreatecrsemptybuf(n, &state->nlcmask, _state); + state->nnlc = 0; + + /* + * Report fields + */ + minlpsolvers_clearoutputs(state, _state); + + /* + * RComm + */ + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 2+1, _state); + state->rstate.stage = -1; + + /* + * Final setup + */ + minlpsolversetbbsyncprofilesmalltree(state, _state); + minlpsolvercautiousinternalparallelism(state, _state); + minlpsolversetalgobbsync(state, 1, _state); + ae_frame_leave(_state); +} + + +void _minlpsolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlpsolverstate *p = (minlpsolverstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isintegral, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isbinary, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->objmask, 0, DT_BOOL, _state, make_automatic); + _xlinearconstraints_init(&p->xlc, _state, make_automatic); + _sparsematrix_init(&p->nlcmask, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasnlcmask, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + ae_smart_ptr_init(&p->_bbgdsubsolver, (void**)&p->bbgdsubsolver, ae_true, _state, make_automatic); + ae_smart_ptr_init(&p->_mirbfvnssubsolver, (void**)&p->mirbfvnssubsolver, ae_true, _state, make_automatic); + ae_vector_init(&p->rdummy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpb1, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->tmpsparse, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _minlpsolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlpsolverstate *dst = (minlpsolverstate*)_dst; + const minlpsolverstate *src = (const minlpsolverstate*)_src; + dst->n = src->n; + dst->algoidx = src->algoidx; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->diffstep = src->diffstep; + dst->convexityflag = src->convexityflag; + dst->pdgap = src->pdgap; + dst->ctol = src->ctol; + dst->subsolverepsx = src->subsolverepsx; + dst->subsolverepsf = src->subsolverepsf; + dst->nmultistarts = src->nmultistarts; + dst->timeout = src->timeout; + dst->bbgdgroupsize = src->bbgdgroupsize; + dst->mirbfvnsbudget = src->mirbfvnsbudget; + dst->mirbfvnsmaxneighborhood = src->mirbfvnsmaxneighborhood; + dst->mirbfvnsbatchsize = src->mirbfvnsbatchsize; + dst->mirbfvnsalgo = src->mirbfvnsalgo; + dst->adaptiveinternalparallelism = src->adaptiveinternalparallelism; + dst->bbsyncprofile = src->bbsyncprofile; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->isintegral, &src->isintegral, _state, make_automatic); + ae_vector_init_copy(&dst->isbinary, &src->isbinary, _state, make_automatic); + dst->hasobjmask = src->hasobjmask; + ae_vector_init_copy(&dst->objmask, &src->objmask, _state, make_automatic); + _xlinearconstraints_init_copy(&dst->xlc, &src->xlc, _state, make_automatic); + _sparsematrix_init_copy(&dst->nlcmask, &src->nlcmask, _state, make_automatic); + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + ae_vector_init_copy(&dst->hasnlcmask, &src->hasnlcmask, _state, make_automatic); + dst->hasx0 = src->hasx0; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->protocolversion = src->protocolversion; + dst->issuesparserequests = src->issuesparserequests; + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + dst->repnfev = src->repnfev; + dst->repnsubproblems = src->repnsubproblems; + dst->repntreenodes = src->repntreenodes; + dst->repnnodesbeforefeasibility = src->repnnodesbeforefeasibility; + dst->repterminationtype = src->repterminationtype; + dst->repf = src->repf; + dst->reppdgap = src->reppdgap; + dst->tracelevel = src->tracelevel; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + ae_smart_ptr_init(&dst->_bbgdsubsolver, (void**)&dst->bbgdsubsolver, ae_true, _state, make_automatic); + if( src->bbgdsubsolver!=NULL ) + { + dst->bbgdsubsolver = (bbgdstate*)ae_malloc(sizeof(bbgdstate), _state); /* note: using bbgdsubsolver as a temporary prior to assigning its value to _bbgdsubsolver */ + memset(dst->bbgdsubsolver, 0, sizeof(bbgdstate)); + _bbgdstate_init_copy(dst->bbgdsubsolver, src->bbgdsubsolver, _state, ae_false); + ae_smart_ptr_assign(&dst->_bbgdsubsolver, dst->bbgdsubsolver, ae_true, ae_true, (ae_int_t)sizeof(bbgdstate), _bbgdstate_init_copy, _bbgdstate_destroy); + } + ae_smart_ptr_init(&dst->_mirbfvnssubsolver, (void**)&dst->mirbfvnssubsolver, ae_true, _state, make_automatic); + if( src->mirbfvnssubsolver!=NULL ) + { + dst->mirbfvnssubsolver = (mirbfvnsstate*)ae_malloc(sizeof(mirbfvnsstate), _state); /* note: using mirbfvnssubsolver as a temporary prior to assigning its value to _mirbfvnssubsolver */ + memset(dst->mirbfvnssubsolver, 0, sizeof(mirbfvnsstate)); + _mirbfvnsstate_init_copy(dst->mirbfvnssubsolver, src->mirbfvnssubsolver, _state, ae_false); + ae_smart_ptr_assign(&dst->_mirbfvnssubsolver, dst->mirbfvnssubsolver, ae_true, ae_true, (ae_int_t)sizeof(mirbfvnsstate), _mirbfvnsstate_init_copy, _mirbfvnsstate_destroy); + } + ae_vector_init_copy(&dst->rdummy, &src->rdummy, _state, make_automatic); + ae_vector_init_copy(&dst->tmpb1, &src->tmpb1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpsparse, &src->tmpsparse, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _minlpsolverstate_clear(void* _p) +{ + minlpsolverstate *p = (minlpsolverstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->isintegral); + ae_vector_clear(&p->isbinary); + ae_vector_clear(&p->objmask); + _xlinearconstraints_clear(&p->xlc); + _sparsematrix_clear(&p->nlcmask); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->hasnlcmask); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + ae_smart_ptr_clear(&p->_bbgdsubsolver); + ae_smart_ptr_clear(&p->_mirbfvnssubsolver); + ae_vector_clear(&p->rdummy); + ae_vector_clear(&p->tmpb1); + _sparsematrix_clear(&p->tmpsparse); + _rcommstate_clear(&p->rstate); +} + + +void _minlpsolverstate_destroy(void* _p) +{ + minlpsolverstate *p = (minlpsolverstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->isintegral); + ae_vector_destroy(&p->isbinary); + ae_vector_destroy(&p->objmask); + _xlinearconstraints_destroy(&p->xlc); + _sparsematrix_destroy(&p->nlcmask); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->hasnlcmask); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + ae_smart_ptr_destroy(&p->_bbgdsubsolver); + ae_smart_ptr_destroy(&p->_mirbfvnssubsolver); + ae_vector_destroy(&p->rdummy); + ae_vector_destroy(&p->tmpb1); + _sparsematrix_destroy(&p->tmpsparse); + _rcommstate_destroy(&p->rstate); +} + + +void _minlpsolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlpsolverreport *p = (minlpsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlpsolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlpsolverreport *dst = (minlpsolverreport*)_dst; + const minlpsolverreport *src = (const minlpsolverreport*)_src; + dst->f = src->f; + dst->nfev = src->nfev; + dst->nsubproblems = src->nsubproblems; + dst->ntreenodes = src->ntreenodes; + dst->nnodesbeforefeasibility = src->nnodesbeforefeasibility; + dst->terminationtype = src->terminationtype; + dst->pdgap = src->pdgap; +} + + +void _minlpsolverreport_clear(void* _p) +{ + minlpsolverreport *p = (minlpsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlpsolverreport_destroy(void* _p) +{ + minlpsolverreport *p = (minlpsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif + +} + diff --git a/core/alglib/minlp.h b/core/alglib/minlp.h new file mode 100644 index 00000000..508ab877 --- /dev/null +++ b/core/alglib/minlp.h @@ -0,0 +1,2283 @@ +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _minlp_pkg_h +#define _minlp_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "solvers.h" +#include "optimization.h" +#include "interpolation.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t leafid; + ae_int_t n; + ae_vector x0; + ae_vector bndl; + ae_vector bndu; + ae_int_t branchbucket; + double parentfdual; + ae_int_t branchvar; + double branchval; + ae_int_t ncuttingplanes; + ae_bool hasprimalsolution; + ae_vector xprim; + double fprim; + double hprim; + ae_bool hasdualsolution; + ae_vector bestxdual; + double bestfdual; + double besthdual; + ae_vector worstxdual; + double worstfdual; + double worsthdual; + ae_bool bestdualisintfeas; + double dualbound; +} bbgdsubproblem; +typedef struct +{ + ae_int_t subsolverstatus; + bbgdsubproblem subproblem; + minnlcstate nlpsubsolver; + ipm2state qpsubsolver; + minnlcreport nlprep; + rcommstate rstate; + ae_vector xsol; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmp3; + ae_vector tmpi; + ae_vector wrks; + ae_vector wrkbndl; + ae_vector wrkbndu; + ae_vector wrkb; + ae_vector psvpackxyperm; + ae_vector psvunpackxyperm; + ae_vector psvs; + ae_vector psvxorigin; + ae_vector psvbndl; + ae_vector psvbndu; + ae_vector psvb; + ae_vector psvfixvals; + ae_vector psvrawbndl; + ae_vector psvrawbndu; + ae_int_t npsv; + sparsematrix psva; + sparsematrix psvsparsec; + ae_vector psvcl; + ae_vector psvcu; + ae_int_t psvlccnt; + ae_vector psvqpordering; +} bbgdfrontsubsolver; +typedef struct +{ + ae_int_t entrystatus; + ae_bool addstatussolutionsaggregated; + ae_bool addstatusdecisionsmade; + ae_int_t entrylock; + ae_bool isrootentry; + ae_int_t maxsubsolvers; + ae_bool hastimeout; + ae_int_t timeout; + stimer timerlocal; + bbgdsubproblem parentsubproblem; + bbgdsubproblem rootproblem; + bbgdsubproblem childsubproblem0; + bbgdsubproblem childsubproblem1; + rcommstate rstate; + ae_bool fathomroot; + ae_bool fathomchild0; + ae_bool fathomchild1; + ae_obj_array subsolvers; + ae_obj_array spqueue; + ae_obj_array solutions; + bbgdsubproblem tmpsubproblem; + ae_vector tmpreliablebranchidx; + ae_vector tmpreliablebranchscore; + ae_vector tmpunreliablebranchidx; + ae_vector tmpunreliablebranchscore; + ae_vector tmpchosenbranchidx; + ae_vector tmpchosenbranchscore; +} bbgdfrontentry; +typedef struct +{ + ae_int_t frontmode; + ae_int_t frontstatus; + ae_bool popmostrecent; + ae_int_t backtrackbudget; + ae_int_t frontsize; + ae_obj_array entries; + ae_shared_pool entrypool; + rcommstate rstate; + ae_vector jobs; +} bbgdfront; +typedef struct +{ + ae_int_t n; + nlpstoppingcriteria criteria; + double diffstep; + ae_int_t convexityflag; + double nonconvexitygain; + double pdgap; + double ctol; + double epsx; + double epsf; + ae_int_t nonrootmaxitslin; + ae_int_t nonrootmaxitsconst; + ae_int_t nonrootadditsforfeasibility; + double pseudocostmu; + double pseudocostminfrac; + double pseudocostinfeaspenaly; + ae_int_t nmultistarts; + ae_int_t branchingtype; + ae_int_t krel; + ae_int_t kevalunreliable; + ae_int_t kevalreliable; + ae_int_t dodiving; + ae_int_t timeout; + ae_int_t bbgdgroupsize; + ae_int_t maxsubsolvers; + ae_bool forceserial; + ae_int_t softmaxnodes; + ae_int_t hardmaxnodes; + ae_int_t maxprimalcandidates; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector isintegral; + ae_vector isbinary; + ae_int_t objtype; + sparsematrix obja; + ae_vector objb; + double objc0; + ae_vector qpordering; + sparsematrix rawa; + ae_vector rawal; + ae_vector rawau; + ae_vector lcsrcidx; + ae_int_t lccnt; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_bool hasx0; + ae_vector x0; + ae_bool userterminationneeded; + ae_vector xc; + ae_int_t repnfev; + ae_int_t repnsubproblems; + ae_int_t repntreenodes; + ae_int_t repnnodesbeforefeasibility; + ae_int_t repnprimalcandidates; + ae_int_t repterminationtype; + double repf; + double reppdgap; + stimer timerglobal; + ae_bool dotrace; + ae_bool dolaconictrace; + ae_int_t nextleafid; + ae_bool hasprimalsolution; + ae_vector xprim; + double fprim; + double hprim; + double ffdual; + ae_bool timedout; + bbgdsubproblem rootsubproblem; + ae_obj_array bbsubproblems; + ae_int_t bbsubproblemsheapsize; + ae_int_t bbsubproblemsrecentlyadded; + bbgdfront front; + ae_shared_pool sppool; + ae_shared_pool subsolverspool; + ae_vector pseudocostsup; + ae_vector pseudocostsdown; + ae_vector pseudocostscntup; + ae_vector pseudocostscntdown; + double globalpseudocostup; + double globalpseudocostdown; + ae_int_t globalpseudocostcntup; + ae_int_t globalpseudocostcntdown; + hqrndstate unsafeglobalrng; + ae_int_t requestsource; + ae_int_t lastrequesttype; + bbgdsubproblem dummysubproblem; + bbgdfrontsubsolver dummysubsolver; + ipm2state dummyqpsubsolver; + bbgdfrontentry dummyentry; + ae_matrix densedummy2; + rcommstate rstate; +} bbgdstate; +#endif +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool isdense; + ae_int_t n; + ae_int_t nf; + ae_vector vmodelbase; + ae_vector vmodelscale; + ae_vector multscale; + ae_matrix clinear; + ae_matrix mx0; + ae_int_t nc; + ae_matrix centers; + ae_matrix crbf; + ae_vector cridx; + sparsematrix spcenters; + ae_vector spcoeffs; +} mirbfmodel; +typedef struct +{ + double trustrad; + ae_bool sufficientcloudsize; + double basef; + double baseh; + double predf; + double predh; + double skrellen; + double maxh; + ae_vector successfhistory; + ae_vector successhhistory; + ae_int_t historymax; +} mirbfvnsnodesubsolver; +typedef struct +{ + nlpstoppingcriteria crit; + ae_vector bndlx; + ae_vector bndux; + ae_vector x0x; + ae_vector sx; + ae_vector scalingfactors; + minfsqpstate fsqpsolver; + smoothnessmonitor smonitor; + sparsematrix cx; + ae_vector clx; + ae_vector cux; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmpnl; + ae_vector tmpnu; + ae_vector tmpi; +} rbfmmtemporaries; +typedef struct +{ + stimer localtimer; + hqrndstate localrng; + ae_vector glbbndl; + ae_vector glbbndu; + ae_vector fullx0; + ae_vector glbx0; + ae_vector glbtmp0; + ae_vector glbtmp1; + ae_vector glbtmp2; + ae_matrix glbxf; + ae_matrix glbsx; + ae_matrix ortdeltas; + ae_vector glbmultscale; + ae_vector glbvtrustregion; + mirbfmodel glbmodel; + rbfmmtemporaries buf; + ae_vector glbsk; + ae_matrix glbrandomprior; + ae_vector glbprioratx0; + ae_vector glbxtrial; + ae_vector glbs; + ae_vector mapfull2compact; + sparsematrix glba; + ae_vector glbal; + ae_vector glbau; + ae_vector glbmask; + rbfmmtemporaries mmbuf; + ae_vector lclidxfrac; + ae_vector lcl2glb; + ae_matrix lclxf; + ae_matrix lclsx; + ae_vector nodeslist; + ae_matrix lclrandomprior; + ae_vector lclmultscale; + ae_vector lcls; + ae_vector lclx0; + mirbfmodel tmpmodel; + ipm2state qpsubsolver; + bbgdstate bbgdsubsolver; + ae_vector wrkbndl; + ae_vector wrkbndu; + sparsematrix diaga; + ae_vector linb; +} mirbfvnstemporaries; +typedef struct +{ + ae_int_t nnodes; + ae_matrix nodesinfo; + ae_int_t ptlistlength; + ae_vector ptlistheads; + ae_vector ptlistdata; + ae_obj_array subsolvers; + ae_int_t naddcols; +} mirbfvnsgrid; +typedef struct +{ + ae_int_t npoints; + ae_int_t nvars; + ae_int_t nnlc; + ae_matrix pointinfo; +} mirbfvnsdataset; +typedef struct +{ + ae_int_t n; + nlpstoppingcriteria criteria; + ae_int_t algomode; + ae_int_t budget; + ae_int_t maxneighborhood; + ae_int_t batchsize; + ae_bool expandneighborhoodonstart; + ae_bool retrylastcut; + ae_int_t convexityflag; + double ctol; + double epsf; + double quickepsf; + double epsx; + ae_int_t adaptiveinternalparallelism; + ae_int_t timeout; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector finitebndl; + ae_vector finitebndu; + ae_vector isintegral; + ae_vector isbinary; + sparsematrix rawa; + ae_vector rawal; + ae_vector rawau; + ae_vector lcsrcidx; + ae_int_t lccnt; + ae_bool haslinearlyconstrainedints; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_bool nomask; + ae_vector hasmask; + sparsematrix varmask; + ae_bool hasx0; + ae_vector x0; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_bool userterminationneeded; + ae_int_t repnfev; + ae_int_t repsubsolverits; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + stimer timerglobal; + stimer timerprepareneighbors; + stimer timerproposetrial; + ae_int_t explorativetrialcnt; + ae_int_t explorativetrialtimems; + ae_int_t localtrialsamplingcnt; + ae_int_t localtrialsamplingtimems; + ae_int_t localtrialrbfcnt; + ae_int_t localtrialrbftimems; + ae_int_t cutcnt; + ae_int_t cuttimems; + ae_int_t dbgpotentiallyparallelbatches; + ae_int_t dbgsequentialbatches; + ae_int_t dbgpotentiallyparallelcutrounds; + ae_int_t dbgsequentialcutrounds; + ae_bool prepareevaluationbatchparallelism; + ae_bool expandcutgenerateneighborsparallelism; + ae_bool doanytrace; + ae_bool dotrace; + ae_bool doextratrace; + ae_bool dolaconictrace; + ae_vector xc; + double fc; + double mxc; + double hc; + ae_int_t nodec; + ae_vector nodecproducedbycut; + mirbfvnsgrid grid; + mirbfvnsdataset dataset; + ae_int_t nfrac; + ae_int_t nint; + ae_vector xcneighbors; + ae_vector xcreachedfrom; + ae_matrix xcreachedbycut; + ae_vector xcqueryflags; + ae_int_t xcneighborscnt; + ae_int_t xcpriorityneighborscnt; + ae_int_t evalbatchsize; + ae_matrix evalbatchpoints; + ae_vector evalbatchnodeidx; + ae_vector evalbatchneighboridx; + ae_bool outofbudget; + hqrndstate unsafeglobalrng; + ae_vector maskint; + ae_vector maskfrac; + ae_vector idxint; + ae_vector idxfrac; + ae_vector xuneighbors; + ae_matrix xucuts; + ae_matrix xupoints; + ae_vector xuflags; + ae_vector xtrial; + ae_vector trialfi; + ae_vector tmpeb0; + ae_vector tmpeb1; + ae_vector tmpeb2; + mirbfvnstemporaries dummytmp; + ae_matrix densedummy2; + ae_nxpool rpool; + ae_shared_pool tmppool; + rcommstate rstate; +} mirbfvnsstate; +#endif +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t algoidx; + nlpstoppingcriteria criteria; + double diffstep; + ae_int_t convexityflag; + double pdgap; + double ctol; + double subsolverepsx; + double subsolverepsf; + ae_int_t nmultistarts; + ae_int_t timeout; + ae_int_t bbgdgroupsize; + ae_int_t mirbfvnsbudget; + ae_int_t mirbfvnsmaxneighborhood; + ae_int_t mirbfvnsbatchsize; + ae_int_t mirbfvnsalgo; + ae_int_t adaptiveinternalparallelism; + ae_int_t bbsyncprofile; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_vector isintegral; + ae_vector isbinary; + ae_bool hasobjmask; + ae_vector objmask; + xlinearconstraints xlc; + sparsematrix nlcmask; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_vector hasnlcmask; + ae_bool hasx0; + ae_vector x0; + ae_int_t protocolversion; + ae_bool issuesparserequests; + ae_bool userterminationneeded; + ae_vector xc; + ae_int_t repnfev; + ae_int_t repnsubproblems; + ae_int_t repntreenodes; + ae_int_t repnnodesbeforefeasibility; + ae_int_t repterminationtype; + double repf; + double reppdgap; + ae_int_t tracelevel; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_smart_ptr _bbgdsubsolver; + bbgdstate *bbgdsubsolver; + ae_smart_ptr _mirbfvnssubsolver; + mirbfvnsstate *mirbfvnssubsolver; + ae_vector rdummy; + ae_vector tmpb1; + sparsematrix tmpsparse; + rcommstate rstate; +} minlpsolverstate; +typedef struct +{ + double f; + ae_int_t nfev; + ae_int_t nsubproblems; + ae_int_t ntreenodes; + ae_int_t nnodesbeforefeasibility; + ae_int_t terminationtype; + double pdgap; +} minlpsolverreport; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +class _minlpsolverstate_owner; +class minlpsolverstate; +class _minlpsolverreport_owner; +class minlpsolverreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinNLC subpackage to work with this +object +*************************************************************************/ +class _minlpsolverstate_owner +{ +public: + _minlpsolverstate_owner(); + _minlpsolverstate_owner(alglib_impl::minlpsolverstate *attach_to); + _minlpsolverstate_owner(const _minlpsolverstate_owner &rhs); + _minlpsolverstate_owner& operator=(const _minlpsolverstate_owner &rhs); + virtual ~_minlpsolverstate_owner(); + alglib_impl::minlpsolverstate* c_ptr(); + const alglib_impl::minlpsolverstate* c_ptr() const; +protected: + alglib_impl::minlpsolverstate *p_struct; + bool is_attached; +}; +class minlpsolverstate : public _minlpsolverstate_owner +{ +public: + minlpsolverstate(); + minlpsolverstate(alglib_impl::minlpsolverstate *attach_to); + minlpsolverstate(const minlpsolverstate &rhs); + minlpsolverstate& operator=(const minlpsolverstate &rhs); + virtual ~minlpsolverstate(); + + +}; + + +/************************************************************************* +This structure stores the optimization report. + +The following fields are set by all MINLP solvers: +* f objective value at the solution +* nfev number of value/gradient evaluations +* terminationtype termination type (see below) + +The BBGD solver additionally sets the following fields: +* pdgap final primal-dual gap +* ntreenodes number of B&B tree nodes traversed +* nsubproblems total number of NLP relaxations solved; can be + larger than ntreenodes because of restarts +* nnodesbeforefeasibility number of nodes evaluated before finding first + integer feasible solution + +TERMINATION CODES + +TerminationType field contains completion code, which can be either FAILURE +code or SUCCESS code. + +=== FAILURE CODE === + -33 timed out, failed to find a feasible point within time limit or + iteration budget + -8 internal integrity control detected infinite or NAN values in + function/gradient, recovery was impossible. Abnormal termination + signaled. + -3 integer infeasibility is signaled: + * for convex problems: proved to be infeasible + * for nonconvex problems: a primal feasible point is nonexistent + or too difficult to find + + +=== SUCCESS CODE === + 2 successful solution: + * for BBGD - entire tree was scanned + * for MIVNS - either entire integer grid was scanned, or the + neighborhood size based condition was triggered (in future + versions other criteria may be introduced) + 5 a primal feasible point was found, but time or iteration limit was + exhausted but we failed to find a better one or prove its + optimality; the best point so far is returned. +*************************************************************************/ +class _minlpsolverreport_owner +{ +public: + _minlpsolverreport_owner(); + _minlpsolverreport_owner(alglib_impl::minlpsolverreport *attach_to); + _minlpsolverreport_owner(const _minlpsolverreport_owner &rhs); + _minlpsolverreport_owner& operator=(const _minlpsolverreport_owner &rhs); + virtual ~_minlpsolverreport_owner(); + alglib_impl::minlpsolverreport* c_ptr(); + const alglib_impl::minlpsolverreport* c_ptr() const; +protected: + alglib_impl::minlpsolverreport *p_struct; + bool is_attached; +}; +class minlpsolverreport : public _minlpsolverreport_owner +{ +public: + minlpsolverreport(); + minlpsolverreport(alglib_impl::minlpsolverreport *attach_to); + minlpsolverreport(const minlpsolverreport &rhs); + minlpsolverreport& operator=(const minlpsolverreport &rhs); + virtual ~minlpsolverreport(); + double &f; + ae_int_t &nfev; + ae_int_t &nsubproblems; + ae_int_t &ntreenodes; + ae_int_t &nnodesbeforefeasibility; + ae_int_t &terminationtype; + double &pdgap; + + +}; +#endif + +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + MIXED INTEGER NONLINEAR PROGRAMMING SOLVER + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to any +combination of: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU +* integrality constraints on some variables + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercreate(const ae_int_t n, const real_1d_array &x, minlpsolverstate &state, const xparams _xparams = alglib::xdefault); +void minlpsolvercreate(const real_1d_array &x, minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for the mixed integer optimizer. + +Box constraints are inactive by default. + +IMPORTANT: box constraints work in parallel with the integrality ones: + * a variable marked as integral is considered having no bounds + until minlpsolversetbc() is called + * a variable with lower and upper bounds set is considered + continuous until marked as integral with the + minlpsolversetintkth() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify a + very small number or -INF, with the latter option being + recommended. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify a + very large number or +INF, with the latter option being + recommended. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th + variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbc(minlpsolverstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2dense(minlpsolverstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minlpsolversetlc2dense(minlpsolverstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2(minlpsolverstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetlc2mixed(minlpsolverstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2dense(minlpsolverstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2(minlpsolverstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minlpsolvercreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddlc2sparsefromdense(minlpsolverstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MINLP optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MINLPSolverOptimize() method as callbacks. + +MINLPSolverOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetnlc2(minlpsolverstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams = alglib::xdefault); +void minlpsolversetnlc2(minlpsolverstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list. + +In fact, this function adds constraint bounds. A constraints itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + +NOTE 3: use addnlc2masked() in order to specify variable mask. Masks are + essential for derivative-free optimization because they provide + important information about relevant and irrelevant variables. + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2(minlpsolverstate &state, const double nl, const double nu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function APPENDS a two-sided nonlinear constraint to the list, with +the variable mask being specified as a compressed index array. A +variable mask is a set of variables actually appearing in the constraint. + +----- ABOUT VARIABLE MASKS ----------------------------------------------- + +Variable masks provide crucial information for derivative-free solvers, +greatly accelerating surrogate model construction. This applies to both +continuous and integral variables, with results for binary variables being +more pronounced. + +Up to 2x improvement in convergence speed has been observed for sufficiently +sparse MINLP problems. + +NOTE: In order to unleash the full potential of variable masking, it is + important to provide masks for objective as well as all nonlinear + constraints. + + Even partial information matters, i.e. if you are 100% sure that + your black-box function does not depend on some variables, but + unsure about other ones, mark surely irrelevant variables, and tell + the solver that other ones may be relevant. + +NOTE: the solver is may behave unpredictably if some relevant variable + is not included into the mask. Most likely it will fail to converge, + although it sometimes possible to converge to solution even with + incorrectly specified mask. + +NOTE: minlpsolversetobjectivemask() can be used to set variable mask for + the objective. + +NOTE: Masks are ignored by branch-and-bound-type solvers relying on + analytic gradients. + +----- ABOUT NONLINEAR CONSTRAINTS ---------------------------------------- + +In fact, this function adds constraint bounds. A constraint itself (a +function) is passed to the MINLPSolverOptimize() method as a callback. See +comments on MINLPSolverSetNLC2() for more information about callback +structure. + +The function adds a two-sided nonlinear constraint NL<=C(x)<=NU, where +* NL=NU => I-th row is an equality constraint Ci(x)=NL +* NL I-th tow is a two-sided constraint NL<=Ci(x)<=NU +* NL=-INF => I-th row is an one-sided constraint Ci(x)<=NU +* NU=+INF => I-th row is an one-sided constraint NL<=Ci(x) +* NL=-INF, NU=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. It helps the optimizer to handle them + more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + NL - lower bound, can be -INF + NU - upper bound, can be +INF + VarIdx - array[NMSK], with potentially unsorted and non-distinct + indexes (the function will sort and merge duplicates). If + a variable index K appears in the list, it means that the + constraint potentially depends on K-th variable. If a + variable index K does NOT appear in the list, it means + that the constraint does NOT depend on K-th variable. + The array can have more than NMSK elements, in which case + only leading NMSK will be used. + NMSK - NMSK>=0, VarIdx[] size: + * NMSK>0 means that the constraint depends on up to NMSK + variables whose indexes are stored in VarIdx[] + * NMSK=0 means that the constraint is a constant function; + the solver may fail if it is not actually the case. + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MINLPSolverSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MINLPSolverSetScale() function). + + -- ALGLIB -- + Copyright 05.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolveraddnlc2masked(minlpsolverstate &state, const double nl, const double nu, const integer_1d_array &varidx, const ae_int_t nmsk, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping condition for the branch-and-bound family of +solvers: a solver must when when the gap between primal and dual bounds is +less than PDGap. + +The solver computes relative gap, equal to |Fprim-Fdual|/max(|Fprim|,1). + +This parameter is ignored by other types of solvers, e.g. MIVNS. + +INPUT PARAMETERS: + State - structure stores algorithm state + PDGap - >=0, tolerance. Zero value means that some default value + is automatically selected. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetpdgap(minlpsolverstate &state, const double pdgap, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets BBSYNC profile to "small tree". + +It means that we expect our problem to have a shallow B&B tree with the +number of nodes comparable to the integer variables count, or below. + +BBSYNC solver will run with simplified settings: +* pseudocost branching is used + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilesmalltree(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets BBSYNC profile to "large tree". + +It means that we expect our problem to have a large B&B tree with much +more than NInt (the integer variables count) nodes. However, we expect it +to be solvable within our computational budget (i.e. that we are able to +explore the entire B&B tree). + +BBSYNC solver will run with heuristics that are costly to power-up, but +greatly improve performance on long distances: +* reliability branching is used + +BBSYNC will not use heuristics that increase chance of finding good +solutions early at the cost of increasing total time to prove optimality. + +INPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.12.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetbbsyncprofilelargetree(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets tolerance for nonlinear constraints; points violating +constraints by no more than CTol are considered feasible. + +Depending on the specific algorithm used, constraint violation may be +checked against internally scaled/normalized constraints (some smooth +solvers renormalize constraints in such a way that they have roughly unit +gradient magnitudes) or against raw constraint values: +* BBSYNC renormalizes constraints prior to comparing them with CTol +* MIRBF-VNS checks violation against raw constraint values + +IMPORTANT: one should be careful when choosing tolerances and stopping + criteria. + + A solver stops as soon as stopping criteria are triggered; + a feasibility check is performed after that. If too loose + stopping criteria are used, the solver may fail to enforce + constraints with sufficient accuracy and fail to recognize + solution as a feasible one. + + For example, stopping with EpsX=0.01 and checking CTol=0.000001 + will almost surely result in problems. Ideally, CTol should be + 1-2 orders of magnitude more relaxed than stopping criteria. + +INPUT PARAMETERS: + State - structure stores algorithm state + CTol - >0, tolerance. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetctol(minlpsolverstate &state, const double ctol, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells MINLP solver to use an objective-based stopping +condition for an underlying subsolver, i.e. to stop subsolver if relative +change in objective between iterations is less than EpsF. + +Too tight EspF, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsF +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if total objective change in last several (between + 5 and 10) steps is less than EpsF. More than one step is used to check + convergence because surrogate model-based solvers usually need more + stringent stopping criteria than SQP. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsF - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsF - >0, stopping condition + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsf(minlpsolverstate &state, const double epsf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells MINLP solver to use a step-based stopping condition +for an underlying subsolver, i.e. to stop subsolver if typical step size +becomes less than EpsX. + +Too tight EspX, as always, result in spending too much time in the solver. +Zero value means that some default non-zero value will be used. + +Exact action of this condition as well as reaction to too relaxed EpsX +depend on specific MINLP solver being used + +* BBSYNC. This condition controls SQP subsolver used to solve NLP (relaxed) + subproblems arising during B&B tree search. Good values are typically + between 1E-6 and 1E-7. + + Too relaxed values may result in subproblems being mistakenly fathomed + (feasible solutions not identified), too large constraint violations, + etc. + +* MIVNS. This condition controls RBF-based surrogate model subsolver used + to handle continuous variables. It is ignored for integer-only problems. + + The subsolver stops if trust radius for a surrogate model optimizer + becomes less than EpsX. + + Good values are relatively high, between 0.01 and 0.0001, depending on + a problem. The MIVNS solver is designed to gracefully handle large + values of EpsX - it will stop early, but it won't compromise feasibility + (it will try to reduce constraint violations below CTol) and will not + drop promising integral nodes. + +INPUT PARAMETERS: + State - solver structure + EpsX - >=0, stopping condition. Zero value means that some default + value will be used. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetsubsolverepsx(minlpsolverstate &state, const double epsx, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to favor parallelism, i.e. utilize +multithreading (when allowed by the user) until statistics prove that +overhead from starting/stopping worker threads is too large. + +This way solver gets the best performance on problems with significant +amount of internal calculations (large QP/MIQP subproblems, lengthy +surrogate model optimization sessions) from the very beginning. The price +is that problems with small solver overhead that does not justify internal +parallelism (<1ms per iteration) will suffer slowdown for several initial +10-20 milliseconds until the solver proves that parallelism makes no sense + +Use MINLPSolver.CautiousInternalParallelism() to avoid slowing down the +solver on easy problems. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverfavorinternalparallelism(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations in the single-threaded +mode until statistics prove that iteration cost justified activating +multithreading. + +This way solver does not suffer slow-down on problems with small iteration +overhead (<1ms per iteration), at the cost of spending initial 10-20 ms +in the single-threaded mode even on difficult problems that justify +parallelism usage. + +Use MINLPSolver.FavorInternalParallelism() to use parallelism until it is +proven to be useless. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvercautiousinternalparallelism(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function controls adaptive internal parallelism, i.e. algorithm used +by the solver to adaptively decide whether parallel acceleration of +solver's internal calculations (B&B code, SQP, parallel linear algebra) +should be actually used or not. + +This function tells the solver to do calculations exactly as prescribed by +the user: in the parallel mode when alglib::parallel flag is passed, in +the single-threaded mode otherwise. The solver does not analyze actual +running times to decide whether parallelism is justified or not. + +NOTE: the internal parallelism is distinct from the callback parallelism. + The former is the ability to utilize parallelism to speed-up solvers + own internal calculations, while the latter is the ability to + perform several callback evaluations at once. Aside from performance + considerations, the internal parallelism is entirely transparent to + the user. The callback parallelism requries the user to write a + thread-safe, reentrant callback. + +NOTE: in order to use internal parallelism, adaptive or not, the user must + activate it by specifying alglib::parallel in flags or global + threading settings. ALGLIB for C++ must be compiled in the OS-aware + mode. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolvernoadaptiveinternalparallelism(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function marks K-th variable as an integral one. + +Unless box constraints are set for the variable, it is unconstrained (i.e. +can take positive or negative values). By default all variables are +continuous. + +IMPORTANT: box constraints work in parallel with the integrality ones: + * a variable marked as integral is considered having no bounds + until minlpsolversetbc() is called + * a variable with lower and upper bounds set is considered + continuous until marked as integral with the + minlpsolversetintkth() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + K - 0<=K=1, group size. Up to GroupSize tree nodes can be + processed in the parallel manner. + + Increasing this parameter makes the solver + less efficient serially (it always tries to fill + the batch with nodes, even if there is a chance + that most of them will be discarded later), but + increases its parallel potential. + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + + Recommended value, depending on callback cost and + matrix factorization overhead, can be: + * 1 for 'easy' problems with cheap callbacks and + small dimensions; also for problems with nearly + linear B&B trees. + * 2-3 for problems with sufficiently costly + callbacks (or sufficiently high linear algebra + overhead) that it makes sense to utilize limited + parallelism. + * cores count - for difficult problems with deep + and wide B&B trees and sufficiently costly + callbacks (or sufficiently high linear algebra + overhead). + +NOTES: DETERMINISM + +Running with fixed GroupSize generally produces same results independently +of whether parallelism is used or not. Changing GroupSize parameter may +change results in the following ways: + +* for problems that are solved to optimality but have multiple solutions, + different values of this parameter may result in different solutions + being returned (but still with the same objective value) + +* while operating close to exhausting budget (either timeout or iterations + limit), different GroupSize values may result in different outcomes: a + solution being found, or budget being exhausted + +* finally, on difficult problems that are too hard to solve to optimality + but still allow finding primal feasible solutions changing GroupSize may + result in different primal feasible solutions being returned. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgobbsync(minlpsolverstate &state, const ae_int_t groupsize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tell the solver to use MIVNS (Mixed-Integer Variable +Neighborhood Search) solver for derivative-free mixed-integer nonlinear +programming with expensive objective/constraints and non-relaxable integer +variables. + +The solver is intended for moderately-sized problems, typically with tens +of variables. + +The algorithm has the following features: +* it supports all-integer and mixed-integer problems with box, linear and + nonlinear equality and inequality constraints +* it makes no assumptions about problem convexity +* it does not require derivative information. Although it still assumes + that objective/constraints are smooth wrt continuous variables, no such + assumptions are made regarding dependence on integer variables. +* it efficiently uses limited computational budget and scales well with + larger budgets +* it does not evaluate objective/constraints at points violating integrality +* it also respects linear constraints in all intermediate points + +NOTE: In particular, if your task uses integrality+sum-to-one set of + constraints to encode multiple choice options (e.g. [1,0,0], [0,1,0] + or [0,0,1]), you can be sure that the algorithm will not ask for an + objective value at a point with fractional values like [0.1,0.5,0.4] + or at one that is not a correct one-hot encoded value (e.g. [1,1,0] + which has two variables set to 1). + +The algorithm is intended for low-to-medium accuracy solution of otherwise +intractable problems with expensive objective/constraints. + +It can solve any MINLP problem; however, it is optimized for the following +problem classes: +* limited variable count +* expensive objective/constraints +* nonrelaxable integer variables +* no derivative information +* problems where changes in integer variables lead to structural changes + in the entire system. Speaking in other words, on problems where each + integer variable acts as an on/off or "choice" switch that completely + rewires the model - turning constraints, variables, or whole sub-systems + on or off + +INPUT PARAMETERS: + State - structure that stores algorithm state + + Budget - optimization budget (function evaluations). The + solver will not stop immediately after reaching + Budget evaluations, but will stop shortly after + that (usually within 2N+1 evaluations). Zero value + means no limit. + + MaxNeighborhood - stopping condition for the solver. The algorithm + will stop as soon as there are no points better + than the current candidate in a neighborhood whose + size is equal to or exceeds MaxNeighborhood. Zero + means no stopping condition. + + Recommended neighborhood size is proportional to + the difference between integral variables count NI + and the number of linear equality constraints on + integral variables L (such constraints effectively + reduce problem dimensionality). + + The very minimal value for binary problems is NI-L, + which means that the solution can not be improved + by flipping one of variables between 0 and 1. The + very minimal value for non-binary integral vars is + twice as much (because now each point has two + neighbors per variable). However, such minimal + values often result in an early termination. + + It is recommended to set this parameter to 5*N or + 10*N (ignoring LI) and to test how it behaves on + your problem. + + BatchSize >=1, recommended batch size for neighborhood + exploration. Up to BatchSize nodes will be + evaluated at any moment, thus up to BatchSize + objective evaluations can be performed in parallel. + + Increasing this parameter makes the solver + slightly less efficient serially (it always tries + to fill the batch with nodes, even if there is a + chance that most of them will be discarded later), + but greatly increases its parallel potential. + + Recommended values depend on the cores count and + on the limitations of the objective/constraints + callback: + * 1 for serial execution, callback that can not be + called from multiple threads, or highly + parallelized expensive callback that keeps all + cores occupied + * small fixed value like 5 or 10, if you need + reproducible behavior independent from the cores + count + * CORESCOUNT, 2*CORESCOUNT or some other multiple + of CORESCOUNT, if you want to utilize parallelism + to the maximum extent + + Parallel speed-up comes from two sources: + * callback parallelism (several objective values + are computed concurrently), which is significant + for problems with callbacks that take more than + 1ms per evaluation + * internal parallelism, i.e. ability to do parallel + sparse matrix factorization and other solver- + related tasks + By default, the solver runs serially even for + GroupSize>1. Both kinds of parallelism have to be + activated by the user, see ALGLIB Reference Manual + for more information. + +NOTES: if no stopping criteria is specified (unlimited budget, no timeout, + no neighborhood size limit), then the solver will run until + enumerating all integer solutions. + +===== ALGORITHM DESCRIPTION ============================================== + +A simplified description for an all-integer algorithm, omitting stopping +criteria and various checks: + + MIVNS (ALL-INTEGER): + 1. Input: initial integral point, may be infeasible wrt nonlinear + constraints, but is feasible wrt linear ones. Enforce linear + feasibility, if needed. + 2. Generate initial neighborhood around the current point that is + equal to the point itself. The point is marked as explored. + 3. Scan neighborhood for a better point (one that is less + infeasible or has lower objective); if one is found, make it + current and goto #2 + 4. Scan neighborhood for an unexplored point (one with no objective + computed). If one if found, compute objective, mark the point as + explored, goto #3 + 5. If there are no unexplored or better points in the neighborhood, + expand it: find a point that was not used for expansion, + compute up to 2N its nearest integral neighbors, add them to + the neighborhood and mark as unexplored. Goto #3. + + NOTE: A nearest integral neighbor is a nearest point that differs at + least by +1 or -1 in one of integral variables and that is + feasible with respect to box and linear constraints (ignoring + nonlinear ones). For problems with difficult constraint sets + integral neighbors are found by solving MIQP subproblems. + +The algorithm above systematically scans neighborhood of a point until +either better point is found, an entire integer grid is enumerated, or one +of stopping conditions is met. + +A mixed-integer version of the algorithm is more complex: +* it still sees optimization space as a set of integer nodes, each node + having a subspace of continuous variables associated with it +* after starting to explore a node, the algorithm runs an RBF surrogate- + based subsolver for the node. It manages a dedicated subsolver for each + node in a neighborhood and adaptively divides its computational budget + between subsolvers, switching to a node as soon as its subsolver shows + better results than its competitors. +* the algorithm remembers all previously evaluated points and reuses them + as much as possible + +===== ALGORITHM SCALING WITH VARIABLES COUNT N =========================== + +A 'neighborhood scan' is a minimum number of function evaluations needed +to perform at least minimal evaluation of the immediate neighborhood. For +an N-dimensional problem with NI integer variables and NF continuous ones +we have ~NI nodes in an immediate neighborhood, and each node needs ~NF +evalutations to build at least linear model of the objective. + +Thus, a MIVNS neighborhood scan will need about NI*NF=NI*(N-NI)=NF*(N-NF) +objective evaluations. + +It is important to note that MIVNS does not share information between +nodes because it assumes that objective landscape can drastically change +when jumping from node to node. That's why we need NI*NF instead of NI+NF +objective values. + +In practice, when started not too far away from the minimum, we can expect +to get some improvement in 5-10 scans, and to get significant progress in +50-100 scans. + +For problems with NF being small or NI being small we have scan cost +being proportional to variables count N, which allows us to achieve good +progress using between 5N and 100N objective values. However, when both +NI and NF are close to N/2, a scan needs ~N^2 objective evaluations, +which results in a much worse scaling behavior. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetalgomivns(minlpsolverstate &state, const ae_int_t budget, const ae_int_t maxneighborhood, const ae_int_t batchsize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates multiple random restarts (performed for each node, +including root and child ones) that help to find global solutions to non- +convex problems. + +This parameter is used by branch-and-bound solvers and is presently +ignored by derivative-free solvers. + +INPUT PARAMETERS: + State - structure that stores algorithm state + NMultistarts - >=1, number of random restarts: + * 1 means that no restarts performed, the solver + assumes convexity + * >=1 means that solver assumes non-convexity and + performs fixed amount of random restarts + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversetmultistarts(minlpsolverstate &state, const ae_int_t nmultistarts, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates timeout feature. The solver finishes after running +for a specified amount of time (in seconds, fractions can be used) with +the best point so far. + +Depending on the situation, the following completion codes can be reported +in rep.terminationtype: +* -33 (failure), if timed out without finding a feasible point +* 5 (partial success), if timed out after finding at least one feasible point + +The solver does not stop immediately after timeout was triggered because +it needs some time for underlying subsolvers to react to timeout signal. +Generally, about one additional subsolver iteration (which is usually far +less than one B&B split) will be performed prior to stopping. + +INPUT PARAMETERS: + State - structure that stores algorithm state + Timeout - >=0, timeout in seconds (floating point number): + * 0 means no timeout + * >=0 means stopping after specified number of + seconds. + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey +*************************************************************************/ +void minlpsolversettimeout(minlpsolverstate &state, const double timeout, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlpsolveriteration(minlpsolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + sjac - callback which calculates function vector fi[] + and sparse Jacobian sjac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + + + -- ALGLIB -- + Copyright 01.01.2025 by Bochkanov Sergey + + +*************************************************************************/ +void minlpsolveroptimize(minlpsolverstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minlpsolveroptimize(minlpsolverstate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minlpsolveroptimize(minlpsolverstate &state, + void (*sjac)(const real_1d_array &x, real_1d_array &fi, sparsematrix &s, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from new point. All optimization +parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MINLPSolverCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverrestartfrom(minlpsolverstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MINLPSolver results: the solution found, completion codes and additional +information. + +INPUT PARAMETERS: + Solver - solver + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + rep.f contains objective value at the solution. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one. + + More information about fields of this structure can be + found in the comments on the minlpsolverreport datatype. + + -- ALGLIB -- + Copyright 18.01.2024 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverresults(const minlpsolverstate &state, real_1d_array &x, minlpsolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +NLC results + +Buffered implementation of MINLPSolverResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minlpsolverresultsbuf(const minlpsolverstate &state, real_1d_array &x, minlpsolverreport &rep, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BBGD) || !defined(AE_PARTIAL_BUILD) +void bbgdcreatebuf(ae_int_t n, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + /* Boolean */ const ae_vector* isintegral, + /* Boolean */ const ae_vector* isbinary, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t groupsize, + ae_int_t nmultistarts, + ae_int_t timeout, + ae_int_t tracelevel, + bbgdstate* state, + ae_state *_state); +void bbgdforceserial(bbgdstate* state, ae_state *_state); +void bbgdsetpdgap(bbgdstate* state, double pdgap, ae_state *_state); +void bbgdsetctol(bbgdstate* state, double ctol, ae_state *_state); +void bbgdsetepsf(bbgdstate* state, double epsf, ae_state *_state); +void bbgdsetsmalltree(bbgdstate* state, ae_state *_state); +void bbgdsetlargetree(bbgdstate* state, ae_state *_state); +void bbgdsetdiving(bbgdstate* state, + ae_int_t divingmode, + ae_state *_state); +void bbgdsetmaxprimalcandidates(bbgdstate* state, + ae_int_t maxcand, + ae_state *_state); +void bbgdsetsoftmaxnodes(bbgdstate* state, + ae_int_t maxnodes, + ae_state *_state); +void bbgdsethardmaxnodes(bbgdstate* state, + ae_int_t maxnodes, + ae_state *_state); +void bbgdsetepsx(bbgdstate* state, double epsx, ae_state *_state); +void bbgdsetquadraticobjective(bbgdstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + double c0, + ae_state *_state); +ae_bool bbgditeration(bbgdstate* state, ae_state *_state); +void bbgdoffloadrcommrequest(bbgdstate* state, + ae_int_t* requesttype, + ae_int_t* querysize, + ae_int_t* queryfuncs, + ae_int_t* queryvars, + ae_int_t* querydim, + ae_int_t* queryformulasize, + /* Real */ ae_vector* querydata, + ae_state *_state); +void bbgdloadrcommreply(bbgdstate* state, + ae_int_t requesttype, + ae_int_t querysize, + ae_int_t queryfuncs, + ae_int_t queryvars, + ae_int_t querydim, + ae_int_t queryformulasize, + /* Real */ const ae_vector* replyfi, + /* Real */ const ae_vector* replydj, + const sparsematrix* replysj, + ae_state *_state); +void _bbgdsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _bbgdsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _bbgdsubproblem_clear(void* _p); +void _bbgdsubproblem_destroy(void* _p); +void _bbgdfrontsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _bbgdfrontsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _bbgdfrontsubsolver_clear(void* _p); +void _bbgdfrontsubsolver_destroy(void* _p); +void _bbgdfrontentry_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _bbgdfrontentry_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _bbgdfrontentry_clear(void* _p); +void _bbgdfrontentry_destroy(void* _p); +void _bbgdfront_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _bbgdfront_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _bbgdfront_clear(void* _p); +void _bbgdfront_destroy(void* _p); +void _bbgdstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _bbgdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _bbgdstate_clear(void* _p); +void _bbgdstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MIRBFVNS) || !defined(AE_PARTIAL_BUILD) +void mirbfvnscreatebuf(ae_int_t n, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + /* Boolean */ const ae_vector* isintegral, + /* Boolean */ const ae_vector* isbinary, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_int_t algomode, + ae_int_t budget, + ae_int_t maxneighborhood, + ae_int_t batchsize, + ae_int_t timeout, + ae_int_t tracelevel, + mirbfvnsstate* state, + ae_state *_state); +void mirbfvnssetctol(mirbfvnsstate* state, double ctol, ae_state *_state); +void mirbfvnssetepsf(mirbfvnsstate* state, double epsf, ae_state *_state); +void mirbfvnssetepsx(mirbfvnsstate* state, double epsx, ae_state *_state); +void mirbfvnssetvariablemask(mirbfvnsstate* state, + /* Boolean */ const ae_vector* hasmask, + const sparsematrix* mask, + ae_state *_state); +void mirbfvnssetadaptiveinternalparallelism(mirbfvnsstate* state, + ae_int_t smpmode, + ae_state *_state); +ae_bool mirbfvnsiteration(mirbfvnsstate* state, ae_state *_state); +void _mirbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfmodel_clear(void* _p); +void _mirbfmodel_destroy(void* _p); +void _mirbfvnsnodesubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsnodesubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsnodesubsolver_clear(void* _p); +void _mirbfvnsnodesubsolver_destroy(void* _p); +void _rbfmmtemporaries_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _rbfmmtemporaries_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _rbfmmtemporaries_clear(void* _p); +void _rbfmmtemporaries_destroy(void* _p); +void _mirbfvnstemporaries_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfvnstemporaries_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfvnstemporaries_clear(void* _p); +void _mirbfvnstemporaries_destroy(void* _p); +void _mirbfvnsgrid_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsgrid_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsgrid_clear(void* _p); +void _mirbfvnsgrid_destroy(void* _p); +void _mirbfvnsdataset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsdataset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsdataset_clear(void* _p); +void _mirbfvnsdataset_destroy(void* _p); +void _mirbfvnsstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mirbfvnsstate_clear(void* _p); +void _mirbfvnsstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINLPSOLVERS) || !defined(AE_PARTIAL_BUILD) +void minlpsolvercreate(ae_int_t n, + /* Real */ const ae_vector* x, + minlpsolverstate* state, + ae_state *_state); +void minlpsolversetbc(minlpsolverstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minlpsolversetlc2dense(minlpsolverstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minlpsolversetlc2(minlpsolverstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minlpsolversetlc2mixed(minlpsolverstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state); +void minlpsolveraddlc2dense(minlpsolverstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void minlpsolveraddlc2(minlpsolverstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void minlpsolveraddlc2sparsefromdense(minlpsolverstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state); +void minlpsolversetnlc2(minlpsolverstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state); +void minlpsolveraddnlc2(minlpsolverstate* state, + double nl, + double nu, + ae_state *_state); +void minlpsolveraddnlc2masked(minlpsolverstate* state, + double nl, + double nu, + /* Integer */ const ae_vector* varidx, + ae_int_t nmsk, + ae_state *_state); +void minlpsolversetpdgap(minlpsolverstate* state, + double pdgap, + ae_state *_state); +void minlpsolversetbbsyncprofilesmalltree(minlpsolverstate* state, + ae_state *_state); +void minlpsolversetbbsyncprofilelargetree(minlpsolverstate* state, + ae_state *_state); +void minlpsolversetctol(minlpsolverstate* state, + double ctol, + ae_state *_state); +void minlpsolversetsubsolverepsf(minlpsolverstate* state, + double epsf, + ae_state *_state); +void minlpsolversetsubsolverepsx(minlpsolverstate* state, + double epsx, + ae_state *_state); +void minlpsolverfavorinternalparallelism(minlpsolverstate* state, + ae_state *_state); +void minlpsolvercautiousinternalparallelism(minlpsolverstate* state, + ae_state *_state); +void minlpsolvernoadaptiveinternalparallelism(minlpsolverstate* state, + ae_state *_state); +void minlpsolversetintkth(minlpsolverstate* state, + ae_int_t k, + ae_state *_state); +void minlpsolversetobjectivemaskdense(minlpsolverstate* state, + /* Boolean */ const ae_vector* _objmask, + ae_state *_state); +void minlpsolversetscale(minlpsolverstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minlpsolversetalgobbsync(minlpsolverstate* state, + ae_int_t groupsize, + ae_state *_state); +void minlpsolversetalgomivns(minlpsolverstate* state, + ae_int_t budget, + ae_int_t maxneighborhood, + ae_int_t batchsize, + ae_state *_state); +void minlpsolversetmultistarts(minlpsolverstate* state, + ae_int_t nmultistarts, + ae_state *_state); +void minlpsolversettimeout(minlpsolverstate* state, + double timeout, + ae_state *_state); +ae_bool minlpsolveriteration(minlpsolverstate* state, ae_state *_state); +void minlpsolverrestartfrom(minlpsolverstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minlpsolverresults(const minlpsolverstate* state, + /* Real */ ae_vector* x, + minlpsolverreport* rep, + ae_state *_state); +void minlpsolverresultsbuf(const minlpsolverstate* state, + /* Real */ ae_vector* x, + minlpsolverreport* rep, + ae_state *_state); +void minlpsolversetprotocolv2(minlpsolverstate* state, ae_state *_state); +void minlpsolversetprotocolv2s(minlpsolverstate* state, ae_state *_state); +void _minlpsolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlpsolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlpsolverstate_clear(void* _p); +void _minlpsolverstate_destroy(void* _p); +void _minlpsolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlpsolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlpsolverreport_clear(void* _p); +void _minlpsolverreport_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/optimization.cpp b/core/alglib/optimization.cpp index ebfae731..ac4d8370 100644 --- a/core/alglib/optimization.cpp +++ b/core/alglib/optimization.cpp @@ -1,25034 +1,144274 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "optimization.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - - - - - - - - - -/************************************************************************* -This object stores state of the nonlinear CG optimizer. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -_mincgstate_owner::_mincgstate_owner() -{ - p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mincgstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mincgstate_owner::_mincgstate_owner(const _mincgstate_owner &rhs) -{ - p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mincgstate_owner& _mincgstate_owner::operator=(const _mincgstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mincgstate_clear(p_struct); - if( !alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mincgstate_owner::~_mincgstate_owner() -{ - alglib_impl::_mincgstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mincgstate* _mincgstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mincgstate* _mincgstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mincgstate::mincgstate() : _mincgstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -mincgstate::mincgstate(const mincgstate &rhs):_mincgstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -mincgstate& mincgstate::operator=(const mincgstate &rhs) -{ - if( this==&rhs ) - return *this; - _mincgstate_owner::operator=(rhs); - return *this; -} - -mincgstate::~mincgstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_mincgreport_owner::_mincgreport_owner() -{ - p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mincgreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mincgreport_owner::_mincgreport_owner(const _mincgreport_owner &rhs) -{ - p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_mincgreport_owner& _mincgreport_owner::operator=(const _mincgreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_mincgreport_clear(p_struct); - if( !alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_mincgreport_owner::~_mincgreport_owner() -{ - alglib_impl::_mincgreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::mincgreport* _mincgreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::mincgreport* _mincgreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -mincgreport::mincgreport() : _mincgreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) -{ -} - -mincgreport::mincgreport(const mincgreport &rhs):_mincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) -{ -} - -mincgreport& mincgreport::operator=(const mincgreport &rhs) -{ - if( this==&rhs ) - return *this; - _mincgreport_owner::operator=(rhs); - return *this; -} - -mincgreport::~mincgreport() -{ -} - -/************************************************************************* - NONLINEAR CONJUGATE GRADIENT METHOD - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using one of the -nonlinear conjugate gradient methods. - -These CG methods are globally convergent (even on non-convex functions) as -long as grad(f) is Lipschitz continuous in a some neighborhood of the -L = { x : f(x)<=f(x0) }. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinCGCreate() call -2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and - other functions -3. User calls MinCGOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinCGResults() to get solution -5. Optionally, user may call MinCGRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinCGRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgcreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - NONLINEAR CONJUGATE GRADIENT METHOD - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using one of the -nonlinear conjugate gradient methods. - -These CG methods are globally convergent (even on non-convex functions) as -long as grad(f) is Lipschitz continuous in a some neighborhood of the -L = { x : f(x)<=f(x0) }. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinCGCreate() call -2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and - other functions -3. User calls MinCGOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinCGResults() to get solution -5. Optionally, user may call MinCGRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinCGRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgcreate(const real_1d_array &x, mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgcreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinCGCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinCGCreate() in order to get more -information about creation of CG optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinCGSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. L-BFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgcreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinCGCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinCGCreate() in order to get more -information about creation of CG optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinCGSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. L-BFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgcreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping conditions for CG optimization algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinCGSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients for CG optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of CG optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the CG too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinCGSetPrec...() functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgsetscale(const mincgstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetxrep(const mincgstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets CG algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - CGType - algorithm type: - * -1 automatic selection of the best algorithm - * 0 DY (Dai and Yuan) algorithm - * 1 Hybrid DY-HS algorithm - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetcgtype(const_cast(state.c_ptr()), cgtype, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetstpmax(const mincgstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function allows to suggest initial step length to the CG algorithm. - -Suggested step length is used as starting point for the line search. It -can be useful when you have badly scaled problem, i.e. when ||grad|| -(which is used as initial estimate for the first step) is many orders of -magnitude different from the desired step. - -Line search may fail on such problems without good estimate of initial -step length. Imagine, for example, problem with ||grad||=10^50 and desired -step equal to 0.1 Line search function will use 10^50 as initial step, -then it will decrease step length by 2 (up to 20 attempts) and will get -10^44, which is still too large. - -This function allows us to tell than line search should be started from -some moderate step length, like 1.0, so algorithm will be able to detect -desired step length in a several searches. - -Default behavior (when no step is suggested) is to use preconditioner, if -it is available, to generate initial estimate of step length. - -This function influences only first iteration of algorithm. It should be -called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. -Suggested step is ignored if you have preconditioner. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - Stp - initial estimate of the step length. - Can be zero (no estimate). - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsuggeststep(const mincgstate &state, const double stp) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsuggeststep(const_cast(state.c_ptr()), stp, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdefault(const mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdiag(const mincgstate &state, const real_1d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinCGSetScale() call -(before or after MinCGSetPrecScale() call). Without knowledge of the scale -of your variables scale-based preconditioner will be just unit matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecscale(const mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool mincgiteration(const mincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::mincgiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void mincgoptimize(mincgstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'mincgoptimize()' (func is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void mincgoptimize(mincgstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'mincgoptimize()' (grad is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -Conjugate gradient results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinCGSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible, - we return best X found so far - * 8 terminated by user - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conjugate gradient results - -Buffered implementation of MinCGResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgrestartfrom(const mincgstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinCGOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinCGSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 31.05.2012 by Bochkanov Sergey -*************************************************************************/ -void mincgsetgradientcheck(const mincgstate &state, const double teststep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mincgsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This object stores nonlinear optimizer state. -You should use functions provided by MinBLEIC subpackage to work with this -object -*************************************************************************/ -_minbleicstate_owner::_minbleicstate_owner() -{ - p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minbleicstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minbleicstate_owner::_minbleicstate_owner(const _minbleicstate_owner &rhs) -{ - p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minbleicstate_owner& _minbleicstate_owner::operator=(const _minbleicstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minbleicstate_clear(p_struct); - if( !alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minbleicstate_owner::~_minbleicstate_owner() -{ - alglib_impl::_minbleicstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minbleicstate::minbleicstate() : _minbleicstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minbleicstate::minbleicstate(const minbleicstate &rhs):_minbleicstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minbleicstate& minbleicstate::operator=(const minbleicstate &rhs) -{ - if( this==&rhs ) - return *this; - _minbleicstate_owner::operator=(rhs); - return *this; -} - -minbleicstate::~minbleicstate() -{ -} - - -/************************************************************************* -This structure stores optimization report: -* IterationsCount number of iterations -* NFEV number of gradient evaluations -* TerminationType termination type (see below) - -TERMINATION CODES - -TerminationType field contains completion code, which can be: - -7 gradient verification failed. - See MinBLEICSetGradientCheck() for more information. - -3 inconsistent constraints. Feasible point is - either nonexistent or too hard to find. Try to - restart optimizer with better initial approximation - 1 relative function improvement is no more than EpsF. - 2 relative step is no more than EpsX. - 4 gradient norm is no more than EpsG - 5 MaxIts steps was taken - 7 stopping conditions are too stringent, - further improvement is impossible, - X contains best point found so far. - -ADDITIONAL FIELDS - -There are additional fields which can be used for debugging: -* DebugEqErr error in the equality constraints (2-norm) -* DebugFS f, calculated at projection of initial point - to the feasible set -* DebugFF f, calculated at the final point -* DebugDX |X_start-X_final| -*************************************************************************/ -_minbleicreport_owner::_minbleicreport_owner() -{ - p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minbleicreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minbleicreport_owner::_minbleicreport_owner(const _minbleicreport_owner &rhs) -{ - p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minbleicreport_owner& _minbleicreport_owner::operator=(const _minbleicreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minbleicreport_clear(p_struct); - if( !alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minbleicreport_owner::~_minbleicreport_owner() -{ - alglib_impl::_minbleicreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minbleicreport::minbleicreport() : _minbleicreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) -{ -} - -minbleicreport::minbleicreport(const minbleicreport &rhs):_minbleicreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) -{ -} - -minbleicreport& minbleicreport::operator=(const minbleicreport &rhs) -{ - if( this==&rhs ) - return *this; - _minbleicreport_owner::operator=(rhs); - return *this; -} - -minbleicreport::~minbleicreport() -{ -} - -/************************************************************************* - BOUND CONSTRAINED OPTIMIZATION - WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments subject to any -combination of: -* bound constraints -* linear inequality constraints -* linear equality constraints - -REQUIREMENTS: -* user must provide function value and gradient -* starting point X0 must be feasible or - not too far away from the feasible set -* grad(f) must be Lipschitz continuous on a level set: - L = { x : f(x)<=f(x0) } -* function must be defined everywhere on the feasible set F - -USAGE: - -Constrained optimization if far more complex than the unconstrained one. -Here we give very brief outline of the BLEIC optimizer. We strongly recommend -you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on optimization, which is available at http://www.alglib.net/optimization/ - -1. User initializes algorithm state with MinBLEICCreate() call - -2. USer adds boundary and/or linear constraints by calling - MinBLEICSetBC() and MinBLEICSetLC() functions. - -3. User sets stopping conditions with MinBLEICSetCond(). - -4. User calls MinBLEICOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -5. User calls MinBLEICResults() to get solution - -6. Optionally user may call MinBLEICRestartFrom() to solve another problem - with same N but another starting point. - MinBLEICRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size ofX - X - starting point, array[N]: - * it is better to set X to a feasible point - * but X can be infeasible, in which case algorithm will try - to find feasible point first, using X as initial - approximation. - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleiccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - BOUND CONSTRAINED OPTIMIZATION - WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments subject to any -combination of: -* bound constraints -* linear inequality constraints -* linear equality constraints - -REQUIREMENTS: -* user must provide function value and gradient -* starting point X0 must be feasible or - not too far away from the feasible set -* grad(f) must be Lipschitz continuous on a level set: - L = { x : f(x)<=f(x0) } -* function must be defined everywhere on the feasible set F - -USAGE: - -Constrained optimization if far more complex than the unconstrained one. -Here we give very brief outline of the BLEIC optimizer. We strongly recommend -you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on optimization, which is available at http://www.alglib.net/optimization/ - -1. User initializes algorithm state with MinBLEICCreate() call - -2. USer adds boundary and/or linear constraints by calling - MinBLEICSetBC() and MinBLEICSetLC() functions. - -3. User sets stopping conditions with MinBLEICSetCond(). - -4. User calls MinBLEICOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -5. User calls MinBLEICResults() to get solution - -6. Optionally user may call MinBLEICRestartFrom() to solve another problem - with same N but another starting point. - MinBLEICRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size ofX - X - starting point, array[N]: - * it is better to set X to a feasible point - * but X can be infeasible, in which case algorithm will try - to find feasible point first, using X as initial - approximation. - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreate(const real_1d_array &x, minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleiccreate(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinBLEICCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinBLEICCreate() in order to get -more information about creation of BLEIC optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinBLEICSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. CG needs exact gradient values. Imprecise - gradient may slow down convergence, especially on highly nonlinear - problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleiccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinBLEICCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinBLEICCreate() in order to get -more information about creation of BLEIC optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinBLEICSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. CG needs exact gradient values. Imprecise - gradient may slow down convergence, especially on highly nonlinear - problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleiccreatef(n, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets boundary constraints for BLEIC optimizer. - -Boundary constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF. - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF. - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: this solver has following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints, - even when numerical differentiation is used (algorithm adjusts nodes - according to boundary constraints) - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear constraints for BLEIC optimizer. - -Linear constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear constraints for BLEIC optimizer. - -Linear constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t k; - if( (c.rows()!=ct.length())) - throw ap_error("Error while calling 'minbleicsetlc': looks like one of arguments has wrong size"); - k = c.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping conditions for the optimizer. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinBLEICSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection. - -NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform - slightly more than MaxIts iterations. I.e., MaxIts sets non-strict - limit on iterations count. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetcond(const minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients for BLEIC optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the BLEIC too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinBLEICSetPrec...() -functions. - -There is a special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetscale(const minbleicstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdefault(const minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE 1: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinBLEICSetScale() -call (before or after MinBLEICSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecscale(const minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinBLEICOptimize(). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetxrep(const minbleicstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -IMPORTANT: this feature is hard to combine with preconditioning. You can't -set upper limit on step length, when you solve optimization problem with -linear (non-boundary) constraints AND preconditioner turned on. - -When non-boundary constraints are present, you have to either a) use -preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! -In this case algorithm will terminate with appropriate error code. - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which lead to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetstpmax(const minbleicstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minbleiciteration(const minbleicstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::minbleiciteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minbleicoptimize(minbleicstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'minbleicoptimize()' (func is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minbleicoptimize(minbleicstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'minbleicoptimize()' (grad is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -BLEIC results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one: - * -7 gradient verification failed. - See MinBLEICSetGradientCheck() for more information. - * -3 inconsistent constraints. Feasible point is - either nonexistent or too hard to find. Try to - restart optimizer with better initial approximation - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - More information about fields of this structure can be - found in the comments on MinBLEICReport datatype. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -BLEIC results - -Buffered implementation of MinBLEICResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine restarts algorithm from new point. -All optimization parameters (including constraints) are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - X - new starting point. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinBLEICOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinBLEICSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetgradientcheck(const minbleicstate &state, const double teststep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_minlbfgsstate_owner::_minlbfgsstate_owner() -{ - p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlbfgsstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlbfgsstate_owner::_minlbfgsstate_owner(const _minlbfgsstate_owner &rhs) -{ - p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlbfgsstate_owner& _minlbfgsstate_owner::operator=(const _minlbfgsstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minlbfgsstate_clear(p_struct); - if( !alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minlbfgsstate_owner::~_minlbfgsstate_owner() -{ - alglib_impl::_minlbfgsstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minlbfgsstate::minlbfgsstate() : _minlbfgsstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minlbfgsstate::minlbfgsstate(const minlbfgsstate &rhs):_minlbfgsstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minlbfgsstate& minlbfgsstate::operator=(const minlbfgsstate &rhs) -{ - if( this==&rhs ) - return *this; - _minlbfgsstate_owner::operator=(rhs); - return *this; -} - -minlbfgsstate::~minlbfgsstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_minlbfgsreport_owner::_minlbfgsreport_owner() -{ - p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlbfgsreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlbfgsreport_owner::_minlbfgsreport_owner(const _minlbfgsreport_owner &rhs) -{ - p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlbfgsreport_owner& _minlbfgsreport_owner::operator=(const _minlbfgsreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minlbfgsreport_clear(p_struct); - if( !alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minlbfgsreport_owner::~_minlbfgsreport_owner() -{ - alglib_impl::_minlbfgsreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minlbfgsreport::minlbfgsreport() : _minlbfgsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) -{ -} - -minlbfgsreport::minlbfgsreport(const minlbfgsreport &rhs):_minlbfgsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) -{ -} - -minlbfgsreport& minlbfgsreport::operator=(const minlbfgsreport &rhs) -{ - if( this==&rhs ) - return *this; - _minlbfgsreport_owner::operator=(rhs); - return *this; -} - -minlbfgsreport::~minlbfgsreport() -{ -} - -/************************************************************************* - LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using a quasi- -Newton method (LBFGS scheme) which is optimized to use a minimum amount -of memory. -The subroutine generates the approximation of an inverse Hessian matrix by -using information about the last M steps of the algorithm (instead of N). -It lessens a required amount of memory from a value of order N^2 to a -value of order 2*N*M. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinLBFGSCreate() call -2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() - and other functions -3. User calls MinLBFGSOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinLBFGSResults() to get solution -5. Optionally user may call MinLBFGSRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLBFGSRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension. N>0 - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - initial solution approximation, array[0..N-1]. - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with MinLBFGSSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLBFGSSetStpMax() function to bound algorithm's steps. However, - L-BFGS rarely needs such a tuning. - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgscreate(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using a quasi- -Newton method (LBFGS scheme) which is optimized to use a minimum amount -of memory. -The subroutine generates the approximation of an inverse Hessian matrix by -using information about the last M steps of the algorithm (instead of N). -It lessens a required amount of memory from a value of order N^2 to a -value of order 2*N*M. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinLBFGSCreate() call -2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() - and other functions -3. User calls MinLBFGSOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinLBFGSResults() to get solution -5. Optionally user may call MinLBFGSRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLBFGSRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension. N>0 - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - initial solution approximation, array[0..N-1]. - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with MinLBFGSSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLBFGSSetStpMax() function to bound algorithm's steps. However, - L-BFGS rarely needs such a tuning. - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgscreate(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinLBFGSCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinLBFGSCreate() in order to get -more information about creation of LBFGS optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinLBFGSSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. LBFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgscreatef(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -The subroutine is finite difference variant of MinLBFGSCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinLBFGSCreate() in order to get -more information about creation of LBFGS optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinLBFGSSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. LBFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgscreatef(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping conditions for L-BFGS optimization algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLBFGSSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLBFGSOptimize(). - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if - you don't want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients for LBFGS optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the LBFGS too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinLBFGSSetPrec...() -functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: default preconditioner (simple -scaling, same for all elements of X) is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdefault(const minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetprecdefault(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: Cholesky factorization of approximate -Hessian is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - P - triangular preconditioner, Cholesky factorization of - the approximate Hessian. array[0..N-1,0..N-1], - (if larger, only leading N elements are used). - IsUpper - whether upper or lower triangle of P is given - (other triangle is not referenced) - -After call to this function preconditioner is changed to P (P is copied -into the internal buffer). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: P should be nonsingular. Exception will be thrown otherwise. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetpreccholesky(const_cast(state.c_ptr()), const_cast(p.c_ptr()), isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &d) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetprecdiag(const_cast(state.c_ptr()), const_cast(d.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() -call (before or after MinLBFGSSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecscale(const minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetprecscale(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minlbfgsiteration(const minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::minlbfgsiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlbfgsoptimize(minlbfgsstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (func is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlbfgsoptimize(minlbfgsstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'minlbfgsoptimize()' (grad is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlbfgsoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -L-BFGS algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinLBFGSSetGradientCheck() for more information. - * -2 rounding errors prevent further improvement. - X contains best point found. - * -1 incorrect parameters were specified - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgsresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -L-BFGS algorithm results - -Buffered implementation of MinLBFGSResults which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgsresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine restarts LBFGS algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgsrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLBFGSOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLBFGSSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 24.05.2012 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetgradientcheck(const minlbfgsstate &state, const double teststep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This object stores nonlinear optimizer state. -You should use functions provided by MinQP subpackage to work with this -object -*************************************************************************/ -_minqpstate_owner::_minqpstate_owner() -{ - p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minqpstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minqpstate_owner::_minqpstate_owner(const _minqpstate_owner &rhs) -{ - p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minqpstate_owner& _minqpstate_owner::operator=(const _minqpstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minqpstate_clear(p_struct); - if( !alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minqpstate_owner::~_minqpstate_owner() -{ - alglib_impl::_minqpstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minqpstate* _minqpstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minqpstate* _minqpstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minqpstate::minqpstate() : _minqpstate_owner() -{ -} - -minqpstate::minqpstate(const minqpstate &rhs):_minqpstate_owner(rhs) -{ -} - -minqpstate& minqpstate::operator=(const minqpstate &rhs) -{ - if( this==&rhs ) - return *this; - _minqpstate_owner::operator=(rhs); - return *this; -} - -minqpstate::~minqpstate() -{ -} - - -/************************************************************************* -This structure stores optimization report: -* InnerIterationsCount number of inner iterations -* OuterIterationsCount number of outer iterations -* NCholesky number of Cholesky decomposition -* NMV number of matrix-vector products - (only products calculated as part of iterative - process are counted) -* TerminationType completion code (see below) - -Completion codes: -* -5 inappropriate solver was used: - * Cholesky solver for semidefinite or indefinite problems - * Cholesky solver for problems with non-boundary constraints -* -4 BLEIC-QP algorithm found unconstrained direction - of negative curvature (function is unbounded from - below even under constraints), no meaningful - minimum can be found. -* -3 inconsistent constraints (or, maybe, feasible point is - too hard to find). If you are sure that constraints are feasible, - try to restart optimizer with better initial approximation. -* -1 solver error -* 4 successful completion -* 5 MaxIts steps was taken -* 7 stopping conditions are too stringent, - further improvement is impossible, - X contains best point found so far. -*************************************************************************/ -_minqpreport_owner::_minqpreport_owner() -{ - p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minqpreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minqpreport_owner::_minqpreport_owner(const _minqpreport_owner &rhs) -{ - p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minqpreport_owner& _minqpreport_owner::operator=(const _minqpreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minqpreport_clear(p_struct); - if( !alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minqpreport_owner::~_minqpreport_owner() -{ - alglib_impl::_minqpreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minqpreport* _minqpreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minqpreport* _minqpreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minqpreport::minqpreport() : _minqpreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype) -{ -} - -minqpreport::minqpreport(const minqpreport &rhs):_minqpreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype) -{ -} - -minqpreport& minqpreport::operator=(const minqpreport &rhs) -{ - if( this==&rhs ) - return *this; - _minqpreport_owner::operator=(rhs); - return *this; -} - -minqpreport::~minqpreport() -{ -} - -/************************************************************************* - CONSTRAINED QUADRATIC PROGRAMMING - -The subroutine creates QP optimizer. After initial creation, it contains -default optimization problem with zero quadratic and linear terms and no -constraints. You should set quadratic/linear terms with calls to functions -provided by MinQP subpackage. - -INPUT PARAMETERS: - N - problem size - -OUTPUT PARAMETERS: - State - optimizer with zero quadratic/linear terms - and no constraints - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpcreate(const ae_int_t n, minqpstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpcreate(n, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear term for QP solver. - -By default, linear term is zero. - -INPUT PARAMETERS: - State - structure which stores algorithm state - B - linear term, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetlinearterm(const_cast(state.c_ptr()), const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets dense quadratic term for QP solver. By default, -quadratic term is zero. - -SUPPORT BY ALGLIB QP ALGORITHMS: - -Dense quadratic term can be handled by any of the QP algorithms supported -by ALGLIB QP Solver. - -IMPORTANT: - -This solver minimizes following function: - f(x) = 0.5*x'*A*x + b'*x. -Note that quadratic term has 0.5 before it. So if you want to minimize - f(x) = x^2 + x -you should rewrite your problem as follows: - f(x) = 0.5*(2*x^2) + x -and your matrix A will be equal to [[2.0]], not to [[1.0]] - -INPUT PARAMETERS: - State - structure which stores algorithm state - A - matrix, array[N,N] - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used - * if not given, both lower and upper triangles must be - filled. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetquadraticterm(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets dense quadratic term for QP solver. By default, -quadratic term is zero. - -SUPPORT BY ALGLIB QP ALGORITHMS: - -Dense quadratic term can be handled by any of the QP algorithms supported -by ALGLIB QP Solver. - -IMPORTANT: - -This solver minimizes following function: - f(x) = 0.5*x'*A*x + b'*x. -Note that quadratic term has 0.5 before it. So if you want to minimize - f(x) = x^2 + x -you should rewrite your problem as follows: - f(x) = 0.5*(2*x^2) + x -and your matrix A will be equal to [[2.0]], not to [[1.0]] - -INPUT PARAMETERS: - State - structure which stores algorithm state - A - matrix, array[N,N] - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used - * if not given, both lower and upper triangles must be - filled. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a) -{ - alglib_impl::ae_state _alglib_env_state; - bool isupper; - if( !alglib_impl::ae_is_symmetric(const_cast(a.c_ptr())) ) - throw ap_error("'a' parameter is not symmetric matrix"); - isupper = false; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetquadraticterm(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets sparse quadratic term for QP solver. By default, -quadratic term is zero. - -SUPPORT BY ALGLIB QP ALGORITHMS: - -Sparse quadratic term is supported only by BLEIC-based QP algorithm (one -which is activated by MinQPSetAlgoBLEIC function). Cholesky-based QP algo -won't be able to deal with sparse quadratic term and will terminate -abnormally. - -IF YOU CALLED THIS FUNCTION, YOU MUST SWITCH TO BLEIC-BASED QP ALGORITHM -BEFORE CALLING MINQPOPTIMIZE() FUNCTION. - -IMPORTANT: - -This solver minimizes following function: - f(x) = 0.5*x'*A*x + b'*x. -Note that quadratic term has 0.5 before it. So if you want to minimize - f(x) = x^2 + x -you should rewrite your problem as follows: - f(x) = 0.5*(2*x^2) + x -and your matrix A will be equal to [[2.0]], not to [[1.0]] - -INPUT PARAMETERS: - State - structure which stores algorithm state - A - matrix, array[N,N] - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used - * if not given, both lower and upper triangles must be - filled. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadratictermsparse(const minqpstate &state, const sparsematrix &a, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetquadratictermsparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets starting point for QP solver. It is useful to have -good initial approximation to the solution, because it will increase -speed of convergence and identification of active constraints. - -INPUT PARAMETERS: - State - structure which stores algorithm state - X - starting point, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetstartingpoint(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets origin for QP solver. By default, following QP program -is solved: - - min(0.5*x'*A*x+b'*x) - -This function allows to solve different problem: - - min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) - -INPUT PARAMETERS: - State - structure which stores algorithm state - XOrigin - origin, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetorigin(const_cast(state.c_ptr()), const_cast(xorigin.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -BLEIC-based QP solver uses scale for two purposes: -* to evaluate stopping conditions -* for preconditioning of the underlying BLEIC solver - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetscale(const minqpstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function tells solver to use Cholesky-based algorithm. This algorithm -is active by default. - -DESCRIPTION: - -Cholesky-based algorithm can be used only for problems which: -* have dense quadratic term, set by MinQPSetQuadraticTerm(), sparse or - structured problems are not supported. -* are strictly convex, i.e. quadratic term is symmetric positive definite, - indefinite or semidefinite problems are not supported by this algorithm. - -If anything of what listed above is violated, you may use BLEIC-based QP -algorithm which can be activated by MinQPSetAlgoBLEIC(). - -BENEFITS AND DRAWBACKS: - -This algorithm gives best precision amongst all QP solvers provided by -ALGLIB (Newton iterations have much higher precision than any other -optimization algorithm). This solver also gracefully handles problems with -very large amount of constraints. - -Performance of the algorithm is good because internally it uses Level 3 -Dense BLAS for its performance-critical parts. - - -From the other side, algorithm has O(N^3) complexity for unconstrained -problems and up to orders of magnitude slower on constrained problems -(these additional iterations are needed to identify active constraints). -So, its running time depends on number of constraints active at solution. - -Furthermore, this algorithm can not solve problems with sparse matrices or -problems with semidefinite/indefinite matrices of any kind (dense/sparse). - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgocholesky(const minqpstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetalgocholesky(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function tells solver to use BLEIC-based algorithm and sets stopping -criteria for the algorithm. - -DESCRIPTION: - -BLEIC-based QP algorithm can be used for any kind of QP problems: -* problems with both dense and sparse quadratic terms -* problems with positive definite, semidefinite, indefinite terms - -BLEIC-based algorithm can solve even indefinite problems - as long as they -are bounded from below on the feasible set. Of course, global minimum is -found only for positive definite and semidefinite problems. As for -indefinite ones - only local minimum is found. - -BENEFITS AND DRAWBACKS: - -This algorithm can be used to solve both convex and indefinite QP problems -and it can utilize sparsity of the quadratic term (algorithm calculates -matrix-vector products, which can be performed efficiently in case of -sparse matrix). - -Algorithm has iteration cost, which (assuming fixed amount of non-boundary -linear constraints) linearly depends on problem size. Boundary constraints -does not significantly change iteration cost. - -Thus, it outperforms Cholesky-based QP algorithm (CQP) on high-dimensional -sparse problems with moderate amount of constraints. - - -From the other side, unlike CQP solver, this algorithm does NOT make use -of Level 3 Dense BLAS. Thus, its performance on dense problems is inferior -to that of CQP solver. - -Its precision is also inferior to that of CQP. CQP performs Newton steps -which are know to achieve very good precision. In many cases Newton step -leads us exactly to the solution. BLEIC-QP performs LBFGS steps, which are -good at detecting neighborhood of the solution, buy need many iterations -to find solution with 6 digits of precision. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - EpsX - >=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinQPSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection (presently it is small step -length, but it may change in the future versions of ALGLIB). - -IT IS VERY IMPORTANT THAT YOU CALL MinQPSetScale() WHEN YOU USE THIS ALGO! - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgobleic(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetalgobleic(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets boundary constraints for QP solver - -Boundary constraints are inactive by default (after initial creation). -After being set, they are preserved until explicitly turned off with -another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear constraints for QP optimizer. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - structure previously allocated with MinQPCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately - - there always exists some minor violation (about 10^-10...10^-13) - due to numerical errors. - - -- ALGLIB -- - Copyright 19.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets linear constraints for QP optimizer. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - structure previously allocated with MinQPCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately - - there always exists some minor violation (about 10^-10...10^-13) - due to numerical errors. - - -- ALGLIB -- - Copyright 19.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t k; - if( (c.rows()!=ct.length())) - throw ap_error("Error while calling 'minqpsetlc': looks like one of arguments has wrong size"); - k = c.rows(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpsetlc(const_cast(state.c_ptr()), const_cast(c.c_ptr()), const_cast(ct.c_ptr()), k, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function solves quadratic programming problem. -You should call it after setting solver options with MinQPSet...() calls. - -INPUT PARAMETERS: - State - algorithm state - -You should use MinQPResults() function to access results after calls -to this function. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey. - Special thanks to Elvira Illarionova for important suggestions on - the linearly constrained QP algorithm. -*************************************************************************/ -void minqpoptimize(const minqpstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpoptimize(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -QP solver results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution. - This array is allocated and initialized only when - Rep.TerminationType parameter is positive (success). - Rep - optimization report. You should check Rep.TerminationType, - which contains completion code, and you may check another - fields which contain another information about algorithm - functioning. - - Failure codes returned by algorithm are: - * -5 inappropriate solver was used: - * Cholesky solver for (semi)indefinite problems - * Cholesky solver for problems with sparse matrix - * -4 BLEIC-QP algorithm found unconstrained direction - of negative curvature (function is unbounded from - below even under constraints), no meaningful - minimum can be found. - * -3 inconsistent constraints (or maybe feasible point - is too hard to find). If you are sure that - constraints are feasible, try to restart optimizer - with better initial approximation. - - Completion codes specific for Cholesky algorithm: - * 4 successful completion - - Completion codes specific for BLEIC-based algorithm: - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -QP results - -Buffered implementation of MinQPResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minqpresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Levenberg-Marquardt optimizer. - -This structure should be created using one of the MinLMCreate???() -functions. You should not access its fields directly; use ALGLIB functions -to work with it. -*************************************************************************/ -_minlmstate_owner::_minlmstate_owner() -{ - p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlmstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlmstate_owner::_minlmstate_owner(const _minlmstate_owner &rhs) -{ - p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlmstate_owner& _minlmstate_owner::operator=(const _minlmstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minlmstate_clear(p_struct); - if( !alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minlmstate_owner::~_minlmstate_owner() -{ - alglib_impl::_minlmstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minlmstate* _minlmstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minlmstate* _minlmstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minlmstate::minlmstate() : _minlmstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x) -{ -} - -minlmstate::minlmstate(const minlmstate &rhs):_minlmstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),g(&p_struct->g),h(&p_struct->h),j(&p_struct->j),x(&p_struct->x) -{ -} - -minlmstate& minlmstate::operator=(const minlmstate &rhs) -{ - if( this==&rhs ) - return *this; - _minlmstate_owner::operator=(rhs); - return *this; -} - -minlmstate::~minlmstate() -{ -} - - -/************************************************************************* -Optimization report, filled by MinLMResults() function - -FIELDS: -* TerminationType, completion code: - * -7 derivative correctness check failed; - see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for - more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient is no more than EpsG. - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible -* IterationsCount, contains iterations count -* NFunc, number of function calculations -* NJac, number of Jacobi matrix calculations -* NGrad, number of gradient calculations -* NHess, number of Hessian calculations -* NCholesky, number of Cholesky decomposition calculations -*************************************************************************/ -_minlmreport_owner::_minlmreport_owner() -{ - p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlmreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlmreport_owner::_minlmreport_owner(const _minlmreport_owner &rhs) -{ - p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minlmreport_owner& _minlmreport_owner::operator=(const _minlmreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minlmreport_clear(p_struct); - if( !alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minlmreport_owner::~_minlmreport_owner() -{ - alglib_impl::_minlmreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minlmreport* _minlmreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minlmreport* _minlmreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minlmreport::minlmreport() : _minlmreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),funcidx(p_struct->funcidx),varidx(p_struct->varidx),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) -{ -} - -minlmreport::minlmreport(const minlmreport &rhs):_minlmreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),funcidx(p_struct->funcidx),varidx(p_struct->varidx),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) -{ -} - -minlmreport& minlmreport::operator=(const minlmreport &rhs) -{ - if( this==&rhs ) - return *this; - _minlmreport_owner::operator=(rhs); - return *this; -} - -minlmreport::~minlmreport() -{ -} - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] and Jacobian of f[]. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function vector f[] at given point X -* function vector f[] and Jacobian of f[] (simultaneously) at given point - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() and jac() callbacks. -First one is used to calculate f[] at given point, second one calculates -f[] and Jacobian df[i]/dx[j]. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not provide Jacobian), but it -will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateVJ() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatevj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] and Jacobian of f[]. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function vector f[] at given point X -* function vector f[] and Jacobian of f[] (simultaneously) at given point - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() and jac() callbacks. -First one is used to calculate f[] at given point, second one calculates -f[] and Jacobian df[i]/dx[j]. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not provide Jacobian), but it -will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateVJ() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatevj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] only. Finite differences are used to -calculate Jacobian. - - -REQUIREMENTS: -This algorithm will request following information during its operation: -* function vector f[] at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() callback. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not accept function vector), but -it will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateV() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also MinLMIteration, MinLMResults. - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatev(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] only. Finite differences are used to -calculate Jacobian. - - -REQUIREMENTS: -This algorithm will request following information during its operation: -* function vector f[] at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() callback. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not accept function vector), but -it will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateV() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also MinLMIteration, MinLMResults. - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatev(n, m, const_cast(x.c_ptr()), diffstep, const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of general form (not "sum-of- --squares") function - F = F(x[0], ..., x[n-1]) -using its gradient and Hessian. Levenberg-Marquardt modification with -L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization -after each Levenberg-Marquardt step is used. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function value F at given point X -* F and gradient G (simultaneously) at given point X -* F, G and Hessian H (simultaneously) at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts func(), grad() and hess() -function pointers. First pointer is used to calculate F at given point, -second one calculates F(x) and grad F(x), third one calculates F(x), -grad F(x), hess F(x). - -You can try to initialize MinLMState structure with FGH-function and then -use incorrect version of MinLMOptimize() (for example, version which does -not provide Hessian matrix), but it will lead to exception being thrown -after first attempt to calculate Hessian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateFGH() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - pointers (delegates, etc.) to callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefgh(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of general form (not "sum-of- --squares") function - F = F(x[0], ..., x[n-1]) -using its gradient and Hessian. Levenberg-Marquardt modification with -L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization -after each Levenberg-Marquardt step is used. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function value F at given point X -* F and gradient G (simultaneously) at given point X -* F, G and Hessian H (simultaneously) at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts func(), grad() and hess() -function pointers. First pointer is used to calculate F at given point, -second one calculates F(x) and grad F(x), third one calculates F(x), -grad F(x), hess F(x). - -You can try to initialize MinLMState structure with FGH-function and then -use incorrect version of MinLMOptimize() (for example, version which does -not provide Hessian matrix), but it will lead to exception being thrown -after first attempt to calculate Hessian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateFGH() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - pointers (delegates, etc.) to callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgh(const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefgh(n, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping conditions for Levenberg-Marquardt optimization -algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLMSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS -iterations are reported. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetxrep(const minlmstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetstpmax(const minlmstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets scaling coefficients for LM optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetscale(const minlmstate &state, const real_1d_array &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetscale(const_cast(state.c_ptr()), const_cast(s.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets boundary constraints for LM optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: this solver has following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - or at its boundary - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetbc(const_cast(state.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is used to change acceleration settings - -You can choose between three acceleration strategies: -* AccType=0, no acceleration. -* AccType=1, secant updates are used to update quadratic model after each - iteration. After fixed number of iterations (or after model breakdown) - we recalculate quadratic model using analytic Jacobian or finite - differences. Number of secant-based iterations depends on optimization - settings: about 3 iterations - when we have analytic Jacobian, up to 2*N - iterations - when we use finite differences to calculate Jacobian. - -AccType=1 is recommended when Jacobian calculation cost is prohibitive -high (several Mx1 function vector calculations followed by several NxN -Cholesky factorizations are faster than calculation of one M*N Jacobian). -It should also be used when we have no Jacobian, because finite difference -approximation takes too much time to compute. - -Table below list optimization protocols (XYZ protocol corresponds to -MinLMCreateXYZ) and acceleration types they support (and use by default). - -ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: - -protocol 0 1 comment -V + + -VJ + + -FGH + - -DAFAULT VALUES: - -protocol 0 1 comment -V x without acceleration it is so slooooooooow -VJ x -FGH x - -NOTE: this function should be called before optimization. Attempt to call -it during algorithm iterations may result in unexpected behavior. - -NOTE: attempt to call this function with unsupported protocol/acceleration -combination will result in exception being thrown. - - -- ALGLIB -- - Copyright 14.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetacctype(const minlmstate &state, const ae_int_t acctype) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetacctype(const_cast(state.c_ptr()), acctype, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minlmiteration(const minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::minlmiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlmoptimize(minlmstate &state, - void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( fvec==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfi ) - { - fvec(state.x, state.fi, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlmoptimize(minlmstate &state, - void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( fvec==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (fvec is NULL)"); - if( jac==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfi ) - { - fvec(state.x, state.fi, ptr); - continue; - } - if( state.needfij ) - { - jac(state.x, state.fi, state.j, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)"); - if( hess==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (hess is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.needfgh ) - { - hess(state.x, state.f, state.g, state.h, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); - if( jac==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.needfij ) - { - jac(state.x, state.fi, state.j, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (func is NULL)"); - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (grad is NULL)"); - if( jac==NULL ) - throw ap_error("ALGLIB: error in 'minlmoptimize()' (jac is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.needfij ) - { - jac(state.x, state.fi, state.j, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minlmoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -Levenberg-Marquardt algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report; - see comments for this structure for more info. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Levenberg-Marquardt algorithm results - -Buffered implementation of MinLMResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine restarts LM algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinLMCreateXXX call. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmrestartfrom(const minlmstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatevgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatevgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefgj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is considered obsolete since ALGLIB 3.1.0 and is present for -backward compatibility only. We recommend to use MinLMCreateVJ, which -provides similar, but more consistent and feature-rich interface. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function is considered obsolete since ALGLIB 3.1.0 and is present for -backward compatibility only. We recommend to use MinLMCreateVJ, which -provides similar, but more consistent and feature-rich interface. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmcreatefj(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLMOptimize() is called -* prior to actual optimization, for each function Fi and each component - of parameters being optimized X[j] algorithm performs following steps: - * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], - where X[j] is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * Fi(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative, - Rep.FuncIdx is set to index of the function. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) Jacobian evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided - by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLMSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minlmsetgradientcheck(const minlmstate &state, const double teststep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlmsetgradientcheck(const_cast(state.c_ptr()), teststep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_minasastate_owner::_minasastate_owner() -{ - p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minasastate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minasastate_owner::_minasastate_owner(const _minasastate_owner &rhs) -{ - p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minasastate_owner& _minasastate_owner::operator=(const _minasastate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minasastate_clear(p_struct); - if( !alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minasastate_owner::~_minasastate_owner() -{ - alglib_impl::_minasastate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minasastate* _minasastate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minasastate* _minasastate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minasastate::minasastate() : _minasastate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minasastate::minasastate(const minasastate &rhs):_minasastate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) -{ -} - -minasastate& minasastate::operator=(const minasastate &rhs) -{ - if( this==&rhs ) - return *this; - _minasastate_owner::operator=(rhs); - return *this; -} - -minasastate::~minasastate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_minasareport_owner::_minasareport_owner() -{ - p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minasareport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minasareport_owner::_minasareport_owner(const _minasareport_owner &rhs) -{ - p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_minasareport_owner& _minasareport_owner::operator=(const _minasareport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_minasareport_clear(p_struct); - if( !alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_minasareport_owner::~_minasareport_owner() -{ - alglib_impl::_minasareport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::minasareport* _minasareport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::minasareport* _minasareport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -minasareport::minasareport() : _minasareport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) -{ -} - -minasareport::minasareport(const minasareport &rhs):_minasareport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) -{ -} - -minasareport& minasareport::operator=(const minasareport &rhs) -{ - if( this==&rhs ) - return *this; - _minasareport_owner::operator=(rhs); - return *this; -} - -minasareport::~minasareport() -{ -} - -/************************************************************************* -Obsolete function, use MinLBFGSSetPrecDefault() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetdefaultpreconditioner(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minlbfgssetcholeskypreconditioner(const_cast(state.c_ptr()), const_cast(p.c_ptr()), isupper, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierwidth(const minbleicstate &state, const double mu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetbarrierwidth(const_cast(state.c_ptr()), mu, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minbleicsetbarrierdecay(const_cast(state.c_ptr()), mudecay, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasacreate(n, const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=bndl.length()) || (x.length()!=bndu.length())) - throw ap_error("Error while calling 'minasacreate': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasacreate(n, const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasasetcond(const_cast(state.c_ptr()), epsg, epsf, epsx, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetxrep(const minasastate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasasetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetalgorithm(const minasastate &state, const ae_int_t algotype) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasasetalgorithm(const_cast(state.c_ptr()), algotype, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetstpmax(const minasastate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasasetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minasaiteration(const minasastate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::minasaiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void minasaoptimize(minasastate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( grad==NULL ) - throw ap_error("ALGLIB: error in 'minasaoptimize()' (grad is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needfg ) - { - grad(state.x, state.f, state.g, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasaresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasaresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::minasarestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(bndl.c_ptr()), const_cast(bndu.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - - -static ae_int_t cqmodels_newtonrefinementits = 3; -static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, - ae_state *_state); -static void cqmodels_cqmsolveea(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* tmp, - ae_state *_state); - - -static ae_int_t snnls_iterativerefinementits = 3; -static ae_bool snnls_boundedstepandactivation(/* Real */ ae_vector* xc, - /* Real */ ae_vector* xn, - /* Boolean */ ae_vector* nnc, - ae_int_t n, - ae_state *_state); - - -static void sactivesets_constraineddescent(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* h, - /* Real */ ae_matrix* ha, - ae_bool normalize, - /* Real */ ae_vector* d, - ae_state *_state); -static void sactivesets_reactivateconstraints(sactiveset* state, - /* Real */ ae_vector* gc, - /* Real */ ae_vector* h, - ae_state *_state); - - -static ae_int_t mincg_rscountdownlen = 10; -static double mincg_gtol = 0.3; -static void mincg_clearrequestfields(mincgstate* state, ae_state *_state); -static void mincg_preconditionedmultiply(mincgstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* work0, - /* Real */ ae_vector* work1, - ae_state *_state); -static double mincg_preconditionedmultiply2(mincgstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* work0, - /* Real */ ae_vector* work1, - ae_state *_state); -static void mincg_mincginitinternal(ae_int_t n, - double diffstep, - mincgstate* state, - ae_state *_state); - - -static double minbleic_gtol = 0.4; -static double minbleic_maxnonmonotoniclen = 1.0E-5; -static double minbleic_initialdecay = 0.5; -static double minbleic_mindecay = 0.1; -static double minbleic_decaycorrection = 0.8; -static double minbleic_penaltyfactor = 100; -static void minbleic_clearrequestfields(minbleicstate* state, - ae_state *_state); -static void minbleic_minbleicinitinternal(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - minbleicstate* state, - ae_state *_state); -static void minbleic_updateestimateofgoodstep(double* estimate, - double newstep, - ae_state *_state); - - -static double minlbfgs_gtol = 0.4; -static void minlbfgs_clearrequestfields(minlbfgsstate* state, - ae_state *_state); - - -static ae_int_t minqp_maxlagrangeits = 10; -static ae_int_t minqp_maxbadnewtonits = 7; -static double minqp_penaltyfactor = 100.0; -static ae_int_t minqp_minqpboundedstepandactivation(minqpstate* state, - /* Real */ ae_vector* xn, - /* Real */ ae_vector* buf, - ae_state *_state); -static double minqp_minqpmodelvalue(convexquadraticmodel* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* xc, - ae_int_t n, - /* Real */ ae_vector* tmp, - ae_state *_state); -static ae_bool minqp_minqpconstrainedoptimum(minqpstate* state, - convexquadraticmodel* a, - double anorm, - /* Real */ ae_vector* b, - /* Real */ ae_vector* xn, - /* Real */ ae_vector* tmp, - /* Boolean */ ae_vector* tmpb, - /* Real */ ae_vector* lagrangec, - ae_state *_state); - - -static double minlm_lambdaup = 2.0; -static double minlm_lambdadown = 0.33; -static double minlm_suspiciousnu = 16; -static ae_int_t minlm_smallmodelage = 3; -static ae_int_t minlm_additers = 5; -static void minlm_lmprepare(ae_int_t n, - ae_int_t m, - ae_bool havegrad, - minlmstate* state, - ae_state *_state); -static void minlm_clearrequestfields(minlmstate* state, ae_state *_state); -static ae_bool minlm_increaselambda(double* lambdav, - double* nu, - ae_state *_state); -static void minlm_decreaselambda(double* lambdav, - double* nu, - ae_state *_state); -static double minlm_boundedscaledantigradnorm(minlmstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* g, - ae_state *_state); - - -static ae_int_t mincomp_n1 = 2; -static ae_int_t mincomp_n2 = 2; -static double mincomp_stpmin = 1.0E-300; -static double mincomp_gtol = 0.3; -static double mincomp_gpaftol = 0.0001; -static double mincomp_gpadecay = 0.5; -static double mincomp_asarho = 0.5; -static double mincomp_asaboundedantigradnorm(minasastate* state, - ae_state *_state); -static double mincomp_asaginorm(minasastate* state, ae_state *_state); -static double mincomp_asad1norm(minasastate* state, ae_state *_state); -static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state); -static void mincomp_clearrequestfields(minasastate* state, - ae_state *_state); - - - - - -/************************************************************************* -This subroutine is used to prepare threshold value which will be used for -trimming of the target function (see comments on TrimFunction() for more -information). - -This function accepts only one parameter: function value at the starting -point. It returns threshold which will be used for trimming. - - -- ALGLIB -- - Copyright 10.05.2011 by Bochkanov Sergey -*************************************************************************/ -void trimprepare(double f, double* threshold, ae_state *_state) -{ - - *threshold = 0; - - *threshold = 10*(ae_fabs(f, _state)+1); -} - - -/************************************************************************* -This subroutine is used to "trim" target function, i.e. to do following -transformation: - - { {F,G} if F=Threshold - -Such transformation allows us to solve problems with singularities by -redefining function in such way that it becomes bounded from above. - - -- ALGLIB -- - Copyright 10.05.2011 by Bochkanov Sergey -*************************************************************************/ -void trimfunction(double* f, - /* Real */ ae_vector* g, - ae_int_t n, - double threshold, - ae_state *_state) -{ - ae_int_t i; - - - if( ae_fp_greater_eq(*f,threshold) ) - { - *f = threshold; - for(i=0; i<=n-1; i++) - { - g->ptr.p_double[i] = 0.0; - } - } -} - - -/************************************************************************* -This function enforces boundary constraints in the X. - -This function correctly (although a bit inefficient) handles BL[i] which -are -INF and BU[i] which are +INF. - -We have NMain+NSlack dimensional X, with first NMain components bounded -by BL/BU, and next NSlack ones bounded by non-negativity constraints. - -INPUT PARAMETERS - X - array[NMain+NSlack], point - BL - array[NMain], lower bounds - (may contain -INF, when bound is not present) - HaveBL - array[NMain], if HaveBL[i] is False, - then i-th bound is not present - BU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBU - array[NMain], if HaveBU[i] is False, - then i-th bound is not present - -OUTPUT PARAMETERS - X - X with all constraints being enforced - -It returns True when constraints are consistent, -False - when constraints are inconsistent. - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, - /* Real */ ae_vector* bl, - /* Boolean */ ae_vector* havebl, - /* Real */ ae_vector* bu, - /* Boolean */ ae_vector* havebu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state) -{ - ae_int_t i; - ae_bool result; - - - result = ae_false; - for(i=0; i<=nmain-1; i++) - { - if( (havebl->ptr.p_bool[i]&&havebu->ptr.p_bool[i])&&ae_fp_greater(bl->ptr.p_double[i],bu->ptr.p_double[i]) ) - { - return result; - } - if( havebl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bl->ptr.p_double[i]) ) - { - x->ptr.p_double[i] = bl->ptr.p_double[i]; - } - if( havebu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bu->ptr.p_double[i]) ) - { - x->ptr.p_double[i] = bu->ptr.p_double[i]; - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_less(x->ptr.p_double[nmain+i],0) ) - { - x->ptr.p_double[nmain+i] = 0; - } - } - result = ae_true; - return result; -} - - -/************************************************************************* -This function projects gradient into feasible area of boundary constrained -optimization problem. X can be infeasible with respect to boundary -constraints. We have NMain+NSlack dimensional X, with first NMain -components bounded by BL/BU, and next NSlack ones bounded by non-negativity -constraints. - -INPUT PARAMETERS - X - array[NMain+NSlack], point - G - array[NMain+NSlack], gradient - BL - lower bounds (may contain -INF, when bound is not present) - HaveBL - if HaveBL[i] is False, then i-th bound is not present - BU - upper bounds (may contain +INF, when bound is not present) - HaveBU - if HaveBU[i] is False, then i-th bound is not present - -OUTPUT PARAMETERS - G - projection of G. Components of G which satisfy one of the - following - (1) (X[I]<=BndL[I]) and (G[I]>0), OR - (2) (X[I]>=BndU[I]) and (G[I]<0) - are replaced by zeros. - -NOTE 1: this function assumes that constraints are feasible. It throws -exception otherwise. - -NOTE 2: in fact, projection of ANTI-gradient is calculated, because this -function trims components of -G which points outside of the feasible area. -However, working with -G is considered confusing, because all optimization -source work with G. - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -void projectgradientintobc(/* Real */ ae_vector* x, - /* Real */ ae_vector* g, - /* Real */ ae_vector* bl, - /* Boolean */ ae_vector* havebl, - /* Real */ ae_vector* bu, - /* Boolean */ ae_vector* havebu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state) -{ - ae_int_t i; - - - for(i=0; i<=nmain-1; i++) - { - ae_assert((!havebl->ptr.p_bool[i]||!havebu->ptr.p_bool[i])||ae_fp_less_eq(bl->ptr.p_double[i],bu->ptr.p_double[i]), "ProjectGradientIntoBC: internal error (infeasible constraints)", _state); - if( (havebl->ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],bl->ptr.p_double[i]))&&ae_fp_greater(g->ptr.p_double[i],0) ) - { - g->ptr.p_double[i] = 0; - } - if( (havebu->ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],bu->ptr.p_double[i]))&&ae_fp_less(g->ptr.p_double[i],0) ) - { - g->ptr.p_double[i] = 0; - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_less_eq(x->ptr.p_double[nmain+i],0)&&ae_fp_greater(g->ptr.p_double[nmain+i],0) ) - { - g->ptr.p_double[nmain+i] = 0; - } - } -} - - -/************************************************************************* -Given - a) initial point X0[NMain+NSlack] - (feasible with respect to bound constraints) - b) step vector alpha*D[NMain+NSlack] - c) boundary constraints BndL[NMain], BndU[NMain] - d) implicit non-negativity constraints for slack variables -this function calculates bound on the step length subject to boundary -constraints. - -It returns: - * MaxStepLen - such step length that X0+MaxStepLen*alpha*D is exactly - at the boundary given by constraints - * VariableToFreeze - index of the constraint to be activated, - 0 <= VariableToFreeze < NMain+NSlack - * ValueToFreeze - value of the corresponding constraint. - -Notes: - * it is possible that several constraints can be activated by the step - at once. In such cases only one constraint is returned. It is caller - responsibility to check other constraints. This function makes sure - that we activate at least one constraint, and everything else is the - responsibility of the caller. - * steps smaller than MaxStepLen still can activate constraints due to - numerical errors. Thus purpose of this function is not to guard - against accidental activation of the constraints - quite the reverse, - its purpose is to activate at least constraint upon performing step - which is too long. - * in case there is no constraints to activate, we return negative - VariableToFreeze and zero MaxStepLen and ValueToFreeze. - * this function assumes that constraints are consistent; it throws - exception otherwise. - -INPUT PARAMETERS - X - array[NMain+NSlack], point. Must be feasible with respect - to bound constraints (exception will be thrown otherwise) - D - array[NMain+NSlack], step direction - alpha - scalar multiplier before D, alpha<>0 - BndL - lower bounds, array[NMain] - (may contain -INF, when bound is not present) - HaveBndL - array[NMain], if HaveBndL[i] is False, - then i-th bound is not present - BndU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBndU - array[NMain], if HaveBndU[i] is False, - then i-th bound is not present - NMain - number of main variables - NSlack - number of slack variables - -OUTPUT PARAMETERS - VariableToFreeze: - * negative value = step is unbounded, ValueToFreeze=0, - MaxStepLen=0. - * non-negative value = at least one constraint, given by - this parameter, will be activated - upon performing maximum step. - ValueToFreeze- value of the variable which will be constrained - MaxStepLen - maximum length of the step. Can be zero when step vector - looks outside of the feasible area. - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -void calculatestepbound(/* Real */ ae_vector* x, - /* Real */ ae_vector* d, - double alpha, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_int_t* variabletofreeze, - double* valuetofreeze, - double* maxsteplen, - ae_state *_state) -{ - ae_int_t i; - double prevmax; - double initval; - - *variabletofreeze = 0; - *valuetofreeze = 0; - *maxsteplen = 0; - - ae_assert(ae_fp_neq(alpha,0), "CalculateStepBound: zero alpha", _state); - *variabletofreeze = -1; - initval = ae_maxrealnumber; - *maxsteplen = initval; - for(i=0; i<=nmain-1; i++) - { - if( havebndl->ptr.p_bool[i]&&ae_fp_less(alpha*d->ptr.p_double[i],0) ) - { - ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); - prevmax = *maxsteplen; - *maxsteplen = safeminposrv(x->ptr.p_double[i]-bndl->ptr.p_double[i], -alpha*d->ptr.p_double[i], *maxsteplen, _state); - if( ae_fp_less(*maxsteplen,prevmax) ) - { - *variabletofreeze = i; - *valuetofreeze = bndl->ptr.p_double[i]; - } - } - if( havebndu->ptr.p_bool[i]&&ae_fp_greater(alpha*d->ptr.p_double[i],0) ) - { - ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); - prevmax = *maxsteplen; - *maxsteplen = safeminposrv(bndu->ptr.p_double[i]-x->ptr.p_double[i], alpha*d->ptr.p_double[i], *maxsteplen, _state); - if( ae_fp_less(*maxsteplen,prevmax) ) - { - *variabletofreeze = i; - *valuetofreeze = bndu->ptr.p_double[i]; - } - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_less(alpha*d->ptr.p_double[nmain+i],0) ) - { - ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],0), "CalculateStepBound: infeasible X", _state); - prevmax = *maxsteplen; - *maxsteplen = safeminposrv(x->ptr.p_double[nmain+i], -alpha*d->ptr.p_double[nmain+i], *maxsteplen, _state); - if( ae_fp_less(*maxsteplen,prevmax) ) - { - *variabletofreeze = nmain+i; - *valuetofreeze = 0; - } - } - } - if( ae_fp_eq(*maxsteplen,initval) ) - { - *valuetofreeze = 0; - *maxsteplen = 0; - } -} - - -/************************************************************************* -This function postprocesses bounded step by: -* analysing step length (whether it is equal to MaxStepLen) and activating - constraint given by VariableToFreeze if needed -* checking for additional bound constraints to activate - -This function uses final point of the step, quantities calculated by the -CalculateStepBound() function. As result, it returns point which is -exactly feasible with respect to boundary constraints. - -NOTE 1: this function does NOT handle and check linear equality constraints -NOTE 2: when StepTaken=MaxStepLen we always activate at least one constraint - -INPUT PARAMETERS - X - array[NMain+NSlack], final point to postprocess - XPrev - array[NMain+NSlack], initial point - BndL - lower bounds, array[NMain] - (may contain -INF, when bound is not present) - HaveBndL - array[NMain], if HaveBndL[i] is False, - then i-th bound is not present - BndU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBndU - array[NMain], if HaveBndU[i] is False, - then i-th bound is not present - NMain - number of main variables - NSlack - number of slack variables - VariableToFreeze-result of CalculateStepBound() - ValueToFreeze- result of CalculateStepBound() - StepTaken - actual step length (actual step is equal to the possibly - non-unit step direction vector times this parameter). - StepTaken<=MaxStepLen. - MaxStepLen - result of CalculateStepBound() - -OUTPUT PARAMETERS - X - point bounded with respect to constraints. - components corresponding to active constraints are exactly - equal to the boundary values. - -RESULT: - number of constraints activated in addition to previously active ones. - Constraints which were DEACTIVATED are ignored (do not influence - function value). - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, - /* Real */ ae_vector* xprev, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_int_t variabletofreeze, - double valuetofreeze, - double steptaken, - double maxsteplen, - ae_state *_state) -{ - ae_int_t i; - ae_bool wasactivated; - ae_int_t result; - - - ae_assert(variabletofreeze<0||ae_fp_less_eq(steptaken,maxsteplen), "Assertion failed", _state); - - /* - * Activate constraints - */ - if( variabletofreeze>=0&&ae_fp_eq(steptaken,maxsteplen) ) - { - x->ptr.p_double[variabletofreeze] = valuetofreeze; - } - for(i=0; i<=nmain-1; i++) - { - if( havebndl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) - { - x->ptr.p_double[i] = bndl->ptr.p_double[i]; - } - if( havebndu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) - { - x->ptr.p_double[i] = bndu->ptr.p_double[i]; - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_less_eq(x->ptr.p_double[nmain+i],0) ) - { - x->ptr.p_double[nmain+i] = 0; - } - } - - /* - * Calculate number of constraints being activated - */ - result = 0; - for(i=0; i<=nmain-1; i++) - { - wasactivated = ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i])&&((havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]))); - wasactivated = wasactivated||variabletofreeze==i; - if( wasactivated ) - { - result = result+1; - } - } - for(i=0; i<=nslack-1; i++) - { - wasactivated = ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&ae_fp_eq(x->ptr.p_double[nmain+i],0.0); - wasactivated = wasactivated||variabletofreeze==nmain+i; - if( wasactivated ) - { - result = result+1; - } - } - return result; -} - - -/************************************************************************* -The purpose of this function is to prevent algorithm from "unsticking" -from the active bound constraints because of numerical noise in the -gradient or Hessian. - -It is done by zeroing some components of the search direction D. D[i] is -zeroed when both (a) and (b) are true: -a) corresponding X[i] is exactly at the boundary -b) |D[i]*S[i]| <= DropTol*Sqrt(SUM(D[i]^2*S[I]^2)) - -D can be step direction , antigradient, gradient, or anything similar. -Sign of D does not matter, nor matters step length. - -NOTE 1: boundary constraints are expected to be consistent, as well as X - is expected to be feasible. Exception will be thrown otherwise. - -INPUT PARAMETERS - D - array[NMain+NSlack], direction - X - array[NMain+NSlack], current point - BndL - lower bounds, array[NMain] - (may contain -INF, when bound is not present) - HaveBndL - array[NMain], if HaveBndL[i] is False, - then i-th bound is not present - BndU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBndU - array[NMain], if HaveBndU[i] is False, - then i-th bound is not present - S - array[NMain+NSlack], scaling of the variables - NMain - number of main variables - NSlack - number of slack variables - DropTol - drop tolerance, >=0 - -OUTPUT PARAMETERS - X - point bounded with respect to constraints. - components corresponding to active constraints are exactly - equal to the boundary values. - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -void filterdirection(/* Real */ ae_vector* d, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - /* Real */ ae_vector* s, - ae_int_t nmain, - ae_int_t nslack, - double droptol, - ae_state *_state) -{ - ae_int_t i; - double scalednorm; - ae_bool isactive; - - - scalednorm = 0.0; - for(i=0; i<=nmain+nslack-1; i++) - { - scalednorm = scalednorm+ae_sqr(d->ptr.p_double[i]*s->ptr.p_double[i], _state); - } - scalednorm = ae_sqrt(scalednorm, _state); - for(i=0; i<=nmain-1; i++) - { - ae_assert(!havebndl->ptr.p_bool[i]||ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "FilterDirection: infeasible point", _state); - ae_assert(!havebndu->ptr.p_bool[i]||ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "FilterDirection: infeasible point", _state); - isactive = (havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])); - if( isactive&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[i]*s->ptr.p_double[i], _state),droptol*scalednorm) ) - { - d->ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=nslack-1; i++) - { - ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],0), "FilterDirection: infeasible point", _state); - if( ae_fp_eq(x->ptr.p_double[nmain+i],0)&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[nmain+i]*s->ptr.p_double[nmain+i], _state),droptol*scalednorm) ) - { - d->ptr.p_double[nmain+i] = 0.0; - } - } -} - - -/************************************************************************* -This function returns number of bound constraints whose state was changed -(either activated or deactivated) when making step from XPrev to X. - -Constraints are considered: -* active - when we are exactly at the boundary -* inactive - when we are not at the boundary - -You should note that antigradient direction is NOT taken into account when -we make decions on the constraint status. - -INPUT PARAMETERS - X - array[NMain+NSlack], final point. - Must be feasible with respect to bound constraints. - XPrev - array[NMain+NSlack], initial point. - Must be feasible with respect to bound constraints. - BndL - lower bounds, array[NMain] - (may contain -INF, when bound is not present) - HaveBndL - array[NMain], if HaveBndL[i] is False, - then i-th bound is not present - BndU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBndU - array[NMain], if HaveBndU[i] is False, - then i-th bound is not present - NMain - number of main variables - NSlack - number of slack variables - -RESULT: - number of constraints whose state was changed. - - -- ALGLIB -- - Copyright 10.01.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t numberofchangedconstraints(/* Real */ ae_vector* x, - /* Real */ ae_vector* xprev, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state) -{ - ae_int_t i; - ae_bool statuschanged; - ae_int_t result; - - - result = 0; - for(i=0; i<=nmain-1; i++) - { - if( ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i]) ) - { - statuschanged = ae_false; - if( havebndl->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndl->ptr.p_double[i])) ) - { - statuschanged = ae_true; - } - if( havebndu->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndu->ptr.p_double[i])) ) - { - statuschanged = ae_true; - } - if( statuschanged ) - { - result = result+1; - } - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&(ae_fp_eq(x->ptr.p_double[nmain+i],0)||ae_fp_eq(xprev->ptr.p_double[nmain+i],0)) ) - { - result = result+1; - } - } - return result; -} - - -/************************************************************************* -This function finds feasible point of (NMain+NSlack)-dimensional problem -subject to NMain explicit boundary constraints (some constraints can be -omitted), NSlack implicit non-negativity constraints, K linear equality -constraints. - -INPUT PARAMETERS - X - array[NMain+NSlack], initial point. - BndL - lower bounds, array[NMain] - (may contain -INF, when bound is not present) - HaveBndL - array[NMain], if HaveBndL[i] is False, - then i-th bound is not present - BndU - array[NMain], upper bounds - (may contain +INF, when bound is not present) - HaveBndU - array[NMain], if HaveBndU[i] is False, - then i-th bound is not present - NMain - number of main variables - NSlack - number of slack variables - CE - array[K,NMain+NSlack+1], equality constraints CE*x=b. - Rows contain constraints, first NMain+NSlack columns - contain coefficients before X[], last column contain - right part. - K - number of linear constraints - EpsI - infeasibility (error in the right part) allowed in the - solution - -OUTPUT PARAMETERS: - X - feasible point or best infeasible point found before - algorithm termination - QPIts - number of QP iterations (for debug purposes) - GPAIts - number of GPA iterations (for debug purposes) - -RESULT: - True in case X is feasible, False - if it is infeasible. - - -- ALGLIB -- - Copyright 20.01.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool findfeasiblepoint(/* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - /* Real */ ae_matrix* ce, - ae_int_t k, - double epsi, - ae_int_t* qpits, - ae_int_t* gpaits, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _ce; - ae_int_t i; - ae_int_t j; - ae_int_t idx0; - ae_int_t idx1; - ae_vector permx; - ae_vector xn; - ae_vector xa; - ae_vector newtonstep; - ae_vector g; - ae_vector pg; - ae_matrix a; - double armijostep; - double armijobeststep; - double armijobestfeas; - double v; - double mx; - double feaserr; - double feasold; - double feasnew; - double pgnorm; - double vn; - double vd; - double stp; - ae_int_t vartofreeze; - double valtofreeze; - double maxsteplen; - ae_bool werechangesinconstraints; - ae_bool stage1isover; - ae_bool converged; - ae_vector activeconstraints; - ae_vector tmpk; - ae_vector colnorms; - ae_int_t nactive; - ae_int_t nfree; - ae_int_t nsvd; - ae_vector p1; - ae_vector p2; - apbuffers buf; - ae_vector w; - ae_vector s; - ae_matrix u; - ae_matrix vt; - ae_int_t itscount; - ae_int_t itswithintolerance; - ae_int_t maxitswithintolerance; - ae_int_t gparuns; - ae_int_t maxarmijoruns; - ae_bool result; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_ce, ce, _state, ae_true); - ce = &_ce; - *qpits = 0; - *gpaits = 0; - ae_vector_init(&permx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xn, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); - ae_vector_init(&newtonstep, 0, DT_REAL, _state, ae_true); - ae_vector_init(&g, 0, DT_REAL, _state, ae_true); - ae_vector_init(&pg, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&activeconstraints, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmpk, 0, DT_REAL, _state, ae_true); - ae_vector_init(&colnorms, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p1, 0, DT_INT, _state, ae_true); - ae_vector_init(&p2, 0, DT_INT, _state, ae_true); - _apbuffers_init(&buf, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - ae_vector_init(&s, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); - - maxitswithintolerance = 3; - maxarmijoruns = 5; - *qpits = 0; - *gpaits = 0; - - /* - * Initial enforcement of the feasibility with respect to boundary constraints - * NOTE: after this block we assume that boundary constraints are consistent. - */ - if( !enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state) ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - if( k==0 ) - { - - /* - * No linear constraints, we can exit right now - */ - result = ae_true; - ae_frame_leave(_state); - return result; - } - - /* - * Scale rows of CE in such way that max(CE[i,0..nmain+nslack-1])=1 for any i=0..k-1 - */ - for(i=0; i<=k-1; i++) - { - v = 0.0; - for(j=0; j<=nmain+nslack-1; j++) - { - v = ae_maxreal(v, ae_fabs(ce->ptr.pp_double[i][j], _state), _state); - } - if( ae_fp_neq(v,0) ) - { - v = 1/v; - ae_v_muld(&ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack), v); - } - } - - /* - * Allocate temporaries - */ - ae_vector_set_length(&xn, nmain+nslack, _state); - ae_vector_set_length(&xa, nmain+nslack, _state); - ae_vector_set_length(&permx, nmain+nslack, _state); - ae_vector_set_length(&g, nmain+nslack, _state); - ae_vector_set_length(&pg, nmain+nslack, _state); - ae_vector_set_length(&tmpk, k, _state); - ae_matrix_set_length(&a, k, nmain+nslack, _state); - ae_vector_set_length(&activeconstraints, nmain+nslack, _state); - ae_vector_set_length(&newtonstep, nmain+nslack, _state); - ae_vector_set_length(&s, nmain+nslack, _state); - ae_vector_set_length(&colnorms, nmain+nslack, _state); - for(i=0; i<=nmain+nslack-1; i++) - { - s.ptr.p_double[i] = 1.0; - colnorms.ptr.p_double[i] = 0.0; - for(j=0; j<=k-1; j++) - { - colnorms.ptr.p_double[i] = colnorms.ptr.p_double[i]+ae_sqr(ce->ptr.pp_double[j][i], _state); - } - } - - /* - * K>0, we have linear equality constraints combined with bound constraints. - * - * Try to find feasible point as minimizer of the quadratic function - * F(x) = 0.5*||CE*x-b||^2 = 0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b - * subject to boundary constraints given by BL, BU and non-negativity of - * the slack variables. BTW, we drop constant term because it does not - * actually influences on the solution. - * - * Below we will assume that K>0. - */ - itswithintolerance = 0; - itscount = 0; - for(;;) - { - - /* - * Stage 0: check for exact convergence - */ - converged = ae_true; - feaserr = 0; - for(i=0; i<=k-1; i++) - { - - /* - * Calculate: - * * V - error in the right part - * * MX - maximum term in the left part - * - * Terminate if error in the right part is not greater than 100*Eps*MX. - * - * IMPORTANT: we must perform check for non-strict inequality, i.e. to use <= instead of <. - * it will allow us to easily handle situations with zero rows of CE. - */ - mx = 0; - v = -ce->ptr.pp_double[i][nmain+nslack]; - for(j=0; j<=nmain+nslack-1; j++) - { - mx = ae_maxreal(mx, ae_fabs(ce->ptr.pp_double[i][j]*x->ptr.p_double[j], _state), _state); - v = v+ce->ptr.pp_double[i][j]*x->ptr.p_double[j]; - } - feaserr = feaserr+ae_sqr(v, _state); - converged = converged&&ae_fp_less_eq(ae_fabs(v, _state),100*ae_machineepsilon*mx); - } - feaserr = ae_sqrt(feaserr, _state); - if( converged ) - { - result = ae_fp_less_eq(feaserr,epsi); - ae_frame_leave(_state); - return result; - } - - /* - * Stage 1: equality constrained quadratic programming - * - * * treat active bound constraints as equality ones (constraint is considered - * active when we are at the boundary, independently of the antigradient direction) - * * calculate unrestricted Newton step to point XM (which may be infeasible) - * calculate MaxStepLen = largest step in direction of XM which retains feasibility. - * * perform bounded step from X to XN: - * a) XN=XM (if XM is feasible) - * b) XN=X-MaxStepLen*(XM-X) (otherwise) - * * X := XN - * * if XM (Newton step subject to currently active constraints) was feasible, goto Stage 2 - * * repeat Stage 1 - * - * NOTE 1: in order to solve constrained qudratic subproblem we will have to reorder - * variables in such way that ones corresponding to inactive constraints will - * be first, and active ones will be last in the list. CE and X are now - * [ xi ] - * separated into two parts: CE = [CEi CEa], x = [ ], where CEi/Xi correspond - * [ xa ] - * to INACTIVE constraints, and CEa/Xa correspond to the ACTIVE ones. - * - * Now, instead of F=0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b, we have - * F(xi) = 0.5*(CEi*xi,CEi*xi) + (CEa*xa-b,CEi*xi) + (0.5*CEa*xa-b,CEa*xa). - * Here xa is considered constant, i.e. we optimize with respect to xi, leaving xa fixed. - * - * We can solve it by performing SVD of CEi and calculating pseudoinverse of the - * Hessian matrix. Of course, we do NOT calculate pseudoinverse explicitly - we - * just use singular vectors to perform implicit multiplication by it. - * - */ - for(;;) - { - - /* - * Calculate G - gradient subject to equality constraints, - * multiply it by inverse of the Hessian diagonal to obtain initial - * step vector. - * - * Bound step subject to constraints which can be activated, - * run Armijo search with increasing step size. - * Search is terminated when feasibility error stops to decrease. - * - * NOTE: it is important to test for "stops to decrease" instead - * of "starts to increase" in order to correctly handle cases with - * zero CE. - */ - armijobeststep = 0.0; - armijobestfeas = 0.0; - for(i=0; i<=nmain+nslack-1; i++) - { - g.ptr.p_double[i] = 0; - } - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - armijobestfeas = armijobestfeas+ae_sqr(v, _state); - ae_v_addd(&g.ptr.p_double[0], 1, &ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v); - } - armijobestfeas = ae_sqrt(armijobestfeas, _state); - for(i=0; i<=nmain-1; i++) - { - if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) - { - g.ptr.p_double[i] = 0.0; - } - if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) - { - g.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=nslack-1; i++) - { - if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) - { - g.ptr.p_double[nmain+i] = 0.0; - } - } - v = 0.0; - for(i=0; i<=nmain+nslack-1; i++) - { - if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),0) ) - { - newtonstep.ptr.p_double[i] = -g.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); - } - else - { - newtonstep.ptr.p_double[i] = 0.0; - } - v = v+ae_sqr(newtonstep.ptr.p_double[i], _state); - } - if( ae_fp_eq(v,0) ) - { - - /* - * Constrained gradient is zero, QP iterations are over - */ - break; - } - calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); - if( vartofreeze>=0&&ae_fp_eq(maxsteplen,0) ) - { - - /* - * Can not perform step, QP iterations are over - */ - break; - } - if( vartofreeze>=0 ) - { - armijostep = ae_minreal(1.0, maxsteplen, _state); - } - else - { - armijostep = 1; - } - for(;;) - { - ae_v_move(&xa.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); - enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); - feaserr = 0.0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - feaserr = feaserr+ae_sqr(v, _state); - } - feaserr = ae_sqrt(feaserr, _state); - if( ae_fp_greater_eq(feaserr,armijobestfeas) ) - { - break; - } - armijobestfeas = feaserr; - armijobeststep = armijostep; - armijostep = 2.0*armijostep; - } - ae_v_addd(&x->ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); - enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); - - /* - * Determine number of active and free constraints - */ - nactive = 0; - for(i=0; i<=nmain-1; i++) - { - activeconstraints.ptr.p_double[i] = 0; - if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) - { - activeconstraints.ptr.p_double[i] = 1; - } - if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) - { - activeconstraints.ptr.p_double[i] = 1; - } - if( ae_fp_greater(activeconstraints.ptr.p_double[i],0) ) - { - nactive = nactive+1; - } - } - for(i=0; i<=nslack-1; i++) - { - activeconstraints.ptr.p_double[nmain+i] = 0; - if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) - { - activeconstraints.ptr.p_double[nmain+i] = 1; - } - if( ae_fp_greater(activeconstraints.ptr.p_double[nmain+i],0) ) - { - nactive = nactive+1; - } - } - nfree = nmain+nslack-nactive; - if( nfree==0 ) - { - break; - } - *qpits = *qpits+1; - - /* - * Reorder variables - */ - tagsortbuf(&activeconstraints, nmain+nslack, &p1, &p2, &buf, _state); - for(i=0; i<=k-1; i++) - { - for(j=0; j<=nmain+nslack-1; j++) - { - a.ptr.pp_double[i][j] = ce->ptr.pp_double[i][j]; - } - } - for(j=0; j<=nmain+nslack-1; j++) - { - permx.ptr.p_double[j] = x->ptr.p_double[j]; - } - for(j=0; j<=nmain+nslack-1; j++) - { - if( p2.ptr.p_int[j]!=j ) - { - idx0 = p2.ptr.p_int[j]; - idx1 = j; - for(i=0; i<=k-1; i++) - { - v = a.ptr.pp_double[i][idx0]; - a.ptr.pp_double[i][idx0] = a.ptr.pp_double[i][idx1]; - a.ptr.pp_double[i][idx1] = v; - } - v = permx.ptr.p_double[idx0]; - permx.ptr.p_double[idx0] = permx.ptr.p_double[idx1]; - permx.ptr.p_double[idx1] = v; - } - } - - /* - * Calculate (unprojected) gradient: - * G(xi) = CEi'*(CEi*xi + CEa*xa - b) - */ - for(i=0; i<=nfree-1; i++) - { - g.ptr.p_double[i] = 0; - } - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&a.ptr.pp_double[i][0], 1, &permx.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - tmpk.ptr.p_double[i] = v-ce->ptr.pp_double[i][nmain+nslack]; - } - for(i=0; i<=k-1; i++) - { - v = tmpk.ptr.p_double[i]; - ae_v_addd(&g.ptr.p_double[0], 1, &a.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); - } - - /* - * Calculate Newton step using SVD of CEi: - * F(xi) = 0.5*xi'*H*xi + g'*xi (Taylor decomposition) - * XN = -H^(-1)*g (new point, solution of the QP subproblem) - * H = CEi'*CEi - * CEi = U*W*V' (SVD of CEi) - * H = V*W^2*V' - * H^(-1) = V*W^(-2)*V' - * step = -V*W^(-2)*V'*g (it is better to perform multiplication from right to left) - * - * NOTE 1: we do NOT need left singular vectors to perform Newton step. - */ - nsvd = ae_minint(k, nfree, _state); - if( !rmatrixsvd(&a, k, nfree, 0, 1, 2, &w, &u, &vt, _state) ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - for(i=0; i<=nsvd-1; i++) - { - v = ae_v_dotproduct(&vt.ptr.pp_double[i][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); - tmpk.ptr.p_double[i] = v; - } - for(i=0; i<=nsvd-1; i++) - { - - /* - * It is important to have strict ">" in order to correctly - * handle zero singular values. - */ - if( ae_fp_greater(ae_sqr(w.ptr.p_double[i], _state),ae_sqr(w.ptr.p_double[0], _state)*(nmain+nslack)*ae_machineepsilon) ) - { - tmpk.ptr.p_double[i] = tmpk.ptr.p_double[i]/ae_sqr(w.ptr.p_double[i], _state); - } - else - { - tmpk.ptr.p_double[i] = 0; - } - } - for(i=0; i<=nmain+nslack-1; i++) - { - newtonstep.ptr.p_double[i] = 0; - } - for(i=0; i<=nsvd-1; i++) - { - v = tmpk.ptr.p_double[i]; - ae_v_subd(&newtonstep.ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); - } - for(j=nmain+nslack-1; j>=0; j--) - { - if( p2.ptr.p_int[j]!=j ) - { - idx0 = p2.ptr.p_int[j]; - idx1 = j; - v = newtonstep.ptr.p_double[idx0]; - newtonstep.ptr.p_double[idx0] = newtonstep.ptr.p_double[idx1]; - newtonstep.ptr.p_double[idx1] = v; - } - } - - /* - * NewtonStep contains Newton step subject to active bound constraints. - * - * Such step leads us to the minimizer of the equality constrained F, - * but such minimizer may be infeasible because some constraints which - * are inactive at the initial point can be violated at the solution. - * - * Thus, we perform optimization in two stages: - * a) perform bounded Newton step, i.e. step in the Newton direction - * until activation of the first constraint - * b) in case (MaxStepLen>0)and(MaxStepLen<1), perform additional iteration - * of the Armijo line search in the rest of the Newton direction. - */ - calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); - if( vartofreeze>=0&&ae_fp_eq(maxsteplen,0) ) - { - - /* - * Activation of the constraints prevent us from performing step, - * QP iterations are over - */ - break; - } - if( vartofreeze>=0 ) - { - v = ae_minreal(1.0, maxsteplen, _state); - } - else - { - v = 1.0; - } - ae_v_moved(&xn.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); - ae_v_add(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); - if( ae_fp_greater(maxsteplen,0)&&ae_fp_less(maxsteplen,1) ) - { - - /* - * Newton step was restricted by activation of the constraints, - * perform Armijo iteration. - * - * Initial estimate for best step is zero step. We try different - * step sizes, from the 1-MaxStepLen (residual of the full Newton - * step) to progressively smaller and smaller steps. - */ - armijobeststep = 0.0; - armijobestfeas = 0.0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - armijobestfeas = armijobestfeas+ae_sqr(v, _state); - } - armijobestfeas = ae_sqrt(armijobestfeas, _state); - armijostep = 1-maxsteplen; - for(j=0; j<=maxarmijoruns-1; j++) - { - ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); - enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); - feaserr = 0.0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - feaserr = feaserr+ae_sqr(v, _state); - } - feaserr = ae_sqrt(feaserr, _state); - if( ae_fp_less(feaserr,armijobestfeas) ) - { - armijobestfeas = feaserr; - armijobeststep = armijostep; - } - armijostep = 0.5*armijostep; - } - ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); - enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); - } - else - { - - /* - * Armijo iteration is not performed - */ - ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - } - stage1isover = ae_fp_greater_eq(maxsteplen,1)||ae_fp_eq(maxsteplen,0); - - /* - * Calculate feasibility errors for old and new X. - * These quantinies are used for debugging purposes only. - * However, we can leave them in release code because performance impact is insignificant. - * - * Update X. Exit if needed. - */ - feasold = 0; - feasnew = 0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - feasold = feasold+ae_sqr(v-ce->ptr.pp_double[i][nmain+nslack], _state); - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - feasnew = feasnew+ae_sqr(v-ce->ptr.pp_double[i][nmain+nslack], _state); - } - feasold = ae_sqrt(feasold, _state); - feasnew = ae_sqrt(feasnew, _state); - if( ae_fp_greater_eq(feasnew,feasold) ) - { - break; - } - ae_v_move(&x->ptr.p_double[0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - if( stage1isover ) - { - break; - } - } - - /* - * Stage 2: gradient projection algorithm (GPA) - * - * * calculate feasibility error (with respect to linear equality constraints) - * * calculate gradient G of F, project it into feasible area (G => PG) - * * exit if norm(PG) is exactly zero or feasibility error is smaller than EpsC - * * let XM be exact minimum of F along -PG (XM may be infeasible). - * calculate MaxStepLen = largest step in direction of -PG which retains feasibility. - * * perform bounded step from X to XN: - * a) XN=XM (if XM is feasible) - * b) XN=X-MaxStepLen*PG (otherwise) - * * X := XN - * * stop after specified number of iterations or when no new constraints was activated - * - * NOTES: - * * grad(F) = (CE'*CE)*x - (b'*CE)^T - * * CE[i] denotes I-th row of CE - * * XM = X+stp*(-PG) where stp=(grad(F(X)),PG)/(CE*PG,CE*PG). - * Here PG is a projected gradient, but in fact it can be arbitrary non-zero - * direction vector - formula for minimum of F along PG still will be correct. - */ - werechangesinconstraints = ae_false; - for(gparuns=1; gparuns<=k; gparuns++) - { - - /* - * calculate feasibility error and G - */ - feaserr = 0; - for(i=0; i<=nmain+nslack-1; i++) - { - g.ptr.p_double[i] = 0; - } - for(i=0; i<=k-1; i++) - { - - /* - * G += CE[i]^T * (CE[i]*x-b[i]) - */ - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - feaserr = feaserr+ae_sqr(v, _state); - ae_v_addd(&g.ptr.p_double[0], 1, &ce->ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack-1), v); - } - - /* - * project G, filter it (strip numerical noise) - */ - ae_v_move(&pg.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - projectgradientintobc(x, &pg, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); - filterdirection(&pg, x, bndl, havebndl, bndu, havebndu, &s, nmain, nslack, 1.0E-9, _state); - for(i=0; i<=nmain+nslack-1; i++) - { - if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),0) ) - { - pg.ptr.p_double[i] = pg.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); - } - else - { - pg.ptr.p_double[i] = 0.0; - } - } - - /* - * Check GNorm and feasibility. - * Exit when GNorm is exactly zero. - */ - pgnorm = ae_v_dotproduct(&pg.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - feaserr = ae_sqrt(feaserr, _state); - pgnorm = ae_sqrt(pgnorm, _state); - if( ae_fp_eq(pgnorm,0) ) - { - result = ae_fp_less_eq(feaserr,epsi); - ae_frame_leave(_state); - return result; - } - - /* - * calculate planned step length - */ - vn = ae_v_dotproduct(&g.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - vd = 0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - vd = vd+ae_sqr(v, _state); - } - stp = vn/vd; - - /* - * Calculate step bound. - * Perform bounded step and post-process it - */ - calculatestepbound(x, &pg, -1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); - if( vartofreeze>=0&&ae_fp_eq(maxsteplen,0) ) - { - result = ae_false; - ae_frame_leave(_state); - return result; - } - if( vartofreeze>=0 ) - { - v = ae_minreal(stp, maxsteplen, _state); - } - else - { - v = stp; - } - ae_v_move(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - ae_v_subd(&xn.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); - postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); - - /* - * update X - * check stopping criteria - */ - werechangesinconstraints = werechangesinconstraints||numberofchangedconstraints(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state)>0; - ae_v_move(&x->ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - *gpaits = *gpaits+1; - if( !werechangesinconstraints ) - { - break; - } - } - - /* - * Stage 3: decide to stop algorithm or not to stop - * - * 1. we can stop when last GPA run did NOT changed constraints status. - * It means that we've found final set of the active constraints even - * before GPA made its run. And it means that Newton step moved us to - * the minimum subject to the present constraints. - * Depending on feasibility error, True or False is returned. - */ - feaserr = 0; - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&ce->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); - v = v-ce->ptr.pp_double[i][nmain+nslack]; - feaserr = feaserr+ae_sqr(v, _state); - } - feaserr = ae_sqrt(feaserr, _state); - if( ae_fp_less_eq(feaserr,epsi) ) - { - itswithintolerance = itswithintolerance+1; - } - else - { - itswithintolerance = 0; - } - if( !werechangesinconstraints||itswithintolerance>=maxitswithintolerance ) - { - result = ae_fp_less_eq(feaserr,epsi); - ae_frame_leave(_state); - return result; - } - itscount = itscount+1; - } - ae_frame_leave(_state); - return result; -} - - -/************************************************************************* - This function check, that input derivatives are right. First it scale -parameters DF0 and DF1 from segment [A;B] to [0;1]. Than it build Hermite -spline and derivative of it in 0,5. Search scale as Max(DF0,DF1, |F0-F1|). -Right derivative has to satisfy condition: - |H-F|/S<=0,01, |H'-F'|/S<=0,01. - -INPUT PARAMETERS: - F0 - function's value in X-TestStep point; - DF0 - derivative's value in X-TestStep point; - F1 - function's value in X+TestStep point; - DF1 - derivative's value in X+TestStep point; - F - testing function's value; - DF - testing derivative's value; - Width- width of verification segment. - -RESULT: - If input derivatives is right then function returns true, else - function returns false. - - -- ALGLIB -- - Copyright 29.05.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool derivativecheck(double f0, - double df0, - double f1, - double df1, - double f, - double df, - double width, - ae_state *_state) -{ - double s; - double h; - double dh; - ae_bool result; - - - df = width*df; - df0 = width*df0; - df1 = width*df1; - s = ae_maxreal(ae_maxreal(ae_fabs(df0, _state), ae_fabs(df1, _state), _state), ae_fabs(f1-f0, _state), _state); - h = 0.5*f0+0.125*df0+0.5*f1-0.125*df1; - dh = -1.5*f0-0.25*df0+1.5*f1-0.25*df1; - if( ae_fp_neq(s,0) ) - { - if( ae_fp_greater(ae_fabs(h-f, _state)/s,0.001)||ae_fp_greater(ae_fabs(dh-df, _state)/s,0.001) ) - { - result = ae_false; - return result; - } - } - else - { - if( ae_fp_neq(h-f,0.0)||ae_fp_neq(dh-df,0.0) ) - { - result = ae_false; - return result; - } - } - result = ae_true; - return result; -} - - - - -/************************************************************************* -This subroutine is used to initialize CQM. By default, empty NxN model is -generated, with Alpha=Lambda=Theta=0.0 and zero b. - -Previously allocated buffer variables are reused as much as possible. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state) -{ - ae_int_t i; - - - s->n = n; - s->k = 0; - s->nfree = n; - s->ecakind = -1; - s->alpha = 0.0; - s->tau = 0.0; - s->theta = 0.0; - s->ismaintermchanged = ae_true; - s->issecondarytermchanged = ae_true; - s->islineartermchanged = ae_true; - s->isactivesetchanged = ae_true; - bvectorsetlengthatleast(&s->activeset, n, _state); - rvectorsetlengthatleast(&s->xc, n, _state); - rvectorsetlengthatleast(&s->eb, n, _state); - rvectorsetlengthatleast(&s->tq1, n, _state); - rvectorsetlengthatleast(&s->txc, n, _state); - rvectorsetlengthatleast(&s->tb, n, _state); - rvectorsetlengthatleast(&s->b, s->n, _state); - rvectorsetlengthatleast(&s->tk1, s->n, _state); - for(i=0; i<=n-1; i++) - { - s->activeset.ptr.p_bool[i] = ae_false; - s->xc.ptr.p_double[i] = 0.0; - s->b.ptr.p_double[i] = 0.0; - } -} - - -/************************************************************************* -This subroutine changes main quadratic term of the model. - -INPUT PARAMETERS: - S - model - A - NxN matrix, only upper or lower triangle is referenced - IsUpper - True, when matrix is stored in upper triangle - Alpha - multiplier; when Alpha=0, A is not referenced at all - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmseta(convexquadraticmodel* s, - /* Real */ ae_matrix* a, - ae_bool isupper, - double alpha, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - double v; - - - ae_assert(ae_isfinite(alpha, _state)&&ae_fp_greater_eq(alpha,0), "CQMSetA: Alpha<0 or is not finite number", _state); - ae_assert(ae_fp_eq(alpha,0)||isfinitertrmatrix(a, s->n, isupper, _state), "CQMSetA: A is not finite NxN matrix", _state); - s->alpha = alpha; - if( ae_fp_greater(alpha,0) ) - { - rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); - rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); - rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); - for(i=0; i<=s->n-1; i++) - { - for(j=i; j<=s->n-1; j++) - { - if( isupper ) - { - v = a->ptr.pp_double[i][j]; - } - else - { - v = a->ptr.pp_double[j][i]; - } - s->a.ptr.pp_double[i][j] = v; - s->a.ptr.pp_double[j][i] = v; - } - } - } - s->ismaintermchanged = ae_true; -} - - -/************************************************************************* -This subroutine rewrites diagonal of the main quadratic term of the model -(dense A) by vector Z/Alpha (current value of the Alpha coefficient is -used). - -IMPORTANT: in case model has no dense quadratic term, this function - allocates N*N dense matrix of zeros, and fills its diagonal by - non-zero values. - -INPUT PARAMETERS: - S - model - Z - new diagonal, array[N] - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmrewritedensediagonal(convexquadraticmodel* s, - /* Real */ ae_vector* z, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - - - n = s->n; - if( ae_fp_eq(s->alpha,0) ) - { - rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); - rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); - rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - s->a.ptr.pp_double[i][j] = 0.0; - } - } - s->alpha = 1.0; - } - for(i=0; i<=s->n-1; i++) - { - s->a.ptr.pp_double[i][i] = z->ptr.p_double[i]/s->alpha; - } - s->ismaintermchanged = ae_true; -} - - -/************************************************************************* -This subroutine changes diagonal quadratic term of the model. - -INPUT PARAMETERS: - S - model - D - array[N], semidefinite diagonal matrix - Tau - multiplier; when Tau=0, D is not referenced at all - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmsetd(convexquadraticmodel* s, - /* Real */ ae_vector* d, - double tau, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(ae_isfinite(tau, _state)&&ae_fp_greater_eq(tau,0), "CQMSetD: Tau<0 or is not finite number", _state); - ae_assert(ae_fp_eq(tau,0)||isfinitevector(d, s->n, _state), "CQMSetD: D is not finite Nx1 vector", _state); - s->tau = tau; - if( ae_fp_greater(tau,0) ) - { - rvectorsetlengthatleast(&s->d, s->n, _state); - rvectorsetlengthatleast(&s->ecadiag, s->n, _state); - rvectorsetlengthatleast(&s->tq2diag, s->n, _state); - for(i=0; i<=s->n-1; i++) - { - ae_assert(ae_fp_greater_eq(d->ptr.p_double[i],0), "CQMSetD: D[i]<0", _state); - s->d.ptr.p_double[i] = d->ptr.p_double[i]; - } - } - s->ismaintermchanged = ae_true; -} - - -/************************************************************************* -This subroutine drops main quadratic term A from the model. It is same as -call to CQMSetA() with zero A, but gives better performance because -algorithm knows that matrix is zero and can optimize subsequent -calculations. - -INPUT PARAMETERS: - S - model - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmdropa(convexquadraticmodel* s, ae_state *_state) -{ - - - s->alpha = 0.0; - s->ismaintermchanged = ae_true; -} - - -/************************************************************************* -This subroutine changes linear term of the model - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmsetb(convexquadraticmodel* s, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(isfinitevector(b, s->n, _state), "CQMSetB: B is not finite vector", _state); - rvectorsetlengthatleast(&s->b, s->n, _state); - for(i=0; i<=s->n-1; i++) - { - s->b.ptr.p_double[i] = b->ptr.p_double[i]; - } - s->islineartermchanged = ae_true; -} - - -/************************************************************************* -This subroutine changes linear term of the model - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmsetq(convexquadraticmodel* s, - /* Real */ ae_matrix* q, - /* Real */ ae_vector* r, - ae_int_t k, - double theta, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - - - ae_assert(k>=0, "CQMSetQ: K<0", _state); - ae_assert((k==0||ae_fp_eq(theta,0))||apservisfinitematrix(q, k, s->n, _state), "CQMSetQ: Q is not finite matrix", _state); - ae_assert((k==0||ae_fp_eq(theta,0))||isfinitevector(r, k, _state), "CQMSetQ: R is not finite vector", _state); - ae_assert(ae_isfinite(theta, _state)&&ae_fp_greater_eq(theta,0), "CQMSetQ: Theta<0 or is not finite number", _state); - - /* - * degenerate case: K=0 or Theta=0 - */ - if( k==0||ae_fp_eq(theta,0) ) - { - s->k = 0; - s->theta = 0; - s->issecondarytermchanged = ae_true; - return; - } - - /* - * General case: both Theta>0 and K>0 - */ - s->k = k; - s->theta = theta; - rmatrixsetlengthatleast(&s->q, s->k, s->n, _state); - rvectorsetlengthatleast(&s->r, s->k, _state); - rmatrixsetlengthatleast(&s->eq, s->k, s->n, _state); - rmatrixsetlengthatleast(&s->eccm, s->k, s->k, _state); - rmatrixsetlengthatleast(&s->tk2, s->k, s->n, _state); - for(i=0; i<=s->k-1; i++) - { - for(j=0; j<=s->n-1; j++) - { - s->q.ptr.pp_double[i][j] = q->ptr.pp_double[i][j]; - } - s->r.ptr.p_double[i] = r->ptr.p_double[i]; - } - s->issecondarytermchanged = ae_true; -} - - -/************************************************************************* -This subroutine changes active set - -INPUT PARAMETERS - S - model - X - array[N], constraint values - ActiveSet- array[N], active set. If ActiveSet[I]=True, then I-th - variables is constrained to X[I]. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmsetactiveset(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Boolean */ ae_vector* activeset, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(x->cnt>=s->n, "CQMSetActiveSet: Length(X)cnt>=s->n, "CQMSetActiveSet: Length(ActiveSet)n-1; i++) - { - s->isactivesetchanged = s->isactivesetchanged||(s->activeset.ptr.p_bool[i]&&!activeset->ptr.p_bool[i]); - s->isactivesetchanged = s->isactivesetchanged||(activeset->ptr.p_bool[i]&&!s->activeset.ptr.p_bool[i]); - s->activeset.ptr.p_bool[i] = activeset->ptr.p_bool[i]; - if( activeset->ptr.p_bool[i] ) - { - ae_assert(ae_isfinite(x->ptr.p_double[i], _state), "CQMSetActiveSet: X[] contains infinite constraints", _state); - s->isactivesetchanged = s->isactivesetchanged||ae_fp_neq(s->xc.ptr.p_double[i],x->ptr.p_double[i]); - s->xc.ptr.p_double[i] = x->ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This subroutine evaluates model at X. Active constraints are ignored. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -double cqmeval(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double v; - double result; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); - result = 0.0; - - /* - * main quadratic term - */ - if( ae_fp_greater(s->alpha,0) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - result = result+s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; - } - } - } - if( ae_fp_greater(s->tau,0) ) - { - for(i=0; i<=n-1; i++) - { - result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; - } - } - - /* - * secondary quadratic term - */ - if( ae_fp_greater(s->theta,0) ) - { - for(i=0; i<=s->k-1; i++) - { - v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - result = result+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); - } - } - - /* - * linear term - */ - for(i=0; i<=s->n-1; i++) - { - result = result+x->ptr.p_double[i]*s->b.ptr.p_double[i]; - } - return result; -} - - -/************************************************************************* -This subroutine evaluates model at X. Active constraints are ignored. -It returns: - R - model value - Noise- estimate of the numerical noise in data - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmevalx(convexquadraticmodel* s, - /* Real */ ae_vector* x, - double* r, - double* noise, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double v; - double v2; - double mxq; - double eps; - - *r = 0; - *noise = 0; - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); - *r = 0.0; - *noise = 0.0; - eps = 2*ae_machineepsilon; - mxq = 0.0; - - /* - * Main quadratic term. - * - * Noise from the main quadratic term is equal to the - * maximum summand in the term. - */ - if( ae_fp_greater(s->alpha,0) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - v = s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; - *r = *r+v; - *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); - } - } - } - if( ae_fp_greater(s->tau,0) ) - { - for(i=0; i<=n-1; i++) - { - v = 0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; - *r = *r+v; - *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); - } - } - - /* - * secondary quadratic term - * - * Noise from the secondary quadratic term is estimated as follows: - * * noise in qi*x-r[i] is estimated as - * Eps*MXQ = Eps*max(|r[i]|, |q[i,j]*x[j]|) - * * noise in (qi*x-r[i])^2 is estimated as - * NOISE = (|qi*x-r[i]|+Eps*MXQ)^2-(|qi*x-r[i]|)^2 - * = Eps*MXQ*(2*|qi*x-r[i]|+Eps*MXQ) - */ - if( ae_fp_greater(s->theta,0) ) - { - for(i=0; i<=s->k-1; i++) - { - v = 0.0; - mxq = ae_fabs(s->r.ptr.p_double[i], _state); - for(j=0; j<=n-1; j++) - { - v2 = s->q.ptr.pp_double[i][j]*x->ptr.p_double[j]; - v = v+v2; - mxq = ae_maxreal(mxq, ae_fabs(v2, _state), _state); - } - *r = *r+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); - *noise = ae_maxreal(*noise, eps*mxq*(2*ae_fabs(v-s->r.ptr.p_double[i], _state)+eps*mxq), _state); - } - } - - /* - * linear term - */ - for(i=0; i<=s->n-1; i++) - { - *r = *r+x->ptr.p_double[i]*s->b.ptr.p_double[i]; - *noise = ae_maxreal(*noise, eps*ae_fabs(x->ptr.p_double[i]*s->b.ptr.p_double[i], _state), _state); - } - - /* - * Final update of the noise - */ - *noise = n*(*noise); -} - - -/************************************************************************* -This subroutine evaluates gradient of the model; active constraints are -ignored. - -INPUT PARAMETERS: - S - convex model - X - point, array[N] - G - possibly preallocated buffer; resized, if too small - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmgradunconstrained(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* g, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double v; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMEvalGradUnconstrained: X is not finite vector", _state); - rvectorsetlengthatleast(g, n, _state); - for(i=0; i<=n-1; i++) - { - g->ptr.p_double[i] = 0; - } - - /* - * main quadratic term - */ - if( ae_fp_greater(s->alpha,0) ) - { - for(i=0; i<=n-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+s->alpha*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; - } - g->ptr.p_double[i] = g->ptr.p_double[i]+v; - } - } - if( ae_fp_greater(s->tau,0) ) - { - for(i=0; i<=n-1; i++) - { - g->ptr.p_double[i] = g->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; - } - } - - /* - * secondary quadratic term - */ - if( ae_fp_greater(s->theta,0) ) - { - for(i=0; i<=s->k-1; i++) - { - v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = s->theta*(v-s->r.ptr.p_double[i]); - ae_v_addd(&g->ptr.p_double[0], 1, &s->q.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - } - - /* - * linear term - */ - for(i=0; i<=n-1; i++) - { - g->ptr.p_double[i] = g->ptr.p_double[i]+s->b.ptr.p_double[i]; - } -} - - -/************************************************************************* -This subroutine evaluates x'*(0.5*alpha*A+tau*D)*x - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -double cqmxtadx2(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double result; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); - result = 0.0; - - /* - * main quadratic term - */ - if( ae_fp_greater(s->alpha,0) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - result = result+s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; - } - } - } - if( ae_fp_greater(s->tau,0) ) - { - for(i=0; i<=n-1; i++) - { - result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; - } - } - return result; -} - - -/************************************************************************* -This subroutine evaluates (0.5*alpha*A+tau*D)*x - -Y is automatically resized if needed - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmadx(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double v; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); - rvectorsetlengthatleast(y, n, _state); - - /* - * main quadratic term - */ - for(i=0; i<=n-1; i++) - { - y->ptr.p_double[i] = 0; - } - if( ae_fp_greater(s->alpha,0) ) - { - for(i=0; i<=n-1; i++) - { - v = ae_v_dotproduct(&s->a.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - y->ptr.p_double[i] = y->ptr.p_double[i]+s->alpha*v; - } - } - if( ae_fp_greater(s->tau,0) ) - { - for(i=0; i<=n-1; i++) - { - y->ptr.p_double[i] = y->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This subroutine finds optimum of the model. It returns False on failure -(indefinite/semidefinite matrix). Optimum is found subject to active -constraints. - -INPUT PARAMETERS - S - model - X - possibly preallocated buffer; automatically resized, if - too small enough. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nfree; - ae_int_t k; - ae_int_t i; - double v; - ae_int_t cidx0; - ae_int_t itidx; - ae_bool result; - - - - /* - * Rebuild internal structures - */ - if( !cqmodels_cqmrebuild(s, _state) ) - { - result = ae_false; - return result; - } - n = s->n; - k = s->k; - nfree = s->nfree; - result = ae_true; - - /* - * Calculate initial point for the iterative refinement: - * * free components are set to zero - * * constrained components are set to their constrained values - */ - rvectorsetlengthatleast(x, n, _state); - for(i=0; i<=n-1; i++) - { - if( s->activeset.ptr.p_bool[i] ) - { - x->ptr.p_double[i] = s->xc.ptr.p_double[i]; - } - else - { - x->ptr.p_double[i] = 0; - } - } - - /* - * Iterative refinement. - * - * In an ideal world without numerical errors it would be enough - * to make just one Newton step from initial point: - * x_new = -H^(-1)*grad(x=0) - * However, roundoff errors can significantly deteriorate quality - * of the solution. So we have to recalculate gradient and to - * perform Newton steps several times. - * - * Below we perform fixed number of Newton iterations. - */ - for(itidx=0; itidx<=cqmodels_newtonrefinementits-1; itidx++) - { - - /* - * Calculate gradient at the current point. - * Move free components of the gradient in the beginning. - */ - cqmgradunconstrained(s, x, &s->tmpg, _state); - cidx0 = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - s->tmpg.ptr.p_double[cidx0] = s->tmpg.ptr.p_double[i]; - cidx0 = cidx0+1; - } - } - - /* - * Free components of the extrema are calculated in the first NFree elements of TXC. - * - * First, we have to calculate original Newton step, without rank-K perturbations - */ - ae_v_moveneg(&s->txc.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); - cqmodels_cqmsolveea(s, &s->txc, &s->tmp0, _state); - - /* - * Then, we account for rank-K correction. - * Woodbury matrix identity is used. - */ - if( s->k>0&&ae_fp_greater(s->theta,0) ) - { - rvectorsetlengthatleast(&s->tmp0, ae_maxint(nfree, k, _state), _state); - rvectorsetlengthatleast(&s->tmp1, ae_maxint(nfree, k, _state), _state); - ae_v_moveneg(&s->tmp1.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); - cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); - for(i=0; i<=k-1; i++) - { - v = ae_v_dotproduct(&s->eq.ptr.pp_double[i][0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); - s->tmp0.ptr.p_double[i] = v; - } - fblscholeskysolve(&s->eccm, 1.0, k, ae_true, &s->tmp0, &s->tmp1, _state); - for(i=0; i<=nfree-1; i++) - { - s->tmp1.ptr.p_double[i] = 0.0; - } - for(i=0; i<=k-1; i++) - { - v = s->tmp0.ptr.p_double[i]; - ae_v_addd(&s->tmp1.ptr.p_double[0], 1, &s->eq.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); - } - cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); - ae_v_sub(&s->txc.ptr.p_double[0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); - } - - /* - * Unpack components from TXC into X. We pass through all - * free components of X and add our step. - */ - cidx0 = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - x->ptr.p_double[i] = x->ptr.p_double[i]+s->txc.ptr.p_double[cidx0]; - cidx0 = cidx0+1; - } - } - } - return result; -} - - -/************************************************************************* -This function scales vector by multiplying it by inverse of the diagonal -of the Hessian matrix. It should be used to accelerate steepest descent -phase of the QP solver. - -Although it is called "scale-grad", it can be called for any vector, -whether it is gradient, anti-gradient, or just some vector. - -This function does NOT takes into account current set of constraints, it -just performs matrix-vector multiplication without taking into account -constraints. - -INPUT PARAMETERS: - S - model - X - vector to scale - -OUTPUT PARAMETERS: - X - scaled vector - -NOTE: - when called for non-SPD matrices, it silently skips components of X - which correspond to zero or negative diagonal elements. - -NOTE: - this function uses diagonals of A and D; it ignores Q - rank-K term of - the quadratic model. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -void cqmscalevector(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double v; - - - n = s->n; - for(i=0; i<=n-1; i++) - { - v = 0.0; - if( ae_fp_greater(s->alpha,0) ) - { - v = v+s->a.ptr.pp_double[i][i]; - } - if( ae_fp_greater(s->tau,0) ) - { - v = v+s->d.ptr.p_double[i]; - } - if( ae_fp_greater(v,0) ) - { - x->ptr.p_double[i] = x->ptr.p_double[i]/v; - } - } -} - - -/************************************************************************* -This subroutine calls CQMRebuild() and evaluates model at X subject to -active constraints. - -It is intended for debug purposes only, because it evaluates model by -means of temporaries, which were calculated by CQMRebuild(). The only -purpose of this function is to check correctness of CQMRebuild() by -comparing results of this function with ones obtained by CQMEval(), which -is used as reference point. The idea is that significant deviation in -results of these two functions is evidence of some error in the -CQMRebuild(). - -NOTE: suffix T denotes that temporaries marked by T-prefix are used. There - is one more variant of this function, which uses "effective" model - built by CQMRebuild(). - -NOTE2: in case CQMRebuild() fails (due to model non-convexity), this - function returns NAN. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -double cqmdebugconstrainedevalt(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nfree; - ae_int_t i; - ae_int_t j; - double v; - double result; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalT: X is not finite vector", _state); - if( !cqmodels_cqmrebuild(s, _state) ) - { - result = _state->v_nan; - return result; - } - result = 0.0; - nfree = s->nfree; - - /* - * Reorder variables - */ - j = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; - j = j+1; - } - } - - /* - * TQ2, TQ1, TQ0 - * - */ - if( ae_fp_greater(s->alpha,0) ) - { - - /* - * Dense TQ2 - */ - for(i=0; i<=nfree-1; i++) - { - for(j=0; j<=nfree-1; j++) - { - result = result+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; - } - } - } - else - { - - /* - * Diagonal TQ2 - */ - for(i=0; i<=nfree-1; i++) - { - result = result+0.5*s->tq2diag.ptr.p_double[i]*ae_sqr(s->txc.ptr.p_double[i], _state); - } - } - for(i=0; i<=nfree-1; i++) - { - result = result+s->tq1.ptr.p_double[i]*s->txc.ptr.p_double[i]; - } - result = result+s->tq0; - - /* - * TK2, TK1, TK0 - */ - if( s->k>0&&ae_fp_greater(s->theta,0) ) - { - for(i=0; i<=s->k-1; i++) - { - v = 0; - for(j=0; j<=nfree-1; j++) - { - v = v+s->tk2.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; - } - result = result+0.5*ae_sqr(v, _state); - } - for(i=0; i<=nfree-1; i++) - { - result = result+s->tk1.ptr.p_double[i]*s->txc.ptr.p_double[i]; - } - result = result+s->tk0; - } - - /* - * TB (Bf and Bc parts) - */ - for(i=0; i<=n-1; i++) - { - result = result+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; - } - return result; -} - - -/************************************************************************* -This subroutine calls CQMRebuild() and evaluates model at X subject to -active constraints. - -It is intended for debug purposes only, because it evaluates model by -means of "effective" matrices built by CQMRebuild(). The only purpose of -this function is to check correctness of CQMRebuild() by comparing results -of this function with ones obtained by CQMEval(), which is used as -reference point. The idea is that significant deviation in results of -these two functions is evidence of some error in the CQMRebuild(). - -NOTE: suffix E denotes that effective matrices. There is one more variant - of this function, which uses temporary matrices built by - CQMRebuild(). - -NOTE2: in case CQMRebuild() fails (due to model non-convexity), this - function returns NAN. - - -- ALGLIB -- - Copyright 12.06.2012 by Bochkanov Sergey -*************************************************************************/ -double cqmdebugconstrainedevale(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nfree; - ae_int_t i; - ae_int_t j; - double v; - double result; - - - n = s->n; - ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalE: X is not finite vector", _state); - if( !cqmodels_cqmrebuild(s, _state) ) - { - result = _state->v_nan; - return result; - } - result = 0.0; - nfree = s->nfree; - - /* - * Reorder variables - */ - j = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; - j = j+1; - } - } - - /* - * ECA - */ - ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&nfree==0), "CQMDebugConstrainedEvalE: unexpected ECAKind", _state); - if( s->ecakind==0 ) - { - - /* - * Dense ECA - */ - for(i=0; i<=nfree-1; i++) - { - v = 0.0; - for(j=i; j<=nfree-1; j++) - { - v = v+s->ecadense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; - } - result = result+0.5*ae_sqr(v, _state); - } - } - if( s->ecakind==1 ) - { - - /* - * Diagonal ECA - */ - for(i=0; i<=nfree-1; i++) - { - result = result+0.5*ae_sqr(s->ecadiag.ptr.p_double[i]*s->txc.ptr.p_double[i], _state); - } - } - - /* - * EQ - */ - for(i=0; i<=s->k-1; i++) - { - v = 0.0; - for(j=0; j<=nfree-1; j++) - { - v = v+s->eq.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; - } - result = result+0.5*ae_sqr(v, _state); - } - - /* - * EB - */ - for(i=0; i<=nfree-1; i++) - { - result = result+s->eb.ptr.p_double[i]*s->txc.ptr.p_double[i]; - } - - /* - * EC - */ - result = result+s->ec; - return result; -} - - -/************************************************************************* -Internal function, rebuilds "effective" model subject to constraints. -Returns False on failure (non-SPD main quadratic term) - - -- ALGLIB -- - Copyright 10.05.2011 by Bochkanov Sergey -*************************************************************************/ -static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nfree; - ae_int_t k; - ae_int_t i; - ae_int_t j; - ae_int_t ridx0; - ae_int_t ridx1; - ae_int_t cidx0; - ae_int_t cidx1; - double v; - ae_bool result; - - - if( ae_fp_eq(s->alpha,0)&&ae_fp_eq(s->tau,0) ) - { - - /* - * Non-SPD model, quick exit - */ - result = ae_false; - return result; - } - result = ae_true; - n = s->n; - k = s->k; - - /* - * Determine number of free variables. - * Fill TXC - array whose last N-NFree elements store constraints. - */ - if( s->isactivesetchanged ) - { - s->nfree = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - s->nfree = s->nfree+1; - } - } - j = s->nfree; - for(i=0; i<=n-1; i++) - { - if( s->activeset.ptr.p_bool[i] ) - { - s->txc.ptr.p_double[j] = s->xc.ptr.p_double[i]; - j = j+1; - } - } - } - nfree = s->nfree; - - /* - * Re-evaluate TQ2/TQ1/TQ0, if needed - */ - if( s->isactivesetchanged||s->ismaintermchanged ) - { - - /* - * Handle cases Alpha>0 and Alpha=0 separately: - * * in the first case we have dense matrix - * * in the second one we have diagonal matrix, which can be - * handled more efficiently - */ - if( ae_fp_greater(s->alpha,0) ) - { - - /* - * Alpha>0, dense QP - * - * Split variables into two groups - free (F) and constrained (C). Reorder - * variables in such way that free vars come first, constrained are last: - * x = [xf, xc]. - * - * Main quadratic term x'*(alpha*A+tau*D)*x now splits into quadratic part, - * linear part and constant part: - * ( alpha*Aff+tau*Df alpha*Afc ) ( xf ) - * 0.5*( xf' xc' )*( )*( ) = - * ( alpha*Acf alpha*Acc+tau*Dc ) ( xc ) - * - * = 0.5*xf'*(alpha*Aff+tau*Df)*xf + (alpha*Afc*xc)'*xf + 0.5*xc'(alpha*Acc+tau*Dc)*xc - * - * We store these parts into temporary variables: - * * alpha*Aff+tau*Df, alpha*Afc, alpha*Acc+tau*Dc are stored into upper - * triangle of TQ2 - * * alpha*Afc*xc is stored into TQ1 - * * 0.5*xc'(alpha*Acc+tau*Dc)*xc is stored into TQ0 - * - * Below comes first part of the work - generation of TQ2: - * * we pass through rows of A and copy I-th row into upper block (Aff/Afc) or - * lower one (Acf/Acc) of TQ2, depending on presence of X[i] in the active set. - * RIdx0 variable contains current position for insertion into upper block, - * RIdx1 contains current position for insertion into lower one. - * * within each row, we copy J-th element into left half (Aff/Acf) or right - * one (Afc/Acc), depending on presence of X[j] in the active set. CIdx0 - * contains current position for insertion into left block, CIdx1 contains - * position for insertion into right one. - * * during copying, we multiply elements by alpha and add diagonal matrix D. - */ - ridx0 = 0; - ridx1 = s->nfree; - for(i=0; i<=n-1; i++) - { - cidx0 = 0; - cidx1 = s->nfree; - for(j=0; j<=n-1; j++) - { - if( !s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) - { - - /* - * Element belongs to Aff - */ - v = s->alpha*s->a.ptr.pp_double[i][j]; - if( i==j&&ae_fp_greater(s->tau,0) ) - { - v = v+s->tau*s->d.ptr.p_double[i]; - } - s->tq2dense.ptr.pp_double[ridx0][cidx0] = v; - } - if( !s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) - { - - /* - * Element belongs to Afc - */ - s->tq2dense.ptr.pp_double[ridx0][cidx1] = s->alpha*s->a.ptr.pp_double[i][j]; - } - if( s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) - { - - /* - * Element belongs to Acf - */ - s->tq2dense.ptr.pp_double[ridx1][cidx0] = s->alpha*s->a.ptr.pp_double[i][j]; - } - if( s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) - { - - /* - * Element belongs to Acc - */ - v = s->alpha*s->a.ptr.pp_double[i][j]; - if( i==j&&ae_fp_greater(s->tau,0) ) - { - v = v+s->tau*s->d.ptr.p_double[i]; - } - s->tq2dense.ptr.pp_double[ridx1][cidx1] = v; - } - if( s->activeset.ptr.p_bool[j] ) - { - cidx1 = cidx1+1; - } - else - { - cidx0 = cidx0+1; - } - } - if( s->activeset.ptr.p_bool[i] ) - { - ridx1 = ridx1+1; - } - else - { - ridx0 = ridx0+1; - } - } - - /* - * Now we have TQ2, and we can evaluate TQ1. - * In the special case when we have Alpha=0, NFree=0 or NFree=N, - * TQ1 is filled by zeros. - */ - for(i=0; i<=n-1; i++) - { - s->tq1.ptr.p_double[i] = 0.0; - } - if( s->nfree>0&&s->nfreenfree, n-s->nfree, &s->tq2dense, 0, s->nfree, 0, &s->txc, s->nfree, &s->tq1, 0, _state); - } - - /* - * And finally, we evaluate TQ0. - */ - v = 0.0; - for(i=s->nfree; i<=n-1; i++) - { - for(j=s->nfree; j<=n-1; j++) - { - v = v+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; - } - } - s->tq0 = v; - } - else - { - - /* - * Alpha=0, diagonal QP - * - * Split variables into two groups - free (F) and constrained (C). Reorder - * variables in such way that free vars come first, constrained are last: - * x = [xf, xc]. - * - * Main quadratic term x'*(tau*D)*x now splits into quadratic and constant - * parts: - * ( tau*Df ) ( xf ) - * 0.5*( xf' xc' )*( )*( ) = - * ( tau*Dc ) ( xc ) - * - * = 0.5*xf'*(tau*Df)*xf + 0.5*xc'(tau*Dc)*xc - * - * We store these parts into temporary variables: - * * tau*Df is stored in TQ2Diag - * * 0.5*xc'(tau*Dc)*xc is stored into TQ0 - */ - s->tq0 = 0.0; - ridx0 = 0; - for(i=0; i<=n-1; i++) - { - if( !s->activeset.ptr.p_bool[i] ) - { - s->tq2diag.ptr.p_double[ridx0] = s->tau*s->d.ptr.p_double[i]; - ridx0 = ridx0+1; - } - else - { - s->tq0 = s->tq0+0.5*s->tau*s->d.ptr.p_double[i]*ae_sqr(s->xc.ptr.p_double[i], _state); - } - } - for(i=0; i<=n-1; i++) - { - s->tq1.ptr.p_double[i] = 0.0; - } - } - } - - /* - * Re-evaluate TK2/TK1/TK0, if needed - */ - if( s->isactivesetchanged||s->issecondarytermchanged ) - { - - /* - * Split variables into two groups - free (F) and constrained (C). Reorder - * variables in such way that free vars come first, constrained are last: - * x = [xf, xc]. - * - * Secondary term theta*(Q*x-r)'*(Q*x-r) now splits into quadratic part, - * linear part and constant part: - * ( ( xf ) )' ( ( xf ) ) - * 0.5*theta*( (Qf Qc)'*( ) - r ) * ( (Qf Qc)'*( ) - r ) = - * ( ( xc ) ) ( ( xc ) ) - * - * = 0.5*theta*xf'*(Qf'*Qf)*xf + theta*((Qc*xc-r)'*Qf)*xf + - * + theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) - * - * We store these parts into temporary variables: - * * sqrt(theta)*Qf is stored into TK2 - * * theta*((Qc*xc-r)'*Qf) is stored into TK1 - * * theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) is stored into TK0 - * - * We use several other temporaries to store intermediate results: - * * Tmp0 - to store Qc*xc-r - * * Tmp1 - to store Qc*xc - * - * Generation of TK2/TK1/TK0 is performed as follows: - * * we fill TK2/TK1/TK0 (to handle K=0 or Theta=0) - * * other steps are performed only for K>0 and Theta>0 - * * we pass through columns of Q and copy I-th column into left block (Qf) or - * right one (Qc) of TK2, depending on presence of X[i] in the active set. - * CIdx0 variable contains current position for insertion into upper block, - * CIdx1 contains current position for insertion into lower one. - * * we calculate Qc*xc-r and store it into Tmp0 - * * we calculate TK0 and TK1 - * * we multiply leading part of TK2 which stores Qf by sqrt(theta) - * it is important to perform this step AFTER calculation of TK0 and TK1, - * because we need original (non-modified) Qf to calculate TK0 and TK1. - */ - for(j=0; j<=n-1; j++) - { - for(i=0; i<=k-1; i++) - { - s->tk2.ptr.pp_double[i][j] = 0.0; - } - s->tk1.ptr.p_double[j] = 0.0; - } - s->tk0 = 0.0; - if( s->k>0&&ae_fp_greater(s->theta,0) ) - { - - /* - * Split Q into Qf and Qc - * Calculate Qc*xc-r, store in Tmp0 - */ - rvectorsetlengthatleast(&s->tmp0, k, _state); - rvectorsetlengthatleast(&s->tmp1, k, _state); - cidx0 = 0; - cidx1 = nfree; - for(i=0; i<=k-1; i++) - { - s->tmp1.ptr.p_double[i] = 0.0; - } - for(j=0; j<=n-1; j++) - { - if( s->activeset.ptr.p_bool[j] ) - { - for(i=0; i<=k-1; i++) - { - s->tk2.ptr.pp_double[i][cidx1] = s->q.ptr.pp_double[i][j]; - s->tmp1.ptr.p_double[i] = s->tmp1.ptr.p_double[i]+s->q.ptr.pp_double[i][j]*s->txc.ptr.p_double[cidx1]; - } - cidx1 = cidx1+1; - } - else - { - for(i=0; i<=k-1; i++) - { - s->tk2.ptr.pp_double[i][cidx0] = s->q.ptr.pp_double[i][j]; - } - cidx0 = cidx0+1; - } - } - for(i=0; i<=k-1; i++) - { - s->tmp0.ptr.p_double[i] = s->tmp1.ptr.p_double[i]-s->r.ptr.p_double[i]; - } - - /* - * Calculate TK0 - */ - v = 0.0; - for(i=0; i<=k-1; i++) - { - v = v+s->theta*(0.5*ae_sqr(s->tmp1.ptr.p_double[i], _state)-s->r.ptr.p_double[i]*s->tmp0.ptr.p_double[i]-0.5*ae_sqr(s->r.ptr.p_double[i], _state)); - } - s->tk0 = v; - - /* - * Calculate TK1 - */ - if( nfree>0 ) - { - for(i=0; i<=k-1; i++) - { - v = s->theta*s->tmp0.ptr.p_double[i]; - ae_v_addd(&s->tk1.ptr.p_double[0], 1, &s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); - } - } - - /* - * Calculate TK2 - */ - if( nfree>0 ) - { - v = ae_sqrt(s->theta, _state); - for(i=0; i<=k-1; i++) - { - ae_v_muld(&s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); - } - } - } - } - - /* - * Re-evaluate TB - */ - if( s->isactivesetchanged||s->islineartermchanged ) - { - ridx0 = 0; - ridx1 = nfree; - for(i=0; i<=n-1; i++) - { - if( s->activeset.ptr.p_bool[i] ) - { - s->tb.ptr.p_double[ridx1] = s->b.ptr.p_double[i]; - ridx1 = ridx1+1; - } - else - { - s->tb.ptr.p_double[ridx0] = s->b.ptr.p_double[i]; - ridx0 = ridx0+1; - } - } - } - - /* - * Compose ECA: either dense ECA or diagonal ECA - */ - if( (s->isactivesetchanged||s->ismaintermchanged)&&nfree>0 ) - { - if( ae_fp_greater(s->alpha,0) ) - { - - /* - * Dense ECA - */ - s->ecakind = 0; - for(i=0; i<=nfree-1; i++) - { - for(j=i; j<=nfree-1; j++) - { - s->ecadense.ptr.pp_double[i][j] = s->tq2dense.ptr.pp_double[i][j]; - } - } - if( !spdmatrixcholeskyrec(&s->ecadense, 0, nfree, ae_true, &s->tmp0, _state) ) - { - result = ae_false; - return result; - } - } - else - { - - /* - * Diagonal ECA - */ - s->ecakind = 1; - for(i=0; i<=nfree-1; i++) - { - if( ae_fp_less(s->tq2diag.ptr.p_double[i],0) ) - { - result = ae_false; - return result; - } - s->ecadiag.ptr.p_double[i] = ae_sqrt(s->tq2diag.ptr.p_double[i], _state); - } - } - } - - /* - * Compose EQ - */ - if( s->isactivesetchanged||s->issecondarytermchanged ) - { - for(i=0; i<=k-1; i++) - { - for(j=0; j<=nfree-1; j++) - { - s->eq.ptr.pp_double[i][j] = s->tk2.ptr.pp_double[i][j]; - } - } - } - - /* - * Calculate ECCM - */ - if( ((((s->isactivesetchanged||s->ismaintermchanged)||s->issecondarytermchanged)&&s->k>0)&&ae_fp_greater(s->theta,0))&&nfree>0 ) - { - - /* - * Calculate ECCM - Cholesky factor of the "effective" capacitance - * matrix CM = I + EQ*inv(EffectiveA)*EQ'. - * - * We calculate CM as follows: - * CM = I + EQ*inv(EffectiveA)*EQ' - * = I + EQ*ECA^(-1)*ECA^(-T)*EQ' - * = I + (EQ*ECA^(-1))*(EQ*ECA^(-1))' - * - * Then we perform Cholesky decomposition of CM. - */ - rmatrixsetlengthatleast(&s->tmp2, k, n, _state); - rmatrixcopy(k, nfree, &s->eq, 0, 0, &s->tmp2, 0, 0, _state); - ae_assert(s->ecakind==0||s->ecakind==1, "CQMRebuild: unexpected ECAKind", _state); - if( s->ecakind==0 ) - { - rmatrixrighttrsm(k, nfree, &s->ecadense, 0, 0, ae_true, ae_false, 0, &s->tmp2, 0, 0, _state); - } - if( s->ecakind==1 ) - { - for(i=0; i<=k-1; i++) - { - for(j=0; j<=nfree-1; j++) - { - s->tmp2.ptr.pp_double[i][j] = s->tmp2.ptr.pp_double[i][j]/s->ecadiag.ptr.p_double[j]; - } - } - } - for(i=0; i<=k-1; i++) - { - for(j=0; j<=k-1; j++) - { - s->eccm.ptr.pp_double[i][j] = 0.0; - } - s->eccm.ptr.pp_double[i][i] = 1.0; - } - rmatrixsyrk(k, nfree, 1.0, &s->tmp2, 0, 0, 0, 1.0, &s->eccm, 0, 0, ae_true, _state); - if( !spdmatrixcholeskyrec(&s->eccm, 0, k, ae_true, &s->tmp0, _state) ) - { - result = ae_false; - return result; - } - } - - /* - * Compose EB and EC - * - * NOTE: because these quantities are cheap to compute, we do not - * use caching here. - */ - for(i=0; i<=nfree-1; i++) - { - s->eb.ptr.p_double[i] = s->tq1.ptr.p_double[i]+s->tk1.ptr.p_double[i]+s->tb.ptr.p_double[i]; - } - s->ec = s->tq0+s->tk0; - for(i=nfree; i<=n-1; i++) - { - s->ec = s->ec+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; - } - - /* - * Change cache status - everything is cached - */ - s->ismaintermchanged = ae_false; - s->issecondarytermchanged = ae_false; - s->islineartermchanged = ae_false; - s->isactivesetchanged = ae_false; - return result; -} - - -/************************************************************************* -Internal function, solves system Effective_A*x = b. -It should be called after successful completion of CQMRebuild(). - -INPUT PARAMETERS: - S - quadratic model, after call to CQMRebuild() - X - right part B, array[S.NFree] - Tmp - temporary array, automatically reallocated if needed - -OUTPUT PARAMETERS: - X - solution, array[S.NFree] - -NOTE: when called with zero S.NFree, returns silently -NOTE: this function assumes that EA is non-degenerate - - -- ALGLIB -- - Copyright 10.05.2011 by Bochkanov Sergey -*************************************************************************/ -static void cqmodels_cqmsolveea(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&s->nfree==0), "CQMSolveEA: unexpected ECAKind", _state); - if( s->ecakind==0 ) - { - - /* - * Dense ECA, use FBLSCholeskySolve() dense solver. - */ - fblscholeskysolve(&s->ecadense, 1.0, s->nfree, ae_true, x, tmp, _state); - } - if( s->ecakind==1 ) - { - - /* - * Diagonal ECA - */ - for(i=0; i<=s->nfree-1; i++) - { - x->ptr.p_double[i] = x->ptr.p_double[i]/ae_sqr(s->ecadiag.ptr.p_double[i], _state); - } - } -} - - -ae_bool _convexquadraticmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - convexquadraticmodel *p = (convexquadraticmodel*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->a, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->activeset, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tq2dense, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tk2, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tq2diag, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tq1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tk1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->txc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tb, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->ecadense, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->eq, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->eccm, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ecadiag, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->eb, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _convexquadraticmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - convexquadraticmodel *dst = (convexquadraticmodel*)_dst; - convexquadraticmodel *src = (convexquadraticmodel*)_src; - dst->n = src->n; - dst->k = src->k; - dst->alpha = src->alpha; - dst->tau = src->tau; - dst->theta = src->theta; - if( !ae_matrix_init_copy(&dst->a, &src->a, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->activeset, &src->activeset, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tq2dense, &src->tq2dense, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tk2, &src->tk2, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tq2diag, &src->tq2diag, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tq1, &src->tq1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tk1, &src->tk1, _state, make_automatic) ) - return ae_false; - dst->tq0 = src->tq0; - dst->tk0 = src->tk0; - if( !ae_vector_init_copy(&dst->txc, &src->txc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tb, &src->tb, _state, make_automatic) ) - return ae_false; - dst->nfree = src->nfree; - dst->ecakind = src->ecakind; - if( !ae_matrix_init_copy(&dst->ecadense, &src->ecadense, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->eq, &src->eq, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->eccm, &src->eccm, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->ecadiag, &src->ecadiag, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->eb, &src->eb, _state, make_automatic) ) - return ae_false; - dst->ec = src->ec; - if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic) ) - return ae_false; - dst->ismaintermchanged = src->ismaintermchanged; - dst->issecondarytermchanged = src->issecondarytermchanged; - dst->islineartermchanged = src->islineartermchanged; - dst->isactivesetchanged = src->isactivesetchanged; - return ae_true; -} - - -void _convexquadraticmodel_clear(void* _p) -{ - convexquadraticmodel *p = (convexquadraticmodel*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->a); - ae_matrix_clear(&p->q); - ae_vector_clear(&p->b); - ae_vector_clear(&p->r); - ae_vector_clear(&p->xc); - ae_vector_clear(&p->d); - ae_vector_clear(&p->activeset); - ae_matrix_clear(&p->tq2dense); - ae_matrix_clear(&p->tk2); - ae_vector_clear(&p->tq2diag); - ae_vector_clear(&p->tq1); - ae_vector_clear(&p->tk1); - ae_vector_clear(&p->txc); - ae_vector_clear(&p->tb); - ae_matrix_clear(&p->ecadense); - ae_matrix_clear(&p->eq); - ae_matrix_clear(&p->eccm); - ae_vector_clear(&p->ecadiag); - ae_vector_clear(&p->eb); - ae_vector_clear(&p->tmp0); - ae_vector_clear(&p->tmp1); - ae_vector_clear(&p->tmpg); - ae_matrix_clear(&p->tmp2); -} - - -void _convexquadraticmodel_destroy(void* _p) -{ - convexquadraticmodel *p = (convexquadraticmodel*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->a); - ae_matrix_destroy(&p->q); - ae_vector_destroy(&p->b); - ae_vector_destroy(&p->r); - ae_vector_destroy(&p->xc); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->activeset); - ae_matrix_destroy(&p->tq2dense); - ae_matrix_destroy(&p->tk2); - ae_vector_destroy(&p->tq2diag); - ae_vector_destroy(&p->tq1); - ae_vector_destroy(&p->tk1); - ae_vector_destroy(&p->txc); - ae_vector_destroy(&p->tb); - ae_matrix_destroy(&p->ecadense); - ae_matrix_destroy(&p->eq); - ae_matrix_destroy(&p->eccm); - ae_vector_destroy(&p->ecadiag); - ae_vector_destroy(&p->eb); - ae_vector_destroy(&p->tmp0); - ae_vector_destroy(&p->tmp1); - ae_vector_destroy(&p->tmpg); - ae_matrix_destroy(&p->tmp2); -} - - - - -/************************************************************************* -This subroutine is used to initialize SNNLS solver. - -By default, empty NNLS problem is produced, but we allocated enough space -to store problems with NSMax+NDMax columns and NRMax rows. It is good -place to provide algorithm with initial estimate of the space requirements, -although you may underestimate problem size or even pass zero estimates - -in this case buffer variables will be resized automatically when you set -NNLS problem. - -Previously allocated buffer variables are reused as much as possible. This -function does not clear structure completely, it tries to preserve as much -dynamically allocated memory as possible. - - -- ALGLIB -- - Copyright 10.10.2012 by Bochkanov Sergey -*************************************************************************/ -void snnlsinit(ae_int_t nsmax, - ae_int_t ndmax, - ae_int_t nrmax, - snnlssolver* s, - ae_state *_state) -{ - - - s->ns = 0; - s->nd = 0; - s->nr = 0; - rmatrixsetlengthatleast(&s->densea, nrmax, ndmax, _state); - rmatrixsetlengthatleast(&s->tmpca, nrmax, ndmax, _state); - rmatrixsetlengthatleast(&s->tmpz, ndmax, ndmax, _state); - rvectorsetlengthatleast(&s->b, nrmax, _state); - bvectorsetlengthatleast(&s->nnc, nsmax+ndmax, _state); - s->debugflops = 0.0; - s->debugmaxnewton = 0; - s->refinementits = snnls_iterativerefinementits; -} - - -/************************************************************************* -This subroutine is used to set NNLS problem: - - ( [ 1 | ] [ ] [ ] )^2 - ( [ 1 | ] [ ] [ ] ) - min ( [ 1 | Ad ] * [ x ] - [ b ] ) s.t. x>=0 - ( [ | ] [ ] [ ] ) - ( [ | ] [ ] [ ] ) - -where: -* identity matrix has NS*NS size (NS<=NR, NS can be zero) -* dense matrix Ad has NR*ND size -* b is NR*1 vector -* x is (NS+ND)*1 vector -* all elements of x are non-negative (this constraint can be removed later - by calling SNNLSDropNNC() function) - -Previously allocated buffer variables are reused as much as possible. -After you set problem, you can solve it with SNNLSSolve(). - -INPUT PARAMETERS: - S - SNNLS solver, must be initialized with SNNLSInit() call - A - array[NR,ND], dense part of the system - B - array[NR], right part - NS - size of the sparse part of the system, 0<=NS<=NR - ND - size of the dense part of the system, ND>=0 - NR - rows count, NR>0 - -NOTE: - 1. You can have NS+ND=0, solver will correctly accept such combination - and return empty array as problem solution. - - -- ALGLIB -- - Copyright 10.10.2012 by Bochkanov Sergey -*************************************************************************/ -void snnlssetproblem(snnlssolver* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* b, - ae_int_t ns, - ae_int_t nd, - ae_int_t nr, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(nd>=0, "SNNLSSetProblem: ND<0", _state); - ae_assert(ns>=0, "SNNLSSetProblem: NS<0", _state); - ae_assert(nr>0, "SNNLSSetProblem: NR<=0", _state); - ae_assert(ns<=nr, "SNNLSSetProblem: NS>NR", _state); - ae_assert(a->rows>=nr||nd==0, "SNNLSSetProblem: rows(A)cols>=nd, "SNNLSSetProblem: cols(A)cnt>=nr, "SNNLSSetProblem: length(B)ns = ns; - s->nd = nd; - s->nr = nr; - if( nd>0 ) - { - rmatrixsetlengthatleast(&s->densea, nr, nd, _state); - for(i=0; i<=nr-1; i++) - { - ae_v_move(&s->densea.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,nd-1)); - } - } - rvectorsetlengthatleast(&s->b, nr, _state); - ae_v_move(&s->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nr-1)); - bvectorsetlengthatleast(&s->nnc, ns+nd, _state); - for(i=0; i<=ns+nd-1; i++) - { - s->nnc.ptr.p_bool[i] = ae_true; - } -} - - -/************************************************************************* -This subroutine drops non-negativity constraint from the problem set by -SNNLSSetProblem() call. This function must be called AFTER problem is set, -because each SetProblem() call resets constraints to their default state -(all constraints are present). - -INPUT PARAMETERS: - S - SNNLS solver, must be initialized with SNNLSInit() call, - problem must be set with SNNLSSetProblem() call. - Idx - constraint index, 0<=IDX=0, "SNNLSDropNNC: Idx<0", _state); - ae_assert(idxns+s->nd, "SNNLSDropNNC: Idx>=NS+ND", _state); - s->nnc.ptr.p_bool[idx] = ae_false; -} - - -/************************************************************************* -This subroutine is used to solve NNLS problem. - -INPUT PARAMETERS: - S - SNNLS solver, must be initialized with SNNLSInit() call and - problem must be set up with SNNLSSetProblem() call. - X - possibly preallocated buffer, automatically resized if needed - -OUTPUT PARAMETERS: - X - array[NS+ND], solution - -NOTE: - 1. You can have NS+ND=0, solver will correctly accept such combination - and return empty array as problem solution. - - 2. Internal field S.DebugFLOPS contains rough estimate of FLOPs used - to solve problem. It can be used for debugging purposes. This field - is real-valued. - - -- ALGLIB -- - Copyright 10.10.2012 by Bochkanov Sergey -*************************************************************************/ -void snnlssolve(snnlssolver* s, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t ns; - ae_int_t nd; - ae_int_t nr; - ae_int_t nsc; - ae_int_t ndc; - ae_int_t newtoncnt; - ae_bool terminationneeded; - double eps; - double fcur; - double fprev; - double fcand; - double noiselevel; - double noisetolerance; - double stplen; - double d2; - double d1; - double d0; - ae_bool wasactivation; - ae_int_t rfsits; - double lambdav; - double v0; - double v1; - double v; - - - - /* - * Prepare - */ - ns = s->ns; - nd = s->nd; - nr = s->nr; - s->debugflops = 0.0; - - /* - * Handle special cases: - * * NS+ND=0 - * * ND=0 - */ - if( ns+nd==0 ) - { - return; - } - if( nd==0 ) - { - rvectorsetlengthatleast(x, ns, _state); - for(i=0; i<=ns-1; i++) - { - x->ptr.p_double[i] = s->b.ptr.p_double[i]; - if( s->nnc.ptr.p_bool[i] ) - { - x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], 0.0, _state); - } - } - return; - } - - /* - * Main cycle of BLEIC-SNNLS algorithm. - * Below we assume that ND>0. - */ - rvectorsetlengthatleast(x, ns+nd, _state); - rvectorsetlengthatleast(&s->xn, ns+nd, _state); - rvectorsetlengthatleast(&s->g, ns+nd, _state); - rvectorsetlengthatleast(&s->d, ns+nd, _state); - rvectorsetlengthatleast(&s->r, nr, _state); - rvectorsetlengthatleast(&s->diagaa, nd, _state); - rvectorsetlengthatleast(&s->dx, ns+nd, _state); - for(i=0; i<=ns+nd-1; i++) - { - x->ptr.p_double[i] = 0.0; - } - eps = 2*ae_machineepsilon; - noisetolerance = 10.0; - lambdav = 1.0E6*ae_machineepsilon; - newtoncnt = 0; - for(;;) - { - - /* - * Phase 1: perform steepest descent step. - * - * TerminationNeeded control variable is set on exit from this loop: - * * TerminationNeeded=False in case we have to proceed to Phase 2 (Newton step) - * * TerminationNeeded=True in case we found solution (step along projected gradient is small enough) - * - * Temporaries used: - * * R (I|A)*x-b - * - * NOTE 1. It is assumed that initial point X is feasible. This feasibility - * is retained during all iterations. - */ - terminationneeded = ae_false; - for(;;) - { - - /* - * Calculate gradient G and constrained descent direction D - */ - for(i=0; i<=nr-1; i++) - { - v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); - if( iptr.p_double[i]; - } - s->r.ptr.p_double[i] = v-s->b.ptr.p_double[i]; - } - for(i=0; i<=ns-1; i++) - { - s->g.ptr.p_double[i] = s->r.ptr.p_double[i]; - } - for(i=ns; i<=ns+nd-1; i++) - { - s->g.ptr.p_double[i] = 0.0; - } - for(i=0; i<=nr-1; i++) - { - v = s->r.ptr.p_double[i]; - ae_v_addd(&s->g.ptr.p_double[ns], 1, &s->densea.ptr.pp_double[i][0], 1, ae_v_len(ns,ns+nd-1), v); - } - for(i=0; i<=ns+nd-1; i++) - { - if( (s->nnc.ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],0))&&ae_fp_greater(s->g.ptr.p_double[i],0) ) - { - s->d.ptr.p_double[i] = 0.0; - } - else - { - s->d.ptr.p_double[i] = -s->g.ptr.p_double[i]; - } - } - s->debugflops = s->debugflops+2*2*nr*nd; - - /* - * Build quadratic model of F along descent direction: - * F(x+alpha*d) = D2*alpha^2 + D1*alpha + D0 - * - * Estimate numerical noise in the X (noise level is used - * to classify step as singificant or insignificant). Noise - * comes from two sources: - * * noise when calculating rows of (I|A)*x - * * noise when calculating norm of residual - * - * In case function curvature is negative or product of descent - * direction and gradient is non-negative, iterations are terminated. - * - * NOTE: D0 is not actually used, but we prefer to maintain it. - */ - fprev = ae_v_dotproduct(&s->r.ptr.p_double[0], 1, &s->r.ptr.p_double[0], 1, ae_v_len(0,nr-1)); - fprev = fprev/2; - noiselevel = 0.0; - for(i=0; i<=nr-1; i++) - { - - /* - * Estimate noise introduced by I-th row of (I|A)*x - */ - v = 0.0; - if( iptr.p_double[i]; - } - for(j=0; j<=nd-1; j++) - { - v = ae_maxreal(v, eps*ae_fabs(s->densea.ptr.pp_double[i][j]*x->ptr.p_double[ns+j], _state), _state); - } - v = 2*ae_fabs(s->r.ptr.p_double[i]*v, _state)+v*v; - - /* - * Add to summary noise in the model - */ - noiselevel = noiselevel+v; - } - noiselevel = ae_maxreal(noiselevel, eps*fprev, _state); - d2 = 0.0; - for(i=0; i<=nr-1; i++) - { - v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &s->d.ptr.p_double[ns], 1, ae_v_len(0,nd-1)); - if( id.ptr.p_double[i]; - } - d2 = d2+0.5*ae_sqr(v, _state); - } - v = ae_v_dotproduct(&s->d.ptr.p_double[0], 1, &s->g.ptr.p_double[0], 1, ae_v_len(0,ns+nd-1)); - d1 = v; - d0 = fprev; - if( ae_fp_less_eq(d2,0)||ae_fp_greater_eq(d1,0) ) - { - terminationneeded = ae_true; - break; - } - s->debugflops = s->debugflops+2*nr*nd; - touchreal(&d0, _state); - - /* - * Perform full (unconstrained) step with length StpLen in direction D. - * - * We can terminate iterations in case one of two criteria is met: - * 1. function change is dominated by noise (or function actually increased - * instead of decreasing) - * 2. relative change in X is small enough - * - * First condition is not enough to guarantee algorithm termination because - * sometimes our noise estimate is too optimistic (say, in situations when - * function value at solition is zero). - */ - stplen = -d1/(2*d2); - ae_v_move(&s->xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,ns+nd-1)); - ae_v_addd(&s->xn.ptr.p_double[0], 1, &s->d.ptr.p_double[0], 1, ae_v_len(0,ns+nd-1), stplen); - fcand = 0.0; - for(i=0; i<=nr-1; i++) - { - v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &s->xn.ptr.p_double[ns], 1, ae_v_len(0,nd-1)); - if( ixn.ptr.p_double[i]; - } - fcand = fcand+0.5*ae_sqr(v-s->b.ptr.p_double[i], _state); - } - s->debugflops = s->debugflops+2*nr*nd; - if( ae_fp_greater_eq(fcand,fprev-noiselevel*noisetolerance) ) - { - terminationneeded = ae_true; - break; - } - v = 0; - for(i=0; i<=ns+nd-1; i++) - { - v0 = ae_fabs(x->ptr.p_double[i], _state); - v1 = ae_fabs(s->xn.ptr.p_double[i], _state); - if( ae_fp_neq(v0,0)||ae_fp_neq(v1,0) ) - { - v = ae_maxreal(v, ae_fabs(x->ptr.p_double[i]-s->xn.ptr.p_double[i], _state)/ae_maxreal(v0, v1, _state), _state); - } - } - if( ae_fp_less_eq(v,eps*noisetolerance) ) - { - terminationneeded = ae_true; - break; - } - - /* - * Perform step one more time, now with non-negativity constraints. - * - * NOTE: complicated code below which deals with VarIdx temporary makes - * sure that in case unconstrained step leads us outside of feasible - * area, we activate at least one constraint. - */ - wasactivation = snnls_boundedstepandactivation(x, &s->xn, &s->nnc, ns+nd, _state); - fcur = 0.0; - for(i=0; i<=nr-1; i++) - { - v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); - if( iptr.p_double[i]; - } - fcur = fcur+0.5*ae_sqr(v-s->b.ptr.p_double[i], _state); - } - s->debugflops = s->debugflops+2*nr*nd; - - /* - * Depending on results, decide what to do: - * 1. In case step was performed without activation of constraints, - * we proceed to Newton method - * 2. In case there was activated at least one constraint, we repeat - * steepest descent step. - */ - if( !wasactivation ) - { - - /* - * Step without activation, proceed to Newton - */ - break; - } - } - if( terminationneeded ) - { - break; - } - - /* - * Phase 2: Newton method. - */ - rvectorsetlengthatleast(&s->cx, ns+nd, _state); - ivectorsetlengthatleast(&s->columnmap, ns+nd, _state); - ivectorsetlengthatleast(&s->rowmap, nr, _state); - rmatrixsetlengthatleast(&s->tmpca, nr, nd, _state); - rmatrixsetlengthatleast(&s->tmpz, nd, nd, _state); - rvectorsetlengthatleast(&s->cborg, nr, _state); - rvectorsetlengthatleast(&s->cb, nr, _state); - terminationneeded = ae_false; - for(;;) - { - - /* - * Prepare equality constrained subproblem with NSC<=NS "sparse" - * variables and NDC<=ND "dense" variables. - * - * First, we reorder variables (columns) and move all unconstrained - * variables "to the left", ColumnMap stores this permutation. - * - * Then, we reorder first NS rows of A and first NS elements of B in - * such way that we still have identity matrix in first NSC columns - * of problem. This permutation is stored in RowMap. - */ - nsc = 0; - ndc = 0; - for(i=0; i<=ns-1; i++) - { - if( !(s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0)) ) - { - s->columnmap.ptr.p_int[nsc] = i; - nsc = nsc+1; - } - } - for(i=ns; i<=ns+nd-1; i++) - { - if( !(s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0)) ) - { - s->columnmap.ptr.p_int[nsc+ndc] = i; - ndc = ndc+1; - } - } - for(i=0; i<=nsc-1; i++) - { - s->rowmap.ptr.p_int[i] = s->columnmap.ptr.p_int[i]; - } - j = nsc; - for(i=0; i<=ns-1; i++) - { - if( s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0) ) - { - s->rowmap.ptr.p_int[j] = i; - j = j+1; - } - } - for(i=ns; i<=nr-1; i++) - { - s->rowmap.ptr.p_int[i] = i; - } - - /* - * Now, permutations are ready, and we can copy/reorder - * A, B and X to CA, CB and CX. - */ - for(i=0; i<=nsc+ndc-1; i++) - { - s->cx.ptr.p_double[i] = x->ptr.p_double[s->columnmap.ptr.p_int[i]]; - } - for(i=0; i<=nr-1; i++) - { - for(j=0; j<=ndc-1; j++) - { - s->tmpca.ptr.pp_double[i][j] = s->densea.ptr.pp_double[s->rowmap.ptr.p_int[i]][s->columnmap.ptr.p_int[nsc+j]-ns]; - } - s->cb.ptr.p_double[i] = s->b.ptr.p_double[s->rowmap.ptr.p_int[i]]; - } - - /* - * Solve equality constrained subproblem. - */ - if( ndc>0 ) - { - - /* - * NDC>0. - * - * Solve subproblem using Newton-type algorithm. We have a - * NR*(NSC+NDC) linear least squares subproblem - * - * | ( I AU ) ( XU ) ( BU ) |^2 - * min | ( ) * ( ) - ( ) | - * | ( 0 AL ) ( XL ) ( BL ) | - * - * where: - * * I is a NSC*NSC identity matrix - * * AU is NSC*NDC dense matrix (first NSC rows of CA) - * * AL is (NR-NSC)*NDC dense matrix (next NR-NSC rows of CA) - * * BU and BL are correspondingly sized parts of CB - * - * After conversion to normal equations and small regularization, - * we get: - * - * ( I AU ) ( XU ) ( BU ) - * ( )*( ) = ( ) - * ( AU' Y ) ( XL ) ( AU'*BU+AL'*BL ) - * - * where Y = AU'*AU + AL'*AL + lambda*diag(AU'*AU+AL'*AL). - * - * With Schur Complement Method this system can be solved in - * O(NR*NDC^2+NDC^3) operations. In order to solve it we multiply - * first row by AU' and subtract it from the second one. As result, - * we get system - * - * Z*XL = AL'*BL, where Z=AL'*AL+lambda*diag(AU'*AU+AL'*AL) - * - * We can easily solve it for XL, and we can get XU as XU = BU-AU*XL. - * - * We will start solution from calculating Cholesky decomposition of Z. - */ - for(i=0; i<=nr-1; i++) - { - s->cborg.ptr.p_double[i] = s->cb.ptr.p_double[i]; - } - for(i=0; i<=ndc-1; i++) - { - s->diagaa.ptr.p_double[i] = 0; - } - for(i=0; i<=nr-1; i++) - { - for(j=0; j<=ndc-1; j++) - { - s->diagaa.ptr.p_double[j] = s->diagaa.ptr.p_double[j]+ae_sqr(s->tmpca.ptr.pp_double[i][j], _state); - } - } - for(j=0; j<=ndc-1; j++) - { - if( ae_fp_eq(s->diagaa.ptr.p_double[j],0) ) - { - s->diagaa.ptr.p_double[j] = 1; - } - } - for(;;) - { - - /* - * NOTE: we try to factorize Z. In case of failure we increase - * regularization parameter and try again. - */ - s->debugflops = s->debugflops+2*(nr-nsc)*ae_sqr(ndc, _state)+ae_pow(ndc, 3, _state)/3; - for(i=0; i<=ndc-1; i++) - { - for(j=0; j<=ndc-1; j++) - { - s->tmpz.ptr.pp_double[i][j] = 0.0; - } - } - rmatrixsyrk(ndc, nr-nsc, 1.0, &s->tmpca, nsc, 0, 2, 0.0, &s->tmpz, 0, 0, ae_true, _state); - for(i=0; i<=ndc-1; i++) - { - s->tmpz.ptr.pp_double[i][i] = s->tmpz.ptr.pp_double[i][i]+lambdav*s->diagaa.ptr.p_double[i]; - } - if( spdmatrixcholeskyrec(&s->tmpz, 0, ndc, ae_true, &s->tmpcholesky, _state) ) - { - break; - } - lambdav = lambdav*10; - } - - /* - * We have Cholesky decomposition of Z, now we can solve system: - * * we start from initial point CX - * * we perform several iterations of refinement: - * * BU_new := BU_orig - XU_cur - AU*XL_cur - * * BL_new := BL_orig - AL*XL_cur - * * solve for BU_new/BL_new, obtain solution dx - * * XU_cur := XU_cur + dx_u - * * XL_cur := XL_cur + dx_l - * * BU_new/BL_new are stored in CB, original right part is - * stored in CBOrg, correction to X is stored in DX, current - * X is stored in CX - */ - for(rfsits=1; rfsits<=s->refinementits; rfsits++) - { - for(i=0; i<=nr-1; i++) - { - v = ae_v_dotproduct(&s->tmpca.ptr.pp_double[i][0], 1, &s->cx.ptr.p_double[nsc], 1, ae_v_len(0,ndc-1)); - s->cb.ptr.p_double[i] = s->cborg.ptr.p_double[i]-v; - if( icb.ptr.p_double[i] = s->cb.ptr.p_double[i]-s->cx.ptr.p_double[i]; - } - } - s->debugflops = s->debugflops+2*nr*ndc; - for(i=0; i<=ndc-1; i++) - { - s->dx.ptr.p_double[i] = 0.0; - } - for(i=nsc; i<=nr-1; i++) - { - v = s->cb.ptr.p_double[i]; - ae_v_addd(&s->dx.ptr.p_double[0], 1, &s->tmpca.ptr.pp_double[i][0], 1, ae_v_len(0,ndc-1), v); - } - fblscholeskysolve(&s->tmpz, 1.0, ndc, ae_true, &s->dx, &s->tmpcholesky, _state); - s->debugflops = s->debugflops+2*ndc*ndc; - ae_v_add(&s->cx.ptr.p_double[nsc], 1, &s->dx.ptr.p_double[0], 1, ae_v_len(nsc,nsc+ndc-1)); - for(i=0; i<=nsc-1; i++) - { - v = ae_v_dotproduct(&s->tmpca.ptr.pp_double[i][0], 1, &s->dx.ptr.p_double[0], 1, ae_v_len(0,ndc-1)); - s->cx.ptr.p_double[i] = s->cx.ptr.p_double[i]+s->cb.ptr.p_double[i]-v; - } - s->debugflops = s->debugflops+2*nsc*ndc; - } - } - else - { - - /* - * NDC=0. - * - * We have a NR*NSC linear least squares subproblem - * - * min |XU-BU|^2 - * - * solution is easy to find - it is XU=BU! - */ - for(i=0; i<=nsc-1; i++) - { - s->cx.ptr.p_double[i] = s->cb.ptr.p_double[i]; - } - } - for(i=0; i<=ns+nd-1; i++) - { - s->xn.ptr.p_double[i] = x->ptr.p_double[i]; - } - for(i=0; i<=nsc+ndc-1; i++) - { - s->xn.ptr.p_double[s->columnmap.ptr.p_int[i]] = s->cx.ptr.p_double[i]; - } - newtoncnt = newtoncnt+1; - - /* - * Step to candidate point. - * If no constraints was added, accept candidate point XN and move to next phase. - * Terminate, if number of Newton iterations exceeded DebugMaxNewton counter. - */ - terminationneeded = s->debugmaxnewton>0&&newtoncnt>=s->debugmaxnewton; - if( !snnls_boundedstepandactivation(x, &s->xn, &s->nnc, ns+nd, _state) ) - { - break; - } - if( terminationneeded ) - { - break; - } - } - if( terminationneeded ) - { - break; - } - } -} - - -/************************************************************************* -Having feasible current point XC and possibly infeasible candidate point -XN, this function performs longest step from XC to XN which retains -feasibility. In case XN is found to be infeasible, at least one constraint -is activated. - -For example, if we have: - XC=0.5 - XN=-1.2 - x>=0 -then this function will move us to X=0 and activate constraint "x>=0". - -INPUT PARAMETERS: - XC - current point, must be feasible with respect to - all constraints - XN - candidate point, can be infeasible with respect to some - constraints - NNC - NNC[i] is True when I-th variable is non-negatively - constrained - N - variable count - -OUTPUT PARAMETERS: - XC - new position - -RESULT: - True in case at least one constraint was activated by step - - -- ALGLIB -- - Copyright 19.10.2012 by Bochkanov Sergey -*************************************************************************/ -static ae_bool snnls_boundedstepandactivation(/* Real */ ae_vector* xc, - /* Real */ ae_vector* xn, - /* Boolean */ ae_vector* nnc, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - ae_int_t varidx; - double vmax; - double v; - double stplen; - ae_bool result; - - - - /* - * Check constraints. - * - * NOTE: it is important to test for XN[i]ptr.p_bool[i]&&ae_fp_less(xn->ptr.p_double[i],xc->ptr.p_double[i]))&&ae_fp_less_eq(xn->ptr.p_double[i],0.0) ) - { - v = vmax; - vmax = safeminposrv(xc->ptr.p_double[i], xc->ptr.p_double[i]-xn->ptr.p_double[i], vmax, _state); - if( ae_fp_less(vmax,v) ) - { - varidx = i; - } - } - } - stplen = ae_minreal(vmax, 1.0, _state); - - /* - * Perform step with activation. - * - * NOTE: it is important to use (1-StpLen)*XC + StpLen*XN because - * it allows us to step exactly to XN when StpLen=1, even in - * the presence of numerical errors. - */ - for(i=0; i<=n-1; i++) - { - xc->ptr.p_double[i] = (1-stplen)*xc->ptr.p_double[i]+stplen*xn->ptr.p_double[i]; - } - if( varidx>=0 ) - { - xc->ptr.p_double[varidx] = 0.0; - result = ae_true; - } - for(i=0; i<=n-1; i++) - { - if( nnc->ptr.p_bool[i]&&ae_fp_less(xc->ptr.p_double[i],0.0) ) - { - xc->ptr.p_double[i] = 0.0; - result = ae_true; - } - } - return result; -} - - -ae_bool _snnlssolver_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - snnlssolver *p = (snnlssolver*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->nnc, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpz, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpca, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->diagaa, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cb, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cborg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->columnmap, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rowmap, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpcholesky, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _snnlssolver_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - snnlssolver *dst = (snnlssolver*)_dst; - snnlssolver *src = (snnlssolver*)_src; - dst->ns = src->ns; - dst->nd = src->nd; - dst->nr = src->nr; - if( !ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->nnc, &src->nnc, _state, make_automatic) ) - return ae_false; - dst->refinementits = src->refinementits; - dst->debugflops = src->debugflops; - dst->debugmaxnewton = src->debugmaxnewton; - if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpz, &src->tmpz, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpca, &src->tmpca, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dx, &src->dx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->diagaa, &src->diagaa, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cb, &src->cb, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cborg, &src->cborg, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->columnmap, &src->columnmap, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rowmap, &src->rowmap, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpcholesky, &src->tmpcholesky, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _snnlssolver_clear(void* _p) -{ - snnlssolver *p = (snnlssolver*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->densea); - ae_vector_clear(&p->b); - ae_vector_clear(&p->nnc); - ae_vector_clear(&p->xn); - ae_matrix_clear(&p->tmpz); - ae_matrix_clear(&p->tmpca); - ae_vector_clear(&p->g); - ae_vector_clear(&p->d); - ae_vector_clear(&p->dx); - ae_vector_clear(&p->diagaa); - ae_vector_clear(&p->cb); - ae_vector_clear(&p->cx); - ae_vector_clear(&p->cborg); - ae_vector_clear(&p->columnmap); - ae_vector_clear(&p->rowmap); - ae_vector_clear(&p->tmpcholesky); - ae_vector_clear(&p->r); -} - - -void _snnlssolver_destroy(void* _p) -{ - snnlssolver *p = (snnlssolver*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->densea); - ae_vector_destroy(&p->b); - ae_vector_destroy(&p->nnc); - ae_vector_destroy(&p->xn); - ae_matrix_destroy(&p->tmpz); - ae_matrix_destroy(&p->tmpca); - ae_vector_destroy(&p->g); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->dx); - ae_vector_destroy(&p->diagaa); - ae_vector_destroy(&p->cb); - ae_vector_destroy(&p->cx); - ae_vector_destroy(&p->cborg); - ae_vector_destroy(&p->columnmap); - ae_vector_destroy(&p->rowmap); - ae_vector_destroy(&p->tmpcholesky); - ae_vector_destroy(&p->r); -} - - - - -/************************************************************************* -This subroutine is used to initialize active set. By default, empty -N-variable model with no constraints is generated. Previously allocated -buffer variables are reused as much as possible. - -Two use cases for this object are described below. - -CASE 1 - STEEPEST DESCENT: - - SASInit() - repeat: - SASReactivateConstraints() - SASDescentDirection() - SASExploreDirection() - SASMoveTo() - until convergence - -CASE 1 - PRECONDITIONED STEEPEST DESCENT: - - SASInit() - repeat: - SASReactivateConstraintsPrec() - SASDescentDirectionPrec() - SASExploreDirection() - SASMoveTo() - until convergence - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasinit(ae_int_t n, sactiveset* s, ae_state *_state) -{ - ae_int_t i; - - - s->n = n; - s->algostate = 0; - - /* - * Constraints - */ - s->constraintschanged = ae_true; - s->nec = 0; - s->nic = 0; - rvectorsetlengthatleast(&s->bndl, n, _state); - bvectorsetlengthatleast(&s->hasbndl, n, _state); - rvectorsetlengthatleast(&s->bndu, n, _state); - bvectorsetlengthatleast(&s->hasbndu, n, _state); - for(i=0; i<=n-1; i++) - { - s->bndl.ptr.p_double[i] = _state->v_neginf; - s->bndu.ptr.p_double[i] = _state->v_posinf; - s->hasbndl.ptr.p_bool[i] = ae_false; - s->hasbndu.ptr.p_bool[i] = ae_false; - } - - /* - * current point, scale - */ - s->hasxc = ae_false; - rvectorsetlengthatleast(&s->xc, n, _state); - rvectorsetlengthatleast(&s->s, n, _state); - rvectorsetlengthatleast(&s->h, n, _state); - for(i=0; i<=n-1; i++) - { - s->xc.ptr.p_double[i] = 0.0; - s->s.ptr.p_double[i] = 1.0; - s->h.ptr.p_double[i] = 1.0; - } - - /* - * Other - */ - rvectorsetlengthatleast(&s->unitdiagonal, n, _state); - for(i=0; i<=n-1; i++) - { - s->unitdiagonal.ptr.p_double[i] = 1.0; - } -} - - -/************************************************************************* -This function sets scaling coefficients for SAS object. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -During orthogonalization phase, scale is used to calculate drop tolerances -(whether vector is significantly non-zero or not). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sassetscale(sactiveset* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(state->algostate==0, "SASSetScale: you may change scale only in modification mode", _state); - ae_assert(s->cnt>=state->n, "SASSetScale: Length(S)n-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "SASSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "SASSetScale: S contains zero elements", _state); - } - for(i=0; i<=state->n-1; i++) - { - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE 1: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sassetprecdiag(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(state->algostate==0, "SASSetPrecDiag: you may change preconditioner only in modification mode", _state); - ae_assert(d->cnt>=state->n, "SASSetPrecDiag: D is too short", _state); - for(i=0; i<=state->n-1; i++) - { - ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "SASSetPrecDiag: D contains infinite or NAN elements", _state); - ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "SASSetPrecDiag: D contains non-positive elements", _state); - } - for(i=0; i<=state->n-1; i++) - { - state->h.ptr.p_double[i] = d->ptr.p_double[i]; - } -} - - -/************************************************************************* -This function sets/changes boundary constraints. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF. - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF. - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sassetbc(sactiveset* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - - - ae_assert(state->algostate==0, "SASSetBC: you may change constraints only in modification mode", _state); - n = state->n; - ae_assert(bndl->cnt>=n, "SASSetBC: Length(BndL)cnt>=n, "SASSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or -INF", _state); - state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; - state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); - state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; - state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); - } - state->constraintschanged = ae_true; -} - - -/************************************************************************* -This function sets linear constraints for SAS object. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - SAS structure - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0 - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void sassetlc(sactiveset* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - - - ae_assert(state->algostate==0, "SASSetLC: you may change constraints only in modification mode", _state); - n = state->n; - - /* - * First, check for errors in the inputs - */ - ae_assert(k>=0, "SASSetLC: K<0", _state); - ae_assert(c->cols>=n+1||k==0, "SASSetLC: Cols(C)rows>=k, "SASSetLC: Rows(C)cnt>=k, "SASSetLC: Length(CT)nec = 0; - state->nic = 0; - state->constraintschanged = ae_true; - return; - } - - /* - * Equality constraints are stored first, in the upper - * NEC rows of State.CLEIC matrix. Inequality constraints - * are stored in the next NIC rows. - * - * NOTE: we convert inequality constraints to the form - * A*x<=b before copying them. - */ - rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); - state->nec = 0; - state->nic = 0; - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]==0 ) - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - state->nec = state->nec+1; - } - } - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]!=0 ) - { - if( ct->ptr.p_int[i]>0 ) - { - ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - else - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - state->nic = state->nic+1; - } - } - - /* - * Mark state as changed - */ - state->constraintschanged = ae_true; -} - - -/************************************************************************* -Another variation of SASSetLC(), which accepts linear constraints using -another representation. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - SAS structure - CLEIC - linear constraints, array[NEC+NIC,N+1]. - Each row of C represents one constraint: - * first N elements correspond to coefficients, - * last element corresponds to the right part. - First NEC rows store equality constraints, next NIC - are - inequality ones. - All elements of C (including right part) must be finite. - NEC - number of equality constraints, NEC>=0 - NIC - number of inequality constraints, NIC>=0 - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void sassetlcx(sactiveset* state, - /* Real */ ae_matrix* cleic, - ae_int_t nec, - ae_int_t nic, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - - - ae_assert(state->algostate==0, "SASSetLCX: you may change constraints only in modification mode", _state); - n = state->n; - - /* - * First, check for errors in the inputs - */ - ae_assert(nec>=0, "SASSetLCX: NEC<0", _state); - ae_assert(nic>=0, "SASSetLCX: NIC<0", _state); - ae_assert(cleic->cols>=n+1||nec+nic==0, "SASSetLCX: Cols(CLEIC)rows>=nec+nic, "SASSetLCX: Rows(CLEIC)cleic, nec+nic, n+1, _state); - state->nec = nec; - state->nic = nic; - for(i=0; i<=nec+nic-1; i++) - { - for(j=0; j<=n; j++) - { - state->cleic.ptr.pp_double[i][j] = cleic->ptr.pp_double[i][j]; - } - } - - /* - * Mark state as changed - */ - state->constraintschanged = ae_true; -} - - -/************************************************************************* -This subroutine turns on optimization mode: -1. feasibility in X is enforced (in case X=S.XC and constraints have not - changed, algorithm just uses X without any modifications at all) -2. constraints are marked as "candidate" or "inactive" - -INPUT PARAMETERS: - S - active set object - X - initial point (candidate), array[N]. It is expected that X - contains only finite values (we do not check it). - -OUTPUT PARAMETERS: - S - state is changed - X - initial point can be changed to enforce feasibility - -RESULT: - True in case feasible point was found (mode was changed to "optimization") - False in case no feasible point was found (mode was not changed) - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -ae_bool sasstartoptimization(sactiveset* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - ae_int_t i; - ae_int_t j; - double v; - ae_bool result; - - - ae_assert(state->algostate==0, "SASStartOptimization: already in optimization mode", _state); - result = ae_false; - n = state->n; - nec = state->nec; - nic = state->nic; - - /* - * Enforce feasibility and calculate set of "candidate"/"active" constraints. - * Always active equality constraints are marked as "active", all other constraints - * are marked as "candidate". - */ - ivectorsetlengthatleast(&state->activeset, n+nec+nic, _state); - for(i=0; i<=n-1; i++) - { - if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) - { - if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - return result; - } - } - } - ae_v_move(&state->xc.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( state->nec+state->nic>0 ) - { - - /* - * General linear constraints are present; general code is used. - */ - rvectorsetlengthatleast(&state->tmp0, n, _state); - rvectorsetlengthatleast(&state->tmpfeas, n+state->nic, _state); - rmatrixsetlengthatleast(&state->tmpm0, state->nec+state->nic, n+state->nic+1, _state); - for(i=0; i<=state->nec+state->nic-1; i++) - { - ae_v_move(&state->tmpm0.ptr.pp_double[i][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - for(j=n; j<=n+state->nic-1; j++) - { - state->tmpm0.ptr.pp_double[i][j] = 0; - } - if( i>=state->nec ) - { - state->tmpm0.ptr.pp_double[i][n+i-state->nec] = 1.0; - } - state->tmpm0.ptr.pp_double[i][n+state->nic] = state->cleic.ptr.pp_double[i][n]; - } - ae_v_move(&state->tmpfeas.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=state->nic-1; i++) - { - v = ae_v_dotproduct(&state->cleic.ptr.pp_double[i+state->nec][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->tmpfeas.ptr.p_double[i+n] = ae_maxreal(state->cleic.ptr.pp_double[i+state->nec][n]-v, 0.0, _state); - } - if( !findfeasiblepoint(&state->tmpfeas, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, state->nic, &state->tmpm0, state->nec+state->nic, 1.0E-6, &i, &j, _state) ) - { - return result; - } - ae_v_move(&state->xc.ptr.p_double[0], 1, &state->tmpfeas.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))||(state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i])) ) - { - state->activeset.ptr.p_int[i] = 0; - continue; - } - state->activeset.ptr.p_int[i] = -1; - } - for(i=0; i<=state->nec-1; i++) - { - state->activeset.ptr.p_int[n+i] = 1; - } - for(i=0; i<=state->nic-1; i++) - { - if( ae_fp_eq(state->tmpfeas.ptr.p_double[n+i],0) ) - { - state->activeset.ptr.p_int[n+state->nec+i] = 0; - } - else - { - state->activeset.ptr.p_int[n+state->nec+i] = -1; - } - } - } - else - { - - /* - * Only bound constraints are present, quick code can be used - */ - for(i=0; i<=n-1; i++) - { - state->activeset.ptr.p_int[i] = -1; - if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->activeset.ptr.p_int[i] = 1; - state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - continue; - } - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) - { - state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - state->activeset.ptr.p_int[i] = 0; - continue; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; - state->activeset.ptr.p_int[i] = 0; - continue; - } - } - } - - /* - * Change state, allocate temporaries - */ - result = ae_true; - state->algostate = 1; - state->basisisready = ae_false; - state->hasxc = ae_true; - rmatrixsetlengthatleast(&state->pbasis, ae_minint(nec+nic, n, _state), n+1, _state); - rmatrixsetlengthatleast(&state->ibasis, ae_minint(nec+nic, n, _state), n+1, _state); - rmatrixsetlengthatleast(&state->sbasis, ae_minint(nec+nic, n, _state), n+1, _state); - return result; -} - - -/************************************************************************* -This function explores search direction and calculates bound for step as -well as information for activation of constraints. - -INPUT PARAMETERS: - State - SAS structure which stores current point and all other - active set related information - D - descent direction to explore - -OUTPUT PARAMETERS: - StpMax - upper limit on step length imposed by yet inactive - constraints. Can be zero in case some constraints - can be activated by zero step. Equal to some large - value in case step is unlimited. - CIdx - -1 for unlimited step, in [0,N+NEC+NIC) in case of - limited step. - VVal - value which is assigned to X[CIdx] during activation. - For CIdx<0 or CIdx>=N some dummy value is assigned to - this parameter. -*************************************************************************/ -void sasexploredirection(sactiveset* state, - /* Real */ ae_vector* d, - double* stpmax, - ae_int_t* cidx, - double* vval, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - ae_int_t i; - double prevmax; - double vc; - double vd; - - *stpmax = 0; - *cidx = 0; - *vval = 0; - - ae_assert(state->algostate==1, "SASExploreDirection: is not in optimization mode", _state); - n = state->n; - nec = state->nec; - nic = state->nic; - *cidx = -1; - *vval = 0; - *stpmax = 1.0E50; - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]<=0 ) - { - ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); - ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(d->ptr.p_double[i],0) ) - { - prevmax = *stpmax; - *stpmax = safeminposrv(state->xc.ptr.p_double[i]-state->bndl.ptr.p_double[i], -d->ptr.p_double[i], *stpmax, _state); - if( ae_fp_less(*stpmax,prevmax) ) - { - *cidx = i; - *vval = state->bndl.ptr.p_double[i]; - } - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(d->ptr.p_double[i],0) ) - { - prevmax = *stpmax; - *stpmax = safeminposrv(state->bndu.ptr.p_double[i]-state->xc.ptr.p_double[i], d->ptr.p_double[i], *stpmax, _state); - if( ae_fp_less(*stpmax,prevmax) ) - { - *cidx = i; - *vval = state->bndu.ptr.p_double[i]; - } - } - } - } - for(i=nec; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]<=0 ) - { - vc = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - vc = vc-state->cleic.ptr.pp_double[i][n]; - vd = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_less_eq(vd,0) ) - { - continue; - } - if( ae_fp_less(vc,0) ) - { - - /* - * XC is strictly feasible with respect to I-th constraint, - * we can perform non-zero step because there is non-zero distance - * between XC and bound. - */ - prevmax = *stpmax; - *stpmax = safeminposrv(-vc, vd, *stpmax, _state); - if( ae_fp_less(*stpmax,prevmax) ) - { - *cidx = n+i; - } - } - else - { - - /* - * XC is at the boundary (or slightly beyond it), and step vector - * points beyond the boundary. - * - * The only thing we can do is to perform zero step and activate - * I-th constraint. - */ - *stpmax = 0; - *cidx = n+i; - } - } - } -} - - -/************************************************************************* -This subroutine moves current point to XN, in the direction previously -explored with SASExploreDirection() function. - -Step may activate one constraint. It is assumed than XN is approximately -feasible (small error as large as several ulps is possible). Strict -feasibility with respect to bound constraints is enforced during -activation, feasibility with respect to general linear constraints is not -enforced. - -INPUT PARAMETERS: - S - active set object - XN - new point. - NeedAct - True in case one constraint needs activation - CIdx - index of constraint, in [0,N+NEC+NIC). - Ignored if NeedAct is false. - This value is calculated by SASExploreDirection(). - CVal - for CIdx in [0,N) this field stores value which is - assigned to XC[CIdx] during activation. CVal is ignored in - other cases. - This value is calculated by SASExploreDirection(). - -OUTPUT PARAMETERS: - S - current point and list of active constraints are changed. - -RESULT: - >0, in case at least one inactive non-candidate constraint was activated - =0, in case only "candidate" constraints were activated - <0, in case no constraints were activated by the step - -NOTE: in general case State.XC<>XN because activation of constraints may - slightly change current point (to enforce feasibility). - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -ae_int_t sasmoveto(sactiveset* state, - /* Real */ ae_vector* xn, - ae_bool needact, - ae_int_t cidx, - double cval, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - ae_int_t i; - ae_bool wasactivation; - ae_int_t result; - - - ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); - n = state->n; - nec = state->nec; - nic = state->nic; - - /* - * Save previous state, update current point - */ - rvectorsetlengthatleast(&state->mtx, n, _state); - ivectorsetlengthatleast(&state->mtas, n+nec+nic, _state); - for(i=0; i<=n-1; i++) - { - state->mtx.ptr.p_double[i] = state->xc.ptr.p_double[i]; - state->xc.ptr.p_double[i] = xn->ptr.p_double[i]; - } - for(i=0; i<=n+nec+nic-1; i++) - { - state->mtas.ptr.p_int[i] = state->activeset.ptr.p_int[i]; - } - - /* - * Activate constraints - */ - wasactivation = ae_false; - if( needact ) - { - - /* - * Activation - */ - ae_assert(cidx>=0&&cidxxc.ptr.p_double[cidx] = cval; - } - state->activeset.ptr.p_int[cidx] = 1; - wasactivation = ae_true; - } - for(i=0; i<=n-1; i++) - { - - /* - * Post-check (some constraints may be activated because of numerical errors) - */ - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) - { - state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - state->activeset.ptr.p_int[i] = 1; - wasactivation = ae_true; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; - state->activeset.ptr.p_int[i] = 1; - wasactivation = ae_true; - } - } - - /* - * Determine return status: - * * -1 in case no constraints were activated - * * 0 in case only "candidate" constraints were activated - * * +1 in case at least one "non-candidate" constraint was activated - */ - if( wasactivation ) - { - - /* - * Step activated one/several constraints, but sometimes it is spurious - * activation - RecalculateConstraints() tells us that constraint is - * inactive (negative Largrange multiplier), but step activates it - * because of numerical noise. - * - * This block of code checks whether step activated truly new constraints - * (ones which were not in the active set at the solution): - * - * * for non-boundary constraint it is enough to check that previous value - * of ActiveSet[i] is negative (=far from boundary), and new one is - * positive (=we are at the boundary, constraint is activated). - * - * * for boundary constraints previous criterion won't work. Each variable - * has two constraints, and simply checking their status is not enough - - * we have to correctly identify cases when we leave one boundary - * (PrevActiveSet[i]=0) and move to another boundary (ActiveSet[i]>0). - * Such cases can be identified if we compare previous X with new X. - * - * In case only "candidate" constraints were activated, result variable - * is set to 0. In case at least one new constraint was activated, result - * is set to 1. - */ - result = 0; - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>0&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) - { - result = 1; - } - } - for(i=n; i<=n+state->nec+state->nic-1; i++) - { - if( state->mtas.ptr.p_int[i]<0&&state->activeset.ptr.p_int[i]>0 ) - { - result = 1; - } - } - } - else - { - - /* - * No activation, return -1 - */ - result = -1; - } - - /* - * Invalidate basis - */ - state->basisisready = ae_false; - return result; -} - - -/************************************************************************* -This subroutine performs immediate activation of one constraint: -* "immediate" means that we do not have to move to activate it -* in case boundary constraint is activated, we enforce current point to be - exactly at the boundary - -INPUT PARAMETERS: - S - active set object - CIdx - index of constraint, in [0,N+NEC+NIC). - This value is calculated by SASExploreDirection(). - CVal - for CIdx in [0,N) this field stores value which is - assigned to XC[CIdx] during activation. CVal is ignored in - other cases. - This value is calculated by SASExploreDirection(). - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasimmediateactivation(sactiveset* state, - ae_int_t cidx, - double cval, - ae_state *_state) -{ - - - ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); - if( cidxn ) - { - state->xc.ptr.p_double[cidx] = cval; - } - state->activeset.ptr.p_int[cidx] = 1; - state->basisisready = ae_false; -} - - -/************************************************************************* -This subroutine calculates descent direction subject to current active set. - -INPUT PARAMETERS: - S - active set object - G - array[N], gradient - D - possibly prealocated buffer; - automatically resized if needed. - -OUTPUT PARAMETERS: - D - descent direction projected onto current active set. - Components of D which correspond to active boundary - constraints are forced to be exactly zero. - In case D is non-zero, it is normalized to have unit norm. - -NOTE: in case active set has N active constraints (or more), descent - direction is forced to be exactly zero. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasconstraineddescent(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* d, - ae_state *_state) -{ - - - ae_assert(state->algostate==1, "SASConstrainedDescent: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - sactivesets_constraineddescent(state, g, &state->unitdiagonal, &state->ibasis, ae_true, d, _state); -} - - -/************************************************************************* -This subroutine calculates preconditioned descent direction subject to -current active set. - -INPUT PARAMETERS: - S - active set object - G - array[N], gradient - D - possibly prealocated buffer; - automatically resized if needed. - -OUTPUT PARAMETERS: - D - descent direction projected onto current active set. - Components of D which correspond to active boundary - constraints are forced to be exactly zero. - In case D is non-zero, it is normalized to have unit norm. - -NOTE: in case active set has N active constraints (or more), descent - direction is forced to be exactly zero. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasconstraineddescentprec(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* d, - ae_state *_state) -{ - - - ae_assert(state->algostate==1, "SASConstrainedDescentPrec: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - sactivesets_constraineddescent(state, g, &state->h, &state->pbasis, ae_true, d, _state); -} - - -/************************************************************************* -This subroutine calculates product of direction vector and preconditioner -multiplied subject to current active set. - -INPUT PARAMETERS: - S - active set object - D - array[N], direction - -OUTPUT PARAMETERS: - D - preconditioned direction projected onto current active set. - Components of D which correspond to active boundary - constraints are forced to be exactly zero. - -NOTE: in case active set has N active constraints (or more), descent - direction is forced to be exactly zero. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasconstraineddirection(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - sactivesets_constraineddescent(state, d, &state->unitdiagonal, &state->ibasis, ae_false, &state->cdtmp, _state); - for(i=0; i<=state->n-1; i++) - { - d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; - } -} - - -/************************************************************************* -This subroutine calculates product of direction vector and preconditioner -multiplied subject to current active set. - -INPUT PARAMETERS: - S - active set object - D - array[N], direction - -OUTPUT PARAMETERS: - D - preconditioned direction projected onto current active set. - Components of D which correspond to active boundary - constraints are forced to be exactly zero. - -NOTE: in case active set has N active constraints (or more), descent - direction is forced to be exactly zero. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasconstraineddirectionprec(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - sactivesets_constraineddescent(state, d, &state->h, &state->pbasis, ae_false, &state->cdtmp, _state); - for(i=0; i<=state->n-1; i++) - { - d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; - } -} - - -/************************************************************************* -This subroutine performs correction of some (possibly infeasible) point -with respect to a) current active set, b) all boundary constraints, both -active and inactive: - -0) we calculate L1 penalty term for violation of active linear constraints - (one which is returned by SASActiveLCPenalty1() function). -1) first, it performs projection (orthogonal with respect to scale matrix - S) of X into current active set: X -> X1. -2) next, we perform projection with respect to ALL boundary constraints - which are violated at X1: X1 -> X2. -3) X is replaced by X2. - -The idea is that this function can preserve and enforce feasibility during -optimization, and additional penalty parameter can be used to prevent algo -from leaving feasible set because of rounding errors. - -INPUT PARAMETERS: - S - active set object - X - array[N], candidate point - -OUTPUT PARAMETERS: - X - "improved" candidate point: - a) feasible with respect to all boundary constraints - b) feasibility with respect to active set is retained at - good level. - Penalty - penalty term, which can be added to function value if user - wants to penalize violation of constraints (recommended). - -NOTE: this function is not intended to find exact projection (i.e. best - approximation) of X into feasible set. It just improves situation a - bit. - Regular use of this function will help you to retain feasibility - - if you already have something to start with and constrain your - steps is such way that the only source of infeasibility are roundoff - errors. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sascorrection(sactiveset* state, - /* Real */ ae_vector* x, - double* penalty, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - double v; - - *penalty = 0; - - ae_assert(state->algostate==1, "SASCorrection: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - n = state->n; - rvectorsetlengthatleast(&state->corrtmp, n, _state); - - /* - * Calculate penalty term. - */ - *penalty = sasactivelcpenalty1(state, x, _state); - - /* - * Perform projection 1. - * - * This projecton is given by: - * - * x_proj = x - S*S*As'*(As*x-b) - * - * where x is original x before projection, S is a scale matrix, - * As is a matrix of equality constraints (active set) which were - * orthogonalized with respect to inner product given by S (i.e. we - * have As*S*S'*As'=I), b is a right part of the orthogonalized - * constraints. - * - * NOTE: you can verify that x_proj is strictly feasible w.r.t. - * active set by multiplying it by As - you will get - * As*x_proj = As*x - As*x + b = b. - * - * This formula for projection can be obtained by solving - * following minimization problem. - * - * min ||inv(S)*(x_proj-x)||^2 s.t. As*x_proj=b - * - */ - ae_v_move(&state->corrtmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=state->basissize-1; i++) - { - v = -state->sbasis.ptr.pp_double[i][n]; - for(j=0; j<=n-1; j++) - { - v = v+state->sbasis.ptr.pp_double[i][j]*state->corrtmp.ptr.p_double[j]; - } - for(j=0; j<=n-1; j++) - { - state->corrtmp.ptr.p_double[j] = state->corrtmp.ptr.p_double[j]-v*state->sbasis.ptr.pp_double[i][j]*ae_sqr(state->s.ptr.p_double[j], _state); - } - } - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>0 ) - { - state->corrtmp.ptr.p_double[i] = state->xc.ptr.p_double[i]; - } - } - - /* - * Perform projection 2 - */ - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = state->corrtmp.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) - { - x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; - } - } -} - - -/************************************************************************* -This subroutine returns L1 penalty for violation of active general linear -constraints (violation of boundary or inactive linear constraints is not -added to penalty). - -Penalty term is equal to: - - Penalty = SUM( Abs((C_i*x-R_i)/Alpha_i) ) - -Here: -* summation is performed for I=0...NEC+NIC-1, ActiveSet[N+I]>0 - (only for rows of CLEIC which are in active set) -* C_i is I-th row of CLEIC -* R_i is corresponding right part -* S is a scale matrix -* Alpha_i = ||S*C_i|| - is a scaling coefficient which "normalizes" - I-th summation term according to its scale. - -INPUT PARAMETERS: - S - active set object - X - array[N], candidate point - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -double sasactivelcpenalty1(sactiveset* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - double v; - double alpha; - double p; - double result; - - - ae_assert(state->algostate==1, "SASActiveLCPenalty1: is not in optimization mode", _state); - sasrebuildbasis(state, _state); - n = state->n; - nec = state->nec; - nic = state->nic; - - /* - * Calculate penalty term. - */ - result = 0; - for(i=0; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]>0 ) - { - alpha = 0; - p = -state->cleic.ptr.pp_double[i][n]; - for(j=0; j<=n-1; j++) - { - v = state->cleic.ptr.pp_double[i][j]; - p = p+v*x->ptr.p_double[j]; - alpha = alpha+ae_sqr(v*state->s.ptr.p_double[j], _state); - } - alpha = ae_sqrt(alpha, _state); - if( ae_fp_neq(alpha,0) ) - { - result = result+ae_fabs(p/alpha, _state); - } - } - } - return result; -} - - -/************************************************************************* -This subroutine calculates scaled norm of vector after projection onto -subspace of active constraints. Most often this function is used to test -stopping conditions. - -INPUT PARAMETERS: - S - active set object - D - vector whose norm is calculated - -RESULT: - Vector norm (after projection and scaling) - -NOTE: projection is performed first, scaling is performed after projection - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -double sasscaledconstrainednorm(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - double v; - double result; - - - ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); - n = state->n; - rvectorsetlengthatleast(&state->scntmp, n, _state); - - /* - * Prepare basis (if needed) - */ - sasrebuildbasis(state, _state); - - /* - * Calculate descent direction - */ - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>0 ) - { - state->scntmp.ptr.p_double[i] = 0; - } - else - { - state->scntmp.ptr.p_double[i] = d->ptr.p_double[i]; - } - } - for(i=0; i<=state->basissize-1; i++) - { - v = ae_v_dotproduct(&state->ibasis.ptr.pp_double[i][0], 1, &state->scntmp.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_subd(&state->scntmp.ptr.p_double[0], 1, &state->ibasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->s.ptr.p_double[i]*state->scntmp.ptr.p_double[i], _state); - } - result = ae_sqrt(v, _state); - return result; -} - - -/************************************************************************* -This subroutine turns off optimization mode. - -INPUT PARAMETERS: - S - active set object - -OUTPUT PARAMETERS: - S - state is changed - -NOTE: this function can be called many times for optimizer which was - already stopped. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -void sasstopoptimization(sactiveset* state, ae_state *_state) -{ - - - state->algostate = 0; -} - - -/************************************************************************* -This function recalculates constraints - activates and deactivates them -according to gradient value at current point. Algorithm assumes that we -want to make steepest descent step from current point; constraints are -activated and deactivated in such way that we won't violate any constraint -by steepest descent step. - -After call to this function active set is ready to try steepest descent -step (SASDescentDirection-SASExploreDirection-SASMoveTo). - -Only already "active" and "candidate" elements of ActiveSet are examined; -constraints which are not active are not examined. - -INPUT PARAMETERS: - State - active set object - GC - array[N], gradient at XC - -OUTPUT PARAMETERS: - State - active set object, with new set of constraint - - -- ALGLIB -- - Copyright 26.09.2012 by Bochkanov Sergey -*************************************************************************/ -void sasreactivateconstraints(sactiveset* state, - /* Real */ ae_vector* gc, - ae_state *_state) -{ - - - ae_assert(state->algostate==1, "SASReactivateConstraints: must be in optimization mode", _state); - sactivesets_reactivateconstraints(state, gc, &state->unitdiagonal, _state); -} - - -/************************************************************************* -This function recalculates constraints - activates and deactivates them -according to gradient value at current point. - -Algorithm assumes that we want to make Quasi-Newton step from current -point with diagonal Quasi-Newton matrix H. Constraints are activated and -deactivated in such way that we won't violate any constraint by step. - -After call to this function active set is ready to try preconditioned -steepest descent step (SASDescentDirection-SASExploreDirection-SASMoveTo). - -Only already "active" and "candidate" elements of ActiveSet are examined; -constraints which are not active are not examined. - -INPUT PARAMETERS: - State - active set object - GC - array[N], gradient at XC - -OUTPUT PARAMETERS: - State - active set object, with new set of constraint - - -- ALGLIB -- - Copyright 26.09.2012 by Bochkanov Sergey -*************************************************************************/ -void sasreactivateconstraintsprec(sactiveset* state, - /* Real */ ae_vector* gc, - ae_state *_state) -{ - - - ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); - sactivesets_reactivateconstraints(state, gc, &state->h, _state); -} - - -/************************************************************************* -This function builds three orthonormal basises for current active set: -* P-orthogonal one, which is orthogonalized with inner product - (x,y) = x'*P*y, where P=inv(H) is current preconditioner -* S-orthogonal one, which is orthogonalized with inner product - (x,y) = x'*S'*S*y, where S is diagonal scaling matrix -* I-orthogonal one, which is orthogonalized with standard dot product - -NOTE: all sets of orthogonal vectors are guaranteed to have same size. - P-orthogonal basis is built first, I/S-orthogonal basises are forced - to have same number of vectors as P-orthogonal one (padded by zero - vectors if needed). - -NOTE: this function tracks changes in active set; first call will result - in reorthogonalization - -INPUT PARAMETERS: - State - active set object - H - diagonal preconditioner, H[i]>0 - -OUTPUT PARAMETERS: - State - active set object with new basis - - -- ALGLIB -- - Copyright 20.06.2012 by Bochkanov Sergey -*************************************************************************/ -void sasrebuildbasis(sactiveset* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - ae_int_t i; - ae_int_t j; - ae_int_t t; - ae_int_t nactivelin; - ae_int_t nactivebnd; - double v; - double vmax; - ae_int_t kmax; - - - if( state->basisisready ) - { - return; - } - n = state->n; - nec = state->nec; - nic = state->nic; - rmatrixsetlengthatleast(&state->tmpbasis, nec+nic, n+1, _state); - state->basissize = 0; - state->basisisready = ae_true; - - /* - * Determine number of active boundary and non-boundary - * constraints, move them to TmpBasis. Quick exit if no - * non-boundary constraints were detected. - */ - nactivelin = 0; - nactivebnd = 0; - for(i=0; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]>0 ) - { - nactivelin = nactivelin+1; - } - } - for(j=0; j<=n-1; j++) - { - if( state->activeset.ptr.p_int[j]>0 ) - { - nactivebnd = nactivebnd+1; - } - } - if( nactivelin==0 ) - { - return; - } - - /* - * Orthogonalize linear constraints (inner product is given by preconditioner) - * with respect to each other and boundary ones: - * * normalize all constraints - * * orthogonalize with respect to boundary ones - * * repeat: - * * if basisSize+nactivebnd=n - TERMINATE - * * choose largest row from TmpBasis - * * if row norm is too small - TERMINATE - * * add row to basis, normalize - * * remove from TmpBasis, orthogonalize other constraints with respect to this one - */ - nactivelin = 0; - for(i=0; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]>0 ) - { - ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); - nactivelin = nactivelin+1; - } - } - for(i=0; i<=nactivelin-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state)/state->h.ptr.p_double[j]; - } - if( ae_fp_greater(v,0) ) - { - v = 1/ae_sqrt(v, _state); - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; - } - } - } - for(j=0; j<=n-1; j++) - { - if( state->activeset.ptr.p_int[j]>0 ) - { - for(i=0; i<=nactivelin-1; i++) - { - state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; - state->tmpbasis.ptr.pp_double[i][j] = 0.0; - } - } - } - while(state->basissize+nactivebndtmpbasis.ptr.pp_double[i][j], _state)/state->h.ptr.p_double[j]; - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(v,vmax) ) - { - vmax = v; - kmax = i; - } - } - if( ae_fp_less(vmax,1.0E4*ae_machineepsilon) ) - { - break; - } - v = 1/vmax; - ae_v_moved(&state->pbasis.ptr.pp_double[state->basissize][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); - state->basissize = state->basissize+1; - - /* - * Reorthogonalize other vectors with respect to chosen one. - * Remove it from the array. - */ - for(i=0; i<=nactivelin-1; i++) - { - if( i!=kmax ) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+state->pbasis.ptr.pp_double[state->basissize-1][j]*state->tmpbasis.ptr.pp_double[i][j]/state->h.ptr.p_double[j]; - } - ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->pbasis.ptr.pp_double[state->basissize-1][0], 1, ae_v_len(0,n), v); - } - } - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[kmax][j] = 0; - } - } - - /* - * Orthogonalize linear constraints using traditional dot product - * with respect to each other and boundary ones. - * - * NOTE: we force basis size to be equal to one which was computed - * at the previous step, with preconditioner-based inner product. - */ - nactivelin = 0; - for(i=0; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]>0 ) - { - ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); - nactivelin = nactivelin+1; - } - } - for(i=0; i<=nactivelin-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state); - } - if( ae_fp_greater(v,0) ) - { - v = 1/ae_sqrt(v, _state); - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; - } - } - } - for(j=0; j<=n-1; j++) - { - if( state->activeset.ptr.p_int[j]>0 ) - { - for(i=0; i<=nactivelin-1; i++) - { - state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; - state->tmpbasis.ptr.pp_double[i][j] = 0.0; - } - } - } - for(t=0; t<=state->basissize-1; t++) - { - - /* - * Find largest vector, add to basis. - */ - vmax = -1; - kmax = -1; - for(i=0; i<=nactivelin-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state); - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(v,vmax) ) - { - vmax = v; - kmax = i; - } - } - if( ae_fp_eq(vmax,0) ) - { - for(j=0; j<=n; j++) - { - state->ibasis.ptr.pp_double[t][j] = 0.0; - } - continue; - } - v = 1/vmax; - ae_v_moved(&state->ibasis.ptr.pp_double[t][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); - - /* - * Reorthogonalize other vectors with respect to chosen one. - * Remove it from the array. - */ - for(i=0; i<=nactivelin-1; i++) - { - if( i!=kmax ) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+state->ibasis.ptr.pp_double[t][j]*state->tmpbasis.ptr.pp_double[i][j]; - } - ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->ibasis.ptr.pp_double[t][0], 1, ae_v_len(0,n), v); - } - } - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[kmax][j] = 0; - } - } - - /* - * Orthogonalize linear constraints using inner product given by - * scale matrix. - * - * NOTE: we force basis size to be equal to one which was computed - * with preconditioner-based inner product. - */ - nactivelin = 0; - for(i=0; i<=nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[n+i]>0 ) - { - ae_v_move(&state->tmpbasis.ptr.pp_double[nactivelin][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); - nactivelin = nactivelin+1; - } - } - for(i=0; i<=nactivelin-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state); - } - if( ae_fp_greater(v,0) ) - { - v = 1/ae_sqrt(v, _state); - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; - } - } - } - for(j=0; j<=n-1; j++) - { - if( state->activeset.ptr.p_int[j]>0 ) - { - for(i=0; i<=nactivelin-1; i++) - { - state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; - state->tmpbasis.ptr.pp_double[i][j] = 0.0; - } - } - } - for(t=0; t<=state->basissize-1; t++) - { - - /* - * Find largest vector, add to basis. - */ - vmax = -1; - kmax = -1; - for(i=0; i<=nactivelin-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state); - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(v,vmax) ) - { - vmax = v; - kmax = i; - } - } - if( ae_fp_eq(vmax,0) ) - { - for(j=0; j<=n; j++) - { - state->sbasis.ptr.pp_double[t][j] = 0.0; - } - continue; - } - v = 1/vmax; - ae_v_moved(&state->sbasis.ptr.pp_double[t][0], 1, &state->tmpbasis.ptr.pp_double[kmax][0], 1, ae_v_len(0,n), v); - - /* - * Reorthogonalize other vectors with respect to chosen one. - * Remove it from the array. - */ - for(i=0; i<=nactivelin-1; i++) - { - if( i!=kmax ) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+state->sbasis.ptr.pp_double[t][j]*state->tmpbasis.ptr.pp_double[i][j]*ae_sqr(state->s.ptr.p_double[j], _state); - } - ae_v_subd(&state->tmpbasis.ptr.pp_double[i][0], 1, &state->sbasis.ptr.pp_double[t][0], 1, ae_v_len(0,n), v); - } - } - for(j=0; j<=n; j++) - { - state->tmpbasis.ptr.pp_double[kmax][j] = 0; - } - } -} - - -/************************************************************************* -This subroutine calculates preconditioned descent direction subject to -current active set. - -INPUT PARAMETERS: - State - active set object - G - array[N], gradient - H - array[N], Hessian matrix - HA - active constraints orthogonalized in such way - that HA*inv(H)*HA'= I. - Normalize- whether we need normalized descent or not - D - possibly preallocated buffer; automatically resized. - -OUTPUT PARAMETERS: - D - descent direction projected onto current active set. - Components of D which correspond to active boundary - constraints are forced to be exactly zero. - In case D is non-zero and Normalize is True, it is - normalized to have unit norm. - - -- ALGLIB -- - Copyright 21.12.2012 by Bochkanov Sergey -*************************************************************************/ -static void sactivesets_constraineddescent(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* h, - /* Real */ ae_matrix* ha, - ae_bool normalize, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - double v; - ae_int_t nactive; - - - ae_assert(state->algostate==1, "SAS: internal error in ConstrainedDescent() - not in optimization mode", _state); - ae_assert(state->basisisready, "SAS: internal error in ConstrainedDescent() - no basis", _state); - n = state->n; - rvectorsetlengthatleast(d, n, _state); - - /* - * Calculate preconditioned constrained descent direction: - * - * d := -inv(H)*( g - HA'*(HA*inv(H)*g) ) - * - * Formula above always gives direction which is orthogonal to rows of HA. - * You can verify it by multiplication of both sides by HA[i] (I-th row), - * taking into account that HA*inv(H)*HA'= I (by definition of HA - it is - * orthogonal basis with inner product given by inv(H)). - */ - nactive = 0; - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>0 ) - { - d->ptr.p_double[i] = 0; - nactive = nactive+1; - } - else - { - d->ptr.p_double[i] = g->ptr.p_double[i]; - } - } - for(i=0; i<=state->basissize-1; i++) - { - v = 0.0; - for(j=0; j<=n-1; j++) - { - v = v+ha->ptr.pp_double[i][j]*d->ptr.p_double[j]/h->ptr.p_double[j]; - } - ae_v_subd(&d->ptr.p_double[0], 1, &ha->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - nactive = nactive+1; - } - v = 0.0; - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>0 ) - { - d->ptr.p_double[i] = 0; - } - else - { - d->ptr.p_double[i] = -d->ptr.p_double[i]/h->ptr.p_double[i]; - v = v+ae_sqr(d->ptr.p_double[i], _state); - } - } - v = ae_sqrt(v, _state); - if( nactive>=n ) - { - v = 0; - for(i=0; i<=n-1; i++) - { - d->ptr.p_double[i] = 0; - } - } - if( normalize&&ae_fp_greater(v,0) ) - { - for(i=0; i<=n-1; i++) - { - d->ptr.p_double[i] = d->ptr.p_double[i]/v; - } - } -} - - -/************************************************************************* -This function recalculates constraints - activates and deactivates them -according to gradient value at current point. - -Algorithm assumes that we want to make Quasi-Newton step from current -point with diagonal Quasi-Newton matrix H. Constraints are activated and -deactivated in such way that we won't violate any constraint by step. - -Only already "active" and "candidate" elements of ActiveSet are examined; -constraints which are not active are not examined. - -INPUT PARAMETERS: - State - active set object - GC - array[N], gradient at XC - H - array[N], Hessian matrix - -OUTPUT PARAMETERS: - State - active set object, with new set of constraint - - -- ALGLIB -- - Copyright 26.09.2012 by Bochkanov Sergey -*************************************************************************/ -static void sactivesets_reactivateconstraints(sactiveset* state, - /* Real */ ae_vector* gc, - /* Real */ ae_vector* h, - ae_state *_state) -{ - ae_int_t n; - ae_int_t nec; - ae_int_t nic; - ae_int_t i; - ae_int_t j; - ae_int_t idx0; - ae_int_t idx1; - double v; - ae_int_t nactivebnd; - ae_int_t nactivelin; - ae_int_t nactiveconstraints; - double rowscale; - - - ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); - - /* - * Prepare - */ - n = state->n; - nec = state->nec; - nic = state->nic; - state->basisisready = ae_false; - - /* - * Handle important special case - no linear constraints, - * only boundary constraints are present - */ - if( nec+nic==0 ) - { - for(i=0; i<=n-1; i++) - { - if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],0) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],0) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - state->activeset.ptr.p_int[i] = -1; - } - return; - } - - /* - * General case. - * Allocate temporaries. - */ - rvectorsetlengthatleast(&state->rctmpg, n, _state); - rvectorsetlengthatleast(&state->rctmprightpart, n, _state); - rvectorsetlengthatleast(&state->rctmps, n, _state); - rmatrixsetlengthatleast(&state->rctmpdense0, n, nec+nic, _state); - rmatrixsetlengthatleast(&state->rctmpdense1, n, nec+nic, _state); - bvectorsetlengthatleast(&state->rctmpisequality, n+nec+nic, _state); - ivectorsetlengthatleast(&state->rctmpconstraintidx, n+nec+nic, _state); - - /* - * Calculate descent direction - */ - ae_v_moveneg(&state->rctmpg.ptr.p_double[0], 1, &gc->ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Determine candidates to the active set. - * - * After this block constraints become either "inactive" (ActiveSet[i]<0) - * or "candidates" (ActiveSet[i]=0). Previously active constraints always - * become "candidates". - */ - for(i=0; i<=n+nec+nic-1; i++) - { - if( state->activeset.ptr.p_int[i]>0 ) - { - state->activeset.ptr.p_int[i] = 0; - } - else - { - state->activeset.ptr.p_int[i] = -1; - } - } - nactiveconstraints = 0; - nactivebnd = 0; - nactivelin = 0; - for(i=0; i<=n-1; i++) - { - - /* - * Activate boundary constraints: - * * copy constraint index to RCTmpConstraintIdx - * * set corresponding element of ActiveSet[] to "candidate" - * * fill RCTmpS by either +1 (lower bound) or -1 (upper bound) - * * set RCTmpIsEquality to False (BndLhasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - - /* - * Equality constraint is activated - */ - state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; - state->activeset.ptr.p_int[i] = 0; - state->rctmps.ptr.p_double[i] = 1.0; - state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_true; - nactiveconstraints = nactiveconstraints+1; - nactivebnd = nactivebnd+1; - continue; - } - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) - { - - /* - * Lower bound is activated - */ - state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; - state->activeset.ptr.p_int[i] = 0; - state->rctmps.ptr.p_double[i] = -1.0; - state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; - nactiveconstraints = nactiveconstraints+1; - nactivebnd = nactivebnd+1; - continue; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - - /* - * Upper bound is activated - */ - state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; - state->activeset.ptr.p_int[i] = 0; - state->rctmps.ptr.p_double[i] = 1.0; - state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; - nactiveconstraints = nactiveconstraints+1; - nactivebnd = nactivebnd+1; - continue; - } - } - for(i=0; i<=nec+nic-1; i++) - { - if( i>=nec ) - { - - /* - * Inequality constraints are skipped if we too far away from - * the boundary. - */ - rowscale = 0.0; - v = -state->cleic.ptr.pp_double[i][n]; - for(j=0; j<=n-1; j++) - { - v = v+state->cleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; - rowscale = ae_maxreal(rowscale, ae_fabs(state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state), _state); - } - if( ae_fp_less_eq(v,-1.0E5*ae_machineepsilon*rowscale) ) - { - - /* - * NOTE: it is important to check for non-strict inequality - * because we have to correctly handle zero constraint - * 0*x<=0 - */ - continue; - } - } - ae_v_move(&state->rctmpdense0.ptr.pp_double[0][nactivelin], state->rctmpdense0.stride, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = n+i; - state->activeset.ptr.p_int[n+i] = 0; - state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ihasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],0) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],0) ) - { - state->activeset.ptr.p_int[i] = 1; - continue; - } - } - return; - } - - /* - * General case. - * - * APPROACH TO CONSTRAINTS ACTIVATION/DEACTIVATION - * - * We have NActiveConstraints "candidates": NActiveBnd boundary candidates, - * NActiveLin linear candidates. Indexes of boundary constraints are stored - * in RCTmpConstraintIdx[0:NActiveBnd-1], indexes of linear ones are stored - * in RCTmpConstraintIdx[NActiveBnd:NActiveBnd+NActiveLin-1]. Some of the - * constraints are equality ones, some are inequality - as specified by - * RCTmpIsEquality[i]. - * - * Now we have to determine active subset of "candidates" set. In order to - * do so we solve following constrained minimization problem: - * ( )^2 - * min ( SUM(lambda[i]*A[i]) + G ) - * ( ) - * Here: - * * G is a gradient (column vector) - * * A[i] is a column vector, linear (left) part of I-th constraint. - * I=0..NActiveConstraints-1, first NActiveBnd elements of A are just - * subset of identity matrix (boundary constraints), next NActiveLin - * elements are subset of rows of the matrix of general linear constraints. - * * lambda[i] is a Lagrange multiplier corresponding to I-th constraint - * - * NOTE: for preconditioned setting A is replaced by A*H^(-0.5), G is - * replaced by G*H^(-0.5). We apply this scaling at the last stage, - * before passing data to NNLS solver. - * - * Minimization is performed subject to non-negativity constraints on - * lambda[i] corresponding to inequality constraints. Inequality constraints - * which correspond to non-zero lambda are activated, equality constraints - * are always considered active. - * - * Informally speaking, we "decompose" descent direction -G and represent - * it as sum of constraint vectors and "residual" part (which is equal to - * the actual descent direction subject to constraints). - * - * SOLUTION OF THE NNLS PROBLEM - * - * We solve this optimization problem with Non-Negative Least Squares solver, - * which can efficiently solve least squares problems of the form - * - * ( [ I | AU ] )^2 - * min ( [ | ]*x-b ) s.t. non-negativity constraints on some x[i] - * ( [ 0 | AL ] ) - * - * In order to use this solver we have to rearrange rows of A[] and G in - * such way that first NActiveBnd columns of A store identity matrix (before - * sorting non-zero elements are randomly distributed in the first NActiveBnd - * columns of A, during sorting we move them to first NActiveBnd rows). - * - * Then we create instance of NNLS solver (we reuse instance left from the - * previous run of the optimization problem) and solve NNLS problem. - */ - idx0 = 0; - idx1 = nactivebnd; - for(i=0; i<=n-1; i++) - { - if( state->activeset.ptr.p_int[i]>=0 ) - { - v = 1/ae_sqrt(h->ptr.p_double[i], _state); - for(j=0; j<=nactivelin-1; j++) - { - state->rctmpdense1.ptr.pp_double[idx0][j] = state->rctmpdense0.ptr.pp_double[i][j]/state->rctmps.ptr.p_double[i]*v; - } - state->rctmprightpart.ptr.p_double[idx0] = state->rctmpg.ptr.p_double[i]/state->rctmps.ptr.p_double[i]*v; - idx0 = idx0+1; - } - else - { - v = 1/ae_sqrt(h->ptr.p_double[i], _state); - for(j=0; j<=nactivelin-1; j++) - { - state->rctmpdense1.ptr.pp_double[idx1][j] = state->rctmpdense0.ptr.pp_double[i][j]*v; - } - state->rctmprightpart.ptr.p_double[idx1] = state->rctmpg.ptr.p_double[i]*v; - idx1 = idx1+1; - } - } - snnlsinit(n, nec+nic, n, &state->solver, _state); - snnlssetproblem(&state->solver, &state->rctmpdense1, &state->rctmprightpart, nactivebnd, nactiveconstraints-nactivebnd, n, _state); - for(i=0; i<=nactiveconstraints-1; i++) - { - if( state->rctmpisequality.ptr.p_bool[i] ) - { - snnlsdropnnc(&state->solver, i, _state); - } - } - snnlssolve(&state->solver, &state->rctmplambdas, _state); - - /* - * After solution of the problem we activate equality constraints (always active) - * and inequality constraints with non-zero Lagrange multipliers. Then we reorthogonalize - * active constraints. - */ - for(i=0; i<=nactiveconstraints-1; i++) - { - if( state->rctmpisequality.ptr.p_bool[i]||ae_fp_greater(state->rctmplambdas.ptr.p_double[i],0) ) - { - state->activeset.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 1; - } - else - { - state->activeset.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 0; - } - } - sasrebuildbasis(state, _state); -} - - -ae_bool _sactiveset_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - sactiveset *p = (sactiveset*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->h, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->activeset, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->sbasis, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->pbasis, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->ibasis, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mtx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mtas, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cdtmp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->corrtmp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->unitdiagonal, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_snnlssolver_init(&p->solver, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->scntmp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpfeas, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpm0, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmps, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmpg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmprightpart, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->rctmpdense0, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->rctmpdense1, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmpisequality, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmpconstraintidx, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmplambdas, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->tmpbasis, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _sactiveset_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - sactiveset *dst = (sactiveset*)_dst; - sactiveset *src = (sactiveset*)_src; - dst->n = src->n; - dst->algostate = src->algostate; - if( !ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic) ) - return ae_false; - dst->hasxc = src->hasxc; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->h, &src->h, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->activeset, &src->activeset, _state, make_automatic) ) - return ae_false; - dst->basisisready = src->basisisready; - if( !ae_matrix_init_copy(&dst->sbasis, &src->sbasis, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->pbasis, &src->pbasis, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->ibasis, &src->ibasis, _state, make_automatic) ) - return ae_false; - dst->basissize = src->basissize; - dst->constraintschanged = src->constraintschanged; - if( !ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic) ) - return ae_false; - dst->nec = src->nec; - dst->nic = src->nic; - if( !ae_vector_init_copy(&dst->mtx, &src->mtx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mtas, &src->mtas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cdtmp, &src->cdtmp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->corrtmp, &src->corrtmp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->unitdiagonal, &src->unitdiagonal, _state, make_automatic) ) - return ae_false; - if( !_snnlssolver_init_copy(&dst->solver, &src->solver, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->scntmp, &src->scntmp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpfeas, &src->tmpfeas, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpm0, &src->tmpm0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmps, &src->rctmps, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmpg, &src->rctmpg, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmprightpart, &src->rctmprightpart, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->rctmpdense0, &src->rctmpdense0, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->rctmpdense1, &src->rctmpdense1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmpisequality, &src->rctmpisequality, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmpconstraintidx, &src->rctmpconstraintidx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmplambdas, &src->rctmplambdas, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->tmpbasis, &src->tmpbasis, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _sactiveset_clear(void* _p) -{ - sactiveset *p = (sactiveset*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->xc); - ae_vector_clear(&p->s); - ae_vector_clear(&p->h); - ae_vector_clear(&p->activeset); - ae_matrix_clear(&p->sbasis); - ae_matrix_clear(&p->pbasis); - ae_matrix_clear(&p->ibasis); - ae_vector_clear(&p->hasbndl); - ae_vector_clear(&p->hasbndu); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_matrix_clear(&p->cleic); - ae_vector_clear(&p->mtx); - ae_vector_clear(&p->mtas); - ae_vector_clear(&p->cdtmp); - ae_vector_clear(&p->corrtmp); - ae_vector_clear(&p->unitdiagonal); - _snnlssolver_clear(&p->solver); - ae_vector_clear(&p->scntmp); - ae_vector_clear(&p->tmp0); - ae_vector_clear(&p->tmpfeas); - ae_matrix_clear(&p->tmpm0); - ae_vector_clear(&p->rctmps); - ae_vector_clear(&p->rctmpg); - ae_vector_clear(&p->rctmprightpart); - ae_matrix_clear(&p->rctmpdense0); - ae_matrix_clear(&p->rctmpdense1); - ae_vector_clear(&p->rctmpisequality); - ae_vector_clear(&p->rctmpconstraintidx); - ae_vector_clear(&p->rctmplambdas); - ae_matrix_clear(&p->tmpbasis); -} - - -void _sactiveset_destroy(void* _p) -{ - sactiveset *p = (sactiveset*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->xc); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->h); - ae_vector_destroy(&p->activeset); - ae_matrix_destroy(&p->sbasis); - ae_matrix_destroy(&p->pbasis); - ae_matrix_destroy(&p->ibasis); - ae_vector_destroy(&p->hasbndl); - ae_vector_destroy(&p->hasbndu); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_matrix_destroy(&p->cleic); - ae_vector_destroy(&p->mtx); - ae_vector_destroy(&p->mtas); - ae_vector_destroy(&p->cdtmp); - ae_vector_destroy(&p->corrtmp); - ae_vector_destroy(&p->unitdiagonal); - _snnlssolver_destroy(&p->solver); - ae_vector_destroy(&p->scntmp); - ae_vector_destroy(&p->tmp0); - ae_vector_destroy(&p->tmpfeas); - ae_matrix_destroy(&p->tmpm0); - ae_vector_destroy(&p->rctmps); - ae_vector_destroy(&p->rctmpg); - ae_vector_destroy(&p->rctmprightpart); - ae_matrix_destroy(&p->rctmpdense0); - ae_matrix_destroy(&p->rctmpdense1); - ae_vector_destroy(&p->rctmpisequality); - ae_vector_destroy(&p->rctmpconstraintidx); - ae_vector_destroy(&p->rctmplambdas); - ae_matrix_destroy(&p->tmpbasis); -} - - - - -/************************************************************************* - NONLINEAR CONJUGATE GRADIENT METHOD - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using one of the -nonlinear conjugate gradient methods. - -These CG methods are globally convergent (even on non-convex functions) as -long as grad(f) is Lipschitz continuous in a some neighborhood of the -L = { x : f(x)<=f(x0) }. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinCGCreate() call -2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and - other functions -3. User calls MinCGOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinCGResults() to get solution -5. Optionally, user may call MinCGRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinCGRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgcreate(ae_int_t n, - /* Real */ ae_vector* x, - mincgstate* state, - ae_state *_state) -{ - - _mincgstate_clear(state); - - ae_assert(n>=1, "MinCGCreate: N too small!", _state); - ae_assert(x->cnt>=n, "MinCGCreate: Length(X)0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinCGSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. L-BFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgcreatef(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - mincgstate* state, - ae_state *_state) -{ - - _mincgstate_clear(state); - - ae_assert(n>=1, "MinCGCreateF: N too small!", _state); - ae_assert(x->cnt>=n, "MinCGCreateF: Length(X)=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinCGSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcond(mincgstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinCGSetCond: EpsG is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinCGSetCond: negative EpsG!", _state); - ae_assert(ae_isfinite(epsf, _state), "MinCGSetCond: EpsF is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinCGSetCond: negative EpsF!", _state); - ae_assert(ae_isfinite(epsx, _state), "MinCGSetCond: EpsX is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinCGSetCond: negative EpsX!", _state); - ae_assert(maxits>=0, "MinCGSetCond: negative MaxIts!", _state); - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->epsg = epsg; - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -This function sets scaling coefficients for CG optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of CG optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the CG too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinCGSetPrec...() functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgsetscale(mincgstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(s->cnt>=state->n, "MinCGSetScale: Length(S)n-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinCGSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinCGSetScale: S contains zero elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function turns on/off line search reports. -These reports are described in more details in developer-only comments on -MinCGState object. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedDRep- whether line search reports are needed or not - -This function is intended for private use only. Turning it on artificially -may cause program failure. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state) -{ - - - state->drep = needdrep; -} - - -/************************************************************************* -This function sets CG algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - CGType - algorithm type: - * -1 automatic selection of the best algorithm - * 0 DY (Dai and Yuan) algorithm - * 1 Hybrid DY-HS algorithm - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state) -{ - - - ae_assert(cgtype>=-1&&cgtype<=1, "MinCGSetCGType: incorrect CGType!", _state); - if( cgtype==-1 ) - { - cgtype = 1; - } - state->cgtype = cgtype; -} - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "MinCGSetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "MinCGSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* -This function allows to suggest initial step length to the CG algorithm. - -Suggested step length is used as starting point for the line search. It -can be useful when you have badly scaled problem, i.e. when ||grad|| -(which is used as initial estimate for the first step) is many orders of -magnitude different from the desired step. - -Line search may fail on such problems without good estimate of initial -step length. Imagine, for example, problem with ||grad||=10^50 and desired -step equal to 0.1 Line search function will use 10^50 as initial step, -then it will decrease step length by 2 (up to 20 attempts) and will get -10^44, which is still too large. - -This function allows us to tell than line search should be started from -some moderate step length, like 1.0, so algorithm will be able to detect -desired step length in a several searches. - -Default behavior (when no step is suggested) is to use preconditioner, if -it is available, to generate initial estimate of step length. - -This function influences only first iteration of algorithm. It should be -called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. -Suggested step is ignored if you have preconditioner. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - Stp - initial estimate of the step length. - Can be zero (no estimate). - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state) -{ - - - ae_assert(ae_isfinite(stp, _state), "MinCGSuggestStep: Stp is infinite or NAN", _state); - ae_assert(ae_fp_greater_eq(stp,0), "MinCGSuggestStep: Stp<0", _state); - state->suggestedstep = stp; -} - - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdefault(mincgstate* state, ae_state *_state) -{ - - - state->prectype = 0; - state->innerresetneeded = ae_true; -} - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdiag(mincgstate* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(d->cnt>=state->n, "MinCGSetPrecDiag: D is too short", _state); - for(i=0; i<=state->n-1; i++) - { - ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinCGSetPrecDiag: D contains infinite or NAN elements", _state); - ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinCGSetPrecDiag: D contains non-positive elements", _state); - } - mincgsetprecdiagfast(state, d, _state); -} - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinCGSetScale() call -(before or after MinCGSetPrecScale() call). Without knowledge of the scale -of your variables scale-based preconditioner will be just unit matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecscale(mincgstate* state, ae_state *_state) -{ - - - state->prectype = 3; - state->innerresetneeded = ae_true; -} - - -/************************************************************************* -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinCGCreate() for analytical gradient or MinCGCreateF() for - numerical differentiation) you should choose appropriate variant of - MinCGOptimize() - one which accepts function AND gradient or one which - accepts function ONLY. - - Be careful to choose variant of MinCGOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinCGOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinCGOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinCGCreateF() | work FAIL - MinCGCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinCGOptimize() version. Attemps to use such combination - (for example, to create optimizer with MinCGCreateF() and to pass - gradient information to MinCGOptimize()) will lead to exception being - thrown. Either you did not pass gradient when it WAS needed or you - passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool mincgiteration(mincgstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double betak; - double v; - double vv; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - i = state->rstate.ia.ptr.p_int[1]; - betak = state->rstate.ra.ptr.p_double[0]; - v = state->rstate.ra.ptr.p_double[1]; - vv = state->rstate.ra.ptr.p_double[2]; - } - else - { - n = -983; - i = -989; - betak = -834; - v = 900; - vv = -287; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - if( state->rstate.stage==14 ) - { - goto lbl_14; - } - if( state->rstate.stage==15 ) - { - goto lbl_15; - } - if( state->rstate.stage==16 ) - { - goto lbl_16; - } - if( state->rstate.stage==17 ) - { - goto lbl_17; - } - if( state->rstate.stage==18 ) - { - goto lbl_18; - } - if( state->rstate.stage==19 ) - { - goto lbl_19; - } - - /* - * Routine body - */ - - /* - * Prepare - */ - n = state->n; - state->repterminationtype = 0; - state->repiterationscount = 0; - state->repvaridx = -1; - state->repnfev = 0; - state->debugrestartscount = 0; - - /* - * Check, that transferred derivative value is right - */ - mincg_clearrequestfields(state, _state); - if( !(ae_fp_eq(state->diffstep,0)&&ae_fp_greater(state->teststep,0)) ) - { - goto lbl_20; - } - state->needfg = ae_true; - i = 0; -lbl_22: - if( i>n-1 ) - { - goto lbl_24; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->fm1 = state->f; - state->fp1 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->fm2 = state->f; - state->fp2 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = v; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - - /* - * 2*State.TestStep - scale parameter - * width of segment [Xi-TestStep;Xi+TestStep] - */ - if( !derivativecheck(state->fm1, state->fp1, state->fm2, state->fp2, state->f, state->g.ptr.p_double[i], 2*state->teststep, _state) ) - { - state->repvaridx = i; - state->repterminationtype = -7; - result = ae_false; - return result; - } - i = i+1; - goto lbl_22; -lbl_24: - state->needfg = ae_false; -lbl_20: - - /* - * Preparations continue: - * * set XK - * * calculate F/G - * * set DK to -G - * * powerup algo (it may change preconditioner) - * * apply preconditioner to DK - * * report update of X - * * check stopping conditions for G - */ - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->terminationneeded = ae_false; - mincg_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_25; - } - state->needfg = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needfg = ae_false; - goto lbl_26; -lbl_25: - state->needf = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->fbase = state->f; - i = 0; -lbl_27: - if( i>n-1 ) - { - goto lbl_29; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->fp2 = state->f; - state->x.ptr.p_double[i] = v; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - i = i+1; - goto lbl_27; -lbl_29: - state->f = state->fbase; - state->needf = ae_false; -lbl_26: - if( !state->drep ) - { - goto lbl_30; - } - - /* - * Report algorithm powerup (if needed) - */ - mincg_clearrequestfields(state, _state); - state->algpowerup = ae_true; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->algpowerup = ae_false; -lbl_30: - trimprepare(state->f, &state->trimthreshold, _state); - ae_v_moveneg(&state->dk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - mincg_preconditionedmultiply(state, &state->dk, &state->work0, &state->work1, _state); - if( !state->xrep ) - { - goto lbl_32; - } - mincg_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->xupdated = ae_false; -lbl_32: - if( state->terminationneeded ) - { - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repterminationtype = 8; - result = ae_false; - return result; - } - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) - { - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repterminationtype = 4; - result = ae_false; - return result; - } - state->repnfev = 1; - state->k = 0; - state->fold = state->f; - - /* - * Choose initial step. - * Apply preconditioner, if we have something other than default. - */ - if( state->prectype==2||state->prectype==3 ) - { - - /* - * because we use preconditioner, step length must be equal - * to the norm of DK - */ - v = ae_v_dotproduct(&state->dk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->lastgoodstep = ae_sqrt(v, _state); - } - else - { - - /* - * No preconditioner is used, we try to use suggested step - */ - if( ae_fp_greater(state->suggestedstep,0) ) - { - state->lastgoodstep = state->suggestedstep; - } - else - { - state->lastgoodstep = 1.0; - } - } - - /* - * Main cycle - */ - state->rstimer = mincg_rscountdownlen; -lbl_34: - if( ae_false ) - { - goto lbl_35; - } - - /* - * * clear reset flag - * * clear termination flag - * * store G[k] for later calculation of Y[k] - * * prepare starting point and direction and step length for line search - */ - state->innerresetneeded = ae_false; - state->terminationneeded = ae_false; - ae_v_moveneg(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->mcstage = 0; - state->stp = 1.0; - linminnormalized(&state->d, &state->stp, n, _state); - if( ae_fp_neq(state->lastgoodstep,0) ) - { - state->stp = state->lastgoodstep; - } - state->curstpmax = state->stpmax; - - /* - * Report beginning of line search (if needed) - * Terminate algorithm, if user request was detected - */ - if( !state->drep ) - { - goto lbl_36; - } - mincg_clearrequestfields(state, _state); - state->lsstart = ae_true; - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - state->lsstart = ae_false; -lbl_36: - if( state->terminationneeded ) - { - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repterminationtype = 8; - result = ae_false; - return result; - } - - /* - * Minimization along D - */ - mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); -lbl_38: - if( state->mcstage==0 ) - { - goto lbl_39; - } - - /* - * Calculate function/gradient using either - * analytical gradient supplied by user - * or finite difference approximation. - * - * "Trim" function in order to handle near-singularity points. - */ - mincg_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_40; - } - state->needfg = ae_true; - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - state->needfg = ae_false; - goto lbl_41; -lbl_40: - state->needf = ae_true; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->fbase = state->f; - i = 0; -lbl_42: - if( i>n-1 ) - { - goto lbl_44; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 14; - goto lbl_rcomm; -lbl_14: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 15; - goto lbl_rcomm; -lbl_15: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 16; - goto lbl_rcomm; -lbl_16: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 17; - goto lbl_rcomm; -lbl_17: - state->fp2 = state->f; - state->x.ptr.p_double[i] = v; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - i = i+1; - goto lbl_42; -lbl_44: - state->f = state->fbase; - state->needf = ae_false; -lbl_41: - trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); - - /* - * Call MCSRCH again - */ - mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); - goto lbl_38; -lbl_39: - - /* - * * report end of line search - * * store current point to XN - * * report iteration - * * terminate algorithm if user request was detected - */ - if( !state->drep ) - { - goto lbl_45; - } - - /* - * Report end of line search (if needed) - */ - mincg_clearrequestfields(state, _state); - state->lsend = ae_true; - state->rstate.stage = 18; - goto lbl_rcomm; -lbl_18: - state->lsend = ae_false; -lbl_45: - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( !state->xrep ) - { - goto lbl_47; - } - mincg_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 19; - goto lbl_rcomm; -lbl_19: - state->xupdated = ae_false; -lbl_47: - if( state->terminationneeded ) - { - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repterminationtype = 8; - result = ae_false; - return result; - } - - /* - * Line search is finished. - * * calculate BetaK - * * calculate DN - * * update timers - * * calculate step length: - * * LastScaledStep is ALWAYS calculated because it is used in the stopping criteria - * * LastGoodStep is updated only when MCINFO is equal to 1 (Wolfe conditions hold). - * See below for more explanation. - */ - if( state->mcinfo==1&&!state->innerresetneeded ) - { - - /* - * Standard Wolfe conditions hold - * Calculate Y[K] and D[K]'*Y[K] - */ - ae_v_add(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Calculate BetaK according to DY formula - */ - v = mincg_preconditionedmultiply2(state, &state->g, &state->g, &state->work0, &state->work1, _state); - state->betady = v/vv; - - /* - * Calculate BetaK according to HS formula - */ - v = mincg_preconditionedmultiply2(state, &state->g, &state->yk, &state->work0, &state->work1, _state); - state->betahs = v/vv; - - /* - * Choose BetaK - */ - if( state->cgtype==0 ) - { - betak = state->betady; - } - if( state->cgtype==1 ) - { - betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state); - } - } - else - { - - /* - * Something is wrong (may be function is too wild or too flat) - * or we just have to restart algo. - * - * We'll set BetaK=0, which will restart CG algorithm. - * We can stop later (during normal checks) if stopping conditions are met. - */ - betak = 0; - state->debugrestartscount = state->debugrestartscount+1; - } - if( state->repiterationscount>0&&state->repiterationscount%(3+n)==0 ) - { - - /* - * clear Beta every N iterations - */ - betak = 0; - } - if( state->mcinfo==1||state->mcinfo==5 ) - { - state->rstimer = mincg_rscountdownlen; - } - else - { - state->rstimer = state->rstimer-1; - } - ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - mincg_preconditionedmultiply(state, &state->dn, &state->work0, &state->work1, _state); - ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); - state->lastscaledstep = 0.0; - for(i=0; i<=n-1; i++) - { - state->lastscaledstep = state->lastscaledstep+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); - } - state->lastscaledstep = state->stp*ae_sqrt(state->lastscaledstep, _state); - if( state->mcinfo==1 ) - { - - /* - * Step is good (Wolfe conditions hold), update LastGoodStep. - * - * This check for MCINFO=1 is essential because sometimes in the - * constrained optimization setting we may take very short steps - * (like 1E-15) because we were very close to boundary of the - * feasible area. Such short step does not mean that we've converged - * to the solution - it was so short because we were close to the - * boundary and there was a limit on step length. - * - * So having such short step is quite normal situation. However, we - * should NOT start next iteration from step whose initial length is - * estimated as 1E-15 because it may lead to the failure of the - * linear minimizer (step is too short, function does not changes, - * line search stagnates). - */ - state->lastgoodstep = 0; - for(i=0; i<=n-1; i++) - { - state->lastgoodstep = state->lastgoodstep+ae_sqr(state->d.ptr.p_double[i], _state); - } - state->lastgoodstep = state->stp*ae_sqrt(state->lastgoodstep, _state); - } - - /* - * Update information. - * Check stopping conditions. - */ - state->repnfev = state->repnfev+state->nfev; - state->repiterationscount = state->repiterationscount+1; - if( state->repiterationscount>=state->maxits&&state->maxits>0 ) - { - - /* - * Too many iterations - */ - state->repterminationtype = 5; - result = ae_false; - return result; - } - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) - { - - /* - * Gradient is small enough - */ - state->repterminationtype = 4; - result = ae_false; - return result; - } - if( !state->innerresetneeded ) - { - - /* - * These conditions are checked only when no inner reset was requested by user - */ - if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) - { - - /* - * F(k+1)-F(k) is small enough - */ - state->repterminationtype = 1; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->lastscaledstep,state->epsx) ) - { - - /* - * X(k+1)-X(k) is small enough - */ - state->repterminationtype = 2; - result = ae_false; - return result; - } - } - if( state->rstimer<=0 ) - { - - /* - * Too many subsequent restarts - */ - state->repterminationtype = 7; - result = ae_false; - return result; - } - - /* - * Shift Xk/Dk, update other information - */ - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fold = state->f; - state->k = state->k+1; - goto lbl_34; -lbl_35: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = i; - state->rstate.ra.ptr.p_double[0] = betak; - state->rstate.ra.ptr.p_double[1] = v; - state->rstate.ra.ptr.p_double[2] = vv; - return result; -} - - -/************************************************************************* -Conjugate gradient results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinCGSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible, - we return best X found so far - * 8 terminated by user - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresults(mincgstate* state, - /* Real */ ae_vector* x, - mincgreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _mincgreport_clear(rep); - - mincgresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -Conjugate gradient results - -Buffered implementation of MinCGResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresultsbuf(mincgstate* state, - /* Real */ ae_vector* x, - mincgreport* rep, - ae_state *_state) -{ - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nfev = state->repnfev; - rep->varidx = state->repvaridx; - rep->terminationtype = state->repterminationtype; -} - - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgrestartfrom(mincgstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - - - ae_assert(x->cnt>=state->n, "MinCGRestartFrom: Length(X)n, _state), "MinCGCreate: X contains infinite or NaN values!", _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - mincgsuggeststep(state, 0.0, _state); - ae_vector_set_length(&state->rstate.ia, 1+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; - mincg_clearrequestfields(state, _state); -} - - -/************************************************************************* -Faster version of MinCGSetPrecDiag(), for time-critical parts of code, -without safety checks. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdiagfast(mincgstate* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - rvectorsetlengthatleast(&state->diagh, state->n, _state); - rvectorsetlengthatleast(&state->diaghl2, state->n, _state); - state->prectype = 2; - state->vcnt = 0; - state->innerresetneeded = ae_true; - for(i=0; i<=state->n-1; i++) - { - state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; - state->diaghl2.ptr.p_double[i] = 0.0; - } -} - - -/************************************************************************* -This function sets low-rank preconditioner for Hessian matrix H=D+V'*C*V, -where: -* H is a Hessian matrix, which is approximated by D/V/C -* D=D1+D2 is a diagonal matrix, which includes two positive definite terms: - * constant term D1 (is not updated or infrequently updated) - * variable term D2 (can be cheaply updated from iteration to iteration) -* V is a low-rank correction -* C is a diagonal factor of low-rank correction - -Preconditioner P is calculated using approximate Woodburry formula: - P = D^(-1) - D^(-1)*V'*(C^(-1)+V*D1^(-1)*V')^(-1)*V*D^(-1) - = D^(-1) - D^(-1)*VC'*VC*D^(-1), -where - VC = sqrt(B)*V - B = (C^(-1)+V*D1^(-1)*V')^(-1) - -Note that B is calculated using constant term (D1) only, which allows us -to update D2 without recalculation of B or VC. Such preconditioner is -exact when D2 is zero. When D2 is non-zero, it is only approximation, but -very good and cheap one. - -This function accepts D1, V, C. -D2 is set to zero by default. - -Cost of this update is O(N*VCnt*VCnt), but D2 can be updated in just O(N) -by MinCGSetPrecVarPart. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetpreclowrankfast(mincgstate* state, - /* Real */ ae_vector* d1, - /* Real */ ae_vector* c, - /* Real */ ae_matrix* v, - ae_int_t vcnt, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t n; - double t; - ae_matrix b; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init(&b, 0, 0, DT_REAL, _state, ae_true); - - if( vcnt==0 ) - { - mincgsetprecdiagfast(state, d1, _state); - ae_frame_leave(_state); - return; - } - n = state->n; - ae_matrix_set_length(&b, vcnt, vcnt, _state); - rvectorsetlengthatleast(&state->diagh, n, _state); - rvectorsetlengthatleast(&state->diaghl2, n, _state); - rmatrixsetlengthatleast(&state->vcorr, vcnt, n, _state); - state->prectype = 2; - state->vcnt = vcnt; - state->innerresetneeded = ae_true; - for(i=0; i<=n-1; i++) - { - state->diagh.ptr.p_double[i] = d1->ptr.p_double[i]; - state->diaghl2.ptr.p_double[i] = 0.0; - } - for(i=0; i<=vcnt-1; i++) - { - for(j=i; j<=vcnt-1; j++) - { - t = 0; - for(k=0; k<=n-1; k++) - { - t = t+v->ptr.pp_double[i][k]*v->ptr.pp_double[j][k]/d1->ptr.p_double[k]; - } - b.ptr.pp_double[i][j] = t; - } - b.ptr.pp_double[i][i] = b.ptr.pp_double[i][i]+1.0/c->ptr.p_double[i]; - } - if( !spdmatrixcholeskyrec(&b, 0, vcnt, ae_true, &state->work0, _state) ) - { - state->vcnt = 0; - ae_frame_leave(_state); - return; - } - for(i=0; i<=vcnt-1; i++) - { - ae_v_move(&state->vcorr.ptr.pp_double[i][0], 1, &v->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - for(j=0; j<=i-1; j++) - { - t = b.ptr.pp_double[j][i]; - ae_v_subd(&state->vcorr.ptr.pp_double[i][0], 1, &state->vcorr.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), t); - } - t = 1/b.ptr.pp_double[i][i]; - ae_v_muld(&state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), t); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -This function updates variable part (diagonal matrix D2) -of low-rank preconditioner. - -This update is very cheap and takes just O(N) time. - -It has no effect with default preconditioner. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecvarpart(mincgstate* state, - /* Real */ ae_vector* d2, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - - - n = state->n; - for(i=0; i<=n-1; i++) - { - state->diaghl2.ptr.p_double[i] = d2->ptr.p_double[i]; - } -} - - -/************************************************************************* - -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinCGOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinCGSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 31.05.2012 by Bochkanov Sergey -*************************************************************************/ -void mincgsetgradientcheck(mincgstate* state, - double teststep, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(teststep, _state), "MinCGSetGradientCheck: TestStep contains NaN or Infinite", _state); - ae_assert(ae_fp_greater_eq(teststep,0), "MinCGSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); - state->teststep = teststep; -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void mincg_clearrequestfields(mincgstate* state, ae_state *_state) -{ - - - state->needf = ae_false; - state->needfg = ae_false; - state->xupdated = ae_false; - state->lsstart = ae_false; - state->lsend = ae_false; - state->algpowerup = ae_false; -} - - -/************************************************************************* -This function calculates preconditioned product H^(-1)*x and stores result -back into X. Work0[] and Work1[] are used as temporaries (size must be at -least N; this function doesn't allocate arrays). - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -static void mincg_preconditionedmultiply(mincgstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* work0, - /* Real */ ae_vector* work1, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - ae_int_t vcnt; - double v; - - - n = state->n; - vcnt = state->vcnt; - if( state->prectype==0 ) - { - return; - } - if( state->prectype==3 ) - { - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; - } - return; - } - ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); - - /* - * handle part common for VCnt=0 and VCnt<>0 - */ - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); - } - - /* - * if VCnt>0 - */ - if( vcnt>0 ) - { - for(i=0; i<=vcnt-1; i++) - { - v = ae_v_dotproduct(&state->vcorr.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - work0->ptr.p_double[i] = v; - } - for(i=0; i<=n-1; i++) - { - work1->ptr.p_double[i] = 0; - } - for(i=0; i<=vcnt-1; i++) - { - v = work0->ptr.p_double[i]; - ae_v_addd(&state->work1.ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - for(i=0; i<=n-1; i++) - { - x->ptr.p_double[i] = x->ptr.p_double[i]-state->work1.ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); - } - } -} - - -/************************************************************************* -This function calculates preconditioned product x'*H^(-1)*y. Work0[] and -Work1[] are used as temporaries (size must be at least N; this function -doesn't allocate arrays). - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -static double mincg_preconditionedmultiply2(mincgstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - /* Real */ ae_vector* work0, - /* Real */ ae_vector* work1, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - ae_int_t vcnt; - double v0; - double v1; - double result; - - - n = state->n; - vcnt = state->vcnt; - - /* - * no preconditioning - */ - if( state->prectype==0 ) - { - v0 = ae_v_dotproduct(&x->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); - result = v0; - return result; - } - if( state->prectype==3 ) - { - result = 0; - for(i=0; i<=n-1; i++) - { - result = result+x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]*y->ptr.p_double[i]; - } - return result; - } - ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); - - /* - * low rank preconditioning - */ - result = 0.0; - for(i=0; i<=n-1; i++) - { - result = result+x->ptr.p_double[i]*y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); - } - if( vcnt>0 ) - { - for(i=0; i<=n-1; i++) - { - work0->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); - work1->ptr.p_double[i] = y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); - } - for(i=0; i<=vcnt-1; i++) - { - v0 = ae_v_dotproduct(&work0->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - v1 = ae_v_dotproduct(&work1->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - result = result-v0*v1; - } - } - return result; -} - - -/************************************************************************* -Internal initialization subroutine - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -static void mincg_mincginitinternal(ae_int_t n, - double diffstep, - mincgstate* state, - ae_state *_state) -{ - ae_int_t i; - - - - /* - * Initialize - */ - state->teststep = 0; - state->n = n; - state->diffstep = diffstep; - mincgsetcond(state, 0, 0, 0, 0, _state); - mincgsetxrep(state, ae_false, _state); - mincgsetdrep(state, ae_false, _state); - mincgsetstpmax(state, 0, _state); - mincgsetcgtype(state, -1, _state); - mincgsetprecdefault(state, _state); - ae_vector_set_length(&state->xk, n, _state); - ae_vector_set_length(&state->dk, n, _state); - ae_vector_set_length(&state->xn, n, _state); - ae_vector_set_length(&state->dn, n, _state); - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->d, n, _state); - ae_vector_set_length(&state->g, n, _state); - ae_vector_set_length(&state->work0, n, _state); - ae_vector_set_length(&state->work1, n, _state); - ae_vector_set_length(&state->yk, n, _state); - ae_vector_set_length(&state->s, n, _state); - for(i=0; i<=n-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - } -} - - -ae_bool _mincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mincgstate *p = (mincgstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->diaghl2, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->vcorr, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !_linminstate_init(&p->lstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->work0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->work1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _mincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mincgstate *dst = (mincgstate*)_dst; - mincgstate *src = (mincgstate*)_src; - dst->n = src->n; - dst->epsg = src->epsg; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->stpmax = src->stpmax; - dst->suggestedstep = src->suggestedstep; - dst->xrep = src->xrep; - dst->drep = src->drep; - dst->cgtype = src->cgtype; - dst->prectype = src->prectype; - if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->diaghl2, &src->diaghl2, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->vcorr, &src->vcorr, _state, make_automatic) ) - return ae_false; - dst->vcnt = src->vcnt; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - dst->diffstep = src->diffstep; - dst->nfev = src->nfev; - dst->mcstage = src->mcstage; - dst->k = src->k; - if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - dst->fold = src->fold; - dst->stp = src->stp; - dst->curstpmax = src->curstpmax; - if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) ) - return ae_false; - dst->lastgoodstep = src->lastgoodstep; - dst->lastscaledstep = src->lastscaledstep; - dst->mcinfo = src->mcinfo; - dst->innerresetneeded = src->innerresetneeded; - dst->terminationneeded = src->terminationneeded; - dst->trimthreshold = src->trimthreshold; - dst->rstimer = src->rstimer; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - dst->needf = src->needf; - dst->needfg = src->needfg; - dst->xupdated = src->xupdated; - dst->algpowerup = src->algpowerup; - dst->lsstart = src->lsstart; - dst->lsend = src->lsend; - dst->teststep = src->teststep; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->repiterationscount = src->repiterationscount; - dst->repnfev = src->repnfev; - dst->repvaridx = src->repvaridx; - dst->repterminationtype = src->repterminationtype; - dst->debugrestartscount = src->debugrestartscount; - if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) ) - return ae_false; - dst->fbase = src->fbase; - dst->fm2 = src->fm2; - dst->fm1 = src->fm1; - dst->fp1 = src->fp1; - dst->fp2 = src->fp2; - dst->betahs = src->betahs; - dst->betady = src->betady; - if( !ae_vector_init_copy(&dst->work0, &src->work0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->work1, &src->work1, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _mincgstate_clear(void* _p) -{ - mincgstate *p = (mincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->diagh); - ae_vector_clear(&p->diaghl2); - ae_matrix_clear(&p->vcorr); - ae_vector_clear(&p->s); - ae_vector_clear(&p->xk); - ae_vector_clear(&p->dk); - ae_vector_clear(&p->xn); - ae_vector_clear(&p->dn); - ae_vector_clear(&p->d); - ae_vector_clear(&p->yk); - ae_vector_clear(&p->x); - ae_vector_clear(&p->g); - _rcommstate_clear(&p->rstate); - _linminstate_clear(&p->lstate); - ae_vector_clear(&p->work0); - ae_vector_clear(&p->work1); -} - - -void _mincgstate_destroy(void* _p) -{ - mincgstate *p = (mincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->diagh); - ae_vector_destroy(&p->diaghl2); - ae_matrix_destroy(&p->vcorr); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->xk); - ae_vector_destroy(&p->dk); - ae_vector_destroy(&p->xn); - ae_vector_destroy(&p->dn); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->yk); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->g); - _rcommstate_destroy(&p->rstate); - _linminstate_destroy(&p->lstate); - ae_vector_destroy(&p->work0); - ae_vector_destroy(&p->work1); -} - - -ae_bool _mincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - mincgreport *p = (mincgreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _mincgreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - mincgreport *dst = (mincgreport*)_dst; - mincgreport *src = (mincgreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nfev = src->nfev; - dst->varidx = src->varidx; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _mincgreport_clear(void* _p) -{ - mincgreport *p = (mincgreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _mincgreport_destroy(void* _p) -{ - mincgreport *p = (mincgreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* - BOUND CONSTRAINED OPTIMIZATION - WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments subject to any -combination of: -* bound constraints -* linear inequality constraints -* linear equality constraints - -REQUIREMENTS: -* user must provide function value and gradient -* starting point X0 must be feasible or - not too far away from the feasible set -* grad(f) must be Lipschitz continuous on a level set: - L = { x : f(x)<=f(x0) } -* function must be defined everywhere on the feasible set F - -USAGE: - -Constrained optimization if far more complex than the unconstrained one. -Here we give very brief outline of the BLEIC optimizer. We strongly recommend -you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on optimization, which is available at http://www.alglib.net/optimization/ - -1. User initializes algorithm state with MinBLEICCreate() call - -2. USer adds boundary and/or linear constraints by calling - MinBLEICSetBC() and MinBLEICSetLC() functions. - -3. User sets stopping conditions with MinBLEICSetCond(). - -4. User calls MinBLEICOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -5. User calls MinBLEICResults() to get solution - -6. Optionally user may call MinBLEICRestartFrom() to solve another problem - with same N but another starting point. - MinBLEICRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size ofX - X - starting point, array[N]: - * it is better to set X to a feasible point - * but X can be infeasible, in which case algorithm will try - to find feasible point first, using X as initial - approximation. - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreate(ae_int_t n, - /* Real */ ae_vector* x, - minbleicstate* state, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix c; - ae_vector ct; - - ae_frame_make(_state, &_frame_block); - _minbleicstate_clear(state); - ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ct, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "MinBLEICCreate: N<1", _state); - ae_assert(x->cnt>=n, "MinBLEICCreate: Length(X)0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinBLEICSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. CG needs exact gradient values. Imprecise - gradient may slow down convergence, especially on highly nonlinear - problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreatef(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - minbleicstate* state, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix c; - ae_vector ct; - - ae_frame_make(_state, &_frame_block); - _minbleicstate_clear(state); - ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ct, 0, DT_INT, _state, ae_true); - - ae_assert(n>=1, "MinBLEICCreateF: N<1", _state); - ae_assert(x->cnt>=n, "MinBLEICCreateF: Length(X)nmain; - ae_assert(bndl->cnt>=n, "MinBLEICSetBC: Length(BndL)cnt>=n, "MinBLEICSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or -INF", _state); - state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; - state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); - state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; - state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); - } - sassetbc(&state->sas, bndl, bndu, _state); -} - - -/************************************************************************* -This function sets linear constraints for BLEIC optimizer. - -Linear constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetlc(minbleicstate* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double v; - - - n = state->nmain; - - /* - * First, check for errors in the inputs - */ - ae_assert(k>=0, "MinBLEICSetLC: K<0", _state); - ae_assert(c->cols>=n+1||k==0, "MinBLEICSetLC: Cols(C)rows>=k, "MinBLEICSetLC: Rows(C)cnt>=k, "MinBLEICSetLC: Length(CT)nec = 0; - state->nic = 0; - return; - } - - /* - * Equality constraints are stored first, in the upper - * NEC rows of State.CLEIC matrix. Inequality constraints - * are stored in the next NIC rows. - * - * NOTE: we convert inequality constraints to the form - * A*x<=b before copying them. - */ - rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); - state->nec = 0; - state->nic = 0; - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]==0 ) - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - state->nec = state->nec+1; - } - } - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]!=0 ) - { - if( ct->ptr.p_int[i]>0 ) - { - ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - else - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - state->nic = state->nic+1; - } - } - - /* - * Normalize rows of State.CLEIC: each row must have unit norm. - * Norm is calculated using first N elements (i.e. right part is - * not counted when we calculate norm). - */ - for(i=0; i<=k-1; i++) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->cleic.ptr.pp_double[i][j], _state); - } - if( ae_fp_eq(v,0) ) - { - continue; - } - v = 1/ae_sqrt(v, _state); - ae_v_muld(&state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n), v); - } - sassetlc(&state->sas, c, ct, k, _state); -} - - -/************************************************************************* -This function sets stopping conditions for the optimizer. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinBLEICSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection. - -NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform - slightly more than MaxIts iterations. I.e., MaxIts sets non-strict - limit on iterations count. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetcond(minbleicstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinBLEICSetCond: EpsG is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinBLEICSetCond: negative EpsG", _state); - ae_assert(ae_isfinite(epsf, _state), "MinBLEICSetCond: EpsF is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinBLEICSetCond: negative EpsF", _state); - ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetCond: EpsX is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinBLEICSetCond: negative EpsX", _state); - ae_assert(maxits>=0, "MinBLEICSetCond: negative MaxIts!", _state); - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->epsg = epsg; - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -This function sets scaling coefficients for BLEIC optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the BLEIC too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinBLEICSetPrec...() -functions. - -There is a special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetscale(minbleicstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(s->cnt>=state->nmain, "MinBLEICSetScale: Length(S)nmain-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinBLEICSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinBLEICSetScale: S contains zero elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } - sassetscale(&state->sas, s, _state); -} - - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdefault(minbleicstate* state, ae_state *_state) -{ - - - state->prectype = 0; -} - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE 1: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdiag(minbleicstate* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(d->cnt>=state->nmain, "MinBLEICSetPrecDiag: D is too short", _state); - for(i=0; i<=state->nmain-1; i++) - { - ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinBLEICSetPrecDiag: D contains infinite or NAN elements", _state); - ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinBLEICSetPrecDiag: D contains non-positive elements", _state); - } - rvectorsetlengthatleast(&state->diagh, state->nmain, _state); - state->prectype = 2; - for(i=0; i<=state->nmain-1; i++) - { - state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; - } -} - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinBLEICSetScale() -call (before or after MinBLEICSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecscale(minbleicstate* state, ae_state *_state) -{ - - - state->prectype = 3; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinBLEICOptimize(). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetxrep(minbleicstate* state, - ae_bool needxrep, - ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function turns on/off line search reports. -These reports are described in more details in developer-only comments on -MinBLEICState object. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedDRep- whether line search reports are needed or not - -This function is intended for private use only. Turning it on artificially -may cause program failure. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetdrep(minbleicstate* state, - ae_bool needdrep, - ae_state *_state) -{ - - - state->drep = needdrep; -} - - -/************************************************************************* -This function sets maximum step length - -IMPORTANT: this feature is hard to combine with preconditioning. You can't -set upper limit on step length, when you solve optimization problem with -linear (non-boundary) constraints AND preconditioner turned on. - -When non-boundary constraints are present, you have to either a) use -preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! -In this case algorithm will terminate with appropriate error code. - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which lead to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetstpmax(minbleicstate* state, - double stpmax, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "MinBLEICSetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "MinBLEICSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() - for numerical differentiation) you should choose appropriate variant of - MinBLEICOptimize() - one which accepts function AND gradient or one - which accepts function ONLY. - - Be careful to choose variant of MinBLEICOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinBLEICOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinBLEICOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinBLEICCreateF() | work FAIL - MinBLEICCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinBLEICOptimize() version. Attemps to use such - combination (for example, to create optimizer with MinBLEICCreateF() - and to pass gradient information to MinCGOptimize()) will lead to - exception being thrown. Either you did not pass gradient when it WAS - needed or you passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -ae_bool minbleiciteration(minbleicstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t m; - ae_int_t i; - ae_int_t j; - double v; - double vv; - ae_int_t badbfgsits; - ae_bool b; - ae_int_t nextaction; - ae_int_t mcinfo; - ae_int_t actstatus; - ae_int_t ic; - double penalty; - double ginit; - double gdecay; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - i = state->rstate.ia.ptr.p_int[2]; - j = state->rstate.ia.ptr.p_int[3]; - badbfgsits = state->rstate.ia.ptr.p_int[4]; - nextaction = state->rstate.ia.ptr.p_int[5]; - mcinfo = state->rstate.ia.ptr.p_int[6]; - actstatus = state->rstate.ia.ptr.p_int[7]; - ic = state->rstate.ia.ptr.p_int[8]; - b = state->rstate.ba.ptr.p_bool[0]; - v = state->rstate.ra.ptr.p_double[0]; - vv = state->rstate.ra.ptr.p_double[1]; - penalty = state->rstate.ra.ptr.p_double[2]; - ginit = state->rstate.ra.ptr.p_double[3]; - gdecay = state->rstate.ra.ptr.p_double[4]; - } - else - { - n = -983; - m = -989; - i = -834; - j = 900; - badbfgsits = -287; - nextaction = 364; - mcinfo = 214; - actstatus = -338; - ic = -686; - b = ae_false; - v = 585; - vv = 497; - penalty = -271; - ginit = -581; - gdecay = 745; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - if( state->rstate.stage==14 ) - { - goto lbl_14; - } - if( state->rstate.stage==15 ) - { - goto lbl_15; - } - if( state->rstate.stage==16 ) - { - goto lbl_16; - } - if( state->rstate.stage==17 ) - { - goto lbl_17; - } - if( state->rstate.stage==18 ) - { - goto lbl_18; - } - if( state->rstate.stage==19 ) - { - goto lbl_19; - } - if( state->rstate.stage==20 ) - { - goto lbl_20; - } - if( state->rstate.stage==21 ) - { - goto lbl_21; - } - if( state->rstate.stage==22 ) - { - goto lbl_22; - } - if( state->rstate.stage==23 ) - { - goto lbl_23; - } - if( state->rstate.stage==24 ) - { - goto lbl_24; - } - if( state->rstate.stage==25 ) - { - goto lbl_25; - } - if( state->rstate.stage==26 ) - { - goto lbl_26; - } - if( state->rstate.stage==27 ) - { - goto lbl_27; - } - if( state->rstate.stage==28 ) - { - goto lbl_28; - } - if( state->rstate.stage==29 ) - { - goto lbl_29; - } - if( state->rstate.stage==30 ) - { - goto lbl_30; - } - if( state->rstate.stage==31 ) - { - goto lbl_31; - } - if( state->rstate.stage==32 ) - { - goto lbl_32; - } - if( state->rstate.stage==33 ) - { - goto lbl_33; - } - if( state->rstate.stage==34 ) - { - goto lbl_34; - } - if( state->rstate.stage==35 ) - { - goto lbl_35; - } - if( state->rstate.stage==36 ) - { - goto lbl_36; - } - if( state->rstate.stage==37 ) - { - goto lbl_37; - } - if( state->rstate.stage==38 ) - { - goto lbl_38; - } - if( state->rstate.stage==39 ) - { - goto lbl_39; - } - if( state->rstate.stage==40 ) - { - goto lbl_40; - } - if( state->rstate.stage==41 ) - { - goto lbl_41; - } - - /* - * Routine body - */ - - /* - * Algorithm parameters: - * * M number of L-BFGS corrections. - * This coefficient remains fixed during iterations. - * * GDecay desired decrease of constrained gradient during L-BFGS iterations. - * This coefficient is decreased after each L-BFGS round until - * it reaches minimum decay. - */ - m = ae_minint(5, state->nmain, _state); - gdecay = minbleic_initialdecay; - - /* - * Init - */ - n = state->nmain; - state->repterminationtype = 0; - state->repinneriterationscount = 0; - state->repouteriterationscount = 0; - state->repnfev = 0; - state->repvaridx = -1; - state->repdebugeqerr = 0.0; - state->repdebugfs = _state->v_nan; - state->repdebugff = _state->v_nan; - state->repdebugdx = _state->v_nan; - if( ae_fp_neq(state->stpmax,0)&&state->prectype!=0 ) - { - state->repterminationtype = -10; - result = ae_false; - return result; - } - rvectorsetlengthatleast(&state->rho, m, _state); - rvectorsetlengthatleast(&state->theta, m, _state); - rmatrixsetlengthatleast(&state->yk, m, n, _state); - rmatrixsetlengthatleast(&state->sk, m, n, _state); - - /* - * Fill TmpPrec with current preconditioner - */ - rvectorsetlengthatleast(&state->tmpprec, n, _state); - for(i=0; i<=n-1; i++) - { - if( state->prectype==2 ) - { - state->tmpprec.ptr.p_double[i] = state->diagh.ptr.p_double[i]; - continue; - } - if( state->prectype==3 ) - { - state->tmpprec.ptr.p_double[i] = 1/ae_sqr(state->s.ptr.p_double[i], _state); - continue; - } - state->tmpprec.ptr.p_double[i] = 1; - } - sassetprecdiag(&state->sas, &state->tmpprec, _state); - - /* - * Start optimization - */ - if( !sasstartoptimization(&state->sas, &state->xstart, _state) ) - { - state->repterminationtype = -3; - result = ae_false; - return result; - } - - /* - * Check correctness of user-supplied gradient - */ - if( !(ae_fp_eq(state->diffstep,0)&&ae_fp_greater(state->teststep,0)) ) - { - goto lbl_42; - } - minbleic_clearrequestfields(state, _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->needfg = ae_true; - i = 0; -lbl_44: - if( i>n-1 ) - { - goto lbl_46; - } - ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->sas.xc.ptr.p_double[i],state->bndl.ptr.p_double[i]), "MinBLEICIteration: internal error(State.X is out of bounds)", _state); - ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->sas.xc.ptr.p_double[i],state->bndu.ptr.p_double[i]), "MinBLEICIteration: internal error(State.X is out of bounds)", _state); - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - state->xm1 = state->x.ptr.p_double[i]; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->fm1 = state->f; - state->gm1 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; - if( state->hasbndu.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - state->xp1 = state->x.ptr.p_double[i]; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->fp1 = state->f; - state->gp1 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = (state->xm1+state->xp1)/2; - if( state->hasbndl.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - if( state->hasbndu.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->x.ptr.p_double[i] = v; - if( !derivativecheck(state->fm1, state->gm1, state->fp1, state->gp1, state->f, state->g.ptr.p_double[i], state->xp1-state->xm1, _state) ) - { - state->repvaridx = i; - state->repterminationtype = -7; - sasstopoptimization(&state->sas, _state); - result = ae_false; - return result; - } - i = i+1; - goto lbl_44; -lbl_46: - state->needfg = ae_false; -lbl_42: - - /* - * Main cycle of BLEIC-PG algorithm - */ - state->repterminationtype = 4; - badbfgsits = 0; - state->lastgoodstep = 0; - state->lastscaledgoodstep = 0; - state->maxscaledgrad = 0; - state->nonmonotoniccnt = n+state->nic; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minbleic_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_47; - } - state->needfg = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needfg = ae_false; - goto lbl_48; -lbl_47: - state->needf = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->needf = ae_false; -lbl_48: - state->fc = state->f; - trimprepare(state->f, &state->trimthreshold, _state); - state->repnfev = state->repnfev+1; - if( !state->xrep ) - { - goto lbl_49; - } - - /* - * Report current point - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fc; - state->xupdated = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->xupdated = ae_false; -lbl_49: -lbl_51: - if( ae_false ) - { - goto lbl_52; - } - - /* - * Phase 1 - * - * (a) calculate unconstrained gradient - * (b) determine active set - * (c) update MaxScaledGrad - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minbleic_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_53; - } - - /* - * Analytic gradient - */ - state->needfg = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->needfg = ae_false; - goto lbl_54; -lbl_53: - - /* - * Numerical differentiation - */ - state->needf = ae_true; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->fbase = state->f; - i = 0; -lbl_55: - if( i>n-1 ) - { - goto lbl_57; - } - v = state->x.ptr.p_double[i]; - b = ae_false; - if( state->hasbndl.ptr.p_bool[i] ) - { - b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); - } - if( state->hasbndu.ptr.p_bool[i] ) - { - b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); - } - if( b ) - { - goto lbl_58; - } - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - state->fp2 = state->f; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - goto lbl_59; -lbl_58: - state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; - state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) - { - state->xm1 = state->bndl.ptr.p_double[i]; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) - { - state->xp1 = state->bndu.ptr.p_double[i]; - } - state->x.ptr.p_double[i] = state->xm1; - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - state->fm1 = state->f; - state->x.ptr.p_double[i] = state->xp1; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->fp1 = state->f; - if( ae_fp_neq(state->xm1,state->xp1) ) - { - state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); - } - else - { - state->g.ptr.p_double[i] = 0; - } -lbl_59: - state->x.ptr.p_double[i] = v; - i = i+1; - goto lbl_55; -lbl_57: - state->f = state->fbase; - state->needf = ae_false; -lbl_54: - state->fc = state->f; - ae_v_move(&state->gc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasreactivateconstraintsprec(&state->sas, &state->gc, _state); - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->gc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - state->maxscaledgrad = ae_maxreal(state->maxscaledgrad, ae_sqrt(v, _state), _state); - - /* - * Phase 2: perform steepest descent step. - * - * NextAction control variable is set on exit from this loop: - * * NextAction>0 in case we have to proceed to Phase 3 (L-BFGS step) - * * NextAction<0 in case we have to proceed to Phase 1 (recalculate active set) - * * NextAction=0 in case we found solution (step size or function change are small enough) - */ - nextaction = 0; -lbl_60: - if( ae_false ) - { - goto lbl_61; - } - - /* - * Check gradient-based stopping criteria - */ - if( ae_fp_less_eq(sasscaledconstrainednorm(&state->sas, &state->gc, _state),state->epsg) ) - { - - /* - * Gradient is small enough, stop iterations - */ - state->repterminationtype = 4; - nextaction = 0; - goto lbl_61; - } - - /* - * Calculate normalized constrained descent direction, store to D. - * Try to use previous scaled step length as initial estimate for new step. - * - * NOTE: D can be exactly zero, in this case Stp is set to 1.0 - */ - sasconstraineddescentprec(&state->sas, &state->gc, &state->d, _state); - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(state->lastscaledgoodstep,0)&&ae_fp_greater(v,0) ) - { - state->stp = state->lastscaledgoodstep/v; - } - else - { - state->stp = 1.0; - } - - /* - * Calculate bound on step length. - * Enforce user-supplied limit on step length. - */ - sasexploredirection(&state->sas, &state->d, &state->curstpmax, &state->cidx, &state->cval, _state); - state->activationstep = state->curstpmax; - if( state->cidx>=0&&ae_fp_eq(state->activationstep,0) ) - { - sasimmediateactivation(&state->sas, state->cidx, state->cval, _state); - goto lbl_60; - } - if( ae_fp_greater(state->stpmax,0) ) - { - state->curstpmax = ae_minreal(state->curstpmax, state->stpmax, _state); - } - - /* - * Report beginning of line search (if requested by caller). - * See description of the MinBLEICState for more information - * about fields accessible to caller. - * - * Caller may do following: - * * change State.Stp and load better initial estimate of - * the step length. - */ - if( !state->drep ) - { - goto lbl_62; - } - minbleic_clearrequestfields(state, _state); - state->lsstart = ae_true; - state->lbfgssearch = ae_false; - state->boundedstep = state->cidx>=0; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->g.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fc; - state->rstate.stage = 14; - goto lbl_rcomm; -lbl_14: - state->lsstart = ae_false; -lbl_62: - - /* - * Perform optimization of F along XC+alpha*D. - */ - state->mcstage = 0; - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->gn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fn = state->fc; - mcsrch(n, &state->xn, &state->fn, &state->gn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); -lbl_64: - if( state->mcstage==0 ) - { - goto lbl_65; - } - - /* - * Enforce constraints (correction) in XN. - * Copy current point from XN to X. - */ - sascorrection(&state->sas, &state->xn, &penalty, _state); - for(i=0; i<=n-1; i++) - { - state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; - } - - /* - * Gradient, either user-provided or numerical differentiation - */ - minbleic_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_66; - } - - /* - * Analytic gradient - */ - state->needfg = ae_true; - state->rstate.stage = 15; - goto lbl_rcomm; -lbl_15: - state->needfg = ae_false; - state->repnfev = state->repnfev+1; - goto lbl_67; -lbl_66: - - /* - * Numerical differentiation - */ - state->needf = ae_true; - state->rstate.stage = 16; - goto lbl_rcomm; -lbl_16: - state->fbase = state->f; - i = 0; -lbl_68: - if( i>n-1 ) - { - goto lbl_70; - } - v = state->x.ptr.p_double[i]; - b = ae_false; - if( state->hasbndl.ptr.p_bool[i] ) - { - b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); - } - if( state->hasbndu.ptr.p_bool[i] ) - { - b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); - } - if( b ) - { - goto lbl_71; - } - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 17; - goto lbl_rcomm; -lbl_17: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 18; - goto lbl_rcomm; -lbl_18: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 19; - goto lbl_rcomm; -lbl_19: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 20; - goto lbl_rcomm; -lbl_20: - state->fp2 = state->f; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - state->repnfev = state->repnfev+4; - goto lbl_72; -lbl_71: - state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; - state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) - { - state->xm1 = state->bndl.ptr.p_double[i]; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) - { - state->xp1 = state->bndu.ptr.p_double[i]; - } - state->x.ptr.p_double[i] = state->xm1; - state->rstate.stage = 21; - goto lbl_rcomm; -lbl_21: - state->fm1 = state->f; - state->x.ptr.p_double[i] = state->xp1; - state->rstate.stage = 22; - goto lbl_rcomm; -lbl_22: - state->fp1 = state->f; - if( ae_fp_neq(state->xm1,state->xp1) ) - { - state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); - } - else - { - state->g.ptr.p_double[i] = 0; - } - state->repnfev = state->repnfev+2; -lbl_72: - state->x.ptr.p_double[i] = v; - i = i+1; - goto lbl_68; -lbl_70: - state->f = state->fbase; - state->needf = ae_false; -lbl_67: - - /* - * Back to MCSRCH - * - * NOTE: penalty term from correction is added to FN in order - * to penalize increase in infeasibility. - */ - state->fn = state->f+minbleic_penaltyfactor*state->maxscaledgrad*penalty; - ae_v_move(&state->gn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - trimfunction(&state->fn, &state->gn, n, state->trimthreshold, _state); - mcsrch(n, &state->xn, &state->fn, &state->gn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); - goto lbl_64; -lbl_65: - - /* - * Handle possible failure of the line search - */ - if( mcinfo!=1&&mcinfo!=5 ) - { - - /* - * We can not find step which decreases function value. We have - * two possibilities: - * (a) numerical properties of the function do not allow us to - * find good solution. - * (b) we are close to activation of some constraint, and it is - * so close that step which activates it leads to change in - * target function which is smaller than numerical noise. - * - * Optimization algorithm must be able to handle case (b), because - * inability to handle it will cause failure when algorithm - * started very close to boundary of the feasible area. - * - * In order to correctly handle such cases we allow limited amount - * of small steps which increase function value. - */ - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->d.ptr.p_double[i]*state->curstpmax/state->s.ptr.p_double[i], _state); - } - v = ae_sqrt(v, _state); - if( (state->cidx>=0&&ae_fp_less_eq(v,minbleic_maxnonmonotoniclen))&&state->nonmonotoniccnt>0 ) - { - - /* - * We enforce non-monotonic step: - * * Stp := CurStpMax - * * MCINFO := 5 - * * XN := XC+CurStpMax*D - * * non-monotonic counter is decreased - */ - state->stp = state->curstpmax; - mcinfo = 5; - v = state->curstpmax; - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - state->nonmonotoniccnt = state->nonmonotoniccnt-1; - } - else - { - - /* - * Numerical properties of the function does not allow us to solve problem - */ - state->repterminationtype = 7; - nextaction = 0; - goto lbl_61; - } - } - - /* - * Current point is updated. - */ - ae_v_move(&state->xp.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->gp.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fp = state->fc; - actstatus = sasmoveto(&state->sas, &state->xn, state->cidx>=0&&ae_fp_greater_eq(state->stp,state->activationstep), state->cidx, state->cval, _state); - ae_v_move(&state->gc.ptr.p_double[0], 1, &state->gn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fc = state->fn; - state->repinneriterationscount = state->repinneriterationscount+1; - if( !state->xrep ) - { - goto lbl_73; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minbleic_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 23; - goto lbl_rcomm; -lbl_23: - state->xupdated = ae_false; -lbl_73: - - /* - * Check for stopping. - * - * Step, gradient and function-based stopping criteria are tested only - * for steps which satisfy Wolfe conditions. - * - * MaxIts-based stopping condition is checked for all steps - */ - if( mcinfo==1 ) - { - - /* - * Step is small enough - */ - v = 0; - vv = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); - vv = vv+ae_sqr(state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i], _state); - } - v = ae_sqrt(v, _state); - vv = ae_sqrt(vv, _state); - if( ae_fp_less_eq(v,state->epsx) ) - { - state->repterminationtype = 2; - nextaction = 0; - goto lbl_61; - } - state->lastgoodstep = vv; - minbleic_updateestimateofgoodstep(&state->lastscaledgoodstep, v, _state); - - /* - * Function change is small enough - */ - if( ae_fp_less_eq(ae_fabs(state->fp-state->fc, _state),state->epsf*ae_maxreal(ae_fabs(state->fc, _state), ae_maxreal(ae_fabs(state->fp, _state), 1.0, _state), _state)) ) - { - - /* - * Function change is small enough - */ - state->repterminationtype = 1; - nextaction = 0; - goto lbl_61; - } - } - if( state->maxits>0&&state->repinneriterationscount>=state->maxits ) - { - - /* - * Required number of iterations was performed - */ - state->repterminationtype = 5; - nextaction = 0; - goto lbl_61; - } - - /* - * Decide where to move: - * * in case only "candidate" constraints were activated, repeat stage 2 - * * in case no constraints was activated, move to stage 3 - * * otherwise, move to stage 1 (re-evaluation of the active set) - */ - if( actstatus==0 ) - { - goto lbl_60; - } - if( actstatus<0 ) - { - nextaction = 1; - } - else - { - nextaction = -1; - } - goto lbl_61; - goto lbl_60; -lbl_61: - if( nextaction<0 ) - { - goto lbl_51; - } - if( nextaction==0 ) - { - goto lbl_52; - } - - /* - * Phase 3: L-BFGS step - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minbleic_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_75; - } - - /* - * Analytic gradient - */ - state->needfg = ae_true; - state->rstate.stage = 24; - goto lbl_rcomm; -lbl_24: - state->needfg = ae_false; - state->repnfev = state->repnfev+1; - goto lbl_76; -lbl_75: - - /* - * Numerical differentiation - */ - state->needf = ae_true; - state->rstate.stage = 25; - goto lbl_rcomm; -lbl_25: - state->fbase = state->f; - i = 0; -lbl_77: - if( i>n-1 ) - { - goto lbl_79; - } - v = state->x.ptr.p_double[i]; - b = ae_false; - if( state->hasbndl.ptr.p_bool[i] ) - { - b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); - } - if( state->hasbndu.ptr.p_bool[i] ) - { - b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); - } - if( b ) - { - goto lbl_80; - } - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 26; - goto lbl_rcomm; -lbl_26: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 27; - goto lbl_rcomm; -lbl_27: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 28; - goto lbl_rcomm; -lbl_28: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 29; - goto lbl_rcomm; -lbl_29: - state->fp2 = state->f; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - state->repnfev = state->repnfev+4; - goto lbl_81; -lbl_80: - state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; - state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) - { - state->xm1 = state->bndl.ptr.p_double[i]; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) - { - state->xp1 = state->bndu.ptr.p_double[i]; - } - state->x.ptr.p_double[i] = state->xm1; - state->rstate.stage = 30; - goto lbl_rcomm; -lbl_30: - state->fm1 = state->f; - state->x.ptr.p_double[i] = state->xp1; - state->rstate.stage = 31; - goto lbl_rcomm; -lbl_31: - state->fp1 = state->f; - if( ae_fp_neq(state->xm1,state->xp1) ) - { - state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); - } - else - { - state->g.ptr.p_double[i] = 0; - } - state->repnfev = state->repnfev+2; -lbl_81: - state->x.ptr.p_double[i] = v; - i = i+1; - goto lbl_77; -lbl_79: - state->f = state->fbase; - state->needf = ae_false; -lbl_76: - state->fc = state->f; - trimprepare(state->fc, &state->trimthreshold, _state); - ae_v_move(&state->gc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasconstraineddirection(&state->sas, &state->gc, _state); - sasconstraineddirectionprec(&state->sas, &state->d, _state); - ginit = 0.0; - for(i=0; i<=n-1; i++) - { - ginit = ginit+ae_sqr(state->gc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - ginit = ae_sqrt(ginit, _state); - state->k = 0; -lbl_82: - if( state->k>n ) - { - goto lbl_83; - } - - /* - * Main cycle: prepare to 1-D line search - */ - state->p = state->k%m; - state->q = ae_minint(state->k, m-1, _state); - - /* - * Store X[k], G[k] - */ - ae_v_moveneg(&state->sk.ptr.pp_double[state->p][0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_moveneg(&state->yk.ptr.pp_double[state->p][0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Try to use previous scaled step length as initial estimate for new step. - */ - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(state->lastscaledgoodstep,0)&&ae_fp_greater(v,0) ) - { - state->stp = state->lastscaledgoodstep/v; - } - else - { - state->stp = 1.0; - } - - /* - * Calculate bound on step length - */ - sasexploredirection(&state->sas, &state->d, &state->curstpmax, &state->cidx, &state->cval, _state); - state->activationstep = state->curstpmax; - if( state->cidx>=0&&ae_fp_eq(state->activationstep,0) ) - { - goto lbl_83; - } - if( ae_fp_greater(state->stpmax,0) ) - { - v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = ae_sqrt(v, _state); - if( ae_fp_greater(v,0) ) - { - state->curstpmax = ae_minreal(state->curstpmax, state->stpmax/v, _state); - } - } - - /* - * Report beginning of line search (if requested by caller). - * See description of the MinBLEICState for more information - * about fields accessible to caller. - * - * Caller may do following: - * * change State.Stp and load better initial estimate of - * the step length. - * Caller may not terminate algorithm. - */ - if( !state->drep ) - { - goto lbl_84; - } - minbleic_clearrequestfields(state, _state); - state->lsstart = ae_true; - state->lbfgssearch = ae_true; - state->boundedstep = state->cidx>=0; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 32; - goto lbl_rcomm; -lbl_32: - state->lsstart = ae_false; -lbl_84: - - /* - * Minimize F(x+alpha*d) - */ - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->gn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fn = state->fc; - state->mcstage = 0; - mcsrch(n, &state->xn, &state->fn, &state->gn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); -lbl_86: - if( state->mcstage==0 ) - { - goto lbl_87; - } - - /* - * Perform correction (constraints are enforced) - * Copy XN to X - */ - sascorrection(&state->sas, &state->xn, &penalty, _state); - for(i=0; i<=n-1; i++) - { - state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; - } - - /* - * Gradient, either user-provided or numerical differentiation - */ - minbleic_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_88; - } - - /* - * Analytic gradient - */ - state->needfg = ae_true; - state->rstate.stage = 33; - goto lbl_rcomm; -lbl_33: - state->needfg = ae_false; - state->repnfev = state->repnfev+1; - goto lbl_89; -lbl_88: - - /* - * Numerical differentiation - */ - state->needf = ae_true; - state->rstate.stage = 34; - goto lbl_rcomm; -lbl_34: - state->fbase = state->f; - i = 0; -lbl_90: - if( i>n-1 ) - { - goto lbl_92; - } - v = state->x.ptr.p_double[i]; - b = ae_false; - if( state->hasbndl.ptr.p_bool[i] ) - { - b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); - } - if( state->hasbndu.ptr.p_bool[i] ) - { - b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); - } - if( b ) - { - goto lbl_93; - } - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 35; - goto lbl_rcomm; -lbl_35: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 36; - goto lbl_rcomm; -lbl_36: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 37; - goto lbl_rcomm; -lbl_37: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 38; - goto lbl_rcomm; -lbl_38: - state->fp2 = state->f; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - state->repnfev = state->repnfev+4; - goto lbl_94; -lbl_93: - state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; - state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; - if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) - { - state->xm1 = state->bndl.ptr.p_double[i]; - } - if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) - { - state->xp1 = state->bndu.ptr.p_double[i]; - } - state->x.ptr.p_double[i] = state->xm1; - state->rstate.stage = 39; - goto lbl_rcomm; -lbl_39: - state->fm1 = state->f; - state->x.ptr.p_double[i] = state->xp1; - state->rstate.stage = 40; - goto lbl_rcomm; -lbl_40: - state->fp1 = state->f; - if( ae_fp_neq(state->xm1,state->xp1) ) - { - state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); - } - else - { - state->g.ptr.p_double[i] = 0; - } - state->repnfev = state->repnfev+2; -lbl_94: - state->x.ptr.p_double[i] = v; - i = i+1; - goto lbl_90; -lbl_92: - state->f = state->fbase; - state->needf = ae_false; -lbl_89: - - /* - * Back to MCSRCH - * - * NOTE: penalty term from correction is added to FN in order - * to penalize increase in infeasibility. - */ - state->fn = state->f+minbleic_penaltyfactor*state->maxscaledgrad*penalty; - ae_v_move(&state->gn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasconstraineddirection(&state->sas, &state->gn, _state); - trimfunction(&state->fn, &state->gn, n, state->trimthreshold, _state); - mcsrch(n, &state->xn, &state->fn, &state->gn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); - goto lbl_86; -lbl_87: - ae_v_add(&state->sk.ptr.pp_double[state->p][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->yk.ptr.pp_double[state->p][0], 1, &state->gn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Handle possible failure of the line search - */ - if( mcinfo!=1&&mcinfo!=5 ) - { - goto lbl_83; - } - - /* - * Current point is updated. - */ - ae_v_move(&state->xp.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->gp.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fp = state->fc; - actstatus = sasmoveto(&state->sas, &state->xn, state->cidx>=0&&ae_fp_greater_eq(state->stp,state->activationstep), state->cidx, state->cval, _state); - ae_v_move(&state->gc.ptr.p_double[0], 1, &state->gn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fc = state->fn; - if( !state->xrep ) - { - goto lbl_95; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minbleic_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 41; - goto lbl_rcomm; -lbl_41: - state->xupdated = ae_false; -lbl_95: - state->repinneriterationscount = state->repinneriterationscount+1; - - /* - * Update length of the good step - */ - if( mcinfo==1 ) - { - v = 0; - vv = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); - vv = vv+ae_sqr(state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i], _state); - } - state->lastgoodstep = ae_sqrt(vv, _state); - minbleic_updateestimateofgoodstep(&state->lastscaledgoodstep, ae_sqrt(v, _state), _state); - } - - /* - * Termination of the L-BFGS algorithm: - * a) line search was performed with activation of constraint - * b) scaled gradient decreased below GDecay - * c) iterations counter >= MaxIts - */ - if( actstatus>=0 ) - { - goto lbl_83; - } - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->gc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - if( ae_fp_less(ae_sqrt(v, _state),gdecay*ginit) ) - { - goto lbl_83; - } - if( state->maxits>0&&state->repinneriterationscount>=state->maxits ) - { - goto lbl_83; - } - - /* - * Update L-BFGS model: - * * calculate Rho[k] - * * calculate d(k+1) = -H(k+1)*g(k+1) - * (use constrained preconditioner to perform multiplication) - */ - v = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->sk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); - vv = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->yk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); - if( ae_fp_eq(v,0)||ae_fp_eq(vv,0) ) - { - goto lbl_83; - } - state->rho.ptr.p_double[state->p] = 1/v; - ae_v_move(&state->work.ptr.p_double[0], 1, &state->gn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=state->k; i>=state->k-state->q; i--) - { - ic = i%m; - v = ae_v_dotproduct(&state->sk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->theta.ptr.p_double[ic] = v; - vv = v*state->rho.ptr.p_double[ic]; - ae_v_subd(&state->work.ptr.p_double[0], 1, &state->yk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); - } - sasconstraineddirectionprec(&state->sas, &state->work, _state); - for(i=state->k-state->q; i<=state->k; i++) - { - ic = i%m; - v = ae_v_dotproduct(&state->yk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]); - ae_v_addd(&state->work.ptr.p_double[0], 1, &state->sk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); - } - ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->k = state->k+1; - goto lbl_82; -lbl_83: - - /* - * Decrease decay coefficient. Subsequent L-BFGS stages will - * have more stringent stopping criteria. - */ - gdecay = ae_maxreal(gdecay*minbleic_decaycorrection, minbleic_mindecay, _state); - goto lbl_51; -lbl_52: - sasstopoptimization(&state->sas, _state); - state->repouteriterationscount = 1; - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = i; - state->rstate.ia.ptr.p_int[3] = j; - state->rstate.ia.ptr.p_int[4] = badbfgsits; - state->rstate.ia.ptr.p_int[5] = nextaction; - state->rstate.ia.ptr.p_int[6] = mcinfo; - state->rstate.ia.ptr.p_int[7] = actstatus; - state->rstate.ia.ptr.p_int[8] = ic; - state->rstate.ba.ptr.p_bool[0] = b; - state->rstate.ra.ptr.p_double[0] = v; - state->rstate.ra.ptr.p_double[1] = vv; - state->rstate.ra.ptr.p_double[2] = penalty; - state->rstate.ra.ptr.p_double[3] = ginit; - state->rstate.ra.ptr.p_double[4] = gdecay; - return result; -} - - -/************************************************************************* -BLEIC results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one: - * -7 gradient verification failed. - See MinBLEICSetGradientCheck() for more information. - * -3 inconsistent constraints. Feasible point is - either nonexistent or too hard to find. Try to - restart optimizer with better initial approximation - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - More information about fields of this structure can be - found in the comments on MinBLEICReport datatype. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresults(minbleicstate* state, - /* Real */ ae_vector* x, - minbleicreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _minbleicreport_clear(rep); - - minbleicresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -BLEIC results - -Buffered implementation of MinBLEICResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresultsbuf(minbleicstate* state, - /* Real */ ae_vector* x, - minbleicreport* rep, - ae_state *_state) -{ - ae_int_t i; - - - if( x->cntnmain ) - { - ae_vector_set_length(x, state->nmain, _state); - } - rep->iterationscount = state->repinneriterationscount; - rep->inneriterationscount = state->repinneriterationscount; - rep->outeriterationscount = state->repouteriterationscount; - rep->nfev = state->repnfev; - rep->varidx = state->repvaridx; - rep->terminationtype = state->repterminationtype; - if( state->repterminationtype>0 ) - { - ae_v_move(&x->ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,state->nmain-1)); - } - else - { - for(i=0; i<=state->nmain-1; i++) - { - x->ptr.p_double[i] = _state->v_nan; - } - } - rep->debugeqerr = state->repdebugeqerr; - rep->debugfs = state->repdebugfs; - rep->debugff = state->repdebugff; - rep->debugdx = state->repdebugdx; - rep->debugfeasqpits = state->repdebugfeasqpits; - rep->debugfeasgpaits = state->repdebugfeasgpaits; -} - - -/************************************************************************* -This subroutine restarts algorithm from new point. -All optimization parameters (including constraints) are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - X - new starting point. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicrestartfrom(minbleicstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - - - n = state->nmain; - - /* - * First, check for errors in the inputs - */ - ae_assert(x->cnt>=n, "MinBLEICRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * prepare RComm facilities - */ - ae_vector_set_length(&state->rstate.ia, 8+1, _state); - ae_vector_set_length(&state->rstate.ba, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 4+1, _state); - state->rstate.stage = -1; - minbleic_clearrequestfields(state, _state); - sasstopoptimization(&state->sas, _state); -} - - -/************************************************************************* -This subroutine finalizes internal structures after emergency termination -from State.LSStart report (see comments on MinBLEICState for more information). - -INPUT PARAMETERS: - State - structure after exit from LSStart report - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicemergencytermination(minbleicstate* state, ae_state *_state) -{ - - - sasstopoptimization(&state->sas, _state); -} - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinBLEICOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinBLEICSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetgradientcheck(minbleicstate* state, - double teststep, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(teststep, _state), "MinBLEICSetGradientCheck: TestStep contains NaN or Infinite", _state); - ae_assert(ae_fp_greater_eq(teststep,0), "MinBLEICSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); - state->teststep = teststep; -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forget to clear something) -*************************************************************************/ -static void minbleic_clearrequestfields(minbleicstate* state, - ae_state *_state) -{ - - - state->needf = ae_false; - state->needfg = ae_false; - state->xupdated = ae_false; - state->lsstart = ae_false; -} - - -/************************************************************************* -Internal initialization subroutine -*************************************************************************/ -static void minbleic_minbleicinitinternal(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - minbleicstate* state, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_matrix c; - ae_vector ct; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ct, 0, DT_INT, _state, ae_true); - - - /* - * Initialize - */ - state->teststep = 0; - state->nmain = n; - state->diffstep = diffstep; - sasinit(n, &state->sas, _state); - ae_vector_set_length(&state->bndl, n, _state); - ae_vector_set_length(&state->hasbndl, n, _state); - ae_vector_set_length(&state->bndu, n, _state); - ae_vector_set_length(&state->hasbndu, n, _state); - ae_vector_set_length(&state->xstart, n, _state); - ae_vector_set_length(&state->gc, n, _state); - ae_vector_set_length(&state->xn, n, _state); - ae_vector_set_length(&state->gn, n, _state); - ae_vector_set_length(&state->xp, n, _state); - ae_vector_set_length(&state->gp, n, _state); - ae_vector_set_length(&state->d, n, _state); - ae_vector_set_length(&state->s, n, _state); - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->g, n, _state); - ae_vector_set_length(&state->work, n, _state); - for(i=0; i<=n-1; i++) - { - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->hasbndl.ptr.p_bool[i] = ae_false; - state->bndu.ptr.p_double[i] = _state->v_posinf; - state->hasbndu.ptr.p_bool[i] = ae_false; - state->s.ptr.p_double[i] = 1.0; - } - minbleicsetlc(state, &c, &ct, 0, _state); - minbleicsetcond(state, 0.0, 0.0, 0.0, 0, _state); - minbleicsetxrep(state, ae_false, _state); - minbleicsetdrep(state, ae_false, _state); - minbleicsetstpmax(state, 0.0, _state); - minbleicsetprecdefault(state, _state); - minbleicrestartfrom(state, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -This subroutine updates estimate of the good step length given: -1) previous estimate -2) new length of the good step - -It makes sure that estimate does not change too rapidly - ratio of new and -old estimates will be at least 0.01, at most 100.0 - -In case previous estimate of good step is zero (no estimate), new estimate -is used unconditionally. - - -- ALGLIB -- - Copyright 16.01.2013 by Bochkanov Sergey -*************************************************************************/ -static void minbleic_updateestimateofgoodstep(double* estimate, - double newstep, - ae_state *_state) -{ - - - if( ae_fp_eq(*estimate,0) ) - { - *estimate = newstep; - return; - } - if( ae_fp_less(newstep,*estimate*0.01) ) - { - *estimate = *estimate*0.01; - return; - } - if( ae_fp_greater(newstep,*estimate*100) ) - { - *estimate = *estimate*100; - return; - } - *estimate = newstep; -} - - -ae_bool _minbleicstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minbleicstate *p = (minbleicstate*)_p; - ae_touch_ptr((void*)p); - if( !_sactiveset_init(&p->sas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gp, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_snnlssolver_init(&p->solver, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpprec, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_linminstate_init(&p->lstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->sk, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->theta, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _minbleicstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minbleicstate *dst = (minbleicstate*)_dst; - minbleicstate *src = (minbleicstate*)_src; - dst->nmain = src->nmain; - dst->nslack = src->nslack; - dst->epsg = src->epsg; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->drep = src->drep; - dst->stpmax = src->stpmax; - dst->diffstep = src->diffstep; - if( !_sactiveset_init_copy(&dst->sas, &src->sas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - dst->prectype = src->prectype; - if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - dst->needf = src->needf; - dst->needfg = src->needfg; - dst->xupdated = src->xupdated; - dst->lsstart = src->lsstart; - dst->lbfgssearch = src->lbfgssearch; - dst->boundedstep = src->boundedstep; - dst->teststep = src->teststep; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gn, &src->gn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gp, &src->gp, _state, make_automatic) ) - return ae_false; - dst->fc = src->fc; - dst->fn = src->fn; - dst->fp = src->fp; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic) ) - return ae_false; - dst->nec = src->nec; - dst->nic = src->nic; - dst->lastgoodstep = src->lastgoodstep; - dst->lastscaledgoodstep = src->lastscaledgoodstep; - dst->maxscaledgrad = src->maxscaledgrad; - if( !ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - dst->repinneriterationscount = src->repinneriterationscount; - dst->repouteriterationscount = src->repouteriterationscount; - dst->repnfev = src->repnfev; - dst->repvaridx = src->repvaridx; - dst->repterminationtype = src->repterminationtype; - dst->repdebugeqerr = src->repdebugeqerr; - dst->repdebugfs = src->repdebugfs; - dst->repdebugff = src->repdebugff; - dst->repdebugdx = src->repdebugdx; - dst->repdebugfeasqpits = src->repdebugfeasqpits; - dst->repdebugfeasgpaits = src->repdebugfeasgpaits; - if( !ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic) ) - return ae_false; - if( !_snnlssolver_init_copy(&dst->solver, &src->solver, _state, make_automatic) ) - return ae_false; - dst->fbase = src->fbase; - dst->fm2 = src->fm2; - dst->fm1 = src->fm1; - dst->fp1 = src->fp1; - dst->fp2 = src->fp2; - dst->xm1 = src->xm1; - dst->xp1 = src->xp1; - dst->gm1 = src->gm1; - dst->gp1 = src->gp1; - dst->cidx = src->cidx; - dst->cval = src->cval; - if( !ae_vector_init_copy(&dst->tmpprec, &src->tmpprec, _state, make_automatic) ) - return ae_false; - dst->nfev = src->nfev; - dst->mcstage = src->mcstage; - dst->stp = src->stp; - dst->curstpmax = src->curstpmax; - dst->activationstep = src->activationstep; - if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) ) - return ae_false; - if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) ) - return ae_false; - dst->trimthreshold = src->trimthreshold; - dst->nonmonotoniccnt = src->nonmonotoniccnt; - dst->k = src->k; - dst->q = src->q; - dst->p = src->p; - if( !ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->yk, &src->yk, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->sk, &src->sk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->theta, &src->theta, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _minbleicstate_clear(void* _p) -{ - minbleicstate *p = (minbleicstate*)_p; - ae_touch_ptr((void*)p); - _sactiveset_clear(&p->sas); - ae_vector_clear(&p->s); - ae_vector_clear(&p->diagh); - ae_vector_clear(&p->x); - ae_vector_clear(&p->g); - _rcommstate_clear(&p->rstate); - ae_vector_clear(&p->gc); - ae_vector_clear(&p->xn); - ae_vector_clear(&p->gn); - ae_vector_clear(&p->xp); - ae_vector_clear(&p->gp); - ae_vector_clear(&p->d); - ae_matrix_clear(&p->cleic); - ae_vector_clear(&p->hasbndl); - ae_vector_clear(&p->hasbndu); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_vector_clear(&p->xstart); - _snnlssolver_clear(&p->solver); - ae_vector_clear(&p->tmpprec); - ae_vector_clear(&p->work); - _linminstate_clear(&p->lstate); - ae_vector_clear(&p->rho); - ae_matrix_clear(&p->yk); - ae_matrix_clear(&p->sk); - ae_vector_clear(&p->theta); -} - - -void _minbleicstate_destroy(void* _p) -{ - minbleicstate *p = (minbleicstate*)_p; - ae_touch_ptr((void*)p); - _sactiveset_destroy(&p->sas); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->diagh); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->g); - _rcommstate_destroy(&p->rstate); - ae_vector_destroy(&p->gc); - ae_vector_destroy(&p->xn); - ae_vector_destroy(&p->gn); - ae_vector_destroy(&p->xp); - ae_vector_destroy(&p->gp); - ae_vector_destroy(&p->d); - ae_matrix_destroy(&p->cleic); - ae_vector_destroy(&p->hasbndl); - ae_vector_destroy(&p->hasbndu); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_vector_destroy(&p->xstart); - _snnlssolver_destroy(&p->solver); - ae_vector_destroy(&p->tmpprec); - ae_vector_destroy(&p->work); - _linminstate_destroy(&p->lstate); - ae_vector_destroy(&p->rho); - ae_matrix_destroy(&p->yk); - ae_matrix_destroy(&p->sk); - ae_vector_destroy(&p->theta); -} - - -ae_bool _minbleicreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minbleicreport *p = (minbleicreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _minbleicreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minbleicreport *dst = (minbleicreport*)_dst; - minbleicreport *src = (minbleicreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nfev = src->nfev; - dst->varidx = src->varidx; - dst->terminationtype = src->terminationtype; - dst->debugeqerr = src->debugeqerr; - dst->debugfs = src->debugfs; - dst->debugff = src->debugff; - dst->debugdx = src->debugdx; - dst->debugfeasqpits = src->debugfeasqpits; - dst->debugfeasgpaits = src->debugfeasgpaits; - dst->inneriterationscount = src->inneriterationscount; - dst->outeriterationscount = src->outeriterationscount; - return ae_true; -} - - -void _minbleicreport_clear(void* _p) -{ - minbleicreport *p = (minbleicreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _minbleicreport_destroy(void* _p) -{ - minbleicreport *p = (minbleicreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* - LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using a quasi- -Newton method (LBFGS scheme) which is optimized to use a minimum amount -of memory. -The subroutine generates the approximation of an inverse Hessian matrix by -using information about the last M steps of the algorithm (instead of N). -It lessens a required amount of memory from a value of order N^2 to a -value of order 2*N*M. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinLBFGSCreate() call -2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() - and other functions -3. User calls MinLBFGSOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinLBFGSResults() to get solution -5. Optionally user may call MinLBFGSRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLBFGSRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension. N>0 - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - initial solution approximation, array[0..N-1]. - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with MinLBFGSSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLBFGSSetStpMax() function to bound algorithm's steps. However, - L-BFGS rarely needs such a tuning. - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreate(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlbfgsstate* state, - ae_state *_state) -{ - - _minlbfgsstate_clear(state); - - ae_assert(n>=1, "MinLBFGSCreate: N<1!", _state); - ae_assert(m>=1, "MinLBFGSCreate: M<1", _state); - ae_assert(m<=n, "MinLBFGSCreate: M>N", _state); - ae_assert(x->cnt>=n, "MinLBFGSCreate: Length(X)0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinLBFGSSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. LBFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreatef(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - double diffstep, - minlbfgsstate* state, - ae_state *_state) -{ - - _minlbfgsstate_clear(state); - - ae_assert(n>=1, "MinLBFGSCreateF: N too small!", _state); - ae_assert(m>=1, "MinLBFGSCreateF: M<1", _state); - ae_assert(m<=n, "MinLBFGSCreateF: M>N", _state); - ae_assert(x->cnt>=n, "MinLBFGSCreateF: Length(X)=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLBFGSSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcond(minlbfgsstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinLBFGSSetCond: EpsG is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinLBFGSSetCond: negative EpsG!", _state); - ae_assert(ae_isfinite(epsf, _state), "MinLBFGSSetCond: EpsF is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinLBFGSSetCond: negative EpsF!", _state); - ae_assert(ae_isfinite(epsx, _state), "MinLBFGSSetCond: EpsX is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinLBFGSSetCond: negative EpsX!", _state); - ae_assert(maxits>=0, "MinLBFGSSetCond: negative MaxIts!", _state); - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->epsg = epsg; - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLBFGSOptimize(). - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetxrep(minlbfgsstate* state, - ae_bool needxrep, - ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if - you don't want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetstpmax(minlbfgsstate* state, - double stpmax, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "MinLBFGSSetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "MinLBFGSSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* -This function sets scaling coefficients for LBFGS optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the LBFGS too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinLBFGSSetPrec...() -functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetscale(minlbfgsstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(s->cnt>=state->n, "MinLBFGSSetScale: Length(S)n-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLBFGSSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinLBFGSSetScale: S contains zero elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -Extended subroutine for internal use only. - -Accepts additional parameters: - - Flags - additional settings: - * Flags = 0 means no additional settings - * Flags = 1 "do not allocate memory". used when solving - a many subsequent tasks with same N/M values. - First call MUST be without this flag bit set, - subsequent calls of MinLBFGS with same - MinLBFGSState structure can set Flags to 1. - DiffStep - numerical differentiation step - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreatex(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - ae_int_t flags, - double diffstep, - minlbfgsstate* state, - ae_state *_state) -{ - ae_bool allocatemem; - ae_int_t i; - - - ae_assert(n>=1, "MinLBFGS: N too small!", _state); - ae_assert(m>=1, "MinLBFGS: M too small!", _state); - ae_assert(m<=n, "MinLBFGS: M too large!", _state); - - /* - * Initialize - */ - state->teststep = 0; - state->diffstep = diffstep; - state->n = n; - state->m = m; - allocatemem = flags%2==0; - flags = flags/2; - if( allocatemem ) - { - ae_vector_set_length(&state->rho, m, _state); - ae_vector_set_length(&state->theta, m, _state); - ae_matrix_set_length(&state->yk, m, n, _state); - ae_matrix_set_length(&state->sk, m, n, _state); - ae_vector_set_length(&state->d, n, _state); - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->s, n, _state); - ae_vector_set_length(&state->g, n, _state); - ae_vector_set_length(&state->work, n, _state); - } - minlbfgssetcond(state, 0, 0, 0, 0, _state); - minlbfgssetxrep(state, ae_false, _state); - minlbfgssetstpmax(state, 0, _state); - minlbfgsrestartfrom(state, x, _state); - for(i=0; i<=n-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - } - state->prectype = 0; -} - - -/************************************************************************* -Modification of the preconditioner: default preconditioner (simple -scaling, same for all elements of X) is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state) -{ - - - state->prectype = 0; -} - - -/************************************************************************* -Modification of the preconditioner: Cholesky factorization of approximate -Hessian is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - P - triangular preconditioner, Cholesky factorization of - the approximate Hessian. array[0..N-1,0..N-1], - (if larger, only leading N elements are used). - IsUpper - whether upper or lower triangle of P is given - (other triangle is not referenced) - -After call to this function preconditioner is changed to P (P is copied -into the internal buffer). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: P should be nonsingular. Exception will be thrown otherwise. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetpreccholesky(minlbfgsstate* state, - /* Real */ ae_matrix* p, - ae_bool isupper, - ae_state *_state) -{ - ae_int_t i; - double mx; - - - ae_assert(isfinitertrmatrix(p, state->n, isupper, _state), "MinLBFGSSetPrecCholesky: P contains infinite or NAN values!", _state); - mx = 0; - for(i=0; i<=state->n-1; i++) - { - mx = ae_maxreal(mx, ae_fabs(p->ptr.pp_double[i][i], _state), _state); - } - ae_assert(ae_fp_greater(mx,0), "MinLBFGSSetPrecCholesky: P is strictly singular!", _state); - if( state->denseh.rowsn||state->denseh.colsn ) - { - ae_matrix_set_length(&state->denseh, state->n, state->n, _state); - } - state->prectype = 1; - if( isupper ) - { - rmatrixcopy(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); - } - else - { - rmatrixtranspose(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); - } -} - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdiag(minlbfgsstate* state, - /* Real */ ae_vector* d, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(d->cnt>=state->n, "MinLBFGSSetPrecDiag: D is too short", _state); - for(i=0; i<=state->n-1; i++) - { - ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinLBFGSSetPrecDiag: D contains infinite or NAN elements", _state); - ae_assert(ae_fp_greater(d->ptr.p_double[i],0), "MinLBFGSSetPrecDiag: D contains non-positive elements", _state); - } - rvectorsetlengthatleast(&state->diagh, state->n, _state); - state->prectype = 2; - for(i=0; i<=state->n-1; i++) - { - state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; - } -} - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() -call (before or after MinLBFGSSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state) -{ - - - state->prectype = 3; -} - - -/************************************************************************* -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() - for numerical differentiation) you should choose appropriate variant of - MinLBFGSOptimize() - one which accepts function AND gradient or one - which accepts function ONLY. - - Be careful to choose variant of MinLBFGSOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinLBFGSOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinLBFGSOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinLBFGSCreateF() | work FAIL - MinLBFGSCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinLBFGSOptimize() version. Attemps to use such - combination (for example, to create optimizer with MinLBFGSCreateF() and - to pass gradient information to MinCGOptimize()) will lead to exception - being thrown. Either you did not pass gradient when it WAS needed or - you passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t m; - ae_int_t i; - ae_int_t j; - ae_int_t ic; - ae_int_t mcinfo; - double v; - double vv; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - i = state->rstate.ia.ptr.p_int[2]; - j = state->rstate.ia.ptr.p_int[3]; - ic = state->rstate.ia.ptr.p_int[4]; - mcinfo = state->rstate.ia.ptr.p_int[5]; - v = state->rstate.ra.ptr.p_double[0]; - vv = state->rstate.ra.ptr.p_double[1]; - } - else - { - n = -983; - m = -989; - i = -834; - j = 900; - ic = -287; - mcinfo = 364; - v = 214; - vv = -338; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - if( state->rstate.stage==14 ) - { - goto lbl_14; - } - if( state->rstate.stage==15 ) - { - goto lbl_15; - } - if( state->rstate.stage==16 ) - { - goto lbl_16; - } - - /* - * Routine body - */ - - /* - * Unload frequently used variables from State structure - * (just for typing convenience) - */ - n = state->n; - m = state->m; - state->repterminationtype = 0; - state->repiterationscount = 0; - state->repvaridx = -1; - state->repnfev = 0; - - /* - * Check, that transferred derivative value is right - */ - minlbfgs_clearrequestfields(state, _state); - if( !(ae_fp_eq(state->diffstep,0)&&ae_fp_greater(state->teststep,0)) ) - { - goto lbl_17; - } - state->needfg = ae_true; - i = 0; -lbl_19: - if( i>n-1 ) - { - goto lbl_21; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->fm1 = state->f; - state->fp1 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->fm2 = state->f; - state->fp2 = state->g.ptr.p_double[i]; - state->x.ptr.p_double[i] = v; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - - /* - * 2*State.TestStep - scale parameter - * width of segment [Xi-TestStep;Xi+TestStep] - */ - if( !derivativecheck(state->fm1, state->fp1, state->fm2, state->fp2, state->f, state->g.ptr.p_double[i], 2*state->teststep, _state) ) - { - state->repvaridx = i; - state->repterminationtype = -7; - result = ae_false; - return result; - } - i = i+1; - goto lbl_19; -lbl_21: - state->needfg = ae_false; -lbl_17: - - /* - * Calculate F/G at the initial point - */ - minlbfgs_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_22; - } - state->needfg = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needfg = ae_false; - goto lbl_23; -lbl_22: - state->needf = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->fbase = state->f; - i = 0; -lbl_24: - if( i>n-1 ) - { - goto lbl_26; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->fp2 = state->f; - state->x.ptr.p_double[i] = v; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - i = i+1; - goto lbl_24; -lbl_26: - state->f = state->fbase; - state->needf = ae_false; -lbl_23: - trimprepare(state->f, &state->trimthreshold, _state); - if( !state->xrep ) - { - goto lbl_27; - } - minlbfgs_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->xupdated = ae_false; -lbl_27: - state->repnfev = 1; - state->fold = state->f; - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) - { - state->repterminationtype = 4; - result = ae_false; - return result; - } - - /* - * Choose initial step and direction. - * Apply preconditioner, if we have something other than default. - */ - ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( state->prectype==0 ) - { - - /* - * Default preconditioner is used, but we can't use it before iterations will start - */ - v = ae_v_dotproduct(&state->g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = ae_sqrt(v, _state); - if( ae_fp_eq(state->stpmax,0) ) - { - state->stp = ae_minreal(1.0/v, 1, _state); - } - else - { - state->stp = ae_minreal(1.0/v, state->stpmax, _state); - } - } - if( state->prectype==1 ) - { - - /* - * Cholesky preconditioner is used - */ - fblscholeskysolve(&state->denseh, 1.0, n, ae_true, &state->d, &state->autobuf, _state); - state->stp = 1; - } - if( state->prectype==2 ) - { - - /* - * diagonal approximation is used - */ - for(i=0; i<=n-1; i++) - { - state->d.ptr.p_double[i] = state->d.ptr.p_double[i]/state->diagh.ptr.p_double[i]; - } - state->stp = 1; - } - if( state->prectype==3 ) - { - - /* - * scale-based preconditioner is used - */ - for(i=0; i<=n-1; i++) - { - state->d.ptr.p_double[i] = state->d.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; - } - state->stp = 1; - } - - /* - * Main cycle - */ - state->k = 0; -lbl_29: - if( ae_false ) - { - goto lbl_30; - } - - /* - * Main cycle: prepare to 1-D line search - */ - state->p = state->k%m; - state->q = ae_minint(state->k, m-1, _state); - - /* - * Store X[k], G[k] - */ - ae_v_moveneg(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_moveneg(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Minimize F(x+alpha*d) - * Calculate S[k], Y[k] - */ - state->mcstage = 0; - if( state->k!=0 ) - { - state->stp = 1.0; - } - linminnormalized(&state->d, &state->stp, n, _state); - mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); -lbl_31: - if( state->mcstage==0 ) - { - goto lbl_32; - } - minlbfgs_clearrequestfields(state, _state); - if( ae_fp_neq(state->diffstep,0) ) - { - goto lbl_33; - } - state->needfg = ae_true; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->needfg = ae_false; - goto lbl_34; -lbl_33: - state->needf = ae_true; - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - state->fbase = state->f; - i = 0; -lbl_35: - if( i>n-1 ) - { - goto lbl_37; - } - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - state->fm2 = state->f; - state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->fm1 = state->f; - state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 14; - goto lbl_rcomm; -lbl_14: - state->fp1 = state->f; - state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; - state->rstate.stage = 15; - goto lbl_rcomm; -lbl_15: - state->fp2 = state->f; - state->x.ptr.p_double[i] = v; - state->g.ptr.p_double[i] = (8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/(6*state->diffstep*state->s.ptr.p_double[i]); - i = i+1; - goto lbl_35; -lbl_37: - state->f = state->fbase; - state->needf = ae_false; -lbl_34: - trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); - mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stpmax, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); - goto lbl_31; -lbl_32: - if( !state->xrep ) - { - goto lbl_38; - } - - /* - * report - */ - minlbfgs_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 16; - goto lbl_rcomm; -lbl_16: - state->xupdated = ae_false; -lbl_38: - state->repnfev = state->repnfev+state->nfev; - state->repiterationscount = state->repiterationscount+1; - ae_v_add(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Stopping conditions - */ - if( state->repiterationscount>=state->maxits&&state->maxits>0 ) - { - - /* - * Too many iterations - */ - state->repterminationtype = 5; - result = ae_false; - return result; - } - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) - { - - /* - * Gradient is small enough - */ - state->repterminationtype = 4; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) - { - - /* - * F(k+1)-F(k) is small enough - */ - state->repterminationtype = 1; - result = ae_false; - return result; - } - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->sk.ptr.pp_double[state->p][i]/state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsx) ) - { - - /* - * X(k+1)-X(k) is small enough - */ - state->repterminationtype = 2; - result = ae_false; - return result; - } - - /* - * If Wolfe conditions are satisfied, we can update - * limited memory model. - * - * However, if conditions are not satisfied (NFEV limit is met, - * function is too wild, ...), we'll skip L-BFGS update - */ - if( mcinfo!=1 ) - { - - /* - * Skip update. - * - * In such cases we'll initialize search direction by - * antigradient vector, because it leads to more - * transparent code with less number of special cases - */ - state->fold = state->f; - ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - } - else - { - - /* - * Calculate Rho[k], GammaK - */ - v = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->sk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); - vv = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->yk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); - if( ae_fp_eq(v,0)||ae_fp_eq(vv,0) ) - { - - /* - * Rounding errors make further iterations impossible. - */ - state->repterminationtype = -2; - result = ae_false; - return result; - } - state->rho.ptr.p_double[state->p] = 1/v; - state->gammak = v/vv; - - /* - * Calculate d(k+1) = -H(k+1)*g(k+1) - * - * for I:=K downto K-Q do - * V = s(i)^T * work(iteration:I) - * theta(i) = V - * work(iteration:I+1) = work(iteration:I) - V*Rho(i)*y(i) - * work(last iteration) = H0*work(last iteration) - preconditioner - * for I:=K-Q to K do - * V = y(i)^T*work(iteration:I) - * work(iteration:I+1) = work(iteration:I) +(-V+theta(i))*Rho(i)*s(i) - * - * NOW WORK CONTAINS d(k+1) - */ - ae_v_move(&state->work.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=state->k; i>=state->k-state->q; i--) - { - ic = i%m; - v = ae_v_dotproduct(&state->sk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->theta.ptr.p_double[ic] = v; - vv = v*state->rho.ptr.p_double[ic]; - ae_v_subd(&state->work.ptr.p_double[0], 1, &state->yk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); - } - if( state->prectype==0 ) - { - - /* - * Simple preconditioner is used - */ - v = state->gammak; - ae_v_muld(&state->work.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - if( state->prectype==1 ) - { - - /* - * Cholesky preconditioner is used - */ - fblscholeskysolve(&state->denseh, 1, n, ae_true, &state->work, &state->autobuf, _state); - } - if( state->prectype==2 ) - { - - /* - * diagonal approximation is used - */ - for(i=0; i<=n-1; i++) - { - state->work.ptr.p_double[i] = state->work.ptr.p_double[i]/state->diagh.ptr.p_double[i]; - } - } - if( state->prectype==3 ) - { - - /* - * scale-based preconditioner is used - */ - for(i=0; i<=n-1; i++) - { - state->work.ptr.p_double[i] = state->work.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; - } - } - for(i=state->k-state->q; i<=state->k; i++) - { - ic = i%m; - v = ae_v_dotproduct(&state->yk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]); - ae_v_addd(&state->work.ptr.p_double[0], 1, &state->sk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); - } - ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Next step - */ - state->fold = state->f; - state->k = state->k+1; - } - goto lbl_29; -lbl_30: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = i; - state->rstate.ia.ptr.p_int[3] = j; - state->rstate.ia.ptr.p_int[4] = ic; - state->rstate.ia.ptr.p_int[5] = mcinfo; - state->rstate.ra.ptr.p_double[0] = v; - state->rstate.ra.ptr.p_double[1] = vv; - return result; -} - - -/************************************************************************* -L-BFGS algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinLBFGSSetGradientCheck() for more information. - * -2 rounding errors prevent further improvement. - X contains best point found. - * -1 incorrect parameters were specified - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresults(minlbfgsstate* state, - /* Real */ ae_vector* x, - minlbfgsreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _minlbfgsreport_clear(rep); - - minlbfgsresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -L-BFGS algorithm results - -Buffered implementation of MinLBFGSResults which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresultsbuf(minlbfgsstate* state, - /* Real */ ae_vector* x, - minlbfgsreport* rep, - ae_state *_state) -{ - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nfev = state->repnfev; - rep->varidx = state->repvaridx; - rep->terminationtype = state->repterminationtype; -} - - -/************************************************************************* -This subroutine restarts LBFGS algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsrestartfrom(minlbfgsstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - - - ae_assert(x->cnt>=state->n, "MinLBFGSRestartFrom: Length(X)n, _state), "MinLBFGSRestartFrom: X contains infinite or NaN values!", _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_vector_set_length(&state->rstate.ia, 5+1, _state); - ae_vector_set_length(&state->rstate.ra, 1+1, _state); - state->rstate.stage = -1; - minlbfgs_clearrequestfields(state, _state); -} - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLBFGSOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLBFGSSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 24.05.2012 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetgradientcheck(minlbfgsstate* state, - double teststep, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(teststep, _state), "MinLBFGSSetGradientCheck: TestStep contains NaN or Infinite", _state); - ae_assert(ae_fp_greater_eq(teststep,0), "MinLBFGSSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); - state->teststep = teststep; -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void minlbfgs_clearrequestfields(minlbfgsstate* state, - ae_state *_state) -{ - - - state->needf = ae_false; - state->needfg = ae_false; - state->xupdated = ae_false; -} - - -ae_bool _minlbfgsstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minlbfgsstate *p = (minlbfgsstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->sk, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->theta, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->autobuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !_linminstate_init(&p->lstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _minlbfgsstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minlbfgsstate *dst = (minlbfgsstate*)_dst; - minlbfgsstate *src = (minlbfgsstate*)_src; - dst->n = src->n; - dst->m = src->m; - dst->epsg = src->epsg; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->stpmax = src->stpmax; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - dst->diffstep = src->diffstep; - dst->nfev = src->nfev; - dst->mcstage = src->mcstage; - dst->k = src->k; - dst->q = src->q; - dst->p = src->p; - if( !ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->yk, &src->yk, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->sk, &src->sk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->theta, &src->theta, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - dst->stp = src->stp; - if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) ) - return ae_false; - dst->fold = src->fold; - dst->trimthreshold = src->trimthreshold; - dst->prectype = src->prectype; - dst->gammak = src->gammak; - if( !ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic) ) - return ae_false; - dst->fbase = src->fbase; - dst->fm2 = src->fm2; - dst->fm1 = src->fm1; - dst->fp1 = src->fp1; - dst->fp2 = src->fp2; - if( !ae_vector_init_copy(&dst->autobuf, &src->autobuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - dst->needf = src->needf; - dst->needfg = src->needfg; - dst->xupdated = src->xupdated; - dst->teststep = src->teststep; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->repiterationscount = src->repiterationscount; - dst->repnfev = src->repnfev; - dst->repvaridx = src->repvaridx; - dst->repterminationtype = src->repterminationtype; - if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _minlbfgsstate_clear(void* _p) -{ - minlbfgsstate *p = (minlbfgsstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->s); - ae_vector_clear(&p->rho); - ae_matrix_clear(&p->yk); - ae_matrix_clear(&p->sk); - ae_vector_clear(&p->theta); - ae_vector_clear(&p->d); - ae_vector_clear(&p->work); - ae_matrix_clear(&p->denseh); - ae_vector_clear(&p->diagh); - ae_vector_clear(&p->autobuf); - ae_vector_clear(&p->x); - ae_vector_clear(&p->g); - _rcommstate_clear(&p->rstate); - _linminstate_clear(&p->lstate); -} - - -void _minlbfgsstate_destroy(void* _p) -{ - minlbfgsstate *p = (minlbfgsstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->rho); - ae_matrix_destroy(&p->yk); - ae_matrix_destroy(&p->sk); - ae_vector_destroy(&p->theta); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->work); - ae_matrix_destroy(&p->denseh); - ae_vector_destroy(&p->diagh); - ae_vector_destroy(&p->autobuf); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->g); - _rcommstate_destroy(&p->rstate); - _linminstate_destroy(&p->lstate); -} - - -ae_bool _minlbfgsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minlbfgsreport *p = (minlbfgsreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _minlbfgsreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minlbfgsreport *dst = (minlbfgsreport*)_dst; - minlbfgsreport *src = (minlbfgsreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nfev = src->nfev; - dst->varidx = src->varidx; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _minlbfgsreport_clear(void* _p) -{ - minlbfgsreport *p = (minlbfgsreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _minlbfgsreport_destroy(void* _p) -{ - minlbfgsreport *p = (minlbfgsreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* - CONSTRAINED QUADRATIC PROGRAMMING - -The subroutine creates QP optimizer. After initial creation, it contains -default optimization problem with zero quadratic and linear terms and no -constraints. You should set quadratic/linear terms with calls to functions -provided by MinQP subpackage. - -INPUT PARAMETERS: - N - problem size - -OUTPUT PARAMETERS: - State - optimizer with zero quadratic/linear terms - and no constraints - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state) -{ - ae_int_t i; - - _minqpstate_clear(state); - - ae_assert(n>=1, "MinQPCreate: N<1", _state); - - /* - * initialize QP solver - */ - state->n = n; - state->nec = 0; - state->nic = 0; - state->repterminationtype = 0; - state->anorm = 1; - state->akind = 0; - cqminit(n, &state->a, _state); - sasinit(n, &state->sas, _state); - ae_vector_set_length(&state->b, n, _state); - ae_vector_set_length(&state->bndl, n, _state); - ae_vector_set_length(&state->bndu, n, _state); - ae_vector_set_length(&state->workbndl, n, _state); - ae_vector_set_length(&state->workbndu, n, _state); - ae_vector_set_length(&state->havebndl, n, _state); - ae_vector_set_length(&state->havebndu, n, _state); - ae_vector_set_length(&state->s, n, _state); - ae_vector_set_length(&state->startx, n, _state); - ae_vector_set_length(&state->xorigin, n, _state); - ae_vector_set_length(&state->xs, n, _state); - ae_vector_set_length(&state->xn, n, _state); - ae_vector_set_length(&state->gc, n, _state); - ae_vector_set_length(&state->pg, n, _state); - for(i=0; i<=n-1; i++) - { - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->bndu.ptr.p_double[i] = _state->v_posinf; - state->havebndl.ptr.p_bool[i] = ae_false; - state->havebndu.ptr.p_bool[i] = ae_false; - state->b.ptr.p_double[i] = 0.0; - state->startx.ptr.p_double[i] = 0.0; - state->xorigin.ptr.p_double[i] = 0.0; - state->s.ptr.p_double[i] = 1.0; - } - state->havex = ae_false; - minqpsetalgocholesky(state, _state); - normestimatorcreate(n, n, 5, 5, &state->estimator, _state); - minbleiccreate(n, &state->startx, &state->solver, _state); -} - - -/************************************************************************* -This function sets linear term for QP solver. - -By default, linear term is zero. - -INPUT PARAMETERS: - State - structure which stores algorithm state - B - linear term, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlinearterm(minqpstate* state, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t n; - - - n = state->n; - ae_assert(b->cnt>=n, "MinQPSetLinearTerm: Length(B)n; - ae_assert(a->rows>=n, "MinQPSetQuadraticTerm: Rows(A)cols>=n, "MinQPSetQuadraticTerm: Cols(A)n; - ae_assert(sparsegetnrows(a, _state)>=n, "MinQPSetQuadraticTermSparse: Rows(A)=n, "MinQPSetQuadraticTermSparse: Cols(A)sparsea, _state); - state->sparseaupper = isupper; - state->akind = 1; -} - - -/************************************************************************* -This function sets starting point for QP solver. It is useful to have -good initial approximation to the solution, because it will increase -speed of convergence and identification of active constraints. - -INPUT PARAMETERS: - State - structure which stores algorithm state - X - starting point, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetstartingpoint(minqpstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - - - n = state->n; - ae_assert(x->cnt>=n, "MinQPSetStartingPoint: Length(B)n; - ae_assert(xorigin->cnt>=n, "MinQPSetOrigin: Length(B)cnt>=state->n, "MinQPSetScale: Length(S)n-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinQPSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinQPSetScale: S contains zero elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function tells solver to use Cholesky-based algorithm. This algorithm -is active by default. - -DESCRIPTION: - -Cholesky-based algorithm can be used only for problems which: -* have dense quadratic term, set by MinQPSetQuadraticTerm(), sparse or - structured problems are not supported. -* are strictly convex, i.e. quadratic term is symmetric positive definite, - indefinite or semidefinite problems are not supported by this algorithm. - -If anything of what listed above is violated, you may use BLEIC-based QP -algorithm which can be activated by MinQPSetAlgoBLEIC(). - -BENEFITS AND DRAWBACKS: - -This algorithm gives best precision amongst all QP solvers provided by -ALGLIB (Newton iterations have much higher precision than any other -optimization algorithm). This solver also gracefully handles problems with -very large amount of constraints. - -Performance of the algorithm is good because internally it uses Level 3 -Dense BLAS for its performance-critical parts. - - -From the other side, algorithm has O(N^3) complexity for unconstrained -problems and up to orders of magnitude slower on constrained problems -(these additional iterations are needed to identify active constraints). -So, its running time depends on number of constraints active at solution. - -Furthermore, this algorithm can not solve problems with sparse matrices or -problems with semidefinite/indefinite matrices of any kind (dense/sparse). - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgocholesky(minqpstate* state, ae_state *_state) -{ - - - state->algokind = 1; -} - - -/************************************************************************* -This function tells solver to use BLEIC-based algorithm and sets stopping -criteria for the algorithm. - -DESCRIPTION: - -BLEIC-based QP algorithm can be used for any kind of QP problems: -* problems with both dense and sparse quadratic terms -* problems with positive definite, semidefinite, indefinite terms - -BLEIC-based algorithm can solve even indefinite problems - as long as they -are bounded from below on the feasible set. Of course, global minimum is -found only for positive definite and semidefinite problems. As for -indefinite ones - only local minimum is found. - -BENEFITS AND DRAWBACKS: - -This algorithm can be used to solve both convex and indefinite QP problems -and it can utilize sparsity of the quadratic term (algorithm calculates -matrix-vector products, which can be performed efficiently in case of -sparse matrix). - -Algorithm has iteration cost, which (assuming fixed amount of non-boundary -linear constraints) linearly depends on problem size. Boundary constraints -does not significantly change iteration cost. - -Thus, it outperforms Cholesky-based QP algorithm (CQP) on high-dimensional -sparse problems with moderate amount of constraints. - - -From the other side, unlike CQP solver, this algorithm does NOT make use -of Level 3 Dense BLAS. Thus, its performance on dense problems is inferior -to that of CQP solver. - -Its precision is also inferior to that of CQP. CQP performs Newton steps -which are know to achieve very good precision. In many cases Newton step -leads us exactly to the solution. BLEIC-QP performs LBFGS steps, which are -good at detecting neighborhood of the solution, buy need many iterations -to find solution with 6 digits of precision. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - EpsX - >=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinQPSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection (presently it is small step -length, but it may change in the future versions of ALGLIB). - -IT IS VERY IMPORTANT THAT YOU CALL MinQPSetScale() WHEN YOU USE THIS ALGO! - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgobleic(minqpstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinQPSetAlgoBLEIC: EpsG is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinQPSetAlgoBLEIC: negative EpsG", _state); - ae_assert(ae_isfinite(epsf, _state), "MinQPSetAlgoBLEIC: EpsF is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinQPSetAlgoBLEIC: negative EpsF", _state); - ae_assert(ae_isfinite(epsx, _state), "MinQPSetAlgoBLEIC: EpsX is not finite number", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinQPSetAlgoBLEIC: negative EpsX", _state); - ae_assert(maxits>=0, "MinQPSetAlgoBLEIC: negative MaxIts!", _state); - state->algokind = 2; - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->bleicepsg = epsg; - state->bleicepsf = epsf; - state->bleicepsx = epsx; - state->bleicmaxits = maxits; -} - - -/************************************************************************* -This function sets boundary constraints for QP solver - -Boundary constraints are inactive by default (after initial creation). -After being set, they are preserved until explicitly turned off with -another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetbc(minqpstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - - - n = state->n; - ae_assert(bndl->cnt>=n, "MinQPSetBC: Length(BndL)cnt>=n, "MinQPSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinQPSetBC: BndL contains NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinQPSetBC: BndU contains NAN or -INF", _state); - state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; - state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); - state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; - state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function sets linear constraints for QP optimizer. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - structure previously allocated with MinQPCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately - - there always exists some minor violation (about 10^-10...10^-13) - due to numerical errors. - - -- ALGLIB -- - Copyright 19.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlc(minqpstate* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - double v; - - - n = state->n; - - /* - * First, check for errors in the inputs - */ - ae_assert(k>=0, "MinQPSetLC: K<0", _state); - ae_assert(c->cols>=n+1||k==0, "MinQPSetLC: Cols(C)rows>=k, "MinQPSetLC: Rows(C)cnt>=k, "MinQPSetLC: Length(CT)nec = 0; - state->nic = 0; - return; - } - - /* - * Equality constraints are stored first, in the upper - * NEC rows of State.CLEIC matrix. Inequality constraints - * are stored in the next NIC rows. - * - * NOTE: we convert inequality constraints to the form - * A*x<=b before copying them. - */ - rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); - state->nec = 0; - state->nic = 0; - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]==0 ) - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - state->nec = state->nec+1; - } - } - for(i=0; i<=k-1; i++) - { - if( ct->ptr.p_int[i]!=0 ) - { - if( ct->ptr.p_int[i]>0 ) - { - ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - else - { - ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); - } - state->nic = state->nic+1; - } - } - - /* - * Normalize rows of State.CLEIC: each row must have unit norm. - * Norm is calculated using first N elements (i.e. right part is - * not counted when we calculate norm). - */ - for(i=0; i<=k-1; i++) - { - v = 0; - for(j=0; j<=n-1; j++) - { - v = v+ae_sqr(state->cleic.ptr.pp_double[i][j], _state); - } - if( ae_fp_eq(v,0) ) - { - continue; - } - v = 1/ae_sqrt(v, _state); - ae_v_muld(&state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n), v); - } -} - - -/************************************************************************* -This function solves quadratic programming problem. -You should call it after setting solver options with MinQPSet...() calls. - -INPUT PARAMETERS: - State - algorithm state - -You should use MinQPResults() function to access results after calls -to this function. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey. - Special thanks to Elvira Illarionova for important suggestions on - the linearly constrained QP algorithm. -*************************************************************************/ -void minqpoptimize(minqpstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t nbc; - double v0; - double v1; - double v; - double d2; - double d1; - double d0; - double noisetolerance; - double fprev; - double fcand; - double fcur; - ae_int_t nextaction; - ae_int_t actstatus; - double noiselevel; - ae_int_t badnewtonits; - double maxscaledgrad; - - - noisetolerance = 10; - n = state->n; - state->repterminationtype = -5; - state->repinneriterationscount = 0; - state->repouteriterationscount = 0; - state->repncholesky = 0; - state->repnmv = 0; - state->debugphase1flops = 0; - state->debugphase2flops = 0; - state->debugphase3flops = 0; - rvectorsetlengthatleast(&state->rctmpg, n, _state); - - /* - * check correctness of constraints - */ - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) - { - if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->repterminationtype = -3; - return; - } - } - } - - /* - * count number of bound and linear constraints - */ - nbc = 0; - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i] ) - { - nbc = nbc+1; - } - if( state->havebndu.ptr.p_bool[i] ) - { - nbc = nbc+1; - } - } - - /* - * Initial point: - * * if we have starting point in StartX, we just have to bound it - * * if we do not have StartX, deduce initial point from boundary constraints - */ - if( state->havex ) - { - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->startx.ptr.p_double[i]; - if( state->havebndl.ptr.p_bool[i]&&ae_fp_less(state->xs.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - } - if( state->havebndu.ptr.p_bool[i]&&ae_fp_greater(state->xs.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; - } - } - } - else - { - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = 0.5*(state->bndl.ptr.p_double[i]+state->bndu.ptr.p_double[i]); - continue; - } - if( state->havebndl.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - continue; - } - if( state->havebndu.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; - continue; - } - state->xs.ptr.p_double[i] = 0; - } - } - - /* - * Cholesky solver. - */ - if( state->algokind==1 ) - { - - /* - * Check matrix type. - * Cholesky solver supports only dense matrices. - */ - if( state->akind!=0 ) - { - state->repterminationtype = -5; - return; - } - - /* - * Our formulation of quadratic problem includes origin point, - * i.e. we have F(x-x_origin) which is minimized subject to - * constraints on x, instead of having simply F(x). - * - * Here we make transition from non-zero origin to zero one. - * In order to make such transition we have to: - * 1. subtract x_origin from x_start - * 2. modify constraints - * 3. solve problem - * 4. add x_origin to solution - * - * There is alternate solution - to modify quadratic function - * by expansion of multipliers containing (x-x_origin), but - * we prefer to modify constraints, because it is a) more precise - * and b) easier to to. - * - * Parts (1)-(2) are done here. After this block is over, - * we have: - * * XS, which stores shifted XStart (if we don't have XStart, - * value of XS will be ignored later) - * * WorkBndL, WorkBndU, which store modified boundary constraints. - */ - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i] ) - { - state->workbndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]-state->xorigin.ptr.p_double[i]; - } - else - { - state->workbndl.ptr.p_double[i] = _state->v_neginf; - } - if( state->havebndu.ptr.p_bool[i] ) - { - state->workbndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]-state->xorigin.ptr.p_double[i]; - } - else - { - state->workbndu.ptr.p_double[i] = _state->v_posinf; - } - } - rmatrixsetlengthatleast(&state->workcleic, state->nec+state->nic, n+1, _state); - for(i=0; i<=state->nec+state->nic-1; i++) - { - v = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &state->xorigin.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->workcleic.ptr.pp_double[i][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - state->workcleic.ptr.pp_double[i][n] = state->cleic.ptr.pp_double[i][n]-v; - } - - /* - * Starting point XS - */ - if( state->havex ) - { - - /* - * We have starting point in StartX, so we just have to shift and bound it - */ - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->startx.ptr.p_double[i]-state->xorigin.ptr.p_double[i]; - if( state->havebndl.ptr.p_bool[i] ) - { - if( ae_fp_less(state->xs.ptr.p_double[i],state->workbndl.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->workbndl.ptr.p_double[i]; - } - } - if( state->havebndu.ptr.p_bool[i] ) - { - if( ae_fp_greater(state->xs.ptr.p_double[i],state->workbndu.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->workbndu.ptr.p_double[i]; - } - } - } - } - else - { - - /* - * We don't have starting point, so we deduce it from - * constraints (if they are present). - * - * NOTE: XS contains some meaningless values from previous block - * which are ignored by code below. - */ - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = 0.5*(state->workbndl.ptr.p_double[i]+state->workbndu.ptr.p_double[i]); - if( ae_fp_less(state->xs.ptr.p_double[i],state->workbndl.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->workbndl.ptr.p_double[i]; - } - if( ae_fp_greater(state->xs.ptr.p_double[i],state->workbndu.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->workbndu.ptr.p_double[i]; - } - continue; - } - if( state->havebndl.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = state->workbndl.ptr.p_double[i]; - continue; - } - if( state->havebndu.ptr.p_bool[i] ) - { - state->xs.ptr.p_double[i] = state->workbndu.ptr.p_double[i]; - continue; - } - state->xs.ptr.p_double[i] = 0; - } - } - - /* - * Handle special case - no constraints - */ - if( nbc==0&&state->nec+state->nic==0 ) - { - - /* - * "Simple" unconstrained Cholesky - */ - bvectorsetlengthatleast(&state->tmpb, n, _state); - for(i=0; i<=n-1; i++) - { - state->tmpb.ptr.p_bool[i] = ae_false; - } - state->repncholesky = state->repncholesky+1; - cqmsetb(&state->a, &state->b, _state); - cqmsetactiveset(&state->a, &state->xs, &state->tmpb, _state); - if( !cqmconstrainedoptimum(&state->a, &state->xn, _state) ) - { - state->repterminationtype = -5; - return; - } - ae_v_move(&state->xs.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->xs.ptr.p_double[0], 1, &state->xorigin.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repinneriterationscount = 1; - state->repouteriterationscount = 1; - state->repterminationtype = 4; - return; - } - - /* - * Prepare "active set" structure - */ - sassetbc(&state->sas, &state->workbndl, &state->workbndu, _state); - sassetlcx(&state->sas, &state->workcleic, state->nec, state->nic, _state); - sassetscale(&state->sas, &state->s, _state); - if( !sasstartoptimization(&state->sas, &state->xs, _state) ) - { - state->repterminationtype = -3; - return; - } - - /* - * Main cycle of CQP algorithm - */ - state->repterminationtype = 4; - badnewtonits = 0; - maxscaledgrad = 0.0; - for(;;) - { - - /* - * Update iterations count - */ - inc(&state->repouteriterationscount, _state); - inc(&state->repinneriterationscount, _state); - - /* - * Phase 1. - * - * Determine active set. - * Update MaxScaledGrad. - */ - cqmadx(&state->a, &state->sas.xc, &state->rctmpg, _state); - ae_v_add(&state->rctmpg.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasreactivateconstraints(&state->sas, &state->rctmpg, _state); - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->rctmpg.ptr.p_double[i]*state->s.ptr.p_double[i], _state); - } - maxscaledgrad = ae_maxreal(maxscaledgrad, ae_sqrt(v, _state), _state); - - /* - * Phase 2: perform penalized steepest descent step. - * - * NextAction control variable is set on exit from this loop: - * * NextAction>0 in case we have to proceed to Phase 3 (Newton step) - * * NextAction<0 in case we have to proceed to Phase 1 (recalculate active set) - * * NextAction=0 in case we found solution (step along projected gradient is small enough) - */ - for(;;) - { - - /* - * Calculate constrained descent direction, store to PG. - * Successful termination if PG is zero. - */ - cqmadx(&state->a, &state->sas.xc, &state->gc, _state); - ae_v_add(&state->gc.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasconstraineddescent(&state->sas, &state->gc, &state->pg, _state); - state->debugphase2flops = state->debugphase2flops+4*(state->nec+state->nic)*n; - v0 = ae_v_dotproduct(&state->pg.ptr.p_double[0], 1, &state->pg.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_eq(v0,0) ) - { - - /* - * Constrained derivative is zero. - * Solution found. - */ - nextaction = 0; - break; - } - - /* - * Build quadratic model of F along descent direction: - * F(xc+alpha*pg) = D2*alpha^2 + D1*alpha + D0 - * Store noise level in the XC (noise level is used to classify - * step as singificant or insignificant). - * - * In case function curvature is negative or product of descent - * direction and gradient is non-negative, iterations are terminated. - * - * NOTE: D0 is not actually used, but we prefer to maintain it. - */ - fprev = minqp_minqpmodelvalue(&state->a, &state->b, &state->sas.xc, n, &state->tmp0, _state); - fprev = fprev+minqp_penaltyfactor*maxscaledgrad*sasactivelcpenalty1(&state->sas, &state->sas.xc, _state); - cqmevalx(&state->a, &state->sas.xc, &v, &noiselevel, _state); - v0 = cqmxtadx2(&state->a, &state->pg, _state); - state->debugphase2flops = state->debugphase2flops+3*2*n*n; - d2 = v0; - v1 = ae_v_dotproduct(&state->pg.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - d1 = v1; - d0 = fprev; - if( ae_fp_less_eq(d2,0) ) - { - - /* - * Second derivative is non-positive, function is non-convex. - */ - state->repterminationtype = -5; - nextaction = 0; - break; - } - if( ae_fp_greater_eq(d1,0) ) - { - - /* - * Second derivative is positive, first derivative is non-negative. - * Solution found. - */ - nextaction = 0; - break; - } - - /* - * Modify quadratic model - add penalty for violation of the active - * constraints. - * - * Boundary constraints are always satisfied exactly, so we do not - * add penalty term for them. General equality constraint of the - * form a'*(xc+alpha*d)=b adds penalty term: - * P(alpha) = (a'*(xc+alpha*d)-b)^2 - * = (alpha*(a'*d) + (a'*xc-b))^2 - * = alpha^2*(a'*d)^2 + alpha*2*(a'*d)*(a'*xc-b) + (a'*xc-b)^2 - * Each penalty term is multiplied by 100*Anorm before adding it to - * the 1-dimensional quadratic model. - * - * Penalization of the quadratic model improves behavior of the - * algorithm in the presence of the multiple degenerate constraints. - * In particular, it prevents algorithm from making large steps in - * directions which violate equality constraints. - */ - for(i=0; i<=state->nec+state->nic-1; i++) - { - if( state->sas.activeset.ptr.p_int[n+i]>0 ) - { - v0 = ae_v_dotproduct(&state->workcleic.ptr.pp_double[i][0], 1, &state->pg.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v1 = ae_v_dotproduct(&state->workcleic.ptr.pp_double[i][0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v1 = v1-state->workcleic.ptr.pp_double[i][n]; - v = 100*state->anorm; - d2 = d2+v*ae_sqr(v0, _state); - d1 = d1+v*2*v0*v1; - d0 = d0+v*ae_sqr(v1, _state); - } - } - state->debugphase2flops = state->debugphase2flops+2*2*(state->nec+state->nic)*n; - - /* - * Try unbounded step. - * In case function change is dominated by noise or function actually increased - * instead of decreasing, we terminate iterations. - */ - v = -d1/(2*d2); - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->pg.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - fcand = minqp_minqpmodelvalue(&state->a, &state->b, &state->xn, n, &state->tmp0, _state); - fcand = fcand+minqp_penaltyfactor*maxscaledgrad*sasactivelcpenalty1(&state->sas, &state->xn, _state); - state->debugphase2flops = state->debugphase2flops+2*n*n; - if( ae_fp_greater_eq(fcand,fprev-noiselevel*noisetolerance) ) - { - nextaction = 0; - break; - } - - /* - * Save active set - * Perform bounded step with (possible) activation - */ - actstatus = minqp_minqpboundedstepandactivation(state, &state->xn, &state->tmp0, _state); - fcur = minqp_minqpmodelvalue(&state->a, &state->b, &state->sas.xc, n, &state->tmp0, _state); - state->debugphase2flops = state->debugphase2flops+2*n*n; - - /* - * Depending on results, decide what to do: - * 1. In case step was performed without activation of constraints, - * we proceed to Newton method - * 2. In case there was activated at least one constraint with ActiveSet[I]<0, - * we proceed to Phase 1 and re-evaluate active set. - * 3. Otherwise (activation of the constraints with ActiveSet[I]=0) - * we try Phase 2 one more time. - */ - if( actstatus<0 ) - { - - /* - * Step without activation, proceed to Newton - */ - nextaction = 1; - break; - } - if( actstatus==0 ) - { - - /* - * No new constraints added during last activation - only - * ones which were at the boundary (ActiveSet[I]=0), but - * inactive due to numerical noise. - * - * Now, these constraints are added to the active set, and - * we try to perform steepest descent (Phase 2) one more time. - */ - continue; - } - else - { - - /* - * Last step activated at least one significantly new - * constraint (ActiveSet[I]<0), we have to re-evaluate - * active set (Phase 1). - */ - nextaction = -1; - break; - } - } - if( nextaction<0 ) - { - continue; - } - if( nextaction==0 ) - { - break; - } - - /* - * Phase 3: fast equality-constrained solver - * - * NOTE: this solver uses Augmented Lagrangian algorithm to solve - * equality-constrained subproblems. This algorithm may - * perform steps which increase function values instead of - * decreasing it (in hard cases, like overconstrained problems). - * - * Such non-monononic steps may create a loop, when Augmented - * Lagrangian algorithm performs uphill step, and steepest - * descent algorithm (Phase 2) performs downhill step in the - * opposite direction. - * - * In order to prevent iterations to continue forever we - * count iterations when AL algorithm increased function - * value instead of decreasing it. When number of such "bad" - * iterations will increase beyong MaxBadNewtonIts, we will - * terminate algorithm. - */ - fprev = minqp_minqpmodelvalue(&state->a, &state->b, &state->sas.xc, n, &state->tmp0, _state); - for(;;) - { - - /* - * Calculate optimum subject to presently active constraints - */ - state->repncholesky = state->repncholesky+1; - state->debugphase3flops = state->debugphase3flops+ae_pow(n, 3, _state)/3; - if( !minqp_minqpconstrainedoptimum(state, &state->a, state->anorm, &state->b, &state->xn, &state->tmp0, &state->tmpb, &state->tmp1, _state) ) - { - state->repterminationtype = -5; - sasstopoptimization(&state->sas, _state); - return; - } - - /* - * Add constraints. - * If no constraints was added, accept candidate point XN and move to next phase. - */ - if( minqp_minqpboundedstepandactivation(state, &state->xn, &state->tmp0, _state)<0 ) - { - break; - } - } - fcur = minqp_minqpmodelvalue(&state->a, &state->b, &state->sas.xc, n, &state->tmp0, _state); - if( ae_fp_greater_eq(fcur,fprev) ) - { - badnewtonits = badnewtonits+1; - } - if( badnewtonits>=minqp_maxbadnewtonits ) - { - - /* - * Algorithm found solution, but keeps iterating because Newton - * algorithm performs uphill steps (noise in the Augmented Lagrangian - * algorithm). We terminate algorithm; it is considered normal - * termination. - */ - break; - } - } - sasstopoptimization(&state->sas, _state); - - /* - * Post-process: add XOrigin to XC - */ - for(i=0; i<=n-1; i++) - { - if( state->havebndl.ptr.p_bool[i]&&ae_fp_eq(state->sas.xc.ptr.p_double[i],state->workbndl.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; - continue; - } - if( state->havebndu.ptr.p_bool[i]&&ae_fp_eq(state->sas.xc.ptr.p_double[i],state->workbndu.ptr.p_double[i]) ) - { - state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; - continue; - } - state->xs.ptr.p_double[i] = boundval(state->sas.xc.ptr.p_double[i]+state->xorigin.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - return; - } - - /* - * BLEIC solver - */ - if( state->algokind==2 ) - { - ae_assert(state->akind==0||state->akind==1, "MinQPOptimize: unexpected AKind", _state); - ivectorsetlengthatleast(&state->tmpi, state->nec+state->nic, _state); - rvectorsetlengthatleast(&state->tmp0, n, _state); - rvectorsetlengthatleast(&state->tmp1, n, _state); - for(i=0; i<=state->nec-1; i++) - { - state->tmpi.ptr.p_int[i] = 0; - } - for(i=0; i<=state->nic-1; i++) - { - state->tmpi.ptr.p_int[state->nec+i] = -1; - } - minbleicsetlc(&state->solver, &state->cleic, &state->tmpi, state->nec+state->nic, _state); - minbleicsetbc(&state->solver, &state->bndl, &state->bndu, _state); - minbleicsetdrep(&state->solver, ae_true, _state); - minbleicsetcond(&state->solver, ae_minrealnumber, 0.0, 0.0, state->bleicmaxits, _state); - minbleicsetscale(&state->solver, &state->s, _state); - minbleicsetprecscale(&state->solver, _state); - minbleicrestartfrom(&state->solver, &state->xs, _state); - state->repterminationtype = 0; - while(minbleiciteration(&state->solver, _state)) - { - - /* - * Line search started - */ - if( state->solver.lsstart ) - { - - /* - * Iteration counters: - * * inner iterations count is increased on every line search - * * outer iterations count is increased only at steepest descent line search - */ - inc(&state->repinneriterationscount, _state); - if( !state->solver.lbfgssearch ) - { - inc(&state->repouteriterationscount, _state); - } - - /* - * Build quadratic model of F along descent direction: - * F(x+alpha*d) = D2*alpha^2 + D1*alpha + D0 - */ - d0 = state->solver.f; - d1 = ae_v_dotproduct(&state->solver.d.ptr.p_double[0], 1, &state->solver.g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - d2 = 0; - if( state->akind==0 ) - { - d2 = cqmxtadx2(&state->a, &state->solver.d, _state); - } - if( state->akind==1 ) - { - sparsesmv(&state->sparsea, state->sparseaupper, &state->solver.d, &state->tmp0, _state); - d2 = 0.0; - for(i=0; i<=n-1; i++) - { - d2 = d2+state->solver.d.ptr.p_double[i]*state->tmp0.ptr.p_double[i]; - } - d2 = 0.5*d2; - } - - /* - * Suggest new step - */ - if( ae_fp_less(d1,0)&&ae_fp_greater(d2,0) ) - { - state->solver.stp = safeminposrv(-d1, 2*d2, state->solver.curstpmax, _state); - } - - /* - * This line search may be started from steepest descent - * stage (stage 2) or from L-BFGS stage (stage 3) of the - * BLEIC algorithm. Depending on stage type, different - * checks are performed. - * - * Say, L-BFGS stage is an equality-constrained refinement - * stage of BLEIC. This stage refines current iterate - * under "frozen" equality constraints. We can terminate - * iterations at this stage only when we encounter - * unconstrained direction of negative curvature. In all - * other cases (say, when constrained gradient is zero) - * we should not terminate algorithm because everything may - * change after de-activating presently active constraints. - * - * At steepest descent stage of BLEIC we can terminate algorithm - * because it found minimum (steepest descent step is zero - * or too short). We also perform check for direction of - * negative curvature. - */ - if( (ae_fp_less(d2,0)||(ae_fp_eq(d2,0)&&ae_fp_less(d1,0)))&&!state->solver.boundedstep ) - { - - /* - * Function is unbounded from below: - * * function will decrease along D, i.e. either: - * * D2<0 - * * D2=0 and D1<0 - * * step is unconstrained - * - * If these conditions are true, we abnormally terminate QP - * algorithm with return code -4 (we can do so at any stage - * of BLEIC - whether it is L-BFGS or steepest descent one). - */ - state->repterminationtype = -4; - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->solver.x.ptr.p_double[i]; - } - break; - } - if( !state->solver.lbfgssearch&&ae_fp_greater_eq(d2,0) ) - { - - /* - * Tests for "normal" convergence. - * - * These tests are performed only at "steepest descent" stage - * of the BLEIC algorithm, and only when function is non-concave - * (D2>=0) along direction D. - * - * NOTE: we do not test iteration count (MaxIts) here, because - * this stopping condition is tested by BLEIC itself. - */ - if( ae_fp_greater_eq(d1,0) ) - { - - /* - * "Emergency" stopping condition: D is non-descent direction. - * Sometimes it is possible because of numerical noise in the - * target function. - */ - state->repterminationtype = 4; - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->solver.x.ptr.p_double[i]; - } - break; - } - if( ae_fp_greater(d2,0) ) - { - - /* - * Stopping condition #4 - gradient norm is small: - * - * 1. rescale State.Solver.D and State.Solver.G according to - * current scaling, store results to Tmp0 and Tmp1. - * 2. Normalize Tmp0 (scaled direction vector). - * 3. compute directional derivative (in scaled variables), - * which is equal to DOTPRODUCT(Tmp0,Tmp1). - */ - v = 0; - for(i=0; i<=n-1; i++) - { - state->tmp0.ptr.p_double[i] = state->solver.d.ptr.p_double[i]/state->s.ptr.p_double[i]; - state->tmp1.ptr.p_double[i] = state->solver.g.ptr.p_double[i]*state->s.ptr.p_double[i]; - v = v+ae_sqr(state->tmp0.ptr.p_double[i], _state); - } - ae_assert(ae_fp_greater(v,0), "MinQPOptimize: inernal errror (scaled direction is zero)", _state); - v = 1/ae_sqrt(v, _state); - ae_v_muld(&state->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - v = ae_v_dotproduct(&state->tmp0.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_less_eq(ae_fabs(v, _state),state->bleicepsg) ) - { - state->repterminationtype = 4; - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->solver.x.ptr.p_double[i]; - } - break; - } - - /* - * Stopping condition #1 - relative function improvement is small: - * - * 1. calculate steepest descent step: V = -D1/(2*D2) - * 2. calculate function change: V1= D2*V^2 + D1*V - * 3. stop if function change is small enough - */ - v = -d1/(2*d2); - v1 = d2*v*v+d1*v; - if( ae_fp_less_eq(ae_fabs(v1, _state),state->bleicepsf*ae_maxreal(d0, 1.0, _state)) ) - { - state->repterminationtype = 1; - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->solver.x.ptr.p_double[i]; - } - break; - } - - /* - * Stopping condition #2 - scaled step is small: - * - * 1. calculate step multiplier V0 (step itself is D*V0) - * 2. calculate scaled step length V - * 3. stop if step is small enough - */ - v0 = -d1/(2*d2); - v = 0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(v0*state->solver.d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); - } - if( ae_fp_less_eq(ae_sqrt(v, _state),state->bleicepsx) ) - { - state->repterminationtype = 2; - for(i=0; i<=n-1; i++) - { - state->xs.ptr.p_double[i] = state->solver.x.ptr.p_double[i]; - } - break; - } - } - } - } - - /* - * Gradient evaluation - */ - if( state->solver.needfg ) - { - for(i=0; i<=n-1; i++) - { - state->tmp0.ptr.p_double[i] = state->solver.x.ptr.p_double[i]-state->xorigin.ptr.p_double[i]; - } - if( state->akind==0 ) - { - cqmadx(&state->a, &state->tmp0, &state->tmp1, _state); - } - if( state->akind==1 ) - { - sparsesmv(&state->sparsea, state->sparseaupper, &state->tmp0, &state->tmp1, _state); - } - v0 = ae_v_dotproduct(&state->tmp0.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v1 = ae_v_dotproduct(&state->tmp0.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->solver.f = 0.5*v0+v1; - ae_v_move(&state->solver.g.ptr.p_double[0], 1, &state->tmp1.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->solver.g.ptr.p_double[0], 1, &state->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); - } - } - if( state->repterminationtype==0 ) - { - - /* - * BLEIC optimizer was terminated by one of its inner stopping - * conditions. Usually it is iteration counter (if such - * stopping condition was specified by user). - */ - minbleicresults(&state->solver, &state->xs, &state->solverrep, _state); - state->repterminationtype = state->solverrep.terminationtype; - } - else - { - - /* - * BLEIC optimizer was terminated in "emergency" mode by QP - * solver. - * - * NOTE: such termination is "emergency" only when viewed from - * BLEIC's position. QP solver sees such termination as - * routine one, triggered by QP's stopping criteria. - */ - minbleicemergencytermination(&state->solver, _state); - } - return; - } -} - - -/************************************************************************* -QP solver results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution. - This array is allocated and initialized only when - Rep.TerminationType parameter is positive (success). - Rep - optimization report. You should check Rep.TerminationType, - which contains completion code, and you may check another - fields which contain another information about algorithm - functioning. - - Failure codes returned by algorithm are: - * -5 inappropriate solver was used: - * Cholesky solver for (semi)indefinite problems - * Cholesky solver for problems with sparse matrix - * -4 BLEIC-QP algorithm found unconstrained direction - of negative curvature (function is unbounded from - below even under constraints), no meaningful - minimum can be found. - * -3 inconsistent constraints (or maybe feasible point - is too hard to find). If you are sure that - constraints are feasible, try to restart optimizer - with better initial approximation. - - Completion codes specific for Cholesky algorithm: - * 4 successful completion - - Completion codes specific for BLEIC-based algorithm: - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresults(minqpstate* state, - /* Real */ ae_vector* x, - minqpreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _minqpreport_clear(rep); - - minqpresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -QP results - -Buffered implementation of MinQPResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresultsbuf(minqpstate* state, - /* Real */ ae_vector* x, - minqpreport* rep, - ae_state *_state) -{ - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->xs.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->inneriterationscount = state->repinneriterationscount; - rep->outeriterationscount = state->repouteriterationscount; - rep->nmv = state->repnmv; - rep->ncholesky = state->repncholesky; - rep->terminationtype = state->repterminationtype; -} - - -/************************************************************************* -Fast version of MinQPSetLinearTerm(), which doesn't check its arguments. -For internal use only. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlineartermfast(minqpstate* state, - /* Real */ ae_vector* b, - ae_state *_state) -{ - - - ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); -} - - -/************************************************************************* -Fast version of MinQPSetQuadraticTerm(), which doesn't check its arguments. - -It accepts additional parameter - shift S, which allows to "shift" matrix -A by adding s*I to A. S must be positive (although it is not checked). - -For internal use only. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadratictermfast(minqpstate* state, - /* Real */ ae_matrix* a, - ae_bool isupper, - double s, - ae_state *_state) -{ - ae_int_t i; - ae_int_t j; - ae_int_t n; - - - n = state->n; - state->akind = 0; - cqmseta(&state->a, a, isupper, 1.0, _state); - if( ae_fp_greater(s,0) ) - { - rvectorsetlengthatleast(&state->tmp0, n, _state); - for(i=0; i<=n-1; i++) - { - state->tmp0.ptr.p_double[i] = a->ptr.pp_double[i][i]+s; - } - cqmrewritedensediagonal(&state->a, &state->tmp0, _state); - } - - /* - * Estimate norm of A - * (it will be used later in the quadratic penalty function) - */ - state->anorm = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - for(j=i; j<=n-1; j++) - { - state->anorm = ae_maxreal(state->anorm, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - else - { - for(j=0; j<=i; j++) - { - state->anorm = ae_maxreal(state->anorm, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - } - state->anorm = state->anorm*n; -} - - -/************************************************************************* -Internal function which allows to rewrite diagonal of quadratic term. -For internal use only. - -This function can be used only when you have dense A and already made -MinQPSetQuadraticTerm(Fast) call. - - -- ALGLIB -- - Copyright 16.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqprewritediagonal(minqpstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - - - cqmrewritedensediagonal(&state->a, s, _state); -} - - -/************************************************************************* -Fast version of MinQPSetStartingPoint(), which doesn't check its arguments. -For internal use only. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetstartingpointfast(minqpstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_int_t n; - - - n = state->n; - ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->havex = ae_true; -} - - -/************************************************************************* -Fast version of MinQPSetOrigin(), which doesn't check its arguments. -For internal use only. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetoriginfast(minqpstate* state, - /* Real */ ae_vector* xorigin, - ae_state *_state) -{ - ae_int_t n; - - - n = state->n; - ae_v_move(&state->xorigin.ptr.p_double[0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1)); -} - - -/************************************************************************* -Having feasible current point XC and possibly infeasible candidate point -XN, this function performs longest step from XC to XN which retains -feasibility. In case XN is found to be infeasible, at least one constraint -is activated. - -For example, if we have: - XC=0.5 - XN=1.2 - x>=0, x<=1 -then this function will move us to X=1.0 and activate constraint "x<=1". - -INPUT PARAMETERS: - State - MinQP state. - XC - current point, must be feasible with respect to - all constraints - XN - candidate point, can be infeasible with respect to some - constraints. Must be located in the subspace of current - active set, i.e. it is feasible with respect to already - active constraints. - Buf - temporary buffer, automatically resized if needed - -OUTPUT PARAMETERS: - State - this function changes following fields of State: - * State.ActiveSet - * State.ActiveC - active linear constraints - XC - new position - -RESULT: - >0, in case at least one inactive non-candidate constraint was activated - =0, in case only "candidate" constraints were activated - <0, in case no constraints were activated by the step - - - -- ALGLIB -- - Copyright 29.02.2012 by Bochkanov Sergey -*************************************************************************/ -static ae_int_t minqp_minqpboundedstepandactivation(minqpstate* state, - /* Real */ ae_vector* xn, - /* Real */ ae_vector* buf, - ae_state *_state) -{ - ae_int_t n; - double stpmax; - ae_int_t cidx; - double cval; - ae_bool needact; - double v; - ae_int_t result; - - - n = state->n; - rvectorsetlengthatleast(buf, n, _state); - ae_v_move(&buf->ptr.p_double[0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_sub(&buf->ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - sasexploredirection(&state->sas, buf, &stpmax, &cidx, &cval, _state); - needact = ae_fp_less_eq(stpmax,1); - v = ae_minreal(stpmax, 1.0, _state); - ae_v_muld(&buf->ptr.p_double[0], 1, ae_v_len(0,n-1), v); - ae_v_add(&buf->ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - result = sasmoveto(&state->sas, buf, needact, cidx, cval, _state); - return result; -} - - -/************************************************************************* -Model value: f = 0.5*x'*A*x + b'*x - -INPUT PARAMETERS: - A - convex quadratic model; only main quadratic term is used, - other parts of the model (D/Q/linear term) are ignored. - This function does not modify model state. - B - right part - XC - evaluation point - Tmp - temporary buffer, automatically resized if needed - - -- ALGLIB -- - Copyright 20.06.2012 by Bochkanov Sergey -*************************************************************************/ -static double minqp_minqpmodelvalue(convexquadraticmodel* a, - /* Real */ ae_vector* b, - /* Real */ ae_vector* xc, - ae_int_t n, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - double v0; - double v1; - double result; - - - rvectorsetlengthatleast(tmp, n, _state); - cqmadx(a, xc, tmp, _state); - v0 = ae_v_dotproduct(&xc->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,n-1)); - v1 = ae_v_dotproduct(&xc->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - result = 0.5*v0+v1; - return result; -} - - -/************************************************************************* -Optimum of A subject to: -a) active boundary constraints (given by ActiveSet[] and corresponding - elements of XC) -b) active linear constraints (given by C, R, LagrangeC) - -INPUT PARAMETERS: - A - main quadratic term of the model; - although structure may store linear and rank-K terms, - these terms are ignored and rewritten by this function. - ANorm - estimate of ||A|| (2-norm is used) - B - array[N], linear term of the model - XN - possibly preallocated buffer - Tmp - temporary buffer (automatically resized) - Tmp1 - temporary buffer (automatically resized) - -OUTPUT PARAMETERS: - A - modified quadratic model (this function changes rank-K - term and linear term of the model) - LagrangeC- current estimate of the Lagrange coefficients - XN - solution - -RESULT: - True on success, False on failure (non-SPD model) - - -- ALGLIB -- - Copyright 20.06.2012 by Bochkanov Sergey -*************************************************************************/ -static ae_bool minqp_minqpconstrainedoptimum(minqpstate* state, - convexquadraticmodel* a, - double anorm, - /* Real */ ae_vector* b, - /* Real */ ae_vector* xn, - /* Real */ ae_vector* tmp, - /* Boolean */ ae_vector* tmpb, - /* Real */ ae_vector* lagrangec, - ae_state *_state) -{ - ae_int_t itidx; - ae_int_t i; - double v; - double feaserrold; - double feaserrnew; - double theta; - ae_int_t n; - ae_bool result; - - - n = state->n; - - /* - * Rebuild basis accroding to current active set. - * We call SASRebuildBasis() to make sure that fields of SAS - * store up to date values. - */ - sasrebuildbasis(&state->sas, _state); - - /* - * Allocate temporaries. - */ - rvectorsetlengthatleast(tmp, ae_maxint(n, state->sas.basissize, _state), _state); - bvectorsetlengthatleast(tmpb, n, _state); - rvectorsetlengthatleast(lagrangec, state->sas.basissize, _state); - - /* - * Prepare model - */ - for(i=0; i<=state->sas.basissize-1; i++) - { - tmp->ptr.p_double[i] = state->sas.pbasis.ptr.pp_double[i][n]; - } - theta = 100.0*anorm; - for(i=0; i<=n-1; i++) - { - if( state->sas.activeset.ptr.p_int[i]>0 ) - { - tmpb->ptr.p_bool[i] = ae_true; - } - else - { - tmpb->ptr.p_bool[i] = ae_false; - } - } - cqmsetactiveset(a, &state->sas.xc, tmpb, _state); - cqmsetq(a, &state->sas.pbasis, tmp, state->sas.basissize, theta, _state); - - /* - * Iterate until optimal values of Lagrange multipliers are found - */ - for(i=0; i<=state->sas.basissize-1; i++) - { - lagrangec->ptr.p_double[i] = 0; - } - feaserrnew = ae_maxrealnumber; - result = ae_true; - for(itidx=1; itidx<=minqp_maxlagrangeits; itidx++) - { - - /* - * Generate right part B using linear term and current - * estimate of the Lagrange multipliers. - */ - ae_v_move(&tmp->ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=state->sas.basissize-1; i++) - { - v = lagrangec->ptr.p_double[i]; - ae_v_subd(&tmp->ptr.p_double[0], 1, &state->sas.pbasis.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); - } - cqmsetb(a, tmp, _state); - - /* - * Solve - */ - result = cqmconstrainedoptimum(a, xn, _state); - if( !result ) - { - return result; - } - - /* - * Compare feasibility errors. - * Terminate if error decreased too slowly. - */ - feaserrold = feaserrnew; - feaserrnew = 0; - for(i=0; i<=state->sas.basissize-1; i++) - { - v = ae_v_dotproduct(&state->sas.pbasis.ptr.pp_double[i][0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); - feaserrnew = feaserrnew+ae_sqr(v-state->sas.pbasis.ptr.pp_double[i][n], _state); - } - feaserrnew = ae_sqrt(feaserrnew, _state); - if( ae_fp_greater_eq(feaserrnew,0.2*feaserrold) ) - { - break; - } - - /* - * Update Lagrange multipliers - */ - for(i=0; i<=state->sas.basissize-1; i++) - { - v = ae_v_dotproduct(&state->sas.pbasis.ptr.pp_double[i][0], 1, &xn->ptr.p_double[0], 1, ae_v_len(0,n-1)); - lagrangec->ptr.p_double[i] = lagrangec->ptr.p_double[i]-theta*(v-state->sas.pbasis.ptr.pp_double[i][n]); - } - } - return result; -} - - -ae_bool _minqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minqpstate *p = (minqpstate*)_p; - ae_touch_ptr((void*)p); - if( !_convexquadraticmodel_init(&p->a, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init(&p->sparsea, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xorigin, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->startx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_sactiveset_init(&p->sas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->pg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->workbndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->workbndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->workcleic, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpb, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rctmpg, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic) ) - return ae_false; - if( !_normestimatorstate_init(&p->estimator, _state, make_automatic) ) - return ae_false; - if( !_minbleicstate_init(&p->solver, _state, make_automatic) ) - return ae_false; - if( !_minbleicreport_init(&p->solverrep, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _minqpstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minqpstate *dst = (minqpstate*)_dst; - minqpstate *src = (minqpstate*)_src; - dst->n = src->n; - dst->algokind = src->algokind; - dst->akind = src->akind; - if( !_convexquadraticmodel_init_copy(&dst->a, &src->a, _state, make_automatic) ) - return ae_false; - if( !_sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state, make_automatic) ) - return ae_false; - dst->sparseaupper = src->sparseaupper; - dst->anorm = src->anorm; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->startx, &src->startx, _state, make_automatic) ) - return ae_false; - dst->havex = src->havex; - if( !ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic) ) - return ae_false; - dst->nec = src->nec; - dst->nic = src->nic; - dst->bleicepsg = src->bleicepsg; - dst->bleicepsf = src->bleicepsf; - dst->bleicepsx = src->bleicepsx; - dst->bleicmaxits = src->bleicmaxits; - if( !_sactiveset_init_copy(&dst->sas, &src->sas, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->pg, &src->pg, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->workbndl, &src->workbndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->workbndu, &src->workbndu, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->workcleic, &src->workcleic, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic) ) - return ae_false; - dst->repinneriterationscount = src->repinneriterationscount; - dst->repouteriterationscount = src->repouteriterationscount; - dst->repncholesky = src->repncholesky; - dst->repnmv = src->repnmv; - dst->repterminationtype = src->repterminationtype; - dst->debugphase1flops = src->debugphase1flops; - dst->debugphase2flops = src->debugphase2flops; - dst->debugphase3flops = src->debugphase3flops; - if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rctmpg, &src->rctmpg, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic) ) - return ae_false; - if( !_normestimatorstate_init_copy(&dst->estimator, &src->estimator, _state, make_automatic) ) - return ae_false; - if( !_minbleicstate_init_copy(&dst->solver, &src->solver, _state, make_automatic) ) - return ae_false; - if( !_minbleicreport_init_copy(&dst->solverrep, &src->solverrep, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _minqpstate_clear(void* _p) -{ - minqpstate *p = (minqpstate*)_p; - ae_touch_ptr((void*)p); - _convexquadraticmodel_clear(&p->a); - _sparsematrix_clear(&p->sparsea); - ae_vector_clear(&p->b); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_vector_clear(&p->s); - ae_vector_clear(&p->havebndl); - ae_vector_clear(&p->havebndu); - ae_vector_clear(&p->xorigin); - ae_vector_clear(&p->startx); - ae_matrix_clear(&p->cleic); - _sactiveset_clear(&p->sas); - ae_vector_clear(&p->gc); - ae_vector_clear(&p->xn); - ae_vector_clear(&p->pg); - ae_vector_clear(&p->workbndl); - ae_vector_clear(&p->workbndu); - ae_matrix_clear(&p->workcleic); - ae_vector_clear(&p->xs); - ae_vector_clear(&p->tmp0); - ae_vector_clear(&p->tmp1); - ae_vector_clear(&p->tmpb); - ae_vector_clear(&p->rctmpg); - ae_vector_clear(&p->tmpi); - _normestimatorstate_clear(&p->estimator); - _minbleicstate_clear(&p->solver); - _minbleicreport_clear(&p->solverrep); -} - - -void _minqpstate_destroy(void* _p) -{ - minqpstate *p = (minqpstate*)_p; - ae_touch_ptr((void*)p); - _convexquadraticmodel_destroy(&p->a); - _sparsematrix_destroy(&p->sparsea); - ae_vector_destroy(&p->b); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->havebndl); - ae_vector_destroy(&p->havebndu); - ae_vector_destroy(&p->xorigin); - ae_vector_destroy(&p->startx); - ae_matrix_destroy(&p->cleic); - _sactiveset_destroy(&p->sas); - ae_vector_destroy(&p->gc); - ae_vector_destroy(&p->xn); - ae_vector_destroy(&p->pg); - ae_vector_destroy(&p->workbndl); - ae_vector_destroy(&p->workbndu); - ae_matrix_destroy(&p->workcleic); - ae_vector_destroy(&p->xs); - ae_vector_destroy(&p->tmp0); - ae_vector_destroy(&p->tmp1); - ae_vector_destroy(&p->tmpb); - ae_vector_destroy(&p->rctmpg); - ae_vector_destroy(&p->tmpi); - _normestimatorstate_destroy(&p->estimator); - _minbleicstate_destroy(&p->solver); - _minbleicreport_destroy(&p->solverrep); -} - - -ae_bool _minqpreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minqpreport *p = (minqpreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _minqpreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minqpreport *dst = (minqpreport*)_dst; - minqpreport *src = (minqpreport*)_src; - dst->inneriterationscount = src->inneriterationscount; - dst->outeriterationscount = src->outeriterationscount; - dst->nmv = src->nmv; - dst->ncholesky = src->ncholesky; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _minqpreport_clear(void* _p) -{ - minqpreport *p = (minqpreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _minqpreport_destroy(void* _p) -{ - minqpreport *p = (minqpreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] and Jacobian of f[]. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function vector f[] at given point X -* function vector f[] and Jacobian of f[] (simultaneously) at given point - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() and jac() callbacks. -First one is used to calculate f[] at given point, second one calculates -f[] and Jacobian df[i]/dx[j]. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not provide Jacobian), but it -will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateVJ() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - ae_assert(n>=1, "MinLMCreateVJ: N<1!", _state); - ae_assert(m>=1, "MinLMCreateVJ: M<1!", _state); - ae_assert(x->cnt>=n, "MinLMCreateVJ: Length(X)teststep = 0; - state->n = n; - state->m = m; - state->algomode = 1; - state->hasf = ae_false; - state->hasfi = ae_true; - state->hasg = ae_false; - - /* - * second stage of initialization - */ - minlm_lmprepare(n, m, ae_false, state, _state); - minlmsetacctype(state, 0, _state); - minlmsetcond(state, 0, 0, 0, 0, _state); - minlmsetxrep(state, ae_false, _state); - minlmsetstpmax(state, 0, _state); - minlmrestartfrom(state, x, _state); -} - - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] only. Finite differences are used to -calculate Jacobian. - - -REQUIREMENTS: -This algorithm will request following information during its operation: -* function vector f[] at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() callback. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not accept function vector), but -it will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateV() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also MinLMIteration, MinLMResults. - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatev(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - double diffstep, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - ae_assert(ae_isfinite(diffstep, _state), "MinLMCreateV: DiffStep is not finite!", _state); - ae_assert(ae_fp_greater(diffstep,0), "MinLMCreateV: DiffStep<=0!", _state); - ae_assert(n>=1, "MinLMCreateV: N<1!", _state); - ae_assert(m>=1, "MinLMCreateV: M<1!", _state); - ae_assert(x->cnt>=n, "MinLMCreateV: Length(X)teststep = 0; - state->n = n; - state->m = m; - state->algomode = 0; - state->hasf = ae_false; - state->hasfi = ae_true; - state->hasg = ae_false; - state->diffstep = diffstep; - - /* - * Second stage of initialization - */ - minlm_lmprepare(n, m, ae_false, state, _state); - minlmsetacctype(state, 1, _state); - minlmsetcond(state, 0, 0, 0, 0, _state); - minlmsetxrep(state, ae_false, _state); - minlmsetstpmax(state, 0, _state); - minlmrestartfrom(state, x, _state); -} - - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of general form (not "sum-of- --squares") function - F = F(x[0], ..., x[n-1]) -using its gradient and Hessian. Levenberg-Marquardt modification with -L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization -after each Levenberg-Marquardt step is used. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function value F at given point X -* F and gradient G (simultaneously) at given point X -* F, G and Hessian H (simultaneously) at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts func(), grad() and hess() -function pointers. First pointer is used to calculate F at given point, -second one calculates F(x) and grad F(x), third one calculates F(x), -grad F(x), hess F(x). - -You can try to initialize MinLMState structure with FGH-function and then -use incorrect version of MinLMOptimize() (for example, version which does -not provide Hessian matrix), but it will lead to exception being thrown -after first attempt to calculate Hessian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateFGH() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - pointers (delegates, etc.) to callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgh(ae_int_t n, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - ae_assert(n>=1, "MinLMCreateFGH: N<1!", _state); - ae_assert(x->cnt>=n, "MinLMCreateFGH: Length(X)teststep = 0; - state->n = n; - state->m = 0; - state->algomode = 2; - state->hasf = ae_true; - state->hasfi = ae_false; - state->hasg = ae_true; - - /* - * init2 - */ - minlm_lmprepare(n, 0, ae_true, state, _state); - minlmsetacctype(state, 2, _state); - minlmsetcond(state, 0, 0, 0, 0, _state); - minlmsetxrep(state, ae_false, _state); - minlmsetstpmax(state, 0, _state); - minlmrestartfrom(state, x, _state); -} - - -/************************************************************************* -This function sets stopping conditions for Levenberg-Marquardt optimization -algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLMSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetcond(minlmstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinLMSetCond: EpsG is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinLMSetCond: negative EpsG!", _state); - ae_assert(ae_isfinite(epsf, _state), "MinLMSetCond: EpsF is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinLMSetCond: negative EpsF!", _state); - ae_assert(ae_isfinite(epsx, _state), "MinLMSetCond: EpsX is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinLMSetCond: negative EpsX!", _state); - ae_assert(maxits>=0, "MinLMSetCond: negative MaxIts!", _state); - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->epsg = epsg; - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS -iterations are reported. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "MinLMSetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "MinLMSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* -This function sets scaling coefficients for LM optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetscale(minlmstate* state, - /* Real */ ae_vector* s, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(s->cnt>=state->n, "MinLMSetScale: Length(S)n-1; i++) - { - ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLMSetScale: S contains infinite or NAN elements", _state); - ae_assert(ae_fp_neq(s->ptr.p_double[i],0), "MinLMSetScale: S contains zero elements", _state); - state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function sets boundary constraints for LM optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: this solver has following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - or at its boundary - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetbc(minlmstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state) -{ - ae_int_t i; - ae_int_t n; - - - n = state->n; - ae_assert(bndl->cnt>=n, "MinLMSetBC: Length(BndL)cnt>=n, "MinLMSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLMSetBC: BndL contains NAN or +INF", _state); - ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLMSetBC: BndU contains NAN or -INF", _state); - state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; - state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); - state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; - state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); - } -} - - -/************************************************************************* -This function is used to change acceleration settings - -You can choose between three acceleration strategies: -* AccType=0, no acceleration. -* AccType=1, secant updates are used to update quadratic model after each - iteration. After fixed number of iterations (or after model breakdown) - we recalculate quadratic model using analytic Jacobian or finite - differences. Number of secant-based iterations depends on optimization - settings: about 3 iterations - when we have analytic Jacobian, up to 2*N - iterations - when we use finite differences to calculate Jacobian. - -AccType=1 is recommended when Jacobian calculation cost is prohibitive -high (several Mx1 function vector calculations followed by several NxN -Cholesky factorizations are faster than calculation of one M*N Jacobian). -It should also be used when we have no Jacobian, because finite difference -approximation takes too much time to compute. - -Table below list optimization protocols (XYZ protocol corresponds to -MinLMCreateXYZ) and acceleration types they support (and use by default). - -ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: - -protocol 0 1 comment -V + + -VJ + + -FGH + - -DAFAULT VALUES: - -protocol 0 1 comment -V x without acceleration it is so slooooooooow -VJ x -FGH x - -NOTE: this function should be called before optimization. Attempt to call -it during algorithm iterations may result in unexpected behavior. - -NOTE: attempt to call this function with unsupported protocol/acceleration -combination will result in exception being thrown. - - -- ALGLIB -- - Copyright 14.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetacctype(minlmstate* state, - ae_int_t acctype, - ae_state *_state) -{ - - - ae_assert((acctype==0||acctype==1)||acctype==2, "MinLMSetAccType: incorrect AccType!", _state); - if( acctype==2 ) - { - acctype = 0; - } - if( acctype==0 ) - { - state->maxmodelage = 0; - state->makeadditers = ae_false; - return; - } - if( acctype==1 ) - { - ae_assert(state->hasfi, "MinLMSetAccType: AccType=1 is incompatible with current protocol!", _state); - if( state->algomode==0 ) - { - state->maxmodelage = 2*state->n; - } - else - { - state->maxmodelage = minlm_smallmodelage; - } - state->makeadditers = ae_false; - return; - } -} - - -/************************************************************************* -NOTES: - -1. Depending on function used to create state structure, this algorithm - may accept Jacobian and/or Hessian and/or gradient. According to the - said above, there ase several versions of this function, which accept - different sets of callbacks. - - This flexibility opens way to subtle errors - you may create state with - MinLMCreateFGH() (optimization using Hessian), but call function which - does not accept Hessian. So when algorithm will request Hessian, there - will be no callback to call. In this case exception will be thrown. - - Be careful to avoid such errors because there is no way to find them at - compile time - you can see them at runtime only. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool minlmiteration(minlmstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t m; - ae_bool bflag; - ae_int_t iflag; - double v; - double s; - double t; - ae_int_t i; - ae_int_t k; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - iflag = state->rstate.ia.ptr.p_int[2]; - i = state->rstate.ia.ptr.p_int[3]; - k = state->rstate.ia.ptr.p_int[4]; - bflag = state->rstate.ba.ptr.p_bool[0]; - v = state->rstate.ra.ptr.p_double[0]; - s = state->rstate.ra.ptr.p_double[1]; - t = state->rstate.ra.ptr.p_double[2]; - } - else - { - n = -983; - m = -989; - iflag = -834; - i = 900; - k = -287; - bflag = ae_false; - v = 214; - s = -338; - t = -686; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - if( state->rstate.stage==14 ) - { - goto lbl_14; - } - if( state->rstate.stage==15 ) - { - goto lbl_15; - } - if( state->rstate.stage==16 ) - { - goto lbl_16; - } - if( state->rstate.stage==17 ) - { - goto lbl_17; - } - if( state->rstate.stage==18 ) - { - goto lbl_18; - } - - /* - * Routine body - */ - - /* - * prepare - */ - n = state->n; - m = state->m; - state->repiterationscount = 0; - state->repterminationtype = 0; - state->repfuncidx = -1; - state->repvaridx = -1; - state->repnfunc = 0; - state->repnjac = 0; - state->repngrad = 0; - state->repnhess = 0; - state->repncholesky = 0; - - /* - * check consistency of constraints, - * enforce feasibility of the solution - * set constraints - */ - if( !enforceboundaryconstraints(&state->xbase, &state->bndl, &state->havebndl, &state->bndu, &state->havebndu, n, 0, _state) ) - { - state->repterminationtype = -3; - result = ae_false; - return result; - } - minqpsetbc(&state->qpstate, &state->bndl, &state->bndu, _state); - - /* - * Check, that transferred derivative value is right - */ - minlm_clearrequestfields(state, _state); - if( !(state->algomode==1&&ae_fp_greater(state->teststep,0)) ) - { - goto lbl_19; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->needfij = ae_true; - i = 0; -lbl_21: - if( i>n-1 ) - { - goto lbl_23; - } - ae_assert((state->havebndl.ptr.p_bool[i]&&ae_fp_less_eq(state->bndl.ptr.p_double[i],state->x.ptr.p_double[i]))||!state->havebndl.ptr.p_bool[i], "MinLM: internal error(State.X is out of bounds)", _state); - ae_assert((state->havebndu.ptr.p_bool[i]&&ae_fp_less_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]))||!state->havebndu.ptr.p_bool[i], "MinLMIteration: internal error(State.X is out of bounds)", _state); - v = state->x.ptr.p_double[i]; - state->x.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i]; - if( state->havebndl.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - state->xm1 = state->x.ptr.p_double[i]; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_move(&state->gm1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); - state->x.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i]; - if( state->havebndu.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - state->xp1 = state->x.ptr.p_double[i]; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_move(&state->gp1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); - state->x.ptr.p_double[i] = (state->xm1+state->xp1)/2; - if( state->havebndl.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_maxreal(state->x.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); - } - if( state->havebndu.ptr.p_bool[i] ) - { - state->x.ptr.p_double[i] = ae_minreal(state->x.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - ae_v_move(&state->fc1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_move(&state->gc1.ptr.p_double[0], 1, &state->j.ptr.pp_double[0][i], state->j.stride, ae_v_len(0,m-1)); - state->x.ptr.p_double[i] = v; - for(k=0; k<=m-1; k++) - { - if( !derivativecheck(state->fm1.ptr.p_double[k], state->gm1.ptr.p_double[k], state->fp1.ptr.p_double[k], state->gp1.ptr.p_double[k], state->fc1.ptr.p_double[k], state->gc1.ptr.p_double[k], state->xp1-state->xm1, _state) ) - { - state->repfuncidx = k; - state->repvaridx = i; - state->repterminationtype = -7; - result = ae_false; - return result; - } - } - i = i+1; - goto lbl_21; -lbl_23: - state->needfij = ae_false; -lbl_19: - - /* - * Initial report of current point - * - * Note 1: we rewrite State.X twice because - * user may accidentally change it after first call. - * - * Note 2: we set NeedF or NeedFI depending on what - * information about function we have. - */ - if( !state->xrep ) - { - goto lbl_24; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - if( !state->hasf ) - { - goto lbl_26; - } - state->needf = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needf = ae_false; - goto lbl_27; -lbl_26: - ae_assert(state->hasfi, "MinLM: internal error 2!", _state); - state->needfi = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->needfi = ae_false; - v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->f = v; -lbl_27: - state->repnfunc = state->repnfunc+1; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->xupdated = ae_false; -lbl_24: - - /* - * Prepare control variables - */ - state->nu = 1; - state->lambdav = -ae_maxrealnumber; - state->modelage = state->maxmodelage+1; - state->deltaxready = ae_false; - state->deltafready = ae_false; - - /* - * Main cycle. - * - * We move through it until either: - * * one of the stopping conditions is met - * * we decide that stopping conditions are too stringent - * and break from cycle - * - */ -lbl_28: - if( ae_false ) - { - goto lbl_29; - } - - /* - * First, we have to prepare quadratic model for our function. - * We use BFlag to ensure that model is prepared; - * if it is false at the end of this block, something went wrong. - * - * We may either calculate brand new model or update old one. - * - * Before this block we have: - * * State.XBase - current position. - * * State.DeltaX - if DeltaXReady is True - * * State.DeltaF - if DeltaFReady is True - * - * After this block is over, we will have: - * * State.XBase - base point (unchanged) - * * State.FBase - F(XBase) - * * State.GBase - linear term - * * State.QuadraticModel - quadratic term - * * State.LambdaV - current estimate for lambda - * - * We also clear DeltaXReady/DeltaFReady flags - * after initialization is done. - */ - bflag = ae_false; - if( !(state->algomode==0||state->algomode==1) ) - { - goto lbl_30; - } - - /* - * Calculate f[] and Jacobian - */ - if( !(state->modelage>state->maxmodelage||!(state->deltaxready&&state->deltafready)) ) - { - goto lbl_32; - } - - /* - * Refresh model (using either finite differences or analytic Jacobian) - */ - if( state->algomode!=0 ) - { - goto lbl_34; - } - - /* - * Optimization using F values only. - * Use finite differences to estimate Jacobian. - */ - ae_assert(state->hasfi, "MinLMIteration: internal error when estimating Jacobian (no f[])", _state); - k = 0; -lbl_36: - if( k>n-1 ) - { - goto lbl_38; - } - - /* - * We guard X[k] from leaving [BndL,BndU]. - * In case BndL=BndU, we assume that derivative in this direction is zero. - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; - if( state->havebndl.ptr.p_bool[k] ) - { - state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); - } - if( state->havebndu.ptr.p_bool[k] ) - { - state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); - } - state->xm1 = state->x.ptr.p_double[k]; - minlm_clearrequestfields(state, _state); - state->needfi = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->repnfunc = state->repnfunc+1; - ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; - if( state->havebndl.ptr.p_bool[k] ) - { - state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); - } - if( state->havebndu.ptr.p_bool[k] ) - { - state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); - } - state->xp1 = state->x.ptr.p_double[k]; - minlm_clearrequestfields(state, _state); - state->needfi = ae_true; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->repnfunc = state->repnfunc+1; - ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - v = state->xp1-state->xm1; - if( ae_fp_neq(v,0) ) - { - v = 1/v; - ae_v_moved(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); - ae_v_subd(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); - } - else - { - for(i=0; i<=m-1; i++) - { - state->j.ptr.pp_double[i][k] = 0; - } - } - k = k+1; - goto lbl_36; -lbl_38: - - /* - * Calculate F(XBase) - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->needfi = ae_true; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->needfi = ae_false; - state->repnfunc = state->repnfunc+1; - state->repnjac = state->repnjac+1; - - /* - * New model - */ - state->modelage = 0; - goto lbl_35; -lbl_34: - - /* - * Obtain f[] and Jacobian - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->needfij = ae_true; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->needfij = ae_false; - state->repnfunc = state->repnfunc+1; - state->repnjac = state->repnjac+1; - - /* - * New model - */ - state->modelage = 0; -lbl_35: - goto lbl_33; -lbl_32: - - /* - * State.J contains Jacobian or its current approximation; - * refresh it using secant updates: - * - * f(x0+dx) = f(x0) + J*dx, - * J_new = J_old + u*h' - * h = x_new-x_old - * u = (f_new - f_old - J_old*h)/(h'h) - * - * We can explicitly generate h and u, but it is - * preferential to do in-place calculations. Only - * I-th row of J_old is needed to calculate u[I], - * so we can update J row by row in one pass. - * - * NOTE: we expect that State.XBase contains new point, - * State.FBase contains old point, State.DeltaX and - * State.DeltaY contain updates from last step. - */ - ae_assert(state->deltaxready&&state->deltafready, "MinLMIteration: uninitialized DeltaX/DeltaF", _state); - t = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_assert(ae_fp_neq(t,0), "MinLM: internal error (T=0)", _state); - for(i=0; i<=m-1; i++) - { - v = ae_v_dotproduct(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = (state->deltaf.ptr.p_double[i]-v)/t; - ae_v_addd(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - ae_v_move(&state->fi.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_add(&state->fi.ptr.p_double[0], 1, &state->deltaf.ptr.p_double[0], 1, ae_v_len(0,m-1)); - - /* - * Increase model age - */ - state->modelage = state->modelage+1; -lbl_33: - - /* - * Generate quadratic model: - * f(xbase+dx) = - * = (f0 + J*dx)'(f0 + J*dx) - * = f0^2 + dx'J'f0 + f0*J*dx + dx'J'J*dx - * = f0^2 + 2*f0*J*dx + dx'J'J*dx - * - * Note that we calculate 2*(J'J) instead of J'J because - * our quadratic model is based on Tailor decomposition, - * i.e. it has 0.5 before quadratic term. - */ - rmatrixgemm(n, n, m, 2.0, &state->j, 0, 0, 1, &state->j, 0, 0, 0, 0.0, &state->quadraticmodel, 0, 0, _state); - rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->gbase, 0, _state); - ae_v_muld(&state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1), 2); - v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->fbase = v; - ae_v_move(&state->fibase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - - /* - * set control variables - */ - bflag = ae_true; -lbl_30: - if( state->algomode!=2 ) - { - goto lbl_39; - } - ae_assert(!state->hasfi, "MinLMIteration: internal error (HasFI is True in Hessian-based mode)", _state); - - /* - * Obtain F, G, H - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->needfgh = ae_true; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->needfgh = ae_false; - state->repnfunc = state->repnfunc+1; - state->repngrad = state->repngrad+1; - state->repnhess = state->repnhess+1; - rmatrixcopy(n, n, &state->h, 0, 0, &state->quadraticmodel, 0, 0, _state); - ae_v_move(&state->gbase.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fbase = state->f; - - /* - * set control variables - */ - bflag = ae_true; - state->modelage = 0; -lbl_39: - ae_assert(bflag, "MinLM: internal integrity check failed!", _state); - state->deltaxready = ae_false; - state->deltafready = ae_false; - - /* - * If Lambda is not initialized, initialize it using quadratic model - */ - if( ae_fp_less(state->lambdav,0) ) - { - state->lambdav = 0; - for(i=0; i<=n-1; i++) - { - state->lambdav = ae_maxreal(state->lambdav, ae_fabs(state->quadraticmodel.ptr.pp_double[i][i], _state)*ae_sqr(state->s.ptr.p_double[i], _state), _state); - } - state->lambdav = 0.001*state->lambdav; - if( ae_fp_eq(state->lambdav,0) ) - { - state->lambdav = 1; - } - } - - /* - * Test stopping conditions for function gradient - */ - if( ae_fp_greater(minlm_boundedscaledantigradnorm(state, &state->xbase, &state->gbase, _state),state->epsg) ) - { - goto lbl_41; - } - if( state->modelage!=0 ) - { - goto lbl_43; - } - - /* - * Model is fresh, we can rely on it and terminate algorithm - */ - state->repterminationtype = 4; - if( !state->xrep ) - { - goto lbl_45; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - state->xupdated = ae_false; -lbl_45: - result = ae_false; - return result; - goto lbl_44; -lbl_43: - - /* - * Model is not fresh, we should refresh it and test - * conditions once more - */ - state->modelage = state->maxmodelage+1; - goto lbl_28; -lbl_44: -lbl_41: - - /* - * Find value of Levenberg-Marquardt damping parameter which: - * * leads to positive definite damped model - * * within bounds specified by StpMax - * * generates step which decreases function value - * - * After this block IFlag is set to: - * * -3, if constraints are infeasible - * * -2, if model update is needed (either Lambda growth is too large - * or step is too short, but we can't rely on model and stop iterations) - * * -1, if model is fresh, Lambda have grown too large, termination is needed - * * 0, if everything is OK, continue iterations - * - * State.Nu can have any value on enter, but after exit it is set to 1.0 - */ - iflag = -99; -lbl_47: - if( ae_false ) - { - goto lbl_48; - } - - /* - * Do we need model update? - */ - if( state->modelage>0&&ae_fp_greater_eq(state->nu,minlm_suspiciousnu) ) - { - iflag = -2; - goto lbl_48; - } - - /* - * Setup quadratic solver and solve quadratic programming problem. - * After problem is solved we'll try to bound step by StpMax - * (Lambda will be increased if step size is too large). - * - * We use BFlag variable to indicate that we have to increase Lambda. - * If it is False, we will try to increase Lambda and move to new iteration. - */ - bflag = ae_true; - minqpsetstartingpointfast(&state->qpstate, &state->xbase, _state); - minqpsetoriginfast(&state->qpstate, &state->xbase, _state); - minqpsetlineartermfast(&state->qpstate, &state->gbase, _state); - minqpsetquadratictermfast(&state->qpstate, &state->quadraticmodel, ae_true, 0.0, _state); - for(i=0; i<=n-1; i++) - { - state->tmp0.ptr.p_double[i] = state->quadraticmodel.ptr.pp_double[i][i]+state->lambdav/ae_sqr(state->s.ptr.p_double[i], _state); - } - minqprewritediagonal(&state->qpstate, &state->tmp0, _state); - minqpoptimize(&state->qpstate, _state); - minqpresultsbuf(&state->qpstate, &state->xdir, &state->qprep, _state); - if( state->qprep.terminationtype>0 ) - { - - /* - * successful solution of QP problem - */ - ae_v_sub(&state->xdir.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = ae_v_dotproduct(&state->xdir.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_isfinite(v, _state) ) - { - v = ae_sqrt(v, _state); - if( ae_fp_greater(state->stpmax,0)&&ae_fp_greater(v,state->stpmax) ) - { - bflag = ae_false; - } - } - else - { - bflag = ae_false; - } - } - else - { - - /* - * Either problem is non-convex (increase LambdaV) or constraints are inconsistent - */ - ae_assert(state->qprep.terminationtype==-3||state->qprep.terminationtype==-5, "MinLM: unexpected completion code from QP solver", _state); - if( state->qprep.terminationtype==-3 ) - { - iflag = -3; - goto lbl_48; - } - bflag = ae_false; - } - if( !bflag ) - { - - /* - * Solution failed: - * try to increase lambda to make matrix positive definite and continue. - */ - if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) ) - { - iflag = -1; - goto lbl_48; - } - goto lbl_47; - } - - /* - * Step in State.XDir and it is bounded by StpMax. - * - * We should check stopping conditions on step size here. - * DeltaX, which is used for secant updates, is initialized here. - * - * This code is a bit tricky because sometimes XDir<>0, but - * it is so small that XDir+XBase==XBase (in finite precision - * arithmetics). So we set DeltaX to XBase, then - * add XDir, and then subtract XBase to get exact value of - * DeltaX. - * - * Step length is estimated using DeltaX. - * - * NOTE: stopping conditions are tested - * for fresh models only (ModelAge=0) - */ - ae_v_move(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->deltax.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_sub(&state->deltax.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->deltaxready = ae_true; - v = 0.0; - for(i=0; i<=n-1; i++) - { - v = v+ae_sqr(state->deltax.ptr.p_double[i]/state->s.ptr.p_double[i], _state); - } - v = ae_sqrt(v, _state); - if( ae_fp_greater(v,state->epsx) ) - { - goto lbl_49; - } - if( state->modelage!=0 ) - { - goto lbl_51; - } - - /* - * Step is too short, model is fresh and we can rely on it. - * Terminating. - */ - state->repterminationtype = 2; - if( !state->xrep ) - { - goto lbl_53; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - state->xupdated = ae_false; -lbl_53: - result = ae_false; - return result; - goto lbl_52; -lbl_51: - - /* - * Step is suspiciously short, but model is not fresh - * and we can't rely on it. - */ - iflag = -2; - goto lbl_48; -lbl_52: -lbl_49: - - /* - * Let's evaluate new step: - * a) if we have Fi vector, we evaluate it using rcomm, and - * then we manually calculate State.F as sum of squares of Fi[] - * b) if we have F value, we just evaluate it through rcomm interface - * - * We prefer (a) because we may need Fi vector for additional - * iterations - */ - ae_assert(state->hasfi||state->hasf, "MinLM: internal error 2!", _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_add(&state->x.ptr.p_double[0], 1, &state->xdir.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - if( !state->hasfi ) - { - goto lbl_55; - } - state->needfi = ae_true; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->needfi = ae_false; - v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->f = v; - ae_v_move(&state->deltaf.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); - ae_v_sub(&state->deltaf.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); - state->deltafready = ae_true; - goto lbl_56; -lbl_55: - state->needf = ae_true; - state->rstate.stage = 14; - goto lbl_rcomm; -lbl_14: - state->needf = ae_false; -lbl_56: - state->repnfunc = state->repnfunc+1; - if( ae_fp_greater_eq(state->f,state->fbase) ) - { - - /* - * Increase lambda and continue - */ - if( !minlm_increaselambda(&state->lambdav, &state->nu, _state) ) - { - iflag = -1; - goto lbl_48; - } - goto lbl_47; - } - - /* - * We've found our step! - */ - iflag = 0; - goto lbl_48; - goto lbl_47; -lbl_48: - state->nu = 1; - ae_assert(iflag>=-3&&iflag<=0, "MinLM: internal integrity check failed!", _state); - if( iflag==-3 ) - { - state->repterminationtype = -3; - result = ae_false; - return result; - } - if( iflag==-2 ) - { - state->modelage = state->maxmodelage+1; - goto lbl_28; - } - if( iflag==-1 ) - { - goto lbl_29; - } - - /* - * Levenberg-Marquardt step is ready. - * Compare predicted vs. actual decrease and decide what to do with lambda. - * - * NOTE: we expect that State.DeltaX contains direction of step, - * State.F contains function value at new point. - */ - ae_assert(state->deltaxready, "MinLM: deltaX is not ready", _state); - t = 0; - for(i=0; i<=n-1; i++) - { - v = ae_v_dotproduct(&state->quadraticmodel.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - t = t+state->deltax.ptr.p_double[i]*state->gbase.ptr.p_double[i]+0.5*state->deltax.ptr.p_double[i]*v; - } - state->predicteddecrease = -t; - state->actualdecrease = -(state->f-state->fbase); - if( ae_fp_less_eq(state->predicteddecrease,0) ) - { - goto lbl_29; - } - v = state->actualdecrease/state->predicteddecrease; - if( ae_fp_greater_eq(v,0.1) ) - { - goto lbl_57; - } - if( minlm_increaselambda(&state->lambdav, &state->nu, _state) ) - { - goto lbl_59; - } - - /* - * Lambda is too large, we have to break iterations. - */ - state->repterminationtype = 7; - if( !state->xrep ) - { - goto lbl_61; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 15; - goto lbl_rcomm; -lbl_15: - state->xupdated = ae_false; -lbl_61: - result = ae_false; - return result; -lbl_59: -lbl_57: - if( ae_fp_greater(v,0.5) ) - { - minlm_decreaselambda(&state->lambdav, &state->nu, _state); - } - - /* - * Accept step, report it and - * test stopping conditions on iterations count and function decrease. - * - * NOTE: we expect that State.DeltaX contains direction of step, - * State.F contains function value at new point. - * - * NOTE2: we should update XBase ONLY. In the beginning of the next - * iteration we expect that State.FIBase is NOT updated and - * contains old value of a function vector. - */ - ae_v_add(&state->xbase.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( !state->xrep ) - { - goto lbl_63; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 16; - goto lbl_rcomm; -lbl_16: - state->xupdated = ae_false; -lbl_63: - state->repiterationscount = state->repiterationscount+1; - if( state->repiterationscount>=state->maxits&&state->maxits>0 ) - { - state->repterminationtype = 5; - } - if( state->modelage==0 ) - { - if( ae_fp_less_eq(ae_fabs(state->f-state->fbase, _state),state->epsf*ae_maxreal(1, ae_maxreal(ae_fabs(state->f, _state), ae_fabs(state->fbase, _state), _state), _state)) ) - { - state->repterminationtype = 1; - } - } - if( state->repterminationtype<=0 ) - { - goto lbl_65; - } - if( !state->xrep ) - { - goto lbl_67; - } - - /* - * Report: XBase contains new point, F contains function value at new point - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 17; - goto lbl_rcomm; -lbl_17: - state->xupdated = ae_false; -lbl_67: - result = ae_false; - return result; -lbl_65: - state->modelage = state->modelage+1; - goto lbl_28; -lbl_29: - - /* - * Lambda is too large, we have to break iterations. - */ - state->repterminationtype = 7; - if( !state->xrep ) - { - goto lbl_69; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - minlm_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 18; - goto lbl_rcomm; -lbl_18: - state->xupdated = ae_false; -lbl_69: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = iflag; - state->rstate.ia.ptr.p_int[3] = i; - state->rstate.ia.ptr.p_int[4] = k; - state->rstate.ba.ptr.p_bool[0] = bflag; - state->rstate.ra.ptr.p_double[0] = v; - state->rstate.ra.ptr.p_double[1] = s; - state->rstate.ra.ptr.p_double[2] = t; - return result; -} - - -/************************************************************************* -Levenberg-Marquardt algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report; - see comments for this structure for more info. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresults(minlmstate* state, - /* Real */ ae_vector* x, - minlmreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _minlmreport_clear(rep); - - minlmresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -Levenberg-Marquardt algorithm results - -Buffered implementation of MinLMResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresultsbuf(minlmstate* state, - /* Real */ ae_vector* x, - minlmreport* rep, - ae_state *_state) -{ - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->terminationtype = state->repterminationtype; - rep->funcidx = state->repfuncidx; - rep->varidx = state->repvaridx; - rep->nfunc = state->repnfunc; - rep->njac = state->repnjac; - rep->ngrad = state->repngrad; - rep->nhess = state->repnhess; - rep->ncholesky = state->repncholesky; -} - - -/************************************************************************* -This subroutine restarts LM algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinLMCreateXXX call. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmrestartfrom(minlmstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - - - ae_assert(x->cnt>=state->n, "MinLMRestartFrom: Length(X)n, _state), "MinLMRestartFrom: X contains infinite or NaN values!", _state); - ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_vector_set_length(&state->rstate.ia, 4+1, _state); - ae_vector_set_length(&state->rstate.ba, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; - minlm_clearrequestfields(state, _state); -} - - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevgj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - minlmcreatevj(n, m, x, state, _state); -} - - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - minlmcreatefj(n, m, x, state, _state); -} - - -/************************************************************************* -This function is considered obsolete since ALGLIB 3.1.0 and is present for -backward compatibility only. We recommend to use MinLMCreateVJ, which -provides similar, but more consistent and feature-rich interface. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state) -{ - - _minlmstate_clear(state); - - ae_assert(n>=1, "MinLMCreateFJ: N<1!", _state); - ae_assert(m>=1, "MinLMCreateFJ: M<1!", _state); - ae_assert(x->cnt>=n, "MinLMCreateFJ: Length(X)teststep = 0; - state->n = n; - state->m = m; - state->algomode = 1; - state->hasf = ae_true; - state->hasfi = ae_false; - state->hasg = ae_false; - - /* - * init 2 - */ - minlm_lmprepare(n, m, ae_true, state, _state); - minlmsetacctype(state, 0, _state); - minlmsetcond(state, 0, 0, 0, 0, _state); - minlmsetxrep(state, ae_false, _state); - minlmsetstpmax(state, 0, _state); - minlmrestartfrom(state, x, _state); -} - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLMOptimize() is called -* prior to actual optimization, for each function Fi and each component - of parameters being optimized X[j] algorithm performs following steps: - * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], - where X[j] is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * Fi(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative, - Rep.FuncIdx is set to index of the function. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) Jacobian evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided - by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLMSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minlmsetgradientcheck(minlmstate* state, - double teststep, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(teststep, _state), "MinLMSetGradientCheck: TestStep contains NaN or Infinite", _state); - ae_assert(ae_fp_greater_eq(teststep,0), "MinLMSetGradientCheck: invalid argument TestStep(TestStep<0)", _state); - state->teststep = teststep; -} - - -/************************************************************************* -Prepare internal structures (except for RComm). - -Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode. -*************************************************************************/ -static void minlm_lmprepare(ae_int_t n, - ae_int_t m, - ae_bool havegrad, - minlmstate* state, - ae_state *_state) -{ - ae_int_t i; - - - if( n<=0||m<0 ) - { - return; - } - if( havegrad ) - { - ae_vector_set_length(&state->g, n, _state); - } - if( m!=0 ) - { - ae_matrix_set_length(&state->j, m, n, _state); - ae_vector_set_length(&state->fi, m, _state); - ae_vector_set_length(&state->fibase, m, _state); - ae_vector_set_length(&state->deltaf, m, _state); - ae_vector_set_length(&state->fm1, m, _state); - ae_vector_set_length(&state->fp1, m, _state); - ae_vector_set_length(&state->fc1, m, _state); - ae_vector_set_length(&state->gm1, m, _state); - ae_vector_set_length(&state->gp1, m, _state); - ae_vector_set_length(&state->gc1, m, _state); - } - else - { - ae_matrix_set_length(&state->h, n, n, _state); - } - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->deltax, n, _state); - ae_matrix_set_length(&state->quadraticmodel, n, n, _state); - ae_vector_set_length(&state->xbase, n, _state); - ae_vector_set_length(&state->gbase, n, _state); - ae_vector_set_length(&state->xdir, n, _state); - ae_vector_set_length(&state->tmp0, n, _state); - - /* - * prepare internal L-BFGS - */ - for(i=0; i<=n-1; i++) - { - state->x.ptr.p_double[i] = 0; - } - minlbfgscreate(n, ae_minint(minlm_additers, n, _state), &state->x, &state->internalstate, _state); - minlbfgssetcond(&state->internalstate, 0.0, 0.0, 0.0, ae_minint(minlm_additers, n, _state), _state); - - /* - * Prepare internal QP solver - */ - minqpcreate(n, &state->qpstate, _state); - minqpsetalgocholesky(&state->qpstate, _state); - - /* - * Prepare boundary constraints - */ - ae_vector_set_length(&state->bndl, n, _state); - ae_vector_set_length(&state->bndu, n, _state); - ae_vector_set_length(&state->havebndl, n, _state); - ae_vector_set_length(&state->havebndu, n, _state); - for(i=0; i<=n-1; i++) - { - state->bndl.ptr.p_double[i] = _state->v_neginf; - state->havebndl.ptr.p_bool[i] = ae_false; - state->bndu.ptr.p_double[i] = _state->v_posinf; - state->havebndu.ptr.p_bool[i] = ae_false; - } - - /* - * Prepare scaling matrix - */ - ae_vector_set_length(&state->s, n, _state); - for(i=0; i<=n-1; i++) - { - state->s.ptr.p_double[i] = 1.0; - } -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void minlm_clearrequestfields(minlmstate* state, ae_state *_state) -{ - - - state->needf = ae_false; - state->needfg = ae_false; - state->needfgh = ae_false; - state->needfij = ae_false; - state->needfi = ae_false; - state->xupdated = ae_false; -} - - -/************************************************************************* -Increases lambda, returns False when there is a danger of overflow -*************************************************************************/ -static ae_bool minlm_increaselambda(double* lambdav, - double* nu, - ae_state *_state) -{ - double lnlambda; - double lnnu; - double lnlambdaup; - double lnmax; - ae_bool result; - - - result = ae_false; - lnlambda = ae_log(*lambdav, _state); - lnlambdaup = ae_log(minlm_lambdaup, _state); - lnnu = ae_log(*nu, _state); - lnmax = ae_log(ae_maxrealnumber, _state); - if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,0.25*lnmax) ) - { - return result; - } - if( ae_fp_greater(lnnu+ae_log(2, _state),lnmax) ) - { - return result; - } - *lambdav = *lambdav*minlm_lambdaup*(*nu); - *nu = *nu*2; - result = ae_true; - return result; -} - - -/************************************************************************* -Decreases lambda, but leaves it unchanged when there is danger of underflow. -*************************************************************************/ -static void minlm_decreaselambda(double* lambdav, - double* nu, - ae_state *_state) -{ - - - *nu = 1; - if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(minlm_lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) - { - *lambdav = ae_minrealnumber; - } - else - { - *lambdav = *lambdav*minlm_lambdadown; - } -} - - -/************************************************************************* -Returns norm of bounded scaled anti-gradient. - -Bounded antigradient is a vector obtained from anti-gradient by zeroing -components which point outwards: - result = norm(v) - v[i]=0 if ((-g[i]<0)and(x[i]=bndl[i])) or - ((-g[i]>0)and(x[i]=bndu[i])) - v[i]=-g[i]*s[i] otherwise, where s[i] is a scale for I-th variable - -This function may be used to check a stopping criterion. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -static double minlm_boundedscaledantigradnorm(minlmstate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* g, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double v; - double result; - - - result = 0; - n = state->n; - for(i=0; i<=n-1; i++) - { - v = -g->ptr.p_double[i]*state->s.ptr.p_double[i]; - if( state->havebndl.ptr.p_bool[i] ) - { - if( ae_fp_less_eq(x->ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-g->ptr.p_double[i],0) ) - { - v = 0; - } - } - if( state->havebndu.ptr.p_bool[i] ) - { - if( ae_fp_greater_eq(x->ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-g->ptr.p_double[i],0) ) - { - v = 0; - } - } - result = result+ae_sqr(v, _state); - } - result = ae_sqrt(result, _state); - return result; -} - - -ae_bool _minlmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minlmstate *p = (minlmstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fibase, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gbase, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->quadraticmodel, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xdir, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->deltaf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fc1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gm1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gp1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gc1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsstate_init(&p->internalstate, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsreport_init(&p->internalrep, _state, make_automatic) ) - return ae_false; - if( !_minqpstate_init(&p->qpstate, _state, make_automatic) ) - return ae_false; - if( !_minqpreport_init(&p->qprep, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _minlmstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minlmstate *dst = (minlmstate*)_dst; - minlmstate *src = (minlmstate*)_src; - dst->n = src->n; - dst->m = src->m; - dst->diffstep = src->diffstep; - dst->epsg = src->epsg; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->stpmax = src->stpmax; - dst->maxmodelage = src->maxmodelage; - dst->makeadditers = src->makeadditers; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - dst->needf = src->needf; - dst->needfg = src->needfg; - dst->needfgh = src->needfgh; - dst->needfij = src->needfij; - dst->needfi = src->needfi; - dst->xupdated = src->xupdated; - dst->algomode = src->algomode; - dst->hasf = src->hasf; - dst->hasfi = src->hasfi; - dst->hasg = src->hasg; - if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) ) - return ae_false; - dst->fbase = src->fbase; - if( !ae_vector_init_copy(&dst->fibase, &src->fibase, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gbase, &src->gbase, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->quadraticmodel, &src->quadraticmodel, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic) ) - return ae_false; - dst->lambdav = src->lambdav; - dst->nu = src->nu; - dst->modelage = src->modelage; - if( !ae_vector_init_copy(&dst->xdir, &src->xdir, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->deltaf, &src->deltaf, _state, make_automatic) ) - return ae_false; - dst->deltaxready = src->deltaxready; - dst->deltafready = src->deltafready; - dst->teststep = src->teststep; - dst->repiterationscount = src->repiterationscount; - dst->repterminationtype = src->repterminationtype; - dst->repfuncidx = src->repfuncidx; - dst->repvaridx = src->repvaridx; - dst->repnfunc = src->repnfunc; - dst->repnjac = src->repnjac; - dst->repngrad = src->repngrad; - dst->repnhess = src->repnhess; - dst->repncholesky = src->repncholesky; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic) ) - return ae_false; - dst->actualdecrease = src->actualdecrease; - dst->predicteddecrease = src->predicteddecrease; - dst->xm1 = src->xm1; - dst->xp1 = src->xp1; - if( !ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->fc1, &src->fc1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gm1, &src->gm1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gp1, &src->gp1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gc1, &src->gc1, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic) ) - return ae_false; - if( !_minlbfgsreport_init_copy(&dst->internalrep, &src->internalrep, _state, make_automatic) ) - return ae_false; - if( !_minqpstate_init_copy(&dst->qpstate, &src->qpstate, _state, make_automatic) ) - return ae_false; - if( !_minqpreport_init_copy(&dst->qprep, &src->qprep, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _minlmstate_clear(void* _p) -{ - minlmstate *p = (minlmstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->fi); - ae_matrix_clear(&p->j); - ae_matrix_clear(&p->h); - ae_vector_clear(&p->g); - ae_vector_clear(&p->xbase); - ae_vector_clear(&p->fibase); - ae_vector_clear(&p->gbase); - ae_matrix_clear(&p->quadraticmodel); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_vector_clear(&p->havebndl); - ae_vector_clear(&p->havebndu); - ae_vector_clear(&p->s); - ae_vector_clear(&p->xdir); - ae_vector_clear(&p->deltax); - ae_vector_clear(&p->deltaf); - _rcommstate_clear(&p->rstate); - ae_vector_clear(&p->choleskybuf); - ae_vector_clear(&p->tmp0); - ae_vector_clear(&p->fm1); - ae_vector_clear(&p->fp1); - ae_vector_clear(&p->fc1); - ae_vector_clear(&p->gm1); - ae_vector_clear(&p->gp1); - ae_vector_clear(&p->gc1); - _minlbfgsstate_clear(&p->internalstate); - _minlbfgsreport_clear(&p->internalrep); - _minqpstate_clear(&p->qpstate); - _minqpreport_clear(&p->qprep); -} - - -void _minlmstate_destroy(void* _p) -{ - minlmstate *p = (minlmstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->fi); - ae_matrix_destroy(&p->j); - ae_matrix_destroy(&p->h); - ae_vector_destroy(&p->g); - ae_vector_destroy(&p->xbase); - ae_vector_destroy(&p->fibase); - ae_vector_destroy(&p->gbase); - ae_matrix_destroy(&p->quadraticmodel); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_vector_destroy(&p->havebndl); - ae_vector_destroy(&p->havebndu); - ae_vector_destroy(&p->s); - ae_vector_destroy(&p->xdir); - ae_vector_destroy(&p->deltax); - ae_vector_destroy(&p->deltaf); - _rcommstate_destroy(&p->rstate); - ae_vector_destroy(&p->choleskybuf); - ae_vector_destroy(&p->tmp0); - ae_vector_destroy(&p->fm1); - ae_vector_destroy(&p->fp1); - ae_vector_destroy(&p->fc1); - ae_vector_destroy(&p->gm1); - ae_vector_destroy(&p->gp1); - ae_vector_destroy(&p->gc1); - _minlbfgsstate_destroy(&p->internalstate); - _minlbfgsreport_destroy(&p->internalrep); - _minqpstate_destroy(&p->qpstate); - _minqpreport_destroy(&p->qprep); -} - - -ae_bool _minlmreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minlmreport *p = (minlmreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _minlmreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minlmreport *dst = (minlmreport*)_dst; - minlmreport *src = (minlmreport*)_src; - dst->iterationscount = src->iterationscount; - dst->terminationtype = src->terminationtype; - dst->funcidx = src->funcidx; - dst->varidx = src->varidx; - dst->nfunc = src->nfunc; - dst->njac = src->njac; - dst->ngrad = src->ngrad; - dst->nhess = src->nhess; - dst->ncholesky = src->ncholesky; - return ae_true; -} - - -void _minlmreport_clear(void* _p) -{ - minlmreport *p = (minlmreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _minlmreport_destroy(void* _p) -{ - minlmreport *p = (minlmreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -Obsolete function, use MinLBFGSSetPrecDefault() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, - ae_state *_state) -{ - - - minlbfgssetprecdefault(state, _state); -} - - -/************************************************************************* -Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, - /* Real */ ae_matrix* p, - ae_bool isupper, - ae_state *_state) -{ - - - minlbfgssetpreccholesky(state, p, isupper, _state); -} - - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierwidth(minbleicstate* state, - double mu, - ae_state *_state) -{ - - -} - - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierdecay(minbleicstate* state, - double mudecay, - ae_state *_state) -{ - - -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void minasacreate(ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - minasastate* state, - ae_state *_state) -{ - ae_int_t i; - - _minasastate_clear(state); - - ae_assert(n>=1, "MinASA: N too small!", _state); - ae_assert(x->cnt>=n, "MinCGCreate: Length(X)cnt>=n, "MinCGCreate: Length(BndL)cnt>=n, "MinCGCreate: Length(BndU)ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: inconsistent bounds!", _state); - ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],x->ptr.p_double[i]), "MinASA: infeasible X!", _state); - ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: infeasible X!", _state); - } - - /* - * Initialize - */ - state->n = n; - minasasetcond(state, 0, 0, 0, 0, _state); - minasasetxrep(state, ae_false, _state); - minasasetstpmax(state, 0, _state); - minasasetalgorithm(state, -1, _state); - ae_vector_set_length(&state->bndl, n, _state); - ae_vector_set_length(&state->bndu, n, _state); - ae_vector_set_length(&state->ak, n, _state); - ae_vector_set_length(&state->xk, n, _state); - ae_vector_set_length(&state->dk, n, _state); - ae_vector_set_length(&state->an, n, _state); - ae_vector_set_length(&state->xn, n, _state); - ae_vector_set_length(&state->dn, n, _state); - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->d, n, _state); - ae_vector_set_length(&state->g, n, _state); - ae_vector_set_length(&state->gc, n, _state); - ae_vector_set_length(&state->work, n, _state); - ae_vector_set_length(&state->yk, n, _state); - minasarestartfrom(state, x, bndl, bndu, _state); -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetcond(minasastate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsg, _state), "MinASASetCond: EpsG is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsg,0), "MinASASetCond: negative EpsG!", _state); - ae_assert(ae_isfinite(epsf, _state), "MinASASetCond: EpsF is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "MinASASetCond: negative EpsF!", _state); - ae_assert(ae_isfinite(epsx, _state), "MinASASetCond: EpsX is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsx,0), "MinASASetCond: negative EpsX!", _state); - ae_assert(maxits>=0, "MinASASetCond: negative MaxIts!", _state); - if( ((ae_fp_eq(epsg,0)&&ae_fp_eq(epsf,0))&&ae_fp_eq(epsx,0))&&maxits==0 ) - { - epsx = 1.0E-6; - } - state->epsg = epsg; - state->epsf = epsf; - state->epsx = epsx; - state->maxits = maxits; -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetalgorithm(minasastate* state, - ae_int_t algotype, - ae_state *_state) -{ - - - ae_assert(algotype>=-1&&algotype<=1, "MinASASetAlgorithm: incorrect AlgoType!", _state); - if( algotype==-1 ) - { - algotype = 1; - } - state->cgtype = algotype; -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "MinASASetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "MinASASetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool minasaiteration(minasastate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double betak; - double v; - double vv; - ae_int_t mcinfo; - ae_bool b; - ae_bool stepfound; - ae_int_t diffcnt; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - i = state->rstate.ia.ptr.p_int[1]; - mcinfo = state->rstate.ia.ptr.p_int[2]; - diffcnt = state->rstate.ia.ptr.p_int[3]; - b = state->rstate.ba.ptr.p_bool[0]; - stepfound = state->rstate.ba.ptr.p_bool[1]; - betak = state->rstate.ra.ptr.p_double[0]; - v = state->rstate.ra.ptr.p_double[1]; - vv = state->rstate.ra.ptr.p_double[2]; - } - else - { - n = -983; - i = -989; - mcinfo = -834; - diffcnt = 900; - b = ae_true; - stepfound = ae_false; - betak = 214; - v = -338; - vv = -686; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - if( state->rstate.stage==8 ) - { - goto lbl_8; - } - if( state->rstate.stage==9 ) - { - goto lbl_9; - } - if( state->rstate.stage==10 ) - { - goto lbl_10; - } - if( state->rstate.stage==11 ) - { - goto lbl_11; - } - if( state->rstate.stage==12 ) - { - goto lbl_12; - } - if( state->rstate.stage==13 ) - { - goto lbl_13; - } - if( state->rstate.stage==14 ) - { - goto lbl_14; - } - - /* - * Routine body - */ - - /* - * Prepare - */ - n = state->n; - state->repterminationtype = 0; - state->repiterationscount = 0; - state->repnfev = 0; - state->debugrestartscount = 0; - state->cgtype = 1; - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - if( ae_fp_eq(state->xk.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xk.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->ak.ptr.p_double[i] = 0; - } - else - { - state->ak.ptr.p_double[i] = 1; - } - } - state->mu = 0.1; - state->curalgo = 0; - - /* - * Calculate F/G, initialize algorithm - */ - mincomp_clearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needfg = ae_false; - if( !state->xrep ) - { - goto lbl_15; - } - - /* - * progress report - */ - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->xupdated = ae_false; -lbl_15: - if( ae_fp_less_eq(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) - { - state->repterminationtype = 4; - result = ae_false; - return result; - } - state->repnfev = state->repnfev+1; - - /* - * Main cycle - * - * At the beginning of new iteration: - * * CurAlgo stores current algorithm selector - * * State.XK, State.F and State.G store current X/F/G - * * State.AK stores current set of active constraints - */ -lbl_17: - if( ae_false ) - { - goto lbl_18; - } - - /* - * GPA algorithm - */ - if( state->curalgo!=0 ) - { - goto lbl_19; - } - state->k = 0; - state->acount = 0; -lbl_21: - if( ae_false ) - { - goto lbl_22; - } - - /* - * Determine Dk = proj(xk - gk)-xk - */ - for(i=0; i<=n-1; i++) - { - state->d.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->xk.ptr.p_double[i]; - } - - /* - * Armijo line search. - * * exact search with alpha=1 is tried first, - * 'exact' means that we evaluate f() EXACTLY at - * bound(x-g,bndl,bndu), without intermediate floating - * point operations. - * * alpha<1 are tried if explicit search wasn't successful - * Result is placed into XN. - * - * Two types of search are needed because we can't - * just use second type with alpha=1 because in finite - * precision arithmetics (x1-x0)+x0 may differ from x1. - * So while x1 is correctly bounded (it lie EXACTLY on - * boundary, if it is active), (x1-x0)+x0 may be - * not bounded. - */ - v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->dginit = v; - state->finit = state->f; - if( !(ae_fp_less_eq(mincomp_asad1norm(state, _state),state->stpmax)||ae_fp_eq(state->stpmax,0)) ) - { - goto lbl_23; - } - - /* - * Try alpha=1 step first - */ - for(i=0; i<=n-1; i++) - { - state->x.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - mincomp_clearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->needfg = ae_false; - state->repnfev = state->repnfev+1; - stepfound = ae_fp_less_eq(state->f,state->finit+mincomp_gpaftol*state->dginit); - goto lbl_24; -lbl_23: - stepfound = ae_false; -lbl_24: - if( !stepfound ) - { - goto lbl_25; - } - - /* - * we are at the boundary(ies) - */ - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->stp = 1; - goto lbl_26; -lbl_25: - - /* - * alpha=1 is too large, try smaller values - */ - state->stp = 1; - linminnormalized(&state->d, &state->stp, n, _state); - state->dginit = state->dginit/state->stp; - state->stp = mincomp_gpadecay*state->stp; - if( ae_fp_greater(state->stpmax,0) ) - { - state->stp = ae_minreal(state->stp, state->stpmax, _state); - } -lbl_27: - if( ae_false ) - { - goto lbl_28; - } - v = state->stp; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - mincomp_clearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needfg = ae_false; - state->repnfev = state->repnfev+1; - if( ae_fp_less_eq(state->stp,mincomp_stpmin) ) - { - goto lbl_28; - } - if( ae_fp_less_eq(state->f,state->finit+state->stp*mincomp_gpaftol*state->dginit) ) - { - goto lbl_28; - } - state->stp = state->stp*mincomp_gpadecay; - goto lbl_27; -lbl_28: - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); -lbl_26: - state->repiterationscount = state->repiterationscount+1; - if( !state->xrep ) - { - goto lbl_29; - } - - /* - * progress report - */ - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->xupdated = ae_false; -lbl_29: - - /* - * Calculate new set of active constraints. - * Reset counter if active set was changed. - * Prepare for the new iteration - */ - for(i=0; i<=n-1; i++) - { - if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->an.ptr.p_double[i] = 0; - } - else - { - state->an.ptr.p_double[i] = 1; - } - } - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(state->ak.ptr.p_double[i],state->an.ptr.p_double[i]) ) - { - state->acount = -1; - break; - } - } - state->acount = state->acount+1; - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->ak.ptr.p_double[0], 1, &state->an.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * Stopping conditions - */ - if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) - { - goto lbl_31; - } - - /* - * Too many iterations - */ - state->repterminationtype = 5; - if( !state->xrep ) - { - goto lbl_33; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->xupdated = ae_false; -lbl_33: - result = ae_false; - return result; -lbl_31: - if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) - { - goto lbl_35; - } - - /* - * Gradient is small enough - */ - state->repterminationtype = 4; - if( !state->xrep ) - { - goto lbl_37; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->xupdated = ae_false; -lbl_37: - result = ae_false; - return result; -lbl_35: - v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); - if( ae_fp_greater(ae_sqrt(v, _state)*state->stp,state->epsx) ) - { - goto lbl_39; - } - - /* - * Step size is too small, no further improvement is - * possible - */ - state->repterminationtype = 2; - if( !state->xrep ) - { - goto lbl_41; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->xupdated = ae_false; -lbl_41: - result = ae_false; - return result; -lbl_39: - if( ae_fp_greater(state->finit-state->f,state->epsf*ae_maxreal(ae_fabs(state->finit, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) - { - goto lbl_43; - } - - /* - * F(k+1)-F(k) is small enough - */ - state->repterminationtype = 1; - if( !state->xrep ) - { - goto lbl_45; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 8; - goto lbl_rcomm; -lbl_8: - state->xupdated = ae_false; -lbl_45: - result = ae_false; - return result; -lbl_43: - - /* - * Decide - should we switch algorithm or not - */ - if( mincomp_asauisempty(state, _state) ) - { - if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) - { - state->curalgo = 1; - goto lbl_22; - } - else - { - state->mu = state->mu*mincomp_asarho; - } - } - else - { - if( state->acount==mincomp_n1 ) - { - if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) - { - state->curalgo = 1; - goto lbl_22; - } - } - } - - /* - * Next iteration - */ - state->k = state->k+1; - goto lbl_21; -lbl_22: -lbl_19: - - /* - * CG algorithm - */ - if( state->curalgo!=1 ) - { - goto lbl_47; - } - - /* - * first, check that there are non-active constraints. - * move to GPA algorithm, if all constraints are active - */ - b = ae_true; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(state->ak.ptr.p_double[i],0) ) - { - b = ae_false; - break; - } - } - if( b ) - { - state->curalgo = 0; - goto lbl_17; - } - - /* - * CG iterations - */ - state->fold = state->f; - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - state->dk.ptr.p_double[i] = -state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; - state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; - } -lbl_49: - if( ae_false ) - { - goto lbl_50; - } - - /* - * Store G[k] for later calculation of Y[k] - */ - for(i=0; i<=n-1; i++) - { - state->yk.ptr.p_double[i] = -state->gc.ptr.p_double[i]; - } - - /* - * Make a CG step in direction given by DK[]: - * * calculate step. Step projection into feasible set - * is used. It has several benefits: a) step may be - * found with usual line search, b) multiple constraints - * may be activated with one step, c) activated constraints - * are detected in a natural way - just compare x[i] with - * bounds - * * update active set, set B to True, if there - * were changes in the set. - */ - ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->mcstage = 0; - state->stp = 1; - linminnormalized(&state->d, &state->stp, n, _state); - if( ae_fp_neq(state->laststep,0) ) - { - state->stp = state->laststep; - } - mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); -lbl_51: - if( state->mcstage==0 ) - { - goto lbl_52; - } - - /* - * preprocess data: bound State.XN so it belongs to the - * feasible set and store it in the State.X - */ - for(i=0; i<=n-1; i++) - { - state->x.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - } - - /* - * RComm - */ - mincomp_clearrequestfields(state, _state); - state->needfg = ae_true; - state->rstate.stage = 9; - goto lbl_rcomm; -lbl_9: - state->needfg = ae_false; - - /* - * postprocess data: zero components of G corresponding to - * the active constraints - */ - for(i=0; i<=n-1; i++) - { - if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->gc.ptr.p_double[i] = 0; - } - else - { - state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]; - } - } - mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); - goto lbl_51; -lbl_52: - diffcnt = 0; - for(i=0; i<=n-1; i++) - { - - /* - * XN contains unprojected result, project it, - * save copy to X (will be used for progress reporting) - */ - state->xn.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); - - /* - * update active set - */ - if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - state->an.ptr.p_double[i] = 0; - } - else - { - state->an.ptr.p_double[i] = 1; - } - if( ae_fp_neq(state->an.ptr.p_double[i],state->ak.ptr.p_double[i]) ) - { - diffcnt = diffcnt+1; - } - state->ak.ptr.p_double[i] = state->an.ptr.p_double[i]; - } - ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->repnfev = state->repnfev+state->nfev; - state->repiterationscount = state->repiterationscount+1; - if( !state->xrep ) - { - goto lbl_53; - } - - /* - * progress report - */ - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 10; - goto lbl_rcomm; -lbl_10: - state->xupdated = ae_false; -lbl_53: - - /* - * Update info about step length - */ - v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->laststep = ae_sqrt(v, _state)*state->stp; - - /* - * Check stopping conditions. - */ - if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) - { - goto lbl_55; - } - - /* - * Gradient is small enough - */ - state->repterminationtype = 4; - if( !state->xrep ) - { - goto lbl_57; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 11; - goto lbl_rcomm; -lbl_11: - state->xupdated = ae_false; -lbl_57: - result = ae_false; - return result; -lbl_55: - if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) - { - goto lbl_59; - } - - /* - * Too many iterations - */ - state->repterminationtype = 5; - if( !state->xrep ) - { - goto lbl_61; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 12; - goto lbl_rcomm; -lbl_12: - state->xupdated = ae_false; -lbl_61: - result = ae_false; - return result; -lbl_59: - if( !(ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state))&&diffcnt==0) ) - { - goto lbl_63; - } - - /* - * These conditions (EpsF/EpsX) are explicitly or implicitly - * related to the current step size and influenced - * by changes in the active constraints. - * - * For these reasons they are checked only when we don't - * want to 'unstick' at the end of the iteration and there - * were no changes in the active set. - * - * NOTE: consition |G|>=Mu*|D1| must be exactly opposite - * to the condition used to switch back to GPA. At least - * one inequality must be strict, otherwise infinite cycle - * may occur when |G|=Mu*|D1| (we DON'T test stopping - * conditions and we DON'T switch to GPA, so we cycle - * indefinitely). - */ - if( ae_fp_greater(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) - { - goto lbl_65; - } - - /* - * F(k+1)-F(k) is small enough - */ - state->repterminationtype = 1; - if( !state->xrep ) - { - goto lbl_67; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 13; - goto lbl_rcomm; -lbl_13: - state->xupdated = ae_false; -lbl_67: - result = ae_false; - return result; -lbl_65: - if( ae_fp_greater(state->laststep,state->epsx) ) - { - goto lbl_69; - } - - /* - * X(k+1)-X(k) is small enough - */ - state->repterminationtype = 2; - if( !state->xrep ) - { - goto lbl_71; - } - mincomp_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 14; - goto lbl_rcomm; -lbl_14: - state->xupdated = ae_false; -lbl_71: - result = ae_false; - return result; -lbl_69: -lbl_63: - - /* - * Check conditions for switching - */ - if( ae_fp_less(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) - { - state->curalgo = 0; - goto lbl_50; - } - if( diffcnt>0 ) - { - if( mincomp_asauisempty(state, _state)||diffcnt>=mincomp_n2 ) - { - state->curalgo = 1; - } - else - { - state->curalgo = 0; - } - goto lbl_50; - } - - /* - * Calculate D(k+1) - * - * Line search may result in: - * * maximum feasible step being taken (already processed) - * * point satisfying Wolfe conditions - * * some kind of error (CG is restarted by assigning 0.0 to Beta) - */ - if( mcinfo==1 ) - { - - /* - * Standard Wolfe conditions are satisfied: - * * calculate Y[K] and BetaK - */ - ae_v_add(&state->yk.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->betady = v/vv; - v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->betahs = v/vv; - if( state->cgtype==0 ) - { - betak = state->betady; - } - if( state->cgtype==1 ) - { - betak = ae_maxreal(0, ae_minreal(state->betady, state->betahs, _state), _state); - } - } - else - { - - /* - * Something is wrong (may be function is too wild or too flat). - * - * We'll set BetaK=0, which will restart CG algorithm. - * We can stop later (during normal checks) if stopping conditions are met. - */ - betak = 0; - state->debugrestartscount = state->debugrestartscount+1; - } - ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); - ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); - - /* - * update other information - */ - state->fold = state->f; - state->k = state->k+1; - goto lbl_49; -lbl_50: -lbl_47: - goto lbl_17; -lbl_18: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = i; - state->rstate.ia.ptr.p_int[2] = mcinfo; - state->rstate.ia.ptr.p_int[3] = diffcnt; - state->rstate.ba.ptr.p_bool[0] = b; - state->rstate.ba.ptr.p_bool[1] = stepfound; - state->rstate.ra.ptr.p_double[0] = betak; - state->rstate.ra.ptr.p_double[1] = v; - state->rstate.ra.ptr.p_double[2] = vv; - return result; -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresults(minasastate* state, - /* Real */ ae_vector* x, - minasareport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _minasareport_clear(rep); - - minasaresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresultsbuf(minasastate* state, - /* Real */ ae_vector* x, - minasareport* rep, - ae_state *_state) -{ - ae_int_t i; - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nfev = state->repnfev; - rep->terminationtype = state->repterminationtype; - rep->activeconstraints = 0; - for(i=0; i<=state->n-1; i++) - { - if( ae_fp_eq(state->ak.ptr.p_double[i],0) ) - { - rep->activeconstraints = rep->activeconstraints+1; - } - } -} - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minasarestartfrom(minasastate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state) -{ - - - ae_assert(x->cnt>=state->n, "MinASARestartFrom: Length(X)n, _state), "MinASARestartFrom: X contains infinite or NaN values!", _state); - ae_assert(bndl->cnt>=state->n, "MinASARestartFrom: Length(BndL)n, _state), "MinASARestartFrom: BndL contains infinite or NaN values!", _state); - ae_assert(bndu->cnt>=state->n, "MinASARestartFrom: Length(BndU)n, _state), "MinASARestartFrom: BndU contains infinite or NaN values!", _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_v_move(&state->bndl.ptr.p_double[0], 1, &bndl->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_v_move(&state->bndu.ptr.p_double[0], 1, &bndu->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->laststep = 0; - ae_vector_set_length(&state->rstate.ia, 3+1, _state); - ae_vector_set_length(&state->rstate.ba, 1+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; - mincomp_clearrequestfields(state, _state); -} - - -/************************************************************************* -Returns norm of bounded anti-gradient. - -Bounded antigradient is a vector obtained from anti-gradient by zeroing -components which point outwards: - result = norm(v) - v[i]=0 if ((-g[i]<0)and(x[i]=bndl[i])) or - ((-g[i]>0)and(x[i]=bndu[i])) - v[i]=-g[i] otherwise - -This function may be used to check a stopping criterion. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -static double mincomp_asaboundedantigradnorm(minasastate* state, - ae_state *_state) -{ - ae_int_t i; - double v; - double result; - - - result = 0; - for(i=0; i<=state->n-1; i++) - { - v = -state->g.ptr.p_double[i]; - if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-state->g.ptr.p_double[i],0) ) - { - v = 0; - } - if( ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-state->g.ptr.p_double[i],0) ) - { - v = 0; - } - result = result+ae_sqr(v, _state); - } - result = ae_sqrt(result, _state); - return result; -} - - -/************************************************************************* -Returns norm of GI(x). - -GI(x) is a gradient vector whose components associated with active -constraints are zeroed. It differs from bounded anti-gradient because -components of GI(x) are zeroed independently of sign(g[i]), and -anti-gradient's components are zeroed with respect to both constraint and -sign. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -static double mincomp_asaginorm(minasastate* state, ae_state *_state) -{ - ae_int_t i; - double result; - - - result = 0; - for(i=0; i<=state->n-1; i++) - { - if( ae_fp_neq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_neq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) - { - result = result+ae_sqr(state->g.ptr.p_double[i], _state); - } - } - result = ae_sqrt(result, _state); - return result; -} - - -/************************************************************************* -Returns norm(D1(State.X)) - -For a meaning of D1 see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED -OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -static double mincomp_asad1norm(minasastate* state, ae_state *_state) -{ - ae_int_t i; - double result; - - - result = 0; - for(i=0; i<=state->n-1; i++) - { - result = result+ae_sqr(boundval(state->x.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->x.ptr.p_double[i], _state); - } - result = ae_sqrt(result, _state); - return result; -} - - -/************************************************************************* -Returns True, if U set is empty. - -* State.X is used as point, -* State.G - as gradient, -* D is calculated within function (because State.D may have different - meaning depending on current optimization algorithm) - -For a meaning of U see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED -OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -static ae_bool mincomp_asauisempty(minasastate* state, ae_state *_state) -{ - ae_int_t i; - double d; - double d2; - double d32; - ae_bool result; - - - d = mincomp_asad1norm(state, _state); - d2 = ae_sqrt(d, _state); - d32 = d*d2; - result = ae_true; - for(i=0; i<=state->n-1; i++) - { - if( ae_fp_greater_eq(ae_fabs(state->g.ptr.p_double[i], _state),d2)&&ae_fp_greater_eq(ae_minreal(state->x.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i]-state->x.ptr.p_double[i], _state),d32) ) - { - result = ae_false; - return result; - } - } - return result; -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void mincomp_clearrequestfields(minasastate* state, - ae_state *_state) -{ - - - state->needfg = ae_false; - state->xupdated = ae_false; -} - - -ae_bool _minasastate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minasastate *p = (minasastate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ak, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->an, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !_linminstate_init(&p->lstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _minasastate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minasastate *dst = (minasastate*)_dst; - minasastate *src = (minasastate*)_src; - dst->n = src->n; - dst->epsg = src->epsg; - dst->epsf = src->epsf; - dst->epsx = src->epsx; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->stpmax = src->stpmax; - dst->cgtype = src->cgtype; - dst->k = src->k; - dst->nfev = src->nfev; - dst->mcstage = src->mcstage; - if( !ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic) ) - return ae_false; - dst->curalgo = src->curalgo; - dst->acount = src->acount; - dst->mu = src->mu; - dst->finit = src->finit; - dst->dginit = src->dginit; - if( !ae_vector_init_copy(&dst->ak, &src->ak, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->an, &src->an, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - dst->fold = src->fold; - dst->stp = src->stp; - if( !ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic) ) - return ae_false; - dst->laststep = src->laststep; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic) ) - return ae_false; - dst->needfg = src->needfg; - dst->xupdated = src->xupdated; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->repiterationscount = src->repiterationscount; - dst->repnfev = src->repnfev; - dst->repterminationtype = src->repterminationtype; - dst->debugrestartscount = src->debugrestartscount; - if( !_linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic) ) - return ae_false; - dst->betahs = src->betahs; - dst->betady = src->betady; - return ae_true; -} - - -void _minasastate_clear(void* _p) -{ - minasastate *p = (minasastate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->bndl); - ae_vector_clear(&p->bndu); - ae_vector_clear(&p->ak); - ae_vector_clear(&p->xk); - ae_vector_clear(&p->dk); - ae_vector_clear(&p->an); - ae_vector_clear(&p->xn); - ae_vector_clear(&p->dn); - ae_vector_clear(&p->d); - ae_vector_clear(&p->work); - ae_vector_clear(&p->yk); - ae_vector_clear(&p->gc); - ae_vector_clear(&p->x); - ae_vector_clear(&p->g); - _rcommstate_clear(&p->rstate); - _linminstate_clear(&p->lstate); -} - - -void _minasastate_destroy(void* _p) -{ - minasastate *p = (minasastate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->bndl); - ae_vector_destroy(&p->bndu); - ae_vector_destroy(&p->ak); - ae_vector_destroy(&p->xk); - ae_vector_destroy(&p->dk); - ae_vector_destroy(&p->an); - ae_vector_destroy(&p->xn); - ae_vector_destroy(&p->dn); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->work); - ae_vector_destroy(&p->yk); - ae_vector_destroy(&p->gc); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->g); - _rcommstate_destroy(&p->rstate); - _linminstate_destroy(&p->lstate); -} - - -ae_bool _minasareport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - minasareport *p = (minasareport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _minasareport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - minasareport *dst = (minasareport*)_dst; - minasareport *src = (minasareport*)_src; - dst->iterationscount = src->iterationscount; - dst->nfev = src->nfev; - dst->terminationtype = src->terminationtype; - dst->activeconstraints = src->activeconstraints; - return ae_true; -} - - -void _minasareport_clear(void* _p) -{ - minasareport *p = (minasareport*)_p; - ae_touch_ptr((void*)p); -} - - -void _minasareport_destroy(void* _p) -{ - minasareport *p = (minasareport*)_p; - ae_touch_ptr((void*)p); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "optimization.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This structure is used to store OptGuard report, i.e. report on the +properties of the nonlinear function being optimized with ALGLIB. + +After you tell your optimizer to activate OptGuard this technology starts +to silently monitor function values and gradients/Jacobians being passed +all around during your optimization session. Depending on specific set of +checks enabled OptGuard may perform additional function evaluations (say, +about 3*N evaluations if you want to check analytic gradient for errors). + +Upon discovering that something strange happens (function values and/or +gradient components change too sharply and/or unexpectedly) OptGuard sets +one of the "suspicion flags" (without interrupting optimization session). +After optimization is done, you can examine OptGuard report. + +Following report fields can be set: +* nonc0suspected +* nonc1suspected +* badgradsuspected + + +=== WHAT CAN BE DETECTED WITH OptGuard INTEGRITY CHECKER ================= + +Following types of errors in your target function (constraints) can be +caught: +a) discontinuous functions ("non-C0" part of the report) +b) functions with discontinuous derivative ("non-C1" part of the report) +c) errors in the analytic gradient provided by user + +These types of errors result in optimizer stopping well before reaching +solution (most often - right after encountering discontinuity). + +Type A errors are usually coding errors during implementation of the +target function. Most "normal" problems involve continuous functions, and +anyway you can't reliably optimize discontinuous function. + +Type B errors are either coding errors or (in case code itself is correct) +evidence of the fact that your problem is an "incorrect" one. Most +optimizers (except for ones provided by MINNS subpackage) do not support +nonsmooth problems. + +Type C errors are coding errors which often prevent optimizer from making +even one step or result in optimizing stopping too early, as soon as +actual descent direction becomes too different from one suggested by user- +supplied gradient. + + +=== WHAT IS REPORTED ===================================================== + +Following set of report fields deals with discontinuous target functions, +ones not belonging to C0 continuity class: + +* nonc0suspected - is a flag which is set upon discovering some indication + of the discontinuity. If this flag is false, the rest of "non-C0" fields + should be ignored +* nonc0fidx - is an index of the function (0 for target function, 1 or + higher for nonlinear constraints) which is suspected of being "non-C0" +* nonc0lipshitzc - a Lipchitz constant for a function which was suspected + of being non-continuous. +* nonc0test0positive - set to indicate specific test which detected + continuity violation (test #0) + +Following set of report fields deals with discontinuous gradient/Jacobian, +i.e. with functions violating C1 continuity: + +* nonc1suspected - is a flag which is set upon discovering some indication + of the discontinuity. If this flag is false, the rest of "non-C1" fields + should be ignored +* nonc1fidx - is an index of the function (0 for target function, 1 or + higher for nonlinear constraints) which is suspected of being "non-C1" +* nonc1lipshitzc - a Lipchitz constant for a function gradient which was + suspected of being non-smooth. +* nonc1test0positive - set to indicate specific test which detected + continuity violation (test #0) +* nonc1test1positive - set to indicate specific test which detected + continuity violation (test #1) + +Following set of report fields deals with errors in the gradient: +* badgradsuspected - is a flad which is set upon discovering an error in + the analytic gradient supplied by user +* badgradfidx - index of the function with bad gradient (0 for target + function, 1 or higher for nonlinear constraints) +* badgradvidx - index of the variable +* badgradxbase - location where Jacobian is tested +* following matrices store user-supplied Jacobian and its numerical + differentiation version (which is assumed to be free from the coding + errors), both of them computed near the initial point: + * badgraduser, an array[K,N], analytic Jacobian supplied by user + * badgradnum, an array[K,N], numeric Jacobian computed by ALGLIB + Here K is a total number of nonlinear functions (target + nonlinear + constraints), N is a variable number. + The element of badgraduser[] with index [badgradfidx,badgradvidx] is + assumed to be wrong. + +More detailed error log can be obtained from optimizer by explicitly +requesting reports for tests C0.0, C1.0, C1.1. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +_optguardreport_owner::_optguardreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::optguardreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardreport)); + alglib_impl::_optguardreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardreport_owner::_optguardreport_owner(alglib_impl::optguardreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_optguardreport_owner::_optguardreport_owner(const _optguardreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::optguardreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardreport)); + alglib_impl::_optguardreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardreport_owner& _optguardreport_owner::operator=(const _optguardreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: optguardreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: optguardreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_optguardreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::optguardreport)); + alglib_impl::_optguardreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_optguardreport_owner::~_optguardreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_optguardreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::optguardreport* _optguardreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::optguardreport* _optguardreport_owner::c_ptr() const +{ + return p_struct; +} +optguardreport::optguardreport() : _optguardreport_owner() ,nonc0suspected(p_struct->nonc0suspected),nonc0test0positive(p_struct->nonc0test0positive),nonc0fidx(p_struct->nonc0fidx),nonc0lipschitzc(p_struct->nonc0lipschitzc),nonc1suspected(p_struct->nonc1suspected),nonc1test0positive(p_struct->nonc1test0positive),nonc1test1positive(p_struct->nonc1test1positive),nonc1fidx(p_struct->nonc1fidx),nonc1lipschitzc(p_struct->nonc1lipschitzc),badgradsuspected(p_struct->badgradsuspected),badgradfidx(p_struct->badgradfidx),badgradvidx(p_struct->badgradvidx),badgradxbase(&p_struct->badgradxbase),badgraduser(&p_struct->badgraduser),badgradnum(&p_struct->badgradnum) +{ +} + +optguardreport::optguardreport(alglib_impl::optguardreport *attach_to):_optguardreport_owner(attach_to) ,nonc0suspected(p_struct->nonc0suspected),nonc0test0positive(p_struct->nonc0test0positive),nonc0fidx(p_struct->nonc0fidx),nonc0lipschitzc(p_struct->nonc0lipschitzc),nonc1suspected(p_struct->nonc1suspected),nonc1test0positive(p_struct->nonc1test0positive),nonc1test1positive(p_struct->nonc1test1positive),nonc1fidx(p_struct->nonc1fidx),nonc1lipschitzc(p_struct->nonc1lipschitzc),badgradsuspected(p_struct->badgradsuspected),badgradfidx(p_struct->badgradfidx),badgradvidx(p_struct->badgradvidx),badgradxbase(&p_struct->badgradxbase),badgraduser(&p_struct->badgraduser),badgradnum(&p_struct->badgradnum) +{ +} + +optguardreport::optguardreport(const optguardreport &rhs):_optguardreport_owner(rhs) ,nonc0suspected(p_struct->nonc0suspected),nonc0test0positive(p_struct->nonc0test0positive),nonc0fidx(p_struct->nonc0fidx),nonc0lipschitzc(p_struct->nonc0lipschitzc),nonc1suspected(p_struct->nonc1suspected),nonc1test0positive(p_struct->nonc1test0positive),nonc1test1positive(p_struct->nonc1test1positive),nonc1fidx(p_struct->nonc1fidx),nonc1lipschitzc(p_struct->nonc1lipschitzc),badgradsuspected(p_struct->badgradsuspected),badgradfidx(p_struct->badgradfidx),badgradvidx(p_struct->badgradvidx),badgradxbase(&p_struct->badgradxbase),badgraduser(&p_struct->badgraduser),badgradnum(&p_struct->badgradnum) +{ +} + +optguardreport& optguardreport::operator=(const optguardreport &rhs) +{ + if( this==&rhs ) + return *this; + _optguardreport_owner::operator=(rhs); + return *this; +} + +optguardreport::~optguardreport() +{ +} + + + + +/************************************************************************* +This structure is used for detailed reporting about suspected C0 +continuity violation. + +=== WHAT IS TESTED ======================================================= + +C0 test studies function values (not gradient!) obtained during line +searches and monitors estimate of the Lipschitz constant. Sudden spikes +usually indicate that discontinuity was detected. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the function value), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #0 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and f[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +_optguardnonc0report_owner::_optguardnonc0report_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc0report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::optguardnonc0report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc0report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc0report)); + alglib_impl::_optguardnonc0report_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc0report_owner::_optguardnonc0report_owner(alglib_impl::optguardnonc0report *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_optguardnonc0report_owner::_optguardnonc0report_owner(const _optguardnonc0report_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc0report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc0report copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::optguardnonc0report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc0report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc0report)); + alglib_impl::_optguardnonc0report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc0report_owner& _optguardnonc0report_owner::operator=(const _optguardnonc0report_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: optguardnonc0report assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc0report assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: optguardnonc0report assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_optguardnonc0report_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc0report)); + alglib_impl::_optguardnonc0report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_optguardnonc0report_owner::~_optguardnonc0report_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_optguardnonc0report_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::optguardnonc0report* _optguardnonc0report_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::optguardnonc0report* _optguardnonc0report_owner::c_ptr() const +{ + return p_struct; +} +optguardnonc0report::optguardnonc0report() : _optguardnonc0report_owner() ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc0report::optguardnonc0report(alglib_impl::optguardnonc0report *attach_to):_optguardnonc0report_owner(attach_to) ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc0report::optguardnonc0report(const optguardnonc0report &rhs):_optguardnonc0report_owner(rhs) ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc0report& optguardnonc0report::operator=(const optguardnonc0report &rhs) +{ + if( this==&rhs ) + return *this; + _optguardnonc0report_owner::operator=(rhs); + return *this; +} + +optguardnonc0report::~optguardnonc0report() +{ +} + + + + +/************************************************************************* +This structure is used for detailed reporting about suspected C1 +continuity violation as flagged by C1 test #0 (OptGuard has several tests +for C1 continuity, this report is used by #0). + +=== WHAT IS TESTED ======================================================= + +C1 test #0 studies function values (not gradient!) obtained during line +searches and monitors behavior of directional derivative estimate. This +test is less powerful than test #1, but it does not depend on gradient +values and thus it is more robust against artifacts introduced by +numerical differentiation. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the directional derivative), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #0 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and f[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +_optguardnonc1test0report_owner::_optguardnonc1test0report_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc1test0report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::optguardnonc1test0report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc1test0report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test0report)); + alglib_impl::_optguardnonc1test0report_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc1test0report_owner::_optguardnonc1test0report_owner(alglib_impl::optguardnonc1test0report *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_optguardnonc1test0report_owner::_optguardnonc1test0report_owner(const _optguardnonc1test0report_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc1test0report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc1test0report copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::optguardnonc1test0report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc1test0report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test0report)); + alglib_impl::_optguardnonc1test0report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc1test0report_owner& _optguardnonc1test0report_owner::operator=(const _optguardnonc1test0report_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: optguardnonc1test0report assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc1test0report assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: optguardnonc1test0report assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_optguardnonc1test0report_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test0report)); + alglib_impl::_optguardnonc1test0report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_optguardnonc1test0report_owner::~_optguardnonc1test0report_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_optguardnonc1test0report_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::optguardnonc1test0report* _optguardnonc1test0report_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::optguardnonc1test0report* _optguardnonc1test0report_owner::c_ptr() const +{ + return p_struct; +} +optguardnonc1test0report::optguardnonc1test0report() : _optguardnonc1test0report_owner() ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test0report::optguardnonc1test0report(alglib_impl::optguardnonc1test0report *attach_to):_optguardnonc1test0report_owner(attach_to) ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test0report::optguardnonc1test0report(const optguardnonc1test0report &rhs):_optguardnonc1test0report_owner(rhs) ,positive(p_struct->positive),fidx(p_struct->fidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),f(&p_struct->f),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test0report& optguardnonc1test0report::operator=(const optguardnonc1test0report &rhs) +{ + if( this==&rhs ) + return *this; + _optguardnonc1test0report_owner::operator=(rhs); + return *this; +} + +optguardnonc1test0report::~optguardnonc1test0report() +{ +} + + + + +/************************************************************************* +This structure is used for detailed reporting about suspected C1 +continuity violation as flagged by C1 test #1 (OptGuard has several tests +for C1 continuity, this report is used by #1). + +=== WHAT IS TESTED ======================================================= + +C1 test #1 studies individual components of the gradient as recorded +during line searches. Upon discovering discontinuity in the gradient this +test records specific component which was suspected (or one with highest +indication of discontinuity if multiple components are suspected). + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the directional derivative), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #1 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and g[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +_optguardnonc1test1report_owner::_optguardnonc1test1report_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc1test1report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::optguardnonc1test1report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc1test1report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test1report)); + alglib_impl::_optguardnonc1test1report_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc1test1report_owner::_optguardnonc1test1report_owner(alglib_impl::optguardnonc1test1report *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_optguardnonc1test1report_owner::_optguardnonc1test1report_owner(const _optguardnonc1test1report_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_optguardnonc1test1report_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc1test1report copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::optguardnonc1test1report*)alglib_impl::ae_malloc(sizeof(alglib_impl::optguardnonc1test1report), &_state); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test1report)); + alglib_impl::_optguardnonc1test1report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_optguardnonc1test1report_owner& _optguardnonc1test1report_owner::operator=(const _optguardnonc1test1report_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: optguardnonc1test1report assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: optguardnonc1test1report assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: optguardnonc1test1report assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_optguardnonc1test1report_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::optguardnonc1test1report)); + alglib_impl::_optguardnonc1test1report_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_optguardnonc1test1report_owner::~_optguardnonc1test1report_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_optguardnonc1test1report_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::optguardnonc1test1report* _optguardnonc1test1report_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::optguardnonc1test1report* _optguardnonc1test1report_owner::c_ptr() const +{ + return p_struct; +} +optguardnonc1test1report::optguardnonc1test1report() : _optguardnonc1test1report_owner() ,positive(p_struct->positive),fidx(p_struct->fidx),vidx(p_struct->vidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),g(&p_struct->g),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test1report::optguardnonc1test1report(alglib_impl::optguardnonc1test1report *attach_to):_optguardnonc1test1report_owner(attach_to) ,positive(p_struct->positive),fidx(p_struct->fidx),vidx(p_struct->vidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),g(&p_struct->g),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test1report::optguardnonc1test1report(const optguardnonc1test1report &rhs):_optguardnonc1test1report_owner(rhs) ,positive(p_struct->positive),fidx(p_struct->fidx),vidx(p_struct->vidx),x0(&p_struct->x0),d(&p_struct->d),n(p_struct->n),stp(&p_struct->stp),g(&p_struct->g),cnt(p_struct->cnt),stpidxa(p_struct->stpidxa),stpidxb(p_struct->stpidxb),inneriter(p_struct->inneriter),outeriter(p_struct->outeriter) +{ +} + +optguardnonc1test1report& optguardnonc1test1report::operator=(const optguardnonc1test1report &rhs) +{ + if( this==&rhs ) + return *this; + _optguardnonc1test1report_owner::operator=(rhs); + return *this; +} + +optguardnonc1test1report::~optguardnonc1test1report() +{ +} +#endif + +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void lptestproblemserialize(const lptestproblem &obj, std::string &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + alglib_impl::ae_int_t ssize; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::lptestproblemalloc(&serializer, obj.c_ptr(), &state); + ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer); + s_out.clear(); + s_out.reserve((size_t)(ssize+1)); + alglib_impl::ae_serializer_sstart_str(&serializer, &s_out); + alglib_impl::lptestproblemserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void lptestproblemserialize(const lptestproblem &obj, std::ostream &s_out) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_alloc_start(&serializer); + alglib_impl::lptestproblemalloc(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask + alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out); + alglib_impl::lptestproblemserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void lptestproblemunserialize(const std::string &s_in, lptestproblem &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_str(&serializer, &s_in); + alglib_impl::lptestproblemunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void lptestproblemunserialize(const std::istream &s_in, lptestproblem &obj) +{ + jmp_buf _break_jump; + alglib_impl::ae_state state; + alglib_impl::ae_serializer serializer; + + alglib_impl::ae_state_init(&state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&state, &_break_jump); + alglib_impl::ae_serializer_init(&serializer); + alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in); + alglib_impl::lptestproblemunserialize(&serializer, obj.c_ptr(), &state); + alglib_impl::ae_serializer_stop(&serializer, &state); + alglib_impl::ae_serializer_clear(&serializer); + alglib_impl::ae_state_clear(&state); +} + +/************************************************************************* +Initialize test LP problem. + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemcreate(const ae_int_t n, const bool hasknowntarget, const double targetf, lptestproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lptestproblemcreate(n, hasknowntarget, targetf, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +bool lptestproblemhasknowntarget(lptestproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::lptestproblemhasknowntarget(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +double lptestproblemgettargetf(lptestproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lptestproblemgettargetf(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetn(lptestproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::lptestproblemgetn(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetm(lptestproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::lptestproblemgetm(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Set scale for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetscale(lptestproblem &p, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lptestproblemsetscale(p.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Set cost for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetcost(lptestproblem &p, const real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lptestproblemsetcost(p.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetbc(lptestproblem &p, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lptestproblemsetbc(p.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetlc2(lptestproblem &p, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lptestproblemsetlc2(p.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +Initialize QPX problem. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemcreate(const ae_int_t n, qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemcreate(n, p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns objective type: True for zero/linear/constant. + +Present version does not return False. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemisquadraticobjective(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::qpxproblemisquadraticobjective(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Get variables count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetn(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::qpxproblemgetn(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Get linear constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmlc(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::qpxproblemgetmlc(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Get quadratic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmqc(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::qpxproblemgetmqc(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Get conic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmcc(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::qpxproblemgetmcc(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +Get total constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgettotalconstraints(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::qpxproblemgettotalconstraints(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + + + +/************************************************************************* +Set initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetinitialpoint(qpxproblem &p, const real_1d_array &x0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetinitialpoint(p.c_ptr(), x0.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetinitialpoint(qpxproblem &p, real_1d_array &x0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetinitialpoint(p.c_ptr(), x0.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get initial point presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasinitialpoint(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::qpxproblemhasinitialpoint(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + + +/************************************************************************* +Set scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetscale(qpxproblem &p, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetscale(p.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetscale(qpxproblem &p, real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetscale(p.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get scale presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasscale(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::qpxproblemhasscale(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + + +/************************************************************************* +Set origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetorigin(qpxproblem &p, const real_1d_array &xorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetorigin(p.c_ptr(), xorigin.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetorigin(qpxproblem &p, real_1d_array &xorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetorigin(p.c_ptr(), xorigin.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get origin presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasorigin(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::qpxproblemhasorigin(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + + +/************************************************************************* +Set linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlinearterm(qpxproblem &p, const real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetlinearterm(p.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlinearterm(qpxproblem &p, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetlinearterm(p.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +Set quadratic term; Q can be in any sparse matrix format. + +Only one triangle (lower or upper) is referenced by this function. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetquadraticterm(qpxproblem &p, const sparsematrix &q, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetquadraticterm(p.c_ptr(), q.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get quadratic term, returns zero matrix if no quadratic term is present + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetquadraticterm(qpxproblem &p, sparsematrix &q, bool &isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetquadraticterm(p.c_ptr(), q.c_ptr(), &isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Returns False if no quadratic term was specified, or quadratic term is +numerically zero. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasquadraticterm(qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::qpxproblemhasquadraticterm(p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + + +/************************************************************************* +Set box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetbc(qpxproblem &p, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetbc(p.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetbc(qpxproblem &p, real_1d_array &bndl, real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetbc(p.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +Set linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetlc2(qpxproblem &p, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemsetlc2(p.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlc2(qpxproblem &p, sparsematrix &a, real_1d_array &al, real_1d_array &au, ae_int_t &m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetlc2(p.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), &m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + + +/************************************************************************* +Append two-sided quadratic constraint, same format as minqpaddqc2() + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemaddqc2(qpxproblem &p, const sparsematrix &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemaddqc2(p.c_ptr(), q.c_ptr(), isupper, b.c_ptr(), cl, cu, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Get IDX-th two-sided quadratic constraint, same format as minqpaddqc2(), +except for the fact that it always returns isUpper=False, even if the +original matrix was an upper triangular one. + +NOTE: this function is not optimized for big matrices. Whilst still having + O(max(N,Nonzeros)) running time, it may be somewhat slow due to + dynamic structures being used internally. + + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetqc2i(qpxproblem &p, const ae_int_t idx, sparsematrix &q, bool &isupper, real_1d_array &b, double &cl, double &cu, bool &applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::qpxproblemgetqc2i(p.c_ptr(), idx, q.c_ptr(), &isupper, b.c_ptr(), &cl, &cu, &applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +A general QP problem (a linear/quadratic target subject to a mix of box, +linear, quadratic and conic constraints). + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +_qpxproblem_owner::_qpxproblem_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_qpxproblem_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::qpxproblem*)alglib_impl::ae_malloc(sizeof(alglib_impl::qpxproblem), &_state); + memset(p_struct, 0, sizeof(alglib_impl::qpxproblem)); + alglib_impl::_qpxproblem_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_qpxproblem_owner::_qpxproblem_owner(alglib_impl::qpxproblem *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_qpxproblem_owner::_qpxproblem_owner(const _qpxproblem_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_qpxproblem_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: qpxproblem copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::qpxproblem*)alglib_impl::ae_malloc(sizeof(alglib_impl::qpxproblem), &_state); + memset(p_struct, 0, sizeof(alglib_impl::qpxproblem)); + alglib_impl::_qpxproblem_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_qpxproblem_owner& _qpxproblem_owner::operator=(const _qpxproblem_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: qpxproblem assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: qpxproblem assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: qpxproblem assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_qpxproblem_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::qpxproblem)); + alglib_impl::_qpxproblem_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_qpxproblem_owner::~_qpxproblem_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_qpxproblem_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::qpxproblem* _qpxproblem_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::qpxproblem* _qpxproblem_owner::c_ptr() const +{ + return p_struct; +} +qpxproblem::qpxproblem() : _qpxproblem_owner() +{ +} + +qpxproblem::qpxproblem(alglib_impl::qpxproblem *attach_to):_qpxproblem_owner(attach_to) +{ +} + +qpxproblem::qpxproblem(const qpxproblem &rhs):_qpxproblem_owner(rhs) +{ +} + +qpxproblem& qpxproblem::operator=(const qpxproblem &rhs) +{ + if( this==&rhs ) + return *this; + _qpxproblem_owner::operator=(rhs); + return *this; +} + +qpxproblem::~qpxproblem() +{ +} + + + + +/************************************************************************* +This is a test problem class intended for internal performance tests. +Never use it directly in your projects. +*************************************************************************/ +_lptestproblem_owner::_lptestproblem_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lptestproblem_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lptestproblem*)alglib_impl::ae_malloc(sizeof(alglib_impl::lptestproblem), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lptestproblem)); + alglib_impl::_lptestproblem_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lptestproblem_owner::_lptestproblem_owner(alglib_impl::lptestproblem *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lptestproblem_owner::_lptestproblem_owner(const _lptestproblem_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lptestproblem_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lptestproblem copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lptestproblem*)alglib_impl::ae_malloc(sizeof(alglib_impl::lptestproblem), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lptestproblem)); + alglib_impl::_lptestproblem_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lptestproblem_owner& _lptestproblem_owner::operator=(const _lptestproblem_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lptestproblem assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lptestproblem assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lptestproblem assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lptestproblem_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lptestproblem)); + alglib_impl::_lptestproblem_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lptestproblem_owner::~_lptestproblem_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lptestproblem_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lptestproblem* _lptestproblem_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lptestproblem* _lptestproblem_owner::c_ptr() const +{ + return p_struct; +} +lptestproblem::lptestproblem() : _lptestproblem_owner() +{ +} + +lptestproblem::lptestproblem(alglib_impl::lptestproblem *attach_to):_lptestproblem_owner(attach_to) +{ +} + +lptestproblem::lptestproblem(const lptestproblem &rhs):_lptestproblem_owner(rhs) +{ +} + +lptestproblem& lptestproblem::operator=(const lptestproblem &rhs) +{ + if( this==&rhs ) + return *this; + _lptestproblem_owner::operator=(rhs); + return *this; +} + +lptestproblem::~lptestproblem() +{ +} +#endif + +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using a quasi- +Newton method (LBFGS scheme) which is optimized to use a minimum amount +of memory. +The subroutine generates the approximation of an inverse Hessian matrix by +using information about the last M steps of the algorithm (instead of N). +It lessens a required amount of memory from a value of order N^2 to a +value of order 2*N*M. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinLBFGSCreate() call +2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() + and other functions +3. User calls MinLBFGSOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinLBFGSResults() to get solution +5. Optionally user may call MinLBFGSRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLBFGSRestartFrom() allows to reuse already initialized structure. + +INPUT PARAMETERS: + N - problem dimension. N>0 + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - initial solution approximation, array[0..N-1]. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. you may tune stopping conditions with MinLBFGSSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLBFGSSetStpMax() function to bound algorithm's steps. However, + L-BFGS rarely needs such a tuning. + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgscreate(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using a quasi- +Newton method (LBFGS scheme) which is optimized to use a minimum amount +of memory. +The subroutine generates the approximation of an inverse Hessian matrix by +using information about the last M steps of the algorithm (instead of N). +It lessens a required amount of memory from a value of order N^2 to a +value of order 2*N*M. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinLBFGSCreate() call +2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() + and other functions +3. User calls MinLBFGSOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinLBFGSResults() to get solution +5. Optionally user may call MinLBFGSRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLBFGSRestartFrom() allows to reuse already initialized structure. + +INPUT PARAMETERS: + N - problem dimension. N>0 + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - initial solution approximation, array[0..N-1]. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. you may tune stopping conditions with MinLBFGSSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLBFGSSetStpMax() function to bound algorithm's steps. However, + L-BFGS rarely needs such a tuning. + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgscreate(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +The subroutine is finite difference variant of MinLBFGSCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinLBFGSCreate() in order to get +more information about creation of LBFGS optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinLBFGSSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. LBFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgscreatef(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +The subroutine is finite difference variant of MinLBFGSCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinLBFGSCreate() in order to get +more information about creation of LBFGS optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinLBFGSSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. LBFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgscreatef(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for L-BFGS optimization algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLBFGSSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcond(minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetcond(state.c_ptr(), epsg, epsf, epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLBFGSOptimize(). + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetxrep(minlbfgsstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetstpmax(minlbfgsstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for LBFGS optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the LBFGS too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinLBFGSSetPrec...() +functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetscale(minlbfgsstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: default preconditioner (simple +scaling, same for all elements of X) is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdefault(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetprecdefault(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: Cholesky factorization of approximate +Hessian is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + P - triangular preconditioner, Cholesky factorization of + the approximate Hessian. array[0..N-1,0..N-1], + (if larger, only leading N elements are used). + IsUpper - whether upper or lower triangle of P is given + (other triangle is not referenced) + +After call to this function preconditioner is changed to P (P is copied +into the internal buffer). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: P should be nonsingular. Exception will be thrown otherwise. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetpreccholesky(minlbfgsstate &state, const real_2d_array &p, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetpreccholesky(state.c_ptr(), p.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdiag(minlbfgsstate &state, const real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetprecdiag(state.c_ptr(), d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() +call (before or after MinLBFGSSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecscale(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetprecscale(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlbfgsiteration(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minlbfgsoptimize(minlbfgsstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::minlbfgsstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "minlbfgs"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'minlbfgsoptimize()' (func is NULL)", &_alglib_env_state); +callbacks.func = func; + + alglib_impl::minlbfgssetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'minlbfgsoptimize()' (grad is NULL)", &_alglib_env_state); +callbacks.grad = grad; + + alglib_impl::minlbfgssetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlbfgsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidx0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlbfgssetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardgradient(minlbfgsstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardsmoothness(minlbfgsstate &state, const ae_int_t level, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlbfgsoptguardsmoothness(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t level; + + level = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minlbfgsoptguardgradient() for gradient verification +* minlbfgsoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minlbfgsoptguardnonc1test0results() +* minlbfgsoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardresults(minlbfgsstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test0results(const minlbfgsstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardnonc1test0results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test1results(minlbfgsstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsoptguardnonc1test1results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +L-BFGS algorithm results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -2 rounding errors prevent further improvement. + X contains best point found. + * -1 incorrect parameters were specified + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlbfgsrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +L-BFGS algorithm results + +Buffered implementation of MinLBFGSResults which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts LBFGS algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrestartfrom(minlbfgsstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrequesttermination(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgsrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* + +*************************************************************************/ +_minlbfgsstate_owner::_minlbfgsstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlbfgsstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsstate)); + alglib_impl::_minlbfgsstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlbfgsstate_owner::_minlbfgsstate_owner(alglib_impl::minlbfgsstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlbfgsstate_owner::_minlbfgsstate_owner(const _minlbfgsstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlbfgsstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlbfgsstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlbfgsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsstate)); + alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlbfgsstate_owner& _minlbfgsstate_owner::operator=(const _minlbfgsstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlbfgsstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlbfgsstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlbfgsstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlbfgsstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsstate)); + alglib_impl::_minlbfgsstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlbfgsstate_owner::~_minlbfgsstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlbfgsstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlbfgsstate* _minlbfgsstate_owner::c_ptr() const +{ + return p_struct; +} +minlbfgsstate::minlbfgsstate() : _minlbfgsstate_owner() +{ +} + +minlbfgsstate::minlbfgsstate(alglib_impl::minlbfgsstate *attach_to):_minlbfgsstate_owner(attach_to) +{ +} + +minlbfgsstate::minlbfgsstate(const minlbfgsstate &rhs):_minlbfgsstate_owner(rhs) +{ +} + +minlbfgsstate& minlbfgsstate::operator=(const minlbfgsstate &rhs) +{ + if( this==&rhs ) + return *this; + _minlbfgsstate_owner::operator=(rhs); + return *this; +} + +minlbfgsstate::~minlbfgsstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minlbfgsrequesttermination(). + X contains point which was "current accepted" when termination + request was submitted. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +_minlbfgsreport_owner::_minlbfgsreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlbfgsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsreport)); + alglib_impl::_minlbfgsreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlbfgsreport_owner::_minlbfgsreport_owner(alglib_impl::minlbfgsreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlbfgsreport_owner::_minlbfgsreport_owner(const _minlbfgsreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlbfgsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlbfgsreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlbfgsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlbfgsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsreport)); + alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlbfgsreport_owner& _minlbfgsreport_owner::operator=(const _minlbfgsreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlbfgsreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlbfgsreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlbfgsreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlbfgsreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlbfgsreport)); + alglib_impl::_minlbfgsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlbfgsreport_owner::~_minlbfgsreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlbfgsreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlbfgsreport* _minlbfgsreport_owner::c_ptr() const +{ + return p_struct; +} +minlbfgsreport::minlbfgsreport() : _minlbfgsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +minlbfgsreport::minlbfgsreport(alglib_impl::minlbfgsreport *attach_to):_minlbfgsreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +minlbfgsreport::minlbfgsreport(const minlbfgsreport &rhs):_minlbfgsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +minlbfgsreport& minlbfgsreport::operator=(const minlbfgsreport &rhs) +{ + if( this==&rhs ) + return *this; + _minlbfgsreport_owner::operator=(rhs); + return *this; +} + +minlbfgsreport::~minlbfgsreport() +{ +} +#endif + +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + CONSTRAINED QUADRATIC PROGRAMMING + +The subroutine creates QP optimizer. After initial creation, it contains +default optimization problem with zero quadratic and linear terms and no +constraints. + +In order to actually solve something you should: + +specify objective: +* set linear term with minqpsetlinearterm() +* set quadratic term with minqpsetquadraticterm() or + minqpsetquadratictermsparse() + +specify constraints: +* set variable bounds with minqpsetbc() or minqpsetbcall() +* specify linear constraint matrix with one of the following functions: + * modern API: + * minqpsetlc2() for sparse two-sided constraints AL <= A*x <= AU + * minqpsetlc2dense() for dense two-sided constraints AL <= A*x <= AU + * minqpsetlc2mixed() for mixed two-sided constraints AL <= A*x <= AU + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + * legacy API: + * minqpsetlc() for dense one-sided equality/inequality constraints + * minqpsetlcsparse() for sparse one-sided equality/inequality constraints + * minqpsetlcmixed() for mixed dense/sparse one-sided equality/inequality constraints +* add two-sided quadratic constraint(s) of the form CL <= b'x+0.5*x'Qx <= CU + with one of the following functions: + * minqpaddqc2() for a quadratic constraint given by a sparse + matrix structure; has O(max(N,NNZ)) memory and + running time requirements. + * minqpaddqc2dense() for a quadratic constraint given by a dense + matrix; has O(N^2) memory and running time requirements. + * minqpaddqc2list() for a sparse quadratic constraint given by + a list of non-zero entries; has O(NNZ) memory + and O(NNZ*logNNZ) running time requirements, + ideal for constraints with much less than N + nonzero elements. +* add second order cone constraints with: + * minqpaddsoccprimitive() for a primitive second order cone constraint + * minqpaddsoccorthogonal() for an axis-orthogonal second order cone constraint +* add power cone constraints with: + * minqpaddpowccprimitive() for a primitive power cone constraint + * minqpaddpowccorthogonal() for an axis-orthogonal power cone constraint + +configure and run QP solver: +* choose appropriate QP solver and set it and its stopping criteria by + means of minqpsetalgo??????() function +* call minqpoptimize() to run the solver and minqpresults() to get the + solution vector and additional information. + +Following solvers are recommended for convex and semidefinite problems +with box and linear constraints: +* QuickQP for small dense problems with box-only constraints (or no + constraints at all) +* DENSE-IPM-QP for convex or semidefinite problems with medium (up + to several thousands) variable count, dense/sparse quadratic term and + any number (up to many thousands) of dense/sparse general linear + constraints +* SPARSE-IPM-QP for convex or semidefinite problems with large (many + thousands) variable count, sparse quadratic term AND linear constraints. +* SPARSE-ECQP for convex having only linear equality constraints. This + specialized solver can be orders of magnitude faster than IPM. + +If your problem happens to be nonconvex or has nonlinear constraints, then +you can use: +* DENSE-GENIPM or SPARSE-GENIPM solver which supports convex/nonconvex + QP problems with box, linear, quadratic equality/inequality and + conic constraints. +* HYBRID-GENIPM solver which is optimized for well-conditioned problems + with large dense quadratic term/constraints or for problems with large + sparse quadratic terms having prohibitively dense Cholesky factors. The + solver uses limited-memory SR1 quadratic model to accelerate Newton step. +* QuickQP for small dense nonconvex problems with box-only constraints + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer with zero quadratic/linear terms + and no constraints + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpcreate(const ae_int_t n, minqpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpcreate(n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear term for QP solver. + +By default, linear term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + B - linear term, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlinearterm(minqpstate &state, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlinearterm(state.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets dense quadratic term for QP solver. By default, +quadratic term is zero. + +IMPORTANT: + +This solver minimizes following function: + f(x) = 0.5*x'*A*x + b'*x. +Note that quadratic term has 0.5 before it. So if you want to minimize + f(x) = x^2 + x +you should rewrite your problem as follows: + f(x) = 0.5*(2*x^2) + x +and your matrix A will be equal to [[2.0]], not to [[1.0]] + +INPUT PARAMETERS: + State - structure which stores algorithm state + A - matrix, array[N,N] + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetquadraticterm(minqpstate &state, const real_2d_array &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetquadraticterm(state.c_ptr(), a.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets sparse quadratic term for QP solver. By default, +quadratic term is zero. This function overrides previous calls to +minqpsetquadraticterm() or minqpsetquadratictermsparse(). + +NOTE: dense solvers like DENSE-AUL-QP or DENSE-IPM-QP will convert this + matrix to dense storage anyway. + +IMPORTANT: + +This solver minimizes following function: + f(x) = 0.5*x'*A*x + b'*x. +Note that quadratic term has 0.5 before it. So if you want to minimize + f(x) = x^2 + x +you should rewrite your problem as follows: + f(x) = 0.5*(2*x^2) + x +and your matrix A will be equal to [[2.0]], not to [[1.0]] + +INPUT PARAMETERS: + State - structure which stores algorithm state + A - matrix, array[N,N] + IsUpper - (optional) storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used + * if not given, both lower and upper triangles must be + filled. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetquadratictermsparse(minqpstate &state, const sparsematrix &a, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetquadratictermsparse(state.c_ptr(), a.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets starting point for QP solver. It is useful to have good +initial approximation to the solution, because it will increase speed of +convergence and identification of active constraints. + +NOTE: interior point solvers ignore initial point provided by user. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetstartingpoint(minqpstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetstartingpoint(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets origin for QP solver. By default, following QP program +is solved: + + min(0.5*x'*A*x+b'*x) + +This function allows to solve a different problem: + + min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + +Specification of non-zero origin affects function being minimized and +quadratic/conic constraints, but not box and linear constraints which are +still calculated without origin. + +INPUT PARAMETERS: + State - structure which stores algorithm state + XOrigin - origin, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetorigin(minqpstate &state, const real_1d_array &xorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetorigin(state.c_ptr(), xorigin.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and as +preconditioner. + +Scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the + function + +If you do not know how to choose scales of your variables, you can: +* read www.alglib.net/optimization/scaling.php article +* use minqpsetscaleautodiag(), which calculates scale using diagonal of + the quadratic term: S is set to 1/sqrt(diag(A)), which works well + sometimes. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetscale(minqpstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets automatic evaluation of variable scaling. + +IMPORTANT: this function works only for matrices with positive diagonal + elements! Zero or negative elements will result in -9 error + code being returned. Specify scale vector manually with + minqpsetscale() in such cases. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and as +preconditioner. + +The best way to set scaling is to manually specify variable scales. +However, sometimes you just need quick-and-dirty solution - either when +you perform fast prototyping, or when you know your problem well and you +are 100% sure that this quick solution is robust enough in your case. + +One such solution is to evaluate scale of I-th variable as 1/Sqrt(A[i,i]), +where A[i,i] is an I-th diagonal element of the quadratic term. + +Such approach works well sometimes, but you have to be careful here. + +INPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void minqpsetscaleautodiag(minqpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetscaleautodiag(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use DENSE-AUL algorithm and sets stopping +criteria for the algorithm. + +This algorithm is intended for non-convex problems with moderate (up +to several thousands) variable count and arbitrary number of constraints +which are either (a) effectively convexified under constraints or (b) have +unique solution even with nonconvex target. + +IMPORTANT: when DENSE-IPM solver is applicable, its performance is usually + much better than that of DENSE-AUL. + We recommend you to use DENSE-AUL only when other solvers can + not be used. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* convergence is theoretically proved for positive-definite (convex) QP + problems. Semidefinite and non-convex problems can be solved as long as + they are bounded from below under constraints, although without + theoretical guarantees. + +ALGORITHM OUTLINE: + +* this algorithm is an augmented Lagrangian method with dense + preconditioner (hence its name). +* it performs several outer iterations in order to refine values of the + Lagrange multipliers. Single outer iteration is a solution of some + unconstrained optimization problem: first it performs dense Cholesky + factorization of the Hessian in order to build preconditioner (adaptive + regularization is applied to enforce positive definiteness), and then + it uses L-BFGS optimizer to solve optimization problem. +* typically you need about 5-10 outer iterations to converge to solution + +ALGORITHM LIMITATIONS: + +* because dense Cholesky driver is used, this algorithm has O(N^2) memory + requirements and O(OuterIterations*N^3) minimum running time. From the + practical point of view, it limits its applicability by several + thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + constraint matrix is sparse, it may handle tens of thousands of general + linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0, stopping criteria for inner optimizer. + Inner iterations are stopped when step length (with + variable scaling being applied) is less than EpsX. + See minqpsetscale() for more information on variable + scaling. + Rho - penalty coefficient, Rho>0: + * large enough that algorithm converges with desired + precision. + * not TOO large to prevent ill-conditioning + * recommended values are 100, 1000 or 10000 + ItsCnt - number of outer iterations: + * recommended values: 10-15 (although in most cases it + converges within 5 iterations, you may need a few more + to be sure). + * ItsCnt=0 means that small number of outer iterations is + automatically chosen (10 iterations in current version). + * ItsCnt=1 means that AUL algorithm performs just as usual + penalty method. + * ItsCnt>1 means that AUL algorithm performs specified + number of outer iterations + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic step length selection + (specific step length chosen may change in the future versions of + ALGLIB, so it is better to specify step length explicitly). + + -- ALGLIB -- + Copyright 20.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseaul(minqpstate &state, const double epsx, const double rho, const ae_int_t itscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgodenseaul(state.c_ptr(), epsx, rho, itscnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use DENSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with moderate (up to several thousands) variable count +and arbitrary number of linear constraints. Quadratic and conic constraints +are supported by another solver (DENSE-GENIPM). + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: this algorithm is likely to fail on nonconvex problems, + furthermore, sometimes it fails without a notice. If you try to + run DENSE-IPM on a problem with indefinite matrix (a matrix + having at least one negative eigenvalue) then depending on the + circumstances it may either (a) stall at some arbitrary point, + or (b) throw an exception due to the failure of the Cholesky + decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseipm(minqpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgodenseipm(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use SPARSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with large variable and constraint count and sparse +quadratic term and sparse linear constraints. It was successfully used for +problems with millions of variables and constraints. Quadratic and conic +constraints are supported by another solver (SPARSE-GENIPM). + +It is possible to have some limited set of dense linear constraints - they +will be handled separately by the dense BLAS - but the more dense +constraints you have, the more time solver needs. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +IMPORTANT: this algorithm won't work for nonconvex problems. If you try to + run SPARSE-IPM on a problem with indefinite quadratic term (a + matrix having at least one negative eigenvalue) then depending + on the circumstances it may either (a) stall at some arbitrary + point, or (b) throw an exception due to the failure of the + Cholesky decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* specializes on large-scale sparse problems + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseipm(minqpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgosparseipm(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use DENSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically +constrained QP problems with moderate (up to several thousands) variables +count and arbitrary number of constraints. Use SPARSE-GENIPM if your +problem is sparse. + +The algorithm is a generalization of DENSE-IPM solver, capable of handling +more general constraints as well as nonconvexity of the target. In the +latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +ALGORITHM FEATURES: + +* supports box, linear equality/inequality and conic constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'GENIPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodensegenipm(minqpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgodensegenipm(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use SPARSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically/ +quadratically constrained QP problems with sparse quadratic term and +constraints. It can handle millions of variables and constraints, assuming +that the problem is sufficiently sparse. If your problem is small (several +thousands vars at most) and dense, consider using DENSE-GENIPM as a more +efficient alternative. + +The algorithm is a generalization of the SPARSE-IPM solver, capable of +handling more general constraints as well as nonconvexity of the target. +In the latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +ALGORITHM FEATURES: + + +* supports box, linear equality/inequality constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) +* specializes on large-scale sparse problems + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparsegenipm(minqpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgosparsegenipm(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use HYBRID-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for finding medium-accuracy solutions (say, no +more than 5 accurate digits) to large-scale convex/nonconvex box/linearly/ +conically/quadratically constrained QP problems with objective and/or +quadratic constraints being well-conditioned but having prohibitively +dense Cholesky factors. This includes both dense problems and problems +with sparse terms having too dense factorizations. + +Being well conditioned allows us to use low rank LBFGS/LSR1 approximations +to the objective (quadratic constraints) and use sparse linear algebra for +the rest of the problem, thus achieving significant speed-up on many +types of problems. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: performance of this function depends on both sparsity pattern + of the problem and on its conditioning properties. The running + time for a dense QP/QCQP problem grows with variables count as + O(N^2) while DENSE-GENIPM running time grows as O(N^3). + + On the other hand, DENSE/SPARSE-GENIPM running time shows only + moderate dependence on the condition number, while HYBRID-GENIPM + running time often explodes with condition number larger than + 10000. + + In practice, on a dense QCQP problem HYBRID algorithm starts to + singificantly outperform DENSE-GENIPM for N>=1000. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + + This solver is optimized for finding medium-accuracy + solutions, with eps being between 1E-3 and 1E-5. + + MemLen - >=0, memory length for the limited memory SR1 model. Zero + value means automatic selection of some small predefined + value which may change in future versions of ALGLIB. + Optimal value is problem-dependent, with 8...32 being a + good initial point for the experimentation. Values above + N are silently truncated down to N. + + MaxOffdiag- >=0, quadratic terms with more than MaxOffdiag offdiagonal + elements are handled via quasi-Newton approximation. Terms + with no more than MaxOffdiag elements are handled exactly, + including strictly diagonal terms that are always handled + exactly (because they have the minimum number off-diagonal + elements possible - zero). Symmetric terms appearing above + and below diagonal are counted as one term, not two. A + single quasi-Newton model is built, which approximates all + eligible quadratic terms together. + + The following values are possible: + * 0 - approximate every quadratic term having at least one + off-diagonal element with a quasi-Newton model. + * 0=N*(N-1)/2 - no quadratic term is eligible + for quasi-Newton approximation, algorithm performance is + roughly similar to that of SPARSE-GENIPM, with some + additional small overhead for quasi-Newton code checks. + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgohybridgenipm(minqpstate &state, const double eps, const ae_int_t memlen, const ae_int_t maxoffdiag, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgohybridgenipm(state.c_ptr(), eps, memlen, maxoffdiag, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells QP solver to use an ECQP algorithm. + +This algorithm is intended for sparse convex problems with only linear +equality constraints. It can handle millions of variables and constraints, +assuming that the problem is sufficiently sparse. However, it can NOT +deal with nonlinear equality constraints or inequality constraints of any +type (including box ones), nor it can deal with nonconvex problems. + +When applicable, it outperforms SPARSE-IPM by tens of times. It is a +regularized direct linear algebra solver that performs several rounds of +iterative refinement in order to improve a solution. Thus, due to its +direct nature, it does not need stopping criteria and performs much faster +than interior point methods. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities are less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseecqp(minqpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgosparseecqp(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells solver to use QuickQP algorithm: special extra-fast +algorithm for problems with box-only constrants. It may solve non-convex +problems as long as they are bounded from below under constraints. + +ALGORITHM FEATURES: +* several times faster than DENSE-IPM when running on box-only problem +* utilizes accelerated methods for activation of constraints. +* supports dense and sparse QP problems +* supports ONLY box constraints; general linear constraints are NOT + supported by this solver +* can solve all types of problems (convex, semidefinite, nonconvex) as + long as they are bounded from below under constraints. + Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". + In convex/semidefinite case global minimum is returned, in nonconvex + case - algorithm returns one of the local minimums. + +ALGORITHM OUTLINE: + +* algorithm performs two kinds of iterations: constrained CG iterations + and constrained Newton iterations +* initially it performs small number of constrained CG iterations, which + can efficiently activate/deactivate multiple constraints +* after CG phase algorithm tries to calculate Cholesky decomposition and + to perform several constrained Newton steps. If Cholesky decomposition + failed (matrix is indefinite even under constraints), we perform more + CG iterations until we converge to such set of constraints that system + matrix becomes positive definite. Constrained Newton steps greatly + increase convergence speed and precision. +* algorithm interleaves CG and Newton iterations which allows to handle + indefinite matrices (CG phase) and quickly converge after final set of + constraints is found (Newton phase). Combination of CG and Newton phases + is called "outer iteration". +* it is possible to turn off Newton phase (beneficial for semidefinite + problems - Cholesky decomposition will fail too often) + +ALGORITHM LIMITATIONS: + +* algorithm does not support general linear constraints; only box ones + are supported +* Cholesky decomposition for sparse problems is performed with Skyline + Cholesky solver, which is intended for low-profile matrices. No profile- + reducing reordering of variables is performed in this version of ALGLIB. +* problems with near-zero negative eigenvalues (or exacty zero ones) may + experience about 2-3x performance penalty. The reason is that Cholesky + decomposition can not be performed until we identify directions of zero + and negative curvature and activate corresponding boundary constraints - + but we need a lot of trial and errors because these directions are hard + to notice in the matrix spectrum. + In this case you may turn off Newton phase of algorithm. + Large negative eigenvalues are not an issue, so highly non-convex + problems can be solved very efficiently. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + EpsX - >=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinQPSetScale() + MaxOuterIts-maximum number of OUTER iterations. One outer iteration + includes some amount of CG iterations (from 5 to ~N) and + one or several (usually small amount) Newton steps. Thus, + one outer iteration has high cost, but can greatly reduce + funcation value. + Use 0 if you do not want to limit number of outer iterations. + UseNewton- use Newton phase or not: + * Newton phase improves performance of positive definite + dense problems (about 2 times improvement can be observed) + * can result in some performance penalty on semidefinite + or slightly negative definite problems - each Newton + phase will bring no improvement (Cholesky failure), but + still will require computational time. + * if you doubt, you can turn off this phase - optimizer + will retain its most of its high speed. + +IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection (presently it is small step +length, but it may change in the future versions of ALGLIB). + + -- ALGLIB -- + Copyright 22.05.2014 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgoquickqp(minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxouterits, const bool usenewton, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetalgoquickqp(state.c_ptr(), epsg, epsf, epsx, maxouterits, usenewton, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for QP solver + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minqpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbc(minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for QP solver (all variables at once, +same constraints for all variables) + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbcall(minqpstate &state, const double bndl, const double bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetbcall(state.c_ptr(), bndl, bndu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound + BndU - upper bound + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbci(minqpstate &state, const ae_int_t i, const double bndl, const double bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetbci(state.c_ptr(), i, bndl, bndu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets dense linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 19.06.2012 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc(minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets dense linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 19.06.2012 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minqpsetlc(minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minqpsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets sparse linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, sparse matrix with dimensions at + least [K,N+1]. If matrix has larger size, only leading + Kx(N+1) rectangle is used. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0 + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcsparse(minqpstate &state, const sparsematrix &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlcsparse(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets mixed linear constraints, which include a set of dense +rows, and a set of sparse rows. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + SparseC - linear constraints, sparse matrix with dimensions EXACTLY + EQUAL TO [SparseK,N+1]. Each row of C represents one + constraint, either equality or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + SparseCT- type of sparse constraints, array[K]: + * if SparseCT[i]>0, then I-th constraint is SparseC[i,*]*x >= SparseC[i,n+1] + * if SparseCT[i]=0, then I-th constraint is SparseC[i,*]*x = SparseC[i,n+1] + * if SparseCT[i]<0, then I-th constraint is SparseC[i,*]*x <= SparseC[i,n+1] + SparseK - number of sparse equality/inequality constraints, K>=0 + DenseC - dense linear constraints, array[K,N+1]. + Each row of DenseC represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of DenseC (including right part) must be finite. + DenseCT - type of constraints, array[K]: + * if DenseCT[i]>0, then I-th constraint is DenseC[i,*]*x >= DenseC[i,n+1] + * if DenseCT[i]=0, then I-th constraint is DenseC[i,*]*x = DenseC[i,n+1] + * if DenseCT[i]<0, then I-th constraint is DenseC[i,*]*x <= DenseC[i,n+1] + DenseK - number of equality/inequality constraints, DenseK>=0 + +NOTE 1: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE 2: due to backward compatibility reasons SparseC can be larger than + [SparseK,N+1]. In this case only leading [SparseK,N+1] submatrix + will be used. However, the rest of ALGLIB has more strict + requirements on the input size, so we recommend you to pass sparse + term whose size exactly matches algorithm expectations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixed(minqpstate &state, const sparsematrix &sparsec, const integer_1d_array &sparsect, const ae_int_t sparsek, const real_2d_array &densec, const integer_1d_array &densect, const ae_int_t densek, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlcmixed(state.c_ptr(), sparsec.c_ptr(), sparsect.c_ptr(), sparsek, densec.c_ptr(), densect.c_ptr(), densek, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides legacy API for specification of mixed dense/sparse +linear constraints. + +New conventions used by ALGLIB since release 3.16.0 state that set of +sparse constraints comes first, followed by set of dense ones. This +convention is essential when you talk about things like order of Lagrange +multipliers. + +However, legacy API accepted mixed constraints in reverse order. This +function is here to simplify situation with code relying on legacy API. It +simply accepts constraints in one order (old) and passes them to new API, +now in correct order. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixedlegacy(minqpstate &state, const real_2d_array &densec, const integer_1d_array &densect, const ae_int_t densek, const sparsematrix &sparsec, const integer_1d_array &sparsect, const ae_int_t sparsek, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlcmixedlegacy(state.c_ptr(), densec.c_ptr(), densect.c_ptr(), densek, sparsec.c_ptr(), sparsect.c_ptr(), sparsek, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense helps some QP solvers + (especially modern IPM method) to utilize efficient dense Level 3 + BLAS for dense parts of the problem. If your problem has both dense + and sparse constraints, you can use minqpsetlc2mixed() function, + which will result in dense algebra being applied to dense terms, and + sparse sparse linear algebra applied to sparse terms. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2dense(minqpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense helps some QP solvers + (especially modern IPM method) to utilize efficient dense Level 3 + BLAS for dense parts of the problem. If your problem has both dense + and sparse constraints, you can use minqpsetlc2mixed() function, + which will result in dense algebra being applied to dense terms, and + sparse sparse linear algebra applied to sparse terms. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minqpsetlc2dense(minqpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minqpsetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2(minqpstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc2(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2mixed(minqpstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpsetlc2mixed(state.c_ptr(), sparsea.c_ptr(), ksparse, densea.c_ptr(), kdense, al.c_ptr(), au.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +matrix of currently present dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2dense(minqpstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpaddlc2dense(state.c_ptr(), a.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2(minqpstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpaddlc2(state.c_ptr(), idxa.c_ptr(), vala.c_ptr(), nnz, al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2sparsefromdense(minqpstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpaddlc2sparsefromdense(state.c_ptr(), da.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function clears the list of quadratic constraints. Other constraints +are not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearqc(minqpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpclearqc(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear term is given by +a dense array, the quadratic term is given by a sparse array. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function has O(max(N,NNZ)) memory and time requirements because a +dense array is used to store linear term and because most sparse matrix +storage formats supported by ALGLIB need at least O(N) memory even for an +empty quadratic constraint matrix. + +Use minqpaddqc2list() if you have to add many constraints with much less +than N nonzero elements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - symmetric matrix Q in a sparse matrix storage format: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * any sparse matrix storage format present in ALGLIB is + supported + * the matrix must be exactly NxN + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2(minqpstate &state, const sparsematrix &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::minqpaddqc2(state.c_ptr(), q.c_ptr(), isupper, b.c_ptr(), cl, cu, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. Both linear and quadratic +terms are given as lists of non-zero entries. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function needs O(NNZ) memory for temporaries and O(NNZ*logNNZ) time, +where NNZ is a total number of non-zeros in both lists. For small +constraints it can be orders of magnitude faster than minqpaddqc2() with +its O(max(N,NNZ)) temporary memory or minqpaddqc2dense() with its O(N^2) +temporaries. Thus, it is recommended if you have many small constraints. + +NOTE: in the end, all quadratic constraints are stored in the same + memory-efficient compressed format. However, you have to allocate an + NxN temporary dense matrix when you pass a constraint using + minqpaddqc2dense(). Similarly, data structures used as a part of the + API provided by minqpaddqc2() have O(N) temporary memory + requirements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + QRIdx - array[QNNZ], stores row indexes of QNNZ nonzero elements + of a symmetric matrix Q + QCIdx - array[QNNZ], stores col indexes of QNNZ nonzero elements + of a symmetric matrix Q + QVals - array[QNNZ], stores values of QNNZ nonzero elements of a + symmetric matrix Q + QNNZ - number of non-zero elements in Q, QNNZ>=0 + IsUpper - whether upper or lower triangle of Q is used: + * if IsUpper=True, then only elements with QRIdx[I]<=QCIdx[I] + are used and the rest is ignored + * if IsUpper=False, then only elements with QRIdx[I]>=QCIdx[I] + are used and the rest is ignored + BIdx - array[BNNZ], indexes of BNNZ nonzero elements of a linear term + BVals - array[BNNZ], values of BNNZ nonzero elements of a linear term + BNNZ - number of nonzero elements in B, BNNZ>=0 + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2list(minqpstate &state, const integer_1d_array &qridx, const integer_1d_array &qcidx, const real_1d_array &qvals, const ae_int_t qnnz, const bool isupper, const integer_1d_array &bidx, const real_1d_array &bvals, const ae_int_t bnnz, const double cl, const double cu, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::minqpaddqc2list(state.c_ptr(), qridx.c_ptr(), qcidx.c_ptr(), qvals.c_ptr(), qnnz, isupper, bidx.c_ptr(), bvals.c_ptr(), bnnz, cl, cu, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear and quadratic terms +are given by dense arrays. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +This function trades convenience of using dense arrays for the efficiency. +Because dense NxN storage is used, merely calling this function has O(N^2) +complexity, no matter how sparse the Q is. + +Use minqpaddqc2() or minqpaddqc2list() if you have sparse Q and/or many +constraints to handle. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - array[N,N], symmetric matrix Q: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * if more than N rows/cols are present, only leading N + elements are used + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2dense(minqpstate &state, const real_2d_array &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::minqpaddqc2dense(state.c_ptr(), q.c_ptr(), isupper, b.c_ptr(), cl, cu, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function clears the list of conic constraints. Other constraints are +not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearcc(minqpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpclearcc(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends a primitive second-order conic constraint of the +form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx] + ( ) + +with 'primitive' meaning that there are no per-variable scales and that +variables under the square root have sequential indexes. More general form +of conic constraints can be specified with minqpaddsoccorthogonal(). + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB allows conic constraints to +overlap, i.e. it allows a variable to be a part of multiple conic +constraints. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Range0, + Range1 - 0<=range0<=range1<=N, variable range for the LHS; + * squared variables x[range0]...x[range1-1] are summed up + under the square root. + * range0=range1 means that the constraint is interpreted + as x[AxisIdx]>=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccprimitive(minqpstate &state, const ae_int_t range0, const ae_int_t range1, const ae_int_t axisidx, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::minqpaddsoccprimitive(state.c_ptr(), range0, range1, axisidx, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function appends an axis-orthogonal second-order conic constraint of +the form + + ( k-2 ( )^2 ) + sqrt ( SUM ( a[i]*x[idx[i]]+c[i] ) + theta^2 ) <= a[k-1]*x[idx[k-1]]+c[k-1] + ( i=0 ( ) ) + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows a[] to have zero elements at arbitrary positions (e.g., |x|<=const +can be handled just as easy as |x|<=y). Furthermore, ALGLIB allows conic +constraints to overlap, i.e. it allows a variable to be a part of multiple +conic constraints, or to appear multiple times in the same constraint. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Idx - array[K] (or larger, only leading K elements are used) + storing variable indexes. Indexes can be unsorted and/or + non-distinct. + A - array[K] (or larger, only leading K elements are used), + variable multipliers. Can contain zero values. + C - array[K] (or larger, only leading K elements are used), + variable shifts. + K - cone dimensionality, K>=1. It is possible to have K>N. + Theta - additional constant term, can be zero + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccorthogonal(minqpstate &state, const integer_1d_array &idx, const real_1d_array &a, const real_1d_array &c, const ae_int_t k, const double theta, const bool applyorigin, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::minqpaddsoccorthogonal(state.c_ptr(), idx.c_ptr(), a.c_ptr(), c.c_ptr(), k, theta, applyorigin, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This function appends a primitive power cone constraint of the form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx]^alpha + ( ) + +or, written in another form, + + ( ( ))^(1/alpha) + (sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 )) <= x[axisidx] + ( ( )) + +where + + 0=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + Alpha - power parameter, 0=0 + + 0=|theta| + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows alpha[] to sum up to any positive value less than or equal to 1 +(e.g. it is possible to formulate |x|=1. It is possible to have K>N. + Theta - additional constant term, can be zero + AlphaV - array[KPow], power coefficients: + * 00 success +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +QP results + +Buffered implementation of MinQPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Export current QP problem stored in the solver into QPXProblem instance. +This instance can be serialized into ALGLIB-specific format and +unserialized from several widely acknowledged formats. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpexport(minqpstate &state, qpxproblem &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpexport(state.c_ptr(), p.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Imports QP problem, as defined by QPXProblem instance, creating a QP solver +with objective/constraints/scales/origin set to that stored in the instance. + +INPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + +OUTPUT PARAMETERS: + State - newly created solver + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpimport(qpxproblem &p, minqpstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minqpimport(p.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinQP subpackage to work with this +object +*************************************************************************/ +_minqpstate_owner::_minqpstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minqpstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minqpstate)); + alglib_impl::_minqpstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minqpstate_owner::_minqpstate_owner(alglib_impl::minqpstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minqpstate_owner::_minqpstate_owner(const _minqpstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minqpstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minqpstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minqpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minqpstate)); + alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minqpstate_owner& _minqpstate_owner::operator=(const _minqpstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minqpstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minqpstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minqpstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minqpstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minqpstate)); + alglib_impl::_minqpstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minqpstate_owner::~_minqpstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minqpstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minqpstate* _minqpstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minqpstate* _minqpstate_owner::c_ptr() const +{ + return p_struct; +} +minqpstate::minqpstate() : _minqpstate_owner() +{ +} + +minqpstate::minqpstate(alglib_impl::minqpstate *attach_to):_minqpstate_owner(attach_to) +{ +} + +minqpstate::minqpstate(const minqpstate &rhs):_minqpstate_owner(rhs) +{ +} + +minqpstate& minqpstate::operator=(const minqpstate &rhs) +{ + if( this==&rhs ) + return *this; + _minqpstate_owner::operator=(rhs); + return *this; +} + +minqpstate::~minqpstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* InnerIterationsCount number of inner iterations +* OuterIterationsCount number of outer iterations +* NCholesky number of Cholesky decomposition +* NMV number of matrix-vector products + (only products calculated as part of iterative + process are counted) +* TerminationType completion code (see below) +* F for positive terminationtype stores quadratic + model value at the solution +* LagBC Lagrange multipliers for box constraints, + array[N] +* LagLC Lagrange multipliers for linear constraints, + array[MSparse+MDense] +* LagQC Lagrange multipliers for quadratic constraints + +=== COMPLETION CODES ===================================================== + +Completion codes: +* -9 failure of the automatic scale evaluation: one of the diagonal + elements of the quadratic term is non-positive. Specify variable + scales manually! +* -5 inappropriate solver was used: + * QuickQP solver for a problem with general linear constraints (dense/sparse) + * QuickQP/DENSE-AUL/DENSE-IPM/SPARSE-IPM for a problem with + quadratic/conic constraints + * ECQP for a problem with inequality or nonlinear equality constraints +* -4 the problem is highly likely to be unbounded; either one of the solvers + found an unconstrained direction of negative curvature, or objective + simply decreased for too much (more than 1E50). +* -3 inconsistent constraints (or, maybe, feasible point is + too hard to find). If you are sure that constraints are feasible, + try to restart optimizer with better initial approximation. +* -2 IPM solver has difficulty finding primal/dual feasible point. + It is likely that the problem is either infeasible or unbounded, + but it is difficult to determine exact reason for termination. + X contains best point found so far. +* 1..4 successful completion +* 5 MaxIts steps was taken +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +=== LAGRANGE MULTIPLIERS ================================================= + +Some optimizers report values of Lagrange multipliers on successful +completion (positive completion code): +* dense and sparse IPM/GENIPM return very precise Lagrange multipliers as + determined during solution process. +* DENSE-AUL-QP returns approximate Lagrange multipliers (which are very + close to "true" Lagrange multipliers except for overconstrained or + degenerate problems) + +Three arrays of multipliers are returned: +* LagBC is array[N] which is loaded with multipliers from box constraints; + LagBC[i]>0 means that I-th constraint is at the upper bound, LagBC[I]<0 + means that I-th constraint is at the lower bound, LagBC[I]=0 means that + I-th box constraint is inactive. +* LagLC is array[MSparse+MDense] which is loaded with multipliers from + general linear constraints (former MSparse elements corresponds to + sparse part of the constraint matrix, latter MDense are for the dense + constraints, as was specified by user). + LagLC[i]>0 means that I-th constraint at the upper bound, LagLC[i]<0 + means that I-th constraint is at the lower bound, LagLC[i]=0 means that + I-th linear constraint is inactive. +* LagQC is array[MQC] which stores multipliers for quadratic constraints. + LagQC[i]>0 means that I-th constraint at the upper bound, LagQC[i]<0 + means that I-th constraint is at the lower bound, LagQC[i]=0 means that + I-th linear constraint is inactive. + +On failure (or when optimizer does not support Lagrange multipliers) these +arrays are zero-filled. + +It is expected that at solution the dual feasibility condition holds: + + C+H*(Xs-X0) + SUM(Ei*LagBC[i],i=0..n-1) + SUM(Ai*LagLC[i],i=0..m-1) + ... ~ 0 + +where +* C is a linear term +* H is a quadratic term +* Xs is a solution, and X0 is an origin term (zero by default) +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix + +NOTE: methods from IPM family may also return meaningful Lagrange + multipliers on completion with code -2 (infeasibility or + unboundedness detected). +*************************************************************************/ +_minqpreport_owner::_minqpreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minqpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minqpreport)); + alglib_impl::_minqpreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minqpreport_owner::_minqpreport_owner(alglib_impl::minqpreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minqpreport_owner::_minqpreport_owner(const _minqpreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minqpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minqpreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minqpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minqpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minqpreport)); + alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minqpreport_owner& _minqpreport_owner::operator=(const _minqpreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minqpreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minqpreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minqpreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minqpreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minqpreport)); + alglib_impl::_minqpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minqpreport_owner::~_minqpreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minqpreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minqpreport* _minqpreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minqpreport* _minqpreport_owner::c_ptr() const +{ + return p_struct; +} +minqpreport::minqpreport() : _minqpreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype),f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),lagqc(&p_struct->lagqc) +{ +} + +minqpreport::minqpreport(alglib_impl::minqpreport *attach_to):_minqpreport_owner(attach_to) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype),f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),lagqc(&p_struct->lagqc) +{ +} + +minqpreport::minqpreport(const minqpreport &rhs):_minqpreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nmv(p_struct->nmv),ncholesky(p_struct->ncholesky),terminationtype(p_struct->terminationtype),f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),lagqc(&p_struct->lagqc) +{ +} + +minqpreport& minqpreport::operator=(const minqpreport &rhs) +{ + if( this==&rhs ) + return *this; + _minqpreport_owner::operator=(rhs); + return *this; +} + +minqpreport::~minqpreport() +{ +} +#endif + +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] and Jacobian of f[]. + + +REQUIREMENTS: +This algorithm will request following information during its operation: + +* function vector f[] at given point X +* function vector f[] and Jacobian of f[] (simultaneously) at given point + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() and jac() callbacks. +First one is used to calculate f[] at given point, second one calculates +f[] and Jacobian df[i]/dx[j]. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not provide Jacobian), but it +will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateVJ() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmcreatevj(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] and Jacobian of f[]. + + +REQUIREMENTS: +This algorithm will request following information during its operation: + +* function vector f[] at given point X +* function vector f[] and Jacobian of f[] (simultaneously) at given point + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() and jac() callbacks. +First one is used to calculate f[] at given point, second one calculates +f[] and Jacobian df[i]/dx[j]. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not provide Jacobian), but it +will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateVJ() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmcreatevj(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] only. Finite differences are used to +calculate Jacobian. + + +REQUIREMENTS: +This algorithm will request following information during its operation: +* function vector f[] at given point X + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() callback. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not accept function vector), but +it will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateV() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + DiffStep- differentiation step, >0. By default, symmetric 3-point + formula which provides good accuracy is used. It can be + changed to a faster but less precise 2-point one with + minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also MinLMIteration, MinLMResults. + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmcreatev(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] only. Finite differences are used to +calculate Jacobian. + + +REQUIREMENTS: +This algorithm will request following information during its operation: +* function vector f[] at given point X + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() callback. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not accept function vector), but +it will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateV() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + DiffStep- differentiation step, >0. By default, symmetric 3-point + formula which provides good accuracy is used. It can be + changed to a faster but less precise 2-point one with + minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also MinLMIteration, MinLMResults. + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmcreatev(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for Levenberg-Marquardt optimization +algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLMSetScale() + Recommended values: 1E-9 ... 1E-12. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + +NOTE: it is not recommended to set large EpsX (say, 0.001). Because LM is + a second-order method, it performs very precise steps anyway. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetcond(minlmstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetcond(state.c_ptr(), epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS +iterations are reported. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetxrep(minlmstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetstpmax(minlmstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for LM optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetscale(minlmstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets boundary constraints for LM optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + or at its boundary + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetbc(minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets general linear constraints for LM optimizer + +Linear constraints are inactive by default (after initial creation). They +are preserved until explicitly turned off with another minlmsetlc() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with minlmsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +IMPORTANT: solvers created with minlmcreatefgh() do not support linear + constraints. + +NOTE: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetlc(minlmstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets general linear constraints for LM optimizer + +Linear constraints are inactive by default (after initial creation). They +are preserved until explicitly turned off with another minlmsetlc() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with minlmsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +IMPORTANT: solvers created with minlmcreatefgh() do not support linear + constraints. + +NOTE: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlmsetlc(minlmstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minlmsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function is used to change acceleration settings + +You can choose between three acceleration strategies: +* AccType=0, no acceleration. +* AccType=1, secant updates are used to update quadratic model after each + iteration. After fixed number of iterations (or after model breakdown) + we recalculate quadratic model using analytic Jacobian or finite + differences. Number of secant-based iterations depends on optimization + settings: about 3 iterations - when we have analytic Jacobian, up to 2*N + iterations - when we use finite differences to calculate Jacobian. + +AccType=1 is recommended when Jacobian calculation cost is prohibitively +high (several Mx1 function vector calculations followed by several NxN +Cholesky factorizations are faster than calculation of one M*N Jacobian). +It should also be used when we have no Jacobian, because finite difference +approximation takes too much time to compute. + +Table below list optimization protocols (XYZ protocol corresponds to +MinLMCreateXYZ) and acceleration types they support (and use by default). + +ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: + +protocol 0 1 comment +V + + +VJ + + +FGH + + +DEFAULT VALUES: + +protocol 0 1 comment +V x without acceleration it is so slooooooooow +VJ x +FGH x + +NOTE: this function should be called before optimization. Attempt to call +it during algorithm iterations may result in unexpected behavior. + +NOTE: attempt to call this function with unsupported protocol/acceleration +combination will result in exception being thrown. + + -- ALGLIB -- + Copyright 14.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetacctype(minlmstate &state, const ae_int_t acctype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetacctype(state.c_ptr(), acctype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LM solver compares value at the trial point f[1] +with the value at the current point f[0]. Only steps that decrease f() are +accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnonmonotonicsteps(minlmstate &state, const ae_int_t cnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetnonmonotonicsteps(state.c_ptr(), cnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minlmcreatev() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinLMCreateV() call. + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnumdiff(minlmstate &state, const ae_int_t formulatype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmsetnumdiff(state.c_ptr(), formulatype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlmiteration(minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minlmoptimize(minlmstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::minlmstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "minlm"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minlmoptimize()' (fvec is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; + + alglib_impl::minlmsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minlmoptimize()' (fvec is NULL)", &_alglib_env_state); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'minlmoptimize()' (jac is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; +callbacks.jac = jac; + + alglib_impl::minlmsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minlmiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidx0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlmsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardgradient(minlmstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +OptGuard checks analytic Jacobian against reference value obtained by +numerical differentiation with user-specified step. + +NOTE: other optimizers perform additional OptGuard checks for things like + C0/C1-continuity violations. However, LM optimizer can check only + for incorrect Jacobian. + + The reason is that unlike line search methods LM optimizer does not + perform extensive evaluations along the line. Thus, we simply do not + have enough data to catch C0/C1-violations. + +This check is activated with minlmoptguardgradient() function. + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - OptGuard report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardresults(minlmstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Levenberg-Marquardt algorithm results + +NOTE: if you activated OptGuard integrity checking functionality and want + to get OptGuard report, it can be retrieved with the help of + minlmoptguardresults() function. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report; includes termination codes and + additional information. Termination codes are listed below, + see comments for this structure for more info. + + Termination code is stored in rep.terminationtype field: + * -8 optimizer detected NAN/INF values either in the + function itself, or in its Jacobian + * -3 constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlmrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + + rep.f contains SUM(f[i]^2) at X + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Levenberg-Marquardt algorithm results + +Buffered implementation of MinLMResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts LM algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinLMCreateXXX call. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmrestartfrom(minlmstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmrequesttermination(minlmstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlmrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +Levenberg-Marquardt optimizer. + +This structure should be created using one of the MinLMCreate???() +functions. You should not access its fields directly; use ALGLIB functions +to work with it. +*************************************************************************/ +_minlmstate_owner::_minlmstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlmstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlmstate)); + alglib_impl::_minlmstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlmstate_owner::_minlmstate_owner(alglib_impl::minlmstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlmstate_owner::_minlmstate_owner(const _minlmstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlmstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlmstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlmstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlmstate)); + alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlmstate_owner& _minlmstate_owner::operator=(const _minlmstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlmstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlmstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlmstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlmstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlmstate)); + alglib_impl::_minlmstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlmstate_owner::~_minlmstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlmstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlmstate* _minlmstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlmstate* _minlmstate_owner::c_ptr() const +{ + return p_struct; +} +minlmstate::minlmstate() : _minlmstate_owner() +{ +} + +minlmstate::minlmstate(alglib_impl::minlmstate *attach_to):_minlmstate_owner(attach_to) +{ +} + +minlmstate::minlmstate(const minlmstate &rhs):_minlmstate_owner(rhs) +{ +} + +minlmstate& minlmstate::operator=(const minlmstate &rhs) +{ + if( this==&rhs ) + return *this; + _minlmstate_owner::operator=(rhs); + return *this; +} + +minlmstate::~minlmstate() +{ +} + + + + +/************************************************************************* +Optimization report, filled by MinLMResults() function + +FIELDS: +* TerminationType, completetion code: + * -8 optimizer detected NAN/INF values either in the function itself, + or in its Jacobian + * -5 inappropriate solver was used: + * solver created with minlmcreatefgh() used on problem with + general linear constraints (set with minlmsetlc() call). + * -3 constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called MinLMRequestTermination(). + X contains point which was "current accepted" when termination + request was submitted. +* F, objective value, SUM(f[i]^2) +* IterationsCount, contains iterations count +* NFunc, number of function calculations +* NJac, number of Jacobi matrix calculations +* NGrad, number of gradient calculations +* NHess, number of Hessian calculations +* NCholesky, number of Cholesky decomposition calculations +*************************************************************************/ +_minlmreport_owner::_minlmreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlmreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlmreport)); + alglib_impl::_minlmreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlmreport_owner::_minlmreport_owner(alglib_impl::minlmreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlmreport_owner::_minlmreport_owner(const _minlmreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlmreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlmreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlmreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlmreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlmreport)); + alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlmreport_owner& _minlmreport_owner::operator=(const _minlmreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlmreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlmreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlmreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlmreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlmreport)); + alglib_impl::_minlmreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlmreport_owner::~_minlmreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlmreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlmreport* _minlmreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlmreport* _minlmreport_owner::c_ptr() const +{ + return p_struct; +} +minlmreport::minlmreport() : _minlmreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),f(p_struct->f),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +minlmreport::minlmreport(alglib_impl::minlmreport *attach_to):_minlmreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),f(p_struct->f),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +minlmreport::minlmreport(const minlmreport &rhs):_minlmreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),f(p_struct->f),nfunc(p_struct->nfunc),njac(p_struct->njac),ngrad(p_struct->ngrad),nhess(p_struct->nhess),ncholesky(p_struct->ncholesky) +{ +} + +minlmreport& minlmreport::operator=(const minlmreport &rhs) +{ + if( this==&rhs ) + return *this; + _minlmreport_owner::operator=(rhs); + return *this; +} + +minlmreport::~minlmreport() +{ +} +#endif + +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONLINEAR CONJUGATE GRADIENT METHOD + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using one of the +nonlinear conjugate gradient methods. + +These CG methods are globally convergent (even on non-convex functions) as +long as grad(f) is Lipschitz continuous in a some neighborhood of the +L = { x : f(x)<=f(x0) }. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinCGCreate() call +2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and + other functions +3. User calls MinCGOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinCGResults() to get solution +5. Optionally, user may call MinCGRestartFrom() to solve another problem + with same N but another starting point and/or another function. + MinCGRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgcreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + NONLINEAR CONJUGATE GRADIENT METHOD + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using one of the +nonlinear conjugate gradient methods. + +These CG methods are globally convergent (even on non-convex functions) as +long as grad(f) is Lipschitz continuous in a some neighborhood of the +L = { x : f(x)<=f(x0) }. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinCGCreate() call +2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and + other functions +3. User calls MinCGOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinCGResults() to get solution +5. Optionally, user may call MinCGRestartFrom() to solve another problem + with same N but another starting point and/or another function. + MinCGRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mincgcreate(const real_1d_array &x, mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgcreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +The subroutine is finite difference variant of MinCGCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinCGCreate() in order to get more +information about creation of CG optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinCGSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. L-BFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgcreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +The subroutine is finite difference variant of MinCGCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinCGCreate() in order to get more +information about creation of CG optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinCGSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. L-BFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgcreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for CG optimization algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinCGSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcond(mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetcond(state.c_ptr(), epsg, epsf, epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for CG optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of CG optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the CG too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinCGSetPrec...() functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgsetscale(mincgstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetxrep(mincgstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets CG algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + CGType - algorithm type: + * -1 automatic selection of the best algorithm + * 0 DY (Dai and Yuan) algorithm + * 1 Hybrid DY-HS algorithm + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcgtype(mincgstate &state, const ae_int_t cgtype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetcgtype(state.c_ptr(), cgtype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetstpmax(mincgstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function allows to suggest initial step length to the CG algorithm. + +Suggested step length is used as starting point for the line search. It +can be useful when you have badly scaled problem, i.e. when ||grad|| +(which is used as initial estimate for the first step) is many orders of +magnitude different from the desired step. + +Line search may fail on such problems without good estimate of initial +step length. Imagine, for example, problem with ||grad||=10^50 and desired +step equal to 0.1 Line search function will use 10^50 as initial step, +then it will decrease step length by 2 (up to 20 attempts) and will get +10^44, which is still too large. + +This function allows us to tell than line search should be started from +some moderate step length, like 1.0, so algorithm will be able to detect +desired step length in a several searches. + +Default behavior (when no step is suggested) is to use preconditioner, if +it is available, to generate initial estimate of step length. + +This function influences only first iteration of algorithm. It should be +called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. +Suggested step is ignored if you have preconditioner. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + Stp - initial estimate of the step length. + Can be zero (no estimate). + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsuggeststep(mincgstate &state, const double stp, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsuggeststep(state.c_ptr(), stp, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdefault(mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetprecdefault(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdiag(mincgstate &state, const real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetprecdiag(state.c_ptr(), d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinCGSetScale() call +(before or after MinCGSetPrecScale() call). Without knowledge of the scale +of your variables scale-based preconditioner will be just unit matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecscale(mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgsetprecscale(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mincgiteration(mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void mincgoptimize(mincgstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'mincgoptimize()' (func is NULL)", &_alglib_env_state); + alglib_impl::mincgsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needf ) + { + func(state.x, state.f, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + +void mincgoptimize(mincgstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'mincgoptimize()' (grad is NULL)", &_alglib_env_state); + alglib_impl::mincgsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::mincgiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfg ) + { + grad(state.x, state.f, state.g, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'mincgoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with mincgoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with mincgsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardgradient(mincgstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardsmoothness(mincgstate &state, const ae_int_t level, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mincgoptguardsmoothness(mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t level; + + level = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* mincgoptguardgradient() for gradient verification +* mincgoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* mincgoptguardnonc1test0results() +* mincgoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardresults(mincgstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test0results(const mincgstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardnonc1test0results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test1results(mincgstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgoptguardnonc1test1results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conjugate gradient results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -7 gradient verification failed. + See MinCGSetGradientCheck() for more information. + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible, + we return best X found so far + * 8 terminated by user + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conjugate gradient results + +Buffered implementation of MinCGResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgrestartfrom(mincgstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgrequesttermination(mincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mincgrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores state of the nonlinear CG optimizer. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_mincgstate_owner::_mincgstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mincgstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mincgstate)); + alglib_impl::_mincgstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mincgstate_owner::_mincgstate_owner(alglib_impl::mincgstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mincgstate_owner::_mincgstate_owner(const _mincgstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mincgstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mincgstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mincgstate)); + alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mincgstate_owner& _mincgstate_owner::operator=(const _mincgstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mincgstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mincgstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mincgstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mincgstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mincgstate)); + alglib_impl::_mincgstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mincgstate_owner::~_mincgstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mincgstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mincgstate* _mincgstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mincgstate* _mincgstate_owner::c_ptr() const +{ + return p_struct; +} +mincgstate::mincgstate() : _mincgstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +mincgstate::mincgstate(alglib_impl::mincgstate *attach_to):_mincgstate_owner(attach_to) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +mincgstate::mincgstate(const mincgstate &rhs):_mincgstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +mincgstate& mincgstate::operator=(const mincgstate &rhs) +{ + if( this==&rhs ) + return *this; + _mincgstate_owner::operator=(rhs); + return *this; +} + +mincgstate::~mincgstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called mincgrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +_mincgreport_owner::_mincgreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mincgreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mincgreport)); + alglib_impl::_mincgreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mincgreport_owner::_mincgreport_owner(alglib_impl::mincgreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mincgreport_owner::_mincgreport_owner(const _mincgreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mincgreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mincgreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mincgreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mincgreport)); + alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mincgreport_owner& _mincgreport_owner::operator=(const _mincgreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mincgreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mincgreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mincgreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mincgreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mincgreport)); + alglib_impl::_mincgreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mincgreport_owner::~_mincgreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mincgreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mincgreport* _mincgreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mincgreport* _mincgreport_owner::c_ptr() const +{ + return p_struct; +} +mincgreport::mincgreport() : _mincgreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mincgreport::mincgreport(alglib_impl::mincgreport *attach_to):_mincgreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mincgreport::mincgreport(const mincgreport &rhs):_mincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype) +{ +} + +mincgreport& mincgreport::operator=(const mincgreport &rhs) +{ + if( this==&rhs ) + return *this; + _mincgreport_owner::operator=(rhs); + return *this; +} + +mincgreport::~mincgreport() +{ +} +#endif + +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + GLOBAL OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR CONSTRAINTS + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear generalized inequality constraints Li<=Ci(x)<=Ui, with one of + Li/Ui possibly being infinite + +REQUIREMENTS: +* F() and C() do NOT have to be differentiable, locally Lipschitz or + continuous. Most solvers in this subpackage can deal with nonsmoothness + or minor discontinuities, although obviously smoother problems are the + most easy ones. +* generally, F() and C() must be computable at any point which is feasible + subject to box constraints + +USAGE: + +1. User initializes algorithm state with mindfcreate() call and + chooses specific solver to be used. There is some solver which is used + by default, with default settings, but you should NOT rely on the + default choice. It may change in the future releases of ALGLIB without + notice, and no one can guarantee that the new solver will be able to + solve your problem with default settings. + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) mindfsetbc() for boundary constraints + b) mindfsetlc2dense() for linear constraints + c) mindfsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with mindfsetscale() function. It is + VERY important to set variable scales because many derivative-free + algorithms refuse to work when variables are badly scaled. + Scaling helps to seed initial population, control convergence and + enforce penalties for constraint violation. + +4. Finally, user calls mindfoptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F and G. + +5. User calls mindfresults() to get a solution + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]. Some solvers can utilize a good + initial point to seed computations. + + As of ALGLIB 4.04, the initial point is: + * used by GDEMO + + If the chosen solver does not need initial point, one can + supply zeros. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + +IMPORTANT: the MINDF optimizer supports parallel model evaluation + ('callback parallelism'). This feature, which is present in + commercial ALGLIB editions, greatly accelerates algorithms like + differential evolution which usually issue batch requests to + user callbacks which can be efficiently parallelized. + + Callback parallelism is usually beneficial when the batch + evalution requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on mindfoptimize() function for more + information. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfcreate(const ae_int_t n, const real_1d_array &x, mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfcreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + GLOBAL OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR CONSTRAINTS + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear generalized inequality constraints Li<=Ci(x)<=Ui, with one of + Li/Ui possibly being infinite + +REQUIREMENTS: +* F() and C() do NOT have to be differentiable, locally Lipschitz or + continuous. Most solvers in this subpackage can deal with nonsmoothness + or minor discontinuities, although obviously smoother problems are the + most easy ones. +* generally, F() and C() must be computable at any point which is feasible + subject to box constraints + +USAGE: + +1. User initializes algorithm state with mindfcreate() call and + chooses specific solver to be used. There is some solver which is used + by default, with default settings, but you should NOT rely on the + default choice. It may change in the future releases of ALGLIB without + notice, and no one can guarantee that the new solver will be able to + solve your problem with default settings. + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) mindfsetbc() for boundary constraints + b) mindfsetlc2dense() for linear constraints + c) mindfsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with mindfsetscale() function. It is + VERY important to set variable scales because many derivative-free + algorithms refuse to work when variables are badly scaled. + Scaling helps to seed initial population, control convergence and + enforce penalties for constraint violation. + +4. Finally, user calls mindfoptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F and G. + +5. User calls mindfresults() to get a solution + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]. Some solvers can utilize a good + initial point to seed computations. + + As of ALGLIB 4.04, the initial point is: + * used by GDEMO + + If the chosen solver does not need initial point, one can + supply zeros. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + +IMPORTANT: the MINDF optimizer supports parallel model evaluation + ('callback parallelism'). This feature, which is present in + commercial ALGLIB editions, greatly accelerates algorithms like + differential evolution which usually issue batch requests to + user callbacks which can be efficiently parallelized. + + Callback parallelism is usually beneficial when the batch + evalution requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on mindfoptimize() function for more + information. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mindfcreate(const real_1d_array &x, mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfcreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets box constraints. + +Box constraints are inactive by default (after initial creation). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetbc(mindfstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetlc2dense(mindfstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mindfsetlc2dense(mindfstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'mindfsetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided nonlinear constraints. + +In fact, this function sets only NUMBER of the nonlinear constraints. +Constraints themselves (constraint functions) are passed to the +MinDFOptimize() method. + +This method accepts user-defined vector function F[] where: +* first component of F[] corresponds to the objective +* subsequent NNLC components of F[] correspond to the two-sided nonlinear + constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + +NOTE 2: the algorithm scales variables according to the scale specified by + MinDFSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints. We recommend you to scale + nonlinear constraints in such a way that the derivatives (if + constraints are differentiable) have approximately unit magnitude + (for problems with unit variable scales) or have magnitudes + approximately equal to 1/S[i] (where S is a variable scale set by + MinDFSetScale() function). + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetnlc2(mindfstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints. + +In fact, this function sets only NUMBER of the nonlinear constraints. +Constraints themselves (constraint functions) are passed to the +MinDFOptimize() method. + +This method accepts user-defined vector function F[] where: +* first component of F[] corresponds to the objective +* subsequent NNLC components of F[] correspond to the two-sided nonlinear + constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + +NOTE 2: the algorithm scales variables according to the scale specified by + MinDFSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints. We recommend you to scale + nonlinear constraints in such a way that the derivatives (if + constraints are differentiable) have approximately unit magnitude + (for problems with unit variable scales) or have magnitudes + approximately equal to 1/S[i] (where S is a variable scale set by + MinDFSetScale() function). + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mindfsetnlc2(mindfstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nnlc; + if( (nl.length()!=nu.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'mindfsetnlc2': looks like one of arguments has wrong size"); + nnlc = nl.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function sets a combined stopping condition: stopping when two +criteria are met simultaneously: +* function values has converged to a neighborhood whose size is + proportional to epsF +* variable values has converged to a neighborhood whose size is + proportional to epsX +It is possible to use only one condition by setting another EPS to zero. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + EpsX - >=0: + * zero value means no condition for X + * EpsX>0 means stopping when the solver converged with + error in I-th variable less than EpsX*S[i], where S[i] + is a variable scale + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondfx(mindfstate &state, const double epsf, const double epsx, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetcondfx(state.c_ptr(), epsf, epsx, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates internal timers used to track time +spent in various parts of the solver (mostly, callbacks vs solver itself). + +When activated with this function, the following timings are stored in the +mindfreport structure fields: +* total time spend in the optimization +* time spent in the callback +* time spent in the solver itself + +See comments on mindfreport structure for more information about timers +and their accuracy. + +Timers are an essential part of reports that helps to find out where the +most time is spent and how to optimize the code. E.g., noticing that +significant amount of time is spent in numerical differentiation makes +obvious that ALGLIB-provided parallel numerical differentiation is needed. + +However, time measurements add noticeable overhead, about 50-100ns per +function call. In some applications it results in a significant slowdown, +that's why this option is inactive by default and should be manually +activated. + +INPUT PARAMETERS: + State - structure which stores algorithm state + UseTimers- true or false + +NOTE: when tracing is turned on with alglib::trace_file(), some derivative + free solvers may also perform internal, more detailed time + measurements, which are printed to the log file. + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfusetimers(mindfstate &state, const bool usetimers, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfusetimers(state.c_ptr(), usetimers, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping condition for the optimizer: function values +has converged to a neighborhood whose size is proportional to epsF. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondf(mindfstate &state, const double epsf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetcondf(state.c_ptr(), epsf, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets variable scales. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and to +guide algorithm steps. + +The scale of a variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetscale(mindfstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinDFOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - the best point + so far and a function value at the point. For unconstrained problems + the function value is non-increasing (the most recent best point is + always at least not worse than the previous best one). However, it + can increase between iterations when solving constrained problems + (a better point may have higher objective value but smaller + constraint violation). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void mindfsetxrep(mindfstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of a running optimizer. It +should be called from a user-supplied callback when user decides that it +is time to "smoothly" terminate optimization process. As a result, the +optimizer stops at the point which was "current accepted" when the +termination request was submitted and returns error code 8 (successful +termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on an optimizer which is NOT running will have + no effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfrequesttermination(mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets seed used by internal RNG. + +By default, a random seed is used, i.e. every time you run the solver, we +seed its generator with a new value obtained from the system-wide RNG. +Thus, the solver returns non-deterministic results. You can change such +a behavior by specifying a fixed positive seed value. + +INPUT PARAMETERS: + S - optimizer structure + SeedVal - seed value: + * positive values are used for seeding RNG with a + fixed seed, i.e. subsequent runs on the same + objective will return the same results + * non-positive seed means that a random seed is used + for every run, i.e. subsequent runs on the same + objective will return slightly different results + + -- ALGLIB -- + Copyright 26.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetseed(mindfstate &s, const ae_int_t seedval, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetseed(s.c_ptr(), seedval, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with an +automatic parameters selection. + +NOTE: a version with manually tuned parameters can be activated by calling + the mindfsetalgogdemofixed() function. + +The primary stopping condition for the solver is to stop after the specified +number of iterations. You can also specify additional criteria to stop +early: +* stop when subpopulation target values (2N+1 best individuals) are within + EPS from the best one so far (function values seem to converge) +* stop when both subpopulation target values AND subpopulation variable + values are within EPS from the best one so far + +The first condition is specified with mindfsetcondf(), the second one is +activated with mindfsetcondfx(). + +Both conditions are heuristics which may fail. Being 'within EPS from the +best value so far' in practice means that we are somewhere within +[0.1EPS,10EPS] from the true solution; however, on difficult problems +this condition may fire too early. + +Imposing an additional requirement that variable values have clustered too +may prevent us from premature stopping. However, on multi-extremal and/or +noisy problems too many individuals may be trapped away from the optimum, +preventing this condition from activation. + +ALGORITHM PROPERTIES: + +* the solver uses a variant of the adaptive parameter tuning strategy + called 'Success-History Based Parameter Adaptation for Differential + Evolution Ensemble' (SHADE) by Ryoji Tanabe and Alex Fukunaga. You do + not have to specify crossover probability and differential weight, the + solver will automatically choose the most appropriate strategy. + +* the solver can handle box, linear, nonlinear constraints. Linear and + nonlinear constraints are handled by means of an L1/L2 penalty. The + solver does not violate box constraints at any point, but may violate + linear and nonlinear ones. Penalty coefficient can be changed with the + mindfsetgdemopenalty() function. + +* the solver heavily depends on variable scales being available (specified + by means of mindfsetscale() call) and on box constraints with both lower + and upper bounds being available which are used to determine the search + region. It will work without box constraints and without scales, but + results are likely to be suboptimal. + +* the solver is SIMD-optimized and parallelized (in commercial ALGLIB + editions), with nearly linear scalability of parallel processing. + +* this solver is intended for finding solutions with up to several digits + of precision at best. Its primary purpose is to find at least some + solution to an otherwise intractable problem. + +IMPORTANT: derivative-free optimization is inherently less robust than the + smooth nonlinear programming, especially when nonsmoothness and + discontinuities are present. + + Derivative-free algorithms have less convergence guarantees + than their smooth counterparts. It is considered a normal + (although, obviously, undesirable) situation when a derivative- + -free algorithm fails to converge with desired precision. Having + 2 digits of accurasy is already a good result, on difficult + problems (high numerical noise, discontinuities) you may have + even less than that. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + PopSize - population size, >=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemo(mindfstate &state, const ae_int_t epochscnt, const ae_int_t popsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetalgogdemo(state.c_ptr(), epochscnt, popsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with an +automatic parameters selection. + +NOTE: a version with manually tuned parameters can be activated by calling + the mindfsetalgogdemofixed() function. + +The primary stopping condition for the solver is to stop after the specified +number of iterations. You can also specify additional criteria to stop +early: +* stop when subpopulation target values (2N+1 best individuals) are within + EPS from the best one so far (function values seem to converge) +* stop when both subpopulation target values AND subpopulation variable + values are within EPS from the best one so far + +The first condition is specified with mindfsetcondf(), the second one is +activated with mindfsetcondfx(). + +Both conditions are heuristics which may fail. Being 'within EPS from the +best value so far' in practice means that we are somewhere within +[0.1EPS,10EPS] from the true solution; however, on difficult problems +this condition may fire too early. + +Imposing an additional requirement that variable values have clustered too +may prevent us from premature stopping. However, on multi-extremal and/or +noisy problems too many individuals may be trapped away from the optimum, +preventing this condition from activation. + +ALGORITHM PROPERTIES: + +* the solver uses a variant of the adaptive parameter tuning strategy + called 'Success-History Based Parameter Adaptation for Differential + Evolution Ensemble' (SHADE) by Ryoji Tanabe and Alex Fukunaga. You do + not have to specify crossover probability and differential weight, the + solver will automatically choose the most appropriate strategy. + +* the solver can handle box, linear, nonlinear constraints. Linear and + nonlinear constraints are handled by means of an L1/L2 penalty. The + solver does not violate box constraints at any point, but may violate + linear and nonlinear ones. Penalty coefficient can be changed with the + mindfsetgdemopenalty() function. + +* the solver heavily depends on variable scales being available (specified + by means of mindfsetscale() call) and on box constraints with both lower + and upper bounds being available which are used to determine the search + region. It will work without box constraints and without scales, but + results are likely to be suboptimal. + +* the solver is SIMD-optimized and parallelized (in commercial ALGLIB + editions), with nearly linear scalability of parallel processing. + +* this solver is intended for finding solutions with up to several digits + of precision at best. Its primary purpose is to find at least some + solution to an otherwise intractable problem. + +IMPORTANT: derivative-free optimization is inherently less robust than the + smooth nonlinear programming, especially when nonsmoothness and + discontinuities are present. + + Derivative-free algorithms have less convergence guarantees + than their smooth counterparts. It is considered a normal + (although, obviously, undesirable) situation when a derivative- + -free algorithm fails to converge with desired precision. Having + 2 digits of accurasy is already a good result, on difficult + problems (high numerical noise, discontinuities) you may have + even less than that. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + PopSize - population size, >=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mindfsetalgogdemo(mindfstate &state, const ae_int_t epochscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t popsize; + + popsize = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetalgogdemo(state.c_ptr(), epochscnt, popsize, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +ROBUST profile (the default option). + +The ROBUST profile is intended to facilitate explorative behavior and +robust convergence even on difficult multi-extremal problems. It comes at +the expense of increased running time even on easy problems. The QUICK +profile can be chosen if your problem is relatively easy to handle and you +prefer speed over robustness. In most cases, the QUICK profile is ~2x-3x +faster than the robust one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilerobust(mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetgdemoprofilerobust(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +QUICK profile. + +The QUICK profile is intended to facilitate accelerated convergence on +medium-complexity problems at the cost of (sometimes) having premature +convergence on difficult and/or multi-extremal problems. The ROBUST +profile can be selected if you favor convergence warranties over speed. +In most cases, the ROBUST profile is ~2x-3x slower than the QUICK one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + you want to activate differential evolution solver, you still + have to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilequick(mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetgdemoprofilequick(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to handle +linear/nonlinear constraints by an L1/L2 penalty function. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + Rho1, Rho2 - penalty parameters for constraint violations: + * Rho1 is a multiplier for L1 penalty + * Rho2 is a multiplier for L2 penalty + * Rho1,Rho2>=0 + * having both of them at zero means that some default + value will be chosen. + Ignored for problems with box-only constraints. + + L1 penalty is usually better at enforcing constraints, + but leads to slower convergence than L2 penalty. It is + possible to combine both kinds of penalties together. + + There is a compromise between constraint satisfaction + and optimality: high values of Rho mean that + constraints are satisfied with high accuracy but that + the target may be underoptimized due to numerical + difficulties. Small values of Rho mean that the + solution may grossly violate constraints. Choosing + good Rho is usually a matter of trial and error. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemopenalty(mindfstate &state, const double rho1, const double rho2, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetgdemopenalty(state.c_ptr(), rho1, rho2, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with the +manual parameters selection. + +Unlike DE with an automatic parameters selection this function requires +user to manually specify algorithm parameters. In the general case the +full-auto GDEMO is better. However, it has to spend some time finding out +properties of a problem being solved; furthermore, it is not allowed to +try potentially dangerous values of parameters that lead to premature +stopping. Manually tuning the solver to the specific problem at hand can +get 2x-3x better running time. + +Aside from that, the algorithm is fully equivalent to automatic GDEMO, and +we recommend you reading comments on mindfsetalgogdemo() for more +information about algorithm properties and stopping criteria. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + Strategy - specific DE strategy to use: + * 0 for DE/rand/1 + * 1 for DE/best/2 + * 2 for DE/current-to-best/1 + CrossoverProb- crossover probability, 0=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemofixed(mindfstate &state, const ae_int_t epochscnt, const ae_int_t strategy, const double crossoverprob, const double differentialweight, const ae_int_t popsize, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mindfsetalgogdemofixed(state.c_ptr(), epochscnt, strategy, crossoverprob, differentialweight, popsize, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mindfiteration(mindfstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mindfiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void mindfoptimize(mindfstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::mindfstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "mindf"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'mindfoptimize()' (fvec is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; + + alglib_impl::mindfsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::mindfiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idx(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mindfstate_owner& _mindfstate_owner::operator=(const _mindfstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mindfstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mindfstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mindfstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mindfstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mindfstate)); + alglib_impl::_mindfstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mindfstate_owner::~_mindfstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mindfstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mindfstate* _mindfstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mindfstate* _mindfstate_owner::c_ptr() const +{ + return p_struct; +} +mindfstate::mindfstate() : _mindfstate_owner() +{ +} + +mindfstate::mindfstate(alglib_impl::mindfstate *attach_to):_mindfstate_owner(attach_to) +{ +} + +mindfstate::mindfstate(const mindfstate &rhs):_mindfstate_owner(rhs) +{ +} + +mindfstate& mindfstate::operator=(const mindfstate &rhs) +{ + if( this==&rhs ) + return *this; + _mindfstate_owner::operator=(rhs); + return *this; +} + +mindfstate::~mindfstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* f objective value at the solution +* iterationscount total number of inner iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) +* bcerr maximum violation of box constraints +* lcerr maximum violation of linear constraints +* nlcerr maximum violation of nonlinear constraints + +If timers were activated, the structure also stores running times: +* timesolver time (in seconds, stored as a floating-point + value) spent in the solver itself. Time spent + in the user callback is not included. + See 'TIMERS' below for more information. +* timecallback time (in seconds, stored as a floating-point + value) spent in the user callback. + See 'TIMERS' below for more information. +* timetotal total time spent during the optimization, + including both the solver and callbacks. + See 'TIMERS' below for more information. +In order to activate timers, the caller has to call mindfusetimers() +function. + +Other fields of this structure are not documented and should not be used! + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 box constraints are inconsistent + -1 inconsistent parameters were passed: + * penalty parameter is zero, but we have nonlinear constraints + set by mindfsetnlc2() + 1 function value has converged within epsf + 2 sampling radius decreased below epsx + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 User requested termination via mindfrequesttermination() + +TIMERS + +Starting from ALGLIB 4.04, many optimizers report time spent in in the +solver itself and in user callbacks. The time is reported in seconds, +using floating-point (i.e. fractional-length intervals can be reported). + +In order to activate timers, the caller has to call mindfusetimers() +function. + +The accuracy of the reported value depends on the specific programming +language and OS being used: +* C++, no AE_OS is #defined - the accuracy is that of time() function, i.e. + one second. +* C++, AE_OS=AE_WINDOWS is #defined - the accuracy is that of GetTickCount(), + i.e. about 10-20ms +* C++, AE_OS=AE_POSIX is #defined - the accuracy is that of gettimeofday() +* C#, managed core, any OS - the accuracy is that of Environment.TickCount +* C#, HPC core, any OS - the accuracy is that of a corresponding C++ version +* any other language - the accuracy is that of a corresponding C++ version + +Whilst modern operating systems provide more accurate timers, these timers +often have significant overhead or backward compatibility issues. Thus, +ALGLIB stick to the most basic and efficient functions, even at the cost +of some accuracy being lost. +*************************************************************************/ +_mindfreport_owner::_mindfreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mindfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mindfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mindfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mindfreport)); + alglib_impl::_mindfreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mindfreport_owner::_mindfreport_owner(alglib_impl::mindfreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mindfreport_owner::_mindfreport_owner(const _mindfreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mindfreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mindfreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mindfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mindfreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mindfreport)); + alglib_impl::_mindfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mindfreport_owner& _mindfreport_owner::operator=(const _mindfreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mindfreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mindfreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mindfreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mindfreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mindfreport)); + alglib_impl::_mindfreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mindfreport_owner::~_mindfreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mindfreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mindfreport* _mindfreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mindfreport* _mindfreport_owner::c_ptr() const +{ + return p_struct; +} +mindfreport::mindfreport() : _mindfreport_owner() ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),bcerr(p_struct->bcerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),timetotal(p_struct->timetotal),timesolver(p_struct->timesolver),timecallback(p_struct->timecallback) +{ +} + +mindfreport::mindfreport(alglib_impl::mindfreport *attach_to):_mindfreport_owner(attach_to) ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),bcerr(p_struct->bcerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),timetotal(p_struct->timetotal),timesolver(p_struct->timesolver),timecallback(p_struct->timecallback) +{ +} + +mindfreport::mindfreport(const mindfreport &rhs):_mindfreport_owner(rhs) ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),bcerr(p_struct->bcerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),timetotal(p_struct->timetotal),timesolver(p_struct->timesolver),timecallback(p_struct->timecallback) +{ +} + +mindfreport& mindfreport::operator=(const mindfreport &rhs) +{ + if( this==&rhs ) + return *this; + _mindfreport_owner::operator=(rhs); + return *this; +} + +mindfreport::~mindfreport() +{ +} +#endif + +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LINEAR PROGRAMMING + +The subroutine creates LP solver. After initial creation it contains +default optimization problem with zero cost vector and all variables being +fixed to zero values and no constraints. + +In order to actually solve something you should: +* set cost vector with minlpsetcost() +* set variable bounds with minlpsetbc() or minlpsetbcall() +* specify constraint matrix with one of the following functions: + [*] minlpsetlc() for dense one-sided constraints + [*] minlpsetlc2dense() for dense two-sided constraints + [*] minlpsetlc2() for sparse two-sided constraints + [*] minlpaddlc2dense() to add one dense row to constraint matrix + [*] minlpaddlc2() to add one row to constraint matrix (compressed format) +* call minlpoptimize() to run the solver and minlpresults() to get the + solution vector and additional information. + +By default, LP solver uses best algorithm available. As of ALGLIB 3.17, +sparse interior point (barrier) solver is used. Future releases of ALGLIB +may introduce other solvers. + +User may choose specific LP algorithm by calling: +* minlpsetalgodss() for revised dual simplex method with DSE pricing and + bounds flipping ratio test (aka long dual step). Large-scale sparse LU + solverwith Forest-Tomlin update is used internally as linear algebra + driver. +* minlpsetalgoipm() for sparse interior point method + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer in the default state + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpcreate(const ae_int_t n, minlpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpcreate(n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets LP algorithm to revised dual simplex method. + +ALGLIB implementation of dual simplex method supports advanced performance +and stability improvements like DSE pricing , bounds flipping ratio test +(aka long dual step), Forest-Tomlin update, shifting. + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-7. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when relative error is less than Eps. + +===== TRACING DSS SOLVER ================================================= + +DSS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'DSS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'DSS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'DSS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("DSS,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgodss(minlpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetalgodss(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets LP algorithm to sparse interior point method. + +ALGORITHM INFORMATION: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-8. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when primal error AND dual error AND + duality gap are less than Eps. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgoipm(minlpstate &state, const double eps, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetalgoipm(state.c_ptr(), eps, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets LP algorithm to sparse interior point method. + +ALGORITHM INFORMATION: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-8. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when primal error AND dual error AND + duality gap are less than Eps. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsetalgoipm(minlpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double eps; + + eps = 0.0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetalgoipm(state.c_ptr(), eps, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets cost term for LP solver. + +By default, cost term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + C - cost term, array[N]. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetcost(minlpstate &state, const real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetcost(state.c_ptr(), c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients. + +ALGLIB optimizers use scaling matrices to test stopping conditions and as +preconditioner. + +Scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the + function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetscale(minlpstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +different constraints for different variables). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call, overwritten with minlpsetbcall(), or partially +overwritten with minlmsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + BndU - upper bounds, array[N]. + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minlpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbc(minlpstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +same constraints for all variables) + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call or partially overwritten with minlpsetbcall(). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbcall(minlpstate &state, const double bndl, const double bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetbcall(state.c_ptr(), bndl, bndu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + I - variable index, in [0,N) + BndL - lower bound for I-th variable + BndU - upper bound for I-th variable + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbci(minlpstate &state, const ae_int_t i, const double bndl, const double bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetbci(state.c_ptr(), i, bndl, bndu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets one-sided linear constraints A*x ~ AU, where "~" can be +a mix of "<=", "=" and ">=". + +IMPORTANT: this function is provided here for compatibility with the rest + of ALGLIB optimizers which accept constraints in format like + this one. Many real-life problems feature two-sided constraints + like a0 <= a*x <= a1. It is really inefficient to add them as a + pair of one-sided constraints. + + Use minlpsetlc2dense(), minlpsetlc2(), minlpaddlc2() (or its + sparse version) wherever possible. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N+1]. Each row of A represents + one constraint, with first N elements being linear coefficients, + and last element being right side. + CT - constraint types, array[K]: + * if CT[i]>0, then I-th constraint is A[i,*]*x >= A[i,n] + * if CT[i]=0, then I-th constraint is A[i,*]*x = A[i,n] + * if CT[i]<0, then I-th constraint is A[i,*]*x <= A[i,n] + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A and CT. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc(minlpstate &state, const real_2d_array &a, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetlc(state.c_ptr(), a.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets one-sided linear constraints A*x ~ AU, where "~" can be +a mix of "<=", "=" and ">=". + +IMPORTANT: this function is provided here for compatibility with the rest + of ALGLIB optimizers which accept constraints in format like + this one. Many real-life problems feature two-sided constraints + like a0 <= a*x <= a1. It is really inefficient to add them as a + pair of one-sided constraints. + + Use minlpsetlc2dense(), minlpsetlc2(), minlpaddlc2() (or its + sparse version) wherever possible. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N+1]. Each row of A represents + one constraint, with first N elements being linear coefficients, + and last element being right side. + CT - constraint types, array[K]: + * if CT[i]>0, then I-th constraint is A[i,*]*x >= A[i,n] + * if CT[i]=0, then I-th constraint is A[i,*]*x = A[i,n] + * if CT[i]<0, then I-th constraint is A[i,*]*x <= A[i,n] + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A and CT. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsetlc(minlpstate &state, const real_2d_array &a, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minlpsetlc': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetlc(state.c_ptr(), a.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU. + +This version accepts dense matrix as input; internally LP solver uses +sparse storage anyway (most LP problems are sparse), but for your +convenience it may accept dense inputs. This function overwrites linear +constraints set by previous calls (if such calls were made). + +We recommend you to use sparse version of this function unless you solve +small-scale LP problem (less than few hundreds of variables). + +NOTE: there also exist several versions of this function: + * one-sided dense version which accepts constraints in the same + format as one used by QP and NLP solvers + * two-sided sparse version which accepts sparse matrix + * two-sided dense version which allows you to add constraints row by row + * two-sided sparse version which allows you to add constraints row by row + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2dense(minlpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU. + +This version accepts dense matrix as input; internally LP solver uses +sparse storage anyway (most LP problems are sparse), but for your +convenience it may accept dense inputs. This function overwrites linear +constraints set by previous calls (if such calls were made). + +We recommend you to use sparse version of this function unless you solve +small-scale LP problem (less than few hundreds of variables). + +NOTE: there also exist several versions of this function: + * one-sided dense version which accepts constraints in the same + format as one used by QP and NLP solvers + * two-sided sparse version which accepts sparse matrix + * two-sided dense version which allows you to add constraints row by row + * two-sided sparse version which allows you to add constraints row by row + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minlpsetlc2dense(minlpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minlpsetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2(minlpstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpsetlc2(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +This version accepts dense constraint vector as input, but sparsifies it +for internal storage and processing. Thus, time to add one constraint in +is O(N) - we have to scan entire array of length N. Sparse version of this +function is order of magnitude faster for constraints with just a few +nonzeros per row. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2dense(minlpstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpaddlc2dense(state.c_ptr(), a.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2(minlpstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpaddlc2(state.c_ptr(), idxa.c_ptr(), vala.c_ptr(), nnz, al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function solves LP problem. + +INPUT PARAMETERS: + State - algorithm state + +You should use minlpresults() function to access results after calls to +this function. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey. +*************************************************************************/ +void minlpoptimize(minlpstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpoptimize(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LP solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution (on failure: last trial point) + Rep - optimization report. You should check Rep.TerminationType, + which contains completion code, and you may check another + fields which contain another information about algorithm + functioning. + + Failure codes returned by algorithm are: + * -4 LP problem is primal unbounded (dual infeasible) + * -3 LP problem is primal infeasible (dual unbounded) + * -2 IPM solver detected that problem is either + infeasible or unbounded + + Success codes: + * 1..4 successful completion + * 5 MaxIts steps was taken + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresults(const minlpstate &state, real_1d_array &x, minlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LP results + +Buffered implementation of MinLPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresultsbuf(const minlpstate &state, real_1d_array &x, minlpreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlpresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores linear solver state. +You should use functions provided by MinLP subpackage to work with this +object +*************************************************************************/ +_minlpstate_owner::_minlpstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpstate)); + alglib_impl::_minlpstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpstate_owner::_minlpstate_owner(alglib_impl::minlpstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlpstate_owner::_minlpstate_owner(const _minlpstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlpstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpstate)); + alglib_impl::_minlpstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpstate_owner& _minlpstate_owner::operator=(const _minlpstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlpstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlpstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlpstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlpstate)); + alglib_impl::_minlpstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlpstate_owner::~_minlpstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlpstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlpstate* _minlpstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlpstate* _minlpstate_owner::c_ptr() const +{ + return p_struct; +} +minlpstate::minlpstate() : _minlpstate_owner() +{ +} + +minlpstate::minlpstate(alglib_impl::minlpstate *attach_to):_minlpstate_owner(attach_to) +{ +} + +minlpstate::minlpstate(const minlpstate &rhs):_minlpstate_owner(rhs) +{ +} + +minlpstate& minlpstate::operator=(const minlpstate &rhs) +{ + if( this==&rhs ) + return *this; + _minlpstate_owner::operator=(rhs); + return *this; +} + +minlpstate::~minlpstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* f target function value +* lagbc Lagrange coefficients for box constraints +* laglc Lagrange coefficients for linear constraints +* y dual variables +* stats array[N+M], statuses of box (N) and linear (M) + constraints. This array is filled only by DSS + algorithm because IPM always stops at INTERIOR + point: + * stats[i]>0 => constraint at upper bound + (also used for free non-basic + variables set to zero) + * stats[i]<0 => constraint at lower bound + * stats[i]=0 => constraint is inactive, basic + variable +* primalerror primal feasibility error +* dualerror dual feasibility error +* slackerror complementary slackness error +* iterationscount iteration count +* terminationtype completion code (see below) + +COMPLETION CODES + +Completion codes: +* -4 LP problem is primal unbounded (dual infeasible) +* -3 LP problem is primal infeasible (dual unbounded) +* 1..4 successful completion +* 5 MaxIts steps was taken +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +LAGRANGE COEFFICIENTS + +Positive Lagrange coefficient means that constraint is at its upper bound. +Negative coefficient means that constraint is at its lower bound. It is +expected that at the solution the dual feasibility condition holds: + + C + SUM(Ei*LagBC[i],i=0..n-1) + SUM(Ai*LagLC[i],i=0..m-1) ~ 0 + +where +* C is a cost vector (linear term) +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix +*************************************************************************/ +_minlpreport_owner::_minlpreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpreport)); + alglib_impl::_minlpreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpreport_owner::_minlpreport_owner(alglib_impl::minlpreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minlpreport_owner::_minlpreport_owner(const _minlpreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minlpreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minlpreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minlpreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minlpreport)); + alglib_impl::_minlpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minlpreport_owner& _minlpreport_owner::operator=(const _minlpreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minlpreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minlpreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minlpreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minlpreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minlpreport)); + alglib_impl::_minlpreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minlpreport_owner::~_minlpreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minlpreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minlpreport* _minlpreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minlpreport* _minlpreport_owner::c_ptr() const +{ + return p_struct; +} +minlpreport::minlpreport() : _minlpreport_owner() ,f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),y(&p_struct->y),stats(&p_struct->stats),primalerror(p_struct->primalerror),dualerror(p_struct->dualerror),slackerror(p_struct->slackerror),iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype) +{ +} + +minlpreport::minlpreport(alglib_impl::minlpreport *attach_to):_minlpreport_owner(attach_to) ,f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),y(&p_struct->y),stats(&p_struct->stats),primalerror(p_struct->primalerror),dualerror(p_struct->dualerror),slackerror(p_struct->slackerror),iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype) +{ +} + +minlpreport::minlpreport(const minlpreport &rhs):_minlpreport_owner(rhs) ,f(p_struct->f),lagbc(&p_struct->lagbc),laglc(&p_struct->laglc),y(&p_struct->y),stats(&p_struct->stats),primalerror(p_struct->primalerror),dualerror(p_struct->dualerror),slackerror(p_struct->slackerror),iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype) +{ +} + +minlpreport& minlpreport::operator=(const minlpreport &rhs) +{ + if( this==&rhs ) + return *this; + _minlpreport_owner::operator=(rhs); + return *this; +} + +minlpreport::~minlpreport() +{ +} +#endif + +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + DERIVATIVE-FREE NONLINEAR LEAST SQUARES + +DESCRIPTION: + +This function creates a NLS solver configured to solve a constrained +nonlinear least squares problem + + min F(x) = f[0]^2 + f[1]^2 + ... + f[m-1]^2 + +where f[i] are available, but not their derivatives. + +The functions f[i] are assumed to be smooth, but may have some +amount of numerical noise (either random noise or deterministic noise +arising from numerical simulations or other complex numerical processes). + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i], M>=1 + X - initial point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlscreatedfo(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nlsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlscreatedfo(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + DERIVATIVE-FREE NONLINEAR LEAST SQUARES + +DESCRIPTION: + +This function creates a NLS solver configured to solve a constrained +nonlinear least squares problem + + min F(x) = f[0]^2 + f[1]^2 + ... + f[m-1]^2 + +where f[i] are available, but not their derivatives. + +The functions f[i] are assumed to be smooth, but may have some +amount of numerical noise (either random noise or deterministic noise +arising from numerical simulations or other complex numerical processes). + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i], M>=1 + X - initial point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void nlscreatedfo(const ae_int_t m, const real_1d_array &x, nlsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlscreatedfo(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +2PS (2-Point Stencil) algorithm. + +This solver is recommended for the following cases: +* an expensive target function is minimized by the commercial ALGLIB with + callback parallelism activated (see ALGLIB Reference Manual for more + information about parallel callbacks) +* an inexpensive target function is minimized by any ALGLIB edition (free + or commercial) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The 2PS algorithm is a derivative-free model-based nonlinear least squares +solver which builds local models by evaluating the target at N additional +points around the current one, with geometry similar to the 2-point finite +difference stencil. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. + +When compared with the DFO-LSA solver, the 2PS algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by the DFO-LSA) +* 2PS requires several times less iterations than the DFO-LSA because each + iteration extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets 2PS provides better parallelism potential than + DFO-LSA because the former issues many simultaneous target evaluation + requests which can be easily parallelized. It is possible for 2PS to + outperform DFO-LSA by parallelism alone, despite the fact that the + latter needs 3-4 times less target function evaluations. +* for inexpensive targets 2PS may win because it needs many times less + iterations, and thus the overhead associated with the working set updates + is also many times less. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgo2ps(nlsstate &state, const ae_int_t nnoisyrestarts, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetalgo2ps(state.c_ptr(), nnoisyrestarts, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +2PS (2-Point Stencil) algorithm. + +This solver is recommended for the following cases: +* an expensive target function is minimized by the commercial ALGLIB with + callback parallelism activated (see ALGLIB Reference Manual for more + information about parallel callbacks) +* an inexpensive target function is minimized by any ALGLIB edition (free + or commercial) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The 2PS algorithm is a derivative-free model-based nonlinear least squares +solver which builds local models by evaluating the target at N additional +points around the current one, with geometry similar to the 2-point finite +difference stencil. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. + +When compared with the DFO-LSA solver, the 2PS algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by the DFO-LSA) +* 2PS requires several times less iterations than the DFO-LSA because each + iteration extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets 2PS provides better parallelism potential than + DFO-LSA because the former issues many simultaneous target evaluation + requests which can be easily parallelized. It is possible for 2PS to + outperform DFO-LSA by parallelism alone, despite the fact that the + latter needs 3-4 times less target function evaluations. +* for inexpensive targets 2PS may win because it needs many times less + iterations, and thus the overhead associated with the working set updates + is also many times less. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void nlssetalgo2ps(nlsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nnoisyrestarts; + + nnoisyrestarts = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetalgo2ps(state.c_ptr(), nnoisyrestarts, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +DFO-LSA algorithm, an ALGLIB implementation (with several modifications)of +the original DFO-LS algorithm by Cartis, C., Fiala, J., Marteau, B. and +Roberts, L. ('Improving the Flexibility and Robustness of Model-Based +Derivative-Free Optimization Solvers', 2019). The A in DFO-LSA stands for +ALGLIB, in order to distinguish our slightly modified implementation from +the original algorithm. + +This solver is recommended for the following case: an expensive target +function is minimized without parallelism being used (either free ALGLIB +is used or commercial one is used but the target callback is non-reentrant +i.e. it can not be simultaneously called from multiple threads) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The DFO-LSA algorithm is a derivative-free model-based NLS solver which +builds local models by remembering N+1 previously computed target values +and updating them as optimization progresses. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. Our +implementation generally follows the same lines as the original DFO-LSA, +with several modifications to trust radius update strategies, stability +fixes (unlike original DFO-LS, our implementation can handle and recover +from the target breaking down due to infeasible arguments) and other minor +implementation details. + +When compared with the 2PS solver, the DFO-LSA algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by DFO-LSA) +* 2PS requires several times less iterations than DFO-LSA because each + iterations extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets DFO-LSA is much more efficient than 2PS because + it reuses previously computed target values as much as possible. +* however, DFO-LSA has little parallelism potential because (unlike 2PS) + it does not evaluate the target in several points simultaneously and + independently +* additionally, because DFO-LSA performs many times more iterations than + 2PS, iteration overhead (working set updates and matrix inversions) is + an issue here. For inexpensive targets it is possible for DFO-LSA to be + outperformed by 2PS merely because of the linear algebra cost. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgodfolsa(nlsstate &state, const ae_int_t nnoisyrestarts, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetalgodfolsa(state.c_ptr(), nnoisyrestarts, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +DFO-LSA algorithm, an ALGLIB implementation (with several modifications)of +the original DFO-LS algorithm by Cartis, C., Fiala, J., Marteau, B. and +Roberts, L. ('Improving the Flexibility and Robustness of Model-Based +Derivative-Free Optimization Solvers', 2019). The A in DFO-LSA stands for +ALGLIB, in order to distinguish our slightly modified implementation from +the original algorithm. + +This solver is recommended for the following case: an expensive target +function is minimized without parallelism being used (either free ALGLIB +is used or commercial one is used but the target callback is non-reentrant +i.e. it can not be simultaneously called from multiple threads) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The DFO-LSA algorithm is a derivative-free model-based NLS solver which +builds local models by remembering N+1 previously computed target values +and updating them as optimization progresses. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. Our +implementation generally follows the same lines as the original DFO-LSA, +with several modifications to trust radius update strategies, stability +fixes (unlike original DFO-LS, our implementation can handle and recover +from the target breaking down due to infeasible arguments) and other minor +implementation details. + +When compared with the 2PS solver, the DFO-LSA algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by DFO-LSA) +* 2PS requires several times less iterations than DFO-LSA because each + iterations extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets DFO-LSA is much more efficient than 2PS because + it reuses previously computed target values as much as possible. +* however, DFO-LSA has little parallelism potential because (unlike 2PS) + it does not evaluate the target in several points simultaneously and + independently +* additionally, because DFO-LSA performs many times more iterations than + 2PS, iteration overhead (working set updates and matrix inversions) is + an issue here. For inexpensive targets it is possible for DFO-LSA to be + outperformed by 2PS merely because of the linear algebra cost. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void nlssetalgodfolsa(nlsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nnoisyrestarts; + + nnoisyrestarts = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetalgodfolsa(state.c_ptr(), nnoisyrestarts, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - stop when the scaled trust region radius is smaller than + EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetcond(nlsstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetcond(state.c_ptr(), epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLSOptimize(). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetxrep(nlsstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets variable scales + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But +derivative-free optimizers often use scaling matrix both in the stopping +condition tests and as a preconditioner. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetscale(nlsstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets box constraints + +Box constraints are inactive by default (after initial creation). They are +preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (the latter is recommended). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (the latter is recommended). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unless explicitly mentioned in the specific NLS algorithm + description, the following holds: + * box constraints are always satisfied exactly + * the target is NOT evaluated outside of the box-constrained area + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetbc(nlsstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nlssetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool nlsiteration(nlsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::nlsiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void nlsoptimize(nlsstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::nlsstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "nls"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'nlsoptimize()' (fvec is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; + + alglib_impl::nlssetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::nlsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'nlsoptimize()' (fvec is NULL)", &_alglib_env_state); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'nlsoptimize()' (jac is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; +callbacks.jac = jac; + + alglib_impl::nlssetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::nlsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidx(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nlsstate_owner& _nlsstate_owner::operator=(const _nlsstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: nlsstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nlsstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: nlsstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_nlsstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::nlsstate)); + alglib_impl::_nlsstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_nlsstate_owner::~_nlsstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_nlsstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::nlsstate* _nlsstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::nlsstate* _nlsstate_owner::c_ptr() const +{ + return p_struct; +} +nlsstate::nlsstate() : _nlsstate_owner() +{ +} + +nlsstate::nlsstate(alglib_impl::nlsstate *attach_to):_nlsstate_owner(attach_to) +{ +} + +nlsstate::nlsstate(const nlsstate &rhs):_nlsstate_owner(rhs) +{ +} + +nlsstate& nlsstate::operator=(const nlsstate &rhs) +{ + if( this==&rhs ) + return *this; + _nlsstate_owner::operator=(rhs); + return *this; +} + +nlsstate::~nlsstate() +{ +} + + + + +/************************************************************************* +Optimization report, filled by NLSResults() function + +FIELDS: +* TerminationType, completion code, which is a sum of a BASIC code and an +ADDITIONAL code. + + The following basic codes denote failure: + * -8 optimizer detected NAN/INF either in the function itself, + or its Jacobian; recovery was impossible, abnormal termination + reported. + * -3 box constraints are inconsistent + + The following basic codes denote success: + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called NLSRequestTermination(). + X contains point which was "current accepted" when termination + request was submitted. + + Additional codes can be set on success, but not on failure: + * +800 if during algorithm execution the solver encountered + NAN/INF values in the target or constraints but managed to + recover by reducing trust region radius, the solver returns + one of SUCCESS codes but adds +800 to the code. + +* IterationsCount, contains iterations count +* NFunc, number of function calculations +*************************************************************************/ +_nlsreport_owner::_nlsreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nlsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::nlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nlsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nlsreport)); + alglib_impl::_nlsreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nlsreport_owner::_nlsreport_owner(alglib_impl::nlsreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_nlsreport_owner::_nlsreport_owner(const _nlsreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nlsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nlsreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::nlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nlsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nlsreport)); + alglib_impl::_nlsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nlsreport_owner& _nlsreport_owner::operator=(const _nlsreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: nlsreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nlsreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: nlsreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_nlsreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::nlsreport)); + alglib_impl::_nlsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_nlsreport_owner::~_nlsreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_nlsreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::nlsreport* _nlsreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::nlsreport* _nlsreport_owner::c_ptr() const +{ + return p_struct; +} +nlsreport::nlsreport() : _nlsreport_owner() ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc) +{ +} + +nlsreport::nlsreport(alglib_impl::nlsreport *attach_to):_nlsreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc) +{ +} + +nlsreport::nlsreport(const nlsreport &rhs):_nlsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),terminationtype(p_struct->terminationtype),nfunc(p_struct->nfunc) +{ +} + +nlsreport& nlsreport::operator=(const nlsreport &rhs) +{ + if( this==&rhs ) + return *this; + _nlsreport_owner::operator=(rhs); + return *this; +} + +nlsreport::~nlsreport() +{ +} +#endif + +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + BOUND CONSTRAINED OPTIMIZATION + WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BLEIC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBLEICCreate() call + +2. USer adds boundary and/or linear constraints by calling + MinBLEICSetBC() and MinBLEICSetLC() functions. + +3. User sets stopping conditions with MinBLEICSetCond(). + +4. User calls MinBLEICOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBLEICResults() to get solution + +6. Optionally user may call MinBLEICRestartFrom() to solve another problem + with same N but another starting point. + MinBLEICRestartFrom() allows to reuse already initialized structure. + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleiccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + BOUND CONSTRAINED OPTIMIZATION + WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BLEIC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBLEICCreate() call + +2. USer adds boundary and/or linear constraints by calling + MinBLEICSetBC() and MinBLEICSetLC() functions. + +3. User sets stopping conditions with MinBLEICSetCond(). + +4. User calls MinBLEICOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBLEICResults() to get solution + +6. Optionally user may call MinBLEICRestartFrom() to solve another problem + with same N but another starting point. + MinBLEICRestartFrom() allows to reuse already initialized structure. + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbleiccreate(const real_1d_array &x, minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleiccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +The subroutine is finite difference variant of MinBLEICCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBLEICCreate() in order to get +more information about creation of BLEIC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBLEICSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleiccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +The subroutine is finite difference variant of MinBLEICCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBLEICCreate() in order to get +more information about creation of BLEIC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBLEICSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleiccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets boundary constraints for BLEIC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbc(minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for BLEIC optimizer. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetlc(minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for BLEIC optimizer. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbleicsetlc(minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minbleicsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBLEICSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetcond(minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetcond(state.c_ptr(), epsg, epsf, epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for BLEIC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BLEIC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBLEICSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetscale(minbleicstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdefault(minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetprecdefault(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdiag(minbleicstate &state, const real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetprecdiag(state.c_ptr(), d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBLEICSetScale() +call (before or after MinBLEICSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecscale(minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetprecscale(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBLEICOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetxrep(minbleicstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +IMPORTANT: this feature is hard to combine with preconditioning. You can't +set upper limit on step length, when you solve optimization problem with +linear (non-boundary) constraints AND preconditioner turned on. + +When non-boundary constraints are present, you have to either a) use +preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! +In this case algorithm will terminate with appropriate error code. + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetstpmax(minbleicstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minbleiciteration(minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minbleicoptimize(minbleicstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'minbleicoptimize()' (func is NULL)", &_alglib_env_state); + alglib_impl::minbleicsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needf ) + { + func(state.x, state.f, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + +void minbleicoptimize(minbleicstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'minbleicoptimize()' (grad is NULL)", &_alglib_env_state); + alglib_impl::minbleicsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minbleiciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfg ) + { + grad(state.x, state.f, state.g, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minbleicoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbleicoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbleicsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardgradient(minbleicstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardsmoothness(minbleicstate &state, const ae_int_t level, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbleicoptguardsmoothness(minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t level; + + level = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbleicoptguardgradient() for gradient verification +* minbleicoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbleicoptguardnonc1test0results() +* minbleicoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardresults(minbleicstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test0results(const minbleicstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardnonc1test0results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test1results(minbleicstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicoptguardnonc1test1results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +BLEIC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. Feasible point is + either nonexistent or too hard to find. Try to + restart optimizer with better initial approximation + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbleicrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBLEICReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +BLEIC results + +Buffered implementation of MinBLEICResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicrestartfrom(minbleicstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicrequesttermination(minbleicstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinBLEIC subpackage to work with this +object +*************************************************************************/ +_minbleicstate_owner::_minbleicstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbleicstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbleicstate)); + alglib_impl::_minbleicstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbleicstate_owner::_minbleicstate_owner(alglib_impl::minbleicstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minbleicstate_owner::_minbleicstate_owner(const _minbleicstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbleicstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbleicstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minbleicstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbleicstate)); + alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbleicstate_owner& _minbleicstate_owner::operator=(const _minbleicstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minbleicstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbleicstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minbleicstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minbleicstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minbleicstate)); + alglib_impl::_minbleicstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minbleicstate_owner::~_minbleicstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minbleicstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minbleicstate* _minbleicstate_owner::c_ptr() const +{ + return p_struct; +} +minbleicstate::minbleicstate() : _minbleicstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbleicstate::minbleicstate(alglib_impl::minbleicstate *attach_to):_minbleicstate_owner(attach_to) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbleicstate::minbleicstate(const minbleicstate &rhs):_minbleicstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbleicstate& minbleicstate::operator=(const minbleicstate &rhs) +{ + if( this==&rhs ) + return *this; + _minbleicstate_owner::operator=(rhs); + return *this; +} + +minbleicstate::~minbleicstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount number of iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 inconsistent constraints. Feasible point is + either nonexistent or too hard to find. Try to + restart optimizer with better initial approximation + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minbleicrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. + +ADDITIONAL FIELDS + +There are additional fields which can be used for debugging: +* DebugEqErr error in the equality constraints (2-norm) +* DebugFS f, calculated at projection of initial point + to the feasible set +* DebugFF f, calculated at the final point +* DebugDX |X_start-X_final| +*************************************************************************/ +_minbleicreport_owner::_minbleicreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbleicreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbleicreport)); + alglib_impl::_minbleicreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbleicreport_owner::_minbleicreport_owner(alglib_impl::minbleicreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minbleicreport_owner::_minbleicreport_owner(const _minbleicreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbleicreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbleicreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minbleicreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbleicreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbleicreport)); + alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbleicreport_owner& _minbleicreport_owner::operator=(const _minbleicreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minbleicreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbleicreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minbleicreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minbleicreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minbleicreport)); + alglib_impl::_minbleicreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minbleicreport_owner::~_minbleicreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minbleicreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minbleicreport* _minbleicreport_owner::c_ptr() const +{ + return p_struct; +} +minbleicreport::minbleicreport() : _minbleicreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) +{ +} + +minbleicreport::minbleicreport(alglib_impl::minbleicreport *attach_to):_minbleicreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) +{ +} + +minbleicreport::minbleicreport(const minbleicreport &rhs):_minbleicreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype),debugeqerr(p_struct->debugeqerr),debugfs(p_struct->debugfs),debugff(p_struct->debugff),debugdx(p_struct->debugdx),debugfeasqpits(p_struct->debugfeasqpits),debugfeasgpaits(p_struct->debugfeasgpaits),inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount) +{ +} + +minbleicreport& minbleicreport::operator=(const minbleicreport &rhs) +{ + if( this==&rhs ) + return *this; + _minbleicreport_owner::operator=(rhs); + return *this; +} + +minbleicreport::~minbleicreport() +{ +} +#endif + +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONLINEARLY CONSTRAINED OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to the +any combination of the: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +USAGE: + +Here we give the very brief outline of the MinNLC optimizer. We strongly +recommend you to study examples in the ALGLIB Reference Manual and to read +ALGLIB User Guide: https://www.alglib.net/nonlinear-programming/ + +1. The user initializes the solver with minnlccreate() or minnlccreatef(), + depending on the specific solver chosen: + * minnlccreate() for solvers capable of handling the problem 'as is', + without relying on numerical differentiation (SQP/GIPM2 for problems + with analytic derivatives, ORBIT for derivative-free problems) + * minnlccreatef(), when a numerical differentiation is used to provide + derivatives to a smooth derivative-based solver (SQP or GIPM2). + + In the current release the following solvers can be used: + + * sparse large-scale filter-based SQP solver, recommended for problems + of any size (from several variables to hundreds of thousands of + variables). Good at warm-starts. Activated with the minnlcsetalgosqp() + function. + + * sparse large-scale nonlinear nonconvex interior point method (GIPM2), + recommended for problems of any size (from several variables to + hundreds of thousands of variables). Has lower iteration overhead + than SQP, but is worse at using good initial points (it will need + at least tens of iterations even when started from the solution). + Activated with minnlcsetalgogipm2() function. + + * dense SQP-BFGS solver, recommended for small-scale problems (up to + several hundreds of variables). Requires less function evaluations + than SQP, but has more expensive iteration. + Activated with minnlcsetalgosqpbfgs() function. + + * ORBIT, a model-based derivative free solver that uses local RBF + models to optimize expensive objectives. This solver is activated + with minnlcsetalgoorbit() function. + + * several other solvers, including legacy ones + +2. [optional] user activates OptGuard integrity checker which tries to + detect possible errors in the user-supplied callbacks: + * discontinuity/nonsmoothness of the target/nonlinear constraints + * errors in the analytic gradient provided by user + This feature is essential for early prototyping stages because it helps + to catch common coding and problem statement errors. + OptGuard can be activated with following functions (one per each check + performed): + * minnlcoptguardsmoothness() + * minnlcoptguardgradient() + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minnlcsetbc() for boundary constraints + b) minnlcsetlc2() for sparse two-sided linear constraints, + minnlcsetlc2dense() for dense two-sided linear constraints, + minnlcsetlc2mixed() for mixed sparse/dense two-sided linear constraints + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + c) minnlcsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minnlcsetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + Knowing variable scales helps to check stopping criteria and + precondition the solver. + +5. User sets stopping conditions with minnlcsetcond3() or minnlcsetcond(). + If NLC solver uses inner/outer iteration layout, this function sets + stopping conditions for INNER iterations. + +6. Finally, user calls minnlcoptimize() function which takes algorithm + state and pointer (delegate, etc.) to callback function which calculates + F/G/H. + +7. User calls minnlcresults() to get solution; additionally you can + retrieve OptGuard report with minnlcoptguardresults(), and get detailed + report about purported errors in the target function with: + * minnlcoptguardnonc1test0results() + * minnlcoptguardnonc1test1results() + +8. Optionally user may call minnlcrestartfrom() to solve another problem + with same N but another starting point. minnlcrestartfrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreate(const ae_int_t n, const real_1d_array &x, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + NONLINEARLY CONSTRAINED OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to the +any combination of the: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +USAGE: + +Here we give the very brief outline of the MinNLC optimizer. We strongly +recommend you to study examples in the ALGLIB Reference Manual and to read +ALGLIB User Guide: https://www.alglib.net/nonlinear-programming/ + +1. The user initializes the solver with minnlccreate() or minnlccreatef(), + depending on the specific solver chosen: + * minnlccreate() for solvers capable of handling the problem 'as is', + without relying on numerical differentiation (SQP/GIPM2 for problems + with analytic derivatives, ORBIT for derivative-free problems) + * minnlccreatef(), when a numerical differentiation is used to provide + derivatives to a smooth derivative-based solver (SQP or GIPM2). + + In the current release the following solvers can be used: + + * sparse large-scale filter-based SQP solver, recommended for problems + of any size (from several variables to hundreds of thousands of + variables). Good at warm-starts. Activated with the minnlcsetalgosqp() + function. + + * sparse large-scale nonlinear nonconvex interior point method (GIPM2), + recommended for problems of any size (from several variables to + hundreds of thousands of variables). Has lower iteration overhead + than SQP, but is worse at using good initial points (it will need + at least tens of iterations even when started from the solution). + Activated with minnlcsetalgogipm2() function. + + * dense SQP-BFGS solver, recommended for small-scale problems (up to + several hundreds of variables). Requires less function evaluations + than SQP, but has more expensive iteration. + Activated with minnlcsetalgosqpbfgs() function. + + * ORBIT, a model-based derivative free solver that uses local RBF + models to optimize expensive objectives. This solver is activated + with minnlcsetalgoorbit() function. + + * several other solvers, including legacy ones + +2. [optional] user activates OptGuard integrity checker which tries to + detect possible errors in the user-supplied callbacks: + * discontinuity/nonsmoothness of the target/nonlinear constraints + * errors in the analytic gradient provided by user + This feature is essential for early prototyping stages because it helps + to catch common coding and problem statement errors. + OptGuard can be activated with following functions (one per each check + performed): + * minnlcoptguardsmoothness() + * minnlcoptguardgradient() + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minnlcsetbc() for boundary constraints + b) minnlcsetlc2() for sparse two-sided linear constraints, + minnlcsetlc2dense() for dense two-sided linear constraints, + minnlcsetlc2mixed() for mixed sparse/dense two-sided linear constraints + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + c) minnlcsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minnlcsetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + Knowing variable scales helps to check stopping criteria and + precondition the solver. + +5. User sets stopping conditions with minnlcsetcond3() or minnlcsetcond(). + If NLC solver uses inner/outer iteration layout, this function sets + stopping conditions for INNER iterations. + +6. Finally, user calls minnlcoptimize() function which takes algorithm + state and pointer (delegate, etc.) to callback function which calculates + F/G/H. + +7. User calls minnlcresults() to get solution; additionally you can + retrieve OptGuard report with minnlcoptguardresults(), and get detailed + report about purported errors in the target function with: + * minnlcoptguardnonc1test0results() + * minnlcoptguardnonc1test1results() + +8. Optionally user may call minnlcrestartfrom() to solve another problem + with same N but another starting point. minnlcrestartfrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlccreate(const real_1d_array &x, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Buffered version of minnlccreate() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.10.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatebuf(const ae_int_t n, const real_1d_array &x, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatebuf(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Buffered version of minnlccreate() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.10.2024 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlccreatebuf(const real_1d_array &x, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatebuf(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine is a finite difference variant of MinNLCCreate(). It uses +finite differences in order to differentiate target function. + +This function is relevant when you want to solve a derivative-free problem +using a solver that relies on gradient info being available (e.g. SQP or +GIPM2). Do not use it for derivative-free solvers like ORBIT, the algo +will generate an exception during optimization. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinNLCCreate() in order to get more +information about creation of the NLC optimizer. + +CALLBACK PARALLELISM + +The MINNLC optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, >0. + By default, a 5-point formula is used (actually, only 4 + function values per variable are used because the central + one has zero coefficient due to symmetry; that's why this + formula is often called a 4-point one). It can be changed + with minnlcsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTES: + +1. the differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinNLCSetScale() call. + +2. we recommend you to use moderate values of differentiation step. Too + large step will result in too large TRUNCATION errors, while too small + step will result in too large NUMERICAL errors. 1.0E-4 can be good + value to start from. + +3. Numerical differentiation is very inefficient - one gradient + calculation needs ~N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems or near the + solution. + + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine is a finite difference variant of MinNLCCreate(). It uses +finite differences in order to differentiate target function. + +This function is relevant when you want to solve a derivative-free problem +using a solver that relies on gradient info being available (e.g. SQP or +GIPM2). Do not use it for derivative-free solvers like ORBIT, the algo +will generate an exception during optimization. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinNLCCreate() in order to get more +information about creation of the NLC optimizer. + +CALLBACK PARALLELISM + +The MINNLC optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, >0. + By default, a 5-point formula is used (actually, only 4 + function values per variable are used because the central + one has zero coefficient due to symmetry; that's why this + formula is often called a 4-point one). It can be changed + with minnlcsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTES: + +1. the differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinNLCSetScale() call. + +2. we recommend you to use moderate values of differentiation step. Too + large step will result in too large TRUNCATION errors, while too small + step will result in too large NUMERICAL errors. 1.0E-4 can be good + value to start from. + +3. Numerical differentiation is very inefficient - one gradient + calculation needs ~N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems or near the + solution. + + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlccreatef(const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Buffered version of minnlccreatef() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatefbuf(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatefbuf(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Buffered version of minnlccreatef() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlccreatefbuf(const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlccreatefbuf(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets boundary constraints for NLC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine boundary constraints with general linear ones - and with +nonlinear ones! Boundary constraints are handled more efficiently than +other types. Thus, if your problem has mixed constraints, you may +explicitly specify some of them as boundary and save some time/space. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: when you solve your problem with augmented Lagrangian solver, + boundary constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetbc(minnlcstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for MinNLC optimizer. + +Linear constraints are inactive by default (after initial creation). They +are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine linear constraints with boundary ones - and with nonlinear +ones! If your problem has mixed constraints, you may explicitly specify +some of them as linear. It may help optimizer to handle them more +efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: when you solve your problem with augmented Lagrangian solver, + linear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc(minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints for MinNLC optimizer. + +Linear constraints are inactive by default (after initial creation). They +are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine linear constraints with boundary ones - and with nonlinear +ones! If your problem has mixed constraints, you may explicitly specify +some of them as linear. It may help optimizer to handle them more +efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: when you solve your problem with augmented Lagrangian solver, + linear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlcsetlc(minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minnlcsetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2dense(minnlcstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlcsetlc2dense(minnlcstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minnlcsetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2(minnlcstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc2(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2mixed(minnlcstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetlc2mixed(state.c_ptr(), sparsea.c_ptr(), ksparse, densea.c_ptr(), kdense, al.c_ptr(), au.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2dense(minnlcstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcaddlc2dense(state.c_ptr(), a.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2(minnlcstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcaddlc2(state.c_ptr(), idxa.c_ptr(), vala.c_ptr(), nnz, al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2sparsefromdense(minnlcstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcaddlc2sparsefromdense(state.c_ptr(), da.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets nonlinear constraints for MinNLC optimizer. + +It sets constraints of the form + + Ci(x)=0 for i=0..NLEC-1 + Ci(x)<=0 for i=NLEC..NLEC+NLIC-1 + +See MinNLCSetNLC2() for a modern function which allows greater flexibility +in the constraint specification. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc(minnlcstate &state, const ae_int_t nlec, const ae_int_t nlic, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetnlc(state.c_ptr(), nlec, nlic, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinNLC optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinNLCOptimize() method as callbacks. + +MinNLCOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinNLCSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinNLCSetScale() function). + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc2(minnlcstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinNLC optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinNLCOptimize() method as callbacks. + +MinNLCOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinNLCSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinNLCSetScale() function). + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlcsetnlc2(minnlcstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nnlc; + if( (nl.length()!=nu.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minnlcsetnlc2': looks like one of arguments has wrong size"); + nnlc = nl.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minnlccreatef() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreateF call. + FormulaType - formula type: + * 5 for a 5-point formula (actually, only 4 values per + variable are used, ones at x+h, x+h/2, x-h/2 and + x-h; the central one has zero multiplier due to + symmetry). The most precise and the most expensive + option, chosen by default + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good compromise for medium-accuracy + setups + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnumdiff(minnlcstate &state, const ae_int_t formulatype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetnumdiff(state.c_ptr(), formulatype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set iterations limit and step-based stopping +conditions. If you want the solver to stop upon having a small change in +the target, use minnlcsetcond3() function. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond(minnlcstate &state, const double eps, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetcond(state.c_ptr(), eps, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set three types of stopping conditions: +* iterations limit +* stopping upon performing a short step (depending on the specific solver + being used it may stop as soon as the first short step was made, or + only after performing several sequential short steps) +* stopping upon having a small change in the target (depending on the + specific solver being used it may stop as soon as the first step with + small change in the target was made, or only after performing several + sequential steps) + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The optimizer will stop as soon as the following condition + is met: + + |f_scl(k+1)-f_scl(k)| <= max(|f_scl(k+1)|,|f_scl(k)|,1) + + where f_scl is an internally used by the optimizer rescaled + target (ALGLIB optimizers usually apply rescaling in order + to normalize target and constraints). + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF, EpsX=0 and MaxIts=0 (simultaneously) will lead to the +automatic selection of the stopping condition. + + -- ALGLIB -- + Copyright 21.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond3(minnlcstate &state, const double epsf, const double eps, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetcond3(state.c_ptr(), epsf, eps, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scales +are also used by the finite difference variant of the optimizer - the step +along I-th axis is equal to DiffStep*S[I]. Finally, variable scales are +used for preconditioning (i.e. to speed up the solver). + +The scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetscale(minnlcstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length (after scaling of step vector with +respect to variable scales specified by minnlcsetscale() call). + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: different solvers employed by MinNLC optimizer may use different + norms for the step. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetstpmax(minnlcstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells MinNLC unit to use the large-scale augmented Lagrangian +algorithm for nonlinearly constrained optimization. + +This algorithm is a significant refactoring of one described in "A +Modified Barrier-Augmented Lagrangian Method for Constrained Minimization +(1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH with the +following additions: +* improved sparsity support +* improved handling of large-scale problems with the low rank LBFGS-based + sparse preconditioner +* automatic selection of the penalty parameter Rho + +AUL solver can be significantly faster than SQP on easy problems due to +cheaper iterations, although it needs more function evaluations. On large- +scale sparse problems one iteration of the AUL solver usually costs tens +times less than one iteration of the SQP solver. + +However, the SQP solver is more robust than the AUL. In particular, it is +much better at constraint enforcement and will never escape feasible area +after constraints were successfully enforced. It also needs much less +target function evaluations. + +INPUT PARAMETERS: + State - structure which stores algorithm state + MaxOuterIts-upper limit on outer iterations count: + * MaxOuterIts=0 means that the solver will automatically + choose an upper limit. Recommended value. + * MaxOuterIts>1 means that the AUL solver will performs at + most specified number of outer iterations + + -- ALGLIB -- + Copyright 22.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoaul2(minnlcstate &state, const ae_int_t maxouterits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgoaul2(state.c_ptr(), maxouterits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the sparse l-BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. +> + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qp(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgosl1qp(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the dense BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qpbfgs(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgosl1qpbfgs(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects large-scale sparse filter-based SQP solver, the +most robust solver in ALGLIB, a recommended option. + +This algorithm is scalable to problems with millions of variables and can +efficiently handle sparsity of constraints. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqp(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgosqp(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects ORBIT solver, a model-based derivative-free solver +for minimization of expensive derivative-free functions. + +The ORBIT algorithm by Wild and Shoemaker (2013) is an algorithm that uses +objective function values to build a smooth RBF model (f=r^3) that is +minimized over a trust region in order to identify step direction. The +algorithm saves and reuses function values at all previously known points. + +ALGLIB added to the original algorithm the following modifications: +* box, linear and nonlinear constraints +* improved tolerance to noise in the objective/constraints + +Its intended area of application is a low-accuracy minimization of +expensive objectives with no gradient available. It is expected that +additional overhead of building and minimizing an RBF model is negligible +when compared with the objective evaluation cost. Iteration overhead grows +as O(N^3), so this solver is recommended for problems with N below 100. + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear and nonlinear constraints are enforced, the algorithm will + try to respect them as much as possible. + +When compared with SQP solver, ORBIT: +* is much faster than the finite-difference based serial SQP at early + stages of optimization, being able to achieve 0.1-0.01 relative accuracy + about 4x-10x faster than SQP solver +* has slower asymptotic convergence on ill-conditioned problems, sometimes + being unable to reduce error in objective or constraints below 1E-5 in + a reasonable amount of time +* has no obvious benefits over SQP with analytic gradient or highly + parallelized (more than 10 cores) finite-difference SQP + +NOTE: whilst technically this algorithm supports callback parallelism, in + practice it can't efficiently utilize parallel resources because it + issues requests for objective/constraints in an inherently serial + manner. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Rad0 - initial sampling radius (multiplied by per-variable + scales), Rad0>=0, zero value means automatic radius + selection. + An ideal value is large enough to allow significant + progress by making a Rad0-sized step, but not too large + (so that initial linear model well approximates the + objective). + Recommended values: 0.1 or 1 (assuming properly chosen + variable scales. + The solver can tolerate inappropriately chosen Rad0, at + the expense of additional function evaluations needed to + adjust it. + + MaxNFEV - MaxNFEV>=0, with zero value meaning no limit. This + parameter allows to control computational budget (measured + in function evaluations). + + It provides somewhat finer control than MaxIts parameter + of minnlcsetcond(), which controls the maximum amount of + iterations performed by the algorithm, with one iteration + usually needing more than one function evaluation. + + The solver does not stop immediately after reaching + MaxNFEV evaluations, but will stop shortly after that + (usually within N+1 evaluations, often within 1-2). + + -- ALGLIB -- + Copyright 02.10.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoorbit(minnlcstate &state, const double rad0, const ae_int_t maxnfev, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgoorbit(state.c_ptr(), rad0, maxnfev, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects a SQP solver specialized on low-dimensional problems +- dense filter-based SQP-BFGS solver. + +This algorithm uses a dense quadratic model of the target and solves a +dense QP subproblem at each step. Thus, it has difficulties scaling beyond +several hundreds of variables. However, it usually needs the smallest +number of the target evaluations - sometimes up to 30% less than the +sparse large-scale filter-based SQP. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a well optimized implementation; + however, using a hardware vendor-provided performance library + usually results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqpbfgs(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgosqpbfgs(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function selects large-scale sparse interior point solver (GIPM2). + +This algorithm is scalable to problems with hundreds of thousands of +variables and can efficiently handle sparsity of constraints. + +When compared to SQP, the following differences can be noted: +* GIPM2 has lower iteration overhead than SQP +* GIPM2 violates all non-box constraints (linear and nonlinear, equality + and inequality ones) until it finally converges. Contrary to that, SQP + respects linear constraints after initial enforcement, and tends to + closely follow nonlinear ones. +* as all interior point methods, GIPM2 is bad at hot starts. Even if + started from solution, it will perform at least 30-60 iterations (first, + it will move away from the solution to find a centered initial point, + then it will converge back along the central path). + +The shorty summary is that SQP wins when starting close to the solution, +and GIPM2 tends to win on large-scale sparse problems where constraint +factorization adds significant linear algebra overhead. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING GIPM2 SOLVER =============================================== + +GIPM2 solver supports advanced tracing capabilities. You can trace +algorithm output by specifying following trace symbols (case-insensitive) +by means of trace_file() call: +* 'GIPM2' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GIPM2,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.02.2025 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgogipm2(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetalgogipm2(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinNLCOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - current point + and penalized function value at current point. Important - function + value which is returned is NOT function being minimized. It is sum + of the value of the function being minimized - and penalty term. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetxrep(minnlcstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minnlciteration(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minnlcoptimize(minnlcstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::minnlcstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "minnlc"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minnlcoptimize()' (fvec is NULL)", &_alglib_env_state); +callbacks.fvec = fvec; + + alglib_impl::minnlcsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'minnlcoptimize()' (jac is NULL)", &_alglib_env_state); +callbacks.jac = jac; + + alglib_impl::minnlcsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==2 ) + { + for(alglib_impl::ae_int_t qidx=0; qidxtmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(sjac!=NULL, "ALGLIB: error in 'minnlcoptimize()' (sjac is NULL)", &_alglib_env_state); +callbacks.sjac = sjac; + + alglib_impl::minnlcsetprotocolv2s(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minnlciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==1 ) + { + alglib_impl::sparsecreatecrsemptybuf(request.vars, &state.c_ptr()->replysj, &_alglib_env_state); + for(alglib_impl::ae_int_t qidx=0; qidx0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minnlcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardgradient(minnlcstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) and/or constraints +b) nonsmooth target function (non-C1) and/or constraints + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + This kind of monitoring does not work well with SQP + because SQP solver needs just 1-2 function evaluations + per step, which is not enough for OptGuard to make + any conclusions. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardsmoothness(minnlcstate &state, const ae_int_t level, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) and/or constraints +b) nonsmooth target function (non-C1) and/or constraints + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + This kind of monitoring does not work well with SQP + because SQP solver needs just 1-2 function evaluations + per step, which is not enough for OptGuard to make + any conclusions. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnlcoptguardsmoothness(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t level; + + level = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minnlcoptguardgradient() for gradient verification +* minnlcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation +* rep.nonc0suspected, and additionally: + * rep.nonc0fidx - an index of specific function violating C0 continuity +* rep.nonc1suspected, and additionally + * rep.nonc1fidx - an index of specific function violating C1 continuity +Here function index 0 means target function, index 1 or higher denotes +nonlinear constraints. + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minnlcoptguardnonc1test0results() +* minnlcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardresults(minnlcstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test0results(const minnlcstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardnonc1test0results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test1results(minnlcstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcoptguardnonc1test1results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +MinNLC results: the solution found, completion codes and additional +information. + +If you activated OptGuard integrity checking functionality and want to get +OptGuard report, it can be retrieved with: +* minnlcoptguardresults() - for a primary report about (a) suspected C0/C1 + continuity violations and (b) errors in the analytic gradient. +* minnlcoptguardnonc1test0results() - for C1 continuity violation test #0, + detailed line search log +* minnlcoptguardnonc1test1results() - for C1 continuity violation test #1, + detailed line search log + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + rep.f contains objective value at the solution. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient, recovery was + impossible. Abnormal termination signalled. + * -3 box constraints are infeasible. + Note: infeasibility of non-box constraints does + NOT trigger emergency completion; you have + to examine rep.bcerr/rep.lcerr/rep.nlcerr to + detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 1 small objective decrease indicates convergence + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 7 stopping conditions are too stringent, returning + the best point so far + * 8 user requested algorithm termination via + minnlcrequesttermination(), last accepted point is + returned. + + === ADDITIONAL CODES === + * +800 if during algorithm execution the solver + encountered NAN/INF values in the target or + constraints but managed to recover by reducing + trust region radius, the solver returns one + of SUCCESS codes but adds +800 to the code. + + Some solvers (as of ALGLIB 4.05, SQP and GIPM2) return + Lagrange multipliers in rep.lagbc/lagbcnz, laglc, lagnlc + fields. + + More information about fields of this structure can be + found in the comments on the minnlcreport datatype. + + -- ALGLIB -- + Copyright 18.01.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcresults(const minnlcstate &state, real_1d_array &x, minnlcreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +NLC results + +Buffered implementation of MinNLCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcresultsbuf(const minnlcstate &state, real_1d_array &x, minnlcreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcrequesttermination(minnlcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcrestartfrom(minnlcstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnlcrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinNLC subpackage to work with this +object +*************************************************************************/ +_minnlcstate_owner::_minnlcstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnlcstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minnlcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnlcstate)); + alglib_impl::_minnlcstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnlcstate_owner::_minnlcstate_owner(alglib_impl::minnlcstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minnlcstate_owner::_minnlcstate_owner(const _minnlcstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnlcstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnlcstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minnlcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnlcstate)); + alglib_impl::_minnlcstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnlcstate_owner& _minnlcstate_owner::operator=(const _minnlcstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minnlcstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnlcstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minnlcstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minnlcstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minnlcstate)); + alglib_impl::_minnlcstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minnlcstate_owner::~_minnlcstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minnlcstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minnlcstate* _minnlcstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minnlcstate* _minnlcstate_owner::c_ptr() const +{ + return p_struct; +} +minnlcstate::minnlcstate() : _minnlcstate_owner() +{ +} + +minnlcstate::minnlcstate(alglib_impl::minnlcstate *attach_to):_minnlcstate_owner(attach_to) +{ +} + +minnlcstate::minnlcstate(const minnlcstate &rhs):_minnlcstate_owner(rhs) +{ +} + +minnlcstate& minnlcstate::operator=(const minnlcstate &rhs) +{ + if( this==&rhs ) + return *this; + _minnlcstate_owner::operator=(rhs); + return *this; +} + +minnlcstate::~minnlcstate() +{ +} + + + + +/************************************************************************* +These fields store optimization report: +* f objective value at the solution +* iterationscount total number of inner iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +Scaled constraint violations are reported: +* bcerr maximum violation of the box constraints +* bcidx index of the most violated box constraint (or + -1, if all box constraints are satisfied or + there is no box constraint) +* lcerr maximum violation of the linear constraints, + computed as maximum scaled distance between + final point and constraint boundary. +* lcidx index of the most violated linear constraint + (or -1, if all constraints are satisfied or + there is no general linear constraints) +* nlcerr maximum violation of the nonlinear constraints +* nlcidx index of the most violated nonlinear constraint + (or -1, if all constraints are satisfied or + there is no nonlinear constraints) +* sclfeaserr maximum violation over all constraints, + computed with scaling/renormalization applied. + +Violations of box constraints are scaled on per-component basis according +to the scale vector s[] as specified by minnlcsetscale(). Violations of +the general linear constraints are also computed using user-supplied +variable scaling. Violations of nonlinear constraints are computed "as is" + +LAGRANGE COEFFICIENTS + +GIPM2 and modern SQP (one activated by setalgosqp()/setalgosqpbfgs(), but +not with legacy functions) set the following fields (other solvers fill +them by zeros): + +* lagbc[] array[N], Lagrange multipliers for box + constraints. IMPORTANT: COEFFICIENTS FOR FIXED + VARIABLES ARE SET TO ZERO. See below for an + explanation. + This parameter stores the same results + independently of whether analytic gradient is + provided or numerical differentiation is used. + +* lagbcnz[] array[N], Lagrange multipliers for box + constraints, behaves differently depending on + whether analytic gradient is provided or + numerical differentiation is used: + * for analytic Jacobian, lagbcnz[] contains + correct coefficients for all kinds of + variables - fixed or not. + * for numerical Jacobian, it is the same as + lagbc[], i.e. components corresponding to + fixed vars are zero. + See below for an explanation. + +* laglc[] array[Mlin], coeffs for linear constraints + +* lagnlc[] array[Mnlc], coeffs for nonlinear constraints + + +Positive Lagrange coefficient means that constraint is at its upper bound. +Negative coefficient means that constraint is at its lower bound. It is +expected that at the solution the dual feasibility condition holds: + + grad + SUM(Ei*LagBC[i],i=0..n-1) + + SUM(Ai*LagLC[i],i=0..mlin-1) + + SUM(Ni*LagNLC[i],i=0..mnlc-1) ~ 0 + + (except for fixed variables which are handled specially) + +where +* grad is a gradient at the solution +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix +* Ni is an gradient of I-th nonlinear constraint + +Fixed variables have two sets of Lagrange multipliers for the following +reasons: +* analytic gradient and numerical gradient behave differently for fixed + vars. Numerical differentiation does not violate box constraints, thus + gradient components corresponding to fixed vars are zero because we have + no way of differentiating for these vars without violating box + constraints. + Contrary to that, analytic gradient usually returns correct values even + for fixed vars. +* ideally, we would like numerical gradient to be an almost perfect + replacement for an analytic one. Thus, we need Lagrange multipliers + which do not change when we change the gradient type. +* on the other hand, we do not want to lose the possibility of having + a full set of Lagrange multipliers for problems with analytic gradient. + Thus, there is a special field lagbcnz[] whose contents depends on the + information available to us. + +TERMINATION CODES + +TerminationType field contains completion code, which can be either FAILURE +code, SUCCESS code, or SUCCESS code + ADDITIONAL code. The latter option +is used for more detailed reporting. + +=== FAILURE CODE === + -8 internal integrity control detected infinite or NAN values in + function/gradient, recovery was impossible. Abnormal termination + signaled. + -3 box constraints are infeasible. Note: infeasibility of non-box + constraints does NOT trigger emergency completion; you have to + examine bcerr/lcerr/nlcerr to detect possibly inconsistent + constraints. + +=== SUCCESS CODE === + 1 small objective decrease indicates convergence + 2 Eps-based condition (depending on the solver): + * relative step is no more than Eps (for SQP and similar) + * primal/dual/complementarity errors are less than Eps (for GIPM2) + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 user requested algorithm termination via minnlcrequesttermination(), + last accepted point is returned + +=== ADDITIONAL CODES === +* +800 if during algorithm execution the solver encountered + NAN/INF values in the target or constraints but managed to + recover by reducing trust region radius, the solver returns + one of SUCCESS codes but adds +800 to the code. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +_minnlcreport_owner::_minnlcreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnlcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minnlcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnlcreport)); + alglib_impl::_minnlcreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnlcreport_owner::_minnlcreport_owner(alglib_impl::minnlcreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minnlcreport_owner::_minnlcreport_owner(const _minnlcreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnlcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnlcreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minnlcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnlcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnlcreport)); + alglib_impl::_minnlcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnlcreport_owner& _minnlcreport_owner::operator=(const _minnlcreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minnlcreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnlcreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minnlcreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minnlcreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minnlcreport)); + alglib_impl::_minnlcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minnlcreport_owner::~_minnlcreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minnlcreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minnlcreport* _minnlcreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minnlcreport* _minnlcreport_owner::c_ptr() const +{ + return p_struct; +} +minnlcreport::minnlcreport() : _minnlcreport_owner() ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx),sclfeaserr(p_struct->sclfeaserr),lagbc(&p_struct->lagbc),lagbcnz(&p_struct->lagbcnz),laglc(&p_struct->laglc),lagnlc(&p_struct->lagnlc),dbgphase0its(p_struct->dbgphase0its) +{ +} + +minnlcreport::minnlcreport(alglib_impl::minnlcreport *attach_to):_minnlcreport_owner(attach_to) ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx),sclfeaserr(p_struct->sclfeaserr),lagbc(&p_struct->lagbc),lagbcnz(&p_struct->lagbcnz),laglc(&p_struct->laglc),lagnlc(&p_struct->lagnlc),dbgphase0its(p_struct->dbgphase0its) +{ +} + +minnlcreport::minnlcreport(const minnlcreport &rhs):_minnlcreport_owner(rhs) ,f(p_struct->f),iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx),sclfeaserr(p_struct->sclfeaserr),lagbc(&p_struct->lagbc),lagbcnz(&p_struct->lagbcnz),laglc(&p_struct->laglc),lagnlc(&p_struct->lagnlc),dbgphase0its(p_struct->dbgphase0its) +{ +} + +minnlcreport& minnlcreport::operator=(const minnlcreport &rhs) +{ + if( this==&rhs ) + return *this; + _minnlcreport_owner::operator=(rhs); + return *this; +} + +minnlcreport::~minnlcreport() +{ +} +#endif + +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + MULTI-OBJECTIVE OPTIMIZATION + +DESCRIPTION: + +The solver minimizes an M-dimensional vector function F(x) of N arguments +subject to any combination of: +* box constraints +* two-sided linear equality/inequality constraints AL<=A*x<=AU, where some + of AL/AU can be infinite (i.e. missing) +* two-sided nonlinear equality/inequality constraints NL<=C(x)<=NU, where + some of NL/NU can be infinite (i.e. missing) + +REQUIREMENTS: +* F(), C() are continuously differentiable on the feasible set and on its + neighborhood + +USAGE: + +1. User initializes algorithm state using either: + * minmocreate() to perform optimization with user-supplied Jacobian + * minmocreatef() to perform optimization with numerical differentiation + +2. User chooses which multi-objective solver to use. At the present moment + only NBI (Normal Boundary Intersection) solver is implemented, which is + activated by calling minmosetalgonbi(). + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minmosetbc() for boundary constraints + b) minmosetlc2() for two-sided sparse linear constraints; + minmosetlc2dense() for two-sided dense linear constraints; + minmosetlc2mixed() for two-sided mixed sparse/dense constraints + c) minmosetnlc2() for two-sided nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minmosetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +5. User sets stopping conditions with minmosetcond(). + +6. Finally, user calls minmooptimize() function which takes algorithm + state and pointers (delegate, etc.) to the callback functions which + calculate F/C + +7. User calls minmoresults() to get the solution + +8. Optionally user may call minmorestartfrom() to solve another problem + with same M,N but another starting point. minmorestartfrom() allows to + reuse an already initialized optimizer structure. + + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmocreate(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + MULTI-OBJECTIVE OPTIMIZATION + +DESCRIPTION: + +The solver minimizes an M-dimensional vector function F(x) of N arguments +subject to any combination of: +* box constraints +* two-sided linear equality/inequality constraints AL<=A*x<=AU, where some + of AL/AU can be infinite (i.e. missing) +* two-sided nonlinear equality/inequality constraints NL<=C(x)<=NU, where + some of NL/NU can be infinite (i.e. missing) + +REQUIREMENTS: +* F(), C() are continuously differentiable on the feasible set and on its + neighborhood + +USAGE: + +1. User initializes algorithm state using either: + * minmocreate() to perform optimization with user-supplied Jacobian + * minmocreatef() to perform optimization with numerical differentiation + +2. User chooses which multi-objective solver to use. At the present moment + only NBI (Normal Boundary Intersection) solver is implemented, which is + activated by calling minmosetalgonbi(). + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minmosetbc() for boundary constraints + b) minmosetlc2() for two-sided sparse linear constraints; + minmosetlc2dense() for two-sided dense linear constraints; + minmosetlc2mixed() for two-sided mixed sparse/dense constraints + c) minmosetnlc2() for two-sided nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minmosetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +5. User sets stopping conditions with minmosetcond(). + +6. Finally, user calls minmooptimize() function which takes algorithm + state and pointers (delegate, etc.) to the callback functions which + calculate F/C + +7. User calls minmoresults() to get the solution + +8. Optionally user may call minmorestartfrom() to solve another problem + with same M,N but another starting point. minmorestartfrom() allows to + reuse an already initialized optimizer structure. + + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minmocreate(const ae_int_t m, const real_1d_array &x, minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmocreate(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This subroutine is a finite difference variant of minmocreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on minmocreate() too. + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is a scaling vector which can be set by minmosetscale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step means too large TRUNCATION errors, whilst too small step + means too large NUMERICAL errors. + 1.0E-4 can be good value to start from for a unit-scaled problem. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmocreatef(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine is a finite difference variant of minmocreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on minmocreate() too. + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is a scaling vector which can be set by minmosetscale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step means too large TRUNCATION errors, whilst too small step + means too large NUMERICAL errors. + 1.0E-4 can be good value to start from for a unit-scaled problem. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minmocreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmocreatef(n, m, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Use the NBI (Normal Boundary Intersection) algorithm for multiobjective +optimization. + +NBI is a simple yet powerful multiobjective optimization algorithm that +has the following attractive properties: +* it generates nearly uniformly distributed Pareto points +* it is applicable to problems with more than 2 objectives +* it naturally supports a mix of box, linear and nonlinear constraints +* it is less sensitive to the bad scaling of the targets + +The only drawback of the algorithm is that for more than 2 objectives it +can miss some small parts of the Pareto front that are located near its +boundaries. + +INPUT PARAMETERS: + State - structure which stores algorithm state + FrontSize - desired Pareto front size, FrontSize>=M, + where M is an objectives count + PolishSolutions-whether additional solution improving phase is needed + or not: + * if False, the original NBI as formulated by Das and + Dennis is used. It quickly produces good solutions, + but these solutions can be suboptimal (usually within + 0.1% of the optimal values). + The reason is that the original NBI formulation does + not account for degeneracies that allow significant + progress for one objective with no deterioration for + other objectives. + * if True, the original NBI is followed by the + additional solution polishing phase. This solver + mode is several times slower than the original NBI, + but produces better solutions. + + -- ALGLIB -- + Copyright 20.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetalgonbi(minmostate &state, const ae_int_t frontsize, const bool polishsolutions, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetalgonbi(state.c_ptr(), frontsize, polishsolutions, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets boundary constraints for the MO optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinMORestartFrom(). + +You may combine boundary constraints with general linear ones - and with +nonlinear ones! Boundary constraints are handled more efficiently than +other types. Thus, if your problem has mixed constraints, you may +explicitly specify some of them as boundary and save some time/space. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetbc(minmostate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense may help some MO solvers + to utilize efficient dense Level 3 BLAS for dense parts of the + problem. If your problem has both dense and sparse constraints, you + can use minmosetlc2mixed() function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2dense(minmostate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense may help some MO solvers + to utilize efficient dense Level 3 BLAS for dense parts of the + problem. If your problem has both dense and sparse constraints, you + can use minmosetlc2mixed() function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minmosetlc2dense(minmostate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (a.rows()!=al.length()) || (a.rows()!=au.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minmosetlc2dense': looks like one of arguments has wrong size"); + k = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetlc2dense(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2(minmostate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetlc2(state.c_ptr(), a.c_ptr(), al.c_ptr(), au.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you can store them in the +sparse format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2mixed(minmostate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetlc2mixed(state.c_ptr(), sparsea.c_ptr(), ksparse, densea.c_ptr(), kdense, al.c_ptr(), au.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL<=A*x<=AU to dense +constraints list. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2dense(minmostate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmoaddlc2dense(state.c_ptr(), a.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of sparse constraints. + +Constraint is passed in the compressed format: as a list of non-zero +entries of the coefficient vector A. Such approach is more efficient than +the dense storage for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2(minmostate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmoaddlc2(state.c_ptr(), idxa.c_ptr(), vala.c_ptr(), nnz, al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2sparsefromdense(minmostate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmoaddlc2sparsefromdense(state.c_ptr(), da.c_ptr(), al, au, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinMO optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinMOOptimize() method as callbacks. + +MinMOOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first M components of F[] and first M rows of J[] correspond to + multiple objectives +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinMOSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinMOSetScale() function). + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetnlc2(minmostate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetnlc2(state.c_ptr(), nl.c_ptr(), nu.c_ptr(), nnlc, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping conditions for inner iterations of the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinMOSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to an automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetcond(minmostate &state, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetcond(state.c_ptr(), epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for the MO optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetscale(minmostate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting of the Pareto front points. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function (if it +was provided to MinMOOptimize) every time we find a Pareto front point. + +NOTE: according to the communication protocol used by ALGLIB, the solver + passes two parameters to the rep() callback - a current point and a + target value at the current point. + However, because we solve a multi-objective problem, the target + parameter is not used and set to zero. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetxrep(minmostate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmosetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minmoiteration(minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minmoiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minmooptimize(minmostate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minmooptimize()' (fvec is NULL)", &_alglib_env_state); + alglib_impl::minmosetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minmoiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfi ) + { + fvec(state.x, state.fi, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minmooptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + +void minmooptimize(minmostate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'minmooptimize()' (jac is NULL)", &_alglib_env_state); + alglib_impl::minmosetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minmoiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfij ) + { + jac(state.x, state.fi, state.j, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minmooptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +MinMO results: the solution found, completion codes and additional +information. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + ParetoFront-array[FrontSize,N+M], approximate Pareto front. + Its columns have the following structure: + * first N columns are variable values + * next M columns are objectives at these points + Its rows have the following structure: + * first M rows contain solutions to single-objective tasks + with I-th row storing result for I-th objective being + minimized ignoring other ones. + Thus, ParetoFront[I,N+I] for 0<=I=0. + * no larger than the number passed to setalgo() + * for a single-objective task, FrontSize=1 is ALWAYS + returned, no matter what was specified during setalgo() + call. + * if the solver was prematurely terminated with + minnorequesttermination(), an incomplete Pareto front + will be returned (it may even have less than M rows) + * if a failure (negative completion code) was signaled, + FrontSize=0 will be returned + + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 constraint bounds are infeasible, i.e. we have + box/linear/nonlinear constraint with two bounds + present, and a lower one being greater than the + upper one. + Note: less obvious infeasibilities of constraints + do NOT trigger emergency completion; you + have to examine rep.bcerr/rep.lcerr/rep.nlcerr + to detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 8 user requested algorithm termination via + minmorequesttermination(), last accepted point is + returned. + + More information about fields of this structure can be + found in the comments on minmoreport datatype. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmoresults(const minmostate &state, real_2d_array &paretofront, ae_int_t &frontsize, minmoreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmoresults(state.c_ptr(), paretofront.c_ptr(), &frontsize, rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for the termination of the running +optimizer. + +It should be called from the user-supplied callback when user decides that +it is time to "smoothly" terminate optimization process, or from some other +thread. As a result, optimizer stops at the state which was "current +accepted" when termination request was submitted and returns error code 8 +(successful termination). + +Usually it results in an incomplete Pareto front being returned. + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorequesttermination(minmostate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmorequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts algorithm from the new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorestartfrom(minmostate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minmorestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinMO subpackage to work with this +object +*************************************************************************/ +_minmostate_owner::_minmostate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minmostate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minmostate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minmostate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minmostate)); + alglib_impl::_minmostate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minmostate_owner::_minmostate_owner(alglib_impl::minmostate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minmostate_owner::_minmostate_owner(const _minmostate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minmostate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minmostate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minmostate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minmostate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minmostate)); + alglib_impl::_minmostate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minmostate_owner& _minmostate_owner::operator=(const _minmostate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minmostate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minmostate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minmostate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minmostate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minmostate)); + alglib_impl::_minmostate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minmostate_owner::~_minmostate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minmostate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minmostate* _minmostate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minmostate* _minmostate_owner::c_ptr() const +{ + return p_struct; +} +minmostate::minmostate() : _minmostate_owner() ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minmostate::minmostate(alglib_impl::minmostate *attach_to):_minmostate_owner(attach_to) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minmostate::minmostate(const minmostate &rhs):_minmostate_owner(rhs) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minmostate& minmostate::operator=(const minmostate &rhs) +{ + if( this==&rhs ) + return *this; + _minmostate_owner::operator=(rhs); + return *this; +} + +minmostate::~minmostate() +{ +} + + + + +/************************************************************************* +These fields store optimization report: +* inneriterationscount total number of inner iterations +* outeriterationscount number of internal optimization sessions performed +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +Scaled constraint violations (maximum over all Pareto points) are reported: +* bcerr maximum violation of the box constraints +* bcidx index of the most violated box constraint (or + -1, if all box constraints are satisfied or + there are no box constraint) +* lcerr maximum violation of the linear constraints, + computed as maximum scaled distance between + final point and constraint boundary. +* lcidx index of the most violated linear constraint + (or -1, if all constraints are satisfied or + there are no general linear constraints) +* nlcerr maximum violation of the nonlinear constraints +* nlcidx index of the most violated nonlinear constraint + (or -1, if all constraints are satisfied or + there are no nonlinear constraints) + +Violations of the box constraints are scaled on per-component basis +according to the scale vector s[] as specified by the minmosetscale(). +Violations of the general linear constraints are also computed using +user-supplied variable scaling. Violations of the nonlinear constraints +are computed "as is" + +TERMINATION CODES + +TerminationType field contains completion code, which can be either: + +=== FAILURE CODE === + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signaled. + -3 box constraints are infeasible. Note: infeasibility of non-box + constraints does NOT trigger emergency completion; you have to + examine bcerr/lcerr/nlcerr to detect possibly inconsistent + constraints. + +=== SUCCESS CODE === + 2 relative step is no more than EpsX. + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +NOTE: The solver internally performs many optimization sessions: one for + each Pareto point, and some amount of preparatory optimizations. + Different optimization sessions may return different completion + codes. If at least one of internal optimizations failed, its failure + code is returned. If none of them failed, the most frequent code is + returned. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +_minmoreport_owner::_minmoreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minmoreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minmoreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minmoreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minmoreport)); + alglib_impl::_minmoreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minmoreport_owner::_minmoreport_owner(alglib_impl::minmoreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minmoreport_owner::_minmoreport_owner(const _minmoreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minmoreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minmoreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minmoreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minmoreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minmoreport)); + alglib_impl::_minmoreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minmoreport_owner& _minmoreport_owner::operator=(const _minmoreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minmoreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minmoreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minmoreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minmoreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minmoreport)); + alglib_impl::_minmoreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minmoreport_owner::~_minmoreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minmoreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minmoreport* _minmoreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minmoreport* _minmoreport_owner::c_ptr() const +{ + return p_struct; +} +minmoreport::minmoreport() : _minmoreport_owner() ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx) +{ +} + +minmoreport::minmoreport(alglib_impl::minmoreport *attach_to):_minmoreport_owner(attach_to) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx) +{ +} + +minmoreport::minmoreport(const minmoreport &rhs):_minmoreport_owner(rhs) ,inneriterationscount(p_struct->inneriterationscount),outeriterationscount(p_struct->outeriterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),bcerr(p_struct->bcerr),bcidx(p_struct->bcidx),lcerr(p_struct->lcerr),lcidx(p_struct->lcidx),nlcerr(p_struct->nlcerr),nlcidx(p_struct->nlcidx) +{ +} + +minmoreport& minmoreport::operator=(const minmoreport &rhs) +{ + if( this==&rhs ) + return *this; + _minmoreport_owner::operator=(rhs); + return *this; +} + +minmoreport::~minmoreport() +{ +} +#endif + +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONSMOOTH NONCONVEX OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS + +DESCRIPTION: + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear equality constraints Gi(x)=0 +* nonlinear inequality constraints Hi(x)<=0 + +IMPORTANT: see MinNSSetAlgoAGS for important information on performance + restrictions of AGS solver. + +REQUIREMENTS: +* starting point X0 must be feasible or not too far away from the feasible + set +* F(), G(), H() are continuous, locally Lipschitz and continuously (but + not necessarily twice) differentiable in an open dense subset of R^N. + Functions F(), G() and H() may be nonsmooth and non-convex. + Informally speaking, it means that functions are composed of large + differentiable "patches" with nonsmoothness having place only at the + boundaries between these "patches". + Most real-life nonsmooth functions satisfy these requirements. Say, + anything which involves finite number of abs(), min() and max() is very + likely to pass the test. + Say, it is possible to optimize anything of the following: + * f=abs(x0)+2*abs(x1) + * f=max(x0,x1) + * f=sin(max(x0,x1)+abs(x2)) +* for nonlinearly constrained problems: F() must be bounded from below + without nonlinear constraints (this requirement is due to the fact that, + contrary to box and linear constraints, nonlinear ones require special + handling). +* user must provide function value and gradient for F(), H(), G() at all + points where function/gradient can be calculated. If optimizer requires + value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), + where gradient is not defined, user may resolve tie arbitrarily (in our + case - return +1 or -1 at its discretion). +* NS solver supports numerical differentiation, i.e. it may differentiate + your function for you, but it results in 2N increase of function + evaluations. Not recommended unless you solve really small problems. See + minnscreatef() for more information on this functionality. + +USAGE: + +1. User initializes algorithm state with MinNSCreate() call and chooses + what NLC solver to use. There is some solver which is used by default, + with default settings, but you should NOT rely on default choice. It + may change in future releases of ALGLIB without notice, and no one can + guarantee that new solver will be able to solve your problem with + default settings. + + From the other side, if you choose solver explicitly, you can be pretty + sure that it will work with new ALGLIB releases. + + In the current release following solvers can be used: + * AGS solver (activated with MinNSSetAlgoAGS() function) + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) MinNSSetBC() for boundary constraints + b) MinNSSetLC() for linear constraints + c) MinNSSetNLC() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with MinNSSetScale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +4. User sets stopping conditions with MinNSSetCond(). + +5. Finally, user calls MinNSOptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F/G/H. + +7. User calls MinNSResults() to get solution + +8. Optionally user may call MinNSRestartFrom() to solve another problem + with same N but another starting point. MinNSRestartFrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTE: minnscreatef() function may be used if you do not have analytic + gradient. This function creates solver which uses numerical + differentiation with user-specified step. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreate(const ae_int_t n, const real_1d_array &x, minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnscreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + NONSMOOTH NONCONVEX OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS + +DESCRIPTION: + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear equality constraints Gi(x)=0 +* nonlinear inequality constraints Hi(x)<=0 + +IMPORTANT: see MinNSSetAlgoAGS for important information on performance + restrictions of AGS solver. + +REQUIREMENTS: +* starting point X0 must be feasible or not too far away from the feasible + set +* F(), G(), H() are continuous, locally Lipschitz and continuously (but + not necessarily twice) differentiable in an open dense subset of R^N. + Functions F(), G() and H() may be nonsmooth and non-convex. + Informally speaking, it means that functions are composed of large + differentiable "patches" with nonsmoothness having place only at the + boundaries between these "patches". + Most real-life nonsmooth functions satisfy these requirements. Say, + anything which involves finite number of abs(), min() and max() is very + likely to pass the test. + Say, it is possible to optimize anything of the following: + * f=abs(x0)+2*abs(x1) + * f=max(x0,x1) + * f=sin(max(x0,x1)+abs(x2)) +* for nonlinearly constrained problems: F() must be bounded from below + without nonlinear constraints (this requirement is due to the fact that, + contrary to box and linear constraints, nonlinear ones require special + handling). +* user must provide function value and gradient for F(), H(), G() at all + points where function/gradient can be calculated. If optimizer requires + value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), + where gradient is not defined, user may resolve tie arbitrarily (in our + case - return +1 or -1 at its discretion). +* NS solver supports numerical differentiation, i.e. it may differentiate + your function for you, but it results in 2N increase of function + evaluations. Not recommended unless you solve really small problems. See + minnscreatef() for more information on this functionality. + +USAGE: + +1. User initializes algorithm state with MinNSCreate() call and chooses + what NLC solver to use. There is some solver which is used by default, + with default settings, but you should NOT rely on default choice. It + may change in future releases of ALGLIB without notice, and no one can + guarantee that new solver will be able to solve your problem with + default settings. + + From the other side, if you choose solver explicitly, you can be pretty + sure that it will work with new ALGLIB releases. + + In the current release following solvers can be used: + * AGS solver (activated with MinNSSetAlgoAGS() function) + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) MinNSSetBC() for boundary constraints + b) MinNSSetLC() for linear constraints + c) MinNSSetNLC() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with MinNSSetScale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +4. User sets stopping conditions with MinNSSetCond(). + +5. Finally, user calls MinNSOptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F/G/H. + +7. User calls MinNSResults() to get solution + +8. Optionally user may call MinNSRestartFrom() to solve another problem + with same N but another starting point. MinNSRestartFrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTE: minnscreatef() function may be used if you do not have analytic + gradient. This function creates solver which uses numerical + differentiation with user-specified step. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnscreate(const real_1d_array &x, minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnscreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Version of minnscreatef() which uses numerical differentiation. I.e., you +do not have to calculate derivatives yourself. However, this version needs +2N times more function evaluations. + +2-point differentiation formula is used, because more precise 4-point +formula is unstable when used on non-smooth functions. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, DiffStep>0. Algorithm performs + numerical differentiation with step for I-th variable + being equal to DiffStep*S[I] (here S[] is a scale vector, + set by minnssetscale() function). + Do not use too small steps, because it may lead to + catastrophic cancellation during intermediate calculations. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnscreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Version of minnscreatef() which uses numerical differentiation. I.e., you +do not have to calculate derivatives yourself. However, this version needs +2N times more function evaluations. + +2-point differentiation formula is used, because more precise 4-point +formula is unstable when used on non-smooth functions. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, DiffStep>0. Algorithm performs + numerical differentiation with step for I-th variable + being equal to DiffStep*S[I] (here S[] is a scale vector, + set by minnssetscale() function). + Do not use too small steps, because it may lead to + catastrophic cancellation during intermediate calculations. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnscreatef(const real_1d_array &x, const double diffstep, minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnscreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets boundary constraints. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: AGS solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetbc(minnsstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE: linear (non-bound) constraints are satisfied only approximately: + +* there always exists some minor violation (about current sampling radius + in magnitude during optimization, about EpsX in the solution) due to use + of penalty method to handle constraints. +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. + +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetlc(minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets linear constraints. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE: linear (non-bound) constraints are satisfied only approximately: + +* there always exists some minor violation (about current sampling radius + in magnitude during optimization, about EpsX in the solution) due to use + of penalty method to handle constraints. +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. + +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minnssetlc(minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t k; + if( (c.rows()!=ct.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minnssetlc': looks like one of arguments has wrong size"); + k = c.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetlc(state.c_ptr(), c.c_ptr(), ct.c_ptr(), k, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets nonlinear constraints. + +In fact, this function sets NUMBER of nonlinear constraints. Constraints +itself (constraint functions) are passed to minnsoptimize() method. This +method requires user-defined vector function F[] and its Jacobian J[], +where: +* first component of F[] and first row of Jacobian J[] correspond to + function being minimized +* next NLEC components of F[] (and rows of J) correspond to nonlinear + equality constraints G_i(x)=0 +* next NLIC components of F[] (and rows of J) correspond to nonlinear + inequality constraints H_i(x)<=0 + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear ones. It may help optimizer to handle them more + efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 + NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to scale specified by + minnssetscale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for correct + scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you + to scale nonlinear constraints in such way that I-th component of + dG/dX (or dH/dx) has approximately unit magnitude (for problems + with unit scale) or has magnitude approximately equal to 1/S[i] + (where S is a scale set by minnssetscale() function). + +NOTE 3: nonlinear constraints are always hard to handle, no matter what + algorithm you try to use. Even basic box/linear constraints modify + function curvature by adding valleys and ridges. However, + nonlinear constraints add valleys which are very hard to follow + due to their "curved" nature. + + It means that optimization with single nonlinear constraint may be + significantly slower than optimization with multiple linear ones. + It is normal situation, and we recommend you to carefully choose + Rho parameter of minnssetalgoags(), because too large value may + slow down convergence. + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetnlc(minnsstate &state, const ae_int_t nlec, const ae_int_t nlic, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetnlc(state.c_ptr(), nlec, nlic, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping conditions for iterations of optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The AGS solver finishes its work if on k+1-th iteration + sampling radius decreases below EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection. We do not recommend you to rely on default +choice in production code. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetcond(minnsstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetcond(state.c_ptr(), epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetscale(minnsstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function tells MinNS unit to use AGS (adaptive gradient sampling) +algorithm for nonsmooth constrained optimization. This algorithm is a +slight modification of one described in "An Adaptive Gradient Sampling +Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. + +This optimizer has following benefits and drawbacks: ++ robustness; it can be used with nonsmooth and nonconvex functions. ++ relatively easy tuning; most of the metaparameters are easy to select. +- it has convergence of steepest descent, slower than CG/LBFGS. +- each iteration involves evaluation of ~2N gradient values and solution + of 2Nx2N quadratic programming problem, which limits applicability of + algorithm by small-scale problems (up to 50-100). + +IMPORTANT: this algorithm has convergence guarantees, i.e. it will + steadily move towards some stationary point of the function. + + However, "stationary point" does not always mean "solution". + Nonsmooth problems often have "flat spots", i.e. areas where + function do not change at all. Such "flat spots" are stationary + points by definition, and algorithm may be caught here. + + Nonsmooth CONVEX tasks are not prone to this problem. Say, if + your function has form f()=MAX(f0,f1,...), and f_i are convex, + then f() is convex too and you have guaranteed convergence to + solution. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Radius - initial sampling radius, >=0. + + Internally multiplied by vector of per-variable scales + specified by minnssetscale()). + + You should select relatively large sampling radius, roughly + proportional to scaled length of the first steps of the + algorithm. Something close to 0.1 in magnitude should be + good for most problems. + + AGS solver can automatically decrease radius, so too large + radius is not a problem (assuming that you won't choose + so large radius that algorithm will sample function in + too far away points, where gradient value is irrelevant). + + Too small radius won't cause algorithm to fail, but it may + slow down algorithm (it may have to perform too short + steps). + Penalty - penalty coefficient for nonlinear constraints: + * for problem with nonlinear constraints should be some + problem-specific positive value, large enough that + penalty term changes shape of the function. + Starting from some problem-specific value penalty + coefficient becomes large enough to exactly enforce + nonlinear constraints; larger values do not improve + precision. + Increasing it too much may slow down convergence, so you + should choose it carefully. + * can be zero for problems WITHOUT nonlinear constraints + (i.e. for unconstrained ones or ones with just box or + linear constraints) + * if you specify zero value for problem with at least one + nonlinear constraint, algorithm will terminate with + error code -1. + +ALGORITHM OUTLINE + +The very basic outline of unconstrained AGS algorithm is given below: + +0. If sampling radius is below EpsX or we performed more then MaxIts + iterations - STOP. +1. sample O(N) gradient values at random locations around current point; + informally speaking, this sample is an implicit piecewise linear model + of the function, although algorithm formulation does not mention that + explicitly +2. solve quadratic programming problem in order to find descent direction +3. if QP solver tells us that we are near solution, decrease sampling + radius and move to (0) +4. perform backtracking line search +5. after moving to new point, goto (0) + +Constraint handling details: +* box constraints are handled exactly by algorithm +* linear/nonlinear constraints are handled by adding L1 penalty. Because + our solver can handle nonsmoothness, we can use L1 penalty function, + which is an exact one (i.e. exact solution is returned under such + penalty). +* penalty coefficient for linear constraints is chosen automatically; + however, penalty coefficient for nonlinear constraints must be specified + by user. + +===== TRACING AGS SOLVER ================================================= + +AGS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'AGS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'AGS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'AGS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'AGS.DETAILED.SAMPLE'- + for output of points being visited , search directions + and gradient sample. May take a LOT of space , do not + use it on problems with more that several tens of vars. + This symbol also implicitly defines 'AGS' and + 'AGS.DETAILED'. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("AGS,PREC.F6", "path/to/trace.log") +> + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetalgoags(minnsstate &state, const double radius, const double penalty, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetalgoags(state.c_ptr(), radius, penalty, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to minnsoptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnssetxrep(minnsstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnssetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrequesttermination(minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnsrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minnsiteration(minnsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minnsiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minnsoptimize(minnsstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(fvec!=NULL, "ALGLIB: error in 'minnsoptimize()' (fvec is NULL)", &_alglib_env_state); + alglib_impl::minnssetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minnsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfi ) + { + fvec(state.x, state.fi, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minnsoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + +void minnsoptimize(minnsstate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'minnsoptimize()' (jac is NULL)", &_alglib_env_state); + alglib_impl::minnssetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minnsiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfij ) + { + jac(state.x, state.fi, state.j, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minnsoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +MinNS results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 box constraints are inconsistent + * -1 inconsistent parameters were passed: + * penalty parameter for minnssetalgoags() is zero, + but we have nonlinear constraints set by minnssetnlc() + * 2 sampling radius decreased below epsx + * 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + * 8 User requested termination via minnsrequesttermination() + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresults(const minnsstate &state, real_1d_array &x, minnsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnsresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + +Buffered implementation of minnsresults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresultsbuf(const minnsstate &state, real_1d_array &x, minnsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnsresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + X - new starting point. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrestartfrom(minnsstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minnsrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinNS subpackage to work with this +object +*************************************************************************/ +_minnsstate_owner::_minnsstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnsstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minnsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnsstate)); + alglib_impl::_minnsstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnsstate_owner::_minnsstate_owner(alglib_impl::minnsstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minnsstate_owner::_minnsstate_owner(const _minnsstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnsstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnsstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minnsstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnsstate)); + alglib_impl::_minnsstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnsstate_owner& _minnsstate_owner::operator=(const _minnsstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minnsstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnsstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minnsstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minnsstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minnsstate)); + alglib_impl::_minnsstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minnsstate_owner::~_minnsstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minnsstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minnsstate* _minnsstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minnsstate* _minnsstate_owner::c_ptr() const +{ + return p_struct; +} +minnsstate::minnsstate() : _minnsstate_owner() ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minnsstate::minnsstate(alglib_impl::minnsstate *attach_to):_minnsstate_owner(attach_to) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minnsstate::minnsstate(const minnsstate &rhs):_minnsstate_owner(rhs) ,needfi(p_struct->needfi),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +minnsstate& minnsstate::operator=(const minnsstate &rhs) +{ + if( this==&rhs ) + return *this; + _minnsstate_owner::operator=(rhs); + return *this; +} + +minnsstate::~minnsstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) +* CErr maximum violation of all types of constraints +* LCErr maximum violation of linear constraints +* NLCErr maximum violation of nonlinear constraints + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 box constraints are inconsistent + -1 inconsistent parameters were passed: + * penalty parameter for minnssetalgoags() is zero, + but we have nonlinear constraints set by minnssetnlc() + 2 sampling radius decreased below epsx + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 User requested termination via MinNSRequestTermination() + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +_minnsreport_owner::_minnsreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minnsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnsreport)); + alglib_impl::_minnsreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnsreport_owner::_minnsreport_owner(alglib_impl::minnsreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minnsreport_owner::_minnsreport_owner(const _minnsreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minnsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnsreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minnsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minnsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minnsreport)); + alglib_impl::_minnsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minnsreport_owner& _minnsreport_owner::operator=(const _minnsreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minnsreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minnsreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minnsreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minnsreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minnsreport)); + alglib_impl::_minnsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minnsreport_owner::~_minnsreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minnsreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minnsreport* _minnsreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minnsreport* _minnsreport_owner::c_ptr() const +{ + return p_struct; +} +minnsreport::minnsreport() : _minnsreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),cerr(p_struct->cerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),varidx(p_struct->varidx),funcidx(p_struct->funcidx) +{ +} + +minnsreport::minnsreport(alglib_impl::minnsreport *attach_to):_minnsreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),cerr(p_struct->cerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),varidx(p_struct->varidx),funcidx(p_struct->funcidx) +{ +} + +minnsreport::minnsreport(const minnsreport &rhs):_minnsreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),cerr(p_struct->cerr),lcerr(p_struct->lcerr),nlcerr(p_struct->nlcerr),terminationtype(p_struct->terminationtype),varidx(p_struct->varidx),funcidx(p_struct->funcidx) +{ +} + +minnsreport& minnsreport::operator=(const minnsreport &rhs) +{ + if( this==&rhs ) + return *this; + _minnsreport_owner::operator=(rhs); + return *this; +} + +minnsreport::~minnsreport() +{ +} +#endif + +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Obsolete function, use MinLBFGSSetPrecDefault() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetdefaultpreconditioner(minlbfgsstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetdefaultpreconditioner(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcholeskypreconditioner(minlbfgsstate &state, const real_2d_array &p, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minlbfgssetcholeskypreconditioner(state.c_ptr(), p.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierwidth(minbleicstate &state, const double mu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetbarrierwidth(state.c_ptr(), mu, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierdecay(minbleicstate &state, const double mudecay, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbleicsetbarrierdecay(state.c_ptr(), mudecay, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasacreate(n, x.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=bndl.length()) || (x.length()!=bndu.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'minasacreate': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasacreate(n, x.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetcond(minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasasetcond(state.c_ptr(), epsg, epsf, epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetxrep(minasastate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasasetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetalgorithm(minasastate &state, const ae_int_t algotype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasasetalgorithm(state.c_ptr(), algotype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetstpmax(minasastate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasasetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minasaiteration(minasastate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minasaoptimize(minasastate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'minasaoptimize()' (grad is NULL)", &_alglib_env_state); + alglib_impl::minasasetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minasaiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfg ) + { + grad(state.x, state.f, state.g, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minasaoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasaresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasaresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minasarestartfrom(minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minasarestartfrom(state.c_ptr(), x.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* + +*************************************************************************/ +_minasastate_owner::_minasastate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minasastate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minasastate)); + alglib_impl::_minasastate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minasastate_owner::_minasastate_owner(alglib_impl::minasastate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minasastate_owner::_minasastate_owner(const _minasastate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minasastate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minasastate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minasastate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasastate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minasastate)); + alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minasastate_owner& _minasastate_owner::operator=(const _minasastate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minasastate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minasastate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minasastate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minasastate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minasastate)); + alglib_impl::_minasastate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minasastate_owner::~_minasastate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minasastate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minasastate* _minasastate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minasastate* _minasastate_owner::c_ptr() const +{ + return p_struct; +} +minasastate::minasastate() : _minasastate_owner() ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minasastate::minasastate(alglib_impl::minasastate *attach_to):_minasastate_owner(attach_to) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minasastate::minasastate(const minasastate &rhs):_minasastate_owner(rhs) ,needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minasastate& minasastate::operator=(const minasastate &rhs) +{ + if( this==&rhs ) + return *this; + _minasastate_owner::operator=(rhs); + return *this; +} + +minasastate::~minasastate() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_minasareport_owner::_minasareport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minasareport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minasareport)); + alglib_impl::_minasareport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minasareport_owner::_minasareport_owner(alglib_impl::minasareport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minasareport_owner::_minasareport_owner(const _minasareport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minasareport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minasareport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minasareport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minasareport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minasareport)); + alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minasareport_owner& _minasareport_owner::operator=(const _minasareport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minasareport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minasareport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minasareport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minasareport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minasareport)); + alglib_impl::_minasareport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minasareport_owner::~_minasareport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minasareport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minasareport* _minasareport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minasareport* _minasareport_owner::c_ptr() const +{ + return p_struct; +} +minasareport::minasareport() : _minasareport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) +{ +} + +minasareport::minasareport(alglib_impl::minasareport *attach_to):_minasareport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) +{ +} + +minasareport::minasareport(const minasareport &rhs):_minasareport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),terminationtype(p_struct->terminationtype),activeconstraints(p_struct->activeconstraints) +{ +} + +minasareport& minasareport::operator=(const minasareport &rhs) +{ + if( this==&rhs ) + return *this; + _minasareport_owner::operator=(rhs); + return *this; +} + +minasareport::~minasareport() +{ +} +#endif + +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + BOX CONSTRAINED OPTIMIZATION + WITH FAST ACTIVATION OF MULTIPLE BOX CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to box +constraints (with some of box constraints actually being equality ones). + +This optimizer uses algorithm similar to that of MinBLEIC (optimizer with +general linear constraints), but presence of box-only constraints allows +us to use faster constraint activation strategies. On large-scale problems, +with multiple constraints active at the solution, this optimizer can be +several times faster than BLEIC. + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBCCreate() call + +2. USer adds box constraints by calling MinBCSetBC() function. + +3. User sets stopping conditions with MinBCSetCond(). + +4. User calls MinBCOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBCResults() to get solution + +6. Optionally user may call MinBCRestartFrom() to solve another problem + with same N but another starting point. + MinBCRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbccreate(const ae_int_t n, const real_1d_array &x, minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + BOX CONSTRAINED OPTIMIZATION + WITH FAST ACTIVATION OF MULTIPLE BOX CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to box +constraints (with some of box constraints actually being equality ones). + +This optimizer uses algorithm similar to that of MinBLEIC (optimizer with +general linear constraints), but presence of box-only constraints allows +us to use faster constraint activation strategies. On large-scale problems, +with multiple constraints active at the solution, this optimizer can be +several times faster than BLEIC. + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBCCreate() call + +2. USer adds box constraints by calling MinBCSetBC() function. + +3. User sets stopping conditions with MinBCSetCond(). + +4. User calls MinBCOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBCResults() to get solution + +6. Optionally user may call MinBCRestartFrom() to solve another problem + with same N but another starting point. + MinBCRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbccreate(const real_1d_array &x, minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbccreate(n, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +The subroutine is finite difference variant of MinBCCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBCCreate() in order to get +more information about creation of BC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBCSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +The subroutine is finite difference variant of MinBCCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBCCreate() in order to get +more information about creation of BC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBCSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbccreatef(const real_1d_array &x, const double diffstep, minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbccreatef(n, x.c_ptr(), diffstep, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets boundary constraints for BC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBCRestartFrom(). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetbc(minbcstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetbc(state.c_ptr(), bndl.c_ptr(), bndu.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBCSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetcond(minbcstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetcond(state.c_ptr(), epsg, epsf, epsx, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets scaling coefficients for BC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBCSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbcsetscale(minbcstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdefault(minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetprecdefault(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdiag(minbcstate &state, const real_1d_array &d, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetprecdiag(state.c_ptr(), d.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBCSetScale() +call (before or after MinBCSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecscale(minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetprecscale(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBCOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetxrep(minbcstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetstpmax(minbcstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minbciteration(minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::minbciteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void minbcoptimize(minbcstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'minbcoptimize()' (func is NULL)", &_alglib_env_state); + alglib_impl::minbcsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minbciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needf ) + { + func(state.x, state.f, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minbcoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + +void minbcoptimize(minbcstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'minbcoptimize()' (grad is NULL)", &_alglib_env_state); + alglib_impl::minbcsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::minbciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needfg ) + { + grad(state.x, state.f, state.g, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'minbcoptimize' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbcoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardgradient(minbcstate &state, const double teststep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardgradient(state.c_ptr(), teststep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardsmoothness(minbcstate &state, const ae_int_t level, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void minbcoptguardsmoothness(minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t level; + + level = 1; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardsmoothness(state.c_ptr(), level, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbcoptguardgradient() for gradient verification +* minbcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbcoptguardnonc1test0results() +* minbcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardresults(minbcstate &state, optguardreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardresults(state.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test0results(const minbcstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardnonc1test0results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test1results(minbcstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcoptguardnonc1test1results(state.c_ptr(), strrep.c_ptr(), lngrep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +BC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbcrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBCReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresults(const minbcstate &state, real_1d_array &x, minbcreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +BC results + +Buffered implementation of MinBCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresultsbuf(const minbcstate &state, real_1d_array &x, minbcreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcrestartfrom(minbcstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcrequesttermination(minbcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::minbcrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinBC subpackage to work with this +object +*************************************************************************/ +_minbcstate_owner::_minbcstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbcstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minbcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbcstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbcstate)); + alglib_impl::_minbcstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbcstate_owner::_minbcstate_owner(alglib_impl::minbcstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minbcstate_owner::_minbcstate_owner(const _minbcstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbcstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbcstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minbcstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbcstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbcstate)); + alglib_impl::_minbcstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbcstate_owner& _minbcstate_owner::operator=(const _minbcstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minbcstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbcstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minbcstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minbcstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minbcstate)); + alglib_impl::_minbcstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minbcstate_owner::~_minbcstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minbcstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minbcstate* _minbcstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minbcstate* _minbcstate_owner::c_ptr() const +{ + return p_struct; +} +minbcstate::minbcstate() : _minbcstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbcstate::minbcstate(alglib_impl::minbcstate *attach_to):_minbcstate_owner(attach_to) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbcstate::minbcstate(const minbcstate &rhs):_minbcstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),xupdated(p_struct->xupdated),f(p_struct->f),g(&p_struct->g),x(&p_struct->x) +{ +} + +minbcstate& minbcstate::operator=(const minbcstate &rhs) +{ + if( this==&rhs ) + return *this; + _minbcstate_owner::operator=(rhs); + return *this; +} + +minbcstate::~minbcstate() +{ +} + + + + +/************************************************************************* +This structure stores optimization report: +* iterationscount number of iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +TERMINATION CODES + +terminationtype field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 inconsistent constraints. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minbcrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. +*************************************************************************/ +_minbcreport_owner::_minbcreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::minbcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbcreport)); + alglib_impl::_minbcreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbcreport_owner::_minbcreport_owner(alglib_impl::minbcreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_minbcreport_owner::_minbcreport_owner(const _minbcreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_minbcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbcreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::minbcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::minbcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::minbcreport)); + alglib_impl::_minbcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_minbcreport_owner& _minbcreport_owner::operator=(const _minbcreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: minbcreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: minbcreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: minbcreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_minbcreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::minbcreport)); + alglib_impl::_minbcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_minbcreport_owner::~_minbcreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_minbcreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::minbcreport* _minbcreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::minbcreport* _minbcreport_owner::c_ptr() const +{ + return p_struct; +} +minbcreport::minbcreport() : _minbcreport_owner() ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) +{ +} + +minbcreport::minbcreport(alglib_impl::minbcreport *attach_to):_minbcreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) +{ +} + +minbcreport::minbcreport(const minbcreport &rhs):_minbcreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfev(p_struct->nfev),varidx(p_struct->varidx),terminationtype(p_struct->terminationtype) +{ +} + +minbcreport& minbcreport::operator=(const minbcreport &rhs) +{ + if( this==&rhs ) + return *this; + _minbcreport_owner::operator=(rhs); + return *this; +} + +minbcreport::~minbcreport() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) +static double optserv_ognoiselevelf = 1.0E2*ae_machineepsilon; +static double optserv_ognoiselevelg = 1.0E4*ae_machineepsilon; +static double optserv_ogminrating0 = 50.0; +static double optserv_ogminrating1 = 50.0; +static double optserv_xbfgssigma2 = 0.2; +static double optserv_xbfgssigma3 = 5; +static double optserv_feasibilityerror(/* Real */ const ae_matrix* ce, + /* Real */ const ae_vector* x, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t k, + /* Real */ ae_vector* tmp0, + ae_state *_state); +static void optserv_feasibilityerrorgrad(/* Real */ const ae_matrix* ce, + /* Real */ const ae_vector* x, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t k, + double* err, + /* Real */ ae_vector* grad, + /* Real */ ae_vector* tmp0, + ae_state *_state); +static void optserv_testc0continuity(double f0, + double f1, + double f2, + double f3, + double noise0, + double noise1, + double noise2, + double noise3, + double delta0, + double delta1, + double delta2, + ae_bool applyspecialcorrection, + double* rating, + double* lipschitz, + ae_state *_state); +static void optserv_c1continuitytest0(smoothnessmonitor* monitor, + ae_int_t funcidx, + ae_int_t stpidx, + ae_int_t sortedcnt, + ae_state *_state); +static void optserv_c1continuitytest1(smoothnessmonitor* monitor, + ae_int_t funcidx, + ae_int_t stpidx, + ae_int_t sortedcnt, + ae_state *_state); +static void optserv_popfrontxy(xbfgshessian* hess, ae_state *_state); +static void optserv_hessianupdatelowlevel(xbfgshessian* hess, + /* Real */ ae_matrix* h, + /* Real */ const ae_vector* sk, + /* Real */ const ae_vector* yk, + ae_int_t* status, + ae_state *_state); +static void optserv_hessianupdatelowlevel2(xbfgshessian* hess, + /* Real */ ae_matrix* h, + /* Real */ const ae_vector* sk, + /* Real */ const ae_vector* yk, + ae_int_t* status, + ae_state *_state); +static void optserv_resetlowrankmodel(xbfgshessian* hess, + ae_state *_state); +static void optserv_recomputelowrankmodel(xbfgshessian* hess, + ae_state *_state); +static void optserv_recomputelowrankmodellbfgs(xbfgshessian* hess, + ae_state *_state); +static void optserv_recomputelowrankmodelsr1(xbfgshessian* hess, + ae_state *_state); +static void optserv_scaleandperformfinitenessassurance(xbfgshessian* hess, + /* Real */ ae_matrix* s, + /* Real */ ae_matrix* y, + double* sigma, + /* Real */ ae_matrix* l, + /* Real */ ae_vector* d, + ae_int_t* filteredlen, + ae_state *_state); +static void optserv_recomputelowrankdiagonal(xbfgshessian* hess, + ae_state *_state); +static void optserv_recomputelowrankdiagonalbfgs(xbfgshessian* hess, + ae_state *_state); +static void optserv_recomputelowrankdiagonalsr1(xbfgshessian* hess, + ae_state *_state); +static ae_bool optserv_unscalexbatchfinitebndkernel(/* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Real */ const ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* sclfinitebndl, + /* Real */ const ae_vector* sclfinitebndu, + /* Real */ const ae_vector* rawfinitebndl, + /* Real */ const ae_vector* rawfinitebndu, + /* Real */ ae_vector* xu, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +static double minlbfgs_gtol = 0.4; +static void minlbfgs_clearrequestfields(minlbfgsstate* state, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) +static ae_int_t cqmodels_newtonrefinementits = 3; +static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, + ae_state *_state); +static void cqmodels_cqmsolveea(convexquadraticmodel* s, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmp, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) +static void snnls_funcgradu(const snnlssolver* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + /* Real */ ae_vector* g, + double* f, + ae_state *_state); +static void snnls_func(const snnlssolver* s, + /* Real */ const ae_vector* x, + double* f, + ae_state *_state); +static void snnls_trdprepare(snnlssolver* s, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* diag, + double lambdav, + /* Real */ ae_vector* trdd, + /* Real */ ae_matrix* trda, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + /* Real */ ae_vector* tmp2, + /* Real */ ae_matrix* tmplq, + ae_state *_state); +static void snnls_trdsolve(/* Real */ const ae_vector* trdd, + /* Real */ const ae_matrix* trda, + ae_int_t ns, + ae_int_t nd, + /* Real */ ae_vector* d, + ae_state *_state); +static void snnls_trdfixvariable(/* Real */ ae_vector* trdd, + /* Real */ ae_matrix* trda, + ae_int_t ns, + ae_int_t nd, + ae_int_t idx, + /* Real */ ae_vector* tmp, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) +static ae_int_t sactivesets_maxbasisage = 5; +static double sactivesets_maxbasisdecay = 0.01; +static double sactivesets_minnormseparation = 0.25; +static void sactivesets_constraineddescent(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ const ae_vector* h, + /* Real */ const ae_matrix* ha, + ae_bool normalize, + /* Real */ ae_vector* d, + ae_state *_state); +static void sactivesets_reactivateconstraints(sactiveset* state, + /* Real */ const ae_vector* gc, + /* Real */ const ae_vector* h, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) +static ae_int_t qqpsolver_quickqprestartcg = 50; +static double qqpsolver_regz = 1.0E-9; +static double qqpsolver_projectedtargetfunction(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double stp, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + ae_state *_state); +static void qqpsolver_targetgradient(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + ae_state *_state); +static void qqpsolver_quadraticmodel(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* g, + double* d1, + ae_int_t* d1est, + double* d2, + ae_int_t* d2est, + /* Real */ ae_vector* tmp0, + ae_state *_state); +static void qqpsolver_findbeststepandmove(const qqpbuffers* sstate, + sactiveset* sas, + /* Real */ const ae_vector* d, + double stp, + ae_bool needact, + ae_int_t cidx, + double cval, + /* Real */ const ae_vector* addsteps, + ae_int_t addstepscnt, + /* Boolean */ ae_vector* activated, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + ae_state *_state); +static ae_bool qqpsolver_cnewtonbuild(qqpbuffers* sstate, + ae_int_t sparsesolver, + ae_int_t* ncholesky, + ae_state *_state); +static ae_bool qqpsolver_cnewtonupdate(qqpbuffers* sstate, + const qqpsettings* settings, + ae_int_t* ncupdates, + ae_state *_state); +static ae_bool qqpsolver_cnewtonstep(qqpbuffers* sstate, + const qqpsettings* settings, + /* Real */ ae_vector* gc, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) +static double qpdenseaulsolver_evictionlevel = -0.01; +static double qpdenseaulsolver_expansionratio = 0.20; +static void qpdenseaulsolver_generateexmodel(/* Real */ const ae_matrix* sclsfta, + /* Real */ const ae_vector* sclsftb, + ae_int_t nmain, + /* Real */ const ae_vector* sclsftbndl, + /* Boolean */ const ae_vector* sclsfthasbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* sclsfthasbndu, + /* Real */ const ae_matrix* sclsftcleic, + ae_int_t sclsftnec, + ae_int_t sclsftnic, + /* Real */ const ae_vector* nulc, + double rho, + /* Real */ ae_matrix* exa, + /* Real */ ae_vector* exb, + /* Real */ ae_vector* exbndl, + /* Real */ ae_vector* exbndu, + /* Real */ ae_matrix* tmp2, + ae_state *_state); +static void qpdenseaulsolver_generateexinitialpoint(/* Real */ const ae_vector* sclsftxc, + ae_int_t nmain, + ae_int_t nslack, + /* Real */ ae_vector* exxc, + ae_state *_state); +static void qpdenseaulsolver_updatelagrangemultipliers(/* Real */ const ae_matrix* sclsfta, + /* Real */ const ae_vector* sclsftb, + ae_int_t nmain, + /* Real */ const ae_vector* sclsftbndl, + /* Boolean */ const ae_vector* sclsfthasbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* sclsfthasbndu, + /* Real */ const ae_matrix* sclsftcleic, + ae_int_t sclsftnec, + ae_int_t sclsftnic, + /* Real */ const ae_vector* exxc, + /* Real */ ae_vector* nulcest, + qpdenseaulbuffers* buffers, + ae_state *_state); +static void qpdenseaulsolver_scaleshiftoriginalproblem(const convexquadraticmodel* a, + const sparsematrix* sparsea, + ae_int_t akind, + ae_bool sparseaupper, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nmain, + /* Real */ const ae_matrix* cleic, + ae_int_t dnec, + ae_int_t dnic, + const sparsematrix* scleic, + ae_int_t snec, + ae_int_t snic, + ae_bool renormlc, + qpdenseaulbuffers* state, + /* Real */ ae_vector* xs, + ae_state *_state); +static double qpdenseaulsolver_normalizequadraticterm(/* Real */ ae_matrix* a, + /* Real */ ae_vector* b, + ae_int_t n, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + ae_bool usecleic, + /* Real */ ae_matrix* tmp2, + ae_state *_state); +static void qpdenseaulsolver_selectinitialworkingset(/* Real */ const ae_matrix* a, + ae_int_t nmain, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + /* Real */ ae_vector* tmp0, + /* Real */ ae_matrix* tmp2, + ae_int_t* nicwork, + ae_bool* allowwseviction, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) +static double vipmsolver_muquasidense = 5.0; +static ae_int_t vipmsolver_maxipmits = 200; +static double vipmsolver_initslackval = 100.0; +static double vipmsolver_maxdualslackval = 1.0E4; +static double vipmsolver_steplengthdecay = 0.95; +static double vipmsolver_stagnationdelta = 0.99999; +static double vipmsolver_primalinfeasible1 = 1.0E-3; +static double vipmsolver_dualinfeasible1 = 1.0E-3; +static double vipmsolver_bigy = 1.0E8; +static double vipmsolver_ygrowth = 1.0E6; +static ae_int_t vipmsolver_phase0length = 10; +static ae_int_t vipmsolver_itersfortoostringentcond = 25; +static ae_int_t vipmsolver_minitersbeforedroppingbounds = 3; +static ae_int_t vipmsolver_minitersbeforeinfeasible = 3; +static ae_int_t vipmsolver_minitersbeforestagnation = 5; +static ae_int_t vipmsolver_minitersbeforeeworststagnation = 50; +static ae_int_t vipmsolver_primalstagnationlen = 5; +static ae_int_t vipmsolver_dualstagnationlen = 7; +static double vipmsolver_bigconstrxtol = 1.0E-5; +static double vipmsolver_bigconstrmag = 1.0E3; +static double vipmsolver_minitersbeforesafeguards = 5; +static double vipmsolver_badsteplength = 1.0E-3; +static ae_int_t vipmsolver_maxrefinementits = 5; +static void vipmsolver_varsinitbyzero(vipmvars* vstate, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static void vipmsolver_varsinitfrom(vipmvars* vstate, + const vipmvars* vsrc, + ae_state *_state); +static void vipmsolver_varsaddstep(vipmvars* vstate, + const vipmvars* vdir, + double stpp, + double stpd, + ae_state *_state); +static double vipmsolver_varscomputecomplementaritygap(const vipmvars* vstate, + ae_state *_state); +static double vipmsolver_varscomputemu(const vipmstate* state, + const vipmvars* vstate, + ae_state *_state); +static void vipmsolver_reducedsysteminit(vipmreducedsparsesystem* s, + const vipmstate* solver, + ae_state *_state); +static ae_bool vipmsolver_reducedsystemfactorizewithaddends(vipmreducedsparsesystem* s, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* damp, + double modeps, + double badchol, + double* sumsq, + double* errsq, + ae_state *_state); +static void vipmsolver_reducedsystemsolve(vipmreducedsparsesystem* s, + ae_bool dotrace, + /* Real */ ae_vector* b, + ae_state *_state); +static void vipmsolver_vipminit(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_int_t nmain, + ae_int_t ftype, + ae_bool normalize, + ae_state *_state); +static double vipmsolver_vipmtarget(const vipmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +static void vipmsolver_multiplygeax(const vipmstate* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsax, + ae_state *_state); +static void vipmsolver_multiplygeatx(const vipmstate* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); +static void vipmsolver_multiplyhx(const vipmstate* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state); +static void vipmsolver_vipmmultiply(const vipmstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* hx, + /* Real */ ae_vector* ax, + /* Real */ ae_vector* aty, + ae_state *_state); +static void vipmsolver_vipmpowerup(vipmstate* state, + double regfree, + ae_state *_state); +static ae_bool vipmsolver_vipmfactorize(vipmstate* state, + double alpha0, + /* Real */ const ae_vector* d, + double beta0, + /* Real */ const ae_vector* e, + double alpha11, + double beta11, + double modeps, + double dampeps, + ae_state *_state); +static void vipmsolver_solvereducedkktsystem(vipmstate* state, + /* Real */ ae_vector* deltaxy, + ae_state *_state); +static ae_bool vipmsolver_vipmprecomputenewtonfactorization(vipmstate* state, + const vipmvars* v0, + double regeps, + double modeps, + double dampeps, + double dampfree, + ae_state *_state); +static void vipmsolver_solvekktsystem(vipmstate* state, + const vipmrighthandside* rhs, + vipmvars* sol, + ae_state *_state); +static ae_bool vipmsolver_vipmcomputestepdirection(vipmstate* state, + const vipmvars* v0, + double muestimate, + const vipmvars* vdestimate, + vipmvars* vdresult, + double reg, + ae_bool isdampepslarge, + ae_state *_state); +static void vipmsolver_vipmcomputesteplength(const vipmstate* state, + const vipmvars* v0, + const vipmvars* vs, + double stepdecay, + ae_bool separatestep, + double* alphap, + double* alphad, + ae_state *_state); +static void vipmsolver_vipmperformstep(vipmstate* state, + double alphap, + double alphad, + ae_state *_state); +static void vipmsolver_computeerrors(vipmstate* state, + double* errp2, + double* errd2, + double* errpinf, + double* errdinf, + double* egap, + ae_state *_state); +static void vipmsolver_runintegritychecks(const vipmstate* state, + const vipmvars* v0, + const vipmvars* vd, + double alphap, + double alphad, + ae_state *_state); +static void vipmsolver_traceprogress(vipmstate* state, + double mu, + double muaff, + double sigma, + double alphap, + double alphad, + ae_state *_state); +static void vipmsolver_rhscompute(vipmstate* state, + const vipmvars* v0, + double muestimate, + const vipmvars* direstimate, + vipmrighthandside* rhs, + double reg, + ae_state *_state); +static void vipmsolver_rhssubtract(vipmstate* state, + vipmrighthandside* rhs, + const vipmvars* v0, + const vipmvars* vdcandidate, + double reg, + ae_state *_state); +static double vipmsolver_rhsprimal2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static double vipmsolver_rhsdual2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static double vipmsolver_rhsprimalinf(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static double vipmsolver_rhsdualinf(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static double vipmsolver_rhscompl2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static double vipmsolver_minnz(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +static double vipmsolver_minprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); +static double vipmsolver_maxprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) +static ae_int_t ipm2solver_spsymmfacttype = 21; +static double ipm2solver_muquasidense = 10.0; +static double ipm2solver_mupromote = 10.0; +static ae_int_t ipm2solver_defipmits = 200; +static double ipm2solver_initslackval = 100.0; +static double ipm2solver_steplengthdecay = 0.95; +static double ipm2solver_stagnationdelta = 0.99999; +static double ipm2solver_primalinfeasible1 = 1.0E-3; +static double ipm2solver_dualinfeasible1 = 1.0E-3; +static double ipm2solver_bigy = 1.0E8; +static double ipm2solver_ygrowth = 1.0E6; +static ae_int_t ipm2solver_itersfortoostringentcond = 25; +static ae_int_t ipm2solver_minitersbeforeinfeasible = 3; +static ae_int_t ipm2solver_minitersbeforestagnation = 5; +static ae_int_t ipm2solver_minitersbeforeeworststagnation = 15; +static ae_int_t ipm2solver_primalstagnationlen = 5; +static ae_int_t ipm2solver_dualstagnationlen = 7; +static double ipm2solver_minitersbeforesafeguards = 5; +static double ipm2solver_badsteplength = 1.0E-3; +static void ipm2solver_varsinitbyzero(ipm2vars* vstate, + ae_int_t ntotal, + ae_int_t m, + ae_state *_state); +static void ipm2solver_varsinitfrom(ipm2vars* vstate, + const ipm2vars* vsrc, + ae_state *_state); +static void ipm2solver_varsaddstep(ipm2vars* vstate, + const ipm2vars* vdir, + double stp, + ae_state *_state); +static double ipm2solver_varscomputecomplementaritygap(const ipm2vars* vstate, + ae_state *_state); +static double ipm2solver_varscomputemu(const ipm2state* state, + const ipm2vars* vstate, + ae_state *_state); +static double ipm2solver_varscomputemutrial(const ipm2state* state, + const ipm2vars* current, + const ipm2vars* delta, + double alpha, + ae_state *_state); +static void ipm2solver_multiplygeax(const ipm2state* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsax, + ae_state *_state); +static void ipm2solver_multiplygeatx(const ipm2state* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state); +static void ipm2solver_multiplyhx(const ipm2state* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state); +static void ipm2solver_ipm2multiply(const ipm2state* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* hx, + /* Real */ ae_vector* ax, + /* Real */ ae_vector* aty, + ae_state *_state); +static void ipm2solver_ipm2powerup(ipm2state* state, + double regfree, + ae_state *_state); +static void ipm2solver_reducedsystempowerup(ipm2reducedsystem* s, + ipm2state* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static ae_bool ipm2solver_reducedsystemcomputefactorization(ipm2reducedsystem* redsys, + ipm2state* sstate, + const ipm2vars* current, + double dampepsmu, + double dampepszs, + double dampepsp, + double dampepsd, + ae_state *_state); +static void ipm2solver_ipm2computesteplength(const ipm2state* state, + const ipm2vars* current, + const ipm2vars* delta, + double* alpha, + ae_state *_state); +static void ipm2solver_computeerrors(const ipm2state* state, + const ipm2righthandside* rhs, + /* Real */ const ae_vector* currenthx, + /* Real */ const ae_vector* currentax, + /* Real */ const ae_vector* currentaty, + double* errp2, + double* errd2, + double* errpinf, + double* errdinf, + double* egap, + ae_state *_state); +static void ipm2solver_traceprogress(ipm2state* state, + double muinit, + double alphaaff, + double alphafin, + ae_state *_state); +static void ipm2solver_rhscomputeprimdual(const ipm2state* state, + const ipm2vars* current, + /* Real */ const ae_vector* currenthx, + /* Real */ const ae_vector* currentax, + /* Real */ const ae_vector* currentaty, + ipm2righthandside* rhs, + ae_state *_state); +static void ipm2solver_rhsrecomputegammapredictor(const ipm2state* state, + const ipm2vars* current, + double mutarget, + ipm2righthandside* rhs, + ae_state *_state); +static void ipm2solver_rhsrecomputegammamehrotra(const ipm2state* state, + const ipm2vars* current, + double mutarget, + const ipm2vars* deltaaff, + ipm2righthandside* rhs, + ae_state *_state); +static ae_bool ipm2solver_reducedsystemsolve(ipm2reducedsystem* redsys, + ipm2state* sstate, + const ipm2vars* current, + const ipm2righthandside* rhs, + ipm2vars* delta, + ae_state *_state); +static double ipm2solver_minnz(/* Real */ const ae_vector* x, + ae_int_t n0, + ae_int_t n1, + ae_state *_state); +static double ipm2solver_minprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n0, + ae_int_t n1, + ae_state *_state); +static double ipm2solver_maxprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n0, + ae_int_t n1, + ae_state *_state); +static double ipm2solver_maxabsrange(/* Real */ const ae_vector* x, + ae_int_t r0, + ae_int_t r1, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) +static double ecqpsolver_mupromote = 10.0; + + +#endif +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) +static double gipm_initmu = 0.1; +static double gipm_maxmu = 10000; +static double gipm_tightendist = 5.0; +static double gipm_relaxdist = 2.0; +static double gipm_penaltygrowth = 1.0; +static double gipm_maxnu = 0.001; +static double gipm_relaxfactor = 1.0; +static double gipm_maxrelaxation = 0.0001; +static double gipm_lambdamax = 1.0E6; +static double gipm_lambdagrowth = 2.0; +static double gipm_lambdarapidgrowth = 100.0; +static double gipm_lambdadecayacc = 0.90; +static ae_int_t gipm_maxsubsequentfailuresforweakgrowth = 5; +static double gipm_damptau = 0.0001; +static double gipm_fractobnd = 0.98; +static double gipm_mudecaylinear = 0.2; +static double gipm_mudecaypower = 1.2; +static double gipm_checkpointacceptance = 0.9; +static ae_int_t gipm_maxcheckpointstagnationits = 25; +static double gipm_firstiterationcheckpointstagnationeps = 0.001; +static double gipm_rhsstagnationtol1 = 0.001; +static double gipm_rhsstagnationtol2 = 0.05; +static ae_int_t gipm_maxrhsstagnationits = 5; +static double gipm_smallstep = 1.0E-8; +static double gipm_initbigval = 1.0E9; +static double gipm_initbiggrowth = 1.0E9; +static double gipm_maxbigval = 1.0E50; +static double gipm_maxbiggrowth = 1.0E20; +static double gipm_vggrowth = 1.0E3; +static ae_int_t gipm_maxsmalltrials = 3; +static ae_int_t gipm_maxrfsits = 5; +static double gipm_rhstol = (double)100*ae_machineepsilon; +static ae_int_t gipm_maxnd = 2; +static ae_int_t gipm_maxnonmonotonic = 1; +static ae_int_t gipm_nonmonotonicdelay = 10; +static double gipm_dualmeritnu = 0.1; +static void gipm_varsinitbyzero(gipmvars* vstate, + ae_int_t nraw, + ae_int_t mflex, + ae_int_t mhard, + ae_state *_state); +static void gipm_varsapplystep(gipmvars* vstate, + const gipmvars* delta, + double alpha, + ae_state *_state); +static void gipm_varscopy(const gipmvars* src, + gipmvars* dst, + ae_state *_state); +static double gipm_computesteplength(const gipmstate* state, + const gipmvars* current, + const gipmvars* delta, + ae_state *_state); +static void gipm_computerhs(gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + gipmrhs* rhs, + double* eprim2, + double* edual2, + double* ecmpl2, + double* sprim, + double* sdual, + double* scmpl, + ae_state *_state); +static double gipm_computeupdateresidual(gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + double lambdatouse, + const gipmvars* delta, + /* Real */ const ae_vector* hdxp, + /* Real */ const ae_vector* jdxp, + /* Real */ const ae_vector* jtdy, + gipmrhs* rhs, + ae_state *_state); +static void gipm_condenselhs(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + gipmcondensedsystem* c, + ae_state *_state); +static void gipm_condenserhs(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + const gipmrhs* rhs, + gipmcondensedsystem* c, + ae_state *_state); +static void gipm_unpacksolution(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + const gipmrhs* rhs, + gipmcondensedsystem* c, + /* Real */ const ae_vector* replysol, + gipmvars* delta, + ae_state *_state); +static void gipm_barrierpenaltyandcmplerror(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + double* barrierf, + double* penaltyf, + double* cmplerr, + ae_state *_state); +static double gipm_meritv0(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + ae_state *_state); +static double gipm_meritfunctionpd(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + ae_state *_state); +static void gipm_preparequasinewtonupdate(gipmstate* state, + ae_state *_state); +static double gipm_minabsnz(/* Real */ const ae_vector* x, + ae_int_t n1, + ae_state *_state); +static void gipm_safeboundsfromfinitetightened(gipmstate* state, + ae_state *_state); +static void gipm_tightenrelaxbounds(gipmstate* state, ae_state *_state); +static double gipm_getnu(double currentmu, ae_state *_state); +static void gipm_nonmonotonicinit(gipmstate* state, + ae_int_t memlen, + double merit0, + ae_state *_state); +static void gipm_nonmonotonicpush(gipmstate* state, + double meritv, + ae_state *_state); +static double gipm_nonmonotonicgetcorr(gipmstate* state, + double meritv, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) +static double gqpipm_minconicdenominator = 0.05; +static double gqpipm_tootightconstraints = 0.0001; +static double gqpipm_mupromote = 10.0; +static double gqpipm_bigboxconstraint = 1.0E9; +static ae_int_t gqpipm_amdense = 0; +static ae_int_t gqpipm_amsparse = 1; +static ae_int_t gqpipm_amhybrid = 2; +static ae_int_t gqpipm_xbfgsdefaultmemlen = 32; +static double gqpipm_xbfgsmaxhess = 1.0E6; +static void gqpipm_appendtorckv(/* Integer */ const ae_vector* varidx, + const sparsematrix* q, + ae_int_t nv, + ae_int_t id, + /* Integer */ ae_vector* hr, + /* Integer */ ae_vector* hc, + /* Integer */ ae_vector* hk, + /* Real */ ae_vector* hv, + ae_int_t* hcnt, + ae_state *_state); +static void gqpipm_initializehessjac(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_state *_state); +static void gqpipm_sortrck(/* Integer */ ae_vector* vecr, + /* Integer */ ae_vector* vecc, + /* Integer */ ae_vector* veck, + /* Real */ ae_vector* vecv, + ae_int_t n, + /* Integer */ ae_vector* tmpr, + /* Integer */ ae_vector* tmpc, + /* Integer */ ae_vector* tmpk, + /* Real */ ae_vector* tmpv, + ae_state *_state); +static void gqpipm_sortrckrec(/* Integer */ ae_vector* vecr, + /* Integer */ ae_vector* vecc, + /* Integer */ ae_vector* veck, + /* Real */ ae_vector* vecv, + ae_int_t idx0, + ae_int_t idx1, + /* Integer */ ae_vector* tmpr, + /* Integer */ ae_vector* tmpc, + /* Integer */ ae_vector* tmpk, + /* Real */ ae_vector* tmpv, + ae_state *_state); +static void gqpipm_handlecomputeandremember(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state); +static void gqpipm_handlefactorize(gqpipmstate* state, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state); +static void gqpipm_handlesolve(gqpipmstate* state, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state); +static void gqpipm_handlemv(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state); +static void gqpipm_optionaldensefromsparse(gqpoptionaldense* opt, + sparsematrix* s, + ae_int_t nq, + ae_state *_state); +static void gqpipm_optionaldensefromsparseqc(gqpoptionaldense* opt, + xquadraticconstraint* qc, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) +static ae_int_t lpqppresolve_pstobjectivescaling = 0; +static ae_int_t lpqppresolve_pstcolscaling = 1; +static ae_int_t lpqppresolve_pstrowscaling = 2; +static ae_int_t lpqppresolve_pstdropemptycol = 3; +static ae_int_t lpqppresolve_pstdropemptyrow = 4; +static ae_int_t lpqppresolve_pstsingletonrow = 5; +static ae_int_t lpqppresolve_pstfixedvar = 6; +static ae_int_t lpqppresolve_pstexplicitslack = 7; +static ae_int_t lpqppresolve_pstimplicitslack = 8; +static ae_int_t lpqppresolve_pstcolshifting = 9; +static ae_int_t lpqppresolve_pstdoubletoneq = 10; +static ae_int_t lpqppresolve_pstqcscaling = 11; +static ae_int_t lpqppresolve_pstdropemptyqc = 12; +static ae_int_t lpqppresolve_actlowerboundonk0 = 0; +static ae_int_t lpqppresolve_actupperboundonk0 = 1; +static ae_int_t lpqppresolve_actlowerboundonk1 = 2; +static ae_int_t lpqppresolve_actupperboundonk1 = 3; +static ae_int_t lpqppresolve_actnone = -1; +static double lpqppresolve_smlcoeff = 0.001; +static double lpqppresolve_maxcoeffgrowth = 100.0; +static ae_bool lpqppresolve_isfixed(double bndl, + double bndu, + double eps, + ae_state *_state); +static void lpqppresolve_dyncrsinitempty(dynamiccrs* r, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static void lpqppresolve_dyncrscopy(const dynamiccrs* src, + dynamiccrs* dst, + ae_state *_state); +static void lpqppresolve_dyncrscopydeleterowcol(const dynamiccrs* src, + ae_int_t deletepos, + dynamiccrs* dst, + ae_state *_state); +static void lpqppresolve_dyncrscopydeleterowscols(const dynamiccrs* src, + const niset* deleteset, + dynamiccrs* dst, + /* Integer */ ae_vector* buf, + ae_state *_state); +static void lpqppresolve_dyncrscopyinsertrowcol(const dynamiccrs* src, + ae_int_t insertpos, + dynamiccrs* dst, + ae_state *_state); +static void lpqppresolve_dyncrsinitfromsparsecrs(const sparsematrix* s, + dynamiccrs* r, + ae_state *_state); +static void lpqppresolve_dyncrsdropzeros(dynamiccrs* a, ae_state *_state); +static void lpqppresolve_dyncrsdropoffdiagonalzeros(dynamiccrs* a, + ae_state *_state); +static void lpqppresolve_dyncrsclearrow(dynamiccrs* a, + ae_int_t rowidx, + ae_state *_state); +static void lpqppresolve_dyncrsremovefromrow(dynamiccrs* a, + ae_int_t rowidx, + ae_int_t j, + ae_state *_state); +static void lpqppresolve_dyncrsfactoroutfromrow(dynamiccrs* a, + ae_int_t rowidx, + ae_int_t j, + double c0, + double c1, + ae_int_t k, + ae_bool checkcancellation, + double* newval, + double* shift, + ae_state *_state); +static void lpqppresolve_dyncrsaddrowto(dynamiccrs* a, + ae_int_t row0, + double c, + ae_int_t row1, + ae_bool retaindiagonal, + ae_bool checkcancellation, + ae_state *_state); +static void lpqppresolve_dyncrsinsertwithrewrite(dynamiccrs* a, + ae_int_t tgtrow, + /* Integer */ const ae_vector* idx, + /* Real */ const ae_vector* vals, + ae_int_t cnt, + ae_state *_state); +static void lpqppresolve_dyncrsremovesetfromrow(dynamiccrs* a, + ae_int_t rowidx, + const niset* s, + ae_state *_state); +static double lpqppresolve_dyncrsgetexistingelement(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + ae_state *_state); +static double lpqppresolve_dyncrsgetelementifexists(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + ae_state *_state); +static void lpqppresolve_dyncrssetexistingelement(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + double v, + ae_state *_state); +static void lpqppresolve_dynqcinitfromxqc(xquadraticconstraints* src, + dynamiccrsqconstraints* dst, + ae_state *_state); +static void lpqppresolve_dynqccopy(const dynamiccrsqconstraint* src, + dynamiccrsqconstraint* dst, + ae_state *_state); +static void lpqppresolve_dynqccopyinsertrowcol(dynamiccrsqconstraint* src, + ae_int_t vidx, + ae_int_t insertpos, + dynamiccrsqconstraint* dst, + ae_state *_state); +static void lpqppresolve_dynqccopydeleterowcol(const dynamiccrsqconstraint* src, + ae_int_t deletepos, + dynamiccrsqconstraint* dst, + ae_state *_state); +static void lpqppresolve_dynqccopydeleterowscols(const dynamiccrsqconstraint* src, + const niset* deleteset, + dynamiccrsqconstraint* dst, + /* Integer */ ae_vector* buf, + ae_state *_state); +static double lpqppresolve_factoroutfromquadratic(dynamiccrs* h, + /* Real */ ae_vector* c, + ae_int_t k0, + double alpha0, + double alpha1, + ae_int_t k1, + ae_state *_state); +static double lpqppresolve_fixquadraticvariable(dynamiccrs* h, + /* Real */ ae_vector* c, + ae_int_t fixidx, + double fixval, + ae_state *_state); +static void lpqppresolve_dynqcpermtoxqc(dynamiccrsqconstraint* src, + /* Integer */ const ae_vector* packxperm, + /* Integer */ const ae_vector* unpackxperm, + xquadraticconstraint* dst, + ae_state *_state); +static void lpqppresolve_presolverstackinit(ae_int_t n, + ae_int_t m, + ae_int_t mqc, + ae_int_t mcc, + presolverstack* s, + ae_state *_state); +static void lpqppresolve_presolverstreamb(presolverstack* s, + ae_bool b, + ae_state *_state); +static void lpqppresolve_presolverstreami(presolverstack* s, + ae_int_t i, + ae_state *_state); +static void lpqppresolve_presolverstreamr(presolverstack* s, + double v, + ae_state *_state); +static void lpqppresolve_presolverstreamir(presolverstack* s, + ae_int_t i, + double v, + ae_state *_state); +static void lpqppresolve_presolverstreamcrsrow(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + ae_state *_state); +static void lpqppresolve_presolverstreamcrsrownot1(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + ae_int_t notidx, + ae_state *_state); +static void lpqppresolve_presolverstreamcrsrownonflagged(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + /* Boolean */ const ae_vector* flags, + ae_state *_state); +static void lpqppresolve_presolverselectstreamsource(presolverstack* s, + ae_int_t tidx, + ae_state *_state); +static void lpqppresolve_presolverunstreamb(presolverstack* s, + ae_bool* v, + ae_state *_state); +static ae_bool lpqppresolve_presolverunstreambf(presolverstack* s, + ae_state *_state); +static void lpqppresolve_presolverunstreami(presolverstack* s, + ae_int_t* v, + ae_state *_state); +static void lpqppresolve_presolverunstreamr(presolverstack* s, + double* v, + ae_state *_state); +static void lpqppresolve_presolverunstreamir(presolverstack* s, + ae_int_t* vi, + double* vr, + ae_state *_state); +static void lpqppresolve_presolverunstreamsparsevec(presolverstack* s, + ae_int_t* cnt, + /* Integer */ ae_vector* idx, + /* Real */ ae_vector* vals, + ae_state *_state); +static void lpqppresolve_presolverasserteos(presolverstack* s, + ae_state *_state); +static void lpqppresolve_presolverappendtrf(presolverstack* s, + ae_int_t tt, + ae_state *_state); +static void lpqppresolve_presolverappendcostscaling(presolverstack* s, + double vmul, + ae_state *_state); +static void lpqppresolve_presolverappendcolscaling(presolverstack* s, + ae_int_t colidx, + double vmul, + ae_state *_state); +static void lpqppresolve_presolverappendcolshifting(presolverstack* s, + ae_int_t colidx, + double vadd, + ae_state *_state); +static void lpqppresolve_presolverappendrowscaling(presolverstack* s, + ae_int_t rowidx, + double vmul, + ae_state *_state); +static void lpqppresolve_presolverappendqcscaling(presolverstack* s, + ae_int_t qcidx, + double vmul, + ae_state *_state); +static void lpqppresolve_presolverappendccscaling(presolverstack* s, + ae_int_t ccidx, + double vmul, + ae_state *_state); +static void lpqppresolve_presolverappenddropemptycol(presolverstack* s, + ae_int_t colidx, + double varval, + double lagval, + ae_int_t statval, + ae_state *_state); +static void lpqppresolve_presolverappenddropemptyrow(presolverstack* s, + ae_int_t rowidx, + ae_state *_state); +static void lpqppresolve_presolverappenddropemptyqc(presolverstack* s, + ae_int_t qcidx, + ae_state *_state); +static void lpqppresolve_presolverappendsingletonrow(presolverstack* s, + ae_int_t i, + ae_int_t j, + double v, + double swapsign, + double bndl, + ae_bool bndlisbc, + double bndu, + ae_bool bnduisbc, + ae_state *_state); +static void lpqppresolve_presolverappendfixedvar(presolverstack* s, + ae_int_t colidx, + double fixval, + double ci, + const dynamiccrs* sparseh, + const presolvervcstats* vcstats, + ae_bool hash, + const dynamiccrs* at, + ae_bool hasat, + dynamiccrsqconstraints* qc, + ae_state *_state); +static void lpqppresolve_presolverappendexplicitslack(presolverstack* s, + ae_int_t i, + ae_int_t j, + double aij, + double slackbndl, + double slackbndu, + double al, + double au, + const dynamiccrs* a, + ae_state *_state); +static void lpqppresolve_presolverappendimplicitslack(presolverstack* s, + ae_int_t i, + ae_int_t j, + double aij, + double cj, + double equalitybnd, + const dynamiccrs* a, + ae_state *_state); +static void lpqppresolve_presolverappenddoubletonfactorout(presolverstack* s, + const presolvervcstats* vcstats, + ae_int_t rowidx, + ae_int_t col0, + double bndl0, + double bndu0, + ae_int_t col1, + double bndl1, + double bndu1, + double c0, + double c1, + const dynamiccrs* sparseh, + ae_bool hash, + const dynamiccrs* at, + dynamiccrsqconstraints* qc, + double ai0, + double ai1, + double abnd, + double newbndl1, + double newbndu1, + ae_int_t bndlactivates, + ae_int_t bnduactivates, + ae_state *_state); +static void lpqppresolve_presolverrestoresolution(presolverstack* s, + /* Real */ ae_vector* x, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + /* Integer */ ae_vector* stats, + ae_bool needstats, + double eps, + ae_state *_state); +static void lpqppresolve_copyexpandh(const sparsematrix* rawh, + ae_bool isupper, + sparsematrix* fullh, + ae_state *_state); +static void lpqppresolve_presolvebuffersinit(presolvebuffers* buf, + ae_int_t n, + ae_int_t m, + ae_state *_state); +static ae_bool lpqppresolve_dropemptycol(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + /* Boolean */ ae_vector* lagrangefromresidual, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntdropped, + ae_state *_state); +static ae_bool lpqppresolve_dropclearlynonbindingrows(ae_int_t n, + presolvervcstats* vcstats, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntempty, + ae_int_t* cntemptyqc, + ae_int_t* cntnobounds, + ae_int_t* cntnoboundsqc, + ae_state *_state); +static ae_bool lpqppresolve_singletonrowtobc(/* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntsingleton, + ae_state *_state); +static ae_bool lpqppresolve_doubletonrow(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntdoubleton, + ae_state *_state); +static ae_bool lpqppresolve_singletoncols(/* Real */ ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntslackvars, + ae_int_t* cntimplicitslacks, + ae_int_t* cntfreecolumnsingletons, + ae_state *_state); +static ae_bool lpqppresolve_fixvariables(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntfixed, + ae_state *_state); +static void lpqppresolve_scaleshiftobjectiveandconstraints(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + /* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + sparsematrix* sparseh, + ae_bool hash, + sparsematrix* sparsea, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + presolverstack* trfstack, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) +static double nlcfsqp_sqpdeltadecrease = 0.05; +static double nlcfsqp_sqpdeltaincrease = 0.99; +static double nlcfsqp_maxtrustraddecay = 0.1; +static double nlcfsqp_deftrustradgrowth = 1.41; +static double nlcfsqp_maxtrustradgrowth = 10.0; +static double nlcfsqp_momentumgrowth = 2; +static double nlcfsqp_augmentationfactor = 0.1; +static double nlcfsqp_definittrustrad = 0.1; +static double nlcfsqp_stagnationepsf = 1.0E-12; +static ae_int_t nlcfsqp_fstagnationlimit = 20; +static ae_int_t nlcfsqp_trustradstagnationlimit = 5; +static ae_int_t nlcfsqp_defaultbfgsresetfreq = 999999; +static double nlcfsqp_sufficientdecreasesigma = 0.1; +static ae_int_t nlcfsqp_xbfgsmemlen = 8; +static double nlcfsqp_xbfgsmaxhess = 1.0E6; +static double nlcfsqp_defsqpbigscale = 4.0; +static double nlcfsqp_defsqpsmallscale = 0.1; +static double nlcfsqp_sqpsmallscaledecrease = 0.5; +static double nlcfsqp_sqpmaxrescale = 10.0; +static double nlcfsqp_sqpminrescale = 0.1; +static ae_int_t nlcfsqp_maxipmits = 100; +static void nlcfsqp_initqpsubsolver(const minfsqpstate* sstate, + minfsqpsubsolver* subsolver, + ae_state *_state); +static ae_bool nlcfsqp_qpsubproblemsolvesqp(minfsqpstate* state, + minfsqpsubsolver* subsolver, + const varsfuncjac* model, + xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_bool* isinfeasible, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* d2trustradratio, + ae_state *_state); +static ae_bool nlcfsqp_qpsubproblemsolveelastic(minfsqpstate* state, + minfsqpsubsolver* subsolver, + const varsfuncjac* model, + xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_bool* isinfeasible, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* d2trustradratio, + ae_state *_state); +static ae_bool nlcfsqp_qpsubproblemisfeasible(const minfsqpstate* state, + const minfsqpsubsolver* subsolver, + const varsfuncjac* model, + /* Real */ const ae_vector* d, + ae_state *_state); +static void nlcfsqp_sqpsendx(minfsqpstate* state, + /* Real */ const ae_vector* xs, + ae_state *_state); +static ae_bool nlcfsqp_sqpretrievefij(const minfsqpstate* state, + varsfuncjac* vfj, + ae_state *_state); +static void nlcfsqp_lagrangianfg(minfsqpstate* state, + /* Real */ const ae_vector* x, + double trustrad, + /* Real */ const ae_vector* fi, + const sparsematrix* sj, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_bool uselagrangeterms, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static void nlcfsqp_penalizedfg(minfsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + const sparsematrix* sj, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static void nlcfsqp_targetandconstraints(minfsqpstate* state, + const varsfuncjac* vfj, + double* tgt, + double* cv, + ae_state *_state); +static double nlcfsqp_rawlagrangian(minfsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_state *_state); +static double nlcfsqp_gettrustregionk(/* Real */ const ae_vector* xcur, + ae_int_t k, + double trustrad, + ae_state *_state); +static ae_bool nlcfsqp_isacceptable(minfsqpstate* state, + double tgt0, + double h0, + double tgt1, + double h1, + double predictedchangemodel, + double predictedchangepenalty, + ae_bool dotraceunacceptability, + ae_state *_state); +static void nlcfsqp_autoscalevarstargetconstraints(minfsqpstate* state, + varsfuncjac* model, + ae_bool firstscaling, + ae_bool dotrace, + ae_state *_state); +static ae_int_t nlcfsqp_geteffectivemaxits(minfsqpstate* state, + ae_state *_state); +static void nlcfsqp_sparse2dense(const sparsematrix* s, + /* Real */ ae_matrix* d, + ae_state *_state); +static void nlcfsqp_appendscaledsparserow(sparsematrix* dst, + double alpha, + const sparsematrix* src, + ae_int_t rowidx, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +static double minlm_lambdaup = 2.0; +static double minlm_lambdadown = 0.33; +static double minlm_suspiciousnu = 16; +static ae_int_t minlm_smallmodelage = 3; +static ae_int_t minlm_additers = 5; +static double minlm_stagnationfeps = 1.0E-12; +static ae_int_t minlm_stagnationfits = 20; +static void minlm_lmprepare(ae_int_t n, + ae_int_t m, + ae_bool havegrad, + minlmstate* state, + ae_state *_state); +static void minlm_clearrequestfields(minlmstate* state, ae_state *_state); +static void minlm_tracefinalreport(minlmstate* state, + ae_bool dotrace, + ae_state *_state); +static ae_bool minlm_increaselambda(double* lambdav, + double* nu, + ae_state *_state); +static void minlm_decreaselambda(double* lambdav, + double* nu, + ae_state *_state); +static ae_int_t minlm_checkdecrease(/* Real */ const ae_matrix* quadraticmodel, + /* Real */ const ae_vector* gbase, + double fbase, + ae_int_t n, + /* Real */ const ae_vector* deltax, + double fnew, + double* lambdav, + double* nu, + ae_state *_state); +static ae_bool minlm_minlmstepfinderinit(minlmstepfinder* state, + ae_int_t n, + ae_int_t m, + ae_int_t maxmodelage, + /* Real */ ae_vector* xbase, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + /* Real */ const ae_vector* s, + double stpmax, + double epsx, + ae_state *_state); +static void minlm_minlmstepfinderstart(minlmstepfinder* state, + /* Real */ const ae_matrix* quadraticmodel, + /* Real */ const ae_vector* gbase, + double fbase, + /* Real */ const ae_vector* xbase, + /* Real */ const ae_vector* fibase, + ae_int_t modelage, + ae_state *_state); +static ae_bool minlm_minlmstepfinderiteration(minlmstepfinder* state, + minlmstate* parentstate, + double* lambdav, + double* nu, + /* Real */ ae_vector* xnew, + /* Real */ ae_vector* deltax, + ae_bool* deltaxready, + /* Real */ ae_vector* deltaf, + ae_bool* deltafready, + ae_int_t* iflag, + double* fnew, + ae_int_t* ncholesky, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) +static double nlcaul_defaultinequalitylag = 1.0; +static double nlcaul_maxlagmult = 1.0E7; +static double nlcaul_minlagmult = 1.0E-10; +static double nlcaul_besterrstagnationcoeff = 0.75; +static ae_int_t nlcaul_besterrstagnationlimit = 10; +static double nlcaul_stagnationepsf = 1.0E-12; +static double nlcaul_stabilizingpoint = 10.0; +static ae_int_t nlcaul_fstagnationlimit = 20; +static double nlcaul_aulmaxgrowth = 10.0; +static double nlcaul_rhomax = 10000; +static double nlcaul_gtol = 0.25; +static double nlcaul_auldeltadecrease = 0.50; +static double nlcaul_auldeltaincrease = 0.99; +static double nlcaul_aulbigscale = 5.0; +static double nlcaul_aulsmallscale = 0.2; +static ae_int_t nlcaul_xbfgsmemlen = 8; +static double nlcaul_xbfgsmaxhess = 1.0E3; +static void nlcaul_preconditionerinit(const minaulstate* sstate, + ae_int_t refreshfreq, + minaulpreconditioner* p, + ae_state *_state); +static void nlcaul_preconditionersendupdates(minaulstate* state, + minaulpreconditioner* prec, + const varsfuncjac* current, + double rho, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + xbfgshessian* hesstgt, + xbfgshessian* hessaug, + ae_state *_state); +static void nlcaul_preconditionersolve(minaulstate* state, + minaulpreconditioner* prec, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state); +static void nlcaul_aulsendvirtualpoint(minaulstate* state, + /* Real */ const ae_vector* xvirt, + /* Real */ ae_vector* xtrue, + ae_state *_state); +static void nlcaul_aulsendtruepoint(minaulstate* state, + /* Real */ const ae_vector* xtrue, + ae_state *_state); +static ae_bool nlcaul_aulretrievesj(minaulstate* state, + varsfuncjac* xvirt, + varsfuncjac* xtrue, + ae_state *_state); +static void nlcaul_modtargetfg(minaulstate* state, + const varsfuncjac* s, + double rhobc, + double rhoxc, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static void nlcaul_auglagfg(minaulstate* state, + const varsfuncjac* s, + double rho, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static void nlcaul_rawlagfg(minaulstate* state, + const varsfuncjac* s, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static void nlcaul_clearrequestfields(minaulstate* state, + ae_state *_state); +static void nlcaul_computeerrors(minaulstate* sstate, + const varsfuncjac* s, + double* errprim, + double* errdual, + double* errcmpl, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +static ae_int_t mincg_rscountdownlen = 10; +static double mincg_gtol = 0.3; +static void mincg_clearrequestfields(mincgstate* state, ae_state *_state); +static void mincg_preconditionedmultiply(mincgstate* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* work0, + /* Real */ ae_vector* work1, + ae_state *_state); +static double mincg_preconditionedmultiply2(mincgstate* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* work0, + /* Real */ ae_vector* work1, + ae_state *_state); +static void mincg_mincginitinternal(ae_int_t n, + double diffstep, + mincgstate* state, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) +static double dfgenmod_gammasafety = 0.5; +static double dfgenmod_omegasafety = 0.1; +static double dfgenmod_alpha1 = 0.1; +static double dfgenmod_alpha2 = 0.5; +static double dfgenmod_eta1 = 0.1; +static double dfgenmod_eta2 = 0.7; +static double dfgenmod_gammabad = 0.1; +static double dfgenmod_gammadec = 0.5; +static double dfgenmod_gammadec2 = 0.85; +static double dfgenmod_gammainc = 2.0; +static double dfgenmod_gammainc2 = 4.0; +static double dfgenmod_twopsstep = 0.5; +static double dfgenmod_twopssteplo = 0.15; +static double dfgenmod_twopsstephi = 1.50; +static double dfgenmod_lsaimprovementlimit = 1; +static double dfgenmod_pointunacceptablyfar = 50.0; +static double dfgenmod_pointtoofar = 2.0; +static double dfgenmod_pointtooclose = 0.02; +static ae_int_t dfgenmod_minhistory = 5; +static ae_int_t dfgenmod_maxhistory = 30; +static double dfgenmod_rbfmindist = 0.10; +static double dfgenmod_rbftheta0 = 20.0; +static double dfgenmod_rbftheta1 = 0.001; +static double dfgenmod_rbfsubsolverepsx = 0.00001; +static void dfgenmod_inithistory(dfgmstate* state, ae_state *_state); +static void dfgenmod_updatehistory(dfgmstate* state, ae_state *_state); +static void dfgenmod_clearhistoryonrestart(dfgmstate* state, + ae_state *_state); +static void dfgenmod_updatetrustregion(dfgmstate* state, + double trustradfactor, + ae_state *_state); +static double dfgenmod_normrelativetotrustregion(const dfgmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +static void dfgenmod_preparetrialrequest(dfgmstate* state, + double* predf, + double* predh, + ae_state *_state); +static void dfgenmod_processtrialrequest(dfgmstate* state, + double* f, + double* h, + ae_state *_state); +static ae_bool dfgenmod_testacceptancebyfilter(dfgmstate* state, + double fk, + double hk, + double fp, + double hp, + double fn, + double hn, + ae_state *_state); +static void dfgenmod_sendstepacceptancetomodel(dfgmstate* state, + double fk, + double hk, + double fn, + double hn, + ae_state *_state); +static void dfgenmod_sendstepdenialtomodel(dfgmstate* state, + ae_state *_state); +static ae_bool dfgenmod_deltakatminimum(const dfgmstate* state, + ae_state *_state); +static ae_bool dfgenmod_restartautodetected(const dfgmstate* state, + ae_state *_state); +static ae_bool dfgenmod_workingsetneedsimprovement(dfgmstate* state, + ae_state *_state); +static ae_bool dfgenmod_updateworkingsetandmodel(dfgmstate* state, + /* Real */ const ae_vector* xk, + /* Real */ const ae_vector* xn, + /* Real */ const ae_vector* fnvec, + double fn, + double hn, + ae_bool successfulstep, + ae_state *_state); +static ae_bool dfgenmod_improveworkingsetgeometry(dfgmstate* state, + ae_state *_state); +static double dfgenmod_maxabslag(/* Real */ const ae_vector* xk, + ae_int_t n, + /* Real */ const ae_vector* trustregion, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + /* Real */ const ae_vector* c, + double c0, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmpx, + ae_bool needx, + ae_state *_state); +static void dfgenmod_mostandleastdistant(/* Real */ const ae_vector* invtrustregion, + ae_int_t n, + /* Real */ const ae_matrix* wrkset, + ae_int_t wrksetsize, + double* mostdistant, + ae_int_t* mostdistantidx, + double* leastdistant, + ae_int_t* leastdistantidx, + ae_state *_state); +static void dfgenmod_initcloud(dfgmstate* state, + ae_bool savetocloud, + ae_state *_state); +static void dfgenmod_sendrequesttocloud(dfgmstate* state, + /* Real */ const ae_vector* querydata, + ae_int_t requestsize, + ae_state *_state); +static void dfgenmod_sendreplytocloud(dfgmstate* state, + /* Real */ const ae_vector* replyfi, + ae_state *_state); +static void dfgenmod_clearcloud(dfgmstate* state, ae_state *_state); +static void dfgenmod_rbfinitializemodelfromworkingset(dfgmstate* state, + ae_state *_state); +static void dfgenmod_rbfcomputemodel(dfgmstate* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* f, + ae_bool needf, + /* Real */ ae_vector* g, + ae_bool needg, + ae_state *_state); +static void dfgenmod_rbfsolvecpdm(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* bb, + ae_int_t ncenters, + ae_int_t nrhs, + ae_int_t nx, + double lambdav, + ae_bool iscpd, + /* Real */ ae_matrix* ssol, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) +static double nlcsqp_sqpdeltadecrease = 0.50; +static double nlcsqp_sqpdeltaincrease = 0.99; +static double nlcsqp_maxtrustraddecay = 0.1; +static double nlcsqp_deftrustradgrowth = 1.41; +static double nlcsqp_maxtrustradgrowth = 10.0; +static double nlcsqp_momentumgrowth = 2; +static double nlcsqp_maxmeritmu = 1.0E5; +static double nlcsqp_augmentationfactor = 0.0; +static double nlcsqp_inittrustrad = 0.1; +static double nlcsqp_stagnationepsf = 1.0E-12; +static ae_int_t nlcsqp_fstagnationlimit = 20; +static ae_int_t nlcsqp_trustradstagnationlimit = 10; +static double nlcsqp_sqpbigscale = 5.0; +static double nlcsqp_sqpsmallscale = 0.2; +static double nlcsqp_sqpmaxrescale = 10.0; +static double nlcsqp_sqpminrescale = 0.1; +static ae_int_t nlcsqp_defaultbfgsresetfreq = 999999; +static double nlcsqp_sufficientdecreasesigma = 0.001; +static double nlcsqp_meritmueps = 0.15; +static ae_int_t nlcsqp_xbfgsmemlen = 8; +static double nlcsqp_xbfgsmaxhess = 1.0E6; +static ae_int_t nlcsqp_nonmonotoniclen = 3; +static double nlcsqp_constraintsstagnationeps = 1.0E-5; +static void nlcsqp_initqpsubsolver(const minsqpstate* sstate, + minsqpsubsolver* subsolver, + ae_state *_state); +static ae_bool nlcsqp_qpsubproblemsolve(minsqpstate* state, + minsqpsubsolver* subsolver, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + xbfgshessian* hess, + double alphag, + double alphah, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* sumc1, + double* d2trustradratio, + ae_state *_state); +static void nlcsqp_sqpsendx(minsqpstate* state, + /* Real */ const ae_vector* xs, + ae_state *_state); +static ae_bool nlcsqp_sqpretrievefij(const minsqpstate* state, + varsfuncjac* vfj, + ae_state *_state); +static void nlcsqp_lagrangianfg(minsqpstate* state, + /* Real */ const ae_vector* x, + double trustrad, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* j, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_bool uselagrangeterms, + double* f, + /* Real */ ae_vector* g, + ae_state *_state); +static double nlcsqp_meritfunction(minsqpstate* state, + const varsfuncjac* vfj, + double meritmu, + ae_state *_state); +static double nlcsqp_rawlagrangian(minsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + double meritmu, + ae_state *_state); +static void nlcsqp_meritfunctionandrawlagrangian(minsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + double meritmu, + double* meritf, + double* rawlag, + ae_state *_state); +static ae_bool nlcsqp_penaltiesneedincrease(minsqpstate* state, + const varsfuncjac* currentlinearization, + /* Real */ const ae_vector* dtrial, + double predictedchangemodel, + double predictedchangepenalty, + ae_bool dotrace, + ae_state *_state); +static double nlcsqp_gettrustregionk(/* Real */ const ae_vector* xcur, + ae_int_t k, + double trustrad, + ae_state *_state); +static double nlcsqp_nonmonotonicadjustment(minsqpstate* state, + double fraw, + ae_state *_state); +static void nlcsqp_nonmonotonicsave(minsqpstate* state, + const varsfuncjac* cur, + ae_state *_state); +static void nlcsqp_nonmonotonicmultiplyby(minsqpstate* state, + ae_int_t jacrow, + double v, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) +static double ssgd_secanttoblurratio = 1.0; +static double ssgd_defaultpenalty = 100; +static double ssgd_sqjmomentum = 0.05; +static void ssgd_clearrequestfields(ssgdstate* state, ae_state *_state); +static double ssgd_penalizedtarget(ssgdstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + ae_state *_state); +static double ssgd_lcpenalty(ssgdstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +static double ssgd_scalednlcpenalty(ssgdstate* state, + /* Real */ const ae_vector* _fi, + ae_int_t idx, + double fscale, + ae_state *_state); +static double ssgd_lcviolation(ssgdstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) +static double diffevo_defaultpenalty = 100; +static ae_int_t diffevo_paramscnt = 4; +static ae_int_t diffevo_minpowerupits = 10; +static ae_int_t diffevo_minpopsizefortightening = 5; +static double diffevo_tighteningmu = 0.66; +static double diffevo_bndlimit = 0.85; +static double diffevo_mulearningrate = 0.2; +static ae_int_t diffevo_stcurrenttobest1 = 2; +static ae_int_t diffevo_stcurrenttoordbest1 = 10; +static void diffevo_computefitness(const gdemostate* state, + const gdemopopulation* refpopulation, + ae_bool hasreference, + gdemopopulation* trial, + ae_state *_state); +static void diffevo_updatebest(gdemostate* state, ae_state *_state); +static void diffevo_generatetrialpoints(gdemostate* state, + const gdemopopulation* population, + gdemopopulation* trial, + ae_state *_state); +static void diffevo_gencand(/* Real */ const ae_matrix* deparams, + /* Real */ const ae_matrix* populationx, + /* Real */ const ae_matrix* populationfitness, + ae_int_t n, + ae_int_t m, + ae_int_t popsize, + /* Real */ const ae_matrix* xbest, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + hqrndstate* rs, + /* Real */ ae_matrix* trialx, + ae_state *_state); +static ae_bool diffevo_gdemogencandkernel(/* Real */ const ae_matrix* deparams, + /* Real */ const ae_matrix* populationx, + /* Real */ const ae_matrix* populationfitness, + ae_int_t n, + ae_int_t m, + ae_int_t popsize, + /* Real */ const ae_matrix* xbest, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + double bndsmooth, + ae_int_t seedval, + /* Real */ ae_matrix* trialx, + ae_state *_state); +static void diffevo_updatepopulation(gdemostate* state, + const gdemopopulation* children, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +static double mindf_defaultmomentum = 0.9; +static void mindf_unscale(const mindfstate* state, + /* Real */ const ae_vector* xs, + /* Real */ ae_vector* xu, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) +static ae_int_t reviseddualsimplex_maxforcedrestarts = 1; +static ae_int_t reviseddualsimplex_safetrfage = 5; +static ae_int_t reviseddualsimplex_defaultmaxtrfage = 100; +static double reviseddualsimplex_minbeta = 1.0E-4; +static double reviseddualsimplex_maxudecay = 0.001; +static double reviseddualsimplex_shiftlen = 1.0E-12; +static double reviseddualsimplex_alphatrigger = 1.0E8*ae_machineepsilon; +static double reviseddualsimplex_alphatrigger2 = 0.001; +static ae_int_t reviseddualsimplex_ssinvalid = 0; +static ae_int_t reviseddualsimplex_ssvalidxn = 1; +static ae_int_t reviseddualsimplex_ssvalid = 2; +static ae_int_t reviseddualsimplex_ccfixed = 0; +static ae_int_t reviseddualsimplex_cclower = 1; +static ae_int_t reviseddualsimplex_ccupper = 2; +static ae_int_t reviseddualsimplex_ccrange = 3; +static ae_int_t reviseddualsimplex_ccfree = 4; +static ae_int_t reviseddualsimplex_ccinfeasible = 5; +static void reviseddualsimplex_subprobleminit(ae_int_t n, + dualsimplexsubproblem* s, + ae_state *_state); +static void reviseddualsimplex_subprobleminitphase1(const dualsimplexsubproblem* s0, + const dualsimplexbasis* basis, + dualsimplexsubproblem* s1, + ae_state *_state); +static void reviseddualsimplex_subprobleminitphase3(const dualsimplexsubproblem* s0, + dualsimplexsubproblem* s1, + ae_state *_state); +static void reviseddualsimplex_subprobleminferinitialxn(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_state *_state); +static void reviseddualsimplex_subproblemhandlexnupdate(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_state *_state); +static double reviseddualsimplex_initialdualfeasibilitycorrection(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_shifting(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* alphar, + double delta, + ae_int_t q, + double alpharpiv, + double* thetad, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_pricingstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_bool phase1pricing, + ae_int_t* p, + ae_int_t* r, + double* delta, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_btranstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_int_t r, + dssvector* rhor, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_pivotrowstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* rhor, + dssvector* alphar, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_ftranstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* rhor, + ae_int_t q, + /* Real */ ae_vector* alphaq, + /* Real */ ae_vector* alphaqim, + /* Real */ ae_vector* tau, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_ratiotest(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* alphar, + double delta, + ae_int_t p, + ae_int_t* q, + double* alpharpiv, + double* thetad, + /* Integer */ ae_vector* possibleflips, + ae_int_t* possibleflipscnt, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_updatestep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_int_t p, + ae_int_t q, + ae_int_t r, + double delta, + double alphapiv, + double thetap, + double thetad, + /* Real */ const ae_vector* alphaq, + /* Real */ const ae_vector* alphaqim, + const dssvector* alphar, + /* Real */ const ae_vector* tau, + /* Integer */ const ae_vector* possiblealpharflips, + ae_int_t possiblealpharflipscnt, + const dualsimplexsettings* settings, + ae_state *_state); +static ae_bool reviseddualsimplex_refactorizationrequired(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + ae_int_t q, + double alpharpiv, + ae_int_t r, + double alphaqpiv, + ae_state *_state); +static void reviseddualsimplex_cacheboundinfo(dualsimplexsubproblem* s, + ae_int_t i, + ae_int_t k, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_solvesubproblemdual(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_bool isphase1, + const dualsimplexsettings* settings, + ae_int_t* info, + ae_state *_state); +static void reviseddualsimplex_solvesubproblemprimal(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_int_t* info, + ae_state *_state); +static void reviseddualsimplex_invokephase1(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_dssoptimizewrk(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_solveboxonly(dualsimplexstate* state, + ae_state *_state); +static void reviseddualsimplex_setzeroxystats(dualsimplexstate* state, + ae_state *_state); +static void reviseddualsimplex_basisinit(ae_int_t ns, + ae_int_t m, + dualsimplexbasis* s, + ae_state *_state); +static void reviseddualsimplex_basisclearstats(dualsimplexbasis* s, + ae_state *_state); +static ae_bool reviseddualsimplex_basistryresize(dualsimplexbasis* s, + ae_int_t newm, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state); +static double reviseddualsimplex_basisminimumdiagonalelement(const dualsimplexbasis* s, + ae_state *_state); +static void reviseddualsimplex_basisexportto(const dualsimplexbasis* s0, + dualsimplexbasis* s1, + ae_state *_state); +static ae_bool reviseddualsimplex_basistryimportfrom(dualsimplexbasis* s0, + const dualsimplexbasis* s1, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_basisfreshtrf(dualsimplexbasis* s, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state); +static double reviseddualsimplex_basisfreshtrfunsafe(dualsimplexbasis* s, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_basisrequestweights(dualsimplexbasis* s, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_basisupdatetrf(dualsimplexbasis* s, + const sparsematrix* at, + ae_int_t p, + ae_int_t q, + /* Real */ const ae_vector* alphaq, + /* Real */ const ae_vector* alphaqim, + ae_int_t r, + /* Real */ const ae_vector* tau, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_basissolve(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmpx, + ae_state *_state); +static void reviseddualsimplex_basissolvex(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* xim, + ae_bool needintermediate, + /* Real */ ae_vector* tx, + ae_state *_state); +static void reviseddualsimplex_basissolvet(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tx, + ae_state *_state); +static void reviseddualsimplex_computeanxn(const dualsimplexstate* state, + const dualsimplexsubproblem* subproblem, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +static void reviseddualsimplex_computeantv(const dualsimplexstate* state, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* r, + ae_state *_state); +static ae_bool reviseddualsimplex_hasbndl(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state); +static ae_bool reviseddualsimplex_hasbndu(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state); +static ae_bool reviseddualsimplex_isfree(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state); +static void reviseddualsimplex_downgradestate(dualsimplexsubproblem* subproblem, + ae_int_t s, + ae_state *_state); +static double reviseddualsimplex_dualfeasibilityerror(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + ae_state *_state); +static ae_bool reviseddualsimplex_isdualfeasible(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_pivottobwd(/* Integer */ const ae_vector* p, + ae_int_t m, + /* Integer */ ae_vector* bwd, + ae_state *_state); +static void reviseddualsimplex_inversecyclicpermutation(/* Integer */ ae_vector* bwd, + ae_int_t m, + ae_int_t d, + /* Integer */ ae_vector* tmpi, + ae_state *_state); +static void reviseddualsimplex_offloadbasiccomponents(dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + const dualsimplexsettings* settings, + ae_state *_state); +static void reviseddualsimplex_recombinebasicnonbasicx(dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + ae_state *_state); +static void reviseddualsimplex_setxydstats(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + apbuffers* buffers, + /* Real */ ae_vector* x, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Integer */ ae_vector* stats, + ae_state *_state); +static void reviseddualsimplex_dvalloc(dssvector* x, + ae_int_t n, + ae_state *_state); +static void reviseddualsimplex_dvinit(dssvector* x, + ae_int_t n, + ae_state *_state); +static void reviseddualsimplex_dvdensetosparse(dssvector* x, + ae_state *_state); +static void reviseddualsimplex_dvsparsetodense(dssvector* x, + ae_state *_state); +static double reviseddualsimplex_sparsityof(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +static void reviseddualsimplex_updateavgcounter(double v, + double* acc, + ae_int_t* cnt, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +static ae_int_t lpsolvers_alllogicalsbasis = 0; +static void lpsolvers_clearreportfields(minlpstate* state, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +static void nls_unscalebatch(const nlsstate* state, + /* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Integer */ const ae_vector* idxraw2red, + ae_int_t nreduced, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) +static double gipm2_initrlxpenalty = 1.0; +static double gipm2_rlxsafetyhi = 0.85; +static double gipm2_rlxsafetylo = 0.50; +static double gipm2_initmu = 0.1; +static double gipm2_relaxfactor = 1.0; +static double gipm2_lambdamax = 1.0E6; +static double gipm2_initbigval = 1.0E9; +static double gipm2_initbiggrowth = 1.0E9; +static double gipm2_maxbigval = 1.0E50; +static double gipm2_maxbiggrowth = 1.0E20; +static double gipm2_vggrowth = 1.0E3; +static double gipm2_damptau = 0.0001; +static double gipm2_lambdagrowth = 2.0; +static double gipm2_lambdarapidgrowth = 10.0; +static double gipm2_lambdadecayacc = 0.90; +static ae_int_t gipm2_maxsubsequentfailuresforweakgrowth = 5; +static ae_int_t gipm2_maxrejectedwithineps = 2; +static ae_int_t gipm2_maxrfsits = 5; +static double gipm2_rhstol = (double)100*ae_machineepsilon; +static double gipm2_fractobnd = 0.98; +static double gipm2_smallstep = 1.0E-8; +static double gipm2_tightendist = 5.0; +static double gipm2_middist = 3.0; +static double gipm2_relaxdist = 2.0; +static double gipm2_checkpointacceptancef = 0.000001; +static double gipm2_checkpointacceptanced = 0.999999; +static double gipm2_checkpointacceptancec = 0.999999; +static ae_int_t gipm2_maxsmalltrials = 3; +static double gipm2_dualmeritnu = 1.0; +static ae_int_t gipm2_maxnd = 5; +static void gipm2_varsinitbyzero(gipm2vars* vstate, + ae_int_t np, + ae_int_t mflex, + ae_int_t meq, + ae_int_t mrlxeq, + ae_int_t m1, + ae_int_t mrlx1, + ae_bool hashardbc, + ae_bool hassoftbc, + ae_state *_state); +static void gipm2_multinitbyzero(gipm2mult* vstate, + ae_int_t np, + ae_int_t mflex, + ae_int_t meq, + ae_int_t mrlxeq, + ae_int_t m1, + ae_int_t mrlx1, + ae_bool hashardbc, + ae_bool hassoftbc, + ae_state *_state); +static void gipm2_varsapplystep(gipm2vars* vstate, + const gipm2vars* delta, + double alpha, + ae_state *_state); +static void gipm2_multapplystep(gipm2mult* vstate, + const gipm2mult* delta, + double alpha, + ae_state *_state); +static void gipm2_varscopy(const gipm2vars* src, + gipm2vars* dst, + ae_state *_state); +static void gipm2_multcopy(const gipm2mult* src, + gipm2mult* dst, + ae_state *_state); +static double gipm2_computesteplengthp(const gipm2state* state, + const gipm2vars* current, + const gipm2vars* delta, + ae_state *_state); +static double gipm2_computesteplengthpd(const gipm2state* state, + const gipm2vars* current, + const gipm2vars* delta, + const gipm2mult* currentmult, + const gipm2mult* deltamult, + ae_state *_state); +static void gipm2_computeprimalmult(gipm2state* state, + const gipm2vars* current, + double currentmu, + gipm2mult* mult, + ae_state *_state); +static void gipm2_computerp(gipm2state* state, + const gipm2vars* current, + double currentmu, + const gipm2mult* mult, + /* Real */ ae_vector* rp, + ae_state *_state); +static void gipm2_computerhs(gipm2state* state, + const gipm2vars* current, + double currentmu, + const gipm2mult* currentmult, + gipm2rhs* rhs, + double* epriminf, + double* edualinf, + double* ecmplinf, + double* sprim, + double* sdual, + double* scmpl, + ae_state *_state); +static double gipm2_computeecmpl2(const gipm2state* state, + const gipm2rhs* rhs, + ae_state *_state); +static void gipm2_copyrhs(const gipm2state* state, + const gipm2rhs* src, + gipm2rhs* dst, + ae_state *_state); +static double gipm2_computedg(const gipm2state* state, + const gipm2vars* delta, + const gipm2rhs* rhs, + ae_state *_state); +static double gipm2_computeupdateresidual(gipm2state* state, + const gipm2vars* current, + const gipm2mult* multlhs, + double currentmu, + double currentdiag, + const gipm2vars* delta, + const gipm2mult* deltamult, + /* Real */ const ae_vector* hdxp, + /* Real */ const ae_vector* jdxp, + /* Real */ const ae_vector* jtdy, + gipm2rhs* rhs, + ae_state *_state); +static void gipm2_condenselhs(const gipm2state* state, + const gipm2vars* current, + const gipm2mult* currentmult, + double currentmu, + double currentdiag, + gipm2condensedsystem* c, + ae_state *_state); +static void gipm2_condenserhs(const gipm2state* state, + const gipm2vars* currentvars, + const gipm2mult* currentmult, + const gipm2rhs* rhs, + double currentmu, + double currentdiag, + gipm2condensedsystem* c, + ae_state *_state); +static void gipm2_unpacksolution(const gipm2state* state, + const gipm2vars* currentvars, + const gipm2mult* multlhs, + double currentmu, + double currentdiag, + const gipm2rhs* rhs, + gipm2condensedsystem* c, + /* Real */ const ae_vector* replysol, + gipm2vars* delta, + gipm2mult* deltamult, + ae_state *_state); +static double gipm2_meritfunction(const gipm2state* state, + const gipm2vars* current, + double currentmu, + ae_state *_state); +static double gipm2_meritfunctionpd(const gipm2state* state, + const gipm2vars* current, + const gipm2mult* currentmult, + double currentmu, + ae_state *_state); +static void gipm2_safeboundsfromfinitetightened(gipm2state* state, + ae_state *_state); +static void gipm2_tunepenalties(gipm2state* state, + const gipm2mult* currentmult, + ae_state *_state); +static double gipm2_tgtrlxbndl(double vx, + double vxnrm, + double wrkbndl, + double truebndl, + ae_int_t* ntightened, + ae_int_t* nrelaxed, + ae_state *_state); +static double gipm2_tgtrlxbndu(double vx, + double vxnrm, + double wrkbndu, + double truebndu, + ae_int_t* ntightened, + ae_int_t* nrelaxed, + ae_state *_state); +static void gipm2_tightenrelaxbounds(gipm2state* state, ae_state *_state); +static void gipm2_updateerrorestimates(gipm2state* state, + ae_state *_state); +static void gipm2_sendx(gipm2state* state, + /* Real */ const ae_vector* xs, + ae_state *_state); +static void gipm2_sendlagrangianinfo(gipm2state* state, + gipm2vars* current, + gipm2mult* curmult, + gipm2vars* cand, + gipm2mult* candmult, + ae_bool usebestmult, + ae_state *_state); +static void gipm2_lagcoeffsfrommultipliers(const gipm2mult* mult, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagnlc, + ae_state *_state); +static ae_bool gipm2_retrievefij(const gipm2state* state, + gipm2vars* vfj, + ae_state *_state); +static void gipm2_nonmonotonicinit(gipm2state* state, + ae_int_t memlen, + double merit0, + ae_state *_state); +static void gipm2_nonmonotonicpush(gipm2state* state, + double meritv, + ae_state *_state); +static double gipm2_nonmonotonicgetcorr(gipm2state* state, + double meritv, + ae_state *_state); +static void gipm2_rescalecurrentbest(gipm2state* state, + /* Real */ const ae_vector* rescaleby, + ae_bool rescalebest, + ae_state *_state); +static double gipm2_aggregateerr(double p, + double d, + double c, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) +static double nlcgipm2_mupromote = 10.0; +static ae_int_t nlcgipm2_xbfgsmemlen = 32; +static double nlcgipm2_xbfgsmaxhess = 1.0E6; +static double nlcgipm2_smallscaledecrease = 0.5; +static double nlcgipm2_maxrescale = 10.0; +static double nlcgipm2_minrescale = 0.1; +static double nlcgipm2_autoscalerhessdecay = 0.9; +static double nlcgipm2_maxhessnrm = 100.0; +static void nlcgipm2_savepointaslast(nlpgipm2state* state, + double rawf0, + ae_state *_state); +static void nlcgipm2_lastpointasbase(nlpgipm2state* state, + /* Real */ const ae_vector* querydata, + ae_state *_state); +static void nlcgipm2_basepointasbest(nlpgipm2state* state, + ae_state *_state); +static void nlcgipm2_restorebestpoint(nlpgipm2state* state, + ae_state *_state); +static void nlcgipm2_factorizematrix(nlpgipm2state* state, + ae_state *_state); +static void nlcgipm2_solvesystem(nlpgipm2state* state, ae_state *_state); +static void nlcgipm2_matrixvector(nlpgipm2state* state, ae_state *_state); +static void nlcgipm2_autoscaleinit(nlpgipm2state* state, ae_state *_state); +static void nlcgipm2_autoscaletargetconstraints(nlpgipm2state* state, + ae_state *_state); +static void nlcgipm2_applyrescale(/* Real */ ae_vector* fi, + sparsematrix* sj, + ae_int_t idx, + double multiplyby, + ae_state *_state); +static void nlcgipm2_generatesparsesys(nlpgipm2state* state, + const sparsematrix* upcomingsj, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +static double minbleic_gtol = 0.4; +static double minbleic_maxnonmonotoniclen = 1.0E-7; +static double minbleic_initialdecay = 0.5; +static double minbleic_mindecay = 0.1; +static double minbleic_decaycorrection = 0.8; +static double minbleic_penaltyfactor = 100; +static void minbleic_clearrequestfields(minbleicstate* state, + ae_state *_state); +static void minbleic_minbleicinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbleicstate* state, + ae_state *_state); +static void minbleic_updateestimateofgoodstep(double* estimate, + double newstep, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +static void minnlc_clearrequestfields(minnlcstate* state, + ae_state *_state); +static void minnlc_minnlcinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnlcstate* state, + ae_state *_state); +static void minnlc_unscale(const minnlcstate* state, + /* Real */ const ae_vector* xs, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state); +static void minnlc_crsfromdense(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +static void minnlc_crsfromdensev(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state); +static void minnlc_unscalebatch(const minnlcstate* state, + /* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Integer */ const ae_vector* idxraw2red, + ae_int_t nreduced, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) +static void monbi_clearrequestfields(nbistate* state, ae_state *_state); +static void monbi_setnlcalgo(minnlcstate* s, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +static void minmo_clearrequestfields(minmostate* state, ae_state *_state); +static void minmo_minmoinitinternal(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minmostate* state, + ae_state *_state); +static void minmo_unscale(const minmostate* state, + /* Real */ const ae_vector* xs, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +static void minns_clearrequestfields(minnsstate* state, ae_state *_state); +static void minns_minnsinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnsstate* state, + ae_state *_state); +static ae_bool minns_agsiteration(minnsstate* state, ae_state *_state); +static void minns_unscalepointbc(const minnsstate* state, + /* Real */ ae_vector* x, + ae_state *_state); +static void minns_solveqp(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ ae_vector* coeffs, + ae_int_t* dbgncholesky, + minnsqp* state, + ae_state *_state); +static void minns_qpcalculategradfunc(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ const ae_vector* coeffs, + /* Real */ ae_vector* g, + double* f, + /* Real */ ae_vector* tmp, + ae_state *_state); +static void minns_qpcalculatefunc(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ const ae_vector* coeffs, + double* f, + /* Real */ ae_vector* tmp, + ae_state *_state); +static void minns_qpsolveu(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); +static void minns_qpsolveut(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +static ae_int_t mincomp_n1 = 2; +static ae_int_t mincomp_n2 = 2; +static double mincomp_stpmin = 1.0E-300; +static double mincomp_gtol = 0.3; +static double mincomp_gpaftol = 0.0001; +static double mincomp_gpadecay = 0.5; +static double mincomp_asarho = 0.5; +static double mincomp_asaboundedantigradnorm(const minasastate* state, + ae_state *_state); +static double mincomp_asaginorm(const minasastate* state, + ae_state *_state); +static double mincomp_asad1norm(const minasastate* state, + ae_state *_state); +static ae_bool mincomp_asauisempty(const minasastate* state, + ae_state *_state); +static void mincomp_clearrequestfields(minasastate* state, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +static double minbc_gtol = 0.4; +static double minbc_maxnonmonotoniclen = 1.0E-5; +static double minbc_initialdecay = 0.5; +static double minbc_mindecay = 0.1; +static double minbc_decaycorrection = 0.8; +static void minbc_clearrequestfields(minbcstate* state, ae_state *_state); +static void minbc_minbcinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbcstate* state, + ae_state *_state); +static void minbc_updateestimateofgoodstep(double* estimate, + double newstep, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine initializes "internal" OptGuard report, i.e. one intended +for internal use by optimizers. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void optguardinitinternal(optguardreport* rep, + ae_int_t n, + ae_int_t k, + ae_state *_state) +{ + + + rep->nonc0suspected = ae_false; + rep->nonc0test0positive = ae_false; + rep->nonc0lipschitzc = (double)(0); + rep->nonc0fidx = -1; + rep->nonc1suspected = ae_false; + rep->nonc1test0positive = ae_false; + rep->nonc1test1positive = ae_false; + rep->nonc1lipschitzc = (double)(0); + rep->nonc1fidx = -1; + rep->badgradsuspected = ae_false; + rep->badgradfidx = -1; + rep->badgradvidx = -1; +} + + +/************************************************************************* +This subroutine exports report to user-readable representation (all arrays +are forced to have exactly same size as needed; unused arrays are set to +zero length). + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void optguardexportreport(const optguardreport* srcrep, + ae_int_t n, + ae_int_t k, + ae_bool badgradhasxj, + optguardreport* dstrep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + dstrep->nonc0suspected = srcrep->nonc0suspected; + dstrep->nonc0test0positive = srcrep->nonc0test0positive; + if( srcrep->nonc0suspected ) + { + dstrep->nonc0lipschitzc = srcrep->nonc0lipschitzc; + dstrep->nonc0fidx = srcrep->nonc0fidx; + } + else + { + dstrep->nonc0lipschitzc = (double)(0); + dstrep->nonc0fidx = -1; + } + dstrep->nonc1suspected = srcrep->nonc1suspected; + dstrep->nonc1test0positive = srcrep->nonc1test0positive; + dstrep->nonc1test1positive = srcrep->nonc1test1positive; + if( srcrep->nonc1suspected ) + { + dstrep->nonc1lipschitzc = srcrep->nonc1lipschitzc; + dstrep->nonc1fidx = srcrep->nonc1fidx; + } + else + { + dstrep->nonc1lipschitzc = (double)(0); + dstrep->nonc1fidx = -1; + } + dstrep->badgradsuspected = srcrep->badgradsuspected; + if( srcrep->badgradsuspected ) + { + dstrep->badgradfidx = srcrep->badgradfidx; + dstrep->badgradvidx = srcrep->badgradvidx; + } + else + { + dstrep->badgradfidx = -1; + dstrep->badgradvidx = -1; + } + if( badgradhasxj ) + { + ae_vector_set_length(&dstrep->badgradxbase, n, _state); + for(j=0; j<=n-1; j++) + { + dstrep->badgradxbase.ptr.p_double[j] = srcrep->badgradxbase.ptr.p_double[j]; + } + ae_matrix_set_length(&dstrep->badgraduser, k, n, _state); + ae_matrix_set_length(&dstrep->badgradnum, k, n, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + dstrep->badgraduser.ptr.pp_double[i][j] = srcrep->badgraduser.ptr.pp_double[i][j]; + dstrep->badgradnum.ptr.pp_double[i][j] = srcrep->badgradnum.ptr.pp_double[i][j]; + } + } + } + else + { + ae_vector_set_length(&dstrep->badgradxbase, 0, _state); + ae_matrix_set_length(&dstrep->badgraduser, 0, 0, _state); + ae_matrix_set_length(&dstrep->badgradnum, 0, 0, _state); + } +} + + +/************************************************************************* +This subroutine exports report to user-readable representation (all arrays +are forced to have exactly same size as needed; unused arrays are set to +zero length). + +NOTE: we assume that SrcRep contains scaled X0[] and D[], i.e. explicit + variable scaling was applied. We need to rescale them during export, + that's why we need S[] parameter. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorexportc1test0report(const optguardnonc1test0report* srcrep, + /* Real */ const ae_vector* s, + optguardnonc1test0report* dstrep, + ae_state *_state) +{ + ae_int_t i; + + + dstrep->positive = srcrep->positive; + if( srcrep->positive ) + { + dstrep->stpidxa = srcrep->stpidxa; + dstrep->stpidxb = srcrep->stpidxb; + dstrep->inneriter = srcrep->inneriter; + dstrep->outeriter = srcrep->outeriter; + dstrep->fidx = srcrep->fidx; + dstrep->cnt = srcrep->cnt; + dstrep->n = srcrep->n; + ae_vector_set_length(&dstrep->x0, srcrep->n, _state); + ae_vector_set_length(&dstrep->d, srcrep->n, _state); + for(i=0; i<=srcrep->n-1; i++) + { + dstrep->x0.ptr.p_double[i] = srcrep->x0.ptr.p_double[i]*s->ptr.p_double[i]; + dstrep->d.ptr.p_double[i] = srcrep->d.ptr.p_double[i]*s->ptr.p_double[i]; + } + ae_vector_set_length(&dstrep->stp, srcrep->cnt, _state); + ae_vector_set_length(&dstrep->f, srcrep->cnt, _state); + for(i=0; i<=srcrep->cnt-1; i++) + { + dstrep->stp.ptr.p_double[i] = srcrep->stp.ptr.p_double[i]; + dstrep->f.ptr.p_double[i] = srcrep->f.ptr.p_double[i]; + } + } + else + { + dstrep->stpidxa = -1; + dstrep->stpidxb = -1; + dstrep->inneriter = -1; + dstrep->outeriter = -1; + dstrep->fidx = -1; + dstrep->cnt = 0; + dstrep->n = 0; + ae_vector_set_length(&dstrep->x0, 0, _state); + ae_vector_set_length(&dstrep->d, 0, _state); + ae_vector_set_length(&dstrep->stp, 0, _state); + ae_vector_set_length(&dstrep->f, 0, _state); + } +} + + +/************************************************************************* +This subroutine exports report to user-readable representation (all arrays +are forced to have exactly same size as needed; unused arrays are set to +zero length). + +NOTE: we assume that SrcRep contains scaled X0[], D[] and G[], i.e. explicit + variable scaling was applied. We need to rescale them during export, + that's why we need S[] parameter. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorexportc1test1report(const optguardnonc1test1report* srcrep, + /* Real */ const ae_vector* s, + optguardnonc1test1report* dstrep, + ae_state *_state) +{ + ae_int_t i; + + + dstrep->positive = srcrep->positive; + if( srcrep->positive ) + { + ae_assert(srcrep->vidx>=0&&srcrep->vidxn, "SmoothnessMonitorExportC1Test1Report: integrity check failed", _state); + dstrep->stpidxa = srcrep->stpidxa; + dstrep->stpidxb = srcrep->stpidxb; + dstrep->inneriter = srcrep->inneriter; + dstrep->outeriter = srcrep->outeriter; + dstrep->fidx = srcrep->fidx; + dstrep->vidx = srcrep->vidx; + dstrep->cnt = srcrep->cnt; + dstrep->n = srcrep->n; + ae_vector_set_length(&dstrep->x0, srcrep->n, _state); + ae_vector_set_length(&dstrep->d, srcrep->n, _state); + for(i=0; i<=srcrep->n-1; i++) + { + dstrep->x0.ptr.p_double[i] = srcrep->x0.ptr.p_double[i]*s->ptr.p_double[i]; + dstrep->d.ptr.p_double[i] = srcrep->d.ptr.p_double[i]*s->ptr.p_double[i]; + } + ae_vector_set_length(&dstrep->stp, srcrep->cnt, _state); + ae_vector_set_length(&dstrep->g, srcrep->cnt, _state); + for(i=0; i<=srcrep->cnt-1; i++) + { + dstrep->stp.ptr.p_double[i] = srcrep->stp.ptr.p_double[i]; + dstrep->g.ptr.p_double[i] = srcrep->g.ptr.p_double[i]/s->ptr.p_double[srcrep->vidx]; + } + } + else + { + dstrep->stpidxa = -1; + dstrep->stpidxb = -1; + dstrep->inneriter = -1; + dstrep->outeriter = -1; + dstrep->fidx = -1; + dstrep->vidx = -1; + dstrep->cnt = 0; + dstrep->n = 0; + ae_vector_set_length(&dstrep->x0, 0, _state); + ae_vector_set_length(&dstrep->d, 0, _state); + ae_vector_set_length(&dstrep->stp, 0, _state); + ae_vector_set_length(&dstrep->g, 0, _state); + } +} + + +/************************************************************************* +Returns True when all flags are clear. Intended for easy coding of unit +tests. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +ae_bool optguardallclear(const optguardreport* rep, ae_state *_state) +{ + ae_bool result; + + + result = !((rep->badgradsuspected||rep->nonc0suspected)||rep->nonc1suspected); + return result; +} + + +void _optguardreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + optguardreport *p = (optguardreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->badgradxbase, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->badgraduser, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->badgradnum, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _optguardreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + optguardreport *dst = (optguardreport*)_dst; + const optguardreport *src = (const optguardreport*)_src; + dst->nonc0suspected = src->nonc0suspected; + dst->nonc0test0positive = src->nonc0test0positive; + dst->nonc0fidx = src->nonc0fidx; + dst->nonc0lipschitzc = src->nonc0lipschitzc; + dst->nonc1suspected = src->nonc1suspected; + dst->nonc1test0positive = src->nonc1test0positive; + dst->nonc1test1positive = src->nonc1test1positive; + dst->nonc1fidx = src->nonc1fidx; + dst->nonc1lipschitzc = src->nonc1lipschitzc; + dst->badgradsuspected = src->badgradsuspected; + dst->badgradfidx = src->badgradfidx; + dst->badgradvidx = src->badgradvidx; + ae_vector_init_copy(&dst->badgradxbase, &src->badgradxbase, _state, make_automatic); + ae_matrix_init_copy(&dst->badgraduser, &src->badgraduser, _state, make_automatic); + ae_matrix_init_copy(&dst->badgradnum, &src->badgradnum, _state, make_automatic); +} + + +void _optguardreport_clear(void* _p) +{ + optguardreport *p = (optguardreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->badgradxbase); + ae_matrix_clear(&p->badgraduser); + ae_matrix_clear(&p->badgradnum); +} + + +void _optguardreport_destroy(void* _p) +{ + optguardreport *p = (optguardreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->badgradxbase); + ae_matrix_destroy(&p->badgraduser); + ae_matrix_destroy(&p->badgradnum); +} + + +void _optguardnonc0report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc0report *p = (optguardnonc0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic); +} + + +void _optguardnonc0report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc0report *dst = (optguardnonc0report*)_dst; + const optguardnonc0report *src = (const optguardnonc0report*)_src; + dst->positive = src->positive; + dst->fidx = src->fidx; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->n = src->n; + ae_vector_init_copy(&dst->stp, &src->stp, _state, make_automatic); + ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic); + dst->cnt = src->cnt; + dst->stpidxa = src->stpidxa; + dst->stpidxb = src->stpidxb; + dst->inneriter = src->inneriter; + dst->outeriter = src->outeriter; +} + + +void _optguardnonc0report_clear(void* _p) +{ + optguardnonc0report *p = (optguardnonc0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->d); + ae_vector_clear(&p->stp); + ae_vector_clear(&p->f); +} + + +void _optguardnonc0report_destroy(void* _p) +{ + optguardnonc0report *p = (optguardnonc0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->stp); + ae_vector_destroy(&p->f); +} + + +void _optguardnonc1test0report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc1test0report *p = (optguardnonc1test0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic); +} + + +void _optguardnonc1test0report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc1test0report *dst = (optguardnonc1test0report*)_dst; + const optguardnonc1test0report *src = (const optguardnonc1test0report*)_src; + dst->positive = src->positive; + dst->fidx = src->fidx; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->n = src->n; + ae_vector_init_copy(&dst->stp, &src->stp, _state, make_automatic); + ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic); + dst->cnt = src->cnt; + dst->stpidxa = src->stpidxa; + dst->stpidxb = src->stpidxb; + dst->inneriter = src->inneriter; + dst->outeriter = src->outeriter; +} + + +void _optguardnonc1test0report_clear(void* _p) +{ + optguardnonc1test0report *p = (optguardnonc1test0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->d); + ae_vector_clear(&p->stp); + ae_vector_clear(&p->f); +} + + +void _optguardnonc1test0report_destroy(void* _p) +{ + optguardnonc1test0report *p = (optguardnonc1test0report*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->stp); + ae_vector_destroy(&p->f); +} + + +void _optguardnonc1test1report_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc1test1report *p = (optguardnonc1test1report*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); +} + + +void _optguardnonc1test1report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + optguardnonc1test1report *dst = (optguardnonc1test1report*)_dst; + const optguardnonc1test1report *src = (const optguardnonc1test1report*)_src; + dst->positive = src->positive; + dst->fidx = src->fidx; + dst->vidx = src->vidx; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->n = src->n; + ae_vector_init_copy(&dst->stp, &src->stp, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->cnt = src->cnt; + dst->stpidxa = src->stpidxa; + dst->stpidxb = src->stpidxb; + dst->inneriter = src->inneriter; + dst->outeriter = src->outeriter; +} + + +void _optguardnonc1test1report_clear(void* _p) +{ + optguardnonc1test1report *p = (optguardnonc1test1report*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->d); + ae_vector_clear(&p->stp); + ae_vector_clear(&p->g); +} + + +void _optguardnonc1test1report_destroy(void* _p) +{ + optguardnonc1test1report *p = (optguardnonc1test1report*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->stp); + ae_vector_destroy(&p->g); +} + + +#endif +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initialize test LP problem. + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemcreate(ae_int_t n, + ae_bool hasknowntarget, + double targetf, + lptestproblem* p, + ae_state *_state) +{ + + _lptestproblem_clear(p); + + ae_assert(n>=1, "LPTestProblemCreate: N<1", _state); + p->n = n; + p->hasknowntarget = hasknowntarget; + if( hasknowntarget ) + { + p->targetf = targetf; + } + else + { + p->targetf = _state->v_nan; + } + ae_vector_set_length(&p->s, n, _state); + rsetv(n, 1.0, &p->s, _state); + ae_vector_set_length(&p->c, n, _state); + rsetv(n, 0.0, &p->c, _state); + ae_vector_set_length(&p->bndl, n, _state); + rsetv(n, 0.0, &p->bndl, _state); + ae_vector_set_length(&p->bndu, n, _state); + rsetv(n, 0.0, &p->bndu, _state); + p->m = 0; + ae_vector_set_length(&p->al, 0, _state); + ae_vector_set_length(&p->au, 0, _state); +} + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_bool lptestproblemhasknowntarget(lptestproblem* p, ae_state *_state) +{ + ae_bool result; + + + result = p->hasknowntarget; + return result; +} + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +double lptestproblemgettargetf(lptestproblem* p, ae_state *_state) +{ + double result; + + + result = p->targetf; + return result; +} + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetn(lptestproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->n; + return result; +} + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetm(lptestproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->m; + return result; +} + + +/************************************************************************* +Set scale for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetscale(lptestproblem* p, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + + + rcopyv(p->n, s, &p->s, _state); +} + + +/************************************************************************* +Set cost for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetcost(lptestproblem* p, + /* Real */ const ae_vector* c, + ae_state *_state) +{ + + + rcopyv(p->n, c, &p->c, _state); +} + + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetbc(lptestproblem* p, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + + + rcopyv(p->n, bndl, &p->bndl, _state); + rcopyv(p->n, bndu, &p->bndu, _state); +} + + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetlc2(lptestproblem* p, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t m, + ae_state *_state) +{ + + + if( m<=0 ) + { + p->m = 0; + return; + } + ae_assert(sparsegetnrows(a, _state)==m, "LPTestProblemSetLC2: rows(A)<>M", _state); + p->m = m; + sparsecopytocrs(a, &p->a, _state); + ae_vector_set_length(&p->al, m, _state); + ae_vector_set_length(&p->au, m, _state); + rcopyv(m, al, &p->al, _state); + rcopyv(m, au, &p->au, _state); +} + + +/************************************************************************* +Serializer: allocation + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemalloc(ae_serializer* s, + const lptestproblem* p, + ae_state *_state) +{ + + + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + ae_serializer_alloc_entry(s); + allocrealarray(s, &p->s, p->n, _state); + allocrealarray(s, &p->c, p->n, _state); + allocrealarray(s, &p->bndl, p->n, _state); + allocrealarray(s, &p->bndu, p->n, _state); + ae_serializer_alloc_entry(s); + if( p->m>0 ) + { + sparsealloc(s, &p->a, _state); + allocrealarray(s, &p->al, p->m, _state); + allocrealarray(s, &p->au, p->m, _state); + } + ae_serializer_alloc_entry(s); +} + + +/************************************************************************* +Serializer: serialization + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemserialize(ae_serializer* s, + const lptestproblem* p, + ae_state *_state) +{ + + + ae_serializer_serialize_int(s, getlptestserializationcode(_state), _state); + ae_serializer_serialize_int(s, 0, _state); + ae_serializer_serialize_int(s, p->n, _state); + ae_serializer_serialize_bool(s, p->hasknowntarget, _state); + ae_serializer_serialize_double(s, p->targetf, _state); + serializerealarray(s, &p->s, p->n, _state); + serializerealarray(s, &p->c, p->n, _state); + serializerealarray(s, &p->bndl, p->n, _state); + serializerealarray(s, &p->bndu, p->n, _state); + ae_serializer_serialize_int(s, p->m, _state); + if( p->m>0 ) + { + sparseserialize(s, &p->a, _state); + serializerealarray(s, &p->al, p->m, _state); + serializerealarray(s, &p->au, p->m, _state); + } + ae_serializer_serialize_int(s, 872, _state); +} + + +/************************************************************************* +Serializer: unserialization + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemunserialize(ae_serializer* s, + lptestproblem* p, + ae_state *_state) +{ + ae_int_t k; + + _lptestproblem_clear(p); + + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==getlptestserializationcode(_state), "LPTestProblemUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==0, "LPTestProblemUnserialize: stream header corrupted", _state); + ae_serializer_unserialize_int(s, &p->n, _state); + ae_serializer_unserialize_bool(s, &p->hasknowntarget, _state); + ae_serializer_unserialize_double(s, &p->targetf, _state); + unserializerealarray(s, &p->s, _state); + unserializerealarray(s, &p->c, _state); + unserializerealarray(s, &p->bndl, _state); + unserializerealarray(s, &p->bndu, _state); + ae_serializer_unserialize_int(s, &p->m, _state); + if( p->m>0 ) + { + sparseunserialize(s, &p->a, _state); + unserializerealarray(s, &p->al, _state); + unserializerealarray(s, &p->au, _state); + } + ae_serializer_unserialize_int(s, &k, _state); + ae_assert(k==872, "LPTestProblemUnserialize: end-of-stream marker not found", _state); +} + + +/************************************************************************* +Returns objective type: True for zero/linear/constant. + +Present version does not return False. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool qpxproblemisquadraticobjective(qpxproblem* p, ae_state *_state) +{ + ae_bool result; + + + result = ae_true; + return result; +} + + +/************************************************************************* +Get variables count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetn(qpxproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->n; + return result; +} + + +/************************************************************************* +Get linear constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmlc(qpxproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->mlc; + return result; +} + + +/************************************************************************* +Get quadratic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmqc(qpxproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->mqc; + return result; +} + + +/************************************************************************* +Get conic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmcc(qpxproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->mcc; + return result; +} + + +/************************************************************************* +Get total constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgettotalconstraints(qpxproblem* p, ae_state *_state) +{ + ae_int_t result; + + + result = p->mlc+p->mqc+p->mcc; + return result; +} + + +/************************************************************************* +Get initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetinitialpoint(qpxproblem* p, + /* Real */ ae_vector* x0, + ae_state *_state) +{ + + ae_vector_clear(x0); + + if( p->hasinitialpoint ) + { + rcopyallocv(p->n, &p->x0, x0, _state); + } + else + { + rsetallocv(p->n, 1.0, x0, _state); + } +} + + +/************************************************************************* +Get initial point presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool qpxproblemhasinitialpoint(qpxproblem* p, ae_state *_state) +{ + ae_bool result; + + + result = p->hasinitialpoint; + return result; +} + + +/************************************************************************* +Get scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetscale(qpxproblem* p, + /* Real */ ae_vector* s, + ae_state *_state) +{ + + ae_vector_clear(s); + + if( p->hasscale ) + { + rcopyallocv(p->n, &p->s, s, _state); + } + else + { + rsetallocv(p->n, 1.0, s, _state); + } +} + + +/************************************************************************* +Get scale presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool qpxproblemhasscale(qpxproblem* p, ae_state *_state) +{ + ae_bool result; + + + result = p->hasscale; + return result; +} + + +/************************************************************************* +Get origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetorigin(qpxproblem* p, + /* Real */ ae_vector* xorigin, + ae_state *_state) +{ + + ae_vector_clear(xorigin); + + if( p->hasorigin ) + { + rcopyallocv(p->n, &p->xorigin, xorigin, _state); + } + else + { + rsetallocv(p->n, 0.0, xorigin, _state); + } +} + + +/************************************************************************* +Get origin presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool qpxproblemhasorigin(qpxproblem* p, ae_state *_state) +{ + ae_bool result; + + + result = p->hasorigin; + return result; +} + + +/************************************************************************* +Get linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlinearterm(qpxproblem* p, + /* Real */ ae_vector* c, + ae_state *_state) +{ + + ae_vector_clear(c); + + rcopyallocv(p->n, &p->c, c, _state); +} + + +/************************************************************************* +Get quadratic term, returns zero matrix if no quadratic term is present + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetquadraticterm(qpxproblem* p, + sparsematrix* q, + ae_bool* isupper, + ae_state *_state) +{ + + _sparsematrix_clear(q); + *isupper = ae_false; + + if( !p->hasq ) + { + q->matrixtype = 1; + q->m = p->n; + q->n = p->n; + q->ninitialized = 0; + isetallocv(p->n, 0, &q->didx, _state); + isetallocv(p->n, 0, &q->uidx, _state); + isetallocv(p->n+1, 0, &q->ridx, _state); + *isupper = ae_false; + return; + } + *isupper = p->isupperq; + sparsecopybuf(&p->q, q, _state); +} + + +/************************************************************************* +Returns False if no quadratic term was specified, or quadratic term is +numerically zero. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool qpxproblemhasquadraticterm(qpxproblem* p, ae_state *_state) +{ + ae_bool result; + + + if( !p->hasq ) + { + result = ae_false; + return result; + } + result = p->q.ridx.ptr.p_int[p->n]>0; + return result; +} + + +/************************************************************************* +Get box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetbc(qpxproblem* p, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + ae_state *_state) +{ + + ae_vector_clear(bndl); + ae_vector_clear(bndu); + + rcopyallocv(p->n, &p->bndl, bndl, _state); + rcopyallocv(p->n, &p->bndu, bndu, _state); +} + + +/************************************************************************* +Get linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlc2(qpxproblem* p, + sparsematrix* a, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t* m, + ae_state *_state) +{ + + _sparsematrix_clear(a); + ae_vector_clear(al); + ae_vector_clear(au); + *m = 0; + + if( p->mlc==0 ) + { + *m = 0; + return; + } + *m = p->mlc; + sparsecopybuf(&p->a, a, _state); + rcopyallocv(*m, &p->al, al, _state); + rcopyallocv(*m, &p->au, au, _state); +} + + +/************************************************************************* +Passes entire set of quadratic constraints, overwriting internally +stored ones. + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemsetxqc(qpxproblem* p, + xquadraticconstraints* src, + ae_state *_state) +{ + + + xqccopy(src, &p->qc, _state); + p->mqc = xqcgetcount(&p->qc, _state); +} + + +/************************************************************************* +Get IDX-th two-sided quadratic constraint, same format as minqpaddqc2(), +except for the fact that it always returns isUpper=False, even if the +original matrix was an upper triangular one. + +NOTE: this function is not optimized for big matrices. Whilst still having + O(max(N,Nonzeros)) running time, it may be somewhat slow due to + dynamic structures being used internally. + + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetqc2i(qpxproblem* p, + ae_int_t idx, + sparsematrix* q, + ae_bool* isupper, + /* Real */ ae_vector* b, + double* cl, + double* cu, + ae_bool* applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t j; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + _sparsematrix_clear(q); + *isupper = ae_false; + ae_vector_clear(b); + *cl = 0.0; + *cu = 0.0; + *applyorigin = ae_false; + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + + ae_assert(idx>=0&&idxmqc, "QPXProblemGetQC2i: Idx is outside of [0,MQC) range", _state); + ae_obj_array_get(&p->qc.constraints, idx, &_qci, _state); + if( qci->nvars==0 ) + { + q->matrixtype = 1; + q->m = p->n; + q->n = p->n; + q->ninitialized = 0; + isetallocv(p->n, 0, &q->didx, _state); + isetallocv(p->n, 0, &q->uidx, _state); + isetallocv(p->n+1, 0, &q->ridx, _state); + *isupper = ae_false; + rsetallocv(p->n, 0.0, b, _state); + *cl = qci->cl; + *cu = qci->cu; + *applyorigin = qci->applyorigin; + ae_frame_leave(_state); + return; + } + sparsecreatebuf(p->n, p->n, qci->lowerq.ridx.ptr.p_int[qci->nvars], q, _state); + for(i=0; i<=qci->nvars-1; i++) + { + j0 = qci->lowerq.ridx.ptr.p_int[i]; + j1 = qci->lowerq.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = qci->lowerq.idx.ptr.p_int[jj]; + v = qci->lowerq.vals.ptr.p_double[jj]; + sparseset(q, qci->varidx.ptr.p_int[i], qci->varidx.ptr.p_int[j], v, _state); + } + } + sparseconverttocrs(q, _state); + *isupper = ae_false; + rsetallocv(p->n, 0.0, b, _state); + for(i=0; i<=qci->nvars-1; i++) + { + b->ptr.p_double[qci->varidx.ptr.p_int[i]] = qci->b.ptr.p_double[i]; + } + *cl = qci->cl; + *cu = qci->cu; + *applyorigin = qci->applyorigin; + ae_frame_leave(_state); +} + + +/************************************************************************* +Copies quadratic constraints structure, target structure is cleared, +previously allocated memory is ignored. +*************************************************************************/ +void xqccopy(xquadraticconstraints* src, + xquadraticconstraints* dst, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t m; + xquadraticconstraint *c; + ae_smart_ptr _c; + xquadraticconstraint *c1; + ae_smart_ptr _c1; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + memset(&_c1, 0, sizeof(_c1)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + ae_smart_ptr_init(&_c1, (void**)&c1, ae_false, _state, ae_true); + + dst->n = src->n; + m = ae_obj_array_get_length(&src->constraints); + ae_obj_array_clear(&dst->constraints); + for(i=0; i<=m-1; i++) + { + ae_obj_array_get(&src->constraints, i, &_c, _state); + c1 = (xquadraticconstraint*)ae_malloc(sizeof(xquadraticconstraint), _state); /* note: using c1 as a temporary prior to assigning its value to _c1 */ + memset(c1, 0, sizeof(xquadraticconstraint)); + _xquadraticconstraint_init(c1, _state, ae_false); + ae_smart_ptr_assign(&_c1, c1, ae_true, ae_true, (ae_int_t)sizeof(xquadraticconstraint), _xquadraticconstraint_init_copy, _xquadraticconstraint_destroy); + c1->nvars = c->nvars; + c1->cl = c->cl; + c1->cu = c->cu; + c1->applyorigin = c->applyorigin; + if( c->nvars>0 ) + { + icopyallocv(c->nvars, &c->varidx, &c1->varidx, _state); + rcopyallocv(c->nvars, &c->b, &c1->b, _state); + sparsecopybuf(&c->lowerq, &c1->lowerq, _state); + } + ae_obj_array_append_transfer(&dst->constraints, &_c1, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Get constraints count +*************************************************************************/ +ae_int_t xqcgetcount(const xquadraticconstraints* xqc, ae_state *_state) +{ + ae_int_t result; + + + result = ae_obj_array_get_length(&xqc->constraints); + return result; +} + + +void _xlinearconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xlinearconstraints *p = (xlinearconstraints*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->densec, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsec, _state, make_automatic); + ae_vector_init(&p->dcl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dcu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->lcsrcmult, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->effsparsea, _state, make_automatic); + ae_vector_init(&p->effal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effau, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps, _state, make_automatic); +} + + +void _xlinearconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xlinearconstraints *dst = (xlinearconstraints*)_dst; + const xlinearconstraints *src = (const xlinearconstraints*)_src; + dst->n = src->n; + dst->ndense = src->ndense; + dst->nsparse = src->nsparse; + ae_matrix_init_copy(&dst->densec, &src->densec, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsec, &src->sparsec, _state, make_automatic); + ae_vector_init_copy(&dst->dcl, &src->dcl, _state, make_automatic); + ae_vector_init_copy(&dst->dcu, &src->dcu, _state, make_automatic); + ae_vector_init_copy(&dst->scl, &src->scl, _state, make_automatic); + ae_vector_init_copy(&dst->scu, &src->scu, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcmult, &src->lcsrcmult, _state, make_automatic); + _sparsematrix_init_copy(&dst->effsparsea, &src->effsparsea, _state, make_automatic); + ae_vector_init_copy(&dst->effal, &src->effal, _state, make_automatic); + ae_vector_init_copy(&dst->effau, &src->effau, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps, &src->tmps, _state, make_automatic); +} + + +void _xlinearconstraints_clear(void* _p) +{ + xlinearconstraints *p = (xlinearconstraints*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->densec); + _sparsematrix_clear(&p->sparsec); + ae_vector_clear(&p->dcl); + ae_vector_clear(&p->dcu); + ae_vector_clear(&p->scl); + ae_vector_clear(&p->scu); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->lcsrcmult); + _sparsematrix_clear(&p->effsparsea); + ae_vector_clear(&p->effal); + ae_vector_clear(&p->effau); + _sparsematrix_clear(&p->tmps); +} + + +void _xlinearconstraints_destroy(void* _p) +{ + xlinearconstraints *p = (xlinearconstraints*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->densec); + _sparsematrix_destroy(&p->sparsec); + ae_vector_destroy(&p->dcl); + ae_vector_destroy(&p->dcu); + ae_vector_destroy(&p->scl); + ae_vector_destroy(&p->scu); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->lcsrcmult); + _sparsematrix_destroy(&p->effsparsea); + ae_vector_destroy(&p->effal); + ae_vector_destroy(&p->effau); + _sparsematrix_destroy(&p->tmps); +} + + +void _lptestproblem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lptestproblem *p = (lptestproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->a, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); +} + + +void _lptestproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lptestproblem *dst = (lptestproblem*)_dst; + const lptestproblem *src = (const lptestproblem*)_src; + dst->n = src->n; + dst->hasknowntarget = src->hasknowntarget; + dst->targetf = src->targetf; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->m = src->m; + _sparsematrix_init_copy(&dst->a, &src->a, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); +} + + +void _lptestproblem_clear(void* _p) +{ + lptestproblem *p = (lptestproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->c); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + _sparsematrix_clear(&p->a); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); +} + + +void _lptestproblem_destroy(void* _p) +{ + lptestproblem *p = (lptestproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->c); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + _sparsematrix_destroy(&p->a); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); +} + + +#endif +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine checks violation of the box constraints. On output it sets +bcerr to the maximum scaled violation, bcidx to the index of the violating +constraint. + +if bcerr=0 (say, if no constraints are violated) then bcidx=-1. + +If nonunits=false then s[] is not referenced at all (assumed unit). + + -- ALGLIB -- + Copyright 7.11.2018 by Bochkanov Sergey +*************************************************************************/ +void checkbcviolation(/* Boolean */ const ae_vector* hasbndl, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* hasbndu, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* s, + ae_bool nonunits, + double* bcerr, + ae_int_t* bcidx, + ae_state *_state) +{ + ae_int_t i; + double vs; + double ve; + + *bcerr = 0.0; + *bcidx = 0; + + *bcerr = (double)(0); + *bcidx = -1; + for(i=0; i<=n-1; i++) + { + + /* + * Fetch scale + */ + if( nonunits ) + { + vs = (double)1/s->ptr.p_double[i]; + } + else + { + vs = (double)(1); + } + + /* + * Check lower bound + */ + if( hasbndl->ptr.p_bool[i]&&x->ptr.p_double[i]ptr.p_double[i] ) + { + ve = (bndl->ptr.p_double[i]-x->ptr.p_double[i])*vs; + if( ve>*bcerr ) + { + *bcerr = ve; + *bcidx = i; + } + } + + /* + * Check upper bound + */ + if( hasbndu->ptr.p_bool[i]&&x->ptr.p_double[i]>bndu->ptr.p_double[i] ) + { + ve = (x->ptr.p_double[i]-bndu->ptr.p_double[i])*vs; + if( ve>*bcerr ) + { + *bcerr = ve; + *bcidx = i; + } + } + } +} + + +/************************************************************************* +This subroutine checks violation of the general linear constraints. + +Constraints are assumed to be un-normalized and stored in the format "NEC +equality ones followed by NIC inequality ones". + +On output it sets lcerr to the maximum scaled violation, lcidx to the source +index of the most violating constraint (row indexes of CLEIC are mapped to +the indexes of the "original" constraints via LCSrcIdx[] array. + +if lcerr=0 (say, if no constraints are violated) then lcidx=-1. + + -- ALGLIB -- + Copyright 07.11.2018 by Bochkanov Sergey +*************************************************************************/ +void checklcviolation(/* Real */ const ae_matrix* cleic, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t nec, + ae_int_t nic, + /* Real */ const ae_vector* x, + ae_int_t n, + double* lcerr, + ae_int_t* lcidx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double cx; + double cnrm; + double v; + + *lcerr = 0.0; + *lcidx = 0; + + *lcerr = (double)(0); + *lcidx = -1; + for(i=0; i<=nec+nic-1; i++) + { + cx = -cleic->ptr.pp_double[i][n]; + cnrm = (double)(0); + for(j=0; j<=n-1; j++) + { + v = cleic->ptr.pp_double[i][j]; + cx = cx+v*x->ptr.p_double[j]; + cnrm = cnrm+v*v; + } + cnrm = ae_sqrt(cnrm, _state); + cx = cx/coalesce(cnrm, (double)(1), _state); + if( i*lcerr ) + { + *lcerr = cx; + *lcidx = lcsrcidx->ptr.p_int[i]; + } + } +} + + +/************************************************************************* +This subroutine checks violation of the general linear constraints. + +Constraints are assumed to be un-normalized and having the following format: + + L <= A*x <= U, with some of L/U being infinite + +On output it sets lcerr to the maximum scaled violation, lcidx to the source +index of the most violating constraint (row indexes of A are mapped to the +indexes of the "original" constraints via LCSrcIdx[] array). + +if lcerr=0 (say, if no constraints are violated) then lcidx=-1. + + -- ALGLIB -- + Copyright 07.11.2018 by Bochkanov Sergey +*************************************************************************/ +void checklc2violation(const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* x, + double* lcerr, + ae_int_t* lcidx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double cx; + double cnrm; + double v; + + *lcerr = 0.0; + *lcidx = 0; + + *lcerr = (double)(0); + *lcidx = -1; + if( cntlc==0 ) + { + return; + } + ae_assert(a->matrixtype==1, "CheckLC2Violation: non-CRS input detected", _state); + for(i=0; i<=a->m-1; i++) + { + cx = 0.0; + cnrm = (double)(0); + j0 = a->ridx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + v = a->vals.ptr.p_double[j]; + cx = cx+v*x->ptr.p_double[a->idx.ptr.p_int[j]]; + cnrm = cnrm+v*v; + } + cnrm = coalesce(ae_sqrt(cnrm, _state), (double)(1), _state); + if( ae_isfinite(al->ptr.p_double[i], _state)&&(al->ptr.p_double[i]-cx)/cnrm>*lcerr ) + { + *lcerr = (al->ptr.p_double[i]-cx)/cnrm; + *lcidx = lcsrcidx->ptr.p_int[i]; + } + if( ae_isfinite(au->ptr.p_double[i], _state)&&(cx-au->ptr.p_double[i])/cnrm>*lcerr ) + { + *lcerr = (cx-au->ptr.p_double[i])/cnrm; + *lcidx = lcsrcidx->ptr.p_int[i]; + } + } +} + + +/************************************************************************* +This subroutine checks violation of the general linear constraints, computed +after on-the-fly rescaling according to variable scales vector S. + +Constraints are assumed to be un-normalized and having the following format: + + L <= A*x <= U, with some of L/U being infinite + +The function internally replaces them by + + L <= (A*S)*(x/S) <= U + +and divides each row #i by the norm of A[i]*S before computing violation. + +On output it sets lcerr to the maximum scaled violation, lcidx to the source +index of the most violating constraint (row indexes of A are mapped to the +indexes of the "original" constraints via LCSrcIdx[] array). + +if lcerr=0 (say, if no constraints are violated) then lcidx=-1. + + -- ALGLIB -- + Copyright 07.11.2018 by Bochkanov Sergey +*************************************************************************/ +void unscaleandchecklc2violation(/* Real */ const ae_vector* s, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* x, + double* sumerr, + double* maxerr, + ae_int_t* maxidx, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double cx; + double cnrm; + double v; + double vv; + + *sumerr = 0.0; + *maxerr = 0.0; + *maxidx = 0; + + *sumerr = (double)(0); + *maxerr = (double)(0); + *maxidx = -1; + if( cntlc==0 ) + { + return; + } + ae_assert(a->matrixtype==1, "CheckLC2Violation: non-CRS input detected", _state); + for(i=0; i<=a->m-1; i++) + { + cx = 0.0; + cnrm = (double)(0); + j0 = a->ridx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + v = a->vals.ptr.p_double[j]; + k = a->idx.ptr.p_int[j]; + cx = cx+v*x->ptr.p_double[k]; + vv = v*s->ptr.p_double[k]; + cnrm = cnrm+vv*vv; + } + cnrm = coalesce(ae_sqrt(cnrm, _state), (double)(1), _state); + if( ae_isfinite(al->ptr.p_double[i], _state) ) + { + v = ae_maxreal((al->ptr.p_double[i]-cx)/cnrm, 0.0, _state); + *sumerr = *sumerr+v; + if( v>*maxerr ) + { + *maxerr = v; + *maxidx = lcsrcidx->ptr.p_int[i]; + } + } + if( ae_isfinite(au->ptr.p_double[i], _state) ) + { + v = ae_maxreal((cx-au->ptr.p_double[i])/cnrm, 0.0, _state); + *sumerr = *sumerr+v; + if( v>*maxerr ) + { + *maxerr = v; + *maxidx = lcsrcidx->ptr.p_int[i]; + } + } + } +} + + +/************************************************************************* +This subroutine checks violation of the nonlinear constraints. Fi[0] is the +target value (ignored), Fi[1:NG+NH] are values of nonlinear constraints. + +On output it sets nlcerr to the scaled violation, nlcidx to the index +of the most violating constraint in [0,NG+NH-1] range. + +if nlcerr=0 (say, if no constraints are violated) then nlcidx=-1. + +If nonunits=false then s[] is not referenced at all (assumed unit). + + -- ALGLIB -- + Copyright 7.11.2018 by Bochkanov Sergey +*************************************************************************/ +void checknlcviolation(/* Real */ const ae_vector* fi, + ae_int_t ng, + ae_int_t nh, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state) +{ + ae_int_t i; + double v; + + *nlcerr = 0.0; + *nlcidx = 0; + + *nlcerr = (double)(0); + *nlcidx = -1; + for(i=0; i<=ng+nh-1; i++) + { + v = fi->ptr.p_double[i+1]; + if( i*nlcerr ) + { + *nlcerr = v; + *nlcidx = i; + } + } +} + + +/************************************************************************* +This subroutine is same as CheckNLCViolation, but is works with scaled +constraints: it assumes that Fi[] were divided by FScales[] vector BEFORE +passing them to this function. + +The function checks scaled values, but reports unscaled errors. + + -- ALGLIB -- + Copyright 7.11.2018 by Bochkanov Sergey +*************************************************************************/ +void unscaleandchecknlcviolation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* fscales, + ae_int_t ng, + ae_int_t nh, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state) +{ + ae_int_t i; + double v; + + *nlcerr = 0.0; + *nlcidx = 0; + + *nlcerr = (double)(0); + *nlcidx = -1; + for(i=0; i<=ng+nh-1; i++) + { + ae_assert(ae_fp_greater(fscales->ptr.p_double[i+1],(double)(0)), "UnscaleAndCheckNLCViolation: integrity check failed", _state); + v = fi->ptr.p_double[i+1]*fscales->ptr.p_double[i+1]; + if( i*nlcerr ) + { + *nlcerr = v; + *nlcidx = i; + } + } +} + + +/************************************************************************* +This subroutine is same as CheckNLCViolation, but is works with scaled +constraints: it assumes that Fi[] were divided by FScales[] vector BEFORE +passing them to this function. + +The function checks scaled values, but reports unscaled errors. + + -- ALGLIB -- + Copyright 7.11.2018 by Bochkanov Sergey +*************************************************************************/ +void unscaleandchecknlc2violation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* fscales, + /* Real */ const ae_vector* rawnl, + /* Real */ const ae_vector* rawnu, + ae_int_t cntnlc, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double err; + + *nlcerr = 0.0; + *nlcidx = 0; + + *nlcerr = (double)(0); + *nlcidx = -1; + for(i=0; i<=cntnlc-1; i++) + { + ae_assert(ae_fp_greater(fscales->ptr.p_double[i+1],(double)(0)), "UnscaleAndCheckNLC2Violation: integrity check failed", _state); + v = fi->ptr.p_double[i+1]*fscales->ptr.p_double[i+1]; + err = (double)(0); + if( ae_isfinite(rawnl->ptr.p_double[i], _state) ) + { + err = ae_maxreal(err, rawnl->ptr.p_double[i]-v, _state); + } + if( ae_isfinite(rawnu->ptr.p_double[i], _state) ) + { + err = ae_maxreal(err, v-rawnu->ptr.p_double[i], _state); + } + if( err>*nlcerr ) + { + *nlcerr = err; + *nlcidx = i; + } + } +} + + +/************************************************************************* +Check violation of two-sided constraints + + -- ALGLIB -- + Copyright 7.11.2018 by Bochkanov Sergey +*************************************************************************/ +void checknlc2violation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* rawnl, + /* Real */ const ae_vector* rawnu, + ae_int_t cntnlc, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state) +{ + ae_int_t i; + double v; + double err; + + *nlcerr = 0.0; + *nlcidx = 0; + + *nlcerr = (double)(0); + *nlcidx = -1; + for(i=0; i<=cntnlc-1; i++) + { + v = fi->ptr.p_double[i+1]; + err = (double)(0); + if( ae_isfinite(rawnl->ptr.p_double[i], _state) ) + { + err = ae_maxreal(err, rawnl->ptr.p_double[i]-v, _state); + } + if( ae_isfinite(rawnu->ptr.p_double[i], _state) ) + { + err = ae_maxreal(err, v-rawnu->ptr.p_double[i], _state); + } + if( err>*nlcerr ) + { + *nlcerr = err; + *nlcidx = i; + } + } +} + + +/************************************************************************* +This subroutine is used to prepare threshold value which will be used for +trimming of the target function (see comments on TrimFunction() for more +information). + +This function accepts only one parameter: function value at the starting +point. It returns threshold which will be used for trimming. + + -- ALGLIB -- + Copyright 10.05.2011 by Bochkanov Sergey +*************************************************************************/ +void trimprepare(double f, double* threshold, ae_state *_state) +{ + + *threshold = 0.0; + + *threshold = (double)10*(ae_fabs(f, _state)+(double)1); +} + + +/************************************************************************* +This subroutine is used to "trim" target function, i.e. to do following +transformation: + + { {F,G} if F=Threshold + +Such transformation allows us to solve problems with singularities by +redefining function in such way that it becomes bounded from above. + + -- ALGLIB -- + Copyright 10.05.2011 by Bochkanov Sergey +*************************************************************************/ +void trimfunction(double* f, + /* Real */ ae_vector* g, + ae_int_t n, + double threshold, + ae_state *_state) +{ + ae_int_t i; + + + if( ae_fp_greater_eq(*f,threshold) ) + { + *f = threshold; + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = 0.0; + } + } +} + + +/************************************************************************* +This function enforces boundary constraints in the X. + +This function correctly (although a bit inefficient) handles BL[i] which +are -INF and BU[i] which are +INF. + +We have NMain+NSlack dimensional X, with first NMain components bounded +by BL/BU, and next NSlack ones bounded by non-negativity constraints. + +INPUT PARAMETERS + X - array[NMain+NSlack], point + BL - array[NMain], lower bounds + (may contain -INF, when bound is not present) + HaveBL - array[NMain], if HaveBL[i] is False, + then i-th bound is not present + BU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBU - array[NMain], if HaveBU[i] is False, + then i-th bound is not present + +OUTPUT PARAMETERS + X - X with all constraints being enforced + +It returns True when constraints are consistent, +False - when constraints are inconsistent. + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, + /* Real */ const ae_vector* bl, + /* Boolean */ const ae_vector* havebl, + /* Real */ const ae_vector* bu, + /* Boolean */ const ae_vector* havebu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state) +{ + ae_int_t i; + ae_bool result; + + + result = ae_false; + for(i=0; i<=nmain-1; i++) + { + if( (havebl->ptr.p_bool[i]&&havebu->ptr.p_bool[i])&&ae_fp_greater(bl->ptr.p_double[i],bu->ptr.p_double[i]) ) + { + return result; + } + if( havebl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bl->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = bl->ptr.p_double[i]; + } + if( havebu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bu->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = bu->ptr.p_double[i]; + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_less(x->ptr.p_double[nmain+i],(double)(0)) ) + { + x->ptr.p_double[nmain+i] = (double)(0); + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +This function projects gradient into feasible area of boundary constrained +optimization problem. X can be infeasible with respect to boundary +constraints. We have NMain+NSlack dimensional X, with first NMain +components bounded by BL/BU, and next NSlack ones bounded by non-negativity +constraints. + +INPUT PARAMETERS + X - array[NMain+NSlack], point + G - array[NMain+NSlack], gradient + BL - lower bounds (may contain -INF, when bound is not present) + HaveBL - if HaveBL[i] is False, then i-th bound is not present + BU - upper bounds (may contain +INF, when bound is not present) + HaveBU - if HaveBU[i] is False, then i-th bound is not present + +OUTPUT PARAMETERS + G - projection of G. Components of G which satisfy one of the + following + (1) (X[I]<=BndL[I]) and (G[I]>0), OR + (2) (X[I]>=BndU[I]) and (G[I]<0) + are replaced by zeros. + +NOTE 1: this function assumes that constraints are feasible. It throws +exception otherwise. + +NOTE 2: in fact, projection of ANTI-gradient is calculated, because this +function trims components of -G which points outside of the feasible area. +However, working with -G is considered confusing, because all optimization +source work with G. + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +void projectgradientintobc(/* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* bl, + /* Boolean */ const ae_vector* havebl, + /* Real */ const ae_vector* bu, + /* Boolean */ const ae_vector* havebu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=nmain-1; i++) + { + ae_assert((!havebl->ptr.p_bool[i]||!havebu->ptr.p_bool[i])||ae_fp_less_eq(bl->ptr.p_double[i],bu->ptr.p_double[i]), "ProjectGradientIntoBC: internal error (infeasible constraints)", _state); + if( (havebl->ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],bl->ptr.p_double[i]))&&ae_fp_greater(g->ptr.p_double[i],(double)(0)) ) + { + g->ptr.p_double[i] = (double)(0); + } + if( (havebu->ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],bu->ptr.p_double[i]))&&ae_fp_less(g->ptr.p_double[i],(double)(0)) ) + { + g->ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_less_eq(x->ptr.p_double[nmain+i],(double)(0))&&ae_fp_greater(g->ptr.p_double[nmain+i],(double)(0)) ) + { + g->ptr.p_double[nmain+i] = (double)(0); + } + } +} + + +/************************************************************************* +Given + a) initial point X0[NMain+NSlack] + (feasible with respect to bound constraints) + b) step vector alpha*D[NMain+NSlack] + c) boundary constraints BndL[NMain], BndU[NMain] + d) implicit non-negativity constraints for slack variables +this function calculates bound on the step length subject to boundary +constraints. + +It returns: + * MaxStepLen - such step length that X0+MaxStepLen*alpha*D is exactly + at the boundary given by constraints + * VariableToFreeze - index of the constraint to be activated, + 0 <= VariableToFreeze < NMain+NSlack + * ValueToFreeze - value of the corresponding constraint. + +Notes: + * it is possible that several constraints can be activated by the step + at once. In such cases only one constraint is returned. It is caller + responsibility to check other constraints. This function makes sure + that we activate at least one constraint, and everything else is the + responsibility of the caller. + * steps smaller than MaxStepLen still can activate constraints due to + numerical errors. Thus purpose of this function is not to guard + against accidental activation of the constraints - quite the reverse, + its purpose is to activate at least constraint upon performing step + which is too long. + * in case there is no constraints to activate, we return negative + VariableToFreeze and zero MaxStepLen and ValueToFreeze. + * this function assumes that constraints are consistent; it throws + exception otherwise. + +INPUT PARAMETERS + X - array[NMain+NSlack], point. Must be feasible with respect + to bound constraints (exception will be thrown otherwise) + D - array[NMain+NSlack], step direction + alpha - scalar multiplier before D, alpha<>0 + BndL - lower bounds, array[NMain] + (may contain -INF, when bound is not present) + HaveBndL - array[NMain], if HaveBndL[i] is False, + then i-th bound is not present + BndU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBndU - array[NMain], if HaveBndU[i] is False, + then i-th bound is not present + NMain - number of main variables + NSlack - number of slack variables + +OUTPUT PARAMETERS + VariableToFreeze: + * negative value = step is unbounded, ValueToFreeze=0, + MaxStepLen=0. + * non-negative value = at least one constraint, given by + this parameter, will be activated + upon performing maximum step. + ValueToFreeze- value of the variable which will be constrained + MaxStepLen - maximum length of the step. Can be zero when step vector + looks outside of the feasible area. + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +void calculatestepbound(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double alpha, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t* variabletofreeze, + double* valuetofreeze, + double* maxsteplen, + ae_state *_state) +{ + ae_int_t i; + double prevmax; + double initval; + + *variabletofreeze = 0; + *valuetofreeze = 0.0; + *maxsteplen = 0.0; + + ae_assert(ae_fp_neq(alpha,(double)(0)), "CalculateStepBound: zero alpha", _state); + *variabletofreeze = -1; + initval = ae_maxrealnumber; + *maxsteplen = initval; + for(i=0; i<=nmain-1; i++) + { + if( havebndl->ptr.p_bool[i]&&ae_fp_less(alpha*d->ptr.p_double[i],(double)(0)) ) + { + ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); + prevmax = *maxsteplen; + *maxsteplen = safeminposrv(x->ptr.p_double[i]-bndl->ptr.p_double[i], -alpha*d->ptr.p_double[i], *maxsteplen, _state); + if( ae_fp_less(*maxsteplen,prevmax) ) + { + *variabletofreeze = i; + *valuetofreeze = bndl->ptr.p_double[i]; + } + } + if( havebndu->ptr.p_bool[i]&&ae_fp_greater(alpha*d->ptr.p_double[i],(double)(0)) ) + { + ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "CalculateStepBound: infeasible X", _state); + prevmax = *maxsteplen; + *maxsteplen = safeminposrv(bndu->ptr.p_double[i]-x->ptr.p_double[i], alpha*d->ptr.p_double[i], *maxsteplen, _state); + if( ae_fp_less(*maxsteplen,prevmax) ) + { + *variabletofreeze = i; + *valuetofreeze = bndu->ptr.p_double[i]; + } + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_less(alpha*d->ptr.p_double[nmain+i],(double)(0)) ) + { + ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],(double)(0)), "CalculateStepBound: infeasible X", _state); + prevmax = *maxsteplen; + *maxsteplen = safeminposrv(x->ptr.p_double[nmain+i], -alpha*d->ptr.p_double[nmain+i], *maxsteplen, _state); + if( ae_fp_less(*maxsteplen,prevmax) ) + { + *variabletofreeze = nmain+i; + *valuetofreeze = (double)(0); + } + } + } + if( ae_fp_eq(*maxsteplen,initval) ) + { + *valuetofreeze = (double)(0); + *maxsteplen = (double)(0); + } +} + + +/************************************************************************* +This function postprocesses bounded step by: +* analysing step length (whether it is equal to MaxStepLen) and activating + constraint given by VariableToFreeze if needed +* checking for additional bound constraints to activate + +This function uses final point of the step, quantities calculated by the +CalculateStepBound() function. As result, it returns point which is +exactly feasible with respect to boundary constraints. + +NOTE 1: this function does NOT handle and check linear equality constraints +NOTE 2: when StepTaken=MaxStepLen we always activate at least one constraint + +INPUT PARAMETERS + X - array[NMain+NSlack], final point to postprocess + XPrev - array[NMain+NSlack], initial point + BndL - lower bounds, array[NMain] + (may contain -INF, when bound is not present) + HaveBndL - array[NMain], if HaveBndL[i] is False, + then i-th bound is not present + BndU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBndU - array[NMain], if HaveBndU[i] is False, + then i-th bound is not present + NMain - number of main variables + NSlack - number of slack variables + VariableToFreeze-result of CalculateStepBound() + ValueToFreeze- result of CalculateStepBound() + StepTaken - actual step length (actual step is equal to the possibly + non-unit step direction vector times this parameter). + StepTaken<=MaxStepLen. + MaxStepLen - result of CalculateStepBound() + +OUTPUT PARAMETERS + X - point bounded with respect to constraints. + components corresponding to active constraints are exactly + equal to the boundary values. + +RESULT: + number of constraints activated in addition to previously active ones. + Constraints which were DEACTIVATED are ignored (do not influence + function value). + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, + /* Real */ const ae_vector* xprev, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t variabletofreeze, + double valuetofreeze, + double steptaken, + double maxsteplen, + ae_state *_state) +{ + ae_int_t i; + ae_bool wasactivated; + ae_int_t result; + + + ae_assert(variabletofreeze<0||ae_fp_less_eq(steptaken,maxsteplen), "Assertion failed", _state); + + /* + * Activate constraints + */ + if( variabletofreeze>=0&&ae_fp_eq(steptaken,maxsteplen) ) + { + x->ptr.p_double[variabletofreeze] = valuetofreeze; + } + for(i=0; i<=nmain-1; i++) + { + if( havebndl->ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = bndl->ptr.p_double[i]; + } + if( havebndu->ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = bndu->ptr.p_double[i]; + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_less_eq(x->ptr.p_double[nmain+i],(double)(0)) ) + { + x->ptr.p_double[nmain+i] = (double)(0); + } + } + + /* + * Calculate number of constraints being activated + */ + result = 0; + for(i=0; i<=nmain-1; i++) + { + wasactivated = ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i])&&((havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]))); + wasactivated = wasactivated||variabletofreeze==i; + if( wasactivated ) + { + result = result+1; + } + } + for(i=0; i<=nslack-1; i++) + { + wasactivated = ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&ae_fp_eq(x->ptr.p_double[nmain+i],0.0); + wasactivated = wasactivated||variabletofreeze==nmain+i; + if( wasactivated ) + { + result = result+1; + } + } + return result; +} + + +/************************************************************************* +The purpose of this function is to prevent algorithm from "unsticking" +from the active bound constraints because of numerical noise in the +gradient or Hessian. + +It is done by zeroing some components of the search direction D. D[i] is +zeroed when both (a) and (b) are true: +a) corresponding X[i] is exactly at the boundary +b) |D[i]*S[i]| <= DropTol*Sqrt(SUM(D[i]^2*S[I]^2)) + +D can be step direction , antigradient, gradient, or anything similar. +Sign of D does not matter, nor matters step length. + +NOTE 1: boundary constraints are expected to be consistent, as well as X + is expected to be feasible. Exception will be thrown otherwise. + +INPUT PARAMETERS + D - array[NMain+NSlack], direction + X - array[NMain+NSlack], current point + BndL - lower bounds, array[NMain] + (may contain -INF, when bound is not present) + HaveBndL - array[NMain], if HaveBndL[i] is False, + then i-th bound is not present + BndU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBndU - array[NMain], if HaveBndU[i] is False, + then i-th bound is not present + S - array[NMain+NSlack], scaling of the variables + NMain - number of main variables + NSlack - number of slack variables + DropTol - drop tolerance, >=0 + +OUTPUT PARAMETERS + X - point bounded with respect to constraints. + components corresponding to active constraints are exactly + equal to the boundary values. + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +void filterdirection(/* Real */ ae_vector* d, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + /* Real */ const ae_vector* s, + ae_int_t nmain, + ae_int_t nslack, + double droptol, + ae_state *_state) +{ + ae_int_t i; + double scalednorm; + ae_bool isactive; + + + scalednorm = 0.0; + for(i=0; i<=nmain+nslack-1; i++) + { + scalednorm = scalednorm+ae_sqr(d->ptr.p_double[i]*s->ptr.p_double[i], _state); + } + scalednorm = ae_sqrt(scalednorm, _state); + for(i=0; i<=nmain-1; i++) + { + ae_assert(!havebndl->ptr.p_bool[i]||ae_fp_greater_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]), "FilterDirection: infeasible point", _state); + ae_assert(!havebndu->ptr.p_bool[i]||ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "FilterDirection: infeasible point", _state); + isactive = (havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]))||(havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])); + if( isactive&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[i]*s->ptr.p_double[i], _state),droptol*scalednorm) ) + { + d->ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=nslack-1; i++) + { + ae_assert(ae_fp_greater_eq(x->ptr.p_double[nmain+i],(double)(0)), "FilterDirection: infeasible point", _state); + if( ae_fp_eq(x->ptr.p_double[nmain+i],(double)(0))&&ae_fp_less_eq(ae_fabs(d->ptr.p_double[nmain+i]*s->ptr.p_double[nmain+i], _state),droptol*scalednorm) ) + { + d->ptr.p_double[nmain+i] = 0.0; + } + } +} + + +/************************************************************************* +This function returns number of bound constraints whose state was changed +(either activated or deactivated) when making step from XPrev to X. + +Constraints are considered: +* active - when we are exactly at the boundary +* inactive - when we are not at the boundary + +You should note that antigradient direction is NOT taken into account when +we make decions on the constraint status. + +INPUT PARAMETERS + X - array[NMain+NSlack], final point. + Must be feasible with respect to bound constraints. + XPrev - array[NMain+NSlack], initial point. + Must be feasible with respect to bound constraints. + BndL - lower bounds, array[NMain] + (may contain -INF, when bound is not present) + HaveBndL - array[NMain], if HaveBndL[i] is False, + then i-th bound is not present + BndU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBndU - array[NMain], if HaveBndU[i] is False, + then i-th bound is not present + NMain - number of main variables + NSlack - number of slack variables + +RESULT: + number of constraints whose state was changed. + + -- ALGLIB -- + Copyright 10.01.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t numberofchangedconstraints(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* xprev, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state) +{ + ae_int_t i; + ae_bool statuschanged; + ae_int_t result; + + + result = 0; + for(i=0; i<=nmain-1; i++) + { + if( ae_fp_neq(x->ptr.p_double[i],xprev->ptr.p_double[i]) ) + { + statuschanged = ae_false; + if( havebndl->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndl->ptr.p_double[i])) ) + { + statuschanged = ae_true; + } + if( havebndu->ptr.p_bool[i]&&(ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i])||ae_fp_eq(xprev->ptr.p_double[i],bndu->ptr.p_double[i])) ) + { + statuschanged = ae_true; + } + if( statuschanged ) + { + result = result+1; + } + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_neq(x->ptr.p_double[nmain+i],xprev->ptr.p_double[nmain+i])&&(ae_fp_eq(x->ptr.p_double[nmain+i],(double)(0))||ae_fp_eq(xprev->ptr.p_double[nmain+i],(double)(0))) ) + { + result = result+1; + } + } + return result; +} + + +/************************************************************************* +This function finds feasible point of (NMain+NSlack)-dimensional problem +subject to NMain explicit boundary constraints (some constraints can be +omitted), NSlack implicit non-negativity constraints, K linear equality +constraints. + +INPUT PARAMETERS + X - array[NMain+NSlack], initial point. + BndL - lower bounds, array[NMain] + (may contain -INF, when bound is not present) + HaveBndL - array[NMain], if HaveBndL[i] is False, + then i-th bound is not present + BndU - array[NMain], upper bounds + (may contain +INF, when bound is not present) + HaveBndU - array[NMain], if HaveBndU[i] is False, + then i-th bound is not present + NMain - number of main variables + NSlack - number of slack variables + CE - array[K,NMain+NSlack+1], equality constraints CE*x=b. + Rows contain constraints, first NMain+NSlack columns + contain coefficients before X[], last column contain + right part. + K - number of linear constraints + EpsI - infeasibility (error in the right part) allowed in the + solution + +OUTPUT PARAMETERS: + X - feasible point or best infeasible point found before + algorithm termination + QPIts - number of QP iterations (for debug purposes) + GPAIts - number of GPA iterations (for debug purposes) + +RESULT: + True in case X is feasible, False - if it is infeasible. + + -- ALGLIB -- + Copyright 20.01.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool findfeasiblepoint(/* Real */ ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + /* Real */ const ae_matrix* _ce, + ae_int_t k, + double epsi, + ae_int_t* qpits, + ae_int_t* gpaits, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix ce; + ae_int_t i; + ae_int_t j; + ae_int_t idx0; + ae_int_t idx1; + ae_vector permx; + ae_vector xn; + ae_vector xa; + ae_vector newtonstep; + ae_vector g; + ae_vector pg; + ae_vector tau; + ae_vector s; + double armijostep; + double armijobeststep; + double armijobestfeas; + double v; + double vv; + double mx; + double feaserr; + double feaserr0; + double feaserr1; + double feasold; + double feasnew; + double pgnorm; + double vn; + double vd; + double stp; + ae_int_t vartofreeze; + double valtofreeze; + double maxsteplen; + ae_bool werechangesinconstraints; + ae_bool stage1isover; + ae_bool converged; + ae_vector activeconstraints; + ae_vector tmpk; + ae_vector colnorms; + ae_int_t nactive; + ae_int_t nfree; + ae_vector p1; + ae_vector p2; + apbuffers buf; + ae_int_t itscount; + ae_int_t itswithintolerance; + ae_int_t maxitswithintolerance; + ae_int_t badits; + ae_int_t maxbadits; + ae_int_t gparuns; + ae_int_t maxarmijoruns; + double infeasibilityincreasetolerance; + ae_matrix permce; + ae_matrix q; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&ce, 0, sizeof(ce)); + memset(&permx, 0, sizeof(permx)); + memset(&xn, 0, sizeof(xn)); + memset(&xa, 0, sizeof(xa)); + memset(&newtonstep, 0, sizeof(newtonstep)); + memset(&g, 0, sizeof(g)); + memset(&pg, 0, sizeof(pg)); + memset(&tau, 0, sizeof(tau)); + memset(&s, 0, sizeof(s)); + memset(&activeconstraints, 0, sizeof(activeconstraints)); + memset(&tmpk, 0, sizeof(tmpk)); + memset(&colnorms, 0, sizeof(colnorms)); + memset(&p1, 0, sizeof(p1)); + memset(&p2, 0, sizeof(p2)); + memset(&buf, 0, sizeof(buf)); + memset(&permce, 0, sizeof(permce)); + memset(&q, 0, sizeof(q)); + ae_matrix_init_copy(&ce, _ce, _state, ae_true); + *qpits = 0; + *gpaits = 0; + ae_vector_init(&permx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xn, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); + ae_vector_init(&newtonstep, 0, DT_REAL, _state, ae_true); + ae_vector_init(&g, 0, DT_REAL, _state, ae_true); + ae_vector_init(&pg, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tau, 0, DT_REAL, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + ae_vector_init(&activeconstraints, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmpk, 0, DT_REAL, _state, ae_true); + ae_vector_init(&colnorms, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p1, 0, DT_INT, _state, ae_true); + ae_vector_init(&p2, 0, DT_INT, _state, ae_true); + _apbuffers_init(&buf, _state, ae_true); + ae_matrix_init(&permce, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + + maxitswithintolerance = 3; + maxbadits = 3; + maxarmijoruns = 5; + *qpits = 0; + *gpaits = 0; + + /* + * Initial enforcement of the feasibility with respect to boundary constraints + * NOTE: after this block we assume that boundary constraints are consistent. + */ + if( !enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( k==0 ) + { + + /* + * No linear constraints, we can exit right now + */ + result = ae_true; + ae_frame_leave(_state); + return result; + } + + /* + * Scale rows of CE in such way that max(CE[i,0..nmain+nslack-1])=1 for any i=0..k-1 + */ + for(i=0; i<=k-1; i++) + { + v = 0.0; + for(j=0; j<=nmain+nslack-1; j++) + { + v = ae_maxreal(v, ae_fabs(ce.ptr.pp_double[i][j], _state), _state); + } + if( ae_fp_neq(v,(double)(0)) ) + { + v = (double)1/v; + ae_v_muld(&ce.ptr.pp_double[i][0], 1, ae_v_len(0,nmain+nslack), v); + } + } + + /* + * Allocate temporaries + */ + ae_vector_set_length(&xn, nmain+nslack, _state); + ae_vector_set_length(&xa, nmain+nslack, _state); + ae_vector_set_length(&permx, nmain+nslack, _state); + ae_vector_set_length(&g, nmain+nslack, _state); + ae_vector_set_length(&pg, nmain+nslack, _state); + ae_vector_set_length(&tmpk, k, _state); + ae_matrix_set_length(&permce, k, nmain+nslack, _state); + ae_vector_set_length(&activeconstraints, nmain+nslack, _state); + ae_vector_set_length(&newtonstep, nmain+nslack, _state); + ae_vector_set_length(&s, nmain+nslack, _state); + ae_vector_set_length(&colnorms, nmain+nslack, _state); + for(i=0; i<=nmain+nslack-1; i++) + { + s.ptr.p_double[i] = 1.0; + colnorms.ptr.p_double[i] = 0.0; + for(j=0; j<=k-1; j++) + { + colnorms.ptr.p_double[i] = colnorms.ptr.p_double[i]+ae_sqr(ce.ptr.pp_double[j][i], _state); + } + } + + /* + * K>0, we have linear equality constraints combined with bound constraints. + * + * Try to find feasible point as minimizer of the quadratic function + * F(x) = 0.5*||CE*x-b||^2 = 0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b + * subject to boundary constraints given by BL, BU and non-negativity of + * the slack variables. BTW, we drop constant term because it does not + * actually influences on the solution. + * + * Below we will assume that K>0. + */ + itswithintolerance = 0; + badits = 0; + itscount = 0; + for(;;) + { + + /* + * Dynamically adjust infeasibility error tolerance + */ + infeasibilityincreasetolerance = ae_maxreal(rmaxabsv(nmain+nslack, x, _state), (double)(1), _state)*(double)(1000+nmain)*ae_machineepsilon; + + /* + * Stage 0: check for exact convergence + */ + converged = ae_true; + feaserr = optserv_feasibilityerror(&ce, x, nmain, nslack, k, &tmpk, _state); + for(i=0; i<=k-1; i++) + { + + /* + * Calculate MX - maximum term in the left part + * + * Terminate if error in the right part is not greater than 100*Eps*MX. + * + * IMPORTANT: we must perform check for non-strict inequality, i.e. to use <= instead of <. + * it will allow us to easily handle situations with zero rows of CE. + * + * NOTE: it is important to calculate feasibility error with dedicated + * function. Once we had a situation when usage of "inline" code + * resulted in different numerical values calculated at different + * parts of program for exactly same X. However, this value is + * essential for algorithm's ability to terminate before entering + * infinite loop, so reproducibility of numerical results is very + * important. + */ + mx = (double)(0); + v = -ce.ptr.pp_double[i][nmain+nslack]; + for(j=0; j<=nmain+nslack-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(ce.ptr.pp_double[i][j]*x->ptr.p_double[j], _state), _state); + v = v+ce.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + converged = converged&&ae_fp_less_eq(ae_fabs(v, _state),(double)100*ae_machineepsilon*mx); + } + feaserr0 = feaserr; + if( converged ) + { + result = ae_fp_less_eq(feaserr,epsi); + ae_frame_leave(_state); + return result; + } + + /* + * Stage 1: equality constrained quadratic programming + * + * * treat active bound constraints as equality ones (constraint is considered + * active when we are at the boundary, independently of the antigradient direction) + * * calculate unrestricted Newton step to point XM (which may be infeasible) + * calculate MaxStepLen = largest step in direction of XM which retains feasibility. + * * perform bounded step from X to XN: + * a) XN=XM (if XM is feasible) + * b) XN=X-MaxStepLen*(XM-X) (otherwise) + * * X := XN + * * if XM (Newton step subject to currently active constraints) was feasible, goto Stage 2 + * * repeat Stage 1 + * + * NOTE 1: in order to solve constrained qudratic subproblem we will have to reorder + * variables in such way that ones corresponding to inactive constraints will + * be first, and active ones will be last in the list. CE and X are now + * [ xi ] + * separated into two parts: CE = [CEi CEa], x = [ ], where CEi/Xi correspond + * [ xa ] + * to INACTIVE constraints, and CEa/Xa correspond to the ACTIVE ones. + * + * Now, instead of F=0.5*x'*(CE'*CE)*x - (b'*CE)*x + 0.5*b'*b, we have + * F(xi) = 0.5*(CEi*xi,CEi*xi) + (CEa*xa-b,CEi*xi) + (0.5*CEa*xa-b,CEa*xa). + * Here xa is considered constant, i.e. we optimize with respect to xi, leaving xa fixed. + * + * We can solve it by performing SVD of CEi and calculating pseudoinverse of the + * Hessian matrix. Of course, we do NOT calculate pseudoinverse explicitly - we + * just use singular vectors to perform implicit multiplication by it. + * + */ + for(;;) + { + + /* + * Calculate G - gradient subject to equality constraints, + * multiply it by inverse of the Hessian diagonal to obtain initial + * step vector. + * + * Bound step subject to constraints which can be activated, + * run Armijo search with increasing step size. + * Search is terminated when feasibility error stops to decrease. + * + * NOTE: it is important to test for "stops to decrease" instead + * of "starts to increase" in order to correctly handle cases with + * zero CE. + */ + armijobeststep = 0.0; + optserv_feasibilityerrorgrad(&ce, x, nmain, nslack, k, &armijobestfeas, &g, &tmpk, _state); + for(i=0; i<=nmain-1; i++) + { + if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) + { + g.ptr.p_double[i] = 0.0; + } + if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + g.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=nslack-1; i++) + { + if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) + { + g.ptr.p_double[nmain+i] = 0.0; + } + } + v = 0.0; + for(i=0; i<=nmain+nslack-1; i++) + { + if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),(double)(0)) ) + { + newtonstep.ptr.p_double[i] = -g.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); + } + else + { + newtonstep.ptr.p_double[i] = 0.0; + } + v = v+ae_sqr(newtonstep.ptr.p_double[i], _state); + } + if( ae_fp_eq(v,(double)(0)) ) + { + + /* + * Constrained gradient is zero, QP iterations are over + */ + break; + } + calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); + if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) + { + + /* + * Can not perform step, QP iterations are over + */ + break; + } + if( vartofreeze>=0 ) + { + armijostep = ae_minreal(1.0, maxsteplen, _state); + } + else + { + armijostep = (double)(1); + } + for(;;) + { + ae_v_move(&xa.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); + enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); + feaserr = optserv_feasibilityerror(&ce, &xa, nmain, nslack, k, &tmpk, _state); + if( ae_fp_greater_eq(feaserr,armijobestfeas) ) + { + break; + } + armijobestfeas = feaserr; + armijobeststep = armijostep; + armijostep = 2.0*armijostep; + } + ae_v_addd(&x->ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); + enforceboundaryconstraints(x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); + + /* + * Determine number of active and free constraints + */ + nactive = 0; + for(i=0; i<=nmain-1; i++) + { + activeconstraints.ptr.p_double[i] = (double)(0); + if( havebndl->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndl->ptr.p_double[i]) ) + { + activeconstraints.ptr.p_double[i] = (double)(1); + } + if( havebndu->ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + activeconstraints.ptr.p_double[i] = (double)(1); + } + if( ae_fp_greater(activeconstraints.ptr.p_double[i],(double)(0)) ) + { + nactive = nactive+1; + } + } + for(i=0; i<=nslack-1; i++) + { + activeconstraints.ptr.p_double[nmain+i] = (double)(0); + if( ae_fp_eq(x->ptr.p_double[nmain+i],0.0) ) + { + activeconstraints.ptr.p_double[nmain+i] = (double)(1); + } + if( ae_fp_greater(activeconstraints.ptr.p_double[nmain+i],(double)(0)) ) + { + nactive = nactive+1; + } + } + nfree = nmain+nslack-nactive; + if( nfree==0 ) + { + break; + } + *qpits = *qpits+1; + + /* + * Reorder variables: CE is reordered to PermCE, X is reordered to PermX + */ + tagsortbuf(&activeconstraints, nmain+nslack, &p1, &p2, &buf, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=nmain+nslack-1; j++) + { + permce.ptr.pp_double[i][j] = ce.ptr.pp_double[i][j]; + } + } + for(j=0; j<=nmain+nslack-1; j++) + { + permx.ptr.p_double[j] = x->ptr.p_double[j]; + } + for(j=0; j<=nmain+nslack-1; j++) + { + if( p2.ptr.p_int[j]!=j ) + { + idx0 = p2.ptr.p_int[j]; + idx1 = j; + for(i=0; i<=k-1; i++) + { + v = permce.ptr.pp_double[i][idx0]; + permce.ptr.pp_double[i][idx0] = permce.ptr.pp_double[i][idx1]; + permce.ptr.pp_double[i][idx1] = v; + } + v = permx.ptr.p_double[idx0]; + permx.ptr.p_double[idx0] = permx.ptr.p_double[idx1]; + permx.ptr.p_double[idx1] = v; + } + } + + /* + * Calculate (unprojected) gradient: + * G(xi) = CEi'*(CEi*xi + CEa*xa - b) + */ + for(i=0; i<=nfree-1; i++) + { + g.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=k-1; i++) + { + v = ae_v_dotproduct(&permce.ptr.pp_double[i][0], 1, &permx.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + tmpk.ptr.p_double[i] = v-ce.ptr.pp_double[i][nmain+nslack]; + } + for(i=0; i<=k-1; i++) + { + v = tmpk.ptr.p_double[i]; + ae_v_addd(&g.ptr.p_double[0], 1, &permce.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); + } + + /* + * Calculate Newton step using pseudoinverse PermCE: + * F(xi) = 0.5*xi'*H*xi + g'*xi (Taylor decomposition) + * XN = -H^(-1)*g (new point, solution of the QP subproblem) + * H = CEi'*CEi + * H^(-1) can be calculated via QR or LQ decomposition (see below) + * step = -H^(-1)*g + * + * NOTE: PermCE is destroyed after this block + */ + for(i=0; i<=nmain+nslack-1; i++) + { + newtonstep.ptr.p_double[i] = (double)(0); + } + if( k<=nfree ) + { + + /* + * CEi = L*Q + * H = Q'*L'*L*Q + * inv(H) = Q'*inv(L)*inv(L')*Q + * + * NOTE: we apply minor regularizing perturbation to diagonal of L, + * which is equal to 10*K*Eps + */ + rmatrixlq(&permce, k, nfree, &tau, _state); + rmatrixlqunpackq(&permce, k, nfree, &tau, k, &q, _state); + v = (double)(0); + for(i=0; i<=k-1; i++) + { + v = ae_maxreal(v, ae_fabs(permce.ptr.pp_double[i][i], _state), _state); + } + v = coalesce(v, (double)(1), _state); + for(i=0; i<=k-1; i++) + { + permce.ptr.pp_double[i][i] = permce.ptr.pp_double[i][i]+(double)(10*k)*ae_machineepsilon*v; + } + rmatrixgemv(k, nfree, 1.0, &q, 0, 0, 0, &g, 0, 0.0, &tmpk, 0, _state); + rmatrixtrsv(k, &permce, 0, 0, ae_false, ae_false, 1, &tmpk, 0, _state); + rmatrixtrsv(k, &permce, 0, 0, ae_false, ae_false, 0, &tmpk, 0, _state); + rmatrixgemv(nfree, k, -1.0, &q, 0, 0, 1, &tmpk, 0, 0.0, &newtonstep, 0, _state); + } + else + { + + /* + * CEi = Q*R + * H = R'*R + * inv(H) = inv(R)*inv(R') + * + * NOTE: we apply minor regularizing perturbation to diagonal of R, + * which is equal to 10*K*Eps + */ + rmatrixqr(&permce, k, nfree, &tau, _state); + v = (double)(0); + for(i=0; i<=nfree-1; i++) + { + v = ae_maxreal(v, ae_fabs(permce.ptr.pp_double[i][i], _state), _state); + } + v = coalesce(v, (double)(1), _state); + for(i=0; i<=nfree-1; i++) + { + vv = (double)(10*nfree)*ae_machineepsilon*v; + if( ae_fp_less(permce.ptr.pp_double[i][i],(double)(0)) ) + { + vv = -vv; + } + permce.ptr.pp_double[i][i] = permce.ptr.pp_double[i][i]+vv; + } + ae_v_moveneg(&newtonstep.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); + rmatrixtrsv(nfree, &permce, 0, 0, ae_true, ae_false, 1, &newtonstep, 0, _state); + rmatrixtrsv(nfree, &permce, 0, 0, ae_true, ae_false, 0, &newtonstep, 0, _state); + } + + /* + * Post-reordering of Newton step + */ + for(j=nmain+nslack-1; j>=0; j--) + { + if( p2.ptr.p_int[j]!=j ) + { + idx0 = p2.ptr.p_int[j]; + idx1 = j; + v = newtonstep.ptr.p_double[idx0]; + newtonstep.ptr.p_double[idx0] = newtonstep.ptr.p_double[idx1]; + newtonstep.ptr.p_double[idx1] = v; + } + } + + /* + * NewtonStep contains Newton step subject to active bound constraints. + * + * Such step leads us to the minimizer of the equality constrained F, + * but such minimizer may be infeasible because some constraints which + * are inactive at the initial point can be violated at the solution. + * + * Thus, we perform optimization in two stages: + * a) perform bounded Newton step, i.e. step in the Newton direction + * until activation of the first constraint + * b) in case (MaxStepLen>0)and(MaxStepLen<1), perform additional iteration + * of the Armijo line search in the rest of the Newton direction. + */ + calculatestepbound(x, &newtonstep, 1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); + if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) + { + + /* + * Activation of the constraints prevent us from performing step, + * QP iterations are over + */ + break; + } + if( vartofreeze>=0 ) + { + v = ae_minreal(1.0, maxsteplen, _state); + } + else + { + v = 1.0; + } + ae_v_moved(&xn.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); + ae_v_add(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); + if( ae_fp_greater(maxsteplen,(double)(0))&&ae_fp_less(maxsteplen,(double)(1)) ) + { + + /* + * Newton step was restricted by activation of the constraints, + * perform Armijo iteration. + * + * Initial estimate for best step is zero step. We try different + * step sizes, from the 1-MaxStepLen (residual of the full Newton + * step) to progressively smaller and smaller steps. + */ + armijobeststep = 0.0; + armijobestfeas = optserv_feasibilityerror(&ce, &xn, nmain, nslack, k, &tmpk, _state); + armijostep = (double)1-maxsteplen; + for(j=0; j<=maxarmijoruns-1; j++) + { + ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijostep); + enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); + feaserr = optserv_feasibilityerror(&ce, &xa, nmain, nslack, k, &tmpk, _state); + if( ae_fp_less(feaserr,armijobestfeas) ) + { + armijobestfeas = feaserr; + armijobeststep = armijostep; + } + armijostep = 0.5*armijostep; + } + ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + ae_v_addd(&xa.ptr.p_double[0], 1, &newtonstep.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), armijobeststep); + enforceboundaryconstraints(&xa, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); + } + else + { + + /* + * Armijo iteration is not performed + */ + ae_v_move(&xa.ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + } + stage1isover = ae_fp_greater_eq(maxsteplen,(double)(1))||ae_fp_eq(maxsteplen,(double)(0)); + + /* + * Calculate feasibility errors for old and new X. + * These quantinies are used for debugging purposes only. + * However, we can leave them in release code because performance impact is insignificant. + * + * Update X. Exit if needed. + */ + feasold = optserv_feasibilityerror(&ce, x, nmain, nslack, k, &tmpk, _state); + feasnew = optserv_feasibilityerror(&ce, &xa, nmain, nslack, k, &tmpk, _state); + if( ae_fp_greater_eq(feasnew,feasold+infeasibilityincreasetolerance) ) + { + break; + } + ae_v_move(&x->ptr.p_double[0], 1, &xa.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + if( stage1isover ) + { + break; + } + } + + /* + * Stage 2: gradient projection algorithm (GPA) + * + * * calculate feasibility error (with respect to linear equality constraints) + * * calculate gradient G of F, project it into feasible area (G => PG) + * * exit if norm(PG) is exactly zero or feasibility error is smaller than EpsC + * * let XM be exact minimum of F along -PG (XM may be infeasible). + * calculate MaxStepLen = largest step in direction of -PG which retains feasibility. + * * perform bounded step from X to XN: + * a) XN=XM (if XM is feasible) + * b) XN=X-MaxStepLen*PG (otherwise) + * * X := XN + * * stop after specified number of iterations or when no new constraints was activated + * + * NOTES: + * * grad(F) = (CE'*CE)*x - (b'*CE)^T + * * CE[i] denotes I-th row of CE + * * XM = X+stp*(-PG) where stp=(grad(F(X)),PG)/(CE*PG,CE*PG). + * Here PG is a projected gradient, but in fact it can be arbitrary non-zero + * direction vector - formula for minimum of F along PG still will be correct. + */ + werechangesinconstraints = ae_false; + for(gparuns=1; gparuns<=k; gparuns++) + { + + /* + * calculate feasibility error and G + */ + optserv_feasibilityerrorgrad(&ce, x, nmain, nslack, k, &feaserr, &g, &tmpk, _state); + + /* + * project G, filter it (strip numerical noise) + */ + ae_v_move(&pg.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + projectgradientintobc(x, &pg, bndl, havebndl, bndu, havebndu, nmain, nslack, _state); + filterdirection(&pg, x, bndl, havebndl, bndu, havebndu, &s, nmain, nslack, 1.0E-9, _state); + for(i=0; i<=nmain+nslack-1; i++) + { + if( ae_fp_neq(ae_sqr(colnorms.ptr.p_double[i], _state),(double)(0)) ) + { + pg.ptr.p_double[i] = pg.ptr.p_double[i]/ae_sqr(colnorms.ptr.p_double[i], _state); + } + else + { + pg.ptr.p_double[i] = 0.0; + } + } + + /* + * Check GNorm and feasibility. + * Exit when GNorm is exactly zero. + */ + pgnorm = ae_v_dotproduct(&pg.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + pgnorm = ae_sqrt(pgnorm, _state); + if( ae_fp_eq(pgnorm,(double)(0)) ) + { + result = ae_fp_less_eq(feaserr,epsi); + ae_frame_leave(_state); + return result; + } + + /* + * calculate planned step length + */ + vn = ae_v_dotproduct(&g.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + vd = (double)(0); + rmatrixgemv(k, nmain+nslack, 1.0, &ce, 0, 0, 0, &pg, 0, 0.0, &tmpk, 0, _state); + for(i=0; i<=k-1; i++) + { + vd = vd+ae_sqr(tmpk.ptr.p_double[i], _state); + } + stp = vn/vd; + + /* + * Calculate step bound. + * Perform bounded step and post-process it + */ + calculatestepbound(x, &pg, -1.0, bndl, havebndl, bndu, havebndu, nmain, nslack, &vartofreeze, &valtofreeze, &maxsteplen, _state); + if( vartofreeze>=0&&ae_fp_eq(maxsteplen,(double)(0)) ) + { + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( vartofreeze>=0 ) + { + v = ae_minreal(stp, maxsteplen, _state); + } + else + { + v = stp; + } + ae_v_move(&xn.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + ae_v_subd(&xn.ptr.p_double[0], 1, &pg.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1), v); + postprocessboundedstep(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, vartofreeze, valtofreeze, v, maxsteplen, _state); + + /* + * update X + * check stopping criteria + */ + werechangesinconstraints = werechangesinconstraints||numberofchangedconstraints(&xn, x, bndl, havebndl, bndu, havebndu, nmain, nslack, _state)>0; + ae_v_move(&x->ptr.p_double[0], 1, &xn.ptr.p_double[0], 1, ae_v_len(0,nmain+nslack-1)); + *gpaits = *gpaits+1; + if( !werechangesinconstraints ) + { + break; + } + } + + /* + * Stage 3: decide to stop algorithm or not to stop + * + * 1. we can stop when last GPA run did NOT changed constraints status. + * It means that we've found final set of the active constraints even + * before GPA made its run. And it means that Newton step moved us to + * the minimum subject to the present constraints. + * Depending on feasibility error, True or False is returned. + */ + feaserr = optserv_feasibilityerror(&ce, x, nmain, nslack, k, &tmpk, _state); + feaserr1 = feaserr; + if( ae_fp_greater_eq(feaserr1,feaserr0-infeasibilityincreasetolerance) ) + { + inc(&badits, _state); + } + else + { + badits = 0; + } + if( ae_fp_less_eq(feaserr,epsi) ) + { + inc(&itswithintolerance, _state); + } + else + { + itswithintolerance = 0; + } + if( (!werechangesinconstraints||itswithintolerance>=maxitswithintolerance)||badits>=maxbadits ) + { + result = ae_fp_less_eq(feaserr,epsi); + ae_frame_leave(_state); + return result; + } + itscount = itscount+1; + + /* + * Block below is never executed; it is necessary just to avoid + * "unreachable code" warning about automatically generated code. + * + * We just need a way to transfer control to the end of the function, + * even a fake way which is never actually traversed. + */ + if( alwaysfalse(_state) ) + { + result = ae_false; + ae_assert(ae_false, "Assertion failed", _state); + break; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* + This function checks that input derivatives are right. First it scales +parameters DF0 and DF1 from segment [A;B] to [0;1]. Then it builds Hermite +spline and derivative of it in 0.5. Search scale as Max(DF0,DF1, |F0-F1|). +Right derivative has to satisfy condition: + |H-F|/S<=0,001, |H'-F'|/S<=0,001. + +INPUT PARAMETERS: + F0 - function's value in X-TestStep point; + DF0 - derivative's value in X-TestStep point; + F1 - function's value in X+TestStep point; + DF1 - derivative's value in X+TestStep point; + F - testing function's value; + DF - testing derivative's value; + Width- width of verification segment. + +RESULT: + If input derivatives is right then function returns true, else + function returns false. + + -- ALGLIB -- + Copyright 29.05.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool derivativecheck(double f0, + double df0, + double f1, + double df1, + double f, + double df, + double width, + ae_state *_state) +{ + double s; + double h; + double dh; + ae_bool result; + + + + /* + * Rescale input data to [0,1] + */ + df = width*df; + df0 = width*df0; + df1 = width*df1; + + /* + * Compute error scale, two sources are used: + * * magnitudes of derivatives and secants + * * magnitudes of input data times sqrt(machine_epsilon) + */ + s = 0.0; + s = ae_maxreal(s, ae_fabs(df0, _state), _state); + s = ae_maxreal(s, ae_fabs(df1, _state), _state); + s = ae_maxreal(s, ae_fabs(f1-f0, _state), _state); + s = ae_maxreal(s, ae_sqrt(ae_machineepsilon, _state)*ae_fabs(f0, _state), _state); + s = ae_maxreal(s, ae_sqrt(ae_machineepsilon, _state)*ae_fabs(f1, _state), _state); + + /* + * Compute H and dH/dX at the middle of interval + */ + h = 0.5*(f0+f1)+0.125*(df0-df1); + dh = 1.5*(f1-f0)-0.250*(df0+df1); + + /* + * Check + */ + if( ae_fp_neq(s,(double)(0)) ) + { + if( ae_fp_greater(ae_fabs(h-f, _state)/s,0.001)||ae_fp_greater(ae_fabs(dh-df, _state)/s,0.001) ) + { + result = ae_false; + return result; + } + } + else + { + if( ae_fp_neq(h-f,0.0)||ae_fp_neq(dh-df,0.0) ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Having quadratic target function + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +and its parabolic model along direction D + + F(x0+alpha*D) = D2*alpha^2 + D1*alpha + +this function estimates numerical errors in the coefficients of the model. + +It is important that this function does NOT calculate D1/D2 - it only +estimates numerical errors introduced during evaluation and compares their +magnitudes against magnitudes of numerical errors. As result, one of three +outcomes is returned for each coefficient: + * "true" coefficient is almost surely positive + * "true" coefficient is almost surely negative + * numerical errors in coefficient are so large that it can not be + reliably distinguished from zero + +INPUT PARAMETERS: + AbsASum - SUM(|A[i,j]|) + AbsASum2- SUM(A[i,j]^2) + MB - max(|B|) + MX - max(|X|) + MD - max(|D|) + D1 - linear coefficient + D2 - quadratic coefficient + +OUTPUT PARAMETERS: + D1Est - estimate of D1 sign, accounting for possible numerical + errors: + * >0 means "almost surely positive" (D1>0 and large) + * <0 means "almost surely negative" (D1<0 and large) + * =0 means "pessimistic estimate of numerical errors + in D1 is larger than magnitude of D1 itself; it is + impossible to reliably distinguish D1 from zero". + D2Est - estimate of D2 sign, accounting for possible numerical + errors: + * >0 means "almost surely positive" (D2>0 and large) + * <0 means "almost surely negative" (D2<0 and large) + * =0 means "pessimistic estimate of numerical errors + in D2 is larger than magnitude of D2 itself; it is + impossible to reliably distinguish D2 from zero". + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +void estimateparabolicmodel(double absasum, + double absasum2, + double mx, + double mb, + double md, + double d1, + double d2, + ae_int_t* d1est, + ae_int_t* d2est, + ae_state *_state) +{ + double d1esterror; + double d2esterror; + double eps; + double e1; + double e2; + + *d1est = 0; + *d2est = 0; + + + /* + * Error estimates: + * + * * error in D1=d'*(A*x+b) is estimated as + * ED1 = eps*MAX_ABS(D)*(MAX_ABS(X)*ENORM(A)+MAX_ABS(B)) + * * error in D2=0.5*d'*A*d is estimated as + * ED2 = eps*MAX_ABS(D)^2*ENORM(A) + * + * Here ENORM(A) is some pseudo-norm which reflects the way numerical + * error accumulates during addition. Two ways of accumulation are + * possible - worst case (errors always increase) and mean-case (errors + * may cancel each other). We calculate geometrical average of both: + * * ENORM_WORST(A) = SUM(|A[i,j]|) error in N-term sum grows as O(N) + * * ENORM_MEAN(A) = SQRT(SUM(A[i,j]^2)) error in N-term sum grows as O(sqrt(N)) + * * ENORM(A) = SQRT(ENORM_WORST(A),ENORM_MEAN(A)) + */ + eps = (double)4*ae_machineepsilon; + e1 = eps*md*(mx*absasum+mb); + e2 = eps*md*(mx*ae_sqrt(absasum2, _state)+mb); + d1esterror = ae_sqrt(e1*e2, _state); + if( ae_fp_less_eq(ae_fabs(d1, _state),d1esterror) ) + { + *d1est = 0; + } + else + { + *d1est = ae_sign(d1, _state); + } + e1 = eps*md*md*absasum; + e2 = eps*md*md*ae_sqrt(absasum2, _state); + d2esterror = ae_sqrt(e1*e2, _state); + if( ae_fp_less_eq(ae_fabs(d2, _state),d2esterror) ) + { + *d2est = 0; + } + else + { + *d2est = ae_sign(d2, _state); + } +} + + +/************************************************************************* +This function calculates inexact rank-K preconditioner for Hessian matrix +H=D+W'*C*W, where: +* H is a Hessian matrix, which is approximated by D/W/C +* D is a diagonal matrix with positive entries +* W is a rank-K correction +* C is a diagonal factor of rank-K correction + +This preconditioner is inexact but fast - it requires O(N*K) time to be +applied. Its main purpose - to be used in barrier/penalty/AUL methods, +where ill-conditioning is created by combination of two factors: +* simple bounds on variables => ill-conditioned D +* general barrier/penalty => correction W with large coefficient C (makes + problem ill-conditioned) but W itself is well conditioned. + +Preconditioner P is calculated by artificially constructing a set of BFGS +updates which tries to reproduce behavior of H: +* Sk = Wk (k-th row of W) +* Yk = (D+Wk'*Ck*Wk)*Sk +* Yk/Sk are reordered by ascending of C[k]*norm(Wk)^2 + +Here we assume that rows of Wk are orthogonal or nearly orthogonal, which +allows us to have O(N*K+K^2) update instead of O(N*K^2) one. Reordering of +updates is essential for having good performance on non-orthogonal problems +(updates which do not add much of curvature are added first, and updates +which add very large eigenvalues are added last and override effect of the +first updates). + +On input this function takes direction S and components of H. +On output it returns inv(H)*S + + -- ALGLIB -- + Copyright 30.06.2014 by Bochkanov Sergey +*************************************************************************/ +void inexactlbfgspreconditioner(/* Real */ ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t k, + precbuflbfgs* buf, + ae_state *_state) +{ + ae_int_t idx; + ae_int_t i; + ae_int_t j; + double v; + double v0; + double v1; + double vx; + double vy; + + + rvectorsetlengthatleast(&buf->norms, k, _state); + rvectorsetlengthatleast(&buf->alpha, k, _state); + rvectorsetlengthatleast(&buf->rho, k, _state); + rmatrixsetlengthatleast(&buf->yk, k, n, _state); + ivectorsetlengthatleast(&buf->idx, k, _state); + + /* + * Check inputs + */ + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "InexactLBFGSPreconditioner: D[]<=0", _state); + } + for(i=0; i<=k-1; i++) + { + ae_assert(ae_fp_greater_eq(c->ptr.p_double[i],(double)(0)), "InexactLBFGSPreconditioner: C[]<0", _state); + } + + /* + * Reorder linear terms according to increase of second derivative. + * Fill Norms[] array. + */ + for(idx=0; idx<=k-1; idx++) + { + v = ae_v_dotproduct(&w->ptr.pp_double[idx][0], 1, &w->ptr.pp_double[idx][0], 1, ae_v_len(0,n-1)); + buf->norms.ptr.p_double[idx] = v*c->ptr.p_double[idx]; + buf->idx.ptr.p_int[idx] = idx; + } + tagsortfasti(&buf->norms, &buf->idx, &buf->bufa, &buf->bufb, k, _state); + + /* + * Apply updates + */ + for(idx=0; idx<=k-1; idx++) + { + + /* + * Select update to perform (ordered by ascending of second derivative) + */ + i = buf->idx.ptr.p_int[idx]; + + /* + * Calculate YK and Rho + */ + v = ae_v_dotproduct(&w->ptr.pp_double[i][0], 1, &w->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + v = v*c->ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + buf->yk.ptr.pp_double[i][j] = (d->ptr.p_double[j]+v)*w->ptr.pp_double[i][j]; + } + v = 0.0; + v0 = 0.0; + v1 = 0.0; + for(j=0; j<=n-1; j++) + { + vx = w->ptr.pp_double[i][j]; + vy = buf->yk.ptr.pp_double[i][j]; + v = v+vx*vy; + v0 = v0+vx*vx; + v1 = v1+vy*vy; + } + if( (ae_fp_greater(v,(double)(0))&&ae_fp_greater(v0*v1,(double)(0)))&&ae_fp_greater(v/ae_sqrt(v0*v1, _state),(double)(n*10)*ae_machineepsilon) ) + { + buf->rho.ptr.p_double[i] = (double)1/v; + } + else + { + buf->rho.ptr.p_double[i] = 0.0; + } + } + for(idx=k-1; idx>=0; idx--) + { + + /* + * Select update to perform (ordered by ascending of second derivative) + */ + i = buf->idx.ptr.p_int[idx]; + + /* + * Calculate Alpha[] according to L-BFGS algorithm + * and update S[] + */ + v = ae_v_dotproduct(&w->ptr.pp_double[i][0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = buf->rho.ptr.p_double[i]*v; + buf->alpha.ptr.p_double[i] = v; + ae_v_subd(&s->ptr.p_double[0], 1, &buf->yk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + for(j=0; j<=n-1; j++) + { + s->ptr.p_double[j] = s->ptr.p_double[j]/d->ptr.p_double[j]; + } + for(idx=0; idx<=k-1; idx++) + { + + /* + * Select update to perform (ordered by ascending of second derivative) + */ + i = buf->idx.ptr.p_int[idx]; + + /* + * Calculate Beta according to L-BFGS algorithm + * and update S[] + */ + v = ae_v_dotproduct(&buf->yk.ptr.pp_double[i][0], 1, &s->ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = buf->alpha.ptr.p_double[i]-buf->rho.ptr.p_double[i]*v; + ae_v_addd(&s->ptr.p_double[0], 1, &w->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } +} + + +/************************************************************************* +This function prepares exact low-rank preconditioner for Hessian matrix +H=D+W'*C*W, where: +* H is a Hessian matrix, which is approximated by D/W/C +* D is a diagonal matrix with positive entries +* W is a rank-K correction +* C is a diagonal factor of rank-K correction, positive semidefinite + +This preconditioner is exact but relatively slow - it requires O(N*K^2) +time to be prepared and O(N*K) time to be applied. It is calculated with +the help of Woodbury matrix identity. + +It should be used as follows: +* PrepareLowRankPreconditioner() call PREPARES data structure +* subsequent calls to ApplyLowRankPreconditioner() APPLY preconditioner to + user-specified search direction. + + -- ALGLIB -- + Copyright 30.06.2014 by Bochkanov Sergey +*************************************************************************/ +void preparelowrankpreconditioner(/* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t n, + ae_int_t k, + precbuflowrank* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_bool b; + + + + /* + * Check inputs + */ + ae_assert(n>0, "PrepareLowRankPreconditioner: N<=0", _state); + ae_assert(k>=0, "PrepareLowRankPreconditioner: N<=0", _state); + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "PrepareLowRankPreconditioner: D[]<=0", _state); + } + for(i=0; i<=k-1; i++) + { + ae_assert(ae_fp_greater_eq(c->ptr.p_double[i],(double)(0)), "PrepareLowRankPreconditioner: C[]<0", _state); + } + + /* + * Prepare buffer structure; skip zero entries of update. + */ + rvectorsetlengthatleast(&buf->d, n, _state); + rmatrixsetlengthatleast(&buf->v, k, n, _state); + rvectorsetlengthatleast(&buf->bufc, k, _state); + rmatrixsetlengthatleast(&buf->bufw, k+1, n, _state); + buf->n = n; + buf->k = 0; + for(i=0; i<=k-1; i++) + { + + /* + * Estimate magnitude of update row; skip zero rows (either W or C are zero) + */ + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = v+w->ptr.pp_double[i][j]*w->ptr.pp_double[i][j]; + } + v = v*c->ptr.p_double[i]; + if( ae_fp_eq(v,(double)(0)) ) + { + continue; + } + ae_assert(ae_fp_greater(v,(double)(0)), "PrepareLowRankPreconditioner: internal error", _state); + + /* + * Copy non-zero update to buffer + */ + buf->bufc.ptr.p_double[buf->k] = c->ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + buf->v.ptr.pp_double[buf->k][j] = w->ptr.pp_double[i][j]; + buf->bufw.ptr.pp_double[buf->k][j] = w->ptr.pp_double[i][j]; + } + inc(&buf->k, _state); + } + + /* + * Reset K (for convenience) + */ + k = buf->k; + + /* + * Prepare diagonal factor; quick exit for K=0 + */ + for(i=0; i<=n-1; i++) + { + buf->d.ptr.p_double[i] = (double)1/d->ptr.p_double[i]; + } + if( k==0 ) + { + return; + } + + /* + * Use Woodbury matrix identity + */ + rmatrixsetlengthatleast(&buf->bufz, k, k, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=k-1; j++) + { + buf->bufz.ptr.pp_double[i][j] = 0.0; + } + } + for(i=0; i<=k-1; i++) + { + buf->bufz.ptr.pp_double[i][i] = (double)1/buf->bufc.ptr.p_double[i]; + } + for(j=0; j<=n-1; j++) + { + buf->bufw.ptr.pp_double[k][j] = (double)1/ae_sqrt(d->ptr.p_double[j], _state); + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + buf->bufw.ptr.pp_double[i][j] = buf->bufw.ptr.pp_double[i][j]*buf->bufw.ptr.pp_double[k][j]; + } + } + rmatrixgemm(k, k, n, 1.0, &buf->bufw, 0, 0, 0, &buf->bufw, 0, 0, 1, 1.0, &buf->bufz, 0, 0, _state); + b = spdmatrixcholeskyrec(&buf->bufz, 0, k, ae_true, &buf->tmp, _state); + ae_assert(b, "PrepareLowRankPreconditioner: internal error (Cholesky failure)", _state); + rmatrixlefttrsm(k, n, &buf->bufz, 0, 0, ae_true, ae_false, 1, &buf->v, 0, 0, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + buf->v.ptr.pp_double[i][j] = buf->v.ptr.pp_double[i][j]*buf->d.ptr.p_double[j]; + } + } +} + + +/************************************************************************* +This function apply exact low-rank preconditioner prepared by +PrepareLowRankPreconditioner function (see its comments for more information). + + -- ALGLIB -- + Copyright 30.06.2014 by Bochkanov Sergey +*************************************************************************/ +void applylowrankpreconditioner(/* Real */ ae_vector* s, + precbuflowrank* buf, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + double v; + + + n = buf->n; + k = buf->k; + rvectorsetlengthatleast(&buf->tmp, n, _state); + for(j=0; j<=n-1; j++) + { + buf->tmp.ptr.p_double[j] = buf->d.ptr.p_double[j]*s->ptr.p_double[j]; + } + for(i=0; i<=k-1; i++) + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = v+buf->v.ptr.pp_double[i][j]*s->ptr.p_double[j]; + } + for(j=0; j<=n-1; j++) + { + buf->tmp.ptr.p_double[j] = buf->tmp.ptr.p_double[j]-v*buf->v.ptr.pp_double[i][j]; + } + } + for(i=0; i<=n-1; i++) + { + s->ptr.p_double[i] = buf->tmp.ptr.p_double[i]; + } +} + + +/************************************************************************* +This subroutine initializes smoothness monitor at the beginning of the +optimization session. It requires variable scales to be passed. + +It is possible to perform "dummy" initialization with N=K=0. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorinit(smoothnessmonitor* monitor, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t k, + ae_bool checksmoothness, + ae_state *_state) +{ + ae_int_t i; + + + monitor->n = n; + monitor->k = k; + monitor->checksmoothness = checksmoothness; + monitor->linesearchspoiled = ae_false; + monitor->linesearchstarted = ae_false; + monitor->linesearchinneridx = -1; + monitor->linesearchouteridx = -1; + monitor->enqueuedcnt = 0; + monitor->sortedcnt = 0; + rvectorsetlengthatleast(&monitor->s, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + monitor->nonc0currentrating = 0.0; + monitor->nonc1currentrating = 0.0; + optguardinitinternal(&monitor->rep, n, k, _state); + monitor->nonc0strrating = 0.0; + monitor->nonc0lngrating = -ae_maxrealnumber; + monitor->nonc0strrep.positive = ae_false; + monitor->nonc0lngrep.positive = ae_false; + monitor->nonc1test0strrating = 0.0; + monitor->nonc1test0lngrating = -ae_maxrealnumber; + monitor->nonc1test0strrep.positive = ae_false; + monitor->nonc1test0lngrep.positive = ae_false; + monitor->nonc1test1strrating = 0.0; + monitor->nonc1test1lngrating = -ae_maxrealnumber; + monitor->nonc1test1strrep.positive = ae_false; + monitor->nonc1test1lngrep.positive = ae_false; + monitor->badgradhasxj = ae_false; + ae_vector_set_length(&monitor->rstateg0.ia, 4+1, _state); + ae_vector_set_length(&monitor->rstateg0.ra, 3+1, _state); + monitor->rstateg0.stage = -1; +} + + +/************************************************************************* +This subroutine starts line search + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorstartlinesearch(smoothnessmonitor* monitor, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + double v; + + + n = monitor->n; + k = monitor->k; + + /* + * Skip if inactive or spoiled by NAN + */ + if( !monitor->checksmoothness ) + { + return; + } + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = 0.5*v+x->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + v = 0.5*v+fi->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = 0.5*v+jac->ptr.pp_double[i][j]; + } + } + if( !ae_isfinite(v, _state) ) + { + monitor->linesearchspoiled = ae_true; + return; + } + + /* + * Finalize previous line search + */ + if( monitor->enqueuedcnt>0 ) + { + smoothnessmonitorfinalizelinesearch(monitor, _state); + } + + /* + * Store initial point + */ + monitor->linesearchstarted = ae_true; + monitor->linesearchinneridx = inneriter; + monitor->linesearchouteridx = outeriter; + monitor->enqueuedcnt = 1; + rvectorgrowto(&monitor->enqueuedstp, monitor->enqueuedcnt, _state); + rvectorgrowto(&monitor->enqueuedx, monitor->enqueuedcnt*n, _state); + rvectorgrowto(&monitor->enqueuedfunc, monitor->enqueuedcnt*k, _state); + rmatrixgrowrowsto(&monitor->enqueuedjac, monitor->enqueuedcnt*k, n, _state); + monitor->enqueuedstp.ptr.p_double[0] = 0.0; + for(j=0; j<=n-1; j++) + { + monitor->enqueuedx.ptr.p_double[j] = x->ptr.p_double[j]; + } + for(i=0; i<=k-1; i++) + { + monitor->enqueuedfunc.ptr.p_double[i] = fi->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + monitor->enqueuedjac.ptr.pp_double[i][j] = jac->ptr.pp_double[i][j]; + } + } + + /* + * Initialize sorted representation + */ + rvectorgrowto(&monitor->sortedstp, 1, _state); + ivectorgrowto(&monitor->sortedidx, 1, _state); + monitor->sortedstp.ptr.p_double[0] = 0.0; + monitor->sortedidx.ptr.p_int[0] = 0; + monitor->sortedcnt = 1; +} + + +/************************************************************************* +This subroutine starts line search for a scalar function - convenience +wrapper for ....StartLineSearch() with unscaled variables. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorstartlinesearch1u(smoothnessmonitor* monitor, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* invs, + /* Real */ const ae_vector* x, + double f0, + /* Real */ const ae_vector* j0, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + + + n = monitor->n; + k = monitor->k; + if( !monitor->checksmoothness ) + { + return; + } + ae_assert(k==1, "SmoothnessMonitorStartLineSearch1: K<>1", _state); + rvectorsetlengthatleast(&monitor->xu, n, _state); + rvectorsetlengthatleast(&monitor->f0, 1, _state); + rmatrixsetlengthatleast(&monitor->j0, 1, n, _state); + monitor->f0.ptr.p_double[0] = f0; + for(i=0; i<=n-1; i++) + { + monitor->xu.ptr.p_double[i] = x->ptr.p_double[i]*invs->ptr.p_double[i]; + monitor->j0.ptr.pp_double[0][i] = j0->ptr.p_double[i]*s->ptr.p_double[i]; + } + smoothnessmonitorstartlinesearch(monitor, &monitor->xu, &monitor->f0, &monitor->j0, inneriter, outeriter, _state); +} + + +/************************************************************************* +This subroutine enqueues one more trial point + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorenqueuepoint(smoothnessmonitor* monitor, + /* Real */ const ae_vector* d, + double stp, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + double v; + ae_int_t enqueuedcnt; + ae_int_t sortedcnt; + ae_bool hasduplicates; + ae_int_t funcidx; + ae_int_t stpidx; + double f0; + double f1; + double f2; + double f3; + double f4; + double noise0; + double noise1; + double noise2; + double noise3; + double rating; + double lipschitz; + double nrm; + double lengthrating; + + + n = monitor->n; + k = monitor->k; + + /* + * Skip if inactive or spoiled by NAN + */ + if( (!monitor->checksmoothness||monitor->linesearchspoiled)||!monitor->linesearchstarted ) + { + return; + } + v = stp; + for(i=0; i<=n-1; i++) + { + v = 0.5*v+x->ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + v = 0.5*v+d->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + v = 0.5*v+fi->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = 0.5*v+jac->ptr.pp_double[i][j]; + } + } + if( !ae_isfinite(v, _state) ) + { + monitor->linesearchspoiled = ae_true; + return; + } + + /* + * Enqueue + */ + inc(&monitor->enqueuedcnt, _state); + enqueuedcnt = monitor->enqueuedcnt; + rvectorgrowto(&monitor->dcur, n, _state); + rvectorgrowto(&monitor->enqueuedstp, enqueuedcnt, _state); + rvectorgrowto(&monitor->enqueuedx, enqueuedcnt*n, _state); + rvectorgrowto(&monitor->enqueuedfunc, enqueuedcnt*k, _state); + rmatrixgrowrowsto(&monitor->enqueuedjac, enqueuedcnt*k, n, _state); + monitor->enqueuedstp.ptr.p_double[enqueuedcnt-1] = stp; + for(j=0; j<=n-1; j++) + { + monitor->dcur.ptr.p_double[j] = d->ptr.p_double[j]; + } + for(j=0; j<=n-1; j++) + { + monitor->enqueuedx.ptr.p_double[(enqueuedcnt-1)*n+j] = x->ptr.p_double[j]; + } + for(i=0; i<=k-1; i++) + { + monitor->enqueuedfunc.ptr.p_double[(enqueuedcnt-1)*k+i] = fi->ptr.p_double[i]; + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + monitor->enqueuedjac.ptr.pp_double[(enqueuedcnt-1)*k+i][j] = jac->ptr.pp_double[i][j]; + } + } + + /* + * Update sorted representation: insert to the end, reorder + */ + sortedcnt = monitor->sortedcnt; + hasduplicates = ae_false; + for(i=0; i<=sortedcnt-1; i++) + { + hasduplicates = hasduplicates||monitor->sortedstp.ptr.p_double[i]==stp; + } + if( !hasduplicates ) + { + inc(&monitor->sortedcnt, _state); + sortedcnt = monitor->sortedcnt; + rvectorgrowto(&monitor->sortedstp, sortedcnt, _state); + ivectorgrowto(&monitor->sortedidx, sortedcnt, _state); + monitor->sortedstp.ptr.p_double[sortedcnt-1] = stp; + monitor->sortedidx.ptr.p_int[sortedcnt-1] = enqueuedcnt-1; + for(i=sortedcnt-2; i>=0; i--) + { + if( monitor->sortedstp.ptr.p_double[i]<=monitor->sortedstp.ptr.p_double[i+1] ) + { + break; + } + v = monitor->sortedstp.ptr.p_double[i]; + monitor->sortedstp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i+1]; + monitor->sortedstp.ptr.p_double[i+1] = v; + j = monitor->sortedidx.ptr.p_int[i]; + monitor->sortedidx.ptr.p_int[i] = monitor->sortedidx.ptr.p_int[i+1]; + monitor->sortedidx.ptr.p_int[i+1] = j; + } + } + + /* + * Scan sorted representation, check for C0 and C1 continuity + * violations. + */ + rvectorsetlengthatleast(&monitor->f, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->g, sortedcnt*n, _state); + for(funcidx=0; funcidx<=k-1; funcidx++) + { + + /* + * Fetch current function and its gradient to the contiguous storage + */ + for(i=0; i<=sortedcnt-1; i++) + { + monitor->f.ptr.p_double[i] = monitor->enqueuedfunc.ptr.p_double[monitor->sortedidx.ptr.p_int[i]*k+funcidx]; + for(j=0; j<=n-1; j++) + { + monitor->g.ptr.p_double[i*n+j] = monitor->enqueuedjac.ptr.pp_double[monitor->sortedidx.ptr.p_int[i]*k+funcidx][j]; + } + } + + /* + * Check C0 continuity. + * + * The basis approach is that we find appropriate candidate point + * (either a local minimum along the line - for target; or an interval + * where function sign is changed - for constraints), calculate left + * and right estimates of the Lipschitz constant (slopes between points + * #0 and #1, #2 and #3), and then calculate slope between points #1 and + * #2 and compare it with left/right estimates. + * + * The actual approach is a bit more complex to account for different + * sources of numerical noise and different false positive scenarios. + */ + if( funcidx==0 ) + { + for(stpidx=0; stpidx<=sortedcnt-4; stpidx++) + { + f0 = monitor->f.ptr.p_double[stpidx+0]; + f1 = monitor->f.ptr.p_double[stpidx+1]; + f2 = monitor->f.ptr.p_double[stpidx+2]; + f3 = monitor->f.ptr.p_double[stpidx+3]; + noise0 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f0, _state), 1.0, _state); + noise1 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f1, _state), 1.0, _state); + noise2 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f2, _state), 1.0, _state); + noise3 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f3, _state), 1.0, _state); + if( !(f1sortedstp.ptr.p_double[stpidx+1]-monitor->sortedstp.ptr.p_double[stpidx+0], monitor->sortedstp.ptr.p_double[stpidx+2]-monitor->sortedstp.ptr.p_double[stpidx+1], monitor->sortedstp.ptr.p_double[stpidx+3]-monitor->sortedstp.ptr.p_double[stpidx+2], ae_false, &rating, &lipschitz, _state); + if( rating>optserv_ogminrating0 ) + { + + /* + * Store to total report + */ + monitor->rep.nonc0suspected = ae_true; + monitor->rep.nonc0test0positive = ae_true; + if( rating>monitor->nonc0currentrating ) + { + monitor->nonc0currentrating = rating; + monitor->rep.nonc0lipschitzc = lipschitz; + monitor->rep.nonc0fidx = funcidx; + } + + /* + * Store to "strongest" report + */ + if( rating>monitor->nonc0strrating ) + { + monitor->nonc0strrating = rating; + monitor->nonc0strrep.positive = ae_true; + monitor->nonc0strrep.fidx = funcidx; + monitor->nonc0strrep.n = n; + monitor->nonc0strrep.cnt = sortedcnt; + monitor->nonc0strrep.stpidxa = stpidx+0; + monitor->nonc0strrep.stpidxb = stpidx+3; + monitor->nonc0strrep.inneriter = monitor->linesearchinneridx; + monitor->nonc0strrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc0strrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc0strrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc0strrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc0strrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc0strrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc0strrep.f, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc0strrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc0strrep.f.ptr.p_double[i] = monitor->f.ptr.p_double[i]; + } + } + + /* + * Store to "longest" report + */ + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = nrm+ae_sqr(monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]-monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[sortedcnt-1]*n+i], _state); + } + nrm = ae_sqrt(nrm, _state); + nrm = coalesce(nrm, ae_machineepsilon, _state); + lengthrating = ae_log(nrm, _state)+0.2*ae_log((double)(sortedcnt), _state)+0.2*ae_log(rating, _state); + if( lengthrating>monitor->nonc0lngrating ) + { + monitor->nonc0lngrating = lengthrating; + monitor->nonc0lngrep.positive = ae_true; + monitor->nonc0lngrep.fidx = funcidx; + monitor->nonc0lngrep.n = n; + monitor->nonc0lngrep.cnt = sortedcnt; + monitor->nonc0lngrep.stpidxa = stpidx+0; + monitor->nonc0lngrep.stpidxb = stpidx+3; + monitor->nonc0lngrep.inneriter = monitor->linesearchinneridx; + monitor->nonc0lngrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc0lngrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc0lngrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc0lngrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc0lngrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc0lngrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc0lngrep.f, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc0lngrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc0lngrep.f.ptr.p_double[i] = monitor->f.ptr.p_double[i]; + } + } + } + } + } + + /* + * C1 continuity test #0 + */ + for(stpidx=0; stpidx<=sortedcnt-7; stpidx++) + { + + /* + * Fetch function values + */ + f2 = monitor->f.ptr.p_double[stpidx+2]; + f3 = monitor->f.ptr.p_double[stpidx+3]; + f4 = monitor->f.ptr.p_double[stpidx+4]; + noise2 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f2, _state), 1.0, _state); + noise3 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f3, _state), 1.0, _state); + + /* + * Decide whether we want to test this interval or not; for target + * function we test intervals around minimum, for constraints we + * additionally test intervals of sign change. + */ + if( funcidx==0 ) + { + + /* + * Target function: skip if not minimum + */ + if( !(f30&&!(f3f.ptr.p_double[stpidx+0]; + f1 = monitor->f.ptr.p_double[stpidx+1]; + f2 = monitor->f.ptr.p_double[stpidx+2]; + f3 = monitor->f.ptr.p_double[stpidx+3]; + noise0 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f0, _state), 1.0, _state); + noise1 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f1, _state), 1.0, _state); + noise2 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f2, _state), 1.0, _state); + noise3 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f3, _state), 1.0, _state); + + /* + * Decide whether we want to test this interval or not; for target + * function we test intervals around minimum, for constraints we + * additionally test intervals of sign change. + */ + if( funcidx==0 ) + { + + /* + * Skip if not minimum + */ + if( !(f10&&!(f1n; + k = monitor->k; + if( !monitor->checksmoothness ) + { + return; + } + ae_assert(k==1, "SmoothnessMonitorEnqueuePoint1: K<>1", _state); + rvectorsetlengthatleast(&monitor->xu, n, _state); + rvectorsetlengthatleast(&monitor->du, n, _state); + rvectorsetlengthatleast(&monitor->f0, 1, _state); + rmatrixsetlengthatleast(&monitor->j0, 1, n, _state); + monitor->f0.ptr.p_double[0] = f0; + for(i=0; i<=n-1; i++) + { + monitor->xu.ptr.p_double[i] = x->ptr.p_double[i]*invs->ptr.p_double[i]; + monitor->du.ptr.p_double[i] = d->ptr.p_double[i]*invs->ptr.p_double[i]; + monitor->j0.ptr.pp_double[0][i] = j0->ptr.p_double[i]*s->ptr.p_double[i]; + } + smoothnessmonitorenqueuepoint(monitor, &monitor->du, stp, &monitor->xu, &monitor->f0, &monitor->j0, _state); +} + + +/************************************************************************* +This subroutine finalizes line search + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorfinalizelinesearch(smoothnessmonitor* monitor, + ae_state *_state) +{ + + + + /* + * As for now - nothing to be done. + */ +} + + +/************************************************************************* +This function starts aggressive probing of the Lagrangian for a range of +step lengths [0,StpMax]. + +INPUT PARAMETERS: + Monitor - monitor object + LagMult - array[K-1], lagrange multipliers for nonlinear + constraints + X - array[N], initial point for probing + D - array[N], probing direction + StpMax - range of steps to probe + + + -- ALGLIB -- + Copyright 10.10.2019 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorstartlagrangianprobing(smoothnessmonitor* monitor, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double stpmax, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + + + n = monitor->n; + k = monitor->k; + ae_assert(isfinitevector(x, n, _state), "SmoothnessMonitorStartLagrangianProbing: bad X[] array", _state); + ae_assert(isfinitevector(d, n, _state), "SmoothnessMonitorStartLagrangianProbing: bad D[] array", _state); + ae_assert(ae_isfinite(stpmax, _state)&&ae_fp_greater(stpmax,(double)(0)), "SmoothnessMonitorStartLagrangianProbing: StpMax<=0", _state); + ae_assert(k>=1, "SmoothnessMonitorStartLagrangianProbing: monitor object is initialized with K<=0", _state); + monitor->lagprobnstepsstored = 0; + monitor->lagprobstepmax = stpmax; + monitor->lagprobinneriter = inneriter; + monitor->lagprobouteriter = outeriter; + rvectorsetlengthatleast(&monitor->lagprobxs, n, _state); + rvectorsetlengthatleast(&monitor->lagprobd, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->lagprobxs.ptr.p_double[i] = x->ptr.p_double[i]; + monitor->lagprobd.ptr.p_double[i] = d->ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->lagprobx, n, _state); + rvectorsetlengthatleast(&monitor->lagprobfi, k, _state); + rmatrixsetlengthatleast(&monitor->lagprobj, k, n, _state); + ae_vector_set_length(&monitor->lagrangianprobingrcomm.ia, 3+1, _state); + ae_vector_set_length(&monitor->lagrangianprobingrcomm.ra, 4+1, _state); + monitor->lagrangianprobingrcomm.stage = -1; +} + + +/************************************************************************* +This function performs aggressive probing and sends points to smoothness +monitoring queue via EnqueuePoint() call. + +After each call it returns point to evaluate in Monitor.LagProbX and +current step in Monitor.LagProbStp. Caller has to load function values and +Jacobian at X into Monitor.LagProbFi and Monitor.LagProbJ, current Lagrangian +to Monitor.LagProbRawLag and continue iteration. + +NOTE: LagProbX[] is not guarded against constraint violation. Both non-box + and box constraints are ignored. It is caller responsibility to + provide appropriate X[], D[] and StpMax which do not violate + important constraints + + -- ALGLIB -- + Copyright 10.10.2019 by Bochkanov Sergey +*************************************************************************/ +ae_bool smoothnessmonitorprobelagrangian(smoothnessmonitor* monitor, + ae_state *_state) +{ + ae_int_t stpidx; + ae_int_t i; + ae_int_t j; + ae_int_t idx; + double stp; + double vlargest; + double v; + double v0; + double v1; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( monitor->lagrangianprobingrcomm.stage>=0 ) + { + stpidx = monitor->lagrangianprobingrcomm.ia.ptr.p_int[0]; + i = monitor->lagrangianprobingrcomm.ia.ptr.p_int[1]; + j = monitor->lagrangianprobingrcomm.ia.ptr.p_int[2]; + idx = monitor->lagrangianprobingrcomm.ia.ptr.p_int[3]; + stp = monitor->lagrangianprobingrcomm.ra.ptr.p_double[0]; + vlargest = monitor->lagrangianprobingrcomm.ra.ptr.p_double[1]; + v = monitor->lagrangianprobingrcomm.ra.ptr.p_double[2]; + v0 = monitor->lagrangianprobingrcomm.ra.ptr.p_double[3]; + v1 = monitor->lagrangianprobingrcomm.ra.ptr.p_double[4]; + } + else + { + stpidx = 359; + i = -58; + j = -919; + idx = -909; + stp = 81.0; + vlargest = 255.0; + v = 74.0; + v0 = -788.0; + v1 = 809.0; + } + if( monitor->lagrangianprobingrcomm.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + stpidx = 0; +lbl_1: + if( stpidx>40 ) + { + goto lbl_3; + } + + /* + * Increase storage size + */ + rvectorgrowto(&monitor->lagprobsteps, monitor->lagprobnstepsstored+1, _state); + rvectorgrowto(&monitor->lagproblagrangians, monitor->lagprobnstepsstored+1, _state); + rmatrixgrowrowsto(&monitor->lagprobvalues, monitor->lagprobnstepsstored+1, monitor->k, _state); + rmatrixgrowrowsto(&monitor->lagprobjacobians, monitor->lagprobnstepsstored+1, monitor->n*monitor->k, _state); + + /* + * Determine probing step length, save step to the end of the storage + */ + if( stpidx<=10 ) + { + + /* + * First 11 steps are performed over equidistant grid + */ + stp = (double)stpidx/(double)10*monitor->lagprobstepmax; + } + else + { + + /* + * Subsequent steps target interesting points + */ + ae_assert(monitor->lagprobnstepsstored>=3, "SMonitor: critical integrity check failed", _state); + stp = (double)(0); + if( stpidx%3==0 ) + { + + /* + * Target interval with maximum change in Lagrangian + */ + idx = -1; + vlargest = (double)(0); + for(j=0; j<=monitor->lagprobnstepsstored-2; j++) + { + v = ae_fabs(monitor->lagproblagrangians.ptr.p_double[j+1]-monitor->lagproblagrangians.ptr.p_double[j], _state); + if( idx<0||ae_fp_greater(v,vlargest) ) + { + idx = j; + vlargest = v; + } + } + stp = 0.5*(monitor->lagprobsteps.ptr.p_double[idx]+monitor->lagprobsteps.ptr.p_double[idx+1]); + } + if( stpidx%3==1 ) + { + + /* + * Target interval [J,J+2] with maximum change in slope of Lagrangian, + * select subinterval [J,J+1] or [J+1,J+2] (one with maximum length). + */ + idx = -1; + vlargest = (double)(0); + for(j=0; j<=monitor->lagprobnstepsstored-3; j++) + { + v0 = (monitor->lagproblagrangians.ptr.p_double[j+1]-monitor->lagproblagrangians.ptr.p_double[j+0])/(monitor->lagprobsteps.ptr.p_double[j+1]-monitor->lagprobsteps.ptr.p_double[j+0]+ae_machineepsilon); + v1 = (monitor->lagproblagrangians.ptr.p_double[j+2]-monitor->lagproblagrangians.ptr.p_double[j+1])/(monitor->lagprobsteps.ptr.p_double[j+2]-monitor->lagprobsteps.ptr.p_double[j+1]+ae_machineepsilon); + v = ae_fabs(v0-v1, _state); + if( idx<0||ae_fp_greater(v,vlargest) ) + { + idx = j; + vlargest = v; + } + } + if( ae_fp_greater(monitor->lagprobsteps.ptr.p_double[idx+2]-monitor->lagprobsteps.ptr.p_double[idx+1],monitor->lagprobsteps.ptr.p_double[idx+1]-monitor->lagprobsteps.ptr.p_double[idx+0]) ) + { + stp = 0.5*(monitor->lagprobsteps.ptr.p_double[idx+2]+monitor->lagprobsteps.ptr.p_double[idx+1]); + } + else + { + stp = 0.5*(monitor->lagprobsteps.ptr.p_double[idx+1]+monitor->lagprobsteps.ptr.p_double[idx+0]); + } + } + if( stpidx%3==2 ) + { + + /* + * Target interval with maximum change in sum of squared Jacobian differences + */ + idx = -1; + vlargest = (double)(0); + for(j=0; j<=monitor->lagprobnstepsstored-2; j++) + { + v = (double)(0); + for(i=0; i<=monitor->k*monitor->n-1; i++) + { + v = v+ae_sqr(monitor->lagprobjacobians.ptr.pp_double[j+1][i]-monitor->lagprobjacobians.ptr.pp_double[j][i], _state); + } + if( idx<0||ae_fp_greater(v,vlargest) ) + { + idx = j; + vlargest = v; + } + } + stp = 0.5*(monitor->lagprobsteps.ptr.p_double[idx]+monitor->lagprobsteps.ptr.p_double[idx+1]); + } + } + monitor->lagprobsteps.ptr.p_double[monitor->lagprobnstepsstored] = stp; + + /* + * Retrieve user values + */ + for(i=0; i<=monitor->n-1; i++) + { + monitor->lagprobx.ptr.p_double[i] = monitor->lagprobxs.ptr.p_double[i]+monitor->lagprobd.ptr.p_double[i]*stp; + } + monitor->lagprobstp = stp; + monitor->lagrangianprobingrcomm.stage = 0; + goto lbl_rcomm; +lbl_0: + for(i=0; i<=monitor->k-1; i++) + { + monitor->lagprobvalues.ptr.pp_double[monitor->lagprobnstepsstored][i] = monitor->lagprobfi.ptr.p_double[i]; + for(j=0; j<=monitor->n-1; j++) + { + monitor->lagprobjacobians.ptr.pp_double[monitor->lagprobnstepsstored][i*monitor->n+j] = monitor->lagprobj.ptr.pp_double[i][j]; + } + } + monitor->lagproblagrangians.ptr.p_double[monitor->lagprobnstepsstored] = monitor->lagprobrawlag; + inc(&monitor->lagprobnstepsstored, _state); + if( stpidx==0 ) + { + ae_assert(ae_fp_eq(stp,(double)(0)), "SmoothnessMonitorProbeLagrangian: integrity check failed", _state); + smoothnessmonitorstartlinesearch(monitor, &monitor->lagprobx, &monitor->lagprobfi, &monitor->lagprobj, monitor->lagprobinneriter, monitor->lagprobouteriter, _state); + } + else + { + smoothnessmonitorenqueuepoint(monitor, &monitor->lagprobd, stp, &monitor->lagprobx, &monitor->lagprobfi, &monitor->lagprobj, _state); + } + + /* + * Resort + */ + for(j=monitor->lagprobnstepsstored-1; j>=1; j--) + { + if( ae_fp_less_eq(monitor->lagprobsteps.ptr.p_double[j-1],monitor->lagprobsteps.ptr.p_double[j]) ) + { + break; + } + swapelements(&monitor->lagprobsteps, j-1, j, _state); + swapelements(&monitor->lagproblagrangians, j-1, j, _state); + swaprows(&monitor->lagprobvalues, j-1, j, monitor->k, _state); + swaprows(&monitor->lagprobjacobians, j-1, j, monitor->n*monitor->k, _state); + } + stpidx = stpidx+1; + goto lbl_1; +lbl_3: + smoothnessmonitorfinalizelinesearch(monitor, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + monitor->lagrangianprobingrcomm.ia.ptr.p_int[0] = stpidx; + monitor->lagrangianprobingrcomm.ia.ptr.p_int[1] = i; + monitor->lagrangianprobingrcomm.ia.ptr.p_int[2] = j; + monitor->lagrangianprobingrcomm.ia.ptr.p_int[3] = idx; + monitor->lagrangianprobingrcomm.ra.ptr.p_double[0] = stp; + monitor->lagrangianprobingrcomm.ra.ptr.p_double[1] = vlargest; + monitor->lagrangianprobingrcomm.ra.ptr.p_double[2] = v; + monitor->lagrangianprobingrcomm.ra.ptr.p_double[3] = v0; + monitor->lagrangianprobingrcomm.ra.ptr.p_double[4] = v1; + return result; +} + + +/************************************************************************* +This function prints probing results to trace log. + +Tracing is performed using fixed width for all columns, so you may print +a header before printing trace - and reasonably expect that its width will +match that of the trace. This function promises that it wont change trace +output format without introducing breaking changes into its signature. + +NOTE: this function ALWAYS tries to print results; it is caller's responsibility + to decide whether he needs tracing or not. + + -- ALGLIB -- + Copyright 10.10.2019 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitortracelagrangianprobingresults(smoothnessmonitor* monitor, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + double steplen; + double mxd; + ae_vector lagrangianslopes; + ae_vector targetslopes; + + ae_frame_make(_state, &_frame_block); + memset(&lagrangianslopes, 0, sizeof(lagrangianslopes)); + memset(&targetslopes, 0, sizeof(targetslopes)); + ae_vector_init(&lagrangianslopes, 0, DT_REAL, _state, ae_true); + ae_vector_init(&targetslopes, 0, DT_REAL, _state, ae_true); + + + /* + * Compute slopes + */ + ae_assert(monitor->lagprobnstepsstored>=2, "SmoothnessMonitorTraceLagrangianProbingResults: less than 2 probing steps", _state); + ae_vector_set_length(&lagrangianslopes, monitor->lagprobnstepsstored, _state); + ae_vector_set_length(&targetslopes, monitor->lagprobnstepsstored, _state); + mxd = (double)(0); + for(i=0; i<=monitor->n-1; i++) + { + mxd = ae_maxreal(mxd, ae_fabs(monitor->lagprobd.ptr.p_double[i], _state), _state); + } + for(i=0; i<=monitor->lagprobnstepsstored-2; i++) + { + steplen = monitor->lagprobsteps.ptr.p_double[i+1]-monitor->lagprobsteps.ptr.p_double[i]+(double)100*ae_machineepsilon; + steplen = steplen*(mxd+(double)100*ae_machineepsilon); + lagrangianslopes.ptr.p_double[i] = (monitor->lagproblagrangians.ptr.p_double[i+1]-monitor->lagproblagrangians.ptr.p_double[i])/steplen; + targetslopes.ptr.p_double[i] = (monitor->lagprobvalues.ptr.pp_double[i+1][0]-monitor->lagprobvalues.ptr.pp_double[i][0])/steplen; + } + lagrangianslopes.ptr.p_double[monitor->lagprobnstepsstored-1] = lagrangianslopes.ptr.p_double[monitor->lagprobnstepsstored-2]; + targetslopes.ptr.p_double[monitor->lagprobnstepsstored-1] = targetslopes.ptr.p_double[monitor->lagprobnstepsstored-2]; + + /* + * Print to trace log + */ + ae_trace("*** ------------------------------------------------------------\n"); + for(i=0; i<=monitor->lagprobnstepsstored-1; i++) + { + ae_trace("*** | %0.4f |", + (double)(monitor->lagprobsteps.ptr.p_double[i])); + ae_trace(" %11.3e %10.2e |", + (double)(monitor->lagproblagrangians.ptr.p_double[i]-monitor->lagproblagrangians.ptr.p_double[0]), + (double)(lagrangianslopes.ptr.p_double[i])); + ae_trace(" %11.3e %10.2e |", + (double)(monitor->lagprobvalues.ptr.pp_double[i][0]-monitor->lagprobvalues.ptr.pp_double[0][0]), + (double)(targetslopes.ptr.p_double[i])); + ae_trace("\n"); + } + ae_trace("*** ------------------------------------------------------------\n"); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine tells monitor to output trace info. + +If CallerSuggestsTrace=True, monitor ALWAYS prints trace, even if no +suspicions were raised during optimization. If CallerSuggestsTrace=False, +the monitor will print trace only if: +* trace was requested by trace tag 'OPTGUARD' AND suspicious points were + found during optimization +* trace was requested by trace tag 'OPTGUARD.ALWAYS' - always + + -- ALGLIB -- + Copyright 11.10.2019 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitortracestatus(const smoothnessmonitor* monitor, + ae_bool callersuggeststrace, + ae_state *_state) +{ + ae_bool needreport; + ae_bool needxdreport; + ae_bool suspicionsraised; + ae_int_t i; + double slope; + + + + /* + * Do we need trace report? + */ + suspicionsraised = (monitor->rep.nonc0suspected||monitor->rep.nonc1suspected)||monitor->rep.badgradsuspected; + needreport = ae_false; + needreport = needreport||callersuggeststrace; + needreport = needreport||ae_is_trace_enabled("OPTGUARD.ALWAYS"); + needreport = needreport||(ae_is_trace_enabled("OPTGUARD")&&suspicionsraised); + if( !needreport ) + { + return; + } + needxdreport = needreport&&ae_is_trace_enabled("OPTIMIZERS.X"); + + /* + * + */ + ae_trace("\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// OPTGUARD INTEGRITY CHECKER REPORT //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + if( !suspicionsraised ) + { + ae_trace("> no discontinuity/nonsmoothness/bad-gradient suspicions were raised during optimization\n"); + return; + } + if( monitor->rep.nonc0suspected ) + { + ae_trace("> [WARNING] suspected discontinuity (aka C0-discontinuity)\n"); + } + if( monitor->rep.nonc1suspected ) + { + ae_trace("> [WARNING] suspected nonsmoothness (aka C1-discontinuity)\n"); + } + ae_trace("> printing out test reports...\n"); + if( monitor->rep.nonc0suspected&&monitor->rep.nonc0test0positive ) + { + ae_trace("> printing out discontinuity test #0 report:\n"); + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | Test #0 for discontinuity was triggered (this test |\n"); + ae_trace("*** | analyzes changes in function values). |\n"); + ae_trace("*** | |\n"); + ae_trace("*** | Function information: |\n"); + ae_trace("*** | * function index: %10d", + (int)(monitor->nonc0lngrep.fidx)); + if( monitor->nonc0lngrep.fidx==0 ) + { + ae_trace(" (target) |\n"); + } + else + { + ae_trace(" (constraint) |\n"); + } + ae_trace("*** | * F() Lipschitz const: %10.2e |\n", + (double)(monitor->rep.nonc0lipschitzc)); + ae_trace("*** | |\n"); + ae_trace("*** | Iteration information: |\n"); + if( monitor->nonc0lngrep.inneriter>=0 ) + { + ae_trace("*** | * inner iter idx: %10d |\n", + (int)(monitor->nonc0lngrep.inneriter)); + } + if( monitor->nonc0lngrep.outeriter>=0 ) + { + ae_trace("*** | * outer iter idx: %10d |\n", + (int)(monitor->nonc0lngrep.outeriter)); + } + ae_trace("*** | |\n"); + ae_trace("*** | Printing out log of suspicious line search XK+Stp*D |\n"); + ae_trace("*** | Look for abrupt changes in slope. |\n"); + if( !needxdreport ) + { + ae_trace("*** | NOTE: XK and D are not printed by default. If you |\n"); + ae_trace("*** | need them, add trace tag OPTIMIZERS.X |\n"); + } + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | step along D | delta F | slope |\n"); + ae_trace("*** ------------------------------------------------------|\n"); + for(i=0; i<=monitor->nonc0lngrep.cnt-1; i++) + { + slope = monitor->nonc0lngrep.f.ptr.p_double[ae_minint(i+1, monitor->nonc0lngrep.cnt-1, _state)]-monitor->nonc0lngrep.f.ptr.p_double[i]; + slope = slope/(1.0e-15+monitor->nonc0lngrep.stp.ptr.p_double[ae_minint(i+1, monitor->nonc0lngrep.cnt-1, _state)]-monitor->nonc0lngrep.stp.ptr.p_double[i]); + ae_trace("*** | %13.5e | %13.5e | %11.3e |", + (double)(monitor->nonc0lngrep.stp.ptr.p_double[i]), + (double)(monitor->nonc0lngrep.f.ptr.p_double[i]-monitor->nonc0lngrep.f.ptr.p_double[0]), + (double)(slope)); + if( i>=monitor->nonc0lngrep.stpidxa&&i<=monitor->nonc0lngrep.stpidxb ) + { + ae_trace(" <---"); + } + ae_trace("\n"); + } + ae_trace("*** ------------------------------------------------------|\n"); + if( needxdreport ) + { + ae_trace("*** > printing raw variables\n"); + ae_trace("*** XK = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc0lngrep.x0, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc0lngrep.d, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** > printing scaled variables (values are divided by user-specified scales)\n"); + ae_trace("*** XK = "); + tracevectorautoprec(&monitor->nonc0lngrep.x0, 0, monitor->n, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorautoprec(&monitor->nonc0lngrep.d, 0, monitor->n, _state); + ae_trace("\n"); + } + } + if( monitor->rep.nonc1suspected&&monitor->rep.nonc1test0positive ) + { + ae_trace("> printing out nonsmoothness test #0 report:\n"); + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | Test #0 for nonsmoothness was triggered (this test |\n"); + ae_trace("*** | analyzes changes in function values and ignores |\n"); + ae_trace("*** | gradient info). |\n"); + ae_trace("*** | |\n"); + ae_trace("*** | Function information: |\n"); + ae_trace("*** | * function index: %10d", + (int)(monitor->nonc1test0lngrep.fidx)); + if( monitor->nonc1test0lngrep.fidx==0 ) + { + ae_trace(" (target) |\n"); + } + else + { + ae_trace(" (constraint) |\n"); + } + ae_trace("*** | * dF/dX Lipschitz const: %10.2e |\n", + (double)(monitor->rep.nonc1lipschitzc)); + ae_trace("*** | |\n"); + ae_trace("*** | Iteration information: |\n"); + if( monitor->nonc1test0lngrep.inneriter>=0 ) + { + ae_trace("*** | * inner iter idx: %10d |\n", + (int)(monitor->nonc1test0lngrep.inneriter)); + } + if( monitor->nonc1test0lngrep.outeriter>=0 ) + { + ae_trace("*** | * outer iter idx: %10d |\n", + (int)(monitor->nonc1test0lngrep.outeriter)); + } + ae_trace("*** | |\n"); + ae_trace("*** | Printing out log of suspicious line search XK+Stp*D |\n"); + ae_trace("*** | Look for abrupt changes in slope. |\n"); + if( !needxdreport ) + { + ae_trace("*** | NOTE: XK and D are not printed by default. If you |\n"); + ae_trace("*** | need them, add trace tag OPTIMIZERS.X |\n"); + } + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | step along D | delta F | slope |\n"); + ae_trace("*** ------------------------------------------------------|\n"); + for(i=0; i<=monitor->nonc1test0lngrep.cnt-1; i++) + { + slope = monitor->nonc1test0lngrep.f.ptr.p_double[ae_minint(i+1, monitor->nonc1test0lngrep.cnt-1, _state)]-monitor->nonc1test0lngrep.f.ptr.p_double[i]; + slope = slope/(1.0e-15+monitor->nonc1test0lngrep.stp.ptr.p_double[ae_minint(i+1, monitor->nonc1test0lngrep.cnt-1, _state)]-monitor->nonc1test0lngrep.stp.ptr.p_double[i]); + ae_trace("*** | %13.5e | %13.5e | %11.3e |", + (double)(monitor->nonc1test0lngrep.stp.ptr.p_double[i]), + (double)(monitor->nonc1test0lngrep.f.ptr.p_double[i]-monitor->nonc1test0lngrep.f.ptr.p_double[0]), + (double)(slope)); + if( i>=monitor->nonc1test0lngrep.stpidxa&&i<=monitor->nonc1test0lngrep.stpidxb ) + { + ae_trace(" <---"); + } + ae_trace("\n"); + } + ae_trace("*** ------------------------------------------------------|\n"); + if( needxdreport ) + { + ae_trace("*** > printing raw variables\n"); + ae_trace("*** XK = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc1test0lngrep.x0, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc1test0lngrep.d, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** > printing scaled variables (values are divided by user-specified scales)\n"); + ae_trace("*** XK = "); + tracevectorautoprec(&monitor->nonc1test0lngrep.x0, 0, monitor->n, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorautoprec(&monitor->nonc1test0lngrep.d, 0, monitor->n, _state); + ae_trace("\n"); + } + } + if( monitor->rep.nonc1suspected&&monitor->rep.nonc1test1positive ) + { + ae_trace("> printing out nonsmoothness test #1 report:\n"); + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | Test #1 for nonsmoothness was triggered (this test |\n"); + ae_trace("*** | analyzes changes in gradient components). |\n"); + ae_trace("*** | |\n"); + ae_trace("*** | Function information: |\n"); + ae_trace("*** | * function index: %10d", + (int)(monitor->nonc1test1lngrep.fidx)); + if( monitor->nonc1test1lngrep.fidx==0 ) + { + ae_trace(" (target) |\n"); + } + else + { + ae_trace(" (constraint) |\n"); + } + ae_trace("*** | * variable index I: %10d |\n", + (int)(monitor->nonc1test1lngrep.vidx)); + ae_trace("*** | * dF/dX Lipschitz const: %10.2e |\n", + (double)(monitor->rep.nonc1lipschitzc)); + ae_trace("*** | |\n"); + ae_trace("*** | Iteration information: |\n"); + if( monitor->nonc1test1lngrep.inneriter>=0 ) + { + ae_trace("*** | * inner iter idx: %10d |\n", + (int)(monitor->nonc1test1lngrep.inneriter)); + } + if( monitor->nonc1test1lngrep.outeriter>=0 ) + { + ae_trace("*** | * outer iter idx: %10d |\n", + (int)(monitor->nonc1test1lngrep.outeriter)); + } + ae_trace("*** | |\n"); + ae_trace("*** | Printing out log of suspicious line search XK+Stp*D |\n"); + ae_trace("*** | Look for abrupt changes in slope. |\n"); + if( !needxdreport ) + { + ae_trace("*** | NOTE: XK and D are not printed by default. If you |\n"); + ae_trace("*** | need them, add trace tag OPTIMIZERS.X |\n"); + } + ae_trace("*** -------------------------------------------------------\n"); + ae_trace("*** | step along D | delta Gi | slope |\n"); + ae_trace("*** ------------------------------------------------------|\n"); + for(i=0; i<=monitor->nonc1test1lngrep.cnt-1; i++) + { + slope = monitor->nonc1test1lngrep.g.ptr.p_double[ae_minint(i+1, monitor->nonc1test1lngrep.cnt-1, _state)]-monitor->nonc1test1lngrep.g.ptr.p_double[i]; + slope = slope/(1.0e-15+monitor->nonc1test1lngrep.stp.ptr.p_double[ae_minint(i+1, monitor->nonc1test1lngrep.cnt-1, _state)]-monitor->nonc1test1lngrep.stp.ptr.p_double[i]); + ae_trace("*** | %13.5e | %13.5e | %11.3e |", + (double)(monitor->nonc1test1lngrep.stp.ptr.p_double[i]), + (double)(monitor->nonc1test1lngrep.g.ptr.p_double[i]-monitor->nonc1test1lngrep.g.ptr.p_double[0]), + (double)(slope)); + if( i>=monitor->nonc1test1lngrep.stpidxa&&i<=monitor->nonc1test1lngrep.stpidxb ) + { + ae_trace(" <---"); + } + ae_trace("\n"); + } + ae_trace("*** ------------------------------------------------------|\n"); + if( needxdreport ) + { + ae_trace("*** > printing raw variables\n"); + ae_trace("*** XK = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc1test1lngrep.x0, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorunscaledunshiftedautoprec(&monitor->nonc1test1lngrep.d, monitor->n, &monitor->s, ae_true, &monitor->s, ae_false, _state); + ae_trace("\n"); + ae_trace("*** > printing scaled variables (values are divided by user-specified scales)\n"); + ae_trace("*** XK = "); + tracevectorautoprec(&monitor->nonc1test1lngrep.x0, 0, monitor->n, _state); + ae_trace("\n"); + ae_trace("*** D = "); + tracevectorautoprec(&monitor->nonc1test1lngrep.d, 0, monitor->n, _state); + ae_trace("\n"); + } + } +} + + +/************************************************************************* +This subroutine exports report to user-readable representation (all arrays +are forced to have exactly same size as needed; unused arrays are set to +zero length). + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +void smoothnessmonitorexportreport(smoothnessmonitor* monitor, + optguardreport* rep, + ae_state *_state) +{ + + + + /* + * Finalize last line search, just to be sure + */ + if( monitor->enqueuedcnt>0 ) + { + smoothnessmonitorfinalizelinesearch(monitor, _state); + } + + /* + * Export report + */ + optguardexportreport(&monitor->rep, monitor->n, monitor->k, monitor->badgradhasxj, rep, _state); +} + + +/************************************************************************* +Check numerical gradient at point X0 (unscaled variables!), with optional +box constraints [BndL,BndU] (if HasBoxConstraints=True) and with scale +vector S[]. + +Step S[i]*TestStep is performed along I-th variable. + +NeedFiJ rcomm protocol is used to request derivative information. + +Box constraints BndL/BndU are expected to be feasible. It is possible to +have BndL=BndU. + + -- ALGLIB -- + Copyright 06.12.2018 by Bochkanov Sergey +*************************************************************************/ +ae_bool smoothnessmonitorcheckgradientatx0(smoothnessmonitor* monitor, + /* Real */ const ae_vector* unscaledx0, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_bool hasboxconstraints, + double teststep, + ae_state *_state) +{ + ae_int_t n; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t varidx; + double v; + double vp; + double vm; + double vc; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( monitor->rstateg0.stage>=0 ) + { + n = monitor->rstateg0.ia.ptr.p_int[0]; + k = monitor->rstateg0.ia.ptr.p_int[1]; + i = monitor->rstateg0.ia.ptr.p_int[2]; + j = monitor->rstateg0.ia.ptr.p_int[3]; + varidx = monitor->rstateg0.ia.ptr.p_int[4]; + v = monitor->rstateg0.ra.ptr.p_double[0]; + vp = monitor->rstateg0.ra.ptr.p_double[1]; + vm = monitor->rstateg0.ra.ptr.p_double[2]; + vc = monitor->rstateg0.ra.ptr.p_double[3]; + } + else + { + n = 205; + k = -838; + i = 939; + j = -526; + varidx = 763; + v = -541.0; + vp = -698.0; + vm = -900.0; + vc = -318.0; + } + if( monitor->rstateg0.stage==0 ) + { + goto lbl_0; + } + if( monitor->rstateg0.stage==1 ) + { + goto lbl_1; + } + if( monitor->rstateg0.stage==2 ) + { + goto lbl_2; + } + if( monitor->rstateg0.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + n = monitor->n; + k = monitor->k; + monitor->needfij = ae_false; + + /* + * Quick exit + */ + if( ((n<=0||k<=0)||!ae_isfinite(teststep, _state))||ae_fp_eq(teststep,(double)(0)) ) + { + result = ae_false; + return result; + } + teststep = ae_fabs(teststep, _state); + + /* + * Allocate storage + */ + rvectorsetlengthatleast(&monitor->x, n, _state); + rvectorsetlengthatleast(&monitor->fi, k, _state); + rmatrixsetlengthatleast(&monitor->j, k, n, _state); + rvectorsetlengthatleast(&monitor->xbase, n, _state); + rvectorsetlengthatleast(&monitor->fbase, k, _state); + rvectorsetlengthatleast(&monitor->fm, k, _state); + rvectorsetlengthatleast(&monitor->fc, k, _state); + rvectorsetlengthatleast(&monitor->fp, k, _state); + rvectorsetlengthatleast(&monitor->jm, k, _state); + rvectorsetlengthatleast(&monitor->jc, k, _state); + rvectorsetlengthatleast(&monitor->jp, k, _state); + rmatrixsetlengthatleast(&monitor->jbaseusr, k, n, _state); + rmatrixsetlengthatleast(&monitor->jbasenum, k, n, _state); + rvectorsetlengthatleast(&monitor->rep.badgradxbase, n, _state); + rmatrixsetlengthatleast(&monitor->rep.badgraduser, k, n, _state); + rmatrixsetlengthatleast(&monitor->rep.badgradnum, k, n, _state); + + /* + * Set XBase/Jacobian presence flag + */ + monitor->badgradhasxj = ae_true; + + /* + * Determine reference point, compute function vector and user-supplied Jacobian + */ + for(i=0; i<=n-1; i++) + { + v = unscaledx0->ptr.p_double[i]; + if( (hasboxconstraints&&ae_isfinite(bndl->ptr.p_double[i], _state))&&ae_fp_less(v,bndl->ptr.p_double[i]) ) + { + v = bndl->ptr.p_double[i]; + } + if( (hasboxconstraints&&ae_isfinite(bndu->ptr.p_double[i], _state))&&ae_fp_greater(v,bndu->ptr.p_double[i]) ) + { + v = bndu->ptr.p_double[i]; + } + monitor->xbase.ptr.p_double[i] = v; + monitor->rep.badgradxbase.ptr.p_double[i] = v; + monitor->x.ptr.p_double[i] = v; + } + monitor->needfij = ae_true; + monitor->rstateg0.stage = 0; + goto lbl_rcomm; +lbl_0: + monitor->needfij = ae_false; + for(i=0; i<=k-1; i++) + { + monitor->fbase.ptr.p_double[i] = monitor->fi.ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + monitor->jbaseusr.ptr.pp_double[i][j] = monitor->j.ptr.pp_double[i][j]; + monitor->rep.badgraduser.ptr.pp_double[i][j] = monitor->j.ptr.pp_double[i][j]; + } + } + + /* + * Check Jacobian column by column + */ + varidx = 0; +lbl_4: + if( varidx>n-1 ) + { + goto lbl_6; + } + + /* + * Determine test location. + */ + v = monitor->xbase.ptr.p_double[varidx]; + vm = v-s->ptr.p_double[varidx]*teststep; + vp = v+s->ptr.p_double[varidx]*teststep; + if( (hasboxconstraints&&ae_isfinite(bndl->ptr.p_double[varidx], _state))&&ae_fp_less(vm,bndl->ptr.p_double[varidx]) ) + { + vm = bndl->ptr.p_double[varidx]; + } + if( (hasboxconstraints&&ae_isfinite(bndu->ptr.p_double[varidx], _state))&&ae_fp_greater(vp,bndu->ptr.p_double[varidx]) ) + { + vp = bndu->ptr.p_double[varidx]; + } + vc = vm+(vp-vm)/(double)2; + + /* + * Quickly skip fixed variables + */ + if( (ae_fp_eq(vm,vp)||ae_fp_eq(vc,vm))||ae_fp_eq(vc,vp) ) + { + for(i=0; i<=k-1; i++) + { + monitor->rep.badgradnum.ptr.pp_double[i][varidx] = (double)(0); + } + goto lbl_5; + } + + /* + * Compute F/J at three trial points + */ + for(i=0; i<=n-1; i++) + { + monitor->x.ptr.p_double[i] = monitor->xbase.ptr.p_double[i]; + } + monitor->x.ptr.p_double[varidx] = vm; + monitor->needfij = ae_true; + monitor->rstateg0.stage = 1; + goto lbl_rcomm; +lbl_1: + monitor->needfij = ae_false; + for(i=0; i<=k-1; i++) + { + monitor->fm.ptr.p_double[i] = monitor->fi.ptr.p_double[i]; + monitor->jm.ptr.p_double[i] = monitor->j.ptr.pp_double[i][varidx]; + } + for(i=0; i<=n-1; i++) + { + monitor->x.ptr.p_double[i] = monitor->xbase.ptr.p_double[i]; + } + monitor->x.ptr.p_double[varidx] = vc; + monitor->needfij = ae_true; + monitor->rstateg0.stage = 2; + goto lbl_rcomm; +lbl_2: + monitor->needfij = ae_false; + for(i=0; i<=k-1; i++) + { + monitor->fc.ptr.p_double[i] = monitor->fi.ptr.p_double[i]; + monitor->jc.ptr.p_double[i] = monitor->j.ptr.pp_double[i][varidx]; + } + for(i=0; i<=n-1; i++) + { + monitor->x.ptr.p_double[i] = monitor->xbase.ptr.p_double[i]; + } + monitor->x.ptr.p_double[varidx] = vp; + monitor->needfij = ae_true; + monitor->rstateg0.stage = 3; + goto lbl_rcomm; +lbl_3: + monitor->needfij = ae_false; + for(i=0; i<=k-1; i++) + { + monitor->fp.ptr.p_double[i] = monitor->fi.ptr.p_double[i]; + monitor->jp.ptr.p_double[i] = monitor->j.ptr.pp_double[i][varidx]; + } + + /* + * Check derivative + */ + for(i=0; i<=k-1; i++) + { + monitor->rep.badgradnum.ptr.pp_double[i][varidx] = (monitor->fp.ptr.p_double[i]-monitor->fm.ptr.p_double[i])/(vp-vm); + if( !derivativecheck(monitor->fm.ptr.p_double[i], monitor->jm.ptr.p_double[i]*s->ptr.p_double[varidx], monitor->fp.ptr.p_double[i], monitor->jp.ptr.p_double[i]*s->ptr.p_double[varidx], monitor->fc.ptr.p_double[i], monitor->jc.ptr.p_double[i]*s->ptr.p_double[varidx], (vp-vm)/s->ptr.p_double[varidx], _state) ) + { + monitor->rep.badgradsuspected = ae_true; + monitor->rep.badgradfidx = i; + monitor->rep.badgradvidx = varidx; + } + } +lbl_5: + varidx = varidx+1; + goto lbl_4; +lbl_6: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + monitor->rstateg0.ia.ptr.p_int[0] = n; + monitor->rstateg0.ia.ptr.p_int[1] = k; + monitor->rstateg0.ia.ptr.p_int[2] = i; + monitor->rstateg0.ia.ptr.p_int[3] = j; + monitor->rstateg0.ia.ptr.p_int[4] = varidx; + monitor->rstateg0.ra.ptr.p_double[0] = v; + monitor->rstateg0.ra.ptr.p_double[1] = vp; + monitor->rstateg0.ra.ptr.p_double[2] = vm; + monitor->rstateg0.ra.ptr.p_double[3] = vc; + return result; +} + + +/************************************************************************* +This function initializes approximation of a Hessian. + +Direct BFGS (Hessian matrix H is stored) with stability improvements is used. + +INPUT PARAMETERS: + Hess - Hessian structure, initial state is ignored, but + previously allocated memory is reused as much as + possible + N - dimensions count + ResetFreq - reset frequency for BFGS : + * ResetFreq=0 for standard BFGS + * ResetFreq>0 for BFGS with periodic resets (helps + to maintain fresh curvature information, works + better for highly nonquadratic problems) + StpShort - short step length (INF-norm); steps shorter than that + are not used for Hessian updates + + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessianinitbfgs(xbfgshessian* hess, + ae_int_t n, + ae_int_t resetfreq, + double stpshort, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(resetfreq>=0, "HessianInit: ResetFreq<0", _state); + resetfreq = ae_minint(resetfreq, n, _state); + hess->htype = 0; + hess->n = n; + hess->resetfreq = resetfreq; + hess->stpshort = stpshort; + hess->hage = 0; + hess->gammasml = 0.000001; + hess->reg = (double)100*ae_sqrt(ae_machineepsilon, _state); + hess->smallreg = 0.01*ae_sqrt(ae_machineepsilon, _state); + hess->microreg = ((double)1000+ae_sqrt((double)(n), _state))*ae_machineepsilon; + hess->wolfeeps = 0.001; + hess->maxhess = 1.0E8; + hess->sumsy = ae_sqr(ae_machineepsilon, _state); + hess->sumy2 = hess->sumsy*hess->gammasml; + hess->sums2 = (double)(0); + hess->updatestatus = 0; + rvectorsetlengthatleast(&hess->sk, n, _state); + rvectorsetlengthatleast(&hess->yk, n, _state); + rsetallocm(n, n, 0.0, &hess->hcurrent, _state); + rsetallocm(n, n, 0.0, &hess->hincoming, _state); + for(i=0; i<=n-1; i++) + { + hess->hcurrent.ptr.pp_double[i][i] = (double)(1); + hess->hincoming.ptr.pp_double[i][i] = (double)(1); + } +} + + +/************************************************************************* +This function initializes approximation of a Hessian. + +Explicit low-rank representation of LBFGS is used. + +INPUT PARAMETERS: + Hess - Hessian structure, initial state is ignored, but + previously allocated memory is reused as much as + possible + N - dimensions count, N>0 + M - memory size, M>=0 (values above N will be reduced + to N) + StpShort - short step length (INF-norm); steps shorter than that + are not used for Hessian updates + MaxHess - maximum Hessian curvature; steps producing curvature + larger than that are rejected + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessianinitlowrank(xbfgshessian* hess, + ae_int_t n, + ae_int_t m, + double stpshort, + double maxhess, + ae_state *_state) +{ + + + ae_assert(n>0, "HessianInitLowRank: N<=0", _state); + ae_assert(m>=0, "HessianInitLowRank: M<0", _state); + m = ae_minint(m, n, _state); + + /* + * Initialize generic fields + */ + hess->htype = 3; + hess->n = n; + + /* + * Initialize mode-specific fields + */ + hess->m = m; + hess->memlen = 0; + hess->sigma = (double)(1); + if( m>0 ) + { + rallocm(m, n, &hess->s, _state); + rallocm(m, n, &hess->y, _state); + rallocm(m, m, &hess->lowranksst, _state); + rallocm(m, m, &hess->lowranksyt, _state); + } + optserv_resetlowrankmodel(hess, _state); + + /* + * Other fields + */ + hess->resetfreq = 0; + hess->stpshort = stpshort; + hess->hage = 0; + hess->gammasml = 0.000001; + hess->reg = (double)100*ae_sqrt(ae_machineepsilon, _state); + hess->smallreg = 0.01*ae_sqrt(ae_machineepsilon, _state); + hess->microreg = ((double)1000+ae_sqrt((double)(n), _state))*ae_machineepsilon; + hess->sumsy = ae_sqr(ae_machineepsilon, _state); + hess->sumy2 = hess->sumsy*hess->gammasml; + hess->sums2 = ae_sqr(ae_machineepsilon, _state); + hess->wolfeeps = 0.001; + hess->maxhess = maxhess; + hess->updatestatus = 0; + rallocv(n, &hess->sk, _state); + rallocv(n, &hess->yk, _state); +} + + +/************************************************************************* +This function initializes approximation of a Hessian as a limited memory +SR1 model. + +INPUT PARAMETERS: + Hess - Hessian structure, initial state is ignored, but + previously allocated memory is reused as much as + possible + N - dimensions count, N>0 + M - memory size, M>=0 (values above N will be reduced + to N) + StpShort - short step length (INF-norm); steps shorter than that + are not used for Hessian updates + MaxHess - maximum Hessian curvature; steps producing curvature + larger than that are rejected + + -- ALGLIB -- + Copyright 08.02.2024 by Bochkanov Sergey +*************************************************************************/ +void hessianinitlowranksr1(xbfgshessian* hess, + ae_int_t n, + ae_int_t m, + double stpshort, + double maxhess, + ae_state *_state) +{ + + + ae_assert(n>0, "HessianInitLowRankSR1: N<=0", _state); + ae_assert(m>=0, "HessianInitLowRankSR1: M<0", _state); + m = ae_minint(m, n, _state); + + /* + * Initialize generic fields + */ + hess->htype = 4; + hess->n = n; + + /* + * Initialize mode-specific fields + */ + hess->m = m; + hess->memlen = 0; + rsetallocv(n, 1.0, &hess->varscale, _state); + rsetallocv(n, 1.0, &hess->invscale, _state); + if( m>0 ) + { + rallocm(m, n, &hess->s, _state); + rallocm(m, n, &hess->y, _state); + rallocm(m, n, &hess->corr2, _state); + } + optserv_resetlowrankmodel(hess, _state); + + /* + * Other fields + */ + hess->stpshort = stpshort; + hess->hage = 0; + hess->maxhess = maxhess; + hess->updatestatus = 0; + hess->mincostheta = (double)500*ae_sqrt(ae_machineepsilon, _state); + hess->mincrv = (double)10*ae_sqrt(ae_machineepsilon, _state); + rallocv(n, &hess->sk, _state); + rallocv(n, &hess->yk, _state); + rallocv(n, &hess->rk, _state); +} + + +/************************************************************************* +This function changes upper limit on Hessian norm. It will take effect +upon the next model recomputation. + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void hessiansetmaxhess(xbfgshessian* hess, + double maxhess, + ae_state *_state) +{ + + + hess->maxhess = maxhess; +} + + +/************************************************************************* +This function changes variable scales. The model is invalidated. + +Variable scales must be strictly positive. Variable scales are ignored by +models other than SR1. + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void hessiansetscales(xbfgshessian* hess, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianSetScales: Hessian mode not supported", _state); + if( hess->htype!=4 ) + { + return; + } + n = hess->n; + for(i=0; i<=n-1; i++) + { + if( s->ptr.p_double[i]<=0.0 ) + { + ae_assert(ae_false, "HessianSetScales: non-positive scales were supplied", _state); + } + } + rcopyv(n, s, &hess->varscale, _state); + rsetv(n, 1.0, &hess->invscale, _state); + rmergedivv(n, s, &hess->invscale, _state); + optserv_resetlowrankmodel(hess, _state); +} + + +/************************************************************************* +This function changes variable scales, trying to move them closer to user- +supplied ones, but staying within [0.5,2.0] of the former ones in order +to avoid sharp changes in the Hessian curvature. Specific interval may +change in future versions without notice. + +This function invalidates the model. + +Variable scales must be strictly positive. Variable scales are ignored by +models other than SR1. + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void hessiansetscalesinertial(xbfgshessian* hess, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double s0; + double s1; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianSetScales: Hessian mode not supported", _state); + if( hess->htype!=4 ) + { + return; + } + n = hess->n; + for(i=0; i<=n-1; i++) + { + s0 = hess->varscale.ptr.p_double[i]; + s1 = s->ptr.p_double[i]; + if( s1<=0.0 ) + { + ae_assert(ae_false, "HessianSetScales: non-positive scales were supplied", _state); + } + if( s1<0.5*s0 ) + { + s1 = 0.5*s0; + } + if( s1>2.0*s0 ) + { + s1 = 2.0*s0; + } + hess->varscale.ptr.p_double[i] = s1; + hess->invscale.ptr.p_double[i] = (double)1/s1; + } + optserv_resetlowrankmodel(hess, _state); +} + + +/************************************************************************* +Updates Hessian estimate, uses regularized formula which prevents Hessian +eigenvalues from decreasing below ~sqrt(Eps) and rejects updates larger +than ~1/sqrt(Eps) in magnitude. + +Either BFGS or LBFGS formula is used, depending on Hessian model settings. +Exception is generated if called for SR1. + +INPUT PARAMETERS: + Hess - Hessian state + X0, G0 - point #0 and gradient at #0, array[N] + X1, G1 - point #1 and gradient at #1, array[N] + DoTrace - True if we want to print trace messages + +On return sets Hess.UpdateStatus flag + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessianupdate(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_bool dotrace, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double gamma; + double sy; + double snrm2; + double ynrm2; + double ski; + double yki; + double yk2; + double skyk; + double skg0; + double skg1; + double wolfedecay; + + + n = hess->n; + + /* + * Prepare Sk, Yk + */ + sy = (double)(0); + snrm2 = (double)(0); + ynrm2 = (double)(0); + skg0 = (double)(0); + skg1 = (double)(0); + for(i=0; i<=n-1; i++) + { + ski = x1->ptr.p_double[i]-x0->ptr.p_double[i]; + yki = g1->ptr.p_double[i]-g0->ptr.p_double[i]; + hess->sk.ptr.p_double[i] = ski; + hess->yk.ptr.p_double[i] = yki; + sy = sy+ski*yki; + snrm2 = snrm2+ski*ski; + ynrm2 = ynrm2+yki*yki; + skg0 = skg0+ski*g0->ptr.p_double[i]; + skg1 = skg1+ski*g1->ptr.p_double[i]; + } + hess->updatestatus = 0; + + /* + * Update current and incoming Hessians + */ + ae_assert(hess->htype==0||hess->htype==3, "HessianUpdate: Hessian mode not supported", _state); + if( hess->htype==0 ) + { + + /* + * Update dense Hessian using BFGS formula for Bk + */ + optserv_hessianupdatelowlevel(hess, &hess->hcurrent, &hess->sk, &hess->yk, &hess->updatestatus, _state); + optserv_hessianupdatelowlevel(hess, &hess->hincoming, &hess->sk, &hess->yk, &i, _state); + if( ae_fp_greater(sy,(double)(0)) ) + { + hess->sumsy = hess->sumsy+sy; + hess->sumy2 = hess->sumy2+ynrm2; + } + hess->sums2 = hess->sums2+snrm2; + hess->hage = hess->hage+1; + + /* + * Perform Hessian reset if needed + */ + if( hess->resetfreq>0&&hess->hage>=hess->resetfreq ) + { + rmatrixcopy(n, n, &hess->hincoming, 0, 0, &hess->hcurrent, 0, 0, _state); + gamma = hess->sumy2/(hess->sumsy+hess->reg*hess->sumy2+hess->smallreg*hess->sums2); + rsetm(n, n, 0.0, &hess->hincoming, _state); + for(i=0; i<=n-1; i++) + { + hess->hincoming.ptr.pp_double[i][i] = gamma; + } + hess->sumsy = ae_sqr(ae_machineepsilon, _state); + hess->sumy2 = hess->sumsy*hess->gammasml; + hess->sums2 = (double)(0); + hess->hage = 0; + hess->updatestatus = 3; + } + return; + } + if( hess->htype==3 ) + { + if( dotrace ) + { + ae_trace("> analyzing Hessian update:\n>> (Sk,G0)=%0.15e (Sk,G1)=%0.15e (Yk,Yk)/(Sk.Yk)=%0.15e\n", + (double)(skg0), + (double)(skg1), + (double)(ynrm2/sy)); + } + + /* + * Decide whether update is good enough to be remembered + */ + if( hess->m==0 ) + { + + /* + * Zero memory was specified, update ignored + */ + if( dotrace ) + { + ae_trace(">> zero memory length, update rejected\n"); + } + return; + } + if( ae_fp_less_eq(rmaxabsv(n, &hess->sk, _state),hess->stpshort) ) + { + + /* + * Sk is too small, skip update + */ + if( dotrace ) + { + ae_trace(">> step is too short, update rejected\n"); + } + return; + } + + /* + * Reject bad steps + */ + if( ae_fp_eq(rdotv2(n, &hess->yk, _state),(double)(0)) ) + { + + /* + * The function is linear in the step direction, no update applied + */ + optserv_popfrontxy(hess, _state); + hess->sigma = ae_maxreal(0.1*hess->sigma, 1.0E-4, _state); + optserv_resetlowrankmodel(hess, _state); + if( dotrace ) + { + ae_trace(">> zero Yk (linear function?), update rejected, queue size decreased by 1, diagonal scaling sigma=%0.2e (decreased)\n", + (double)(hess->sigma)); + } + return; + } + wolfedecay = (double)1-hess->wolfeeps*ae_minreal(ae_sqrt(snrm2, _state), 1.0, _state); + if( !((ae_fp_less(skg0,(double)(0))&&ae_fp_greater(skg1,wolfedecay*skg0))||(ae_fp_greater(skg1,(double)(0))&&ae_fp_less(skg0,wolfedecay*skg1))) ) + { + + /* + * Wolfe decay condition does not hold + */ + optserv_popfrontxy(hess, _state); + hess->sigma = ae_maxreal(0.1*hess->sigma, 1.0E-4, _state); + optserv_resetlowrankmodel(hess, _state); + if( dotrace ) + { + ae_trace(">> Wolfe decay condition does not hold, update rejected, queue size decreased by 1, diagonal scaling sigma=%0.2e (decreased)\n", + (double)(hess->sigma)); + } + return; + } + if( ae_fp_greater(sy,(double)(0))&&ae_fp_greater(ynrm2/sy,hess->maxhess) ) + { + + /* + * Hessian norm is too high + */ + optserv_popfrontxy(hess, _state); + hess->sigma = ae_maxreal(0.1*hess->sigma, 1.0E-4, _state); + optserv_resetlowrankmodel(hess, _state); + if( dotrace ) + { + ae_trace(">> Hessian norm is too high (%0.2e), update rejected, queue size decreased by 1, diagonal scaling sigma=%0.2e (decreased)\n", + (double)(ynrm2/sy), + (double)(hess->sigma)); + } + return; + } + + /* + * Update historical averages + */ + hess->sumsy = hess->sumsy+sy; + hess->sumy2 = hess->sumy2+ynrm2; + hess->sums2 = hess->sums2+snrm2; + + /* + * Apply regularization: + * * first, add REG*Sk to Yk in order to make model at least slightly convex (Sigma is at least REG + * * second, add REG*Yk to Xk in order to limit model curvature (Sigma is at most 1/REG) + * + * Whilst specific order of these operations is not very important, we prefer to Yk+=REG*Sk be first + * due to Sk being better guarded away from zero. + */ + raddv(n, hess->reg, &hess->sk, &hess->yk, _state); + raddv(n, hess->reg, &hess->yk, &hess->sk, _state); + + /* + * Update low rank Hessian data + */ + ae_assert(hess->memlen<=hess->m, "HessianUpdate: integrity check 5763 failed", _state); + if( hess->memlen==hess->m ) + { + optserv_popfrontxy(hess, _state); + } + + /* + * Append to S and Y + */ + ae_assert(hess->memlenm, "HessianUpdate: integrity check 5764 failed", _state); + hess->memlen = hess->memlen+1; + rcopyvr(n, &hess->sk, &hess->s, hess->memlen-1, _state); + rcopyvr(n, &hess->yk, &hess->y, hess->memlen-1, _state); + + /* + * Append row/col to LowRankSST and LowRankSYT + */ + rallocv(hess->memlen, &hess->buf, _state); + rgemv(hess->memlen, n, 1.0, &hess->s, 0, &hess->sk, 0.0, &hess->buf, _state); + rcopyvr(hess->memlen, &hess->buf, &hess->lowranksst, hess->memlen-1, _state); + rcopyvc(hess->memlen, &hess->buf, &hess->lowranksst, hess->memlen-1, _state); + rgemv(hess->memlen, n, 1.0, &hess->y, 0, &hess->sk, 0.0, &hess->buf, _state); + rcopyvr(hess->memlen, &hess->buf, &hess->lowranksyt, hess->memlen-1, _state); + rgemv(hess->memlen, n, 1.0, &hess->s, 0, &hess->yk, 0.0, &hess->buf, _state); + rcopyvc(hess->memlen, &hess->buf, &hess->lowranksyt, hess->memlen-1, _state); + + /* + * Recompute scaling + */ + yk2 = rdotv2(n, &hess->yk, _state); + skyk = rdotv(n, &hess->sk, &hess->yk, _state); + hess->sigma = boundval(yk2/skyk, 0.1*hess->sigma, (double)10*hess->sigma, _state); + hess->sigma = ae_minreal(hess->sigma, (double)1/(hess->reg+ae_machineepsilon), _state); + if( dotrace ) + { + ae_trace(">> diagonal scaling sigma=%0.2e\n", + (double)(hess->sigma)); + } + + /* + * Invalidate model + */ + optserv_resetlowrankmodel(hess, _state); + } +} + + +/************************************************************************* +Updates Hessian estimate, uses damped formula which prevents Hessian +eigenvalues from decreasing below ~sqrt(Eps) and rejects updates larger +than ~1/sqrt(Eps) in magnitude. + +Either BFGS, LBFGS or SR1 formula is used, depending on Hessian model +settings. For SR1 models it simply forwards call to HessianUpdateSR1(). + +INPUT PARAMETERS: + Hess - Hessian state + X0, G0 - point #0 and gradient at #0, array[N] + X1, G1 - point #1 and gradient at #1, array[N] + Strategy - update stabilization strategy: + * 0 do nothing + * 1 apply damped (L)BFGS, safeguarding from + rapid curvature increase and decrease + * 2 apply damped (L)BFGS for too high curvature, + ignore Y and decrease curvature conservatively + for low values of S'Y + Ignored by SR1 update. + TryReplaceLast - whether we append update or try to replace the last + one in a queue: + * if False, update is applied as usual + * if True, then: + * if we have BFGS Hessian - applied as usual + * if we have L-BFGS Hessian, we pop the last one + in a memory (if have any), then add this update + DoTrace - True if we want to print trace messages + TraceLevel - amount of ">" symbols to append to trace messages + + + -- ALGLIB -- + Copyright 28.09.2023 by Bochkanov Sergey +*************************************************************************/ +void hessianupdatev2(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_int_t strategy, + ae_bool tryreplacelast, + ae_bool dotrace, + ae_int_t tracelevel, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double gamma; + double sy; + double snrm2; + double ynrm2; + double ski; + double yki; + double skg0; + double skg1; + double shs; + double tau; + double phi; + double eps2; + double eps3; + double v; + + + if( hess->htype==4 ) + { + hessianupdatesr1(hess, x0, g0, x1, g1, dotrace, tracelevel, _state); + return; + } + n = hess->n; + eps2 = (double)10*ae_sqrt(ae_machineepsilon, _state); + eps3 = (double)10*ae_machineepsilon*((double)1+ae_sqrt((double)(n), _state)); + + /* + * Print initial trace line + */ + if( dotrace ) + { + traceangles(tracelevel, _state); + ae_trace(" analyzing Hessian update\n"); + } + + /* + * Prepare Sk, Yk, compute some necessary quantities + */ + sy = (double)(0); + snrm2 = (double)(0); + ynrm2 = (double)(0); + skg0 = (double)(0); + skg1 = (double)(0); + for(i=0; i<=n-1; i++) + { + ski = x1->ptr.p_double[i]-x0->ptr.p_double[i]; + yki = g1->ptr.p_double[i]-g0->ptr.p_double[i]; + hess->sk.ptr.p_double[i] = ski; + hess->yk.ptr.p_double[i] = yki; + sy = sy+ski*yki; + snrm2 = snrm2+ski*ski; + ynrm2 = ynrm2+yki*yki; + skg0 = skg0+ski*g0->ptr.p_double[i]; + skg1 = skg1+ski*g1->ptr.p_double[i]; + } + hess->updatestatus = 0; + + /* + * Skip updates with zero or short steps + */ + if( ae_fp_less_eq(rmaxabsv(n, &hess->sk, _state),hess->stpshort) ) + { + + /* + * Sk is too small, skip update + */ + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" step is too short, update rejected\n"); + } + return; + } + + /* + * Analyze existing curvature along S + */ + hessianmv(hess, &hess->sk, &hess->hsk, _state); + shs = rdotv(n, &hess->sk, &hess->hsk, _state); + if( ae_fp_greater(shs,eps3*snrm2) ) + { + + /* + * Hessian has sufficiently good curvature along Sk, can proceed with analysis of update. + * Apply damping or other stabilization + */ + ae_assert((strategy==0||strategy==1)||strategy==2, "OPTSERV: integrity check 9223 failed", _state); + phi = 1.0; + tau = sy/shs; + if( strategy==1&&ae_fp_less(tau,optserv_xbfgssigma2) ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" applying damping to correct too low (or rapidly changing) curvature\n"); + } + phi = ((double)1-optserv_xbfgssigma2)/((double)1-tau); + } + if( strategy==2&&ae_fp_less(tau,optserv_xbfgssigma2) ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" applying conservative curvature decrease to correct too low (or rapidly changing) curvature\n"); + } + rcopyv(n, &hess->hsk, &hess->yk, _state); + rmulv(n, optserv_xbfgssigma2, &hess->yk, _state); + sy = optserv_xbfgssigma2*shs; + ynrm2 = rdotv2(n, &hess->yk, _state); + } + if( (strategy==1||strategy==2)&&ae_fp_greater(tau,optserv_xbfgssigma3) ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" applying damping to correct too high (or rapidly changing) curvature\n"); + } + phi = (optserv_xbfgssigma3-(double)1)/(tau-(double)1); + } + if( ae_fp_neq(phi,(double)(1)) ) + { + rmulv(n, phi, &hess->yk, _state); + raddv(n, (double)1-phi, &hess->hsk, &hess->yk, _state); + sy = rdotv(n, &hess->sk, &hess->yk, _state); + ynrm2 = rdotv2(n, &hess->yk, _state); + } + } + else + { + + /* + * Hessian is not sufficiently good along Sk, propose conservative curvature-preserving update + */ + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" Hessian curvature along Sk is too low, proposing conservative corrector update\n"); + } + rcopymulv(n, eps2, &hess->sk, &hess->yk, _state); + sy = rdotv(n, &hess->sk, &hess->yk, _state); + ynrm2 = rdotv2(n, &hess->yk, _state); + } + + /* + * Do not allow a lower bound on Hessian eigenvalues (S'Y)/(S'S) to decrease below Eps2, + * do not allow an upper bound on Hessian eigenvalues (Y'Y)/(S'Y) to increase above 1/Eps2 + */ + if( ae_fp_less_eq(sy,(double)(0))||ae_fp_less(sy/snrm2,eps2) ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" damped curvature is still too low (lower estimate is SY/SS=%0.2e), truncating to ~sqrt(epsilon)\n", + (double)(sy/snrm2)); + } + rcopymulv(n, eps2, &hess->sk, &hess->yk, _state); + sy = rdotv(n, &hess->sk, &hess->yk, _state); + ynrm2 = rdotv2(n, &hess->yk, _state); + } + if( ae_fp_greater(sy,(double)(0))&&ae_fp_greater(ynrm2/sy,(double)1/eps2) ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" damped curvature is still too high (upper estimate is YY/SY=%0.2e), truncating to ~1/sqrt(epsilon)\n", + (double)(ynrm2/sy)); + } + v = (double)1/eps2/(ynrm2/sy); + rmulv(n, v, &hess->yk, _state); + sy = v*sy; + ynrm2 = v*v*ynrm2; + } + + /* + * Update current and incoming Hessians + */ + ae_assert(hess->htype==0||hess->htype==3, "HessianUpdate: Hessian mode not supported", _state); + if( hess->htype==0 ) + { + + /* + * Update dense Hessian using BFGS formula for Bk + */ + optserv_hessianupdatelowlevel2(hess, &hess->hcurrent, &hess->sk, &hess->yk, &hess->updatestatus, _state); + optserv_hessianupdatelowlevel2(hess, &hess->hincoming, &hess->sk, &hess->yk, &i, _state); + if( ae_fp_greater(sy,(double)(0)) ) + { + hess->sumsy = hess->sumsy+sy; + hess->sumy2 = hess->sumy2+ynrm2; + } + hess->sums2 = hess->sums2+snrm2; + hess->hage = hess->hage+1; + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" BFGS update applied\n"); + } + + /* + * Perform Hessian reset if needed + */ + if( hess->resetfreq>0&&hess->hage>=hess->resetfreq ) + { + rmatrixcopy(n, n, &hess->hincoming, 0, 0, &hess->hcurrent, 0, 0, _state); + gamma = hess->sumy2/(hess->sumsy+hess->reg*hess->sumy2+hess->smallreg*hess->sums2); + rsetm(n, n, 0.0, &hess->hincoming, _state); + for(i=0; i<=n-1; i++) + { + hess->hincoming.ptr.pp_double[i][i] = gamma; + } + hess->sumsy = ae_sqr(ae_machineepsilon, _state); + hess->sumy2 = hess->sumsy*hess->gammasml; + hess->sums2 = (double)(0); + hess->hage = 0; + hess->updatestatus = 3; + } + return; + } + if( hess->htype==3 ) + { + + /* + * Decide whether update is good enough to be remembered + */ + if( hess->m==0 ) + { + + /* + * Zero memory was specified, update ignored + */ + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" zero memory length, update rejected\n"); + } + return; + } + + /* + * Update historical averages + */ + hess->sumsy = hess->sumsy+sy; + hess->sumy2 = hess->sumy2+ynrm2; + hess->sums2 = hess->sums2+snrm2; + + /* + * Remove items from memory, if necessary + */ + ae_assert(hess->memlen<=hess->m, "HessianUpdate: integrity check 5763 failed", _state); + if( tryreplacelast ) + { + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" rewriting most recent update pair\n"); + } + hessianpoplatestifpossible(hess, _state); + } + if( hess->memlen==hess->m ) + { + optserv_popfrontxy(hess, _state); + } + + /* + * Append to S and Y + */ + ae_assert(hess->memlenm, "HessianUpdate: integrity check 5764 failed", _state); + hess->memlen = hess->memlen+1; + rcopyvr(n, &hess->sk, &hess->s, hess->memlen-1, _state); + rcopyvr(n, &hess->yk, &hess->y, hess->memlen-1, _state); + + /* + * Append row/col to LowRankSST and LowRankSYT + */ + rallocv(hess->memlen, &hess->buf, _state); + rgemv(hess->memlen, n, 1.0, &hess->s, 0, &hess->sk, 0.0, &hess->buf, _state); + rcopyvr(hess->memlen, &hess->buf, &hess->lowranksst, hess->memlen-1, _state); + rcopyvc(hess->memlen, &hess->buf, &hess->lowranksst, hess->memlen-1, _state); + rgemv(hess->memlen, n, 1.0, &hess->y, 0, &hess->sk, 0.0, &hess->buf, _state); + rcopyvr(hess->memlen, &hess->buf, &hess->lowranksyt, hess->memlen-1, _state); + rgemv(hess->memlen, n, 1.0, &hess->s, 0, &hess->yk, 0.0, &hess->buf, _state); + rcopyvc(hess->memlen, &hess->buf, &hess->lowranksyt, hess->memlen-1, _state); + + /* + * Recompute scaling + */ + hess->sigma = boundval(ynrm2/sy, eps2, (double)1/eps2, _state); + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" LBFGS update applied, diagonal scaling sigma=%0.2e\n", + (double)(hess->sigma)); + } + + /* + * Invalidate model + */ + optserv_resetlowrankmodel(hess, _state); + } +} + + +/************************************************************************* +Updates Hessian estimate using SR1 formula. Fails for other model types. + +INPUT PARAMETERS: + Hess - Hessian state + X0, G0 - point #0 and gradient at #0, array[N] + X1, G1 - point #1 and gradient at #1, array[N] + DoTrace - True if we want to print trace messages + TraceLevel - amount of ">" symbols to append to trace messages + + + -- ALGLIB -- + Copyright 08.02.2024 by Bochkanov Sergey +*************************************************************************/ +void hessianupdatesr1(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_bool dotrace, + ae_int_t tracelevel, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double dbgsigma; + double dbgsy; + double dbgsnrm2; + + + ae_assert(hess->htype==4, "HessianUpdateSR1: only SR1 models are supported", _state); + n = hess->n; + + /* + * Print initial trace line + */ + if( dotrace ) + { + traceangles(tracelevel, _state); + ae_trace(" analyzing Hessian update\n"); + } + + /* + * Prepare Sk, Yk, compute some necessary quantities + */ + for(i=0; i<=n-1; i++) + { + hess->sk.ptr.p_double[i] = x1->ptr.p_double[i]-x0->ptr.p_double[i]; + hess->yk.ptr.p_double[i] = g1->ptr.p_double[i]-g0->ptr.p_double[i]; + } + + /* + * Skip updates with zero or short steps, zero memory, etc + */ + if( hess->m==0 ) + { + + /* + * Zero memory was specified, update ignored + */ + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" zero memory length, update rejected\n"); + } + return; + } + if( ae_fp_less_eq(rmaxabsv(n, &hess->sk, _state),hess->stpshort) ) + { + + /* + * Sk is too small, skip update + */ + if( dotrace ) + { + traceangles(tracelevel+1, _state); + ae_trace(" step is too short, update rejected, enforcing Hessian decay\n"); + } + hessianmultiplyby(hess, 0.2, _state); + return; + } + + /* + * Prepare update + */ + ae_assert(hess->memlen<=hess->m, "HessianUpdateSR1: integrity check 7929 failed", _state); + if( hess->memlen==hess->m ) + { + optserv_popfrontxy(hess, _state); + } + ae_assert(hess->memlenm, "HessianUpdateSR1: integrity check 7930 failed", _state); + hess->memlen = hess->memlen+1; + rcopyvr(n, &hess->sk, &hess->s, hess->memlen-1, _state); + rcopyvr(n, &hess->yk, &hess->y, hess->memlen-1, _state); + if( dotrace ) + { + traceangles(tracelevel+1, _state); + dbgsy = (double)(0); + dbgsnrm2 = (double)(0); + for(i=0; i<=n-1; i++) + { + dbgsy = dbgsy+hess->sk.ptr.p_double[i]*hess->yk.ptr.p_double[i]; + dbgsnrm2 = dbgsnrm2+ae_sqr(hess->sk.ptr.p_double[i]/hess->varscale.ptr.p_double[i], _state); + } + dbgsigma = dbgsy/(dbgsnrm2+ae_machineepsilon*ae_machineepsilon); + ae_trace(" SR1 update applied, diagonal scaling sigma=SY/SS=%0.2e (SY=%0.2e, SS=%0.2e in scaled vars)\n", + (double)(dbgsigma), + (double)(dbgsy), + (double)(dbgsnrm2)); + } + optserv_resetlowrankmodel(hess, _state); +} + + +/************************************************************************* +Removes newest update pair from the limited memory Hessian model and +invalidates Hessian model. If Hessian does not allow to pop latest pair, +does nothing. + + -- ALGLIB -- + Copyright 28.09.2023 by Bochkanov Sergey +*************************************************************************/ +void hessianpoplatestifpossible(xbfgshessian* hess, ae_state *_state) +{ + + + ae_assert(hess->htype==0||hess->htype==3, "HessianPopLatestIfPossible: Hessian mode is not supported", _state); + if( hess->htype==0 ) + { + return; + } + if( hess->memlen==0 ) + { + return; + } + ae_assert(hess->htype==3, "OPTSERV: integrity check 0140 failed", _state); + hess->memlen = hess->memlen-1; + optserv_resetlowrankmodel(hess, _state); +} + + +/************************************************************************* +Multiplies internally stored model (and all internally stored corrections) +by S. + +This function works only with the following Hessian modes: +* direct BFGS +* low-rank LBFGS + +Any attempt to call it for other Hessian type will result in exception. + +INPUT PARAMETERS: + Hess - Hessian state + S - scale factor + + -- ALGLIB -- + Copyright 05.06.2023 by Bochkanov Sergey +*************************************************************************/ +void hessianmultiplyby(xbfgshessian* hess, double s, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianMultiplyBy: Hessian mode is not supported", _state); + n = hess->n; + if( hess->htype==0 ) + { + + /* + * Explicit dense Hessian + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + hess->hcurrent.ptr.pp_double[i][j] = hess->hcurrent.ptr.pp_double[i][j]*s; + hess->hincoming.ptr.pp_double[i][j] = hess->hincoming.ptr.pp_double[i][j]*s; + } + } + } + if( hess->htype==3 ) + { + + /* + * Low rank model + */ + hess->sigma = s*hess->sigma; + for(i=0; i<=hess->memlen-1; i++) + { + rmulr(n, s, &hess->y, i, _state); + rmulr(hess->memlen, s, &hess->lowranksyt, i, _state); + } + optserv_resetlowrankmodel(hess, _state); + } + if( hess->htype==4 ) + { + + /* + * Low rank model + */ + for(i=0; i<=hess->memlen-1; i++) + { + rmulr(n, s, &hess->y, i, _state); + } + optserv_resetlowrankmodel(hess, _state); + } +} + + +/************************************************************************* +Get diagonal of the Hessian. + +This function works only with the following Hessian modes: +* direct BFGS +* low-rank LBFGS + +Any attempt to call it for other Hessian type will result in exception. + +INPUT PARAMETERS: + Hess - Hessian state + D - possibly preallocated array; resized if needed + +OUTPUT PARAMETERS: + D - first N elements are filled with Hessian diagonal + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessiangetdiagonal(xbfgshessian* hess, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianGetDiagonal: Hessian mode is not supported", _state); + n = hess->n; + rallocv(n, d, _state); + if( hess->htype==0 ) + { + + /* + * Explicit dense Hessian + */ + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = hess->hcurrent.ptr.pp_double[i][i]; + } + } + if( hess->htype==3 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + optserv_recomputelowrankdiagonal(hess, _state); + rcopyv(n, &hess->lowrankeffd, d, _state); + } + if( hess->htype==4 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + optserv_recomputelowrankdiagonal(hess, _state); + rcopyv(n, &hess->sr1effd, d, _state); + } +} + + +/************************************************************************* +Get Hessian matrix in a dense format. + +This function works only with the following Hessian modes: +* direct BFGS +* low-rank LBFGS (needs k*N*N operations) + +Any attempt to call it for other Hessian type will result in exception. + +INPUT PARAMETERS: + Hess - Hessian state + IsUpper - whether upper or lower triangle is needed + H - possibly preallocated array; resized if needed + +OUTPUT PARAMETERS: + H - either upper or lower NxN elements are filled + with Hessian + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessiangetmatrix(xbfgshessian* hess, + ae_bool isupper, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianGetMatrix: Hessian mode is not supported", _state); + n = hess->n; + rallocm(n, n, h, _state); + if( hess->htype==0 ) + { + + /* + * Dense direct Hessian + */ + rcopym(n, n, &hess->hcurrent, h, _state); + } + if( hess->htype==3 ) + { + + /* + * Low-rank BFGS model + */ + optserv_recomputelowrankmodel(hess, _state); + rsetm(n, n, 0.0, h, _state); + for(i=0; i<=n-1; i++) + { + h->ptr.pp_double[i][i] = hess->sigma; + } + rmatrixgemm(n, n, hess->lowrankk, 1.0, &hess->lowrankcp, 0, 0, 1, &hess->lowrankcp, 0, 0, 0, 1.0, h, 0, 0, _state); + rmatrixgemm(n, n, hess->lowrankk, -1.0, &hess->lowrankcm, 0, 0, 1, &hess->lowrankcm, 0, 0, 0, 1.0, h, 0, 0, _state); + } + if( hess->htype==4 ) + { + + /* + * Low-rank SR1 model + */ + optserv_recomputelowrankmodel(hess, _state); + rsetm(n, n, 0.0, h, _state); + for(i=0; i<=n-1; i++) + { + h->ptr.pp_double[i][i] = hess->sr1d.ptr.p_double[i]; + } + if( hess->sr1k>0 ) + { + ae_assert(hess->sr1k<=hess->m, "OPTSERV: integrity check 4215 failed", _state); + rcopym(hess->sr1k, n, &hess->sr1c, &hess->corr2, _state); + for(i=0; i<=hess->sr1k-1; i++) + { + rmulr(n, hess->sr1z.ptr.p_double[i], &hess->corr2, i, _state); + } + rmatrixgemm(n, n, hess->sr1k, 1.0, &hess->sr1c, 0, 0, 1, &hess->corr2, 0, 0, 0, 1.0, h, 0, 0, _state); + } + } +} + + +/************************************************************************* +Returns 2-norm of the Hessian (can be cheaply computed due to its low-rank +structure, always computed during the update) + +This function works only with the following Hessian modes: +* low-rank SR1 + +Any attempt to call it for other Hessian type will result in exception. + +INPUT PARAMETERS: + Hess - Hessian state + +RESULT: + 2-norm of the unmodified Hessian (no positive-definiteness correction). + The norm is computed in scaled variables, as set by HessianSetScales. + + + -- ALGLIB -- + Copyright 28.02.2024 by Bochkanov Sergey +*************************************************************************/ +double hessiangetnrm2(xbfgshessian* hess, ae_state *_state) +{ + double result; + + + ae_assert(hess->htype==4, "HessianGetNrm2: Hessian mode is not supported", _state); + result = (double)(0); + if( hess->htype==4 ) + { + + /* + * Low-rank SR1 model + */ + optserv_recomputelowrankmodel(hess, _state); + result = hess->sr1nrm2; + } + return result; +} + + +/************************************************************************* +Returns 2-norm of the stabilized Hessian (can be cheaply computed due to +its low-rank structure, always computed during the update) + +This function works only with the following Hessian modes: +* low-rank SR1 + +Any attempt to call it for other Hessian type will result in exception. + +INPUT PARAMETERS: + Hess - Hessian state + +RESULT: + 2-norm of the stabilized Hessian (positive-definiteness correction). + The norm is computed in scaled variables, as set by HessianSetScales. + + + -- ALGLIB -- + Copyright 28.02.2024 by Bochkanov Sergey +*************************************************************************/ +double hessiangetnrm2stab(xbfgshessian* hess, ae_state *_state) +{ + double result; + + + ae_assert(hess->htype==4, "HessianGetNrm2: Hessian mode is not supported", _state); + result = (double)(0); + if( hess->htype==4 ) + { + + /* + * Low-rank SR1 model + */ + optserv_recomputelowrankmodel(hess, _state); + result = hess->sr1nrm2stab; + } + return result; +} + + +/************************************************************************* +Get Hessian matrix in a low-rank format D + C'*S*C where D is a diagonal +matrix, C is a low rank matrix, S is a matrix of +1 and -1. + +This function works only with the following Hessian modes: +* low-rank LBFGS (needs k*N operations) + +Any attempt to call it for other Hessian type will result in an exception. + +IMPORTANT: thus function uses original formulas from 'REPRESENTATIONS OF + QUASI-NEWTON MATRICES AND THEIR USE IN LIMITED MEMORY METHODS' + which produce a positive definite D+C'*S*C. + However, only the final result is positive definite. Any + partial update D+G'*U*G, where G/U are subsets of C/S, is NOT + guaranteed to be positive definite. Lack of these guarantees + usually destabilizes interior point low rank QP solvers and + other algorithms which rely on positive definiteness of partial + updates. + Use HessianGetLowRankStabilized() if you need robust updates. + +INPUT PARAMETERS: + Hess - Hessian state + D - possibly preallocated array, reused if large enough + CorrC - possibly preallocated array, reused if large enough + CorrS - possibly preallocated array, reused if large enough + +OUTPUT PARAMETERS: + D - array[N], diagonal matrix + CorrC - array[CorrK,N], low rank correction + CorrS - array[CorrK], signs + CorrK - correction rank, CorrK>=0 + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessiangetlowrank(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + *corrk = 0; + + ae_assert(hess->htype==3||hess->htype==4, "HessianGetMatrixLowRank: Hessian mode is not supported", _state); + n = hess->n; + if( hess->htype==3 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + *corrk = 2*hess->lowrankk; + rsetallocv(n, hess->sigma, d, _state); + if( hess->lowrankk>0 ) + { + rallocm(*corrk, n, corrc, _state); + rallocv(*corrk, corrs, _state); + for(i=0; i<=hess->lowrankk-1; i++) + { + for(j=0; j<=n-1; j++) + { + corrc->ptr.pp_double[2*i+0][j] = hess->lowrankcp.ptr.pp_double[i][j]; + corrc->ptr.pp_double[2*i+1][j] = hess->lowrankcm.ptr.pp_double[i][j]; + } + corrs->ptr.p_double[2*i+0] = (double)(1); + corrs->ptr.p_double[2*i+1] = (double)(-1); + } + } + } + if( hess->htype==4 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + *corrk = hess->sr1k; + rcopyallocv(n, &hess->sr1d, d, _state); + if( hess->sr1k>0 ) + { + rcopyallocm(*corrk, n, &hess->sr1c, corrc, _state); + rcopyallocv(*corrk, &hess->sr1z, corrs, _state); + } + } +} + + +/************************************************************************* +Get LBFGS memory contents: +* steps S +* gradient changes Y +* diagonal scaling Sigma + +The function guarantees that for each k we have (Sk,Yk)>0, however it does +NOT guarantee that all steps are stored and that steps are stored as is. +It may modify S and Y in order to improve conditioning, and it may skip +some update pairs if it decides to do so. + +This function works only with the following Hessian modes: +* low-rank LBFGS + +Any attempt to call it for other Hessian type will result in an exception. + +INPUT PARAMETERS: + Hess - Hessian state + S - possibly preallocated array, reused if large enough + Y - possibly preallocated array, reused if large enough + +OUTPUT PARAMETERS: + Sigma - Hessian diagonal magnitude, Sigma>0 + S - array[UpdCnt,N], steps stored (latest steps are + stored at the end) + Y - array[UpdCnt,N], gradient changes + UpdCnt - updates count + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessiangetlowrankmemory(xbfgshessian* hess, + double* sigma, + /* Real */ ae_matrix* s, + /* Real */ ae_matrix* y, + ae_int_t* updcnt, + ae_state *_state) +{ + ae_int_t n; + + *sigma = 0.0; + *updcnt = 0; + + ae_assert(hess->htype==3, "HessianGetMatrixLowRank: Hessian mode is not supported", _state); + n = hess->n; + if( hess->htype==3 ) + { + *sigma = hess->sigma; + *updcnt = hess->memlen; + if( hess->memlen>0 ) + { + rcopyallocm(hess->memlen, n, &hess->s, s, _state); + rcopyallocm(hess->memlen, n, &hess->y, y, _state); + } + } +} + + +/************************************************************************* +Get Hessian matrix in a low-rank format D + C'*S*C where D is a diagonal +matrix, C is a low rank matrix, S is a matrix of +1 and -1. + +This is a stabilized version of a low rank representation which guarantees +that both complete update C'*S*C of D and any partial update are positive +definite. It is more expensive than HessianGetLowRank() because a KxK +symmetric eigenproblem has to be solved in order to compute robust update. + +Unlike non-stabilized version, this function produces C with orthogonal +rows (rows are mutually orthogonal, although not normalized and can even +be zero). + +This function works only with the following Hessian modes: +* low-rank LBFGS +* low-rank SR1, in which case it returns a positive definite approximation + +Any attempt to call it for other Hessian type will result in an exception. + +INPUT PARAMETERS: + Hess - Hessian state + D - possibly preallocated array, reused if large enough + CorrC - possibly preallocated array, reused if large enough + CorrS - possibly preallocated array, reused if large enough + +OUTPUT PARAMETERS: + D - array[N], diagonal matrix + CorrC - array[CorrK,N], low rank correction + CorrS - array[CorrK], signs + CorrK - correction rank, CorrK>=0 + + -- ALGLIB -- + Copyright 10.02.2024 by Bochkanov Sergey +*************************************************************************/ +void hessiangetlowrankstabilized(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state) +{ + + *corrk = 0; + + ae_assert(hess->htype==3||hess->htype==4, "HessianGetMatrixLowRankStabilized: Hessian mode is not supported", _state); + if( hess->htype==3 ) + { + hessiangetlowrankstabilizedlbfgs(hess, d, corrc, corrs, corrk, _state); + } + if( hess->htype==4 ) + { + hessiangetlowrankstabilizedsr1(hess, d, corrc, corrs, corrk, _state); + } +} + + +/************************************************************************* +Low rank stabilized LBFGS model + + -- ALGLIB -- + Copyright 06.06.2023 by Bochkanov Sergey +*************************************************************************/ +void hessiangetlowrankstabilizedlbfgs(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + *corrk = 0; + + ae_assert(hess->htype==3, "HessianGetMatrixLowRankStabilized: Hessian mode is not supported", _state); + n = hess->n; + + /* + * Get non-modified low rank representation D+C'*S*C + */ + hessiangetlowrank(hess, d, &hess->tmpunstablec, &hess->tmpunstables, corrk, _state); + if( *corrk==0 ) + { + return; + } + + /* + * Handle low-dimensional case where K>N. We handle it by + * forming C'*S*C explicitly and by performing its EVD + * decomposition. + * + * As a result, CorrK is decreased down to N. + * + * A degenerate case which does not need much sophistication. + */ + if( *corrk>n ) + { + rallocm(*corrk, n, &hess->tmpsl, _state); + rallocm(*corrk, n, &hess->tmpl, _state); + for(i=0; i<=*corrk-1; i++) + { + rcopyrr(n, &hess->tmpunstablec, i, &hess->tmpl, i, _state); + rcopyrr(n, &hess->tmpunstablec, i, &hess->tmpsl, i, _state); + rmulr(n, hess->tmpunstables.ptr.p_double[i], &hess->tmpsl, i, _state); + } + rallocm(n, n, &hess->tmpw, _state); + rmatrixgemm(n, n, *corrk, 1.0, &hess->tmpl, 0, 0, 1, &hess->tmpsl, 0, 0, 0, 0.0, &hess->tmpw, 0, 0, _state); + if( !smatrixevd(&hess->tmpw, n, 1, ae_false, &hess->tmpe, &hess->tmpq, _state) ) + { + ae_assert(ae_false, "HessianGetLowRankStabilizedLBFGS: eigensolver failure", _state); + } + *corrk = n; + rallocm(n, n, corrc, _state); + rmatrixtranspose(n, n, &hess->tmpq, 0, 0, corrc, 0, 0, _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, ae_sqrt(ae_fabs(hess->tmpe.ptr.p_double[i], _state), _state), corrc, i, _state); + } + rallocv(n, corrs, _state); + for(i=0; i<=n-1; i++) + { + corrs->ptr.p_double[i] = rcase2(ae_fp_greater_eq(hess->tmpe.ptr.p_double[i],(double)(0)), (double)(1), (double)(-1), _state); + } + return; + } + + /* + * A non-degenerate case with CorrK<=N. + * + * Compute LQ decomposition of C, use it to transform C'*S*C to + * U'*W*U with orthogonal U being a factor from LQ decomposition + * and W being a KxK matrix equal to L'*S*L + * + */ + rmatrixlq(&hess->tmpunstablec, *corrk, n, &hess->tmptau, _state); + rmatrixlqunpackq(&hess->tmpunstablec, *corrk, n, &hess->tmptau, *corrk, &hess->tmpu, _state); + rsetallocm(*corrk, *corrk, 0.0, &hess->tmpsl, _state); + rsetallocm(*corrk, *corrk, 0.0, &hess->tmpl, _state); + for(i=0; i<=*corrk-1; i++) + { + rcopyrr(i+1, &hess->tmpunstablec, i, &hess->tmpl, i, _state); + rcopyrr(i+1, &hess->tmpunstablec, i, &hess->tmpsl, i, _state); + rmulr(i+1, hess->tmpunstables.ptr.p_double[i], &hess->tmpsl, i, _state); + } + rallocm(*corrk, *corrk, &hess->tmpw, _state); + rmatrixgemm(*corrk, *corrk, *corrk, 1.0, &hess->tmpl, 0, 0, 1, &hess->tmpsl, 0, 0, 0, 0.0, &hess->tmpw, 0, 0, _state); + + /* + * Now we have C'*S*C = U'*W*U, with S being diagonal and W being a general matrix. + * Another different is that C is non-orthogonal whilst U is orthogonal. + * + * Use EVD to obtain orthogonal decomposition W=Q*E*Q' with orthogonal Q and diagonal E. + */ + if( !smatrixevd(&hess->tmpw, *corrk, 1, ae_false, &hess->tmpe, &hess->tmpq, _state) ) + { + ae_assert(ae_false, "HessianGetLowRankStabilizedLBFGS: eigensolver failure", _state); + } + + /* + * Finally, output robust representation: + * * C = sqrt(abs(E))*Q'*U + * * S = E/abs(E) + */ + rallocm(*corrk, n, corrc, _state); + rmatrixgemm(*corrk, n, *corrk, 1.0, &hess->tmpq, 0, 0, 1, &hess->tmpu, 0, 0, 0, 0.0, corrc, 0, 0, _state); + for(i=0; i<=*corrk-1; i++) + { + rmulr(n, ae_sqrt(ae_fabs(hess->tmpe.ptr.p_double[i], _state), _state), corrc, i, _state); + } + rallocv(*corrk, corrs, _state); + for(i=0; i<=*corrk-1; i++) + { + corrs->ptr.p_double[i] = rcase2(ae_fp_greater_eq(hess->tmpe.ptr.p_double[i],(double)(0)), (double)(1), (double)(-1), _state); + } +} + + +/************************************************************************* +Stabilized low rank model for SR1 update. + + -- ALGLIB -- + Copyright 10.02.2024 by Bochkanov Sergey +*************************************************************************/ +void hessiangetlowrankstabilizedsr1(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state) +{ + ae_int_t n; + + *corrk = 0; + + ae_assert(hess->htype==4, "HessianGetMatrixLowRankStabilizedSR1: Hessian mode is not supported", _state); + n = hess->n; + optserv_recomputelowrankmodel(hess, _state); + rcopyallocv(n, &hess->sr1stabd, d, _state); + rcopyallocm(hess->sr1k, n, &hess->sr1stabc, corrc, _state); + rcopyallocv(hess->sr1k, &hess->sr1stabz, corrs, _state); + *corrk = hess->sr1k; +} + + +/************************************************************************* +Returns maximum rank of the models returned by the HessianGetLowRank() +function. + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +ae_int_t hessiangetmaxrank(const xbfgshessian* hess, ae_state *_state) +{ + ae_int_t result; + + + ae_assert(hess->htype==3||hess->htype==4, "HessianGetMaxRank: Hessian mode is not supported", _state); + result = 0; + if( hess->htype==3 ) + { + result = 2*hess->m; + } + if( hess->htype==4 ) + { + result = hess->m; + } + return result; +} + + +/************************************************************************* +Computes direct product H*x (here H is a Hessian matrix, not its inverse). +Either BFGS or LBFGS formula is used, depending on Hessian model settings. + +NOTE: this function modifies internal state of Hess, it uses temporary + arrays allocated in Hess. Thus, it is not thread-safe. + +INPUT PARAMETERS: + Hess - Hessian state + X - array[N] + +OUTPUT PARAMETERS: + HX - array[N], H*x + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +void hessianmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state) +{ + ae_int_t n; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianMV: Hessian mode is not supported", _state); + n = hess->n; + rallocv(n, hx, _state); + if( hess->htype==0 ) + { + + /* + * Dense direct Hessian + */ + rgemv(n, n, 1.0, &hess->hcurrent, 0, x, 0.0, hx, _state); + } + if( hess->htype==3 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + rcopymulv(n, hess->sigma, x, hx, _state); + if( hess->lowrankk>0 ) + { + rallocv(hess->lowrankk, &hess->buf, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcp, 0, x, 0.0, &hess->buf, _state); + rgemv(n, hess->lowrankk, 1.0, &hess->lowrankcp, 1, &hess->buf, 1.0, hx, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcm, 0, x, 0.0, &hess->buf, _state); + rgemv(n, hess->lowrankk, -1.0, &hess->lowrankcm, 1, &hess->buf, 1.0, hx, _state); + } + } + if( hess->htype==4 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + rcopyv(n, x, hx, _state); + rmergemulv(n, &hess->sr1d, hx, _state); + if( hess->sr1k>0 ) + { + rallocv(hess->sr1k, &hess->buf, _state); + rgemv(hess->sr1k, n, 1.0, &hess->sr1c, 0, x, 0.0, &hess->buf, _state); + rmergemulv(hess->sr1k, &hess->sr1z, &hess->buf, _state); + rgemv(n, hess->sr1k, 1.0, &hess->sr1c, 1, &hess->buf, 1.0, hx, _state); + } + } +} + + +/************************************************************************* +Computes direct product x'*H*x (here H is a Hessian matrix, not its inverse). +Either BFGS or LBFGS formula is used, depending on Hessian model settings. + +NOTE: this function modifies internal state of Hess, it uses temporary + arrays allocated in Hess. Thus, it is not thread-safe. + +NOTE: for low-rank models this function is much more precise than computing + H*x and then computing dot product with x. + +INPUT PARAMETERS: + Hess - Hessian state + X - array[N] + +RESULT: + x'*H*x + + -- ALGLIB -- + Copyright 14.03.2023 by Bochkanov Sergey +*************************************************************************/ +double hessianvmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double result; + + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianVMV: Hessian mode is not supported", _state); + result = (double)(0); + n = hess->n; + if( hess->htype==0 ) + { + + /* + * Dense direct Hessian + */ + hessianmv(hess, x, &hess->bufvmv, _state); + result = rdotv(n, x, &hess->bufvmv, _state); + return result; + } + if( hess->htype==3 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + result = hess->sigma*rdotv2(n, x, _state); + if( hess->lowrankk>0 ) + { + rallocv(hess->lowrankk, &hess->bufvmv, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcp, 0, x, 0.0, &hess->bufvmv, _state); + result = result+rdotv2(hess->lowrankk, &hess->bufvmv, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcm, 0, x, 0.0, &hess->bufvmv, _state); + result = result-rdotv2(hess->lowrankk, &hess->bufvmv, _state); + } + return result; + } + if( hess->htype==4 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+hess->sr1d.ptr.p_double[i]*(x->ptr.p_double[i]*x->ptr.p_double[i]); + } + if( hess->sr1k>0 ) + { + rallocv(hess->sr1k, &hess->bufvmv, _state); + rgemv(hess->sr1k, n, 1.0, &hess->sr1c, 0, x, 0.0, &hess->bufvmv, _state); + for(i=0; i<=hess->sr1k-1; i++) + { + result = result+hess->sr1z.ptr.p_double[i]*(hess->bufvmv.ptr.p_double[i]*hess->bufvmv.ptr.p_double[i]); + } + } + return result; + } + return result; +} + + +/************************************************************************* +Computes direct product x'*H*x (here H is a Hessian matrix, not its inverse) +along with direct product H*x. + +Either BFGS or LBFGS formula is used, depending on Hessian model settings. + +NOTE: this function modifies internal state of Hess, it uses temporary + arrays allocated in Hess. Thus, it is not thread-safe. + +NOTE: for low-rank models this function computes more precise x'*H*x than + H*x multiplied by x. + +INPUT PARAMETERS: + Hess - Hessian state + X - array[N] + +OUTPUT PARAMETERS: + HX - array[N], H*x + XHX - x'*H*x + + -- ALGLIB -- + Copyright 14.03.2023 by Bochkanov Sergey +*************************************************************************/ +void hessianxmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + double* xhx, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + *xhx = 0.0; + + ae_assert((hess->htype==0||hess->htype==3)||hess->htype==4, "HessianXMV: Hessian mode is not supported", _state); + n = hess->n; + rallocv(n, hx, _state); + *xhx = (double)(0); + if( hess->htype==0 ) + { + + /* + * Dense direct Hessian + */ + rgemv(n, n, 1.0, &hess->hcurrent, 0, x, 0.0, hx, _state); + *xhx = rdotv(n, x, hx, _state); + return; + } + if( hess->htype==3 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + rcopymulv(n, hess->sigma, x, hx, _state); + *xhx = hess->sigma*rdotv2(n, x, _state); + if( hess->lowrankk>0 ) + { + rallocv(hess->lowrankk, &hess->buf, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcp, 0, x, 0.0, &hess->buf, _state); + rgemv(n, hess->lowrankk, 1.0, &hess->lowrankcp, 1, &hess->buf, 1.0, hx, _state); + *xhx = *xhx+rdotv2(hess->lowrankk, &hess->buf, _state); + rgemv(hess->lowrankk, n, 1.0, &hess->lowrankcm, 0, x, 0.0, &hess->buf, _state); + rgemv(n, hess->lowrankk, -1.0, &hess->lowrankcm, 1, &hess->buf, 1.0, hx, _state); + *xhx = *xhx-rdotv2(hess->lowrankk, &hess->buf, _state); + } + return; + } + if( hess->htype==4 ) + { + + /* + * Low-rank model + */ + optserv_recomputelowrankmodel(hess, _state); + rcopyv(n, x, hx, _state); + rmergemulv(n, &hess->sr1d, hx, _state); + *xhx = rdotv(n, x, hx, _state); + if( hess->sr1k>0 ) + { + rallocv(hess->sr1k, &hess->buf, _state); + rgemv(hess->sr1k, n, 1.0, &hess->sr1c, 0, x, 0.0, &hess->buf, _state); + for(i=0; i<=hess->sr1k-1; i++) + { + *xhx = *xhx+hess->sr1z.ptr.p_double[i]*(hess->buf.ptr.p_double[i]*hess->buf.ptr.p_double[i]); + hess->buf.ptr.p_double[i] = hess->sr1z.ptr.p_double[i]*hess->buf.ptr.p_double[i]; + } + rgemv(n, hess->sr1k, 1.0, &hess->sr1c, 1, &hess->buf, 1.0, hx, _state); + } + return; + } +} + + +/************************************************************************* +Creates random multiobjective test problem with no known answers + +INPUT PARAMETERS: + N - vars cnt + M - targets cnt + NEquality - desired count of equality constraints of all kinds + (box, linear, nonlinear) + NInequality - desired count of non-box inequality constraints + TaskKind - task type: + * 0 = convex quartic + * 1 = convex quadratic + * 2 = convex low rank quadratic + * 3 = linear + * 4 = constant + NLQuadratic - scale of the quadratic term of nonlinear constraints + NLQuartic - scale of the quadratic term of nonlinear constraints + +NOTE: this function does NOT set Lagrange multipliers because it does not + know them. + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreaterandomunknown(ae_int_t n, + ae_int_t m, + ae_int_t nequality, + ae_int_t ninequality, + ae_int_t taskkind, + double nlquadratic, + double nlquartic, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t rk; + ae_matrix q; + ae_vector grad; + ae_vector x; + ae_vector ax; + ae_vector c; + ae_bool issemidefinite; + ae_bool haslinearterm; + ae_bool hasnonlinearterms; + ae_bool hasquadraticterm; + ae_bool hasquarticterm; + ae_int_t ngenerated; + ae_int_t cidx; + ae_int_t ctype; + double v; + double vmul; + ae_vector xtrial; + ae_int_t passcount; + ae_int_t nboxinequality; + ae_int_t nlinearinequality; + ae_int_t nnonlinearinequality; + + ae_frame_make(_state, &_frame_block); + memset(&q, 0, sizeof(q)); + memset(&grad, 0, sizeof(grad)); + memset(&x, 0, sizeof(x)); + memset(&ax, 0, sizeof(ax)); + memset(&c, 0, sizeof(c)); + memset(&xtrial, 0, sizeof(xtrial)); + _multiobjectivetestfunction_clear(problem); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&grad, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ax, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xtrial, 0, DT_REAL, _state, ae_true); + + haslinearterm = ae_false; + hasnonlinearterms = ae_false; + hasquadraticterm = ae_false; + hasquarticterm = ae_false; + issemidefinite = ae_false; + touchboolean(&haslinearterm, _state); + touchboolean(&hasnonlinearterms, _state); + touchboolean(&hasquadraticterm, _state); + touchboolean(&hasquarticterm, _state); + touchboolean(&issemidefinite, _state); + + /* + * Generate random test functions + */ + problem->isrotated = ae_false; + problem->problemtype = 0; + problem->n = n; + problem->m = m; + rsetallocv(m, 0.0, &problem->tgtc, _state); + rsetallocm(m, n, 0.0, &problem->tgtb, _state); + rsetallocm(m*n, n, 0.0, &problem->tgta, _state); + rsetallocm(m, n, 0.0, &problem->tgtd, _state); + ae_assert(taskkind>=0&&taskkind<=4, "MOTFCreate: incorrect TaskKind", _state); + if( taskkind==0 ) + { + + /* + * Quartic term + */ + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + problem->tgtd.ptr.pp_double[i][j] = ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + } + } + hasnonlinearterms = ae_true; + hasquarticterm = ae_true; + } + if( taskkind<=2 ) + { + + /* + * Quadratic term + */ + if( taskkind!=2 ) + { + + /* + * well conditioned matrix + */ + for(k=0; k<=m-1; k++) + { + spdmatrixrndcond(n, 100.0, &q, _state); + rmatrixcopy(n, n, &q, 0, 0, &problem->tgta, k*n, 0, _state); + } + } + else + { + + /* + * Low rank matrix + */ + rk = ae_minint(n, 1+hqrnduniformi(rs, 5, _state), _state); + for(k=0; k<=m-1; k++) + { + hqrndnormalm(rs, rk, n, &q, _state); + rmatrixgemm(n, n, rk, 1.0, &q, 0, 0, 1, &q, 0, 0, 0, 0.0, &problem->tgta, k*n, 0, _state); + } + } + hasquadraticterm = ae_true; + hasnonlinearterms = ae_true; + } + if( taskkind<=3 ) + { + + /* + * Linear term + */ + hqrndnormalm(rs, m, n, &problem->tgtb, _state); + haslinearterm = ae_true; + } + if( taskkind<=4 ) + { + + /* + * Constant term + */ + hqrndnormalv(rs, m, &problem->tgtc, _state); + } + issemidefinite = taskkind>=2; + + /* + * No initial points + */ + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + + /* + * No known solutions + */ + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + problem->ksol = 0; + + /* + * No Lagrange multipliers + */ + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Generate random trial point which will be strictly feasible + */ + hqrndnormalv(rs, n, &xtrial, _state); + + /* + * + * Generate empty set of constraints + */ + rsetallocv(n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(n, _state->v_posinf, &problem->bndu, _state); + problem->nlinear = 0; + problem->nnonlinear = 0; + + /* + * Randomly generate equality constraints using trial point + */ + ngenerated = 0; + passcount = 0; + while(ngeneratedbndl.ptr.p_double[i], _state)&&ae_isposinf(problem->bndu.ptr.p_double[i], _state) ) + { + + /* + * Use this box constraint. + * Fix a bound corresponding to the Lagrange multiplier direction, + * with probability 15% fix other bound too (when it is free). + */ + problem->bndl.ptr.p_double[i] = xtrial.ptr.p_double[i]; + problem->bndu.ptr.p_double[i] = xtrial.ptr.p_double[i]; + ngenerated = ngenerated+1; + } + } + + /* + * Add a linear equality constraint. + */ + if( ctype==1 ) + { + hqrndnormalv(rs, n, &c, _state); + v = rdotv(n, &c, &xtrial, _state); + rmatrixgrowrowsto(&problem->densea, problem->nlinear+1, n, _state); + rgrowv(problem->nlinear+1, &problem->al, _state); + rgrowv(problem->nlinear+1, &problem->au, _state); + rcopyvr(n, &c, &problem->densea, problem->nlinear, _state); + problem->al.ptr.p_double[problem->nlinear] = v; + problem->au.ptr.p_double[problem->nlinear] = v; + problem->nlinear = problem->nlinear+1; + ngenerated = ngenerated+1; + } + + /* + * Add a nonlinear equality constraint. + */ + if( ctype==2 ) + { + + /* + * Allocate place + */ + rgrowv(problem->nnonlinear+1, &problem->nlc, _state); + rmatrixgrowrowsto(&problem->nlb, problem->nnonlinear+1, n, _state); + rmatrixgrowrowsto(&problem->nla, (problem->nnonlinear+1)*n, n, _state); + rmatrixgrowrowsto(&problem->nld, problem->nnonlinear+1, n, _state); + rgrowv(problem->nnonlinear+1, &problem->hl, _state); + rgrowv(problem->nnonlinear+1, &problem->hu, _state); + + /* + * Generate and compute nonlinear constraint + */ + v = (double)(0); + problem->nlc.ptr.p_double[problem->nnonlinear] = hqrndnormal(rs, _state); + v = v+problem->nlc.ptr.p_double[problem->nnonlinear]; + hqrndnormalv(rs, n, &c, _state); + rcopyvr(n, &c, &problem->nlb, problem->nnonlinear, _state); + v = v+rdotv(n, &c, &xtrial, _state); + spdmatrixrndcond(n, 10.0, &q, _state); + vmul = nlquadratic*ae_fabs(hqrndnormal(rs, _state), _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, vmul, &q, i, _state); + } + rmatrixcopy(n, n, &q, 0, 0, &problem->nla, problem->nnonlinear*n, 0, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = v+0.5*xtrial.ptr.p_double[i]*q.ptr.pp_double[i][j]*xtrial.ptr.p_double[j]; + } + } + for(i=0; i<=n-1; i++) + { + problem->nld.ptr.pp_double[problem->nnonlinear][i] = nlquartic*ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + v = v+problem->nld.ptr.pp_double[problem->nnonlinear][i]*ae_pow(xtrial.ptr.p_double[i], (double)(4), _state); + } + problem->hl.ptr.p_double[problem->nnonlinear] = v; + problem->hu.ptr.p_double[problem->nnonlinear] = v; + problem->nnonlinear = problem->nnonlinear+1; + ngenerated = ngenerated+1; + } + } + + /* + * Decide on desired count of inequality constraints of all types (for box constraints - only approximate count) + */ + nboxinequality = hqrnduniformi(rs, ninequality+1, _state); + nlinearinequality = hqrnduniformi(rs, ninequality-nboxinequality+1, _state); + nnonlinearinequality = ninequality-nboxinequality-nlinearinequality; + + /* + * Randomly generate box/linear/nonlinear inequality constraints inactive at the trial point + */ + for(k=0; k<=nboxinequality-1; k++) + { + i = hqrnduniformi(rs, n, _state); + if( ae_isneginf(problem->bndl.ptr.p_double[i], _state)&&ae_isposinf(problem->bndu.ptr.p_double[i], _state) ) + { + ctype = hqrnduniformi(rs, 3, _state); + problem->bndl.ptr.p_double[i] = rcase2(ctype==0||ctype==2, xtrial.ptr.p_double[i]-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->bndu.ptr.p_double[i] = rcase2(ctype==1||ctype==2, xtrial.ptr.p_double[i]+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + } + } + for(cidx=0; cidx<=nlinearinequality-1; cidx++) + { + hqrndnormalv(rs, n, &c, _state); + v = rdotv(n, &c, &xtrial, _state); + ctype = hqrnduniformi(rs, 3, _state); + rmatrixgrowrowsto(&problem->densea, problem->nlinear+1, n, _state); + rgrowv(problem->nlinear+1, &problem->al, _state); + rgrowv(problem->nlinear+1, &problem->au, _state); + rcopyvr(n, &c, &problem->densea, problem->nlinear, _state); + problem->al.ptr.p_double[problem->nlinear] = rcase2(ctype==0||ctype==2, v-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->au.ptr.p_double[problem->nlinear] = rcase2(ctype==1||ctype==2, v+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + problem->nlinear = problem->nlinear+1; + } + for(cidx=0; cidx<=nnonlinearinequality-1; cidx++) + { + + /* + * Allocate place + */ + rgrowv(problem->nnonlinear+1, &problem->nlc, _state); + rmatrixgrowrowsto(&problem->nlb, problem->nnonlinear+1, n, _state); + rmatrixgrowrowsto(&problem->nla, (problem->nnonlinear+1)*n, n, _state); + rmatrixgrowrowsto(&problem->nld, problem->nnonlinear+1, n, _state); + rgrowv(problem->nnonlinear+1, &problem->hl, _state); + rgrowv(problem->nnonlinear+1, &problem->hu, _state); + + /* + * Generate and compute nonlinear constraint + */ + v = (double)(0); + problem->nlc.ptr.p_double[problem->nnonlinear] = hqrndnormal(rs, _state); + v = v+problem->nlc.ptr.p_double[problem->nnonlinear]; + hqrndnormalv(rs, n, &c, _state); + rcopyvr(n, &c, &problem->nlb, problem->nnonlinear, _state); + v = v+rdotv(n, &c, &xtrial, _state); + spdmatrixrndcond(n, 10.0, &q, _state); + vmul = nlquadratic*ae_fabs(hqrndnormal(rs, _state), _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, vmul, &q, i, _state); + } + rmatrixcopy(n, n, &q, 0, 0, &problem->nla, problem->nnonlinear*n, 0, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = v+0.5*xtrial.ptr.p_double[i]*q.ptr.pp_double[i][j]*xtrial.ptr.p_double[j]; + } + } + for(i=0; i<=n-1; i++) + { + problem->nld.ptr.pp_double[problem->nnonlinear][i] = nlquartic*ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + v = v+problem->nld.ptr.pp_double[problem->nnonlinear][i]*ae_pow(xtrial.ptr.p_double[i], (double)(4), _state); + } + ctype = hqrnduniformi(rs, 3, _state); + problem->hl.ptr.p_double[problem->nnonlinear] = rcase2(ctype==0||ctype==2, v-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->hu.ptr.p_double[problem->nnonlinear] = rcase2(ctype==1||ctype==2, v+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + problem->nnonlinear = problem->nnonlinear+1; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Creates random multiobjective test problem with known answer and Lagrange +multipliers + +INPUT PARAMETERS: + N - vars cnt, N>=3 + NLQuadratic - scale of the quadratic term of nonlinear constraints + NLQuartic - scale of the quartic term of nonlinear constraints + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreate1knownanswer(ae_int_t n, + double nlquadratic, + double nlquartic, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector grad; + ae_vector c; + ae_int_t nactive; + ae_int_t ngenerated; + ae_int_t nadditionallin; + ae_int_t nadditionalnl; + double lagmult; + ae_int_t passcount; + ae_int_t ctype; + double v; + double vmul; + ae_matrix q; + double padinactive; + + ae_frame_make(_state, &_frame_block); + memset(&grad, 0, sizeof(grad)); + memset(&c, 0, sizeof(c)); + memset(&q, 0, sizeof(q)); + _multiobjectivetestfunction_clear(problem); + ae_vector_init(&grad, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + + padinactive = 10.0; + + /* + * Set problem metrics + */ + problem->isrotated = ae_false; + problem->problemtype = 0; + problem->n = n; + problem->m = 1; + + /* + * Set empty constraints + */ + rsetallocv(n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(n, _state->v_posinf, &problem->bndu, _state); + problem->nlinear = 0; + problem->nnonlinear = 0; + + /* + * No initial points + */ + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + + /* + * Generate a priori known solution + */ + ae_matrix_set_length(&problem->xsol, 1, n, _state); + ae_matrix_set_length(&problem->fsol, 1, 1, _state); + for(i=0; i<=n-1; i++) + { + problem->xsol.ptr.pp_double[0][i] = hqrndnormal(rs, _state); + } + problem->fsol.ptr.pp_double[0][0] = (double)(0); + problem->ksol = 1; + + /* + * Initial state of Lagrange multipliers + */ + ae_vector_set_length(&problem->lagmultbc, n, _state); + rsetv(n, 0.0, &problem->lagmultbc, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Compute gradient introduced by constraints multiplied by Lagrange coefficients + * Randomly generate set of active (equality or inequality) constraints + */ + ae_assert(n>=3, "MOTFCreate1KnownAnswer: N<3", _state); + rsetallocv(n, 0.0, &grad, _state); + ngenerated = 0; + nactive = hqrnduniformi(rs, n-2, _state); + passcount = 0; + while(ngeneratedbndl.ptr.p_double[i], _state)&&ae_isposinf(problem->bndu.ptr.p_double[i], _state) ) + { + + /* + * Use this box constraint. + * Fix a bound corresponding to the Lagrange multiplier direction, + * with probability 15% fix other bound too (when it is free). + */ + ae_assert(ae_fp_neq(lagmult,(double)(0)), "OPTSERV: integrity check 0948 failed", _state); + if( ae_fp_less(lagmult,(double)(0)) ) + { + problem->bndl.ptr.p_double[i] = problem->xsol.ptr.pp_double[0][i]; + } + if( ae_fp_greater(lagmult,(double)(0)) ) + { + problem->bndu.ptr.p_double[i] = problem->xsol.ptr.pp_double[0][i]; + } + if( ae_fp_less(hqrnduniformr(rs, _state),0.15) ) + { + problem->bndl.ptr.p_double[i] = problem->xsol.ptr.pp_double[0][i]; + problem->bndu.ptr.p_double[i] = problem->xsol.ptr.pp_double[0][i]; + } + grad.ptr.p_double[i] = grad.ptr.p_double[i]+lagmult; + problem->lagmultbc.ptr.p_double[i] = problem->lagmultbc.ptr.p_double[i]+lagmult; + ngenerated = ngenerated+1; + } + continue; + } + + /* + * Add a linear constraint. + */ + if( ctype==1 ) + { + ae_assert(ae_fp_neq(lagmult,(double)(0)), "OPTSERV: integrity check 0948 failed", _state); + hqrndnormalv(rs, n, &c, _state); + v = rdotvr(n, &c, &problem->xsol, 0, _state); + rmatrixgrowrowsto(&problem->densea, problem->nlinear+1, n, _state); + rgrowv(problem->nlinear+1, &problem->al, _state); + rgrowv(problem->nlinear+1, &problem->au, _state); + rcopyvr(n, &c, &problem->densea, problem->nlinear, _state); + problem->al.ptr.p_double[problem->nlinear] = _state->v_neginf; + problem->au.ptr.p_double[problem->nlinear] = _state->v_posinf; + if( ae_fp_less(lagmult,(double)(0)) ) + { + problem->al.ptr.p_double[problem->nlinear] = v; + } + if( ae_fp_greater(lagmult,(double)(0)) ) + { + problem->au.ptr.p_double[problem->nlinear] = v; + } + if( ae_fp_less(hqrnduniformr(rs, _state),0.15) ) + { + problem->al.ptr.p_double[problem->nlinear] = v; + problem->au.ptr.p_double[problem->nlinear] = v; + } + raddv(n, lagmult, &c, &grad, _state); + rvectorresize(&problem->lagmultlc, problem->nlinear+1, _state); + problem->lagmultlc.ptr.p_double[problem->nlinear] = lagmult; + problem->nlinear = problem->nlinear+1; + ngenerated = ngenerated+1; + continue; + } + + /* + * Add a nonlinear constraint. + */ + if( ctype==2 ) + { + ae_assert(ae_fp_neq(lagmult,(double)(0)), "OPTSERV: integrity check 0948 failed", _state); + + /* + * Allocate place + */ + rgrowv(problem->nnonlinear+1, &problem->nlc, _state); + rmatrixgrowrowsto(&problem->nlb, problem->nnonlinear+1, n, _state); + rmatrixgrowrowsto(&problem->nla, (problem->nnonlinear+1)*n, n, _state); + rmatrixgrowrowsto(&problem->nld, problem->nnonlinear+1, n, _state); + rgrowv(problem->nnonlinear+1, &problem->hl, _state); + rgrowv(problem->nnonlinear+1, &problem->hu, _state); + + /* + * Generate and compute value of the nonlinear constraint, update gradient + */ + v = (double)(0); + problem->nlc.ptr.p_double[problem->nnonlinear] = hqrndnormal(rs, _state); + v = v+problem->nlc.ptr.p_double[problem->nnonlinear]; + hqrndnormalv(rs, n, &c, _state); + rcopyvr(n, &c, &problem->nlb, problem->nnonlinear, _state); + v = v+rdotvr(n, &c, &problem->xsol, 0, _state); + raddv(n, lagmult, &c, &grad, _state); + spdmatrixrndcond(n, 10.0, &q, _state); + vmul = nlquadratic*ae_fabs(hqrndnormal(rs, _state), _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, vmul, &q, i, _state); + } + rmatrixcopy(n, n, &q, 0, 0, &problem->nla, problem->nnonlinear*n, 0, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = v+0.5*problem->xsol.ptr.pp_double[0][i]*q.ptr.pp_double[i][j]*problem->xsol.ptr.pp_double[0][j]; + grad.ptr.p_double[i] = grad.ptr.p_double[i]+lagmult*q.ptr.pp_double[i][j]*problem->xsol.ptr.pp_double[0][j]; + } + } + for(i=0; i<=n-1; i++) + { + problem->nld.ptr.pp_double[problem->nnonlinear][i] = nlquartic*ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + v = v+problem->nld.ptr.pp_double[problem->nnonlinear][i]*ae_pow(problem->xsol.ptr.pp_double[0][i], (double)(4), _state); + grad.ptr.p_double[i] = grad.ptr.p_double[i]+lagmult*problem->nld.ptr.pp_double[problem->nnonlinear][i]*(double)4*ae_pow(problem->xsol.ptr.pp_double[0][i], (double)(3), _state); + } + problem->hl.ptr.p_double[problem->nnonlinear] = _state->v_neginf; + problem->hu.ptr.p_double[problem->nnonlinear] = _state->v_posinf; + if( ae_fp_less(lagmult,(double)(0)) ) + { + problem->hl.ptr.p_double[problem->nnonlinear] = v; + } + if( ae_fp_greater(lagmult,(double)(0)) ) + { + problem->hu.ptr.p_double[problem->nnonlinear] = v; + } + if( ae_fp_less(hqrnduniformr(rs, _state),0.15) ) + { + problem->hl.ptr.p_double[problem->nnonlinear] = v; + problem->hu.ptr.p_double[problem->nnonlinear] = v; + } + rvectorresize(&problem->lagmultnlc, problem->nnonlinear+1, _state); + problem->lagmultnlc.ptr.p_double[problem->nnonlinear] = lagmult; + problem->nnonlinear = problem->nnonlinear+1; + ngenerated = ngenerated+1; + continue; + } + } + + /* + * Generate convex target which exactly balances gradient introduced by constraints + */ + rsetallocv(1, 0.0, &problem->tgtc, _state); + rsetallocm(1, n, 0.0, &problem->tgtb, _state); + rsetallocm(n, n, 0.0, &problem->tgta, _state); + rsetallocm(1, n, 0.0, &problem->tgtd, _state); + for(i=0; i<=n-1; i++) + { + problem->tgtd.ptr.pp_double[0][i] = 0.05*ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + problem->fsol.ptr.pp_double[0][0] = problem->fsol.ptr.pp_double[0][0]+problem->tgtd.ptr.pp_double[0][i]*ae_pow(problem->xsol.ptr.pp_double[0][i], (double)(4), _state); + grad.ptr.p_double[i] = grad.ptr.p_double[i]+problem->tgtd.ptr.pp_double[0][i]*(double)4*ae_pow(problem->xsol.ptr.pp_double[0][i], (double)(3), _state); + } + for(i=0; i<=n-1; i++) + { + problem->tgtb.ptr.pp_double[0][i] = -grad.ptr.p_double[i]; + problem->fsol.ptr.pp_double[0][0] = problem->fsol.ptr.pp_double[0][0]+problem->tgtb.ptr.pp_double[0][i]*problem->xsol.ptr.pp_double[0][i]; + } + + /* + * Randomly generate constraints which are inactive at the trial point + */ + k = hqrnduniformi(rs, ae_minint(1+n/2, 5, _state), _state); + nadditionallin = hqrnduniformi(rs, k+1, _state); + nadditionalnl = k-nadditionallin; + for(i=0; i<=n-1; i++) + { + if( (ae_fp_less(hqrnduniformr(rs, _state),0.5)&&ae_isneginf(problem->bndl.ptr.p_double[i], _state))&&ae_isposinf(problem->bndu.ptr.p_double[i], _state) ) + { + ctype = hqrnduniformi(rs, 3, _state); + problem->bndl.ptr.p_double[i] = rcase2(ctype==0||ctype==2, problem->xsol.ptr.pp_double[0][i]-padinactive-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->bndu.ptr.p_double[i] = rcase2(ctype==1||ctype==2, problem->xsol.ptr.pp_double[0][i]+padinactive+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + } + } + for(k=0; k<=nadditionallin-1; k++) + { + hqrndnormalv(rs, n, &c, _state); + v = rdotvr(n, &c, &problem->xsol, 0, _state); + rmatrixgrowrowsto(&problem->densea, problem->nlinear+1, n, _state); + rgrowv(problem->nlinear+1, &problem->al, _state); + rgrowv(problem->nlinear+1, &problem->au, _state); + rcopyvr(n, &c, &problem->densea, problem->nlinear, _state); + ctype = hqrnduniformi(rs, 3, _state); + problem->al.ptr.p_double[problem->nlinear] = rcase2(ctype==0||ctype==2, v-padinactive-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->au.ptr.p_double[problem->nlinear] = rcase2(ctype==1||ctype==2, v+padinactive+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + problem->nlinear = problem->nlinear+1; + } + for(k=0; k<=nadditionalnl-1; k++) + { + + /* + * Allocate place + */ + rgrowv(problem->nnonlinear+1, &problem->nlc, _state); + rmatrixgrowrowsto(&problem->nlb, problem->nnonlinear+1, n, _state); + rmatrixgrowrowsto(&problem->nla, (problem->nnonlinear+1)*n, n, _state); + rmatrixgrowrowsto(&problem->nld, problem->nnonlinear+1, n, _state); + rgrowv(problem->nnonlinear+1, &problem->hl, _state); + rgrowv(problem->nnonlinear+1, &problem->hu, _state); + + /* + * Generate and compute value of the nonlinear constraint + */ + v = (double)(0); + problem->nlc.ptr.p_double[problem->nnonlinear] = hqrndnormal(rs, _state); + v = v+problem->nlc.ptr.p_double[problem->nnonlinear]; + hqrndnormalv(rs, n, &c, _state); + rcopyvr(n, &c, &problem->nlb, problem->nnonlinear, _state); + v = v+rdotvr(n, &c, &problem->xsol, 0, _state); + spdmatrixrndcond(n, 10.0, &q, _state); + vmul = nlquadratic*ae_fabs(hqrndnormal(rs, _state), _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, vmul, &q, i, _state); + } + rmatrixcopy(n, n, &q, 0, 0, &problem->nla, problem->nnonlinear*n, 0, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = v+0.5*problem->xsol.ptr.pp_double[0][i]*q.ptr.pp_double[i][j]*problem->xsol.ptr.pp_double[0][j]; + } + } + for(i=0; i<=n-1; i++) + { + problem->nld.ptr.pp_double[problem->nnonlinear][i] = nlquartic*ae_pow((double)(2), 0.33*hqrndnormal(rs, _state), _state); + v = v+problem->nld.ptr.pp_double[problem->nnonlinear][i]*ae_pow(problem->xsol.ptr.pp_double[0][i], (double)(4), _state); + } + ctype = hqrnduniformi(rs, 3, _state); + problem->hl.ptr.p_double[problem->nnonlinear] = rcase2(ctype==0||ctype==2, v-padinactive-ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_neginf, _state); + problem->hu.ptr.p_double[problem->nnonlinear] = rcase2(ctype==1||ctype==2, v+padinactive+ae_pow((double)(2), hqrndnormal(rs, _state), _state), _state->v_posinf, _state); + problem->nnonlinear = problem->nnonlinear+1; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Returns the size of the METAHEURISTIC-U1 collection + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +ae_int_t motfgetmetaheuristicu1size(ae_state *_state) +{ + ae_int_t result; + + + result = 11; + return result; +} + + +/************************************************************************* +Returns the size of the METAHEURISTIC-U2 collection + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +ae_int_t motfgetmetaheuristicu2size(ae_state *_state) +{ + ae_int_t result; + + + result = 10; + return result; +} + + +/************************************************************************* +Returns the size of the METAHEURISTIC-U3 collection + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +ae_int_t motfgetmetaheuristicu3size(ae_state *_state) +{ + ae_int_t result; + + + result = 4; + return result; +} + + +/************************************************************************* +Returns the size of the NLS-1 collection + + -- ALGLIB -- + Copyright 04.04.2023 by Bochkanov Sergey +*************************************************************************/ +ae_int_t motfgetnls1size(ae_state *_state) +{ + ae_int_t result; + + + result = 16; + return result; +} + + +/************************************************************************* +Returns the size of the NLS-2 collection + + -- ALGLIB -- + Copyright 04.04.2023 by Bochkanov Sergey +*************************************************************************/ +ae_int_t motfgetnls2size(ae_state *_state) +{ + ae_int_t result; + + + result = 1; + return result; +} + + +/************************************************************************* +Creates a single-objective test problem from the METAHEURISTIC-U1 collection + +INPUT PARAMETERS: + ProblemIdx - a value from [0,MOTFGetMetaheuristicU1Size) + IsRotated - if True, a random rotation is applied to variables + RS - RNG, used for random rotations + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreatemetaheuristicu1(ae_int_t problemidx, + ae_bool isrotated, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_bool processed; + ae_int_t i; + ae_int_t j; + + _multiobjectivetestfunction_clear(problem); + + + /* + * Set problem metrics + */ + problem->problemtype = 1; + problem->problemsubtype = problemidx; + problem->isrotated = isrotated; + problem->m = 1; + problem->nlinear = 0; + problem->nnonlinear = 0; + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + problem->ksol = 0; + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Handle various problems from the collection + */ + processed = ae_false; + if( problemidx==0 ) + { + + /* + * f_sp = sum(x^2) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==1 ) + { + + /* + * f_sch = sum(|x|) + prod(|x|) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-10), &problem->bndl, _state); + rsetallocv(problem->n, (double)(10), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==2 ) + { + + /* + * f_schDS + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==3 ) + { + + /* + * f_sch + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==4 ) + { + + /* + * f_ros + */ + problem->n = 3; + rsetallocv(problem->n, (double)(-30), &problem->bndl, _state); + rsetallocv(problem->n, (double)(30), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==5 ) + { + + /* + * f = |x|^2 / (1+|x|^2) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-30), &problem->bndl, _state); + rsetallocv(problem->n, (double)(30), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==6 ) + { + + /* + * f = |x| / (1+|x|) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-30), &problem->bndl, _state); + rsetallocv(problem->n, (double)(30), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==7 ) + { + + /* + * f = |x| + |x|^2 + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-30), &problem->bndl, _state); + rsetallocv(problem->n, (double)(30), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==8 ) + { + + /* + * f_sp = sum(I*x^2) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==9 ) + { + + /* + * f_sp = sum(I*|x|) + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==10 ) + { + + /* + * Brown function + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-1), &problem->bndl, _state); + rsetallocv(problem->n, (double)(4), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + ae_assert(processed, "MOTFCreateMetaheuristicU1: incorrect ProblemIdx", _state); + + /* + * Generate random rotation + */ + if( isrotated ) + { + hqrndnormalm(rs, problem->n, problem->n, &problem->rotq, _state); + for(i=0; i<=problem->n-1; i++) + { + rmulr(problem->n, (double)1/coalesce(ae_sqrt(rdotrr(problem->n, &problem->rotq, i, &problem->rotq, i, _state), _state), (double)(1), _state), &problem->rotq, i, _state); + for(j=i+1; j<=problem->n-1; j++) + { + raddrr(problem->n, -rdotrr(problem->n, &problem->rotq, i, &problem->rotq, j, _state), &problem->rotq, i, &problem->rotq, j, _state); + } + } + } +} + + +/************************************************************************* +Creates a single-objective test problem from the METAHEURISTIC-U2 collection + +INPUT PARAMETERS: + ProblemIdx - a value from [0,MOTFGetMetaheuristicU2Size) + IsRotated - if True, a random rotation is applied to variables + RS - RNG, used for random rotations + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreatemetaheuristicu2(ae_int_t problemidx, + ae_bool isrotated, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_bool processed; + ae_int_t i; + ae_int_t j; + + _multiobjectivetestfunction_clear(problem); + + + /* + * Set problem metrics + */ + problem->isrotated = isrotated; + problem->problemtype = 2; + problem->problemsubtype = problemidx; + problem->m = 1; + problem->nlinear = 0; + problem->nnonlinear = 0; + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + problem->ksol = 0; + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Handle various problems from the collection + */ + processed = ae_false; + if( problemidx==0 ) + { + + /* + * Rastrigin: f = sum( x_i^2 - 10*cos(2pi*x_i)+10 ) + */ + problem->n = 30; + rsetallocv(problem->n, -5.12, &problem->bndl, _state); + rsetallocv(problem->n, 5.12, &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==1 ) + { + + /* + * Ackley function + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-32), &problem->bndl, _state); + rsetallocv(problem->n, (double)(32), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==2 ) + { + + /* + * Alphine 1 function + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-10), &problem->bndl, _state); + rsetallocv(problem->n, (double)(10), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==3 ) + { + + /* + * Csendes function + */ + problem->n = 50; + rsetallocv(problem->n, (double)(-1), &problem->bndl, _state); + rsetallocv(problem->n, (double)(1), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==4 ) + { + + /* + * Griewank function + */ + problem->n = 30; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==5 ) + { + + /* + * Brown function + */ + problem->n = 50; + rsetallocv(problem->n, (double)(-1), &problem->bndl, _state); + rsetallocv(problem->n, (double)(4), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==6 ) + { + + /* + * Pathological function + */ + problem->n = 4; + rsetallocv(problem->n, (double)(-100), &problem->bndl, _state); + rsetallocv(problem->n, (double)(100), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==7 ) + { + + /* + * Pinter function + */ + problem->n = 7; + rsetallocv(problem->n, (double)(-10), &problem->bndl, _state); + rsetallocv(problem->n, (double)(10), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==8 ) + { + + /* + * Streched V Sine Wave Function function + */ + problem->n = 3; + rsetallocv(problem->n, (double)(-10), &problem->bndl, _state); + rsetallocv(problem->n, (double)(10), &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==9 ) + { + + /* + * Wavy function + */ + problem->n = 20; + rsetallocv(problem->n, -ae_pi, &problem->bndl, _state); + rsetallocv(problem->n, ae_pi, &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + ae_assert(processed, "MOTFCreateMetaheuristicU2: incorrect ProblemIdx", _state); + + /* + * Generate random rotation + */ + if( isrotated ) + { + hqrndnormalm(rs, problem->n, problem->n, &problem->rotq, _state); + for(i=0; i<=problem->n-1; i++) + { + rmulr(problem->n, (double)1/coalesce(ae_sqrt(rdotrr(problem->n, &problem->rotq, i, &problem->rotq, i, _state), _state), (double)(1), _state), &problem->rotq, i, _state); + for(j=i+1; j<=problem->n-1; j++) + { + raddrr(problem->n, -rdotrr(problem->n, &problem->rotq, i, &problem->rotq, j, _state), &problem->rotq, i, &problem->rotq, j, _state); + } + } + } +} + + +/************************************************************************* +Creates a single-objective test problem from the METAHEURISTIC-U3 collection + +INPUT PARAMETERS: + ProblemIdx - a value from [0,MOTFGetMetaheuristicU3Size) + RS - RNG, ignored in the current version because + all problems are deterministic, but may be used + later + + -- ALGLIB -- + Copyright 04.03.2024 by Bochkanov Sergey +*************************************************************************/ +void motfcreatemetaheuristicu3(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_bool processed; + ae_int_t i; + + _multiobjectivetestfunction_clear(problem); + + + /* + * Set problem metrics + */ + problem->isrotated = ae_false; + problem->problemtype = 3; + problem->problemsubtype = problemidx; + problem->m = 1; + problem->nlinear = 0; + problem->nnonlinear = 0; + problem->ksol = 0; + problem->k0 = 0; + ae_matrix_set_length(&problem->x0, 0, 0, _state); + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Handle various problems from the collection + */ + processed = ae_false; + if( problemidx==0 ) + { + + /* + * Trigonometric 1 Function + */ + problem->n = 10; + rsetallocv(problem->n, (double)(0), &problem->bndl, _state); + rsetallocv(problem->n, ae_pi, &problem->bndu, _state); + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==1 ) + { + + /* + * Xin-She Yang (Function 2) + */ + problem->n = 2; + rsetallocv(problem->n, -(double)2*ae_pi, &problem->bndl, _state); + rsetallocv(problem->n, (double)2*ae_pi, &problem->bndu, _state); + for(i=0; i<=problem->n-1; i++) + { + problem->bndl.ptr.p_double[i] = problem->bndl.ptr.p_double[i]*(0.5+0.5*ae_sqr(ae_sin((double)(117+89*i), _state), _state)); + problem->bndu.ptr.p_double[i] = problem->bndu.ptr.p_double[i]*(0.5+0.5*ae_sqr(ae_sin((double)(653+83*i), _state), _state)); + } + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==2 ) + { + + /* + * Xin-She Yang (Function 4) + */ + problem->n = 2; + rsetallocv(problem->n, (double)(-10), &problem->bndl, _state); + rsetallocv(problem->n, (double)(10), &problem->bndu, _state); + for(i=0; i<=problem->n-1; i++) + { + problem->bndl.ptr.p_double[i] = problem->bndl.ptr.p_double[i]*(0.1+0.9*ae_sqr(ae_sin((double)(117+89*i), _state), _state)); + problem->bndu.ptr.p_double[i] = problem->bndu.ptr.p_double[i]*(0.1+0.9*ae_sqr(ae_sin((double)(653+83*i), _state), _state)); + } + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, -1.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==3 ) + { + + /* + * Big Rosenbrock + */ + problem->n = 5; + rsetallocv(problem->n, (double)(-30), &problem->bndl, _state); + rsetallocv(problem->n, (double)(30), &problem->bndu, _state); + for(i=0; i<=problem->n-1; i++) + { + problem->bndl.ptr.p_double[i] = problem->bndl.ptr.p_double[i]*(0.5+0.5*ae_sqr(ae_sin((double)(117+89*i), _state), _state)); + problem->bndu.ptr.p_double[i] = problem->bndu.ptr.p_double[i]*(0.5+0.5*ae_sqr(ae_sin((double)(653+83*i), _state), _state)); + } + problem->ksol = 1; + rsetallocm(1, problem->n, 0.0, &problem->xsol, _state); + rsetallocm(1, 1, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + ae_assert(processed, "MOTFCreateMetaheuristicU3: incorrect ProblemIdx", _state); +} + + +/************************************************************************* +Creates a nonlinear least squares test problem from the NLS1 collection. +Usually comes with initial points. + +INPUT PARAMETERS: + ProblemIdx - a value from [0,MOTFGetNLS1Size) + RS - RNG, ignored in the current version because + all problems are deterministic, but may be used + later + + -- ALGLIB -- + Copyright 04.04.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreatenls1(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_bool processed; + + _multiobjectivetestfunction_clear(problem); + + + /* + * Set problem metrics + */ + problem->problemtype = 50; + problem->problemsubtype = problemidx; + problem->n = 0; + problem->m = 0; + problem->nlinear = 0; + problem->nnonlinear = 0; + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + problem->ksol = 0; + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Handle various problems from the collection + */ + processed = ae_false; + if( problemidx==0 ) + { + + /* + * NF1 + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + problem->ksol = 1; + rallocm(1, problem->n, &problem->xsol, _state); + problem->xsol.ptr.pp_double[0][0] = (double)(0); + problem->xsol.ptr.pp_double[0][1] = (double)(1); + rsetallocm(1, problem->m, 0.0, &problem->fsol, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==1 ) + { + + /* + * NF2 + */ + problem->n = 2; + problem->m = 4; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==2 ) + { + + /* + * NF3 + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + processed = ae_true; + } + if( problemidx==3 ) + { + + /* + * Brown badly scaled function + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rsetallocm(1, problem->n, 1.0, &problem->x0, _state); + problem->ksol = 1; + rallocm(1, problem->n, &problem->xsol, _state); + problem->xsol.ptr.pp_double[0][0] = 1.0E6; + problem->xsol.ptr.pp_double[0][1] = 2.0E-6; + rsetallocm(1, problem->m, 0.0, &problem->fsol, _state); + processed = ae_true; + } + if( problemidx==4 ) + { + + /* + * Mod Barbashin and Krasovskii function 1 + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(5); + problem->x0.ptr.pp_double[0][1] = (double)(-6); + problem->ksol = 1; + rallocm(1, problem->n, &problem->xsol, _state); + problem->xsol.ptr.pp_double[0][0] = (double)(0); + problem->xsol.ptr.pp_double[0][1] = (double)(0); + rsetallocm(1, problem->m, 0.0, &problem->fsol, _state); + processed = ae_true; + } + if( problemidx==5 ) + { + + /* + * Mod Barbashin and Krasovskii function 2 + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(5); + problem->x0.ptr.pp_double[0][1] = (double)(-6); + problem->ksol = 1; + rallocm(1, problem->n, &problem->xsol, _state); + problem->xsol.ptr.pp_double[0][0] = (double)(0); + problem->xsol.ptr.pp_double[0][1] = (double)(0); + rsetallocm(1, problem->m, 0.0, &problem->fsol, _state); + problem->fsol.ptr.pp_double[0][2] = (double)(1); + processed = ae_true; + } + if( problemidx==6 ) + { + + /* + * Mod Rosenbrock 3 + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = -1.2; + problem->x0.ptr.pp_double[0][1] = 1.0; + processed = ae_true; + } + if( problemidx==7 ) + { + + /* + * Beale function + */ + problem->n = 2; + problem->m = 3; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(-5); + problem->x0.ptr.pp_double[0][1] = (double)(-2); + problem->ksol = 1; + rallocm(1, problem->n, &problem->xsol, _state); + problem->xsol.ptr.pp_double[0][0] = (double)(3); + problem->xsol.ptr.pp_double[0][1] = 0.5; + rsetallocm(1, problem->m, 0.0, &problem->fsol, _state); + processed = ae_true; + } + if( problemidx==8 ) + { + + /* + * B3DF function + */ + problem->n = 3; + problem->m = 10; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(0); + problem->x0.ptr.pp_double[0][1] = (double)(10); + problem->x0.ptr.pp_double[0][2] = (double)(20); + processed = ae_true; + } + if( problemidx==9 ) + { + + /* + * GRDF function + */ + problem->n = 3; + problem->m = 10; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + problem->bndl.ptr.p_double[0] = 1.0E-5; + problem->bndl.ptr.p_double[1] = 1.0E-5; + problem->bndl.ptr.p_double[2] = 1.0E-1; + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(5); + problem->x0.ptr.pp_double[0][1] = 2.5; + problem->x0.ptr.pp_double[0][2] = 0.15; + processed = ae_true; + } + if( problemidx==10 ) + { + + /* + * BARD function + */ + problem->n = 3; + problem->m = 15; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rsetallocm(1, problem->n, 1.0, &problem->x0, _state); + processed = ae_true; + } + if( problemidx==11 ) + { + + /* + * Colville function + */ + problem->n = 4; + problem->m = 7; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + problem->bndl.ptr.p_double[1] = 1.0; + problem->bndl.ptr.p_double[3] = 1.0; + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(10); + problem->x0.ptr.pp_double[0][1] = (double)(10); + problem->x0.ptr.pp_double[0][2] = (double)(10); + problem->x0.ptr.pp_double[0][3] = (double)(10); + processed = ae_true; + } + if( problemidx==12 ) + { + + /* + * Hyperellipsoid function + */ + problem->n = 8; + problem->m = 9; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(-1); + problem->x0.ptr.pp_double[0][1] = (double)(2); + problem->x0.ptr.pp_double[0][2] = (double)(-3); + problem->x0.ptr.pp_double[0][3] = (double)(4); + problem->x0.ptr.pp_double[0][4] = (double)(-5); + problem->x0.ptr.pp_double[0][5] = (double)(6); + problem->x0.ptr.pp_double[0][6] = (double)(-7); + problem->x0.ptr.pp_double[0][7] = (double)(8); + processed = ae_true; + } + if( problemidx==13 ) + { + + /* + * Kowalik and Osborne Function + */ + problem->n = 4; + problem->m = 11; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = 0.25; + problem->x0.ptr.pp_double[0][1] = 0.39; + problem->x0.ptr.pp_double[0][2] = 0.415; + problem->x0.ptr.pp_double[0][3] = 0.39; + processed = ae_true; + } + if( problemidx==14 ) + { + + /* + * Biggs EXP6 Function + */ + problem->n = 6; + problem->m = 13; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(1); + problem->x0.ptr.pp_double[0][1] = (double)(2); + problem->x0.ptr.pp_double[0][2] = (double)(1); + problem->x0.ptr.pp_double[0][3] = (double)(1); + problem->x0.ptr.pp_double[0][4] = (double)(1); + problem->x0.ptr.pp_double[0][5] = (double)(1); + processed = ae_true; + } + if( problemidx==15 ) + { + + /* + * Highly ill-conditioned Rosenbrock + */ + problem->n = 2; + problem->m = 2; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = (double)(-1); + problem->x0.ptr.pp_double[0][1] = (double)(1); + processed = ae_true; + } + ae_assert(processed, "MOTFCreateNLS1: incorrect ProblemIdx", _state); +} + + +/************************************************************************* +Creates a nonlinear least squares test problem from the NLS2 collection. +Usually comes with initial points. + +INPUT PARAMETERS: + ProblemIdx - a value from [0,MOTFGetNLS1Size) + RS - RNG, ignored in the current version because + all problems are deterministic, but may be used + later + + -- ALGLIB -- + Copyright 04.04.2023 by Bochkanov Sergey +*************************************************************************/ +void motfcreatenls2(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state) +{ + ae_bool processed; + + _multiobjectivetestfunction_clear(problem); + + + /* + * Set problem metrics + */ + problem->problemtype = 51; + problem->problemsubtype = problemidx; + problem->n = 0; + problem->m = 0; + problem->nlinear = 0; + problem->nnonlinear = 0; + ae_matrix_set_length(&problem->x0, 0, 0, _state); + problem->k0 = 0; + problem->ksol = 0; + ae_matrix_set_length(&problem->xsol, 0, 0, _state); + ae_matrix_set_length(&problem->fsol, 0, 0, _state); + ae_vector_set_length(&problem->lagmultbc, 0, _state); + ae_vector_set_length(&problem->lagmultlc, 0, _state); + ae_vector_set_length(&problem->lagmultnlc, 0, _state); + + /* + * Handle various problems from the collection + */ + processed = ae_false; + if( problemidx==0 ) + { + + /* + * Meyer function + */ + problem->n = 3; + problem->m = 16; + rsetallocv(problem->n, _state->v_neginf, &problem->bndl, _state); + rsetallocv(problem->n, _state->v_posinf, &problem->bndu, _state); + rsetallocv(problem->n, 0.0, &problem->lagmultbc, _state); + problem->k0 = 1; + rallocm(1, problem->n, &problem->x0, _state); + problem->x0.ptr.pp_double[0][0] = 0.02; + problem->x0.ptr.pp_double[0][1] = (double)(4000); + problem->x0.ptr.pp_double[0][2] = (double)(250); + processed = ae_true; + } + ae_assert(processed, "MOTFCreateNLS2: incorrect ProblemIdx", _state); +} + + +/************************************************************************* +Evaluate multiobjective test problem and its nonlinear constraints. + +INPUT PARAMETERS: + Problem - problem structure + X - trial point + Fi - preallocated array for M objectives and + Problem.NNonLinear constraints + NeedFi - whether Fi is needed or not + Jac - preallocated Jacobian array + NeedJac - whether Jac is needed or not + + -- ALGLIB -- + Copyright 04.03.2023 by Bochkanov Sergey +*************************************************************************/ +void motfeval(const multiobjectivetestfunction* problem, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* fi, + ae_bool needfi, + /* Real */ ae_matrix* jac, + ae_bool needjac, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t n; + ae_int_t m; + ae_int_t dst; + ae_vector ax; + ae_vector y; + double vsum; + double vprod; + double v; + double ui; + double vi; + double wi; + double yi; + double ti; + double thetai; + double ai; + double bi; + double ci; + + ae_frame_make(_state, &_frame_block); + memset(&ax, 0, sizeof(ax)); + memset(&y, 0, sizeof(y)); + ae_vector_init(&ax, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_assert(((((problem->problemtype==0||problem->problemtype==1)||problem->problemtype==2)||problem->problemtype==3)||problem->problemtype==50)||problem->problemtype==51, "MOTFEval: unknown problem type", _state); + ae_assert(!needfi||fi->cnt>=problem->m+problem->nnonlinear, "MOTFEval: Fi is too short", _state); + ae_assert(!needjac||jac->rows>=problem->m+problem->nnonlinear, "MOTFEval: Jac is too short", _state); + ae_assert(!needjac||jac->cols>=problem->n, "MOTFEval: Jac is too short", _state); + n = problem->n; + m = problem->m; + + /* + * Problem type #0 + */ + if( problem->problemtype==0 ) + { + ae_assert(!problem->isrotated, "OPTSERV: integrity check 0009 failed", _state); + + /* + * Evaluate objectives + */ + for(k=0; k<=m-1; k++) + { + dst = k; + + /* + * Initial values (constant term) + */ + if( needfi ) + { + fi->ptr.p_double[dst] = problem->tgtc.ptr.p_double[k]; + } + if( needjac ) + { + rsetr(n, 0.0, jac, dst, _state); + } + + /* + * Linear term + */ + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+rdotvr(n, x, &problem->tgtb, k, _state); + } + if( needjac ) + { + raddrr(n, 1.0, &problem->tgtb, k, jac, dst, _state); + } + + /* + * Quadratic term + */ + rallocv(n, &ax, _state); + rmatrixgemv(n, n, 1.0, &problem->tgta, k*n, 0, 0, x, 0, 0.0, &ax, 0, _state); + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+0.5*rdotv(n, x, &ax, _state); + } + if( needjac ) + { + raddvr(n, 1.0, &ax, jac, dst, _state); + } + + /* + * Quartic term + */ + for(i=0; i<=n-1; i++) + { + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+problem->tgtd.ptr.pp_double[k][i]*ae_pow(x->ptr.p_double[i], (double)(4), _state); + } + if( needjac ) + { + jac->ptr.pp_double[dst][i] = jac->ptr.pp_double[dst][i]+problem->tgtd.ptr.pp_double[k][i]*(double)4*ae_pow(x->ptr.p_double[i], (double)(3), _state); + } + } + } + + /* + * Nonlinear constraints + */ + for(k=0; k<=problem->nnonlinear-1; k++) + { + dst = m+k; + + /* + * Initial values (constant term) + */ + if( needfi ) + { + fi->ptr.p_double[dst] = problem->nlc.ptr.p_double[k]; + } + if( needjac ) + { + rsetr(n, 0.0, jac, dst, _state); + } + + /* + * Linear term + */ + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+rdotvr(n, x, &problem->nlb, k, _state); + } + if( needjac ) + { + raddrr(n, 1.0, &problem->nlb, k, jac, dst, _state); + } + + /* + * Quadratic term + */ + rallocv(n, &ax, _state); + rmatrixgemv(n, n, 1.0, &problem->nla, k*n, 0, 0, x, 0, 0.0, &ax, 0, _state); + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+0.5*rdotv(n, x, &ax, _state); + } + if( needjac ) + { + raddvr(n, 1.0, &ax, jac, dst, _state); + } + + /* + * Quartic term + */ + for(i=0; i<=n-1; i++) + { + if( needfi ) + { + fi->ptr.p_double[dst] = fi->ptr.p_double[dst]+problem->nld.ptr.pp_double[k][i]*ae_pow(x->ptr.p_double[i], (double)(4), _state); + } + if( needjac ) + { + jac->ptr.pp_double[dst][i] = jac->ptr.pp_double[dst][i]+problem->nld.ptr.pp_double[k][i]*(double)4*ae_pow(x->ptr.p_double[i], (double)(3), _state); + } + } + } + + /* + * Done + */ + ae_frame_leave(_state); + return; + } + + /* + * METAHEURISTICS-U1 collection + */ + if( problem->problemtype==1 ) + { + ae_assert(!needjac, "OPTSERV: the METAHEURISTICS-U1 collection does not support Jacobians", _state); + if( !needfi ) + { + ae_frame_leave(_state); + return; + } + rallocv(problem->n, &y, _state); + if( problem->isrotated ) + { + rgemv(problem->n, problem->n, 1.0, &problem->rotq, 0, x, 0.0, &y, _state); + } + else + { + rcopyv(problem->n, x, &y, _state); + } + fi->ptr.p_double[0] = (double)(0); + if( problem->problemsubtype==0 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_sqr(y.ptr.p_double[i], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==1 ) + { + vsum = (double)(0); + vprod = (double)(1); + for(i=0; i<=problem->n-1; i++) + { + vsum = vsum+ae_fabs(y.ptr.p_double[i], _state); + vprod = vprod*ae_fabs(y.ptr.p_double[i], _state); + } + fi->ptr.p_double[0] = vsum+vprod; + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==2 ) + { + for(i=0; i<=problem->n-1; i++) + { + v = (double)(0); + for(j=0; j<=i; j++) + { + v = v+y.ptr.p_double[i]; + } + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_sqr(v, _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==3 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = ae_maxreal(fi->ptr.p_double[0], ae_fabs(y.ptr.p_double[i], _state), _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==4 ) + { + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+((double)100*ae_sqr(y.ptr.p_double[i+1]-y.ptr.p_double[i]*y.ptr.p_double[i], _state)+ae_sqr(y.ptr.p_double[i]-(double)1, _state)); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==5 ) + { + v = rdotv2(problem->n, &y, _state); + fi->ptr.p_double[0] = v/(v+(double)1); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==6 ) + { + v = ae_sqrt(rdotv2(problem->n, &y, _state), _state); + fi->ptr.p_double[0] = v/(v+(double)1); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==7 ) + { + v = rdotv2(problem->n, &y, _state); + fi->ptr.p_double[0] = v+ae_sqrt(v, _state); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==8 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+(double)(i+1)*ae_sqr(y.ptr.p_double[i], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==9 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+(double)(i+1)*ae_fabs(y.ptr.p_double[i], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==10 ) + { + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_pow(ae_sqr(y.ptr.p_double[i], _state), ae_sqr(y.ptr.p_double[i+1], _state)+(double)1, _state)+ae_pow(ae_sqr(y.ptr.p_double[i+1], _state), ae_sqr(y.ptr.p_double[i], _state)+(double)1, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 9909 failed", _state); + } + + /* + * METAHEURISTICS-U2 collection + */ + if( problem->problemtype==2 ) + { + ae_assert(!needjac, "OPTSERV: the METAHEURISTICS-U2 collection does not support Jacobians", _state); + if( !needfi ) + { + ae_frame_leave(_state); + return; + } + rallocv(problem->n, &y, _state); + if( problem->isrotated ) + { + rgemv(problem->n, problem->n, 1.0, &problem->rotq, 0, x, 0.0, &y, _state); + } + else + { + rcopyv(problem->n, x, &y, _state); + } + fi->ptr.p_double[0] = (double)(0); + if( problem->problemsubtype==0 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_sqr(y.ptr.p_double[i], _state)-(double)10*ae_cos((double)2*ae_pi*y.ptr.p_double[i], _state)+(double)10; + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==1 ) + { + v = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + v = v+ae_sqr(y.ptr.p_double[i], _state); + } + fi->ptr.p_double[0] = fi->ptr.p_double[0]-(double)20*ae_exp(-0.2*ae_sqrt(v/(double)problem->n, _state), _state); + v = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + v = v+ae_cos((double)2*ae_pi*y.ptr.p_double[i], _state); + } + fi->ptr.p_double[0] = fi->ptr.p_double[0]-ae_exp(v/(double)problem->n, _state); + fi->ptr.p_double[0] = fi->ptr.p_double[0]+(double)20+ae_exp((double)(1), _state); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==2 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_fabs(y.ptr.p_double[i]*(0.1+ae_sin(y.ptr.p_double[i], _state)), _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==3 ) + { + for(i=0; i<=problem->n-1; i++) + { + if( ae_fp_neq(y.ptr.p_double[i],(double)(0)) ) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_pow(y.ptr.p_double[i], (double)(6), _state)*((double)2+ae_sin((double)1/y.ptr.p_double[i], _state)); + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==4 ) + { + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_sqr(y.ptr.p_double[i], _state)/(double)4000; + } + v = (double)(1); + for(i=0; i<=problem->n-1; i++) + { + v = v*ae_cos(y.ptr.p_double[i]/ae_sqrt((double)(i+1), _state), _state); + } + fi->ptr.p_double[0] = fi->ptr.p_double[0]+((double)1-v); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==5 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_pow(ae_sqr(y.ptr.p_double[i], _state), ae_sqr(y.ptr.p_double[i+1], _state)+(double)1, _state)+ae_pow(ae_sqr(y.ptr.p_double[i+1], _state), ae_sqr(y.ptr.p_double[i], _state)+(double)1, _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==6 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+0.5+(ae_sqr(ae_sin(ae_sqrt((double)100*y.ptr.p_double[i]*y.ptr.p_double[i]+y.ptr.p_double[i+1]*y.ptr.p_double[i+1], _state), _state), _state)-0.5)/((double)1+0.001*ae_sqr(ae_sqr(y.ptr.p_double[i]-y.ptr.p_double[i+1], _state), _state)); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==7 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + ai = y.ptr.p_double[(i-1+problem->n)%problem->n]*ae_sin(y.ptr.p_double[i], _state)+ae_sin(y.ptr.p_double[(i+1)%problem->n], _state); + bi = ae_sqr(y.ptr.p_double[(i-1+problem->n)%problem->n], _state)-(double)2*y.ptr.p_double[i]+(double)3*y.ptr.p_double[(i+1)%problem->n]-ae_cos(y.ptr.p_double[i], _state)+(double)1; + fi->ptr.p_double[0] = fi->ptr.p_double[0]+(double)(i+1)*(ae_sqr(y.ptr.p_double[i], _state)+(double)20*ae_sqr(ae_sin(ai, _state), _state)+ae_log((double)1+(double)(i+1)*bi*bi, _state)); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==8 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+ae_pow(y.ptr.p_double[i+1]*y.ptr.p_double[i+1]+y.ptr.p_double[i]*y.ptr.p_double[i], 0.25, _state)*(ae_sqr(ae_sin((double)50*ae_pow(y.ptr.p_double[i+1]*y.ptr.p_double[i+1]+y.ptr.p_double[i]*y.ptr.p_double[i], 0.1, _state), _state), _state)+0.1); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==9 ) + { + fi->ptr.p_double[0] = (double)(1); + for(i=0; i<=problem->n-1; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]-ae_cos((double)10*y.ptr.p_double[i], _state)*ae_exp(-ae_sqr(y.ptr.p_double[i], _state)/(double)2, _state)/(double)problem->n; + } + ae_frame_leave(_state); + return; + } + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 9919 failed", _state); + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 9919 failed", _state); + } + + /* + * NLS1 collection + */ + if( problem->problemtype==50 ) + { + if( !needfi&&!needjac ) + { + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==0 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = x->ptr.p_double[1]-ae_cosh(x->ptr.p_double[0], _state); + fi->ptr.p_double[1] = x->ptr.p_double[1]-ae_cos(x->ptr.p_double[0], _state); + fi->ptr.p_double[2] = x->ptr.p_double[1]-ae_sqr(x->ptr.p_double[0], _state)-(double)1; + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = -ae_sinh(x->ptr.p_double[0], _state); + jac->ptr.pp_double[0][1] = (double)(1); + jac->ptr.pp_double[1][0] = ae_sin(x->ptr.p_double[0], _state); + jac->ptr.pp_double[1][1] = (double)(1); + jac->ptr.pp_double[2][0] = -(double)2*x->ptr.p_double[0]; + jac->ptr.pp_double[2][1] = (double)(1); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==1 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = x->ptr.p_double[1]-ae_cosh(x->ptr.p_double[0]+(double)1, _state)+(double)1; + fi->ptr.p_double[1] = x->ptr.p_double[1]-ae_sin(x->ptr.p_double[0], _state)-ae_cos(x->ptr.p_double[0], _state); + fi->ptr.p_double[2] = ae_sqr(x->ptr.p_double[1], _state)-x->ptr.p_double[0]+(double)1; + fi->ptr.p_double[3] = x->ptr.p_double[0]+(double)1; + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = -ae_sinh(x->ptr.p_double[0]+(double)1, _state); + jac->ptr.pp_double[0][1] = (double)(1); + jac->ptr.pp_double[1][0] = ae_sin(x->ptr.p_double[0], _state)-ae_cos(x->ptr.p_double[0], _state); + jac->ptr.pp_double[1][1] = (double)(1); + jac->ptr.pp_double[2][0] = (double)(-1); + jac->ptr.pp_double[2][1] = (double)2*x->ptr.p_double[1]; + jac->ptr.pp_double[3][0] = (double)(1); + jac->ptr.pp_double[3][1] = (double)(0); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==2 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = x->ptr.p_double[0]+1.5; + fi->ptr.p_double[1] = x->ptr.p_double[1]; + fi->ptr.p_double[2] = ae_sqrt((double)(10), _state)*(ae_sqr(x->ptr.p_double[0], _state)+ae_sqr(x->ptr.p_double[1], _state)-(double)1); + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = (double)(1); + jac->ptr.pp_double[0][1] = (double)(0); + jac->ptr.pp_double[1][0] = (double)(0); + jac->ptr.pp_double[1][1] = (double)(1); + jac->ptr.pp_double[2][0] = ae_sqrt((double)(10), _state)*(double)2*x->ptr.p_double[0]; + jac->ptr.pp_double[2][1] = ae_sqrt((double)(10), _state)*(double)2*x->ptr.p_double[1]; + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==3 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = x->ptr.p_double[0]-1.0E6; + fi->ptr.p_double[1] = x->ptr.p_double[1]-2.0E-6; + fi->ptr.p_double[2] = x->ptr.p_double[0]*x->ptr.p_double[1]-(double)2; + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = (double)(1); + jac->ptr.pp_double[0][1] = (double)(0); + jac->ptr.pp_double[1][0] = (double)(0); + jac->ptr.pp_double[1][1] = (double)(1); + jac->ptr.pp_double[2][0] = x->ptr.p_double[1]; + jac->ptr.pp_double[2][1] = x->ptr.p_double[0]; + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==4 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = (double)100*x->ptr.p_double[0]/ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state); + fi->ptr.p_double[1] = (double)10*x->ptr.p_double[1]; + fi->ptr.p_double[2] = ae_sinh(x->ptr.p_double[0], _state); + } + if( needjac ) + { + rsetm(3, 2, 0.0, jac, _state); + jac->ptr.pp_double[0][0] = ((double)100*ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state)-(double)100*x->ptr.p_double[0]*0.5/ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state))/((double)1+x->ptr.p_double[0]*x->ptr.p_double[0]); + jac->ptr.pp_double[1][1] = (double)(10); + jac->ptr.pp_double[2][0] = ae_cosh(x->ptr.p_double[0], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==5 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = (double)100*x->ptr.p_double[0]/ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state); + fi->ptr.p_double[1] = (double)10*x->ptr.p_double[1]; + fi->ptr.p_double[2] = ae_cosh(x->ptr.p_double[0], _state); + } + if( needjac ) + { + rsetm(3, 2, 0.0, jac, _state); + jac->ptr.pp_double[0][0] = ((double)100*ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state)-(double)100*x->ptr.p_double[0]*0.5/ae_sqrt((double)1+x->ptr.p_double[0]*x->ptr.p_double[0], _state))/((double)1+x->ptr.p_double[0]*x->ptr.p_double[0]); + jac->ptr.pp_double[1][1] = (double)(10); + jac->ptr.pp_double[2][0] = ae_sinh(x->ptr.p_double[0], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==6 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = (double)100*(x->ptr.p_double[1]-ae_sqr(x->ptr.p_double[0], _state)); + fi->ptr.p_double[1] = (double)10*(x->ptr.p_double[0]-(double)1); + fi->ptr.p_double[2] = ae_sqr(x->ptr.p_double[1]+(double)1, _state)-x->ptr.p_double[0]+(double)1; + } + if( needjac ) + { + rsetm(3, 2, 0.0, jac, _state); + jac->ptr.pp_double[0][0] = -(double)200*x->ptr.p_double[0]; + jac->ptr.pp_double[0][1] = (double)(100); + jac->ptr.pp_double[1][0] = (double)(10); + jac->ptr.pp_double[2][0] = (double)(-1); + jac->ptr.pp_double[2][1] = (double)2*(x->ptr.p_double[1]+(double)1); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==7 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = 1.5+x->ptr.p_double[0]*(x->ptr.p_double[1]-(double)1); + fi->ptr.p_double[1] = 2.25+x->ptr.p_double[0]*(x->ptr.p_double[1]*x->ptr.p_double[1]-(double)1); + fi->ptr.p_double[2] = 2.625+x->ptr.p_double[0]*(x->ptr.p_double[1]*x->ptr.p_double[1]*x->ptr.p_double[1]-(double)1); + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = x->ptr.p_double[1]-(double)1; + jac->ptr.pp_double[0][1] = x->ptr.p_double[0]; + jac->ptr.pp_double[1][0] = x->ptr.p_double[1]*x->ptr.p_double[1]-(double)1; + jac->ptr.pp_double[1][1] = x->ptr.p_double[0]*(double)2*x->ptr.p_double[1]; + jac->ptr.pp_double[2][0] = x->ptr.p_double[1]*x->ptr.p_double[1]*x->ptr.p_double[1]-(double)1; + jac->ptr.pp_double[2][1] = x->ptr.p_double[0]*(double)3*x->ptr.p_double[1]*x->ptr.p_double[1]; + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==8 ) + { + if( needfi ) + { + for(i=0; i<=9; i++) + { + v = 0.1*(double)(i+1); + fi->ptr.p_double[i] = ae_exp(-v*x->ptr.p_double[0], _state)-ae_exp(-v*x->ptr.p_double[1], _state)-x->ptr.p_double[2]*(ae_exp(-v, _state)-ae_exp(-(double)10*v, _state)); + } + } + if( needjac ) + { + for(i=0; i<=9; i++) + { + v = 0.1*(double)(i+1); + jac->ptr.pp_double[i][0] = ae_exp(-v*x->ptr.p_double[0], _state)*(-v); + jac->ptr.pp_double[i][1] = -ae_exp(-v*x->ptr.p_double[1], _state)*(-v); + jac->ptr.pp_double[i][2] = -(ae_exp(-v, _state)-ae_exp(-(double)10*v, _state)); + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==9 ) + { + if( needfi ) + { + for(i=0; i<=9; i++) + { + thetai = 0.01*(double)(i+1); + yi = (double)25+ae_pow(-(double)50*ae_log(thetai, _state), (double)2/(double)3, _state); + fi->ptr.p_double[i] = ae_exp(-ae_pow(ae_fabs(yi*(double)problem->m*(double)(i+1)*x->ptr.p_double[1], _state), x->ptr.p_double[2], _state)/x->ptr.p_double[0], _state)-thetai; + } + } + if( needjac ) + { + for(i=0; i<=9; i++) + { + thetai = 0.01*(double)(i+1); + yi = (double)25+ae_pow(-(double)50*ae_log(thetai, _state), (double)2/(double)3, _state); + wi = ae_fabs(yi*(double)problem->m*(double)(i+1), _state); + v = ae_exp(-ae_pow(wi*x->ptr.p_double[1], x->ptr.p_double[2], _state)/x->ptr.p_double[0], _state); + jac->ptr.pp_double[i][0] = v*ae_pow(wi*x->ptr.p_double[1], x->ptr.p_double[2], _state)/ae_sqr(x->ptr.p_double[0], _state); + jac->ptr.pp_double[i][1] = v*(-(double)1/x->ptr.p_double[0])*x->ptr.p_double[2]*ae_pow(wi*x->ptr.p_double[1], x->ptr.p_double[2]-(double)1, _state)*wi; + jac->ptr.pp_double[i][2] = v*(-(double)1/x->ptr.p_double[0])*ae_pow(wi*x->ptr.p_double[1], x->ptr.p_double[2], _state)*ae_log(wi*x->ptr.p_double[1], _state); + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==10 ) + { + for(i=0; i<=14; i++) + { + yi = (double)(0); + if( i==0 ) + { + yi = 0.14; + } + if( i==1 ) + { + yi = 0.18; + } + if( i==2 ) + { + yi = 0.22; + } + if( i==3 ) + { + yi = 0.25; + } + if( i==4 ) + { + yi = 0.29; + } + if( i==5 ) + { + yi = 0.32; + } + if( i==6 ) + { + yi = 0.35; + } + if( i==7 ) + { + yi = 0.39; + } + if( i==8 ) + { + yi = 0.37; + } + if( i==9 ) + { + yi = 0.58; + } + if( i==10 ) + { + yi = 0.73; + } + if( i==11 ) + { + yi = 0.96; + } + if( i==12 ) + { + yi = 1.34; + } + if( i==13 ) + { + yi = 2.10; + } + if( i==14 ) + { + yi = 4.39; + } + ui = (double)(i+1); + vi = (double)(15-i); + wi = ae_minreal(ui, vi, _state); + if( ae_fp_greater(vi*x->ptr.p_double[1]+wi*x->ptr.p_double[2],ae_minrealnumber) ) + { + if( needfi ) + { + fi->ptr.p_double[i] = yi-(x->ptr.p_double[0]+ui/(vi*x->ptr.p_double[1]+wi*x->ptr.p_double[2])); + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = (double)(-1); + jac->ptr.pp_double[i][1] = ui/ae_sqr(vi*x->ptr.p_double[1]+wi*x->ptr.p_double[2], _state)*vi; + jac->ptr.pp_double[i][2] = ui/ae_sqr(vi*x->ptr.p_double[1]+wi*x->ptr.p_double[2], _state)*wi; + } + } + else + { + if( needfi ) + { + fi->ptr.p_double[i] = yi-(x->ptr.p_double[0]+ui/ae_minrealnumber); + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = (double)(0); + jac->ptr.pp_double[i][1] = (double)(0); + jac->ptr.pp_double[i][2] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==11 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = (double)10*(ae_sqr(x->ptr.p_double[0], _state)-x->ptr.p_double[1]); + fi->ptr.p_double[1] = x->ptr.p_double[0]-(double)1; + fi->ptr.p_double[2] = x->ptr.p_double[2]-(double)1; + fi->ptr.p_double[3] = ae_sqrt((double)(90), _state)*(ae_sqr(x->ptr.p_double[2], _state)-x->ptr.p_double[3]); + fi->ptr.p_double[4] = ae_sqrt(10.1, _state)*(x->ptr.p_double[1]-(double)1); + fi->ptr.p_double[5] = ae_sqrt(10.1, _state)*(x->ptr.p_double[3]-(double)1); + fi->ptr.p_double[6] = ae_sqrt(19.8*(x->ptr.p_double[1]-(double)1)*(x->ptr.p_double[3]-(double)1)+ae_machineepsilon, _state); + } + if( needjac ) + { + rsetm(problem->m, problem->n, 0.0, jac, _state); + jac->ptr.pp_double[0][0] = (double)20*x->ptr.p_double[0]; + jac->ptr.pp_double[0][1] = (double)(-10); + jac->ptr.pp_double[1][0] = (double)(1); + jac->ptr.pp_double[2][2] = (double)(1); + jac->ptr.pp_double[3][2] = ae_sqrt((double)(90), _state)*(double)2*x->ptr.p_double[2]; + jac->ptr.pp_double[3][3] = -ae_sqrt((double)(90), _state); + jac->ptr.pp_double[4][1] = ae_sqrt(10.1, _state); + jac->ptr.pp_double[5][3] = ae_sqrt(10.1, _state); + jac->ptr.pp_double[6][1] = 0.5/ae_sqrt(19.8*(x->ptr.p_double[1]-(double)1)*(x->ptr.p_double[3]-(double)1)+ae_machineepsilon, _state)*19.8*(x->ptr.p_double[3]-(double)1); + jac->ptr.pp_double[6][3] = 0.5/ae_sqrt(19.8*(x->ptr.p_double[1]-(double)1)*(x->ptr.p_double[3]-(double)1)+ae_machineepsilon, _state)*19.8*(x->ptr.p_double[1]-(double)1); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==12 ) + { + if( needjac ) + { + rsetm(problem->m, problem->n, 0.0, jac, _state); + } + for(i=0; i<=7; i++) + { + if( needfi ) + { + fi->ptr.p_double[i] = ae_sqrt((double)(2), _state)*ae_sqr(x->ptr.p_double[i], _state); + } + if( needjac ) + { + jac->ptr.pp_double[i][i] = (double)2*ae_sqrt((double)(2), _state)*x->ptr.p_double[i]; + } + } + if( needfi ) + { + fi->ptr.p_double[8] = (double)(0); + for(i=0; i<=8; i++) + { + fi->ptr.p_double[8] = fi->ptr.p_double[8]+ae_pow(2.2, (double)(i), _state); + } + fi->ptr.p_double[8] = ae_sqrt(fi->ptr.p_double[8], _state); + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==13 ) + { + for(i=0; i<=10; i++) + { + yi = (double)(0); + ti = (double)(0); + if( i==0 ) + { + yi = 0.1957; + ti = 4.0000; + } + if( i==1 ) + { + yi = 0.1947; + ti = 2.0000; + } + if( i==2 ) + { + yi = 0.1735; + ti = 1.0000; + } + if( i==3 ) + { + yi = 0.1600; + ti = 0.5000; + } + if( i==4 ) + { + yi = 0.0844; + ti = 0.2500; + } + if( i==5 ) + { + yi = 0.0627; + ti = 0.1670; + } + if( i==6 ) + { + yi = 0.0456; + ti = 0.1250; + } + if( i==7 ) + { + yi = 0.0342; + ti = 0.1000; + } + if( i==8 ) + { + yi = 0.0323; + ti = 0.0833; + } + if( i==9 ) + { + yi = 0.0235; + ti = 0.0714; + } + if( i==10 ) + { + yi = 0.0246; + ti = 0.0625; + } + if( ae_fp_greater(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3],1.0E-20) ) + { + if( needfi ) + { + fi->ptr.p_double[i] = yi-x->ptr.p_double[0]*(ti*ti+ti*x->ptr.p_double[1])/(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3]); + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = -(ti*ti+ti*x->ptr.p_double[1])/(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3]); + jac->ptr.pp_double[i][1] = -x->ptr.p_double[0]*ti/(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3]); + jac->ptr.pp_double[i][2] = (ti*ti+ti*x->ptr.p_double[1])/ae_sqr(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3], _state)*ti; + jac->ptr.pp_double[i][3] = (ti*ti+ti*x->ptr.p_double[1])/ae_sqr(ti*ti+ti*x->ptr.p_double[2]+x->ptr.p_double[3], _state); + } + } + else + { + if( needfi ) + { + fi->ptr.p_double[i] = ae_sqrt(ae_maxrealnumber, _state); + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = (double)(0); + jac->ptr.pp_double[i][1] = (double)(0); + jac->ptr.pp_double[i][2] = (double)(0); + jac->ptr.pp_double[i][3] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==14 ) + { + for(i=0; i<=12; i++) + { + ti = 0.1*(double)(i+1); + yi = ae_exp(-ti, _state)-(double)5*ae_exp(-(double)10*ti, _state)+(double)3*ae_exp(-(double)4*ti, _state); + if( needfi ) + { + fi->ptr.p_double[i] = x->ptr.p_double[2]*ae_exp(-ti*x->ptr.p_double[0], _state)-x->ptr.p_double[3]*ae_exp(-ti*x->ptr.p_double[1], _state)+x->ptr.p_double[5]*ae_exp(-ti*x->ptr.p_double[4], _state)-yi; + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = x->ptr.p_double[2]*ae_exp(-ti*x->ptr.p_double[0], _state)*(-ti); + jac->ptr.pp_double[i][1] = -x->ptr.p_double[3]*ae_exp(-ti*x->ptr.p_double[1], _state)*(-ti); + jac->ptr.pp_double[i][2] = ae_exp(-ti*x->ptr.p_double[0], _state); + jac->ptr.pp_double[i][3] = -ae_exp(-ti*x->ptr.p_double[1], _state); + jac->ptr.pp_double[i][4] = x->ptr.p_double[5]*ae_exp(-ti*x->ptr.p_double[4], _state)*(-ti); + jac->ptr.pp_double[i][5] = ae_exp(-ti*x->ptr.p_double[4], _state); + } + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==15 ) + { + if( needfi ) + { + fi->ptr.p_double[0] = (double)1-x->ptr.p_double[0]; + fi->ptr.p_double[1] = (double)1000*(x->ptr.p_double[1]-ae_sqr(x->ptr.p_double[0], _state)); + } + if( needjac ) + { + jac->ptr.pp_double[0][0] = (double)(-1); + jac->ptr.pp_double[0][1] = (double)(0); + jac->ptr.pp_double[1][0] = -(double)2000*x->ptr.p_double[0]; + jac->ptr.pp_double[1][1] = (double)(1000); + } + ae_frame_leave(_state); + return; + } + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 9919 failed", _state); + } + + /* + * NLS1 collection + */ + if( problem->problemtype==51 ) + { + if( !needfi&&!needjac ) + { + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==0 ) + { + for(i=0; i<=15; i++) + { + yi = (double)(0); + if( i==0 ) + { + yi = (double)(34780); + } + if( i==1 ) + { + yi = (double)(28610); + } + if( i==2 ) + { + yi = (double)(23650); + } + if( i==3 ) + { + yi = (double)(19630); + } + if( i==4 ) + { + yi = (double)(16370); + } + if( i==5 ) + { + yi = (double)(13720); + } + if( i==6 ) + { + yi = (double)(11540); + } + if( i==7 ) + { + yi = (double)(9744); + } + if( i==8 ) + { + yi = (double)(8261); + } + if( i==9 ) + { + yi = (double)(7030); + } + if( i==10 ) + { + yi = (double)(6005); + } + if( i==11 ) + { + yi = (double)(5147); + } + if( i==12 ) + { + yi = (double)(4427); + } + if( i==13 ) + { + yi = (double)(3820); + } + if( i==14 ) + { + yi = (double)(3307); + } + if( i==15 ) + { + yi = (double)(2872); + } + thetai = (double)(45+5*(i+1)); + if( ae_fp_greater(thetai+x->ptr.p_double[2],(double)(0))&&ae_fp_less(x->ptr.p_double[1]/(thetai+x->ptr.p_double[2]),ae_log(ae_maxrealnumber, _state)) ) + { + if( needfi ) + { + fi->ptr.p_double[i] = x->ptr.p_double[0]*ae_exp(x->ptr.p_double[1]/(thetai+x->ptr.p_double[2]), _state)-yi; + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = ae_exp(x->ptr.p_double[1]/(thetai+x->ptr.p_double[2]), _state); + jac->ptr.pp_double[i][1] = x->ptr.p_double[0]*ae_exp(x->ptr.p_double[1]/(thetai+x->ptr.p_double[2]), _state)/(thetai+x->ptr.p_double[2]); + jac->ptr.pp_double[i][2] = x->ptr.p_double[0]*ae_exp(x->ptr.p_double[1]/(thetai+x->ptr.p_double[2]), _state)*x->ptr.p_double[1]*(double)(-1)/ae_sqr(thetai+x->ptr.p_double[2], _state); + } + } + else + { + if( needfi ) + { + fi->ptr.p_double[i] = ae_sqrt(ae_maxrealnumber, _state); + } + if( needjac ) + { + jac->ptr.pp_double[i][0] = (double)(0); + jac->ptr.pp_double[i][1] = (double)(0); + jac->ptr.pp_double[i][2] = (double)(0); + } + } + } + ae_frame_leave(_state); + return; + } + } + + /* + * METAHEURISTICS-U3 collection + */ + if( problem->problemtype==3 ) + { + ae_assert(!problem->isrotated, "OPTSERV: integrity check 9609 failed", _state); + ae_assert(!needjac, "OPTSERV: the METAHEURISTICS-U3 collection does not support Jacobians", _state); + if( !needfi ) + { + ae_frame_leave(_state); + return; + } + fi->ptr.p_double[0] = (double)(0); + if( problem->problemsubtype==0 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + v = (double)(problem->n); + for(j=0; j<=problem->n-1; j++) + { + v = v-ae_cos(x->ptr.p_double[j], _state); + } + v = v+(double)(1+i)*((double)1-ae_cos(x->ptr.p_double[i], _state)-ae_sin(x->ptr.p_double[i], _state)); + fi->ptr.p_double[0] = fi->ptr.p_double[0]+v*v; + } + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==1 ) + { + ai = (double)(0); + bi = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + ai = ai+ae_fabs(x->ptr.p_double[i], _state); + bi = bi+ae_sin(x->ptr.p_double[i]*x->ptr.p_double[i], _state); + } + fi->ptr.p_double[0] = ai*ae_exp(-bi, _state); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==2 ) + { + ai = (double)(0); + bi = (double)(0); + ci = (double)(0); + for(i=0; i<=problem->n-1; i++) + { + ai = ai+ae_sqr(ae_sin(x->ptr.p_double[i], _state), _state); + bi = bi+x->ptr.p_double[i]*x->ptr.p_double[i]; + ci = ci+ae_sqr(ae_sin(ae_sqrt(ae_fabs(x->ptr.p_double[i], _state), _state), _state), _state); + } + fi->ptr.p_double[0] = (ai-ae_exp(-bi, _state))*ae_exp(-ci, _state); + ae_frame_leave(_state); + return; + } + if( problem->problemsubtype==3 ) + { + fi->ptr.p_double[0] = (double)(0); + for(i=0; i<=problem->n-2; i++) + { + fi->ptr.p_double[0] = fi->ptr.p_double[0]+((double)100*ae_sqr(x->ptr.p_double[i+1]-x->ptr.p_double[i]*x->ptr.p_double[i], _state)+ae_sqr(x->ptr.p_double[i]-(double)1, _state)); + } + ae_frame_leave(_state); + return; + } + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 1559 failed", _state); + } + + /* + * Error + */ + ae_assert(ae_false, "OPTSERV: integrity check 4407 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Converts modern two-sided mixed sparse/dense linear constraints to an old +dense single-sided format. + +NOTE: this function ignores inconsistent bounds, like CL>CU, assuming that + either they were already noticed, or will be noticed later. +*************************************************************************/ +void converttwosidedlctoonesidedold(const sparsematrix* sparsec, + ae_int_t ksparse, + /* Real */ const ae_matrix* densec, + ae_int_t kdense, + ae_int_t n, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + /* Real */ ae_matrix* olddensec, + /* Integer */ ae_vector* olddensect, + ae_int_t* olddensek, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t idxout; + + + + /* + * Compute required amount of single-sided constraints + */ + *olddensek = 0; + for(i=0; i<=ksparse+kdense-1; i++) + { + ae_assert(ae_isfinite(cl->ptr.p_double[i], _state)||ae_isneginf(cl->ptr.p_double[i], _state), "OPTSERV: integrity check 7117 failed", _state); + ae_assert(ae_isfinite(cu->ptr.p_double[i], _state)||ae_isposinf(cu->ptr.p_double[i], _state), "OPTSERV: integrity check 7118 failed", _state); + if( (ae_isfinite(cl->ptr.p_double[i], _state)&&ae_isfinite(cu->ptr.p_double[i], _state))&&ae_fp_eq(cl->ptr.p_double[i],cu->ptr.p_double[i]) ) + { + *olddensek = *olddensek+1; + continue; + } + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + *olddensek = *olddensek+1; + } + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + *olddensek = *olddensek+1; + } + } + if( *olddensek==0 ) + { + return; + } + + /* + * Convert two-sided constraints into single-sided + */ + idxout = 0; + rallocm(*olddensek, n+1, olddensec, _state); + iallocv(*olddensek, olddensect, _state); + for(i=0; i<=ksparse+kdense-1; i++) + { + + /* + * Ignore non-binding rows + */ + if( !ae_isfinite(cl->ptr.p_double[i], _state)&&!ae_isfinite(cu->ptr.p_double[i], _state) ) + { + continue; + } + + /* + * Extract row + */ + ae_assert(idxout<(*olddensek), "OPTSERV: integrity check 0324 failed", _state); + if( iridx.ptr.p_int[i]; + k1 = sparsec->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + olddensec->ptr.pp_double[idxout][sparsec->idx.ptr.p_int[k]] = sparsec->vals.ptr.p_double[k]; + } + } + else + { + + /* + * Copy from the dense matrix + */ + rcopyrr(n, densec, i-ksparse, olddensec, idxout, _state); + } + + /* + * Two bounds are present + */ + if( ae_isfinite(cl->ptr.p_double[i], _state)&&ae_isfinite(cu->ptr.p_double[i], _state) ) + { + if( ae_fp_eq(cl->ptr.p_double[i],cu->ptr.p_double[i]) ) + { + + /* + * Two bounds = equality constraints, one row is output + */ + olddensect->ptr.p_int[idxout] = 0; + olddensec->ptr.pp_double[idxout][n] = cl->ptr.p_double[i]; + idxout = idxout+1; + continue; + } + else + { + + /* + * Two bounds = range constraint, two rows are output + */ + rcopyrr(n, olddensec, idxout, olddensec, idxout+1, _state); + olddensect->ptr.p_int[idxout+0] = 1; + olddensect->ptr.p_int[idxout+1] = -1; + olddensec->ptr.pp_double[idxout+0][n] = cl->ptr.p_double[i]; + olddensec->ptr.pp_double[idxout+1][n] = cu->ptr.p_double[i]; + idxout = idxout+2; + continue; + } + } + + /* + * Only one bound is present + */ + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + olddensect->ptr.p_int[idxout] = 1; + olddensec->ptr.pp_double[idxout][n] = cl->ptr.p_double[i]; + idxout = idxout+1; + continue; + } + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + olddensect->ptr.p_int[idxout] = -1; + olddensec->ptr.pp_double[idxout][n] = cu->ptr.p_double[i]; + idxout = idxout+1; + continue; + } + ae_assert(ae_false, "OPTSERV: integrity check 7025 failed", _state); + } + ae_assert(idxout==(*olddensek), "OPTSERV: integrity check 0214 failed", _state); +} + + +/************************************************************************* +Prepares conversion of the modern two-sided nonlinear constraints to an old +single-sided zero-bounded format. + +NOTE: this function ignores inconsistent bounds, like NL>NU, assuming that + either they were already noticed, or will be noticed later. +*************************************************************************/ +void converttwosidednlctoonesidedold(/* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + /* Integer */ ae_vector* nlcidx, + /* Real */ ae_vector* nlcmul, + /* Real */ ae_vector* nlcadd, + ae_int_t* cntnlec, + ae_int_t* cntnlic, + ae_state *_state) +{ + ae_int_t i; + ae_int_t idxoutnlec; + ae_int_t idxoutnlic; + + + + /* + * Compute required amount of single-sided constraints + */ + *cntnlec = 0; + *cntnlic = 0; + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "OPTSERV: integrity check 0017 failed", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "OPTSERV: integrity check 0018 failed", _state); + if( (ae_isfinite(nl->ptr.p_double[i], _state)&&ae_isfinite(nu->ptr.p_double[i], _state))&&ae_fp_eq(nl->ptr.p_double[i],nu->ptr.p_double[i]) ) + { + *cntnlec = *cntnlec+1; + continue; + } + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + *cntnlic = *cntnlic+1; + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + *cntnlic = *cntnlic+1; + } + } + if( *cntnlec+(*cntnlic)==0 ) + { + return; + } + + /* + * Convert two-sided constraints into single-sided ones + */ + idxoutnlec = 0; + idxoutnlic = *cntnlec; + iallocv(*cntnlec+(*cntnlic), nlcidx, _state); + rallocv(*cntnlec+(*cntnlic), nlcmul, _state); + rallocv(*cntnlec+(*cntnlic), nlcadd, _state); + for(i=0; i<=nnlc-1; i++) + { + + /* + * Ignore non-binding rows + */ + if( !ae_isfinite(nl->ptr.p_double[i], _state)&&!ae_isfinite(nu->ptr.p_double[i], _state) ) + { + continue; + } + + /* + * + * Two bounds are present + */ + if( ae_isfinite(nl->ptr.p_double[i], _state)&&ae_isfinite(nu->ptr.p_double[i], _state) ) + { + if( ae_fp_eq(nl->ptr.p_double[i],nu->ptr.p_double[i]) ) + { + + /* + * Two bounds = equality constraints, one row is output + */ + nlcidx->ptr.p_int[idxoutnlec] = i; + nlcmul->ptr.p_double[idxoutnlec] = 1.0; + nlcadd->ptr.p_double[idxoutnlec] = -nl->ptr.p_double[i]; + idxoutnlec = idxoutnlec+1; + continue; + } + else + { + + /* + * Two bounds = range constraint, two rows are output + */ + nlcidx->ptr.p_int[idxoutnlic+0] = i; + nlcmul->ptr.p_double[idxoutnlic+0] = -1.0; + nlcadd->ptr.p_double[idxoutnlic+0] = nl->ptr.p_double[i]; + nlcidx->ptr.p_int[idxoutnlic+1] = i; + nlcmul->ptr.p_double[idxoutnlic+1] = 1.0; + nlcadd->ptr.p_double[idxoutnlic+1] = -nu->ptr.p_double[i]; + idxoutnlic = idxoutnlic+2; + continue; + } + } + + /* + * Only one bound is present + */ + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + nlcidx->ptr.p_int[idxoutnlic+0] = i; + nlcmul->ptr.p_double[idxoutnlic+0] = -1.0; + nlcadd->ptr.p_double[idxoutnlic+0] = nl->ptr.p_double[i]; + idxoutnlic = idxoutnlic+1; + continue; + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + nlcidx->ptr.p_int[idxoutnlic+0] = i; + nlcmul->ptr.p_double[idxoutnlic+0] = 1.0; + nlcadd->ptr.p_double[idxoutnlic+0] = -nu->ptr.p_double[i]; + idxoutnlic = idxoutnlic+1; + continue; + } + ae_assert(ae_false, "OPTSERV: integrity check 9041 failed", _state); + } + ae_assert(idxoutnlec==(*cntnlec), "OPTSERV: integrity check 9242 failed", _state); + ae_assert(idxoutnlic==*cntnlec+(*cntnlic), "OPTSERV: integrity check 9243 failed", _state); +} + + +/************************************************************************* +Increases trust region growth factor until maximum growth reached. +*************************************************************************/ +void trustradincreasemomentum(double* growthfactor, + double growthincrease, + double maxgrowthfactor, + ae_state *_state) +{ + + + *growthfactor = ae_minreal(*growthfactor*growthincrease, maxgrowthfactor, _state); +} + + +/************************************************************************* +Resets trust region growth factor to its default state. +*************************************************************************/ +void trustradresetmomentum(double* growthfactor, + double mingrowthfactor, + ae_state *_state) +{ + + + *growthfactor = mingrowthfactor; +} + + +/************************************************************************* +Initialize V-F-J structure by allocating uninitialized fields +*************************************************************************/ +void vfjallocdense(ae_int_t n, + ae_int_t m, + varsfuncjac* s, + ae_state *_state) +{ + + + ae_assert(n>=1, "vfjAllocDense: N<1", _state); + ae_assert(m>=1, "vfjAllocDense: M<1", _state); + s->n = n; + s->m = m; + s->isdense = ae_true; + rallocv(n, &s->x, _state); + rallocv(m, &s->fi, _state); + rallocm(m, n, &s->jac, _state); +} + + +/************************************************************************* +Initialize V-F-J structure by allocating uninitialized fields +*************************************************************************/ +void vfjallocsparse(ae_int_t n, + ae_int_t m, + varsfuncjac* s, + ae_state *_state) +{ + + + ae_assert(n>=1, "vfjAllocSparse: N<1", _state); + ae_assert(m>=1, "vfjAllocSparse: M<1", _state); + s->n = n; + s->m = m; + s->isdense = ae_false; + rallocv(n, &s->x, _state); + rallocv(m, &s->fi, _state); + s->sj.matrixtype = -1; + s->sj.m = -1; + s->sj.n = -1; +} + + +/************************************************************************* +Initialize V-F-J structure from user-supplied data +*************************************************************************/ +void vfjinitfromdense(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* fi, + ae_int_t m, + /* Real */ const ae_matrix* jac, + varsfuncjac* s, + ae_state *_state) +{ + + + ae_assert(n>=1, "vfjInitFromDense: N<1", _state); + ae_assert(m>=1, "vfjInitFromDense: M<1", _state); + s->n = n; + s->m = m; + s->isdense = ae_true; + rcopyallocv(n, x, &s->x, _state); + rcopyallocv(m, fi, &s->fi, _state); + rcopyallocm(m, n, jac, &s->jac, _state); +} + + +/************************************************************************* +Initialize V-F-J structure from user-supplied data +*************************************************************************/ +void vfjinitfromsparse(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* fi, + ae_int_t m, + const sparsematrix* jac, + varsfuncjac* s, + ae_state *_state) +{ + + + ae_assert(n>=1, "vfjInitFromSparse: N<1", _state); + ae_assert(m>=1, "vfjInitFromSparse: M<1", _state); + ae_assert(sparsegetnrows(jac, _state)==m, "vfjInitFromSparse: Jac has incorrect rows count", _state); + ae_assert(sparsegetncols(jac, _state)==n, "vfjInitFromSparse: Jac has incorrect cols count", _state); + s->n = n; + s->m = m; + s->isdense = ae_false; + rcopyallocv(n, x, &s->x, _state); + rcopyallocv(m, fi, &s->fi, _state); + sparsecopytocrsbuf(jac, &s->sj, _state); +} + + +/************************************************************************* +Copy V-F-J structure +*************************************************************************/ +void vfjcopy(const varsfuncjac* src, varsfuncjac* dst, ae_state *_state) +{ + + + dst->n = src->n; + dst->m = src->m; + dst->isdense = src->isdense; + rcopyallocv(src->n, &src->x, &dst->x, _state); + rcopyallocv(src->m, &src->fi, &dst->fi, _state); + if( src->isdense ) + { + rcopyallocm(src->m, src->n, &src->jac, &dst->jac, _state); + } + else + { + sparsecopybuf(&src->sj, &dst->sj, _state); + } +} + + +/************************************************************************* +Initialize criteria with default settings +*************************************************************************/ +void critinitdefault(nlpstoppingcriteria* crit, ae_state *_state) +{ + + + crit->epsf = (double)(0); + crit->eps = (double)(0); + crit->maxits = 0; +} + + +/************************************************************************* +Copy criteria +*************************************************************************/ +void critcopy(const nlpstoppingcriteria* src, + nlpstoppingcriteria* dst, + ae_state *_state) +{ + + + dst->epsf = src->epsf; + dst->eps = src->eps; + dst->maxits = src->maxits; +} + + +/************************************************************************* +Overwrites stopping CONDITIONS (not TOLERANCES) by values passed by the +user. + +Future versions of the structure may introduce additional conditions, these +condifitons will be set to zero by this version-1 function. +*************************************************************************/ +void critsetcondv1(nlpstoppingcriteria* crit, + double epsf, + double eps, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state)&&ae_fp_greater_eq(epsf,(double)(0)), "critSetCondV1: EpsF is infinite or negative", _state); + ae_assert(ae_isfinite(eps, _state)&&ae_fp_greater_eq(eps,(double)(0)), "critSetCondV1: Eps is infinite or negative", _state); + ae_assert(maxits>=0, "critSetCondV1: MaxIts is negative", _state); + crit->epsf = epsf; + crit->eps = eps; + crit->maxits = maxits; +} + + +/************************************************************************* +Returns the value of the EpsF stopping condition: +* if user specified nonzero value, it will be returned +* if user specified zero value of EpsF, but non-zero value for any other + condition or tolerance, zero will be returned +* if user specified zero value of EpsF and zero values for all other + conditions and tolerances, a default value will be returned +*************************************************************************/ +double critgetepsf(const nlpstoppingcriteria* crit, ae_state *_state) +{ + double result; + + + if( rmax3(crit->epsf, crit->eps, (double)(crit->maxits), _state)==0.0 ) + { + result = 1.0E-8; + } + else + { + result = crit->epsf; + } + return result; +} + + +/************************************************************************* +Returns the value of the EpsX stopping condition: +* if user specified nonzero value, it will be returned +* if user specified zero value of EpsX, but non-zero value for any other + condition or tolerance, zero will be returned +* if user specified zero value of EpsX and zero values for all other + conditions and tolerances, a default value will be returned +*************************************************************************/ +double critgeteps(const nlpstoppingcriteria* crit, ae_state *_state) +{ + double result; + + + result = critgetepswithdefault(crit, 1.0E-7, _state); + return result; +} + + +/************************************************************************* +Returns the value of the EpsX stopping condition: +* if user specified nonzero value, it will be returned +* if user specified zero value of EpsX, but non-zero value for any other + condition or tolerance, zero will be returned +* if user specified zero value of EpsX and zero values for all other + conditions and tolerances, a default value will be returned +*************************************************************************/ +double critgetepswithdefault(const nlpstoppingcriteria* crit, + double defval, + ae_state *_state) +{ + double result; + + + if( rmax3(crit->epsf, crit->eps, (double)(crit->maxits), _state)==0.0 ) + { + result = defval; + } + else + { + result = crit->eps; + } + return result; +} + + +/************************************************************************* +Returns the value of the MaxIts stopping condition: +* the value specified by the user (either zero or nonzero) will be returned +*************************************************************************/ +ae_int_t critgetmaxits(const nlpstoppingcriteria* crit, ae_state *_state) +{ + ae_int_t result; + + + result = crit->maxits; + return result; +} + + +/************************************************************************* +Initializes line search using bisection + +NOTES: +* MaxIts>=2 is required +*************************************************************************/ +void linesearchinitbisect(double f0, + double g0, + double alpha1, + double alphamax, + double c1, + double c2, + ae_bool strongwolfecond, + ae_int_t maxits, + ae_bool dotrace, + ae_int_t tracelevel, + linesearchstate* state, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(f0, _state), "OPTSERV: integrity check 9420 failed", _state); + ae_assert(ae_isfinite(g0, _state), "OPTSERV: integrity check 9421 failed", _state); + ae_assert(ae_isfinite(alpha1, _state), "OPTSERV: integrity check 9422 failed", _state); + ae_assert(ae_isfinite(alphamax, _state), "OPTSERV: integrity check 9422A failed", _state); + ae_assert(ae_fp_greater(alpha1,(double)(0)), "OPTSERV: integrity check 9423 failed", _state); + ae_assert(ae_fp_greater_eq(alphamax,alpha1), "OPTSERV: integrity check 9423A failed", _state); + ae_assert(maxits>=2, "OPTSERV: integrity check 9424 failed", _state); + ae_assert(ae_isfinite(c1, _state), "OPTSERV: integrity check 9425 failed", _state); + ae_assert(ae_isfinite(c2, _state), "OPTSERV: integrity check 9426 failed", _state); + ae_assert(ae_fp_greater(c1,(double)(0))&&ae_fp_less(c1,(double)(1)), "OPTSERV: integrity check 9427 failed", _state); + ae_assert(ae_fp_greater(c2,(double)(0))&&ae_fp_less(c2,(double)(1)), "OPTSERV: integrity check 9428 failed", _state); + state->f0 = f0; + state->g0 = g0; + state->alpha1 = alpha1; + state->alphamax = alphamax; + state->c1 = c1; + state->c2 = c2; + state->strongwolfecond = strongwolfecond; + state->maxits = maxits; + state->dotrace = dotrace; + state->tracelevel = tracelevel; + state->rstate.stage = -1; +} + + +/************************************************************************* +Performs iteration. + +After the end it stores the best step to State.AlphaSol. The function +warrants that either: +* AlphaSol is the last Alpha tried +* AlphaSol=0, which means that a non-descent direction was specified. + In the latter case no search was performed. + +The function also sets TerminationType field to a value which roughly +corresponds to ones returned by MCSRCH: +* 0 for non-descent direction +* 1 for search ended with the sufficient decrease condition and the + curvature condition satisfied +* 3 for iteration budget being exhausted, stopping at the best point so far +* 5 for a step being at the upper bound +*************************************************************************/ +ae_bool linesearchiteration(linesearchstate* state, ae_state *_state) +{ + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + } + else + { + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + + /* + * Routine body + */ + + /* + * Initial checks + */ + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" starting line search\n"); + } + if( ae_fp_greater_eq(state->g0,(double)(0)) ) + { + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" directional derivative non-negative (%0.2e), stopping\n", + (double)(state->g0)); + } + state->alphasol = 0.0; + state->terminationtype = 0; + result = ae_false; + return result; + } + state->nfev = 0; + + /* + * Phase 1: bracket step + */ + state->fprev = state->f0; + state->gprev = state->g0; + state->alphaprev = (double)(0); + state->alphacur = state->alpha1; + state->bestalphasofar = (double)(0); + state->bestfsofar = state->f0; +lbl_5: + if( ae_false ) + { + goto lbl_6; + } + + /* + * RComm + */ + state->alphatrial = state->alphacur; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->fcur = state->ftrial; + state->gcur = state->gtrial; + state->nfev = state->nfev+1; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" target evaluated at stp=%0.3e, deltaF=%0.3e, dg=%0.3e\n", + (double)(state->alphacur), + (double)(state->fcur-state->f0), + (double)(state->gcur)); + } + + /* + * Update best point so far + * + * NOTE: strict inequality is essential + */ + if( ae_fp_eq(state->bestalphasofar,(double)(0))||ae_fp_less(state->fcur,state->bestfsofar) ) + { + state->bestalphasofar = state->alphacur; + state->bestfsofar = state->fcur; + } + + /* + * Tests + */ + if( state->nfevmaxits-1 ) + { + goto lbl_7; + } + + /* + * Function budget is almost exhausted. We may have to terminate before exhausting it completely + * in order to be able to evaluate the target at the last point known. + */ + ae_assert(ae_fp_greater(state->bestalphasofar,(double)(0)), "OPTSERV: integrity check 1224 failed", _state); + if( ae_fp_eq(state->alphacur,state->bestalphasofar) ) + { + goto lbl_9; + } + + /* + * Make one reverse communication request. + * + * We do not use its results, it is here merely for caller to evaluate the target at the point where we stopped + */ + state->alphatrial = state->bestalphasofar; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->nfev = state->nfev+1; +lbl_9: + state->alphasol = state->bestalphasofar; + state->terminationtype = 3; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" iteration budget of %0d evaluations is used, stopping\n", + (int)(state->maxits)); + } + result = ae_false; + return result; +lbl_7: + if( ae_fp_less_eq(state->fcur,state->f0+state->c1*state->alphacur*state->g0)&&(ae_fp_less_eq(ae_fabs(state->gcur, _state),-state->c2*state->g0)||(!state->strongwolfecond&&ae_fp_greater_eq(state->gcur,state->c2*state->g0))) ) + { + + /* + * Found + */ + state->alphasol = state->alphacur; + state->terminationtype = 1; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" sufficient decrease and curvature conditions hold, stopping\n"); + } + result = ae_false; + return result; + } + if( ae_fp_greater_eq(state->fcur,state->f0+state->c1*state->alphacur*state->g0)||ae_fp_greater_eq(state->fcur,state->fprev) ) + { + + /* + * Bracketed by target value + */ + state->alphalo = state->alphaprev; + state->alphahi = state->alphacur; + state->flo = state->fprev; + state->fhi = state->fcur; + state->glo = state->gprev; + state->ghi = state->gcur; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" the minimum is bracketed by the target, stp=[%0.3e,%0.3e], proceeding to phase 2\n", + (double)(state->alphalo), + (double)(state->alphahi)); + } + goto lbl_6; + } + if( ae_fp_greater_eq(state->gcur,(double)(0)) ) + { + + /* + * Bracketed by gradient value + */ + state->alphahi = state->alphaprev; + state->alphalo = state->alphacur; + state->fhi = state->fprev; + state->flo = state->fcur; + state->ghi = state->gprev; + state->glo = state->gcur; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" the minimum is bracketed by the gradient, stp=[%0.3e,%0.3e], proceeding to phase 2\n", + (double)(state->alphahi), + (double)(state->alphalo)); + } + goto lbl_6; + } + if( !(ae_fp_greater_eq(state->alphacur,0.999*state->alphamax)||ae_fp_eq(state->alphacur,state->alphaprev)) ) + { + goto lbl_11; + } + + /* + * We reached upper bound on the step length (or the step stagnated due to numerical errors) + */ + ae_assert(ae_fp_greater(state->bestalphasofar,(double)(0)), "OPTSERV: integrity check 1224 failed", _state); + if( ae_fp_eq(state->alphacur,state->bestalphasofar) ) + { + goto lbl_13; + } + + /* + * Make one reverse communication request. + * + * We do not use its results, it is here merely for caller to evaluate the target at the point where we stopped + */ + state->alphatrial = state->bestalphasofar; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->nfev = state->nfev+1; +lbl_13: + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" reached an upper bound on the step length, stopping at the best point so far (stp=%0.3e)\n", + (double)(state->bestalphasofar)); + } + state->alphasol = state->bestalphasofar; + state->terminationtype = 5; + result = ae_false; + return result; +lbl_11: + + /* + * Next step + */ + state->fprev = state->fcur; + state->gprev = state->gcur; + state->alphaprev = state->alphacur; + state->alphacur = ae_minreal((double)2*state->alphacur, state->alphamax, _state); + goto lbl_5; +lbl_6: + + /* + * Phase 2: perform bisection on bracketed step + */ +lbl_15: + if( ae_false ) + { + goto lbl_16; + } + + /* + * Compute AlphaTrial and evaluate target + */ + state->alphacur = 0.5*(state->alphalo+state->alphahi); + state->alphatrial = state->alphacur; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->fcur = state->ftrial; + state->gcur = state->gtrial; + state->nfev = state->nfev+1; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" target evaluated at stp=%0.3e, deltaF=%0.3e, dg=%0.3e, interval of uncertainty is [%0.3e,%0.3e]\n", + (double)(state->alphacur), + (double)(state->fcur-state->f0), + (double)(state->gcur), + (double)(ae_minreal(state->alphalo, state->alphahi, _state)), + (double)(ae_maxreal(state->alphalo, state->alphahi, _state))); + } + + /* + * Update best point so far + * + * NOTE: strict inequality is essential + */ + ae_assert(ae_fp_neq(state->bestalphasofar,(double)(0)), "OPTSERV: integrity check 1130 failed", _state); + if( ae_fp_less(state->fcur,state->bestfsofar) ) + { + state->bestalphasofar = state->alphacur; + state->bestfsofar = state->fcur; + } + + /* + * Check iteration budget + */ + if( state->nfevmaxits-1 ) + { + goto lbl_17; + } + + /* + * Function budget is almost exhausted. We may have to terminate before exhausting it completely + * in order to be able to evaluate the target at the last point known. + */ + ae_assert(ae_fp_greater(state->bestalphasofar,(double)(0)), "OPTSERV: integrity check 1224 failed", _state); + if( ae_fp_eq(state->alphacur,state->bestalphasofar) ) + { + goto lbl_19; + } + + /* + * Make one reverse communication request. + * + * We do not use its results, it is here merely for caller to evaluate the target at the point where we stopped + */ + state->alphatrial = state->bestalphasofar; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->nfev = state->nfev+1; +lbl_19: + state->alphasol = state->bestalphasofar; + state->terminationtype = 3; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" iteration budget of %0d evaluations is used, stopping\n", + (int)(state->maxits)); + } + result = ae_false; + return result; +lbl_17: + + /* + * Check stopping criteria + */ + if( ae_fp_less_eq(state->fcur,state->f0+state->c1*state->alphacur*state->g0)&&(ae_fp_less_eq(ae_fabs(state->gcur, _state),-state->c2*state->g0)||(!state->strongwolfecond&&ae_fp_greater_eq(state->gcur,state->c2*state->g0))) ) + { + + /* + * Found + */ + state->alphasol = state->alphacur; + state->terminationtype = 1; + if( state->dotrace ) + { + traceangles(state->tracelevel, _state); + ae_trace(" sufficient decrease and curvature conditions hold, stopping\n"); + } + result = ae_false; + return result; + } + + /* + * Analyze + */ + if( ae_fp_greater_eq(state->fcur,state->f0+state->c1*state->alphatrial*state->g0)||ae_fp_greater_eq(state->fcur,state->flo) ) + { + state->alphahi = state->alphacur; + state->fhi = state->fcur; + state->ghi = state->gcur; + } + else + { + if( ae_fp_greater_eq(state->gcur*(state->alphahi-state->alphalo),(double)(0)) ) + { + state->alphahi = state->alphalo; + state->fhi = state->flo; + state->ghi = state->glo; + } + state->alphalo = state->alphacur; + state->flo = state->fcur; + state->glo = state->gcur; + } + goto lbl_15; +lbl_16: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + return result; +} + + +/************************************************************************* +Create a filter for NLP solver +*************************************************************************/ +void nlpfinit(double maxh, nlpfilter* s, ae_state *_state) +{ + + + s->maxh = maxh; + s->filtersize = 0; + s->gammaf = 0.0; + s->gammah = 1.0; + s->maxdominating = 0; +} + + +/************************************************************************* +Copy filter +*************************************************************************/ +void nlpfinitfrom(const nlpfilter* src, nlpfilter* dst, ae_state *_state) +{ + + + dst->maxh = src->maxh; + dst->filtersize = src->filtersize; + dst->maxdominating = src->maxdominating; + dst->gammaf = src->gammaf; + dst->gammah = src->gammah; + dst->violationistoohigh = src->violationistoohigh; + rcopyallocv(dst->filtersize, &src->filterf, &dst->filterf, _state); + rcopyallocv(dst->filtersize, &src->filterh, &dst->filterh, _state); +} + + +/************************************************************************* +Create a filter for NLP solver with the possibility of points being accepted +when dominated by no more than MD>=0 ones. + +MD=0 corresponds to the traditional filter. +*************************************************************************/ +void nlpfinitx(double maxh, ae_int_t md, nlpfilter* s, ae_state *_state) +{ + + + ae_assert(md>=0, "nlpfInitX: MD<0", _state); + s->maxh = maxh; + s->filtersize = 0; + s->gammaf = 0.0; + s->gammah = 1.0; + s->maxdominating = md; +} + + +/************************************************************************* +Check point for acceptance. + +On failure sets S.ViolationIsTooHigh. +*************************************************************************/ +ae_bool nlpfisacceptable(nlpfilter* s, + double f0, + double h0, + double f1, + double h1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t dcnt; + ae_bool result; + + + if( h1>s->maxh ) + { + s->violationistoohigh = ae_true; + result = ae_false; + return result; + } + s->violationistoohigh = ae_false; + if( f1>=f0-s->gammaf*h0&&h1>=h0*s->gammah ) + { + result = ae_false; + return result; + } + dcnt = 0; + for(i=0; i<=s->filtersize-1; i++) + { + if( f1>=s->filterf.ptr.p_double[i]-s->gammaf*h1&&h1>=s->filterh.ptr.p_double[i]*s->gammah ) + { + dcnt = dcnt+1; + } + if( dcnt>s->maxdominating ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Check point for acceptance. + +On failure sets S.ViolationIsTooHigh. +*************************************************************************/ +ae_bool nlpfisacceptable1(nlpfilter* s, + double f, + double h, + ae_state *_state) +{ + ae_int_t i; + ae_int_t dcnt; + ae_bool result; + + + if( h>=s->maxh ) + { + s->violationistoohigh = ae_true; + result = ae_false; + return result; + } + s->violationistoohigh = ae_false; + dcnt = 0; + for(i=0; i<=s->filtersize-1; i++) + { + if( f>=s->filterf.ptr.p_double[i]-s->gammaf*h&&h>=s->filterh.ptr.p_double[i]*s->gammah ) + { + dcnt = dcnt+1; + } + if( dcnt>s->maxdominating ) + { + result = ae_false; + return result; + } + } + result = ae_true; + return result; +} + + +/************************************************************************* +Append point, if acceptable. Behavior is undefined for unacceptable points. +*************************************************************************/ +void nlpfappend(nlpfilter* s, double f, double h, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t dcnt; + ae_int_t newsize; + double fcand; + double hcand; + + + if( s->maxdominating==0 ) + { + + /* + * Quick O(FilterSize) code for the traditional filter + */ + i = 0; + while(ifiltersize) + { + if( f<=s->filterf.ptr.p_double[i]&&h<=s->filterh.ptr.p_double[i] ) + { + + /* + * The point being added dominates the I-th one, remove it + */ + s->filterf.ptr.p_double[i] = s->filterf.ptr.p_double[s->filtersize-1]; + s->filterh.ptr.p_double[i] = s->filterh.ptr.p_double[s->filtersize-1]; + s->filtersize = s->filtersize-1; + continue; + } + i = i+1; + } + rgrowv(s->filtersize+1, &s->filterf, _state); + rgrowv(s->filtersize+1, &s->filterh, _state); + s->filterf.ptr.p_double[s->filtersize] = f; + s->filterh.ptr.p_double[s->filtersize] = h; + s->filtersize = s->filtersize+1; + } + else + { + + /* + * Slower O(FilterSize^2) code for the D-dominating filter. + * + * First, insert new point to the beginning. This way we make sure + * that it is always retained, even under rounding errors. + */ + rgrowv(s->filtersize+1, &s->filterf, _state); + rgrowv(s->filtersize+1, &s->filterh, _state); + s->filterf.ptr.p_double[s->filtersize] = s->filterf.ptr.p_double[0]; + s->filterh.ptr.p_double[s->filtersize] = s->filterh.ptr.p_double[0]; + s->filterf.ptr.p_double[0] = f; + s->filterh.ptr.p_double[0] = h; + s->filtersize = s->filtersize+1; + + /* + * Then, for each point compute how many times it is dominated + */ + newsize = 1; + for(i=1; i<=s->filtersize-1; i++) + { + dcnt = 0; + fcand = s->filterf.ptr.p_double[i]; + hcand = s->filterh.ptr.p_double[i]; + for(j=0; j<=newsize-1; j++) + { + if( fcand>=s->filterf.ptr.p_double[j]&&hcand>=s->filterh.ptr.p_double[j] ) + { + dcnt = dcnt+1; + } + } + if( dcnt<=s->maxdominating ) + { + s->filterf.ptr.p_double[newsize] = fcand; + s->filterh.ptr.p_double[newsize] = hcand; + newsize = newsize+1; + } + } + + /* + * Done + */ + s->filtersize = newsize; + } +} + + +/************************************************************************* +Drop all points stored in the filter +*************************************************************************/ +void nlpfclear(nlpfilter* s, ae_state *_state) +{ + + + s->filtersize = 0; +} + + +/************************************************************************* +Updates maximum violation +*************************************************************************/ +void nlpfsetmaxh(nlpfilter* s, double maxh, ae_state *_state) +{ + + + s->maxh = maxh; +} + + +/************************************************************************* +Initialize linear constraints structure +*************************************************************************/ +void xlcinit(ae_int_t n, xlinearconstraints* state, ae_state *_state) +{ + + + ae_assert(n>=1, "xlcInit: N<1", _state); + state->n = n; + state->ndense = 0; + state->nsparse = 0; +} + + +/************************************************************************* +SINGLE-SIDED CONSTRANTS USING LEGACY FORMAT + +This function sets mixed linear constraints, which include a set of dense +rows, and a set of sparse rows. + +This function overrides results of previous constraint modifications. + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + SparseC - linear constraints, sparse matrix with dimensions EXACTLY + EQUAL TO [SparseK,N+1]. Each row of C represents one + constraint, either equality or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + SparseCT- type of sparse constraints, array[K]: + * if SparseCT[i]>0, then I-th constraint is SparseC[i,*]*x >= SparseC[i,n+1] + * if SparseCT[i]=0, then I-th constraint is SparseC[i,*]*x = SparseC[i,n+1] + * if SparseCT[i]<0, then I-th constraint is SparseC[i,*]*x <= SparseC[i,n+1] + SparseK - number of sparse equality/inequality constraints, K>=0 + DenseC - dense linear constraints, array[K,N+1]. + Each row of DenseC represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of DenseC (including right part) must be finite. + DenseCT - type of constraints, array[K]: + * if DenseCT[i]>0, then I-th constraint is DenseC[i,*]*x >= DenseC[i,n+1] + * if DenseCT[i]=0, then I-th constraint is DenseC[i,*]*x = DenseC[i,n+1] + * if DenseCT[i]<0, then I-th constraint is DenseC[i,*]*x <= DenseC[i,n+1] + DenseK - number of equality/inequality constraints, DenseK>=0 + + -- ALGLIB -- + Copyright 13.04.2024 by Bochkanov Sergey +*************************************************************************/ +void xlcsetlcmixed(xlinearconstraints* state, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + double v; + ae_vector srcidx; + ae_vector dstidx; + ae_vector s; + ae_vector rs; + ae_vector eoffs; + ae_vector roffs; + ae_vector v2; + ae_vector eidx; + ae_vector eval; + ae_int_t t0; + ae_int_t t1; + ae_int_t nnz; + + ae_frame_make(_state, &_frame_block); + memset(&srcidx, 0, sizeof(srcidx)); + memset(&dstidx, 0, sizeof(dstidx)); + memset(&s, 0, sizeof(s)); + memset(&rs, 0, sizeof(rs)); + memset(&eoffs, 0, sizeof(eoffs)); + memset(&roffs, 0, sizeof(roffs)); + memset(&v2, 0, sizeof(v2)); + memset(&eidx, 0, sizeof(eidx)); + memset(&eval, 0, sizeof(eval)); + ae_vector_init(&srcidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&dstidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&s, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rs, 0, DT_INT, _state, ae_true); + ae_vector_init(&eoffs, 0, DT_INT, _state, ae_true); + ae_vector_init(&roffs, 0, DT_INT, _state, ae_true); + ae_vector_init(&v2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&eidx, 0, DT_INT, _state, ae_true); + ae_vector_init(&eval, 0, DT_REAL, _state, ae_true); + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(densek>=0, "xlcSetLCMixed: K<0", _state); + ae_assert(densek==0||densec->cols>=n+1, "xlcSetLCMixed: Cols(C)rows>=densek, "xlcSetLCMixed: Rows(DenseC)cnt>=densek, "xlcSetLCMixed: Length(DenseCT)=0, "xlcSetLCMixed: SparseK<0", _state); + ae_assert(sparsek==0||sparsegetncols(sparsec, _state)>=n+1, "xlcSetLCMixed: Cols(SparseC)=sparsek, "xlcSetLCMixed: Rows(SparseC)cnt>=sparsek, "xlcSetLCMixed: Length(SparseCT)ndense = densek; + state->nsparse = sparsek; + if( sparsek>0 ) + { + rallocv(sparsek, &state->scl, _state); + rallocv(sparsek, &state->scu, _state); + + /* + * Evaluate row sizes for new storage + */ + ae_vector_set_length(&rs, sparsek, _state); + for(i=0; i<=sparsek-1; i++) + { + rs.ptr.p_int[i] = 0; + } + t0 = 0; + t1 = 0; + nnz = 0; + while(sparseenumerate(sparsec, &t0, &t1, &i, &j, &v, _state)) + { + if( i>sparsek-1||j>n-1 ) + { + continue; + } + ae_assert(ae_isfinite(v, _state), "xlcSetLCSparse: C contains infinite or NAN values", _state); + nnz = nnz+1; + rs.ptr.p_int[i] = rs.ptr.p_int[i]+1; + } + + /* + * Prepare new sparse CRS storage, copy leading SparseK*N submatrix into the storage + */ + for(i=0; i<=sparsek-1; i++) + { + state->scl.ptr.p_double[i] = (double)(0); + state->scu.ptr.p_double[i] = (double)(0); + } + state->sparsec.m = sparsek; + state->sparsec.n = n; + ivectorsetlengthatleast(&state->sparsec.ridx, sparsek+1, _state); + ivectorsetlengthatleast(&state->sparsec.idx, nnz, _state); + rvectorsetlengthatleast(&state->sparsec.vals, nnz, _state); + ae_vector_set_length(&eoffs, sparsek+1, _state); + state->sparsec.ridx.ptr.p_int[0] = 0; + eoffs.ptr.p_int[0] = 0; + for(i=1; i<=sparsek; i++) + { + state->sparsec.ridx.ptr.p_int[i] = state->sparsec.ridx.ptr.p_int[i-1]+rs.ptr.p_int[i-1]; + eoffs.ptr.p_int[i] = state->sparsec.ridx.ptr.p_int[i]; + } + t0 = 0; + t1 = 0; + while(sparseenumerate(sparsec, &t0, &t1, &i, &j, &v, _state)) + { + if( i>sparsek-1||j>n ) + { + continue; + } + if( jsparsec.idx.ptr.p_int[j0] = j; + state->sparsec.vals.ptr.p_double[j0] = v; + eoffs.ptr.p_int[i] = j0+1; + } + else + { + + /* + * Handle right part of the constraint + */ + state->scl.ptr.p_double[i] = v; + state->scu.ptr.p_double[i] = v; + } + } + for(i=0; i<=sparsek-1; i++) + { + ae_assert(eoffs.ptr.p_int[i]==state->sparsec.ridx.ptr.p_int[i+1], "xlc: critical integrity check failed (sparse copying)", _state); + } + sparsecreatecrsinplace(&state->sparsec, _state); + for(i=0; i<=sparsek-1; i++) + { + if( sparsect->ptr.p_int[i]>0 ) + { + state->scu.ptr.p_double[i] = _state->v_posinf; + } + if( sparsect->ptr.p_int[i]<0 ) + { + state->scl.ptr.p_double[i] = _state->v_neginf; + } + } + } + if( densek>0 ) + { + + /* + * Copy dense constraints + */ + rallocv(densek, &state->dcl, _state); + rallocv(densek, &state->dcu, _state); + rmatrixsetlengthatleast(&state->densec, densek, n, _state); + for(i=0; i<=densek-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->densec.ptr.pp_double[i][j] = densec->ptr.pp_double[i][j]; + } + if( densect->ptr.p_int[i]>0 ) + { + state->dcl.ptr.p_double[i] = densec->ptr.pp_double[i][n]; + state->dcu.ptr.p_double[i] = _state->v_posinf; + continue; + } + if( densect->ptr.p_int[i]<0 ) + { + state->dcl.ptr.p_double[i] = _state->v_neginf; + state->dcu.ptr.p_double[i] = densec->ptr.pp_double[i][n]; + continue; + } + state->dcl.ptr.p_double[i] = densec->ptr.pp_double[i][n]; + state->dcu.ptr.p_double[i] = densec->ptr.pp_double[i][n]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites modifications set by previous calls (if such +calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - linear constraints structure + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 13.04.2024 by Bochkanov Sergey +*************************************************************************/ +void xlcsetlc2mixed(xlinearconstraints* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = kdense+ksparse; + + /* + * Check input arguments + */ + ae_assert(ksparse>=0, "xlcSetLC2Mixed: KSparse<0", _state); + ae_assert(ksparse==0||sparsegetncols(sparsea, _state)==n, "xlcSetLC2: Cols(SparseA)<>N", _state); + ae_assert(ksparse==0||sparsegetnrows(sparsea, _state)==ksparse, "xlcSetLC2: Rows(SparseA)<>K", _state); + ae_assert(kdense>=0, "xlcSetLC2Mixed: KDense<0", _state); + ae_assert(kdense==0||densea->cols>=n, "xlcSetLC2Mixed: Cols(DenseA)rows>=kdense, "xlcSetLC2Mixed: Rows(DenseA)cnt>=kdense+ksparse, "xlcSetLC2Mixed: Length(AL)cnt>=kdense+ksparse, "xlcSetLC2Mixed: Length(AU)ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "xlcSetLC2Mixed: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "xlcSetLC2Mixed: AU contains NAN or -INF", _state); + } + + /* + * Quick exit if needed + */ + if( m==0 ) + { + state->ndense = 0; + state->nsparse = 0; + return; + } + + /* + * Prepare + */ + rallocv(ksparse, &state->scl, _state); + rallocv(ksparse, &state->scu, _state); + rallocv(kdense, &state->dcl, _state); + rallocv(kdense, &state->dcu, _state); + rcopyvx(ksparse, al, 0, &state->scl, 0, _state); + rcopyvx(ksparse, au, 0, &state->scu, 0, _state); + rcopyvx(kdense, al, ksparse, &state->dcl, 0, _state); + rcopyvx(kdense, au, ksparse, &state->dcu, 0, _state); + state->ndense = kdense; + state->nsparse = ksparse; + + /* + * Copy dense and sparse terms + */ + if( ksparse>0 ) + { + sparsecopytocrsbuf(sparsea, &state->sparsec, _state); + } + if( kdense>0 ) + { + rcopyallocm(kdense, n, densea, &state->densec, _state); + } +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +matrix of currently present dense constraints. + +INPUT PARAMETERS: + State - current constraints + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void xlcaddlc2dense(xlinearconstraints* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(a->cnt>=n, "xlcAddLC2Dense: Length(A)ndense+1, &state->dcl, _state); + rgrowv(state->ndense+1, &state->dcu, _state); + rmatrixgrowrowsto(&state->densec, state->ndense+1, n, _state); + rcopyvr(n, a, &state->densec, state->ndense, _state); + state->dcl.ptr.p_double[state->ndense] = al; + state->dcu.ptr.p_double[state->ndense] = au; + state->ndense = state->ndense+1; +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void xlcaddlc2(xlinearconstraints* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs; + ae_int_t offsdst; + ae_int_t n; + ae_int_t didx; + ae_int_t uidx; + + + n = state->n; + + /* + * Check inputs + */ + ae_assert(nnz>=0, "xlcAddLC2: NNZ<0", _state); + ae_assert(idxa->cnt>=nnz, "xlcAddLC2: Length(IdxA)cnt>=nnz, "xlcAddLC2: Length(ValA)ptr.p_int[i]>=0&&idxa->ptr.p_int[i]nsparse==0 ) + { + state->sparsec.matrixtype = 1; + state->sparsec.m = 0; + state->sparsec.n = n; + state->sparsec.ninitialized = 0; + ivectorsetlengthatleast(&state->sparsec.ridx, 1, _state); + state->sparsec.ridx.ptr.p_int[0] = 0; + } + ae_assert(state->sparsec.matrixtype==1&&state->sparsec.m==state->nsparse, "xlcAddLC2: integrity check failed!", _state); + + /* + * Reallocate inequality bounds + */ + rgrowv(state->nsparse+1, &state->scl, _state); + rgrowv(state->nsparse+1, &state->scu, _state); + state->scl.ptr.p_double[state->nsparse] = al; + state->scu.ptr.p_double[state->nsparse] = au; + + /* + * Reallocate sparse storage + */ + offs = state->sparsec.ridx.ptr.p_int[state->nsparse]; + ivectorgrowto(&state->sparsec.idx, offs+nnz, _state); + rvectorgrowto(&state->sparsec.vals, offs+nnz, _state); + ivectorgrowto(&state->sparsec.didx, state->nsparse+1, _state); + ivectorgrowto(&state->sparsec.uidx, state->nsparse+1, _state); + ivectorgrowto(&state->sparsec.ridx, state->nsparse+2, _state); + + /* + * If NNZ=0, perform quick and simple row append. + */ + if( nnz==0 ) + { + state->sparsec.didx.ptr.p_int[state->nsparse] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + state->sparsec.uidx.ptr.p_int[state->nsparse] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + state->sparsec.ridx.ptr.p_int[state->nsparse+1] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + inc(&state->sparsec.m, _state); + inc(&state->nsparse, _state); + return; + } + + /* + * Now we are sure that SparseC contains properly initialized sparse + * matrix (or some appropriate dummy for M=0) and we have NNZ>0 + * (no need to care about degenerate cases). + * + * Append rows to SparseC: + * * append data + * * sort in place + * * merge duplicate indexes + * * compute DIdx and UIdx + * + */ + for(i=0; i<=nnz-1; i++) + { + state->sparsec.idx.ptr.p_int[offs+i] = idxa->ptr.p_int[i]; + state->sparsec.vals.ptr.p_double[offs+i] = vala->ptr.p_double[i]; + } + tagsortmiddleir(&state->sparsec.idx, &state->sparsec.vals, offs, nnz, _state); + offsdst = offs; + for(i=1; i<=nnz-1; i++) + { + if( state->sparsec.idx.ptr.p_int[offsdst]!=state->sparsec.idx.ptr.p_int[offs+i] ) + { + offsdst = offsdst+1; + state->sparsec.idx.ptr.p_int[offsdst] = state->sparsec.idx.ptr.p_int[offs+i]; + state->sparsec.vals.ptr.p_double[offsdst] = state->sparsec.vals.ptr.p_double[offs+i]; + } + else + { + state->sparsec.vals.ptr.p_double[offsdst] = state->sparsec.vals.ptr.p_double[offsdst]+state->sparsec.vals.ptr.p_double[offs+i]; + } + } + nnz = offsdst-offs+1; + uidx = -1; + didx = -1; + for(j=offs; j<=offsdst; j++) + { + k = state->sparsec.idx.ptr.p_int[j]; + if( k==state->nsparse ) + { + didx = j; + } + else + { + if( k>state->nsparse&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offsdst+1; + } + if( didx==-1 ) + { + didx = uidx; + } + state->sparsec.didx.ptr.p_int[state->nsparse] = didx; + state->sparsec.uidx.ptr.p_int[state->nsparse] = uidx; + state->sparsec.ridx.ptr.p_int[state->nsparse+1] = offsdst+1; + state->sparsec.ninitialized = state->sparsec.ridx.ptr.p_int[state->nsparse+1]; + inc(&state->sparsec.m, _state); + inc(&state->nsparse, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void xlcaddlc2sparsefromdense(xlinearconstraints* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nzi; + ae_int_t offs; + ae_int_t n; + ae_int_t nnz; + ae_int_t didx; + ae_int_t uidx; + + + n = state->n; + + /* + * Check inputs + */ + ae_assert(da->cnt>=n, "xlcAddLC2SparseFromDense: Length(DA)nsparse==0 ) + { + state->sparsec.matrixtype = 1; + state->sparsec.m = 0; + state->sparsec.n = n; + state->sparsec.ninitialized = 0; + ivectorsetlengthatleast(&state->sparsec.ridx, 1, _state); + state->sparsec.ridx.ptr.p_int[0] = 0; + } + ae_assert(state->sparsec.matrixtype==1&&state->sparsec.m==state->nsparse, "xlcAddLC2SparseFromDense: integrity check failed!", _state); + + /* + * Reallocate inequality bounds + */ + rvectorgrowto(&state->scl, state->nsparse+1, _state); + rvectorgrowto(&state->scu, state->nsparse+1, _state); + state->scl.ptr.p_double[state->nsparse] = al; + state->scu.ptr.p_double[state->nsparse] = au; + + /* + * Determine nonzeros count. + * Reallocate sparse storage. + */ + nnz = 0; + for(i=0; i<=n-1; i++) + { + if( !(da->ptr.p_double[i]==0.0) ) + { + nnz = nnz+1; + } + } + offs = state->sparsec.ridx.ptr.p_int[state->nsparse]; + ivectorgrowto(&state->sparsec.idx, offs+nnz, _state); + rvectorgrowto(&state->sparsec.vals, offs+nnz, _state); + ivectorgrowto(&state->sparsec.didx, state->nsparse+1, _state); + ivectorgrowto(&state->sparsec.uidx, state->nsparse+1, _state); + ivectorgrowto(&state->sparsec.ridx, state->nsparse+2, _state); + + /* + * If NNZ=0, perform quick and simple row append. + */ + if( nnz==0 ) + { + state->sparsec.didx.ptr.p_int[state->nsparse] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + state->sparsec.uidx.ptr.p_int[state->nsparse] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + state->sparsec.ridx.ptr.p_int[state->nsparse+1] = state->sparsec.ridx.ptr.p_int[state->nsparse]; + inc(&state->sparsec.m, _state); + inc(&state->nsparse, _state); + return; + } + + /* + * Now we are sure that SparseC contains properly initialized sparse + * matrix (or some appropriate dummy for M=0) and we have NNZ>0 + * (no need to care about degenerate cases). + * + * Append rows to SparseC: + * * append data + * * compute DIdx and UIdx + * + */ + nzi = 0; + for(i=0; i<=n-1; i++) + { + if( !(da->ptr.p_double[i]==0.0) ) + { + state->sparsec.idx.ptr.p_int[offs+nzi] = i; + state->sparsec.vals.ptr.p_double[offs+nzi] = da->ptr.p_double[i]; + nzi = nzi+1; + } + } + uidx = -1; + didx = -1; + for(j=offs; j<=offs+nnz-1; j++) + { + k = state->sparsec.idx.ptr.p_int[j]; + if( k==state->nsparse ) + { + didx = j; + } + else + { + if( k>state->nsparse&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offs+nnz; + } + if( didx==-1 ) + { + didx = uidx; + } + state->sparsec.didx.ptr.p_int[state->nsparse] = didx; + state->sparsec.uidx.ptr.p_int[state->nsparse] = uidx; + state->sparsec.ridx.ptr.p_int[state->nsparse+1] = offs+nnz; + state->sparsec.ninitialized = state->sparsec.ridx.ptr.p_int[state->nsparse+1]; + inc(&state->sparsec.m, _state); + inc(&state->nsparse, _state); +} + + +/************************************************************************* +Converts linear constraints to the legacy dense single-sided format. Sets +State.NEC, State.NIC, State.CLEIC, State.LCSrcIdx, State.LCSrcMult + +NOTE: this function ignores inconsistent bounds, like CL>CU, assuming that + either they were already noticed, or will be noticed later. +*************************************************************************/ +void xlcconverttoold(xlinearconstraints* state, ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t idxoutec; + ae_int_t idxoutic; + ae_int_t dstrow0; + ae_int_t dstrow1; + double vdst0; + double vdst1; + double rhsdst0; + double rhsdst1; + ae_int_t n; + double vl; + double vu; + + + n = state->n; + state->nec = 0; + state->nic = 0; + + /* + * Compute required amount of single-sided constraints + */ + for(i=0; i<=state->nsparse+state->ndense-1; i++) + { + if( insparse ) + { + vl = state->scl.ptr.p_double[i]; + vu = state->scu.ptr.p_double[i]; + } + else + { + vl = state->dcl.ptr.p_double[i-state->nsparse]; + vu = state->dcu.ptr.p_double[i-state->nsparse]; + } + ae_assert(ae_isfinite(vl, _state)||ae_isneginf(vl, _state), "OPTSERV: integrity check 0354 failed", _state); + ae_assert(ae_isfinite(vu, _state)||ae_isposinf(vu, _state), "OPTSERV: integrity check 0355 failed", _state); + if( (ae_isfinite(vl, _state)&&ae_isfinite(vu, _state))&&ae_fp_eq(vl,vu) ) + { + state->nec = state->nec+1; + continue; + } + if( ae_isfinite(vl, _state) ) + { + state->nic = state->nic+1; + } + if( ae_isfinite(vu, _state) ) + { + state->nic = state->nic+1; + } + } + if( state->nec+state->nic==0 ) + { + return; + } + + /* + * Convert two-sided constraints into single-sided + */ + idxoutec = 0; + idxoutic = state->nec; + rallocm(state->nec+state->nic, n+1, &state->cleic, _state); + isetallocv(state->nec+state->nic, -1, &state->lcsrcidx, _state); + rsetallocv(state->nec+state->nic, 0.0, &state->lcsrcmult, _state); + for(i=0; i<=state->nsparse+state->ndense-1; i++) + { + + /* + * Extract bounds + */ + if( insparse ) + { + vl = state->scl.ptr.p_double[i]; + vu = state->scu.ptr.p_double[i]; + } + else + { + vl = state->dcl.ptr.p_double[i-state->nsparse]; + vu = state->dcu.ptr.p_double[i-state->nsparse]; + } + + /* + * Ignore non-binding rows + */ + if( !ae_isfinite(vl, _state)&&!ae_isfinite(vu, _state) ) + { + continue; + } + + /* + * Analyze bounds + */ + dstrow0 = -1; + dstrow1 = -1; + vdst0 = (double)(0); + vdst1 = (double)(0); + rhsdst0 = (double)(0); + rhsdst1 = (double)(0); + if( ae_isfinite(vl, _state)&&ae_isfinite(vu, _state) ) + { + if( ae_fp_eq(vl,vu) ) + { + + /* + * Two bounds = equality constraints, one row is output + */ + dstrow0 = idxoutec; + vdst0 = 1.0; + rhsdst0 = vl; + idxoutec = idxoutec+1; + } + else + { + + /* + * Two bounds = range constraint, two rows are output + */ + dstrow0 = idxoutic; + dstrow1 = idxoutic+1; + vdst0 = -1.0; + vdst1 = 1.0; + rhsdst0 = -vl; + rhsdst1 = vu; + idxoutic = idxoutic+2; + } + } + else + { + + /* + * Only one bound is present + */ + if( ae_isfinite(vl, _state) ) + { + dstrow0 = idxoutic; + vdst0 = -1.0; + rhsdst0 = -vl; + idxoutic = idxoutic+1; + } + if( ae_isfinite(vu, _state) ) + { + dstrow0 = idxoutic; + vdst0 = 1.0; + rhsdst0 = vu; + idxoutic = idxoutic+1; + } + } + + /* + * Extract row + */ + ae_assert(idxoutec<=state->nec, "OPTSERV: integrity check 2607 failed", _state); + ae_assert(idxoutic<=state->nec+state->nic, "OPTSERV: integrity check 2608 failed", _state); + if( insparse ) + { + + /* + * Extract from the sparse matrix + */ + if( dstrow0>=0 ) + { + rsetr(n, 0.0, &state->cleic, dstrow0, _state); + k0 = state->sparsec.ridx.ptr.p_int[i]; + k1 = state->sparsec.ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + state->cleic.ptr.pp_double[dstrow0][state->sparsec.idx.ptr.p_int[k]] = vdst0*state->sparsec.vals.ptr.p_double[k]; + } + state->cleic.ptr.pp_double[dstrow0][n] = rhsdst0; + } + if( dstrow1>=0 ) + { + rsetr(n, 0.0, &state->cleic, dstrow1, _state); + k0 = state->sparsec.ridx.ptr.p_int[i]; + k1 = state->sparsec.ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + state->cleic.ptr.pp_double[dstrow1][state->sparsec.idx.ptr.p_int[k]] = vdst1*state->sparsec.vals.ptr.p_double[k]; + } + state->cleic.ptr.pp_double[dstrow1][n] = rhsdst1; + } + } + else + { + + /* + * Copy from the dense matrix + */ + if( dstrow0>=0 ) + { + rcopyrr(n, &state->densec, i-state->nsparse, &state->cleic, dstrow0, _state); + rmulr(n, vdst0, &state->cleic, dstrow0, _state); + state->cleic.ptr.pp_double[dstrow0][n] = rhsdst0; + } + if( dstrow1>=0 ) + { + rcopyrr(n, &state->densec, i-state->nsparse, &state->cleic, dstrow1, _state); + rmulr(n, vdst1, &state->cleic, dstrow1, _state); + state->cleic.ptr.pp_double[dstrow1][n] = rhsdst1; + } + } + if( dstrow0>=0 ) + { + state->lcsrcidx.ptr.p_int[dstrow0] = i; + state->lcsrcmult.ptr.p_double[dstrow0] = vdst0; + } + if( dstrow1>=0 ) + { + state->lcsrcidx.ptr.p_int[dstrow1] = i; + state->lcsrcmult.ptr.p_double[dstrow1] = vdst1; + } + } +} + + +/************************************************************************* +Converts linear constraints to the modern 2-sided sparse-only format. + +Sets State.EffSparseA, State.EffAL, State.EffAU. After these fields are +set, they can be modified by the user (e.g. by adding rows and/or slack +variables). + +Additionally sets State.LCSrcIdx to an identity map. + +NOTE: this function ignores inconsistent bounds, like CL>CU, assuming that + either they were already noticed, or will be noticed later. +*************************************************************************/ +void xlcconverttosparse(xlinearconstraints* state, ae_state *_state) +{ + ae_int_t i; + + + if( state->nsparse+state->ndense==0 ) + { + return; + } + rallocv(state->nsparse+state->ndense, &state->effal, _state); + rallocv(state->nsparse+state->ndense, &state->effau, _state); + if( state->nsparse>0 ) + { + sparsecopytocrsbuf(&state->sparsec, &state->effsparsea, _state); + rcopyvx(state->nsparse, &state->scl, 0, &state->effal, 0, _state); + rcopyvx(state->nsparse, &state->scu, 0, &state->effau, 0, _state); + } + else + { + sparsecreatecrsemptybuf(state->n, &state->effsparsea, _state); + } + if( state->ndense>0 ) + { + sparsecreatecrsfromdensebuf(&state->densec, state->ndense, state->n, &state->tmps, _state); + sparseappendmatrix(&state->effsparsea, &state->tmps, _state); + rcopyvx(state->ndense, &state->dcl, 0, &state->effal, state->nsparse, _state); + rcopyvx(state->ndense, &state->dcu, 0, &state->effau, state->nsparse, _state); + } + iallocv(state->nsparse+state->ndense, &state->lcsrcidx, _state); + for(i=0; i<=state->nsparse+state->ndense-1; i++) + { + state->lcsrcidx.ptr.p_int[i] = i; + } +} + + +/************************************************************************* +Append quadratic constraint given by a list of nonzeros +*************************************************************************/ +void xqcaddqc2list(xquadraticconstraints* xqc, + /* Integer */ const ae_vector* qridx, + /* Integer */ const ae_vector* qcidx, + /* Real */ const ae_vector* qvals, + ae_int_t qnnz, + ae_bool isupper, + /* Integer */ const ae_vector* bidx, + /* Real */ const ae_vector* bvals, + ae_int_t bnnz, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector allitems; + xquadraticconstraint *c; + ae_smart_ptr _c; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs; + ae_vector b; + sparsematrix q; + + ae_frame_make(_state, &_frame_block); + memset(&allitems, 0, sizeof(allitems)); + memset(&_c, 0, sizeof(_c)); + memset(&b, 0, sizeof(b)); + memset(&q, 0, sizeof(q)); + ae_vector_init(&allitems, 0, DT_INT, _state, ae_true); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + ae_vector_init(&b, 0, DT_REAL, _state, ae_true); + _sparsematrix_init(&q, _state, ae_true); + + n = xqc->n; + c = (xquadraticconstraint*)ae_malloc(sizeof(xquadraticconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xquadraticconstraint)); + _xquadraticconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xquadraticconstraint), _xquadraticconstraint_init_copy, _xquadraticconstraint_destroy); + + /* + * Determine unique variable indexes + */ + iallocv(2*qnnz+bnnz, &allitems, _state); + offs = 0; + for(i=0; i<=qnnz-1; i++) + { + if( (isupper&&qcidx->ptr.p_int[i]>=qridx->ptr.p_int[i])||(!isupper&&qridx->ptr.p_int[i]>=qcidx->ptr.p_int[i]) ) + { + if( qvals->ptr.p_double[i]!=(double)0 ) + { + allitems.ptr.p_int[offs+0] = qridx->ptr.p_int[i]; + allitems.ptr.p_int[offs+1] = qcidx->ptr.p_int[i]; + offs = offs+2; + } + } + } + for(i=0; i<=bnnz-1; i++) + { + if( bvals->ptr.p_double[i]!=(double)0 ) + { + allitems.ptr.p_int[offs] = bidx->ptr.p_int[i]; + offs = offs+1; + } + } + if( offs==0 ) + { + + /* + * Quick exit + */ + c->nvars = 0; + c->applyorigin = applyorigin; + c->cl = cl; + c->cu = cu; + ae_obj_array_append_transfer(&xqc->constraints, &_c, _state); + ae_frame_leave(_state); + return; + } + tagsortmiddlei(&allitems, 0, offs, _state); + ae_assert(allitems.ptr.p_int[0]>=0&&allitems.ptr.p_int[offs-1]nvars = 0; + for(i=0; i<=offs-1; i++) + { + if( c->nvars==0||c->varidx.ptr.p_int[c->nvars-1]!=allitems.ptr.p_int[i] ) + { + igrowv(c->nvars+1, &c->varidx, _state); + c->varidx.ptr.p_int[c->nvars] = allitems.ptr.p_int[i]; + c->nvars = c->nvars+1; + } + } + + /* + * Save constraints + */ + c->applyorigin = applyorigin; + c->cl = cl; + c->cu = cu; + if( c->nvars>0 ) + { + + /* + * Compress B + */ + rsetallocv(c->nvars, 0.0, &c->b, _state); + for(i=0; i<=bnnz-1; i++) + { + c->b.ptr.p_double[ibinarysearchexisting(&c->varidx, 0, c->nvars, bidx->ptr.p_int[i], _state)] = bvals->ptr.p_double[i]; + } + + /* + * Compress Q + */ + c->lowerq.m = c->nvars; + c->lowerq.n = c->nvars; + isetallocv(c->nvars, 0, &c->lowerq.didx, _state); + for(k=0; k<=qnnz-1; k++) + { + if( (isupper&&qcidx->ptr.p_int[k]>=qridx->ptr.p_int[k])||(!isupper&&qridx->ptr.p_int[k]>=qcidx->ptr.p_int[k]) ) + { + if( qvals->ptr.p_double[k]!=0.0 ) + { + if( isupper ) + { + i = ibinarysearchexisting(&c->varidx, 0, c->nvars, qcidx->ptr.p_int[k], _state); + } + else + { + i = ibinarysearchexisting(&c->varidx, 0, c->nvars, qridx->ptr.p_int[k], _state); + } + c->lowerq.didx.ptr.p_int[i] = c->lowerq.didx.ptr.p_int[i]+1; + } + } + } + iallocv(c->nvars+1, &c->lowerq.ridx, _state); + c->lowerq.ridx.ptr.p_int[0] = 0; + for(i=0; i<=c->nvars-1; i++) + { + c->lowerq.ridx.ptr.p_int[i+1] = c->lowerq.ridx.ptr.p_int[i]+c->lowerq.didx.ptr.p_int[i]; + } + iallocv(c->lowerq.ridx.ptr.p_int[c->nvars], &c->lowerq.idx, _state); + rallocv(c->lowerq.ridx.ptr.p_int[c->nvars], &c->lowerq.vals, _state); + icopyv(c->nvars, &c->lowerq.ridx, &c->lowerq.didx, _state); + for(k=0; k<=qnnz-1; k++) + { + if( (isupper&&qcidx->ptr.p_int[k]>=qridx->ptr.p_int[k])||(!isupper&&qridx->ptr.p_int[k]>=qcidx->ptr.p_int[k]) ) + { + if( qvals->ptr.p_double[k]!=0.0 ) + { + if( isupper ) + { + i = ibinarysearchexisting(&c->varidx, 0, c->nvars, qcidx->ptr.p_int[k], _state); + j = ibinarysearchexisting(&c->varidx, 0, c->nvars, qridx->ptr.p_int[k], _state); + } + else + { + i = ibinarysearchexisting(&c->varidx, 0, c->nvars, qridx->ptr.p_int[k], _state); + j = ibinarysearchexisting(&c->varidx, 0, c->nvars, qcidx->ptr.p_int[k], _state); + } + offs = c->lowerq.didx.ptr.p_int[i]; + c->lowerq.idx.ptr.p_int[offs] = j; + c->lowerq.vals.ptr.p_double[offs] = qvals->ptr.p_double[k]; + c->lowerq.didx.ptr.p_int[i] = offs+1; + } + } + } + for(i=0; i<=c->nvars-1; i++) + { + if( c->lowerq.didx.ptr.p_int[i]!=c->lowerq.ridx.ptr.p_int[i+1] ) + { + ae_assert(ae_false, "OPTSERV: integrity check 4227 failed", _state); + } + } + sparsecreatecrsinplace(&c->lowerq, _state); + } + ae_obj_array_append_transfer(&xqc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Append quadratic constraint given by dense quadratic matrix +*************************************************************************/ +void xqcaddqc2dense(xquadraticconstraints* xqc, + /* Real */ const ae_matrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t n; + double vq; + xquadraticconstraint *c; + ae_smart_ptr _c; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + ae_assert(ae_isfinite(cl, _state)||ae_isneginf(cl, _state), "xqcAppendDense: CL is not finite or -INF", _state); + ae_assert(ae_isfinite(cu, _state)||ae_isposinf(cu, _state), "xqcAppendDense: CU is not finite or +INF", _state); + n = xqc->n; + c = (xquadraticconstraint*)ae_malloc(sizeof(xquadraticconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xquadraticconstraint)); + _xquadraticconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xquadraticconstraint), _xquadraticconstraint_init_copy, _xquadraticconstraint_destroy); + + /* + * Determine working variables + */ + isetallocv(n, 0, &xqc->tmpi, _state); + for(i=0; i<=n-1; i++) + { + if( b->ptr.p_double[i]!=0.0 ) + { + xqc->tmpi.ptr.p_int[i] = 1; + } + } + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = i; + j1 = n-1; + } + else + { + j0 = 0; + j1 = i; + } + for(j=j0; j<=j1; j++) + { + if( q->ptr.pp_double[i][j]!=0.0 ) + { + xqc->tmpi.ptr.p_int[i] = 1; + xqc->tmpi.ptr.p_int[j] = 1; + } + } + } + c->nvars = 0; + for(i=0; i<=n-1; i++) + { + if( xqc->tmpi.ptr.p_int[i]!=0 ) + { + igrowv(c->nvars+1, &c->varidx, _state); + c->varidx.ptr.p_int[c->nvars] = i; + c->nvars = c->nvars+1; + } + } + + /* + * Save constraints + */ + c->applyorigin = applyorigin; + c->cl = cl; + c->cu = cu; + if( c->nvars>0 ) + { + rallocv(c->nvars, &c->b, _state); + for(i=0; i<=c->nvars-1; i++) + { + c->b.ptr.p_double[i] = b->ptr.p_double[c->varidx.ptr.p_int[i]]; + } + c->lowerq.m = c->nvars; + c->lowerq.n = c->nvars; + iallocv(c->nvars+1, &c->lowerq.ridx, _state); + c->lowerq.ridx.ptr.p_int[0] = 0; + for(i=0; i<=c->nvars-1; i++) + { + offs = c->lowerq.ridx.ptr.p_int[i]; + igrowv(offs+c->nvars, &c->lowerq.idx, _state); + rgrowv(offs+c->nvars, &c->lowerq.vals, _state); + for(j=0; j<=i; j++) + { + if( isupper ) + { + vq = q->ptr.pp_double[c->varidx.ptr.p_int[j]][c->varidx.ptr.p_int[i]]; + } + else + { + vq = q->ptr.pp_double[c->varidx.ptr.p_int[i]][c->varidx.ptr.p_int[j]]; + } + if( vq!=0.0||j==i ) + { + c->lowerq.idx.ptr.p_int[offs] = j; + c->lowerq.vals.ptr.p_double[offs] = vq; + offs = offs+1; + } + } + c->lowerq.ridx.ptr.p_int[i+1] = offs; + } + sparsecreatecrsinplace(&c->lowerq, _state); + } + ae_obj_array_append_transfer(&xqc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Slightly denormalized primitive power cone +*************************************************************************/ +ae_int_t xccdenormalizedprimitivepowerconetype(ae_state *_state) +{ + ae_int_t result; + + + result = -4; + return result; +} + + +/************************************************************************* +Generic orthogonal power cone +*************************************************************************/ +ae_int_t xccgenericorthogonalpowerconetype(ae_state *_state) +{ + ae_int_t result; + + + result = -3; + return result; +} + + +/************************************************************************* +Slightly denormalized primitive SOC +*************************************************************************/ +ae_int_t xccdenormalizedprimitiveconetype(ae_state *_state) +{ + ae_int_t result; + + + result = -2; + return result; +} + + +/************************************************************************* +Slightly denormalized primitive SOC +*************************************************************************/ +ae_int_t xccgenericorthogonalconetype(ae_state *_state) +{ + ae_int_t result; + + + result = -1; + return result; +} + + +/************************************************************************* +Primitive SOC +*************************************************************************/ +ae_int_t xccprimitiveconetype(ae_state *_state) +{ + ae_int_t result; + + + result = 1; + return result; +} + + +/************************************************************************* +Primitive SOC +*************************************************************************/ +ae_int_t xccprimitivepowerconetype(ae_state *_state) +{ + ae_int_t result; + + + result = 2; + return result; +} + + +/************************************************************************* +Clear quadratic constraints structure +*************************************************************************/ +void xccclear(xconicconstraints* state, ae_state *_state) +{ + + + ae_obj_array_clear(&state->constraints); +} + + +/************************************************************************* +Copies conic constraints structure, target structure is cleared, +previously allocated memory is ignored. +*************************************************************************/ +void xcccopy(xconicconstraints* src, + xconicconstraints* dst, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t m; + xconicconstraint *c; + ae_smart_ptr _c; + xconicconstraint *c1; + ae_smart_ptr _c1; + ae_bool donecc; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + memset(&_c1, 0, sizeof(_c1)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + ae_smart_ptr_init(&_c1, (void**)&c1, ae_false, _state, ae_true); + + dst->n = src->n; + m = ae_obj_array_get_length(&src->constraints); + ae_obj_array_clear(&dst->constraints); + for(i=0; i<=m-1; i++) + { + ae_obj_array_get(&src->constraints, i, &_c, _state); + c1 = (xconicconstraint*)ae_malloc(sizeof(xconicconstraint), _state); /* note: using c1 as a temporary prior to assigning its value to _c1 */ + memset(c1, 0, sizeof(xconicconstraint)); + _xconicconstraint_init(c1, _state, ae_false); + ae_smart_ptr_assign(&_c1, c1, ae_true, ae_true, (ae_int_t)sizeof(xconicconstraint), _xconicconstraint_init_copy, _xconicconstraint_destroy); + donecc = ae_false; + c1->conetype = c->conetype; + c1->nvars = c->nvars; + c1->applyorigin = c->applyorigin; + if( c->conetype==-1||c->conetype==1 ) + { + + /* + * Canonic/noncanonic orthogonal cones + */ + if( c->nvars>0 ) + { + icopyallocv(c->nvars, &c->varidx, &c1->varidx, _state); + rcopyallocv(c->nvars, &c->diaga, &c1->diaga, _state); + rcopyallocv(c->nvars+1, &c->shftc, &c1->shftc, _state); + } + donecc = ae_true; + } + if( c->conetype==xccgenericorthogonalpowerconetype(_state)||c->conetype==xccprimitivepowerconetype(_state) ) + { + + /* + * Power cones + */ + ae_assert(c->nvars>0, "xccCopy: integrity check 561151 failed", _state); + icopyallocv(c->nvars, &c->varidx, &c1->varidx, _state); + rcopyallocv(c->nvars, &c->diaga, &c1->diaga, _state); + rcopyallocv(c->nvars+1, &c->shftc, &c1->shftc, _state); + c1->kpow = c->kpow; + rcopyallocv(c->kpow, &c->alphapow, &c1->alphapow, _state); + donecc = ae_true; + } + ae_assert(donecc, "xccCopy: unexpected cone type", _state); + ae_obj_array_append_transfer(&dst->constraints, &_c1, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Copies conic constraints structure, skipping some constraints and permuting +variables using so-called 'pack' permutation that monotonically maps increasing +indexes into increasing indexes. + +The target structure is cleared, previously allocated memory is ignored. +*************************************************************************/ +void xcccopywithskipandpack(xconicconstraints* src, + /* Boolean */ const ae_vector* skipflags, + /* Integer */ const ae_vector* packxperm, + xconicconstraints* dst, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t srcm; + xconicconstraint *c; + ae_smart_ptr _c; + xconicconstraint *c1; + ae_smart_ptr _c1; + ae_bool donecc; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + memset(&_c1, 0, sizeof(_c1)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + ae_smart_ptr_init(&_c1, (void**)&c1, ae_false, _state, ae_true); + + dst->n = src->n; + srcm = ae_obj_array_get_length(&src->constraints); + ae_obj_array_clear(&dst->constraints); + for(i=0; i<=srcm-1; i++) + { + if( !skipflags->ptr.p_bool[i] ) + { + ae_obj_array_get(&src->constraints, i, &_c, _state); + c1 = (xconicconstraint*)ae_malloc(sizeof(xconicconstraint), _state); /* note: using c1 as a temporary prior to assigning its value to _c1 */ + memset(c1, 0, sizeof(xconicconstraint)); + _xconicconstraint_init(c1, _state, ae_false); + ae_smart_ptr_assign(&_c1, c1, ae_true, ae_true, (ae_int_t)sizeof(xconicconstraint), _xconicconstraint_init_copy, _xconicconstraint_destroy); + donecc = ae_false; + c1->conetype = c->conetype; + c1->nvars = c->nvars; + c1->applyorigin = c->applyorigin; + if( c->conetype==-1||c->conetype==1 ) + { + + /* + * Canonic/noncanonic orthogonal cones + */ + if( c->nvars>0 ) + { + rcopyallocv(c->nvars, &c->diaga, &c1->diaga, _state); + rcopyallocv(c->nvars+1, &c->shftc, &c1->shftc, _state); + iallocv(c->nvars, &c1->varidx, _state); + for(j=0; j<=c->nvars-1; j++) + { + c1->varidx.ptr.p_int[j] = packxperm->ptr.p_int[c->varidx.ptr.p_int[j]]; + } + } + donecc = ae_true; + } + if( c->conetype==xccprimitivepowerconetype(_state) ) + { + + /* + * Power cones + */ + ae_assert(c->nvars>0, "OPTSERV: integrity check 625237 failed", _state); + rcopyallocv(c->nvars, &c->diaga, &c1->diaga, _state); + rcopyallocv(c->nvars+1, &c->shftc, &c1->shftc, _state); + iallocv(c->nvars, &c1->varidx, _state); + for(j=0; j<=c->nvars-1; j++) + { + c1->varidx.ptr.p_int[j] = packxperm->ptr.p_int[c->varidx.ptr.p_int[j]]; + } + c1->kpow = c->kpow; + rcopyallocv(c->kpow, &c->alphapow, &c1->alphapow, _state); + donecc = ae_true; + } + ae_assert(donecc, "xccCopyWithSkipAndPack: unexpected cone type", _state); + ae_obj_array_append_transfer(&dst->constraints, &_c1, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Get constraints count +*************************************************************************/ +ae_int_t xccgetcount(const xconicconstraints* xcc, ae_state *_state) +{ + ae_int_t result; + + + result = ae_obj_array_get_length(&xcc->constraints); + return result; +} + + +/************************************************************************* +Adds noncanonic orthogonal second order cone. + +INPUT PARAMETERS: + XCC - a set of conic constraints + VarIdx - array[NVars], can be unsorted and non-distinct + Diag - array[NVars], diagonal multipliers before variables + Shft - array[NVars], shifts applied to variables + NVars - 1<=NVars, variables count (can be larger than N). + The last variable is the cone axis. + Theta - theta^2 is added to the term under the square root + ApplyOrigin - whether conic constraint applies as f(x-origin)<=0 + (ApplyOrigin=True) or as f(x)<=0. +*************************************************************************/ +void xccaddsoccorthogonalnoncanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + double theta, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + xconicconstraint *c; + ae_smart_ptr _c; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + n = xcc->n; + ae_assert(nvars>=1, "xccAddSOCCOrthogonalNoncanonic: NVars<1", _state); + ae_assert(varidx->cnt>=nvars, "xccAddSOCCOrthogonalNoncanonic: len(VarIdx)cnt>=nvars, "xccAddSOCCOrthogonalNoncanonic: len(Diag)cnt>=nvars, "xccAddSOCCOrthogonalNoncanonic: len(Shft)ptr.p_int[i]>=0&&varidx->ptr.p_int[i]ptr.p_double[i], _state), "xccAddSOCCOrthogonalNoncanonic: Diaga[] contains infinite values", _state); + ae_assert(ae_isfinite(shft->ptr.p_double[i], _state), "xccAddSOCCOrthogonalNoncanonic: Shft[] contains infinite values", _state); + } + ae_assert(ae_isfinite(theta, _state), "xccAddSOCCOrthogonalNoncanonic: theta is not a finite number", _state); + c = (xconicconstraint*)ae_malloc(sizeof(xconicconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xconicconstraint)); + _xconicconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xconicconstraint), _xconicconstraint_init_copy, _xconicconstraint_destroy); + c->conetype = -1; + c->nvars = nvars; + c->applyorigin = applyorigin; + icopyallocv(nvars, varidx, &c->varidx, _state); + rcopyallocv(nvars, diag, &c->diaga, _state); + rallocv(nvars+1, &c->shftc, _state); + rcopyv(nvars, shft, &c->shftc, _state); + c->shftc.ptr.p_double[nvars] = theta*theta; + ae_obj_array_append_transfer(&xcc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Adds canonic primitive second order cone. The canonic primitive cone has +requirement that all variables are distinct. + +INPUT PARAMETERS: + XCC - a set of conic constraints + VarIdx - array[NVars], sorted by ascending (except for the + last element) + Diag - array[NVars], diagonal multipliers before variables + Shft - array[NVars], shifts applied to variables + NVars - 1<=NVars<=N, variables count. The last variable is the + cone axis. + ApplyOrigin - whether conic constraint applies as f(x-origin)<=0 + (ApplyOrigin=True) or as f(x)<=0. +*************************************************************************/ +void xccaddsoccprimitivecanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + xconicconstraint *c; + ae_smart_ptr _c; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + n = xcc->n; + ae_assert(nvars>=1&&nvars<=xcc->n, "xccAddSOCCPrimitiveCanonic: NVars<1 or NVars>N", _state); + ae_assert(varidx->ptr.p_int[0]>=0&&varidx->ptr.p_int[0]ptr.p_int[nvars-1]>=0&&varidx->ptr.p_int[nvars-1]ptr.p_int[i]>varidx->ptr.p_int[i-1], "xccAddSOCCPrimitiveCanonic: VarIdx[] is unsorted and/or has nondistinct values", _state); + ae_assert(varidx->ptr.p_int[i]conetype = 1; + c->nvars = nvars; + c->applyorigin = applyorigin; + icopyallocv(nvars, varidx, &c->varidx, _state); + rcopyallocv(nvars, diag, &c->diaga, _state); + rallocv(nvars+1, &c->shftc, _state); + rcopyv(nvars, shft, &c->shftc, _state); + c->shftc.ptr.p_double[nvars] = 0.0; + ae_obj_array_append_transfer(&xcc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Adds canonic primitive power cone. The canonic primitive cone has +requirement that all variables are distinct. + +INPUT PARAMETERS: + XCC - a set of conic constraints + VarIdx - array[NVars]: + * first NVars-KPow elements are sorted by ascending, + all elements within the subsequence are distinct + * last KPow elements are sorted by ascending, + all elements within the subsequence are distinct + Diag - array[NVars], diagonal multipliers before variables; + Diag[i] is nonzero for NVars-KPow <= i < NVars. + Shft - array[NVars], shifts applied to variables + NVars - 1<=NVars<=N, variables count. The last KPow variables + are the cone axis. + AlphaPow - array[KPow], powers: + * AlphaPow[I]>0 + * 0 < SUM(AlphaPow[]) <= 1 + KPow - 1<=NPow<=NVars + ApplyOrigin - whether conic constraint applies as f(x-origin)<=0 + (ApplyOrigin=True) or as f(x)<=0. +*************************************************************************/ +void xccaddpowccprimitivecanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + /* Real */ const ae_vector* alphapow, + ae_int_t kpow, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + xconicconstraint *c; + ae_smart_ptr _c; + double vs; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + n = xcc->n; + ae_assert(nvars>=1&&nvars<=xcc->n, "xccAddPOWCCPrimitiveCanonic: NVars<1 or NVars>N", _state); + ae_assert(kpow>=1&&kpow<=nvars, "xccAddPOWCCPrimitiveCanonic: KPow<1 or KPow>NVars", _state); + if( kpowptr.p_int[0]>=0&&varidx->ptr.p_int[0]ptr.p_int[nvars-kpow-1]>=0&&varidx->ptr.p_int[nvars-kpow-1]ptr.p_int[i]>varidx->ptr.p_int[i-1], "xccAddPOWCCPrimitiveCanonic: VarIdx[] is unsorted and/or has nondistinct values", _state); + ae_assert(varidx->ptr.p_int[i]ptr.p_int[nvars-kpow]>=0&&varidx->ptr.p_int[nvars-kpow]ptr.p_int[nvars-1]>=0&&varidx->ptr.p_int[nvars-1]ptr.p_int[i]>varidx->ptr.p_int[i-1], "xccAddPOWCCPrimitiveCanonic: VarIdx[] is unsorted and/or has nondistinct values", _state); + ae_assert(varidx->ptr.p_int[i]ptr.p_double[i], _state), "xccAddPOWCCPrimitiveCanonic: AlphaPow[] contains INF/NAN values", _state); + ae_assert(ae_fp_greater(alphapow->ptr.p_double[i],(double)(0))&&ae_fp_less_eq(alphapow->ptr.p_double[i],(double)(1)), "xccAddPOWCCPrimitiveCanonic: AlphaPow[] is outside of (0,1]", _state); + ae_assert(ae_fp_neq(diag->ptr.p_double[nvars-kpow+i],(double)(0)), "xccAddPOWCCPrimitiveCanonic: scaling coefficient for power terms is zero", _state); + vs = vs+alphapow->ptr.p_double[i]; + } + ae_assert(ae_fp_greater(vs,(double)(0))&&ae_fp_less_eq(vs,(double)1+(double)(10*kpow)*ae_machineepsilon), "xccAddPOWCCPrimitiveCanonic: AlphaPow[] sum is is outside of (0,1]", _state); + c = (xconicconstraint*)ae_malloc(sizeof(xconicconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xconicconstraint)); + _xconicconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xconicconstraint), _xconicconstraint_init_copy, _xconicconstraint_destroy); + c->conetype = xccprimitivepowerconetype(_state); + c->nvars = nvars; + c->kpow = kpow; + c->applyorigin = applyorigin; + icopyallocv(nvars, varidx, &c->varidx, _state); + rcopyallocv(nvars, diag, &c->diaga, _state); + rallocv(nvars+1, &c->shftc, _state); + rcopyv(nvars, shft, &c->shftc, _state); + c->shftc.ptr.p_double[nvars] = 0.0; + rcopyallocv(kpow, alphapow, &c->alphapow, _state); + ae_obj_array_append_transfer(&xcc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Adds noncanonic orthogonal second order cone. + +INPUT PARAMETERS: + XCC - a set of conic constraints + VarIdx - array[NVars], can be unsorted and non-distinct + Diag - array[NVars], diagonal multipliers before variables + Shft - array[NVars], shifts applied to variables + NVars - 1<=NVars, variables count (can be larger than N). + The last variable is the cone axis. + Theta - theta^2 is added to the term under the square root + AlphaPow - array[KPow], power coeffs + KPow - 1<=KPow<=NVars, number of power terms + ApplyOrigin - whether conic constraint applies as f(x-origin)<=0 + (ApplyOrigin=True) or as f(x)<=0. +*************************************************************************/ +void xccaddpowccorthogonalnoncanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + double theta, + /* Real */ const ae_vector* alphapow, + ae_int_t kpow, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + double vs; + xconicconstraint *c; + ae_smart_ptr _c; + + ae_frame_make(_state, &_frame_block); + memset(&_c, 0, sizeof(_c)); + ae_smart_ptr_init(&_c, (void**)&c, ae_false, _state, ae_true); + + n = xcc->n; + ae_assert(nvars>=1, "xccAddPOWCCOrthogonalNoncanonic: NVars<1", _state); + ae_assert(varidx->cnt>=nvars, "xccAddPOWCCOrthogonalNoncanonic: len(VarIdx)cnt>=nvars, "xccAddPOWCCOrthogonalNoncanonic: len(Diag)cnt>=nvars, "xccAddPOWCCOrthogonalNoncanonic: len(Shft)ptr.p_int[i]>=0&&varidx->ptr.p_int[i]ptr.p_double[i], _state), "xccAddPOWCCOrthogonalNoncanonic: Diaga[] contains infinite values", _state); + ae_assert(ae_isfinite(shft->ptr.p_double[i], _state), "xccAddPOWCCOrthogonalNoncanonic: Shft[] contains infinite values", _state); + } + ae_assert(ae_isfinite(theta, _state), "xccAddPOWCCOrthogonalNoncanonic: theta is not a finite number", _state); + vs = (double)(0); + for(i=0; i<=kpow-1; i++) + { + ae_assert(ae_isfinite(alphapow->ptr.p_double[i], _state), "xccAddPOWCCOrthogonalNoncanonic: AlphaPow[] contains INF/NAN values", _state); + ae_assert(ae_fp_greater(alphapow->ptr.p_double[i],(double)(0))&&ae_fp_less_eq(alphapow->ptr.p_double[i],(double)(1)), "xccAddPOWCCOrthogonalNoncanonic: AlphaPow[] is outside of (0,1]", _state); + vs = vs+alphapow->ptr.p_double[i]; + } + ae_assert(ae_fp_greater(vs,(double)(0))&&ae_fp_less_eq(vs,(double)1+(double)(10*kpow)*ae_machineepsilon), "xccAddPOWCCOrthogonalNoncanonic: AlphaPow[] sum is is outside of (0,1]", _state); + c = (xconicconstraint*)ae_malloc(sizeof(xconicconstraint), _state); /* note: using c as a temporary prior to assigning its value to _c */ + memset(c, 0, sizeof(xconicconstraint)); + _xconicconstraint_init(c, _state, ae_false); + ae_smart_ptr_assign(&_c, c, ae_true, ae_true, (ae_int_t)sizeof(xconicconstraint), _xconicconstraint_init_copy, _xconicconstraint_destroy); + c->conetype = xccgenericorthogonalpowerconetype(_state); + c->nvars = nvars; + c->kpow = kpow; + c->applyorigin = applyorigin; + icopyallocv(nvars, varidx, &c->varidx, _state); + rcopyallocv(nvars, diag, &c->diaga, _state); + rallocv(nvars+1, &c->shftc, _state); + rcopyv(nvars, shft, &c->shftc, _state); + c->shftc.ptr.p_double[nvars] = theta*theta; + rcopyallocv(kpow, alphapow, &c->alphapow, _state); + ae_obj_array_append_transfer(&xcc->constraints, &_c, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Factors out non-axial variable K0 from a conic constraint by making a +substitution X[k0]:=alpha0 + alpha1*X[k1]. Both K0 and K1 must be non-axial +variables. If Alpha1 is zero, then K1 must be equal to -1. + +Returns: +* HadK0 - True if K0 was found in the original (unmodified) VarIdx[]. + If HadK0=False it means that no modification was applied. +* HadK1 - True if K1 was found in the original (unmodified) VarIdx[] + +Works with the following cones: +* xccPrimitiveConeType() + + -- ALGLIB -- + Copyright 01.11.2024 by Bochkanov Sergey +*************************************************************************/ +void xccfactoroutnonaxial(xconicconstraint* c, + ae_int_t k0, + double alpha0, + double alpha1, + ae_int_t k1, + ae_bool* hadk0, + ae_bool* hadk1, + ae_state *_state) +{ + ae_int_t nv; + ae_int_t nradial; + ae_int_t localk0; + ae_int_t localk1; + ae_int_t j; + double a0; + double a1; + double c0; + double c1; + double f; + double g; + double h; + + *hadk0 = ae_false; + *hadk1 = ae_false; + + nv = c->nvars; + *hadk0 = ae_false; + *hadk1 = ae_false; + if( nv==0 ) + { + return; + } + if( c->conetype==xccprimitiveconetype(_state)||c->conetype==xccprimitivepowerconetype(_state) ) + { + + /* + * Analyze cone + */ + nradial = -1; + if( c->conetype==xccprimitiveconetype(_state) ) + { + nradial = nv-1; + ae_assert(c->varidx.ptr.p_int[nv-1]!=k0&&c->varidx.ptr.p_int[nv-1]!=k1, "xccFactorOutNonAxial: K0 or K1 is an axial variable for the cone", _state); + } + if( c->conetype==xccprimitivepowerconetype(_state) ) + { + nradial = nv-c->kpow; + ae_assert(!ilinearsearchispresent(&c->varidx, nradial, nv, k0, _state)&&!ilinearsearchispresent(&c->varidx, nradial, nv, k1, _state), "xccFactorOutNonAxial: K0 or K1 is an axial variable for the power cone", _state); + } + ae_assert(nradial>=1, "xccFactorOutNonAxial: unrecognized cone type", _state); + + /* + * Determine variable locations in the array + * Quick exit if variable K0 is not found + */ + localk0 = -1; + localk1 = -1; + for(j=0; j<=nradial-1; j++) + { + if( c->varidx.ptr.p_int[j]==k0 ) + { + localk0 = j; + } + if( c->varidx.ptr.p_int[j]==k1 ) + { + localk1 = j; + } + } + *hadk0 = localk0>=0; + *hadk1 = localk1>=0; + if( localk0<0 ) + { + return; + } + if( ae_fp_eq(alpha1,(double)(0)) ) + { + ae_assert(k1==-1, "xccFactorOutNonAxial: alpha1=0, but K1 is different from -1", _state); + c->shftc.ptr.p_double[nv] = c->shftc.ptr.p_double[nv]+ae_sqr(c->diaga.ptr.p_double[localk0]*alpha0+c->shftc.ptr.p_double[localk0], _state); + for(j=localk0; j<=nv-2; j++) + { + c->varidx.ptr.p_int[j] = c->varidx.ptr.p_int[j+1]; + c->diaga.ptr.p_double[j] = c->diaga.ptr.p_double[j+1]; + c->shftc.ptr.p_double[j] = c->shftc.ptr.p_double[j+1]; + } + c->shftc.ptr.p_double[nv-1] = c->shftc.ptr.p_double[nv]; + c->nvars = nv-1; + return; + } + ae_assert(k1>=0, "xccFactorOutNonAxial: alpha1<>0, but K1 negative", _state); + + /* + * Different algorithms for K1 being present or absent + */ + if( localk1<0 ) + { + + /* + * The element K1 is not present, we can simply replace K0 by K1 as follows. Let A0 and + * C0 are multiplier and shift for K0. Substituting Xk0:=Alpha0+Xk1*Alpha1 gives us + * + * (A0*Xk0+C0)^2 = + * = (A0*(Alpha0+Xk1*Alpha1)+C0)^2 = + * = (A0*Alpha1*Xk1+(C0+A0*Alpha0))^2 + */ + a0 = c->diaga.ptr.p_double[localk0]; + c0 = c->shftc.ptr.p_double[localk0]; + c->varidx.ptr.p_int[localk0] = k1; + c->diaga.ptr.p_double[localk0] = a0*alpha1; + c->shftc.ptr.p_double[localk0] = c0+a0*alpha0; + tagsortmiddleirr(&c->varidx, &c->diaga, &c->shftc, 0, nradial, _state); + } + else + { + + /* + * The element K1 is present. + * + * Let A0 and C0 are multiplier and shift for K0, and similarly A1 and C1 are multiplier + * and shift for K1. Substituting Xk0:=Alpha0+Xk1*Alpha1 gives us + * + * (A0*Xk0+C0)^2 + (A1*Xk1+C1)^2 = + * = (A0*(Alpha0+Xk1*Alpha1)+C0)^2 + (A1*Xk1+C1)^2 = + * = (A0*Alpha1*Xk1+C0+A0*Alpha0)^2 + (A1*Xk1+C1)^2 = + * = (A0*Alpha1)^2*Xk1^2 + 2*(A0*Alpha1)*(C0+A0*Alpha0)*Xk1 + (C0+A0*Alpha0)^2 + A1^2*Xk1^2 + 2*A1*C1*Xk1 + C1^2 = + * = ((A0*Alpha1)^2+A1^2)*Xk1^2 + 2*((A0*Alpha1)*(C0+A0*Alpha0)+A1*C1)*Xk1 + ((C0+A0*Alpha0)^2+C1^2) = + * = f^2*Xk1^2 + 2*g*Xk1 + h = + * = (f*Xk1)^2 + 2*(g/f)*(f*Xk1) + (g/f)^2 + h-(g/f)^2 = + * = (f*Xk1 + g/f)^2 + h-(g/f)^2 + * + * Modify coefficients for K1. + */ + a0 = c->diaga.ptr.p_double[localk0]; + a1 = c->diaga.ptr.p_double[localk1]; + c0 = c->shftc.ptr.p_double[localk0]; + c1 = c->shftc.ptr.p_double[localk1]; + f = ae_sqrt(a0*alpha1*(a0*alpha1)+a1*a1, _state); + g = a0*alpha1*(c0+a0*alpha0)+a1*c1; + h = (c0+a0*alpha0)*(c0+a0*alpha0)+c1*c1; + ae_assert(ae_fp_greater(f,(double)(0)), "xccFactorOutNonAxial: diagonal term is zero", _state); + c->diaga.ptr.p_double[localk1] = f; + c->shftc.ptr.p_double[localk1] = g/f; + c->shftc.ptr.p_double[nv] = c->shftc.ptr.p_double[nv]+ae_maxreal(h-g/f*(g/f), 0.0, _state); + + /* + * Remove K0 + */ + for(j=localk0; j<=nv-2; j++) + { + c->varidx.ptr.p_int[j] = c->varidx.ptr.p_int[j+1]; + c->diaga.ptr.p_double[j] = c->diaga.ptr.p_double[j+1]; + c->shftc.ptr.p_double[j] = c->shftc.ptr.p_double[j+1]; + } + c->shftc.ptr.p_double[nv-1] = c->shftc.ptr.p_double[nv]; + c->nvars = nv-1; + } + return; + } + ae_assert(ae_false, "xccFactorOutNonAxial: unexpected cone type", _state); +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones), paying special +attention to box constraints (output is always feasible; active constraints +are mapped to active ones). + +Can handle batch requests. + +Parameters: + XS array[N*BatchSize] - scaled variables. The function + assumes that vars are feasible with respect to SCALED + box constraints. + SclFiniteBndL, + SclFiniteBndU array[N], lower/upper bounds for SCALED variables with + infinities being replaced by big numbers + RawFiniteBndL, + RawFiniteBndU array[N], lower/upper bounds for ORIGINAL variables with + infinities being replaced by big numbers + +output: + XU array[N*BatchSize], vars after unscaling +*************************************************************************/ +void unscalexbatchfinitebnd(/* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Real */ const ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* sclfinitebndl, + /* Real */ const ae_vector* sclfinitebndu, + /* Real */ const ae_vector* rawfinitebndl, + /* Real */ const ae_vector* rawfinitebndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double vs; + + + if( optserv_unscalexbatchfinitebndkernel(xs, batchsize, s, n, sclfinitebndl, sclfinitebndu, rawfinitebndl, rawfinitebndu, xu, _state) ) + { + return; + } + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=n-1; j++) + { + i = k*n+j; + vs = xs->ptr.p_double[i]; + if( vs<=sclfinitebndl->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = rawfinitebndl->ptr.p_double[j]; + continue; + } + if( vs>=sclfinitebndu->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = rawfinitebndu->ptr.p_double[j]; + continue; + } + xu->ptr.p_double[i] = vs*s->ptr.p_double[j]; + if( xu->ptr.p_double[i]ptr.p_double[j] ) + { + xu->ptr.p_double[i] = rawfinitebndl->ptr.p_double[j]; + } + if( xu->ptr.p_double[i]>rawfinitebndu->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = rawfinitebndu->ptr.p_double[j]; + } + } + } +} + + +/************************************************************************* +This function calculates feasibility error (square root of sum of squared +errors) for a Kx(NMain+NSlack) system of linear equalities. + +INPUT PARAMETERS: + CE - set of K equality constraints, array[K,NMain+NSlack+1] + X - candidate point, array [NMain+NSlack] + NMain - number of primary variables + NSlack - number of slack variables + K - number of constraints + Tmp0 - possible preallocated buffer, automatically resized + +RESULT: + Sqrt(SUM(Err^2)) + + -- ALGLIB -- + Copyright 17.09.2015 by Bochkanov Sergey +*************************************************************************/ +static double optserv_feasibilityerror(/* Real */ const ae_matrix* ce, + /* Real */ const ae_vector* x, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t k, + /* Real */ ae_vector* tmp0, + ae_state *_state) +{ + ae_int_t i; + double result; + + + rvectorsetlengthatleast(tmp0, k, _state); + for(i=0; i<=k-1; i++) + { + tmp0->ptr.p_double[i] = -ce->ptr.pp_double[i][nmain+nslack]; + } + rmatrixgemv(k, nmain+nslack, 1.0, ce, 0, 0, 0, x, 0, 1.0, tmp0, 0, _state); + result = 0.0; + for(i=0; i<=k-1; i++) + { + result = result+tmp0->ptr.p_double[i]*tmp0->ptr.p_double[i]; + } + result = ae_sqrt(result, _state); + return result; +} + + +/************************************************************************* +This function calculates feasibility error (square root of sum of squared +errors) for a Kx(NMain+NSlack) system of linear equalities and error +gradient (with respect to x) + +INPUT PARAMETERS: + CE - set of K equality constraints, array[K,NMain+NSlack+1] + X - candidate point, array [NMain+NSlack] + NMain - number of primary variables + NSlack - number of slack variables + K - number of constraints + Grad - preallocated array[NMain+NSlack] + Tmp0 - possible preallocated buffer, automatically resized + +RESULT: + Err - Sqrt(SUM(Err^2)) + Grad - error gradient with respect to X, array[NMain+NSlack] + + -- ALGLIB -- + Copyright 17.09.2015 by Bochkanov Sergey +*************************************************************************/ +static void optserv_feasibilityerrorgrad(/* Real */ const ae_matrix* ce, + /* Real */ const ae_vector* x, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t k, + double* err, + /* Real */ ae_vector* grad, + /* Real */ ae_vector* tmp0, + ae_state *_state) +{ + ae_int_t i; + double v; + + *err = 0.0; + + ae_assert(grad->cnt>=nmain+nslack, "FeasibilityErrorGrad: integrity check failed", _state); + rvectorsetlengthatleast(tmp0, k, _state); + rmatrixgemv(k, nmain+nslack, 1.0, ce, 0, 0, 0, x, 0, 0.0, tmp0, 0, _state); + *err = 0.0; + for(i=0; i<=k-1; i++) + { + v = tmp0->ptr.p_double[i]-ce->ptr.pp_double[i][nmain+nslack]; + tmp0->ptr.p_double[i] = v; + *err = *err+v*v; + } + *err = ae_sqrt(*err, _state); + rmatrixgemv(nmain+nslack, k, 1.0, ce, 0, 0, 1, tmp0, 0, 0.0, grad, 0, _state); +} + + +/************************************************************************* +This subroutine checks C0 continuity and returns continuity rating +(normalized value, with values above 50-500 being good indication of the +discontinuity) and Lipschitz constant. + +An interval between F1 and F2 is tested for (dis)continuity. Per-point +noise estimates are provided. Delta[i] is a step from F[i] to F[i+1]. + +ApplySpecialCorrection parameter should be set to True if you use this +function to estimate continuity of the model around minimum; it adds +special correction which helps to detect "max(0,1/x)"-like discontinuities. +Without this correction algorithm will still work, but will be a bit less +powerful. Do not use this correction for situations when you want to +estimate continuity around some non-extremal point - it may result in +spurious discontinuities being reported. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +static void optserv_testc0continuity(double f0, + double f1, + double f2, + double f3, + double noise0, + double noise1, + double noise2, + double noise3, + double delta0, + double delta1, + double delta2, + ae_bool applyspecialcorrection, + double* rating, + double* lipschitz, + ae_state *_state) +{ + double lipschitz01; + double lipschitz12; + double lipschitz23; + + *rating = 0.0; + *lipschitz = 0.0; + + + /* + * Compute Lipschitz constant for the interval [0,1], + * add noise correction in order to get increased estimate (makes + * comparison below more conservative). + */ + lipschitz01 = (ae_fabs(f1-f0, _state)+(noise0+noise1))/delta0; + + /* + * Compute Lipschitz constant for the interval [StpIdx+1,StpIdx+2], + * SUBTRACT noise correction in order to get decreased estimate (makes + * comparison below more conservative). + */ + lipschitz12 = ae_maxreal(ae_fabs(f2-f1, _state)-(noise1+noise2), 0.0, _state)/delta1; + + /* + * Compute Lipschitz constant for the interval [StpIdx+2,StpIdx+3] + * using special algorithm: + * a) if F3(double)0, "OptGuard: integrity check failed", _state); + *rating = lipschitz12/ae_maxreal(lipschitz01, lipschitz23, _state); + *lipschitz = lipschitz12; +} + + +/************************************************************************* +This subroutine checks C1 continuity using test #0 (function values from +the line search log are studied, gradient is not used). + +An interval between F[StpIdx+0] and F[StpIdx+5]is tested for continuity. +An normalized error metric (Lipschitz constant growth for the derivative) +for the interval in question is calculated. Values above 50 are a good +indication of the discontinuity. + +A six-point algorithm is used for testing, so we expect that Monitor.F and +Monitor.Stp have enough points for this test. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +static void optserv_c1continuitytest0(smoothnessmonitor* monitor, + ae_int_t funcidx, + ae_int_t stpidx, + ae_int_t sortedcnt, + ae_state *_state) +{ + double f0; + double f1; + double f2; + double f3; + double f4; + double f5; + double noise0; + double noise1; + double noise2; + double noise3; + double noise4; + double noise5; + double delta0; + double delta1; + double delta2; + double delta3; + double delta4; + double d0; + double d1; + double d2; + double d3; + double newnoise0; + double newnoise1; + double newnoise2; + double newnoise3; + double newdelta0; + double newdelta1; + double newdelta2; + double rating; + double lipschitz; + double lengthrating; + ae_int_t i; + ae_int_t n; + double nrm; + + + n = monitor->n; + ae_assert(stpidx+5sortedstp.ptr.p_double[0],(double)(0)), "C1ContinuityTest0: integrity check failed", _state); + ae_assert(ae_fp_greater(monitor->sortedstp.ptr.p_double[sortedcnt-1],(double)(0)), "C1ContinuityTest0: integrity check failed", _state); + + /* + * Fetch F, noise, Delta's + */ + f0 = monitor->f.ptr.p_double[stpidx+0]; + f1 = monitor->f.ptr.p_double[stpidx+1]; + f2 = monitor->f.ptr.p_double[stpidx+2]; + f3 = monitor->f.ptr.p_double[stpidx+3]; + f4 = monitor->f.ptr.p_double[stpidx+4]; + f5 = monitor->f.ptr.p_double[stpidx+5]; + noise0 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f0, _state), 1.0, _state); + noise1 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f1, _state), 1.0, _state); + noise2 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f2, _state), 1.0, _state); + noise3 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f3, _state), 1.0, _state); + noise4 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f4, _state), 1.0, _state); + noise5 = optserv_ognoiselevelf*ae_maxreal(ae_fabs(f5, _state), 1.0, _state); + delta0 = monitor->sortedstp.ptr.p_double[stpidx+1]-monitor->sortedstp.ptr.p_double[stpidx+0]; + delta1 = monitor->sortedstp.ptr.p_double[stpidx+2]-monitor->sortedstp.ptr.p_double[stpidx+1]; + delta2 = monitor->sortedstp.ptr.p_double[stpidx+3]-monitor->sortedstp.ptr.p_double[stpidx+2]; + delta3 = monitor->sortedstp.ptr.p_double[stpidx+4]-monitor->sortedstp.ptr.p_double[stpidx+3]; + delta4 = monitor->sortedstp.ptr.p_double[stpidx+5]-monitor->sortedstp.ptr.p_double[stpidx+4]; + + /* + * Differentiate functions, get derivative values and noise + * estimates at points (0+1)/2, (1+2)/2, (3+4)/2, (3+4)/2, + * (4+5)/2. Compute new step values NewDelta[i] and new + * noise estimates. + */ + d0 = (f1-f0)/delta0; + d1 = (f2-f1)/delta1; + d2 = (f4-f3)/delta3; + d3 = (f5-f4)/delta4; + newnoise0 = (noise0+noise1)/delta0; + newnoise1 = (noise1+noise2)/delta1; + newnoise2 = (noise3+noise4)/delta3; + newnoise3 = (noise4+noise5)/delta4; + newdelta0 = 0.5*(delta0+delta1); + newdelta1 = 0.5*delta1+delta2+0.5*delta3; + newdelta2 = 0.5*(delta3+delta4); + + /* + * Test with C0 continuity tester. "Special correction" is + * turned off for this test. + */ + optserv_testc0continuity(d0, d1, d2, d3, newnoise0, newnoise1, newnoise2, newnoise3, newdelta0, newdelta1, newdelta2, ae_false, &rating, &lipschitz, _state); + + /* + * Store results + */ + if( rating>optserv_ogminrating1 ) + { + + /* + * Store to total report + */ + monitor->rep.nonc1test0positive = ae_true; + if( rating>monitor->nonc1currentrating ) + { + monitor->nonc1currentrating = rating; + monitor->rep.nonc1suspected = ae_true; + monitor->rep.nonc1lipschitzc = lipschitz; + monitor->rep.nonc1fidx = funcidx; + } + + /* + * Store to "strongest" report + */ + if( rating>monitor->nonc1test0strrating ) + { + monitor->nonc1test0strrating = rating; + monitor->nonc1test0strrep.positive = ae_true; + monitor->nonc1test0strrep.fidx = funcidx; + monitor->nonc1test0strrep.n = n; + monitor->nonc1test0strrep.cnt = sortedcnt; + monitor->nonc1test0strrep.stpidxa = stpidx+1; + monitor->nonc1test0strrep.stpidxb = stpidx+4; + monitor->nonc1test0strrep.inneriter = monitor->linesearchinneridx; + monitor->nonc1test0strrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc1test0strrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc1test0strrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc1test0strrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc1test0strrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc1test0strrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc1test0strrep.f, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc1test0strrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc1test0strrep.f.ptr.p_double[i] = monitor->f.ptr.p_double[i]; + } + } + + /* + * Store to "longest" report + */ + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = nrm+ae_sqr(monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]-monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[sortedcnt-1]*n+i], _state); + } + nrm = ae_sqrt(nrm, _state); + nrm = coalesce(nrm, ae_machineepsilon, _state); + lengthrating = nrm; + if( lengthrating>monitor->nonc1test0lngrating ) + { + monitor->nonc1test0lngrating = lengthrating; + monitor->nonc1test0lngrep.positive = ae_true; + monitor->nonc1test0lngrep.fidx = funcidx; + monitor->nonc1test0lngrep.n = n; + monitor->nonc1test0lngrep.cnt = sortedcnt; + monitor->nonc1test0lngrep.stpidxa = stpidx+1; + monitor->nonc1test0lngrep.stpidxb = stpidx+4; + monitor->nonc1test0lngrep.inneriter = monitor->linesearchinneridx; + monitor->nonc1test0lngrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc1test0lngrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc1test0lngrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc1test0lngrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc1test0lngrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc1test0lngrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc1test0lngrep.f, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc1test0lngrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc1test0lngrep.f.ptr.p_double[i] = monitor->f.ptr.p_double[i]; + } + } + } +} + + +/************************************************************************* +This subroutine checks C1 continuity using test #1 (individual gradient +components from the line search log are studied for continuity). + +An interval between F[StpIdx+0] and F[StpIdx+3]is tested for continuity. +An normalized error metric (Lipschitz constant growth for the derivative) +for the interval in question is calculated. Values above 50 are a good +indication of the discontinuity. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +static void optserv_c1continuitytest1(smoothnessmonitor* monitor, + ae_int_t funcidx, + ae_int_t stpidx, + ae_int_t sortedcnt, + ae_state *_state) +{ + ae_int_t i; + ae_int_t varidx; + ae_int_t n; + double f0; + double f1; + double f2; + double f3; + double noise0; + double noise1; + double noise2; + double noise3; + double nrm; + double rating; + double lengthrating; + double lipschitz; + + + n = monitor->n; + ae_assert(stpidx+3sortedstp.ptr.p_double[0],(double)(0)), "C1ContinuityTest1: integrity check failed", _state); + ae_assert(ae_fp_greater(monitor->sortedstp.ptr.p_double[sortedcnt-1],(double)(0)), "C1ContinuityTest1: integrity check failed", _state); + + /* + * Study each component of the gradient in the interval in question + */ + for(varidx=0; varidx<=n-1; varidx++) + { + f0 = monitor->g.ptr.p_double[(stpidx+0)*n+varidx]; + f1 = monitor->g.ptr.p_double[(stpidx+1)*n+varidx]; + f2 = monitor->g.ptr.p_double[(stpidx+2)*n+varidx]; + f3 = monitor->g.ptr.p_double[(stpidx+3)*n+varidx]; + noise0 = optserv_ognoiselevelg*ae_maxreal(ae_fabs(f0, _state), 1.0, _state); + noise1 = optserv_ognoiselevelg*ae_maxreal(ae_fabs(f1, _state), 1.0, _state); + noise2 = optserv_ognoiselevelg*ae_maxreal(ae_fabs(f2, _state), 1.0, _state); + noise3 = optserv_ognoiselevelg*ae_maxreal(ae_fabs(f3, _state), 1.0, _state); + optserv_testc0continuity(f0, f1, f2, f3, noise0, noise1, noise2, noise3, monitor->sortedstp.ptr.p_double[stpidx+1]-monitor->sortedstp.ptr.p_double[stpidx+0], monitor->sortedstp.ptr.p_double[stpidx+2]-monitor->sortedstp.ptr.p_double[stpidx+1], monitor->sortedstp.ptr.p_double[stpidx+3]-monitor->sortedstp.ptr.p_double[stpidx+2], ae_false, &rating, &lipschitz, _state); + + /* + * Store results + */ + if( rating>optserv_ogminrating1 ) + { + + /* + * Store to total report + */ + monitor->rep.nonc1test1positive = ae_true; + if( rating>monitor->nonc1currentrating ) + { + monitor->nonc1currentrating = rating; + monitor->rep.nonc1suspected = ae_true; + monitor->rep.nonc1lipschitzc = lipschitz; + monitor->rep.nonc1fidx = funcidx; + } + + /* + * Store to "strongest" report + */ + if( rating>monitor->nonc1test1strrating ) + { + monitor->nonc1test1strrating = rating; + monitor->nonc1test1strrep.positive = ae_true; + monitor->nonc1test1strrep.fidx = funcidx; + monitor->nonc1test1strrep.vidx = varidx; + monitor->nonc1test1strrep.n = n; + monitor->nonc1test1strrep.cnt = sortedcnt; + monitor->nonc1test1strrep.stpidxa = stpidx+0; + monitor->nonc1test1strrep.stpidxb = stpidx+3; + monitor->nonc1test1strrep.inneriter = monitor->linesearchinneridx; + monitor->nonc1test1strrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc1test1strrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc1test1strrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc1test1strrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc1test1strrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc1test1strrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc1test1strrep.g, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc1test1strrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc1test1strrep.g.ptr.p_double[i] = monitor->g.ptr.p_double[i*n+varidx]; + } + } + + /* + * Store to "longest" report + */ + nrm = (double)(0); + for(i=0; i<=n-1; i++) + { + nrm = nrm+ae_sqr(monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]-monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[sortedcnt-1]*n+i], _state); + } + nrm = ae_sqrt(nrm, _state); + nrm = coalesce(nrm, ae_machineepsilon, _state); + lengthrating = nrm; + if( lengthrating>monitor->nonc1test1lngrating ) + { + monitor->nonc1test1lngrating = lengthrating; + monitor->nonc1test1lngrep.positive = ae_true; + monitor->nonc1test1lngrep.fidx = funcidx; + monitor->nonc1test1lngrep.vidx = varidx; + monitor->nonc1test1lngrep.n = n; + monitor->nonc1test1lngrep.cnt = sortedcnt; + monitor->nonc1test1lngrep.stpidxa = stpidx+0; + monitor->nonc1test1lngrep.stpidxb = stpidx+3; + monitor->nonc1test1lngrep.inneriter = monitor->linesearchinneridx; + monitor->nonc1test1lngrep.outeriter = monitor->linesearchouteridx; + rvectorsetlengthatleast(&monitor->nonc1test1lngrep.x0, n, _state); + rvectorsetlengthatleast(&monitor->nonc1test1lngrep.d, n, _state); + for(i=0; i<=n-1; i++) + { + monitor->nonc1test1lngrep.x0.ptr.p_double[i] = monitor->enqueuedx.ptr.p_double[monitor->sortedidx.ptr.p_int[0]*n+i]; + monitor->nonc1test1lngrep.d.ptr.p_double[i] = monitor->dcur.ptr.p_double[i]; + } + rvectorsetlengthatleast(&monitor->nonc1test1lngrep.stp, sortedcnt, _state); + rvectorsetlengthatleast(&monitor->nonc1test1lngrep.g, sortedcnt, _state); + for(i=0; i<=sortedcnt-1; i++) + { + monitor->nonc1test1lngrep.stp.ptr.p_double[i] = monitor->sortedstp.ptr.p_double[i]; + monitor->nonc1test1lngrep.g.ptr.p_double[i] = monitor->g.ptr.p_double[i*n+varidx]; + } + } + } + } +} + + +/************************************************************************* +Removes oldest update pair from the limited memory Hessian model and +invalidates Hessian model + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_popfrontxy(xbfgshessian* hess, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(hess->htype==3||hess->htype==4, "PopFrontXY: Hessian mode is not supported", _state); + if( hess->memlen==0 ) + { + return; + } + for(i=0; i<=hess->memlen-2; i++) + { + rcopyrr(hess->n, &hess->s, i+1, &hess->s, i, _state); + rcopyrr(hess->n, &hess->y, i+1, &hess->y, i, _state); + } + if( hess->htype==3 ) + { + for(i=0; i<=hess->memlen-2; i++) + { + for(j=0; j<=hess->memlen-2; j++) + { + hess->lowranksst.ptr.pp_double[i][j] = hess->lowranksst.ptr.pp_double[i+1][j+1]; + hess->lowranksyt.ptr.pp_double[i][j] = hess->lowranksyt.ptr.pp_double[i+1][j+1]; + } + } + } + hess->memlen = hess->memlen-1; + optserv_resetlowrankmodel(hess, _state); +} + + +/************************************************************************* +Lowe-level Hessian update function, to be used by HessianUpdate() + +INPUT PARAMETERS: + Hess - Hessian state + H - specific Hessian matrix to update, usually one + of the Hess fields + X0, G0 - point #0 and gradient at #0, array[N] + X1, G1 - point #1 and gradient at #1, array[N] + +OUTPUT PARAMETERS: + Status - sets update status (informative) + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_hessianupdatelowlevel(xbfgshessian* hess, + /* Real */ ae_matrix* h, + /* Real */ const ae_vector* sk, + /* Real */ const ae_vector* yk, + ae_int_t* status, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double shs; + double sy; + double snrm2; + double hsnrm2; + double ynrm2; + double ski; + double yki; + double mxs; + double mxy; + double mxhs; + double mxd; + double big; + + *status = 0; + + n = hess->n; + *status = 0; + big = (double)1/hess->reg; + + /* + * Perform preliminary analysis + */ + rvectorsetlengthatleast(&hess->hsk, n, _state); + rmatrixgemv(n, n, 1.0, h, 0, 0, 0, sk, 0, 0.0, &hess->hsk, 0, _state); + shs = (double)(0); + sy = (double)(0); + snrm2 = (double)(0); + ynrm2 = (double)(0); + mxs = (double)(0); + mxy = (double)(0); + mxhs = (double)(0); + hsnrm2 = (double)(0); + mxd = (double)(0); + for(i=0; i<=n-1; i++) + { + ski = sk->ptr.p_double[i]; + yki = yk->ptr.p_double[i]; + shs = shs+ski*hess->hsk.ptr.p_double[i]; + sy = sy+ski*yki; + snrm2 = snrm2+ski*ski; + ynrm2 = ynrm2+yki*yki; + mxs = ae_maxreal(mxs, ae_fabs(ski, _state), _state); + mxy = ae_maxreal(mxy, ae_fabs(yki, _state), _state); + mxhs = ae_maxreal(mxhs, ae_fabs(hess->hsk.ptr.p_double[i], _state), _state); + hsnrm2 = hsnrm2+ae_sqr(hess->hsk.ptr.p_double[i], _state); + mxd = ae_maxreal(mxd, ae_fabs(h->ptr.pp_double[i][i], _state), _state); + } + + /* + * Completely skip updates with too short steps and degenerate updates + * + * NOTE: may prevent us from updating Hessian near the solution + */ + if( ae_fp_less_eq(mxs,hess->stpshort) ) + { + + /* + * Sk is too small + */ + return; + } + if( ae_fp_eq(hsnrm2,(double)(0)) ) + { + + /* + * H*Sk is exactly zero, exit + */ + return; + } + if( ae_fp_less_eq(shs,(double)(0))||ae_fp_less_eq(shs,mxs*mxd*mxs*hess->microreg) ) + { + + /* + * Sk'*H*Sk is too small. + * + * Apply regularization to Hessian before exiting + */ + ae_assert(ae_fp_greater(hsnrm2,(double)(0)), "UpdateHessian: integrity check failed", _state); + rmatrixger(n, n, h, 0, 0, hess->reg/hsnrm2, &hess->hsk, 0, &hess->hsk, 0, _state); + return; + } + + /* + * First, we discard Hessian components which give non-zero product with Sk. + * + * We apply some damping in order to avoid problems arising with very small + * Sk'*H*Sk, and we apply some regularization term in order to have Sk'*Hnew*Sk + * still slightly larger than zero. + * + * Traditional BFGS update adds -(Hk*Sk)*(Hk*Sk)'/(Sk'*H*Sk). We use + * modified, more robust formula (below Z=(H*Sk)/|H*Sk|) + * + * ( (H*Sk,H*Sk) ) + * ( - --------------------------------------------------------- + Reg ) * Z * Z' + * ( Sk'*H*Sk + Reg*(H*Sk,H*Sk) + MicroReg*(max(H)*max(S))^2 ) + */ + ae_assert(ae_fp_greater(hsnrm2,(double)(0)), "UpdateHessian: integrity check failed", _state); + rmatrixger(n, n, h, 0, 0, -(double)1/(shs+hsnrm2*hess->reg+ae_sqr(mxd*mxs, _state)*hess->microreg)+hess->reg/hsnrm2, &hess->hsk, 0, &hess->hsk, 0, _state); + *status = 1; + + /* + * Before we update Hessian with Yk, decide whether we need this update - or + * maybe it is better to leave Hessian as is, with small curvature along Sk + * (in the latter case we still treat BFGS update as successful). + * + * Traditional BFGS update adds Yk*Yk'/(Sk,Yk) to the Hessian. Instead we + * use modified update (below U=Yk/|Yk|) + * + * (Yk,Yk) + * -------------------------------------- * U * U' + * (Sk,Yk)+Reg*(Yk,Yk)+MicroReg*(Sk,Sk) + */ + if( ae_fp_eq(ynrm2,(double)(0)) ) + { + return; + } + if( ae_fp_less_eq(sy,(double)(0)) ) + { + return; + } + if( ae_fp_greater_eq(ae_sqr(mxy, _state)/sy,big) ) + { + return; + } + ae_assert(ae_fp_greater(sy,(double)(0)), "UpdateHessian: integrity check failed", _state); + rmatrixger(n, n, h, 0, 0, (double)1/(sy+hess->reg*ynrm2+hess->microreg*snrm2), yk, 0, yk, 0, _state); + *status = 2; +} + + +/************************************************************************* +Low-level Hessian update function, to be used by HessianUpdate(). + +Performs no integrity checks. + +INPUT PARAMETERS: + Hess - Hessian state + H - specific Hessian matrix to update, usually one + of the Hess fields + X0, G0 - point #0 and gradient at #0, array[N] + X1, G1 - point #1 and gradient at #1, array[N] + +OUTPUT PARAMETERS: + Status - sets update status (informative) + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_hessianupdatelowlevel2(xbfgshessian* hess, + /* Real */ ae_matrix* h, + /* Real */ const ae_vector* sk, + /* Real */ const ae_vector* yk, + ae_int_t* status, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double shs; + double sy; + double snrm2; + double hsnrm2; + double ynrm2; + double ski; + double yki; + double mxs; + double mxy; + double mxhs; + double mxd; + + *status = 0; + + n = hess->n; + *status = 0; + + /* + * Perform preliminary analysis + */ + rvectorsetlengthatleast(&hess->hsk, n, _state); + rmatrixgemv(n, n, 1.0, h, 0, 0, 0, sk, 0, 0.0, &hess->hsk, 0, _state); + shs = (double)(0); + sy = (double)(0); + snrm2 = (double)(0); + ynrm2 = (double)(0); + mxs = (double)(0); + mxy = (double)(0); + mxhs = (double)(0); + hsnrm2 = (double)(0); + mxd = (double)(0); + for(i=0; i<=n-1; i++) + { + ski = sk->ptr.p_double[i]; + yki = yk->ptr.p_double[i]; + shs = shs+ski*hess->hsk.ptr.p_double[i]; + sy = sy+ski*yki; + snrm2 = snrm2+ski*ski; + ynrm2 = ynrm2+yki*yki; + mxs = ae_maxreal(mxs, ae_fabs(ski, _state), _state); + mxy = ae_maxreal(mxy, ae_fabs(yki, _state), _state); + mxhs = ae_maxreal(mxhs, ae_fabs(hess->hsk.ptr.p_double[i], _state), _state); + hsnrm2 = hsnrm2+ae_sqr(hess->hsk.ptr.p_double[i], _state); + mxd = ae_maxreal(mxd, ae_fabs(h->ptr.pp_double[i][i], _state), _state); + } + + /* + * First, we discard Hessian components which give non-zero product with Sk. + */ + ae_assert(ae_fp_greater(hsnrm2,(double)(0)), "UpdateHessian: integrity check failed", _state); + rmatrixger(n, n, h, 0, 0, -(double)1/shs, &hess->hsk, 0, &hess->hsk, 0, _state); + *status = 1; + ae_assert(ae_fp_greater(sy,(double)(0)), "UpdateHessian: integrity check failed", _state); + rmatrixger(n, n, h, 0, 0, (double)1/sy, yk, 0, yk, 0, _state); + *status = 2; +} + + +/************************************************************************* +Invalidate low-rank model + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_resetlowrankmodel(xbfgshessian* hess, + ae_state *_state) +{ + + + ae_assert(hess->htype==3||hess->htype==4, "OPTSERV: integrity check 9940 failed", _state); + if( hess->htype==3 ) + { + hess->lowrankmodelvalid = ae_false; + hess->lowrankeffdvalid = ae_false; + } + if( hess->htype==4 ) + { + hess->sr1modelvalid = ae_false; + hess->sr1effdvalid = ae_false; + } +} + + +/************************************************************************* +Recomputes low-rank LBFGS or SR1 model + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankmodel(xbfgshessian* hess, + ae_state *_state) +{ + + + ae_assert(hess->htype==3||hess->htype==4, "RecomputeLowRankModel: Hessian mode is not supported", _state); + if( hess->htype==3 ) + { + optserv_recomputelowrankmodellbfgs(hess, _state); + } + if( hess->htype==4 ) + { + optserv_recomputelowrankmodelsr1(hess, _state); + } +} + + +/************************************************************************* +Recomputes low-rank model (DIAG and CORR fields) according to the current +state of the LBFGS memory + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankmodellbfgs(xbfgshessian* hess, + ae_state *_state) +{ + ae_int_t n; + ae_int_t memlen; + ae_int_t i; + ae_int_t j; + double reg; + double mx; + + + ae_assert(hess->htype==3, "RecomputeLowRankModelLBFGS: Hessian mode is not supported", _state); + n = hess->n; + memlen = hess->memlen; + + /* + * If the model is valid, exit. + * Otherwise, recompute it from scratch + */ + if( hess->lowrankmodelvalid ) + { + return; + } + optserv_resetlowrankmodel(hess, _state); + + /* + * Quick exit for MemLen=0. + * After this block we assume that MemLen>0 + */ + if( memlen==0 ) + { + hess->lowrankmodelvalid = ae_true; + hess->lowrankk = 0; + return; + } + + /* + * Prepare RAW_CORR2, a right part of correction matrix + * + * Bk = sigma*I - RAW_CORR2'*RAW_BLOCK*RAW_CORR2 + * + * with RAW_CORR2 being 2MEMLEN*N matrix and RAW_BLOCK being 2MEMLEN*2MEMLEN matrix, + * as defined by equations 2.17 and 3.22 in 'REPRESENTATION OF QUASI-NEWTON MATRICES + * AND THEIR USE IN LIMITED MEMORY METHODS' by Byrd, Nocedal and Schnabel. + * + * The initial form for Bk is + * + * [ ] [ -Dk Lk' ]-1 [ Y ] + * Bk = sigma*I - [ Y' B0*S' ] * [ ] * [ ] + * [ ] [ Lk S*B0*S' ] [ S*B0 ] + * + * with + * + * Lk[i,j]=(Si,Yj) for i>j, 0 otherwise + * Dk = diag[(Si,Yj)] + * + */ + rallocm(2*memlen, n, &hess->corr2, _state); + for(i=0; i<=memlen-1; i++) + { + rcopyrr(n, &hess->s, i, &hess->corr2, memlen+i, _state); + rmulr(n, hess->sigma, &hess->corr2, memlen+i, _state); + rcopyrr(n, &hess->y, i, &hess->corr2, i, _state); + } + + /* + * Start factorizing central block. Whilst it is indefinite, it has + * pretty simple factorization + * + * [ -Dk Lk' ] [ Dk^(0.5) ] [ -I ] [ Dk^(0.5) -Dk^(-0.5)*Lk' ] + * [ ] = [ ] * [ ] * [ ] + * [ Lk S*B0*S' ] [ -Lk*Dk^(-0.5) Jk ] [ +I ] [ Jk' ] + * + * First, we compute lower triangular Jk such that Jk*Jk' = S*B0*S' + Lk*inv(Dk)*Lk' + */ + rallocv(memlen, &hess->buf, _state); + for(i=0; i<=memlen-1; i++) + { + hess->buf.ptr.p_double[i] = (double)1/ae_sqrt(hess->lowranksyt.ptr.pp_double[i][i], _state); + } + rsetallocm(memlen, memlen, 0.0, &hess->invsqrtdlk, _state); + for(i=1; i<=memlen-1; i++) + { + rcopyrr(i, &hess->lowranksyt, i, &hess->invsqrtdlk, i, _state); + rmergemulvr(i, &hess->buf, &hess->invsqrtdlk, i, _state); + } + reg = (double)(0); + mx = (double)(0); + for(;;) + { + + /* + * Try Cholesky decomposition + */ + rcopyallocm(memlen, memlen, &hess->lowranksst, &hess->jk, _state); + rmatrixgemm(memlen, memlen, memlen, 1.0, &hess->invsqrtdlk, 0, 0, 0, &hess->invsqrtdlk, 0, 0, 1, hess->sigma, &hess->jk, 0, 0, _state); + for(i=0; i<=memlen-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(hess->jk.ptr.pp_double[i][i], _state), _state); + hess->jk.ptr.pp_double[i][i] = hess->jk.ptr.pp_double[i][i]+reg; + } + if( spdmatrixcholeskyrec(&hess->jk, 0, memlen, ae_false, &hess->buf, _state) ) + { + break; + } + + /* + * Cholesky decomposition failed, increase regularization + */ + mx = coalesce(mx, ae_machineepsilon, _state); + reg = coalesce((double)10*reg, ae_sqrt(ae_machineepsilon, _state)*mx, _state); + } + + /* + * After computing Jk we proceed to form triangular factorization of the entire block matrix + */ + rsetallocm(2*memlen, 2*memlen, 0.0, &hess->blk, _state); + for(i=0; i<=memlen-1; i++) + { + hess->blk.ptr.pp_double[i][i] = ae_sqrt(hess->lowranksyt.ptr.pp_double[i][i], _state); + } + for(i=0; i<=memlen-1; i++) + { + for(j=0; j<=i-1; j++) + { + hess->blk.ptr.pp_double[memlen+i][j] = -hess->invsqrtdlk.ptr.pp_double[i][j]; + } + } + for(i=0; i<=memlen-1; i++) + { + for(j=0; j<=i; j++) + { + hess->blk.ptr.pp_double[memlen+i][memlen+j] = hess->jk.ptr.pp_double[i][j]; + } + } + + /* + * And finally we merge triangular factor into CORR2 in order to get desired two-factor + * low rank representation without additional middle matrix. This representation is + * computed in CORR2 and unpacked into LowRankCp and LowRankCm ('minus' and 'plus' terms). + */ + rmatrixlefttrsm(2*memlen, n, &hess->blk, 0, 0, ae_false, ae_false, 0, &hess->corr2, 0, 0, _state); + rallocm(memlen, n, &hess->lowrankcp, _state); + for(i=0; i<=memlen-1; i++) + { + rcopyrr(n, &hess->corr2, i, &hess->lowrankcp, i, _state); + } + rallocm(memlen, n, &hess->lowrankcm, _state); + for(i=0; i<=memlen-1; i++) + { + rcopyrr(n, &hess->corr2, memlen+i, &hess->lowrankcm, i, _state); + } + + /* + * The model was created + */ + hess->lowrankmodelvalid = ae_true; + hess->lowrankk = memlen; +} + + +/************************************************************************* +Recomputes low-rank SR1 model + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 09.02.2024 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankmodelsr1(xbfgshessian* hess, + ae_state *_state) +{ + ae_int_t n; + ae_int_t memlen; + ae_int_t i; + ae_int_t j; + double v; + double ev; + double eps; + double scaledsigma; + double stabsigma; + double minimalcurvature; + double absoluteminimum; + + + ae_assert(hess->htype==4, "RecomputeLowRankModelSR1: Hessian mode is not supported", _state); + n = hess->n; + eps = ae_sqrt(ae_machineepsilon, _state); + + /* + * If the model is valid, exit. + * Otherwise, recompute it from scratch + */ + if( hess->sr1modelvalid ) + { + return; + } + optserv_resetlowrankmodel(hess, _state); + + /* + * Rescale S and Y to internal scale, as set in Hess.varScale. + * + * Prepare a low-rank representation of SR1 update with additional orthogonality + * properties. The original form of low-rank SR1 update is + * + * [ ] [ ]-1 [ ] + * Bk = sigma*I + [ Y'- Sigma*S' ] * [ Dk+Lk+Lk' - Sigma*Sk*Sk' ] * [ Y - Sigma*S ] + * [ ] [ ] [ ] + * + * with + * + * Lk[i,j]=(Si,Yj) for i>j, 0 otherwise + * Dk = diag[(Si,Yj)] + * + * as defined by equations 2.17 and 5.2 in 'REPRESENTATION OF QUASI-NEWTON MATRICES + * AND THEIR USE IN LIMITED MEMORY METHODS' by Byrd, Nocedal and Schnabel. + * + * We plan to transform it into + * + * Bk = sigma*I + C'*Z*C + * + * with Z being diagonal with +1 or -1 elements, and C being orthogonal (but not necessarily + * orthonormal) matrices, with some rows maybe being zero. + * + * + * First, we perform initial finiteness assurance (dropping degenerate SR1 updates). This + * function, as defined in 'A study of the limited memory SR1 method in practice' by + * Xuehua Lu, drops degenerate updates and, additionally, returns a decomposition + * + * inv(M) = Lm'*Dm*Lm, with M=Dk+Lk+Lk'-Sigma*Sk*Sk' + * + * An important point is that M=Dk+Lk+Lk'-Sigma*Sk*Sk' is guaranteed to be non-degenerate + * after the finiteness assurance; however, corresponding Y-sigma*S still can have zero rows, + * i.e. be rank-deficient. Thus, operations involving potentially rank-deficient Y-sigma*S + * have to be performed very carefully. + */ + optserv_scaleandperformfinitenessassurance(hess, &hess->tmps, &hess->tmpy, &scaledsigma, &hess->tmpl, &hess->tmpe, &memlen, _state); + absoluteminimum = (double)100*ae_machineepsilon; + minimalcurvature = ae_maxreal(ae_minreal(scaledsigma, hess->mincrv, _state), absoluteminimum, _state); + stabsigma = ae_maxreal(scaledsigma, minimalcurvature, _state); + if( memlen==0 ) + { + hess->sr1modelvalid = ae_true; + hess->sr1k = 0; + hess->sr1nrm2 = ae_fabs(scaledsigma, _state); + hess->sr1nrm2stab = stabsigma; + rsetallocv(n, scaledsigma, &hess->sr1d, _state); + rsetallocv(n, stabsigma, &hess->sr1stabd, _state); + rmergemulv(n, &hess->invscale, &hess->sr1d, _state); + rmergemulv(n, &hess->invscale, &hess->sr1d, _state); + rmergemulv(n, &hess->invscale, &hess->sr1stabd, _state); + rmergemulv(n, &hess->invscale, &hess->sr1stabd, _state); + return; + } + ae_assert(memlen>0&&memlen<=n, "OPTSERV: integrity check 9823 failed", _state); + + /* + * Decompose Y-sigma*S into L*Q with orthogonal Q and lower triangular L and store + * Q to Hess.tmpU (here L is not to be confused with Lk and/or Lm). The factor L + * can have exactly zero rows and/or be rank-deficient. + */ + for(i=0; i<=memlen-1; i++) + { + rcopyrr(n, &hess->tmpy, i, &hess->corr2, i, _state); + raddrr(n, -scaledsigma, &hess->tmps, i, &hess->corr2, i, _state); + } + rmatrixlq(&hess->corr2, memlen, n, &hess->tmptau, _state); + rmatrixlqunpackq(&hess->corr2, memlen, n, &hess->tmptau, memlen, &hess->tmpu, _state); + + /* + * Now we have + * + * Bk = sigma*I + Q'*L'*Lm'*Dm*Lm*L*Q + * + * which can be transformed into + * + * Bk = sigma*I + Q'*(Lm'*L'*Dm*Lm*L)*Q + * = sigma*I + Q'*BLK*Q + */ + for(i=0; i<=memlen-1; i++) + { + for(j=i+1; j<=memlen-1; j++) + { + hess->corr2.ptr.pp_double[i][j] = 0.0; + hess->tmpl.ptr.pp_double[i][j] = 0.0; + } + } + rallocm(memlen, memlen, &hess->blk2, _state); + rmatrixgemm(memlen, memlen, memlen, 1.0, &hess->tmpl, 0, 0, 0, &hess->corr2, 0, 0, 0, 0.0, &hess->blk2, 0, 0, _state); + rcopyallocm(memlen, memlen, &hess->blk2, &hess->blk3, _state); + for(i=0; i<=memlen-1; i++) + { + rmulr(memlen, hess->tmpe.ptr.p_double[i], &hess->blk2, i, _state); + } + rallocm(memlen, memlen, &hess->blk, _state); + rmatrixgemm(memlen, memlen, memlen, 1.0, &hess->blk3, 0, 0, 1, &hess->blk2, 0, 0, 0, 0.0, &hess->blk, 0, 0, _state); + + /* + * Perform eigendecomposition BLK=W*D*W', get + * + * Bk = sigma*I + Q'*BLK*Q + * = sigma*I + Q'*W*D*W'*Q + * = sigma*I + (W'Q)'*D*(W'Q) + * + * then transform diagonal D (not to be confused with Dk) into one + * with +1 or -1 on its diagonal. + * + * Produce both raw and positive definite stabilized updates. + * Compute SR1Nrm2. + */ + hess->sr1nrm2 = ae_fabs(scaledsigma, _state); + hess->sr1nrm2stab = stabsigma; + if( !smatrixevd(&hess->blk, memlen, 1, ae_false, &hess->tmpe, &hess->tmpq, _state) ) + { + ae_assert(ae_false, "HessianGetLowRankStabilizedSR1: eigensolver failure", _state); + } + rallocm(memlen, n, &hess->sr1c, _state); + rmatrixgemm(memlen, n, memlen, 1.0, &hess->tmpq, 0, 0, 1, &hess->tmpu, 0, 0, 0, 0.0, &hess->sr1c, 0, 0, _state); + rallocv(memlen, &hess->sr1z, _state); + rcopyallocm(memlen, n, &hess->sr1c, &hess->sr1stabc, _state); + rallocv(memlen, &hess->sr1stabz, _state); + rsetallocv(n, scaledsigma, &hess->sr1d, _state); + rsetallocv(n, stabsigma, &hess->sr1stabd, _state); + for(i=0; i<=memlen-1; i++) + { + + /* + * Update SR1Nrm2 + */ + hess->sr1nrm2 = ae_maxreal(hess->sr1nrm2, ae_fabs(scaledsigma+hess->tmpe.ptr.p_double[i], _state), _state); + hess->sr1nrm2stab = ae_maxreal(hess->sr1nrm2stab, stabsigma+hess->tmpe.ptr.p_double[i], _state); + + /* + * Produce raw update + */ + ev = hess->tmpe.ptr.p_double[i]; + v = ae_fabs(ev, _state); + v = ae_minreal(v, (ae_fabs(scaledsigma, _state)+(double)1)/eps, _state); + rmulr(n, ae_sqrt(v, _state), &hess->sr1c, i, _state); + hess->sr1z.ptr.p_double[i] = possign(ev, _state); + + /* + * Produce stabilized update + */ + ev = hess->tmpe.ptr.p_double[i]-(stabsigma-scaledsigma); + v = ae_fabs(ev, _state); + v = ae_minreal(v, (ae_fabs(stabsigma, _state)+(double)1)/eps, _state); + if( ae_fp_less(ev,(double)(0)) ) + { + v = ae_minreal(v, stabsigma-minimalcurvature, _state); + } + rmulr(n, ae_sqrt(v, _state), &hess->sr1stabc, i, _state); + hess->sr1stabz.ptr.p_double[i] = possign(ev, _state); + } + hess->sr1k = memlen; + + /* + * Perform unscaling + */ + rmergemulv(n, &hess->invscale, &hess->sr1d, _state); + rmergemulv(n, &hess->invscale, &hess->sr1d, _state); + rmergemulv(n, &hess->invscale, &hess->sr1stabd, _state); + rmergemulv(n, &hess->invscale, &hess->sr1stabd, _state); + for(i=0; i<=hess->sr1k-1; i++) + { + rmergemulvr(n, &hess->invscale, &hess->sr1c, i, _state); + rmergemulvr(n, &hess->invscale, &hess->sr1stabc, i, _state); + } + + /* + * Done + */ + hess->sr1modelvalid = ae_true; +} + + +/************************************************************************* +Filters update pairs Hess.S, Hess.Y for the SR1 model, removing ill-defined +updates. May reorder pairs during the pocess, or drop some or all of them. + + -- ALGLIB -- + Copyright 09.02.2024 by Bochkanov Sergey +*************************************************************************/ +static void optserv_scaleandperformfinitenessassurance(xbfgshessian* hess, + /* Real */ ae_matrix* s, + /* Real */ ae_matrix* y, + double* sigma, + /* Real */ ae_matrix* l, + /* Real */ ae_vector* d, + ae_int_t* filteredlen, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t i0; + ae_int_t i1; + ae_int_t memlen; + ae_int_t n; + ae_int_t wrksize; + double v; + double v0; + double v1; + double costheta; + double lintol; + + + ae_assert(hess->htype==4, "FinitenessAssurance: Hessian mode is not supported", _state); + memlen = hess->memlen; + n = hess->n; + lintol = (double)100*ae_sqrt(ae_machineepsilon, _state); + if( memlen==0 ) + { + *sigma = (double)(1); + *filteredlen = 0; + return; + } + + /* + * Copy and scale S and Y, compute initial scaling factor Sigma (after the variable scaling) + */ + rcopyallocm(hess->m, hess->n, &hess->s, s, _state); + rcopyallocm(hess->m, hess->n, &hess->y, y, _state); + for(i=0; i<=memlen-1; i++) + { + rmergemulvr(n, &hess->invscale, s, i, _state); + rmergemulvr(n, &hess->varscale, y, i, _state); + } + *sigma = rdotrr(n, s, memlen-1, y, memlen-1, _state)/(rdotrr(n, s, memlen-1, s, memlen-1, _state)+ae_machineepsilon*ae_machineepsilon); + if( memlen==1 ) + { + + /* + * There is no need to build an SR1 model for MemLen=1 update because it produces nearly-zero (and + * sometimes degenerate) correction to the original diagonal matrix. + */ + *filteredlen = 0; + return; + } + + /* + * Enforce sufficient linear independence by zeroing out redundant rows. Rows which are exactly zero + * will be dropped during the finiteness assurance iteration. The last row (the most recent update) + * is always retained, that's why we start orthogonalization from the end. + */ + rcopym(memlen, n, &hess->s, &hess->corr2, _state); + for(i=0; i<=memlen-1; i++) + { + rmulr(n, (double)1/coalesce(ae_sqrt(rdotrr(n, &hess->corr2, i, &hess->corr2, i, _state), _state), (double)(1), _state), &hess->corr2, i, _state); + } + for(i=memlen-1; i>=0; i--) + { + v0 = rdotrr(n, &hess->corr2, i, &hess->corr2, i, _state); + if( ae_fp_less(v0,lintol*lintol) ) + { + rsetr(n, 0.0, s, i, _state); + rsetr(n, 0.0, y, i, _state); + rsetr(n, 0.0, &hess->corr2, i, _state); + continue; + } + for(j=i-1; j>=0; j--) + { + raddrr(n, -rdotrr(n, &hess->corr2, i, &hess->corr2, j, _state)/v0, &hess->corr2, i, &hess->corr2, j, _state); + } + } + + /* + * Prepare finiteness assurance iteration + */ + rsetallocm(memlen, memlen, 0.0, l, _state); + rallocv(memlen, d, _state); + for(i=0; i<=memlen-1; i++) + { + rcopyrr(n, y, i, &hess->corr2, i, _state); + raddrr(n, -*sigma, s, i, &hess->corr2, i, _state); + } + rallocm(memlen, memlen, &hess->blk, _state); + rmatrixgemm(memlen, memlen, n, 1.0, s, 0, 0, 0, y, 0, 0, 1, 0.0, &hess->blk, 0, 0, _state); + for(i=0; i<=memlen-1; i++) + { + for(j=0; j<=i-1; j++) + { + hess->blk.ptr.pp_double[j][i] = hess->blk.ptr.pp_double[i][j]; + } + } + rmatrixgemm(memlen, memlen, n, -*sigma, s, 0, 0, 0, s, 0, 0, 1, 1.0, &hess->blk, 0, 0, _state); + + /* + * Iterate until all updates are processed: approved or dropped + */ + rallocv(memlen, &hess->buf, _state); + rallocv(memlen, &hess->buf2, _state); + *filteredlen = 0; + j = 0; + wrksize = hess->memlen; + while(j0 ) + { + rcopyrv(j, &hess->blk, j, &hess->buf, _state); + rgemv(j, j, 1.0, l, 0, &hess->buf, 0.0, &hess->buf2, _state); + rmergedivv(j, d, &hess->buf2, _state); + rgemv(j, j, -1.0, l, 1, &hess->buf2, 0.0, &hess->buf, _state); + rcopyvr(j, &hess->buf, l, j, _state); + } + l->ptr.pp_double[j][j] = 1.0; + d->ptr.p_double[j] = rdotrr(j+1, l, j, &hess->blk, j, _state); + + /* + * Compute cos(theta) as defined by the formula 3.13 of 'A study of the + * limited memory SR1 method in practice' by Xuehua Lu: + * * first, compute v0=norm2(L[0:MemLen-1,J]*CORR2[J,0:N-1]) and v1=norm2(S[J,0:N-1]) + * * then, compute cos(theta)=D[J]/(v0*v1) + */ + v0 = 0.0; + for(i=0; i<=n-1; i++) + { + v = 0.0; + for(k=0; k<=j; k++) + { + v = v+l->ptr.pp_double[j][k]*hess->corr2.ptr.pp_double[k][i]; + } + v0 = v0+v*v; + } + v0 = ae_sqrt(v0, _state); + v1 = ae_sqrt(rdotrr(n, s, j, s, j, _state), _state); + if( ae_fp_neq(d->ptr.p_double[j],(double)(0))&&ae_fp_neq(v0*v1,(double)(0)) ) + { + costheta = d->ptr.p_double[j]/(v0*v1); + } + else + { + costheta = 0.0; + } + + /* + * If CosTheta is too low, swap the last row with the J-th one and update S, Y, BLK, CORR2. + * Otherwise, accept the row. + */ + if( ae_fp_less_eq(ae_fabs(costheta, _state),hess->mincostheta) ) + { + if( j!=wrksize-1 ) + { + for(i0=j; i0<=wrksize-2; i0++) + { + rcopyrr(n, s, i0+1, s, i0, _state); + rcopyrr(n, y, i0+1, y, i0, _state); + rcopyrr(n, &hess->corr2, i0+1, &hess->corr2, i0, _state); + } + for(i0=0; i0<=wrksize-2; i0++) + { + for(i1=0; i1<=wrksize-2; i1++) + { + hess->blk.ptr.pp_double[i0][i1] = hess->blk.ptr.pp_double[icase2(i0ptr.p_double[j] = (double)1/d->ptr.p_double[j]; + } +} + + +/************************************************************************* +Recomputes diagonal of the low-rank model, either LBFGS or SR1 one + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankdiagonal(xbfgshessian* hess, + ae_state *_state) +{ + + + ae_assert(hess->htype==3||hess->htype==4, "RecomputeLowRankDiagonal: Hessian mode is not supported", _state); + if( hess->htype==3 ) + { + optserv_recomputelowrankdiagonalbfgs(hess, _state); + } + if( hess->htype==4 ) + { + optserv_recomputelowrankdiagonalsr1(hess, _state); + } +} + + +/************************************************************************* +Recomputes diagonal of the low-rank model (EFFD) according to the current +state of the LBFGS memory + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankdiagonalbfgs(xbfgshessian* hess, + ae_state *_state) +{ + ae_int_t n; + ae_int_t memlen; + ae_int_t i; + + + ae_assert(hess->htype==3, "RecomputeLowRankDiagonalBFGS: Hessian mode is not supported", _state); + n = hess->n; + memlen = hess->memlen; + + /* + * If the diagonal is valid, exit. + * Otherwise, recompute it from scratch + */ + if( hess->lowrankeffdvalid ) + { + return; + } + optserv_recomputelowrankmodel(hess, _state); + + /* + * Quick exit for MemLen=0 + */ + if( memlen==0 ) + { + hess->lowrankeffdvalid = ae_true; + rsetallocv(n, hess->sigma, &hess->lowrankeffd, _state); + return; + } + + /* + * Assuming MemLen>0 + */ + rsetallocv(n, hess->sigma, &hess->lowrankeffd, _state); + rallocv(n, &hess->buf, _state); + for(i=0; i<=hess->lowrankk-1; i++) + { + rcopyrv(n, &hess->lowrankcp, i, &hess->buf, _state); + rmuladdv(n, &hess->buf, &hess->buf, &hess->lowrankeffd, _state); + rcopyrv(n, &hess->lowrankcm, i, &hess->buf, _state); + rnegmuladdv(n, &hess->buf, &hess->buf, &hess->lowrankeffd, _state); + } + hess->lowrankeffdvalid = ae_true; +} + + +/************************************************************************* +Recomputes diagonal of the low-rank SR1 model + +INPUT PARAMETERS: + Hess - Hessian state + + -- ALGLIB -- + Copyright 28.11.2022 by Bochkanov Sergey +*************************************************************************/ +static void optserv_recomputelowrankdiagonalsr1(xbfgshessian* hess, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + ae_assert(hess->htype==4, "RecomputeLowRankDiagonalSR1: Hessian mode is not supported", _state); + n = hess->n; + if( hess->sr1effdvalid ) + { + return; + } + optserv_recomputelowrankmodelsr1(hess, _state); + if( hess->sr1k==0 ) + { + hess->sr1effdvalid = ae_true; + rcopyallocv(n, &hess->sr1d, &hess->sr1effd, _state); + return; + } + + /* + * Assuming SR1K>0 + */ + rcopyallocv(n, &hess->sr1d, &hess->sr1effd, _state); + rallocv(n, &hess->buf, _state); + for(i=0; i<=hess->sr1k-1; i++) + { + ae_assert(ae_fp_eq(hess->sr1z.ptr.p_double[i]*hess->sr1z.ptr.p_double[i],(double)(1)), "OPTSERV: ingegrity check 3416 failed", _state); + rcopyrv(n, &hess->sr1c, i, &hess->buf, _state); + if( ae_fp_greater(hess->sr1z.ptr.p_double[i],(double)(0)) ) + { + rmuladdv(n, &hess->buf, &hess->buf, &hess->sr1effd, _state); + } + else + { + rnegmuladdv(n, &hess->buf, &hess->buf, &hess->sr1effd, _state); + } + } + hess->sr1effdvalid = ae_true; +} + + +/************************************************************************* +Fast kernel for unscalexbatchfinitebnd() +*************************************************************************/ +static ae_bool optserv_unscalexbatchfinitebndkernel(/* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Real */ const ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* sclfinitebndl, + /* Real */ const ae_vector* sclfinitebndu, + /* Real */ const ae_vector* rawfinitebndl, + /* Real */ const ae_vector* rawfinitebndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +void _precbuflbfgs_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + precbuflbfgs *p = (precbuflbfgs*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->norms, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alpha, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->bufa, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufb, 0, DT_INT, _state, make_automatic); +} + + +void _precbuflbfgs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + precbuflbfgs *dst = (precbuflbfgs*)_dst; + const precbuflbfgs *src = (const precbuflbfgs*)_src; + ae_vector_init_copy(&dst->norms, &src->norms, _state, make_automatic); + ae_vector_init_copy(&dst->alpha, &src->alpha, _state, make_automatic); + ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic); + ae_matrix_init_copy(&dst->yk, &src->yk, _state, make_automatic); + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->bufa, &src->bufa, _state, make_automatic); + ae_vector_init_copy(&dst->bufb, &src->bufb, _state, make_automatic); +} + + +void _precbuflbfgs_clear(void* _p) +{ + precbuflbfgs *p = (precbuflbfgs*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->norms); + ae_vector_clear(&p->alpha); + ae_vector_clear(&p->rho); + ae_matrix_clear(&p->yk); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->bufa); + ae_vector_clear(&p->bufb); +} + + +void _precbuflbfgs_destroy(void* _p) +{ + precbuflbfgs *p = (precbuflbfgs*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->norms); + ae_vector_destroy(&p->alpha); + ae_vector_destroy(&p->rho); + ae_matrix_destroy(&p->yk); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->bufa); + ae_vector_destroy(&p->bufb); +} + + +void _precbuflowrank_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + precbuflowrank *p = (precbuflowrank*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bufz, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bufw, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp, 0, DT_REAL, _state, make_automatic); +} + + +void _precbuflowrank_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + precbuflowrank *dst = (precbuflowrank*)_dst; + const precbuflowrank *src = (const precbuflowrank*)_src; + dst->n = src->n; + dst->k = src->k; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic); + ae_vector_init_copy(&dst->bufc, &src->bufc, _state, make_automatic); + ae_matrix_init_copy(&dst->bufz, &src->bufz, _state, make_automatic); + ae_matrix_init_copy(&dst->bufw, &src->bufw, _state, make_automatic); + ae_vector_init_copy(&dst->tmp, &src->tmp, _state, make_automatic); +} + + +void _precbuflowrank_clear(void* _p) +{ + precbuflowrank *p = (precbuflowrank*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->d); + ae_matrix_clear(&p->v); + ae_vector_clear(&p->bufc); + ae_matrix_clear(&p->bufz); + ae_matrix_clear(&p->bufw); + ae_vector_clear(&p->tmp); +} + + +void _precbuflowrank_destroy(void* _p) +{ + precbuflowrank *p = (precbuflowrank*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->d); + ae_matrix_destroy(&p->v); + ae_vector_destroy(&p->bufc); + ae_matrix_destroy(&p->bufz); + ae_matrix_destroy(&p->bufw); + ae_vector_destroy(&p->tmp); +} + + +void _xbfgshessian_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + xbfgshessian *p = (xbfgshessian*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->varscale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invscale, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hcurrent, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->s, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lowranksst, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lowranksyt, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lowrankcp, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lowrankcm, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lowrankeffd, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sr1c, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sr1d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sr1z, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sr1stabc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sr1stabz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sr1stabd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sr1effd, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hincoming, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hsk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->buf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->buf2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->corr2, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmps, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpy, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->blk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->blk2, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->blk3, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->invsqrtdlk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufvmv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufupdhx, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpunstablec, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpunstables, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpu, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpw, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpsl, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpl, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpe, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmptau, 0, DT_REAL, _state, make_automatic); +} + + +void _xbfgshessian_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + xbfgshessian *dst = (xbfgshessian*)_dst; + const xbfgshessian *src = (const xbfgshessian*)_src; + dst->htype = src->htype; + ae_vector_init_copy(&dst->varscale, &src->varscale, _state, make_automatic); + ae_vector_init_copy(&dst->invscale, &src->invscale, _state, make_automatic); + dst->n = src->n; + dst->resetfreq = src->resetfreq; + dst->stpshort = src->stpshort; + dst->gammasml = src->gammasml; + dst->reg = src->reg; + dst->smallreg = src->smallreg; + dst->microreg = src->microreg; + dst->wolfeeps = src->wolfeeps; + dst->maxhess = src->maxhess; + dst->m = src->m; + dst->mincostheta = src->mincostheta; + dst->mincrv = src->mincrv; + ae_matrix_init_copy(&dst->hcurrent, &src->hcurrent, _state, make_automatic); + dst->hage = src->hage; + dst->sumy2 = src->sumy2; + dst->sums2 = src->sums2; + dst->sumsy = src->sumsy; + dst->memlen = src->memlen; + dst->sigma = src->sigma; + ae_matrix_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_matrix_init_copy(&dst->lowranksst, &src->lowranksst, _state, make_automatic); + ae_matrix_init_copy(&dst->lowranksyt, &src->lowranksyt, _state, make_automatic); + dst->lowrankmodelvalid = src->lowrankmodelvalid; + dst->lowrankk = src->lowrankk; + ae_matrix_init_copy(&dst->lowrankcp, &src->lowrankcp, _state, make_automatic); + ae_matrix_init_copy(&dst->lowrankcm, &src->lowrankcm, _state, make_automatic); + dst->lowrankeffdvalid = src->lowrankeffdvalid; + ae_vector_init_copy(&dst->lowrankeffd, &src->lowrankeffd, _state, make_automatic); + dst->sr1modelvalid = src->sr1modelvalid; + dst->sr1k = src->sr1k; + ae_matrix_init_copy(&dst->sr1c, &src->sr1c, _state, make_automatic); + ae_vector_init_copy(&dst->sr1d, &src->sr1d, _state, make_automatic); + ae_vector_init_copy(&dst->sr1z, &src->sr1z, _state, make_automatic); + ae_matrix_init_copy(&dst->sr1stabc, &src->sr1stabc, _state, make_automatic); + ae_vector_init_copy(&dst->sr1stabz, &src->sr1stabz, _state, make_automatic); + ae_vector_init_copy(&dst->sr1stabd, &src->sr1stabd, _state, make_automatic); + dst->sr1effdvalid = src->sr1effdvalid; + ae_vector_init_copy(&dst->sr1effd, &src->sr1effd, _state, make_automatic); + dst->sr1nrm2 = src->sr1nrm2; + dst->sr1nrm2stab = src->sr1nrm2stab; + dst->updatestatus = src->updatestatus; + ae_matrix_init_copy(&dst->hincoming, &src->hincoming, _state, make_automatic); + ae_vector_init_copy(&dst->sk, &src->sk, _state, make_automatic); + ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic); + ae_vector_init_copy(&dst->rk, &src->rk, _state, make_automatic); + ae_vector_init_copy(&dst->hsk, &src->hsk, _state, make_automatic); + ae_vector_init_copy(&dst->buf, &src->buf, _state, make_automatic); + ae_vector_init_copy(&dst->buf2, &src->buf2, _state, make_automatic); + ae_matrix_init_copy(&dst->corr2, &src->corr2, _state, make_automatic); + ae_matrix_init_copy(&dst->tmps, &src->tmps, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpy, &src->tmpy, _state, make_automatic); + ae_matrix_init_copy(&dst->jk, &src->jk, _state, make_automatic); + ae_matrix_init_copy(&dst->blk, &src->blk, _state, make_automatic); + ae_matrix_init_copy(&dst->blk2, &src->blk2, _state, make_automatic); + ae_matrix_init_copy(&dst->blk3, &src->blk3, _state, make_automatic); + ae_matrix_init_copy(&dst->invsqrtdlk, &src->invsqrtdlk, _state, make_automatic); + ae_vector_init_copy(&dst->bufvmv, &src->bufvmv, _state, make_automatic); + ae_vector_init_copy(&dst->bufupdhx, &src->bufupdhx, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpunstablec, &src->tmpunstablec, _state, make_automatic); + ae_vector_init_copy(&dst->tmpunstables, &src->tmpunstables, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpu, &src->tmpu, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpq, &src->tmpq, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpw, &src->tmpw, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpsl, &src->tmpsl, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpl, &src->tmpl, _state, make_automatic); + ae_vector_init_copy(&dst->tmpe, &src->tmpe, _state, make_automatic); + ae_vector_init_copy(&dst->tmptau, &src->tmptau, _state, make_automatic); +} + + +void _xbfgshessian_clear(void* _p) +{ + xbfgshessian *p = (xbfgshessian*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->varscale); + ae_vector_clear(&p->invscale); + ae_matrix_clear(&p->hcurrent); + ae_matrix_clear(&p->s); + ae_matrix_clear(&p->y); + ae_matrix_clear(&p->lowranksst); + ae_matrix_clear(&p->lowranksyt); + ae_matrix_clear(&p->lowrankcp); + ae_matrix_clear(&p->lowrankcm); + ae_vector_clear(&p->lowrankeffd); + ae_matrix_clear(&p->sr1c); + ae_vector_clear(&p->sr1d); + ae_vector_clear(&p->sr1z); + ae_matrix_clear(&p->sr1stabc); + ae_vector_clear(&p->sr1stabz); + ae_vector_clear(&p->sr1stabd); + ae_vector_clear(&p->sr1effd); + ae_matrix_clear(&p->hincoming); + ae_vector_clear(&p->sk); + ae_vector_clear(&p->yk); + ae_vector_clear(&p->rk); + ae_vector_clear(&p->hsk); + ae_vector_clear(&p->buf); + ae_vector_clear(&p->buf2); + ae_matrix_clear(&p->corr2); + ae_matrix_clear(&p->tmps); + ae_matrix_clear(&p->tmpy); + ae_matrix_clear(&p->jk); + ae_matrix_clear(&p->blk); + ae_matrix_clear(&p->blk2); + ae_matrix_clear(&p->blk3); + ae_matrix_clear(&p->invsqrtdlk); + ae_vector_clear(&p->bufvmv); + ae_vector_clear(&p->bufupdhx); + ae_matrix_clear(&p->tmpunstablec); + ae_vector_clear(&p->tmpunstables); + ae_matrix_clear(&p->tmpu); + ae_matrix_clear(&p->tmpq); + ae_matrix_clear(&p->tmpw); + ae_matrix_clear(&p->tmpsl); + ae_matrix_clear(&p->tmpl); + ae_vector_clear(&p->tmpe); + ae_vector_clear(&p->tmptau); +} + + +void _xbfgshessian_destroy(void* _p) +{ + xbfgshessian *p = (xbfgshessian*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->varscale); + ae_vector_destroy(&p->invscale); + ae_matrix_destroy(&p->hcurrent); + ae_matrix_destroy(&p->s); + ae_matrix_destroy(&p->y); + ae_matrix_destroy(&p->lowranksst); + ae_matrix_destroy(&p->lowranksyt); + ae_matrix_destroy(&p->lowrankcp); + ae_matrix_destroy(&p->lowrankcm); + ae_vector_destroy(&p->lowrankeffd); + ae_matrix_destroy(&p->sr1c); + ae_vector_destroy(&p->sr1d); + ae_vector_destroy(&p->sr1z); + ae_matrix_destroy(&p->sr1stabc); + ae_vector_destroy(&p->sr1stabz); + ae_vector_destroy(&p->sr1stabd); + ae_vector_destroy(&p->sr1effd); + ae_matrix_destroy(&p->hincoming); + ae_vector_destroy(&p->sk); + ae_vector_destroy(&p->yk); + ae_vector_destroy(&p->rk); + ae_vector_destroy(&p->hsk); + ae_vector_destroy(&p->buf); + ae_vector_destroy(&p->buf2); + ae_matrix_destroy(&p->corr2); + ae_matrix_destroy(&p->tmps); + ae_matrix_destroy(&p->tmpy); + ae_matrix_destroy(&p->jk); + ae_matrix_destroy(&p->blk); + ae_matrix_destroy(&p->blk2); + ae_matrix_destroy(&p->blk3); + ae_matrix_destroy(&p->invsqrtdlk); + ae_vector_destroy(&p->bufvmv); + ae_vector_destroy(&p->bufupdhx); + ae_matrix_destroy(&p->tmpunstablec); + ae_vector_destroy(&p->tmpunstables); + ae_matrix_destroy(&p->tmpu); + ae_matrix_destroy(&p->tmpq); + ae_matrix_destroy(&p->tmpw); + ae_matrix_destroy(&p->tmpsl); + ae_matrix_destroy(&p->tmpl); + ae_vector_destroy(&p->tmpe); + ae_vector_destroy(&p->tmptau); +} + + +void _varsfuncjac_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + varsfuncjac *p = (varsfuncjac*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jac, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sj, _state, make_automatic); +} + + +void _varsfuncjac_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + varsfuncjac *dst = (varsfuncjac*)_dst; + const varsfuncjac *src = (const varsfuncjac*)_src; + dst->n = src->n; + dst->m = src->m; + dst->isdense = src->isdense; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->jac, &src->jac, _state, make_automatic); + _sparsematrix_init_copy(&dst->sj, &src->sj, _state, make_automatic); +} + + +void _varsfuncjac_clear(void* _p) +{ + varsfuncjac *p = (varsfuncjac*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->jac); + _sparsematrix_clear(&p->sj); +} + + +void _varsfuncjac_destroy(void* _p) +{ + varsfuncjac *p = (varsfuncjac*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->jac); + _sparsematrix_destroy(&p->sj); +} + + +void _nlpstoppingcriteria_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nlpstoppingcriteria *p = (nlpstoppingcriteria*)_p; + ae_touch_ptr((void*)p); +} + + +void _nlpstoppingcriteria_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nlpstoppingcriteria *dst = (nlpstoppingcriteria*)_dst; + const nlpstoppingcriteria *src = (const nlpstoppingcriteria*)_src; + dst->epsf = src->epsf; + dst->eps = src->eps; + dst->maxits = src->maxits; +} + + +void _nlpstoppingcriteria_clear(void* _p) +{ + nlpstoppingcriteria *p = (nlpstoppingcriteria*)_p; + ae_touch_ptr((void*)p); +} + + +void _nlpstoppingcriteria_destroy(void* _p) +{ + nlpstoppingcriteria *p = (nlpstoppingcriteria*)_p; + ae_touch_ptr((void*)p); +} + + +void _smoothnessmonitor_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + smoothnessmonitor *p = (smoothnessmonitor*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->enqueuedstp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->enqueuedx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->enqueuedfunc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->enqueuedjac, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sortedstp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sortedidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->lagprobxs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagprobd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagprobx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagprobfi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lagprobj, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lagprobvalues, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lagprobjacobians, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagprobsteps, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagproblagrangians, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->lagrangianprobingrcomm, _state, make_automatic); + _optguardreport_init(&p->rep, _state, make_automatic); + _optguardnonc0report_init(&p->nonc0strrep, _state, make_automatic); + _optguardnonc0report_init(&p->nonc0lngrep, _state, make_automatic); + _optguardnonc1test0report_init(&p->nonc1test0strrep, _state, make_automatic); + _optguardnonc1test0report_init(&p->nonc1test0lngrep, _state, make_automatic); + _optguardnonc1test1report_init(&p->nonc1test1strrep, _state, make_automatic); + _optguardnonc1test1report_init(&p->nonc1test1lngrep, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstateg0, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->jm, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->jc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->jp, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jbaseusr, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jbasenum, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->bufi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->du, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->f0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j0, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _smoothnessmonitor_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + smoothnessmonitor *dst = (smoothnessmonitor*)_dst; + const smoothnessmonitor *src = (const smoothnessmonitor*)_src; + dst->n = src->n; + dst->k = src->k; + dst->checksmoothness = src->checksmoothness; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->dcur, &src->dcur, _state, make_automatic); + dst->enqueuedcnt = src->enqueuedcnt; + ae_vector_init_copy(&dst->enqueuedstp, &src->enqueuedstp, _state, make_automatic); + ae_vector_init_copy(&dst->enqueuedx, &src->enqueuedx, _state, make_automatic); + ae_vector_init_copy(&dst->enqueuedfunc, &src->enqueuedfunc, _state, make_automatic); + ae_matrix_init_copy(&dst->enqueuedjac, &src->enqueuedjac, _state, make_automatic); + ae_vector_init_copy(&dst->sortedstp, &src->sortedstp, _state, make_automatic); + ae_vector_init_copy(&dst->sortedidx, &src->sortedidx, _state, make_automatic); + dst->sortedcnt = src->sortedcnt; + dst->lagprobinneriter = src->lagprobinneriter; + dst->lagprobouteriter = src->lagprobouteriter; + dst->lagprobstepmax = src->lagprobstepmax; + dst->lagprobnstepsstored = src->lagprobnstepsstored; + ae_vector_init_copy(&dst->lagprobxs, &src->lagprobxs, _state, make_automatic); + ae_vector_init_copy(&dst->lagprobd, &src->lagprobd, _state, make_automatic); + dst->lagprobstp = src->lagprobstp; + ae_vector_init_copy(&dst->lagprobx, &src->lagprobx, _state, make_automatic); + ae_vector_init_copy(&dst->lagprobfi, &src->lagprobfi, _state, make_automatic); + dst->lagprobrawlag = src->lagprobrawlag; + ae_matrix_init_copy(&dst->lagprobj, &src->lagprobj, _state, make_automatic); + ae_matrix_init_copy(&dst->lagprobvalues, &src->lagprobvalues, _state, make_automatic); + ae_matrix_init_copy(&dst->lagprobjacobians, &src->lagprobjacobians, _state, make_automatic); + ae_vector_init_copy(&dst->lagprobsteps, &src->lagprobsteps, _state, make_automatic); + ae_vector_init_copy(&dst->lagproblagrangians, &src->lagproblagrangians, _state, make_automatic); + _rcommstate_init_copy(&dst->lagrangianprobingrcomm, &src->lagrangianprobingrcomm, _state, make_automatic); + dst->linesearchspoiled = src->linesearchspoiled; + dst->linesearchstarted = src->linesearchstarted; + dst->linesearchinneridx = src->linesearchinneridx; + dst->linesearchouteridx = src->linesearchouteridx; + dst->nonc0currentrating = src->nonc0currentrating; + dst->nonc1currentrating = src->nonc1currentrating; + dst->badgradhasxj = src->badgradhasxj; + _optguardreport_init_copy(&dst->rep, &src->rep, _state, make_automatic); + dst->nonc0strrating = src->nonc0strrating; + dst->nonc0lngrating = src->nonc0lngrating; + _optguardnonc0report_init_copy(&dst->nonc0strrep, &src->nonc0strrep, _state, make_automatic); + _optguardnonc0report_init_copy(&dst->nonc0lngrep, &src->nonc0lngrep, _state, make_automatic); + dst->nonc1test0strrating = src->nonc1test0strrating; + dst->nonc1test0lngrating = src->nonc1test0lngrating; + _optguardnonc1test0report_init_copy(&dst->nonc1test0strrep, &src->nonc1test0strrep, _state, make_automatic); + _optguardnonc1test0report_init_copy(&dst->nonc1test0lngrep, &src->nonc1test0lngrep, _state, make_automatic); + dst->nonc1test1strrating = src->nonc1test1strrating; + dst->nonc1test1lngrating = src->nonc1test1lngrating; + _optguardnonc1test1report_init_copy(&dst->nonc1test1strrep, &src->nonc1test1strrep, _state, make_automatic); + _optguardnonc1test1report_init_copy(&dst->nonc1test1lngrep, &src->nonc1test1lngrep, _state, make_automatic); + dst->needfij = src->needfij; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + _rcommstate_init_copy(&dst->rstateg0, &src->rstateg0, _state, make_automatic); + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->fbase, &src->fbase, _state, make_automatic); + ae_vector_init_copy(&dst->fm, &src->fm, _state, make_automatic); + ae_vector_init_copy(&dst->fc, &src->fc, _state, make_automatic); + ae_vector_init_copy(&dst->fp, &src->fp, _state, make_automatic); + ae_vector_init_copy(&dst->jm, &src->jm, _state, make_automatic); + ae_vector_init_copy(&dst->jc, &src->jc, _state, make_automatic); + ae_vector_init_copy(&dst->jp, &src->jp, _state, make_automatic); + ae_matrix_init_copy(&dst->jbaseusr, &src->jbaseusr, _state, make_automatic); + ae_matrix_init_copy(&dst->jbasenum, &src->jbasenum, _state, make_automatic); + ae_vector_init_copy(&dst->stp, &src->stp, _state, make_automatic); + ae_vector_init_copy(&dst->bufr, &src->bufr, _state, make_automatic); + ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic); + ae_vector_init_copy(&dst->tmpidx, &src->tmpidx, _state, make_automatic); + ae_vector_init_copy(&dst->bufi, &src->bufi, _state, make_automatic); + ae_vector_init_copy(&dst->xu, &src->xu, _state, make_automatic); + ae_vector_init_copy(&dst->du, &src->du, _state, make_automatic); + ae_vector_init_copy(&dst->f0, &src->f0, _state, make_automatic); + ae_matrix_init_copy(&dst->j0, &src->j0, _state, make_automatic); +} + + +void _smoothnessmonitor_clear(void* _p) +{ + smoothnessmonitor *p = (smoothnessmonitor*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->dcur); + ae_vector_clear(&p->enqueuedstp); + ae_vector_clear(&p->enqueuedx); + ae_vector_clear(&p->enqueuedfunc); + ae_matrix_clear(&p->enqueuedjac); + ae_vector_clear(&p->sortedstp); + ae_vector_clear(&p->sortedidx); + ae_vector_clear(&p->lagprobxs); + ae_vector_clear(&p->lagprobd); + ae_vector_clear(&p->lagprobx); + ae_vector_clear(&p->lagprobfi); + ae_matrix_clear(&p->lagprobj); + ae_matrix_clear(&p->lagprobvalues); + ae_matrix_clear(&p->lagprobjacobians); + ae_vector_clear(&p->lagprobsteps); + ae_vector_clear(&p->lagproblagrangians); + _rcommstate_clear(&p->lagrangianprobingrcomm); + _optguardreport_clear(&p->rep); + _optguardnonc0report_clear(&p->nonc0strrep); + _optguardnonc0report_clear(&p->nonc0lngrep); + _optguardnonc1test0report_clear(&p->nonc1test0strrep); + _optguardnonc1test0report_clear(&p->nonc1test0lngrep); + _optguardnonc1test1report_clear(&p->nonc1test1strrep); + _optguardnonc1test1report_clear(&p->nonc1test1lngrep); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstateg0); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fbase); + ae_vector_clear(&p->fm); + ae_vector_clear(&p->fc); + ae_vector_clear(&p->fp); + ae_vector_clear(&p->jm); + ae_vector_clear(&p->jc); + ae_vector_clear(&p->jp); + ae_matrix_clear(&p->jbaseusr); + ae_matrix_clear(&p->jbasenum); + ae_vector_clear(&p->stp); + ae_vector_clear(&p->bufr); + ae_vector_clear(&p->f); + ae_vector_clear(&p->g); + ae_vector_clear(&p->deltax); + ae_vector_clear(&p->tmpidx); + ae_vector_clear(&p->bufi); + ae_vector_clear(&p->xu); + ae_vector_clear(&p->du); + ae_vector_clear(&p->f0); + ae_matrix_clear(&p->j0); +} + + +void _smoothnessmonitor_destroy(void* _p) +{ + smoothnessmonitor *p = (smoothnessmonitor*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->dcur); + ae_vector_destroy(&p->enqueuedstp); + ae_vector_destroy(&p->enqueuedx); + ae_vector_destroy(&p->enqueuedfunc); + ae_matrix_destroy(&p->enqueuedjac); + ae_vector_destroy(&p->sortedstp); + ae_vector_destroy(&p->sortedidx); + ae_vector_destroy(&p->lagprobxs); + ae_vector_destroy(&p->lagprobd); + ae_vector_destroy(&p->lagprobx); + ae_vector_destroy(&p->lagprobfi); + ae_matrix_destroy(&p->lagprobj); + ae_matrix_destroy(&p->lagprobvalues); + ae_matrix_destroy(&p->lagprobjacobians); + ae_vector_destroy(&p->lagprobsteps); + ae_vector_destroy(&p->lagproblagrangians); + _rcommstate_destroy(&p->lagrangianprobingrcomm); + _optguardreport_destroy(&p->rep); + _optguardnonc0report_destroy(&p->nonc0strrep); + _optguardnonc0report_destroy(&p->nonc0lngrep); + _optguardnonc1test0report_destroy(&p->nonc1test0strrep); + _optguardnonc1test0report_destroy(&p->nonc1test0lngrep); + _optguardnonc1test1report_destroy(&p->nonc1test1strrep); + _optguardnonc1test1report_destroy(&p->nonc1test1lngrep); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _rcommstate_destroy(&p->rstateg0); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fbase); + ae_vector_destroy(&p->fm); + ae_vector_destroy(&p->fc); + ae_vector_destroy(&p->fp); + ae_vector_destroy(&p->jm); + ae_vector_destroy(&p->jc); + ae_vector_destroy(&p->jp); + ae_matrix_destroy(&p->jbaseusr); + ae_matrix_destroy(&p->jbasenum); + ae_vector_destroy(&p->stp); + ae_vector_destroy(&p->bufr); + ae_vector_destroy(&p->f); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->deltax); + ae_vector_destroy(&p->tmpidx); + ae_vector_destroy(&p->bufi); + ae_vector_destroy(&p->xu); + ae_vector_destroy(&p->du); + ae_vector_destroy(&p->f0); + ae_matrix_destroy(&p->j0); +} + + +void _multiobjectivetestfunction_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + multiobjectivetestfunction *p = (multiobjectivetestfunction*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->x0, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->xsol, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->fsol, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagmultbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagmultlc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagmultnlc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rotq, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tgtc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tgtb, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tgta, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tgtd, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nlc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->nlb, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->nla, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->nld, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hu, 0, DT_REAL, _state, make_automatic); +} + + +void _multiobjectivetestfunction_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + multiobjectivetestfunction *dst = (multiobjectivetestfunction*)_dst; + const multiobjectivetestfunction *src = (const multiobjectivetestfunction*)_src; + dst->problemtype = src->problemtype; + dst->problemsubtype = src->problemsubtype; + dst->n = src->n; + dst->m = src->m; + ae_matrix_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->k0 = src->k0; + ae_matrix_init_copy(&dst->xsol, &src->xsol, _state, make_automatic); + ae_matrix_init_copy(&dst->fsol, &src->fsol, _state, make_automatic); + dst->ksol = src->ksol; + ae_vector_init_copy(&dst->lagmultbc, &src->lagmultbc, _state, make_automatic); + ae_vector_init_copy(&dst->lagmultlc, &src->lagmultlc, _state, make_automatic); + ae_vector_init_copy(&dst->lagmultnlc, &src->lagmultnlc, _state, make_automatic); + dst->isrotated = src->isrotated; + ae_matrix_init_copy(&dst->rotq, &src->rotq, _state, make_automatic); + ae_vector_init_copy(&dst->tgtc, &src->tgtc, _state, make_automatic); + ae_matrix_init_copy(&dst->tgtb, &src->tgtb, _state, make_automatic); + ae_matrix_init_copy(&dst->tgta, &src->tgta, _state, make_automatic); + ae_matrix_init_copy(&dst->tgtd, &src->tgtd, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + dst->nlinear = src->nlinear; + ae_vector_init_copy(&dst->nlc, &src->nlc, _state, make_automatic); + ae_matrix_init_copy(&dst->nlb, &src->nlb, _state, make_automatic); + ae_matrix_init_copy(&dst->nla, &src->nla, _state, make_automatic); + ae_matrix_init_copy(&dst->nld, &src->nld, _state, make_automatic); + ae_vector_init_copy(&dst->hl, &src->hl, _state, make_automatic); + ae_vector_init_copy(&dst->hu, &src->hu, _state, make_automatic); + dst->nnonlinear = src->nnonlinear; +} + + +void _multiobjectivetestfunction_clear(void* _p) +{ + multiobjectivetestfunction *p = (multiobjectivetestfunction*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->x0); + ae_matrix_clear(&p->xsol); + ae_matrix_clear(&p->fsol); + ae_vector_clear(&p->lagmultbc); + ae_vector_clear(&p->lagmultlc); + ae_vector_clear(&p->lagmultnlc); + ae_matrix_clear(&p->rotq); + ae_vector_clear(&p->tgtc); + ae_matrix_clear(&p->tgtb); + ae_matrix_clear(&p->tgta); + ae_matrix_clear(&p->tgtd); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_matrix_clear(&p->densea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + ae_vector_clear(&p->nlc); + ae_matrix_clear(&p->nlb); + ae_matrix_clear(&p->nla); + ae_matrix_clear(&p->nld); + ae_vector_clear(&p->hl); + ae_vector_clear(&p->hu); +} + + +void _multiobjectivetestfunction_destroy(void* _p) +{ + multiobjectivetestfunction *p = (multiobjectivetestfunction*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->x0); + ae_matrix_destroy(&p->xsol); + ae_matrix_destroy(&p->fsol); + ae_vector_destroy(&p->lagmultbc); + ae_vector_destroy(&p->lagmultlc); + ae_vector_destroy(&p->lagmultnlc); + ae_matrix_destroy(&p->rotq); + ae_vector_destroy(&p->tgtc); + ae_matrix_destroy(&p->tgtb); + ae_matrix_destroy(&p->tgta); + ae_matrix_destroy(&p->tgtd); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_matrix_destroy(&p->densea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + ae_vector_destroy(&p->nlc); + ae_matrix_destroy(&p->nlb); + ae_matrix_destroy(&p->nla); + ae_matrix_destroy(&p->nld); + ae_vector_destroy(&p->hl); + ae_vector_destroy(&p->hu); +} + + +void _linesearchstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + linesearchstate *p = (linesearchstate*)_p; + ae_touch_ptr((void*)p); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _linesearchstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + linesearchstate *dst = (linesearchstate*)_dst; + const linesearchstate *src = (const linesearchstate*)_src; + dst->f0 = src->f0; + dst->g0 = src->g0; + dst->alpha1 = src->alpha1; + dst->alphamax = src->alphamax; + dst->c1 = src->c1; + dst->c2 = src->c2; + dst->strongwolfecond = src->strongwolfecond; + dst->maxits = src->maxits; + dst->dotrace = src->dotrace; + dst->tracelevel = src->tracelevel; + dst->bestalphasofar = src->bestalphasofar; + dst->bestfsofar = src->bestfsofar; + dst->alphaprev = src->alphaprev; + dst->fprev = src->fprev; + dst->gprev = src->gprev; + dst->alphacur = src->alphacur; + dst->fcur = src->fcur; + dst->gcur = src->gcur; + dst->alphalo = src->alphalo; + dst->alphahi = src->alphahi; + dst->flo = src->flo; + dst->fhi = src->fhi; + dst->glo = src->glo; + dst->ghi = src->ghi; + dst->nfev = src->nfev; + dst->alphasol = src->alphasol; + dst->terminationtype = src->terminationtype; + dst->alphatrial = src->alphatrial; + dst->ftrial = src->ftrial; + dst->gtrial = src->gtrial; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _linesearchstate_clear(void* _p) +{ + linesearchstate *p = (linesearchstate*)_p; + ae_touch_ptr((void*)p); + _rcommstate_clear(&p->rstate); +} + + +void _linesearchstate_destroy(void* _p) +{ + linesearchstate *p = (linesearchstate*)_p; + ae_touch_ptr((void*)p); + _rcommstate_destroy(&p->rstate); +} + + +void _nlpfilter_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nlpfilter *p = (nlpfilter*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->filterf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->filterh, 0, DT_REAL, _state, make_automatic); +} + + +void _nlpfilter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nlpfilter *dst = (nlpfilter*)_dst; + const nlpfilter *src = (const nlpfilter*)_src; + dst->maxh = src->maxh; + dst->filtersize = src->filtersize; + dst->maxdominating = src->maxdominating; + dst->gammaf = src->gammaf; + dst->gammah = src->gammah; + dst->violationistoohigh = src->violationistoohigh; + ae_vector_init_copy(&dst->filterf, &src->filterf, _state, make_automatic); + ae_vector_init_copy(&dst->filterh, &src->filterh, _state, make_automatic); +} + + +void _nlpfilter_clear(void* _p) +{ + nlpfilter *p = (nlpfilter*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->filterf); + ae_vector_clear(&p->filterh); +} + + +void _nlpfilter_destroy(void* _p) +{ + nlpfilter *p = (nlpfilter*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->filterf); + ae_vector_destroy(&p->filterh); +} + + +#endif +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using a quasi- +Newton method (LBFGS scheme) which is optimized to use a minimum amount +of memory. +The subroutine generates the approximation of an inverse Hessian matrix by +using information about the last M steps of the algorithm (instead of N). +It lessens a required amount of memory from a value of order N^2 to a +value of order 2*N*M. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinLBFGSCreate() call +2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() + and other functions +3. User calls MinLBFGSOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinLBFGSResults() to get solution +5. Optionally user may call MinLBFGSRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLBFGSRestartFrom() allows to reuse already initialized structure. + +INPUT PARAMETERS: + N - problem dimension. N>0 + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - initial solution approximation, array[0..N-1]. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. you may tune stopping conditions with MinLBFGSSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLBFGSSetStpMax() function to bound algorithm's steps. However, + L-BFGS rarely needs such a tuning. + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreate(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minlbfgsstate* state, + ae_state *_state) +{ + + _minlbfgsstate_clear(state); + + ae_assert(n>=1, "MinLBFGSCreate: N<1!", _state); + ae_assert(m>=1, "MinLBFGSCreate: M<1", _state); + ae_assert(m<=n, "MinLBFGSCreate: M>N", _state); + ae_assert(x->cnt>=n, "MinLBFGSCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinLBFGSSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. LBFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreatef(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minlbfgsstate* state, + ae_state *_state) +{ + + _minlbfgsstate_clear(state); + + ae_assert(n>=1, "MinLBFGSCreateF: N too small!", _state); + ae_assert(m>=1, "MinLBFGSCreateF: M<1", _state); + ae_assert(m<=n, "MinLBFGSCreateF: M>N", _state); + ae_assert(x->cnt>=n, "MinLBFGSCreateF: Length(X)=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLBFGSSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcond(minlbfgsstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinLBFGSSetCond: EpsG is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinLBFGSSetCond: negative EpsG!", _state); + ae_assert(ae_isfinite(epsf, _state), "MinLBFGSSetCond: EpsF is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinLBFGSSetCond: negative EpsF!", _state); + ae_assert(ae_isfinite(epsx, _state), "MinLBFGSSetCond: EpsX is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinLBFGSSetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "MinLBFGSSetCond: negative MaxIts!", _state); + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsg = epsg; + state->epsf = epsf; + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLBFGSOptimize(). + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetxrep(minlbfgsstate* state, + ae_bool needxrep, + ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetstpmax(minlbfgsstate* state, + double stpmax, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinLBFGSSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinLBFGSSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +This function sets scaling coefficients for LBFGS optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the LBFGS too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinLBFGSSetPrec...() +functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetscale(minlbfgsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinLBFGSSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLBFGSSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinLBFGSSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Extended subroutine for internal use only. + +Accepts additional parameters: + + Flags - additional settings: + * Flags = 0 means no additional settings + * Flags = 1 "do not allocate memory". used when solving + a many subsequent tasks with same N/M values. + First call MUST be without this flag bit set, + subsequent calls of MinLBFGS with same + MinLBFGSState structure can set Flags to 1. + DiffStep - numerical differentiation step + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreatex(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + ae_int_t flags, + double diffstep, + minlbfgsstate* state, + ae_state *_state) +{ + ae_bool allocatemem; + ae_int_t i; + + + ae_assert(n>=1, "MinLBFGS: N too small!", _state); + ae_assert(m>=1, "MinLBFGS: M too small!", _state); + ae_assert(m<=n, "MinLBFGS: M too large!", _state); + + /* + * Initialize + */ + state->protocolversion = 1; + state->teststep = (double)(0); + state->smoothnessguardlevel = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + state->diffstep = diffstep; + state->n = n; + state->m = m; + allocatemem = flags%2==0; + flags = flags/2; + if( allocatemem ) + { + rvectorsetlengthatleast(&state->rho, m, _state); + rvectorsetlengthatleast(&state->theta, m, _state); + rmatrixsetlengthatleast(&state->yk, m, n, _state); + rmatrixsetlengthatleast(&state->sk, m, n, _state); + rvectorsetlengthatleast(&state->d, n, _state); + rvectorsetlengthatleast(&state->xp, n, _state); + rvectorsetlengthatleast(&state->x, n, _state); + rvectorsetlengthatleast(&state->xbase, n, _state); + rvectorsetlengthatleast(&state->s, n, _state); + rvectorsetlengthatleast(&state->invs, n, _state); + rvectorsetlengthatleast(&state->lastscaleused, n, _state); + rvectorsetlengthatleast(&state->g, n, _state); + rvectorsetlengthatleast(&state->work, n, _state); + } + for(i=0; i<=n-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->invs.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + } + state->prectype = 0; + minlbfgssetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); + minlbfgssetxrep(state, ae_false, _state); + minlbfgssetstpmax(state, (double)(0), _state); + minlbfgsrestartfrom(state, x, _state); +} + + +/************************************************************************* +Modification of the preconditioner: default preconditioner (simple +scaling, same for all elements of X) is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state) +{ + + + state->prectype = 0; +} + + +/************************************************************************* +Modification of the preconditioner: Cholesky factorization of approximate +Hessian is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + P - triangular preconditioner, Cholesky factorization of + the approximate Hessian. array[0..N-1,0..N-1], + (if larger, only leading N elements are used). + IsUpper - whether upper or lower triangle of P is given + (other triangle is not referenced) + +After call to this function preconditioner is changed to P (P is copied +into the internal buffer). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: P should be nonsingular. Exception will be thrown otherwise. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetpreccholesky(minlbfgsstate* state, + /* Real */ const ae_matrix* p, + ae_bool isupper, + ae_state *_state) +{ + ae_int_t i; + double mx; + + + ae_assert(isfinitertrmatrix(p, state->n, isupper, _state), "MinLBFGSSetPrecCholesky: P contains infinite or NAN values!", _state); + mx = (double)(0); + for(i=0; i<=state->n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(p->ptr.pp_double[i][i], _state), _state); + } + ae_assert(ae_fp_greater(mx,(double)(0)), "MinLBFGSSetPrecCholesky: P is strictly singular!", _state); + if( state->denseh.rowsn||state->denseh.colsn ) + { + ae_matrix_set_length(&state->denseh, state->n, state->n, _state); + } + state->prectype = 1; + if( isupper ) + { + rmatrixcopy(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); + } + else + { + rmatrixtranspose(state->n, state->n, p, 0, 0, &state->denseh, 0, 0, _state); + } +} + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdiag(minlbfgsstate* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(d->cnt>=state->n, "MinLBFGSSetPrecDiag: D is too short", _state); + for(i=0; i<=state->n-1; i++) + { + ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinLBFGSSetPrecDiag: D contains infinite or NAN elements", _state); + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinLBFGSSetPrecDiag: D contains non-positive elements", _state); + } + rvectorsetlengthatleast(&state->diagh, state->n, _state); + state->prectype = 2; + for(i=0; i<=state->n-1; i++) + { + state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; + } +} + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() +call (before or after MinLBFGSSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state) +{ + + + state->prectype = 3; +} + + +/************************************************************************* +This function sets low-rank preconditioner for Hessian matrix H=D+W'*C*W, +where: +* H is a Hessian matrix, which is approximated by D/W/C +* D is a NxN diagonal positive definite matrix +* W is a KxN low-rank correction +* C is a KxK positive definite diagonal factor of low-rank correction + +This preconditioner is inexact but fast - it requires O(N*K) time to be +applied. Preconditioner P is calculated by artificially constructing a set +of BFGS updates which tries to reproduce behavior of H: +* Sk = Wk (k-th row of W) +* Yk = (D+Wk'*Ck*Wk)*Sk +* Yk/Sk are reordered by ascending of C[k]*norm(Wk)^2 + +Here we assume that rows of Wk are orthogonal or nearly orthogonal, which +allows us to have O(N*K+K^2) update instead of O(N*K^2) one. Reordering of +updates is essential for having good performance on non-orthogonal problems +(updates which do not add much of curvature are added first, and updates +which add very large eigenvalues are added last and override effect of the +first updates). + +In practice, this preconditioner is perfect when ortogonal correction is +applied; on non-orthogonal problems sometimes it allows to achieve 5x +speedup (when compared to non-preconditioned solver). + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecrankklbfgsfast(minlbfgsstate* state, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t cnt, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + + + n = state->n; + state->prectype = 4; + state->preck = cnt; + rvectorsetlengthatleast(&state->precc, cnt, _state); + rvectorsetlengthatleast(&state->precd, n, _state); + rmatrixsetlengthatleast(&state->precw, cnt, n, _state); + for(i=0; i<=n-1; i++) + { + state->precd.ptr.p_double[i] = d->ptr.p_double[i]; + } + for(i=0; i<=cnt-1; i++) + { + state->precc.ptr.p_double[i] = c->ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + state->precw.ptr.pp_double[i][j] = w->ptr.pp_double[i][j]; + } + } +} + + +/************************************************************************* +This function sets exact low-rank preconditioner for Hessian matrix +H=D+W'*C*W, where: +* H is a Hessian matrix, which is approximated by D/W/C +* D is a NxN diagonal positive definite matrix +* W is a KxN low-rank correction +* C is a KxK semidefinite diagonal factor of low-rank correction + +This preconditioner is exact but slow - it requires O(N*K^2) time to be +built and O(N*K) time to be applied. Woodbury matrix identity is used to +build inverse matrix. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetpreclowrankexact(minlbfgsstate* state, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t cnt, + ae_state *_state) +{ + + + state->prectype = 5; + preparelowrankpreconditioner(d, c, w, state->n, cnt, &state->lowrankbuf, _state); +} + + +/************************************************************************* + +CALLBACK PARALLELISM: + +The LBFGS optimizer supports parallel numerical differentiation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates numerical differentiation of expensive +targets. + +Callback parallelism is usually beneficial computing a numerical gradient +requires more than several milliseconds. In this case the job of computing +individual gradient components can be split between multiple threads. Even +inexpensive targets can benefit from parallelism, if you have many +variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +CALLBACKS ACCEPTED + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() + for numerical differentiation) you should choose appropriate variant of + MinLBFGSOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinLBFGSOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinLBFGSOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinLBFGSOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinLBFGSCreateF() | work FAIL + MinLBFGSCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinLBFGSOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinLBFGSCreateF() and + to pass gradient information to MinCGOptimize()) will lead to exception + being thrown. Either you did not pass gradient when it WAS needed or + you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t ic; + ae_int_t mcinfo; + double v; + double vv; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + j = state->rstate.ia.ptr.p_int[3]; + ic = state->rstate.ia.ptr.p_int[4]; + mcinfo = state->rstate.ia.ptr.p_int[5]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + } + else + { + n = 359; + m = -58; + i = -919; + j = -909; + ic = 81; + mcinfo = 255; + v = 74.0; + vv = -788.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + if( state->rstate.stage==20 ) + { + goto lbl_20; + } + if( state->rstate.stage==21 ) + { + goto lbl_21; + } + + /* + * Routine body + */ + + /* + * Unload frequently used variables from State structure + * (just for typing convinience) + */ + n = state->n; + m = state->m; + + /* + * Init + */ + state->userterminationneeded = ae_false; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, n, 1, state->smoothnessguardlevel>0, _state); + rvectorsetlengthatleast(&state->invs, n, _state); + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + state->invs.ptr.p_double[i] = (double)1/state->s.ptr.p_double[i]; + } + + /* + * Allocate temporaries, as mandated by the V2 protocol + */ + if( state->protocolversion==2 ) + { + rallocm(1, n, &state->tmpj1, _state); + rallocv(1, &state->tmpf1, _state); + rallocv(n, &state->tmpg1, _state); + rallocv(n, &state->tmpx1, _state); + } + + /* + * Check, that transferred derivative value is right + */ + state->stp = (double)(0); + if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_22; + } +lbl_24: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xbase, &state->s, &state->s, &state->s, ae_false, state->teststep, _state) ) + { + goto lbl_25; + } + if( state->protocolversion!=2 ) + { + goto lbl_26; + } + + /* + * Use V2 reverse communication protocol + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->smonitor.x, &state->querydata, _state); + rallocv(1, &state->replyfi, _state); + rallocv(n, &state->replydj, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->smonitor.fi.ptr.p_double[0] = state->replyfi.ptr.p_double[0]; + rcopyvr(n, &state->replydj, &state->smonitor.j, 0, _state); + goto lbl_27; +lbl_26: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLBFGS: unexpected protocol, integrity check 0125 failed", _state); + minlbfgs_clearrequestfields(state, _state); + rcopyv(n, &state->smonitor.x, &state->x, _state); + state->needfg = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfg = ae_false; + state->smonitor.fi.ptr.p_double[0] = state->f; + rcopyvr(n, &state->g, &state->smonitor.j, 0, _state); +lbl_27: + goto lbl_24; +lbl_25: +lbl_22: + + /* + * Calculate F/G at the initial point + */ + if( state->protocolversion!=2 ) + { + goto lbl_28; + } + + /* + * Issue request using V2 protocol + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->stp = (double)(0); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_30; + } + + /* + * Request dense analytic Jacobian + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->x, &state->querydata, _state); + rallocv(1, &state->replyfi, _state); + rallocv(n, &state->replydj, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->f = state->replyfi.ptr.p_double[0]; + rcopyallocv(n, &state->replydj, &state->g, _state); + goto lbl_31; +lbl_30: + + /* + * Request dense numerical Jacobian, propose 5-point formula + */ + state->requesttype = 3; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + state->queryformulasize = 5; + rallocv(n+n*2*state->queryformulasize, &state->querydata, _state); + rcopyallocv(n, &state->x, &state->querydata, _state); + for(i=0; i<=n-1; i++) + { + v = state->diffstep*state->s.ptr.p_double[i]; + state->querydata.ptr.p_double[n+10*i+0*2+0] = (double)(0); + state->querydata.ptr.p_double[n+10*i+0*2+1] = (double)(0); + state->querydata.ptr.p_double[n+10*i+1*2+0] = state->querydata.ptr.p_double[i]-1.0*v; + state->querydata.ptr.p_double[n+10*i+1*2+1] = (double)1/((double)6*v); + state->querydata.ptr.p_double[n+10*i+2*2+0] = state->querydata.ptr.p_double[i]-0.5*v; + state->querydata.ptr.p_double[n+10*i+2*2+1] = -(double)8/((double)6*v); + state->querydata.ptr.p_double[n+10*i+3*2+0] = state->querydata.ptr.p_double[i]+0.5*v; + state->querydata.ptr.p_double[n+10*i+3*2+1] = (double)8/((double)6*v); + state->querydata.ptr.p_double[n+10*i+4*2+0] = state->querydata.ptr.p_double[i]+1.0*v; + state->querydata.ptr.p_double[n+10*i+4*2+1] = -(double)1/((double)6*v); + } + rallocv(1, &state->replyfi, _state); + rallocv(n, &state->replydj, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->f = state->replyfi.ptr.p_double[0]; + rcopyallocv(n, &state->replydj, &state->g, _state); +lbl_31: + if( !state->xrep ) + { + goto lbl_32; + } + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->x, &state->reportx, _state); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: +lbl_32: + goto lbl_29; +lbl_28: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLBFGS: unexpected protocol, integrity check 9600 failed", _state); + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->xbase.ptr.p_double[i]; + } + state->stp = (double)(0); + minlbfgs_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_34; + } + state->needfg = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->needfg = ae_false; + goto lbl_35; +lbl_34: + state->needf = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->fbase = state->f; + i = 0; +lbl_36: + if( i>n-1 ) + { + goto lbl_38; + } + v = state->x.ptr.p_double[i]; + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->fp2 = state->f; + state->x.ptr.p_double[i] = v; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + i = i+1; + goto lbl_36; +lbl_38: + state->f = state->fbase; + state->needf = ae_false; +lbl_35: + if( !state->xrep ) + { + goto lbl_39; + } + minlbfgs_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->xupdated = ae_false; +lbl_39: +lbl_29: + trimprepare(state->f, &state->trimthreshold, _state); + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + state->repnfev = 1; + state->fold = state->f; + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) + { + state->repterminationtype = 4; + result = ae_false; + return result; + } + + /* + * Choose initial step and direction. + * Apply preconditioner, if we have something other than default. + */ + rcopymulv(n, -1.0, &state->g, &state->d, _state); + if( state->prectype==0 ) + { + + /* + * Default preconditioner is used, but we can't use it before iterations will start + */ + v = ae_sqrt(rdotv2(n, &state->g, _state), _state); + if( ae_fp_eq(state->stpmax,(double)(0)) ) + { + state->stp = ae_minreal(1.0/v, (double)(1), _state); + } + else + { + state->stp = ae_minreal(1.0/v, state->stpmax, _state); + } + } + if( state->prectype==1 ) + { + + /* + * Cholesky preconditioner is used + */ + fblscholeskysolve(&state->denseh, 1.0, n, ae_true, &state->d, &state->autobuf, _state); + state->stp = (double)(1); + } + if( state->prectype==2 ) + { + + /* + * diagonal approximation is used + */ + rmergedivv(n, &state->diagh, &state->d, _state); + state->stp = (double)(1); + } + if( state->prectype==3 ) + { + + /* + * scale-based preconditioner is used + */ + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = state->d.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; + } + state->stp = (double)(1); + } + if( state->prectype==4 ) + { + + /* + * rank-k BFGS-based preconditioner is used + */ + inexactlbfgspreconditioner(&state->d, n, &state->precd, &state->precc, &state->precw, state->preck, &state->precbuf, _state); + state->stp = (double)(1); + } + if( state->prectype==5 ) + { + + /* + * exact low-rank preconditioner is used + */ + applylowrankpreconditioner(&state->d, &state->lowrankbuf, _state); + state->stp = (double)(1); + } + linminnormalized(&state->d, &state->stp, n, _state); + state->longeststp = state->stp; + + /* + * Main cycle + */ + state->k = 0; +lbl_41: + if( ae_false ) + { + goto lbl_42; + } + + /* + * Main cycle: prepare to 1-D line search + */ + state->p = state->k%m; + state->q = ae_minint(state->k, m-1, _state); + + /* + * Store X[k], G[k] + */ + ae_v_move(&state->xp.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_moveneg(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_moveneg(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Minimize F(x+alpha*d) + * Calculate S[k], Y[k] + */ + state->mcstage = 0; + if( state->k!=0 ) + { + state->stp = 1.0; + } + linminnormalized(&state->d, &state->stp, n, _state); + state->stplimit = (double)10*state->longeststp; + if( ae_fp_neq(state->stpmax,(double)(0)) ) + { + state->stplimit = ae_minreal(state->stplimit, state->stpmax, _state); + } + smoothnessmonitorstartlinesearch1u(&state->smonitor, &state->s, &state->invs, &state->x, state->f, &state->g, state->k, -1, _state); + mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stplimit, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_43: + if( state->mcstage==0 ) + { + goto lbl_44; + } + if( state->protocolversion!=2 ) + { + goto lbl_45; + } + + /* + * Issue request using V2 protocol + */ + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_47; + } + + /* + * Request dense analytic Jacobian + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->x, &state->querydata, _state); + rallocv(1, &state->replyfi, _state); + rallocv(n, &state->replydj, _state); + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->f = state->replyfi.ptr.p_double[0]; + rcopyallocv(n, &state->replydj, &state->g, _state); + goto lbl_48; +lbl_47: + + /* + * Request dense numerical Jacobian, propose 5-point formula + */ + state->requesttype = 3; + state->querysize = 1; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + state->queryformulasize = 5; + rallocv(n+n*2*5, &state->querydata, _state); + rcopyallocv(n, &state->x, &state->querydata, _state); + for(i=0; i<=n-1; i++) + { + v = state->diffstep*state->s.ptr.p_double[i]; + state->querydata.ptr.p_double[n+10*i+0*2+0] = (double)(0); + state->querydata.ptr.p_double[n+10*i+0*2+1] = (double)(0); + state->querydata.ptr.p_double[n+10*i+1*2+0] = state->querydata.ptr.p_double[i]-1.0*v; + state->querydata.ptr.p_double[n+10*i+1*2+1] = (double)1/((double)6*v); + state->querydata.ptr.p_double[n+10*i+2*2+0] = state->querydata.ptr.p_double[i]-0.5*v; + state->querydata.ptr.p_double[n+10*i+2*2+1] = -(double)8/((double)6*v); + state->querydata.ptr.p_double[n+10*i+3*2+0] = state->querydata.ptr.p_double[i]+0.5*v; + state->querydata.ptr.p_double[n+10*i+3*2+1] = (double)8/((double)6*v); + state->querydata.ptr.p_double[n+10*i+4*2+0] = state->querydata.ptr.p_double[i]+1.0*v; + state->querydata.ptr.p_double[n+10*i+4*2+1] = -(double)1/((double)6*v); + } + rallocv(1, &state->replyfi, _state); + rallocv(n, &state->replydj, _state); + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->f = state->replyfi.ptr.p_double[0]; + rcopyallocv(n, &state->replydj, &state->g, _state); +lbl_48: + goto lbl_46; +lbl_45: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLBFGS: unexpected protocol, integrity check 1506 failed", _state); + minlbfgs_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_49; + } + state->needfg = ae_true; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->needfg = ae_false; + goto lbl_50; +lbl_49: + state->needf = ae_true; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->fbase = state->f; + i = 0; +lbl_51: + if( i>n-1 ) + { + goto lbl_53; + } + v = state->x.ptr.p_double[i]; + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + state->fp2 = state->f; + state->x.ptr.p_double[i] = v; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + i = i+1; + goto lbl_51; +lbl_53: + state->f = state->fbase; + state->needf = ae_false; +lbl_50: +lbl_46: + smoothnessmonitorenqueuepoint1u(&state->smonitor, &state->s, &state->invs, &state->d, state->stp, &state->x, state->f, &state->g, _state); + trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); + mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->stplimit, minlbfgs_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_43; +lbl_44: + smoothnessmonitorfinalizelinesearch(&state->smonitor, _state); + if( state->userterminationneeded ) + { + + /* + * User requested termination. + * Restore previous point and return. + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xp.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->xrep ) + { + goto lbl_54; + } + + /* + * report + */ + if( state->protocolversion!=2 ) + { + goto lbl_56; + } + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->x, &state->reportx, _state); + state->rstate.stage = 20; + goto lbl_rcomm; +lbl_20: + goto lbl_57; +lbl_56: + ae_assert(state->protocolversion==1, "MINLBFGS: unexpected protocol, integrity check 8007 failed", _state); + minlbfgs_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 21; + goto lbl_rcomm; +lbl_21: + state->xupdated = ae_false; +lbl_57: +lbl_54: + state->repnfev = state->repnfev+state->nfev; + state->repiterationscount = state->repiterationscount+1; + ae_v_add(&state->sk.ptr.pp_double[state->p][0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_add(&state->yk.ptr.pp_double[state->p][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->longeststp = ae_maxreal(state->longeststp, state->stp, _state); + + /* + * Stopping conditions + */ + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( !ae_isfinite(v, _state)||!ae_isfinite(state->f, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + + /* + * Too many iterations + */ + state->repterminationtype = 5; + result = ae_false; + return result; + } + if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) + { + + /* + * Gradient is small enough + */ + state->repterminationtype = 4; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) + { + + /* + * F(k+1)-F(k) is small enough + */ + state->repterminationtype = 1; + result = ae_false; + return result; + } + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->sk.ptr.pp_double[state->p][i]/state->s.ptr.p_double[i], _state); + } + if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsx) ) + { + + /* + * X(k+1)-X(k) is small enough + */ + state->repterminationtype = 2; + result = ae_false; + return result; + } + + /* + * If Wolfe conditions are satisfied, we can update + * limited memory model. + * + * However, if conditions are not satisfied (NFEV limit is met, + * function is too wild, ...), we'll skip L-BFGS update + */ + if( mcinfo!=1 ) + { + + /* + * Skip update. + * + * In such cases we'll initialize search direction by + * antigradient vector, because it leads to more + * transparent code with less number of special cases + */ + state->fold = state->f; + ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + } + else + { + + /* + * Calculate Rho[k], GammaK + */ + v = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->sk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); + vv = ae_v_dotproduct(&state->yk.ptr.pp_double[state->p][0], 1, &state->yk.ptr.pp_double[state->p][0], 1, ae_v_len(0,n-1)); + if( ae_fp_eq(v,(double)(0))||ae_fp_eq(vv,(double)(0)) ) + { + + /* + * Rounding errors make further iterations impossible. + */ + state->repterminationtype = -2; + result = ae_false; + return result; + } + state->rho.ptr.p_double[state->p] = (double)1/v; + state->gammak = v/vv; + + /* + * Calculate d(k+1) = -H(k+1)*g(k+1) + * + * for I:=K downto K-Q do + * V = s(i)^T * work(iteration:I) + * theta(i) = V + * work(iteration:I+1) = work(iteration:I) - V*Rho(i)*y(i) + * work(last iteration) = H0*work(last iteration) - preconditioner + * for I:=K-Q to K do + * V = y(i)^T*work(iteration:I) + * work(iteration:I+1) = work(iteration:I) +(-V+theta(i))*Rho(i)*s(i) + * + * NOW WORK CONTAINS d(k+1) + */ + ae_v_move(&state->work.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=state->k; i>=state->k-state->q; i--) + { + ic = i%m; + v = ae_v_dotproduct(&state->sk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->theta.ptr.p_double[ic] = v; + vv = v*state->rho.ptr.p_double[ic]; + ae_v_subd(&state->work.ptr.p_double[0], 1, &state->yk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); + } + if( state->prectype==0 ) + { + + /* + * Simple preconditioner is used + */ + v = state->gammak; + ae_v_muld(&state->work.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + } + if( state->prectype==1 ) + { + + /* + * Cholesky preconditioner is used + */ + fblscholeskysolve(&state->denseh, (double)(1), n, ae_true, &state->work, &state->autobuf, _state); + } + if( state->prectype==2 ) + { + + /* + * diagonal approximation is used + */ + for(i=0; i<=n-1; i++) + { + state->work.ptr.p_double[i] = state->work.ptr.p_double[i]/state->diagh.ptr.p_double[i]; + } + } + if( state->prectype==3 ) + { + + /* + * scale-based preconditioner is used + */ + for(i=0; i<=n-1; i++) + { + state->work.ptr.p_double[i] = state->work.ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; + } + } + if( state->prectype==4 ) + { + + /* + * Rank-K BFGS-based preconditioner is used + */ + inexactlbfgspreconditioner(&state->work, n, &state->precd, &state->precc, &state->precw, state->preck, &state->precbuf, _state); + } + if( state->prectype==5 ) + { + + /* + * Exact low-rank preconditioner is used + */ + applylowrankpreconditioner(&state->work, &state->lowrankbuf, _state); + } + for(i=state->k-state->q; i<=state->k; i++) + { + ic = i%m; + v = ae_v_dotproduct(&state->yk.ptr.pp_double[ic][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vv = state->rho.ptr.p_double[ic]*(-v+state->theta.ptr.p_double[ic]); + ae_v_addd(&state->work.ptr.p_double[0], 1, &state->sk.ptr.pp_double[ic][0], 1, ae_v_len(0,n-1), vv); + } + ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Next step + */ + state->fold = state->f; + state->k = state->k+1; + } + goto lbl_41; +lbl_42: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = j; + state->rstate.ia.ptr.p_int[4] = ic; + state->rstate.ia.ptr.p_int[5] = mcinfo; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minlbfgsoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlbfgssetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardgradient(minlbfgsstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinLBFGSOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinLBFGSOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardsmoothness(minlbfgsstate* state, + ae_int_t level, + ae_state *_state) +{ + + + ae_assert(level==0||level==1, "MinLBFGSOptGuardSmoothness: unexpected value of level parameter", _state); + state->smoothnessguardlevel = level; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minlbfgsoptguardgradient() for gradient verification +* minlbfgsoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minlbfgsoptguardnonc1test0results() +* minlbfgsoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardresults(minlbfgsstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test0results(const minlbfgsstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test0report_clear(strrep); + _optguardnonc1test0report_clear(lngrep); + + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test1results(minlbfgsstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test1report_clear(strrep); + _optguardnonc1test1report_clear(lngrep); + + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +L-BFGS algorithm results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -2 rounding errors prevent further improvement. + X contains best point found. + * -1 incorrect parameters were specified + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlbfgsrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresults(const minlbfgsstate* state, + /* Real */ ae_vector* x, + minlbfgsreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minlbfgsreport_clear(rep); + + minlbfgsresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +L-BFGS algorithm results + +Buffered implementation of MinLBFGSResults which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresultsbuf(const minlbfgsstate* state, + /* Real */ ae_vector* x, + minlbfgsreport* rep, + ae_state *_state) +{ + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nfev = state->repnfev; + rep->terminationtype = state->repterminationtype; +} + + +/************************************************************************* +This subroutine restarts LBFGS algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrestartfrom(minlbfgsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "MinLBFGSRestartFrom: Length(X)n, _state), "MinLBFGSRestartFrom: X contains infinite or NaN values!", _state); + ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrequesttermination(minlbfgsstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minlbfgssetprotocolv1(minlbfgsstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol +*************************************************************************/ +void minlbfgssetprotocolv2(minlbfgsstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void minlbfgs_clearrequestfields(minlbfgsstate* state, + ae_state *_state) +{ + + + ae_assert(state->protocolversion==1, "MINLBFGS: unexpected protocol", _state); + state->needf = ae_false; + state->needfg = ae_false; + state->xupdated = ae_false; +} + + +void _minlbfgsstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlbfgsstate *p = (minlbfgsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->yk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->theta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->precc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->precd, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->precw, 0, 0, DT_REAL, _state, make_automatic); + _precbuflbfgs_init(&p->precbuf, _state, make_automatic); + _precbuflowrank_init(&p->lowrankbuf, _state, make_automatic); + ae_vector_init(&p->autobuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); +} + + +void _minlbfgsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlbfgsstate *dst = (minlbfgsstate*)_dst; + const minlbfgsstate *src = (const minlbfgsstate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->diffstep = src->diffstep; + dst->nfev = src->nfev; + dst->mcstage = src->mcstage; + dst->k = src->k; + dst->q = src->q; + dst->p = src->p; + ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic); + ae_matrix_init_copy(&dst->yk, &src->yk, _state, make_automatic); + ae_matrix_init_copy(&dst->sk, &src->sk, _state, make_automatic); + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_vector_init_copy(&dst->theta, &src->theta, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->stp = src->stp; + dst->longeststp = src->longeststp; + ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic); + dst->fold = src->fold; + dst->trimthreshold = src->trimthreshold; + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + dst->prectype = src->prectype; + dst->gammak = src->gammak; + ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic); + ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic); + ae_vector_init_copy(&dst->precc, &src->precc, _state, make_automatic); + ae_vector_init_copy(&dst->precd, &src->precd, _state, make_automatic); + ae_matrix_init_copy(&dst->precw, &src->precw, _state, make_automatic); + dst->preck = src->preck; + _precbuflbfgs_init_copy(&dst->precbuf, &src->precbuf, _state, make_automatic); + _precbuflowrank_init_copy(&dst->lowrankbuf, &src->lowrankbuf, _state, make_automatic); + dst->fbase = src->fbase; + dst->fm2 = src->fm2; + dst->fm1 = src->fm1; + dst->fp1 = src->fp1; + dst->fp2 = src->fp2; + dst->stplimit = src->stplimit; + ae_vector_init_copy(&dst->autobuf, &src->autobuf, _state, make_automatic); + ae_vector_init_copy(&dst->invs, &src->invs, _state, make_automatic); + dst->protocolversion = src->protocolversion; + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->xupdated = src->xupdated; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + dst->teststep = src->teststep; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->smoothnessguardlevel = src->smoothnessguardlevel; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); +} + + +void _minlbfgsstate_clear(void* _p) +{ + minlbfgsstate *p = (minlbfgsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->rho); + ae_matrix_clear(&p->yk); + ae_matrix_clear(&p->sk); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->theta); + ae_vector_clear(&p->d); + ae_vector_clear(&p->work); + ae_vector_clear(&p->xbase); + ae_matrix_clear(&p->denseh); + ae_vector_clear(&p->diagh); + ae_vector_clear(&p->precc); + ae_vector_clear(&p->precd); + ae_matrix_clear(&p->precw); + _precbuflbfgs_clear(&p->precbuf); + _precbuflowrank_clear(&p->lowrankbuf); + ae_vector_clear(&p->autobuf); + ae_vector_clear(&p->invs); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + _rcommstate_clear(&p->rstate); + _linminstate_clear(&p->lstate); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); +} + + +void _minlbfgsstate_destroy(void* _p) +{ + minlbfgsstate *p = (minlbfgsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->rho); + ae_matrix_destroy(&p->yk); + ae_matrix_destroy(&p->sk); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->theta); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->work); + ae_vector_destroy(&p->xbase); + ae_matrix_destroy(&p->denseh); + ae_vector_destroy(&p->diagh); + ae_vector_destroy(&p->precc); + ae_vector_destroy(&p->precd); + ae_matrix_destroy(&p->precw); + _precbuflbfgs_destroy(&p->precbuf); + _precbuflowrank_destroy(&p->lowrankbuf); + ae_vector_destroy(&p->autobuf); + ae_vector_destroy(&p->invs); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + _rcommstate_destroy(&p->rstate); + _linminstate_destroy(&p->lstate); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); +} + + +void _minlbfgsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlbfgsreport *p = (minlbfgsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlbfgsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlbfgsreport *dst = (minlbfgsreport*)_dst; + const minlbfgsreport *src = (const minlbfgsreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; +} + + +void _minlbfgsreport_clear(void* _p) +{ + minlbfgsreport *p = (minlbfgsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlbfgsreport_destroy(void* _p) +{ + minlbfgsreport *p = (minlbfgsreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine is used to initialize CQM. By default, empty NxN model is +generated, with Alpha=Lambda=Theta=0.0 and zero b. + +Previously allocated buffer variables are reused as much as possible. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state) +{ + ae_int_t i; + + + s->n = n; + s->k = 0; + s->nfree = n; + s->ecakind = -1; + s->alpha = 0.0; + s->tau = 0.0; + s->theta = 0.0; + s->ismaintermchanged = ae_true; + s->issecondarytermchanged = ae_true; + s->islineartermchanged = ae_true; + s->isactivesetchanged = ae_true; + bvectorsetlengthatleast(&s->activeset, n, _state); + rvectorsetlengthatleast(&s->xc, n, _state); + rvectorsetlengthatleast(&s->eb, n, _state); + rvectorsetlengthatleast(&s->tq1, n, _state); + rvectorsetlengthatleast(&s->txc, n, _state); + rvectorsetlengthatleast(&s->tb, n, _state); + rvectorsetlengthatleast(&s->b, s->n, _state); + rvectorsetlengthatleast(&s->tk1, s->n, _state); + for(i=0; i<=n-1; i++) + { + s->activeset.ptr.p_bool[i] = ae_false; + s->xc.ptr.p_double[i] = 0.0; + s->b.ptr.p_double[i] = 0.0; + } +} + + +/************************************************************************* +This subroutine changes main quadratic term of the model. + +INPUT PARAMETERS: + S - model + A - NxN matrix, only upper or lower triangle is referenced + IsUpper - True, when matrix is stored in upper triangle + Alpha - multiplier; when Alpha=0, A is not referenced at all + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmseta(convexquadraticmodel* s, + /* Real */ const ae_matrix* a, + ae_bool isupper, + double alpha, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + ae_assert(ae_isfinite(alpha, _state)&&ae_fp_greater_eq(alpha,(double)(0)), "CQMSetA: Alpha<0 or is not finite number", _state); + ae_assert(ae_fp_eq(alpha,(double)(0))||isfinitertrmatrix(a, s->n, isupper, _state), "CQMSetA: A is not finite NxN matrix", _state); + s->alpha = alpha; + if( ae_fp_greater(alpha,(double)(0)) ) + { + rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); + rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); + rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); + for(i=0; i<=s->n-1; i++) + { + for(j=i; j<=s->n-1; j++) + { + if( isupper ) + { + v = a->ptr.pp_double[i][j]; + } + else + { + v = a->ptr.pp_double[j][i]; + } + s->a.ptr.pp_double[i][j] = v; + s->a.ptr.pp_double[j][i] = v; + } + } + } + s->ismaintermchanged = ae_true; +} + + +/************************************************************************* +This subroutine changes main quadratic term of the model. + +INPUT PARAMETERS: + S - model + A - possibly preallocated buffer + +OUTPUT PARAMETERS: + A - NxN matrix, full matrix is returned. + Zero matrix is returned if model is empty. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmgeta(const convexquadraticmodel* s, + /* Real */ ae_matrix* a, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t n; + + + n = s->n; + rmatrixsetlengthatleast(a, n, n, _state); + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + v = s->alpha; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = v*s->a.ptr.pp_double[i][j]; + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + a->ptr.pp_double[i][j] = 0.0; + } + } + } +} + + +/************************************************************************* +This subroutine rewrites diagonal of the main quadratic term of the model +(dense A) by vector Z/Alpha (current value of the Alpha coefficient is +used). + +IMPORTANT: in case model has no dense quadratic term, this function + allocates N*N dense matrix of zeros, and fills its diagonal by + non-zero values. + +INPUT PARAMETERS: + S - model + Z - new diagonal, array[N] + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmrewritedensediagonal(convexquadraticmodel* s, + /* Real */ const ae_vector* z, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + + + n = s->n; + if( ae_fp_eq(s->alpha,(double)(0)) ) + { + rmatrixsetlengthatleast(&s->a, s->n, s->n, _state); + rmatrixsetlengthatleast(&s->ecadense, s->n, s->n, _state); + rmatrixsetlengthatleast(&s->tq2dense, s->n, s->n, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + s->a.ptr.pp_double[i][j] = 0.0; + } + } + s->alpha = 1.0; + } + for(i=0; i<=s->n-1; i++) + { + s->a.ptr.pp_double[i][i] = z->ptr.p_double[i]/s->alpha; + } + s->ismaintermchanged = ae_true; +} + + +/************************************************************************* +This subroutine changes diagonal quadratic term of the model. + +INPUT PARAMETERS: + S - model + D - array[N], semidefinite diagonal matrix + Tau - multiplier; when Tau=0, D is not referenced at all + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmsetd(convexquadraticmodel* s, + /* Real */ const ae_vector* d, + double tau, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(ae_isfinite(tau, _state)&&ae_fp_greater_eq(tau,(double)(0)), "CQMSetD: Tau<0 or is not finite number", _state); + ae_assert(ae_fp_eq(tau,(double)(0))||isfinitevector(d, s->n, _state), "CQMSetD: D is not finite Nx1 vector", _state); + s->tau = tau; + if( ae_fp_greater(tau,(double)(0)) ) + { + rvectorsetlengthatleast(&s->d, s->n, _state); + rvectorsetlengthatleast(&s->ecadiag, s->n, _state); + rvectorsetlengthatleast(&s->tq2diag, s->n, _state); + for(i=0; i<=s->n-1; i++) + { + ae_assert(ae_fp_greater_eq(d->ptr.p_double[i],(double)(0)), "CQMSetD: D[i]<0", _state); + s->d.ptr.p_double[i] = d->ptr.p_double[i]; + } + } + s->ismaintermchanged = ae_true; +} + + +/************************************************************************* +This subroutine drops main quadratic term A from the model. It is same as +call to CQMSetA() with zero A, but gives better performance because +algorithm knows that matrix is zero and can optimize subsequent +calculations. + +INPUT PARAMETERS: + S - model + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmdropa(convexquadraticmodel* s, ae_state *_state) +{ + + + s->alpha = 0.0; + s->ismaintermchanged = ae_true; +} + + +/************************************************************************* +This subroutine changes linear term of the model + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmsetb(convexquadraticmodel* s, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(isfinitevector(b, s->n, _state), "CQMSetB: B is not finite vector", _state); + rvectorsetlengthatleast(&s->b, s->n, _state); + for(i=0; i<=s->n-1; i++) + { + s->b.ptr.p_double[i] = b->ptr.p_double[i]; + } + s->islineartermchanged = ae_true; +} + + +/************************************************************************* +This subroutine changes linear term of the model + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmsetq(convexquadraticmodel* s, + /* Real */ const ae_matrix* q, + /* Real */ const ae_vector* r, + ae_int_t k, + double theta, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + ae_assert(k>=0, "CQMSetQ: K<0", _state); + ae_assert((k==0||ae_fp_eq(theta,(double)(0)))||apservisfinitematrix(q, k, s->n, _state), "CQMSetQ: Q is not finite matrix", _state); + ae_assert((k==0||ae_fp_eq(theta,(double)(0)))||isfinitevector(r, k, _state), "CQMSetQ: R is not finite vector", _state); + ae_assert(ae_isfinite(theta, _state)&&ae_fp_greater_eq(theta,(double)(0)), "CQMSetQ: Theta<0 or is not finite number", _state); + + /* + * degenerate case: K=0 or Theta=0 + */ + if( k==0||ae_fp_eq(theta,(double)(0)) ) + { + s->k = 0; + s->theta = (double)(0); + s->issecondarytermchanged = ae_true; + return; + } + + /* + * General case: both Theta>0 and K>0 + */ + s->k = k; + s->theta = theta; + rmatrixsetlengthatleast(&s->q, s->k, s->n, _state); + rvectorsetlengthatleast(&s->r, s->k, _state); + rmatrixsetlengthatleast(&s->eq, s->k, s->n, _state); + rmatrixsetlengthatleast(&s->eccm, s->k, s->k, _state); + rmatrixsetlengthatleast(&s->tk2, s->k, s->n, _state); + for(i=0; i<=s->k-1; i++) + { + for(j=0; j<=s->n-1; j++) + { + s->q.ptr.pp_double[i][j] = q->ptr.pp_double[i][j]; + } + s->r.ptr.p_double[i] = r->ptr.p_double[i]; + } + s->issecondarytermchanged = ae_true; +} + + +/************************************************************************* +This subroutine changes active set + +INPUT PARAMETERS + S - model + X - array[N], constraint values + ActiveSet- array[N], active set. If ActiveSet[I]=True, then I-th + variables is constrained to X[I]. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmsetactiveset(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Boolean */ const ae_vector* activeset, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(x->cnt>=s->n, "CQMSetActiveSet: Length(X)cnt>=s->n, "CQMSetActiveSet: Length(ActiveSet)n-1; i++) + { + s->isactivesetchanged = s->isactivesetchanged||(s->activeset.ptr.p_bool[i]&&!activeset->ptr.p_bool[i]); + s->isactivesetchanged = s->isactivesetchanged||(activeset->ptr.p_bool[i]&&!s->activeset.ptr.p_bool[i]); + s->activeset.ptr.p_bool[i] = activeset->ptr.p_bool[i]; + if( activeset->ptr.p_bool[i] ) + { + ae_assert(ae_isfinite(x->ptr.p_double[i], _state), "CQMSetActiveSet: X[] contains infinite constraints", _state); + s->isactivesetchanged = s->isactivesetchanged||ae_fp_neq(s->xc.ptr.p_double[i],x->ptr.p_double[i]); + s->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This subroutine evaluates model at X. Active constraints are ignored. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +double cqmeval(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + double v; + double result; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); + result = 0.0; + + /* + * main quadratic term + */ + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + result = result+s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + } + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; + } + } + + /* + * secondary quadratic term + */ + if( ae_fp_greater(s->theta,(double)(0)) ) + { + for(i=0; i<=s->k-1; i++) + { + v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + result = result+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); + } + } + + /* + * linear term + */ + for(i=0; i<=s->n-1; i++) + { + result = result+x->ptr.p_double[i]*s->b.ptr.p_double[i]; + } + return result; +} + + +/************************************************************************* +This subroutine evaluates model at X. Active constraints are ignored. +It returns: + R - model value + Noise- estimate of the numerical noise in data + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmevalx(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + double* r, + double* noise, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + double v; + double v2; + double mxq; + double eps; + + *r = 0.0; + *noise = 0.0; + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); + *r = 0.0; + *noise = 0.0; + eps = (double)2*ae_machineepsilon; + mxq = 0.0; + + /* + * Main quadratic term. + * + * Noise from the main quadratic term is equal to the + * maximum summand in the term. + */ + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = s->alpha*0.5*x->ptr.p_double[i]*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; + *r = *r+v; + *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); + } + } + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + v = 0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; + *r = *r+v; + *noise = ae_maxreal(*noise, eps*ae_fabs(v, _state), _state); + } + } + + /* + * secondary quadratic term + * + * Noise from the secondary quadratic term is estimated as follows: + * * noise in qi*x-r[i] is estimated as + * Eps*MXQ = Eps*max(|r[i]|, |q[i,j]*x[j]|) + * * noise in (qi*x-r[i])^2 is estimated as + * NOISE = (|qi*x-r[i]|+Eps*MXQ)^2-(|qi*x-r[i]|)^2 + * = Eps*MXQ*(2*|qi*x-r[i]|+Eps*MXQ) + */ + if( ae_fp_greater(s->theta,(double)(0)) ) + { + for(i=0; i<=s->k-1; i++) + { + v = 0.0; + mxq = ae_fabs(s->r.ptr.p_double[i], _state); + for(j=0; j<=n-1; j++) + { + v2 = s->q.ptr.pp_double[i][j]*x->ptr.p_double[j]; + v = v+v2; + mxq = ae_maxreal(mxq, ae_fabs(v2, _state), _state); + } + *r = *r+0.5*s->theta*ae_sqr(v-s->r.ptr.p_double[i], _state); + *noise = ae_maxreal(*noise, eps*mxq*((double)2*ae_fabs(v-s->r.ptr.p_double[i], _state)+eps*mxq), _state); + } + } + + /* + * linear term + */ + for(i=0; i<=s->n-1; i++) + { + *r = *r+x->ptr.p_double[i]*s->b.ptr.p_double[i]; + *noise = ae_maxreal(*noise, eps*ae_fabs(x->ptr.p_double[i]*s->b.ptr.p_double[i], _state), _state); + } + + /* + * Final update of the noise + */ + *noise = (double)n*(*noise); +} + + +/************************************************************************* +This subroutine evaluates gradient of the model; active constraints are +ignored. + +INPUT PARAMETERS: + S - convex model + X - point, array[N] + G - possibly preallocated buffer; resized, if too small + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmgradunconstrained(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + double v; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMEvalGradUnconstrained: X is not finite vector", _state); + rvectorsetlengthatleast(g, n, _state); + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = (double)(0); + } + + /* + * main quadratic term + */ + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = v+s->alpha*s->a.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + g->ptr.p_double[i] = g->ptr.p_double[i]+v; + } + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = g->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; + } + } + + /* + * secondary quadratic term + */ + if( ae_fp_greater(s->theta,(double)(0)) ) + { + for(i=0; i<=s->k-1; i++) + { + v = ae_v_dotproduct(&s->q.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = s->theta*(v-s->r.ptr.p_double[i]); + ae_v_addd(&g->ptr.p_double[0], 1, &s->q.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + } + + /* + * linear term + */ + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = g->ptr.p_double[i]+s->b.ptr.p_double[i]; + } +} + + +/************************************************************************* +This subroutine evaluates x'*(0.5*alpha*A+tau*D)*x + +NOTE: Tmp[] must be preallocated array whose length is at least N + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +double cqmxtadx2(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double result; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMXTADX2: X is not finite vector", _state); + ae_assert(tmp->cnt>=n, "CQMXTADX2: Length(Tmp)alpha,(double)(0)) ) + { + result = result+s->alpha*0.5*rmatrixsyvmv(n, &s->a, 0, 0, ae_true, x, 0, tmp, _state); + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + result = result+0.5*ae_sqr(x->ptr.p_double[i], _state)*s->tau*s->d.ptr.p_double[i]; + } + } + return result; +} + + +/************************************************************************* +This subroutine evaluates (0.5*alpha*A+tau*D)*x + +Y is automatically resized if needed + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmadx(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMEval: X is not finite vector", _state); + rvectorsetlengthatleast(y, n, _state); + + /* + * main quadratic term + */ + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + rmatrixsymv(n, s->alpha, &s->a, 0, 0, ae_true, x, 0, 1.0, y, 0, _state); + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + y->ptr.p_double[i] = y->ptr.p_double[i]+x->ptr.p_double[i]*s->tau*s->d.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This subroutine finds optimum of the model. It returns False on failure +(indefinite/semidefinite matrix). Optimum is found subject to active +constraints. + +INPUT PARAMETERS + S - model + X - possibly preallocated buffer; automatically resized, if + too small enough. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nfree; + ae_int_t k; + ae_int_t i; + double v; + ae_int_t cidx0; + ae_int_t itidx; + ae_bool result; + + + + /* + * Rebuild internal structures + */ + if( !cqmodels_cqmrebuild(s, _state) ) + { + result = ae_false; + return result; + } + n = s->n; + k = s->k; + nfree = s->nfree; + result = ae_true; + + /* + * Calculate initial point for the iterative refinement: + * * free components are set to zero + * * constrained components are set to their constrained values + */ + rvectorsetlengthatleast(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( s->activeset.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = s->xc.ptr.p_double[i]; + } + else + { + x->ptr.p_double[i] = (double)(0); + } + } + + /* + * Iterative refinement. + * + * In an ideal world without numerical errors it would be enough + * to make just one Newton step from initial point: + * x_new = -H^(-1)*grad(x=0) + * However, roundoff errors can significantly deteriorate quality + * of the solution. So we have to recalculate gradient and to + * perform Newton steps several times. + * + * Below we perform fixed number of Newton iterations. + */ + for(itidx=0; itidx<=cqmodels_newtonrefinementits-1; itidx++) + { + + /* + * Calculate gradient at the current point. + * Move free components of the gradient in the beginning. + */ + cqmgradunconstrained(s, x, &s->tmpg, _state); + cidx0 = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + s->tmpg.ptr.p_double[cidx0] = s->tmpg.ptr.p_double[i]; + cidx0 = cidx0+1; + } + } + + /* + * Free components of the extrema are calculated in the first NFree elements of TXC. + * + * First, we have to calculate original Newton step, without rank-K perturbations + */ + ae_v_moveneg(&s->txc.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); + cqmodels_cqmsolveea(s, &s->txc, &s->tmp0, _state); + + /* + * Then, we account for rank-K correction. + * Woodbury matrix identity is used. + */ + if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) + { + rvectorsetlengthatleast(&s->tmp0, ae_maxint(nfree, k, _state), _state); + rvectorsetlengthatleast(&s->tmp1, ae_maxint(nfree, k, _state), _state); + ae_v_moveneg(&s->tmp1.ptr.p_double[0], 1, &s->tmpg.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); + cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); + for(i=0; i<=k-1; i++) + { + v = ae_v_dotproduct(&s->eq.ptr.pp_double[i][0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); + s->tmp0.ptr.p_double[i] = v; + } + fblscholeskysolve(&s->eccm, 1.0, k, ae_true, &s->tmp0, &s->tmp1, _state); + for(i=0; i<=nfree-1; i++) + { + s->tmp1.ptr.p_double[i] = 0.0; + } + for(i=0; i<=k-1; i++) + { + v = s->tmp0.ptr.p_double[i]; + ae_v_addd(&s->tmp1.ptr.p_double[0], 1, &s->eq.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); + } + cqmodels_cqmsolveea(s, &s->tmp1, &s->tmp0, _state); + ae_v_sub(&s->txc.ptr.p_double[0], 1, &s->tmp1.ptr.p_double[0], 1, ae_v_len(0,nfree-1)); + } + + /* + * Unpack components from TXC into X. We pass through all + * free components of X and add our step. + */ + cidx0 = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+s->txc.ptr.p_double[cidx0]; + cidx0 = cidx0+1; + } + } + } + return result; +} + + +/************************************************************************* +This function scales vector by multiplying it by inverse of the diagonal +of the Hessian matrix. It should be used to accelerate steepest descent +phase of the QP solver. + +Although it is called "scale-grad", it can be called for any vector, +whether it is gradient, anti-gradient, or just some vector. + +This function does NOT takes into account current set of constraints, it +just performs matrix-vector multiplication without taking into account +constraints. + +INPUT PARAMETERS: + S - model + X - vector to scale + +OUTPUT PARAMETERS: + X - scaled vector + +NOTE: + when called for non-SPD matrices, it silently skips components of X + which correspond to zero or negative diagonal elements. + +NOTE: + this function uses diagonals of A and D; it ignores Q - rank-K term of + the quadratic model. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +void cqmscalevector(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double v; + + + n = s->n; + for(i=0; i<=n-1; i++) + { + v = 0.0; + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + v = v+s->a.ptr.pp_double[i][i]; + } + if( ae_fp_greater(s->tau,(double)(0)) ) + { + v = v+s->d.ptr.p_double[i]; + } + if( ae_fp_greater(v,(double)(0)) ) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/v; + } + } +} + + +/************************************************************************* +This function returns diagonal of the A-term. + +INPUT PARAMETERS: + S - model + +OUTPUT PARAMETERS: + D - diagonal of the A (or zero) + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void cqmgetdiaga(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = s->n; + rvectorsetlengthatleast(x, n, _state); + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + x->ptr.p_double[i] = s->a.ptr.pp_double[i][i]; + } + else + { + x->ptr.p_double[i] = (double)(0); + } + } +} + + +/************************************************************************* +This subroutine calls CQMRebuild() and evaluates model at X subject to +active constraints. + +It is intended for debug purposes only, because it evaluates model by +means of temporaries, which were calculated by CQMRebuild(). The only +purpose of this function is to check correctness of CQMRebuild() by +comparing results of this function with ones obtained by CQMEval(), which +is used as reference point. The idea is that significant deviation in +results of these two functions is evidence of some error in the +CQMRebuild(). + +NOTE: suffix T denotes that temporaries marked by T-prefix are used. There + is one more variant of this function, which uses "effective" model + built by CQMRebuild(). + +NOTE2: in case CQMRebuild() fails (due to model non-convexity), this + function returns NAN. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +double cqmdebugconstrainedevalt(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nfree; + ae_int_t i; + ae_int_t j; + double v; + double result; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalT: X is not finite vector", _state); + if( !cqmodels_cqmrebuild(s, _state) ) + { + result = _state->v_nan; + return result; + } + result = 0.0; + nfree = s->nfree; + + /* + * Reorder variables + */ + j = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; + j = j+1; + } + } + + /* + * TQ2, TQ1, TQ0 + * + */ + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + + /* + * Dense TQ2 + */ + for(i=0; i<=nfree-1; i++) + { + for(j=0; j<=nfree-1; j++) + { + result = result+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; + } + } + } + else + { + + /* + * Diagonal TQ2 + */ + for(i=0; i<=nfree-1; i++) + { + result = result+0.5*s->tq2diag.ptr.p_double[i]*ae_sqr(s->txc.ptr.p_double[i], _state); + } + } + for(i=0; i<=nfree-1; i++) + { + result = result+s->tq1.ptr.p_double[i]*s->txc.ptr.p_double[i]; + } + result = result+s->tq0; + + /* + * TK2, TK1, TK0 + */ + if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) + { + for(i=0; i<=s->k-1; i++) + { + v = (double)(0); + for(j=0; j<=nfree-1; j++) + { + v = v+s->tk2.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; + } + result = result+0.5*ae_sqr(v, _state); + } + for(i=0; i<=nfree-1; i++) + { + result = result+s->tk1.ptr.p_double[i]*s->txc.ptr.p_double[i]; + } + result = result+s->tk0; + } + + /* + * TB (Bf and Bc parts) + */ + for(i=0; i<=n-1; i++) + { + result = result+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; + } + return result; +} + + +/************************************************************************* +This subroutine calls CQMRebuild() and evaluates model at X subject to +active constraints. + +It is intended for debug purposes only, because it evaluates model by +means of "effective" matrices built by CQMRebuild(). The only purpose of +this function is to check correctness of CQMRebuild() by comparing results +of this function with ones obtained by CQMEval(), which is used as +reference point. The idea is that significant deviation in results of +these two functions is evidence of some error in the CQMRebuild(). + +NOTE: suffix E denotes that effective matrices. There is one more variant + of this function, which uses temporary matrices built by + CQMRebuild(). + +NOTE2: in case CQMRebuild() fails (due to model non-convexity), this + function returns NAN. + + -- ALGLIB -- + Copyright 12.06.2012 by Bochkanov Sergey +*************************************************************************/ +double cqmdebugconstrainedevale(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nfree; + ae_int_t i; + ae_int_t j; + double v; + double result; + + + n = s->n; + ae_assert(isfinitevector(x, n, _state), "CQMDebugConstrainedEvalE: X is not finite vector", _state); + if( !cqmodels_cqmrebuild(s, _state) ) + { + result = _state->v_nan; + return result; + } + result = 0.0; + nfree = s->nfree; + + /* + * Reorder variables + */ + j = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + ae_assert(jtxc.ptr.p_double[j] = x->ptr.p_double[i]; + j = j+1; + } + } + + /* + * ECA + */ + ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&nfree==0), "CQMDebugConstrainedEvalE: unexpected ECAKind", _state); + if( s->ecakind==0 ) + { + + /* + * Dense ECA + */ + for(i=0; i<=nfree-1; i++) + { + v = 0.0; + for(j=i; j<=nfree-1; j++) + { + v = v+s->ecadense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; + } + result = result+0.5*ae_sqr(v, _state); + } + } + if( s->ecakind==1 ) + { + + /* + * Diagonal ECA + */ + for(i=0; i<=nfree-1; i++) + { + result = result+0.5*ae_sqr(s->ecadiag.ptr.p_double[i]*s->txc.ptr.p_double[i], _state); + } + } + + /* + * EQ + */ + for(i=0; i<=s->k-1; i++) + { + v = 0.0; + for(j=0; j<=nfree-1; j++) + { + v = v+s->eq.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; + } + result = result+0.5*ae_sqr(v, _state); + } + + /* + * EB + */ + for(i=0; i<=nfree-1; i++) + { + result = result+s->eb.ptr.p_double[i]*s->txc.ptr.p_double[i]; + } + + /* + * EC + */ + result = result+s->ec; + return result; +} + + +/************************************************************************* +Internal function, rebuilds "effective" model subject to constraints. +Returns False on failure (non-SPD main quadratic term) + + -- ALGLIB -- + Copyright 10.05.2011 by Bochkanov Sergey +*************************************************************************/ +static ae_bool cqmodels_cqmrebuild(convexquadraticmodel* s, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nfree; + ae_int_t k; + ae_int_t i; + ae_int_t j; + ae_int_t ridx0; + ae_int_t ridx1; + ae_int_t cidx0; + ae_int_t cidx1; + double v; + ae_bool result; + + + if( ae_fp_eq(s->alpha,(double)(0))&&ae_fp_eq(s->tau,(double)(0)) ) + { + + /* + * Non-SPD model, quick exit + */ + result = ae_false; + return result; + } + result = ae_true; + n = s->n; + k = s->k; + + /* + * Determine number of free variables. + * Fill TXC - array whose last N-NFree elements store constraints. + */ + if( s->isactivesetchanged ) + { + s->nfree = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + s->nfree = s->nfree+1; + } + } + j = s->nfree; + for(i=0; i<=n-1; i++) + { + if( s->activeset.ptr.p_bool[i] ) + { + s->txc.ptr.p_double[j] = s->xc.ptr.p_double[i]; + j = j+1; + } + } + } + nfree = s->nfree; + + /* + * Re-evaluate TQ2/TQ1/TQ0, if needed + */ + if( s->isactivesetchanged||s->ismaintermchanged ) + { + + /* + * Handle cases Alpha>0 and Alpha=0 separately: + * * in the first case we have dense matrix + * * in the second one we have diagonal matrix, which can be + * handled more efficiently + */ + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + + /* + * Alpha>0, dense QP + * + * Split variables into two groups - free (F) and constrained (C). Reorder + * variables in such way that free vars come first, constrained are last: + * x = [xf, xc]. + * + * Main quadratic term x'*(alpha*A+tau*D)*x now splits into quadratic part, + * linear part and constant part: + * ( alpha*Aff+tau*Df alpha*Afc ) ( xf ) + * 0.5*( xf' xc' )*( )*( ) = + * ( alpha*Acf alpha*Acc+tau*Dc ) ( xc ) + * + * = 0.5*xf'*(alpha*Aff+tau*Df)*xf + (alpha*Afc*xc)'*xf + 0.5*xc'(alpha*Acc+tau*Dc)*xc + * + * We store these parts into temporary variables: + * * alpha*Aff+tau*Df, alpha*Afc, alpha*Acc+tau*Dc are stored into upper + * triangle of TQ2 + * * alpha*Afc*xc is stored into TQ1 + * * 0.5*xc'(alpha*Acc+tau*Dc)*xc is stored into TQ0 + * + * Below comes first part of the work - generation of TQ2: + * * we pass through rows of A and copy I-th row into upper block (Aff/Afc) or + * lower one (Acf/Acc) of TQ2, depending on presence of X[i] in the active set. + * RIdx0 variable contains current position for insertion into upper block, + * RIdx1 contains current position for insertion into lower one. + * * within each row, we copy J-th element into left half (Aff/Acf) or right + * one (Afc/Acc), depending on presence of X[j] in the active set. CIdx0 + * contains current position for insertion into left block, CIdx1 contains + * position for insertion into right one. + * * during copying, we multiply elements by alpha and add diagonal matrix D. + */ + ridx0 = 0; + ridx1 = s->nfree; + for(i=0; i<=n-1; i++) + { + cidx0 = 0; + cidx1 = s->nfree; + for(j=0; j<=n-1; j++) + { + if( !s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) + { + + /* + * Element belongs to Aff + */ + v = s->alpha*s->a.ptr.pp_double[i][j]; + if( i==j&&ae_fp_greater(s->tau,(double)(0)) ) + { + v = v+s->tau*s->d.ptr.p_double[i]; + } + s->tq2dense.ptr.pp_double[ridx0][cidx0] = v; + } + if( !s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) + { + + /* + * Element belongs to Afc + */ + s->tq2dense.ptr.pp_double[ridx0][cidx1] = s->alpha*s->a.ptr.pp_double[i][j]; + } + if( s->activeset.ptr.p_bool[i]&&!s->activeset.ptr.p_bool[j] ) + { + + /* + * Element belongs to Acf + */ + s->tq2dense.ptr.pp_double[ridx1][cidx0] = s->alpha*s->a.ptr.pp_double[i][j]; + } + if( s->activeset.ptr.p_bool[i]&&s->activeset.ptr.p_bool[j] ) + { + + /* + * Element belongs to Acc + */ + v = s->alpha*s->a.ptr.pp_double[i][j]; + if( i==j&&ae_fp_greater(s->tau,(double)(0)) ) + { + v = v+s->tau*s->d.ptr.p_double[i]; + } + s->tq2dense.ptr.pp_double[ridx1][cidx1] = v; + } + if( s->activeset.ptr.p_bool[j] ) + { + cidx1 = cidx1+1; + } + else + { + cidx0 = cidx0+1; + } + } + if( s->activeset.ptr.p_bool[i] ) + { + ridx1 = ridx1+1; + } + else + { + ridx0 = ridx0+1; + } + } + + /* + * Now we have TQ2, and we can evaluate TQ1. + * In the special case when we have Alpha=0, NFree=0 or NFree=N, + * TQ1 is filled by zeros. + */ + for(i=0; i<=n-1; i++) + { + s->tq1.ptr.p_double[i] = 0.0; + } + if( s->nfree>0&&s->nfreenfree, n-s->nfree, &s->tq2dense, 0, s->nfree, 0, &s->txc, s->nfree, &s->tq1, 0, _state); + } + + /* + * And finally, we evaluate TQ0. + */ + v = 0.0; + for(i=s->nfree; i<=n-1; i++) + { + for(j=s->nfree; j<=n-1; j++) + { + v = v+0.5*s->txc.ptr.p_double[i]*s->tq2dense.ptr.pp_double[i][j]*s->txc.ptr.p_double[j]; + } + } + s->tq0 = v; + } + else + { + + /* + * Alpha=0, diagonal QP + * + * Split variables into two groups - free (F) and constrained (C). Reorder + * variables in such way that free vars come first, constrained are last: + * x = [xf, xc]. + * + * Main quadratic term x'*(tau*D)*x now splits into quadratic and constant + * parts: + * ( tau*Df ) ( xf ) + * 0.5*( xf' xc' )*( )*( ) = + * ( tau*Dc ) ( xc ) + * + * = 0.5*xf'*(tau*Df)*xf + 0.5*xc'(tau*Dc)*xc + * + * We store these parts into temporary variables: + * * tau*Df is stored in TQ2Diag + * * 0.5*xc'(tau*Dc)*xc is stored into TQ0 + */ + s->tq0 = 0.0; + ridx0 = 0; + for(i=0; i<=n-1; i++) + { + if( !s->activeset.ptr.p_bool[i] ) + { + s->tq2diag.ptr.p_double[ridx0] = s->tau*s->d.ptr.p_double[i]; + ridx0 = ridx0+1; + } + else + { + s->tq0 = s->tq0+0.5*s->tau*s->d.ptr.p_double[i]*ae_sqr(s->xc.ptr.p_double[i], _state); + } + } + for(i=0; i<=n-1; i++) + { + s->tq1.ptr.p_double[i] = 0.0; + } + } + } + + /* + * Re-evaluate TK2/TK1/TK0, if needed + */ + if( s->isactivesetchanged||s->issecondarytermchanged ) + { + + /* + * Split variables into two groups - free (F) and constrained (C). Reorder + * variables in such way that free vars come first, constrained are last: + * x = [xf, xc]. + * + * Secondary term theta*(Q*x-r)'*(Q*x-r) now splits into quadratic part, + * linear part and constant part: + * ( ( xf ) )' ( ( xf ) ) + * 0.5*theta*( (Qf Qc)'*( ) - r ) * ( (Qf Qc)'*( ) - r ) = + * ( ( xc ) ) ( ( xc ) ) + * + * = 0.5*theta*xf'*(Qf'*Qf)*xf + theta*((Qc*xc-r)'*Qf)*xf + + * + theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) + * + * We store these parts into temporary variables: + * * sqrt(theta)*Qf is stored into TK2 + * * theta*((Qc*xc-r)'*Qf) is stored into TK1 + * * theta*(-r'*(Qc*xc-r)-0.5*r'*r+0.5*xc'*Qc'*Qc*xc) is stored into TK0 + * + * We use several other temporaries to store intermediate results: + * * Tmp0 - to store Qc*xc-r + * * Tmp1 - to store Qc*xc + * + * Generation of TK2/TK1/TK0 is performed as follows: + * * we fill TK2/TK1/TK0 (to handle K=0 or Theta=0) + * * other steps are performed only for K>0 and Theta>0 + * * we pass through columns of Q and copy I-th column into left block (Qf) or + * right one (Qc) of TK2, depending on presence of X[i] in the active set. + * CIdx0 variable contains current position for insertion into upper block, + * CIdx1 contains current position for insertion into lower one. + * * we calculate Qc*xc-r and store it into Tmp0 + * * we calculate TK0 and TK1 + * * we multiply leading part of TK2 which stores Qf by sqrt(theta) + * it is important to perform this step AFTER calculation of TK0 and TK1, + * because we need original (non-modified) Qf to calculate TK0 and TK1. + */ + for(j=0; j<=n-1; j++) + { + for(i=0; i<=k-1; i++) + { + s->tk2.ptr.pp_double[i][j] = 0.0; + } + s->tk1.ptr.p_double[j] = 0.0; + } + s->tk0 = 0.0; + if( s->k>0&&ae_fp_greater(s->theta,(double)(0)) ) + { + + /* + * Split Q into Qf and Qc + * Calculate Qc*xc-r, store in Tmp0 + */ + rvectorsetlengthatleast(&s->tmp0, k, _state); + rvectorsetlengthatleast(&s->tmp1, k, _state); + cidx0 = 0; + cidx1 = nfree; + for(i=0; i<=k-1; i++) + { + s->tmp1.ptr.p_double[i] = 0.0; + } + for(j=0; j<=n-1; j++) + { + if( s->activeset.ptr.p_bool[j] ) + { + for(i=0; i<=k-1; i++) + { + s->tk2.ptr.pp_double[i][cidx1] = s->q.ptr.pp_double[i][j]; + s->tmp1.ptr.p_double[i] = s->tmp1.ptr.p_double[i]+s->q.ptr.pp_double[i][j]*s->txc.ptr.p_double[cidx1]; + } + cidx1 = cidx1+1; + } + else + { + for(i=0; i<=k-1; i++) + { + s->tk2.ptr.pp_double[i][cidx0] = s->q.ptr.pp_double[i][j]; + } + cidx0 = cidx0+1; + } + } + for(i=0; i<=k-1; i++) + { + s->tmp0.ptr.p_double[i] = s->tmp1.ptr.p_double[i]-s->r.ptr.p_double[i]; + } + + /* + * Calculate TK0 + */ + v = 0.0; + for(i=0; i<=k-1; i++) + { + v = v+s->theta*(0.5*ae_sqr(s->tmp1.ptr.p_double[i], _state)-s->r.ptr.p_double[i]*s->tmp0.ptr.p_double[i]-0.5*ae_sqr(s->r.ptr.p_double[i], _state)); + } + s->tk0 = v; + + /* + * Calculate TK1 + */ + if( nfree>0 ) + { + for(i=0; i<=k-1; i++) + { + v = s->theta*s->tmp0.ptr.p_double[i]; + ae_v_addd(&s->tk1.ptr.p_double[0], 1, &s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); + } + } + + /* + * Calculate TK2 + */ + if( nfree>0 ) + { + v = ae_sqrt(s->theta, _state); + for(i=0; i<=k-1; i++) + { + ae_v_muld(&s->tk2.ptr.pp_double[i][0], 1, ae_v_len(0,nfree-1), v); + } + } + } + } + + /* + * Re-evaluate TB + */ + if( s->isactivesetchanged||s->islineartermchanged ) + { + ridx0 = 0; + ridx1 = nfree; + for(i=0; i<=n-1; i++) + { + if( s->activeset.ptr.p_bool[i] ) + { + s->tb.ptr.p_double[ridx1] = s->b.ptr.p_double[i]; + ridx1 = ridx1+1; + } + else + { + s->tb.ptr.p_double[ridx0] = s->b.ptr.p_double[i]; + ridx0 = ridx0+1; + } + } + } + + /* + * Compose ECA: either dense ECA or diagonal ECA + */ + if( (s->isactivesetchanged||s->ismaintermchanged)&&nfree>0 ) + { + if( ae_fp_greater(s->alpha,(double)(0)) ) + { + + /* + * Dense ECA + */ + s->ecakind = 0; + for(i=0; i<=nfree-1; i++) + { + for(j=i; j<=nfree-1; j++) + { + s->ecadense.ptr.pp_double[i][j] = s->tq2dense.ptr.pp_double[i][j]; + } + } + if( !spdmatrixcholeskyrec(&s->ecadense, 0, nfree, ae_true, &s->tmp0, _state) ) + { + result = ae_false; + return result; + } + } + else + { + + /* + * Diagonal ECA + */ + s->ecakind = 1; + for(i=0; i<=nfree-1; i++) + { + if( ae_fp_less(s->tq2diag.ptr.p_double[i],(double)(0)) ) + { + result = ae_false; + return result; + } + s->ecadiag.ptr.p_double[i] = ae_sqrt(s->tq2diag.ptr.p_double[i], _state); + } + } + } + + /* + * Compose EQ + */ + if( s->isactivesetchanged||s->issecondarytermchanged ) + { + for(i=0; i<=k-1; i++) + { + for(j=0; j<=nfree-1; j++) + { + s->eq.ptr.pp_double[i][j] = s->tk2.ptr.pp_double[i][j]; + } + } + } + + /* + * Calculate ECCM + */ + if( ((((s->isactivesetchanged||s->ismaintermchanged)||s->issecondarytermchanged)&&s->k>0)&&ae_fp_greater(s->theta,(double)(0)))&&nfree>0 ) + { + + /* + * Calculate ECCM - Cholesky factor of the "effective" capacitance + * matrix CM = I + EQ*inv(EffectiveA)*EQ'. + * + * We calculate CM as follows: + * CM = I + EQ*inv(EffectiveA)*EQ' + * = I + EQ*ECA^(-1)*ECA^(-T)*EQ' + * = I + (EQ*ECA^(-1))*(EQ*ECA^(-1))' + * + * Then we perform Cholesky decomposition of CM. + */ + rmatrixsetlengthatleast(&s->tmp2, k, n, _state); + rmatrixcopy(k, nfree, &s->eq, 0, 0, &s->tmp2, 0, 0, _state); + ae_assert(s->ecakind==0||s->ecakind==1, "CQMRebuild: unexpected ECAKind", _state); + if( s->ecakind==0 ) + { + rmatrixrighttrsm(k, nfree, &s->ecadense, 0, 0, ae_true, ae_false, 0, &s->tmp2, 0, 0, _state); + } + if( s->ecakind==1 ) + { + for(i=0; i<=k-1; i++) + { + for(j=0; j<=nfree-1; j++) + { + s->tmp2.ptr.pp_double[i][j] = s->tmp2.ptr.pp_double[i][j]/s->ecadiag.ptr.p_double[j]; + } + } + } + for(i=0; i<=k-1; i++) + { + for(j=0; j<=k-1; j++) + { + s->eccm.ptr.pp_double[i][j] = 0.0; + } + s->eccm.ptr.pp_double[i][i] = 1.0; + } + rmatrixsyrk(k, nfree, 1.0, &s->tmp2, 0, 0, 0, 1.0, &s->eccm, 0, 0, ae_true, _state); + if( !spdmatrixcholeskyrec(&s->eccm, 0, k, ae_true, &s->tmp0, _state) ) + { + result = ae_false; + return result; + } + } + + /* + * Compose EB and EC + * + * NOTE: because these quantities are cheap to compute, we do not + * use caching here. + */ + for(i=0; i<=nfree-1; i++) + { + s->eb.ptr.p_double[i] = s->tq1.ptr.p_double[i]+s->tk1.ptr.p_double[i]+s->tb.ptr.p_double[i]; + } + s->ec = s->tq0+s->tk0; + for(i=nfree; i<=n-1; i++) + { + s->ec = s->ec+s->tb.ptr.p_double[i]*s->txc.ptr.p_double[i]; + } + + /* + * Change cache status - everything is cached + */ + s->ismaintermchanged = ae_false; + s->issecondarytermchanged = ae_false; + s->islineartermchanged = ae_false; + s->isactivesetchanged = ae_false; + return result; +} + + +/************************************************************************* +Internal function, solves system Effective_A*x = b. +It should be called after successful completion of CQMRebuild(). + +INPUT PARAMETERS: + S - quadratic model, after call to CQMRebuild() + X - right part B, array[S.NFree] + Tmp - temporary array, automatically reallocated if needed + +OUTPUT PARAMETERS: + X - solution, array[S.NFree] + +NOTE: when called with zero S.NFree, returns silently +NOTE: this function assumes that EA is non-degenerate + + -- ALGLIB -- + Copyright 10.05.2011 by Bochkanov Sergey +*************************************************************************/ +static void cqmodels_cqmsolveea(convexquadraticmodel* s, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert((s->ecakind==0||s->ecakind==1)||(s->ecakind==-1&&s->nfree==0), "CQMSolveEA: unexpected ECAKind", _state); + if( s->ecakind==0 ) + { + + /* + * Dense ECA, use FBLSCholeskySolve() dense solver. + */ + fblscholeskysolve(&s->ecadense, 1.0, s->nfree, ae_true, x, tmp, _state); + } + if( s->ecakind==1 ) + { + + /* + * Diagonal ECA + */ + for(i=0; i<=s->nfree-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/ae_sqr(s->ecadiag.ptr.p_double[i], _state); + } + } +} + + +void _convexquadraticmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + convexquadraticmodel *p = (convexquadraticmodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->a, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->activeset, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->tq2dense, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tk2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tq2diag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tq1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tk1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->txc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tb, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ecadense, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->eq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->eccm, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ecadiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _convexquadraticmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + convexquadraticmodel *dst = (convexquadraticmodel*)_dst; + const convexquadraticmodel *src = (const convexquadraticmodel*)_src; + dst->n = src->n; + dst->k = src->k; + dst->alpha = src->alpha; + dst->tau = src->tau; + dst->theta = src->theta; + ae_matrix_init_copy(&dst->a, &src->a, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->activeset, &src->activeset, _state, make_automatic); + ae_matrix_init_copy(&dst->tq2dense, &src->tq2dense, _state, make_automatic); + ae_matrix_init_copy(&dst->tk2, &src->tk2, _state, make_automatic); + ae_vector_init_copy(&dst->tq2diag, &src->tq2diag, _state, make_automatic); + ae_vector_init_copy(&dst->tq1, &src->tq1, _state, make_automatic); + ae_vector_init_copy(&dst->tk1, &src->tk1, _state, make_automatic); + dst->tq0 = src->tq0; + dst->tk0 = src->tk0; + ae_vector_init_copy(&dst->txc, &src->txc, _state, make_automatic); + ae_vector_init_copy(&dst->tb, &src->tb, _state, make_automatic); + dst->nfree = src->nfree; + dst->ecakind = src->ecakind; + ae_matrix_init_copy(&dst->ecadense, &src->ecadense, _state, make_automatic); + ae_matrix_init_copy(&dst->eq, &src->eq, _state, make_automatic); + ae_matrix_init_copy(&dst->eccm, &src->eccm, _state, make_automatic); + ae_vector_init_copy(&dst->ecadiag, &src->ecadiag, _state, make_automatic); + ae_vector_init_copy(&dst->eb, &src->eb, _state, make_automatic); + dst->ec = src->ec; + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state, make_automatic); + ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + dst->ismaintermchanged = src->ismaintermchanged; + dst->issecondarytermchanged = src->issecondarytermchanged; + dst->islineartermchanged = src->islineartermchanged; + dst->isactivesetchanged = src->isactivesetchanged; +} + + +void _convexquadraticmodel_clear(void* _p) +{ + convexquadraticmodel *p = (convexquadraticmodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->a); + ae_matrix_clear(&p->q); + ae_vector_clear(&p->b); + ae_vector_clear(&p->r); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->d); + ae_vector_clear(&p->activeset); + ae_matrix_clear(&p->tq2dense); + ae_matrix_clear(&p->tk2); + ae_vector_clear(&p->tq2diag); + ae_vector_clear(&p->tq1); + ae_vector_clear(&p->tk1); + ae_vector_clear(&p->txc); + ae_vector_clear(&p->tb); + ae_matrix_clear(&p->ecadense); + ae_matrix_clear(&p->eq); + ae_matrix_clear(&p->eccm); + ae_vector_clear(&p->ecadiag); + ae_vector_clear(&p->eb); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmpg); + ae_matrix_clear(&p->tmp2); +} + + +void _convexquadraticmodel_destroy(void* _p) +{ + convexquadraticmodel *p = (convexquadraticmodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->a); + ae_matrix_destroy(&p->q); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->r); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->activeset); + ae_matrix_destroy(&p->tq2dense); + ae_matrix_destroy(&p->tk2); + ae_vector_destroy(&p->tq2diag); + ae_vector_destroy(&p->tq1); + ae_vector_destroy(&p->tk1); + ae_vector_destroy(&p->txc); + ae_vector_destroy(&p->tb); + ae_matrix_destroy(&p->ecadense); + ae_matrix_destroy(&p->eq); + ae_matrix_destroy(&p->eccm); + ae_vector_destroy(&p->ecadiag); + ae_vector_destroy(&p->eb); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmpg); + ae_matrix_destroy(&p->tmp2); +} + + +#endif +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +two-sided "lower-bound/upper-bound" constraints stored in mixed dense/sparse format. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[N]. Can be zero. + N - number of variables. + SparseA - sparse M*N constraint matrix in CRS format; + ignored if M=0. + M - sparse constraint count, M>=0 + AL - lower bounds for constraints, array[M] + AU - upper bounds for constraints, array[M] + +OUTPUT PARAMETERS: + SparseA - replaced by scaled/shifted constraints + AL - replaced by scaled/shifted lower bounds + AU - replaced by scaled/shifted upper bounds + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaleshiftmixedlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + + + ae_assert(msparse==0||((sparsea->matrixtype==1&&sparsea->m==msparse)&&sparsea->n==n), "ScaleShiftMixedLCInplace: non-CRS sparse constraint matrix!", _state); + for(i=0; i<=msparse+mdense-1; i++) + { + + /* + * Scale/shift constraint; shift its lower and upper bounds + */ + if( iridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + j = sparsea->idx.ptr.p_int[k]; + vv = sparsea->vals.ptr.p_double[k]; + v = v+vv*xorigin->ptr.p_double[j]; + sparsea->vals.ptr.p_double[k] = vv*s->ptr.p_double[j]; + } + al->ptr.p_double[i] = al->ptr.p_double[i]-v; + au->ptr.p_double[i] = au->ptr.p_double[i]-v; + } + else + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + vv = densea->ptr.pp_double[i-msparse][j]; + v = v+vv*xorigin->ptr.p_double[j]; + densea->ptr.pp_double[i-msparse][j] = vv*s->ptr.p_double[j]; + } + al->ptr.p_double[i] = al->ptr.p_double[i]-v; + au->ptr.p_double[i] = au->ptr.p_double[i]-v; + } + } +} + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +the box constraints. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[N]. Can be zero. + BndL - raw lower bounds, array[N] + BndU - raw upper bounds, array[N] + N - number of variables. + +OUTPUT PARAMETERS: + BndL - replaced by scaled/shifted lower bounds, array[N] + BndU - replaced by scaled/shifted upper bounds, array[N] + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaleshiftbcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_bool hasbndl; + ae_bool hasbndu; + + + for(i=0; i<=n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state)&&s->ptr.p_double[i]>0.0, "ScaleShiftBC: S[i] is nonpositive", _state); + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "ScaleShiftBC: BndL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "ScaleShiftBC: BndU[i] is -INF or NAN", _state); + hasbndl = ae_isfinite(bndl->ptr.p_double[i], _state); + hasbndu = ae_isfinite(bndu->ptr.p_double[i], _state); + if( (hasbndl&&hasbndu)&&ae_fp_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + + /* + * Make sure that BndL[I]=BndU[I] bit-to-bit + * even with CRAZY optimizing compiler. + */ + bndu->ptr.p_double[i] = (bndu->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + bndl->ptr.p_double[i] = bndu->ptr.p_double[i]; + continue; + } + if( hasbndl ) + { + bndl->ptr.p_double[i] = (bndl->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + } + if( hasbndu ) + { + bndu->ptr.p_double[i] = (bndu->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +two-sided "lower-bound/range" constraints stored in dense format. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[N]. Can be zero. + N - number of variables. + DenseA - array[M,N], constraint matrix + AB - lower bounds for constraints, always present and + finite, array[M] + AR - ranges for constraints, can be zero (equality + constraint), positive (range constraint) or +INF + (lower bound constraint), array[M] + M - constraint count, M>=0 + +OUTPUT PARAMETERS: + DenseA - replaced by scaled/shifted constraints, array[M,N] + AB - replaced by scaled/shifted lower bounds, array[M] + AR - replaced by scaled/shifted ranges, array[M] + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaleshiftdensebrlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + /* Real */ ae_matrix* densea, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t m, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double vv; + + + for(i=0; i<=m-1; i++) + { + + /* + * Scale/shift constraint; shift its lower bound + * + * NOTE: range is NOT scaled or shifted + */ + v = 0.0; + for(j=0; j<=n-1; j++) + { + vv = densea->ptr.pp_double[i][j]; + v = v+vv*xorigin->ptr.p_double[j]; + densea->ptr.pp_double[i][j] = vv*s->ptr.p_double[j]; + } + ab->ptr.p_double[i] = ab->ptr.p_double[i]-v; + } +} + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +two-sided "lower-bound/range" constraints stored in dense format. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[N]. Can be zero. + N - number of variables. + SparseA - sparse MSparse*N constraint matrix in CRS format; + ignored if MSparse=0. + MSparse - dense constraint count, MSparse>=0 + DenseA - array[MDense,N], constraint matrix; + ignored if MDense=0. + MDense - dense constraint count, MDense>=0 + AB - lower bounds for constraints, always present and + finite, array[MSparse+MDense] + AR - ranges for constraints, can be zero (equality + constraint), positive (range constraint) or +INF + (lower bound constraint), array[MSparse+MDense] + +OUTPUT PARAMETERS: + DenseA - replaced by scaled/shifted constraints, array[MDense,N] + SparseA - replaced by scaled/shifted constraints, array[MSparse,N] + AB - replaced by scaled/shifted lower bounds, array[MDense+MSparse] + AR - replaced by scaled/shifted ranges, array[MDense+MSparse] + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaleshiftmixedbrlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + + + ae_assert(msparse==0||((sparsea->matrixtype==1&&sparsea->m==msparse)&&sparsea->n==n), "ScaleShiftMixedBRLCInplace: non-CRS sparse constraint matrix!", _state); + for(i=0; i<=msparse-1; i++) + { + + /* + * Scale/shift constraint; shift its lower bound + * + * NOTE: range is NOT scaled or shifted + */ + v = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + j = sparsea->idx.ptr.p_int[k]; + vv = sparsea->vals.ptr.p_double[k]; + v = v+vv*xorigin->ptr.p_double[j]; + sparsea->vals.ptr.p_double[k] = vv*s->ptr.p_double[j]; + } + ab->ptr.p_double[i] = ab->ptr.p_double[i]-v; + } + for(i=0; i<=mdense-1; i++) + { + + /* + * Scale/shift constraint; shift its lower bound + * + * NOTE: range is NOT scaled or shifted + */ + v = 0.0; + for(j=0; j<=n-1; j++) + { + vv = densea->ptr.pp_double[i][j]; + v = v+vv*xorigin->ptr.p_double[j]; + densea->ptr.pp_double[i][j] = vv*s->ptr.p_double[j]; + } + ab->ptr.p_double[msparse+i] = ab->ptr.p_double[msparse+i]-v; + } +} + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +two-sided "lower-bound/upper-bound" constraints stored in sparse format. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[N]. Can be zero. + N - number of variables. + SparseA - sparse M*N constraint matrix in CRS format; + ignored if M=0. + M - sparse constraint count, M>=0 + AL - lower bounds for constraints, array[M] + AU - upper bounds for constraints, array[M] + +OUTPUT PARAMETERS: + SparseA - replaced by scaled/shifted constraints + AL - replaced by scaled/shifted lower bounds + AU - replaced by scaled/shifted upper bounds + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaleshiftsparselcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + + + ae_assert(m==0||((sparsea->matrixtype==1&&sparsea->m==m)&&sparsea->n==n), "ScaleShiftSparseLCInplace: non-CRS sparse constraint matrix!", _state); + for(i=0; i<=m-1; i++) + { + + /* + * Scale/shift constraint; shift its lower and upper bounds + */ + v = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + j = sparsea->idx.ptr.p_int[k]; + vv = sparsea->vals.ptr.p_double[k]; + v = v+vv*xorigin->ptr.p_double[j]; + sparsea->vals.ptr.p_double[k] = vv*s->ptr.p_double[j]; + } + al->ptr.p_double[i] = al->ptr.p_double[i]-v; + au->ptr.p_double[i] = au->ptr.p_double[i]-v; + } +} + + +/************************************************************************* +This function generates scaled (by S) reformulation of dense quadratic and +linear terms in QP problem. + +INPUT PARAMETERS: + N - number of variables. + DenseA - array[NMain,NMain], quadratic term + IsUpper - whether upper or lower triangle is present + NMain - number of nonslack vars, 1<=NMain<=NTotal + DenseB - array[NTotal], linear term + NTotal - total number of variables, NTotal>=1 + S - scale vector, array[NTotal]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + +OUTPUT PARAMETERS: + DenseA - replaced by scaled term, array[N,N] + DenseB - replaced by scaled term, array[N] + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scaledenseqpinplace(/* Real */ ae_matrix* densea, + ae_bool isupper, + ae_int_t nmain, + /* Real */ ae_vector* denseb, + ae_int_t ntotal, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double si; + + + for(i=0; i<=nmain-1; i++) + { + si = s->ptr.p_double[i]; + if( isupper ) + { + j0 = i; + j1 = nmain-1; + } + else + { + j0 = 0; + j1 = i; + } + for(j=j0; j<=j1; j++) + { + densea->ptr.pp_double[i][j] = densea->ptr.pp_double[i][j]*si*s->ptr.p_double[j]; + } + } + for(i=0; i<=ntotal-1; i++) + { + denseb->ptr.p_double[i] = denseb->ptr.p_double[i]*s->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function generates scaled (by S) reformulation of sparse quadratic and +linear terms in QP problem. + +INPUT PARAMETERS: + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + N - number of variables. + SparseA - quadratic term, NxN SparseMatrix in CRS format + (any triangle can be present, we will scale everything) + DenseCorrC - array[CorrRank,N], low rank correction C'*D*C being + added to the quadratic term + DenseCorrD - array[CorrRank], low rank correction, diagonal factors + CorrRank - correction rank, >=0 + DenseB - array[N], linear term + +OUTPUT PARAMETERS: + SparseA - replaced by scaled term + DenseB - replaced by scaled term + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void scalesparseqpinplace(/* Real */ const ae_vector* s, + ae_int_t n, + sparsematrix* sparsea, + /* Real */ ae_matrix* densecorrc, + /* Real */ ae_vector* densecorrd, + ae_int_t corrrank, + /* Real */ ae_vector* denseb, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k0; + ae_int_t k1; + ae_int_t k; + double si; + + + ae_assert((sparsea->matrixtype==1&&sparsea->m==n)&&sparsea->n==n, "ScaleSparseQPInplace: SparseA in unexpected format", _state); + for(i=0; i<=n-1; i++) + { + si = s->ptr.p_double[i]; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*si*s->ptr.p_double[sparsea->idx.ptr.p_int[k]]; + } + denseb->ptr.p_double[i] = denseb->ptr.p_double[i]*si; + } + for(k=0; k<=corrrank-1; k++) + { + for(i=0; i<=n-1; i++) + { + densecorrc->ptr.pp_double[k][i] = densecorrc->ptr.pp_double[k][i]*s->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function normalizes two-sided "lower-bound/range" constraints stored +in dense format in such a way that L2 norms of rows (right hand side NOT +included) become equal to 1.0. Exactly zero rows are handled correctly. + +INPUT PARAMETERS: + DenseA - array[M,N], constraint matrix + AB - lower bounds for constraints, always present and + finite, array[M] + AR - ranges for constraints, can be zero (equality + constraint), positive (range constraint) or +INF + (lower bound constraint), array[M] + N - number of variables, N>=1. + M - constraint count, M>=0 + NeedNorms - whether we need row norms or not + +OUTPUT PARAMETERS: + DenseA - replaced by normalized constraints, array[M,N] + AB - replaced by normalized lower bounds, array[M] + AR - replaced by normalized ranges, array[M] + RowNorms - if NeedNorms is true, leading M elements (resized + if length is less than M) are filled by row norms + before normalization was performed. + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void normalizedensebrlcinplace(/* Real */ ae_matrix* densea, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double vv; + + + if( neednorms ) + { + rvectorsetlengthatleast(rownorms, m, _state); + } + for(i=0; i<=m-1; i++) + { + vv = 0.0; + for(j=0; j<=n-1; j++) + { + v = densea->ptr.pp_double[i][j]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + if( neednorms ) + { + rownorms->ptr.p_double[i] = vv; + } + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + for(j=0; j<=n-1; j++) + { + densea->ptr.pp_double[i][j] = densea->ptr.pp_double[i][j]*vv; + } + ab->ptr.p_double[i] = ab->ptr.p_double[i]*vv; + if( ae_isfinite(ar->ptr.p_double[i], _state) ) + { + ar->ptr.p_double[i] = ar->ptr.p_double[i]*vv; + } + } + } +} + + +/************************************************************************* +This function normalizes two-sided "lower-bound/range" constraints stored +in dense format in such a way that L2 norms of rows (right hand side NOT +included) become equal to 1.0. Exactly zero rows are handled correctly. + +INPUT PARAMETERS: + SparseA - sparse MSparse*N constraint matrix in CRS format; + ignored if MSparse=0. + MSparse - dense constraint count, MSparse>=0 + DenseA - array[MDense,N], constraint matrix; + ignored if MDense=0. + MDense - dense constraint count, MDense>=0 + AB - lower bounds for constraints, always present and + finite, array[MSparse+MDense] + AR - ranges for constraints, can be zero (equality + constraint), positive (range constraint) or +INF + (lower bound constraint), array[MSparse+MDense] + N - number of variables, N>=1. + LimitedAmplification- whether row amplification is limited or not: + * if False, rows with small norms (less than 1.0) + are always normalized + * if True, we do not increase individual row norms + during normalization - only decrease. However, + we may apply one amplification round to the entire + constraint matrix, i.e. amplify all rows by the same + coefficient. As result, we do not overamplify + any single row, but still make sure than the entire + problem is well scaled. + * large rows are always normalized + NeedNorms - whether we need row norms or not + +OUTPUT PARAMETERS: + DenseA - replaced by normalized constraints, array[M,N] + AB - replaced by normalized lower bounds, array[M] + AR - replaced by normalized ranges, array[M] + RowNorms - if NeedNorms is true, leading M elements (resized + if length is less than M) are filled by row norms + before normalization was performed. + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void normalizemixedbrlcinplace(sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + double maxnrm2; + + + ae_assert(msparse==0||((sparsea->matrixtype==1&&sparsea->m==msparse)&&sparsea->n==n), "ScaleShiftMixedBRLCInplace: non-CRS sparse constraint matrix!", _state); + if( neednorms ) + { + rvectorsetlengthatleast(rownorms, mdense+msparse, _state); + } + + /* + * First round of normalization - normalize row 2-norms subject to limited amplification status + */ + maxnrm2 = (double)(0); + for(i=0; i<=msparse-1; i++) + { + vv = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + v = sparsea->vals.ptr.p_double[k]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + if( limitedamplification ) + { + vv = ae_maxreal(vv, 1.0, _state); + } + if( neednorms ) + { + rownorms->ptr.p_double[i] = vv; + } + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*vv; + } + ab->ptr.p_double[i] = ab->ptr.p_double[i]*vv; + if( ae_isfinite(ar->ptr.p_double[i], _state) ) + { + ar->ptr.p_double[i] = ar->ptr.p_double[i]*vv; + } + } + } + for(i=0; i<=mdense-1; i++) + { + vv = 0.0; + for(j=0; j<=n-1; j++) + { + v = densea->ptr.pp_double[i][j]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + if( limitedamplification ) + { + vv = ae_maxreal(vv, 1.0, _state); + } + if( neednorms ) + { + rownorms->ptr.p_double[msparse+i] = vv; + } + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + for(j=0; j<=n-1; j++) + { + densea->ptr.pp_double[i][j] = densea->ptr.pp_double[i][j]*vv; + } + ab->ptr.p_double[msparse+i] = ab->ptr.p_double[msparse+i]*vv; + if( ae_isfinite(ar->ptr.p_double[msparse+i], _state) ) + { + ar->ptr.p_double[msparse+i] = ar->ptr.p_double[msparse+i]*vv; + } + } + } + + /* + * If amplification was limited, perform second round of normalization + */ + if( limitedamplification ) + { + + /* + * Recompute maximum norm + */ + maxnrm2 = (double)(0); + for(i=0; i<=msparse-1; i++) + { + vv = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + v = sparsea->vals.ptr.p_double[k]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + } + for(i=0; i<=mdense-1; i++) + { + maxnrm2 = ae_maxreal(maxnrm2, ae_sqrt(rdotrr(n, densea, i, densea, i, _state), _state), _state); + } + + /* + * Amplify, if needed + */ + if( ae_fp_less(maxnrm2,1.0)&&ae_fp_greater(maxnrm2,(double)(0)) ) + { + if( neednorms ) + { + rmulv(mdense+msparse, maxnrm2, rownorms, _state); + } + vv = (double)1/maxnrm2; + for(i=0; i<=msparse-1; i++) + { + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*vv; + } + ab->ptr.p_double[i] = ab->ptr.p_double[i]*vv; + if( ae_isfinite(ar->ptr.p_double[i], _state) ) + { + ar->ptr.p_double[i] = ar->ptr.p_double[i]*vv; + } + } + for(i=0; i<=mdense-1; i++) + { + rmulr(n, vv, densea, i, _state); + ab->ptr.p_double[msparse+i] = ab->ptr.p_double[msparse+i]*vv; + if( ae_isfinite(ar->ptr.p_double[msparse+i], _state) ) + { + ar->ptr.p_double[msparse+i] = ar->ptr.p_double[msparse+i]*vv; + } + } + } + } +} + + +/************************************************************************* +This function normalizes two-sided "lower-bound/upper-bound" constraints +stored in dense format in such a way that L2 norms of rows (right hand +side NOT included) become equal to 1.0. + +Exactly zero rows are handled correctly. + +INPUT PARAMETERS: + DenseA - dense M*N constraint matrix; + ignored if M=0. + M - constraint count, M>=0 + AL - lower bounds for constraints, array[M] + AU - upper bounds for constraints, array[M] + N - number of variables, N>=1. + LimitedAmplification- whether row amplification is limited or not: + * if False, rows with small norms (less than 1.0) + are always normalized + * if True, we do not increase individual row norms + during normalization - only decrease. However, + we may apply one amplification rount to entire + constraint matrix, i.e. amplify all rows by same + coefficient. As result, we do not overamplify + any single row, but still make sure than entire + problem is well scaled. + * large rows are always normalized + NeedNorms - whether we need row norms or not + +OUTPUT PARAMETERS: + SparseA - replaced by normalized constraints + AL - replaced by normalized lower bounds + AU - replaced by normalized upper bounds + RowNorms - if NeedNorms is true, leading M elements (resized + if length is less than M) are filled by row norms + before normalization was performed. + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void normalizedenselcinplace(/* Real */ ae_matrix* densea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state) +{ + ae_int_t i; + double vv; + double maxnrm2; + + + ae_assert(m==0||(densea->rows>=m&&densea->cols>=n), "NormalizeDenseLCInplace: matrix size is too small", _state); + if( neednorms ) + { + rallocv(m, rownorms, _state); + } + + /* + * First round of normalization - normalize row 2-norms subject to limited amplification status + */ + for(i=0; i<=m-1; i++) + { + vv = ae_sqrt(rdotrr(n, densea, i, densea, i, _state), _state); + if( limitedamplification ) + { + vv = ae_maxreal(vv, 1.0, _state); + } + if( neednorms ) + { + rownorms->ptr.p_double[i] = vv; + } + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + rmulr(n, vv, densea, i, _state); + al->ptr.p_double[i] = al->ptr.p_double[i]*vv; + au->ptr.p_double[i] = au->ptr.p_double[i]*vv; + } + } + + /* + * If amplification was limited, perform second round of normalization + */ + if( limitedamplification ) + { + maxnrm2 = (double)(0); + for(i=0; i<=m-1; i++) + { + maxnrm2 = ae_maxreal(maxnrm2, ae_sqrt(rdotrr(n, densea, i, densea, i, _state), _state), _state); + } + if( ae_fp_less(maxnrm2,1.0)&&ae_fp_greater(maxnrm2,(double)(0)) ) + { + if( neednorms ) + { + rmulv(m, maxnrm2, rownorms, _state); + } + vv = (double)1/maxnrm2; + for(i=0; i<=m-1; i++) + { + rmulr(n, vv, densea, i, _state); + al->ptr.p_double[i] = al->ptr.p_double[i]*vv; + au->ptr.p_double[i] = au->ptr.p_double[i]*vv; + } + } + } +} + + +/************************************************************************* +This function normalizes two-sided "lower-bound/upper-bound" constraints +stored in sparse format in such a way that L2 norms of rows (right hand +side NOT included) become equal to 1.0. + +Exactly zero rows are handled correctly. + +INPUT PARAMETERS: + SparseA - sparse M*N constraint matrix in CRS format; + ignored if M=0. + M - constraint count, M>=0 + AL - lower bounds for constraints, array[M] + AU - upper bounds for constraints, array[M] + N - number of variables, N>=1. + LimitedAmplification- whether row amplification is limited or not: + * if False, rows with small norms (less than 1.0) + are always normalized + * if True, we do not increase individual row norms + during normalization - only decrease. However, + we may apply one amplification rount to entire + constraint matrix, i.e. amplify all rows by same + coefficient. As result, we do not overamplify + any single row, but still make sure than entire + problem is well scaled. + * large rows are always normalized + NeedNorms - whether we need row norms or not + +OUTPUT PARAMETERS: + SparseA - replaced by normalized constraints + AL - replaced by normalized lower bounds + AU - replaced by normalized upper bounds + RowNorms - if NeedNorms is true, leading M elements (resized + if length is less than M) are filled by row norms + before normalization was performed. + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void normalizesparselcinplace(sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + double maxnrm2; + + + ae_assert(m==0||((sparsea->matrixtype==1&&sparsea->m==m)&&sparsea->n==n), "ScaleShiftMixedBRLCInplace: non-CRS sparse constraint matrix!", _state); + if( neednorms ) + { + rallocv(m, rownorms, _state); + } + + /* + * First round of normalization - normalize row 2-norms subject to limited amplification status + */ + maxnrm2 = (double)(0); + for(i=0; i<=m-1; i++) + { + vv = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + v = sparsea->vals.ptr.p_double[k]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + if( limitedamplification ) + { + vv = ae_maxreal(vv, 1.0, _state); + } + if( neednorms ) + { + rownorms->ptr.p_double[i] = vv; + } + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*vv; + } + al->ptr.p_double[i] = al->ptr.p_double[i]*vv; + au->ptr.p_double[i] = au->ptr.p_double[i]*vv; + } + } + + /* + * If amplification was limited, perform second round of normalization + */ + if( limitedamplification ) + { + + /* + * Recompute maximum row norm + */ + maxnrm2 = (double)(0); + for(i=0; i<=m-1; i++) + { + vv = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + v = sparsea->vals.ptr.p_double[k]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + } + + /* + * Perform limited amplification, if needed + */ + if( ae_fp_less(maxnrm2,1.0)&&ae_fp_greater(maxnrm2,(double)(0)) ) + { + if( neednorms ) + { + rmulv(m, maxnrm2, rownorms, _state); + } + vv = (double)1/maxnrm2; + for(i=0; i<=m-1; i++) + { + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*vv; + } + al->ptr.p_double[i] = al->ptr.p_double[i]*vv; + au->ptr.p_double[i] = au->ptr.p_double[i]*vv; + } + } + } +} + + +/************************************************************************* +This function normalizes two-sided "lower-bound/upper-bound" constraints +stored in sparse format in such a way that maximum of row L2 norms (right +hand side NOT included) become equal to 1.0. + +Exactly zero rows are handled correctly. + +INPUT PARAMETERS: + SparseA - sparse M*N constraint matrix in CRS format; + ignored if M=0. + M - constraint count, M>=0 + AL - lower bounds for constraints, array[M] + AU - upper bounds for constraints, array[M] + N - number of variables, N>=1. + NeedScales - whether we need rescaling factors or not + +OUTPUT PARAMETERS: + SparseA - replaced by normalized constraints + AL - replaced by normalized lower bounds + AU - replaced by normalized upper bounds + AScales - if NeedScales is true, leading M elements (resized + if length is less than M) are filled by the same + number which was used to scale a matrix. If all + rows are zero, AScales[] is set to 1.0 + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void normalizesparselcinplaceuniform(sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + /* Real */ ae_vector* ascales, + ae_bool needscales, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double v; + double vv; + double maxnrm2; + + + ae_assert(m==0||((sparsea->matrixtype==1&&sparsea->m==m)&&sparsea->n==n), "ScaleShiftMixedBRLCInplace: non-CRS sparse constraint matrix!", _state); + if( needscales ) + { + rallocv(m, ascales, _state); + } + + /* + * Compute maximum row norm + */ + maxnrm2 = (double)(0); + for(i=0; i<=m-1; i++) + { + vv = 0.0; + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + v = sparsea->vals.ptr.p_double[k]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + maxnrm2 = ae_maxreal(maxnrm2, vv, _state); + } + if( ae_fp_eq(maxnrm2,(double)(0)) ) + { + if( needscales ) + { + rsetv(m, 1.0, ascales, _state); + } + return; + } + + /* + * Renormalize + */ + vv = (double)1/maxnrm2; + if( needscales ) + { + rsetv(m, maxnrm2, ascales, _state); + } + for(i=0; i<=m-1; i++) + { + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*vv; + } + al->ptr.p_double[i] = al->ptr.p_double[i]*vv; + au->ptr.p_double[i] = au->ptr.p_double[i]*vv; + } +} + + +/************************************************************************* +This function normalizes dense QP problem in such a way that maximum over +its linear/quadratic coefficients max(max(A),max(B)) becomes equal to 1.0. + +NOTE: completely zero A and B are handled correctly. + +INPUT PARAMETERS: + DenseA - array[NMain,NMain], quadratic term + IsUpper - whether upper or lower triangle is present + NMain - number of nonslack vars, 1<=NMain<=NTotal + DenseB - array[NTotal], linear term + NTotal - total number of variables. + +OUTPUT PARAMETERS: + DenseA - replaced by normalized term + DenseB - replaced by normalized term + +RESULT: + max(max(A),max(B)) is returned + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +double normalizedenseqpinplace(/* Real */ ae_matrix* densea, + ae_bool isupper, + ae_int_t nmain, + /* Real */ ae_vector* denseb, + ae_int_t ntotal, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double mx; + double v; + double result; + + + mx = (double)(0); + for(i=0; i<=nmain-1; i++) + { + if( isupper ) + { + j0 = i; + j1 = nmain-1; + } + else + { + j0 = 0; + j1 = i; + } + for(j=j0; j<=j1; j++) + { + mx = ae_maxreal(mx, ae_fabs(densea->ptr.pp_double[i][j], _state), _state); + } + } + for(i=0; i<=ntotal-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(denseb->ptr.p_double[i], _state), _state); + } + result = mx; + if( ae_fp_eq(mx,(double)(0)) ) + { + return result; + } + v = (double)1/mx; + for(i=0; i<=nmain-1; i++) + { + if( isupper ) + { + j0 = i; + j1 = nmain-1; + } + else + { + j0 = 0; + j1 = i; + } + for(j=j0; j<=j1; j++) + { + densea->ptr.pp_double[i][j] = densea->ptr.pp_double[i][j]*v; + } + } + for(i=0; i<=ntotal-1; i++) + { + denseb->ptr.p_double[i] = denseb->ptr.p_double[i]*v; + } + return result; +} + + +/************************************************************************* +This function normalizes sparse QP problem in such a way that maximum over +its linear/quadratic coefficients max(max(A),max(B)) becomes equal to 1.0. + +NOTE: completely zero A and B are handled correctly. + +INPUT PARAMETERS: + SparseA - Sparse NxN matrix, either upper or lower triangle, + diagonal MUST be present + IsUpper - which triangle is present (other one is ignored) + DenseCorrC - array[CorrRank,N], low rank correction C'*D*C being + added to the quadratic term + DenseCorrD - array[CorrRank], low rank correction, diagonal factors + CorrRank - correction rank, >=0 + DenseB - array[N], linear term + N - number of variables. + +OUTPUT PARAMETERS: + DenseA - replaced by normalized term, array[N,N] + DenseB - replaced by normalized term, array[N] + +RESULT: + max(max(A),max(B)) is returned + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +double normalizesparseqpinplace(sparsematrix* sparsea, + ae_bool isupper, + /* Real */ ae_matrix* densecorrc, + /* Real */ ae_vector* densecorrd, + ae_int_t corrrank, + /* Real */ ae_vector* denseb, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + double mx; + double v; + double result; + + + ae_assert((sparsea->matrixtype==1&&sparsea->m==n)&&sparsea->n==n, "NormalizeSparseQPInplace: SparseA in unexpected format", _state); + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + ae_assert(sparsea->didx.ptr.p_int[i]+1==sparsea->uidx.ptr.p_int[i], "NormalizeSparseQPInplace: critical integrity check failed, sparse diagonal not found", _state); + v = sparsea->vals.ptr.p_double[sparsea->didx.ptr.p_int[i]]; + for(k=0; k<=corrrank-1; k++) + { + v = v+densecorrd->ptr.p_double[k]*ae_sqr(densecorrc->ptr.pp_double[k][i], _state); + } + mx = ae_maxreal(mx, ae_fabs(v, _state), _state); + mx = ae_maxreal(mx, ae_fabs(denseb->ptr.p_double[i], _state), _state); + } + result = mx; + if( ae_fp_eq(mx,(double)(0)) ) + { + return result; + } + v = (double)1/mx; + for(i=0; i<=n-1; i++) + { + k0 = sparsea->ridx.ptr.p_int[i]; + k1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + sparsea->vals.ptr.p_double[k] = sparsea->vals.ptr.p_double[k]*v; + } + denseb->ptr.p_double[i] = denseb->ptr.p_double[i]*v; + } + for(k=0; k<=corrrank-1; k++) + { + rmulr(n, ae_sqrt(v, _state), densecorrc, k, _state); + } + return result; +} + + +/************************************************************************* +This function performs transformation of X from scaled/shifted coordinates +to unscaled/unshifted ones, paying special attention to box constraints: +* points which were exactly at the boundary before scaling will be mapped + to corresponding boundary after scaling +* in any case, unscaled box constraints will be satisfied + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +void unscaleunshiftpointbc(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + /* Real */ const ae_vector* sclsftbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* hasbndl, + /* Boolean */ const ae_vector* hasbndu, + /* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=n-1; i++) + { + if( hasbndl->ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],sclsftbndl->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = rawbndl->ptr.p_double[i]; + continue; + } + if( hasbndu->ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],sclsftbndu->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = rawbndu->ptr.p_double[i]; + continue; + } + x->ptr.p_double[i] = x->ptr.p_double[i]*s->ptr.p_double[i]+xorigin->ptr.p_double[i]; + if( hasbndl->ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],rawbndl->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = rawbndl->ptr.p_double[i]; + } + if( hasbndu->ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],rawbndu->ptr.p_double[i]) ) + { + x->ptr.p_double[i] = rawbndu->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Converts dense/sparse linear and quadratic terms (the latter can be given +by the upper/lower triangle) to the dense lower triangular form. + +INPUT PARAMETERS: + RawC - array[N], linear term + N - variables count + DenseH - if HKind=0: array[NMain,NMain], dense quadratic term + (either upper or lower triangle) + SparseH - if HKind=1: array[NMain,NMain], sparse quadratic term + (either upper or lower triangle) + HKind - 0 or 1, quadratic term format + IsUpper - whether dense/sparse H contains lower or upper + triangle of the quadratic term + H - possibly preallocated matrix + +OUTPUT PARAMETERS: + C - array[N], scaled linear term + H - array[N,N], lower triangle is converted H + + -- ALGLIB -- + Copyright 23.05.2024 by Bochkanov Sergey +*************************************************************************/ +void quadraticlinearconverttodenseltr(/* Real */ const ae_vector* rawc, + ae_int_t n, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ ae_vector* c, + /* Real */ ae_matrix* h, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double v; + + + ae_assert(hkind==0||hkind==1, "QuadraticLinearScaleConvertToDenseLTR: incorrect HKind", _state); + ae_assert(n>=1, "QuadraticLinearScaleConvertToDenseLTR: N<1", _state); + + /* + * Raw linear term + */ + rcopyallocv(n, rawc, c, _state); + + /* + * Quadratic term, without normalization + * + * NOTE: we perform integrity check for inifinities/NANs by + * computing sum of all matrix elements and checking its + * value for being finite. It is a bit faster than checking + * each element individually. + */ + rallocm(n, n, h, _state); + if( hkind==0 ) + { + + /* + * Copy dense quadratic term + */ + if( isupper ) + { + rmatrixtranspose(n, n, denseh, 0, 0, h, 0, 0, _state); + } + else + { + rmatrixcopy(n, n, denseh, 0, 0, h, 0, 0, _state); + } + } + if( hkind==1 ) + { + + /* + * Extract sparse quadratic term + */ + ae_assert(sparseh->matrixtype==1, "QuadraticLinearScaleConvertToDenseLTR: unexpected sparse matrix format", _state); + ae_assert(sparseh->m==n, "QuadraticLinearScaleConvertToDenseLTR: unexpected sparse matrix size", _state); + ae_assert(sparseh->n==n, "QuadraticLinearScaleConvertToDenseLTR: unexpected sparse matrix size", _state); + rsetm(n, n, 0.0, h, _state); + for(i=0; i<=n-1; i++) + { + + /* + * diagonal element + */ + if( sparseh->didx.ptr.p_int[i]!=sparseh->uidx.ptr.p_int[i] ) + { + h->ptr.pp_double[i][i] = sparseh->vals.ptr.p_double[sparseh->didx.ptr.p_int[i]]; + } + + /* + * Off-diagonal elements + */ + if( isupper ) + { + + /* + * superdiagonal elements are moved to the subdiagonal part + */ + j0 = sparseh->uidx.ptr.p_int[i]; + j1 = sparseh->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + h->ptr.pp_double[sparseh->idx.ptr.p_int[j]][i] = sparseh->vals.ptr.p_double[j]; + } + } + else + { + + /* + * subdiagonal elements are moved to the subdiagonal part + */ + j0 = sparseh->ridx.ptr.p_int[i]; + j1 = sparseh->didx.ptr.p_int[i]-1; + for(j=j0; j<=j1; j++) + { + h->ptr.pp_double[i][sparseh->idx.ptr.p_int[j]] = sparseh->vals.ptr.p_double[j]; + } + } + } + } + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+rdotrr(i+1, h, i, h, i, _state); + } + ae_assert(ae_isfinite(v, _state), "QuadraticLinearScaleConvertToDenseLTR: H contains infinite or NaN values!", _state); +} + + +#endif +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine is used to initialize SNNLS solver. + +By default, empty NNLS problem is produced, but we allocated enough space +to store problems with NSMax+NDMax columns and NRMax rows. It is good +place to provide algorithm with initial estimate of the space requirements, +although you may underestimate problem size or even pass zero estimates - +in this case buffer variables will be resized automatically when you set +NNLS problem. + +Previously allocated buffer variables are reused as much as possible. This +function does not clear structure completely, it tries to preserve as much +dynamically allocated memory as possible. + + -- ALGLIB -- + Copyright 10.10.2012 by Bochkanov Sergey +*************************************************************************/ +void snnlsinit(ae_int_t nsmax, + ae_int_t ndmax, + ae_int_t nrmax, + snnlssolver* s, + ae_state *_state) +{ + + + s->ns = 0; + s->nd = 0; + s->nr = 0; + rmatrixsetlengthatleast(&s->densea, nrmax, ndmax, _state); + rmatrixsetlengthatleast(&s->tmpca, nrmax, ndmax, _state); + rvectorsetlengthatleast(&s->b, nrmax, _state); + bvectorsetlengthatleast(&s->nnc, nsmax+ndmax, _state); + s->debugflops = 0.0; + s->debugmaxinnerits = 0; +} + + +/************************************************************************* +This subroutine is used to set NNLS problem: + + ( [ 1 | ] [ ] [ ] )^2 + ( [ 1 | ] [ ] [ ] ) + min ( [ 1 | Ad ] * [ x ] - [ b ] ) s.t. x>=0 + ( [ | ] [ ] [ ] ) + ( [ | ] [ ] [ ] ) + +where: +* identity matrix has NS*NS size (NS<=NR, NS can be zero) +* dense matrix Ad has NR*ND size +* b is NR*1 vector +* x is (NS+ND)*1 vector +* all elements of x are non-negative (this constraint can be removed later + by calling SNNLSDropNNC() function) + +Previously allocated buffer variables are reused as much as possible. +After you set problem, you can solve it with SNNLSSolve(). + +INPUT PARAMETERS: + S - SNNLS solver, must be initialized with SNNLSInit() call + A - array[NR,ND], dense part of the system + B - array[NR], right part + NS - size of the sparse part of the system, 0<=NS<=NR + ND - size of the dense part of the system, ND>=0 + NR - rows count, NR>0 + +NOTE: + 1. You can have NS+ND=0, solver will correctly accept such combination + and return empty array as problem solution. + + -- ALGLIB -- + Copyright 10.10.2012 by Bochkanov Sergey +*************************************************************************/ +void snnlssetproblem(snnlssolver* s, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* b, + ae_int_t ns, + ae_int_t nd, + ae_int_t nr, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nd>=0, "SNNLSSetProblem: ND<0", _state); + ae_assert(ns>=0, "SNNLSSetProblem: NS<0", _state); + ae_assert(nr>0, "SNNLSSetProblem: NR<=0", _state); + ae_assert(ns<=nr, "SNNLSSetProblem: NS>NR", _state); + ae_assert(a->rows>=nr||nd==0, "SNNLSSetProblem: rows(A)cols>=nd, "SNNLSSetProblem: cols(A)cnt>=nr, "SNNLSSetProblem: length(B)ns = ns; + s->nd = nd; + s->nr = nr; + if( nd>0 ) + { + rmatrixsetlengthatleast(&s->densea, nr, nd, _state); + for(i=0; i<=nr-1; i++) + { + ae_v_move(&s->densea.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,nd-1)); + } + } + rvectorsetlengthatleast(&s->b, nr, _state); + ae_v_move(&s->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nr-1)); + bvectorsetlengthatleast(&s->nnc, ns+nd, _state); + for(i=0; i<=ns+nd-1; i++) + { + s->nnc.ptr.p_bool[i] = ae_true; + } +} + + +/************************************************************************* +This subroutine drops non-negativity constraint from the problem set by +SNNLSSetProblem() call. This function must be called AFTER problem is set, +because each SetProblem() call resets constraints to their default state +(all constraints are present). + +INPUT PARAMETERS: + S - SNNLS solver, must be initialized with SNNLSInit() call, + problem must be set with SNNLSSetProblem() call. + Idx - constraint index, 0<=IDX=0, "SNNLSDropNNC: Idx<0", _state); + ae_assert(idxns+s->nd, "SNNLSDropNNC: Idx>=NS+ND", _state); + s->nnc.ptr.p_bool[idx] = ae_false; +} + + +/************************************************************************* +This subroutine is used to solve NNLS problem. + +INPUT PARAMETERS: + S - SNNLS solver, must be initialized with SNNLSInit() call and + problem must be set up with SNNLSSetProblem() call. + X - possibly preallocated buffer, automatically resized if needed + +OUTPUT PARAMETERS: + X - array[NS+ND], solution + +NOTE: + 1. You can have NS+ND=0, solver will correctly accept such combination + and return empty array as problem solution. + + 2. Internal field S.DebugFLOPS contains rough estimate of FLOPs used + to solve problem. It can be used for debugging purposes. This field + is real-valued. + + -- ALGLIB -- + Copyright 10.10.2012 by Bochkanov Sergey +*************************************************************************/ +void snnlssolve(snnlssolver* s, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ns; + ae_int_t nd; + ae_int_t nr; + ae_bool wasactivation; + double lambdav; + double v0; + double v1; + double v; + ae_int_t outerits; + ae_int_t innerits; + ae_int_t maxouterits; + double xtol; + double kicklength; + ae_bool kickneeded; + double f0; + double f1; + double dnrm; + ae_int_t actidx; + double stp; + double stpmax; + + + + /* + * Prepare + */ + ns = s->ns; + nd = s->nd; + nr = s->nr; + s->debugflops = 0.0; + + /* + * Handle special cases: + * * NS+ND=0 + * * ND=0 + */ + if( ns+nd==0 ) + { + return; + } + if( nd==0 ) + { + rvectorsetlengthatleast(x, ns, _state); + for(i=0; i<=ns-1; i++) + { + x->ptr.p_double[i] = s->b.ptr.p_double[i]; + if( s->nnc.ptr.p_bool[i] ) + { + x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], 0.0, _state); + } + } + return; + } + + /* + * Main cycle of BLEIC-SNNLS algorithm. + * Below we assume that ND>0. + */ + rvectorsetlengthatleast(x, ns+nd, _state); + rvectorsetlengthatleast(&s->xn, ns+nd, _state); + rvectorsetlengthatleast(&s->xp, ns+nd, _state); + rvectorsetlengthatleast(&s->g, ns+nd, _state); + rvectorsetlengthatleast(&s->d, ns+nd, _state); + rvectorsetlengthatleast(&s->r, nr, _state); + rvectorsetlengthatleast(&s->diagaa, nd, _state); + rvectorsetlengthatleast(&s->regdiag, ns+nd, _state); + rvectorsetlengthatleast(&s->dx, ns+nd, _state); + for(i=0; i<=ns+nd-1; i++) + { + x->ptr.p_double[i] = 0.0; + s->regdiag.ptr.p_double[i] = 1.0; + } + lambdav = 1.0E6*ae_machineepsilon; + maxouterits = 10; + outerits = 0; + innerits = 0; + xtol = 1.0E3*ae_machineepsilon; + kicklength = ae_sqrt(ae_minrealnumber, _state); + for(;;) + { + + /* + * Initial check for correctness of X + */ + for(i=0; i<=ns+nd-1; i++) + { + ae_assert(!s->nnc.ptr.p_bool[i]||ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)), "SNNLS: integrity check failed", _state); + } + + /* + * Calculate gradient G and constrained descent direction D + */ + snnls_funcgradu(s, x, &s->r, &s->g, &f0, _state); + for(i=0; i<=ns+nd-1; i++) + { + if( (s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],(double)(0)))&&ae_fp_greater(s->g.ptr.p_double[i],(double)(0)) ) + { + s->d.ptr.p_double[i] = 0.0; + } + else + { + s->d.ptr.p_double[i] = -s->g.ptr.p_double[i]; + } + } + + /* + * Decide whether we need "kick" stage: special stage + * that moves us away from boundary constraints which are + * not strictly active (i.e. such constraints that x[i]=0.0 and d[i]>0). + * + * If we need kick stage, we make a kick - and restart iteration. + * If not, after this block we can rely on the fact that + * for all x[i]=0.0 we have d[i]=0.0 + * + * NOTE: we do not increase outer iterations counter here + */ + kickneeded = ae_false; + for(i=0; i<=ns+nd-1; i++) + { + if( (s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0))&&ae_fp_greater(s->d.ptr.p_double[i],0.0) ) + { + kickneeded = ae_true; + } + } + if( kickneeded ) + { + + /* + * Perform kick. + * Restart. + * Do not increase iterations counter. + */ + for(i=0; i<=ns+nd-1; i++) + { + if( ae_fp_eq(x->ptr.p_double[i],0.0)&&ae_fp_greater(s->d.ptr.p_double[i],0.0) ) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+kicklength; + } + } + continue; + } + + /* + * Newton phase + * Reduce problem to constrained triangular form and perform Newton + * steps with quick activation of constrants (triangular form is + * updated in order to handle changed constraints). + */ + for(i=0; i<=ns+nd-1; i++) + { + s->xp.ptr.p_double[i] = x->ptr.p_double[i]; + } + snnls_trdprepare(s, x, &s->regdiag, lambdav, &s->trdd, &s->trda, &s->tmp0, &s->tmp1, &s->tmp2, &s->tmplq, _state); + for(;;) + { + + /* + * Skip if debug limit on inner iterations count is turned on. + */ + if( s->debugmaxinnerits>0&&innerits>=s->debugmaxinnerits ) + { + break; + } + + /* + * Prepare step vector. + */ + snnls_funcgradu(s, x, &s->r, &s->g, &f0, _state); + for(i=0; i<=ns+nd-1; i++) + { + s->d.ptr.p_double[i] = -s->g.ptr.p_double[i]; + if( s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0) ) + { + s->d.ptr.p_double[i] = 0.0; + } + } + snnls_trdsolve(&s->trdd, &s->trda, ns, nd, &s->d, _state); + + /* + * Perform unconstrained trial step and compare function values. + */ + for(i=0; i<=ns+nd-1; i++) + { + s->xn.ptr.p_double[i] = x->ptr.p_double[i]+s->d.ptr.p_double[i]; + } + snnls_func(s, &s->xn, &f1, _state); + if( ae_fp_greater_eq(f1,f0) ) + { + break; + } + + /* + * Calculate length of D, maximum step and component which is + * activated by this step. Break if D is exactly zero. + */ + dnrm = 0.0; + for(i=0; i<=ns+nd-1; i++) + { + dnrm = dnrm+ae_sqr(s->d.ptr.p_double[i], _state); + } + dnrm = ae_sqrt(dnrm, _state); + actidx = -1; + stpmax = 1.0E50; + for(i=0; i<=ns+nd-1; i++) + { + if( s->nnc.ptr.p_bool[i]&&ae_fp_less(s->d.ptr.p_double[i],0.0) ) + { + v = stpmax; + stpmax = safeminposrv(x->ptr.p_double[i], -s->d.ptr.p_double[i], stpmax, _state); + if( ae_fp_less(stpmax,v) ) + { + actidx = i; + } + } + } + if( ae_fp_eq(dnrm,0.0) ) + { + break; + } + + /* + * Perform constrained step and update X + * and triangular model. + */ + stp = ae_minreal(1.0, stpmax, _state); + for(i=0; i<=ns+nd-1; i++) + { + v = x->ptr.p_double[i]+stp*s->d.ptr.p_double[i]; + if( s->nnc.ptr.p_bool[i] ) + { + v = ae_maxreal(v, 0.0, _state); + } + s->xn.ptr.p_double[i] = v; + } + if( ae_fp_eq(stp,stpmax)&&actidx>=0 ) + { + s->xn.ptr.p_double[actidx] = 0.0; + } + wasactivation = ae_false; + for(i=0; i<=ns+nd-1; i++) + { + if( ae_fp_eq(s->xn.ptr.p_double[i],0.0)&&ae_fp_neq(x->ptr.p_double[i],0.0) ) + { + wasactivation = ae_true; + snnls_trdfixvariable(&s->trdd, &s->trda, ns, nd, i, &s->tmpcholesky, _state); + } + } + for(i=0; i<=ns+nd-1; i++) + { + x->ptr.p_double[i] = s->xn.ptr.p_double[i]; + } + + /* + * Increment iterations counter. + * Terminate if no constraint was activated. + */ + inc(&innerits, _state); + if( !wasactivation ) + { + break; + } + } + + /* + * Update outer iterations counter. + * + * Break if necessary: + * * maximum number of outer iterations performed + * * relative change in X is small enough + */ + inc(&outerits, _state); + if( outerits>=maxouterits ) + { + break; + } + v = (double)(0); + for(i=0; i<=ns+nd-1; i++) + { + v0 = ae_fabs(s->xp.ptr.p_double[i], _state); + v1 = ae_fabs(x->ptr.p_double[i], _state); + if( ae_fp_neq(v0,(double)(0))||ae_fp_neq(v1,(double)(0)) ) + { + v = ae_maxreal(v, ae_fabs(x->ptr.p_double[i]-s->xp.ptr.p_double[i], _state)/ae_maxreal(v0, v1, _state), _state); + } + } + if( ae_fp_less_eq(v,xtol) ) + { + break; + } + } +} + + +/************************************************************************* +This function calculates: +* residual vector R = A*x-b +* unconstrained gradient vector G +* function value F = 0.5*|R|^2 + +R and G must have at least N elements. + + -- ALGLIB -- + Copyright 15.07.2015 by Bochkanov Sergey +*************************************************************************/ +static void snnls_funcgradu(const snnlssolver* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* r, + /* Real */ ae_vector* g, + double* f, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nr; + ae_int_t nd; + ae_int_t ns; + double v; + + *f = 0.0; + + nr = s->nr; + nd = s->nd; + ns = s->ns; + *f = 0.0; + for(i=0; i<=nr-1; i++) + { + v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); + if( iptr.p_double[i]; + } + v = v-s->b.ptr.p_double[i]; + r->ptr.p_double[i] = v; + *f = *f+0.5*v*v; + } + for(i=0; i<=ns-1; i++) + { + g->ptr.p_double[i] = r->ptr.p_double[i]; + } + for(i=ns; i<=ns+nd-1; i++) + { + g->ptr.p_double[i] = 0.0; + } + for(i=0; i<=nr-1; i++) + { + v = r->ptr.p_double[i]; + ae_v_addd(&g->ptr.p_double[ns], 1, &s->densea.ptr.pp_double[i][0], 1, ae_v_len(ns,ns+nd-1), v); + } +} + + +/************************************************************************* +This function calculates function value F = 0.5*|R|^2 at X. + + -- ALGLIB -- + Copyright 15.07.2015 by Bochkanov Sergey +*************************************************************************/ +static void snnls_func(const snnlssolver* s, + /* Real */ const ae_vector* x, + double* f, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nr; + ae_int_t nd; + ae_int_t ns; + double v; + + *f = 0.0; + + nr = s->nr; + nd = s->nd; + ns = s->ns; + *f = 0.0; + for(i=0; i<=nr-1; i++) + { + v = ae_v_dotproduct(&s->densea.ptr.pp_double[i][0], 1, &x->ptr.p_double[ns], 1, ae_v_len(0,nd-1)); + if( iptr.p_double[i]; + } + v = v-s->b.ptr.p_double[i]; + *f = *f+0.5*v*v; + } +} + + +static void snnls_trdprepare(snnlssolver* s, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* diag, + double lambdav, + /* Real */ ae_vector* trdd, + /* Real */ ae_matrix* trda, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + /* Real */ ae_vector* tmp2, + /* Real */ ae_matrix* tmplq, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ns; + ae_int_t nd; + ae_int_t nr; + double v; + double cs; + double sn; + double r; + + + + /* + * Prepare + */ + ns = s->ns; + nd = s->nd; + nr = s->nr; + + /* + * Triangular reduction + */ + rvectorsetlengthatleast(trdd, ns, _state); + rmatrixsetlengthatleast(trda, ns+nd, nd, _state); + rmatrixsetlengthatleast(tmplq, nd, nr+nd, _state); + for(i=0; i<=ns-1; i++) + { + + /* + * Apply rotation to I-th row and corresponding row of + * regularizer. Here V is diagonal element of I-th row, + * which is set to 1.0 or 0.0 depending on variable + * status (constrained or not). + */ + v = 1.0; + if( s->nnc.ptr.p_bool[i]&&ae_fp_eq(x->ptr.p_double[i],0.0) ) + { + v = 0.0; + } + generaterotation(v, lambdav, &cs, &sn, &r, _state); + trdd->ptr.p_double[i] = cs*v+sn*lambdav; + for(j=0; j<=nd-1; j++) + { + v = s->densea.ptr.pp_double[i][j]; + trda->ptr.pp_double[i][j] = cs*v; + tmplq->ptr.pp_double[j][i] = -sn*v; + } + } + for(j=0; j<=nd-1; j++) + { + for(i=ns; i<=nr-1; i++) + { + tmplq->ptr.pp_double[j][i] = s->densea.ptr.pp_double[i][j]; + } + } + for(j=0; j<=nd-1; j++) + { + if( s->nnc.ptr.p_bool[ns+j]&&ae_fp_eq(x->ptr.p_double[ns+j],0.0) ) + { + + /* + * Variable is constrained, entire row is set to zero. + */ + for(i=0; i<=nr-1; i++) + { + tmplq->ptr.pp_double[j][i] = 0.0; + } + for(i=0; i<=ns-1; i++) + { + trda->ptr.pp_double[i][j] = 0.0; + } + } + } + for(i=0; i<=nd-1; i++) + { + for(j=0; j<=nd-1; j++) + { + tmplq->ptr.pp_double[j][nr+i] = 0.0; + } + tmplq->ptr.pp_double[i][nr+i] = lambdav*diag->ptr.p_double[i]; + } + rvectorsetlengthatleast(tmp0, nr+nd+1, _state); + rvectorsetlengthatleast(tmp1, nr+nd+1, _state); + rvectorsetlengthatleast(tmp2, nr+nd+1, _state); + rmatrixlqbasecase(tmplq, nd, nr+nd, tmp0, tmp1, tmp2, _state); + for(i=0; i<=nd-1; i++) + { + if( ae_fp_less(tmplq->ptr.pp_double[i][i],0.0) ) + { + for(j=i; j<=nd-1; j++) + { + tmplq->ptr.pp_double[j][i] = -tmplq->ptr.pp_double[j][i]; + } + } + } + for(i=0; i<=nd-1; i++) + { + for(j=0; j<=i; j++) + { + trda->ptr.pp_double[ns+j][i] = tmplq->ptr.pp_double[i][j]; + } + } +} + + +static void snnls_trdsolve(/* Real */ const ae_vector* trdd, + /* Real */ const ae_matrix* trda, + ae_int_t ns, + ae_int_t nd, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * Solve U'*y=d first. + * + * This section includes two parts: + * * solve diagonal part of U' + * * solve dense part of U' + */ + for(i=0; i<=ns-1; i++) + { + d->ptr.p_double[i] = d->ptr.p_double[i]/trdd->ptr.p_double[i]; + v = d->ptr.p_double[i]; + for(j=0; j<=nd-1; j++) + { + d->ptr.p_double[ns+j] = d->ptr.p_double[ns+j]-v*trda->ptr.pp_double[i][j]; + } + } + for(i=0; i<=nd-1; i++) + { + d->ptr.p_double[ns+i] = d->ptr.p_double[ns+i]/trda->ptr.pp_double[ns+i][i]; + v = d->ptr.p_double[ns+i]; + for(j=i+1; j<=nd-1; j++) + { + d->ptr.p_double[ns+j] = d->ptr.p_double[ns+j]-v*trda->ptr.pp_double[ns+i][j]; + } + } + + /* + * Solve U*x=y then. + * + * This section includes two parts: + * * solve trailing triangular part of U + * * solve combination of diagonal and dense parts of U + */ + for(i=nd-1; i>=0; i--) + { + v = 0.0; + for(j=i+1; j<=nd-1; j++) + { + v = v+trda->ptr.pp_double[ns+i][j]*d->ptr.p_double[ns+j]; + } + d->ptr.p_double[ns+i] = (d->ptr.p_double[ns+i]-v)/trda->ptr.pp_double[ns+i][i]; + } + for(i=ns-1; i>=0; i--) + { + v = 0.0; + for(j=0; j<=nd-1; j++) + { + v = v+trda->ptr.pp_double[i][j]*d->ptr.p_double[ns+j]; + } + d->ptr.p_double[i] = (d->ptr.p_double[i]-v)/trdd->ptr.p_double[i]; + } +} + + +static void snnls_trdfixvariable(/* Real */ ae_vector* trdd, + /* Real */ ae_matrix* trda, + ae_int_t ns, + ae_int_t nd, + ae_int_t idx, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double cs; + double sn; + double r; + double v; + double vv; + + + ae_assert(ns>=0, "TRDFixVariable: integrity error", _state); + ae_assert(nd>=0, "TRDFixVariable: integrity error", _state); + ae_assert(ns+nd>0, "TRDFixVariable: integrity error", _state); + ae_assert(idx>=0, "TRDFixVariable: integrity error", _state); + ae_assert(idxptr.p_double[idx] = 1.0; + return; + } + for(j=0; j<=nd-1; j++) + { + + /* + * Apply first rotation + */ + tmp->ptr.p_double[j] = trda->ptr.pp_double[idx][j]; + trda->ptr.pp_double[idx][j] = 0.0; + } + trdd->ptr.p_double[idx] = 1.0; + for(i=0; i<=nd-1; i++) + { + if( ae_fp_neq(tmp->ptr.p_double[i],(double)(0)) ) + { + + /* + * Apply subsequent rotations with bottom triangular part of A + */ + generaterotation(trda->ptr.pp_double[ns+i][i], tmp->ptr.p_double[i], &cs, &sn, &r, _state); + for(j=i; j<=nd-1; j++) + { + v = trda->ptr.pp_double[ns+i][j]; + vv = tmp->ptr.p_double[j]; + trda->ptr.pp_double[ns+i][j] = v*cs+vv*sn; + tmp->ptr.p_double[j] = vv*cs-v*sn; + } + } + } + } + else + { + + /* + * We fix variable in the dense part of the model. It means + * that prior to fixing we have: + * + * ( | ) + * ( D | ) + * ( | ) + * (-----| A ) + * ( |0 ) + * ( |00 ) + * ( |000 ) + * ( |0000 ) + * ( |00000) + * + * then we replace idx-th column by zeros: + * + * ( | 0 ) + * ( D | 0 ) + * ( | 0 ) + * (-----|A 0 A) + * ( | 0 ) + * ( | 0 ) + * ( | 0 ) + * + * and append row with unit element to bottom, in order to + * regularize problem + * + * ( | 0 ) + * ( D | 0 ) + * ( | 0 ) + * (-----|A 0 A) + * ( | 0 ) + * ( | 0 ) + * ( | 0 ) + * (00000|00100) <- appended + * + * and then we nullify this row by applying rotations: + * + * (D 0 | ) + * ( 0 | ) + * ( 0 D| ) + * (-----| A ) + * ( | ) + * ( | ) <- first rotation is applied here + * ( | ) <- subsequent rotations are applied to rows below + * ( 0 | 0 ) <- as result, row becomes zero + * + * and triangular structure is preserved. + */ + k = idx-ns; + for(i=0; i<=ns+nd-1; i++) + { + trda->ptr.pp_double[i][k] = 0.0; + } + for(j=k+1; j<=nd-1; j++) + { + + /* + * Apply first rotation + */ + tmp->ptr.p_double[j] = trda->ptr.pp_double[idx][j]; + trda->ptr.pp_double[idx][j] = 0.0; + } + trda->ptr.pp_double[idx][k] = 1.0; + for(i=k+1; i<=nd-1; i++) + { + if( ae_fp_neq(tmp->ptr.p_double[i],(double)(0)) ) + { + + /* + * Apply subsequent rotations with bottom triangular part of A + */ + generaterotation(trda->ptr.pp_double[ns+i][i], tmp->ptr.p_double[i], &cs, &sn, &r, _state); + for(j=i; j<=nd-1; j++) + { + v = trda->ptr.pp_double[ns+i][j]; + vv = tmp->ptr.p_double[j]; + trda->ptr.pp_double[ns+i][j] = v*cs+vv*sn; + tmp->ptr.p_double[j] = vv*cs-v*sn; + } + } + } + } +} + + +void _snnlssolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + snnlssolver *p = (snnlssolver*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nnc, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpca, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmplq, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->trda, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->trdd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->crb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagaa, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cborg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcholesky, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->regdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdtmprowmap, 0, DT_INT, _state, make_automatic); +} + + +void _snnlssolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + snnlssolver *dst = (snnlssolver*)_dst; + const snnlssolver *src = (const snnlssolver*)_src; + dst->ns = src->ns; + dst->nd = src->nd; + dst->nr = src->nr; + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->nnc, &src->nnc, _state, make_automatic); + dst->debugflops = src->debugflops; + dst->debugmaxinnerits = src->debugmaxinnerits; + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpca, &src->tmpca, _state, make_automatic); + ae_matrix_init_copy(&dst->tmplq, &src->tmplq, _state, make_automatic); + ae_matrix_init_copy(&dst->trda, &src->trda, _state, make_automatic); + ae_vector_init_copy(&dst->trdd, &src->trdd, _state, make_automatic); + ae_vector_init_copy(&dst->crb, &src->crb, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->dx, &src->dx, _state, make_automatic); + ae_vector_init_copy(&dst->diagaa, &src->diagaa, _state, make_automatic); + ae_vector_init_copy(&dst->cb, &src->cb, _state, make_automatic); + ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->cborg, &src->cborg, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcholesky, &src->tmpcholesky, _state, make_automatic); + ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->regdiag, &src->regdiag, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->rdtmprowmap, &src->rdtmprowmap, _state, make_automatic); +} + + +void _snnlssolver_clear(void* _p) +{ + snnlssolver *p = (snnlssolver*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->densea); + ae_vector_clear(&p->b); + ae_vector_clear(&p->nnc); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->xp); + ae_matrix_clear(&p->tmpca); + ae_matrix_clear(&p->tmplq); + ae_matrix_clear(&p->trda); + ae_vector_clear(&p->trdd); + ae_vector_clear(&p->crb); + ae_vector_clear(&p->g); + ae_vector_clear(&p->d); + ae_vector_clear(&p->dx); + ae_vector_clear(&p->diagaa); + ae_vector_clear(&p->cb); + ae_vector_clear(&p->cx); + ae_vector_clear(&p->cborg); + ae_vector_clear(&p->tmpcholesky); + ae_vector_clear(&p->r); + ae_vector_clear(&p->regdiag); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->rdtmprowmap); +} + + +void _snnlssolver_destroy(void* _p) +{ + snnlssolver *p = (snnlssolver*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->densea); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->nnc); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->xp); + ae_matrix_destroy(&p->tmpca); + ae_matrix_destroy(&p->tmplq); + ae_matrix_destroy(&p->trda); + ae_vector_destroy(&p->trdd); + ae_vector_destroy(&p->crb); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->dx); + ae_vector_destroy(&p->diagaa); + ae_vector_destroy(&p->cb); + ae_vector_destroy(&p->cx); + ae_vector_destroy(&p->cborg); + ae_vector_destroy(&p->tmpcholesky); + ae_vector_destroy(&p->r); + ae_vector_destroy(&p->regdiag); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->rdtmprowmap); +} + + +#endif +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This subroutine is used to initialize active set. By default, empty +N-variable model with no constraints is generated. Previously allocated +buffer variables are reused as much as possible. + +Two use cases for this object are described below. + +CASE 1 - STEEPEST DESCENT: + + SASInit() + repeat: + SASReactivateConstraints() + SASDescentDirection() + SASExploreDirection() + SASMoveTo() + until convergence + +CASE 1 - PRECONDITIONED STEEPEST DESCENT: + + SASInit() + repeat: + SASReactivateConstraintsPrec() + SASDescentDirectionPrec() + SASExploreDirection() + SASMoveTo() + until convergence + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasinit(ae_int_t n, sactiveset* s, ae_state *_state) +{ + ae_int_t i; + + + s->n = n; + s->algostate = 0; + + /* + * Constraints + */ + s->constraintschanged = ae_true; + s->nec = 0; + s->nic = 0; + rvectorsetlengthatleast(&s->bndl, n, _state); + bvectorsetlengthatleast(&s->hasbndl, n, _state); + rvectorsetlengthatleast(&s->bndu, n, _state); + bvectorsetlengthatleast(&s->hasbndu, n, _state); + for(i=0; i<=n-1; i++) + { + s->bndl.ptr.p_double[i] = _state->v_neginf; + s->bndu.ptr.p_double[i] = _state->v_posinf; + s->hasbndl.ptr.p_bool[i] = ae_false; + s->hasbndu.ptr.p_bool[i] = ae_false; + } + + /* + * current point, scale + */ + s->hasxc = ae_false; + rvectorsetlengthatleast(&s->xc, n, _state); + rvectorsetlengthatleast(&s->s, n, _state); + rvectorsetlengthatleast(&s->h, n, _state); + for(i=0; i<=n-1; i++) + { + s->xc.ptr.p_double[i] = 0.0; + s->s.ptr.p_double[i] = 1.0; + s->h.ptr.p_double[i] = 1.0; + } + + /* + * Other + */ + rvectorsetlengthatleast(&s->unitdiagonal, n, _state); + for(i=0; i<=n-1; i++) + { + s->unitdiagonal.ptr.p_double[i] = 1.0; + } +} + + +/************************************************************************* +This function sets scaling coefficients for SAS object. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +During orthogonalization phase, scale is used to calculate drop tolerances +(whether vector is significantly non-zero or not). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sassetscale(sactiveset* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->algostate==0, "SASSetScale: you may change scale only in modification mode", _state); + ae_assert(s->cnt>=state->n, "SASSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "SASSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "SASSetScale: S contains zero elements", _state); + } + for(i=0; i<=state->n-1; i++) + { + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sassetprecdiag(sactiveset* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->algostate==0, "SASSetPrecDiag: you may change preconditioner only in modification mode", _state); + ae_assert(d->cnt>=state->n, "SASSetPrecDiag: D is too short", _state); + for(i=0; i<=state->n-1; i++) + { + ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "SASSetPrecDiag: D contains infinite or NAN elements", _state); + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "SASSetPrecDiag: D contains non-positive elements", _state); + } + for(i=0; i<=state->n-1; i++) + { + state->h.ptr.p_double[i] = d->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets/changes boundary constraints. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sassetbc(sactiveset* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + ae_assert(state->algostate==0, "SASSetBC: you may change constraints only in modification mode", _state); + n = state->n; + ae_assert(bndl->cnt>=n, "SASSetBC: Length(BndL)cnt>=n, "SASSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "SASSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } + state->constraintschanged = ae_true; +} + + +/************************************************************************* +This function sets linear constraints for SAS object. + +Linear constraints are inactive by default (after initial creation). + +INPUT PARAMETERS: + State - SAS structure + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0 + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void sassetlc(sactiveset* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + ae_assert(state->algostate==0, "SASSetLC: you may change constraints only in modification mode", _state); + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(k>=0, "SASSetLC: K<0", _state); + ae_assert(c->cols>=n+1||k==0, "SASSetLC: Cols(C)rows>=k, "SASSetLC: Rows(C)cnt>=k, "SASSetLC: Length(CT)nec = 0; + state->nic = 0; + state->constraintschanged = ae_true; + return; + } + + /* + * Equality constraints are stored first, in the upper + * NEC rows of State.CLEIC matrix. Inequality constraints + * are stored in the next NIC rows. + * + * NOTE: we convert inequality constraints to the form + * A*x<=b before copying them. + */ + rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); + state->nec = 0; + state->nic = 0; + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]==0 ) + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + state->nec = state->nec+1; + } + } + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]!=0 ) + { + if( ct->ptr.p_int[i]>0 ) + { + ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + else + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + state->nic = state->nic+1; + } + } + + /* + * Mark state as changed + */ + state->constraintschanged = ae_true; +} + + +/************************************************************************* +Another variation of SASSetLC(), which accepts linear constraints using +another representation. + +Linear constraints are inactive by default (after initial creation). + +INPUT PARAMETERS: + State - SAS structure + CLEIC - linear constraints, array[NEC+NIC,N+1]. + Each row of C represents one constraint: + * first N elements correspond to coefficients, + * last element corresponds to the right part. + First NEC rows store equality constraints, next NIC - are + inequality ones. + All elements of C (including right part) must be finite. + NEC - number of equality constraints, NEC>=0 + NIC - number of inequality constraints, NIC>=0 + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void sassetlcx(sactiveset* state, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + + + ae_assert(state->algostate==0, "SASSetLCX: you may change constraints only in modification mode", _state); + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(nec>=0, "SASSetLCX: NEC<0", _state); + ae_assert(nic>=0, "SASSetLCX: NIC<0", _state); + ae_assert(cleic->cols>=n+1||nec+nic==0, "SASSetLCX: Cols(CLEIC)rows>=nec+nic, "SASSetLCX: Rows(CLEIC)cleic, nec+nic, n+1, _state); + state->nec = nec; + state->nic = nic; + for(i=0; i<=nec+nic-1; i++) + { + for(j=0; j<=n; j++) + { + state->cleic.ptr.pp_double[i][j] = cleic->ptr.pp_double[i][j]; + } + } + + /* + * Mark state as changed + */ + state->constraintschanged = ae_true; +} + + +/************************************************************************* +This subroutine turns on optimization mode: +1. feasibility in X is enforced (in case X=S.XC and constraints have not + changed, algorithm just uses X without any modifications at all) +2. constraints are marked as "candidate" or "inactive" + +INPUT PARAMETERS: + S - active set object + X - initial point (candidate), array[N]. It is expected that X + contains only finite values (we do not check it). + +OUTPUT PARAMETERS: + S - state is changed + X - initial point can be changed to enforce feasibility + +RESULT: + True in case feasible point was found (mode was changed to "optimization") + False in case no feasible point was found (mode was not changed) + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +ae_bool sasstartoptimization(sactiveset* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + ae_int_t j; + double v; + double v0; + double v1; + double vv; + double vc; + double vx; + ae_bool result; + + + ae_assert(state->algostate==0, "SASStartOptimization: already in optimization mode", _state); + result = ae_false; + n = state->n; + nec = state->nec; + nic = state->nic; + + /* + * Enforce feasibility and calculate set of "candidate"/"active" constraints. + * Always active equality constraints are marked as "active", all other constraints + * are marked as "candidate". + */ + ivectorsetlengthatleast(&state->cstatus, n+nec+nic, _state); + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + return result; + } + } + } + ae_v_move(&state->xc.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( state->nec+state->nic>0 ) + { + + /* + * General linear constraints are present. + * Try to use fast code for feasible initial point with modest + * memory requirements. + */ + rvectorsetlengthatleast(&state->tmp0, n, _state); + state->feasinitpt = ae_true; + for(i=0; i<=n-1; i++) + { + state->tmp0.ptr.p_double[i] = x->ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = -1; + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->tmp0.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->tmp0.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 0; + state->tmp0.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->tmp0.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 0; + state->tmp0.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + for(i=0; i<=state->nec+state->nic-1; i++) + { + v = -state->cleic.ptr.pp_double[i][n]; + v0 = (double)(0); + v1 = (double)(0); + for(j=0; j<=n-1; j++) + { + vx = state->tmp0.ptr.p_double[j]/state->s.ptr.p_double[j]; + vc = state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; + v = v+vx*vc; + v0 = v0+ae_sqr(vx, _state); + v1 = v1+ae_sqr(vc, _state); + } + vv = ae_sqrt(v0, _state)*ae_sqrt(v1, _state)*(double)1000*ae_machineepsilon; + if( inec ) + { + state->cstatus.ptr.p_int[n+i] = 1; + state->feasinitpt = state->feasinitpt&&ae_fp_less(ae_fabs(v, _state),vv); + } + else + { + state->feasinitpt = state->feasinitpt&&ae_fp_less(v,vv); + if( ae_fp_less(v,-vv) ) + { + state->cstatus.ptr.p_int[n+i] = -1; + } + else + { + state->cstatus.ptr.p_int[n+i] = 0; + } + } + } + if( state->feasinitpt ) + { + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1)); + } + + /* + * Fast code failed? Use general code with ~(N+NIC)^2 memory requirements + */ + if( !state->feasinitpt ) + { + rvectorsetlengthatleast(&state->tmp0, n, _state); + rvectorsetlengthatleast(&state->tmpfeas, n+state->nic, _state); + rmatrixsetlengthatleast(&state->tmpm0, state->nec+state->nic, n+state->nic+1, _state); + for(i=0; i<=state->nec+state->nic-1; i++) + { + ae_v_move(&state->tmpm0.ptr.pp_double[i][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + for(j=n; j<=n+state->nic-1; j++) + { + state->tmpm0.ptr.pp_double[i][j] = (double)(0); + } + if( i>=state->nec ) + { + state->tmpm0.ptr.pp_double[i][n+i-state->nec] = 1.0; + } + state->tmpm0.ptr.pp_double[i][n+state->nic] = state->cleic.ptr.pp_double[i][n]; + } + ae_v_move(&state->tmpfeas.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=state->nic-1; i++) + { + v = ae_v_dotproduct(&state->cleic.ptr.pp_double[i+state->nec][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->tmpfeas.ptr.p_double[i+n] = ae_maxreal(state->cleic.ptr.pp_double[i+state->nec][n]-v, 0.0, _state); + } + if( !findfeasiblepoint(&state->tmpfeas, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, state->nic, &state->tmpm0, state->nec+state->nic, 1.0E-6, &i, &j, _state) ) + { + return result; + } + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->tmpfeas.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))||(state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i])) ) + { + state->cstatus.ptr.p_int[i] = 0; + continue; + } + state->cstatus.ptr.p_int[i] = -1; + } + for(i=0; i<=state->nec-1; i++) + { + state->cstatus.ptr.p_int[n+i] = 1; + } + for(i=0; i<=state->nic-1; i++) + { + if( ae_fp_eq(state->tmpfeas.ptr.p_double[n+i],(double)(0)) ) + { + state->cstatus.ptr.p_int[n+state->nec+i] = 0; + } + else + { + state->cstatus.ptr.p_int[n+state->nec+i] = -1; + } + } + } + } + else + { + + /* + * Only box constraints are present, quick code can be used + */ + for(i=0; i<=n-1; i++) + { + state->cstatus.ptr.p_int[i] = -1; + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 1; + state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + continue; + } + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = 0; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = 0; + continue; + } + } + state->feasinitpt = ae_true; + } + + /* + * Change state, allocate temporaries + */ + result = ae_true; + state->algostate = 1; + state->basisisready = ae_false; + state->hasxc = ae_true; + return result; +} + + +/************************************************************************* +This function explores search direction and calculates bound for step as +well as information for activation of constraints. + +INPUT PARAMETERS: + State - SAS structure which stores current point and all other + active set related information + D - descent direction to explore + +OUTPUT PARAMETERS: + StpMax - upper limit on step length imposed by yet inactive + constraints. Can be zero in case some constraints + can be activated by zero step. Equal to some large + value in case step is unlimited. + CIdx - -1 for unlimited step, in [0,N+NEC+NIC) in case of + limited step. + VVal - value which is assigned to X[CIdx] during activation. + For CIdx<0 or CIdx>=N some dummy value is assigned to + this parameter. +*************************************************************************/ +void sasexploredirection(const sactiveset* state, + /* Real */ const ae_vector* d, + double* stpmax, + ae_int_t* cidx, + double* vval, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + double prevmax; + double vc; + double vd; + + *stpmax = 0.0; + *cidx = 0; + *vval = 0.0; + + ae_assert(state->algostate==1, "SASExploreDirection: is not in optimization mode", _state); + n = state->n; + nec = state->nec; + nic = state->nic; + *cidx = -1; + *vval = (double)(0); + *stpmax = 1.0E50; + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]<=0 ) + { + ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); + ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]), "SASExploreDirection: internal error - infeasible X", _state); + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(d->ptr.p_double[i],(double)(0)) ) + { + prevmax = *stpmax; + *stpmax = safeminposrv(state->xc.ptr.p_double[i]-state->bndl.ptr.p_double[i], -d->ptr.p_double[i], *stpmax, _state); + if( ae_fp_less(*stpmax,prevmax) ) + { + *cidx = i; + *vval = state->bndl.ptr.p_double[i]; + } + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(d->ptr.p_double[i],(double)(0)) ) + { + prevmax = *stpmax; + *stpmax = safeminposrv(state->bndu.ptr.p_double[i]-state->xc.ptr.p_double[i], d->ptr.p_double[i], *stpmax, _state); + if( ae_fp_less(*stpmax,prevmax) ) + { + *cidx = i; + *vval = state->bndu.ptr.p_double[i]; + } + } + } + } + for(i=nec; i<=nec+nic-1; i++) + { + if( state->cstatus.ptr.p_int[n+i]<=0 ) + { + vc = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vc = vc-state->cleic.ptr.pp_double[i][n]; + vd = ae_v_dotproduct(&state->cleic.ptr.pp_double[i][0], 1, &d->ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_less_eq(vd,(double)(0)) ) + { + continue; + } + if( ae_fp_less(vc,(double)(0)) ) + { + + /* + * XC is strictly feasible with respect to I-th constraint, + * we can perform non-zero step because there is non-zero distance + * between XC and bound. + */ + prevmax = *stpmax; + *stpmax = safeminposrv(-vc, vd, *stpmax, _state); + if( ae_fp_less(*stpmax,prevmax) ) + { + *cidx = n+i; + } + } + else + { + + /* + * XC is at the boundary (or slightly beyond it), and step vector + * points beyond the boundary. + * + * The only thing we can do is to perform zero step and activate + * I-th constraint. + */ + *stpmax = (double)(0); + *cidx = n+i; + } + } + } +} + + +/************************************************************************* +This subroutine moves current point to XN, which can be: +a) point in the direction previously explored with SASExploreDirection() + function (in this case NeedAct/CIdx/CVal are used) +b) point in arbitrary direction, not necessarily previously checked with + SASExploreDirection() function. + +Step may activate one constraint. It is assumed than XN is approximately +feasible (small error as large as several ulps is possible). Strict +feasibility with respect to bound constraints is enforced during +activation, feasibility with respect to general linear constraints is not +enforced. + +This function activates boundary constraints, such that both is True: +1) XC[I] is not at the boundary +2) XN[I] is at the boundary or beyond it + +INPUT PARAMETERS: + S - active set object + XN - new point. + NeedAct - True in case one constraint needs activation + CIdx - index of constraint, in [0,N+NEC+NIC). + Ignored if NeedAct is false. + This value is calculated by SASExploreDirection(). + CVal - for CIdx in [0,N) this field stores value which is + assigned to XC[CIdx] during activation. CVal is ignored in + other cases. + This value is calculated by SASExploreDirection(). + +OUTPUT PARAMETERS: + S - current point and list of active constraints are changed. + +RESULT: + >0, in case at least one inactive non-candidate constraint was activated + =0, in case only "candidate" constraints were activated + <0, in case no constraints were activated by the step + +NOTE: in general case State.XC<>XN because activation of constraints may + slightly change current point (to enforce feasibility). + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +ae_int_t sasmoveto(sactiveset* state, + /* Real */ const ae_vector* xn, + ae_bool needact, + ae_int_t cidx, + double cval, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + ae_bool wasactivation; + ae_int_t result; + + + ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); + n = state->n; + nec = state->nec; + nic = state->nic; + + /* + * Save previous state, update current point + */ + rvectorsetlengthatleast(&state->mtx, n, _state); + ivectorsetlengthatleast(&state->mtas, n+nec+nic, _state); + for(i=0; i<=n-1; i++) + { + state->mtx.ptr.p_double[i] = state->xc.ptr.p_double[i]; + state->xc.ptr.p_double[i] = xn->ptr.p_double[i]; + } + for(i=0; i<=n+nec+nic-1; i++) + { + state->mtas.ptr.p_int[i] = state->cstatus.ptr.p_int[i]; + } + + /* + * Activate constraints + */ + bvectorsetlengthatleast(&state->mtnew, n+nec+nic, _state); + wasactivation = ae_false; + for(i=0; i<=n+nec+nic-1; i++) + { + state->mtnew.ptr.p_bool[i] = ae_false; + } + if( needact ) + { + + /* + * Activation + */ + ae_assert(cidx>=0&&cidxxc.ptr.p_double[cidx] = cval; + } + state->cstatus.ptr.p_int[cidx] = 1; + state->mtnew.ptr.p_bool[cidx] = ae_true; + wasactivation = ae_true; + } + for(i=0; i<=n-1; i++) + { + + /* + * Post-check (some constraints may be activated because of numerical errors) + */ + if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = 1; + state->mtnew.ptr.p_bool[i] = ae_true; + wasactivation = ae_true; + } + if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + state->cstatus.ptr.p_int[i] = 1; + state->mtnew.ptr.p_bool[i] = ae_true; + wasactivation = ae_true; + } + } + + /* + * Determine return status: + * * -1 in case no constraints were activated + * * 0 in case only "candidate" constraints were activated + * * +1 in case at least one "non-candidate" constraint was activated + */ + if( wasactivation ) + { + + /* + * Step activated one/several constraints, but sometimes it is spurious + * activation - RecalculateConstraints() tells us that constraint is + * inactive (negative Largrange multiplier), but step activates it + * because of numerical noise. + * + * This block of code checks whether step activated truly new constraints + * (ones which were not in the active set at the solution): + * + * * for non-boundary constraint it is enough to check that previous value + * of CStatus[i] is negative (=far from boundary), and new one is + * positive (=we are at the boundary, constraint is activated). + * + * * for boundary constraints previous criterion won't work. Each variable + * has two constraints, and simply checking their status is not enough - + * we have to correctly identify cases when we leave one boundary + * (PrevActiveSet[i]=0) and move to another boundary (CStatus[i]>0). + * Such cases can be identified if we compare previous X with new X. + * + * In case only "candidate" constraints were activated, result variable + * is set to 0. In case at least one new constraint was activated, result + * is set to 1. + */ + result = 0; + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]>0&&ae_fp_neq(state->xc.ptr.p_double[i],state->mtx.ptr.p_double[i]) ) + { + result = 1; + } + } + for(i=n; i<=n+state->nec+state->nic-1; i++) + { + if( state->mtas.ptr.p_int[i]<0&&state->cstatus.ptr.p_int[i]>0 ) + { + result = 1; + } + } + } + else + { + + /* + * No activation, return -1 + */ + result = -1; + } + + /* + * Update basis + */ + sasappendtobasis(state, &state->mtnew, _state); + return result; +} + + +/************************************************************************* +This subroutine performs immediate activation of one constraint: +* "immediate" means that we do not have to move to activate it +* in case boundary constraint is activated, we enforce current point to be + exactly at the boundary + +INPUT PARAMETERS: + S - active set object + CIdx - index of constraint, in [0,N+NEC+NIC). + This value is calculated by SASExploreDirection(). + CVal - for CIdx in [0,N) this field stores value which is + assigned to XC[CIdx] during activation. CVal is ignored in + other cases. + This value is calculated by SASExploreDirection(). + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasimmediateactivation(sactiveset* state, + ae_int_t cidx, + double cval, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); + if( cidxn ) + { + state->xc.ptr.p_double[cidx] = cval; + } + state->cstatus.ptr.p_int[cidx] = 1; + bvectorsetlengthatleast(&state->mtnew, state->n+state->nec+state->nic, _state); + for(i=0; i<=state->n+state->nec+state->nic-1; i++) + { + state->mtnew.ptr.p_bool[i] = ae_false; + } + state->mtnew.ptr.p_bool[cidx] = ae_true; + sasappendtobasis(state, &state->mtnew, _state); +} + + +/************************************************************************* +This subroutine calculates descent direction subject to current active set. + +INPUT PARAMETERS: + S - active set object + G - array[N], gradient + D - possibly prealocated buffer; + automatically resized if needed. + +OUTPUT PARAMETERS: + D - descent direction projected onto current active set. + Components of D which correspond to active boundary + constraints are forced to be exactly zero. + In case D is non-zero, it is normalized to have unit norm. + +NOTE: in case active set has N active constraints (or more), descent + direction is forced to be exactly zero. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasconstraineddescent(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state) +{ + + + ae_assert(state->algostate==1, "SASConstrainedDescent: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + sactivesets_constraineddescent(state, g, &state->unitdiagonal, &state->idensebatch, ae_true, d, _state); +} + + +/************************************************************************* +This subroutine calculates preconditioned descent direction subject to +current active set. + +INPUT PARAMETERS: + S - active set object + G - array[N], gradient + D - possibly prealocated buffer; + automatically resized if needed. + +OUTPUT PARAMETERS: + D - descent direction projected onto current active set. + Components of D which correspond to active boundary + constraints are forced to be exactly zero. + In case D is non-zero, it is normalized to have unit norm. + +NOTE: in case active set has N active constraints (or more), descent + direction is forced to be exactly zero. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasconstraineddescentprec(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state) +{ + + + ae_assert(state->algostate==1, "SASConstrainedDescentPrec: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + sactivesets_constraineddescent(state, g, &state->h, &state->pdensebatch, ae_true, d, _state); +} + + +/************************************************************************* +This subroutine calculates projection of direction vector to current +active set. + +INPUT PARAMETERS: + S - active set object + D - array[N], direction + +OUTPUT PARAMETERS: + D - direction projected onto current active set. + Components of D which correspond to active boundary + constraints are forced to be exactly zero. + +NOTE: in case active set has N active constraints (or more), descent + direction is forced to be exactly zero. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasconstraineddirection(sactiveset* state, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + sactivesets_constraineddescent(state, d, &state->unitdiagonal, &state->idensebatch, ae_false, &state->cdtmp, _state); + for(i=0; i<=state->n-1; i++) + { + d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; + } +} + + +/************************************************************************* +This subroutine calculates product of direction vector and preconditioner +multiplied subject to current active set. + +INPUT PARAMETERS: + S - active set object + D - array[N], direction + +OUTPUT PARAMETERS: + D - preconditioned direction projected onto current active set. + Components of D which correspond to active boundary + constraints are forced to be exactly zero. + +NOTE: in case active set has N active constraints (or more), descent + direction is forced to be exactly zero. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasconstraineddirectionprec(sactiveset* state, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->algostate==1, "SASConstrainedAntigradientPrec: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + sactivesets_constraineddescent(state, d, &state->h, &state->pdensebatch, ae_false, &state->cdtmp, _state); + for(i=0; i<=state->n-1; i++) + { + d->ptr.p_double[i] = -state->cdtmp.ptr.p_double[i]; + } +} + + +/************************************************************************* +This subroutine performs correction of some (possibly infeasible) point +with respect to a) current active set, b) all boundary constraints, both +active and inactive: + +0) we calculate L1 penalty term for violation of active linear constraints + (one which is returned by SASActiveLCPenalty1() function). +1) first, it performs projection (orthogonal with respect to scale matrix + S) of X into current active set: X -> X1. +2) next, we perform projection with respect to ALL boundary constraints + which are violated at X1: X1 -> X2. +3) X is replaced by X2. + +The idea is that this function can preserve and enforce feasibility during +optimization, and additional penalty parameter can be used to prevent algo +from leaving feasible set because of rounding errors. + +INPUT PARAMETERS: + S - active set object + X - array[N], candidate point + +OUTPUT PARAMETERS: + X - "improved" candidate point: + a) feasible with respect to all boundary constraints + b) feasibility with respect to active set is retained at + good level. + Penalty - penalty term, which can be added to function value if user + wants to penalize violation of constraints (recommended). + +NOTE: this function is not intended to find exact projection (i.e. best + approximation) of X into feasible set. It just improves situation a + bit. + Regular use of this function will help you to retain feasibility + - if you already have something to start with and constrain your + steps is such way that the only source of infeasibility are roundoff + errors. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sascorrection(sactiveset* state, + /* Real */ ae_vector* x, + double* penalty, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + double v; + + *penalty = 0.0; + + ae_assert(state->algostate==1, "SASCorrection: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + n = state->n; + rvectorsetlengthatleast(&state->corrtmp, n, _state); + + /* + * Calculate penalty term. + */ + *penalty = sasactivelcpenalty1(state, x, _state); + + /* + * Perform projection 1. + * + * This projecton is given by: + * + * x_proj = x - S*S*As'*(As*x-b) + * + * where x is original x before projection, S is a scale matrix, + * As is a matrix of equality constraints (active set) which were + * orthogonalized with respect to inner product given by S (i.e. we + * have As*S*S'*As'=I), b is a right part of the orthogonalized + * constraints. + * + * NOTE: you can verify that x_proj is strictly feasible w.r.t. + * active set by multiplying it by As - you will get + * As*x_proj = As*x - As*x + b = b. + * + * This formula for projection can be obtained by solving + * following minimization problem. + * + * min ||inv(S)*(x_proj-x)||^2 s.t. As*x_proj=b + * + * NOTE: we apply sparse batch by examining CStatus[]; it is guaranteed + * to contain sparse batch, but avoids roundoff errors associated + * with the fact that some box constraints were moved to sparse + * storage + * + */ + ae_v_move(&state->corrtmp.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=state->densebatchsize-1; i++) + { + v = -state->sdensebatch.ptr.pp_double[i][n]; + for(j=0; j<=n-1; j++) + { + v = v+state->sdensebatch.ptr.pp_double[i][j]*state->corrtmp.ptr.p_double[j]; + } + for(j=0; j<=n-1; j++) + { + state->corrtmp.ptr.p_double[j] = state->corrtmp.ptr.p_double[j]-v*state->sdensebatch.ptr.pp_double[i][j]*ae_sqr(state->s.ptr.p_double[j], _state); + } + } + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]>0 ) + { + state->corrtmp.ptr.p_double[i] = state->xc.ptr.p_double[i]; + } + } + + /* + * Perform projection 2 + */ + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = state->corrtmp.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This subroutine returns L1 penalty for violation of active general linear +constraints (violation of boundary or inactive linear constraints is not +added to penalty). + +Penalty term is equal to: + + Penalty = SUM( Abs((C_i*x-R_i)/Alpha_i) ) + +Here: +* summation is performed for I=0...NEC+NIC-1, CStatus[N+I]>0 + (only for rows of CLEIC which are in active set) +* C_i is I-th row of CLEIC +* R_i is corresponding right part +* S is a scale matrix +* Alpha_i = ||S*C_i|| - is a scaling coefficient which "normalizes" + I-th summation term according to its scale. + +INPUT PARAMETERS: + S - active set object + X - array[N], candidate point + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +double sasactivelcpenalty1(sactiveset* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + double v; + double alpha; + double p; + double result; + + + ae_assert(state->algostate==1, "SASActiveLCPenalty1: is not in optimization mode", _state); + sasrebuildbasis(state, _state); + n = state->n; + nec = state->nec; + nic = state->nic; + + /* + * Calculate penalty term. + */ + result = (double)(0); + for(i=0; i<=nec+nic-1; i++) + { + if( state->cstatus.ptr.p_int[n+i]>0 ) + { + alpha = (double)(0); + p = -state->cleic.ptr.pp_double[i][n]; + for(j=0; j<=n-1; j++) + { + v = state->cleic.ptr.pp_double[i][j]; + p = p+v*x->ptr.p_double[j]; + alpha = alpha+ae_sqr(v*state->s.ptr.p_double[j], _state); + } + alpha = ae_sqrt(alpha, _state); + if( ae_fp_neq(alpha,(double)(0)) ) + { + result = result+ae_fabs(p/alpha, _state); + } + } + } + return result; +} + + +/************************************************************************* +This subroutine calculates scaled norm of vector after projection onto +subspace of active constraints. Most often this function is used to test +stopping conditions. + +INPUT PARAMETERS: + S - active set object + D - vector whose norm is calculated + +RESULT: + Vector norm (after projection and scaling) + +NOTE: projection is performed first, scaling is performed after projection + +NOTE: if we have N active constraints, zero value (exact zero) is returned + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +double sasscaledconstrainednorm(sactiveset* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double v; + double result; + + + ae_assert(state->algostate==1, "SASMoveTo: is not in optimization mode", _state); + n = state->n; + rvectorsetlengthatleast(&state->scntmp, n, _state); + + /* + * Prepare basis (if needed) + */ + sasrebuildbasis(state, _state); + + /* + * Calculate descent direction + */ + if( state->sparsebatchsize+state->densebatchsize>=n ) + { + + /* + * Quick exit if number of active constraints is N or larger + */ + result = 0.0; + return result; + } + for(i=0; i<=n-1; i++) + { + state->scntmp.ptr.p_double[i] = d->ptr.p_double[i]; + } + for(i=0; i<=state->densebatchsize-1; i++) + { + v = ae_v_dotproduct(&state->idensebatch.ptr.pp_double[i][0], 1, &state->scntmp.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_subd(&state->scntmp.ptr.p_double[0], 1, &state->idensebatch.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]>0 ) + { + state->scntmp.ptr.p_double[i] = (double)(0); + } + } + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->s.ptr.p_double[i]*state->scntmp.ptr.p_double[i], _state); + } + result = ae_sqrt(v, _state); + return result; +} + + +/************************************************************************* +This subroutine turns off optimization mode. + +INPUT PARAMETERS: + S - active set object + +OUTPUT PARAMETERS: + S - state is changed + +NOTE: this function can be called many times for optimizer which was + already stopped. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +void sasstopoptimization(sactiveset* state, ae_state *_state) +{ + + + state->algostate = 0; +} + + +/************************************************************************* +This function recalculates constraints - activates and deactivates them +according to gradient value at current point. Algorithm assumes that we +want to make steepest descent step from current point; constraints are +activated and deactivated in such way that we won't violate any constraint +by steepest descent step. + +After call to this function active set is ready to try steepest descent +step (SASDescentDirection-SASExploreDirection-SASMoveTo). + +Only already "active" and "candidate" elements of ActiveSet are examined; +constraints which are not active are not examined. + +INPUT PARAMETERS: + State - active set object + GC - array[N], gradient at XC + +OUTPUT PARAMETERS: + State - active set object, with new set of constraint + + -- ALGLIB -- + Copyright 26.09.2012 by Bochkanov Sergey +*************************************************************************/ +void sasreactivateconstraints(sactiveset* state, + /* Real */ const ae_vector* gc, + ae_state *_state) +{ + + + ae_assert(state->algostate==1, "SASReactivateConstraints: must be in optimization mode", _state); + sactivesets_reactivateconstraints(state, gc, &state->unitdiagonal, _state); +} + + +/************************************************************************* +This function recalculates constraints - activates and deactivates them +according to gradient value at current point. + +Algorithm assumes that we want to make Quasi-Newton step from current +point with diagonal Quasi-Newton matrix H. Constraints are activated and +deactivated in such way that we won't violate any constraint by step. + +After call to this function active set is ready to try preconditioned +steepest descent step (SASDescentDirection-SASExploreDirection-SASMoveTo). + +Only already "active" and "candidate" elements of ActiveSet are examined; +constraints which are not active are not examined. + +INPUT PARAMETERS: + State - active set object + GC - array[N], gradient at XC + +OUTPUT PARAMETERS: + State - active set object, with new set of constraint + + -- ALGLIB -- + Copyright 26.09.2012 by Bochkanov Sergey +*************************************************************************/ +void sasreactivateconstraintsprec(sactiveset* state, + /* Real */ const ae_vector* gc, + ae_state *_state) +{ + + + ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); + sactivesets_reactivateconstraints(state, gc, &state->h, _state); +} + + +/************************************************************************* +This function builds three orthonormal basises for current active set: +* P-orthogonal one, which is orthogonalized with inner product + (x,y) = x'*P*y, where P=inv(H) is current preconditioner +* S-orthogonal one, which is orthogonalized with inner product + (x,y) = x'*S'*S*y, where S is diagonal scaling matrix +* I-orthogonal one, which is orthogonalized with standard dot product + +NOTE: all sets of orthogonal vectors are guaranteed to have same size. + P-orthogonal basis is built first, I/S-orthogonal basises are forced + to have same number of vectors as P-orthogonal one (padded by zero + vectors if needed). + +NOTE: this function tracks changes in active set; first call will result + in reorthogonalization + +INPUT PARAMETERS: + State - active set object + H - diagonal preconditioner, H[i]>0 + +OUTPUT PARAMETERS: + State - active set object with new basis + + -- ALGLIB -- + Copyright 20.06.2012 by Bochkanov Sergey +*************************************************************************/ +void sasrebuildbasis(sactiveset* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + ae_int_t j; + ae_bool hasactivelin; + ae_int_t candidatescnt; + double v; + double vv; + double vmax; + ae_int_t kmax; + + + if( state->basisisready ) + { + return; + } + n = state->n; + nec = state->nec; + nic = state->nic; + rvectorsetlengthatleast(&state->tmp0, n, _state); + rvectorsetlengthatleast(&state->tmpprodp, n, _state); + rvectorsetlengthatleast(&state->tmpprods, n, _state); + rvectorsetlengthatleast(&state->tmpcp, n+1, _state); + rvectorsetlengthatleast(&state->tmpcs, n+1, _state); + rvectorsetlengthatleast(&state->tmpci, n+1, _state); + rmatrixsetlengthatleast(&state->tmpbasis, nec+nic, n+1, _state); + rmatrixsetlengthatleast(&state->pdensebatch, nec+nic, n+1, _state); + rmatrixsetlengthatleast(&state->idensebatch, nec+nic, n+1, _state); + rmatrixsetlengthatleast(&state->sdensebatch, nec+nic, n+1, _state); + ivectorsetlengthatleast(&state->sparsebatch, n, _state); + state->sparsebatchsize = 0; + state->densebatchsize = 0; + state->basisage = 0; + state->basisisready = ae_true; + + /* + * Determine number of active boundary and non-boundary + * constraints, move them to TmpBasis. Quick exit if no + * non-boundary constraints were detected. + */ + hasactivelin = ae_false; + for(i=0; i<=nec+nic-1; i++) + { + if( state->cstatus.ptr.p_int[n+i]>0 ) + { + hasactivelin = ae_true; + } + } + for(j=0; j<=n-1; j++) + { + if( state->cstatus.ptr.p_int[j]>0 ) + { + state->sparsebatch.ptr.p_int[state->sparsebatchsize] = j; + state->sparsebatchsize = state->sparsebatchsize+1; + } + } + if( !hasactivelin ) + { + return; + } + + /* + * Prepare precomputed values + */ + rvectorsetlengthatleast(&state->tmpreciph, n, _state); + for(i=0; i<=n-1; i++) + { + state->tmpreciph.ptr.p_double[i] = (double)1/state->h.ptr.p_double[i]; + } + + /* + * Prepare initial candidate set: + * * select active constraints + * * normalize (inner product is given by preconditioner) + * * orthogonalize with respect to active box constraints + * * copy normalized/orthogonalized candidates to PBasis/SBasis/IBasis + */ + candidatescnt = 0; + for(i=0; i<=nec+nic-1; i++) + { + if( state->cstatus.ptr.p_int[n+i]>0 ) + { + ae_v_move(&state->tmpbasis.ptr.pp_double[candidatescnt][0], 1, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n)); + inc(&candidatescnt, _state); + } + } + for(i=0; i<=candidatescnt-1; i++) + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = v+ae_sqr(state->tmpbasis.ptr.pp_double[i][j], _state)*state->tmpreciph.ptr.p_double[j]; + } + if( ae_fp_greater(v,(double)(0)) ) + { + v = (double)1/ae_sqrt(v, _state); + for(j=0; j<=n; j++) + { + state->tmpbasis.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]*v; + } + } + } + for(j=0; j<=n-1; j++) + { + if( state->cstatus.ptr.p_int[j]>0 ) + { + for(i=0; i<=candidatescnt-1; i++) + { + state->tmpbasis.ptr.pp_double[i][n] = state->tmpbasis.ptr.pp_double[i][n]-state->tmpbasis.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; + state->tmpbasis.ptr.pp_double[i][j] = 0.0; + } + } + } + for(i=0; i<=candidatescnt-1; i++) + { + for(j=0; j<=n; j++) + { + state->pdensebatch.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]; + state->sdensebatch.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]; + state->idensebatch.ptr.pp_double[i][j] = state->tmpbasis.ptr.pp_double[i][j]; + } + } + + /* + * Perform orthogonalization of general linear constraints with respect + * to each other (constraints in P/S/IBasis are already normalized w.r.t. + * box constraints). During this process we select strictly active constraints + * from the candidate set, and drop ones which were detected as redundant + * during orthogonalization. + * + * Orthogonalization is performed with the help of Gram-Schmidt process. + * Due to accumulation of round-off errors it is beneficial to perform + * pivoting, i.e. to select candidate vector with largest norm at each + * step. + * + * First (basic) version of the algorithm is: + * 0. split all constraints into two sets: basis ones (initially empty) + * and candidate ones (all constraints) + * 1. fill PBasis with H-normalized candidate constraints, fill + * corresponding entries of S/IBasis with corresponding + * (non-normalized) constraints + * 2. select row of PBasis with largest norm, move it (and its S/IBasis + * counterparts) to the beginning of the candidate set, H-normalize + * this row (rows of S/IBasis are normalized using corresponding norms). + * Stop if largest row is nearly (or exactly) zero. + * 3. orthogonalize remaining rows of P/S/IBasis with respect to + * one chosen at step (2). It can be done efficiently using + * combination of DGEMV/DGER BLAS calls. + * 4. increase basis size by one, decrease candidate set size by one, + * goto (2) + * + * However, naive implementation of the algorithm above spends significant + * amount of time in step (2) - selection of row with largest H-norm. Step + * (3) can be efficiently implemented with optimized BLAS, but we have no + * optimized BLAS kernels for step(2). And because step (3) changes row norms, + * step (2) have to be re-calculated every time, which is quite slow. + * + * We can save significant amount of calculations by noticing that: + * * step (3) DECREASES row norms, but never increases it + * * we can maintain upper bounds for row H-norms is a separate array, + * use them for initial evaluation of best candidates, and update them + * after we find some promising row (all bounds are invalidated after + * step 3, but their old values still carry some information) + * * it is beneficial re-evaluate bounds only for rows which are + * significantly (at least few percents) larger than best one found so far + * * because rows are initially normalized, initial values for upper bounds + * can be set to 1.0 + */ + ae_assert(state->densebatchsize==0, "SAS: integrity check failed", _state); + ae_assert(ae_fp_greater(sactivesets_minnormseparation,(double)(0)), "SAS: integrity check failed", _state); + rvectorsetlengthatleast(&state->tmpnormestimates, candidatescnt, _state); + for(i=0; i<=candidatescnt-1; i++) + { + state->tmpnormestimates.ptr.p_double[i] = 1.0; + } + while(state->sparsebatchsize+state->densebatchsizedensebatchsize; i<=state->densebatchsize+candidatescnt-1; i++) + { + + /* + * Use upper bound for row norm for initial evaluation. + * Skip rows whose upper bound is less than best candidate + * found so far. + * + * NOTE: in fact, we may skip rows whose upper bound is + * marginally higher than that of best candidate. + * No need to perform costly re-evaluation in order + * to get just few percents of improvement. + */ + if( ae_fp_less(state->tmpnormestimates.ptr.p_double[i],vmax*((double)1+sactivesets_minnormseparation)) ) + { + continue; + } + + /* + * OK, upper bound is large enough... lets perform full + * re-evaluation and update of the estimate. + */ + v = 0.0; + for(j=0; j<=n-1; j++) + { + vv = state->pdensebatch.ptr.pp_double[i][j]; + v = v+vv*vv*state->tmpreciph.ptr.p_double[j]; + } + v = ae_sqrt(v, _state); + state->tmpnormestimates.ptr.p_double[i] = v; + + /* + * Now compare with best candidate so far + */ + if( ae_fp_greater(v,vmax) ) + { + vmax = v; + kmax = i; + } + } + if( ae_fp_less(vmax,1.0E4*ae_machineepsilon)||kmax<0 ) + { + + /* + * All candidates are either zero or too small (after orthogonalization) + */ + candidatescnt = 0; + break; + } + + /* + * Candidate is selected for inclusion into basis set. + * + * Move candidate row to the beginning of candidate array (which is + * right past the end of the approved basis). Normalize (for P-basis + * we perform preconditioner-based normalization, for S-basis - scale + * based, for I-basis - identity based). + */ + swaprows(&state->pdensebatch, state->densebatchsize, kmax, n+1, _state); + swaprows(&state->sdensebatch, state->densebatchsize, kmax, n+1, _state); + swaprows(&state->idensebatch, state->densebatchsize, kmax, n+1, _state); + swapelements(&state->tmpnormestimates, state->densebatchsize, kmax, _state); + v = (double)1/vmax; + ae_v_muld(&state->pdensebatch.ptr.pp_double[state->densebatchsize][0], 1, ae_v_len(0,n), v); + v = (double)(0); + for(j=0; j<=n-1; j++) + { + vv = state->sdensebatch.ptr.pp_double[state->densebatchsize][j]*state->s.ptr.p_double[j]; + v = v+vv*vv; + } + ae_assert(ae_fp_greater(v,(double)(0)), "SActiveSet.RebuildBasis(): integrity check failed, SNorm=0", _state); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&state->sdensebatch.ptr.pp_double[state->densebatchsize][0], 1, ae_v_len(0,n), v); + v = (double)(0); + for(j=0; j<=n-1; j++) + { + vv = state->idensebatch.ptr.pp_double[state->densebatchsize][j]; + v = v+vv*vv; + } + ae_assert(ae_fp_greater(v,(double)(0)), "SActiveSet.RebuildBasis(): integrity check failed, INorm=0", _state); + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&state->idensebatch.ptr.pp_double[state->densebatchsize][0], 1, ae_v_len(0,n), v); + + /* + * Reorthogonalize other candidates with respect to candidate #0: + * * calculate projections en masse with GEMV() + * * subtract projections with GER() + */ + rvectorsetlengthatleast(&state->tmp0, candidatescnt-1, _state); + for(j=0; j<=n-1; j++) + { + state->tmpprodp.ptr.p_double[j] = state->pdensebatch.ptr.pp_double[state->densebatchsize][j]/state->h.ptr.p_double[j]; + state->tmpprods.ptr.p_double[j] = state->sdensebatch.ptr.pp_double[state->densebatchsize][j]*ae_sqr(state->s.ptr.p_double[j], _state); + } + for(j=0; j<=n; j++) + { + state->tmpcp.ptr.p_double[j] = state->pdensebatch.ptr.pp_double[state->densebatchsize][j]; + state->tmpcs.ptr.p_double[j] = state->sdensebatch.ptr.pp_double[state->densebatchsize][j]; + state->tmpci.ptr.p_double[j] = state->idensebatch.ptr.pp_double[state->densebatchsize][j]; + } + rmatrixgemv(candidatescnt-1, n, 1.0, &state->pdensebatch, state->densebatchsize+1, 0, 0, &state->tmpprodp, 0, 0.0, &state->tmp0, 0, _state); + rmatrixger(candidatescnt-1, n+1, &state->pdensebatch, state->densebatchsize+1, 0, -1.0, &state->tmp0, 0, &state->tmpcp, 0, _state); + rmatrixgemv(candidatescnt-1, n, 1.0, &state->sdensebatch, state->densebatchsize+1, 0, 0, &state->tmpprods, 0, 0.0, &state->tmp0, 0, _state); + rmatrixger(candidatescnt-1, n+1, &state->sdensebatch, state->densebatchsize+1, 0, -1.0, &state->tmp0, 0, &state->tmpcs, 0, _state); + rmatrixgemv(candidatescnt-1, n, 1.0, &state->idensebatch, state->densebatchsize+1, 0, 0, &state->tmpci, 0, 0.0, &state->tmp0, 0, _state); + rmatrixger(candidatescnt-1, n+1, &state->idensebatch, state->densebatchsize+1, 0, -1.0, &state->tmp0, 0, &state->tmpci, 0, _state); + + /* + * Increase basis, decrease candidates count + */ + inc(&state->densebatchsize, _state); + dec(&candidatescnt, _state); + } +} + + +/************************************************************************* +This function appends new constraints (if possible; sometimes it isn't!) +to three orthonormal basises for current active set: +* P-orthogonal one, which is orthogonalized with inner product + (x,y) = x'*P*y, where P=inv(H) is current preconditioner +* S-orthogonal one, which is orthogonalized with inner product + (x,y) = x'*S'*S*y, where S is diagonal scaling matrix +* I-orthogonal one, which is orthogonalized with standard dot product + +NOTE: all sets of orthogonal vectors are guaranteed to have same size. + P-orthogonal basis is built first, I/S-orthogonal basises are forced + to have same number of vectors as P-orthogonal one (padded by zero + vectors if needed). + +NOTE: this function may fail to update basis without full recalculation; + in such case it will set BasisIsReady to False and silently return; + if it succeeds, it will increase BasisSize. + +INPUT PARAMETERS: + State - active set object + NewEntries - array[N+NEC+NIC], indexes of constraints being added + are marked as True; it is responsibility of the caller + to specify only those constraints which were previously + inactive; when some constraint is already in the + active set, algorithm behavior is undefined. + +OUTPUT PARAMETERS: + State - active set object with new basis + + -- ALGLIB -- + Copyright 03.10.2017 by Bochkanov Sergey +*************************************************************************/ +void sasappendtobasis(sactiveset* state, + /* Boolean */ const ae_vector* newentries, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + ae_int_t j; + ae_int_t t; + ae_int_t nact; + double v; + double vp; + double vs; + double vi; + double initnormp; + double projnormp; + double projnorms; + double projnormi; + + + if( !state->basisisready ) + { + return; + } + n = state->n; + nec = state->nec; + nic = state->nic; + + /* + * Count number of constraints to activate; + * perform integrity check. + */ + nact = 0; + for(i=0; i<=n-1; i++) + { + if( newentries->ptr.p_bool[i] ) + { + nact = nact+1; + } + } + for(i=n; i<=n+nec-1; i++) + { + ae_assert(!newentries->ptr.p_bool[i], "SAS: integrity check failed (appendtobasis.0)", _state); + } + for(i=n+nec; i<=n+nec+nic-1; i++) + { + if( newentries->ptr.p_bool[i] ) + { + nact = nact+1; + } + } + if( nact+state->basisage>sactivesets_maxbasisage ) + { + state->basisisready = ae_false; + return; + } + + /* + * Resize basis matrices if needed + */ + rmatrixgrowrowsto(&state->pdensebatch, state->densebatchsize+nact, n+1, _state); + rmatrixgrowrowsto(&state->sdensebatch, state->densebatchsize+nact, n+1, _state); + rmatrixgrowrowsto(&state->idensebatch, state->densebatchsize+nact, n+1, _state); + + /* + * Try adding recommended entries to basis. + * If reorthogonalization removes too much of candidate constraint, + * we will invalidate basis and try to rebuild it from scratch. + */ + rvectorsetlengthatleast(&state->tmp0, n+1, _state); + rvectorsetlengthatleast(&state->tmpcp, n+1, _state); + rvectorsetlengthatleast(&state->tmpcs, n+1, _state); + rvectorsetlengthatleast(&state->tmpci, n+1, _state); + rvectorsetlengthatleast(&state->tmpprodp, n, _state); + rvectorsetlengthatleast(&state->tmpprods, n, _state); + for(t=0; t<=n+nec+nic-1; t++) + { + if( newentries->ptr.p_bool[t] ) + { + + /* + * Basis is full? Quick skip! + */ + if( state->sparsebatchsize+state->densebatchsize>=n ) + { + ae_assert(state->sparsebatchsize+state->densebatchsize==n, "SAS: integrity check failed (sasappendtobasis)", _state); + break; + } + + /* + * Copy constraint to temporary storage. + */ + if( ttmp0.ptr.p_double[j] = (double)(0); + } + state->tmp0.ptr.p_double[t] = 1.0; + state->tmp0.ptr.p_double[n] = state->xc.ptr.p_double[t]; + } + else + { + + /* + * Copy general linear constraint + */ + for(j=0; j<=n; j++) + { + state->tmp0.ptr.p_double[j] = state->cleic.ptr.pp_double[t-n][j]; + } + } + + /* + * Calculate initial norm (preconditioner is used for norm calculation). + */ + initnormp = 0.0; + for(j=0; j<=n-1; j++) + { + v = state->tmp0.ptr.p_double[j]; + initnormp = initnormp+v*v/state->h.ptr.p_double[j]; + } + initnormp = ae_sqrt(initnormp, _state); + if( ae_fp_eq(initnormp,(double)(0)) ) + { + + /* + * Well, it is not expected. Let's just rebuild basis + * from scratch and forget about this strange situation... + */ + state->basisisready = ae_false; + return; + } + + /* + * Orthogonalize Tmp0 w.r.t. sparse batch (box constraints stored in sparse storage). + * + * Copy to TmpCP/TmpCS/TmpCI (P for preconditioner-based inner product + * used for orthogonalization, S for scale-based orthogonalization, + * I for "traditional" inner product used for Gram-Schmidt orthogonalization). + */ + for(i=0; i<=state->sparsebatchsize-1; i++) + { + j = state->sparsebatch.ptr.p_int[i]; + state->tmp0.ptr.p_double[n] = state->tmp0.ptr.p_double[n]-state->tmp0.ptr.p_double[j]*state->xc.ptr.p_double[j]; + state->tmp0.ptr.p_double[j] = 0.0; + } + for(j=0; j<=n; j++) + { + state->tmpcp.ptr.p_double[j] = state->tmp0.ptr.p_double[j]; + state->tmpcs.ptr.p_double[j] = state->tmp0.ptr.p_double[j]; + state->tmpci.ptr.p_double[j] = state->tmp0.ptr.p_double[j]; + } + + /* + * Orthogonalize TmpCP/S/I with respect to active linear constraints from dense batch. + * Corresponding norm (preconditioner, scale, identity) is used in each case. + */ + for(j=0; j<=n-1; j++) + { + state->tmpprodp.ptr.p_double[j] = (double)1/state->h.ptr.p_double[j]; + state->tmpprods.ptr.p_double[j] = ae_sqr(state->s.ptr.p_double[j], _state); + } + for(i=0; i<=state->densebatchsize-1; i++) + { + vp = (double)(0); + vs = (double)(0); + vi = (double)(0); + for(j=0; j<=n-1; j++) + { + vp = vp+state->pdensebatch.ptr.pp_double[i][j]*state->tmpcp.ptr.p_double[j]*state->tmpprodp.ptr.p_double[j]; + vs = vs+state->sdensebatch.ptr.pp_double[i][j]*state->tmpcs.ptr.p_double[j]*state->tmpprods.ptr.p_double[j]; + vi = vi+state->idensebatch.ptr.pp_double[i][j]*state->tmpci.ptr.p_double[j]; + } + ae_v_subd(&state->tmpcp.ptr.p_double[0], 1, &state->pdensebatch.ptr.pp_double[i][0], 1, ae_v_len(0,n), vp); + ae_v_subd(&state->tmpcs.ptr.p_double[0], 1, &state->sdensebatch.ptr.pp_double[i][0], 1, ae_v_len(0,n), vs); + ae_v_subd(&state->tmpci.ptr.p_double[0], 1, &state->idensebatch.ptr.pp_double[i][0], 1, ae_v_len(0,n), vi); + } + projnormp = 0.0; + projnorms = 0.0; + projnormi = 0.0; + for(j=0; j<=n-1; j++) + { + projnormp = projnormp+ae_sqr(state->tmpcp.ptr.p_double[j], _state)/state->h.ptr.p_double[j]; + projnorms = projnorms+ae_sqr(state->tmpcs.ptr.p_double[j], _state)*ae_sqr(state->s.ptr.p_double[j], _state); + projnormi = projnormi+ae_sqr(state->tmpci.ptr.p_double[j], _state); + } + projnormp = ae_sqrt(projnormp, _state); + projnorms = ae_sqrt(projnorms, _state); + projnormi = ae_sqrt(projnormi, _state); + if( ae_fp_less_eq(projnormp,sactivesets_maxbasisdecay*initnormp) ) + { + state->basisisready = ae_false; + return; + + /* + * Nearly zero row, skip + */ + } + ae_assert(ae_fp_greater(projnormp,(double)(0)), "SAS: integrity check failed, ProjNormP=0", _state); + ae_assert(ae_fp_greater(projnorms,(double)(0)), "SAS: integrity check failed, ProjNormS=0", _state); + ae_assert(ae_fp_greater(projnormi,(double)(0)), "SAS: integrity check failed, ProjNormI=0", _state); + v = (double)1/projnormp; + ae_v_moved(&state->pdensebatch.ptr.pp_double[state->densebatchsize][0], 1, &state->tmpcp.ptr.p_double[0], 1, ae_v_len(0,n), v); + v = (double)1/projnorms; + ae_v_moved(&state->sdensebatch.ptr.pp_double[state->densebatchsize][0], 1, &state->tmpcs.ptr.p_double[0], 1, ae_v_len(0,n), v); + v = (double)1/projnormi; + ae_v_moved(&state->idensebatch.ptr.pp_double[state->densebatchsize][0], 1, &state->tmpci.ptr.p_double[0], 1, ae_v_len(0,n), v); + + /* + * Increase set size + */ + inc(&state->densebatchsize, _state); + inc(&state->basisage, _state); + } + } +} + + +/************************************************************************* +This subroutine calculates preconditioned descent direction subject to +current active set. + +INPUT PARAMETERS: + State - active set object + G - array[N], gradient + H - array[N], Hessian matrix + HA - active constraints orthogonalized in such way + that HA*inv(H)*HA'= I. + Normalize- whether we need normalized descent or not + D - possibly preallocated buffer; automatically resized. + +OUTPUT PARAMETERS: + D - descent direction projected onto current active set. + Components of D which correspond to active boundary + constraints are forced to be exactly zero. + In case D is non-zero and Normalize is True, it is + normalized to have unit norm. + +NOTE: if we have N active constraints, D is explicitly set to zero. + + -- ALGLIB -- + Copyright 21.12.2012 by Bochkanov Sergey +*************************************************************************/ +static void sactivesets_constraineddescent(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ const ae_vector* h, + /* Real */ const ae_matrix* ha, + ae_bool normalize, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + double v; + + + ae_assert(state->algostate==1, "SAS: internal error in ConstrainedDescent() - not in optimization mode", _state); + ae_assert(state->basisisready, "SAS: internal error in ConstrainedDescent() - no basis", _state); + n = state->n; + rvectorsetlengthatleast(d, n, _state); + + /* + * Calculate preconditioned constrained descent direction: + * + * d := -inv(H)*( g - HA'*(HA*inv(H)*g) ) + * + * Formula above always gives direction which is orthogonal to rows of HA. + * You can verify it by multiplication of both sides by HA[i] (I-th row), + * taking into account that HA*inv(H)*HA'= I (by definition of HA - it is + * orthogonal basis with inner product given by inv(H)). + */ + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = g->ptr.p_double[i]; + } + for(i=0; i<=state->densebatchsize-1; i++) + { + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = v+ha->ptr.pp_double[i][j]*d->ptr.p_double[j]/h->ptr.p_double[j]; + } + ae_v_subd(&d->ptr.p_double[0], 1, &ha->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]>0 ) + { + d->ptr.p_double[i] = (double)(0); + } + } + v = 0.0; + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = -d->ptr.p_double[i]/h->ptr.p_double[i]; + v = v+ae_sqr(d->ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + if( state->sparsebatchsize+state->densebatchsize>=n ) + { + v = (double)(0); + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = (double)(0); + } + } + if( normalize&&ae_fp_greater(v,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + d->ptr.p_double[i] = d->ptr.p_double[i]/v; + } + } +} + + +/************************************************************************* +This function recalculates constraints - activates and deactivates them +according to gradient value at current point. + +Algorithm assumes that we want to make Quasi-Newton step from current +point with diagonal Quasi-Newton matrix H. Constraints are activated and +deactivated in such way that we won't violate any constraint by step. + +Only already "active" and "candidate" elements of ActiveSet are examined; +constraints which are not active are not examined. + +INPUT PARAMETERS: + State - active set object + GC - array[N], gradient at XC + H - array[N], Hessian matrix + +OUTPUT PARAMETERS: + State - active set object, with new set of constraint + + -- ALGLIB -- + Copyright 26.09.2012 by Bochkanov Sergey +*************************************************************************/ +static void sactivesets_reactivateconstraints(sactiveset* state, + /* Real */ const ae_vector* gc, + /* Real */ const ae_vector* h, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t i; + ae_int_t j; + ae_int_t idx0; + ae_int_t idx1; + double v; + ae_int_t nactivebnd; + ae_int_t nactivelin; + ae_int_t nactiveconstraints; + double rowscale; + + + ae_assert(state->algostate==1, "SASReactivateConstraintsPrec: must be in optimization mode", _state); + + /* + * Prepare + */ + n = state->n; + nec = state->nec; + nic = state->nic; + state->basisisready = ae_false; + + /* + * Handle important special case - no linear constraints, + * only boundary constraints are present + */ + if( nec+nic==0 ) + { + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],(double)(0)) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],(double)(0)) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + state->cstatus.ptr.p_int[i] = -1; + } + return; + } + + /* + * General case. + * Allocate temporaries. + */ + rvectorsetlengthatleast(&state->rctmpg, n, _state); + rvectorsetlengthatleast(&state->rctmprightpart, n, _state); + rvectorsetlengthatleast(&state->rctmps, n, _state); + rmatrixsetlengthatleast(&state->rctmpdense0, n, nec+nic, _state); + rmatrixsetlengthatleast(&state->rctmpdense1, n, nec+nic, _state); + bvectorsetlengthatleast(&state->rctmpisequality, n+nec+nic, _state); + ivectorsetlengthatleast(&state->rctmpconstraintidx, n+nec+nic, _state); + + /* + * Calculate descent direction + */ + ae_v_moveneg(&state->rctmpg.ptr.p_double[0], 1, &gc->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Determine candidates to the active set. + * + * After this block constraints become either "inactive" (CStatus[i]<0) + * or "candidates" (CStatus[i]=0). Previously active constraints always + * become "candidates". + */ + for(i=0; i<=n-1; i++) + { + state->cstatus.ptr.p_int[i] = -1; + } + for(i=n; i<=n+nec+nic-1; i++) + { + if( state->cstatus.ptr.p_int[i]>0 ) + { + state->cstatus.ptr.p_int[i] = 0; + } + else + { + state->cstatus.ptr.p_int[i] = -1; + } + } + nactiveconstraints = 0; + nactivebnd = 0; + nactivelin = 0; + for(i=0; i<=n-1; i++) + { + + /* + * Activate boundary constraints: + * * copy constraint index to RCTmpConstraintIdx + * * set corresponding element of CStatus[] to "candidate" + * * fill RCTmpS by either +1 (lower bound) or -1 (upper bound) + * * set RCTmpIsEquality to False (BndLhasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + + /* + * Equality constraint is activated + */ + state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; + state->cstatus.ptr.p_int[i] = 0; + state->rctmps.ptr.p_double[i] = 1.0; + state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_true; + nactiveconstraints = nactiveconstraints+1; + nactivebnd = nactivebnd+1; + continue; + } + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + + /* + * Lower bound is activated + */ + state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; + state->cstatus.ptr.p_int[i] = 0; + state->rctmps.ptr.p_double[i] = -1.0; + state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; + nactiveconstraints = nactiveconstraints+1; + nactivebnd = nactivebnd+1; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + + /* + * Upper bound is activated + */ + state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = i; + state->cstatus.ptr.p_int[i] = 0; + state->rctmps.ptr.p_double[i] = 1.0; + state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ae_false; + nactiveconstraints = nactiveconstraints+1; + nactivebnd = nactivebnd+1; + continue; + } + } + for(i=0; i<=nec+nic-1; i++) + { + if( i>=nec&&state->cstatus.ptr.p_int[n+i]<0 ) + { + + /* + * Inequality constraints are skipped if both (a) constraint was + * not active, and (b) we are too far away from the boundary. + */ + rowscale = 0.0; + v = -state->cleic.ptr.pp_double[i][n]; + for(j=0; j<=n-1; j++) + { + v = v+state->cleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; + rowscale = ae_maxreal(rowscale, ae_fabs(state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j], _state), _state); + } + if( ae_fp_less_eq(v,-1.0E5*ae_machineepsilon*rowscale) ) + { + + /* + * NOTE: it is important to check for non-strict inequality + * because we have to correctly handle zero constraint + * 0*x<=0 + */ + continue; + } + } + ae_v_move(&state->rctmpdense0.ptr.pp_double[0][nactivelin], state->rctmpdense0.stride, &state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + state->rctmpconstraintidx.ptr.p_int[nactiveconstraints] = n+i; + state->cstatus.ptr.p_int[n+i] = 0; + state->rctmpisequality.ptr.p_bool[nactiveconstraints] = ihasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_greater_eq(gc->ptr.p_double[i],(double)(0)) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_less_eq(gc->ptr.p_double[i],(double)(0)) ) + { + state->cstatus.ptr.p_int[i] = 1; + continue; + } + } + return; + } + + /* + * General case. + * + * APPROACH TO CONSTRAINTS ACTIVATION/DEACTIVATION + * + * We have NActiveConstraints "candidates": NActiveBnd boundary candidates, + * NActiveLin linear candidates. Indexes of boundary constraints are stored + * in RCTmpConstraintIdx[0:NActiveBnd-1], indexes of linear ones are stored + * in RCTmpConstraintIdx[NActiveBnd:NActiveBnd+NActiveLin-1]. Some of the + * constraints are equality ones, some are inequality - as specified by + * RCTmpIsEquality[i]. + * + * Now we have to determine active subset of "candidates" set. In order to + * do so we solve following constrained minimization problem: + * ( )^2 + * min ( SUM(lambda[i]*A[i]) + G ) + * ( ) + * Here: + * * G is a gradient (column vector) + * * A[i] is a column vector, linear (left) part of I-th constraint. + * I=0..NActiveConstraints-1, first NActiveBnd elements of A are just + * subset of identity matrix (boundary constraints), next NActiveLin + * elements are subset of rows of the matrix of general linear constraints. + * * lambda[i] is a Lagrange multiplier corresponding to I-th constraint + * + * NOTE: for preconditioned setting A is replaced by A*H^(-0.5), G is + * replaced by G*H^(-0.5). We apply this scaling at the last stage, + * before passing data to NNLS solver. + * + * Minimization is performed subject to non-negativity constraints on + * lambda[i] corresponding to inequality constraints. Inequality constraints + * which correspond to non-zero lambda are activated, equality constraints + * are always considered active. + * + * Informally speaking, we "decompose" descent direction -G and represent + * it as sum of constraint vectors and "residual" part (which is equal to + * the actual descent direction subject to constraints). + * + * SOLUTION OF THE NNLS PROBLEM + * + * We solve this optimization problem with Non-Negative Least Squares solver, + * which can efficiently solve least squares problems of the form + * + * ( [ I | AU ] )^2 + * min ( [ | ]*x-b ) s.t. non-negativity constraints on some x[i] + * ( [ 0 | AL ] ) + * + * In order to use this solver we have to rearrange rows of A[] and G in + * such way that first NActiveBnd columns of A store identity matrix (before + * sorting non-zero elements are randomly distributed in the first NActiveBnd + * columns of A, during sorting we move them to first NActiveBnd rows). + * + * Then we create instance of NNLS solver (we reuse instance left from the + * previous run of the optimization problem) and solve NNLS problem. + */ + idx0 = 0; + idx1 = nactivebnd; + for(i=0; i<=n-1; i++) + { + if( state->cstatus.ptr.p_int[i]>=0 ) + { + v = (double)1/ae_sqrt(h->ptr.p_double[i], _state); + for(j=0; j<=nactivelin-1; j++) + { + state->rctmpdense1.ptr.pp_double[idx0][j] = state->rctmpdense0.ptr.pp_double[i][j]/state->rctmps.ptr.p_double[i]*v; + } + state->rctmprightpart.ptr.p_double[idx0] = state->rctmpg.ptr.p_double[i]/state->rctmps.ptr.p_double[i]*v; + idx0 = idx0+1; + } + else + { + v = (double)1/ae_sqrt(h->ptr.p_double[i], _state); + for(j=0; j<=nactivelin-1; j++) + { + state->rctmpdense1.ptr.pp_double[idx1][j] = state->rctmpdense0.ptr.pp_double[i][j]*v; + } + state->rctmprightpart.ptr.p_double[idx1] = state->rctmpg.ptr.p_double[i]*v; + idx1 = idx1+1; + } + } + snnlsinit(n, ae_minint(nec+nic, n, _state), n, &state->solver, _state); + snnlssetproblem(&state->solver, &state->rctmpdense1, &state->rctmprightpart, nactivebnd, nactiveconstraints-nactivebnd, n, _state); + for(i=0; i<=nactiveconstraints-1; i++) + { + if( state->rctmpisequality.ptr.p_bool[i] ) + { + snnlsdropnnc(&state->solver, i, _state); + } + } + snnlssolve(&state->solver, &state->rctmplambdas, _state); + + /* + * After solution of the problem we activate equality constraints (always active) + * and inequality constraints with non-zero Lagrange multipliers. Then we reorthogonalize + * active constraints. + */ + for(i=0; i<=n+nec+nic-1; i++) + { + state->cstatus.ptr.p_int[i] = -1; + } + for(i=0; i<=nactiveconstraints-1; i++) + { + if( state->rctmpisequality.ptr.p_bool[i]||ae_fp_greater(state->rctmplambdas.ptr.p_double[i],(double)(0)) ) + { + state->cstatus.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 1; + } + else + { + state->cstatus.ptr.p_int[state->rctmpconstraintidx.ptr.p_int[i]] = 0; + } + } + sasrebuildbasis(state, _state); +} + + +void _sactiveset_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sactiveset *p = (sactiveset*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->h, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cstatus, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->sdensebatch, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->pdensebatch, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->idensebatch, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sparsebatch, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mtnew, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->mtx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mtas, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->cdtmp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->corrtmp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->unitdiagonal, 0, DT_REAL, _state, make_automatic); + _snnlssolver_init(&p->solver, _state, make_automatic); + ae_vector_init(&p->scntmp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpfeas, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpm0, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rctmps, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rctmpg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rctmprightpart, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rctmpdense0, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rctmpdense1, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rctmpisequality, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rctmpconstraintidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rctmplambdas, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpbasis, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpnormestimates, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpreciph, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpprodp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpprods, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpci, 0, DT_REAL, _state, make_automatic); +} + + +void _sactiveset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sactiveset *dst = (sactiveset*)_dst; + const sactiveset *src = (const sactiveset*)_src; + dst->n = src->n; + dst->algostate = src->algostate; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + dst->hasxc = src->hasxc; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->h, &src->h, _state, make_automatic); + ae_vector_init_copy(&dst->cstatus, &src->cstatus, _state, make_automatic); + dst->basisisready = src->basisisready; + ae_matrix_init_copy(&dst->sdensebatch, &src->sdensebatch, _state, make_automatic); + ae_matrix_init_copy(&dst->pdensebatch, &src->pdensebatch, _state, make_automatic); + ae_matrix_init_copy(&dst->idensebatch, &src->idensebatch, _state, make_automatic); + dst->densebatchsize = src->densebatchsize; + ae_vector_init_copy(&dst->sparsebatch, &src->sparsebatch, _state, make_automatic); + dst->sparsebatchsize = src->sparsebatchsize; + dst->basisage = src->basisage; + dst->feasinitpt = src->feasinitpt; + dst->constraintschanged = src->constraintschanged; + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + ae_vector_init_copy(&dst->mtnew, &src->mtnew, _state, make_automatic); + ae_vector_init_copy(&dst->mtx, &src->mtx, _state, make_automatic); + ae_vector_init_copy(&dst->mtas, &src->mtas, _state, make_automatic); + ae_vector_init_copy(&dst->cdtmp, &src->cdtmp, _state, make_automatic); + ae_vector_init_copy(&dst->corrtmp, &src->corrtmp, _state, make_automatic); + ae_vector_init_copy(&dst->unitdiagonal, &src->unitdiagonal, _state, make_automatic); + _snnlssolver_init_copy(&dst->solver, &src->solver, _state, make_automatic); + ae_vector_init_copy(&dst->scntmp, &src->scntmp, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpfeas, &src->tmpfeas, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpm0, &src->tmpm0, _state, make_automatic); + ae_vector_init_copy(&dst->rctmps, &src->rctmps, _state, make_automatic); + ae_vector_init_copy(&dst->rctmpg, &src->rctmpg, _state, make_automatic); + ae_vector_init_copy(&dst->rctmprightpart, &src->rctmprightpart, _state, make_automatic); + ae_matrix_init_copy(&dst->rctmpdense0, &src->rctmpdense0, _state, make_automatic); + ae_matrix_init_copy(&dst->rctmpdense1, &src->rctmpdense1, _state, make_automatic); + ae_vector_init_copy(&dst->rctmpisequality, &src->rctmpisequality, _state, make_automatic); + ae_vector_init_copy(&dst->rctmpconstraintidx, &src->rctmpconstraintidx, _state, make_automatic); + ae_vector_init_copy(&dst->rctmplambdas, &src->rctmplambdas, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpbasis, &src->tmpbasis, _state, make_automatic); + ae_vector_init_copy(&dst->tmpnormestimates, &src->tmpnormestimates, _state, make_automatic); + ae_vector_init_copy(&dst->tmpreciph, &src->tmpreciph, _state, make_automatic); + ae_vector_init_copy(&dst->tmpprodp, &src->tmpprodp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpprods, &src->tmpprods, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcp, &src->tmpcp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcs, &src->tmpcs, _state, make_automatic); + ae_vector_init_copy(&dst->tmpci, &src->tmpci, _state, make_automatic); +} + + +void _sactiveset_clear(void* _p) +{ + sactiveset *p = (sactiveset*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->s); + ae_vector_clear(&p->h); + ae_vector_clear(&p->cstatus); + ae_matrix_clear(&p->sdensebatch); + ae_matrix_clear(&p->pdensebatch); + ae_matrix_clear(&p->idensebatch); + ae_vector_clear(&p->sparsebatch); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->mtnew); + ae_vector_clear(&p->mtx); + ae_vector_clear(&p->mtas); + ae_vector_clear(&p->cdtmp); + ae_vector_clear(&p->corrtmp); + ae_vector_clear(&p->unitdiagonal); + _snnlssolver_clear(&p->solver); + ae_vector_clear(&p->scntmp); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmpfeas); + ae_matrix_clear(&p->tmpm0); + ae_vector_clear(&p->rctmps); + ae_vector_clear(&p->rctmpg); + ae_vector_clear(&p->rctmprightpart); + ae_matrix_clear(&p->rctmpdense0); + ae_matrix_clear(&p->rctmpdense1); + ae_vector_clear(&p->rctmpisequality); + ae_vector_clear(&p->rctmpconstraintidx); + ae_vector_clear(&p->rctmplambdas); + ae_matrix_clear(&p->tmpbasis); + ae_vector_clear(&p->tmpnormestimates); + ae_vector_clear(&p->tmpreciph); + ae_vector_clear(&p->tmpprodp); + ae_vector_clear(&p->tmpprods); + ae_vector_clear(&p->tmpcp); + ae_vector_clear(&p->tmpcs); + ae_vector_clear(&p->tmpci); +} + + +void _sactiveset_destroy(void* _p) +{ + sactiveset *p = (sactiveset*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->h); + ae_vector_destroy(&p->cstatus); + ae_matrix_destroy(&p->sdensebatch); + ae_matrix_destroy(&p->pdensebatch); + ae_matrix_destroy(&p->idensebatch); + ae_vector_destroy(&p->sparsebatch); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->mtnew); + ae_vector_destroy(&p->mtx); + ae_vector_destroy(&p->mtas); + ae_vector_destroy(&p->cdtmp); + ae_vector_destroy(&p->corrtmp); + ae_vector_destroy(&p->unitdiagonal); + _snnlssolver_destroy(&p->solver); + ae_vector_destroy(&p->scntmp); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmpfeas); + ae_matrix_destroy(&p->tmpm0); + ae_vector_destroy(&p->rctmps); + ae_vector_destroy(&p->rctmpg); + ae_vector_destroy(&p->rctmprightpart); + ae_matrix_destroy(&p->rctmpdense0); + ae_matrix_destroy(&p->rctmpdense1); + ae_vector_destroy(&p->rctmpisequality); + ae_vector_destroy(&p->rctmpconstraintidx); + ae_vector_destroy(&p->rctmplambdas); + ae_matrix_destroy(&p->tmpbasis); + ae_vector_destroy(&p->tmpnormestimates); + ae_vector_destroy(&p->tmpreciph); + ae_vector_destroy(&p->tmpprodp); + ae_vector_destroy(&p->tmpprods); + ae_vector_destroy(&p->tmpcp); + ae_vector_destroy(&p->tmpcs); + ae_vector_destroy(&p->tmpci); +} + + +#endif +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes QQPSettings structure with default settings. + +Newly created structure MUST be initialized by default settings - or by +copy of the already initialized structure. + + -- ALGLIB -- + Copyright 14.05.2011 by Bochkanov Sergey +*************************************************************************/ +void qqploaddefaults(ae_int_t n, qqpsettings* s, ae_state *_state) +{ + + + s->epsg = 0.0; + s->epsf = 0.0; + s->epsx = 1.0E-6; + s->maxouterits = 0; + s->cgphase = ae_true; + s->cnphase = ae_true; + s->cgminits = 5; + s->cgmaxits = ae_maxint(s->cgminits, ae_round((double)1+0.33*(double)n, _state), _state); + s->sparsesolver = 0; + s->cnmaxupdates = ae_round((double)1+0.1*(double)n, _state); +} + + +/************************************************************************* +This function initializes QQPSettings structure with copy of another, +already initialized structure. + + -- ALGLIB -- + Copyright 14.05.2011 by Bochkanov Sergey +*************************************************************************/ +void qqpcopysettings(const qqpsettings* src, + qqpsettings* dst, + ae_state *_state) +{ + + + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxouterits = src->maxouterits; + dst->cgphase = src->cgphase; + dst->cnphase = src->cnphase; + dst->cgminits = src->cgminits; + dst->cgmaxits = src->cgmaxits; + dst->sparsesolver = src->sparsesolver; + dst->cnmaxupdates = src->cnmaxupdates; +} + + +/************************************************************************* +This function performs preallocation of internal 2D matrices. If matrix +size is less than expected, we grow to some larger value (specified by user). + +It can be useful in cases when we solve many subsequent QP problems with +increasing sizes - helps to avoid multiple allocations. + +INPUT PARAMETERS: + SState - object which stores temporaries: + * uninitialized object is automatically initialized + * previously allocated memory is reused as much + as possible + NExpected - if internal buffers have size enough for NExpected, + no preallocation happens. If size is less than NExpected, + buffers are preallocated up to NGrowTo*NGrowTo + NGrowTo - new size + + +OUTPUT PARAMETERS: + SState - temporary buffers, some of them are preallocated + + -- ALGLIB -- + Copyright 09.10.2017 by Bochkanov Sergey +*************************************************************************/ +void qqppreallocategrowdense(qqpbuffers* sstate, + ae_int_t nexpected, + ae_int_t ngrowto, + ae_state *_state) +{ + + + if( sstate->densea.rowsdensea.colsdensea, ngrowto, ngrowto, _state); + } + if( sstate->densez.rowsdensez.colsdensez, ngrowto, ngrowto, _state); + } +} + + +/************************************************************************* +This function runs QQP solver; it returns after optimization process was +completed. Following QP problem is solved: + + min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + +subject to boundary constraints. + +IMPORTANT: UNLIKE MANY OTHER SOLVERS, THIS FUNCTION DOES NOT REQUIRE YOU + TO INITIALIZE STATE OBJECT. IT CAN BE AUTOMATICALLY INITIALIZED + DURING SOLUTION PROCESS. + +INPUT PARAMETERS: + AC - for dense problems given by CQM model (AKind=0) A-term + of CQM object contains system matrix. Other terms are + unspecified and should not be referenced. + SparseAC - for sparse problems (AKind=1) + DenseAC - for traditional dense matrices (AKind=2) + AKind - matrix term to use: + * 0 for dense CQM (CQMAC) + * 1 for sparse matrix (SparseAC) + * 2 for dense matrix (DenseAC) + IsUpper - which triangle of SparseAC/DenseAC stores matrix - + upper or lower one (for dense matrices this parameter + is not actual). + BC - linear term, array[NC] + BndLC - lower bound, array[NC] + BndUC - upper bound, array[NC] + SC - scale vector, array[NC]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOriginC - origin term, array[NC]. Can be zero. + NC - number of variables in the original formulation (no + slack variables). + CLEICC - linear equality/inequality constraints. Present version + of this function does NOT provide publicly available + support for linear constraints. This feature will be + introduced in the future versions of the function. + NEC, NIC - number of equality/inequality constraints. + MUST BE ZERO IN THE CURRENT VERSION!!! + Settings - QQPSettings object initialized by one of the initialization + functions. + SState - object which stores temporaries: + * uninitialized object is automatically initialized + * previously allocated memory is reused as much + as possible + XS - initial point, array[NC] + + +OUTPUT PARAMETERS: + XS - last point + TerminationType-termination type: + * + * + * + + -- ALGLIB -- + Copyright 14.05.2011 by Bochkanov Sergey +*************************************************************************/ +void qqpoptimize(const convexquadraticmodel* cqmac, + const sparsematrix* sparseac, + /* Real */ const ae_matrix* denseac, + ae_int_t akind, + ae_bool isupper, + /* Real */ const ae_vector* bc, + /* Real */ const ae_vector* bndlc, + /* Real */ const ae_vector* bnduc, + /* Real */ const ae_vector* sc, + /* Real */ const ae_vector* xoriginc, + ae_int_t nc, + const qqpsettings* settings, + qqpbuffers* sstate, + /* Real */ ae_vector* xs, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double d2; + double d1; + ae_int_t d1est; + ae_int_t d2est; + ae_bool needact; + double reststp; + double fullstp; + double stpmax; + double stp; + ae_int_t stpcnt; + ae_int_t cidx; + double cval; + ae_int_t cgcnt; + ae_int_t cgmax; + ae_int_t newtcnt; + ae_int_t sparsesolver; + double beta; + ae_bool b; + double fprev; + double fcur; + ae_bool problemsolved; + ae_bool isconstrained; + double f0; + double f1; + + *terminationtype = 0; + + + /* + * Primary checks + */ + ae_assert((akind==0||akind==1)||akind==2, "QQPOptimize: incorrect AKind", _state); + sstate->n = nc; + n = sstate->n; + *terminationtype = 0; + sstate->repinneriterationscount = 0; + sstate->repouteriterationscount = 0; + sstate->repncholesky = 0; + sstate->repncupdates = 0; + + /* + * Several checks + * * matrix size + * * scale vector + * * consistency of bound constraints + * * consistency of settings + */ + if( akind==1 ) + { + ae_assert(sparsegetnrows(sparseac, _state)==n, "QQPOptimize: rows(SparseAC)<>N", _state); + ae_assert(sparsegetncols(sparseac, _state)==n, "QQPOptimize: cols(SparseAC)<>N", _state); + } + for(i=0; i<=n-1; i++) + { + ae_assert(ae_isfinite(sc->ptr.p_double[i], _state)&&ae_fp_greater(sc->ptr.p_double[i],(double)(0)), "QQPOptimize: incorrect scale", _state); + } + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(bndlc->ptr.p_double[i], _state)&&ae_isfinite(bnduc->ptr.p_double[i], _state) ) + { + if( ae_fp_greater(bndlc->ptr.p_double[i],bnduc->ptr.p_double[i]) ) + { + *terminationtype = -3; + return; + } + } + } + ae_assert(settings->cgphase||settings->cnphase, "QQPOptimize: both phases (CG and Newton) are inactive", _state); + + /* + * Allocate data structures + */ + rvectorsetlengthatleast(&sstate->bndl, n, _state); + rvectorsetlengthatleast(&sstate->bndu, n, _state); + bvectorsetlengthatleast(&sstate->havebndl, n, _state); + bvectorsetlengthatleast(&sstate->havebndu, n, _state); + rvectorsetlengthatleast(&sstate->xs, n, _state); + rvectorsetlengthatleast(&sstate->xf, n, _state); + rvectorsetlengthatleast(&sstate->xp, n, _state); + rvectorsetlengthatleast(&sstate->gc, n, _state); + rvectorsetlengthatleast(&sstate->cgc, n, _state); + rvectorsetlengthatleast(&sstate->cgp, n, _state); + rvectorsetlengthatleast(&sstate->dc, n, _state); + rvectorsetlengthatleast(&sstate->dp, n, _state); + rvectorsetlengthatleast(&sstate->tmp0, n, _state); + rvectorsetlengthatleast(&sstate->tmp1, n, _state); + rvectorsetlengthatleast(&sstate->stpbuf, 15, _state); + sasinit(n, &sstate->sas, _state); + + /* + * Scale/shift problem coefficients: + * + * min { 0.5*(x-x0)'*A*(x-x0) + b'*(x-x0) } + * + * becomes (after transformation "x = S*y+x0") + * + * min { 0.5*y'*(S*A*S)*y + (S*b)'*y + * + * Modified A_mod=S*A*S and b_mod=S*(b+A*x0) are + * stored into SState.DenseA and SState.B. + * + */ + rvectorsetlengthatleast(&sstate->b, n, _state); + for(i=0; i<=n-1; i++) + { + sstate->b.ptr.p_double[i] = sc->ptr.p_double[i]*bc->ptr.p_double[i]; + } + sstate->akind = -99; + if( akind==0 ) + { + + /* + * Dense QP problem - just copy and scale. + */ + rmatrixsetlengthatleast(&sstate->densea, n, n, _state); + cqmgeta(cqmac, &sstate->densea, _state); + sstate->akind = 0; + sstate->absamax = (double)(0); + sstate->absasum = (double)(0); + sstate->absasum2 = (double)(0); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = sc->ptr.p_double[i]*sstate->densea.ptr.pp_double[i][j]*sc->ptr.p_double[j]; + vv = ae_fabs(v, _state); + sstate->densea.ptr.pp_double[i][j] = v; + sstate->absamax = ae_maxreal(sstate->absamax, vv, _state); + sstate->absasum = sstate->absasum+vv; + sstate->absasum2 = sstate->absasum2+vv*vv; + } + } + } + if( akind==1 ) + { + + /* + * Sparse QP problem - a bit tricky. Depending on format of the + * input we use different strategies for copying matrix: + * * SKS matrices are copied to SKS format + * * anything else is copied to CRS format + */ + sparsecopytosksbuf(sparseac, &sstate->sparsea, _state); + if( isupper ) + { + sparsetransposesks(&sstate->sparsea, _state); + } + sstate->akind = 1; + sstate->sparseupper = ae_false; + sstate->absamax = (double)(0); + sstate->absasum = (double)(0); + sstate->absasum2 = (double)(0); + for(i=0; i<=n-1; i++) + { + k = sstate->sparsea.ridx.ptr.p_int[i]; + for(j=i-sstate->sparsea.didx.ptr.p_int[i]; j<=i; j++) + { + v = sc->ptr.p_double[i]*sstate->sparsea.vals.ptr.p_double[k]*sc->ptr.p_double[j]; + vv = ae_fabs(v, _state); + sstate->sparsea.vals.ptr.p_double[k] = v; + if( i==j ) + { + + /* + * Diagonal terms are counted only once + */ + sstate->absamax = ae_maxreal(sstate->absamax, vv, _state); + sstate->absasum = sstate->absasum+vv; + sstate->absasum2 = sstate->absasum2+vv*vv; + } + else + { + + /* + * Offdiagonal terms are counted twice + */ + sstate->absamax = ae_maxreal(sstate->absamax, vv, _state); + sstate->absasum = sstate->absasum+(double)2*vv; + sstate->absasum2 = sstate->absasum2+(double)2*vv*vv; + } + k = k+1; + } + } + } + if( akind==2 ) + { + + /* + * Dense QP problem - just copy and scale. + */ + rmatrixsetlengthatleast(&sstate->densea, n, n, _state); + sstate->akind = 0; + sstate->absamax = (double)(0); + sstate->absasum = (double)(0); + sstate->absasum2 = (double)(0); + if( isupper ) + { + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + v = sc->ptr.p_double[i]*denseac->ptr.pp_double[i][j]*sc->ptr.p_double[j]; + vv = ae_fabs(v, _state); + sstate->densea.ptr.pp_double[i][j] = v; + sstate->densea.ptr.pp_double[j][i] = v; + if( ae_fp_eq((double)(i),v) ) + { + k = 1; + } + else + { + k = 2; + } + sstate->absamax = ae_maxreal(sstate->absamax, vv, _state); + sstate->absasum = sstate->absasum+vv*(double)k; + sstate->absasum2 = sstate->absasum2+vv*vv*(double)k; + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=i; j++) + { + v = sc->ptr.p_double[i]*denseac->ptr.pp_double[i][j]*sc->ptr.p_double[j]; + vv = ae_fabs(v, _state); + sstate->densea.ptr.pp_double[i][j] = v; + sstate->densea.ptr.pp_double[j][i] = v; + if( ae_fp_eq((double)(i),v) ) + { + k = 1; + } + else + { + k = 2; + } + sstate->absamax = ae_maxreal(sstate->absamax, vv, _state); + sstate->absasum = sstate->absasum+vv*(double)k; + sstate->absasum2 = sstate->absasum2+vv*vv*(double)k; + } + } + } + } + ae_assert(sstate->akind>=0, "QQP: integrity check failed", _state); + + /* + * Load box constraints into State structure. + * + * We apply transformation to variables: y=(x-x_origin)/s, + * each of the constraints is appropriately shifted/scaled. + */ + for(i=0; i<=n-1; i++) + { + sstate->havebndl.ptr.p_bool[i] = ae_isfinite(bndlc->ptr.p_double[i], _state); + if( sstate->havebndl.ptr.p_bool[i] ) + { + sstate->bndl.ptr.p_double[i] = (bndlc->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; + } + else + { + ae_assert(ae_isneginf(bndlc->ptr.p_double[i], _state), "QQPOptimize: incorrect lower bound", _state); + sstate->bndl.ptr.p_double[i] = _state->v_neginf; + } + sstate->havebndu.ptr.p_bool[i] = ae_isfinite(bnduc->ptr.p_double[i], _state); + if( sstate->havebndu.ptr.p_bool[i] ) + { + sstate->bndu.ptr.p_double[i] = (bnduc->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; + } + else + { + ae_assert(ae_isposinf(bnduc->ptr.p_double[i], _state), "QQPOptimize: incorrect upper bound", _state); + sstate->bndu.ptr.p_double[i] = _state->v_posinf; + } + } + + /* + * Process initial point: + * * set it to XS-XOriginC + * * make sure that boundary constraints are preserved by transformation + */ + for(i=0; i<=n-1; i++) + { + sstate->xs.ptr.p_double[i] = (xs->ptr.p_double[i]-xoriginc->ptr.p_double[i])/sc->ptr.p_double[i]; + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(sstate->xs.ptr.p_double[i],sstate->bndl.ptr.p_double[i]) ) + { + sstate->xs.ptr.p_double[i] = sstate->bndl.ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(sstate->xs.ptr.p_double[i],sstate->bndu.ptr.p_double[i]) ) + { + sstate->xs.ptr.p_double[i] = sstate->bndu.ptr.p_double[i]; + } + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(xs->ptr.p_double[i],bndlc->ptr.p_double[i]) ) + { + sstate->xs.ptr.p_double[i] = sstate->bndl.ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(xs->ptr.p_double[i],bnduc->ptr.p_double[i]) ) + { + sstate->xs.ptr.p_double[i] = sstate->bndu.ptr.p_double[i]; + } + } + + /* + * Select sparse direct solver + */ + if( akind==1 ) + { + sparsesolver = settings->sparsesolver; + if( sparsesolver==0 ) + { + sparsesolver = 1; + } + if( sparseissks(&sstate->sparsea, _state) ) + { + sparsesolver = 2; + } + sparsesolver = 2; + ae_assert(sparsesolver==1||sparsesolver==2, "QQPOptimize: incorrect SparseSolver", _state); + } + else + { + sparsesolver = 0; + } + + /* + * For unconstrained problems - try to use fast approach which requires + * just one unregularized Cholesky decomposition for solution. If it fails, + * switch to general QQP code. + */ + problemsolved = ae_false; + isconstrained = ae_false; + for(i=0; i<=n-1; i++) + { + isconstrained = (isconstrained||sstate->havebndl.ptr.p_bool[i])||sstate->havebndu.ptr.p_bool[i]; + } + if( (!isconstrained&&settings->cnphase)&&akind==0 ) + { + rmatrixsetlengthatleast(&sstate->densez, n, n, _state); + rvectorsetlengthatleast(&sstate->tmpcn, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + sstate->densez.ptr.pp_double[i][j] = sstate->densea.ptr.pp_double[i][j]; + } + } + inc(&sstate->repncholesky, _state); + if( spdmatrixcholeskyrec(&sstate->densez, 0, n, ae_true, &sstate->tmpcn, _state) ) + { + ae_v_move(&sstate->xf.ptr.p_double[0], 1, &sstate->xs.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + sstate->dc.ptr.p_double[i] = (double)(0); + } + f0 = qqpsolver_projectedtargetfunction(sstate, &sstate->xf, &sstate->dc, 0.0, &sstate->tmpcn, &sstate->tmp1, _state); + for(k=0; k<=3; k++) + { + rmatrixmv(n, n, &sstate->densea, 0, 0, 0, &sstate->xf, 0, &sstate->gc, 0, _state); + ae_v_add(&sstate->gc.ptr.p_double[0], 1, &sstate->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + sstate->dc.ptr.p_double[i] = -sstate->gc.ptr.p_double[i]; + } + fblscholeskysolve(&sstate->densez, 1.0, n, ae_true, &sstate->dc, &sstate->tmpcn, _state); + f1 = qqpsolver_projectedtargetfunction(sstate, &sstate->xf, &sstate->dc, 1.0, &sstate->tmpcn, &sstate->tmp1, _state); + if( ae_fp_greater_eq(f1,f0) ) + { + break; + } + ae_v_add(&sstate->xf.ptr.p_double[0], 1, &sstate->dc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + f0 = f1; + } + *terminationtype = 2; + problemsolved = ae_true; + } + } + + /* + * Attempt to solve problem with fast approach failed, use generic QQP + */ + if( !problemsolved ) + { + + /* + * Prepare "active set" structure + */ + sassetbc(&sstate->sas, &sstate->bndl, &sstate->bndu, _state); + if( !sasstartoptimization(&sstate->sas, &sstate->xs, _state) ) + { + *terminationtype = -3; + return; + } + + /* + * Main loop. + * + * Following variables are used: + * * GC stores current gradient (unconstrained) + * * CGC stores current gradient (constrained) + * * DC stores current search direction + * * CGP stores constrained gradient at previous point + * (zero on initial entry) + * * DP stores previous search direction + * (zero on initial entry) + */ + cgmax = settings->cgminits; + sstate->repinneriterationscount = 0; + sstate->repouteriterationscount = 0; + for(;;) + { + if( settings->maxouterits>0&&sstate->repouteriterationscount>=settings->maxouterits ) + { + *terminationtype = 5; + break; + } + if( sstate->repouteriterationscount>0 ) + { + + /* + * Check EpsF- and EpsX-based stopping criteria. + * Because problem was already scaled, we do not scale step before checking its length. + * NOTE: these checks are performed only after at least one outer iteration was made. + */ + if( ae_fp_greater(settings->epsf,(double)(0)) ) + { + + /* + * NOTE 1: here we rely on the fact that ProjectedTargetFunction() ignore D when Stp=0 + * NOTE 2: code below handles situation when update increases function value instead + * of decreasing it. + */ + fprev = qqpsolver_projectedtargetfunction(sstate, &sstate->xp, &sstate->dc, 0.0, &sstate->tmp0, &sstate->tmp1, _state); + fcur = qqpsolver_projectedtargetfunction(sstate, &sstate->sas.xc, &sstate->dc, 0.0, &sstate->tmp0, &sstate->tmp1, _state); + if( ae_fp_less_eq(fprev-fcur,settings->epsf*ae_maxreal(ae_fabs(fprev, _state), ae_maxreal(ae_fabs(fcur, _state), 1.0, _state), _state)) ) + { + *terminationtype = 1; + break; + } + } + if( ae_fp_greater(settings->epsx,(double)(0)) ) + { + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(sstate->xp.ptr.p_double[i]-sstate->sas.xc.ptr.p_double[i], _state); + } + if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsx) ) + { + *terminationtype = 2; + break; + } + } + } + inc(&sstate->repouteriterationscount, _state); + ae_v_move(&sstate->xp.ptr.p_double[0], 1, &sstate->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( !settings->cgphase ) + { + cgmax = 0; + } + for(i=0; i<=n-1; i++) + { + sstate->cgp.ptr.p_double[i] = 0.0; + sstate->dp.ptr.p_double[i] = 0.0; + } + for(cgcnt=0; cgcnt<=cgmax-1; cgcnt++) + { + + /* + * Calculate unconstrained gradient GC for "extended" QP problem + * Determine active set, current constrained gradient CGC. + * Check gradient-based stopping condition. + * + * NOTE: because problem was scaled, we do not have to apply scaling + * to gradient before checking stopping condition. + */ + qqpsolver_targetgradient(sstate, &sstate->sas.xc, &sstate->gc, _state); + sasreactivateconstraints(&sstate->sas, &sstate->gc, _state); + ae_v_move(&sstate->cgc.ptr.p_double[0], 1, &sstate->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + sasconstraineddirection(&sstate->sas, &sstate->cgc, _state); + v = ae_v_dotproduct(&sstate->cgc.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsg) ) + { + *terminationtype = 4; + break; + } + + /* + * Prepare search direction DC and explore it. + * + * We try to use CGP/DP to prepare conjugate gradient step, + * but we resort to steepest descent step (Beta=0) in case + * we are at I-th boundary, but DP[I]<>0. + * + * Such approach allows us to ALWAYS have feasible DC, with + * guaranteed compatibility with both feasible area and current + * active set. + * + * Automatic CG reset performed every time DP is incompatible + * with current active set and/or feasible area. We also + * perform reset every QuickQPRestartCG iterations. + */ + ae_v_moveneg(&sstate->dc.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = 0.0; + vv = 0.0; + b = ae_false; + for(i=0; i<=n-1; i++) + { + v = v+sstate->cgc.ptr.p_double[i]*sstate->cgc.ptr.p_double[i]; + vv = vv+sstate->cgp.ptr.p_double[i]*sstate->cgp.ptr.p_double[i]; + b = b||((sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]))&&ae_fp_neq(sstate->dp.ptr.p_double[i],(double)(0))); + b = b||((sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]))&&ae_fp_neq(sstate->dp.ptr.p_double[i],(double)(0))); + } + b = b||ae_fp_eq(vv,(double)(0)); + b = b||cgcnt%qqpsolver_quickqprestartcg==0; + if( !b ) + { + beta = v/vv; + } + else + { + beta = 0.0; + } + ae_v_addd(&sstate->dc.ptr.p_double[0], 1, &sstate->dp.ptr.p_double[0], 1, ae_v_len(0,n-1), beta); + sasconstraineddirection(&sstate->sas, &sstate->dc, _state); + sasexploredirection(&sstate->sas, &sstate->dc, &stpmax, &cidx, &cval, _state); + + /* + * Build quadratic model of F along descent direction: + * + * F(xc+alpha*D) = D2*alpha^2 + D1*alpha + * + * Terminate algorithm if needed. + * + * NOTE: we do not maintain constant term D0 + */ + qqpsolver_quadraticmodel(sstate, &sstate->sas.xc, &sstate->dc, &sstate->gc, &d1, &d1est, &d2, &d2est, &sstate->tmp0, _state); + if( ae_fp_eq(d1,(double)(0))&&ae_fp_eq(d2,(double)(0)) ) + { + + /* + * D1 and D2 are exactly zero, success. + * After this if-then we assume that D is non-zero. + */ + *terminationtype = 4; + break; + } + if( d1est>=0 ) + { + + /* + * Numerical noise is too large, it means that we are close + * to minimum - and that further improvement is impossible. + * + * After this if-then we assume that D1 is definitely negative + * (even under presence of numerical errors). + */ + *terminationtype = 7; + break; + } + if( d2est<=0&&cidx<0 ) + { + + /* + * Function is unbounded from below: + * * D1<0 (verified by previous block) + * * D2Est<=0, which means that either D2<0 - or it can not + * be reliably distinguished from zero. + * * step is unconstrained + * + * If these conditions are true, we abnormally terminate QP + * algorithm with return code -4 + */ + *terminationtype = -4; + break; + } + + /* + * Perform step along DC. + * + * In this block of code we maintain two step length: + * * RestStp - restricted step, maximum step length along DC which does + * not violate constraints + * * FullStp - step length along DC which minimizes quadratic function + * without taking constraints into account. If problem is + * unbounded from below without constraints, FullStp is + * forced to be RestStp. + * + * So, if function is convex (D2>0): + * * FullStp = -D1/(2*D2) + * * RestStp = restricted FullStp + * * 0<=RestStp<=FullStp + * + * If function is non-convex, but bounded from below under constraints: + * * RestStp = step length subject to constraints + * * FullStp = RestStp + * + * After RestStp and FullStp are initialized, we generate several trial + * steps which are different multiples of RestStp and FullStp. + */ + if( d2est>0 ) + { + ae_assert(ae_fp_less(d1,(double)(0)), "QQPOptimize: internal error", _state); + fullstp = -d1/((double)2*d2); + needact = ae_fp_greater_eq(fullstp,stpmax); + if( needact ) + { + ae_assert(sstate->stpbuf.cnt>=3, "QQPOptimize: StpBuf overflow", _state); + reststp = stpmax; + stp = reststp; + sstate->stpbuf.ptr.p_double[0] = reststp*(double)4; + sstate->stpbuf.ptr.p_double[1] = fullstp; + sstate->stpbuf.ptr.p_double[2] = fullstp/(double)4; + stpcnt = 3; + } + else + { + reststp = fullstp; + stp = fullstp; + stpcnt = 0; + } + } + else + { + ae_assert(cidx>=0, "QQPOptimize: internal error", _state); + ae_assert(sstate->stpbuf.cnt>=2, "QQPOptimize: StpBuf overflow", _state); + reststp = stpmax; + fullstp = stpmax; + stp = reststp; + needact = ae_true; + sstate->stpbuf.ptr.p_double[0] = (double)4*reststp; + stpcnt = 1; + } + qqpsolver_findbeststepandmove(sstate, &sstate->sas, &sstate->dc, stp, needact, cidx, cval, &sstate->stpbuf, stpcnt, &sstate->activated, &sstate->tmp0, &sstate->tmp1, _state); + + /* + * Update CG information. + */ + ae_v_move(&sstate->dp.ptr.p_double[0], 1, &sstate->dc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&sstate->cgp.ptr.p_double[0], 1, &sstate->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Update iterations counter + */ + sstate->repinneriterationscount = sstate->repinneriterationscount+1; + } + if( *terminationtype!=0 ) + { + break; + } + cgmax = settings->cgmaxits; + + /* + * Generate YIdx - reordering of variables for constrained Newton phase. + * Free variables come first, fixed are last ones. + */ + newtcnt = 0; + for(;;) + { + + /* + * Skip iteration if constrained Newton is turned off. + */ + if( !settings->cnphase ) + { + break; + } + + /* + * At the first iteration - build Cholesky decomposition of Hessian. + * At subsequent iterations - refine Hessian by adding new constraints. + * + * Loop is terminated in following cases: + * * Hessian is not positive definite subject to current constraints + * (termination during initial decomposition) + * * there were no new constraints being activated + * (termination during update) + * * all constraints were activated during last step + * (termination during update) + * * CNMaxUpdates were performed on matrix + * (termination during update) + */ + if( newtcnt==0 ) + { + + /* + * Perform initial Newton step. If Cholesky decomposition fails, + * increase number of CG iterations to CGMaxIts - it should help + * us to find set of constraints which will make matrix positive + * definite. + */ + b = qqpsolver_cnewtonbuild(sstate, sparsesolver, &sstate->repncholesky, _state); + if( b ) + { + cgmax = settings->cgminits; + } + } + else + { + b = qqpsolver_cnewtonupdate(sstate, settings, &sstate->repncupdates, _state); + } + if( !b ) + { + break; + } + inc(&newtcnt, _state); + + /* + * Calculate gradient GC. + */ + qqpsolver_targetgradient(sstate, &sstate->sas.xc, &sstate->gc, _state); + + /* + * Bound-constrained Newton step + */ + for(i=0; i<=n-1; i++) + { + sstate->dc.ptr.p_double[i] = sstate->gc.ptr.p_double[i]; + } + if( !qqpsolver_cnewtonstep(sstate, settings, &sstate->dc, _state) ) + { + break; + } + qqpsolver_quadraticmodel(sstate, &sstate->sas.xc, &sstate->dc, &sstate->gc, &d1, &d1est, &d2, &d2est, &sstate->tmp0, _state); + if( d1est>=0 ) + { + + /* + * We are close to minimum, derivative is nearly zero, break Newton iteration + */ + break; + } + if( d2est>0 ) + { + + /* + * Positive definite matrix, we can perform Newton step + */ + ae_assert(ae_fp_less(d1,(double)(0)), "QQPOptimize: internal error", _state); + fullstp = -d1/((double)2*d2); + sasexploredirection(&sstate->sas, &sstate->dc, &stpmax, &cidx, &cval, _state); + needact = ae_fp_greater_eq(fullstp,stpmax); + if( needact ) + { + ae_assert(sstate->stpbuf.cnt>=3, "QQPOptimize: StpBuf overflow", _state); + reststp = stpmax; + stp = reststp; + sstate->stpbuf.ptr.p_double[0] = reststp*(double)4; + sstate->stpbuf.ptr.p_double[1] = fullstp; + sstate->stpbuf.ptr.p_double[2] = fullstp/(double)4; + stpcnt = 3; + } + else + { + reststp = fullstp; + stp = fullstp; + stpcnt = 0; + } + qqpsolver_findbeststepandmove(sstate, &sstate->sas, &sstate->dc, stp, needact, cidx, cval, &sstate->stpbuf, stpcnt, &sstate->activated, &sstate->tmp0, &sstate->tmp1, _state); + } + else + { + + /* + * Matrix is semi-definite or indefinite, but regularized + * Cholesky succeeded and gave us descent direction in DC. + * + * We will investigate it and try to perform descent step: + * * first, we explore direction: + * * if it is unbounded, we stop algorithm with + * appropriate termination code -4. + * * if StpMax=0, we break Newton phase and return to + * CG phase - constraint geometry is complicated near + * current point, so it is better to use simpler algo. + * * second, we check that bounded step decreases function; + * if not, we again skip to CG phase + * * finally, we use FindBestStep...() function to choose + * between bounded step and projection of full-length step + * (latter may give additional decrease in + */ + sasexploredirection(&sstate->sas, &sstate->dc, &stpmax, &cidx, &cval, _state); + if( cidx<0 ) + { + + /* + * Function is unbounded from below: + * * D1<0 (verified by previous block) + * * D2Est<=0, which means that either D2<0 - or it can not + * be reliably distinguished from zero. + * * step is unconstrained + * + * If these conditions are true, we abnormally terminate QP + * algorithm with return code -4 + */ + *terminationtype = -4; + break; + } + if( ae_fp_eq(stpmax,(double)(0)) ) + { + + /* + * Resort to CG phase. + * Increase number of CG iterations. + */ + cgmax = settings->cgmaxits; + break; + } + ae_assert(ae_fp_greater(stpmax,(double)(0)), "QQPOptimize: internal error", _state); + f0 = qqpsolver_projectedtargetfunction(sstate, &sstate->sas.xc, &sstate->dc, 0.0, &sstate->tmp0, &sstate->tmp1, _state); + f1 = qqpsolver_projectedtargetfunction(sstate, &sstate->sas.xc, &sstate->dc, stpmax, &sstate->tmp0, &sstate->tmp1, _state); + if( ae_fp_greater_eq(f1,f0) ) + { + + /* + * Descent direction does not actually decrease function value. + * Resort to CG phase + * Increase number of CG iterations. + */ + cgmax = settings->cgmaxits; + break; + } + ae_assert(sstate->stpbuf.cnt>=3, "QQPOptimize: StpBuf overflow", _state); + reststp = stpmax; + stp = reststp; + sstate->stpbuf.ptr.p_double[0] = reststp*(double)4; + sstate->stpbuf.ptr.p_double[1] = 1.00; + sstate->stpbuf.ptr.p_double[2] = 0.25; + stpcnt = 3; + qqpsolver_findbeststepandmove(sstate, &sstate->sas, &sstate->dc, stp, ae_true, cidx, cval, &sstate->stpbuf, stpcnt, &sstate->activated, &sstate->tmp0, &sstate->tmp1, _state); + } + } + if( *terminationtype!=0 ) + { + break; + } + } + sasstopoptimization(&sstate->sas, _state); + ae_v_move(&sstate->xf.ptr.p_double[0], 1, &sstate->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + } + + /* + * Stop optimization and unpack results. + * + * Add XOriginC to XS and make sure that boundary constraints are + * both (a) satisfied, (b) preserved. Former means that "shifted" + * point is feasible, while latter means that point which was exactly + * at the boundary before shift will be exactly at the boundary + * after shift. + */ + for(i=0; i<=n-1; i++) + { + xs->ptr.p_double[i] = sc->ptr.p_double[i]*sstate->xf.ptr.p_double[i]+xoriginc->ptr.p_double[i]; + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(xs->ptr.p_double[i],bndlc->ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndlc->ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(xs->ptr.p_double[i],bnduc->ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bnduc->ptr.p_double[i]; + } + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->xf.ptr.p_double[i],sstate->bndl.ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndlc->ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->xf.ptr.p_double[i],sstate->bndu.ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bnduc->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Target function at point PROJ(X+Stp*D), where PROJ(.) is a projection into +feasible set. + +NOTE: if Stp=0, D is not referenced at all. Thus, there is no need to + fill it by some meaningful values for Stp=0. + +This subroutine uses temporary buffers Tmp0/1, which are automatically +resized if needed. + + -- ALGLIB -- + Copyright 21.12.2013 by Bochkanov Sergey +*************************************************************************/ +static double qqpsolver_projectedtargetfunction(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double stp, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double v; + double result; + + + n = sstate->n; + rvectorsetlengthatleast(tmp0, n, _state); + rvectorsetlengthatleast(tmp1, n, _state); + + /* + * Calculate projected point + */ + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(stp,(double)(0)) ) + { + v = x->ptr.p_double[i]+stp*d->ptr.p_double[i]; + } + else + { + v = x->ptr.p_double[i]; + } + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) + { + v = sstate->bndl.ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) + { + v = sstate->bndu.ptr.p_double[i]; + } + tmp0->ptr.p_double[i] = v; + } + + /* + * Function value at the Tmp0: + * + * f(x) = 0.5*x'*A*x + b'*x + */ + result = 0.0; + for(i=0; i<=n-1; i++) + { + result = result+sstate->b.ptr.p_double[i]*tmp0->ptr.p_double[i]; + } + if( sstate->akind==0 ) + { + + /* + * Dense matrix A + */ + result = result+0.5*rmatrixsyvmv(n, &sstate->densea, 0, 0, ae_true, tmp0, 0, tmp1, _state); + } + else + { + + /* + * sparse matrix A + */ + ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in ProjectedTargetFunction", _state); + result = result+0.5*sparsevsmv(&sstate->sparsea, sstate->sparseupper, tmp0, _state); + } + return result; +} + + +/************************************************************************* +Gradient of the target function: + + f(x) = 0.5*x'*A*x + b'*x + +which is equal to + + grad = A*x + b + +Here: +* x is array[N] +* A is array[N,N] +* b is array[N] + +INPUT PARAMETERS: + SState - structure which stores function terms (not modified) + X - location + G - possibly preallocated buffer + +OUTPUT PARAMETERS: + G - array[N], gradient + + -- ALGLIB -- + Copyright 21.12.2013 by Bochkanov Sergey +*************************************************************************/ +static void qqpsolver_targetgradient(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t n; + + + n = sstate->n; + rvectorsetlengthatleast(g, n, _state); + if( sstate->akind==0 ) + { + + /* + * Dense matrix A + */ + rmatrixsymv(n, 1.0, &sstate->densea, 0, 0, ae_true, x, 0, 0.0, g, 0, _state); + } + else + { + + /* + * Sparse matrix A + */ + ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in TargetGradient", _state); + sparsesmv(&sstate->sparsea, sstate->sparseupper, x, g, _state); + } + ae_v_add(&g->ptr.p_double[0], 1, &sstate->b.ptr.p_double[0], 1, ae_v_len(0,n-1)); +} + + +/************************************************************************* +First and second derivatives of the "extended" target function along +specified direction. Target function is called "extended" because of +additional slack variables and has form: + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +with gradient + + grad = A*x + b + penaltyfactor*C'*(C*x-b) + +Quadratic model has form + + F(x0+alpha*D) = D2*alpha^2 + D1*alpha + +INPUT PARAMETERS: + SState - structure which is used to obtain quadratic term of the model + X - current point, array[N] + D - direction across which derivatives are calculated, array[N] + G - gradient at current point (pre-calculated by caller), array[N] + +OUTPUT PARAMETERS: + D1 - linear coefficient + D1Est - estimate of D1 sign, accounting for possible numerical + errors: + * >0 means "almost surely positive" + * <0 means "almost surely negative" + * =0 means "pessimistic estimate of numerical errors + in D1 is larger than magnitude of D1 itself; it is + impossible to reliably distinguish D1 from zero". + D2 - quadratic coefficient + D2Est - estimate of D2 sign, accounting for possible numerical + errors: + * >0 means "almost surely positive" + * <0 means "almost surely negative" + * =0 means "pessimistic estimate of numerical errors + in D2 is larger than magnitude of D2 itself; it is + impossible to reliably distinguish D2 from zero". + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +static void qqpsolver_quadraticmodel(const qqpbuffers* sstate, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* g, + double* d1, + ae_int_t* d1est, + double* d2, + ae_int_t* d2est, + /* Real */ ae_vector* tmp0, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double v; + double mx; + double mb; + double md; + + *d1 = 0.0; + *d1est = 0; + *d2 = 0.0; + *d2est = 0; + + n = sstate->n; + + /* + * Maximums + */ + mx = 0.0; + md = 0.0; + mb = 0.0; + for(i=0; i<=n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(x->ptr.p_double[i], _state), _state); + md = ae_maxreal(md, ae_fabs(d->ptr.p_double[i], _state), _state); + } + for(i=0; i<=n-1; i++) + { + mb = ae_maxreal(mb, ae_fabs(sstate->b.ptr.p_double[i], _state), _state); + } + + /* + * D2 + */ + if( sstate->akind==0 ) + { + + /* + * Dense matrix A + */ + *d2 = 0.5*rmatrixsyvmv(n, &sstate->densea, 0, 0, ae_true, d, 0, tmp0, _state); + } + else + { + + /* + * Sparse matrix A + */ + ae_assert(sstate->akind==1, "QQPOptimize: unexpected AKind in TargetGradient", _state); + *d2 = 0.5*sparsevsmv(&sstate->sparsea, sstate->sparseupper, d, _state); + } + v = ae_v_dotproduct(&d->ptr.p_double[0], 1, &g->ptr.p_double[0], 1, ae_v_len(0,n-1)); + *d1 = v; + + /* + * Error estimates + */ + estimateparabolicmodel(sstate->absasum, sstate->absasum2, mx, mb, md, *d1, *d2, d1est, d2est, _state); +} + + +/************************************************************************* +This function accepts quadratic model of the form + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +and list of possible steps along direction D. It chooses best step (one +which achieves minimum value of the target function) and moves current +point (given by SAS object) to the new location. Step is bounded subject +to boundary constraints. + +Candidate steps are divided into two groups: +* "default" step, which is always performed when no candidate steps LONGER + THAN THE DEFAULT ONE is given. This candidate MUST reduce target + function value; it is responsibility of caller to provide default + candidate which reduces target function. +* "additional candidates", which may be shorter or longer than the default + step. Candidates which are shorter that the default step are ignored; + candidates which are longer than the "default" step are tested. + +The idea is that we ALWAYS try "default" step, and it is responsibility of +the caller to provide us with something which is worth trying. This step +may activate some constraint - that's why we stopped at "default" step +size. However, we may also try longer steps which may activate additional +constraints and further reduce function value. + +INPUT PARAMETERS: + SState - structure which stores model + SAS - active set structure which stores current point in SAS.XC + D - direction for step + Stp - step length for "default" candidate + NeedAct - whether default candidate activates some constraint; + if NeedAct is True, constraint given by CIdc/CVal is + GUARANTEED to be activated in the final point. + CIdx - if NeedAct is True, stores index of the constraint to activate + CVal - if NeedAct is True, stores constrained value; + SAS.XC[CIdx] is forced to be equal to CVal. + AddSteps- array[AddStepsCnt] of additional steps: + * AddSteps[]<=Stp are ignored + * AddSteps[]>Stp are tried + Activated- possibly preallocated buffer; previously allocated memory + will be reused. + Tmp0/1 - possibly preallocated buffers; previously allocated memory + will be reused. + +OUTPUT PARAMETERS: + SAS - SAS.XC is set to new point; if there was a constraint + specified by NeedAct/CIdx/CVal, it will be activated + (other constraints may be activated too, but this one is + guaranteed to be active in the final point). + Activated- elements of this array are set to True, if I-th constraint + as inactive at previous point, but become active in the + new one. + Situations when we deactivate xi>=0 and activate xi<=1 are + considered as activation of previously inactive constraint + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +static void qqpsolver_findbeststepandmove(const qqpbuffers* sstate, + sactiveset* sas, + /* Real */ const ae_vector* d, + double stp, + ae_bool needact, + ae_int_t cidx, + double cval, + /* Real */ const ae_vector* addsteps, + ae_int_t addstepscnt, + /* Boolean */ ae_vector* activated, + /* Real */ ae_vector* tmp0, + /* Real */ ae_vector* tmp1, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t k; + double v; + double stpbest; + double fbest; + double fcand; + + + n = sstate->n; + rvectorsetlengthatleast(tmp0, n, _state); + bvectorsetlengthatleast(activated, n, _state); + + /* + * Calculate initial step, store to Tmp0 + * + * NOTE: Tmp0 is guaranteed to be feasible w.r.t. boundary constraints + */ + for(i=0; i<=n-1; i++) + { + v = sas->xc.ptr.p_double[i]+stp*d->ptr.p_double[i]; + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) + { + v = sstate->bndl.ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) + { + v = sstate->bndu.ptr.p_double[i]; + } + tmp0->ptr.p_double[i] = v; + } + if( needact ) + { + tmp0->ptr.p_double[cidx] = cval; + } + + /* + * Try additional steps, if AddStepsCnt>0 + */ + if( addstepscnt>0 ) + { + + /* + * Find best step + */ + stpbest = stp; + fbest = qqpsolver_projectedtargetfunction(sstate, &sas->xc, d, stpbest, tmp0, tmp1, _state); + for(k=0; k<=addstepscnt-1; k++) + { + if( ae_fp_greater(addsteps->ptr.p_double[k],stp) ) + { + fcand = qqpsolver_projectedtargetfunction(sstate, &sas->xc, d, addsteps->ptr.p_double[k], tmp0, tmp1, _state); + if( ae_fp_less(fcand,fbest) ) + { + fbest = fcand; + stpbest = addsteps->ptr.p_double[k]; + } + } + } + + /* + * Prepare best step + * + * NOTE: because only AddSteps[]>Stp were checked, + * this step will activate constraint CIdx. + */ + for(i=0; i<=n-1; i++) + { + v = sas->xc.ptr.p_double[i]+stpbest*d->ptr.p_double[i]; + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_less(v,sstate->bndl.ptr.p_double[i]) ) + { + v = sstate->bndl.ptr.p_double[i]; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_greater(v,sstate->bndu.ptr.p_double[i]) ) + { + v = sstate->bndu.ptr.p_double[i]; + } + tmp0->ptr.p_double[i] = v; + } + if( needact ) + { + tmp0->ptr.p_double[cidx] = cval; + } + } + + /* + * Fill Activated array by information about activated constraints. + * Perform step + */ + for(i=0; i<=n-1; i++) + { + activated->ptr.p_bool[i] = ae_false; + v = tmp0->ptr.p_double[i]; + if( ae_fp_eq(v,sas->xc.ptr.p_double[i]) ) + { + continue; + } + if( sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(v,sstate->bndl.ptr.p_double[i]) ) + { + activated->ptr.p_bool[i] = ae_true; + } + if( sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(v,sstate->bndu.ptr.p_double[i]) ) + { + activated->ptr.p_bool[i] = ae_true; + } + } + sasmoveto(sas, tmp0, needact, cidx, cval, _state); +} + + +/************************************************************************* +This function prepares data for constrained Newton step for penalized +quadratic model of the form + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +where A can be dense or sparse, and model is considered subject to equality +constraints specified by SState.SAS.XC object. Constraint is considered +active if XC[i] is exactly BndL[i] or BndU[i], i.e. we ignore internal +list of constraints monitored by SAS object. Our own set of constraints +includes all constraints stored by SAS, but also may include some +constraints which are inactive in SAS. + +"Preparation" means that Cholesky decomposition of the effective system +matrix is performed, and we can perform constrained Newton step. + +This function works as black box. It uses fields of SState which are marked +as "Variables for constrained Newton phase", and only this function and +its friends know about these variables. Everyone else should use: +* CNewtonBuild() to prepare initial Cholesky decomposition for step +* CNewtonStep() to perform constrained Newton step +* CNewtonUpdate() to update Cholesky matrix after point was moved and + constraints were updated. In some cases it is possible to efficiently + re-calculate Cholesky decomposition if you know which constraints were + activated. If efficient re-calculation is impossible, this function + returns False. + +INPUT PARAMETERS: + SState - structure which stores model and temporaries for CN phase; + in particular, SAS.XC stores current point. + SparseSolver-which sparse solver to use for sparse model; ignored for + dense QP. Can be: + * 2 - SKS-based Cholesky + NCholesky- counter which is incremented after Cholesky (successful or + failed one) + +OUTPUT PARAMETERS: + NCholesky- possibly updated counter + +RESULT: + True, if Cholesky decomposition was successfully performed. + False, if a) matrix was semi-definite or indefinite, or b) particular + combination of matrix type (sparse) and constraints (general linear) + is not supported. + +NOTE: this function may routinely return False, for indefinite matrices or + for sparse problems with general linear constraints. You should be + able to handle such situations. + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +static ae_bool qqpsolver_cnewtonbuild(qqpbuffers* sstate, + ae_int_t sparsesolver, + ae_int_t* ncholesky, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + ae_bool b; + ae_int_t ridx0; + ae_int_t ridx1; + ae_int_t nfree; + ae_bool result; + + + result = ae_false; + + /* + * Fetch often used fields + */ + n = sstate->n; + + /* + * 1. Set CNModelAge to zero + * 2. Generate YIdx - reordering of variables such that free variables + * come first and are ordered by ascending, fixed are last ones and + * have no particular ordering. + * + * This step is same for dense and sparse problems. + */ + sstate->cnmodelage = 0; + ivectorsetlengthatleast(&sstate->yidx, n, _state); + ridx0 = 0; + ridx1 = n-1; + for(i=0; i<=n-1; i++) + { + sstate->yidx.ptr.p_int[i] = -1; + } + for(i=0; i<=n-1; i++) + { + ae_assert(!sstate->havebndl.ptr.p_bool[i]||ae_fp_greater_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]), "CNewtonBuild: internal error", _state); + ae_assert(!sstate->havebndu.ptr.p_bool[i]||ae_fp_less_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]), "CNewtonBuild: internal error", _state); + b = ae_false; + b = b||(sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i])); + b = b||(sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i])); + if( b ) + { + sstate->yidx.ptr.p_int[ridx1] = i; + ridx1 = ridx1-1; + } + else + { + sstate->yidx.ptr.p_int[ridx0] = i; + ridx0 = ridx0+1; + } + } + ae_assert(ridx0==ridx1+1, "CNewtonBuild: internal error", _state); + nfree = ridx0; + sstate->nfree = nfree; + if( nfree==0 ) + { + return result; + } + + /* + * Constrained Newton matrix: dense version + */ + if( sstate->akind==0 ) + { + rmatrixsetlengthatleast(&sstate->densez, n, n, _state); + rvectorsetlengthatleast(&sstate->tmpcn, n, _state); + for(i=0; i<=n-1; i++) + { + for(j=i; j<=n-1; j++) + { + sstate->densez.ptr.pp_double[i][j] = sstate->densea.ptr.pp_double[i][j]; + } + } + for(i=1; i<=nfree-1; i++) + { + ae_assert(sstate->yidx.ptr.p_int[i]>sstate->yidx.ptr.p_int[i-1], "CNewtonBuild: integrity check failed", _state); + } + for(i=0; i<=nfree-1; i++) + { + k = sstate->yidx.ptr.p_int[i]; + for(j=i; j<=nfree-1; j++) + { + sstate->densez.ptr.pp_double[i][j] = sstate->densez.ptr.pp_double[k][sstate->yidx.ptr.p_int[j]]; + } + } + rvectorsetlengthatleast(&sstate->regdiag, n, _state); + for(i=0; i<=nfree-1; i++) + { + v = 0.0; + for(j=0; j<=i-1; j++) + { + v = v+ae_fabs(sstate->densez.ptr.pp_double[j][i], _state); + } + for(j=i; j<=nfree-1; j++) + { + v = v+ae_fabs(sstate->densez.ptr.pp_double[i][j], _state); + } + if( ae_fp_eq(v,(double)(0)) ) + { + v = 1.0; + } + sstate->regdiag.ptr.p_double[i] = qqpsolver_regz*v; + } + for(i=0; i<=nfree-1; i++) + { + sstate->densez.ptr.pp_double[i][i] = sstate->densez.ptr.pp_double[i][i]+sstate->regdiag.ptr.p_double[i]; + } + inc(ncholesky, _state); + if( !spdmatrixcholeskyrec(&sstate->densez, 0, nfree, ae_true, &sstate->tmpcn, _state) ) + { + return result; + } + for(i=nfree-1; i>=0; i--) + { + ae_v_move(&sstate->tmpcn.ptr.p_double[i], 1, &sstate->densez.ptr.pp_double[i][i], 1, ae_v_len(i,nfree-1)); + k = sstate->yidx.ptr.p_int[i]; + for(j=k; j<=n-1; j++) + { + sstate->densez.ptr.pp_double[k][j] = (double)(0); + } + for(j=i; j<=nfree-1; j++) + { + sstate->densez.ptr.pp_double[k][sstate->yidx.ptr.p_int[j]] = sstate->tmpcn.ptr.p_double[j]; + } + } + for(i=nfree; i<=n-1; i++) + { + k = sstate->yidx.ptr.p_int[i]; + sstate->densez.ptr.pp_double[k][k] = 1.0; + for(j=k+1; j<=n-1; j++) + { + sstate->densez.ptr.pp_double[k][j] = (double)(0); + } + } + result = ae_true; + return result; + } + + /* + * Constrained Newton matrix: sparse version + */ + if( sstate->akind==1 ) + { + ae_assert(sparsesolver==2, "CNewtonBuild: internal error", _state); + + /* + * Copy sparse A to Z and fill rows/columns corresponding to active + * constraints by zeros. Diagonal elements corresponding to active + * constraints are filled by unit values. + */ + sparsecopytosksbuf(&sstate->sparsea, &sstate->sparsecca, _state); + rvectorsetlengthatleast(&sstate->tmpcn, n, _state); + for(i=0; i<=n-1; i++) + { + sstate->tmpcn.ptr.p_double[i] = (double)(0); + } + for(i=nfree; i<=n-1; i++) + { + sstate->tmpcn.ptr.p_double[sstate->yidx.ptr.p_int[i]] = (double)(1); + } + for(i=0; i<=n-1; i++) + { + k = sstate->sparsecca.ridx.ptr.p_int[i]; + for(j=i-sstate->sparsecca.didx.ptr.p_int[i]; j<=i; j++) + { + if( ae_fp_neq(sstate->tmpcn.ptr.p_double[i],(double)(0))||ae_fp_neq(sstate->tmpcn.ptr.p_double[j],(double)(0)) ) + { + + /* + * I-th or J-th variable is in active set (constrained) + */ + if( i==j ) + { + sstate->sparsecca.vals.ptr.p_double[k] = 1.0; + } + else + { + sstate->sparsecca.vals.ptr.p_double[k] = 0.0; + } + } + k = k+1; + } + } + + /* + * Perform sparse Cholesky + */ + inc(ncholesky, _state); + if( !sparsecholeskyskyline(&sstate->sparsecca, n, sstate->sparseupper, _state) ) + { + return result; + } + result = ae_true; + return result; + } + + /* + * Unexpected :) + */ + ae_assert(ae_false, "CNewtonBuild: internal error", _state); + return result; +} + + +/************************************************************************* +This function updates equality-constrained Cholesky matrix after +activation of the new equality constraints. Matrix being updated is +quadratic term of the function below + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +where A can be dense or sparse. + +This function uses YIdx[] array (set by CNewtonBuild() function) to +distinguish between active and inactive constraints. + +This function works as black box. It uses fields of SState which are marked +as "Variables for constrained Newton phase", and only this function and +its friends know about these variables. Everyone else should use: +* CNewtonBuild() to prepare initial Cholesky decomposition for step +* CNewtonStep() to perform constrained Newton step +* CNewtonUpdate() to update Cholesky matrix after point was moved and + constraints were updated. In some cases it is possible to efficiently + re-calculate Cholesky decomposition if you know which constraints were + activated. If efficient re-calculation is impossible, this function + returns False. + +INPUT PARAMETERS: + SState - structure which stores model and temporaries for CN phase; + in particular, SAS.XC stores current point. + Settings - QQPSettings object which was initialized by appropriate + construction function. + NCUpdates- counter which is incremented after each update (one update + means one variable being fixed) + +OUTPUT PARAMETERS: + NCUpdates- possibly updated counter + +RESULT: + True, if Cholesky decomposition was successfully performed. + False, if a) model age was too high, or b) particular combination of + matrix type (sparse) and constraints (general linear) is not supported + +NOTE: this function may routinely return False. + You should be able to handle such situations. + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +static ae_bool qqpsolver_cnewtonupdate(qqpbuffers* sstate, + const qqpsettings* settings, + ae_int_t* ncupdates, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nfree; + ae_int_t ntofix; + ae_bool b; + ae_int_t ridx0; + ae_int_t ridx1; + ae_int_t i; + ae_int_t k; + ae_bool result; + + + result = ae_false; + + /* + * Cholesky updates for sparse problems are not supported + */ + if( sstate->akind==1 ) + { + return result; + } + + /* + * Fetch often used fields + */ + n = sstate->n; + nfree = sstate->nfree; + + /* + * Determine variables to fix and move them to YIdx[NFree-NToFix:NFree-1] + * Exit if CNModelAge increased too much. + */ + ivectorsetlengthatleast(&sstate->tmpcni, n, _state); + ridx0 = 0; + ridx1 = nfree-1; + for(i=0; i<=nfree-1; i++) + { + sstate->tmpcni.ptr.p_int[i] = -1; + } + for(k=0; k<=nfree-1; k++) + { + i = sstate->yidx.ptr.p_int[k]; + ae_assert(!sstate->havebndl.ptr.p_bool[i]||ae_fp_greater_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i]), "CNewtonUpdate: internal error", _state); + ae_assert(!sstate->havebndu.ptr.p_bool[i]||ae_fp_less_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i]), "CNewtonUpdate: internal error", _state); + b = ae_false; + b = b||(sstate->havebndl.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndl.ptr.p_double[i])); + b = b||(sstate->havebndu.ptr.p_bool[i]&&ae_fp_eq(sstate->sas.xc.ptr.p_double[i],sstate->bndu.ptr.p_double[i])); + if( b ) + { + sstate->tmpcni.ptr.p_int[ridx1] = i; + ridx1 = ridx1-1; + } + else + { + sstate->tmpcni.ptr.p_int[ridx0] = i; + ridx0 = ridx0+1; + } + } + ae_assert(ridx0==ridx1+1, "CNewtonUpdate: internal error", _state); + ntofix = nfree-ridx0; + if( ntofix==0||ntofix==nfree ) + { + return result; + } + if( sstate->cnmodelage+ntofix>settings->cnmaxupdates ) + { + return result; + } + for(i=0; i<=nfree-1; i++) + { + sstate->yidx.ptr.p_int[i] = sstate->tmpcni.ptr.p_int[i]; + } + + /* + * Constrained Newton matrix: dense version. + */ + if( sstate->akind==0 ) + { + + /* + * Update Cholesky matrix with SPDMatrixCholeskyUpdateFixBuf() + */ + bvectorsetlengthatleast(&sstate->tmpcnb, n, _state); + for(i=0; i<=n-1; i++) + { + sstate->tmpcnb.ptr.p_bool[i] = ae_false; + } + for(i=nfree-ntofix; i<=nfree-1; i++) + { + sstate->tmpcnb.ptr.p_bool[sstate->yidx.ptr.p_int[i]] = ae_true; + } + spdmatrixcholeskyupdatefixbuf(&sstate->densez, n, ae_true, &sstate->tmpcnb, &sstate->tmpcn, _state); + + /* + * Update information stored in State and exit + */ + sstate->nfree = nfree-ntofix; + sstate->cnmodelage = sstate->cnmodelage+ntofix; + *ncupdates = *ncupdates+ntofix; + result = ae_true; + return result; + } + + /* + * Unexpected :) + */ + ae_assert(ae_false, "CNewtonUpdate: internal error", _state); + return result; +} + + +/************************************************************************* +This function prepares equality-constrained Newton step using previously +calculated constrained Cholesky matrix of the problem + + f(x) = 0.5*x'*A*x + b'*x + penaltyfactor*0.5*(C*x-b)'*(C*x-b) + +where A can be dense or sparse. + +As input, this function accepts gradient at the current location. As +output, it returns step vector (replaces gradient). + +This function works as black box. It uses fields of SState which are marked +as "Variables for constrained Newton phase", and only this function and +its friends know about these variables. Everyone else should use: +* CNewtonBuild() to prepare initial Cholesky decomposition for step +* CNewtonStep() to perform constrained Newton step +* CNewtonUpdate() to update Cholesky matrix after point was moved and + constraints were updated. In some cases it is possible to efficiently + re-calculate Cholesky decomposition if you know which constraints were + activated. If efficient re-calculation is impossible, this function + returns False. + +INPUT PARAMETERS: + SState - structure which stores model and temporaries for CN phase; + in particular, SAS.XC stores current point. + Settings - QQPSettings object which was initialized by appropriate + construction function. + GC - array[N], gradient of the target function + +OUTPUT PARAMETERS: + GC - array[N], step vector (on success) + +RESULT: + True, if step was successfully calculated. + False, if step calculation failed: + a) gradient was exactly zero, + b) gradient norm was smaller than EpsG (stopping condition) + c) all variables were equality-constrained + +NOTE: this function may routinely return False. + You should be able to handle such situations. + + -- ALGLIB -- + Copyright 14.05.2014 by Bochkanov Sergey +*************************************************************************/ +static ae_bool qqpsolver_cnewtonstep(qqpbuffers* sstate, + const qqpsettings* settings, + /* Real */ ae_vector* gc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t nfree; + double v; + ae_bool result; + + + result = ae_false; + n = sstate->n; + nfree = sstate->nfree; + for(i=nfree; i<=n-1; i++) + { + gc->ptr.p_double[sstate->yidx.ptr.p_int[i]] = 0.0; + } + v = ae_v_dotproduct(&gc->ptr.p_double[0], 1, &gc->ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_less_eq(ae_sqrt(v, _state),settings->epsg) ) + { + return result; + } + for(i=0; i<=n-1; i++) + { + gc->ptr.p_double[i] = -gc->ptr.p_double[i]; + } + if( sstate->akind==0 ) + { + + /* + * Dense Newton step. + * Use straightforward Cholesky solver. + */ + fblscholeskysolve(&sstate->densez, 1.0, n, ae_true, gc, &sstate->tmpcn, _state); + result = ae_true; + return result; + } + if( sstate->akind==1 ) + { + + /* + * Sparse Newton step. + * + * We have T*T' = L*L' = U'*U (depending on specific triangle stored in SparseCCA). + */ + if( sstate->sparseupper ) + { + sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 1, gc, _state); + sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 0, gc, _state); + } + else + { + sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 0, gc, _state); + sparsetrsv(&sstate->sparsecca, sstate->sparseupper, ae_false, 1, gc, _state); + } + result = ae_true; + return result; + } + ae_assert(ae_false, "CNewtonStep: internal error", _state); + return result; +} + + +void _qqpsettings_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + qqpsettings *p = (qqpsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qqpsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + qqpsettings *dst = (qqpsettings*)_dst; + const qqpsettings *src = (const qqpsettings*)_src; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxouterits = src->maxouterits; + dst->cgphase = src->cgphase; + dst->cnphase = src->cnphase; + dst->cgminits = src->cgminits; + dst->cgmaxits = src->cgmaxits; + dst->cnmaxupdates = src->cnmaxupdates; + dst->sparsesolver = src->sparsesolver; +} + + +void _qqpsettings_clear(void* _p) +{ + qqpsettings *p = (qqpsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qqpsettings_destroy(void* _p) +{ + qqpsettings *p = (qqpsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qqpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + qqpbuffers *p = (qqpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsea, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgp, 0, DT_REAL, _state, make_automatic); + _sactiveset_init(&p->sas, _state, make_automatic); + ae_vector_init(&p->activated, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->densez, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsecca, _state, make_automatic); + ae_vector_init(&p->yidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->regdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->regx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcni, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpcnb, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stpbuf, 0, DT_REAL, _state, make_automatic); + _sparsebuffers_init(&p->sbuf, _state, make_automatic); +} + + +void _qqpbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + qqpbuffers *dst = (qqpbuffers*)_dst; + const qqpbuffers *src = (const qqpbuffers*)_src; + dst->n = src->n; + dst->akind = src->akind; + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state, make_automatic); + dst->sparseupper = src->sparseupper; + dst->absamax = src->absamax; + dst->absasum = src->absasum; + dst->absasum2 = src->absasum2; + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic); + ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic); + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + ae_vector_init_copy(&dst->xf, &src->xf, _state, make_automatic); + ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic); + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_vector_init_copy(&dst->dc, &src->dc, _state, make_automatic); + ae_vector_init_copy(&dst->dp, &src->dp, _state, make_automatic); + ae_vector_init_copy(&dst->cgc, &src->cgc, _state, make_automatic); + ae_vector_init_copy(&dst->cgp, &src->cgp, _state, make_automatic); + _sactiveset_init_copy(&dst->sas, &src->sas, _state, make_automatic); + ae_vector_init_copy(&dst->activated, &src->activated, _state, make_automatic); + dst->nfree = src->nfree; + dst->cnmodelage = src->cnmodelage; + ae_matrix_init_copy(&dst->densez, &src->densez, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsecca, &src->sparsecca, _state, make_automatic); + ae_vector_init_copy(&dst->yidx, &src->yidx, _state, make_automatic); + ae_vector_init_copy(&dst->regdiag, &src->regdiag, _state, make_automatic); + ae_vector_init_copy(&dst->regx0, &src->regx0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcn, &src->tmpcn, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcni, &src->tmpcni, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcnb, &src->tmpcnb, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->stpbuf, &src->stpbuf, _state, make_automatic); + _sparsebuffers_init_copy(&dst->sbuf, &src->sbuf, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repncholesky = src->repncholesky; + dst->repncupdates = src->repncupdates; +} + + +void _qqpbuffers_clear(void* _p) +{ + qqpbuffers *p = (qqpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->densea); + _sparsematrix_clear(&p->sparsea); + ae_vector_clear(&p->b); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->havebndl); + ae_vector_clear(&p->havebndu); + ae_vector_clear(&p->xs); + ae_vector_clear(&p->xf); + ae_vector_clear(&p->gc); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->dc); + ae_vector_clear(&p->dp); + ae_vector_clear(&p->cgc); + ae_vector_clear(&p->cgp); + _sactiveset_clear(&p->sas); + ae_vector_clear(&p->activated); + ae_matrix_clear(&p->densez); + _sparsematrix_clear(&p->sparsecca); + ae_vector_clear(&p->yidx); + ae_vector_clear(&p->regdiag); + ae_vector_clear(&p->regx0); + ae_vector_clear(&p->tmpcn); + ae_vector_clear(&p->tmpcni); + ae_vector_clear(&p->tmpcnb); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->stpbuf); + _sparsebuffers_clear(&p->sbuf); +} + + +void _qqpbuffers_destroy(void* _p) +{ + qqpbuffers *p = (qqpbuffers*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->densea); + _sparsematrix_destroy(&p->sparsea); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->havebndl); + ae_vector_destroy(&p->havebndu); + ae_vector_destroy(&p->xs); + ae_vector_destroy(&p->xf); + ae_vector_destroy(&p->gc); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->dc); + ae_vector_destroy(&p->dp); + ae_vector_destroy(&p->cgc); + ae_vector_destroy(&p->cgp); + _sactiveset_destroy(&p->sas); + ae_vector_destroy(&p->activated); + ae_matrix_destroy(&p->densez); + _sparsematrix_destroy(&p->sparsecca); + ae_vector_destroy(&p->yidx); + ae_vector_destroy(&p->regdiag); + ae_vector_destroy(&p->regx0); + ae_vector_destroy(&p->tmpcn); + ae_vector_destroy(&p->tmpcni); + ae_vector_destroy(&p->tmpcnb); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->stpbuf); + _sparsebuffers_destroy(&p->sbuf); +} + + +#endif +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes QPDENSEAULSettings structure with default settings. + +Newly created structure MUST be initialized by default settings - or by +copy of the already initialized structure. + + -- ALGLIB -- + Copyright 14.05.2011 by Bochkanov Sergey +*************************************************************************/ +void qpdenseaulloaddefaults(ae_int_t nmain, + qpdenseaulsettings* s, + ae_state *_state) +{ + + + s->epsx = 1.0E-6; + s->outerits = 5; + s->rho = 100.0; +} + + +/************************************************************************* +This function runs Dense-AUL solver; it returns after optimization process +was completed. Following QP problem is solved: + + min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + +subject to combination of box and general linear dense/sparse constraints. + +INPUT PARAMETERS: + DenseA - for dense problems (AKind=0), A-term of CQM object + contains system matrix. Other terms are unspecified + and should not be referenced. + SparseA - for sparse problems (AKind=1), CRS format + AKind - sparse matrix format: + * 0 for dense matrix + * 1 for sparse matrix + SparseUpper - which triangle of SparseAC stores matrix - upper or + lower one (for dense matrices this parameter is not + actual). + B - linear term, array[N] + BndL - lower bound, array[N] + BndU - upper bound, array[N] + S - scale vector, array[NC]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[NC]. Can be zero. + N - number of variables in the original formulation (no + slack variables). + CLEIC - dense linear equality/inequality constraints. Equality + constraints come first. + NEC, NIC - number of dense equality/inequality constraints. + SCLEIC - sparse linear equality/inequality constraints. Equality + constraints come first. + SNEC, SNIC - number of sparse equality/inequality constraints. + RenormLC - whether constraints should be renormalized (recommended) + or used "as is". + Settings - QPDENSEAULSettings object initialized by one of the initialization + functions. + State - object which stores temporaries + XS - initial point, array[NC] + + +OUTPUT PARAMETERS: + XS - last point + TerminationType-termination type: + * + * + * + + -- ALGLIB -- + Copyright 2017 by Bochkanov Sergey +*************************************************************************/ +void qpdenseauloptimize(const convexquadraticmodel* a, + const sparsematrix* sparsea, + ae_int_t akind, + ae_bool sparseaupper, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nn, + /* Real */ const ae_matrix* cleic, + ae_int_t dnec, + ae_int_t dnic, + const sparsematrix* scleic, + ae_int_t snec, + ae_int_t snic, + ae_bool renormlc, + const qpdenseaulsettings* settings, + qpdenseaulbuffers* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double rho; + double epsx; + ae_int_t outeridx; + ae_int_t nmain; + ae_int_t nslack; + ae_int_t ntotal; + ae_int_t ktotal; + double maxrho; + double feaserr; + double feaserrprev; + double requestedfeasdecrease; + ae_int_t goodcounter; + ae_int_t stagnationcounter; + ae_int_t nectotal; + ae_int_t nictotal; + ae_int_t nicwork; + ae_int_t kwork; + ae_int_t nwork; + ae_bool allowwseviction; + ae_bool workingsetextended; + double targetscale; + + *terminationtype = 0; + + nmain = nn; + nslack = dnic+snic; + ntotal = nmain+nslack; + nectotal = dnec+snec; + nictotal = dnic+snic; + ktotal = dnec+dnic+snec+snic; + rho = settings->rho; + epsx = settings->epsx; + requestedfeasdecrease = 0.33; + maxrho = 1.0E12; + if( ae_fp_less_eq(epsx,(double)(0)) ) + { + epsx = 1.0E-9; + } + + /* + * Integrity checks + */ + if( snec+snic>0 ) + { + ae_assert(scleic->matrixtype==1, "QPDENSEAULOptimize: unexpected sparse matrix format", _state); + ae_assert(scleic->m==snec+snic, "QPDENSEAULOptimize: unexpected sparse matrix size", _state); + ae_assert(scleic->n==nmain+1, "QPDENSEAULOptimize: unexpected sparse matrix size", _state); + } + + /* + * Prepare + */ + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repncholesky = 0; + state->repnmv = 0; + state->repnwrkchanges = 0; + state->repnwrk0 = 0; + state->repnwrk1 = 0; + state->repnwrkf = 0; + *terminationtype = 0; + ivectorsetlengthatleast(&state->cidx, ktotal, _state); + rvectorsetlengthatleast(&state->nulc, ktotal, _state); + rvectorsetlengthatleast(&state->nulcest, ktotal, _state); + rvectorsetlengthatleast(&state->exb, ntotal, _state); + rvectorsetlengthatleast(&state->exxc, ntotal, _state); + rvectorsetlengthatleast(&state->exxorigin, ntotal, _state); + rvectorsetlengthatleast(&state->exbndl, ntotal, _state); + rvectorsetlengthatleast(&state->exbndu, ntotal, _state); + rvectorsetlengthatleast(&state->exscale, ntotal, _state); + rvectorsetlengthatleast(&state->tmp0, ntotal, _state); + rvectorsetlengthatleast(&state->nicerr, nictotal, _state); + ivectorsetlengthatleast(&state->nicnact, nictotal, _state); + + /* + * Allocate Lagrange multipliers, fill by default values (zeros) + */ + rvectorsetlengthatleast(lagbc, nmain, _state); + rvectorsetlengthatleast(laglc, ktotal, _state); + for(i=0; i<=nmain-1; i++) + { + lagbc->ptr.p_double[i] = 0.0; + } + for(i=0; i<=ktotal-1; i++) + { + laglc->ptr.p_double[i] = 0.0; + } + + /* + * Prepare scaled/shifted model in dense format - input parameters + * are converted and stored in State.SclSftA/B/HasBndL/HasBndU/BndL/BndU/CLEIC/XC/CScales + */ + qpdenseaulsolver_scaleshiftoriginalproblem(a, sparsea, akind, sparseaupper, b, bndl, bndu, s, xorigin, nmain, cleic, dnec, dnic, scleic, snec, snic, renormlc, state, xs, _state); + + /* + * Normalize model in such way that norm(A)~1 (very roughly) + * + * We have two lower bounds for sigma_max(A): + * * first estimate is provided by Frobenius norm, it is equal to ANorm/NMain + * * second estimate is provided by max(CAC) + * + * We select largest one of these estimates, because using just one + * of them is prone to different failure modes. Then, we divide A and B + * by this estimate. + */ + targetscale = qpdenseaulsolver_normalizequadraticterm(&state->sclsfta, &state->sclsftb, nmain, &state->sclsftcleic, nectotal, nictotal, renormlc, &state->tmp2, _state); + + /* + * Select working set of inequality constraints. + * + * Although it is possible to process all inequality constraints + * at once, in one large batch, some QP problems have NIC>>N constraints, + * but only minor fraction of them is inactive in the solution. + * + * Because algorithm running time is O((N+NEC+NIC)^3), we can + * save a lot of time if we process only those inequality constraints + * which need activation. Generally, NECsclsfta, nmain, &state->sclsftcleic, nectotal, nictotal, &state->tmp0, &state->tmp2, &nicwork, &allowwseviction, _state); + kwork = nectotal+nicwork; + nwork = nmain+nicwork; + state->repnwrk0 = nicwork; + for(i=0; i<=nicwork-1; i++) + { + state->nicnact.ptr.p_int[i] = 1; + } + for(i=nicwork; i<=nictotal-1; i++) + { + state->nicnact.ptr.p_int[i] = 0; + } + for(i=0; i<=ktotal-1; i++) + { + state->cidx.ptr.p_int[i] = i; + } + + /* + * Perform outer iteration + */ + for(i=0; i<=ktotal-1; i++) + { + state->nulc.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=ntotal-1; i++) + { + state->exscale.ptr.p_double[i] = 1.0; + state->exxorigin.ptr.p_double[i] = 0.0; + } + qpdenseaulsolver_generateexinitialpoint(&state->sclsftxc, nmain, nslack, &state->exxc, _state); + goodcounter = 0; + stagnationcounter = 0; + feaserr = ae_maxrealnumber; + for(outeridx=0; outeridx<=settings->outerits-1; outeridx++) + { + + /* + * Repeat loop until working set stabilizes. + */ + do + { + + /* + * Preallocate space for ExA and for QQP solver; we do not allocate + * array[NTotal,NTotal] from the start because NTotal can be much + * larger than NMain for problems with large amount of inequality + * constraints, and we usually need NWork=O(NMain). + * + * NOTE: for the sake of simplicity, 1-dimensional arrays were + * preallocated to the maximum size required (NTotal). + */ + if( state->exa.rowsexa.colsexa, i, i, _state); + } + qqppreallocategrowdense(&state->qqpbuf, nwork, i, _state); + + /* + * Generate penalized quadratic model + */ + qpdenseaulsolver_generateexmodel(&state->sclsfta, &state->sclsftb, nmain, &state->sclsftbndl, &state->sclsfthasbndl, &state->sclsftbndu, &state->sclsfthasbndu, &state->sclsftcleic, nectotal, nicwork, &state->nulc, rho, &state->exa, &state->exb, &state->exbndl, &state->exbndu, &state->tmp2, _state); + + /* + * Solve extended QP problem subject to current working set of general + * inequality constraints. + */ + qqploaddefaults(nwork, &state->qqpsettingsuser, _state); + state->qqpsettingsuser.maxouterits = 50; + state->qqpsettingsuser.epsg = 0.0; + state->qqpsettingsuser.epsf = 0.0; + state->qqpsettingsuser.epsx = 0.01*epsx; + state->qqpsettingsuser.cnphase = ae_true; + qqpoptimize(&state->dummycqm, &state->dummysparse, &state->exa, 2, ae_true, &state->exb, &state->exbndl, &state->exbndu, &state->exscale, &state->exxorigin, nwork, &state->qqpsettingsuser, &state->qqpbuf, &state->exxc, &k, _state); + state->repncholesky = state->repncholesky+state->qqpbuf.repncholesky; + + /* + * Evaluate violation of constraints + */ + for(i=0; i<=nictotal-1; i++) + { + v = ae_v_dotproduct(&state->sclsftcleic.ptr.pp_double[nectotal+i][0], 1, &state->exxc.ptr.p_double[0], 1, ae_v_len(0,nmain-1)); + v = v-state->sclsftcleic.ptr.pp_double[nectotal+i][nmain]; + state->nicerr.ptr.p_double[i] = v; + } + + /* + * Working set expansion: + * * select limited amount of most violated constraints + * * perform permutation of non-work constraints such that + * candidate constraint is first the list (update XC and NuLC) + * * increase working set size by 1 + * * increase activation count for new constraint by 1 (this count + * is used later by working set eviction phase) + * * repeat + * + * NOTE: we use selection sort algorithm because its O(NAdded*NWork) cost + * is still comparable to the cost of constraints evaluation + */ + workingsetextended = ae_false; + i = 0; + while(ae_fp_less((double)(i),(double)1+qpdenseaulsolver_expansionratio*(double)nmain)&&nicworknicerr.ptr.p_double[j],state->nicerr.ptr.p_double[k]) ) + { + k = j; + } + } + + /* + * If violation is positive, add it + */ + if( ae_fp_greater(state->nicerr.ptr.p_double[k],(double)(0)) ) + { + swaprows(&state->sclsftcleic, nectotal+nicwork, nectotal+k, -1, _state); + swapelements(&state->nicerr, nicwork, k, _state); + swapelementsi(&state->nicnact, nicwork, k, _state); + swapelementsi(&state->cidx, nectotal+nicwork, nectotal+k, _state); + swapelements(&state->cscales, nectotal+nicwork, nectotal+k, _state); + state->exxc.ptr.p_double[nmain+nicwork] = 0.0; + state->nulc.ptr.p_double[nectotal+nicwork] = 0.0; + state->nicnact.ptr.p_int[nicwork] = state->nicnact.ptr.p_int[nicwork]+1; + inc(&nicwork, _state); + inc(&nwork, _state); + inc(&kwork, _state); + inc(&i, _state); + workingsetextended = ae_true; + } + else + { + break; + } + } + + /* + * Working set eviction: + * * select constraints which are (1) far away from the + * boundary, AND (2) has less than two activation attempts + * (if constraint is regularly activated/deactivated, we keep + * it in the working set no matter what) + * * remove such constraints from the working set one by one + */ + if( allowwseviction ) + { + for(k=nicwork-1; k>=0; k--) + { + if( ae_fp_less(state->nicerr.ptr.p_double[k],qpdenseaulsolver_evictionlevel)&&state->nicnact.ptr.p_int[k]<=1 ) + { + swaprows(&state->sclsftcleic, nectotal+nicwork-1, nectotal+k, -1, _state); + swapelementsi(&state->cidx, nectotal+nicwork-1, nectotal+k, _state); + swapelements(&state->cscales, nectotal+nicwork-1, nectotal+k, _state); + swapelements(&state->nicerr, nicwork-1, k, _state); + swapelementsi(&state->nicnact, nicwork-1, k, _state); + swapelements(&state->exxc, nmain+nicwork-1, nmain+k, _state); + swapelements(&state->nulc, nectotal+nicwork-1, nectotal+k, _state); + dec(&nicwork, _state); + dec(&nwork, _state); + dec(&kwork, _state); + } + } + } + + /* + * Report working set statistics + */ + if( state->repnwrk1==0 ) + { + state->repnwrk1 = nicwork; + } + state->repnwrkf = nicwork; + if( workingsetextended ) + { + inc(&state->repnwrkchanges, _state); + } + } + while(workingsetextended); + + /* + * Estimate Lagrange multipliers using alternative algorithm + */ + ae_v_move(&state->nulcest.ptr.p_double[0], 1, &state->nulc.ptr.p_double[0], 1, ae_v_len(0,kwork-1)); + qpdenseaulsolver_updatelagrangemultipliers(&state->sclsfta, &state->sclsftb, nmain, &state->sclsftbndl, &state->sclsfthasbndl, &state->sclsftbndu, &state->sclsfthasbndu, &state->sclsftcleic, nectotal, nicwork, &state->exxc, &state->nulcest, state, _state); + + /* + * Update XC and Lagrange multipliers + */ + feaserrprev = feaserr; + feaserr = (double)(0); + for(i=0; i<=kwork-1; i++) + { + + /* + * Calculate I-th feasibility error in V using formula for distance + * between point and line (here we calculate actual distance between + * XN and hyperplane Ci'*XN=Bi, which is different from error Ci'*XN-Bi). + */ + v = (double)(0); + vv = (double)(0); + for(j=0; j<=nmain-1; j++) + { + v = v+state->sclsftcleic.ptr.pp_double[i][j]*state->exxc.ptr.p_double[j]; + vv = vv+ae_sqr(state->sclsftcleic.ptr.pp_double[i][j], _state); + } + if( i>=nectotal ) + { + v = v+state->exxc.ptr.p_double[nmain+(i-nectotal)]; + vv = vv+ae_sqr((double)(1), _state); + } + v = v-state->sclsftcleic.ptr.pp_double[i][nmain]; + vv = coalesce(vv, (double)(1), _state); + v = v/ae_sqrt(vv, _state); + + /* + * Calculate magnitude of Lagrangian update (and Lagrangian parameters themselves) + */ + feaserr = feaserr+ae_sqr(v, _state); + state->nulc.ptr.p_double[i] = state->nulcest.ptr.p_double[i]; + } + feaserr = ae_sqrt(feaserr, _state); + if( ae_fp_less(feaserr,epsx) ) + { + inc(&goodcounter, _state); + } + else + { + goodcounter = 0; + } + if( ae_fp_greater(feaserr,feaserrprev*requestedfeasdecrease) ) + { + inc(&stagnationcounter, _state); + } + else + { + stagnationcounter = 0; + } + if( goodcounter>=2 ) + { + break; + } + if( stagnationcounter>=2 ) + { + rho = ae_minreal(rho*10.0, maxrho, _state); + } + else + { + rho = ae_minreal(rho*1.41, maxrho, _state); + } + } + + /* + * Convert Lagrange multipliers from internal format to one expected + * by caller: + * * reorder multipliers for linear constraints + * * compute residual from gradient+linearconstraints + * * compute multipliers for box constraints from residual + * * rescale everything + */ + for(i=0; i<=nectotal+nicwork-1; i++) + { + laglc->ptr.p_double[state->cidx.ptr.p_int[i]] = -state->nulc.ptr.p_double[i]*targetscale/state->cscales.ptr.p_double[i]; + } + rvectorsetlengthatleast(&state->tmpg, nmain, _state); + for(i=0; i<=nmain-1; i++) + { + v = state->sclsftb.ptr.p_double[i]; + for(j=0; j<=nmain-1; j++) + { + v = v+state->sclsfta.ptr.pp_double[i][j]*state->exxc.ptr.p_double[j]; + } + state->tmpg.ptr.p_double[i] = v; + } + rmatrixgemv(nmain, nectotal+nicwork, -1.0, &state->sclsftcleic, 0, 0, 1, &state->nulc, 0, 1.0, &state->tmpg, 0, _state); + for(i=0; i<=nmain-1; i++) + { + if( (state->sclsfthasbndl.ptr.p_bool[i]&&ae_fp_eq(state->exxc.ptr.p_double[i],state->sclsftbndl.ptr.p_double[i]))||(state->sclsfthasbndu.ptr.p_bool[i]&&ae_fp_eq(state->exxc.ptr.p_double[i],state->sclsftbndu.ptr.p_double[i])) ) + { + lagbc->ptr.p_double[i] = -state->tmpg.ptr.p_double[i]; + } + } + for(i=0; i<=nmain-1; i++) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]*targetscale/s->ptr.p_double[i]; + } + + /* + * Unpack results. + * + * Add XOrigin to XC and make sure that boundary constraints are + * satisfied. + */ + for(i=0; i<=nmain-1; i++) + { + + /* + * Unscale/unshift + */ + xs->ptr.p_double[i] = s->ptr.p_double[i]*state->exxc.ptr.p_double[i]+xorigin->ptr.p_double[i]; + + /* + * Make sure that point is feasible w.r.t. box constraints. + * Enforce box constraints which were active in the scaled/shifted solution. + */ + if( state->sclsfthasbndl.ptr.p_bool[i] ) + { + if( ae_fp_less(xs->ptr.p_double[i],bndl->ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndl->ptr.p_double[i]; + } + if( ae_fp_eq(state->exxc.ptr.p_double[i],state->sclsftbndl.ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndl->ptr.p_double[i]; + } + } + if( state->sclsfthasbndu.ptr.p_bool[i] ) + { + if( ae_fp_greater(xs->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndu->ptr.p_double[i]; + } + if( ae_fp_eq(state->exxc.ptr.p_double[i],state->sclsftbndu.ptr.p_double[i]) ) + { + xs->ptr.p_double[i] = bndu->ptr.p_double[i]; + } + } + } + *terminationtype = 2; +} + + +/************************************************************************* +This function generates box-constrained QP problem, which is penalized and +augmented formulation of original linearly constrained problem + + -- ALGLIB -- + Copyright 23.02.2017 by Bochkanov Sergey +*************************************************************************/ +static void qpdenseaulsolver_generateexmodel(/* Real */ const ae_matrix* sclsfta, + /* Real */ const ae_vector* sclsftb, + ae_int_t nmain, + /* Real */ const ae_vector* sclsftbndl, + /* Boolean */ const ae_vector* sclsfthasbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* sclsfthasbndu, + /* Real */ const ae_matrix* sclsftcleic, + ae_int_t sclsftnec, + ae_int_t sclsftnic, + /* Real */ const ae_vector* nulc, + double rho, + /* Real */ ae_matrix* exa, + /* Real */ ae_vector* exb, + /* Real */ ae_vector* exbndl, + /* Real */ ae_vector* exbndu, + /* Real */ ae_matrix* tmp2, + ae_state *_state) +{ + ae_int_t nslack; + ae_int_t ntotal; + ae_int_t i; + ae_int_t j; + double v; + + + nslack = sclsftnic; + ntotal = nmain+nslack; + + /* + * Integrity check for properly preallocated storage + */ + ae_assert(exa->rows>=ntotal&&exa->cols>=ntotal, "QPDenseAUL.GenerateExModel - integrity check failed", _state); + ae_assert((exb->cnt>=ntotal&&exbndl->cnt>=ntotal)&&exbndu->cnt>=ntotal, "QPDenseAUL.GenerateExModel - integrity check failed", _state); + + /* + * Primary quadratic term + */ + for(i=0; i<=ntotal-1; i++) + { + for(j=i; j<=ntotal-1; j++) + { + exa->ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=nmain-1; i++) + { + for(j=i; j<=nmain-1; j++) + { + exa->ptr.pp_double[i][j] = sclsfta->ptr.pp_double[i][j]; + } + } + + /* + * Primary linear term + */ + for(i=0; i<=ntotal-1; i++) + { + exb->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nmain-1; i++) + { + exb->ptr.p_double[i] = sclsftb->ptr.p_double[i]; + } + + /* + * Box constraints - move primary, add slack + */ + for(i=0; i<=nmain-1; i++) + { + if( sclsfthasbndl->ptr.p_bool[i] ) + { + exbndl->ptr.p_double[i] = sclsftbndl->ptr.p_double[i]; + } + else + { + exbndl->ptr.p_double[i] = _state->v_neginf; + } + if( sclsfthasbndu->ptr.p_bool[i] ) + { + exbndu->ptr.p_double[i] = sclsftbndu->ptr.p_double[i]; + } + else + { + exbndu->ptr.p_double[i] = _state->v_posinf; + } + } + for(i=nmain; i<=ntotal-1; i++) + { + exbndl->ptr.p_double[i] = (double)(0); + exbndu->ptr.p_double[i] = _state->v_posinf; + } + + /* + * Handle equality constraints: + * * modify quadratic term + * * modify linear term + * * add Lagrangian term + */ + rmatrixsetlengthatleast(tmp2, sclsftnec+sclsftnic, ntotal, _state); + for(i=0; i<=sclsftnec+sclsftnic-1; i++) + { + + /* + * Given constraint row ci and right hand side ri, + * I-th quadratic constraint adds penalty term + * + * 0.5*Rho*(ci'*x-ri)^2 = + * = 0.5*Rho*(ci'*x-ri)^T*(ci'*x-ri) = + * = 0.5*Rho*(x'*ci-ri')*(ci'*x-ri) = + * = 0.5*Rho*(x'*ci*ci'*x - ri'*ci'*x - x'*ci*ri + ri'*ri ) + * = 0.5*Rho*(x'*(ci*ci')*x - 2*ri*(ci'*x) + ri^2 ) + * + * Thus, quadratic term is updated by + * + * 0.5*Rho*(ci*ci') + * + * (with actual update to ExA being performed without 0.5 + * multiplier because entire matrix is post-multipliead by 0.5) + * and linear term receives update + * + * -Rho*ri*ci + * + * Similaryly, lagrangian term is -NUi*(ci'*x-ri), + * so linear term is updated by + * + * -NUi*ci + * + * Because our model does not take into account constant term, + * we calculate just quadratic and linear terms. + */ + ae_v_move(&tmp2->ptr.pp_double[i][0], 1, &sclsftcleic->ptr.pp_double[i][0], 1, ae_v_len(0,nmain-1)); + for(j=nmain; j<=ntotal-1; j++) + { + tmp2->ptr.pp_double[i][j] = (double)(0); + } + if( i>=sclsftnec ) + { + tmp2->ptr.pp_double[i][nmain+i-sclsftnec] = 1.0; + } + v = -rho*sclsftcleic->ptr.pp_double[i][nmain]; + ae_v_addd(&exb->ptr.p_double[0], 1, &tmp2->ptr.pp_double[i][0], 1, ae_v_len(0,ntotal-1), v); + v = -nulc->ptr.p_double[i]; + ae_v_addd(&exb->ptr.p_double[0], 1, &tmp2->ptr.pp_double[i][0], 1, ae_v_len(0,ntotal-1), v); + } + rmatrixsyrk(ntotal, sclsftnec+sclsftnic, rho, tmp2, 0, 0, 2, 1.0, exa, 0, 0, ae_true, _state); +} + + +/************************************************************************* +This function generates initial point for "extended" box-constrained QP +problem. + + -- ALGLIB -- + Copyright 23.02.2017 by Bochkanov Sergey +*************************************************************************/ +static void qpdenseaulsolver_generateexinitialpoint(/* Real */ const ae_vector* sclsftxc, + ae_int_t nmain, + ae_int_t nslack, + /* Real */ ae_vector* exxc, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t i; + + + ntotal = nmain+nslack; + for(i=0; i<=ntotal-1; i++) + { + exxc->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nmain-1; i++) + { + exxc->ptr.p_double[i] = sclsftxc->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function estimates Lagrange multipliers for scaled-shifted QP problem +(here "scaled-shifted" means that we performed variable scaling and +subtracted origin) given by quadratic term A, linear term B, box constraints +and linear constraint matrix. + +It is assumed that all linear constraints are equality ones, with first +NEC ones being constraints without slack variables, and next NIC ones +having slack variables. The only inequality constraints we have are box +ones, with first NMain ones being "general" box constraints, and next NIC +ones being non-negativity constraints (not specified explicitly). + +We also make use of the current point XC, which is used to determine active +box constraints. + +Actual QP problem size is NMain+NIC, but some parameters have lower +dimensionality. + +Parameters sizes are: +* A is assumed to be array[NMain,NMain] +* B is assumed to be array[NMain] +* BndL, BndU are array[NMain] +* CLEIC is array[NEC+NIC,NMain+1] (last item in a row containts right part) +* ExXC is array[NMain+NIC], holds current point +* NuLCEst is array[NEC+NIC], holds initial values of Lagrange coeffs + +On exit NuLCEst is updated with new estimate of Lagrange multipliers. + + -- ALGLIB -- + Copyright 23.02.2017 by Bochkanov Sergey +*************************************************************************/ +static void qpdenseaulsolver_updatelagrangemultipliers(/* Real */ const ae_matrix* sclsfta, + /* Real */ const ae_vector* sclsftb, + ae_int_t nmain, + /* Real */ const ae_vector* sclsftbndl, + /* Boolean */ const ae_vector* sclsfthasbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* sclsfthasbndu, + /* Real */ const ae_matrix* sclsftcleic, + ae_int_t sclsftnec, + ae_int_t sclsftnic, + /* Real */ const ae_vector* exxc, + /* Real */ ae_vector* nulcest, + qpdenseaulbuffers* buffers, + ae_state *_state) +{ + ae_int_t nslack; + ae_int_t ntotal; + ae_int_t ktotal; + ae_int_t nqrrows; + ae_int_t nqrcols; + ae_int_t i; + ae_int_t j; + double lambdareg; + double mxdiag; + double v; + ae_bool isactive; + + + nslack = sclsftnic; + ntotal = nmain+nslack; + ktotal = sclsftnec+sclsftnic; + + /* + * Given current point ExXC, we can determine active and inactive + * constraints. After we drop inactive inequality constraints, we + * have equality-only constrained QP problem, with mix of general + * linear equality constraints and "simple" constraints Xi=Ci. + * + * Problem min(0.5*x'*A*x + b'*x) s.t. C*x=d (general linear + * constraints) can be solved by explicitly writing out Lagrange + * equations: + * + * [ A C' ] [ X ] [ -b] + * [ ] [ ] = [ ] + * [ C ] [ L ] [ d ] + * + * or + * + * [ X ] + * A1* [ ] = b1 + * [ L ] + * + * where X stands for solution itself, and L stands for Lagrange + * multipliers. It can be easily solved with direct linear solver. + * However, such formulation does not account for "simple" equality + * constraints on variables. It is possible to include "simple" + * constraints into "general" ones (i.e. append (0 ... 0 -1 0 ... 0)' + * to the constraint matrix), but it will increase problem + * size. + * + * Another approach is to use initial values of X and L (X0 and L0) + * as starting point, and to solve for "offset" from (X0, L0): + * + * [ X0+X1 ] + * A1*[ ] = b1 + * [ L0+L1 ] + * + * or + * + * [ X1 ] [ X0 ] + * A1*[ ] = b1 - A1*[ ] + * [ L1 ] [ L0 ] + * + * In such formulation components of X1 which correspond to active + * constraints on variables are "frozen" at value 0 (because we have + * equality constraint, offset from constrained value have to be zero). + * + * Thus, we can rewrite corresponding columns of A1 with zeros - and + * use this space to store (0 ... 0 -1 0 ... 0)', which is used to + * account for Lagrange multipliers for "simple" constraints. + */ + nqrcols = ntotal+ktotal; + nqrrows = nqrcols; + rvectorsetlengthatleast(&buffers->qrsv0, nqrcols, _state); + rvectorsetlengthatleast(&buffers->qrsvx1, nqrcols, _state); + for(i=0; i<=ntotal-1; i++) + { + buffers->qrsv0.ptr.p_double[i] = exxc->ptr.p_double[i]; + } + for(i=0; i<=ktotal-1; i++) + { + buffers->qrsv0.ptr.p_double[ntotal+i] = nulcest->ptr.p_double[i]; + } + rmatrixsetlengthatleast(&buffers->qrkkt, nqrcols+nqrcols, nqrcols+1, _state); + rvectorsetlengthatleast(&buffers->qrrightpart, nqrcols+nqrcols, _state); + lambdareg = 1.0E-8; + for(;;) + { + + /* + * Initialize matrix A1 and right part b1 with zeros + */ + for(i=0; i<=buffers->qrkkt.rows-1; i++) + { + for(j=0; j<=buffers->qrkkt.cols-1; j++) + { + buffers->qrkkt.ptr.pp_double[i][j] = (double)(0); + } + buffers->qrrightpart.ptr.p_double[i] = (double)(0); + } + + /* + * Append quadratic term (note: we implicitly add NSlack zeros to + * A and b). + */ + mxdiag = (double)(0); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + buffers->qrkkt.ptr.pp_double[i][j] = sclsfta->ptr.pp_double[i][j]; + } + buffers->qrrightpart.ptr.p_double[i] = -sclsftb->ptr.p_double[i]; + mxdiag = ae_maxreal(mxdiag, ae_fabs(sclsfta->ptr.pp_double[i][i], _state), _state); + } + mxdiag = coalesce(mxdiag, (double)(1), _state); + + /* + * Append general linear constraints + */ + for(i=0; i<=ktotal-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + buffers->qrkkt.ptr.pp_double[ntotal+i][j] = -sclsftcleic->ptr.pp_double[i][j]; + buffers->qrkkt.ptr.pp_double[j][ntotal+i] = -sclsftcleic->ptr.pp_double[i][j]; + } + if( i>=sclsftnec ) + { + buffers->qrkkt.ptr.pp_double[ntotal+i][nmain+(i-sclsftnec)] = (double)(-1); + buffers->qrkkt.ptr.pp_double[nmain+(i-sclsftnec)][ntotal+i] = (double)(-1); + } + buffers->qrrightpart.ptr.p_double[ntotal+i] = -sclsftcleic->ptr.pp_double[i][nmain]; + } + + /* + * Append regularizer to the bottom of the matrix + * (it will be factored in during QR decomposition) + */ + if( ae_fp_greater(lambdareg,(double)(0)) ) + { + nqrrows = nqrcols+nqrcols; + for(i=0; i<=nqrcols-1; i++) + { + buffers->qrkkt.ptr.pp_double[nqrcols+i][i] = lambdareg*mxdiag; + } + } + + /* + * Subtract reference point (X0,L0) from the system + */ + for(i=0; i<=nqrcols-1; i++) + { + v = ae_v_dotproduct(&buffers->qrkkt.ptr.pp_double[i][0], 1, &buffers->qrsv0.ptr.p_double[0], 1, ae_v_len(0,nqrcols-1)); + buffers->qrrightpart.ptr.p_double[i] = buffers->qrrightpart.ptr.p_double[i]-v; + } + + /* + * Handle active "simple" equality constraints + */ + for(i=0; i<=ntotal-1; i++) + { + isactive = ae_false; + if( iptr.p_bool[i]&&ae_fp_eq(exxc->ptr.p_double[i],sclsftbndl->ptr.p_double[i]))||(sclsfthasbndu->ptr.p_bool[i]&&ae_fp_eq(exxc->ptr.p_double[i],sclsftbndu->ptr.p_double[i]))) ) + { + isactive = ae_true; + } + if( i>=nmain&&ae_fp_eq(exxc->ptr.p_double[i],0.0) ) + { + isactive = ae_true; + } + if( !isactive ) + { + continue; + } + for(j=0; j<=nqrrows-1; j++) + { + buffers->qrkkt.ptr.pp_double[j][i] = (double)(0); + } + buffers->qrkkt.ptr.pp_double[i][i] = (double)(-1); + } + + /* + * Solve via QR decomposition: + * * append right part to the system matrix + * * perform QR decomposition of the extended matrix (right part is implicitly + * multiplied by Q during decomposition; believe me, it works!) + * * check condition number, increase regularization value if necessary and retry + * * solve triangular system, break iteration + */ + for(i=0; i<=nqrrows-1; i++) + { + buffers->qrkkt.ptr.pp_double[i][nqrcols] = buffers->qrrightpart.ptr.p_double[i]; + } + rmatrixqr(&buffers->qrkkt, nqrrows, nqrcols+1, &buffers->qrtau, _state); + if( ae_fp_less_eq(rmatrixtrrcond1(&buffers->qrkkt, nqrcols, ae_true, ae_false, _state),(double)1000*ae_machineepsilon) ) + { + lambdareg = coalesce((double)10*lambdareg, 1.0E-13, _state); + continue; + } + for(i=nqrcols-1; i>=0; i--) + { + v = buffers->qrkkt.ptr.pp_double[i][nqrcols]; + for(j=i+1; j<=nqrcols-1; j++) + { + v = v-buffers->qrkkt.ptr.pp_double[i][j]*buffers->qrsvx1.ptr.p_double[j]; + } + buffers->qrsvx1.ptr.p_double[i] = v/buffers->qrkkt.ptr.pp_double[i][i]; + } + break; + } + + /* + * Update Lagrange coefficients + */ + for(i=0; i<=ktotal-1; i++) + { + nulcest->ptr.p_double[i] = buffers->qrsv0.ptr.p_double[ntotal+i]+buffers->qrsvx1.ptr.p_double[ntotal+i]; + } +} + + +/************************************************************************* +This function generates scaled (by S) and shifted (by XC) reformulation of +the original problem. + +INPUT PARAMETERS: + DenseA - for dense problems (AKind=0), A-term of CQM object + contains system matrix. Other terms are unspecified + and should not be referenced. + SparseA - for sparse problems (AKind=1), CRS format + AKind - sparse matrix format: + * 0 for dense matrix + * 1 for sparse matrix + SparseUpper - which triangle of SparseAC stores matrix - upper or + lower one (for dense matrices this parameter is not + actual). + B - linear term, array[N] + BndL - lower bound, array[N] + BndU - upper bound, array[N] + S - scale vector, array[NC]: + * I-th element contains scale of I-th variable, + * SC[I]>0 + XOrigin - origin term, array[NC]. Can be zero. + N - number of variables in the original formulation (no + slack variables). + CLEIC - dense linear equality/inequality constraints. Equality + constraints come first. + NEC, NIC - number of dense equality/inequality constraints. + SCLEIC - sparse linear equality/inequality constraints. Equality + constraints come first. + SNEC, SNIC - number of sparse equality/inequality constraints. + RenormLC - whether constraints should be renormalized (recommended) + or used "as is". + Settings - QPDENSEAULSettings object initialized by one of the initialization + functions. + State - object which stores temporaries + XS - initial point, array[NC] + + +On output, following fields of the State structure are modified: +* SclSftA - array[NMain,NMain], quadratic term, both triangles +* SclSftB - array[NMain], linear term +* SclSftXC - array[NMain], initial point +* SclSftHasBndL, + SclSftHasBndU, + SclSftBndL, + SclSftBndU - array[NMain], lower/upper bounds +* SclSftCLEIC - array[KTotal,NMain+1], general linear constraints + +NOTE: State.Tmp2 is used to store temporary array[NMain,NMain] + + -- ALGLIB -- + Copyright 01.10.2017 by Bochkanov Sergey +*************************************************************************/ +static void qpdenseaulsolver_scaleshiftoriginalproblem(const convexquadraticmodel* a, + const sparsematrix* sparsea, + ae_int_t akind, + ae_bool sparseaupper, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nmain, + /* Real */ const ae_matrix* cleic, + ae_int_t dnec, + ae_int_t dnic, + const sparsematrix* scleic, + ae_int_t snec, + ae_int_t snic, + ae_bool renormlc, + qpdenseaulbuffers* state, + /* Real */ ae_vector* xs, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t ktotal; + + + ae_assert(akind==0||akind==1, "QPDENSEAULOptimize: unexpected AKind", _state); + ktotal = dnec+dnic+snec+snic; + rmatrixsetlengthatleast(&state->sclsfta, nmain, nmain, _state); + rvectorsetlengthatleast(&state->sclsftb, nmain, _state); + rvectorsetlengthatleast(&state->sclsftxc, nmain, _state); + rvectorsetlengthatleast(&state->sclsftbndl, nmain, _state); + rvectorsetlengthatleast(&state->sclsftbndu, nmain, _state); + bvectorsetlengthatleast(&state->sclsfthasbndl, nmain, _state); + bvectorsetlengthatleast(&state->sclsfthasbndu, nmain, _state); + rmatrixsetlengthatleast(&state->sclsftcleic, ktotal, nmain+1, _state); + rvectorsetlengthatleast(&state->cscales, ktotal, _state); + if( akind==0 ) + { + + /* + * Extract dense A and scale + */ + cqmgeta(a, &state->tmp2, _state); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + state->sclsfta.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=nmain-1; i++) + { + for(j=i; j<=nmain-1; j++) + { + v = state->tmp2.ptr.pp_double[i][j]*s->ptr.p_double[i]*s->ptr.p_double[j]; + state->sclsfta.ptr.pp_double[i][j] = v; + state->sclsfta.ptr.pp_double[j][i] = v; + } + } + } + if( akind==1 ) + { + + /* + * Extract sparse A and scale + */ + ae_assert(sparsea->matrixtype==1, "QPDENSEAULOptimize: unexpected sparse matrix format", _state); + ae_assert(sparsea->m==nmain, "QPDENSEAULOptimize: unexpected sparse matrix size", _state); + ae_assert(sparsea->n==nmain, "QPDENSEAULOptimize: unexpected sparse matrix size", _state); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + state->sclsfta.ptr.pp_double[i][j] = (double)(0); + } + } + if( sparseaupper ) + { + for(i=0; i<=nmain-1; i++) + { + if( sparsea->didx.ptr.p_int[i]!=sparsea->uidx.ptr.p_int[i] ) + { + state->sclsfta.ptr.pp_double[i][i] = sparsea->vals.ptr.p_double[sparsea->didx.ptr.p_int[i]]*s->ptr.p_double[i]*s->ptr.p_double[i]; + } + j0 = sparsea->uidx.ptr.p_int[i]; + j1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + k = sparsea->idx.ptr.p_int[j]; + v = sparsea->vals.ptr.p_double[j]*s->ptr.p_double[i]*s->ptr.p_double[k]; + state->sclsfta.ptr.pp_double[i][k] = v; + state->sclsfta.ptr.pp_double[k][i] = v; + } + } + } + else + { + for(i=0; i<=nmain-1; i++) + { + if( sparsea->didx.ptr.p_int[i]!=sparsea->uidx.ptr.p_int[i] ) + { + state->sclsfta.ptr.pp_double[i][i] = sparsea->vals.ptr.p_double[sparsea->didx.ptr.p_int[i]]*s->ptr.p_double[i]*s->ptr.p_double[i]; + } + j0 = sparsea->ridx.ptr.p_int[i]; + j1 = sparsea->didx.ptr.p_int[i]-1; + for(j=j0; j<=j1; j++) + { + k = sparsea->idx.ptr.p_int[j]; + v = sparsea->vals.ptr.p_double[j]*s->ptr.p_double[i]*s->ptr.p_double[k]; + state->sclsfta.ptr.pp_double[i][k] = v; + state->sclsfta.ptr.pp_double[k][i] = v; + } + } + } + } + for(i=0; i<=nmain-1; i++) + { + state->sclsftb.ptr.p_double[i] = b->ptr.p_double[i]*s->ptr.p_double[i]; + state->sclsftxc.ptr.p_double[i] = (xs->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + state->sclsfthasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->sclsfthasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + state->sclsftbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->sclsftbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + scaleshiftbcinplace(s, xorigin, &state->sclsftbndl, &state->sclsftbndu, nmain, _state); + for(i=0; i<=ktotal-1; i++) + { + for(j=0; j<=nmain; j++) + { + state->sclsftcleic.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=dnec-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + v = cleic->ptr.pp_double[i][j]*s->ptr.p_double[j]; + state->sclsftcleic.ptr.pp_double[i][j] = v; + } + state->sclsftcleic.ptr.pp_double[i][nmain] = cleic->ptr.pp_double[i][nmain]; + } + for(i=0; i<=dnic-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + v = cleic->ptr.pp_double[dnec+i][j]*s->ptr.p_double[j]; + state->sclsftcleic.ptr.pp_double[dnec+snec+i][j] = v; + } + state->sclsftcleic.ptr.pp_double[dnec+snec+i][nmain] = cleic->ptr.pp_double[dnec+i][nmain]; + } + for(i=0; i<=snec-1; i++) + { + + /* + * Because constraints are sparse, everything is a bit tricky - + * it is possible that N-th element of the row is zero and not + * stored; it is also possible that entire row is empty. + */ + j0 = scleic->ridx.ptr.p_int[i]; + j1 = scleic->ridx.ptr.p_int[i+1]-1; + if( j1>=j0&&scleic->idx.ptr.p_int[j1]==nmain ) + { + state->sclsftcleic.ptr.pp_double[dnec+i][nmain] = scleic->vals.ptr.p_double[j1]; + j1 = j1-1; + } + for(j=j0; j<=j1; j++) + { + k = scleic->idx.ptr.p_int[j]; + v = scleic->vals.ptr.p_double[j]*s->ptr.p_double[k]; + state->sclsftcleic.ptr.pp_double[dnec+i][k] = v; + } + } + for(i=0; i<=snic-1; i++) + { + + /* + * Because constraints are sparse, everything is a bit tricky - + * it is possible that N-th element of the row is zero and not + * stored; it is also possible that entire row is empty. + */ + j0 = scleic->ridx.ptr.p_int[snec+i]; + j1 = scleic->ridx.ptr.p_int[snec+i+1]-1; + if( j1>=j0&&scleic->idx.ptr.p_int[j1]==nmain ) + { + state->sclsftcleic.ptr.pp_double[dnec+snec+dnic+i][nmain] = scleic->vals.ptr.p_double[j1]; + j1 = j1-1; + } + for(j=j0; j<=j1; j++) + { + k = scleic->idx.ptr.p_int[j]; + v = scleic->vals.ptr.p_double[j]*s->ptr.p_double[k]; + state->sclsftcleic.ptr.pp_double[dnec+snec+dnic+i][k] = v; + } + } + if( renormlc&&ktotal>0 ) + { + + /* + * Normalize linear constraints in such way that they have unit norm + * (after variable scaling) + */ + for(i=0; i<=ktotal-1; i++) + { + vv = 0.0; + for(j=0; j<=nmain-1; j++) + { + v = state->sclsftcleic.ptr.pp_double[i][j]; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + state->cscales.ptr.p_double[i] = vv; + if( ae_fp_greater(vv,(double)(0)) ) + { + vv = (double)1/vv; + for(j=0; j<=nmain; j++) + { + state->sclsftcleic.ptr.pp_double[i][j] = state->sclsftcleic.ptr.pp_double[i][j]*vv; + } + } + } + } + else + { + + /* + * Load unit scales + */ + for(i=0; i<=ktotal-1; i++) + { + state->cscales.ptr.p_double[i] = 1.0; + } + } + for(i=0; i<=ktotal-1; i++) + { + + /* + * Apply XOrigin + */ + v = 0.0; + for(j=0; j<=nmain-1; j++) + { + v = v+state->sclsftcleic.ptr.pp_double[i][j]*(xorigin->ptr.p_double[j]/s->ptr.p_double[j]); + } + state->sclsftcleic.ptr.pp_double[i][nmain] = state->sclsftcleic.ptr.pp_double[i][nmain]-v; + } +} + + +/************************************************************************* +Normalize model in such way that norm(A)~1 (very roughly) + +We have two lower bounds for sigma_max(A): +* first estimate is provided by Frobenius norm, it is equal to ANorm/NMain +* second estimate is provided by max(CAC) + +We select largest one of these estimates, because using just one +of them is prone to different failure modes. Then, we divide A and B +by this estimate. + +INPUT PARAMETERS: + A - array[N,N], quadratic term, full triangle is given + B - array[N], linear term + N - problem size + CLEIC- array[NEC+NIC,N+1], linear equality/inequality constraints + NEC - number of equality constraints + NIC - number of inequality constraints + UseCLEIC- additional normalization of A in such way that CLEIC*A*CLEIC'~1: + * if False, CLEIC is ignored + * if True, CLEIC rows MUST have unit norm (we check it) + Tmp2- additional buffer, possibly preallocated + +OUTPUT PARAMETERS: + A, B - appropriately rescaled by 1/SCL + +RESULT: + multiplier SCL + + -- ALGLIB -- + Copyright 01.10.2017 by Bochkanov Sergey +*************************************************************************/ +static double qpdenseaulsolver_normalizequadraticterm(/* Real */ ae_matrix* a, + /* Real */ ae_vector* b, + ae_int_t n, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + ae_bool usecleic, + /* Real */ ae_matrix* tmp2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double anorm; + double maxcac; + double v; + double vv; + ae_int_t ktotal; + ae_int_t nmain; + double result; + + + nmain = n; + ktotal = nec+nic; + anorm = (double)(0); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + anorm = anorm+ae_sqr(a->ptr.pp_double[i][j], _state); + } + } + anorm = ae_sqrt(anorm, _state); + if( usecleic&&ktotal>0 ) + { + + /* + * Calculate max(|diag(C*A*C')|), where C is constraint matrix + */ + rmatrixsetlengthatleast(tmp2, ktotal, nmain, _state); + rmatrixgemm(ktotal, nmain, nmain, 1.0, cleic, 0, 0, 0, a, 0, 0, 0, 0.0, tmp2, 0, 0, _state); + maxcac = 0.0; + for(i=0; i<=ktotal-1; i++) + { + v = (double)(0); + vv = (double)(0); + for(j=0; j<=nmain-1; j++) + { + v = v+tmp2->ptr.pp_double[i][j]*cleic->ptr.pp_double[i][j]; + vv = vv+ae_sqr(cleic->ptr.pp_double[i][j], _state); + } + ae_assert(ae_fp_less(ae_fabs(vv-(double)1, _state),1.0E-9)||ae_fp_eq(vv,(double)(0)), "DENSE-AUL: integrity check failed", _state); + maxcac = ae_maxreal(maxcac, ae_fabs(v, _state), _state); + } + } + else + { + maxcac = (double)(0); + } + result = coalesce(ae_maxreal(maxcac, anorm/(double)nmain, _state), (double)(1), _state); + v = (double)1/result; + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=nmain-1; j++) + { + a->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]*v; + } + } + for(i=0; i<=nmain-1; i++) + { + b->ptr.p_double[i] = b->ptr.p_double[i]*v; + } + return result; +} + + +/************************************************************************* +This function selects initial working set of general inequality constraints +for QP problem: +* for non-convex QP problems - NICWork=NIC is returned +* otherwise - NICWork=0 is returned (we have to + determine working set iteratively) + +INPUT PARAMETERS: + A - array[NMain], quadratic term, full matrix is stored + NMain - number of variables in the "original" QP problem + CLEIC - array[NEC+NIC,NMain+1], constraint matrix + NEC - number of equality constraints + NIC - number of inequality constraints + +OUTPUT PARAMETERS: + NICWork - recommended size of working set; in current version + either all (NICWork=NIC) or none (NICWork=0) constraints + are included. + AllowWSEviction-whether problem properties allow eviction of constraints + from working set or not. Non-convex problems do not + allow eviction, convex ones do. + + -- ALGLIB -- + Copyright 02.10.2017 by Bochkanov Sergey +*************************************************************************/ +static void qpdenseaulsolver_selectinitialworkingset(/* Real */ const ae_matrix* a, + ae_int_t nmain, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + /* Real */ ae_vector* tmp0, + /* Real */ ae_matrix* tmp2, + ae_int_t* nicwork, + ae_bool* allowwseviction, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + *nicwork = 0; + *allowwseviction = ae_false; + + rmatrixsetlengthatleast(tmp2, nmain, nmain, _state); + rvectorsetlengthatleast(tmp0, nmain, _state); + for(i=0; i<=nmain-1; i++) + { + for(j=i; j<=nmain-1; j++) + { + tmp2->ptr.pp_double[i][j] = a->ptr.pp_double[i][j]; + } + } + if( !spdmatrixcholeskyrec(tmp2, 0, nmain, ae_true, tmp0, _state) ) + { + + /* + * Matrix is indefinite. + * + * We have to select full working set, otherwise algorithm may fail + * because problem with reduced working set can be unbounded from below. + */ + *nicwork = nic; + *allowwseviction = ae_false; + } + else + { + + /* + * Positive definite matrix. + * + * We can select zero initial working set and expand it later. + */ + *nicwork = 0; + *allowwseviction = ae_true; + } +} + + +void _qpdenseaulsettings_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + qpdenseaulsettings *p = (qpdenseaulsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qpdenseaulsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + qpdenseaulsettings *dst = (qpdenseaulsettings*)_dst; + const qpdenseaulsettings *src = (const qpdenseaulsettings*)_src; + dst->epsx = src->epsx; + dst->outerits = src->outerits; + dst->rho = src->rho; +} + + +void _qpdenseaulsettings_clear(void* _p) +{ + qpdenseaulsettings *p = (qpdenseaulsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qpdenseaulsettings_destroy(void* _p) +{ + qpdenseaulsettings *p = (qpdenseaulsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _qpdenseaulbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + qpdenseaulbuffers *p = (qpdenseaulbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->nulc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sclsfta, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclsftb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclsfthasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->sclsfthasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->sclsftbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclsftbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclsftxc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->sclsftcleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->cscales, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->exa, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exxc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exscale, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->exxorigin, 0, DT_REAL, _state, make_automatic); + _qqpsettings_init(&p->qqpsettingsuser, _state, make_automatic); + _qqpbuffers_init(&p->qqpbuf, _state, make_automatic); + ae_vector_init(&p->nulcest, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->modelg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic); + _convexquadraticmodel_init(&p->dummycqm, _state, make_automatic); + _sparsematrix_init(&p->dummysparse, _state, make_automatic); + ae_matrix_init(&p->qrkkt, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qrrightpart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qrtau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qrsv0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qrsvx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nicerr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nicnact, 0, DT_INT, _state, make_automatic); +} + + +void _qpdenseaulbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + qpdenseaulbuffers *dst = (qpdenseaulbuffers*)_dst; + const qpdenseaulbuffers *src = (const qpdenseaulbuffers*)_src; + ae_vector_init_copy(&dst->nulc, &src->nulc, _state, make_automatic); + ae_matrix_init_copy(&dst->sclsfta, &src->sclsfta, _state, make_automatic); + ae_vector_init_copy(&dst->sclsftb, &src->sclsftb, _state, make_automatic); + ae_vector_init_copy(&dst->sclsfthasbndl, &src->sclsfthasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->sclsfthasbndu, &src->sclsfthasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->sclsftbndl, &src->sclsftbndl, _state, make_automatic); + ae_vector_init_copy(&dst->sclsftbndu, &src->sclsftbndu, _state, make_automatic); + ae_vector_init_copy(&dst->sclsftxc, &src->sclsftxc, _state, make_automatic); + ae_matrix_init_copy(&dst->sclsftcleic, &src->sclsftcleic, _state, make_automatic); + ae_vector_init_copy(&dst->cidx, &src->cidx, _state, make_automatic); + ae_vector_init_copy(&dst->cscales, &src->cscales, _state, make_automatic); + ae_matrix_init_copy(&dst->exa, &src->exa, _state, make_automatic); + ae_vector_init_copy(&dst->exb, &src->exb, _state, make_automatic); + ae_vector_init_copy(&dst->exxc, &src->exxc, _state, make_automatic); + ae_vector_init_copy(&dst->exbndl, &src->exbndl, _state, make_automatic); + ae_vector_init_copy(&dst->exbndu, &src->exbndu, _state, make_automatic); + ae_vector_init_copy(&dst->exscale, &src->exscale, _state, make_automatic); + ae_vector_init_copy(&dst->exxorigin, &src->exxorigin, _state, make_automatic); + _qqpsettings_init_copy(&dst->qqpsettingsuser, &src->qqpsettingsuser, _state, make_automatic); + _qqpbuffers_init_copy(&dst->qqpbuf, &src->qqpbuf, _state, make_automatic); + ae_vector_init_copy(&dst->nulcest, &src->nulcest, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->modelg, &src->modelg, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic); + _convexquadraticmodel_init_copy(&dst->dummycqm, &src->dummycqm, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysparse, &src->dummysparse, _state, make_automatic); + ae_matrix_init_copy(&dst->qrkkt, &src->qrkkt, _state, make_automatic); + ae_vector_init_copy(&dst->qrrightpart, &src->qrrightpart, _state, make_automatic); + ae_vector_init_copy(&dst->qrtau, &src->qrtau, _state, make_automatic); + ae_vector_init_copy(&dst->qrsv0, &src->qrsv0, _state, make_automatic); + ae_vector_init_copy(&dst->qrsvx1, &src->qrsvx1, _state, make_automatic); + ae_vector_init_copy(&dst->nicerr, &src->nicerr, _state, make_automatic); + ae_vector_init_copy(&dst->nicnact, &src->nicnact, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repncholesky = src->repncholesky; + dst->repnwrkchanges = src->repnwrkchanges; + dst->repnwrk0 = src->repnwrk0; + dst->repnwrk1 = src->repnwrk1; + dst->repnwrkf = src->repnwrkf; + dst->repnmv = src->repnmv; +} + + +void _qpdenseaulbuffers_clear(void* _p) +{ + qpdenseaulbuffers *p = (qpdenseaulbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->nulc); + ae_matrix_clear(&p->sclsfta); + ae_vector_clear(&p->sclsftb); + ae_vector_clear(&p->sclsfthasbndl); + ae_vector_clear(&p->sclsfthasbndu); + ae_vector_clear(&p->sclsftbndl); + ae_vector_clear(&p->sclsftbndu); + ae_vector_clear(&p->sclsftxc); + ae_matrix_clear(&p->sclsftcleic); + ae_vector_clear(&p->cidx); + ae_vector_clear(&p->cscales); + ae_matrix_clear(&p->exa); + ae_vector_clear(&p->exb); + ae_vector_clear(&p->exxc); + ae_vector_clear(&p->exbndl); + ae_vector_clear(&p->exbndu); + ae_vector_clear(&p->exscale); + ae_vector_clear(&p->exxorigin); + _qqpsettings_clear(&p->qqpsettingsuser); + _qqpbuffers_clear(&p->qqpbuf); + ae_vector_clear(&p->nulcest); + ae_vector_clear(&p->tmpg); + ae_vector_clear(&p->tmp0); + ae_matrix_clear(&p->tmp2); + ae_vector_clear(&p->modelg); + ae_vector_clear(&p->d); + ae_vector_clear(&p->deltax); + _convexquadraticmodel_clear(&p->dummycqm); + _sparsematrix_clear(&p->dummysparse); + ae_matrix_clear(&p->qrkkt); + ae_vector_clear(&p->qrrightpart); + ae_vector_clear(&p->qrtau); + ae_vector_clear(&p->qrsv0); + ae_vector_clear(&p->qrsvx1); + ae_vector_clear(&p->nicerr); + ae_vector_clear(&p->nicnact); +} + + +void _qpdenseaulbuffers_destroy(void* _p) +{ + qpdenseaulbuffers *p = (qpdenseaulbuffers*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->nulc); + ae_matrix_destroy(&p->sclsfta); + ae_vector_destroy(&p->sclsftb); + ae_vector_destroy(&p->sclsfthasbndl); + ae_vector_destroy(&p->sclsfthasbndu); + ae_vector_destroy(&p->sclsftbndl); + ae_vector_destroy(&p->sclsftbndu); + ae_vector_destroy(&p->sclsftxc); + ae_matrix_destroy(&p->sclsftcleic); + ae_vector_destroy(&p->cidx); + ae_vector_destroy(&p->cscales); + ae_matrix_destroy(&p->exa); + ae_vector_destroy(&p->exb); + ae_vector_destroy(&p->exxc); + ae_vector_destroy(&p->exbndl); + ae_vector_destroy(&p->exbndu); + ae_vector_destroy(&p->exscale); + ae_vector_destroy(&p->exxorigin); + _qqpsettings_destroy(&p->qqpsettingsuser); + _qqpbuffers_destroy(&p->qqpbuf); + ae_vector_destroy(&p->nulcest); + ae_vector_destroy(&p->tmpg); + ae_vector_destroy(&p->tmp0); + ae_matrix_destroy(&p->tmp2); + ae_vector_destroy(&p->modelg); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->deltax); + _convexquadraticmodel_destroy(&p->dummycqm); + _sparsematrix_destroy(&p->dummysparse); + ae_matrix_destroy(&p->qrkkt); + ae_vector_destroy(&p->qrrightpart); + ae_vector_destroy(&p->qrtau); + ae_vector_destroy(&p->qrsv0); + ae_vector_destroy(&p->qrsvx1); + ae_vector_destroy(&p->nicerr); + ae_vector_destroy(&p->nicnact); +} + + +#endif +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +The solver is configured to work internally with dense NxN factorization, +no matter what exactly is passed - dense or sparse matrices. + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + + The terms A and b (as well as constraints) will be + specified later with separate calls. + N - vars count, N>=1 + Normalize - apply normalization to target/constraints or not: + * if True, then target and constraints are normalized + to unit scale + * if False, it is assumed that the caller has performed + normalization. + The latter is recommended for presolved problems. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipminitdense(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_bool normalize, + ae_state *_state) +{ + + + ae_assert(n>=1, "VIPMInitDense: N<1", _state); + ae_assert(isfinitevector(s, n, _state), "VIPMInitDense: S contains infinite or NaN elements", _state); + ae_assert(isfinitevector(xorigin, n, _state), "VIPMInitDense: XOrigin contains infinite or NaN elements", _state); + vipmsolver_vipminit(state, s, xorigin, n, n, 0, normalize, _state); +} + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +The solver is configured to work internally with dense NxN problem divided +into two distinct parts - "main" and slack one: +* dense quadratic term is a NMain*NMain matrix (NMain<=N), quadratic + coefficients are zero for variables outside of [0,NMain) range) +* linear term is general vector of length N +* linear constraints have special structure for variable with indexes in + [NMain,N) range: at most one element per column can be nonzero. + +This mode is intended for problems arising during SL1QP nonlinear programming. + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + + The terms A and b (as well as constraints) will be + specified later with separate calls. + NMain - number of "main" variables, 1<=NMain<=N + N - total number of variables including slack ones + Normalize - apply normalization to target/constraints or not: + * if True, then target and constraints are normalized + to unit scale + * if False, it is assumed that the caller has performed + normalization. + The latter is recommended for presolved problems. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipminitdensewithslacks(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nmain, + ae_int_t n, + ae_bool normalize, + ae_state *_state) +{ + + + ae_assert(nmain>=1, "VIPMInitDense: NMain<1", _state); + ae_assert(n>=1, "VIPMInitDense: N<1", _state); + ae_assert(nmain<=n, "VIPMInitDense: NMain>N", _state); + ae_assert(isfinitevector(s, n, _state), "VIPMInitDense: S contains infinite or NaN elements", _state); + ae_assert(isfinitevector(xorigin, n, _state), "VIPMInitDense: XOrigin contains infinite or NaN elements", _state); + vipmsolver_vipminit(state, s, xorigin, n, nmain, 0, normalize, _state); +} + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +The solver is configured to work internally with sparse (N+M)x(N+M) +factorization no matter what exactly is passed - dense or sparse matrices. +Dense quadratic term will be sparsified prior to storage. + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + The terms A and b (as well as constraints) will be + specified later with separate calls. + N - total number of variables, N>=1 + Normalize - apply normalization to target/constraints or not: + * if True, then target and constraints are normalized + to unit scale + * if False, it is assumed that the caller has performed + normalization. + The latter is recommended for presolved problems. + +This optimization mode assumes that no slack variables is present. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipminitsparse(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_bool normalize, + ae_state *_state) +{ + + + ae_assert(n>=1, "VIPMInitSparse: N<1", _state); + ae_assert(isfinitevector(s, n, _state), "VIPMInitSparse: S contains infinite or NaN elements", _state); + ae_assert(isfinitevector(xorigin, n, _state), "VIPMInitSparse: XOrigin contains infinite or NaN elements", _state); + vipmsolver_vipminit(state, s, xorigin, n, n, 1, normalize, _state); +} + + +/************************************************************************* +Sets linear/quadratic terms for QP-IPM solver + +If you initialized solver with VIMPInitDenseWithSlacks(), NMain below is a +number of non-slack variables. In other cases, NMain=N. + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + DenseH - if HKind=0: array[NMain,NMain], dense quadratic term + (either upper or lower triangle) + SparseH - if HKind=1: array[NMain,NMain], sparse quadratic term + (either upper or lower triangle) + HKind - 0 or 1, quadratic term format + IsUpper - whether dense/sparse H contains lower or upper + triangle of the quadratic term + C - array[N], linear term + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipmsetquadraticlinear(vipmstate* state, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ const ae_vector* c, + ae_state *_state) +{ + ae_int_t nmain; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t nnz; + ae_int_t offs; + + + nmain = state->nmain; + n = state->n; + ae_assert(hkind==0||hkind==1, "VIPMSetQuadraticLinear: incorrect HKind", _state); + ae_assert(isfinitevector(c, n, _state), "VIPMSetQuadraticLinear: C contains infinite or NaN elements", _state); + ae_assert(state->factorizationtype==0||state->factorizationtype==1, "VIPMSetQuadraticLinear: unexpected factorization type", _state); + + /* + * Set problem info, reset factorization flag + */ + state->islinear = ae_false; + state->factorizationpresent = ae_false; + state->factorizationpoweredup = ae_false; + + /* + * Linear term + */ + rvectorsetlengthatleast(&state->c, n, _state); + rvectorcopy(n, c, 0, &state->c, 0, _state); + + /* + * Quadratic term and normalization + * + * NOTE: we perform integrity check for inifinities/NANs by + * computing sum of all matrix elements and checking its + * value for being finite. It is a bit faster than checking + * each element individually. + */ + state->hkind = -1; + state->targetscale = 1.0; + if( state->factorizationtype==0 ) + { + + /* + * Quadratic term is stored in dense format: either copy dense + * term of densify sparse one + */ + state->hkind = 0; + rmatrixsetlengthatleast(&state->denseh, nmain, nmain, _state); + if( hkind==0 ) + { + + /* + * Copy dense quadratic term + */ + if( isupper ) + { + rmatrixtranspose(nmain, nmain, denseh, 0, 0, &state->denseh, 0, 0, _state); + } + else + { + rmatrixcopy(nmain, nmain, denseh, 0, 0, &state->denseh, 0, 0, _state); + } + } + if( hkind==1 ) + { + + /* + * Extract sparse quadratic term + */ + ae_assert(sparseh->matrixtype==1, "VIPMSetQuadraticLinear: unexpected sparse matrix format", _state); + ae_assert(sparseh->m==nmain, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + ae_assert(sparseh->n==nmain, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=i; j++) + { + state->denseh.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=nmain-1; i++) + { + + /* + * diagonal element + */ + if( sparseh->didx.ptr.p_int[i]!=sparseh->uidx.ptr.p_int[i] ) + { + state->denseh.ptr.pp_double[i][i] = sparseh->vals.ptr.p_double[sparseh->didx.ptr.p_int[i]]; + } + + /* + * Off-diagonal elements + */ + if( isupper ) + { + + /* + * superdiagonal elements are moved to subdiagonal part + */ + j0 = sparseh->uidx.ptr.p_int[i]; + j1 = sparseh->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->denseh.ptr.pp_double[sparseh->idx.ptr.p_int[j]][i] = sparseh->vals.ptr.p_double[j]; + } + } + else + { + + /* + * subdiagonal elements are moved to subdiagonal part + */ + j0 = sparseh->ridx.ptr.p_int[i]; + j1 = sparseh->didx.ptr.p_int[i]-1; + for(j=j0; j<=j1; j++) + { + state->denseh.ptr.pp_double[i][sparseh->idx.ptr.p_int[j]] = sparseh->vals.ptr.p_double[j]; + } + } + } + } + vv = (double)(0); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=i; j++) + { + vv = vv+state->denseh.ptr.pp_double[i][j]; + } + } + ae_assert(ae_isfinite(vv, _state), "VIPMSetQuadraticLinear: DenseH contains infinite or NaN values!", _state); + scaledenseqpinplace(&state->denseh, ae_false, nmain, &state->c, n, &state->scl, _state); + if( state->normalize ) + { + state->targetscale = normalizedenseqpinplace(&state->denseh, ae_false, nmain, &state->c, n, _state); + } + state->isdiagonalh = ae_false; + } + if( state->factorizationtype==1 ) + { + ae_assert(nmain==n, "VIPMSetQuadraticLinear: critical integrity check failed, NMain!=N", _state); + + /* + * Quadratic term is stored in sparse format: either sparsify dense + * term or copy the sparse one + */ + state->hkind = 1; + state->sparseh.matrixtype = 1; + state->sparseh.m = n; + state->sparseh.n = n; + if( hkind==0 ) + { + + /* + * Sparsify dense term + */ + nnz = 0; + for(i=0; i<=n-1; i++) + { + nnz = nnz+1; + if( isupper ) + { + j0 = i+1; + j1 = n-1; + } + else + { + j0 = 0; + j1 = i-1; + } + for(j=j0; j<=j1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + nnz = nnz+1; + } + } + } + ivectorsetlengthatleast(&state->sparseh.ridx, n+1, _state); + ivectorsetlengthatleast(&state->sparseh.idx, nnz, _state); + rvectorsetlengthatleast(&state->sparseh.vals, nnz, _state); + state->sparseh.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=n-1; i++) + { + + /* + * Off-diagonal elements are copied only when nonzero + */ + if( !isupper ) + { + for(j=0; j<=i-1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + v = denseh->ptr.pp_double[i][j]; + state->sparseh.idx.ptr.p_int[offs] = j; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + } + + /* + * Diagonal element is always copied + */ + v = denseh->ptr.pp_double[i][i]; + state->sparseh.idx.ptr.p_int[offs] = i; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + + /* + * Off-diagonal elements are copied only when nonzero + */ + if( isupper ) + { + for(j=i+1; j<=n-1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + v = denseh->ptr.pp_double[i][j]; + state->sparseh.idx.ptr.p_int[offs] = j; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + } + + /* + * Finalize row + */ + state->sparseh.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "VIPMSetQuadraticLinear: DenseH contains infinite or NaN values!", _state); + ae_assert(offs==nnz, "VIPMSetQuadraticLinear: integrity check failed", _state); + sparsecreatecrsinplace(&state->sparseh, _state); + } + if( hkind==1 ) + { + + /* + * Copy sparse quadratic term, but make sure that we have diagonal elements + * present (we add diagonal if it is not present) + */ + ae_assert(sparseh->matrixtype==1, "VIPMSetQuadraticLinear: unexpected sparse matrix format", _state); + ae_assert(sparseh->m==n, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + ae_assert(sparseh->n==n, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + ivectorsetlengthatleast(&state->sparseh.ridx, n+1, _state); + ivectorsetlengthatleast(&state->sparseh.idx, sparseh->ridx.ptr.p_int[n]+n, _state); + rvectorsetlengthatleast(&state->sparseh.vals, sparseh->ridx.ptr.p_int[n]+n, _state); + state->sparseh.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=n-1; i++) + { + + /* + * Copy subdiagonal elements (if needed) + */ + if( !isupper ) + { + j0 = sparseh->ridx.ptr.p_int[i]; + j1 = sparseh->didx.ptr.p_int[i]-1; + for(k=j0; k<=j1; k++) + { + v = sparseh->vals.ptr.p_double[k]; + state->sparseh.idx.ptr.p_int[offs] = sparseh->idx.ptr.p_int[k]; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + + /* + * Diagonal element is always copied + */ + v = (double)(0); + if( sparseh->uidx.ptr.p_int[i]!=sparseh->didx.ptr.p_int[i] ) + { + v = sparseh->vals.ptr.p_double[sparseh->didx.ptr.p_int[i]]; + } + state->sparseh.idx.ptr.p_int[offs] = i; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + + /* + * Copy superdiagonal elements (if needed) + */ + if( isupper ) + { + j0 = sparseh->uidx.ptr.p_int[i]; + j1 = sparseh->ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + v = sparseh->vals.ptr.p_double[k]; + state->sparseh.idx.ptr.p_int[offs] = sparseh->idx.ptr.p_int[k]; + state->sparseh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + + /* + * Finalize row + */ + state->sparseh.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "VIPMSetQuadraticLinear: SparseH contains infinite or NaN values!", _state); + ae_assert(offs<=state->sparseh.vals.cnt&&offs<=state->sparseh.idx.cnt, "VIPMSetQuadraticLinear: integrity check failed", _state); + sparsecreatecrsinplace(&state->sparseh, _state); + } + if( isupper ) + { + sparsecopytransposecrsbuf(&state->sparseh, &state->tmpsparse0, _state); + sparsecopybuf(&state->tmpsparse0, &state->sparseh, _state); + } + + /* + * Finalize + */ + scalesparseqpinplace(&state->scl, n, &state->sparseh, &state->tmpr2, &state->dummyr, 0, &state->c, _state); + if( state->normalize ) + { + state->targetscale = normalizesparseqpinplace(&state->sparseh, ae_false, &state->tmpr2, &state->dummyr, 0, &state->c, n, _state); + } + state->isdiagonalh = state->sparseh.ridx.ptr.p_int[n]==n; + } + ae_assert(state->hkind>=0, "VIPMSetQuadraticLinear: integrity check failed", _state); +} + + +/************************************************************************* +Sets constraints for QP-IPM solver + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + BndL, BndU - lower and upper bound. BndL[] can be -INF, + BndU[] can be +INF. + SparseA - sparse constraint matrix, CRS format + MSparse - number of sparse constraints + DenseA - array[MDense,N], dense part of the constraints + MDense - number of dense constraints + CL, CU - lower and upper bounds for constraints, first + MSparse are bounds for sparse part, following + MDense ones are bounds for dense part, + MSparse+MDense in total. + -INF <= CL[I] <= CU[I] <= +INF. + +This function throws exception if constraints have inconsistent bounds, i.e. +either BndL[I]>BndU[I] or CL[I]>CU[I]. In all other cases it succeeds. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipmsetconstraints(vipmstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ const ae_matrix* densea, + ae_int_t mdense, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_state *_state) +{ + ae_int_t m; + ae_int_t n; + ae_int_t nmain; + ae_int_t nslack; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t offsmain; + ae_int_t offscombined; + double vs; + double v; + + + n = state->n; + nmain = state->nmain; + nslack = n-nmain; + ae_assert(mdense>=0, "VIPMSetConstraints: MDense<0", _state); + ae_assert(msparse>=0, "VIPMSetConstraints: MSparse<0", _state); + ae_assert(apservisfinitematrix(densea, mdense, n, _state), "VIPMSetConstraints: DenseA contains infinite or NaN values!", _state); + ae_assert(msparse==0||sparsea->matrixtype==1, "VIPMSetConstraints: non-CRS constraint matrix!", _state); + ae_assert(msparse==0||(sparsea->m==msparse&&sparsea->n==n), "VIPMSetConstraints: constraint matrix has incorrect size", _state); + ae_assert(cl->cnt>=mdense+msparse, "VIPMSetConstraints: CL is too short!", _state); + ae_assert(cu->cnt>=mdense+msparse, "VIPMSetConstraints: CU is too short!", _state); + + /* + * Reset factorization flag + */ + state->factorizationpresent = ae_false; + state->factorizationpoweredup = ae_false; + + /* + * Box constraints + */ + rvectorsetlengthatleast(&state->bndl, n, _state); + rvectorsetlengthatleast(&state->bndu, n, _state); + rvectorsetlengthatleast(&state->rawbndl, n, _state); + rvectorsetlengthatleast(&state->rawbndu, n, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + ae_assert(!((state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i])), "VIPMInitDenseQuadratic: inconsistent range for box constraints", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->rawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->rawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + scaleshiftbcinplace(&state->scl, &state->xorigin, &state->bndl, &state->bndu, n, _state); + + /* + * Linear constraints (full matrices) + */ + m = mdense+msparse; + rvectorsetlengthatleast(&state->b, m, _state); + rvectorsetlengthatleast(&state->r, m, _state); + rvectorsetlengthatleast(&state->ascales, m, _state); + bvectorsetlengthatleast(&state->aflips, m, _state); + bvectorsetlengthatleast(&state->hasr, m, _state); + rmatrixsetlengthatleast(&state->denseafull, mdense, n, _state); + if( msparse>0 ) + { + sparsecopytocrsbuf(sparsea, &state->sparseafull, _state); + } + if( mdense>0 ) + { + rmatrixcopy(mdense, n, densea, 0, 0, &state->denseafull, 0, 0, _state); + } + for(i=0; i<=m-1; i++) + { + ae_assert(ae_isfinite(cl->ptr.p_double[i], _state)||ae_isneginf(cl->ptr.p_double[i], _state), "VIPMInitDenseQuadratic: CL is not finite number or -INF", _state); + ae_assert(ae_isfinite(cu->ptr.p_double[i], _state)||ae_isposinf(cu->ptr.p_double[i], _state), "VIPMInitDenseQuadratic: CU is not finite number or +INF", _state); + + /* + * Store range + */ + if( ae_isfinite(cl->ptr.p_double[i], _state)||ae_isfinite(cu->ptr.p_double[i], _state) ) + { + + /* + * Non-degenerate constraint, at least one of bounds is present + */ + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + ae_assert(!ae_isfinite(cu->ptr.p_double[i], _state)||ae_fp_greater_eq(cu->ptr.p_double[i],cl->ptr.p_double[i]), "VIPMInitDenseQuadratic: inconsistent range (right-hand side) for linear constraint", _state); + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + + /* + * We have both CL and CU, i.e. CL <= A*x <= CU. + * + * It can be either equality constraint (no slacks) or range constraint + * (two pairs of slacks variables). + * + * Try to arrange things in such a way that |CU|>=|CL| (it can be done + * by multiplication by -1 and boundaries swap). + * + * Having |CU|>=|CL| will allow us to drop huge irrelevant bound CU, + * if we find it irrelevant during computations. Due to limitations + * of our slack variable substitution, it can be done only for CU. + */ + if( ae_fp_greater_eq(ae_fabs(cu->ptr.p_double[i], _state),ae_fabs(cl->ptr.p_double[i], _state)) ) + { + state->b.ptr.p_double[i] = cl->ptr.p_double[i]; + state->r.ptr.p_double[i] = cu->ptr.p_double[i]-cl->ptr.p_double[i]; + state->hasr.ptr.p_bool[i] = ae_true; + state->aflips.ptr.p_bool[i] = ae_false; + vs = (double)(1); + } + else + { + state->b.ptr.p_double[i] = -cu->ptr.p_double[i]; + state->r.ptr.p_double[i] = cu->ptr.p_double[i]-cl->ptr.p_double[i]; + state->hasr.ptr.p_bool[i] = ae_true; + state->aflips.ptr.p_bool[i] = ae_true; + vs = (double)(-1); + } + } + else + { + + /* + * Only lower bound: CL <= A*x. + * + * One pair of slack variables added. + */ + state->b.ptr.p_double[i] = cl->ptr.p_double[i]; + state->r.ptr.p_double[i] = _state->v_posinf; + state->hasr.ptr.p_bool[i] = ae_false; + state->aflips.ptr.p_bool[i] = ae_false; + vs = (double)(1); + } + } + else + { + + /* + * Only upper bound: A*x <= CU + * + * One pair of slack variables added. + */ + state->b.ptr.p_double[i] = -cu->ptr.p_double[i]; + state->r.ptr.p_double[i] = _state->v_posinf; + state->hasr.ptr.p_bool[i] = ae_false; + state->aflips.ptr.p_bool[i] = ae_true; + vs = (double)(-1); + } + } + else + { + + /* + * Degenerate constraint -inf <= Ax <= +inf. + * Generate dummy formulation. + */ + state->b.ptr.p_double[i] = (double)(-1); + state->r.ptr.p_double[i] = (double)(2); + state->hasr.ptr.p_bool[i] = ae_true; + state->aflips.ptr.p_bool[i] = ae_false; + vs = (double)(0); + } + + /* + * Store matrix row and its scaling coefficient + */ + if( isparseafull.ridx.ptr.p_int[i]; + j1 = state->sparseafull.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->sparseafull.vals.ptr.p_double[j] = state->sparseafull.vals.ptr.p_double[j]*vs; + } + } + else + { + for(j=0; j<=n-1; j++) + { + state->denseafull.ptr.pp_double[i-msparse][j] = state->denseafull.ptr.pp_double[i-msparse][j]*vs; + } + } + state->ascales.ptr.p_double[i] = vs; + } + scaleshiftmixedbrlcinplace(&state->scl, &state->xorigin, n, &state->sparseafull, msparse, &state->denseafull, mdense, &state->b, &state->r, _state); + if( state->normalize ) + { + normalizemixedbrlcinplace(&state->sparseafull, msparse, &state->denseafull, mdense, &state->b, &state->r, n, ae_true, &state->tmp0, ae_true, _state); + for(i=0; i<=m-1; i++) + { + state->ascales.ptr.p_double[i] = state->ascales.ptr.p_double[i]*state->tmp0.ptr.p_double[i]; + } + } + state->mdense = mdense; + state->msparse = msparse; + + /* + * Separate main and slack parts of the constraint matrices + */ + ivectorsetlengthatleast(&state->tmpi, nslack, _state); + for(i=0; i<=nslack-1; i++) + { + state->tmpi.ptr.p_int[i] = 0; + } + state->combinedaslack.m = mdense+msparse; + state->combinedaslack.n = nslack; + ivectorsetlengthatleast(&state->combinedaslack.ridx, mdense+msparse+1, _state); + ivectorsetlengthatleast(&state->combinedaslack.idx, nslack, _state); + rvectorsetlengthatleast(&state->combinedaslack.vals, nslack, _state); + state->combinedaslack.ridx.ptr.p_int[0] = 0; + state->sparseamain.m = msparse; + state->sparseamain.n = nmain; + if( msparse>0 ) + { + ivectorsetlengthatleast(&state->sparseamain.ridx, msparse+1, _state); + ivectorsetlengthatleast(&state->sparseamain.idx, sparsea->ridx.ptr.p_int[msparse], _state); + rvectorsetlengthatleast(&state->sparseamain.vals, sparsea->ridx.ptr.p_int[msparse], _state); + state->sparseamain.ridx.ptr.p_int[0] = 0; + for(i=0; i<=msparse-1; i++) + { + offsmain = state->sparseamain.ridx.ptr.p_int[i]; + offscombined = state->combinedaslack.ridx.ptr.p_int[i]; + j0 = state->sparseafull.ridx.ptr.p_int[i]; + j1 = state->sparseafull.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + v = state->sparseafull.vals.ptr.p_double[j]; + k = state->sparseafull.idx.ptr.p_int[j]; + if( ksparseamain.idx.ptr.p_int[offsmain] = k; + state->sparseamain.vals.ptr.p_double[offsmain] = v; + offsmain = offsmain+1; + } + else + { + ae_assert(state->tmpi.ptr.p_int[k-nmain]==0, "VIPMSetConstraints: slack column contains more than one nonzero element", _state); + state->combinedaslack.idx.ptr.p_int[offscombined] = k-nmain; + state->combinedaslack.vals.ptr.p_double[offscombined] = v; + state->tmpi.ptr.p_int[k-nmain] = state->tmpi.ptr.p_int[k-nmain]+1; + offscombined = offscombined+1; + } + } + state->sparseamain.ridx.ptr.p_int[i+1] = offsmain; + state->combinedaslack.ridx.ptr.p_int[i+1] = offscombined; + } + } + sparsecreatecrsinplace(&state->sparseamain, _state); + if( mdense>0 ) + { + rmatrixsetlengthatleast(&state->denseamain, mdense, nmain, _state); + rmatrixcopy(mdense, nmain, &state->denseafull, 0, 0, &state->denseamain, 0, 0, _state); + for(i=0; i<=mdense-1; i++) + { + offscombined = state->combinedaslack.ridx.ptr.p_int[msparse+i]; + for(k=nmain; k<=n-1; k++) + { + if( state->denseafull.ptr.pp_double[i][k]!=(double)0 ) + { + ae_assert(state->tmpi.ptr.p_int[k-nmain]==0, "VIPMSetConstraints: slack column contains more than one nonzero element", _state); + state->combinedaslack.idx.ptr.p_int[offscombined] = k-nmain; + state->combinedaslack.vals.ptr.p_double[offscombined] = state->denseafull.ptr.pp_double[i][k]; + state->tmpi.ptr.p_int[k-nmain] = state->tmpi.ptr.p_int[k-nmain]+1; + offscombined = offscombined+1; + } + } + state->combinedaslack.ridx.ptr.p_int[msparse+i+1] = offscombined; + } + } + sparsecreatecrsinplace(&state->combinedaslack, _state); +} + + +/************************************************************************* +Sets stopping criteria for QP-IPM solver. + +You can set all epsilon-values to one small value, about 1.0E-6. + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + EpsP - maximum primal error allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + EpsD - maximum dual error allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + EpsGap - maximum duality gap allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipmsetcond(vipmstate* state, + double epsp, + double epsd, + double epsgap, + ae_state *_state) +{ + double sml; + + + ae_assert(ae_isfinite(epsp, _state)&&ae_fp_greater_eq(epsp,(double)(0)), "VIPMSetCond: EpsP is infinite or negative", _state); + ae_assert(ae_isfinite(epsd, _state)&&ae_fp_greater_eq(epsd,(double)(0)), "VIPMSetCond: EpsD is infinite or negative", _state); + ae_assert(ae_isfinite(epsgap, _state)&&ae_fp_greater_eq(epsgap,(double)(0)), "VIPMSetCond: EpsP is infinite or negative", _state); + sml = ae_sqrt(ae_machineepsilon, _state); + state->epsp = coalesce(epsp, sml, _state); + state->epsd = coalesce(epsd, sml, _state); + state->epsgap = coalesce(epsgap, sml, _state); +} + + +/************************************************************************* +Solve QP problem. + +INPUT PARAMETERS: + State - solver instance + DropBigBounds - If True, algorithm may drop box and linear constraints + with huge bound values that destabilize algorithm. + +OUTPUT PARAMETERS: + XS - array[N], solution + LagBC - array[N], Lagrange multipliers for box constraints + LagLC - array[M], Lagrange multipliers for linear constraints + TerminationType - completion code, positive values for success, + negative for failures (XS constrains best point + found so far): + * -2 the task is either unbounded or infeasible; + the IPM solver has difficulty distinguishing between these two. + * +1 stopping criteria are met + * +7 stopping criteria are too stringent + +RESULT: + +This function ALWAYS returns something meaningful in XS, LagBC, LagLC - +either solution or the best point so far, even for negative TerminationType. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void vipmoptimize(vipmstate* state, + ae_bool dropbigbounds, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t iteridx; + double mu; + double muaff; + double sigma; + double alphaaffp; + double alphaaffd; + double alphap; + double alphad; + ae_int_t primalstagnationcnt; + ae_int_t dualstagnationcnt; + double regeps; + double regeps0; + double regeps1; + double dampeps; + double safedampeps; + double modeps; + double maxdampeps; + double regfree; + double dampfree; + ae_int_t droppedbounds; + double primalxscale; + double errp2; + double errd2; + double errpinf; + double errdinf; + double preverrp2; + double preverrd2; + double errgap; + double eprimal; + double edual; + double egap; + double mumin; + double mustop; + double y0nrm; + double bady; + double mxprimal; + double mxdeltaprimal; + ae_int_t bestiteridx; + double besterr; + double bestegap; + double besteprimal; + double bestedual; + ae_bool loadbest; + + *terminationtype = 0; + + n = state->n; + m = state->mdense+state->msparse; + state->dotrace = ae_is_trace_enabled("IPM"); + state->dodetailedtrace = state->dotrace&&ae_is_trace_enabled("IPM.DETAILED"); + + /* + * Prepare outputs + */ + rsetallocv(n, 0.0, xs, _state); + rsetallocv(n, 0.0, lagbc, _state); + rsetallocv(m, 0.0, laglc, _state); + + /* + * Some integrity checks: + * * we need PrimalStagnationLendotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// IPM SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Prepare regularization coefficients: + * * RegEps - one that is applied to initial (5N+5M)x(5N+5M) KKT system. This one has to be + * small because it perturbs solution returned by the algorithm. Essential in order to + * avoid stalling at extremely large points. + * * ModEps - small modification applied to LDLT decomposition in order to preserve sign + * of diagonal elements + * * DampEps - damping coefficient for damped Newton step. Comes along with SafeDampEps + * (threshold value when some safeguards are turned off in order to preserve convergence + * speed) and MaxDampEps - threshold value when we consider problem overregularized and stop. + * * DampFree - additional damping coefficient for free variables + */ + regfree = ae_pow(ae_machineepsilon, 0.75, _state); + dampfree = (double)(0); + regeps0 = ae_sqrt(ae_machineepsilon, _state); + regeps1 = (double)10*ae_machineepsilon; + regeps = regeps0; + modeps = ((double)100+ae_sqrt((double)(n), _state))*ae_machineepsilon; + dampeps = (double)10*ae_machineepsilon; + safedampeps = ae_sqrt(ae_machineepsilon, _state); + maxdampeps = ae_sqrt(ae_sqrt(ae_machineepsilon, _state), _state); + + /* + * Set up initial state + */ + state->repiterationscount = 0; + state->repncholesky = 0; + mustop = ((double)100+ae_sqrt((double)(n), _state))*ae_machineepsilon; + mumin = 0.01*mustop; + vipmsolver_vipmpowerup(state, regfree, _state); + vipmsolver_varsinitfrom(&state->best, &state->current, _state); + vipmsolver_varsinitbyzero(&state->zerovars, n, m, _state); + vipmsolver_varsinitbyzero(&state->deltaaff, n, m, _state); + vipmsolver_varsinitbyzero(&state->deltacorr, n, m, _state); + bestiteridx = -1; + besterr = ae_maxrealnumber; + bestegap = ae_maxrealnumber; + besteprimal = ae_maxrealnumber; + bestedual = ae_maxrealnumber; + vipmsolver_traceprogress(state, 0.0, 0.0, 0.0, 0.0, 0.0, _state); + y0nrm = (double)(0); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(m, &state->current.y, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(m, &state->current.v, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(m, &state->current.q, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(n, &state->current.z, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(n, &state->current.s, _state), _state); + + /* + * Start iteration + */ + loadbest = ae_true; + primalstagnationcnt = 0; + dualstagnationcnt = 0; + *terminationtype = 7; + errp2 = ae_maxrealnumber; + errd2 = ae_maxrealnumber; + for(iteridx=0; iteridx<=vipmsolver_maxipmits-1; iteridx++) + { + regeps = rcase2(iteridxdotrace ) + { + ae_trace("=== PREDICTOR-CORRECTOR STEP %2d ====================================================================\n", + (int)(iteridx)); + } + + /* + * Check regularization status, terminate if overregularized + */ + if( ae_fp_greater_eq(dampeps,maxdampeps) ) + { + if( state->dotrace ) + { + ae_trace("> tried to increase regularization parameter, but it is too large\n"); + ae_trace("> it is likely that stopping conditions are too stringent, stopping at the best point found so far\n"); + } + *terminationtype = 7; + break; + } + + /* + * Precompute factorization + * + * NOTE: we use "solver" regularization coefficient at this moment + */ + if( !vipmsolver_vipmprecomputenewtonfactorization(state, &state->current, regeps, modeps, dampeps, dampfree, _state) ) + { + + /* + * KKT factorization failed. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> LDLT factorization failed due to rounding errors\n"); + ae_trace("> increasing damping coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + + /* + * Compute Mu + */ + mu = vipmsolver_varscomputemu(state, &state->current, _state); + + /* + * Compute affine scaling step for Mehrotra's predictor-corrector algorithm + */ + if( !vipmsolver_vipmcomputestepdirection(state, &state->current, 0.0, &state->zerovars, &state->deltaaff, regeps, ae_fp_greater_eq(dampeps,safedampeps), _state) ) + { + + /* + * Affine scaling step failed due to numerical errors. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> affine scaling step failed to decrease residual due to rounding errors\n"); + ae_trace("> increasing damping coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + vipmsolver_vipmcomputesteplength(state, &state->current, &state->deltaaff, vipmsolver_steplengthdecay, ae_false, &alphaaffp, &alphaaffd, _state); + + /* + * Compute MuAff and centering parameter + */ + vipmsolver_varsinitfrom(&state->trial, &state->current, _state); + vipmsolver_varsaddstep(&state->trial, &state->deltaaff, alphaaffp, alphaaffd, _state); + muaff = vipmsolver_varscomputemu(state, &state->trial, _state); + sigma = ae_minreal(ae_pow((muaff+mumin)/(mu+mumin), (double)(3), _state), 1.0, _state); + ae_assert(ae_isfinite(sigma, _state)&&ae_fp_less_eq(sigma,(double)(1)), "VIPMOptimize: critical integrity check failed for Sigma (infinite or greater than 1)", _state); + + /* + * Compute corrector step + */ + if( !vipmsolver_vipmcomputestepdirection(state, &state->current, sigma*mu+mumin, &state->deltaaff, &state->deltacorr, regeps, ae_fp_greater_eq(dampeps,safedampeps), _state) ) + { + + /* + * Affine scaling step failed due to numerical errors. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> corrector step failed to decrease residual due to rounding errors\n"); + ae_trace("> increasing damping coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + vipmsolver_vipmcomputesteplength(state, &state->current, &state->deltacorr, vipmsolver_steplengthdecay, ae_false, &alphap, &alphad, _state); + if( ae_fp_greater_eq((double)(iteridx),vipmsolver_minitersbeforesafeguards)&&(ae_fp_less_eq(alphap,vipmsolver_badsteplength)||ae_fp_less_eq(alphad,vipmsolver_badsteplength)) ) + { + + /* + * Affine scaling step failed due to numerical errors. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> step length is too short, suspecting rounding errors\n"); + ae_trace("> increasing damping coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + + /* + * Perform a step + */ + vipmsolver_runintegritychecks(state, &state->current, &state->deltacorr, alphap, alphad, _state); + vipmsolver_vipmperformstep(state, alphap, alphad, _state); + vipmsolver_traceprogress(state, mu, muaff, sigma, alphap, alphad, _state); + + /* + * Check for excessive bounds (one that are so large that they are both irrelevant + * and destabilizing due to their magnitude) + */ + if( dropbigbounds&&iteridx>=vipmsolver_minitersbeforedroppingbounds ) + { + ae_assert(ae_fp_less_eq((double)10*vipmsolver_bigconstrmag,(double)1/vipmsolver_bigconstrxtol), "VIPMOptimize: integrity check failed (incorrect BigConstr settings)", _state); + droppedbounds = 0; + + /* + * Determine variable and step scales. + * Both quantities are bounded from below by 1.0 + */ + mxprimal = 1.0; + mxprimal = ae_maxreal(mxprimal, rmaxabsv(n, &state->current.x, _state), _state); + mxprimal = ae_maxreal(mxprimal, rmaxabsv(n, &state->current.g, _state), _state); + mxprimal = ae_maxreal(mxprimal, rmaxabsv(n, &state->current.t, _state), _state); + mxprimal = ae_maxreal(mxprimal, rmaxabsv(m, &state->current.w, _state), _state); + mxprimal = ae_maxreal(mxprimal, rmaxabsv(m, &state->current.p, _state), _state); + mxdeltaprimal = 1.0; + mxdeltaprimal = ae_maxreal(mxdeltaprimal, alphap*rmaxabsv(n, &state->deltacorr.x, _state), _state); + mxdeltaprimal = ae_maxreal(mxdeltaprimal, alphap*rmaxabsv(n, &state->deltacorr.g, _state), _state); + mxdeltaprimal = ae_maxreal(mxdeltaprimal, alphap*rmaxabsv(n, &state->deltacorr.t, _state), _state); + mxdeltaprimal = ae_maxreal(mxdeltaprimal, alphap*rmaxabsv(m, &state->deltacorr.w, _state), _state); + mxdeltaprimal = ae_maxreal(mxdeltaprimal, alphap*rmaxabsv(m, &state->deltacorr.p, _state), _state); + + /* + * If changes in primal variables are small enough, try dropping too large bounds + */ + if( ae_fp_less(mxdeltaprimal,mxprimal*vipmsolver_bigconstrxtol) ) + { + + /* + * Drop irrelevant box constraints + */ + primalxscale = 1.0; + primalxscale = ae_maxreal(primalxscale, rmaxabsv(n, &state->current.x, _state), _state); + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasgz.ptr.p_bool[i])&&ae_fp_greater(ae_fabs(state->bndl.ptr.p_double[i], _state),vipmsolver_bigconstrmag*primalxscale) ) + { + state->hasgz.ptr.p_bool[i] = ae_false; + state->current.g.ptr.p_double[i] = (double)(0); + state->current.z.ptr.p_double[i] = (double)(0); + state->cntgz = state->cntgz-1; + inc(&droppedbounds, _state); + } + if( (state->hasbndu.ptr.p_bool[i]&&state->hasts.ptr.p_bool[i])&&ae_fp_greater(ae_fabs(state->bndu.ptr.p_double[i], _state),vipmsolver_bigconstrmag*primalxscale) ) + { + state->hasts.ptr.p_bool[i] = ae_false; + state->current.t.ptr.p_double[i] = (double)(0); + state->current.s.ptr.p_double[i] = (double)(0); + state->cntts = state->cntts-1; + inc(&droppedbounds, _state); + } + } + + /* + * Drop irrelevant linear constraints. Due to specifics of the solver + * we can drop only right part part of b<=Ax<=b+r. + * + * We can't drop b<=A from b<=A<=b+r because it impossible with our choice of + * slack variables. Usually we do not need to do so because we reorder constraints + * during initialization in such a way that |b+r|>|b| and because typical + * applications do not have excessively large lower AND upper bound (user may + * specify large value for 'absent' bound, but usually he does not mark both bounds as absent). + */ + vipmsolver_multiplygeax(state, 1.0, &state->current.x, 0, 0.0, &state->tmpax, 0, _state); + primalxscale = 1.0; + primalxscale = ae_maxreal(primalxscale, rmaxabsv(n, &state->current.x, _state), _state); + primalxscale = ae_maxreal(primalxscale, rmaxabsv(m, &state->tmpax, _state), _state); + for(i=0; i<=m-1; i++) + { + if( ((state->hasr.ptr.p_bool[i]&&state->haspq.ptr.p_bool[i])&&ae_fp_greater(ae_fabs(state->b.ptr.p_double[i]+state->r.ptr.p_double[i], _state),vipmsolver_bigconstrmag*primalxscale))&&ae_fp_less(ae_fabs(state->b.ptr.p_double[i], _state),vipmsolver_bigconstrmag*primalxscale) ) + { + ae_assert(state->haswv.ptr.p_bool[i]&&state->haspq.ptr.p_bool[i], "VIPMOptimize: unexpected integrity check failure (4y64)", _state); + state->haspq.ptr.p_bool[i] = ae_false; + state->current.p.ptr.p_double[i] = (double)(0); + state->current.q.ptr.p_double[i] = (double)(0); + state->cntpq = state->cntpq-1; + inc(&droppedbounds, _state); + } + } + + /* + * Trace output + */ + if( droppedbounds>0 ) + { + if( state->dotrace ) + { + ae_trace("[NOTICE] detected %0d irrelevant constraints with huge bounds, X converged to values well below them, dropping...\n", + (int)(droppedbounds)); + } + } + } + } + + /* + * Check stopping criteria + * * primal and dual stagnation are checked only when following criteria are met: + * 1) Mu is smaller than 1 (we already converged close enough) + * 2) we performed more than MinItersBeforeStagnation iterations + */ + preverrp2 = errp2; + preverrd2 = errd2; + vipmsolver_computeerrors(state, &errp2, &errd2, &errpinf, &errdinf, &errgap, _state); + mu = vipmsolver_varscomputemu(state, &state->current, _state); + egap = errgap; + eprimal = errpinf; + edual = errdinf; + if( ae_fp_less(rmax3(egap, eprimal, edual, _state),besterr) ) + { + + /* + * Save best point found so far + */ + vipmsolver_varsinitfrom(&state->best, &state->current, _state); + bestiteridx = iteridx; + besterr = rmax3(egap, eprimal, edual, _state); + bestegap = egap; + besteprimal = eprimal; + bestedual = edual; + } + if( bestiteridx>0&&iteridx>bestiteridx+vipmsolver_minitersbeforeeworststagnation ) + { + if( state->dotrace ) + { + ae_trace("> worst of primal/dual/gap errors stagnated for %0d its, stopping at the best point found so far\n", + (int)(vipmsolver_minitersbeforeeworststagnation)); + } + break; + } + if( ((ae_fp_less_eq(egap,state->epsgap)&&ae_fp_greater_eq(errp2,vipmsolver_stagnationdelta*preverrp2))&&ae_fp_greater_eq(errpinf,vipmsolver_primalinfeasible1))&&iteridx>=vipmsolver_minitersbeforestagnation ) + { + inc(&primalstagnationcnt, _state); + if( primalstagnationcnt>=vipmsolver_primalstagnationlen ) + { + if( state->dotrace ) + { + ae_trace("> primal error stagnated for %0d its, stopping at the best point found so far\n", + (int)(vipmsolver_primalstagnationlen)); + } + break; + } + } + else + { + primalstagnationcnt = 0; + } + if( ((ae_fp_less_eq(egap,state->epsgap)&&ae_fp_greater_eq(errd2,vipmsolver_stagnationdelta*preverrd2))&&ae_fp_greater_eq(errdinf,vipmsolver_dualinfeasible1))&&iteridx>=vipmsolver_minitersbeforestagnation ) + { + inc(&dualstagnationcnt, _state); + if( dualstagnationcnt>=vipmsolver_dualstagnationlen ) + { + if( state->dotrace ) + { + ae_trace("> dual error stagnated for %0d its, stopping at the best point found so far\n", + (int)(vipmsolver_dualstagnationlen)); + } + break; + } + } + else + { + dualstagnationcnt = 0; + } + if( ae_fp_less_eq(mu,mustop)&&iteridx>=vipmsolver_itersfortoostringentcond ) + { + if( state->dotrace ) + { + ae_trace("> stopping conditions are too stringent, stopping at the best point found so far\n"); + } + *terminationtype = 7; + break; + } + if( (ae_fp_less_eq(egap,state->epsgap)&&ae_fp_less_eq(eprimal,state->epsp))&&ae_fp_less_eq(edual,state->epsd) ) + { + if( state->dotrace ) + { + ae_trace("> stopping criteria are met\n"); + } + *terminationtype = 1; + loadbest = ae_false; + break; + } + bady = vipmsolver_bigy; + bady = ae_maxreal(bady, vipmsolver_ygrowth*y0nrm, _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.x, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.g, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.t, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(m, &state->current.w, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(m, &state->current.p, _state), _state); + if( ae_fp_greater_eq(rmaxabsv(m, &state->current.y, _state),bady)&&iteridx>=vipmsolver_minitersbeforeinfeasible ) + { + if( state->dotrace ) + { + ae_trace("> |Y| increased beyond %0.1e, stopping at the best point found so far\n", + (double)(bady)); + } + break; + } + } + + /* + * Load best point, perform some checks + */ + if( loadbest ) + { + + /* + * Load best point + * + * NOTE: TouchReal() is used to avoid spurious compiler warnings about 'set but unused' + */ + if( state->dotrace ) + { + ae_trace("> the best point so far is one from iteration %0d\n", + (int)(bestiteridx)); + } + vipmsolver_varsinitfrom(&state->current, &state->best, _state); + touchreal(&besteprimal, _state); + touchreal(&bestedual, _state); + touchreal(&bestegap, _state); + + /* + * If no error flags were set yet, check solution quality + */ + bady = vipmsolver_bigy; + bady = ae_maxreal(bady, vipmsolver_ygrowth*y0nrm, _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.x, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.g, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(n, &state->current.t, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(m, &state->current.w, _state), _state); + bady = ae_maxreal(bady, vipmsolver_ygrowth*rmaxabsv(m, &state->current.p, _state), _state); + if( *terminationtype>0&&ae_fp_greater_eq(rmaxabsv(m, &state->current.y, _state),bady) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> |Y| increased beyond %0.1e, declaring infeasibility/unboundedness\n", + (double)(bady)); + } + } + if( *terminationtype>0&&ae_fp_greater_eq(besteprimal,vipmsolver_primalinfeasible1) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> primal error at the best point is too high, declaring infeasibility/unboundedness\n"); + } + } + if( *terminationtype>0&&ae_fp_greater_eq(bestedual,vipmsolver_dualinfeasible1) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> dual error at the best point is too high, declaring infeasibility/unboundedness\n"); + } + } + } + + /* + * Output + */ + vipmsolver_multiplyhx(state, &state->current.x, &state->tmp0, _state); + raddv(n, 1.0, &state->c, &state->tmp0, _state); + vipmsolver_multiplygeatx(state, -1.0, &state->current.y, 0, 1.0, &state->tmp0, 0, _state); + for(i=0; i<=n-1; i++) + { + if( state->isfrozen.ptr.p_bool[i] ) + { + + /* + * I-th variable is frozen, use its frozen value. + * By the definition, I-th Lagrangian multiplier is an I-th component of Lagrangian gradient + */ + xs->ptr.p_double[i] = state->current.x.ptr.p_double[i]; + lagbc->ptr.p_double[i] = -state->tmp0.ptr.p_double[i]; + } + else + { + xs->ptr.p_double[i] = state->current.x.ptr.p_double[i]; + lagbc->ptr.p_double[i] = 0.0; + if( state->hasgz.ptr.p_bool[i] ) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]-state->current.z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]+state->current.s.ptr.p_double[i]; + } + } + } + for(i=0; i<=m-1; i++) + { + laglc->ptr.p_double[i] = -state->current.y.ptr.p_double[i]; + } + + /* + * Unscale point and Lagrange multipliers + */ + unscaleunshiftpointbc(&state->scl, &state->xorigin, &state->rawbndl, &state->rawbndu, &state->bndl, &state->bndu, &state->hasbndl, &state->hasbndu, xs, n, _state); + for(i=0; i<=n-1; i++) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]*state->targetscale/state->scl.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + laglc->ptr.p_double[i] = laglc->ptr.p_double[i]*state->targetscale/coalesce(state->ascales.ptr.p_double[i], 1.0, _state); + } +} + + +/************************************************************************* +Allocates place for variables of IPM and fills by zeros. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_varsinitbyzero(vipmvars* vstate, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + + + ae_assert(n>=1, "VarsInitByZero: N<1", _state); + ae_assert(m>=0, "VarsInitByZero: M<0", _state); + vstate->n = n; + vstate->m = m; + rsetallocv(n, 0.0, &vstate->x, _state); + rsetallocv(n, 0.0, &vstate->g, _state); + rsetallocv(n, 0.0, &vstate->t, _state); + rsetallocv(n, 0.0, &vstate->z, _state); + rsetallocv(n, 0.0, &vstate->s, _state); + rsetallocv(m, 0.0, &vstate->y, _state); + rsetallocv(m, 0.0, &vstate->w, _state); + rsetallocv(m, 0.0, &vstate->p, _state); + rsetallocv(m, 0.0, &vstate->v, _state); + rsetallocv(m, 0.0, &vstate->q, _state); +} + + +/************************************************************************* +Allocates place for variables of IPM and fills them by values of +the source + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_varsinitfrom(vipmvars* vstate, + const vipmvars* vsrc, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + + + n = vsrc->n; + m = vsrc->m; + ae_assert(n>=1, "VarsInitFrom: N<1", _state); + ae_assert(m>=0, "VarsInitFrom: M<0", _state); + vstate->n = n; + vstate->m = m; + rcopyallocv(n, &vsrc->x, &vstate->x, _state); + rcopyallocv(n, &vsrc->g, &vstate->g, _state); + rcopyallocv(n, &vsrc->t, &vstate->t, _state); + rcopyallocv(n, &vsrc->z, &vstate->z, _state); + rcopyallocv(n, &vsrc->s, &vstate->s, _state); + rcopyallocv(m, &vsrc->y, &vstate->y, _state); + rcopyallocv(m, &vsrc->w, &vstate->w, _state); + rcopyallocv(m, &vsrc->p, &vstate->p, _state); + rcopyallocv(m, &vsrc->v, &vstate->v, _state); + rcopyallocv(m, &vsrc->q, &vstate->q, _state); +} + + +/************************************************************************* +Adds to variables direction vector times step length. Different +lengths are used for primal and dual steps. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_varsaddstep(vipmvars* vstate, + const vipmvars* vdir, + double stpp, + double stpd, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t m; + + + n = vstate->n; + m = vstate->m; + ae_assert(n>=1, "VarsAddStep: N<1", _state); + ae_assert(m>=0, "VarsAddStep: M<0", _state); + ae_assert(n==vdir->n, "VarsAddStep: sizes mismatch", _state); + ae_assert(m==vdir->m, "VarsAddStep: sizes mismatch", _state); + for(i=0; i<=n-1; i++) + { + vstate->x.ptr.p_double[i] = vstate->x.ptr.p_double[i]+stpp*vdir->x.ptr.p_double[i]; + vstate->g.ptr.p_double[i] = vstate->g.ptr.p_double[i]+stpp*vdir->g.ptr.p_double[i]; + vstate->t.ptr.p_double[i] = vstate->t.ptr.p_double[i]+stpp*vdir->t.ptr.p_double[i]; + vstate->z.ptr.p_double[i] = vstate->z.ptr.p_double[i]+stpd*vdir->z.ptr.p_double[i]; + vstate->s.ptr.p_double[i] = vstate->s.ptr.p_double[i]+stpd*vdir->s.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + vstate->w.ptr.p_double[i] = vstate->w.ptr.p_double[i]+stpp*vdir->w.ptr.p_double[i]; + vstate->p.ptr.p_double[i] = vstate->p.ptr.p_double[i]+stpp*vdir->p.ptr.p_double[i]; + vstate->y.ptr.p_double[i] = vstate->y.ptr.p_double[i]+stpd*vdir->y.ptr.p_double[i]; + vstate->v.ptr.p_double[i] = vstate->v.ptr.p_double[i]+stpd*vdir->v.ptr.p_double[i]; + vstate->q.ptr.p_double[i] = vstate->q.ptr.p_double[i]+stpd*vdir->q.ptr.p_double[i]; + } +} + + +/************************************************************************* +Computes complementarity gap + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_varscomputecomplementaritygap(const vipmvars* vstate, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t m; + double result; + + + n = vstate->n; + m = vstate->m; + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+vstate->z.ptr.p_double[i]*vstate->g.ptr.p_double[i]+vstate->s.ptr.p_double[i]*vstate->t.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + result = result+vstate->v.ptr.p_double[i]*vstate->w.ptr.p_double[i]+vstate->p.ptr.p_double[i]*vstate->q.ptr.p_double[i]; + } + return result; +} + + +/************************************************************************* +Computes empirical value of the barrier parameter Mu + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_varscomputemu(const vipmstate* state, + const vipmvars* vstate, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = result+rdotv(vstate->n, &vstate->z, &vstate->g, _state)+rdotv(vstate->n, &vstate->s, &vstate->t, _state); + result = result+rdotv(vstate->m, &vstate->v, &vstate->w, _state)+rdotv(vstate->m, &vstate->p, &vstate->q, _state); + result = result/coalesce((double)(state->cntgz+state->cntts+state->cntwv+state->cntpq), (double)(1), _state); + return result; +} + + +/************************************************************************* +Initializes reduced sparse system. + +Works only for sparse IPM. + + -- ALGLIB -- + Copyright 15.11.2021 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_reducedsysteminit(vipmreducedsparsesystem* s, + const vipmstate* solver, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t nnzmax; + ae_int_t factldlt; + ae_int_t permpriorityamd; + ae_int_t memreuse; + ae_int_t offs; + ae_int_t rowoffs; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t sumcoldeg; + ae_int_t sumrowdeg; + ae_int_t colthreshold; + ae_int_t rowthreshold; + ae_int_t eligiblecols; + ae_int_t eligiblerows; + + + ae_assert(solver->factorizationtype==1, "ReducedSystemInit: unexpected factorization type", _state); + ae_assert(solver->hkind==1, "ReducedSystemInit: unexpected HKind", _state); + ntotal = solver->n+solver->mdense+solver->msparse; + s->ntotal = ntotal; + rallocv(ntotal, &s->effectivediag, _state); + + /* + * Determine maximum amount of memory required to store sparse matrices + */ + nnzmax = solver->sparseh.ridx.ptr.p_int[solver->n]; + if( solver->msparse>0 ) + { + nnzmax = nnzmax+solver->sparseafull.ridx.ptr.p_int[solver->msparse]; + } + if( solver->mdense>0 ) + { + nnzmax = nnzmax+solver->n*solver->mdense; + } + nnzmax = nnzmax+ntotal; + + /* + * Default DIAG and DAMP terms + */ + rsetallocv(ntotal, 0.0, &s->diagterm, _state); + rsetallocv(ntotal, 0.0, &s->dampterm, _state); + + /* + * Prepare lower triangle of template KKT matrix (KKT system without D and E + * terms being added to diagonals) + */ + s->rawsystem.m = ntotal; + s->rawsystem.n = ntotal; + ivectorsetlengthatleast(&s->rawsystem.idx, nnzmax, _state); + rvectorsetlengthatleast(&s->rawsystem.vals, nnzmax, _state); + ivectorsetlengthatleast(&s->rawsystem.ridx, ntotal+1, _state); + s->rawsystem.ridx.ptr.p_int[0] = 0; + offs = 0; + rowoffs = 0; + sumcoldeg = 0; + sumrowdeg = 0; + isetallocv(solver->n, 0, &s->coldegrees, _state); + isetallocv(solver->msparse+solver->mdense, 0, &s->rowdegrees, _state); + bsetallocv(solver->n, ae_true, &s->isdiagonal, _state); + for(i=0; i<=solver->n-1; i++) + { + ae_assert(solver->sparseh.didx.ptr.p_int[i]+1==solver->sparseh.uidx.ptr.p_int[i], "ReducedSystemInit: critical integrity check failed for diagonal of H", _state); + if( !solver->isfrozen.ptr.p_bool[i] ) + { + + /* + * Entire row is not frozen, but some of its entries can be. + * Output non-frozen offdiagonal entries. + */ + k0 = solver->sparseh.ridx.ptr.p_int[i]; + k1 = solver->sparseh.didx.ptr.p_int[i]-1; + for(k=k0; k<=k1; k++) + { + j = solver->sparseh.idx.ptr.p_int[k]; + if( !solver->isfrozen.ptr.p_bool[j] ) + { + s->rawsystem.idx.ptr.p_int[offs] = j; + s->rawsystem.vals.ptr.p_double[offs] = -solver->sparseh.vals.ptr.p_double[k]; + s->isdiagonal.ptr.p_bool[i] = ae_false; + s->isdiagonal.ptr.p_bool[j] = ae_false; + s->coldegrees.ptr.p_int[i] = s->coldegrees.ptr.p_int[i]+1; + s->coldegrees.ptr.p_int[j] = s->coldegrees.ptr.p_int[j]+1; + sumcoldeg = sumcoldeg+2; + offs = offs+1; + } + } + + /* + * Output diagonal entry (it is always not frozen) + */ + s->rawsystem.idx.ptr.p_int[offs] = i; + s->rawsystem.vals.ptr.p_double[offs] = -solver->sparseh.vals.ptr.p_double[solver->sparseh.didx.ptr.p_int[i]]; + offs = offs+1; + } + else + { + + /* + * Entire row is frozen, output just -1 + */ + s->rawsystem.idx.ptr.p_int[offs] = i; + s->rawsystem.vals.ptr.p_double[offs] = -1.0; + offs = offs+1; + } + rowoffs = rowoffs+1; + s->rawsystem.ridx.ptr.p_int[rowoffs] = offs; + } + for(i=0; i<=solver->msparse-1; i++) + { + k0 = solver->sparseafull.ridx.ptr.p_int[i]; + k1 = solver->sparseafull.ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + j = solver->sparseafull.idx.ptr.p_int[k]; + if( !solver->isfrozen.ptr.p_bool[j] ) + { + s->rawsystem.idx.ptr.p_int[offs] = j; + s->rawsystem.vals.ptr.p_double[offs] = solver->sparseafull.vals.ptr.p_double[k]; + s->rowdegrees.ptr.p_int[i] = s->rowdegrees.ptr.p_int[i]+1; + s->coldegrees.ptr.p_int[j] = s->coldegrees.ptr.p_int[j]+1; + sumcoldeg = sumcoldeg+1; + sumrowdeg = sumrowdeg+1; + offs = offs+1; + } + } + s->rawsystem.idx.ptr.p_int[offs] = rowoffs; + s->rawsystem.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + rowoffs = rowoffs+1; + s->rawsystem.ridx.ptr.p_int[rowoffs] = offs; + } + for(i=0; i<=solver->mdense-1; i++) + { + for(k=0; k<=solver->n-1; k++) + { + if( solver->denseafull.ptr.pp_double[i][k]!=0.0&&!solver->isfrozen.ptr.p_bool[k] ) + { + s->rawsystem.idx.ptr.p_int[offs] = k; + s->rawsystem.vals.ptr.p_double[offs] = solver->denseafull.ptr.pp_double[i][k]; + s->rowdegrees.ptr.p_int[solver->msparse+i] = s->rowdegrees.ptr.p_int[solver->msparse+i]+1; + s->coldegrees.ptr.p_int[k] = s->coldegrees.ptr.p_int[k]+1; + sumcoldeg = sumcoldeg+1; + sumrowdeg = sumrowdeg+1; + offs = offs+1; + } + } + s->rawsystem.idx.ptr.p_int[offs] = rowoffs; + s->rawsystem.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + rowoffs = rowoffs+1; + s->rawsystem.ridx.ptr.p_int[rowoffs] = offs; + } + ae_assert(rowoffs==ntotal, "ReducedSystemInit: critical integrity check failed", _state); + ae_assert(offs<=nnzmax, "ReducedSystemInit: critical integrity check failed", _state); + sparsecreatecrsinplace(&s->rawsystem, _state); + + /* + * Prepare reordering + */ + isetallocv(ntotal, 0, &s->priorities, _state); + colthreshold = ae_round(vipmsolver_muquasidense*(double)sumcoldeg/(double)solver->n, _state)+1; + rowthreshold = ae_round(vipmsolver_muquasidense*(double)sumrowdeg/(double)(solver->msparse+solver->mdense+1), _state)+1; + eligiblecols = 0; + eligiblerows = 0; + for(i=0; i<=solver->n-1; i++) + { + if( s->coldegrees.ptr.p_int[i]<=colthreshold ) + { + eligiblecols = eligiblecols+1; + } + } + for(i=0; i<=solver->mdense+solver->msparse-1; i++) + { + if( s->rowdegrees.ptr.p_int[i]<=rowthreshold ) + { + eligiblerows = eligiblerows+1; + } + } + if( ae_maxint(eligiblecols, eligiblerows, _state)>0&&ae_maxint(eligiblecols, eligiblerows, _state)=eligiblerows ) + { + + /* + * Eliminate columns first + */ + for(i=0; i<=solver->n-1; i++) + { + s->priorities.ptr.p_int[i] = icase2(s->coldegrees.ptr.p_int[i]<=colthreshold, 0, 2, _state); + } + for(i=solver->n; i<=ntotal-1; i++) + { + s->priorities.ptr.p_int[i] = icase2(s->rowdegrees.ptr.p_int[i-solver->n]<=rowthreshold, 1, 2, _state); + } + } + else + { + + /* + * Eliminate rows first + */ + for(i=0; i<=solver->n-1; i++) + { + s->priorities.ptr.p_int[i] = icase2(s->coldegrees.ptr.p_int[i]<=colthreshold, 1, 2, _state); + } + for(i=solver->n; i<=ntotal-1; i++) + { + s->priorities.ptr.p_int[i] = icase2(s->rowdegrees.ptr.p_int[i-solver->n]<=rowthreshold, 0, 2, _state); + } + } + } + for(i=0; i<=solver->n-1; i++) + { + s->priorities.ptr.p_int[i] = icase2(solver->hasbndl.ptr.p_bool[i]||solver->hasbndu.ptr.p_bool[i], s->priorities.ptr.p_int[i], 2, _state); + } + if( solver->dotrace ) + { + ae_trace("> initializing KKT system; no priority ordering being applied\n"); + } + + /* + * Perform factorization analysis using sparsity pattern (but not numerical values) + */ + factldlt = 1; + permpriorityamd = 3; + memreuse = 1; + if( !spsymmanalyze(&s->rawsystem, &s->priorities, (double)ntotal+1.0, 0, factldlt, permpriorityamd, memreuse, &s->analysis, _state) ) + { + ae_assert(ae_false, "ReducedSystemInit: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } +} + + +/************************************************************************* +Computes factorization of A+Diag+Damp, where A is an internally stored KKT +matrix and Diag and Damp are user-supplied diagonal terms. + +The Diag term is assumed to be a "true" modification of the system, and +Damp is assumed to be a small damping factor. The difference is that the +damping factor is added during the factorization, but not accounted for +during the iterative refinement stage, i.e. we factor A+Diag+Damp, but aim +to solve A+Diag. + +ModEps and BadChol are user supplied tolerances for modified Cholesky/LDLT. + +Returns True on success, False on LDLT failure. + +On success outputs diagonal reproduction error ErrSq, and sum of squared +diagonal elements SumSq + + -- ALGLIB -- + Copyright 15.11.2021 by Bochkanov Sergey +*************************************************************************/ +static ae_bool vipmsolver_reducedsystemfactorizewithaddends(vipmreducedsparsesystem* s, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* damp, + double modeps, + double badchol, + double* sumsq, + double* errsq, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t i; + ae_bool result; + + *sumsq = 0.0; + *errsq = 0.0; + + ntotal = s->ntotal; + rcopyv(ntotal, diag, &s->diagterm, _state); + rcopyv(ntotal, damp, &s->dampterm, _state); + for(i=0; i<=ntotal-1; i++) + { + s->effectivediag.ptr.p_double[i] = s->rawsystem.vals.ptr.p_double[s->rawsystem.didx.ptr.p_int[i]]+diag->ptr.p_double[i]+damp->ptr.p_double[i]; + } + spsymmreloaddiagonal(&s->analysis, &s->effectivediag, _state); + result = ae_true; + spsymmsetmodificationstrategy(&s->analysis, 1, modeps, badchol, 0.0, 0.0, _state); + if( spsymmfactorize(&s->analysis, _state) ) + { + + /* + * Compute diagonal reproduction error + */ + spsymmdiagerr(&s->analysis, sumsq, errsq, _state); + } + else + { + *sumsq = (double)(0); + *errsq = (double)(0); + result = ae_false; + } + return result; +} + + +/************************************************************************* +Solve reduced KKT system, replacing right part by its solution. + + -- ALGLIB -- + Copyright 15.11.2021 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_reducedsystemsolve(vipmreducedsparsesystem* s, + ae_bool dotrace, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t iteridx; + double bnrm2; + double relerr; + double prevrelerr; + + + + /* + * Perform initial solution + */ + rcopyallocv(s->ntotal, b, &s->tmpb, _state); + spsymmsolve(&s->analysis, b, _state); + + /* + * Trace residual and relative error + */ + bnrm2 = ae_maxreal(rdotv2(s->ntotal, &s->tmpb, _state), 1.0, _state); + sparsesmv(&s->rawsystem, ae_false, b, &s->tmprhs, _state); + rmuladdv(s->ntotal, b, &s->diagterm, &s->tmprhs, _state); + rmulv(s->ntotal, -1.0, &s->tmprhs, _state); + raddv(s->ntotal, 1.0, &s->tmpb, &s->tmprhs, _state); + relerr = ae_sqrt(rdotv2(s->ntotal, &s->tmprhs, _state)/bnrm2, _state); + if( dotrace ) + { + ae_trace("> reduced system solved, res/rhs = %0.3e (initial)\n", + (double)(relerr)); + } + + /* + * Perform iterative refinement, if necessary + */ + prevrelerr = 1.0E50; + iteridx = 0; + while((iteridxntotal, &s->tmprhs, &s->tmpcorr, _state); + spsymmsolve(&s->analysis, &s->tmpcorr, _state); + raddv(s->ntotal, 1.0, &s->tmpcorr, b, _state); + + /* + * Recompute residual + */ + sparsesmv(&s->rawsystem, ae_false, b, &s->tmprhs, _state); + rmuladdv(s->ntotal, b, &s->diagterm, &s->tmprhs, _state); + rmulv(s->ntotal, -1.0, &s->tmprhs, _state); + raddv(s->ntotal, 1.0, &s->tmpb, &s->tmprhs, _state); + prevrelerr = relerr; + relerr = ae_sqrt(rdotv2(s->ntotal, &s->tmprhs, _state)/bnrm2, _state); + iteridx = iteridx+1; + } + if( dotrace&&iteridx>0 ) + { + ae_trace("> reduced system solved, res/rhs = %0.3e (refined, %0d its)\n", + (double)(relerr), + (int)(iteridx)); + } +} + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +The solver is configured to work internally with factorization FType + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + + The terms A and b (as well as constraints) will be + specified later with separate calls. + FType - factorization type: + * 0 for dense NxN factorization (normal equations) + * 1 for sparse (N+M)x(N+M) factorization + Normalize - apply normalization to target/constraints or not: + * if True, then target and constraints are normalized + to unit scale + * if False, it is assumed that the caller has performed + normalization. + The latter is recommended for presolved problems. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_vipminit(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_int_t nmain, + ae_int_t ftype, + ae_bool normalize, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nslack; + + + ae_assert(n>=1, "VIPMInit: N<1", _state); + ae_assert(isfinitevector(s, n, _state), "VIPMInit: S contains infinite or NaN elements", _state); + ae_assert(isfinitevector(xorigin, n, _state), "VIPMInit: XOrigin contains infinite or NaN elements", _state); + ae_assert(ftype==0||ftype==1, "VIPMInit: unexpected FType", _state); + ae_assert(nmain>=1, "VIPMInit: NMain<1", _state); + ae_assert(nmain<=n, "VIPMInit: NMain>N", _state); + nslack = n-nmain; + + /* + * Problem metrics, settings and type + */ + state->n = n; + state->nmain = nmain; + state->normalize = normalize; + state->islinear = ae_true; + state->factorizationtype = ftype; + state->factorizationpresent = ae_false; + state->factorizationpoweredup = ae_false; + vipmsetcond(state, 0.0, 0.0, 0.0, _state); + state->slacksforequalityconstraints = ae_true; + + /* + * Reports + */ + state->repiterationscount = 0; + state->repncholesky = 0; + + /* + * Trace + */ + state->dotrace = ae_false; + state->dodetailedtrace = ae_false; + + /* + * Scale and origin + */ + rvectorsetlengthatleast(&state->scl, n, _state); + rvectorsetlengthatleast(&state->invscl, n, _state); + rvectorsetlengthatleast(&state->xorigin, n, _state); + for(i=0; i<=n-1; i++) + { + ae_assert(s->ptr.p_double[i]>0.0, "VIPMInit: S[i] is non-positive", _state); + state->scl.ptr.p_double[i] = s->ptr.p_double[i]; + state->invscl.ptr.p_double[i] = (double)1/s->ptr.p_double[i]; + state->xorigin.ptr.p_double[i] = xorigin->ptr.p_double[i]; + } + state->targetscale = 1.0; + + /* + * Linear and quadratic terms - default value + */ + rvectorsetlengthatleast(&state->c, n, _state); + for(i=0; i<=n-1; i++) + { + state->c.ptr.p_double[i] = (double)(0); + } + state->hkind = -1; + if( ftype==0 ) + { + + /* + * Dense quadratic term + */ + rmatrixsetlengthatleast(&state->denseh, nmain, nmain, _state); + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=i; j++) + { + state->denseh.ptr.pp_double[i][j] = (double)(0); + } + } + state->hkind = 0; + state->isdiagonalh = ae_false; + } + if( ftype==1 ) + { + + /* + * Sparse quadratic term + */ + state->sparseh.matrixtype = 1; + state->sparseh.m = n; + state->sparseh.n = n; + state->sparseh.ninitialized = n; + ivectorsetlengthatleast(&state->sparseh.idx, n, _state); + rvectorsetlengthatleast(&state->sparseh.vals, n, _state); + ivectorsetlengthatleast(&state->sparseh.ridx, n+1, _state); + for(i=0; i<=n-1; i++) + { + state->sparseh.idx.ptr.p_int[i] = i; + state->sparseh.vals.ptr.p_double[i] = 0.0; + state->sparseh.ridx.ptr.p_int[i] = i; + } + state->sparseh.ridx.ptr.p_int[n] = n; + sparsecreatecrsinplace(&state->sparseh, _state); + state->hkind = 1; + state->isdiagonalh = ae_true; + } + ae_assert(state->hkind>=0, "VIPMInit: integrity check failed", _state); + + /* + * Box constraints - default values + */ + rvectorsetlengthatleast(&state->bndl, n, _state); + rvectorsetlengthatleast(&state->bndu, n, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_false; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + } + + /* + * Linear constraints - empty + */ + state->mdense = 0; + state->msparse = 0; + state->combinedaslack.m = 0; + state->combinedaslack.n = nslack; + state->sparseamain.m = 0; + state->sparseamain.n = nmain; + sparsecreatecrsinplace(&state->sparseamain, _state); + sparsecreatecrsinplace(&state->combinedaslack, _state); +} + + +/************************************************************************* +Computes target function 0.5*x'*H*x+c'*x + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_vipmtarget(const vipmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nmain; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + double result; + + + n = state->n; + nmain = state->nmain; + ae_assert(state->hkind==0||state->hkind==1, "VIPMTarget: unexpected HKind", _state); + result = (double)(0); + + /* + * Dense + */ + if( state->hkind==0 ) + { + for(i=0; i<=nmain-1; i++) + { + for(j=0; j<=i-1; j++) + { + result = result+x->ptr.p_double[i]*state->denseh.ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + result = result+0.5*x->ptr.p_double[i]*x->ptr.p_double[i]*state->denseh.ptr.pp_double[i][i]; + } + for(i=0; i<=n-1; i++) + { + result = result+state->c.ptr.p_double[i]*x->ptr.p_double[i]; + } + return result; + } + + /* + * Sparse + */ + if( state->hkind==1 ) + { + for(i=0; i<=n-1; i++) + { + result = result+state->c.ptr.p_double[i]*x->ptr.p_double[i]; + j0 = state->sparseh.ridx.ptr.p_int[i]; + j1 = state->sparseh.didx.ptr.p_int[i]-1; + for(k=j0; k<=j1; k++) + { + v = state->sparseh.vals.ptr.p_double[k]; + j = state->sparseh.idx.ptr.p_int[k]; + result = result+v*x->ptr.p_double[i]*x->ptr.p_double[j]; + } + ae_assert(state->sparseh.uidx.ptr.p_int[i]!=state->sparseh.didx.ptr.p_int[i], "VIPMTarget: sparse diagonal not found", _state); + v = state->sparseh.vals.ptr.p_double[state->sparseh.didx.ptr.p_int[i]]; + result = result+0.5*v*x->ptr.p_double[i]*x->ptr.p_double[i]; + } + return result; + } + return result; +} + + +/************************************************************************* +Computes + + Y := alpha*A*x + beta*Y + +where A is constraint matrix, X is user-specified source, Y is target. + +Beta can be zero (in this case original contents of Y is ignored). +If Beta is nonzero, we expect that Y contains preallocated array. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_multiplygeax(const vipmstate* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsax, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t mdense; + ae_int_t msparse; + + + n = state->n; + m = state->mdense+state->msparse; + mdense = state->mdense; + msparse = state->msparse; + if( ae_fp_eq(beta,(double)(0)) ) + { + rallocv(offsax+m, y, _state); + } + else + { + ae_assert(y->cnt>=offsax+m, "MultiplyGEAX: Y is too short", _state); + } + if( msparse>0 ) + { + sparsegemv(&state->sparseafull, alpha, 0, x, offsx, beta, y, offsax, _state); + } + if( mdense>0 ) + { + rmatrixgemv(mdense, n, alpha, &state->denseafull, 0, 0, 0, x, offsx, beta, y, offsax+msparse, _state); + } +} + + +/************************************************************************* +Computes + + Y := alpha*A'*x + beta*Y + +where A is constraint matrix, X is user-specified source, Y is target. + +Beta can be zero, in this case we automatically reallocate target if it is +too short (but do NOT reallocate it if its size is large enough). +If Beta is nonzero, we expect that Y contains preallocated array. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_multiplygeatx(const vipmstate* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t n; + ae_int_t mdense; + ae_int_t msparse; + + + n = state->n; + mdense = state->mdense; + msparse = state->msparse; + if( ae_fp_eq(beta,(double)(0)) ) + { + rallocv(offsy+n, y, _state); + rsetvx(n, 0.0, y, offsy, _state); + } + else + { + ae_assert(y->cnt>=offsy+n, "MultiplyGEATX: Y is too short", _state); + rmulvx(n, beta, y, offsy, _state); + } + if( msparse>0 ) + { + sparsegemv(&state->sparseafull, alpha, 1, x, offsx, 1.0, y, offsy, _state); + } + if( mdense>0 ) + { + rmatrixgemv(n, mdense, alpha, &state->denseafull, 0, 0, 1, x, offsx+msparse, 1.0, y, offsy, _state); + } +} + + +/************************************************************************* +Computes H*x, does not support advanced functionality of GEAX/GEATX + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_multiplyhx(const vipmstate* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nmain; + ae_int_t i; + + + n = state->n; + nmain = state->nmain; + rvectorsetlengthatleast(hx, n, _state); + ae_assert(state->hkind==0||state->hkind==1, "VIPMMultiplyHX: unexpected HKind", _state); + if( state->hkind==0 ) + { + rmatrixsymv(nmain, 1.0, &state->denseh, 0, 0, ae_false, x, 0, 0.0, hx, 0, _state); + for(i=nmain; i<=n-1; i++) + { + hx->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=n-1; i++) + { + hx->ptr.p_double[i] = hx->ptr.p_double[i]+x->ptr.p_double[i]*state->diagr.ptr.p_double[i]; + } + } + if( state->hkind==1 ) + { + ae_assert(state->sparseh.n==n&&state->sparseh.m==n, "VIPMMultiplyHX: sparse H has incorrect size", _state); + if( state->isdiagonalh ) + { + + /* + * H is known to be diagonal, much faster code can be used + */ + rcopyv(n, &state->diagr, hx, _state); + raddv(n, 1.0, &state->sparseh.vals, hx, _state); + rmergemulv(n, x, hx, _state); + } + else + { + + /* + * H is a general sparse matrix, use generic sparse matrix-vector multiply + */ + sparsesmv(&state->sparseh, ae_false, x, hx, _state); + for(i=0; i<=n-1; i++) + { + hx->ptr.p_double[i] = hx->ptr.p_double[i]+x->ptr.p_double[i]*state->diagr.ptr.p_double[i]; + } + } + } +} + + +/************************************************************************* +Computes products H*x, A*x, A^T*y + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_vipmmultiply(const vipmstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* hx, + /* Real */ ae_vector* ax, + /* Real */ ae_vector* aty, + ae_state *_state) +{ + + + vipmsolver_multiplygeax(state, 1.0, x, 0, 0.0, ax, 0, _state); + vipmsolver_multiplygeatx(state, 1.0, y, 0, 0.0, aty, 0, _state); + vipmsolver_multiplyhx(state, x, hx, _state); +} + + +/************************************************************************* +This function "powers up" factorization, i.e. prepares some important +temporaries. It should be called once prior to the first call to +VIPMInitialPoint() or VIPMFactorize(). + +Parameters: + RegFree - regularization for free variables; + good value sqrt(MachineEpsilon) + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_vipmpowerup(vipmstate* state, + double regfree, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + double v; + double vrhs; + double priorcoeff; + double initprimslack; + double initdualslack; + double maxinitialnoncentrality; + double maxinitialimbalance; + double maxdualslack; + double mu0; + double mumin; + ae_bool success; + + + ae_assert(state->factorizationtype==0||state->factorizationtype==1, "VIPMPowerUp: unexpected factorization type", _state); + n = state->n; + m = state->mdense+state->msparse; + ae_assert(!state->factorizationpoweredup, "VIPMPowerUp: repeated call", _state); + maxinitialnoncentrality = 1.0E-6; + maxinitialimbalance = 1.0E-6; + + /* + * Set up information about presence of slack variables. + * Decide which components of X should be frozen. + * Compute diagonal regularization matrix R. + */ + bcopyallocv(n, &state->hasbndl, &state->hasgz, _state); + bcopyallocv(n, &state->hasbndu, &state->hasts, _state); + bsetallocv(n, ae_false, &state->isfrozen, _state); + rsetallocv(n, 0.0, &state->diagr, _state); + vipmsolver_varsinitbyzero(&state->current, n, m, _state); + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->isfrozen.ptr.p_bool[i] = ae_true; + state->hasgz.ptr.p_bool[i] = ae_false; + state->hasts.ptr.p_bool[i] = ae_false; + state->current.x.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( !state->hasbndl.ptr.p_bool[i]&&!state->hasbndu.ptr.p_bool[i] ) + { + state->diagr.ptr.p_double[i] = regfree; + } + } + ballocv(m, &state->haspq, _state); + ballocv(m, &state->haswv, _state); + for(i=0; i<=m-1; i++) + { + state->haswv.ptr.p_bool[i] = (state->slacksforequalityconstraints||!state->hasr.ptr.p_bool[i])||ae_fp_greater(state->r.ptr.p_double[i],(double)(0)); + state->haspq.ptr.p_bool[i] = state->hasr.ptr.p_bool[i]&&state->haswv.ptr.p_bool[i]; + } + state->cntgz = 0; + state->cntts = 0; + state->cntwv = 0; + state->cntpq = 0; + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + state->cntgz = state->cntgz+1; + } + if( state->hasts.ptr.p_bool[i] ) + { + state->cntts = state->cntts+1; + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + state->cntwv = state->cntwv+1; + } + if( state->haspq.ptr.p_bool[i] ) + { + state->cntpq = state->cntpq+1; + } + } + + /* + * Special initialization for sparse version + */ + if( state->factorizationtype==1 ) + { + vipmsolver_reducedsysteminit(&state->reducedsparsesystem, state, _state); + } + state->factorizationpoweredup = ae_true; + + /* + * Set up initial values of primal and dual variables X and Y by solving + * modified KKT system which tries to enforce linear constraints (ignoring + * box constraints for a while) subject to minimization of additional prior + * term which moves solution towards some interior point. + * + * Here we expect that State.Current.X contains zeros in non-fixed variables + * and their fixed values for fixed ones. + */ + priorcoeff = 1.0; + success = vipmsolver_vipmfactorize(state, 0.0, &state->diagddr, 0.0, &state->diagder, priorcoeff, priorcoeff, ae_machineepsilon, ae_machineepsilon, _state); + ae_assert(success, "VIPMInitialPoint: impossible failure of LDLT factorization", _state); + vipmsolver_multiplyhx(state, &state->current.x, &state->tmp0, _state); + vipmsolver_multiplygeax(state, 1.0, &state->current.x, 0, 0.0, &state->tmp1, 0, _state); + rallocv(n+m, &state->deltaxy, _state); + for(i=0; i<=n-1; i++) + { + state->deltaxy.ptr.p_double[i] = state->c.ptr.p_double[i]+state->tmp0.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + + /* + * We need to specify target right-hand sides for constraints. + * + * Ether zero, b or b+r is used (depending on presence of r and + * magnitudes of b and b+r, and subject to current state of frozen + * variables). + */ + vrhs = state->b.ptr.p_double[i]-state->tmp1.ptr.p_double[i]; + if( state->hasr.ptr.p_bool[i] ) + { + + /* + * Range constraint b<=Ax<=b+r + */ + if( ae_fp_greater_eq(vrhs,(double)(0)) ) + { + + /* + * 0<=b<=b+r, select target at lower bound + */ + v = vrhs; + } + else + { + + /* + * b<=0, b+r can have any sign. + * Select zero target if possible, if not - one with smallest absolute value. + */ + v = ae_minreal(vrhs+state->r.ptr.p_double[i], 0.0, _state); + } + } + else + { + + /* + * Single-sided constraint Ax>=b. + * Select zero target if possible, if not - one with smallest absolute value. + */ + v = ae_maxreal(vrhs, 0.0, _state); + } + state->deltaxy.ptr.p_double[n+i] = v; + } + vipmsolver_solvereducedkktsystem(state, &state->deltaxy, _state); + for(i=0; i<=n-1; i++) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + state->current.x.ptr.p_double[i] = state->deltaxy.ptr.p_double[i]; + } + } + for(i=0; i<=m-1; i++) + { + state->current.y.ptr.p_double[i] = state->deltaxy.ptr.p_double[n+i]; + } + + /* + * Set up slacks according to our own heuristic + */ + initprimslack = ae_maxreal(vipmsolver_initslackval, rmaxabsv(n, &state->current.x, _state), _state); + initdualslack = ae_maxreal(vipmsolver_initslackval, rmaxabsv(m, &state->current.y, _state), _state); + maxdualslack = ae_maxreal((double)10*initdualslack, vipmsolver_maxdualslackval, _state); + vipmsolver_multiplygeax(state, 1.0, &state->current.x, 0, 0.0, &state->tmpax, 0, _state); + mu0 = 1.0; + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + state->current.g.ptr.p_double[i] = ae_maxreal(ae_fabs(state->current.x.ptr.p_double[i]-state->bndl.ptr.p_double[i], _state), initprimslack, _state); + state->current.z.ptr.p_double[i] = boundval(state->current.g.ptr.p_double[i]*maxinitialimbalance, initdualslack, maxdualslack, _state); + mu0 = ae_maxreal(mu0, state->current.g.ptr.p_double[i]*state->current.z.ptr.p_double[i], _state); + } + if( state->hasts.ptr.p_bool[i] ) + { + state->current.t.ptr.p_double[i] = ae_maxreal(ae_fabs(state->current.x.ptr.p_double[i]-state->bndu.ptr.p_double[i], _state), initprimslack, _state); + state->current.s.ptr.p_double[i] = boundval(state->current.t.ptr.p_double[i]*maxinitialimbalance, initdualslack, maxdualslack, _state); + mu0 = ae_maxreal(mu0, state->current.t.ptr.p_double[i]*state->current.s.ptr.p_double[i], _state); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + state->current.w.ptr.p_double[i] = ae_maxreal(ae_fabs(state->tmpax.ptr.p_double[i]-state->b.ptr.p_double[i], _state), initprimslack, _state); + state->current.v.ptr.p_double[i] = boundval(ae_maxreal(state->current.w.ptr.p_double[i]*maxinitialimbalance, ae_fabs(state->current.y.ptr.p_double[i], _state), _state), vipmsolver_initslackval, maxdualslack, _state); + mu0 = ae_maxreal(mu0, state->current.w.ptr.p_double[i]*state->current.v.ptr.p_double[i], _state); + } + if( state->haspq.ptr.p_bool[i] ) + { + state->current.p.ptr.p_double[i] = ae_maxreal(ae_fabs(state->r.ptr.p_double[i]-state->current.w.ptr.p_double[i], _state), initprimslack, _state); + state->current.q.ptr.p_double[i] = boundval(ae_maxreal(state->current.p.ptr.p_double[i]*maxinitialimbalance, ae_fabs(state->current.y.ptr.p_double[i], _state), _state), vipmsolver_initslackval, maxdualslack, _state); + mu0 = ae_maxreal(mu0, state->current.p.ptr.p_double[i]*state->current.q.ptr.p_double[i], _state); + } + } + + /* + * Additional shift to ensure that initial point is not too non-centered + */ + mumin = mu0*maxinitialnoncentrality; + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i]&&ae_fp_less(state->current.g.ptr.p_double[i]*state->current.z.ptr.p_double[i],mumin) ) + { + v = ae_sqrt(mumin/(state->current.g.ptr.p_double[i]*state->current.z.ptr.p_double[i]), _state); + state->current.g.ptr.p_double[i] = state->current.g.ptr.p_double[i]*v; + state->current.z.ptr.p_double[i] = state->current.z.ptr.p_double[i]*v; + } + if( state->hasts.ptr.p_bool[i]&&ae_fp_less(state->current.t.ptr.p_double[i]*state->current.s.ptr.p_double[i],mumin) ) + { + v = ae_sqrt(mumin/(state->current.t.ptr.p_double[i]*state->current.s.ptr.p_double[i]), _state); + state->current.t.ptr.p_double[i] = state->current.t.ptr.p_double[i]*v; + state->current.s.ptr.p_double[i] = state->current.s.ptr.p_double[i]*v; + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i]&&ae_fp_less(state->current.w.ptr.p_double[i]*state->current.v.ptr.p_double[i],mumin) ) + { + v = ae_sqrt(mumin/(state->current.w.ptr.p_double[i]*state->current.v.ptr.p_double[i]), _state); + state->current.w.ptr.p_double[i] = state->current.w.ptr.p_double[i]*v; + state->current.v.ptr.p_double[i] = state->current.v.ptr.p_double[i]*v; + } + if( state->haspq.ptr.p_bool[i]&&ae_fp_less(state->current.p.ptr.p_double[i]*state->current.q.ptr.p_double[i],mumin) ) + { + v = ae_sqrt(mumin/(state->current.p.ptr.p_double[i]*state->current.q.ptr.p_double[i]), _state); + state->current.p.ptr.p_double[i] = state->current.p.ptr.p_double[i]*v; + state->current.q.ptr.p_double[i] = state->current.q.ptr.p_double[i]*v; + } + } + + /* + * Almost done + */ + if( state->dotrace ) + { + ae_trace("> initial point was generated\n"); + } +} + + +/************************************************************************* +This function performs factorization of modified KKT system + + ( | ) + ( -(H+alpha0*D+alpha1*I) | A^T ) + ( | ) + (------------------------|-----------------) + ( | ) + ( A | beta0*E+beta1*I ) + ( | ) + +where: +* H is an NxN quadratic term +* A is an MxN matrix of linear constraint +* alpha0, alpha1, beta0, beta1 are nonnegative scalars +* D and E are diagonal matrices with nonnegative entries (which are ignored + if alpha0 and beta0 are zero - arrays are not referenced at all) +* I is an NxN or MxM identity matrix + +Additionally, regularizing term + + ( | ) + ( -reg*I | ) + ( | ) + (--------|--------) + ( | ) + ( | +reg*I ) + ( | ) + +is added to the entire KKT system prior to factorization in order to +improve its numerical stability. + +Returns True on success, False on falure of factorization (it is recommended +to increase regularization parameter and try one more time). + + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_bool vipmsolver_vipmfactorize(vipmstate* state, + double alpha0, + /* Real */ const ae_vector* d, + double beta0, + /* Real */ const ae_vector* e, + double alpha11, + double beta11, + double modeps, + double dampeps, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nmain; + ae_int_t nslack; + ae_int_t m; + ae_int_t mdense; + ae_int_t msparse; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t ka; + ae_int_t kb; + ae_int_t ja; + ae_int_t jb; + double va; + double vb; + double v; + double vv; + double badchol; + double sumsq; + double errsq; + ae_int_t t0; + ae_bool result; + + + ae_assert(ae_isfinite(alpha0, _state)&&ae_fp_greater_eq(alpha0,(double)(0)), "VIPMFactorize: Alpha0 is infinite or negative", _state); + ae_assert(ae_isfinite(alpha11, _state)&&ae_fp_greater_eq(alpha11,(double)(0)), "VIPMFactorize: Alpha1 is infinite or negative", _state); + ae_assert(ae_isfinite(beta0, _state)&&ae_fp_greater_eq(beta0,(double)(0)), "VIPMFactorize: Beta0 is infinite or negative", _state); + ae_assert(ae_isfinite(beta11, _state)&&ae_fp_greater_eq(beta11,(double)(0)), "VIPMFactorize: Beta1 is infinite or negative", _state); + ae_assert(state->factorizationtype==0||state->factorizationtype==1, "VIPMFactorize: unexpected factorization type", _state); + ae_assert(state->factorizationpoweredup, "VIPMFactorize: critical integrity check failed (no powerup stage)", _state); + n = state->n; + nmain = state->nmain; + nslack = n-nmain; + m = state->mdense+state->msparse; + mdense = state->mdense; + msparse = state->msparse; + state->factorizationpresent = ae_false; + badchol = 1.0E50; + result = ae_true; + + /* + * Dense NxN normal equations approach + */ + if( state->factorizationtype==0 ) + { + + /* + * A problem formulation with possible slacks. + * + * === A FORMULATION WITHOUT FROZEN VARIABLES === + * + * We have to solve following system: + * + * [ -(H+Dh+Rh) Ah' ] [ Xh ] [ Bh ] + * [ -(Dz+Rz) Az' ] [ Xz ] = [ Bz ] + * [ Ah Az E ] [ Y ] [ By ] + * + * with Xh being NMain-dimensional vector, Xz being NSlack-dimensional vector, constraint + * matrix A being divided into non-slack and slack parts Ah and Az (and Ah, in turn, being + * divided into sparse and dense parts), Rh and Rz being diagonal regularization matrix, + * Y being M-dimensional vector. + * + * NOTE: due to definition of slack variables following holds: for any diagonal matrix W + * a product Az*W*Az' is a diagonal matrix. + * + * From the second line we get + * + * Xz = inv(Dz+Rz)*Az'*y - inv(Dz+Rz)*Bz + * = inv(Dz+Rz)*Az'*y - BzWave + * + * Using this value for Zx, third line gives us + * + * Y = inv(E+Az*inv(Dz+Rz)*Az')*(By+Az*BzWave-Ah*Xh) + * = inv(EWave)*(ByWave-Ah*Xh) + * with EWave = E+Az*inv(Dz+Rz)*Az' and ByWave = By+Az*BzWave + * + * Finally, first line gives us + * + * Xh = -inv(H+Dh+Rh+Ah'*inv(EWave)*Ah)*(Bh-Ah'*inv(EWave)*ByWave) + * = -inv(HWave)*BhWave + * with HWave = H+Dh+Rh+Ah'*inv(EWave)*Ah and BhWave = Bh-Ah'*inv(EWave)*ByWave + * + * In order to prepare factorization we need to compute: + * (a) diagonal matrices Dh, Rh, Dz and Rz (and precomputed inverse of Dz+Rz) + * (b) EWave + * (c) HWave + * + * === SPECIAL HANDLING OF FROZEN VARIABLES === + * + * Frozen variables result in zero steps, i.e. zero components of Xh and Xz. + * It could be implemented by explicit modification of KKT system (zeroing out + * columns/rows of KKT matrix, rows of right part, putting 1's to diagonal). + * + * However, it is possible to do without actually modifying quadratic term and + * constraints: + * * freezing elements of Xz can be implemented by zeroing out corresponding + * columns of inv(Dz+Rz) because Az always appears in computations along with diagonal Dz+Rz. + * * freezing elements of Xh is a bit more complex - it needs: + * * zeroing out columns/rows of HWave and setting up unit diagonal prior to solving for Xh + * * explicitly zeroing out computed elements of Xh prior to computing Y and Xz + */ + rvectorsetlengthatleast(&state->factregdhrh, nmain, _state); + rvectorsetlengthatleast(&state->factinvregdzrz, nslack, _state); + for(i=0; i<=n-1; i++) + { + v = (double)(0); + if( alpha0>(double)0 ) + { + v = v+alpha0*d->ptr.p_double[i]; + } + if( alpha11>(double)0 ) + { + v = v+alpha11; + } + v = v+state->diagr.ptr.p_double[i]; + v = v+dampeps; + ae_assert(v>(double)0, "VIPMFactorize: integrity check failed, degenerate diagonal matrix", _state); + if( i>=nmain ) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + state->factinvregdzrz.ptr.p_double[i-nmain] = (double)1/v; + } + else + { + state->factinvregdzrz.ptr.p_double[i-nmain] = 0.0; + } + } + else + { + state->factregdhrh.ptr.p_double[i] = v; + } + } + + /* + * Now we are ready to compute EWave + */ + rvectorsetlengthatleast(&state->factregewave, m, _state); + for(i=0; i<=m-1; i++) + { + + /* + * Compute diagonal element of E + */ + v = (double)(0); + if( beta0>(double)0 ) + { + v = v+beta0*e->ptr.p_double[i]; + } + if( beta11>(double)0 ) + { + v = v+beta11; + } + v = v+dampeps; + ae_assert(v>(double)0, "VIPMFactorize: integrity check failed, degenerate diagonal matrix", _state); + + /* + * Compute diagonal modification Az*inv(Dz)*Az' + */ + k0 = state->combinedaslack.ridx.ptr.p_int[i]; + k1 = state->combinedaslack.ridx.ptr.p_int[i+1]-1; + for(k=k0; k<=k1; k++) + { + vv = state->combinedaslack.vals.ptr.p_double[k]; + v = v+vv*vv*state->factinvregdzrz.ptr.p_double[state->combinedaslack.idx.ptr.p_int[k]]; + } + + /* + * Save EWave + */ + state->factregewave.ptr.p_double[i] = v; + } + + /* + * Now we are ready to compute HWave: + * * store H + * * add Dh + * * add Ah'*inv(EWave)*Ah + */ + rmatrixsetlengthatleast(&state->factdensehaug, nmain, nmain, _state); + ae_assert(state->hkind==0, "VIPMFactorize: unexpected HKind", _state); + rmatrixcopy(nmain, nmain, &state->denseh, 0, 0, &state->factdensehaug, 0, 0, _state); + for(i=0; i<=nmain-1; i++) + { + state->factdensehaug.ptr.pp_double[i][i] = state->factdensehaug.ptr.pp_double[i][i]+state->factregdhrh.ptr.p_double[i]; + } + if( msparse>0 ) + { + + /* + * Handle sparse part of Ah in Ah'*inv(EWave)*Ah + */ + for(i=0; i<=msparse-1; i++) + { + v = 1.0/state->factregewave.ptr.p_double[i]; + k0 = state->sparseamain.ridx.ptr.p_int[i]; + k1 = state->sparseamain.ridx.ptr.p_int[i+1]-1; + for(ka=k0; ka<=k1; ka++) + { + ja = state->sparseamain.idx.ptr.p_int[ka]; + va = state->sparseamain.vals.ptr.p_double[ka]; + for(kb=k0; kb<=ka; kb++) + { + jb = state->sparseamain.idx.ptr.p_int[kb]; + vb = state->sparseamain.vals.ptr.p_double[kb]; + state->factdensehaug.ptr.pp_double[ja][jb] = state->factdensehaug.ptr.pp_double[ja][jb]+v*va*vb; + } + } + } + } + if( mdense>0 ) + { + + /* + * Handle dense part of Ah in Ah'*inv(EWave)*Ah + */ + rmatrixsetlengthatleast(&state->tmpr2, mdense, nmain, _state); + rmatrixcopy(mdense, nmain, &state->denseamain, 0, 0, &state->tmpr2, 0, 0, _state); + for(i=0; i<=mdense-1; i++) + { + v = 1.0/ae_sqrt(state->factregewave.ptr.p_double[msparse+i], _state); + for(j=0; j<=nmain-1; j++) + { + state->tmpr2.ptr.pp_double[i][j] = v*state->tmpr2.ptr.pp_double[i][j]; + } + } + rmatrixsyrk(nmain, mdense, 1.0, &state->tmpr2, 0, 0, 2, 1.0, &state->factdensehaug, 0, 0, ae_false, _state); + } + + /* + * Zero out rows/cols of HWave corresponding to frozen variables, set up unit diagonal + */ + rsetallocv(nmain, 1.0, &state->tmp0, _state); + for(i=0; i<=nmain-1; i++) + { + if( state->isfrozen.ptr.p_bool[i] ) + { + state->tmp0.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=nmain-1; i++) + { + if( state->isfrozen.ptr.p_bool[i] ) + { + + /* + * Entire row is nullified except for diagonal element + */ + rsetr(i+1, 0.0, &state->factdensehaug, i, _state); + state->factdensehaug.ptr.pp_double[i][i] = 1.0; + } + else + { + + /* + * Only some components are nullified + */ + rmergemulvr(i+1, &state->tmp0, &state->factdensehaug, i, _state); + } + } + + /* + * Compute Cholesky factorization of HWave + */ + if( !spdmatrixcholesky(&state->factdensehaug, nmain, ae_false, _state) ) + { + result = ae_false; + return result; + } + v = (double)(0); + for(i=0; i<=nmain-1; i++) + { + v = v+state->factdensehaug.ptr.pp_double[i][i]; + } + if( !ae_isfinite(v, _state)||ae_fp_greater(v,badchol) ) + { + result = ae_false; + return result; + } + state->factorizationpresent = ae_true; + } + + /* + * Sparse (M+N)x(M+N) factorization + */ + if( state->factorizationtype==1 ) + { + t0 = 0; + + /* + * Generate reduced KKT matrix + */ + rallocv(n+m, &state->facttmpdiag, _state); + rallocv(n+m, &state->facttmpdamp, _state); + for(i=0; i<=n-1; i++) + { + vv = (double)(0); + if( alpha0>(double)0 ) + { + vv = vv+alpha0*d->ptr.p_double[i]; + } + if( alpha11>(double)0 ) + { + vv = vv+alpha11; + } + vv = vv+state->diagr.ptr.p_double[i]; + state->facttmpdiag.ptr.p_double[i] = -vv; + state->facttmpdamp.ptr.p_double[i] = -dampeps; + ae_assert(vv>(double)0, "VIPMFactorize: integrity check failed, degenerate diagonal matrix", _state); + } + for(i=0; i<=msparse+mdense-1; i++) + { + vv = (double)(0); + if( beta0>(double)0 ) + { + vv = vv+beta0*e->ptr.p_double[i]; + } + if( beta11>(double)0 ) + { + vv = vv+beta11; + } + state->facttmpdiag.ptr.p_double[n+i] = vv; + state->facttmpdamp.ptr.p_double[n+i] = dampeps; + ae_assert(vv>(double)0, "VIPMFactorize: integrity check failed, degenerate diagonal matrix", _state); + } + + /* + * Perform factorization + * Perform additional integrity check: LDLT should reproduce diagonal of initial KKT system with good precision + */ + if( state->dotrace ) + { + ae_trace("--- sparse KKT factorization report ----------------------------------------------------------------\n"); + t0 = ae_tickcount(); + } + if( !vipmsolver_reducedsystemfactorizewithaddends(&state->reducedsparsesystem, &state->facttmpdiag, &state->facttmpdamp, modeps, badchol, &sumsq, &errsq, _state) ) + { + result = ae_false; + return result; + } + if( state->dotrace ) + { + ae_trace("> factorized in %0d ms\n", + (int)(ae_tickcount()-t0)); + } + if( ae_fp_greater(ae_sqrt(errsq/((double)1+sumsq), _state),ae_sqrt(ae_machineepsilon, _state)) ) + { + if( state->dotrace ) + { + ae_trace("LDLT-diag-err= %0.3e (diagonal reproduction error)\n", + (double)(ae_sqrt(errsq/((double)1+sumsq), _state))); + } + result = ae_false; + return result; + } + state->factorizationpresent = ae_true; + + /* + * Trace + */ + if( state->dotrace ) + { + ae_trace("diag-err = %0.3e (diagonal reproduction error)\n", + (double)(ae_sqrt(errsq/((double)1+sumsq), _state))); + } + } + + /* + * Done, integrity control + */ + ae_assert(state->factorizationpresent, "VIPMFactorize: integrity check failed", _state); + inc(&state->repncholesky, _state); + return result; +} + + +/************************************************************************* +A low-level function which solves KKT system whose regularized (!) +factorization was prepared by VIPMFactorize(). No iterative refinement is +performed. + +On input, right-hand-side is stored in DeltaXY; on output, solution replaces +DeltaXY. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_solvereducedkktsystem(vipmstate* state, + /* Real */ ae_vector* deltaxy, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nmain; + ae_int_t nslack; + ae_int_t m; + ae_int_t mdense; + ae_int_t msparse; + ae_int_t i; + + + ae_assert(state->factorizationpresent, "VIPMSolve: integrity check failed - factorization is not present", _state); + ae_assert(state->factorizationtype==0||state->factorizationtype==1, "VIPMSolve: unexpected factorization type", _state); + n = state->n; + nmain = state->nmain; + nslack = n-nmain; + m = state->mdense+state->msparse; + mdense = state->mdense; + msparse = state->msparse; + + /* + * Dense solving + */ + if( state->factorizationtype==0 ) + { + + /* + * Compute + * + * BzWave = inv(Dz+Rz)*Bz + * ByWave = By+Az*BzWave + * BhWave = Bh-Ah'*inv(EWave)*ByWave + */ + for(i=0; i<=nslack-1; i++) + { + deltaxy->ptr.p_double[nmain+i] = deltaxy->ptr.p_double[nmain+i]*state->factinvregdzrz.ptr.p_double[i]; + } + sparsegemv(&state->combinedaslack, 1.0, 0, deltaxy, nmain, 1.0, deltaxy, n, _state); + rvectorsetlengthatleast(&state->tmp1, m, _state); + for(i=0; i<=m-1; i++) + { + state->tmp1.ptr.p_double[i] = deltaxy->ptr.p_double[n+i]/state->factregewave.ptr.p_double[i]; + } + sparsegemv(&state->sparseamain, -1.0, 1, &state->tmp1, 0, 1.0, deltaxy, 0, _state); + rmatrixgemv(nmain, mdense, -1.0, &state->denseamain, 0, 0, 1, &state->tmp1, msparse, 1.0, deltaxy, 0, _state); + + /* + * Compute Xh = -inv(HWave)*BhWave. + * Zero out components corresponding to frozen variables. + */ + for(i=0; i<=nmain-1; i++) + { + deltaxy->ptr.p_double[i] = -deltaxy->ptr.p_double[i]; + } + rmatrixtrsv(nmain, &state->factdensehaug, 0, 0, ae_false, ae_false, 0, deltaxy, 0, _state); + rmatrixtrsv(nmain, &state->factdensehaug, 0, 0, ae_false, ae_false, 1, deltaxy, 0, _state); + for(i=0; i<=n-1; i++) + { + if( state->isfrozen.ptr.p_bool[i] ) + { + deltaxy->ptr.p_double[i] = (double)(0); + } + } + + /* + * Compute Y = inv(EWave)*(ByWave-Ah*Xh) + */ + sparsegemv(&state->sparseamain, -1.0, 0, deltaxy, 0, 1.0, deltaxy, n, _state); + rmatrixgemv(mdense, nmain, -1.0, &state->denseamain, 0, 0, 0, deltaxy, 0, 1.0, deltaxy, n+msparse, _state); + for(i=0; i<=m-1; i++) + { + deltaxy->ptr.p_double[n+i] = deltaxy->ptr.p_double[n+i]/state->factregewave.ptr.p_double[i]; + } + + /* + * Compute Xz = -(BzWave - inv(Dz+Rz)*Az'*y) + */ + rvectorsetlengthatleast(&state->tmp0, nslack, _state); + for(i=0; i<=nslack-1; i++) + { + state->tmp0.ptr.p_double[i] = (double)(0); + } + sparsegemv(&state->combinedaslack, 1.0, 1, deltaxy, n, 1.0, &state->tmp0, 0, _state); + for(i=0; i<=nslack-1; i++) + { + deltaxy->ptr.p_double[nmain+i] = -(deltaxy->ptr.p_double[nmain+i]-state->factinvregdzrz.ptr.p_double[i]*state->tmp0.ptr.p_double[i]); + } + + /* + * Done + */ + return; + } + + /* + * Sparse solving + */ + if( state->factorizationtype==1 ) + { + vipmsolver_reducedsystemsolve(&state->reducedsparsesystem, state->dotrace, deltaxy, _state); + for(i=0; i<=n-1; i++) + { + if( state->isfrozen.ptr.p_bool[i] ) + { + deltaxy->ptr.p_double[i] = (double)(0); + } + } + return; + } + + /* + * + */ + ae_assert(ae_false, "VIPMSolve: integrity check failed - unexpected factorization", _state); +} + + +/************************************************************************* +Generates precomputed temporary vectors and KKT factorization at the +beginning of the current iteration. + +This function uses representation of KKT system inspired by Vanderbei +slack variable approach, but with additional regularization being applied +all along computations. + +On successful factorization returns True; on failure returns False - it is +recommended to increase regularization parameter and try one more time. + +--- DESCRIPTION ---------------------------------------------------------- + +Initial KKT system proposed by Vanderbei has following structure: + + (1) -DS*deltaT - I*deltaS = -mu/T + s + DELTAT*DELTAS/T = -GammaS + (2) -DZ*deltaG - I*deltaZ = -mu/G + z + DELTAG*DELTAZ/G = -GammaZ + (3) -DQ*deltaP - I*deltaQ = -mu/P + q + DELTAP*DELTAQ/P = -GammaQ + (4) -DW*deltaV - I*deltaW = -mu/V + w + DELTAV*DELTAW/V = -GammaW + (5) -I*deltaY - I*deltaQ + I*deltaV = y-q+v = Beta + (6) -H*deltaX +A'*deltaY + I*deltaZ - I*deltaS = c-A'*y-z+s+H*x = Sigma + (7) A*deltaX - I*deltaW = b-A*x+w = Rho + (8) I*deltaX - I*deltaG = l-x+g = Nu + (9) -I*deltaX - I*deltaT = -u+x+t = -Tau + (10) -I*deltaW - I*deltaP = -r+w+p = -Alpha + +where + + DS = diag(S/T) + DZ = diag(Z/G) + DQ = diag(Q/P) + DW = diag(W/V) + +This linear system is actually symmetric indefinite one, that can be +regularized by modifying equations (5), (6), (7), (8), (9), (10): + + (5) -I*deltaY - I*deltaQ + I*deltaV -REG*deltaW= y+q-v+REG*w = Beta + (6) -(H+REG)*deltaX +A'*deltaY + I*deltaZ - I*deltaS = c-A'*y-z+s+(H+REG)*x = Sigma + (7) A*deltaX - I*deltaW +REG*deltaY= b-A*x+w-REG*y = Rho + (8) I*deltaX - I*deltaG +REG*deltaZ= l-x+g-REG*z = Nu + (9) -I*deltaX - I*deltaT +REG*deltaS= -u+x+t-REG*s = -Tau + (10) -I*deltaW - I*deltaP +REG*deltaQ= -r+w+p-REG*q = -Alpha + +NOTE: regularizing equations (5)-(10) seems to be beneficial because their + coefficients are well-normalized, usually having unit scale. Contrary + to that, equations (1)-(4) are wildly nonnormalized, and regularization + ruins algorithm convergence. + +From (1), (2), (3) and (4) we obtain + + deltaT = (GammaS-I*deltaS)/DS + deltaG = (GammaZ-I*deltaZ)/DZ + deltaP = (GammaQ-I*deltaQ)/DQ + deltaV = (GammaW-I*deltaW)/DW + +and substitute them to equations to obtain + + (5) -I*deltaY - I*deltaQ - (inv(DW)+REG)*deltaW = Beta-inv(DW)*GammaW = BetaCap + (8) I*deltaX + (inv(DZ)+REG)*deltaZ = Nu+inv(DZ)*GammaZ = NuCap + (9) -I*deltaX + (inv(DS)+REG)*deltaS = -(Tau-inv(DS)*GammaS) = -TauCap + (10) -I*deltaW + (inv(DQ)+REG)*deltaQ = -(Alpha-inv(DQ)*GammaQ) = -AlphaCap + (6) A'*deltaY + I*deltaZ - I*deltaS - (H+REG)*deltaX = c-A'*y-z+s+(H+REG)*x = Sigma + (7) REG*deltaY + A*deltaX - I*deltaW = b-A*x+w-REG*y = Rho + +then, we obtain (here IRI stands for Invert-Regularize-Invert) + + DQIRI = inv(inv(DQ)+REG) + DZIRI = inv(inv(DZ)+REG) + DSIRI = inv(inv(DS)+REG) + + deltaQ = (I*deltaW-AlphaCap)*DQIRI + deltaZ = (NuCap-I*deltaX)*DZIRI + deltaS = (I*deltaX-TauCap)*DSIRI + + DWIR = inv(DW)+REG + +and after substitution + + (5) -I*deltaY - (DQIRI+DWIR)*deltaW = BetaCap-DQIRI*AlphaCap + (6) A'*deltaY - (H+REG+DSIRI+DZIRI)*deltaX = Sigma-DSIRI*TauCap-DZIRI*NuCap + (7) REG*deltaY + A*deltaX - I*deltaW = Rho + +finally, we obtain + + DE = inv(DQIRI+DWIR) + DER = DE+REG + DDR = DSIRI+DZIRI+REG + deltaW = -(BetaCap-DQIRI*AlphaCap+I*deltaY)*DE + +and after substitution + + (6) -(H+DDR)*deltaX + A'*deltaY = Sigma-DSIRI*TauCap-DZIRI*NuCap + (7) A*deltaX + DER*deltaY = Rho-DE*(BetaCap-DQIRI*AlphaCap) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static ae_bool vipmsolver_vipmprecomputenewtonfactorization(vipmstate* state, + const vipmvars* v0, + double regeps, + double modeps, + double dampeps, + double dampfree, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_bool result; + + + n = state->n; + m = state->mdense+state->msparse; + rsetallocv(n, 0.0, &state->diagdz, _state); + rsetallocv(n, 0.0, &state->diagdzi, _state); + rsetallocv(n, 0.0, &state->diagdziri, _state); + rsetallocv(n, 0.0, &state->diagds, _state); + rsetallocv(n, 0.0, &state->diagdsi, _state); + rsetallocv(n, 0.0, &state->diagdsiri, _state); + rsetallocv(m, 0.0, &state->diagdw, _state); + rsetallocv(m, 0.0, &state->diagdwi, _state); + rsetallocv(m, 0.0, &state->diagdwir, _state); + rsetallocv(m, 0.0, &state->diagdq, _state); + rsetallocv(m, 0.0, &state->diagdqi, _state); + rsetallocv(m, 0.0, &state->diagdqiri, _state); + rallocv(n, &state->diagddr, _state); + rallocv(m, &state->diagde, _state); + rallocv(m, &state->diagder, _state); + + /* + * Handle temporary matrices arising due to box constraints + */ + for(i=0; i<=n-1; i++) + { + + /* + * Lower bound: G*inv(Z) and Z*inv(G) + */ + if( state->hasgz.ptr.p_bool[i] ) + { + ae_assert(v0->g.ptr.p_double[i]>0.0&&v0->z.ptr.p_double[i]>0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - G[i]<=0 or Z[i]<=0", _state); + state->diagdz.ptr.p_double[i] = v0->z.ptr.p_double[i]/v0->g.ptr.p_double[i]; + state->diagdzi.ptr.p_double[i] = (double)1/state->diagdz.ptr.p_double[i]; + state->diagdziri.ptr.p_double[i] = (double)1/(state->diagdzi.ptr.p_double[i]+regeps); + } + else + { + ae_assert(v0->g.ptr.p_double[i]==0.0&&v0->z.ptr.p_double[i]==0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - G[i]<>0 or Z[i]<>0 for absent lower bound", _state); + } + + /* + * Upper bound: T*inv(S) and S*inv(T) + */ + if( state->hasts.ptr.p_bool[i] ) + { + ae_assert(v0->t.ptr.p_double[i]>0.0&&v0->s.ptr.p_double[i]>0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - T[i]<=0 or S[i]<=0", _state); + state->diagds.ptr.p_double[i] = v0->s.ptr.p_double[i]/v0->t.ptr.p_double[i]; + state->diagdsi.ptr.p_double[i] = (double)1/state->diagds.ptr.p_double[i]; + state->diagdsiri.ptr.p_double[i] = (double)1/(state->diagdsi.ptr.p_double[i]+regeps); + } + else + { + ae_assert(v0->t.ptr.p_double[i]==0.0&&v0->s.ptr.p_double[i]==0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - T[i]<>0 or S[i]<>0 for absent upper bound", _state); + } + + /* + * Diagonal term D + */ + state->diagddr.ptr.p_double[i] = state->diagdziri.ptr.p_double[i]+state->diagdsiri.ptr.p_double[i]+regeps; + if( !state->hasgz.ptr.p_bool[i]&&!state->hasts.ptr.p_bool[i] ) + { + state->diagddr.ptr.p_double[i] = state->diagddr.ptr.p_double[i]+dampfree; + } + } + + /* + * Handle temporary matrices arising due to linear constraints: with lower bound B[] + * or with lower and upper bounds. + */ + for(i=0; i<=m-1; i++) + { + + /* + * Lower bound + */ + if( state->haswv.ptr.p_bool[i] ) + { + ae_assert(v0->v.ptr.p_double[i]>0.0&&v0->w.ptr.p_double[i]>0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - V[i]<=0 or W[i]<=0", _state); + state->diagdw.ptr.p_double[i] = v0->w.ptr.p_double[i]/v0->v.ptr.p_double[i]; + state->diagdwi.ptr.p_double[i] = (double)1/state->diagdw.ptr.p_double[i]; + state->diagdwir.ptr.p_double[i] = state->diagdwi.ptr.p_double[i]+regeps; + } + else + { + ae_assert(v0->v.ptr.p_double[i]==0.0&&v0->w.ptr.p_double[i]==0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - V[i]<>0 or W[i]<>0 for linear equality constraint", _state); + } + + /* + * Upper bound + */ + if( state->haspq.ptr.p_bool[i] ) + { + ae_assert(v0->p.ptr.p_double[i]>0.0&&v0->q.ptr.p_double[i]>0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - P[i]<=0 or Q[i]<=0", _state); + state->diagdq.ptr.p_double[i] = v0->q.ptr.p_double[i]/v0->p.ptr.p_double[i]; + state->diagdqi.ptr.p_double[i] = (double)1/state->diagdq.ptr.p_double[i]; + state->diagdqiri.ptr.p_double[i] = (double)1/(state->diagdqi.ptr.p_double[i]+regeps); + } + else + { + ae_assert(v0->p.ptr.p_double[i]==0.0&&v0->q.ptr.p_double[i]==0.0, "VIPMPrecomputeNewtonFactorization: integrity failure - P[i]<>0 or Q[i]<>0 for absent linear constraint", _state); + } + + /* + * Diagonal term E + */ + if( state->haswv.ptr.p_bool[i]||state->haspq.ptr.p_bool[i] ) + { + state->diagde.ptr.p_double[i] = (double)1/(state->diagdwir.ptr.p_double[i]+state->diagdqiri.ptr.p_double[i]); + } + else + { + state->diagde.ptr.p_double[i] = 0.0; + } + state->diagder.ptr.p_double[i] = state->diagde.ptr.p_double[i]+regeps; + } + + /* + * Perform factorization + */ + result = vipmsolver_vipmfactorize(state, 1.0, &state->diagddr, 1.0, &state->diagder, 0.0, 0.0, modeps, dampeps, _state); + return result; +} + + +/************************************************************************* +Solves KKT system stored in VIPMState with user-passed RHS. +Sol must be preallocated VIPMVars object whose initial values are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_solvekktsystem(vipmstate* state, + const vipmrighthandside* rhs, + vipmvars* sol, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = state->mdense+state->msparse; + + /* + * Compute elimination temporaries + * + * RhsAlphaCap = RhsAlpha - InvDQ*GammaQ + * RhsNuCap = RhsNu + InvDZ*GammaZ + * RhsTauCap = RhsTau - InvDS*GammaS + * RhsBetaCap = RhsBeta - InvDW*GammaW + */ + rallocv(n, &state->rhsnucap, _state); + rallocv(n, &state->rhstaucap, _state); + rallocv(m, &state->rhsbetacap, _state); + rallocv(m, &state->rhsalphacap, _state); + rcopynegmuladdv(m, &state->diagdqi, &rhs->gammaq, &rhs->alpha, &state->rhsalphacap, _state); + rcopymuladdv(n, &state->diagdzi, &rhs->gammaz, &rhs->nu, &state->rhsnucap, _state); + rcopynegmuladdv(n, &state->diagdsi, &rhs->gammas, &rhs->tau, &state->rhstaucap, _state); + rcopynegmuladdv(m, &state->diagdwi, &rhs->gammaw, &rhs->beta, &state->rhsbetacap, _state); + + /* + * Solve reduced KKT system + */ + rvectorsetlengthatleast(&state->deltaxy, n+m, _state); + for(i=0; i<=n-1; i++) + { + state->deltaxy.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]-state->diagdziri.ptr.p_double[i]*state->rhsnucap.ptr.p_double[i]-state->diagdsiri.ptr.p_double[i]*state->rhstaucap.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + state->deltaxy.ptr.p_double[n+i] = rhs->rho.ptr.p_double[i]-state->diagde.ptr.p_double[i]*(state->rhsbetacap.ptr.p_double[i]-state->diagdqiri.ptr.p_double[i]*state->rhsalphacap.ptr.p_double[i]); + } + vipmsolver_solvereducedkktsystem(state, &state->deltaxy, _state); + + /* + * Perform backsubstitution + */ + for(i=0; i<=n-1; i++) + { + sol->x.ptr.p_double[i] = state->deltaxy.ptr.p_double[i]; + sol->s.ptr.p_double[i] = state->diagdsiri.ptr.p_double[i]*(sol->x.ptr.p_double[i]-state->rhstaucap.ptr.p_double[i]); + sol->z.ptr.p_double[i] = state->diagdziri.ptr.p_double[i]*(state->rhsnucap.ptr.p_double[i]-sol->x.ptr.p_double[i]); + sol->g.ptr.p_double[i] = state->diagdzi.ptr.p_double[i]*(rhs->gammaz.ptr.p_double[i]-sol->z.ptr.p_double[i]); + sol->t.ptr.p_double[i] = state->diagdsi.ptr.p_double[i]*(rhs->gammas.ptr.p_double[i]-sol->s.ptr.p_double[i]); + } + for(i=0; i<=m-1; i++) + { + sol->y.ptr.p_double[i] = state->deltaxy.ptr.p_double[n+i]; + sol->w.ptr.p_double[i] = -state->diagde.ptr.p_double[i]*(state->rhsbetacap.ptr.p_double[i]-state->diagdqiri.ptr.p_double[i]*state->rhsalphacap.ptr.p_double[i]+sol->y.ptr.p_double[i]); + sol->q.ptr.p_double[i] = state->diagdqiri.ptr.p_double[i]*(sol->w.ptr.p_double[i]-state->rhsalphacap.ptr.p_double[i]); + sol->v.ptr.p_double[i] = state->diagdwi.ptr.p_double[i]*(rhs->gammaw.ptr.p_double[i]-sol->w.ptr.p_double[i]); + sol->p.ptr.p_double[i] = state->diagdqi.ptr.p_double[i]*(rhs->gammaq.ptr.p_double[i]-sol->q.ptr.p_double[i]); + } +} + + +/************************************************************************* +Compute VIPM step by solving KKT system. + +VDResult must be preallocated VIPMVars object whose initial values are +ignored. + +Returns False on failure to compute step direction with reasonable accuracy +(it is advised to terminate iterations immediately). + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_bool vipmsolver_vipmcomputestepdirection(vipmstate* state, + const vipmvars* v0, + double muestimate, + const vipmvars* vdestimate, + vipmvars* vdresult, + double reg, + ae_bool isdampepslarge, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + double vrhsprim2; + double vrhsdual2; + double vrhscmpl2; + double vresprim2; + double vresdual2; + double vrescmpl2; + double vrhspriminf; + double vrhsdualinf; + double vrespriminf; + double vresdualinf; + double badres; + double verybadres; + double residualgrowth; + ae_bool primaldestabilized; + ae_bool dualdestabilized; + ae_bool result; + + + n = state->n; + m = state->mdense+state->msparse; + badres = 1.01; + verybadres = 1.0E3; + result = ae_true; + + /* + * Initial solver report + */ + if( state->dotrace ) + { + ae_trace("--- detailed KKT solver report ---------------------------------------------------------------------\n"); + } + + /* + * Solve KKT system with right-hand sides coming from primal, dual + * and complementary slackness conditions. Analyze solution, + * terminate immediately if primal/dual residuals are way too high. + */ + vipmsolver_rhscompute(state, v0, muestimate, vdestimate, &state->rhs, reg, _state); + vrhsprim2 = vipmsolver_rhsprimal2(&state->rhs, n, m, _state); + vrhsdual2 = vipmsolver_rhsdual2(&state->rhs, n, m, _state); + vrhscmpl2 = vipmsolver_rhscompl2(&state->rhs, n, m, _state); + vrhspriminf = vipmsolver_rhsprimalinf(&state->rhs, n, m, _state); + vrhsdualinf = vipmsolver_rhsdualinf(&state->rhs, n, m, _state); + if( state->dotrace ) + { + ae_trace("> primal/dual/complementarity right-hand-side\n"); + ae_trace("rhs-prim = %0.3e (2-norm)\n", + (double)(ae_sqrt(vrhsprim2, _state))); + ae_trace("rhs-dual = %0.3e (2-norm)\n", + (double)(ae_sqrt(vrhsdual2, _state))); + ae_trace("rhs-cmpl = %0.3e (2-norm)\n", + (double)(ae_sqrt(vrhscmpl2, _state))); + } + vipmsolver_solvekktsystem(state, &state->rhs, vdresult, _state); + vipmsolver_rhssubtract(state, &state->rhs, v0, vdresult, reg, _state); + vresprim2 = vipmsolver_rhsprimal2(&state->rhs, n, m, _state); + vresdual2 = vipmsolver_rhsdual2(&state->rhs, n, m, _state); + vrescmpl2 = vipmsolver_rhscompl2(&state->rhs, n, m, _state); + vrespriminf = vipmsolver_rhsprimalinf(&state->rhs, n, m, _state); + vresdualinf = vipmsolver_rhsdualinf(&state->rhs, n, m, _state); + if( state->dotrace ) + { + ae_trace("> primal/dual/complementarity residuals compared with RHS\n"); + ae_trace("res/rhs prim = %0.3e\n", + (double)(ae_sqrt(vresprim2/coalesce(vrhsprim2, (double)(1), _state), _state))); + ae_trace("res/rhs dual = %0.3e\n", + (double)(ae_sqrt(vresdual2/coalesce(vrhsdual2, (double)(1), _state), _state))); + ae_trace("res/rhs cmpl = %0.3e\n", + (double)(ae_sqrt(vrescmpl2/coalesce(vrhscmpl2, (double)(1), _state), _state))); + ae_trace("res/rhs all = %0.3e\n", + (double)(ae_sqrt((vresprim2+vresdual2+vrescmpl2)/coalesce(vrhsprim2+vrhsdual2+vrhscmpl2, (double)(1), _state), _state))); + } + primaldestabilized = ae_fp_less_eq(vrhspriminf,state->epsp)&&ae_fp_greater_eq(vrespriminf,ae_maxreal(verybadres*vrhspriminf, state->epsp, _state)); + dualdestabilized = ae_fp_less_eq(vrhsdualinf,state->epsd)&&ae_fp_greater_eq(vresdualinf,ae_maxreal(verybadres*vrhsdualinf, state->epsd, _state)); + residualgrowth = ae_sqrt((vresprim2+vresdual2+vrescmpl2)/coalesce(vrhsprim2+vrhsdual2+vrhscmpl2, (double)(1), _state), _state); + if( ((primaldestabilized||dualdestabilized)&&ae_fp_greater(residualgrowth,0.01*ae_sqrt(ae_machineepsilon, _state)))&&!isdampepslarge ) + { + if( state->dotrace ) + { + ae_trace("> primal/dual residual growth is too high, signaling presence of numerical errors\n"); + } + result = ae_false; + return result; + } + if( ae_fp_greater(residualgrowth,badres) ) + { + if( state->dotrace ) + { + ae_trace("> total residual is too high, signaling presence of numerical errors\n"); + } + result = ae_false; + return result; + } + return result; +} + + +/************************************************************************* +This function estimates primal and dual step lengths (subject to step +decay parameter, which should be in [0,1] range). + +Current version returns same step lengths for primal and dual steps. + +INPUT PARAMETERS: + State - solver state + V0 - current point (we ignore one stored in State.Current) + VS - step direction + StepDecay - decay parameter, the step is multiplied by this + coefficient. 1.0 corresponds to full step + length being returned. Values in (0,1] range. + SeparateStep - separate step for primal and dual vars + +OUTPUT PARAMETERS: + AlphaP - primal step (after applying decay coefficient) + AlphaD - dual step (after applying decay coefficient) + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_vipmcomputesteplength(const vipmstate* state, + const vipmvars* v0, + const vipmvars* vs, + double stepdecay, + ae_bool separatestep, + double* alphap, + double* alphad, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + double alpha; + + *alphap = 0.0; + *alphad = 0.0; + + n = state->n; + m = state->mdense+state->msparse; + ae_assert(n==v0->n&&m==v0->m, "VIPMComputeStepLength: sizes mismatch", _state); + *alphap = (double)(1); + *alphad = (double)(1); + for(i=0; i<=n-1; i++) + { + + /* + * Primal + */ + if( vs->g.ptr.p_double[i]<0.0 ) + { + *alphap = safeminposrv(v0->g.ptr.p_double[i], -vs->g.ptr.p_double[i], *alphap, _state); + } + if( vs->t.ptr.p_double[i]<0.0 ) + { + *alphap = safeminposrv(v0->t.ptr.p_double[i], -vs->t.ptr.p_double[i], *alphap, _state); + } + + /* + * Dual + */ + if( vs->z.ptr.p_double[i]<0.0 ) + { + *alphad = safeminposrv(v0->z.ptr.p_double[i], -vs->z.ptr.p_double[i], *alphad, _state); + } + if( vs->s.ptr.p_double[i]<0.0 ) + { + *alphad = safeminposrv(v0->s.ptr.p_double[i], -vs->s.ptr.p_double[i], *alphad, _state); + } + } + for(i=0; i<=m-1; i++) + { + + /* + * Primal + */ + if( vs->w.ptr.p_double[i]<0.0 ) + { + *alphap = safeminposrv(v0->w.ptr.p_double[i], -vs->w.ptr.p_double[i], *alphap, _state); + } + if( vs->p.ptr.p_double[i]<0.0 ) + { + *alphap = safeminposrv(v0->p.ptr.p_double[i], -vs->p.ptr.p_double[i], *alphap, _state); + } + + /* + * Dual + */ + if( vs->v.ptr.p_double[i]<0.0 ) + { + *alphad = safeminposrv(v0->v.ptr.p_double[i], -vs->v.ptr.p_double[i], *alphad, _state); + } + if( vs->q.ptr.p_double[i]<0.0 ) + { + *alphad = safeminposrv(v0->q.ptr.p_double[i], -vs->q.ptr.p_double[i], *alphad, _state); + } + } + + /* + * Separate step or joint step? + */ + if( separatestep ) + { + + /* + * Separate step on primal/dual + */ + *alphap = stepdecay*(*alphap); + *alphad = stepdecay*(*alphad); + } + else + { + + /* + * Because we may solve QP problem, step length has to be same for primal and dual variables + */ + alpha = ae_minreal(*alphap, *alphad, _state); + *alphap = stepdecay*alpha; + *alphad = stepdecay*alpha; + } +} + + +/************************************************************************* +This function performs IPM step, updates iteration counts and performs +following additional checks: +* it monitors status of box/linear constraints and smoothly drops ones + with too large bounds (a variable or linear sum is well below constraint + bound for several iterations) + +INPUT PARAMETERS: + State - solver state + AlphaP - primal step to perform + AlphaD - dual step to perform + +OUTPUT PARAMETERS: + + -- ALGLIB -- + Copyright 01.08.2020 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_vipmperformstep(vipmstate* state, + double alphap, + double alphad, + ae_state *_state) +{ + + + + /* + * Perform step + */ + vipmsolver_varsaddstep(&state->current, &state->deltacorr, alphap, alphad, _state); + + /* + * Update iterations count + */ + inc(&state->repiterationscount, _state); +} + + +/************************************************************************* +Compute primal/dual errors and complementarity gap + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_computeerrors(vipmstate* state, + double* errp2, + double* errd2, + double* errpinf, + double* errdinf, + double* egap, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t cntp2; + ae_int_t cntd2; + double v; + + *errp2 = 0.0; + *errd2 = 0.0; + *errpinf = 0.0; + *errdinf = 0.0; + *egap = 0.0; + + n = state->n; + m = state->mdense+state->msparse; + + /* + * Compute primal and dual infeasibilities + */ + vipmsolver_vipmmultiply(state, &state->current.x, &state->current.y, &state->tmphx, &state->tmpax, &state->tmpaty, _state); + cntp2 = 0; + *errp2 = (double)(0); + *errpinf = (double)(0); + for(i=0; i<=m-1; i++) + { + v = state->tmpax.ptr.p_double[i]-state->current.w.ptr.p_double[i]-state->b.ptr.p_double[i]; + *errp2 = *errp2+v*v; + *errpinf = ae_maxreal(*errpinf, ae_fabs(v, _state), _state); + inc(&cntp2, _state); + if( state->haspq.ptr.p_bool[i] ) + { + v = state->current.w.ptr.p_double[i]+state->current.p.ptr.p_double[i]-state->r.ptr.p_double[i]; + *errp2 = *errp2+v*v; + *errpinf = ae_maxreal(*errpinf, ae_fabs(v, _state), _state); + inc(&cntp2, _state); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + v = state->current.x.ptr.p_double[i]-state->current.g.ptr.p_double[i]-state->bndl.ptr.p_double[i]; + *errp2 = *errp2+v*v; + *errpinf = ae_maxreal(*errpinf, ae_fabs(v, _state), _state); + inc(&cntp2, _state); + } + if( state->hasts.ptr.p_bool[i] ) + { + v = state->current.x.ptr.p_double[i]+state->current.t.ptr.p_double[i]-state->bndu.ptr.p_double[i]; + *errp2 = *errp2+v*v; + *errpinf = ae_maxreal(*errpinf, ae_fabs(v, _state), _state); + inc(&cntp2, _state); + } + } + *errp2 = ae_sqrt(*errp2/coalesce((double)(cntp2), (double)(1), _state), _state); + cntd2 = 0; + *errd2 = (double)(0); + *errdinf = (double)(0); + for(i=0; i<=n-1; i++) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + v = state->tmphx.ptr.p_double[i]+state->c.ptr.p_double[i]-state->tmpaty.ptr.p_double[i]; + if( state->hasgz.ptr.p_bool[i] ) + { + v = v-state->current.z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + v = v+state->current.s.ptr.p_double[i]; + } + *errd2 = *errd2+v*v; + *errdinf = ae_maxreal(*errdinf, ae_fabs(v, _state), _state); + inc(&cntd2, _state); + } + } + for(i=0; i<=m-1; i++) + { + v = (double)(0); + if( state->haswv.ptr.p_bool[i] ) + { + v = state->current.y.ptr.p_double[i]-state->current.v.ptr.p_double[i]; + } + if( state->haspq.ptr.p_bool[i] ) + { + v = v+state->current.q.ptr.p_double[i]; + } + *errd2 = *errd2+v*v; + *errdinf = ae_maxreal(*errdinf, ae_fabs(v, _state), _state); + if( state->haswv.ptr.p_bool[i]||state->haspq.ptr.p_bool[i] ) + { + inc(&cntd2, _state); + } + } + *errd2 = ae_sqrt(*errd2/coalesce((double)(cntd2), (double)(1), _state), _state); + *egap = vipmsolver_varscomputecomplementaritygap(&state->current, _state)/(1.0+ae_fabs(vipmsolver_vipmtarget(state, &state->current.x, _state), _state)); +} + + +/************************************************************************* +Performs integrity checks for current point and step + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_runintegritychecks(const vipmstate* state, + const vipmvars* v0, + const vipmvars* vd, + double alphap, + double alphad, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = state->mdense+state->msparse; + ae_assert(ae_isfinite(alphap, _state)&&ae_fp_greater_eq(alphap,(double)(0)), "[VIPM]RunIntegrityChecks: bad AlphaP", _state); + ae_assert(ae_isfinite(alphad, _state)&&ae_fp_greater_eq(alphad,(double)(0)), "[VIPM]RunIntegrityChecks: bad AlphaD", _state); + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + ae_assert(!state->isfrozen.ptr.p_bool[i], "[VIPM]RunIntegrityChecks: integrity failure - X[I] is frozen", _state); + ae_assert(v0->g.ptr.p_double[i]>0.0&&v0->z.ptr.p_double[i]>0.0, "[VIPM]RunIntegrityChecks: integrity failure - G[i]<=0 or Z[i]<=0", _state); + } + else + { + ae_assert(v0->g.ptr.p_double[i]==0.0&&v0->z.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - G[i]<>0 or Z[i]<>0 for absent lower bound", _state); + ae_assert(vd->g.ptr.p_double[i]==0.0&&vd->z.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - G[i]<>0 or Z[i]<>0 for absent lower bound", _state); + } + if( state->hasts.ptr.p_bool[i] ) + { + ae_assert(!state->isfrozen.ptr.p_bool[i], "[VIPM]RunIntegrityChecks: integrity failure - X[I] is frozen", _state); + ae_assert(v0->t.ptr.p_double[i]>0.0&&v0->s.ptr.p_double[i]>0.0, "[VIPM]RunIntegrityChecks: integrity failure - T[i]<=0 or S[i]<=0", _state); + } + else + { + ae_assert(v0->t.ptr.p_double[i]==0.0&&v0->s.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - T[i]<>0 or S[i]<>0 for absent upper bound", _state); + ae_assert(vd->t.ptr.p_double[i]==0.0&&vd->s.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - T[i]<>0 or S[i]<>0 for absent upper bound", _state); + } + } + for(i=0; i<=m-1; i++) + { + ae_assert(state->haswv.ptr.p_bool[i]||!state->haspq.ptr.p_bool[i], "[VIPM]RunIntegrityChecks: inconsistent HasWV/HasPQ", _state); + if( state->haswv.ptr.p_bool[i] ) + { + ae_assert(v0->v.ptr.p_double[i]>0.0&&v0->w.ptr.p_double[i]>0.0, "[VIPM]RunIntegrityChecks: integrity failure - V[i]<=0 or W[i]<=0", _state); + } + else + { + ae_assert(v0->v.ptr.p_double[i]==0.0&&v0->w.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - V[i]<>0 or W[i]<>0 for linear equality constraint", _state); + ae_assert(vd->v.ptr.p_double[i]==0.0&&vd->w.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - V[i]<>0 or W[i]<>0 for linear equality constraint", _state); + } + if( state->haspq.ptr.p_bool[i] ) + { + ae_assert(v0->p.ptr.p_double[i]>0.0&&v0->q.ptr.p_double[i]>0.0, "[VIPM]RunIntegrityChecks: integrity failure - P[i]<=0 or Q[i]<=0", _state); + } + else + { + ae_assert(v0->p.ptr.p_double[i]==0.0&&v0->q.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - P[i]<>0 or Q[i]<>0 for absent range of linear constraint", _state); + ae_assert(vd->p.ptr.p_double[i]==0.0&&vd->q.ptr.p_double[i]==0.0, "[VIPM]RunIntegrityChecks: integrity failure - P[i]<>0 or Q[i]<>0 for absent range of linear constraint", _state); + } + } +} + + +/************************************************************************* +Evaluate progress so far, outputs trace data, if requested to do so. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_traceprogress(vipmstate* state, + double mu, + double muaff, + double sigma, + double alphap, + double alphad, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + double v; + double errp2; + double errd2; + double errpinf; + double errdinf; + double errgap; + + + n = state->n; + m = state->mdense+state->msparse; + if( !state->dotrace ) + { + return; + } + + /* + * Print high-level information + */ + vipmsolver_computeerrors(state, &errp2, &errd2, &errpinf, &errdinf, &errgap, _state); + ae_trace("--- step report ------------------------------------------------------------------------------------\n"); + ae_trace("> step information\n"); + ae_trace("mu_init = %0.3e (at the beginning)\n", + (double)(mu)); + ae_trace("mu_aff = %0.3e (by affine scaling step)\n", + (double)(muaff)); + ae_trace("sigma = %0.3e (centering parameter)\n", + (double)(sigma)); + ae_trace("alphaP = %0.3e (primal step)\n", + (double)(alphap)); + ae_trace("alphaD = %0.3e (dual step)\n", + (double)(alphad)); + ae_trace("mu_cur = %0.3e (after the step)\n", + (double)(vipmsolver_varscomputemu(state, &state->current, _state))); + ae_trace("> errors\n"); + ae_trace("errP = %0.3e (primal infeasibility, inf-norm)\n", + (double)(errpinf)); + ae_trace("errD = %0.3e (dual infeasibility, inf-norm)\n", + (double)(errdinf)); + ae_trace("errGap = %0.3e (complementarity gap)\n", + (double)(errgap)); + ae_trace("> current point information (inf-norm)\n"); + ae_trace("|X|=%8.1e, |G|=%8.1e, |T|=%8.1e, |W|=%8.1e, |P|=%8.1e\n", + (double)(rmaxabsv(n, &state->current.x, _state)), + (double)(rmaxabsv(n, &state->current.g, _state)), + (double)(rmaxabsv(n, &state->current.t, _state)), + (double)(rmaxabsv(m, &state->current.w, _state)), + (double)(rmaxabsv(m, &state->current.p, _state))); + ae_trace("|Y|=%8.1e, |Z|=%8.1e, |S|=%8.1e, |V|=%8.1e, |Q|=%8.1e\n", + (double)(rmaxabsv(m, &state->current.y, _state)), + (double)(rmaxabsv(n, &state->current.z, _state)), + (double)(rmaxabsv(n, &state->current.s, _state)), + (double)(rmaxabsv(m, &state->current.v, _state)), + (double)(rmaxabsv(m, &state->current.q, _state))); + + /* + * Print variable stats, if required + */ + if( state->dotrace ) + { + ae_trace("--- variable statistics ----------------------------------------------------------------------------\n"); + ae_trace("> smallest values for nonnegative vars\n"); + ae_trace("primal: minG=%8.1e minT=%8.1e minW=%8.1e minP=%8.1e\n", + (double)(vipmsolver_minnz(&state->current.g, n, _state)), + (double)(vipmsolver_minnz(&state->current.t, n, _state)), + (double)(vipmsolver_minnz(&state->current.w, m, _state)), + (double)(vipmsolver_minnz(&state->current.p, m, _state))); + ae_trace("dual: minZ=%8.1e minS=%8.1e minV=%8.1e minQ=%8.1e\n", + (double)(vipmsolver_minnz(&state->current.z, n, _state)), + (double)(vipmsolver_minnz(&state->current.s, n, _state)), + (double)(vipmsolver_minnz(&state->current.v, m, _state)), + (double)(vipmsolver_minnz(&state->current.q, m, _state))); + ae_trace("> min and max complementary slackness\n"); + ae_trace("min: GZ=%8.1e TS=%8.1e WV=%8.1e PQ=%8.1e\n", + (double)(vipmsolver_minprodnz(&state->current.g, &state->current.z, n, _state)), + (double)(vipmsolver_minprodnz(&state->current.t, &state->current.s, n, _state)), + (double)(vipmsolver_minprodnz(&state->current.w, &state->current.v, m, _state)), + (double)(vipmsolver_minprodnz(&state->current.p, &state->current.q, m, _state))); + ae_trace("max: GZ=%8.1e TS=%8.1e WV=%8.1e PQ=%8.1e\n", + (double)(vipmsolver_maxprodnz(&state->current.g, &state->current.z, n, _state)), + (double)(vipmsolver_maxprodnz(&state->current.t, &state->current.s, n, _state)), + (double)(vipmsolver_maxprodnz(&state->current.w, &state->current.v, m, _state)), + (double)(vipmsolver_maxprodnz(&state->current.p, &state->current.q, m, _state))); + } + + /* + * Detailed output (all variables values, not suited for high-dimensional problems) + */ + if( state->dodetailedtrace ) + { + vipmsolver_vipmmultiply(state, &state->current.x, &state->current.y, &state->tmphx, &state->tmpax, &state->tmpaty, _state); + rsetallocv(n, 0.0, &state->tmplaggrad, _state); + for(i=0; i<=n-1; i++) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + v = state->tmphx.ptr.p_double[i]+state->c.ptr.p_double[i]-state->tmpaty.ptr.p_double[i]; + if( state->hasgz.ptr.p_bool[i] ) + { + v = v-state->current.z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + v = v+state->current.s.ptr.p_double[i]; + } + state->tmplaggrad.ptr.p_double[i] = v; + } + } + ae_trace("--- printing raw data (prior to applying variable scales and shifting by XOrigin) ------------------\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->current.x, n, &state->scl, ae_true, &state->xorigin, ae_true, _state); + ae_trace("\n"); + ae_trace("--- printing scaled data (after applying variable scales and shifting by XOrigin) ------------------\n"); + ae_trace("> reporting X, Lagrangian gradient\n"); + ae_trace("Xnew = "); + tracevectorautoprec(&state->current.x, 0, n, _state); + ae_trace("\n"); + ae_trace("Lag-grad = "); + tracevectorautoprec(&state->tmplaggrad, 0, n, _state); + ae_trace("\n"); + ae_trace("--- printing new point -----------------------------------------------------------------------------\n"); + ae_trace("> primal slacks and dual multipliers for box constraints\n"); + ae_trace("G (L prim slck) = "); + tracevectorautoprec(&state->current.g, 0, n, _state); + ae_trace("\n"); + ae_trace("Z (L dual mult) = "); + tracevectorautoprec(&state->current.z, 0, n, _state); + ae_trace("\n"); + ae_trace("T (U prim slck) = "); + tracevectorautoprec(&state->current.t, 0, n, _state); + ae_trace("\n"); + ae_trace("S (U dual mult) = "); + tracevectorautoprec(&state->current.s, 0, n, _state); + ae_trace("\n"); + ae_trace("> primal slacks and dual multipliers for linear constraints, B/R stand for B<=Ax<=B+R\n"); + ae_trace("Y (lag mult) = "); + tracevectorautoprec(&state->current.y, 0, m, _state); + ae_trace("\n"); + ae_trace("W (B prim slck) = "); + tracevectorautoprec(&state->current.w, 0, m, _state); + ae_trace("\n"); + ae_trace("V (B dual mult) = "); + tracevectorautoprec(&state->current.v, 0, m, _state); + ae_trace("\n"); + ae_trace("P (R prim slck) = "); + tracevectorautoprec(&state->current.p, 0, m, _state); + ae_trace("\n"); + ae_trace("Q (R dual mult) = "); + tracevectorautoprec(&state->current.q, 0, m, _state); + ae_trace("\n"); + } + ae_trace("\n"); +} + + +/************************************************************************* +Compute right-hand side for KKT system. + +INPUT PARAMETERS: + State - IPM state + V0 - current point (used to compute RHS) + MuEstimate - estimate of Mu (can be zero) + DirEstimate - estimate of delta's (can be zero) + +OUTPUT PARAMETERS: + Rhs - RHS + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_rhscompute(vipmstate* state, + const vipmvars* v0, + double muestimate, + const vipmvars* direstimate, + vipmrighthandside* rhs, + double reg, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = state->mdense+state->msparse; + + /* + * Allocate + */ + rvectorsetlengthatleast(&rhs->sigma, n, _state); + rvectorsetlengthatleast(&rhs->nu, n, _state); + rvectorsetlengthatleast(&rhs->tau, n, _state); + rvectorsetlengthatleast(&rhs->gammaz, n, _state); + rvectorsetlengthatleast(&rhs->gammas, n, _state); + rvectorsetlengthatleast(&rhs->gammaw, m, _state); + rvectorsetlengthatleast(&rhs->gammaq, m, _state); + rsetallocv(m, 0.0, &rhs->beta, _state); + rsetallocv(m, 0.0, &rhs->rho, _state); + rsetallocv(m, 0.0, &rhs->alpha, _state); + + /* + * Compute products H*x, A*x, A^T*y + * We compute these products in one location for the sake of simplicity. + */ + vipmsolver_vipmmultiply(state, &v0->x, &v0->y, &state->tmphx, &state->tmpax, &state->tmpaty, _state); + + /* + * Compute right-hand side: + * Rho = b - A*x + w + * Nu = l - x + g + * Tau = u - x - t + * Alpha = r - w - p + * Sigma = c - A^T*y - z + s + (H+REG)*x + * Beta = y + q - v + */ + for(i=0; i<=m-1; i++) + { + rhs->rho.ptr.p_double[i] = state->b.ptr.p_double[i]-state->tmpax.ptr.p_double[i]-reg*v0->y.ptr.p_double[i]; + if( state->haswv.ptr.p_bool[i] ) + { + + /* + * Inequality/range constraint + */ + rhs->rho.ptr.p_double[i] = rhs->rho.ptr.p_double[i]+v0->w.ptr.p_double[i]; + } + else + { + + /* + * Equality constraint without slack variables, W[i]=0 + */ + ae_assert(v0->w.ptr.p_double[i]==0.0, "RhsCompute: W[i]<>0 for linear equality constraint", _state); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + + /* + * Lower bound is present + */ + rhs->nu.ptr.p_double[i] = state->bndl.ptr.p_double[i]-v0->x.ptr.p_double[i]+v0->g.ptr.p_double[i]-reg*v0->z.ptr.p_double[i]; + } + else + { + + /* + * Lower bound is absent, g[i] = 0 + */ + ae_assert(v0->g.ptr.p_double[i]==0.0, "RhsCompute: G[i]<>0 for absent constraint", _state); + rhs->nu.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasts.ptr.p_bool[i] ) + { + + /* + * Upper bound is present + */ + rhs->tau.ptr.p_double[i] = state->bndu.ptr.p_double[i]-v0->x.ptr.p_double[i]-v0->t.ptr.p_double[i]+reg*v0->s.ptr.p_double[i]; + } + else + { + + /* + * Upper bound is absent, t[i] = 0 + */ + ae_assert(v0->t.ptr.p_double[i]==0.0, "RhsCompute: T[i]<>0 for absent constraint", _state); + rhs->tau.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haspq.ptr.p_bool[i] ) + { + rhs->alpha.ptr.p_double[i] = state->r.ptr.p_double[i]-v0->w.ptr.p_double[i]-v0->p.ptr.p_double[i]+reg*v0->q.ptr.p_double[i]; + } + } + for(i=0; i<=n-1; i++) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = state->c.ptr.p_double[i]-state->tmpaty.ptr.p_double[i]+state->tmphx.ptr.p_double[i]+reg*v0->x.ptr.p_double[i]; + if( state->hasgz.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]-v0->z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]+v0->s.ptr.p_double[i]; + } + } + else + { + rhs->sigma.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + rhs->beta.ptr.p_double[i] = rhs->beta.ptr.p_double[i]+v0->y.ptr.p_double[i]-v0->v.ptr.p_double[i]+reg*v0->w.ptr.p_double[i]; + } + if( state->haspq.ptr.p_bool[i] ) + { + rhs->beta.ptr.p_double[i] = rhs->beta.ptr.p_double[i]+v0->q.ptr.p_double[i]; + } + } + + /* + * Compute right-hand side: + * GammaZ = mu*inv(G)*e - z - inv(G)*DELTAG*deltaZ + * GammaW = mu*inv(V)*e - w - inv(V)*DELTAV*deltaW + * GammaS = mu*inv(T)*e - s - inv(T)*DELTAT*deltaS + * GammaQ = mu*inv(P)*e - q - inv(P)*DELTAP*deltaQ + */ + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + ae_assert(v0->g.ptr.p_double[i]>0.0, "RhsCompute: G[i]<=0", _state); + rhs->gammaz.ptr.p_double[i] = muestimate/v0->g.ptr.p_double[i]-v0->z.ptr.p_double[i]-direstimate->g.ptr.p_double[i]*direstimate->z.ptr.p_double[i]/v0->g.ptr.p_double[i]; + } + else + { + ae_assert(v0->g.ptr.p_double[i]==0.0, "RhsCompute: G[i]<>0 for absent constraint", _state); + ae_assert(v0->z.ptr.p_double[i]==0.0, "RhsCompute: Z[i]<>0 for absent constraint", _state); + rhs->gammaz.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + + /* + * Inequality/range constraint + */ + ae_assert(v0->v.ptr.p_double[i]>0.0, "RhsCompute: V[i]<=0", _state); + rhs->gammaw.ptr.p_double[i] = muestimate/v0->v.ptr.p_double[i]-v0->w.ptr.p_double[i]-direstimate->v.ptr.p_double[i]*direstimate->w.ptr.p_double[i]/v0->v.ptr.p_double[i]; + } + else + { + + /* + * Equality constraint + */ + ae_assert(v0->v.ptr.p_double[i]==0.0, "RhsCompute: V[i]<>0 for equality constraint", _state); + ae_assert(v0->w.ptr.p_double[i]==0.0, "RhsCompute: W[i]<>0 for equality constraint", _state); + rhs->gammaw.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasts.ptr.p_bool[i] ) + { + + /* + * Upper bound is present + */ + ae_assert(v0->t.ptr.p_double[i]>0.0, "RhsCompute: T[i]<=0", _state); + rhs->gammas.ptr.p_double[i] = muestimate/v0->t.ptr.p_double[i]-v0->s.ptr.p_double[i]-direstimate->t.ptr.p_double[i]*direstimate->s.ptr.p_double[i]/v0->t.ptr.p_double[i]; + } + else + { + + /* + * Upper bound is absent + */ + ae_assert(v0->t.ptr.p_double[i]==0.0, "RhsCompute: T[i]<>0 for absent constraint", _state); + ae_assert(v0->s.ptr.p_double[i]==0.0, "RhsCompute: S[i]<>0 for absent constraint", _state); + rhs->gammas.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haspq.ptr.p_bool[i] ) + { + ae_assert(v0->p.ptr.p_double[i]>0.0, "RhsCompute: P[i]<=0", _state); + rhs->gammaq.ptr.p_double[i] = muestimate/v0->p.ptr.p_double[i]-v0->q.ptr.p_double[i]-direstimate->p.ptr.p_double[i]*direstimate->q.ptr.p_double[i]/v0->p.ptr.p_double[i]; + } + else + { + ae_assert(v0->p.ptr.p_double[i]==0.0, "RhsCompute: P[i]<>0 for absent range", _state); + ae_assert(v0->q.ptr.p_double[i]==0.0, "RhsCompute: Q[i]<>0 for absent range", _state); + rhs->gammaq.ptr.p_double[i] = (double)(0); + } + } +} + + +/************************************************************************* +Subtracts KKT*cand from already computed RHS. + +A pair of RhsCompute/RhsSubtract calls results in residual being loaded +into the RHS structure. + +INPUT PARAMETERS: + State - IPM state + V0 - current point (used to compute RHS) + MuEstimate - estimate of Mu (can be zero) + DirEstimate - estimate of delta's (can be zero) + ResidualFrom - whether we want to compute RHS or residual computed + using VDCandidate + VDCandidate - solution candidate + +OUTPUT PARAMETERS: + Rhs - either RHS or residual RHS-KKT*Cand + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void vipmsolver_rhssubtract(vipmstate* state, + vipmrighthandside* rhs, + const vipmvars* v0, + const vipmvars* vdcandidate, + double reg, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = state->mdense+state->msparse; + vipmsolver_vipmmultiply(state, &vdcandidate->x, &vdcandidate->y, &state->tmphx, &state->tmpax, &state->tmpaty, _state); + + /* + * Residual for Rho, Nu, Tau, Alpha, Sigma, Beta + */ + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + rhs->rho.ptr.p_double[i] = rhs->rho.ptr.p_double[i]-(state->tmpax.ptr.p_double[i]-vdcandidate->w.ptr.p_double[i]+reg*vdcandidate->y.ptr.p_double[i]); + } + else + { + rhs->rho.ptr.p_double[i] = rhs->rho.ptr.p_double[i]-(state->tmpax.ptr.p_double[i]+reg*vdcandidate->y.ptr.p_double[i]); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + rhs->nu.ptr.p_double[i] = rhs->nu.ptr.p_double[i]-(vdcandidate->x.ptr.p_double[i]-vdcandidate->g.ptr.p_double[i]+reg*vdcandidate->z.ptr.p_double[i]); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasts.ptr.p_bool[i] ) + { + rhs->tau.ptr.p_double[i] = rhs->tau.ptr.p_double[i]-(vdcandidate->x.ptr.p_double[i]+vdcandidate->t.ptr.p_double[i]-reg*vdcandidate->s.ptr.p_double[i]); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haspq.ptr.p_bool[i] ) + { + rhs->alpha.ptr.p_double[i] = rhs->alpha.ptr.p_double[i]-(vdcandidate->w.ptr.p_double[i]+vdcandidate->p.ptr.p_double[i]-reg*vdcandidate->q.ptr.p_double[i]); + } + } + for(i=0; i<=n-1; i++) + { + if( !state->isfrozen.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]-(state->tmpaty.ptr.p_double[i]-state->tmphx.ptr.p_double[i]-reg*vdcandidate->x.ptr.p_double[i]); + if( state->hasgz.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]-vdcandidate->z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + rhs->sigma.ptr.p_double[i] = rhs->sigma.ptr.p_double[i]+vdcandidate->s.ptr.p_double[i]; + } + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + rhs->beta.ptr.p_double[i] = rhs->beta.ptr.p_double[i]-(-vdcandidate->y.ptr.p_double[i]+vdcandidate->v.ptr.p_double[i]-reg*vdcandidate->w.ptr.p_double[i]); + } + if( state->haspq.ptr.p_bool[i] ) + { + rhs->beta.ptr.p_double[i] = rhs->beta.ptr.p_double[i]+vdcandidate->q.ptr.p_double[i]; + } + } + + /* + * Residual for GammaZ, GammaW, GammaS, GammaQ + */ + for(i=0; i<=n-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + rhs->gammaz.ptr.p_double[i] = rhs->gammaz.ptr.p_double[i]-(v0->z.ptr.p_double[i]/v0->g.ptr.p_double[i]*vdcandidate->g.ptr.p_double[i]+vdcandidate->z.ptr.p_double[i]); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haswv.ptr.p_bool[i] ) + { + rhs->gammaw.ptr.p_double[i] = rhs->gammaw.ptr.p_double[i]-(v0->w.ptr.p_double[i]/v0->v.ptr.p_double[i]*vdcandidate->v.ptr.p_double[i]+vdcandidate->w.ptr.p_double[i]); + } + } + for(i=0; i<=n-1; i++) + { + if( state->hasts.ptr.p_bool[i] ) + { + rhs->gammas.ptr.p_double[i] = rhs->gammas.ptr.p_double[i]-(v0->s.ptr.p_double[i]/v0->t.ptr.p_double[i]*vdcandidate->t.ptr.p_double[i]+vdcandidate->s.ptr.p_double[i]); + } + } + for(i=0; i<=m-1; i++) + { + if( state->haspq.ptr.p_bool[i] ) + { + rhs->gammaq.ptr.p_double[i] = rhs->gammaq.ptr.p_double[i]-(v0->q.ptr.p_double[i]/v0->p.ptr.p_double[i]*vdcandidate->p.ptr.p_double[i]+vdcandidate->q.ptr.p_double[i]); + } + } +} + + +/************************************************************************* +Computes sum of squared primal terms of RHS + +INPUT PARAMETERS: + Rhs - RHS structure + N, M - problem metrics + +RESULT: + sum(sqr()) computed over primal terms (Rho, Nu, Tau, Alpha) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_rhsprimal2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = result+rdotv2(m, &rhs->rho, _state); + result = result+rdotv2(n, &rhs->nu, _state); + result = result+rdotv2(n, &rhs->tau, _state); + result = result+rdotv2(m, &rhs->alpha, _state); + return result; +} + + +/************************************************************************* +Computes sum of squared dual terms of RHS + +INPUT PARAMETERS: + Rhs - RHS structure + N, M - problem metrics + +RESULT: + sum(sqr()) computed over dual terms (Sigma, Beta) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_rhsdual2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = result+rdotv2(n, &rhs->sigma, _state); + result = result+rdotv2(m, &rhs->beta, _state); + return result; +} + + +/************************************************************************* +Computes inf-norm of primal terms of RHS + +INPUT PARAMETERS: + Rhs - RHS structure + N, M - problem metrics + +RESULT: + max(abs()) computed over primal terms (Rho, Nu, Tau, Alpha) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_rhsprimalinf(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = ae_maxreal(result, rmaxabsv(m, &rhs->rho, _state), _state); + result = ae_maxreal(result, rmaxabsv(n, &rhs->nu, _state), _state); + result = ae_maxreal(result, rmaxabsv(n, &rhs->tau, _state), _state); + result = ae_maxreal(result, rmaxabsv(m, &rhs->alpha, _state), _state); + return result; +} + + +/************************************************************************* +Computes inf-norm of dual terms of RHS + +INPUT PARAMETERS: + Rhs - RHS structure + N, M - problem metrics + +RESULT: + max(abs()) computed over dual terms (Sigma, Beta) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_rhsdualinf(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = ae_maxreal(result, rmaxabsv(n, &rhs->sigma, _state), _state); + result = ae_maxreal(result, rmaxabsv(m, &rhs->beta, _state), _state); + return result; +} + + +/************************************************************************* +Computes maximum over complementarity slackness terms of RHS + +INPUT PARAMETERS: + Rhs - RHS structure + N, M - problem metrics + +RESULT: + max(abs()) computed over complementarity terms (GammaZ, GammaS, GammaW, GammaQ) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_rhscompl2(const vipmrighthandside* rhs, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + double result; + + + result = (double)(0); + result = result+rdotv2(n, &rhs->gammaz, _state); + result = result+rdotv2(n, &rhs->gammas, _state); + result = result+rdotv2(m, &rhs->gammaw, _state); + result = result+rdotv2(m, &rhs->gammaq, _state); + return result; +} + + +/************************************************************************* +Computes minimum nonzero value of the vector. Returns 0 if all components +are nonpositive. + +INPUT PARAMETERS: + X - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_minnz(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_minreal(result, x->ptr.p_double[i], _state); + } + } + } + return result; +} + + +/************************************************************************* +Computes minimum product of nonzero components. +Returns 0 if all components are nonpositive. + +INPUT PARAMETERS: + X - vector + Y - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_minprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0))&&ae_fp_greater(y->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]*y->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_minreal(result, x->ptr.p_double[i]*y->ptr.p_double[i], _state); + } + } + } + return result; +} + + +/************************************************************************* +Computes maximum product of nonzero components. +Returns 0 if all components are nonpositive. + +INPUT PARAMETERS: + X - vector + Y - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double vipmsolver_maxprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0))&&ae_fp_greater(y->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]*y->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_maxreal(result, x->ptr.p_double[i]*y->ptr.p_double[i], _state); + } + } + } + return result; +} + + +void _vipmvars_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + vipmvars *p = (vipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->v, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->q, 0, DT_REAL, _state, make_automatic); +} + + +void _vipmvars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + vipmvars *dst = (vipmvars*)_dst; + const vipmvars *src = (const vipmvars*)_src; + dst->n = src->n; + dst->m = src->m; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic); + ae_vector_init_copy(&dst->t, &src->t, _state, make_automatic); + ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic); + ae_vector_init_copy(&dst->v, &src->v, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->q, &src->q, _state, make_automatic); +} + + +void _vipmvars_clear(void* _p) +{ + vipmvars *p = (vipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + ae_vector_clear(&p->w); + ae_vector_clear(&p->t); + ae_vector_clear(&p->p); + ae_vector_clear(&p->y); + ae_vector_clear(&p->z); + ae_vector_clear(&p->v); + ae_vector_clear(&p->s); + ae_vector_clear(&p->q); +} + + +void _vipmvars_destroy(void* _p) +{ + vipmvars *p = (vipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->w); + ae_vector_destroy(&p->t); + ae_vector_destroy(&p->p); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->z); + ae_vector_destroy(&p->v); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->q); +} + + +void _vipmreducedsparsesystem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + vipmreducedsparsesystem *p = (vipmreducedsparsesystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_init(&p->rawsystem, _state, make_automatic); + ae_vector_init(&p->effectivediag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isdiagonal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rowdegrees, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->coldegrees, 0, DT_INT, _state, make_automatic); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + ae_vector_init(&p->priorities, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->diagterm, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dampterm, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmprhs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcorr, 0, DT_REAL, _state, make_automatic); +} + + +void _vipmreducedsparsesystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + vipmreducedsparsesystem *dst = (vipmreducedsparsesystem*)_dst; + const vipmreducedsparsesystem *src = (const vipmreducedsparsesystem*)_src; + _sparsematrix_init_copy(&dst->rawsystem, &src->rawsystem, _state, make_automatic); + ae_vector_init_copy(&dst->effectivediag, &src->effectivediag, _state, make_automatic); + ae_vector_init_copy(&dst->isdiagonal, &src->isdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->rowdegrees, &src->rowdegrees, _state, make_automatic); + ae_vector_init_copy(&dst->coldegrees, &src->coldegrees, _state, make_automatic); + dst->ntotal = src->ntotal; + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + ae_vector_init_copy(&dst->priorities, &src->priorities, _state, make_automatic); + ae_vector_init_copy(&dst->diagterm, &src->diagterm, _state, make_automatic); + ae_vector_init_copy(&dst->dampterm, &src->dampterm, _state, make_automatic); + ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state, make_automatic); + ae_vector_init_copy(&dst->tmprhs, &src->tmprhs, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcorr, &src->tmpcorr, _state, make_automatic); +} + + +void _vipmreducedsparsesystem_clear(void* _p) +{ + vipmreducedsparsesystem *p = (vipmreducedsparsesystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_clear(&p->rawsystem); + ae_vector_clear(&p->effectivediag); + ae_vector_clear(&p->isdiagonal); + ae_vector_clear(&p->rowdegrees); + ae_vector_clear(&p->coldegrees); + _spcholanalysis_clear(&p->analysis); + ae_vector_clear(&p->priorities); + ae_vector_clear(&p->diagterm); + ae_vector_clear(&p->dampterm); + ae_vector_clear(&p->tmpb); + ae_vector_clear(&p->tmprhs); + ae_vector_clear(&p->tmpcorr); +} + + +void _vipmreducedsparsesystem_destroy(void* _p) +{ + vipmreducedsparsesystem *p = (vipmreducedsparsesystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_destroy(&p->rawsystem); + ae_vector_destroy(&p->effectivediag); + ae_vector_destroy(&p->isdiagonal); + ae_vector_destroy(&p->rowdegrees); + ae_vector_destroy(&p->coldegrees); + _spcholanalysis_destroy(&p->analysis); + ae_vector_destroy(&p->priorities); + ae_vector_destroy(&p->diagterm); + ae_vector_destroy(&p->dampterm); + ae_vector_destroy(&p->tmpb); + ae_vector_destroy(&p->tmprhs); + ae_vector_destroy(&p->tmpcorr); +} + + +void _vipmrighthandside_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + vipmrighthandside *p = (vipmrighthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->sigma, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->beta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rho, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alpha, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gammaz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gammas, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gammaw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gammaq, 0, DT_REAL, _state, make_automatic); +} + + +void _vipmrighthandside_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + vipmrighthandside *dst = (vipmrighthandside*)_dst; + const vipmrighthandside *src = (const vipmrighthandside*)_src; + ae_vector_init_copy(&dst->sigma, &src->sigma, _state, make_automatic); + ae_vector_init_copy(&dst->beta, &src->beta, _state, make_automatic); + ae_vector_init_copy(&dst->rho, &src->rho, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + ae_vector_init_copy(&dst->tau, &src->tau, _state, make_automatic); + ae_vector_init_copy(&dst->alpha, &src->alpha, _state, make_automatic); + ae_vector_init_copy(&dst->gammaz, &src->gammaz, _state, make_automatic); + ae_vector_init_copy(&dst->gammas, &src->gammas, _state, make_automatic); + ae_vector_init_copy(&dst->gammaw, &src->gammaw, _state, make_automatic); + ae_vector_init_copy(&dst->gammaq, &src->gammaq, _state, make_automatic); +} + + +void _vipmrighthandside_clear(void* _p) +{ + vipmrighthandside *p = (vipmrighthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->sigma); + ae_vector_clear(&p->beta); + ae_vector_clear(&p->rho); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->tau); + ae_vector_clear(&p->alpha); + ae_vector_clear(&p->gammaz); + ae_vector_clear(&p->gammas); + ae_vector_clear(&p->gammaw); + ae_vector_clear(&p->gammaq); +} + + +void _vipmrighthandside_destroy(void* _p) +{ + vipmrighthandside *p = (vipmrighthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->sigma); + ae_vector_destroy(&p->beta); + ae_vector_destroy(&p->rho); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->tau); + ae_vector_destroy(&p->alpha); + ae_vector_destroy(&p->gammaz); + ae_vector_destroy(&p->gammas); + ae_vector_destroy(&p->gammaw); + ae_vector_destroy(&p->gammaq); +} + + +void _vipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + vipmstate *p = (vipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->scl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invscl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xorigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparseh, _state, make_automatic); + ae_vector_init(&p->diagr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->denseafull, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->denseamain, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparseafull, _state, make_automatic); + _sparsematrix_init(&p->sparseamain, _state, make_automatic); + _sparsematrix_init(&p->combinedaslack, _state, make_automatic); + ae_vector_init(&p->ascales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->aflips, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasr, 0, DT_BOOL, _state, make_automatic); + _vipmvars_init(&p->current, _state, make_automatic); + _vipmvars_init(&p->best, _state, make_automatic); + _vipmvars_init(&p->trial, _state, make_automatic); + _vipmvars_init(&p->deltaaff, _state, make_automatic); + _vipmvars_init(&p->deltacorr, _state, make_automatic); + ae_vector_init(&p->isfrozen, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasgz, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasts, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->haswv, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->haspq, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->diagdz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdzi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdziri, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagds, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdsi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdsiri, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdw, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdwi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdwir, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdq, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdqi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagdqiri, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagddr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagde, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagder, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->factdensehaug, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->factregdhrh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->factinvregdzrz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->factregewave, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->facttmpdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->facttmpdamp, 0, DT_REAL, _state, make_automatic); + _vipmreducedsparsesystem_init(&p->reducedsparsesystem, _state, make_automatic); + _vipmrighthandside_init(&p->rhs, _state, make_automatic); + ae_vector_init(&p->rhsalphacap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rhsbetacap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rhsnucap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rhstaucap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltaxy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpaty, 0, DT_REAL, _state, make_automatic); + _vipmvars_init(&p->zerovars, _state, make_automatic); + ae_vector_init(&p->dummyr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpr2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmplaggrad, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->tmpsparse0, _state, make_automatic); +} + + +void _vipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + vipmstate *dst = (vipmstate*)_dst; + const vipmstate *src = (const vipmstate*)_src; + dst->slacksforequalityconstraints = src->slacksforequalityconstraints; + dst->normalize = src->normalize; + dst->n = src->n; + dst->nmain = src->nmain; + dst->epsp = src->epsp; + dst->epsd = src->epsd; + dst->epsgap = src->epsgap; + dst->islinear = src->islinear; + ae_vector_init_copy(&dst->scl, &src->scl, _state, make_automatic); + ae_vector_init_copy(&dst->invscl, &src->invscl, _state, make_automatic); + ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state, make_automatic); + dst->targetscale = src->targetscale; + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseh, &src->sparseh, _state, make_automatic); + ae_vector_init_copy(&dst->diagr, &src->diagr, _state, make_automatic); + dst->hkind = src->hkind; + dst->isdiagonalh = src->isdiagonalh; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndl, &src->rawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndu, &src->rawbndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_matrix_init_copy(&dst->denseafull, &src->denseafull, _state, make_automatic); + ae_matrix_init_copy(&dst->denseamain, &src->denseamain, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseafull, &src->sparseafull, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseamain, &src->sparseamain, _state, make_automatic); + _sparsematrix_init_copy(&dst->combinedaslack, &src->combinedaslack, _state, make_automatic); + ae_vector_init_copy(&dst->ascales, &src->ascales, _state, make_automatic); + ae_vector_init_copy(&dst->aflips, &src->aflips, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->hasr, &src->hasr, _state, make_automatic); + dst->mdense = src->mdense; + dst->msparse = src->msparse; + _vipmvars_init_copy(&dst->current, &src->current, _state, make_automatic); + _vipmvars_init_copy(&dst->best, &src->best, _state, make_automatic); + _vipmvars_init_copy(&dst->trial, &src->trial, _state, make_automatic); + _vipmvars_init_copy(&dst->deltaaff, &src->deltaaff, _state, make_automatic); + _vipmvars_init_copy(&dst->deltacorr, &src->deltacorr, _state, make_automatic); + ae_vector_init_copy(&dst->isfrozen, &src->isfrozen, _state, make_automatic); + ae_vector_init_copy(&dst->hasgz, &src->hasgz, _state, make_automatic); + ae_vector_init_copy(&dst->hasts, &src->hasts, _state, make_automatic); + ae_vector_init_copy(&dst->haswv, &src->haswv, _state, make_automatic); + ae_vector_init_copy(&dst->haspq, &src->haspq, _state, make_automatic); + dst->cntgz = src->cntgz; + dst->cntts = src->cntts; + dst->cntwv = src->cntwv; + dst->cntpq = src->cntpq; + dst->repiterationscount = src->repiterationscount; + dst->repncholesky = src->repncholesky; + dst->dotrace = src->dotrace; + dst->dodetailedtrace = src->dodetailedtrace; + dst->factorizationtype = src->factorizationtype; + dst->factorizationpoweredup = src->factorizationpoweredup; + dst->factorizationpresent = src->factorizationpresent; + ae_vector_init_copy(&dst->diagdz, &src->diagdz, _state, make_automatic); + ae_vector_init_copy(&dst->diagdzi, &src->diagdzi, _state, make_automatic); + ae_vector_init_copy(&dst->diagdziri, &src->diagdziri, _state, make_automatic); + ae_vector_init_copy(&dst->diagds, &src->diagds, _state, make_automatic); + ae_vector_init_copy(&dst->diagdsi, &src->diagdsi, _state, make_automatic); + ae_vector_init_copy(&dst->diagdsiri, &src->diagdsiri, _state, make_automatic); + ae_vector_init_copy(&dst->diagdw, &src->diagdw, _state, make_automatic); + ae_vector_init_copy(&dst->diagdwi, &src->diagdwi, _state, make_automatic); + ae_vector_init_copy(&dst->diagdwir, &src->diagdwir, _state, make_automatic); + ae_vector_init_copy(&dst->diagdq, &src->diagdq, _state, make_automatic); + ae_vector_init_copy(&dst->diagdqi, &src->diagdqi, _state, make_automatic); + ae_vector_init_copy(&dst->diagdqiri, &src->diagdqiri, _state, make_automatic); + ae_vector_init_copy(&dst->diagddr, &src->diagddr, _state, make_automatic); + ae_vector_init_copy(&dst->diagde, &src->diagde, _state, make_automatic); + ae_vector_init_copy(&dst->diagder, &src->diagder, _state, make_automatic); + ae_matrix_init_copy(&dst->factdensehaug, &src->factdensehaug, _state, make_automatic); + ae_vector_init_copy(&dst->factregdhrh, &src->factregdhrh, _state, make_automatic); + ae_vector_init_copy(&dst->factinvregdzrz, &src->factinvregdzrz, _state, make_automatic); + ae_vector_init_copy(&dst->factregewave, &src->factregewave, _state, make_automatic); + ae_vector_init_copy(&dst->facttmpdiag, &src->facttmpdiag, _state, make_automatic); + ae_vector_init_copy(&dst->facttmpdamp, &src->facttmpdamp, _state, make_automatic); + _vipmreducedsparsesystem_init_copy(&dst->reducedsparsesystem, &src->reducedsparsesystem, _state, make_automatic); + _vipmrighthandside_init_copy(&dst->rhs, &src->rhs, _state, make_automatic); + ae_vector_init_copy(&dst->rhsalphacap, &src->rhsalphacap, _state, make_automatic); + ae_vector_init_copy(&dst->rhsbetacap, &src->rhsbetacap, _state, make_automatic); + ae_vector_init_copy(&dst->rhsnucap, &src->rhsnucap, _state, make_automatic); + ae_vector_init_copy(&dst->rhstaucap, &src->rhstaucap, _state, make_automatic); + ae_vector_init_copy(&dst->deltaxy, &src->deltaxy, _state, make_automatic); + ae_vector_init_copy(&dst->tmphx, &src->tmphx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpax, &src->tmpax, _state, make_automatic); + ae_vector_init_copy(&dst->tmpaty, &src->tmpaty, _state, make_automatic); + _vipmvars_init_copy(&dst->zerovars, &src->zerovars, _state, make_automatic); + ae_vector_init_copy(&dst->dummyr, &src->dummyr, _state, make_automatic); + ae_vector_init_copy(&dst->tmpy, &src->tmpy, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpr2, &src->tmpr2, _state, make_automatic); + ae_vector_init_copy(&dst->tmplaggrad, &src->tmplaggrad, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpsparse0, &src->tmpsparse0, _state, make_automatic); +} + + +void _vipmstate_clear(void* _p) +{ + vipmstate *p = (vipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->scl); + ae_vector_clear(&p->invscl); + ae_vector_clear(&p->xorigin); + ae_vector_clear(&p->c); + ae_matrix_clear(&p->denseh); + _sparsematrix_clear(&p->sparseh); + ae_vector_clear(&p->diagr); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->rawbndl); + ae_vector_clear(&p->rawbndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_matrix_clear(&p->denseafull); + ae_matrix_clear(&p->denseamain); + _sparsematrix_clear(&p->sparseafull); + _sparsematrix_clear(&p->sparseamain); + _sparsematrix_clear(&p->combinedaslack); + ae_vector_clear(&p->ascales); + ae_vector_clear(&p->aflips); + ae_vector_clear(&p->b); + ae_vector_clear(&p->r); + ae_vector_clear(&p->hasr); + _vipmvars_clear(&p->current); + _vipmvars_clear(&p->best); + _vipmvars_clear(&p->trial); + _vipmvars_clear(&p->deltaaff); + _vipmvars_clear(&p->deltacorr); + ae_vector_clear(&p->isfrozen); + ae_vector_clear(&p->hasgz); + ae_vector_clear(&p->hasts); + ae_vector_clear(&p->haswv); + ae_vector_clear(&p->haspq); + ae_vector_clear(&p->diagdz); + ae_vector_clear(&p->diagdzi); + ae_vector_clear(&p->diagdziri); + ae_vector_clear(&p->diagds); + ae_vector_clear(&p->diagdsi); + ae_vector_clear(&p->diagdsiri); + ae_vector_clear(&p->diagdw); + ae_vector_clear(&p->diagdwi); + ae_vector_clear(&p->diagdwir); + ae_vector_clear(&p->diagdq); + ae_vector_clear(&p->diagdqi); + ae_vector_clear(&p->diagdqiri); + ae_vector_clear(&p->diagddr); + ae_vector_clear(&p->diagde); + ae_vector_clear(&p->diagder); + ae_matrix_clear(&p->factdensehaug); + ae_vector_clear(&p->factregdhrh); + ae_vector_clear(&p->factinvregdzrz); + ae_vector_clear(&p->factregewave); + ae_vector_clear(&p->facttmpdiag); + ae_vector_clear(&p->facttmpdamp); + _vipmreducedsparsesystem_clear(&p->reducedsparsesystem); + _vipmrighthandside_clear(&p->rhs); + ae_vector_clear(&p->rhsalphacap); + ae_vector_clear(&p->rhsbetacap); + ae_vector_clear(&p->rhsnucap); + ae_vector_clear(&p->rhstaucap); + ae_vector_clear(&p->deltaxy); + ae_vector_clear(&p->tmphx); + ae_vector_clear(&p->tmpax); + ae_vector_clear(&p->tmpaty); + _vipmvars_clear(&p->zerovars); + ae_vector_clear(&p->dummyr); + ae_vector_clear(&p->tmpy); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_matrix_clear(&p->tmpr2); + ae_vector_clear(&p->tmplaggrad); + ae_vector_clear(&p->tmpi); + _sparsematrix_clear(&p->tmpsparse0); +} + + +void _vipmstate_destroy(void* _p) +{ + vipmstate *p = (vipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->scl); + ae_vector_destroy(&p->invscl); + ae_vector_destroy(&p->xorigin); + ae_vector_destroy(&p->c); + ae_matrix_destroy(&p->denseh); + _sparsematrix_destroy(&p->sparseh); + ae_vector_destroy(&p->diagr); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->rawbndl); + ae_vector_destroy(&p->rawbndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_matrix_destroy(&p->denseafull); + ae_matrix_destroy(&p->denseamain); + _sparsematrix_destroy(&p->sparseafull); + _sparsematrix_destroy(&p->sparseamain); + _sparsematrix_destroy(&p->combinedaslack); + ae_vector_destroy(&p->ascales); + ae_vector_destroy(&p->aflips); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->r); + ae_vector_destroy(&p->hasr); + _vipmvars_destroy(&p->current); + _vipmvars_destroy(&p->best); + _vipmvars_destroy(&p->trial); + _vipmvars_destroy(&p->deltaaff); + _vipmvars_destroy(&p->deltacorr); + ae_vector_destroy(&p->isfrozen); + ae_vector_destroy(&p->hasgz); + ae_vector_destroy(&p->hasts); + ae_vector_destroy(&p->haswv); + ae_vector_destroy(&p->haspq); + ae_vector_destroy(&p->diagdz); + ae_vector_destroy(&p->diagdzi); + ae_vector_destroy(&p->diagdziri); + ae_vector_destroy(&p->diagds); + ae_vector_destroy(&p->diagdsi); + ae_vector_destroy(&p->diagdsiri); + ae_vector_destroy(&p->diagdw); + ae_vector_destroy(&p->diagdwi); + ae_vector_destroy(&p->diagdwir); + ae_vector_destroy(&p->diagdq); + ae_vector_destroy(&p->diagdqi); + ae_vector_destroy(&p->diagdqiri); + ae_vector_destroy(&p->diagddr); + ae_vector_destroy(&p->diagde); + ae_vector_destroy(&p->diagder); + ae_matrix_destroy(&p->factdensehaug); + ae_vector_destroy(&p->factregdhrh); + ae_vector_destroy(&p->factinvregdzrz); + ae_vector_destroy(&p->factregewave); + ae_vector_destroy(&p->facttmpdiag); + ae_vector_destroy(&p->facttmpdamp); + _vipmreducedsparsesystem_destroy(&p->reducedsparsesystem); + _vipmrighthandside_destroy(&p->rhs); + ae_vector_destroy(&p->rhsalphacap); + ae_vector_destroy(&p->rhsbetacap); + ae_vector_destroy(&p->rhsnucap); + ae_vector_destroy(&p->rhstaucap); + ae_vector_destroy(&p->deltaxy); + ae_vector_destroy(&p->tmphx); + ae_vector_destroy(&p->tmpax); + ae_vector_destroy(&p->tmpaty); + _vipmvars_destroy(&p->zerovars); + ae_vector_destroy(&p->dummyr); + ae_vector_destroy(&p->tmpy); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_matrix_destroy(&p->tmpr2); + ae_vector_destroy(&p->tmplaggrad); + ae_vector_destroy(&p->tmpi); + _sparsematrix_destroy(&p->tmpsparse0); +} + + +#endif +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + The terms A and b (as well as constraints) will be + specified later with separate calls. + N - total number of variables, N>=1 + TargetScale - target scale: + * >=0 + * recommended to be max(nrm2(C),nrm2(H+corr)) + * if zero, autodetected by performing several iterations + of a subspace eigensolver + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2init(ipm2state* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nuser, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ const ae_matrix* ccorr, + /* Real */ const ae_vector* dcorr, + ae_int_t kcorr, + /* Real */ const ae_vector* c, + double targetscale, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ const ae_matrix* densea, + ae_int_t mdense, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_bool uniformlcscale, + ae_bool skipnormalization, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t naug; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t nnz; + ae_int_t offs; + + + ae_assert(nuser>=1, "IPM2Init: N<1", _state); + ae_assert(isfinitevector(s, nuser, _state), "IPM2Init: S contains infinite or NaN elements", _state); + ae_assert(isfinitevector(xorigin, nuser, _state), "IPM2Init: XOrigin contains infinite or NaN elements", _state); + ae_assert(hkind==0||hkind==1, "IPM2Init: incorrect HKind", _state); + ae_assert(isfinitevector(c, nuser, _state), "IPM2Init: C contains infinite or NaN elements", _state); + ae_assert(mdense>=0, "IPM2Init: MDense<0", _state); + ae_assert(msparse>=0, "IPM2Init: MSparse<0", _state); + ae_assert(apservisfinitematrix(densea, mdense, nuser, _state), "IPM2Init: DenseA contains infinite or NaN values!", _state); + ae_assert(msparse==0||sparsea->matrixtype==1, "IPM2Init: non-CRS constraint matrix!", _state); + ae_assert(msparse==0||(sparsea->m==msparse&&sparsea->n==nuser), "IPM2Init: constraint matrix has incorrect size", _state); + ae_assert(cl->cnt>=mdense+msparse, "IPM2Init: CL is too short!", _state); + ae_assert(cu->cnt>=mdense+msparse, "IPM2Init: CU is too short!", _state); + ae_assert(kcorr>=0, "IPM2Init: KCorr<0", _state); + ae_assert(kcorr==0||ccorr->rows>=kcorr, "IPM2Init: CCorr size is not KCorr*N, rows count is too small", _state); + ae_assert(kcorr==0||ccorr->cols>=nuser, "IPM2Init: CCorr size is not KCorr*N, cols count is too small", _state); + ae_assert(kcorr==0||dcorr->cnt>=kcorr, "IPM2Init: DCorr size is not [KCorr]", _state); + for(i=0; i<=kcorr-1; i++) + { + ae_assert(ae_fp_eq(ae_fabs(dcorr->ptr.p_double[i], _state),(double)(1)), "IPM2Init: |DCorr[I]|<>1", _state); + } + ae_assert(ae_isfinite(targetscale, _state)&&ae_fp_greater_eq(targetscale,(double)(0)), "IPM2Init: TargetScale<0 or is not finite number", _state); + + /* + * Problem metrics, settings and type + */ + ntotal = nuser+kcorr+msparse+mdense; + naug = nuser+kcorr; + state->nuser = nuser; + state->naug = naug; + state->ntotal = ntotal; + state->islinear = ae_false; + state->hasuserpermutation = ae_false; + ipm2setcond(state, 0.0, 0.0, 0.0, _state); + state->maxipmits = ipm2solver_defipmits; + + /* + * Reports + */ + state->repiterationscount = 0; + state->repncholesky = 0; + + /* + * Trace + */ + state->dotrace = ae_false; + state->dotimers = ae_false; + state->dodetailedtrace = ae_false; + + /* + * Scale and origin + */ + rsetallocv(ntotal, 1.0, &state->sclx, _state); + rsetallocv(ntotal, 1.0, &state->invsclx, _state); + rsetallocv(ntotal, 0.0, &state->xoriginx, _state); + for(i=0; i<=nuser-1; i++) + { + ae_assert(s->ptr.p_double[i]>0.0, "IPM2Init: S[i] is non-positive", _state); + state->sclx.ptr.p_double[i] = s->ptr.p_double[i]; + state->invsclx.ptr.p_double[i] = (double)1/s->ptr.p_double[i]; + state->xoriginx.ptr.p_double[i] = xorigin->ptr.p_double[i]; + } + + /* + * Extended linear term + */ + rsetallocv(ntotal, 0.0, &state->ce, _state); + rcopyv(nuser, c, &state->ce, _state); + + /* + * Generate sparse lower triangular representation of the quadratic term H and dense + * corrector CCorr/DCorr. Apply scaling and normalization. + */ + state->tmplowerh.matrixtype = 1; + state->tmplowerh.m = nuser; + state->tmplowerh.n = nuser; + iallocv(nuser+1, &state->tmplowerh.ridx, _state); + if( hkind==0 ) + { + + /* + * Sparsify dense term, generate leading N*N part of HX + */ + nnz = 0; + for(i=0; i<=nuser-1; i++) + { + nnz = nnz+1; + if( isupper ) + { + j0 = i+1; + j1 = nuser-1; + } + else + { + j0 = 0; + j1 = i-1; + } + for(j=j0; j<=j1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + nnz = nnz+1; + } + } + } + iallocv(nnz+nuser, &state->tmplowerh.idx, _state); + rallocv(nnz+nuser, &state->tmplowerh.vals, _state); + state->tmplowerh.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=state->nuser-1; i++) + { + + /* + * Off-diagonal elements are copied only when nonzero + */ + if( !isupper ) + { + for(j=0; j<=i-1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + v = denseh->ptr.pp_double[i][j]; + state->tmplowerh.idx.ptr.p_int[offs] = j; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + } + + /* + * Diagonal element is always copied + */ + v = denseh->ptr.pp_double[i][i]; + state->tmplowerh.idx.ptr.p_int[offs] = i; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + + /* + * Off-diagonal elements are copied only when nonzero + */ + if( isupper ) + { + for(j=i+1; j<=nuser-1; j++) + { + if( denseh->ptr.pp_double[i][j]!=(double)0 ) + { + v = denseh->ptr.pp_double[i][j]; + state->tmplowerh.idx.ptr.p_int[offs] = j; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + } + + /* + * Finalize row + */ + state->tmplowerh.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "VIPMSetQuadraticLinear: DenseH contains infinite or NaN values!", _state); + ae_assert(offs==nnz, "VIPMSetQuadraticLinear: integrity check failed", _state); + ae_assert(offs<=state->tmplowerh.vals.cnt&&offs<=state->tmplowerh.idx.cnt, "IPM2Init: integrity check failed", _state); + sparsecreatecrsinplace(&state->tmplowerh, _state); + } + if( hkind==1 ) + { + + /* + * Copy sparse quadratic term, but make sure that we have diagonal elements + * present (we add diagonal if it is not present) + */ + ae_assert(sparseh->matrixtype==1, "VIPMSetQuadraticLinear: unexpected sparse matrix format", _state); + ae_assert(sparseh->m==nuser, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + ae_assert(sparseh->n==nuser, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + iallocv(sparseh->ridx.ptr.p_int[nuser]+nuser, &state->tmplowerh.idx, _state); + rallocv(sparseh->ridx.ptr.p_int[nuser]+nuser, &state->tmplowerh.vals, _state); + state->tmplowerh.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=state->nuser-1; i++) + { + + /* + * Copy subdiagonal elements (if needed) + */ + if( !isupper ) + { + j0 = sparseh->ridx.ptr.p_int[i]; + j1 = sparseh->didx.ptr.p_int[i]-1; + for(k=j0; k<=j1; k++) + { + v = sparseh->vals.ptr.p_double[k]; + state->tmplowerh.idx.ptr.p_int[offs] = sparseh->idx.ptr.p_int[k]; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + + /* + * Diagonal element is always copied + */ + v = (double)(0); + if( sparseh->uidx.ptr.p_int[i]!=sparseh->didx.ptr.p_int[i] ) + { + v = sparseh->vals.ptr.p_double[sparseh->didx.ptr.p_int[i]]; + } + state->tmplowerh.idx.ptr.p_int[offs] = i; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + + /* + * Copy superdiagonal elements (if needed) + */ + if( isupper ) + { + j0 = sparseh->uidx.ptr.p_int[i]; + j1 = sparseh->ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + v = sparseh->vals.ptr.p_double[k]; + state->tmplowerh.idx.ptr.p_int[offs] = sparseh->idx.ptr.p_int[k]; + state->tmplowerh.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + } + + /* + * Finalize row + */ + state->tmplowerh.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "IPM2Init: SparseH contains infinite or NaN values!", _state); + ae_assert(offs<=state->tmplowerh.vals.cnt&&offs<=state->tmplowerh.idx.cnt, "IPM2Init: integrity check failed", _state); + sparsecreatecrsinplace(&state->tmplowerh, _state); + } + if( isupper ) + { + sparsecopytransposecrsbuf(&state->tmplowerh, &state->tmpsparse0, _state); + sparsecopybuf(&state->tmpsparse0, &state->tmplowerh, _state); + } + if( kcorr>0 ) + { + for(i=0; i<=kcorr-1; i++) + { + ae_assert(ae_fp_eq(ae_fabs(dcorr->ptr.p_double[i], _state),1.0), "IPM2: DCorr[i] is neither 1 nor -1", _state); + } + rcopyallocm(kcorr, state->nuser, ccorr, &state->tmpccorr, _state); + rcopyallocv(kcorr, dcorr, &state->tmpdcorr, _state); + } + scalesparseqpinplace(&state->sclx, state->nuser, &state->tmplowerh, &state->tmpccorr, &state->tmpdcorr, kcorr, &state->ce, _state); + if( !skipnormalization ) + { + if( ae_fp_eq(targetscale,(double)(0)) ) + { + state->targetscale = normalizesparseqpinplace(&state->tmplowerh, ae_false, &state->tmpccorr, &state->tmpdcorr, kcorr, &state->ce, state->nuser, _state); + state->targetscale = coalesce(state->targetscale, 1.0, _state); + } + else + { + v = (double)1/targetscale; + rmulv(state->tmplowerh.ridx.ptr.p_int[state->nuser], v, &state->tmplowerh.vals, _state); + rmulv(ntotal, v, &state->ce, _state); + for(k=0; k<=kcorr-1; k++) + { + rmulr(state->nuser, ae_sqrt(v, _state), &state->tmpccorr, k, _state); + } + state->targetscale = targetscale; + } + } + else + { + state->targetscale = 1.0; + } + + /* + * Extended quadratic term: copy, extend + * + * NOTE: we perform integrity check for inifinities/NANs by + * computing sum of all matrix elements and checking its + * value for being finite. It is a bit faster than checking + * each element individually. + */ + state->sparsehe.matrixtype = 1; + state->sparsehe.m = ntotal; + state->sparsehe.n = ntotal; + iallocv(ntotal+1, &state->sparsehe.ridx, _state); + ae_assert(state->tmplowerh.matrixtype==1, "VIPMSetQuadraticLinear: unexpected sparse matrix format", _state); + ae_assert(state->tmplowerh.m==nuser, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + ae_assert(state->tmplowerh.n==nuser, "VIPMSetQuadraticLinear: unexpected sparse matrix size", _state); + iallocv(state->tmplowerh.ridx.ptr.p_int[nuser]+kcorr*(nuser+1)+(state->ntotal-nuser), &state->sparsehe.idx, _state); + rallocv(state->tmplowerh.ridx.ptr.p_int[nuser]+kcorr*(nuser+1)+(state->ntotal-nuser), &state->sparsehe.vals, _state); + state->sparsehe.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=state->nuser-1; i++) + { + + /* + * Copy subdiagonal elements (if needed) + */ + j0 = state->tmplowerh.ridx.ptr.p_int[i]; + j1 = state->tmplowerh.didx.ptr.p_int[i]-1; + for(k=j0; k<=j1; k++) + { + v = state->tmplowerh.vals.ptr.p_double[k]; + state->sparsehe.idx.ptr.p_int[offs] = state->tmplowerh.idx.ptr.p_int[k]; + state->sparsehe.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + + /* + * The diagonal element is always copied + */ + v = (double)(0); + if( state->tmplowerh.uidx.ptr.p_int[i]!=state->tmplowerh.didx.ptr.p_int[i] ) + { + v = state->tmplowerh.vals.ptr.p_double[state->tmplowerh.didx.ptr.p_int[i]]; + } + state->sparsehe.idx.ptr.p_int[offs] = i; + state->sparsehe.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + + /* + * Finalize row + */ + state->sparsehe.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "IPM2Init: SparseH contains infinite or NaN values!", _state); + for(i=state->nuser; i<=state->naug-1; i++) + { + + /* + * Augmentation row + */ + offs = state->sparsehe.ridx.ptr.p_int[i]; + for(j=0; j<=nuser-1; j++) + { + if( state->tmpccorr.ptr.pp_double[i-state->nuser][j]!=0.0 ) + { + state->sparsehe.idx.ptr.p_int[offs] = j; + state->sparsehe.vals.ptr.p_double[offs] = state->tmpccorr.ptr.pp_double[i-state->nuser][j]; + offs = offs+1; + } + } + + /* + * Diagonal element + */ + state->sparsehe.idx.ptr.p_int[offs] = i; + state->sparsehe.vals.ptr.p_double[offs] = -state->tmpdcorr.ptr.p_double[i-state->nuser]; + offs = offs+1; + + /* + * Finalize row + */ + state->sparsehe.ridx.ptr.p_int[i+1] = offs; + } + for(i=state->naug; i<=state->ntotal-1; i++) + { + + /* + * Extend with zeros + */ + state->sparsehe.idx.ptr.p_int[offs] = i; + state->sparsehe.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + state->sparsehe.ridx.ptr.p_int[i+1] = offs; + } + ae_assert(offs<=state->sparsehe.vals.cnt&&offs<=state->sparsehe.idx.cnt, "IPM2Init: integrity check failed", _state); + sparsecreatecrsinplace(&state->sparsehe, _state); + state->isdiagonalh = state->sparsehe.ridx.ptr.p_int[state->ntotal]==state->ntotal; + + /* + * Primary part of the box constraints + */ + rcopyallocv(state->nuser, bndl, &state->rawbndl, _state); + rcopyallocv(state->nuser, bndu, &state->rawbndu, _state); + rsetallocv(state->ntotal, _state->v_neginf, &state->bndle, _state); + rsetallocv(state->ntotal, _state->v_posinf, &state->bndue, _state); + bsetallocv(state->ntotal, ae_false, &state->hasbndle, _state); + bsetallocv(state->ntotal, ae_false, &state->hasbndue, _state); + for(i=0; i<=state->nuser-1; i++) + { + state->hasbndle.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndue.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + ae_assert(!((state->hasbndle.ptr.p_bool[i]&&state->hasbndue.ptr.p_bool[i])&&ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i])), "IPM2Init: inconsistent range for box constraints", _state); + state->bndle.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->bndue.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + scaleshiftbcinplace(&state->sclx, &state->xoriginx, &state->bndle, &state->bndue, state->ntotal, _state); + + /* + * Linear constraints (sparsified): + * * copy to TmpA, normalize here + * * extend with slack variables, save to RawAE + * * append constraint bounds to the extended box constraints + */ + m = mdense+msparse; + state->mraw = m; + for(i=0; i<=m-1; i++) + { + ae_assert(ae_isfinite(cl->ptr.p_double[i], _state)||ae_isneginf(cl->ptr.p_double[i], _state), "IPM2: CL is not finite number or -INF", _state); + ae_assert(ae_isfinite(cu->ptr.p_double[i], _state)||ae_isposinf(cu->ptr.p_double[i], _state), "IPM2: CU is not finite number or +INF", _state); + } + state->mraw = m; + state->tmpa.m = m; + state->tmpa.n = state->ntotal; + iallocv(m+1, &state->tmpa.ridx, _state); + state->tmpa.ridx.ptr.p_int[0] = 0; + for(i=0; i<=msparse-1; i++) + { + offs = state->tmpa.ridx.ptr.p_int[i]; + igrowv(offs+state->ntotal, &state->tmpa.idx, _state); + rgrowv(offs+state->ntotal, &state->tmpa.vals, _state); + j0 = sparsea->ridx.ptr.p_int[i]; + j1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->tmpa.idx.ptr.p_int[offs] = sparsea->idx.ptr.p_int[j]; + state->tmpa.vals.ptr.p_double[offs] = sparsea->vals.ptr.p_double[j]; + offs = offs+1; + } + state->tmpa.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=mdense-1; i++) + { + offs = state->tmpa.ridx.ptr.p_int[msparse+i]; + igrowv(offs+state->ntotal, &state->tmpa.idx, _state); + rgrowv(offs+state->ntotal, &state->tmpa.vals, _state); + for(k=0; k<=state->nuser-1; k++) + { + if( densea->ptr.pp_double[i][k]!=(double)0 ) + { + state->tmpa.idx.ptr.p_int[offs] = k; + state->tmpa.vals.ptr.p_double[offs] = densea->ptr.pp_double[i][k]; + offs = offs+1; + } + } + state->tmpa.ridx.ptr.p_int[msparse+i+1] = offs; + } + sparsecreatecrsinplace(&state->tmpa, _state); + rcopyallocv(m, cl, &state->tmpal, _state); + rcopyallocv(m, cu, &state->tmpau, _state); + scaleshiftsparselcinplace(&state->sclx, &state->xoriginx, state->ntotal, &state->tmpa, m, &state->tmpal, &state->tmpau, _state); + if( !skipnormalization ) + { + if( uniformlcscale ) + { + normalizesparselcinplaceuniform(&state->tmpa, m, &state->tmpal, &state->tmpau, state->ntotal, &state->ascales, ae_true, _state); + } + else + { + normalizesparselcinplace(&state->tmpa, m, &state->tmpal, &state->tmpau, state->ntotal, ae_true, &state->ascales, ae_true, _state); + } + } + else + { + rsetallocv(m, 1.0, &state->ascales, _state); + } + for(i=0; i<=m-1; i++) + { + if( state->ascales.ptr.p_double[i]==0.0 ) + { + state->ascales.ptr.p_double[i] = 1.0; + } + } + state->rawae.m = m; + state->rawae.n = state->ntotal; + iallocv(m+1, &state->rawae.ridx, _state); + state->rawae.ridx.ptr.p_int[0] = 0; + for(i=0; i<=m-1; i++) + { + + /* + * Copy I-th row of TmpA to RawAE, extend with slacks + */ + offs = state->rawae.ridx.ptr.p_int[i]; + igrowv(offs+state->ntotal, &state->rawae.idx, _state); + rgrowv(offs+state->ntotal, &state->rawae.vals, _state); + j0 = state->tmpa.ridx.ptr.p_int[i]; + j1 = state->tmpa.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->rawae.idx.ptr.p_int[offs] = state->tmpa.idx.ptr.p_int[j]; + state->rawae.vals.ptr.p_double[offs] = state->tmpa.vals.ptr.p_double[j]; + offs = offs+1; + } + state->rawae.idx.ptr.p_int[offs] = state->naug+i; + state->rawae.vals.ptr.p_double[offs] = -1.0; + offs = offs+1; + state->rawae.ridx.ptr.p_int[i+1] = offs; + + /* + * Extend box constraints + */ + state->bndle.ptr.p_double[state->naug+i] = state->tmpal.ptr.p_double[i]; + state->bndue.ptr.p_double[state->naug+i] = state->tmpau.ptr.p_double[i]; + state->hasbndle.ptr.p_bool[state->naug+i] = ae_isfinite(state->tmpal.ptr.p_double[i], _state); + state->hasbndue.ptr.p_bool[state->naug+i] = ae_isfinite(state->tmpau.ptr.p_double[i], _state); + } + sparsecreatecrsinplace(&state->rawae, _state); + + /* + * Global regularized, default state (zero) + */ + state->greg = 0.0; + + /* + * Finite version of box constraints - infinities replaced by very big numbers. + * Allows us to avoid conditional checks during KKT system generation. + */ + rallocv(state->ntotal, &state->bndlef, _state); + rallocv(state->ntotal, &state->bnduef, _state); + for(i=0; i<=state->ntotal-1; i++) + { + state->bndlef.ptr.p_double[i] = rcase2(ae_isfinite(state->bndle.ptr.p_double[i], _state), state->bndle.ptr.p_double[i], -0.001*ae_maxrealnumber, _state); + state->bnduef.ptr.p_double[i] = rcase2(ae_isfinite(state->bndue.ptr.p_double[i], _state), state->bndue.ptr.p_double[i], 0.001*ae_maxrealnumber, _state); + } +} + + +/************************************************************************* +Sets global regularization for X and Y and origin + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + RegXY - >=0, global regularization + OriginX - array[NUser] + OriginY - array[MSparse+MDense] + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2setreg(ipm2state* state, + double regxy, + /* Real */ const ae_vector* originx, + /* Real */ const ae_vector* originy, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(regxy, _state)&&ae_fp_greater_eq(regxy,(double)(0)), "IPM2SetReg: RegXY is infinite or negative", _state); + ae_assert(originx->cnt>=state->nuser, "IPM2SetReg: OriginX is too short", _state); + ae_assert(originy->cnt>=state->mraw, "IPM2SetReg: OriginY is too short", _state); + ae_assert(isfinitevector(originx, state->nuser, _state), "IPM2SetReg: OriginX contains infinite values", _state); + ae_assert(isfinitevector(originy, state->mraw, _state), "IPM2SetReg: OriginY contains infinite values", _state); + state->greg = regxy; + rcopyallocv(state->nuser, originx, &state->gregoriginxuser, _state); + rcopyallocv(state->mraw, originy, &state->gregoriginyuser, _state); +} + + +/************************************************************************* +Sets stopping criteria for QP-IPM solver. + +You can set all epsilon-values to one small value, about 1.0E-6. + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + EpsP - maximum primal error allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + EpsD - maximum dual error allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + EpsGap - maximum duality gap allowed in the solution, + EpsP>=0. Zero will be automatically replaced + by recommended default value, which is equal + to 10*Sqrt(Epsilon) in the current version + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2setcond(ipm2state* state, + double epsp, + double epsd, + double epsgap, + ae_state *_state) +{ + double sml; + + + ae_assert(ae_isfinite(epsp, _state)&&ae_fp_greater_eq(epsp,(double)(0)), "IPM2SetCond: EpsP is infinite or negative", _state); + ae_assert(ae_isfinite(epsd, _state)&&ae_fp_greater_eq(epsd,(double)(0)), "IPM2SetCond: EpsD is infinite or negative", _state); + ae_assert(ae_isfinite(epsgap, _state)&&ae_fp_greater_eq(epsgap,(double)(0)), "IPM2SetCond: EpsP is infinite or negative", _state); + sml = ae_sqrt(ae_machineepsilon, _state); + state->epsp = coalesce(epsp, sml, _state); + state->epsd = coalesce(epsd, sml, _state); + state->epsgap = coalesce(epsgap, sml, _state); +} + + +/************************************************************************* +Sets maximum iterations count for IPM. + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + MaxIts - maximum iterations count; + recommended in 100..200. + Zero means default value (200). + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2setmaxits(ipm2state* state, ae_int_t maxits, ae_state *_state) +{ + + + ae_assert(maxits>=0, "IPM2SetMaxIts: MaxIts<0", _state); + state->maxipmits = maxits; +} + + +/************************************************************************* +This function proposes user ordering for a KKT system, as accepted by +IPM2SetOrdering(). + +This function accepts linear constraints matrix and it assumes that the +quadratic term is diagonal (a placeholder parameter is used to ensure that +the caller is aware of the fact). Only sparsity patter is used, not specific +coefficient values. + +It returns proposed ordering. An instance of IPM2State structure is passed +to be used as a temporary buffer; its initial state is invalidated. However, +large internal temporaries are left intact and memory allocated by them can +be reused later. + +INPUT PARAMETERS: + State - uninitialized or initialized instance + N - variables count + IsDiagonalQ - must be true to confirm that the caller is aware + of absence of support for non-diagonal quadratic + terms + HasBndL - array[N], I-th element is true if bound is finite + HasBndU - array[N], I-th element is true if bound is finite + C - if M>0, sparse constraints in CRS format + CL, CU - array[M], lower and upper bounds for linear + constrains + M - >=0, linear constraints count + P - potentially preallocated buffer, array[N+M], + resized if needed + +OUTPUT PARAMETERS: + P - array[N+M] that maps original indexes of a + KKT matrix (between 0 and N-1 for variables, + between N and N+M-1 for constraints) to + permuted indexes + +NOTE: the function assumes that all variables are boxed + +NOTE: the optimizer also allows to work with QP problems with low rank + correction applied to the quadratic term. + + This function and IPM2SetOrdering() assume that independently of + modification actual sparsity pattern its rows are assumed to be dense + and are moved to the end. So, these rows are not included into the + analysis. It allows us to reuse the same ordering for multiple problems + with varying correction sizes but the same sparsity pattern for the + rest of problem. + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2proposeordering(ipm2state* state, + ae_int_t n, + ae_bool isdiagonalq, + /* Boolean */ const ae_vector* hasbndl, + /* Boolean */ const ae_vector* hasbndu, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + /* Integer */ ae_vector* p, + ae_state *_state) +{ + ae_int_t offs; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t colthreshold; + ae_int_t rowthreshold; + ae_int_t sumcoldeg; + ae_int_t sumrowdeg; + ae_int_t groupcols; + ae_int_t grouprows; + ae_int_t groupequality; + ae_int_t groupfree; + ae_int_t densegroup; + + + ae_assert(isdiagonalq, "IPM2ProposeOrdering: does not support non-diagonal Q", _state); + + /* + * Allocate sparse matrix + */ + sumcoldeg = 0; + sumrowdeg = 0; + isetallocv(n, 0, &state->reducedsystem.coldegrees, _state); + isetallocv(m, 0, &state->reducedsystem.rowdegrees, _state); + state->reducedsystem.compactkkt.matrixtype = 1; + state->reducedsystem.compactkkt.m = n+m; + state->reducedsystem.compactkkt.n = n+m; + iallocv(state->reducedsystem.compactkkt.m+1, &state->reducedsystem.compactkkt.ridx, _state); + state->reducedsystem.compactkkt.ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + offs = state->reducedsystem.compactkkt.ridx.ptr.p_int[i]; + igrowv(offs+1, &state->reducedsystem.compactkkt.idx, _state); + rgrowv(offs+1, &state->reducedsystem.compactkkt.vals, _state); + state->reducedsystem.compactkkt.idx.ptr.p_int[offs] = i; + state->reducedsystem.compactkkt.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->reducedsystem.compactkkt.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=m-1; i++) + { + offs = state->reducedsystem.compactkkt.ridx.ptr.p_int[n+i]; + igrowv(offs+n+1, &state->reducedsystem.compactkkt.idx, _state); + rgrowv(offs+n+1, &state->reducedsystem.compactkkt.vals, _state); + j0 = c->ridx.ptr.p_int[i]; + j1 = c->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + k = c->idx.ptr.p_int[j]; + state->reducedsystem.compactkkt.idx.ptr.p_int[offs] = k; + state->reducedsystem.compactkkt.vals.ptr.p_double[offs] = 1.0; + state->reducedsystem.rowdegrees.ptr.p_int[i] = state->reducedsystem.rowdegrees.ptr.p_int[i]+1; + state->reducedsystem.coldegrees.ptr.p_int[k] = state->reducedsystem.coldegrees.ptr.p_int[k]+1; + sumrowdeg = sumrowdeg+1; + sumcoldeg = sumcoldeg+1; + offs = offs+1; + } + state->reducedsystem.compactkkt.idx.ptr.p_int[offs] = n+i; + state->reducedsystem.compactkkt.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->reducedsystem.compactkkt.ridx.ptr.p_int[n+i+1] = offs; + } + sparsecreatecrsinplace(&state->reducedsystem.compactkkt, _state); + + /* + * Determine elimination priorities + */ + colthreshold = ae_round(ipm2solver_muquasidense*(double)sumcoldeg/(double)n, _state)+1; + rowthreshold = ae_round(ipm2solver_muquasidense*(double)sumrowdeg/coalesce((double)(m), (double)(1), _state), _state)+1; + if( ae_fp_less_eq((double)sumcoldeg/(double)n,(double)sumrowdeg/coalesce((double)(m), (double)(1), _state)) ) + { + groupcols = 0; + grouprows = 1; + } + else + { + groupcols = 1; + grouprows = 0; + } + groupequality = 2; + groupfree = 3; + densegroup = ae_maxint(groupfree, groupequality, _state); + isetallocv(n+m, 0, &state->reducedsystem.compactpriorities, _state); + for(i=0; i<=n-1; i++) + { + state->reducedsystem.compactpriorities.ptr.p_int[i] = groupcols; + if( !hasbndl->ptr.p_bool[i]&&!hasbndu->ptr.p_bool[i] ) + { + state->reducedsystem.compactpriorities.ptr.p_int[i] = groupfree; + } + if( state->reducedsystem.coldegrees.ptr.p_int[i]>colthreshold ) + { + state->reducedsystem.compactpriorities.ptr.p_int[i] = densegroup; + } + } + for(i=0; i<=m-1; i++) + { + state->reducedsystem.compactpriorities.ptr.p_int[n+i] = grouprows; + if( (ae_isfinite(cl->ptr.p_double[i], _state)&&ae_isfinite(cu->ptr.p_double[i], _state))&&ae_fp_less(cl->ptr.p_double[i]-cu->ptr.p_double[i],(double)1000*ae_sqrt(ae_machineepsilon, _state)*rmaxabs3(cl->ptr.p_double[i], cu->ptr.p_double[i], 1.0, _state)) ) + { + state->reducedsystem.compactpriorities.ptr.p_int[n+i] = groupequality; + } + if( state->reducedsystem.rowdegrees.ptr.p_int[i]>rowthreshold ) + { + state->reducedsystem.compactpriorities.ptr.p_int[n+i] = densegroup; + } + } + if( !spsymmanalyze(&state->reducedsystem.compactkkt, &state->reducedsystem.compactpriorities, ipm2solver_mupromote, densegroup, ipm2solver_spsymmfacttype, 3, 1, &state->reducedsystem.analysis, _state) ) + { + ae_assert(ae_false, "ReducedSystemPowerUp: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } + icopyallocv(n+m, &state->reducedsystem.analysis.fillinperm, p, _state); +} + + +/************************************************************************* +Sets KKT system ordering to that produced by IPM2ProposeOrdering(). + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + P - array[N+M], ordering + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ipm2setordering(ipm2state* state, + /* Integer */ const ae_vector* p, + ae_state *_state) +{ + + + icopyallocv(state->nuser+state->mraw, p, &state->userpermutation, _state); + state->hasuserpermutation = ae_true; +} + + +/************************************************************************* +Solve QP problem. + +INPUT PARAMETERS: + State - solver instance + DropBigBounds - If True, algorithm may drop box and linear constraints + with huge bound values that destabilize algorithm. + +OUTPUT PARAMETERS: + XS - array[N], solution + LagBC - array[N], Lagrange multipliers for box constraints + LagLC - array[M], Lagrange multipliers for linear constraints + TerminationType - completion code, positive values for success, + negative for failures (XS constrains best point + found so far): + * -2 the task is either unbounded or infeasible; + the IPM solver has difficulty distinguishing between these two. + * +1 stopping criteria are met + * +7 stopping criteria are too stringent + +RESULT: + +This function ALWAYS returns something meaningful in XS, LagBC, LagLC - +either solution or the best point so far, even for negative TerminationType. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void ipm2optimize(ipm2state* state, + ae_bool dropbigbounds, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_int_t nuser; + ae_int_t ntotal; + ae_int_t m; + ae_int_t i; + double regfree; + double dampeps; + double maxdampeps; + double dampepsmu; + double dampepszs; + ae_int_t iteridx; + double mu0; + double mu1; + double alpha; + double alphaprev; + double alphac; + ae_int_t primalstagnationcnt; + ae_int_t dualstagnationcnt; + double errp2; + double errd2; + double errpinf; + double errdinf; + double preverrp2; + double preverrd2; + double errgap; + double eprimal; + double edual; + double egap; + double y0nrm; + double bady; + ae_int_t bestiteridx; + double besterr; + double bestegap; + double besteprimal; + double bestedual; + ae_bool loadbest; + double mustop; + + *terminationtype = 0; + + nuser = state->nuser; + ntotal = state->ntotal; + m = state->mraw; + state->dotrace = ae_is_trace_enabled("IPM"); + state->dotimers = state->dotrace||ae_is_trace_enabled("TIMERS.IPM"); + state->dodetailedtrace = state->dotrace&&ae_is_trace_enabled("IPM.DETAILED"); + + /* + * Prepare outputs + */ + rsetallocv(nuser, 0.0, xs, _state); + rsetallocv(nuser, 0.0, lagbc, _state); + rsetallocv(m, 0.0, laglc, _state); + + /* + * Some integrity checks: + * * we need PrimalStagnationLendotimers ) + { + stimerinit(&state->timertotal, _state); + stimerinit(&state->timeranalyze, _state); + stimerinit(&state->timerfactorize, _state); + stimerinit(&state->timerspsymmsolve, _state); + stimerinit(&state->timerothersolve, _state); + stimerstart(&state->timertotal, _state); + } + if( state->dotrace||state->dotimers ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// IPM SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Prepare regularization coefficients: + * * DampEps - damping coefficient for damped Newton step. Comes along with SafeDampEps + * (threshold value when some safeguards are turned off in order to preserve convergence + * speed) and MaxDampEps - threshold value when we consider problem overregularized and stop. + */ + regfree = ae_pow(ae_machineepsilon, 0.75, _state); + dampepsmu = ae_machineepsilon; + dampepszs = ae_machineepsilon; + dampeps = (double)10*ae_machineepsilon; + maxdampeps = ae_sqrt(ae_sqrt(ae_machineepsilon, _state), _state); + + /* + * Set up initial state + */ + state->repiterationscount = 0; + state->repncholesky = 0; + mustop = (double)100*ae_machineepsilon; + ipm2solver_ipm2powerup(state, regfree, _state); + ipm2solver_varsinitfrom(&state->best, &state->current, _state); + ipm2solver_varsinitbyzero(&state->delta, ntotal, m, _state); + ipm2solver_varsinitbyzero(&state->corr, ntotal, m, _state); + bestiteridx = -1; + besterr = ae_maxrealnumber; + bestegap = ae_maxrealnumber; + besteprimal = ae_maxrealnumber; + bestedual = ae_maxrealnumber; + ipm2solver_traceprogress(state, 0.0, 0.0, 0.0, _state); + y0nrm = (double)(0); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(m, &state->current.y, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(ntotal, &state->current.z, _state), _state); + y0nrm = ae_maxreal(y0nrm, rmaxabsv(ntotal, &state->current.s, _state), _state); + + /* + * Start iteration + */ + loadbest = ae_true; + primalstagnationcnt = 0; + dualstagnationcnt = 0; + *terminationtype = 7; + errp2 = ae_maxrealnumber; + errd2 = ae_maxrealnumber; + alphaprev = 0.0; + ipm2solver_ipm2multiply(state, &state->current.x, &state->current.y, &state->currenthx, &state->currentax, &state->currentaty, _state); + mu0 = ipm2solver_varscomputemu(state, &state->current, _state); + ipm2solver_rhscomputeprimdual(state, &state->current, &state->currenthx, &state->currentax, &state->currentaty, &state->rhstarget, _state); + for(iteridx=0; iteridx<=state->maxipmits-1; iteridx++) + { + + /* + * Trace beginning + */ + if( state->dotrace ) + { + ae_trace("=== PREDICTOR-CORRECTOR STEP %2d ====================================================================\n", + (int)(iteridx)); + } + + /* + * Check regularization status, terminate if overregularized + */ + if( ae_fp_greater_eq(dampeps,maxdampeps) ) + { + if( state->dotrace ) + { + ae_trace("> tried to increase regularization parameter, but it is too large\n"); + ae_trace("> it is likely that stopping conditions are too stringent, stopping at the best point found so far\n"); + } + *terminationtype = 7; + break; + } + + /* + * Precompute factorization + */ + if( !ipm2solver_reducedsystemcomputefactorization(&state->reducedsystem, state, &state->current, dampepsmu, dampepszs, dampeps, dampeps, _state) ) + { + + /* + * KKT factorization failed. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> LDLT factorization failed due to rounding errors\n"); + ae_trace("> increasing DampEps coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + + /* + * Mehrotra predictor-corrector. + * Prepare initial predictor step + */ + ipm2solver_rhsrecomputegammapredictor(state, &state->current, 0.0, &state->rhstarget, _state); + if( !ipm2solver_reducedsystemsolve(&state->reducedsystem, state, &state->current, &state->rhstarget, &state->delta, _state) ) + { + + /* + * Initial affine scaling step failed due to numerical errors. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> initial affine scaling step failed to decrease residual due to rounding errors\n"); + ae_trace("> increasing DampEps coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + ipm2solver_ipm2computesteplength(state, &state->current, &state->delta, &alpha, _state); + mu1 = ipm2solver_varscomputemutrial(state, &state->current, &state->delta, alpha, _state); + + /* + * Perform corrector step + */ + ipm2solver_rhsrecomputegammamehrotra(state, &state->current, ae_pow(mu1/(mu0+ae_machineepsilon), (double)(3), _state)*mu0, &state->delta, &state->rhstarget, _state); + if( !ipm2solver_reducedsystemsolve(&state->reducedsystem, state, &state->current, &state->rhstarget, &state->corr, _state) ) + { + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> corrector failed to decrease residual due to rounding errors\n"); + ae_trace("> increasing DampEps coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + + /* + * Finally, computing a step length and making a step + */ + ipm2solver_ipm2computesteplength(state, &state->current, &state->corr, &alphac, _state); + if( ae_fp_greater_eq((double)(iteridx),ipm2solver_minitersbeforesafeguards)&&(ae_fp_less_eq(alphac,ipm2solver_badsteplength)&&ae_fp_greater(alphaprev,ipm2solver_badsteplength)) ) + { + + /* + * Previous step was good, but this step is too short, likely to fail due to numerical errors. + * Increase regularization parameter and skip this iteration. + */ + dampeps = (double)10*dampeps; + if( state->dotrace ) + { + ae_trace("> step length is too short (after having a good step before), suspecting rounding errors\n"); + ae_trace("> increasing DampEps coefficient to %0.2e, skipping iteration\n", + (double)(dampeps)); + } + continue; + } + ipm2solver_varsaddstep(&state->current, &state->corr, alphac, _state); + inc(&state->repiterationscount, _state); + alphaprev = alphac; + ipm2solver_traceprogress(state, mu0, alpha, alphac, _state); + ipm2solver_ipm2multiply(state, &state->current.x, &state->current.y, &state->currenthx, &state->currentax, &state->currentaty, _state); + ipm2solver_rhscomputeprimdual(state, &state->current, &state->currenthx, &state->currentax, &state->currentaty, &state->rhstarget, _state); + mu0 = ipm2solver_varscomputemu(state, &state->current, _state); + + /* + * Check stopping criteria + * * primal and dual stagnation are checked only when following criteria are met: + * 1) Mu is smaller than 1 (we already converged close enough) + * 2) we performed more than MinItersBeforeStagnation iterations + */ + preverrp2 = errp2; + preverrd2 = errd2; + ipm2solver_computeerrors(state, &state->rhstarget, &state->currenthx, &state->currentax, &state->currentaty, &errp2, &errd2, &errpinf, &errdinf, &errgap, _state); + egap = errgap; + eprimal = errpinf; + edual = errdinf; + if( ae_fp_less(rmax3(egap, eprimal, edual, _state),besterr) ) + { + + /* + * Save best point found so far + */ + ipm2solver_varsinitfrom(&state->best, &state->current, _state); + bestiteridx = iteridx; + besterr = rmax3(egap, eprimal, edual, _state); + bestegap = egap; + besteprimal = eprimal; + bestedual = edual; + } + if( bestiteridx>0&&iteridx>bestiteridx+ipm2solver_minitersbeforeeworststagnation ) + { + if( state->dotrace ) + { + ae_trace("> worst of primal/dual/gap errors stagnated for %0d its, stopping at the best point found so far\n", + (int)(ipm2solver_minitersbeforeeworststagnation)); + } + break; + } + if( ((ae_fp_less_eq(egap,state->epsgap)&&ae_fp_greater_eq(errp2,ipm2solver_stagnationdelta*preverrp2))&&ae_fp_greater_eq(errpinf,ipm2solver_primalinfeasible1))&&iteridx>=ipm2solver_minitersbeforestagnation ) + { + inc(&primalstagnationcnt, _state); + if( primalstagnationcnt>=ipm2solver_primalstagnationlen ) + { + if( state->dotrace ) + { + ae_trace("> primal error stagnated for %0d its, stopping at the best point found so far\n", + (int)(ipm2solver_primalstagnationlen)); + } + break; + } + } + else + { + primalstagnationcnt = 0; + } + if( ((ae_fp_less_eq(egap,state->epsgap)&&ae_fp_greater_eq(errd2,ipm2solver_stagnationdelta*preverrd2))&&ae_fp_greater_eq(errdinf,ipm2solver_dualinfeasible1))&&iteridx>=ipm2solver_minitersbeforestagnation ) + { + inc(&dualstagnationcnt, _state); + if( dualstagnationcnt>=ipm2solver_dualstagnationlen ) + { + if( state->dotrace ) + { + ae_trace("> dual error stagnated for %0d its, stopping at the best point found so far\n", + (int)(ipm2solver_dualstagnationlen)); + } + break; + } + } + else + { + dualstagnationcnt = 0; + } + if( ae_fp_less_eq(mu0,mustop)&&iteridx>=ipm2solver_itersfortoostringentcond ) + { + if( state->dotrace ) + { + ae_trace("> stopping conditions are too stringent, stopping at the best point found so far\n"); + } + *terminationtype = 7; + break; + } + if( (ae_fp_less_eq(egap,state->epsgap)&&ae_fp_less_eq(eprimal,state->epsp))&&ae_fp_less_eq(edual,state->epsd) ) + { + if( state->dotrace ) + { + ae_trace("> stopping criteria are met\n"); + } + *terminationtype = 1; + loadbest = ae_false; + break; + } + bady = ipm2solver_bigy; + bady = ae_maxreal(bady, ipm2solver_ygrowth*y0nrm, _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.x, _state), _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.g, _state), _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.t, _state), _state); + if( ae_fp_greater_eq(rmaxabsv(m, &state->current.y, _state),bady)&&iteridx>=ipm2solver_minitersbeforeinfeasible ) + { + if( state->dotrace ) + { + ae_trace("> |Y| increased beyond %0.1e, stopping at the best point found so far\n", + (double)(bady)); + } + break; + } + } + + /* + * Load best point, perform some checks + */ + if( loadbest ) + { + + /* + * Load best point + * + * NOTE: TouchReal() is used to avoid spurious compiler warnings about 'set but unused' + */ + if( state->dotrace ) + { + ae_trace("> the best point so far is one from iteration %0d\n", + (int)(bestiteridx)); + } + ipm2solver_varsinitfrom(&state->current, &state->best, _state); + touchreal(&besteprimal, _state); + touchreal(&bestedual, _state); + touchreal(&bestegap, _state); + + /* + * If no error flags were set yet, check solution quality + */ + bady = ipm2solver_bigy; + bady = ae_maxreal(bady, ipm2solver_ygrowth*y0nrm, _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.x, _state), _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.g, _state), _state); + bady = ae_maxreal(bady, ipm2solver_ygrowth*rmaxabsv(ntotal, &state->current.t, _state), _state); + if( *terminationtype>0&&ae_fp_greater_eq(rmaxabsv(m, &state->current.y, _state),bady) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> |Y| increased beyond %0.1e, declaring infeasibility/unboundedness\n", + (double)(bady)); + } + } + if( *terminationtype>0&&ae_fp_greater_eq(besteprimal,ipm2solver_primalinfeasible1) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> primal error at the best point is too high, declaring infeasibility/unboundedness\n"); + } + } + if( *terminationtype>0&&ae_fp_greater_eq(bestedual,ipm2solver_dualinfeasible1) ) + { + *terminationtype = -2; + if( state->dotrace ) + { + ae_trace("> dual error at the best point is too high, declaring infeasibility/unboundedness\n"); + } + } + } + + /* + * Output + */ + for(i=0; i<=nuser-1; i++) + { + xs->ptr.p_double[i] = state->current.x.ptr.p_double[i]; + lagbc->ptr.p_double[i] = 0.0; + if( state->hasgz.ptr.p_bool[i] ) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]-state->current.z.ptr.p_double[i]; + } + if( state->hasts.ptr.p_bool[i] ) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]+state->current.s.ptr.p_double[i]; + } + } + for(i=0; i<=m-1; i++) + { + laglc->ptr.p_double[i] = -state->current.y.ptr.p_double[i]; + } + + /* + * Unscale point and Lagrange multipliers + */ + unscaleunshiftpointbc(&state->sclx, &state->xoriginx, &state->rawbndl, &state->rawbndu, &state->bndle, &state->bndue, &state->hasbndle, &state->hasbndue, xs, nuser, _state); + for(i=0; i<=nuser-1; i++) + { + lagbc->ptr.p_double[i] = lagbc->ptr.p_double[i]*state->targetscale/state->sclx.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + laglc->ptr.p_double[i] = laglc->ptr.p_double[i]*state->targetscale/state->ascales.ptr.p_double[i]; + } + + /* + * Timers and reports + */ + if( state->dotimers ) + { + stimerstop(&state->timertotal, _state); + ae_trace("\n> printing internal timers (can be zero when run in OS-agnostic mode)\n"); + ae_trace("> total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("> * in analyze: %10.1f ms\n", + (double)(stimergetms(&state->timeranalyze, _state))); + ae_trace("> * in factorize: %10.1f ms\n", + (double)(stimergetms(&state->timerfactorize, _state))); + ae_trace("> * in spsymmsolve(): %10.1f ms\n", + (double)(stimergetms(&state->timerspsymmsolve, _state))); + ae_trace("> * in other solve: %10.1f ms\n", + (double)(stimergetms(&state->timerothersolve, _state)-stimergetms(&state->timerspsymmsolve, _state))); + } +} + + +/************************************************************************* +Allocates place for variables of IPM and fills by zeros. + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_varsinitbyzero(ipm2vars* vstate, + ae_int_t ntotal, + ae_int_t m, + ae_state *_state) +{ + + + ae_assert(ntotal>=1, "VarsInitByZero: NTotal<1", _state); + ae_assert(m>=0, "VarsInitByZero: M<0", _state); + vstate->ntotal = ntotal; + vstate->m = m; + rsetallocv(ntotal, 0.0, &vstate->x, _state); + rsetallocv(ntotal, 0.0, &vstate->g, _state); + rsetallocv(ntotal, 0.0, &vstate->t, _state); + rsetallocv(ntotal, 0.0, &vstate->z, _state); + rsetallocv(ntotal, 0.0, &vstate->s, _state); + rsetallocv(m, 0.0, &vstate->y, _state); +} + + +/************************************************************************* +Allocates place for variables of IPM and fills them by values of +the source + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_varsinitfrom(ipm2vars* vstate, + const ipm2vars* vsrc, + ae_state *_state) +{ + + + ae_assert(vsrc->ntotal>=1, "VarsInitFrom: NTotal<1", _state); + ae_assert(vsrc->m>=0, "VarsInitFrom: M<0", _state); + vstate->ntotal = vsrc->ntotal; + vstate->m = vsrc->m; + rcopyallocv(vsrc->ntotal, &vsrc->x, &vstate->x, _state); + rcopyallocv(vsrc->ntotal, &vsrc->g, &vstate->g, _state); + rcopyallocv(vsrc->ntotal, &vsrc->t, &vstate->t, _state); + rcopyallocv(vsrc->ntotal, &vsrc->z, &vstate->z, _state); + rcopyallocv(vsrc->ntotal, &vsrc->s, &vstate->s, _state); + rcopyallocv(vsrc->m, &vsrc->y, &vstate->y, _state); +} + + +/************************************************************************* +Adds to variables direction vector times step length. Different +lengths are used for primal and dual steps. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_varsaddstep(ipm2vars* vstate, + const ipm2vars* vdir, + double stp, + ae_state *_state) +{ + + + raddv(vstate->ntotal, stp, &vdir->x, &vstate->x, _state); + raddv(vstate->ntotal, stp, &vdir->g, &vstate->g, _state); + raddv(vstate->ntotal, stp, &vdir->z, &vstate->z, _state); + raddv(vstate->ntotal, stp, &vdir->t, &vstate->t, _state); + raddv(vstate->ntotal, stp, &vdir->s, &vstate->s, _state); + raddv(vstate->m, stp, &vdir->y, &vstate->y, _state); +} + + +/************************************************************************* +Computes complementarity gap + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_varscomputecomplementaritygap(const ipm2vars* vstate, + ae_state *_state) +{ + double result; + + + result = rdotv(vstate->ntotal, &vstate->g, &vstate->z, _state)+rdotv(vstate->ntotal, &vstate->t, &vstate->s, _state); + return result; +} + + +/************************************************************************* +Computes empirical value of the barrier parameter Mu + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_varscomputemu(const ipm2state* state, + const ipm2vars* vstate, + ae_state *_state) +{ + double result; + + + result = (rdotv(state->ntotal, &vstate->z, &vstate->g, _state)+rdotv(state->ntotal, &vstate->s, &vstate->t, _state))/coalesce((double)(state->cntgz+state->cntts), (double)(1), _state); + return result; +} + + +/************************************************************************* +Computes empirical value of the barrier parameter Mu at the trial point +Current+Alpha*Delta without computing the point itself. + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_varscomputemutrial(const ipm2state* state, + const ipm2vars* current, + const ipm2vars* delta, + double alpha, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nx; + double result; + + + nx = state->ntotal; + result = (double)(0); + for(i=0; i<=nx-1; i++) + { + result = result+(current->g.ptr.p_double[i]+alpha*delta->g.ptr.p_double[i])*(current->z.ptr.p_double[i]+alpha*delta->z.ptr.p_double[i]); + result = result+(current->t.ptr.p_double[i]+alpha*delta->t.ptr.p_double[i])*(current->s.ptr.p_double[i]+alpha*delta->s.ptr.p_double[i]); + } + result = result/coalesce((double)(state->cntgz+state->cntts), (double)(1), _state); + return result; +} + + +/************************************************************************* +Computes + + Y := alpha*A*x + beta*Y + +where A is constraint matrix, X is user-specified source, Y is target. + +Beta can be zero (in this case original contents of Y is ignored). +If Beta is nonzero, we expect that Y contains preallocated array. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_multiplygeax(const ipm2state* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsax, + ae_state *_state) +{ + ae_int_t m; + + + m = state->mraw; + if( ae_fp_eq(beta,(double)(0)) ) + { + rallocv(offsax+m, y, _state); + } + else + { + ae_assert(y->cnt>=offsax+m, "MultiplyGEAX: Y is too short", _state); + } + if( ae_fp_neq(alpha,(double)(0))&&m!=0 ) + { + sparsegemv(&state->rawae, alpha, 0, x, offsx, beta, y, offsax, _state); + } +} + + +/************************************************************************* +Computes + + Y := alpha*A'*x + beta*Y + +where A is constraint matrix, X is user-specified source, Y is target. + +Beta can be zero, in this case we automatically reallocate target if it is +too short (but do NOT reallocate it if its size is large enough). +If Beta is nonzero, we expect that Y contains preallocated array. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_multiplygeatx(const ipm2state* state, + double alpha, + /* Real */ const ae_vector* x, + ae_int_t offsx, + double beta, + /* Real */ ae_vector* y, + ae_int_t offsy, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t m; + + + ntotal = state->ntotal; + m = state->mraw; + if( ae_fp_eq(beta,(double)(0)) ) + { + rallocv(offsy+ntotal, y, _state); + rsetvx(ntotal, 0.0, y, offsy, _state); + } + else + { + ae_assert(y->cnt>=offsy+ntotal, "MultiplyGEATX: Y is too short", _state); + rmulvx(ntotal, beta, y, offsy, _state); + } + if( ae_fp_neq(alpha,(double)(0))&&m!=0 ) + { + sparsegemv(&state->rawae, alpha, 1, x, offsx, 1.0, y, offsy, _state); + } +} + + +/************************************************************************* +Computes H*x, does not support advanced functionality of GEAX/GEATX + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_multiplyhx(const ipm2state* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t i; + + + ntotal = state->ntotal; + rallocv(ntotal, hx, _state); + ae_assert(state->sparsehe.n==ntotal&&state->sparsehe.m==ntotal, "IPM2MultiplyHX: sparse H has incorrect size", _state); + if( state->isdiagonalh ) + { + + /* + * H is known to be diagonal, much faster code can be used + */ + rcopyv(ntotal, &state->diagr, hx, _state); + raddv(ntotal, 1.0, &state->sparsehe.vals, hx, _state); + rmergemulv(ntotal, x, hx, _state); + } + else + { + + /* + * H is a general sparse matrix, use generic sparse matrix-vector multiply + */ + sparsesmv(&state->sparsehe, ae_false, x, hx, _state); + for(i=0; i<=ntotal-1; i++) + { + hx->ptr.p_double[i] = hx->ptr.p_double[i]+x->ptr.p_double[i]*state->diagr.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Computes products H*x, A*x, A^T*y + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_ipm2multiply(const ipm2state* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* hx, + /* Real */ ae_vector* ax, + /* Real */ ae_vector* aty, + ae_state *_state) +{ + + + ipm2solver_multiplygeax(state, 1.0, x, 0, 0.0, ax, 0, _state); + ipm2solver_multiplygeatx(state, 1.0, y, 0, 0.0, aty, 0, _state); + ipm2solver_multiplyhx(state, x, hx, _state); +} + + +/************************************************************************* +This function "powers up" factorization, i.e. prepares some important +temporaries. It should be called once prior to the first call to +VIPMInitialPoint() or VIPMFactorize(). + +Parameters: + RegFree - regularization for free variables; + good value sqrt(MachineEpsilon) + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_ipm2powerup(ipm2state* state, + double regfree, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t m; + ae_int_t i; + double initprimslack; + double initdualslack; + + + ntotal = state->ntotal; + m = state->mraw; + + /* + * Set up information about presence of slack variables. + * Compute diagonal regularization matrix R. + */ + bcopyallocv(ntotal, &state->hasbndle, &state->hasgz, _state); + bcopyallocv(ntotal, &state->hasbndue, &state->hasts, _state); + rsetallocv(ntotal, 0.0, &state->diagr, _state); + ipm2solver_varsinitbyzero(&state->current, ntotal, m, _state); + rsetallocv(ntotal, 0.0, &state->maskgz, _state); + rsetallocv(ntotal, 0.0, &state->maskts, _state); + state->cntgz = 0; + state->cntts = 0; + for(i=0; i<=ntotal-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + state->maskgz.ptr.p_double[i] = 1.0; + state->cntgz = state->cntgz+1; + } + if( state->hasts.ptr.p_bool[i] ) + { + state->maskts.ptr.p_double[i] = 1.0; + state->cntts = state->cntts+1; + } + if( !state->hasgz.ptr.p_bool[i]&&!state->hasts.ptr.p_bool[i] ) + { + state->diagr.ptr.p_double[i] = regfree; + } + } + + /* + * Compute global regularizer for X and Y + */ + if( ae_fp_neq(state->greg,(double)(0)) ) + { + + /* + * Compute diagonal modifications to LHS and RHS + */ + rsetallocv(ntotal+m, 0.0, &state->gregdiag, _state); + rsetvx(state->nuser, -state->greg, &state->gregdiag, 0, _state); + rsetvx(m, state->greg, &state->gregdiag, ntotal, _state); + rallocv(ntotal, &state->gregrhsx, _state); + rsetvx(state->nuser, state->greg, &state->gregrhsx, 0, _state); + rsetvx(ntotal-state->nuser, 0.0, &state->gregrhsx, state->nuser, _state); + rsetallocv(m, -state->greg, &state->gregrhsy, _state); + + /* + * Combine X-origin and Y-origin + */ + rsetallocv(ntotal, 0.0, &state->gregoriginx, _state); + rcopyv(state->nuser, &state->gregoriginxuser, &state->gregoriginx, _state); + rmergemulv(state->nuser, &state->invsclx, &state->gregoriginx, _state); + rcopyallocv(m, &state->gregoriginyuser, &state->gregoriginy, _state); + rmergemulv(m, &state->ascales, &state->gregoriginy, _state); + rmulv(m, (double)1/state->targetscale, &state->gregoriginy, _state); + } + + /* + * Initialize sparse system + * Set up current primal and dual slacks + */ + ipm2solver_reducedsystempowerup(&state->reducedsystem, state, &state->current.x, &state->current.y, _state); + initprimslack = ae_maxreal(ipm2solver_initslackval, rmaxabsv(ntotal, &state->current.x, _state), _state); + initdualslack = ae_maxreal(ipm2solver_initslackval, rmaxabsv(m, &state->current.y, _state), _state); + rsetv(ntotal, 0.0, &state->current.g, _state); + rsetv(ntotal, 0.0, &state->current.z, _state); + rsetv(ntotal, 0.0, &state->current.t, _state); + rsetv(ntotal, 0.0, &state->current.s, _state); + for(i=0; i<=ntotal-1; i++) + { + if( state->hasgz.ptr.p_bool[i] ) + { + state->current.g.ptr.p_double[i] = ae_maxreal(initprimslack, state->current.x.ptr.p_double[i]-state->bndle.ptr.p_double[i], _state); + state->current.z.ptr.p_double[i] = ae_minreal(initdualslack, initprimslack*initdualslack/state->current.g.ptr.p_double[i], _state); + } + if( state->hasts.ptr.p_bool[i] ) + { + state->current.t.ptr.p_double[i] = ae_maxreal(initprimslack, state->bndue.ptr.p_double[i]-state->current.x.ptr.p_double[i], _state); + state->current.s.ptr.p_double[i] = ae_minreal(initdualslack, initprimslack*initdualslack/state->current.t.ptr.p_double[i], _state); + } + } + + /* + * Almost done + */ + if( state->dotrace ) + { + ae_trace("> initial point was generated\n"); + } +} + + +/************************************************************************* +This function "powers up" reduced (NX+M)*(NX+M) system, i.e. prepares data +structures to receive data necessary for the factorization and solution. + +It should be called once at the beginning of the optimization. + +This function also proposes initial X and Y by solving strongly damped +augmented system. It expects X and Y to be preallocated arrays long enough +to store the result. + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_reducedsystempowerup(ipm2reducedsystem* s, + ipm2state* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t nuser; + ae_int_t naug; + ae_int_t ntotal; + ae_int_t m; + ae_int_t offs; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t colthreshold; + ae_int_t rowthreshold; + ae_int_t sumcoldeg; + ae_int_t sumrowdeg; + ae_int_t n0; + ae_int_t n1; + ae_int_t n2; + ae_int_t n3; + ae_int_t n4; + ae_int_t groupcols; + ae_int_t grouprows; + ae_int_t groupequality; + ae_int_t groupfree; + ae_int_t densegroup; + ae_int_t denseupdatesgroup; + ae_int_t orderingtouse; + + + nuser = state->nuser; + naug = state->naug; + ntotal = state->ntotal; + m = state->mraw; + + /* + * Allocate sparse matrix + */ + sumcoldeg = 0; + sumrowdeg = 0; + isetallocv(naug, 0, &s->coldegrees, _state); + isetallocv(m, 0, &s->rowdegrees, _state); + rallocv(ntotal+m, &s->extendedrawdiagonal, _state); + s->compactkkt.matrixtype = 1; + s->compactkkt.m = ntotal; + s->compactkkt.n = ntotal; + iallocv(s->compactkkt.m+1, &s->compactkkt.ridx, _state); + s->compactkkt.ridx.ptr.p_int[0] = 0; + for(i=0; i<=naug-1; i++) + { + offs = s->compactkkt.ridx.ptr.p_int[i]; + igrowv(offs+naug+1, &s->compactkkt.idx, _state); + rgrowv(offs+naug+1, &s->compactkkt.vals, _state); + + /* + * Offdiagonal elements + */ + j0 = state->sparsehe.ridx.ptr.p_int[i]; + j1 = state->sparsehe.didx.ptr.p_int[i]-1; + for(j=j0; j<=j1; j++) + { + k = state->sparsehe.idx.ptr.p_int[j]; + s->compactkkt.idx.ptr.p_int[offs] = k; + s->compactkkt.vals.ptr.p_double[offs] = -state->sparsehe.vals.ptr.p_double[j]; + s->coldegrees.ptr.p_int[i] = s->coldegrees.ptr.p_int[i]+1; + s->coldegrees.ptr.p_int[k] = s->coldegrees.ptr.p_int[k]+1; + sumcoldeg = sumcoldeg+2; + offs = offs+1; + } + + /* + * Diagonal element + */ + j1 = state->sparsehe.didx.ptr.p_int[i]; + s->extendedrawdiagonal.ptr.p_double[i] = -(state->sparsehe.vals.ptr.p_double[j1]+state->diagr.ptr.p_double[i]); + s->compactkkt.idx.ptr.p_int[offs] = state->sparsehe.idx.ptr.p_int[j1]; + s->compactkkt.vals.ptr.p_double[offs] = s->extendedrawdiagonal.ptr.p_double[i]; + offs = offs+1; + + /* + * Done + */ + s->compactkkt.ridx.ptr.p_int[i+1] = offs; + } + for(i=naug; i<=ntotal-1; i++) + { + ae_assert(state->sparsehe.ridx.ptr.p_int[i]==state->sparsehe.didx.ptr.p_int[i], "IPM2: integrity check 0546 failed", _state); + ae_assert(state->sparsehe.didx.ptr.p_int[i]==state->sparsehe.uidx.ptr.p_int[i]-1, "IPM2: integrity check 0547 failed", _state); + ae_assert(ae_fp_eq(state->sparsehe.vals.ptr.p_double[state->sparsehe.didx.ptr.p_int[i]],0.0), "IPM2: integrity check 0548 failed", _state); + s->extendedrawdiagonal.ptr.p_double[i] = -(state->sparsehe.vals.ptr.p_double[state->sparsehe.didx.ptr.p_int[i]]+state->diagr.ptr.p_double[i]); + } + for(i=0; i<=m-1; i++) + { + ae_assert(state->rawae.ridx.ptr.p_int[i+1]>state->rawae.ridx.ptr.p_int[i], "IPM2: integrity check 1251 failed", _state); + ae_assert(state->rawae.idx.ptr.p_int[state->rawae.ridx.ptr.p_int[i+1]-1]==naug+i, "IPM2: integrity check 1252 failed", _state); + ae_assert(ae_fp_eq(state->rawae.vals.ptr.p_double[state->rawae.ridx.ptr.p_int[i+1]-1],-1.0), "IPM2: integrity check 1253 failed", _state); + offs = s->compactkkt.ridx.ptr.p_int[naug+i]; + igrowv(offs+naug+1, &s->compactkkt.idx, _state); + rgrowv(offs+naug+1, &s->compactkkt.vals, _state); + j0 = state->rawae.ridx.ptr.p_int[i]; + j1 = state->rawae.ridx.ptr.p_int[i+1]-2; + for(j=j0; j<=j1; j++) + { + k = state->rawae.idx.ptr.p_int[j]; + s->compactkkt.idx.ptr.p_int[offs] = k; + s->compactkkt.vals.ptr.p_double[offs] = state->rawae.vals.ptr.p_double[j]; + s->rowdegrees.ptr.p_int[i] = s->rowdegrees.ptr.p_int[i]+1; + s->coldegrees.ptr.p_int[k] = s->coldegrees.ptr.p_int[k]+1; + sumrowdeg = sumrowdeg+1; + sumcoldeg = sumcoldeg+1; + offs = offs+1; + } + s->compactkkt.idx.ptr.p_int[offs] = naug+i; + s->compactkkt.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + s->extendedrawdiagonal.ptr.p_double[ntotal+i] = 0.0; + s->compactkkt.ridx.ptr.p_int[naug+i+1] = offs; + } + sparsecreatecrsinplace(&s->compactkkt, _state); + + /* + * Determine elimination priorities + */ + if( state->hasuserpermutation ) + { + + /* + * Use permutation proposed by user + */ + isetallocv(ntotal, -1, &s->compactpriorities, _state); + for(i=0; i<=state->nuser-1; i++) + { + s->compactpriorities.ptr.p_int[i] = state->userpermutation.ptr.p_int[i]; + } + for(i=state->nuser; i<=state->naug-1; i++) + { + s->compactpriorities.ptr.p_int[i] = state->nuser+state->mraw+(i-state->nuser); + } + for(i=state->naug; i<=state->ntotal-1; i++) + { + s->compactpriorities.ptr.p_int[i] = state->userpermutation.ptr.p_int[state->nuser+(i-state->naug)]; + } + orderingtouse = -4; + densegroup = 0; + } + else + { + + /* + * Use AMD to determine elimination priorities + */ + colthreshold = ae_round(ipm2solver_muquasidense*(double)sumcoldeg/(double)naug, _state)+1; + rowthreshold = ae_round(ipm2solver_muquasidense*(double)sumrowdeg/coalesce((double)(m), (double)(1), _state), _state)+1; + if( ae_fp_less_eq((double)sumcoldeg/(double)naug,(double)sumrowdeg/coalesce((double)(m), (double)(1), _state)) ) + { + groupcols = 0; + grouprows = 1; + } + else + { + groupcols = 1; + grouprows = 0; + } + groupequality = 2; + groupfree = 3; + densegroup = ae_maxint(groupfree, groupequality, _state); + denseupdatesgroup = densegroup+1; + isetallocv(ntotal, 0, &s->compactpriorities, _state); + for(i=0; i<=nuser-1; i++) + { + s->compactpriorities.ptr.p_int[i] = groupcols; + if( !state->hasbndle.ptr.p_bool[i]&&!state->hasbndue.ptr.p_bool[i] ) + { + s->compactpriorities.ptr.p_int[i] = groupfree; + } + if( s->coldegrees.ptr.p_int[i]>colthreshold ) + { + s->compactpriorities.ptr.p_int[i] = densegroup; + } + } + for(i=nuser; i<=naug-1; i++) + { + s->compactpriorities.ptr.p_int[i] = denseupdatesgroup; + } + for(i=0; i<=m-1; i++) + { + s->compactpriorities.ptr.p_int[naug+i] = grouprows; + if( (state->hasbndle.ptr.p_bool[naug+i]&&state->hasbndue.ptr.p_bool[naug+i])&&ae_fp_less(state->bndue.ptr.p_double[naug+i]-state->bndle.ptr.p_double[naug+i],(double)1000*ae_maxreal(state->epsp, ae_sqrt(ae_machineepsilon, _state), _state)*rmax3(ae_fabs(state->bndue.ptr.p_double[naug+i], _state), ae_fabs(state->bndle.ptr.p_double[naug+i], _state), 1.0, _state)) ) + { + s->compactpriorities.ptr.p_int[naug+i] = groupequality; + } + if( s->rowdegrees.ptr.p_int[i]>rowthreshold ) + { + s->compactpriorities.ptr.p_int[naug+i] = densegroup; + } + } + if( state->dotrace ) + { + n0 = 0; + n1 = 0; + n2 = 0; + n3 = 0; + n4 = 0; + for(i=0; i<=ntotal-1; i++) + { + if( s->compactpriorities.ptr.p_int[i]==0 ) + { + inc(&n0, _state); + } + if( s->compactpriorities.ptr.p_int[i]==1 ) + { + inc(&n1, _state); + } + if( s->compactpriorities.ptr.p_int[i]==2 ) + { + inc(&n2, _state); + } + if( s->compactpriorities.ptr.p_int[i]==3 ) + { + inc(&n3, _state); + } + if( s->compactpriorities.ptr.p_int[i]==4 ) + { + inc(&n4, _state); + } + } + ae_trace("> KKT matrix formed, elimination groups determined:\n"); + if( groupcols==0 ) + { + ae_trace(">> group 0 (variables): %7d columns\n", + (int)(n0)); + ae_trace(">> group 1 (equations): %7d columns\n", + (int)(n1)); + } + else + { + ae_trace(">> group 0 (equations): %7d columns\n", + (int)(n0)); + ae_trace(">> group 1 (variables): %7d columns\n", + (int)(n1)); + } + ae_trace(">> group 2 (equality ): %7d columns\n", + (int)(n2)); + ae_trace(">> group 3 (free ): %7d columns\n", + (int)(n3)); + ae_trace(">> group 4 (dense ): %7d columns\n", + (int)(n4)); + } + orderingtouse = 3; + } + + /* + * Analyze + */ + stimerstartcond(&state->timeranalyze, state->dotimers, _state); + if( !spsymmanalyze(&s->compactkkt, &s->compactpriorities, ipm2solver_mupromote, densegroup, ipm2solver_spsymmfacttype, orderingtouse, 1, &s->analysis, _state) ) + { + ae_assert(ae_false, "ReducedSystemPowerUp: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } + stimerstopcond(&state->timeranalyze, state->dotimers, _state); + + /* + * Prepare initial X and Y by solving strongly factorized system + */ + ae_assert(x->cnt>=ntotal, "IPM2: integrity check 7400 failed", _state); + ae_assert(y->cnt>=m, "IPM2: integrity check 7401 failed", _state); + rallocv(ntotal+m, &s->extendedeffdiagonal, _state); + for(i=0; i<=nuser-1; i++) + { + s->extendedeffdiagonal.ptr.p_double[i] = ae_minreal(s->extendedrawdiagonal.ptr.p_double[i], 0.0, _state)-1.0; + } + for(i=nuser; i<=naug-1; i++) + { + s->extendedeffdiagonal.ptr.p_double[i] = s->extendedrawdiagonal.ptr.p_double[i]+possign(s->extendedrawdiagonal.ptr.p_double[i], _state); + } + for(i=naug; i<=ntotal-1; i++) + { + s->extendedeffdiagonal.ptr.p_double[i] = ae_minreal(s->extendedrawdiagonal.ptr.p_double[i], 0.0, _state)-1.0; + } + for(i=ntotal; i<=ntotal+m-1; i++) + { + s->extendedeffdiagonal.ptr.p_double[i] = ae_maxreal(s->extendedrawdiagonal.ptr.p_double[i], 0.0, _state)+1.0; + } + rallocv(naug+m, &s->compacteffdiagonal, _state); + for(i=0; i<=naug-1; i++) + { + s->compacteffdiagonal.ptr.p_double[i] = s->extendedeffdiagonal.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + s->compacteffdiagonal.ptr.p_double[naug+i] = -(double)1/s->extendedeffdiagonal.ptr.p_double[naug+i]+s->extendedeffdiagonal.ptr.p_double[ntotal+i]; + } + stimerstartcond(&state->timerfactorize, state->dotimers, _state); + spsymmreloaddiagonal(&s->analysis, &s->compacteffdiagonal, _state); + if( !spsymmfactorize(&s->analysis, _state) ) + { + ae_assert(ae_false, "ReducedSystemPowerUp: unexpected failure during decomposition of a strongly damped system", _state); + } + stimerstopcond(&state->timerfactorize, state->dotimers, _state); + rallocv(ntotal+m, &s->extendedrhs, _state); + rcopyv(ntotal, &state->ce, &s->extendedrhs, _state); + for(i=0; i<=m-1; i++) + { + v = (double)(0); + if( state->hasbndle.ptr.p_bool[naug+i]&&ae_fp_greater(state->bndle.ptr.p_double[naug+i],v) ) + { + v = state->bndle.ptr.p_double[naug+i]; + } + if( state->hasbndue.ptr.p_bool[naug+i]&&ae_fp_less(state->bndue.ptr.p_double[naug+i],v) ) + { + v = state->bndue.ptr.p_double[naug+i]; + } + s->extendedrhs.ptr.p_double[ntotal+i] = v; + } + rallocv(ntotal, &s->compactrhs, _state); + for(i=0; i<=naug-1; i++) + { + s->compactrhs.ptr.p_double[i] = s->extendedrhs.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + s->compactrhs.ptr.p_double[naug+i] = s->extendedrhs.ptr.p_double[ntotal+i]+s->extendedrhs.ptr.p_double[naug+i]/s->extendedeffdiagonal.ptr.p_double[naug+i]; + } + stimerstartcond(&state->timerspsymmsolve, state->dotimers, _state); + spsymmsolve(&s->analysis, &s->compactrhs, _state); + stimerstopcond(&state->timerspsymmsolve, state->dotimers, _state); + for(i=0; i<=naug-1; i++) + { + s->extendedrhs.ptr.p_double[i] = s->compactrhs.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + s->extendedrhs.ptr.p_double[ntotal+i] = s->compactrhs.ptr.p_double[naug+i]; + s->extendedrhs.ptr.p_double[naug+i] = (s->extendedrhs.ptr.p_double[naug+i]+s->compactrhs.ptr.p_double[naug+i])/s->extendedeffdiagonal.ptr.p_double[naug+i]; + } + rcopyvx(ntotal, &s->extendedrhs, 0, x, 0, _state); + rcopyvx(m, &s->extendedrhs, ntotal, y, 0, _state); +} + + +/************************************************************************* +Generates precomputed temporary vectors and KKT factorization at the +beginning of the current iteration. + +This function uses representation of QP problem as a box-constrained one +with linear equality constraints A*x=0. + +On successful factorization returns True; on failure returns False - it is +recommended to increase regularization parameter and try one more time. + +--- DESCRIPTION ---------------------------------------------------------- + + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool ipm2solver_reducedsystemcomputefactorization(ipm2reducedsystem* redsys, + ipm2state* sstate, + const ipm2vars* current, + double dampepsmu, + double dampepszs, + double dampepsp, + double dampepsd, + ae_state *_state) +{ + ae_int_t naug; + ae_int_t ntotal; + ae_int_t m; + ae_int_t i; + double gz; + double st; + double sumsq; + double errsq; + double badchol; + ae_bool result; + + + naug = sstate->naug; + ntotal = sstate->ntotal; + m = sstate->mraw; + result = ae_true; + badchol = 1.0E50; + + /* + * Pivot out dT and dS, dG and dZ + */ + rallocv(ntotal, &redsys->d0, _state); + rallocv(ntotal, &redsys->d1, _state); + rallocv(ntotal, &redsys->d2, _state); + rallocv(ntotal, &redsys->d3, _state); + rallocv(ntotal, &redsys->d4, _state); + rallocv(ntotal, &redsys->d5, _state); + rallocv(ntotal, &redsys->d6, _state); + rallocv(ntotal, &redsys->d7, _state); + rallocv(ntotal+m, &redsys->extendedeffdiagonal, _state); + rsetvx(ntotal, -dampepsp, &redsys->extendedeffdiagonal, 0, _state); + rsetvx(m, dampepsd, &redsys->extendedeffdiagonal, ntotal, _state); + if( ae_fp_greater(sstate->greg,(double)(0)) ) + { + raddv(ntotal+m, 1.0, &sstate->gregdiag, &redsys->extendedeffdiagonal, _state); + } + raddv(ntotal+m, 1.0, &redsys->extendedrawdiagonal, &redsys->extendedeffdiagonal, _state); + for(i=0; i<=ntotal-1; i++) + { + st = current->s.ptr.p_double[i]*current->t.ptr.p_double[i]; + redsys->d0.ptr.p_double[i] = (double)1/(dampepsmu+st); + redsys->d1.ptr.p_double[i] = redsys->d0.ptr.p_double[i]*current->t.ptr.p_double[i]; + redsys->d3.ptr.p_double[i] = sstate->maskts.ptr.p_double[i]/(dampepszs+redsys->d1.ptr.p_double[i]*current->t.ptr.p_double[i]); + gz = current->g.ptr.p_double[i]*current->z.ptr.p_double[i]; + redsys->d4.ptr.p_double[i] = (double)1/(dampepsmu+gz); + redsys->d5.ptr.p_double[i] = redsys->d4.ptr.p_double[i]*current->g.ptr.p_double[i]; + redsys->d7.ptr.p_double[i] = sstate->maskgz.ptr.p_double[i]/(dampepszs+redsys->d5.ptr.p_double[i]*current->g.ptr.p_double[i]); + } + raddv(ntotal, -1.0, &redsys->d3, &redsys->extendedeffdiagonal, _state); + raddv(ntotal, -1.0, &redsys->d7, &redsys->extendedeffdiagonal, _state); + rallocv(ntotal, &redsys->compacteffdiagonal, _state); + for(i=0; i<=naug-1; i++) + { + redsys->compacteffdiagonal.ptr.p_double[i] = redsys->extendedeffdiagonal.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + redsys->compacteffdiagonal.ptr.p_double[naug+i] = -(double)1/redsys->extendedeffdiagonal.ptr.p_double[naug+i]+redsys->extendedeffdiagonal.ptr.p_double[ntotal+i]; + } + spsymmreloaddiagonal(&redsys->analysis, &redsys->compacteffdiagonal, _state); + spsymmsetmodificationstrategy(&redsys->analysis, 1, ae_machineepsilon, badchol, 0.0, 0.0, _state); + stimerstartcond(&sstate->timerfactorize, sstate->dotimers, _state); + if( !spsymmfactorize(&redsys->analysis, _state) ) + { + stimerstopcond(&sstate->timerfactorize, sstate->dotimers, _state); + result = ae_false; + return result; + } + stimerstopcond(&sstate->timerfactorize, sstate->dotimers, _state); + spsymmdiagerr(&redsys->analysis, &sumsq, &errsq, _state); + if( sstate->dotrace ) + { + ae_trace("LDLT-diag-err= %0.3e (diagonal reproduction error)\n", + (double)(ae_sqrt(errsq/((double)1+sumsq), _state))); + } + if( ae_fp_greater(ae_sqrt(errsq/((double)1+sumsq), _state),ae_sqrt(ae_machineepsilon, _state)) ) + { + result = ae_false; + return result; + } + return result; +} + + +/************************************************************************* +This function estimates primal and dual step lengths (subject to step +decay parameter, which should be in [0,1] range). + +Current version returns same step lengths for primal and dual steps. + +INPUT PARAMETERS: + State - solver state + V0 - current point (we ignore one stored in State.Current) + VS - step direction + StepDecay - decay parameter, the step is multiplied by this + coefficient. 1.0 corresponds to full step + length being returned. Values in (0,1] range. + SeparateStep - separate step for primal and dual vars + +OUTPUT PARAMETERS: + AlphaP - primal step (after applying decay coefficient) + AlphaD - dual step (after applying decay coefficient) + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_ipm2computesteplength(const ipm2state* state, + const ipm2vars* current, + const ipm2vars* delta, + double* alpha, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t i; + + *alpha = 0.0; + + ntotal = state->ntotal; + *alpha = (double)(1); + for(i=0; i<=ntotal-1; i++) + { + + /* + * Primal + */ + if( delta->g.ptr.p_double[i]<0.0 ) + { + *alpha = safeminposrv(current->g.ptr.p_double[i], -delta->g.ptr.p_double[i], *alpha, _state); + } + if( delta->t.ptr.p_double[i]<0.0 ) + { + *alpha = safeminposrv(current->t.ptr.p_double[i], -delta->t.ptr.p_double[i], *alpha, _state); + } + + /* + * Dual + */ + if( delta->z.ptr.p_double[i]<0.0 ) + { + *alpha = safeminposrv(current->z.ptr.p_double[i], -delta->z.ptr.p_double[i], *alpha, _state); + } + if( delta->s.ptr.p_double[i]<0.0 ) + { + *alpha = safeminposrv(current->s.ptr.p_double[i], -delta->s.ptr.p_double[i], *alpha, _state); + } + } + *alpha = ipm2solver_steplengthdecay*(*alpha); +} + + +/************************************************************************* +Compute primal/dual errors and complementarity gap + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_computeerrors(const ipm2state* state, + const ipm2righthandside* rhs, + /* Real */ const ae_vector* currenthx, + /* Real */ const ae_vector* currentax, + /* Real */ const ae_vector* currentaty, + double* errp2, + double* errd2, + double* errpinf, + double* errdinf, + double* egap, + ae_state *_state) +{ + ae_int_t m; + ae_int_t ntotal; + ae_int_t cntp2; + ae_int_t cntd2; + double vtgt; + + *errp2 = 0.0; + *errd2 = 0.0; + *errpinf = 0.0; + *errdinf = 0.0; + *egap = 0.0; + + m = state->mraw; + ntotal = state->ntotal; + + /* + * Compute primal error + */ + cntp2 = 0; + *errp2 = (double)(0); + *errpinf = (double)(0); + *errp2 = *errp2+rdotv2(m, &rhs->ea, _state); + *errpinf = ae_maxreal(*errpinf, rmaxabsv(m, &rhs->ea, _state), _state); + cntp2 = cntp2+m; + *errp2 = *errp2+rdotv2(ntotal, &rhs->el, _state); + *errpinf = ae_maxreal(*errpinf, rmaxabsv(ntotal, &rhs->el, _state), _state); + cntp2 = cntp2+state->cntgz; + *errp2 = *errp2+rdotv2(ntotal, &rhs->eu, _state); + *errpinf = ae_maxreal(*errpinf, rmaxabsv(ntotal, &rhs->eu, _state), _state); + cntp2 = cntp2+state->cntts; + *errp2 = ae_sqrt(*errp2/coalesce((double)(cntp2), (double)(1), _state), _state); + + /* + * Compute dual error + */ + cntd2 = 0; + *errd2 = (double)(0); + *errdinf = (double)(0); + *errd2 = *errd2+rdotv2(ntotal, &rhs->ed, _state); + *errdinf = ae_maxreal(*errdinf, rmaxabsv(ntotal, &rhs->ed, _state), _state); + cntd2 = cntd2+m; + *errd2 = ae_sqrt(*errd2/coalesce((double)(cntd2), (double)(1), _state), _state); + + /* + * Compute complementarity gap + */ + vtgt = 0.5*rdotv(ntotal, currenthx, &state->current.x, _state)+rdotv(ntotal, &state->ce, &state->current.x, _state); + *egap = ipm2solver_varscomputecomplementaritygap(&state->current, _state)/(1.0+ae_fabs(vtgt, _state)); +} + + +/************************************************************************* +Evaluate progress so far, outputs trace data, if requested to do so. + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_traceprogress(ipm2state* state, + double muinit, + double alphaaff, + double alphafin, + ae_state *_state) +{ + ae_int_t naug; + ae_int_t mraw; + ae_int_t ntotal; + double errp2; + double errd2; + double errpinf; + double errdinf; + double errgap; + + + naug = state->naug; + mraw = state->mraw; + ntotal = state->ntotal; + if( !state->dotrace ) + { + return; + } + + /* + * Compute temporary products, RHS and errors + */ + ipm2solver_ipm2multiply(state, &state->current.x, &state->current.y, &state->tmphx, &state->tmpax, &state->tmpaty, _state); + ipm2solver_rhscomputeprimdual(state, &state->current, &state->tmphx, &state->tmpax, &state->tmpaty, &state->rhsprogress, _state); + ipm2solver_computeerrors(state, &state->rhsprogress, &state->tmphx, &state->tmpax, &state->tmpaty, &errp2, &errd2, &errpinf, &errdinf, &errgap, _state); + + /* + * Print high-level information + */ + ae_trace("--- step report ------------------------------------------------------------------------------------\n"); + ae_trace("> step information\n"); + ae_trace("mu_init = %0.3e (at the beginning)\n", + (double)(muinit)); + if( ae_fp_neq(alphafin,(double)(0)) ) + { + ae_trace("alphaA = %0.3e (initial affine scaling step)\n", + (double)(alphaaff)); + ae_trace("alphaR = %0.3e (refined step)\n", + (double)(alphafin)); + } + else + { + ae_trace("alpha = %0.3e\n", + (double)(alphaaff)); + } + ae_trace("mu_cur = %0.3e (after the step)\n", + (double)(ipm2solver_varscomputemu(state, &state->current, _state))); + ae_trace("> errors\n"); + ae_trace("errP = %0.3e (primal infeasibility, inf-norm)\n", + (double)(errpinf)); + ae_trace("errD = %0.3e (dual infeasibility, inf-norm)\n", + (double)(errdinf)); + ae_trace("errGap = %0.3e (complementarity gap)\n", + (double)(errgap)); + ae_trace("> current point information (inf-norm, x-suffix stands for N raw vars, a-suffix stands for M slacks)\n"); + ae_trace("|Xx|=%8.1e, |Xa|=%8.1e, |Gx|=%8.1e, |Tx|=%8.1e, |Ga|=%8.1e, |Ta|=%8.1e\n", + (double)(ipm2solver_maxabsrange(&state->current.x, 0, naug, _state)), + (double)(ipm2solver_maxabsrange(&state->current.x, naug, ntotal, _state)), + (double)(ipm2solver_maxabsrange(&state->current.g, 0, naug, _state)), + (double)(ipm2solver_maxabsrange(&state->current.t, 0, naug, _state)), + (double)(ipm2solver_maxabsrange(&state->current.g, naug, ntotal, _state)), + (double)(ipm2solver_maxabsrange(&state->current.t, naug, ntotal, _state))); + ae_trace(" |Y|=%8.1e, |Zx|=%8.1e, |Sx|=%8.1e, |Za|=%8.1e, |Sa|=%8.1e\n", + (double)(ipm2solver_maxabsrange(&state->current.y, 0, mraw, _state)), + (double)(ipm2solver_maxabsrange(&state->current.z, 0, naug, _state)), + (double)(ipm2solver_maxabsrange(&state->current.s, 0, naug, _state)), + (double)(ipm2solver_maxabsrange(&state->current.z, naug, ntotal, _state)), + (double)(ipm2solver_maxabsrange(&state->current.s, naug, ntotal, _state))); + + /* + * Print variable stats, if required + */ + if( state->dotrace ) + { + ae_trace("--- variable statistics ----------------------------------------------------------------------------\n"); + ae_trace("> smallest values for nonnegative vars\n"); + ae_trace("primal: minGx=%8.1e minTx=%8.1e minGa=%8.1e minTa=%8.1e\n", + (double)(ipm2solver_minnz(&state->current.g, 0, naug, _state)), + (double)(ipm2solver_minnz(&state->current.t, 0, naug, _state)), + (double)(ipm2solver_minnz(&state->current.g, naug, ntotal, _state)), + (double)(ipm2solver_minnz(&state->current.t, naug, ntotal, _state))); + ae_trace("dual: minZx=%8.1e minSx=%8.1e minGa=%8.1e minSa=%8.1e\n", + (double)(ipm2solver_minnz(&state->current.z, 0, naug, _state)), + (double)(ipm2solver_minnz(&state->current.s, 0, naug, _state)), + (double)(ipm2solver_minnz(&state->current.z, naug, ntotal, _state)), + (double)(ipm2solver_minnz(&state->current.s, naug, ntotal, _state))); + ae_trace("> min and max complementary slackness\n"); + ae_trace("min: GZx=%8.1e TSx=%8.1e GZa=%8.1e TSa=%8.1e\n", + (double)(ipm2solver_minprodnz(&state->current.g, &state->current.z, 0, naug, _state)), + (double)(ipm2solver_minprodnz(&state->current.t, &state->current.s, 0, naug, _state)), + (double)(ipm2solver_minprodnz(&state->current.g, &state->current.z, naug, ntotal, _state)), + (double)(ipm2solver_minprodnz(&state->current.t, &state->current.s, naug, ntotal, _state))); + ae_trace("max: GZx=%8.1e TSx=%8.1e GZa=%8.1e TSa=%8.1e\n", + (double)(ipm2solver_maxprodnz(&state->current.g, &state->current.z, 0, naug, _state)), + (double)(ipm2solver_maxprodnz(&state->current.t, &state->current.s, 0, naug, _state)), + (double)(ipm2solver_maxprodnz(&state->current.g, &state->current.z, naug, ntotal, _state)), + (double)(ipm2solver_maxprodnz(&state->current.t, &state->current.s, naug, ntotal, _state))); + } + ae_trace("\n"); +} + + +/************************************************************************* +Computes primal-dual right-hand side for a KKT system. + +GammaGZ and GammaTS are not computed by this function. + +INPUT PARAMETERS: + State - IPM state + Current - current point (used to compute RHS) + CurrentHX - precomputed H*Current.X + CurrentAX - precomputed A*Current.X + CurrentATY - precomputed A'*Current.Y + +OUTPUT PARAMETERS: + Rhs - RHS + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_rhscomputeprimdual(const ipm2state* state, + const ipm2vars* current, + /* Real */ const ae_vector* currenthx, + /* Real */ const ae_vector* currentax, + /* Real */ const ae_vector* currentaty, + ipm2righthandside* rhs, + ae_state *_state) +{ + ae_int_t ntotal; + ae_int_t m; + + + ntotal = state->ntotal; + m = state->mraw; + + /* + * ED + */ + rallocv(ntotal, &rhs->ed, _state); + if( ae_fp_greater(state->greg,(double)(0)) ) + { + rcopyv(ntotal, ¤t->x, &rhs->ed, _state); + raddv(ntotal, -1.0, &state->gregoriginx, &rhs->ed, _state); + rmergemulv(ntotal, &state->gregrhsx, &rhs->ed, _state); + raddv(ntotal, 1.0, &state->ce, &rhs->ed, _state); + } + else + { + rcopyv(ntotal, &state->ce, &rhs->ed, _state); + } + raddv(ntotal, -1.0, currentaty, &rhs->ed, _state); + raddv(ntotal, 1.0, currenthx, &rhs->ed, _state); + raddv(ntotal, -1.0, ¤t->z, &rhs->ed, _state); + raddv(ntotal, 1.0, ¤t->s, &rhs->ed, _state); + + /* + * EA + */ + rallocv(m, &rhs->ea, _state); + if( ae_fp_greater(state->greg,(double)(0)) ) + { + rcopyv(m, ¤t->y, &rhs->ea, _state); + raddv(m, -1.0, &state->gregoriginy, &rhs->ea, _state); + rmergemulv(m, &state->gregrhsy, &rhs->ea, _state); + raddv(m, -1.0, currentax, &rhs->ea, _state); + } + else + { + rcopymulv(m, -1.0, currentax, &rhs->ea, _state); + } + + /* + * EL + */ + rcopyallocv(ntotal, &state->bndlef, &rhs->el, _state); + raddv(ntotal, -1.0, ¤t->x, &rhs->el, _state); + raddv(ntotal, 1.0, ¤t->g, &rhs->el, _state); + rmergemulv(ntotal, &state->maskgz, &rhs->el, _state); + + /* + * EU + */ + rcopyallocv(ntotal, ¤t->x, &rhs->eu, _state); + raddv(ntotal, 1.0, ¤t->t, &rhs->eu, _state); + raddv(ntotal, -1.0, &state->bnduef, &rhs->eu, _state); + rmergemulv(ntotal, &state->maskts, &rhs->eu, _state); +} + + +/************************************************************************* +Recomputes GammaGZ/TS according to a predictor (affine scaling) step + +INPUT PARAMETERS: + State - IPM state + Current - current point (used to compute RHS) + MuTarget - target Mu (can be zero), + used to compute GammaGZ and GammaST + +OUTPUT PARAMETERS: + Rhs - RHS + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_rhsrecomputegammapredictor(const ipm2state* state, + const ipm2vars* current, + double mutarget, + ipm2righthandside* rhs, + ae_state *_state) +{ + ae_int_t ntotal; + + + ntotal = state->ntotal; + + /* + * GammaGZ + */ + rallocv(ntotal, &rhs->gammagz, _state); + rcopymulv(ntotal, mutarget, &state->maskgz, &rhs->gammagz, _state); + rnegmuladdv(ntotal, ¤t->g, ¤t->z, &rhs->gammagz, _state); + + /* + * GammaTS + */ + rallocv(ntotal, &rhs->gammats, _state); + rcopymulv(ntotal, mutarget, &state->maskts, &rhs->gammats, _state); + rnegmuladdv(ntotal, ¤t->t, ¤t->s, &rhs->gammats, _state); +} + + +/************************************************************************* +Recomputes GammaGZ/GammaTS part of RHS according to the Mehrotra corrector +heuristic. The rest of the right-hand side is unchanged. + +INPUT PARAMETERS: + State - IPM state + Current - current point (used to compute RHS) + MuTarget - target Mu, used to compute GammaGZ and GammaST + Delta - affine-scaling step produced by predictor stage + of the Mehrotra algorithm + +OUTPUT PARAMETERS: + Rhs - RHS.GammaGZ, Rhs.GammaTS are recomputed + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static void ipm2solver_rhsrecomputegammamehrotra(const ipm2state* state, + const ipm2vars* current, + double mutarget, + const ipm2vars* deltaaff, + ipm2righthandside* rhs, + ae_state *_state) +{ + ae_int_t ntotal; + + + ntotal = state->ntotal; + + /* + * GammaGZ + */ + rallocv(ntotal, &rhs->gammagz, _state); + rcopymulv(ntotal, mutarget, &state->maskgz, &rhs->gammagz, _state); + rnegmuladdv(ntotal, ¤t->g, ¤t->z, &rhs->gammagz, _state); + rnegmuladdv(ntotal, &deltaaff->g, &deltaaff->z, &rhs->gammagz, _state); + + /* + * GammaTS + */ + rallocv(ntotal, &rhs->gammats, _state); + rcopymulv(ntotal, mutarget, &state->maskts, &rhs->gammats, _state); + rnegmuladdv(ntotal, ¤t->t, ¤t->s, &rhs->gammats, _state); + rnegmuladdv(ntotal, &deltaaff->t, &deltaaff->s, &rhs->gammats, _state); +} + + +/************************************************************************* +Solves KKT system with given right-hand side + +INPUT PARAMETERS: + State - IPM state + Current - current point (beginning of the iteration) + RHS - right-hand side + +OUTPUT PARAMETERS: + Delta - solution + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool ipm2solver_reducedsystemsolve(ipm2reducedsystem* redsys, + ipm2state* sstate, + const ipm2vars* current, + const ipm2righthandside* rhs, + ipm2vars* delta, + ae_state *_state) +{ + ae_int_t naug; + ae_int_t ntotal; + ae_int_t m; + ae_bool result; + + + stimerstartcond(&sstate->timerothersolve, sstate->dotimers, _state); + naug = sstate->naug; + ntotal = sstate->ntotal; + m = sstate->mraw; + rallocv(ntotal+m, &redsys->extendedrhs, _state); + rcopymuladdv(ntotal, &redsys->d1, &rhs->gammats, &rhs->eu, &redsys->d2, _state); + rcopymuladdv(ntotal, &redsys->d5, &rhs->gammagz, &rhs->el, &redsys->d6, _state); + rcopymuladdv(ntotal, &redsys->d3, &redsys->d2, &rhs->ed, &redsys->extendedrhs, _state); + rnegmuladdv(ntotal, &redsys->d7, &redsys->d6, &redsys->extendedrhs, _state); + rcopyvx(m, &rhs->ea, 0, &redsys->extendedrhs, ntotal, _state); + + /* + * Reduce (NTotal+M)*(NTotal+M) extended system to a (N+M)*(N+M) compact one + */ + rallocv(m, &redsys->vm0, _state); + rsetallocv(m, 1.0, &redsys->um0, _state); + rcopyvx(m, &redsys->extendedeffdiagonal, naug, &redsys->vm0, 0, _state); + rmergedivv(m, &redsys->vm0, &redsys->um0, _state); + rcopyvx(m, &redsys->extendedrhs, naug, &redsys->vm0, 0, _state); + rallocv(m, &redsys->vm1, _state); + rcopymuladdv(m, &redsys->um0, &redsys->vm0, &rhs->ea, &redsys->vm1, _state); + rcopyvx(naug, &redsys->extendedrhs, 0, &redsys->compactrhs, 0, _state); + rcopyvx(m, &redsys->vm1, 0, &redsys->compactrhs, naug, _state); + stimerstartcond(&sstate->timerspsymmsolve, sstate->dotimers, _state); + spsymmsolve(&redsys->analysis, &redsys->compactrhs, _state); + stimerstopcond(&sstate->timerspsymmsolve, sstate->dotimers, _state); + + /* + * Perform backsubstitution + */ + raddvx(m, 1.0, &redsys->compactrhs, naug, &redsys->vm0, 0, _state); + rmergemulv(m, &redsys->um0, &redsys->vm0, _state); + rcopyvx(naug, &redsys->compactrhs, 0, &delta->x, 0, _state); + rcopyvx(m, &redsys->vm0, 0, &delta->x, naug, _state); + rcopyv(ntotal, &redsys->d2, &delta->s, _state); + raddv(ntotal, 1.0, &delta->x, &delta->s, _state); + rmergemulv(ntotal, &redsys->d3, &delta->s, _state); + rcopyv(ntotal, &redsys->d6, &delta->z, _state); + raddv(ntotal, -1.0, &delta->x, &delta->z, _state); + rmergemulv(ntotal, &redsys->d7, &delta->z, _state); + rcopynegmuladdv(ntotal, ¤t->t, &delta->s, &rhs->gammats, &delta->t, _state); + rcopynegmuladdv(ntotal, ¤t->g, &delta->z, &rhs->gammagz, &delta->g, _state); + rmergemulv(ntotal, &redsys->d1, &delta->t, _state); + rmergemulv(ntotal, &redsys->d5, &delta->g, _state); + rcopyvx(m, &redsys->compactrhs, naug, &delta->y, 0, _state); + stimerstopcond(&sstate->timerothersolve, sstate->dotimers, _state); + result = ae_true; + return result; +} + + +/************************************************************************* +Computes minimum nonzero value of the vector. Returns 0 if all components +are nonpositive. + +INPUT PARAMETERS: + X - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_minnz(/* Real */ const ae_vector* x, + ae_int_t n0, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=n0; i<=n1-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_minreal(result, x->ptr.p_double[i], _state); + } + } + } + return result; +} + + +/************************************************************************* +Computes minimum product of nonzero components. +Returns 0 if all components are nonpositive. + +INPUT PARAMETERS: + X - vector + Y - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_minprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n0, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=n0; i<=n1-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0))&&ae_fp_greater(y->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]*y->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_minreal(result, x->ptr.p_double[i]*y->ptr.p_double[i], _state); + } + } + } + return result; +} + + +/************************************************************************* +Computes maximum product of nonzero components. +Returns 0 if all components are nonpositive. + +INPUT PARAMETERS: + X - vector + Y - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_maxprodnz(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n0, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + nz = ae_false; + for(i=n0; i<=n1-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],(double)(0))&&ae_fp_greater(y->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = x->ptr.p_double[i]*y->ptr.p_double[i]; + nz = ae_true; + } + else + { + result = ae_maxreal(result, x->ptr.p_double[i]*y->ptr.p_double[i], _state); + } + } + } + return result; +} + + +/************************************************************************* +Computes maximum absolute value within a range of elements. +Debug function, not optimized. + +INPUT PARAMETERS: + X - vector + R0,R1 - range [R0,R1) + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double ipm2solver_maxabsrange(/* Real */ const ae_vector* x, + ae_int_t r0, + ae_int_t r1, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=r0; i<=r1-1; i++) + { + result = ae_maxreal(result, ae_fabs(x->ptr.p_double[i], _state), _state); + } + return result; +} + + +void _ipm2vars_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ipm2vars *p = (ipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); +} + + +void _ipm2vars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ipm2vars *dst = (ipm2vars*)_dst; + const ipm2vars *src = (const ipm2vars*)_src; + dst->ntotal = src->ntotal; + dst->m = src->m; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_vector_init_copy(&dst->t, &src->t, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); +} + + +void _ipm2vars_clear(void* _p) +{ + ipm2vars *p = (ipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + ae_vector_clear(&p->t); + ae_vector_clear(&p->y); + ae_vector_clear(&p->z); + ae_vector_clear(&p->s); +} + + +void _ipm2vars_destroy(void* _p) +{ + ipm2vars *p = (ipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->t); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->z); + ae_vector_destroy(&p->s); +} + + +void _ipm2reducedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ipm2reducedsystem *p = (ipm2reducedsystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_init(&p->compactkkt, _state, make_automatic); + ae_vector_init(&p->compactpriorities, 0, DT_INT, _state, make_automatic); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + ae_vector_init(&p->extendedrawdiagonal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->extendedeffdiagonal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->compacteffdiagonal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->extendedrhs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->compactrhs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->u0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->u1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->v0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->v1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->vm0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->vm1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->um0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d3, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d4, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d5, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d6, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d7, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rowdegrees, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->coldegrees, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpregrhs, 0, DT_REAL, _state, make_automatic); +} + + +void _ipm2reducedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ipm2reducedsystem *dst = (ipm2reducedsystem*)_dst; + const ipm2reducedsystem *src = (const ipm2reducedsystem*)_src; + _sparsematrix_init_copy(&dst->compactkkt, &src->compactkkt, _state, make_automatic); + ae_vector_init_copy(&dst->compactpriorities, &src->compactpriorities, _state, make_automatic); + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + ae_vector_init_copy(&dst->extendedrawdiagonal, &src->extendedrawdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->extendedeffdiagonal, &src->extendedeffdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->compacteffdiagonal, &src->compacteffdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->extendedrhs, &src->extendedrhs, _state, make_automatic); + ae_vector_init_copy(&dst->compactrhs, &src->compactrhs, _state, make_automatic); + ae_vector_init_copy(&dst->u0, &src->u0, _state, make_automatic); + ae_vector_init_copy(&dst->u1, &src->u1, _state, make_automatic); + ae_vector_init_copy(&dst->v0, &src->v0, _state, make_automatic); + ae_vector_init_copy(&dst->v1, &src->v1, _state, make_automatic); + ae_vector_init_copy(&dst->vm0, &src->vm0, _state, make_automatic); + ae_vector_init_copy(&dst->vm1, &src->vm1, _state, make_automatic); + ae_vector_init_copy(&dst->um0, &src->um0, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_vector_init_copy(&dst->d1, &src->d1, _state, make_automatic); + ae_vector_init_copy(&dst->d2, &src->d2, _state, make_automatic); + ae_vector_init_copy(&dst->d3, &src->d3, _state, make_automatic); + ae_vector_init_copy(&dst->d4, &src->d4, _state, make_automatic); + ae_vector_init_copy(&dst->d5, &src->d5, _state, make_automatic); + ae_vector_init_copy(&dst->d6, &src->d6, _state, make_automatic); + ae_vector_init_copy(&dst->d7, &src->d7, _state, make_automatic); + ae_vector_init_copy(&dst->rowdegrees, &src->rowdegrees, _state, make_automatic); + ae_vector_init_copy(&dst->coldegrees, &src->coldegrees, _state, make_automatic); + ae_vector_init_copy(&dst->tmpregrhs, &src->tmpregrhs, _state, make_automatic); +} + + +void _ipm2reducedsystem_clear(void* _p) +{ + ipm2reducedsystem *p = (ipm2reducedsystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_clear(&p->compactkkt); + ae_vector_clear(&p->compactpriorities); + _spcholanalysis_clear(&p->analysis); + ae_vector_clear(&p->extendedrawdiagonal); + ae_vector_clear(&p->extendedeffdiagonal); + ae_vector_clear(&p->compacteffdiagonal); + ae_vector_clear(&p->extendedrhs); + ae_vector_clear(&p->compactrhs); + ae_vector_clear(&p->u0); + ae_vector_clear(&p->u1); + ae_vector_clear(&p->v0); + ae_vector_clear(&p->v1); + ae_vector_clear(&p->vm0); + ae_vector_clear(&p->vm1); + ae_vector_clear(&p->um0); + ae_vector_clear(&p->d0); + ae_vector_clear(&p->d1); + ae_vector_clear(&p->d2); + ae_vector_clear(&p->d3); + ae_vector_clear(&p->d4); + ae_vector_clear(&p->d5); + ae_vector_clear(&p->d6); + ae_vector_clear(&p->d7); + ae_vector_clear(&p->rowdegrees); + ae_vector_clear(&p->coldegrees); + ae_vector_clear(&p->tmpregrhs); +} + + +void _ipm2reducedsystem_destroy(void* _p) +{ + ipm2reducedsystem *p = (ipm2reducedsystem*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_destroy(&p->compactkkt); + ae_vector_destroy(&p->compactpriorities); + _spcholanalysis_destroy(&p->analysis); + ae_vector_destroy(&p->extendedrawdiagonal); + ae_vector_destroy(&p->extendedeffdiagonal); + ae_vector_destroy(&p->compacteffdiagonal); + ae_vector_destroy(&p->extendedrhs); + ae_vector_destroy(&p->compactrhs); + ae_vector_destroy(&p->u0); + ae_vector_destroy(&p->u1); + ae_vector_destroy(&p->v0); + ae_vector_destroy(&p->v1); + ae_vector_destroy(&p->vm0); + ae_vector_destroy(&p->vm1); + ae_vector_destroy(&p->um0); + ae_vector_destroy(&p->d0); + ae_vector_destroy(&p->d1); + ae_vector_destroy(&p->d2); + ae_vector_destroy(&p->d3); + ae_vector_destroy(&p->d4); + ae_vector_destroy(&p->d5); + ae_vector_destroy(&p->d6); + ae_vector_destroy(&p->d7); + ae_vector_destroy(&p->rowdegrees); + ae_vector_destroy(&p->coldegrees); + ae_vector_destroy(&p->tmpregrhs); +} + + +void _ipm2righthandside_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ipm2righthandside *p = (ipm2righthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->gammagz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gammats, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ed, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ea, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->el, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eu, 0, DT_REAL, _state, make_automatic); +} + + +void _ipm2righthandside_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ipm2righthandside *dst = (ipm2righthandside*)_dst; + const ipm2righthandside *src = (const ipm2righthandside*)_src; + ae_vector_init_copy(&dst->gammagz, &src->gammagz, _state, make_automatic); + ae_vector_init_copy(&dst->gammats, &src->gammats, _state, make_automatic); + ae_vector_init_copy(&dst->ed, &src->ed, _state, make_automatic); + ae_vector_init_copy(&dst->ea, &src->ea, _state, make_automatic); + ae_vector_init_copy(&dst->el, &src->el, _state, make_automatic); + ae_vector_init_copy(&dst->eu, &src->eu, _state, make_automatic); +} + + +void _ipm2righthandside_clear(void* _p) +{ + ipm2righthandside *p = (ipm2righthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->gammagz); + ae_vector_clear(&p->gammats); + ae_vector_clear(&p->ed); + ae_vector_clear(&p->ea); + ae_vector_clear(&p->el); + ae_vector_clear(&p->eu); +} + + +void _ipm2righthandside_destroy(void* _p) +{ + ipm2righthandside *p = (ipm2righthandside*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->gammagz); + ae_vector_destroy(&p->gammats); + ae_vector_destroy(&p->ed); + ae_vector_destroy(&p->ea); + ae_vector_destroy(&p->el); + ae_vector_destroy(&p->eu); +} + + +void _ipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ipm2state *p = (ipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->userpermutation, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sclx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invsclx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xoriginx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ce, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsehe, _state, make_automatic); + ae_vector_init(&p->diagr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregoriginxuser, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregoriginyuser, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregrhsx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregrhsy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregoriginx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gregoriginy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndle, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndue, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndlef, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bnduef, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndle, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndue, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->rawae, _state, make_automatic); + ae_vector_init(&p->ascales, 0, DT_REAL, _state, make_automatic); + _ipm2vars_init(&p->current, _state, make_automatic); + _ipm2vars_init(&p->best, _state, make_automatic); + _ipm2vars_init(&p->delta, _state, make_automatic); + _ipm2vars_init(&p->corr, _state, make_automatic); + ae_vector_init(&p->hasgz, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasts, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->maskgz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->maskts, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currenthx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentaty, 0, DT_REAL, _state, make_automatic); + _ipm2righthandside_init(&p->rhstarget, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timeranalyze, _state, make_automatic); + _stimer_init(&p->timerfactorize, _state, make_automatic); + _stimer_init(&p->timerspsymmsolve, _state, make_automatic); + _stimer_init(&p->timerothersolve, _state, make_automatic); + _ipm2reducedsystem_init(&p->reducedsystem, _state, make_automatic); + _ipm2righthandside_init(&p->rhsprogress, _state, make_automatic); + ae_vector_init(&p->tmphx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpaty, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummyr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpr2, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmpa, _state, make_automatic); + ae_vector_init(&p->tmpal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpau, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmpsparse0, _state, make_automatic); + _sparsematrix_init(&p->tmplowerh, _state, make_automatic); + ae_matrix_init(&p->tmpccorr, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdcorr, 0, DT_REAL, _state, make_automatic); +} + + +void _ipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ipm2state *dst = (ipm2state*)_dst; + const ipm2state *src = (const ipm2state*)_src; + dst->nuser = src->nuser; + dst->naug = src->naug; + dst->ntotal = src->ntotal; + dst->hasuserpermutation = src->hasuserpermutation; + ae_vector_init_copy(&dst->userpermutation, &src->userpermutation, _state, make_automatic); + dst->epsp = src->epsp; + dst->epsd = src->epsd; + dst->epsgap = src->epsgap; + dst->maxipmits = src->maxipmits; + dst->islinear = src->islinear; + ae_vector_init_copy(&dst->sclx, &src->sclx, _state, make_automatic); + ae_vector_init_copy(&dst->invsclx, &src->invsclx, _state, make_automatic); + ae_vector_init_copy(&dst->xoriginx, &src->xoriginx, _state, make_automatic); + dst->targetscale = src->targetscale; + ae_vector_init_copy(&dst->ce, &src->ce, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsehe, &src->sparsehe, _state, make_automatic); + ae_vector_init_copy(&dst->diagr, &src->diagr, _state, make_automatic); + dst->isdiagonalh = src->isdiagonalh; + dst->greg = src->greg; + ae_vector_init_copy(&dst->gregoriginxuser, &src->gregoriginxuser, _state, make_automatic); + ae_vector_init_copy(&dst->gregoriginyuser, &src->gregoriginyuser, _state, make_automatic); + ae_vector_init_copy(&dst->gregdiag, &src->gregdiag, _state, make_automatic); + ae_vector_init_copy(&dst->gregrhsx, &src->gregrhsx, _state, make_automatic); + ae_vector_init_copy(&dst->gregrhsy, &src->gregrhsy, _state, make_automatic); + ae_vector_init_copy(&dst->gregoriginx, &src->gregoriginx, _state, make_automatic); + ae_vector_init_copy(&dst->gregoriginy, &src->gregoriginy, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndl, &src->rawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndu, &src->rawbndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndle, &src->bndle, _state, make_automatic); + ae_vector_init_copy(&dst->bndue, &src->bndue, _state, make_automatic); + ae_vector_init_copy(&dst->bndlef, &src->bndlef, _state, make_automatic); + ae_vector_init_copy(&dst->bnduef, &src->bnduef, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndle, &src->hasbndle, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndue, &src->hasbndue, _state, make_automatic); + _sparsematrix_init_copy(&dst->rawae, &src->rawae, _state, make_automatic); + ae_vector_init_copy(&dst->ascales, &src->ascales, _state, make_automatic); + dst->mraw = src->mraw; + _ipm2vars_init_copy(&dst->current, &src->current, _state, make_automatic); + _ipm2vars_init_copy(&dst->best, &src->best, _state, make_automatic); + _ipm2vars_init_copy(&dst->delta, &src->delta, _state, make_automatic); + _ipm2vars_init_copy(&dst->corr, &src->corr, _state, make_automatic); + ae_vector_init_copy(&dst->hasgz, &src->hasgz, _state, make_automatic); + ae_vector_init_copy(&dst->hasts, &src->hasts, _state, make_automatic); + ae_vector_init_copy(&dst->maskgz, &src->maskgz, _state, make_automatic); + ae_vector_init_copy(&dst->maskts, &src->maskts, _state, make_automatic); + dst->cntgz = src->cntgz; + dst->cntts = src->cntts; + ae_vector_init_copy(&dst->currenthx, &src->currenthx, _state, make_automatic); + ae_vector_init_copy(&dst->currentax, &src->currentax, _state, make_automatic); + ae_vector_init_copy(&dst->currentaty, &src->currentaty, _state, make_automatic); + _ipm2righthandside_init_copy(&dst->rhstarget, &src->rhstarget, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repncholesky = src->repncholesky; + dst->dotrace = src->dotrace; + dst->dotimers = src->dotimers; + dst->dodetailedtrace = src->dodetailedtrace; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timeranalyze, &src->timeranalyze, _state, make_automatic); + _stimer_init_copy(&dst->timerfactorize, &src->timerfactorize, _state, make_automatic); + _stimer_init_copy(&dst->timerspsymmsolve, &src->timerspsymmsolve, _state, make_automatic); + _stimer_init_copy(&dst->timerothersolve, &src->timerothersolve, _state, make_automatic); + _ipm2reducedsystem_init_copy(&dst->reducedsystem, &src->reducedsystem, _state, make_automatic); + _ipm2righthandside_init_copy(&dst->rhsprogress, &src->rhsprogress, _state, make_automatic); + ae_vector_init_copy(&dst->tmphx, &src->tmphx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpax, &src->tmpax, _state, make_automatic); + ae_vector_init_copy(&dst->tmpaty, &src->tmpaty, _state, make_automatic); + ae_vector_init_copy(&dst->dummyr, &src->dummyr, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpr2, &src->tmpr2, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpa, &src->tmpa, _state, make_automatic); + ae_vector_init_copy(&dst->tmpal, &src->tmpal, _state, make_automatic); + ae_vector_init_copy(&dst->tmpau, &src->tmpau, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpsparse0, &src->tmpsparse0, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmplowerh, &src->tmplowerh, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpccorr, &src->tmpccorr, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdcorr, &src->tmpdcorr, _state, make_automatic); +} + + +void _ipm2state_clear(void* _p) +{ + ipm2state *p = (ipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->userpermutation); + ae_vector_clear(&p->sclx); + ae_vector_clear(&p->invsclx); + ae_vector_clear(&p->xoriginx); + ae_vector_clear(&p->ce); + _sparsematrix_clear(&p->sparsehe); + ae_vector_clear(&p->diagr); + ae_vector_clear(&p->gregoriginxuser); + ae_vector_clear(&p->gregoriginyuser); + ae_vector_clear(&p->gregdiag); + ae_vector_clear(&p->gregrhsx); + ae_vector_clear(&p->gregrhsy); + ae_vector_clear(&p->gregoriginx); + ae_vector_clear(&p->gregoriginy); + ae_vector_clear(&p->rawbndl); + ae_vector_clear(&p->rawbndu); + ae_vector_clear(&p->bndle); + ae_vector_clear(&p->bndue); + ae_vector_clear(&p->bndlef); + ae_vector_clear(&p->bnduef); + ae_vector_clear(&p->hasbndle); + ae_vector_clear(&p->hasbndue); + _sparsematrix_clear(&p->rawae); + ae_vector_clear(&p->ascales); + _ipm2vars_clear(&p->current); + _ipm2vars_clear(&p->best); + _ipm2vars_clear(&p->delta); + _ipm2vars_clear(&p->corr); + ae_vector_clear(&p->hasgz); + ae_vector_clear(&p->hasts); + ae_vector_clear(&p->maskgz); + ae_vector_clear(&p->maskts); + ae_vector_clear(&p->currenthx); + ae_vector_clear(&p->currentax); + ae_vector_clear(&p->currentaty); + _ipm2righthandside_clear(&p->rhstarget); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timeranalyze); + _stimer_clear(&p->timerfactorize); + _stimer_clear(&p->timerspsymmsolve); + _stimer_clear(&p->timerothersolve); + _ipm2reducedsystem_clear(&p->reducedsystem); + _ipm2righthandside_clear(&p->rhsprogress); + ae_vector_clear(&p->tmphx); + ae_vector_clear(&p->tmpax); + ae_vector_clear(&p->tmpaty); + ae_vector_clear(&p->dummyr); + ae_vector_clear(&p->tmp0); + ae_matrix_clear(&p->tmpr2); + _sparsematrix_clear(&p->tmpa); + ae_vector_clear(&p->tmpal); + ae_vector_clear(&p->tmpau); + _sparsematrix_clear(&p->tmpsparse0); + _sparsematrix_clear(&p->tmplowerh); + ae_matrix_clear(&p->tmpccorr); + ae_vector_clear(&p->tmpdcorr); +} + + +void _ipm2state_destroy(void* _p) +{ + ipm2state *p = (ipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->userpermutation); + ae_vector_destroy(&p->sclx); + ae_vector_destroy(&p->invsclx); + ae_vector_destroy(&p->xoriginx); + ae_vector_destroy(&p->ce); + _sparsematrix_destroy(&p->sparsehe); + ae_vector_destroy(&p->diagr); + ae_vector_destroy(&p->gregoriginxuser); + ae_vector_destroy(&p->gregoriginyuser); + ae_vector_destroy(&p->gregdiag); + ae_vector_destroy(&p->gregrhsx); + ae_vector_destroy(&p->gregrhsy); + ae_vector_destroy(&p->gregoriginx); + ae_vector_destroy(&p->gregoriginy); + ae_vector_destroy(&p->rawbndl); + ae_vector_destroy(&p->rawbndu); + ae_vector_destroy(&p->bndle); + ae_vector_destroy(&p->bndue); + ae_vector_destroy(&p->bndlef); + ae_vector_destroy(&p->bnduef); + ae_vector_destroy(&p->hasbndle); + ae_vector_destroy(&p->hasbndue); + _sparsematrix_destroy(&p->rawae); + ae_vector_destroy(&p->ascales); + _ipm2vars_destroy(&p->current); + _ipm2vars_destroy(&p->best); + _ipm2vars_destroy(&p->delta); + _ipm2vars_destroy(&p->corr); + ae_vector_destroy(&p->hasgz); + ae_vector_destroy(&p->hasts); + ae_vector_destroy(&p->maskgz); + ae_vector_destroy(&p->maskts); + ae_vector_destroy(&p->currenthx); + ae_vector_destroy(&p->currentax); + ae_vector_destroy(&p->currentaty); + _ipm2righthandside_destroy(&p->rhstarget); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timeranalyze); + _stimer_destroy(&p->timerfactorize); + _stimer_destroy(&p->timerspsymmsolve); + _stimer_destroy(&p->timerothersolve); + _ipm2reducedsystem_destroy(&p->reducedsystem); + _ipm2righthandside_destroy(&p->rhsprogress); + ae_vector_destroy(&p->tmphx); + ae_vector_destroy(&p->tmpax); + ae_vector_destroy(&p->tmpaty); + ae_vector_destroy(&p->dummyr); + ae_vector_destroy(&p->tmp0); + ae_matrix_destroy(&p->tmpr2); + _sparsematrix_destroy(&p->tmpa); + ae_vector_destroy(&p->tmpal); + ae_vector_destroy(&p->tmpau); + _sparsematrix_destroy(&p->tmpsparse0); + _sparsematrix_destroy(&p->tmplowerh); + ae_matrix_destroy(&p->tmpccorr); + ae_vector_destroy(&p->tmpdcorr); +} + + +#endif +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initializes QP-IPM state and prepares it to receive quadratic/linear terms +and constraints. + +INPUT PARAMETERS: + State - solver state to be configured; previously allocated + memory is reused as much as possible + S - scale vector, array[N]: + * I-th element contains scale of I-th variable, + * S[I]>0 + XOrigin - origin term, array[N]. Can be zero. The solver solves + problem of the form + > + > min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + > + The terms A and b (as well as constraints) will be + specified later with separate calls. + N - total number of variables, N>=1 + TargetScale - target scale: + * >=0 + * recommended to be max(nrm2(C),nrm2(H+corr)) + * if zero, autodetected by performing several iterations + of a subspace eigensolver + + -- ALGLIB -- + Copyright 21.12.2022 by Bochkanov Sergey +*************************************************************************/ +void ecqpsolve(ecqpstate* state, + ae_int_t nuser, + const sparsematrix* lowerh, + /* Real */ const ae_vector* c, + const sparsematrix* sparsea, + /* Real */ const ae_vector* ae, + ae_int_t m, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_int_t nnza; + ae_int_t ntotal; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t offs; + double damp; + double reg; + double badchol; + double sumsq; + double errsq; + ae_int_t rfsidx; + ae_int_t facttype; + + *terminationtype = 0; + + ae_assert(nuser>=1, "ECQPInit: N<1", _state); + ae_assert(isfinitevector(c, nuser, _state), "ECQPInit: C contains infinite or NaN elements", _state); + ae_assert(m>=0, "ECQPInit: M<0", _state); + ae_assert(m==0||sparsea->matrixtype==1, "ECQPInit: non-CRS constraint matrix!", _state); + ae_assert(m==0||(sparsea->m==m&&sparsea->n==nuser), "ECQPInit: constraint matrix has incorrect size", _state); + ae_assert(ae->cnt>=m, "ECQPInit: AE is too short!", _state); + + /* + * Problem metrics, settings and type + */ + nnza = 0; + if( m>0 ) + { + nnza = sparsea->ridx.ptr.p_int[m]; + } + ntotal = nuser+m; + + /* + * Reports + */ + state->repiterationscount = 0; + state->repncholesky = 0; + + /* + * Trace + */ + state->dotrace = ae_is_trace_enabled("ECQP"); + state->dotimers = state->dotrace||ae_is_trace_enabled("TIMERS.ECQP"); + if( state->dotimers ) + { + stimerinit(&state->timertotal, _state); + stimerinit(&state->timeranalyze, _state); + stimerinit(&state->timerfactorize, _state); + stimerinit(&state->timerspsymmsolve, _state); + stimerinit(&state->timerothersolve, _state); + stimerstart(&state->timertotal, _state); + } + if( state->dotrace||state->dotimers ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// SPARSE ECQP SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Generate extended (N+M)x(N+M) matrix + */ + rallocv(ntotal, &state->effdiagonal, _state); + state->haug.matrixtype = 1; + state->haug.m = ntotal; + state->haug.n = ntotal; + iallocv(ntotal+1, &state->haug.ridx, _state); + ae_assert(lowerh->matrixtype==1, "ECQP: unexpected sparse matrix format", _state); + ae_assert(lowerh->m==nuser, "ECQP: unexpected sparse matrix size", _state); + ae_assert(lowerh->n==nuser, "ECQP: unexpected sparse matrix size", _state); + iallocv(lowerh->ridx.ptr.p_int[nuser]+nuser+nnza+nuser, &state->haug.idx, _state); + rallocv(lowerh->ridx.ptr.p_int[nuser]+nuser+nnza+nuser, &state->haug.vals, _state); + state->haug.ridx.ptr.p_int[0] = 0; + offs = 0; + vv = (double)(0); + for(i=0; i<=nuser-1; i++) + { + + /* + * Copy subdiagonal elements (if needed) + */ + j0 = lowerh->ridx.ptr.p_int[i]; + j1 = lowerh->didx.ptr.p_int[i]-1; + for(k=j0; k<=j1; k++) + { + v = lowerh->vals.ptr.p_double[k]; + state->haug.idx.ptr.p_int[offs] = lowerh->idx.ptr.p_int[k]; + state->haug.vals.ptr.p_double[offs] = v; + vv = vv+v; + offs = offs+1; + } + + /* + * Diagonal element is always copied + */ + v = (double)(0); + if( lowerh->uidx.ptr.p_int[i]!=lowerh->didx.ptr.p_int[i] ) + { + v = lowerh->vals.ptr.p_double[lowerh->didx.ptr.p_int[i]]; + } + state->haug.idx.ptr.p_int[offs] = i; + state->haug.vals.ptr.p_double[offs] = v; + state->effdiagonal.ptr.p_double[i] = v; + vv = vv+v; + offs = offs+1; + + /* + * Finalize row + */ + state->haug.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=m-1; i++) + { + offs = state->haug.ridx.ptr.p_int[nuser+i]; + j0 = sparsea->ridx.ptr.p_int[i]; + j1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->haug.idx.ptr.p_int[offs] = sparsea->idx.ptr.p_int[j]; + state->haug.vals.ptr.p_double[offs] = sparsea->vals.ptr.p_double[j]; + offs = offs+1; + } + state->haug.idx.ptr.p_int[offs] = nuser+i; + state->haug.vals.ptr.p_double[offs] = 0.0; + state->effdiagonal.ptr.p_double[nuser+i] = 0.0; + offs = offs+1; + state->haug.ridx.ptr.p_int[nuser+i+1] = offs; + } + ae_assert(ae_isfinite(vv, _state), "ECQPInit: LowerH contains infinite or NaN values!", _state); + ae_assert(offs<=state->haug.vals.cnt&&offs<=state->haug.idx.cnt, "ECQPInit: integrity check failed", _state); + sparsecreatecrsinplace(&state->haug, _state); + + /* + * Prepare sparse Cholesky + */ + facttype = 21; + isetallocv(state->haug.n, 0, &state->priorities, _state); + isetv(nuser, 1, &state->priorities, _state); + stimerstartcond(&state->timeranalyze, state->dotimers, _state); + if( !spsymmanalyze(&state->haug, &state->priorities, ecqpsolver_mupromote, 0, facttype, 3, 1, &state->analysis, _state) ) + { + ae_assert(ae_false, "ReducedSystemPowerUp: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } + stimerstopcond(&state->timeranalyze, state->dotimers, _state); + + /* + * Regularize until factorization succeeds + */ + rallocv(ntotal, &state->dampdiagonal, _state); + damp = ae_sqrt(ae_machineepsilon, _state); + badchol = 1.0E50; + for(;;) + { + for(i=0; i<=nuser-1; i++) + { + state->dampdiagonal.ptr.p_double[i] = state->effdiagonal.ptr.p_double[i]+damp; + } + for(i=nuser; i<=ntotal-1; i++) + { + state->dampdiagonal.ptr.p_double[i] = state->effdiagonal.ptr.p_double[i]-damp; + } + spsymmreloaddiagonal(&state->analysis, &state->dampdiagonal, _state); + spsymmsetmodificationstrategy(&state->analysis, 1, ae_machineepsilon, badchol, 0.0, 0.0, _state); + stimerstartcond(&state->timerfactorize, state->dotimers, _state); + if( !spsymmfactorize(&state->analysis, _state) ) + { + stimerstopcond(&state->timerfactorize, state->dotimers, _state); + damp = (double)10*damp; + if( state->dotrace ) + { + ae_trace("> cholesky factorization failed, increasing damping to %0.2e\n", + (double)(damp)); + } + continue; + } + stimerstopcond(&state->timerfactorize, state->dotimers, _state); + spsymmdiagerr(&state->analysis, &sumsq, &errsq, _state); + if( ae_fp_greater(ae_sqrt(errsq/((double)1+sumsq), _state),(double)100*ae_sqrt(ae_machineepsilon, _state)) ) + { + damp = (double)10*damp; + if( state->dotrace ) + { + ae_trace("LDLT-diag-err= %0.3e (diagonal reproduction error), increasing damping to %0.2e\n", + (double)(ae_sqrt(errsq/((double)1+sumsq), _state)), + (double)(damp)); + } + continue; + } + if( state->dotrace ) + { + ae_trace("> factorization accepted\n"); + } + break; + } + + /* + * Solve + */ + stimerstartcond(&state->timerothersolve, state->dotimers, _state); + reg = (double)1000*ae_machineepsilon; + rallocv(ntotal, &state->bx, _state); + rcopymulv(nuser, -1.0, c, &state->bx, _state); + rcopyvx(m, ae, 0, &state->bx, nuser, _state); + fblsgmrescreate(&state->bx, ntotal, ae_minint(25, ntotal, _state), &state->gmressolver, _state); + state->gmressolver.epsres = (double)100*ae_machineepsilon; + state->gmressolver.epsred = 0.999999; + rfsidx = 0; + while(fblsgmresiteration(&state->gmressolver, _state)) + { + if( state->dotrace ) + { + ae_trace(">> GMRES iteration %2d: %0.2e relative residual\n", + (int)(rfsidx), + (double)(state->gmressolver.reprelres)); + } + for(i=0; i<=nuser-1; i++) + { + state->gmressolver.ax.ptr.p_double[i] = reg*state->gmressolver.x.ptr.p_double[i]; + } + for(i=nuser; i<=ntotal-1; i++) + { + state->gmressolver.ax.ptr.p_double[i] = -reg*state->gmressolver.x.ptr.p_double[i]; + } + rcopyallocv(ntotal, &state->gmressolver.x, &state->dx, _state); + stimerstartcond(&state->timerspsymmsolve, state->dotimers, _state); + spsymmsolve(&state->analysis, &state->dx, _state); + stimerstopcond(&state->timerspsymmsolve, state->dotimers, _state); + sparsesmv(lowerh, ae_false, &state->dx, &state->dh, _state); + raddvx(nuser, 1.0, &state->dh, 0, &state->gmressolver.ax, 0, _state); + if( m>0 ) + { + sparsegemv(sparsea, 1.0, 1, &state->dx, nuser, 1.0, &state->gmressolver.ax, 0, _state); + sparsegemv(sparsea, 1.0, 0, &state->dx, 0, 1.0, &state->gmressolver.ax, nuser, _state); + } + rfsidx = rfsidx+1; + } + stimerstartcond(&state->timerspsymmsolve, state->dotimers, _state); + spsymmsolve(&state->analysis, &state->gmressolver.xs, _state); + stimerstopcond(&state->timerspsymmsolve, state->dotimers, _state); + stimerstopcond(&state->timerothersolve, state->dotimers, _state); + rallocv(nuser, xs, _state); + rallocv(m, laglc, _state); + rcopyvx(nuser, &state->gmressolver.xs, 0, xs, 0, _state); + rcopyvx(m, &state->gmressolver.xs, nuser, laglc, 0, _state); + state->repiterationscount = 1; + state->repncholesky = 1; + *terminationtype = 1; + + /* + * Timers and reports + */ + if( state->dotimers ) + { + stimerstop(&state->timertotal, _state); + ae_trace("\n> printing internal timers (can be zero when run in OS-agnostic mode)\n"); + ae_trace("> total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("> * in analyze: %10.1f ms\n", + (double)(stimergetms(&state->timeranalyze, _state))); + ae_trace("> * in factorize: %10.1f ms\n", + (double)(stimergetms(&state->timerfactorize, _state))); + ae_trace("> * in spsymmsolve(): %10.1f ms\n", + (double)(stimergetms(&state->timerspsymmsolve, _state))); + ae_trace("> * in other solve: %10.1f ms\n", + (double)(stimergetms(&state->timerothersolve, _state)-stimergetms(&state->timerspsymmsolve, _state))); + } +} + + +void _ecqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ecqpstate *p = (ecqpstate*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_init(&p->haug, _state, make_automatic); + ae_vector_init(&p->priorities, 0, DT_INT, _state, make_automatic); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + ae_vector_init(&p->effdiagonal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dampdiagonal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dh, 0, DT_REAL, _state, make_automatic); + _fblsgmresstate_init(&p->gmressolver, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timeranalyze, _state, make_automatic); + _stimer_init(&p->timerfactorize, _state, make_automatic); + _stimer_init(&p->timerspsymmsolve, _state, make_automatic); + _stimer_init(&p->timerothersolve, _state, make_automatic); +} + + +void _ecqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ecqpstate *dst = (ecqpstate*)_dst; + const ecqpstate *src = (const ecqpstate*)_src; + _sparsematrix_init_copy(&dst->haug, &src->haug, _state, make_automatic); + ae_vector_init_copy(&dst->priorities, &src->priorities, _state, make_automatic); + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + ae_vector_init_copy(&dst->effdiagonal, &src->effdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->dampdiagonal, &src->dampdiagonal, _state, make_automatic); + ae_vector_init_copy(&dst->dx, &src->dx, _state, make_automatic); + ae_vector_init_copy(&dst->bx, &src->bx, _state, make_automatic); + ae_vector_init_copy(&dst->dh, &src->dh, _state, make_automatic); + _fblsgmresstate_init_copy(&dst->gmressolver, &src->gmressolver, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repncholesky = src->repncholesky; + dst->dotrace = src->dotrace; + dst->dotimers = src->dotimers; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timeranalyze, &src->timeranalyze, _state, make_automatic); + _stimer_init_copy(&dst->timerfactorize, &src->timerfactorize, _state, make_automatic); + _stimer_init_copy(&dst->timerspsymmsolve, &src->timerspsymmsolve, _state, make_automatic); + _stimer_init_copy(&dst->timerothersolve, &src->timerothersolve, _state, make_automatic); +} + + +void _ecqpstate_clear(void* _p) +{ + ecqpstate *p = (ecqpstate*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_clear(&p->haug); + ae_vector_clear(&p->priorities); + _spcholanalysis_clear(&p->analysis); + ae_vector_clear(&p->effdiagonal); + ae_vector_clear(&p->dampdiagonal); + ae_vector_clear(&p->dx); + ae_vector_clear(&p->bx); + ae_vector_clear(&p->dh); + _fblsgmresstate_clear(&p->gmressolver); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timeranalyze); + _stimer_clear(&p->timerfactorize); + _stimer_clear(&p->timerspsymmsolve); + _stimer_clear(&p->timerothersolve); +} + + +void _ecqpstate_destroy(void* _p) +{ + ecqpstate *p = (ecqpstate*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_destroy(&p->haug); + ae_vector_destroy(&p->priorities); + _spcholanalysis_destroy(&p->analysis); + ae_vector_destroy(&p->effdiagonal); + ae_vector_destroy(&p->dampdiagonal); + ae_vector_destroy(&p->dx); + ae_vector_destroy(&p->bx); + ae_vector_destroy(&p->dh); + _fblsgmresstate_destroy(&p->gmressolver); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timeranalyze); + _stimer_destroy(&p->timerfactorize); + _stimer_destroy(&p->timerspsymmsolve); + _stimer_destroy(&p->timerothersolve); +} + + +#endif +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Get recommended initial value for mu. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +double gipmgetinitprimdual(ae_state *_state) +{ + double result; + + + result = ae_sqrt(gipm_initmu, _state); + return result; +} + + +/************************************************************************* +Initialize GIPM structure + +NOTES: + + FScales - objective/constraint scales, used merely for + reporting + DoQNReport - array[MFlex+MHard+1], flags for quasi-Newton + reports. + + If DoQNReport[i] is true, then (I-1)-th constraint + is included into report sent with the code 1004. + The first element corresponds to the objective. + Ignored when IsFirstOrder=False + +IMPORTANT: equality box constraints on X are NOT supported! you have to + reformulate your problem in order to avoid equality constraints + on primal variables. Box constraints on them should be have + width bounded away from zero. + Nonlinear equality constraints are supported. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gipminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x0, + ae_int_t nraw, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t mflex, + ae_int_t mhard, + /* Real */ const ae_vector* fscales, + /* Boolean */ const ae_vector* doqnreport, + double eps, + ae_int_t maxits, + ae_bool isfirstorder, + gipmstate* state, + ae_state *_state) +{ + ae_int_t i; + double eqeps; + + + state->nraw = nraw; + state->mflex = mflex; + state->mhard = mhard; + state->mudependent = ae_false; + state->isfirstorder = isfirstorder; + eqeps = ae_maxreal(1.0E-3*eps, 1.0E3*ae_machineepsilon, _state); + if( isfirstorder ) + { + rsetallocv(1+mflex+mhard, 0.0, &state->qnmask, _state); + state->isqnmasknonzero = ae_false; + for(i=0; i<=mflex+mhard; i++) + { + if( doqnreport->ptr.p_bool[i] ) + { + state->qnmask.ptr.p_double[i] = 1.0; + state->isqnmasknonzero = ae_true; + } + } + } + + /* + * Save initial point for further processing + */ + rcopyallocv(nraw, x0, &state->x0, _state); + + /* + * Function scales + */ + rcopyallocv(1+mflex+mhard, fscales, &state->fscales, _state); + + /* + * Prepare RCOMM-V2 protocol + */ + ae_vector_set_length(&state->rstate.ia, 13+1, _state); + ae_vector_set_length(&state->rstate.ba, 6+1, _state); + ae_vector_set_length(&state->rstate.ra, 30+1, _state); + state->rstate.stage = -1; + + /* + * Box constraints: convert from the original form into a slack representation + */ + bsetallocv(mflex, ae_false, &state->isequality, _state); + rsetallocv(nraw+mflex, _state->v_neginf, &state->bndlx, _state); + bsetallocv(nraw+mflex, ae_false, &state->hasbndlx, _state); + rsetallocv(nraw+mflex+mhard, _state->v_posinf, &state->bndux, _state); + bsetallocv(nraw+mflex+mhard, ae_false, &state->hasbndux, _state); + for(i=0; i<=nraw-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + state->bndlx.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndlx.ptr.p_bool[i] = ae_true; + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + state->bndux.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndux.ptr.p_bool[i] = ae_true; + } + if( state->hasbndlx.ptr.p_bool[i]&&state->hasbndux.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less(state->bndlx.ptr.p_double[i],state->bndux.ptr.p_double[i]), "GIPM: equality box constraints on primal variables are NOT supported by design", _state); + } + } + for(i=0; i<=mflex-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isfinite(nu->ptr.p_double[i], _state), "GIPM: one of general constraints has both bounds absent", _state); + if( ae_isfinite(nl->ptr.p_double[i], _state) ) + { + state->bndlx.ptr.p_double[nraw+i] = nl->ptr.p_double[i]; + state->hasbndlx.ptr.p_bool[nraw+i] = ae_true; + } + if( ae_isfinite(nu->ptr.p_double[i], _state) ) + { + state->bndux.ptr.p_double[nraw+i] = nu->ptr.p_double[i]; + state->hasbndux.ptr.p_bool[nraw+i] = ae_true; + } + if( state->hasbndlx.ptr.p_bool[nraw+i]&&state->hasbndux.ptr.p_bool[nraw+i] ) + { + ae_assert(ae_fp_less_eq(state->bndlx.ptr.p_double[nraw+i],state->bndux.ptr.p_double[nraw+i]), "GIPM: one of nonlinear constraints has incompatible range", _state); + if( ae_fp_less_eq(ae_fabs(state->bndlx.ptr.p_double[nraw+i]-state->bndux.ptr.p_double[nraw+i], _state),eqeps) ) + { + state->isequality.ptr.p_bool[i] = ae_true; + } + } + } + for(i=mflex; i<=mflex+mhard-1; i++) + { + ae_assert(ae_isneginf(nl->ptr.p_double[i], _state)&&ae_isfinite(nu->ptr.p_double[i], _state), "GIPM: one of hard constraints has infinite upper bound or has finite upper bound", _state); + state->bndux.ptr.p_double[nraw+i] = nu->ptr.p_double[i]; + state->hasbndux.ptr.p_bool[nraw+i] = ae_true; + } + + /* + * Stopping criteria and settings + */ + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "GIPM: integrity check 9756 failed", _state); + state->eps = coalesce(eps, (double)10*ae_sqrt(ae_machineepsilon, _state), _state); + state->maxits = maxits; + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repiterationscount = 0; + + /* + * Trace status + */ + state->dolaconictrace = ae_is_trace_enabled("GENIPM.LACONIC"); + state->dotrace = ae_is_trace_enabled("GENIPM")&&!state->dolaconictrace; + state->dodetailedtrace = state->dotrace&&ae_is_trace_enabled("GENIPM.DETAILED"); +} + + +/************************************************************************* +This function performs actual processing for GIPM algorithm. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +ae_bool gipmiteration(gipmstate* state, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t nraw; + ae_int_t mtotal; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t nxf; + ae_int_t nxh; + ae_int_t i; + ae_int_t rfsidx; + ae_int_t j; + double v; + double vv; + double v2; + double alpha; + double f0; + double f1; + double p0; + double p1; + double cmpl0; + double cmpl1; + double gnrm; + ae_int_t innerloopstart; + double initprimdual; + double eprim; + double edual; + double ecmpl; + ae_bool firstouteriteration; + ae_bool infinitiesdetected; + ae_bool failedtorecoverfrominfinities; + ae_bool unboundednesssuspected; + ae_bool lambdafound; + ae_bool accepted; + ae_bool violated; + double mumin; + double curbigval; + double curbiggrowth; + ae_int_t smalltrials; + double rhs0; + double rhsk; + double lastcheckpointp; + double lastcheckpointd; + double lastcheckpointc; + ae_int_t lastcheckpointidx; + ae_int_t btits; + double lastprim; + double lastdual; + double lastcmpl; + ae_int_t goodinnerits; + double maxabsf; + double minmeritv0; + double curmeritv0; + double merit0; + double merit1; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + nraw = state->rstate.ia.ptr.p_int[0]; + mtotal = state->rstate.ia.ptr.p_int[1]; + mflex = state->rstate.ia.ptr.p_int[2]; + mhard = state->rstate.ia.ptr.p_int[3]; + nxf = state->rstate.ia.ptr.p_int[4]; + nxh = state->rstate.ia.ptr.p_int[5]; + i = state->rstate.ia.ptr.p_int[6]; + rfsidx = state->rstate.ia.ptr.p_int[7]; + j = state->rstate.ia.ptr.p_int[8]; + innerloopstart = state->rstate.ia.ptr.p_int[9]; + smalltrials = state->rstate.ia.ptr.p_int[10]; + lastcheckpointidx = state->rstate.ia.ptr.p_int[11]; + btits = state->rstate.ia.ptr.p_int[12]; + goodinnerits = state->rstate.ia.ptr.p_int[13]; + firstouteriteration = state->rstate.ba.ptr.p_bool[0]; + infinitiesdetected = state->rstate.ba.ptr.p_bool[1]; + failedtorecoverfrominfinities = state->rstate.ba.ptr.p_bool[2]; + unboundednesssuspected = state->rstate.ba.ptr.p_bool[3]; + lambdafound = state->rstate.ba.ptr.p_bool[4]; + accepted = state->rstate.ba.ptr.p_bool[5]; + violated = state->rstate.ba.ptr.p_bool[6]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + v2 = state->rstate.ra.ptr.p_double[2]; + alpha = state->rstate.ra.ptr.p_double[3]; + f0 = state->rstate.ra.ptr.p_double[4]; + f1 = state->rstate.ra.ptr.p_double[5]; + p0 = state->rstate.ra.ptr.p_double[6]; + p1 = state->rstate.ra.ptr.p_double[7]; + cmpl0 = state->rstate.ra.ptr.p_double[8]; + cmpl1 = state->rstate.ra.ptr.p_double[9]; + gnrm = state->rstate.ra.ptr.p_double[10]; + initprimdual = state->rstate.ra.ptr.p_double[11]; + eprim = state->rstate.ra.ptr.p_double[12]; + edual = state->rstate.ra.ptr.p_double[13]; + ecmpl = state->rstate.ra.ptr.p_double[14]; + mumin = state->rstate.ra.ptr.p_double[15]; + curbigval = state->rstate.ra.ptr.p_double[16]; + curbiggrowth = state->rstate.ra.ptr.p_double[17]; + rhs0 = state->rstate.ra.ptr.p_double[18]; + rhsk = state->rstate.ra.ptr.p_double[19]; + lastcheckpointp = state->rstate.ra.ptr.p_double[20]; + lastcheckpointd = state->rstate.ra.ptr.p_double[21]; + lastcheckpointc = state->rstate.ra.ptr.p_double[22]; + lastprim = state->rstate.ra.ptr.p_double[23]; + lastdual = state->rstate.ra.ptr.p_double[24]; + lastcmpl = state->rstate.ra.ptr.p_double[25]; + maxabsf = state->rstate.ra.ptr.p_double[26]; + minmeritv0 = state->rstate.ra.ptr.p_double[27]; + curmeritv0 = state->rstate.ra.ptr.p_double[28]; + merit0 = state->rstate.ra.ptr.p_double[29]; + merit1 = state->rstate.ra.ptr.p_double[30]; + } + else + { + nraw = 359; + mtotal = -58; + mflex = -919; + mhard = -909; + nxf = 81; + nxh = 255; + i = 74; + rfsidx = -788; + j = 809; + innerloopstart = 205; + smalltrials = -838; + lastcheckpointidx = 939; + btits = -526; + goodinnerits = 763; + firstouteriteration = ae_true; + infinitiesdetected = ae_false; + failedtorecoverfrominfinities = ae_false; + unboundednesssuspected = ae_false; + lambdafound = ae_false; + accepted = ae_false; + violated = ae_true; + v = -536.0; + vv = 487.0; + v2 = -115.0; + alpha = 886.0; + f0 = 346.0; + f1 = -722.0; + p0 = -413.0; + p1 = -461.0; + cmpl0 = 927.0; + cmpl1 = 201.0; + gnrm = 922.0; + initprimdual = -154.0; + eprim = 306.0; + edual = -1011.0; + ecmpl = 951.0; + mumin = -463.0; + curbigval = 88.0; + curbiggrowth = -861.0; + rhs0 = -678.0; + rhsk = -731.0; + lastcheckpointp = -675.0; + lastcheckpointd = -763.0; + lastcheckpointc = -233.0; + lastprim = -936.0; + lastdual = -279.0; + lastcmpl = 94.0; + maxabsf = -812.0; + minmeritv0 = 427.0; + curmeritv0 = 178.0; + merit0 = -819.0; + merit1 = -826.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + + /* + * Routine body + */ + nraw = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + mtotal = mflex+mhard; + nxf = state->nraw+state->mflex; + nxh = state->nraw+state->mflex+state->mhard; + + /* + * Prepare debug timers and temporaries + */ + stimerinit(&state->timertotal, _state); + ae_nxpool_alloc(&state->mnx1pool, ae_maxint(nxh, mtotal, _state)+1, _state); + stimerstart(&state->timertotal, _state); + + /* + * Trace output (if needed) + */ + if( state->dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// NONLINEAR IPM SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(nraw)); + ae_trace("M = %6d (incl %0d non-relaxable inequalities)\n", + (int)(mflex+mhard), + (int)(mhard)); + } + + /* + * Prepare quantities used during iterations + */ + rsetallocv(nraw, 0.0, &state->elp, _state); + rsetallocv(nraw, 0.0, &state->eup, _state); + rsetallocv(mflex, 0.0, &state->els, _state); + rsetallocv(mflex, 0.0, &state->eus, _state); + for(i=0; i<=nxf-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + if( ielp.ptr.p_double[i] = (double)(1); + } + if( i>=nraw&&!state->isequality.ptr.p_bool[i-nraw] ) + { + state->els.ptr.p_double[i-nraw] = (double)(1); + } + } + if( state->hasbndux.ptr.p_bool[i] ) + { + if( ieup.ptr.p_double[i] = (double)(1); + } + if( i>=nraw&&!state->isequality.ptr.p_bool[i-nraw] ) + { + state->eus.ptr.p_double[i-nraw] = (double)(1); + } + } + } + rsetallocv(nxf, -ae_sqrt(ae_maxrealnumber, _state), &state->finitebndlx, _state); + rsetallocv(nxh, ae_sqrt(ae_maxrealnumber, _state), &state->finitebndux, _state); + for(i=0; i<=nxf-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + state->finitebndlx.ptr.p_double[i] = state->bndlx.ptr.p_double[i]; + } + if( state->hasbndux.ptr.p_bool[i] ) + { + state->finitebndux.ptr.p_double[i] = state->bndux.ptr.p_double[i]; + } + } + for(i=nxf; i<=nxh-1; i++) + { + state->finitebndux.ptr.p_double[i] = state->bndux.ptr.p_double[i]; + } + gipm_safeboundsfromfinitetightened(state, _state); + + /* + * Choose initial mu + */ + state->mu = gipm_initmu; + mumin = ae_maxreal(0.0001*state->eps/((double)1+gipm_relaxfactor), (double)100*ae_machineepsilon, _state); + + /* + * Initial point: perform RCOMM request, prepare the initial point + */ + initprimdual = gipmgetinitprimdual(_state); + gipm_varsinitbyzero(&state->current, nraw, mflex, mhard, _state); + gipm_varsinitbyzero(&state->delta, nraw, mflex, mhard, _state); + gipm_varsinitbyzero(&state->corr, nraw, mflex, mhard, _state); + for(i=0; i<=nraw-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + ae_assert(ae_fp_greater(state->x0.ptr.p_double[i],state->bndlx.ptr.p_double[i]), "GIPM: the initial point is not strictly feasible wrt box constraints", _state); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less(state->x0.ptr.p_double[i],state->bndux.ptr.p_double[i]), "GIPM: the initial point is not strictly feasible wrt box constraints", _state); + } + } + rcopyv(nraw, &state->x0, &state->current.xp, _state); + rmergemaxv(nraw, &state->safeguardbndlp, &state->current.xp, _state); + rmergeminv(nraw, &state->safeguardbndup, &state->current.xp, _state); + for(i=0; i<=mflex-1; i++) + { + if( state->hasbndlx.ptr.p_bool[nraw+i]&&!state->hasbndux.ptr.p_bool[nraw+i] ) + { + state->current.yp.ptr.p_double[i] = -initprimdual; + } + if( state->hasbndux.ptr.p_bool[nraw+i]&&!state->hasbndlx.ptr.p_bool[nraw+i] ) + { + state->current.yp.ptr.p_double[i] = initprimdual; + } + } + rsetv(mhard, initprimdual, &state->current.yv, _state); + state->requesttype = 1; + state->querymu = state->mu; + rallocv(nxh, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + vfjinitfromsparse(&state->current.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->currentfj, _state); + for(i=0; i<=nraw-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + state->current.zlp.ptr.p_double[i] = boundval(gipm_initmu/(state->current.xp.ptr.p_double[i]-state->bndlx.ptr.p_double[i]), (double)100*ae_sqrt(ae_machineepsilon, _state), initprimdual, _state); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + state->current.zup.ptr.p_double[i] = boundval(gipm_initmu/(state->bndux.ptr.p_double[i]-state->current.xp.ptr.p_double[i]), (double)100*ae_sqrt(ae_machineepsilon, _state), initprimdual, _state); + } + } + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + state->current.xs.ptr.p_double[i] = state->replyfi.ptr.p_double[1+i]; + if( state->hasbndlx.ptr.p_bool[nraw+i] ) + { + state->current.gl.ptr.p_double[i] = ae_maxreal(initprimdual, state->current.xs.ptr.p_double[i]-state->bndlx.ptr.p_double[nraw+i], _state); + state->current.zls.ptr.p_double[i] = boundval(gipm_initmu/state->current.gl.ptr.p_double[i], (double)100*ae_sqrt(ae_machineepsilon, _state), initprimdual, _state); + } + if( state->hasbndux.ptr.p_bool[nraw+i] ) + { + state->current.gu.ptr.p_double[i] = ae_maxreal(initprimdual, state->bndux.ptr.p_double[nraw+i]-state->current.xs.ptr.p_double[i], _state); + state->current.zus.ptr.p_double[i] = boundval(gipm_initmu/state->current.gu.ptr.p_double[i], (double)100*ae_sqrt(ae_machineepsilon, _state), initprimdual, _state); + } + } + } + for(i=0; i<=mhard-1; i++) + { + ae_assert(ae_fp_less(state->replyfi.ptr.p_double[1+mflex+i],state->finitebndux.ptr.p_double[nxf+i]), "GIPM: the initial point is infeasible with respect to hard inequality constraints", _state); + state->current.yv.ptr.p_double[i] = boundval(gipm_initmu/(state->finitebndux.ptr.p_double[nxf+i]-state->replyfi.ptr.p_double[1+mflex+i]), (double)100*ae_sqrt(ae_machineepsilon, _state), initprimdual, _state); + } + state->nrmx0 = rmaxabsv(nraw, &state->current.xp, _state); + state->absf0 = ae_fabs(state->replyfi.ptr.p_double[0], _state); + + /* + * Outer iterations + */ + curbigval = gipm_initbigval; + curbiggrowth = gipm_initbiggrowth; + state->lambdav = 0.0; + state->lambdadecay = 0.0; + state->besterr = ae_maxrealnumber; + gipm_varscopy(&state->current, &state->best, _state); + infinitiesdetected = ae_false; + failedtorecoverfrominfinities = ae_false; + lambdafound = ae_false; + state->subsequentfactfailures = 0; + firstouteriteration = ae_true; + gipm_barrierpenaltyandcmplerror(state, &state->current, &state->currentfj, state->mu, &f0, &p0, &cmpl0, _state); + lastprim = ae_sqrt(ae_maxrealnumber, _state); + lastdual = lastprim; + lastcmpl = lastprim; + gnrm = (double)(1); + maxabsf = (double)(0); +lbl_11: + if( ae_false ) + { + goto lbl_12; + } + + /* + * Reset parameters and flags at the beginning of inner iterations + */ + unboundednesssuspected = ae_false; + lastcheckpointp = ae_maxrealnumber; + lastcheckpointd = ae_maxrealnumber; + lastcheckpointc = ae_maxrealnumber; + lastcheckpointidx = state->repiterationscount; + innerloopstart = state->repiterationscount; + state->rhsstagnationcounter = 0; + goodinnerits = 0; + if( ae_fp_greater_eq(state->lambdav,gipm_lambdamax) ) + { + if( state->dotrace ) + { + ae_trace("> regularization is at maximum, resetting to 1.0\n"); + } + state->lambdav = (double)(1); + state->lambdadecay = (double)(1); + } + state->filterready = ae_false; + state->nonmonotonicmemlen = -1; + minmeritv0 = ae_maxrealnumber; + curmeritv0 = minmeritv0; + + /* + * If the problem formulation is mu-dependent, recompute target/objective using + * current value of Mu. + */ + if( !state->mudependent ) + { + goto lbl_13; + } + state->requesttype = 1; + state->querymu = state->mu; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + vfjinitfromsparse(&state->current.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->currentfj, _state); +lbl_13: + + /* + * Inner iterations for fixed Mu. + * + * After this loop is done we have current point in State.Current/State.CurrentFJ and + * current residual in State.RHS. Additionally, the current point is remembered as the + * one where the Hessian should be calculated. + */ +lbl_15: + if( ae_false ) + { + goto lbl_16; + } + if( userterminationneeded ) + { + goto lbl_16; + } + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + if( state->dotrace ) + { + ae_trace("> maximum number of iterations performed, stopping\n"); + } + state->repterminationtype = 5; + goto lbl_16; + } + + /* + * Trace iteration start + */ + if( state->dotrace ) + { + ae_trace("\n=== ITERATION %5d STARTED ========================================================================\n", + (int)(state->repiterationscount)); + ae_trace("mu = %11.3e\n", + (double)(state->mu)); + ae_trace("lambda = %11.3e (damping term for the Hessian)\n", + (double)(state->lambdav)); + ae_trace("lambda_decay = %7.4f (decay for the damping term)\n", + (double)(state->lambdadecay)); + ae_trace("|x|inf = %11.3e\n", + (double)(rmaxabsv(nraw, &state->current.xp, _state))); + ae_trace("|y|inf = %11.3e\n", + (double)(ae_maxreal(rmaxabsv(mflex, &state->current.yp, _state), rmaxabsv(mhard, &state->current.yv, _state), _state))); + ae_trace("\n"); + } + + /* + * Print variable stats if necessary + */ + if( state->dotrace ) + { + ae_trace("> var stats min.abs max.abs \n"); + ae_trace("x (prim) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.xp, nraw, _state)), + (double)(rmaxabsv(nraw, &state->current.xp, _state))); + ae_trace("x (slck) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.xs, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.xs, _state))); + ae_trace("g (lo) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.gl, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.gl, _state))); + ae_trace("g (hi) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.gu, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.gu, _state))); + ae_trace("z (prim.lo) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.zlp, nraw, _state)), + (double)(rmaxabsv(nraw, &state->current.zlp, _state))); + ae_trace("z (prim.hi) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.zup, nraw, _state)), + (double)(rmaxabsv(nraw, &state->current.zup, _state))); + ae_trace("y (prim) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.yp, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.yp, _state))); + ae_trace("y (lo) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.yl, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.yl, _state))); + ae_trace("y (hi) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.yu, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.yu, _state))); + ae_trace("y (hard) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.yv, mhard, _state)), + (double)(rmaxabsv(mhard, &state->current.yv, _state))); + ae_trace("z (slck.lo) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.zls, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.zls, _state))); + ae_trace("z (slck.hi) %11.3e %11.3e\n", + (double)(gipm_minabsnz(&state->current.zus, mflex, _state)), + (double)(rmaxabsv(mflex, &state->current.zus, _state))); + if( state->dodetailedtrace ) + { + ae_trace("> printing detailed data\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->current.xp, 0, nraw, _state); + ae_trace("\n"); + ae_trace("XS (scaled) = "); + tracevectorautoprec(&state->current.xs, 0, mflex, _state); + ae_trace("\n"); + } + } + + /* + * Compute residual for the non-condensed unsymmetric primal-dual system. + * Compute erorrs, check stopping and stagnation criteria. + */ + gipm_computerhs(state, &state->current, &state->currentfj, state->mu, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + gnrm = ae_sqrt(rdotv2(nraw, &state->rhs.rp, _state), _state); + rhs0 = rmax3(eprim, edual, ecmpl, _state); + if( state->dotrace ) + { + ae_trace("> computing absolute errors:\n"); + ae_trace("primal = %0.3e\n", + (double)(eprim)); + ae_trace("dual = %0.3e\n", + (double)(edual)); + ae_trace("compl = %0.3e\n", + (double)(ecmpl)); + ae_trace("rhs.max = %0.3e\n", + (double)(rhs0)); + } + if( (ae_fp_less(eprim,gipm_checkpointacceptance*lastcheckpointp)||ae_fp_less(edual,gipm_checkpointacceptance*lastcheckpointd))||ae_fp_less(ecmpl,gipm_checkpointacceptance*lastcheckpointc) ) + { + + /* + * Significant progress achieved for at least one parameter. Save checkpoint (used to detect stagnation). + * + * NOTE: it is important that the comparison is strict! Non-strict comparison is likely to cause inability to + * detect stagnation should any error become exactly zero. + */ + ae_assert((ae_fp_neq(eprim,lastcheckpointp)||ae_fp_neq(edual,lastcheckpointd))||ae_fp_neq(ecmpl,lastcheckpointc), "GIPM: integrity check 1500 failed", _state); + lastcheckpointp = ae_minreal(lastcheckpointp, eprim, _state); + lastcheckpointd = ae_minreal(lastcheckpointd, edual, _state); + lastcheckpointc = ae_minreal(lastcheckpointc, ecmpl, _state); + lastcheckpointidx = state->repiterationscount; + } + if( ae_fp_less_eq(rmax3(eprim/v, edual/vv, ecmpl/v2, _state),state->mu) ) + { + + /* + * NOTE: the additional 0.9 multiplier prevents the situation when internal iteration always finishes with error + * just below Eps, but outer iteration always sees the error just above Eps (due to mu being set to zero). + */ + if( state->dotrace ) + { + ae_trace("> stopping criteria for inner iterations met (relative error is small enough), exit to outer iterations\n"); + } + goto lbl_16; + } + if( ae_fp_greater_eq(state->lambdav,gipm_lambdamax) ) + { + if( state->dotrace ) + { + ae_trace("> regularization is at maximum, stopping inner iterations\n"); + } + state->lambdav = (double)(1); + state->lambdadecay = (double)(1); + goto lbl_16; + } + if( !firstouteriteration ) + { + + /* + * Two stopping criteria below are checked only after the first outer iteration is done + */ + if( ae_fp_greater_eq(state->mu,0.1*ae_sqrt(ae_machineepsilon, _state)) ) + { + + /* + * Midgame stopping condition: RHS stagnation + */ + if( firstouteriteration ) + { + state->rhsstagnationcounter = 0; + } + if( ae_fp_greater(ae_fabs(eprim-lastprim, _state),rmaxabs2(gipm_rhsstagnationtol1*lastprim, gipm_rhsstagnationtol2*state->eps, _state)) ) + { + state->rhsstagnationcounter = 0; + } + if( ae_fp_greater(ae_fabs(edual-lastdual, _state),rmaxabs2(gipm_rhsstagnationtol1*lastdual, gipm_rhsstagnationtol2*state->eps, _state)) ) + { + state->rhsstagnationcounter = 0; + } + if( ae_fp_greater(ae_fabs(ecmpl-lastcmpl, _state),rmaxabs2(gipm_rhsstagnationtol1*lastcmpl, gipm_rhsstagnationtol2*state->eps, _state)) ) + { + state->rhsstagnationcounter = 0; + } + if( state->rhsstagnationcounter>gipm_maxrhsstagnationits ) + { + if( state->dotrace ) + { + ae_trace("> RHS stagnated (no significant changes for %0d its)\n", + (int)(gipm_maxrhsstagnationits)); + } + goto lbl_16; + } + } + } + if( !firstouteriteration||ae_fp_less_eq(rmax3(eprim/v, edual/vv, ecmpl/v2, _state),gipm_firstiterationcheckpointstagnationeps) ) + { + + /* + * This stopping condition is checked at the first outer iteration, in the midgame and at the late phase + */ + if( state->repiterationscount>lastcheckpointidx+gipm_maxcheckpointstagnationits ) + { + if( state->dotrace ) + { + ae_trace("> iteration stagnated (no new checkpoints for %0d its)\n", + (int)(gipm_maxcheckpointstagnationits)); + } + goto lbl_16; + } + } + + /* + * Condense LHS (system matrix) and perform modified RCOMM request to factorize it + */ + gipm_condenselhs(state, &state->current, &state->currentfj, state->mu, &state->condensed, _state); + state->requesttype = 1001; + state->factsuccess = ae_false; + rallocv(nxh, &state->querydata, _state); + rcopyvx(nraw, &state->condensed.d0, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->condensed.d1, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->condensed.d1v, 0, &state->querydata, nraw+mflex, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + if( !state->factsuccess ) + { + if( state->subsequentfactfailures<=gipm_maxsubsequentfailuresforweakgrowth ) + { + + /* + * Slowly growing Lambda + */ + if( state->dotrace ) + { + ae_trace("> factorization failed, Hessian is not sufficiently positive definite, increasing damping factor\n"); + } + state->lambdav = rcase2(lambdafound, gipm_lambdagrowth*coalesce(state->lambdav, state->mu, _state), coalesce((double)10*state->lambdav, (double)10*state->mu, _state), _state); + state->lambdadecay = 1.0; + } + else + { + + /* + * Many subsequent failures, rapid growth + */ + if( state->dotrace ) + { + ae_trace("> factorization failed too many times in a row, rapid growth of LambdaV is activated\n"); + } + state->lambdav = ae_maxreal(gipm_lambdarapidgrowth*state->lambdav, 0.001*state->mu, _state); + state->lambdadecay = 1.0; + } + state->subsequentfactfailures = state->subsequentfactfailures+1; + goto lbl_15; + } + state->subsequentfactfailures = 0; + lambdafound = lambdafound||ae_fp_neq(state->lambdav,(double)(0)); + + /* + * Run iterative refinement + */ + rhsk = ae_maxrealnumber; + gipm_varsinitbyzero(&state->delta, nraw, mflex, mhard, _state); + rfsidx = 0; +lbl_17: + if( rfsidx>gipm_maxrfsits-1 ) + { + goto lbl_19; + } + gipm_condenserhs(state, &state->current, &state->currentfj, state->mu, &state->rhs, &state->condensed, _state); + state->requesttype = 1002; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->condensed.wx, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->condensed.wy, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->condensed.wyv, 0, &state->querydata, nraw+mflex, _state); + rallocv(nraw+mtotal, &state->replysol, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + gipm_unpacksolution(state, &state->current, &state->currentfj, state->mu, &state->rhs, &state->condensed, &state->replysol, &state->corr, _state); + gipm_varsapplystep(&state->delta, &state->corr, 1.0, _state); + state->requesttype = 1003; + rallocv(nraw+mtotal, &state->querydata, _state); + rallocv(nraw+mtotal+nraw, &state->replyprod, _state); + rcopyvx(nraw, &state->corr.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->corr.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->corr.yv, 0, &state->querydata, nraw+mflex, _state); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + rallocv(nraw, &state->tmphdxp, _state); + rallocv(mtotal, &state->tmpjdxp, _state); + rallocv(nraw, &state->tmpjtdy, _state); + rcopyvx(nraw, &state->replyprod, 0, &state->tmphdxp, 0, _state); + rcopyvx(mtotal, &state->replyprod, nraw, &state->tmpjdxp, 0, _state); + rcopyvx(nraw, &state->replyprod, nraw+mtotal, &state->tmpjtdy, 0, _state); + rhsk = gipm_computeupdateresidual(state, &state->current, &state->currentfj, state->mu, state->lambdav, &state->corr, &state->tmphdxp, &state->tmpjdxp, &state->tmpjtdy, &state->rhs, _state); + if( state->dotrace ) + { + ae_trace("> analyzing solution to the linear system, relative residual norm is %0.2e\n", + (double)(rhsk/coalesce(rhs0, (double)(1), _state))); + } + if( ae_fp_less(rhsk,gipm_rhstol*rhs0) ) + { + if( state->dotrace ) + { + ae_trace("> residual norm is small enough, stopping refinement\n"); + } + goto lbl_19; + } + rfsidx = rfsidx+1; + goto lbl_17; +lbl_19: + if( ae_fp_greater(rhsk,ae_maxreal((double)2*gipm_rhstol, 0.001, _state)*rhs0) ) + { + if( state->dotrace ) + { + ae_trace("> iterative refinement failed to sufficiently decrease residual, increasing Lambda and retrying\n"); + } + state->lambdav = coalesce((double)10*state->lambdav, (double)1000*ae_machineepsilon*((double)1/state->mu), _state); + state->lambdadecay = 1.0; + state->repiterationscount = state->repiterationscount+1; + goto lbl_15; + } + + /* + * Perform line search + */ + if( state->dodetailedtrace ) + { + ae_trace("> printing detailed step information\n"); + ae_trace("dX = "); + tracevectorautoprec(&state->delta.xp, 0, nraw, _state); + ae_trace("\n"); + ae_trace("dXS = "); + tracevectorautoprec(&state->delta.xs, 0, mflex, _state); + ae_trace("\n"); + } + alpha = gipm_computesteplength(state, &state->current, &state->delta, _state); + if( state->dotrace ) + { + ae_trace("> computed maximum step length: alpha=%0.6f\n", + (double)(alpha)); + } + gipm_barrierpenaltyandcmplerror(state, &state->current, &state->currentfj, state->mu, &f0, &p0, &cmpl0, _state); + merit0 = gipm_meritfunctionpd(state, &state->current, &state->currentfj, state->mu, _state); + if( !state->filterready ) + { + nlpfinitx((double)10*(p0+cmpl0+(double)10), gipm_maxnd, &state->filter, _state); + state->filterready = ae_true; + } + if( state->nonmonotonicmemlen<0 ) + { + gipm_nonmonotonicinit(state, gipm_maxnonmonotonic, ae_sqrt(ae_maxrealnumber, _state), _state); + } + maxabsf = ae_maxreal(maxabsf, ae_fabs(f0, _state), _state); + if( state->dotrace ) + { + ae_trace("> line search starts: f_barr = %14.6e l2_p = %14.6e cmpl = %14.6e mrtf = %14.6e\n", + (double)(f0), + (double)(p0), + (double)(cmpl0), + (double)(merit0)); + } + smalltrials = 0; + btits = 0; +lbl_20: + if( ae_false ) + { + goto lbl_21; + } + + /* + * Preliminary checks + */ + if( ae_fp_less(alpha,gipm_smallstep) ) + { + smalltrials = smalltrials+1; + } + if( smalltrials>=gipm_maxsmalltrials ) + { + alpha = (double)(0); + goto lbl_21; + } + + /* + * Compute merit function and complementarity error at the trial point + */ + gipm_varscopy(&state->current, &state->trial, _state); + gipm_varsapplystep(&state->trial, &state->delta, alpha, _state); + rmergemaxv(nraw, &state->safeguardbndlp, &state->trial.xp, _state); + rmergeminv(nraw, &state->safeguardbndup, &state->trial.xp, _state); + state->requesttype = 1; + state->querymu = state->mu; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->trial.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->trial.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->trial.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + vfjinitfromsparse(&state->trial.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->trialfj, _state); + gipm_barrierpenaltyandcmplerror(state, &state->trial, &state->trialfj, state->mu, &f1, &p1, &cmpl1, _state); + merit1 = gipm_meritfunctionpd(state, &state->trial, &state->trialfj, state->mu, _state); + + /* + * Control violation of hard constraints + */ + violated = ae_false; + for(i=0; i<=mhard-1; i++) + { + if( ae_fp_greater_eq(state->trialfj.fi.ptr.p_double[1+mflex+i],state->finitebndux.ptr.p_double[nxf+i]) ) + { + if( state->dotrace ) + { + ae_trace("> stp=%11.3e, hard inequality %0d is violated, decreasing step\n", + (double)(alpha), + (int)(i)); + } + btits = btits+1; + alpha = 0.5*alpha; + violated = ae_true; + break; + } + } + if( violated ) + { + goto lbl_20; + } + + /* + * Report step + */ + if( state->dotrace ) + { + ae_trace("> stp=%11.3e, delta: %14.6e %14.6e %14.6e %14.6e\n", + (double)(alpha), + (double)(f1-f0), + (double)(p1-p0), + (double)(cmpl1-cmpl0), + (double)(merit1-merit0)); + } + + /* + * Markov filter or classic filter + */ + if( (!state->isfirstorder||state->repiterationscount-innerloopstart=3 ) + { + state->lambdav = ae_maxreal((double)2*state->lambdav, gnrm, _state); + state->lambdadecay = 1.0; + if( state->dotrace ) + { + ae_trace("> too many backtracking its performed, increasing regularization coeff LambdaV to %0.2e\n", + (double)(state->lambdav)); + } + } + if( ae_fp_neq(alpha,(double)(0)) ) + { + goto lbl_22; + } + + /* + * Line search failed, return back to the original point. We just need the caller to remember it, + * so we actually do not use returned values. A suboptimal solution, but this line of code is + * VERY rarely executed. + */ + if( state->dotrace ) + { + ae_trace("> line search failed to provide sufficient decrease, stopping inner iterations\n"); + } + state->requesttype = 1; + state->querymu = state->mu; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->repiterationscount = state->repiterationscount+1; + goto lbl_16; +lbl_22: + if( state->dotrace ) + { + ae_trace("> line search finished with alpha=%0.2e\n", + (double)(alpha)); + ae_trace("> f: %0.9e -> %0.9e (delta=%0.3e)\n", + (double)(state->currentfj.fi.ptr.p_double[0]), + (double)(state->trialfj.fi.ptr.p_double[0]), + (double)(state->trialfj.fi.ptr.p_double[0]-state->currentfj.fi.ptr.p_double[0])); + ae_trace("> f_barrier: %0.9e -> %0.9e (delta=%0.3e)\n", + (double)(f0), + (double)(f1), + (double)(f1-f0)); + } + if( !state->isfirstorder ) + { + goto lbl_24; + } + + /* + * Send quasi-Newton update + */ + gipm_preparequasinewtonupdate(state, _state); + state->requesttype = 1004; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: +lbl_24: + gipm_varscopy(&state->trial, &state->current, _state); + vfjcopy(&state->trialfj, &state->currentfj, _state); + if( firstouteriteration ) + { + nlpfappend(&state->filter, f0, p0+cmpl0, _state); + } + gipm_nonmonotonicpush(state, merit1, _state); + curmeritv0 = gipm_meritv0(state, &state->current, &state->currentfj, state->mu, _state); + minmeritv0 = ae_minreal(minmeritv0, curmeritv0, _state); + if( state->dotrace ) + { + ae_trace("> meritV0: min=%0.6e, cur=%0.6e\n", + (double)(minmeritv0), + (double)(curmeritv0)); + } + + /* + * Check for unboundedness + */ + v = rmaxabsv(nraw, &state->current.xp, _state); + if( ae_fp_greater(v,curbigval)&&ae_fp_greater(v,curbiggrowth*state->nrmx0) ) + { + if( state->dotrace ) + { + ae_trace("> |x| tends to infinity, suspecting unboundedness\n"); + } + unboundednesssuspected = ae_true; + } + vv = state->currentfj.fi.ptr.p_double[0]; + if( ae_fp_less(vv,-curbigval)&&ae_fp_less(vv,-curbiggrowth*state->absf0) ) + { + if( state->dotrace ) + { + ae_trace("> f tends to negative infinity, suspecting unboundedness\n"); + } + unboundednesssuspected = ae_true; + } + if( unboundednesssuspected ) + { + curbigval = rmaxabs3(curbigval, v, vv, _state); + state->repiterationscount = state->repiterationscount+1; + goto lbl_16; + } + + /* + * If we run the very first outer iteration, check whether we need to increase Mu. + * Sometimes initial value of the Mu is too low, so we need a way to increase it. + * Such increases are performed only during the first outer iteration; subsequent + * iterations see only monotonic decrease. + */ + if( !firstouteriteration ) + { + goto lbl_26; + } + v = 1.0; + v = ae_maxreal(v, rmaxabsv(nraw, &state->current.xp, _state), _state); + v = ae_maxreal(v, rmaxabsv(mflex, &state->current.xs, _state), _state); + v = ae_maxreal(v, rmaxabsv(mflex, &state->current.gl, _state), _state); + v = ae_maxreal(v, rmaxabsv(mflex, &state->current.gu, _state), _state); + v = ae_minreal(ae_pow(v, 0.75, _state)*gipm_initmu, gipm_maxmu, _state); + if( ae_fp_less_eq(v,1.41*state->mu) ) + { + goto lbl_28; + } + if( state->dotrace ) + { + ae_trace("> increasing Mu to %0.2e according to the growth of the primal variables, reseting the filter\n", + (double)(v)); + } + state->mu = v; + lastcheckpointp = ae_maxrealnumber; + lastcheckpointd = ae_maxrealnumber; + lastcheckpointc = ae_maxrealnumber; + lastcheckpointidx = state->repiterationscount; + if( !state->mudependent ) + { + goto lbl_30; + } + + /* + * If the problem formulation is mu-dependent, recompute target/objective using + * current value of Mu. + */ + state->requesttype = 1; + state->querymu = state->mu; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + vfjinitfromsparse(&state->current.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->currentfj, _state); + gipm_barrierpenaltyandcmplerror(state, &state->current, &state->currentfj, state->mu, &f1, &p1, &cmpl1, _state); +lbl_30: + state->filterready = ae_false; + state->nonmonotonicmemlen = -1; + curmeritv0 = gipm_meritv0(state, &state->current, &state->currentfj, state->mu, _state); + minmeritv0 = curmeritv0; +lbl_28: +lbl_26: + + /* + * Next iteration + */ + lastprim = eprim; + lastdual = edual; + lastcmpl = ecmpl; + if( ae_fp_neq(state->lambdav,(double)(0)) ) + { + state->lambdav = state->lambdav*state->lambdadecay; + state->lambdadecay = ae_maxreal(state->lambdadecay*gipm_lambdadecayacc, ae_sqrt(ae_sqrt(ae_machineepsilon, _state), _state), _state); + if( ae_fp_less(state->lambdav,state->mu*ae_machineepsilon) ) + { + state->lambdav = (double)(0); + state->lambdadecay = (double)(0); + } + } + state->repiterationscount = state->repiterationscount+1; + state->rhsstagnationcounter = state->rhsstagnationcounter+1; + goodinnerits = goodinnerits+1; + goto lbl_15; +lbl_16: + firstouteriteration = ae_false; + if( state->dotrace ) + { + ae_trace("\n----- outer iteration ------------------------------------------------------------------------------\n"); + } + if( userterminationneeded ) + { + if( state->dotrace ) + { + ae_trace("> user requested immediate termination, stopping\n"); + } + state->repterminationtype = 8; + goto lbl_12; + } + if( state->repterminationtype!=0 ) + { + goto lbl_12; + } + if( unboundednesssuspected ) + { + if( (ae_fp_less_eq(state->mu,1.001*mumin)&&ae_fp_greater_eq(curbigval,0.999*gipm_maxbigval))&&ae_fp_greater_eq(curbiggrowth,0.999*gipm_maxbiggrowth) ) + { + if( state->dotrace ) + { + ae_trace("> unboundedness detected (mu at minimum, thresholds at maximum, the problem is still unbounded)\n"); + } + state->repterminationtype = -4; + goto lbl_12; + } + if( state->dotrace ) + { + ae_trace("> decreasing mu, increasing unboundedness detection thresholds, continuing iterations\n"); + } + state->mu = ae_maxreal(mumin, 0.01*state->mu, _state); + curbigval = ae_minreal(gipm_vggrowth*curbigval, gipm_maxbigval, _state); + curbiggrowth = ae_minreal(gipm_vggrowth*curbiggrowth, gipm_maxbiggrowth, _state); + goto lbl_11; + } + + /* + * Recompute RHS from scratch (less dependency on the internal loop). + * Check primal/dual/complementarity errors for the original problem (mu=0). + */ + if( !state->mudependent ) + { + goto lbl_32; + } + + /* + * If the problem formulation is mu-dependent, recompute target/objective using zero Mu. + */ + state->requesttype = 1; + state->querymu = 0.0; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + vfjinitfromsparse(&state->current.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->currentfj, _state); +lbl_32: + gipm_computerhs(state, &state->current, &state->currentfj, 0.0, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + if( state->dotrace ) + { + ae_trace("> computing absolute errors for the original problem (mu=0):\n"); + ae_trace("primal = %0.3e\n", + (double)(eprim)); + ae_trace("dual = %0.3e\n", + (double)(edual)); + ae_trace("compl = %0.3e\n", + (double)(ecmpl)); + } + if( ae_fp_less(rmax3(eprim, edual, ecmpl, _state),state->besterr) ) + { + + /* + * Save the best point so far + */ + gipm_varscopy(&state->current, &state->best, _state); + vfjcopy(&state->currentfj, &state->bestfj, _state); + state->besterr = rmax3(eprim, edual, ecmpl, _state); + if( state->dotrace ) + { + ae_trace("> the point provides the best prim/dual/cmpl errors so far, saving\n"); + } + } + else + { + if( state->dotrace ) + { + ae_trace("> the point does not improve over the best prim/dual/cmpl errors so far, not saved\n"); + } + } + if( ae_fp_less_eq(rmax3(eprim/v, edual/vv, ecmpl/v2, _state),state->eps) ) + { + if( state->dotrace ) + { + ae_trace("> stopping criteria for outer iterations met (relative error is below Eps=%0.2e), solved\n", + (double)(state->eps)); + } + state->repterminationtype = 2; + goto lbl_12; + } + if( ae_fp_less_eq(state->mu,1.001*mumin) ) + { + if( state->dotrace ) + { + ae_trace("> mu is at minimum, stagnation detected, stopping\n"); + } + state->repterminationtype = 7; + goto lbl_12; + } + + /* + * Inner iterations are over, tighten/relax bounds if necessary and decrease Mu + */ + gipm_tightenrelaxbounds(state, _state); + state->mu = ae_maxreal(mumin, ae_minreal(gipm_mudecaylinear*state->mu, ae_pow(state->mu, gipm_mudecaypower, _state), _state), _state); + goto lbl_11; +lbl_12: + + /* + * Almost done: + * * compare error at State.Current with one at State.Best, restore from State.Best + * if optimizer went in wrong direction + * * set completion flags + */ + if( state->dotrace ) + { + ae_trace("\n=== STOPPED ========================================================================================\n"); + } + if( !state->mudependent ) + { + goto lbl_34; + } + + /* + * If the problem formulation is mu-dependent, recompute target/objective using zero Mu. + */ + state->requesttype = 1; + state->querymu = 0.0; + rallocv(nraw+mtotal, &state->querydata, _state); + rcopyvx(nraw, &state->current.xp, 0, &state->querydata, 0, _state); + rcopyvx(mflex, &state->current.yp, 0, &state->querydata, nraw, _state); + rcopyvx(mhard, &state->current.yv, 0, &state->querydata, nraw+mflex, _state); + rallocv(1+mtotal, &state->replyfi, _state); + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + vfjinitfromsparse(&state->current.xp, nraw, &state->replyfi, 1+mtotal, &state->replysj, &state->currentfj, _state); +lbl_34: + gipm_computerhs(state, &state->current, &state->currentfj, 0.0, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + if( ae_fp_greater(rmax3(eprim, edual, ecmpl, _state),state->besterr) ) + { + + /* + * Restore best point so far + */ + gipm_varscopy(&state->best, &state->current, _state); + vfjcopy(&state->bestfj, &state->currentfj, _state); + if( state->dotrace ) + { + ae_trace("> the last accepted point is worse than the best one seen so far (p/d/c err: %0.2e vs %0.2e), restoring the best one\n", + (double)(rmax3(eprim, edual, ecmpl, _state)), + (double)(state->besterr)); + } + } + if( infinitiesdetected ) + { + state->repterminationtype = icase2(failedtorecoverfrominfinities, -8, state->repterminationtype+800, _state); + } + stimerstop(&state->timertotal, _state); + if( state->dotrace ) + { + if( infinitiesdetected&&failedtorecoverfrominfinities ) + { + ae_trace("> infinities were detected, but we failed to recover by decreasing trust radius; declaring failure with the code -8\n"); + } + ae_trace("raw target: %20.12e\n", + (double)(state->currentfj.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0])); + ae_trace("total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = nraw; + state->rstate.ia.ptr.p_int[1] = mtotal; + state->rstate.ia.ptr.p_int[2] = mflex; + state->rstate.ia.ptr.p_int[3] = mhard; + state->rstate.ia.ptr.p_int[4] = nxf; + state->rstate.ia.ptr.p_int[5] = nxh; + state->rstate.ia.ptr.p_int[6] = i; + state->rstate.ia.ptr.p_int[7] = rfsidx; + state->rstate.ia.ptr.p_int[8] = j; + state->rstate.ia.ptr.p_int[9] = innerloopstart; + state->rstate.ia.ptr.p_int[10] = smalltrials; + state->rstate.ia.ptr.p_int[11] = lastcheckpointidx; + state->rstate.ia.ptr.p_int[12] = btits; + state->rstate.ia.ptr.p_int[13] = goodinnerits; + state->rstate.ba.ptr.p_bool[0] = firstouteriteration; + state->rstate.ba.ptr.p_bool[1] = infinitiesdetected; + state->rstate.ba.ptr.p_bool[2] = failedtorecoverfrominfinities; + state->rstate.ba.ptr.p_bool[3] = unboundednesssuspected; + state->rstate.ba.ptr.p_bool[4] = lambdafound; + state->rstate.ba.ptr.p_bool[5] = accepted; + state->rstate.ba.ptr.p_bool[6] = violated; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + state->rstate.ra.ptr.p_double[2] = v2; + state->rstate.ra.ptr.p_double[3] = alpha; + state->rstate.ra.ptr.p_double[4] = f0; + state->rstate.ra.ptr.p_double[5] = f1; + state->rstate.ra.ptr.p_double[6] = p0; + state->rstate.ra.ptr.p_double[7] = p1; + state->rstate.ra.ptr.p_double[8] = cmpl0; + state->rstate.ra.ptr.p_double[9] = cmpl1; + state->rstate.ra.ptr.p_double[10] = gnrm; + state->rstate.ra.ptr.p_double[11] = initprimdual; + state->rstate.ra.ptr.p_double[12] = eprim; + state->rstate.ra.ptr.p_double[13] = edual; + state->rstate.ra.ptr.p_double[14] = ecmpl; + state->rstate.ra.ptr.p_double[15] = mumin; + state->rstate.ra.ptr.p_double[16] = curbigval; + state->rstate.ra.ptr.p_double[17] = curbiggrowth; + state->rstate.ra.ptr.p_double[18] = rhs0; + state->rstate.ra.ptr.p_double[19] = rhsk; + state->rstate.ra.ptr.p_double[20] = lastcheckpointp; + state->rstate.ra.ptr.p_double[21] = lastcheckpointd; + state->rstate.ra.ptr.p_double[22] = lastcheckpointc; + state->rstate.ra.ptr.p_double[23] = lastprim; + state->rstate.ra.ptr.p_double[24] = lastdual; + state->rstate.ra.ptr.p_double[25] = lastcmpl; + state->rstate.ra.ptr.p_double[26] = maxabsf; + state->rstate.ra.ptr.p_double[27] = minmeritv0; + state->rstate.ra.ptr.p_double[28] = curmeritv0; + state->rstate.ra.ptr.p_double[29] = merit0; + state->rstate.ra.ptr.p_double[30] = merit1; + return result; +} + + +/************************************************************************* +Extract solution + +INPUT PARAMETERS: + State - solver instance + +OUTPUT PARAMETERS: + XS - array[N], solution + LagBC - array[N], Lagrange multipliers for box constraints + LagXC - array[M], Lagrange multipliers for linear, quadratic, conic constraints + TerminationType - completion code, positive values for success, + negative for failures (XS constrains best point + found so far): + * -2 the task is either unbounded or infeasible; + the IPM solver has difficulty distinguishing between these two. + * +1 stopping criteria are met + * +7 stopping criteria are too stringent + +RESULT: + +This function ALWAYS returns something meaningful in XS, LagBC, LagLC - +either solution or the best point so far, even for negative TerminationType. + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gipmresults(gipmstate* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagxc, + ae_int_t* terminationtype, + ae_state *_state) +{ + + *terminationtype = 0; + + *terminationtype = state->repterminationtype; + rcopyallocv(state->nraw, &state->current.xp, xs, _state); + rcopyallocv(state->nraw, &state->current.zup, lagbc, _state); + raddv(state->nraw, -1.0, &state->current.zlp, lagbc, _state); + rcopyallocv(state->mflex, &state->current.yp, lagxc, _state); +} + + +/************************************************************************* +Allocates place for variables of IPM and fills by zeros. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_varsinitbyzero(gipmvars* vstate, + ae_int_t nraw, + ae_int_t mflex, + ae_int_t mhard, + ae_state *_state) +{ + + + ae_assert(nraw>=1, "VarsInitByZero: N<1", _state); + ae_assert(mflex>=0, "VarsInitByZero: MFlex<0", _state); + ae_assert(mhard>=0, "VarsInitByZero: MHard<0", _state); + vstate->np = nraw; + vstate->nf = nraw+mflex; + vstate->mflex = mflex; + vstate->mhard = mhard; + rsetallocv(nraw, 0.0, &vstate->xp, _state); + rsetallocv(nraw, 0.0, &vstate->zlp, _state); + rsetallocv(nraw, 0.0, &vstate->zup, _state); + rsetallocv(mflex, 0.0, &vstate->yp, _state); + rsetallocv(mflex, 0.0, &vstate->yl, _state); + rsetallocv(mflex, 0.0, &vstate->yu, _state); + rsetallocv(mflex, 0.0, &vstate->xs, _state); + rsetallocv(mflex, 0.0, &vstate->gl, _state); + rsetallocv(mflex, 0.0, &vstate->gu, _state); + rsetallocv(mflex, 0.0, &vstate->zls, _state); + rsetallocv(mflex, 0.0, &vstate->zus, _state); + rsetallocv(mhard, 0.0, &vstate->yv, _state); +} + + +/************************************************************************* +Apply step + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_varsapplystep(gipmvars* vstate, + const gipmvars* delta, + double alpha, + ae_state *_state) +{ + + + raddv(vstate->np, alpha, &delta->xp, &vstate->xp, _state); + raddv(vstate->np, alpha, &delta->zlp, &vstate->zlp, _state); + raddv(vstate->np, alpha, &delta->zup, &vstate->zup, _state); + raddv(vstate->mflex, alpha, &delta->yp, &vstate->yp, _state); + raddv(vstate->mflex, alpha, &delta->yl, &vstate->yl, _state); + raddv(vstate->mflex, alpha, &delta->yu, &vstate->yu, _state); + raddv(vstate->mflex, alpha, &delta->xs, &vstate->xs, _state); + raddv(vstate->mflex, alpha, &delta->gl, &vstate->gl, _state); + raddv(vstate->mflex, alpha, &delta->gu, &vstate->gu, _state); + raddv(vstate->mflex, alpha, &delta->zls, &vstate->zls, _state); + raddv(vstate->mflex, alpha, &delta->zus, &vstate->zus, _state); + raddv(vstate->mhard, alpha, &delta->yv, &vstate->yv, _state); +} + + +/************************************************************************* +Copy vars + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_varscopy(const gipmvars* src, + gipmvars* dst, + ae_state *_state) +{ + + + dst->np = src->np; + dst->nf = src->nf; + dst->mflex = src->mflex; + dst->mhard = src->mhard; + rcopyallocv(src->np, &src->xp, &dst->xp, _state); + rcopyallocv(src->np, &src->zlp, &dst->zlp, _state); + rcopyallocv(src->np, &src->zup, &dst->zup, _state); + rcopyallocv(src->mflex, &src->yp, &dst->yp, _state); + rcopyallocv(src->mflex, &src->yl, &dst->yl, _state); + rcopyallocv(src->mflex, &src->yu, &dst->yu, _state); + rcopyallocv(src->mflex, &src->xs, &dst->xs, _state); + rcopyallocv(src->mflex, &src->gl, &dst->gl, _state); + rcopyallocv(src->mflex, &src->gu, &dst->gu, _state); + rcopyallocv(src->mflex, &src->zls, &dst->zls, _state); + rcopyallocv(src->mflex, &src->zus, &dst->zus, _state); + rcopyallocv(src->mhard, &src->yv, &dst->yv, _state); +} + + +/************************************************************************* +Computes step length + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm_computesteplength(const gipmstate* state, + const gipmvars* current, + const gipmvars* delta, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double eps2; + double result; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + eps2 = (double)1/ae_sqrt(ae_maxrealnumber, _state); + result = ae_maxrealnumber; + + /* + * Analyze NP-sized components + */ + for(i=0; i<=np-1; i++) + { + if( delta->xp.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (current->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i])/(eps2-delta->xp.ptr.p_double[i]), _state); + } + if( delta->xp.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->finitebndux.ptr.p_double[i]-current->xp.ptr.p_double[i])/(eps2+delta->xp.ptr.p_double[i]), _state); + } + if( delta->zlp.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->zlp.ptr.p_double[i]/(eps2-delta->zlp.ptr.p_double[i]), _state); + } + if( delta->zup.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->zup.ptr.p_double[i]/(eps2-delta->zup.ptr.p_double[i]), _state); + } + } + + /* + * analyze MFlex-sized components + */ + for(i=0; i<=mflex-1; i++) + { + if( delta->gl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gl.ptr.p_double[i]/(eps2-delta->gl.ptr.p_double[i]), _state); + } + if( delta->gu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gu.ptr.p_double[i]/(eps2-delta->gu.ptr.p_double[i]), _state); + } + if( delta->zls.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->zls.ptr.p_double[i]/(eps2-delta->zls.ptr.p_double[i]), _state); + } + if( delta->zus.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->zus.ptr.p_double[i]/(eps2-delta->zus.ptr.p_double[i]), _state); + } + } + + /* + * analyze MHard-sized components + */ + for(i=0; i<=mhard-1; i++) + { + if( delta->yv.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->yv.ptr.p_double[i]/(eps2-delta->yv.ptr.p_double[i]), _state); + } + } + + /* + * Apply fraction to boundary + */ + result = ae_minreal(gipm_fractobnd*result, 1.0, _state); + return result; +} + + +/************************************************************************* +Compute RHS for a Newton system. +Returns inf-norms of raw (unnormalized) primal, dual, complementarity errors. +Also returns normalizing coefficients for errors. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_computerhs(gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + gipmrhs* rhs, + double* eprim2, + double* edual2, + double* ecmpl2, + double* sprim, + double* sdual, + double* scmpl, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t np; + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double v; + ae_vector tmp; + double nu; + double relaxby; + ae_int_t nprim2; + ae_int_t ndual2; + ae_int_t ncmpl2; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + *eprim2 = 0.0; + *edual2 = 0.0; + *ecmpl2 = 0.0; + *sprim = 0.0; + *sdual = 0.0; + *scmpl = 0.0; + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + mflex = currentvars->mflex; + mhard = currentvars->mhard; + np = currentvars->np; + ae_nxpool_retrieve(&state->mnx1pool, &tmp, _state); + ae_assert(tmp.cnt>=mflex+mhard+1, "GIPM: integrity check 7328 failed", _state); + nu = gipm_getnu(currentmu, _state); + relaxby = ae_minreal(gipm_relaxfactor*currentmu, gipm_maxrelaxation, _state); + *eprim2 = (double)(0); + *edual2 = (double)(0); + *ecmpl2 = (double)(0); + *sprim = (double)(1); + *sdual = (double)(1); + *scmpl = (double)(1); + nprim2 = 0; + ndual2 = 0; + ncmpl2 = 0; + + /* + * Compute RP = -(gmod(xp) + J'*yp + Jv'*yv - ZLP + ZUP) + */ + rsetallocv(np, 0.0, &rhs->rp, _state); + ae_assert(!currentfj->isdense, "GIPM: integrity check 8517 failed", _state); + j0 = currentfj->sj.ridx.ptr.p_int[0]; + j1 = currentfj->sj.ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + rhs->rp.ptr.p_double[currentfj->sj.idx.ptr.p_int[jj]] = currentfj->sj.vals.ptr.p_double[jj]; + } + raddv(np, gipm_damptau*currentmu, ¤tvars->xp, &rhs->rp, _state); + tmp.ptr.p_double[0] = (double)(0); + rcopyvx(mflex, ¤tvars->yp, 0, &tmp, 1, _state); + rcopyvx(mhard, ¤tvars->yv, 0, &tmp, 1+mflex, _state); + sparsegemv(¤tfj->sj, 1.0, 1, &tmp, 0, 1.0, &rhs->rp, 0, _state); + raddv(np, -1.0, ¤tvars->zlp, &rhs->rp, _state); + raddv(np, 1.0, ¤tvars->zup, &rhs->rp, _state); + rmulv(np, -1.0, &rhs->rp, _state); + *edual2 = *edual2+rdotv2(np, &rhs->rp, _state); + ndual2 = ndual2+np; + + /* + * Compute RS = yp - yl - yu + */ + rsetallocv(mflex, 0.0, &rhs->rs, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rs.ptr.p_double[i] = currentvars->yp.ptr.p_double[i]-currentvars->yl.ptr.p_double[i]-currentvars->yu.ptr.p_double[i]; + } + } + *edual2 = *edual2+rdotv2(mflex, &rhs->rs, _state); + ndual2 = ndual2+mflex; + + /* + * Compute RGL = yl + ZLS + */ + rsetallocv(mflex, 0.0, &rhs->rgl, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rgl.ptr.p_double[i] = currentvars->yl.ptr.p_double[i]+currentvars->zls.ptr.p_double[i]; + } + } + *edual2 = *edual2+rdotv2(mflex, &rhs->rgl, _state); + ndual2 = ndual2+mflex; + + /* + * Compute RGU = ZUS-yu + */ + rsetallocv(mflex, 0.0, &rhs->rgu, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rgu.ptr.p_double[i] = currentvars->zus.ptr.p_double[i]-currentvars->yu.ptr.p_double[i]; + } + } + *edual2 = *edual2+rdotv2(mflex, &rhs->rgu, _state); + ndual2 = ndual2+mflex; + + /* + * Compute RLP = mu*ELP-ZLP*(xp-bl) + * RUP = mu*EUP-ZUP*(bu-xp) + */ + rallocv(np, &rhs->rlp, _state); + rallocv(np, &rhs->rup, _state); + for(i=0; i<=np-1; i++) + { + rhs->rlp.ptr.p_double[i] = currentmu*state->elp.ptr.p_double[i]-currentvars->zlp.ptr.p_double[i]*(currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i]); + rhs->rup.ptr.p_double[i] = currentmu*state->eup.ptr.p_double[i]-currentvars->zup.ptr.p_double[i]*(state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]); + } + *ecmpl2 = *ecmpl2+rdotv2(np, &rhs->rlp, _state); + ncmpl2 = ncmpl2+np; + *ecmpl2 = *ecmpl2+rdotv2(np, &rhs->rup, _state); + ncmpl2 = ncmpl2+np; + + /* + * / xs-c(xp)+nu*yp for I in range/slack constraints + * Compute RY = | + * \ nu*y-(c(xp)-bndu) for I in equality constraints + */ + rallocv(mflex, &rhs->ry, _state); + for(i=0; i<=mflex-1; i++) + { + if( state->isequality.ptr.p_bool[i] ) + { + rhs->ry.ptr.p_double[i] = nu*currentvars->yp.ptr.p_double[i]-(currentfj->fi.ptr.p_double[1+i]-state->finitebndux.ptr.p_double[np+i]); + } + else + { + rhs->ry.ptr.p_double[i] = currentvars->xs.ptr.p_double[i]-currentfj->fi.ptr.p_double[1+i]+nu*currentvars->yp.ptr.p_double[i]; + } + } + *eprim2 = *eprim2+rdotv2(mflex, &rhs->ry, _state); + nprim2 = nprim2+mflex; + + /* + * Compute RCL = ELS*(cl-rlx*mu+gl-xs+nu*yl) + * RCU = EUS*(cu+rlx*mu-gu-xs+nu*yu) + */ + rsetallocv(mflex, 0.0, &rhs->rcl, _state); + rsetallocv(mflex, 0.0, &rhs->rcu, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rcl.ptr.p_double[i] = state->els.ptr.p_double[i]*(state->finitebndlx.ptr.p_double[np+i]-relaxby+currentvars->gl.ptr.p_double[i]-currentvars->xs.ptr.p_double[i]+nu*currentvars->yl.ptr.p_double[i]); + rhs->rcu.ptr.p_double[i] = state->eus.ptr.p_double[i]*(state->finitebndux.ptr.p_double[np+i]+relaxby-currentvars->xs.ptr.p_double[i]-currentvars->gu.ptr.p_double[i]+nu*currentvars->yu.ptr.p_double[i]); + } + } + *eprim2 = *eprim2+rdotv2(mflex, &rhs->rcl, _state); + nprim2 = nprim2+mflex; + *eprim2 = *eprim2+rdotv2(mflex, &rhs->rcu, _state); + nprim2 = nprim2+mflex; + + /* + * Compute RLS = mu*ELS-ZLS*gl + * RUS = mu*EUS-ZUS*gu + */ + rsetallocv(mflex, 0.0, &rhs->rls, _state); + rsetallocv(mflex, 0.0, &rhs->rus, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rls.ptr.p_double[i] = currentmu*state->els.ptr.p_double[i]-currentvars->zls.ptr.p_double[i]*currentvars->gl.ptr.p_double[i]; + rhs->rus.ptr.p_double[i] = currentmu*state->eus.ptr.p_double[i]-currentvars->zus.ptr.p_double[i]*currentvars->gu.ptr.p_double[i]; + } + } + *ecmpl2 = *ecmpl2+rdotv2(mflex, &rhs->rls, _state); + ncmpl2 = ncmpl2+mflex; + *ecmpl2 = *ecmpl2+rdotv2(mflex, &rhs->rus, _state); + ncmpl2 = ncmpl2+mflex; + + /* + * Compute RV = mu-YV*(vu-v()) + */ + rallocv(mhard, &rhs->rv, _state); + for(i=0; i<=mhard-1; i++) + { + rhs->rv.ptr.p_double[i] = currentvars->yv.ptr.p_double[i]*(state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i])-currentmu; + } + *ecmpl2 = *ecmpl2+rdotv2(mhard, &rhs->rv, _state); + ncmpl2 = ncmpl2+mhard; + + /* + * Compute scales + */ + *sdual = ae_maxreal(*sdual, rmaxabsv(mflex, ¤tvars->yp, _state), _state); + *sdual = ae_maxreal(*sdual, rmaxabsv(mflex, ¤tvars->yl, _state), _state); + *sdual = ae_maxreal(*sdual, rmaxabsv(mflex, ¤tvars->yu, _state), _state); + *sdual = ae_maxreal(*sdual, rmaxabsv(mhard, ¤tvars->yv, _state), _state); + v = rmaxabsv(np, ¤tvars->zlp, _state); + *sdual = ae_maxreal(*sdual, v, _state); + *scmpl = ae_maxreal(*scmpl, v, _state); + v = rmaxabsv(np, ¤tvars->zup, _state); + *sdual = ae_maxreal(*sdual, v, _state); + *scmpl = ae_maxreal(*scmpl, v, _state); + v = rmaxabsv(mflex, ¤tvars->zls, _state); + *sdual = ae_maxreal(*sdual, v, _state); + *scmpl = ae_maxreal(*scmpl, v, _state); + v = rmaxabsv(mflex, ¤tvars->zus, _state); + *sdual = ae_maxreal(*sdual, v, _state); + *scmpl = ae_maxreal(*scmpl, v, _state); + *sprim = ae_maxreal(*sprim/(double)1000, (double)(1), _state); + *sdual = ae_maxreal(*sdual/(double)1000, (double)(1), _state); + *scmpl = ae_maxreal(*scmpl/(double)1000, (double)(1), _state); + + /* + * Done + */ + *eprim2 = ae_sqrt(*eprim2/coalesce((double)(nprim2), (double)(1), _state), _state); + *edual2 = ae_sqrt(*edual2/coalesce((double)(ndual2), (double)(1), _state), _state); + *ecmpl2 = ae_sqrt(*ecmpl2/coalesce((double)(ncmpl2), (double)(1), _state), _state); + ae_nxpool_recycle(&state->mnx1pool, &tmp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Compute residual from the candidate solution for the already compute RHS: + + RHS := RHS - [SYSTEM]*delta + +Inputs include current location, candidate solution Delta and precomputed +products H*Delta.XP, J*Delta.XP, J'*Delta.Y + +Returns inf-norm of the residual. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm_computeupdateresidual(gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + double lambdatouse, + const gipmvars* delta, + /* Real */ const ae_vector* hdxp, + /* Real */ const ae_vector* jdxp, + /* Real */ const ae_vector* jtdy, + gipmrhs* rhs, + ae_state *_state) +{ + ae_int_t mflex; + ae_int_t mhard; + ae_int_t np; + ae_int_t i; + double nu; + double lambdatau; + double result; + + + mflex = currentvars->mflex; + mhard = currentvars->mhard; + np = currentvars->np; + nu = gipm_getnu(currentmu, _state); + lambdatau = lambdatouse+currentmu*gipm_damptau; + result = (double)(0); + + /* + * Update RP := RP - (Hmod+L+TAU)*d_xp - (J'*d_yp + Jv'*d_yv) + d_zlp - d_zup + * RS := RS + d_yp - d_yl - d_yu + * RGL := RGL + d_yl + d_zls + * RGU := RGU - d_yu + d_zus + * + */ + raddv(np, -1.0, hdxp, &rhs->rp, _state); + raddv(np, -lambdatau, &delta->xp, &rhs->rp, _state); + raddv(np, -1.0, jtdy, &rhs->rp, _state); + raddv(np, 1.0, &delta->zlp, &rhs->rp, _state); + raddv(np, -1.0, &delta->zup, &rhs->rp, _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rp, _state), _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->rs.ptr.p_double[i] = rhs->rs.ptr.p_double[i]+delta->yp.ptr.p_double[i]-delta->yl.ptr.p_double[i]-delta->yu.ptr.p_double[i]; + } + } + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rs, _state), _state); + raddv(mflex, 1.0, &delta->yl, &rhs->rgl, _state); + raddv(mflex, 1.0, &delta->zls, &rhs->rgl, _state); + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rgl, _state), _state); + raddv(mflex, -1.0, &delta->yu, &rhs->rgu, _state); + raddv(mflex, 1.0, &delta->zus, &rhs->rgu, _state); + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rgu, _state), _state); + + /* + * Update RLP := RLP - ZLP*dxp-(XP-BL)*dzlp + * RUP := RUP + ZUP*dxp-(BU-XP)*dzup + */ + for(i=0; i<=np-1; i++) + { + rhs->rlp.ptr.p_double[i] = rhs->rlp.ptr.p_double[i]-currentvars->zlp.ptr.p_double[i]*delta->xp.ptr.p_double[i]-(currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i])*delta->zlp.ptr.p_double[i]; + rhs->rup.ptr.p_double[i] = rhs->rup.ptr.p_double[i]+currentvars->zup.ptr.p_double[i]*delta->xp.ptr.p_double[i]-(state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i])*delta->zup.ptr.p_double[i]; + } + result = ae_maxreal(result, rmaxabsv(np, &rhs->rlp, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rup, _state), _state); + + /* + * Update RY := RY-J*d_xp + d_xs + nu*d_yp + */ + for(i=0; i<=mflex-1; i++) + { + rhs->ry.ptr.p_double[i] = rhs->ry.ptr.p_double[i]-jdxp->ptr.p_double[i]+nu*delta->yp.ptr.p_double[i]; + if( !state->isequality.ptr.p_bool[i] ) + { + rhs->ry.ptr.p_double[i] = rhs->ry.ptr.p_double[i]+delta->xs.ptr.p_double[i]; + } + } + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->ry, _state), _state); + + /* + * Update RCL := RCL - ELS*(dxs - dgl - nu*dyl) + * RCU := RCU - EUS*(dxs + dgu - nu*dyu) + */ + for(i=0; i<=mflex-1; i++) + { + rhs->rcl.ptr.p_double[i] = rhs->rcl.ptr.p_double[i]-state->els.ptr.p_double[i]*(delta->xs.ptr.p_double[i]-delta->gl.ptr.p_double[i]-nu*delta->yl.ptr.p_double[i]); + rhs->rcu.ptr.p_double[i] = rhs->rcu.ptr.p_double[i]-state->eus.ptr.p_double[i]*(delta->xs.ptr.p_double[i]+delta->gu.ptr.p_double[i]-nu*delta->yu.ptr.p_double[i]); + } + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rcl, _state), _state); + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rcu, _state), _state); + + /* + * Update RLS := RLS-(GL*d_zls + ZLS*d_gl) + * RUS := RUS-(GU*d_zus + ZUS*d_gu) + */ + for(i=0; i<=mflex-1; i++) + { + rhs->rls.ptr.p_double[i] = rhs->rls.ptr.p_double[i]-(currentvars->gl.ptr.p_double[i]*delta->zls.ptr.p_double[i]+currentvars->zls.ptr.p_double[i]*delta->gl.ptr.p_double[i]); + rhs->rus.ptr.p_double[i] = rhs->rus.ptr.p_double[i]-(currentvars->gu.ptr.p_double[i]*delta->zus.ptr.p_double[i]+currentvars->zus.ptr.p_double[i]*delta->gu.ptr.p_double[i]); + } + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rls, _state), _state); + result = ae_maxreal(result, rmaxabsv(mflex, &rhs->rus, _state), _state); + + /* + * Update RV := RV - (YV*Jv*d_xp - (vu-v(xp))*d_yv) + */ + for(i=0; i<=mhard-1; i++) + { + rhs->rv.ptr.p_double[i] = rhs->rv.ptr.p_double[i]-(currentvars->yv.ptr.p_double[i]*jdxp->ptr.p_double[mflex+i]-(state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i])*delta->yv.ptr.p_double[i]); + } + result = ae_maxreal(result, rmaxabsv(mhard, &rhs->rv, _state), _state); + return result; +} + + +/************************************************************************* +Transforms nonsymmetric primal-dual Newtom system into a symmetric condensed form + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_condenselhs(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + gipmcondensedsystem* c, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double nu; + double smallnumber; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + nu = gipm_getnu(currentmu, _state); + smallnumber = ae_sqrt((double)1/ae_maxrealnumber, _state); + rallocv(mhard, &c->d1v, _state); + for(i=0; i<=mhard-1; i++) + { + c->d1v.ptr.p_double[i] = -(state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i])/currentvars->yv.ptr.p_double[i]; + } + rallocv(mflex, &c->t0, _state); + rallocv(mflex, &c->t1, _state); + rallocv(mflex, &c->t2, _state); + rallocv(mflex, &c->t3, _state); + rallocv(mflex, &c->ta, _state); + rallocv(mflex, &c->d1, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + c->t0.ptr.p_double[i] = currentvars->zls.ptr.p_double[i]/(smallnumber+currentvars->gl.ptr.p_double[i]); + c->t1.ptr.p_double[i] = currentvars->zus.ptr.p_double[i]/(smallnumber+currentvars->gu.ptr.p_double[i]); + c->t2.ptr.p_double[i] = (double)1/((double)1+nu*c->t0.ptr.p_double[i]); + c->t3.ptr.p_double[i] = (double)1/((double)1+nu*c->t1.ptr.p_double[i]); + c->ta.ptr.p_double[i] = (double)1/(c->t2.ptr.p_double[i]*c->t0.ptr.p_double[i]+c->t3.ptr.p_double[i]*c->t1.ptr.p_double[i]); + c->d1.ptr.p_double[i] = -c->ta.ptr.p_double[i]-nu; + } + else + { + c->d1.ptr.p_double[i] = -nu; + } + } + rallocv(np, &c->t4, _state); + rallocv(np, &c->t5, _state); + rallocv(np, &c->d0, _state); + for(i=0; i<=np-1; i++) + { + c->t4.ptr.p_double[i] = (double)1/(currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i]); + c->t5.ptr.p_double[i] = (double)1/(state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]); + c->d0.ptr.p_double[i] = state->lambdav+currentmu*gipm_damptau+c->t4.ptr.p_double[i]*currentvars->zlp.ptr.p_double[i]+c->t5.ptr.p_double[i]*currentvars->zup.ptr.p_double[i]; + } +} + + +/************************************************************************* +Condense only right-hand-side using already condensed left hand side. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_condenserhs(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + const gipmrhs* rhs, + gipmcondensedsystem* c, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double invgli; + double invgui; + double smallnumber; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + smallnumber = ae_sqrt((double)1/ae_maxrealnumber, _state); + rallocv(mhard, &c->wyv, _state); + for(i=0; i<=mhard-1; i++) + { + c->wyv.ptr.p_double[i] = rhs->rv.ptr.p_double[i]/currentvars->yv.ptr.p_double[i]; + } + rallocv(mflex, &c->tls, _state); + rallocv(mflex, &c->tus, _state); + rallocv(mflex, &c->tgl, _state); + rallocv(mflex, &c->tgu, _state); + rallocv(mflex, &c->ts, _state); + rallocv(mflex, &c->wy, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + invgli = (double)1/(smallnumber+currentvars->gl.ptr.p_double[i]); + invgui = (double)1/(smallnumber+currentvars->gu.ptr.p_double[i]); + c->tls.ptr.p_double[i] = rhs->rls.ptr.p_double[i]+currentvars->zls.ptr.p_double[i]*rhs->rcl.ptr.p_double[i]; + c->tus.ptr.p_double[i] = rhs->rus.ptr.p_double[i]-currentvars->zus.ptr.p_double[i]*rhs->rcu.ptr.p_double[i]; + c->tgl.ptr.p_double[i] = rhs->rgl.ptr.p_double[i]+invgli*c->tls.ptr.p_double[i]; + c->tgu.ptr.p_double[i] = rhs->rgu.ptr.p_double[i]+invgui*c->tus.ptr.p_double[i]; + c->ts.ptr.p_double[i] = rhs->rs.ptr.p_double[i]-c->t3.ptr.p_double[i]*c->tgu.ptr.p_double[i]+c->t2.ptr.p_double[i]*c->tgl.ptr.p_double[i]; + c->wy.ptr.p_double[i] = rhs->ry.ptr.p_double[i]+c->ta.ptr.p_double[i]*c->ts.ptr.p_double[i]; + } + else + { + c->wy.ptr.p_double[i] = rhs->ry.ptr.p_double[i]; + } + } + rallocv(np, &c->wx, _state); + for(i=0; i<=np-1; i++) + { + c->wx.ptr.p_double[i] = rhs->rp.ptr.p_double[i]+c->t4.ptr.p_double[i]*rhs->rlp.ptr.p_double[i]-c->t5.ptr.p_double[i]*rhs->rup.ptr.p_double[i]; + } +} + + +/************************************************************************* +Unpack reply to Request=1002 into a solution to the original primal-dual system. +Returns maximum over step components; + +Delta must be properly allocated GIPMVars; however, initial values of +its variables are ignored. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_unpacksolution(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + const gipmrhs* rhs, + gipmcondensedsystem* c, + /* Real */ const ae_vector* replysol, + gipmvars* delta, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double v0; + double v1; + double nu; + double invgli; + double invgui; + double smallnumber; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + nu = gipm_getnu(currentmu, _state); + smallnumber = ae_sqrt((double)1/ae_maxrealnumber, _state); + rcopyvx(np, &state->replysol, 0, &delta->xp, 0, _state); + rcopyvx(mflex, &state->replysol, np, &delta->yp, 0, _state); + rcopyvx(mhard, &state->replysol, np+mflex, &delta->yv, 0, _state); + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + invgli = (double)1/(smallnumber+currentvars->gl.ptr.p_double[i]); + invgui = (double)1/(smallnumber+currentvars->gu.ptr.p_double[i]); + delta->xs.ptr.p_double[i] = c->ta.ptr.p_double[i]*(c->ts.ptr.p_double[i]+delta->yp.ptr.p_double[i]); + delta->yl.ptr.p_double[i] = c->t2.ptr.p_double[i]*(c->t0.ptr.p_double[i]*delta->xs.ptr.p_double[i]-c->tgl.ptr.p_double[i]); + delta->yu.ptr.p_double[i] = c->t3.ptr.p_double[i]*(c->t1.ptr.p_double[i]*delta->xs.ptr.p_double[i]+c->tgu.ptr.p_double[i]); + v0 = delta->xs.ptr.p_double[i]-nu*delta->yl.ptr.p_double[i]; + v1 = delta->xs.ptr.p_double[i]-nu*delta->yu.ptr.p_double[i]; + delta->zls.ptr.p_double[i] = invgli*c->tls.ptr.p_double[i]-c->t0.ptr.p_double[i]*v0; + delta->zus.ptr.p_double[i] = invgui*c->tus.ptr.p_double[i]+c->t1.ptr.p_double[i]*v1; + delta->gl.ptr.p_double[i] = state->els.ptr.p_double[i]*(v0-rhs->rcl.ptr.p_double[i]); + delta->gu.ptr.p_double[i] = state->eus.ptr.p_double[i]*(rhs->rcu.ptr.p_double[i]-v1); + } + else + { + delta->xs.ptr.p_double[i] = (double)(0); + delta->yl.ptr.p_double[i] = (double)(0); + delta->yu.ptr.p_double[i] = (double)(0); + delta->zls.ptr.p_double[i] = (double)(0); + delta->zus.ptr.p_double[i] = (double)(0); + delta->gl.ptr.p_double[i] = (double)(0); + delta->gu.ptr.p_double[i] = (double)(0); + } + } + for(i=0; i<=np-1; i++) + { + delta->zlp.ptr.p_double[i] = c->t4.ptr.p_double[i]*(rhs->rlp.ptr.p_double[i]-currentvars->zlp.ptr.p_double[i]*delta->xp.ptr.p_double[i]); + delta->zup.ptr.p_double[i] = c->t5.ptr.p_double[i]*(rhs->rup.ptr.p_double[i]+currentvars->zup.ptr.p_double[i]*delta->xp.ptr.p_double[i]); + } +} + + +/************************************************************************* +Compute barrier function, L2 penalty and complementarity errors + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_barrierpenaltyandcmplerror(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + double* barrierf, + double* penaltyf, + double* cmplerr, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double nu; + double relaxby; + + *barrierf = 0.0; + *penaltyf = 0.0; + *cmplerr = 0.0; + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + relaxby = ae_minreal(gipm_relaxfactor*currentmu, gipm_maxrelaxation, _state); + nu = gipm_getnu(currentmu, _state); + + /* + * Compute fmod(xp,mu) and barrier terms with respect to primal variables XP + */ + *barrierf = currentfj->fi.ptr.p_double[0]+0.5*currentmu*gipm_damptau*rdotv2(np, ¤tvars->xp, _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + *barrierf = *barrierf-currentmu*ae_log(currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i], _state); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + *barrierf = *barrierf-currentmu*ae_log(state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i], _state); + } + } + + /* + * Handle barrier terms on primal variables GL and GU + */ + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + *barrierf = *barrierf-currentmu*ae_log(currentvars->gl.ptr.p_double[i], _state); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + *barrierf = *barrierf-currentmu*ae_log(currentvars->gu.ptr.p_double[i], _state); + } + } + } + + /* + * Handle barrier terms on 'hard' constraints V() + */ + for(i=0; i<=mhard-1; i++) + { + *barrierf = *barrierf-currentmu*ae_log(state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i], _state); + } + + /* + * Handle penalty for violation of equality constraints c(xp)-xs=0, xs-gl=cl-rlx*mu, xs+gu=cu+rlx*mu + */ + *penaltyf = 0.0; + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + *penaltyf = *penaltyf+0.5*ae_sqr(currentfj->fi.ptr.p_double[1+i]-currentvars->xs.ptr.p_double[i]-nu*currentvars->yp.ptr.p_double[i], _state); + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + *penaltyf = *penaltyf+0.5*ae_sqr(currentvars->xs.ptr.p_double[i]-currentvars->gl.ptr.p_double[i]-state->finitebndlx.ptr.p_double[np+i]-nu*currentvars->yl.ptr.p_double[i]+relaxby, _state); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + *penaltyf = *penaltyf+0.5*ae_sqr(currentvars->xs.ptr.p_double[i]+currentvars->gu.ptr.p_double[i]-state->finitebndux.ptr.p_double[np+i]-nu*currentvars->yu.ptr.p_double[i]-relaxby, _state); + } + } + else + { + *penaltyf = *penaltyf+0.5*ae_sqr(currentfj->fi.ptr.p_double[1+i]-state->finitebndux.ptr.p_double[np+i]-nu*currentvars->yp.ptr.p_double[i], _state); + } + } + + /* + * Compute complementarity error + */ + *cmplerr = (double)(0); + for(i=0; i<=np-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + *cmplerr = *cmplerr+ae_sqr((currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i])*currentvars->zlp.ptr.p_double[i]-currentmu, _state); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + *cmplerr = *cmplerr+ae_sqr((state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i])*currentvars->zup.ptr.p_double[i]-currentmu, _state); + } + } + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + *cmplerr = *cmplerr+ae_sqr(currentvars->gl.ptr.p_double[i]*currentvars->zls.ptr.p_double[i]-currentmu, _state); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + *cmplerr = *cmplerr+ae_sqr(currentvars->gu.ptr.p_double[i]*currentvars->zus.ptr.p_double[i]-currentmu, _state); + } + } + } +} + + +/************************************************************************* +Merit function V0 + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm_meritv0(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double nu; + double relaxby; + double penaltyf; + double result; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + relaxby = ae_minreal(gipm_relaxfactor*currentmu, gipm_maxrelaxation, _state); + nu = gipm_getnu(currentmu, _state); + + /* + * Compute fmod(xp,mu) and barrier terms with respect to primal variables XP + */ + result = currentfj->fi.ptr.p_double[0]+0.5*currentmu*gipm_damptau*rdotv2(np, ¤tvars->xp, _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + result = result-currentmu*ae_log(currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i], _state); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + result = result-currentmu*ae_log(state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i], _state); + } + } + + /* + * Handle barrier terms on primal variables GL and GU + */ + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + result = result-currentmu*ae_log(currentvars->gl.ptr.p_double[i], _state); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + result = result-currentmu*ae_log(currentvars->gu.ptr.p_double[i], _state); + } + } + } + + /* + * Handle barrier terms on 'hard' constraints V() + */ + for(i=0; i<=mhard-1; i++) + { + result = result-currentmu*ae_log(state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i], _state); + } + + /* + * Handle penalty for violation of equality constraints c(xp)-xs=0, xs-gl=cl-rlx*mu, xs+gu=cu+rlx*mu + */ + penaltyf = 0.0; + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + penaltyf = penaltyf+0.5*ae_sqr(currentfj->fi.ptr.p_double[1+i]-currentvars->xs.ptr.p_double[i], _state); + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + penaltyf = penaltyf+0.5*ae_sqr(currentvars->xs.ptr.p_double[i]-currentvars->gl.ptr.p_double[i]-state->finitebndlx.ptr.p_double[np+i]+relaxby, _state); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + penaltyf = penaltyf+0.5*ae_sqr(currentvars->xs.ptr.p_double[i]+currentvars->gu.ptr.p_double[i]-state->finitebndux.ptr.p_double[np+i]-relaxby, _state); + } + } + else + { + penaltyf = penaltyf+0.5*ae_sqr(currentfj->fi.ptr.p_double[1+i]-state->finitebndux.ptr.p_double[np+i], _state); + } + } + result = result+penaltyf/((double)2*nu); + return result; +} + + +/************************************************************************* +Merit function V0 + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm_meritfunctionpd(const gipmstate* state, + const gipmvars* currentvars, + const varsfuncjac* currentfj, + double currentmu, + ae_state *_state) +{ + double v; + double vv; + ae_int_t np; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t i; + double nu; + double relaxby; + double penaltyf; + double invmu; + double result; + + + np = state->nraw; + mflex = state->mflex; + mhard = state->mhard; + relaxby = ae_minreal(gipm_relaxfactor*currentmu, gipm_maxrelaxation, _state); + nu = gipm_getnu(currentmu, _state); + invmu = (double)1/currentmu; + + /* + * Compute fmod(xp,mu) and barrier terms with respect to primal variables XP + */ + result = currentfj->fi.ptr.p_double[0]+0.5*currentmu*gipm_damptau*rdotv2(np, ¤tvars->xp, _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndlx.ptr.p_bool[i] ) + { + v = currentvars->xp.ptr.p_double[i]-state->finitebndlx.ptr.p_double[i]; + vv = v*currentvars->zlp.ptr.p_double[i]*invmu; + result = result-currentmu*(ae_log(v, _state)+gipm_dualmeritnu*(ae_log(vv, _state)+(double)1-vv)); + } + if( state->hasbndux.ptr.p_bool[i] ) + { + v = state->finitebndux.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]; + vv = v*currentvars->zup.ptr.p_double[i]*invmu; + result = result-currentmu*(ae_log(v, _state)+gipm_dualmeritnu*(ae_log(vv, _state)+(double)1-vv)); + } + } + + /* + * Handle barrier terms on primal variables GL and GU + */ + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + v = currentvars->gl.ptr.p_double[i]; + vv = v*currentvars->zls.ptr.p_double[i]*invmu; + result = result-currentmu*(ae_log(v, _state)+gipm_dualmeritnu*(ae_log(vv, _state)+(double)1-vv)); + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + v = currentvars->gu.ptr.p_double[i]; + vv = v*currentvars->zus.ptr.p_double[i]*invmu; + result = result-currentmu*(ae_log(v, _state)+gipm_dualmeritnu*(ae_log(vv, _state)+(double)1-vv)); + } + } + } + + /* + * Handle barrier terms on 'hard' constraints V() + */ + for(i=0; i<=mhard-1; i++) + { + v = state->finitebndux.ptr.p_double[np+mflex+i]-currentfj->fi.ptr.p_double[1+mflex+i]; + vv = v*currentvars->yv.ptr.p_double[i]*invmu; + result = result-currentmu*(ae_log(v, _state)+gipm_dualmeritnu*(ae_log(vv, _state)+(double)1-vv)); + } + + /* + * Handle penalty for violation of equality constraints c(xp)-xs=0, xs-gl=cl-rlx*mu, xs+gu=cu+rlx*mu + */ + penaltyf = 0.0; + for(i=0; i<=mflex-1; i++) + { + if( !state->isequality.ptr.p_bool[i] ) + { + v = currentfj->fi.ptr.p_double[1+i]-currentvars->xs.ptr.p_double[i]; + vv = v+nu*currentvars->yp.ptr.p_double[i]; + penaltyf = penaltyf+0.5*v*v+gipm_dualmeritnu*vv*vv; + if( state->hasbndlx.ptr.p_bool[np+i] ) + { + v = currentvars->xs.ptr.p_double[i]-currentvars->gl.ptr.p_double[i]-state->finitebndlx.ptr.p_double[np+i]+relaxby; + vv = v+nu*currentvars->yl.ptr.p_double[i]; + penaltyf = penaltyf+0.5*v*v+gipm_dualmeritnu*vv*vv; + } + if( state->hasbndux.ptr.p_bool[np+i] ) + { + v = currentvars->xs.ptr.p_double[i]+currentvars->gu.ptr.p_double[i]-state->finitebndux.ptr.p_double[np+i]-relaxby; + vv = v+nu*currentvars->yu.ptr.p_double[i]; + penaltyf = penaltyf+0.5*v*v+gipm_dualmeritnu*vv*vv; + } + } + else + { + v = currentfj->fi.ptr.p_double[1+i]-state->finitebndux.ptr.p_double[np+i]; + vv = v+nu*currentvars->yp.ptr.p_double[i]; + penaltyf = penaltyf+0.5*v*v+gipm_dualmeritnu*vv*vv; + } + } + result = result+penaltyf/((double)2*nu); + return result; +} + + +/************************************************************************* +Prepare quasi-Newton update information + + -- ALGLIB -- + Copyright 11.04.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm_preparequasinewtonupdate(gipmstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t mflex; + ae_int_t mhard; + ae_int_t np; + ae_vector tmp0; + + ae_frame_make(_state, &_frame_block); + memset(&tmp0, 0, sizeof(tmp0)); + ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true); + + mflex = state->mflex; + mhard = state->mhard; + np = state->nraw; + ae_nxpool_retrieve(&state->mnx1pool, &tmp0, _state); + ae_assert(tmp0.cnt>=mflex+mhard+1, "GIPM: integrity check 943226 failed", _state); + tmp0.ptr.p_double[0] = (double)(1); + rcopyvx(mflex, &state->trial.yp, 0, &tmp0, 1, _state); + rcopyvx(mhard, &state->trial.yv, 0, &tmp0, 1+mflex, _state); + rmergemulv(1+mflex+mhard, &state->qnmask, &tmp0, _state); + rsetallocv(4*np, 0.0, &state->querydata, _state); + rcopyvx(np, &state->current.xp, 0, &state->querydata, 0*np, _state); + rcopyvx(np, &state->trial.xp, 0, &state->querydata, 1*np, _state); + ae_assert(!state->currentfj.isdense&&!state->trialfj.isdense, "GIPM: integrity check 418223 failed", _state); + sparsegemv(&state->currentfj.sj, 1.0, 1, &tmp0, 0, 0.0, &state->querydata, 2*np, _state); + raddvx(np, gipm_damptau*state->mu, &state->current.xp, 0, &state->querydata, 2*np, _state); + sparsegemv(&state->trialfj.sj, 1.0, 1, &tmp0, 0, 0.0, &state->querydata, 3*np, _state); + raddvx(np, gipm_damptau*state->mu, &state->trial.xp, 0, &state->querydata, 3*np, _state); + ae_nxpool_recycle(&state->mnx1pool, &tmp0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Computes minimum nonzero value of the vector. Returns 0 if all components +are nonpositive. + +INPUT PARAMETERS: + X - vector + N - length + + -- ALGLIB -- + Copyright 01.11.2020 by Bochkanov Sergey +*************************************************************************/ +static double gipm_minabsnz(/* Real */ const ae_vector* x, + ae_int_t n1, + ae_state *_state) +{ + ae_int_t n0; + ae_int_t i; + ae_bool nz; + double result; + + + result = (double)(0); + n0 = 0; + nz = ae_false; + for(i=n0; i<=n1-1; i++) + { + if( ae_fp_neq(x->ptr.p_double[i],(double)(0)) ) + { + if( !nz ) + { + result = ae_fabs(x->ptr.p_double[i], _state); + nz = ae_true; + } + else + { + result = ae_minreal(result, ae_fabs(x->ptr.p_double[i], _state), _state); + } + } + } + return result; +} + + +/************************************************************************* +Compute safeguard BndLP/UP from FiniteBndLX/UX. + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_safeboundsfromfinitetightened(gipmstate* state, + ae_state *_state) +{ + ae_int_t nraw; + ae_int_t i; + double vmid; + double v; + + + nraw = state->nraw; + rallocv(nraw, &state->safeguardbndlp, _state); + rallocv(nraw, &state->safeguardbndup, _state); + v = (double)10*ae_machineepsilon; + for(i=0; i<=nraw-1; i++) + { + + /* + * Safeguard bounds on primal variables and check interval width + */ + vmid = 0.5*(state->finitebndlx.ptr.p_double[i]+state->finitebndux.ptr.p_double[i]); + state->safeguardbndlp.ptr.p_double[i] = ae_minreal(state->finitebndlx.ptr.p_double[i]+ae_maxreal(ae_fabs(state->finitebndlx.ptr.p_double[i], _state), 1.0, _state)*v, vmid, _state); + state->safeguardbndup.ptr.p_double[i] = ae_maxreal(state->finitebndux.ptr.p_double[i]-ae_maxreal(ae_fabs(state->finitebndux.ptr.p_double[i], _state), 1.0, _state)*v, vmid, _state); + ae_assert(ae_fp_greater_eq(state->safeguardbndup.ptr.p_double[i],state->safeguardbndlp.ptr.p_double[i]), "GIPM: bounds on primal variables are too tight, bad problem preprocessing", _state); + } +} + + +/************************************************************************* +Tightens/relaxes bounds, recomputes safeguarded BndLP/UP if necessary. + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm_tightenrelaxbounds(gipmstate* state, ae_state *_state) +{ + ae_int_t nraw; + ae_int_t mflex; + ae_int_t nxf; + ae_int_t ntightened; + ae_int_t nrelaxed; + ae_int_t i; + double xpnrm; + double xsnrm; + double vtgt; + double vrlx; + double vmid; + double vx; + double vnrm; + double vprev; + double targetdist; + + + ae_assert(ae_fp_less(gipm_relaxdist,gipm_tightendist), "GIPM: integrity check 1821 failed", _state); + targetdist = ae_sqrt(gipm_relaxdist*gipm_tightendist, _state); + nraw = state->nraw; + mflex = state->mflex; + nxf = nraw+mflex; + xpnrm = ae_maxreal(rmaxabsv(nraw, &state->current.xp, _state), (double)(1), _state); + xsnrm = ae_maxreal(rmaxabsv(mflex, &state->current.xs, _state), (double)(1), _state); + ntightened = 0; + nrelaxed = 0; + for(i=0; i<=nxf-1; i++) + { + if( iisequality.ptr.p_bool[i-nraw] ) + { + + /* + * Variable value and distance scaling factor + */ + if( icurrent.xp.ptr.p_double[i]; + vnrm = xpnrm; + } + else + { + vx = state->current.xs.ptr.p_double[i-nraw]; + vnrm = xsnrm; + } + if( state->hasbndlx.ptr.p_bool[i] ) + { + vtgt = ae_maxreal(vx-vnrm*gipm_tightendist, state->bndlx.ptr.p_double[i], _state); + vrlx = ae_maxreal(vx-vnrm*gipm_relaxdist, state->bndlx.ptr.p_double[i], _state); + vmid = ae_maxreal(vx-vnrm*targetdist, state->bndlx.ptr.p_double[i], _state); + vprev = state->finitebndlx.ptr.p_double[i]; + if( ae_fp_less(state->finitebndlx.ptr.p_double[i],vtgt) ) + { + state->finitebndlx.ptr.p_double[i] = vmid; + ntightened = ntightened+1; + } + if( ae_fp_greater(state->finitebndlx.ptr.p_double[i],vrlx) ) + { + state->finitebndlx.ptr.p_double[i] = vmid; + nrelaxed = nrelaxed+1; + } + if( i>=nraw ) + { + state->current.gl.ptr.p_double[i-nraw] = ae_maxreal(state->current.gl.ptr.p_double[i-nraw]-(state->finitebndlx.ptr.p_double[i]-vprev), ae_machineepsilon, _state); + } + } + if( state->hasbndux.ptr.p_bool[i] ) + { + vtgt = ae_minreal(vx+vnrm*gipm_tightendist, state->bndux.ptr.p_double[i], _state); + vrlx = ae_minreal(vx+vnrm*gipm_relaxdist, state->bndux.ptr.p_double[i], _state); + vmid = ae_minreal(vx+vnrm*targetdist, state->bndux.ptr.p_double[i], _state); + vprev = state->finitebndux.ptr.p_double[i]; + if( ae_fp_greater(state->finitebndux.ptr.p_double[i],vtgt) ) + { + state->finitebndux.ptr.p_double[i] = vmid; + ntightened = ntightened+1; + } + if( ae_fp_less(state->finitebndux.ptr.p_double[i],vrlx) ) + { + state->finitebndux.ptr.p_double[i] = vmid; + nrelaxed = nrelaxed+1; + } + if( i>=nraw ) + { + state->current.gu.ptr.p_double[i-nraw] = ae_maxreal(state->current.gu.ptr.p_double[i-nraw]-(vprev-state->finitebndux.ptr.p_double[i]), ae_machineepsilon, _state); + } + } + } + } + gipm_safeboundsfromfinitetightened(state, _state); + if( state->dotrace&&nrelaxed+ntightened>0 ) + { + ae_trace("> %0d bounds tightened, %0d bounds relaxed\n", + (int)(ntightened), + (int)(nrelaxed)); + } +} + + +/************************************************************************* +Compute recommended penalty coefficient Nu + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm_getnu(double currentmu, ae_state *_state) +{ + double result; + + + result = ae_minreal(currentmu/gipm_penaltygrowth, gipm_maxnu*ae_maxreal(currentmu, (double)(1), _state), _state); + return result; +} + + +/************************************************************************* +Initialize memory for nonmonotonic merit function optimization + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm_nonmonotonicinit(gipmstate* state, + ae_int_t memlen, + double merit0, + ae_state *_state) +{ + + + ae_assert(memlen>=0, "GIPM: integrity check 696157 failed", _state); + state->nonmonotonicmemlen = memlen; + state->nonmonotonicpos = 0; + rsetallocv(memlen+1, merit0, &state->nonmonotonicmerit, _state); + state->nonmonotonicmerit.ptr.p_double[memlen] = merit0; +} + + +/************************************************************************* +Push new value to the nonmonotonic memory + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm_nonmonotonicpush(gipmstate* state, + double meritv, + ae_state *_state) +{ + + + state->nonmonotonicmerit.ptr.p_double[state->nonmonotonicpos] = meritv; + state->nonmonotonicpos = (state->nonmonotonicpos+1)%(state->nonmonotonicmemlen+1); +} + + +/************************************************************************* +Returns nonmonotonic correction that should be added to MeritV + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static double gipm_nonmonotonicgetcorr(gipmstate* state, + double meritv, + ae_state *_state) +{ + ae_int_t i; + double mx; + double result; + + + mx = meritv; + for(i=0; i<=state->nonmonotonicmemlen; i++) + { + mx = ae_maxreal(mx, state->nonmonotonicmerit.ptr.p_double[i], _state); + } + result = ae_maxreal(mx-meritv, 0.0, _state); + return result; +} + + +void _gipmvars_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipmvars *p = (gipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zlp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zls, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zus, 0, DT_REAL, _state, make_automatic); +} + + +void _gipmvars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipmvars *dst = (gipmvars*)_dst; + const gipmvars *src = (const gipmvars*)_src; + dst->np = src->np; + dst->nf = src->nf; + dst->mflex = src->mflex; + dst->mhard = src->mhard; + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_vector_init_copy(&dst->zlp, &src->zlp, _state, make_automatic); + ae_vector_init_copy(&dst->zup, &src->zup, _state, make_automatic); + ae_vector_init_copy(&dst->yp, &src->yp, _state, make_automatic); + ae_vector_init_copy(&dst->yl, &src->yl, _state, make_automatic); + ae_vector_init_copy(&dst->yu, &src->yu, _state, make_automatic); + ae_vector_init_copy(&dst->yv, &src->yv, _state, make_automatic); + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + ae_vector_init_copy(&dst->gl, &src->gl, _state, make_automatic); + ae_vector_init_copy(&dst->gu, &src->gu, _state, make_automatic); + ae_vector_init_copy(&dst->zls, &src->zls, _state, make_automatic); + ae_vector_init_copy(&dst->zus, &src->zus, _state, make_automatic); +} + + +void _gipmvars_clear(void* _p) +{ + gipmvars *p = (gipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->zlp); + ae_vector_clear(&p->zup); + ae_vector_clear(&p->yp); + ae_vector_clear(&p->yl); + ae_vector_clear(&p->yu); + ae_vector_clear(&p->yv); + ae_vector_clear(&p->xs); + ae_vector_clear(&p->gl); + ae_vector_clear(&p->gu); + ae_vector_clear(&p->zls); + ae_vector_clear(&p->zus); +} + + +void _gipmvars_destroy(void* _p) +{ + gipmvars *p = (gipmvars*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->zlp); + ae_vector_destroy(&p->zup); + ae_vector_destroy(&p->yp); + ae_vector_destroy(&p->yl); + ae_vector_destroy(&p->yu); + ae_vector_destroy(&p->yv); + ae_vector_destroy(&p->xs); + ae_vector_destroy(&p->gl); + ae_vector_destroy(&p->gu); + ae_vector_destroy(&p->zls); + ae_vector_destroy(&p->zus); +} + + +void _gipmrhs_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipmrhs *p = (gipmrhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rgu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ry, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rcl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rcu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rlp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rls, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rus, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rv, 0, DT_REAL, _state, make_automatic); +} + + +void _gipmrhs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipmrhs *dst = (gipmrhs*)_dst; + const gipmrhs *src = (const gipmrhs*)_src; + ae_vector_init_copy(&dst->rp, &src->rp, _state, make_automatic); + ae_vector_init_copy(&dst->rs, &src->rs, _state, make_automatic); + ae_vector_init_copy(&dst->rgl, &src->rgl, _state, make_automatic); + ae_vector_init_copy(&dst->rgu, &src->rgu, _state, make_automatic); + ae_vector_init_copy(&dst->ry, &src->ry, _state, make_automatic); + ae_vector_init_copy(&dst->rcl, &src->rcl, _state, make_automatic); + ae_vector_init_copy(&dst->rcu, &src->rcu, _state, make_automatic); + ae_vector_init_copy(&dst->rlp, &src->rlp, _state, make_automatic); + ae_vector_init_copy(&dst->rup, &src->rup, _state, make_automatic); + ae_vector_init_copy(&dst->rls, &src->rls, _state, make_automatic); + ae_vector_init_copy(&dst->rus, &src->rus, _state, make_automatic); + ae_vector_init_copy(&dst->rv, &src->rv, _state, make_automatic); +} + + +void _gipmrhs_clear(void* _p) +{ + gipmrhs *p = (gipmrhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rp); + ae_vector_clear(&p->rs); + ae_vector_clear(&p->rgl); + ae_vector_clear(&p->rgu); + ae_vector_clear(&p->ry); + ae_vector_clear(&p->rcl); + ae_vector_clear(&p->rcu); + ae_vector_clear(&p->rlp); + ae_vector_clear(&p->rup); + ae_vector_clear(&p->rls); + ae_vector_clear(&p->rus); + ae_vector_clear(&p->rv); +} + + +void _gipmrhs_destroy(void* _p) +{ + gipmrhs *p = (gipmrhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rp); + ae_vector_destroy(&p->rs); + ae_vector_destroy(&p->rgl); + ae_vector_destroy(&p->rgu); + ae_vector_destroy(&p->ry); + ae_vector_destroy(&p->rcl); + ae_vector_destroy(&p->rcu); + ae_vector_destroy(&p->rlp); + ae_vector_destroy(&p->rup); + ae_vector_destroy(&p->rls); + ae_vector_destroy(&p->rus); + ae_vector_destroy(&p->rv); +} + + +void _gipmcondensedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipmcondensedsystem *p = (gipmcondensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->tls, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tus, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tgu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ts, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t3, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t4, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->t5, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wyv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d1v, 0, DT_REAL, _state, make_automatic); +} + + +void _gipmcondensedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipmcondensedsystem *dst = (gipmcondensedsystem*)_dst; + const gipmcondensedsystem *src = (const gipmcondensedsystem*)_src; + ae_vector_init_copy(&dst->tls, &src->tls, _state, make_automatic); + ae_vector_init_copy(&dst->tus, &src->tus, _state, make_automatic); + ae_vector_init_copy(&dst->tgl, &src->tgl, _state, make_automatic); + ae_vector_init_copy(&dst->tgu, &src->tgu, _state, make_automatic); + ae_vector_init_copy(&dst->ts, &src->ts, _state, make_automatic); + ae_vector_init_copy(&dst->ta, &src->ta, _state, make_automatic); + ae_vector_init_copy(&dst->t0, &src->t0, _state, make_automatic); + ae_vector_init_copy(&dst->t1, &src->t1, _state, make_automatic); + ae_vector_init_copy(&dst->t2, &src->t2, _state, make_automatic); + ae_vector_init_copy(&dst->t3, &src->t3, _state, make_automatic); + ae_vector_init_copy(&dst->t4, &src->t4, _state, make_automatic); + ae_vector_init_copy(&dst->t5, &src->t5, _state, make_automatic); + ae_vector_init_copy(&dst->wx, &src->wx, _state, make_automatic); + ae_vector_init_copy(&dst->wy, &src->wy, _state, make_automatic); + ae_vector_init_copy(&dst->wyv, &src->wyv, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_vector_init_copy(&dst->d1, &src->d1, _state, make_automatic); + ae_vector_init_copy(&dst->d1v, &src->d1v, _state, make_automatic); +} + + +void _gipmcondensedsystem_clear(void* _p) +{ + gipmcondensedsystem *p = (gipmcondensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->tls); + ae_vector_clear(&p->tus); + ae_vector_clear(&p->tgl); + ae_vector_clear(&p->tgu); + ae_vector_clear(&p->ts); + ae_vector_clear(&p->ta); + ae_vector_clear(&p->t0); + ae_vector_clear(&p->t1); + ae_vector_clear(&p->t2); + ae_vector_clear(&p->t3); + ae_vector_clear(&p->t4); + ae_vector_clear(&p->t5); + ae_vector_clear(&p->wx); + ae_vector_clear(&p->wy); + ae_vector_clear(&p->wyv); + ae_vector_clear(&p->d0); + ae_vector_clear(&p->d1); + ae_vector_clear(&p->d1v); +} + + +void _gipmcondensedsystem_destroy(void* _p) +{ + gipmcondensedsystem *p = (gipmcondensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->tls); + ae_vector_destroy(&p->tus); + ae_vector_destroy(&p->tgl); + ae_vector_destroy(&p->tgu); + ae_vector_destroy(&p->ts); + ae_vector_destroy(&p->ta); + ae_vector_destroy(&p->t0); + ae_vector_destroy(&p->t1); + ae_vector_destroy(&p->t2); + ae_vector_destroy(&p->t3); + ae_vector_destroy(&p->t4); + ae_vector_destroy(&p->t5); + ae_vector_destroy(&p->wx); + ae_vector_destroy(&p->wy); + ae_vector_destroy(&p->wyv); + ae_vector_destroy(&p->d0); + ae_vector_destroy(&p->d1); + ae_vector_destroy(&p->d1v); +} + + +void _gipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipmstate *p = (gipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndlx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndux, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndlx, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndux, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isequality, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->qnmask, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->replysol, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyprod, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->elp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->els, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eus, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndlx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndux, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->safeguardbndlp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->safeguardbndup, 0, DT_REAL, _state, make_automatic); + _gipmvars_init(&p->current, _state, make_automatic); + _gipmvars_init(&p->best, _state, make_automatic); + _varsfuncjac_init(&p->currentfj, _state, make_automatic); + _varsfuncjac_init(&p->bestfj, _state, make_automatic); + _nlpfilter_init(&p->filter, _state, make_automatic); + ae_vector_init(&p->nonmonotonicmerit, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + ae_nxpool_init(&p->mnx1pool, DT_REAL, _state, make_automatic); + _gipmrhs_init(&p->rhs, _state, make_automatic); + _gipmcondensedsystem_init(&p->condensed, _state, make_automatic); + _gipmvars_init(&p->delta, _state, make_automatic); + _gipmvars_init(&p->corr, _state, make_automatic); + ae_vector_init(&p->tmphdxp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpjdxp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpjtdy, 0, DT_REAL, _state, make_automatic); + _gipmvars_init(&p->trial, _state, make_automatic); + _varsfuncjac_init(&p->trialfj, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _gipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipmstate *dst = (gipmstate*)_dst; + const gipmstate *src = (const gipmstate*)_src; + dst->nraw = src->nraw; + dst->mflex = src->mflex; + dst->mhard = src->mhard; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->bndlx, &src->bndlx, _state, make_automatic); + ae_vector_init_copy(&dst->bndux, &src->bndux, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndlx, &src->hasbndlx, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndux, &src->hasbndux, _state, make_automatic); + ae_vector_init_copy(&dst->isequality, &src->isequality, _state, make_automatic); + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + dst->isfirstorder = src->isfirstorder; + ae_vector_init_copy(&dst->qnmask, &src->qnmask, _state, make_automatic); + dst->isqnmasknonzero = src->isqnmasknonzero; + dst->trustradxp = src->trustradxp; + dst->mudependent = src->mudependent; + dst->eps = src->eps; + dst->maxits = src->maxits; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + dst->querymu = src->querymu; + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->replysol, &src->replysol, _state, make_automatic); + ae_vector_init_copy(&dst->replyprod, &src->replyprod, _state, make_automatic); + dst->hasjac = src->hasjac; + dst->factsuccess = src->factsuccess; + ae_vector_init_copy(&dst->elp, &src->elp, _state, make_automatic); + ae_vector_init_copy(&dst->eup, &src->eup, _state, make_automatic); + ae_vector_init_copy(&dst->els, &src->els, _state, make_automatic); + ae_vector_init_copy(&dst->eus, &src->eus, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndlx, &src->finitebndlx, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndux, &src->finitebndux, _state, make_automatic); + ae_vector_init_copy(&dst->safeguardbndlp, &src->safeguardbndlp, _state, make_automatic); + ae_vector_init_copy(&dst->safeguardbndup, &src->safeguardbndup, _state, make_automatic); + dst->nrmx0 = src->nrmx0; + dst->absf0 = src->absf0; + dst->mu = src->mu; + dst->lambdav = src->lambdav; + dst->lambdadecay = src->lambdadecay; + dst->subsequentfactfailures = src->subsequentfactfailures; + _gipmvars_init_copy(&dst->current, &src->current, _state, make_automatic); + _gipmvars_init_copy(&dst->best, &src->best, _state, make_automatic); + _varsfuncjac_init_copy(&dst->currentfj, &src->currentfj, _state, make_automatic); + _varsfuncjac_init_copy(&dst->bestfj, &src->bestfj, _state, make_automatic); + dst->besterr = src->besterr; + dst->rhsstagnationcounter = src->rhsstagnationcounter; + dst->filterready = src->filterready; + _nlpfilter_init_copy(&dst->filter, &src->filter, _state, make_automatic); + dst->dotrace = src->dotrace; + dst->dodetailedtrace = src->dodetailedtrace; + dst->dolaconictrace = src->dolaconictrace; + dst->nonmonotonicmemlen = src->nonmonotonicmemlen; + dst->nonmonotonicpos = src->nonmonotonicpos; + ae_vector_init_copy(&dst->nonmonotonicmerit, &src->nonmonotonicmerit, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + ae_nxpool_init_copy(&dst->mnx1pool, &src->mnx1pool, _state, make_automatic); + _gipmrhs_init_copy(&dst->rhs, &src->rhs, _state, make_automatic); + _gipmcondensedsystem_init_copy(&dst->condensed, &src->condensed, _state, make_automatic); + _gipmvars_init_copy(&dst->delta, &src->delta, _state, make_automatic); + _gipmvars_init_copy(&dst->corr, &src->corr, _state, make_automatic); + ae_vector_init_copy(&dst->tmphdxp, &src->tmphdxp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpjdxp, &src->tmpjdxp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpjtdy, &src->tmpjtdy, _state, make_automatic); + _gipmvars_init_copy(&dst->trial, &src->trial, _state, make_automatic); + _varsfuncjac_init_copy(&dst->trialfj, &src->trialfj, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _gipmstate_clear(void* _p) +{ + gipmstate *p = (gipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->bndlx); + ae_vector_clear(&p->bndux); + ae_vector_clear(&p->hasbndlx); + ae_vector_clear(&p->hasbndux); + ae_vector_clear(&p->isequality); + ae_vector_clear(&p->fscales); + ae_vector_clear(&p->qnmask); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->replysol); + ae_vector_clear(&p->replyprod); + ae_vector_clear(&p->elp); + ae_vector_clear(&p->eup); + ae_vector_clear(&p->els); + ae_vector_clear(&p->eus); + ae_vector_clear(&p->finitebndlx); + ae_vector_clear(&p->finitebndux); + ae_vector_clear(&p->safeguardbndlp); + ae_vector_clear(&p->safeguardbndup); + _gipmvars_clear(&p->current); + _gipmvars_clear(&p->best); + _varsfuncjac_clear(&p->currentfj); + _varsfuncjac_clear(&p->bestfj); + _nlpfilter_clear(&p->filter); + ae_vector_clear(&p->nonmonotonicmerit); + _stimer_clear(&p->timertotal); + ae_nxpool_clear(&p->mnx1pool); + _gipmrhs_clear(&p->rhs); + _gipmcondensedsystem_clear(&p->condensed); + _gipmvars_clear(&p->delta); + _gipmvars_clear(&p->corr); + ae_vector_clear(&p->tmphdxp); + ae_vector_clear(&p->tmpjdxp); + ae_vector_clear(&p->tmpjtdy); + _gipmvars_clear(&p->trial); + _varsfuncjac_clear(&p->trialfj); + _rcommstate_clear(&p->rstate); +} + + +void _gipmstate_destroy(void* _p) +{ + gipmstate *p = (gipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->bndlx); + ae_vector_destroy(&p->bndux); + ae_vector_destroy(&p->hasbndlx); + ae_vector_destroy(&p->hasbndux); + ae_vector_destroy(&p->isequality); + ae_vector_destroy(&p->fscales); + ae_vector_destroy(&p->qnmask); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->replysol); + ae_vector_destroy(&p->replyprod); + ae_vector_destroy(&p->elp); + ae_vector_destroy(&p->eup); + ae_vector_destroy(&p->els); + ae_vector_destroy(&p->eus); + ae_vector_destroy(&p->finitebndlx); + ae_vector_destroy(&p->finitebndux); + ae_vector_destroy(&p->safeguardbndlp); + ae_vector_destroy(&p->safeguardbndup); + _gipmvars_destroy(&p->current); + _gipmvars_destroy(&p->best); + _varsfuncjac_destroy(&p->currentfj); + _varsfuncjac_destroy(&p->bestfj); + _nlpfilter_destroy(&p->filter); + ae_vector_destroy(&p->nonmonotonicmerit); + _stimer_destroy(&p->timertotal); + ae_nxpool_destroy(&p->mnx1pool); + _gipmrhs_destroy(&p->rhs); + _gipmcondensedsystem_destroy(&p->condensed); + _gipmvars_destroy(&p->delta); + _gipmvars_destroy(&p->corr); + ae_vector_destroy(&p->tmphdxp); + ae_vector_destroy(&p->tmpjdxp); + ae_vector_destroy(&p->tmpjtdy); + _gipmvars_destroy(&p->trial); + _varsfuncjac_destroy(&p->trialfj); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function canonicalizes conic constraints by adding slack variables +and linear equality constraints in order to transform the problem into a +canonic form (all conic constraints are axis-orthogonal, ConeType>=0, any +constraint can be made strictly feasible by shifting one/several variables +without disturbing other constraints. + +The function can add new variables and modify scales/origin/constraints. + +The function must be called (if necessary) prior to initializing the GQPIPM +solver, so that it receives modified constraints. + + -- ALGLIB -- + Copyright 11.09.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipmcanonicalizeconicconstraints(/* Real */ ae_vector* s, + /* Real */ ae_vector* xorigin, + /* Real */ ae_vector* b, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + /* Real */ ae_vector* xs, + sparsematrix* sparseh, + ae_bool hupper, + ae_bool hash, + ae_int_t* n, + sparsematrix* a, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t* m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + /* Real */ ae_vector* lagbcmin, + /* Real */ ae_vector* lagbcmax, + ae_state *_state) +{ + ae_frame _frame_block; + xconicconstraint *cci; + ae_smart_ptr _cci; + ae_int_t coneidx; + ae_int_t nv; + ae_int_t i; + ae_int_t j; + ae_int_t newnradial; + ae_int_t newaxial; + ae_vector impliedbndl; + ae_vector impliedbndu; + ae_vector isconicradial; + ae_vector isconicaxial; + ae_vector cntradial; + ae_vector cntupwardaxial; + ae_vector cntdownwardaxial; + double initprimdual; + double vbnd; + double ccscale; + ae_bool needslacks; + ae_bool donecc; + ae_int_t axisidx; + ae_int_t kpow; + double a0; + double a1; + double b0; + double b1; + double rhs; + double tmpr; + ae_int_t tmpi; + + ae_frame_make(_state, &_frame_block); + memset(&_cci, 0, sizeof(_cci)); + memset(&impliedbndl, 0, sizeof(impliedbndl)); + memset(&impliedbndu, 0, sizeof(impliedbndu)); + memset(&isconicradial, 0, sizeof(isconicradial)); + memset(&isconicaxial, 0, sizeof(isconicaxial)); + memset(&cntradial, 0, sizeof(cntradial)); + memset(&cntupwardaxial, 0, sizeof(cntupwardaxial)); + memset(&cntdownwardaxial, 0, sizeof(cntdownwardaxial)); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_vector_init(&impliedbndl, 0, DT_REAL, _state, ae_true); + ae_vector_init(&impliedbndu, 0, DT_REAL, _state, ae_true); + ae_vector_init(&isconicradial, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&isconicaxial, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&cntradial, 0, DT_INT, _state, ae_true); + ae_vector_init(&cntupwardaxial, 0, DT_INT, _state, ae_true); + ae_vector_init(&cntdownwardaxial, 0, DT_INT, _state, ae_true); + + initprimdual = gipmgetinitprimdual(_state); + rsetallocv(*n, _state->v_neginf, &impliedbndl, _state); + rsetallocv(*n, _state->v_posinf, &impliedbndu, _state); + rsetallocv(*n, -ae_maxrealnumber, lagbcmin, _state); + rsetallocv(*n, ae_maxrealnumber, lagbcmax, _state); + for(coneidx=0; coneidx<=xccgetcount(xcc, _state)-1; coneidx++) + { + ae_obj_array_get(&xcc->constraints, coneidx, &_cci, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + if( cci->conetype==xccgenericorthogonalconetype(_state) ) + { + tagsortmiddleirr(&cci->varidx, &cci->diaga, &cci->shftc, 0, nv-1, _state); + newnradial = 0; + for(i=0; i<=nv-2; i++) + { + if( ae_fp_eq(cci->diaga.ptr.p_double[i],0.0) ) + { + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]+cci->shftc.ptr.p_double[i]*cci->shftc.ptr.p_double[i]; + continue; + } + if( newnradial>0&&cci->varidx.ptr.p_int[i]==cci->varidx.ptr.p_int[newnradial-1] ) + { + a0 = cci->diaga.ptr.p_double[newnradial-1]; + b0 = cci->shftc.ptr.p_double[newnradial-1]; + a1 = cci->diaga.ptr.p_double[i]; + b1 = cci->shftc.ptr.p_double[i]; + cci->diaga.ptr.p_double[newnradial-1] = ae_sqrt(a0*a0+a1*a1, _state); + ae_assert(ae_fp_greater(cci->diaga.ptr.p_double[newnradial-1],(double)(0)), "GQPIPM: integrity check 248622 failed", _state); + cci->shftc.ptr.p_double[newnradial-1] = (a0*b0+a1*b1)/cci->diaga.ptr.p_double[newnradial-1]; + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]+ae_maxreal(b0*b0+b1*b1-cci->shftc.ptr.p_double[newnradial-1]*cci->shftc.ptr.p_double[newnradial-1], 0.0, _state); + continue; + } + cci->varidx.ptr.p_int[newnradial] = cci->varidx.ptr.p_int[i]; + cci->diaga.ptr.p_double[newnradial] = cci->diaga.ptr.p_double[i]; + cci->shftc.ptr.p_double[newnradial] = cci->shftc.ptr.p_double[i]; + newnradial = newnradial+1; + } + cci->varidx.ptr.p_int[newnradial] = cci->varidx.ptr.p_int[nv-1]; + cci->diaga.ptr.p_double[newnradial] = cci->diaga.ptr.p_double[nv-1]; + cci->shftc.ptr.p_double[newnradial] = cci->shftc.ptr.p_double[nv-1]; + newnradial = newnradial+1; + cci->shftc.ptr.p_double[newnradial] = cci->shftc.ptr.p_double[nv]; + nv = newnradial; + cci->nvars = nv; + cci->conetype = xccprimitiveconetype(_state); + if( ibinarysearchispresent(&cci->varidx, 0, nv-1, cci->varidx.ptr.p_int[nv-1], _state) ) + { + cci->conetype = xccdenormalizedprimitiveconetype(_state); + } + continue; + } + if( cci->conetype==xccgenericorthogonalpowerconetype(_state) ) + { + kpow = cci->kpow; + newnradial = 0; + if( kpowvaridx, &cci->diaga, &cci->shftc, 0, nv-kpow, _state); + for(i=0; i<=nv-kpow-1; i++) + { + if( ae_fp_eq(cci->diaga.ptr.p_double[i],0.0) ) + { + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]+cci->shftc.ptr.p_double[i]*cci->shftc.ptr.p_double[i]; + continue; + } + if( newnradial>0&&cci->varidx.ptr.p_int[i]==cci->varidx.ptr.p_int[newnradial-1] ) + { + a0 = cci->diaga.ptr.p_double[newnradial-1]; + b0 = cci->shftc.ptr.p_double[newnradial-1]; + a1 = cci->diaga.ptr.p_double[i]; + b1 = cci->shftc.ptr.p_double[i]; + cci->diaga.ptr.p_double[newnradial-1] = ae_sqrt(a0*a0+a1*a1, _state); + ae_assert(ae_fp_greater(cci->diaga.ptr.p_double[newnradial-1],(double)(0)), "GQPIPM: integrity check 248622 failed", _state); + cci->shftc.ptr.p_double[newnradial-1] = (a0*b0+a1*b1)/cci->diaga.ptr.p_double[newnradial-1]; + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]+ae_maxreal(b0*b0+b1*b1-cci->shftc.ptr.p_double[newnradial-1]*cci->shftc.ptr.p_double[newnradial-1], 0.0, _state); + continue; + } + cci->varidx.ptr.p_int[newnradial] = cci->varidx.ptr.p_int[i]; + cci->diaga.ptr.p_double[newnradial] = cci->diaga.ptr.p_double[i]; + cci->shftc.ptr.p_double[newnradial] = cci->shftc.ptr.p_double[i]; + newnradial = newnradial+1; + } + } + newaxial = 0; + for(i=nv-kpow; i<=nv-1; i++) + { + cci->varidx.ptr.p_int[newnradial+newaxial] = cci->varidx.ptr.p_int[i]; + cci->diaga.ptr.p_double[newnradial+newaxial] = cci->diaga.ptr.p_double[i]; + cci->shftc.ptr.p_double[newnradial+newaxial] = cci->shftc.ptr.p_double[i]; + newaxial = newaxial+1; + } + cci->shftc.ptr.p_double[newnradial+newaxial] = cci->shftc.ptr.p_double[nv]; + nv = newnradial+newaxial; + cci->nvars = nv; + cci->conetype = xccdenormalizedprimitivepowerconetype(_state); + continue; + } + if( cci->conetype==xccprimitiveconetype(_state) ) + { + continue; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + continue; + } + ae_assert(ae_false, "GQPIPM: integrity check 227420 failed", _state); + } + bsetallocv(*n, ae_false, &isconicradial, _state); + bsetallocv(*n, ae_false, &isconicaxial, _state); + isetallocv(*n, 0, &cntradial, _state); + isetallocv(*n, 0, &cntupwardaxial, _state); + isetallocv(*n, 0, &cntdownwardaxial, _state); + for(coneidx=0; coneidx<=xccgetcount(xcc, _state)-1; coneidx++) + { + ae_obj_array_get(&xcc->constraints, coneidx, &_cci, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + if( cci->conetype==xccdenormalizedprimitiveconetype(_state)||cci->conetype==xccprimitiveconetype(_state) ) + { + for(i=0; i<=nv-2; i++) + { + cntradial.ptr.p_int[cci->varidx.ptr.p_int[i]] = cntradial.ptr.p_int[cci->varidx.ptr.p_int[i]]+1; + } + if( ae_fp_greater(cci->diaga.ptr.p_double[nv-1],(double)(0)) ) + { + cntupwardaxial.ptr.p_int[cci->varidx.ptr.p_int[nv-1]] = cntupwardaxial.ptr.p_int[cci->varidx.ptr.p_int[nv-1]]+1; + } + if( ae_fp_less(cci->diaga.ptr.p_double[nv-1],(double)(0)) ) + { + cntdownwardaxial.ptr.p_int[cci->varidx.ptr.p_int[nv-1]] = cntdownwardaxial.ptr.p_int[cci->varidx.ptr.p_int[nv-1]]+1; + } + continue; + } + if( cci->conetype==xccdenormalizedprimitivepowerconetype(_state)||cci->conetype==xccprimitivepowerconetype(_state) ) + { + kpow = cci->kpow; + for(i=0; i<=nv-kpow-1; i++) + { + cntradial.ptr.p_int[cci->varidx.ptr.p_int[i]] = cntradial.ptr.p_int[cci->varidx.ptr.p_int[i]]+1; + } + for(i=nv-kpow; i<=nv-1; i++) + { + if( ae_fp_greater(cci->diaga.ptr.p_double[i],(double)(0)) ) + { + cntupwardaxial.ptr.p_int[cci->varidx.ptr.p_int[i]] = cntupwardaxial.ptr.p_int[cci->varidx.ptr.p_int[i]]+1; + } + if( ae_fp_less(cci->diaga.ptr.p_double[i],(double)(0)) ) + { + cntdownwardaxial.ptr.p_int[cci->varidx.ptr.p_int[i]] = cntdownwardaxial.ptr.p_int[cci->varidx.ptr.p_int[i]]+1; + } + } + continue; + } + ae_assert(ae_false, "GQPIPM: integrity check 397122 failed", _state); + } + for(coneidx=0; coneidx<=xccgetcount(xcc, _state)-1; coneidx++) + { + ae_obj_array_get(&xcc->constraints, coneidx, &_cci, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + ae_assert(!donecc, "GQIPM: integrity check 267115 failed", _state); + needslacks = ae_false; + ccscale = (double)(0); + for(i=0; i<=nv-1; i++) + { + ccscale = ae_maxreal(ccscale, ae_fabs(cci->diaga.ptr.p_double[i]*s->ptr.p_double[cci->varidx.ptr.p_int[i]], _state), _state); + } + ccscale = ae_maxreal(ccscale, (double)(1), _state); + axisidx = cci->varidx.ptr.p_int[nv-1]; + a0 = cci->diaga.ptr.p_double[nv-1]; + b0 = cci->shftc.ptr.p_double[nv-1]; + needslacks = (needslacks||ae_fp_eq(ccscale,(double)(0)))||ae_fp_less_eq(ae_fabs(a0*s->ptr.p_double[axisidx], _state),gqpipm_minconicdenominator*ccscale); + needslacks = needslacks||ibinarysearchispresent(&cci->varidx, 0, nv-1, axisidx, _state); + needslacks = needslacks||((ae_isfinite(bndl->ptr.p_double[axisidx], _state)&&ae_isfinite(bndu->ptr.p_double[axisidx], _state))&&ae_fp_less_eq(bndu->ptr.p_double[axisidx]-bndl->ptr.p_double[axisidx],gqpipm_tootightconstraints*s->ptr.p_double[axisidx])); + if( !needslacks ) + { + vbnd = -b0/a0; + if( ae_fp_greater(a0,(double)(0)) ) + { + if( !ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx]) ) + { + bndl->ptr.p_double[axisidx] = vbnd; + lagbcmin->ptr.p_double[axisidx] = 0.0; + } + } + else + { + if( !ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx]) ) + { + bndu->ptr.p_double[axisidx] = vbnd; + lagbcmax->ptr.p_double[axisidx] = 0.0; + } + } + continue; + } + } + if( cci->conetype==xccdenormalizedprimitiveconetype(_state)||cci->conetype==xccprimitiveconetype(_state) ) + { + ae_assert(!donecc, "GQIPM: integrity check 314116 failed", _state); + a0 = cci->diaga.ptr.p_double[nv-1]; + b0 = cci->shftc.ptr.p_double[nv-1]; + axisidx = cci->varidx.ptr.p_int[nv-1]; + rgrowappendv(*n+1, s, s->ptr.p_double[axisidx], _state); + rgrowappendv(*n+1, xorigin, 0.0, _state); + rgrowappendv(*n+1, b, 0.0, _state); + rgrowappendv(*n+1, bndl, 0.0, _state); + rgrowappendv(*n+1, bndu, _state->v_posinf, _state); + rgrowappendv(*n+1, xs, initprimdual, _state); + if( hash ) + { + ae_assert(sparseh->n==(*n)&&sparseh->m==(*n), "GQPIPM: integrity check 243517 failed", _state); + sparseh->n = sparseh->n+1; + sparseappendemptyrow(sparseh, _state); + } + if( *m==0 ) + { + sparsecreatecrsemptybuf(*n, a, _state); + } + ae_assert(a->n==(*n)&&a->m==(*m), "GQPIPM: integrity check 243517 failed", _state); + a->n = *n+1; + sparseappendemptyrow(a, _state); + sparseappendelement(a, axisidx, -a0, _state); + sparseappendelement(a, *n, 1.0, _state); + rhs = cci->shftc.ptr.p_double[nv-1]; + if( cci->applyorigin ) + { + rhs = rhs-a0*xorigin->ptr.p_double[axisidx]; + } + rgrowappendv(*m+1, al, rhs, _state); + rgrowappendv(*m+1, au, rhs, _state); + rgrowappendv(*n+1, lagbcmin, -ae_maxrealnumber, _state); + rgrowappendv(*n+1, lagbcmax, ae_maxrealnumber, _state); + rgrowappendv(*n+1, &impliedbndl, 0.0, _state); + rgrowappendv(*n+1, &impliedbndu, _state->v_posinf, _state); + bgrowappendv(*n+1, &isconicradial, ae_false, _state); + bgrowappendv(*n+1, &isconicaxial, ae_true, _state); + cci->diaga.ptr.p_double[nv-1] = 1.0; + cci->shftc.ptr.p_double[nv-1] = 0.0; + cci->varidx.ptr.p_int[nv-1] = *n; + if( ae_fp_neq(a0,(double)(0))&&ae_fp_less(ae_fabs(b0/a0, _state),gqpipm_bigboxconstraint*s->ptr.p_double[axisidx]) ) + { + vbnd = -b0/a0; + if( (ae_fp_greater(a0,(double)(0))&&(!ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx])))&&(!ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx]-gqpipm_tootightconstraints*s->ptr.p_double[axisidx])) ) + { + bndl->ptr.p_double[axisidx] = vbnd; + lagbcmin->ptr.p_double[axisidx] = 0.0; + } + if( (ae_fp_less(a0,(double)(0))&&(!ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx])))&&(!ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx]+gqpipm_tootightconstraints*s->ptr.p_double[axisidx])) ) + { + bndu->ptr.p_double[axisidx] = vbnd; + lagbcmax->ptr.p_double[axisidx] = 0.0; + } + } + if( ae_fp_greater(a0,(double)(0)) ) + { + ae_assert(cntupwardaxial.ptr.p_int[axisidx]>0, "GQPIPM: integrity check 395304 failed", _state); + cntupwardaxial.ptr.p_int[axisidx] = cntupwardaxial.ptr.p_int[axisidx]-1; + igrowappendv(*n+1, &cntupwardaxial, 1, _state); + } + if( ae_fp_less(a0,(double)(0)) ) + { + ae_assert(cntdownwardaxial.ptr.p_int[axisidx]>0, "GQPIPM: integrity check 400305 failed", _state); + cntdownwardaxial.ptr.p_int[axisidx] = cntdownwardaxial.ptr.p_int[axisidx]-1; + igrowappendv(*n+1, &cntdownwardaxial, 1, _state); + } + cci->conetype = xccprimitiveconetype(_state); + *n = *n+1; + *m = *m+1; + donecc = ae_true; + } + if( cci->conetype==xccdenormalizedprimitivepowerconetype(_state)||cci->conetype==xccprimitivepowerconetype(_state) ) + { + ae_assert(!donecc, "GQIPM: integrity check 497219 failed", _state); + kpow = cci->kpow; + ccscale = (double)(0); + for(i=0; i<=nv-kpow-1; i++) + { + ccscale = ae_maxreal(ccscale, ae_fabs(cci->diaga.ptr.p_double[i]*s->ptr.p_double[cci->varidx.ptr.p_int[i]], _state), _state); + } + ccscale = ae_maxreal(ccscale, (double)(1), _state); + for(i=nv-kpow; i<=nv-1; i++) + { + axisidx = cci->varidx.ptr.p_int[i]; + a0 = cci->diaga.ptr.p_double[i]; + b0 = cci->shftc.ptr.p_double[i]; + needslacks = ae_false; + needslacks = (needslacks||ae_fp_eq(ccscale,(double)(0)))||ae_fp_less_eq(ae_fabs(a0*s->ptr.p_double[axisidx], _state),gqpipm_minconicdenominator*ccscale); + needslacks = (needslacks||ibinarysearchispresent(&cci->varidx, 0, nv-kpow, axisidx, _state))||ilinearsearchispresent(&cci->varidx, nv-kpow, i, axisidx, _state); + needslacks = needslacks||((ae_isfinite(bndl->ptr.p_double[axisidx], _state)&&ae_isfinite(bndu->ptr.p_double[axisidx], _state))&&ae_fp_less_eq(bndu->ptr.p_double[axisidx]-bndl->ptr.p_double[axisidx],gqpipm_tootightconstraints*s->ptr.p_double[axisidx])); + if( !needslacks ) + { + vbnd = -b0/a0; + if( ae_fp_greater(a0,(double)(0)) ) + { + if( !ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx]) ) + { + bndl->ptr.p_double[axisidx] = vbnd; + lagbcmin->ptr.p_double[axisidx] = 0.0; + } + } + else + { + if( !ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx]) ) + { + bndu->ptr.p_double[axisidx] = vbnd; + lagbcmax->ptr.p_double[axisidx] = 0.0; + } + } + continue; + } + rgrowappendv(*n+1, s, s->ptr.p_double[axisidx], _state); + rgrowappendv(*n+1, xorigin, 0.0, _state); + rgrowappendv(*n+1, b, 0.0, _state); + rgrowappendv(*n+1, bndl, 0.0, _state); + rgrowappendv(*n+1, bndu, _state->v_posinf, _state); + rgrowappendv(*n+1, xs, initprimdual, _state); + if( hash ) + { + ae_assert(sparseh->n==(*n)&&sparseh->m==(*n), "GQPIPM: integrity check 567225 failed", _state); + sparseh->n = sparseh->n+1; + sparseappendemptyrow(sparseh, _state); + } + if( *m==0 ) + { + sparsecreatecrsemptybuf(*n, a, _state); + } + ae_assert(a->n==(*n)&&a->m==(*m), "GQPIPM: integrity check 573226 failed", _state); + a->n = *n+1; + sparseappendemptyrow(a, _state); + sparseappendelement(a, axisidx, -a0, _state); + sparseappendelement(a, *n, 1.0, _state); + rhs = b0; + if( cci->applyorigin ) + { + rhs = rhs-a0*xorigin->ptr.p_double[axisidx]; + } + rgrowappendv(*m+1, al, rhs, _state); + rgrowappendv(*m+1, au, rhs, _state); + rgrowappendv(*n+1, lagbcmin, -ae_maxrealnumber, _state); + rgrowappendv(*n+1, lagbcmax, ae_maxrealnumber, _state); + rgrowappendv(*n+1, &impliedbndl, 0.0, _state); + rgrowappendv(*n+1, &impliedbndu, _state->v_posinf, _state); + bgrowappendv(*n+1, &isconicradial, ae_false, _state); + bgrowappendv(*n+1, &isconicaxial, ae_true, _state); + cci->diaga.ptr.p_double[i] = 1.0; + cci->shftc.ptr.p_double[i] = 0.0; + cci->varidx.ptr.p_int[i] = *n; + if( ae_fp_neq(a0,(double)(0))&&ae_fp_less(ae_fabs(b0/a0, _state),gqpipm_bigboxconstraint*s->ptr.p_double[axisidx]) ) + { + vbnd = -b0/a0; + if( (ae_fp_greater(a0,(double)(0))&&(!ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx])))&&(!ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx]-gqpipm_tootightconstraints*s->ptr.p_double[axisidx])) ) + { + bndl->ptr.p_double[axisidx] = vbnd; + lagbcmin->ptr.p_double[axisidx] = 0.0; + } + if( (ae_fp_less(a0,(double)(0))&&(!ae_isfinite(bndu->ptr.p_double[axisidx], _state)||ae_fp_less(vbnd,bndu->ptr.p_double[axisidx])))&&(!ae_isfinite(bndl->ptr.p_double[axisidx], _state)||ae_fp_greater(vbnd,bndl->ptr.p_double[axisidx]+gqpipm_tootightconstraints*s->ptr.p_double[axisidx])) ) + { + bndu->ptr.p_double[axisidx] = vbnd; + lagbcmax->ptr.p_double[axisidx] = 0.0; + } + } + if( ae_fp_greater(a0,(double)(0)) ) + { + ae_assert(cntupwardaxial.ptr.p_int[axisidx]>0, "GQPIPM: integrity check 395304 failed", _state); + cntupwardaxial.ptr.p_int[axisidx] = cntupwardaxial.ptr.p_int[axisidx]-1; + igrowappendv(*n+1, &cntupwardaxial, 1, _state); + } + if( ae_fp_less(a0,(double)(0)) ) + { + ae_assert(cntdownwardaxial.ptr.p_int[axisidx]>0, "GQPIPM: integrity check 400305 failed", _state); + cntdownwardaxial.ptr.p_int[axisidx] = cntdownwardaxial.ptr.p_int[axisidx]-1; + igrowappendv(*n+1, &cntdownwardaxial, 1, _state); + } + *n = *n+1; + *m = *m+1; + } + for(i=nv-kpow; i<=nv-2; i++) + { + for(j=i; j<=nv-2; j++) + { + if( cci->varidx.ptr.p_int[j]>cci->varidx.ptr.p_int[j+1] ) + { + tmpi = cci->varidx.ptr.p_int[j]; + cci->varidx.ptr.p_int[j] = cci->varidx.ptr.p_int[j+1]; + cci->varidx.ptr.p_int[j+1] = tmpi; + tmpr = cci->diaga.ptr.p_double[j]; + cci->diaga.ptr.p_double[j] = cci->diaga.ptr.p_double[j+1]; + cci->diaga.ptr.p_double[j+1] = tmpr; + tmpr = cci->shftc.ptr.p_double[j]; + cci->shftc.ptr.p_double[j] = cci->shftc.ptr.p_double[j+1]; + cci->shftc.ptr.p_double[j+1] = tmpr; + tmpr = cci->alphapow.ptr.p_double[j-(nv-kpow)]; + cci->alphapow.ptr.p_double[j-(nv-kpow)] = cci->alphapow.ptr.p_double[j+1-(nv-kpow)]; + cci->alphapow.ptr.p_double[j+1-(nv-kpow)] = tmpr; + } + } + } + cci->conetype = xccprimitivepowerconetype(_state); + donecc = ae_true; + } + ae_assert(donecc, "GQPIPM: integrity check 218502 failed (unexpected cone type and/or barrier type)", _state); + } + xqcupdaten(xqc, *n, _state); + xccupdaten(xcc, *n, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Initialize GQPIPM structure. + +X0 - initial point; must be: + * strictly feasible wrt non-equality box constraints + * non-strictly feasible wrt equality box constraints + * strictly feasible wrt conic constraints, if present + Failure to satisfy these properties will lead to an exception + generated either during initialization or during the very + first iteration. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x0, + ae_int_t n, + ae_bool isdense, + ae_bool isfirstorder, + double eps, + ae_int_t maxits, + gqpipmstate* state, + ae_state *_state) +{ + ae_int_t i; + double fixtol; + ae_bool bflg; + + + ae_assert(!(isdense&&isfirstorder), "QPIPM: dense problems do not support first order iteration, only second order one", _state); + fixtol = ae_maxreal(coalesce(eps, 0.01*ae_sqrt(ae_machineepsilon, _state), _state), ae_pow(ae_machineepsilon, 0.75, _state), _state); + state->algomode = gqpipm_amdense; + if( !isdense ) + { + state->algomode = icase2(isfirstorder, gqpipm_amhybrid, gqpipm_amsparse, _state); + } + state->basehrank = 0; + if( state->algomode==gqpipm_amhybrid ) + { + rsetallocv(n, 0.0, &state->basehsr1diag, _state); + } + state->n = n; + state->mlc = 0; + state->mqc = 0; + state->msocc = 0; + state->hessmemlen = 0; + state->hessmaxoffdiag = 0; + state->cvxobjective = 0; + state->cvxqc = 0; + state->cvxcc = 0; + xqcinit(n, &state->xqc, _state); + xccinit(n, &state->xcc, _state); + state->optionaldenseq1.hasdenseterm = ae_false; + ae_obj_array_clear(&state->optionaldensexqc); + state->fixedvarscnt = 0; + rsetallocv(n, _state->v_neginf, &state->wrkbndl, _state); + rsetallocv(n, _state->v_posinf, &state->wrkbndu, _state); + rsetallocv(n, -ae_sqrt(ae_maxrealnumber, _state), &state->finiterawbndl, _state); + rsetallocv(n, ae_sqrt(ae_maxrealnumber, _state), &state->finiterawbndu, _state); + bsetallocv(n, ae_false, &state->isfixed, _state); + iallocv(n, &state->fixedidx, _state); + rallocv(n, &state->x0, _state); + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state))&&ae_fp_less(bndu->ptr.p_double[i]-bndl->ptr.p_double[i],fixtol) ) + { + state->isfixed.ptr.p_bool[i] = ae_true; + state->fixedidx.ptr.p_int[state->fixedvarscnt] = i; + state->fixedvarscnt = state->fixedvarscnt+1; + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]; + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + state->wrkbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->finiterawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + state->wrkbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->finiterawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + } + rsetallocv(n, 0.0, &state->c, _state); + iallocv(n, &state->iotac, _state); + for(i=0; i<=n-1; i++) + { + state->iotac.ptr.p_int[i] = i; + } + state->nq = 0; + bflg = ae_false; + if( state->algomode==gqpipm_amdense ) + { + rsetallocm(n, n, 0.0, &state->denseq, _state); + bflg = ae_true; + } + if( state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid ) + { + state->sparseq1.m = n; + state->sparseq1.n = n; + iallocv(n+1, &state->sparseq1.ridx, _state); + iallocv(n, &state->sparseq1.idx, _state); + rallocv(n, &state->sparseq1.vals, _state); + for(i=0; i<=n-1; i++) + { + state->sparseq1.ridx.ptr.p_int[i] = i; + state->sparseq1.idx.ptr.p_int[i] = i; + state->sparseq1.vals.ptr.p_double[i] = 0.0; + } + state->sparseq1.ridx.ptr.p_int[n] = n; + sparsecreatecrsinplace(&state->sparseq1, _state); + bflg = ae_true; + } + ae_assert(bflg, "GQPIPM: 896235 failed", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "QPIPM: integrity check 9756 failed", _state); + state->eps = coalesce(eps, (double)10*ae_sqrt(ae_machineepsilon, _state), _state); + state->maxits = maxits; + state->pctype = 0; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->dolaconictrace = ae_is_trace_enabled("GENIPM.LACONIC"); + state->dotrace = ae_is_trace_enabled("GENIPM")&&!state->dolaconictrace; +} + + +/************************************************************************* +Set linear and quadratic terms + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipmsetquadraticlinear(gqpipmstate* state, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + /* Real */ const ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + + if( state->algomode==gqpipm_amdense ) + { + quadraticlinearconverttodenseltr(c, state->n, denseh, sparseh, hkind, ae_false, &state->c, &state->denseq, _state); + for(i=0; i<=state->n-1; i++) + { + for(j=0; j<=i-1; j++) + { + state->denseq.ptr.pp_double[j][i] = state->denseq.ptr.pp_double[i][j]; + } + } + for(i=state->n-1; i>=0; i--) + { + if( ae_fp_greater(rmaxabsr(state->n, &state->denseq, i, _state),(double)(0)) ) + { + state->nq = ae_maxint(state->nq, i+1, _state); + break; + } + } + } + else + { + ae_assert(state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid, "QPGIPM: integrity check 945236 failed", _state); + ae_assert(hkind==0||hkind==1, "QPGIPM: integrity check 5022 failed", _state); + rcopyv(state->n, c, &state->c, _state); + if( hkind==0 ) + { + sparsecreatecrsfromdensebuf(denseh, state->n, state->n, &state->sparseq1, _state); + } + if( hkind==1 ) + { + sparsecopytocrsbuf(sparseh, &state->sparseq1, _state); + } + rsetallocv(state->n, 0.0, &state->tmp0, _state); + for(i=0; i<=state->n-1; i++) + { + j0 = state->sparseq1.ridx.ptr.p_int[i]; + j1 = state->sparseq1.uidx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + if( ae_fp_neq(state->sparseq1.vals.ptr.p_double[jj],(double)(0)) ) + { + state->tmp0.ptr.p_double[i] = (double)(1); + state->tmp0.ptr.p_double[state->sparseq1.idx.ptr.p_int[jj]] = (double)(1); + } + } + } + for(i=state->n-1; i>=0; i--) + { + if( ae_fp_neq(state->tmp0.ptr.p_double[i],(double)(0)) ) + { + state->nq = ae_maxint(state->nq, i+1, _state); + break; + } + } + } +} + + +/************************************************************************* +Set linear constraints + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + SparseA - sparse constraint matrix, CRS format + CL, CU - lower and upper bounds for constraints + -INF <= CL[I] <= CU[I] <= +INF. + XQC - quadratic constraints + XCC - conic constraints + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipmsetconstraints(gqpipmstate* state, + const sparsematrix* sparsea, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + + n = state->n; + ae_assert(m>=0, "GQPIPMSetConstraints: M<0", _state); + ae_assert(m==0||((sparsea->matrixtype==1&&sparsea->m==m)&&sparsea->n==n), "GQPIPMSetConstraints: constraint matrix has incorrect size", _state); + ae_assert(cl->cnt>=m, "GQPIPMSetConstraints: CL is too short!", _state); + ae_assert(cu->cnt>=m, "GQPIPMSetConstraints: CU is too short!", _state); + state->mlc = m; + if( m>0 ) + { + sparsecopytocrsbuf(sparsea, &state->sparselc, _state); + rallocv(m, &state->lcbndl, _state); + rallocv(m, &state->lcbndu, _state); + for(i=0; i<=m-1; i++) + { + ae_assert(ae_isfinite(cl->ptr.p_double[i], _state)||ae_isneginf(cl->ptr.p_double[i], _state), "GQPIPMSetConstraints: CL is not finite number or -INF", _state); + ae_assert(ae_isfinite(cu->ptr.p_double[i], _state)||ae_isposinf(cu->ptr.p_double[i], _state), "GQPIPMSetConstraints: CU is not finite number or +INF", _state); + state->lcbndl.ptr.p_double[i] = cl->ptr.p_double[i]; + state->lcbndu.ptr.p_double[i] = cu->ptr.p_double[i]; + } + } + state->mqc = xqcgetcount(xqc, _state); + xqccopy(xqc, &state->xqc, _state); + for(i=0; i<=state->mqc-1; i++) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + for(j=0; j<=qci->nvars-1; j++) + { + j0 = qci->lowerq.ridx.ptr.p_int[j]; + j1 = qci->lowerq.didx.ptr.p_int[j]-1; + for(jj=j0; jj<=j1; jj++) + { + state->nq = ae_maxint(state->nq, qci->varidx.ptr.p_int[j], _state); + state->nq = ae_maxint(state->nq, qci->varidx.ptr.p_int[qci->lowerq.idx.ptr.p_int[jj]], _state); + } + } + } + state->msocc = xccgetcount(xcc, _state); + xcccopy(xcc, &state->xcc, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Set quasi-Newton parameters + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + MemLen - memory length + MaxOffdiag - threshold for moving quadratic terms to a + quasi-Newton approximation + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipmsetquasinewtonparams(gqpipmstate* state, + ae_int_t memlen, + ae_int_t maxoffdiag, + ae_state *_state) +{ + + + ae_assert(memlen>=0, "GQPIPMSetQuasiNewtonParams: MemLen<0", _state); + ae_assert(maxoffdiag>=0, "GQPIPMSetQuasiNewtonParams: MaxOffdiag<0", _state); + state->hessmemlen = memlen; + state->hessmaxoffdiag = maxoffdiag; +} + + +/************************************************************************* +Solve QP problem. + +INPUT PARAMETERS: + State - solver instance + +OUTPUT PARAMETERS: + XS - array[N], solution + LagBC - array[N], Lagrange multipliers for box constraints + LagLC - array[MLC], Lagrange multipliers for linear constraints + LagQC - array[MQC], Lagrange multipliers for quadratic constraints + TerminationType - completion code, positive values for success, + negative for failures (XS constrains best point + found so far): + * -2 the task is either unbounded or infeasible; + the IPM solver has difficulty distinguishing between these two. + * +1 stopping criteria are met + * +7 stopping criteria are too stringent + +RESULT: + +This function ALWAYS returns something meaningful in XS, LagBC, LagLC - +either solution or the best point so far, even for negative TerminationType. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gqpipmoptimize(gqpipmstate* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + ae_int_t* terminationtype, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t nnz; + double initprimdual; + ae_int_t mlc; + ae_int_t mtotal; + ae_int_t offslast; + ae_int_t offslc; + ae_int_t offsqc; + ae_int_t offscc; + ae_int_t offsec; + ae_bool remembered; + ae_bool factorized; + ae_bool donecc; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + *terminationtype = 0; + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + + n = state->n; + mlc = state->mlc; + offslast = 0; + mtotal = 0; + ae_nxpool_alloc(&state->nrealpool, n, _state); + rsetallocv(1, 1.0, &state->fscales, _state); + offslc = offslast; + offslast = offslast+mlc; + for(i=0; i<=mlc-1; i++) + { + rgrowv(mtotal+1, &state->totalnl, _state); + rgrowv(mtotal+1, &state->totalnu, _state); + state->totalnl.ptr.p_double[mtotal] = state->lcbndl.ptr.p_double[i]; + state->totalnu.ptr.p_double[mtotal] = state->lcbndu.ptr.p_double[i]; + rgrowv(1+mtotal+1, &state->fscales, _state); + state->fscales.ptr.p_double[1+mtotal] = 1.0; + mtotal = mtotal+1; + } + offsec = offslast; + offslast = offsec+state->fixedvarscnt; + for(i=0; i<=n-1; i++) + { + if( state->isfixed.ptr.p_bool[i] ) + { + rgrowv(mtotal+1, &state->totalnl, _state); + rgrowv(mtotal+1, &state->totalnu, _state); + state->totalnl.ptr.p_double[mtotal] = state->wrkbndl.ptr.p_double[i]; + state->totalnu.ptr.p_double[mtotal] = state->wrkbndu.ptr.p_double[i]; + rgrowv(1+mtotal+1, &state->fscales, _state); + state->fscales.ptr.p_double[1+mtotal] = 1.0; + state->wrkbndl.ptr.p_double[i] = _state->v_neginf; + state->wrkbndu.ptr.p_double[i] = _state->v_posinf; + mtotal = mtotal+1; + } + } + offsqc = offslast; + offslast = offslast+state->mqc; + for(i=0; i<=state->mqc-1; i++) + { + rgrowv(mtotal+1, &state->totalnl, _state); + rgrowv(mtotal+1, &state->totalnu, _state); + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + state->totalnl.ptr.p_double[mtotal] = qci->cl; + state->totalnu.ptr.p_double[mtotal] = qci->cu; + rgrowv(1+mtotal+1, &state->fscales, _state); + state->fscales.ptr.p_double[1+mtotal] = 1.0; + mtotal = mtotal+1; + } + offscc = offslast; + offslast = offslast+state->msocc; + for(i=0; i<=state->msocc-1; i++) + { + rgrowv(mtotal+1, &state->totalnl, _state); + rgrowv(mtotal+1, &state->totalnu, _state); + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + ae_assert(cci->conetype>=0, "GQPIPM: non-canonic cone constraints are provided", _state); + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + state->totalnl.ptr.p_double[mtotal] = _state->v_neginf; + state->totalnu.ptr.p_double[mtotal] = 0.0; + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + state->totalnl.ptr.p_double[mtotal] = _state->v_neginf; + state->totalnu.ptr.p_double[mtotal] = 0.0; + donecc = ae_true; + } + ae_assert(donecc, "GQPIPM: unexpected cone type", _state); + rgrowv(1+mtotal+1, &state->fscales, _state); + state->fscales.ptr.p_double[1+mtotal] = 1.0; + mtotal = mtotal+1; + } + ae_assert(mtotal==offslast, "GQPIPM: integrity check 5535 failed", _state); + bsetallocv(1+mtotal, ae_false, &state->doqnupdates, _state); + if( state->algomode==gqpipm_amhybrid ) + { + nnz = 0; + for(i=0; i<=n-1; i++) + { + nnz = nnz+(state->sparseq1.didx.ptr.p_int[i]-state->sparseq1.ridx.ptr.p_int[i]); + } + state->doqnupdates.ptr.p_bool[0] = nnz>state->hessmaxoffdiag; + for(i=0; i<=state->mqc-1; i++) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + nnz = 0; + for(j=0; j<=qci->nvars-1; j++) + { + nnz = nnz+(qci->lowerq.didx.ptr.p_int[j]-qci->lowerq.ridx.ptr.p_int[j]); + } + state->doqnupdates.ptr.p_bool[1+offsqc+i] = nnz>state->hessmaxoffdiag; + } + } + gqpipm_initializehessjac(state, offslc, offsqc, offsec, offscc, mtotal, _state); + rsetallocv(n, 0.0, xs, _state); + rsetallocv(n, 0.0, lagbc, _state); + rsetallocv(state->mlc, 0.0, laglc, _state); + rsetallocv(state->mqc, 0.0, lagqc, _state); + initprimdual = gipmgetinitprimdual(_state); + for(i=0; i<=n-1; i++) + { + if( !ae_isfinite(state->wrkbndl.ptr.p_double[i], _state)&&!ae_isfinite(state->wrkbndu.ptr.p_double[i], _state) ) + { + continue; + } + if( ae_isfinite(state->wrkbndl.ptr.p_double[i], _state)&&!ae_isfinite(state->wrkbndu.ptr.p_double[i], _state) ) + { + state->x0.ptr.p_double[i] = ae_maxreal(state->x0.ptr.p_double[i], state->wrkbndl.ptr.p_double[i]+initprimdual, _state); + continue; + } + if( ae_isfinite(state->wrkbndu.ptr.p_double[i], _state)&&!ae_isfinite(state->wrkbndl.ptr.p_double[i], _state) ) + { + state->x0.ptr.p_double[i] = ae_minreal(state->x0.ptr.p_double[i], state->wrkbndu.ptr.p_double[i]-initprimdual, _state); + continue; + } + if( ae_fp_greater(state->wrkbndu.ptr.p_double[i]-state->wrkbndl.ptr.p_double[i],(double)2*initprimdual) ) + { + state->x0.ptr.p_double[i] = ae_maxreal(state->x0.ptr.p_double[i], state->wrkbndl.ptr.p_double[i]+initprimdual, _state); + state->x0.ptr.p_double[i] = ae_minreal(state->x0.ptr.p_double[i], state->wrkbndu.ptr.p_double[i]-initprimdual, _state); + continue; + } + ae_assert(ae_fp_less(state->wrkbndl.ptr.p_double[i],state->wrkbndu.ptr.p_double[i]), "GQPIPM: integrity check 609424 failed", _state); + state->x0.ptr.p_double[i] = 0.5*(state->wrkbndl.ptr.p_double[i]+state->wrkbndu.ptr.p_double[i]); + ae_assert(ae_fp_greater(state->x0.ptr.p_double[i],state->wrkbndl.ptr.p_double[i]), "GQPIPM: integrity check 609425 failed", _state); + ae_assert(ae_fp_less(state->x0.ptr.p_double[i],state->wrkbndu.ptr.p_double[i]), "GQPIPM: integrity check 609426 failed", _state); + } + for(i=0; i<=state->msocc-1; i++) + { + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + if( cci->nvars==0 ) + { + continue; + } + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + donecc = ae_true; + } + ae_assert(donecc, "GQPIPM: integrity check 876620 failed", _state); + } + ae_assert(state->fscales.cnt>=1+mtotal, "GQPIPM: integrity check 8248 failed", _state); + gipminitbuf(&state->wrkbndl, &state->wrkbndu, &state->x0, n, &state->totalnl, &state->totalnu, mtotal-0*state->msocc, 0*state->msocc, &state->fscales, &state->doqnupdates, state->eps, state->maxits, state->algomode==gqpipm_amhybrid, &state->solver, _state); + if( state->dotrace ) + { + ae_trace("\n----- printing additional problem info -------------------------------------------------------------\n"); + if( (state->cvxobjective!=0||state->cvxqc!=0)||state->cvxcc!=0 ) + { + ae_trace("> analyzing problem convexity:\n"); + if( state->cvxobjective>0 ) + { + ae_trace(">> objective = convex\n"); + } + if( state->cvxobjective<0 ) + { + ae_trace(">> objective = non-convex\n"); + } + if( state->cvxobjective==0 ) + { + ae_trace(">> objective = convexity is unknown\n"); + } + if( xqcgetcount(&state->xqc, _state)>0 ) + { + if( state->cvxqc>0 ) + { + ae_trace(">> quadratic constraints = all convex\n"); + } + if( state->cvxqc<0 ) + { + ae_trace(">> quadratic constraints = non-convex (at least one)\n"); + } + if( state->cvxqc==0 ) + { + ae_trace(">> quadratic constraints = convexity is unknown\n"); + } + } + else + { + ae_trace(">> no quadratic constraints\n"); + } + if( xccgetcount(&state->xcc, _state)>0 ) + { + if( state->cvxcc>0 ) + { + ae_trace(">> conic constraints = all convex\n"); + } + if( state->cvxcc<0 ) + { + ae_trace(">> conic constraints = non-convex (at least one)\n"); + } + if( state->cvxcc==0 ) + { + ae_trace(">> conic constraints = convexity is unknown\n"); + } + } + else + { + ae_trace(">> no conic constraints\n"); + } + } + ae_trace("\n"); + } + remembered = ae_false; + factorized = ae_false; + while(gipmiteration(&state->solver, ae_false, _state)) + { + if( state->solver.requesttype==1 ) + { + gqpipm_handlecomputeandremember(state, offslc, offsqc, offsec, offscc, mtotal, &remembered, &factorized, _state); + continue; + } + if( state->solver.requesttype==1001 ) + { + gqpipm_handlefactorize(state, mtotal, &remembered, &factorized, _state); + continue; + } + if( state->solver.requesttype==1002 ) + { + gqpipm_handlesolve(state, mtotal, &remembered, &factorized, _state); + continue; + } + if( state->solver.requesttype==1003 ) + { + gqpipm_handlemv(state, offslc, offsqc, offsec, offscc, mtotal, &remembered, &factorized, _state); + continue; + } + if( state->solver.requesttype==1004 ) + { + if( state->algomode==gqpipm_amhybrid&&state->nq>0 ) + { + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + rallocv(n, &state->tmp2, _state); + rallocv(n, &state->tmp3, _state); + rcopyvx(n, &state->solver.querydata, 0*n, &state->tmp0, 0, _state); + rcopyvx(n, &state->solver.querydata, 1*n, &state->tmp1, 0, _state); + rcopyvx(n, &state->solver.querydata, 2*n, &state->tmp2, 0, _state); + rcopyvx(n, &state->solver.querydata, 3*n, &state->tmp3, 0, _state); + hessianupdatev2(&state->hess, &state->tmp0, &state->tmp2, &state->tmp1, &state->tmp3, 2, ae_false, state->dotrace, 2, _state); + hessianmultiplyby(&state->hess, 0.95, _state); + } + continue; + } + ae_assert(ae_false, "GQPIPM: request not implemented", _state); + } + gipmresults(&state->solver, xs, lagbc, &state->tmp0, terminationtype, _state); + state->repiterationscount = state->solver.repiterationscount; + for(i=0; i<=state->fixedvarscnt-1; i++) + { + lagbc->ptr.p_double[state->fixedidx.ptr.p_int[i]] = state->tmp0.ptr.p_double[offsec+i]; + } + for(i=0; i<=mlc-1; i++) + { + laglc->ptr.p_double[i] = state->tmp0.ptr.p_double[offslc+i]; + } + for(i=0; i<=state->mqc-1; i++) + { + lagqc->ptr.p_double[i] = state->tmp0.ptr.p_double[offsqc+i]; + } + rmergemaxv(n, &state->finiterawbndl, xs, _state); + rmergeminv(n, &state->finiterawbndu, xs, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Appends a lower triangular sparse matrix to the list of row/column/id/value +elements. Grows list as necessary, returns modified list length. + +If VarIdx[] is unordered, i.e. VarIdx[i0]>VarIdx[i1] for some i0ridx.ptr.p_int[tgt0]; + j1 = q->didx.ptr.p_int[tgt0]-1; + w = j1-j0+1+1; + igrowv(*hcnt+w, hr, _state); + igrowv(*hcnt+w, hc, _state); + igrowv(*hcnt+w, hk, _state); + rgrowv(*hcnt+w, hv, _state); + for(jj=j0; jj<=j1; jj++) + { + k0 = varidx->ptr.p_int[tgt0]; + k1 = varidx->ptr.p_int[q->idx.ptr.p_int[jj]]; + if( k0>=k1 ) + { + hr->ptr.p_int[*hcnt] = k0; + hc->ptr.p_int[*hcnt] = k1; + } + else + { + hr->ptr.p_int[*hcnt] = k1; + hc->ptr.p_int[*hcnt] = k0; + } + hk->ptr.p_int[*hcnt] = id; + hv->ptr.p_double[*hcnt] = q->vals.ptr.p_double[jj]; + *hcnt = *hcnt+1; + } + v = 0.0; + if( j1+1uidx.ptr.p_int[tgt0] ) + { + v = q->vals.ptr.p_double[j1+1]; + } + hr->ptr.p_int[*hcnt] = varidx->ptr.p_int[tgt0]; + hc->ptr.p_int[*hcnt] = varidx->ptr.p_int[tgt0]; + hk->ptr.p_int[*hcnt] = id; + hv->ptr.p_double[*hcnt] = v; + *hcnt = *hcnt+1; + } +} + + +/************************************************************************* +Prepares sparse Hessian, dependencies of its elements on Lagrange multipliers, +SPSymmAnalyze(), etc. + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_initializehessjac(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t w; + ae_int_t n; + ae_int_t mlc; + ae_int_t offs; + ae_int_t dstrow; + ae_int_t cidx; + ae_int_t kpow; + double v; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t jprev; + ae_int_t nv; + ae_int_t tgt0; + ae_int_t tgt1; + ae_int_t tgtx; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + gqpsparseconichessian *chi; + ae_smart_ptr _chi; + gqpoptionaldense *opti; + ae_smart_ptr _opti; + ae_int_t hcnt; + ae_int_t dstidx; + ae_int_t srcidx; + ae_int_t srcrange1; + ae_int_t facttype; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + memset(&_chi, 0, sizeof(_chi)); + memset(&_opti, 0, sizeof(_opti)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_chi, (void**)&chi, ae_false, _state, ae_true); + ae_smart_ptr_init(&_opti, (void**)&opti, ae_false, _state, ae_true); + + n = state->n; + mlc = state->mlc; + iallocv(n, &state->tmpi, _state); + ae_obj_array_clear(&state->xchsparse); + for(i=0; i<=state->msocc-1; i++) + { + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + chi = (gqpsparseconichessian*)ae_malloc(sizeof(gqpsparseconichessian), _state); /* note: using chi as a temporary prior to assigning its value to _chi */ + memset(chi, 0, sizeof(gqpsparseconichessian)); + _gqpsparseconichessian_init(chi, _state, ae_false); + ae_smart_ptr_assign(&_chi, chi, ae_true, ae_true, (ae_int_t)sizeof(gqpsparseconichessian), _gqpsparseconichessian_init_copy, _gqpsparseconichessian_destroy); + ae_obj_array_append_transfer(&state->xchsparse, &_chi, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + if( cci->conetype==xccprimitiveconetype(_state) ) + { + chi->lowerh.n = nv; + chi->lowerh.m = nv; + iallocv(nv+1, &chi->lowerh.ridx, _state); + iallocv(2*(nv-1)+1, &chi->lowerh.idx, _state); + rallocv(2*(nv-1)+1, &chi->lowerh.vals, _state); + offs = 0; + for(j=0; j<=nv-2; j++) + { + chi->lowerh.ridx.ptr.p_int[j] = offs; + chi->lowerh.idx.ptr.p_int[offs] = j; + chi->lowerh.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + chi->lowerh.ridx.ptr.p_int[nv-1] = offs; + for(j=0; j<=nv-1; j++) + { + chi->lowerh.idx.ptr.p_int[offs] = j; + chi->lowerh.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + chi->lowerh.ridx.ptr.p_int[nv] = offs; + ae_assert(offs==2*nv-1, "GQPIPM: integrity check 136309 failed", _state); + sparsecreatecrsinplace(&chi->lowerh, _state); + icopyv(nv, &cci->varidx, &state->tmpi, _state); + iallocv(nv, &chi->ordervaridx, _state); + for(j=0; j<=nv-1; j++) + { + chi->ordervaridx.ptr.p_int[j] = j; + } + tagsortmiddleii(&state->tmpi, &chi->ordervaridx, 0, nv, _state); + continue; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + ae_assert(state->pctype==0, "GQPIPM: integrity check 446815 failed", _state); + kpow = cci->kpow; + chi->lowerh.n = nv; + chi->lowerh.m = nv; + iallocv(nv+1, &chi->lowerh.ridx, _state); + iallocv(nv+kpow*nv, &chi->lowerh.idx, _state); + rallocv(nv+kpow*nv, &chi->lowerh.vals, _state); + offs = 0; + for(j=0; j<=nv-kpow-1; j++) + { + chi->lowerh.ridx.ptr.p_int[j] = offs; + chi->lowerh.idx.ptr.p_int[offs] = j; + chi->lowerh.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + for(j=nv-kpow; j<=nv-1; j++) + { + chi->lowerh.ridx.ptr.p_int[j] = offs; + for(j1=0; j1<=j; j1++) + { + chi->lowerh.idx.ptr.p_int[offs] = j1; + chi->lowerh.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + } + chi->lowerh.ridx.ptr.p_int[nv] = offs; + sparsecreatecrsinplace(&chi->lowerh, _state); + icopyv(nv, &cci->varidx, &state->tmpi, _state); + iallocv(nv, &chi->ordervaridx, _state); + for(j=0; j<=nv-1; j++) + { + chi->ordervaridx.ptr.p_int[j] = j; + } + tagsortmiddleii(&state->tmpi, &chi->ordervaridx, 0, nv, _state); + continue; + } + ae_assert(ae_false, "GQPIPM: integrity check 140309 failed", _state); + } + ae_assert(ae_obj_array_get_length(&state->xcc.constraints)==ae_obj_array_get_length(&state->xchsparse), "GQPIPM: integrity check 142310 failed", _state); + state->curjac.m = mtotal; + state->curjac.n = n; + iallocv(mtotal+1, &state->curjac.ridx, _state); + state->curjac.ridx.ptr.p_int[0] = 0; + dstrow = 0; + ae_assert(dstrow==offslc, "GQPIPM: integrity check 2900 failed", _state); + if( mlc>0 ) + { + k = state->sparselc.ridx.ptr.p_int[mlc]; + igrowv(state->curjac.ridx.ptr.p_int[dstrow]+k, &state->curjac.idx, _state); + rgrowv(state->curjac.ridx.ptr.p_int[dstrow]+k, &state->curjac.vals, _state); + for(i=0; i<=mlc-1; i++) + { + k = state->sparselc.ridx.ptr.p_int[i+1]-state->sparselc.ridx.ptr.p_int[i]; + icopyvx(k, &state->sparselc.idx, state->sparselc.ridx.ptr.p_int[i], &state->curjac.idx, state->curjac.ridx.ptr.p_int[dstrow], _state); + rsetvx(k, 0.0, &state->curjac.vals, state->curjac.ridx.ptr.p_int[dstrow], _state); + state->curjac.ridx.ptr.p_int[dstrow+1] = state->curjac.ridx.ptr.p_int[dstrow]+k; + dstrow = dstrow+1; + } + } + ae_assert(dstrow==offsec, "GQPIPM: integrity check 945839 failed", _state); + igrowv(state->curjac.ridx.ptr.p_int[dstrow]+state->fixedvarscnt, &state->curjac.idx, _state); + rgrowv(state->curjac.ridx.ptr.p_int[dstrow]+state->fixedvarscnt, &state->curjac.vals, _state); + for(i=0; i<=state->fixedvarscnt-1; i++) + { + k = state->curjac.ridx.ptr.p_int[dstrow]; + state->curjac.idx.ptr.p_int[k] = state->fixedidx.ptr.p_int[i]; + state->curjac.vals.ptr.p_double[k] = 0.0; + state->curjac.ridx.ptr.p_int[dstrow+1] = k+1; + dstrow = dstrow+1; + } + ae_assert(dstrow==offsqc, "GQPIPM: integrity check 949844 failed", _state); + for(i=0; i<=state->mqc-1; i++) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + igrowv(state->curjac.ridx.ptr.p_int[dstrow]+qci->nvars, &state->curjac.idx, _state); + rgrowv(state->curjac.ridx.ptr.p_int[dstrow]+qci->nvars, &state->curjac.vals, _state); + icopyvx(qci->nvars, &qci->varidx, 0, &state->curjac.idx, state->curjac.ridx.ptr.p_int[dstrow], _state); + rsetvx(qci->nvars, 0.0, &state->curjac.vals, state->curjac.ridx.ptr.p_int[dstrow], _state); + state->curjac.ridx.ptr.p_int[dstrow+1] = state->curjac.ridx.ptr.p_int[dstrow]+qci->nvars; + dstrow = dstrow+1; + } + for(i=0; i<=state->msocc-1; i++) + { + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + igrowv(state->curjac.ridx.ptr.p_int[dstrow]+cci->nvars, &state->curjac.idx, _state); + rgrowv(state->curjac.ridx.ptr.p_int[dstrow]+cci->nvars, &state->curjac.vals, _state); + icopyvx(cci->nvars, &cci->varidx, 0, &state->curjac.idx, state->curjac.ridx.ptr.p_int[dstrow], _state); + tagsortmiddlei(&state->curjac.idx, state->curjac.ridx.ptr.p_int[dstrow], cci->nvars, _state); + rsetvx(cci->nvars, 0.0, &state->curjac.vals, state->curjac.ridx.ptr.p_int[dstrow], _state); + state->curjac.ridx.ptr.p_int[dstrow+1] = state->curjac.ridx.ptr.p_int[dstrow]+cci->nvars; + dstrow = dstrow+1; + } + ae_assert(dstrow==mtotal, "GQPIPM: integrity check 993315 failed", _state); + if( mtotal>0 ) + { + sparsecreatecrsinplace(&state->curjac, _state); + } + if( state->algomode==gqpipm_amdense ) + { + rallocm(n, n, &state->currenth, _state); + ae_frame_leave(_state); + return; + } + ae_assert(state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid, "QPGIPM: 654249 failed", _state); + if( state->algomode==gqpipm_amhybrid&&state->nq>0 ) + { + state->hessmemlen = ae_minint(state->nq, icoalesce(state->hessmemlen, gqpipm_xbfgsdefaultmemlen, _state), _state); + hessianinitlowranksr1(&state->hess, state->nq, state->hessmemlen, ae_maxreal(state->eps, ae_sqrt(ae_machineepsilon, _state), _state), gqpipm_xbfgsmaxhess, _state); + } + hcnt = 0; + if( state->algomode==gqpipm_amhybrid&&state->doqnupdates.ptr.p_bool[0] ) + { + igrowv(hcnt+n, &state->tmphr, _state); + igrowv(hcnt+n, &state->tmphc, _state); + igrowv(hcnt+n, &state->tmphk, _state); + rgrowv(hcnt+n, &state->tmphv, _state); + for(i=0; i<=n-1; i++) + { + state->tmphr.ptr.p_int[hcnt] = i; + state->tmphc.ptr.p_int[hcnt] = i; + state->tmphk.ptr.p_int[hcnt] = mtotal; + state->tmphv.ptr.p_double[hcnt] = 0.0; + hcnt = hcnt+1; + } + } + else + { + for(i=0; i<=n-1; i++) + { + j0 = state->sparseq1.ridx.ptr.p_int[i]; + j1 = state->sparseq1.didx.ptr.p_int[i]-1; + w = j1-j0+1+1; + igrowv(hcnt+w, &state->tmphr, _state); + igrowv(hcnt+w, &state->tmphc, _state); + igrowv(hcnt+w, &state->tmphk, _state); + rgrowv(hcnt+w, &state->tmphv, _state); + for(jj=j0; jj<=j1; jj++) + { + state->tmphr.ptr.p_int[hcnt] = i; + state->tmphc.ptr.p_int[hcnt] = state->sparseq1.idx.ptr.p_int[jj]; + state->tmphk.ptr.p_int[hcnt] = mtotal; + state->tmphv.ptr.p_double[hcnt] = state->sparseq1.vals.ptr.p_double[jj]; + hcnt = hcnt+1; + } + v = 0.0; + if( j1+1sparseq1.uidx.ptr.p_int[i] ) + { + v = state->sparseq1.vals.ptr.p_double[j1+1]; + } + state->tmphr.ptr.p_int[hcnt] = i; + state->tmphc.ptr.p_int[hcnt] = i; + state->tmphk.ptr.p_int[hcnt] = mtotal; + state->tmphv.ptr.p_double[hcnt] = v; + hcnt = hcnt+1; + } + } + for(i=0; i<=state->mqc-1; i++) + { + if( state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[1+offsqc+i] ) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + if( qci->nvars==0 ) + { + continue; + } + gqpipm_appendtorckv(&qci->varidx, &qci->lowerq, qci->nvars, offsqc+i, &state->tmphr, &state->tmphc, &state->tmphk, &state->tmphv, &hcnt, _state); + } + } + for(i=0; i<=state->msocc-1; i++) + { + ae_assert(state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[1+offscc+i], "GQPIPM: integrity check 832348 failed", _state); + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + ae_obj_array_get(&state->xchsparse, i, &_chi, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + gqpipm_appendtorckv(&cci->varidx, &chi->lowerh, nv, offscc+i, &state->tmphr, &state->tmphc, &state->tmphk, &state->tmphv, &hcnt, _state); + } + ae_assert(ae_obj_array_get_length(&state->xcc.constraints)==ae_obj_array_get_length(&state->xchsparse), "GQPIPM: integrity check 142310 failed", _state); + ae_assert(hcnt>=n, "GQPIPN: integrity check 937222 failed", _state); + gqpipm_sortrck(&state->tmphr, &state->tmphc, &state->tmphk, &state->tmphv, hcnt, &state->tmphr2, &state->tmphc2, &state->tmphk2, &state->tmphv2, _state); + state->sparseh.m = n; + state->sparseh.n = n; + iallocv(n+1, &state->sparseh.ridx, _state); + state->sparseh.ridx.ptr.p_int[0] = 0; + state->sparsehdeps.m = 0; + state->sparsehdeps.n = mtotal+1; + iallocv(1, &state->sparsehdeps.ridx, _state); + state->sparsehdeps.ridx.ptr.p_int[0] = 0; + srcidx = 0; + dstidx = 0; + for(dstrow=0; dstrow<=n-1; dstrow++) + { + ae_assert(state->tmphr.ptr.p_int[srcidx]==dstrow, "GQPIPM: integrity check 951223 failed", _state); + dstidx = state->sparseh.ridx.ptr.p_int[dstrow]; + jprev = -1; + while(srcidxtmphr.ptr.p_int[srcidx]==dstrow) + { + j = state->tmphc.ptr.p_int[srcidx]; + if( j<=jprev||j>dstrow ) + { + ae_assert(ae_false, "GQPIPM: integrity check 958230 failed", _state); + } + srcrange1 = srcidx; + offs = state->sparsehdeps.ridx.ptr.p_int[state->sparsehdeps.m]; + while((srcrange1tmphr.ptr.p_int[srcrange1]==dstrow)&&state->tmphc.ptr.p_int[srcrange1]==j) + { + igrowv(offs+1, &state->sparsehdeps.idx, _state); + rgrowv(offs+1, &state->sparsehdeps.vals, _state); + state->sparsehdeps.idx.ptr.p_int[offs] = state->tmphk.ptr.p_int[srcrange1]; + state->sparsehdeps.vals.ptr.p_double[offs] = state->tmphv.ptr.p_double[srcrange1]; + srcrange1 = srcrange1+1; + offs = offs+1; + } + state->sparsehdeps.m = state->sparsehdeps.m+1; + igrowv(state->sparsehdeps.m+1, &state->sparsehdeps.ridx, _state); + state->sparsehdeps.ridx.ptr.p_int[state->sparsehdeps.m] = offs; + igrowv(dstidx+1, &state->sparseh.idx, _state); + rgrowv(dstidx+1, &state->sparseh.vals, _state); + state->sparseh.idx.ptr.p_int[dstidx] = j; + state->sparseh.vals.ptr.p_double[dstidx] = 0.0; + dstidx = dstidx+1; + srcidx = srcrange1; + jprev = j; + } + state->sparseh.ridx.ptr.p_int[dstrow+1] = dstidx; + } + sparsecreatecrsinplace(&state->sparseh, _state); + sparsecreatecrsinplace(&state->sparsehdeps, _state); + for(cidx=0; cidx<=state->msocc-1; cidx++) + { + ae_assert(state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[1+offscc+cidx], "GQPIPM: integrity check 912350 failed", _state); + ae_obj_array_get(&state->xcc.constraints, cidx, &_cci, _state); + ae_obj_array_get(&state->xchsparse, cidx, &_chi, _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + iallocv(chi->lowerh.ridx.ptr.p_int[nv], &chi->injectionoffsets, _state); + for(i=0; i<=nv-1; i++) + { + j0 = chi->lowerh.ridx.ptr.p_int[i]; + j1 = chi->lowerh.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + tgt0 = cci->varidx.ptr.p_int[i]; + tgt1 = cci->varidx.ptr.p_int[chi->lowerh.idx.ptr.p_int[jj]]; + if( tgt1>tgt0 ) + { + tgtx = tgt0; + tgt0 = tgt1; + tgt1 = tgtx; + } + offs = ibinarysearchexisting(&state->sparseh.idx, state->sparseh.ridx.ptr.p_int[tgt0], state->sparseh.uidx.ptr.p_int[tgt0], tgt1, _state); + chi->injectionoffsets.ptr.p_int[jj] = ibinarysearchexisting(&state->sparsehdeps.idx, state->sparsehdeps.ridx.ptr.p_int[offs], state->sparsehdeps.ridx.ptr.p_int[offs+1], offscc+cidx, _state); + } + } + } + ae_assert(state->algomode==gqpipm_amhybrid||state->hessmemlen==0, "QPGIPM: 838258 failed", _state); + state->sparsesys.m = n+mtotal+2*state->hessmemlen; + state->sparsesys.n = state->sparsesys.m; + iallocv(state->sparsesys.m+1, &state->sparsesys.ridx, _state); + state->sparsesys.ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=n-1; i++) + { + igrowv(offs+n, &state->sparsesys.idx, _state); + rgrowv(offs+n, &state->sparsesys.vals, _state); + j0 = state->sparseh.ridx.ptr.p_int[i]; + j1 = state->sparseh.didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = state->sparseh.idx.ptr.p_int[jj]; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + } + state->sparsesys.idx.ptr.p_int[offs] = i; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=mtotal-1; i++) + { + igrowv(offs+n+1, &state->sparsesys.idx, _state); + rgrowv(offs+n+1, &state->sparsesys.vals, _state); + j0 = state->curjac.ridx.ptr.p_int[i]; + j1 = state->curjac.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = state->curjac.idx.ptr.p_int[jj]; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + } + state->sparsesys.idx.ptr.p_int[offs] = n+i; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[n+i+1] = offs; + } + for(i=0; i<=2*state->hessmemlen-1; i++) + { + igrowv(offs+state->nq+1, &state->sparsesys.idx, _state); + rgrowv(offs+state->nq+1, &state->sparsesys.vals, _state); + for(jj=0; jj<=state->nq-1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = jj; + state->sparsesys.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + state->sparsesys.idx.ptr.p_int[offs] = n+mtotal+i; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[n+mtotal+i+1] = offs; + } + sparsecreatecrsinplace(&state->sparsesys, _state); + gqpipm_optionaldensefromsparse(&state->optionaldenseq1, &state->sparseq1, state->nq, _state); + ae_obj_array_clear(&state->optionaldensexqc); + for(i=0; i<=state->mqc-1; i++) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + opti = (gqpoptionaldense*)ae_malloc(sizeof(gqpoptionaldense), _state); /* note: using opti as a temporary prior to assigning its value to _opti */ + memset(opti, 0, sizeof(gqpoptionaldense)); + _gqpoptionaldense_init(opti, _state, ae_false); + ae_smart_ptr_assign(&_opti, opti, ae_true, ae_true, (ae_int_t)sizeof(gqpoptionaldense), _gqpoptionaldense_init_copy, _gqpoptionaldense_destroy); + gqpipm_optionaldensefromsparseqc(opti, qci, _state); + ae_obj_array_append_transfer(&state->optionaldensexqc, &_opti, _state); + } + facttype = 1; + isetallocv(n+mtotal+2*state->hessmemlen, 0, &state->priorities, _state); + if( state->algomode!=gqpipm_amhybrid ) + { + for(i=0; i<=n-1; i++) + { + state->priorities.ptr.p_int[i] = 1; + } + for(i=n; i<=n+mtotal-1; i++) + { + state->priorities.ptr.p_int[i] = 0; + } + } + for(i=n+mtotal; i<=n+mtotal+2*state->hessmemlen-1; i++) + { + state->priorities.ptr.p_int[i] = 2; + } + if( !spsymmanalyze(&state->sparsesys, &state->priorities, gqpipm_mupromote, 0, facttype, 3, 1, &state->analysis, _state) ) + { + ae_assert(ae_false, "QPGIPM: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Lexicographically sorts a list of row-column-index elements. + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_sortrck(/* Integer */ ae_vector* vecr, + /* Integer */ ae_vector* vecc, + /* Integer */ ae_vector* veck, + /* Real */ ae_vector* vecv, + ae_int_t n, + /* Integer */ ae_vector* tmpr, + /* Integer */ ae_vector* tmpc, + /* Integer */ ae_vector* tmpk, + /* Real */ ae_vector* tmpv, + ae_state *_state) +{ + + + if( n==0 ) + { + return; + } + iallocv(n, tmpr, _state); + iallocv(n, tmpc, _state); + iallocv(n, tmpk, _state); + rallocv(n, tmpv, _state); + gqpipm_sortrckrec(vecr, vecc, veck, vecv, 0, n, tmpr, tmpc, tmpk, tmpv, _state); +} + + +/************************************************************************* +Recursive sorting routine. + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_sortrckrec(/* Integer */ ae_vector* vecr, + /* Integer */ ae_vector* vecc, + /* Integer */ ae_vector* veck, + /* Real */ ae_vector* vecv, + ae_int_t idx0, + ae_int_t idx1, + /* Integer */ ae_vector* tmpr, + /* Integer */ ae_vector* tmpc, + /* Integer */ ae_vector* tmpk, + /* Real */ ae_vector* tmpv, + ae_state *_state) +{ + ae_int_t idxmid; + ae_int_t src0; + ae_int_t src1; + ae_int_t end0; + ae_int_t end1; + ae_int_t dst; + ae_int_t s; + + + if( idx1-idx0<=1 ) + { + return; + } + idxmid = idx0+(idx1-idx0)/2; + gqpipm_sortrckrec(vecr, vecc, veck, vecv, idx0, idxmid, tmpr, tmpc, tmpk, tmpv, _state); + gqpipm_sortrckrec(vecr, vecc, veck, vecv, idxmid, idx1, tmpr, tmpc, tmpk, tmpv, _state); + src0 = idx0; + end0 = idxmid; + src1 = idxmid; + end1 = idx1; + dst = idx0; + while(src0ptr.p_int[src0]ptr.p_int[src1] ) + { + s = -1; + } + if( vecr->ptr.p_int[src0]>vecr->ptr.p_int[src1] ) + { + s = 1; + } + if( s==0 ) + { + if( vecc->ptr.p_int[src0]ptr.p_int[src1] ) + { + s = -1; + } + if( vecc->ptr.p_int[src0]>vecc->ptr.p_int[src1] ) + { + s = 1; + } + } + if( s==0 ) + { + if( veck->ptr.p_int[src0]ptr.p_int[src1] ) + { + s = -1; + } + if( veck->ptr.p_int[src0]>veck->ptr.p_int[src1] ) + { + s = 1; + } + } + if( s==0 ) + { + ae_assert(ae_false, "SortRCKRec: integrity check failed, non-distinct entries", _state); + } + if( s<0 ) + { + tmpr->ptr.p_int[dst] = vecr->ptr.p_int[src0]; + tmpc->ptr.p_int[dst] = vecc->ptr.p_int[src0]; + tmpk->ptr.p_int[dst] = veck->ptr.p_int[src0]; + tmpv->ptr.p_double[dst] = vecv->ptr.p_double[src0]; + src0 = src0+1; + dst = dst+1; + } + else + { + tmpr->ptr.p_int[dst] = vecr->ptr.p_int[src1]; + tmpc->ptr.p_int[dst] = vecc->ptr.p_int[src1]; + tmpk->ptr.p_int[dst] = veck->ptr.p_int[src1]; + tmpv->ptr.p_double[dst] = vecv->ptr.p_double[src1]; + src1 = src1+1; + dst = dst+1; + } + } + while(src0ptr.p_int[dst] = vecr->ptr.p_int[src0]; + tmpc->ptr.p_int[dst] = vecc->ptr.p_int[src0]; + tmpk->ptr.p_int[dst] = veck->ptr.p_int[src0]; + tmpv->ptr.p_double[dst] = vecv->ptr.p_double[src0]; + src0 = src0+1; + dst = dst+1; + } + while(src1ptr.p_int[dst] = vecr->ptr.p_int[src1]; + tmpc->ptr.p_int[dst] = vecc->ptr.p_int[src1]; + tmpk->ptr.p_int[dst] = veck->ptr.p_int[src1]; + tmpv->ptr.p_double[dst] = vecv->ptr.p_double[src1]; + src1 = src1+1; + dst = dst+1; + } + ae_assert(dst==idx1, "SortRCKRec: integrity check 211811 failed", _state); + icopyvx(idx1-idx0, tmpr, idx0, vecr, idx0, _state); + icopyvx(idx1-idx0, tmpc, idx0, vecc, idx0, _state); + icopyvx(idx1-idx0, tmpk, idx0, veck, idx0, _state); + rcopyvx(idx1-idx0, tmpv, idx0, vecv, idx0, _state); +} + + +/************************************************************************* +Handle compute-and-remember request + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_handlecomputeandremember(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t mlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t tgt0; + ae_int_t tgt1; + ae_int_t jmid; + ae_int_t offs; + ae_int_t nv; + double v; + double vlag; + double valpha; + ae_int_t kpow; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + gqpsparseconichessian *chi; + ae_smart_ptr _chi; + gqpoptionaldense *opti; + ae_smart_ptr _opti; + ae_bool donecc; + ae_bool donemv; + ae_vector ccy; + double vv; + double vy; + double invvy; + double vz; + double u2; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + memset(&_chi, 0, sizeof(_chi)); + memset(&_opti, 0, sizeof(_opti)); + memset(&ccy, 0, sizeof(ccy)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_chi, (void**)&chi, ae_false, _state, ae_true); + ae_smart_ptr_init(&_opti, (void**)&opti, ae_false, _state, ae_true); + ae_vector_init(&ccy, 0, DT_REAL, _state, ae_true); + + ae_assert((state->algomode==gqpipm_amdense||state->algomode==gqpipm_amsparse)||state->algomode==gqpipm_amhybrid, "QPGIPM: 087304 failed", _state); + n = state->n; + mlc = state->mlc; + ae_nxpool_retrieve(&state->nrealpool, &ccy, _state); + sparsecreatecrsemptybuf(n, &state->solver.replysj, _state); + rallocv(n, &state->tmp0, _state); + iallocv(n, &state->tmpi, _state); + rcopyallocv(n, &state->solver.querydata, &state->tmpx, _state); + rallocv(n, &state->currentx, _state); + rallocv(mtotal, &state->currentlag, _state); + rcopyvx(n, &state->solver.querydata, 0, &state->currentx, 0, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->currentlag, 0, _state); + for(i=0; i<=state->msocc-1; i++) + { + state->currentlag.ptr.p_double[offscc+i] = ae_maxreal(state->currentlag.ptr.p_double[offscc+i], 0.0, _state); + } + *remembered = ae_true; + *factorized = ae_false; + if( state->algomode==gqpipm_amdense ) + { + rgemv(n, n, 1.0, &state->denseq, 0, &state->tmpx, 0.0, &state->tmp0, _state); + } + else + { + ae_assert(state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid, "GQPIPM: integrity check 387218 failed", _state); + if( state->optionaldenseq1.hasdenseterm&&state->optionaldenseq1.nvars>0 ) + { + ae_assert((state->optionaldenseq1.nvars>0&&state->optionaldenseq1.varidx.ptr.p_int[0]==0)&&state->optionaldenseq1.varidx.ptr.p_int[state->optionaldenseq1.nvars-1]==state->optionaldenseq1.nvars-1, "GQPIPM: integrity check 390220 failed", _state); + rmatrixsymv(state->optionaldenseq1.nvars, 1.0, &state->optionaldenseq1.q, 0, 0, ae_false, &state->tmpx, 0, 0.0, &state->tmp0, 0, _state); + rsetvx(n-state->optionaldenseq1.nvars, 0.0, &state->tmp0, state->optionaldenseq1.nvars, _state); + } + else + { + sparsesmv(&state->sparseq1, ae_false, &state->tmpx, &state->tmp0, _state); + } + } + state->solver.replyfi.ptr.p_double[0] = rdotv(n, &state->tmpx, &state->c, _state)+0.5*rdotv(n, &state->tmpx, &state->tmp0, _state); + raddv(n, 1.0, &state->c, &state->tmp0, _state); + sparseappendcompressedrow(&state->solver.replysj, &state->iotac, &state->tmp0, n, _state); + if( state->algomode==gqpipm_amdense ) + { + rcopyallocm(n, n, &state->denseq, &state->currenth, _state); + } + if( mlc>0 ) + { + sparsemv(&state->sparselc, &state->tmpx, &state->tmp0, _state); + rcopyvx(mlc, &state->tmp0, 0, &state->solver.replyfi, 1+offslc, _state); + ae_assert(state->curjac.ridx.ptr.p_int[offslc+mlc]-state->curjac.ridx.ptr.p_int[offslc]==state->sparselc.ridx.ptr.p_int[mlc], "GQPIPM: integrity check 3638 failed", _state); + rcopyvx(state->sparselc.ridx.ptr.p_int[mlc], &state->sparselc.vals, 0, &state->curjac.vals, state->curjac.ridx.ptr.p_int[offslc], _state); + } + for(i=0; i<=state->fixedvarscnt-1; i++) + { + j = state->fixedidx.ptr.p_int[i]; + v = state->tmpx.ptr.p_double[j]; + state->solver.replyfi.ptr.p_double[1+offsec+i] = v; + ae_assert(state->curjac.ridx.ptr.p_int[offsec+i+1]-state->curjac.ridx.ptr.p_int[offsec+i]==1, "GQPIPM: integrity check 6240 failed", _state); + state->curjac.vals.ptr.p_double[state->curjac.ridx.ptr.p_int[offsec+i]] = 1.0; + } + for(i=0; i<=state->mqc-1; i++) + { + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + if( qci->nvars==0 ) + { + state->solver.replyfi.ptr.p_double[1+offsqc+i] = 0.0; + continue; + } + for(j=0; j<=qci->nvars-1; j++) + { + state->tmp0.ptr.p_double[j] = state->tmpx.ptr.p_double[qci->varidx.ptr.p_int[j]]; + } + donemv = ae_false; + if( ae_obj_array_get_length(&state->optionaldensexqc)==state->mqc ) + { + ae_obj_array_get(&state->optionaldensexqc, i, &_opti, _state); + if( opti->hasdenseterm ) + { + rmatrixsymv(opti->nvars, 1.0, &opti->q, 0, 0, ae_false, &state->tmp0, 0, 0.0, &state->tmp1, 0, _state); + donemv = ae_true; + } + } + if( !donemv ) + { + sparsesmv(&qci->lowerq, ae_false, &state->tmp0, &state->tmp1, _state); + } + state->solver.replyfi.ptr.p_double[1+offsqc+i] = rdotv(qci->nvars, &qci->b, &state->tmp0, _state)+0.5*rdotv(qci->nvars, &state->tmp0, &state->tmp1, _state); + raddv(qci->nvars, 1.0, &qci->b, &state->tmp1, _state); + if( state->algomode==gqpipm_amdense ) + { + vlag = state->currentlag.ptr.p_double[offsqc+i]; + for(j=0; j<=qci->nvars-1; j++) + { + ae_assert(qci->lowerq.didx.ptr.p_int[j]==qci->lowerq.uidx.ptr.p_int[j]-1, "GQPIPM: integrity check 2148 failed", _state); + j0 = qci->lowerq.ridx.ptr.p_int[j]; + j1 = qci->lowerq.didx.ptr.p_int[j]-1; + tgt0 = qci->varidx.ptr.p_int[j]; + for(jj=j0; jj<=j1; jj++) + { + tgt1 = qci->varidx.ptr.p_int[qci->lowerq.idx.ptr.p_int[jj]]; + state->currenth.ptr.pp_double[tgt0][tgt1] = state->currenth.ptr.pp_double[tgt0][tgt1]+vlag*qci->lowerq.vals.ptr.p_double[jj]; + } + state->currenth.ptr.pp_double[tgt0][tgt0] = state->currenth.ptr.pp_double[tgt0][tgt0]+vlag*qci->lowerq.vals.ptr.p_double[qci->lowerq.didx.ptr.p_int[j]]; + } + } + ae_assert(state->curjac.ridx.ptr.p_int[offsqc+i+1]-state->curjac.ridx.ptr.p_int[offsqc+i]==qci->nvars, "GQPIPM: integrity check 2645 failed", _state); + rcopyvx(qci->nvars, &state->tmp1, 0, &state->curjac.vals, state->curjac.ridx.ptr.p_int[offsqc+i], _state); + } + for(i=0; i<=state->msocc-1; i++) + { + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + ae_obj_array_get(&state->xchsparse, i, &_chi, _state); + if( cci->nvars==0 ) + { + state->solver.replyfi.ptr.p_double[1+offscc+i] = 0.0; + continue; + } + nv = cci->nvars; + kpow = cci->kpow; + for(j=0; j<=cci->nvars-1; j++) + { + state->tmp0.ptr.p_double[j] = state->tmpx.ptr.p_double[cci->varidx.ptr.p_int[j]]; + } + donecc = ae_false; + v = (double)(0); + u2 = (double)(0); + if( cci->conetype==xccprimitiveconetype(_state) ) + { + vy = state->tmp0.ptr.p_double[cci->nvars-1]*cci->diaga.ptr.p_double[cci->nvars-1]+cci->shftc.ptr.p_double[cci->nvars-1]; + ccy.ptr.p_double[cci->nvars-1] = vy; + ae_assert(ae_fp_greater(vy,(double)(0)), "GQPIPM: integrity check 251633 failed", _state); + u2 = cci->shftc.ptr.p_double[cci->nvars]; + for(j=0; j<=cci->nvars-2; j++) + { + vv = state->tmp0.ptr.p_double[j]*cci->diaga.ptr.p_double[j]+cci->shftc.ptr.p_double[j]; + ccy.ptr.p_double[j] = vv; + u2 = u2+vv*vv; + state->tmp1.ptr.p_double[j] = (double)2*vv*cci->diaga.ptr.p_double[j]; + } + rmulv(cci->nvars-1, (double)1/vy, &state->tmp1, _state); + state->tmp1.ptr.p_double[cci->nvars-1] = (-u2/(vy*vy)-(double)1)*cci->diaga.ptr.p_double[cci->nvars-1]; + v = u2/vy-vy; + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + u2 = cci->shftc.ptr.p_double[nv]; + for(j=0; j<=nv-kpow-1; j++) + { + vv = state->tmp0.ptr.p_double[j]*cci->diaga.ptr.p_double[j]+cci->shftc.ptr.p_double[j]; + ccy.ptr.p_double[j] = vv; + u2 = u2+vv*vv; + } + vy = (double)(1); + vz = (double)(1); + for(j=nv-kpow; j<=nv-1; j++) + { + vv = state->tmp0.ptr.p_double[j]*cci->diaga.ptr.p_double[j]+cci->shftc.ptr.p_double[j]; + ccy.ptr.p_double[j] = vv; + ae_assert(ae_fp_greater(vv,(double)(0)), "GQPIPM: integrity check 063327 failed", _state); + vy = vy*ae_pow(vv, cci->alphapow.ptr.p_double[j-(nv-kpow)], _state); + vz = vz*vv; + } + invvy = (double)1/vy; + if( state->pctype==0 ) + { + v = u2*invvy-vy; + for(j=0; j<=nv-kpow-1; j++) + { + state->tmp1.ptr.p_double[j] = (double)2*ccy.ptr.p_double[j]*invvy*cci->diaga.ptr.p_double[j]; + } + for(j=nv-kpow; j<=nv-1; j++) + { + state->tmp1.ptr.p_double[j] = cci->diaga.ptr.p_double[j]*(-u2*invvy-vy)*cci->alphapow.ptr.p_double[j-(nv-kpow)]/ccy.ptr.p_double[j]; + } + donecc = ae_true; + } + if( state->pctype==1 ) + { + v = u2*vz*invvy-vz*vy; + for(j=0; j<=nv-kpow-1; j++) + { + state->tmp1.ptr.p_double[j] = (double)2*ccy.ptr.p_double[j]*vz*invvy*cci->diaga.ptr.p_double[j]; + } + for(j=nv-kpow; j<=nv-1; j++) + { + valpha = cci->alphapow.ptr.p_double[j-(nv-kpow)]; + state->tmp1.ptr.p_double[j] = (u2*((double)1-valpha)*invvy-((double)1+valpha)*vy)*vz/ccy.ptr.p_double[j]*cci->diaga.ptr.p_double[j]; + } + donecc = ae_true; + } + } + ae_assert(donecc, "GQPIPM: integrity check 189820 failed (unexpected cone type and/or barrier type)", _state); + state->solver.replyfi.ptr.p_double[1+offscc+i] = v; + ae_assert(state->curjac.ridx.ptr.p_int[offscc+i+1]-state->curjac.ridx.ptr.p_int[offscc+i]==cci->nvars, "GQPIPM: integrity check 811110 failed", _state); + offs = state->curjac.ridx.ptr.p_int[offscc+i]; + for(j=0; j<=cci->nvars-1; j++) + { + state->curjac.vals.ptr.p_double[offs+j] = state->tmp1.ptr.p_double[chi->ordervaridx.ptr.p_int[j]]; + } + if( state->algomode==gqpipm_amdense ) + { + vlag = state->currentlag.ptr.p_double[offscc+i]; + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + vy = ccy.ptr.p_double[cci->nvars-1]; + ae_assert(ae_fp_greater(vy,(double)(0)), "GQPIPM: integrity check 323638 failed", _state); + v = (double)2/vy; + tgt1 = cci->varidx.ptr.p_int[cci->nvars-1]; + jmid = ibinarysearchlft(&cci->varidx, 0, cci->nvars-1, tgt1, _state); + ae_assert(jmid==cci->nvars-1||cci->varidx.ptr.p_int[jmid]>tgt1, "GQPIPM: integrity check 547204 failed", _state); + for(j=0; j<=jmid-1; j++) + { + tgt0 = cci->varidx.ptr.p_int[j]; + state->currenth.ptr.pp_double[tgt0][tgt0] = state->currenth.ptr.pp_double[tgt0][tgt0]+vlag*v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[j]); + state->currenth.ptr.pp_double[tgt1][tgt0] = state->currenth.ptr.pp_double[tgt1][tgt0]-vlag*v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[cci->nvars-1]*ccy.ptr.p_double[j]/vy); + } + state->currenth.ptr.pp_double[tgt1][tgt1] = state->currenth.ptr.pp_double[tgt1][tgt1]+vlag*v*(cci->diaga.ptr.p_double[cci->nvars-1]*cci->diaga.ptr.p_double[cci->nvars-1]*u2/(vy*vy)); + for(j=jmid; j<=cci->nvars-2; j++) + { + tgt0 = cci->varidx.ptr.p_int[j]; + state->currenth.ptr.pp_double[tgt0][tgt0] = state->currenth.ptr.pp_double[tgt0][tgt0]+vlag*v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[j]); + state->currenth.ptr.pp_double[tgt0][tgt1] = state->currenth.ptr.pp_double[tgt0][tgt1]-vlag*v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[cci->nvars-1]*ccy.ptr.p_double[j]/vy); + } + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + ae_assert(state->pctype==0, "GQPIPM: integrity check 194815 failed", _state); + u2 = cci->shftc.ptr.p_double[nv]; + for(j=0; j<=nv-kpow-1; j++) + { + u2 = u2+ccy.ptr.p_double[j]*ccy.ptr.p_double[j]; + } + vy = (double)(1); + for(j=nv-kpow; j<=nv-1; j++) + { + vy = vy*ae_pow(ccy.ptr.p_double[j], cci->alphapow.ptr.p_double[j-(nv-kpow)], _state); + } + invvy = (double)1/vy; + v = (double)2/vy; + for(j=0; j<=nv-kpow-1; j++) + { + tgt0 = cci->varidx.ptr.p_int[j]; + state->currenth.ptr.pp_double[tgt0][tgt0] = state->currenth.ptr.pp_double[tgt0][tgt0]+vlag*v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[j]); + } + for(j0=nv-kpow; j0<=nv-1; j0++) + { + for(j1=nv-kpow; j1<=j0-1; j1++) + { + tgt0 = cci->varidx.ptr.p_int[j0]; + tgt1 = cci->varidx.ptr.p_int[j1]; + if( tgt1>tgt0 ) + { + jj = tgt0; + tgt0 = tgt1; + tgt1 = jj; + } + v = cci->alphapow.ptr.p_double[j0-(nv-kpow)]*cci->alphapow.ptr.p_double[j1-(nv-kpow)]/(ccy.ptr.p_double[j0]*ccy.ptr.p_double[j1]); + state->currenth.ptr.pp_double[tgt0][tgt1] = state->currenth.ptr.pp_double[tgt0][tgt1]+vlag*v*(u2*invvy-vy)*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j1]); + } + tgt0 = cci->varidx.ptr.p_int[j0]; + valpha = cci->alphapow.ptr.p_double[j0-(nv-kpow)]; + v = valpha/(ccy.ptr.p_double[j0]*ccy.ptr.p_double[j0]); + state->currenth.ptr.pp_double[tgt0][tgt0] = state->currenth.ptr.pp_double[tgt0][tgt0]+vlag*v*((valpha+(double)1)*u2*invvy-(valpha-(double)1)*vy)*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j0]); + } + v = (double)2/vy; + for(j0=nv-kpow; j0<=nv-1; j0++) + { + for(j1=0; j1<=nv-kpow-1; j1++) + { + tgt0 = cci->varidx.ptr.p_int[j0]; + tgt1 = cci->varidx.ptr.p_int[j1]; + if( tgt1>tgt0 ) + { + jj = tgt0; + tgt0 = tgt1; + tgt1 = jj; + } + valpha = cci->alphapow.ptr.p_double[j0-(nv-kpow)]; + state->currenth.ptr.pp_double[tgt0][tgt1] = state->currenth.ptr.pp_double[tgt0][tgt1]+vlag*v*(-valpha*ccy.ptr.p_double[j1]/ccy.ptr.p_double[j0])*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j1]); + } + } + donecc = ae_true; + } + ae_assert(donecc, "GQPIPM: integrity check 251026 failed", _state); + } + else + { + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + vy = ccy.ptr.p_double[cci->nvars-1]; + ae_assert(ae_fp_greater(vy,(double)(0)), "GQPIPM: integrity check 323638 failed", _state); + v = (double)2/vy; + offs = 0; + for(j=0; j<=nv-2; j++) + { + chi->lowerh.vals.ptr.p_double[offs] = v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[j]); + offs = offs+1; + } + for(j=0; j<=nv-2; j++) + { + chi->lowerh.vals.ptr.p_double[offs] = -v*(cci->diaga.ptr.p_double[j]*cci->diaga.ptr.p_double[cci->nvars-1]*ccy.ptr.p_double[j]/vy); + offs = offs+1; + } + chi->lowerh.vals.ptr.p_double[offs] = v*(cci->diaga.ptr.p_double[cci->nvars-1]*cci->diaga.ptr.p_double[cci->nvars-1]*u2/(vy*vy)); + offs = offs+1; + ae_assert(offs==2*nv-1, "GQPIPM: integrity check 895149 failed", _state); + k = chi->lowerh.ridx.ptr.p_int[nv]; + for(j=0; j<=k-1; j++) + { + state->sparsehdeps.vals.ptr.p_double[chi->injectionoffsets.ptr.p_int[j]] = chi->lowerh.vals.ptr.p_double[j]; + } + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + ae_assert(state->pctype==0, "GQPIPM: integrity check 311816 failed", _state); + u2 = cci->shftc.ptr.p_double[nv]; + for(j=0; j<=nv-kpow-1; j++) + { + u2 = u2+ccy.ptr.p_double[j]*ccy.ptr.p_double[j]; + } + vy = (double)(1); + for(j=nv-kpow; j<=nv-1; j++) + { + vy = vy*ae_pow(ccy.ptr.p_double[j], cci->alphapow.ptr.p_double[j-(nv-kpow)], _state); + } + invvy = (double)1/vy; + offs = 0; + v = (double)2/vy; + for(j0=0; j0<=nv-kpow-1; j0++) + { + chi->lowerh.vals.ptr.p_double[offs] = v*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j0]); + offs = offs+1; + } + for(j0=nv-kpow; j0<=nv-1; j0++) + { + for(j1=0; j1<=nv-kpow-1; j1++) + { + chi->lowerh.vals.ptr.p_double[offs] = (double)2*invvy*(-cci->alphapow.ptr.p_double[j0-(nv-kpow)]*ccy.ptr.p_double[j1]/ccy.ptr.p_double[j0])*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j1]); + offs = offs+1; + } + for(j1=nv-kpow; j1<=j0-1; j1++) + { + v = cci->alphapow.ptr.p_double[j0-(nv-kpow)]*cci->alphapow.ptr.p_double[j1-(nv-kpow)]/(ccy.ptr.p_double[j0]*ccy.ptr.p_double[j1]); + chi->lowerh.vals.ptr.p_double[offs] = v*(u2*invvy-vy)*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j1]); + offs = offs+1; + } + valpha = cci->alphapow.ptr.p_double[j0-(nv-kpow)]; + v = valpha/(ccy.ptr.p_double[j0]*ccy.ptr.p_double[j0]); + chi->lowerh.vals.ptr.p_double[offs] = v*((valpha+(double)1)*u2*invvy-(valpha-(double)1)*vy)*(cci->diaga.ptr.p_double[j0]*cci->diaga.ptr.p_double[j0]); + offs = offs+1; + } + ae_assert(offs==chi->lowerh.ridx.ptr.p_int[nv], "GQPIPM: integrity check 318256 failed", _state); + k = chi->lowerh.ridx.ptr.p_int[nv]; + for(j=0; j<=k-1; j++) + { + state->sparsehdeps.vals.ptr.p_double[chi->injectionoffsets.ptr.p_int[j]] = chi->lowerh.vals.ptr.p_double[j]; + } + donecc = ae_true; + } + ae_assert(donecc, "GQPIPM: integrity check 895132 failed", _state); + } + } + if( mtotal>0 ) + { + sparseappendmatrix(&state->solver.replysj, &state->curjac, _state); + } + if( state->algomode!=gqpipm_amdense ) + { + rallocv(mtotal+1, &state->tmp0, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmp0, 0, _state); + for(i=0; i<=state->msocc-1; i++) + { + state->tmp0.ptr.p_double[offscc+i] = ae_maxreal(state->tmp0.ptr.p_double[offscc+i], 0.0, _state); + } + state->tmp0.ptr.p_double[mtotal] = 1.0; + sparsemv(&state->sparsehdeps, &state->tmp0, &state->sparseh.vals, _state); + } + ae_nxpool_recycle(&state->nrealpool, &ccy, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Handle factorization request + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_handlefactorize(gqpipmstate* state, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + double v; + + + n = state->n; + ae_assert(*remembered, "GQPIPM: integrity check 8128 failed", _state); + if( state->algomode==gqpipm_amdense ) + { + rallocv(n, &state->tmpd1, _state); + rcopyvx(n, &state->solver.querydata, 0, &state->tmpd1, 0, _state); + rallocv(mtotal, &state->tmpd2, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmpd2, 0, _state); + rcopyallocm(n, n, &state->currenth, &state->currentch, _state); + for(i=0; i<=n-1; i++) + { + state->currentch.ptr.pp_double[i][i] = state->currentch.ptr.pp_double[i][i]+state->tmpd1.ptr.p_double[i]; + } + if( mtotal>0 ) + { + rallocm(mtotal, n, &state->tmpwj, _state); + for(i=0; i<=mtotal-1; i++) + { + rsetr(n, 0.0, &state->tmpwj, i, _state); + v = ae_sqrt(-(double)1/state->tmpd2.ptr.p_double[i], _state); + j0 = state->curjac.ridx.ptr.p_int[i]; + j1 = state->curjac.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->tmpwj.ptr.pp_double[i][state->curjac.idx.ptr.p_int[jj]] = v*state->curjac.vals.ptr.p_double[jj]; + } + } + rmatrixsyrk(n, mtotal, 1.0, &state->tmpwj, 0, 0, 2, 1.0, &state->currentch, 0, 0, ae_false, _state); + } + *factorized = spdmatrixcholeskyrec(&state->currentch, 0, n, ae_false, &state->tmp0, _state); + } + else + { + ae_assert(state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid, "GQPIPM: integrity check 577311 failed", _state); + ae_assert(state->algomode==gqpipm_amhybrid||state->hessmemlen==0, "GQPIPM: integrity check 578312 failed", _state); + if( state->algomode==gqpipm_amhybrid&&state->nq>0 ) + { + ae_assert(state->basehrank<=2*state->hessmemlen, "GQPIPM: integrity check 533316 failed", _state); + hessiangetlowrankstabilized(&state->hess, &state->basehsr1diag, &state->basehsr1corrc, &state->basehsr1corrd, &state->basehrank, _state); + } + ballocv(n+mtotal+2*state->hessmemlen, &state->tmpb, _state); + state->sparsesys.m = n+mtotal+2*state->hessmemlen; + state->sparsesys.n = n+mtotal+2*state->hessmemlen; + iallocv(n+mtotal+1, &state->sparsesys.ridx, _state); + state->sparsesys.ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=n-1; i++) + { + igrowv(offs+n, &state->sparsesys.idx, _state); + rgrowv(offs+n, &state->sparsesys.vals, _state); + j0 = state->sparseh.ridx.ptr.p_int[i]; + j1 = state->sparseh.didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = state->sparseh.idx.ptr.p_int[jj]; + state->sparsesys.vals.ptr.p_double[offs] = state->sparseh.vals.ptr.p_double[jj]; + offs = offs+1; + } + v = 0.0; + if( state->sparseh.didx.ptr.p_int[i]sparseh.uidx.ptr.p_int[i] ) + { + v = state->sparseh.vals.ptr.p_double[state->sparseh.didx.ptr.p_int[i]]; + } + if( state->algomode==gqpipm_amhybrid&&inq ) + { + v = v+state->basehsr1diag.ptr.p_double[i]; + } + v = v+state->solver.querydata.ptr.p_double[i]; + state->sparsesys.idx.ptr.p_int[offs] = i; + state->sparsesys.vals.ptr.p_double[offs] = v; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[i+1] = offs; + state->tmpb.ptr.p_bool[i] = ae_true; + } + for(i=0; i<=mtotal-1; i++) + { + igrowv(offs+n+1, &state->sparsesys.idx, _state); + rgrowv(offs+n+1, &state->sparsesys.vals, _state); + j0 = state->curjac.ridx.ptr.p_int[i]; + j1 = state->curjac.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = state->curjac.idx.ptr.p_int[jj]; + state->sparsesys.vals.ptr.p_double[offs] = state->curjac.vals.ptr.p_double[jj]; + offs = offs+1; + } + v = state->solver.querydata.ptr.p_double[n+i]; + state->sparsesys.idx.ptr.p_int[offs] = n+i; + state->sparsesys.vals.ptr.p_double[offs] = v; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[n+i+1] = offs; + state->tmpb.ptr.p_bool[n+i] = ae_false; + } + for(i=0; i<=2*state->hessmemlen-1; i++) + { + if( state->nq>0&&ibasehrank ) + { + for(j=0; j<=state->nq-1; j++) + { + state->sparsesys.vals.ptr.p_double[offs+j] = state->basehsr1corrc.ptr.pp_double[i][j]; + } + state->sparsesys.vals.ptr.p_double[offs+state->nq] = -state->basehsr1corrd.ptr.p_double[i]; + } + else + { + for(j=0; j<=state->nq-1; j++) + { + state->sparsesys.vals.ptr.p_double[offs+j] = (double)(0); + } + state->sparsesys.vals.ptr.p_double[offs+state->nq] = (double)(1); + } + state->tmpb.ptr.p_bool[n+mtotal+i] = ae_fp_greater(state->sparsesys.vals.ptr.p_double[offs+state->nq],(double)(0)); + offs = offs+state->nq+1; + state->sparsesys.ridx.ptr.p_int[n+mtotal+i+1] = offs; + } + sparsecreatecrsinplace(&state->sparsesys, _state); + spsymmreload(&state->analysis, &state->sparsesys, _state); + spsymmcontrolsign(&state->analysis, &state->tmpb, 0.0, _state); + *factorized = spsymmfactorize(&state->analysis, _state); + } + state->solver.factsuccess = *factorized; +} + + +/************************************************************************* +Handle solve request + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_handlesolve(gqpipmstate* state, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(*factorized, "GQPIPM: integrity check 2043 failed", _state); + if( state->algomode==gqpipm_amdense ) + { + rallocv(mtotal, &state->tmprhsy, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmprhsy, 0, _state); + rcopyallocv(mtotal, &state->tmprhsy, &state->tmp1, _state); + rmergedivv(mtotal, &state->tmpd2, &state->tmp1, _state); + rcopyv(n, &state->solver.querydata, &state->solver.replysol, _state); + if( mtotal>0 ) + { + sparsegemv(&state->curjac, -1.0, 1, &state->tmp1, 0, 1.0, &state->solver.replysol, 0, _state); + } + rtrsvx(n, &state->currentch, 0, 0, ae_false, ae_false, 0, &state->solver.replysol, 0, _state); + rtrsvx(n, &state->currentch, 0, 0, ae_false, ae_false, 1, &state->solver.replysol, 0, _state); + if( mtotal>0 ) + { + sparsegemv(&state->curjac, -1.0, 0, &state->solver.replysol, 0, 1.0, &state->tmprhsy, 0, _state); + } + rmergedivv(mtotal, &state->tmpd2, &state->tmprhsy, _state); + rcopyvx(mtotal, &state->tmprhsy, 0, &state->solver.replysol, n, _state); + return; + } + if( state->algomode==gqpipm_amsparse ) + { + rcopyv(n+mtotal, &state->solver.querydata, &state->solver.replysol, _state); + spsymmsolve(&state->analysis, &state->solver.replysol, _state); + return; + } + if( state->algomode==gqpipm_amhybrid ) + { + rallocv(n+mtotal+2*state->hessmemlen, &state->tmp0, _state); + rcopyv(n+mtotal, &state->solver.querydata, &state->tmp0, _state); + rsetvx(2*state->hessmemlen, 0.0, &state->tmp0, n+mtotal, _state); + spsymmsolve(&state->analysis, &state->tmp0, _state); + rcopyv(n+mtotal, &state->tmp0, &state->solver.replysol, _state); + return; + } + ae_assert(ae_false, "GQPIPM: integrity check 721333 failed", _state); +} + + +/************************************************************************* +Handle matrix-vector product request + + -- ALGLIB -- + Copyright 25.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_handlemv(gqpipmstate* state, + ae_int_t offslc, + ae_int_t offsqc, + ae_int_t offsec, + ae_int_t offscc, + ae_int_t mtotal, + ae_bool* remembered, + ae_bool* factorized, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_int_t j; + double vlag; + xquadraticconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + gqpsparseconichessian *chi; + ae_smart_ptr _chi; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + memset(&_chi, 0, sizeof(_chi)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_chi, (void**)&chi, ae_false, _state, ae_true); + + n = state->n; + ae_assert(*remembered, "GQPIPM: integrity check 4322 failed", _state); + if( state->algomode==gqpipm_amdense ) + { + rallocv(ae_maxint(n, mtotal, _state), &state->tmp0, _state); + rallocv(ae_maxint(n, mtotal, _state), &state->tmp1, _state); + rcopyvx(n, &state->solver.querydata, 0, &state->tmp0, 0, _state); + rmatrixsymv(n, 1.0, &state->currenth, 0, 0, ae_false, &state->tmp0, 0, 0.0, &state->tmp1, 0, _state); + rcopyvx(n, &state->tmp1, 0, &state->solver.replyprod, 0, _state); + if( mtotal>0 ) + { + sparsegemv(&state->curjac, 1.0, 0, &state->tmp0, 0, 0.0, &state->tmp1, 0, _state); + } + else + { + rsetv(mtotal, 0.0, &state->tmp1, _state); + } + rcopyvx(mtotal, &state->tmp1, 0, &state->solver.replyprod, n, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmp0, 0, _state); + if( mtotal>0 ) + { + sparsegemv(&state->curjac, 1.0, 1, &state->tmp0, 0, 0.0, &state->tmp1, 0, _state); + } + else + { + rsetv(n, 0.0, &state->tmp1, _state); + } + rcopyvx(n, &state->tmp1, 0, &state->solver.replyprod, n+mtotal, _state); + } + else + { + ae_assert(state->algomode==gqpipm_amsparse||state->algomode==gqpipm_amhybrid, "GQPIPM: integrity check 777338 failed", _state); + rallocv(ae_maxint(n, mtotal, _state), &state->tmp0, _state); + rallocv(ae_maxint(n, mtotal, _state), &state->tmp1, _state); + if( state->algomode==gqpipm_amhybrid ) + { + if( state->nq>0 ) + { + rcopyv(state->nq, &state->solver.querydata, &state->tmp0, _state); + rmergemulv(state->nq, &state->basehsr1diag, &state->tmp0, _state); + if( state->basehrank>0 ) + { + rgemv(state->basehrank, state->nq, 1.0, &state->basehsr1corrc, 0, &state->solver.querydata, 0.0, &state->tmp1, _state); + rmergemulv(state->basehrank, &state->basehsr1corrd, &state->tmp1, _state); + rgemv(state->nq, state->basehrank, 1.0, &state->basehsr1corrc, 1, &state->tmp1, 1.0, &state->tmp0, _state); + } + rcopyvx(state->nq, &state->tmp0, 0, &state->solver.replyprod, 0, _state); + } + rsetvx(n-state->nq, 0.0, &state->solver.replyprod, state->nq, _state); + } + else + { + rsetv(n, 0.0, &state->solver.replyprod, _state); + } + if( state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[0] ) + { + sparsesmv(&state->sparseq1, ae_false, &state->solver.querydata, &state->tmp0, _state); + raddv(n, 1.0, &state->tmp0, &state->solver.replyprod, _state); + } + for(i=0; i<=state->mqc-1; i++) + { + if( state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[1+offsqc+i] ) + { + ae_obj_array_get(&state->xqc.constraints, i, &_qci, _state); + if( qci->nvars==0 ) + { + continue; + } + for(j=0; j<=qci->nvars-1; j++) + { + state->tmp0.ptr.p_double[j] = state->solver.querydata.ptr.p_double[qci->varidx.ptr.p_int[j]]; + } + sparsesmv(&qci->lowerq, ae_false, &state->tmp0, &state->tmp1, _state); + vlag = state->currentlag.ptr.p_double[offsqc+i]; + for(j=0; j<=qci->nvars-1; j++) + { + state->solver.replyprod.ptr.p_double[qci->varidx.ptr.p_int[j]] = state->solver.replyprod.ptr.p_double[qci->varidx.ptr.p_int[j]]+vlag*state->tmp1.ptr.p_double[j]; + } + } + } + for(i=0; i<=state->msocc-1; i++) + { + ae_assert(state->algomode!=gqpipm_amhybrid||!state->doqnupdates.ptr.p_bool[1+offscc+i], "GQPIPM: integrity check 907345 failed", _state); + ae_obj_array_get(&state->xcc.constraints, i, &_cci, _state); + ae_obj_array_get(&state->xchsparse, i, &_chi, _state); + if( cci->nvars==0 ) + { + continue; + } + for(j=0; j<=cci->nvars-1; j++) + { + state->tmp0.ptr.p_double[j] = state->solver.querydata.ptr.p_double[cci->varidx.ptr.p_int[j]]; + } + sparsesmv(&chi->lowerh, ae_false, &state->tmp0, &state->tmp1, _state); + vlag = state->currentlag.ptr.p_double[offscc+i]; + for(j=0; j<=cci->nvars-1; j++) + { + state->solver.replyprod.ptr.p_double[cci->varidx.ptr.p_int[j]] = state->solver.replyprod.ptr.p_double[cci->varidx.ptr.p_int[j]]+vlag*state->tmp1.ptr.p_double[j]; + } + } + if( mtotal>0 ) + { + sparsemv(&state->curjac, &state->solver.querydata, &state->tmp1, _state); + rcopyvx(mtotal, &state->tmp1, 0, &state->solver.replyprod, n, _state); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmp0, 0, _state); + sparsemtv(&state->curjac, &state->tmp0, &state->tmp1, _state); + rcopyvx(n, &state->tmp1, 0, &state->solver.replyprod, n+mtotal, _state); + } + else + { + rsetvx(n, 0.0, &state->solver.replyprod, n+mtotal, _state); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Create optional-dense quadratic term from a sparse quadratic objective term. + + -- ALGLIB -- + Copyright 02.05.2025 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_optionaldensefromsparse(gqpoptionaldense* opt, + sparsematrix* s, + ae_int_t nq, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + + + ae_assert((sparseiscrs(s, _state)&&s->n==s->m)&&s->n>=nq, "GQPIPM: integrity check 127140 failed", _state); + opt->hasdenseterm = ae_false; + k = 0; + for(i=0; i<=nq-1; i++) + { + k = k+(s->didx.ptr.p_int[i]-s->ridx.ptr.p_int[i])+1; + } + if( nq<=2||ae_fp_less((double)(k),0.5*((double)(nq*(nq-1))/(double)2)) ) + { + return; + } + opt->nvars = nq; + iallocv(nq, &opt->varidx, _state); + for(i=0; i<=nq-1; i++) + { + opt->varidx.ptr.p_int[i] = i; + } + rallocm(nq, nq, &opt->q, _state); + for(i=0; i<=nq-1; i++) + { + rsetr(i+1, 0.0, &opt->q, i, _state); + j0 = s->ridx.ptr.p_int[i]; + j1 = s->didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + opt->q.ptr.pp_double[i][s->idx.ptr.p_int[jj]] = s->vals.ptr.p_double[jj]; + } + if( s->didx.ptr.p_int[i]uidx.ptr.p_int[i] ) + { + opt->q.ptr.pp_double[i][i] = s->vals.ptr.p_double[s->didx.ptr.p_int[i]]; + } + } + opt->hasdenseterm = ae_true; +} + + +/************************************************************************* +Create optional-dense quadratic term from sparse quadratic constraint term + + -- ALGLIB -- + Copyright 02.05.2025 by Bochkanov Sergey +*************************************************************************/ +static void gqpipm_optionaldensefromsparseqc(gqpoptionaldense* opt, + xquadraticconstraint* qc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t nq; + + + opt->hasdenseterm = ae_false; + if( qc->nvars<=2 ) + { + return; + } + nq = qc->nvars; + k = 0; + for(i=0; i<=nq-1; i++) + { + k = k+(qc->lowerq.didx.ptr.p_int[i]-qc->lowerq.ridx.ptr.p_int[i])+1; + } + if( ae_fp_less((double)(k),0.5*((double)(nq*(nq-1))/(double)2)) ) + { + return; + } + opt->nvars = nq; + iallocv(nq, &opt->varidx, _state); + for(i=0; i<=nq-1; i++) + { + opt->varidx.ptr.p_int[i] = qc->varidx.ptr.p_int[i]; + } + rallocm(nq, nq, &opt->q, _state); + for(i=0; i<=nq-1; i++) + { + rsetr(i+1, 0.0, &opt->q, i, _state); + j0 = qc->lowerq.ridx.ptr.p_int[i]; + j1 = qc->lowerq.didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + opt->q.ptr.pp_double[i][qc->lowerq.idx.ptr.p_int[jj]] = qc->lowerq.vals.ptr.p_double[jj]; + } + if( qc->lowerq.didx.ptr.p_int[i]lowerq.uidx.ptr.p_int[i] ) + { + opt->q.ptr.pp_double[i][i] = qc->lowerq.vals.ptr.p_double[qc->lowerq.didx.ptr.p_int[i]]; + } + } + opt->hasdenseterm = ae_true; +} + + +void _gqpsparseconichessian_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gqpsparseconichessian *p = (gqpsparseconichessian*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_init(&p->lowerh, _state, make_automatic); + ae_vector_init(&p->ordervaridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->injectionoffsets, 0, DT_INT, _state, make_automatic); +} + + +void _gqpsparseconichessian_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gqpsparseconichessian *dst = (gqpsparseconichessian*)_dst; + const gqpsparseconichessian *src = (const gqpsparseconichessian*)_src; + _sparsematrix_init_copy(&dst->lowerh, &src->lowerh, _state, make_automatic); + ae_vector_init_copy(&dst->ordervaridx, &src->ordervaridx, _state, make_automatic); + ae_vector_init_copy(&dst->injectionoffsets, &src->injectionoffsets, _state, make_automatic); +} + + +void _gqpsparseconichessian_clear(void* _p) +{ + gqpsparseconichessian *p = (gqpsparseconichessian*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_clear(&p->lowerh); + ae_vector_clear(&p->ordervaridx); + ae_vector_clear(&p->injectionoffsets); +} + + +void _gqpsparseconichessian_destroy(void* _p) +{ + gqpsparseconichessian *p = (gqpsparseconichessian*)_p; + ae_touch_ptr((void*)p); + _sparsematrix_destroy(&p->lowerh); + ae_vector_destroy(&p->ordervaridx); + ae_vector_destroy(&p->injectionoffsets); +} + + +void _gqpoptionaldense_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gqpoptionaldense *p = (gqpoptionaldense*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->varidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _gqpoptionaldense_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gqpoptionaldense *dst = (gqpoptionaldense*)_dst; + const gqpoptionaldense *src = (const gqpoptionaldense*)_src; + dst->hasdenseterm = src->hasdenseterm; + dst->nvars = src->nvars; + ae_vector_init_copy(&dst->varidx, &src->varidx, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); +} + + +void _gqpoptionaldense_clear(void* _p) +{ + gqpoptionaldense *p = (gqpoptionaldense*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->varidx); + ae_matrix_clear(&p->q); +} + + +void _gqpoptionaldense_destroy(void* _p) +{ + gqpoptionaldense *p = (gqpoptionaldense*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->varidx); + ae_matrix_destroy(&p->q); +} + + +void _gqpipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gqpipmstate *p = (gqpipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finiterawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finiterawbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isfixed, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->fixedidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->iotac, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->denseq, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparseq1, _state, make_automatic); + _gqpoptionaldense_init(&p->optionaldenseq1, _state, make_automatic); + _sparsematrix_init(&p->sparselc, _state, make_automatic); + ae_vector_init(&p->lcbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcbndu, 0, DT_REAL, _state, make_automatic); + _xquadraticconstraints_init(&p->xqc, _state, make_automatic); + _xconicconstraints_init(&p->xcc, _state, make_automatic); + ae_obj_array_init(&p->optionaldensexqc, _state, make_automatic); + ae_obj_array_init(&p->xchsparse, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _gipmstate_init(&p->solver, _state, make_automatic); + _sparsematrix_init(&p->curjac, _state, make_automatic); + ae_matrix_init(&p->currenth, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpd1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpd2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->currentch, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpwj, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentlag, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparseh, _state, make_automatic); + _sparsematrix_init(&p->sparsehdeps, _state, make_automatic); + _sparsematrix_init(&p->sparsesys, _state, make_automatic); + ae_vector_init(&p->priorities, 0, DT_INT, _state, make_automatic); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + _xbfgshessian_init(&p->hess, _state, make_automatic); + ae_vector_init(&p->basehsr1diag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->basehsr1corrd, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->basehsr1corrc, 0, 0, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->nrealpool, DT_REAL, _state, make_automatic); + ae_vector_init(&p->totalnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->totalnu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->wrklc, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp3, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmprhsy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->dummy2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphr, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphc, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphk, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphr2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphc2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphk2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmphv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphv2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpb, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->doqnupdates, 0, DT_BOOL, _state, make_automatic); +} + + +void _gqpipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gqpipmstate *dst = (gqpipmstate*)_dst; + const gqpipmstate *src = (const gqpipmstate*)_src; + dst->algomode = src->algomode; + dst->hessmemlen = src->hessmemlen; + dst->hessmaxoffdiag = src->hessmaxoffdiag; + dst->n = src->n; + dst->mlc = src->mlc; + dst->mqc = src->mqc; + dst->msocc = src->msocc; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndl, &src->wrkbndl, _state, make_automatic); + ae_vector_init_copy(&dst->wrkbndu, &src->wrkbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finiterawbndl, &src->finiterawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->finiterawbndu, &src->finiterawbndu, _state, make_automatic); + ae_vector_init_copy(&dst->isfixed, &src->isfixed, _state, make_automatic); + ae_vector_init_copy(&dst->fixedidx, &src->fixedidx, _state, make_automatic); + dst->fixedvarscnt = src->fixedvarscnt; + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->iotac, &src->iotac, _state, make_automatic); + ae_matrix_init_copy(&dst->denseq, &src->denseq, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseq1, &src->sparseq1, _state, make_automatic); + _gqpoptionaldense_init_copy(&dst->optionaldenseq1, &src->optionaldenseq1, _state, make_automatic); + dst->nq = src->nq; + dst->cvxobjective = src->cvxobjective; + _sparsematrix_init_copy(&dst->sparselc, &src->sparselc, _state, make_automatic); + ae_vector_init_copy(&dst->lcbndl, &src->lcbndl, _state, make_automatic); + ae_vector_init_copy(&dst->lcbndu, &src->lcbndu, _state, make_automatic); + _xquadraticconstraints_init_copy(&dst->xqc, &src->xqc, _state, make_automatic); + _xconicconstraints_init_copy(&dst->xcc, &src->xcc, _state, make_automatic); + ae_obj_array_init_copy(&dst->optionaldensexqc, &src->optionaldensexqc, _state, make_automatic); + ae_obj_array_init_copy(&dst->xchsparse, &src->xchsparse, _state, make_automatic); + dst->pctype = src->pctype; + dst->cvxqc = src->cvxqc; + dst->cvxcc = src->cvxcc; + dst->eps = src->eps; + dst->maxits = src->maxits; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->dotrace = src->dotrace; + dst->dolaconictrace = src->dolaconictrace; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _gipmstate_init_copy(&dst->solver, &src->solver, _state, make_automatic); + _sparsematrix_init_copy(&dst->curjac, &src->curjac, _state, make_automatic); + ae_matrix_init_copy(&dst->currenth, &src->currenth, _state, make_automatic); + ae_vector_init_copy(&dst->tmpd1, &src->tmpd1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpd2, &src->tmpd2, _state, make_automatic); + ae_matrix_init_copy(&dst->currentch, &src->currentch, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpwj, &src->tmpwj, _state, make_automatic); + ae_vector_init_copy(&dst->currentx, &src->currentx, _state, make_automatic); + ae_vector_init_copy(&dst->currentlag, &src->currentlag, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseh, &src->sparseh, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsehdeps, &src->sparsehdeps, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsesys, &src->sparsesys, _state, make_automatic); + ae_vector_init_copy(&dst->priorities, &src->priorities, _state, make_automatic); + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + _xbfgshessian_init_copy(&dst->hess, &src->hess, _state, make_automatic); + ae_vector_init_copy(&dst->basehsr1diag, &src->basehsr1diag, _state, make_automatic); + ae_vector_init_copy(&dst->basehsr1corrd, &src->basehsr1corrd, _state, make_automatic); + ae_matrix_init_copy(&dst->basehsr1corrc, &src->basehsr1corrc, _state, make_automatic); + dst->basehrank = src->basehrank; + ae_nxpool_init_copy(&dst->nrealpool, &src->nrealpool, _state, make_automatic); + ae_vector_init_copy(&dst->totalnl, &src->totalnl, _state, make_automatic); + ae_vector_init_copy(&dst->totalnu, &src->totalnu, _state, make_automatic); + _sparsematrix_init_copy(&dst->wrklc, &src->wrklc, _state, make_automatic); + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic); + ae_vector_init_copy(&dst->tmprhsy, &src->tmprhsy, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_matrix_init_copy(&dst->dummy2, &src->dummy2, _state, make_automatic); + ae_vector_init_copy(&dst->tmphr, &src->tmphr, _state, make_automatic); + ae_vector_init_copy(&dst->tmphc, &src->tmphc, _state, make_automatic); + ae_vector_init_copy(&dst->tmphk, &src->tmphk, _state, make_automatic); + ae_vector_init_copy(&dst->tmphr2, &src->tmphr2, _state, make_automatic); + ae_vector_init_copy(&dst->tmphc2, &src->tmphc2, _state, make_automatic); + ae_vector_init_copy(&dst->tmphk2, &src->tmphk2, _state, make_automatic); + ae_vector_init_copy(&dst->tmphv, &src->tmphv, _state, make_automatic); + ae_vector_init_copy(&dst->tmphv2, &src->tmphv2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state, make_automatic); + ae_vector_init_copy(&dst->doqnupdates, &src->doqnupdates, _state, make_automatic); +} + + +void _gqpipmstate_clear(void* _p) +{ + gqpipmstate *p = (gqpipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->wrkbndl); + ae_vector_clear(&p->wrkbndu); + ae_vector_clear(&p->finiterawbndl); + ae_vector_clear(&p->finiterawbndu); + ae_vector_clear(&p->isfixed); + ae_vector_clear(&p->fixedidx); + ae_vector_clear(&p->c); + ae_vector_clear(&p->iotac); + ae_matrix_clear(&p->denseq); + _sparsematrix_clear(&p->sparseq1); + _gqpoptionaldense_clear(&p->optionaldenseq1); + _sparsematrix_clear(&p->sparselc); + ae_vector_clear(&p->lcbndl); + ae_vector_clear(&p->lcbndu); + _xquadraticconstraints_clear(&p->xqc); + _xconicconstraints_clear(&p->xcc); + ae_obj_array_clear(&p->optionaldensexqc); + ae_obj_array_clear(&p->xchsparse); + _stimer_clear(&p->timertotal); + _gipmstate_clear(&p->solver); + _sparsematrix_clear(&p->curjac); + ae_matrix_clear(&p->currenth); + ae_vector_clear(&p->tmpd1); + ae_vector_clear(&p->tmpd2); + ae_matrix_clear(&p->currentch); + ae_matrix_clear(&p->tmpwj); + ae_vector_clear(&p->currentx); + ae_vector_clear(&p->currentlag); + _sparsematrix_clear(&p->sparseh); + _sparsematrix_clear(&p->sparsehdeps); + _sparsematrix_clear(&p->sparsesys); + ae_vector_clear(&p->priorities); + _spcholanalysis_clear(&p->analysis); + _xbfgshessian_clear(&p->hess); + ae_vector_clear(&p->basehsr1diag); + ae_vector_clear(&p->basehsr1corrd); + ae_matrix_clear(&p->basehsr1corrc); + ae_nxpool_clear(&p->nrealpool); + ae_vector_clear(&p->totalnl); + ae_vector_clear(&p->totalnu); + _sparsematrix_clear(&p->wrklc); + ae_vector_clear(&p->fscales); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmp3); + ae_vector_clear(&p->tmpx); + ae_vector_clear(&p->tmprhsy); + ae_vector_clear(&p->tmpi); + ae_matrix_clear(&p->dummy2); + ae_vector_clear(&p->tmphr); + ae_vector_clear(&p->tmphc); + ae_vector_clear(&p->tmphk); + ae_vector_clear(&p->tmphr2); + ae_vector_clear(&p->tmphc2); + ae_vector_clear(&p->tmphk2); + ae_vector_clear(&p->tmphv); + ae_vector_clear(&p->tmphv2); + ae_vector_clear(&p->tmpb); + ae_vector_clear(&p->doqnupdates); +} + + +void _gqpipmstate_destroy(void* _p) +{ + gqpipmstate *p = (gqpipmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->wrkbndl); + ae_vector_destroy(&p->wrkbndu); + ae_vector_destroy(&p->finiterawbndl); + ae_vector_destroy(&p->finiterawbndu); + ae_vector_destroy(&p->isfixed); + ae_vector_destroy(&p->fixedidx); + ae_vector_destroy(&p->c); + ae_vector_destroy(&p->iotac); + ae_matrix_destroy(&p->denseq); + _sparsematrix_destroy(&p->sparseq1); + _gqpoptionaldense_destroy(&p->optionaldenseq1); + _sparsematrix_destroy(&p->sparselc); + ae_vector_destroy(&p->lcbndl); + ae_vector_destroy(&p->lcbndu); + _xquadraticconstraints_destroy(&p->xqc); + _xconicconstraints_destroy(&p->xcc); + ae_obj_array_destroy(&p->optionaldensexqc); + ae_obj_array_destroy(&p->xchsparse); + _stimer_destroy(&p->timertotal); + _gipmstate_destroy(&p->solver); + _sparsematrix_destroy(&p->curjac); + ae_matrix_destroy(&p->currenth); + ae_vector_destroy(&p->tmpd1); + ae_vector_destroy(&p->tmpd2); + ae_matrix_destroy(&p->currentch); + ae_matrix_destroy(&p->tmpwj); + ae_vector_destroy(&p->currentx); + ae_vector_destroy(&p->currentlag); + _sparsematrix_destroy(&p->sparseh); + _sparsematrix_destroy(&p->sparsehdeps); + _sparsematrix_destroy(&p->sparsesys); + ae_vector_destroy(&p->priorities); + _spcholanalysis_destroy(&p->analysis); + _xbfgshessian_destroy(&p->hess); + ae_vector_destroy(&p->basehsr1diag); + ae_vector_destroy(&p->basehsr1corrd); + ae_matrix_destroy(&p->basehsr1corrc); + ae_nxpool_destroy(&p->nrealpool); + ae_vector_destroy(&p->totalnl); + ae_vector_destroy(&p->totalnu); + _sparsematrix_destroy(&p->wrklc); + ae_vector_destroy(&p->fscales); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmp3); + ae_vector_destroy(&p->tmpx); + ae_vector_destroy(&p->tmprhsy); + ae_vector_destroy(&p->tmpi); + ae_matrix_destroy(&p->dummy2); + ae_vector_destroy(&p->tmphr); + ae_vector_destroy(&p->tmphc); + ae_vector_destroy(&p->tmphk); + ae_vector_destroy(&p->tmphr2); + ae_vector_destroy(&p->tmphc2); + ae_vector_destroy(&p->tmphk2); + ae_vector_destroy(&p->tmphv); + ae_vector_destroy(&p->tmphv2); + ae_vector_destroy(&p->tmpb); + ae_vector_destroy(&p->doqnupdates); +} + + +#endif +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +No presolve, just user-supplied scaling + constraint and cost vector +normalization. + +INPUT PARAMETERS: + S - array[N], user-supplied scale vector, S[I]>0 + C - array[N], costs + BndL - array[N], lower bounds (may contain -INF) + BndU - array[N], upper bounds (may contain +INF) + N - variable count, N>0 + SparseA - matrix[K,N], sparse constraints + AL - array[K], lower constraint bounds (may contain -INF) + AU - array[K], upper constraint bounds (may contain +INF) + K - constraint count, K>=0 + Info - presolve info structure; temporaries allocated during + previous calls may be reused by this function. + +OUTPUT PARAMETERS: + Info - contains transformed C, BndL, bndU, SparseA, AL, AU + and information necessary to perform backward + transformation. + Following fields can be accessed: + * ProblemStatus which is: + * 0 for successful transformation + * -3 for infeasible problem + * -4 for unbounded problem + + If Info.ProblemStatus=0, then the following fields can + be accessed: + * Info.NewN>0 for transformed problem size + * Info.NewM>=0 for transformed linear constraint count + * Info.NewMQC>=0 for transformed quadratic constraint count + * always: Info.C, Info.BndL, Info.BndU - array[NewN] + * for Info.NewM>0: Info.SparseA, Info.AL, Info.AU + * for Info.NewMQC>0: Info.XQC + +NOTE: this routine does not reallocate arrays if NNew<=NOld and/or KNew<=KOld. + + -- ALGLIB -- + Copyright 01.07.2020 by Bochkanov Sergey +*************************************************************************/ +void presolvenonescaleuser(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparseh, + ae_bool isupper, + ae_bool hash, + ae_int_t n, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_bool dotrace, + presolveinfo* info, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + xconicconstraint *cc; + ae_smart_ptr _cc; + + ae_frame_make(_state, &_frame_block); + memset(&_cc, 0, sizeof(_cc)); + ae_smart_ptr_init(&_cc, (void**)&cc, ae_false, _state, ae_true); + + + /* + * Integrity checks + */ + ae_assert(bndl->cnt>=n, "PresolveNoneScaleUser: Length(BndL)cnt>=n, "PresolveNoneScaleUser: Length(BndU)cnt>=n, "PresolveNoneScaleUser: Length(S)cnt>=n, "PresolveNoneScaleUser: Length(C)=0, "PresolveNoneScaleUser: K<0", _state); + ae_assert(k==0||sparseiscrs(sparsea, _state), "PresolveNoneScaleUser: A is not CRS", _state); + ae_assert(k==0||sparsea->m==k, "PresolveNoneScaleUser: rows(A)<>K", _state); + ae_assert(k==0||sparsea->n==n, "PresolveNoneScaleUser: cols(A)<>N", _state); + ae_assert(!hash||sparseiscrs(sparseh, _state), "PresolveNoneScaleUser: A is not CRS", _state); + + /* + * Initial check for constraint feasibility and canonicity + */ + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state))&&ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + if( dotrace ) + { + ae_trace("> variable %0d is found to have infeasible box constraints, terminating\n", + (int)(i)); + } + info->problemstatus = -3; + ae_frame_leave(_state); + return; + } + } + for(i=0; i<=k-1; i++) + { + if( (ae_isfinite(al->ptr.p_double[i], _state)&&ae_isfinite(au->ptr.p_double[i], _state))&&ae_fp_greater(al->ptr.p_double[i],au->ptr.p_double[i]) ) + { + if( dotrace ) + { + ae_trace("> linear constraint %0d is found to have infeasible bounds, terminating\n", + (int)(i)); + } + info->problemstatus = -3; + ae_frame_leave(_state); + return; + } + } + for(i=0; i<=xccgetcount(xcc, _state)-1; i++) + { + ae_obj_array_get(&xcc->constraints, i, &_cc, _state); + ae_assert(cc->conetype>=0, "PresolveNoneScaleUser: one of the conic constraints has non-canonic form", _state); + } + + /* + * Reallocate storage + */ + rvectorgrowto(&info->rawc, n, _state); + rvectorgrowto(&info->rawbndl, n, _state); + rvectorgrowto(&info->rawbndu, n, _state); + + /* + * Save original problem formulation + */ + lpqppresolve_presolverstackinit(n, k, xqcgetcount(xqc, _state), xccgetcount(xcc, _state), &info->trfstack, _state); + info->eps = ae_machineepsilon; + info->problemstatus = 0; + info->newn = n; + info->oldn = n; + info->newm = k; + info->oldm = k; + info->oldmqc = xqcgetcount(xqc, _state); + info->newmqc = info->oldmqc; + info->oldmcc = xccgetcount(xcc, _state); + info->newmcc = info->oldmcc; + bsetallocv(n, ae_false, &info->lagrangefromresidual, _state); + iallocv(n, &info->packxperm, _state); + iallocv(n, &info->unpackxperm, _state); + for(i=0; i<=n-1; i++) + { + ae_assert(s->ptr.p_double[i]>(double)0, "PresolveNoneScaleUser: S<=0", _state); + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "PresolveNoneScaleUser: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "PresolveNoneScaleUser: BndU contains NAN or -INF", _state); + info->rawc.ptr.p_double[i] = c->ptr.p_double[i]; + info->rawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + info->rawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + info->packxperm.ptr.p_int[i] = i; + info->unpackxperm.ptr.p_int[i] = i; + } + info->hash = hash; + if( hash ) + { + lpqppresolve_copyexpandh(sparseh, isupper, &info->rawh, _state); + sparsecopybuf(&info->rawh, &info->sparseh, _state); + } + iallocv(k, &info->packyperm, _state); + iallocv(k, &info->unpackyperm, _state); + for(i=0; i<=k-1; i++) + { + info->packyperm.ptr.p_int[i] = i; + info->unpackyperm.ptr.p_int[i] = i; + } + iallocv(info->newmqc, &info->packqcperm, _state); + iallocv(info->newmqc, &info->unpackqcperm, _state); + for(i=0; i<=info->newmqc-1; i++) + { + info->packqcperm.ptr.p_int[i] = i; + info->unpackqcperm.ptr.p_int[i] = i; + } + iallocv(n+k, &info->packstatperm, _state); + iallocv(n+k, &info->unpackstatperm, _state); + for(i=0; i<=n+k-1; i++) + { + info->packstatperm.ptr.p_int[i] = i; + info->unpackstatperm.ptr.p_int[i] = i; + } + sparsecopytocrsbuf(sparsea, &info->rawa, _state); + xqccopy(xqc, &info->rawxqc, _state); + xcccopy(xcc, &info->rawxcc, _state); + + /* + * Scale cost and box constraints + */ + rcopyallocv(n, c, &info->c, _state); + rcopyallocv(n, bndl, &info->bndl, _state); + rcopyallocv(n, bndu, &info->bndu, _state); + if( k>0 ) + { + rcopyallocv(k, al, &info->al, _state); + rcopyallocv(k, au, &info->au, _state); + sparsecopybuf(sparsea, &info->sparsea, _state); + } + xqccopy(xqc, &info->xqc, _state); + xcccopy(xcc, &info->xcc, _state); + lpqppresolve_scaleshiftobjectiveandconstraints(s, xorigin, n, &info->c, &info->bndl, &info->bndu, &info->sparseh, hash, &info->sparsea, &info->al, &info->au, k, &info->xqc, &info->xcc, &info->trfstack, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Extensive presolving for an LP problem, all techniques are used + +INPUT PARAMETERS: + S - array[N], user-supplied scale vector, S[I]>0 + C - array[N], costs + BndL - array[N], lower bounds (may contain -INF) + BndU - array[N], upper bounds (may contain +INF) + N - variable count, N>0 + SparseA - matrix[K,N], sparse constraints + AL - array[K], lower constraint bounds (may contain -INF) + AU - array[K], upper constraint bounds (may contain +INF) + K - constraint count, K>=0 + XQC - quadratic constraints; can be empty, but must be correctly + initialized with xqcInit() + XCC - conic constraints; can be empty, but must be correctly + initialized with xccInit() + Info - presolve info structure; temporaries allocated during + previous calls may be reused by this function. + +OUTPUT PARAMETERS: + Info - contains transformed C, BndL, bndU, SparseA, AL, AU + and information necessary to perform backward + transformation. + Following fields can be acessed: + * Info.NewN>0 for transformed problem size + * Info.NewM>=0 for transformed constraint count + * always: Info.C, Info.BndL, Info.BndU - array[NewN] + * for Info.NewM>0: Info.SparseA, Info.AL, Info.AU + +NOTE: this routine does not reallocate arrays if NNew<=NOld and/or KNew<=KOld. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +void presolvelp(/* Real */ const ae_vector* raws, + /* Real */ const ae_vector* rawc, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + ae_int_t n, + const sparsematrix* rawsparsea, + /* Real */ const ae_vector* rawal, + /* Real */ const ae_vector* rawau, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_bool dotrace, + presolveinfo* presolved, + ae_state *_state) +{ + ae_frame _frame_block; + sparsematrix dummyh; + ae_vector dummyorigin; + + ae_frame_make(_state, &_frame_block); + memset(&dummyh, 0, sizeof(dummyh)); + memset(&dummyorigin, 0, sizeof(dummyorigin)); + _sparsematrix_init(&dummyh, _state, ae_true); + ae_vector_init(&dummyorigin, 0, DT_REAL, _state, ae_true); + + rsetallocv(n, 0.0, &dummyorigin, _state); + presolveqp(raws, &dummyorigin, rawc, rawbndl, rawbndu, &dummyh, ae_false, ae_false, n, rawsparsea, rawal, rawau, m, xqc, xcc, dotrace, presolved, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Extensive presolving for an QP problem, all techniques are used + +INPUT PARAMETERS: + S - array[N], user-supplied scale vector, S[I]>0 + C - array[N], costs + BndL - array[N], lower bounds (may contain -INF) + BndU - array[N], upper bounds (may contain +INF) + H - if HasH=True, lower/upper triangular quadratic term + HasH - if false, H is ignored + N - variable count, N>0 + SparseA - matrix[K,N], sparse constraints + AL - array[K], lower constraint bounds (may contain -INF) + AU - array[K], upper constraint bounds (may contain +INF) + K - constraint count, K>=0 + XQC - quadratic constraints; can be empty, but must be correctly + initialized with xqcInit(). Not modified, however it + is passed as shared because we access it with + objArray...() family of functions. + XCC - conic constraints; can be empty, but must be correctly + initialized with xccInit(). Not modified, however it + is passed as shared because we access it with + objArray...() family of functions. + Info - presolve info structure; temporaries allocated during + previous calls may be reused by this function. + +OUTPUT PARAMETERS: + Info - contains transformed C, BndL, bndU, SparseA, AL, AU + and information necessary to perform backward + transformation. + Following fields can be acessed: + * Info.NewN>0 for transformed problem size + * Info.NewM>=0 for transformed constraint count + * always: Info.C, Info.BndL, Info.BndU - array[NewN] + * for Info.NewM>0: Info.SparseA, Info.AL, Info.AU + +NOTE: this routine does not reallocate arrays if NNew<=NOld and/or KNew<=KOld. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +void presolveqp(/* Real */ const ae_vector* raws, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* rawc, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + const sparsematrix* rawsparseh, + ae_bool isupper, + ae_bool hash, + ae_int_t n, + const sparsematrix* rawsparsea, + /* Real */ const ae_vector* rawal, + /* Real */ const ae_vector* rawau, + ae_int_t m, + xquadraticconstraints* rawxqc, + xconicconstraints* rawxcc, + ae_bool dotrace, + presolveinfo* presolved, + ae_state *_state) +{ + ae_frame _frame_block; + ae_bool somethingchanged; + sparsematrix normsparsea; + sparsematrix normsparseat; + xquadraticconstraints normxqc; + xconicconstraints normxcc; + dynamiccrs sparseh; + dynamiccrs a; + dynamiccrs at; + dynamiccrsqconstraints qc; + ae_vector c; + ae_vector bndl; + ae_vector bndu; + ae_vector al; + ae_vector au; + ae_int_t i; + ae_int_t k; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t mqc; + ae_int_t mcc; + ae_int_t nv; + ae_int_t offs; + ae_int_t dbgemptycol; + ae_int_t dbgemptyrow; + ae_int_t dbgemptyqc; + ae_int_t dbgnonbindingrows; + ae_int_t dbgnonbindingqc; + ae_int_t dbgfixed; + ae_int_t dbgsingletonrow; + ae_int_t dbgdoubletonrow; + ae_int_t dbgslackvars; + ae_int_t dbgimplicitslacks; + ae_int_t dbgfreecolumnsingletons; + double eps; + ae_int_t presolverounds; + sparsematrix sparsetmp; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + xquadraticconstraint *xqci; + ae_smart_ptr _xqci; + presolvervcstats vcstats; + ae_int_t kpow; + ae_bool donecc; + + ae_frame_make(_state, &_frame_block); + memset(&normsparsea, 0, sizeof(normsparsea)); + memset(&normsparseat, 0, sizeof(normsparseat)); + memset(&normxqc, 0, sizeof(normxqc)); + memset(&normxcc, 0, sizeof(normxcc)); + memset(&sparseh, 0, sizeof(sparseh)); + memset(&a, 0, sizeof(a)); + memset(&at, 0, sizeof(at)); + memset(&qc, 0, sizeof(qc)); + memset(&c, 0, sizeof(c)); + memset(&bndl, 0, sizeof(bndl)); + memset(&bndu, 0, sizeof(bndu)); + memset(&al, 0, sizeof(al)); + memset(&au, 0, sizeof(au)); + memset(&sparsetmp, 0, sizeof(sparsetmp)); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + memset(&_xqci, 0, sizeof(_xqci)); + memset(&vcstats, 0, sizeof(vcstats)); + _sparsematrix_init(&normsparsea, _state, ae_true); + _sparsematrix_init(&normsparseat, _state, ae_true); + _xquadraticconstraints_init(&normxqc, _state, ae_true); + _xconicconstraints_init(&normxcc, _state, ae_true); + _dynamiccrs_init(&sparseh, _state, ae_true); + _dynamiccrs_init(&a, _state, ae_true); + _dynamiccrs_init(&at, _state, ae_true); + _dynamiccrsqconstraints_init(&qc, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndl, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bndu, 0, DT_REAL, _state, ae_true); + ae_vector_init(&al, 0, DT_REAL, _state, ae_true); + ae_vector_init(&au, 0, DT_REAL, _state, ae_true); + _sparsematrix_init(&sparsetmp, _state, ae_true); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_xqci, (void**)&xqci, ae_false, _state, ae_true); + _presolvervcstats_init(&vcstats, _state, ae_true); + + ae_assert(m==0||sparseiscrs(rawsparsea, _state), "PRESOLVER: A is non-CRS sparse matrix", _state); + ae_assert(!hash||sparseiscrs(rawsparseh, _state), "PRESOLVER: quadratic term must be stored in the CRS format", _state); + mqc = xqcgetcount(rawxqc, _state); + mcc = xccgetcount(rawxcc, _state); + + /* + * Trace + */ + dotrace = (dotrace||(ae_is_trace_enabled("PRESOLVER.LP")&&!hash))||ae_is_trace_enabled("PRESOLVER.QP"); + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + if( hash ) + { + ae_trace("// QP PRESOLVER STARTED //\n"); + } + else + { + ae_trace("// LP PRESOLVER STARTED //\n"); + } + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("----- printing input problem metrics ---------------------------------------------------------------\n"); + ae_trace("N = %10d (variables)\n", + (int)(n)); + ae_trace("M = %10d (linear constraints)\n", + (int)(m)); + if( m!=0 ) + { + ae_trace("nz(A) = %10d (nonzeros in linear constraints)\n", + (int)(rawsparsea->ridx.ptr.p_int[rawsparsea->m])); + } + ae_trace("MQC = %10d (quadratic constraints)\n", + (int)(mqc)); + ae_trace("MCC = %10d (conic constraints)\n", + (int)(mcc)); + } + + /* + * Initial check for constraint feasibility + */ + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(rawbndl->ptr.p_double[i], _state)&&ae_isfinite(rawbndu->ptr.p_double[i], _state))&&ae_fp_greater(rawbndl->ptr.p_double[i],rawbndu->ptr.p_double[i]) ) + { + if( dotrace ) + { + ae_trace("> variable %0d is found to have infeasible box constraints, terminating\n", + (int)(i)); + } + presolved->problemstatus = -3; + ae_frame_leave(_state); + return; + } + } + for(i=0; i<=m-1; i++) + { + if( (ae_isfinite(rawal->ptr.p_double[i], _state)&&ae_isfinite(rawau->ptr.p_double[i], _state))&&ae_fp_greater(rawal->ptr.p_double[i],rawau->ptr.p_double[i]) ) + { + if( dotrace ) + { + ae_trace("> linear constraint %0d is found to have infeasible bounds, terminating\n", + (int)(i)); + } + presolved->problemstatus = -3; + ae_frame_leave(_state); + return; + } + } + for(i=0; i<=mqc-1; i++) + { + ae_obj_array_get(&rawxqc->constraints, i, &_xqci, _state); + if( (ae_isfinite(xqci->cl, _state)&&ae_isfinite(xqci->cu, _state))&&ae_fp_greater(xqci->cl,xqci->cu) ) + { + if( dotrace ) + { + ae_trace("> quadratic constraint %0d is found to have infeasible bounds, terminating\n", + (int)(i)); + } + presolved->problemstatus = -3; + ae_frame_leave(_state); + return; + } + } + + /* + * Starting output + */ + rcopyallocv(n, rawc, &presolved->rawc, _state); + rcopyallocv(n, rawbndl, &presolved->rawbndl, _state); + rcopyallocv(n, rawbndu, &presolved->rawbndu, _state); + if( m>0 ) + { + sparsecopytocrsbuf(rawsparsea, &presolved->rawa, _state); + } + xqccopy(rawxqc, &presolved->rawxqc, _state); + xcccopy(rawxcc, &presolved->rawxcc, _state); + presolved->hash = hash; + if( hash ) + { + lpqppresolve_copyexpandh(rawsparseh, isupper, &presolved->rawh, _state); + } + + /* + * Trace counters + */ + dbgemptycol = 0; + dbgemptyrow = 0; + dbgemptyqc = 0; + dbgnonbindingrows = 0; + dbgnonbindingqc = 0; + dbgfixed = 0; + dbgsingletonrow = 0; + dbgdoubletonrow = 0; + dbgslackvars = 0; + dbgimplicitslacks = 0; + dbgfreecolumnsingletons = 0; + + /* + * Initial state of the presolver + */ + eps = (double)(1000+n+m)*ae_machineepsilon+ae_pow(ae_machineepsilon, 0.75, _state); + presolved->eps = eps; + lpqppresolve_presolverstackinit(n, m, xqcgetcount(rawxqc, _state), xccgetcount(rawxcc, _state), &presolved->trfstack, _state); + presolved->problemstatus = 0; + rcopyallocv(n, rawc, &c, _state); + rcopyallocv(n, rawbndl, &bndl, _state); + rcopyallocv(n, rawbndu, &bndu, _state); + if( m>0 ) + { + sparsecopybuf(rawsparsea, &normsparsea, _state); + rcopyallocv(m, rawal, &al, _state); + rcopyallocv(m, rawau, &au, _state); + } + xqccopy(rawxqc, &normxqc, _state); + xcccopy(rawxcc, &normxcc, _state); + if( hash ) + { + sparsecopybuf(&presolved->rawh, &sparsetmp, _state); + } + lpqppresolve_scaleshiftobjectiveandconstraints(raws, xorigin, n, &c, &bndl, &bndu, &sparsetmp, hash, &normsparsea, &al, &au, m, &normxqc, &normxcc, &presolved->trfstack, _state); + if( hash ) + { + lpqppresolve_dyncrsinitfromsparsecrs(&sparsetmp, &sparseh, _state); + lpqppresolve_dyncrsdropoffdiagonalzeros(&sparseh, _state); + } + if( m>0 ) + { + sparsecopytransposecrsbuf(&normsparsea, &normsparseat, _state); + lpqppresolve_dyncrsinitfromsparsecrs(&normsparsea, &a, _state); + lpqppresolve_dyncrsinitfromsparsecrs(&normsparseat, &at, _state); + lpqppresolve_dyncrsdropzeros(&a, _state); + lpqppresolve_dyncrsdropzeros(&at, _state); + } + else + { + lpqppresolve_dyncrsinitempty(&a, 0, n, _state); + lpqppresolve_dyncrsinitempty(&at, n, 0, _state); + } + bsetallocv(n, ae_false, &presolved->lagrangefromresidual, _state); + lpqppresolve_presolvebuffersinit(&presolved->buf, n, m, _state); + + /* + * Initial state of QC and CC-related variables + */ + bsetallocv(n, ae_false, &vcstats.isdroppedcol, _state); + bsetallocv(m, ae_false, &vcstats.isdroppedlc, _state); + isetallocv(n, 0, &vcstats.nlcpervar, _state); + isetallocv(n, 0, &vcstats.cntdownwardaxial, _state); + isetallocv(n, 0, &vcstats.cntupwardaxial, _state); + isetallocv(n, 0, &vcstats.cntaxial, _state); + isetallocv(n, 0, &vcstats.cntradial, _state); + lpqppresolve_dynqcinitfromxqc(&normxqc, &qc, _state); + bsetallocv(mqc, ae_false, &vcstats.isdroppedqc, _state); + knisinitunsorted(n, mqc, 0, &vcstats.varbyqc, _state); + for(i=0; i<=mqc-1; i++) + { + ae_obj_array_get(&qc.constraints, i, &_qci, _state); + for(j=0; j<=qci->nvars-1; j++) + { + k = qci->varidx.ptr.p_int[j]; + vcstats.nlcpervar.ptr.p_int[k] = vcstats.nlcpervar.ptr.p_int[k]+1; + knisaddnewelement(&vcstats.varbyqc, k, i, _state); + } + } + bsetallocv(mcc, ae_false, &vcstats.isdroppedcc, _state); + knisinitunsorted(n, mcc, 0, &vcstats.varbycc, _state); + for(i=0; i<=mcc-1; i++) + { + ae_obj_array_get(&normxcc.constraints, i, &_cci, _state); + nv = cci->nvars; + for(j=0; j<=nv-1; j++) + { + k = cci->varidx.ptr.p_int[j]; + vcstats.nlcpervar.ptr.p_int[k] = vcstats.nlcpervar.ptr.p_int[k]+1; + knisaddnewelement(&vcstats.varbycc, k, i, _state); + } + donecc = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + for(j=0; j<=nv-2; j++) + { + vcstats.cntradial.ptr.p_int[cci->varidx.ptr.p_int[j]] = vcstats.cntradial.ptr.p_int[cci->varidx.ptr.p_int[j]]+1; + } + k = cci->varidx.ptr.p_int[nv-1]; + vcstats.cntaxial.ptr.p_int[k] = vcstats.cntaxial.ptr.p_int[k]+1; + if( ae_fp_greater(cci->diaga.ptr.p_double[nv-1],(double)(0)) ) + { + vcstats.cntupwardaxial.ptr.p_int[k] = vcstats.cntupwardaxial.ptr.p_int[k]+1; + } + if( ae_fp_less(cci->diaga.ptr.p_double[nv-1],(double)(0)) ) + { + vcstats.cntdownwardaxial.ptr.p_int[k] = vcstats.cntdownwardaxial.ptr.p_int[k]+1; + } + donecc = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + kpow = cci->kpow; + for(j=0; j<=nv-kpow-1; j++) + { + vcstats.cntradial.ptr.p_int[cci->varidx.ptr.p_int[j]] = vcstats.cntradial.ptr.p_int[cci->varidx.ptr.p_int[j]]+1; + } + for(j=nv-kpow; j<=nv-1; j++) + { + k = cci->varidx.ptr.p_int[j]; + vcstats.cntaxial.ptr.p_int[k] = vcstats.cntaxial.ptr.p_int[k]+1; + if( ae_fp_greater(cci->diaga.ptr.p_double[j],(double)(0)) ) + { + vcstats.cntupwardaxial.ptr.p_int[k] = vcstats.cntupwardaxial.ptr.p_int[k]+1; + } + if( ae_fp_less(cci->diaga.ptr.p_double[j],(double)(0)) ) + { + vcstats.cntdownwardaxial.ptr.p_int[k] = vcstats.cntdownwardaxial.ptr.p_int[k]+1; + } + } + donecc = ae_true; + } + ae_assert(donecc, "PRESOLVER: integrity check 485227 failed", _state); + } + + /* + * While something changes, keep iterating + */ + presolverounds = 0; + somethingchanged = ae_true; + while(somethingchanged) + { + somethingchanged = ae_false; + if( !lpqppresolve_dropemptycol(&c, &bndl, &bndu, &vcstats, &presolved->lagrangefromresidual, &sparseh, hash, n, &a, &at, &al, &au, m, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgemptycol, _state) ) + { + ae_frame_leave(_state); + return; + } + if( !lpqppresolve_dropclearlynonbindingrows(n, &vcstats, &a, &at, &al, &au, m, &qc, &normxcc, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgemptyrow, &dbgemptyqc, &dbgnonbindingrows, &dbgnonbindingqc, _state) ) + { + ae_frame_leave(_state); + return; + } + if( !lpqppresolve_singletonrowtobc(&bndl, &bndu, &vcstats, n, &a, &at, &al, &au, m, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgsingletonrow, _state) ) + { + ae_frame_leave(_state); + return; + } + if( !lpqppresolve_doubletonrow(&c, &bndl, &bndu, &vcstats, &sparseh, hash, n, &a, &at, &al, &au, m, &qc, &normxcc, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgdoubletonrow, _state) ) + { + ae_frame_leave(_state); + return; + } + if( !lpqppresolve_fixvariables(&c, &bndl, &bndu, &vcstats, &sparseh, hash, n, &a, &at, &al, &au, m, &qc, &normxcc, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgfixed, _state) ) + { + ae_frame_leave(_state); + return; + } + if( !lpqppresolve_singletoncols(&c, &bndl, &bndu, &vcstats, &sparseh, hash, n, &a, &at, &al, &au, m, eps, dotrace, &presolved->buf, &presolved->trfstack, &presolved->problemstatus, &somethingchanged, &dbgslackvars, &dbgimplicitslacks, &dbgfreecolumnsingletons, _state) ) + { + ae_frame_leave(_state); + return; + } + presolverounds = presolverounds+1; + } + + /* + * Integrity checks + * * A and AT have the same number of elements (we do not check actual elements, only their total count) + * * VCStats.NLCPerVar is zero after we subtract all non-dropped constraints + */ + if( m>0 ) + { + j0 = 0; + for(j=0; j<=m-1; j++) + { + j0 = j0+(a.rowend.ptr.p_int[j]-a.rowbegin.ptr.p_int[j]); + } + j1 = 0; + for(j=0; j<=n-1; j++) + { + j1 = j1+(at.rowend.ptr.p_int[j]-at.rowbegin.ptr.p_int[j]); + } + ae_assert(j0==j1, "PRESOLVER: integrity check 4347 failed", _state); + } + for(i=0; i<=n-1; i++) + { + ae_assert(vcstats.nlcpervar.ptr.p_int[i]==kniscountkth(&vcstats.varbyqc, i, _state)+kniscountkth(&vcstats.varbycc, i, _state), "PRESOLVER: integrity check 566152 failed", _state); + } + for(i=0; i<=mqc-1; i++) + { + if( vcstats.isdroppedqc.ptr.p_bool[i] ) + { + continue; + } + ae_obj_array_get(&qc.constraints, i, &_qci, _state); + for(j=0; j<=qci->nvars-1; j++) + { + if( vcstats.isdroppedcol.ptr.p_bool[qci->varidx.ptr.p_int[j]] ) + { + ae_assert(ae_false, "PRESOLVER: integrity check 2602 failed", _state); + } + vcstats.nlcpervar.ptr.p_int[qci->varidx.ptr.p_int[j]] = vcstats.nlcpervar.ptr.p_int[qci->varidx.ptr.p_int[j]]-1; + } + } + for(i=0; i<=mcc-1; i++) + { + if( vcstats.isdroppedcc.ptr.p_bool[i] ) + { + continue; + } + ae_obj_array_get(&normxcc.constraints, i, &_cci, _state); + for(j=0; j<=cci->nvars-1; j++) + { + if( vcstats.isdroppedcol.ptr.p_bool[cci->varidx.ptr.p_int[j]] ) + { + ae_assert(ae_false, "PRESOLVER: integrity check 529049 failed", _state); + } + vcstats.nlcpervar.ptr.p_int[cci->varidx.ptr.p_int[j]] = vcstats.nlcpervar.ptr.p_int[cci->varidx.ptr.p_int[j]]-1; + } + } + for(i=0; i<=n-1; i++) + { + if( vcstats.nlcpervar.ptr.p_int[i]!=0 ) + { + ae_assert(ae_false, "PRESOLVER: integrity check 3303 failed", _state); + } + } + + /* + * Output data that are permuted by XPerm[] + */ + presolved->oldn = n; + presolved->newn = 0; + isetallocv(n, -1, &presolved->packxperm, _state); + isetallocv(n, -1, &presolved->unpackxperm, _state); + for(i=0; i<=n-1; i++) + { + if( !vcstats.isdroppedcol.ptr.p_bool[i] ) + { + presolved->unpackxperm.ptr.p_int[presolved->newn] = i; + presolved->packxperm.ptr.p_int[i] = presolved->newn; + presolved->newn = presolved->newn+1; + } + } + rallocv(presolved->newn, &presolved->bndl, _state); + rallocv(presolved->newn, &presolved->bndu, _state); + rallocv(presolved->newn, &presolved->c, _state); + for(i=0; i<=presolved->newn-1; i++) + { + presolved->c.ptr.p_double[i] = c.ptr.p_double[presolved->unpackxperm.ptr.p_int[i]]; + presolved->bndl.ptr.p_double[i] = bndl.ptr.p_double[presolved->unpackxperm.ptr.p_int[i]]; + presolved->bndu.ptr.p_double[i] = bndu.ptr.p_double[presolved->unpackxperm.ptr.p_int[i]]; + } + if( hash ) + { + presolved->sparseh.n = presolved->newn; + presolved->sparseh.m = presolved->newn; + iallocv(presolved->newn+1, &presolved->sparseh.ridx, _state); + presolved->sparseh.ridx.ptr.p_int[0] = 0; + for(i=0; i<=presolved->newn-1; i++) + { + offs = presolved->sparseh.ridx.ptr.p_int[i]; + igrowv(offs+n, &presolved->sparseh.idx, _state); + rgrowv(offs+n, &presolved->sparseh.vals, _state); + k = presolved->unpackxperm.ptr.p_int[i]; + j0 = sparseh.rowbegin.ptr.p_int[k]; + j1 = sparseh.rowend.ptr.p_int[k]-1; + for(jj=j0; jj<=j1; jj++) + { + j = presolved->packxperm.ptr.p_int[sparseh.idx.ptr.p_int[jj]]; + if( j<0||j>i ) + { + continue; + } + presolved->sparseh.idx.ptr.p_int[offs] = j; + presolved->sparseh.vals.ptr.p_double[offs] = sparseh.vals.ptr.p_double[jj]; + offs = offs+1; + } + presolved->sparseh.ridx.ptr.p_int[i+1] = offs; + } + sparsecreatecrsinplace(&presolved->sparseh, _state); + } + + /* + * Output data that are permuted by YPerm[] + */ + presolved->oldm = m; + presolved->newm = 0; + isetallocv(m, -1, &presolved->packyperm, _state); + isetallocv(m, -1, &presolved->unpackyperm, _state); + for(i=0; i<=m-1; i++) + { + if( !vcstats.isdroppedlc.ptr.p_bool[i] ) + { + presolved->unpackyperm.ptr.p_int[presolved->newm] = i; + presolved->packyperm.ptr.p_int[i] = presolved->newm; + presolved->newm = presolved->newm+1; + } + } + rallocv(presolved->newm, &presolved->al, _state); + rallocv(presolved->newm, &presolved->au, _state); + for(i=0; i<=presolved->newm-1; i++) + { + presolved->al.ptr.p_double[i] = al.ptr.p_double[presolved->unpackyperm.ptr.p_int[i]]; + presolved->au.ptr.p_double[i] = au.ptr.p_double[presolved->unpackyperm.ptr.p_int[i]]; + } + + /* + * Output A which is permuted by both XPerm[] and YPerm[] + */ + presolved->sparsea.m = 0; + presolved->sparsea.n = presolved->newn; + iallocv(presolved->newm+1, &presolved->sparsea.ridx, _state); + presolved->sparsea.ridx.ptr.p_int[0] = 0; + for(i=0; i<=m-1; i++) + { + if( !vcstats.isdroppedlc.ptr.p_bool[i] ) + { + offs = presolved->sparsea.ridx.ptr.p_int[presolved->sparsea.m]; + igrowv(offs+n, &presolved->sparsea.idx, _state); + rgrowv(offs+n, &presolved->sparsea.vals, _state); + j0 = a.rowbegin.ptr.p_int[i]; + j1 = a.rowend.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = presolved->packxperm.ptr.p_int[a.idx.ptr.p_int[jj]]; + ae_assert(j>=0, "PRESOLVE: integrity check 54fc failed", _state); + presolved->sparsea.idx.ptr.p_int[offs] = j; + presolved->sparsea.vals.ptr.p_double[offs] = a.vals.ptr.p_double[jj]; + offs = offs+1; + } + presolved->sparsea.m = presolved->sparsea.m+1; + presolved->sparsea.ridx.ptr.p_int[presolved->sparsea.m] = offs; + } + } + ae_assert(presolved->sparsea.m==presolved->newm, "PRESOLVE: integrity check ee3a failed", _state); + sparsecreatecrsinplace(&presolved->sparsea, _state); + + /* + * Output data permuted by QCPerm[] and XPerm[] + */ + presolved->xqc.n = n; + ae_obj_array_clear(&presolved->xqc.constraints); + presolved->oldmqc = mqc; + presolved->newmqc = 0; + isetallocv(mqc, -1, &presolved->packqcperm, _state); + isetallocv(mqc, -1, &presolved->unpackqcperm, _state); + for(i=0; i<=mqc-1; i++) + { + if( !vcstats.isdroppedqc.ptr.p_bool[i] ) + { + presolved->unpackqcperm.ptr.p_int[presolved->newmqc] = i; + presolved->packqcperm.ptr.p_int[i] = presolved->newmqc; + presolved->newmqc = presolved->newmqc+1; + ae_obj_array_get(&qc.constraints, i, &_qci, _state); + xqci = (xquadraticconstraint*)ae_malloc(sizeof(xquadraticconstraint), _state); /* note: using xqci as a temporary prior to assigning its value to _xqci */ + memset(xqci, 0, sizeof(xquadraticconstraint)); + _xquadraticconstraint_init(xqci, _state, ae_false); + ae_smart_ptr_assign(&_xqci, xqci, ae_true, ae_true, (ae_int_t)sizeof(xquadraticconstraint), _xquadraticconstraint_init_copy, _xquadraticconstraint_destroy); + lpqppresolve_dynqcpermtoxqc(qci, &presolved->packxperm, &presolved->unpackxperm, xqci, _state); + ae_obj_array_append_transfer(&presolved->xqc.constraints, &_xqci, _state); + } + } + + /* + * Output data permuted by CCPerm and XPerm + */ + presolved->oldmcc = mcc; + presolved->newmcc = 0; + isetallocv(mcc, -1, &presolved->packccperm, _state); + isetallocv(mcc, -1, &presolved->unpackccperm, _state); + for(i=0; i<=mcc-1; i++) + { + if( !vcstats.isdroppedcc.ptr.p_bool[i] ) + { + presolved->unpackccperm.ptr.p_int[presolved->newmcc] = i; + presolved->packccperm.ptr.p_int[i] = presolved->newmcc; + presolved->newmcc = presolved->newmcc+1; + } + } + xcccopywithskipandpack(&normxcc, &vcstats.isdroppedcc, &presolved->packxperm, &presolved->xcc, _state); + ae_assert(presolved->newmcc==xccgetcount(&presolved->xcc, _state), "PRESOLVER: integrity check 682108 failed", _state); + + /* + * Prepare permutation for constraint Stats[] + */ + isetallocv(n+m, -1, &presolved->packstatperm, _state); + isetallocv(n+m, -1, &presolved->unpackstatperm, _state); + offs = 0; + for(i=0; i<=n-1; i++) + { + if( !vcstats.isdroppedcol.ptr.p_bool[i] ) + { + presolved->packstatperm.ptr.p_int[i] = offs; + offs = offs+1; + } + } + for(i=0; i<=m-1; i++) + { + if( !vcstats.isdroppedlc.ptr.p_bool[i] ) + { + presolved->packstatperm.ptr.p_int[n+i] = offs; + offs = offs+1; + } + } + ae_assert(offs==presolved->newn+presolved->newm, "PRESOLVE: integrity check 3632 failed", _state); + for(i=0; i<=n+m-1; i++) + { + if( presolved->packstatperm.ptr.p_int[i]>=0 ) + { + presolved->unpackstatperm.ptr.p_int[presolved->packstatperm.ptr.p_int[i]] = i; + } + } + + /* + * Trace output + */ + if( dotrace ) + { + ae_trace("done in %0d rounds\n\n", + (int)(presolverounds)); + ae_trace("----- printing information about reductions --------------------------------------------------------\n"); + ae_trace("fixed vars = %10d (fixed variables)\n", + (int)(dbgfixed)); + ae_trace("empty cols = %10d (empty constraint columns)\n", + (int)(dbgemptycol)); + ae_trace("empty rows = %10d (empty constraint rows)\n", + (int)(dbgemptyrow)); + ae_trace("empty QC = %10d (empty quadratic constraints)\n", + (int)(dbgemptyqc)); + ae_trace("nonbinding rows = %10d (irrelevant LC due to bounds)\n", + (int)(dbgnonbindingrows)); + ae_trace("nonbinding QC = %10d (irrelevant QC due to bounds)\n", + (int)(dbgnonbindingqc)); + ae_trace("singleton rows = %10d (singleton rows converted to box constraints)\n", + (int)(dbgsingletonrow)); + ae_trace("doubleton rows = %10d (doubleton equality constraints used to factor out variables)\n", + (int)(dbgdoubletonrow)); + ae_trace("slack variables = %10d (singleton cols with zero cost, recognized as explicit slacks)\n", + (int)(dbgslackvars)); + ae_trace("implicit slacks = %10d (singleton cols at equality rows, recognized as implicit slacks)\n", + (int)(dbgimplicitslacks)); + ae_trace("free col singletons = %10d (free singleton columns)\n", + (int)(dbgfreecolumnsingletons)); + ae_trace("----- printing output problem metrics --------------------------------------------------------------\n"); + ae_trace("N = %10d (variables)\n", + (int)(presolved->newn)); + ae_trace("M = %10d (constraints)\n", + (int)(presolved->newm)); + ae_trace("MQC = %10d (quadratic constraints)\n", + (int)(presolved->newmqc)); + if( m!=0 ) + { + ae_trace("nz(A) = %10d (nonzeros in A)\n", + (int)(presolved->sparsea.ridx.ptr.p_int[presolved->sparsea.m])); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Forward transformation which transforms a set of original variables (e.g. +an initial point) to the converted problem format. + +INPUT PARAMETERS: + Info - presolve info structure + X - array[NOld], original point + +OUTPUT PARAMETERS: + X - array[NNew], transformed point + +NOTE: this routine does not reallocate arrays if NOld<=NNew and/or KOld<=KNew. + + -- ALGLIB -- + Copyright 01.07.2020 by Bochkanov Sergey +*************************************************************************/ +void presolvefwd(presolveinfo* s, + /* Real */ ae_vector* xx, + ae_state *_state) +{ + ae_int_t tidx; + ae_int_t tt; + ae_int_t i; + ae_int_t k; + double v; + + + rcopyallocv(s->oldn, xx, &s->x1, _state); + for(tidx=0; tidx<=s->trfstack.ntrf-1; tidx++) + { + tt = s->trfstack.trftype.ptr.p_int[tidx]; + if( tt==lpqppresolve_pstobjectivescaling ) + { + continue; + } + if( tt==lpqppresolve_pstcolscaling ) + { + + /* + * Column scaling + */ + lpqppresolve_presolverselectstreamsource(&s->trfstack, tidx, _state); + lpqppresolve_presolverunstreamir(&s->trfstack, &k, &v, _state); + lpqppresolve_presolverasserteos(&s->trfstack, _state); + s->x1.ptr.p_double[k] = s->x1.ptr.p_double[k]*v; + continue; + } + if( tt==lpqppresolve_pstcolshifting ) + { + + /* + * Variable shifting + */ + lpqppresolve_presolverselectstreamsource(&s->trfstack, tidx, _state); + lpqppresolve_presolverunstreamir(&s->trfstack, &k, &v, _state); + lpqppresolve_presolverasserteos(&s->trfstack, _state); + s->x1.ptr.p_double[k] = s->x1.ptr.p_double[k]+v; + continue; + } + if( tt==lpqppresolve_pstrowscaling ) + { + continue; + } + if( tt==lpqppresolve_pstqcscaling ) + { + continue; + } + if( tt==lpqppresolve_pstdropemptycol ) + { + continue; + } + if( tt==lpqppresolve_pstdropemptyrow ) + { + continue; + } + if( tt==lpqppresolve_pstdropemptyqc ) + { + continue; + } + if( tt==lpqppresolve_pstsingletonrow ) + { + continue; + } + if( tt==lpqppresolve_pstfixedvar ) + { + continue; + } + if( tt==lpqppresolve_pstexplicitslack ) + { + continue; + } + if( tt==lpqppresolve_pstimplicitslack ) + { + continue; + } + if( tt==lpqppresolve_pstdoubletoneq ) + { + continue; + } + ae_assert(ae_false, "PresolverFwd: unexpected transform type", _state); + } + rallocv(s->newn, xx, _state); + for(i=0; i<=s->newn-1; i++) + { + xx->ptr.p_double[i] = s->x1.ptr.p_double[s->unpackxperm.ptr.p_int[i]]; + } +} + + +/************************************************************************* +Backward transformation which extracts original solution from that of the +converted problem. + +Below NNew/KNew correspond to transformed problem size (as returned by the +presolve routine) and NOld/KOld correspond to original problem size (as +specified by caller). We expect that caller knows these sizes, so this +routine does not report them. + +INPUT PARAMETERS: + Info - presolve info structure + X - array[NNew], transformed solution (primal variables) + Stats - array[NNew+MNew], transformed constraint status (negative - + at lower bound, positive - at upper bound, zero - + inactive). + LagBC - array[NNew], transformed Lagrange multipliers + LagLC - array[KNew], transformed Lagrange multipliers + LagQC - array[MQCNew], transformed Lagrange multipliers + +OUTPUT PARAMETERS: + X - array[NOld], original solution (primal variables) + Stats - array[NOld+MOld], original constraint status + LagBC - array[NOld], Lagrange multipliers + LagLC - array[KOld], Lagrange multipliers + LagQC - array[MQCOld], transformed Lagrange multipliers + +NOTE: this routine does not reallocate arrays if NOld<=NNew and/or KOld<=KNew. + + -- ALGLIB -- + Copyright 01.07.2020 by Bochkanov Sergey +*************************************************************************/ +void presolvebwd(presolveinfo* info, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* stats, + ae_bool needstats, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * Read state of the transformed problem into storage allocated for the original problem + */ + if( needstats ) + { + isetallocv(info->oldn+info->oldm, 0, &info->s1, _state); + for(i=0; i<=info->newn+info->newm-1; i++) + { + info->s1.ptr.p_int[info->unpackstatperm.ptr.p_int[i]] = stats->ptr.p_int[i]; + } + } + rsetallocv(info->oldn, 0.0, &info->x1, _state); + for(i=0; i<=info->newn-1; i++) + { + info->x1.ptr.p_double[info->unpackxperm.ptr.p_int[i]] = x->ptr.p_double[i]; + } + rsetallocv(info->oldn, 0.0, &info->bc1, _state); + for(i=0; i<=info->newn-1; i++) + { + info->bc1.ptr.p_double[info->unpackxperm.ptr.p_int[i]] = lagbc->ptr.p_double[i]; + } + rsetallocv(info->oldm, 0.0, &info->y1, _state); + for(i=0; i<=info->newm-1; i++) + { + info->y1.ptr.p_double[info->unpackyperm.ptr.p_int[i]] = laglc->ptr.p_double[i]; + } + rsetallocv(info->oldmqc, 0.0, &info->yqc, _state); + for(i=0; i<=info->newmqc-1; i++) + { + info->yqc.ptr.p_double[info->unpackqcperm.ptr.p_int[i]] = lagqc->ptr.p_double[i]; + } + + /* + * Apply reverse transformation + */ + lpqppresolve_presolverrestoresolution(&info->trfstack, &info->x1, &info->bc1, &info->y1, &info->yqc, &info->s1, needstats, info->eps, _state); + + /* + * Polish X according to box constraints and info from newly recovered Stats[] + * Recompute coefficients corresponding to variables fixed during presolve using residual costs. + */ + for(i=0; i<=info->oldn-1; i++) + { + if( ae_isfinite(info->rawbndl.ptr.p_double[i], _state) ) + { + info->x1.ptr.p_double[i] = ae_maxreal(info->x1.ptr.p_double[i], info->rawbndl.ptr.p_double[i], _state); + } + if( ae_isfinite(info->rawbndu.ptr.p_double[i], _state) ) + { + info->x1.ptr.p_double[i] = ae_minreal(info->x1.ptr.p_double[i], info->rawbndu.ptr.p_double[i], _state); + } + if( needstats ) + { + if( info->s1.ptr.p_int[i]<0 ) + { + info->x1.ptr.p_double[i] = info->rawbndl.ptr.p_double[i]; + } + if( info->s1.ptr.p_int[i]>0 ) + { + info->x1.ptr.p_double[i] = info->rawbndu.ptr.p_double[i]; + } + } + } + rcopyallocv(info->oldn, &info->rawc, &info->d, _state); + if( info->oldm>0 ) + { + sparsegemv(&info->rawa, 1.0, 1, &info->y1, 0, 1.0, &info->d, 0, _state); + } + for(i=0; i<=info->oldn-1; i++) + { + if( info->lagrangefromresidual.ptr.p_bool[i] ) + { + info->bc1.ptr.p_double[i] = -info->d.ptr.p_double[i]; + } + } + + /* + * Output + */ + rcopyallocv(info->oldn, &info->x1, x, _state); + rcopyallocv(info->oldmqc, &info->yqc, lagqc, _state); + rcopyallocv(info->oldm, &info->y1, laglc, _state); + if( needstats ) + { + icopyallocv(info->oldn+info->oldm, &info->s1, stats, _state); + } + rcopyallocv(info->oldn, &info->bc1, lagbc, _state); +} + + +/************************************************************************* +Returns true if both bounds are finite and the difference is less than Eps. + +Used to provide consistent way of checking for fixed vars across the unit. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_isfixed(double bndl, + double bndu, + double eps, + ae_state *_state) +{ + ae_bool result; + + + result = (ae_isfinite(bndl, _state)&&ae_isfinite(bndu, _state))&&ae_fp_greater_eq(bndl,bndu-eps); + return result; +} + + +/************************************************************************* +Initializes empty dynamic CRS matrix with either M or N equal to zero. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsinitempty(dynamiccrs* r, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + + + ae_assert(n*m==0, "DynCRSInitEmpty: M*N<>0", _state); + r->m = m; + r->n = n; + if( m>0 ) + { + isetallocv(m, 0, &r->rowbegin, _state); + isetallocv(m, 0, &r->rowend, _state); + } + r->maxallocated = 0; +} + + +/************************************************************************* +Copies dynamic CRS matrix + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrscopy(const dynamiccrs* src, + dynamiccrs* dst, + ae_state *_state) +{ + ae_int_t i; + ae_int_t m; + ae_int_t n; + ae_int_t rowsize; + + + m = src->m; + n = src->n; + dst->m = m; + dst->n = n; + dst->maxallocated = 0; + iallocv(m, &dst->rowbegin, _state); + iallocv(m, &dst->rowend, _state); + for(i=0; i<=m-1; i++) + { + rowsize = src->rowend.ptr.p_int[i]-src->rowbegin.ptr.p_int[i]; + dst->rowbegin.ptr.p_int[i] = dst->maxallocated; + dst->rowend.ptr.p_int[i] = dst->maxallocated+rowsize; + dst->maxallocated = dst->rowend.ptr.p_int[i]; + igrowv(dst->rowend.ptr.p_int[i], &dst->idx, _state); + rgrowv(dst->rowend.ptr.p_int[i], &dst->vals, _state); + icopyvx(rowsize, &src->idx, src->rowbegin.ptr.p_int[i], &dst->idx, dst->rowbegin.ptr.p_int[i], _state); + rcopyvx(rowsize, &src->vals, src->rowbegin.ptr.p_int[i], &dst->vals, dst->rowbegin.ptr.p_int[i], _state); + } +} + + +/************************************************************************* +Copies DynCRS matrix with deletion of row/column at position DeletePos +(the matrix must be square), with 0<=DeletePosm; + n = src->n; + ae_assert(m==n, "DynCRSCopyDeleteRowCol: non-square input matrix", _state); + ae_assert(0<=deletepos&&deleteposm = m-1; + dst->n = n-1; + dst->maxallocated = 0; + iallocv(m-1, &dst->rowbegin, _state); + iallocv(m-1, &dst->rowend, _state); + idst = 0; + for(isrc=0; isrc<=m-1; isrc++) + { + if( isrc!=deletepos ) + { + maxrowsize = src->rowend.ptr.p_int[isrc]-src->rowbegin.ptr.p_int[isrc]; + dst->rowbegin.ptr.p_int[idst] = dst->maxallocated; + igrowv(dst->maxallocated+maxrowsize, &dst->idx, _state); + rgrowv(dst->maxallocated+maxrowsize, &dst->vals, _state); + j0 = src->rowbegin.ptr.p_int[isrc]; + j1 = src->rowend.ptr.p_int[isrc]-1; + for(jj=j0; jj<=j1; jj++) + { + if( src->idx.ptr.p_int[jj]!=deletepos ) + { + j = src->idx.ptr.p_int[jj]; + if( j>deletepos ) + { + j = j-1; + } + dst->idx.ptr.p_int[dst->maxallocated] = j; + dst->vals.ptr.p_double[dst->maxallocated] = src->vals.ptr.p_double[jj]; + dst->maxallocated = dst->maxallocated+1; + } + } + dst->rowend.ptr.p_int[idst] = dst->maxallocated; + idst = idst+1; + } + } +} + + +/************************************************************************* +Copies DynCRS matrix with deletion of rows/columns at positions in DeleteSet +(the matrix must be square). Cols/rows are shifted to the left. The matrix +must be a square one. + +Correctly creates an empty matrix if all rows/cols are removed. + +Buf must be a preallocated array, with at least Src.N elements. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrscopydeleterowscols(const dynamiccrs* src, + const niset* deleteset, + dynamiccrs* dst, + /* Integer */ ae_vector* buf, + ae_state *_state) +{ + ae_int_t isrc; + ae_int_t idst; + ae_int_t m; + ae_int_t n; + ae_int_t maxrowsize; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t j; + + + m = src->m; + n = src->n; + + /* + * Integrity checks + */ + ae_assert(m==n, "DynCRSCopyDeleteRowsCols: non-square input matrix", _state); + ae_assert(buf->cnt>=n, "DynCRSCopyDeleteRowsCols: buf[] array is too short", _state); + ae_assert(0<=deleteset->nstored&&deleteset->nstored<=n, "DynCRSCopyDeleteRowsCols: incorrect DeleteSet size", _state); + for(j=0; j<=deleteset->nstored-1; j++) + { + ae_assert(deleteset->items.ptr.p_int[j]>=0&&deleteset->items.ptr.p_int[j]locationof.ptr.p_int[j]<0 ) + { + buf->ptr.p_int[j] = idst; + idst = idst+1; + } + else + { + buf->ptr.p_int[j] = -999999; + } + } + + /* + * Copy/convert matrix + */ + dst->m = m-deleteset->nstored; + dst->n = n-deleteset->nstored; + dst->maxallocated = 0; + iallocv(dst->m, &dst->rowbegin, _state); + iallocv(dst->m, &dst->rowend, _state); + idst = 0; + for(isrc=0; isrc<=m-1; isrc++) + { + if( deleteset->locationof.ptr.p_int[isrc]<0 ) + { + maxrowsize = src->rowend.ptr.p_int[isrc]-src->rowbegin.ptr.p_int[isrc]; + dst->rowbegin.ptr.p_int[idst] = dst->maxallocated; + igrowv(dst->maxallocated+maxrowsize, &dst->idx, _state); + rgrowv(dst->maxallocated+maxrowsize, &dst->vals, _state); + j0 = src->rowbegin.ptr.p_int[isrc]; + j1 = src->rowend.ptr.p_int[isrc]-1; + for(jj=j0; jj<=j1; jj++) + { + if( deleteset->locationof.ptr.p_int[src->idx.ptr.p_int[jj]]<0 ) + { + j = src->idx.ptr.p_int[jj]; + j = buf->ptr.p_int[j]; + dst->idx.ptr.p_int[dst->maxallocated] = j; + dst->vals.ptr.p_double[dst->maxallocated] = src->vals.ptr.p_double[jj]; + dst->maxallocated = dst->maxallocated+1; + } + } + dst->rowend.ptr.p_int[idst] = dst->maxallocated; + idst = idst+1; + } + } +} + + +/************************************************************************* +Copies DynCRS matrix with insertion of zero row/column at position InsertPos +(the matrix must be square), with 0<=InsertPos<=N/M. Cols/rows at the +position InsertPos and past it are shifted to the right. If N=M=1, then an +empty matrix is correctly created. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrscopyinsertrowcol(const dynamiccrs* src, + ae_int_t insertpos, + dynamiccrs* dst, + ae_state *_state) +{ + ae_int_t isrc; + ae_int_t idst; + ae_int_t m; + ae_int_t n; + ae_int_t maxrowsize; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t j; + + + m = src->m; + n = src->n; + ae_assert(m==n, "DynCRSCopyInsertRowCol: non-square input matrix", _state); + ae_assert(0<=insertpos&&insertpos<=n, "DynCRSCopyInsertRowCol: incorrect InsertPos", _state); + dst->m = m+1; + dst->n = n+1; + dst->maxallocated = 0; + iallocv(m+1, &dst->rowbegin, _state); + iallocv(m+1, &dst->rowend, _state); + idst = 0; + for(isrc=0; isrc<=m; isrc++) + { + if( isrc==insertpos ) + { + dst->rowbegin.ptr.p_int[idst] = dst->maxallocated; + igrowv(dst->maxallocated+1, &dst->idx, _state); + rgrowv(dst->maxallocated+1, &dst->vals, _state); + dst->idx.ptr.p_int[dst->maxallocated] = idst; + dst->vals.ptr.p_double[dst->maxallocated] = 0.0; + dst->maxallocated = dst->maxallocated+1; + dst->rowend.ptr.p_int[idst] = dst->maxallocated; + idst = idst+1; + } + if( isrcrowend.ptr.p_int[isrc]-src->rowbegin.ptr.p_int[isrc]; + dst->rowbegin.ptr.p_int[idst] = dst->maxallocated; + igrowv(dst->maxallocated+maxrowsize, &dst->idx, _state); + rgrowv(dst->maxallocated+maxrowsize, &dst->vals, _state); + j0 = src->rowbegin.ptr.p_int[isrc]; + j1 = src->rowend.ptr.p_int[isrc]-1; + for(jj=j0; jj<=j1; jj++) + { + j = src->idx.ptr.p_int[jj]; + if( j>=insertpos ) + { + j = j+1; + } + dst->idx.ptr.p_int[dst->maxallocated] = j; + dst->vals.ptr.p_double[dst->maxallocated] = src->vals.ptr.p_double[jj]; + dst->maxallocated = dst->maxallocated+1; + } + dst->rowend.ptr.p_int[idst] = dst->maxallocated; + idst = idst+1; + } + } +} + + +/************************************************************************* +Initialize dynamic CRS matrix using SparseMatrix structure + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsinitfromsparsecrs(const sparsematrix* s, + dynamiccrs* r, + ae_state *_state) +{ + ae_int_t m; + ae_int_t n; + + + m = s->m; + n = s->n; + ae_assert(s->matrixtype==1, "DynCRSInitFromSparseCRS: S is not CRS matrix", _state); + r->m = m; + r->n = n; + icopyallocv(s->ridx.ptr.p_int[m], &s->idx, &r->idx, _state); + rcopyallocv(s->ridx.ptr.p_int[m], &s->vals, &r->vals, _state); + iallocv(m, &r->rowbegin, _state); + iallocv(m, &r->rowend, _state); + icopyvx(m, &s->ridx, 0, &r->rowbegin, 0, _state); + icopyvx(m, &s->ridx, 1, &r->rowend, 0, _state); + r->maxallocated = r->rowend.ptr.p_int[m-1]; +} + + +/************************************************************************* +Drops numerical zeros from the matrix + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsdropzeros(dynamiccrs* a, ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t offs; + double v; + + + m = a->m; + for(i=0; i<=m-1; i++) + { + offs = a->rowbegin.ptr.p_int[i]; + for(jj=a->rowbegin.ptr.p_int[i]; jj<=a->rowend.ptr.p_int[i]-1; jj++) + { + j = a->idx.ptr.p_int[jj]; + v = a->vals.ptr.p_double[jj]; + if( v==(double)0 ) + { + continue; + } + a->idx.ptr.p_int[offs] = j; + a->vals.ptr.p_double[offs] = v; + offs = offs+1; + } + a->rowend.ptr.p_int[i] = offs; + } +} + + +/************************************************************************* +Drops offdiagonal numerical zeros from the matrix + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsdropoffdiagonalzeros(dynamiccrs* a, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t offs; + double v; + + + m = a->m; + for(i=0; i<=m-1; i++) + { + offs = a->rowbegin.ptr.p_int[i]; + for(jj=a->rowbegin.ptr.p_int[i]; jj<=a->rowend.ptr.p_int[i]-1; jj++) + { + j = a->idx.ptr.p_int[jj]; + v = a->vals.ptr.p_double[jj]; + if( j!=i&&v==(double)0 ) + { + continue; + } + a->idx.ptr.p_int[offs] = j; + a->vals.ptr.p_double[offs] = v; + offs = offs+1; + } + a->rowend.ptr.p_int[i] = offs; + } +} + + +/************************************************************************* +Removes rows + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsclearrow(dynamiccrs* a, + ae_int_t rowidx, + ae_state *_state) +{ + + + a->rowend.ptr.p_int[rowidx] = a->rowbegin.ptr.p_int[rowidx]; +} + + +/************************************************************************* +Removes element from the row + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsremovefromrow(dynamiccrs* a, + ae_int_t rowidx, + ae_int_t j, + ae_state *_state) +{ + ae_int_t ii; + ae_int_t offs; + + + offs = a->rowbegin.ptr.p_int[rowidx]; + for(ii=a->rowbegin.ptr.p_int[rowidx]; ii<=a->rowend.ptr.p_int[rowidx]-1; ii++) + { + if( a->idx.ptr.p_int[ii]!=j ) + { + a->idx.ptr.p_int[offs] = a->idx.ptr.p_int[ii]; + a->vals.ptr.p_double[offs] = a->vals.ptr.p_double[ii]; + offs = offs+1; + } + } + a->rowend.ptr.p_int[rowidx] = offs; +} + + +/************************************************************************* +Factors out element J from the row RowIdx by means of transformation + + X[J] = C0+C1*X[K]. + +Depending on context, can be used to factor out elements from individual +rows of a quadratic matrix H (in this case C0 can be zero because it does +not actually used), or to factor out elements from the linear constraints +matrix. + +The function returns the value of new element A[RowIdx,K]. A zero can be +returned, e.g. if cancellation or nearly-cancellation has occurred. + +When used to process linear constraints, it also returns a shift that should be applied to row bounds, +which is equal to C0*A[I,J]. Correctly handles the situation when factoring +an element out results in a cancellation: if CheckCancellation is True, +it removes canceled element from the row. + +When no element J is present in the row RowIdx, does nothing and returns zero. + + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsfactoroutfromrow(dynamiccrs* a, + ae_int_t rowidx, + ae_int_t j, + double c0, + double c1, + ae_int_t k, + ae_bool checkcancellation, + double* newval, + double* shift, + ae_state *_state) +{ + ae_int_t ii; + ae_int_t pos0; + ae_int_t pos1; + ae_int_t i; + ae_int_t i0; + ae_int_t i1; + double eps; + double mx; + double v; + + *newval = 0.0; + *shift = 0.0; + + eps = (double)10*ae_machineepsilon; + *newval = 0.0; + *shift = 0.0; + + /* + * Find elements J and K in the array. + * Return if there is no J. + * Compute result. + */ + pos0 = a->rowend.ptr.p_int[rowidx]; + pos1 = a->rowend.ptr.p_int[rowidx]; + for(ii=a->rowbegin.ptr.p_int[rowidx]; ii<=a->rowend.ptr.p_int[rowidx]-1; ii++) + { + if( a->idx.ptr.p_int[ii]==j ) + { + pos0 = ii; + } + if( a->idx.ptr.p_int[ii]==k ) + { + pos1 = ii; + } + } + if( pos0==a->rowend.ptr.p_int[rowidx] ) + { + return; + } + *shift = a->vals.ptr.p_double[pos0]*c0; + + /* + * Element J is present, what about K? + */ + if( pos1!=a->rowend.ptr.p_int[rowidx] ) + { + + /* + * If both elements are present, add J to K, remove J, check for cancellation + */ + mx = ae_maxreal(ae_fabs(a->vals.ptr.p_double[pos0], _state), ae_fabs(a->vals.ptr.p_double[pos1], _state), _state); + v = a->vals.ptr.p_double[pos1]+a->vals.ptr.p_double[pos0]*c1; + a->vals.ptr.p_double[pos1] = v; + *newval = v; + lpqppresolve_dyncrsremovefromrow(a, rowidx, j, _state); + if( checkcancellation&&ae_fp_less_eq(ae_fabs(v, _state),eps*mx) ) + { + lpqppresolve_dyncrsremovefromrow(a, rowidx, k, _state); + *newval = 0.0; + } + } + else + { + + /* + * If only J is present, then perform inplace modification then run a bubble sort + */ + v = a->vals.ptr.p_double[pos0]*c1; + a->idx.ptr.p_int[pos0] = k; + a->vals.ptr.p_double[pos0] = v; + *newval = v; + if( k>j ) + { + i0 = pos0; + i1 = a->rowend.ptr.p_int[rowidx]-1; + while(i0idx.ptr.p_int[i0+1]; + if( i>k ) + { + break; + } + a->idx.ptr.p_int[i0] = i; + a->vals.ptr.p_double[i0] = a->vals.ptr.p_double[i0+1]; + a->idx.ptr.p_int[i0+1] = k; + a->vals.ptr.p_double[i0+1] = v; + i0 = i0+1; + } + } + else + { + i0 = pos0; + i1 = a->rowbegin.ptr.p_int[rowidx]; + while(i0>i1) + { + i = a->idx.ptr.p_int[i0-1]; + if( iidx.ptr.p_int[i0] = i; + a->vals.ptr.p_double[i0] = a->vals.ptr.p_double[i0-1]; + a->idx.ptr.p_int[i0-1] = k; + a->vals.ptr.p_double[i0-1] = v; + i0 = i0-1; + } + } + } +} + + +/************************************************************************* +Adds Row0 times C to Row1. If RetainDiagonal is True, never removes diagonal +elements from Row1 even if cancellation is present + + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsaddrowto(dynamiccrs* a, + ae_int_t row0, + double c, + ae_int_t row1, + ae_bool retaindiagonal, + ae_bool checkcancellation, + ae_state *_state) +{ + ae_int_t begin0; + ae_int_t begin1; + ae_int_t end0; + ae_int_t end1; + ae_int_t i0; + ae_int_t i1; + double v0; + double v1; + double mx; + ae_int_t beginr; + ae_int_t endr; + double eps; + + + eps = (double)10*ae_machineepsilon; + + /* + * Analyze inputs, allocate place for output + */ + if( ae_fp_eq(c,0.0) ) + { + return; + } + begin0 = a->rowbegin.ptr.p_int[row0]; + begin1 = a->rowbegin.ptr.p_int[row1]; + end0 = a->rowend.ptr.p_int[row0]; + end1 = a->rowend.ptr.p_int[row1]; + if( begin0==end0 ) + { + return; + } + igrowv(a->maxallocated+(end0-begin0)+(end1-begin1), &a->idx, _state); + rgrowv(a->maxallocated+(end0-begin0)+(end1-begin1), &a->vals, _state); + beginr = a->maxallocated; + endr = beginr; + while(begin0idx.ptr.p_int[begin0]; + i1 = a->idx.ptr.p_int[begin1]; + if( i0idx.ptr.p_int[endr] = i0; + a->vals.ptr.p_double[endr] = c*a->vals.ptr.p_double[begin0]; + endr = endr+1; + begin0 = begin0+1; + continue; + } + if( i1idx.ptr.p_int[endr] = i1; + a->vals.ptr.p_double[endr] = a->vals.ptr.p_double[begin1]; + endr = endr+1; + begin1 = begin1+1; + continue; + } + v0 = a->vals.ptr.p_double[begin0]; + v1 = a->vals.ptr.p_double[begin1]; + if( checkcancellation ) + { + mx = ae_maxreal(ae_fabs(v0, _state), ae_fabs(v1, _state), _state); + if( (!retaindiagonal||i1!=row1)&&(ae_fp_eq(mx,(double)(0))||ae_fabs(c*v0+v1, _state)<=eps*mx) ) + { + + /* + * Do not output zero elements resulting from cancellation. + */ + begin0 = begin0+1; + begin1 = begin1+1; + continue; + } + } + a->idx.ptr.p_int[endr] = i1; + a->vals.ptr.p_double[endr] = c*v0+v1; + endr = endr+1; + begin0 = begin0+1; + begin1 = begin1+1; + } + while(begin0idx.ptr.p_int[endr] = a->idx.ptr.p_int[begin0]; + a->vals.ptr.p_double[endr] = c*a->vals.ptr.p_double[begin0]; + endr = endr+1; + begin0 = begin0+1; + } + while(begin1idx.ptr.p_int[endr] = a->idx.ptr.p_int[begin1]; + a->vals.ptr.p_double[endr] = a->vals.ptr.p_double[begin1]; + endr = endr+1; + begin1 = begin1+1; + } + a->maxallocated = endr; + a->rowbegin.ptr.p_int[row1] = beginr; + a->rowend.ptr.p_int[row1] = endr; +} + + +/************************************************************************* +Inserts sparse vector into the row, rewriting existing elements by new values. +If a new value is zero, the element (if exists) is removed from the target +row. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsinsertwithrewrite(dynamiccrs* a, + ae_int_t tgtrow, + /* Integer */ const ae_vector* idx, + /* Real */ const ae_vector* vals, + ae_int_t cnt, + ae_state *_state) +{ + ae_int_t begins; + ae_int_t ends; + ae_int_t begini; + ae_int_t i0; + ae_int_t i1; + ae_int_t beginr; + ae_int_t endr; + + + + /* + * Analyze inputs, allocate place for output + */ + if( cnt==0 ) + { + return; + } + begins = a->rowbegin.ptr.p_int[tgtrow]; + ends = a->rowend.ptr.p_int[tgtrow]; + igrowv(a->maxallocated+(ends-begins)+cnt, &a->idx, _state); + rgrowv(a->maxallocated+(ends-begins)+cnt, &a->vals, _state); + beginr = a->maxallocated; + endr = beginr; + begini = 0; + while(beginsidx.ptr.p_int[begins]; + i1 = idx->ptr.p_int[begini]; + if( i0idx.ptr.p_int[endr] = i0; + a->vals.ptr.p_double[endr] = a->vals.ptr.p_double[begins]; + endr = endr+1; + begins = begins+1; + continue; + } + if( i1ptr.p_double[begini]!=0.0 ) + { + a->idx.ptr.p_int[endr] = i1; + a->vals.ptr.p_double[endr] = vals->ptr.p_double[begini]; + endr = endr+1; + } + begini = begini+1; + continue; + } + if( vals->ptr.p_double[begini]!=0.0 ) + { + a->idx.ptr.p_int[endr] = i1; + a->vals.ptr.p_double[endr] = vals->ptr.p_double[begini]; + endr = endr+1; + } + begins = begins+1; + begini = begini+1; + } + while(beginsidx.ptr.p_int[endr] = a->idx.ptr.p_int[begins]; + a->vals.ptr.p_double[endr] = a->vals.ptr.p_double[begins]; + endr = endr+1; + begins = begins+1; + } + while(beginiptr.p_double[begini]!=0.0 ) + { + a->idx.ptr.p_int[endr] = idx->ptr.p_int[begini]; + a->vals.ptr.p_double[endr] = vals->ptr.p_double[begini]; + endr = endr+1; + } + begini = begini+1; + } + a->maxallocated = endr; + a->rowbegin.ptr.p_int[tgtrow] = beginr; + a->rowend.ptr.p_int[tgtrow] = endr; +} + + +/************************************************************************* +Removes elements with indexes in the set from the row + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrsremovesetfromrow(dynamiccrs* a, + ae_int_t rowidx, + const niset* s, + ae_state *_state) +{ + ae_int_t ii; + ae_int_t offs; + + + offs = a->rowbegin.ptr.p_int[rowidx]; + for(ii=a->rowbegin.ptr.p_int[rowidx]; ii<=a->rowend.ptr.p_int[rowidx]-1; ii++) + { + if( s->locationof.ptr.p_int[a->idx.ptr.p_int[ii]]<0 ) + { + a->idx.ptr.p_int[offs] = a->idx.ptr.p_int[ii]; + a->vals.ptr.p_double[offs] = a->vals.ptr.p_double[ii]; + offs = offs+1; + } + } + a->rowend.ptr.p_int[rowidx] = offs; +} + + +/************************************************************************* +Get element that it known to exist in the matrix. If it does not, the +function fails with an exception. O(log(row_size)) running time. + + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static double lpqppresolve_dyncrsgetexistingelement(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + ae_state *_state) +{ + ae_int_t k; + double result; + + + k = ibinarysearchlft(&a->idx, a->rowbegin.ptr.p_int[i], a->rowend.ptr.p_int[i], j, _state); + ae_assert(krowend.ptr.p_int[i]&&a->idx.ptr.p_int[k]==j, "DynCRSGetExistingElement: element not found", _state); + result = a->vals.ptr.p_double[k]; + return result; +} + + +/************************************************************************* +Get element, return zero for non-existent element. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static double lpqppresolve_dyncrsgetelementifexists(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + ae_state *_state) +{ + ae_int_t k; + double result; + + + k = ibinarysearchlft(&a->idx, a->rowbegin.ptr.p_int[i], a->rowend.ptr.p_int[i], j, _state); + result = (double)(0); + if( krowend.ptr.p_int[i]&&a->idx.ptr.p_int[k]==j ) + { + result = a->vals.ptr.p_double[k]; + } + return result; +} + + +/************************************************************************* +Sets an element that it known to exist in the matrix. If it does not, the +function fails with an exception. O(log(row_size)) running time. + + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dyncrssetexistingelement(dynamiccrs* a, + ae_int_t i, + ae_int_t j, + double v, + ae_state *_state) +{ + ae_int_t k; + + + k = ibinarysearchlft(&a->idx, a->rowbegin.ptr.p_int[i], a->rowend.ptr.p_int[i], j, _state); + ae_assert(krowend.ptr.p_int[i]&&a->idx.ptr.p_int[k]==j, "DynCRSSetExistingElement: element not found", _state); + a->vals.ptr.p_double[k] = v; +} + + +/************************************************************************* +Initialize dynamic-CRS-based quadratic constraints from the standard ones + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dynqcinitfromxqc(xquadraticconstraints* src, + dynamiccrsqconstraints* dst, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t cnt; + ae_int_t nv; + xquadraticconstraint *qcsrc; + ae_smart_ptr _qcsrc; + dynamiccrsqconstraint *qcdst; + ae_smart_ptr _qcdst; + sparsematrix fullq; + + ae_frame_make(_state, &_frame_block); + memset(&_qcsrc, 0, sizeof(_qcsrc)); + memset(&_qcdst, 0, sizeof(_qcdst)); + memset(&fullq, 0, sizeof(fullq)); + ae_smart_ptr_init(&_qcsrc, (void**)&qcsrc, ae_false, _state, ae_true); + ae_smart_ptr_init(&_qcdst, (void**)&qcdst, ae_false, _state, ae_true); + _sparsematrix_init(&fullq, _state, ae_true); + + cnt = xqcgetcount(src, _state); + ae_obj_array_clear(&dst->constraints); + for(i=0; i<=cnt-1; i++) + { + ae_obj_array_get(&src->constraints, i, &_qcsrc, _state); + qcdst = (dynamiccrsqconstraint*)ae_malloc(sizeof(dynamiccrsqconstraint), _state); /* note: using qcdst as a temporary prior to assigning its value to _qcdst */ + memset(qcdst, 0, sizeof(dynamiccrsqconstraint)); + _dynamiccrsqconstraint_init(qcdst, _state, ae_false); + ae_smart_ptr_assign(&_qcdst, qcdst, ae_true, ae_true, (ae_int_t)sizeof(dynamiccrsqconstraint), _dynamiccrsqconstraint_init_copy, _dynamiccrsqconstraint_destroy); + nv = qcsrc->nvars; + qcdst->nvars = nv; + qcdst->cl = qcsrc->cl; + qcdst->cu = qcsrc->cu; + qcdst->applyorigin = qcsrc->applyorigin; + if( nv>0 ) + { + icopyallocv(nv, &qcsrc->varidx, &qcdst->varidx, _state); + rcopyallocv(nv, &qcsrc->b, &qcdst->b, _state); + lpqppresolve_copyexpandh(&qcsrc->lowerq, ae_false, &fullq, _state); + lpqppresolve_dyncrsinitfromsparsecrs(&fullq, &qcdst->fullq, _state); + } + ae_obj_array_append_transfer(&dst->constraints, &_qcdst, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Copy structure + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dynqccopy(const dynamiccrsqconstraint* src, + dynamiccrsqconstraint* dst, + ae_state *_state) +{ + + + dst->nvars = src->nvars; + icopyallocv(src->nvars, &src->varidx, &dst->varidx, _state); + rcopyallocv(src->nvars, &src->b, &dst->b, _state); + lpqppresolve_dyncrscopy(&src->fullq, &dst->fullq, _state); + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; +} + + +/************************************************************************* +Copies quadratic constraint with insertion of variable VIdx into position +InsertPos, with 0<=InsertPos<=NVars. Variables at position InsertPos and +past it are shifted to the right. + +The function checks that Src.VarIdx[InsertPos-1]=0&&insertpos<=src->nvars, "dynqcCopyInsertRowCol: incorrect InsertPos", _state); + ae_assert(insertpos==0||src->varidx.ptr.p_int[insertpos-1]nvars||src->varidx.ptr.p_int[insertpos]>vidx, "dynqcCopyInsertRowCol: VIdx is out of order (right)", _state); + dst->nvars = src->nvars+1; + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; + iallocv(dst->nvars, &dst->varidx, _state); + rallocv(dst->nvars, &dst->b, _state); + offs = 0; + for(i=0; i<=src->nvars; i++) + { + if( i==insertpos ) + { + dst->varidx.ptr.p_int[offs] = vidx; + dst->b.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + if( invars ) + { + dst->varidx.ptr.p_int[offs] = src->varidx.ptr.p_int[i]; + dst->b.ptr.p_double[offs] = src->b.ptr.p_double[i]; + offs = offs+1; + } + } + ae_assert(offs==dst->nvars, "PRESOLVER: integrity check 4228 failed", _state); + lpqppresolve_dyncrscopyinsertrowcol(&src->fullq, insertpos, &dst->fullq, _state); +} + + +/************************************************************************* +Copies quadratic constraint with deletion of variable at position DeletePos, +with 0<=DeletePos=0&&deleteposnvars, "dynqcCopyDeleteRowCol: incorrect DeletePos", _state); + dst->nvars = src->nvars-1; + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; + if( dst->nvars==0 ) + { + dst->fullq.n = 0; + dst->fullq.m = 0; + return; + } + iallocv(dst->nvars, &dst->varidx, _state); + rallocv(dst->nvars, &dst->b, _state); + offs = 0; + for(i=0; i<=src->nvars-1; i++) + { + if( i!=deletepos ) + { + dst->varidx.ptr.p_int[offs] = src->varidx.ptr.p_int[i]; + dst->b.ptr.p_double[offs] = src->b.ptr.p_double[i]; + offs = offs+1; + } + } + lpqppresolve_dyncrscopydeleterowcol(&src->fullq, deletepos, &dst->fullq, _state); +} + + +/************************************************************************* +Copies quadratic constraint with deletion of variables DeleteSet and a +corresponding shifts to the left in variables indexes. + +If NVars=|DeleteSet|, then an empty quadratic constraint is correctly created. + +Buf must be a preallocated array, with at least Src.NVars elements. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dynqccopydeleterowscols(const dynamiccrsqconstraint* src, + const niset* deleteset, + dynamiccrsqconstraint* dst, + /* Integer */ ae_vector* buf, + ae_state *_state) +{ + ae_int_t i; + ae_int_t offs; + + + ae_assert(buf->cnt>=src->nvars, "dynqcCopyDeleteRowsCols: buf is too short", _state); + ae_assert(deleteset->nstored>=0&&deleteset->nstored<=src->nvars, "dynqcCopyDeleteRowsCols: incorrect DeletePos", _state); + for(i=0; i<=deleteset->nstored-1; i++) + { + ae_assert(deleteset->items.ptr.p_int[i]>=0&&deleteset->items.ptr.p_int[i]nvars, "dynqcCopyDeleteRowsCols: items in DeleteSet are outside of [0,NVars) range", _state); + } + dst->nvars = src->nvars-deleteset->nstored; + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; + if( dst->nvars==0 ) + { + dst->fullq.n = 0; + dst->fullq.m = 0; + return; + } + iallocv(dst->nvars, &dst->varidx, _state); + rallocv(dst->nvars, &dst->b, _state); + offs = 0; + for(i=0; i<=src->nvars-1; i++) + { + if( deleteset->locationof.ptr.p_int[i]<0 ) + { + dst->varidx.ptr.p_int[offs] = src->varidx.ptr.p_int[i]; + dst->b.ptr.p_double[offs] = src->b.ptr.p_double[i]; + offs = offs+1; + } + } + lpqppresolve_dyncrscopydeleterowscols(&src->fullq, deleteset, &dst->fullq, buf, _state); +} + + +/************************************************************************* +Factors out variable K0 from a quadratic form c'x + 0.5x'Hx by making a +substitution X[k0]:=alpha0 + alpha1*X[k1] and correspondingly rewriting +c and H. + +Returns constant term that is produced as a result of such a transformation. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static double lpqppresolve_factoroutfromquadratic(dynamiccrs* h, + /* Real */ ae_vector* c, + ae_int_t k0, + double alpha0, + double alpha1, + ae_int_t k1, + ae_state *_state) +{ + double h00; + double h11; + double h01; + double v; + double v0; + double v1; + ae_int_t ii; + ae_int_t j; + double result; + + + result = (double)(0); + + /* + * Modify linear term with an update to C[K1] from C[K0] + */ + c->ptr.p_double[k1] = c->ptr.p_double[k1]+c->ptr.p_double[k0]*alpha1; + result = result+c->ptr.p_double[k0]*alpha0; + c->ptr.p_double[k0] = (double)(0); + + /* + * Handle updates coming from the quadratic term + * + * Analyze how 2x2 quadratic [h00 h01 ; h10 h11] changes when we + * substitute x0 := alpha0 + alpha1*x1. + * + * We have + * + * h00*(alpha0+alpha1*x1)^2 + 2*h01*(alpha0+alpha1*x1)*x1 + h11*x1^2 = + * h00*alpha0^2 + 2*h00*alpha0*alpha1*x1 + h00*alpha1^2*x1^2 + 2*h01*alpha0*x1+2*h01*alpha1*x1^2 + h11*x1^2 = + * h00*alpha0^2 + 2*(h00*alpha0*alpha1+h01*alpha0)*x1 + (h00*alpha1^2+2*h01*alpha1+h11)*x1^2 + */ + h00 = lpqppresolve_dyncrsgetexistingelement(h, k0, k0, _state); + h11 = lpqppresolve_dyncrsgetexistingelement(h, k1, k1, _state); + h01 = lpqppresolve_dyncrsgetelementifexists(h, k0, k1, _state); + + /* + * Handle updates coming from modification of elements of H that are outside of the + * [k0,k1]x[k0,k1] diagonal block. The constant term in X[K0]:=Alpha0+Alpha1*X[K1] + * updates the linear term C[], the linear term Alpha1 updates the matrix H. + * + * The matrix H is updates applied to its column K1, then to its row K1. The row update + * modifies the [k0,k1]x[k0,k1] diagonal block because there is no easy way to do it + * without touching elements that we want to process later. We handle it by saving + * H00, H01, H11 prior to this block and by discarding and rewriting diagonal completely + * after calling DynCRSAddRowTo(). + */ + for(ii=h->rowbegin.ptr.p_int[k0]; ii<=h->rowend.ptr.p_int[k0]-1; ii++) + { + j = h->idx.ptr.p_int[ii]; + if( j!=k0&&j!=k1 ) + { + + /* + * Update C[] and column K1 of H. + */ + v = h->vals.ptr.p_double[ii]; + c->ptr.p_double[j] = c->ptr.p_double[j]+v*alpha0; + lpqppresolve_dyncrsfactoroutfromrow(h, j, k0, 0.0, alpha1, k1, ae_false, &v0, &v1, _state); + } + } + lpqppresolve_dyncrsaddrowto(h, k0, alpha1, k1, ae_true, ae_false, _state); + lpqppresolve_dyncrsclearrow(h, k0, _state); + lpqppresolve_dyncrsremovefromrow(h, k1, k0, _state); + + /* + * Handle updates coming from substituting X[K0]:=Alpha0+Alpha1*X[K1] to the + * [k0,k1]x[k0,k1] diagonal block. + */ + result = result+0.5*h00*alpha0*alpha0; + c->ptr.p_double[k1] = c->ptr.p_double[k1]+(h00*alpha0*alpha1+h01*alpha0); + lpqppresolve_dyncrssetexistingelement(h, k1, k1, h00*alpha1*alpha1+(double)2*h01*alpha1+h11, _state); + return result; +} + + +/************************************************************************* +Fixed single variable at the quadratic form c'x + 0.5x'Hx and correspondingly +rewrites c and H, clearing entries (but not removing them). + +Returns constant term that is produced as a result of such a transformation. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static double lpqppresolve_fixquadraticvariable(dynamiccrs* h, + /* Real */ ae_vector* c, + ae_int_t fixidx, + double fixval, + ae_state *_state) +{ + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t j; + ae_int_t n; + double result; + + + ae_assert(h->n==h->m, "PRESOLVER: integrity check 5812 failed", _state); + ae_assert(fixidx>=0&&fixidxn, "PRESOLVER: integrity check 5813 failed", _state); + result = (double)(0); + n = h->n; + if( n==0 ) + { + return result; + } + + /* + * Modify linear term + */ + result = result+c->ptr.p_double[fixidx]*fixval; + c->ptr.p_double[fixidx] = 0.0; + + /* + * Modify quadratic term: scan FixIdx-th row, for each off-diagonal element found + * clear (set to zero) corresponding element from FixIdx-th column + */ + j0 = h->rowbegin.ptr.p_int[fixidx]; + j1 = h->rowend.ptr.p_int[fixidx]-1; + for(jj=j0; jj<=j1; jj++) + { + j = h->idx.ptr.p_int[jj]; + if( j!=fixidx ) + { + + /* + * Offdiagonal element + */ + c->ptr.p_double[j] = c->ptr.p_double[j]+h->vals.ptr.p_double[jj]*fixval; + h->vals.ptr.p_double[jj] = 0.0; + h->vals.ptr.p_double[ibinarysearchexisting(&h->idx, h->rowbegin.ptr.p_int[j], h->rowend.ptr.p_int[j], fixidx, _state)] = 0.0; + } + else + { + + /* + * Diagonal element + */ + result = result+0.5*h->vals.ptr.p_double[jj]*fixval*fixval; + h->vals.ptr.p_double[jj] = 0.0; + } + } + return result; +} + + +/************************************************************************* +convert single quadratic constraint between formats + + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_dynqcpermtoxqc(dynamiccrsqconstraint* src, + /* Integer */ const ae_vector* packxperm, + /* Integer */ const ae_vector* unpackxperm, + xquadraticconstraint* dst, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t offs; + ae_int_t nv; + ae_int_t jprev; + + + nv = src->nvars; + dst->nvars = nv; + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; + if( nv>0 ) + { + iallocv(nv, &dst->varidx, _state); + for(i=0; i<=nv-1; i++) + { + dst->varidx.ptr.p_int[i] = packxperm->ptr.p_int[src->varidx.ptr.p_int[i]]; + } + for(i=0; i<=nv-2; i++) + { + ae_assert(dst->varidx.ptr.p_int[i]varidx.ptr.p_int[i+1], "PRESOLVER: integrity check 1658 failed", _state); + } + rcopyallocv(nv, &src->b, &dst->b, _state); + dst->lowerq.matrixtype = 1; + dst->lowerq.m = nv; + dst->lowerq.n = nv; + iallocv(nv, &dst->lowerq.didx, _state); + iallocv(nv, &dst->lowerq.uidx, _state); + iallocv(nv+1, &dst->lowerq.ridx, _state); + dst->lowerq.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nv-1; i++) + { + offs = dst->lowerq.ridx.ptr.p_int[i]; + igrowv(offs+nv, &dst->lowerq.idx, _state); + rgrowv(offs+nv, &dst->lowerq.vals, _state); + jprev = -1; + j0 = src->fullq.rowbegin.ptr.p_int[i]; + j1 = src->fullq.rowend.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = src->fullq.idx.ptr.p_int[jj]; + if( j<=jprev ) + { + ae_assert(ae_false, "PRESOLVER: integrity check 381649 failed", _state); + } + jprev = j; + if( j>i ) + { + continue; + } + dst->lowerq.idx.ptr.p_int[offs] = j; + dst->lowerq.vals.ptr.p_double[offs] = src->fullq.vals.ptr.p_double[jj]; + offs = offs+1; + } + ae_assert(offs>dst->lowerq.ridx.ptr.p_int[i]&&dst->lowerq.idx.ptr.p_int[offs-1]==i, "PRESOLVER: integrity check 389651 failed", _state); + dst->lowerq.didx.ptr.p_int[i] = offs-1; + dst->lowerq.uidx.ptr.p_int[i] = offs; + dst->lowerq.ridx.ptr.p_int[i+1] = offs; + } + dst->lowerq.ninitialized = dst->lowerq.ridx.ptr.p_int[nv]; + } +} + + +/************************************************************************* +Initialize presolver stack + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstackinit(ae_int_t n, + ae_int_t m, + ae_int_t mqc, + ae_int_t mcc, + presolverstack* s, + ae_state *_state) +{ + + + s->n = n; + s->m = m; + s->mqc = mqc; + s->mcc = mcc; + s->ntrf = 0; + isetallocv(1, 0, &s->idataridx, _state); + isetallocv(1, 0, &s->rdataridx, _state); +} + + +/************************************************************************* +Streams boolean value to the presolver stack data storage (the data +are appended to the last transform on top of the stack). + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamb(presolverstack* s, + ae_bool b, + ae_state *_state) +{ + ae_int_t ilast; + + + ilast = s->idataridx.ptr.p_int[s->ntrf]; + igrowv(ilast+1, &s->idata, _state); + s->idata.ptr.p_int[ilast] = icase2(b, 1, 0, _state); + s->idataridx.ptr.p_int[s->ntrf] = ilast+1; +} + + +/************************************************************************* +Streams integer value to the presolver stack data storage (the data +are appended to the last transform on top of the stack). + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreami(presolverstack* s, + ae_int_t i, + ae_state *_state) +{ + ae_int_t ilast; + + + ilast = s->idataridx.ptr.p_int[s->ntrf]; + igrowv(ilast+1, &s->idata, _state); + s->idata.ptr.p_int[ilast] = i; + s->idataridx.ptr.p_int[s->ntrf] = ilast+1; +} + + +/************************************************************************* +Streams real value to the presolver stack data storage (the data +are appended to the last transform on top of the stack). + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamr(presolverstack* s, + double v, + ae_state *_state) +{ + ae_int_t rlast; + + + rlast = s->rdataridx.ptr.p_int[s->ntrf]; + rgrowv(rlast+1, &s->rdata, _state); + s->rdata.ptr.p_double[rlast] = v; + s->rdataridx.ptr.p_int[s->ntrf] = rlast+1; +} + + +/************************************************************************* +Streams a integer/real pair to the presolver stack data storage (the data +are appended to the last transform on top of the stack). + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamir(presolverstack* s, + ae_int_t i, + double v, + ae_state *_state) +{ + ae_int_t ilast; + ae_int_t rlast; + + + ilast = s->idataridx.ptr.p_int[s->ntrf]; + rlast = s->rdataridx.ptr.p_int[s->ntrf]; + igrowv(ilast+1, &s->idata, _state); + rgrowv(rlast+1, &s->rdata, _state); + s->idata.ptr.p_int[ilast] = i; + s->rdata.ptr.p_double[rlast] = v; + s->idataridx.ptr.p_int[s->ntrf] = ilast+1; + s->rdataridx.ptr.p_int[s->ntrf] = rlast+1; +} + + +/************************************************************************* +Streams DynamicCRS row. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamcrsrow(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + ae_state *_state) +{ + ae_int_t k; + + + lpqppresolve_presolverstreami(s, a->rowend.ptr.p_int[i]-a->rowbegin.ptr.p_int[i], _state); + for(k=a->rowbegin.ptr.p_int[i]; k<=a->rowend.ptr.p_int[i]-1; k++) + { + lpqppresolve_presolverstreamir(s, a->idx.ptr.p_int[k], a->vals.ptr.p_double[k], _state); + } +} + + +/************************************************************************* +Streams DynamicCRS row, except for element in the column NotIdx (if such an +element is present) + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamcrsrownot1(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + ae_int_t notidx, + ae_state *_state) +{ + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_int_t cnt; + + + j0 = a->rowbegin.ptr.p_int[i]; + j1 = a->rowend.ptr.p_int[i]-1; + cnt = 0; + for(k=j0; k<=j1; k++) + { + if( a->idx.ptr.p_int[k]!=notidx ) + { + cnt = cnt+1; + } + } + lpqppresolve_presolverstreami(s, cnt, _state); + for(k=j0; k<=j1; k++) + { + if( a->idx.ptr.p_int[k]!=notidx ) + { + lpqppresolve_presolverstreamir(s, a->idx.ptr.p_int[k], a->vals.ptr.p_double[k], _state); + } + } +} + + +/************************************************************************* +Streams entries of a DynamicCRS row that have corresponding flags set to false. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverstreamcrsrownonflagged(presolverstack* s, + const dynamiccrs* a, + ae_int_t i, + /* Boolean */ const ae_vector* flags, + ae_state *_state) +{ + ae_int_t k; + ae_int_t cnt; + ae_int_t j0; + ae_int_t j1; + + + j0 = a->rowbegin.ptr.p_int[i]; + j1 = a->rowend.ptr.p_int[i]-1; + cnt = 0; + for(k=j0; k<=j1; k++) + { + if( !flags->ptr.p_bool[a->idx.ptr.p_int[k]] ) + { + cnt = cnt+1; + } + } + lpqppresolve_presolverstreami(s, cnt, _state); + for(k=j0; k<=j1; k++) + { + if( !flags->ptr.p_bool[a->idx.ptr.p_int[k]] ) + { + lpqppresolve_presolverstreamir(s, a->idx.ptr.p_int[k], a->vals.ptr.p_double[k], _state); + } + } +} + + +/************************************************************************* +Select transformation TIdx as the source for stream reads + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverselectstreamsource(presolverstack* s, + ae_int_t tidx, + ae_state *_state) +{ + + + s->sourceidx = tidx; + s->isrc = s->idataridx.ptr.p_int[tidx]; + s->rsrc = s->rdataridx.ptr.p_int[tidx]; +} + + +/************************************************************************* +Reads from presolver stack boolean value, advances stream pointer + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverunstreamb(presolverstack* s, + ae_bool* v, + ae_state *_state) +{ + + *v = ae_false; + + *v = s->idata.ptr.p_int[s->isrc]!=0; + s->isrc = s->isrc+1; +} + + +/************************************************************************* +Reads from presolver stack boolean value, advances stream pointer. +Function instead of a proceduring + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_presolverunstreambf(presolverstack* s, + ae_state *_state) +{ + ae_bool result; + + + result = s->idata.ptr.p_int[s->isrc]!=0; + s->isrc = s->isrc+1; + return result; +} + + +/************************************************************************* +Reads from presolver stack integer value, advances stream pointer + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverunstreami(presolverstack* s, + ae_int_t* v, + ae_state *_state) +{ + + *v = 0; + + *v = s->idata.ptr.p_int[s->isrc]; + s->isrc = s->isrc+1; +} + + +/************************************************************************* +Reads from presolver stack real value, advances stream pointer + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverunstreamr(presolverstack* s, + double* v, + ae_state *_state) +{ + + *v = 0.0; + + *v = s->rdata.ptr.p_double[s->rsrc]; + s->rsrc = s->rsrc+1; +} + + +/************************************************************************* +Reads from presolver stack int/real pair, advances stream pointers + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverunstreamir(presolverstack* s, + ae_int_t* vi, + double* vr, + ae_state *_state) +{ + + *vi = 0; + *vr = 0.0; + + *vi = s->idata.ptr.p_int[s->isrc]; + s->isrc = s->isrc+1; + *vr = s->rdata.ptr.p_double[s->rsrc]; + s->rsrc = s->rsrc+1; +} + + +/************************************************************************* +Reads from presolver stack compressed sparse vector, advances stream pointers + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverunstreamsparsevec(presolverstack* s, + ae_int_t* cnt, + /* Integer */ ae_vector* idx, + /* Real */ ae_vector* vals, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + lpqppresolve_presolverunstreami(s, cnt, _state); + iallocv(*cnt, idx, _state); + rallocv(*cnt, vals, _state); + for(i=0; i<=*cnt-1; i++) + { + lpqppresolve_presolverunstreamir(s, &j, &v, _state); + idx->ptr.p_int[i] = j; + vals->ptr.p_double[i] = v; + } +} + + +/************************************************************************* +Checks that we are at the end of the stream corresponding to transfrom #TIdx + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverasserteos(presolverstack* s, + ae_state *_state) +{ + + + ae_assert(s->isrc==s->idataridx.ptr.p_int[s->sourceidx+1], "PresolverAssertEOS: unread integers in the stream", _state); + ae_assert(s->rsrc==s->rdataridx.ptr.p_int[s->sourceidx+1], "PresolverAssertEOS: unread reals in the stream", _state); +} + + +/************************************************************************* +Appends transform placeholder + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendtrf(presolverstack* s, + ae_int_t tt, + ae_state *_state) +{ + + + igrowv(s->ntrf+1, &s->trftype, _state); + igrowv(s->ntrf+2, &s->idataridx, _state); + igrowv(s->ntrf+2, &s->rdataridx, _state); + s->trftype.ptr.p_int[s->ntrf] = tt; + s->idataridx.ptr.p_int[s->ntrf+1] = s->idataridx.ptr.p_int[s->ntrf]; + s->rdataridx.ptr.p_int[s->ntrf+1] = s->rdataridx.ptr.p_int[s->ntrf]; + s->ntrf = s->ntrf+1; +} + + +/************************************************************************* +Appends cost scaling to the presolver stack. + +The cost vector is MULTIPLIED by the scale coefficient. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendcostscaling(presolverstack* s, + double vmul, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstobjectivescaling, _state); + lpqppresolve_presolverstreamr(s, vmul, _state); +} + + +/************************************************************************* +Appends column scaling to the presolver stack. + +The variable is MULTIPLIED by the scale coefficient. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendcolscaling(presolverstack* s, + ae_int_t colidx, + double vmul, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstcolscaling, _state); + lpqppresolve_presolverstreamir(s, colidx, vmul, _state); +} + + +/************************************************************************* +Appends column shifting to the presolver stack. + +The variable is INCREASED by the shift offset. + + -- ALGLIB -- + Copyright 01.06.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendcolshifting(presolverstack* s, + ae_int_t colidx, + double vadd, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstcolshifting, _state); + lpqppresolve_presolverstreamir(s, colidx, vadd, _state); +} + + +/************************************************************************* +Appends row scaling to the presolver stack. + +The row is MULTIPLIED by the scale coefficient. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendrowscaling(presolverstack* s, + ae_int_t rowidx, + double vmul, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstrowscaling, _state); + lpqppresolve_presolverstreamir(s, rowidx, vmul, _state); +} + + +/************************************************************************* +Appends quadratic constraint scaling to the presolver stack. + +The row is MULTIPLIED by the scale coefficient. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendqcscaling(presolverstack* s, + ae_int_t qcidx, + double vmul, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstqcscaling, _state); + lpqppresolve_presolverstreamir(s, qcidx, vmul, _state); +} + + +/************************************************************************* +Appends conic constraint scaling to the presolver stack. + +The row is MULTIPLIED by the scale coefficient. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendccscaling(presolverstack* s, + ae_int_t ccidx, + double vmul, + ae_state *_state) +{ + + +} + + +/************************************************************************* +Appends command to drop empty col and set variable and Lagrange multiplier +to prescribed values + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappenddropemptycol(presolverstack* s, + ae_int_t colidx, + double varval, + double lagval, + ae_int_t statval, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstdropemptycol, _state); + lpqppresolve_presolverstreami(s, colidx, _state); + lpqppresolve_presolverstreamr(s, varval, _state); + lpqppresolve_presolverstreamr(s, lagval, _state); + lpqppresolve_presolverstreami(s, statval, _state); +} + + +/************************************************************************* +Appends command to drop empty row + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappenddropemptyrow(presolverstack* s, + ae_int_t rowidx, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstdropemptyrow, _state); + lpqppresolve_presolverstreami(s, rowidx, _state); +} + + +/************************************************************************* +Appends command to drop empty/irrelevant quadratic constraints + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappenddropemptyqc(presolverstack* s, + ae_int_t qcidx, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstdropemptyqc, _state); + lpqppresolve_presolverstreami(s, qcidx, _state); +} + + +/************************************************************************* +Appends command to convert singleton row to box constraint + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendsingletonrow(presolverstack* s, + ae_int_t i, + ae_int_t j, + double v, + double swapsign, + double bndl, + ae_bool bndlisbc, + double bndu, + ae_bool bnduisbc, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstsingletonrow, _state); + lpqppresolve_presolverstreami(s, i, _state); + lpqppresolve_presolverstreami(s, j, _state); + lpqppresolve_presolverstreamr(s, v, _state); + lpqppresolve_presolverstreamr(s, swapsign, _state); + lpqppresolve_presolverstreamr(s, bndl, _state); + lpqppresolve_presolverstreamb(s, bndlisbc, _state); + lpqppresolve_presolverstreamr(s, bndu, _state); + lpqppresolve_presolverstreamb(s, bnduisbc, _state); +} + + +/************************************************************************* +Appends command to fix variable. + +Parameters: + ColIdx, FixVal - column index and value for fixing + Ci - C[i], linear term + SparseH - if HasH=True, quadratic term; may contain already + dropped elements. Both triangles are included. + IsDroppedCol - flags for variables that were already dropped. + The ColIdx-th one must NOT be included. + Used to correctly output elements of H and QC when + multiple variables are fixed sequentially. + HasH - if False, SparseH/IsDroppedCol are ignored. + AT - if HasAT=True, linear constraints matrix (transposed) + HasAT - if False, AT is ignored + QC - quadratic constraints, if any + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendfixedvar(presolverstack* s, + ae_int_t colidx, + double fixval, + double ci, + const dynamiccrs* sparseh, + const presolvervcstats* vcstats, + ae_bool hash, + const dynamiccrs* at, + ae_bool hasat, + dynamiccrsqconstraints* qc, + ae_state *_state) +{ + ae_frame _frame_block; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + ae_int_t qidx; + ae_int_t qccnt; + ae_int_t k; + ae_int_t varpos; + ae_int_t cntout; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + + ae_assert(!vcstats->isdroppedcol.ptr.p_bool[colidx], "PRESOLVER: integrity check 6632 failed", _state); + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstfixedvar, _state); + lpqppresolve_presolverstreami(s, colidx, _state); + lpqppresolve_presolverstreamr(s, fixval, _state); + lpqppresolve_presolverstreamr(s, ci, _state); + lpqppresolve_presolverstreamb(s, hash, _state); + if( hash ) + { + lpqppresolve_presolverstreamcrsrownonflagged(s, sparseh, colidx, &vcstats->isdroppedcol, _state); + } + + /* + * Stream linear constraints column, or zero (denoting zero-length array) if no linear constraint + */ + if( hasat ) + { + lpqppresolve_presolverstreamcrsrow(s, at, colidx, _state); + } + else + { + lpqppresolve_presolverstreami(s, 0, _state); + } + + /* + * Stream quadratic constraints + */ + qccnt = ae_obj_array_get_length(&qc->constraints); + for(qidx=0; qidx<=qccnt-1; qidx++) + { + + /* + * Skip constraints that are dropped at this moment + */ + if( vcstats->isdroppedqc.ptr.p_bool[qidx] ) + { + continue; + } + + /* + * Skip constraints that do not include the fixed variable + */ + ae_obj_array_get(&qc->constraints, qidx, &_qci, _state); + varpos = ibinarysearchlft(&qci->varidx, 0, qci->nvars, colidx, _state); + if( varpos==qci->nvars||qci->varidx.ptr.p_int[varpos]!=colidx ) + { + continue; + } + + /* + * The constraint is accepted and streamed + */ + lpqppresolve_presolverstreamb(s, ae_true, _state); + lpqppresolve_presolverstreami(s, qidx, _state); + lpqppresolve_presolverstreamr(s, qci->b.ptr.p_double[varpos], _state); + cntout = 0; + for(k=qci->fullq.rowbegin.ptr.p_int[varpos]; k<=qci->fullq.rowend.ptr.p_int[varpos]-1; k++) + { + if( !vcstats->isdroppedcol.ptr.p_bool[qci->varidx.ptr.p_int[qci->fullq.idx.ptr.p_int[k]]] ) + { + cntout = cntout+1; + } + } + lpqppresolve_presolverstreami(s, cntout, _state); + for(k=qci->fullq.rowbegin.ptr.p_int[varpos]; k<=qci->fullq.rowend.ptr.p_int[varpos]-1; k++) + { + if( !vcstats->isdroppedcol.ptr.p_bool[qci->varidx.ptr.p_int[qci->fullq.idx.ptr.p_int[k]]] ) + { + lpqppresolve_presolverstreamir(s, qci->varidx.ptr.p_int[qci->fullq.idx.ptr.p_int[k]], qci->fullq.vals.ptr.p_double[k], _state); + } + } + } + lpqppresolve_presolverstreamb(s, ae_false, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Appends explicit slack transformation + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendexplicitslack(presolverstack* s, + ae_int_t i, + ae_int_t j, + double aij, + double slackbndl, + double slackbndu, + double al, + double au, + const dynamiccrs* a, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstexplicitslack, _state); + lpqppresolve_presolverstreami(s, i, _state); + lpqppresolve_presolverstreami(s, j, _state); + lpqppresolve_presolverstreamr(s, aij, _state); + lpqppresolve_presolverstreamr(s, slackbndl, _state); + lpqppresolve_presolverstreamr(s, slackbndu, _state); + lpqppresolve_presolverstreamr(s, al, _state); + lpqppresolve_presolverstreamr(s, au, _state); + lpqppresolve_presolverstreamcrsrow(s, a, i, _state); +} + + +/************************************************************************* +Appends implicit slack transformation + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappendimplicitslack(presolverstack* s, + ae_int_t i, + ae_int_t j, + double aij, + double cj, + double equalitybnd, + const dynamiccrs* a, + ae_state *_state) +{ + + + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstimplicitslack, _state); + lpqppresolve_presolverstreami(s, i, _state); + lpqppresolve_presolverstreami(s, j, _state); + lpqppresolve_presolverstreamr(s, aij, _state); + lpqppresolve_presolverstreamr(s, cj, _state); + lpqppresolve_presolverstreamr(s, equalitybnd, _state); + lpqppresolve_presolverstreamcrsrow(s, a, i, _state); +} + + +/************************************************************************* +Appends doubleton row which is used to factor out variable Col0 using +substitution X[COL0] := (ABnd-Ai1*X[COL1])/Ai0. + +AT and SparseH (if HasH=True) must contain original linear constraints prior to substitution. + + -- ALGLIB -- + Copyright 11.06.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverappenddoubletonfactorout(presolverstack* s, + const presolvervcstats* vcstats, + ae_int_t rowidx, + ae_int_t col0, + double bndl0, + double bndu0, + ae_int_t col1, + double bndl1, + double bndu1, + double c0, + double c1, + const dynamiccrs* sparseh, + ae_bool hash, + const dynamiccrs* at, + dynamiccrsqconstraints* qc, + double ai0, + double ai1, + double abnd, + double newbndl1, + double newbndu1, + ae_int_t bndlactivates, + ae_int_t bnduactivates, + ae_state *_state) +{ + ae_frame _frame_block; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + ae_int_t qccnt; + ae_int_t k; + ae_int_t qidx; + ae_int_t pos0; + ae_int_t pos1; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + + qccnt = ae_obj_array_get_length(&qc->constraints); + lpqppresolve_presolverappendtrf(s, lpqppresolve_pstdoubletoneq, _state); + lpqppresolve_presolverstreami(s, rowidx, _state); + lpqppresolve_presolverstreami(s, col0, _state); + lpqppresolve_presolverstreamr(s, bndl0, _state); + lpqppresolve_presolverstreamr(s, bndu0, _state); + lpqppresolve_presolverstreami(s, col1, _state); + lpqppresolve_presolverstreamr(s, bndl1, _state); + lpqppresolve_presolverstreamr(s, bndu1, _state); + lpqppresolve_presolverstreamr(s, ai0, _state); + lpqppresolve_presolverstreamr(s, ai1, _state); + lpqppresolve_presolverstreamr(s, abnd, _state); + lpqppresolve_presolverstreamr(s, newbndl1, _state); + lpqppresolve_presolverstreamr(s, newbndu1, _state); + lpqppresolve_presolverstreami(s, bndlactivates, _state); + lpqppresolve_presolverstreami(s, bnduactivates, _state); + lpqppresolve_presolverstreamr(s, c0, _state); + lpqppresolve_presolverstreamr(s, c1, _state); + lpqppresolve_presolverstreamb(s, hash, _state); + if( hash ) + { + lpqppresolve_presolverstreamcrsrow(s, sparseh, col0, _state); + lpqppresolve_presolverstreamcrsrow(s, sparseh, col1, _state); + } + lpqppresolve_presolverstreamcrsrownot1(s, at, col0, rowidx, _state); + lpqppresolve_presolverstreamcrsrownot1(s, at, col1, rowidx, _state); + for(qidx=0; qidx<=qccnt-1; qidx++) + { + + /* + * Skip constraints that are dropped at this moment + */ + if( vcstats->isdroppedqc.ptr.p_bool[qidx] ) + { + continue; + } + + /* + * Skip constraints that do not include at least one of these variables + */ + ae_obj_array_get(&qc->constraints, qidx, &_qci, _state); + pos0 = ibinarysearchlft(&qci->varidx, 0, qci->nvars, col0, _state); + pos1 = ibinarysearchlft(&qci->varidx, 0, qci->nvars, col1, _state); + if( (pos0==qci->nvars||qci->varidx.ptr.p_int[pos0]!=col0)&&(pos1==qci->nvars||qci->varidx.ptr.p_int[pos1]!=col1) ) + { + continue; + } + + /* + * The constraint is accepted and streamed + */ + lpqppresolve_presolverstreamb(s, ae_true, _state); + lpqppresolve_presolverstreami(s, qidx, _state); + if( pos0nvars&&qci->varidx.ptr.p_int[pos0]==col0 ) + { + lpqppresolve_presolverstreamr(s, qci->b.ptr.p_double[pos0], _state); + lpqppresolve_presolverstreami(s, qci->fullq.rowend.ptr.p_int[pos0]-qci->fullq.rowbegin.ptr.p_int[pos0], _state); + for(k=qci->fullq.rowbegin.ptr.p_int[pos0]; k<=qci->fullq.rowend.ptr.p_int[pos0]-1; k++) + { + lpqppresolve_presolverstreamir(s, qci->varidx.ptr.p_int[qci->fullq.idx.ptr.p_int[k]], qci->fullq.vals.ptr.p_double[k], _state); + } + } + else + { + lpqppresolve_presolverstreamr(s, 0.0, _state); + lpqppresolve_presolverstreami(s, 0, _state); + } + if( pos1nvars&&qci->varidx.ptr.p_int[pos1]==col1 ) + { + lpqppresolve_presolverstreamr(s, qci->b.ptr.p_double[pos1], _state); + lpqppresolve_presolverstreami(s, qci->fullq.rowend.ptr.p_int[pos1]-qci->fullq.rowbegin.ptr.p_int[pos1], _state); + for(k=qci->fullq.rowbegin.ptr.p_int[pos1]; k<=qci->fullq.rowend.ptr.p_int[pos1]-1; k++) + { + lpqppresolve_presolverstreamir(s, qci->varidx.ptr.p_int[qci->fullq.idx.ptr.p_int[k]], qci->fullq.vals.ptr.p_double[k], _state); + } + } + else + { + lpqppresolve_presolverstreamr(s, 0.0, _state); + lpqppresolve_presolverstreami(s, 0, _state); + } + } + lpqppresolve_presolverstreamb(s, ae_false, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function restores original solution, given the solution of the +transformed problem. + +Below N and M denote column/row count for both the original problem and +transformed one PRIOR to removal of dropped columns and rows. + +INPUT PARAMETERS: + S - a sequence of presolve transformations + X - array[N], transformed solution after permutation + that restores original variable order (moves all + fixed variables to their positions) + LagBC- array[N], Lagrange coeffs for box constraints + LagLC- array[M], Lagrange coeffs for linear constraints + after permutation that restores original row order + (moves all dropped rows to their positions) + LagQC- array[MQC], Lagrange coeffs for quadratic constraints + after permutation that restores original row order + (moves all dropped rows to their positions) + Stats- array[N+M], constraint stats for box and linear constraints; + quadratic constraints are not included. + Ignored if NeedStats=False + EPS - stopping criteria, >=0, used to regularize some computations + (the idea is that the more regularization, the better, as + long as it is below EPS). + +OUTPUT PARAMETERS: + X, LagBC, LagLC, Stats-restored solution + + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolverrestoresolution(presolverstack* s, + /* Real */ ae_vector* x, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + /* Integer */ ae_vector* stats, + ae_bool needstats, + double eps, + ae_state *_state) +{ + ae_int_t tidx; + ae_int_t tt; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t cnt; + ae_int_t vstat; + double aij; + double v; + double vv; + double vvar; + double vlag; + double vswap; + double fixval; + double ci; + double cj; + double c0; + double c1; + double equalitybnd; + double bndl; + double bndu; + double al; + double au; + ae_bool bndlisbc; + ae_bool bnduisbc; + ae_bool transferlagtobc; + double ratingl; + double ratingu; + ae_bool hash; + ae_int_t rowidx; + ae_int_t col0; + double bndl0; + double bndu0; + ae_int_t col1; + double bndl1; + double bndu1; + double ai0; + double ai1; + double abnd; + double newbndl1; + double newbndu1; + ae_int_t bndlactivates; + ae_int_t bnduactivates; + ae_int_t cnt0; + ae_int_t cnt1; + ae_int_t cnt2; + ae_int_t cnt3; + ae_int_t cntq; + double g0; + double g1; + ae_int_t relevantboundactivatedby; + ae_int_t qcidx; + double d; + double cs; + double sn; + double s00; + double s01; + double s10; + double s11; + double s20; + double s21; + double r0; + double r1; + double r2; + double v0; + double v1; + + + for(tidx=s->ntrf-1; tidx>=0; tidx--) + { + tt = s->trftype.ptr.p_int[tidx]; + if( tt==lpqppresolve_pstobjectivescaling ) + { + + /* + * Reverse cost scaling + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreamr(s, &v, _state); + lpqppresolve_presolverasserteos(s, _state); + rmulv(s->n, (double)1/v, lagbc, _state); + rmulv(s->m, (double)1/v, laglc, _state); + rmulv(s->mqc, (double)1/v, lagqc, _state); + continue; + } + if( tt==lpqppresolve_pstcolscaling ) + { + + /* + * Reverse column scaling + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreamir(s, &k, &v, _state); + lpqppresolve_presolverasserteos(s, _state); + x->ptr.p_double[k] = x->ptr.p_double[k]/v; + lagbc->ptr.p_double[k] = lagbc->ptr.p_double[k]*v; + continue; + } + if( tt==lpqppresolve_pstcolshifting ) + { + + /* + * Reverse variable shifting + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreamir(s, &k, &v, _state); + lpqppresolve_presolverasserteos(s, _state); + x->ptr.p_double[k] = x->ptr.p_double[k]-v; + continue; + } + if( tt==lpqppresolve_pstrowscaling ) + { + + /* + * Reverse row scaling + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreamir(s, &k, &v, _state); + lpqppresolve_presolverasserteos(s, _state); + laglc->ptr.p_double[k] = laglc->ptr.p_double[k]*v; + continue; + } + if( tt==lpqppresolve_pstqcscaling ) + { + + /* + * Reverse QC scaling + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreamir(s, &k, &v, _state); + lpqppresolve_presolverasserteos(s, _state); + lagqc->ptr.p_double[k] = lagqc->ptr.p_double[k]*v; + continue; + } + if( tt==lpqppresolve_pstdropemptycol ) + { + + /* + * Reverse dropping empty col + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &k, _state); + lpqppresolve_presolverunstreamr(s, &vvar, _state); + lpqppresolve_presolverunstreamr(s, &vlag, _state); + lpqppresolve_presolverunstreami(s, &vstat, _state); + lpqppresolve_presolverasserteos(s, _state); + x->ptr.p_double[k] = vvar; + lagbc->ptr.p_double[k] = vlag; + if( needstats ) + { + stats->ptr.p_int[k] = vstat; + } + continue; + } + if( tt==lpqppresolve_pstdropemptyrow ) + { + + /* + * Reverse dropping empty row + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &k, _state); + lpqppresolve_presolverasserteos(s, _state); + laglc->ptr.p_double[k] = (double)(0); + if( needstats ) + { + stats->ptr.p_int[k] = 0; + } + continue; + } + if( tt==lpqppresolve_pstdropemptyqc ) + { + + /* + * Reverse dropping QC + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &k, _state); + lpqppresolve_presolverasserteos(s, _state); + lagqc->ptr.p_double[k] = (double)(0); + continue; + } + if( tt==lpqppresolve_pstsingletonrow ) + { + + /* + * Handle singleton row. + * Read data from stream. + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &i, _state); + lpqppresolve_presolverunstreami(s, &j, _state); + lpqppresolve_presolverunstreamr(s, &v, _state); + lpqppresolve_presolverunstreamr(s, &vswap, _state); + lpqppresolve_presolverunstreamr(s, &bndl, _state); + lpqppresolve_presolverunstreamb(s, &bndlisbc, _state); + lpqppresolve_presolverunstreamr(s, &bndu, _state); + lpqppresolve_presolverunstreamb(s, &bnduisbc, _state); + lpqppresolve_presolverasserteos(s, _state); + + /* + * Determine bound that is "most active" using rating that combines Lagrangian magnitude + */ + ae_assert(ae_isfinite(bndl, _state)||ae_isfinite(bndu, _state), "PRESOLVE: singleton row with both bounds absent", _state); + ae_assert(ae_fp_eq(ae_fabs(vswap, _state),(double)(1)), "PRESOLVE: unexpected VSwap", _state); + ratingl = x->ptr.p_double[j]-bndl+ae_maxreal(lagbc->ptr.p_double[j], 0.0, _state); + ratingu = bndu-x->ptr.p_double[j]+ae_maxreal(-lagbc->ptr.p_double[j], 0.0, _state); + if( ae_fp_less(ratingl,ratingu) ) + { + + /* + * Lower bound is more likely + */ + transferlagtobc = bndlisbc; + } + else + { + + /* + * Upper bound is more likely + */ + transferlagtobc = bnduisbc; + } + + /* + * Transfer constraint activity from the transformed problem to the original one + */ + if( transferlagtobc ) + { + + /* + * Box constraint of the original problem is active, linear singleton constraint is inactive + */ + laglc->ptr.p_double[i] = 0.0; + if( needstats ) + { + stats->ptr.p_int[s->n+i] = 0; + } + } + else + { + + /* + * Linear constraint of the original problem is active, box constraint is inactive. + */ + laglc->ptr.p_double[i] = lagbc->ptr.p_double[j]/v*vswap; + lagbc->ptr.p_double[j] = (double)(0); + if( needstats ) + { + stats->ptr.p_int[s->n+i] = ae_round((double)stats->ptr.p_int[j]*vswap, _state); + stats->ptr.p_int[j] = 0; + } + } + continue; + } + if( tt==lpqppresolve_pstfixedvar ) + { + + /* + * Fixed variable + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &j, _state); + lpqppresolve_presolverunstreamr(s, &fixval, _state); + + /* + * Restore variable + */ + x->ptr.p_double[j] = fixval; + + /* + * Unstream linear term and start computing gradient for the J-th variable + */ + lpqppresolve_presolverunstreamr(s, &ci, _state); + g0 = ci; + + /* + * Unstream quadratic term and update gradient + */ + lpqppresolve_presolverunstreamb(s, &hash, _state); + if( hash ) + { + lpqppresolve_presolverunstreamsparsevec(s, &cnt, &s->sparseidx0, &s->sparseval0, _state); + for(i=0; i<=cnt-1; i++) + { + g0 = g0+s->sparseval0.ptr.p_double[i]*x->ptr.p_double[s->sparseidx0.ptr.p_int[i]]; + } + } + + /* + * Unstream linear constraints and update gradient + */ + lpqppresolve_presolverunstreamsparsevec(s, &cnt, &s->sparseidx0, &s->sparseval0, _state); + for(i=0; i<=cnt-1; i++) + { + g0 = g0+s->sparseval0.ptr.p_double[i]*laglc->ptr.p_double[s->sparseidx0.ptr.p_int[i]]; + } + + /* + * Unstream quadratic constraints and update gradient + */ + while(lpqppresolve_presolverunstreambf(s, _state)) + { + lpqppresolve_presolverunstreami(s, &qcidx, _state); + lpqppresolve_presolverunstreamr(s, &v, _state); + lpqppresolve_presolverunstreami(s, &cntq, _state); + for(i=0; i<=cntq-1; i++) + { + lpqppresolve_presolverunstreamir(s, &k, &vv, _state); + v = v+vv*x->ptr.p_double[k]; + } + g0 = g0+lagqc->ptr.p_double[qcidx]*v; + } + + /* + * Check EOS + */ + lpqppresolve_presolverasserteos(s, _state); + + /* + * Recompute Lagrange multiplier for the constraint + */ + lagbc->ptr.p_double[j] = -g0; + if( needstats ) + { + stats->ptr.p_int[j] = ae_sign(lagbc->ptr.p_double[j], _state); + } + continue; + } + if( tt==lpqppresolve_pstexplicitslack ) + { + + /* + * Explicit slack variable: + * * deduce its bounds from row activity + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &i, _state); + lpqppresolve_presolverunstreami(s, &j, _state); + lpqppresolve_presolverunstreamr(s, &aij, _state); + lpqppresolve_presolverunstreamr(s, &bndl, _state); + lpqppresolve_presolverunstreamr(s, &bndu, _state); + lpqppresolve_presolverunstreamr(s, &al, _state); + lpqppresolve_presolverunstreamr(s, &au, _state); + lpqppresolve_presolverunstreamsparsevec(s, &cnt, &s->sparseidx0, &s->sparseval0, _state); + lpqppresolve_presolverasserteos(s, _state); + x->ptr.p_double[j] = (double)(0); + v = (double)(0); + for(k=0; k<=cnt-1; k++) + { + v = v+s->sparseval0.ptr.p_double[k]*x->ptr.p_double[s->sparseidx0.ptr.p_int[k]]; + } + if( ae_isfinite(al, _state) ) + { + al = (al-v)/aij; + } + if( ae_isfinite(au, _state) ) + { + au = (au-v)/aij; + } + if( ae_fp_less(aij,(double)(0)) ) + { + swapr(&al, &au, _state); + if( !ae_isfinite(al, _state) ) + { + al = _state->v_neginf; + } + if( !ae_isfinite(au, _state) ) + { + au = _state->v_posinf; + } + } + if( ae_isfinite(al, _state)&&ae_fp_greater(al,bndl) ) + { + bndl = al; + } + if( ae_isfinite(au, _state)&&ae_fp_less(au,bndu) ) + { + bndu = au; + } + if( ae_isfinite(bndl, _state) ) + { + x->ptr.p_double[j] = bndl; + } + else + { + if( ae_isfinite(bndu, _state) ) + { + x->ptr.p_double[j] = bndu; + } + else + { + x->ptr.p_double[j] = (double)(0); + } + } + lagbc->ptr.p_double[j] = -aij*laglc->ptr.p_double[i]; + if( needstats ) + { + stats->ptr.p_int[j] = -ae_sign(aij, _state)*stats->ptr.p_int[s->n+i]; + } + continue; + } + if( tt==lpqppresolve_pstimplicitslack ) + { + + /* + * Implicit slack variable: + * * deduce its bounds from row activity + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &i, _state); + lpqppresolve_presolverunstreami(s, &j, _state); + lpqppresolve_presolverunstreamr(s, &aij, _state); + lpqppresolve_presolverunstreamr(s, &cj, _state); + lpqppresolve_presolverunstreamr(s, &equalitybnd, _state); + lpqppresolve_presolverunstreamsparsevec(s, &cnt, &s->sparseidx0, &s->sparseval0, _state); + lpqppresolve_presolverasserteos(s, _state); + x->ptr.p_double[j] = (double)(0); + v = (double)(0); + for(k=0; k<=cnt-1; k++) + { + v = v+s->sparseval0.ptr.p_double[k]*x->ptr.p_double[s->sparseidx0.ptr.p_int[k]]; + } + x->ptr.p_double[j] = (equalitybnd-v)/aij; + lagbc->ptr.p_double[j] = -aij*laglc->ptr.p_double[i]; + laglc->ptr.p_double[i] = laglc->ptr.p_double[i]-cj/aij; + if( needstats ) + { + stats->ptr.p_int[j] = -ae_sign(aij, _state)*stats->ptr.p_int[s->n+i]; + } + continue; + } + if( tt==lpqppresolve_pstdoubletoneq ) + { + + /* + * Doubleton equality transformation: unstream data and compute residual gradient wrt variables col0 and col1 + */ + lpqppresolve_presolverselectstreamsource(s, tidx, _state); + lpqppresolve_presolverunstreami(s, &rowidx, _state); + lpqppresolve_presolverunstreami(s, &col0, _state); + lpqppresolve_presolverunstreamr(s, &bndl0, _state); + lpqppresolve_presolverunstreamr(s, &bndu0, _state); + lpqppresolve_presolverunstreami(s, &col1, _state); + lpqppresolve_presolverunstreamr(s, &bndl1, _state); + lpqppresolve_presolverunstreamr(s, &bndu1, _state); + lpqppresolve_presolverunstreamr(s, &ai0, _state); + lpqppresolve_presolverunstreamr(s, &ai1, _state); + lpqppresolve_presolverunstreamr(s, &abnd, _state); + lpqppresolve_presolverunstreamr(s, &newbndl1, _state); + lpqppresolve_presolverunstreamr(s, &newbndu1, _state); + lpqppresolve_presolverunstreami(s, &bndlactivates, _state); + lpqppresolve_presolverunstreami(s, &bnduactivates, _state); + + /* + * Restore variable Col0 + */ + x->ptr.p_double[col0] = boundval((abnd-ai1*x->ptr.p_double[col1])/ai0, bndl0, bndu0, _state); + + /* + * Unstream linear term and start computing gradient + */ + lpqppresolve_presolverunstreamr(s, &c0, _state); + lpqppresolve_presolverunstreamr(s, &c1, _state); + g0 = c0; + g1 = c1; + + /* + * Unstream quadratic term, add to the residual gradient + */ + lpqppresolve_presolverunstreamb(s, &hash, _state); + if( hash ) + { + lpqppresolve_presolverunstreamsparsevec(s, &cnt0, &s->sparseidx0, &s->sparseval0, _state); + lpqppresolve_presolverunstreamsparsevec(s, &cnt1, &s->sparseidx1, &s->sparseval1, _state); + } + else + { + cnt0 = 0; + cnt1 = 0; + } + for(i=0; i<=cnt0-1; i++) + { + g0 = g0+s->sparseval0.ptr.p_double[i]*x->ptr.p_double[s->sparseidx0.ptr.p_int[i]]; + } + for(i=0; i<=cnt1-1; i++) + { + g1 = g1+s->sparseval1.ptr.p_double[i]*x->ptr.p_double[s->sparseidx1.ptr.p_int[i]]; + } + + /* + * Unstream linear term, add to the residual gradient + */ + lpqppresolve_presolverunstreamsparsevec(s, &cnt2, &s->sparseidx2, &s->sparseval2, _state); + lpqppresolve_presolverunstreamsparsevec(s, &cnt3, &s->sparseidx3, &s->sparseval3, _state); + for(i=0; i<=cnt2-1; i++) + { + g0 = g0+s->sparseval2.ptr.p_double[i]*laglc->ptr.p_double[s->sparseidx2.ptr.p_int[i]]; + } + for(i=0; i<=cnt3-1; i++) + { + g1 = g1+s->sparseval3.ptr.p_double[i]*laglc->ptr.p_double[s->sparseidx3.ptr.p_int[i]]; + } + + /* + * Unstream quadratic constraints, add to the residual gradient + */ + while(lpqppresolve_presolverunstreambf(s, _state)) + { + lpqppresolve_presolverunstreami(s, &qcidx, _state); + lpqppresolve_presolverunstreamr(s, &v, _state); + lpqppresolve_presolverunstreami(s, &cntq, _state); + for(i=0; i<=cntq-1; i++) + { + lpqppresolve_presolverunstreamir(s, &j, &vv, _state); + v = v+vv*x->ptr.p_double[j]; + } + g0 = g0+lagqc->ptr.p_double[qcidx]*v; + lpqppresolve_presolverunstreamr(s, &v, _state); + lpqppresolve_presolverunstreami(s, &cntq, _state); + for(i=0; i<=cntq-1; i++) + { + lpqppresolve_presolverunstreamir(s, &j, &vv, _state); + v = v+vv*x->ptr.p_double[j]; + } + g1 = g1+lagqc->ptr.p_double[qcidx]*v; + } + + /* + * The stream was fully processed + */ + lpqppresolve_presolverasserteos(s, _state); + + /* + * Compute Lagrange multipliers for box and linear constraints. In order to do + * it we solve the following system: + * + * [ E0 Ai0 ] [ lagBC ] [ -(C0 + SUM(lagLC[j]*Aj0)) ] + * [ ] [ ] = [ ] + * [ E1 Ai1 ] [ lagLC ] [ -(C1 + SUM(lagLC[j]*Aj1)) ] + * + * where [E0,E1] is either [0,1], [1,0] or [0,0], depending on which box constraint + * is active, if active at all. + * + * Here LagLC corresponds to the doubleton equality row being handled, and LagBC + * corresponds to one of the variable bounds (the specific one is determined + * during analysis of the solution recovered). + * + * We try all three options: no bounds active, bound on col0 is active, bound + * on col1 is active, and compare dual and complementarity errors. The option + * which gives the smallest error is chosen. + * + * The current box constraint on variable COL1 is an amalgamation of original + * box constraints coming from variables COL0 and COL1. First, we have to determine + * whether the constraint is at the upper or at the lower bound. Lagrange + * multiplier sign is not a good measure because nearly-zero multipliers can have + * their sign flipped due to rounding errors. In order to do so we compute + * rating for lower and upper bounds. After comparing them we determine + * which bound is active. + */ + v = (-g0*ai0-g1*ai1)/(ai0*ai0+ai1*ai1); + if( ae_isfinite(newbndl1, _state)||ae_isfinite(newbndu1, _state) ) + { + ratingl = ae_maxrealnumber; + ratingu = ae_maxrealnumber; + if( ae_isfinite(newbndl1, _state) ) + { + ratingl = ae_fabs(x->ptr.p_double[col1]-newbndl1, _state)*ae_maxreal(-lagbc->ptr.p_double[col1], 0.0, _state)+ae_maxreal(x->ptr.p_double[col1]-newbndl1, 0.0, _state)+ae_maxreal(lagbc->ptr.p_double[col1], 0.0, _state); + } + if( ae_isfinite(newbndu1, _state) ) + { + ratingu = ae_fabs(newbndu1-x->ptr.p_double[col1], _state)*ae_maxreal(lagbc->ptr.p_double[col1], 0.0, _state)+ae_maxreal(newbndu1-x->ptr.p_double[col1], 0.0, _state)+ae_maxreal(-lagbc->ptr.p_double[col1], 0.0, _state); + } + relevantboundactivatedby = icase2(ae_fp_less(ratingl,ratingu), bndlactivates, bnduactivates, _state); + } + else + { + relevantboundactivatedby = lpqppresolve_actnone; + } + if( relevantboundactivatedby==lpqppresolve_actlowerboundonk0||relevantboundactivatedby==lpqppresolve_actupperboundonk0 ) + { + + /* + * The system to be solved in the least-squares sense is + * + * [ 1 Ai0 ] [ -(G0 + SUM(lagLC[j]*Aj0)) ] + * [ ] [ lagBC ] [ ] + * [ Ai1 ]*[ ] = [ -(G1 + SUM(lagLC[j]*Aj1)) ] + * [ ] [ lagLC ] [ ] + * [ D ] [ 0 ] + * + * where D=|X0-BNDL0|+eps or D=|X0-BNDU0|+eps, depending on RelevantBoundActivatedBy. + * The first two rows come from requirement for Lagrangian gradient to be zero, + * the last row comes from complementarity conditions for lagBC, with EPS being added + * to help regularize the problem. + * + * The system is rewritten as + * + * [ S00 S01 ] [ R0 ] + * [ ] [ lagBC ] [ ] + * [ S11 ]*[ ] = [ R1 ] + * [ ] [ lagLC ] [ ] + * [ S20 ] [ R2 ] + * + * and is solved by applying a sequence of rotations that converts it to an upper + * triangular form. + */ + d = ae_fabs(x->ptr.p_double[col0]-rcase2(relevantboundactivatedby==lpqppresolve_actlowerboundonk0, bndl0, bndu0, _state), _state)+eps; + s00 = (double)(1); + s01 = ai0; + s11 = ai1; + s20 = d; + r0 = -g0; + r1 = -g1; + r2 = (double)(0); + generaterotation(s00, s20, &cs, &sn, &v, _state); + s00 = v; + v0 = s01; + s01 = cs*v0; + s21 = -sn*v0; + v0 = r0; + v1 = r2; + r0 = cs*v0+sn*v1; + r2 = -sn*v0+cs*v1; + generaterotation(s11, s21, &cs, &sn, &v, _state); + s11 = v; + v0 = r1; + v1 = r2; + r1 = cs*v0+sn*v1; + r2 = -sn*v0+cs*v1; + ae_assert(ae_fp_neq(s11,(double)(0)), "PRESOLVE: integrity check 781139 failed", _state); + laglc->ptr.p_double[rowidx] = r1/s11; + lagbc->ptr.p_double[col0] = (r0-s01*laglc->ptr.p_double[rowidx])/s00; + lagbc->ptr.p_double[col1] = (double)(0); + if( needstats ) + { + + /* + * Determine constraint status; the linear equality constraint is always + * active, the question is whether box constraint is actually active or + * not. We compare the rating for the activity (Lagrangian multiplier value) + * with the rating for inactivity (a distance towards corresponding bound), + * and depending on that we set constraint status. + */ + stats->ptr.p_int[col0] = 0; + stats->ptr.p_int[col1] = 0; + if( ae_isfinite(bndl0, _state)&&ae_maxreal(-lagbc->ptr.p_double[col0], 0.0, _state)>x->ptr.p_double[col0]-bndl0 ) + { + stats->ptr.p_int[col0] = -1; + } + if( ae_isfinite(bndu0, _state)&&ae_maxreal(lagbc->ptr.p_double[col0], 0.0, _state)>bndu0-x->ptr.p_double[col0] ) + { + stats->ptr.p_int[col0] = 1; + } + stats->ptr.p_int[s->n+rowidx] = ipossign(laglc->ptr.p_double[rowidx], _state); + } + continue; + } + if( relevantboundactivatedby==lpqppresolve_actlowerboundonk1||relevantboundactivatedby==lpqppresolve_actupperboundonk1 ) + { + + /* + * The system is + * + * [ Ai0 ] [ -(G0 + SUM(lagLC[j]*Aj0)) ] + * [ ] [ lagBC ] [ ] + * [ 1 Ai1 ]*[ ] = [ -(G1 + SUM(lagLC[j]*Aj1)) ] + * [ ] [ lagLC ] [ ] + * [ D ] [ 0 ] + * + * where D=|X1-BNDL1|+eps or D=|X1-BNDU1|+eps, depending on RelevantBoundActivatedBy. + * The first two rows come from requirement for Lagrangian gradient to be zero, + * the last row comes from complementarity conditions for lagBC, with EPS being added + * to help regularize the problem. + * + * The system is rewritten as + * + * [ S01 ] [ R0 ] + * [ ] [ lagBC ] [ ] + * [ S10 S11 ]*[ ] = [ R1 ] + * [ ] [ lagLC ] [ ] + * [ S20 ] [ R2 ] + * + * and is solved by applying a sequence of rotations that converts it to a + * triangular form. + */ + d = ae_fabs(x->ptr.p_double[col1]-rcase2(relevantboundactivatedby==lpqppresolve_actlowerboundonk1, bndl1, bndu1, _state), _state)+eps; + s10 = (double)(1); + s01 = ai0; + s11 = ai1; + s20 = d; + r0 = -g0; + r1 = -g1; + r2 = (double)(0); + generaterotation(s10, s20, &cs, &sn, &v, _state); + s10 = v; + v0 = s11; + s11 = cs*v0; + s21 = -sn*v0; + v0 = r1; + v1 = r2; + r1 = cs*v0+sn*v1; + r2 = -sn*v0+cs*v1; + generaterotation(s01, s21, &cs, &sn, &v, _state); + s01 = v; + v0 = r0; + v1 = r2; + r0 = cs*v0+sn*v1; + r2 = -sn*v0+cs*v1; + laglc->ptr.p_double[rowidx] = r0/s01; + lagbc->ptr.p_double[col0] = (double)(0); + lagbc->ptr.p_double[col1] = (r1-s11*laglc->ptr.p_double[rowidx])/s10; + if( needstats ) + { + + /* + * Determine constraint status; the linear equality constraint is always + * active, the question is whether box constraint is actually active or + * not. We compare the rating for the activity (Lagrangian multiplier value) + * with the rating for inactivity (a distance towards corresponding bound), + * and depending on that we set constraint status. + */ + stats->ptr.p_int[col0] = 0; + stats->ptr.p_int[col1] = 0; + if( ae_isfinite(bndl1, _state)&&ae_maxreal(-lagbc->ptr.p_double[col1], 0.0, _state)>x->ptr.p_double[col1]-bndl1 ) + { + stats->ptr.p_int[col1] = -1; + } + if( ae_isfinite(bndu1, _state)&&ae_maxreal(lagbc->ptr.p_double[col1], 0.0, _state)>bndu1-x->ptr.p_double[col1] ) + { + stats->ptr.p_int[col1] = 1; + } + stats->ptr.p_int[s->n+rowidx] = ipossign(laglc->ptr.p_double[rowidx], _state); + } + continue; + } + if( relevantboundactivatedby==lpqppresolve_actnone ) + { + + /* + * No box constraints active at the solution, determine Lagrange multiplier for + * the linear constraints by solving a least-squares system + * + * [ Ai0 ] [ lagBC ] [ -(G0 + SUM(lagLC[j]*Aj0)) ] + * [ ] [ ] = [ ] + * [ Ai1 ] [ lagLC ] [ -(G1 + SUM(lagLC[j]*Aj1)) ] + */ + lagbc->ptr.p_double[col0] = (double)(0); + lagbc->ptr.p_double[col1] = (double)(0); + laglc->ptr.p_double[rowidx] = (-g0*ai0-g1*ai1)/(ai0*ai0+ai1*ai1); + if( needstats ) + { + stats->ptr.p_int[col0] = 0; + stats->ptr.p_int[col1] = 0; + stats->ptr.p_int[s->n+rowidx] = ipossign(laglc->ptr.p_double[rowidx], _state); + } + continue; + } + ae_assert(ae_false, "PRESOLVER: integrity check 8410 failed", _state); + } + ae_assert(ae_false, "PresolverRestoreSolution: unexpected transform type", _state); + } +} + + +/************************************************************************* +Convert sparse H given by a single triangle into a full symmetric matrix. + +INPUT PARAMETERS: + H - lower/upper triangular quadratic term + IsUpper - whether H is upper or lower triangular (the other triangle + is ignored) + sparseTmp - possibly preallocated buffer; memory is reused if possible + FullH - possibly preallocated matrix; memory is reused if possible + +OUTPUT PARAMETERS: + FullH - NxN CRS matrix, fully symmetric H + + -- ALGLIB -- + Copyright 01.06.2024 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_copyexpandh(const sparsematrix* rawh, + ae_bool isupper, + sparsematrix* fullh, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t n; + ae_int_t j; + ae_int_t k; + double v; + + + ae_assert(sparseiscrs(rawh, _state)&&rawh->n==rawh->m, "PRESOLVE: integrity check 0935 failed", _state); + n = rawh->n; + + /* + * Compute row sizes for an expanded matrix + */ + isetallocv(n+1, 0, &fullh->ridx, _state); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = rawh->uidx.ptr.p_int[i]; + j1 = rawh->ridx.ptr.p_int[i+1]-1; + } + else + { + j0 = rawh->ridx.ptr.p_int[i]; + j1 = rawh->didx.ptr.p_int[i]-1; + } + fullh->ridx.ptr.p_int[i+1] = fullh->ridx.ptr.p_int[i+1]+(j1-j0+1); + for(jj=j0; jj<=j1; jj++) + { + j = rawh->idx.ptr.p_int[jj]; + fullh->ridx.ptr.p_int[j+1] = fullh->ridx.ptr.p_int[j+1]+1; + } + fullh->ridx.ptr.p_int[i+1] = fullh->ridx.ptr.p_int[i+1]+1; + } + for(i=0; i<=n-1; i++) + { + fullh->ridx.ptr.p_int[i+1] = fullh->ridx.ptr.p_int[i+1]+fullh->ridx.ptr.p_int[i]; + } + + /* + * Copy/transpose/merge, use UIdx[] as a temporary buffer to store insert position + */ + iallocv(fullh->ridx.ptr.p_int[n], &fullh->idx, _state); + rallocv(fullh->ridx.ptr.p_int[n], &fullh->vals, _state); + iallocv(n, &fullh->didx, _state); + iallocv(n, &fullh->uidx, _state); + if( isupper ) + { + icopyvx(n, &fullh->ridx, 1, &fullh->uidx, 0, _state); + for(i=n-1; i>=0; i--) + { + j0 = rawh->uidx.ptr.p_int[i]; + j1 = rawh->ridx.ptr.p_int[i+1]-1; + for(jj=j1; jj>=j0; jj--) + { + j = rawh->idx.ptr.p_int[jj]; + v = rawh->vals.ptr.p_double[jj]; + k = fullh->uidx.ptr.p_int[i]-1; + fullh->idx.ptr.p_int[k] = j; + fullh->vals.ptr.p_double[k] = v; + fullh->uidx.ptr.p_int[i] = k; + k = fullh->uidx.ptr.p_int[j]-1; + fullh->idx.ptr.p_int[k] = i; + fullh->vals.ptr.p_double[k] = v; + fullh->uidx.ptr.p_int[j] = k; + } + k = fullh->uidx.ptr.p_int[i]-1; + fullh->idx.ptr.p_int[k] = i; + if( rawh->uidx.ptr.p_int[i]>rawh->didx.ptr.p_int[i] ) + { + fullh->vals.ptr.p_double[k] = rawh->vals.ptr.p_double[rawh->didx.ptr.p_int[i]]; + } + else + { + fullh->vals.ptr.p_double[k] = 0.0; + } + fullh->didx.ptr.p_int[i] = k; + fullh->uidx.ptr.p_int[i] = k; + } + } + else + { + icopyvx(n, &fullh->ridx, 0, &fullh->uidx, 0, _state); + for(i=0; i<=n-1; i++) + { + j0 = rawh->ridx.ptr.p_int[i]; + j1 = rawh->didx.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = rawh->idx.ptr.p_int[jj]; + v = rawh->vals.ptr.p_double[jj]; + k = fullh->uidx.ptr.p_int[i]; + fullh->idx.ptr.p_int[k] = j; + fullh->vals.ptr.p_double[k] = v; + fullh->uidx.ptr.p_int[i] = k+1; + k = fullh->uidx.ptr.p_int[j]; + fullh->idx.ptr.p_int[k] = i; + fullh->vals.ptr.p_double[k] = v; + fullh->uidx.ptr.p_int[j] = k+1; + } + k = fullh->uidx.ptr.p_int[i]; + fullh->idx.ptr.p_int[k] = i; + if( rawh->uidx.ptr.p_int[i]>rawh->didx.ptr.p_int[i] ) + { + fullh->vals.ptr.p_double[k] = rawh->vals.ptr.p_double[rawh->didx.ptr.p_int[i]]; + } + else + { + fullh->vals.ptr.p_double[k] = 0.0; + } + fullh->didx.ptr.p_int[i] = k; + fullh->uidx.ptr.p_int[i] = k+1; + } + } + + /* + * Recompute UIdx[] + */ + for(i=0; i<=n-1; i++) + { + fullh->uidx.ptr.p_int[i] = fullh->didx.ptr.p_int[i]+1; + } + + /* + * Set up sparse matrix metrics + */ + fullh->matrixtype = 1; + fullh->m = n; + fullh->n = n; + fullh->ninitialized = fullh->ridx.ptr.p_int[n]; +} + + +/************************************************************************* +Prepare temporaries + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_presolvebuffersinit(presolvebuffers* buf, + ae_int_t n, + ae_int_t m, + ae_state *_state) +{ + + + if( n>0 ) + { + nisinitemptyslow(n, &buf->setn, _state); + nisinitemptyslow(n, &buf->setn2, _state); + nisinitemptyslow(n, &buf->setn3, _state); + } + if( m>0 ) + { + nisinitemptyslow(m, &buf->setm, _state); + } + else + { + nisinitemptyslow(1, &buf->setm, _state); + } +} + + +/************************************************************************* +This function drops empty columns from the matrix. It may detect unbounded +problems (when unboundedness is caused by unconstrained column). + +INPUT PARAMETERS: + C, BndL, BndU - array[N], current cost and box constraints. + IsDroppedCol- array[N], column statuses; only non-dropped ones are examined. + LagrangeFromResidual- array[N], whether we want to compute Lagrange coeffs + for box constraints using residual costs + H - if HasH=True, a full symmetric H with both triangles; + diagonal elements are always present, even if zero. + If HasH=False, ignored. + N - variables count (including both fixed and non-fixed) + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + Eps - unboundedness is checked subject to small dual feasibility + error tolerance + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + CntFixed - debug counter, updated by the function + trfStack - sequence of already applied transformations + +OUTPUT PARAMETERS: + IsDroppedCol- array[N], dropped columns are marked + LagrangeFromResidual- + array[N], dropped cols are marked + ProblemStatus- on failure (unboundedness detected) is set to -2, + unchanged otherwise + SomethingChanged-is set to True if at least one col was dropped + It is not changed otherwise. + CntDropped - debug counter, updated by the function + trfStack - updated with new transforms + +RESULT: + if unboundedness was detected, False is returned. + True is returned otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_dropemptycol(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + /* Boolean */ ae_vector* lagrangefromresidual, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntdropped, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_int_t statsval; + ae_bool result; + + + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "LPPRESOLVE: Eps<0", _state); + result = ae_true; + + /* + * Scan columns, search for an empty one + */ + for(i=0; i<=n-1; i++) + { + + /* + * Skip: + * * already dropped columns + * * columns that have non-empty A + * * columns that have non-empty H + */ + if( vcstats->isdroppedcol.ptr.p_bool[i] ) + { + continue; + } + if( m!=0&&at->rowbegin.ptr.p_int[i]!=at->rowend.ptr.p_int[i] ) + { + continue; + } + if( hash&&((sparseh->rowbegin.ptr.p_int[i]+1!=sparseh->rowend.ptr.p_int[i]||sparseh->idx.ptr.p_int[sparseh->rowbegin.ptr.p_int[i]]!=i)||ae_fp_neq(sparseh->vals.ptr.p_double[sparseh->rowbegin.ptr.p_int[i]],0.0)) ) + { + continue; + } + if( vcstats->nlcpervar.ptr.p_int[i]!=0 ) + { + continue; + } + + /* + * First, try to detect unboundedness + */ + if( (c->ptr.p_double[i]<-eps&&ae_isposinf(bndu->ptr.p_double[i], _state))||(c->ptr.p_double[i]>eps&&ae_isneginf(bndl->ptr.p_double[i], _state)) ) + { + if( dotrace ) + { + ae_trace("> the target is unbounded (column %0d is empty, C[%0d]<>0, box constraints are insufficient)\n", + (int)(i), + (int)(i)); + } + *problemstatus = -2; + *somethingchanged = ae_true; + *cntdropped = *cntdropped+1; + result = ae_false; + return result; + } + + /* + * Mark variable as fixed and issue transformation + */ + vcstats->isdroppedcol.ptr.p_bool[i] = ae_true; + *somethingchanged = ae_true; + *cntdropped = *cntdropped+1; + v = (double)(0); + statsval = 0; + if( c->ptr.p_double[i]>(double)0&&ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + + /* + * Variable has to be fixed at the lower bound + */ + v = bndl->ptr.p_double[i]; + statsval = -1; + } + if( c->ptr.p_double[i]<(double)0&&ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + + /* + * Variable has to be fixed at the upper bound + */ + v = bndu->ptr.p_double[i]; + statsval = 1; + } + if( statsval==0 ) + { + + /* + * Variable value can be chosen arbitrarily, choose as close to zero as possible + */ + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + v = ae_maxreal(v, bndl->ptr.p_double[i], _state); + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + v = ae_minreal(v, bndu->ptr.p_double[i], _state); + } + } + lpqppresolve_presolverappenddropemptycol(trfstack, i, v, -c->ptr.p_double[i], statsval, _state); + } + return result; +} + + +/************************************************************************* +This function drops clearly nonbinding constraines: empty ones and ones +with infinite bounds. + +It may detect infeasible problems (when infeasibility is caused by +constraint ranges that do not include zero - the only value possible for +an empty constraint). + +INPUT PARAMETERS: + N - vars count + VCStats - variable/constraint statistics + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + Eps - small primal feasibility error is allowed + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + TrfYLag, TrfYTgt, TrfStat, TrfStatTgt - + sequence of already applied transformations + +OUTPUT PARAMETERS: + VCStats.IsDroppedLC/QC- dropped rows are marked + ProblemStatus- on failure (infeasibility detected) is set to -3, + unchanged otherwise + SomethingChanged-is set to True if at least one row was dropped + It is not changed otherwise. + CntEmpty - debug counter, updated by the function + CntNoBounds - debug counter, updated by the function + TrfYLag, TrfYTgt, TrfStat, TrfStatTgt - + sequence of already applied transformations + +RESULT: + if infeasibility was detected, False is returned. + True is returned otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_dropclearlynonbindingrows(ae_int_t n, + presolvervcstats* vcstats, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntempty, + ae_int_t* cntemptyqc, + ae_int_t* cntnobounds, + ae_int_t* cntnoboundsqc, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t ii; + ae_int_t jj; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + ae_int_t qcidx; + ae_int_t qccnt; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + + result = ae_true; + + /* + * Scan linear constraints + */ + nisclear(&buf->setn, _state); + nisclear(&buf->setm, _state); + for(i=0; i<=m-1; i++) + { + if( !vcstats->isdroppedlc.ptr.p_bool[i] ) + { + + /* + * Empty row + */ + if( a->rowbegin.ptr.p_int[i]==a->rowend.ptr.p_int[i] ) + { + + /* + * Try to detect infeasibility + */ + if( (ae_isfinite(al->ptr.p_double[i], _state)&&ae_fp_greater(al->ptr.p_double[i],eps))||(ae_isfinite(au->ptr.p_double[i], _state)&&ae_fp_less(au->ptr.p_double[i],-eps)) ) + { + if( dotrace ) + { + ae_trace("> the constraints are infeasible (row %0d is empty, initially or due to reductions, updated constraint range does not include zero)\n", + (int)(i)); + } + *problemstatus = -3; + *somethingchanged = ae_true; + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Mark row as dropped and issue transformation + */ + vcstats->isdroppedlc.ptr.p_bool[i] = ae_true; + *somethingchanged = ae_true; + *cntempty = *cntempty+1; + lpqppresolve_presolverappenddropemptyrow(trfstack, i, _state); + continue; + } + + /* + * No bounds + */ + if( ae_isneginf(al->ptr.p_double[i], _state)&&ae_isposinf(au->ptr.p_double[i], _state) ) + { + + /* + * Add row and column containing its elements to the cleanup list + */ + nisaddelement(&buf->setm, i, _state); + for(jj=a->rowbegin.ptr.p_int[i]; jj<=a->rowend.ptr.p_int[i]-1; jj++) + { + nisaddelement(&buf->setn, a->idx.ptr.p_int[jj], _state); + } + + /* + * Mark row as dropped and issue transformation + */ + vcstats->isdroppedlc.ptr.p_bool[i] = ae_true; + *somethingchanged = ae_true; + *cntnobounds = *cntnobounds+1; + lpqppresolve_presolverappenddropemptyrow(trfstack, i, _state); + continue; + } + } + } + for(ii=0; ii<=buf->setm.nstored-1; ii++) + { + a->rowend.ptr.p_int[buf->setm.items.ptr.p_int[ii]] = a->rowbegin.ptr.p_int[buf->setm.items.ptr.p_int[ii]]; + } + for(jj=0; jj<=buf->setn.nstored-1; jj++) + { + lpqppresolve_dyncrsremovesetfromrow(at, buf->setn.items.ptr.p_int[jj], &buf->setm, _state); + } + + /* + * Scan quadratic constraints + */ + qccnt = ae_obj_array_get_length(&qc->constraints); + for(qcidx=0; qcidx<=qccnt-1; qcidx++) + { + if( vcstats->isdroppedqc.ptr.p_bool[qcidx] ) + { + continue; + } + ae_obj_array_get(&qc->constraints, qcidx, &_qci, _state); + + /* + * Handle empty constraint + */ + if( qci->nvars==0 ) + { + if( (ae_isfinite(qci->cl, _state)&&ae_fp_greater(qci->cl,eps))||(ae_isfinite(qci->cu, _state)&&ae_fp_less(qci->cu,-eps)) ) + { + if( dotrace ) + { + ae_trace("> the quadratic constraints are infeasible (row %0d is empty, initially or due to reductions, updated constraint range does not include zero)\n", + (int)(qcidx)); + } + *problemstatus = -3; + *somethingchanged = ae_true; + result = ae_false; + ae_frame_leave(_state); + return result; + } + vcstats->isdroppedqc.ptr.p_bool[qcidx] = ae_true; + *somethingchanged = ae_true; + *cntemptyqc = *cntemptyqc+1; + lpqppresolve_presolverappenddropemptyqc(trfstack, qcidx, _state); + continue; + } + + /* + * Handle constraint with no bounds + */ + if( ae_isneginf(qci->cl, _state)&&ae_isposinf(qci->cu, _state) ) + { + for(i=0; i<=qci->nvars-1; i++) + { + vcstats->nlcpervar.ptr.p_int[qci->varidx.ptr.p_int[i]] = vcstats->nlcpervar.ptr.p_int[qci->varidx.ptr.p_int[i]]-1; + } + vcstats->isdroppedqc.ptr.p_bool[qcidx] = ae_true; + *somethingchanged = ae_true; + *cntnoboundsqc = *cntnoboundsqc+1; + lpqppresolve_presolverappenddropemptyqc(trfstack, qcidx, _state); + continue; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function scans rows and converts singleton rows to box constraints. + +INPUT PARAMETERS: + BndL, BndU - array[N], box constraints. + VCStats - var/constr statistics + N - variables count (including both fixed and non-fixed) + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + Eps - tolerance used to resolve infeasibilities + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + CntFixed - debug counter, updated by the function + trfStack - sequence of already applied transformations + +OUTPUT PARAMETERS: + IsDroppedCol- array[N], dropped columns are marked + ProblemStatus- on failure (unboundedness detected) is set to -2, + unchanged otherwise + SomethingChanged-is set to True if at least one col was dropped + It is not changed otherwise. + CntDropped - debug counter, updated by the function + trfStack - updated with new transforms + +RESULT: + if unboundedness was detected, False is returned. + True is returned otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_singletonrowtobc(/* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntsingleton, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ii; + ae_int_t offs; + double v; + double prevbndl; + double prevbndu; + double wrkal; + double wrkau; + double swapsign; + double midpoint; + ae_bool lowerboundisbc; + ae_bool upperboundisbc; + ae_bool result; + + + result = ae_true; + for(i=0; i<=m-1; i++) + { + if( (!vcstats->isdroppedlc.ptr.p_bool[i]&&a->rowbegin.ptr.p_int[i]+1==a->rowend.ptr.p_int[i])&&(ae_isfinite(al->ptr.p_double[i], _state)||ae_isfinite(au->ptr.p_double[i], _state)) ) + { + + /* + * Read singleton row, perform integrity checks and normalization + */ + j = a->idx.ptr.p_int[a->rowbegin.ptr.p_int[i]]; + v = a->vals.ptr.p_double[a->rowbegin.ptr.p_int[i]]; + if( ae_fp_less_eq(ae_fabs(v, _state),lpqppresolve_smlcoeff) ) + { + + /* + * The constraint coefficient is too small, factoring it out may result in numerical instability + */ + continue; + } + ae_assert(!vcstats->isdroppedlc.ptr.p_bool[i], "SingletonRowToBC: integrity check 6363 failed", _state); + ae_assert(!vcstats->isdroppedcol.ptr.p_bool[j], "SingletonRowToBC: integrity check 6364 failed", _state); + ae_assert(ae_fp_neq(v,(double)(0)), "SingletonRowToBC: integrity check 6366 failed", _state); + wrkal = al->ptr.p_double[i]; + wrkau = au->ptr.p_double[i]; + swapsign = (double)(1); + if( ae_fp_less(v,(double)(0)) ) + { + swapr(&wrkal, &wrkau, _state); + wrkal = -wrkal; + wrkau = -wrkau; + v = -v; + swapsign = (double)(-1); + } + wrkal = wrkal/v; + wrkau = wrkau/v; + prevbndl = bndl->ptr.p_double[j]; + prevbndu = bndu->ptr.p_double[j]; + + /* + * Check feasibility + */ + if( ae_fp_greater(prevbndl,prevbndu+eps) ) + { + if( dotrace ) + { + ae_trace("> the problem is infeasible (box constraint for variable %0d)\n", + (int)(j)); + } + *problemstatus = -3; + *somethingchanged = ae_true; + result = ae_false; + return result; + } + if( ae_fp_greater(wrkal,prevbndu+eps)||ae_fp_less(wrkau,prevbndl-eps) ) + { + if( dotrace ) + { + ae_trace("> the problem is infeasible (singleton row %0d is incompatible with box constraints for variable %0d)\n", + (int)(i), + (int)(j)); + } + *problemstatus = -3; + *somethingchanged = ae_true; + result = ae_false; + return result; + } + + /* + * Check compatibility with conic constraints + */ + if( ae_isfinite(wrkal, _state)&&vcstats->cntdownwardaxial.ptr.p_int[j]>0 ) + { + + /* + * Constraint enforces lower bound on a downward axial variable (a conically + * constrained variable with cone axis oriented towards -INF), skip. + */ + continue; + } + if( ae_isfinite(wrkau, _state)&&vcstats->cntupwardaxial.ptr.p_int[j]>0 ) + { + + /* + * Constraint enforces lower bound on a downward axial variable (a conically + * constrained variable with cone axis oriented towards -INF), skip. + */ + continue; + } + + /* + * Modify problem, perform constraint harmonization for slightly infeasible box constraints + */ + lowerboundisbc = ae_true; + upperboundisbc = ae_true; + if( ae_isfinite(wrkal, _state)&&ae_fp_greater(wrkal,prevbndl) ) + { + bndl->ptr.p_double[j] = wrkal; + lowerboundisbc = ae_false; + } + if( ae_isfinite(wrkau, _state)&&ae_fp_less(wrkau,prevbndu) ) + { + bndu->ptr.p_double[j] = wrkau; + upperboundisbc = ae_false; + } + if( ae_fp_less(bndu->ptr.p_double[j],bndl->ptr.p_double[j]) ) + { + midpoint = 0.5*(bndu->ptr.p_double[j]+bndl->ptr.p_double[j]); + bndl->ptr.p_double[j] = midpoint; + bndu->ptr.p_double[j] = midpoint; + } + a->rowend.ptr.p_int[i] = a->rowbegin.ptr.p_int[i]; + offs = at->rowbegin.ptr.p_int[j]; + for(ii=at->rowbegin.ptr.p_int[j]; ii<=at->rowend.ptr.p_int[j]-1; ii++) + { + if( at->idx.ptr.p_int[ii]!=i ) + { + at->idx.ptr.p_int[offs] = at->idx.ptr.p_int[ii]; + at->vals.ptr.p_double[offs] = at->vals.ptr.p_double[ii]; + offs = offs+1; + } + } + at->rowend.ptr.p_int[j] = offs; + vcstats->isdroppedlc.ptr.p_bool[i] = ae_true; + *somethingchanged = ae_true; + *cntsingleton = *cntsingleton+1; + lpqppresolve_presolverappendsingletonrow(trfstack, i, j, v, swapsign, bndl->ptr.p_double[j], lowerboundisbc, bndu->ptr.p_double[j], upperboundisbc, _state); + } + } + return result; +} + + +/************************************************************************* +This function scans rows and uses doubleton equality rows to factor out +linear/quadratic variables. + +INPUT PARAMETERS: + BndL, BndU - array[N], box constraints. + VCStats - variable/constr stats + H - if HasH=True, a full symmetric H with both triangles; + diagonal elements are always present, even if zero. + If HasH=False, ignored. + N - variables count (including both fixed and non-fixed) + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + QC - DynCRS-based quadratic constraints + Eps - tolerance used to resolve infeasibilities + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + CntFixed - debug counter, updated by the function + trfStack - sequence of already applied transformations + +OUTPUT PARAMETERS: + VCStats - dropped columns and rows are marked + ProblemStatus- on failure (unboundedness detected) is set to -2, + unchanged otherwise + SomethingChanged-is set to True if at least one col was dropped + It is not changed otherwise. + CntDropped - debug counter, updated by the function + trfStack - updated with new transforms + +RESULT: + if unboundedness was detected, False is returned. + True is returned otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_doubletonrow(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntdoubleton, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k0; + ae_int_t k1; + ae_int_t ii; + ae_int_t cnt; + ae_int_t qcidx; + ae_int_t ccidx; + double v; + double v0; + double v1; + double h00; + double h01; + double h11; + double shift; + double abnd; + double proposedbndl; + double proposedbndu; + ae_int_t proposedactl; + ae_int_t proposedactu; + double oribndl0; + double oribndl1; + double oribndu0; + double oribndu1; + double wrkbndl; + double wrkbndu; + double alpha0; + double alpha1; + ae_int_t bndlactivates; + ae_int_t bnduactivates; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + ae_int_t localk0; + ae_int_t localk1; + ae_bool hadk0; + ae_bool hadk1; + double dummy0; + double dummy1; + ae_int_t addedtok1; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + + result = ae_true; + for(i=0; i<=m-1; i++) + { + if( (((!vcstats->isdroppedlc.ptr.p_bool[i]&&a->rowbegin.ptr.p_int[i]+2==a->rowend.ptr.p_int[i])&&ae_isfinite(al->ptr.p_double[i], _state))&&ae_isfinite(au->ptr.p_double[i], _state))&&ae_fabs(au->ptr.p_double[i]-al->ptr.p_double[i], _state)<=eps ) + { + + /* + * Read doubleton row, perform integrity checks and normalization. + * + * We factor out X[K0] from the problem and retain X[K1]. We arrange equations + * in such a way that |A[i,k0||>=|A[i,k1|| + */ + k0 = a->idx.ptr.p_int[a->rowbegin.ptr.p_int[i]]; + k1 = a->idx.ptr.p_int[a->rowbegin.ptr.p_int[i]+1]; + if( lpqppresolve_isfixed(bndl->ptr.p_double[k0], bndu->ptr.p_double[k0], eps, _state)||lpqppresolve_isfixed(bndl->ptr.p_double[k1], bndu->ptr.p_double[k1], eps, _state) ) + { + + /* + * If at least one of variables is fixed, we skip doubleton transformation. + */ + continue; + } + if( vcstats->cntaxial.ptr.p_int[k0]+vcstats->cntaxial.ptr.p_int[k1]>0 ) + { + + /* + * If at least one of variables is axial for some conic constraint, we skip doubleton transformation + */ + continue; + } + v0 = a->vals.ptr.p_double[a->rowbegin.ptr.p_int[i]]; + v1 = a->vals.ptr.p_double[a->rowbegin.ptr.p_int[i]+1]; + if( ae_fp_eq(v0*v1,(double)(0)) ) + { + continue; + } + ae_assert(!vcstats->isdroppedcol.ptr.p_bool[k0], "PRESOLVER: integrity check 4253 failed", _state); + ae_assert(!vcstats->isdroppedcol.ptr.p_bool[k1], "PRESOLVER: integrity check 4254 failed", _state); + if( ae_fp_less(ae_fabs(v0, _state),ae_fabs(v1, _state)) ) + { + swapi(&k0, &k1, _state); + swapr(&v0, &v1, _state); + } + if( ae_fp_less(ae_fabs(v0, _state),lpqppresolve_smlcoeff) ) + { + + /* + * Row magnitude is too small, do not perform substitution because it may result in + * the loss of numerical stability + */ + continue; + } + abnd = 0.5*(al->ptr.p_double[i]+au->ptr.p_double[i]); + alpha0 = abnd/v0; + alpha1 = -v1/v0; + + /* + * Compute updated bounds on X[K1], for each bound compute variable being activated: + * * 0 means that reduced variable at this bound activates lower bound on X0 + * * 1 means that reduced variable at this bound activates upper bound on X0 + * * 2 means that reduced variable at this bound activates lower bound on X1 + * * 3 means that reduced variable at this bound activates upper bound on X1 + * * -1 denotes absent bound + * + * Check feasibility. + */ + oribndl0 = bndl->ptr.p_double[k0]; + oribndu0 = bndu->ptr.p_double[k0]; + oribndl1 = bndl->ptr.p_double[k1]; + oribndu1 = bndu->ptr.p_double[k1]; + wrkbndl = bndl->ptr.p_double[k1]; + wrkbndu = bndu->ptr.p_double[k1]; + bndlactivates = icase2(ae_isfinite(wrkbndl, _state), lpqppresolve_actlowerboundonk1, lpqppresolve_actnone, _state); + bnduactivates = icase2(ae_isfinite(wrkbndu, _state), lpqppresolve_actupperboundonk1, lpqppresolve_actnone, _state); + proposedactl = lpqppresolve_actnone; + proposedactu = lpqppresolve_actnone; + proposedbndl = 0.0; + proposedbndu = 0.0; + if( ae_fp_greater(v0*v1,(double)(0)) ) + { + if( ae_isfinite(bndu->ptr.p_double[k0], _state) ) + { + proposedbndl = (abnd-v0*bndu->ptr.p_double[k0])/v1; + proposedactl = lpqppresolve_actupperboundonk0; + } + if( ae_isfinite(bndl->ptr.p_double[k0], _state) ) + { + proposedbndu = (abnd-v0*bndl->ptr.p_double[k0])/v1; + proposedactu = lpqppresolve_actlowerboundonk0; + } + } + else + { + if( ae_isfinite(bndl->ptr.p_double[k0], _state) ) + { + proposedbndl = (abnd-v0*bndl->ptr.p_double[k0])/v1; + proposedactl = lpqppresolve_actlowerboundonk0; + } + if( ae_isfinite(bndu->ptr.p_double[k0], _state) ) + { + proposedbndu = (abnd-v0*bndu->ptr.p_double[k0])/v1; + proposedactu = lpqppresolve_actupperboundonk0; + } + } + if( proposedactl!=lpqppresolve_actnone&&proposedbndl>wrkbndl ) + { + wrkbndl = proposedbndl; + bndlactivates = proposedactl; + } + if( proposedactu!=lpqppresolve_actnone&&proposedbndu the problem is infeasible (equality constraint %0d is incompatible with bounds on variable %0d and %0d)\n", + (int)(i), + (int)(k0), + (int)(k1)); + } + *problemstatus = -3; + *somethingchanged = ae_true; + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( ae_fp_greater(wrkbndl,wrkbndu) ) + { + ae_assert(ae_isfinite(wrkbndl, _state)&&ae_isfinite(wrkbndu, _state), "PRESOLVER: integrity check 2124 failed", _state); + v = 0.5*(wrkbndl+wrkbndu); + wrkbndl = v; + wrkbndu = v; + } + + /* + * Modify constraints: + * * issue transformation + * * drop variable K0 + * * drop constraint I + * * factor out variable K0 from all constraints where it is present + * * change bounds for K1 + */ + lpqppresolve_presolverappenddoubletonfactorout(trfstack, vcstats, i, k0, oribndl0, oribndu0, k1, oribndl1, oribndu1, c->ptr.p_double[k0], c->ptr.p_double[k1], sparseh, hash, at, qc, v0, v1, abnd, wrkbndl, wrkbndu, bndlactivates, bnduactivates, _state); + vcstats->isdroppedcol.ptr.p_bool[k0] = ae_true; + vcstats->isdroppedlc.ptr.p_bool[i] = ae_true; + lpqppresolve_dyncrsclearrow(a, i, _state); + lpqppresolve_dyncrsremovefromrow(at, k0, i, _state); + lpqppresolve_dyncrsremovefromrow(at, k1, i, _state); + cnt = 0; + iallocv(at->rowend.ptr.p_int[k0]-at->rowbegin.ptr.p_int[k0], &buf->sparseidx, _state); + rallocv(at->rowend.ptr.p_int[k0]-at->rowbegin.ptr.p_int[k0], &buf->sparsevals, _state); + for(ii=at->rowbegin.ptr.p_int[k0]; ii<=at->rowend.ptr.p_int[k0]-1; ii++) + { + k = at->idx.ptr.p_int[ii]; + lpqppresolve_dyncrsfactoroutfromrow(a, k, k0, alpha0, alpha1, k1, ae_true, &v, &shift, _state); + buf->sparseidx.ptr.p_int[cnt] = k; + buf->sparsevals.ptr.p_double[cnt] = v; + cnt = cnt+1; + if( ae_isfinite(al->ptr.p_double[k], _state) ) + { + al->ptr.p_double[k] = al->ptr.p_double[k]-shift; + } + if( ae_isfinite(au->ptr.p_double[k], _state) ) + { + au->ptr.p_double[k] = au->ptr.p_double[k]-shift; + } + } + lpqppresolve_dyncrsinsertwithrewrite(at, k1, &buf->sparseidx, &buf->sparsevals, cnt, _state); + lpqppresolve_dyncrsclearrow(at, k0, _state); + bndl->ptr.p_double[k1] = wrkbndl; + bndu->ptr.p_double[k1] = wrkbndu; + + /* + * Modify linear term with an update to C[K1] from C[K0] + */ + c->ptr.p_double[k1] = c->ptr.p_double[k1]+c->ptr.p_double[k0]*alpha1; + + /* + * Handle updates coming from the quadratic term, if we have it; clear H. + */ + if( hash ) + { + + /* + * Analyze how 2x2 quadratic [h00 h01 ; h10 h11] changes when we + * substitute x0 := alpha0 + alpha1*x1. + * + * We have + * + * h00*(alpha0+alpha1*x1)^2 + 2*h01*(alpha0+alpha1*x1)*x1 + h11*x1^2 = + * h00*alpha0^2 + 2*h00*alpha0*alpha1*x1 + h00*alpha1^2*x1^2 + 2*h01*alpha0*x1+2*h01*alpha1*x1^2 + h11*x1^2 = + * 2*(h00*alpha0*alpha1+h01*alpha0)*x1 + (h00*alpha1^2+2*h01*alpha1+h11)*x1^2 + */ + h00 = lpqppresolve_dyncrsgetexistingelement(sparseh, k0, k0, _state); + h11 = lpqppresolve_dyncrsgetexistingelement(sparseh, k1, k1, _state); + h01 = lpqppresolve_dyncrsgetelementifexists(sparseh, k0, k1, _state); + + /* + * Handle updates coming from modification of elements of H that are outside of the + * [k0,k1]x[k0,k1] diagonal block. The constant term in X[K0]:=Alpha0+Alpha1*X[K1] + * updates the linear term C[], the linear term Alpha1 updates the matrix H. + * + * The matrix H is updates applied to its column K1, then to its row K1. The row update + * modifies the [k0,k1]x[k0,k1] diagonal block because there is no easy way to do it + * without touching elements that we want to process later. We handle it by saving + * H00, H01, H11 prior to this block and by discarding and rewriting diagonal completely + * after calling DynCRSAddRowTo(). + */ + for(ii=sparseh->rowbegin.ptr.p_int[k0]; ii<=sparseh->rowend.ptr.p_int[k0]-1; ii++) + { + j = sparseh->idx.ptr.p_int[ii]; + if( j!=k0&&j!=k1 ) + { + + /* + * Update C[] and column K1 of H. + */ + v = sparseh->vals.ptr.p_double[ii]; + c->ptr.p_double[j] = c->ptr.p_double[j]+v*alpha0; + lpqppresolve_dyncrsfactoroutfromrow(sparseh, j, k0, 0.0, alpha1, k1, ae_false, &dummy0, &dummy1, _state); + } + } + lpqppresolve_dyncrsaddrowto(sparseh, k0, alpha1, k1, ae_true, ae_false, _state); + lpqppresolve_dyncrsclearrow(sparseh, k0, _state); + lpqppresolve_dyncrsremovefromrow(sparseh, k1, k0, _state); + + /* + * Handle updates coming from substituting X[K0]:=Alpha0+Alpha1*X[K1] to the + * [k0,k1]x[k0,k1] diagonal block. + */ + c->ptr.p_double[k1] = c->ptr.p_double[k1]+(h00*alpha0*alpha1+h01*alpha0); + lpqppresolve_dyncrssetexistingelement(sparseh, k1, k1, h00*alpha1*alpha1+(double)2*h01*alpha1+h11, _state); + } + + /* + * Update quadratic and conic constraints + */ + if( vcstats->nlcpervar.ptr.p_int[k0]+vcstats->nlcpervar.ptr.p_int[k1]>0 ) + { + + /* + * Update quadratic constraints: + * * use VarByQC for quick navigation (no need to enumerate all constraints) + * * pop indexes of constraints referencing K0 from VarByQC + * * save indexes of constraints added to K1 in Buf.tmp0[] (we can't immediately call + * knisAddNewElement because it can invalidate pointers used for direct access) + * * tell VarByQC that memory occupied by the K0-th set can be reclaimed + */ + addedtok1 = 0; + while(kniscountkth(&vcstats->varbyqc, k0, _state)>0) + { + qcidx = knispoplast(&vcstats->varbyqc, k0, _state); + ae_assert(!vcstats->isdroppedqc.ptr.p_bool[qcidx], "PRESOLVER: integrity check 635245 failed", _state); + ae_obj_array_get(&qc->constraints, qcidx, &_qci, _state); + localk0 = -1; + localk1 = -1; + for(j=0; j<=qci->nvars-1; j++) + { + if( qci->varidx.ptr.p_int[j]==k0 ) + { + localk0 = j; + } + if( qci->varidx.ptr.p_int[j]==k1 ) + { + localk1 = j; + } + } + hadk1 = localk1>=0; + if( localk0<0 ) + { + continue; + } + if( localk1<0 ) + { + localk1 = ibinarysearchlft(&qci->varidx, 0, qci->nvars, k1, _state); + if( localk0>=localk1 ) + { + localk0 = localk0+1; + } + lpqppresolve_dynqccopyinsertrowcol(qci, k1, localk1, &buf->qc, _state); + } + else + { + lpqppresolve_dynqccopy(qci, &buf->qc, _state); + } + v = lpqppresolve_factoroutfromquadratic(&buf->qc.fullq, &buf->qc.b, localk0, alpha0, alpha1, localk1, _state); + if( ae_isfinite(buf->qc.cl, _state) ) + { + buf->qc.cl = buf->qc.cl-v; + } + if( ae_isfinite(buf->qc.cu, _state) ) + { + buf->qc.cu = buf->qc.cu-v; + } + lpqppresolve_dynqccopydeleterowcol(&buf->qc, localk0, qci, _state); + vcstats->nlcpervar.ptr.p_int[k0] = vcstats->nlcpervar.ptr.p_int[k0]-1; + if( !hadk1 ) + { + vcstats->nlcpervar.ptr.p_int[k1] = vcstats->nlcpervar.ptr.p_int[k1]+1; + igrowappendv(addedtok1+1, &buf->tmp0, qcidx, _state); + addedtok1 = addedtok1+1; + } + } + for(qcidx=0; qcidx<=addedtok1-1; qcidx++) + { + knisaddnewelement(&vcstats->varbyqc, k1, buf->tmp0.ptr.p_int[qcidx], _state); + } + knisclearkthreclaim(&vcstats->varbyqc, k0, _state); + + /* + * Update conic constraints: + * * use VarByCC for quick navigation (no need to enumerate all constraints) + * * pop indexes of constraints referencing K0 from VarByCC + * * save indexes of constraints added to K1 in Buf.tmp0[] (we can't immediately call + * knisAddNewElement because it can invalidate pointers used for direct access) + * * tell VarByCC that memory occupied by the K0-th set can be reclaimed + */ + addedtok1 = 0; + while(kniscountkth(&vcstats->varbycc, k0, _state)>0) + { + ccidx = knispoplast(&vcstats->varbycc, k0, _state); + ae_assert(!vcstats->isdroppedcc.ptr.p_bool[ccidx], "PRESOLVER: integrity check 4672221 failed", _state); + ae_obj_array_get(&cc->constraints, ccidx, &_cci, _state); + xccfactoroutnonaxial(cci, k0, alpha0, alpha1, k1, &hadk0, &hadk1, _state); + ae_assert(hadk0, "PRESOLVER: integrity check 675222 failed", _state); + vcstats->cntradial.ptr.p_int[k0] = vcstats->cntradial.ptr.p_int[k0]-1; + vcstats->nlcpervar.ptr.p_int[k0] = vcstats->nlcpervar.ptr.p_int[k0]-1; + if( !hadk1 ) + { + vcstats->cntradial.ptr.p_int[k1] = vcstats->cntradial.ptr.p_int[k1]+1; + vcstats->nlcpervar.ptr.p_int[k1] = vcstats->nlcpervar.ptr.p_int[k1]+1; + igrowappendv(addedtok1+1, &buf->tmp0, ccidx, _state); + addedtok1 = addedtok1+1; + } + } + for(ccidx=0; ccidx<=addedtok1-1; ccidx++) + { + knisaddnewelement(&vcstats->varbycc, k1, buf->tmp0.ptr.p_int[ccidx], _state); + } + knisclearkthreclaim(&vcstats->varbycc, k0, _state); + } + + /* + * Done + */ + *somethingchanged = ae_true; + *cntdoubleton = *cntdoubleton+1; + } + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function tries to process singleton cols using various heuristics: +* detect explicit slacks + +INPUT PARAMETERS: + C. BndL, BndU- array[N], cost and box constraints. + IsDroppedCol- array[N], column statuses, used for integrity checks + H - if HasH=True, a full symmetric H with both triangles; + diagonal elements are always present, even if zero. + If HasH=False, ignored. + N - variables count (including both fixed and non-fixed) + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + Eps - tolerance used to resolve infeasibilities + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + CntFixed - debug counter, updated by the function + trfStack - sequence of already applied transformations + +OUTPUT PARAMETERS: + C, BndL, BndU- may be modified + IsDroppedCol- array[N], dropped columns are marked + ProblemStatus- on failure (unboundedness detected) is set to -2, + unchanged otherwise + SomethingChanged-is set to True if at least one col was dropped + It is not changed otherwise. + CntSlackVars- debug counter, updated by the function + trfStack - updated with new transforms + +RESULT: + if infeasibility or unboundedness was detected, False is returned. + True is returned otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_singletoncols(/* Real */ ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntslackvars, + ae_int_t* cntimplicitslacks, + ae_int_t* cntfreecolumnsingletons, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t ii; + double preval; + double prevau; + double prevabnd; + double aij; + double aslk; + double vslk; + double v; + double cj; + ae_bool result; + + + result = ae_true; + if( m==0 ) + { + return result; + } + for(j=0; j<=n-1; j++) + { + + /* + * skip: + * * already dropped columns + * * non-singleton columns + * * columns with non-zero quadratic term + */ + if( vcstats->isdroppedcol.ptr.p_bool[j] ) + { + continue; + } + if( at->rowbegin.ptr.p_int[j]+1!=at->rowend.ptr.p_int[j] ) + { + continue; + } + if( hash&&((sparseh->rowbegin.ptr.p_int[j]+1!=sparseh->rowend.ptr.p_int[j]||sparseh->idx.ptr.p_int[sparseh->rowbegin.ptr.p_int[j]]!=j)||ae_fp_neq(sparseh->vals.ptr.p_double[sparseh->rowbegin.ptr.p_int[j]],0.0)) ) + { + continue; + } + if( vcstats->nlcpervar.ptr.p_int[j]>0 ) + { + continue; + } + + /* + * Proceed + */ + i = at->idx.ptr.p_int[at->rowbegin.ptr.p_int[j]]; + cj = c->ptr.p_double[j]; + aij = at->vals.ptr.p_double[at->rowbegin.ptr.p_int[j]]; + if( ae_fp_less_eq(ae_fabs(aij, _state),lpqppresolve_smlcoeff) ) + { + continue; + } + + /* + * Skip rows with no bounds, at least one bound is expected for the transformations below + */ + if( !(ae_isfinite(al->ptr.p_double[i], _state)||ae_isfinite(au->ptr.p_double[i], _state)) ) + { + continue; + } + + /* + * Is it an explicit slack? + */ + if( ae_fp_less_eq(ae_fabs(cj, _state),eps) ) + { + + /* + * Clear Cj + * Update constraint bounds + * Issue "explicit slack" transformation + */ + c->ptr.p_double[j] = (double)(0); + preval = al->ptr.p_double[i]; + prevau = au->ptr.p_double[i]; + if( ae_fp_greater(aij,(double)(0)) ) + { + if( ae_isfinite(bndl->ptr.p_double[j], _state) ) + { + au->ptr.p_double[i] = au->ptr.p_double[i]-aij*bndl->ptr.p_double[j]; + } + else + { + au->ptr.p_double[i] = _state->v_posinf; + } + if( ae_isfinite(bndu->ptr.p_double[j], _state) ) + { + al->ptr.p_double[i] = al->ptr.p_double[i]-aij*bndu->ptr.p_double[j]; + } + else + { + al->ptr.p_double[i] = _state->v_neginf; + } + } + else + { + if( ae_isfinite(bndu->ptr.p_double[j], _state) ) + { + au->ptr.p_double[i] = au->ptr.p_double[i]-aij*bndu->ptr.p_double[j]; + } + else + { + au->ptr.p_double[i] = _state->v_posinf; + } + if( ae_isfinite(bndl->ptr.p_double[j], _state) ) + { + al->ptr.p_double[i] = al->ptr.p_double[i]-aij*bndl->ptr.p_double[j]; + } + else + { + al->ptr.p_double[i] = _state->v_neginf; + } + } + lpqppresolve_presolverappendexplicitslack(trfstack, i, j, aij, bndl->ptr.p_double[j], bndu->ptr.p_double[j], preval, prevau, a, _state); + + /* + * Remove variable from A and AT + */ + lpqppresolve_dyncrsclearrow(at, j, _state); + lpqppresolve_dyncrsremovefromrow(a, i, j, _state); + vcstats->isdroppedcol.ptr.p_bool[j] = ae_true; + + /* + * Done + */ + *somethingchanged = ae_true; + *cntslackvars = *cntslackvars+1; + continue; + } + + /* + * Is it equality row? The variable can be treated as an implicit slack + */ + if( ((ae_isfinite(al->ptr.p_double[i], _state)&&ae_isfinite(au->ptr.p_double[i], _state))&&ae_fp_less_eq(ae_fabs(al->ptr.p_double[i]-au->ptr.p_double[i], _state),eps))&&ae_fp_greater_eq(ae_fabs(aij, _state)*lpqppresolve_maxcoeffgrowth,ae_fabs(cj, _state)) ) + { + + /* + * Enforce AL=AU, set Cj to zero + */ + prevabnd = 0.5*(al->ptr.p_double[i]+au->ptr.p_double[i]); + al->ptr.p_double[i] = prevabnd; + au->ptr.p_double[i] = prevabnd; + v = cj/aij; + for(ii=a->rowbegin.ptr.p_int[i]; ii<=a->rowend.ptr.p_int[i]-1; ii++) + { + c->ptr.p_double[a->idx.ptr.p_int[ii]] = c->ptr.p_double[a->idx.ptr.p_int[ii]]-v*a->vals.ptr.p_double[ii]; + } + c->ptr.p_double[j] = (double)(0); + + /* + * Update constraint bounds + * Issue "implicit slack" transformation + */ + if( ae_fp_greater(aij,(double)(0)) ) + { + if( ae_isfinite(bndl->ptr.p_double[j], _state) ) + { + au->ptr.p_double[i] = au->ptr.p_double[i]-aij*bndl->ptr.p_double[j]; + } + else + { + au->ptr.p_double[i] = _state->v_posinf; + } + if( ae_isfinite(bndu->ptr.p_double[j], _state) ) + { + al->ptr.p_double[i] = al->ptr.p_double[i]-aij*bndu->ptr.p_double[j]; + } + else + { + al->ptr.p_double[i] = _state->v_neginf; + } + } + else + { + if( ae_isfinite(bndu->ptr.p_double[j], _state) ) + { + au->ptr.p_double[i] = au->ptr.p_double[i]-aij*bndu->ptr.p_double[j]; + } + else + { + au->ptr.p_double[i] = _state->v_posinf; + } + if( ae_isfinite(bndl->ptr.p_double[j], _state) ) + { + al->ptr.p_double[i] = al->ptr.p_double[i]-aij*bndl->ptr.p_double[j]; + } + else + { + al->ptr.p_double[i] = _state->v_neginf; + } + } + lpqppresolve_presolverappendimplicitslack(trfstack, i, j, aij, cj, prevabnd, a, _state); + + /* + * Remove variable from A and AT, set Cj to zero + */ + lpqppresolve_dyncrsclearrow(at, j, _state); + lpqppresolve_dyncrsremovefromrow(a, i, j, _state); + vcstats->isdroppedcol.ptr.p_bool[j] = ae_true; + + /* + * Done + */ + *somethingchanged = ae_true; + *cntimplicitslacks = *cntimplicitslacks+1; + continue; + } + + /* + * Is it a free column singleton? + */ + if( (!ae_isfinite(bndl->ptr.p_double[j], _state)&&!ae_isfinite(bndu->ptr.p_double[j], _state))&&ae_fp_greater_eq(ae_fabs(aij, _state)*lpqppresolve_maxcoeffgrowth,ae_fabs(cj, _state)) ) + { + + /* + * Handle single-sided linear constraints or two-sided one. + * + * A general inequality/range constraint is converted to an equality one by + * adding temporary slack variable SLK. This variable is not actually added + * to the problem - we analytically remove it right after the addition. + * + * See 3.2.2 from "A modular presolve procedure for large scale linear programming" + * by Swietanowski for more information + */ + if( !ae_isfinite(al->ptr.p_double[i], _state)||!ae_isfinite(au->ptr.p_double[i], _state) ) + { + + /* + * Single-sided constraint + * + * Determine multiplier for the artificial temporary slack variable S. + * Check for unboundedness. If bounded, the slack S is zero, right-hand + * side of the equality constraint is not modified. + */ + aslk = rcase2(ae_isfinite(au->ptr.p_double[i], _state), (double)(1), (double)(-1), _state); + if( ae_fp_greater(aslk*cj/aij,eps) ) + { + if( dotrace ) + { + ae_trace("> the problem is unbounded (deduced from free column singleton analysis for variable %0d, row %0d)\n", + (int)(j), + (int)(i)); + } + *problemstatus = -2; + *somethingchanged = ae_true; + result = ae_false; + return result; + } + vslk = (double)(0); + if( !ae_isfinite(au->ptr.p_double[i], _state) ) + { + au->ptr.p_double[i] = al->ptr.p_double[i]; + } + } + else + { + + /* + * Two-sided constraint + * + * Determine value of the temporary slack variable, modify right-hand side + * of the constraint. + */ + vslk = rcase2(ae_fp_greater(cj/aij,(double)(0)), au->ptr.p_double[i]-al->ptr.p_double[i], 0.0, _state); + } + v = cj/aij; + for(ii=a->rowbegin.ptr.p_int[i]; ii<=a->rowend.ptr.p_int[i]-1; ii++) + { + c->ptr.p_double[a->idx.ptr.p_int[ii]] = c->ptr.p_double[a->idx.ptr.p_int[ii]]-v*a->vals.ptr.p_double[ii]; + } + c->ptr.p_double[j] = (double)(0); + lpqppresolve_presolverappendimplicitslack(trfstack, i, j, aij, cj, au->ptr.p_double[i]-vslk, a, _state); + al->ptr.p_double[i] = _state->v_neginf; + au->ptr.p_double[i] = _state->v_posinf; + lpqppresolve_dyncrsclearrow(at, j, _state); + lpqppresolve_dyncrsremovefromrow(a, i, j, _state); + vcstats->isdroppedcol.ptr.p_bool[j] = ae_true; + *cntfreecolumnsingletons = *cntfreecolumnsingletons+1; + continue; + } + } + return result; +} + + +/************************************************************************* +This function scans box constraints list and tries to fix variables by +removing them from the A and AT matrices and by recording transformation +in trfStack. + +If infeasibility is detected, returns False. + +INPUT PARAMETERS: + BndL, BndU - array[N], current set of box constraints. Only entries + with IsDroppedCol[]=False are examined. Entries corresponding + to fixed variables are forced to be equal. + VCStats - variable/constr stats + H - if HasH=True, a full symmetric H with both triangles; + diagonal elements are always present, even if zero. + If HasH=False, ignored. + N - variables count (including both fixed and non-fixed) + A, AT - current A and AT, dynamic CRS matrices + AL, AU - array[M], lower/upper bounds for linear constraints + M - linear constraints count + Eps - tolerance to resolve slightly infeasible constraints + DoTrace - whether tracing is needed or not + SomethingChanged-flag variable + CntFixed - debug counter, updated by the function + +OUTPUT PARAMETERS: + VCStats - fixed vars are marked + A - columns corresponding to fixed vars are removed from A. + The matrix size does not change. + AT - rows corresponding to fixed vars are removed from A. + The matrix size does not change. + AL, AU - updated with fixed values + SomethingChanged-is set to True if at least one variable was fixed. + It is not changed otherwise. + CntFixed - debug counter, updated by the function + +RESULT: + if infeasibility is detected, returns False. + True otherwise. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static ae_bool lpqppresolve_fixvariables(/* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + presolvervcstats* vcstats, + dynamiccrs* sparseh, + ae_bool hash, + ae_int_t n, + dynamiccrs* a, + dynamiccrs* at, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + dynamiccrsqconstraints* qc, + xconicconstraints* cc, + double eps, + ae_bool dotrace, + presolvebuffers* buf, + presolverstack* trfstack, + ae_int_t* problemstatus, + ae_bool* somethingchanged, + ae_int_t* cntfixed, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t ii; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + ae_int_t offs; + double v; + double vfixed; + ae_int_t qcidx; + ae_int_t qccnt; + ae_int_t ccidx; + dynamiccrsqconstraint *qci; + ae_smart_ptr _qci; + xconicconstraint *cci; + ae_smart_ptr _cci; + ae_bool hadk0; + ae_bool hadk1; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&_qci, 0, sizeof(_qci)); + memset(&_cci, 0, sizeof(_cci)); + ae_smart_ptr_init(&_qci, (void**)&qci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + + result = ae_true; + qccnt = ae_obj_array_get_length(&qc->constraints); + + /* + * Scan variables, determine rows to update + */ + nisclear(&buf->setn, _state); + nisclear(&buf->setm, _state); + if( hash ) + { + nisclear(&buf->setn2, _state); + } + for(i=0; i<=n-1; i++) + { + if( !vcstats->isdroppedcol.ptr.p_bool[i]&&lpqppresolve_isfixed(bndl->ptr.p_double[i], bndu->ptr.p_double[i], eps, _state) ) + { + + /* + * Detect infeasibility + */ + if( ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i]+eps) ) + { + *somethingchanged = ae_true; + *problemstatus = -3; + result = ae_false; + ae_frame_leave(_state); + return result; + } + + /* + * Ignore axial variables + */ + if( vcstats->cntaxial.ptr.p_int[i]>0 ) + { + continue; + } + + /* + * Fix variable and issue transformation + */ + vfixed = boundval(0.5*(bndl->ptr.p_double[i]+bndu->ptr.p_double[i]), bndl->ptr.p_double[i], bndu->ptr.p_double[i], _state); + *somethingchanged = ae_true; + *cntfixed = *cntfixed+1; + bndl->ptr.p_double[i] = vfixed; + bndu->ptr.p_double[i] = vfixed; + lpqppresolve_presolverappendfixedvar(trfstack, i, vfixed, c->ptr.p_double[i], sparseh, vcstats, hash, at, m!=0, qc, _state); + vcstats->isdroppedcol.ptr.p_bool[i] = ae_true; + + /* + * Modify linear term due to modification of a quadratic one, save rows of H that contain I-th variable for further cleaning at the end + */ + if( hash ) + { + j0 = sparseh->rowbegin.ptr.p_int[i]; + j1 = sparseh->rowend.ptr.p_int[i]-1; + for(jj=j0; jj<=j1; jj++) + { + j = sparseh->idx.ptr.p_int[jj]; + if( vcstats->isdroppedcol.ptr.p_bool[j] ) + { + continue; + } + c->ptr.p_double[j] = c->ptr.p_double[j]+vfixed*sparseh->vals.ptr.p_double[jj]; + nisaddelement(&buf->setn2, j, _state); + } + } + + /* + * Save dependent linear constraints to SetM + */ + nisaddelement(&buf->setn, i, _state); + if( m!=0 ) + { + for(jj=at->rowbegin.ptr.p_int[i]; jj<=at->rowend.ptr.p_int[i]-1; jj++) + { + nisaddelement(&buf->setm, at->idx.ptr.p_int[jj], _state); + } + } + + /* + * Modify quadratic constraints + */ + while(kniscountkth(&vcstats->varbyqc, i, _state)>0) + { + qcidx = knispoplast(&vcstats->varbyqc, i, _state); + ae_assert(!vcstats->isdroppedqc.ptr.p_bool[qcidx], "PRESOLVER: integrity check 148217 failed", _state); + ae_obj_array_get(&qc->constraints, qcidx, &_qci, _state); + k = ibinarysearchlft(&qci->varidx, 0, qci->nvars, i, _state); + ae_assert(knvars&&qci->varidx.ptr.p_int[k]==i, "PRESOLVER: integrity check 151219 failed", _state); + vcstats->nlcpervar.ptr.p_int[i] = vcstats->nlcpervar.ptr.p_int[i]-1; + v = lpqppresolve_fixquadraticvariable(&qci->fullq, &qci->b, k, vfixed, _state); + if( ae_isfinite(qci->cl, _state) ) + { + qci->cl = qci->cl-v; + } + if( ae_isfinite(qci->cu, _state) ) + { + qci->cu = qci->cu-v; + } + } + knisclearkthreclaim(&vcstats->varbyqc, i, _state); + + /* + * Modify conic constraints + */ + while(kniscountkth(&vcstats->varbycc, i, _state)>0) + { + ccidx = knispoplast(&vcstats->varbycc, i, _state); + ae_assert(!vcstats->isdroppedcc.ptr.p_bool[ccidx], "PRESOLVER: integrity check 166221 failed", _state); + ae_obj_array_get(&cc->constraints, ccidx, &_cci, _state); + xccfactoroutnonaxial(cci, i, vfixed, 0.0, -1, &hadk0, &hadk1, _state); + ae_assert(hadk0, "PRESOLVER: integrity check 169221 failed", _state); + vcstats->cntradial.ptr.p_int[i] = vcstats->cntradial.ptr.p_int[i]-1; + vcstats->nlcpervar.ptr.p_int[i] = vcstats->nlcpervar.ptr.p_int[i]-1; + } + knisclearkthreclaim(&vcstats->varbycc, i, _state); + } + } + if( !*somethingchanged ) + { + ae_frame_leave(_state); + return result; + } + + /* + * If linear constraints are present, clear them + */ + if( m>0 ) + { + + /* + * Clear columns of AT corresponding to fixed variables + */ + for(jj=0; jj<=buf->setn.nstored-1; jj++) + { + i = buf->setn.items.ptr.p_int[jj]; + lpqppresolve_dyncrsclearrow(at, i, _state); + } + + /* + * Scan marked rows of A and remove fixed variables + */ + for(ii=0; ii<=buf->setm.nstored-1; ii++) + { + i = buf->setm.items.ptr.p_int[ii]; + offs = a->rowbegin.ptr.p_int[i]; + v = (double)(0); + for(jj=a->rowbegin.ptr.p_int[i]; jj<=a->rowend.ptr.p_int[i]-1; jj++) + { + j = a->idx.ptr.p_int[jj]; + if( buf->setn.locationof.ptr.p_int[j]>=0 ) + { + + /* + * Update constraint bounds with fixed variables, remove from linear constraint + */ + v = v+bndl->ptr.p_double[j]*a->vals.ptr.p_double[jj]; + } + else + { + + /* + * Non-fixed variable, retain it + */ + a->idx.ptr.p_int[offs] = j; + a->vals.ptr.p_double[offs] = a->vals.ptr.p_double[jj]; + offs = offs+1; + } + } + a->rowend.ptr.p_int[i] = offs; + if( ae_isfinite(al->ptr.p_double[i], _state) ) + { + al->ptr.p_double[i] = al->ptr.p_double[i]-v; + } + if( ae_isfinite(au->ptr.p_double[i], _state) ) + { + au->ptr.p_double[i] = au->ptr.p_double[i]-v; + } + } + } + + /* + * Clear flagged rows/columns of SparseH + */ + if( hash ) + { + for(ii=0; ii<=buf->setn.nstored-1; ii++) + { + sparseh->rowend.ptr.p_int[buf->setn.items.ptr.p_int[ii]] = sparseh->rowbegin.ptr.p_int[buf->setn.items.ptr.p_int[ii]]; + } + for(jj=0; jj<=buf->setn2.nstored-1; jj++) + { + lpqppresolve_dyncrsremovesetfromrow(sparseh, buf->setn2.items.ptr.p_int[jj], &buf->setn, _state); + } + } + + /* + * Clear quadratic constraints + */ + for(qcidx=0; qcidx<=qccnt-1; qcidx++) + { + if( vcstats->isdroppedqc.ptr.p_bool[qcidx] ) + { + continue; + } + ae_obj_array_get(&qc->constraints, qcidx, &_qci, _state); + nisclear(&buf->setn3, _state); + for(j=0; j<=qci->nvars-1; j++) + { + if( buf->setn.locationof.ptr.p_int[qci->varidx.ptr.p_int[j]]>=0 ) + { + nisaddelement(&buf->setn3, j, _state); + } + } + if( buf->setn3.nstored==0 ) + { + continue; + } + lpqppresolve_dynqccopy(qci, &buf->qc, _state); + igrowv(buf->qc.nvars, &buf->tmp0, _state); + lpqppresolve_dynqccopydeleterowscols(&buf->qc, &buf->setn3, qci, &buf->tmp0, _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Scale cost vector and constraints, normalize cost. + + -- ALGLIB -- + Copyright 01.07.2022 by Bochkanov Sergey +*************************************************************************/ +static void lpqppresolve_scaleshiftobjectiveandconstraints(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + /* Real */ ae_vector* c, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + sparsematrix* sparseh, + ae_bool hash, + sparsematrix* sparsea, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + presolverstack* trfstack, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t nv; + double objscale; + double v; + double vv; + double vshift; + double rowscale; + double qcscale; + double ccscale; + double maxscale; + ae_int_t mqc; + ae_int_t mcc; + xquadraticconstraint *xqci; + ae_smart_ptr _xqci; + xconicconstraint *cci; + ae_smart_ptr _cci; + ae_vector bufs; + ae_vector bufori; + ae_vector bufqx; + ae_bool done; + + ae_frame_make(_state, &_frame_block); + memset(&_xqci, 0, sizeof(_xqci)); + memset(&_cci, 0, sizeof(_cci)); + memset(&bufs, 0, sizeof(bufs)); + memset(&bufori, 0, sizeof(bufori)); + memset(&bufqx, 0, sizeof(bufqx)); + ae_smart_ptr_init(&_xqci, (void**)&xqci, ae_false, _state, ae_true); + ae_smart_ptr_init(&_cci, (void**)&cci, ae_false, _state, ae_true); + ae_vector_init(&bufs, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bufori, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bufqx, 0, DT_REAL, _state, ae_true); + + mqc = xqcgetcount(xqc, _state); + mcc = xccgetcount(xcc, _state); + + /* + * Apply scaling to linear/quadratic term, determine additional scaling due to normalization + */ + objscale = (double)(0); + for(i=0; i<=n-1; i++) + { + c->ptr.p_double[i] = c->ptr.p_double[i]*s->ptr.p_double[i]; + objscale = ae_maxreal(objscale, ae_fabs(c->ptr.p_double[i], _state), _state); + } + if( hash ) + { + for(i=0; i<=n-1; i++) + { + j0 = sparseh->ridx.ptr.p_int[i]; + j1 = sparseh->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + sparseh->vals.ptr.p_double[jj] = sparseh->vals.ptr.p_double[jj]*s->ptr.p_double[i]*s->ptr.p_double[sparseh->idx.ptr.p_int[jj]]; + objscale = ae_maxreal(objscale, ae_fabs(sparseh->vals.ptr.p_double[jj], _state), _state); + } + } + } + objscale = coalesce(objscale, (double)(1), _state); + rmulv(n, (double)1/objscale, c, _state); + if( hash ) + { + rmulv(sparseh->ridx.ptr.p_int[n], (double)1/objscale, &sparseh->vals, _state); + } + lpqppresolve_presolverappendcostscaling(trfstack, (double)1/objscale, _state); + + /* + * Apply column scaling/shifting to box constraints + */ + for(i=0; i<=n-1; i++) + { + + /* + * Transform problem + */ + lpqppresolve_presolverappendcolshifting(trfstack, i, -xorigin->ptr.p_double[i], _state); + lpqppresolve_presolverappendcolscaling(trfstack, i, (double)1/s->ptr.p_double[i], _state); + bndl->ptr.p_double[i] = (bndl->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + bndu->ptr.p_double[i] = (bndu->ptr.p_double[i]-xorigin->ptr.p_double[i])/s->ptr.p_double[i]; + } + + /* + * Process linear constraints + */ + maxscale = (double)(0); + for(i=0; i<=m-1; i++) + { + rowscale = (double)(0); + vshift = (double)(0); + j0 = sparsea->ridx.ptr.p_int[i]; + j1 = sparsea->ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + vshift = vshift+sparsea->vals.ptr.p_double[j]*xorigin->ptr.p_double[sparsea->idx.ptr.p_int[j]]; + v = s->ptr.p_double[sparsea->idx.ptr.p_int[j]]*sparsea->vals.ptr.p_double[j]; + sparsea->vals.ptr.p_double[j] = v; + rowscale = ae_maxreal(rowscale, ae_fabs(v, _state), _state); + } + al->ptr.p_double[i] = al->ptr.p_double[i]-vshift; + au->ptr.p_double[i] = au->ptr.p_double[i]-vshift; + maxscale = ae_maxreal(maxscale, rowscale, _state); + rowscale = ae_maxreal(rowscale, 1.0, _state); + + /* + * Apply transformation to A/AL/AU + */ + v = (double)1/rowscale; + for(j=j0; j<=j1; j++) + { + sparsea->vals.ptr.p_double[j] = v*sparsea->vals.ptr.p_double[j]; + } + al->ptr.p_double[i] = al->ptr.p_double[i]*v; + au->ptr.p_double[i] = au->ptr.p_double[i]*v; + lpqppresolve_presolverappendrowscaling(trfstack, i, (double)1/rowscale, _state); + } + + /* + * Process quadratic constraints + */ + maxscale = (double)(0); + for(i=0; i<=mqc-1; i++) + { + ae_obj_array_get(&xqc->constraints, i, &_xqci, _state); + nv = xqci->nvars; + if( nv==0 ) + { + continue; + } + rgrowv(nv, &bufs, _state); + rgrowv(nv, &bufori, _state); + for(j=0; j<=nv-1; j++) + { + bufs.ptr.p_double[j] = s->ptr.p_double[xqci->varidx.ptr.p_int[j]]; + bufori.ptr.p_double[j] = xorigin->ptr.p_double[xqci->varidx.ptr.p_int[j]]; + } + + /* + * First, apply origin: + * + * x := (x-ori) + ori + * b'(x+ori) + 0.5(x+ori)'Q(x+ori) = + * = b'x + b'ori + 0.5*[ x'Qx + 2*ori'Qx + ori'*Q*ori ] + * = (b+Q*ori)'x + 0.5*x'Qx + [b'ori + 0.5*ori'*Q*ori] + */ + if( !xqci->applyorigin ) + { + rallocv(nv, &bufqx, _state); + sparsesmv(&xqci->lowerq, ae_false, &bufori, &bufqx, _state); + vshift = rdotv(nv, &xqci->b, &bufori, _state)+0.5*rdotv(nv, &bufori, &bufqx, _state); + xqci->cl = xqci->cl-vshift; + xqci->cu = xqci->cu-vshift; + raddv(nv, 1.0, &bufqx, &xqci->b, _state); + } + + /* + * Second, apply column scales and normalization + */ + qcscale = (double)(0); + for(j=0; j<=nv-1; j++) + { + v = xqci->b.ptr.p_double[j]*bufs.ptr.p_double[j]; + xqci->b.ptr.p_double[j] = v; + qcscale = ae_maxreal(qcscale, ae_fabs(v, _state), _state); + j0 = xqci->lowerq.ridx.ptr.p_int[j]; + j1 = xqci->lowerq.ridx.ptr.p_int[j+1]-1; + for(jj=j0; jj<=j1; jj++) + { + v = bufs.ptr.p_double[j]*xqci->lowerq.vals.ptr.p_double[jj]*bufs.ptr.p_double[xqci->lowerq.idx.ptr.p_int[jj]]; + xqci->lowerq.vals.ptr.p_double[jj] = v; + qcscale = ae_maxreal(qcscale, ae_fabs(v, _state), _state); + } + } + maxscale = ae_maxreal(maxscale, qcscale, _state); + qcscale = ae_maxreal(qcscale, (double)(1), _state); + if( ae_fp_greater(qcscale,(double)(1)) ) + { + v = (double)1/qcscale; + rmulv(nv, v, &xqci->b, _state); + rmulv(xqci->lowerq.ridx.ptr.p_int[nv], v, &xqci->lowerq.vals, _state); + xqci->cl = xqci->cl*v; + xqci->cu = xqci->cu*v; + lpqppresolve_presolverappendqcscaling(trfstack, i, (double)1/qcscale, _state); + } + } + + /* + * Process conic constraints + */ + maxscale = (double)(0); + for(i=0; i<=mcc-1; i++) + { + ae_obj_array_get(&xcc->constraints, i, &_cci, _state); + ae_assert(cci->conetype>=0, "PRESOLVER: unexpected constraint type (non-canonic)", _state); + nv = cci->nvars; + if( nv==0 ) + { + continue; + } + rgrowv(nv, &bufs, _state); + rgrowv(nv, &bufori, _state); + for(j=0; j<=nv-1; j++) + { + bufs.ptr.p_double[j] = s->ptr.p_double[cci->varidx.ptr.p_int[j]]; + bufori.ptr.p_double[j] = xorigin->ptr.p_double[cci->varidx.ptr.p_int[j]]; + } + + /* + * First, handle origin, if origin is not included into the constraint + */ + if( !cci->applyorigin ) + { + for(j=0; j<=nv-1; j++) + { + cci->shftc.ptr.p_double[j] = cci->shftc.ptr.p_double[j]+bufori.ptr.p_double[j]*cci->diaga.ptr.p_double[j]; + } + } + + /* + * Second, apply column scales and normalization + */ + done = ae_false; + if( cci->conetype==xccprimitiveconetype(_state) ) + { + ccscale = (double)(0); + for(j=0; j<=nv-1; j++) + { + v = cci->diaga.ptr.p_double[j]*bufs.ptr.p_double[j]; + cci->diaga.ptr.p_double[j] = v; + ccscale = ae_maxreal(ccscale, ae_fabs(v, _state), _state); + } + maxscale = ae_maxreal(maxscale, ccscale, _state); + ccscale = ae_maxreal(ccscale, (double)(1), _state); + if( ae_fp_greater(ccscale,(double)(1)) ) + { + v = (double)1/ccscale; + rmulv(nv, v, &cci->diaga, _state); + rmulv(nv, v, &cci->shftc, _state); + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]*v*v; + lpqppresolve_presolverappendccscaling(trfstack, i, (double)1/ccscale, _state); + } + done = ae_true; + } + if( cci->conetype==xccprimitivepowerconetype(_state) ) + { + v = (double)(1); + for(j=nv-cci->kpow; j<=nv-1; j++) + { + vv = coalesce(rmaxabs2(cci->diaga.ptr.p_double[j]*bufs.ptr.p_double[j], cci->shftc.ptr.p_double[j], _state), (double)(1), _state); + v = v*ae_pow(vv, cci->alphapow.ptr.p_double[j-(nv-cci->kpow)], _state); + cci->diaga.ptr.p_double[j] = cci->diaga.ptr.p_double[j]*bufs.ptr.p_double[j]/vv; + cci->shftc.ptr.p_double[j] = cci->shftc.ptr.p_double[j]/vv; + } + ccscale = v; + maxscale = ae_maxreal(maxscale, ccscale, _state); + rmergemulv(nv-cci->kpow, &bufs, &cci->diaga, _state); + rmulv(nv-cci->kpow, (double)1/ccscale, &cci->diaga, _state); + rmulv(nv-cci->kpow, (double)1/ccscale, &cci->shftc, _state); + cci->shftc.ptr.p_double[nv] = cci->shftc.ptr.p_double[nv]/ae_sqr(ccscale, _state); + lpqppresolve_presolverappendccscaling(trfstack, i, (double)1/ccscale, _state); + done = ae_true; + } + ae_assert(done, "PRESOLVER: integrity check 707240 failed", _state); + } + ae_frame_leave(_state); +} + + +void _dynamiccrs_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrs *p = (dynamiccrs*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rowbegin, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rowend, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vals, 0, DT_REAL, _state, make_automatic); +} + + +void _dynamiccrs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrs *dst = (dynamiccrs*)_dst; + const dynamiccrs *src = (const dynamiccrs*)_src; + dst->m = src->m; + dst->n = src->n; + dst->maxallocated = src->maxallocated; + ae_vector_init_copy(&dst->rowbegin, &src->rowbegin, _state, make_automatic); + ae_vector_init_copy(&dst->rowend, &src->rowend, _state, make_automatic); + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->vals, &src->vals, _state, make_automatic); +} + + +void _dynamiccrs_clear(void* _p) +{ + dynamiccrs *p = (dynamiccrs*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rowbegin); + ae_vector_clear(&p->rowend); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->vals); +} + + +void _dynamiccrs_destroy(void* _p) +{ + dynamiccrs *p = (dynamiccrs*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rowbegin); + ae_vector_destroy(&p->rowend); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->vals); +} + + +void _dynamiccrsqconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrsqconstraint *p = (dynamiccrsqconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->varidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + _dynamiccrs_init(&p->fullq, _state, make_automatic); +} + + +void _dynamiccrsqconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrsqconstraint *dst = (dynamiccrsqconstraint*)_dst; + const dynamiccrsqconstraint *src = (const dynamiccrsqconstraint*)_src; + dst->nvars = src->nvars; + ae_vector_init_copy(&dst->varidx, &src->varidx, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + _dynamiccrs_init_copy(&dst->fullq, &src->fullq, _state, make_automatic); + dst->cl = src->cl; + dst->cu = src->cu; + dst->applyorigin = src->applyorigin; +} + + +void _dynamiccrsqconstraint_clear(void* _p) +{ + dynamiccrsqconstraint *p = (dynamiccrsqconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->varidx); + ae_vector_clear(&p->b); + _dynamiccrs_clear(&p->fullq); +} + + +void _dynamiccrsqconstraint_destroy(void* _p) +{ + dynamiccrsqconstraint *p = (dynamiccrsqconstraint*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->varidx); + ae_vector_destroy(&p->b); + _dynamiccrs_destroy(&p->fullq); +} + + +void _dynamiccrsqconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrsqconstraints *p = (dynamiccrsqconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_init(&p->constraints, _state, make_automatic); +} + + +void _dynamiccrsqconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dynamiccrsqconstraints *dst = (dynamiccrsqconstraints*)_dst; + const dynamiccrsqconstraints *src = (const dynamiccrsqconstraints*)_src; + ae_obj_array_init_copy(&dst->constraints, &src->constraints, _state, make_automatic); +} + + +void _dynamiccrsqconstraints_clear(void* _p) +{ + dynamiccrsqconstraints *p = (dynamiccrsqconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_clear(&p->constraints); +} + + +void _dynamiccrsqconstraints_destroy(void* _p) +{ + dynamiccrsqconstraints *p = (dynamiccrsqconstraints*)_p; + ae_touch_ptr((void*)p); + ae_obj_array_destroy(&p->constraints); +} + + +void _presolvebuffers_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + presolvebuffers *p = (presolvebuffers*)_p; + ae_touch_ptr((void*)p); + _niset_init(&p->setn, _state, make_automatic); + _niset_init(&p->setn2, _state, make_automatic); + _niset_init(&p->setn3, _state, make_automatic); + _niset_init(&p->setm, _state, make_automatic); + ae_vector_init(&p->sparseidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparsevals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fixedlocal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_INT, _state, make_automatic); + _dynamiccrsqconstraint_init(&p->qc, _state, make_automatic); +} + + +void _presolvebuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + presolvebuffers *dst = (presolvebuffers*)_dst; + const presolvebuffers *src = (const presolvebuffers*)_src; + _niset_init_copy(&dst->setn, &src->setn, _state, make_automatic); + _niset_init_copy(&dst->setn2, &src->setn2, _state, make_automatic); + _niset_init_copy(&dst->setn3, &src->setn3, _state, make_automatic); + _niset_init_copy(&dst->setm, &src->setm, _state, make_automatic); + ae_vector_init_copy(&dst->sparseidx, &src->sparseidx, _state, make_automatic); + ae_vector_init_copy(&dst->sparsevals, &src->sparsevals, _state, make_automatic); + ae_vector_init_copy(&dst->fixedlocal, &src->fixedlocal, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + _dynamiccrsqconstraint_init_copy(&dst->qc, &src->qc, _state, make_automatic); +} + + +void _presolvebuffers_clear(void* _p) +{ + presolvebuffers *p = (presolvebuffers*)_p; + ae_touch_ptr((void*)p); + _niset_clear(&p->setn); + _niset_clear(&p->setn2); + _niset_clear(&p->setn3); + _niset_clear(&p->setm); + ae_vector_clear(&p->sparseidx); + ae_vector_clear(&p->sparsevals); + ae_vector_clear(&p->fixedlocal); + ae_vector_clear(&p->tmp0); + _dynamiccrsqconstraint_clear(&p->qc); +} + + +void _presolvebuffers_destroy(void* _p) +{ + presolvebuffers *p = (presolvebuffers*)_p; + ae_touch_ptr((void*)p); + _niset_destroy(&p->setn); + _niset_destroy(&p->setn2); + _niset_destroy(&p->setn3); + _niset_destroy(&p->setm); + ae_vector_destroy(&p->sparseidx); + ae_vector_destroy(&p->sparsevals); + ae_vector_destroy(&p->fixedlocal); + ae_vector_destroy(&p->tmp0); + _dynamiccrsqconstraint_destroy(&p->qc); +} + + +void _presolverstack_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + presolverstack *p = (presolverstack*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->trftype, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->idata, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rdata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idataridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->rdataridx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparseidx0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparseidx1, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparseidx2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparseidx3, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->sparseval0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sparseval1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sparseval2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sparseval3, 0, DT_REAL, _state, make_automatic); +} + + +void _presolverstack_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + presolverstack *dst = (presolverstack*)_dst; + const presolverstack *src = (const presolverstack*)_src; + dst->n = src->n; + dst->m = src->m; + dst->mqc = src->mqc; + dst->mcc = src->mcc; + dst->ntrf = src->ntrf; + ae_vector_init_copy(&dst->trftype, &src->trftype, _state, make_automatic); + ae_vector_init_copy(&dst->idata, &src->idata, _state, make_automatic); + ae_vector_init_copy(&dst->rdata, &src->rdata, _state, make_automatic); + ae_vector_init_copy(&dst->idataridx, &src->idataridx, _state, make_automatic); + ae_vector_init_copy(&dst->rdataridx, &src->rdataridx, _state, make_automatic); + dst->sourceidx = src->sourceidx; + dst->isrc = src->isrc; + dst->rsrc = src->rsrc; + ae_vector_init_copy(&dst->sparseidx0, &src->sparseidx0, _state, make_automatic); + ae_vector_init_copy(&dst->sparseidx1, &src->sparseidx1, _state, make_automatic); + ae_vector_init_copy(&dst->sparseidx2, &src->sparseidx2, _state, make_automatic); + ae_vector_init_copy(&dst->sparseidx3, &src->sparseidx3, _state, make_automatic); + ae_vector_init_copy(&dst->sparseval0, &src->sparseval0, _state, make_automatic); + ae_vector_init_copy(&dst->sparseval1, &src->sparseval1, _state, make_automatic); + ae_vector_init_copy(&dst->sparseval2, &src->sparseval2, _state, make_automatic); + ae_vector_init_copy(&dst->sparseval3, &src->sparseval3, _state, make_automatic); +} + + +void _presolverstack_clear(void* _p) +{ + presolverstack *p = (presolverstack*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->trftype); + ae_vector_clear(&p->idata); + ae_vector_clear(&p->rdata); + ae_vector_clear(&p->idataridx); + ae_vector_clear(&p->rdataridx); + ae_vector_clear(&p->sparseidx0); + ae_vector_clear(&p->sparseidx1); + ae_vector_clear(&p->sparseidx2); + ae_vector_clear(&p->sparseidx3); + ae_vector_clear(&p->sparseval0); + ae_vector_clear(&p->sparseval1); + ae_vector_clear(&p->sparseval2); + ae_vector_clear(&p->sparseval3); +} + + +void _presolverstack_destroy(void* _p) +{ + presolverstack *p = (presolverstack*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->trftype); + ae_vector_destroy(&p->idata); + ae_vector_destroy(&p->rdata); + ae_vector_destroy(&p->idataridx); + ae_vector_destroy(&p->rdataridx); + ae_vector_destroy(&p->sparseidx0); + ae_vector_destroy(&p->sparseidx1); + ae_vector_destroy(&p->sparseidx2); + ae_vector_destroy(&p->sparseidx3); + ae_vector_destroy(&p->sparseval0); + ae_vector_destroy(&p->sparseval1); + ae_vector_destroy(&p->sparseval2); + ae_vector_destroy(&p->sparseval3); +} + + +void _presolvervcstats_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + presolvervcstats *p = (presolvervcstats*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->isdroppedcol, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isdroppedlc, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isdroppedqc, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->isdroppedcc, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->cntdownwardaxial, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->cntupwardaxial, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->cntaxial, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->cntradial, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nlcpervar, 0, DT_INT, _state, make_automatic); + _kniset_init(&p->varbyqc, _state, make_automatic); + _kniset_init(&p->varbycc, _state, make_automatic); +} + + +void _presolvervcstats_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + presolvervcstats *dst = (presolvervcstats*)_dst; + const presolvervcstats *src = (const presolvervcstats*)_src; + ae_vector_init_copy(&dst->isdroppedcol, &src->isdroppedcol, _state, make_automatic); + ae_vector_init_copy(&dst->isdroppedlc, &src->isdroppedlc, _state, make_automatic); + ae_vector_init_copy(&dst->isdroppedqc, &src->isdroppedqc, _state, make_automatic); + ae_vector_init_copy(&dst->isdroppedcc, &src->isdroppedcc, _state, make_automatic); + ae_vector_init_copy(&dst->cntdownwardaxial, &src->cntdownwardaxial, _state, make_automatic); + ae_vector_init_copy(&dst->cntupwardaxial, &src->cntupwardaxial, _state, make_automatic); + ae_vector_init_copy(&dst->cntaxial, &src->cntaxial, _state, make_automatic); + ae_vector_init_copy(&dst->cntradial, &src->cntradial, _state, make_automatic); + ae_vector_init_copy(&dst->nlcpervar, &src->nlcpervar, _state, make_automatic); + _kniset_init_copy(&dst->varbyqc, &src->varbyqc, _state, make_automatic); + _kniset_init_copy(&dst->varbycc, &src->varbycc, _state, make_automatic); +} + + +void _presolvervcstats_clear(void* _p) +{ + presolvervcstats *p = (presolvervcstats*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->isdroppedcol); + ae_vector_clear(&p->isdroppedlc); + ae_vector_clear(&p->isdroppedqc); + ae_vector_clear(&p->isdroppedcc); + ae_vector_clear(&p->cntdownwardaxial); + ae_vector_clear(&p->cntupwardaxial); + ae_vector_clear(&p->cntaxial); + ae_vector_clear(&p->cntradial); + ae_vector_clear(&p->nlcpervar); + _kniset_clear(&p->varbyqc); + _kniset_clear(&p->varbycc); +} + + +void _presolvervcstats_destroy(void* _p) +{ + presolvervcstats *p = (presolvervcstats*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->isdroppedcol); + ae_vector_destroy(&p->isdroppedlc); + ae_vector_destroy(&p->isdroppedqc); + ae_vector_destroy(&p->isdroppedcc); + ae_vector_destroy(&p->cntdownwardaxial); + ae_vector_destroy(&p->cntupwardaxial); + ae_vector_destroy(&p->cntaxial); + ae_vector_destroy(&p->cntradial); + ae_vector_destroy(&p->nlcpervar); + _kniset_destroy(&p->varbyqc); + _kniset_destroy(&p->varbycc); +} + + +void _presolveinfo_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + presolveinfo *p = (presolveinfo*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rawc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->rawh, _state, make_automatic); + _sparsematrix_init(&p->rawa, _state, make_automatic); + _xquadraticconstraints_init(&p->rawxqc, _state, make_automatic); + _xconicconstraints_init(&p->rawxcc, _state, make_automatic); + ae_vector_init(&p->lagrangefromresidual, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparseh, _state, make_automatic); + _sparsematrix_init(&p->sparsea, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + _xquadraticconstraints_init(&p->xqc, _state, make_automatic); + _xconicconstraints_init(&p->xcc, _state, make_automatic); + ae_vector_init(&p->packxperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->packyperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->packqcperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->packccperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->packstatperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->unpackxperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->unpackyperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->unpackqcperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->unpackccperm, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->unpackstatperm, 0, DT_INT, _state, make_automatic); + _presolverstack_init(&p->trfstack, _state, make_automatic); + ae_vector_init(&p->s1, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->bc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yqc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + _presolvebuffers_init(&p->buf, _state, make_automatic); +} + + +void _presolveinfo_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + presolveinfo *dst = (presolveinfo*)_dst; + const presolveinfo *src = (const presolveinfo*)_src; + dst->eps = src->eps; + dst->newn = src->newn; + dst->oldn = src->oldn; + dst->oldmqc = src->oldmqc; + dst->oldmcc = src->oldmcc; + dst->newm = src->newm; + dst->oldm = src->oldm; + dst->newmqc = src->newmqc; + dst->newmcc = src->newmcc; + ae_vector_init_copy(&dst->rawc, &src->rawc, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndl, &src->rawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndu, &src->rawbndu, _state, make_automatic); + dst->hash = src->hash; + _sparsematrix_init_copy(&dst->rawh, &src->rawh, _state, make_automatic); + _sparsematrix_init_copy(&dst->rawa, &src->rawa, _state, make_automatic); + _xquadraticconstraints_init_copy(&dst->rawxqc, &src->rawxqc, _state, make_automatic); + _xconicconstraints_init_copy(&dst->rawxcc, &src->rawxcc, _state, make_automatic); + dst->problemstatus = src->problemstatus; + ae_vector_init_copy(&dst->lagrangefromresidual, &src->lagrangefromresidual, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseh, &src->sparseh, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + _xquadraticconstraints_init_copy(&dst->xqc, &src->xqc, _state, make_automatic); + _xconicconstraints_init_copy(&dst->xcc, &src->xcc, _state, make_automatic); + ae_vector_init_copy(&dst->packxperm, &src->packxperm, _state, make_automatic); + ae_vector_init_copy(&dst->packyperm, &src->packyperm, _state, make_automatic); + ae_vector_init_copy(&dst->packqcperm, &src->packqcperm, _state, make_automatic); + ae_vector_init_copy(&dst->packccperm, &src->packccperm, _state, make_automatic); + ae_vector_init_copy(&dst->packstatperm, &src->packstatperm, _state, make_automatic); + ae_vector_init_copy(&dst->unpackxperm, &src->unpackxperm, _state, make_automatic); + ae_vector_init_copy(&dst->unpackyperm, &src->unpackyperm, _state, make_automatic); + ae_vector_init_copy(&dst->unpackqcperm, &src->unpackqcperm, _state, make_automatic); + ae_vector_init_copy(&dst->unpackccperm, &src->unpackccperm, _state, make_automatic); + ae_vector_init_copy(&dst->unpackstatperm, &src->unpackstatperm, _state, make_automatic); + _presolverstack_init_copy(&dst->trfstack, &src->trfstack, _state, make_automatic); + ae_vector_init_copy(&dst->s1, &src->s1, _state, make_automatic); + ae_vector_init_copy(&dst->bc1, &src->bc1, _state, make_automatic); + ae_vector_init_copy(&dst->x1, &src->x1, _state, make_automatic); + ae_vector_init_copy(&dst->y1, &src->y1, _state, make_automatic); + ae_vector_init_copy(&dst->yqc, &src->yqc, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + _presolvebuffers_init_copy(&dst->buf, &src->buf, _state, make_automatic); +} + + +void _presolveinfo_clear(void* _p) +{ + presolveinfo *p = (presolveinfo*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rawc); + ae_vector_clear(&p->rawbndl); + ae_vector_clear(&p->rawbndu); + _sparsematrix_clear(&p->rawh); + _sparsematrix_clear(&p->rawa); + _xquadraticconstraints_clear(&p->rawxqc); + _xconicconstraints_clear(&p->rawxcc); + ae_vector_clear(&p->lagrangefromresidual); + ae_vector_clear(&p->c); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + _sparsematrix_clear(&p->sparseh); + _sparsematrix_clear(&p->sparsea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + _xquadraticconstraints_clear(&p->xqc); + _xconicconstraints_clear(&p->xcc); + ae_vector_clear(&p->packxperm); + ae_vector_clear(&p->packyperm); + ae_vector_clear(&p->packqcperm); + ae_vector_clear(&p->packccperm); + ae_vector_clear(&p->packstatperm); + ae_vector_clear(&p->unpackxperm); + ae_vector_clear(&p->unpackyperm); + ae_vector_clear(&p->unpackqcperm); + ae_vector_clear(&p->unpackccperm); + ae_vector_clear(&p->unpackstatperm); + _presolverstack_clear(&p->trfstack); + ae_vector_clear(&p->s1); + ae_vector_clear(&p->bc1); + ae_vector_clear(&p->x1); + ae_vector_clear(&p->y1); + ae_vector_clear(&p->yqc); + ae_vector_clear(&p->d); + ae_vector_clear(&p->tmpi); + _presolvebuffers_clear(&p->buf); +} + + +void _presolveinfo_destroy(void* _p) +{ + presolveinfo *p = (presolveinfo*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rawc); + ae_vector_destroy(&p->rawbndl); + ae_vector_destroy(&p->rawbndu); + _sparsematrix_destroy(&p->rawh); + _sparsematrix_destroy(&p->rawa); + _xquadraticconstraints_destroy(&p->rawxqc); + _xconicconstraints_destroy(&p->rawxcc); + ae_vector_destroy(&p->lagrangefromresidual); + ae_vector_destroy(&p->c); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + _sparsematrix_destroy(&p->sparseh); + _sparsematrix_destroy(&p->sparsea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + _xquadraticconstraints_destroy(&p->xqc); + _xconicconstraints_destroy(&p->xcc); + ae_vector_destroy(&p->packxperm); + ae_vector_destroy(&p->packyperm); + ae_vector_destroy(&p->packqcperm); + ae_vector_destroy(&p->packccperm); + ae_vector_destroy(&p->packstatperm); + ae_vector_destroy(&p->unpackxperm); + ae_vector_destroy(&p->unpackyperm); + ae_vector_destroy(&p->unpackqcperm); + ae_vector_destroy(&p->unpackccperm); + ae_vector_destroy(&p->unpackstatperm); + _presolverstack_destroy(&p->trfstack); + ae_vector_destroy(&p->s1); + ae_vector_destroy(&p->bc1); + ae_vector_destroy(&p->x1); + ae_vector_destroy(&p->y1); + ae_vector_destroy(&p->yqc); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->tmpi); + _presolvebuffers_destroy(&p->buf); +} + + +#endif +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + CONSTRAINED QUADRATIC PROGRAMMING + +The subroutine creates QP optimizer. After initial creation, it contains +default optimization problem with zero quadratic and linear terms and no +constraints. + +In order to actually solve something you should: + +specify objective: +* set linear term with minqpsetlinearterm() +* set quadratic term with minqpsetquadraticterm() or + minqpsetquadratictermsparse() + +specify constraints: +* set variable bounds with minqpsetbc() or minqpsetbcall() +* specify linear constraint matrix with one of the following functions: + * modern API: + * minqpsetlc2() for sparse two-sided constraints AL <= A*x <= AU + * minqpsetlc2dense() for dense two-sided constraints AL <= A*x <= AU + * minqpsetlc2mixed() for mixed two-sided constraints AL <= A*x <= AU + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + * legacy API: + * minqpsetlc() for dense one-sided equality/inequality constraints + * minqpsetlcsparse() for sparse one-sided equality/inequality constraints + * minqpsetlcmixed() for mixed dense/sparse one-sided equality/inequality constraints +* add two-sided quadratic constraint(s) of the form CL <= b'x+0.5*x'Qx <= CU + with one of the following functions: + * minqpaddqc2() for a quadratic constraint given by a sparse + matrix structure; has O(max(N,NNZ)) memory and + running time requirements. + * minqpaddqc2dense() for a quadratic constraint given by a dense + matrix; has O(N^2) memory and running time requirements. + * minqpaddqc2list() for a sparse quadratic constraint given by + a list of non-zero entries; has O(NNZ) memory + and O(NNZ*logNNZ) running time requirements, + ideal for constraints with much less than N + nonzero elements. +* add second order cone constraints with: + * minqpaddsoccprimitive() for a primitive second order cone constraint + * minqpaddsoccorthogonal() for an axis-orthogonal second order cone constraint +* add power cone constraints with: + * minqpaddpowccprimitive() for a primitive power cone constraint + * minqpaddpowccorthogonal() for an axis-orthogonal power cone constraint + +configure and run QP solver: +* choose appropriate QP solver and set it and its stopping criteria by + means of minqpsetalgo??????() function +* call minqpoptimize() to run the solver and minqpresults() to get the + solution vector and additional information. + +Following solvers are recommended for convex and semidefinite problems +with box and linear constraints: +* QuickQP for small dense problems with box-only constraints (or no + constraints at all) +* DENSE-IPM-QP for convex or semidefinite problems with medium (up + to several thousands) variable count, dense/sparse quadratic term and + any number (up to many thousands) of dense/sparse general linear + constraints +* SPARSE-IPM-QP for convex or semidefinite problems with large (many + thousands) variable count, sparse quadratic term AND linear constraints. +* SPARSE-ECQP for convex having only linear equality constraints. This + specialized solver can be orders of magnitude faster than IPM. + +If your problem happens to be nonconvex or has nonlinear constraints, then +you can use: +* DENSE-GENIPM or SPARSE-GENIPM solver which supports convex/nonconvex + QP problems with box, linear, quadratic equality/inequality and + conic constraints. +* HYBRID-GENIPM solver which is optimized for well-conditioned problems + with large dense quadratic term/constraints or for problems with large + sparse quadratic terms having prohibitively dense Cholesky factors. The + solver uses limited-memory SR1 quadratic model to accelerate Newton step. +* QuickQP for small dense nonconvex problems with box-only constraints + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer with zero quadratic/linear terms + and no constraints + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state) +{ + ae_int_t i; + + _minqpstate_clear(state); + + ae_assert(n>=1, "MinQPCreate: N<1", _state); + + /* + * initialize QP solver + */ + state->n = n; + state->repterminationtype = 0; + state->repf = (double)(0); + state->absamax = (double)(1); + state->absasum = (double)(1); + state->absasum2 = (double)(1); + state->cqmready = ae_false; + state->akind = 1; + state->sparseaupper = ae_false; + state->sparsea.m = n; + state->sparsea.n = n; + isetallocv(n+1, 0, &state->sparsea.ridx, _state); + sparsecreatecrsinplace(&state->sparsea, _state); + ae_vector_set_length(&state->b, n, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->havebndl, n, _state); + ae_vector_set_length(&state->havebndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->startx, n, _state); + ae_vector_set_length(&state->xorigin, n, _state); + ae_vector_set_length(&state->xs, n, _state); + rvectorsetlengthatleast(&state->replagbc, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->havebndl.ptr.p_bool[i] = ae_false; + state->havebndu.ptr.p_bool[i] = ae_false; + state->b.ptr.p_double[i] = 0.0; + state->startx.ptr.p_double[i] = 0.0; + state->xorigin.ptr.p_double[i] = 0.0; + state->s.ptr.p_double[i] = 1.0; + state->replagbc.ptr.p_double[i] = 0.0; + } + state->stype = 0; + state->havex = ae_false; + minqpsetalgosparseipm(state, 0.0, _state); + qqploaddefaults(n, &state->qqpsettingsuser, _state); + qpdenseaulloaddefaults(n, &state->qpdenseaulsettingsuser, _state); + xlcinit(n, &state->xlc, _state); + xqcinit(n, &state->xqc, _state); + xccinit(n, &state->xcc, _state); + state->dbgskipconstraintnormalization = ae_false; + state->dbgdopresolve = ae_true; + state->veps = 0.0; + state->vmemlen = 0; + state->vmaxoffdiag = 0; + state->gmaxits = 0; + state->repn = 0; + state->repm = 0; + state->repmqc = 0; + state->repmcc = 0; + + /* + * Prepare buffers + */ + ae_nxpool_alloc(&state->n1realpool, n+1, _state); + ae_nxpool_alloc(&state->n1intpool, n+1, _state); +} + + +/************************************************************************* +This function sets linear term for QP solver. + +By default, linear term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + B - linear term, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlinearterm(minqpstate* state, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(b->cnt>=n, "MinQPSetLinearTerm: Length(B)n; + ae_assert(a->rows>=n, "MinQPSetQuadraticTerm: Rows(A)cols>=n, "MinQPSetQuadraticTerm: Cols(A)n; + ae_assert(sparsegetnrows(a, _state)==n, "MinQPSetQuadraticTermSparse: Rows(A)<>N", _state); + ae_assert(sparsegetncols(a, _state)==n, "MinQPSetQuadraticTermSparse: Cols(A)<>N", _state); + sparsecopytocrsbuf(a, &state->sparsea, _state); + state->sparseaupper = isupper; + state->akind = 1; + + /* + * Estimate norm of A + * (it will be used later in the quadratic penalty function) + */ + state->absamax = (double)(0); + state->absasum = (double)(0); + state->absasum2 = (double)(0); + t0 = 0; + t1 = 0; + while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) + { + if( i==j ) + { + + /* + * Diagonal terms are counted only once + */ + state->absamax = ae_maxreal(state->absamax, v, _state); + state->absasum = state->absasum+v; + state->absasum2 = state->absasum2+v*v; + } + if( (j>i&&isupper)||(jabsamax = ae_maxreal(state->absamax, v, _state); + state->absasum = state->absasum+(double)2*v; + state->absasum2 = state->absasum2+(double)2*v*v; + } + } +} + + +/************************************************************************* +This function sets starting point for QP solver. It is useful to have good +initial approximation to the solution, because it will increase speed of +convergence and identification of active constraints. + +NOTE: interior point solvers ignore initial point provided by user. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetstartingpoint(minqpstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(x->cnt>=n, "MinQPSetStartingPoint: Length(B)n; + ae_assert(xorigin->cnt>=n, "MinQPSetOrigin: Length(B)cnt>=state->n, "MinQPSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinQPSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinQPSetScale: S contains zero elements", _state); + } + for(i=0; i<=state->n-1; i++) + { + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } + state->stype = 0; +} + + +/************************************************************************* +This function sets automatic evaluation of variable scaling. + +IMPORTANT: this function works only for matrices with positive diagonal + elements! Zero or negative elements will result in -9 error + code being returned. Specify scale vector manually with + minqpsetscale() in such cases. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and as +preconditioner. + +The best way to set scaling is to manually specify variable scales. +However, sometimes you just need quick-and-dirty solution - either when +you perform fast prototyping, or when you know your problem well and you +are 100% sure that this quick solution is robust enough in your case. + +One such solution is to evaluate scale of I-th variable as 1/Sqrt(A[i,i]), +where A[i,i] is an I-th diagonal element of the quadratic term. + +Such approach works well sometimes, but you have to be careful here. + +INPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void minqpsetscaleautodiag(minqpstate* state, ae_state *_state) +{ + + + state->stype = 1; +} + + +/************************************************************************* +This function tells QP solver to use DENSE-AUL algorithm and sets stopping +criteria for the algorithm. + +This algorithm is intended for non-convex problems with moderate (up +to several thousands) variable count and arbitrary number of constraints +which are either (a) effectively convexified under constraints or (b) have +unique solution even with nonconvex target. + +IMPORTANT: when DENSE-IPM solver is applicable, its performance is usually + much better than that of DENSE-AUL. + We recommend you to use DENSE-AUL only when other solvers can + not be used. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* convergence is theoretically proved for positive-definite (convex) QP + problems. Semidefinite and non-convex problems can be solved as long as + they are bounded from below under constraints, although without + theoretical guarantees. + +ALGORITHM OUTLINE: + +* this algorithm is an augmented Lagrangian method with dense + preconditioner (hence its name). +* it performs several outer iterations in order to refine values of the + Lagrange multipliers. Single outer iteration is a solution of some + unconstrained optimization problem: first it performs dense Cholesky + factorization of the Hessian in order to build preconditioner (adaptive + regularization is applied to enforce positive definiteness), and then + it uses L-BFGS optimizer to solve optimization problem. +* typically you need about 5-10 outer iterations to converge to solution + +ALGORITHM LIMITATIONS: + +* because dense Cholesky driver is used, this algorithm has O(N^2) memory + requirements and O(OuterIterations*N^3) minimum running time. From the + practical point of view, it limits its applicability by several + thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + constraint matrix is sparse, it may handle tens of thousands of general + linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0, stopping criteria for inner optimizer. + Inner iterations are stopped when step length (with + variable scaling being applied) is less than EpsX. + See minqpsetscale() for more information on variable + scaling. + Rho - penalty coefficient, Rho>0: + * large enough that algorithm converges with desired + precision. + * not TOO large to prevent ill-conditioning + * recommended values are 100, 1000 or 10000 + ItsCnt - number of outer iterations: + * recommended values: 10-15 (although in most cases it + converges within 5 iterations, you may need a few more + to be sure). + * ItsCnt=0 means that small number of outer iterations is + automatically chosen (10 iterations in current version). + * ItsCnt=1 means that AUL algorithm performs just as usual + penalty method. + * ItsCnt>1 means that AUL algorithm performs specified + number of outer iterations + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic step length selection + (specific step length chosen may change in the future versions of + ALGLIB, so it is better to specify step length explicitly). + + -- ALGLIB -- + Copyright 20.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseaul(minqpstate* state, + double epsx, + double rho, + ae_int_t itscnt, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "MinQPSetAlgoDenseAUL: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinQPSetAlgoDenseAUL: negative EpsX", _state); + ae_assert(ae_isfinite(rho, _state), "MinQPSetAlgoDenseAUL: Rho is not finite number", _state); + ae_assert(ae_fp_greater(rho,(double)(0)), "MinQPSetAlgoDenseAUL: non-positive Rho", _state); + ae_assert(itscnt>=0, "MinQPSetAlgoDenseAUL: negative ItsCnt!", _state); + state->algokind = 4; + if( ae_fp_eq(epsx,(double)(0)) ) + { + epsx = 1.0E-8; + } + if( itscnt==0 ) + { + itscnt = 10; + } + state->qpdenseaulsettingsuser.epsx = epsx; + state->qpdenseaulsettingsuser.outerits = itscnt; + state->qpdenseaulsettingsuser.rho = rho; +} + + +/************************************************************************* +This function tells QP solver to use DENSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with moderate (up to several thousands) variable count +and arbitrary number of linear constraints. Quadratic and conic constraints +are supported by another solver (DENSE-GENIPM). + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: this algorithm is likely to fail on nonconvex problems, + furthermore, sometimes it fails without a notice. If you try to + run DENSE-IPM on a problem with indefinite matrix (a matrix + having at least one negative eigenvalue) then depending on the + circumstances it may either (a) stall at some arbitrary point, + or (b) throw an exception due to the failure of the Cholesky + decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseipm(minqpstate* state, double eps, ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinQPSetAlgoDenseIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinQPSetAlgoDenseIPM: negative Eps", _state); + state->algokind = 5; + state->veps = eps; +} + + +/************************************************************************* +This function tells QP solver to use SPARSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with large variable and constraint count and sparse +quadratic term and sparse linear constraints. It was successfully used for +problems with millions of variables and constraints. Quadratic and conic +constraints are supported by another solver (SPARSE-GENIPM). + +It is possible to have some limited set of dense linear constraints - they +will be handled separately by the dense BLAS - but the more dense +constraints you have, the more time solver needs. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +IMPORTANT: this algorithm won't work for nonconvex problems. If you try to + run SPARSE-IPM on a problem with indefinite quadratic term (a + matrix having at least one negative eigenvalue) then depending + on the circumstances it may either (a) stall at some arbitrary + point, or (b) throw an exception due to the failure of the + Cholesky decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* specializes on large-scale sparse problems + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseipm(minqpstate* state, + double eps, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinQPSetAlgoSparseIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinQPSetAlgoSparseIPM: negative Eps", _state); + state->algokind = 6; + state->veps = eps; +} + + +/************************************************************************* +This function tells QP solver to use DENSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically +constrained QP problems with moderate (up to several thousands) variables +count and arbitrary number of constraints. Use SPARSE-GENIPM if your +problem is sparse. + +The algorithm is a generalization of DENSE-IPM solver, capable of handling +more general constraints as well as nonconvexity of the target. In the +latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +ALGORITHM FEATURES: + +* supports box, linear equality/inequality and conic constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'GENIPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodensegenipm(minqpstate* state, + double eps, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinQPSetAlgoDenseGENIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinQPSetAlgoDenseGENIPM: negative Eps", _state); + state->algokind = 7; + state->veps = eps; +} + + +/************************************************************************* +This function tells QP solver to use SPARSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically/ +quadratically constrained QP problems with sparse quadratic term and +constraints. It can handle millions of variables and constraints, assuming +that the problem is sufficiently sparse. If your problem is small (several +thousands vars at most) and dense, consider using DENSE-GENIPM as a more +efficient alternative. + +The algorithm is a generalization of the SPARSE-IPM solver, capable of +handling more general constraints as well as nonconvexity of the target. +In the latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +ALGORITHM FEATURES: + + +* supports box, linear equality/inequality constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) +* specializes on large-scale sparse problems + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparsegenipm(minqpstate* state, + double eps, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinQPSetAlgoSparseGENIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinQPSetAlgoSparseGENIPM: negative Eps", _state); + state->algokind = 8; + state->veps = eps; +} + + +/************************************************************************* +This function tells QP solver to use HYBRID-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for finding medium-accuracy solutions (say, no +more than 5 accurate digits) to large-scale convex/nonconvex box/linearly/ +conically/quadratically constrained QP problems with objective and/or +quadratic constraints being well-conditioned but having prohibitively +dense Cholesky factors. This includes both dense problems and problems +with sparse terms having too dense factorizations. + +Being well conditioned allows us to use low rank LBFGS/LSR1 approximations +to the objective (quadratic constraints) and use sparse linear algebra for +the rest of the problem, thus achieving significant speed-up on many +types of problems. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: performance of this function depends on both sparsity pattern + of the problem and on its conditioning properties. The running + time for a dense QP/QCQP problem grows with variables count as + O(N^2) while DENSE-GENIPM running time grows as O(N^3). + + On the other hand, DENSE/SPARSE-GENIPM running time shows only + moderate dependence on the condition number, while HYBRID-GENIPM + running time often explodes with condition number larger than + 10000. + + In practice, on a dense QCQP problem HYBRID algorithm starts to + singificantly outperform DENSE-GENIPM for N>=1000. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + + This solver is optimized for finding medium-accuracy + solutions, with eps being between 1E-3 and 1E-5. + + MemLen - >=0, memory length for the limited memory SR1 model. Zero + value means automatic selection of some small predefined + value which may change in future versions of ALGLIB. + Optimal value is problem-dependent, with 8...32 being a + good initial point for the experimentation. Values above + N are silently truncated down to N. + + MaxOffdiag- >=0, quadratic terms with more than MaxOffdiag offdiagonal + elements are handled via quasi-Newton approximation. Terms + with no more than MaxOffdiag elements are handled exactly, + including strictly diagonal terms that are always handled + exactly (because they have the minimum number off-diagonal + elements possible - zero). Symmetric terms appearing above + and below diagonal are counted as one term, not two. A + single quasi-Newton model is built, which approximates all + eligible quadratic terms together. + + The following values are possible: + * 0 - approximate every quadratic term having at least one + off-diagonal element with a quasi-Newton model. + * 0=N*(N-1)/2 - no quadratic term is eligible + for quasi-Newton approximation, algorithm performance is + roughly similar to that of SPARSE-GENIPM, with some + additional small overhead for quasi-Newton code checks. + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgohybridgenipm(minqpstate* state, + double eps, + ae_int_t memlen, + ae_int_t maxoffdiag, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinQPSetAlgoHybridGENIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinQPSetAlgoHybridGENIPM: negative Eps", _state); + ae_assert(memlen>=0, "MinQPSetAlgoHybridGENIPM: negative MemLen", _state); + ae_assert(maxoffdiag>=0, "MinQPSetAlgoHybridGENIPM: negative MaxOffdiag", _state); + state->algokind = 10; + state->veps = eps; + state->vmemlen = memlen; + state->vmaxoffdiag = maxoffdiag; +} + + +/************************************************************************* +This function tells QP solver to use an ECQP algorithm. + +This algorithm is intended for sparse convex problems with only linear +equality constraints. It can handle millions of variables and constraints, +assuming that the problem is sufficiently sparse. However, it can NOT +deal with nonlinear equality constraints or inequality constraints of any +type (including box ones), nor it can deal with nonconvex problems. + +When applicable, it outperforms SPARSE-IPM by tens of times. It is a +regularized direct linear algebra solver that performs several rounds of +iterative refinement in order to improve a solution. Thus, due to its +direct nature, it does not need stopping criteria and performs much faster +than interior point methods. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities are less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseecqp(minqpstate* state, ae_state *_state) +{ + + + state->algokind = 9; +} + + +/************************************************************************* +This function tells solver to use QuickQP algorithm: special extra-fast +algorithm for problems with box-only constrants. It may solve non-convex +problems as long as they are bounded from below under constraints. + +ALGORITHM FEATURES: +* several times faster than DENSE-IPM when running on box-only problem +* utilizes accelerated methods for activation of constraints. +* supports dense and sparse QP problems +* supports ONLY box constraints; general linear constraints are NOT + supported by this solver +* can solve all types of problems (convex, semidefinite, nonconvex) as + long as they are bounded from below under constraints. + Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". + In convex/semidefinite case global minimum is returned, in nonconvex + case - algorithm returns one of the local minimums. + +ALGORITHM OUTLINE: + +* algorithm performs two kinds of iterations: constrained CG iterations + and constrained Newton iterations +* initially it performs small number of constrained CG iterations, which + can efficiently activate/deactivate multiple constraints +* after CG phase algorithm tries to calculate Cholesky decomposition and + to perform several constrained Newton steps. If Cholesky decomposition + failed (matrix is indefinite even under constraints), we perform more + CG iterations until we converge to such set of constraints that system + matrix becomes positive definite. Constrained Newton steps greatly + increase convergence speed and precision. +* algorithm interleaves CG and Newton iterations which allows to handle + indefinite matrices (CG phase) and quickly converge after final set of + constraints is found (Newton phase). Combination of CG and Newton phases + is called "outer iteration". +* it is possible to turn off Newton phase (beneficial for semidefinite + problems - Cholesky decomposition will fail too often) + +ALGORITHM LIMITATIONS: + +* algorithm does not support general linear constraints; only box ones + are supported +* Cholesky decomposition for sparse problems is performed with Skyline + Cholesky solver, which is intended for low-profile matrices. No profile- + reducing reordering of variables is performed in this version of ALGLIB. +* problems with near-zero negative eigenvalues (or exacty zero ones) may + experience about 2-3x performance penalty. The reason is that Cholesky + decomposition can not be performed until we identify directions of zero + and negative curvature and activate corresponding boundary constraints - + but we need a lot of trial and errors because these directions are hard + to notice in the matrix spectrum. + In this case you may turn off Newton phase of algorithm. + Large negative eigenvalues are not an issue, so highly non-convex + problems can be solved very efficiently. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + EpsX - >=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinQPSetScale() + MaxOuterIts-maximum number of OUTER iterations. One outer iteration + includes some amount of CG iterations (from 5 to ~N) and + one or several (usually small amount) Newton steps. Thus, + one outer iteration has high cost, but can greatly reduce + funcation value. + Use 0 if you do not want to limit number of outer iterations. + UseNewton- use Newton phase or not: + * Newton phase improves performance of positive definite + dense problems (about 2 times improvement can be observed) + * can result in some performance penalty on semidefinite + or slightly negative definite problems - each Newton + phase will bring no improvement (Cholesky failure), but + still will require computational time. + * if you doubt, you can turn off this phase - optimizer + will retain its most of its high speed. + +IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection (presently it is small step +length, but it may change in the future versions of ALGLIB). + + -- ALGLIB -- + Copyright 22.05.2014 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgoquickqp(minqpstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxouterits, + ae_bool usenewton, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinQPSetAlgoQuickQP: EpsG is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsG", _state); + ae_assert(ae_isfinite(epsf, _state), "MinQPSetAlgoQuickQP: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsF", _state); + ae_assert(ae_isfinite(epsx, _state), "MinQPSetAlgoQuickQP: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinQPSetAlgoQuickQP: negative EpsX", _state); + ae_assert(maxouterits>=0, "MinQPSetAlgoQuickQP: negative MaxOuterIts!", _state); + state->algokind = 3; + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxouterits==0 ) + { + epsx = 1.0E-6; + } + state->qqpsettingsuser.maxouterits = maxouterits; + state->qqpsettingsuser.epsg = epsg; + state->qqpsettingsuser.epsf = epsf; + state->qqpsettingsuser.epsx = epsx; + state->qqpsettingsuser.cnphase = usenewton; +} + + +/************************************************************************* +This function sets box constraints for QP solver + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minqpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbc(minqpstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "MinQPSetBC: Length(BndL)cnt>=n, "MinQPSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinQPSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinQPSetBC: BndU contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets box constraints for QP solver (all variables at once, +same constraints for all variables) + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbcall(minqpstate* state, + double bndl, + double bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MinQPSetBCAll: BndL is NAN or +INF", _state); + ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MinQPSetBCAll: BndU is NAN or -INF", _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = bndl; + state->bndu.ptr.p_double[i] = bndu; + state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl, _state); + state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu, _state); + } +} + + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound + BndU - upper bound + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbci(minqpstate* state, + ae_int_t i, + double bndl, + double bndu, + ae_state *_state) +{ + + + ae_assert(i>=0&&in, "MinQPSetBCi: I is outside of [0,N)", _state); + ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MinQPSetBCi: BndL is NAN or +INF", _state); + ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MinQPSetBCi: BndU is NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl; + state->bndu.ptr.p_double[i] = bndu; + state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl, _state); + state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu, _state); +} + + +/************************************************************************* +This function sets dense linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 19.06.2012 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc(minqpstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_frame _frame_block; + sparsematrix dummyc; + ae_vector dummyct; + + ae_frame_make(_state, &_frame_block); + memset(&dummyc, 0, sizeof(dummyc)); + memset(&dummyct, 0, sizeof(dummyct)); + _sparsematrix_init(&dummyc, _state, ae_true); + ae_vector_init(&dummyct, 0, DT_INT, _state, ae_true); + + minqpsetlcmixed(state, &dummyc, &dummyct, 0, c, ct, k, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets sparse linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, sparse matrix with dimensions at + least [K,N+1]. If matrix has larger size, only leading + Kx(N+1) rectangle is used. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0 + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcsparse(minqpstate* state, + const sparsematrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix dummyc; + ae_vector dummyct; + + ae_frame_make(_state, &_frame_block); + memset(&dummyc, 0, sizeof(dummyc)); + memset(&dummyct, 0, sizeof(dummyct)); + ae_matrix_init(&dummyc, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&dummyct, 0, DT_INT, _state, ae_true); + + minqpsetlcmixed(state, c, ct, k, &dummyc, &dummyct, 0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets mixed linear constraints, which include a set of dense +rows, and a set of sparse rows. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + SparseC - linear constraints, sparse matrix with dimensions EXACTLY + EQUAL TO [SparseK,N+1]. Each row of C represents one + constraint, either equality or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + SparseCT- type of sparse constraints, array[K]: + * if SparseCT[i]>0, then I-th constraint is SparseC[i,*]*x >= SparseC[i,n+1] + * if SparseCT[i]=0, then I-th constraint is SparseC[i,*]*x = SparseC[i,n+1] + * if SparseCT[i]<0, then I-th constraint is SparseC[i,*]*x <= SparseC[i,n+1] + SparseK - number of sparse equality/inequality constraints, K>=0 + DenseC - dense linear constraints, array[K,N+1]. + Each row of DenseC represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of DenseC (including right part) must be finite. + DenseCT - type of constraints, array[K]: + * if DenseCT[i]>0, then I-th constraint is DenseC[i,*]*x >= DenseC[i,n+1] + * if DenseCT[i]=0, then I-th constraint is DenseC[i,*]*x = DenseC[i,n+1] + * if DenseCT[i]<0, then I-th constraint is DenseC[i,*]*x <= DenseC[i,n+1] + DenseK - number of equality/inequality constraints, DenseK>=0 + +NOTE 1: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE 2: due to backward compatibility reasons SparseC can be larger than + [SparseK,N+1]. In this case only leading [SparseK,N+1] submatrix + will be used. However, the rest of ALGLIB has more strict + requirements on the input size, so we recommend you to pass sparse + term whose size exactly matches algorithm expectations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixed(minqpstate* state, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(densek>=0, "MinQPSetLCMixed: K<0", _state); + ae_assert(densek==0||densec->cols>=n+1, "MinQPSetLCMixed: Cols(C)rows>=densek, "MinQPSetLCMixed: Rows(DenseC)cnt>=densek, "MinQPSetLCMixed: Length(DenseCT)=0, "MinQPSetLCMixed: SparseK<0", _state); + ae_assert(sparsek==0||sparsegetncols(sparsec, _state)>=n+1, "MinQPSetLCMixed: Cols(SparseC)=sparsek, "MinQPSetLCMixed: Rows(SparseC)cnt>=sparsek, "MinQPSetLCMixed: Length(SparseCT)replaglc, _state); + xlcsetlcmixed(&state->xlc, sparsec, sparsect, sparsek, densec, densect, densek, _state); +} + + +/************************************************************************* +This function provides legacy API for specification of mixed dense/sparse +linear constraints. + +New conventions used by ALGLIB since release 3.16.0 state that set of +sparse constraints comes first, followed by set of dense ones. This +convention is essential when you talk about things like order of Lagrange +multipliers. + +However, legacy API accepted mixed constraints in reverse order. This +function is here to simplify situation with code relying on legacy API. It +simply accepts constraints in one order (old) and passes them to new API, +now in correct order. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixedlegacy(minqpstate* state, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + ae_state *_state) +{ + + + minqpsetlcmixed(state, sparsec, sparsect, sparsek, densec, densect, densek, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense helps some QP solvers + (especially modern IPM method) to utilize efficient dense Level 3 + BLAS for dense parts of the problem. If your problem has both dense + and sparse constraints, you can use minqpsetlc2mixed() function, + which will result in dense algebra being applied to dense terms, and + sparse sparse linear algebra applied to sparse terms. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2dense(minqpstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + minqpsetlc2mixed(state, &state->dummysparse, 0, a, k, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2(minqpstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + minqpsetlc2mixed(state, a, k, &state->dummyr2, 0, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2mixed(minqpstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t m; + + + n = state->n; + m = kdense+ksparse; + + /* + * Check input arguments + */ + ae_assert(ksparse>=0, "MinQPSetLC2Mixed: KSparse<0", _state); + ae_assert(ksparse==0||sparsegetncols(sparsea, _state)==n, "MinQPSetLC2: Cols(SparseA)<>N", _state); + ae_assert(ksparse==0||sparsegetnrows(sparsea, _state)==ksparse, "MinQPSetLC2: Rows(SparseA)<>K", _state); + ae_assert(kdense>=0, "MinQPSetLC2Mixed: KDense<0", _state); + ae_assert(kdense==0||densea->cols>=n, "MinQPSetLC2Mixed: Cols(DenseA)rows>=kdense, "MinQPSetLC2Mixed: Rows(DenseA)cnt>=kdense+ksparse, "MinQPSetLC2Mixed: Length(AL)cnt>=kdense+ksparse, "MinQPSetLC2Mixed: Length(AU)ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "MinQPSetLC2Mixed: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "MinQPSetLC2Mixed: AU contains NAN or -INF", _state); + } + + /* + * Allocate place for Lagrange multipliers, fill by zero, set constraints + */ + rsetallocv(kdense+ksparse, 0.0, &state->replaglc, _state); + xlcsetlc2mixed(&state->xlc, sparsea, ksparse, densea, kdense, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +matrix of currently present dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2dense(minqpstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(a->cnt>=n, "MinQPAddLC2Dense: Length(A)xlc, a, al, au, _state); + rvectorgrowto(&state->replaglc, state->xlc.nsparse+state->xlc.ndense+1, _state); + state->replaglc.ptr.p_double[state->xlc.nsparse+state->xlc.ndense] = 0.0; +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2(minqpstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + + /* + * Check inputs + */ + ae_assert(nnz>=0, "MinQPAddLC2: NNZ<0", _state); + ae_assert(idxa->cnt>=nnz, "MinQPAddLC2: Length(IdxA)cnt>=nnz, "MinQPAddLC2: Length(ValA)ptr.p_int[i]>=0&&idxa->ptr.p_int[i]xlc, idxa, vala, nnz, al, au, _state); + rvectorgrowto(&state->replaglc, state->xlc.nsparse+state->xlc.ndense+1, _state); + state->replaglc.ptr.p_double[state->xlc.nsparse+state->xlc.ndense] = 0.0; +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2sparsefromdense(minqpstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(da->cnt>=n, "MinQPAddLC2SparseFromDense: Length(DA)xlc, da, al, au, _state); + rvectorgrowto(&state->replaglc, state->xlc.nsparse+state->xlc.ndense+1, _state); + state->replaglc.ptr.p_double[state->xlc.nsparse+state->xlc.ndense] = 0.0; +} + + +/************************************************************************* +This function clears the list of quadratic constraints. Other constraints +are not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearqc(minqpstate* state, ae_state *_state) +{ + + + xqcclear(&state->xqc, _state); + state->repmqc = 0; +} + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear term is given by +a dense array, the quadratic term is given by a sparse array. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function has O(max(N,NNZ)) memory and time requirements because a +dense array is used to store linear term and because most sparse matrix +storage formats supported by ALGLIB need at least O(N) memory even for an +empty quadratic constraint matrix. + +Use minqpaddqc2list() if you have to add many constraints with much less +than N nonzero elements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - symmetric matrix Q in a sparse matrix storage format: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * any sparse matrix storage format present in ALGLIB is + supported + * the matrix must be exactly NxN + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2(minqpstate* state, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_int_t n; + ae_int_t result; + + + n = state->n; + ae_assert(sparsegetnrows(q, _state)==n&&sparsegetncols(q, _state)==n, "MinQPAddQC2: rows(Q)<>N or cols(Q)<>N", _state); + ae_assert(b->cnt>=n, "MinQPAddQC2: Length(B)dummysparse, _state); + xqcaddqc2(&state->xqc, &state->dummysparse, isupper, b, cl, cu, applyorigin, _state); + } + else + { + xqcaddqc2(&state->xqc, q, isupper, b, cl, cu, applyorigin, _state); + } + state->repmqc = xqcgetcount(&state->xqc, _state); + rgrowv(state->repmqc, &state->replagqc, _state); + state->replagqc.ptr.p_double[state->repmqc-1] = 0.0; + result = state->repmqc-1; + return result; +} + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. Both linear and quadratic +terms are given as lists of non-zero entries. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function needs O(NNZ) memory for temporaries and O(NNZ*logNNZ) time, +where NNZ is a total number of non-zeros in both lists. For small +constraints it can be orders of magnitude faster than minqpaddqc2() with +its O(max(N,NNZ)) temporary memory or minqpaddqc2dense() with its O(N^2) +temporaries. Thus, it is recommended if you have many small constraints. + +NOTE: in the end, all quadratic constraints are stored in the same + memory-efficient compressed format. However, you have to allocate an + NxN temporary dense matrix when you pass a constraint using + minqpaddqc2dense(). Similarly, data structures used as a part of the + API provided by minqpaddqc2() have O(N) temporary memory + requirements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + QRIdx - array[QNNZ], stores row indexes of QNNZ nonzero elements + of a symmetric matrix Q + QCIdx - array[QNNZ], stores col indexes of QNNZ nonzero elements + of a symmetric matrix Q + QVals - array[QNNZ], stores values of QNNZ nonzero elements of a + symmetric matrix Q + QNNZ - number of non-zero elements in Q, QNNZ>=0 + IsUpper - whether upper or lower triangle of Q is used: + * if IsUpper=True, then only elements with QRIdx[I]<=QCIdx[I] + are used and the rest is ignored + * if IsUpper=False, then only elements with QRIdx[I]>=QCIdx[I] + are used and the rest is ignored + BIdx - array[BNNZ], indexes of BNNZ nonzero elements of a linear term + BVals - array[BNNZ], values of BNNZ nonzero elements of a linear term + BNNZ - number of nonzero elements in B, BNNZ>=0 + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2list(minqpstate* state, + /* Integer */ const ae_vector* qridx, + /* Integer */ const ae_vector* qcidx, + /* Real */ const ae_vector* qvals, + ae_int_t qnnz, + ae_bool isupper, + /* Integer */ const ae_vector* bidx, + /* Real */ const ae_vector* bvals, + ae_int_t bnnz, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t result; + + + n = state->n; + ae_assert(qnnz>=0, "MinQPAddQC2List: QNNZ<0", _state); + ae_assert(qridx->cnt>=qnnz, "MinQPAddQC2List: len(QRIdx)cnt>=qnnz, "MinQPAddQC2List: len(QCIdx)cnt>=qnnz, "MinQPAddQC2List: len(QVals)ptr.p_int[i]<0||qridx->ptr.p_int[i]>=n ) + { + ae_assert(ae_false, "MinQPAddQC2List: one of QRIdx[] is outside of [0,N) range", _state); + } + if( qcidx->ptr.p_int[i]<0||qcidx->ptr.p_int[i]>=n ) + { + ae_assert(ae_false, "MinQPAddQC2List: one of QCIdx[] is outside of [0,N) range", _state); + } + if( !ae_isfinite(qvals->ptr.p_double[i], _state) ) + { + ae_assert(ae_false, "MinQPAddQC2List: one of QVals[] is not finite", _state); + } + } + ae_assert(bnnz>=0, "MinQPAddQC2List: BNNZ<0", _state); + ae_assert(bidx->cnt>=bnnz, "MinQPAddQC2List: len(BIdx)cnt>=bnnz, "MinQPAddQC2List: len(BVals)ptr.p_int[i]<0||bidx->ptr.p_int[i]>=n ) + { + ae_assert(ae_false, "MinQPAddQC2List: one of BIdx[] is outside of [0,N) range", _state); + } + if( !ae_isfinite(bvals->ptr.p_double[i], _state) ) + { + ae_assert(ae_false, "MinQPAddQC2List: one of BVals[] is not finite", _state); + } + } + xqcaddqc2list(&state->xqc, qridx, qcidx, qvals, qnnz, isupper, bidx, bvals, bnnz, cl, cu, applyorigin, _state); + state->repmqc = xqcgetcount(&state->xqc, _state); + rgrowv(state->repmqc, &state->replagqc, _state); + state->replagqc.ptr.p_double[state->repmqc-1] = 0.0; + result = state->repmqc-1; + return result; +} + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear and quadratic terms +are given by dense arrays. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +This function trades convenience of using dense arrays for the efficiency. +Because dense NxN storage is used, merely calling this function has O(N^2) +complexity, no matter how sparse the Q is. + +Use minqpaddqc2() or minqpaddqc2list() if you have sparse Q and/or many +constraints to handle. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - array[N,N], symmetric matrix Q: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * if more than N rows/cols are present, only leading N + elements are used + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2dense(minqpstate* state, + /* Real */ const ae_matrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state) +{ + ae_int_t n; + ae_int_t result; + + + n = state->n; + ae_assert(q->rows>=n&&q->cols>=n, "MinQPAddQC2Dense: rows(Q)cnt>=n, "MinQPAddQC2Dense: Length(B)xqc, q, isupper, b, cl, cu, applyorigin, _state); + state->repmqc = xqcgetcount(&state->xqc, _state); + rgrowv(state->repmqc, &state->replagqc, _state); + state->replagqc.ptr.p_double[state->repmqc-1] = 0.0; + result = state->repmqc-1; + return result; +} + + +/************************************************************************* +This function clears the list of conic constraints. Other constraints are +not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearcc(minqpstate* state, ae_state *_state) +{ + + + xccclear(&state->xcc, _state); + state->repmcc = 0; +} + + +/************************************************************************* +This function appends a primitive second-order conic constraint of the +form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx] + ( ) + +with 'primitive' meaning that there are no per-variable scales and that +variables under the square root have sequential indexes. More general form +of conic constraints can be specified with minqpaddsoccorthogonal(). + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB allows conic constraints to +overlap, i.e. it allows a variable to be a part of multiple conic +constraints. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Range0, + Range1 - 0<=range0<=range1<=N, variable range for the LHS; + * squared variables x[range0]...x[range1-1] are summed up + under the square root. + * range0=range1 means that the constraint is interpreted + as x[AxisIdx]>=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccprimitive(minqpstate* state, + ae_int_t range0, + ae_int_t range1, + ae_int_t axisidx, + ae_bool applyorigin, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t i; + ae_vector idx; + ae_vector diag; + ae_vector shft; + ae_int_t result; + + ae_frame_make(_state, &_frame_block); + memset(&idx, 0, sizeof(idx)); + memset(&diag, 0, sizeof(diag)); + memset(&shft, 0, sizeof(shft)); + ae_vector_init(&idx, 0, DT_INT, _state, ae_true); + ae_vector_init(&diag, 0, DT_REAL, _state, ae_true); + ae_vector_init(&shft, 0, DT_REAL, _state, ae_true); + + n = state->n; + ae_assert(axisidx>=0&&axisidx=0&&range0<=n, "MinQPAddSOCCPrimitive: range0 is outside of [0,N)", _state); + ae_assert(range1>=0&&range1<=n, "MinQPAddSOCCPrimitive: range1 is outside of [0,N]", _state); + ae_assert(range0<=range1, "MinQPAddSOCCPrimitive: range1=range1, "MinQPAddSOCCPrimitive: AxisIdx intersects with the range", _state); + + /* + * Retrieve temporaries from pools + */ + ae_nxpool_retrieve(&state->n1intpool, &idx, _state); + ae_nxpool_retrieve(&state->n1realpool, &diag, _state); + ae_nxpool_retrieve(&state->n1realpool, &shft, _state); + + /* + * Prepare cone description + */ + for(i=range0; i<=range1-1; i++) + { + idx.ptr.p_int[i-range0] = i; + diag.ptr.p_double[i-range0] = 1.0; + shft.ptr.p_double[i-range0] = 0.0; + } + idx.ptr.p_int[range1-range0] = axisidx; + diag.ptr.p_double[range1-range0] = 1.0; + shft.ptr.p_double[range1-range0] = 0.0; + + /* + * Add cone + */ + xccaddsoccprimitivecanonic(&state->xcc, &idx, &diag, &shft, range1-range0+1, applyorigin, _state); + state->repmcc = xccgetcount(&state->xcc, _state); + result = state->repmcc-1; + + /* + * Recycle temporaries + */ + ae_nxpool_recycle(&state->n1intpool, &idx, _state); + ae_nxpool_recycle(&state->n1realpool, &diag, _state); + ae_nxpool_recycle(&state->n1realpool, &shft, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function appends an axis-orthogonal second-order conic constraint of +the form + + ( k-2 ( )^2 ) + sqrt ( SUM ( a[i]*x[idx[i]]+c[i] ) + theta^2 ) <= a[k-1]*x[idx[k-1]]+c[k-1] + ( i=0 ( ) ) + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows a[] to have zero elements at arbitrary positions (e.g., |x|<=const +can be handled just as easy as |x|<=y). Furthermore, ALGLIB allows conic +constraints to overlap, i.e. it allows a variable to be a part of multiple +conic constraints, or to appear multiple times in the same constraint. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Idx - array[K] (or larger, only leading K elements are used) + storing variable indexes. Indexes can be unsorted and/or + non-distinct. + A - array[K] (or larger, only leading K elements are used), + variable multipliers. Can contain zero values. + C - array[K] (or larger, only leading K elements are used), + variable shifts. + K - cone dimensionality, K>=1. It is possible to have K>N. + Theta - additional constant term, can be zero + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccorthogonal(minqpstate* state, + /* Integer */ const ae_vector* idx, + /* Real */ const ae_vector* a, + /* Real */ const ae_vector* c, + ae_int_t k, + double theta, + ae_bool applyorigin, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t result; + + + n = state->n; + ae_assert(k>=1, "MinQPAddSOCCOrthogonal: K<1", _state); + ae_assert(idx->cnt>=k, "MinQPAddSOCCOrthogonal: len(idx)cnt>=k, "MinQPAddSOCCOrthogonal: len(a)cnt>=k, "MinQPAddSOCCOrthogonal: len(c)ptr.p_int[i]>=0&&idx->ptr.p_int[i]ptr.p_double[i], _state), "MinQPAddSOCCOrthogonal: a[] contains infinite values", _state); + ae_assert(ae_isfinite(c->ptr.p_double[i], _state), "MinQPAddSOCCOrthogonal: c[] contains infinite values", _state); + } + ae_assert(ae_isfinite(theta, _state), "MinQPAddSOCCOrthogonal: theta is not a finite number", _state); + + /* + * Add cone + */ + xccaddsoccorthogonalnoncanonic(&state->xcc, idx, a, c, k, theta, applyorigin, _state); + state->repmcc = xccgetcount(&state->xcc, _state); + result = state->repmcc-1; + return result; +} + + +/************************************************************************* +This function appends a primitive power cone constraint of the form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx]^alpha + ( ) + +or, written in another form, + + ( ( ))^(1/alpha) + (sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 )) <= x[axisidx] + ( ( )) + +where + + 0=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + Alpha - power parameter, 0n; + ae_assert(axisidx>=0&&axisidx=0&&range0<=n, "MinQPAddPOWCCPrimitive: range0 is outside of [0,N)", _state); + ae_assert(range1>=0&&range1<=n, "MinQPAddPOWCCPrimitive: range1 is outside of [0,N]", _state); + ae_assert(range0<=range1, "MinQPAddPOWCCPrimitive: range1=range1, "MinQPAddPOWCCPrimitive: AxisIdx intersects with the range", _state); + ae_assert(ae_isfinite(alpha, _state), "MinQPAddPOWCCPrimitive: Alpha is not finite", _state); + ae_assert(ae_fp_greater(alpha,(double)(0))&&ae_fp_less_eq(alpha,(double)(1)), "MinQPAddPOWCCPrimitive: Alpha is outside of (0,1]", _state); + + /* + * Retrieve temporaries from pools + */ + ae_nxpool_retrieve(&state->n1intpool, &idx, _state); + ae_nxpool_retrieve(&state->n1realpool, &diag, _state); + ae_nxpool_retrieve(&state->n1realpool, &shft, _state); + ae_nxpool_retrieve(&state->n1realpool, &alphavec, _state); + + /* + * Prepare cone description + */ + for(i=range0; i<=range1-1; i++) + { + idx.ptr.p_int[i-range0] = i; + diag.ptr.p_double[i-range0] = 1.0; + shft.ptr.p_double[i-range0] = 0.0; + } + idx.ptr.p_int[range1-range0] = axisidx; + diag.ptr.p_double[range1-range0] = 1.0; + shft.ptr.p_double[range1-range0] = 0.0; + alphavec.ptr.p_double[0] = ae_minreal(alpha, 1.0, _state); + + /* + * Add cone + */ + xccaddpowccprimitivecanonic(&state->xcc, &idx, &diag, &shft, range1-range0+1, &alphavec, 1, applyorigin, _state); + state->repmcc = xccgetcount(&state->xcc, _state); + result = state->repmcc-1; + + /* + * Recycle temporaries + */ + ae_nxpool_recycle(&state->n1intpool, &idx, _state); + ae_nxpool_recycle(&state->n1realpool, &diag, _state); + ae_nxpool_recycle(&state->n1realpool, &shft, _state); + ae_nxpool_recycle(&state->n1realpool, &alphavec, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function appends an axis-orthogonal power cone constraint of the form + + ( k-kp-1 ) k-1 + sqrt ( theta^2 + SUM y[i]^2 ) <= MUL y[i]^alpha[i] + ( i=0 ) i=k-kp + +where + + y[i] = a[i]*x[idx[i]]+c[i], y[i]>=0 + + 0=|theta| + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows alpha[] to sum up to any positive value less than or equal to 1 +(e.g. it is possible to formulate |x|=1. It is possible to have K>N. + Theta - additional constant term, can be zero + AlphaV - array[KPow], power coefficients: + * 0n; + ae_assert(k>=1, "MinQPAddPOWCCOrthogonal: K<1", _state); + ae_assert(kpow>=1, "MinQPAddPOWCCOrthogonal: KPow<1", _state); + ae_assert(kpow<=k, "MinQPAddPOWCCOrthogonal: KPow>K", _state); + ae_assert(idx->cnt>=k, "MinQPAddPOWCCOrthogonal: len(idx)cnt>=k, "MinQPAddPOWCCOrthogonal: len(a)cnt>=k, "MinQPAddPOWCCOrthogonal: len(c)ptr.p_int[i]>=0&&idx->ptr.p_int[i]ptr.p_double[i], _state), "MinQPAddPOWCCOrthogonal: a[] contains infinite values", _state); + ae_assert(ae_isfinite(c->ptr.p_double[i], _state), "MinQPAddPOWCCOrthogonal: c[] contains infinite values", _state); + } + ae_assert(ae_isfinite(theta, _state), "MinQPAddPOWCCOrthogonal: theta is not a finite number", _state); + vs = 0.0; + for(i=0; i<=kpow-1; i++) + { + ae_assert(ae_isfinite(alphav->ptr.p_double[i], _state), "MinQPAddPOWCCOrthogonal: alphav[] contains infinite values", _state); + ae_assert(ae_fp_greater(alphav->ptr.p_double[i],(double)(0))&&ae_fp_less_eq(alphav->ptr.p_double[i],(double)(1)), "MinQPAddPOWCCOrthogonal: one of alphav[] elements is outside of (0,1] range", _state); + vs = vs+alphav->ptr.p_double[i]; + } + ae_assert(ae_fp_greater(vs,(double)(0))&&ae_fp_less_eq(vs,(double)1+(double)(10*kpow)*ae_machineepsilon), "MinQPAddPOWCCOrthogonal: alphav[] elements do not sum to a value in the (0,1] range", _state); + + /* + * Add cone + */ + xccaddpowccorthogonalnoncanonic(&state->xcc, idx, a, c, k, theta, alphav, kpow, applyorigin, _state); + state->repmcc = xccgetcount(&state->xcc, _state); + result = state->repmcc-1; + return result; +} + + +/************************************************************************* +This function solves quadratic programming problem. + +Prior to calling this function you should choose solver by means of one of +the following functions: + +* minqpsetalgoquickqp() - for QuickQP solver +* minqpsetalgodenseaul() - for Dense-AUL-QP solver +* minqpsetalgodenseipm() - for convex Dense-IPM-QP solver +* minqpsetalgosparseipm() - for convex Sparse-IPM-QP solver +* minqpsetalgodensegenipm() - for convex/nonconvex Dense-IPM-QP solver with conic constraints +* minqpsetalgosparsegenipm()- for convex/nonconvex Sparse-IPM-QP solver with conic constraints + +These functions also allow you to control stopping criteria of the solver. +If you did not set solver, MinQP subpackage will automatically select +solver for your problem and will run it with default stopping criteria. + +However, it is better to set explicitly solver and its stopping criteria. + +INPUT PARAMETERS: + State - algorithm state + +You should use MinQPResults() function to access results after calls +to this function. + + -- ALGLIB -- + Copyright 2011-2024 by Bochkanov Sergey. + Special thanks to Elvira Illarionova for important suggestions on + the linearly constrained QP algorithm. +*************************************************************************/ +void minqpoptimize(minqpstate* state, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + ae_int_t mqc; + ae_int_t mcc; + ae_int_t i; + ae_int_t nbc; + ae_bool dotracepresolve; + ae_vector lagbcmin; + ae_vector lagbcmax; + ae_vector mods; + ae_vector modorigin; + ae_vector modbndl; + ae_vector modbndu; + ae_vector modb; + ae_vector modxs; + ae_int_t modn; + ae_int_t modm; + + ae_frame_make(_state, &_frame_block); + memset(&lagbcmin, 0, sizeof(lagbcmin)); + memset(&lagbcmax, 0, sizeof(lagbcmax)); + memset(&mods, 0, sizeof(mods)); + memset(&modorigin, 0, sizeof(modorigin)); + memset(&modbndl, 0, sizeof(modbndl)); + memset(&modbndu, 0, sizeof(modbndu)); + memset(&modb, 0, sizeof(modb)); + memset(&modxs, 0, sizeof(modxs)); + ae_vector_init(&lagbcmin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&lagbcmax, 0, DT_REAL, _state, ae_true); + ae_vector_init(&mods, 0, DT_REAL, _state, ae_true); + ae_vector_init(&modorigin, 0, DT_REAL, _state, ae_true); + ae_vector_init(&modbndl, 0, DT_REAL, _state, ae_true); + ae_vector_init(&modbndu, 0, DT_REAL, _state, ae_true); + ae_vector_init(&modb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&modxs, 0, DT_REAL, _state, ae_true); + + n = state->n; + m = state->xlc.ndense+state->xlc.nsparse; + mqc = xqcgetcount(&state->xqc, _state); + mcc = xccgetcount(&state->xcc, _state); + state->repterminationtype = -5; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repncholesky = 0; + state->repnmv = 0; + state->repn = n; + state->repm = m; + dotracepresolve = (ae_is_trace_enabled("IPM")||ae_is_trace_enabled("GENIPM"))||ae_is_trace_enabled("GIPM"); + + /* + * Zero-fill Lagrange multipliers (their initial value) + */ + ae_assert(mqc==state->repmqc, "MINQP: integrity check 1221 failed", _state); + ae_assert(mcc==state->repmcc, "MINQP: integrity check 1222 failed", _state); + state->repf = 0.0; + for(i=0; i<=n-1; i++) + { + state->replagbc.ptr.p_double[i] = 0.0; + } + for(i=0; i<=m-1; i++) + { + state->replaglc.ptr.p_double[i] = 0.0; + } + rsetv(mqc, 0.0, &state->replagqc, _state); + + /* + * Initial point: + * * if we have starting point in StartX, we just have to bound it + * * if we do not have StartX, deduce initial point from boundary constraints + */ + if( state->havex ) + { + for(i=0; i<=n-1; i++) + { + state->xs.ptr.p_double[i] = state->startx.ptr.p_double[i]; + if( state->havebndl.ptr.p_bool[i]&&ae_fp_less(state->xs.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->xs.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->havebndu.ptr.p_bool[i]&&ae_fp_greater(state->xs.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->xs.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + } + else + { + for(i=0; i<=n-1; i++) + { + state->xs.ptr.p_double[i] = state->xorigin.ptr.p_double[i]; + if( state->havebndl.ptr.p_bool[i] ) + { + state->xs.ptr.p_double[i] = ae_maxreal(state->xs.ptr.p_double[i], state->bndl.ptr.p_double[i], _state); + } + if( state->havebndu.ptr.p_bool[i] ) + { + state->xs.ptr.p_double[i] = ae_minreal(state->xs.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + } + } + + /* + * check correctness of constraints + */ + for(i=0; i<=n-1; i++) + { + if( state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i] ) + { + if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->repterminationtype = -3; + ae_frame_leave(_state); + return; + } + } + } + + /* + * count number of bound and linear constraints + */ + nbc = 0; + for(i=0; i<=n-1; i++) + { + if( state->havebndl.ptr.p_bool[i] ) + { + nbc = nbc+1; + } + if( state->havebndu.ptr.p_bool[i] ) + { + nbc = nbc+1; + } + } + + /* + * Effective scale + */ + rvectorsetlengthatleast(&state->effectives, n, _state); + if( state->stype==0 ) + { + + /* + * User scale (or default one) + */ + for(i=0; i<=n-1; i++) + { + state->effectives.ptr.p_double[i] = state->s.ptr.p_double[i]; + } + } + else + { + if( state->stype==1 ) + { + + /* + * Diagonal is used for scaling: + * * unpack + * * convert to scale, return error on failure + */ + if( state->akind==0 ) + { + + /* + * Unpack CQM structure + */ + cqmgetdiaga(&state->a, &state->effectives, _state); + } + else + { + if( state->akind==1 ) + { + for(i=0; i<=n-1; i++) + { + state->effectives.ptr.p_double[i] = sparseget(&state->sparsea, i, i, _state); + } + } + else + { + ae_assert(ae_false, "MinQPOptimize: integrity check failed", _state); + } + } + for(i=0; i<=n-1; i++) + { + if( ae_fp_less_eq(state->effectives.ptr.p_double[i],(double)(0)) ) + { + state->repterminationtype = -9; + ae_frame_leave(_state); + return; + } + state->effectives.ptr.p_double[i] = (double)1/ae_sqrt(state->effectives.ptr.p_double[i], _state); + } + } + else + { + ae_assert(ae_false, "MinQPOptimize: integrity check failed", _state); + } + } + + /* + * Solvers which can not handle new two-sided constraints need them to be + * converted into legacy equality/inequality one-sided format + */ + if( state->algokind==4 ) + { + if( xqcgetcount(&state->xqc, _state)+xccgetcount(&state->xcc, _state)>0 ) + { + state->repterminationtype = -5; + ae_frame_leave(_state); + return; + } + xlcconverttoold(&state->xlc, _state); + qpdenseauloptimize(&state->a, &state->sparsea, state->akind, state->sparseaupper, &state->b, &state->bndl, &state->bndu, &state->effectives, &state->xorigin, n, &state->xlc.cleic, state->xlc.nec, state->xlc.nic, &state->dummysparse, 0, 0, !state->dbgskipconstraintnormalization, &state->qpdenseaulsettingsuser, &state->qpdenseaulbuf, &state->xs, &state->replagbc, &state->elaglc, &state->repterminationtype, _state); + for(i=0; i<=state->xlc.nec+state->xlc.nic-1; i++) + { + state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]] = state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]]+state->elaglc.ptr.p_double[i]*state->xlc.lcsrcmult.ptr.p_double[i]; + } + state->repinneriterationscount = state->qpdenseaulbuf.repinneriterationscount; + state->repouteriterationscount = state->qpdenseaulbuf.repouteriterationscount; + state->repncholesky = state->qpdenseaulbuf.repncholesky; + if( state->repterminationtype>0 ) + { + if( state->akind==0 ) + { + state->repf = cqmeval(&state->a, &state->xs, _state); + } + if( state->akind==1 ) + { + state->repf = 0.5*sparsevsmv(&state->sparsea, state->sparseaupper, &state->xs, _state); + } + state->repf = state->repf+rdotv(n, &state->b, &state->xs, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * QuickQP solver + */ + if( state->algokind==3 ) + { + if( state->xlc.ndense+state->xlc.nsparse+xqcgetcount(&state->xqc, _state)+xccgetcount(&state->xcc, _state)>0 ) + { + state->repterminationtype = -5; + ae_frame_leave(_state); + return; + } + qqpoptimize(&state->a, &state->sparsea, &state->dummyr2, state->akind, state->sparseaupper, &state->b, &state->bndl, &state->bndu, &state->effectives, &state->xorigin, n, &state->qqpsettingsuser, &state->qqpbuf, &state->xs, &state->repterminationtype, _state); + state->repinneriterationscount = state->qqpbuf.repinneriterationscount; + state->repouteriterationscount = state->qqpbuf.repouteriterationscount; + state->repncholesky = state->qqpbuf.repncholesky; + if( state->repterminationtype>0 ) + { + if( state->akind==0 ) + { + state->repf = cqmeval(&state->a, &state->xs, _state); + } + if( state->akind==1 ) + { + state->repf = 0.5*sparsevsmv(&state->sparsea, state->sparseaupper, &state->xs, _state); + } + state->repf = state->repf+rdotv(n, &state->b, &state->xs, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * QP-DENSE-IPM and QP-SPARSE-IPM solvers + */ + if( state->algokind==5||state->algokind==6 ) + { + + /* + * Check quadratic constraints + */ + if( xqcgetcount(&state->xqc, _state)+xccgetcount(&state->xcc, _state)>0 ) + { + state->repterminationtype = -5; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + + /* + * Run presolver + */ + xlcconverttosparse(&state->xlc, _state); + ae_assert(state->akind==0||state->akind==1, "MinQPOptimize: unexpected AKind", _state); + if( state->akind==0 ) + { + cqmgeta(&state->a, &state->tmpr2, _state); + sparsecreatecrsfromdensebuf(&state->tmpr2, n, n, &state->sparsea, _state); + } + if( state->dbgdopresolve ) + { + presolveqp(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + else + { + presolvenonescaleuser(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + if( state->presolver.problemstatus==-3||state->presolver.problemstatus==-2 ) + { + state->repterminationtype = state->presolver.problemstatus; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + ae_assert(state->presolver.problemstatus==0, "MINQP: integrity check 6035 failed", _state); + + /* + * Run the solver + */ + if( state->presolver.newn>0 ) + { + if( state->algokind==5 ) + { + rsetallocv(state->presolver.newn, 0.0, &state->tmp0, _state); + rsetallocv(state->presolver.newn, 1.0, &state->tmp1, _state); + vipminitdense(&state->vsolver, &state->tmp1, &state->tmp0, state->presolver.newn, ae_false, _state); + vipmsetquadraticlinear(&state->vsolver, &state->tmpr2, &state->presolver.sparseh, 1, ae_false, &state->presolver.c, _state); + vipmsetconstraints(&state->vsolver, &state->presolver.bndl, &state->presolver.bndu, &state->presolver.sparsea, state->presolver.newm, &state->dummyr2, 0, &state->presolver.al, &state->presolver.au, _state); + vipmsetcond(&state->vsolver, state->veps, state->veps, state->veps, _state); + vipmoptimize(&state->vsolver, ae_true, &state->xs, &state->replagbc, &state->replaglc, &state->repterminationtype, _state); + state->repinneriterationscount = state->vsolver.repiterationscount; + state->repouteriterationscount = state->repinneriterationscount; + state->repncholesky = state->vsolver.repncholesky; + } + else + { + + /* + * If presolver did NOT remove all variables (NewN>0), call the current solver + */ + rsetallocv(state->presolver.newn, 0.0, &state->tmp0, _state); + rsetallocv(state->presolver.newn, 1.0, &state->tmp1, _state); + ipm2init(&state->ipm2, &state->tmp1, &state->tmp0, state->presolver.newn, &state->tmpr2, &state->presolver.sparseh, 1, ae_false, &state->dummyr2, &state->dummyr, 0, &state->presolver.c, 0.0, &state->presolver.bndl, &state->presolver.bndu, &state->presolver.sparsea, state->presolver.newm, &state->dummyr2, 0, &state->presolver.al, &state->presolver.au, ae_false, ae_true, _state); + ipm2setcond(&state->ipm2, state->veps, state->veps, state->veps, _state); + ipm2optimize(&state->ipm2, ae_true, &state->xs, &state->replagbc, &state->replaglc, &state->repterminationtype, _state); + state->repinneriterationscount = state->ipm2.repiterationscount; + state->repouteriterationscount = state->ipm2.repiterationscount; + state->repncholesky = state->ipm2.repiterationscount; + } + } + else + { + + /* + * Presolver removed all variables, manually set up XS and Lagrange multipliers + */ + rsetallocv(state->presolver.newn, 0.0, &state->replagbc, _state); + rsetallocv(state->presolver.newm, 0.0, &state->replaglc, _state); + rsetallocv(state->presolver.newmqc, 0.0, &state->replagqc, _state); + state->repterminationtype = 1; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + } + presolvebwd(&state->presolver, &state->xs, &state->tmpi, ae_false, &state->replagbc, &state->replaglc, &state->replagqc, _state); + state->repn = n; + state->repm = m; + if( state->repterminationtype>0 ) + { + if( state->akind==0 ) + { + state->repf = cqmeval(&state->a, &state->xs, _state); + } + if( state->akind==1 ) + { + state->repf = 0.5*sparsevsmv(&state->sparsea, state->sparseaupper, &state->xs, _state); + } + state->repf = state->repf+rdotv(n, &state->b, &state->xs, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * QP-DENSE-GENIPM and QP-SPARSE-GENIPM solvers + */ + if( (state->algokind==7||state->algokind==8)||state->algokind==10 ) + { + + /* + * Either run presolver directly on the original problem (when no conic constraints are + * present) or canonicalize conic constraints first and run presolver on the canonicalized + * problem. + */ + xlcconverttosparse(&state->xlc, _state); + ae_assert(state->akind==0||state->akind==1, "MinQPOptimize: unexpected AKind", _state); + if( state->akind==0 ) + { + cqmgeta(&state->a, &state->tmpr2, _state); + sparsecreatecrsfromdensebuf(&state->tmpr2, n, n, &state->sparsea, _state); + } + if( xccgetcount(&state->xcc, _state)==0 ) + { + + /* + * No conic constraints, we can use constraint information directly as is, without + * creating intermediary copies + */ + if( state->dbgdopresolve ) + { + presolveqp(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + else + { + presolvenonescaleuser(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + if( state->presolver.problemstatus==-3||state->presolver.problemstatus==-2 ) + { + state->repterminationtype = state->presolver.problemstatus; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + rsetallocv(n, -ae_maxrealnumber, &lagbcmin, _state); + rsetallocv(n, ae_maxrealnumber, &lagbcmax, _state); + } + else + { + + /* + * Canonicalize constraints by adding slack variables and modifying variable bounds if necessary. + * + * We modify XLC.EffSparseA/AL/AU inplace; however, we have to create new copies of + * S, XOrigin, Bnd/L, BndU, SparseA. + */ + rcopyallocv(n, &state->effectives, &mods, _state); + rcopyallocv(n, &state->xorigin, &modorigin, _state); + rcopyallocv(n, &state->bndl, &modbndl, _state); + rcopyallocv(n, &state->bndu, &modbndu, _state); + rcopyallocv(n, &state->b, &modb, _state); + rcopyallocv(n, &state->xs, &modxs, _state); + sparsecopybuf(&state->sparsea, &state->modsparsea, _state); + xcccopy(&state->xcc, &state->modxcc, _state); + modn = n; + modm = m; + gqpipmcanonicalizeconicconstraints(&mods, &modorigin, &modb, &modbndl, &modbndu, &modxs, &state->modsparsea, state->sparseaupper, ae_true, &modn, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &modm, &state->xqc, &state->modxcc, &lagbcmin, &lagbcmax, _state); + + /* + * Run presolver on the modified problem + */ + if( state->dbgdopresolve ) + { + presolveqp(&mods, &modorigin, &modb, &modbndl, &modbndu, &state->modsparsea, state->sparseaupper, ae_true, modn, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, modm, &state->xqc, &state->modxcc, dotracepresolve, &state->presolver, _state); + } + else + { + presolvenonescaleuser(&mods, &modorigin, &modb, &modbndl, &modbndu, &state->modsparsea, state->sparseaupper, ae_true, modn, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, modm, &state->xqc, &state->modxcc, dotracepresolve, &state->presolver, _state); + } + rcopyallocv(modn, &modxs, &state->xs, _state); + + /* + * Done + */ + if( state->presolver.problemstatus==-3||state->presolver.problemstatus==-2 ) + { + state->repterminationtype = state->presolver.problemstatus; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + } + ae_assert(state->presolver.problemstatus==0, "MINQP: integrity check 7828 failed", _state); + + /* + * Run the solver + */ + if( state->presolver.newn>0 ) + { + presolvefwd(&state->presolver, &state->xs, _state); + gqpipminitbuf(&state->presolver.bndl, &state->presolver.bndu, &state->xs, state->presolver.newn, state->algokind==7, state->algokind==10, state->veps, state->gmaxits, &state->genipm, _state); + gqpipmsetquadraticlinear(&state->genipm, &state->tmpr2, &state->presolver.sparseh, 1, &state->presolver.c, _state); + gqpipmsetconstraints(&state->genipm, &state->presolver.sparsea, &state->presolver.al, &state->presolver.au, state->presolver.newm, &state->presolver.xqc, &state->presolver.xcc, _state); + if( state->algokind==10 ) + { + gqpipmsetquasinewtonparams(&state->genipm, state->vmemlen, state->vmaxoffdiag, _state); + } + gqpipmoptimize(&state->genipm, &state->xs, &state->replagbc, &state->replaglc, &state->replagqc, &state->repterminationtype, _state); + state->repinneriterationscount = state->genipm.repiterationscount; + state->repouteriterationscount = state->genipm.repiterationscount; + state->repncholesky = state->genipm.repiterationscount; + } + else + { + + /* + * Presolver removed all variables, manually set up XS and Lagrange multipliers + */ + rsetallocv(state->presolver.newn, 0.0, &state->replagbc, _state); + rsetallocv(state->presolver.newm, 0.0, &state->replaglc, _state); + rsetallocv(state->presolver.newmqc, 0.0, &state->replagqc, _state); + state->repterminationtype = 1; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + } + presolvebwd(&state->presolver, &state->xs, &state->tmpi, ae_false, &state->replagbc, &state->replaglc, &state->replagqc, _state); + rmergemaxv(n, &lagbcmin, &state->replagbc, _state); + rmergeminv(n, &lagbcmax, &state->replagbc, _state); + state->repn = n; + state->repm = m; + if( state->repterminationtype>0 ) + { + if( state->akind==0 ) + { + state->repf = cqmeval(&state->a, &state->xs, _state); + } + if( state->akind==1 ) + { + state->repf = 0.5*sparsevsmv(&state->sparsea, state->sparseaupper, &state->xs, _state); + } + state->repf = state->repf+rdotv(n, &state->b, &state->xs, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * ECQP + */ + if( state->algokind==9 ) + { + + /* + * Check constraints + */ + xlcconverttosparse(&state->xlc, _state); + if( xqcgetcount(&state->xqc, _state)+xccgetcount(&state->xcc, _state)>0 ) + { + state->repterminationtype = -5; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + if( !ae_isfinite(state->bndl.ptr.p_double[i], _state)&&!ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + continue; + } + if( (ae_isfinite(state->bndl.ptr.p_double[i], _state)&&ae_isfinite(state->bndu.ptr.p_double[i], _state))&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + continue; + } + state->repterminationtype = -5; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + for(i=0; i<=m-1; i++) + { + if( !ae_isfinite(state->xlc.effal.ptr.p_double[i], _state)&&!ae_isfinite(state->xlc.effau.ptr.p_double[i], _state) ) + { + continue; + } + if( (ae_isfinite(state->xlc.effal.ptr.p_double[i], _state)&&ae_isfinite(state->xlc.effau.ptr.p_double[i], _state))&&ae_fp_eq(state->xlc.effal.ptr.p_double[i],state->xlc.effau.ptr.p_double[i]) ) + { + continue; + } + state->repterminationtype = -5; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + + /* + * Run presolver + */ + ae_assert(state->akind==0||state->akind==1, "MinQPOptimize: unexpected AKind", _state); + if( state->akind==0 ) + { + cqmgeta(&state->a, &state->tmpr2, _state); + sparsecreatecrsfromdensebuf(&state->tmpr2, n, n, &state->sparsea, _state); + } + if( state->dbgdopresolve ) + { + presolveqp(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + else + { + presolvenonescaleuser(&state->effectives, &state->xorigin, &state->b, &state->bndl, &state->bndu, &state->sparsea, state->sparseaupper, ae_true, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, m, &state->xqc, &state->xcc, dotracepresolve, &state->presolver, _state); + } + if( state->presolver.problemstatus==-3||state->presolver.problemstatus==-2 ) + { + state->repterminationtype = state->presolver.problemstatus; + rsetallocv(n, 0.0, &state->xs, _state); + ae_frame_leave(_state); + return; + } + ae_assert(state->presolver.problemstatus==0, "MINQP: integrity check 8938 failed", _state); + + /* + * Run the solver + */ + if( state->presolver.newn>0 ) + { + + /* + * If presolver did NOT remove all variables (NewN>0), call the current solver. + * Below we assume that the presolver returned an equality constrained problem. + */ + ecqpsolve(&state->ecqp, state->presolver.newn, &state->presolver.sparseh, &state->presolver.c, &state->presolver.sparsea, &state->presolver.al, state->presolver.newm, &state->xs, &state->replaglc, &state->repterminationtype, _state); + state->repinneriterationscount = state->ecqp.repiterationscount; + state->repouteriterationscount = state->ecqp.repiterationscount; + state->repncholesky = state->ecqp.repiterationscount; + } + else + { + + /* + * Presolver removed all variables, manually set up XS and Lagrange multipliers + */ + rsetallocv(state->presolver.newn, 0.0, &state->replagbc, _state); + rsetallocv(state->presolver.newm, 0.0, &state->replaglc, _state); + rsetallocv(state->presolver.newmqc, 0.0, &state->replagqc, _state); + state->repterminationtype = 1; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + } + presolvebwd(&state->presolver, &state->xs, &state->tmpi, ae_false, &state->replagbc, &state->replaglc, &state->replagqc, _state); + state->repn = n; + state->repm = m; + if( state->repterminationtype>0 ) + { + if( state->akind==0 ) + { + state->repf = cqmeval(&state->a, &state->xs, _state); + } + if( state->akind==1 ) + { + state->repf = 0.5*sparsevsmv(&state->sparsea, state->sparseaupper, &state->xs, _state); + } + state->repf = state->repf+rdotv(n, &state->b, &state->xs, _state); + } + ae_frame_leave(_state); + return; + } + + /* + * Integrity check failed - unknown solver + */ + ae_assert(ae_false, "MinQPOptimize: integrity check failed - unknown solver", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +QP solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution (on failure - the best point found + so far). + Rep - optimization report, contains: + * completion code in Rep.TerminationType (positive values + denote some kind of success, negative - failures) + * Lagrange multipliers - for QP solvers which support them + * other statistics + See comments on minqpreport structure for more information + +Following completion codes are returned in Rep.TerminationType: +* -9 failure of the automatic scale evaluation: one of the diagonal + elements of the quadratic term is non-positive. Specify variable + scales manually! +* -5 inappropriate solver was used: + * QuickQP solver for problem with general linear constraints + * QuickQP/DENSE-AUL/DENSE-IPM/SPARSE-IPM for a problem with + quadratic/conic constraints +* -4 the function is unbounded from below even under constraints, + no meaningful minimum can be found. +* -3 inconsistent constraints (or, maybe, feasible point is too hard to + find). +* -2 IPM solver has difficulty finding primal/dual feasible point. + It is likely that the problem is either infeasible or unbounded, + but it is difficult to determine exact reason for termination. + X contains best point found so far. +* >0 success +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresults(const minqpstate* state, + /* Real */ ae_vector* x, + minqpreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minqpreport_clear(rep); + + minqpresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +QP results + +Buffered implementation of MinQPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresultsbuf(const minqpstate* state, + /* Real */ ae_vector* x, + minqpreport* rep, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(state->xs.cnt>=state->n, "MinQPResultsBuf: integrity check failed", _state); + ae_assert(state->replagbc.cnt>=state->n, "MinQPResultsBuf: integrity check failed", _state); + ae_assert(state->replaglc.cnt>=state->xlc.ndense+state->xlc.nsparse, "MinQPResultsBuf: integrity check failed", _state); + ae_assert(state->replagqc.cnt>=state->repmqc, "MinQPResultsBuf: integrity check failed", _state); + rvectorsetlengthatleast(x, state->n, _state); + rvectorsetlengthatleast(&rep->lagbc, state->n, _state); + rvectorsetlengthatleast(&rep->laglc, state->xlc.ndense+state->xlc.nsparse, _state); + rcopyallocv(state->repmqc, &state->replagqc, &rep->lagqc, _state); + for(i=0; i<=state->n-1; i++) + { + x->ptr.p_double[i] = state->xs.ptr.p_double[i]; + rep->lagbc.ptr.p_double[i] = state->replagbc.ptr.p_double[i]; + } + for(i=0; i<=state->xlc.ndense+state->xlc.nsparse-1; i++) + { + rep->laglc.ptr.p_double[i] = state->replaglc.ptr.p_double[i]; + } + rep->inneriterationscount = state->repinneriterationscount; + rep->outeriterationscount = state->repouteriterationscount; + rep->nmv = state->repnmv; + rep->ncholesky = state->repncholesky; + rep->terminationtype = state->repterminationtype; + rep->f = state->repf; +} + + +/************************************************************************* +Export current QP problem stored in the solver into QPXProblem instance. +This instance can be serialized into ALGLIB-specific format and +unserialized from several widely acknowledged formats. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpexport(minqpstate* state, qpxproblem* p, ae_state *_state) +{ + ae_frame _frame_block; + ae_bool done; + ae_bool isdifferent; + ae_int_t i; + ae_matrix tmpr2; + sparsematrix tmpa; + + ae_frame_make(_state, &_frame_block); + memset(&tmpr2, 0, sizeof(tmpr2)); + memset(&tmpa, 0, sizeof(tmpa)); + _qpxproblem_clear(p); + ae_matrix_init(&tmpr2, 0, 0, DT_REAL, _state, ae_true); + _sparsematrix_init(&tmpa, _state, ae_true); + + qpxproblemcreate(state->n, p, _state); + + /* + * Optional terms: scales, origin, initial point + */ + if( state->havex ) + { + qpxproblemsetinitialpoint(p, &state->startx, _state); + } + isdifferent = ae_false; + for(i=0; i<=state->n-1; i++) + { + isdifferent = isdifferent||state->s.ptr.p_double[i]!=1.0; + } + if( isdifferent ) + { + qpxproblemsetscale(p, &state->s, _state); + } + isdifferent = ae_false; + for(i=0; i<=state->n-1; i++) + { + isdifferent = isdifferent||state->xorigin.ptr.p_double[i]!=0.0; + } + if( isdifferent ) + { + qpxproblemsetorigin(p, &state->xorigin, _state); + } + + /* + * Mandatory terms: objective, box constraints, linear and quadratic constraints + */ + qpxproblemsetlinearterm(p, &state->b, _state); + done = ae_false; + if( state->akind==0 ) + { + cqmgeta(&state->a, &tmpr2, _state); + sparsecreatecrsfromdensebuf(&tmpr2, state->n, state->n, &tmpa, _state); + qpxproblemsetquadraticterm(p, &tmpa, ae_false, _state); + done = ae_true; + } + if( state->akind==1 ) + { + qpxproblemsetquadraticterm(p, &state->sparsea, state->sparseaupper, _state); + done = ae_true; + } + ae_assert(done, "MinQPExport: unexpected AKind", _state); + qpxproblemsetbc(p, &state->bndl, &state->bndu, _state); + if( state->xlc.nsparse+state->xlc.ndense>0 ) + { + xlcconverttosparse(&state->xlc, _state); + qpxproblemsetlc2(p, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, state->xlc.nsparse+state->xlc.ndense, _state); + } + if( xqcgetcount(&state->xqc, _state)>0 ) + { + qpxproblemsetxqc(p, &state->xqc, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Imports QP problem, as defined by QPXProblem instance, creating a QP solver +with objective/constraints/scales/origin set to that stored in the instance. + +INPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + +OUTPUT PARAMETERS: + State - newly created solver + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpimport(qpxproblem* p, minqpstate* s, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t n; + ae_int_t m; + double v0; + double v1; + ae_bool b0; + ae_vector t1; + ae_vector t1a; + sparsematrix s2; + ae_bool isupper; + + ae_frame_make(_state, &_frame_block); + memset(&t1, 0, sizeof(t1)); + memset(&t1a, 0, sizeof(t1a)); + memset(&s2, 0, sizeof(s2)); + _minqpstate_clear(s); + ae_vector_init(&t1, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t1a, 0, DT_REAL, _state, ae_true); + _sparsematrix_init(&s2, _state, ae_true); + + ae_assert(qpxproblemisquadraticobjective(p, _state), "MinQPImport: nonquadratic objectives are not supported", _state); + ae_assert(qpxproblemgettotalconstraints(p, _state)==qpxproblemgetmlc(p, _state)+qpxproblemgetmqc(p, _state)+qpxproblemgetmcc(p, _state), "MinQPImport: unknown constraint type detected", _state); + + /* + * Create the solver + */ + n = qpxproblemgetn(p, _state); + minqpcreate(n, s, _state); + + /* + * Optional terms: scales, origin, initial point + */ + if( qpxproblemhasinitialpoint(p, _state) ) + { + qpxproblemgetinitialpoint(p, &t1, _state); + minqpsetstartingpoint(s, &t1, _state); + } + if( qpxproblemhasscale(p, _state) ) + { + qpxproblemgetscale(p, &t1, _state); + minqpsetscale(s, &t1, _state); + } + if( qpxproblemhasorigin(p, _state) ) + { + qpxproblemgetorigin(p, &t1, _state); + minqpsetorigin(s, &t1, _state); + } + + /* + * Mandatory terms: objective, box constraints, linear and quadratic constraints + */ + qpxproblemgetlinearterm(p, &t1, _state); + minqpsetlinearterm(s, &t1, _state); + qpxproblemgetquadraticterm(p, &s2, &isupper, _state); + minqpsetquadratictermsparse(s, &s2, isupper, _state); + qpxproblemgetbc(p, &t1, &t1a, _state); + minqpsetbc(s, &t1, &t1a, _state); + if( qpxproblemgetmlc(p, _state)>0 ) + { + qpxproblemgetlc2(p, &s2, &t1, &t1a, &m, _state); + minqpsetlc2(s, &s2, &t1, &t1a, m, _state); + } + if( qpxproblemgetmqc(p, _state)>0 ) + { + m = qpxproblemgetmqc(p, _state); + for(i=0; i<=m-1; i++) + { + qpxproblemgetqc2i(p, i, &s2, &isupper, &t1, &v0, &v1, &b0, _state); + minqpaddqc2(s, &s2, isupper, &t1, v0, v1, b0, _state); + } + } + ae_assert(qpxproblemgetmcc(p, _state)==0, "MinQPImport: conic constraints are not supported yet", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Fast version of MinQPSetLinearTerm(), which doesn't check its arguments. +For internal use only. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlineartermfast(minqpstate* state, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + + + ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); +} + + +/************************************************************************* +Fast version of MinQPSetQuadraticTerm(), which doesn't check its arguments. + +It accepts additional parameter - shift S, which allows to "shift" matrix +A by adding s*I to A. S must be positive (although it is not checked). + +For internal use only. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetquadratictermfast(minqpstate* state, + /* Real */ const ae_matrix* a, + ae_bool isupper, + double s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + double v; + ae_int_t j0; + ae_int_t j1; + + + n = state->n; + state->akind = 0; + if( !state->cqmready ) + { + cqminit(n, &state->a, _state); + state->cqmready = ae_true; + } + cqmseta(&state->a, a, isupper, 1.0, _state); + if( ae_fp_greater(s,(double)(0)) ) + { + rvectorsetlengthatleast(&state->tmp0, n, _state); + for(i=0; i<=n-1; i++) + { + state->tmp0.ptr.p_double[i] = a->ptr.pp_double[i][i]+s; + } + cqmrewritedensediagonal(&state->a, &state->tmp0, _state); + } + + /* + * Estimate norm of A + * (it will be used later in the quadratic penalty function) + */ + state->absamax = (double)(0); + state->absasum = (double)(0); + state->absasum2 = (double)(0); + for(i=0; i<=n-1; i++) + { + if( isupper ) + { + j0 = i; + j1 = n-1; + } + else + { + j0 = 0; + j1 = i; + } + for(j=j0; j<=j1; j++) + { + v = ae_fabs(a->ptr.pp_double[i][j], _state); + state->absamax = ae_maxreal(state->absamax, v, _state); + state->absasum = state->absasum+v; + state->absasum2 = state->absasum2+v*v; + } + } +} + + +/************************************************************************* +Internal function which allows to rewrite diagonal of quadratic term. +For internal use only. + +This function can be used only when you have dense A and already made +MinQPSetQuadraticTerm(Fast) call. + + -- ALGLIB -- + Copyright 16.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqprewritediagonal(minqpstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + + + cqmrewritedensediagonal(&state->a, s, _state); +} + + +/************************************************************************* +Fast version of MinQPSetStartingPoint(), which doesn't check its arguments. +For internal use only. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetstartingpointfast(minqpstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->havex = ae_true; +} + + +/************************************************************************* +Fast version of MinQPSetOrigin(), which doesn't check its arguments. +For internal use only. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetoriginfast(minqpstate* state, + /* Real */ const ae_vector* xorigin, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_v_move(&state->xorigin.ptr.p_double[0], 1, &xorigin->ptr.p_double[0], 1, ae_v_len(0,n-1)); +} + + +void _minqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minqpstate *p = (minqpstate*)_p; + ae_touch_ptr((void*)p); + _qqpsettings_init(&p->qqpsettingsuser, _state, make_automatic); + _qpdenseaulsettings_init(&p->qpdenseaulsettingsuser, _state, make_automatic); + _convexquadraticmodel_init(&p->a, _state, make_automatic); + _sparsematrix_init(&p->sparsea, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->xorigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->startx, 0, DT_REAL, _state, make_automatic); + _xlinearconstraints_init(&p->xlc, _state, make_automatic); + _xquadraticconstraints_init(&p->xqc, _state, make_automatic); + _xconicconstraints_init(&p->xcc, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagqc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effectives, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->elaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummyr, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummyr2, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->dummysparse, _state, make_automatic); + ae_matrix_init(&p->tmpr2, 0, 0, DT_REAL, _state, make_automatic); + _presolveinfo_init(&p->presolver, _state, make_automatic); + ae_nxpool_init(&p->n1realpool, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->n1intpool, DT_INT, _state, make_automatic); + _qqpbuffers_init(&p->qqpbuf, _state, make_automatic); + _qpdenseaulbuffers_init(&p->qpdenseaulbuf, _state, make_automatic); + _vipmstate_init(&p->vsolver, _state, make_automatic); + _ipm2state_init(&p->ipm2, _state, make_automatic); + _ecqpstate_init(&p->ecqp, _state, make_automatic); + _gqpipmstate_init(&p->genipm, _state, make_automatic); + _sparsematrix_init(&p->modsparsea, _state, make_automatic); + _xconicconstraints_init(&p->modxcc, _state, make_automatic); +} + + +void _minqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minqpstate *dst = (minqpstate*)_dst; + const minqpstate *src = (const minqpstate*)_src; + dst->n = src->n; + _qqpsettings_init_copy(&dst->qqpsettingsuser, &src->qqpsettingsuser, _state, make_automatic); + _qpdenseaulsettings_init_copy(&dst->qpdenseaulsettingsuser, &src->qpdenseaulsettingsuser, _state, make_automatic); + dst->veps = src->veps; + dst->vmemlen = src->vmemlen; + dst->vmaxoffdiag = src->vmaxoffdiag; + dst->gmaxits = src->gmaxits; + dst->dbgskipconstraintnormalization = src->dbgskipconstraintnormalization; + dst->dbgdopresolve = src->dbgdopresolve; + dst->algokind = src->algokind; + dst->akind = src->akind; + _convexquadraticmodel_init_copy(&dst->a, &src->a, _state, make_automatic); + dst->cqmready = src->cqmready; + _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state, make_automatic); + dst->sparseaupper = src->sparseaupper; + dst->absamax = src->absamax; + dst->absasum = src->absasum; + dst->absasum2 = src->absasum2; + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->stype = src->stype; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic); + ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic); + ae_vector_init_copy(&dst->xorigin, &src->xorigin, _state, make_automatic); + ae_vector_init_copy(&dst->startx, &src->startx, _state, make_automatic); + dst->havex = src->havex; + _xlinearconstraints_init_copy(&dst->xlc, &src->xlc, _state, make_automatic); + _xquadraticconstraints_init_copy(&dst->xqc, &src->xqc, _state, make_automatic); + _xconicconstraints_init_copy(&dst->xcc, &src->xcc, _state, make_automatic); + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + dst->repf = src->repf; + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repncholesky = src->repncholesky; + dst->repnmv = src->repnmv; + dst->repterminationtype = src->repterminationtype; + ae_vector_init_copy(&dst->replagbc, &src->replagbc, _state, make_automatic); + ae_vector_init_copy(&dst->replaglc, &src->replaglc, _state, make_automatic); + ae_vector_init_copy(&dst->replagqc, &src->replagqc, _state, make_automatic); + dst->repn = src->repn; + dst->repm = src->repm; + dst->repmqc = src->repmqc; + dst->repmcc = src->repmcc; + ae_vector_init_copy(&dst->effectives, &src->effectives, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_vector_init_copy(&dst->elaglc, &src->elaglc, _state, make_automatic); + ae_vector_init_copy(&dst->dummyr, &src->dummyr, _state, make_automatic); + ae_matrix_init_copy(&dst->dummyr2, &src->dummyr2, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysparse, &src->dummysparse, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpr2, &src->tmpr2, _state, make_automatic); + _presolveinfo_init_copy(&dst->presolver, &src->presolver, _state, make_automatic); + ae_nxpool_init_copy(&dst->n1realpool, &src->n1realpool, _state, make_automatic); + ae_nxpool_init_copy(&dst->n1intpool, &src->n1intpool, _state, make_automatic); + _qqpbuffers_init_copy(&dst->qqpbuf, &src->qqpbuf, _state, make_automatic); + _qpdenseaulbuffers_init_copy(&dst->qpdenseaulbuf, &src->qpdenseaulbuf, _state, make_automatic); + _vipmstate_init_copy(&dst->vsolver, &src->vsolver, _state, make_automatic); + _ipm2state_init_copy(&dst->ipm2, &src->ipm2, _state, make_automatic); + _ecqpstate_init_copy(&dst->ecqp, &src->ecqp, _state, make_automatic); + _gqpipmstate_init_copy(&dst->genipm, &src->genipm, _state, make_automatic); + _sparsematrix_init_copy(&dst->modsparsea, &src->modsparsea, _state, make_automatic); + _xconicconstraints_init_copy(&dst->modxcc, &src->modxcc, _state, make_automatic); +} + + +void _minqpstate_clear(void* _p) +{ + minqpstate *p = (minqpstate*)_p; + ae_touch_ptr((void*)p); + _qqpsettings_clear(&p->qqpsettingsuser); + _qpdenseaulsettings_clear(&p->qpdenseaulsettingsuser); + _convexquadraticmodel_clear(&p->a); + _sparsematrix_clear(&p->sparsea); + ae_vector_clear(&p->b); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->s); + ae_vector_clear(&p->havebndl); + ae_vector_clear(&p->havebndu); + ae_vector_clear(&p->xorigin); + ae_vector_clear(&p->startx); + _xlinearconstraints_clear(&p->xlc); + _xquadraticconstraints_clear(&p->xqc); + _xconicconstraints_clear(&p->xcc); + ae_vector_clear(&p->xs); + ae_vector_clear(&p->replagbc); + ae_vector_clear(&p->replaglc); + ae_vector_clear(&p->replagqc); + ae_vector_clear(&p->effectives); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmpi); + ae_vector_clear(&p->elaglc); + ae_vector_clear(&p->dummyr); + ae_matrix_clear(&p->dummyr2); + _sparsematrix_clear(&p->dummysparse); + ae_matrix_clear(&p->tmpr2); + _presolveinfo_clear(&p->presolver); + ae_nxpool_clear(&p->n1realpool); + ae_nxpool_clear(&p->n1intpool); + _qqpbuffers_clear(&p->qqpbuf); + _qpdenseaulbuffers_clear(&p->qpdenseaulbuf); + _vipmstate_clear(&p->vsolver); + _ipm2state_clear(&p->ipm2); + _ecqpstate_clear(&p->ecqp); + _gqpipmstate_clear(&p->genipm); + _sparsematrix_clear(&p->modsparsea); + _xconicconstraints_clear(&p->modxcc); +} + + +void _minqpstate_destroy(void* _p) +{ + minqpstate *p = (minqpstate*)_p; + ae_touch_ptr((void*)p); + _qqpsettings_destroy(&p->qqpsettingsuser); + _qpdenseaulsettings_destroy(&p->qpdenseaulsettingsuser); + _convexquadraticmodel_destroy(&p->a); + _sparsematrix_destroy(&p->sparsea); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->havebndl); + ae_vector_destroy(&p->havebndu); + ae_vector_destroy(&p->xorigin); + ae_vector_destroy(&p->startx); + _xlinearconstraints_destroy(&p->xlc); + _xquadraticconstraints_destroy(&p->xqc); + _xconicconstraints_destroy(&p->xcc); + ae_vector_destroy(&p->xs); + ae_vector_destroy(&p->replagbc); + ae_vector_destroy(&p->replaglc); + ae_vector_destroy(&p->replagqc); + ae_vector_destroy(&p->effectives); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmpi); + ae_vector_destroy(&p->elaglc); + ae_vector_destroy(&p->dummyr); + ae_matrix_destroy(&p->dummyr2); + _sparsematrix_destroy(&p->dummysparse); + ae_matrix_destroy(&p->tmpr2); + _presolveinfo_destroy(&p->presolver); + ae_nxpool_destroy(&p->n1realpool); + ae_nxpool_destroy(&p->n1intpool); + _qqpbuffers_destroy(&p->qqpbuf); + _qpdenseaulbuffers_destroy(&p->qpdenseaulbuf); + _vipmstate_destroy(&p->vsolver); + _ipm2state_destroy(&p->ipm2); + _ecqpstate_destroy(&p->ecqp); + _gqpipmstate_destroy(&p->genipm); + _sparsematrix_destroy(&p->modsparsea); + _xconicconstraints_destroy(&p->modxcc); +} + + +void _minqpreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minqpreport *p = (minqpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->lagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagqc, 0, DT_REAL, _state, make_automatic); +} + + +void _minqpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minqpreport *dst = (minqpreport*)_dst; + const minqpreport *src = (const minqpreport*)_src; + dst->inneriterationscount = src->inneriterationscount; + dst->outeriterationscount = src->outeriterationscount; + dst->nmv = src->nmv; + dst->ncholesky = src->ncholesky; + dst->terminationtype = src->terminationtype; + dst->f = src->f; + ae_vector_init_copy(&dst->lagbc, &src->lagbc, _state, make_automatic); + ae_vector_init_copy(&dst->laglc, &src->laglc, _state, make_automatic); + ae_vector_init_copy(&dst->lagqc, &src->lagqc, _state, make_automatic); +} + + +void _minqpreport_clear(void* _p) +{ + minqpreport *p = (minqpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->lagbc); + ae_vector_clear(&p->laglc); + ae_vector_clear(&p->lagqc); +} + + +void _minqpreport_destroy(void* _p) +{ + minqpreport *p = (minqpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->lagbc); + ae_vector_destroy(&p->laglc); + ae_vector_destroy(&p->lagqc); +} + + +#endif +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) + + +void minfsqpinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + const nlpstoppingcriteria* criteria, + ae_bool usedensebfgs, + minfsqpstate* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t nslack; + + + nslack = n+2*lccnt+2*nnlc; + state->n = n; + state->lccnt = lccnt; + state->nnlc = nnlc; + state->additsforctol = 0; + state->ctol = (double)(0); + + /* + * Prepare RCOMM state + */ + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ba, 14+1, _state); + ae_vector_set_length(&state->rstate.ra, 17+1, _state); + state->rstate.stage = -1; + state->needfisj = ae_false; + state->xupdated = ae_false; + rallocv(n, &state->x, _state); + rallocv(1+nnlc, &state->fi, _state); + + /* + * Allocate memory. + */ + rallocv(n, &state->x0, _state); + rallocv(n, &state->xprev, _state); + rvectorsetlengthatleast(&state->s, n, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rvectorsetlengthatleast(&state->scaledbndl, n, _state); + rvectorsetlengthatleast(&state->scaledbndu, n, _state); + rvectorsetlengthatleast(&state->dtrial, nslack, _state); + rvectorsetlengthatleast(&state->d0, nslack, _state); + rvectorsetlengthatleast(&state->dmu, nslack, _state); + rvectorsetlengthatleast(&state->lagbcmult, n, _state); + rvectorsetlengthatleast(&state->dummylagbcmult, n, _state); + rvectorsetlengthatleast(&state->lagxcmult, lccnt+nnlc, _state); + rvectorsetlengthatleast(&state->dummylagxcmult, lccnt+nnlc, _state); + ballocv(nnlc, &state->hasnl, _state); + ballocv(nnlc, &state->hasnu, _state); + rallocv(nnlc, &state->rawnl, _state); + rallocv(nnlc, &state->rawnu, _state); + + /* + * Prepare scaled problem + */ + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->scaledbndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->scaledbndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "SQP: integrity check failed, box constraints are inconsistent", _state); + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + if( lccnt>0 ) + { + rsetallocv(lccnt, 1.0, &state->lcscales, _state); + iallocv(lccnt, &state->lcsrcidx, _state); + bsetallocv(lccnt, ae_false, &state->hasal, _state); + bsetallocv(lccnt, ae_false, &state->hasau, _state); + rallocv(lccnt, &state->sclal, _state); + rallocv(lccnt, &state->sclau, _state); + sparsecopytocrsbuf(sparsea, &state->scla, _state); + for(i=0; i<=lccnt-1; i++) + { + state->lcsrcidx.ptr.p_int[i] = lcsrcidx->ptr.p_int[i]; + + /* + * Scale and normalize linear constraints + */ + vv = 0.0; + j0 = state->scla.ridx.ptr.p_int[i]; + j1 = state->scla.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + v = state->scla.vals.ptr.p_double[jj]*s->ptr.p_double[state->scla.idx.ptr.p_int[jj]]; + state->scla.vals.ptr.p_double[jj] = v; + vv = vv+v*v; + } + vv = coalesce(ae_sqrt(vv, _state), (double)(1), _state); + state->lcscales.ptr.p_double[i] = vv; + vv = (double)1/vv; + for(jj=j0; jj<=j1; jj++) + { + state->scla.vals.ptr.p_double[jj] = state->scla.vals.ptr.p_double[jj]*vv; + } + if( ae_isfinite(al->ptr.p_double[i], _state) ) + { + state->hasal.ptr.p_bool[i] = ae_true; + state->sclal.ptr.p_double[i] = al->ptr.p_double[i]*vv; + } + else + { + state->sclal.ptr.p_double[i] = _state->v_neginf; + } + if( ae_isfinite(au->ptr.p_double[i], _state) ) + { + state->hasau.ptr.p_bool[i] = ae_true; + state->sclau.ptr.p_double[i] = au->ptr.p_double[i]*vv; + } + else + { + state->sclau.ptr.p_double[i] = _state->v_posinf; + } + } + } + for(i=0; i<=nnlc-1; i++) + { + state->hasnl.ptr.p_bool[i] = ae_isfinite(nl->ptr.p_double[i], _state); + state->hasnu.ptr.p_bool[i] = ae_isfinite(nu->ptr.p_double[i], _state); + state->rawnl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->rawnu.ptr.p_double[i] = nu->ptr.p_double[i]; + } + + /* + * Initial enforcement of box constraints + */ + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + state->x0.ptr.p_double[i] = ae_maxreal(state->x0.ptr.p_double[i], state->scaledbndl.ptr.p_double[i], _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->x0.ptr.p_double[i] = ae_minreal(state->x0.ptr.p_double[i], state->scaledbndu.ptr.p_double[i], _state); + } + } + + /* + * Stopping criteria and settings + */ + critcopy(criteria, &state->criteria, _state); + state->bfgsresetfreq = nlcfsqp_defaultbfgsresetfreq; + state->usedensebfgs = usedensebfgs; + state->inittrustrad = nlcfsqp_definittrustrad; + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repsclerr = (double)(0); + state->repiterationscount = 0; + + /* + * Integrity checks + */ + ae_assert(ae_fp_less(nlcfsqp_sqpdeltadecrease,nlcfsqp_sqpdeltaincrease), "MinSQP: integrity check failed", _state); +} + + +/************************************************************************* +This function sets the number additional iterations that can be performed +after reaching MaxIts limit, if the current point is infeasible (scaled +constraint violation is above CTol), but there was a feasible point in the +optimization history. + +Up to AddIts iterations will be performed, with iterations being terminated +immediately after reaching CTol level of error. + +INPUT PARAMETERS: + State - solver state + CTol - scaled constraint violation tolerance. Points with + violation below or at CTol are considered feasible + + Do not use zero value because it is likely to + reject points with even a tiny violation of + constraints. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +void minfsqpsetadditsforctol(minfsqpstate* state, + ae_int_t addits, + double ctol, + ae_state *_state) +{ + + + state->additsforctol = addits; + state->ctol = ctol; +} + + +/************************************************************************* +This function sets initial trust radius + +INPUT PARAMETERS: + State - solver state + Rad0 - initial trust radius, Rad0>0 + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +void minfsqpsetinittrustrad(minfsqpstate* state, + double rad0, + ae_state *_state) +{ + + + state->inittrustrad = rad0; +} + + +/************************************************************************* +This function performs actual processing for SQP algorithm. It expects +that caller redirects its reverse communication requests NeedFiJ/XUpdated +to external user who will provide analytic derivative (or handle reports +about progress). + +In case external user does not have analytic derivative, it is responsibility +of caller to intercept NeedFiJ request and replace it with appropriate +numerical differentiation scheme. + +Results are stored: +* point - in State.StepKX.X, State.StepKX.Fi + +IMPORTANT: this function works with scaled problem formulation; it is + responsibility of the caller to unscale request and scale + Jacobian. + +NOTE: SMonitor is expected to be correctly initialized smoothness monitor. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +ae_bool minfsqpiteration(minfsqpstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double mx; + double deltamax; + double multiplyby; + double setscaleto; + double prevtrustrad; + ae_bool trustradstagnated; + double relativetargetdecrease; + ae_bool dotrace; + ae_bool dotracelaconic; + ae_bool doprobingalways; + ae_bool doprobingonfailure; + ae_bool dodetailedtrace; + ae_bool meritfstagnated; + double tgt0; + double h0; + double tgt1; + double h1; + double tol; + double stepklagval; + double stepknlagval; + double d2trustradratio; + double predictedchangemodel; + double predictedchangepenalty; + ae_bool infinitiesdetected; + ae_bool failedtorecoverfrominfinities; + ae_bool isinfeasible; + ae_bool feasibilityrestoration; + ae_bool firstrestorationiteration; + ae_bool stepfailed; + ae_bool restartiteration; + ae_bool leavefeasibilityrestoration; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + lccnt = state->rstate.ia.ptr.p_int[1]; + nnlc = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + j = state->rstate.ia.ptr.p_int[4]; + trustradstagnated = state->rstate.ba.ptr.p_bool[0]; + dotrace = state->rstate.ba.ptr.p_bool[1]; + dotracelaconic = state->rstate.ba.ptr.p_bool[2]; + doprobingalways = state->rstate.ba.ptr.p_bool[3]; + doprobingonfailure = state->rstate.ba.ptr.p_bool[4]; + dodetailedtrace = state->rstate.ba.ptr.p_bool[5]; + meritfstagnated = state->rstate.ba.ptr.p_bool[6]; + infinitiesdetected = state->rstate.ba.ptr.p_bool[7]; + failedtorecoverfrominfinities = state->rstate.ba.ptr.p_bool[8]; + isinfeasible = state->rstate.ba.ptr.p_bool[9]; + feasibilityrestoration = state->rstate.ba.ptr.p_bool[10]; + firstrestorationiteration = state->rstate.ba.ptr.p_bool[11]; + stepfailed = state->rstate.ba.ptr.p_bool[12]; + restartiteration = state->rstate.ba.ptr.p_bool[13]; + leavefeasibilityrestoration = state->rstate.ba.ptr.p_bool[14]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + mx = state->rstate.ra.ptr.p_double[2]; + deltamax = state->rstate.ra.ptr.p_double[3]; + multiplyby = state->rstate.ra.ptr.p_double[4]; + setscaleto = state->rstate.ra.ptr.p_double[5]; + prevtrustrad = state->rstate.ra.ptr.p_double[6]; + relativetargetdecrease = state->rstate.ra.ptr.p_double[7]; + tgt0 = state->rstate.ra.ptr.p_double[8]; + h0 = state->rstate.ra.ptr.p_double[9]; + tgt1 = state->rstate.ra.ptr.p_double[10]; + h1 = state->rstate.ra.ptr.p_double[11]; + tol = state->rstate.ra.ptr.p_double[12]; + stepklagval = state->rstate.ra.ptr.p_double[13]; + stepknlagval = state->rstate.ra.ptr.p_double[14]; + d2trustradratio = state->rstate.ra.ptr.p_double[15]; + predictedchangemodel = state->rstate.ra.ptr.p_double[16]; + predictedchangepenalty = state->rstate.ra.ptr.p_double[17]; + } + else + { + n = 359; + lccnt = -58; + nnlc = -919; + i = -909; + j = 81; + trustradstagnated = ae_true; + dotrace = ae_false; + dotracelaconic = ae_false; + doprobingalways = ae_true; + doprobingonfailure = ae_true; + dodetailedtrace = ae_false; + meritfstagnated = ae_true; + infinitiesdetected = ae_false; + failedtorecoverfrominfinities = ae_true; + isinfeasible = ae_true; + feasibilityrestoration = ae_false; + firstrestorationiteration = ae_false; + stepfailed = ae_false; + restartiteration = ae_false; + leavefeasibilityrestoration = ae_false; + v = -229.0; + vv = -536.0; + mx = 487.0; + deltamax = -115.0; + multiplyby = 886.0; + setscaleto = 346.0; + prevtrustrad = -722.0; + relativetargetdecrease = -413.0; + tgt0 = -461.0; + h0 = 927.0; + tgt1 = 201.0; + h1 = 922.0; + tol = -154.0; + stepklagval = 306.0; + stepknlagval = -1011.0; + d2trustradratio = 951.0; + predictedchangemodel = -463.0; + predictedchangepenalty = 88.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + + /* + * Routine body + */ + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + dotracelaconic = ae_is_trace_enabled("SQP.LACONIC"); + dotrace = ae_is_trace_enabled("SQP")&&!dotracelaconic; + dodetailedtrace = dotrace&&ae_is_trace_enabled("SQP.DETAILED"); + doprobingalways = dotrace&&ae_is_trace_enabled("SQP.PROBING"); + doprobingonfailure = dotrace&&ae_is_trace_enabled("SQP.PROBINGONFAILURE"); + + /* + * Prepare rcomm interface + */ + state->needfisj = ae_false; + state->xupdated = ae_false; + + /* + * Prepare debug timers + */ + stimerinit(&state->timertotal, _state); + stimerinit(&state->timerqpgen, _state); + stimerinit(&state->timeripminit, _state); + stimerinit(&state->timeripmsolve, _state); + stimerinit(&state->timercallback, _state); + stimerstart(&state->timertotal, _state); + + /* + * Initialize algorithm data: + * * Lagrangian and "Big C" estimates + * * trust region + * * initial function scales (vector of 1's) + * * current approximation of the Hessian matrix H (unit matrix) + * * initial linearized constraints + * * initial violation of linear/nonlinear constraints + */ + state->werepointsbelowctol = ae_false; + state->fstagnationcnt = 0; + state->trustradstagnationcnt = 0; + state->trustrad = state->inittrustrad; + state->trustradgrowth = nlcfsqp_deftrustradgrowth; + rsetallocv(n, 0.0, &state->replagbc, _state); + rsetallocv(lccnt, 0.0, &state->replaglc, _state); + rsetallocv(nnlc, 0.0, &state->replagnlc, _state); + + /* + * Evaluate function vector and Jacobian at X0, send first location report. + * Compute initial violation of constraints. + */ + rsetallocv(1+nnlc, 1.0, &state->fscaleszzz, _state); + rsetallocv(1+nnlc, 1.0, &state->invfscales, _state); + state->sqpbigscale = nlcfsqp_defsqpbigscale; + state->sqpsmallscale = nlcfsqp_defsqpsmallscale; + rcopyallocv(nnlc, &state->rawnl, &state->scalednl, _state); + rcopyallocv(nnlc, &state->rawnu, &state->scalednu, _state); + vfjallocsparse(n, 1+nnlc, &state->stepk, _state); + vfjallocsparse(n, 1+nnlc, &state->cand, _state); + vfjallocsparse(n, 1+nnlc, &state->probe, _state); + rcopyv(n, &state->x0, &state->stepk.x, _state); + nlcfsqp_sqpsendx(state, &state->stepk.x, _state); + state->needfisj = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfisj = ae_false; + if( !nlcfsqp_sqpretrievefij(state, &state->stepk, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + nlcfsqp_sqpsendx(state, &state->stepk.x, _state); + state->f = state->stepk.fi.ptr.p_double[0]*state->fscaleszzz.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; + checklc2violation(&state->scla, &state->sclal, &state->sclau, &state->lcsrcidx, lccnt, &state->stepk.x, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlc2violation(&state->stepk.fi, &state->fscaleszzz, &state->rawnl, &state->rawnu, nnlc, &state->repnlcerr, &state->repnlcidx, _state); + checknlc2violation(&state->stepk.fi, &state->scalednl, &state->scalednu, nnlc, &state->repsclerr, &i, _state); + state->repsclerr = rmaxabs3(state->repsclerr, state->repbcerr, state->replcerr, _state); + nlcfsqp_targetandconstraints(state, &state->stepk, &tgt0, &h0, _state); + nlpfinit((double)10*(h0+(double)1), &state->filter, _state); + state->filter.gammaf = 0.001; + state->filter.gammah = 0.999; + state->werepointsbelowctol = state->werepointsbelowctol||ae_fp_less_eq(state->repsclerr,state->ctol); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// FILTER SQP SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("cntLC = %6d\n", + (int)(lccnt)); + ae_trace("cntNLC = %6d\n", + (int)(nnlc)); + } + if( dotracelaconic ) + { + ae_trace("> ALGLIB filter SQP solver started, %0d variables, %0d linear constraints, %0d general constraints\n", + (int)(n), + (int)(lccnt), + (int)(nnlc)); + ae_trace(" ITS TR.RAD OBJECTIVE FEAS.ERR TIME\n"); + } + + /* + * Perform outer (NLC) iterations + */ + feasibilityrestoration = ae_false; + firstrestorationiteration = ae_false; + infinitiesdetected = ae_false; + failedtorecoverfrominfinities = ae_false; + relativetargetdecrease = 1.0E50; + if( state->usedensebfgs ) + { + hessianinitbfgs(&state->hess, n, state->bfgsresetfreq, 0.1*nlcfsqp_sqpdeltadecrease*ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), _state); + } + else + { + hessianinitlowranksr1(&state->hess, n, ae_minint(n, nlcfsqp_xbfgsmemlen, _state), 0.1*nlcfsqp_sqpdeltadecrease*ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), nlcfsqp_xbfgsmaxhess, _state); + state->hess.mincrv = 0.0001; + } + rallocv(n, &state->varscales, _state); + for(i=0; i<=n-1; i++) + { + state->varscales.ptr.p_double[i] = nlcfsqp_gettrustregionk(&state->stepk.x, i, 1.0, _state); + } + nlcfsqp_initqpsubsolver(state, &state->subsolver, _state); +lbl_5: + if( ae_false ) + { + goto lbl_6; + } + + /* + * Compute current function and variable scales, send to Hessian and filter + */ + nlcfsqp_autoscalevarstargetconstraints(state, &state->stepk, ae_false, dotrace, _state); + nlcfsqp_targetandconstraints(state, &state->stepk, &tgt0, &h0, _state); + + /* + * Before beginning new outer iteration: + * * check stopping criteria + * * renormalize target function and/or constraints, if some of them have too large magnitudes + * * save initial point for the outer iteration + */ + if( ae_fp_less_eq(relativetargetdecrease,critgetepsf(&state->criteria, _state)) ) + { + state->repterminationtype = 1; + if( dotrace||dotracelaconic ) + { + ae_trace("> stopping condition met: relative change in target is less than %0.3e\n", + (double)(critgetepsf(&state->criteria, _state))); + } + goto lbl_6; + } + if( ae_fp_less_eq(state->trustrad,critgeteps(&state->criteria, _state)) ) + { + state->repterminationtype = 2; + if( dotrace||dotracelaconic ) + { + ae_trace("> stopping condition met: trust radius is smaller than %0.3e\n", + (double)(critgeteps(&state->criteria, _state))); + } + goto lbl_6; + } + v = ae_sqrt(ae_machineepsilon, _state); + if( ae_fp_less_eq(state->trustrad,v) ) + { + state->repterminationtype = 7; + if( dotrace||dotracelaconic ) + { + ae_trace("> stopping condition met: trust radius is smaller than the absolute minimum %0.3e\n", + (double)(v)); + } + goto lbl_6; + } + if( critgetmaxits(&state->criteria, _state)>0&&state->repiterationscount>=nlcfsqp_geteffectivemaxits(state, _state) ) + { + state->repterminationtype = 5; + if( dotrace||dotracelaconic ) + { + ae_trace("> stopping condition met: %0d iterations performed\n", + (int)(state->repiterationscount)); + } + goto lbl_6; + } + if( state->fstagnationcnt>=nlcfsqp_fstagnationlimit ) + { + state->repterminationtype = 7; + if( dotrace||dotracelaconic ) + { + ae_trace("> stopping criteria are too stringent: F stagnated for %0d its, stopping\n", + (int)(state->fstagnationcnt)); + } + goto lbl_6; + } + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n=== OUTER ITERATION %5d STARTED ==================================================================\n", + (int)(state->repiterationscount)); + if( dodetailedtrace ) + { + ae_trace("> printing raw data (prior to applying variable and function scales)\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->stepk.x, n, &state->s, ae_true, &state->s, ae_false, _state); + ae_trace("\n"); + ae_trace("> printing scaled data (after applying variable and function scales)\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->stepk.x, 0, n, _state); + ae_trace("\n"); + ae_trace("FScales = "); + tracevectorautoprec(&state->fscaleszzz, 0, 1+nnlc, _state); + ae_trace("\n"); + ae_trace("Fi (scaled) = "); + tracevectorautoprec(&state->stepk.fi, 0, 1+nnlc, _state); + ae_trace("\n"); + } + mx = (double)(0); + for(i=0; i<=nnlc-1; i++) + { + if( state->hasnl.ptr.p_bool[i] ) + { + mx = ae_maxreal(mx, state->scalednl.ptr.p_double[i]-state->stepk.fi.ptr.p_double[1+i], _state); + } + if( state->hasnu.ptr.p_bool[i] ) + { + mx = ae_maxreal(mx, state->stepk.fi.ptr.p_double[1+i]-state->scalednu.ptr.p_double[i], _state); + } + } + ae_trace("trustRad = %0.3e\n", + (double)(state->trustrad)); + ae_trace("lin.violation = %0.3e (scaled violation of linear constraints)\n", + (double)(state->replcerr)); + ae_trace("nlc.violation = %0.3e (scaled violation of nonlinear constraints)\n", + (double)(mx)); + ae_trace("|x|inf = %0.3e\n", + (double)(rmaxabsv(n, &state->stepk.x, _state))); + } + if( dotracelaconic ) + { + i = 0; + if( state->repiterationscount<=10 ) + { + i = 1; + } + if( state->repiterationscount<=100&&state->repiterationscount%5==0 ) + { + i = 1; + } + if( state->repiterationscount%50==0 ) + { + i = 1; + } + if( i>0 ) + { + ae_trace("%6d %10.2e %23.15e %14.6e %10.3fs\n", + (int)(state->repiterationscount), + (double)(state->trustrad), + (double)(tgt0*state->fscaleszzz.ptr.p_double[0]), + (double)(h0), + (double)(0.001*stimergetmsrunning(&state->timertotal, _state))); + } + } + + /* + * Start of the SQP iteration + */ + rcopyv(n, &state->stepk.x, &state->xprev, _state); + rsetv(n, 0.0, &state->d0, _state); + if( dotrace ) + { + if( feasibilityrestoration ) + { + ae_trace("\n--- feasibility restoration step -------------------------------------------------------------------\n"); + } + else + { + ae_trace("\n--- filter SQP step --------------------------------------------------------------------------------\n"); + } + } + + /* + * Default values of the flag variables + */ + stepfailed = ae_false; + restartiteration = ae_false; + leavefeasibilityrestoration = ae_false; + meritfstagnated = ae_false; + relativetargetdecrease = 1.0E50; + + /* + * Determine step direction + */ + if( !feasibilityrestoration ) + { + if( !nlcfsqp_qpsubproblemsolvesqp(state, &state->subsolver, &state->stepk, &state->hess, &state->d0, &state->lagbcmult, &state->lagxcmult, dotrace, &isinfeasible, &j, &predictedchangemodel, &predictedchangepenalty, &d2trustradratio, _state) ) + { + if( dotrace ) + { + ae_trace("> [WARNING] QP subproblem failed with TerminationType=%0d\n> decreasing trust radius\n", + (int)(j)); + } + state->trustrad = 0.1*state->trustrad; + inc(&state->repiterationscount, _state); + goto lbl_5; + } + if( dotrace ) + { + ae_trace("> the QP subproblem was solved with TerminationType=%0d, max|lagBoxMult|=%0.2e, max|lagNonBoxMult|=%0.2e\n", + (int)(j), + (double)(rmaxabsv(n, &state->lagbcmult, _state)), + (double)(rmaxabsv(lccnt+nnlc, &state->lagxcmult, _state))); + } + if( isinfeasible ) + { + nlpfappend(&state->filter, tgt0, h0, _state); + feasibilityrestoration = ae_true; + firstrestorationiteration = ae_true; + inc(&state->repiterationscount, _state); + if( dotrace ) + { + ae_trace(">> the QP subproblem is infeasible (constraint violation delta=%0.2e, ratio=%0.3f), entering feasibility restoration phase\n>> the initial point was added to the filter (%0d entries in the filter)\n>> restarting iteration\n\n", + (double)(predictedchangepenalty), + (double)(state->subsolver.penalty1/state->subsolver.penalty0), + (int)(state->filter.filtersize)); + } + goto lbl_5; + } + + /* + * The problem was solved and is feasible. + * Save most recent Lagrange multipliers + */ + rcopyv(n, &state->lagbcmult, &state->replagbc, _state); + rmergedivv(n, &state->s, &state->replagbc, _state); + rmulv(n, state->fscaleszzz.ptr.p_double[0], &state->replagbc, _state); + rcopyv(lccnt, &state->lagxcmult, &state->replaglc, _state); + rmergedivv(lccnt, &state->lcscales, &state->replaglc, _state); + rmulv(lccnt, state->fscaleszzz.ptr.p_double[0], &state->replaglc, _state); + rcopyvx(nnlc, &state->lagxcmult, lccnt, &state->replagnlc, 0, _state); + for(i=0; i<=nnlc-1; i++) + { + state->replagnlc.ptr.p_double[i] = state->replagnlc.ptr.p_double[i]/state->fscaleszzz.ptr.p_double[1+i]*state->fscaleszzz.ptr.p_double[0]; + } + } + else + { + if( !nlcfsqp_qpsubproblemsolveelastic(state, &state->subsolver, &state->stepk, &state->hess, &state->d0, &state->lagbcmult, &state->lagxcmult, dotrace, &isinfeasible, &j, &predictedchangemodel, &predictedchangepenalty, &d2trustradratio, _state) ) + { + if( dotrace ) + { + ae_trace("> [WARNING] QP subproblem failed with TerminationType=%0d\n> decreasing trust radius\n", + (int)(j)); + } + state->trustrad = 0.1*state->trustrad; + inc(&state->repiterationscount, _state); + goto lbl_5; + } + if( dotrace ) + { + ae_trace("> elastic QP subproblem was solved with TerminationType=%0d, max|lagBoxMult|=%0.2e, max|lagNonBoxMult|=%0.2e\n\n", + (int)(j), + (double)(rmaxabsv(n, &state->lagbcmult, _state)), + (double)(rmaxabsv(lccnt+nnlc, &state->lagxcmult, _state))); + } + } + rcopyv(n, &state->d0, &state->dtrial, _state); + + /* + * Perform merit function line search. + * + * First, we try unit step. If it does not decrease merit function, + * a second-order correction is tried (helps to combat Maratos effect). + */ + rcopyv(n, &state->stepk.x, &state->cand.x, _state); + raddv(n, 1.0, &state->dtrial, &state->cand.x, _state); + nlcfsqp_sqpsendx(state, &state->cand.x, _state); + state->needfisj = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfisj = ae_false; + if( !nlcfsqp_sqpretrievefij(state, &state->cand, _state) ) + { + + /* + * Failed to retrieve func/Jac, infinities detected + */ + if( dotrace ) + { + ae_trace("[WARNING] infinities in target/constraints are detected, forcing trust radius decrease and restarting iteration\n"); + } + state->trustrad = state->trustrad*nlcfsqp_maxtrustraddecay; + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + infinitiesdetected = ae_true; + failedtorecoverfrominfinities = ae_true; + inc(&state->repiterationscount, _state); + goto lbl_5; + } + nlcfsqp_targetandconstraints(state, &state->cand, &tgt1, &h1, _state); + if( dotrace ) + { + rallocv(n, &state->tmplaggrad, _state); + rallocv(n, &state->tmpcandlaggrad, _state); + nlcfsqp_lagrangianfg(state, &state->stepk.x, state->trustrad, &state->stepk.fi, &state->stepk.sj, &state->lagbcmult, &state->lagxcmult, ae_true, &stepklagval, &state->tmplaggrad, _state); + nlcfsqp_lagrangianfg(state, &state->cand.x, state->trustrad, &state->cand.fi, &state->cand.sj, &state->lagbcmult, &state->lagxcmult, ae_true, &stepknlagval, &state->tmpcandlaggrad, _state); + ae_trace("> proposed step with relative len %0.6f (compared to trust radius)\n", + (double)(d2trustradratio)); + ae_trace(">> change in the target function: predicted=%0.2e, actual=%0.2e, ratio=%5.2f\n", + (double)(predictedchangemodel), + (double)(tgt1-tgt0), + (double)((tgt1-tgt0)/predictedchangemodel)); + ae_trace(">> change in the constraints violation: predicted=%0.2e, actual=%0.2e, ratio=%5.2f\n", + (double)(predictedchangepenalty), + (double)(h1-h0), + (double)((h1-h0)/predictedchangepenalty)); + ae_trace(">> target and constraints are:\n"); + ae_trace("targetF: %17.9e -> %17.9e (delta=%11.3e, raw)\n", + (double)(state->fscaleszzz.ptr.p_double[0]*state->stepk.fi.ptr.p_double[0]), + (double)(state->fscaleszzz.ptr.p_double[0]*state->cand.fi.ptr.p_double[0]), + (double)(state->fscaleszzz.ptr.p_double[0]*(state->cand.fi.ptr.p_double[0]-state->stepk.fi.ptr.p_double[0]))); + ae_trace("meritF: %17.9e -> %17.9e (delta=%11.3e, scaled penalized target)\n", + (double)(tgt0), + (double)(tgt1), + (double)(tgt1-tgt0)); + ae_trace("sum-of-constr: %17.9e -> %17.9e (delta=%11.3e, scaled)\n", + (double)(h0), + (double)(h1), + (double)(h1-h0)); + ae_trace("|grad L|: %17.9e -> %17.9e\n", + (double)(rmaxabsv(n, &state->tmplaggrad, _state)), + (double)(rmaxabsv(n, &state->tmpcandlaggrad, _state))); + ae_trace("\n"); + } + enforceboundaryconstraints(&state->cand.x, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + if( userterminationneeded ) + { + + /* + * User requested termination, break before we move to new point + */ + state->repterminationtype = icase2(failedtorecoverfrominfinities, -8, 8, _state); + if( dotrace||dotracelaconic ) + { + ae_trace("> user requested termination\n"); + } + goto lbl_6; + } + + /* + * Update Hessian + */ + if( !feasibilityrestoration ) + { + rallocv(n, &state->tmplaggrad, _state); + rallocv(n, &state->tmpcandlaggrad, _state); + nlcfsqp_lagrangianfg(state, &state->stepk.x, state->trustrad, &state->stepk.fi, &state->stepk.sj, &state->lagbcmult, &state->lagxcmult, ae_true, &stepklagval, &state->tmplaggrad, _state); + nlcfsqp_lagrangianfg(state, &state->cand.x, state->trustrad, &state->cand.fi, &state->cand.sj, &state->lagbcmult, &state->lagxcmult, ae_true, &stepknlagval, &state->tmpcandlaggrad, _state); + hessianupdatev2(&state->hess, &state->stepk.x, &state->tmplaggrad, &state->cand.x, &state->tmpcandlaggrad, 2, ae_false, dotrace, 1, _state); + if( dotrace ) + { + hessiangetdiagonal(&state->hess, &state->tmphdiag, _state); + ae_trace(">> printing information about Hessian:\n"); + v = state->tmphdiag.ptr.p_double[0]; + for(i=0; i<=n-1; i++) + { + v = ae_minreal(v, state->tmphdiag.ptr.p_double[i], _state); + } + ae_trace("mindiag(Bk) = %0.3e\n", + (double)(v)); + v = state->tmphdiag.ptr.p_double[0]; + for(i=0; i<=n-1; i++) + { + v = ae_maxreal(v, state->tmphdiag.ptr.p_double[i], _state); + } + ae_trace("maxdiag(Bk) = %0.3e\n", + (double)(v)); + ae_trace("\n"); + } + } + + /* + * Analyze current step and decide what to do: to continue iteration or to restart it. + * + * The latter option has two possible choices: to restart it with trust radius decreased + * (StepFailed=True) or with the same trust radius (StepFailed=False, performed when exiting + * from the feasibility restoration phase). + * + * Depending on the outcome, we set/clear FeasibilityRestoration, RestartIteration and StepFailed. + * Then we do some other work like printing trace logs, and finally restart iteration if needed. + */ + if( feasibilityrestoration ) + { + + /* + * Feasibility restoration phase + */ + if( (!firstrestorationiteration&&!isinfeasible)&&nlpfisacceptable1(&state->filter, tgt0, h0, _state) ) + { + + /* + * Exit restoration if initial point is feasible and acceptable, and we performed at least one restoration iteration + */ + if( dotrace ) + { + ae_trace("> the initial point is feasible and accepted by the filter, exiting feasibility restoration phase\n"); + } + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + leavefeasibilityrestoration = ae_true; + restartiteration = ae_true; + } + else + { + + /* + * Check sufficient decrease condition for modified penalty + * + * NOTE: it is essential to have strict ">" for both conditions below in order to be able + * to properly handle situations with zero predicted change + */ + if( ae_fp_greater(predictedchangepenalty,(double)(0))||ae_fp_greater(h1-h0,nlcfsqp_sufficientdecreasesigma*predictedchangepenalty) ) + { + if( dotrace ) + { + ae_trace("> the sufficient decrease condition does not hold, decreasing trust radius\n"); + } + restartiteration = ae_true; + stepfailed = ae_true; + } + } + meritfstagnated = ae_fp_less_eq(ae_fabs(h1-h0, _state),nlcfsqp_stagnationepsf*ae_maxreal(h0, h1, _state)); + firstrestorationiteration = ae_false; + } + else + { + + /* + * SQP phase + */ + if( !nlcfsqp_isacceptable(state, tgt0, h0, tgt1, h1, predictedchangemodel, predictedchangepenalty, dotrace, _state) ) + { + + /* + * The point is not acceptable, decrease trust radius and retry + */ + if( dotrace ) + { + ae_trace("> decreasing trust radius\n"); + } + restartiteration = ae_true; + stepfailed = ae_true; + } + meritfstagnated = ae_fp_less_eq(ae_fabs(tgt1-tgt0, _state),nlcfsqp_stagnationepsf*ae_fabs(tgt0, _state))&&ae_fp_less_eq(ae_fabs(h1-h0, _state),nlcfsqp_stagnationepsf*ae_maxreal(h0, h1, _state)); + } + if( !dotrace ) + { + goto lbl_7; + } + + /* + * Perform agressive probing of the search direction - additional function evaluations + * which help us to determine possible discontinuity and nonsmoothness of the problem + */ + if( !(doprobingalways||(doprobingonfailure&&stepfailed)) ) + { + goto lbl_9; + } + smoothnessmonitorstartlagrangianprobing(smonitor, &state->stepk.x, &state->dtrial, 1.0, state->repiterationscount, -1, _state); +lbl_11: + if( !smoothnessmonitorprobelagrangian(smonitor, _state) ) + { + goto lbl_12; + } + for(j=0; j<=n-1; j++) + { + state->probe.x.ptr.p_double[j] = smonitor->lagprobx.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j] ) + { + state->probe.x.ptr.p_double[j] = ae_maxreal(state->probe.x.ptr.p_double[j], state->scaledbndl.ptr.p_double[j], _state); + } + if( state->hasbndu.ptr.p_bool[j] ) + { + state->probe.x.ptr.p_double[j] = ae_minreal(state->probe.x.ptr.p_double[j], state->scaledbndu.ptr.p_double[j], _state); + } + } + nlcfsqp_sqpsendx(state, &state->probe.x, _state); + state->needfisj = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfisj = ae_false; + if( !nlcfsqp_sqpretrievefij(state, &state->probe, _state) ) + { + goto lbl_12; + } + rcopyallocv(1+nnlc, &state->probe.fi, &smonitor->lagprobfi, _state); + nlcfsqp_sparse2dense(&state->probe.sj, &smonitor->lagprobj, _state); + smonitor->lagprobrawlag = nlcfsqp_rawlagrangian(state, &state->probe.x, &state->probe.fi, &state->lagbcmult, &state->lagxcmult, _state); + goto lbl_11; +lbl_12: + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | probing search direction |\n"); + ae_trace("*** | suggested by first-order QP subproblem |\n"); + ae_trace("*** | |\n"); + ae_trace("*** | note: the target/Lagrangian may increase |\n"); + ae_trace("*** | along the search direction due to |\n"); + ae_trace("*** | nonmonotonic steps of the filter SQP |\n"); + ae_trace("*** | However, they MUST be smooth and |\n"); + ae_trace("*** | continuous. |\n"); + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | Step | Lagrangian (unaugmentd)| Target function |\n"); + ae_trace("*** |along D| must be smooth | must be smooth |\n"); + ae_trace("*** | | function | slope | function | slope |\n"); + smoothnessmonitortracelagrangianprobingresults(smonitor, _state); + ae_trace("\n"); +lbl_9: + + /* + * Output other information + */ +lbl_7: + if( leavefeasibilityrestoration ) + { + feasibilityrestoration = ae_false; + } + if( restartiteration ) + { + if( stepfailed ) + { + state->trustrad = state->trustrad*0.5; + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + } + if( dotrace ) + { + ae_trace("> restarting iteration\n\n"); + } + inc(&state->repiterationscount, _state); + goto lbl_5; + } + if( dotrace ) + { + ae_trace("> the step was successfully performed\n"); + } + if( (!feasibilityrestoration&&(ae_fp_greater_eq(predictedchangemodel,(double)(0))||ae_fp_greater(tgt1-tgt0,nlcfsqp_sufficientdecreasesigma*predictedchangemodel)))&&ae_fp_greater(h0,(double)(0)) ) + { + nlpfappend(&state->filter, tgt0, h0, _state); + if( dotrace ) + { + ae_trace(">> the initial point was added to the filter (%0d entries in the filter)\n", + (int)(state->filter.filtersize)); + } + } + if( dotrace ) + { + ae_trace("\n"); + } + + /* + * Analyze merit F for stagnation + */ + relativetargetdecrease = ae_maxreal(ae_fabs(tgt1-tgt0, _state)/rmaxabs3(tgt0, tgt1, (double)(1), _state), ae_fabs(h1-h0, _state)/rmaxabs3(h0, h1, (double)(1), _state), _state); + + /* + * Move to new point + * Report one more inner iteration + * Update constraint violations + */ + vfjcopy(&state->cand, &state->stepk, _state); + failedtorecoverfrominfinities = ae_false; + nlcfsqp_sqpsendx(state, &state->stepk.x, _state); + state->f = state->stepk.fi.ptr.p_double[0]*state->fscaleszzz.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->xupdated = ae_false; + checklc2violation(&state->scla, &state->sclal, &state->sclau, &state->lcsrcidx, lccnt, &state->stepk.x, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlc2violation(&state->stepk.fi, &state->fscaleszzz, &state->rawnl, &state->rawnu, nnlc, &state->repnlcerr, &state->repnlcidx, _state); + checknlc2violation(&state->stepk.fi, &state->scalednl, &state->scalednu, nnlc, &state->repsclerr, &i, _state); + state->repsclerr = rmaxabs3(state->repsclerr, state->repbcerr, state->replcerr, _state); + state->werepointsbelowctol = state->werepointsbelowctol||ae_fp_less_eq(state->repsclerr,state->ctol); + + /* + * Update trust region. + * + * NOTE: when trust region radius remains fixed for a long time it may mean that we + * stagnated in eternal loop. In such cases we decrease it slightly in order + * to break possible loop. If such decrease was unnecessary, it may be easily + * fixed within few iterations. + */ + trustradstagnated = ae_true; + prevtrustrad = state->trustrad; + deltamax = (double)(0); + for(i=0; i<=n-1; i++) + { + deltamax = ae_maxreal(deltamax, ae_fabs(state->xprev.ptr.p_double[i]-state->stepk.x.ptr.p_double[i], _state)/nlcfsqp_gettrustregionk(&state->xprev, i, state->trustrad, _state), _state); + } + if( ae_fp_less_eq(deltamax,nlcfsqp_sqpdeltadecrease) ) + { + state->trustrad = state->trustrad*ae_maxreal(deltamax/nlcfsqp_sqpdeltadecrease, nlcfsqp_maxtrustraddecay, _state); + trustradstagnated = ae_false; + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + } + if( ae_fp_greater_eq(deltamax,nlcfsqp_sqpdeltaincrease) ) + { + state->trustrad = state->trustrad*state->trustradgrowth; + trustradstagnated = ae_false; + trustradincreasemomentum(&state->trustradgrowth, nlcfsqp_momentumgrowth, nlcfsqp_maxtrustradgrowth, _state); + } + else + { + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + } + state->trustradstagnationcnt = icase2(trustradstagnated, state->trustradstagnationcnt+1, 0, _state); + if( state->trustradstagnationcnt>=nlcfsqp_trustradstagnationlimit ) + { + + /* + * Trust radius stagnated for too long, decrease it and reset stagnation counter + */ + if( dotrace ) + { + ae_trace("> detected stagnation of a trust radius, forcing decrease\n"); + } + state->trustrad = state->trustrad*0.5; + state->trustradstagnationcnt = 0; + trustradresetmomentum(&state->trustradgrowth, nlcfsqp_deftrustradgrowth, _state); + } + + /* + * Trace + */ + if( dotrace ) + { + ae_trace("\n--- iteration ends ---------------------------------------------------------------------------------\n"); + ae_trace("deltaMax = %0.3f (ratio of step length to trust radius)\n", + (double)(deltamax)); + ae_trace("newTrustRad = %0.3e", + (double)(state->trustrad)); + if( ae_fp_greater(state->trustrad,prevtrustrad) ) + { + ae_trace(", trust radius increased"); + } + if( ae_fp_less(state->trustrad,prevtrustrad) ) + { + ae_trace(", trust radius decreased"); + } + ae_trace("\n"); + } + + /* + * Advance outer iteration counter + */ + inc(&state->repiterationscount, _state); + state->fstagnationcnt = icase2(meritfstagnated, state->fstagnationcnt+1, 0, _state); + goto lbl_5; +lbl_6: + + /* + * Almost done + */ + if( infinitiesdetected ) + { + state->repterminationtype = icase2(failedtorecoverfrominfinities, -8, state->repterminationtype+800, _state); + } + if( dotrace ) + { + stimerstop(&state->timertotal, _state); + ae_trace("\n=== STOPPED ========================================================================================\n"); + if( infinitiesdetected&&failedtorecoverfrominfinities ) + { + ae_trace("> infinities were detected, but we failed to recover by decreasing trust radius; declaring failure with the code -8\n"); + } + ae_trace("raw target: %20.12e\n", + (double)(state->stepk.fi.ptr.p_double[0]*state->fscaleszzz.ptr.p_double[0])); + ae_trace("total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("* cbck: %10.1f ms\n", + (double)(stimergetms(&state->timercallback, _state))); + ae_trace("* QP gen: %10.1f ms\n", + (double)(stimergetms(&state->timerqpgen, _state))); + ae_trace("* IPM init: %10.1f ms\n", + (double)(stimergetms(&state->timeripminit, _state))); + ae_trace("* IPM solve: %10.1f ms\n", + (double)(stimergetms(&state->timeripmsolve, _state))); + } + if( dotracelaconic ) + { + nlcfsqp_targetandconstraints(state, &state->stepk, &tgt0, &h0, _state); + ae_trace("STOPPED %23.15e %14.6e %10.3fs\n", + (double)(tgt0*state->fscaleszzz.ptr.p_double[0]), + (double)(h0), + (double)(0.001*stimergetmsrunning(&state->timertotal, _state))); + } + smoothnessmonitortracestatus(smonitor, dotrace, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = lccnt; + state->rstate.ia.ptr.p_int[2] = nnlc; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = j; + state->rstate.ba.ptr.p_bool[0] = trustradstagnated; + state->rstate.ba.ptr.p_bool[1] = dotrace; + state->rstate.ba.ptr.p_bool[2] = dotracelaconic; + state->rstate.ba.ptr.p_bool[3] = doprobingalways; + state->rstate.ba.ptr.p_bool[4] = doprobingonfailure; + state->rstate.ba.ptr.p_bool[5] = dodetailedtrace; + state->rstate.ba.ptr.p_bool[6] = meritfstagnated; + state->rstate.ba.ptr.p_bool[7] = infinitiesdetected; + state->rstate.ba.ptr.p_bool[8] = failedtorecoverfrominfinities; + state->rstate.ba.ptr.p_bool[9] = isinfeasible; + state->rstate.ba.ptr.p_bool[10] = feasibilityrestoration; + state->rstate.ba.ptr.p_bool[11] = firstrestorationiteration; + state->rstate.ba.ptr.p_bool[12] = stepfailed; + state->rstate.ba.ptr.p_bool[13] = restartiteration; + state->rstate.ba.ptr.p_bool[14] = leavefeasibilityrestoration; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + state->rstate.ra.ptr.p_double[2] = mx; + state->rstate.ra.ptr.p_double[3] = deltamax; + state->rstate.ra.ptr.p_double[4] = multiplyby; + state->rstate.ra.ptr.p_double[5] = setscaleto; + state->rstate.ra.ptr.p_double[6] = prevtrustrad; + state->rstate.ra.ptr.p_double[7] = relativetargetdecrease; + state->rstate.ra.ptr.p_double[8] = tgt0; + state->rstate.ra.ptr.p_double[9] = h0; + state->rstate.ra.ptr.p_double[10] = tgt1; + state->rstate.ra.ptr.p_double[11] = h1; + state->rstate.ra.ptr.p_double[12] = tol; + state->rstate.ra.ptr.p_double[13] = stepklagval; + state->rstate.ra.ptr.p_double[14] = stepknlagval; + state->rstate.ra.ptr.p_double[15] = d2trustradratio; + state->rstate.ra.ptr.p_double[16] = predictedchangemodel; + state->rstate.ra.ptr.p_double[17] = predictedchangepenalty; + return result; +} + + +/************************************************************************* +This function initializes SQP subproblem. +Should be called once in the beginning of the optimization. + +INPUT PARAMETERS: + SState - solver state + Subsolver - SQP subproblem to initialize + + +RETURN VALUE: + True on success + False on failure of the QP solver (unexpected... but possible due to numerical errors) + + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static void nlcfsqp_initqpsubsolver(const minfsqpstate* sstate, + minfsqpsubsolver* subsolver, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nslack; + ae_int_t nnlc; + ae_int_t i; + ae_int_t lccnt; + + + n = sstate->n; + nnlc = sstate->nnlc; + nslack = n+2*sstate->lccnt+2*nnlc; + lccnt = sstate->lccnt+nnlc; + + /* + * Initial ordering state + */ + iallocv(n+lccnt, &subsolver->ordering, _state); + for(i=0; i<=n+lccnt-1; i++) + { + subsolver->ordering.ptr.p_int[i] = i; + } + iallocv(nslack+lccnt, &subsolver->elasticordering, _state); + for(i=0; i<=nslack+lccnt-1; i++) + { + subsolver->elasticordering.ptr.p_int[i] = i; + } + sparsecreatecrsempty(n, &subsolver->pattern, _state); + for(i=0; i<=lccnt-1; i++) + { + sparseappendemptyrow(&subsolver->pattern, _state); + } + sparsecreatecrsempty(nslack, &subsolver->elasticpattern, _state); + for(i=0; i<=lccnt-1; i++) + { + sparseappendemptyrow(&subsolver->elasticpattern, _state); + } + + /* + * Allocate temporaries + */ + rvectorsetlengthatleast(&subsolver->cural, lccnt, _state); + rvectorsetlengthatleast(&subsolver->curau, lccnt, _state); + rvectorsetlengthatleast(&subsolver->curbndl, nslack, _state); + rvectorsetlengthatleast(&subsolver->curbndu, nslack, _state); + rvectorsetlengthatleast(&subsolver->curb, nslack, _state); + + /* + * Linear constraints do not change across subiterations, that's + * why we allocate storage for them at the start of the program. + * + * A full set of "raw" constraints is stored; later we will filter + * out inequality ones which are inactive anywhere in the current + * trust region. + * + * NOTE: because sparserawlc object stores only linear constraint + * (linearizations of nonlinear ones are not stored) we + * allocate only minimum necessary space. + */ + if( sstate->lccnt>0 ) + { + sparsecopytocrsbuf(&sstate->scla, &subsolver->sparserawlc, _state); + } + + /* + * Initialize prior for regularization + */ + rsetallocv(lccnt, 0.0, &subsolver->lastlaglc, _state); +} + + +/************************************************************************* +This function solves QP subproblem + +This function returns: +* search direction D[] +* estimates of Lagrangian multipliers +* predicted change in the quadratic model of the target, and in the L1-penalty + added to the model + +Additionally it sets the following fields of the Subsolver: +* Penalty0 - sum of constraint violations at the initial point X +* Penalty1 - sum of constraint violations at X+D + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcfsqp_qpsubproblemsolvesqp(minfsqpstate* state, + minfsqpsubsolver* subsolver, + const varsfuncjac* model, + xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_bool* isinfeasible, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* d2trustradratio, + ae_state *_state) +{ + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t k; + double v; + double vv; + double vright; + double vmax; + double vmin; + ae_int_t xccnt; + ae_int_t offs; + ae_int_t nnz; + ae_bool bndlinactive; + ae_bool bnduinactive; + double rescaleby; + double targetscale; + ae_bool result; + + *isinfeasible = ae_false; + *terminationtype = 0; + *predictedchangemodel = 0.0; + *predictedchangepenalty = 0.0; + *d2trustradratio = 0.0; + + ae_assert(!model->isdense, "FSQP: integrity check 2314 failed", _state); + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + xccnt = lccnt+nnlc; + + /* + * Prepare temporary structures + */ + rvectorgrowto(&subsolver->cural, xccnt, _state); + rvectorgrowto(&subsolver->curau, xccnt, _state); + rallocv(xccnt, &subsolver->rescalelag, _state); + + /* + * Prepare default solution: all zeros + */ + result = ae_true; + *terminationtype = 0; + *predictedchangemodel = (double)(0); + *predictedchangepenalty = (double)(0); + *d2trustradratio = 0.0; + *isinfeasible = ae_false; + subsolver->penalty0 = 0.0; + subsolver->penalty1 = 0.0; + rsetv(n, 0.0, d, _state); + rsetv(n, 0.0, lagbcmult, _state); + rsetv(xccnt, 0.0, lagxcmult, _state); + bsetallocv(xccnt, ae_false, &subsolver->isinactive, _state); + + /* + * Linear term B + */ + nlcfsqp_penalizedfg(state, &model->x, &model->fi, &model->sj, &v, &subsolver->curb, _state); + + /* + * Trust radius constraints for primary variables + */ + bsetallocv(n, ae_false, &subsolver->retainnegativebclm, _state); + bsetallocv(n, ae_false, &subsolver->retainpositivebclm, _state); + for(i=0; i<=n-1; i++) + { + subsolver->curbndl.ptr.p_double[i] = -nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + subsolver->curbndu.ptr.p_double[i] = nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i]-model->x.ptr.p_double[i],subsolver->curbndl.ptr.p_double[i]) ) + { + subsolver->curbndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]-model->x.ptr.p_double[i]; + subsolver->retainnegativebclm.ptr.p_bool[i] = ae_true; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i]-model->x.ptr.p_double[i],subsolver->curbndu.ptr.p_double[i]) ) + { + subsolver->curbndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]-model->x.ptr.p_double[i]; + subsolver->retainpositivebclm.ptr.p_bool[i] = ae_true; + } + } + + /* + * Prepare storage for the "effective" constraining matrix (one with rows guaranteed to be + * inactive removed) and for the upcoming pattern matrix (one that is not subject to + * removal of any rows). + */ + nnz = 0; + if( lccnt>0 ) + { + nnz = nnz+subsolver->sparserawlc.ridx.ptr.p_int[lccnt]; + } + nnz = nnz+(model->sj.ridx.ptr.p_int[1+nnlc]-model->sj.ridx.ptr.p_int[1]); + ivectorgrowto(&subsolver->sparseefflc.ridx, xccnt+1, _state); + rvectorgrowto(&subsolver->sparseefflc.vals, nnz, _state); + ivectorgrowto(&subsolver->sparseefflc.idx, nnz, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.didx, xccnt, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.uidx, xccnt, _state); + subsolver->sparseefflc.ridx.ptr.p_int[0] = 0; + subsolver->sparseefflc.m = 0; + subsolver->sparseefflc.n = n; + subsolver->sparseefflc.matrixtype = 1; + sparsecreatecrsemptybuf(n, &subsolver->upcomingpattern, _state); + + /* + * Append linear equality/inequality constraints + * + * Scan sparsified linear constraints stored in sparserawlc[], skip ones + * which are inactive anywhere in the trust region. + */ + for(i=0; i<=lccnt-1; i++) + { + + /* + * Calculate: + * * VRight - product of X[] and AR[i] - Ith row of sparserawlc matrix. + * * VMin - minimum value of X*ARi computed over trust region + * * VMax - maximum value of X*ARi computed over trust region + */ + vright = (double)(0); + vmax = (double)(0); + vmin = (double)(0); + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + j = subsolver->sparserawlc.idx.ptr.p_int[k]; + v = model->x.ptr.p_double[j]; + vv = subsolver->sparserawlc.vals.ptr.p_double[k]; + vright = vright+vv*v; + if( vv>=(double)0 ) + { + vmax = vmax+vv*(v+subsolver->curbndu.ptr.p_double[j]); + vmin = vmin+vv*(v+subsolver->curbndl.ptr.p_double[j]); + } + else + { + vmax = vmax+vv*(v+subsolver->curbndl.ptr.p_double[j]); + vmin = vmin+vv*(v+subsolver->curbndu.ptr.p_double[j]); + } + } + bndlinactive = !state->hasal.ptr.p_bool[i]||vmin>state->sclal.ptr.p_double[i]; + bnduinactive = !state->hasau.ptr.p_bool[i]||vmaxsclau.ptr.p_double[i]; + + /* + * Linear constraints are passed 'as is', without additional rescaling + */ + subsolver->rescalelag.ptr.p_double[i] = 1.0; + + /* + * Always append full row to the upcoming pattern; rows to the effective linear + * constraints matrix are added subject to basic presolve (remove constraints that + * are guaranteed to be inactive). + */ + nlcfsqp_appendscaledsparserow(&subsolver->upcomingpattern, 1.0, &subsolver->sparserawlc, i, _state); + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (the row itself is retained but + * filled by zeros). + */ + if( bndlinactive&&bnduinactive ) + { + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = subsolver->sparseefflc.ridx.ptr.p_int[i]; + subsolver->cural.ptr.p_double[i] = 0.0; + subsolver->curau.ptr.p_double[i] = 0.0; + subsolver->rescalelag.ptr.p_double[i] = 0.0; + subsolver->isinactive.ptr.p_bool[i] = ae_true; + continue; + } + + /* + * Copy constraint from sparserawlc[] to sparseefflc[] + */ + offs = subsolver->sparseefflc.ridx.ptr.p_int[i]; + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + subsolver->sparseefflc.idx.ptr.p_int[offs] = subsolver->sparserawlc.idx.ptr.p_int[k]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = subsolver->sparserawlc.vals.ptr.p_double[k]; + offs = offs+1; + } + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = offs; + + /* + * Set up bounds and slack part of D0. + * + * NOTE: bounds for equality and inequality constraints are + * handled differently + */ + subsolver->cural.ptr.p_double[i] = _state->v_neginf; + subsolver->curau.ptr.p_double[i] = _state->v_posinf; + if( !bndlinactive ) + { + subsolver->cural.ptr.p_double[i] = state->sclal.ptr.p_double[i]-vright; + } + if( !bnduinactive ) + { + subsolver->curau.ptr.p_double[i] = state->sclau.ptr.p_double[i]-vright; + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+lccnt; + + /* + * Append nonlinear equality/inequality constraints + */ + for(i=0; i<=nnlc-1; i++) + { + + /* + * Calculate: + * * rescale coefficient used to normalize constraints + * * VMax - maximum of constraint value over trust region + */ + vmax = model->fi.ptr.p_double[1+i]; + vmin = model->fi.ptr.p_double[1+i]; + vv = (double)(0); + j0 = model->sj.ridx.ptr.p_int[1+i]; + j1 = model->sj.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = model->sj.idx.ptr.p_int[jj]; + v = model->sj.vals.ptr.p_double[jj]; + vv = vv+v*v; + if( v>=(double)0 ) + { + vmax = vmax+v*subsolver->curbndu.ptr.p_double[j]; + vmin = vmin+v*subsolver->curbndl.ptr.p_double[j]; + } + else + { + vmax = vmax+v*subsolver->curbndl.ptr.p_double[j]; + vmin = vmin+v*subsolver->curbndu.ptr.p_double[j]; + } + } + rescaleby = (double)1/coalesce(ae_sqrt(vv, _state), (double)(1), _state); + bndlinactive = !state->hasnl.ptr.p_bool[i]||vmin>state->scalednl.ptr.p_double[i]; + bnduinactive = !state->hasnu.ptr.p_bool[i]||vmaxscalednu.ptr.p_double[i]; + + /* + * Nonlinear constraints are passed with normalization + */ + subsolver->rescalelag.ptr.p_double[lccnt+i] = rescaleby; + + /* + * Always append full row to the upcoming pattern; rows to the effective linear + * constraints matrix are added subject to basic presolve (remove constraints that + * are guaranteed to be inactive). + */ + nlcfsqp_appendscaledsparserow(&subsolver->upcomingpattern, rescaleby, &model->sj, 1+i, _state); + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (row itself is retained but + * filled by zeros). + */ + if( bndlinactive&&bnduinactive ) + { + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->rescalelag.ptr.p_double[lccnt+i] = 0.0; + subsolver->isinactive.ptr.p_bool[lccnt+i] = ae_true; + continue; + } + + /* + * Copy scaled row + */ + j0 = model->sj.ridx.ptr.p_int[1+i]; + j1 = model->sj.ridx.ptr.p_int[1+i+1]-1; + offs = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + for(jj=j0; jj<=j1; jj++) + { + j = model->sj.idx.ptr.p_int[jj]; + v = model->sj.vals.ptr.p_double[jj]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = rescaleby*v; + subsolver->sparseefflc.idx.ptr.p_int[offs] = j; + offs = offs+1; + } + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = offs; + + /* + * Set bounds on linear equality/inequality constraints + */ + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = _state->v_neginf; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = _state->v_posinf; + if( !bndlinactive ) + { + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = rescaleby*(state->scalednl.ptr.p_double[i]-model->fi.ptr.p_double[1+i]); + } + if( !bnduinactive ) + { + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = rescaleby*(state->scalednu.ptr.p_double[i]-model->fi.ptr.p_double[1+i]); + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+nnlc; + + /* + * Finalize sparse matrix structure + */ + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.idx.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.vals.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + subsolver->sparseefflc.ninitialized = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]; + sparseinitduidx(&subsolver->sparseefflc, _state); + + /* + * Solve quadratic program with IPM. + * + * We always treat its result as a valid solution, even for TerminationType<=0. + * In case anything is wrong with solution vector, we will detect it during line + * search phase (merit function does not increase). + * + * NOTE: because we cleaned up constraints that are DEFINITELY inactive within + * trust region, we do not have to worry about StopOnExcessiveBounds option. + */ + rallocv(n, &subsolver->tmps, _state); + for(i=0; i<=n-1; i++) + { + subsolver->tmps.ptr.p_double[i] = nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + } + rsetallocv(n, 0.0, &subsolver->tmporigin, _state); + if( state->usedensebfgs ) + { + + /* + * Dense BFGS is used to generate a quasi-Newton matrix, + * dense IPM is used to solve QP subproblems. + */ + if( dotrace ) + { + stimerstart(&state->timerqpgen, _state); + } + hessiangetmatrix(hess, ae_true, &subsolver->denseh, _state); + if( dotrace ) + { + stimerstop(&state->timerqpgen, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripminit, _state); + } + vipminitdensewithslacks(&subsolver->ipmsolver, &subsolver->tmps, &subsolver->tmporigin, n, n, ae_true, _state); + vipmsetquadraticlinear(&subsolver->ipmsolver, &subsolver->denseh, &subsolver->sparsedummy, 0, ae_true, &subsolver->curb, _state); + vipmsetconstraints(&subsolver->ipmsolver, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, _state); + if( dotrace ) + { + stimerstop(&state->timeripminit, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripmsolve, _state); + } + vipmoptimize(&subsolver->ipmsolver, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + if( dotrace ) + { + stimerstop(&state->timeripmsolve, _state); + } + } + else + { + + /* + * Prepare ordering for QP subproblem or reuse previously computed one + */ + if( xccnt>0&&!sparsetrygatherclear(&subsolver->pattern, &subsolver->upcomingpattern, _state) ) + { + sparsemergepatterns(&subsolver->pattern, &subsolver->upcomingpattern, &subsolver->sparsetmp, _state); + sparsecopybuf(&subsolver->sparsetmp, &subsolver->pattern, _state); + bsetallocv(n, ae_true, &subsolver->isbounded, _state); + ipm2proposeordering(&subsolver->ipm2, n, ae_true, &subsolver->isbounded, &subsolver->isbounded, &subsolver->pattern, &subsolver->cural, &subsolver->curau, xccnt, &subsolver->ordering, _state); + } + + /* + * Low-rank quasi-Newton matrix with positive-only corrections is used, + * sparse IPM with low-rank updates is used to solve QP subproblems. + */ + if( dotrace ) + { + stimerstart(&state->timerqpgen, _state); + } + hessiangetlowrankstabilized(hess, &subsolver->tmpdiag, &subsolver->tmpcorrc, &subsolver->hesscorrd, &subsolver->hessrank, _state); + subsolver->hesssparsediag.matrixtype = 1; + subsolver->hesssparsediag.m = n; + subsolver->hesssparsediag.n = n; + iallocv(n+1, &subsolver->hesssparsediag.ridx, _state); + iallocv(n, &subsolver->hesssparsediag.idx, _state); + rallocv(n, &subsolver->hesssparsediag.vals, _state); + subsolver->hesssparsediag.ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + subsolver->hesssparsediag.idx.ptr.p_int[i] = i; + subsolver->hesssparsediag.vals.ptr.p_double[i] = subsolver->tmpdiag.ptr.p_double[i]; + subsolver->hesssparsediag.ridx.ptr.p_int[i+1] = i+1; + } + sparsecreatecrsinplace(&subsolver->hesssparsediag, _state); + if( subsolver->hessrank>0 ) + { + rcopyallocm(subsolver->hessrank, n, &subsolver->tmpcorrc, &subsolver->hesscorrc, _state); + } + targetscale = (double)(0); + for(i=0; i<=n-1; i++) + { + v = subsolver->curb.ptr.p_double[i]*state->varscales.ptr.p_double[i]; + targetscale = targetscale+v*v; + } + targetscale = ae_sqrt(targetscale, _state)*state->trustrad; + targetscale = ae_maxreal(targetscale, hessiangetnrm2stab(hess, _state)*ae_sqr(state->trustrad, _state), _state); + targetscale = coalesce(targetscale, (double)(1), _state); + if( dotrace ) + { + stimerstop(&state->timerqpgen, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripminit, _state); + } + ipm2init(&subsolver->ipm2, &subsolver->tmps, &subsolver->tmporigin, n, &subsolver->densedummy, &subsolver->hesssparsediag, 1, ae_true, &subsolver->hesscorrc, &subsolver->hesscorrd, subsolver->hessrank, &subsolver->curb, targetscale, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, ae_true, ae_false, _state); + ipm2setmaxits(&subsolver->ipm2, nlcfsqp_maxipmits, _state); + ipm2setordering(&subsolver->ipm2, &subsolver->ordering, _state); + if( dotrace ) + { + stimerstop(&state->timeripminit, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripmsolve, _state); + } + ipm2optimize(&subsolver->ipm2, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + if( dotrace ) + { + stimerstop(&state->timeripmsolve, _state); + } + rcopyv(xccnt, &subsolver->tmp2, &subsolver->lastlaglc, _state); + } + rcopyv(n, &subsolver->tmp0, d, _state); + + /* + * Analyze constraint violation + */ + *isinfeasible = *isinfeasible||*terminationtype<=0; + + /* + * Unpack results + */ + for(i=0; i<=n-1; i++) + { + lagbcmult->ptr.p_double[i] = (double)(0); + if( subsolver->retainpositivebclm.ptr.p_bool[i]&&ae_fp_greater(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + if( subsolver->retainnegativebclm.ptr.p_bool[i]&&ae_fp_less(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + } + rcopyv(xccnt, &subsolver->tmp2, lagxcmult, _state); + rmergemulv(xccnt, &subsolver->rescalelag, lagxcmult, _state); + + /* + * Compute predicted decrease in an L1-penalized quadratic model + */ + for(i=0; i<=lccnt-1; i++) + { + v = spdotvr(&model->x, &state->scla, i, _state); + vv = v+spdotvr(d, &state->scla, i, _state); + if( state->hasal.ptr.p_bool[i] ) + { + subsolver->penalty0 = subsolver->penalty0+ae_maxreal(state->sclal.ptr.p_double[i]-v, (double)(0), _state); + subsolver->penalty1 = subsolver->penalty1+ae_maxreal(state->sclal.ptr.p_double[i]-vv, (double)(0), _state); + } + if( state->hasau.ptr.p_bool[i] ) + { + subsolver->penalty0 = subsolver->penalty0+ae_maxreal(v-state->sclau.ptr.p_double[i], (double)(0), _state); + subsolver->penalty1 = subsolver->penalty1+ae_maxreal(vv-state->sclau.ptr.p_double[i], (double)(0), _state); + } + } + for(i=0; i<=nnlc-1; i++) + { + v = model->fi.ptr.p_double[1+i]; + vv = v+spdotvr(d, &model->sj, 1+i, _state); + if( state->hasnl.ptr.p_bool[i] ) + { + subsolver->penalty0 = subsolver->penalty0+ae_maxreal(state->scalednl.ptr.p_double[i]-v, (double)(0), _state); + subsolver->penalty1 = subsolver->penalty1+ae_maxreal(state->scalednl.ptr.p_double[i]-vv, (double)(0), _state); + } + if( state->hasnu.ptr.p_bool[i] ) + { + subsolver->penalty0 = subsolver->penalty0+ae_maxreal(v-state->scalednu.ptr.p_double[i], (double)(0), _state); + subsolver->penalty1 = subsolver->penalty1+ae_maxreal(vv-state->scalednu.ptr.p_double[i], (double)(0), _state); + } + } + *predictedchangemodel = rdotv(n, d, &subsolver->curb, _state)+0.5*hessianvmv(hess, d, _state); + *predictedchangepenalty = subsolver->penalty1-subsolver->penalty0; + *isinfeasible = *isinfeasible||ae_fp_greater(subsolver->penalty1,subsolver->penalty0*nlcfsqp_sufficientdecreasesigma+ae_maxreal(critgetepsf(&state->criteria, _state), (double)100*ae_sqrt(ae_machineepsilon, _state), _state)*rmaxabs3(subsolver->penalty0, subsolver->penalty1, (double)(1), _state)); + + /* + * Analyze length of D + */ + ae_assert(ae_fp_eq(*d2trustradratio,0.0), "SQP: integrity check 0157 failed", _state); + for(i=0; i<=n-1; i++) + { + *d2trustradratio = ae_maxreal(*d2trustradratio, ae_fabs(d->ptr.p_double[i]/nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state), _state), _state); + } + return result; +} + + +/************************************************************************* +This function solves elastic QP subproblem arising during feasibility +restoration phase. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcfsqp_qpsubproblemsolveelastic(minfsqpstate* state, + minfsqpsubsolver* subsolver, + const varsfuncjac* model, + xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_bool* isinfeasible, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* d2trustradratio, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nslack; + ae_int_t lccnt; + ae_int_t nnlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jj; + double v; + double vv; + double vright; + double vmax; + double vmin; + ae_int_t xccnt; + ae_int_t offsslacklc; + ae_int_t offsslacknnlc; + ae_int_t offs; + ae_int_t nnz; + ae_int_t j0; + ae_int_t j1; + double rescaleby; + ae_bool bndlinactive; + ae_bool bnduinactive; + double targetscale; + ae_bool result; + + *isinfeasible = ae_false; + *terminationtype = 0; + *predictedchangemodel = 0.0; + *predictedchangepenalty = 0.0; + *d2trustradratio = 0.0; + + ae_assert(!model->isdense, "SQP: integrity check 8637 failed", _state); + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + nslack = n+2*lccnt+2*nnlc; + xccnt = lccnt+nnlc; + + /* + * Locations of slack variables + */ + offsslacklc = n; + offsslacknnlc = n+2*lccnt; + + /* + * Prepare temporary structures + */ + rvectorgrowto(&subsolver->cural, xccnt, _state); + rvectorgrowto(&subsolver->curau, xccnt, _state); + rallocv(xccnt, &subsolver->rescalelag, _state); + + /* + * Prepare default solution: all zeros + */ + result = ae_true; + *terminationtype = 0; + *predictedchangemodel = (double)(0); + *predictedchangepenalty = (double)(0); + *d2trustradratio = 0.0; + *isinfeasible = ae_false; + rsetv(n, 0.0, d, _state); + rsetv(n, 0.0, lagbcmult, _state); + rsetv(xccnt, 0.0, lagxcmult, _state); + bsetallocv(lccnt+nnlc, ae_false, &subsolver->isinactive, _state); + + /* + * Linear term B + */ + rsetv(n, 0.0, &subsolver->curb, _state); + for(i=n; i<=nslack-1; i++) + { + subsolver->curb.ptr.p_double[i] = 1.0; + } + + /* + * Trust radius constraints for primary variables + */ + bsetallocv(n, ae_false, &subsolver->retainnegativebclm, _state); + bsetallocv(n, ae_false, &subsolver->retainpositivebclm, _state); + for(i=0; i<=n-1; i++) + { + subsolver->curbndl.ptr.p_double[i] = -nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + subsolver->curbndu.ptr.p_double[i] = nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i]-model->x.ptr.p_double[i],subsolver->curbndl.ptr.p_double[i]) ) + { + subsolver->curbndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]-model->x.ptr.p_double[i]; + subsolver->retainnegativebclm.ptr.p_bool[i] = ae_true; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i]-model->x.ptr.p_double[i],subsolver->curbndu.ptr.p_double[i]) ) + { + subsolver->curbndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]-model->x.ptr.p_double[i]; + subsolver->retainpositivebclm.ptr.p_bool[i] = ae_true; + } + } + + /* + * Prepare storage for "effective" constraining matrix + */ + nnz = 0; + if( lccnt>0 ) + { + nnz = nnz+subsolver->sparserawlc.ridx.ptr.p_int[lccnt]; + } + nnz = nnz+(model->sj.ridx.ptr.p_int[1+nnlc]-model->sj.ridx.ptr.p_int[1]); + nnz = nnz+2*lccnt; + nnz = nnz+2*nnlc; + ivectorgrowto(&subsolver->sparseefflc.ridx, xccnt+1, _state); + rvectorgrowto(&subsolver->sparseefflc.vals, nnz, _state); + ivectorgrowto(&subsolver->sparseefflc.idx, nnz, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.didx, xccnt, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.uidx, xccnt, _state); + subsolver->sparseefflc.ridx.ptr.p_int[0] = 0; + subsolver->sparseefflc.m = 0; + subsolver->sparseefflc.n = nslack; + subsolver->sparseefflc.matrixtype = 1; + sparsecreatecrsemptybuf(nslack, &subsolver->upcomingpattern, _state); + + /* + * Append linear equality/inequality constraints + * + * Scan sparsified linear constraints stored in sparserawlc[], skip ones + * which are inactive anywhere in the trust region. + */ + rvectorsetlengthatleast(&subsolver->tmp0, nslack, _state); + for(i=0; i<=n-1; i++) + { + subsolver->tmp0.ptr.p_double[i] = model->x.ptr.p_double[i]; + } + for(i=n; i<=nslack-1; i++) + { + subsolver->tmp0.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=lccnt-1; i++) + { + + /* + * Calculate: + * * VRight - product of X[] (extended with zeros up to NSlack elements) + * and AR[i] - Ith row of sparserawlc matrix. + * * VMax - maximum value of X*ARi computed over trust region + */ + vright = (double)(0); + vmax = (double)(0); + vmin = (double)(0); + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + j = subsolver->sparserawlc.idx.ptr.p_int[k]; + v = model->x.ptr.p_double[j]; + vv = subsolver->sparserawlc.vals.ptr.p_double[k]; + vright = vright+vv*v; + if( vv>=(double)0 ) + { + vmax = vmax+vv*(v+subsolver->curbndu.ptr.p_double[j]); + vmin = vmin+vv*(v+subsolver->curbndl.ptr.p_double[j]); + } + else + { + vmax = vmax+vv*(v+subsolver->curbndl.ptr.p_double[j]); + vmin = vmin+vv*(v+subsolver->curbndu.ptr.p_double[j]); + } + } + bndlinactive = !state->hasal.ptr.p_bool[i]||vmin>state->sclal.ptr.p_double[i]; + bnduinactive = !state->hasau.ptr.p_bool[i]||vmaxsclau.ptr.p_double[i]; + + /* + * Linear constraints are passed 'as is', without additional rescaling + */ + subsolver->rescalelag.ptr.p_double[i] = 1.0; + + /* + * Always append full row to the upcoming pattern; rows to the effective linear + * constraints matrix are added subject to basic presolve (remove constraints that + * are guaranteed to be inactive). + */ + nlcfsqp_appendscaledsparserow(&subsolver->upcomingpattern, 1.0, &subsolver->sparserawlc, i, _state); + sparseappendelement(&subsolver->upcomingpattern, offsslacklc+2*i+0, 1.0, _state); + sparseappendelement(&subsolver->upcomingpattern, offsslacklc+2*i+1, -1.0, _state); + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (the row itself is retained but + * filled by zeros). + */ + if( bndlinactive&&bnduinactive ) + { + offs = subsolver->sparseefflc.ridx.ptr.p_int[i]; + subsolver->sparseefflc.vals.ptr.p_double[offs+0] = (double)(1); + subsolver->sparseefflc.vals.ptr.p_double[offs+1] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs+0] = offsslacklc+2*i+0; + subsolver->sparseefflc.idx.ptr.p_int[offs+1] = offsslacklc+2*i+1; + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = offs+2; + subsolver->cural.ptr.p_double[i] = 0.0; + subsolver->curau.ptr.p_double[i] = 0.0; + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+0] = (double)(0); + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+0] = _state->v_posinf; + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+1] = _state->v_posinf; + subsolver->rescalelag.ptr.p_double[i] = 0.0; + subsolver->isinactive.ptr.p_bool[i] = ae_true; + continue; + } + + /* + * Start working on row I + */ + offs = subsolver->sparseefflc.ridx.ptr.p_int[i]; + + /* + * Copy constraint from sparserawlc[] to sparseefflc[], add slack terms + */ + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + subsolver->sparseefflc.idx.ptr.p_int[offs] = subsolver->sparserawlc.idx.ptr.p_int[k]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = subsolver->sparserawlc.vals.ptr.p_double[k]; + offs = offs+1; + } + if( !bndlinactive ) + { + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacklc+2*i+0; + offs = offs+1; + } + if( !bnduinactive ) + { + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacklc+2*i+1; + offs = offs+1; + } + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = offs; + + /* + * Set box constraints on slack variables and bounds on linear equality/inequality constraints + */ + if( !bndlinactive ) + { + subsolver->cural.ptr.p_double[i] = state->sclal.ptr.p_double[i]-vright; + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+0] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+0] = ae_maxreal(state->sclal.ptr.p_double[i]-vright, 0.0, _state); + } + else + { + subsolver->cural.ptr.p_double[i] = _state->v_neginf; + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+0] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+0] = _state->v_posinf; + } + if( !bnduinactive ) + { + subsolver->curau.ptr.p_double[i] = state->sclau.ptr.p_double[i]-vright; + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+1] = ae_maxreal(vright-state->sclau.ptr.p_double[i], 0.0, _state); + } + else + { + subsolver->curau.ptr.p_double[i] = _state->v_posinf; + subsolver->curbndl.ptr.p_double[offsslacklc+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacklc+2*i+1] = _state->v_posinf; + } + + /* + * Additional integrity check to fix rounding bugs, to make sure that curAL<=curAU. + */ + if( !bndlinactive&&!bnduinactive ) + { + subsolver->curau.ptr.p_double[i] = ae_maxreal(subsolver->curau.ptr.p_double[i], subsolver->cural.ptr.p_double[i], _state); + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+lccnt; + + /* + * Append nonlinear equality/inequality constraints + */ + for(i=0; i<=nnlc-1; i++) + { + + /* + * Calculate: + * * rescale coefficient used to normalize constraints + * * VMax - maximum of constraint value over trust region + */ + vmax = model->fi.ptr.p_double[1+i]; + vmin = model->fi.ptr.p_double[1+i]; + j0 = model->sj.ridx.ptr.p_int[1+i]; + j1 = model->sj.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = model->sj.idx.ptr.p_int[jj]; + v = model->sj.vals.ptr.p_double[jj]; + if( v>=(double)0 ) + { + vmax = vmax+v*subsolver->curbndu.ptr.p_double[j]; + vmin = vmin+v*subsolver->curbndl.ptr.p_double[j]; + } + else + { + vmax = vmax+v*subsolver->curbndl.ptr.p_double[j]; + vmin = vmin+v*subsolver->curbndu.ptr.p_double[j]; + } + } + rescaleby = 1.0; + bndlinactive = !state->hasnl.ptr.p_bool[i]||vmin>state->scalednl.ptr.p_double[i]; + bnduinactive = !state->hasnu.ptr.p_bool[i]||vmaxscalednu.ptr.p_double[i]; + + /* + * Nonlinear constraints are passed with normalization + */ + subsolver->rescalelag.ptr.p_double[lccnt+i] = rescaleby; + + /* + * Always append full row to the upcoming pattern; rows to the effective linear + * constraints matrix are added subject to basic presolve (remove constraints that + * are guaranteed to be inactive). + */ + nlcfsqp_appendscaledsparserow(&subsolver->upcomingpattern, rescaleby, &model->sj, 1+i, _state); + sparseappendelement(&subsolver->upcomingpattern, offsslacknnlc+2*i+0, 1.0, _state); + sparseappendelement(&subsolver->upcomingpattern, offsslacknnlc+2*i+1, -1.0, _state); + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (row itself is retained but + * filled by zeros). + */ + if( bndlinactive&&bnduinactive ) + { + offs = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + subsolver->sparseefflc.vals.ptr.p_double[offs+0] = (double)(1); + subsolver->sparseefflc.vals.ptr.p_double[offs+1] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs+0] = offsslacknnlc+2*i+0; + subsolver->sparseefflc.idx.ptr.p_int[offs+1] = offsslacknnlc+2*i+1; + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = offs+2; + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+0] = 0.0; + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+0] = _state->v_posinf; + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+1] = 0.0; + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+1] = _state->v_posinf; + subsolver->rescalelag.ptr.p_double[lccnt+i] = 0.0; + subsolver->isinactive.ptr.p_bool[lccnt+i] = ae_true; + continue; + } + + /* + * Copy scaled row, add slack terms + */ + offs = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + j0 = model->sj.ridx.ptr.p_int[1+i]; + j1 = model->sj.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + j = model->sj.idx.ptr.p_int[jj]; + v = model->sj.vals.ptr.p_double[jj]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = rescaleby*v; + subsolver->sparseefflc.idx.ptr.p_int[offs] = j; + offs = offs+1; + } + if( !bndlinactive ) + { + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacknnlc+2*i+0; + offs = offs+1; + } + if( !bnduinactive ) + { + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacknnlc+2*i+1; + offs = offs+1; + } + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = offs; + + /* + * Set box constraints on slack variables and bounds on linear equality/inequality constraints + */ + if( !bndlinactive ) + { + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = rescaleby*(state->scalednl.ptr.p_double[i]-model->fi.ptr.p_double[1+i]); + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+0] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+0] = rescaleby*ae_maxreal(state->scalednl.ptr.p_double[i]-model->fi.ptr.p_double[1+i], 0.0, _state); + } + else + { + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = _state->v_neginf; + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+0] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+0] = _state->v_posinf; + } + if( !bnduinactive ) + { + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = rescaleby*(state->scalednu.ptr.p_double[i]-model->fi.ptr.p_double[1+i]); + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+1] = rescaleby*ae_maxreal(model->fi.ptr.p_double[1+i]-state->scalednu.ptr.p_double[i], 0.0, _state); + } + else + { + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = _state->v_posinf; + subsolver->curbndl.ptr.p_double[offsslacknnlc+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknnlc+2*i+1] = _state->v_posinf; + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+nnlc; + + /* + * Finalize sparse matrix structure + */ + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.idx.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.vals.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + subsolver->sparseefflc.ninitialized = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]; + sparseinitduidx(&subsolver->sparseefflc, _state); + + /* + * Solve quadratic program with IPM. + * + * We always treat its result as a valid solution, even for TerminationType<=0. + * In case anything is wrong with solution vector, we will detect it during line + * search phase (merit function does not increase). + * + * NOTE: because we cleaned up constraints that are DEFINITELY inactive within + * trust region, we do not have to worry about StopOnExcessiveBounds option. + */ + rsetallocv(nslack, state->trustrad, &subsolver->tmps, _state); + for(i=0; i<=n-1; i++) + { + subsolver->tmps.ptr.p_double[i] = nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state); + } + rsetallocv(nslack, 0.0, &subsolver->tmporigin, _state); + if( state->usedensebfgs ) + { + + /* + * Dense BFGS is used to generate a quasi-Newton matrix, + * dense IPM is used to solve QP subproblems. + */ + if( dotrace ) + { + stimerstart(&state->timerqpgen, _state); + } + rsetallocm(n, n, 0.0, &subsolver->denseh, _state); + if( dotrace ) + { + stimerstop(&state->timerqpgen, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripminit, _state); + } + vipminitdensewithslacks(&subsolver->ipmsolver, &subsolver->tmps, &subsolver->tmporigin, n, nslack, ae_true, _state); + vipmsetquadraticlinear(&subsolver->ipmsolver, &subsolver->denseh, &subsolver->sparsedummy, 0, ae_true, &subsolver->curb, _state); + vipmsetconstraints(&subsolver->ipmsolver, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, _state); + if( dotrace ) + { + stimerstop(&state->timeripminit, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripmsolve, _state); + } + vipmoptimize(&subsolver->ipmsolver, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + if( dotrace ) + { + stimerstop(&state->timeripmsolve, _state); + } + } + else + { + + /* + * Prepare ordering for QP subproblem or reuse previously computed one + */ + if( xccnt>0&&!sparsetrygatherclear(&subsolver->elasticpattern, &subsolver->upcomingpattern, _state) ) + { + sparsemergepatterns(&subsolver->elasticpattern, &subsolver->upcomingpattern, &subsolver->sparsetmp, _state); + sparsecopybuf(&subsolver->sparsetmp, &subsolver->elasticpattern, _state); + bsetallocv(nslack, ae_true, &subsolver->isbounded, _state); + ipm2proposeordering(&subsolver->ipm2, nslack, ae_true, &subsolver->isbounded, &subsolver->isbounded, &subsolver->elasticpattern, &subsolver->cural, &subsolver->curau, xccnt, &subsolver->elasticordering, _state); + } + + /* + * Low-rank quasi-Newton matrix with positive-only corrections is used, + * sparse IPM with low-rank updates is used to solve QP subproblems. + */ + if( dotrace ) + { + stimerstart(&state->timerqpgen, _state); + } + subsolver->hesssparsediag.matrixtype = 1; + subsolver->hesssparsediag.m = nslack; + subsolver->hesssparsediag.n = nslack; + iallocv(nslack+1, &subsolver->hesssparsediag.ridx, _state); + iallocv(nslack, &subsolver->hesssparsediag.idx, _state); + rallocv(nslack, &subsolver->hesssparsediag.vals, _state); + subsolver->hesssparsediag.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nslack-1; i++) + { + subsolver->hesssparsediag.idx.ptr.p_int[i] = i; + subsolver->hesssparsediag.vals.ptr.p_double[i] = ae_sqrt(ae_machineepsilon, _state)/ae_sqr(subsolver->tmps.ptr.p_double[i], _state); + subsolver->hesssparsediag.ridx.ptr.p_int[i+1] = i+1; + } + targetscale = (double)(0); + for(i=0; i<=nslack-1; i++) + { + v = subsolver->curb.ptr.p_double[i]; + if( ivarscales.ptr.p_double[i]; + } + targetscale = targetscale+v*v; + } + targetscale = ae_sqrt(targetscale, _state)*state->trustrad; + sparsecreatecrsinplace(&subsolver->hesssparsediag, _state); + if( dotrace ) + { + stimerstop(&state->timerqpgen, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripminit, _state); + } + ipm2init(&subsolver->ipm2, &subsolver->tmps, &subsolver->tmporigin, nslack, &subsolver->densedummy, &subsolver->hesssparsediag, 1, ae_true, &subsolver->hesscorrc, &subsolver->hesscorrd, 0, &subsolver->curb, targetscale, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, ae_true, ae_false, _state); + ipm2setmaxits(&subsolver->ipm2, nlcfsqp_maxipmits, _state); + ipm2setordering(&subsolver->ipm2, &subsolver->elasticordering, _state); + if( dotrace ) + { + stimerstop(&state->timeripminit, _state); + } + if( dotrace ) + { + stimerstart(&state->timeripmsolve, _state); + } + ipm2optimize(&subsolver->ipm2, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + if( dotrace ) + { + stimerstop(&state->timeripmsolve, _state); + } + } + rcopyv(n, &subsolver->tmp0, d, _state); + *isinfeasible = !nlcfsqp_qpsubproblemisfeasible(state, subsolver, model, d, _state); + + /* + * Unpack results + */ + for(i=0; i<=n-1; i++) + { + lagbcmult->ptr.p_double[i] = (double)(0); + if( subsolver->retainpositivebclm.ptr.p_bool[i]&&ae_fp_greater(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + if( subsolver->retainnegativebclm.ptr.p_bool[i]&&ae_fp_less(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + } + rcopyv(xccnt, &subsolver->tmp2, lagxcmult, _state); + rmergemulv(xccnt, &subsolver->rescalelag, lagxcmult, _state); + + /* + * Compute predicted decrease in an L1-penalized quadratic model + */ + nlcfsqp_penalizedfg(state, &model->x, &model->fi, &model->sj, &v, &subsolver->tmp0, _state); + *predictedchangemodel = rdotv(n, d, &subsolver->tmp0, _state)+0.5*hessianvmv(hess, d, _state); + *predictedchangepenalty = (double)(0); + for(i=0; i<=lccnt-1; i++) + { + v = spdotvr(&model->x, &state->scla, i, _state); + vv = v+spdotvr(d, &state->scla, i, _state); + if( state->hasal.ptr.p_bool[i] ) + { + *predictedchangepenalty = *predictedchangepenalty+(ae_maxreal(state->sclal.ptr.p_double[i]-vv, (double)(0), _state)-ae_maxreal(state->sclal.ptr.p_double[i]-v, (double)(0), _state)); + } + if( state->hasau.ptr.p_bool[i] ) + { + *predictedchangepenalty = *predictedchangepenalty+(ae_maxreal(vv-state->sclau.ptr.p_double[i], (double)(0), _state)-ae_maxreal(v-state->sclau.ptr.p_double[i], (double)(0), _state)); + } + } + for(i=0; i<=nnlc-1; i++) + { + v = model->fi.ptr.p_double[1+i]; + vv = v+spdotvr(d, &model->sj, 1+i, _state); + if( state->hasnl.ptr.p_bool[i] ) + { + *predictedchangepenalty = *predictedchangepenalty+(ae_maxreal(state->scalednl.ptr.p_double[i]-vv, (double)(0), _state)-ae_maxreal(state->scalednl.ptr.p_double[i]-v, (double)(0), _state)); + } + if( state->hasnu.ptr.p_bool[i] ) + { + *predictedchangepenalty = *predictedchangepenalty+(ae_maxreal(vv-state->scalednu.ptr.p_double[i], (double)(0), _state)-ae_maxreal(v-state->scalednu.ptr.p_double[i], (double)(0), _state)); + } + } + + /* + * Analyze length of D + */ + ae_assert(ae_fp_eq(*d2trustradratio,0.0), "SQP: integrity check 0157 failed", _state); + for(i=0; i<=n-1; i++) + { + *d2trustradratio = ae_maxreal(*d2trustradratio, ae_fabs(d->ptr.p_double[i]/nlcfsqp_gettrustregionk(&model->x, i, state->trustrad, _state), _state), _state); + } + return result; +} + + +/************************************************************************* +This function checks feasibility of a QP subproblem solution D (which +corresponds to X+D after correcting for origin) + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcfsqp_qpsubproblemisfeasible(const minfsqpstate* state, + const minfsqpsubsolver* subsolver, + const varsfuncjac* model, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + double tol; + double v0; + double v1; + double v2; + double vv; + ae_int_t lccnt; + ae_int_t nnlc; + ae_int_t i; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_bool isinfeasible; + ae_bool result; + + + ae_assert(!model->isdense, "SQP: integrity check 5436 failed", _state); + lccnt = state->lccnt; + nnlc = state->nnlc; + tol = ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state); + tol = ae_maxreal(tol, 1.0E-5*state->trustrad, _state); + isinfeasible = ae_false; + for(i=0; i<=lccnt-1; i++) + { + if( !subsolver->isinactive.ptr.p_bool[i] ) + { + + /* + * Calculate product of X+D with I-th linear constraint + */ + v0 = (double)(0); + v1 = (double)(0); + v2 = (double)(0); + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + vv = subsolver->sparserawlc.vals.ptr.p_double[k]; + v0 = v0+vv*model->x.ptr.p_double[subsolver->sparserawlc.idx.ptr.p_int[k]]; + v1 = v1+vv*d->ptr.p_double[subsolver->sparserawlc.idx.ptr.p_int[k]]; + v2 = v2+vv*vv; + } + v1 = v1+v0; + if( state->hasal.ptr.p_bool[i] ) + { + isinfeasible = isinfeasible||ae_maxreal(state->sclal.ptr.p_double[i]-v1, 0.0, _state)/coalesce(ae_sqrt(v2, _state), (double)(1), _state)>tol; + } + if( state->hasau.ptr.p_bool[i] ) + { + isinfeasible = isinfeasible||ae_maxreal(v1-state->sclau.ptr.p_double[i], 0.0, _state)/coalesce(ae_sqrt(v2, _state), (double)(1), _state)>tol; + } + } + } + for(i=0; i<=nnlc-1; i++) + { + if( !subsolver->isinactive.ptr.p_bool[lccnt+i] ) + { + v1 = model->fi.ptr.p_double[1+i]+spdotvr(d, &model->sj, 1+i, _state); + v2 = spdotr2(&model->sj, 1+i, _state); + if( state->hasnl.ptr.p_bool[i] ) + { + isinfeasible = isinfeasible||ae_maxreal(state->scalednl.ptr.p_double[i]-v1, 0.0, _state)/coalesce(ae_sqrt(v2, _state), (double)(1), _state)>tol; + } + if( state->hasnu.ptr.p_bool[i] ) + { + isinfeasible = isinfeasible||ae_maxreal(v1-state->scalednu.ptr.p_double[i], 0.0, _state)/coalesce(ae_sqrt(v2, _state), (double)(1), _state)>tol; + } + } + } + result = !isinfeasible; + return result; +} + + +/************************************************************************* +Copies X to State.X +*************************************************************************/ +static void nlcfsqp_sqpsendx(minfsqpstate* state, + /* Real */ const ae_vector* xs, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&xs->ptr.p_double[i]<=state->scaledbndl.ptr.p_double[i] ) + { + state->x.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&xs->ptr.p_double[i]>=state->scaledbndu.ptr.p_double[i] ) + { + state->x.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + continue; + } + state->x.ptr.p_double[i] = xs->ptr.p_double[i]; + } +} + + +/************************************************************************* +Retrieves F-vector and scaled Jacobian, copies them to FiS and JS. + +Returns True on success, False on failure (when F or J are not finite numbers). +*************************************************************************/ +static ae_bool nlcfsqp_sqpretrievefij(const minfsqpstate* state, + varsfuncjac* vfj, + ae_state *_state) +{ + ae_bool result; + + + ae_assert(!vfj->isdense, "SQP: integrity check 0016 failed", _state); + + /* + * Retrieve function vector and Jacobian + */ + rcopyv(state->nnlc+1, &state->fi, &vfj->fi, _state); + sparsecopybuf(&state->sj, &vfj->sj, _state); + rmergemulv(state->nnlc+1, &state->invfscales, &vfj->fi, _state); + sparsemultiplyrowsby(&vfj->sj, &state->invfscales, _state); + + /* + * Check finiteness + */ + result = ae_isfinite(rdotv2(state->nnlc+1, &vfj->fi, _state), _state)&&ae_isfinite(rdotv2(vfj->sj.ridx.ptr.p_int[state->nnlc+1], &vfj->sj.vals, _state), _state); + return result; +} + + +/************************************************************************* +This function calculates Lagrangian of the problem (in scaled variables): +its value and gradient. + +Additionally it also estimates violation of linear constraints at the point +as well as index of the most violated constraint +*************************************************************************/ +static void nlcfsqp_lagrangianfg(minfsqpstate* state, + /* Real */ const ae_vector* x, + double trustrad, + /* Real */ const ae_vector* fi, + const sparsematrix* sj, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_bool uselagrangeterms, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + double v; + double vlag; + double vact; + double vd; + double vs; + double lagalpha; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + *f = 0.0; + + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + lagalpha = rcase2(uselagrangeterms, (double)(1), (double)(0), _state); + + /* + * Target function + */ + rsetv(n, 0.0, g, _state); + *f = fi->ptr.p_double[0]; + j0 = sj->ridx.ptr.p_int[0]; + j1 = sj->ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[sj->idx.ptr.p_int[jj]] = sj->vals.ptr.p_double[jj]; + } + + /* + * Lagrangian terms for box constraints + */ + for(i=0; i<=n-1; i++) + { + *f = *f+lagalpha*lagbcmult->ptr.p_double[i]*x->ptr.p_double[i]; + g->ptr.p_double[i] = g->ptr.p_double[i]+lagalpha*lagbcmult->ptr.p_double[i]; + } + + /* + * Lagrangian terms for linear constraints, constraint violations + */ + if( lccnt>0 ) + { + rvectorsetlengthatleast(&state->sclagtmp0, ae_maxint(lccnt, n, _state), _state); + rvectorsetlengthatleast(&state->sclagtmp1, ae_maxint(lccnt, n, _state), _state); + sparsemv(&state->scla, x, &state->sclagtmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + + /* + * Prepare + */ + v = state->sclagtmp0.ptr.p_double[i]; + vlag = lagalpha*lagxcmult->ptr.p_double[i]; + state->sclagtmp1.ptr.p_double[i] = (double)(0); + + /* + * Primary Lagrangian term + */ + vact = v; + vd = (double)(1); + *f = *f+vlag*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+vlag*vd; + + /* + * Quadratic augmentation term + */ + if( state->hasal.ptr.p_bool[i]&&vsclal.ptr.p_double[i] ) + { + vact = v-state->sclal.ptr.p_double[i]; + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcfsqp_augmentationfactor*vact; + } + if( state->hasau.ptr.p_bool[i]&&v>state->sclau.ptr.p_double[i] ) + { + vact = v-state->sclau.ptr.p_double[i]; + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcfsqp_augmentationfactor*vact; + } + } + sparsemtv(&state->scla, &state->sclagtmp1, &state->sclagtmp0, _state); + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = g->ptr.p_double[i]+state->sclagtmp0.ptr.p_double[i]; + } + } + + /* + * Lagrangian terms for nonlinear constraints + */ + rvectorsetlengthatleast(&state->sclagtmp1, nnlc, _state); + for(i=0; i<=nnlc-1; i++) + { + v = fi->ptr.p_double[1+i]; + vlag = lagalpha*lagxcmult->ptr.p_double[lccnt+i]; + vs = (double)(0); + + /* + * Lagrangian term + */ + vact = v; + vd = (double)(1); + *f = *f+vlag*vact; + vs = vs+vlag*vd; + + /* + * Augmentation term + */ + vact = (double)(0); + vd = (double)(0); + if( state->hasnl.ptr.p_bool[i]&&vscalednl.ptr.p_double[i] ) + { + vact = state->scalednl.ptr.p_double[i]-v; + vd = (double)(-1); + } + if( state->hasnu.ptr.p_bool[i]&&v>state->scalednu.ptr.p_double[i] ) + { + vact = v-state->scalednu.ptr.p_double[i]; + vd = (double)(1); + } + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + vs = vs+nlcfsqp_augmentationfactor*vact*vd; + + /* + * Modify gradient + */ + j0 = sj->ridx.ptr.p_int[1+i]; + j1 = sj->ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[sj->idx.ptr.p_int[jj]] = g->ptr.p_double[sj->idx.ptr.p_int[jj]]+vs*sj->vals.ptr.p_double[jj]; + } + } +} + + +/************************************************************************* +This function calculates Lagrangian of the problem (in scaled variables): +its value and gradient. + +Additionally it also estimates violation of linear constraints at the point +as well as index of the most violated constraint +*************************************************************************/ +static void nlcfsqp_penalizedfg(minfsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + const sparsematrix* sj, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + double v; + double vact; + double vd; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + *f = 0.0; + + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + + /* + * Target function + */ + rsetv(n, 0.0, g, _state); + *f = fi->ptr.p_double[0]; + j0 = sj->ridx.ptr.p_int[0]; + j1 = sj->ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[sj->idx.ptr.p_int[jj]] = sj->vals.ptr.p_double[jj]; + } + + /* + * penalties for linear constraints + */ + if( lccnt>0 ) + { + rvectorsetlengthatleast(&state->sclagtmp0, ae_maxint(lccnt, n, _state), _state); + rvectorsetlengthatleast(&state->sclagtmp1, ae_maxint(lccnt, n, _state), _state); + sparsemv(&state->scla, x, &state->sclagtmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + v = state->sclagtmp0.ptr.p_double[i]; + state->sclagtmp1.ptr.p_double[i] = (double)(0); + if( state->hasal.ptr.p_bool[i]&&vsclal.ptr.p_double[i] ) + { + vact = v-state->sclal.ptr.p_double[i]; + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcfsqp_augmentationfactor*vact; + } + if( state->hasau.ptr.p_bool[i]&&v>state->sclau.ptr.p_double[i] ) + { + vact = v-state->sclau.ptr.p_double[i]; + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcfsqp_augmentationfactor*vact; + } + } + sparsemtv(&state->scla, &state->sclagtmp1, &state->sclagtmp0, _state); + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = g->ptr.p_double[i]+state->sclagtmp0.ptr.p_double[i]; + } + } + + /* + * Lagrangian terms for nonlinear constraints + */ + for(i=0; i<=nnlc-1; i++) + { + v = fi->ptr.p_double[1+i]; + vact = (double)(0); + vd = (double)(0); + if( state->hasnl.ptr.p_bool[i]&&vscalednl.ptr.p_double[i] ) + { + vact = state->scalednl.ptr.p_double[i]-v; + vd = (double)(-1); + } + if( state->hasnu.ptr.p_bool[i]&&v>state->scalednu.ptr.p_double[i] ) + { + vact = v-state->scalednu.ptr.p_double[i]; + vd = (double)(1); + } + *f = *f+0.5*nlcfsqp_augmentationfactor*vact*vact; + j0 = sj->ridx.ptr.p_int[1+i]; + j1 = sj->ridx.ptr.p_int[1+i+1]-1; + v = nlcfsqp_augmentationfactor*vact*vd; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[sj->idx.ptr.p_int[jj]] = g->ptr.p_double[sj->idx.ptr.p_int[jj]]+v*sj->vals.ptr.p_double[jj]; + } + } +} + + +/************************************************************************* +This function calculates target and constraint violation +*************************************************************************/ +static void nlcfsqp_targetandconstraints(minfsqpstate* state, + const varsfuncjac* vfj, + double* tgt, + double* cv, + ae_state *_state) +{ + ae_int_t i; + ae_int_t lccnt; + ae_int_t nnlc; + double v; + double vv; + + *tgt = 0.0; + *cv = 0.0; + + lccnt = state->lccnt; + nnlc = state->nnlc; + + /* + * Target and constraints: initial state + */ + *tgt = vfj->fi.ptr.p_double[0]; + *cv = (double)(0); + + /* + * Constraint violation + */ + if( lccnt>0 ) + { + rvectorsetlengthatleast(&state->mftmp0, lccnt, _state); + sparsemv(&state->scla, &vfj->x, &state->mftmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + v = state->mftmp0.ptr.p_double[i]; + if( state->hasal.ptr.p_bool[i]&&vsclal.ptr.p_double[i] ) + { + vv = state->sclal.ptr.p_double[i]-v; + *tgt = *tgt+0.5*nlcfsqp_augmentationfactor*vv*vv; + *cv = *cv+vv; + } + if( state->hasau.ptr.p_bool[i]&&v>state->sclau.ptr.p_double[i] ) + { + vv = v-state->sclau.ptr.p_double[i]; + *tgt = *tgt+0.5*nlcfsqp_augmentationfactor*vv*vv; + *cv = *cv+vv; + } + } + } + for(i=0; i<=nnlc-1; i++) + { + v = vfj->fi.ptr.p_double[1+i]; + if( state->hasnl.ptr.p_bool[i]&&vscalednl.ptr.p_double[i] ) + { + vv = state->scalednl.ptr.p_double[i]-v; + *cv = *cv+vv; + *tgt = *tgt+0.5*nlcfsqp_augmentationfactor*vv*vv; + } + if( state->hasnu.ptr.p_bool[i]&&v>state->scalednu.ptr.p_double[i] ) + { + vv = v-state->scalednu.ptr.p_double[i]; + *cv = *cv+vv; + *tgt = *tgt+0.5*nlcfsqp_augmentationfactor*vv*vv; + } + } +} + + +/************************************************************************* +This function calculates raw (unaugmented and smooth) Lagrangian +*************************************************************************/ +static double nlcfsqp_rawlagrangian(minfsqpstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + double result; + + + n = state->n; + lccnt = state->lccnt; + nnlc = state->nnlc; + + /* + * Lagrangian: primary term + */ + result = fi->ptr.p_double[0]; + + /* + * Lagrangian: handle box constraints + * + * NOTE: we do not add box constrained term to the merit function because + * box constraints are handled exactly and we do not violate them. + */ + for(i=0; i<=n-1; i++) + { + result = result+lagbcmult->ptr.p_double[i]*x->ptr.p_double[i]; + } + + /* + * Merit function: augmentation and penalty for linear constraints + */ + if( lccnt>0 ) + { + rvectorsetlengthatleast(&state->mftmp0, lccnt, _state); + sparsemv(&state->scla, x, &state->mftmp0, _state); + for(i=0; i<=lccnt-1; i++) + { + result = result+lagxcmult->ptr.p_double[i]*state->mftmp0.ptr.p_double[i]; + } + } + + /* + * Merit function: augmentation and penalty for nonlinear constraints + */ + for(i=0; i<=nnlc-1; i++) + { + result = result+lagxcmult->ptr.p_double[lccnt+i]*fi->ptr.p_double[1+i]; + } + return result; +} + + +/************************************************************************* +Returns k-th component of the trust region + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static double nlcfsqp_gettrustregionk(/* Real */ const ae_vector* xcur, + ae_int_t k, + double trustrad, + ae_state *_state) +{ + double result; + + + result = trustrad*ae_maxreal(ae_fabs(xcur->ptr.p_double[k], _state), 1.0, _state); + return result; +} + + +/************************************************************************* +Checks acceptability by the filter + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcfsqp_isacceptable(minfsqpstate* state, + double tgt0, + double h0, + double tgt1, + double h1, + double predictedchangemodel, + double predictedchangepenalty, + ae_bool dotraceunacceptability, + ae_state *_state) +{ + ae_bool result; + + + if( ae_fp_greater_eq(tgt1,tgt0)&&ae_fp_greater_eq(h1,h0) ) + { + + /* + * Neither the target nor constraints were improved + */ + if( dotraceunacceptability ) + { + ae_trace("> the filter rejects step: both meritf and constraint violations increase\n"); + } + result = ae_false; + return result; + } + if( ae_fp_less(predictedchangemodel,(double)(0))&&ae_fp_greater(tgt1-tgt0,nlcfsqp_sufficientdecreasesigma*predictedchangemodel) ) + { + + /* + * The model is predicted to decrease, but it does not decrease fast enough, or does not decrease at all + */ + if( dotraceunacceptability ) + { + ae_trace("> the filter rejects step: sufficient decrease condition for meritf does not hold\n"); + } + result = ae_false; + return result; + } + if( !nlpfisacceptable(&state->filter, tgt0, h0, tgt1, h1, _state) ) + { + + /* + * Dominated by another point + */ + if( dotraceunacceptability ) + { + if( state->filter.violationistoohigh ) + { + ae_trace("> the filter rejects step: constraint violation cv=%0.9e is too high (higher than maxcv=%0.9e)\n", + (double)(h1), + (double)(state->filter.maxh)); + } + else + { + ae_trace("> the filter rejects step: the new point is dominated\n"); + } + } + result = ae_false; + return result; + } + result = ae_true; + return result; +} + + +/************************************************************************* +Rescale target/constraints if gradients deviate from 1.0 too much. Compute +diagonal scales for the Hessian. + +Parameters: + Model current function vector and Jacobian, already + scaled according to the present scaling. + FirstScaling if True, this function exactly normalizes everything, + except for the case when norms are less than 1. + If False, it tries to normalize but performs only + limited renormalization in order to avoid destabilization + of the process. + + -- ALGLIB -- + Copyright 23.02.2024 by Bochkanov Sergey +*************************************************************************/ +static void nlcfsqp_autoscalevarstargetconstraints(minfsqpstate* state, + varsfuncjac* model, + ae_bool firstscaling, + ae_bool dotrace, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nnlc; + ae_int_t i; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + double nrm2; + double v; + double multiplyby; + double setscaleto; + ae_bool wasrescale; + ae_bool bigscaletriggered; + ae_bool smallscaletriggered; + + + ae_assert(!model->isdense, "FSQP: integrity check 3219 failed", _state); + n = state->n; + nnlc = state->nnlc; + + /* + * Hessian scale + */ + rallocv(n, &state->varscales, _state); + for(i=0; i<=n-1; i++) + { + state->varscales.ptr.p_double[i] = nlcfsqp_gettrustregionk(&state->stepk.x, i, 1.0, _state); + } + + /* + * Target/constraints + */ + wasrescale = ae_false; + bigscaletriggered = ae_false; + smallscaletriggered = ae_false; + for(i=0; i<=nnlc; i++) + { + + /* + * Determine (a) multiplicative coefficient applied to function value + * and Jacobian row, and (b) new value of the function scale. + */ + j0 = model->sj.ridx.ptr.p_int[i]; + j1 = model->sj.ridx.ptr.p_int[i+1]-1; + nrm2 = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + v = model->sj.vals.ptr.p_double[jj]*state->varscales.ptr.p_double[model->sj.idx.ptr.p_int[jj]]; + nrm2 = nrm2+v*v; + } + nrm2 = ae_sqrt(nrm2, _state); + multiplyby = 1.0; + setscaleto = state->fscaleszzz.ptr.p_double[i]; + if( ae_fp_greater_eq(nrm2,state->sqpbigscale) ) + { + v = nrm2; + if( !firstscaling ) + { + v = ae_minreal(v, nlcfsqp_sqpmaxrescale, _state); + } + multiplyby = (double)1/v; + setscaleto = state->fscaleszzz.ptr.p_double[i]*v; + bigscaletriggered = ae_true; + } + if( ae_fp_less_eq(nrm2,state->sqpsmallscale)&&ae_fp_greater(state->fscaleszzz.ptr.p_double[i],1.0) ) + { + v = nrm2; + if( !firstscaling ) + { + v = ae_maxreal(v, nlcfsqp_sqpminrescale, _state); + } + if( ae_fp_greater(state->fscaleszzz.ptr.p_double[i]*v,(double)(1)) ) + { + multiplyby = (double)1/v; + setscaleto = state->fscaleszzz.ptr.p_double[i]*v; + } + else + { + multiplyby = state->fscaleszzz.ptr.p_double[i]; + setscaleto = 1.0; + } + smallscaletriggered = ae_true; + } + if( ae_fp_neq(multiplyby,1.0) ) + { + model->fi.ptr.p_double[i] = model->fi.ptr.p_double[i]*multiplyby; + j0 = model->sj.ridx.ptr.p_int[i]; + j1 = model->sj.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + model->sj.vals.ptr.p_double[jj] = model->sj.vals.ptr.p_double[jj]*multiplyby; + } + state->fscaleszzz.ptr.p_double[i] = setscaleto; + state->invfscales.ptr.p_double[i] = (double)1/setscaleto; + if( i>=1 ) + { + if( state->hasnl.ptr.p_bool[i-1] ) + { + state->scalednl.ptr.p_double[i-1] = state->rawnl.ptr.p_double[i-1]/setscaleto; + } + if( state->hasnu.ptr.p_bool[i-1] ) + { + state->scalednu.ptr.p_double[i-1] = state->rawnu.ptr.p_double[i-1]/setscaleto; + } + } + wasrescale = ae_true; + } + } + if( wasrescale ) + { + nlpfclear(&state->filter, _state); + if( dotrace ) + { + ae_trace("> target/constraints were rescaled due to gradient norms deviating too much from 1.0, filter cleared"); + } + if( dotrace&&bigscaletriggered ) + { + ae_trace(", downscaled"); + } + if( smallscaletriggered ) + { + state->sqpsmallscale = state->sqpsmallscale*nlcfsqp_sqpsmallscaledecrease; + if( dotrace ) + { + ae_trace(", upscaled and decreased the lower bound"); + } + } + if( dotrace ) + { + ae_trace("\n"); + } + } +} + + +/************************************************************************* +Returns effective iteration limit (MaxIts + modification), given additional +iterations for feasibility restoration: + +* 0 if MaxIts=0 +* otherwise: MaxIts if AddItsForCTol=0 +* otherwise: MaxIts if not WerePointsBelowCTol +* otherwise: MaxIts if RepSclErr<=CTol +: otherwise: MaxIts+AddItsForCTol + + -- ALGLIB -- + Copyright 10.06.2025 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t nlcfsqp_geteffectivemaxits(minfsqpstate* state, + ae_state *_state) +{ + ae_int_t result; + + + result = critgetmaxits(&state->criteria, _state); + if( (result==0||state->additsforctol==0)||!state->werepointsbelowctol ) + { + return result; + } + if( ae_fp_greater(state->repsclerr,state->ctol) ) + { + result = result+state->additsforctol; + } + return result; +} + + +/************************************************************************* +Convert sparse matrix to a dense one +*************************************************************************/ +static void nlcfsqp_sparse2dense(const sparsematrix* s, + /* Real */ ae_matrix* d, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + + ae_assert((s->matrixtype==1&&s->m>=1)&&s->n>=1, "SQP: integrity check 5541 failed", _state); + rsetallocm(s->m, s->n, 0.0, d, _state); + for(i=0; i<=s->m-1; i++) + { + j0 = s->ridx.ptr.p_int[i]; + j1 = s->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + d->ptr.pp_double[i][s->idx.ptr.p_int[jj]] = s->vals.ptr.p_double[jj]; + } + } +} + + +/************************************************************************* +Append matrix row multiplied by a scaling factor; silently switches +MatrixType=-10083 to MatrixType=1 +*************************************************************************/ +static void nlcfsqp_appendscaledsparserow(sparsematrix* dst, + double alpha, + const sparsematrix* src, + ae_int_t rowidx, + ae_state *_state) +{ + ae_int_t m; + ae_int_t offs; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t nnz; + + + ae_assert((dst->matrixtype==1||dst->matrixtype==-10083)&&dst->ninitialized==dst->ridx.ptr.p_int[dst->m], "FSQP.AppendScaledSparseRow: Dst is not completely initialized", _state); + m = dst->m; + offs = dst->ridx.ptr.p_int[m]; + j0 = src->ridx.ptr.p_int[rowidx]; + j1 = src->ridx.ptr.p_int[rowidx+1]-1; + nnz = j1-j0+1; + dst->matrixtype = 1; + igrowv(m+1, &dst->didx, _state); + igrowv(m+1, &dst->uidx, _state); + igrowv(m+2, &dst->ridx, _state); + igrowv(dst->ridx.ptr.p_int[m]+nnz, &dst->idx, _state); + rgrowv(dst->ridx.ptr.p_int[m]+nnz, &dst->vals, _state); + offs = dst->ridx.ptr.p_int[m]; + for(jj=j0; jj<=j1; jj++) + { + dst->idx.ptr.p_int[offs] = src->idx.ptr.p_int[jj]; + dst->vals.ptr.p_double[offs] = alpha*src->vals.ptr.p_double[jj]; + offs = offs+1; + } + dst->ridx.ptr.p_int[m+1] = offs; + dst->didx.ptr.p_int[m] = ibinarysearchlft(&dst->idx, dst->ridx.ptr.p_int[m], dst->ridx.ptr.p_int[m+1], m, _state); + dst->uidx.ptr.p_int[m] = dst->didx.ptr.p_int[m]+icase2(dst->didx.ptr.p_int[m]ridx.ptr.p_int[m+1]&&dst->idx.ptr.p_int[dst->didx.ptr.p_int[m]]==m, 1, 0, _state); + dst->ninitialized = dst->ridx.ptr.p_int[m+1]; + dst->m = m+1; +} + + +void _minfsqpsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minfsqpsubsolver *p = (minfsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_init(&p->ipmsolver, _state, make_automatic); + _ipm2state_init(&p->ipm2, _state, make_automatic); + ae_vector_init(&p->ordering, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->elasticordering, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->pattern, _state, make_automatic); + _sparsematrix_init(&p->elasticpattern, _state, make_automatic); + _sparsematrix_init(&p->upcomingpattern, _state, make_automatic); + ae_vector_init(&p->curb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cural, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curau, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparserawlc, _state, make_automatic); + _sparsematrix_init(&p->sparseefflc, _state, make_automatic); + ae_vector_init(&p->lastlaglc, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummy1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densedummy, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsetmp, _state, make_automatic); + _sparsematrix_init(&p->sparsedummy, _state, make_automatic); + ae_vector_init(&p->tmps, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmporigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->retainnegativebclm, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->retainpositivebclm, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rescalelag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isinactive, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->tmpcorrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isbounded, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hessdiag, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hesscorrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hesscorrd, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->hesssparsediag, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); +} + + +void _minfsqpsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minfsqpsubsolver *dst = (minfsqpsubsolver*)_dst; + const minfsqpsubsolver *src = (const minfsqpsubsolver*)_src; + _vipmstate_init_copy(&dst->ipmsolver, &src->ipmsolver, _state, make_automatic); + _ipm2state_init_copy(&dst->ipm2, &src->ipm2, _state, make_automatic); + ae_vector_init_copy(&dst->ordering, &src->ordering, _state, make_automatic); + ae_vector_init_copy(&dst->elasticordering, &src->elasticordering, _state, make_automatic); + _sparsematrix_init_copy(&dst->pattern, &src->pattern, _state, make_automatic); + _sparsematrix_init_copy(&dst->elasticpattern, &src->elasticpattern, _state, make_automatic); + _sparsematrix_init_copy(&dst->upcomingpattern, &src->upcomingpattern, _state, make_automatic); + ae_vector_init_copy(&dst->curb, &src->curb, _state, make_automatic); + ae_vector_init_copy(&dst->curbndl, &src->curbndl, _state, make_automatic); + ae_vector_init_copy(&dst->curbndu, &src->curbndu, _state, make_automatic); + ae_vector_init_copy(&dst->cural, &src->cural, _state, make_automatic); + ae_vector_init_copy(&dst->curau, &src->curau, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparserawlc, &src->sparserawlc, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseefflc, &src->sparseefflc, _state, make_automatic); + ae_vector_init_copy(&dst->lastlaglc, &src->lastlaglc, _state, make_automatic); + dst->penalty0 = src->penalty0; + dst->penalty1 = src->penalty1; + ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic); + ae_vector_init_copy(&dst->dummy1, &src->dummy1, _state, make_automatic); + ae_matrix_init_copy(&dst->densedummy, &src->densedummy, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsetmp, &src->sparsetmp, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsedummy, &src->sparsedummy, _state, make_automatic); + ae_vector_init_copy(&dst->tmps, &src->tmps, _state, make_automatic); + ae_vector_init_copy(&dst->tmporigin, &src->tmporigin, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->retainnegativebclm, &src->retainnegativebclm, _state, make_automatic); + ae_vector_init_copy(&dst->retainpositivebclm, &src->retainpositivebclm, _state, make_automatic); + ae_vector_init_copy(&dst->rescalelag, &src->rescalelag, _state, make_automatic); + ae_vector_init_copy(&dst->isinactive, &src->isinactive, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpcorrc, &src->tmpcorrc, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdiag, &src->tmpdiag, _state, make_automatic); + ae_vector_init_copy(&dst->isbounded, &src->isbounded, _state, make_automatic); + ae_vector_init_copy(&dst->hessdiag, &src->hessdiag, _state, make_automatic); + ae_matrix_init_copy(&dst->hesscorrc, &src->hesscorrc, _state, make_automatic); + ae_vector_init_copy(&dst->hesscorrd, &src->hesscorrd, _state, make_automatic); + dst->hessrank = src->hessrank; + _sparsematrix_init_copy(&dst->hesssparsediag, &src->hesssparsediag, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); +} + + +void _minfsqpsubsolver_clear(void* _p) +{ + minfsqpsubsolver *p = (minfsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_clear(&p->ipmsolver); + _ipm2state_clear(&p->ipm2); + ae_vector_clear(&p->ordering); + ae_vector_clear(&p->elasticordering); + _sparsematrix_clear(&p->pattern); + _sparsematrix_clear(&p->elasticpattern); + _sparsematrix_clear(&p->upcomingpattern); + ae_vector_clear(&p->curb); + ae_vector_clear(&p->curbndl); + ae_vector_clear(&p->curbndu); + ae_vector_clear(&p->cural); + ae_vector_clear(&p->curau); + _sparsematrix_clear(&p->sparserawlc); + _sparsematrix_clear(&p->sparseefflc); + ae_vector_clear(&p->lastlaglc); + ae_matrix_clear(&p->denseh); + ae_vector_clear(&p->dummy1); + ae_matrix_clear(&p->densedummy); + _sparsematrix_clear(&p->sparsetmp); + _sparsematrix_clear(&p->sparsedummy); + ae_vector_clear(&p->tmps); + ae_vector_clear(&p->tmporigin); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->retainnegativebclm); + ae_vector_clear(&p->retainpositivebclm); + ae_vector_clear(&p->rescalelag); + ae_vector_clear(&p->isinactive); + ae_matrix_clear(&p->tmpcorrc); + ae_vector_clear(&p->tmpdiag); + ae_vector_clear(&p->isbounded); + ae_vector_clear(&p->hessdiag); + ae_matrix_clear(&p->hesscorrc); + ae_vector_clear(&p->hesscorrd); + _sparsematrix_clear(&p->hesssparsediag); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); +} + + +void _minfsqpsubsolver_destroy(void* _p) +{ + minfsqpsubsolver *p = (minfsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_destroy(&p->ipmsolver); + _ipm2state_destroy(&p->ipm2); + ae_vector_destroy(&p->ordering); + ae_vector_destroy(&p->elasticordering); + _sparsematrix_destroy(&p->pattern); + _sparsematrix_destroy(&p->elasticpattern); + _sparsematrix_destroy(&p->upcomingpattern); + ae_vector_destroy(&p->curb); + ae_vector_destroy(&p->curbndl); + ae_vector_destroy(&p->curbndu); + ae_vector_destroy(&p->cural); + ae_vector_destroy(&p->curau); + _sparsematrix_destroy(&p->sparserawlc); + _sparsematrix_destroy(&p->sparseefflc); + ae_vector_destroy(&p->lastlaglc); + ae_matrix_destroy(&p->denseh); + ae_vector_destroy(&p->dummy1); + ae_matrix_destroy(&p->densedummy); + _sparsematrix_destroy(&p->sparsetmp); + _sparsematrix_destroy(&p->sparsedummy); + ae_vector_destroy(&p->tmps); + ae_vector_destroy(&p->tmporigin); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->retainnegativebclm); + ae_vector_destroy(&p->retainpositivebclm); + ae_vector_destroy(&p->rescalelag); + ae_vector_destroy(&p->isinactive); + ae_matrix_destroy(&p->tmpcorrc); + ae_vector_destroy(&p->tmpdiag); + ae_vector_destroy(&p->isbounded); + ae_vector_destroy(&p->hessdiag); + ae_matrix_destroy(&p->hesscorrc); + ae_vector_destroy(&p->hesscorrd); + _sparsematrix_destroy(&p->hesssparsediag); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); +} + + +void _minfsqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minfsqpstate *p = (minfsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->scla, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->sclal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasnl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasnu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rawnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scalednl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scalednu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fscaleszzz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invfscales, 0, DT_REAL, _state, make_automatic); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sj, _state, make_automatic); + _varsfuncjac_init(&p->stepk, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xprev, 0, DT_REAL, _state, make_automatic); + _minfsqpsubsolver_init(&p->subsolver, _state, make_automatic); + _xbfgshessian_init(&p->hess, _state, make_automatic); + ae_vector_init(&p->lagbcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagxcmult, 0, DT_REAL, _state, make_automatic); + _varsfuncjac_init(&p->cand, _state, make_automatic); + _varsfuncjac_init(&p->probe, _state, make_automatic); + ae_vector_init(&p->dtrial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dmu, 0, DT_REAL, _state, make_automatic); + _nlpfilter_init(&p->filter, _state, make_automatic); + ae_vector_init(&p->replagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagnlc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->varscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmppend, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummylagbcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummylagxcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmplaggrad, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcandlaggrad, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclagtmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclagtmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mftmp0, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timerqpgen, _state, make_automatic); + _stimer_init(&p->timeripminit, _state, make_automatic); + _stimer_init(&p->timeripmsolve, _state, make_automatic); + _stimer_init(&p->timercallback, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _minfsqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minfsqpstate *dst = (minfsqpstate*)_dst; + const minfsqpstate *src = (const minfsqpstate*)_src; + dst->n = src->n; + dst->lccnt = src->lccnt; + dst->nnlc = src->nnlc; + dst->usedensebfgs = src->usedensebfgs; + dst->inittrustrad = src->inittrustrad; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + _sparsematrix_init_copy(&dst->scla, &src->scla, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); + ae_vector_init_copy(&dst->sclal, &src->sclal, _state, make_automatic); + ae_vector_init_copy(&dst->sclau, &src->sclau, _state, make_automatic); + ae_vector_init_copy(&dst->lcscales, &src->lcscales, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasnl, &src->hasnl, _state, make_automatic); + ae_vector_init_copy(&dst->hasnu, &src->hasnu, _state, make_automatic); + ae_vector_init_copy(&dst->rawnl, &src->rawnl, _state, make_automatic); + ae_vector_init_copy(&dst->rawnu, &src->rawnu, _state, make_automatic); + ae_vector_init_copy(&dst->scalednl, &src->scalednl, _state, make_automatic); + ae_vector_init_copy(&dst->scalednu, &src->scalednu, _state, make_automatic); + ae_vector_init_copy(&dst->fscaleszzz, &src->fscaleszzz, _state, make_automatic); + ae_vector_init_copy(&dst->invfscales, &src->invfscales, _state, make_automatic); + dst->sqpbigscale = src->sqpbigscale; + dst->sqpsmallscale = src->sqpsmallscale; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->bfgsresetfreq = src->bfgsresetfreq; + dst->additsforctol = src->additsforctol; + dst->ctol = src->ctol; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + _sparsematrix_init_copy(&dst->sj, &src->sj, _state, make_automatic); + dst->f = src->f; + dst->needfisj = src->needfisj; + dst->xupdated = src->xupdated; + dst->werepointsbelowctol = src->werepointsbelowctol; + dst->trustrad = src->trustrad; + dst->trustradgrowth = src->trustradgrowth; + dst->trustradstagnationcnt = src->trustradstagnationcnt; + dst->fstagnationcnt = src->fstagnationcnt; + _varsfuncjac_init_copy(&dst->stepk, &src->stepk, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->xprev, &src->xprev, _state, make_automatic); + _minfsqpsubsolver_init_copy(&dst->subsolver, &src->subsolver, _state, make_automatic); + _xbfgshessian_init_copy(&dst->hess, &src->hess, _state, make_automatic); + ae_vector_init_copy(&dst->lagbcmult, &src->lagbcmult, _state, make_automatic); + ae_vector_init_copy(&dst->lagxcmult, &src->lagxcmult, _state, make_automatic); + _varsfuncjac_init_copy(&dst->cand, &src->cand, _state, make_automatic); + _varsfuncjac_init_copy(&dst->probe, &src->probe, _state, make_automatic); + ae_vector_init_copy(&dst->dtrial, &src->dtrial, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_vector_init_copy(&dst->dmu, &src->dmu, _state, make_automatic); + _nlpfilter_init_copy(&dst->filter, &src->filter, _state, make_automatic); + ae_vector_init_copy(&dst->replagbc, &src->replagbc, _state, make_automatic); + ae_vector_init_copy(&dst->replaglc, &src->replaglc, _state, make_automatic); + ae_vector_init_copy(&dst->replagnlc, &src->replagnlc, _state, make_automatic); + ae_vector_init_copy(&dst->varscales, &src->varscales, _state, make_automatic); + ae_vector_init_copy(&dst->tmppend, &src->tmppend, _state, make_automatic); + ae_vector_init_copy(&dst->tmphd, &src->tmphd, _state, make_automatic); + ae_vector_init_copy(&dst->dummylagbcmult, &src->dummylagbcmult, _state, make_automatic); + ae_vector_init_copy(&dst->dummylagxcmult, &src->dummylagxcmult, _state, make_automatic); + ae_vector_init_copy(&dst->tmplaggrad, &src->tmplaggrad, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcandlaggrad, &src->tmpcandlaggrad, _state, make_automatic); + ae_vector_init_copy(&dst->tmphdiag, &src->tmphdiag, _state, make_automatic); + ae_vector_init_copy(&dst->sclagtmp0, &src->sclagtmp0, _state, make_automatic); + ae_vector_init_copy(&dst->sclagtmp1, &src->sclagtmp1, _state, make_automatic); + ae_vector_init_copy(&dst->mftmp0, &src->mftmp0, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->repsclerr = src->repsclerr; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timerqpgen, &src->timerqpgen, _state, make_automatic); + _stimer_init_copy(&dst->timeripminit, &src->timeripminit, _state, make_automatic); + _stimer_init_copy(&dst->timeripmsolve, &src->timeripmsolve, _state, make_automatic); + _stimer_init_copy(&dst->timercallback, &src->timercallback, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _minfsqpstate_clear(void* _p) +{ + minfsqpstate *p = (minfsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + _sparsematrix_clear(&p->scla); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); + ae_vector_clear(&p->sclal); + ae_vector_clear(&p->sclau); + ae_vector_clear(&p->lcscales); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_vector_clear(&p->hasnl); + ae_vector_clear(&p->hasnu); + ae_vector_clear(&p->rawnl); + ae_vector_clear(&p->rawnu); + ae_vector_clear(&p->scalednl); + ae_vector_clear(&p->scalednu); + ae_vector_clear(&p->fscaleszzz); + ae_vector_clear(&p->invfscales); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + _sparsematrix_clear(&p->sj); + _varsfuncjac_clear(&p->stepk); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->xprev); + _minfsqpsubsolver_clear(&p->subsolver); + _xbfgshessian_clear(&p->hess); + ae_vector_clear(&p->lagbcmult); + ae_vector_clear(&p->lagxcmult); + _varsfuncjac_clear(&p->cand); + _varsfuncjac_clear(&p->probe); + ae_vector_clear(&p->dtrial); + ae_vector_clear(&p->d0); + ae_vector_clear(&p->dmu); + _nlpfilter_clear(&p->filter); + ae_vector_clear(&p->replagbc); + ae_vector_clear(&p->replaglc); + ae_vector_clear(&p->replagnlc); + ae_vector_clear(&p->varscales); + ae_vector_clear(&p->tmppend); + ae_vector_clear(&p->tmphd); + ae_vector_clear(&p->dummylagbcmult); + ae_vector_clear(&p->dummylagxcmult); + ae_vector_clear(&p->tmplaggrad); + ae_vector_clear(&p->tmpcandlaggrad); + ae_vector_clear(&p->tmphdiag); + ae_vector_clear(&p->sclagtmp0); + ae_vector_clear(&p->sclagtmp1); + ae_vector_clear(&p->mftmp0); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timerqpgen); + _stimer_clear(&p->timeripminit); + _stimer_clear(&p->timeripmsolve); + _stimer_clear(&p->timercallback); + _rcommstate_clear(&p->rstate); +} + + +void _minfsqpstate_destroy(void* _p) +{ + minfsqpstate *p = (minfsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + _sparsematrix_destroy(&p->scla); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); + ae_vector_destroy(&p->sclal); + ae_vector_destroy(&p->sclau); + ae_vector_destroy(&p->lcscales); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_vector_destroy(&p->hasnl); + ae_vector_destroy(&p->hasnu); + ae_vector_destroy(&p->rawnl); + ae_vector_destroy(&p->rawnu); + ae_vector_destroy(&p->scalednl); + ae_vector_destroy(&p->scalednu); + ae_vector_destroy(&p->fscaleszzz); + ae_vector_destroy(&p->invfscales); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + _sparsematrix_destroy(&p->sj); + _varsfuncjac_destroy(&p->stepk); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->xprev); + _minfsqpsubsolver_destroy(&p->subsolver); + _xbfgshessian_destroy(&p->hess); + ae_vector_destroy(&p->lagbcmult); + ae_vector_destroy(&p->lagxcmult); + _varsfuncjac_destroy(&p->cand); + _varsfuncjac_destroy(&p->probe); + ae_vector_destroy(&p->dtrial); + ae_vector_destroy(&p->d0); + ae_vector_destroy(&p->dmu); + _nlpfilter_destroy(&p->filter); + ae_vector_destroy(&p->replagbc); + ae_vector_destroy(&p->replaglc); + ae_vector_destroy(&p->replagnlc); + ae_vector_destroy(&p->varscales); + ae_vector_destroy(&p->tmppend); + ae_vector_destroy(&p->tmphd); + ae_vector_destroy(&p->dummylagbcmult); + ae_vector_destroy(&p->dummylagxcmult); + ae_vector_destroy(&p->tmplaggrad); + ae_vector_destroy(&p->tmpcandlaggrad); + ae_vector_destroy(&p->tmphdiag); + ae_vector_destroy(&p->sclagtmp0); + ae_vector_destroy(&p->sclagtmp1); + ae_vector_destroy(&p->mftmp0); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timerqpgen); + _stimer_destroy(&p->timeripminit); + _stimer_destroy(&p->timeripmsolve); + _stimer_destroy(&p->timercallback); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] and Jacobian of f[]. + + +REQUIREMENTS: +This algorithm will request following information during its operation: + +* function vector f[] at given point X +* function vector f[] and Jacobian of f[] (simultaneously) at given point + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() and jac() callbacks. +First one is used to calculate f[] at given point, second one calculates +f[] and Jacobian df[i]/dx[j]. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not provide Jacobian), but it +will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateVJ() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatevj(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minlmstate* state, + ae_state *_state) +{ + + _minlmstate_clear(state); + + ae_assert(n>=1, "MinLMCreateVJ: N<1!", _state); + ae_assert(m>=1, "MinLMCreateVJ: M<1!", _state); + ae_assert(x->cnt>=n, "MinLMCreateVJ: Length(X)protocolversion = 1; + state->teststep = (double)(0); + state->n = n; + state->m = m; + state->algomode = 1; + state->nonmonotoniccnt = 0; + state->formulatype = 3; + + /* + * second stage of initialization + */ + minlm_lmprepare(n, m, ae_false, state, _state); + minlmsetacctype(state, 0, _state); + minlmsetcond(state, (double)(0), 0, _state); + minlmsetxrep(state, ae_false, _state); + minlmsetstpmax(state, (double)(0), _state); + minlmrestartfrom(state, x, _state); +} + + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] only. Finite differences are used to +calculate Jacobian. + + +REQUIREMENTS: +This algorithm will request following information during its operation: +* function vector f[] at given point X + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() callback. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not accept function vector), but +it will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateV() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + DiffStep- differentiation step, >0. By default, symmetric 3-point + formula which provides good accuracy is used. It can be + changed to a faster but less precise 2-point one with + minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also MinLMIteration, MinLMResults. + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatev(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minlmstate* state, + ae_state *_state) +{ + + _minlmstate_clear(state); + + ae_assert(ae_isfinite(diffstep, _state), "MinLMCreateV: DiffStep is not finite!", _state); + ae_assert(ae_fp_greater(diffstep,(double)(0)), "MinLMCreateV: DiffStep<=0!", _state); + ae_assert(n>=1, "MinLMCreateV: N<1!", _state); + ae_assert(m>=1, "MinLMCreateV: M<1!", _state); + ae_assert(x->cnt>=n, "MinLMCreateV: Length(X)protocolversion = 1; + state->teststep = (double)(0); + state->n = n; + state->m = m; + state->algomode = 0; + state->diffstep = diffstep; + state->nonmonotoniccnt = 0; + state->formulatype = 3; + + /* + * Second stage of initialization + */ + minlm_lmprepare(n, m, ae_false, state, _state); + minlmsetacctype(state, 1, _state); + minlmsetcond(state, (double)(0), 0, _state); + minlmsetxrep(state, ae_false, _state); + minlmsetstpmax(state, (double)(0), _state); + minlmrestartfrom(state, x, _state); +} + + +/************************************************************************* +This function sets stopping conditions for Levenberg-Marquardt optimization +algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLMSetScale() + Recommended values: 1E-9 ... 1E-12. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + +NOTE: it is not recommended to set large EpsX (say, 0.001). Because LM is + a second-order method, it performs very precise steps anyway. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetcond(minlmstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "MinLMSetCond: EpsX is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinLMSetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "MinLMSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsx,(double)(0))&&maxits==0 ) + { + epsx = 1.0E-9; + } + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS +iterations are reported. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinLMSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinLMSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +This function sets scaling coefficients for LM optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetscale(minlmstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinLMSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLMSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinLMSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets boundary constraints for LM optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + or at its boundary + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetbc(minlmstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "MinLMSetBC: Length(BndL)cnt>=n, "MinLMSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLMSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLMSetBC: BndU contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets general linear constraints for LM optimizer + +Linear constraints are inactive by default (after initial creation). They +are preserved until explicitly turned off with another minlmsetlc() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with minlmsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +IMPORTANT: solvers created with minlmcreatefgh() do not support linear + constraints. + +NOTE: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetlc(minlmstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(k>=0, "MinLMSetLC: K<0", _state); + ae_assert(c->cols>=n+1||k==0, "MinLMSetLC: Cols(C)rows>=k, "MinLMSetLC: Rows(C)cnt>=k, "MinLMSetLC: Length(CT)nec = 0; + state->nic = 0; + return; + } + + /* + * Equality constraints are stored first, in the upper + * NEC rows of State.CLEIC matrix. Inequality constraints + * are stored in the next NIC rows. + * + * NOTE: we convert inequality constraints to the form + * A*x<=b before copying them. + */ + rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); + state->nec = 0; + state->nic = 0; + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]==0 ) + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + state->nec = state->nec+1; + } + } + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]!=0 ) + { + if( ct->ptr.p_int[i]>0 ) + { + ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + else + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + state->nic = state->nic+1; + } + } +} + + +/************************************************************************* +This function is used to change acceleration settings + +You can choose between three acceleration strategies: +* AccType=0, no acceleration. +* AccType=1, secant updates are used to update quadratic model after each + iteration. After fixed number of iterations (or after model breakdown) + we recalculate quadratic model using analytic Jacobian or finite + differences. Number of secant-based iterations depends on optimization + settings: about 3 iterations - when we have analytic Jacobian, up to 2*N + iterations - when we use finite differences to calculate Jacobian. + +AccType=1 is recommended when Jacobian calculation cost is prohibitively +high (several Mx1 function vector calculations followed by several NxN +Cholesky factorizations are faster than calculation of one M*N Jacobian). +It should also be used when we have no Jacobian, because finite difference +approximation takes too much time to compute. + +Table below list optimization protocols (XYZ protocol corresponds to +MinLMCreateXYZ) and acceleration types they support (and use by default). + +ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: + +protocol 0 1 comment +V + + +VJ + + +FGH + + +DEFAULT VALUES: + +protocol 0 1 comment +V x without acceleration it is so slooooooooow +VJ x +FGH x + +NOTE: this function should be called before optimization. Attempt to call +it during algorithm iterations may result in unexpected behavior. + +NOTE: attempt to call this function with unsupported protocol/acceleration +combination will result in exception being thrown. + + -- ALGLIB -- + Copyright 14.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetacctype(minlmstate* state, + ae_int_t acctype, + ae_state *_state) +{ + + + ae_assert((acctype==0||acctype==1)||acctype==2, "MinLMSetAccType: incorrect AccType!", _state); + if( acctype==2 ) + { + acctype = 0; + } + if( acctype==0 ) + { + state->maxmodelage = 0; + state->makeadditers = ae_false; + return; + } + if( acctype==1 ) + { + if( state->algomode==0 ) + { + state->maxmodelage = 2*state->n; + } + else + { + state->maxmodelage = minlm_smallmodelage; + } + state->makeadditers = ae_false; + return; + } +} + + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LM solver compares value at the trial point f[1] +with the value at the current point f[0]. Only steps that decrease f() are +accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnonmonotonicsteps(minlmstate* state, + ae_int_t cnt, + ae_state *_state) +{ + + + ae_assert(cnt>=0, "MinLMSetNonmonotonicSteps: incorrect AccType!", _state); + state->nonmonotoniccnt = cnt; +} + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minlmcreatev() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinLMCreateV() call. + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnumdiff(minlmstate* state, + ae_int_t formulatype, + ae_state *_state) +{ + + + ae_assert(formulatype==2||formulatype==3, "MinLMSetNumDiff: unexpected formula type", _state); + state->formulatype = formulatype; +} + + +/************************************************************************* + +CALLBACK PARALLELISM + +The MINLM optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +If you solve a curve fitting problem, i.e. the function vector is actually +the same function computed at different points of a data points space, it +may be better to use an LSFIT curve fitting solver, which offers more +fine-grained parallelism due to knowledge of the problem structure. In +particular, it can accelerate both numerical differentiation and problems +with user-supplied gradients. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + + -- ALGLIB -- + Copyright 03.12.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool minlmiteration(minlmstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_bool bflag; + ae_int_t iflag; + double v; + double xl; + double xr; + double s; + double t; + double fnew; + ae_int_t i; + ae_int_t k; + ae_bool dotrace; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + iflag = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + k = state->rstate.ia.ptr.p_int[4]; + bflag = state->rstate.ba.ptr.p_bool[0]; + dotrace = state->rstate.ba.ptr.p_bool[1]; + v = state->rstate.ra.ptr.p_double[0]; + xl = state->rstate.ra.ptr.p_double[1]; + xr = state->rstate.ra.ptr.p_double[2]; + s = state->rstate.ra.ptr.p_double[3]; + t = state->rstate.ra.ptr.p_double[4]; + fnew = state->rstate.ra.ptr.p_double[5]; + } + else + { + n = 359; + m = -58; + iflag = -919; + i = -909; + k = 81; + bflag = ae_true; + dotrace = ae_false; + v = -788.0; + xl = 809.0; + xr = 205.0; + s = -838.0; + t = 939.0; + fnew = -526.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + if( state->rstate.stage==20 ) + { + goto lbl_20; + } + if( state->rstate.stage==21 ) + { + goto lbl_21; + } + if( state->rstate.stage==22 ) + { + goto lbl_22; + } + if( state->rstate.stage==23 ) + { + goto lbl_23; + } + if( state->rstate.stage==24 ) + { + goto lbl_24; + } + if( state->rstate.stage==25 ) + { + goto lbl_25; + } + + /* + * Routine body + */ + + /* + * prepare + */ + dotrace = ae_is_trace_enabled("LM"); + state->dotimers = dotrace; + if( state->dotimers ) + { + state->tstart = ae_tickcount(); + state->tqp = 0; + } + n = state->n; + m = state->m; + state->repiterationscount = 0; + state->repterminationtype = 0; + state->repnfunc = 0; + state->repnjac = 0; + state->repngrad = 0; + state->repnhess = 0; + state->repncholesky = 0; + state->userterminationneeded = ae_false; + state->fbase = ae_maxrealnumber; + if( m>0 ) + { + smoothnessmonitorinit(&state->smonitor, &state->s, n, m, ae_false, _state); + } + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + } + + /* + * Allocate temporaries, as mandated by the V2 protocol + */ + if( state->protocolversion==2 ) + { + rallocm(m, n, &state->tmpj1, _state); + rallocv(m, &state->tmpf1, _state); + rallocv(n, &state->tmpg1, _state); + rallocv(n, &state->tmpx1, _state); + } + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// LM SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("M = %6d\n", + (int)(m)); + } + + /* + * Prepare LM step finder and enforce/check feasibility of constraints + */ + if( !minlm_minlmstepfinderinit(&state->finderstate, n, m, state->maxmodelage, &state->xbase, &state->bndl, &state->bndu, &state->cleic, state->nec, state->nic, &state->s, state->stpmax, state->epsx, _state) ) + { + state->repterminationtype = -3; + result = ae_false; + return result; + } + + /* + * set constraints for obsolete QP solver + */ + minqpsetbc(&state->qpstate, &state->bndl, &state->bndu, _state); + + /* + * Check correctness of the analytic Jacobian + */ + if( state->protocolversion==1 ) + { + minlm_clearrequestfields(state, _state); + } + if( !(state->algomode==1&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_26; + } + ae_assert(m>0, "MinLM: integrity check failed", _state); +lbl_28: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xbase, &state->s, &state->bndl, &state->bndu, ae_true, state->teststep, _state) ) + { + goto lbl_29; + } + if( state->protocolversion!=2 ) + { + goto lbl_30; + } + + /* + * Use V2 reverse communication protocol + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = m; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->smonitor.x, &state->querydata, _state); + rallocv(m, &state->replyfi, _state); + rallocv(m*n, &state->replydj, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + rcopyv(m, &state->replyfi, &state->smonitor.fi, _state); + unpackdj(m, n, &state->replydj, &state->smonitor.j, _state); + goto lbl_31; +lbl_30: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 0125 failed", _state); + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->smonitor.x.ptr.p_double[i]; + } + state->needfij = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfij = ae_false; + for(i=0; i<=m-1; i++) + { + state->smonitor.fi.ptr.p_double[i] = state->fi.ptr.p_double[i]; + for(k=0; k<=n-1; k++) + { + state->smonitor.j.ptr.pp_double[i][k] = state->j.ptr.pp_double[i][k]; + } + } +lbl_31: + goto lbl_28; +lbl_29: +lbl_26: + + /* + * Initial evaluation of the target and report of the current point + */ + if( !state->xrep ) + { + goto lbl_32; + } + if( state->protocolversion!=2 ) + { + goto lbl_34; + } + + /* + * Issue request and perform report using V2 protocol + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->requesttype = 4; + state->querysize = 1; + state->queryfuncs = m; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->x, &state->querydata, _state); + rallocv(m, &state->replyfi, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->repnfunc = state->repnfunc+1; + rcopyv(m, &state->replyfi, &state->fi, _state); + state->f = rdotv2(m, &state->fi, _state); + state->fbase = state->f; + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->x, &state->reportx, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + goto lbl_35; +lbl_34: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + rcopyv(n, &state->xbase, &state->x, _state); + minlm_clearrequestfields(state, _state); + state->needfi = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfi = ae_false; + state->f = rdotv2(m, &state->fi, _state); + state->fbase = state->f; + state->repnfunc = state->repnfunc+1; + rcopyv(n, &state->xbase, &state->x, _state); + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->xupdated = ae_false; +lbl_35: +lbl_32: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->repterminationtype = 8; + result = ae_false; + return result; + } + + /* + * Prepare control variables + */ + state->fstagnationcnt = 0; + state->nu = (double)(1); + state->lambdav = -ae_maxrealnumber; + state->modelage = state->maxmodelage+1; + state->deltaxready = ae_false; + state->deltafready = ae_false; + state->nonmonotonicpos = -1; + + /* + * fvector/Jacobian-based optimization mode + * + * Main cycle. + * + * We move through it until either: + * * one of the stopping conditions is met + * * we decide that stopping conditions are too stringent + * and break from cycle + */ +lbl_36: + if( ae_false ) + { + goto lbl_37; + } + if( dotrace ) + { + ae_trace("\n=== ITERATION %5d ==================================================================================\n", + (int)(state->repiterationscount)); + } + + /* + * First, we have to prepare quadratic model for our function. + * We use BFlag to ensure that model is prepared; + * if it is false at the end of this block, something went wrong. + * + * We may either calculate brand new model or update old one. + * + * Before this block we have: + * * State.XBase - current position. + * * State.DeltaX - if DeltaXReady is True + * * State.DeltaF - if DeltaFReady is True + * + * After this block is over, we will have: + * * State.XBase - base point (unchanged) + * * State.FBase - F(XBase) + * * State.GBase - linear term + * * State.QuadraticModel - quadratic term + * * State.LambdaV - current estimate for lambda + * + * We also clear DeltaXReady/DeltaFReady flags + * after initialization is done. + */ + if( !(state->modelage>state->maxmodelage||!(state->deltaxready&&state->deltafready)) ) + { + goto lbl_38; + } + + /* + * Refresh model (using either finite differences or analytic Jacobian) + */ + if( state->protocolversion!=2 ) + { + goto lbl_40; + } + + /* + * Issue request using V2 protocol + */ + if( state->algomode!=0 ) + { + goto lbl_42; + } + + /* + * Optimization using F values only. Use finite differences to estimate Jacobian. + * + * Request dense numerical Jacobian, propose 2-point finite difference formula + */ + state->requesttype = 3; + state->querysize = 1; + state->queryfuncs = m; + state->queryvars = n; + state->querydim = 0; + state->queryformulasize = 0; + if( state->formulatype==2||state->formulatype==3 ) + { + + /* + * either 2-point difference, or a 3-point central one + */ + state->queryformulasize = 2; + rallocv(n+n*2*state->queryformulasize, &state->querydata, _state); + rcopyv(n, &state->xbase, &state->querydata, _state); + for(k=0; k<=n-1; k++) + { + + /* + * We guard X[k] from leaving [BndL,BndU]. + * In case BndL=BndU, we assume that derivative in this direction is zero. + */ + v = state->diffstep*state->s.ptr.p_double[k]; + xl = state->xbase.ptr.p_double[k]-v; + if( state->havebndl.ptr.p_bool[k]&&ae_fp_less(xl,state->bndl.ptr.p_double[k]) ) + { + xl = state->bndl.ptr.p_double[k]; + } + xr = state->xbase.ptr.p_double[k]+v; + if( state->havebndu.ptr.p_bool[k]&&ae_fp_greater(xr,state->bndu.ptr.p_double[k]) ) + { + xr = state->bndu.ptr.p_double[k]; + } + if( xl>=xr ) + { + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+0] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+1] = 0.0; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+0] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+1] = 0.0; + continue; + } + if( state->formulatype==2 ) + { + if( ae_fp_greater(xr-state->xbase.ptr.p_double[k],state->xbase.ptr.p_double[k]-xl) ) + { + v = (double)1/(xr-state->xbase.ptr.p_double[k]); + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+0] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+1] = -v; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+0] = xr; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+1] = v; + } + else + { + v = (double)1/(state->xbase.ptr.p_double[k]-xl); + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+0] = xl; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+1] = -v; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+0] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+1] = v; + } + continue; + } + if( state->formulatype==3 ) + { + v = (double)1/(xr-xl); + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+0] = xl; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+0*2+1] = -v; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+0] = xr; + state->querydata.ptr.p_double[n+2*state->queryformulasize*k+1*2+1] = v; + continue; + } + ae_assert(ae_false, "MINLM: integrity check 431017 failed", _state); + } + } + ae_assert(state->queryformulasize>=1, "MINLM: integrity check 397250 failed", _state); + rallocv(m, &state->replyfi, _state); + rallocv(m*n, &state->replydj, _state); + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + rcopyv(m, &state->replyfi, &state->fi, _state); + unpackdj(m, n, &state->replydj, &state->j, _state); + state->repnfunc = state->repnfunc+1+n*state->queryformulasize; + state->repnjac = state->repnjac+1; + + /* + * New model + */ + state->modelage = 0; + goto lbl_43; +lbl_42: + + /* + * Request dense analytic Jacobian + */ + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = m; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->xbase, &state->querydata, _state); + rallocv(m, &state->replyfi, _state); + rallocv(m*n, &state->replydj, _state); + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + rcopyv(m, &state->replyfi, &state->fi, _state); + unpackdj(m, n, &state->replydj, &state->j, _state); + state->repnfunc = state->repnfunc+1; + state->repnjac = state->repnjac+1; + + /* + * New model + */ + state->modelage = 0; +lbl_43: + goto lbl_41; +lbl_40: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + if( state->algomode!=0 ) + { + goto lbl_44; + } + + /* + * Optimization using F values only. + * Use finite differences to estimate Jacobian. + */ + k = 0; +lbl_46: + if( k>n-1 ) + { + goto lbl_48; + } + + /* + * We guard X[k] from leaving [BndL,BndU]. + * In case BndL=BndU, we assume that derivative in this direction is zero. + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + if( state->havebndl.ptr.p_bool[k] ) + { + state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); + } + if( state->havebndu.ptr.p_bool[k] ) + { + state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); + } + state->xm1 = state->x.ptr.p_double[k]; + minlm_clearrequestfields(state, _state); + state->needfi = ae_true; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->repnfunc = state->repnfunc+1; + ae_v_move(&state->fm1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + if( state->havebndl.ptr.p_bool[k] ) + { + state->x.ptr.p_double[k] = ae_maxreal(state->x.ptr.p_double[k], state->bndl.ptr.p_double[k], _state); + } + if( state->havebndu.ptr.p_bool[k] ) + { + state->x.ptr.p_double[k] = ae_minreal(state->x.ptr.p_double[k], state->bndu.ptr.p_double[k], _state); + } + state->xp1 = state->x.ptr.p_double[k]; + minlm_clearrequestfields(state, _state); + state->needfi = ae_true; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->repnfunc = state->repnfunc+1; + ae_v_move(&state->fp1.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + v = state->xp1-state->xm1; + if( ae_fp_neq(v,(double)(0)) ) + { + v = (double)1/v; + ae_v_moved(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fp1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); + ae_v_subd(&state->j.ptr.pp_double[0][k], state->j.stride, &state->fm1.ptr.p_double[0], 1, ae_v_len(0,m-1), v); + } + else + { + for(i=0; i<=m-1; i++) + { + state->j.ptr.pp_double[i][k] = (double)(0); + } + } + k = k+1; + goto lbl_46; +lbl_48: + + /* + * Calculate F(XBase) + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minlm_clearrequestfields(state, _state); + state->needfi = ae_true; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->needfi = ae_false; + state->repnfunc = state->repnfunc+1; + state->repnjac = state->repnjac+1; + + /* + * New model + */ + state->modelage = 0; + goto lbl_45; +lbl_44: + + /* + * Obtain f[] and Jacobian + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minlm_clearrequestfields(state, _state); + state->needfij = ae_true; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->needfij = ae_false; + state->repnfunc = state->repnfunc+1; + state->repnjac = state->repnjac+1; + + /* + * New model + */ + state->modelage = 0; +lbl_45: +lbl_41: + goto lbl_39; +lbl_38: + + /* + * State.J contains Jacobian or its current approximation; + * refresh it using secant updates: + * + * f(x0+dx) = f(x0) + J*dx, + * J_new = J_old + u*h' + * h = x_new-x_old + * u = (f_new - f_old - J_old*h)/(h'h) + * + * We can explicitly generate h and u, but it is + * preferential to do in-place calculations. Only + * I-th row of J_old is needed to calculate u[I], + * so we can update J row by row in one pass. + * + * NOTE: we expect that State.XBase contains new point, + * State.FBase contains old point, State.DeltaX and + * State.DeltaY contain updates from last step. + */ + ae_assert(state->deltaxready&&state->deltafready, "MinLMIteration: uninitialized DeltaX/DeltaF", _state); + t = ae_v_dotproduct(&state->deltax.ptr.p_double[0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_assert(ae_fp_neq(t,(double)(0)), "MinLM: internal error (T=0)", _state); + for(i=0; i<=m-1; i++) + { + v = ae_v_dotproduct(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = (state->deltaf.ptr.p_double[i]-v)/t; + ae_v_addd(&state->j.ptr.pp_double[i][0], 1, &state->deltax.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + } + ae_v_move(&state->fi.ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); + ae_v_add(&state->fi.ptr.p_double[0], 1, &state->deltaf.ptr.p_double[0], 1, ae_v_len(0,m-1)); + + /* + * Increase model age + */ + state->modelage = state->modelage+1; +lbl_39: + rmatrixgemm(n, n, m, 2.0, &state->j, 0, 0, 1, &state->j, 0, 0, 0, 0.0, &state->quadraticmodel, 0, 0, _state); + rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->gbase, 0, _state); + ae_v_muld(&state->gbase.ptr.p_double[0], 1, ae_v_len(0,n-1), 2.0); + v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + state->fbase = v; + ae_v_move(&state->fibase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + state->deltaxready = ae_false; + state->deltafready = ae_false; + if( dotrace ) + { + ae_trace("ModelAge = %9d (model age)\n", + (int)(state->modelage)); + } + if( state->nonmonotonicpos<0 ) + { + + /* + * Initialize nonmonotonic buffer + */ + rsetallocv(state->nonmonotoniccnt+1, (double)2*state->fbase, &state->nonmonotonicbuf, _state); + state->nonmonotonicbuf.ptr.p_double[0] = state->fbase; + state->nonmonotonicpos = 1%(state->nonmonotoniccnt+1); + } + + /* + * Perform integrity check (presense of NAN/INF) + */ + v = state->fbase; + for(i=0; i<=n-1; i++) + { + v = 0.1*v+state->gbase.ptr.p_double[i]; + } + if( !ae_isfinite(v, _state) ) + { + + /* + * Break! + */ + if( dotrace ) + { + ae_trace("> infinities detected, abnormal termination!\n"); + } + state->repterminationtype = -8; + result = ae_false; + return result; + } + + /* + * If Lambda is not initialized, initialize it using quadratic model + */ + if( ae_fp_less(state->lambdav,(double)(0)) ) + { + state->lambdav = (double)(0); + for(i=0; i<=n-1; i++) + { + state->lambdav = ae_maxreal(state->lambdav, ae_fabs(state->quadraticmodel.ptr.pp_double[i][i], _state)*ae_sqr(state->s.ptr.p_double[i], _state), _state); + } + state->lambdav = 0.001*state->lambdav; + if( ae_fp_eq(state->lambdav,(double)(0)) ) + { + state->lambdav = (double)(1); + } + } + if( dotrace ) + { + ae_trace("LambdaV = %9.3e (damping coefficient)\n", + (double)(state->lambdav)); + } + + /* + * Find value of Levenberg-Marquardt damping parameter which: + * * leads to positive definite damped model + * * within bounds specified by StpMax + * * generates step which decreases function value + * + * After this block IFlag is set to: + * * -8, if internal integrity control detected NAN/INF in function values + * * -3, if constraints are infeasible + * * -2, if model update is needed (either Lambda growth is too large + * or step is too short, but we can't rely on model and stop iterations) + * * -1, if model is fresh, Lambda have grown too large, termination is needed + * * 0, if everything is OK, continue iterations + * * >0, successful termination, step is less than EpsX + * + * State.Nu can have any value on enter, but after exit it is set to 1.0 + */ + iflag = -99; + minlm_minlmstepfinderstart(&state->finderstate, &state->quadraticmodel, &state->gbase, rmaxv(state->nonmonotoniccnt+1, &state->nonmonotonicbuf, _state), &state->xbase, &state->fibase, state->modelage, _state); +lbl_49: + if( !minlm_minlmstepfinderiteration(&state->finderstate, state, &state->lambdav, &state->nu, &state->xnew, &state->deltax, &state->deltaxready, &state->deltaf, &state->deltafready, &iflag, &fnew, &state->repncholesky, _state) ) + { + goto lbl_50; + } + ae_assert(state->finderstate.needfi, "MinLM: internal error 2!", _state); + state->repnfunc = state->repnfunc+1; + if( state->protocolversion!=2 ) + { + goto lbl_51; + } + + /* + * Issue request and perform report using V2 protocol + */ + state->requesttype = 4; + state->querysize = 1; + state->queryfuncs = m; + state->queryvars = n; + state->querydim = 0; + rcopyallocv(n, &state->finderstate.x, &state->querydata, _state); + rallocv(m, &state->replyfi, _state); + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + rcopyv(m, &state->replyfi, &state->finderstate.fi, _state); + goto lbl_52; +lbl_51: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 5138 failed", _state); + minlm_clearrequestfields(state, _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->finderstate.x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->needfi = ae_true; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->needfi = ae_false; + ae_v_move(&state->finderstate.fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); +lbl_52: + goto lbl_49; +lbl_50: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + if( dotrace ) + { + ae_trace("> user requested termination!\n"); + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; + } + state->nu = (double)(1); + ae_assert(((iflag>=-3&&iflag<=0)||iflag==-8)||iflag>0, "MinLM: internal integrity check failed!", _state); + if( iflag==-3 ) + { + if( dotrace ) + { + ae_trace("> constraints are inconsistent!\n"); + } + state->repterminationtype = -3; + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; + } + if( iflag==-2 ) + { + if( dotrace ) + { + ae_trace("> model refresh requested\n"); + } + state->modelage = state->maxmodelage+1; + goto lbl_36; + } + if( iflag!=-1 ) + { + goto lbl_53; + } + + /* + * Stopping conditions are too stringent + */ + if( dotrace ) + { + ae_trace("> stopping conditions are too stringent, terminating at the best point so far\n"); + } + state->repterminationtype = 7; + if( !state->xrep ) + { + goto lbl_55; + } + if( state->protocolversion!=2 ) + { + goto lbl_57; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->fbase; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + goto lbl_58; +lbl_57: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fbase; + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->xupdated = ae_false; +lbl_58: +lbl_55: + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; +lbl_53: + if( !(iflag==-8||iflag>0) ) + { + goto lbl_59; + } + + /* + * Either: + * * Integrity check failed - infinities or NANs + * * successful termination (step size is small enough) + */ + if( dotrace&&iflag==-8 ) + { + ae_trace("> infinities detected, abnormal termination!\n"); + } + if( dotrace&&iflag>0 ) + { + ae_trace("> step size is small engough, succeful termination\n"); + } + state->repterminationtype = iflag; + if( !state->xrep ) + { + goto lbl_61; + } + if( state->protocolversion!=2 ) + { + goto lbl_63; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->fbase; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + goto lbl_64; +lbl_63: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 4042 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fbase; + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->xupdated = ae_false; +lbl_64: +lbl_61: + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; +lbl_59: + state->f = fnew; + + /* + * Levenberg-Marquardt step is ready. + * Compare predicted vs. actual decrease and decide what to do with lambda. + * + * NOTE: we expect that State.DeltaX contains direction of step, + * State.F contains function value at new point. + */ + ae_assert(state->deltaxready, "MinLM: deltaX is not ready", _state); + iflag = minlm_checkdecrease(&state->quadraticmodel, &state->gbase, rmaxv(state->nonmonotoniccnt+1, &state->nonmonotonicbuf, _state), n, &state->deltax, state->f, &state->lambdav, &state->nu, _state); + if( iflag==0 ) + { + goto lbl_65; + } + state->repterminationtype = iflag; + if( !state->xrep ) + { + goto lbl_67; + } + if( state->protocolversion!=2 ) + { + goto lbl_69; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->fbase; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + goto lbl_70; +lbl_69: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 8643 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fbase; + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + state->xupdated = ae_false; +lbl_70: +lbl_67: + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; +lbl_65: + + /* + * Accept step, report it and + * test stopping conditions on iterations count and function decrease. + * + * NOTE: we expect that State.DeltaX contains direction of step, + * State.F contains function value at new point. + * + * NOTE2: we should update XBase ONLY. In the beginning of the next + * iteration we expect that State.FIBase is NOT updated and + * contains old value of a function vector. + */ + state->fstagnationcnt = icase2(ae_fp_less(ae_fabs(state->fbase-state->f, _state),minlm_stagnationfeps*rmaxabs3(state->fbase, state->f, (double)(1), _state)), state->fstagnationcnt+1, 0, _state); + ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->xnew.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fbase = fnew; + state->nonmonotonicbuf.ptr.p_double[state->nonmonotonicpos] = state->f; + state->nonmonotonicpos = (state->nonmonotonicpos+1)%(state->nonmonotoniccnt+1); + if( !state->xrep ) + { + goto lbl_71; + } + if( state->protocolversion!=2 ) + { + goto lbl_73; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 20; + goto lbl_rcomm; +lbl_20: + goto lbl_74; +lbl_73: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 21; + goto lbl_rcomm; +lbl_21: + state->xupdated = ae_false; +lbl_74: +lbl_71: + state->repiterationscount = state->repiterationscount+1; + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + state->repterminationtype = 5; + } + if( state->fstagnationcnt>=minlm_stagnationfits ) + { + state->repterminationtype = 7; + } + if( state->repterminationtype<=0 ) + { + goto lbl_75; + } + if( !state->xrep ) + { + goto lbl_77; + } + + /* + * Report: XBase contains new point, F contains function value at new point + */ + if( state->protocolversion!=2 ) + { + goto lbl_79; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 22; + goto lbl_rcomm; +lbl_22: + goto lbl_80; +lbl_79: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 23; + goto lbl_rcomm; +lbl_23: + state->xupdated = ae_false; +lbl_80: +lbl_77: + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; +lbl_75: + state->modelage = state->modelage+1; + goto lbl_36; +lbl_37: + + /* + * Lambda is too large, we have to break iterations. + */ + state->repterminationtype = 7; + if( !state->xrep ) + { + goto lbl_81; + } + if( state->protocolversion!=2 ) + { + goto lbl_83; + } + + /* + * Issue request using V2 protocol + */ + state->requesttype = -1; + state->queryvars = n; + state->reportf = state->f; + rcopyallocv(n, &state->xbase, &state->reportx, _state); + state->rstate.stage = 24; + goto lbl_rcomm; +lbl_24: + goto lbl_84; +lbl_83: + + /* + * Use legacy V1 protocol + */ + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol, integrity check 9600 failed", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minlm_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 25; + goto lbl_rcomm; +lbl_25: + state->xupdated = ae_false; +lbl_84: +lbl_81: + minlm_tracefinalreport(state, dotrace||state->dotimers, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = iflag; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = k; + state->rstate.ba.ptr.p_bool[0] = bflag; + state->rstate.ba.ptr.p_bool[1] = dotrace; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = xl; + state->rstate.ra.ptr.p_double[2] = xr; + state->rstate.ra.ptr.p_double[3] = s; + state->rstate.ra.ptr.p_double[4] = t; + state->rstate.ra.ptr.p_double[5] = fnew; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic Jacobian. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function vector at the initial +point (note: future versions may also perform check at the final point) +and compares numerical Jacobian with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both Jacobians, and specific components highlighted as +suspicious by the OptGuard. + +The OptGuard report can be retrieved with minlmoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlmsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardgradient(minlmstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinLMOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinLMOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +OptGuard checks analytic Jacobian against reference value obtained by +numerical differentiation with user-specified step. + +NOTE: other optimizers perform additional OptGuard checks for things like + C0/C1-continuity violations. However, LM optimizer can check only + for incorrect Jacobian. + + The reason is that unlike line search methods LM optimizer does not + perform extensive evaluations along the line. Thus, we simply do not + have enough data to catch C0/C1-violations. + +This check is activated with minlmoptguardgradient() function. + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - OptGuard report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardresults(minlmstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Levenberg-Marquardt algorithm results + +NOTE: if you activated OptGuard integrity checking functionality and want + to get OptGuard report, it can be retrieved with the help of + minlmoptguardresults() function. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report; includes termination codes and + additional information. Termination codes are listed below, + see comments for this structure for more info. + + Termination code is stored in rep.terminationtype field: + * -8 optimizer detected NAN/INF values either in the + function itself, or in its Jacobian + * -3 constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlmrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + + rep.f contains SUM(f[i]^2) at X + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresults(const minlmstate* state, + /* Real */ ae_vector* x, + minlmreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minlmreport_clear(rep); + + minlmresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +Levenberg-Marquardt algorithm results + +Buffered implementation of MinLMResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresultsbuf(const minlmstate* state, + /* Real */ ae_vector* x, + minlmreport* rep, + ae_state *_state) +{ + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->terminationtype = state->repterminationtype; + rep->nfunc = state->repnfunc; + rep->njac = state->repnjac; + rep->ngrad = state->repngrad; + rep->nhess = state->repnhess; + rep->ncholesky = state->repncholesky; + rep->f = state->fbase; +} + + +/************************************************************************* +This subroutine restarts LM algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinLMCreateXXX call. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmrestartfrom(minlmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "MinLMRestartFrom: Length(X)n, _state), "MinLMRestartFrom: X contains infinite or NaN values!", _state); + ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmrequesttermination(minlmstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minlmsetprotocolv1(minlmstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol +*************************************************************************/ +void minlmsetprotocolv2(minlmstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Unpacks dense Jacobian into array +*************************************************************************/ +void unpackdj(ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* replydj, + /* Real */ ae_matrix* jac, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t offs; + + + if( replydj->cntrowscolsptr.pp_double[i][j] = replydj->ptr.p_double[offs]; + offs = offs+1; + } + } +} + + +/************************************************************************* +Prepare internal structures (except for RComm). + +Note: M must be zero for FGH mode, non-zero for V/VJ/FJ/FGJ mode. +*************************************************************************/ +static void minlm_lmprepare(ae_int_t n, + ae_int_t m, + ae_bool havegrad, + minlmstate* state, + ae_state *_state) +{ + ae_int_t i; + + + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + if( n<=0||m<0 ) + { + return; + } + if( havegrad ) + { + ae_vector_set_length(&state->g, n, _state); + } + if( m!=0 ) + { + ae_matrix_set_length(&state->j, m, n, _state); + ae_vector_set_length(&state->fi, m, _state); + ae_vector_set_length(&state->fibase, m, _state); + ae_vector_set_length(&state->deltaf, m, _state); + ae_vector_set_length(&state->fm1, m, _state); + ae_vector_set_length(&state->fp1, m, _state); + ae_vector_set_length(&state->fc1, m, _state); + ae_vector_set_length(&state->gm1, m, _state); + ae_vector_set_length(&state->gp1, m, _state); + ae_vector_set_length(&state->gc1, m, _state); + } + else + { + ae_matrix_set_length(&state->h, n, n, _state); + } + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->deltax, n, _state); + ae_matrix_set_length(&state->quadraticmodel, n, n, _state); + ae_vector_set_length(&state->xbase, n, _state); + ae_vector_set_length(&state->gbase, n, _state); + ae_vector_set_length(&state->xdir, n, _state); + ae_vector_set_length(&state->tmp0, n, _state); + + /* + * prepare internal L-BFGS + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = (double)(0); + } + minlbfgscreate(n, ae_minint(minlm_additers, n, _state), &state->x, &state->internalstate, _state); + minlbfgssetcond(&state->internalstate, 0.0, 0.0, 0.0, ae_minint(minlm_additers, n, _state), _state); + + /* + * Prepare internal QP solver + */ + minqpcreate(n, &state->qpstate, _state); + minqpsetalgoquickqp(&state->qpstate, 0.0, 0.0, coalesce(0.01*state->epsx, 1.0E-12, _state), 10, ae_true, _state); + + /* + * Prepare boundary constraints + */ + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->havebndl, n, _state); + ae_vector_set_length(&state->havebndu, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->havebndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->havebndu.ptr.p_bool[i] = ae_false; + } + + /* + * Prepare scaling matrix + */ + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->lastscaleused, n, _state); + for(i=0; i<=n-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + } + + /* + * Prepare linear constraints + */ + state->nec = 0; + state->nic = 0; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void minlm_clearrequestfields(minlmstate* state, ae_state *_state) +{ + + + ae_assert(state->protocolversion==1, "MINLM: unexpected protocol", _state); + state->needf = ae_false; + state->needfg = ae_false; + state->needfgh = ae_false; + state->needfij = ae_false; + state->needfi = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +static void minlm_tracefinalreport(minlmstate* state, + ae_bool dotrace, + ae_state *_state) +{ + + + if( !dotrace ) + { + return; + } + ae_trace("\n\n----------------------------------------------------------------------------------------------------\n"); + ae_trace("Total running time is %0d ms, including:\n", + (int)(ae_tickcount()-state->tstart)); + ae_trace("> QP time: %8d ms\n", + (int)(state->tqp)); +} + + +/************************************************************************* +Increases lambda, returns False when there is a danger of overflow +*************************************************************************/ +static ae_bool minlm_increaselambda(double* lambdav, + double* nu, + ae_state *_state) +{ + double lnlambda; + double lnnu; + double lnlambdaup; + double lnmax; + ae_bool result; + + + result = ae_false; + lnlambda = ae_log(*lambdav, _state); + lnlambdaup = ae_log(minlm_lambdaup, _state); + lnnu = ae_log(*nu, _state); + lnmax = ae_log(ae_maxrealnumber, _state); + if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,0.25*lnmax) ) + { + return result; + } + if( ae_fp_greater(lnnu+ae_log((double)(2), _state),lnmax) ) + { + return result; + } + *lambdav = *lambdav*minlm_lambdaup*(*nu); + *nu = *nu*(double)2; + result = ae_true; + return result; +} + + +/************************************************************************* +Decreases lambda, but leaves it unchanged when there is danger of underflow. +*************************************************************************/ +static void minlm_decreaselambda(double* lambdav, + double* nu, + ae_state *_state) +{ + + + *nu = (double)(1); + if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(minlm_lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) + { + *lambdav = ae_minrealnumber; + } + else + { + *lambdav = *lambdav*minlm_lambdadown; + } +} + + +/************************************************************************* +This function compares actual decrease vs predicted decrease and updates +LambdaV/Nu accordingly. + +INPUT PARAMETERS: + QuadraticModel - array[N,N], full Hessian matrix of quadratic + model at deltaX=0 + GBase - array[N], gradient at deltaX=0 + FBase - F(deltaX=0) + N - size + DeltaX - step vector + FNew - new function value + LambdaV - lambda-value, updated on exit + Nu - Nu-multiplier, updated on exit + +On exit it returns: +* Result=0 - if we have to continue iterations +* Result<>0 - if termination with completion code Result is requested + + -- ALGLIB -- + Copyright 17.02.2017 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t minlm_checkdecrease(/* Real */ const ae_matrix* quadraticmodel, + /* Real */ const ae_vector* gbase, + double fbase, + ae_int_t n, + /* Real */ const ae_vector* deltax, + double fnew, + double* lambdav, + double* nu, + ae_state *_state) +{ + ae_int_t i; + double v; + double t; + double predicteddecrease; + double actualdecrease; + ae_int_t result; + + + result = 0; + t = (double)(0); + for(i=0; i<=n-1; i++) + { + v = ae_v_dotproduct(&quadraticmodel->ptr.pp_double[i][0], 1, &deltax->ptr.p_double[0], 1, ae_v_len(0,n-1)); + t = t+deltax->ptr.p_double[i]*gbase->ptr.p_double[i]+0.5*deltax->ptr.p_double[i]*v; + } + predicteddecrease = -t; + actualdecrease = -(fnew-fbase); + if( ae_fp_less_eq(predicteddecrease,(double)(0)) ) + { + result = 7; + return result; + } + v = actualdecrease/predicteddecrease; + if( ae_fp_less(v,0.1) ) + { + if( !minlm_increaselambda(lambdav, nu, _state) ) + { + + /* + * Lambda is too large, we have to break iterations. + */ + result = 7; + return result; + } + } + if( ae_fp_greater(v,0.5) ) + { + minlm_decreaselambda(lambdav, nu, _state); + } + return result; +} + + +/************************************************************************* +This function initializes step finder object with problem statement; +model parameters specified during this call should not (and can not) +change during object lifetime (although it is possible to re-initialize +object with different settings). + +This function reuses internally allocated objects as much as possible. + +In addition to initializing step finder, this function enforces feasibility +in initial point X passed to this function. It is important that LM iteration +starts from feasible point and performs feasible steps; + +RETURN VALUE: + True for successful initialization + False for inconsistent constraints; you should not use step finder if + it returned False. +*************************************************************************/ +static ae_bool minlm_minlmstepfinderinit(minlmstepfinder* state, + ae_int_t n, + ae_int_t m, + ae_int_t maxmodelage, + /* Real */ ae_vector* xbase, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + /* Real */ const ae_vector* s, + double stpmax, + double epsx, + ae_state *_state) +{ + ae_int_t i; + ae_bool result; + + + state->n = n; + state->m = m; + state->maxmodelage = maxmodelage; + state->stpmax = stpmax; + state->epsx = epsx; + + /* + * Allocate temporaries, create QP solver, select QP algorithm + */ + rvectorsetlengthatleast(&state->bndl, n, _state); + rvectorsetlengthatleast(&state->bndu, n, _state); + rvectorsetlengthatleast(&state->s, n, _state); + bvectorsetlengthatleast(&state->havebndl, n, _state); + bvectorsetlengthatleast(&state->havebndu, n, _state); + rvectorsetlengthatleast(&state->x, n, _state); + rvectorsetlengthatleast(&state->xbase, n, _state); + rvectorsetlengthatleast(&state->tmp0, n, _state); + rvectorsetlengthatleast(&state->modeldiag, n, _state); + ivectorsetlengthatleast(&state->tmpct, nec+nic, _state); + rvectorsetlengthatleast(&state->xdir, n, _state); + rvectorsetlengthatleast(&state->fi, m, _state); + rvectorsetlengthatleast(&state->fibase, m, _state); + for(i=0; i<=n-1; i++) + { + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLM: integrity check failed", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLM: integrity check failed", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->havebndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->havebndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + for(i=0; i<=nec-1; i++) + { + state->tmpct.ptr.p_int[i] = 0; + } + for(i=0; i<=nic-1; i++) + { + state->tmpct.ptr.p_int[nec+i] = -1; + } + minqpcreate(n, &state->qpstate, _state); + if( nec+nic==0 ) + { + minqpsetalgoquickqp(&state->qpstate, 0.0, 0.0, coalesce(0.01*epsx, 1.0E-12, _state), 10, ae_true, _state); + } + else + { + minqpsetalgodenseaul(&state->qpstate, coalesce(0.01*epsx, 1.0E-12, _state), (double)(100), 10, _state); + } + minqpsetbc(&state->qpstate, bndl, bndu, _state); + minqpsetlc(&state->qpstate, cleic, &state->tmpct, nec+nic, _state); + minqpsetscale(&state->qpstate, s, _state); + + /* + * Check feasibility of constraints: + * * check/enforce box constraints (straightforward) + * * prepare QP subproblem which return us a feasible point + */ + result = ae_true; + for(i=0; i<=n-1; i++) + { + if( (state->havebndl.ptr.p_bool[i]&&state->havebndu.ptr.p_bool[i])&&ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + result = ae_false; + return result; + } + if( state->havebndl.ptr.p_bool[i]&&ae_fp_less(xbase->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + xbase->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->havebndu.ptr.p_bool[i]&&ae_fp_greater(xbase->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + xbase->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + if( nec+nic>0 ) + { + + /* + * Well, we have linear constraints... let's use heavy machinery. + * + * We will modify QP solver state below, but everything will be + * restored in MinLMStepFinderStart(). + */ + sparsecreate(n, n, n, &state->tmpsp, _state); + for(i=0; i<=n-1; i++) + { + sparseset(&state->tmpsp, i, i, 0.5, _state); + state->tmp0.ptr.p_double[i] = (double)(0); + } + minqpsetstartingpointfast(&state->qpstate, xbase, _state); + minqpsetoriginfast(&state->qpstate, xbase, _state); + minqpsetlineartermfast(&state->qpstate, &state->tmp0, _state); + minqpsetquadratictermsparse(&state->qpstate, &state->tmpsp, ae_true, _state); + minqpoptimize(&state->qpstate, _state); + minqpresultsbuf(&state->qpstate, xbase, &state->qprep, _state); + } + return result; +} + + +/************************************************************************* +This function prepares LM step search session. +*************************************************************************/ +static void minlm_minlmstepfinderstart(minlmstepfinder* state, + /* Real */ const ae_matrix* quadraticmodel, + /* Real */ const ae_vector* gbase, + double fbase, + /* Real */ const ae_vector* xbase, + /* Real */ const ae_vector* fibase, + ae_int_t modelage, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; + state->modelage = modelage; + state->fbase = fbase; + for(i=0; i<=state->m-1; i++) + { + state->fibase.ptr.p_double[i] = fibase->ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + state->xbase.ptr.p_double[i] = xbase->ptr.p_double[i]; + state->modeldiag.ptr.p_double[i] = quadraticmodel->ptr.pp_double[i][i]; + } + minqpsetstartingpointfast(&state->qpstate, xbase, _state); + minqpsetoriginfast(&state->qpstate, xbase, _state); + minqpsetlineartermfast(&state->qpstate, gbase, _state); + minqpsetquadratictermfast(&state->qpstate, quadraticmodel, ae_true, 0.0, _state); +} + + +/************************************************************************* +This function runs LM step search session. +// +// Find value of Levenberg-Marquardt damping parameter which: +// * leads to positive definite damped model +// * within bounds specified by StpMax +// * generates step which decreases function value +// +// After this block IFlag is set to: +// * -8, if infinities/NANs were detected in function values/gradient +// * -3, if constraints are infeasible +// * -2, if model update is needed (either Lambda growth is too large +// or step is too short, but we can't rely on model and stop iterations) +// * -1, if model is fresh, Lambda have grown too large, termination is needed +// * 0, if everything is OK, continue iterations +// * >0 - successful completion (step size is small enough) +// +// State.Nu can have any value on enter, but after exit it is set to 1.0 +// +*************************************************************************/ +static ae_bool minlm_minlmstepfinderiteration(minlmstepfinder* state, + minlmstate* parentstate, + double* lambdav, + double* nu, + /* Real */ ae_vector* xnew, + /* Real */ ae_vector* deltax, + ae_bool* deltaxready, + /* Real */ ae_vector* deltaf, + ae_bool* deltafready, + ae_int_t* iflag, + double* fnew, + ae_int_t* ncholesky, + ae_state *_state) +{ + ae_int_t i; + ae_bool bflag; + double v; + ae_int_t n; + ae_int_t m; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + n = state->rstate.ia.ptr.p_int[1]; + m = state->rstate.ia.ptr.p_int[2]; + bflag = state->rstate.ba.ptr.p_bool[0]; + v = state->rstate.ra.ptr.p_double[0]; + } + else + { + i = 763; + n = -541; + m = -698; + bflag = ae_false; + v = -318.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + + /* + * Routine body + */ + *iflag = -99; + n = state->n; + m = state->m; +lbl_1: + if( ae_false ) + { + goto lbl_2; + } + *deltaxready = ae_false; + *deltafready = ae_false; + + /* + * Do we need model update? + */ + if( state->modelage>0&&ae_fp_greater_eq(*nu,minlm_suspiciousnu) ) + { + *iflag = -2; + goto lbl_2; + } + + /* + * Setup quadratic solver and solve quadratic programming problem. + * After problem is solved we'll try to bound step by StpMax + * (Lambda will be increased if step size is too large). + * + * We use BFlag variable to indicate that we have to increase Lambda. + * If it is False, we will try to increase Lambda and move to new iteration. + */ + bflag = ae_true; + for(i=0; i<=n-1; i++) + { + state->tmp0.ptr.p_double[i] = state->modeldiag.ptr.p_double[i]+*lambdav/ae_sqr(state->s.ptr.p_double[i], _state); + } + if( parentstate->dotimers ) + { + parentstate->tqp = parentstate->tqp-ae_tickcount(); + } + minqprewritediagonal(&state->qpstate, &state->tmp0, _state); + minqpoptimize(&state->qpstate, _state); + minqpresultsbuf(&state->qpstate, xnew, &state->qprep, _state); + if( parentstate->dotimers ) + { + parentstate->tqp = parentstate->tqp+ae_tickcount(); + } + *ncholesky = *ncholesky+state->qprep.ncholesky; + if( state->qprep.terminationtype==-3 ) + { + + /* + * Infeasible constraints + */ + *iflag = -3; + goto lbl_2; + } + if( state->qprep.terminationtype==-4||state->qprep.terminationtype==-5 ) + { + + /* + * Unconstrained direction of negative curvature was detected + */ + if( !minlm_increaselambda(lambdav, nu, _state) ) + { + *iflag = -1; + goto lbl_2; + } + goto lbl_1; + } + ae_assert(state->qprep.terminationtype>0, "MinLM: unexpected completion code from QP solver", _state); + ae_v_move(&state->xdir.ptr.p_double[0], 1, &xnew->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_sub(&state->xdir.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->xdir.ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + if( ae_isfinite(v, _state) ) + { + v = ae_sqrt(v, _state); + if( ae_fp_greater(state->stpmax,(double)(0))&&ae_fp_greater(v,state->stpmax) ) + { + bflag = ae_false; + } + } + else + { + bflag = ae_false; + } + if( !bflag ) + { + + /* + * Solution failed: + * try to increase lambda to make matrix positive definite and continue. + */ + if( !minlm_increaselambda(lambdav, nu, _state) ) + { + *iflag = -1; + goto lbl_2; + } + goto lbl_1; + } + + /* + * Step in State.XDir and it is bounded by StpMax. + * + * We should check stopping conditions on step size here. + * DeltaX, which is used for secant updates, is initialized here. + * + * This code is a bit tricky because sometimes XDir<>0, but + * it is so small that XDir+XBase==XBase (in finite precision + * arithmetics). So we set DeltaX to XBase, then + * add XDir, and then subtract XBase to get exact value of + * DeltaX. + * + * Step length is estimated using DeltaX. + * + * NOTE: stopping conditions are tested + * for fresh models only (ModelAge=0) + */ + ae_v_move(&deltax->ptr.p_double[0], 1, &xnew->ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_sub(&deltax->ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + *deltaxready = ae_true; + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(deltax->ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + if( ae_fp_less_eq(v,state->epsx) ) + { + if( state->modelage==0 ) + { + + /* + * Step is too short, model is fresh and we can rely on it. + * Terminating. + */ + *iflag = 2; + goto lbl_2; + } + else + { + + /* + * Step is suspiciously short, but model is not fresh + * and we can't rely on it. + */ + *iflag = -2; + goto lbl_2; + } + } + + /* + * Let's evaluate new step: + * a) if we have Fi vector, we evaluate it using rcomm, and + * then we manually calculate State.F as sum of squares of Fi[] + * b) if we have F value, we just evaluate it through rcomm interface + * + * We prefer (a) because we may need Fi vector for additional + * iterations + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &xnew->ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->needf = ae_false; + state->needfi = ae_false; + state->needfi = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfi = ae_false; + v = ae_v_dotproduct(&state->fi.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + *fnew = v; + ae_v_move(&deltaf->ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,m-1)); + ae_v_sub(&deltaf->ptr.p_double[0], 1, &state->fibase.ptr.p_double[0], 1, ae_v_len(0,m-1)); + *deltafready = ae_true; + if( !ae_isfinite(*fnew, _state) ) + { + + /* + * Integrity check failed, break! + */ + *iflag = -8; + goto lbl_2; + } + if( ae_fp_greater_eq(*fnew,state->fbase) ) + { + + /* + * Increase lambda and continue + */ + if( !minlm_increaselambda(lambdav, nu, _state) ) + { + *iflag = -1; + goto lbl_2; + } + goto lbl_1; + } + + /* + * We've found our step! + */ + *iflag = 0; + goto lbl_2; + goto lbl_1; +lbl_2: + *nu = (double)(1); + ae_assert(((*iflag>=-3&&*iflag<=0)||*iflag==-8)||*iflag>0, "MinLM: internal integrity check failed!", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = n; + state->rstate.ia.ptr.p_int[2] = m; + state->rstate.ba.ptr.p_bool[0] = bflag; + state->rstate.ra.ptr.p_double[0] = v; + return result; +} + + +void _minlmstepfinder_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlmstepfinder *p = (minlmstepfinder*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->modeldiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fibase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->xdir, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpct, 0, DT_INT, _state, make_automatic); + _minqpstate_init(&p->qpstate, _state, make_automatic); + _minqpreport_init(&p->qprep, _state, make_automatic); + _sparsematrix_init(&p->tmpsp, _state, make_automatic); +} + + +void _minlmstepfinder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlmstepfinder *dst = (minlmstepfinder*)_dst; + const minlmstepfinder *src = (const minlmstepfinder*)_src; + dst->n = src->n; + dst->m = src->m; + dst->stpmax = src->stpmax; + dst->modelage = src->modelage; + dst->maxmodelage = src->maxmodelage; + dst->epsx = src->epsx; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + dst->needf = src->needf; + dst->needfi = src->needfi; + dst->fbase = src->fbase; + ae_vector_init_copy(&dst->modeldiag, &src->modeldiag, _state, make_automatic); + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->fibase, &src->fibase, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic); + ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->xdir, &src->xdir, _state, make_automatic); + ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpct, &src->tmpct, _state, make_automatic); + dst->actualdecrease = src->actualdecrease; + dst->predicteddecrease = src->predicteddecrease; + _minqpstate_init_copy(&dst->qpstate, &src->qpstate, _state, make_automatic); + _minqpreport_init_copy(&dst->qprep, &src->qprep, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpsp, &src->tmpsp, _state, make_automatic); +} + + +void _minlmstepfinder_clear(void* _p) +{ + minlmstepfinder *p = (minlmstepfinder*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_vector_clear(&p->modeldiag); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fibase); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->havebndl); + ae_vector_clear(&p->havebndu); + ae_vector_clear(&p->s); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->xdir); + ae_vector_clear(&p->choleskybuf); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmpct); + _minqpstate_clear(&p->qpstate); + _minqpreport_clear(&p->qprep); + _sparsematrix_clear(&p->tmpsp); +} + + +void _minlmstepfinder_destroy(void* _p) +{ + minlmstepfinder *p = (minlmstepfinder*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_vector_destroy(&p->modeldiag); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fibase); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->havebndl); + ae_vector_destroy(&p->havebndu); + ae_vector_destroy(&p->s); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->xdir); + ae_vector_destroy(&p->choleskybuf); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmpct); + _minqpstate_destroy(&p->qpstate); + _minqpreport_destroy(&p->qprep); + _sparsematrix_destroy(&p->tmpsp); +} + + +void _minlmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlmstate *p = (minlmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fibase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gbase, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->quadraticmodel, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->havebndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->havebndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nonmonotonicbuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xnew, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xdir, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltaf, 0, DT_REAL, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->choleskybuf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gm1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gc1, 0, DT_REAL, _state, make_automatic); + _minlbfgsstate_init(&p->internalstate, _state, make_automatic); + _minlbfgsreport_init(&p->internalrep, _state, make_automatic); + _minqpstate_init(&p->qpstate, _state, make_automatic); + _minqpreport_init(&p->qprep, _state, make_automatic); + _minlmstepfinder_init(&p->finderstate, _state, make_automatic); +} + + +void _minlmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlmstate *dst = (minlmstate*)_dst; + const minlmstate *src = (const minlmstate*)_src; + dst->protocolversion = src->protocolversion; + dst->n = src->n; + dst->m = src->m; + dst->diffstep = src->diffstep; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + dst->maxmodelage = src->maxmodelage; + dst->makeadditers = src->makeadditers; + dst->nonmonotoniccnt = src->nonmonotoniccnt; + dst->formulatype = src->formulatype; + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->needfgh = src->needfgh; + dst->needfij = src->needfij; + dst->needfi = src->needfi; + dst->xupdated = src->xupdated; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + dst->algomode = src->algomode; + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + dst->fbase = src->fbase; + ae_vector_init_copy(&dst->fibase, &src->fibase, _state, make_automatic); + ae_vector_init_copy(&dst->gbase, &src->gbase, _state, make_automatic); + ae_matrix_init_copy(&dst->quadraticmodel, &src->quadraticmodel, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->havebndl, &src->havebndl, _state, make_automatic); + ae_vector_init_copy(&dst->havebndu, &src->havebndu, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + dst->lambdav = src->lambdav; + dst->nu = src->nu; + dst->modelage = src->modelage; + dst->nonmonotonicpos = src->nonmonotonicpos; + ae_vector_init_copy(&dst->nonmonotonicbuf, &src->nonmonotonicbuf, _state, make_automatic); + ae_vector_init_copy(&dst->xnew, &src->xnew, _state, make_automatic); + ae_vector_init_copy(&dst->xdir, &src->xdir, _state, make_automatic); + ae_vector_init_copy(&dst->deltax, &src->deltax, _state, make_automatic); + ae_vector_init_copy(&dst->deltaf, &src->deltaf, _state, make_automatic); + dst->deltaxready = src->deltaxready; + dst->deltafready = src->deltafready; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + dst->teststep = src->teststep; + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); + dst->fstagnationcnt = src->fstagnationcnt; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repnfunc = src->repnfunc; + dst->repnjac = src->repnjac; + dst->repngrad = src->repngrad; + dst->repnhess = src->repnhess; + dst->repncholesky = src->repncholesky; + dst->dotimers = src->dotimers; + dst->tstart = src->tstart; + dst->tqp = src->tqp; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->choleskybuf, &src->choleskybuf, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + dst->actualdecrease = src->actualdecrease; + dst->predicteddecrease = src->predicteddecrease; + dst->xm1 = src->xm1; + dst->xp1 = src->xp1; + ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic); + ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic); + ae_vector_init_copy(&dst->fc1, &src->fc1, _state, make_automatic); + ae_vector_init_copy(&dst->gm1, &src->gm1, _state, make_automatic); + ae_vector_init_copy(&dst->gp1, &src->gp1, _state, make_automatic); + ae_vector_init_copy(&dst->gc1, &src->gc1, _state, make_automatic); + _minlbfgsstate_init_copy(&dst->internalstate, &src->internalstate, _state, make_automatic); + _minlbfgsreport_init_copy(&dst->internalrep, &src->internalrep, _state, make_automatic); + _minqpstate_init_copy(&dst->qpstate, &src->qpstate, _state, make_automatic); + _minqpreport_init_copy(&dst->qprep, &src->qprep, _state, make_automatic); + _minlmstepfinder_init_copy(&dst->finderstate, &src->finderstate, _state, make_automatic); +} + + +void _minlmstate_clear(void* _p) +{ + minlmstate *p = (minlmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + ae_matrix_clear(&p->h); + ae_vector_clear(&p->g); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fibase); + ae_vector_clear(&p->gbase); + ae_matrix_clear(&p->quadraticmodel); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->havebndl); + ae_vector_clear(&p->havebndu); + ae_vector_clear(&p->s); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->nonmonotonicbuf); + ae_vector_clear(&p->xnew); + ae_vector_clear(&p->xdir); + ae_vector_clear(&p->deltax); + ae_vector_clear(&p->deltaf); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->choleskybuf); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->fm1); + ae_vector_clear(&p->fp1); + ae_vector_clear(&p->fc1); + ae_vector_clear(&p->gm1); + ae_vector_clear(&p->gp1); + ae_vector_clear(&p->gc1); + _minlbfgsstate_clear(&p->internalstate); + _minlbfgsreport_clear(&p->internalrep); + _minqpstate_clear(&p->qpstate); + _minqpreport_clear(&p->qprep); + _minlmstepfinder_clear(&p->finderstate); +} + + +void _minlmstate_destroy(void* _p) +{ + minlmstate *p = (minlmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + ae_matrix_destroy(&p->h); + ae_vector_destroy(&p->g); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fibase); + ae_vector_destroy(&p->gbase); + ae_matrix_destroy(&p->quadraticmodel); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->havebndl); + ae_vector_destroy(&p->havebndu); + ae_vector_destroy(&p->s); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->nonmonotonicbuf); + ae_vector_destroy(&p->xnew); + ae_vector_destroy(&p->xdir); + ae_vector_destroy(&p->deltax); + ae_vector_destroy(&p->deltaf); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->choleskybuf); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->fm1); + ae_vector_destroy(&p->fp1); + ae_vector_destroy(&p->fc1); + ae_vector_destroy(&p->gm1); + ae_vector_destroy(&p->gp1); + ae_vector_destroy(&p->gc1); + _minlbfgsstate_destroy(&p->internalstate); + _minlbfgsreport_destroy(&p->internalrep); + _minqpstate_destroy(&p->qpstate); + _minqpreport_destroy(&p->qprep); + _minlmstepfinder_destroy(&p->finderstate); +} + + +void _minlmreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlmreport *p = (minlmreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlmreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlmreport *dst = (minlmreport*)_dst; + const minlmreport *src = (const minlmreport*)_src; + dst->iterationscount = src->iterationscount; + dst->terminationtype = src->terminationtype; + dst->f = src->f; + dst->nfunc = src->nfunc; + dst->njac = src->njac; + dst->ngrad = src->ngrad; + dst->nhess = src->nhess; + dst->ncholesky = src->ncholesky; +} + + +void _minlmreport_clear(void* _p) +{ + minlmreport *p = (minlmreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minlmreport_destroy(void* _p) +{ + minlmreport *p = (minlmreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes solver state +*************************************************************************/ +void minaulinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + const nlpstoppingcriteria* criteria, + ae_int_t maxouterits, + minaulstate* state, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(cntlc==0||a->m==cntlc, "AUL: rows(A)<>CntLC", _state); + ae_assert(maxouterits>=0, "AUL: MaxOuterIts<0", _state); + + /* + * Initialization + */ + if( maxouterits==0 ) + { + maxouterits = 20; + } + state->n = n; + state->cntlc = cntlc; + state->cntnlc = cntnlc; + + /* + * Prepare RCOMM state + */ + ae_vector_set_length(&state->rstate.ia, 9+1, _state); + ae_vector_set_length(&state->rstate.ba, 4+1, _state); + ae_vector_set_length(&state->rstate.ra, 23+1, _state); + state->rstate.stage = -1; + state->needsj = ae_false; + state->precrefreshupcoming = ae_false; + state->xupdated = ae_false; + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->fi, 1+cntnlc, _state); + + /* + * Allocate memory. + */ + rallocv(n, &state->x0, _state); + rsetallocv(n, 1.0, &state->s, _state); + rvectorsetlengthatleast(&state->fscales, 1+cntnlc, _state); + rvectorsetlengthatleast(&state->tracegamma, 1+cntnlc, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rvectorsetlengthatleast(&state->scaledbndl, n, _state); + rvectorsetlengthatleast(&state->scaledbndu, n, _state); + rallocv(2*n, &state->lagmultbc2, _state); + rvectorsetlengthatleast(&state->lagmultxc2, 2*(cntlc+cntnlc), _state); + rallocv(n, &state->d, _state); + rallocv(n, &state->du, _state); + rallocv(n, &state->laggradcur, _state); + rallocv(n, &state->modtgtgrad0, _state); + rallocv(n, &state->modtgtgrad1, _state); + + /* + * Prepare scaled problem + */ + rsetallocv(n, -1.0E50, &state->finitebndl, _state); + rsetallocv(n, 1.0E50, &state->finitebndu, _state); + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->scaledbndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitebndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->scaledbndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitebndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "AUL: integrity check failed, box constraints are inconsistent", _state); + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + if( cntlc>0 ) + { + rsetallocv(n, 0.0, &state->tmpzero, _state); + sparsecopytocrsbuf(a, &state->sparsea, _state); + rcopyallocv(cntlc, al, &state->al, _state); + rcopyallocv(cntlc, au, &state->au, _state); + icopyallocv(cntlc, lcsrcidx, &state->lcsrcidx, _state); + scaleshiftmixedlcinplace(s, &state->tmpzero, n, &state->sparsea, cntlc, &state->dummy2, 0, &state->al, &state->au, _state); + normalizesparselcinplace(&state->sparsea, cntlc, &state->al, &state->au, n, ae_true, &state->ascales, ae_true, _state); + ballocv(cntlc, &state->hasal, _state); + ballocv(cntlc, &state->hasau, _state); + for(i=0; i<=cntlc-1; i++) + { + state->hasal.ptr.p_bool[i] = ae_isfinite(state->al.ptr.p_double[i], _state); + state->hasau.ptr.p_bool[i] = ae_isfinite(state->au.ptr.p_double[i], _state); + } + } + if( cntnlc>0 ) + { + rcopyallocv(cntnlc, nl, &state->rawnl, _state); + rcopyallocv(cntnlc, nu, &state->rawnu, _state); + ballocv(cntnlc, &state->hasnl, _state); + ballocv(cntnlc, &state->hasnu, _state); + for(i=0; i<=cntnlc-1; i++) + { + state->hasnl.ptr.p_bool[i] = ae_isfinite(state->rawnl.ptr.p_double[i], _state); + state->hasnu.ptr.p_bool[i] = ae_isfinite(state->rawnu.ptr.p_double[i], _state); + } + } + enforceboundaryconstraints(&state->x0, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + + /* + * Stopping criteria and settings + */ + critcopy(criteria, &state->criteria, _state); + state->maxouterits = maxouterits; + state->restartfreq = 5; + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repiterationscount = 0; + + /* + * Integrity checks + */ + ae_assert(ae_fp_less(nlcaul_auldeltadecrease,nlcaul_auldeltaincrease), "MinAUL: integrity check failed", _state); +} + + +/************************************************************************* +This function performs actual processing for AUL algorithm. It expects +that caller redirects its reverse communication requests NeedFiJ/XUpdated +to external user who will provide analytic derivative (or handle reports +about progress). + +In case external user does not have analytic derivative, it is responsibility +of caller to intercept NeedFiJ request and replace it with appropriate +numerical differentiation scheme. + +Results are stored: +* point - in State.StepKX + +IMPORTANT: this function works with scaled problem formulation; it is + responsibility of the caller to unscale request and scale + Jacobian. + +NOTE: SMonitor is expected to be correctly initialized smoothness monitor. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +ae_bool minauliteration(minaulstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t nconstr; + ae_bool dotrace; + ae_bool doprobingalways; + ae_bool dodetailedtrace; + double lagcur; + double lag0; + double lag1; + double laga; + double lagb; + double ci; + double modtgt0; + double modtgt1; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + double mx; + double setscaleto; + double multiplyby; + ae_int_t mcinfo; + ae_bool inneriterationsstopped; + double stpproposed; + double p; + double dp; + double d2p; + double steplengthtoprobe; + double v; + double vv; + ae_bool stepaccepted; + double errprim; + double errdual; + double errcmpl; + double preverrprim; + double preverrdual; + double preverrcmpl; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + cntlc = state->rstate.ia.ptr.p_int[1]; + cntnlc = state->rstate.ia.ptr.p_int[2]; + nconstr = state->rstate.ia.ptr.p_int[3]; + i = state->rstate.ia.ptr.p_int[4]; + j = state->rstate.ia.ptr.p_int[5]; + j0 = state->rstate.ia.ptr.p_int[6]; + j1 = state->rstate.ia.ptr.p_int[7]; + jj = state->rstate.ia.ptr.p_int[8]; + mcinfo = state->rstate.ia.ptr.p_int[9]; + dotrace = state->rstate.ba.ptr.p_bool[0]; + doprobingalways = state->rstate.ba.ptr.p_bool[1]; + dodetailedtrace = state->rstate.ba.ptr.p_bool[2]; + inneriterationsstopped = state->rstate.ba.ptr.p_bool[3]; + stepaccepted = state->rstate.ba.ptr.p_bool[4]; + lagcur = state->rstate.ra.ptr.p_double[0]; + lag0 = state->rstate.ra.ptr.p_double[1]; + lag1 = state->rstate.ra.ptr.p_double[2]; + laga = state->rstate.ra.ptr.p_double[3]; + lagb = state->rstate.ra.ptr.p_double[4]; + ci = state->rstate.ra.ptr.p_double[5]; + modtgt0 = state->rstate.ra.ptr.p_double[6]; + modtgt1 = state->rstate.ra.ptr.p_double[7]; + mx = state->rstate.ra.ptr.p_double[8]; + setscaleto = state->rstate.ra.ptr.p_double[9]; + multiplyby = state->rstate.ra.ptr.p_double[10]; + stpproposed = state->rstate.ra.ptr.p_double[11]; + p = state->rstate.ra.ptr.p_double[12]; + dp = state->rstate.ra.ptr.p_double[13]; + d2p = state->rstate.ra.ptr.p_double[14]; + steplengthtoprobe = state->rstate.ra.ptr.p_double[15]; + v = state->rstate.ra.ptr.p_double[16]; + vv = state->rstate.ra.ptr.p_double[17]; + errprim = state->rstate.ra.ptr.p_double[18]; + errdual = state->rstate.ra.ptr.p_double[19]; + errcmpl = state->rstate.ra.ptr.p_double[20]; + preverrprim = state->rstate.ra.ptr.p_double[21]; + preverrdual = state->rstate.ra.ptr.p_double[22]; + preverrcmpl = state->rstate.ra.ptr.p_double[23]; + } + else + { + n = 359; + cntlc = -58; + cntnlc = -919; + nconstr = -909; + i = 81; + j = 255; + j0 = 74; + j1 = -788; + jj = 809; + mcinfo = 205; + dotrace = ae_false; + doprobingalways = ae_true; + dodetailedtrace = ae_false; + inneriterationsstopped = ae_true; + stepaccepted = ae_true; + lagcur = -698.0; + lag0 = -900.0; + lag1 = -318.0; + laga = -940.0; + lagb = 1016.0; + ci = -229.0; + modtgt0 = -536.0; + modtgt1 = 487.0; + mx = -115.0; + setscaleto = 886.0; + multiplyby = 346.0; + stpproposed = -722.0; + p = -413.0; + dp = -461.0; + d2p = 927.0; + steplengthtoprobe = 201.0; + v = 922.0; + vv = -154.0; + errprim = 306.0; + errdual = -1011.0; + errcmpl = 951.0; + preverrprim = -463.0; + preverrdual = 88.0; + preverrcmpl = -861.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + + /* + * Routine body + */ + n = state->n; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + nconstr = state->cntlc+state->cntnlc; + dotrace = ae_is_trace_enabled("AUL"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("AUL.DETAILED"); + doprobingalways = dotrace&&ae_is_trace_enabled("AUL.PROBING"); + + /* + * Prepare rcomm interface + */ + state->needsj = ae_false; + state->precrefreshupcoming = ae_false; + state->xupdated = ae_false; + + /* + * Initialize algorithm state. + * + * Create two points that will be maintained during iterations: + * * a 'virtual' point which is used by the AUL solver. This point is + * subject to box constraints, but they are enforced only approximately. + * Constraint violation in the intermediate points can be very large. + * However, the user does not see this point when we send a callback request. + * * a 'true' point which actually sent to the user - obtained by clipping + * the virtual point to the box constrained area. + */ + for(i=0; i<=cntnlc; i++) + { + state->fscales.ptr.p_double[i] = 1.0; + state->tracegamma.ptr.p_double[i] = 0.0; + } + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + state->inneriterationscount = 0; + state->outeriterationscount = 0; + rsetv(2*n, 0.0, &state->lagmultbc2, _state); + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + state->lagmultbc2.ptr.p_double[2*i+0] = 0.0; + state->lagmultbc2.ptr.p_double[2*i+1] = 0.0; + continue; + } + if( state->hasbndl.ptr.p_bool[i] ) + { + state->lagmultbc2.ptr.p_double[2*i+0] = nlcaul_defaultinequalitylag; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->lagmultbc2.ptr.p_double[2*i+1] = nlcaul_defaultinequalitylag; + } + } + rsetv(2*(cntlc+cntnlc), 0.0, &state->lagmultxc2, _state); + for(i=0; i<=cntlc-1; i++) + { + if( (state->hasal.ptr.p_bool[i]&&state->hasau.ptr.p_bool[i])&&ae_fp_eq(state->al.ptr.p_double[i],state->au.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + state->lagmultxc2.ptr.p_double[2*i+0] = 0.0; + state->lagmultxc2.ptr.p_double[2*i+1] = 0.0; + continue; + } + if( state->hasal.ptr.p_bool[i] ) + { + state->lagmultxc2.ptr.p_double[2*i+0] = nlcaul_defaultinequalitylag; + } + if( state->hasau.ptr.p_bool[i] ) + { + state->lagmultxc2.ptr.p_double[2*i+1] = nlcaul_defaultinequalitylag; + } + } + for(i=0; i<=cntnlc-1; i++) + { + if( (state->hasnl.ptr.p_bool[i]&&state->hasnu.ptr.p_bool[i])&&ae_fp_eq(state->rawnl.ptr.p_double[i],state->rawnu.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0] = 0.0; + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+1] = 0.0; + continue; + } + if( state->hasnl.ptr.p_bool[i] ) + { + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0] = nlcaul_defaultinequalitylag; + } + if( state->hasnu.ptr.p_bool[i] ) + { + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+1] = nlcaul_defaultinequalitylag; + } + } + vfjallocsparse(n, 1+cntnlc, &state->xvirt, _state); + vfjallocsparse(n, 1+cntnlc, &state->xtrue, _state); + rcopyv(n, &state->x0, &state->xvirt.x, _state); + + /* + * Evaluate function vector and Jacobian at X0, send first location report. + * Compute initial violation of constraints. + */ + nlcaul_aulsendvirtualpoint(state, &state->xvirt.x, &state->xtrue.x, _state); + state->needsj = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needsj = ae_false; + if( !nlcaul_aulretrievesj(state, &state->xvirt, &state->xtrue, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + nlcaul_aulsendtruepoint(state, &state->xtrue.x, _state); + state->f = state->xtrue.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; + checklc2violation(&state->sparsea, &state->al, &state->au, &state->lcsrcidx, cntlc, &state->xtrue.x, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlc2violation(&state->xtrue.fi, &state->fscales, &state->rawnl, &state->rawnu, cntnlc, &state->repnlcerr, &state->repnlcidx, _state); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// AUL SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("cntLC = %6d\n", + (int)(state->cntlc)); + ae_trace("cntNLC = %6d\n", + (int)(state->cntnlc)); + } + + /* + * Perform outer (NLC) iterations + */ + preverrprim = 1.0E50; + preverrdual = 1.0E50; + preverrcmpl = 1.0E50; + state->fstagnationcnt = 0; + state->longeststp = 0.0; + state->rho = 500.0; + hessianinitlowrank(&state->hessaug, n, ae_minint(n, nlcaul_xbfgsmemlen, _state), ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), nlcaul_xbfgsmaxhess*((double)1+state->rho), _state); + hessianinitlowrank(&state->hesstgt, n, 1, ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), nlcaul_xbfgsmaxhess, _state); + vfjcopy(&state->xvirt, &state->xvirtbest, _state); + vfjcopy(&state->xtrue, &state->xtruebest, _state); + state->besterr = ae_maxrealnumber; + state->bestiteridx = -1; + state->besterrnegligibleupdates = 0; + nlcaul_preconditionerinit(state, state->restartfreq, &state->preconditioner, _state); +lbl_6: + if( ae_false ) + { + goto lbl_7; + } + if( dotrace ) + { + ae_trace("\n=== INNER ITERATION %5d, OUTER ITERATION %5d ===================================================\n", + (int)(state->repiterationscount), + (int)(state->outeriterationscount)); + } + + /* + * Renormalize target function and/or constraints, if some of them have too large magnitudes + */ + for(i=0; i<=cntnlc; i++) + { + + /* + * Determine (a) multiplicative coefficient applied to function value + * and Jacobian row, and (b) new value of the function scale. + */ + mx = (double)(0); + j0 = state->xvirt.sj.ridx.ptr.p_int[i]; + j1 = state->xvirt.sj.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + mx = mx+ae_sqr(state->xvirt.sj.vals.ptr.p_double[j], _state); + } + mx = ae_sqrt(mx, _state); + multiplyby = 1.0; + setscaleto = state->fscales.ptr.p_double[i]; + if( ae_fp_greater_eq(mx,nlcaul_aulbigscale) ) + { + multiplyby = (double)1/mx; + setscaleto = state->fscales.ptr.p_double[i]*mx; + } + if( ae_fp_less_eq(mx,nlcaul_aulsmallscale)&&ae_fp_greater(state->fscales.ptr.p_double[i],1.0) ) + { + if( ae_fp_greater(state->fscales.ptr.p_double[i]*mx,(double)(1)) ) + { + multiplyby = (double)1/mx; + setscaleto = state->fscales.ptr.p_double[i]*mx; + } + else + { + multiplyby = state->fscales.ptr.p_double[i]; + setscaleto = 1.0; + } + } + if( ae_fp_neq(multiplyby,1.0) ) + { + + /* + * Function #I needs renormalization: + * * update function vector element and Jacobian matrix row + * * update slack variable and box constraints + * * update FScales[] and TraceGamma[] arrays + */ + state->xvirt.fi.ptr.p_double[i] = state->xvirt.fi.ptr.p_double[i]*multiplyby; + state->xtrue.fi.ptr.p_double[i] = state->xtrue.fi.ptr.p_double[i]*multiplyby; + j0 = state->xvirt.sj.ridx.ptr.p_int[i]; + j1 = state->xvirt.sj.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->xvirt.sj.vals.ptr.p_double[j] = state->xvirt.sj.vals.ptr.p_double[j]*multiplyby; + } + j0 = state->xtrue.sj.ridx.ptr.p_int[i]; + j1 = state->xtrue.sj.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->xtrue.sj.vals.ptr.p_double[j] = state->xtrue.sj.vals.ptr.p_double[j]*multiplyby; + } + if( i==0 ) + { + + /* + * Rescaling target, rescale all Lagrange multipliers + */ + rmulv(2*n, multiplyby, &state->lagmultbc2, _state); + rmulv(2*(cntlc+cntnlc), multiplyby, &state->lagmultxc2, _state); + if( dotrace ) + { + ae_trace("> target rescaled by %0.2e during renormalization\n", + (double)(multiplyby)); + } + } + else + { + + /* + * Rescaling nonlinear constraint, rescale only quantities related to this constraint + */ + if( state->hasnl.ptr.p_bool[i-1] ) + { + state->rawnl.ptr.p_double[i-1] = state->rawnl.ptr.p_double[i-1]*multiplyby; + } + if( state->hasnu.ptr.p_bool[i-1] ) + { + state->rawnu.ptr.p_double[i-1] = state->rawnu.ptr.p_double[i-1]*multiplyby; + } + state->lagmultxc2.ptr.p_double[2*(cntlc+(i-1))+0] = state->lagmultxc2.ptr.p_double[2*(cntlc+(i-1))+0]/multiplyby; + state->lagmultxc2.ptr.p_double[2*(cntlc+(i-1))+1] = state->lagmultxc2.ptr.p_double[2*(cntlc+(i-1))+1]/multiplyby; + } + state->fscales.ptr.p_double[i] = setscaleto; + state->tracegamma.ptr.p_double[i] = state->tracegamma.ptr.p_double[i]*multiplyby; + } + } + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + if( dodetailedtrace ) + { + ae_trace("> printing raw data (prior to applying variable and function scales)\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->xvirt.x, n, &state->s, ae_true, &state->s, ae_false, _state); + ae_trace("\n"); + ae_trace("> printing scaled data (after applying variable and function scales)\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->xvirt.x, 0, n, _state); + ae_trace("\n"); + ae_trace("FScales = "); + tracevectorautoprec(&state->fscales, 0, 1+cntnlc, _state); + ae_trace("\n"); + ae_trace("GammaScl = "); + tracevectorautoprec(&state->tracegamma, 0, 1+cntnlc, _state); + ae_trace("\n"); + ae_trace("Fi (scaled) = "); + tracevectorautoprec(&state->xvirt.fi, 0, 1+cntnlc, _state); + ae_trace("\n"); + ae_trace("lagMultBC = "); + tracevectorautoprec(&state->lagmultbc2, 0, 2*n, _state); + ae_trace("\n"); + ae_trace("lagMultLC = "); + tracevectorautoprec(&state->lagmultxc2, 0, 2*cntlc, _state); + ae_trace("\n"); + ae_trace("lagMultNLC = "); + tracevectorautoprec(&state->lagmultxc2, 2*cntlc, 2*cntlc+2*cntnlc, _state); + ae_trace("\n"); + } + mx = (double)(0); + for(i=1; i<=cntnlc; i++) + { + mx = ae_maxreal(mx, ae_fabs(state->xvirt.fi.ptr.p_double[i], _state), _state); + } + ae_trace("Rho = %0.3e (penalty for violation of constraints)\n", + (double)(state->rho)); + ae_trace("lin.violation = %0.3e (scaled violation of linear constraints)\n", + (double)(state->replcerr)); + ae_trace("nlc.violation = %0.3e (scaled violation of nonlinear constraints)\n", + (double)(mx)); + ae_trace("gamma0 = %0.3e (Hessian 2-norm estimate for target)\n", + (double)(state->tracegamma.ptr.p_double[0])); + j = 0; + for(i=0; i<=cntnlc; i++) + { + if( ae_fp_greater(state->tracegamma.ptr.p_double[i],state->tracegamma.ptr.p_double[j]) ) + { + j = i; + } + } + ae_trace("gammaMax = %0.3e (maximum over Hessian 2-norm estimates for target/constraints)\n", + (double)(state->tracegamma.ptr.p_double[j])); + ae_trace("arg(gammaMax) = %0d (function index; 0 for target, >0 for nonlinear constraints)\n", + (int)(j)); + ae_trace("|x|inf = %0.3e\n", + (double)(rmaxabsv(n, &state->xvirt.x, _state))); + ae_trace("|LagBC|inf = %0.3e\n", + (double)(rmaxabsv(2*n, &state->lagmultbc2, _state))); + ae_trace("|LagXC|inf = %0.3e\n", + (double)(rmaxabsv(2*(cntlc+cntnlc), &state->lagmultxc2, _state))); + } + + /* + * Save current state + */ + vfjcopy(&state->xvirt, &state->xvirtprev, _state); + vfjcopy(&state->xtrue, &state->xtrueprev, _state); + + /* + * Send most recent copy of L-BFGS Hessians to the preconditioner + */ + nlcaul_preconditionersendupdates(state, &state->preconditioner, &state->xvirt, state->rho, &state->lagmultbc2, &state->lagmultxc2, &state->hesstgt, &state->hessaug, _state); + + /* + * Compute preconditioned step direction + */ + if( dotrace ) + { + ae_trace("\n--- LBFGS-preconditioned gradient descent ----------------------------------------------------------\n"); + } + nlcaul_auglagfg(state, &state->xvirt, state->rho, &state->lagmultbc2, &state->lagmultxc2, &lagcur, &state->laggradcur, _state); + nlcaul_modtargetfg(state, &state->xvirt, state->rho, state->rho, &modtgt0, &state->modtgtgrad0, _state); + lag0 = lagcur; + nlcaul_preconditionersolve(state, &state->preconditioner, &state->laggradcur, &state->d, _state); + if( dotrace ) + { + if( dodetailedtrace ) + { + ae_trace("grad L(X0) = "); + tracevectorautoprec(&state->laggradcur, 0, n, _state); + ae_trace("\n"); + ae_trace("D = "); + tracevectorautoprec(&state->d, 0, n, _state); + ae_trace("\n"); + } + ae_trace("(D,G) = %0.2e (directional derivative)\n", + (double)(rdotv(n, &state->laggradcur, &state->d, _state))); + } + + /* + * Perform optimization along step directions + */ + rallocv(n, &state->work, _state); + state->mcstage = 0; + state->stp = 1.0; + rcopyv(n, &state->d, &state->du, _state); + linminnormalized(&state->d, &state->stp, n, _state); + stpproposed = state->stp; + state->longeststp = coalesce(state->longeststp, state->stp, _state); + state->stplimit = (double)10*state->longeststp; + rcopyallocv(n, &state->laggradcur, &state->laggrad0, _state); + lag0 = lagcur; + mcsrch(n, &state->xvirt.x, &lagcur, &state->laggradcur, &state->d, &state->stp, state->stplimit, nlcaul_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_8: + if( state->mcstage==0 ) + { + goto lbl_9; + } + nlcaul_clearrequestfields(state, _state); + nlcaul_aulsendvirtualpoint(state, &state->xvirt.x, &state->xtrue.x, _state); + state->needsj = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needsj = ae_false; + if( !nlcaul_aulretrievesj(state, &state->xvirt, &state->xtrue, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + nlcaul_auglagfg(state, &state->xvirt, state->rho, &state->lagmultbc2, &state->lagmultxc2, &lagcur, &state->laggradcur, _state); + mcsrch(n, &state->xvirt.x, &lagcur, &state->laggradcur, &state->d, &state->stp, state->stplimit, nlcaul_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_8; +lbl_9: + lag1 = lagcur; + if( dotrace ) + { + ae_trace("> line search finished with relative step %0.3f, absolute step %0.3e, %0d evals, MCINFO=%0d\n", + (double)(state->stp/stpproposed), + (double)(state->stp*rmaxabsv(n, &state->d, _state)), + (int)(state->nfev), + (int)(mcinfo)); + ae_trace("mod Tgt: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(state->xvirtprev.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]), + (double)(state->xvirt.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]), + (double)(state->xvirt.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]-state->xvirtprev.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0])); + ae_trace("raw Lag: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(lag0), + (double)(lag1), + (double)(lag1-lag0)); + } + nlcaul_clearrequestfields(state, _state); + nlcaul_aulsendtruepoint(state, &state->xtrue.x, _state); + state->f = state->xtrue.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->xupdated = ae_false; + state->repnfev = state->repnfev+state->nfev; + + /* + * Update curvature information, statistics, errors + */ + state->longeststp = ae_maxreal(state->longeststp, state->stp, _state); + if( mcinfo==1 ) + { + hessianupdate(&state->hessaug, &state->xvirtprev.x, &state->laggrad0, &state->xvirt.x, &state->laggradcur, dotrace, _state); + } + else + { + if( dotrace ) + { + ae_trace("> L-BFGS update for an augmented Lagrangian is rejected (MCINFO<>1)\n"); + } + } + nlcaul_modtargetfg(state, &state->xvirt, state->rho, state->rho, &modtgt1, &state->modtgtgrad1, _state); + hessianupdate(&state->hesstgt, &state->xvirtprev.x, &state->modtgtgrad0, &state->xvirt.x, &state->modtgtgrad1, dotrace, _state); + checklc2violation(&state->sparsea, &state->al, &state->au, &state->lcsrcidx, cntlc, &state->xtrue.x, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlc2violation(&state->xtrue.fi, &state->fscales, &state->rawnl, &state->rawnu, cntnlc, &state->repnlcerr, &state->repnlcidx, _state); + nlcaul_computeerrors(state, &state->xvirt, &errprim, &errdual, &errcmpl, _state); + + /* + * Perform agressive probing of the search direction - additional function evaluations + * which help us to determine possible discontinuity and nonsmoothness of the problem + */ + if( !doprobingalways ) + { + goto lbl_10; + } + vfjcopy(&state->xvirtprev, &state->xvirtprobe, _state); + vfjcopy(&state->xtrueprev, &state->xtrueprobe, _state); + steplengthtoprobe = ae_maxreal((double)5*(state->stp/stpproposed), 0.01, _state); + smoothnessmonitorstartlagrangianprobing(smonitor, &state->xvirtprobe.x, &state->du, steplengthtoprobe, state->repiterationscount, state->outeriterationscount, _state); +lbl_12: + if( !smoothnessmonitorprobelagrangian(smonitor, _state) ) + { + goto lbl_13; + } + rcopyv(n, &smonitor->lagprobx, &state->xvirtprobe.x, _state); + nlcaul_clearrequestfields(state, _state); + nlcaul_aulsendvirtualpoint(state, &state->xvirtprobe.x, &state->xtrueprobe.x, _state); + state->needsj = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needsj = ae_false; + if( !nlcaul_aulretrievesj(state, &state->xvirtprobe, &state->xtrueprobe, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + rcopyallocv(1+cntnlc, &state->xvirtprobe.fi, &smonitor->lagprobfi, _state); + rsetallocm(1+cntnlc, n, 0.0, &smonitor->lagprobj, _state); + for(i=0; i<=cntnlc; i++) + { + j0 = state->xvirtprobe.sj.ridx.ptr.p_int[i]; + j1 = state->xvirtprobe.sj.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + smonitor->lagprobj.ptr.pp_double[i][state->xvirtprobe.sj.idx.ptr.p_int[jj]] = state->xvirtprobe.sj.vals.ptr.p_double[jj]; + } + } + rallocv(n, &state->tmpg, _state); + nlcaul_auglagfg(state, &state->xvirtprobe, state->rho, &state->lagmultbc2, &state->lagmultxc2, &smonitor->lagprobrawlag, &state->tmpg, _state); + goto lbl_12; +lbl_13: + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | probing search direction |\n"); + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | Step | Lagrangian (unaugmentd)| Projected target |\n"); + ae_trace("*** |along D| must be smooth | must be smooth |\n"); + ae_trace("*** | | function | slope | function | slope |\n"); + smoothnessmonitortracelagrangianprobingresults(smonitor, _state); +lbl_10: + + /* + * Trace + */ + if( dotrace ) + { + } + + /* + * Trace + */ + if( dotrace ) + { + ae_trace("\n--- inner iteration ends ---------------------------------------------------------------------------\n"); + ae_trace("> printing primal/dual/complementary errors:\n"); + ae_trace("prim.feas = %0.3e (primal feasibility error, inf-norm)\n", + (double)(errprim)); + ae_trace("dual.feas = %0.3e (dual feasibility error, inf-norm)\n", + (double)(errdual)); + ae_trace("cmpl.slckness = %0.3e (complementary slackness, inf-norm)\n", + (double)(errcmpl)); + } + + /* + * Update iterations counts. + * Check stopping criteria for inner iterations. + */ + state->repiterationscount = state->repiterationscount+1; + state->inneriterationscount = state->inneriterationscount+1; + inneriterationsstopped = ae_false; + state->fstagnationcnt = icase2(ae_fp_less_eq(ae_fabs(lag1-lag0, _state),nlcaul_stagnationepsf*rmax3(ae_fabs(lag1, _state), ae_fabs(lag0, _state), (double)(1), _state)), state->fstagnationcnt+1, 0, _state); + v = ae_fabs(lag1-lag0, _state)/rmaxabs3(lag1, lag0, (double)(1), _state); + vv = ae_fabs(modtgt1-modtgt0, _state)/rmaxabs3(modtgt1, modtgt0, (double)(1), _state); + if( ae_fp_less_eq(ae_maxreal(v, vv, _state),critgetepsf(&state->criteria, _state)) ) + { + inneriterationsstopped = ae_true; + if( dotrace ) + { + ae_trace("> stopping condition for inner iterations met: function change is smaller than %0.3e\n", + (double)(critgetepsf(&state->criteria, _state))); + } + } + if( ae_fp_less_eq(rmaxabsv(n, &state->d, _state)*state->stp,critgeteps(&state->criteria, _state)) ) + { + inneriterationsstopped = ae_true; + if( dotrace ) + { + ae_trace("> stopping condition for inner iterations met: step is smaller than %0.3e\n", + (double)(critgeteps(&state->criteria, _state))); + } + } + if( ae_fp_less_eq(rmaxabsv(n, &state->d, _state)*state->stp,0.001*ae_sqrt(ae_machineepsilon, _state)) ) + { + inneriterationsstopped = ae_true; + if( dotrace ) + { + ae_trace("> stopping condition for inner iterations met: step is smaller than the absolute minimum\n"); + } + } + if( critgetmaxits(&state->criteria, _state)>0&&state->inneriterationscount>=critgetmaxits(&state->criteria, _state) ) + { + inneriterationsstopped = ae_true; + if( dotrace ) + { + ae_trace("> stopping condition for inner iterations met: %0d iterations performed\n", + (int)(state->inneriterationscount)); + } + } + if( state->fstagnationcnt>=nlcaul_fstagnationlimit ) + { + if( dotrace ) + { + ae_trace("> stopping criteria are too stringent: F stagnated for %0d its, stopping\n", + (int)(state->fstagnationcnt)); + } + inneriterationsstopped = ae_true; + } + + /* + * Inner iterations stopped (or user requested termination) + * + * Update Lagrange multipliers, penalties, check stopping criteria for outer iterations. + */ + if( inneriterationsstopped||userterminationneeded ) + { + + /* + * Update best point so far + */ + if( ae_fp_less(rmax3(errprim, errdual, errcmpl, _state),state->besterr) ) + { + if( ae_fp_greater(rmax3(errprim, errdual, errcmpl, _state),nlcaul_besterrstagnationcoeff*state->besterr) ) + { + state->besterrnegligibleupdates = state->besterrnegligibleupdates+1; + } + vfjcopy(&state->xvirt, &state->xvirtbest, _state); + vfjcopy(&state->xtrue, &state->xtruebest, _state); + state->besterr = rmax3(errprim, errdual, errcmpl, _state); + state->bestiteridx = state->outeriterationscount; + } + + /* + * Advance outer iterations counter, reset inner iterations count, check stopping criteria + */ + state->outeriterationscount = state->outeriterationscount+1; + state->inneriterationscount = 0; + state->fstagnationcnt = 0; + if( (ae_fp_less_eq(errprim,(double)10*ae_sqrt(ae_machineepsilon, _state))&&ae_fp_less_eq(errdual,(double)10*ae_sqrt(ae_machineepsilon, _state)))&&ae_fp_less_eq(errcmpl,(double)10*ae_sqrt(ae_machineepsilon, _state)) ) + { + if( dotrace ) + { + ae_trace("> primal, dual and complementary slackness errors are small, stopping\n"); + } + state->repterminationtype = 1; + goto lbl_7; + } + if( state->besterrnegligibleupdates>=nlcaul_besterrstagnationlimit ) + { + if( dotrace ) + { + ae_trace("> primal/dual/complementary error had too many negligible updates, stopping\n"); + } + state->repterminationtype = 7; + goto lbl_7; + } + if( state->bestiteridxouteriterationscount-nlcaul_besterrstagnationlimit ) + { + if( dotrace ) + { + ae_trace("> primal/dual/complementary error stagnated for too long, stopping\n"); + } + state->repterminationtype = 7; + goto lbl_7; + } + if( userterminationneeded ) + { + if( dotrace ) + { + ae_trace("> user requested termination, stopping\n"); + } + state->repterminationtype = 8; + goto lbl_7; + } + if( state->outeriterationscount>=state->maxouterits ) + { + state->repterminationtype = 5; + goto lbl_7; + } + + /* + * Save primal/dual/complementary error estimates + */ + preverrprim = errprim; + preverrdual = errdual; + preverrcmpl = errcmpl; + + /* + * Update Lagrange multipliers + */ + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_greater(nlcaul_aulmaxgrowth,1.0), "AUL: integrity check 2444 failed", _state); + if( !state->hasbndl.ptr.p_bool[i]&&!state->hasbndu.ptr.p_bool[i] ) + { + continue; + } + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + v = ae_minreal(nlcaul_maxlagmult, nlcaul_aulmaxgrowth*(ae_fabs(state->lagmultbc2.ptr.p_double[2*i+0], _state)+(double)1), _state); + state->lagmultbc2.ptr.p_double[2*i+0] = boundval(state->lagmultbc2.ptr.p_double[2*i+0]+state->rho*(state->xvirt.x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]), -v, v, _state); + continue; + } + if( state->hasbndl.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->xvirt.x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultbc2.ptr.p_double[2*i+0] = boundval(state->lagmultbc2.ptr.p_double[2*i+0]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->scaledbndu.ptr.p_double[i]-state->xvirt.x.ptr.p_double[i])*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultbc2.ptr.p_double[2*i+1] = boundval(state->lagmultbc2.ptr.p_double[2*i+1]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + } + for(i=0; i<=cntlc-1; i++) + { + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+state->xvirt.x.ptr.p_double[state->sparsea.idx.ptr.p_int[jj]]*state->sparsea.vals.ptr.p_double[jj]; + } + if( (state->hasal.ptr.p_bool[i]&&state->hasau.ptr.p_bool[i])&&ae_fp_eq(state->al.ptr.p_double[i],state->au.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + state->lagmultxc2.ptr.p_double[2*i+0] = state->lagmultxc2.ptr.p_double[2*i+0]+state->rho*(ci-state->al.ptr.p_double[i]); + } + else + { + + /* + * No constraints, inequality constraint or range constraint + */ + if( state->hasal.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((ci-state->al.ptr.p_double[i])*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultxc2.ptr.p_double[2*i+0] = boundval(state->lagmultxc2.ptr.p_double[2*i+0]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + if( state->hasau.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->au.ptr.p_double[i]-ci)*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultxc2.ptr.p_double[2*i+1] = boundval(state->lagmultxc2.ptr.p_double[2*i+1]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + } + } + for(i=0; i<=cntnlc-1; i++) + { + ci = state->xvirt.fi.ptr.p_double[1+i]; + if( (state->hasnl.ptr.p_bool[i]&&state->hasnu.ptr.p_bool[i])&&ae_fp_eq(state->rawnl.ptr.p_double[i],state->rawnu.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0] = state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0]+state->rho*(ci-state->rawnl.ptr.p_double[i]); + } + else + { + + /* + * No constraints, inequality constraint or range constraint + */ + if( state->hasnl.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((ci-state->rawnl.ptr.p_double[i])*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0] = boundval(state->lagmultxc2.ptr.p_double[2*cntlc+2*i+0]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + if( state->hasnu.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->rawnu.ptr.p_double[i]-ci)*state->rho+(double)1, &p, &dp, &d2p, _state); + dp = ae_fabs(dp, _state); + dp = ae_minreal(dp, nlcaul_aulmaxgrowth, _state); + dp = ae_maxreal(dp, (double)1/nlcaul_aulmaxgrowth, _state); + state->lagmultxc2.ptr.p_double[2*cntlc+2*i+1] = boundval(state->lagmultxc2.ptr.p_double[2*cntlc+2*i+1]*dp, nlcaul_minlagmult, nlcaul_maxlagmult, _state); + } + } + } + + /* + * Update upper bound on Hessian norm + */ + hessiansetmaxhess(&state->hessaug, nlcaul_xbfgsmaxhess*((double)1+state->rho)*ae_maxreal((double)1+rmaxabsv(2*n, &state->lagmultbc2, _state), (double)1+rmaxabsv(2*cntlc+2*cntnlc, &state->lagmultxc2, _state), _state), _state); + state->rho = ae_minreal(ae_sqrt((double)(2), _state)*state->rho, nlcaul_rhomax, _state); + } + goto lbl_6; +lbl_7: + + /* + * Perform the final report + */ + nlcaul_clearrequestfields(state, _state); + nlcaul_aulsendtruepoint(state, &state->xtruebest.x, _state); + state->f = state->xtruebest.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->xupdated = ae_false; + + /* + * Almost done + */ + if( dotrace ) + { + ae_trace("\n=== STOPPED ========================================================================================\n"); + ae_trace("raw target: %20.12e\n", + (double)(state->xtruebest.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0])); + } + smoothnessmonitortracestatus(smonitor, dotrace, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = cntlc; + state->rstate.ia.ptr.p_int[2] = cntnlc; + state->rstate.ia.ptr.p_int[3] = nconstr; + state->rstate.ia.ptr.p_int[4] = i; + state->rstate.ia.ptr.p_int[5] = j; + state->rstate.ia.ptr.p_int[6] = j0; + state->rstate.ia.ptr.p_int[7] = j1; + state->rstate.ia.ptr.p_int[8] = jj; + state->rstate.ia.ptr.p_int[9] = mcinfo; + state->rstate.ba.ptr.p_bool[0] = dotrace; + state->rstate.ba.ptr.p_bool[1] = doprobingalways; + state->rstate.ba.ptr.p_bool[2] = dodetailedtrace; + state->rstate.ba.ptr.p_bool[3] = inneriterationsstopped; + state->rstate.ba.ptr.p_bool[4] = stepaccepted; + state->rstate.ra.ptr.p_double[0] = lagcur; + state->rstate.ra.ptr.p_double[1] = lag0; + state->rstate.ra.ptr.p_double[2] = lag1; + state->rstate.ra.ptr.p_double[3] = laga; + state->rstate.ra.ptr.p_double[4] = lagb; + state->rstate.ra.ptr.p_double[5] = ci; + state->rstate.ra.ptr.p_double[6] = modtgt0; + state->rstate.ra.ptr.p_double[7] = modtgt1; + state->rstate.ra.ptr.p_double[8] = mx; + state->rstate.ra.ptr.p_double[9] = setscaleto; + state->rstate.ra.ptr.p_double[10] = multiplyby; + state->rstate.ra.ptr.p_double[11] = stpproposed; + state->rstate.ra.ptr.p_double[12] = p; + state->rstate.ra.ptr.p_double[13] = dp; + state->rstate.ra.ptr.p_double[14] = d2p; + state->rstate.ra.ptr.p_double[15] = steplengthtoprobe; + state->rstate.ra.ptr.p_double[16] = v; + state->rstate.ra.ptr.p_double[17] = vv; + state->rstate.ra.ptr.p_double[18] = errprim; + state->rstate.ra.ptr.p_double[19] = errdual; + state->rstate.ra.ptr.p_double[20] = errcmpl; + state->rstate.ra.ptr.p_double[21] = preverrprim; + state->rstate.ra.ptr.p_double[22] = preverrdual; + state->rstate.ra.ptr.p_double[23] = preverrcmpl; + return result; +} + + +/************************************************************************* +Shifted barrier function for inequality constraints which is multiplied +by the corresponding Lagrange multiplier. + +Shift function must enter augmented Lagrangian as + + LagMult/Rho*SHIFT((x-lowerbound)*Rho+1) + +with corresponding changes being made for upper bound or other kinds of +constraints. + +INPUT PARAMETERS: + Alpha - function argument. Typically, if we have active constraint + with precise Lagrange multiplier, we have Alpha around 1. + Large positive Alpha's correspond to inner area of the + feasible set. Alpha<1 corresponds to outer area of the + feasible set. + +OUTPUT PARAMETERS: + F - F(Alpha) + DF - DF=dF(Alpha)/dAlpha, exact derivative + D2F - second derivative + + -- ALGLIB -- + Copyright 11.07.2023 by Bochkanov Sergey +*************************************************************************/ +void inequalityshiftedbarrierfunction(double alpha, + double* f, + double* df, + double* d2f, + ae_state *_state) +{ + + *f = 0.0; + *df = 0.0; + *d2f = 0.0; + + if( alpha>=0.5 ) + { + *f = -ae_log(alpha, _state); + *df = -(double)1/alpha; + *d2f = *df*(*df); + } + else + { + *f = (double)2*alpha*alpha-(double)4*alpha+(ae_log((double)(2), _state)+1.5); + *df = (double)4*alpha-(double)4; + *d2f = (double)(4); + } +} + + +/************************************************************************* +This function prepares preconditioner for subsequent computation. + +INPUT PARAMETERS: + SState - solver state + RefreshFreq - >=1, refresh frequency + +OUTPUT PARAMETERS: + P - preconditioner object, ready to be computed + + + -- ALGLIB -- + Copyright 13.06.2023 by Bochkanov Sergey +*************************************************************************/ +static void nlcaul_preconditionerinit(const minaulstate* sstate, + ae_int_t refreshfreq, + minaulpreconditioner* p, + ae_state *_state) +{ + + + p->refreshfreq = refreshfreq; + p->modelage = refreshfreq; +} + + +/************************************************************************* +This function sends updated target and augmented Lagrangian Hessians to the +preconditioner. It is expected that this call corresponds to one update of +Hessians. + + -- ALGLIB -- + Copyright 13.06.2023 by Bochkanov Sergey +*************************************************************************/ +static void nlcaul_preconditionersendupdates(minaulstate* state, + minaulpreconditioner* prec, + const varsfuncjac* current, + double rho, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + xbfgshessian* hesstgt, + xbfgshessian* hessaug, + ae_state *_state) +{ + ae_int_t n; + ae_int_t cntlc; + double sigmatgt; + double dummy; + ae_int_t dummyupdcnt; + double dampeps; + ae_int_t nconstr; + ae_int_t naug; + ae_int_t offs; + ae_int_t tgtrowidx; + double vd; + double p; + double dp; + double d2p; + double vcurvature; + double vsqrtcurvature; + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double ci; + double fi; + ae_int_t facttype; + + + n = state->n; + cntlc = state->cntlc; + nconstr = state->cntlc+state->cntnlc; + dampeps = (double)100*ae_sqrt(ae_machineepsilon, _state)*((double)1+rho); + + /* + * Extract LBFGS memory: + * * we extract only diagonal scaling factor Sigma from the mod-target Hessian, ignoring all updates + * * we extract only S/Y updates from the augmented Lagrangian Hessian + */ + hessiangetlowrankmemory(hesstgt, &sigmatgt, &prec->dummys, &prec->dummyy, &dummyupdcnt, _state); + hessiangetlowrankmemory(hessaug, &dummy, &prec->s, &prec->y, &prec->updcnt, _state); + ae_assert(ae_fp_greater(sigmatgt,(double)(0)), "AUL: sigma0<=0", _state); + + /* + * Increase model age, skip factorization update if model age is small enough + */ + prec->modelage = prec->modelage+1; + if( prec->modelagerefreshfreq ) + { + return; + } + + /* + * The model needs refactorization of the initial scaling matrix + */ + prec->modelage = 0; + + /* + * Generate initial scaling matrix which is a diagonal scaling Sigma from the mod-target Hessian + + * correction terms coming from penalized constraints. + */ + naug = n+nconstr; + prec->naug = naug; + prec->augsys.matrixtype = 1; + prec->augsys.m = naug; + prec->augsys.n = naug; + iallocv(naug+1, &prec->augsys.ridx, _state); + prec->augsys.ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + vd = 0.0; + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + + /* + * Equality constraint, quadratic penalty + */ + vd = rho; + } + else + { + if( state->hasbndl.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((current->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + vd = vd+lagmultbc2->ptr.p_double[2*i+0]*d2p*rho; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->scaledbndu.ptr.p_double[i]-current->x.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + vd = vd+lagmultbc2->ptr.p_double[2*i+1]*d2p*rho; + } + } + + /* + * Write the diagonal Hessian + diagonal correction coming from the box constraints + */ + offs = prec->augsys.ridx.ptr.p_int[i]; + igrowv(offs+naug, &prec->augsys.idx, _state); + rgrowv(offs+naug, &prec->augsys.vals, _state); + prec->augsys.idx.ptr.p_int[offs] = i; + prec->augsys.vals.ptr.p_double[offs] = sigmatgt+vd+dampeps; + offs = offs+1; + prec->augsys.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=state->cntlc-1; i++) + { + + /* + * Compute curvature coming from I-th linear constraint + */ + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+current->x.ptr.p_double[state->sparsea.idx.ptr.p_int[jj]]*state->sparsea.vals.ptr.p_double[jj]; + } + vcurvature = 0.0; + if( (state->hasal.ptr.p_bool[i]&&state->hasau.ptr.p_bool[i])&&ae_fp_eq(state->al.ptr.p_double[i],state->au.ptr.p_double[i]) ) + { + + /* + * Equality constraint Ai*x = ALi = AUi + */ + vcurvature = rho; + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasal.ptr.p_bool[i] ) + { + + /* + * Add curvature from inequality constraint Ai*x >= ALi + */ + inequalityshiftedbarrierfunction((ci-state->al.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + vcurvature = vcurvature+lagmultxc2->ptr.p_double[2*i+0]*d2p*rho; + } + if( state->hasau.ptr.p_bool[i] ) + { + + /* + * Add curvature from inequality constraint Ai*x <= AUi + */ + inequalityshiftedbarrierfunction((state->au.ptr.p_double[i]-ci)*rho+(double)1, &p, &dp, &d2p, _state); + vcurvature = vcurvature+lagmultxc2->ptr.p_double[2*i+1]*d2p*rho; + } + } + + /* + * Add modification to the Hessian + */ + vsqrtcurvature = ae_sqrt(ae_maxreal(vcurvature, 0.0, _state), _state); + tgtrowidx = n+i; + offs = prec->augsys.ridx.ptr.p_int[tgtrowidx]; + igrowv(offs+naug, &prec->augsys.idx, _state); + rgrowv(offs+naug, &prec->augsys.vals, _state); + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + prec->augsys.idx.ptr.p_int[offs] = state->sparsea.idx.ptr.p_int[jj]; + prec->augsys.vals.ptr.p_double[offs] = vsqrtcurvature*state->sparsea.vals.ptr.p_double[jj]; + offs = offs+1; + } + prec->augsys.idx.ptr.p_int[offs] = tgtrowidx; + prec->augsys.vals.ptr.p_double[offs] = -1.0; + offs = offs+1; + prec->augsys.ridx.ptr.p_int[tgtrowidx+1] = offs; + } + for(i=0; i<=state->cntnlc-1; i++) + { + + /* + * Compute curvature coming from I-th nonlinear constraint + */ + fi = current->fi.ptr.p_double[1+i]; + vcurvature = 0.0; + if( (state->hasnl.ptr.p_bool[i]&&state->hasnu.ptr.p_bool[i])&&ae_fp_eq(state->rawnl.ptr.p_double[i],state->rawnu.ptr.p_double[i]) ) + { + + /* + * Equality constraint Ai*x = ALi = AUi + */ + vcurvature = rho; + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasnl.ptr.p_bool[i] ) + { + + /* + * Add curvature from inequality constraint Ai*x >= ALi + */ + inequalityshiftedbarrierfunction((fi-state->rawnl.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + vcurvature = vcurvature+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*d2p*rho; + } + if( state->hasnu.ptr.p_bool[i] ) + { + + /* + * Add curvature from inequality constraint Ai*x <= AUi + */ + inequalityshiftedbarrierfunction((state->rawnu.ptr.p_double[i]-fi)*rho+(double)1, &p, &dp, &d2p, _state); + vcurvature = vcurvature+lagmultxc2->ptr.p_double[2*cntlc+2*i+1]*d2p*rho; + } + } + + /* + * Add modification + */ + vsqrtcurvature = ae_sqrt(ae_maxreal(vcurvature, 0.0, _state), _state); + tgtrowidx = n+cntlc+i; + offs = prec->augsys.ridx.ptr.p_int[tgtrowidx]; + igrowv(offs+naug, &prec->augsys.idx, _state); + rgrowv(offs+naug, &prec->augsys.vals, _state); + j0 = current->sj.ridx.ptr.p_int[1+i]; + j1 = current->sj.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + prec->augsys.idx.ptr.p_int[offs] = current->sj.idx.ptr.p_int[jj]; + prec->augsys.vals.ptr.p_double[offs] = vsqrtcurvature*current->sj.vals.ptr.p_double[jj]; + offs = offs+1; + } + prec->augsys.idx.ptr.p_int[offs] = tgtrowidx; + prec->augsys.vals.ptr.p_double[offs] = -1.0; + offs = offs+1; + prec->augsys.ridx.ptr.p_int[tgtrowidx+1] = offs; + } + sparsecreatecrsinplace(&prec->augsys, _state); + + /* + * Perform analysis and factorization + */ + facttype = 21; + isetallocv(naug, 0, &prec->priorities, _state); + if( !spsymmanalyze(&prec->augsys, &prec->priorities, 0.0, 0, facttype, 3, 1, &prec->analysis, _state) ) + { + ae_assert(ae_false, "AUL: integrity check 8126 failed", _state); + } + if( !spsymmfactorize(&prec->analysis, _state) ) + { + ae_assert(ae_false, "AUL: integrity check 8127 failed", _state); + } +} + + +/************************************************************************* +This function computes gradient and applies preconditioner. + + -- ALGLIB -- + Copyright 13.06.2023 by Bochkanov Sergey +*************************************************************************/ +static void nlcaul_preconditionersolve(minaulstate* state, + minaulpreconditioner* prec, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state) +{ + ae_int_t n; + ae_int_t naug; + ae_int_t k; + double betak; + + + ae_assert(prec->modelagerefreshfreq, "AUL: preconditioner needs at least one update in order to properly initialize itself", _state); + n = state->n; + naug = prec->naug; + + /* + * + */ + rallocv(prec->updcnt, &prec->alphak, _state); + rallocv(prec->updcnt, &prec->rhok, _state); + rcopymulv(n, -1.0, g, d, _state); + for(k=prec->updcnt-1; k>=0; k--) + { + prec->rhok.ptr.p_double[k] = (double)1/rdotrr(n, &prec->s, k, &prec->y, k, _state); + prec->alphak.ptr.p_double[k] = prec->rhok.ptr.p_double[k]*rdotvr(n, d, &prec->s, k, _state); + raddrv(n, -prec->alphak.ptr.p_double[k], &prec->y, k, d, _state); + } + rsetallocv(naug, 0.0, &prec->dx, _state); + rcopyv(n, d, &prec->dx, _state); + spsymmsolve(&prec->analysis, &prec->dx, _state); + rcopyv(n, &prec->dx, d, _state); + for(k=0; k<=prec->updcnt-1; k++) + { + betak = prec->rhok.ptr.p_double[k]*rdotvr(n, d, &prec->y, k, _state); + raddrv(n, prec->alphak.ptr.p_double[k]-betak, &prec->s, k, d, _state); + } +} + + +/************************************************************************* +Sends virtual point to the user, enforcing box constraints on it and saving +box-constrained copy to XTrue +*************************************************************************/ +static void nlcaul_aulsendvirtualpoint(minaulstate* state, + /* Real */ const ae_vector* xvirt, + /* Real */ ae_vector* xtrue, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(xvirt->cnt>=n, "AUL: integrity check 6339 failed", _state); + ae_assert(xtrue->cnt>=n, "AUL: integrity check 6440 failed", _state); + rcopyv(n, xvirt, &state->x, _state); + rmergemaxv(n, &state->finitebndl, &state->x, _state); + rmergeminv(n, &state->finitebndu, &state->x, _state); + rcopyv(n, &state->x, xtrue, _state); +} + + +/************************************************************************* +Sends true point (one which is already box-constrained) to the user. +*************************************************************************/ +static void nlcaul_aulsendtruepoint(minaulstate* state, + /* Real */ const ae_vector* xtrue, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(xtrue->cnt>=n, "AUL: integrity check 0044 failed", _state); + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&xtrue->ptr.p_double[i]scaledbndl.ptr.p_double[i] ) + { + ae_assert(ae_false, "AUL: box constrained point falls outside of the box constrained area", _state); + } + if( state->hasbndu.ptr.p_bool[i]&&xtrue->ptr.p_double[i]>state->scaledbndu.ptr.p_double[i] ) + { + ae_assert(ae_false, "AUL: box constrained point falls outside of the box constrained area", _state); + } + state->x.ptr.p_double[i] = xtrue->ptr.p_double[i]; + } +} + + +/************************************************************************* +Retrieves raw functions vector and scaled Jacobian from the user data, +fills two structures, XVirt and XTrue: + +* it is assumed that XVirt.X and XTrue.X are already initialized - the + former is initialized with the virtual point (one which is not subject + to box constraints) and the latter is initialized with the true point + (one which is box constrained and passed to the user) + +* XTrue.Fi and XTrue.SJ are initialized with the true values at XTrue.X + +* XVirt.Fi and XVirt.Sj are initialized with the values of the virtual + model which coincides with the true function vector at box constrained + points, but linearly extrapolates box constrained projection when XVirt + is not box-constrained. + +Returns True on success, False on failure (when F or J are not finite numbers). +*************************************************************************/ +static ae_bool nlcaul_aulretrievesj(minaulstate* state, + varsfuncjac* xvirt, + varsfuncjac* xtrue, + ae_state *_state) +{ + ae_int_t m; + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double v; + double vv; + ae_int_t offs; + ae_bool allsame; + ae_bool result; + + + ae_assert(!xvirt->isdense, "AULRetrieveSJ: dense output was specified", _state); + ae_assert(!xtrue->isdense, "AULRetrieveSJ: dense output was specified", _state); + ae_assert(state->sj.n==state->n, "AULRetrieveSJ: integrity check 2200 failed", _state); + ae_assert(state->sj.m==1+state->cntnlc, "AULRetrieveSJ: integrity check 2300 failed", _state); + ae_assert(xvirt->n==state->n, "AULRetrieveSJ: integrity check 2359 failed", _state); + ae_assert(xvirt->m==1+state->cntnlc, "AULRetrieveSJ: integrity check 1125 failed", _state); + ae_assert(xtrue->n==state->n, "AULRetrieveSJ: integrity check 1126 failed", _state); + ae_assert(xtrue->m==1+state->cntnlc, "AULRetrieveSJ: integrity check 1127 failed", _state); + n = xtrue->n; + m = xtrue->m; + + /* + * Fill true point with the raw data + */ + v = (double)(0); + xtrue->sj.matrixtype = -10080; + xtrue->sj.m = m; + xtrue->sj.n = n; + iallocv(m+1, &xtrue->sj.ridx, _state); + xtrue->sj.ridx.ptr.p_int[0] = 0; + for(i=0; i<=state->cntnlc; i++) + { + + /* + * Function value + */ + vv = (double)1/state->fscales.ptr.p_double[i]; + xtrue->fi.ptr.p_double[i] = vv*state->fi.ptr.p_double[i]; + v = v+xtrue->fi.ptr.p_double[i]; + + /* + * Sparse Jacobian row (slacks are not added) + */ + j0 = state->sj.ridx.ptr.p_int[i]; + j1 = state->sj.ridx.ptr.p_int[i+1]-1; + offs = xtrue->sj.ridx.ptr.p_int[i]; + igrowv(offs+(j1-j0+1), &xtrue->sj.idx, _state); + rgrowv(offs+(j1-j0+1), &xtrue->sj.vals, _state); + for(j=j0; j<=j1; j++) + { + xtrue->sj.idx.ptr.p_int[offs] = state->sj.idx.ptr.p_int[j]; + xtrue->sj.vals.ptr.p_double[offs] = vv*state->sj.vals.ptr.p_double[j]; + v = v+xtrue->sj.vals.ptr.p_double[offs]; + offs = offs+1; + } + + /* + * Done + */ + xtrue->sj.ridx.ptr.p_int[i+1] = offs; + } + result = ae_isfinite(v, _state); + + /* + * Compute function values at the virtual point + */ + rsetallocv(n, 0.0, &state->tmpretrdelta, _state); + allsame = ae_true; + for(i=0; i<=n-1; i++) + { + state->tmpretrdelta.ptr.p_double[i] = xvirt->x.ptr.p_double[i]-xtrue->x.ptr.p_double[i]; + allsame = allsame&&xtrue->x.ptr.p_double[i]==xvirt->x.ptr.p_double[i]; + } + if( allsame ) + { + vfjcopy(xtrue, xvirt, _state); + return result; + } + xvirt->sj.matrixtype = -10080; + xvirt->sj.m = m; + xvirt->sj.n = n; + iallocv(m+1, &xvirt->sj.ridx, _state); + xvirt->sj.ridx.ptr.p_int[0] = 0; + for(i=0; i<=state->cntnlc; i++) + { + j0 = xtrue->sj.ridx.ptr.p_int[i]; + j1 = xtrue->sj.ridx.ptr.p_int[i+1]-1; + + /* + * Function value + */ + xvirt->fi.ptr.p_double[i] = xtrue->fi.ptr.p_double[i]; + for(j=j0; j<=j1; j++) + { + xvirt->fi.ptr.p_double[i] = xvirt->fi.ptr.p_double[i]+xtrue->sj.vals.ptr.p_double[j]*state->tmpretrdelta.ptr.p_double[xtrue->sj.idx.ptr.p_int[j]]; + } + + /* + * Sparse Jacobian row + */ + offs = xvirt->sj.ridx.ptr.p_int[i]; + igrowv(offs+(j1-j0+1), &xvirt->sj.idx, _state); + rgrowv(offs+(j1-j0+1), &xvirt->sj.vals, _state); + for(j=j0; j<=j1; j++) + { + xvirt->sj.idx.ptr.p_int[offs] = xtrue->sj.idx.ptr.p_int[j]; + xvirt->sj.vals.ptr.p_double[offs] = xtrue->sj.vals.ptr.p_double[j]; + offs = offs+1; + } + + /* + * Done + */ + xvirt->sj.ridx.ptr.p_int[i+1] = offs; + } + return result; +} + + +/************************************************************************* +This function calculates target and its gradient, with possibility of +applying additional stabilizing modification which does not change +constrained solution. +*************************************************************************/ +static void nlcaul_modtargetfg(minaulstate* state, + const varsfuncjac* s, + double rhobc, + double rhoxc, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t n; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + *f = 0.0; + + n = state->n; + ae_assert(g->cnt>=n, "AUL: integrity check 5717 failed", _state); + ae_assert(((!s->isdense&&(s->sj.matrixtype==1||s->sj.matrixtype==-10080))&&s->sj.m>=1)&&s->sj.n==n, "AUL: integrity check 5820 failed", _state); + + /* + * Target function + */ + rsetv(n, 0.0, g, _state); + *f = s->fi.ptr.p_double[0]; + j0 = s->sj.ridx.ptr.p_int[0]; + j1 = s->sj.ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[s->sj.idx.ptr.p_int[jj]] = s->sj.vals.ptr.p_double[jj]; + } +} + + +/************************************************************************* +This function calculates augmented (penalized) Lagrangian of the problem +*************************************************************************/ +static void nlcaul_auglagfg(minaulstate* state, + const varsfuncjac* s, + double rho, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double ci; + double v; + double aix; + double fi; + double p; + double dp; + double d2p; + double invrho; + double stabrho; + double rhoci; + + *f = 0.0; + + n = state->n; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + ae_assert(ae_fp_greater(rho,(double)(0)), "AUL: integrity check 1459 failed", _state); + ae_assert(g->cnt>=n, "AUL: integrity check 7517 failed", _state); + ae_assert(((!s->isdense&&(s->sj.matrixtype==1||s->sj.matrixtype==-10080))&&s->sj.m>=1)&&s->sj.n==n, "AUL: integrity check 7720 failed", _state); + ae_assert(state->cntlc==0||((state->sparsea.matrixtype==1&&state->sparsea.m==state->cntlc)&&state->sparsea.n==n), "AUL: integrity check 3528 failed", _state); + invrho = (double)1/rho; + + /* + * Target function + */ + nlcaul_modtargetfg(state, s, rho, rho, f, g, _state); + + /* + * Lagrangian terms for box constraints + */ + for(i=0; i<=n-1; i++) + { + + /* + * Handle equality constraint on a variable + */ + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&state->scaledbndl.ptr.p_double[i]==state->scaledbndu.ptr.p_double[i] ) + { + ci = s->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]; + *f = *f+0.5*rho*ci*ci+lagmultbc2->ptr.p_double[2*i+0]*ci; + g->ptr.p_double[i] = g->ptr.p_double[i]+rho*ci+lagmultbc2->ptr.p_double[2*i+0]; + continue; + } + + /* + * Handle lower bound (inequality or range with non-zero width) + */ + if( state->hasbndl.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((s->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+p*invrho*lagmultbc2->ptr.p_double[2*i+0]; + g->ptr.p_double[i] = g->ptr.p_double[i]+dp*lagmultbc2->ptr.p_double[2*i+0]; + } + + /* + * Handle upper bound (inequality or range with non-zero width) + */ + if( state->hasbndu.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->scaledbndu.ptr.p_double[i]-s->x.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+p*invrho*lagmultbc2->ptr.p_double[2*i+1]; + g->ptr.p_double[i] = g->ptr.p_double[i]-dp*lagmultbc2->ptr.p_double[2*i+1]; + } + } + + /* + * Lagrangian and penalty terms for linear constraints + */ + for(i=0; i<=state->cntlc-1; i++) + { + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + + /* + * Compute constraint value Ai*x + */ + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+s->x.ptr.p_double[state->sparsea.idx.ptr.p_int[jj]]*state->sparsea.vals.ptr.p_double[jj]; + } + + /* + * Handle Lagrangian and penalty terms + */ + if( (state->hasal.ptr.p_bool[i]&&state->hasau.ptr.p_bool[i])&&state->al.ptr.p_double[i]==state->au.ptr.p_double[i] ) + { + + /* + * Equality constraint Ai*x = ALi = AUi + */ + ci = ci-state->al.ptr.p_double[i]; + *f = *f+lagmultxc2->ptr.p_double[2*i+0]*ci+0.5*rho*ci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*i+0]*v+rho*ci*v; + } + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasal.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((ci-state->al.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+lagmultxc2->ptr.p_double[2*i+0]*p*invrho; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*i+0]*dp*v; + } + } + if( state->hasau.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->au.ptr.p_double[i]-ci)*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+lagmultxc2->ptr.p_double[2*i+1]*p*invrho; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-lagmultxc2->ptr.p_double[2*i+1]*dp*v; + } + } + } + } + + /* + * Lagrangian and penalty terms for nonlinear constraints + */ + for(i=0; i<=cntnlc-1; i++) + { + j0 = s->sj.ridx.ptr.p_int[1+i]; + j1 = s->sj.ridx.ptr.p_int[1+i+1]-1; + ci = s->fi.ptr.p_double[1+i]; + + /* + * Handle Lagrangian and penalty terms + */ + if( (state->hasnl.ptr.p_bool[i]&&state->hasnu.ptr.p_bool[i])&&state->rawnl.ptr.p_double[i]==state->rawnu.ptr.p_double[i] ) + { + + /* + * Equality constraint Fi = NLi = NUi + */ + ci = ci-state->rawnl.ptr.p_double[i]; + *f = *f+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*ci+0.5*rho*ci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*v+rho*ci*v; + } + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasnl.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((ci-state->rawnl.ptr.p_double[i])*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*p*invrho; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*dp*v; + } + } + if( state->hasnu.ptr.p_bool[i] ) + { + inequalityshiftedbarrierfunction((state->rawnu.ptr.p_double[i]-ci)*rho+(double)1, &p, &dp, &d2p, _state); + *f = *f+lagmultxc2->ptr.p_double[2*cntlc+2*i+1]*p*invrho; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-lagmultxc2->ptr.p_double[2*cntlc+2*i+1]*dp*v; + } + } + } + } + + /* + * Additional stabilizing penalty term which is inactive within the feasible area + * and close to its boundaries. This term is intended to prevent long steps into + * the infeasible area. + */ + stabrho = nlcaul_stabilizingpoint/rho; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + ci = s->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]+stabrho; + if( ci<0.0 ) + { + rhoci = rho*ci; + *f = *f+0.5*rhoci*ci; + g->ptr.p_double[i] = g->ptr.p_double[i]+rhoci; + } + } + if( state->hasbndu.ptr.p_bool[i] ) + { + ci = state->scaledbndu.ptr.p_double[i]-s->x.ptr.p_double[i]+stabrho; + if( ci<0.0 ) + { + rhoci = rho*ci; + *f = *f+0.5*rhoci*ci; + g->ptr.p_double[i] = g->ptr.p_double[i]-rhoci; + } + } + } + for(i=0; i<=state->cntlc-1; i++) + { + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + aix = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + aix = aix+s->x.ptr.p_double[state->sparsea.idx.ptr.p_int[jj]]*state->sparsea.vals.ptr.p_double[jj]; + } + if( state->hasal.ptr.p_bool[i]&&aix-state->al.ptr.p_double[i]<-stabrho ) + { + ci = aix-state->al.ptr.p_double[i]+stabrho; + *f = *f+0.5*rho*ci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+rho*ci*v; + } + } + if( state->hasau.ptr.p_bool[i]&&state->au.ptr.p_double[i]-aix<-stabrho ) + { + ci = state->au.ptr.p_double[i]-aix+stabrho; + *f = *f+0.5*rho*ci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-rho*ci*v; + } + } + } + for(i=0; i<=state->cntnlc-1; i++) + { + j0 = s->sj.ridx.ptr.p_int[1+i]; + j1 = s->sj.ridx.ptr.p_int[1+i+1]-1; + fi = s->fi.ptr.p_double[1+i]; + if( state->hasnl.ptr.p_bool[i] ) + { + ci = fi-state->rawnl.ptr.p_double[i]+stabrho; + if( ci<0.0 ) + { + rhoci = rho*ci; + *f = *f+0.5*rhoci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+rhoci*v; + } + } + } + if( state->hasnu.ptr.p_bool[i] ) + { + ci = state->rawnu.ptr.p_double[i]-fi+stabrho; + if( ci<0.0 ) + { + rhoci = rho*ci; + *f = *f+0.5*rhoci*ci; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-rhoci*v; + } + } + } + } +} + + +/************************************************************************* +This function calculates raw Lagrangian of the problem +*************************************************************************/ +static void nlcaul_rawlagfg(minaulstate* state, + const varsfuncjac* s, + /* Real */ const ae_vector* lagmultbc2, + /* Real */ const ae_vector* lagmultxc2, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + double fi; + double ci; + double v; + + *f = 0.0; + + n = state->n; + cntlc = state->cntlc; + ae_assert(g->cnt>=n, "AUL: integrity check 7517 failed", _state); + ae_assert(((!s->isdense&&(s->sj.matrixtype==1||s->sj.matrixtype==-10080))&&s->sj.m>=1)&&s->sj.n==n, "AUL: integrity check 7720 failed", _state); + ae_assert(state->cntlc==0||((state->sparsea.matrixtype==1&&state->sparsea.m==state->cntlc)&&state->sparsea.n==n), "AUL: integrity check 3528 failed", _state); + + /* + * Target function + */ + rsetv(n, 0.0, g, _state); + *f = s->fi.ptr.p_double[0]; + j0 = s->sj.ridx.ptr.p_int[0]; + j1 = s->sj.ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + g->ptr.p_double[s->sj.idx.ptr.p_int[jj]] = s->sj.vals.ptr.p_double[jj]; + } + + /* + * Lagrangian terms for box constraints + */ + for(i=0; i<=n-1; i++) + { + + /* + * Handle equality constraint on a variable + */ + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + ci = s->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]; + *f = *f+lagmultbc2->ptr.p_double[2*i+0]*ci; + g->ptr.p_double[i] = g->ptr.p_double[i]+lagmultbc2->ptr.p_double[2*i+0]; + continue; + } + + /* + * Handle lower bound (inequality or range with non-zero width) + */ + if( state->hasbndl.ptr.p_bool[i] ) + { + *f = *f-lagmultbc2->ptr.p_double[2*i+0]*(s->x.ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]); + g->ptr.p_double[i] = g->ptr.p_double[i]-lagmultbc2->ptr.p_double[2*i+0]; + } + + /* + * Handle upper bound (inequality or range with non-zero width) + */ + if( state->hasbndu.ptr.p_bool[i] ) + { + *f = *f-lagmultbc2->ptr.p_double[2*i+1]*(state->scaledbndu.ptr.p_double[i]-s->x.ptr.p_double[i]); + g->ptr.p_double[i] = g->ptr.p_double[i]+lagmultbc2->ptr.p_double[2*i+1]; + } + } + + /* + * Lagrangian and penalty terms for linear constraints + */ + for(i=0; i<=state->cntlc-1; i++) + { + j0 = state->sparsea.ridx.ptr.p_int[i]; + j1 = state->sparsea.ridx.ptr.p_int[i+1]-1; + + /* + * Compute constraint value Ai*x + */ + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+s->x.ptr.p_double[state->sparsea.idx.ptr.p_int[jj]]*state->sparsea.vals.ptr.p_double[jj]; + } + + /* + * Handle Lagrangian and penalty terms + */ + if( (state->hasal.ptr.p_bool[i]&&state->hasau.ptr.p_bool[i])&&ae_fp_eq(state->al.ptr.p_double[i],state->au.ptr.p_double[i]) ) + { + + /* + * Equality constraint Ai*x = ALi = AUi + */ + ci = ci-state->al.ptr.p_double[i]; + *f = *f+lagmultxc2->ptr.p_double[2*i+0]*ci; + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*i+0]*v; + } + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasal.ptr.p_bool[i] ) + { + *f = *f-lagmultxc2->ptr.p_double[2*i+0]*(ci-state->al.ptr.p_double[i]); + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-lagmultxc2->ptr.p_double[2*i+0]*v; + } + } + if( state->hasau.ptr.p_bool[i] ) + { + + /* + * Inequality constraint Ai*x <= AUi + */ + *f = *f-lagmultxc2->ptr.p_double[2*i+1]*(state->au.ptr.p_double[i]-ci); + for(jj=j0; jj<=j1; jj++) + { + j = state->sparsea.idx.ptr.p_int[jj]; + v = state->sparsea.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*i+1]*v; + } + } + } + } + for(i=0; i<=state->cntnlc-1; i++) + { + j0 = s->sj.ridx.ptr.p_int[1+i]; + j1 = s->sj.ridx.ptr.p_int[1+i+1]-1; + fi = s->fi.ptr.p_double[1+i]; + + /* + * Handle Lagrangian and penalty terms + */ + if( (state->hasnl.ptr.p_bool[i]&&state->hasnu.ptr.p_bool[i])&&ae_fp_eq(state->rawnl.ptr.p_double[i],state->rawnu.ptr.p_double[i]) ) + { + + /* + * Equality constraint Fi = NLi = NUi + */ + ci = fi-state->rawnl.ptr.p_double[i]; + *f = *f+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*ci; + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*v; + } + } + else + { + + /* + * Inequality/range constraint + */ + if( state->hasnl.ptr.p_bool[i] ) + { + + /* + * Inequality constraint Ai*x >= ALi + */ + *f = *f-lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*(fi-state->rawnl.ptr.p_double[i]); + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]-lagmultxc2->ptr.p_double[2*cntlc+2*i+0]*v; + } + } + if( state->hasnu.ptr.p_bool[i] ) + { + + /* + * Inequality constraint Ai*x <= AUi + */ + *f = *f-lagmultxc2->ptr.p_double[2*cntlc+2*i+1]*(state->rawnu.ptr.p_double[i]-fi); + for(jj=j0; jj<=j1; jj++) + { + j = s->sj.idx.ptr.p_int[jj]; + v = s->sj.vals.ptr.p_double[jj]; + g->ptr.p_double[j] = g->ptr.p_double[j]+lagmultxc2->ptr.p_double[2*cntlc+2*i+1]*v; + } + } + } + } +} + + +/************************************************************************* +Clears request fileds (to be sure that we didn't forget to clear something) +*************************************************************************/ +static void nlcaul_clearrequestfields(minaulstate* state, + ae_state *_state) +{ + + + state->needsj = ae_false; + state->precrefreshupcoming = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Compute primal/dual/complementary slackness errors +*************************************************************************/ +static void nlcaul_computeerrors(minaulstate* sstate, + const varsfuncjac* s, + double* errprim, + double* errdual, + double* errcmpl, + ae_state *_state) +{ + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + double ci; + double v; + + *errprim = 0.0; + *errdual = 0.0; + *errcmpl = 0.0; + + n = sstate->n; + cntlc = sstate->cntlc; + cntnlc = sstate->cntnlc; + *errprim = 0.0; + for(i=0; i<=n-1; i++) + { + if( sstate->hasbndl.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, sstate->scaledbndl.ptr.p_double[i]-s->x.ptr.p_double[i], _state); + } + if( sstate->hasbndu.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, s->x.ptr.p_double[i]-sstate->scaledbndu.ptr.p_double[i], _state); + } + } + for(i=0; i<=cntlc-1; i++) + { + j0 = sstate->sparsea.ridx.ptr.p_int[i]; + j1 = sstate->sparsea.ridx.ptr.p_int[i+1]-1; + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+s->x.ptr.p_double[sstate->sparsea.idx.ptr.p_int[jj]]*sstate->sparsea.vals.ptr.p_double[jj]; + } + if( sstate->hasal.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, sstate->al.ptr.p_double[i]-ci, _state); + } + if( sstate->hasau.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, ci-sstate->au.ptr.p_double[i], _state); + } + } + for(i=0; i<=cntnlc-1; i++) + { + ci = s->fi.ptr.p_double[1+i]; + if( sstate->hasnl.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, sstate->rawnl.ptr.p_double[i]-ci, _state); + } + if( sstate->hasnu.ptr.p_bool[i] ) + { + *errprim = ae_maxreal(*errprim, ci-sstate->rawnu.ptr.p_double[i], _state); + } + } + rallocv(n, &sstate->tmpg, _state); + nlcaul_rawlagfg(sstate, s, &sstate->lagmultbc2, &sstate->lagmultxc2, &v, &sstate->tmpg, _state); + *errdual = rmaxabsv(n, &sstate->tmpg, _state); + *errcmpl = 0.0; + for(i=0; i<=n-1; i++) + { + if( (sstate->hasbndl.ptr.p_bool[i]&&sstate->hasbndu.ptr.p_bool[i])&&ae_fp_eq(sstate->scaledbndl.ptr.p_double[i],sstate->scaledbndu.ptr.p_double[i]) ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((sstate->scaledbndl.ptr.p_double[i]-s->x.ptr.p_double[i])*sstate->lagmultbc2.ptr.p_double[2*i+0], _state), _state); + continue; + } + if( sstate->hasbndl.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((sstate->scaledbndl.ptr.p_double[i]-s->x.ptr.p_double[i])*sstate->lagmultbc2.ptr.p_double[2*i+0], _state), _state); + } + if( sstate->hasbndu.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((s->x.ptr.p_double[i]-sstate->scaledbndu.ptr.p_double[i])*sstate->lagmultbc2.ptr.p_double[2*i+1], _state), _state); + } + } + for(i=0; i<=cntlc-1; i++) + { + j0 = sstate->sparsea.ridx.ptr.p_int[i]; + j1 = sstate->sparsea.ridx.ptr.p_int[i+1]-1; + ci = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + ci = ci+s->x.ptr.p_double[sstate->sparsea.idx.ptr.p_int[jj]]*sstate->sparsea.vals.ptr.p_double[jj]; + } + if( (sstate->hasal.ptr.p_bool[i]&&sstate->hasau.ptr.p_bool[i])&&ae_fp_eq(sstate->al.ptr.p_double[i],sstate->au.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((ci-sstate->al.ptr.p_double[i])*sstate->lagmultxc2.ptr.p_double[2*i+0], _state), _state); + } + else + { + + /* + * No constraints, inequality constraint or range constraint + */ + if( sstate->hasal.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((sstate->al.ptr.p_double[i]-ci)*sstate->lagmultxc2.ptr.p_double[2*i+0], _state), _state); + } + if( sstate->hasau.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((ci-sstate->au.ptr.p_double[i])*sstate->lagmultxc2.ptr.p_double[2*i+1], _state), _state); + } + } + } + for(i=0; i<=cntnlc-1; i++) + { + ci = s->fi.ptr.p_double[1+i]; + if( (sstate->hasnl.ptr.p_bool[i]&&sstate->hasnu.ptr.p_bool[i])&&ae_fp_eq(sstate->rawnl.ptr.p_double[i],sstate->rawnu.ptr.p_double[i]) ) + { + + /* + * Equality constraint + */ + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((ci-sstate->rawnl.ptr.p_double[i])*sstate->lagmultxc2.ptr.p_double[2*cntlc+2*i+0], _state), _state); + } + else + { + + /* + * No constraints, inequality constraint or range constraint + */ + if( sstate->hasnl.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((sstate->rawnl.ptr.p_double[i]-ci)*sstate->lagmultxc2.ptr.p_double[2*cntlc+2*i+0], _state), _state); + } + if( sstate->hasnu.ptr.p_bool[i] ) + { + *errcmpl = ae_maxreal(*errcmpl, ae_fabs((ci-sstate->rawnu.ptr.p_double[i])*sstate->lagmultxc2.ptr.p_double[2*cntlc+2*i+1], _state), _state); + } + } + } +} + + +void _minaulpreconditioner_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minaulpreconditioner *p = (minaulpreconditioner*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + _sparsematrix_init(&p->augsys, _state, make_automatic); + ae_matrix_init(&p->s, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpcorrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcorrd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->priorities, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->dx, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummys, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummyy, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alphak, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rhok, 0, DT_REAL, _state, make_automatic); +} + + +void _minaulpreconditioner_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minaulpreconditioner *dst = (minaulpreconditioner*)_dst; + const minaulpreconditioner *src = (const minaulpreconditioner*)_src; + dst->refreshfreq = src->refreshfreq; + dst->modelage = src->modelage; + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + _sparsematrix_init_copy(&dst->augsys, &src->augsys, _state, make_automatic); + dst->naug = src->naug; + ae_matrix_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic); + dst->updcnt = src->updcnt; + ae_matrix_init_copy(&dst->tmpcorrc, &src->tmpcorrc, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcorrd, &src->tmpcorrd, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdiag, &src->tmpdiag, _state, make_automatic); + ae_vector_init_copy(&dst->priorities, &src->priorities, _state, make_automatic); + ae_vector_init_copy(&dst->dx, &src->dx, _state, make_automatic); + ae_matrix_init_copy(&dst->dummys, &src->dummys, _state, make_automatic); + ae_matrix_init_copy(&dst->dummyy, &src->dummyy, _state, make_automatic); + ae_vector_init_copy(&dst->alphak, &src->alphak, _state, make_automatic); + ae_vector_init_copy(&dst->rhok, &src->rhok, _state, make_automatic); +} + + +void _minaulpreconditioner_clear(void* _p) +{ + minaulpreconditioner *p = (minaulpreconditioner*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_clear(&p->analysis); + _sparsematrix_clear(&p->augsys); + ae_matrix_clear(&p->s); + ae_matrix_clear(&p->y); + ae_matrix_clear(&p->tmpcorrc); + ae_vector_clear(&p->tmpcorrd); + ae_vector_clear(&p->tmpdiag); + ae_vector_clear(&p->priorities); + ae_vector_clear(&p->dx); + ae_matrix_clear(&p->dummys); + ae_matrix_clear(&p->dummyy); + ae_vector_clear(&p->alphak); + ae_vector_clear(&p->rhok); +} + + +void _minaulpreconditioner_destroy(void* _p) +{ + minaulpreconditioner *p = (minaulpreconditioner*)_p; + ae_touch_ptr((void*)p); + _spcholanalysis_destroy(&p->analysis); + _sparsematrix_destroy(&p->augsys); + ae_matrix_destroy(&p->s); + ae_matrix_destroy(&p->y); + ae_matrix_destroy(&p->tmpcorrc); + ae_vector_destroy(&p->tmpcorrd); + ae_vector_destroy(&p->tmpdiag); + ae_vector_destroy(&p->priorities); + ae_vector_destroy(&p->dx); + ae_matrix_destroy(&p->dummys); + ae_matrix_destroy(&p->dummyy); + ae_vector_destroy(&p->alphak); + ae_vector_destroy(&p->rhok); +} + + +void _minaulstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minaulstate *p = (minaulstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsea, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rawnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasnl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasnu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sj, _state, make_automatic); + _varsfuncjac_init(&p->xvirt, _state, make_automatic); + _varsfuncjac_init(&p->xvirtprev, _state, make_automatic); + _varsfuncjac_init(&p->xvirtbest, _state, make_automatic); + _varsfuncjac_init(&p->xtrue, _state, make_automatic); + _varsfuncjac_init(&p->xtrueprev, _state, make_automatic); + _varsfuncjac_init(&p->xtruebest, _state, make_automatic); + ae_vector_init(&p->lagmultbc2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagmultxc2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->du, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tracegamma, 0, DT_REAL, _state, make_automatic); + _minaulpreconditioner_init(&p->preconditioner, _state, make_automatic); + _xbfgshessian_init(&p->hessaug, _state, make_automatic); + _xbfgshessian_init(&p->hesstgt, _state, make_automatic); + ae_vector_init(&p->laggrad0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laggradcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->modtgtgrad0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->modtgtgrad1, 0, DT_REAL, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); + ae_vector_init(&p->ascales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpzero, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpy, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummy2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpretrdelta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg, 0, DT_REAL, _state, make_automatic); + _varsfuncjac_init(&p->xvirtprobe, _state, make_automatic); + _varsfuncjac_init(&p->xtrueprobe, _state, make_automatic); + ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _minaulstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minaulstate *dst = (minaulstate*)_dst; + const minaulstate *src = (const minaulstate*)_src; + dst->n = src->n; + dst->cntlc = src->cntlc; + dst->cntnlc = src->cntnlc; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsea, &src->sparsea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); + ae_vector_init_copy(&dst->rawnl, &src->rawnl, _state, make_automatic); + ae_vector_init_copy(&dst->rawnu, &src->rawnu, _state, make_automatic); + ae_vector_init_copy(&dst->hasnl, &src->hasnl, _state, make_automatic); + ae_vector_init_copy(&dst->hasnu, &src->hasnu, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->maxouterits = src->maxouterits; + dst->restartfreq = src->restartfreq; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + _sparsematrix_init_copy(&dst->sj, &src->sj, _state, make_automatic); + dst->f = src->f; + dst->needsj = src->needsj; + dst->precrefreshupcoming = src->precrefreshupcoming; + dst->xupdated = src->xupdated; + dst->rho = src->rho; + _varsfuncjac_init_copy(&dst->xvirt, &src->xvirt, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xvirtprev, &src->xvirtprev, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xvirtbest, &src->xvirtbest, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xtrue, &src->xtrue, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xtrueprev, &src->xtrueprev, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xtruebest, &src->xtruebest, _state, make_automatic); + dst->besterr = src->besterr; + dst->bestiteridx = src->bestiteridx; + dst->besterrnegligibleupdates = src->besterrnegligibleupdates; + ae_vector_init_copy(&dst->lagmultbc2, &src->lagmultbc2, _state, make_automatic); + ae_vector_init_copy(&dst->lagmultxc2, &src->lagmultxc2, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->du, &src->du, _state, make_automatic); + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + ae_vector_init_copy(&dst->tracegamma, &src->tracegamma, _state, make_automatic); + _minaulpreconditioner_init_copy(&dst->preconditioner, &src->preconditioner, _state, make_automatic); + _xbfgshessian_init_copy(&dst->hessaug, &src->hessaug, _state, make_automatic); + _xbfgshessian_init_copy(&dst->hesstgt, &src->hesstgt, _state, make_automatic); + ae_vector_init_copy(&dst->laggrad0, &src->laggrad0, _state, make_automatic); + ae_vector_init_copy(&dst->laggradcur, &src->laggradcur, _state, make_automatic); + ae_vector_init_copy(&dst->modtgtgrad0, &src->modtgtgrad0, _state, make_automatic); + ae_vector_init_copy(&dst->modtgtgrad1, &src->modtgtgrad1, _state, make_automatic); + dst->inneriterationscount = src->inneriterationscount; + dst->outeriterationscount = src->outeriterationscount; + dst->fstagnationcnt = src->fstagnationcnt; + dst->longeststp = src->longeststp; + dst->mcstage = src->mcstage; + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->stp = src->stp; + dst->stplimit = src->stplimit; + ae_vector_init_copy(&dst->ascales, &src->ascales, _state, make_automatic); + ae_vector_init_copy(&dst->tmpzero, &src->tmpzero, _state, make_automatic); + ae_vector_init_copy(&dst->tmpy, &src->tmpy, _state, make_automatic); + ae_matrix_init_copy(&dst->dummy2, &src->dummy2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpretrdelta, &src->tmpretrdelta, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xvirtprobe, &src->xvirtprobe, _state, make_automatic); + _varsfuncjac_init_copy(&dst->xtrueprobe, &src->xtrueprobe, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repnfev = src->repnfev; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->nfev = src->nfev; + ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _minaulstate_clear(void* _p) +{ + minaulstate *p = (minaulstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + _sparsematrix_clear(&p->sparsea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); + ae_vector_clear(&p->rawnl); + ae_vector_clear(&p->rawnu); + ae_vector_clear(&p->hasnl); + ae_vector_clear(&p->hasnu); + ae_vector_clear(&p->lcsrcidx); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + _sparsematrix_clear(&p->sj); + _varsfuncjac_clear(&p->xvirt); + _varsfuncjac_clear(&p->xvirtprev); + _varsfuncjac_clear(&p->xvirtbest); + _varsfuncjac_clear(&p->xtrue); + _varsfuncjac_clear(&p->xtrueprev); + _varsfuncjac_clear(&p->xtruebest); + ae_vector_clear(&p->lagmultbc2); + ae_vector_clear(&p->lagmultxc2); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->d); + ae_vector_clear(&p->du); + ae_vector_clear(&p->fscales); + ae_vector_clear(&p->tracegamma); + _minaulpreconditioner_clear(&p->preconditioner); + _xbfgshessian_clear(&p->hessaug); + _xbfgshessian_clear(&p->hesstgt); + ae_vector_clear(&p->laggrad0); + ae_vector_clear(&p->laggradcur); + ae_vector_clear(&p->modtgtgrad0); + ae_vector_clear(&p->modtgtgrad1); + _linminstate_clear(&p->lstate); + ae_vector_clear(&p->ascales); + ae_vector_clear(&p->tmpzero); + ae_vector_clear(&p->tmpy); + ae_matrix_clear(&p->dummy2); + ae_vector_clear(&p->tmpretrdelta); + ae_vector_clear(&p->tmpg); + _varsfuncjac_clear(&p->xvirtprobe); + _varsfuncjac_clear(&p->xtrueprobe); + ae_vector_clear(&p->work); + _rcommstate_clear(&p->rstate); +} + + +void _minaulstate_destroy(void* _p) +{ + minaulstate *p = (minaulstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + _sparsematrix_destroy(&p->sparsea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); + ae_vector_destroy(&p->rawnl); + ae_vector_destroy(&p->rawnu); + ae_vector_destroy(&p->hasnl); + ae_vector_destroy(&p->hasnu); + ae_vector_destroy(&p->lcsrcidx); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + _sparsematrix_destroy(&p->sj); + _varsfuncjac_destroy(&p->xvirt); + _varsfuncjac_destroy(&p->xvirtprev); + _varsfuncjac_destroy(&p->xvirtbest); + _varsfuncjac_destroy(&p->xtrue); + _varsfuncjac_destroy(&p->xtrueprev); + _varsfuncjac_destroy(&p->xtruebest); + ae_vector_destroy(&p->lagmultbc2); + ae_vector_destroy(&p->lagmultxc2); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->du); + ae_vector_destroy(&p->fscales); + ae_vector_destroy(&p->tracegamma); + _minaulpreconditioner_destroy(&p->preconditioner); + _xbfgshessian_destroy(&p->hessaug); + _xbfgshessian_destroy(&p->hesstgt); + ae_vector_destroy(&p->laggrad0); + ae_vector_destroy(&p->laggradcur); + ae_vector_destroy(&p->modtgtgrad0); + ae_vector_destroy(&p->modtgtgrad1); + _linminstate_destroy(&p->lstate); + ae_vector_destroy(&p->ascales); + ae_vector_destroy(&p->tmpzero); + ae_vector_destroy(&p->tmpy); + ae_matrix_destroy(&p->dummy2); + ae_vector_destroy(&p->tmpretrdelta); + ae_vector_destroy(&p->tmpg); + _varsfuncjac_destroy(&p->xvirtprobe); + _varsfuncjac_destroy(&p->xtrueprobe); + ae_vector_destroy(&p->work); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + NONLINEAR CONJUGATE GRADIENT METHOD + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using one of the +nonlinear conjugate gradient methods. + +These CG methods are globally convergent (even on non-convex functions) as +long as grad(f) is Lipschitz continuous in a some neighborhood of the +L = { x : f(x)<=f(x0) }. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinCGCreate() call +2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and + other functions +3. User calls MinCGOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinCGResults() to get solution +5. Optionally, user may call MinCGRestartFrom() to solve another problem + with same N but another starting point and/or another function. + MinCGRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgcreate(ae_int_t n, + /* Real */ const ae_vector* x, + mincgstate* state, + ae_state *_state) +{ + + _mincgstate_clear(state); + + ae_assert(n>=1, "MinCGCreate: N too small!", _state); + ae_assert(x->cnt>=n, "MinCGCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinCGSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. L-BFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgcreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + mincgstate* state, + ae_state *_state) +{ + + _mincgstate_clear(state); + + ae_assert(n>=1, "MinCGCreateF: N too small!", _state); + ae_assert(x->cnt>=n, "MinCGCreateF: Length(X)=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinCGSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcond(mincgstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinCGSetCond: EpsG is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinCGSetCond: negative EpsG!", _state); + ae_assert(ae_isfinite(epsf, _state), "MinCGSetCond: EpsF is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinCGSetCond: negative EpsF!", _state); + ae_assert(ae_isfinite(epsx, _state), "MinCGSetCond: EpsX is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinCGSetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "MinCGSetCond: negative MaxIts!", _state); + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsg = epsg; + state->epsf = epsf; + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets scaling coefficients for CG optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of CG optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the CG too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinCGSetPrec...() functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgsetscale(mincgstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinCGSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinCGSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinCGSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function turns on/off line search reports. +These reports are described in more details in developer-only comments on +MinCGState object. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedDRep- whether line search reports are needed or not + +This function is intended for private use only. Turning it on artificially +may cause program failure. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state) +{ + + + state->drep = needdrep; +} + + +/************************************************************************* +This function sets CG algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + CGType - algorithm type: + * -1 automatic selection of the best algorithm + * 0 DY (Dai and Yuan) algorithm + * 1 Hybrid DY-HS algorithm + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state) +{ + + + ae_assert(cgtype>=-1&&cgtype<=1, "MinCGSetCGType: incorrect CGType!", _state); + if( cgtype==-1 ) + { + cgtype = 1; + } + state->cgtype = cgtype; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinCGSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinCGSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +This function allows to suggest initial step length to the CG algorithm. + +Suggested step length is used as starting point for the line search. It +can be useful when you have badly scaled problem, i.e. when ||grad|| +(which is used as initial estimate for the first step) is many orders of +magnitude different from the desired step. + +Line search may fail on such problems without good estimate of initial +step length. Imagine, for example, problem with ||grad||=10^50 and desired +step equal to 0.1 Line search function will use 10^50 as initial step, +then it will decrease step length by 2 (up to 20 attempts) and will get +10^44, which is still too large. + +This function allows us to tell than line search should be started from +some moderate step length, like 1.0, so algorithm will be able to detect +desired step length in a several searches. + +Default behavior (when no step is suggested) is to use preconditioner, if +it is available, to generate initial estimate of step length. + +This function influences only first iteration of algorithm. It should be +called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. +Suggested step is ignored if you have preconditioner. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + Stp - initial estimate of the step length. + Can be zero (no estimate). + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stp, _state), "MinCGSuggestStep: Stp is infinite or NAN", _state); + ae_assert(ae_fp_greater_eq(stp,(double)(0)), "MinCGSuggestStep: Stp<0", _state); + state->suggestedstep = stp; +} + + +/************************************************************************* +This developer-only function allows to retrieve unscaled (!) length of +last good step (i.e. step which resulted in sufficient decrease of target +function). + +It can be used in for solution of sequential optimization subproblems, +where MinCGSuggestStep() is called with length of previous step as +parameter. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + +RESULT: + length of last good step being accepted + +NOTE: + result of this function is undefined if you called it before + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +double mincglastgoodstep(mincgstate* state, ae_state *_state) +{ + double result; + + + result = state->lastgoodstep; + return result; +} + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdefault(mincgstate* state, ae_state *_state) +{ + + + state->prectype = 0; + state->innerresetneeded = ae_true; +} + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdiag(mincgstate* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(d->cnt>=state->n, "MinCGSetPrecDiag: D is too short", _state); + for(i=0; i<=state->n-1; i++) + { + ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinCGSetPrecDiag: D contains infinite or NAN elements", _state); + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinCGSetPrecDiag: D contains non-positive elements", _state); + } + mincgsetprecdiagfast(state, d, _state); +} + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinCGSetScale() call +(before or after MinCGSetPrecScale() call). Without knowledge of the scale +of your variables scale-based preconditioner will be just unit matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecscale(mincgstate* state, ae_state *_state) +{ + + + state->prectype = 3; + state->innerresetneeded = ae_true; +} + + +/************************************************************************* +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinCGCreate() for analytical gradient or MinCGCreateF() for + numerical differentiation) you should choose appropriate variant of + MinCGOptimize() - one which accepts function AND gradient or one which + accepts function ONLY. + + Be careful to choose variant of MinCGOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinCGOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinCGOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinCGCreateF() | work FAIL + MinCGCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinCGOptimize() version. Attemps to use such combination + (for example, to create optimizer with MinCGCreateF() and to pass + gradient information to MinCGOptimize()) will lead to exception being + thrown. Either you did not pass gradient when it WAS needed or you + passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool mincgiteration(mincgstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double betak; + double v; + double vv; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + betak = state->rstate.ra.ptr.p_double[0]; + v = state->rstate.ra.ptr.p_double[1]; + vv = state->rstate.ra.ptr.p_double[2]; + } + else + { + n = 359; + i = -58; + betak = -919.0; + v = -909.0; + vv = 81.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + + /* + * Routine body + */ + + /* + * Prepare + */ + n = state->n; + state->terminationneeded = ae_false; + state->userterminationneeded = ae_false; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + state->debugrestartscount = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, n, 1, state->smoothnessguardlevel>0, _state); + rvectorsetlengthatleast(&state->invs, n, _state); + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + state->invs.ptr.p_double[i] = (double)1/state->s.ptr.p_double[i]; + } + + /* + * Check, that transferred derivative value is right + */ + mincg_clearrequestfields(state, _state); + if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_18; + } +lbl_20: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xbase, &state->s, &state->s, &state->s, ae_false, state->teststep, _state) ) + { + goto lbl_21; + } + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->smonitor.x.ptr.p_double[i]; + } + state->needfg = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfg = ae_false; + state->smonitor.fi.ptr.p_double[0] = state->f; + for(i=0; i<=n-1; i++) + { + state->smonitor.j.ptr.pp_double[0][i] = state->g.ptr.p_double[i]; + } + goto lbl_20; +lbl_21: +lbl_18: + + /* + * Preparations continue: + * * set XK + * * calculate F/G + * * set DK to -G + * * powerup algo (it may change preconditioner) + * * apply preconditioner to DK + * * report update of X + * * check stopping conditions for G + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->xbase.ptr.p_double[i]; + } + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + mincg_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_22; + } + state->needfg = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfg = ae_false; + goto lbl_23; +lbl_22: + state->needf = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->fbase = state->f; + i = 0; +lbl_24: + if( i>n-1 ) + { + goto lbl_26; + } + v = state->x.ptr.p_double[i]; + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->fp2 = state->f; + state->x.ptr.p_double[i] = v; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + i = i+1; + goto lbl_24; +lbl_26: + state->f = state->fbase; + state->needf = ae_false; +lbl_23: + if( !state->drep ) + { + goto lbl_27; + } + + /* + * Report algorithm powerup (if needed) + */ + mincg_clearrequestfields(state, _state); + state->algpowerup = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->algpowerup = ae_false; +lbl_27: + trimprepare(state->f, &state->trimthreshold, _state); + ae_v_moveneg(&state->dk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + mincg_preconditionedmultiply(state, &state->dk, &state->work0, &state->work1, _state); + if( !state->xrep ) + { + goto lbl_29; + } + mincg_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->xupdated = ae_false; +lbl_29: + if( state->terminationneeded||state->userterminationneeded ) + { + + /* + * Combined termination point for "internal" termination by TerminationNeeded flag + * and for "user" termination by MinCGRequestTermination() (UserTerminationNeeded flag). + * In this location rules for both of methods are same, thus only one exit point is needed. + */ + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + result = ae_false; + return result; + } + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) + { + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 4; + result = ae_false; + return result; + } + state->repnfev = 1; + state->k = 0; + state->fold = state->f; + + /* + * Choose initial step. + * Apply preconditioner, if we have something other than default. + */ + if( state->prectype==2||state->prectype==3 ) + { + + /* + * because we use preconditioner, step length must be equal + * to the norm of DK + */ + v = ae_v_dotproduct(&state->dk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->lastgoodstep = ae_sqrt(v, _state); + } + else + { + + /* + * No preconditioner is used, we try to use suggested step + */ + if( ae_fp_greater(state->suggestedstep,(double)(0)) ) + { + state->lastgoodstep = state->suggestedstep; + } + else + { + state->lastgoodstep = 1.0; + } + } + + /* + * Main cycle + */ + state->rstimer = mincg_rscountdownlen; +lbl_31: + if( ae_false ) + { + goto lbl_32; + } + + /* + * * clear reset flag + * * clear termination flag + * * store G[k] for later calculation of Y[k] + * * prepare starting point and direction and step length for line search + */ + state->innerresetneeded = ae_false; + state->terminationneeded = ae_false; + ae_v_moveneg(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->mcstage = 0; + state->stp = 1.0; + linminnormalized(&state->d, &state->stp, n, _state); + if( ae_fp_neq(state->lastgoodstep,(double)(0)) ) + { + state->stp = state->lastgoodstep; + } + state->curstpmax = state->stpmax; + + /* + * Report beginning of line search (if needed) + * Terminate algorithm, if user request was detected + */ + if( !state->drep ) + { + goto lbl_33; + } + mincg_clearrequestfields(state, _state); + state->lsstart = ae_true; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->lsstart = ae_false; +lbl_33: + if( state->terminationneeded ) + { + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + result = ae_false; + return result; + } + + /* + * Minimization along D + */ + smoothnessmonitorstartlinesearch1u(&state->smonitor, &state->s, &state->invs, &state->x, state->f, &state->g, state->repiterationscount, -1, _state); + mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); +lbl_35: + if( state->mcstage==0 ) + { + goto lbl_36; + } + + /* + * Calculate function/gradient using either + * analytical gradient supplied by user + * or finite difference approximation. + * + * "Trim" function in order to handle near-singularity points. + */ + mincg_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_37; + } + state->needfg = ae_true; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->needfg = ae_false; + goto lbl_38; +lbl_37: + state->needf = ae_true; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->fbase = state->f; + i = 0; +lbl_39: + if( i>n-1 ) + { + goto lbl_41; + } + v = state->x.ptr.p_double[i]; + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->fp2 = state->f; + state->x.ptr.p_double[i] = v; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + i = i+1; + goto lbl_39; +lbl_41: + state->f = state->fbase; + state->needf = ae_false; +lbl_38: + smoothnessmonitorenqueuepoint1u(&state->smonitor, &state->s, &state->invs, &state->d, state->stp, &state->x, state->f, &state->g, _state); + trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); + + /* + * Call MCSRCH again + */ + mcsrch(n, &state->x, &state->f, &state->g, &state->d, &state->stp, state->curstpmax, mincg_gtol, &state->mcinfo, &state->nfev, &state->work0, &state->lstate, &state->mcstage, _state); + goto lbl_35; +lbl_36: + smoothnessmonitorfinalizelinesearch(&state->smonitor, _state); + + /* + * * terminate algorithm if "user" request for detected + * * report end of line search + * * store current point to XN + * * report iteration + * * terminate algorithm if "internal" request was detected + */ + if( state->userterminationneeded ) + { + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->drep ) + { + goto lbl_42; + } + + /* + * Report end of line search (if needed) + */ + mincg_clearrequestfields(state, _state); + state->lsend = ae_true; + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + state->lsend = ae_false; +lbl_42: + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( !state->xrep ) + { + goto lbl_44; + } + mincg_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->xupdated = ae_false; +lbl_44: + if( state->terminationneeded ) + { + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repterminationtype = 8; + result = ae_false; + return result; + } + + /* + * Line search is finished. + * * calculate BetaK + * * calculate DN + * * update timers + * * calculate step length: + * * LastScaledStep is ALWAYS calculated because it is used in the stopping criteria + * * LastGoodStep is updated only when MCINFO is equal to 1 (Wolfe conditions hold). + * See below for more explanation. + */ + if( state->mcinfo==1&&!state->innerresetneeded ) + { + + /* + * Standard Wolfe conditions hold + * Calculate Y[K] and D[K]'*Y[K] + */ + ae_v_add(&state->yk.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Calculate BetaK according to DY formula + */ + v = mincg_preconditionedmultiply2(state, &state->g, &state->g, &state->work0, &state->work1, _state); + state->betady = v/vv; + + /* + * Calculate BetaK according to HS formula + */ + v = mincg_preconditionedmultiply2(state, &state->g, &state->yk, &state->work0, &state->work1, _state); + state->betahs = v/vv; + + /* + * Choose BetaK + */ + if( state->cgtype==0 ) + { + betak = state->betady; + } + if( state->cgtype==1 ) + { + betak = ae_maxreal((double)(0), ae_minreal(state->betady, state->betahs, _state), _state); + } + } + else + { + + /* + * Something is wrong (may be function is too wild or too flat) + * or we just have to restart algo. + * + * We'll set BetaK=0, which will restart CG algorithm. + * We can stop later (during normal checks) if stopping conditions are met. + */ + betak = (double)(0); + state->debugrestartscount = state->debugrestartscount+1; + } + if( state->repiterationscount>0&&state->repiterationscount%(3+n)==0 ) + { + + /* + * clear Beta every N iterations + */ + betak = (double)(0); + } + if( state->mcinfo==1||state->mcinfo==5 ) + { + state->rstimer = mincg_rscountdownlen; + } + else + { + state->rstimer = state->rstimer-1; + } + ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + mincg_preconditionedmultiply(state, &state->dn, &state->work0, &state->work1, _state); + ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); + state->lastscaledstep = 0.0; + for(i=0; i<=n-1; i++) + { + state->lastscaledstep = state->lastscaledstep+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + state->lastscaledstep = state->stp*ae_sqrt(state->lastscaledstep, _state); + if( state->mcinfo==1 ) + { + + /* + * Step is good (Wolfe conditions hold), update LastGoodStep. + * + * This check for MCINFO=1 is essential because sometimes in the + * constrained optimization setting we may take very short steps + * (like 1E-15) because we were very close to boundary of the + * feasible area. Such short step does not mean that we've converged + * to the solution - it was so short because we were close to the + * boundary and there was a limit on step length. + * + * So having such short step is quite normal situation. However, we + * should NOT start next iteration from step whose initial length is + * estimated as 1E-15 because it may lead to the failure of the + * linear minimizer (step is too short, function does not changes, + * line search stagnates). + */ + state->lastgoodstep = (double)(0); + for(i=0; i<=n-1; i++) + { + state->lastgoodstep = state->lastgoodstep+ae_sqr(state->d.ptr.p_double[i], _state); + } + state->lastgoodstep = state->stp*ae_sqrt(state->lastgoodstep, _state); + } + + /* + * Update information. + * Check stopping conditions. + */ + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->g.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( !ae_isfinite(v, _state)||!ae_isfinite(state->f, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + state->repnfev = state->repnfev+state->nfev; + state->repiterationscount = state->repiterationscount+1; + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + + /* + * Too many iterations + */ + state->repterminationtype = 5; + result = ae_false; + return result; + } + if( ae_fp_less_eq(ae_sqrt(v, _state),state->epsg) ) + { + + /* + * Gradient is small enough + */ + state->repterminationtype = 4; + result = ae_false; + return result; + } + if( !state->innerresetneeded ) + { + + /* + * These conditions are checked only when no inner reset was requested by user + */ + if( ae_fp_less_eq(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) + { + + /* + * F(k+1)-F(k) is small enough + */ + state->repterminationtype = 1; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->lastscaledstep,state->epsx) ) + { + + /* + * X(k+1)-X(k) is small enough + */ + state->repterminationtype = 2; + result = ae_false; + return result; + } + } + if( state->rstimer<=0 ) + { + + /* + * Too many subsequent restarts + */ + state->repterminationtype = 7; + result = ae_false; + return result; + } + + /* + * Shift Xk/Dk, update other information + */ + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fold = state->f; + state->k = state->k+1; + goto lbl_31; +lbl_32: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ra.ptr.p_double[0] = betak; + state->rstate.ra.ptr.p_double[1] = v; + state->rstate.ra.ptr.p_double[2] = vv; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with mincgoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with mincgsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardgradient(mincgstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinCGOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinCGOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardsmoothness(mincgstate* state, + ae_int_t level, + ae_state *_state) +{ + + + ae_assert(level==0||level==1, "MinCGOptGuardSmoothness: unexpected value of level parameter", _state); + state->smoothnessguardlevel = level; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* mincgoptguardgradient() for gradient verification +* mincgoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* mincgoptguardnonc1test0results() +* mincgoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardresults(mincgstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test0results(const mincgstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test0report_clear(strrep); + _optguardnonc1test0report_clear(lngrep); + + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test1results(mincgstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test1report_clear(strrep); + _optguardnonc1test1report_clear(lngrep); + + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Conjugate gradient results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -7 gradient verification failed. + See MinCGSetGradientCheck() for more information. + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible, + we return best X found so far + * 8 terminated by user + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresults(const mincgstate* state, + /* Real */ ae_vector* x, + mincgreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _mincgreport_clear(rep); + + mincgresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +Conjugate gradient results + +Buffered implementation of MinCGResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresultsbuf(const mincgstate* state, + /* Real */ ae_vector* x, + mincgreport* rep, + ae_state *_state) +{ + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nfev = state->repnfev; + rep->terminationtype = state->repterminationtype; +} + + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgrestartfrom(mincgstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "MinCGRestartFrom: Length(X)n, _state), "MinCGCreate: X contains infinite or NaN values!", _state); + ae_v_move(&state->xbase.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + mincgsuggeststep(state, 0.0, _state); + ae_vector_set_length(&state->rstate.ia, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + mincg_clearrequestfields(state, _state); +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgrequesttermination(mincgstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Faster version of MinCGSetPrecDiag(), for time-critical parts of code, +without safety checks. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdiagfast(mincgstate* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + rvectorsetlengthatleast(&state->diagh, state->n, _state); + rvectorsetlengthatleast(&state->diaghl2, state->n, _state); + state->prectype = 2; + state->vcnt = 0; + state->innerresetneeded = ae_true; + for(i=0; i<=state->n-1; i++) + { + state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; + state->diaghl2.ptr.p_double[i] = 0.0; + } +} + + +/************************************************************************* +This function sets low-rank preconditioner for Hessian matrix H=D+V'*C*V, +where: +* H is a Hessian matrix, which is approximated by D/V/C +* D=D1+D2 is a diagonal matrix, which includes two positive definite terms: + * constant term D1 (is not updated or infrequently updated) + * variable term D2 (can be cheaply updated from iteration to iteration) +* V is a low-rank correction +* C is a diagonal factor of low-rank correction + +Preconditioner P is calculated using approximate Woodburry formula: + P = D^(-1) - D^(-1)*V'*(C^(-1)+V*D1^(-1)*V')^(-1)*V*D^(-1) + = D^(-1) - D^(-1)*VC'*VC*D^(-1), +where + VC = sqrt(B)*V + B = (C^(-1)+V*D1^(-1)*V')^(-1) + +Note that B is calculated using constant term (D1) only, which allows us +to update D2 without recalculation of B or VC. Such preconditioner is +exact when D2 is zero. When D2 is non-zero, it is only approximation, but +very good and cheap one. + +This function accepts D1, V, C. +D2 is set to zero by default. + +Cost of this update is O(N*VCnt*VCnt), but D2 can be updated in just O(N) +by MinCGSetPrecVarPart. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetpreclowrankfast(mincgstate* state, + /* Real */ const ae_vector* d1, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* v, + ae_int_t vcnt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t n; + double t; + ae_matrix b; + + ae_frame_make(_state, &_frame_block); + memset(&b, 0, sizeof(b)); + ae_matrix_init(&b, 0, 0, DT_REAL, _state, ae_true); + + if( vcnt==0 ) + { + mincgsetprecdiagfast(state, d1, _state); + ae_frame_leave(_state); + return; + } + n = state->n; + ae_matrix_set_length(&b, vcnt, vcnt, _state); + rvectorsetlengthatleast(&state->diagh, n, _state); + rvectorsetlengthatleast(&state->diaghl2, n, _state); + rmatrixsetlengthatleast(&state->vcorr, vcnt, n, _state); + state->prectype = 2; + state->vcnt = vcnt; + state->innerresetneeded = ae_true; + for(i=0; i<=n-1; i++) + { + state->diagh.ptr.p_double[i] = d1->ptr.p_double[i]; + state->diaghl2.ptr.p_double[i] = 0.0; + } + for(i=0; i<=vcnt-1; i++) + { + for(j=i; j<=vcnt-1; j++) + { + t = (double)(0); + for(k=0; k<=n-1; k++) + { + t = t+v->ptr.pp_double[i][k]*v->ptr.pp_double[j][k]/d1->ptr.p_double[k]; + } + b.ptr.pp_double[i][j] = t; + } + b.ptr.pp_double[i][i] = b.ptr.pp_double[i][i]+1.0/c->ptr.p_double[i]; + } + if( !spdmatrixcholeskyrec(&b, 0, vcnt, ae_true, &state->work0, _state) ) + { + state->vcnt = 0; + ae_frame_leave(_state); + return; + } + for(i=0; i<=vcnt-1; i++) + { + ae_v_move(&state->vcorr.ptr.pp_double[i][0], 1, &v->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + for(j=0; j<=i-1; j++) + { + t = b.ptr.pp_double[j][i]; + ae_v_subd(&state->vcorr.ptr.pp_double[i][0], 1, &state->vcorr.ptr.pp_double[j][0], 1, ae_v_len(0,n-1), t); + } + t = (double)1/b.ptr.pp_double[i][i]; + ae_v_muld(&state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), t); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function updates variable part (diagonal matrix D2) +of low-rank preconditioner. + +This update is very cheap and takes just O(N) time. + +It has no effect with default preconditioner. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecvarpart(mincgstate* state, + /* Real */ const ae_vector* d2, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + state->diaghl2.ptr.p_double[i] = d2->ptr.p_double[i]; + } +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void mincgsetprotocolv1(mincgstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void mincg_clearrequestfields(mincgstate* state, ae_state *_state) +{ + + + state->needf = ae_false; + state->needfg = ae_false; + state->xupdated = ae_false; + state->lsstart = ae_false; + state->lsend = ae_false; + state->algpowerup = ae_false; +} + + +/************************************************************************* +This function calculates preconditioned product H^(-1)*x and stores result +back into X. Work0[] and Work1[] are used as temporaries (size must be at +least N; this function doesn't allocate arrays). + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +static void mincg_preconditionedmultiply(mincgstate* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* work0, + /* Real */ ae_vector* work1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t vcnt; + double v; + + + n = state->n; + vcnt = state->vcnt; + if( state->prectype==0 ) + { + return; + } + if( state->prectype==3 ) + { + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]; + } + return; + } + ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); + + /* + * handle part common for VCnt=0 and VCnt<>0 + */ + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); + } + + /* + * if VCnt>0 + */ + if( vcnt>0 ) + { + for(i=0; i<=vcnt-1; i++) + { + v = ae_v_dotproduct(&state->vcorr.ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + work0->ptr.p_double[i] = v; + } + for(i=0; i<=n-1; i++) + { + work1->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=vcnt-1; i++) + { + v = work0->ptr.p_double[i]; + ae_v_addd(&state->work1.ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]-state->work1.ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); + } + } +} + + +/************************************************************************* +This function calculates preconditioned product x'*H^(-1)*y. Work0[] and +Work1[] are used as temporaries (size must be at least N; this function +doesn't allocate arrays). + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +static double mincg_preconditionedmultiply2(mincgstate* state, + /* Real */ ae_vector* x, + /* Real */ ae_vector* y, + /* Real */ ae_vector* work0, + /* Real */ ae_vector* work1, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t vcnt; + double v0; + double v1; + double result; + + + n = state->n; + vcnt = state->vcnt; + + /* + * no preconditioning + */ + if( state->prectype==0 ) + { + v0 = ae_v_dotproduct(&x->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1)); + result = v0; + return result; + } + if( state->prectype==3 ) + { + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[i]*state->s.ptr.p_double[i]*state->s.ptr.p_double[i]*y->ptr.p_double[i]; + } + return result; + } + ae_assert(state->prectype==2, "MinCG: internal error (unexpected PrecType)", _state); + + /* + * low rank preconditioning + */ + result = 0.0; + for(i=0; i<=n-1; i++) + { + result = result+x->ptr.p_double[i]*y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); + } + if( vcnt>0 ) + { + for(i=0; i<=n-1; i++) + { + work0->ptr.p_double[i] = x->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); + work1->ptr.p_double[i] = y->ptr.p_double[i]/(state->diagh.ptr.p_double[i]+state->diaghl2.ptr.p_double[i]); + } + for(i=0; i<=vcnt-1; i++) + { + v0 = ae_v_dotproduct(&work0->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + v1 = ae_v_dotproduct(&work1->ptr.p_double[0], 1, &state->vcorr.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + result = result-v0*v1; + } + } + return result; +} + + +/************************************************************************* +Internal initialization subroutine + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +static void mincg_mincginitinternal(ae_int_t n, + double diffstep, + mincgstate* state, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * Initialize + */ + state->protocolversion = 1; + state->teststep = (double)(0); + state->smoothnessguardlevel = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + state->n = n; + state->diffstep = diffstep; + state->lastgoodstep = (double)(0); + mincgsetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); + mincgsetxrep(state, ae_false, _state); + mincgsetdrep(state, ae_false, _state); + mincgsetstpmax(state, (double)(0), _state); + mincgsetcgtype(state, -1, _state); + mincgsetprecdefault(state, _state); + ae_vector_set_length(&state->xk, n, _state); + ae_vector_set_length(&state->dk, n, _state); + ae_vector_set_length(&state->xn, n, _state); + ae_vector_set_length(&state->dn, n, _state); + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->d, n, _state); + ae_vector_set_length(&state->g, n, _state); + ae_vector_set_length(&state->work0, n, _state); + ae_vector_set_length(&state->work1, n, _state); + ae_vector_set_length(&state->yk, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->invs, n, _state); + ae_vector_set_length(&state->lastscaleused, n, _state); + rvectorsetlengthatleast(&state->xbase, n, _state); + for(i=0; i<=n-1; i++) + { + state->s.ptr.p_double[i] = 1.0; + state->invs.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + } +} + + +void _mincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mincgstate *p = (mincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diaghl2, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->vcorr, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); + ae_vector_init(&p->work0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->work1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invs, 0, DT_REAL, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); +} + + +void _mincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mincgstate *dst = (mincgstate*)_dst; + const mincgstate *src = (const mincgstate*)_src; + dst->n = src->n; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->stpmax = src->stpmax; + dst->suggestedstep = src->suggestedstep; + dst->xrep = src->xrep; + dst->drep = src->drep; + dst->cgtype = src->cgtype; + dst->prectype = src->prectype; + ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic); + ae_vector_init_copy(&dst->diaghl2, &src->diaghl2, _state, make_automatic); + ae_matrix_init_copy(&dst->vcorr, &src->vcorr, _state, make_automatic); + dst->vcnt = src->vcnt; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->diffstep = src->diffstep; + dst->nfev = src->nfev; + dst->mcstage = src->mcstage; + dst->k = src->k; + ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic); + ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->fold = src->fold; + dst->stp = src->stp; + dst->curstpmax = src->curstpmax; + ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic); + dst->lastgoodstep = src->lastgoodstep; + dst->lastscaledstep = src->lastscaledstep; + dst->mcinfo = src->mcinfo; + dst->innerresetneeded = src->innerresetneeded; + dst->terminationneeded = src->terminationneeded; + dst->trimthreshold = src->trimthreshold; + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + dst->rstimer = src->rstimer; + dst->protocolversion = src->protocolversion; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->xupdated = src->xupdated; + dst->algpowerup = src->algpowerup; + dst->lsstart = src->lsstart; + dst->lsend = src->lsend; + dst->userterminationneeded = src->userterminationneeded; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + dst->debugrestartscount = src->debugrestartscount; + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->fbase = src->fbase; + dst->fm2 = src->fm2; + dst->fm1 = src->fm1; + dst->fp1 = src->fp1; + dst->fp2 = src->fp2; + dst->betahs = src->betahs; + dst->betady = src->betady; + ae_vector_init_copy(&dst->work0, &src->work0, _state, make_automatic); + ae_vector_init_copy(&dst->work1, &src->work1, _state, make_automatic); + ae_vector_init_copy(&dst->invs, &src->invs, _state, make_automatic); + dst->teststep = src->teststep; + dst->smoothnessguardlevel = src->smoothnessguardlevel; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); +} + + +void _mincgstate_clear(void* _p) +{ + mincgstate *p = (mincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->diagh); + ae_vector_clear(&p->diaghl2); + ae_matrix_clear(&p->vcorr); + ae_vector_clear(&p->s); + ae_vector_clear(&p->xk); + ae_vector_clear(&p->dk); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->dn); + ae_vector_clear(&p->d); + ae_vector_clear(&p->yk); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + _rcommstate_clear(&p->rstate); + _linminstate_clear(&p->lstate); + ae_vector_clear(&p->work0); + ae_vector_clear(&p->work1); + ae_vector_clear(&p->invs); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); +} + + +void _mincgstate_destroy(void* _p) +{ + mincgstate *p = (mincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->diagh); + ae_vector_destroy(&p->diaghl2); + ae_matrix_destroy(&p->vcorr); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->xk); + ae_vector_destroy(&p->dk); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->dn); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->yk); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + _rcommstate_destroy(&p->rstate); + _linminstate_destroy(&p->lstate); + ae_vector_destroy(&p->work0); + ae_vector_destroy(&p->work1); + ae_vector_destroy(&p->invs); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); +} + + +void _mincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mincgreport *p = (mincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mincgreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mincgreport *dst = (mincgreport*)_dst; + const mincgreport *src = (const mincgreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; +} + + +void _mincgreport_clear(void* _p) +{ + mincgreport *p = (mincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mincgreport_destroy(void* _p) +{ + mincgreport *p = (mincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initialize derivative-free general model-based solver (DFGM) + +IMPORTANT: the solver does NOT support fixed variables. The caller has to + preprocess the problem in order to drop all fixed vars. +*************************************************************************/ +void dfgminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + ae_int_t m, + ae_bool isls, + ae_int_t modeltype, + const nlpstoppingcriteria* criteria, + ae_int_t nnoisyrestarts, + double rad0, + ae_int_t maxfev, + dfgmstate* state, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * General initialization + */ + ae_assert(isls||m==1, "DFGM: M<>1 for a non-least-squares problem", _state); + state->n = n; + state->m = m; + state->isleastsquares = isls; + state->cntlc = 0; + state->cntnlc = 0; + state->rad0 = coalesce(rad0, 0.1, _state); + state->nnoisyrestarts = nnoisyrestarts; + + /* + * Model type + */ + ae_assert((modeltype==0||modeltype==1)||modeltype==2, "DFGM: unexpected model type, check 0316 failed", _state); + ae_assert(modeltype!=0||isls, "DFGM: ModelType=0 is possible only with least squares problems", _state); + ae_assert(modeltype!=1||isls, "DFGM: ModelType=1 is possible only with least squares problems", _state); + ae_assert(modeltype!=2||!isls, "DFGM: ModelType=2 is possible only with non-least squares problems", _state); + state->modeltype = modeltype; + + /* + * + */ + ae_assert((modeltype==0||modeltype==1)||modeltype==2, "DFGM: unexpected model type, check 256748 failed", _state); + + /* + * Stopping criteria + */ + state->epsx = critgetepswithdefault(criteria, 0.000001, _state); + state->epsf = critgetepsf(criteria, _state); + state->maxits = critgetmaxits(criteria, _state); + state->maxfev = maxfev; + state->toosmalltrustrad = coalesce(0.001*state->epsx, ae_machineepsilon, _state); + + /* + * Prepare scaled problem + */ + rallocv(n, &state->x0, _state); + rallocv(n, &state->s, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rvectorsetlengthatleast(&state->scaledbndl, n, _state); + rvectorsetlengthatleast(&state->scaledbndu, n, _state); + rsetallocv(n, -1.0E50, &state->finitebndl, _state); + rsetallocv(n, 1.0E50, &state->finitebndu, _state); + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->scaledbndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitebndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->scaledbndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitebndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "DFGM: integrity check 6007 failed, box constraints with no interior point", _state); + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + enforceboundaryconstraints(&state->x0, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + + /* + * Internal RNG + */ + hqrndseed(117564, 983549, &state->rs, _state); + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + state->repsubsolverits = 0; + + /* + * Model-specific initialization + */ + ae_assert((modeltype==0||modeltype==1)||modeltype==2, "DFGM: unexpected model type, check 302739 failed", _state); + + /* + * Trace status + */ + ae_assert((modeltype==0||modeltype==1)||modeltype==2, "DFGM: unexpected model type, check 0317 failed", _state); + state->dotrace = ae_false; + if( modeltype==0 ) + { + state->dotrace = ae_is_trace_enabled("2PS"); + } + if( modeltype==1 ) + { + state->dotrace = ae_is_trace_enabled("DFOLSA"); + } + if( modeltype==2 ) + { + state->dotrace = ae_is_trace_enabled("ORBIT"); + } + state->dotrace = state->dotrace||ae_is_trace_enabled("DFGM"); + + /* + * RComm + */ + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 7+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Sets linear constraints. Supported only for ModelType=2 +*************************************************************************/ +void dfgmsetlc2(dfgmstate* state, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + ae_state *_state) +{ + + + ae_assert(state->modeltype==2, "DFGMSetLC2: only modelType=2 is supported", _state); + ae_assert(m>=0, "DFGMSetLC2: M<0", _state); + ae_assert(m==0||(c->m==m&&c->n==state->n), "DFGMSetLC2: matrix size does not match problem statement", _state); + state->cntlc = m; + if( m==0 ) + { + return; + } + sparsecopytocrsbuf(c, &state->c, _state); + rcopyallocv(m, cl, &state->cl, _state); + rcopyallocv(m, cu, &state->cu, _state); + rsetallocv(state->n, 0.0, &state->tmp0, _state); + scaleshiftsparselcinplace(&state->s, &state->tmp0, state->n, &state->c, m, &state->cl, &state->cu, _state); + normalizesparselcinplace(&state->c, m, &state->cl, &state->cu, state->n, ae_true, &state->tmp0, ae_false, _state); +} + + +/************************************************************************* +Sets nonlinear constraints. Supported only for ModelType=2 +*************************************************************************/ +void dfgmsetnlc2(dfgmstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t m, + ae_state *_state) +{ + + + ae_assert(state->modeltype==2, "DFGMSetNLC2: only modelType=2 is supported", _state); + ae_assert(m>=0, "DFGMSetNLC2: M<0", _state); + state->cntnlc = m; + if( m==0 ) + { + return; + } + rcopyallocv(m, nl, &state->nl, _state); + rcopyallocv(m, nu, &state->nu, _state); +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool dfgmiteration(dfgmstate* state, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t m; + ae_int_t cntnlc; + double predf; + double predh; + double fnew; + double hnew; + double skrellen; + double v; + double v1; + double vv; + ae_bool accepted; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + j = state->rstate.ia.ptr.p_int[1]; + n = state->rstate.ia.ptr.p_int[2]; + m = state->rstate.ia.ptr.p_int[3]; + cntnlc = state->rstate.ia.ptr.p_int[4]; + accepted = state->rstate.ba.ptr.p_bool[0]; + predf = state->rstate.ra.ptr.p_double[0]; + predh = state->rstate.ra.ptr.p_double[1]; + fnew = state->rstate.ra.ptr.p_double[2]; + hnew = state->rstate.ra.ptr.p_double[3]; + skrellen = state->rstate.ra.ptr.p_double[4]; + v = state->rstate.ra.ptr.p_double[5]; + v1 = state->rstate.ra.ptr.p_double[6]; + vv = state->rstate.ra.ptr.p_double[7]; + } + else + { + i = 359; + j = -58; + n = -919; + m = -909; + cntnlc = 81; + accepted = ae_true; + predf = 74.0; + predh = -788.0; + fnew = 809.0; + hnew = 205.0; + skrellen = -838.0; + v = 939.0; + v1 = -526.0; + vv = 763.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + cntnlc = state->cntnlc; + if( state->dotrace ) + { + ae_trace("> derivative-free model-based solver started\n"); + if( state->modeltype==0 ) + { + ae_trace("algorithm = 2PS\n"); + } + if( state->modeltype==1 ) + { + ae_trace("algorithm = DFO-LSA\n"); + } + } + + /* + * Initialization phase + * + * NOTE: TrustRadFactor is initialized by zero prior to calling UpdateTrustRegion() + * because this function expects some initial value to be present here. + */ + dfgenmod_initcloud(state, state->modeltype==2, _state); + rcopyallocv(n, &state->x0, &state->xk, _state); + state->requesttype = 4; + state->querysize = 1; + rcopyallocv(n, &state->xk, &state->querydata, _state); + rallocv(m+cntnlc, &state->replyfi, _state); + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( !isfinitevector(&state->replyfi, (m+cntnlc)*state->querysize, _state) ) + { + + /* + * Critical failure - the target is infinite from the very beginning + */ + if( state->dotrace ) + { + ae_trace("[ERROR] target at the initial point is infinite, stopping due to the critical failure\n"); + } + state->infinitiesencountered = ae_true; + state->recoveredfrominfinities = ae_false; + state->repterminationtype = -8; + result = ae_false; + return result; + } + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + rcopyallocv(m+cntnlc, &state->replyfi, &state->fkvec, _state); + if( state->isleastsquares ) + { + state->fk = 0.5*rdotv2(m, &state->fkvec, _state); + } + else + { + ae_assert(m==1, "DFGM: integrity check 458634 failed", _state); + state->fk = state->fkvec.ptr.p_double[0]; + } + state->hk = (double)(0); + if( state->cntlc>0 ) + { + rallocv(n, &state->tmp0, _state); + rcopyv(n, &state->xk, &state->tmp0, _state); + sparsemv(&state->c, &state->tmp0, &state->tmp1, _state); + for(i=0; i<=state->cntlc-1; i++) + { + if( ae_isfinite(state->cl.ptr.p_double[i], _state) ) + { + state->hk = state->hk+ae_maxreal(state->cl.ptr.p_double[i]-state->tmp1.ptr.p_double[i], 0.0, _state); + } + if( ae_isfinite(state->cu.ptr.p_double[i], _state) ) + { + state->hk = state->hk+ae_maxreal(state->tmp1.ptr.p_double[i]-state->cu.ptr.p_double[i], 0.0, _state); + } + } + } + for(i=0; i<=cntnlc-1; i++) + { + if( ae_isfinite(state->nl.ptr.p_double[i], _state) ) + { + state->hk = state->hk+ae_maxreal(state->nl.ptr.p_double[i]-state->fkvec.ptr.p_double[m+i], 0.0, _state); + } + if( ae_isfinite(state->nu.ptr.p_double[i], _state) ) + { + state->hk = state->hk+ae_maxreal(state->fkvec.ptr.p_double[m+i]-state->nu.ptr.p_double[i], 0.0, _state); + } + } + rallocv(n, &state->xp, _state); + rallocv(m+cntnlc, &state->fpvec, _state); + rallocv(n, &state->sk, _state); + rallocv(n, &state->xn, _state); + rallocv(m+cntnlc, &state->fnvec, _state); + state->infinitiesencountered = ae_false; + state->recoveredfrominfinities = ae_true; + dfgenmod_inithistory(state, _state); + state->trustradfactor = (double)(0); + dfgenmod_updatetrustregion(state, state->rad0, _state); + state->trustradbnd = state->trustradfactor; + state->wrksetsize = 0; + nlpfinit((double)10*ae_maxreal((double)(10), state->hk, _state), &state->filter, _state); + state->filter.gammaf = 0.001; + if( ae_fp_greater(state->hk,(double)(0)) ) + { + nlpfappend(&state->filter, state->fk, state->hk, _state); + } + + /* + * Start iterations + */ +lbl_8: + if( ae_false ) + { + goto lbl_9; + } + + /* + * The working set is empty. It may happen during either the very first iteration of the solver, + * or after the restart. Generate new working set from scratch, compute FkVec, Fk, Hk. + */ + if( state->wrksetsize!=0 ) + { + goto lbl_10; + } + ae_vector_set_length(&state->rstateimprove.ia, 13+1, _state); + ae_vector_set_length(&state->rstateimprove.ba, 0+1, _state); + ae_vector_set_length(&state->rstateimprove.ra, 12+1, _state); + state->rstateimprove.stage = -1; +lbl_12: + if( !dfgenmod_improveworkingsetgeometry(state, _state) ) + { + goto lbl_13; + } + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + goto lbl_12; +lbl_13: + ae_assert(state->repterminationtype<=0, "DFGM: integrity check 4524 failed", _state); + if( state->repterminationtype<0 ) + { + goto lbl_9; + } + ae_assert(state->wrksetsize>0, "DFGM: integrity check 0227 failed", _state); +lbl_10: + + /* + * Update history of changes in the trust radius and the Jacobian + */ + dfgenmod_updatehistory(state, _state); + + /* + * Report current point + */ + state->requesttype = -1; + rcopyallocv(n, &state->xk, &state->reportx, _state); + state->reportf = state->fk; + if( state->isleastsquares ) + { + state->reportf = (double)2*state->reportf; + } + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + + /* + * Check stopping criteria + */ + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + if( state->dotrace ) + { + ae_trace("> stopping condition triggered: maximum number of iterations\n"); + } + state->repterminationtype = 5; + goto lbl_9; + } + if( state->maxfev>0&&state->repnfev>=state->maxfev ) + { + if( state->dotrace ) + { + ae_trace("> stopping condition triggered: maximum number of function evaluations\n"); + } + state->repterminationtype = 5; + goto lbl_9; + } + if( ae_fp_less_eq(state->trustradbnd,ae_maxreal(state->epsx, state->toosmalltrustrad, _state)) ) + { + + /* + * Trust radius decreased: either perform a restart or stop + */ + if( state->restartstoperform>0 ) + { + dfgenmod_updatetrustregion(state, state->rad0, _state); + state->trustradbnd = state->trustradfactor; + state->wrksetsize = 0; + dfgenmod_clearhistoryonrestart(state, _state); + state->restartstoperform = state->restartstoperform-1; + if( state->dotrace ) + { + ae_trace("> restart is performed due to a small trust region size (%0d restarts left)\n", + (int)(state->restartstoperform)); + } + goto lbl_8; + } + if( ae_fp_less_eq(state->trustradbnd,state->epsx) ) + { + if( state->dotrace ) + { + ae_trace("> stopping condition triggered: step less than EpsX\n"); + } + state->repterminationtype = 2; + } + else + { + if( state->dotrace ) + { + ae_trace("> stopping condition triggered: step is too small, emergency termination\n"); + } + state->repterminationtype = 7; + } + goto lbl_9; + } + v = (double)(0); + for(i=0; i<=state->successhistorylen-1; i++) + { + v = v+state->successhistory.ptr.p_double[i]; + } + if( state->successhistorylen==state->successhistorymax&&ae_fp_less_eq(ae_fabs(v, _state),state->epsf*rmaxabs2(state->fk, (double)(1), _state)) ) + { + if( state->dotrace ) + { + ae_trace("> stopping condition triggered: total progress over last N+1 successful its is less than EpsF\n"); + } + state->repterminationtype = 1; + goto lbl_9; + } + if( userterminationneeded ) + { + if( state->dotrace ) + { + ae_trace("> user requested immediate termination\n"); + } + state->repterminationtype = 8; + goto lbl_9; + } + + /* + * Trace output (if needed) + */ + if( state->dotrace ) + { + ae_trace("\n=== ITERATION %5d STARTED ========================================================================\n", + (int)(state->repiterationscount)); + ae_trace("DeltaK = %0.3e (current trust radius factor)\n", + (double)(state->trustradfactor)); + ae_trace("RhoK = %0.3e (lower bound on the trust radius)\n", + (double)(state->trustradbnd)); + ae_trace("|x|inf = %0.3e\n", + (double)(rmaxabsv(n, &state->xk, _state))); + ae_trace("> stopping criteria:\n"); + v = (double)(0); + for(i=0; i<=state->successhistorylen-1; i++) + { + v = v+state->successhistory.ptr.p_double[i]; + } + ae_trace("sum delta_F = %10.2e (sum of function decreases over last N+1 successful its)\n", + (double)(v)); + ae_trace("> computational budget used:\n"); + ae_trace("eval = %7d (target/constraints evaluations)\n", + (int)(state->repnfev)); + ae_trace("splx.equiv = %9.1f (simplex gradient equivalent = evaluations/(N+1) )\n", + (double)((double)state->repnfev/(double)(n+1))); + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + dfgenmod_mostandleastdistant(&state->invtrustregion, n, &state->wrkset, state->wrksetsize, &v, &i, &vv, &j, _state); + ae_trace("> working set geometry:\n"); + ae_trace("furthest pt = %6.2f (distance to furthest point divided by DeltaK)\n", + (double)(v)); + ae_trace("nearest pt = %6.2f (distance to nearest point divided by DeltaK)\n", + (double)(vv)); + if( state->nnoisyrestarts>0 ) + { + ae_trace("> restart autodetection parameters:\n"); + if( state->historylen>=dfgenmod_minhistory ) + { + linregline(&state->iteridxhistory, &state->jacdiffhistory, state->historylen, &v, &v1, &vv, _state); + ae_trace("slope = %6.2f (slope of log(J[i+1]-J[i]) vs iteration index regression line)\n", + (double)(v1)); + ae_trace("correlation = %6.2f (corr of log(J[i+1]-J[i]) vs iteration index regression line)\n", + (double)(vv)); + v = (double)(0); + v1 = (double)(0); + vv = (double)(0); + for(i=0; i<=state->historylen-1; i++) + { + if( ae_fp_greater(state->trustradhistory.ptr.p_double[i],(double)(0)) ) + { + v = v+(double)1; + } + if( ae_fp_less(state->trustradhistory.ptr.p_double[i],(double)(0)) ) + { + v1 = v1+(double)1; + } + if( ae_fp_eq(state->trustradhistory.ptr.p_double[i],(double)(0)) ) + { + vv = vv+(double)1; + } + } + ae_trace("tr-increase = %3d (steps with increased trust radius)\n", + (int)(ae_round(v, _state))); + ae_trace("tr-decrease = %3d (steps with decreased trust radius)\n", + (int)(ae_round(v1, _state))); + ae_trace("tr-stagnate = %3d (steps with stagnated trust radius)\n", + (int)(ae_round(vv, _state))); + } + else + { + ae_trace(">> accumulating history...\n"); + } + } + ae_trace("\n"); + } + + /* + * Generate trial request, invoke safety phase if necessary + */ + dfgenmod_preparetrialrequest(state, &predf, &predh, _state); + skrellen = dfgenmod_normrelativetotrustregion(state, &state->sk, _state); + if( state->dotrace ) + { + ae_trace("> prepared trial step with relative length |Sk|/DeltaK=%0.1e, predicted deltaF=%0.1e, deltaH=%0.1e\n", + (double)(skrellen), + (double)(predf-state->fk), + (double)(predh-state->hk)); + } + if( ae_fp_greater(skrellen*state->trustradfactor,dfgenmod_gammasafety*state->trustradbnd) ) + { + goto lbl_14; + } + + /* + * Decrease trust region size and send step denial signal + */ + if( state->dotrace ) + { + ae_trace("> proposed step is too short, decreasing trust region radius\n"); + } + dfgenmod_updatetrustregion(state, ae_maxreal(dfgenmod_omegasafety*state->trustradfactor, state->trustradbnd, _state), _state); + if( dfgenmod_deltakatminimum(state, _state) ) + { + v = state->trustradbnd; + dfgenmod_updatetrustregion(state, dfgenmod_alpha2*v, _state); + state->trustradbnd = dfgenmod_alpha1*v; + } + dfgenmod_sendstepdenialtomodel(state, _state); + + /* + * Improve geometry of the dataset + */ + if( state->dotrace ) + { + ae_trace("> improving geometry of the working set\n"); + } + ae_vector_set_length(&state->rstateimprove.ia, 13+1, _state); + ae_vector_set_length(&state->rstateimprove.ba, 0+1, _state); + ae_vector_set_length(&state->rstateimprove.ra, 12+1, _state); + state->rstateimprove.stage = -1; +lbl_16: + if( !dfgenmod_improveworkingsetgeometry(state, _state) ) + { + goto lbl_17; + } + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + goto lbl_16; +lbl_17: + if( state->repterminationtype!=0 ) + { + goto lbl_9; + } + + /* + * Done + */ + inc(&state->repiterationscount, _state); + goto lbl_8; +lbl_14: + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + if( !isfinitevector(&state->replyfi, (m+cntnlc)*state->querysize, _state) ) + { + + /* + * Infinities in the target/constraints, decrease trust radius and retry + */ + if( state->dotrace ) + { + ae_trace("[WARNING] target at the trial point is infinite, decreasing trust radius and restarting iteration\n"); + } + state->infinitiesencountered = ae_true; + state->recoveredfrominfinities = ae_false; + dfgenmod_updatetrustregion(state, dfgenmod_gammabad*state->trustradfactor, _state); + state->trustradbnd = ae_minreal(state->trustradfactor, state->trustradbnd, _state); + dfgenmod_sendstepdenialtomodel(state, _state); + inc(&state->repiterationscount, _state); + goto lbl_8; + } + dfgenmod_processtrialrequest(state, &fnew, &hnew, _state); + if( state->dotrace ) + { + ae_trace("> evaluating target at Xk+Sk, actual deltaF=%0.1e, deltaH=%0.1e\n", + (double)(fnew-state->fk), + (double)(hnew-state->hk)); + } + + /* + * Accept or deny trial step + */ + accepted = dfgenmod_testacceptancebyfilter(state, state->fk, state->hk, predf, predh, fnew, hnew, _state); + if( !accepted ) + { + goto lbl_18; + } + + /* + * Move to the new point + * Update trust radius and filter + */ + if( state->dotrace ) + { + ae_trace("> trial step is accepted by the filter\n"); + if( !state->recoveredfrominfinities ) + { + ae_trace("> successfully recovered from the previous encounter with infinities/NANs in the target!\n"); + } + ae_trace("targetF: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(state->fk), + (double)(fnew), + (double)(fnew-state->fk)); + ae_trace("targetH: %17.9e -> %17.9e (delta=%11.3e; constraints violation)\n", + (double)(state->hk), + (double)(hnew), + (double)(hnew-state->hk)); + } + if( ae_fp_less(predf,state->fk) ) + { + + /* + * f-step is predicted, increase/tighten trust radius depending on the objective behavior + */ + if( ae_fp_greater((state->fk-fnew)/(state->fk-predf),dfgenmod_eta2) ) + { + if( state->dotrace ) + { + ae_trace("> f-step was predicted, model quality is good, increasing trust radius\n"); + } + dfgenmod_updatetrustregion(state, ae_minreal(dfgenmod_gammainc*state->trustradfactor, dfgenmod_gammainc2*(skrellen*state->trustradfactor), _state), _state); + } + else + { + if( state->dotrace ) + { + ae_trace("> f-step was predicted, model quality is low, tightening trust radius\n"); + } + v = ae_maxreal(dfgenmod_gammadec, dfgenmod_gammadec2*skrellen, _state)*state->trustradfactor; + if( ae_fp_less(v,1.5*state->trustradbnd) ) + { + v = state->trustradbnd; + } + dfgenmod_updatetrustregion(state, v, _state); + } + } + else + { + + /* + * h-step is predicted, increase/tighten trust radius depending on the constraint violation behavior + */ + if( ae_fp_less(predh,state->hk)&&ae_fp_greater((state->hk-hnew)/(state->hk-predh),dfgenmod_eta2) ) + { + if( state->dotrace ) + { + ae_trace("> h-step was predicted, constraint linearization quality is good, increasing trust radius\n"); + } + dfgenmod_updatetrustregion(state, ae_minreal(dfgenmod_gammainc*state->trustradfactor, dfgenmod_gammainc2*(skrellen*state->trustradfactor), _state), _state); + } + else + { + if( state->dotrace ) + { + ae_trace("> h-step was predicted, constraint linearization quality is low, tightening trust radius\n"); + } + v = ae_maxreal(dfgenmod_gammadec, dfgenmod_gammadec2*skrellen, _state)*state->trustradfactor; + if( ae_fp_less(v,1.5*state->trustradbnd) ) + { + v = state->trustradbnd; + } + dfgenmod_updatetrustregion(state, v, _state); + } + } + dfgenmod_sendstepacceptancetomodel(state, state->fk, state->hk, fnew, hnew, _state); + rcopyv(n, &state->xk, &state->xp, _state); + rcopyv(m+state->cntnlc, &state->fkvec, &state->fpvec, _state); + state->fp = state->fk; + state->hp = state->hk; + rcopyv(n, &state->xn, &state->xk, _state); + rcopyv(m+state->cntnlc, &state->fnvec, &state->fkvec, _state); + state->fk = fnew; + state->hk = hnew; + state->recoveredfrominfinities = ae_true; + + /* + * Perform step and update working set and model, with possible generation of RComm requests in the process + */ + if( state->dotrace ) + { + ae_trace("> updating working set\n"); + } + ae_vector_set_length(&state->rstateupdate.ia, 7+1, _state); + ae_vector_set_length(&state->rstateupdate.ra, 4+1, _state); + state->rstateupdate.stage = -1; +lbl_20: + if( !dfgenmod_updateworkingsetandmodel(state, &state->xp, &state->xn, &state->fnvec, fnew, hnew, ae_true, _state) ) + { + goto lbl_21; + } + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + goto lbl_20; +lbl_21: + if( state->repterminationtype!=0 ) + { + goto lbl_9; + } + goto lbl_19; +lbl_18: + + /* + * Decrease trust radius, send step denial signal + */ + if( state->dotrace ) + { + ae_trace("> trial step is not accepted by the filter, decreasing trust radius\n"); + } + v = ae_minreal(dfgenmod_gammadec, dfgenmod_gammadec2*skrellen, _state)*state->trustradfactor; + if( ae_fp_less(v,1.5*state->trustradbnd) ) + { + v = state->trustradbnd; + } + dfgenmod_updatetrustregion(state, v, _state); + dfgenmod_sendstepdenialtomodel(state, _state); + + /* + * Update working set and model in order to reuse new information as much as possible. + * Move center to the best point in the working set, as suggested by DFO-LSA authors. + */ + if( state->dotrace ) + { + ae_trace("> updating working set\n"); + } + ae_vector_set_length(&state->rstateupdate.ia, 7+1, _state); + ae_vector_set_length(&state->rstateupdate.ra, 4+1, _state); + state->rstateupdate.stage = -1; +lbl_22: + if( !dfgenmod_updateworkingsetandmodel(state, &state->xk, &state->xn, &state->fnvec, fnew, hnew, ae_false, _state) ) + { + goto lbl_23; + } + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + goto lbl_22; +lbl_23: + if( state->repterminationtype!=0 ) + { + goto lbl_9; + } + + /* + * Handle denial + */ + if( !(dfgenmod_restartautodetected(state, _state)&&state->restartstoperform>0) ) + { + goto lbl_24; + } + + /* + * Step not accepted, the situation suggests restart + */ + if( state->dotrace ) + { + ae_trace("> \n"); + } + dfgenmod_updatetrustregion(state, state->rad0, _state); + state->trustradbnd = state->trustradfactor; + state->wrksetsize = 0; + dfgenmod_clearhistoryonrestart(state, _state); + state->restartstoperform = state->restartstoperform-1; + if( state->dotrace ) + { + ae_trace("> restart is performed due to an autodetection code signal (%0d restarts left)\n", + (int)(state->restartstoperform)); + } + goto lbl_25; +lbl_24: + if( !dfgenmod_workingsetneedsimprovement(state, _state) ) + { + goto lbl_26; + } + + /* + * Step not accepted, working set geometry needs improvement + */ + if( state->dotrace ) + { + ae_trace("> working set needs improvement\n"); + } + ae_vector_set_length(&state->rstateimprove.ia, 13+1, _state); + ae_vector_set_length(&state->rstateimprove.ba, 0+1, _state); + ae_vector_set_length(&state->rstateimprove.ra, 12+1, _state); + state->rstateimprove.stage = -1; +lbl_28: + if( !dfgenmod_improveworkingsetgeometry(state, _state) ) + { + goto lbl_29; + } + if( state->requesttype==4 ) + { + state->repnfev = state->repnfev+state->querysize; + } + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + goto lbl_28; +lbl_29: + if( state->repterminationtype!=0 ) + { + goto lbl_9; + } + goto lbl_27; +lbl_26: + + /* + * Unsuccessful phase: step not accepted, restart not suggested, working set geometry does not need improvement + */ + if( dfgenmod_deltakatminimum(state, _state) ) + { + if( state->dotrace ) + { + ae_trace("> trust radius at the lower bound, decreasing the bound\n"); + } + v = state->trustradbnd; + dfgenmod_updatetrustregion(state, dfgenmod_alpha2*v, _state); + state->trustradbnd = dfgenmod_alpha1*v; + } +lbl_27: +lbl_25: +lbl_19: + + /* + * Update counters + */ + inc(&state->repiterationscount, _state); + goto lbl_8; +lbl_9: + + /* + * Finalize + */ + ae_assert(state->repterminationtype!=0, "DFGM: integrity check 0808 failed", _state); + if( state->repterminationtype<0 ) + { + result = ae_false; + return result; + } + if( state->infinitiesencountered ) + { + if( !state->recoveredfrominfinities ) + { + if( state->dotrace ) + { + ae_trace("> optimizer failed to recover from infinities, declaring unsuccessful termination\n"); + } + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( state->dotrace ) + { + ae_trace("> optimizer encountered infinities, but successfully recovered from them, adding +800 to the completion code\n"); + } + state->repterminationtype = state->repterminationtype+800; + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = j; + state->rstate.ia.ptr.p_int[2] = n; + state->rstate.ia.ptr.p_int[3] = m; + state->rstate.ia.ptr.p_int[4] = cntnlc; + state->rstate.ba.ptr.p_bool[0] = accepted; + state->rstate.ra.ptr.p_double[0] = predf; + state->rstate.ra.ptr.p_double[1] = predh; + state->rstate.ra.ptr.p_double[2] = fnew; + state->rstate.ra.ptr.p_double[3] = hnew; + state->rstate.ra.ptr.p_double[4] = skrellen; + state->rstate.ra.ptr.p_double[5] = v; + state->rstate.ra.ptr.p_double[6] = v1; + state->rstate.ra.ptr.p_double[7] = vv; + return result; +} + + +void linregline(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + double* a, + double* b, + double* corrxy, + ae_state *_state) +{ + ae_int_t i; + double ss; + double sx; + double sxx; + double sy; + double stt; + double e1; + double e2; + double t; + double varx; + double vary; + double meanx; + double meany; + + *a = 0.0; + *b = 0.0; + *corrxy = 0.0; + + ae_assert(n>=2, "DFGM: integrity check 6541 failed", _state); + + /* + * Calculate S, SX, SY, SXX + */ + ss = (double)(0); + sx = (double)(0); + sy = (double)(0); + sxx = (double)(0); + for(i=0; i<=n-1; i++) + { + ss = ss+(double)1; + sx = sx+x->ptr.p_double[i]; + sy = sy+y->ptr.p_double[i]; + sxx = sxx+ae_sqr(x->ptr.p_double[i], _state); + } + + /* + * Test for condition number + */ + t = ae_sqrt((double)4*ae_sqr(sx, _state)+ae_sqr(ss-sxx, _state), _state); + e1 = 0.5*(ss+sxx+t); + e2 = 0.5*(ss+sxx-t); + ae_assert(ae_fp_greater(ae_minreal(e1, e2, _state),(double)1000*ae_machineepsilon*ae_maxreal(e1, e2, _state)), "DFGM: integrity check 6702 failed", _state); + + /* + * Calculate A, B + */ + *a = (double)(0); + *b = (double)(0); + stt = (double)(0); + for(i=0; i<=n-1; i++) + { + t = x->ptr.p_double[i]-sx/ss; + *b = *b+t*y->ptr.p_double[i]; + stt = stt+ae_sqr(t, _state); + } + *b = *b/stt; + *a = (sy-sx*(*b))/ss; + + /* + * Calculate other parameters + */ + meanx = sx/(double)n; + meany = sy/(double)n; + varx = (double)(0); + vary = (double)(0); + *corrxy = (double)(0); + for(i=0; i<=n-1; i++) + { + varx = varx+(x->ptr.p_double[i]-meanx)*(x->ptr.p_double[i]-meanx); + vary = vary+(y->ptr.p_double[i]-meany)*(y->ptr.p_double[i]-meany); + *corrxy = *corrxy+(x->ptr.p_double[i]-meanx)*(y->ptr.p_double[i]-meany); + } + *corrxy = *corrxy/ae_sqrt(coalesce(varx*vary, (double)(1), _state), _state); +} + + +/************************************************************************* +Initialize the following histories: +* a history of changes in the trust radius and the Jacobian. If NNoisyRestarts + is zero from the very beginning, this history is not tracked. +* a history of changes in the objective, which is used to track + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_inithistory(dfgmstate* state, ae_state *_state) +{ + + + state->restartstoperform = state->nnoisyrestarts; + state->historylen = 0; + state->historynext = 0; + state->lasttrustrad = (double)(0); + if( state->nnoisyrestarts>0 ) + { + rsetallocm(state->m+state->cntnlc, state->n, 0.0, &state->lastjac, _state); + rallocv(dfgenmod_maxhistory, &state->trustradhistory, _state); + rallocv(dfgenmod_maxhistory, &state->jacdiffhistory, _state); + rallocv(dfgenmod_maxhistory, &state->iteridxhistory, _state); + } + + /* + * Successful iterations history + */ + state->successhistorymax = ae_maxint(state->n+1, 5, _state); + state->successhistorylen = 0; + state->successhistorynext = 0; + rsetallocv(state->successhistorymax, ae_sqrt(ae_maxrealnumber, _state), &state->successhistory, _state); +} + + +/************************************************************************* +Updates history + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_updatehistory(dfgmstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntnlc; + ae_int_t i; + ae_bool b; + double jacdiff2; + + + n = state->n; + m = state->m; + cntnlc = state->cntnlc; + if( state->nnoisyrestarts==0 ) + { + return; + } + + /* + * Enqueue trust radius change + */ + state->trustradhistory.ptr.p_double[state->historynext] = (double)(0); + if( ae_fp_less(state->trustradfactor,0.999*state->lasttrustrad) ) + { + state->trustradhistory.ptr.p_double[state->historynext] = (double)(-1); + } + if( ae_fp_greater(state->trustradfactor,1.001*state->lasttrustrad) ) + { + state->trustradhistory.ptr.p_double[state->historynext] = (double)(1); + } + state->lasttrustrad = state->trustradfactor; + + /* + * Compute difference in Jacobians, enqueue + */ + rallocv(n, &state->tmp0, _state); + jacdiff2 = (double)(0); + b = ae_false; + if( state->modeltype==0 ) + { + for(i=0; i<=m+cntnlc-1; i++) + { + rcopyrv(n, &state->tpsmodel.jac, i, &state->tmp0, _state); + raddrv(n, -1.0, &state->lastjac, i, &state->tmp0, _state); + jacdiff2 = jacdiff2+rdotv2(n, &state->tmp0, _state); + } + rcopym(m+cntnlc, n, &state->tpsmodel.jac, &state->lastjac, _state); + b = ae_true; + } + if( state->modeltype==1 ) + { + for(i=0; i<=m+cntnlc-1; i++) + { + rcopyrv(n, &state->lsamodel.jac, i, &state->tmp0, _state); + raddrv(n, -1.0, &state->lastjac, i, &state->tmp0, _state); + jacdiff2 = jacdiff2+rdotv2(n, &state->tmp0, _state); + } + rcopym(m+cntnlc, n, &state->lsamodel.jac, &state->lastjac, _state); + b = ae_true; + } + ae_assert(b, "DFGM: integrity check 5451 failed", _state); + state->jacdiffhistory.ptr.p_double[state->historynext] = ae_log(coalesce(jacdiff2, ae_machineepsilon*ae_machineepsilon, _state), _state); + + /* + * Enqueue iterations count + */ + state->iteridxhistory.ptr.p_double[state->historynext] = (double)(state->repiterationscount); + + /* + * Update history size + */ + state->historylen = ae_minint(state->historylen+1, dfgenmod_maxhistory, _state); + state->historynext = (state->historynext+1)%dfgenmod_maxhistory; +} + + +/************************************************************************* +Clear history on restart + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_clearhistoryonrestart(dfgmstate* state, + ae_state *_state) +{ + + + state->historylen = 0; + state->historynext = 0; + state->successhistorylen = 0; + state->successhistorynext = 0; + rsetallocv(state->successhistorymax, ae_sqrt(ae_maxrealnumber, _state), &state->successhistory, _state); + dfgenmod_clearcloud(state, _state); +} + + +/************************************************************************* +Compute per-variable trust region using trust region factor and a current +location State.Xk + +The trust region is stored to State.TrustRegion[], which is array[N], can +be automatically allocated by this function. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_updatetrustregion(dfgmstate* state, + double trustradfactor, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + state->trustradfactor = trustradfactor; + rallocv(n, &state->trustregion, _state); + rallocv(n, &state->invtrustregion, _state); + for(i=0; i<=n-1; i++) + { + ae_assert(ae_fp_less(state->finitebndl.ptr.p_double[i],state->finitebndu.ptr.p_double[i]), "DFGM: integrity check 4230 failed", _state); + state->trustregion.ptr.p_double[i] = trustradfactor*ae_minreal(1.0, state->finitebndu.ptr.p_double[i]-state->finitebndl.ptr.p_double[i], _state); + state->invtrustregion.ptr.p_double[i] = (double)1/state->trustregion.ptr.p_double[i]; + } +} + + +/************************************************************************* +Returns max(|x[i]|/State.TrustRegion[I]) + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static double dfgenmod_normrelativetotrustregion(const dfgmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + double result; + + + n = state->n; + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = ae_maxreal(result, ae_fabs(x->ptr.p_double[i]/state->trustregion.ptr.p_double[i], _state), _state); + } + return result; +} + + +/************************************************************************* +Prepares trial step Sk, Xn=Xk+Sk (guarded against box constraints), loads +RComm V2 request to RequestType, QuerySize, QueryData and preallocates +ReplyFi. + +Returns predicted value of F (target) and sum of constraints violations H + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_preparetrialrequest(dfgmstate* state, + double* predf, + double* predh, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t nnz; + ae_int_t ipmterminationtype; + ae_int_t i; + ae_int_t j; + ae_int_t nx; + + *predf = 0.0; + *predh = 0.0; + + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + *predf = (double)(0); + *predh = (double)(0); + + /* + * 2PS + */ + if( state->modeltype==0 ) + { + ae_assert(cntlc==0, "DFGM: integrity check 4429 failed", _state); + ae_assert(cntnlc==0, "DFGM: integrity check 4430 failed", _state); + ae_assert(state->isleastsquares, "DFGM: integrity check 4431 failed", _state); + + /* + * Generate trial step + */ + rsetallocv(n, 0.0, &state->tmp0, _state); + vipminitdense(&state->ipmsolver, &state->trustregion, &state->tmp0, n, ae_true, _state); + vipmsetquadraticlinear(&state->ipmsolver, &state->tpsmodel.q, &state->sparsedummy, 0, ae_true, &state->tpsmodel.g, _state); + rallocv(n, &state->tmp1, _state); + for(i=0; i<=n-1; i++) + { + state->tmp0.ptr.p_double[i] = -state->trustregion.ptr.p_double[i]; + state->tmp1.ptr.p_double[i] = state->trustregion.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i]-state->xk.ptr.p_double[i],state->tmp0.ptr.p_double[i]) ) + { + state->tmp0.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]-state->xk.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i]-state->xk.ptr.p_double[i],state->tmp1.ptr.p_double[i]) ) + { + state->tmp1.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]-state->xk.ptr.p_double[i]; + } + } + vipmsetconstraints(&state->ipmsolver, &state->tmp0, &state->tmp1, &state->sparsedummy, 0, &state->densedummy, 0, &state->tmp0, &state->tmp1, _state); + vipmoptimize(&state->ipmsolver, ae_false, &state->tmp0, &state->tmp1, &state->tmp2, &ipmterminationtype, _state); + ae_assert(ipmterminationtype>0, "DFGM: integrity check 7740 failed", _state); + rcopyv(n, &state->tmp0, &state->sk, _state); + rcopyv(n, &state->xk, &state->xn, _state); + raddv(n, 1.0, &state->sk, &state->xn, _state); + enforceboundaryconstraints(&state->xn, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + + /* + * Predicted value of target and constraints + */ + ae_assert(cntlc==0, "DFGM: integrity check 9544 failed", _state); + ae_assert(cntnlc==0, "DFGM: integrity check 9545 failed", _state); + rallocv(n, &state->tmp0, _state); + rgemv(n, n, 1.0, &state->tpsmodel.q, 0, &state->sk, 0.0, &state->tmp0, _state); + *predf = state->fk+rdotv(n, &state->sk, &state->tpsmodel.g, _state)+0.5*rdotv(n, &state->sk, &state->tmp0, _state); + *predh = (double)(0); + + /* + * Issue RComm V2 request + */ + state->requesttype = 4; + state->querysize = 1; + rcopyallocv(n, &state->xn, &state->querydata, _state); + rallocv(m+cntnlc, &state->replyfi, _state); + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + + /* + * Done + */ + return; + } + + /* + * DFO-LSA + */ + if( state->modeltype==1 ) + { + ae_assert(cntlc==0, "DFGM: integrity check 2539 failed", _state); + ae_assert(cntnlc==0, "DFGM: integrity check 2639 failed", _state); + ae_assert(state->isleastsquares, "DFGM: integrity check 2739 failed", _state); + + /* + * Generate trial step + */ + rsetallocv(n, 0.0, &state->tmp0, _state); + vipminitdense(&state->ipmsolver, &state->trustregion, &state->tmp0, n, ae_true, _state); + vipmsetquadraticlinear(&state->ipmsolver, &state->lsamodel.q, &state->sparsedummy, 0, ae_true, &state->lsamodel.g, _state); + rallocv(n, &state->tmp1, _state); + for(i=0; i<=n-1; i++) + { + state->tmp0.ptr.p_double[i] = -state->trustregion.ptr.p_double[i]; + state->tmp1.ptr.p_double[i] = state->trustregion.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i]-state->xk.ptr.p_double[i],state->tmp0.ptr.p_double[i]) ) + { + state->tmp0.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]-state->xk.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i]-state->xk.ptr.p_double[i],state->tmp1.ptr.p_double[i]) ) + { + state->tmp1.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]-state->xk.ptr.p_double[i]; + } + } + vipmsetconstraints(&state->ipmsolver, &state->tmp0, &state->tmp1, &state->sparsedummy, 0, &state->densedummy, 0, &state->tmp0, &state->tmp1, _state); + vipmoptimize(&state->ipmsolver, ae_false, &state->tmp0, &state->tmp1, &state->tmp2, &ipmterminationtype, _state); + ae_assert(ipmterminationtype>0, "DFGM: integrity check 7740 failed", _state); + rcopyv(n, &state->tmp0, &state->sk, _state); + rcopyv(n, &state->xk, &state->xn, _state); + raddv(n, 1.0, &state->sk, &state->xn, _state); + enforceboundaryconstraints(&state->xn, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + + /* + * Predicted value of target and constraints + */ + ae_assert(cntlc==0, "DFGM: integrity check 9544 failed", _state); + ae_assert(cntnlc==0, "DFGM: integrity check 9545 failed", _state); + rallocv(n, &state->tmp0, _state); + rgemv(n, n, 1.0, &state->lsamodel.q, 0, &state->sk, 0.0, &state->tmp0, _state); + *predf = state->fk+rdotv(n, &state->sk, &state->lsamodel.g, _state)+0.5*rdotv(n, &state->sk, &state->tmp0, _state); + *predh = (double)(0); + + /* + * Issue RComm V2 request + */ + state->requesttype = 4; + state->querysize = 1; + rcopyallocv(n, &state->xn, &state->querydata, _state); + rallocv(m+cntnlc, &state->replyfi, _state); + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + + /* + * Done + */ + return; + } + + /* + * ORBIT + */ + if( state->modeltype==2 ) + { + dfgenmod_rbfinitializemodelfromworkingset(state, _state); + critinitdefault(&state->rbfmodel.crit, _state); + critsetcondv1(&state->rbfmodel.crit, 0.0, dfgenmod_rbfsubsolverepsx, 0, _state); + nx = n+2*cntlc+2*cntnlc; + rallocv(nx, &state->rbfmodel.tmpbndl, _state); + rallocv(nx, &state->rbfmodel.tmpbndu, _state); + rallocv(nx, &state->rbfmodel.tmpx0, _state); + rallocv(nx, &state->rbfmodel.tmps, _state); + for(i=0; i<=n-1; i++) + { + state->rbfmodel.tmpbndl.ptr.p_double[i] = state->xk.ptr.p_double[i]-state->trustregion.ptr.p_double[i]; + state->rbfmodel.tmpbndu.ptr.p_double[i] = state->xk.ptr.p_double[i]+state->trustregion.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i],state->rbfmodel.tmpbndl.ptr.p_double[i]) ) + { + state->rbfmodel.tmpbndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i],state->rbfmodel.tmpbndu.ptr.p_double[i]) ) + { + state->rbfmodel.tmpbndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + } + state->rbfmodel.tmpx0.ptr.p_double[i] = state->xk.ptr.p_double[i]; + state->rbfmodel.tmps.ptr.p_double[i] = state->trustregion.ptr.p_double[i]; + } + for(i=n; i<=nx-1; i++) + { + state->rbfmodel.tmpbndl.ptr.p_double[i] = 0.0; + state->rbfmodel.tmpbndu.ptr.p_double[i] = _state->v_posinf; + state->rbfmodel.tmps.ptr.p_double[i] = state->trustradfactor; + state->rbfmodel.tmpx0.ptr.p_double[i] = 0.0; + } + rallocv(cntlc+1, &state->rbfmodel.clx, _state); + rallocv(cntlc+1, &state->rbfmodel.cux, _state); + sparsecreatecrsemptybuf(nx, &state->rbfmodel.cx, _state); + iallocv(nx, &state->tmpi, _state); + rallocv(nx, &state->tmp0, _state); + for(i=0; i<=cntlc-1; i++) + { + nnz = 0; + for(j=state->c.ridx.ptr.p_int[i]; j<=state->c.ridx.ptr.p_int[i+1]-1; j++) + { + state->tmpi.ptr.p_int[nnz] = state->c.idx.ptr.p_int[j]; + state->tmp0.ptr.p_double[nnz] = state->c.vals.ptr.p_double[j]; + nnz = nnz+1; + } + state->rbfmodel.clx.ptr.p_double[i] = state->cl.ptr.p_double[i]; + if( ae_isfinite(state->cl.ptr.p_double[i], _state) ) + { + state->tmpi.ptr.p_int[nnz] = n+2*i+0; + state->tmp0.ptr.p_double[nnz] = 1.0; + nnz = nnz+1; + } + state->rbfmodel.cux.ptr.p_double[i] = state->cu.ptr.p_double[i]; + if( ae_isfinite(state->cu.ptr.p_double[i], _state) ) + { + state->tmpi.ptr.p_int[nnz] = n+2*i+1; + state->tmp0.ptr.p_double[nnz] = -1.0; + nnz = nnz+1; + } + ae_assert(nnz<=nx, "DFGM: integrity check 345240 failed", _state); + sparseappendcompressedrow(&state->rbfmodel.cx, &state->tmpi, &state->tmp0, nnz, _state); + } + iallocv(cntlc, &state->tmpi, _state); + for(i=0; i<=cntlc-1; i++) + { + state->tmpi.ptr.p_int[i] = i; + } + minfsqpinitbuf(&state->rbfmodel.tmpbndl, &state->rbfmodel.tmpbndu, &state->rbfmodel.tmps, &state->rbfmodel.tmpx0, nx, &state->rbfmodel.cx, &state->rbfmodel.clx, &state->rbfmodel.cux, &state->tmpi, cntlc, &state->nl, &state->nu, cntnlc, &state->rbfmodel.crit, ae_false, &state->rbfmodel.fsqpsolver, _state); + smoothnessmonitorinit(&state->rbfmodel.smonitor, &state->rbfmodel.tmps, nx, 1+cntnlc, ae_false, _state); + while(minfsqpiteration(&state->rbfmodel.fsqpsolver, &state->rbfmodel.smonitor, ae_false, _state)) + { + if( state->rbfmodel.fsqpsolver.xupdated ) + { + continue; + } + if( state->rbfmodel.fsqpsolver.needfisj ) + { + + /* + * Compute the original model in Fi[] and its gradient in tmp1[] + */ + rallocv(nx, &state->tmp0, _state); + rallocv((m+cntnlc)*n, &state->tmp1, _state); + rcopyv(nx, &state->rbfmodel.fsqpsolver.x, &state->tmp0, _state); + rmergemulv(nx, &state->rbfmodel.tmps, &state->tmp0, _state); + rmergemaxv(nx, &state->rbfmodel.tmpbndl, &state->tmp0, _state); + rmergeminv(nx, &state->rbfmodel.tmpbndu, &state->tmp0, _state); + dfgenmod_rbfcomputemodel(state, &state->tmp0, &state->rbfmodel.fsqpsolver.fi, ae_true, &state->tmp1, ae_true, _state); + + /* + * Modify the model by replacing objective with a sum of constraint violations and + * by adding slacks to nonlinear constraints. + */ + rsetallocv((m+cntnlc)*nx, 0.0, &state->tmp2, _state); + state->rbfmodel.fsqpsolver.fi.ptr.p_double[0] = (double)(0); + for(j=n; j<=nx-1; j++) + { + state->rbfmodel.fsqpsolver.fi.ptr.p_double[0] = state->rbfmodel.fsqpsolver.fi.ptr.p_double[0]+state->tmp0.ptr.p_double[j]; + state->tmp2.ptr.p_double[j] = 1.0; + } + for(i=1; i<=cntnlc; i++) + { + rcopyvx(n, &state->tmp1, i*n, &state->tmp2, i*nx, _state); + if( ae_isfinite(state->nl.ptr.p_double[i-1], _state) ) + { + j = n+2*cntlc+2*(i-1)+0; + state->rbfmodel.fsqpsolver.fi.ptr.p_double[i] = state->rbfmodel.fsqpsolver.fi.ptr.p_double[i]+state->tmp0.ptr.p_double[j]; + state->tmp2.ptr.p_double[i*nx+j] = 1.0; + } + if( ae_isfinite(state->nu.ptr.p_double[i-1], _state) ) + { + j = n+2*cntlc+2*(i-1)+1; + state->rbfmodel.fsqpsolver.fi.ptr.p_double[i] = state->rbfmodel.fsqpsolver.fi.ptr.p_double[i]-state->tmp0.ptr.p_double[j]; + state->tmp2.ptr.p_double[i*nx+j] = -1.0; + } + } + sparsecreatecrsfromdensev(&state->tmp2, 1+cntnlc, nx, &state->rbfmodel.fsqpsolver.sj, _state); + sparsemultiplycolsby(&state->rbfmodel.fsqpsolver.sj, &state->rbfmodel.tmps, _state); + continue; + } + ae_assert(ae_false, "DFGM: integrity check 261738 failed", _state); + } + ae_assert(state->rbfmodel.fsqpsolver.repterminationtype>0, "DFGM: integrity check 265740 failed", _state); + state->repsubsolverits = state->repsubsolverits+state->rbfmodel.fsqpsolver.repiterationscount; + + /* + * Extract stopping point and compute predicted decrease in constraint violation + */ + rcopyv(nx, &state->rbfmodel.fsqpsolver.stepk.x, &state->rbfmodel.tmpx0, _state); + rmergemulv(nx, &state->rbfmodel.tmps, &state->rbfmodel.tmpx0, _state); + rmergemaxv(nx, &state->rbfmodel.tmpbndl, &state->rbfmodel.tmpx0, _state); + rmergeminv(nx, &state->rbfmodel.tmpbndu, &state->rbfmodel.tmpx0, _state); + *predh = 0.0; + for(i=n; i<=nx-1; i++) + { + *predh = *predh+state->rbfmodel.tmpx0.ptr.p_double[i]; + } + if( state->dotrace ) + { + ae_trace("$$ %0d its, best pred H = %0.3e\n", + (int)(state->rbfmodel.fsqpsolver.repiterationscount), + (double)(*predh)); + } + + /* + * Append a constraint on maximum constraint violation to the original problem, solve it + */ + iallocv(nx, &state->tmpi, _state); + rallocv(nx, &state->tmp0, _state); + nnz = 0; + for(i=n; i<=nx-1; i++) + { + state->tmpi.ptr.p_int[nnz] = i; + state->tmp0.ptr.p_double[nnz] = 1.0; + nnz = nnz+1; + } + ae_assert(state->rbfmodel.clx.cnt>=cntlc+1&&state->rbfmodel.cux.cnt>=cntlc+1, "DFGM: integrity check 423305 failed", _state); + sparseappendcompressedrow(&state->rbfmodel.cx, &state->tmpi, &state->tmp0, nnz, _state); + state->rbfmodel.clx.ptr.p_double[cntlc] = _state->v_neginf; + state->rbfmodel.cux.ptr.p_double[cntlc] = *predh; + iallocv(cntlc+1, &state->tmpi, _state); + for(i=0; i<=cntlc; i++) + { + state->tmpi.ptr.p_int[i] = i; + } + minfsqpinitbuf(&state->rbfmodel.tmpbndl, &state->rbfmodel.tmpbndu, &state->rbfmodel.tmps, &state->rbfmodel.tmpx0, nx, &state->rbfmodel.cx, &state->rbfmodel.clx, &state->rbfmodel.cux, &state->tmpi, cntlc+1, &state->nl, &state->nu, cntnlc, &state->rbfmodel.crit, ae_false, &state->rbfmodel.fsqpsolver, _state); + smoothnessmonitorinit(&state->rbfmodel.smonitor, &state->rbfmodel.tmps, nx, 1+cntnlc, ae_false, _state); + while(minfsqpiteration(&state->rbfmodel.fsqpsolver, &state->rbfmodel.smonitor, ae_false, _state)) + { + if( state->rbfmodel.fsqpsolver.xupdated ) + { + continue; + } + if( state->rbfmodel.fsqpsolver.needfisj ) + { + + /* + * Compute the original model in Fi[] and its gradient in tmp1[] + */ + rallocv(nx, &state->tmp0, _state); + rallocv((m+cntnlc)*n, &state->tmp1, _state); + rcopyv(nx, &state->rbfmodel.fsqpsolver.x, &state->tmp0, _state); + rmergemulv(nx, &state->rbfmodel.tmps, &state->tmp0, _state); + rmergemaxv(nx, &state->rbfmodel.tmpbndl, &state->tmp0, _state); + rmergeminv(nx, &state->rbfmodel.tmpbndu, &state->tmp0, _state); + dfgenmod_rbfcomputemodel(state, &state->tmp0, &state->rbfmodel.fsqpsolver.fi, ae_true, &state->tmp1, ae_true, _state); + + /* + * Modify the model by adding slacks to nonlinear constraints. + */ + rsetallocv((m+cntnlc)*nx, 0.0, &state->tmp2, _state); + rcopyvx(n, &state->tmp1, 0, &state->tmp2, 0, _state); + for(i=1; i<=cntnlc; i++) + { + rcopyvx(n, &state->tmp1, i*n, &state->tmp2, i*nx, _state); + if( ae_isfinite(state->nl.ptr.p_double[i-1], _state) ) + { + j = n+2*cntlc+2*(i-1)+0; + state->rbfmodel.fsqpsolver.fi.ptr.p_double[i] = state->rbfmodel.fsqpsolver.fi.ptr.p_double[i]+state->tmp0.ptr.p_double[j]; + state->tmp2.ptr.p_double[i*nx+j] = 1.0; + } + if( ae_isfinite(state->nu.ptr.p_double[i-1], _state) ) + { + j = n+2*cntlc+2*(i-1)+1; + state->rbfmodel.fsqpsolver.fi.ptr.p_double[i] = state->rbfmodel.fsqpsolver.fi.ptr.p_double[i]-state->tmp0.ptr.p_double[j]; + state->tmp2.ptr.p_double[i*nx+j] = -1.0; + } + } + sparsecreatecrsfromdensev(&state->tmp2, 1+cntnlc, nx, &state->rbfmodel.fsqpsolver.sj, _state); + sparsemultiplycolsby(&state->rbfmodel.fsqpsolver.sj, &state->rbfmodel.tmps, _state); + continue; + } + ae_assert(ae_false, "DFGM: integrity check 261738 failed", _state); + } + state->repsubsolverits = state->repsubsolverits+state->rbfmodel.fsqpsolver.repiterationscount; + rcopyv(n, &state->rbfmodel.fsqpsolver.stepk.x, &state->xn, _state); + rmergemulv(n, &state->trustregion, &state->xn, _state); + rmergemaxv(n, &state->finitebndl, &state->xn, _state); + rmergeminv(n, &state->finitebndu, &state->xn, _state); + if( state->dotrace ) + { + ae_trace("$$ %0d its in optimization phase\n", + (int)(state->rbfmodel.fsqpsolver.repiterationscount)); + } + + /* + * + */ + rallocv(m+cntnlc, &state->tmp1, _state); + rcopyv(n, &state->xn, &state->sk, _state); + raddv(n, -1.0, &state->xk, &state->sk, _state); + dfgenmod_rbfcomputemodel(state, &state->xn, &state->tmp1, ae_true, &state->tmp0, ae_false, _state); + *predf = state->tmp1.ptr.p_double[0]; + *predh = (double)(0); + if( cntlc>0 ) + { + sparsemv(&state->c, &state->xn, &state->tmp0, _state); + for(i=0; i<=cntlc-1; i++) + { + if( ae_isfinite(state->cl.ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(state->cl.ptr.p_double[i]-state->tmp0.ptr.p_double[i], 0.0, _state); + } + if( ae_isfinite(state->cu.ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(state->tmp0.ptr.p_double[i]-state->cu.ptr.p_double[i], 0.0, _state); + } + } + } + for(i=0; i<=cntnlc-1; i++) + { + if( ae_isfinite(state->nl.ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(state->nl.ptr.p_double[i]-state->tmp1.ptr.p_double[m+i], 0.0, _state); + } + if( ae_isfinite(state->nu.ptr.p_double[i], _state) ) + { + *predh = *predh+ae_maxreal(state->tmp1.ptr.p_double[m+i]-state->nu.ptr.p_double[i], 0.0, _state); + } + } + + /* + * Issue RComm V2 request + */ + state->requesttype = 4; + state->querysize = 1; + rcopyallocv(n, &state->xn, &state->querydata, _state); + rallocv(m+cntnlc, &state->replyfi, _state); + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + + /* + * Done + */ + return; + } + + /* + * Unexpected + */ + ae_assert(ae_false, "DFGM: PrepareTrialRequest() is unable to handle unexpected algorithm", _state); +} + + +/************************************************************************* +Processes results of the RComm V2 request for a trial point. + +Returns the value of F (target) and sum of constraints violations H + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_processtrialrequest(dfgmstate* state, + double* f, + double* h, + ae_state *_state) +{ + ae_int_t i; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + + *f = 0.0; + *h = 0.0; + + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + *f = (double)(0); + *h = (double)(0); + + /* + * 2PS, LSA + */ + if( state->modeltype==0||state->modeltype==1 ) + { + ae_assert(cntlc==0, "DFGM: integrity check 6222 failed", _state); + ae_assert(cntnlc==0, "DFGM: integrity check 6323 failed", _state); + ae_assert(state->isleastsquares, "DFGM: integrity check 6424 failed", _state); + ae_assert(state->querysize==1, "DFGM: integrity check 3540 failed", _state); + *f = 0.5*rdotv2(m, &state->replyfi, _state); + *h = (double)(0); + rcopyv(m+cntnlc, &state->replyfi, &state->fnvec, _state); + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + return; + } + + /* + * ORBIT + */ + if( state->modeltype==2 ) + { + ae_assert(!state->isleastsquares, "DFGM: integrity check 240106 failed", _state); + ae_assert(state->querysize==1, "DFGM: integrity check 241107 failed", _state); + *f = state->replyfi.ptr.p_double[0]; + *h = (double)(0); + if( cntlc>0 ) + { + sparsemv(&state->c, &state->xn, &state->tmp0, _state); + for(i=0; i<=cntlc-1; i++) + { + if( ae_isfinite(state->cl.ptr.p_double[i], _state) ) + { + *h = *h+ae_maxreal(state->cl.ptr.p_double[i]-state->tmp0.ptr.p_double[i], 0.0, _state); + } + if( ae_isfinite(state->cu.ptr.p_double[i], _state) ) + { + *h = *h+ae_maxreal(state->tmp0.ptr.p_double[i]-state->cu.ptr.p_double[i], 0.0, _state); + } + } + } + for(i=0; i<=cntnlc-1; i++) + { + if( ae_isfinite(state->nl.ptr.p_double[i], _state) ) + { + *h = *h+ae_maxreal(state->nl.ptr.p_double[i]-state->replyfi.ptr.p_double[m+i], 0.0, _state); + } + if( ae_isfinite(state->nu.ptr.p_double[i], _state) ) + { + *h = *h+ae_maxreal(state->replyfi.ptr.p_double[m+i]-state->nu.ptr.p_double[i], 0.0, _state); + } + } + rcopyv(m+cntnlc, &state->replyfi, &state->fnvec, _state); + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + return; + } + ae_assert(ae_false, "DFGM: ProcessTrialRequest() is unable to handle unexpected algorithm", _state); +} + + +/************************************************************************* +Tests step acceptance. + +Input parameters: +* Fk, Hk - current target Fk and a sum of constraint violations Hk at Xk +* Fp, Hp - predicted values +* Fn, Hn - actual values at Xn=Xk+Sk + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_testacceptancebyfilter(dfgmstate* state, + double fk, + double hk, + double fp, + double hp, + double fn, + double hn, + ae_state *_state) +{ + ae_bool result; + + + + /* + * Reject, if the step does not improve either F or H + */ + if( ae_fp_greater_eq(fn,fk)&&ae_fp_greater_eq(hn,hk) ) + { + result = ae_false; + return result; + } + + /* + * The step is an h-type step that reduces constraint violation, however + * fails to reduce it to zero within the trust region. + */ + if( (ae_fp_greater(hk,(double)(0))&&ae_fp_less(hp,hk))&&ae_fp_greater(hp,0.001*hk) ) + { + result = ae_fp_less(hn-hk,dfgenmod_eta1*(hp-hk)); + return result; + } + + /* + * The step is an f-type step + * + * NOTE: it is important to have this block after the previous one, not before; + * having it before in its present form means that steps that reduce constraint + * violation but increase objective will not be accepted. + */ + if( ae_fp_less(fp,fk)&&ae_fp_greater(fn-fk,dfgenmod_eta1*(fp-fk)) ) + { + result = ae_false; + return result; + } + result = nlpfisacceptable(&state->filter, fk, hk, fn, hn, _state); + return result; +} + + +/************************************************************************* +Sets signal that the step was accepted. + +Presently it does the following +* inserts current iterate into the filter. If the iterate is not + acceptable, it is silently denied. + +* if Fnfilter, fn, hn, _state) ) + { + if( ae_fp_greater(hk,(double)(0)) ) + { + nlpfappend(&state->filter, fk, hk, _state); + } + } + + /* + * Append to the State.SuccessHistory + */ + if( ae_fp_less(fn,fk) ) + { + state->successhistorylen = ae_minint(state->successhistorylen+1, state->successhistorymax, _state); + ae_assert(state->successhistorynext<=state->successhistorylen-1, "DFGM: integrity check 697019 failed", _state); + state->successhistory.ptr.p_double[state->successhistorynext] = fn-fk; + state->successhistorynext = (state->successhistorynext+1)%state->successhistorymax; + } +} + + +/************************************************************************* +Sends information about denial of the current step. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_sendstepdenialtomodel(dfgmstate* state, + ae_state *_state) +{ + + + + /* + * 2PS + */ + if( state->modeltype==0 ) + { + return; + } + + /* + * LSA + */ + if( state->modeltype==1 ) + { + return; + } + + /* + * ORBIT + */ + if( state->modeltype==2 ) + { + return; + } + ae_assert(ae_false, "DFGM: SendDenialToModel() is unable to handle unexpected algorithm", _state); +} + + +/************************************************************************* +Returns true if State.DeltaK is roughly State.RhoK + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_deltakatminimum(const dfgmstate* state, + ae_state *_state) +{ + ae_bool result; + + + result = ae_fp_less_eq(state->trustradfactor,state->trustradbnd*1.01); + return result; +} + + +/************************************************************************* +Returns true if restart is recommended right now + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_restartautodetected(const dfgmstate* state, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +Returns true if working set needs improvement + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_workingsetneedsimprovement(dfgmstate* state, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + double mostdistant; + double leastdistant; + ae_bool result; + + + n = state->n; + result = ae_false; + + /* + * 2PS, LSA + */ + if( state->modeltype==0||state->modeltype==1 ) + { + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 2111 failed", _state); + dfgenmod_mostandleastdistant(&state->invtrustregion, n, &state->wrkset, state->wrksetsize, &mostdistant, &i, &leastdistant, &j, _state); + if( state->modeltype==0 ) + { + result = ae_fp_greater(mostdistant,dfgenmod_twopsstephi)||ae_fp_less(leastdistant,dfgenmod_twopssteplo); + } + else + { + result = ae_fp_greater(mostdistant,dfgenmod_pointtoofar)||ae_fp_less(leastdistant,dfgenmod_pointtooclose); + } + return result; + } + + /* + * ORBIT + */ + if( state->modeltype==2 ) + { + + /* + * ORBIT does not check this condition + */ + result = ae_false; + return result; + } + ae_assert(ae_false, "DFGM: WorkingSetNeedsImprovement() is unable to handle unexpected algorithm", _state); + return result; +} + + +/************************************************************************* +Handle successful or failed step. + +This function updates working set and (for some solvers) issues additional +RComm V2 requests if working set needs immediate revaluation. + +It also updates the model. + +On exit it may set State.RepTerminationType to a negative code (failure) +if it encountered infinities in the target/constraints during update and +failed to recover from the problem. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +It expects that State.Xk and State.FkVec were already updated at the moment +this function is called. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_updateworkingsetandmodel(dfgmstate* state, + /* Real */ const ae_vector* xk, + /* Real */ const ae_vector* xn, + /* Real */ const ae_vector* fnvec, + double fn, + double hn, + ae_bool successfulstep, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t replaceidx; + double rating; + double bestrating; + double v; + double vv; + double mx; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstateupdate.stage>=0 ) + { + n = state->rstateupdate.ia.ptr.p_int[0]; + m = state->rstateupdate.ia.ptr.p_int[1]; + cntlc = state->rstateupdate.ia.ptr.p_int[2]; + cntnlc = state->rstateupdate.ia.ptr.p_int[3]; + i = state->rstateupdate.ia.ptr.p_int[4]; + j = state->rstateupdate.ia.ptr.p_int[5]; + k = state->rstateupdate.ia.ptr.p_int[6]; + replaceidx = state->rstateupdate.ia.ptr.p_int[7]; + rating = state->rstateupdate.ra.ptr.p_double[0]; + bestrating = state->rstateupdate.ra.ptr.p_double[1]; + v = state->rstateupdate.ra.ptr.p_double[2]; + vv = state->rstateupdate.ra.ptr.p_double[3]; + mx = state->rstateupdate.ra.ptr.p_double[4]; + } + else + { + n = -541; + m = -698; + cntlc = -900; + cntnlc = -318; + i = -940; + j = 1016; + k = -229; + replaceidx = -536; + rating = 487.0; + bestrating = -115.0; + v = 886.0; + vv = 346.0; + mx = -722.0; + } + if( state->rstateupdate.stage==0 ) + { + goto lbl_0; + } + if( state->rstateupdate.stage==1 ) + { + goto lbl_1; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + + /* + * 2PS + */ + if( state->modeltype!=0 ) + { + goto lbl_2; + } + + /* + * Do not update working set on unsuccessful steps because this solver uses fixed + * stencil which does not allow inclusion of arbitrary points. The only way to update + * working set is to rebuild it at a new point using the same stencil. + */ + if( !successfulstep ) + { + result = ae_false; + return result; + } + + /* + * Clear working set (it will be recomputed from scratch on a new place) and call working set improvement code + */ + state->wrksetsize = 0; + ae_vector_set_length(&state->rstateimprove.ia, 13+1, _state); + ae_vector_set_length(&state->rstateimprove.ba, 0+1, _state); + ae_vector_set_length(&state->rstateimprove.ra, 12+1, _state); + state->rstateimprove.stage = -1; +lbl_4: + if( !dfgenmod_improveworkingsetgeometry(state, _state) ) + { + goto lbl_5; + } + state->rstateupdate.stage = 0; + goto lbl_rcomm; +lbl_0: + goto lbl_4; +lbl_5: + result = ae_false; + return result; +lbl_2: + + /* + * LSA + */ + if( state->modeltype==1 ) + { + + /* + * If the step was not successful, we have to skip update if the new point + * is too close to the center. When the step is successful, we can replace + * the center. But it is not possible on unsuccessful steps. + */ + if( !successfulstep ) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = ae_maxreal(v, ae_fabs(xn->ptr.p_double[j]-xk->ptr.p_double[j], _state)*state->invtrustregion.ptr.p_double[j], _state); + } + if( ae_fp_less(v,dfgenmod_pointtooclose) ) + { + result = ae_false; + return result; + } + } + + /* + * Select ReplaceIdx - index of a point to replace by the new point Xn, + * with 0<=ReplaceIdxtmp0, _state); + rallocv(n, &state->tmp1, _state); + replaceidx = -1; + bestrating = (double)(0); + for(i=0; i<=n; i++) + { + + /* + * Skip central point if the step is not successful (we remain at the old + * place, so the central point can not be replaced) + */ + if( i==n&&!successfulstep ) + { + break; + } + + /* + * Compute Lagrange polynomial coefficients + */ + if( i==n ) + { + rsetv(n, 0.0, &state->tmp0, _state); + for(j=0; j<=n-1; j++) + { + rcopycv(n, &state->lsamodel.invw, j, &state->tmp1, _state); + raddv(n, -1.0, &state->tmp1, &state->tmp0, _state); + } + } + else + { + rcopycv(n, &state->lsamodel.invw, i, &state->tmp0, _state); + } + + /* + * Compute rating as |L(Xn-Xk)|*max(|Xn-Wrk[I]|/Scales,1)^2, compare with the best + */ + rcopyrv(n, &state->wrkset, i, &state->tmp1, _state); + raddv(n, -1.0, xn, &state->tmp1, _state); + rating = ae_fabs(rdotv(n, xn, &state->tmp0, _state)-rdotv(n, xk, &state->tmp0, _state)+rcase2(i==n, (double)(1), (double)(0), _state), _state)*ae_sqr(ae_maxreal(dfgenmod_normrelativetotrustregion(state, &state->tmp1, _state), (double)(1), _state), _state); + if( replaceidx<0||ae_fp_greater(rating,bestrating) ) + { + replaceidx = i; + bestrating = rating; + } + } + ae_assert(replaceidx>=0, "DFGM: integrity check 2850 failed", _state); + if( state->dotrace ) + { + if( replaceidx> replacing point %0d (non-central)\n", + (int)(replaceidx)); + } + else + { + ae_trace(">> replacing previously central point\n"); + } + } + + /* + * Modify WrkSet + */ + if( successfulstep ) + { + if( replaceidxwrkset, n, &state->wrkset, replaceidx, _state); + rcopyvr(n, xn, &state->wrkset, n, _state); + for(i=0; i<=m+cntnlc-1; i++) + { + state->wrkset.ptr.pp_double[n][n+i] = fnvec->ptr.p_double[i]; + } + } + else + { + + /* + * Successful step, we replace central point by Xn. + */ + rcopyvr(n, xn, &state->wrkset, n, _state); + for(i=0; i<=m+cntnlc-1; i++) + { + state->wrkset.ptr.pp_double[n][n+i] = fnvec->ptr.p_double[i]; + } + } + } + else + { + + /* + * Non-successful step, only off-central point can be replaced. The center + * is not replaced or moved. + */ + ae_assert(replaceidxwrkset, replaceidx, _state); + for(i=0; i<=m+cntnlc-1; i++) + { + state->wrkset.ptr.pp_double[replaceidx][n+i] = fnvec->ptr.p_double[i]; + } + } + + /* + * Recompute matrices W and InvW + */ + for(i=0; i<=n-1; i++) + { + rcopyrr(n, &state->wrkset, i, &state->lsamodel.w, i, _state); + raddrr(n, -1.0, &state->wrkset, n, &state->lsamodel.w, i, _state); + } + rcopym(n, n, &state->lsamodel.w, &state->lsamodel.invw, _state); + rmatrixinverse(&state->lsamodel.invw, n, &state->invrep, _state); + if( state->invrep.terminationtype<=0 ) + { + if( state->dotrace ) + { + ae_trace(">> dataset matrix inverse failed, emergency termination with completion code +7\n"); + } + state->repterminationtype = 7; + result = ae_false; + return result; + } + if( state->dotrace ) + { + ae_trace(">> successfully inverted dataset matrix, cond=%0.2e\n", + (double)((double)1/(state->invrep.r1+ae_machineepsilon))); + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + v = (double)(0); + for(i=0; i<=n; i++) + { + if( i==n ) + { + rsetv(n, 0.0, &state->tmp0, _state); + for(j=0; j<=n-1; j++) + { + rcopycv(n, &state->lsamodel.invw, j, &state->tmp1, _state); + raddv(n, -1.0, &state->tmp1, &state->tmp0, _state); + } + } + else + { + rcopycv(n, &state->lsamodel.invw, i, &state->tmp0, _state); + } + v = ae_maxreal(v, dfgenmod_maxabslag(xn, n, &state->trustregion, &state->finitebndl, &state->finitebndu, &state->tmp0, rcase2(i==n, (double)(1), (double)(0), _state), &state->tmp1, &state->tmp2, ae_false, _state), _state); + } + ae_trace(">> poisedness constant is %0.2e\n", + (double)(v)); + } + + /* + * The working set is ready, rebuild a quadratic model of the target. + * + * Below we rely on the specific ordering of the working set + * (the central point comes last, N additional ones come first). + */ + ae_assert(state->cntnlc==0, "DFGM: integrity check 4811 failed", _state); + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 0425 failed", _state); + rallocm(n, m, &state->lsamodel.tmprhs, _state); + rmatrixcopy(n, m, &state->wrkset, 0, n, &state->lsamodel.tmprhs, 0, 0, _state); + rallocv(m, &state->lsamodel.tmp0, _state); + for(i=0; i<=m-1; i++) + { + state->lsamodel.tmp0.ptr.p_double[i] = state->wrkset.ptr.pp_double[n][n+i]; + } + for(i=0; i<=n-1; i++) + { + raddvr(m, -1.0, &state->lsamodel.tmp0, &state->lsamodel.tmprhs, i, _state); + } + rallocm(m, n, &state->lsamodel.jac, _state); + rmatrixgemm(m, n, n, 1.0, &state->lsamodel.tmprhs, 0, 0, 1, &state->lsamodel.invw, 0, 0, 1, 0.0, &state->lsamodel.jac, 0, 0, _state); + rsetallocv(n, 0.0, &state->lsamodel.g, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + state->lsamodel.g.ptr.p_double[i] = state->lsamodel.g.ptr.p_double[i]+state->wrkset.ptr.pp_double[n][n+j]*state->lsamodel.jac.ptr.pp_double[j][i]; + } + } + rallocm(n, n, &state->lsamodel.q, _state); + rmatrixgemm(n, n, m, 1.0, &state->lsamodel.jac, 0, 0, 1, &state->lsamodel.jac, 0, 0, 0, 0.0, &state->lsamodel.q, 0, 0, _state); + + /* + * Done + */ + result = ae_false; + return result; + } + + /* + * ORBIT + */ + if( state->modeltype!=2 ) + { + goto lbl_6; + } + ae_vector_set_length(&state->rstateimprove.ia, 13+1, _state); + ae_vector_set_length(&state->rstateimprove.ba, 0+1, _state); + ae_vector_set_length(&state->rstateimprove.ra, 12+1, _state); + state->rstateimprove.stage = -1; +lbl_8: + if( !dfgenmod_improveworkingsetgeometry(state, _state) ) + { + goto lbl_9; + } + state->rstateupdate.stage = 1; + goto lbl_rcomm; +lbl_1: + goto lbl_8; +lbl_9: + result = ae_false; + return result; +lbl_6: + ae_assert(ae_false, "DFGM: UpdateWorkingSetAndModel() is unable to handle unexpected algorithm", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstateupdate.ia.ptr.p_int[0] = n; + state->rstateupdate.ia.ptr.p_int[1] = m; + state->rstateupdate.ia.ptr.p_int[2] = cntlc; + state->rstateupdate.ia.ptr.p_int[3] = cntnlc; + state->rstateupdate.ia.ptr.p_int[4] = i; + state->rstateupdate.ia.ptr.p_int[5] = j; + state->rstateupdate.ia.ptr.p_int[6] = k; + state->rstateupdate.ia.ptr.p_int[7] = replaceidx; + state->rstateupdate.ra.ptr.p_double[0] = rating; + state->rstateupdate.ra.ptr.p_double[1] = bestrating; + state->rstateupdate.ra.ptr.p_double[2] = v; + state->rstateupdate.ra.ptr.p_double[3] = vv; + state->rstateupdate.ra.ptr.p_double[4] = mx; + return result; +} + + +/************************************************************************* +For State.WrkSetSize=0 this function assumes that we actually perform an +initial model construction. In the latter case we assume that the first +element of the working set contains some meaningful value, in the latter +case the working set is built completely from scratch. + +For State.WrkSetSize>0 this function assumes that the working set was +already initialized and we perform an update: modify working set and +(for some solvers) issues additional RComm V2 requests if working set needs +immediate revaluation. + +It also updates the model: +* recomputes State.Fk and State.Hk +* updates current model by (possibly) incorporating State.Xk and (possibly) + removing some of the previously included points. + +On exit it may set State.RepTerminationType to a negative code (failure) +if it encountered infinities in the target/constraints during update and +failed to recover from the problem. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool dfgenmod_improveworkingsetgeometry(dfgmstate* state, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double vlft; + double vrgt; + double v; + double vmin; + double vmax; + double x0i; + ae_int_t improveidx; + ae_int_t improvedfar; + ae_bool workingsetchanged; + ae_int_t leastdistantidx; + ae_int_t mostdistantidx; + double leastdistant; + double mostdistant; + double mx; + ae_int_t replaceidx; + double rating; + double bestrating; + double vv; + double roundradius; + ae_int_t roundidx; + ae_int_t chosenduringround; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstateimprove.stage>=0 ) + { + n = state->rstateimprove.ia.ptr.p_int[0]; + m = state->rstateimprove.ia.ptr.p_int[1]; + cntlc = state->rstateimprove.ia.ptr.p_int[2]; + cntnlc = state->rstateimprove.ia.ptr.p_int[3]; + i = state->rstateimprove.ia.ptr.p_int[4]; + j = state->rstateimprove.ia.ptr.p_int[5]; + k = state->rstateimprove.ia.ptr.p_int[6]; + improveidx = state->rstateimprove.ia.ptr.p_int[7]; + improvedfar = state->rstateimprove.ia.ptr.p_int[8]; + leastdistantidx = state->rstateimprove.ia.ptr.p_int[9]; + mostdistantidx = state->rstateimprove.ia.ptr.p_int[10]; + replaceidx = state->rstateimprove.ia.ptr.p_int[11]; + roundidx = state->rstateimprove.ia.ptr.p_int[12]; + chosenduringround = state->rstateimprove.ia.ptr.p_int[13]; + workingsetchanged = state->rstateimprove.ba.ptr.p_bool[0]; + vlft = state->rstateimprove.ra.ptr.p_double[0]; + vrgt = state->rstateimprove.ra.ptr.p_double[1]; + v = state->rstateimprove.ra.ptr.p_double[2]; + vmin = state->rstateimprove.ra.ptr.p_double[3]; + vmax = state->rstateimprove.ra.ptr.p_double[4]; + x0i = state->rstateimprove.ra.ptr.p_double[5]; + leastdistant = state->rstateimprove.ra.ptr.p_double[6]; + mostdistant = state->rstateimprove.ra.ptr.p_double[7]; + mx = state->rstateimprove.ra.ptr.p_double[8]; + rating = state->rstateimprove.ra.ptr.p_double[9]; + bestrating = state->rstateimprove.ra.ptr.p_double[10]; + vv = state->rstateimprove.ra.ptr.p_double[11]; + roundradius = state->rstateimprove.ra.ptr.p_double[12]; + } + else + { + n = -413; + m = -461; + cntlc = 927; + cntnlc = 201; + i = 922; + j = -154; + k = 306; + improveidx = -1011; + improvedfar = 951; + leastdistantidx = -463; + mostdistantidx = 88; + replaceidx = -861; + roundidx = -678; + chosenduringround = -731; + workingsetchanged = ae_true; + vlft = -763.0; + vrgt = -233.0; + v = -936.0; + vmin = -279.0; + vmax = 94.0; + x0i = -812.0; + leastdistant = 427.0; + mostdistant = 178.0; + mx = -819.0; + rating = -826.0; + bestrating = 667.0; + vv = 692.0; + roundradius = 84.0; + } + if( state->rstateimprove.stage==0 ) + { + goto lbl_0; + } + if( state->rstateimprove.stage==1 ) + { + goto lbl_1; + } + if( state->rstateimprove.stage==2 ) + { + goto lbl_2; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + + /* + * If working set is empty (initialization) or algorithm rebuilds + * working set from scratch every time (like 2PS), initialize + * working set using the best geometry possible (orthogonal distribution). + * + * After the working set was generated, the model is data structures + * are initialized. + * + * NOTE: this section gets the fresh data from the user even when the algorithm + * relies on a previously stored cloud. + */ + workingsetchanged = ae_false; + if( !(state->wrksetsize==0||state->modeltype==0) ) + { + goto lbl_3; + } + + /* + * Generate working set which satisfies box constraints + */ + rallocv(n, &state->tmpdeltas, _state); +lbl_5: + if( ae_false ) + { + goto lbl_6; + } + + /* + * Initialize working set + */ + rallocm(n+1, n+m+cntnlc, &state->wrkset, _state); + state->wrksetsize = 0; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_greater(state->scaledbndu.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]), "DFGM: integrity check 7909 failed", _state); + } + rcopyvr(n, &state->xk, &state->wrkset, state->wrksetsize, _state); + + /* + * Evaluate two candidate points: one obtained by making a step to the left, and one obtained by making a step to the right + */ + x0i = state->xk.ptr.p_double[i]; + vlft = boundval(x0i-dfgenmod_twopsstep*state->trustregion.ptr.p_double[i], state->finitebndl.ptr.p_double[i], state->finitebndu.ptr.p_double[i], _state); + vrgt = boundval(x0i+dfgenmod_twopsstep*state->trustregion.ptr.p_double[i], state->finitebndl.ptr.p_double[i], state->finitebndu.ptr.p_double[i], _state); + if( ae_fp_less_eq(x0i-vlft,0.9*(vrgt-x0i)) ) + { + + /* + * The left step is shorter than the right one due to box constraints, choose the right step + */ + state->wrkset.ptr.pp_double[state->wrksetsize][i] = vrgt; + state->tmpdeltas.ptr.p_double[i] = vrgt-x0i; + state->wrksetsize = state->wrksetsize+1; + continue; + } + if( ae_fp_less_eq(vrgt-x0i,0.9*(x0i-vlft)) ) + { + + /* + * The right step is shorter than the left one due to box constraints, choose the left step + */ + state->wrkset.ptr.pp_double[state->wrksetsize][i] = vlft; + state->tmpdeltas.ptr.p_double[i] = vlft-x0i; + state->wrksetsize = state->wrksetsize+1; + continue; + } + + /* + * Both steps are equally good, choose the random one + */ + state->wrkset.ptr.pp_double[state->wrksetsize][i] = rcase2(hqrnduniformi(&state->rs, 2, _state)==0, vlft, vrgt, _state); + state->tmpdeltas.ptr.p_double[i] = state->wrkset.ptr.pp_double[state->wrksetsize][i]-x0i; + state->wrksetsize = state->wrksetsize+1; + } + rcopyvr(n, &state->xk, &state->wrkset, state->wrksetsize, _state); + state->wrksetsize = state->wrksetsize+1; + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 1309 failed", _state); + for(i=0; i<=n-1; i++) + { + state->tmpdeltas.ptr.p_double[i] = coalesce(state->tmpdeltas.ptr.p_double[i], 1.0, _state); + } + + /* + * Issue RComm V2 request, check that the reply does not contain infinities + */ + state->requesttype = 4; + state->querysize = state->wrksetsize; + rallocv(n*state->querysize, &state->querydata, _state); + rallocv((m+cntnlc)*state->querysize, &state->replyfi, _state); + for(i=0; i<=state->wrksetsize-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->querydata.ptr.p_double[i*n+j] = state->wrkset.ptr.pp_double[i][j]; + } + } + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + state->rstateimprove.stage = 0; + goto lbl_rcomm; +lbl_0: + if( !isfinitevector(&state->replyfi, (m+cntnlc)*state->querysize, _state) ) + { + + /* + * Decrease trust radius and retry + */ + if( state->dotrace ) + { + ae_trace("[WARNING] target at the geometry-improving point is infinite, decreasing trust radius and restarting iteration\n"); + } + state->infinitiesencountered = ae_true; + state->recoveredfrominfinities = ae_false; + dfgenmod_updatetrustregion(state, dfgenmod_gammabad*state->trustradfactor, _state); + state->trustradbnd = ae_minreal(state->trustradfactor, state->trustradbnd, _state); + if( ae_fp_less(state->trustradfactor,coalesce(state->epsx, state->toosmalltrustrad, _state)) ) + { + state->repterminationtype = -8; + result = ae_false; + return result; + } + goto lbl_5; + } + + /* + * Accept the reply. + * Save to the cloud, if requested by the algorith, + */ + for(i=0; i<=state->wrksetsize-1; i++) + { + for(j=0; j<=m+cntnlc-1; j++) + { + state->wrkset.ptr.pp_double[i][n+j] = state->replyfi.ptr.p_double[i*(m+cntnlc)+j]; + } + } + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + goto lbl_6; + goto lbl_5; +lbl_6: + + /* + * Initialize model data structures + */ + ae_assert((state->modeltype==0||state->modeltype==1)||state->modeltype==2, "DFGM: integrity check 0337 failed", _state); + if( state->modeltype==0 ) + { + rcopyallocv(n, &state->tmpdeltas, &state->tpsmodel.deltas, _state); + } + if( state->modeltype==1 ) + { + rsetallocm(n, n, 0.0, &state->lsamodel.w, _state); + rsetallocm(n, n, 0.0, &state->lsamodel.invw, _state); + for(i=0; i<=n-1; i++) + { + state->lsamodel.w.ptr.pp_double[i][i] = state->tmpdeltas.ptr.p_double[i]; + state->lsamodel.invw.ptr.pp_double[i][i] = (double)1/state->tmpdeltas.ptr.p_double[i]; + } + } + workingsetchanged = ae_true; +lbl_3: + + /* + * 2PS. + */ + if( state->modeltype==0 ) + { + + /* + * The working set was already computed, rebuild a quadratic model of the target. + * + * Below we rely on the specific ordering of the working set + * (the central point comes last, N additional ones come first). + */ + ae_assert(state->cntnlc==0, "DFGM: integrity check 7614 failed", _state); + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 0425 failed", _state); + rsetallocv(n, 0.0, &state->tpsmodel.g, _state); + rallocm(n, n, &state->tpsmodel.q, _state); + rallocm(m, n, &state->tpsmodel.jac, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + state->tpsmodel.jac.ptr.pp_double[j][i] = (state->wrkset.ptr.pp_double[i][n+j]-state->wrkset.ptr.pp_double[n][n+j])/state->tpsmodel.deltas.ptr.p_double[i]; + state->tpsmodel.g.ptr.p_double[i] = state->tpsmodel.g.ptr.p_double[i]+state->wrkset.ptr.pp_double[n][n+j]*state->tpsmodel.jac.ptr.pp_double[j][i]; + } + } + rmatrixgemm(n, n, m, 1.0, &state->tpsmodel.jac, 0, 0, 1, &state->tpsmodel.jac, 0, 0, 0, 0.0, &state->tpsmodel.q, 0, 0, _state); + + /* + * Done + */ + result = ae_false; + return result; + } + + /* + * DFO-LSA. + */ + if( state->modeltype!=1 ) + { + goto lbl_7; + } + + /* + * Improve geometry of the dataset, if needed + */ + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 9726 failed", _state); + improvedfar = 0; + + /* + * Repeat improvement rounds until there is no point selected for improvement. + */ +lbl_9: + + /* + * Select a point to improve: + * * improve location of all points that are too close + * * improve location of a limited number of points that are too far + */ + dfgenmod_mostandleastdistant(&state->invtrustregion, n, &state->wrkset, state->wrksetsize, &mostdistant, &mostdistantidx, &leastdistant, &leastdistantidx, _state); + improveidx = -1; + if( leastdistantidx>=0&&ae_fp_less_eq(leastdistant,dfgenmod_pointtooclose*ae_minreal(mostdistant, 1.0, _state)) ) + { + improveidx = leastdistantidx; + } + if( improveidx<0&&ae_fp_greater_eq(mostdistant,dfgenmod_pointunacceptablyfar) ) + { + improveidx = mostdistantidx; + } + if( (improveidx<0&&ae_fp_less((double)(improvedfar),dfgenmod_lsaimprovementlimit))&&ae_fp_greater_eq(mostdistant,dfgenmod_pointtoofar) ) + { + improvedfar = improvedfar+1; + improveidx = mostdistantidx; + } + + /* + * Try to find a location for an improved point, handle possible infinities in the target + * by decreasing the trust radius and recomputing the proposal. + * + * The loop below has the loop condition "ImproveIdx>=0", the intention is to execute + * it continually (until we settle on an infinity-free trust region) when there is a + * point to improve, but to skip it if there is no points to be improved + */ + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + rallocv(n, &state->tmp2, _state); +lbl_12: + if( improveidx<0 ) + { + goto lbl_13; + } + + /* + * Insert new point to the location where Lagrange polynomial for ImproveIdx-th point + * reaches its maximum absolute value. + * + * Lagrange polynomial for this problem is a linear function with coefficients stored + * in the ImproveIdx-th column of State.lsaModel.InvW (the constant term is zero). We + * solve the problem by finding min L(x) and max L(x) subject to trust radius constraints, + * and then selecting a solution with maximum absolute value. + * + * NOTE: C0 parameter of MaxAbsLag() is zero because we always have ImproveIdxlsamodel.invw, improveidx, &state->tmp2, _state); + dfgenmod_maxabslag(&state->xk, n, &state->trustregion, &state->finitebndl, &state->finitebndu, &state->tmp2, 0.0, &state->tmp0, &state->tmp1, ae_true, _state); + rcopyvr(n, &state->tmp0, &state->wrkset, improveidx, _state); + + /* + * Issue RComm V2 request, check that the reply does not contain infinities + */ + state->requesttype = 4; + state->querysize = 1; + rallocv(n*state->querysize, &state->querydata, _state); + rallocv((m+cntnlc)*state->querysize, &state->replyfi, _state); + for(j=0; j<=n-1; j++) + { + state->querydata.ptr.p_double[j] = state->wrkset.ptr.pp_double[improveidx][j]; + } + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + state->rstateimprove.stage = 1; + goto lbl_rcomm; +lbl_1: + if( !isfinitevector(&state->replyfi, (m+cntnlc)*state->querysize, _state) ) + { + + /* + * Decrease trust radius and retry + */ + if( state->dotrace ) + { + ae_trace("[WARNING] target at the geometry-improving point is infinite, decreasing trust radius and restarting iteration\n"); + } + state->infinitiesencountered = ae_true; + state->recoveredfrominfinities = ae_false; + dfgenmod_updatetrustregion(state, dfgenmod_gammabad*state->trustradfactor, _state); + state->trustradbnd = ae_minreal(state->trustradfactor, state->trustradbnd, _state); + if( ae_fp_less(state->trustradfactor,coalesce(state->epsx, state->toosmalltrustrad, _state)) ) + { + state->repterminationtype = -8; + result = ae_false; + return result; + } + goto lbl_12; + } + + /* + * Accept the reply + */ + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + for(j=0; j<=m+cntnlc-1; j++) + { + state->wrkset.ptr.pp_double[improveidx][n+j] = state->replyfi.ptr.p_double[j]; + } + workingsetchanged = ae_true; + goto lbl_13; + goto lbl_12; +lbl_13: + + /* + * Quick exit: no changes in the working set at this point means that + * the working set will never change. We can exit now. + */ + if( !workingsetchanged ) + { + result = ae_false; + return result; + } + + /* + * Recompute matrices W and InvW, if there was an improvement in the + * working set (this phase is ignored if WorkingSetChanged=True, + * but ImproveIdx<0, which happens during the initialization) + */ + if( improveidx>=0 ) + { + rcopyrr(n, &state->wrkset, improveidx, &state->lsamodel.w, improveidx, _state); + raddvr(n, -1.0, &state->xk, &state->lsamodel.w, improveidx, _state); + rcopym(n, n, &state->lsamodel.w, &state->lsamodel.invw, _state); + rmatrixinverse(&state->lsamodel.invw, n, &state->invrep, _state); + if( state->invrep.terminationtype<=0 ) + { + state->repterminationtype = 7; + result = ae_false; + return result; + } + } + if( improveidx>=0 ) + { + goto lbl_9; + } + + /* + * The working set is ready, rebuild a quadratic model of the target. + * + * Below we rely on the specific ordering of the working set + * (the central point comes last, N additional ones come first). + */ + ae_assert(state->wrksetsize==n+1, "DFGM: integrity check 0425 failed", _state); + rallocm(n, m, &state->lsamodel.tmprhs, _state); + rmatrixcopy(n, m, &state->wrkset, 0, n, &state->lsamodel.tmprhs, 0, 0, _state); + rallocv(m, &state->lsamodel.tmp0, _state); + for(i=0; i<=m-1; i++) + { + state->lsamodel.tmp0.ptr.p_double[i] = state->wrkset.ptr.pp_double[n][n+i]; + } + for(i=0; i<=n-1; i++) + { + raddvr(m, -1.0, &state->lsamodel.tmp0, &state->lsamodel.tmprhs, i, _state); + } + rallocm(m, n, &state->lsamodel.jac, _state); + rmatrixgemm(m, n, n, 1.0, &state->lsamodel.tmprhs, 0, 0, 1, &state->lsamodel.invw, 0, 0, 1, 0.0, &state->lsamodel.jac, 0, 0, _state); + rsetallocv(n, 0.0, &state->lsamodel.g, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + state->lsamodel.g.ptr.p_double[i] = state->lsamodel.g.ptr.p_double[i]+state->wrkset.ptr.pp_double[n][n+j]*state->lsamodel.jac.ptr.pp_double[j][i]; + } + } + rallocm(n, n, &state->lsamodel.q, _state); + rmatrixgemm(n, n, m, 1.0, &state->lsamodel.jac, 0, 0, 1, &state->lsamodel.jac, 0, 0, 0, 0.0, &state->lsamodel.q, 0, 0, _state); + + /* + * Done + */ + result = ae_false; + return result; +lbl_7: + + /* + * ORBIT + */ + if( state->modeltype!=2 ) + { + goto lbl_14; + } + + /* + * Select subset of points from the cloud to work with. + * + * Initialize DistFromCenter[] and DistFromChosen[] (the latter is a copy + * of DistFromCenter[]). Set availability flags. + */ + ae_assert(state->savepointstocloud, "DFGM: integrity check 701531 failed", _state); + state->rbfmodel.currentcloudsize = 0; + for(i=0; i<=state->cloudsize-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = ae_maxreal(v, ae_fabs(state->clouddata.ptr.pp_double[i][j]-state->xk.ptr.p_double[j], _state)*state->invtrustregion.ptr.p_double[j], _state); + } + if( ae_fp_less_eq(v,dfgenmod_rbfmindist)||ae_fp_greater(v,dfgenmod_rbftheta0) ) + { + continue; + } + rgrowrowsfixedcolsm(state->rbfmodel.currentcloudsize+1, n+m+cntnlc, &state->rbfmodel.currentcloud, _state); + rcopyrr(n+m+cntnlc, &state->clouddata, i, &state->rbfmodel.currentcloud, state->rbfmodel.currentcloudsize, _state); + rgrowappendv(state->rbfmodel.currentcloudsize+1, &state->rbfmodel.distfromcenter, v, _state); + rgrowappendv(state->rbfmodel.currentcloudsize+1, &state->rbfmodel.distfromchosen, v, _state); + bgrowappendv(state->rbfmodel.currentcloudsize+1, &state->rbfmodel.available, ae_true, _state); + state->rbfmodel.currentcloudsize = state->rbfmodel.currentcloudsize+1; + } + + /* + * Try to select initial affine-independent working set of N points (plus one central) + * from the cloud, without performing additional evaluations + */ + ae_assert(ae_fp_greater(dfgenmod_rbfmindist,(double)(0)), "DFGM: integrity check 734622 failed", _state); + rallocm(state->rbfmodel.currentcloudsize, n, &state->rbfmodel.residualdisplacements, _state); + for(i=0; i<=state->rbfmodel.currentcloudsize-1; i++) + { + rcopyrr(n, &state->rbfmodel.currentcloud, i, &state->rbfmodel.residualdisplacements, i, _state); + raddvr(n, -1.0, &state->xk, &state->rbfmodel.residualdisplacements, i, _state); + rmergemulvr(n, &state->invtrustregion, &state->rbfmodel.residualdisplacements, i, _state); + } + state->rbfmodel.curwrksetsize = 0; + while(state->rbfmodel.curwrksetsizerbfmodel.currentcloudsize-1; i++) + { + if( !state->rbfmodel.available.ptr.p_bool[i] ) + { + continue; + } + if( ae_fp_less_eq(state->rbfmodel.distfromchosen.ptr.p_double[i],dfgenmod_rbfmindist) ) + { + continue; + } + if( ae_fp_greater(state->rbfmodel.distfromcenter.ptr.p_double[i],mx) ) + { + continue; + } + vv = rdotrr(n, &state->rbfmodel.residualdisplacements, i, &state->rbfmodel.residualdisplacements, i, _state); + if( ae_fp_eq(vv,(double)(0))||ae_fp_less(vv,dfgenmod_rbftheta1*dfgenmod_rbftheta1) ) + { + continue; + } + if( k<0||ae_fp_greater(vv,v) ) + { + k = i; + v = vv; + } + } + if( k<0 ) + { + break; + } + i = k; + + /* + * Orthogonalize residual displacements with respect to the currently chosen one + */ + rallocv(n, &state->rbfmodel.tmpcand, _state); + rcopyrv(n, &state->rbfmodel.residualdisplacements, i, &state->rbfmodel.tmpcand, _state); + v = rdotv2(n, &state->rbfmodel.tmpcand, _state); + for(j=0; j<=state->rbfmodel.currentcloudsize-1; j++) + { + raddvr(n, -rdotvr(n, &state->rbfmodel.tmpcand, &state->rbfmodel.residualdisplacements, j, _state)/v, &state->rbfmodel.tmpcand, &state->rbfmodel.residualdisplacements, j, _state); + } + rmulv(n, (double)1/ae_sqrt(v, _state), &state->rbfmodel.tmpcand, _state); + + /* + * Add to the working set and Q, mark as unavailable and update DistFromChosen[] + */ + rgrowrowsfixedcolsm(state->rbfmodel.curwrksetsize+1, n+m+cntnlc, &state->rbfmodel.curwrkset, _state); + rcopyrr(n+m+cntnlc, &state->rbfmodel.currentcloud, i, &state->rbfmodel.curwrkset, state->rbfmodel.curwrksetsize, _state); + rgrowrowsfixedcolsm(state->rbfmodel.curwrksetsize+1, n, &state->rbfmodel.q, _state); + rcopyvr(n, &state->rbfmodel.tmpcand, &state->rbfmodel.q, state->rbfmodel.curwrksetsize, _state); + state->rbfmodel.available.ptr.p_bool[i] = ae_false; + state->rbfmodel.curwrksetsize = state->rbfmodel.curwrksetsize+1; + for(j=0; j<=state->rbfmodel.currentcloudsize-1; j++) + { + v = (double)(0); + for(k=0; k<=n-1; k++) + { + v = ae_maxreal(v, ae_fabs(state->rbfmodel.currentcloud.ptr.pp_double[i][k]-state->rbfmodel.currentcloud.ptr.pp_double[j][k], _state)*state->invtrustregion.ptr.p_double[k], _state); + } + state->rbfmodel.distfromchosen.ptr.p_double[j] = ae_minreal(state->rbfmodel.distfromchosen.ptr.p_double[j], v, _state); + } + } + ae_assert(state->rbfmodel.curwrksetsize<=n, "DFGM: integrity check 779633 failed", _state); + + /* + * Failed to sample N linearly independent directions from the cloud; perform additional + * sampling by generating random points within trust region. Due to box constraints it + * is not easy to generate a direction orthogonal to the current Q which does not violate + * box constraints, so we generate a random feasible point and check its orthogonality + * properties with respect to Q. Actually, we generate many such points and perform a + * competition amongst them. + */ +lbl_16: + if( state->rbfmodel.curwrksetsize>=n ) + { + goto lbl_17; + } + + /* + * Run the competition + */ + state->rbfmodel.winnerrating = (double)(0); + rcopyallocv(n, &state->xk, &state->rbfmodel.tmpwinner, _state); + rallocv(n, &state->rbfmodel.tmpcand, _state); + k = 0; + while(k<5||ae_fp_eq(state->rbfmodel.winnerrating,(double)(0))) + { + + /* + * Generate random point within a box + */ + for(i=0; i<=n-1; i++) + { + v = ae_maxreal(state->xk.ptr.p_double[i]-state->trustregion.ptr.p_double[i], state->finitebndl.ptr.p_double[i], _state); + vv = ae_minreal(state->xk.ptr.p_double[i]+state->trustregion.ptr.p_double[i], state->finitebndu.ptr.p_double[i], _state); + state->rbfmodel.tmpcand.ptr.p_double[i] = boundval(v+(vv-v)*hqrnduniformr(&state->rs, _state), state->finitebndl.ptr.p_double[i], state->finitebndu.ptr.p_double[i], _state); + } + + /* + * Compute displacement and orthogonalize it wrt Q, compare residual with the largest one so far + */ + rcopyallocv(n, &state->rbfmodel.tmpcand, &state->rbfmodel.tmpdisp, _state); + raddv(n, -1.0, &state->xk, &state->rbfmodel.tmpdisp, _state); + rmergemulv(n, &state->invtrustregion, &state->rbfmodel.tmpdisp, _state); + rmulv(n, (double)1/ae_sqrt(ae_machineepsilon+rdotv2(n, &state->rbfmodel.tmpdisp, _state), _state), &state->rbfmodel.tmpdisp, _state); + rowwisegramschmidt(&state->rbfmodel.q, state->rbfmodel.curwrksetsize, n, &state->rbfmodel.tmpdisp, &state->tmp0, ae_false, _state); + v = ae_sqrt(rdotv2(n, &state->rbfmodel.tmpdisp, _state), _state); + if( ae_fp_greater(v,(double)(0))&&ae_fp_greater(v,state->rbfmodel.winnerrating) ) + { + state->rbfmodel.winnerrating = v; + rcopyv(n, &state->rbfmodel.tmpcand, &state->rbfmodel.tmpwinner, _state); + } + + /* + * Next try, check for eternal loop + */ + k = k+1; + ae_assert(k<1000, "DFGM: integrity check 848747 failed (eternal loop in model-improving points generation)", _state); + } + + /* + * Issue RComm V2 request for the winner, check that the reply does not contain infinities + */ + state->requesttype = 4; + state->querysize = 1; + rcopyallocv(n, &state->rbfmodel.tmpwinner, &state->querydata, _state); + rallocv(m+cntnlc, &state->replyfi, _state); + dfgenmod_sendrequesttocloud(state, &state->querydata, state->querysize, _state); + state->rstateimprove.stage = 2; + goto lbl_rcomm; +lbl_2: + if( !isfinitevector(&state->replyfi, (m+cntnlc)*state->querysize, _state) ) + { + + /* + * Decrease trust radius and retry + */ + if( state->dotrace ) + { + ae_trace("[WARNING] target at the geometry-improving point is infinite, decreasing trust radius and restarting iteration\n"); + } + state->infinitiesencountered = ae_true; + state->recoveredfrominfinities = ae_false; + dfgenmod_updatetrustregion(state, dfgenmod_gammabad*state->trustradfactor, _state); + state->trustradbnd = ae_minreal(state->trustradfactor, state->trustradbnd, _state); + if( ae_fp_less(state->trustradfactor,coalesce(state->epsx, state->toosmalltrustrad, _state)) ) + { + state->repterminationtype = -8; + result = ae_false; + return result; + } + goto lbl_16; + } + dfgenmod_sendreplytocloud(state, &state->replyfi, _state); + rgrowrowsfixedcolsm(state->rbfmodel.curwrksetsize+1, n+m+cntnlc, &state->rbfmodel.curwrkset, _state); + for(j=0; j<=n-1; j++) + { + state->rbfmodel.curwrkset.ptr.pp_double[state->rbfmodel.curwrksetsize][j] = state->rbfmodel.tmpwinner.ptr.p_double[j]; + } + for(j=0; j<=m+cntnlc-1; j++) + { + state->rbfmodel.curwrkset.ptr.pp_double[state->rbfmodel.curwrksetsize][n+j] = state->replyfi.ptr.p_double[j]; + } + rcopyallocv(n, &state->rbfmodel.tmpwinner, &state->rbfmodel.tmpdisp, _state); + raddv(n, -1.0, &state->xk, &state->rbfmodel.tmpdisp, _state); + rmergemulv(n, &state->invtrustregion, &state->rbfmodel.tmpdisp, _state); + rowwisegramschmidt(&state->rbfmodel.q, state->rbfmodel.curwrksetsize, n, &state->rbfmodel.tmpdisp, &state->tmp0, ae_false, _state); + rmulv(n, (double)1/ae_sqrt(rdotv2(n, &state->rbfmodel.tmpdisp, _state), _state), &state->rbfmodel.tmpdisp, _state); + rcopyvr(n, &state->rbfmodel.tmpdisp, &state->rbfmodel.q, state->rbfmodel.curwrksetsize, _state); + state->rbfmodel.curwrksetsize = state->rbfmodel.curwrksetsize+1; + goto lbl_16; +lbl_17: + ae_assert(state->rbfmodel.curwrksetsize==n, "DFGM: integrity check 902742 failed", _state); + + /* + * Select additional points for RBF model, apply several rounds with search radius decreasing + * by 2x each iteration. Such multilayered approach allows us to capture reuse and capture info + * about both far away and close points. + */ + roundradius = dfgenmod_rbftheta0; + for(roundidx=0; roundidx<=3; roundidx++) + { + chosenduringround = 0; + while(chosenduringroundrbfmodel.currentcloudsize-1; i++) + { + if( !state->rbfmodel.available.ptr.p_bool[i] ) + { + continue; + } + if( ae_fp_less_eq(state->rbfmodel.distfromchosen.ptr.p_double[i],dfgenmod_rbfmindist) ) + { + continue; + } + if( ae_fp_greater(state->rbfmodel.distfromcenter.ptr.p_double[i],roundradius) ) + { + continue; + } + vv = state->rbfmodel.distfromchosen.ptr.p_double[i]; + if( k<0||ae_fp_greater(vv,v) ) + { + k = i; + v = vv; + } + } + if( k<0 ) + { + break; + } + i = k; + + /* + * Add to the working set and Q, mark as unavailable and update DistFromChosen[] + */ + rgrowrowsfixedcolsm(state->rbfmodel.curwrksetsize+1, n+m+cntnlc, &state->rbfmodel.curwrkset, _state); + rcopyrr(n+m+cntnlc, &state->rbfmodel.currentcloud, i, &state->rbfmodel.curwrkset, state->rbfmodel.curwrksetsize, _state); + state->rbfmodel.available.ptr.p_bool[i] = ae_false; + state->rbfmodel.curwrksetsize = state->rbfmodel.curwrksetsize+1; + for(j=0; j<=state->rbfmodel.currentcloudsize-1; j++) + { + v = (double)(0); + for(k=0; k<=n-1; k++) + { + v = ae_maxreal(v, ae_fabs(state->rbfmodel.currentcloud.ptr.pp_double[i][k]-state->rbfmodel.currentcloud.ptr.pp_double[j][k], _state)*state->invtrustregion.ptr.p_double[k], _state); + } + state->rbfmodel.distfromchosen.ptr.p_double[j] = ae_minreal(state->rbfmodel.distfromchosen.ptr.p_double[j], v, _state); + } + chosenduringround = chosenduringround+1; + } + roundradius = 0.5*roundradius; + } + + /* + * Append the central point to the working set + */ + rgrowrowsfixedcolsm(state->rbfmodel.curwrksetsize+1, n+m+cntnlc, &state->rbfmodel.curwrkset, _state); + for(i=0; i<=n-1; i++) + { + state->rbfmodel.curwrkset.ptr.pp_double[state->rbfmodel.curwrksetsize][i] = state->xk.ptr.p_double[i]; + } + for(i=0; i<=m+cntnlc-1; i++) + { + state->rbfmodel.curwrkset.ptr.pp_double[state->rbfmodel.curwrksetsize][n+i] = state->fkvec.ptr.p_double[i]; + } + state->rbfmodel.curwrksetsize = state->rbfmodel.curwrksetsize+1; + + /* + * Replace working set with the newly constructed one + */ + state->wrksetsize = state->rbfmodel.curwrksetsize; + rgrowrowsfixedcolsm(state->wrksetsize, n+m+cntnlc, &state->wrkset, _state); + rcopym(state->wrksetsize, n+m+cntnlc, &state->rbfmodel.curwrkset, &state->wrkset, _state); + + /* + * Done + */ + result = ae_false; + return result; +lbl_14: + ae_assert(ae_false, "DFGM: ImproveWorkingSetGeometry() is unable to handle unexpected algorithm", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstateimprove.ia.ptr.p_int[0] = n; + state->rstateimprove.ia.ptr.p_int[1] = m; + state->rstateimprove.ia.ptr.p_int[2] = cntlc; + state->rstateimprove.ia.ptr.p_int[3] = cntnlc; + state->rstateimprove.ia.ptr.p_int[4] = i; + state->rstateimprove.ia.ptr.p_int[5] = j; + state->rstateimprove.ia.ptr.p_int[6] = k; + state->rstateimprove.ia.ptr.p_int[7] = improveidx; + state->rstateimprove.ia.ptr.p_int[8] = improvedfar; + state->rstateimprove.ia.ptr.p_int[9] = leastdistantidx; + state->rstateimprove.ia.ptr.p_int[10] = mostdistantidx; + state->rstateimprove.ia.ptr.p_int[11] = replaceidx; + state->rstateimprove.ia.ptr.p_int[12] = roundidx; + state->rstateimprove.ia.ptr.p_int[13] = chosenduringround; + state->rstateimprove.ba.ptr.p_bool[0] = workingsetchanged; + state->rstateimprove.ra.ptr.p_double[0] = vlft; + state->rstateimprove.ra.ptr.p_double[1] = vrgt; + state->rstateimprove.ra.ptr.p_double[2] = v; + state->rstateimprove.ra.ptr.p_double[3] = vmin; + state->rstateimprove.ra.ptr.p_double[4] = vmax; + state->rstateimprove.ra.ptr.p_double[5] = x0i; + state->rstateimprove.ra.ptr.p_double[6] = leastdistant; + state->rstateimprove.ra.ptr.p_double[7] = mostdistant; + state->rstateimprove.ra.ptr.p_double[8] = mx; + state->rstateimprove.ra.ptr.p_double[9] = rating; + state->rstateimprove.ra.ptr.p_double[10] = bestrating; + state->rstateimprove.ra.ptr.p_double[11] = vv; + state->rstateimprove.ra.ptr.p_double[12] = roundradius; + return result; +} + + +/************************************************************************* +Compute maximum absolute value of a Lagrange polynomial given by its +coefficients vector C[] and value at the trust region center C0 over trust +region. + +Returns maximum absolute value and, optionally, point where the maximum +is obtained. + +if NeedX is True, then X must be preallocated array[N], and tmpX must also +be preallocated array[N]. If NeedX is False, X and tmpX are not referenced. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static double dfgenmod_maxabslag(/* Real */ const ae_vector* xk, + ae_int_t n, + /* Real */ const ae_vector* trustregion, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + /* Real */ const ae_vector* c, + double c0, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmpx, + ae_bool needx, + ae_state *_state) +{ + double vmin; + double vmax; + double vlft; + double vrgt; + double xmin; + double xmax; + double xki; + double ci; + ae_int_t i; + double result; + + + ae_assert(!needx||x->cnt>=n, "DFGM: integrity check 5616 failed", _state); + ae_assert(!needx||tmpx->cnt>=n, "DFGM: integrity check 5716 failed", _state); + vmin = c0; + vmax = c0; + for(i=0; i<=n-1; i++) + { + xki = xk->ptr.p_double[i]; + ci = c->ptr.p_double[i]; + vlft = ae_maxreal(xki-trustregion->ptr.p_double[i], finitebndl->ptr.p_double[i], _state); + vrgt = ae_minreal(xki+trustregion->ptr.p_double[i], finitebndu->ptr.p_double[i], _state); + xmin = rcase2(ae_fp_greater_eq(ci,(double)(0)), vlft, vrgt, _state); + xmax = rcase2(ae_fp_less_eq(ci,(double)(0)), vlft, vrgt, _state); + vmin = vmin+(xmin-xki)*ci; + vmax = vmax+(xmax-xki)*ci; + if( needx ) + { + x->ptr.p_double[i] = xmin; + tmpx->ptr.p_double[i] = xmax; + } + } + result = ae_maxreal(ae_fabs(vmin, _state), ae_fabs(vmax, _state), _state); + if( needx&&ae_fp_less(ae_fabs(vmin, _state),ae_fabs(vmax, _state)) ) + { + rcopyv(n, tmpx, x, _state); + } + return result; +} + + +/************************************************************************* +Compute distance to the most distant and the least distant neighbors in the +working set. The distance is computed using L-inf metric, per-variable +distances are divided by min(DeltaK,BndU[I]-BndL[I]). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_mostandleastdistant(/* Real */ const ae_vector* invtrustregion, + ae_int_t n, + /* Real */ const ae_matrix* wrkset, + ae_int_t wrksetsize, + double* mostdistant, + ae_int_t* mostdistantidx, + double* leastdistant, + ae_int_t* leastdistantidx, + ae_state *_state) +{ + double mx; + ae_int_t i; + ae_int_t j; + ae_int_t centralidx; + + *mostdistant = 0.0; + *mostdistantidx = 0; + *leastdistant = 0.0; + *leastdistantidx = 0; + + + /* + * Find most distant and least distant neighbors, + */ + *mostdistant = 0.0; + *mostdistantidx = -1; + *leastdistant = 1.0E50; + *leastdistantidx = -1; + centralidx = wrksetsize-1; + for(i=0; i<=wrksetsize-2; i++) + { + mx = (double)(0); + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(wrkset->ptr.pp_double[i][j]-wrkset->ptr.pp_double[centralidx][j], _state)*invtrustregion->ptr.p_double[j], _state); + } + if( *mostdistantidx<0||ae_fp_greater(mx,*mostdistant) ) + { + *mostdistant = mx; + *mostdistantidx = i; + } + if( *leastdistantidx<0||ae_fp_less(mx,*leastdistant) ) + { + *leastdistant = mx; + *leastdistantidx = i; + } + } +} + + +/************************************************************************* +This function initializes state of the points cloud: whether all evaluated +target values are saved to cloud or not. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_initcloud(dfgmstate* state, + ae_bool savetocloud, + ae_state *_state) +{ + + + state->savepointstocloud = savetocloud; + state->cloudsize = 0; + state->cloudpendingcnt = 0; +} + + +/************************************************************************* +This function saves request information to the cloud; points locations are +saved in the special 'pending' queue, waiting to be augmented with request +reply (target values). + +If the cloud is not used, it does nothing. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_sendrequesttocloud(dfgmstate* state, + /* Real */ const ae_vector* querydata, + ae_int_t requestsize, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + + if( !state->savepointstocloud ) + { + return; + } + rgrowrowsfixedcolsm(requestsize, state->n, &state->cloudpending, _state); + for(i=0; i<=requestsize-1; i++) + { + for(j=0; j<=state->n-1; j++) + { + state->cloudpending.ptr.pp_double[i][j] = querydata->ptr.p_double[i*state->n+j]; + } + } + state->cloudpendingcnt = requestsize; +} + + +/************************************************************************* +This function sends to the cloud target values at the pending points (ones +previously posted with sendrequesttocloud). The amount of values sent now +must exactly match amount of previously posted values. + +If cloud is not used, it does nothing. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_sendreplytocloud(dfgmstate* state, + /* Real */ const ae_vector* replyfi, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t replyentrysize; + + + if( !state->savepointstocloud ) + { + return; + } + rgrowrowsfixedcolsm(state->cloudsize+state->cloudpendingcnt, state->n+state->m+state->cntnlc, &state->clouddata, _state); + replyentrysize = state->m+state->cntnlc; + for(i=0; i<=state->cloudpendingcnt-1; i++) + { + for(j=0; j<=state->n-1; j++) + { + state->clouddata.ptr.pp_double[state->cloudsize+i][j] = state->cloudpending.ptr.pp_double[i][j]; + } + for(j=0; j<=replyentrysize-1; j++) + { + state->clouddata.ptr.pp_double[state->cloudsize+i][state->n+j] = replyfi->ptr.p_double[i*replyentrysize+j]; + } + } + state->cloudsize = state->cloudsize+state->cloudpendingcnt; + state->cloudpendingcnt = 0; +} + + +/************************************************************************* +This function clears the points cloud. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_clearcloud(dfgmstate* state, ae_state *_state) +{ + + + state->cloudsize = 0; + state->cloudpendingcnt = 0; +} + + +/************************************************************************* +This function performs initial construction of an RBF model. It must be +called once at the initial working set generation. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_rbfinitializemodelfromworkingset(dfgmstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t ws; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t fidx; + double v; + ae_matrix rbfsys; + ae_vector sol; + ae_vector rhs; + ae_vector sol2; + ae_matrix rrhs; + ae_matrix ssol; + + ae_frame_make(_state, &_frame_block); + memset(&rbfsys, 0, sizeof(rbfsys)); + memset(&sol, 0, sizeof(sol)); + memset(&rhs, 0, sizeof(rhs)); + memset(&sol2, 0, sizeof(sol2)); + memset(&rrhs, 0, sizeof(rrhs)); + memset(&ssol, 0, sizeof(ssol)); + ae_matrix_init(&rbfsys, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sol, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rhs, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sol2, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&rrhs, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ssol, 0, 0, DT_REAL, _state, ae_true); + + n = state->n; + ws = state->wrksetsize; + ae_assert(state->modeltype==2, "DFGM: integrity check 211136 failed", _state); + ae_assert(ws>=n+1, "DFGM: integrity check 211137 failed", _state); + ae_assert(state->m==1, "DFGM: integrity check 211138 failed", _state); + rsetallocm(ws+n+1, ws+n+1, 0.0, &rbfsys, _state); + for(i=0; i<=ws-1; i++) + { + for(j=0; j<=i; j++) + { + v = (double)(0); + for(k=0; k<=n-1; k++) + { + v = v+ae_sqr((state->wrkset.ptr.pp_double[i][k]-state->wrkset.ptr.pp_double[j][k])*state->invtrustregion.ptr.p_double[k], _state); + } + v = v*ae_sqrt(v, _state); + rbfsys.ptr.pp_double[i][j] = v; + rbfsys.ptr.pp_double[j][i] = v; + } + } + for(i=0; i<=n-1; i++) + { + for(j=0; j<=ws-1; j++) + { + rbfsys.ptr.pp_double[ws+i][j] = (state->wrkset.ptr.pp_double[j][i]-state->wrkset.ptr.pp_double[ws-1][i])*state->invtrustregion.ptr.p_double[i]; + rbfsys.ptr.pp_double[j][ws+i] = rbfsys.ptr.pp_double[ws+i][j]; + } + } + for(j=0; j<=ws-1; j++) + { + rbfsys.ptr.pp_double[ws+n][j] = 1.0; + rbfsys.ptr.pp_double[j][ws+n] = 1.0; + } + state->rbfmodel.modelbase = state->wrkset.ptr.pp_double[ws-1][n]; + v = (double)(0); + for(i=0; i<=ws-1; i++) + { + v = v+ae_sqr(state->wrkset.ptr.pp_double[i][n]-state->rbfmodel.modelbase, _state); + } + state->rbfmodel.modelscale = ae_sqrt(coalesce(v, (double)(1), _state)/(double)ws, _state); + state->rbfmodel.ncenters = ws; + rgrowrowsfixedcolsm(ws, n, &state->rbfmodel.centers, _state); + rcopym(ws, n, &state->wrkset, &state->rbfmodel.centers, _state); + rallocv(n, &state->rbfmodel.x0, _state); + rcopyrv(n, &state->wrkset, ws-1, &state->rbfmodel.x0, _state); + rcopyallocv(n, &state->invtrustregion, &state->rbfmodel.multscale, _state); + rsetallocm(1+state->cntnlc, ws+n+1, 0.0, &rrhs, _state); + rallocm(1+state->cntnlc, ws, &state->rbfmodel.crbf, _state); + rallocm(1+state->cntnlc, n+1, &state->rbfmodel.clinear, _state); + for(fidx=0; fidx<=state->cntnlc; fidx++) + { + for(i=0; i<=ws-1; i++) + { + rrhs.ptr.pp_double[fidx][i] = (state->wrkset.ptr.pp_double[i][n+fidx]-state->rbfmodel.modelbase)/state->rbfmodel.modelscale; + } + } + dfgenmod_rbfsolvecpdm(&rbfsys, &rrhs, ws, 1+state->cntnlc, n, 0.0, ae_true, &ssol, _state); + rcopym(1+state->cntnlc, ws, &ssol, &state->rbfmodel.crbf, _state); + for(fidx=0; fidx<=state->cntnlc; fidx++) + { + for(i=0; i<=n; i++) + { + state->rbfmodel.clinear.ptr.pp_double[fidx][i] = ssol.ptr.pp_double[fidx][ws+i]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function computes RBF model at the required point. May return model +value and its gradient. + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_rbfcomputemodel(dfgmstate* state, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* f, + ae_bool needf, + /* Real */ ae_vector* g, + ae_bool needg, + ae_state *_state) +{ + ae_int_t cntnlc; + ae_int_t n; + ae_int_t j; + ae_int_t k; + ae_int_t fidx; + double v; + double r; + double vf; + + + n = state->n; + cntnlc = state->cntnlc; + ae_assert(!needf||f->cnt>=1+state->cntnlc, "DFGM: integrity check 419111 failed", _state); + ae_assert(!needg||g->cnt>=(1+state->cntnlc)*n, "DFGM: integrity check 419112 failed", _state); + if( needf ) + { + rsetv(1+cntnlc, 0.0, f, _state); + } + if( needg ) + { + rsetv((1+state->cntnlc)*n, 0.0, g, _state); + } + for(fidx=0; fidx<=cntnlc; fidx++) + { + vf = (double)(0); + for(j=0; j<=state->rbfmodel.ncenters-1; j++) + { + r = (double)(0); + for(k=0; k<=n-1; k++) + { + v = (x->ptr.p_double[k]-state->rbfmodel.centers.ptr.pp_double[j][k])*state->rbfmodel.multscale.ptr.p_double[k]; + r = r+v*v; + } + r = ae_sqrt(r, _state); + vf = vf+state->rbfmodel.crbf.ptr.pp_double[fidx][j]*(r*r*r); + if( needg ) + { + for(k=0; k<=n-1; k++) + { + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+state->rbfmodel.crbf.ptr.pp_double[fidx][j]*(double)3*r*(x->ptr.p_double[k]-state->rbfmodel.centers.ptr.pp_double[j][k])*state->rbfmodel.multscale.ptr.p_double[k]*state->rbfmodel.multscale.ptr.p_double[k]; + } + } + } + for(k=0; k<=n-1; k++) + { + vf = vf+state->rbfmodel.clinear.ptr.pp_double[fidx][k]*(x->ptr.p_double[k]-state->rbfmodel.x0.ptr.p_double[k])*state->rbfmodel.multscale.ptr.p_double[k]; + if( needg ) + { + g->ptr.p_double[fidx*n+k] = g->ptr.p_double[fidx*n+k]+state->rbfmodel.clinear.ptr.pp_double[fidx][k]*state->rbfmodel.multscale.ptr.p_double[k]; + } + } + vf = vf+state->rbfmodel.clinear.ptr.pp_double[fidx][n]; + if( needf ) + { + f->ptr.p_double[fidx] = vf*state->rbfmodel.modelscale+state->rbfmodel.modelbase; + } + if( needg ) + { + rmulvx(n, state->rbfmodel.modelscale, g, fidx*n, _state); + } + } +} + + +/************************************************************************* +This function solves RBF system using conditionally positive definiteness +if possible. + +INPUT PARAMETERS: + A array[NCenters+NX,NCenters], basis function matrix and + linear polynomial values + B array[NCenters], target values + NCenters centers count + NX space dimensionality + LambdaV smoothing parameter, LambdaV>=0 + isCPD whether basis is conditionally positive definite or not + + + -- ALGLIB -- + Copyright 15.10.2024 by Bochkanov Sergey +*************************************************************************/ +static void dfgenmod_rbfsolvecpdm(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* bb, + ae_int_t ncenters, + ae_int_t nrhs, + ae_int_t nx, + double lambdav, + ae_bool iscpd, + /* Real */ ae_matrix* ssol, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t ncoeff; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double mx; + double reg; + ae_int_t ortbasissize; + ae_matrix q; + ae_matrix q1; + ae_matrix r; + ae_vector c; + ae_vector y; + ae_vector z; + ae_vector ortbasismap; + ae_vector choltmp; + + ae_frame_make(_state, &_frame_block); + memset(&q, 0, sizeof(q)); + memset(&q1, 0, sizeof(q1)); + memset(&r, 0, sizeof(r)); + memset(&c, 0, sizeof(c)); + memset(&y, 0, sizeof(y)); + memset(&z, 0, sizeof(z)); + memset(&ortbasismap, 0, sizeof(ortbasismap)); + memset(&choltmp, 0, sizeof(choltmp)); + ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&q1, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&z, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ortbasismap, 0, DT_INT, _state, ae_true); + ae_vector_init(&choltmp, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "DFGM: integrity check 854519 failed", _state); + ae_assert(iscpd, "DFGM: integrity check 855520 failed", _state); + ncoeff = ncenters+nx+1; + reg = ae_sqrt(ae_machineepsilon, _state); + + /* + * First, compute orthogonal basis of space spanned by polynomials of degree 1 + */ + rallocm(ncenters, ncenters, &r, _state); + rallocm(nx+1, ncenters, &q1, _state); + iallocv(nx+1, &ortbasismap, _state); + rsetr(ncenters, (double)1/ae_sqrt((double)(ncenters), _state), &q1, 0, _state); + r.ptr.pp_double[0][0] = ae_sqrt((double)(ncenters), _state); + ortbasismap.ptr.p_int[0] = nx; + ortbasissize = 1; + rallocv(ncenters, &z, _state); + for(k=0; k<=nx-1; k++) + { + for(j=0; j<=ncenters-1; j++) + { + z.ptr.p_double[j] = a->ptr.pp_double[ncenters+k][j]; + } + v = ae_sqrt(rdotv2(ncenters, &z, _state), _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_true, _state); + vv = ae_sqrt(rdotv2(ncenters, &z, _state), _state); + if( ae_fp_greater(vv,ae_sqrt(ae_machineepsilon, _state)*(v+(double)1)) ) + { + rcopymulvr(ncenters, (double)1/vv, &z, &q1, ortbasissize, _state); + rcopyvc(ortbasissize, &y, &r, ortbasissize, _state); + r.ptr.pp_double[ortbasissize][ortbasissize] = vv; + ortbasismap.ptr.p_int[ortbasissize] = k; + ortbasissize = ortbasissize+1; + } + } + + /* + * Second, compute system matrix Q and target values for cardinal basis functions B. + * + * The Q is conditionally positive definite, i.e. x'*Q*x>0 for any x satisfying orthogonality conditions + * (orthogonal with respect to basis stored in Q1). + */ + rsetallocm(ncenters, ncenters, 0.0, &q, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrr(ncenters, a, i, &q, i, _state); + } + rallocm(nrhs, ncoeff, ssol, _state); + rcopym(nrhs, ncenters, bb, ssol, _state); + for(i=0; i<=ncenters-1; i++) + { + q.ptr.pp_double[i][i] = q.ptr.pp_double[i][i]+lambdav; + } + + /* + * Transform Q from conditionally positive definite to the (simply) positive definite one: + * multiply linear system Q*x=RHS from both sides by (I-Q1'*Q1), apply additional regularization. + * + * NOTE: RHS is also multiplied by (I-Q1'*Q1), but from the left only. + */ + rallocv(ncenters, &z, _state); + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &q, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvr(ncenters, &z, &q, i, _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopycv(ncenters, &q, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvc(ncenters, &z, &q, i, _state); + } + for(i=0; i<=nrhs-1; i++) + { + rcopyrv(ncenters, ssol, i, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_false, _state); + rcopyvr(ncenters, &z, ssol, i, _state); + } + mx = 1.0; + for(i=0; i<=ncenters-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(q.ptr.pp_double[i][i], _state), _state); + } + for(i=0; i<=ncenters-1; i++) + { + rcopyrv(ncenters, &q, i, &z, _state); + for(j=0; j<=ortbasissize-1; j++) + { + raddrv(ncenters, mx*q1.ptr.pp_double[j][i], &q1, j, &z, _state); + } + rcopyvr(ncenters, &z, &q, i, _state); + } + for(i=0; i<=ncenters-1; i++) + { + q.ptr.pp_double[i][i] = q.ptr.pp_double[i][i]+reg*mx; + } + + /* + * Perform Cholesky factorization, solve and obtain RBF coefficients (we still have + * to compute polynomial term - it will be done later) + */ + if( !spdmatrixcholeskyrec(&q, 0, ncenters, ae_false, &choltmp, _state) ) + { + ae_assert(ae_false, "GENMOD: RBF solver failed due to extreme degeneracy", _state); + } + rmatrixrighttrsm(nrhs, ncenters, &q, 0, 0, ae_false, ae_false, 1, ssol, 0, 0, _state); + rmatrixrighttrsm(nrhs, ncenters, &q, 0, 0, ae_false, ae_false, 0, ssol, 0, 0, _state); + + /* + * Now, having RBF coefficients we can compute residual from fitting ACBF targets + * with pure RBF term and fit polynomial term to this residual. In the ideal world + * it should result in the nice and precise polynomial coefficients. + */ + rallocv(ncenters, &z, _state); + rallocv(ncenters, &c, _state); + for(i=0; i<=nrhs-1; i++) + { + rcopyrv(ncenters, bb, i, &z, _state); + rcopyrv(ncenters, ssol, i, &c, _state); + rgemv(ncenters, ncenters, -1.0, a, 0, &c, 1.0, &z, _state); + rowwisegramschmidt(&q1, ortbasissize, ncenters, &z, &y, ae_true, _state); + rmatrixtrsv(ortbasissize, &r, 0, 0, ae_true, ae_false, 0, &y, 0, _state); + for(j=0; j<=nx; j++) + { + ssol->ptr.pp_double[i][ncenters+j] = 0.0; + } + for(j=0; j<=ortbasissize-1; j++) + { + ssol->ptr.pp_double[i][ncenters+ortbasismap.ptr.p_int[j]] = y.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +void _df2psmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + df2psmodel *p = (df2psmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->deltas, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jac, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _df2psmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + df2psmodel *dst = (df2psmodel*)_dst; + const df2psmodel *src = (const df2psmodel*)_src; + ae_vector_init_copy(&dst->deltas, &src->deltas, _state, make_automatic); + ae_matrix_init_copy(&dst->jac, &src->jac, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); +} + + +void _df2psmodel_clear(void* _p) +{ + df2psmodel *p = (df2psmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->deltas); + ae_matrix_clear(&p->jac); + ae_vector_clear(&p->g); + ae_matrix_clear(&p->q); +} + + +void _df2psmodel_destroy(void* _p) +{ + df2psmodel *p = (df2psmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->deltas); + ae_matrix_destroy(&p->jac); + ae_vector_destroy(&p->g); + ae_matrix_destroy(&p->q); +} + + +void _dfolsamodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfolsamodel *p = (dfolsamodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->w, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->invw, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->jac, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmprhs, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _dfolsamodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfolsamodel *dst = (dfolsamodel*)_dst; + const dfolsamodel *src = (const dfolsamodel*)_src; + ae_matrix_init_copy(&dst->w, &src->w, _state, make_automatic); + ae_matrix_init_copy(&dst->invw, &src->invw, _state, make_automatic); + ae_matrix_init_copy(&dst->jac, &src->jac, _state, make_automatic); + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_matrix_init_copy(&dst->tmprhs, &src->tmprhs, _state, make_automatic); +} + + +void _dfolsamodel_clear(void* _p) +{ + dfolsamodel *p = (dfolsamodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->w); + ae_matrix_clear(&p->invw); + ae_matrix_clear(&p->jac); + ae_vector_clear(&p->g); + ae_matrix_clear(&p->q); + ae_vector_clear(&p->tmp0); + ae_matrix_clear(&p->tmprhs); +} + + +void _dfolsamodel_destroy(void* _p) +{ + dfolsamodel *p = (dfolsamodel*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->w); + ae_matrix_destroy(&p->invw); + ae_matrix_destroy(&p->jac); + ae_vector_destroy(&p->g); + ae_matrix_destroy(&p->q); + ae_vector_destroy(&p->tmp0); + ae_matrix_destroy(&p->tmprhs); +} + + +void _dforbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dforbfmodel *p = (dforbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->multscale, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->centers, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->crbf, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->clinear, 0, 0, DT_REAL, _state, make_automatic); + _minfsqpstate_init(&p->fsqpsolver, _state, make_automatic); + ae_matrix_init(&p->currentcloud, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->distfromcenter, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->distfromchosen, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->available, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->curwrkset, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->residualdisplacements, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->q, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcand, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdisp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpwinner, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmps, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->cx, _state, make_automatic); + ae_vector_init(&p->clx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cux, 0, DT_REAL, _state, make_automatic); + _nlpstoppingcriteria_init(&p->crit, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); +} + + +void _dforbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dforbfmodel *dst = (dforbfmodel*)_dst; + const dforbfmodel *src = (const dforbfmodel*)_src; + dst->ncenters = src->ncenters; + dst->modelbase = src->modelbase; + dst->modelscale = src->modelscale; + ae_vector_init_copy(&dst->multscale, &src->multscale, _state, make_automatic); + ae_matrix_init_copy(&dst->centers, &src->centers, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_matrix_init_copy(&dst->crbf, &src->crbf, _state, make_automatic); + ae_matrix_init_copy(&dst->clinear, &src->clinear, _state, make_automatic); + _minfsqpstate_init_copy(&dst->fsqpsolver, &src->fsqpsolver, _state, make_automatic); + ae_matrix_init_copy(&dst->currentcloud, &src->currentcloud, _state, make_automatic); + dst->currentcloudsize = src->currentcloudsize; + ae_vector_init_copy(&dst->distfromcenter, &src->distfromcenter, _state, make_automatic); + ae_vector_init_copy(&dst->distfromchosen, &src->distfromchosen, _state, make_automatic); + ae_vector_init_copy(&dst->available, &src->available, _state, make_automatic); + ae_matrix_init_copy(&dst->curwrkset, &src->curwrkset, _state, make_automatic); + dst->curwrksetsize = src->curwrksetsize; + ae_matrix_init_copy(&dst->residualdisplacements, &src->residualdisplacements, _state, make_automatic); + ae_matrix_init_copy(&dst->q, &src->q, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcand, &src->tmpcand, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdisp, &src->tmpdisp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpwinner, &src->tmpwinner, _state, make_automatic); + ae_vector_init_copy(&dst->tmpbndl, &src->tmpbndl, _state, make_automatic); + ae_vector_init_copy(&dst->tmpbndu, &src->tmpbndu, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx0, &src->tmpx0, _state, make_automatic); + ae_vector_init_copy(&dst->tmps, &src->tmps, _state, make_automatic); + dst->winnerrating = src->winnerrating; + _sparsematrix_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->clx, &src->clx, _state, make_automatic); + ae_vector_init_copy(&dst->cux, &src->cux, _state, make_automatic); + _nlpstoppingcriteria_init_copy(&dst->crit, &src->crit, _state, make_automatic); + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); +} + + +void _dforbfmodel_clear(void* _p) +{ + dforbfmodel *p = (dforbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->multscale); + ae_matrix_clear(&p->centers); + ae_vector_clear(&p->x0); + ae_matrix_clear(&p->crbf); + ae_matrix_clear(&p->clinear); + _minfsqpstate_clear(&p->fsqpsolver); + ae_matrix_clear(&p->currentcloud); + ae_vector_clear(&p->distfromcenter); + ae_vector_clear(&p->distfromchosen); + ae_vector_clear(&p->available); + ae_matrix_clear(&p->curwrkset); + ae_matrix_clear(&p->residualdisplacements); + ae_matrix_clear(&p->q); + ae_vector_clear(&p->tmpcand); + ae_vector_clear(&p->tmpdisp); + ae_vector_clear(&p->tmpwinner); + ae_vector_clear(&p->tmpbndl); + ae_vector_clear(&p->tmpbndu); + ae_vector_clear(&p->tmpx0); + ae_vector_clear(&p->tmps); + _sparsematrix_clear(&p->cx); + ae_vector_clear(&p->clx); + ae_vector_clear(&p->cux); + _nlpstoppingcriteria_clear(&p->crit); + _smoothnessmonitor_clear(&p->smonitor); +} + + +void _dforbfmodel_destroy(void* _p) +{ + dforbfmodel *p = (dforbfmodel*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->multscale); + ae_matrix_destroy(&p->centers); + ae_vector_destroy(&p->x0); + ae_matrix_destroy(&p->crbf); + ae_matrix_destroy(&p->clinear); + _minfsqpstate_destroy(&p->fsqpsolver); + ae_matrix_destroy(&p->currentcloud); + ae_vector_destroy(&p->distfromcenter); + ae_vector_destroy(&p->distfromchosen); + ae_vector_destroy(&p->available); + ae_matrix_destroy(&p->curwrkset); + ae_matrix_destroy(&p->residualdisplacements); + ae_matrix_destroy(&p->q); + ae_vector_destroy(&p->tmpcand); + ae_vector_destroy(&p->tmpdisp); + ae_vector_destroy(&p->tmpwinner); + ae_vector_destroy(&p->tmpbndl); + ae_vector_destroy(&p->tmpbndu); + ae_vector_destroy(&p->tmpx0); + ae_vector_destroy(&p->tmps); + _sparsematrix_destroy(&p->cx); + ae_vector_destroy(&p->clx); + ae_vector_destroy(&p->cux); + _nlpstoppingcriteria_destroy(&p->crit); + _smoothnessmonitor_destroy(&p->smonitor); +} + + +void _dfgmstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dfgmstate *p = (dfgmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->c, _state, make_automatic); + ae_vector_init(&p->cl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _rcommstate_init(&p->rstateimprove, _state, make_automatic); + _rcommstate_init(&p->rstateupdate, _state, make_automatic); + ae_vector_init(&p->trustregion, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invtrustregion, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fpvec, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fkvec, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fnvec, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->wrkset, 0, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->rs, _state, make_automatic); + _df2psmodel_init(&p->tpsmodel, _state, make_automatic); + _dfolsamodel_init(&p->lsamodel, _state, make_automatic); + _dforbfmodel_init(&p->rbfmodel, _state, make_automatic); + _nlpfilter_init(&p->filter, _state, make_automatic); + ae_matrix_init(&p->clouddata, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cloudpending, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->successhistory, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->lastjac, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->trustradhistory, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->jacdiffhistory, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->iteridxhistory, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdeltas, 0, DT_REAL, _state, make_automatic); + _vipmstate_init(&p->ipmsolver, _state, make_automatic); + ae_matrix_init(&p->densedummy, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsedummy, _state, make_automatic); + _matinvreport_init(&p->invrep, _state, make_automatic); +} + + +void _dfgmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dfgmstate *dst = (dfgmstate*)_dst; + const dfgmstate *src = (const dfgmstate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->cntlc = src->cntlc; + dst->cntnlc = src->cntnlc; + dst->isleastsquares = src->isleastsquares; + dst->modeltype = src->modeltype; + dst->rad0 = src->rad0; + dst->nnoisyrestarts = src->nnoisyrestarts; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + _sparsematrix_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->cl, &src->cl, _state, make_automatic); + ae_vector_init_copy(&dst->cu, &src->cu, _state, make_automatic); + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->epsx = src->epsx; + dst->epsf = src->epsf; + dst->maxits = src->maxits; + dst->maxfev = src->maxfev; + dst->toosmalltrustrad = src->toosmalltrustrad; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _rcommstate_init_copy(&dst->rstateimprove, &src->rstateimprove, _state, make_automatic); + _rcommstate_init_copy(&dst->rstateupdate, &src->rstateupdate, _state, make_automatic); + dst->dotrace = src->dotrace; + ae_vector_init_copy(&dst->trustregion, &src->trustregion, _state, make_automatic); + ae_vector_init_copy(&dst->invtrustregion, &src->invtrustregion, _state, make_automatic); + dst->trustradfactor = src->trustradfactor; + dst->trustradbnd = src->trustradbnd; + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_vector_init_copy(&dst->fpvec, &src->fpvec, _state, make_automatic); + dst->fp = src->fp; + dst->hp = src->hp; + ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic); + ae_vector_init_copy(&dst->sk, &src->sk, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->fkvec, &src->fkvec, _state, make_automatic); + ae_vector_init_copy(&dst->fnvec, &src->fnvec, _state, make_automatic); + dst->fk = src->fk; + dst->hk = src->hk; + ae_matrix_init_copy(&dst->wrkset, &src->wrkset, _state, make_automatic); + dst->wrksetsize = src->wrksetsize; + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + _df2psmodel_init_copy(&dst->tpsmodel, &src->tpsmodel, _state, make_automatic); + _dfolsamodel_init_copy(&dst->lsamodel, &src->lsamodel, _state, make_automatic); + _dforbfmodel_init_copy(&dst->rbfmodel, &src->rbfmodel, _state, make_automatic); + dst->infinitiesencountered = src->infinitiesencountered; + dst->recoveredfrominfinities = src->recoveredfrominfinities; + _nlpfilter_init_copy(&dst->filter, &src->filter, _state, make_automatic); + dst->savepointstocloud = src->savepointstocloud; + ae_matrix_init_copy(&dst->clouddata, &src->clouddata, _state, make_automatic); + dst->cloudsize = src->cloudsize; + ae_matrix_init_copy(&dst->cloudpending, &src->cloudpending, _state, make_automatic); + dst->cloudpendingcnt = src->cloudpendingcnt; + dst->successhistorylen = src->successhistorylen; + dst->successhistorymax = src->successhistorymax; + dst->successhistorynext = src->successhistorynext; + ae_vector_init_copy(&dst->successhistory, &src->successhistory, _state, make_automatic); + dst->restartstoperform = src->restartstoperform; + dst->lasttrustrad = src->lasttrustrad; + ae_matrix_init_copy(&dst->lastjac, &src->lastjac, _state, make_automatic); + ae_vector_init_copy(&dst->trustradhistory, &src->trustradhistory, _state, make_automatic); + ae_vector_init_copy(&dst->jacdiffhistory, &src->jacdiffhistory, _state, make_automatic); + ae_vector_init_copy(&dst->iteridxhistory, &src->iteridxhistory, _state, make_automatic); + dst->historylen = src->historylen; + dst->historynext = src->historynext; + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdeltas, &src->tmpdeltas, _state, make_automatic); + _vipmstate_init_copy(&dst->ipmsolver, &src->ipmsolver, _state, make_automatic); + ae_matrix_init_copy(&dst->densedummy, &src->densedummy, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsedummy, &src->sparsedummy, _state, make_automatic); + _matinvreport_init_copy(&dst->invrep, &src->invrep, _state, make_automatic); + dst->repterminationtype = src->repterminationtype; + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + dst->repsubsolverits = src->repsubsolverits; +} + + +void _dfgmstate_clear(void* _p) +{ + dfgmstate *p = (dfgmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->s); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + _sparsematrix_clear(&p->c); + ae_vector_clear(&p->cl); + ae_vector_clear(&p->cu); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + _rcommstate_clear(&p->rstate); + _rcommstate_clear(&p->rstateimprove); + _rcommstate_clear(&p->rstateupdate); + ae_vector_clear(&p->trustregion); + ae_vector_clear(&p->invtrustregion); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->fpvec); + ae_vector_clear(&p->xk); + ae_vector_clear(&p->sk); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->fkvec); + ae_vector_clear(&p->fnvec); + ae_matrix_clear(&p->wrkset); + _hqrndstate_clear(&p->rs); + _df2psmodel_clear(&p->tpsmodel); + _dfolsamodel_clear(&p->lsamodel); + _dforbfmodel_clear(&p->rbfmodel); + _nlpfilter_clear(&p->filter); + ae_matrix_clear(&p->clouddata); + ae_matrix_clear(&p->cloudpending); + ae_vector_clear(&p->successhistory); + ae_matrix_clear(&p->lastjac); + ae_vector_clear(&p->trustradhistory); + ae_vector_clear(&p->jacdiffhistory); + ae_vector_clear(&p->iteridxhistory); + ae_vector_clear(&p->tmpi); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmpdeltas); + _vipmstate_clear(&p->ipmsolver); + ae_matrix_clear(&p->densedummy); + _sparsematrix_clear(&p->sparsedummy); + _matinvreport_clear(&p->invrep); +} + + +void _dfgmstate_destroy(void* _p) +{ + dfgmstate *p = (dfgmstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + _sparsematrix_destroy(&p->c); + ae_vector_destroy(&p->cl); + ae_vector_destroy(&p->cu); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + _rcommstate_destroy(&p->rstate); + _rcommstate_destroy(&p->rstateimprove); + _rcommstate_destroy(&p->rstateupdate); + ae_vector_destroy(&p->trustregion); + ae_vector_destroy(&p->invtrustregion); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->fpvec); + ae_vector_destroy(&p->xk); + ae_vector_destroy(&p->sk); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->fkvec); + ae_vector_destroy(&p->fnvec); + ae_matrix_destroy(&p->wrkset); + _hqrndstate_destroy(&p->rs); + _df2psmodel_destroy(&p->tpsmodel); + _dfolsamodel_destroy(&p->lsamodel); + _dforbfmodel_destroy(&p->rbfmodel); + _nlpfilter_destroy(&p->filter); + ae_matrix_destroy(&p->clouddata); + ae_matrix_destroy(&p->cloudpending); + ae_vector_destroy(&p->successhistory); + ae_matrix_destroy(&p->lastjac); + ae_vector_destroy(&p->trustradhistory); + ae_vector_destroy(&p->jacdiffhistory); + ae_vector_destroy(&p->iteridxhistory); + ae_vector_destroy(&p->tmpi); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmpdeltas); + _vipmstate_destroy(&p->ipmsolver); + ae_matrix_destroy(&p->densedummy); + _sparsematrix_destroy(&p->sparsedummy); + _matinvreport_destroy(&p->invrep); +} + + +#endif +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) + + +void minsqpinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + /* Real */ const ae_matrix* cleic, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t nec, + ae_int_t nic, + ae_int_t nlec, + ae_int_t nlic, + const nlpstoppingcriteria* criteria, + ae_bool usedensebfgs, + minsqpstate* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + double vv; + ae_int_t nslack; + + + nslack = n+2*(nec+nlec)+(nic+nlic); + state->n = n; + state->nec = nec; + state->nic = nic; + state->nlec = nlec; + state->nlic = nlic; + + /* + * Prepare RCOMM state + */ + ae_vector_set_length(&state->rstate.ia, 9+1, _state); + ae_vector_set_length(&state->rstate.ba, 14+1, _state); + ae_vector_set_length(&state->rstate.ra, 23+1, _state); + state->rstate.stage = -1; + state->needfij = ae_false; + state->xupdated = ae_false; + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->fi, 1+nlec+nlic, _state); + ae_matrix_set_length(&state->j, 1+nlec+nlic, n, _state); + + /* + * Allocate memory. + */ + rallocv(n, &state->x0, _state); + rallocv(n, &state->xprev, _state); + rvectorsetlengthatleast(&state->s, n, _state); + rvectorsetlengthatleast(&state->fscales, 1+nlec+nlic, _state); + rvectorsetlengthatleast(&state->tracegamma, 1+nlec+nlic, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rvectorsetlengthatleast(&state->scaledbndl, n, _state); + rvectorsetlengthatleast(&state->scaledbndu, n, _state); + rmatrixsetlengthatleast(&state->scaledcleic, nec+nic, n+1, _state); + ivectorsetlengthatleast(&state->lcsrcidx, nec+nic, _state); + rvectorsetlengthatleast(&state->dtrial, nslack, _state); + rvectorsetlengthatleast(&state->d0, nslack, _state); + rvectorsetlengthatleast(&state->d1, nslack, _state); + rvectorsetlengthatleast(&state->dmu, nslack, _state); + rvectorsetlengthatleast(&state->lagbcmult, n, _state); + rvectorsetlengthatleast(&state->dummylagbcmult, n, _state); + rvectorsetlengthatleast(&state->lagxcmult, nec+nic+nlec+nlic, _state); + rvectorsetlengthatleast(&state->dummylagxcmult, nec+nic+nlec+nlic, _state); + + /* + * Prepare scaled problem + */ + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->scaledbndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->scaledbndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "SQP: integrity check failed, box constraints are inconsistent", _state); + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + for(i=0; i<=nec+nic-1; i++) + { + + /* + * Permutation + */ + state->lcsrcidx.ptr.p_int[i] = lcsrcidx->ptr.p_int[i]; + + /* + * Scale and normalize linear constraints + */ + vv = 0.0; + for(j=0; j<=n-1; j++) + { + v = cleic->ptr.pp_double[i][j]*s->ptr.p_double[j]; + state->scaledcleic.ptr.pp_double[i][j] = v; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + state->scaledcleic.ptr.pp_double[i][n] = cleic->ptr.pp_double[i][n]; + if( ae_fp_greater(vv,(double)(0)) ) + { + for(j=0; j<=n; j++) + { + state->scaledcleic.ptr.pp_double[i][j] = state->scaledcleic.ptr.pp_double[i][j]/vv; + } + } + } + + /* + * Initial enforcement of box constraints + */ + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + state->x0.ptr.p_double[i] = ae_maxreal(state->x0.ptr.p_double[i], state->scaledbndl.ptr.p_double[i], _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->x0.ptr.p_double[i] = ae_minreal(state->x0.ptr.p_double[i], state->scaledbndu.ptr.p_double[i], _state); + } + } + + /* + * Stopping criteria and settings + */ + critcopy(criteria, &state->criteria, _state); + state->bfgsresetfreq = nlcsqp_defaultbfgsresetfreq; + state->usedensebfgs = usedensebfgs; + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repiterationscount = 0; + + /* + * Integrity checks + */ + ae_assert(ae_fp_less(nlcsqp_sqpdeltadecrease,nlcsqp_sqpdeltaincrease), "MinSQP: integrity check failed", _state); +} + + +/************************************************************************* +This function performs actual processing for SQP algorithm. It expects +that caller redirects its reverse communication requests NeedFiJ/XUpdated +to external user who will provide analytic derivative (or handle reports +about progress). + +In case external user does not have analytic derivative, it is responsibility +of caller to intercept NeedFiJ request and replace it with appropriate +numerical differentiation scheme. + +Results are stored: +* point - in State.StepKX + +IMPORTANT: this function works with scaled problem formulation; it is + responsibility of the caller to unscale request and scale + Jacobian. + +NOTE: SMonitor is expected to be correctly initialized smoothness monitor. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +ae_bool minsqpiteration(minsqpstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nslack; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double mx; + double deltamax; + double multiplyby; + double setscaleto; + double prevtrustrad; + ae_int_t subiterationidx; + ae_bool trustradstagnated; + double relativetargetdecrease; + ae_bool dotrace; + ae_bool doprobingalways; + ae_bool doprobingonfailure; + ae_bool dodetailedtrace; + ae_bool increasemeritmu; + ae_bool meritfstagnated; + double f0; + double f0raw; + double f1; + double tol; + double stepklagval; + double stepknlagval; + double expandedrad; + ae_bool socperformed; + double d2trustradratio; + ae_int_t didx; + double sksk; + double ykyk; + double skyk; + double sumc1; + double sumc1soc; + double predictedchange; + double predictedchangemodel; + double predictedchangepenalty; + ae_bool meritdecreasefailed; + ae_bool stepperformed; + ae_bool goodstep; + ae_bool firstrescale; + ae_bool infinitiesdetected; + ae_bool failedtorecoverfrominfinities; + ae_bool needsoc; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + nslack = state->rstate.ia.ptr.p_int[1]; + nec = state->rstate.ia.ptr.p_int[2]; + nic = state->rstate.ia.ptr.p_int[3]; + nlec = state->rstate.ia.ptr.p_int[4]; + nlic = state->rstate.ia.ptr.p_int[5]; + i = state->rstate.ia.ptr.p_int[6]; + j = state->rstate.ia.ptr.p_int[7]; + subiterationidx = state->rstate.ia.ptr.p_int[8]; + didx = state->rstate.ia.ptr.p_int[9]; + trustradstagnated = state->rstate.ba.ptr.p_bool[0]; + dotrace = state->rstate.ba.ptr.p_bool[1]; + doprobingalways = state->rstate.ba.ptr.p_bool[2]; + doprobingonfailure = state->rstate.ba.ptr.p_bool[3]; + dodetailedtrace = state->rstate.ba.ptr.p_bool[4]; + increasemeritmu = state->rstate.ba.ptr.p_bool[5]; + meritfstagnated = state->rstate.ba.ptr.p_bool[6]; + socperformed = state->rstate.ba.ptr.p_bool[7]; + meritdecreasefailed = state->rstate.ba.ptr.p_bool[8]; + stepperformed = state->rstate.ba.ptr.p_bool[9]; + goodstep = state->rstate.ba.ptr.p_bool[10]; + firstrescale = state->rstate.ba.ptr.p_bool[11]; + infinitiesdetected = state->rstate.ba.ptr.p_bool[12]; + failedtorecoverfrominfinities = state->rstate.ba.ptr.p_bool[13]; + needsoc = state->rstate.ba.ptr.p_bool[14]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + mx = state->rstate.ra.ptr.p_double[2]; + deltamax = state->rstate.ra.ptr.p_double[3]; + multiplyby = state->rstate.ra.ptr.p_double[4]; + setscaleto = state->rstate.ra.ptr.p_double[5]; + prevtrustrad = state->rstate.ra.ptr.p_double[6]; + relativetargetdecrease = state->rstate.ra.ptr.p_double[7]; + f0 = state->rstate.ra.ptr.p_double[8]; + f0raw = state->rstate.ra.ptr.p_double[9]; + f1 = state->rstate.ra.ptr.p_double[10]; + tol = state->rstate.ra.ptr.p_double[11]; + stepklagval = state->rstate.ra.ptr.p_double[12]; + stepknlagval = state->rstate.ra.ptr.p_double[13]; + expandedrad = state->rstate.ra.ptr.p_double[14]; + d2trustradratio = state->rstate.ra.ptr.p_double[15]; + sksk = state->rstate.ra.ptr.p_double[16]; + ykyk = state->rstate.ra.ptr.p_double[17]; + skyk = state->rstate.ra.ptr.p_double[18]; + sumc1 = state->rstate.ra.ptr.p_double[19]; + sumc1soc = state->rstate.ra.ptr.p_double[20]; + predictedchange = state->rstate.ra.ptr.p_double[21]; + predictedchangemodel = state->rstate.ra.ptr.p_double[22]; + predictedchangepenalty = state->rstate.ra.ptr.p_double[23]; + } + else + { + n = 359; + nslack = -58; + nec = -919; + nic = -909; + nlec = 81; + nlic = 255; + i = 74; + j = -788; + subiterationidx = 809; + didx = 205; + trustradstagnated = ae_false; + dotrace = ae_true; + doprobingalways = ae_false; + doprobingonfailure = ae_true; + dodetailedtrace = ae_true; + increasemeritmu = ae_false; + meritfstagnated = ae_false; + socperformed = ae_false; + meritdecreasefailed = ae_false; + stepperformed = ae_false; + goodstep = ae_true; + firstrescale = ae_false; + infinitiesdetected = ae_true; + failedtorecoverfrominfinities = ae_true; + needsoc = ae_false; + v = 346.0; + vv = -722.0; + mx = -413.0; + deltamax = -461.0; + multiplyby = 927.0; + setscaleto = 201.0; + prevtrustrad = 922.0; + relativetargetdecrease = -154.0; + f0 = 306.0; + f0raw = -1011.0; + f1 = 951.0; + tol = -463.0; + stepklagval = 88.0; + stepknlagval = -861.0; + expandedrad = -678.0; + d2trustradratio = -731.0; + sksk = -675.0; + ykyk = -763.0; + skyk = -233.0; + sumc1 = -936.0; + sumc1soc = -279.0; + predictedchange = 94.0; + predictedchangemodel = -812.0; + predictedchangepenalty = 427.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + + /* + * Routine body + */ + n = state->n; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + nslack = n+2*(nec+nlec)+(nic+nlic); + dotrace = ae_is_trace_enabled("SQP")&&!ae_is_trace_enabled("SQP.LACONIC"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("SQP.DETAILED"); + doprobingalways = dotrace&&ae_is_trace_enabled("SQP.PROBING"); + doprobingonfailure = dotrace&&ae_is_trace_enabled("SQP.PROBINGONFAILURE"); + + /* + * Prepare rcomm interface + */ + state->needfij = ae_false; + state->xupdated = ae_false; + + /* + * Prepare debug timers + */ + stimerinit(&state->timertotal, _state); + stimerinit(&state->timerqp, _state); + stimerinit(&state->timercallback, _state); + stimerstart(&state->timertotal, _state); + + /* + * Initialize algorithm data: + * * Lagrangian and "Big C" estimates + * * trust region + * * initial function scales (vector of 1's) + * * current approximation of the Hessian matrix H (unit matrix) + * * initial linearized constraints + * * initial violation of linear/nonlinear constraints + */ + state->fstagnationcnt = 0; + state->trustradstagnationcnt = 0; + state->trustrad = nlcsqp_inittrustrad; + state->trustradgrowth = nlcsqp_deftrustradgrowth; + for(i=0; i<=nlec+nlic; i++) + { + state->fscales.ptr.p_double[i] = 1.0; + state->tracegamma.ptr.p_double[i] = 0.0; + } + ae_obj_array_clear(&state->nonmonotonicmem); + state->nonmonotoniccnt = 0; + + /* + * Evaluate function vector and Jacobian at X0, send first location report. + * Compute initial violation of constraints. + */ + vfjallocdense(n, 1+nlec+nlic, &state->stepk, _state); + vfjallocdense(n, 1+nlec+nlic, &state->cand, _state); + vfjallocdense(n, 1+nlec+nlic, &state->corr, _state); + vfjallocdense(n, 1+nlec+nlic, &state->probe, _state); + vfjallocdense(n, 1+nlec+nlic, &state->currentlinearization, _state); + rcopyv(n, &state->x0, &state->stepk.x, _state); + nlcsqp_sqpsendx(state, &state->stepk.x, _state); + state->needfij = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfij = ae_false; + if( !nlcsqp_sqpretrievefij(state, &state->stepk, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + nlcsqp_sqpsendx(state, &state->stepk.x, _state); + state->f = state->stepk.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; + checklcviolation(&state->scaledcleic, &state->lcsrcidx, nec, nic, &state->stepk.x, n, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlcviolation(&state->stepk.fi, &state->fscales, nlec, nlic, &state->repnlcerr, &state->repnlcidx, _state); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// SQP SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Perform outer (NLC) iterations + */ + firstrescale = ae_true; + infinitiesdetected = ae_false; + failedtorecoverfrominfinities = ae_false; + relativetargetdecrease = 1.0E50; + state->meritmu = (double)(500); + if( state->usedensebfgs ) + { + hessianinitbfgs(&state->hess, n, state->bfgsresetfreq, (double)10*ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), _state); + } + else + { + hessianinitlowrank(&state->hess, n, ae_minint(n, nlcsqp_xbfgsmemlen, _state), (double)10*ae_maxreal(critgeteps(&state->criteria, _state), ae_sqrt(ae_machineepsilon, _state), _state), nlcsqp_xbfgsmaxhess, _state); + } + nlcsqp_initqpsubsolver(state, &state->subsolver, _state); +lbl_6: + if( ae_false ) + { + goto lbl_7; + } + + /* + * Before beginning new outer iteration: + * * check stopping criteria + * * renormalize target function and/or constraints, if some of them have too large magnitudes + * * save initial point for the outer iteration + */ + if( ae_fp_less_eq(relativetargetdecrease,critgetepsf(&state->criteria, _state)) ) + { + state->repterminationtype = 1; + if( dotrace ) + { + ae_trace("> stopping condition met: relative change in target is less than %0.3e\n", + (double)(critgetepsf(&state->criteria, _state))); + } + goto lbl_7; + } + if( ae_fp_less_eq(state->trustrad,critgeteps(&state->criteria, _state)) ) + { + state->repterminationtype = 2; + if( dotrace ) + { + ae_trace("> stopping condition met: trust radius is smaller than %0.3e\n", + (double)(critgeteps(&state->criteria, _state))); + } + goto lbl_7; + } + v = ae_sqrt(ae_machineepsilon, _state); + if( ae_fp_less_eq(state->trustrad,v) ) + { + state->repterminationtype = 7; + if( dotrace ) + { + ae_trace("> stopping condition met: trust radius is smaller than the absolute minimum %0.3e\n", + (double)(v)); + } + goto lbl_7; + } + if( critgetmaxits(&state->criteria, _state)>0&&state->repiterationscount>=critgetmaxits(&state->criteria, _state) ) + { + state->repterminationtype = 5; + if( dotrace ) + { + ae_trace("> stopping condition met: %0d iterations performed\n", + (int)(state->repiterationscount)); + } + goto lbl_7; + } + if( state->fstagnationcnt>=nlcsqp_fstagnationlimit ) + { + state->repterminationtype = 7; + if( dotrace ) + { + ae_trace("> stopping criteria are too stringent: F stagnated for %0d its, stopping\n", + (int)(state->fstagnationcnt)); + } + goto lbl_7; + } + for(i=0; i<=nlec+nlic; i++) + { + + /* + * Determine (a) multiplicative coefficient applied to function value + * and Jacobian row, and (b) new value of the function scale. + */ + mx = (double)(0); + for(j=0; j<=n-1; j++) + { + mx = ae_maxreal(mx, ae_fabs(state->stepk.jac.ptr.pp_double[i][j], _state), _state); + } + multiplyby = 1.0; + setscaleto = state->fscales.ptr.p_double[i]; + if( ae_fp_greater_eq(mx,nlcsqp_sqpbigscale) ) + { + v = mx; + if( !firstrescale ) + { + v = ae_minreal(v, nlcsqp_sqpmaxrescale, _state); + } + multiplyby = (double)1/v; + setscaleto = state->fscales.ptr.p_double[i]*v; + } + if( ae_fp_less_eq(mx,nlcsqp_sqpsmallscale)&&ae_fp_greater(state->fscales.ptr.p_double[i],1.0) ) + { + v = mx; + if( !firstrescale ) + { + v = ae_maxreal(v, nlcsqp_sqpminrescale, _state); + } + if( ae_fp_greater(state->fscales.ptr.p_double[i]*v,(double)(1)) ) + { + multiplyby = (double)1/v; + setscaleto = state->fscales.ptr.p_double[i]*v; + } + else + { + multiplyby = state->fscales.ptr.p_double[i]; + setscaleto = 1.0; + } + } + if( ae_fp_neq(multiplyby,1.0) ) + { + + /* + * Function #I needs renormalization: + * * update function vector element and Jacobian matrix row + * * update FScales[] and TraceGamma[] arrays + */ + state->stepk.fi.ptr.p_double[i] = state->stepk.fi.ptr.p_double[i]*multiplyby; + for(j=0; j<=n-1; j++) + { + state->stepk.jac.ptr.pp_double[i][j] = state->stepk.jac.ptr.pp_double[i][j]*multiplyby; + } + state->fscales.ptr.p_double[i] = setscaleto; + state->tracegamma.ptr.p_double[i] = state->tracegamma.ptr.p_double[i]*multiplyby; + nlcsqp_nonmonotonicmultiplyby(state, i, multiplyby, _state); + } + } + firstrescale = ae_false; + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n=== OUTER ITERATION %5d STARTED ==================================================================\n", + (int)(state->repiterationscount)); + if( dodetailedtrace ) + { + ae_trace("> printing raw data (prior to applying variable and function scales)\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->stepk.x, n, &state->s, ae_true, &state->s, ae_false, _state); + ae_trace("\n"); + ae_trace("> printing scaled data (after applying variable and function scales)\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->stepk.x, 0, n, _state); + ae_trace("\n"); + ae_trace("FScales = "); + tracevectorautoprec(&state->fscales, 0, 1+nlec+nlic, _state); + ae_trace("\n"); + ae_trace("GammaScl = "); + tracevectorautoprec(&state->tracegamma, 0, 1+nlec+nlic, _state); + ae_trace("\n"); + ae_trace("Fi (scaled) = "); + tracevectorautoprec(&state->stepk.fi, 0, 1+nlec+nlic, _state); + ae_trace("\n"); + ae_trace("|Ji| (scaled) = "); + tracerownrm1autoprec(&state->stepk.jac, 0, 1+nlec+nlic, 0, n, _state); + ae_trace("\n"); + } + mx = (double)(0); + for(i=1; i<=nlec; i++) + { + mx = ae_maxreal(mx, ae_fabs(state->stepk.fi.ptr.p_double[i], _state), _state); + } + for(i=nlec+1; i<=nlec+nlic; i++) + { + mx = ae_maxreal(mx, state->stepk.fi.ptr.p_double[i], _state); + } + ae_trace("trustRad = %0.3e\n", + (double)(state->trustrad)); + ae_trace("meritMu = %0.3e (penalty for violation of constraints)\n", + (double)(state->meritmu)); + ae_trace("lin.violation = %0.3e (scaled violation of linear constraints)\n", + (double)(state->replcerr)); + ae_trace("nlc.violation = %0.3e (scaled violation of nonlinear constraints)\n", + (double)(mx)); + ae_trace("gamma0 = %0.3e (Hessian 2-norm estimate for target)\n", + (double)(state->tracegamma.ptr.p_double[0])); + j = 0; + for(i=0; i<=nlec+nlic; i++) + { + if( ae_fp_greater(state->tracegamma.ptr.p_double[i],state->tracegamma.ptr.p_double[j]) ) + { + j = i; + } + } + ae_trace("gammaMax = %0.3e (maximum over Hessian 2-norm estimates for target/constraints)\n", + (double)(state->tracegamma.ptr.p_double[j])); + ae_trace("arg(gammaMax) = %0d (function index; 0 for target, >0 for nonlinear constraints)\n", + (int)(j)); + ae_trace("|x|inf = %0.3e\n", + (double)(rmaxabsv(n, &state->stepk.x, _state))); + } + + /* + * Start of the SQP iteration + */ + rcopyv(n, &state->stepk.x, &state->xprev, _state); + rsetv(nslack, 0.0, &state->d0, _state); + rsetv(nslack, 0.0, &state->d1, _state); + if( dotrace ) + { + ae_trace("\n--- quadratic step ---------------------------------------------------------------------------------\n"); + } + + /* + * Default values of the flag variables + */ + increasemeritmu = ae_false; + meritfstagnated = ae_false; + meritdecreasefailed = ae_false; + stepperformed = ae_true; + goodstep = ae_true; + relativetargetdecrease = 1.0E50; + + /* + * Determine step direction using initial quadratic model. + */ + socperformed = ae_false; + if( !nlcsqp_qpsubproblemsolve(state, &state->subsolver, &state->stepk.x, &state->stepk.fi, &state->stepk.jac, &state->hess, 1.0, 1.0, &state->d0, &state->lagbcmult, &state->lagxcmult, dotrace, &j, &predictedchangemodel, &predictedchangepenalty, &sumc1, &d2trustradratio, _state) ) + { + if( dotrace ) + { + ae_trace("> [WARNING] QP subproblem failed with TerminationType=%0d\n> decreasing trust radius\n", + (int)(j)); + } + state->trustrad = 0.1*state->trustrad; + inc(&state->repiterationscount, _state); + goto lbl_6; + } + if( dotrace ) + { + ae_trace("> QP subproblem solved with TerminationType=%0d, max|lagBoxMult|=%0.2e, max|lagNonBoxMult|=%0.2e\n", + (int)(j), + (double)(rmaxabsv(n, &state->lagbcmult, _state)), + (double)(rmaxabsv(nec+nic+nlec+nlic, &state->lagxcmult, _state))); + } + rcopyv(nslack, &state->d0, &state->dtrial, _state); + vfjcopy(&state->stepk, &state->currentlinearization, _state); + + /* + * Perform merit function line search. + * + * First, we try unit step. If it does not decrease merit function, + * a second-order correction is tried (helps to combat Maratos effect). + */ + rallocv(n, &state->tmplaggrad, _state); + nlcsqp_lagrangianfg(state, &state->stepk.x, state->trustrad, &state->stepk.fi, &state->stepk.jac, &state->lagbcmult, &state->lagxcmult, ae_true, &stepklagval, &state->tmplaggrad, _state); + f0raw = nlcsqp_meritfunction(state, &state->stepk, state->meritmu, _state); + f0 = nlcsqp_nonmonotonicadjustment(state, f0raw, _state); + rcopyv(n, &state->stepk.x, &state->cand.x, _state); + raddv(n, 1.0, &state->dtrial, &state->cand.x, _state); + nlcsqp_sqpsendx(state, &state->cand.x, _state); + state->needfij = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfij = ae_false; + if( !nlcsqp_sqpretrievefij(state, &state->cand, _state) ) + { + + /* + * Failed to retrieve func/Jac, infinities detected + */ + if( dotrace ) + { + ae_trace("[WARNING] infinities in target/constraints are detected, forcing trust radius decrease and restarting iteration\n"); + } + state->trustrad = state->trustrad*nlcsqp_maxtrustraddecay; + trustradresetmomentum(&state->trustradgrowth, nlcsqp_deftrustradgrowth, _state); + infinitiesdetected = ae_true; + failedtorecoverfrominfinities = ae_true; + inc(&state->repiterationscount, _state); + goto lbl_6; + } + f1 = nlcsqp_meritfunction(state, &state->cand, state->meritmu, _state); + predictedchange = predictedchangemodel+state->meritmu*predictedchangepenalty; + goodstep = ae_fp_less(f1-f0raw,nlcsqp_sufficientdecreasesigma*predictedchange); + rallocv(n, &state->tmpcandlaggrad, _state); + nlcsqp_lagrangianfg(state, &state->cand.x, state->trustrad, &state->cand.fi, &state->cand.jac, &state->lagbcmult, &state->lagxcmult, ae_true, &stepknlagval, &state->tmpcandlaggrad, _state); + hessianupdatev2(&state->hess, &state->stepk.x, &state->tmplaggrad, &state->cand.x, &state->tmpcandlaggrad, 2, ae_false, dotrace, 1, _state); + if( dotrace ) + { + ae_trace("> proposed step with relative len %0.6f, analyzing change in the merit function: predicted=%0.2e, actual=%0.2e (ignoring nonmonotonic adjustment), ratio=%5.2f\n", + (double)(d2trustradratio), + (double)(predictedchange), + (double)(f1-f0raw), + (double)((f1-f0raw)/predictedchange)); + } + needsoc = ae_false; + if( ae_fp_greater_eq(predictedchange,(double)(0))||ae_fp_greater_eq(f1-f0,nlcsqp_sufficientdecreasesigma*predictedchange) ) + { + needsoc = ae_true; + if( dotrace ) + { + ae_trace("> step without correction does not provide sufficient decrease in the merit function, preparing second-order correction\n"); + } + } + if( !needsoc ) + { + goto lbl_8; + } + + /* + * Full step increases merit function. Let's compute second order + * correction to the constraint model and recompute trial step D: + * * use original model of the target + * * extrapolate model of nonlinear constraints at StepKX+D back to origin + * + */ + socperformed = ae_true; + rcopyv(n, &state->stepk.x, &state->corr.x, _state); + state->corr.fi.ptr.p_double[0] = state->stepk.fi.ptr.p_double[0]; + for(j=0; j<=n-1; j++) + { + state->corr.jac.ptr.pp_double[0][j] = state->stepk.jac.ptr.pp_double[0][j]; + } + for(i=1; i<=nlec+nlic; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+state->d0.ptr.p_double[j]*state->stepk.jac.ptr.pp_double[i][j]; + state->corr.jac.ptr.pp_double[i][j] = state->stepk.jac.ptr.pp_double[i][j]; + } + state->corr.fi.ptr.p_double[i] = state->cand.fi.ptr.p_double[i]-v; + } + if( !nlcsqp_qpsubproblemsolve(state, &state->subsolver, &state->corr.x, &state->corr.fi, &state->corr.jac, &state->hess, 1.0, 1.0, &state->d1, &state->dummylagbcmult, &state->dummylagxcmult, dotrace, &j, &predictedchangemodel, &predictedchangepenalty, &sumc1soc, &d2trustradratio, _state) ) + { + if( dotrace ) + { + ae_trace("> [WARNING] second-order QP subproblem failed\n> decreasing trust radius\n"); + } + state->trustrad = 0.1*state->trustrad; + inc(&state->repiterationscount, _state); + goto lbl_6; + } + if( dotrace ) + { + ae_trace("> QP subproblem solved with TerminationType=%0d, max|lagBoxMult|=%0.2e, max|lagNonBoxMult|=%0.2e\n", + (int)(j), + (double)(rmaxabsv(n, &state->dummylagbcmult, _state)), + (double)(rmaxabsv(nec+nic+nlec+nlic, &state->dummylagxcmult, _state))); + } + rcopyv(n, &state->d1, &state->dtrial, _state); + vfjcopy(&state->corr, &state->currentlinearization, _state); + + /* + * Perform line search, we again try full step (maybe it will work after SOC) + */ + smoothnessmonitorstartlinesearch(smonitor, &state->stepk.x, &state->stepk.fi, &state->stepk.jac, state->repiterationscount, -1, _state); + rcopyv(n, &state->stepk.x, &state->cand.x, _state); + raddv(n, 1.0, &state->dtrial, &state->cand.x, _state); + nlcsqp_sqpsendx(state, &state->cand.x, _state); + state->needfij = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfij = ae_false; + if( !nlcsqp_sqpretrievefij(state, &state->cand, _state) ) + { + + /* + * Failed to retrieve func/Jac, infinities detected + */ + if( dotrace ) + { + ae_trace("[WARNING] infinities in target/constraints are detected, forcing trust radius decrease and restarting iteration\n"); + } + state->trustrad = state->trustrad*nlcsqp_maxtrustraddecay; + trustradresetmomentum(&state->trustradgrowth, nlcsqp_deftrustradgrowth, _state); + inc(&state->repiterationscount, _state); + infinitiesdetected = ae_true; + failedtorecoverfrominfinities = ae_true; + goto lbl_6; + } + smoothnessmonitorenqueuepoint(smonitor, &state->dtrial, 1.0, &state->cand.x, &state->cand.fi, &state->cand.jac, _state); + f1 = nlcsqp_meritfunction(state, &state->cand, state->meritmu, _state); + predictedchange = predictedchangemodel+state->meritmu*predictedchangepenalty; + goodstep = ae_fp_less(f1-f0raw,nlcsqp_sufficientdecreasesigma*predictedchange); + rallocv(n, &state->tmpcandlaggrad, _state); + nlcsqp_lagrangianfg(state, &state->cand.x, state->trustrad, &state->cand.fi, &state->cand.jac, &state->lagbcmult, &state->lagxcmult, ae_true, &stepknlagval, &state->tmpcandlaggrad, _state); + hessianpoplatestifpossible(&state->hess, _state); + hessianupdatev2(&state->hess, &state->stepk.x, &state->tmplaggrad, &state->cand.x, &state->tmpcandlaggrad, 2, ae_true, dotrace, 1, _state); + if( dotrace ) + { + ae_trace("> proposed step with relative len %0.6f, analyzing change in the merit function: predicted=%0.2e, actual=%0.2e (ignoring nonmonotonic adjustment), ratio=%5.2f\n", + (double)(d2trustradratio), + (double)(predictedchange), + (double)(f1-f0raw), + (double)((f1-f0raw)/predictedchange)); + } + if( ae_fp_greater_eq(predictedchange,(double)(0))||ae_fp_greater_eq(f1-f0,nlcsqp_sufficientdecreasesigma*predictedchange) ) + { + + /* + * Mark step as failed + */ + stepperformed = ae_false; + goodstep = ae_false; + meritdecreasefailed = ae_true; + f1 = f0; + } + smoothnessmonitorfinalizelinesearch(smonitor, _state); +lbl_8: + enforceboundaryconstraints(&state->cand.x, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + if( userterminationneeded ) + { + + /* + * User requested termination, break before we move to new point + */ + state->repterminationtype = icase2(failedtorecoverfrominfinities, -8, 8, _state); + if( dotrace ) + { + ae_trace("> user requested termination\n"); + } + goto lbl_7; + } + + /* + * Analyze merit F for stagnation + */ + meritfstagnated = stepperformed&&ae_fp_less_eq(ae_fabs(f1-f0, _state),nlcsqp_stagnationepsf*ae_fabs(f0, _state)); + v = ae_fabs(f1-f0, _state)/rmaxabs3(f0, f1, (double)(1), _state); + vv = ae_fabs(state->cand.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]-state->stepk.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0], _state)/rmaxabs3(state->cand.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0], state->stepk.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0], (double)(1), _state); + relativetargetdecrease = rcase2(stepperformed, ae_maxreal(v, vv, _state), 1.0E50, _state); + + /* + * Analyze linearized model - did we enforce zero violations of the constraint linearizations? + * If we did not, we may need to increase MeritMu penalty coefficients. + */ + if( nlcsqp_penaltiesneedincrease(state, &state->currentlinearization, &state->dtrial, predictedchangemodel, predictedchangepenalty, dotrace, _state) ) + { + stepperformed = ae_false; + goodstep = ae_false; + increasemeritmu = ae_true; + } + + /* + * Trace + */ + if( !dotrace ) + { + goto lbl_10; + } + + /* + * Compute Lagrangian + */ + rallocv(n, &state->tmplaggrad, _state); + rallocv(n, &state->tmpcandlaggrad, _state); + nlcsqp_lagrangianfg(state, &state->stepk.x, state->trustrad, &state->stepk.fi, &state->stepk.jac, &state->lagbcmult, &state->lagxcmult, ae_true, &stepklagval, &state->tmplaggrad, _state); + nlcsqp_lagrangianfg(state, &state->cand.x, state->trustrad, &state->cand.fi, &state->cand.jac, &state->lagbcmult, &state->lagxcmult, ae_true, &stepknlagval, &state->tmpcandlaggrad, _state); + + /* + * Update debug curvature information. Let + * + * Sk = X(k+1)-X(k), Yk = G(k+1)-G(k) + * + * for a function Fi and store maximum over curvatures + * + * gamma = (Yk,Yk)/|(Sk,Yk)| + * + * to TraceGamma[] array. Set MaxNewGamma to maximum of new values, set GammaIncreased + * flag if at least one of TraceGamma[] entries was increased. + */ + sksk = (double)(0); + for(j=0; j<=n-1; j++) + { + v = state->cand.x.ptr.p_double[j]-state->stepk.x.ptr.p_double[j]; + sksk = sksk+v*v; + } + if( ae_fp_greater(sksk,(double)(0)) ) + { + for(i=0; i<=nlec+nlic; i++) + { + ykyk = (double)(0); + skyk = (double)(0); + for(j=0; j<=n-1; j++) + { + v = state->cand.x.ptr.p_double[j]-state->stepk.x.ptr.p_double[j]; + vv = state->cand.jac.ptr.pp_double[i][j]-state->stepk.jac.ptr.pp_double[i][j]; + skyk = skyk+v*vv; + ykyk = ykyk+vv*vv; + } + v = skyk/(sksk+ae_machineepsilon*ae_machineepsilon); + state->tracegamma.ptr.p_double[i] = ae_maxreal(state->tracegamma.ptr.p_double[i], v, _state); + } + } + + /* + * Perform agressive probing of the search direction - additional function evaluations + * which help us to determine possible discontinuity and nonsmoothness of the problem + */ + if( !(doprobingalways||(doprobingonfailure&&meritdecreasefailed)) ) + { + goto lbl_12; + } + didx = 0; +lbl_14: + if( didx>1 ) + { + goto lbl_16; + } + if( didx==1&&!socperformed ) + { + goto lbl_16; + } + if( didx==0 ) + { + smoothnessmonitorstartlagrangianprobing(smonitor, &state->stepk.x, &state->d0, 1.0, state->repiterationscount, -1, _state); + } + else + { + smoothnessmonitorstartlagrangianprobing(smonitor, &state->stepk.x, &state->d1, 1.0, state->repiterationscount, -1, _state); + } +lbl_17: + if( !smoothnessmonitorprobelagrangian(smonitor, _state) ) + { + goto lbl_18; + } + for(j=0; j<=n-1; j++) + { + state->probe.x.ptr.p_double[j] = smonitor->lagprobx.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j] ) + { + state->probe.x.ptr.p_double[j] = ae_maxreal(state->probe.x.ptr.p_double[j], state->scaledbndl.ptr.p_double[j], _state); + } + if( state->hasbndu.ptr.p_bool[j] ) + { + state->probe.x.ptr.p_double[j] = ae_minreal(state->probe.x.ptr.p_double[j], state->scaledbndu.ptr.p_double[j], _state); + } + } + nlcsqp_sqpsendx(state, &state->probe.x, _state); + state->needfij = ae_true; + if( dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + if( dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfij = ae_false; + if( !nlcsqp_sqpretrievefij(state, &state->probe, _state) ) + { + goto lbl_18; + } + rcopyallocv(1+nlec+nlic, &state->probe.fi, &smonitor->lagprobfi, _state); + rcopyallocm(1+nlec+nlic, n, &state->probe.jac, &smonitor->lagprobj, _state); + smonitor->lagprobrawlag = nlcsqp_rawlagrangian(state, &state->probe.x, &state->probe.fi, &state->lagbcmult, &state->lagxcmult, state->meritmu, _state); + goto lbl_17; +lbl_18: + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | probing search direction |\n"); + if( didx==0 ) + { + ae_trace("*** | suggested by first-order QP subproblem |\n"); + } + if( didx==1 ) + { + ae_trace("*** | suggested by second-order QP subproblem |\n"); + } + ae_trace("*** ------------------------------------------------------------\n"); + ae_trace("*** | Step | Lagrangian (unaugmentd)| Target function |\n"); + ae_trace("*** |along D| must be smooth | must be smooth |\n"); + ae_trace("*** | | function | slope | function | slope |\n"); + smoothnessmonitortracelagrangianprobingresults(smonitor, _state); + didx = didx+1; + goto lbl_14; +lbl_16: +lbl_12: + + /* + * Output other information + */ + mx = (double)(0); + for(i=0; i<=n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(state->dtrial.ptr.p_double[i], _state)/nlcsqp_gettrustregionk(&state->stepk.x, i, state->trustrad, _state), _state); + } + if( stepperformed&&goodstep ) + { + ae_trace("> sufficient decrease step was performed\n"); + } + else + { + if( stepperformed ) + { + ae_trace("> nonmonotonic step was performed\n"); + } + else + { + ae_trace("> no step was performed\n"); + } + } + ae_trace("max(|Di|)/TrustRad = %0.6f\n", + (double)(mx)); + if( dodetailedtrace ) + { + ae_trace("LagBoxMlt = "); + tracevectorautoprec(&state->lagbcmult, 0, n, _state); + ae_trace("\n"); + ae_trace("LagNonBoxMlt= "); + tracevectorautoprec(&state->lagxcmult, 0, nec+nic+nlec+nlic, _state); + ae_trace("\n"); + } + if( dodetailedtrace ) + { + ae_trace("X0 (scaled) = "); + tracevectorautoprec(&state->stepk.x, 0, n, _state); + ae_trace("\n"); + ae_trace("D (scaled) = "); + tracevectorautoprec(&state->dtrial, 0, n, _state); + ae_trace("\n"); + ae_trace("X1 (scaled) = "); + tracevectorautoprec(&state->cand.x, 0, n, _state); + ae_trace("\n"); + ae_trace("\n"); + ae_trace("grad F(X0) = "); + tracerowautoprec(&state->stepk.jac, 0, 0, n, _state); + ae_trace("\n"); + ae_trace("grad F(X1) = "); + tracerowautoprec(&state->cand.jac, 0, 0, n, _state); + ae_trace("\n"); + ae_trace("\n"); + ae_trace("grad L(X0) = "); + tracevectorautoprec(&state->tmplaggrad, 0, n, _state); + ae_trace("\n"); + ae_trace("grad L(X1) = "); + tracevectorautoprec(&state->tmpcandlaggrad, 0, n, _state); + ae_trace("\n"); + } + ae_trace("targetF: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(state->fscales.ptr.p_double[0]*state->stepk.fi.ptr.p_double[0]), + (double)(state->fscales.ptr.p_double[0]*state->cand.fi.ptr.p_double[0]), + (double)(state->fscales.ptr.p_double[0]*(state->cand.fi.ptr.p_double[0]-state->stepk.fi.ptr.p_double[0]))); + ae_trace("scaled-meritF: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(f0), + (double)(f1), + (double)(f1-f0)); + ae_trace("scaled-targetF: %17.9e -> %17.9e (delta=%11.3e)\n", + (double)(state->stepk.fi.ptr.p_double[0]), + (double)(state->cand.fi.ptr.p_double[0]), + (double)(state->cand.fi.ptr.p_double[0]-state->stepk.fi.ptr.p_double[0])); + ae_trace("max|lag-grad|: %17.9e -> %17.9e\n", + (double)(rmaxabsv(n, &state->tmplaggrad, _state)), + (double)(rmaxabsv(n, &state->tmpcandlaggrad, _state))); + ae_trace("nrm2|lag-grad|: %17.9e -> %17.9e (ratio=%0.6f)\n", + (double)(ae_sqrt(rdotv2(n, &state->tmplaggrad, _state), _state)), + (double)(ae_sqrt(rdotv2(n, &state->tmpcandlaggrad, _state), _state)), + (double)(ae_sqrt(rdotv2(n, &state->tmpcandlaggrad, _state), _state)/ae_sqrt(rdotv2(n, &state->tmplaggrad, _state), _state))); + hessiangetdiagonal(&state->hess, &state->tmphdiag, _state); + v = state->tmphdiag.ptr.p_double[0]; + for(i=0; i<=n-1; i++) + { + v = ae_minreal(v, state->tmphdiag.ptr.p_double[i], _state); + } + ae_trace("mindiag(Bk) = %0.3e\n", + (double)(v)); + v = state->tmphdiag.ptr.p_double[0]; + for(i=0; i<=n-1; i++) + { + v = ae_maxreal(v, state->tmphdiag.ptr.p_double[i], _state); + } + ae_trace("maxdiag(Bk) = %0.3e\n", + (double)(v)); +lbl_10: + + /* + * Move to new point + */ + if( !stepperformed ) + { + goto lbl_19; + } + + /* + * Save current point to the nonmonotonic memory buffer + */ + nlcsqp_nonmonotonicsave(state, &state->cand, _state); + + /* + * Update current state + */ + vfjcopy(&state->cand, &state->stepk, _state); + failedtorecoverfrominfinities = ae_false; + + /* + * Report one more inner iteration + */ + nlcsqp_sqpsendx(state, &state->stepk.x, _state); + state->f = state->stepk.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0]; + state->xupdated = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->xupdated = ae_false; + + /* + * Update constraint violations + */ + checklcviolation(&state->scaledcleic, &state->lcsrcidx, nec, nic, &state->stepk.x, n, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlcviolation(&state->stepk.fi, &state->fscales, nlec, nlic, &state->repnlcerr, &state->repnlcidx, _state); +lbl_19: + + /* + * Update MeritMu + */ + if( increasemeritmu ) + { + state->meritmu = ae_minreal((double)2*state->meritmu, nlcsqp_maxmeritmu, _state); + } + + /* + * Update trust region. + * + * NOTE: when trust region radius remains fixed for a long time it may mean that we + * stagnated in eternal loop. In such cases we decrease it slightly in order + * to break possible loop. If such decrease was unnecessary, it may be easily + * fixed within few iterations. + */ + trustradstagnated = ae_false; + prevtrustrad = state->trustrad; + deltamax = (double)(0); + for(i=0; i<=n-1; i++) + { + deltamax = ae_maxreal(deltamax, ae_fabs(state->xprev.ptr.p_double[i]-state->stepk.x.ptr.p_double[i], _state)/nlcsqp_gettrustregionk(&state->xprev, i, state->trustrad, _state), _state); + } + inc(&state->trustradstagnationcnt, _state); + if( ae_fp_less_eq(deltamax,nlcsqp_sqpdeltadecrease) ) + { + state->trustrad = state->trustrad*ae_maxreal(deltamax/nlcsqp_sqpdeltadecrease, nlcsqp_maxtrustraddecay, _state); + } + if( ae_fp_greater_eq(deltamax,nlcsqp_sqpdeltaincrease)&&goodstep ) + { + state->trustrad = state->trustrad*state->trustradgrowth; + trustradincreasemomentum(&state->trustradgrowth, nlcsqp_momentumgrowth, nlcsqp_maxtrustradgrowth, _state); + } + else + { + trustradresetmomentum(&state->trustradgrowth, nlcsqp_deftrustradgrowth, _state); + } + if( ae_fp_less(state->trustrad,0.99*prevtrustrad)||ae_fp_greater(state->trustrad,1.01*prevtrustrad) ) + { + state->trustradstagnationcnt = 0; + } + if( state->trustradstagnationcnt>=nlcsqp_trustradstagnationlimit ) + { + state->trustrad = 0.5*state->trustrad; + state->trustradstagnationcnt = 0; + trustradstagnated = ae_true; + } + + /* + * Trace + */ + if( dotrace ) + { + ae_trace("\n--- outer iteration ends ---------------------------------------------------------------------------\n"); + ae_trace("deltaMax = %0.3f (ratio of step length to trust radius)\n", + (double)(deltamax)); + ae_trace("newTrustRad = %0.3e", + (double)(state->trustrad)); + if( !trustradstagnated ) + { + if( ae_fp_greater(state->trustrad,prevtrustrad) ) + { + ae_trace(", trust radius increased"); + } + if( ae_fp_less(state->trustrad,prevtrustrad) ) + { + ae_trace(", trust radius decreased"); + } + } + else + { + ae_trace(", trust radius forcibly decreased due to stagnation for %0d iterations", + (int)(nlcsqp_trustradstagnationlimit)); + } + ae_trace("\n"); + if( increasemeritmu ) + { + ae_trace("meritMu = %0.3e (increasing)\n", + (double)(state->meritmu)); + } + } + + /* + * Advance outer iteration counter + */ + inc(&state->repiterationscount, _state); + state->fstagnationcnt = icase2(meritfstagnated, state->fstagnationcnt+1, 0, _state); + goto lbl_6; +lbl_7: + + /* + * Almost done + */ + if( infinitiesdetected ) + { + state->repterminationtype = icase2(failedtorecoverfrominfinities, -8, state->repterminationtype+800, _state); + } + if( dotrace ) + { + stimerstop(&state->timertotal, _state); + ae_trace("\n=== STOPPED ========================================================================================\n"); + if( infinitiesdetected&&failedtorecoverfrominfinities ) + { + ae_trace("> infinities were detected, but we failed to recover by decreasing trust radius; declaring failure with code -8\n"); + } + ae_trace("raw target: %20.12e\n", + (double)(state->stepk.fi.ptr.p_double[0]*state->fscales.ptr.p_double[0])); + ae_trace("total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("* incl cbck: %10.1f ms\n", + (double)(stimergetms(&state->timercallback, _state))); + ae_trace("* incl QP: %10.1f ms\n", + (double)(stimergetms(&state->timerqp, _state))); + } + smoothnessmonitortracestatus(smonitor, dotrace, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = nslack; + state->rstate.ia.ptr.p_int[2] = nec; + state->rstate.ia.ptr.p_int[3] = nic; + state->rstate.ia.ptr.p_int[4] = nlec; + state->rstate.ia.ptr.p_int[5] = nlic; + state->rstate.ia.ptr.p_int[6] = i; + state->rstate.ia.ptr.p_int[7] = j; + state->rstate.ia.ptr.p_int[8] = subiterationidx; + state->rstate.ia.ptr.p_int[9] = didx; + state->rstate.ba.ptr.p_bool[0] = trustradstagnated; + state->rstate.ba.ptr.p_bool[1] = dotrace; + state->rstate.ba.ptr.p_bool[2] = doprobingalways; + state->rstate.ba.ptr.p_bool[3] = doprobingonfailure; + state->rstate.ba.ptr.p_bool[4] = dodetailedtrace; + state->rstate.ba.ptr.p_bool[5] = increasemeritmu; + state->rstate.ba.ptr.p_bool[6] = meritfstagnated; + state->rstate.ba.ptr.p_bool[7] = socperformed; + state->rstate.ba.ptr.p_bool[8] = meritdecreasefailed; + state->rstate.ba.ptr.p_bool[9] = stepperformed; + state->rstate.ba.ptr.p_bool[10] = goodstep; + state->rstate.ba.ptr.p_bool[11] = firstrescale; + state->rstate.ba.ptr.p_bool[12] = infinitiesdetected; + state->rstate.ba.ptr.p_bool[13] = failedtorecoverfrominfinities; + state->rstate.ba.ptr.p_bool[14] = needsoc; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + state->rstate.ra.ptr.p_double[2] = mx; + state->rstate.ra.ptr.p_double[3] = deltamax; + state->rstate.ra.ptr.p_double[4] = multiplyby; + state->rstate.ra.ptr.p_double[5] = setscaleto; + state->rstate.ra.ptr.p_double[6] = prevtrustrad; + state->rstate.ra.ptr.p_double[7] = relativetargetdecrease; + state->rstate.ra.ptr.p_double[8] = f0; + state->rstate.ra.ptr.p_double[9] = f0raw; + state->rstate.ra.ptr.p_double[10] = f1; + state->rstate.ra.ptr.p_double[11] = tol; + state->rstate.ra.ptr.p_double[12] = stepklagval; + state->rstate.ra.ptr.p_double[13] = stepknlagval; + state->rstate.ra.ptr.p_double[14] = expandedrad; + state->rstate.ra.ptr.p_double[15] = d2trustradratio; + state->rstate.ra.ptr.p_double[16] = sksk; + state->rstate.ra.ptr.p_double[17] = ykyk; + state->rstate.ra.ptr.p_double[18] = skyk; + state->rstate.ra.ptr.p_double[19] = sumc1; + state->rstate.ra.ptr.p_double[20] = sumc1soc; + state->rstate.ra.ptr.p_double[21] = predictedchange; + state->rstate.ra.ptr.p_double[22] = predictedchangemodel; + state->rstate.ra.ptr.p_double[23] = predictedchangepenalty; + return result; +} + + +/************************************************************************* +This function initializes SQP subproblem. +Should be called once in the beginning of the optimization. + +INPUT PARAMETERS: + SState - solver state + Subsolver - SQP subproblem to initialize + + +RETURN VALUE: + True on success + False on failure of the QP solver (unexpected... but possible due to numerical errors) + + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static void nlcsqp_initqpsubsolver(const minsqpstate* sstate, + minsqpsubsolver* subsolver, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nslack; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + ae_int_t lccnt; + ae_int_t nnz; + ae_int_t offs; + ae_int_t i; + ae_int_t j; + + + n = sstate->n; + nec = sstate->nec; + nic = sstate->nic; + nlec = sstate->nlec; + nlic = sstate->nlic; + nslack = n+2*(nec+nlec)+(nic+nlic); + lccnt = nec+nic+nlec+nlic; + + /* + * Allocate temporaries + */ + rvectorsetlengthatleast(&subsolver->cural, lccnt, _state); + rvectorsetlengthatleast(&subsolver->curau, lccnt, _state); + rvectorsetlengthatleast(&subsolver->curbndl, nslack, _state); + rvectorsetlengthatleast(&subsolver->curbndu, nslack, _state); + rvectorsetlengthatleast(&subsolver->curb, nslack, _state); + + /* + * Linear constraints do not change across subiterations, that's + * why we allocate storage for them at the start of the program. + * + * A full set of "raw" constraints is stored; later we will filter + * out inequality ones which are inactive anywhere in the current + * trust region. + * + * NOTE: because sparserawlc object stores only linear constraint + * (linearizations of nonlinear ones are not stored) we + * allocate only minimum necessary space. + */ + nnz = 0; + for(i=0; i<=nec+nic-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( sstate->scaledcleic.ptr.pp_double[i][j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + ivectorsetlengthatleast(&subsolver->sparserawlc.ridx, nec+nic+1, _state); + rvectorsetlengthatleast(&subsolver->sparserawlc.vals, nnz, _state); + ivectorsetlengthatleast(&subsolver->sparserawlc.idx, nnz, _state); + ivectorsetlengthatleast(&subsolver->sparserawlc.didx, nec+nic, _state); + ivectorsetlengthatleast(&subsolver->sparserawlc.uidx, nec+nic, _state); + offs = 0; + subsolver->sparserawlc.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nec+nic-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( sstate->scaledcleic.ptr.pp_double[i][j]!=0.0 ) + { + + /* + * Primary part of the matrix + */ + subsolver->sparserawlc.vals.ptr.p_double[offs] = sstate->scaledcleic.ptr.pp_double[i][j]; + subsolver->sparserawlc.idx.ptr.p_int[offs] = j; + offs = offs+1; + } + } + subsolver->sparserawlc.ridx.ptr.p_int[i+1] = offs; + } + subsolver->sparserawlc.matrixtype = 1; + subsolver->sparserawlc.ninitialized = subsolver->sparserawlc.ridx.ptr.p_int[nec+nic]; + subsolver->sparserawlc.m = nec+nic; + subsolver->sparserawlc.n = n; + sparseinitduidx(&subsolver->sparserawlc, _state); +} + + +/************************************************************************* +This function solves QP subproblem given by initial point X, function vector Fi +and Jacobian Jac, and returns: +* search direction D[] +* estimates of Lagrangian multipliers +* predicted change in the quadratic model of the target, and in the L1-penalty + added to the model + +Additionally returns SumC1 - a sum of absolute errors AT THE BEGINNING of +the step (this quantity is used to choose appropriate penalty parameter; +it corresponds to |Ck|_1 at Nocedal and Wright, 'Numerical optimization' 2006, +chapter 18, formula 18.33). + +The QP subproblem linear and quadratic terms are multiplied by the scalar +multipliers AlphaG and AlphaH, which can be: +* (1,1) when we want to compute a step direction +* (0,0) when we want to compute best possible improvement in the linearized + constraints over the trust region +* (1,0) when we want to compute Lagrange multipliers using linearized model + of the target instead of the quadratic one + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcsqp_qpsubproblemsolve(minsqpstate* state, + minsqpsubsolver* subsolver, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + xbfgshessian* hess, + double alphag, + double alphah, + /* Real */ ae_vector* d, + /* Real */ ae_vector* lagbcmult, + /* Real */ ae_vector* lagxcmult, + ae_bool dotrace, + ae_int_t* terminationtype, + double* predictedchangemodel, + double* predictedchangepenalty, + double* sumc1, + double* d2trustradratio, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nslack; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + double vright; + double vmax; + ae_int_t lccnt; + ae_int_t offsslackec; + ae_int_t offsslacknlec; + ae_int_t offsslackic; + ae_int_t offsslacknlic; + ae_int_t offs; + ae_int_t nnz; + ae_int_t j0; + ae_int_t j1; + double rescaleby; + ae_bool result; + + *terminationtype = 0; + *predictedchangemodel = 0.0; + *predictedchangepenalty = 0.0; + *sumc1 = 0.0; + *d2trustradratio = 0.0; + + ae_assert(ae_fp_eq(alphag,(double)(0))||ae_fp_eq(alphag,(double)(1)), "QPSubproblemSolve: AlphaG is neither 0 nor 1", _state); + ae_assert(ae_fp_eq(alphah,(double)(0))||ae_fp_eq(alphah,(double)(1)), "QPSubproblemSolve: AlphaH is neither 0 nor 1", _state); + n = state->n; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + nslack = n+2*(nec+nlec)+(nic+nlic); + lccnt = nec+nic+nlec+nlic; + + /* + * Locations of slack variables + */ + offsslackec = n; + offsslacknlec = n+2*nec; + offsslackic = n+2*nec+2*nlec; + offsslacknlic = n+2*(nec+nlec)+nic; + + /* + * Prepare temporary structures + */ + rvectorgrowto(&subsolver->cural, lccnt, _state); + rvectorgrowto(&subsolver->curau, lccnt, _state); + rvectorsetlengthatleast(&subsolver->d0, nslack, _state); + rallocv(lccnt, &subsolver->rescalelag, _state); + + /* + * Prepare default solution: all zeros + */ + result = ae_true; + *terminationtype = 0; + *sumc1 = (double)(0); + *predictedchangemodel = (double)(0); + *predictedchangepenalty = (double)(0); + *d2trustradratio = 0.0; + for(i=0; i<=nslack-1; i++) + { + d->ptr.p_double[i] = 0.0; + subsolver->d0.ptr.p_double[i] = (double)(0); + } + rsetv(n, 0.0, lagbcmult, _state); + rsetv(lccnt, 0.0, lagxcmult, _state); + + /* + * Linear term B + * + * NOTE: elements [N,NSlack) are equal to MeritMu + perturbation to improve numeric properties of QP problem + */ + for(i=0; i<=n-1; i++) + { + subsolver->curb.ptr.p_double[i] = alphag*jac->ptr.pp_double[0][i]; + } + for(i=n; i<=nslack-1; i++) + { + subsolver->curb.ptr.p_double[i] = state->meritmu; + } + + /* + * Trust radius constraints for primary variables + */ + bsetallocv(n, ae_false, &subsolver->retainnegativebclm, _state); + bsetallocv(n, ae_false, &subsolver->retainpositivebclm, _state); + for(i=0; i<=n-1; i++) + { + subsolver->curbndl.ptr.p_double[i] = -nlcsqp_gettrustregionk(x, i, state->trustrad, _state); + subsolver->curbndu.ptr.p_double[i] = nlcsqp_gettrustregionk(x, i, state->trustrad, _state); + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_greater(state->scaledbndl.ptr.p_double[i]-x->ptr.p_double[i],subsolver->curbndl.ptr.p_double[i]) ) + { + subsolver->curbndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]-x->ptr.p_double[i]; + subsolver->retainnegativebclm.ptr.p_bool[i] = ae_true; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_less(state->scaledbndu.ptr.p_double[i]-x->ptr.p_double[i],subsolver->curbndu.ptr.p_double[i]) ) + { + subsolver->curbndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]-x->ptr.p_double[i]; + subsolver->retainpositivebclm.ptr.p_bool[i] = ae_true; + } + } + + /* + * Prepare storage for "effective" constraining matrix + */ + nnz = subsolver->sparserawlc.ridx.ptr.p_int[nec+nic]; + for(i=0; i<=nlec+nlic-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( jac->ptr.pp_double[1+i][j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + nnz = nnz+2*nec+nic; + nnz = nnz+2*nlec+nlic; + ivectorgrowto(&subsolver->sparseefflc.ridx, lccnt+1, _state); + rvectorgrowto(&subsolver->sparseefflc.vals, nnz, _state); + ivectorgrowto(&subsolver->sparseefflc.idx, nnz, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.didx, lccnt, _state); + ivectorsetlengthatleast(&subsolver->sparseefflc.uidx, lccnt, _state); + subsolver->sparseefflc.m = 0; + subsolver->sparseefflc.n = nslack; + subsolver->sparseefflc.matrixtype = 1; + + /* + * Append linear equality/inequality constraints + * + * Scan sparsified linear constraints stored in sparserawlc[], skip ones + * which are inactive anywhere in the trust region. + */ + rvectorsetlengthatleast(&subsolver->tmp0, nslack, _state); + for(i=0; i<=n-1; i++) + { + subsolver->tmp0.ptr.p_double[i] = x->ptr.p_double[i]; + } + for(i=n; i<=nslack-1; i++) + { + subsolver->tmp0.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nec+nic-1; i++) + { + + /* + * Calculate: + * * VRight - product of X[] (extended with zeros up to NSlack elements) + * and AR[i] - Ith row of sparserawlc matrix. + * * VMax - maximum value of X*ARi computed over trust region + */ + vright = (double)(0); + vmax = (double)(0); + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + j = subsolver->sparserawlc.idx.ptr.p_int[k]; + v = x->ptr.p_double[j]; + vv = subsolver->sparserawlc.vals.ptr.p_double[k]; + vright = vright+vv*v; + if( vv>=(double)0 ) + { + vmax = vmax+vv*(v+subsolver->curbndu.ptr.p_double[j]); + } + else + { + vmax = vmax+vv*(v+subsolver->curbndl.ptr.p_double[j]); + } + } + + /* + * Linear constraints are passed 'as is', without additional rescaling + */ + subsolver->rescalelag.ptr.p_double[i] = 1.0; + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (the row itself is retained but + * filled by zeros). + */ + if( i>=nec&&vmax<=state->scaledcleic.ptr.pp_double[i][n] ) + { + offs = subsolver->sparseefflc.ridx.ptr.p_int[i]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslackic+(i-nec); + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = offs+1; + subsolver->cural.ptr.p_double[i] = 0.0; + subsolver->curau.ptr.p_double[i] = 0.0; + subsolver->curbndl.ptr.p_double[offsslackic+(i-nec)] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslackic+(i-nec)] = (double)(0); + subsolver->rescalelag.ptr.p_double[i] = 0.0; + continue; + } + + /* + * Start working on row I + */ + offs = subsolver->sparseefflc.ridx.ptr.p_int[i]; + + /* + * Copy constraint from sparserawlc[] to sparseefflc[] + */ + j0 = subsolver->sparserawlc.ridx.ptr.p_int[i]; + j1 = subsolver->sparserawlc.ridx.ptr.p_int[i+1]-1; + for(k=j0; k<=j1; k++) + { + subsolver->sparseefflc.idx.ptr.p_int[offs] = subsolver->sparserawlc.idx.ptr.p_int[k]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = subsolver->sparserawlc.vals.ptr.p_double[k]; + offs = offs+1; + } + + /* + * Set up slack variables + */ + if( isparseefflc.vals.ptr.p_double[offs+0] = (double)(-1); + subsolver->sparseefflc.vals.ptr.p_double[offs+1] = (double)(1); + subsolver->sparseefflc.idx.ptr.p_int[offs+0] = offsslackec+2*i+0; + subsolver->sparseefflc.idx.ptr.p_int[offs+1] = offsslackec+2*i+1; + offs = offs+2; + } + else + { + + /* + * Slack variables for inequality constraints + */ + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslackic+(i-nec); + offs = offs+1; + } + + /* + * Finalize row + */ + subsolver->sparseefflc.ridx.ptr.p_int[i+1] = offs; + + /* + * Set up bounds and slack part of D0. + * + * NOTE: bounds for equality and inequality constraints are + * handled differently + */ + v = vright-state->scaledcleic.ptr.pp_double[i][n]; + if( icural.ptr.p_double[i] = -v; + subsolver->curau.ptr.p_double[i] = -v; + subsolver->curbndl.ptr.p_double[offsslackec+2*i+0] = (double)(0); + subsolver->curbndl.ptr.p_double[offsslackec+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslackec+2*i+0] = ae_fabs(v, _state); + subsolver->curbndu.ptr.p_double[offsslackec+2*i+1] = ae_fabs(v, _state); + if( ae_fp_greater_eq(v,(double)(0)) ) + { + subsolver->d0.ptr.p_double[offsslackec+2*i+0] = ae_fabs(v, _state); + subsolver->d0.ptr.p_double[offsslackec+2*i+1] = (double)(0); + } + else + { + subsolver->d0.ptr.p_double[offsslackec+2*i+0] = (double)(0); + subsolver->d0.ptr.p_double[offsslackec+2*i+1] = ae_fabs(v, _state); + } + } + else + { + *sumc1 = *sumc1+ae_maxreal(v, 0.0, _state); + subsolver->cural.ptr.p_double[i] = _state->v_neginf; + subsolver->curau.ptr.p_double[i] = -v; + subsolver->curbndl.ptr.p_double[offsslackic+(i-nec)] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslackic+(i-nec)] = ae_maxreal(v, (double)(0), _state); + subsolver->d0.ptr.p_double[offsslackic+(i-nec)] = ae_maxreal(v, (double)(0), _state); + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+(nec+nic); + + /* + * Append nonlinear equality/inequality constraints + */ + for(i=0; i<=nlec+nlic-1; i++) + { + + /* + * Calculate: + * * rescale coefficient used to normalize constraints + * * VMax - maximum of constraint value over trust region + */ + vmax = fi->ptr.p_double[1+i]; + vv = (double)(0); + for(j=0; j<=n-1; j++) + { + v = jac->ptr.pp_double[1+i][j]; + vv = vv+v*v; + if( v>=(double)0 ) + { + vmax = vmax+v*subsolver->curbndu.ptr.p_double[j]; + } + else + { + vmax = vmax+v*subsolver->curbndl.ptr.p_double[j]; + } + } + rescaleby = (double)1/coalesce(ae_sqrt(vv, _state), (double)(1), _state); + + /* + * Nonlinear constraints are passed with normalization + */ + subsolver->rescalelag.ptr.p_double[nec+nic+i] = rescaleby; + + /* + * If constraint is an inequality one and guaranteed to be inactive + * within trust region, it is skipped (row itself is retained but + * filled by zeros). + */ + if( i>=nlec&&vmax<=0.0 ) + { + offs = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacknlic+(i-nlec); + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = offs+1; + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = 0.0; + subsolver->curbndl.ptr.p_double[offsslacknlic+(i-nlec)] = 0.0; + subsolver->curbndu.ptr.p_double[offsslacknlic+(i-nlec)] = 0.0; + subsolver->d0.ptr.p_double[offsslacknlic+(i-nlec)] = 0.0; + subsolver->rescalelag.ptr.p_double[nec+nic+i] = 0.0; + continue; + } + + /* + * Copy scaled row + */ + offs = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i]; + for(j=0; j<=n-1; j++) + { + if( jac->ptr.pp_double[1+i][j]!=0.0 ) + { + subsolver->sparseefflc.vals.ptr.p_double[offs] = rescaleby*jac->ptr.pp_double[1+i][j]; + subsolver->sparseefflc.idx.ptr.p_int[offs] = j; + offs = offs+1; + } + } + if( isparseefflc.vals.ptr.p_double[offs+0] = (double)(-1); + subsolver->sparseefflc.vals.ptr.p_double[offs+1] = (double)(1); + subsolver->sparseefflc.idx.ptr.p_int[offs+0] = offsslacknlec+2*i+0; + subsolver->sparseefflc.idx.ptr.p_int[offs+1] = offsslacknlec+2*i+1; + offs = offs+2; + } + else + { + + /* + * Add slack terms for inequality constraints + */ + subsolver->sparseefflc.vals.ptr.p_double[offs] = (double)(-1); + subsolver->sparseefflc.idx.ptr.p_int[offs] = offsslacknlic+(i-nlec); + offs = offs+1; + } + subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m+i+1] = offs; + + /* + * Set box constraints on slack variables and bounds on linear equality/inequality constraints + */ + v = rescaleby*fi->ptr.p_double[1+i]; + if( iptr.p_double[1+i], _state); + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = -v; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = -v; + subsolver->curbndl.ptr.p_double[offsslacknlec+2*i+0] = (double)(0); + subsolver->curbndl.ptr.p_double[offsslacknlec+2*i+1] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknlec+2*i+0] = ae_fabs(v, _state); + subsolver->curbndu.ptr.p_double[offsslacknlec+2*i+1] = ae_fabs(v, _state); + if( ae_fp_greater_eq(v,(double)(0)) ) + { + subsolver->d0.ptr.p_double[offsslacknlec+2*i+0] = ae_fabs(v, _state); + subsolver->d0.ptr.p_double[offsslacknlec+2*i+1] = (double)(0); + } + else + { + subsolver->d0.ptr.p_double[offsslacknlec+2*i+0] = (double)(0); + subsolver->d0.ptr.p_double[offsslacknlec+2*i+1] = ae_fabs(v, _state); + } + } + else + { + + /* + * Inequality constraint + */ + *sumc1 = *sumc1+ae_maxreal(fi->ptr.p_double[1+i], 0.0, _state); + subsolver->cural.ptr.p_double[subsolver->sparseefflc.m+i] = _state->v_neginf; + subsolver->curau.ptr.p_double[subsolver->sparseefflc.m+i] = -v; + subsolver->curbndl.ptr.p_double[offsslacknlic+(i-nlec)] = (double)(0); + subsolver->curbndu.ptr.p_double[offsslacknlic+(i-nlec)] = ae_maxreal(v, (double)(0), _state); + subsolver->d0.ptr.p_double[offsslacknlic+(i-nlec)] = ae_maxreal(v, (double)(0), _state); + } + } + subsolver->sparseefflc.m = subsolver->sparseefflc.m+(nlec+nlic); + + /* + * Finalize sparse matrix structure + */ + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.idx.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + ae_assert(subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]<=subsolver->sparseefflc.vals.cnt, "QPSubproblemSolve: critical integrity check failed", _state); + subsolver->sparseefflc.ninitialized = subsolver->sparseefflc.ridx.ptr.p_int[subsolver->sparseefflc.m]; + sparseinitduidx(&subsolver->sparseefflc, _state); + + /* + * Solve quadratic program with IPM. + * + * We always treat its result as a valid solution, even for TerminationType<=0. + * In case anything is wrong with solution vector, we will detect it during line + * search phase (merit function does not increase). + * + * NOTE: because we cleaned up constraints that are DEFINITELY inactive within + * trust region, we do not have to worry about StopOnExcessiveBounds option. + */ + rsetallocv(nslack, state->trustrad, &subsolver->tmps, _state); + for(i=0; i<=n-1; i++) + { + subsolver->tmps.ptr.p_double[i] = nlcsqp_gettrustregionk(x, i, state->trustrad, _state); + } + rsetallocv(nslack, 0.0, &subsolver->tmporigin, _state); + if( dotrace ) + { + stimerstart(&state->timerqp, _state); + } + if( state->usedensebfgs ) + { + + /* + * Dense BFGS is used to generate a quasi-Newton matrix, + * dense IPM is used to solve QP subproblems. + */ + hessiangetmatrix(hess, ae_true, &subsolver->denseh, _state); + for(i=0; i<=n-1; i++) + { + rmulr(n, alphah, &subsolver->denseh, i, _state); + } + vipminitdensewithslacks(&subsolver->ipmsolver, &subsolver->tmps, &subsolver->tmporigin, n, nslack, ae_true, _state); + vipmsetquadraticlinear(&subsolver->ipmsolver, &subsolver->denseh, &subsolver->sparsedummy, 0, ae_true, &subsolver->curb, _state); + vipmsetconstraints(&subsolver->ipmsolver, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, _state); + vipmoptimize(&subsolver->ipmsolver, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + } + else + { + + /* + * Low-rank quasi-Newton matrix with positive-only corrections is used, + * sparse IPM with low-rank updates is used to solve QP subproblems. + */ + hessiangetlowrankstabilized(hess, &subsolver->tmpdiag, &subsolver->tmpcorrc, &subsolver->hesscorrd, &subsolver->hessrank, _state); + ae_assert(ae_fp_eq(alphah,(double)(0))||ae_fp_eq(alphah,(double)(1)), "QPSubproblemSolve: AlphaH is neither 0 nor 1", _state); + subsolver->hesssparsediag.matrixtype = 1; + subsolver->hesssparsediag.m = nslack; + subsolver->hesssparsediag.n = nslack; + iallocv(nslack+1, &subsolver->hesssparsediag.ridx, _state); + iallocv(nslack, &subsolver->hesssparsediag.idx, _state); + rallocv(nslack, &subsolver->hesssparsediag.vals, _state); + subsolver->hesssparsediag.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nslack-1; i++) + { + subsolver->hesssparsediag.idx.ptr.p_int[i] = i; + subsolver->hesssparsediag.vals.ptr.p_double[i] = 0.0; + subsolver->hesssparsediag.ridx.ptr.p_int[i+1] = i+1; + } + raddv(n, alphah, &subsolver->tmpdiag, &subsolver->hesssparsediag.vals, _state); + sparsecreatecrsinplace(&subsolver->hesssparsediag, _state); + if( subsolver->hessrank>0 ) + { + rsetallocm(subsolver->hessrank, nslack, 0.0, &subsolver->hesscorrc, _state); + if( ae_fp_neq(alphah,(double)(0)) ) + { + rcopym(subsolver->hessrank, n, &subsolver->tmpcorrc, &subsolver->hesscorrc, _state); + } + } + ipm2init(&subsolver->ipm2, &subsolver->tmps, &subsolver->tmporigin, nslack, &subsolver->densedummy, &subsolver->hesssparsediag, 1, ae_true, &subsolver->hesscorrc, &subsolver->hesscorrd, subsolver->hessrank, &subsolver->curb, 0.0, &subsolver->curbndl, &subsolver->curbndu, &subsolver->sparseefflc, subsolver->sparseefflc.m, &subsolver->densedummy, 0, &subsolver->cural, &subsolver->curau, ae_false, ae_false, _state); + ipm2optimize(&subsolver->ipm2, ae_false, &subsolver->tmp0, &subsolver->tmp1, &subsolver->tmp2, terminationtype, _state); + } + if( dotrace ) + { + stimerstop(&state->timerqp, _state); + } + + /* + * Unpack results + */ + rcopyv(nslack, &subsolver->tmp0, d, _state); + for(i=0; i<=n-1; i++) + { + lagbcmult->ptr.p_double[i] = (double)(0); + if( subsolver->retainpositivebclm.ptr.p_bool[i]&&ae_fp_greater(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + if( subsolver->retainnegativebclm.ptr.p_bool[i]&&ae_fp_less(subsolver->tmp1.ptr.p_double[i],(double)(0)) ) + { + lagbcmult->ptr.p_double[i] = subsolver->tmp1.ptr.p_double[i]; + } + } + rcopyv(lccnt, &subsolver->tmp2, lagxcmult, _state); + rmergemulv(lccnt, &subsolver->rescalelag, lagxcmult, _state); + + /* + * Compute predicted decrease in an L1-penalized quadratic model + */ + *predictedchangemodel = rdotv(n, d, &subsolver->curb, _state)+0.5*hessianvmv(hess, d, _state); + *predictedchangepenalty = (double)(0); + for(i=0; i<=nec+nic-1; i++) + { + v = rdotvr(n, x, &state->scaledcleic, i, _state)-state->scaledcleic.ptr.pp_double[i][n]; + vv = v+rdotvr(n, d, &state->scaledcleic, i, _state); + *predictedchangepenalty = *predictedchangepenalty+rcase2(iptr.p_double[1+i]; + vv = v+rdotvr(n, d, jac, 1+i, _state); + *predictedchangepenalty = *predictedchangepenalty+rcase2(iptr.p_double[i]/nlcsqp_gettrustregionk(x, i, state->trustrad, _state), _state), _state); + } + return result; +} + + +/************************************************************************* +Copies X to State.X +*************************************************************************/ +static void nlcsqp_sqpsendx(minsqpstate* state, + /* Real */ const ae_vector* xs, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&xs->ptr.p_double[i]<=state->scaledbndl.ptr.p_double[i] ) + { + state->x.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&xs->ptr.p_double[i]>=state->scaledbndu.ptr.p_double[i] ) + { + state->x.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + continue; + } + state->x.ptr.p_double[i] = xs->ptr.p_double[i]; + } +} + + +/************************************************************************* +Retrieves F-vector and scaled Jacobian, copies them to FiS and JS. + +Returns True on success, False on failure (when F or J are not finite numbers). +*************************************************************************/ +static ae_bool nlcsqp_sqpretrievefij(const minsqpstate* state, + varsfuncjac* vfj, + ae_state *_state) +{ + ae_int_t nlec; + ae_int_t nlic; + ae_int_t n; + ae_int_t i; + ae_int_t j; + double v; + double vv; + ae_bool result; + + + n = state->n; + nlec = state->nlec; + nlic = state->nlic; + v = (double)(0); + for(i=0; i<=nlec+nlic; i++) + { + vv = (double)1/state->fscales.ptr.p_double[i]; + vfj->fi.ptr.p_double[i] = vv*state->fi.ptr.p_double[i]; + v = v+vfj->fi.ptr.p_double[i]; + for(j=0; j<=n-1; j++) + { + vfj->jac.ptr.pp_double[i][j] = vv*state->j.ptr.pp_double[i][j]; + v = v+vfj->jac.ptr.pp_double[i][j]; + } + } + result = ae_isfinite(v, _state); + return result; +} + + +/************************************************************************* +This function calculates Lagrangian of the problem (in scaled variables): +its value and gradient. + +Additionally it also estimates violation of linear constraints at the point +as well as index of the most violated constraint +*************************************************************************/ +static void nlcsqp_lagrangianfg(minsqpstate* state, + /* Real */ const ae_vector* x, + double trustrad, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* j, + /* Real */ const ae_vector* lagbcmult, + /* Real */ const ae_vector* lagxcmult, + ae_bool uselagrangeterms, + double* f, + /* Real */ ae_vector* g, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + double v; + double vlag; + double vact; + double vd; + ae_bool usesparsegemv; + double lagalpha; + + *f = 0.0; + + n = state->n; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + lagalpha = rcase2(uselagrangeterms, (double)(1), (double)(0), _state); + + /* + * Target function + */ + *f = fi->ptr.p_double[0]; + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = j->ptr.pp_double[0][i]; + } + + /* + * Lagrangian terms for box constraints + */ + for(i=0; i<=n-1; i++) + { + + /* + * Lagrangian terms + */ + *f = *f+lagalpha*lagbcmult->ptr.p_double[i]*x->ptr.p_double[i]; + g->ptr.p_double[i] = g->ptr.p_double[i]+lagalpha*lagbcmult->ptr.p_double[i]; + + /* + * Penalty term + */ + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(x->ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) + { + *f = *f+nlcsqp_augmentationfactor*(x->ptr.p_double[i]-state->scaledbndl.ptr.p_double[i])*(x->ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]); + g->ptr.p_double[i] = g->ptr.p_double[i]+(double)2*nlcsqp_augmentationfactor*(x->ptr.p_double[i]-state->scaledbndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(x->ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + *f = *f+nlcsqp_augmentationfactor*(x->ptr.p_double[i]-state->scaledbndu.ptr.p_double[i])*(x->ptr.p_double[i]-state->scaledbndu.ptr.p_double[i]); + g->ptr.p_double[i] = g->ptr.p_double[i]+(double)2*nlcsqp_augmentationfactor*(x->ptr.p_double[i]-state->scaledbndu.ptr.p_double[i]); + } + } + + /* + * Lagrangian terms for linear constraints, constraint violations + */ + if( nec+nic>0 ) + { + usesparsegemv = (double)state->subsolver.sparserawlc.ridx.ptr.p_int[nec+nic]sclagtmp0, ae_maxint(nec+nic, n, _state), _state); + rvectorsetlengthatleast(&state->sclagtmp1, ae_maxint(nec+nic, n, _state), _state); + if( usesparsegemv ) + { + sparsemv(&state->subsolver.sparserawlc, x, &state->sclagtmp0, _state); + } + else + { + rmatrixgemv(nec+nic, n, 1.0, &state->scaledcleic, 0, 0, 0, x, 0, 0.0, &state->sclagtmp0, 0, _state); + } + for(i=0; i<=nec+nic-1; i++) + { + + /* + * Prepare + */ + v = state->sclagtmp0.ptr.p_double[i]-state->scaledcleic.ptr.pp_double[i][n]; + vlag = lagalpha*lagxcmult->ptr.p_double[i]; + state->sclagtmp1.ptr.p_double[i] = (double)(0); + + /* + * Primary Lagrangian term + */ + vact = v; + vd = (double)(1); + *f = *f+vlag*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+vlag*vd; + + /* + * Quadratic augmentation term + */ + if( i(double)0 ) + { + vact = v; + } + else + { + vact = (double)(0); + } + *f = *f+0.5*nlcsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcsqp_augmentationfactor*vact; + } + if( usesparsegemv ) + { + sparsemtv(&state->subsolver.sparserawlc, &state->sclagtmp1, &state->sclagtmp0, _state); + for(i=0; i<=n-1; i++) + { + g->ptr.p_double[i] = g->ptr.p_double[i]+state->sclagtmp0.ptr.p_double[i]; + } + } + else + { + rmatrixgemv(n, nec+nic, 1.0, &state->scaledcleic, 0, 0, 1, &state->sclagtmp1, 0, 1.0, g, 0, _state); + } + } + + /* + * Lagrangian terms for nonlinear constraints + */ + rvectorsetlengthatleast(&state->sclagtmp1, nlec+nlic, _state); + for(i=0; i<=nlec+nlic-1; i++) + { + v = fi->ptr.p_double[1+i]; + vlag = lagalpha*lagxcmult->ptr.p_double[nec+nic+i]; + state->sclagtmp1.ptr.p_double[i] = (double)(0); + + /* + * Lagrangian term + */ + vact = v; + vd = (double)(1); + *f = *f+vlag*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+vlag*vd; + + /* + * Augmentation term + */ + if( i(double)0 ) + { + vact = v; + } + else + { + vact = (double)(0); + } + *f = *f+0.5*nlcsqp_augmentationfactor*vact*vact; + state->sclagtmp1.ptr.p_double[i] = state->sclagtmp1.ptr.p_double[i]+nlcsqp_augmentationfactor*vact; + } + rmatrixgemv(n, nlec+nlic, 1.0, j, 1, 0, 1, &state->sclagtmp1, 0, 1.0, g, 0, _state); +} + + +/************************************************************************* +This function calculates L1-penalized merit function +*************************************************************************/ +static double nlcsqp_meritfunction(minsqpstate* state, + const varsfuncjac* vfj, + double meritmu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + double v; + double result; + + + ae_assert(vfj->isdense, "SQP: integrity check 1057 failed", _state); + n = state->n; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + + /* + * Merit function and Lagrangian: primary term + */ + result = vfj->fi.ptr.p_double[0]; + + /* + * Merit function: augmentation and penalty for linear constraints + */ + rvectorsetlengthatleast(&state->mftmp0, nec+nic, _state); + rmatrixgemv(nec+nic, n, 1.0, &state->scaledcleic, 0, 0, 0, &vfj->x, 0, 0.0, &state->mftmp0, 0, _state); + for(i=0; i<=nec+nic-1; i++) + { + v = state->mftmp0.ptr.p_double[i]-state->scaledcleic.ptr.pp_double[i][n]; + if( ifi.ptr.p_double[1+i]; + if( in; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + + /* + * Merit function and Lagrangian: primary term + */ + *meritf = fi->ptr.p_double[0]; + *rawlag = fi->ptr.p_double[0]; + + /* + * Lagrangian: handle box constraints + * + * NOTE: we do not add box constrained term to the merit function because + * box constraints are handled exactly and we do not violate them. + */ + for(i=0; i<=n-1; i++) + { + *rawlag = *rawlag+lagbcmult->ptr.p_double[i]*x->ptr.p_double[i]; + } + + /* + * Merit function: augmentation and penalty for linear constraints + */ + rvectorsetlengthatleast(&state->mftmp0, nec+nic, _state); + rmatrixgemv(nec+nic, n, 1.0, &state->scaledcleic, 0, 0, 0, x, 0, 0.0, &state->mftmp0, 0, _state); + for(i=0; i<=nec+nic-1; i++) + { + v = state->mftmp0.ptr.p_double[i]-state->scaledcleic.ptr.pp_double[i][n]; + if( iptr.p_double[i]*v; + } + else + { + + /* + * Merit function: augmentation term + L1 penalty term + */ + *meritf = *meritf+meritmu*ae_maxreal(v, (double)(0), _state); + + /* + * Raw Lagrangian + */ + *rawlag = *rawlag+lagxcmult->ptr.p_double[i]*v; + } + } + + /* + * Merit function: augmentation and penalty for nonlinear constraints + */ + for(i=0; i<=nlec+nlic-1; i++) + { + v = fi->ptr.p_double[1+i]; + if( iptr.p_double[nec+nic+i]*v; + } + else + { + + /* + * Merit function: augmentation term + L1 penalty term + */ + *meritf = *meritf+meritmu*ae_maxreal(v, (double)(0), _state); + + /* + * Raw Lagrangian + */ + *rawlag = *rawlag+lagxcmult->ptr.p_double[nec+nic+i]*v; + } + } +} + + +/************************************************************************* +This function analyzes constraint linearizations at the proposed candidate +point. Depending on outcome, proposes to increase MeritMu or not. + +If no update is necessary (the best outcome), False will be returned. + + -- ALGLIB -- + Copyright 13.03.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool nlcsqp_penaltiesneedincrease(minsqpstate* state, + const varsfuncjac* currentlinearization, + /* Real */ const ae_vector* dtrial, + double predictedchangemodel, + double predictedchangepenalty, + ae_bool dotrace, + ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + ae_int_t nslack; + ae_int_t i; + ae_int_t j; + ae_int_t tt; + double tol; + double tol2; + double constrval; + double allowederr; + ae_bool failedtoenforce; + ae_bool failedtoenforceinf; + ae_bool infeasiblewithinbox; + double dummy0; + double dummy1; + double dummy2; + double dummy3; + double penaltyatx; + double penaltyatd; + double penaltyatdinf; + double meritdecrease; + double penaltydecrease; + double mxd; + double expandedrad; + double cx; + double cxd; + double sumabs; + ae_bool result; + + + n = state->n; + nec = state->nec; + nic = state->nic; + nlec = state->nlec; + nlic = state->nlic; + nslack = n+2*(nec+nlec)+(nic+nlic); + result = ae_false; + tol = 1.0E-6*state->trustrad*((double)1+rmaxabsv(n, ¤tlinearization->x, _state)); + + /* + * Already too big, skip analysis + */ + if( ae_fp_greater_eq(state->meritmu,0.9*nlcsqp_maxmeritmu) ) + { + return result; + } + + /* + * Allocate storage + */ + rallocv(nslack, &state->tmppend, _state); + rallocv(n, &state->dummylagbcmult, _state); + rallocv(nec+nic+nlec+nlic, &state->dummylagxcmult, _state); + + /* + * Compute the following quantities: + * * penalty at X + * * penalty at X+D + * * whether we failed to enforce constraints at X+D or not + * * whether any single constraint can be made feasible within max(|D|)-sized box (ignoring other constraints) or not + */ + penaltyatx = (double)(0); + penaltyatd = (double)(0); + failedtoenforce = ae_false; + infeasiblewithinbox = ae_false; + mxd = rmaxabsv(n, dtrial, _state); + expandedrad = 1.1*mxd; + tol2 = ae_maxreal(ae_sqrt(ae_machineepsilon, _state)*state->trustrad, (double)1000*ae_machineepsilon, _state); + for(i=0; i<=nec+nic-1; i++) + { + cx = rdotvr(n, ¤tlinearization->x, &state->scaledcleic, i, _state)-state->scaledcleic.ptr.pp_double[i][n]; + cxd = cx+rdotvr(n, dtrial, &state->scaledcleic, i, _state); + cx = rcase2(iscaledcleic.ptr.pp_double[i][j], _state); + } + infeasiblewithinbox = infeasiblewithinbox||ae_fp_greater(ae_fabs(cx, _state),sumabs*expandedrad+tol2); + penaltyatx = penaltyatx+ae_fabs(cx, _state); + penaltyatd = penaltyatd+ae_fabs(cxd, _state); + failedtoenforce = failedtoenforce||ae_fp_greater(ae_fabs(cxd, _state),sumabs*tol); + } + for(i=1; i<=nlec+nlic; i++) + { + cx = currentlinearization->fi.ptr.p_double[i]; + cxd = cx+rdotvr(n, dtrial, ¤tlinearization->jac, i, _state); + cx = rcase2(i<1+nlec, cx, ae_maxreal(cx, 0.0, _state), _state); + cxd = rcase2(i<1+nlec, cxd, ae_maxreal(cxd, 0.0, _state), _state); + sumabs = (double)(0); + for(j=0; j<=n-1; j++) + { + sumabs = sumabs+ae_fabs(currentlinearization->jac.ptr.pp_double[i][j], _state); + } + infeasiblewithinbox = infeasiblewithinbox||ae_fp_greater(ae_fabs(cx, _state),sumabs*expandedrad+tol2); + penaltyatx = penaltyatx+ae_fabs(cx, _state); + penaltyatd = penaltyatd+ae_fabs(cxd, _state); + failedtoenforce = failedtoenforce||ae_fp_greater(ae_fabs(cxd, _state),sumabs*tol); + } + if( infeasiblewithinbox&&ae_fp_less(mxd,0.9*state->trustrad) ) + { + + /* + * MeritMu must be increased if a short DTrial was proposed, but there are some + * constraints that are infeasible within max|DTrial|-sized box + */ + result = ae_true; + if( dotrace ) + { + ae_trace("> a short DTrial was proposed, but some constraints are infeasible within trust region; MeritMu increased, iteration skipped\n"); + } + } + + /* + * We may need to increase MeritMu + */ + if( failedtoenforce ) + { + + /* + * We failed to drive constraints linearizations to zero. But what is the best + * theoretically possible reduction (ignoring quadratic model)? + */ + if( !nlcsqp_qpsubproblemsolve(state, &state->subsolver, ¤tlinearization->x, ¤tlinearization->fi, ¤tlinearization->jac, &state->hess, 0.0, 0.0, &state->tmppend, &state->dummylagbcmult, &state->dummylagxcmult, dotrace, &tt, &dummy0, &dummy1, &dummy2, &dummy3, _state) ) + { + if( dotrace ) + { + ae_trace("> [WARNING] QP subproblem failed with TerminationType=%0d when updating MeritMu\n", + (int)(tt)); + } + return result; + } + penaltyatdinf = (double)(0); + failedtoenforceinf = ae_false; + for(i=0; i<=nec+nic-1; i++) + { + constrval = -state->scaledcleic.ptr.pp_double[i][n]; + allowederr = (double)(0); + for(j=0; j<=n-1; j++) + { + constrval = constrval+state->scaledcleic.ptr.pp_double[i][j]*(currentlinearization->x.ptr.p_double[j]+state->tmppend.ptr.p_double[j]); + allowederr = allowederr+ae_fabs(state->scaledcleic.ptr.pp_double[i][j]*tol, _state); + } + if( i>=nec ) + { + constrval = ae_maxreal(constrval, 0.0, _state); + } + penaltyatdinf = penaltyatdinf+ae_fabs(constrval, _state); + failedtoenforceinf = failedtoenforceinf||ae_fp_greater(ae_fabs(constrval, _state),allowederr); + } + for(i=0; i<=nlec+nlic-1; i++) + { + constrval = currentlinearization->fi.ptr.p_double[1+i]; + allowederr = (double)(0); + for(j=0; j<=n-1; j++) + { + constrval = constrval+currentlinearization->jac.ptr.pp_double[1+i][j]*state->tmppend.ptr.p_double[j]; + allowederr = allowederr+ae_fabs(currentlinearization->jac.ptr.pp_double[1+i][j]*tol, _state); + } + if( i>=nlec ) + { + constrval = ae_maxreal(constrval, 0.0, _state); + } + penaltyatdinf = penaltyatdinf+ae_fabs(constrval, _state); + failedtoenforceinf = failedtoenforceinf||ae_fp_greater(ae_fabs(constrval, _state),allowederr); + } + + /* + * Branch on the constraint status within trust region + */ + if( failedtoenforceinf ) + { + + /* + * Constraints are infeasible within the trust region, check that the actual penalty decrease + * is at least some fraction of the best possible decrease. + */ + if( ae_fp_less(penaltyatx-penaltyatd,nlcsqp_meritmueps*ae_maxreal(penaltyatx-penaltyatdinf, 0.0, _state))&&ae_fp_less(penaltyatdinf,penaltyatx*((double)1-nlcsqp_constraintsstagnationeps)) ) + { + + /* + * Merit function does not decrease fast enough, we must increase MeritMu + */ + result = ae_true; + if( dotrace ) + { + ae_trace("> constraints infeasibility does not decrease fast enough, MeritMu increased, iteration skipped\n"); + } + } + } + else + { + + /* + * Constraints are feasible within trust region, we must increase MeritMu + */ + result = ae_true; + if( dotrace ) + { + ae_trace("> MeritMu penalty does not enforce constraints feasibility, MeritMu increased, iteration skipped\n"); + } + } + } + + /* + * Now we check that decrease in the quadratic model + penalty is a significant fraction of + * the decrease in the penalty. + */ + meritdecrease = -(predictedchangemodel+state->meritmu*predictedchangepenalty); + penaltydecrease = -state->meritmu*predictedchangepenalty; + if( ae_fp_less(meritdecrease,nlcsqp_meritmueps*penaltydecrease) ) + { + result = ae_true; + if( dotrace ) + { + ae_trace("> sufficient negativity condition does not hold, MeritMu increased, iteration skipped\n"); + } + } + return result; +} + + +/************************************************************************* +Returns k-th component of the trust region + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static double nlcsqp_gettrustregionk(/* Real */ const ae_vector* xcur, + ae_int_t k, + double trustrad, + ae_state *_state) +{ + double result; + + + result = trustrad*ae_maxreal(ae_fabs(xcur->ptr.p_double[k], _state), (double)(1), _state); + return result; +} + + +/************************************************************************* +Adjusts merit function value using non-monotonic correction (sets it to +maximum among several last values, returns adjusted value) + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static double nlcsqp_nonmonotonicadjustment(minsqpstate* state, + double fraw, + ae_state *_state) +{ + ae_frame _frame_block; + varsfuncjac *vfj; + ae_smart_ptr _vfj; + ae_int_t i; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&_vfj, 0, sizeof(_vfj)); + ae_smart_ptr_init(&_vfj, (void**)&vfj, ae_false, _state, ae_true); + + result = fraw; + for(i=0; i<=ae_minint(state->nonmonotoniccnt, nlcsqp_nonmonotoniclen, _state)-1; i++) + { + ae_obj_array_get(&state->nonmonotonicmem, i, &_vfj, _state); + result = ae_maxreal(result, nlcsqp_meritfunction(state, vfj, state->meritmu, _state), _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Saves current point to the nonmonotonic memory. + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static void nlcsqp_nonmonotonicsave(minsqpstate* state, + const varsfuncjac* cur, + ae_state *_state) +{ + ae_frame _frame_block; + varsfuncjac *vfj; + ae_smart_ptr _vfj; + + ae_frame_make(_state, &_frame_block); + memset(&_vfj, 0, sizeof(_vfj)); + ae_smart_ptr_init(&_vfj, (void**)&vfj, ae_false, _state, ae_true); + + if( nlcsqp_nonmonotoniclen==0 ) + { + ae_frame_leave(_state); + return; + } + if( state->nonmonotoniccntnonmonotonicmem)==state->nonmonotoniccnt, "SQP: integrity check 3710 failed", _state); + vfj = (varsfuncjac*)ae_malloc(sizeof(varsfuncjac), _state); /* note: using vfj as a temporary prior to assigning its value to _vfj */ + memset(vfj, 0, sizeof(varsfuncjac)); + _varsfuncjac_init(vfj, _state, ae_false); + ae_smart_ptr_assign(&_vfj, vfj, ae_true, ae_true, (ae_int_t)sizeof(varsfuncjac), _varsfuncjac_init_copy, _varsfuncjac_destroy); + vfjcopy(cur, vfj, _state); + ae_obj_array_append_transfer(&state->nonmonotonicmem, &_vfj, _state); + } + else + { + + /* + * Rewrite one of points in the buffer + */ + ae_assert(ae_obj_array_get_length(&state->nonmonotonicmem)==nlcsqp_nonmonotoniclen, "SQP: integrity check 3711 failed", _state); + ae_obj_array_get(&state->nonmonotonicmem, state->nonmonotoniccnt%nlcsqp_nonmonotoniclen, &_vfj, _state); + vfjcopy(cur, vfj, _state); + } + state->nonmonotoniccnt = state->nonmonotoniccnt+1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Rescales target/constraints stored in the nonmonotonic memory. + + -- ALGLIB -- + Copyright 25.09.2023 by Bochkanov Sergey +*************************************************************************/ +static void nlcsqp_nonmonotonicmultiplyby(minsqpstate* state, + ae_int_t jacrow, + double v, + ae_state *_state) +{ + ae_frame _frame_block; + varsfuncjac *vfj; + ae_smart_ptr _vfj; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&_vfj, 0, sizeof(_vfj)); + ae_smart_ptr_init(&_vfj, (void**)&vfj, ae_false, _state, ae_true); + + for(i=0; i<=ae_minint(state->nonmonotoniccnt, nlcsqp_nonmonotoniclen, _state)-1; i++) + { + ae_obj_array_get(&state->nonmonotonicmem, i, &_vfj, _state); + ae_assert(vfj->isdense, "SQP: integrity check 7600 failed", _state); + vfj->fi.ptr.p_double[jacrow] = vfj->fi.ptr.p_double[jacrow]*v; + rmulr(vfj->n, v, &vfj->jac, jacrow, _state); + } + ae_frame_leave(_state); +} + + +void _minsqpsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minsqpsubsolver *p = (minsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_init(&p->ipmsolver, _state, make_automatic); + _ipm2state_init(&p->ipm2, _state, make_automatic); + ae_vector_init(&p->curb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cural, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->curau, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparserawlc, _state, make_automatic); + _sparsematrix_init(&p->sparseefflc, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->denseh, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummy1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densedummy, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsedummy, _state, make_automatic); + ae_vector_init(&p->tmps, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmporigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->retainnegativebclm, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->retainpositivebclm, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rescalelag, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpcorrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hessdiag, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->hesscorrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hesscorrd, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->hesssparsediag, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); +} + + +void _minsqpsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minsqpsubsolver *dst = (minsqpsubsolver*)_dst; + const minsqpsubsolver *src = (const minsqpsubsolver*)_src; + _vipmstate_init_copy(&dst->ipmsolver, &src->ipmsolver, _state, make_automatic); + _ipm2state_init_copy(&dst->ipm2, &src->ipm2, _state, make_automatic); + ae_vector_init_copy(&dst->curb, &src->curb, _state, make_automatic); + ae_vector_init_copy(&dst->curbndl, &src->curbndl, _state, make_automatic); + ae_vector_init_copy(&dst->curbndu, &src->curbndu, _state, make_automatic); + ae_vector_init_copy(&dst->cural, &src->cural, _state, make_automatic); + ae_vector_init_copy(&dst->curau, &src->curau, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparserawlc, &src->sparserawlc, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseefflc, &src->sparseefflc, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_matrix_init_copy(&dst->denseh, &src->denseh, _state, make_automatic); + ae_vector_init_copy(&dst->dummy1, &src->dummy1, _state, make_automatic); + ae_matrix_init_copy(&dst->densedummy, &src->densedummy, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsedummy, &src->sparsedummy, _state, make_automatic); + ae_vector_init_copy(&dst->tmps, &src->tmps, _state, make_automatic); + ae_vector_init_copy(&dst->tmporigin, &src->tmporigin, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->retainnegativebclm, &src->retainnegativebclm, _state, make_automatic); + ae_vector_init_copy(&dst->retainpositivebclm, &src->retainpositivebclm, _state, make_automatic); + ae_vector_init_copy(&dst->rescalelag, &src->rescalelag, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpcorrc, &src->tmpcorrc, _state, make_automatic); + ae_vector_init_copy(&dst->tmpdiag, &src->tmpdiag, _state, make_automatic); + ae_vector_init_copy(&dst->hessdiag, &src->hessdiag, _state, make_automatic); + ae_matrix_init_copy(&dst->hesscorrc, &src->hesscorrc, _state, make_automatic); + ae_vector_init_copy(&dst->hesscorrd, &src->hesscorrd, _state, make_automatic); + dst->hessrank = src->hessrank; + _sparsematrix_init_copy(&dst->hesssparsediag, &src->hesssparsediag, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); +} + + +void _minsqpsubsolver_clear(void* _p) +{ + minsqpsubsolver *p = (minsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_clear(&p->ipmsolver); + _ipm2state_clear(&p->ipm2); + ae_vector_clear(&p->curb); + ae_vector_clear(&p->curbndl); + ae_vector_clear(&p->curbndu); + ae_vector_clear(&p->cural); + ae_vector_clear(&p->curau); + _sparsematrix_clear(&p->sparserawlc); + _sparsematrix_clear(&p->sparseefflc); + ae_vector_clear(&p->d0); + ae_matrix_clear(&p->denseh); + ae_vector_clear(&p->dummy1); + ae_matrix_clear(&p->densedummy); + _sparsematrix_clear(&p->sparsedummy); + ae_vector_clear(&p->tmps); + ae_vector_clear(&p->tmporigin); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->retainnegativebclm); + ae_vector_clear(&p->retainpositivebclm); + ae_vector_clear(&p->rescalelag); + ae_matrix_clear(&p->tmpcorrc); + ae_vector_clear(&p->tmpdiag); + ae_vector_clear(&p->hessdiag); + ae_matrix_clear(&p->hesscorrc); + ae_vector_clear(&p->hesscorrd); + _sparsematrix_clear(&p->hesssparsediag); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); +} + + +void _minsqpsubsolver_destroy(void* _p) +{ + minsqpsubsolver *p = (minsqpsubsolver*)_p; + ae_touch_ptr((void*)p); + _vipmstate_destroy(&p->ipmsolver); + _ipm2state_destroy(&p->ipm2); + ae_vector_destroy(&p->curb); + ae_vector_destroy(&p->curbndl); + ae_vector_destroy(&p->curbndu); + ae_vector_destroy(&p->cural); + ae_vector_destroy(&p->curau); + _sparsematrix_destroy(&p->sparserawlc); + _sparsematrix_destroy(&p->sparseefflc); + ae_vector_destroy(&p->d0); + ae_matrix_destroy(&p->denseh); + ae_vector_destroy(&p->dummy1); + ae_matrix_destroy(&p->densedummy); + _sparsematrix_destroy(&p->sparsedummy); + ae_vector_destroy(&p->tmps); + ae_vector_destroy(&p->tmporigin); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->retainnegativebclm); + ae_vector_destroy(&p->retainpositivebclm); + ae_vector_destroy(&p->rescalelag); + ae_matrix_destroy(&p->tmpcorrc); + ae_vector_destroy(&p->tmpdiag); + ae_vector_destroy(&p->hessdiag); + ae_matrix_destroy(&p->hesscorrc); + ae_vector_destroy(&p->hesscorrd); + _sparsematrix_destroy(&p->hesssparsediag); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); +} + + +void _minsqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minsqpstate *p = (minsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->scaledcleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _varsfuncjac_init(&p->stepk, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xprev, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tracegamma, 0, DT_REAL, _state, make_automatic); + _minsqpsubsolver_init(&p->subsolver, _state, make_automatic); + _xbfgshessian_init(&p->hess, _state, make_automatic); + ae_obj_array_init(&p->nonmonotonicmem, _state, make_automatic); + ae_vector_init(&p->lagbcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagxcmult, 0, DT_REAL, _state, make_automatic); + _varsfuncjac_init(&p->cand, _state, make_automatic); + _varsfuncjac_init(&p->corr, _state, make_automatic); + _varsfuncjac_init(&p->probe, _state, make_automatic); + _varsfuncjac_init(&p->currentlinearization, _state, make_automatic); + ae_vector_init(&p->dtrial, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dmu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmppend, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummylagbcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummylagxcmult, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmplaggrad, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpcandlaggrad, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmphdiag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclagtmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sclagtmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mftmp0, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timerqp, _state, make_automatic); + _stimer_init(&p->timercallback, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _minsqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minsqpstate *dst = (minsqpstate*)_dst; + const minsqpstate *src = (const minsqpstate*)_src; + dst->n = src->n; + dst->nec = src->nec; + dst->nic = src->nic; + dst->nlec = src->nlec; + dst->nlic = src->nlic; + dst->usedensebfgs = src->usedensebfgs; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_matrix_init_copy(&dst->scaledcleic, &src->scaledcleic, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->bfgsresetfreq = src->bfgsresetfreq; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->f = src->f; + dst->needfij = src->needfij; + dst->xupdated = src->xupdated; + dst->meritmu = src->meritmu; + dst->trustrad = src->trustrad; + dst->trustradgrowth = src->trustradgrowth; + dst->trustradstagnationcnt = src->trustradstagnationcnt; + dst->fstagnationcnt = src->fstagnationcnt; + _varsfuncjac_init_copy(&dst->stepk, &src->stepk, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->xprev, &src->xprev, _state, make_automatic); + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + ae_vector_init_copy(&dst->tracegamma, &src->tracegamma, _state, make_automatic); + _minsqpsubsolver_init_copy(&dst->subsolver, &src->subsolver, _state, make_automatic); + _xbfgshessian_init_copy(&dst->hess, &src->hess, _state, make_automatic); + ae_obj_array_init_copy(&dst->nonmonotonicmem, &src->nonmonotonicmem, _state, make_automatic); + dst->nonmonotoniccnt = src->nonmonotoniccnt; + ae_vector_init_copy(&dst->lagbcmult, &src->lagbcmult, _state, make_automatic); + ae_vector_init_copy(&dst->lagxcmult, &src->lagxcmult, _state, make_automatic); + _varsfuncjac_init_copy(&dst->cand, &src->cand, _state, make_automatic); + _varsfuncjac_init_copy(&dst->corr, &src->corr, _state, make_automatic); + _varsfuncjac_init_copy(&dst->probe, &src->probe, _state, make_automatic); + _varsfuncjac_init_copy(&dst->currentlinearization, &src->currentlinearization, _state, make_automatic); + ae_vector_init_copy(&dst->dtrial, &src->dtrial, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_vector_init_copy(&dst->d1, &src->d1, _state, make_automatic); + ae_vector_init_copy(&dst->dmu, &src->dmu, _state, make_automatic); + ae_vector_init_copy(&dst->tmppend, &src->tmppend, _state, make_automatic); + ae_vector_init_copy(&dst->tmphd, &src->tmphd, _state, make_automatic); + ae_vector_init_copy(&dst->dummylagbcmult, &src->dummylagbcmult, _state, make_automatic); + ae_vector_init_copy(&dst->dummylagxcmult, &src->dummylagxcmult, _state, make_automatic); + ae_vector_init_copy(&dst->tmplaggrad, &src->tmplaggrad, _state, make_automatic); + ae_vector_init_copy(&dst->tmpcandlaggrad, &src->tmpcandlaggrad, _state, make_automatic); + ae_vector_init_copy(&dst->tmphdiag, &src->tmphdiag, _state, make_automatic); + ae_vector_init_copy(&dst->sclagtmp0, &src->sclagtmp0, _state, make_automatic); + ae_vector_init_copy(&dst->sclagtmp1, &src->sclagtmp1, _state, make_automatic); + ae_vector_init_copy(&dst->mftmp0, &src->mftmp0, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timerqp, &src->timerqp, _state, make_automatic); + _stimer_init_copy(&dst->timercallback, &src->timercallback, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _minsqpstate_clear(void* _p) +{ + minsqpstate *p = (minsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_matrix_clear(&p->scaledcleic); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _varsfuncjac_clear(&p->stepk); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->xprev); + ae_vector_clear(&p->fscales); + ae_vector_clear(&p->tracegamma); + _minsqpsubsolver_clear(&p->subsolver); + _xbfgshessian_clear(&p->hess); + ae_obj_array_clear(&p->nonmonotonicmem); + ae_vector_clear(&p->lagbcmult); + ae_vector_clear(&p->lagxcmult); + _varsfuncjac_clear(&p->cand); + _varsfuncjac_clear(&p->corr); + _varsfuncjac_clear(&p->probe); + _varsfuncjac_clear(&p->currentlinearization); + ae_vector_clear(&p->dtrial); + ae_vector_clear(&p->d0); + ae_vector_clear(&p->d1); + ae_vector_clear(&p->dmu); + ae_vector_clear(&p->tmppend); + ae_vector_clear(&p->tmphd); + ae_vector_clear(&p->dummylagbcmult); + ae_vector_clear(&p->dummylagxcmult); + ae_vector_clear(&p->tmplaggrad); + ae_vector_clear(&p->tmpcandlaggrad); + ae_vector_clear(&p->tmphdiag); + ae_vector_clear(&p->sclagtmp0); + ae_vector_clear(&p->sclagtmp1); + ae_vector_clear(&p->mftmp0); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timerqp); + _stimer_clear(&p->timercallback); + _rcommstate_clear(&p->rstate); +} + + +void _minsqpstate_destroy(void* _p) +{ + minsqpstate *p = (minsqpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_matrix_destroy(&p->scaledcleic); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _varsfuncjac_destroy(&p->stepk); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->xprev); + ae_vector_destroy(&p->fscales); + ae_vector_destroy(&p->tracegamma); + _minsqpsubsolver_destroy(&p->subsolver); + _xbfgshessian_destroy(&p->hess); + ae_obj_array_destroy(&p->nonmonotonicmem); + ae_vector_destroy(&p->lagbcmult); + ae_vector_destroy(&p->lagxcmult); + _varsfuncjac_destroy(&p->cand); + _varsfuncjac_destroy(&p->corr); + _varsfuncjac_destroy(&p->probe); + _varsfuncjac_destroy(&p->currentlinearization); + ae_vector_destroy(&p->dtrial); + ae_vector_destroy(&p->d0); + ae_vector_destroy(&p->d1); + ae_vector_destroy(&p->dmu); + ae_vector_destroy(&p->tmppend); + ae_vector_destroy(&p->tmphd); + ae_vector_destroy(&p->dummylagbcmult); + ae_vector_destroy(&p->dummylagxcmult); + ae_vector_destroy(&p->tmplaggrad); + ae_vector_destroy(&p->tmpcandlaggrad); + ae_vector_destroy(&p->tmphdiag); + ae_vector_destroy(&p->sclagtmp0); + ae_vector_destroy(&p->sclagtmp1); + ae_vector_destroy(&p->mftmp0); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timerqp); + _stimer_destroy(&p->timercallback); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) + + +void ssgdinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + double rad0, + double rad1, + ae_int_t outerits, + double rate0, + double rate1, + double momentum, + ae_int_t maxits, + double rho, + ssgdstate* state, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * Integrity checks + */ + ae_assert(ae_isfinite(rate0, _state), "SSGD: Rate0 is not a finite number", _state); + ae_assert(ae_isfinite(rate1, _state), "SSGD: Rate1 is not a finite number", _state); + ae_assert(ae_isfinite(momentum, _state), "SSGD: Momentum is not a finite number", _state); + ae_assert(ae_isfinite(rad0, _state), "SSGD: Rad0 is not a finite number", _state); + ae_assert(ae_isfinite(rad1, _state), "SSGD: Rad1 is not a finite number", _state); + ae_assert(ae_isfinite(rho, _state), "SSGD: Rho is not a finite number", _state); + ae_assert(ae_fp_greater(rate0,(double)(0)), "SSGD: Rate0<=0", _state); + ae_assert(ae_fp_greater(rate1,(double)(0)), "SSGD: Rate1<=0", _state); + ae_assert(ae_fp_greater_eq(momentum,(double)(0)), "SSGD: Momentum<0", _state); + ae_assert(ae_fp_less(momentum,(double)(1)), "SSGD: Momentum>=1", _state); + ae_assert(ae_fp_greater(rad0,(double)(0)), "SSGD: Rad0<=0", _state); + ae_assert(ae_fp_greater(rad1,(double)(0)), "SSGD: Rad1<=0", _state); + ae_assert(ae_fp_greater_eq(rate0,rate1), "SSGD: Rate00, "SSGD: MaxIts<=0", _state); + ae_assert(outerits>0, "SSGD: OuterIts<=0", _state); + ae_assert(ae_fp_greater_eq(rho,(double)(0)), "SSGD: Rho<0", _state); + + /* + * Initialization + */ + state->n = n; + state->cntlc = cntlc; + state->cntnlc = cntnlc; + state->rate0 = rate0; + state->rate1 = rate1; + state->blur0 = rad0; + state->blur1 = rad1; + state->outerits = outerits; + state->maxits = maxits; + state->rho = coalesce(rho, ssgd_defaultpenalty, _state); + + /* + * Prepare RCOMM state + */ + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 7+1, _state); + state->rstate.stage = -1; + state->needfi = ae_false; + state->xupdated = ae_false; + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->fi, 1+cntnlc, _state); + + /* + * Allocate memory. + */ + rallocv(n, &state->x0, _state); + rallocv(n, &state->s, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rsetallocv(n, -ae_maxrealnumber, &state->finitebndl, _state); + rsetallocv(n, ae_maxrealnumber, &state->finitebndu, _state); + + /* + * Prepare scaled problem + */ + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->finitebndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->finitebndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "SSGD: integrity check failed, box constraints are inconsistent", _state); + } + state->x0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + if( cntlc>0 ) + { + rsetallocv(n, 0.0, &state->tmpzero, _state); + rcopyallocm(cntlc, n, a, &state->densea, _state); + rcopyallocv(cntlc, al, &state->al, _state); + rcopyallocv(cntlc, au, &state->au, _state); + scaleshiftmixedlcinplace(s, &state->tmpzero, n, &state->dummysparsea, 0, &state->densea, cntlc, &state->al, &state->au, _state); + normalizedenselcinplace(&state->densea, cntlc, &state->al, &state->au, n, ae_true, &state->ascales, ae_true, _state); + ballocv(cntlc, &state->hasal, _state); + ballocv(cntlc, &state->hasau, _state); + for(i=0; i<=cntlc-1; i++) + { + state->hasal.ptr.p_bool[i] = ae_isfinite(state->al.ptr.p_double[i], _state); + state->hasau.ptr.p_bool[i] = ae_isfinite(state->au.ptr.p_double[i], _state); + } + } + if( cntnlc>0 ) + { + rcopyallocv(cntnlc, nl, &state->rawnl, _state); + rcopyallocv(cntnlc, nu, &state->rawnu, _state); + ballocv(cntnlc, &state->hasnl, _state); + ballocv(cntnlc, &state->hasnu, _state); + for(i=0; i<=cntnlc-1; i++) + { + state->hasnl.ptr.p_bool[i] = ae_isfinite(state->rawnl.ptr.p_double[i], _state); + state->hasnu.ptr.p_bool[i] = ae_isfinite(state->rawnu.ptr.p_double[i], _state); + } + } +} + + +/************************************************************************* +This function performs actual processing for SSGD algorithm. It expects +that the caller redirects its reverse communication requests NeedFiJ or +XUpdated to the external user, possibly wrapping them in a numerical +differentiation code. + + -- ALGLIB -- + Copyright 26.07.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool ssgditeration(ssgdstate* state, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_int_t outeridx; + ae_int_t iteridx; + ae_int_t i; + ae_int_t j; + double f0; + double fbest; + double fleft; + double fright; + double avgsqg; + double finalscale; + double t; + double v; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + cntlc = state->rstate.ia.ptr.p_int[1]; + cntnlc = state->rstate.ia.ptr.p_int[2]; + outeridx = state->rstate.ia.ptr.p_int[3]; + iteridx = state->rstate.ia.ptr.p_int[4]; + i = state->rstate.ia.ptr.p_int[5]; + j = state->rstate.ia.ptr.p_int[6]; + dotrace = state->rstate.ba.ptr.p_bool[0]; + dodetailedtrace = state->rstate.ba.ptr.p_bool[1]; + f0 = state->rstate.ra.ptr.p_double[0]; + fbest = state->rstate.ra.ptr.p_double[1]; + fleft = state->rstate.ra.ptr.p_double[2]; + fright = state->rstate.ra.ptr.p_double[3]; + avgsqg = state->rstate.ra.ptr.p_double[4]; + finalscale = state->rstate.ra.ptr.p_double[5]; + t = state->rstate.ra.ptr.p_double[6]; + v = state->rstate.ra.ptr.p_double[7]; + } + else + { + n = 359; + cntlc = -58; + cntnlc = -919; + outeridx = -909; + iteridx = 81; + i = 255; + j = 74; + dotrace = ae_false; + dodetailedtrace = ae_true; + f0 = 205.0; + fbest = -838.0; + fleft = 939.0; + fright = -526.0; + avgsqg = 763.0; + finalscale = -541.0; + t = -698.0; + v = -900.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + n = state->n; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + dotrace = ae_is_trace_enabled("SSGD"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("SSGD.DETAILED"); + + /* + * Prepare rcomm interface + */ + ssgd_clearrequestfields(state, _state); + + /* + * Initialize algorithm state. + */ + hqrndseed(3366544, 86335763, &state->rs, _state); + rallocv(n, &state->xoffs0, _state); + rallocv(n, &state->xoffs1, _state); + rallocv(n, &state->gcur, _state); + rcopyallocv(n, &state->x0, &state->xcur, _state); + rmergemaxv(n, &state->finitebndl, &state->xcur, _state); + rmergeminv(n, &state->finitebndu, &state->xcur, _state); + rsetallocv(n, 0.0, &state->dcur, _state); + state->repiterationscount = 0; + state->repnfev = 0; + avgsqg = ae_machineepsilon; + rsetallocv(1+cntnlc, ae_machineepsilon, &state->avgsqj, _state); + rsetallocv(1+cntnlc, 1.0, &state->fscales, _state); + finalscale = 1.0; + rcopyallocv(n, &state->xcur, &state->xbest, _state); + rcopyv(n, &state->xbest, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfi = ae_false; + rcopyallocv(1+cntnlc, &state->fi, &state->fibest, _state); + rallocv(n, &state->xleft, _state); + rallocv(n, &state->xright, _state); + rallocv(1+cntnlc, &state->fileft, _state); + rallocv(1+cntnlc, &state->firight, _state); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// Smoothed SGD SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("cntLC = %6d\n", + (int)(cntlc)); + ae_trace("cntNLC = %6d\n", + (int)(cntnlc)); + } + + /* + * Perform SGD iterations + */ + outeridx = 0; +lbl_4: + if( outeridx>state->outerits-1 ) + { + goto lbl_6; + } + + /* + * Choose initial point for an outer iteration as the best point found so far + */ + rcopyv(n, &state->xbest, &state->xcur, _state); + + /* + * Inner iteration: perform MaxIts SGD steps + */ + iteridx = 0; +lbl_7: + if( iteridx>state->maxits-1 ) + { + goto lbl_9; + } + + /* + * Determine iteration parameters + */ + t = (double)iteridx/(double)ae_maxint(state->maxits-1, 1, _state); + state->currate = state->rate0*ae_exp(ae_log(state->rate1/state->rate0, _state)*ae_maxreal((double)2*t-(double)1, (double)(0), _state), _state); + state->curblur = state->blur0*ae_exp(ae_log(state->blur1/state->blur0, _state)*(double)outeridx/(double)ae_maxint(state->outerits-1, 1, _state), _state); + state->zcursecantstep = ssgd_secanttoblurratio*state->curblur; + if( dotrace ) + { + ae_trace("\n=== INNER ITERATION %5d, OUTER ITERATION %5d ===================================================\n", + (int)(iteridx), + (int)(outeridx)); + ae_trace("learn.Rate = %0.3e\n", + (double)(state->currate)); + ae_trace("smooth.Rad = %0.3e\n", + (double)(state->curblur)); + ae_trace("secantStep = %0.3e\n", + (double)(state->zcursecantstep)); + } + + /* + * Compute target value at the current point, update best value so far + */ + rcopyv(n, &state->xcur, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfi = ae_false; + f0 = ssgd_penalizedtarget(state, &state->x, &state->fi, _state); + fbest = ssgd_penalizedtarget(state, &state->xbest, &state->fibest, _state); + if( dodetailedtrace ) + { + ae_trace("> printing current location and status:\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->xcur, n, &state->s, ae_true, &state->s, ae_false, _state); + ae_trace("\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->xcur, 0, n, _state); + ae_trace("\n"); + } + if( ae_fp_less(f0,fbest) ) + { + rcopyv(n, &state->xcur, &state->xbest, _state); + rcopyallocv(1+cntnlc, &state->fi, &state->fibest, _state); + } + if( dotrace ) + { + ae_trace("\n--- current target ---------------------------------------------------------------------------------\n"); + ae_trace("F = %0.12e\n", + (double)(state->fi.ptr.p_double[0])); + ae_trace("F-penalized = %0.12e\n", + (double)(f0)); + ae_trace("lin.violation = %0.3e\n", + (double)(ssgd_lcviolation(state, &state->xcur, _state))); + ae_trace("\n--- best point so far ------------------------------------------------------------------------------\n"); + ae_trace("F = %0.12e\n", + (double)(state->fibest.ptr.p_double[0])); + ae_trace("F-penalized = %0.12e\n", + (double)(fbest)); + ae_trace("lin.violation = %0.3e\n", + (double)(ssgd_lcviolation(state, &state->xbest, _state))); + } + + /* + * Compute gradients (target, linear penalties, nonlinear penalties) using secant update + */ + for(i=0; i<=n-1; i++) + { + state->xoffs0.ptr.p_double[i] = hqrnduniformr(&state->rs, _state)-0.5; + state->xoffs1.ptr.p_double[i] = state->xoffs0.ptr.p_double[i]; + } + rsetallocv(1+cntnlc, 0.0, &state->sqj, _state); + i = 0; +lbl_10: + if( i>n-1 ) + { + goto lbl_12; + } + + /* + * Compute f(x-SecantStep) and f(x+SecantStep) + */ + rcopyv(n, &state->xcur, &state->x, _state); + raddv(n, state->curblur, &state->xoffs0, &state->x, _state); + state->x.ptr.p_double[i] = state->x.ptr.p_double[i]-state->zcursecantstep; + rmergemaxv(n, &state->finitebndl, &state->x, _state); + rmergeminv(n, &state->finitebndu, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfi = ae_false; + rcopyv(n, &state->x, &state->xleft, _state); + rcopyv(1+cntnlc, &state->fi, &state->fileft, _state); + rcopyv(n, &state->xcur, &state->x, _state); + raddv(n, state->curblur, &state->xoffs1, &state->x, _state); + state->x.ptr.p_double[i] = state->x.ptr.p_double[i]+state->zcursecantstep; + rmergemaxv(n, &state->finitebndl, &state->x, _state); + rmergeminv(n, &state->finitebndu, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfi = ae_false; + rcopyv(n, &state->x, &state->xright, _state); + rcopyv(1+cntnlc, &state->fi, &state->firight, _state); + + /* + * Compute squared norms of target/constraint gradients + */ + for(j=0; j<=cntnlc; j++) + { + v = (state->firight.ptr.p_double[j]-state->fileft.ptr.p_double[j])/((double)2*state->zcursecantstep); + state->sqj.ptr.p_double[j] = state->sqj.ptr.p_double[j]+v*v; + } + + /* + * Compute gradient using current target/constraint scales + */ + state->gcur.ptr.p_double[i] = (state->firight.ptr.p_double[0]-state->fileft.ptr.p_double[0])/((double)2*state->fscales.ptr.p_double[0]*state->zcursecantstep); + for(j=0; j<=cntnlc-1; j++) + { + state->gcur.ptr.p_double[i] = state->gcur.ptr.p_double[i]+(ssgd_scalednlcpenalty(state, &state->firight, j, state->fscales.ptr.p_double[1+j], _state)-ssgd_scalednlcpenalty(state, &state->fileft, j, state->fscales.ptr.p_double[1+j], _state))/((double)2*state->zcursecantstep); + } + state->gcur.ptr.p_double[i] = state->gcur.ptr.p_double[i]+(ssgd_lcpenalty(state, &state->xright, _state)-ssgd_lcpenalty(state, &state->xleft, _state))/((double)2*state->zcursecantstep); + i = i+1; + goto lbl_10; +lbl_12: + + /* + * Recompute scales using data collected during gradient calculation + */ + for(i=0; i<=cntnlc; i++) + { + state->avgsqj.ptr.p_double[i] = state->avgsqj.ptr.p_double[i]*((double)1-ssgd_sqjmomentum)+ssgd_sqjmomentum*ae_sqrt(state->sqj.ptr.p_double[j], _state); + state->fscales.ptr.p_double[i] = ae_maxreal(state->avgsqj.ptr.p_double[i], 1.0, _state); + } + if( dotrace ) + { + ae_trace("scale(F) = %0.3e\n", + (double)(state->fscales.ptr.p_double[0])); + } + v = ae_sqrt(rdotv2(n, &state->gcur, _state), _state); + avgsqg = avgsqg*((double)1-ssgd_sqjmomentum)+ssgd_sqjmomentum*v; + finalscale = rmax3(avgsqg, v, 1.0, _state); + rmulv(n, (double)1/finalscale, &state->gcur, _state); + + /* + * Perform step + */ + rmulv(n, state->momentum, &state->dcur, _state); + raddv(n, (double)1-state->momentum, &state->gcur, &state->dcur, _state); + raddv(n, -state->currate, &state->dcur, &state->xcur, _state); + rmergemaxv(n, &state->finitebndl, &state->xcur, _state); + rmergeminv(n, &state->finitebndu, &state->xcur, _state); + state->repiterationscount = state->repiterationscount+1; + iteridx = iteridx+1; + goto lbl_7; +lbl_9: + outeridx = outeridx+1; + goto lbl_4; +lbl_6: + if( dotrace ) + { + ae_trace("> reached iterations limit, stopping\n"); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = cntlc; + state->rstate.ia.ptr.p_int[2] = cntnlc; + state->rstate.ia.ptr.p_int[3] = outeridx; + state->rstate.ia.ptr.p_int[4] = iteridx; + state->rstate.ia.ptr.p_int[5] = i; + state->rstate.ia.ptr.p_int[6] = j; + state->rstate.ba.ptr.p_bool[0] = dotrace; + state->rstate.ba.ptr.p_bool[1] = dodetailedtrace; + state->rstate.ra.ptr.p_double[0] = f0; + state->rstate.ra.ptr.p_double[1] = fbest; + state->rstate.ra.ptr.p_double[2] = fleft; + state->rstate.ra.ptr.p_double[3] = fright; + state->rstate.ra.ptr.p_double[4] = avgsqg; + state->rstate.ra.ptr.p_double[5] = finalscale; + state->rstate.ra.ptr.p_double[6] = t; + state->rstate.ra.ptr.p_double[7] = v; + return result; +} + + +/************************************************************************* +Clears request fileds (to be sure that we didn't forget to clear something) +*************************************************************************/ +static void ssgd_clearrequestfields(ssgdstate* state, ae_state *_state) +{ + + + state->needfi = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Compute penalized target +*************************************************************************/ +static double ssgd_penalizedtarget(ssgdstate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = fi->ptr.p_double[0]/state->fscales.ptr.p_double[0]; + for(i=0; i<=state->cntnlc-1; i++) + { + result = result+ssgd_scalednlcpenalty(state, fi, i, state->fscales.ptr.p_double[1+i], _state); + } + result = result+ssgd_lcpenalty(state, x, _state); + return result; +} + + +/************************************************************************* +Compute penalty for linear constraints +*************************************************************************/ +static double ssgd_lcpenalty(ssgdstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = 0.0; + for(i=0; i<=state->cntlc-1; i++) + { + v = rdotvr(state->n, x, &state->densea, i, _state); + if( state->hasal.ptr.p_bool[i]&&val.ptr.p_double[i] ) + { + result = result+(double)0*(state->al.ptr.p_double[i]-v)+state->rho*(state->al.ptr.p_double[i]-v)*(state->al.ptr.p_double[i]-v); + } + if( state->hasau.ptr.p_bool[i]&&v>state->au.ptr.p_double[i] ) + { + result = result+(double)0*(v-state->au.ptr.p_double[i])+state->rho*(v-state->au.ptr.p_double[i])*(v-state->au.ptr.p_double[i]); + } + } + return result; +} + + +/************************************************************************* +Compute penalty for a single nonlinear constraint +*************************************************************************/ +static double ssgd_scalednlcpenalty(ssgdstate* state, + /* Real */ const ae_vector* _fi, + ae_int_t idx, + double fscale, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector fi; + double v; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&fi, 0, sizeof(fi)); + ae_vector_init_copy(&fi, _fi, _state, ae_true); + + result = 0.0; + if( state->hasnl.ptr.p_bool[idx]&&fi.ptr.p_double[1+idx]rawnl.ptr.p_double[idx] ) + { + v = (state->rawnl.ptr.p_double[idx]-fi.ptr.p_double[1+idx])/fscale; + result = result+(double)0*v+state->rho*v*v; + } + if( state->hasnu.ptr.p_bool[idx]&&fi.ptr.p_double[1+idx]>state->rawnu.ptr.p_double[idx] ) + { + v = (fi.ptr.p_double[1+idx]-state->rawnu.ptr.p_double[idx])/fscale; + result = result+(double)0*v+state->rho*v*v; + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Compute violation of linear constraints +*************************************************************************/ +static double ssgd_lcviolation(ssgdstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = 0.0; + for(i=0; i<=state->cntlc-1; i++) + { + v = rdotvr(state->n, x, &state->densea, i, _state); + if( state->hasal.ptr.p_bool[i] ) + { + result = ae_maxreal(result, state->al.ptr.p_double[i]-v, _state); + } + if( state->hasau.ptr.p_bool[i] ) + { + result = ae_maxreal(result, v-state->au.ptr.p_double[i], _state); + } + } + return result; +} + + +void _ssgdstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + ssgdstate *p = (ssgdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rawnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasnl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasnu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->ascales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->avgsqj, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->rs, _state, make_automatic); + ae_vector_init(&p->xbest, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fibest, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gcur, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dcur, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->sqj, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xleft, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xright, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fileft, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->firight, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xoffs0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xoffs1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpzero, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->dummysparsea, _state, make_automatic); +} + + +void _ssgdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + ssgdstate *dst = (ssgdstate*)_dst; + const ssgdstate *src = (const ssgdstate*)_src; + dst->n = src->n; + dst->cntlc = src->cntlc; + dst->cntnlc = src->cntnlc; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); + ae_vector_init_copy(&dst->rawnl, &src->rawnl, _state, make_automatic); + ae_vector_init_copy(&dst->rawnu, &src->rawnu, _state, make_automatic); + ae_vector_init_copy(&dst->hasnl, &src->hasnl, _state, make_automatic); + ae_vector_init_copy(&dst->hasnu, &src->hasnu, _state, make_automatic); + ae_vector_init_copy(&dst->ascales, &src->ascales, _state, make_automatic); + dst->maxits = src->maxits; + dst->rate0 = src->rate0; + dst->rate1 = src->rate1; + dst->momentum = src->momentum; + dst->blur0 = src->blur0; + dst->blur1 = src->blur1; + dst->outerits = src->outerits; + dst->rho = src->rho; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + dst->needfi = src->needfi; + dst->xupdated = src->xupdated; + ae_vector_init_copy(&dst->avgsqj, &src->avgsqj, _state, make_automatic); + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + ae_vector_init_copy(&dst->xbest, &src->xbest, _state, make_automatic); + ae_vector_init_copy(&dst->fibest, &src->fibest, _state, make_automatic); + ae_vector_init_copy(&dst->xcur, &src->xcur, _state, make_automatic); + ae_vector_init_copy(&dst->gcur, &src->gcur, _state, make_automatic); + ae_vector_init_copy(&dst->dcur, &src->dcur, _state, make_automatic); + dst->currate = src->currate; + dst->curblur = src->curblur; + dst->zcursecantstep = src->zcursecantstep; + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->sqj, &src->sqj, _state, make_automatic); + ae_vector_init_copy(&dst->xleft, &src->xleft, _state, make_automatic); + ae_vector_init_copy(&dst->xright, &src->xright, _state, make_automatic); + ae_vector_init_copy(&dst->fileft, &src->fileft, _state, make_automatic); + ae_vector_init_copy(&dst->firight, &src->firight, _state, make_automatic); + ae_vector_init_copy(&dst->xoffs0, &src->xoffs0, _state, make_automatic); + ae_vector_init_copy(&dst->xoffs1, &src->xoffs1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpzero, &src->tmpzero, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysparsea, &src->dummysparsea, _state, make_automatic); +} + + +void _ssgdstate_clear(void* _p) +{ + ssgdstate *p = (ssgdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->s); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + ae_matrix_clear(&p->densea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); + ae_vector_clear(&p->rawnl); + ae_vector_clear(&p->rawnu); + ae_vector_clear(&p->hasnl); + ae_vector_clear(&p->hasnu); + ae_vector_clear(&p->ascales); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_vector_clear(&p->avgsqj); + ae_vector_clear(&p->fscales); + _hqrndstate_clear(&p->rs); + ae_vector_clear(&p->xbest); + ae_vector_clear(&p->fibest); + ae_vector_clear(&p->xcur); + ae_vector_clear(&p->gcur); + ae_vector_clear(&p->dcur); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->sqj); + ae_vector_clear(&p->xleft); + ae_vector_clear(&p->xright); + ae_vector_clear(&p->fileft); + ae_vector_clear(&p->firight); + ae_vector_clear(&p->xoffs0); + ae_vector_clear(&p->xoffs1); + ae_vector_clear(&p->tmpzero); + _sparsematrix_clear(&p->dummysparsea); +} + + +void _ssgdstate_destroy(void* _p) +{ + ssgdstate *p = (ssgdstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + ae_matrix_destroy(&p->densea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); + ae_vector_destroy(&p->rawnl); + ae_vector_destroy(&p->rawnu); + ae_vector_destroy(&p->hasnl); + ae_vector_destroy(&p->hasnu); + ae_vector_destroy(&p->ascales); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_vector_destroy(&p->avgsqj); + ae_vector_destroy(&p->fscales); + _hqrndstate_destroy(&p->rs); + ae_vector_destroy(&p->xbest); + ae_vector_destroy(&p->fibest); + ae_vector_destroy(&p->xcur); + ae_vector_destroy(&p->gcur); + ae_vector_destroy(&p->dcur); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->sqj); + ae_vector_destroy(&p->xleft); + ae_vector_destroy(&p->xright); + ae_vector_destroy(&p->fileft); + ae_vector_destroy(&p->firight); + ae_vector_destroy(&p->xoffs0); + ae_vector_destroy(&p->xoffs1); + ae_vector_destroy(&p->tmpzero); + _sparsematrix_destroy(&p->dummysparsea); +} + + +#endif +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) + + +void gdemoinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t m, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + ae_int_t popsize, + ae_int_t epochscnt, + ae_int_t seed, + gdemostate* state, + ae_state *_state) +{ + ae_int_t i; + + + + /* + * Integrity checks + */ + ae_assert(m==1, "GDEMO: M<>1", _state); + ae_assert(popsize>=0, "GDEMO: PopSize<=0", _state); + ae_assert(epochscnt>0, "GDEMO: EpochsCnt<=0", _state); + + /* + * Initialization + */ + popsize = ae_maxint(coalescei(popsize, 10*n, _state), 10, _state); + state->n = n; + state->m = m; + state->cntlc = cntlc; + state->cntnlc = cntnlc; + state->popsize = popsize; + state->epochscnt = epochscnt; + state->constrmode = 0; + state->rho1 = diffevo_defaultpenalty; + state->rho2 = diffevo_defaultpenalty; + state->eps = 0.0; + state->nsample = (double)(1); + state->fixedparams = ae_false; + state->hasx0 = ae_false; + state->stoponsmallf = ae_false; + state->condfxepsf = 0.0; + state->condfxepsx = 0.0; + if( seed<=0 ) + { + seed = ae_randominteger(30000, _state); + } + hqrndseed(seed, seed+1172, &state->rs, _state); + rsetallocm(m, n, 0.0, &state->xbest, _state); + rsetallocv(m, _state->v_nan, &state->fitbest, _state); + rsetallocv(m, _state->v_nan, &state->rawfbest, _state); + gdemosetprofile(state, 0, _state); + + /* + * Prepare RCOMM state + */ + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ba, 2+1, _state); + ae_vector_set_length(&state->rstate.ra, 3+1, _state); + state->rstate.stage = -1; + + /* + * Prepare scaled problem + */ + rallocv(n, &state->s, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rsetallocv(n, -ae_maxrealnumber, &state->finitebndl, _state); + rsetallocv(n, ae_maxrealnumber, &state->finitebndu, _state); + for(i=0; i<=n-1; i++) + { + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + if( state->hasbndl.ptr.p_bool[i] ) + { + state->finitebndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->finitebndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "GDEMO: integrity check failed, box constraints are inconsistent", _state); + } + state->s.ptr.p_double[i] = s->ptr.p_double[i]; + } + if( cntlc>0 ) + { + rsetallocv(n, 0.0, &state->tmpzero, _state); + rcopyallocm(cntlc, n, a, &state->densea, _state); + rcopyallocv(cntlc, al, &state->al, _state); + rcopyallocv(cntlc, au, &state->au, _state); + scaleshiftmixedlcinplace(s, &state->tmpzero, n, &state->dummysparsea, 0, &state->densea, cntlc, &state->al, &state->au, _state); + normalizedenselcinplace(&state->densea, cntlc, &state->al, &state->au, n, ae_true, &state->ascales, ae_true, _state); + ballocv(cntlc, &state->hasal, _state); + ballocv(cntlc, &state->hasau, _state); + for(i=0; i<=cntlc-1; i++) + { + state->hasal.ptr.p_bool[i] = ae_isfinite(state->al.ptr.p_double[i], _state); + state->hasau.ptr.p_bool[i] = ae_isfinite(state->au.ptr.p_double[i], _state); + } + } + if( cntnlc>0 ) + { + rcopyallocv(cntnlc, nl, &state->rawnl, _state); + rcopyallocv(cntnlc, nu, &state->rawnu, _state); + ballocv(cntnlc, &state->hasnl, _state); + ballocv(cntnlc, &state->hasnu, _state); + for(i=0; i<=cntnlc-1; i++) + { + state->hasnl.ptr.p_bool[i] = ae_isfinite(state->rawnl.ptr.p_double[i], _state); + state->hasnu.ptr.p_bool[i] = ae_isfinite(state->rawnu.ptr.p_double[i], _state); + } + } +} + + +/************************************************************************* +Sets performance profile: +* 0 for ROBUST +* 1 for QUICK + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +void gdemosetprofile(gdemostate* state, + ae_int_t profile, + ae_state *_state) +{ + + + ae_assert(profile==0||profile==1, "GDEMOSetProfile: unexpected profile", _state); + state->profile = profile; +} + + +/************************************************************************* +Set fixed algorithm params (the default is to use adaptive algorithm) + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +void gdemosetfixedparams(gdemostate* state, + ae_int_t strategy, + double crossoverprob, + double differentialweight, + ae_state *_state) +{ + + + state->fixedparams = ae_true; + state->fixedstrategy = strategy; + state->fixedcrossoverprob = crossoverprob; + state->fixeddifferentialweight = differentialweight; +} + + +/************************************************************************* +Sets small F, the solver stops when the best value decreases below this level + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +void gdemosetsmallf(gdemostate* state, double f, ae_state *_state) +{ + + + state->stoponsmallf = ae_true; + state->smallf = f; +} + + +/************************************************************************* +This function sets a combined stopping condition: stopping when two +criteria are met simultaneously: +* function values has converged within epsF +* variable values has converged within epsX + +Ignored for multi-objective setting. + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void gdemosetcondfx(gdemostate* state, + double epsf, + double epsx, + ae_state *_state) +{ + + + state->condfxepsf = epsf; + state->condfxepsx = epsx; +} + + +/************************************************************************* +Sets constraint handling mode to L1/L2 penalty + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +void gdemosetmodepenalty(gdemostate* state, + double rhol1, + double rhol2, + ae_state *_state) +{ + + + state->constrmode = 0; + state->rho1 = rhol1; + state->rho2 = rhol2; +} + + +/************************************************************************* +Sets initial point + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +void gdemosetx0(gdemostate* state, + /* Real */ const ae_vector* x0, + ae_state *_state) +{ + + + state->hasx0 = ae_true; + rcopyallocv(state->n, x0, &state->x0, _state); +} + + +/************************************************************************* +This function performs actual processing for GDEMO algorithm. + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool gdemoiteration(gdemostate* state, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t k1; + double v; + double vv; + double vleft; + double vright; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_int_t popsize; + ae_int_t residualsize; + ae_int_t iteridx; + ae_bool bad; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + cntlc = state->rstate.ia.ptr.p_int[2]; + cntnlc = state->rstate.ia.ptr.p_int[3]; + i = state->rstate.ia.ptr.p_int[4]; + j = state->rstate.ia.ptr.p_int[5]; + k = state->rstate.ia.ptr.p_int[6]; + k1 = state->rstate.ia.ptr.p_int[7]; + popsize = state->rstate.ia.ptr.p_int[8]; + residualsize = state->rstate.ia.ptr.p_int[9]; + iteridx = state->rstate.ia.ptr.p_int[10]; + dotrace = state->rstate.ba.ptr.p_bool[0]; + dodetailedtrace = state->rstate.ba.ptr.p_bool[1]; + bad = state->rstate.ba.ptr.p_bool[2]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + vleft = state->rstate.ra.ptr.p_double[2]; + vright = state->rstate.ra.ptr.p_double[3]; + } + else + { + n = 359; + m = -58; + cntlc = -919; + cntnlc = -909; + i = 81; + j = 255; + k = 74; + k1 = -788; + popsize = 809; + residualsize = 205; + iteridx = -838; + dotrace = ae_true; + dodetailedtrace = ae_false; + bad = ae_true; + v = -541.0; + vv = -698.0; + vleft = -900.0; + vright = -318.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + popsize = state->popsize; + dotrace = ae_is_trace_enabled("GDEMO"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("GDEMO.DETAILED"); + ae_assert(m==1, "GDEMO: integrity check 0732 failed", _state); + + /* + * Init + */ + state->repiterationscount = 0; + state->repterminationtype = 5; + state->replcerr = 0.0; + state->replcidx = -1; + state->repnlcerr = 0.0; + state->repnlcidx = -1; + rallocv(n, &state->reportx, _state); + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// GDEMO SOLVER HAS STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(n)); + ae_trace("M = %6d\n", + (int)(m)); + ae_trace("cntLC = %6d\n", + (int)(cntlc)); + ae_trace("cntNLC = %6d\n", + (int)(cntnlc)); + ae_trace("parameters = "); + if( state->fixedparams ) + { + ae_trace("fixed\n"); + } + else + { + ae_trace("adaptive\n"); + } + } + + /* + * Initial state of memory, pools, etc + */ + state->mucr = 0.5; + state->muf = 0.5; + + /* + * Generate initial population, perform several iterations dropping invalid candidates + * (ones with infinite target/constraint values) until the entire population is generated: + * * generate initial population using INIT heuristic, compute empirical bounds (per-variable + * max and min of population elements) + * * repeatedly query targets, keep good ones, drop bad ones, tighten empirical bounds + * approaching them closer to points that resulted in good values + */ + state->population.cnt = popsize; + rallocm(popsize, n, &state->population.x, _state); + rallocm(popsize, m+cntnlc, &state->population.rawreplies, _state); + rallocm(popsize, m, &state->population.fitness, _state); + rsetallocm(popsize, diffevo_paramscnt, 0.0, &state->population.deparams, _state); + rallocv(n, &state->empiricalbndl, _state); + rallocv(n, &state->empiricalbndu, _state); + for(i=0; i<=popsize-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( state->hasx0&&i==0 ) + { + + /* + * Add user-provided initial point to the population + */ + state->population.x.ptr.pp_double[i][j] = boundval(state->x0.ptr.p_double[j], state->finitebndl.ptr.p_double[j], state->finitebndu.ptr.p_double[j], _state); + } + else + { + + /* + * Generate population individual using hints from box constraints + */ + if( state->hasbndl.ptr.p_bool[j]&&state->hasbndu.ptr.p_bool[j] ) + { + state->population.x.ptr.pp_double[i][j] = state->finitebndl.ptr.p_double[j]+(state->finitebndu.ptr.p_double[j]-state->finitebndl.ptr.p_double[j])*hqrnduniformr(&state->rs, _state); + continue; + } + if( state->hasbndl.ptr.p_bool[j]&&!state->hasbndu.ptr.p_bool[j] ) + { + state->population.x.ptr.pp_double[i][j] = state->finitebndl.ptr.p_double[j]+ae_pow((double)(2), hqrndnormal(&state->rs, _state), _state); + continue; + } + if( state->hasbndu.ptr.p_bool[j]&&!state->hasbndl.ptr.p_bool[j] ) + { + state->population.x.ptr.pp_double[i][j] = state->finitebndu.ptr.p_double[j]-ae_pow((double)(2), hqrndnormal(&state->rs, _state), _state); + continue; + } + state->population.x.ptr.pp_double[i][j] = hqrndnormal(&state->rs, _state); + } + } + if( i==0 ) + { + rcopyrv(n, &state->population.x, i, &state->empiricalbndl, _state); + rcopyrv(n, &state->population.x, i, &state->empiricalbndu, _state); + } + else + { + rmergeminrv(n, &state->population.x, i, &state->empiricalbndl, _state); + rmergemaxrv(n, &state->population.x, i, &state->empiricalbndu, _state); + } + } + rsetallocv(n, ae_maxrealnumber, &state->goodbndl, _state); + rsetallocv(n, -ae_maxrealnumber, &state->goodbndu, _state); + residualsize = popsize; + iteridx = 0; +lbl_4: + if( iteridx>ae_maxint(diffevo_minpowerupits, ae_round(0.25*(double)state->epochscnt, _state), _state)-1 ) + { + goto lbl_6; + } + + /* + * query target values + */ + state->requesttype = 4; + state->querysize = residualsize; + rallocv(n*residualsize, &state->querydata, _state); + for(i=0; i<=residualsize-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->querydata.ptr.p_double[i*n+j] = state->population.x.ptr.pp_double[i][j]; + } + } + rallocv(residualsize*(m+cntnlc), &state->replyfi, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + for(i=0; i<=residualsize-1; i++) + { + for(j=0; j<=m+cntnlc-1; j++) + { + state->population.rawreplies.ptr.pp_double[i][j] = state->replyfi.ptr.p_double[i*(m+cntnlc)+j]; + } + } + + /* + * Move good candidates (ones with finite targets/constraints) to the end, decrease residual size + */ + i = residualsize-1; + while(i>=0) + { + bad = ae_false; + for(j=0; j<=m+cntnlc-1; j++) + { + bad = bad||!ae_isfinite(state->population.rawreplies.ptr.pp_double[i][j], _state); + } + if( !bad ) + { + + /* + * Move candidate to the end of the current subpopulation, update box containing good values, decrease residual size + */ + if( i!=residualsize-1 ) + { + rcopyrr(n, &state->population.x, i, &state->population.x, residualsize-1, _state); + rcopyrr(m+cntnlc, &state->population.rawreplies, i, &state->population.rawreplies, residualsize-1, _state); + } + rmergeminrv(n, &state->population.x, residualsize-1, &state->goodbndl, _state); + rmergemaxrv(n, &state->population.x, residualsize-1, &state->goodbndu, _state); + residualsize = residualsize-1; + } + i = i-1; + } + if( residualsize==0 ) + { + goto lbl_6; + } + + /* + * Tighten empirical bounds used to generate new candidates. + */ + if( residualsize<=popsize-diffevo_minpopsizefortightening ) + { + ae_assert(diffevo_minpopsizefortightening>=2, "GDEMO: integrity check 0618 failed", _state); + for(j=0; j<=n-1; j++) + { + state->empiricalbndl.ptr.p_double[j] = diffevo_tighteningmu*state->empiricalbndl.ptr.p_double[j]+((double)1-diffevo_tighteningmu)*state->goodbndl.ptr.p_double[j]; + state->empiricalbndu.ptr.p_double[j] = diffevo_tighteningmu*state->empiricalbndu.ptr.p_double[j]+((double)1-diffevo_tighteningmu)*state->goodbndu.ptr.p_double[j]; + } + } + + /* + * Generate new candidates in the empirical box + */ + for(i=0; i<=residualsize-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->population.x.ptr.pp_double[i][j] = state->empiricalbndl.ptr.p_double[j]+(state->empiricalbndu.ptr.p_double[j]-state->empiricalbndl.ptr.p_double[j])*hqrnduniformr(&state->rs, _state); + } + } + iteridx = iteridx+1; + goto lbl_4; +lbl_6: + if( residualsize>0 ) + { + + /* + * We failed to generate complete population, return with error + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + diffevo_computefitness(state, &state->population, ae_false, &state->population, _state); + diffevo_updatebest(state, _state); + ae_assert(m==1, "GDEMO: integrity check 566226 failed", _state); + state->requesttype = -1; + rallocv(n, &state->reportx, _state); + rcopyrv(n, &state->xbest, 0, &state->reportx, _state); + state->reportf = state->rawfbest.ptr.p_double[0]; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + + /* + * Run iterations + */ + if( dotrace ) + { + ae_trace("> ALGLIB GDEMO solver started, %0d variables, %0d linear constraints, %0d general constraints\n", + (int)(n), + (int)(cntlc), + (int)(cntnlc)); + ae_trace(" ITS MERIT FUNC OBJECTIVE muCR muF\n"); + } + iteridx = 0; +lbl_7: + if( iteridx>state->epochscnt-1 ) + { + goto lbl_9; + } + if( dotrace ) + { + i = 0; + if( state->repiterationscount<=10 ) + { + i = 1; + } + if( state->repiterationscount<=100&&state->repiterationscount%5==0 ) + { + i = 1; + } + if( state->repiterationscount%50==0 ) + { + i = 1; + } + if( i>0 ) + { + ae_trace("%6d %23.15e %23.15e %16.14f %16.14f\n", + (int)(state->repiterationscount), + (double)(state->fitbest.ptr.p_double[0]), + (double)(state->rawfbest.ptr.p_double[0]), + (double)(state->mucr), + (double)(state->muf)); + } + } + + /* + * Generate candidates + */ + diffevo_generatetrialpoints(state, &state->population, &state->offspring, _state); + + /* + * RComm request and fitness computation + */ + state->requesttype = 4; + state->querysize = state->offspring.cnt; + rallocv(n*state->offspring.cnt, &state->querydata, _state); + for(i=0; i<=state->offspring.cnt-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->querydata.ptr.p_double[i*n+j] = state->offspring.x.ptr.pp_double[i][j]; + } + } + rallocv(state->offspring.cnt*(m+cntnlc), &state->replyfi, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + for(i=0; i<=state->offspring.cnt-1; i++) + { + for(j=0; j<=m+cntnlc-1; j++) + { + state->offspring.rawreplies.ptr.pp_double[i][j] = state->replyfi.ptr.p_double[i*(m+cntnlc)+j]; + } + } + diffevo_computefitness(state, &state->population, ae_true, &state->offspring, _state); + + /* + * Update population with candidates + */ + diffevo_updatepopulation(state, &state->offspring, _state); + + /* + * Update best value so far and other counters, check stopping criteria + */ + diffevo_updatebest(state, _state); + ae_assert(m==1, "GDEMO: integrity check 566226 failed", _state); + state->requesttype = -1; + rallocv(n, &state->reportx, _state); + rcopyrv(n, &state->xbest, 0, &state->reportx, _state); + state->reportf = state->rawfbest.ptr.p_double[0]; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->repiterationscount = state->repiterationscount+1; + if( (state->stoponsmallf&&m==1)&&ae_fp_less_eq(state->rawfbest.ptr.p_double[0],state->smallf) ) + { + state->repterminationtype = 6; + goto lbl_9; + } + if( (ae_fp_greater(state->condfxepsf,(double)(0))||ae_fp_greater(state->condfxepsx,(double)(0)))&&m==1 ) + { + ae_assert(!ae_isnan(state->fitbest.ptr.p_double[0], _state), "GDEMO: integrity check 2618 failed", _state); + + /* + * Count agents within EpsF near the optimal one + */ + k = 0; + k1 = 0; + v = state->fitbest.ptr.p_double[0]+state->condfxepsf*rmaxabs2(state->fitbest.ptr.p_double[0], 1.0, _state); + for(i=0; i<=popsize-1; i++) + { + + /* + * Try to filter out individuals based on: + * * target value (if epsF>0); tried first because it is the cheapest condition + * * distance towards the best one + */ + if( state->condfxepsf>0.0&&state->population.fitness.ptr.pp_double[i][0]>v ) + { + continue; + } + k = k+1; + if( state->condfxepsx>0.0 ) + { + vv = 0.0; + for(j=0; j<=n-1; j++) + { + vv = vv+(state->population.x.ptr.pp_double[i][j]-state->xbest.ptr.pp_double[0][j])*(state->population.x.ptr.pp_double[i][j]-state->xbest.ptr.pp_double[0][j]); + } + if( vv/(double)n>state->condfxepsx*state->condfxepsx ) + { + continue; + } + } + k1 = k1+1; + } + if( ae_fp_greater_eq((double)(k),ae_minreal((double)(2*n+1), (double)(popsize), _state))&&ae_fp_greater_eq((double)(k1),ae_minreal((double)(2*n+1), (double)(popsize), _state)) ) + { + state->repterminationtype = 1; + goto lbl_9; + } + } + iteridx = iteridx+1; + goto lbl_7; +lbl_9: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = cntlc; + state->rstate.ia.ptr.p_int[3] = cntnlc; + state->rstate.ia.ptr.p_int[4] = i; + state->rstate.ia.ptr.p_int[5] = j; + state->rstate.ia.ptr.p_int[6] = k; + state->rstate.ia.ptr.p_int[7] = k1; + state->rstate.ia.ptr.p_int[8] = popsize; + state->rstate.ia.ptr.p_int[9] = residualsize; + state->rstate.ia.ptr.p_int[10] = iteridx; + state->rstate.ba.ptr.p_bool[0] = dotrace; + state->rstate.ba.ptr.p_bool[1] = dodetailedtrace; + state->rstate.ba.ptr.p_bool[2] = bad; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + state->rstate.ra.ptr.p_double[2] = vleft; + state->rstate.ra.ptr.p_double[3] = vright; + return result; +} + + +/************************************************************************* +Compute fitness from raw replies + +INPUT PARAMETERS: + State - solver + Population2RawReplies - present population, used by fitness computation + methods which analyze distribution of constraint + violations in the current population + PopSize - population size, or zero, if this + function is called at the initialization + phase when we compute fitness for the initial + population + RawReplies - raw replies to process + BatchSize - size of the set being processed + Fitness - preallocated output array + + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static void diffevo_computefitness(const gdemostate* state, + const gdemopopulation* refpopulation, + ae_bool hasreference, + gdemopopulation* trial, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + double p; + double v; + double vv; + ae_bool bad; + + + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + ae_assert(trial->fitness.rows>=trial->cnt&&trial->fitness.cols>=m, "GDEMO: integrity check 5831 failed", _state); + ae_assert(ae_fp_eq(state->nsample,(double)(1)), "GDEMO: integrity check 5632 failed", _state); + + /* + * Quick exit + */ + if( cntlc+cntnlc==0 ) + { + for(i=0; i<=trial->cnt-1; i++) + { + bad = ae_false; + for(j=0; j<=m-1; j++) + { + v = trial->rawreplies.ptr.pp_double[i][j]; + trial->fitness.ptr.pp_double[i][j] = v; + bad = bad||!ae_isfinite(v, _state); + } + if( bad ) + { + for(j=0; j<=m-1; j++) + { + trial->fitness.ptr.pp_double[i][j] = ae_maxrealnumber; + } + } + } + return; + } + + /* + * Default constraint handling strategy: L1 penalty + */ + if( state->constrmode==0 ) + { + for(i=0; i<=trial->cnt-1; i++) + { + + /* + * Handle bad targets/constraints + */ + bad = ae_false; + for(j=0; j<=m+cntnlc-1; j++) + { + bad = bad||!ae_isfinite(trial->rawreplies.ptr.pp_double[i][j], _state); + } + if( bad ) + { + for(j=0; j<=m-1; j++) + { + trial->fitness.ptr.pp_double[i][j] = ae_maxrealnumber; + } + continue; + } + + /* + * No infinities, normal processing + */ + p = (double)(0); + for(j=0; j<=cntlc-1; j++) + { + v = rdotrr(n, &trial->x, i, &state->densea, j, _state); + if( state->hasal.ptr.p_bool[j] ) + { + vv = ae_maxreal(state->al.ptr.p_double[j]-v, 0.0, _state); + p = p+state->rho1*vv+state->rho2*vv*vv; + } + if( state->hasau.ptr.p_bool[j] ) + { + vv = ae_maxreal(v-state->au.ptr.p_double[j], 0.0, _state); + p = p+state->rho1*vv+state->rho2*vv*vv; + } + } + for(j=0; j<=cntnlc-1; j++) + { + v = trial->rawreplies.ptr.pp_double[i][m+j]; + if( state->hasnl.ptr.p_bool[j] ) + { + vv = ae_maxreal(state->rawnl.ptr.p_double[j]-v, 0.0, _state); + p = p+state->rho1*vv+state->rho2*vv*vv; + } + if( state->hasnu.ptr.p_bool[j] ) + { + vv = ae_maxreal(v-state->rawnu.ptr.p_double[j], 0.0, _state); + p = p+state->rho1*vv+state->rho2*vv*vv; + } + } + for(j=0; j<=m-1; j++) + { + trial->fitness.ptr.pp_double[i][j] = trial->rawreplies.ptr.pp_double[i][j]+p; + } + } + return; + } + + /* + * Unknown constrmode + */ + ae_assert(ae_false, "GDEMO: integrity check 2202 failed", _state); +} + + +/************************************************************************* +Updates best value so far. For multiobjective models - fails. + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static void diffevo_updatebest(gdemostate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_int_t i; + ae_int_t j; + double v; + double vv; + + + n = state->n; + m = state->m; + cntlc = state->cntlc; + cntnlc = state->cntnlc; + ae_assert(ae_fp_eq(state->nsample,(double)(1)), "GDEMO: integrity check 9242 failed", _state); + ae_assert(m==1, "GDEMO: integrity check 9243 failed", _state); + for(i=0; i<=state->population.cnt-1; i++) + { + if( ae_isnan(state->fitbest.ptr.p_double[0], _state)||ae_fp_less(state->population.fitness.ptr.pp_double[i][0],state->fitbest.ptr.p_double[0]) ) + { + + /* + * Save best value + */ + rcopyrr(n, &state->population.x, i, &state->xbest, 0, _state); + state->fitbest.ptr.p_double[0] = state->population.fitness.ptr.pp_double[i][0]; + state->rawfbest.ptr.p_double[0] = state->population.rawreplies.ptr.pp_double[i][0]; + + /* + * Update errors + */ + state->replcerr = 0.0; + state->replcidx = -1; + for(j=0; j<=cntlc-1; j++) + { + v = rdotrr(n, &state->xbest, 0, &state->densea, j, _state); + if( state->hasal.ptr.p_bool[j] ) + { + vv = state->ascales.ptr.p_double[j]*ae_maxreal(state->al.ptr.p_double[j]-v, 0.0, _state); + if( ae_fp_greater(vv,state->replcerr) ) + { + state->replcerr = vv; + state->replcidx = j; + } + } + if( state->hasau.ptr.p_bool[j] ) + { + vv = state->ascales.ptr.p_double[j]*ae_maxreal(v-state->au.ptr.p_double[j], 0.0, _state); + if( ae_fp_greater(vv,state->replcerr) ) + { + state->replcerr = vv; + state->replcidx = j; + } + } + } + state->repnlcerr = 0.0; + state->repnlcidx = -1; + for(j=0; j<=cntnlc-1; j++) + { + v = state->population.rawreplies.ptr.pp_double[i][m+j]; + if( state->hasnl.ptr.p_bool[j] ) + { + vv = ae_maxreal(state->rawnl.ptr.p_double[j]-v, 0.0, _state); + if( ae_fp_greater(vv,state->repnlcerr) ) + { + state->repnlcerr = vv; + state->repnlcidx = j; + } + } + if( state->hasnu.ptr.p_bool[j] ) + { + vv = ae_maxreal(v-state->rawnu.ptr.p_double[j], 0.0, _state); + if( ae_fp_greater(vv,state->repnlcerr) ) + { + state->repnlcerr = vv; + state->repnlcidx = j; + } + } + } + } + } +} + + +/************************************************************************* +This function generates candidates + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static void diffevo_generatetrialpoints(gdemostate* state, + const gdemopopulation* population, + gdemopopulation* trial, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t rngmax; + double invmax; + ae_int_t i; + ae_int_t popsize; + double v0; + double v1; + + + n = state->n; + m = state->m; + popsize = state->popsize; + ae_assert(m==1, "GDEMO: integrity check 4959 failed", _state); + rngmax = hqrndgetmax(_state); + invmax = (double)1/(double)rngmax; + + /* + * Generate DE parameters for candidates and allocate space + */ + ae_assert(popsize>=10, "GDEMO: integrity check 7156 failed", _state); + rgrowrowsfixedcolsm(popsize, n, &trial->x, _state); + rgrowrowsfixedcolsm(popsize, m+state->cntnlc, &trial->rawreplies, _state); + rgrowrowsfixedcolsm(popsize, m, &trial->fitness, _state); + rgrowrowsfixedcolsm(popsize, diffevo_paramscnt, &trial->deparams, _state); + trial->cnt = 0; + for(i=0; i<=popsize-1; i++) + { + ae_assert(diffevo_paramscnt==4, "GDEMO: integrity check 6759 failed", _state); + if( state->fixedparams ) + { + trial->deparams.ptr.pp_double[trial->cnt][0] = (double)(state->fixedstrategy); + trial->deparams.ptr.pp_double[trial->cnt][1] = state->fixedcrossoverprob; + trial->deparams.ptr.pp_double[trial->cnt][2] = state->fixeddifferentialweight; + trial->deparams.ptr.pp_double[trial->cnt][3] = state->fixeddifferentialweight; + } + else + { + + /* + * Generate a pair of normal numbers V0 and V1, with V1 being guarded away from zero. + * + * Use V0 to compute perturbed CR, and use V1 (or ratio V0/V1) to compute perturbed F. + * Because V0 is sometimes used to perturb both CR and F, there is some inter-dependence + * between two perturbations. However, numerical experiments show that it does not + * impact algorithm convergence. + */ + trial->deparams.ptr.pp_double[trial->cnt][0] = (double)(diffevo_stcurrenttoordbest1); + do + { + hqrndnormal2(&state->rs, &v0, &v1, _state); + } + while(ae_fp_less_eq(ae_fabs(v1, _state),1.0E-9)); + trial->deparams.ptr.pp_double[trial->cnt][1] = boundval(state->mucr+0.1*v0, 0.01, (double)(1), _state); + if( state->profile==0 ) + { + + /* + * Use 'ROBUST' profile for DE weight + */ + trial->deparams.ptr.pp_double[trial->cnt][2] = boundval(state->muf+0.1*(v0/v1), 0.01, (double)(2), _state); + } + else + { + + /* + * Use 'QUICK' profile for DE weight + */ + trial->deparams.ptr.pp_double[trial->cnt][2] = boundval(state->muf+0.1*(2.0*((double)hqrndintegerbase(&state->rs, _state)*invmax)-(double)1), 0.01, (double)(1), _state); + } + trial->deparams.ptr.pp_double[trial->cnt][3] = trial->deparams.ptr.pp_double[trial->cnt][2]; + } + trial->cnt = trial->cnt+1; + } + ae_assert(trial->cnt==popsize, "GDEMO: integrity check 0719 failed", _state); + + /* + * Generate candidates + */ + diffevo_gencand(&trial->deparams, &population->x, &population->fitness, n, m, popsize, &state->xbest, &state->finitebndl, &state->finitebndu, &state->rs, &trial->x, _state); +} + + +/************************************************************************* +This is an internal function that generates candidates given DE params + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static void diffevo_gencand(/* Real */ const ae_matrix* deparams, + /* Real */ const ae_matrix* populationx, + /* Real */ const ae_matrix* populationfitness, + ae_int_t n, + ae_int_t m, + ae_int_t popsize, + /* Real */ const ae_matrix* xbest, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + hqrndstate* rs, + /* Real */ ae_matrix* trialx, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t rngmax; + double invmax; + ae_int_t i; + ae_int_t j; + ae_int_t k0; + ae_int_t k1; + ae_int_t k2; + ae_int_t k3; + ae_int_t r; + ae_bool processed; + ae_int_t strategytype; + double crossoverprob; + double differentialweight; + double differentialweight2; + ae_vector donor; + ae_vector donorbase; + + ae_frame_make(_state, &_frame_block); + memset(&donor, 0, sizeof(donor)); + memset(&donorbase, 0, sizeof(donorbase)); + ae_vector_init(&donor, 0, DT_REAL, _state, ae_true); + ae_vector_init(&donorbase, 0, DT_REAL, _state, ae_true); + + + /* + * Try fast kernel + */ + if( diffevo_gdemogencandkernel(deparams, populationx, populationfitness, n, m, popsize, xbest, finitebndl, finitebndu, diffevo_bndlimit, hqrndintegerbase(rs, _state), trialx, _state) ) + { + ae_frame_leave(_state); + return; + } + + /* + * Use generic code + */ + ae_assert(m==1, "GDEMO: integrity check 4959 failed", _state); + ae_assert(popsize>=10, "GDEMO: integrity check 7156 failed", _state); + ae_assert(trialx->rows>=popsize&&trialx->cols>=n, "GDEMO: integrity check 7530 failed", _state); + rngmax = hqrndgetmax(_state); + invmax = (double)1/(double)rngmax; + rallocv(n, &donor, _state); + rallocv(n, &donorbase, _state); + for(i=0; i<=popsize-1; i++) + { + + /* + * Load candidate parameters + */ + strategytype = ae_round(deparams->ptr.pp_double[i][0], _state); + crossoverprob = deparams->ptr.pp_double[i][1]; + differentialweight = deparams->ptr.pp_double[i][2]; + differentialweight2 = deparams->ptr.pp_double[i][3]; + + /* + * Generate a set of 4 indexes, possibly nondistinct (enforcing distinctness makes the code slower, + * whislt not providing significant improvement in quality) + */ + k0 = hqrndintegerbase(rs, _state)%popsize; + k1 = hqrndintegerbase(rs, _state)%popsize; + k2 = hqrndintegerbase(rs, _state)%popsize; + k3 = hqrndintegerbase(rs, _state)%popsize; + + /* + * Generate donor vector + */ + processed = ae_false; + if( strategytype==0 ) + { + + /* + * DE/rand/1 + */ + rcopyrv(n, populationx, k0, &donor, _state); + raddrv(n, -1.0, populationx, k1, &donor, _state); + rmulv(n, differentialweight, &donor, _state); + rcopyrv(n, populationx, k2, &donorbase, _state); + processed = ae_true; + } + if( strategytype==1 ) + { + + /* + * DE/best/2 + */ + rsetv(n, 0.0, &donor, _state); + raddrv(n, 1.0, populationx, k0, &donor, _state); + raddrv(n, -1.0, populationx, k1, &donor, _state); + raddrv(n, 1.0, populationx, k2, &donor, _state); + raddrv(n, -1.0, populationx, k3, &donor, _state); + rmulv(n, differentialweight, &donor, _state); + rcopyrv(n, xbest, hqrndintegerbase(rs, _state)%m, &donorbase, _state); + processed = ae_true; + } + if( strategytype==diffevo_stcurrenttobest1 ) + { + + /* + * DE/current-to-best/1 + */ + rsetv(n, 0.0, &donor, _state); + raddrv(n, differentialweight, populationx, k0, &donor, _state); + raddrv(n, -differentialweight, populationx, k1, &donor, _state); + raddrv(n, differentialweight2, xbest, hqrndintegerbase(rs, _state)%m, &donor, _state); + raddrv(n, -differentialweight2, populationx, i, &donor, _state); + rcopyrv(n, populationx, i, &donorbase, _state); + processed = ae_true; + } + if( strategytype==diffevo_stcurrenttoordbest1 ) + { + + /* + * DE/current-to-ord_best/1 + */ + if( m!=1 ) + { + ae_assert(ae_false, "GDEMO: integrity check 091405 failed", _state); + } + rsetv(n, 0.0, &donor, _state); + if( ae_fp_less(populationfitness->ptr.pp_double[k0][0],populationfitness->ptr.pp_double[k1][0]) ) + { + raddrv(n, differentialweight, populationx, k0, &donor, _state); + raddrv(n, -differentialweight, populationx, k1, &donor, _state); + } + else + { + raddrv(n, differentialweight, populationx, k1, &donor, _state); + raddrv(n, -differentialweight, populationx, k0, &donor, _state); + } + raddrv(n, differentialweight2, xbest, hqrndintegerbase(rs, _state)%m, &donor, _state); + raddrv(n, -differentialweight2, populationx, i, &donor, _state); + rcopyrv(n, populationx, i, &donorbase, _state); + processed = ae_true; + } + ae_assert(processed, "GDEMO: integrity check 7131 failed", _state); + raddv(n, 1.0, &donorbase, &donor, _state); + for(j=0; j<=n-1; j++) + { + donor.ptr.p_double[j] = ae_maxreal(donor.ptr.p_double[j], diffevo_bndlimit*donorbase.ptr.p_double[j]+((double)1-diffevo_bndlimit)*finitebndl->ptr.p_double[j], _state); + donor.ptr.p_double[j] = ae_minreal(donor.ptr.p_double[j], diffevo_bndlimit*donorbase.ptr.p_double[j]+((double)1-diffevo_bndlimit)*finitebndu->ptr.p_double[j], _state); + } + + /* + * Perform crossover with the target, apply box constraints to the donor in the process + */ + r = hqrndintegerbase(rs, _state)%n; + rcopyrr(n, populationx, i, trialx, i, _state); + for(j=0; j<=n-1; j++) + { + if( (double)hqrndintegerbase(rs, _state)*invmax<=crossoverprob||j==r ) + { + trialx->ptr.pp_double[i][j] = donor.ptr.p_double[j]; + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This is an internal function that generates candidates given DE params +using SIMD kernels + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static ae_bool diffevo_gdemogencandkernel(/* Real */ const ae_matrix* deparams, + /* Real */ const ae_matrix* populationx, + /* Real */ const ae_matrix* populationfitness, + ae_int_t n, + ae_int_t m, + ae_int_t popsize, + /* Real */ const ae_matrix* xbest, + /* Real */ const ae_vector* finitebndl, + /* Real */ const ae_vector* finitebndu, + double bndsmooth, + ae_int_t seedval, + /* Real */ ae_matrix* trialx, + ae_state *_state) +{ + ae_bool result; + + + result = ae_false; + return result; +} + + +/************************************************************************* +Promote candidates + + -- ALGLIB -- + Copyright 07.12.2023 by Bochkanov Sergey +*************************************************************************/ +static void diffevo_updatepopulation(gdemostate* state, + const gdemopopulation* children, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntnlc; + ae_int_t i; + double avgcr; + double sumf; + double sumf2; + double df; + double sumdf; + ae_int_t avgcnt; + + + n = state->n; + m = state->m; + cntnlc = state->cntnlc; + + /* + * Perform competition. + * + * NOTE: it is important to compare fitness as follows: "if CandFitness<=PopFitness", + * using <= instead of <, because it promotes explorational behavior in areas + * with vanishing gradient. + */ + ae_assert(ae_fp_eq(state->nsample,(double)(1)), "GDEMO: integrity check 2649 failed", _state); + ae_assert(m==1, "GDEMO: integrity check 2650 failed", _state); + ae_assert(state->popsize==children->cnt, "GDEMO: integrity check 9300 failed", _state); + avgcr = 0.0; + sumf = 0.0; + sumf2 = 0.0; + sumdf = 0.0; + avgcnt = 0; + for(i=0; i<=state->popsize-1; i++) + { + if( ae_fp_less_eq(children->fitness.ptr.pp_double[i][0],state->population.fitness.ptr.pp_double[i][0]) ) + { + df = state->population.fitness.ptr.pp_double[i][0]-children->fitness.ptr.pp_double[i][0]; + + /* + * The candidate wins! Copy the candidate data + */ + rcopyrr(n, &children->x, i, &state->population.x, i, _state); + rcopyrr(m+cntnlc, &children->rawreplies, i, &state->population.rawreplies, i, _state); + rcopyrr(m, &children->fitness, i, &state->population.fitness, i, _state); + + /* + * Update average params + */ + ae_assert(diffevo_paramscnt==4, "GDEMO: integrity check 207213 failed", _state); + if( df>(double)0 ) + { + avgcr = avgcr+df*children->deparams.ptr.pp_double[i][1]; + sumf = sumf+df*children->deparams.ptr.pp_double[i][2]; + sumf2 = sumf2+df*ae_sqr(children->deparams.ptr.pp_double[i][2], _state); + sumdf = sumdf+df; + avgcnt = avgcnt+1; + } + } + } + if( avgcnt>0 ) + { + state->mucr = ((double)1-diffevo_mulearningrate)*state->mucr+diffevo_mulearningrate*(avgcr/sumdf); + state->muf = ((double)1-diffevo_mulearningrate)*state->muf+diffevo_mulearningrate*(sumf2/sumdf/(sumf/sumdf)); + } +} + + +void _gdemopopulation_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gdemopopulation *p = (gdemopopulation*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rawreplies, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->fitness, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->deparams, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _gdemopopulation_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gdemopopulation *dst = (gdemopopulation*)_dst; + const gdemopopulation *src = (const gdemopopulation*)_src; + dst->cnt = src->cnt; + ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_matrix_init_copy(&dst->rawreplies, &src->rawreplies, _state, make_automatic); + ae_matrix_init_copy(&dst->fitness, &src->fitness, _state, make_automatic); + ae_matrix_init_copy(&dst->deparams, &src->deparams, _state, make_automatic); +} + + +void _gdemopopulation_clear(void* _p) +{ + gdemopopulation *p = (gdemopopulation*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->x); + ae_matrix_clear(&p->rawreplies); + ae_matrix_clear(&p->fitness); + ae_matrix_clear(&p->deparams); +} + + +void _gdemopopulation_destroy(void* _p) +{ + gdemopopulation *p = (gdemopopulation*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->x); + ae_matrix_destroy(&p->rawreplies); + ae_matrix_destroy(&p->fitness); + ae_matrix_destroy(&p->deparams); +} + + +void _gdemostate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gdemostate *p = (gdemostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasal, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasau, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->rawnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasnl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasnu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->ascales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _hqrndstate_init(&p->rs, _state, make_automatic); + _gdemopopulation_init(&p->population, _state, make_automatic); + _gdemopopulation_init(&p->offspring, _state, make_automatic); + ae_matrix_init(&p->xbest, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fitbest, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawfbest, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpzero, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->dummysparsea, _state, make_automatic); + ae_vector_init(&p->goodbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->goodbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->empiricalbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->empiricalbndu, 0, DT_REAL, _state, make_automatic); +} + + +void _gdemostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gdemostate *dst = (gdemostate*)_dst; + const gdemostate *src = (const gdemostate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->cntlc = src->cntlc; + dst->cntnlc = src->cntnlc; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->hasx0 = src->hasx0; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + ae_vector_init_copy(&dst->hasal, &src->hasal, _state, make_automatic); + ae_vector_init_copy(&dst->hasau, &src->hasau, _state, make_automatic); + ae_vector_init_copy(&dst->rawnl, &src->rawnl, _state, make_automatic); + ae_vector_init_copy(&dst->rawnu, &src->rawnu, _state, make_automatic); + ae_vector_init_copy(&dst->hasnl, &src->hasnl, _state, make_automatic); + ae_vector_init_copy(&dst->hasnu, &src->hasnu, _state, make_automatic); + ae_vector_init_copy(&dst->ascales, &src->ascales, _state, make_automatic); + dst->popsize = src->popsize; + dst->epochscnt = src->epochscnt; + dst->constrmode = src->constrmode; + dst->rho1 = src->rho1; + dst->rho2 = src->rho2; + dst->eps = src->eps; + dst->nsample = src->nsample; + dst->profile = src->profile; + dst->fixedparams = src->fixedparams; + dst->fixedstrategy = src->fixedstrategy; + dst->fixedcrossoverprob = src->fixedcrossoverprob; + dst->fixeddifferentialweight = src->fixeddifferentialweight; + dst->stoponsmallf = src->stoponsmallf; + dst->smallf = src->smallf; + dst->condfxepsf = src->condfxepsf; + dst->condfxepsx = src->condfxepsx; + dst->mucr = src->mucr; + dst->muf = src->muf; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + _gdemopopulation_init_copy(&dst->population, &src->population, _state, make_automatic); + _gdemopopulation_init_copy(&dst->offspring, &src->offspring, _state, make_automatic); + ae_matrix_init_copy(&dst->xbest, &src->xbest, _state, make_automatic); + ae_vector_init_copy(&dst->fitbest, &src->fitbest, _state, make_automatic); + ae_vector_init_copy(&dst->rawfbest, &src->rawfbest, _state, make_automatic); + dst->repterminationtype = src->repterminationtype; + dst->repiterationscount = src->repiterationscount; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + ae_vector_init_copy(&dst->tmpzero, &src->tmpzero, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysparsea, &src->dummysparsea, _state, make_automatic); + ae_vector_init_copy(&dst->goodbndl, &src->goodbndl, _state, make_automatic); + ae_vector_init_copy(&dst->goodbndu, &src->goodbndu, _state, make_automatic); + ae_vector_init_copy(&dst->empiricalbndl, &src->empiricalbndl, _state, make_automatic); + ae_vector_init_copy(&dst->empiricalbndu, &src->empiricalbndu, _state, make_automatic); +} + + +void _gdemostate_clear(void* _p) +{ + gdemostate *p = (gdemostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + ae_matrix_clear(&p->densea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + ae_vector_clear(&p->hasal); + ae_vector_clear(&p->hasau); + ae_vector_clear(&p->rawnl); + ae_vector_clear(&p->rawnu); + ae_vector_clear(&p->hasnl); + ae_vector_clear(&p->hasnu); + ae_vector_clear(&p->ascales); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + _rcommstate_clear(&p->rstate); + _hqrndstate_clear(&p->rs); + _gdemopopulation_clear(&p->population); + _gdemopopulation_clear(&p->offspring); + ae_matrix_clear(&p->xbest); + ae_vector_clear(&p->fitbest); + ae_vector_clear(&p->rawfbest); + ae_vector_clear(&p->tmpzero); + _sparsematrix_clear(&p->dummysparsea); + ae_vector_clear(&p->goodbndl); + ae_vector_clear(&p->goodbndu); + ae_vector_clear(&p->empiricalbndl); + ae_vector_clear(&p->empiricalbndu); +} + + +void _gdemostate_destroy(void* _p) +{ + gdemostate *p = (gdemostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + ae_matrix_destroy(&p->densea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + ae_vector_destroy(&p->hasal); + ae_vector_destroy(&p->hasau); + ae_vector_destroy(&p->rawnl); + ae_vector_destroy(&p->rawnu); + ae_vector_destroy(&p->hasnl); + ae_vector_destroy(&p->hasnu); + ae_vector_destroy(&p->ascales); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + _rcommstate_destroy(&p->rstate); + _hqrndstate_destroy(&p->rs); + _gdemopopulation_destroy(&p->population); + _gdemopopulation_destroy(&p->offspring); + ae_matrix_destroy(&p->xbest); + ae_vector_destroy(&p->fitbest); + ae_vector_destroy(&p->rawfbest); + ae_vector_destroy(&p->tmpzero); + _sparsematrix_destroy(&p->dummysparsea); + ae_vector_destroy(&p->goodbndl); + ae_vector_destroy(&p->goodbndu); + ae_vector_destroy(&p->empiricalbndl); + ae_vector_destroy(&p->empiricalbndu); +} + + +#endif +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + GLOBAL OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR CONSTRAINTS + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear generalized inequality constraints Li<=Ci(x)<=Ui, with one of + Li/Ui possibly being infinite + +REQUIREMENTS: +* F() and C() do NOT have to be differentiable, locally Lipschitz or + continuous. Most solvers in this subpackage can deal with nonsmoothness + or minor discontinuities, although obviously smoother problems are the + most easy ones. +* generally, F() and C() must be computable at any point which is feasible + subject to box constraints + +USAGE: + +1. User initializes algorithm state with mindfcreate() call and + chooses specific solver to be used. There is some solver which is used + by default, with default settings, but you should NOT rely on the + default choice. It may change in the future releases of ALGLIB without + notice, and no one can guarantee that the new solver will be able to + solve your problem with default settings. + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) mindfsetbc() for boundary constraints + b) mindfsetlc2dense() for linear constraints + c) mindfsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with mindfsetscale() function. It is + VERY important to set variable scales because many derivative-free + algorithms refuse to work when variables are badly scaled. + Scaling helps to seed initial population, control convergence and + enforce penalties for constraint violation. + +4. Finally, user calls mindfoptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F and G. + +5. User calls mindfresults() to get a solution + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]. Some solvers can utilize a good + initial point to seed computations. + + As of ALGLIB 4.04, the initial point is: + * used by GDEMO + + If the chosen solver does not need initial point, one can + supply zeros. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + +IMPORTANT: the MINDF optimizer supports parallel model evaluation + ('callback parallelism'). This feature, which is present in + commercial ALGLIB editions, greatly accelerates algorithms like + differential evolution which usually issue batch requests to + user callbacks which can be efficiently parallelized. + + Callback parallelism is usually beneficial when the batch + evalution requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on mindfoptimize() function for more + information. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfcreate(ae_int_t n, + /* Real */ const ae_vector* x, + mindfstate* state, + ae_state *_state) +{ + + _mindfstate_clear(state); + + ae_assert(n>=1, "MinDFCreate: N<1", _state); + ae_assert(x->cnt>=n, "MinDFCreate: Length(X)dotimers = ae_false; + state->protocolversion = 2; + state->n = n; + rsetallocv(n, _state->v_neginf, &state->bndl, _state); + rsetallocv(n, _state->v_posinf, &state->bndu, _state); + rsetallocv(n, -ae_maxrealnumber, &state->finitebndl, _state); + rsetallocv(n, ae_maxrealnumber, &state->finitebndu, _state); + bsetallocv(n, ae_false, &state->hasbndl, _state); + bsetallocv(n, ae_false, &state->hasbndu, _state); + state->m = 0; + state->nnlc = 0; + rsetallocv(n, 1.0, &state->s, _state); + state->hasx0 = ae_true; + rcopyallocv(n, x, &state->x0, _state); + rcopyallocv(n, x, &state->xf, _state); + state->xrep = ae_false; + state->ssgdmomentum = mindf_defaultmomentum; + state->rngseed = 0; + state->gdemofixedparams = ae_false; + state->gdemoprofile = 0; + state->gdemorho1 = (double)(0); + state->gdemorho2 = (double)(0); + state->stoponsmallf = ae_false; + state->condfxepsf = 0.0; + state->condfxepsx = 0.0; + mindfsetalgogdemo(state, 100, 0, _state); + + /* + * communication with user + */ + state->userterminationneeded = ae_false; + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function sets box constraints. + +Box constraints are inactive by default (after initial creation). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetbc(mindfstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "MinDFSetBC: Length(BndL)cnt>=n, "MinDFSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinDFSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinDFSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + state->finitebndl.ptr.p_double[i] = rcase2(state->hasbndl.ptr.p_bool[i], state->bndl.ptr.p_double[i], -ae_maxrealnumber, _state); + state->finitebndu.ptr.p_double[i] = rcase2(state->hasbndu.ptr.p_bool[i], state->bndu.ptr.p_double[i], ae_maxrealnumber, _state); + } +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetlc2dense(mindfstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = state->n; + + /* + * Check input arguments + */ + ae_assert(k>=0, "MinDFSetLC2Dense: K<0", _state); + ae_assert(k==0||a->cols>=n, "MinDFSetLC2Dense: Cols(A)rows>=k, "MinDFSetLC2Dense: Rows(A)cnt>=k, "MinDFSetLC2Dense: Length(AL)cnt>=k, "MinDFSetLC2Dense: Length(AU)ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "MinDFSetLC2Dense: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "MinDFSetLC2Dense: AU contains NAN or -INF", _state); + } + + /* + * Quick exit if needed + */ + if( k==0 ) + { + state->m = 0; + return; + } + + /* + * Copy + */ + rcopyallocv(k, al, &state->al, _state); + rcopyallocv(k, au, &state->au, _state); + rcopyallocm(k, n, a, &state->densea, _state); + state->m = k; +} + + +/************************************************************************* +This function sets two-sided nonlinear constraints. + +In fact, this function sets only NUMBER of the nonlinear constraints. +Constraints themselves (constraint functions) are passed to the +MinDFOptimize() method. + +This method accepts user-defined vector function F[] where: +* first component of F[] corresponds to the objective +* subsequent NNLC components of F[] correspond to the two-sided nonlinear + constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + +NOTE 2: the algorithm scales variables according to the scale specified by + MinDFSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints. We recommend you to scale + nonlinear constraints in such a way that the derivatives (if + constraints are differentiable) have approximately unit magnitude + (for problems with unit variable scales) or have magnitudes + approximately equal to 1/S[i] (where S is a variable scale set by + MinDFSetScale() function). + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetnlc2(mindfstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nnlc>=0, "MinDFSetNLC2: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "MinDFSetNLC2: Length(NL)cnt>=nnlc, "MinDFSetNLC2: Length(NU)nnlc = nnlc; + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "MinDFSetNLC2: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "MinDFSetNLC2: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function sets a combined stopping condition: stopping when two +criteria are met simultaneously: +* function values has converged to a neighborhood whose size is + proportional to epsF +* variable values has converged to a neighborhood whose size is + proportional to epsX +It is possible to use only one condition by setting another EPS to zero. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + EpsX - >=0: + * zero value means no condition for X + * EpsX>0 means stopping when the solver converged with + error in I-th variable less than EpsX*S[i], where S[i] + is a variable scale + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondfx(mindfstate* state, + double epsf, + double epsx, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "MinDFSetCondFX: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinDFSetCondFX: negative EpsF", _state); + ae_assert(ae_isfinite(epsx, _state), "MinDFSetCondFX: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinDFSetCondFX: negative EpsX", _state); + state->condfxepsf = epsf; + state->condfxepsx = epsx; +} + + +/************************************************************************* +This function activates/deactivates internal timers used to track time +spent in various parts of the solver (mostly, callbacks vs solver itself). + +When activated with this function, the following timings are stored in the +mindfreport structure fields: +* total time spend in the optimization +* time spent in the callback +* time spent in the solver itself + +See comments on mindfreport structure for more information about timers +and their accuracy. + +Timers are an essential part of reports that helps to find out where the +most time is spent and how to optimize the code. E.g., noticing that +significant amount of time is spent in numerical differentiation makes +obvious that ALGLIB-provided parallel numerical differentiation is needed. + +However, time measurements add noticeable overhead, about 50-100ns per +function call. In some applications it results in a significant slowdown, +that's why this option is inactive by default and should be manually +activated. + +INPUT PARAMETERS: + State - structure which stores algorithm state + UseTimers- true or false + +NOTE: when tracing is turned on with alglib::trace_file(), some derivative + free solvers may also perform internal, more detailed time + measurements, which are printed to the log file. + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfusetimers(mindfstate* state, + ae_bool usetimers, + ae_state *_state) +{ + + + state->dotimers = usetimers; +} + + +/************************************************************************* +This function sets stopping condition for the optimizer: function values +has converged to a neighborhood whose size is proportional to epsF. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondf(mindfstate* state, double epsf, ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "MinDFSetCondF: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinDFSetCondF: negative EpsF", _state); + state->condfxepsf = epsf; + state->condfxepsx = (double)(0); +} + + +/************************************************************************* +This function sets variable scales. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and to +guide algorithm steps. + +The scale of a variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetscale(mindfstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinDFSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinDFSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinDFSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinDFOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - the best point + so far and a function value at the point. For unconstrained problems + the function value is non-increasing (the most recent best point is + always at least not worse than the previous best one). However, it + can increase between iterations when solving constrained problems + (a better point may have higher objective value but smaller + constraint violation). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void mindfsetxrep(mindfstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This subroutine submits request for termination of a running optimizer. It +should be called from a user-supplied callback when user decides that it +is time to "smoothly" terminate optimization process. As a result, the +optimizer stops at the point which was "current accepted" when the +termination request was submitted and returns error code 8 (successful +termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on an optimizer which is NOT running will have + no effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfrequesttermination(mindfstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +This function sets seed used by internal RNG. + +By default, a random seed is used, i.e. every time you run the solver, we +seed its generator with a new value obtained from the system-wide RNG. +Thus, the solver returns non-deterministic results. You can change such +a behavior by specifying a fixed positive seed value. + +INPUT PARAMETERS: + S - optimizer structure + SeedVal - seed value: + * positive values are used for seeding RNG with a + fixed seed, i.e. subsequent runs on the same + objective will return the same results + * non-positive seed means that a random seed is used + for every run, i.e. subsequent runs on the same + objective will return slightly different results + + -- ALGLIB -- + Copyright 26.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetseed(mindfstate* s, ae_int_t seedval, ae_state *_state) +{ + + + s->rngseed = seedval; +} + + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with an +automatic parameters selection. + +NOTE: a version with manually tuned parameters can be activated by calling + the mindfsetalgogdemofixed() function. + +The primary stopping condition for the solver is to stop after the specified +number of iterations. You can also specify additional criteria to stop +early: +* stop when subpopulation target values (2N+1 best individuals) are within + EPS from the best one so far (function values seem to converge) +* stop when both subpopulation target values AND subpopulation variable + values are within EPS from the best one so far + +The first condition is specified with mindfsetcondf(), the second one is +activated with mindfsetcondfx(). + +Both conditions are heuristics which may fail. Being 'within EPS from the +best value so far' in practice means that we are somewhere within +[0.1EPS,10EPS] from the true solution; however, on difficult problems +this condition may fire too early. + +Imposing an additional requirement that variable values have clustered too +may prevent us from premature stopping. However, on multi-extremal and/or +noisy problems too many individuals may be trapped away from the optimum, +preventing this condition from activation. + +ALGORITHM PROPERTIES: + +* the solver uses a variant of the adaptive parameter tuning strategy + called 'Success-History Based Parameter Adaptation for Differential + Evolution Ensemble' (SHADE) by Ryoji Tanabe and Alex Fukunaga. You do + not have to specify crossover probability and differential weight, the + solver will automatically choose the most appropriate strategy. + +* the solver can handle box, linear, nonlinear constraints. Linear and + nonlinear constraints are handled by means of an L1/L2 penalty. The + solver does not violate box constraints at any point, but may violate + linear and nonlinear ones. Penalty coefficient can be changed with the + mindfsetgdemopenalty() function. + +* the solver heavily depends on variable scales being available (specified + by means of mindfsetscale() call) and on box constraints with both lower + and upper bounds being available which are used to determine the search + region. It will work without box constraints and without scales, but + results are likely to be suboptimal. + +* the solver is SIMD-optimized and parallelized (in commercial ALGLIB + editions), with nearly linear scalability of parallel processing. + +* this solver is intended for finding solutions with up to several digits + of precision at best. Its primary purpose is to find at least some + solution to an otherwise intractable problem. + +IMPORTANT: derivative-free optimization is inherently less robust than the + smooth nonlinear programming, especially when nonsmoothness and + discontinuities are present. + + Derivative-free algorithms have less convergence guarantees + than their smooth counterparts. It is considered a normal + (although, obviously, undesirable) situation when a derivative- + -free algorithm fails to converge with desired precision. Having + 2 digits of accurasy is already a good result, on difficult + problems (high numerical noise, discontinuities) you may have + even less than that. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + PopSize - population size, >=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemo(mindfstate* state, + ae_int_t epochscnt, + ae_int_t popsize, + ae_state *_state) +{ + + + ae_assert(popsize>=0, "MinDFSetAlgoGDEMO: PopSize<0", _state); + ae_assert(epochscnt>0, "MinDFSetAlgoGDEMO: EpochsCnt<=0", _state); + state->gdemoepochscnt = epochscnt; + state->gdemopopsize = popsize; + state->gdemofixedparams = ae_false; + state->solvertype = 0; +} + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +ROBUST profile (the default option). + +The ROBUST profile is intended to facilitate explorative behavior and +robust convergence even on difficult multi-extremal problems. It comes at +the expense of increased running time even on easy problems. The QUICK +profile can be chosen if your problem is relatively easy to handle and you +prefer speed over robustness. In most cases, the QUICK profile is ~2x-3x +faster than the robust one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilerobust(mindfstate* state, ae_state *_state) +{ + + + state->gdemoprofile = 0; +} + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +QUICK profile. + +The QUICK profile is intended to facilitate accelerated convergence on +medium-complexity problems at the cost of (sometimes) having premature +convergence on difficult and/or multi-extremal problems. The ROBUST +profile can be selected if you favor convergence warranties over speed. +In most cases, the ROBUST profile is ~2x-3x slower than the QUICK one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + you want to activate differential evolution solver, you still + have to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilequick(mindfstate* state, ae_state *_state) +{ + + + state->gdemoprofile = 1; +} + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to handle +linear/nonlinear constraints by an L1/L2 penalty function. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + Rho1, Rho2 - penalty parameters for constraint violations: + * Rho1 is a multiplier for L1 penalty + * Rho2 is a multiplier for L2 penalty + * Rho1,Rho2>=0 + * having both of them at zero means that some default + value will be chosen. + Ignored for problems with box-only constraints. + + L1 penalty is usually better at enforcing constraints, + but leads to slower convergence than L2 penalty. It is + possible to combine both kinds of penalties together. + + There is a compromise between constraint satisfaction + and optimality: high values of Rho mean that + constraints are satisfied with high accuracy but that + the target may be underoptimized due to numerical + difficulties. Small values of Rho mean that the + solution may grossly violate constraints. Choosing + good Rho is usually a matter of trial and error. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemopenalty(mindfstate* state, + double rho1, + double rho2, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(rho1, _state), "MinDFSetGDEMOPenalty: Rho1 is not a finite number", _state); + ae_assert(ae_isfinite(rho2, _state), "MinDFSetGDEMOPenalty: Rho2 is not a finite number", _state); + ae_assert(ae_fp_greater_eq(rho1,(double)(0)), "MinDFSetGDEMOPenalty: Rho1<0", _state); + ae_assert(ae_fp_greater_eq(rho2,(double)(0)), "MinDFSetGDEMOPenalty: Rho2<0", _state); + state->gdemorho1 = rho1; + state->gdemorho2 = rho2; +} + + +/************************************************************************* +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetsmallf(mindfstate* state, double f, ae_state *_state) +{ + + + ae_assert(ae_isfinite(f, _state), "MinDFSetSmallF: F is not a finite number", _state); + state->stoponsmallf = ae_true; + state->smallf = f; +} + + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with the +manual parameters selection. + +Unlike DE with an automatic parameters selection this function requires +user to manually specify algorithm parameters. In the general case the +full-auto GDEMO is better. However, it has to spend some time finding out +properties of a problem being solved; furthermore, it is not allowed to +try potentially dangerous values of parameters that lead to premature +stopping. Manually tuning the solver to the specific problem at hand can +get 2x-3x better running time. + +Aside from that, the algorithm is fully equivalent to automatic GDEMO, and +we recommend you reading comments on mindfsetalgogdemo() for more +information about algorithm properties and stopping criteria. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + Strategy - specific DE strategy to use: + * 0 for DE/rand/1 + * 1 for DE/best/2 + * 2 for DE/current-to-best/1 + CrossoverProb- crossover probability, 0=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemofixed(mindfstate* state, + ae_int_t epochscnt, + ae_int_t strategy, + double crossoverprob, + double differentialweight, + ae_int_t popsize, + ae_state *_state) +{ + + + ae_assert(strategy>=0&&strategy<=2, "MinDFSetAlgoGDEMOFixed: incorrect Strategy", _state); + ae_assert((ae_isfinite(crossoverprob, _state)&&ae_fp_greater(crossoverprob,(double)(0)))&&ae_fp_less(crossoverprob,(double)(1)), "MinDFSetAlgoGDEMOFixed: CrossoverProb is infinite number or outside of (0,1)", _state); + ae_assert((ae_isfinite(differentialweight, _state)&&ae_fp_greater(differentialweight,(double)(0)))&&ae_fp_less(differentialweight,(double)(2)), "MinDFSetAlgoGDEMOFixed: DifferentialWeight is infinite number or outside of (0,2)", _state); + ae_assert(popsize>=0, "MinDFSetAlgoGDEMOFixed: PopSize<0", _state); + ae_assert(epochscnt>0, "MinDFSetAlgoGDEMOFixed: EpochsCnt<=0", _state); + state->gdemoepochscnt = epochscnt; + state->gdemopopsize = popsize; + state->gdemofixedparams = ae_true; + state->gdemostrategy = strategy; + state->gdemocrossoverprob = crossoverprob; + state->gdemodifferentialweight = differentialweight; + state->solvertype = 0; +} + + +/************************************************************************* + +CALLBACK PARALLELISM + +The MINDF optimizer supports parallel model evaluation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates optimization when using a solver which +issues batch requests, i.e. multiple requests for target values, which +can be computed independently by different threads. + +Callback parallelism is usually beneficial when processing a batch +request requires more than several milliseconds. It also requires the +solver which issues requests in convenient batches, e.g. the differential +evolution solver. + +See ALGLIB Reference Manual, 'Working with commercial version' section for +more information. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool mindfiteration(mindfstate* state, ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_bool b; + ae_int_t originalrequest; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + n = state->rstate.ia.ptr.p_int[1]; + originalrequest = state->rstate.ia.ptr.p_int[2]; + b = state->rstate.ba.ptr.p_bool[0]; + } + else + { + i = 359; + n = -58; + originalrequest = -919; + b = ae_true; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + n = state->n; + + /* + * Init + */ + state->repf = ae_maxrealnumber; + state->replcerr = 0.0; + state->repnlcerr = 0.0; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfunc = 0; + state->repnrequests = 0; + state->reptimetotal = (double)(0); + state->reptimecallback = (double)(0); + state->userterminationneeded = ae_false; + stimerinit(&state->timertotal, _state); + stimerinit(&state->timercallback, _state); + if( state->dotimers ) + { + stimerstart(&state->timertotal, _state); + } + + /* + * Allocate temporaries, as mandated by the V2 protocol + */ + ae_assert(state->protocolversion==2, "MINDF: integrity check 5124 failed", _state); + rallocv(n, &state->reportx, _state); + rallocv(n, &state->tmpx1, _state); + rallocv(1+state->nnlc, &state->tmpf1, _state); + + /* + * Various algorithms supported by the optimizer + */ + if( state->solvertype!=0 ) + { + goto lbl_4; + } + + /* + * Initialize the solver + */ + b = ae_false; + if( state->solvertype==0 ) + { + gdemoinitbuf(&state->bndl, &state->bndu, &state->s, n, 1, &state->densea, &state->al, &state->au, state->m, &state->nl, &state->nu, state->nnlc, state->gdemopopsize, state->gdemoepochscnt, state->rngseed, &state->gdemosolver, _state); + gdemosetprofile(&state->gdemosolver, state->gdemoprofile, _state); + if( state->hasx0 ) + { + gdemosetx0(&state->gdemosolver, &state->x0, _state); + } + if( state->gdemofixedparams ) + { + gdemosetfixedparams(&state->gdemosolver, state->gdemostrategy, state->gdemocrossoverprob, state->gdemodifferentialweight, _state); + } + if( state->stoponsmallf ) + { + gdemosetsmallf(&state->gdemosolver, state->smallf, _state); + } + if( ae_fp_greater(state->condfxepsf,(double)(0))||ae_fp_greater(state->condfxepsx,(double)(0)) ) + { + gdemosetcondfx(&state->gdemosolver, state->condfxepsf, state->condfxepsx, _state); + } + b = ae_fp_neq(state->gdemorho1,(double)(0))||ae_fp_neq(state->gdemorho2,(double)(0)); + gdemosetmodepenalty(&state->gdemosolver, rcase2(b, state->gdemorho1, 50.0, _state), rcase2(b, state->gdemorho2, 50.0, _state), _state); + b = ae_true; + } + ae_assert(b, "MINDF: integrity check 9536 failed", _state); + + /* + * Perform iterations + */ +lbl_6: + if( ae_false ) + { + goto lbl_7; + } + + /* + * Run the iteration function and load request + */ + state->requesttype = 0; + originalrequest = 0; + b = ae_false; + if( state->solvertype==0 ) + { + if( !gdemoiteration(&state->gdemosolver, state->userterminationneeded, _state) ) + { + goto lbl_7; + } + if( state->gdemosolver.requesttype==4 ) + { + rallocv(n*state->gdemosolver.querysize, &state->unscaled, _state); + state->batchsize = state->gdemosolver.querysize; + unscalexbatchfinitebnd(&state->gdemosolver.querydata, state->gdemosolver.querysize, &state->s, n, &state->gdemosolver.finitebndl, &state->gdemosolver.finitebndu, &state->finitebndl, &state->finitebndu, &state->unscaled, _state); + originalrequest = 4; + b = ae_true; + } + if( state->gdemosolver.requesttype==-1 ) + { + unscalexbatchfinitebnd(&state->gdemosolver.reportx, 1, &state->s, n, &state->gdemosolver.finitebndl, &state->gdemosolver.finitebndu, &state->finitebndl, &state->finitebndu, &state->reportx, _state); + state->reportf = state->gdemosolver.reportf; + state->repf = state->gdemosolver.reportf; + originalrequest = -1; + b = ae_true; + } + } + ae_assert(b, "DFGM: integrity check 3141 failed", _state); + + /* + * Forward request to user + */ + b = ae_false; + if( originalrequest!=-1 ) + { + goto lbl_8; + } + + /* + * Report + */ + ae_assert(state->protocolversion==2, "MINDF: integrity check 4642 failed", _state); + state->requesttype = -1; + if( !state->xrep ) + { + goto lbl_10; + } + if( state->dotimers ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( state->dotimers ) + { + stimerstop(&state->timercallback, _state); + } +lbl_10: + b = ae_true; +lbl_8: + if( originalrequest!=4 ) + { + goto lbl_12; + } + if( state->dotimers ) + { + stimerstart(&state->timercallback, _state); + } + state->repnfunc = state->repnfunc+state->batchsize; + state->repnrequests = state->repnrequests+1; + rallocv(n, &state->querydata, _state); + rallocv(1+state->nnlc, &state->replyfi, _state); + rallocv((1+state->nnlc)*state->batchsize, &state->combined, _state); + i = 0; +lbl_14: + if( i>state->batchsize-1 ) + { + goto lbl_16; + } + state->requesttype = 4; + state->queryfuncs = 1+state->nnlc; + state->queryvars = n; + state->querydim = 0; + state->querysize = 1; + rcopyvx(n, &state->unscaled, i*n, &state->querydata, 0, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rcopyvx(1+state->nnlc, &state->replyfi, 0, &state->combined, i*(1+state->nnlc), _state); + i = i+1; + goto lbl_14; +lbl_16: + if( state->dotimers ) + { + stimerstop(&state->timercallback, _state); + } + b = ae_true; +lbl_12: + ae_assert(b, "MINDF: integrity check 8545 failed", _state); + + /* + * Send results back to the optimizer + */ + ae_assert(originalrequest==-1||originalrequest==4, "MINDF: integrity check 9046 failed", _state); + b = ae_false; + if( originalrequest==-1 ) + { + + /* + * Do nothing + */ + b = ae_true; + } + if( originalrequest==4&&state->solvertype==0 ) + { + + /* + * 2PS solver + */ + ae_assert(state->protocolversion==2, "MINDF: integrity check 0446 failed", _state); + rcopyv((1+state->nnlc)*state->batchsize, &state->combined, &state->gdemosolver.replyfi, _state); + b = ae_true; + } + ae_assert(b, "MINDF: integrity check 1247 failed", _state); + goto lbl_6; +lbl_7: + + /* + * Results + */ + if( state->dotimers ) + { + stimerstop(&state->timertotal, _state); + state->reptimetotal = 0.001*stimergetms(&state->timertotal, _state); + state->reptimecallback = 0.001*stimergetms(&state->timercallback, _state); + } + b = ae_false; + if( state->solvertype==0 ) + { + state->repterminationtype = state->gdemosolver.repterminationtype; + state->repiterationscount = state->gdemosolver.repiterationscount; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = state->gdemosolver.replcerr; + state->replcidx = state->gdemosolver.replcidx; + state->repnlcerr = state->gdemosolver.repnlcerr; + state->repnlcidx = state->gdemosolver.repnlcidx; + rallocv(n, &state->tmp0, _state); + rcopyrv(n, &state->gdemosolver.xbest, 0, &state->tmp0, _state); + unscalexbatchfinitebnd(&state->tmp0, 1, &state->s, n, &state->gdemosolver.finitebndl, &state->gdemosolver.finitebndu, &state->finitebndl, &state->finitebndu, &state->xf, _state); + b = ae_true; + } + ae_assert(b, "MINDF: integrity check 435259 failed", _state); + result = ae_false; + return result; +lbl_4: + + /* + * SSGD solver + */ + if( state->solvertype!=-1 ) + { + goto lbl_17; + } + ssgdinitbuf(&state->bndl, &state->bndu, &state->s, &state->x0, n, &state->densea, &state->al, &state->au, state->m, &state->nl, &state->nu, state->nnlc, state->ssgdblur0, state->ssgdblur1, state->ssgdouterits, state->ssgdrate0, state->ssgdrate1, state->ssgdmomentum, state->ssgdmaxits, state->ssgdrho, &state->ssgdsolver, _state); +lbl_19: + if( !ssgditeration(&state->ssgdsolver, state->userterminationneeded, _state) ) + { + goto lbl_20; + } + if( !state->ssgdsolver.needfi ) + { + goto lbl_21; + } + state->requesttype = 4; + state->querysize = 1; + state->queryfuncs = 1+state->nnlc; + state->queryvars = n; + state->querydim = 0; + rallocv(state->querysize*state->queryfuncs, &state->replyfi, _state); + rallocv(n, &state->querydata, _state); + mindf_unscale(state, &state->ssgdsolver.x, &state->querydata, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + rcopyv(1+state->nnlc, &state->replyfi, &state->ssgdsolver.fi, _state); + goto lbl_19; +lbl_21: + if( !state->ssgdsolver.xupdated ) + { + goto lbl_23; + } + + /* + * Report current point + */ + state->repf = state->ssgdsolver.f; + if( !state->xrep ) + { + goto lbl_25; + } + state->requesttype = -1; + mindf_unscale(state, &state->ssgdsolver.x, &state->reportx, _state); + state->reportf = state->ssgdsolver.f; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: +lbl_25: + goto lbl_19; +lbl_23: + ae_assert(ae_false, "MinDF: SSGD solver issued unexpected request", _state); + goto lbl_19; +lbl_20: + state->repterminationtype = 1; + state->repiterationscount = state->ssgdsolver.repiterationscount; + state->repbcerr = (double)(0); + state->repbcidx = 0; + state->replcerr = (double)(0); + state->replcidx = 0; + state->repnlcerr = (double)(0); + state->repnlcidx = 0; + mindf_unscale(state, &state->ssgdsolver.xcur, &state->xf, _state); + result = ae_false; + return result; +lbl_17: + ae_assert(ae_false, "MinDF: unexpected solver type", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = n; + state->rstate.ia.ptr.p_int[2] = originalrequest; + state->rstate.ba.ptr.p_bool[0] = b; + return result; +} + + +/************************************************************************* +MinDF results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + + rep.f stores objective value at the solution + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 box constraints are inconsistent + * -1 inconsistent parameters were passed: + * penalty parameter is zero, but we have nonlinear + constraints set by MinDFsetnlc2() + * 1 successful termination according to a solver-specific + set of conditions + * 8 User requested termination via minnsrequesttermination() + + If you activated timers with mindfusetimers(), you can + also find out how much time was spent in various code parts: + * rep.timetotal - for a total time in seconds + * rep.timesolver - for a time spent in the solver itself + * rep.timecallback - for a time spent in user callbacks + See comments on mindfreport structure for more information + about timers and their accuracy. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfresults(const mindfstate* state, + /* Real */ ae_vector* x, + mindfreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _mindfreport_clear(rep); + + mindfresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* + +Buffered implementation of MinDFresults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfresultsbuf(const mindfstate* state, + /* Real */ ae_vector* x, + mindfreport* rep, + ae_state *_state) +{ + + + rep->f = state->repf; + rep->iterationscount = state->repiterationscount; + rep->nfev = state->repnfunc; + rep->terminationtype = state->repterminationtype; + rep->bcerr = state->repbcerr; + rep->lcerr = state->replcerr; + rep->nlcerr = state->repnlcerr; + rep->timetotal = state->reptimetotal; + rep->timecallback = ae_minreal(state->reptimetotal, state->reptimecallback, _state); + rep->timesolver = rep->timetotal-rep->timecallback; + if( state->repterminationtype>0 ) + { + rcopyallocv(state->n, &state->xf, x, _state); + } + else + { + rsetallocv(state->n, _state->v_nan, x, _state); + } +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void mindfsetprotocolv2(mindfstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones) +*************************************************************************/ +static void mindf_unscale(const mindfstate* state, + /* Real */ const ae_vector* xs, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + xu->ptr.p_double[i] = xs->ptr.p_double[i]*state->s.ptr.p_double[i]; + } +} + + +void _mindfstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mindfstate *p = (mindfstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->densea, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + _gdemostate_init(&p->gdemosolver, _state, make_automatic); + _ssgdstate_init(&p->ssgdsolver, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timercallback, _state, make_automatic); + ae_vector_init(&p->unscaled, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->combined, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); +} + + +void _mindfstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mindfstate *dst = (mindfstate*)_dst; + const mindfstate *src = (const mindfstate*)_src; + dst->solvertype = src->solvertype; + dst->n = src->n; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_matrix_init_copy(&dst->densea, &src->densea, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + dst->m = src->m; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->hasx0 = src->hasx0; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->condfxepsf = src->condfxepsf; + dst->condfxepsx = src->condfxepsx; + dst->stoponsmallf = src->stoponsmallf; + dst->dotimers = src->dotimers; + dst->smallf = src->smallf; + dst->rngseed = src->rngseed; + dst->xrep = src->xrep; + ae_vector_init_copy(&dst->xf, &src->xf, _state, make_automatic); + dst->protocolversion = src->protocolversion; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + dst->userterminationneeded = src->userterminationneeded; + dst->gdemoprofile = src->gdemoprofile; + dst->gdemoepochscnt = src->gdemoepochscnt; + dst->gdemopopsize = src->gdemopopsize; + dst->gdemorho1 = src->gdemorho1; + dst->gdemorho2 = src->gdemorho2; + _gdemostate_init_copy(&dst->gdemosolver, &src->gdemosolver, _state, make_automatic); + dst->gdemofixedparams = src->gdemofixedparams; + dst->gdemostrategy = src->gdemostrategy; + dst->gdemocrossoverprob = src->gdemocrossoverprob; + dst->gdemodifferentialweight = src->gdemodifferentialweight; + dst->ssgdmaxits = src->ssgdmaxits; + dst->ssgdrate0 = src->ssgdrate0; + dst->ssgdrate1 = src->ssgdrate1; + dst->ssgdblur0 = src->ssgdblur0; + dst->ssgdblur1 = src->ssgdblur1; + dst->ssgdouterits = src->ssgdouterits; + dst->ssgdmomentum = src->ssgdmomentum; + dst->ssgdrho = src->ssgdrho; + _ssgdstate_init_copy(&dst->ssgdsolver, &src->ssgdsolver, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->repf = src->repf; + dst->repterminationtype = src->repterminationtype; + dst->repiterationscount = src->repiterationscount; + dst->repnfunc = src->repnfunc; + dst->repnrequests = src->repnrequests; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->reptimetotal = src->reptimetotal; + dst->reptimecallback = src->reptimecallback; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timercallback, &src->timercallback, _state, make_automatic); + ae_vector_init_copy(&dst->unscaled, &src->unscaled, _state, make_automatic); + ae_vector_init_copy(&dst->combined, &src->combined, _state, make_automatic); + dst->batchsize = src->batchsize; + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); +} + + +void _mindfstate_clear(void* _p) +{ + mindfstate *p = (mindfstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_matrix_clear(&p->densea); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->s); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->xf); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + _gdemostate_clear(&p->gdemosolver); + _ssgdstate_clear(&p->ssgdsolver); + _rcommstate_clear(&p->rstate); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timercallback); + ae_vector_clear(&p->unscaled); + ae_vector_clear(&p->combined); + ae_vector_clear(&p->tmp0); +} + + +void _mindfstate_destroy(void* _p) +{ + mindfstate *p = (mindfstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_matrix_destroy(&p->densea); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->xf); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + _gdemostate_destroy(&p->gdemosolver); + _ssgdstate_destroy(&p->ssgdsolver); + _rcommstate_destroy(&p->rstate); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timercallback); + ae_vector_destroy(&p->unscaled); + ae_vector_destroy(&p->combined); + ae_vector_destroy(&p->tmp0); +} + + +void _mindfreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mindfreport *p = (mindfreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mindfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mindfreport *dst = (mindfreport*)_dst; + const mindfreport *src = (const mindfreport*)_src; + dst->f = src->f; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->bcerr = src->bcerr; + dst->lcerr = src->lcerr; + dst->nlcerr = src->nlcerr; + dst->terminationtype = src->terminationtype; + dst->timetotal = src->timetotal; + dst->timesolver = src->timesolver; + dst->timecallback = src->timecallback; +} + + +void _mindfreport_clear(void* _p) +{ + mindfreport *p = (mindfreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _mindfreport_destroy(void* _p) +{ + mindfreport *p = (mindfreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) + + +void dsssettingsinit(dualsimplexsettings* settings, ae_state *_state) +{ + + + settings->xtolabs = 1.0E-6; + settings->dtolabs = 1.0E-6; + settings->xtolrelabs = 0.01; + settings->pivottol = (double)10*ae_sqrt(ae_machineepsilon, _state); + settings->perturbmag = (double)10*settings->pivottol; + settings->maxtrfage = reviseddualsimplex_defaultmaxtrfage; + settings->trftype = 3; + settings->ratiotest = 1; + settings->pricing = 1; + settings->shifting = 2; +} + + +/************************************************************************* +This function initializes DSS structure. Previously allocated memory is +reused as much as possible. + +Default state of the problem is zero cost vector, all variables are fixed +at zero. + + -- ALGLIB -- + Copyright 01.07.2018 by Bochkanov Sergey +*************************************************************************/ +void dssinit(ae_int_t n, dualsimplexstate* s, ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>0, "DSSInit: N<=0", _state); + s->ns = n; + s->m = 0; + rvectorgrowto(&s->rawbndl, n, _state); + rvectorgrowto(&s->rawbndu, n, _state); + for(i=0; i<=n-1; i++) + { + s->rawbndl.ptr.p_double[i] = 0.0; + s->rawbndu.ptr.p_double[i] = 0.0; + } + reviseddualsimplex_subprobleminit(n, &s->primary, _state); + reviseddualsimplex_basisinit(n, 0, &s->basis, _state); + rvectorgrowto(&s->repx, n, _state); + rvectorgrowto(&s->replagbc, n, _state); + ivectorgrowto(&s->repstats, n, _state); + for(i=0; i<=n-1; i++) + { + s->repx.ptr.p_double[i] = 0.0; + s->repstats.ptr.p_int[i] = 1; + } + s->dotrace = ae_false; + s->dodetailedtrace = ae_false; + s->dotimers = ae_false; +} + + +/************************************************************************* +This function specifies LP problem + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + + BndL - lower bounds, array[N]. + BndU - upper bounds, array[N]. + + DenseA - dense array[K,N], dense linear constraints (not supported + in present version) + SparseA - sparse linear constraints, sparsematrix[K,N] in CRS format + AKind - type of A: 0 for dense, 1 for sparse + AL, AU - lower and upper bounds, array[K] + K - number of equality/inequality constraints, K>=0. + + ProposedBasis- basis to import from (if BasisType=2) + BasisInitType- what to do with basis: + * 0 - set new basis to all-logicals + * 1 - try to reuse previous basis as much as possible + * 2 - try to import basis from ProposedBasis + Settings- algorithm settings + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void dsssetproblem(dualsimplexstate* state, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_matrix* densea, + const sparsematrix* sparsea, + ae_int_t akind, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + const dualsimplexbasis* proposedbasis, + ae_int_t basisinittype, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t jj; + ae_int_t offs; + ae_int_t ns; + ae_int_t j0; + ae_int_t j1; + ae_bool processed; + ae_int_t oldm; + ae_bool basisinitialized; + double v; + + + ns = state->primary.ns; + oldm = state->primary.m; + + /* + * Integrity checks + */ + ae_assert(bndl->cnt>=ns, "DSSSetProblem: Length(BndL)cnt>=ns, "DSSSetProblem: Length(BndU)cnt>=ns, "SubproblemSetCost: Length(C)=0, "DSSSetProblem: K<0", _state); + if( k>0&&akind==1 ) + { + ae_assert(sparsea->m==k, "DSSSetProblem: rows(A)<>K", _state); + ae_assert(sparsea->n==ns, "DSSSetProblem: cols(A)<>N", _state); + } + + /* + * Downgrade state + */ + reviseddualsimplex_downgradestate(&state->primary, reviseddualsimplex_ssinvalid, _state); + + /* + * Reallocate storage + */ + rvectorgrowto(&state->primary.bndl, ns+k, _state); + rvectorgrowto(&state->primary.bndu, ns+k, _state); + ivectorgrowto(&state->primary.bndt, ns+k, _state); + rvectorgrowto(&state->primary.rawc, ns+k, _state); + rvectorgrowto(&state->primary.effc, ns+k, _state); + rvectorgrowto(&state->primary.xa, ns+k, _state); + rvectorgrowto(&state->primary.d, ns+k, _state); + rvectorgrowto(&state->primary.xb, k, _state); + rvectorgrowto(&state->primary.bndlb, k, _state); + rvectorgrowto(&state->primary.bndub, k, _state); + ivectorgrowto(&state->primary.bndtb, k, _state); + rvectorgrowto(&state->primary.bndtollb, k, _state); + rvectorgrowto(&state->primary.bndtolub, k, _state); + + /* + * Save original problem formulation + */ + state->ns = ns; + state->m = k; + for(i=0; i<=ns-1; i++) + { + state->rawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->rawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } + + /* + * Setup cost, scale and box constraints + */ + rsetv(ns+k, 0.0, &state->primary.rawc, _state); + rsetv(ns+k, 0.0, &state->primary.effc, _state); + for(i=0; i<=ns-1; i++) + { + state->primary.rawc.ptr.p_double[i] = c->ptr.p_double[i]; + state->primary.effc.ptr.p_double[i] = c->ptr.p_double[i]; + } + for(i=0; i<=ns-1; i++) + { + ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "DSSSetProblem: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "DSSSetProblem: BndU contains NAN or -INF", _state); + state->primary.bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->primary.bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + + /* + * Set bound type + */ + if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + if( ae_fp_greater(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_ccinfeasible; + } + if( ae_fp_less(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_ccrange; + } + if( ae_fp_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_ccfixed; + } + continue; + } + if( ae_isfinite(bndl->ptr.p_double[i], _state)&&!ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_cclower; + continue; + } + if( !ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_ccupper; + continue; + } + ae_assert(ae_isneginf(bndl->ptr.p_double[i], _state)&&ae_isposinf(bndu->ptr.p_double[i], _state), "DSSSetProblem: integrity check failed", _state); + state->primary.bndt.ptr.p_int[i] = reviseddualsimplex_ccfree; + } + + /* + * Quick exit if no linear constraints is present + */ + if( k==0 ) + { + state->primary.m = 0; + reviseddualsimplex_basisinit(state->primary.ns, state->primary.m, &state->basis, _state); + return; + } + + /* + * Extend A with structural terms and transpose it: + * * allocate place for A^T extended with logical part. + * * copy with transposition + * * perform integrity check for array sizes + * * manually append new items + * * update DIdx/UIdx + */ + processed = ae_false; + state->primary.m = k; + if( akind==0 ) + { + ae_assert(ae_false, "DSSSetProblem: does not support dense inputs yet", _state); + } + if( akind==1 ) + { + + /* + * Transpose constraints matrix, apply column and row scaling. + * Extend it with identity submatrix. + * + * NOTE: in order to improve stability of LU factorization we + * normalize rows using 2-norm, not INF-norm. Having rows + * normalized with 2-norm makes every element less than + * 1.0 in magnitude, which allows us later to move logical + * columns to the beginning of LU factors without loosing + * stability. + */ + rvectorsetlengthatleast(&state->at.vals, sparsea->ridx.ptr.p_int[k]+k, _state); + ivectorsetlengthatleast(&state->at.idx, sparsea->ridx.ptr.p_int[k]+k, _state); + ivectorsetlengthatleast(&state->at.ridx, ns+k+1, _state); + ivectorsetlengthatleast(&state->at.didx, ns+k, _state); + ivectorsetlengthatleast(&state->at.uidx, ns+k, _state); + sparsecopytransposecrsbuf(sparsea, &state->at, _state); + rvectorsetlengthatleast(&state->rowscales, k, _state); + for(i=0; i<=k-1; i++) + { + state->rowscales.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=ns-1; i++) + { + j0 = state->at.ridx.ptr.p_int[i]; + j1 = state->at.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + v = state->at.vals.ptr.p_double[j]; + jj = state->at.idx.ptr.p_int[j]; + state->at.vals.ptr.p_double[j] = v; + state->rowscales.ptr.p_double[jj] = state->rowscales.ptr.p_double[jj]+v*v; + } + } + rvectorsetlengthatleast(&state->tmp0, k, _state); + for(i=0; i<=k-1; i++) + { + state->rowscales.ptr.p_double[i] = coalesce(ae_sqrt(state->rowscales.ptr.p_double[i], _state), (double)(1), _state); + state->tmp0.ptr.p_double[i] = (double)1/state->rowscales.ptr.p_double[i]; + } + for(i=0; i<=ns-1; i++) + { + j0 = state->at.ridx.ptr.p_int[i]; + j1 = state->at.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + state->at.vals.ptr.p_double[j] = state->at.vals.ptr.p_double[j]*state->tmp0.ptr.p_double[state->at.idx.ptr.p_int[j]]; + } + } + ae_assert(state->at.vals.cnt>=sparsea->ridx.ptr.p_int[k]+k, "DSSSetProblem: integrity check failed", _state); + ae_assert(state->at.idx.cnt>=sparsea->ridx.ptr.p_int[k]+k, "DSSSetProblem: integrity check failed", _state); + ae_assert(state->at.ridx.cnt>=ns+k+1, "DSSSetProblem: integrity check failed", _state); + ae_assert(state->at.didx.cnt>=ns+k, "DSSSetProblem: integrity check failed", _state); + ae_assert(state->at.uidx.cnt>=ns+k, "DSSSetProblem: integrity check failed", _state); + offs = state->at.ridx.ptr.p_int[ns]; + for(i=0; i<=k-1; i++) + { + state->at.vals.ptr.p_double[offs+i] = -1.0; + state->at.idx.ptr.p_int[offs+i] = i; + state->at.ridx.ptr.p_int[ns+i+1] = state->at.ridx.ptr.p_int[ns+i]+1; + state->at.ninitialized = state->at.ninitialized+1; + } + state->at.m = state->at.m+k; + sparseinitduidx(&state->at, _state); + sparsecopytransposecrsbuf(&state->at, &state->a, _state); + processed = ae_true; + } + ae_assert(processed, "DSSSetProblem: integrity check failed (akind)", _state); + + /* + * Copy AL, AU to BndL/BndT + */ + for(i=0; i<=k-1; i++) + { + ae_assert(ae_isfinite(al->ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "DSSSetProblem: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "DSSSetProblem: AU contains NAN or -INF", _state); + state->primary.bndl.ptr.p_double[ns+i] = al->ptr.p_double[i]/state->rowscales.ptr.p_double[i]; + state->primary.bndu.ptr.p_double[ns+i] = au->ptr.p_double[i]/state->rowscales.ptr.p_double[i]; + + /* + * Set bound type + */ + if( ae_isfinite(al->ptr.p_double[i], _state)&&ae_isfinite(au->ptr.p_double[i], _state) ) + { + if( ae_fp_greater(al->ptr.p_double[i],au->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_ccinfeasible; + } + if( ae_fp_less(al->ptr.p_double[i],au->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_ccrange; + } + if( ae_fp_eq(al->ptr.p_double[i],au->ptr.p_double[i]) ) + { + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_ccfixed; + } + continue; + } + if( ae_isfinite(al->ptr.p_double[i], _state)&&!ae_isfinite(au->ptr.p_double[i], _state) ) + { + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_cclower; + continue; + } + if( !ae_isfinite(al->ptr.p_double[i], _state)&&ae_isfinite(au->ptr.p_double[i], _state) ) + { + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_ccupper; + continue; + } + ae_assert(ae_isneginf(al->ptr.p_double[i], _state)&&ae_isposinf(au->ptr.p_double[i], _state), "DSSSetProblem: integrity check faoled", _state); + state->primary.bndt.ptr.p_int[ns+i] = reviseddualsimplex_ccfree; + } + + /* + * Depending on BasisInitType either start from all-logical basis + * or try to reuse already existing basis. + * + * NOTE: current version does not support basis shrinkage, only + * growing basis can be reused. + */ + basisinitialized = ae_false; + if( basisinittype==2 ) + { + + /* + * Import basis from one proposed by caller + */ + ae_assert(proposedbasis->ns==state->primary.ns, "DSSSetProblemX: unable to import basis, sizes do not match", _state); + ae_assert(proposedbasis->m==state->primary.m, "DSSSetProblemX: unable to import basis, sizes do not match", _state); + basisinitialized = reviseddualsimplex_basistryimportfrom(&state->basis, proposedbasis, &state->at, settings, _state); + } + if( basisinittype==1&&state->primary.m>=oldm ) + { + + /* + * New rows were added, try to reuse previous basis + */ + for(i=oldm; i<=state->primary.m-1; i++) + { + state->primary.rawc.ptr.p_double[ns+i] = 0.0; + state->primary.effc.ptr.p_double[ns+i] = 0.0; + state->primary.xa.ptr.p_double[ns+i] = 0.0; + state->primary.d.ptr.p_double[ns+i] = 0.0; + } + basisinitialized = reviseddualsimplex_basistryresize(&state->basis, state->primary.m, &state->at, settings, _state); + } + if( !basisinitialized ) + { + + /* + * Straightforward code for all-logicals basis + */ + for(i=0; i<=k-1; i++) + { + state->primary.rawc.ptr.p_double[ns+i] = 0.0; + state->primary.effc.ptr.p_double[ns+i] = 0.0; + state->primary.xa.ptr.p_double[ns+i] = 0.0; + state->primary.d.ptr.p_double[ns+i] = 0.0; + } + reviseddualsimplex_basisinit(state->primary.ns, state->primary.m, &state->basis, _state); + reviseddualsimplex_basisfreshtrf(&state->basis, &state->at, settings, _state); + } + rvectorgrowto(&state->replaglc, state->primary.m, _state); + ivectorgrowto(&state->repstats, state->primary.ns+state->primary.m, _state); +} + + +/************************************************************************* +This function exports basis from the primary (phase II) subproblem. + +INPUT PARAMETERS: + State - structure + +OUTPUT PARAMETERS + Basis - current basis exported (no factorization, only set of + basis/nonbasic variables) + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void dssexportbasis(const dualsimplexstate* state, + dualsimplexbasis* basis, + ae_state *_state) +{ + + + reviseddualsimplex_basisexportto(&state->basis, basis, _state); +} + + +/************************************************************************* +This function solves LP problem with dual simplex solver. + +INPUT PARAMETERS: + State - state + +Solution results can be found in fields of State which are explicitly +declared as accessible by external code. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void dssoptimize(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t i; + ae_int_t nx; + double v; + ae_int_t cnt1; + ae_int_t cnt2; + ae_int_t cntfx; + ae_int_t cntfr; + ae_int_t cntif; + ae_int_t ttotal; + + + nx = state->primary.ns+state->primary.m; + ttotal = 0; + + /* + * Trace settings + */ + state->dotrace = ae_is_trace_enabled("DSS"); + state->dodetailedtrace = state->dotrace&&ae_is_trace_enabled("DSS.DETAILED"); + state->dotimers = ae_is_trace_enabled("TIMERS.DSS"); + + /* + * Init report fields + */ + state->repiterationscount = 0; + state->repiterationscount1 = 0; + state->repiterationscount2 = 0; + state->repiterationscount3 = 0; + state->repterminationtype = 1; + state->repphase1time = 0; + state->repphase2time = 0; + state->repphase3time = 0; + state->repdualpricingtime = 0; + state->repdualbtrantime = 0; + state->repdualpivotrowtime = 0; + state->repdualratiotesttime = 0; + state->repdualftrantime = 0; + state->repdualupdatesteptime = 0; + state->repfillpivotrow = (double)(0); + state->repfillpivotrowcnt = 0; + state->repfillrhor = (double)(0); + state->repfillrhorcnt = 0; + state->repfilldensemu = (double)(0); + state->repfilldensemucnt = 0; + reviseddualsimplex_basisclearstats(&state->basis, _state); + + /* + * Setup timer (if needed) + */ + if( state->dotimers ) + { + ttotal = ae_tickcount(); + } + + /* + * Trace output (if needed) + */ + if( state->dotrace||state->dotimers ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// DUAL SIMPLEX SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("> problem size:\n"); + ae_trace("N = %12d (variables)\n", + (int)(state->primary.ns)); + ae_trace("M = %12d (constraints)\n", + (int)(state->primary.m)); + } + if( state->dotrace ) + { + ae_trace("> variable stats:\n"); + if( state->dodetailedtrace ) + { + } + cnt1 = 0; + cnt2 = 0; + cntfx = 0; + cntfr = 0; + cntif = 0; + for(i=0; i<=state->primary.ns-1; i++) + { + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_cclower||state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccupper ) + { + inc(&cnt1, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccrange ) + { + inc(&cnt2, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfixed ) + { + inc(&cntfx, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfree ) + { + inc(&cntfr, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccinfeasible ) + { + inc(&cntif, _state); + } + } + ae_trace("UBnd/LBnd = %12d\n", + (int)(cnt1)); + ae_trace("Range = %12d\n", + (int)(cnt2)); + ae_trace("Fixed = %12d\n", + (int)(cntfx)); + ae_trace("Free = %12d\n", + (int)(cntfr)); + ae_trace("Infeas = %12d\n", + (int)(cntif)); + ae_trace("> constraint stats:\n"); + if( state->dodetailedtrace ) + { + } + cnt1 = 0; + cnt2 = 0; + cntfx = 0; + cntfr = 0; + cntif = 0; + for(i=state->primary.ns-1; i<=nx-1; i++) + { + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_cclower||state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccupper ) + { + inc(&cnt1, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccrange ) + { + inc(&cnt2, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfixed ) + { + inc(&cntfx, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfree ) + { + inc(&cntfr, _state); + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccinfeasible ) + { + inc(&cntif, _state); + } + } + ae_trace("ubnd/lbnd = %12d\n", + (int)(cnt1)); + ae_trace("range = %12d\n", + (int)(cnt2)); + ae_trace("fixed = %12d\n", + (int)(cntfx)); + ae_trace("free = %12d\n", + (int)(cntfr)); + ae_trace("infeas = %12d\n", + (int)(cntif)); + v = (double)(0); + for(i=0; i<=state->primary.ns-1; i++) + { + if( ae_isfinite(state->primary.bndl.ptr.p_double[i], _state) ) + { + v = ae_maxreal(v, ae_fabs(state->primary.bndl.ptr.p_double[i], _state), _state); + } + } + ae_trace("|BndL| = %0.3e\n", + (double)(v)); + v = (double)(0); + for(i=0; i<=state->primary.ns-1; i++) + { + if( ae_isfinite(state->primary.bndu.ptr.p_double[i], _state) ) + { + v = ae_maxreal(v, ae_fabs(state->primary.bndu.ptr.p_double[i], _state), _state); + } + } + ae_trace("|BndU| = %0.3e\n", + (double)(v)); + v = (double)(0); + for(i=state->primary.ns; i<=nx-1; i++) + { + if( ae_isfinite(state->primary.bndl.ptr.p_double[i], _state) ) + { + v = ae_maxreal(v, ae_fabs(state->primary.bndl.ptr.p_double[i], _state), _state); + } + } + ae_trace("|AL| = %0.3e\n", + (double)(v)); + v = (double)(0); + for(i=state->primary.ns; i<=nx-1; i++) + { + if( ae_isfinite(state->primary.bndu.ptr.p_double[i], _state) ) + { + v = ae_maxreal(v, ae_fabs(state->primary.bndu.ptr.p_double[i], _state), _state); + } + } + ae_trace("|AU| = %0.3e\n", + (double)(v)); + } + + /* + * Call actual workhorse function + */ + reviseddualsimplex_dssoptimizewrk(state, settings, _state); + + /* + * Print reports + */ + if( state->dotrace ) + { + ae_trace("\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("* PRINTING ITERATION STATISTICS *\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("> iteration counts:\n"); + ae_trace("Phase 1 = %12d\n", + (int)(state->repiterationscount1)); + ae_trace("Phase 2 = %12d\n", + (int)(state->repiterationscount2)); + ae_trace("Phase 3 = %12d\n", + (int)(state->repiterationscount3)); + ae_trace("> factorization statistics:\n"); + ae_trace("FactCnt = %12d (LU factorizations)\n", + (int)(state->basis.statfact)); + ae_trace("UpdtCnt = %12d (LU updates)\n", + (int)(state->basis.statupdt)); + ae_trace("RefactPeriod= %12.1f (average refactorization interval)\n", + (double)((double)(state->basis.statfact+state->basis.statupdt)/coalesce((double)(state->basis.statfact), (double)(1), _state))); + ae_trace("LU-NZR = %12.1f (average LU nonzeros per row)\n", + (double)(state->basis.statoffdiag/(coalesce((double)(state->m), (double)(1), _state)*coalesce((double)(state->basis.statfact+state->basis.statupdt), (double)(1), _state)))); + ae_trace("> sparsity counters (average fill factors):\n"); + if( state->dodetailedtrace ) + { + ae_trace("RhoR = %12.4f (BTran result)\n", + (double)(state->repfillrhor/coalesce((double)(state->repfillrhorcnt), (double)(1), _state))); + ae_trace("AlphaR = %12.4f (pivot row)\n", + (double)(state->repfillpivotrow/coalesce((double)(state->repfillpivotrowcnt), (double)(1), _state))); + if( state->basis.trftype==3 ) + { + ae_trace("Mu = %12.4f (Forest-Tomlin factor)\n", + (double)(state->repfilldensemu/coalesce((double)(state->repfilldensemucnt), (double)(1), _state))); + } + } + else + { + ae_trace("...skipped, need DUALSIMPLEX.DETAILED trace tag\n"); + } + } + if( state->dotimers ) + { + ttotal = ae_tickcount()-ttotal; + ae_trace("\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("* PRINTING DUAL SIMPLEX TIMERS *\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("> total time:\n"); + ae_trace("Time = %12d ms\n", + (int)(ttotal)); + ae_trace("> time by phase:\n"); + ae_trace("Phase 1 = %12d ms\n", + (int)(state->repphase1time)); + ae_trace("Phase 2 = %12d ms\n", + (int)(state->repphase2time)); + ae_trace("Phase 3 = %12d ms\n", + (int)(state->repphase3time)); + ae_trace("> time by step (dual phases 1 and 2):\n"); + ae_trace("Pricing = %12d ms\n", + (int)(state->repdualpricingtime)); + ae_trace("BTran = %12d ms\n", + (int)(state->repdualbtrantime)); + ae_trace("PivotRow = %12d ms\n", + (int)(state->repdualpivotrowtime)); + ae_trace("RatioTest = %12d ms\n", + (int)(state->repdualratiotesttime)); + ae_trace("FTran = %12d ms\n", + (int)(state->repdualftrantime)); + ae_trace("Update = %12d ms\n", + (int)(state->repdualupdatesteptime)); + } +} + + +/************************************************************************* +This function initializes subproblem structure. Previously allocated memory +is reused as much as possible. + +Default state of the problem is zero cost vector, all variables are fixed +at zero, linear constraint matrix is zero. + + -- ALGLIB -- + Copyright 01.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_subprobleminit(ae_int_t n, + dualsimplexsubproblem* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(n>0, "SubproblemInit: N<=0", _state); + s->ns = n; + s->m = 0; + s->state = reviseddualsimplex_ssinvalid; + rvectorsetlengthatleast(&s->xa, n, _state); + rvectorsetlengthatleast(&s->xb, 0, _state); + rvectorsetlengthatleast(&s->d, n, _state); + rvectorsetlengthatleast(&s->rawc, n, _state); + rvectorsetlengthatleast(&s->effc, n, _state); + rvectorsetlengthatleast(&s->bndl, n, _state); + rvectorsetlengthatleast(&s->bndu, n, _state); + ivectorsetlengthatleast(&s->bndt, n, _state); + for(i=0; i<=n-1; i++) + { + s->rawc.ptr.p_double[i] = (double)(0); + s->effc.ptr.p_double[i] = (double)(0); + s->bndl.ptr.p_double[i] = (double)(0); + s->bndu.ptr.p_double[i] = (double)(0); + s->bndt.ptr.p_int[i] = reviseddualsimplex_ccfixed; + s->xa.ptr.p_double[i] = 0.0; + s->d.ptr.p_double[i] = 0.0; + } +} + + +/************************************************************************* +This function initializes phase #1 subproblem which minimizes sum of dual +infeasibilities. It is required that total count of non-boxed non-fixed +variables is at least M. + +It splits out basic components of XA[] to XB[] + + -- ALGLIB -- + Copyright 01.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_subprobleminitphase1(const dualsimplexsubproblem* s0, + const dualsimplexbasis* basis, + dualsimplexsubproblem* s1, + ae_state *_state) +{ + ae_int_t i; + + + s1->ns = s0->ns; + s1->m = s0->m; + copyrealarray(&s0->rawc, &s1->rawc, _state); + copyrealarray(&s0->effc, &s1->effc, _state); + copyrealarray(&s0->bndl, &s1->bndl, _state); + copyrealarray(&s0->bndu, &s1->bndu, _state); + copyintegerarray(&s0->bndt, &s1->bndt, _state); + copyrealarray(&s0->xa, &s1->xa, _state); + copyrealarray(&s0->xb, &s1->xb, _state); + copyrealarray(&s0->bndlb, &s1->bndlb, _state); + copyrealarray(&s0->bndub, &s1->bndub, _state); + copyintegerarray(&s0->bndtb, &s1->bndtb, _state); + copyrealarray(&s0->bndtollb, &s1->bndtollb, _state); + copyrealarray(&s0->bndtolub, &s1->bndtolub, _state); + copyrealarray(&s0->d, &s1->d, _state); + for(i=0; i<=s1->ns+s1->m-1; i++) + { + if( s1->bndt.ptr.p_int[i]==reviseddualsimplex_cclower ) + { + s1->bndt.ptr.p_int[i] = reviseddualsimplex_ccrange; + s1->bndl.ptr.p_double[i] = (double)(0); + s1->bndu.ptr.p_double[i] = (double)(1); + s1->xa.ptr.p_double[i] = (double)(0); + continue; + } + if( s1->bndt.ptr.p_int[i]==reviseddualsimplex_ccupper ) + { + s1->bndt.ptr.p_int[i] = reviseddualsimplex_ccrange; + s1->bndl.ptr.p_double[i] = (double)(-1); + s1->bndu.ptr.p_double[i] = (double)(0); + s1->xa.ptr.p_double[i] = (double)(0); + continue; + } + if( s1->bndt.ptr.p_int[i]==reviseddualsimplex_ccfree ) + { + s1->bndt.ptr.p_int[i] = reviseddualsimplex_ccrange; + s1->bndl.ptr.p_double[i] = (double)(-1); + s1->bndu.ptr.p_double[i] = (double)(1); + if( ae_fp_greater_eq(s1->effc.ptr.p_double[i],(double)(0)) ) + { + s1->xa.ptr.p_double[i] = (double)(-1); + } + else + { + s1->xa.ptr.p_double[i] = (double)(1); + } + continue; + } + s1->bndt.ptr.p_int[i] = reviseddualsimplex_ccfixed; + s1->bndl.ptr.p_double[i] = (double)(0); + s1->bndu.ptr.p_double[i] = (double)(0); + s1->xa.ptr.p_double[i] = (double)(0); + } + s1->state = reviseddualsimplex_ssvalidxn; +} + + +/************************************************************************* +This function initializes phase #3 subproblem which applies primal simplex +method to the result of the phase #2. + +It also performs modification of the subproblem in order to ensure that +initial point is primal feasible. + +NOTE: this function expects that all components (basic and nonbasic ones) + are stored in XA[] + + -- ALGLIB -- + Copyright 01.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_subprobleminitphase3(const dualsimplexsubproblem* s0, + dualsimplexsubproblem* s1, + ae_state *_state) +{ + + + s1->ns = s0->ns; + s1->m = s0->m; + copyrealarray(&s0->rawc, &s1->rawc, _state); + copyrealarray(&s0->effc, &s1->effc, _state); + copyrealarray(&s0->bndl, &s1->bndl, _state); + copyrealarray(&s0->bndu, &s1->bndu, _state); + copyintegerarray(&s0->bndt, &s1->bndt, _state); + copyrealarray(&s0->xa, &s1->xa, _state); + copyrealarray(&s0->xb, &s1->xb, _state); + copyrealarray(&s0->bndlb, &s1->bndlb, _state); + copyrealarray(&s0->bndub, &s1->bndub, _state); + copyintegerarray(&s0->bndtb, &s1->bndtb, _state); + copyrealarray(&s0->bndtollb, &s1->bndtollb, _state); + copyrealarray(&s0->bndtolub, &s1->bndtolub, _state); + copyrealarray(&s0->d, &s1->d, _state); + s1->state = reviseddualsimplex_ssvalidxn; +} + + +/************************************************************************* +This function infers nonbasic variables of X using sign of effective C[]. + +Only non-basic components of XN are changed; everything else is NOT updated. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_subprobleminferinitialxn(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ii; + ae_int_t bndt; + + + for(ii=0; ii<=s->ns-1; ii++) + { + i = state->basis.nidx.ptr.p_int[ii]; + bndt = s->bndt.ptr.p_int[i]; + if( bndt==reviseddualsimplex_ccfixed||bndt==reviseddualsimplex_ccrange ) + { + if( s->effc.ptr.p_double[i]>=(double)0 ) + { + s->xa.ptr.p_double[i] = s->bndl.ptr.p_double[i]; + } + else + { + s->xa.ptr.p_double[i] = s->bndu.ptr.p_double[i]; + } + continue; + } + if( bndt==reviseddualsimplex_cclower ) + { + s->xa.ptr.p_double[i] = s->bndl.ptr.p_double[i]; + continue; + } + if( bndt==reviseddualsimplex_ccupper ) + { + s->xa.ptr.p_double[i] = s->bndu.ptr.p_double[i]; + continue; + } + if( bndt==reviseddualsimplex_ccfree ) + { + s->xa.ptr.p_double[i] = 0.0; + continue; + } + ae_assert(ae_false, "SubproblemInferInitialXN: integrity check failed (infeasible constraint)", _state); + } + s->state = reviseddualsimplex_ssvalidxn; +} + + +/************************************************************************* +This function infers basic variables of X using values of non-basic vars +and updates reduced cost vector D and target function Z. Sets state age +to zero. + +D[] is allocated during computations. + +Temporary vectors Tmp0 and Tmp1 are used (reallocated as needed). + +NOTE: this function expects that both nonbasic and basic components are + stored in XA[]. XB[] array is not referenced. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_subproblemhandlexnupdate(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t m; + ae_int_t nn; + + + ae_assert(s->state>=reviseddualsimplex_ssvalidxn, "SubproblemHandleXNUpdate: integrity check failed (XN is not valid)", _state); + nn = s->ns; + m = s->m; + + /* + * Compute nonbasic components + */ + reviseddualsimplex_computeanxn(state, s, &s->xa, &state->tmp0, _state); + reviseddualsimplex_basissolve(&state->basis, &state->tmp0, &state->tmp1, &state->tmp2, _state); + for(i=0; i<=m-1; i++) + { + s->xa.ptr.p_double[state->basis.idx.ptr.p_int[i]] = -state->tmp1.ptr.p_double[i]; + } + + /* + * Compute D + */ + for(i=0; i<=m-1; i++) + { + state->tmp0.ptr.p_double[i] = s->effc.ptr.p_double[state->basis.idx.ptr.p_int[i]]; + } + reviseddualsimplex_basissolvet(&state->basis, &state->tmp0, &state->tmp1, &state->tmp2, _state); + reviseddualsimplex_computeantv(state, &state->tmp1, &s->d, _state); + for(i=0; i<=nn-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + s->d.ptr.p_double[j] = s->effc.ptr.p_double[j]-s->d.ptr.p_double[j]; + } + + /* + * Update state validity/age + */ + s->state = reviseddualsimplex_ssvalid; +} + + +/************************************************************************* +This function performs initial dual feasibility correction on the subproblem. +It assumes that problem state is at least ssValidXN. After call to this +function the problem state is set to ssValid. + +This function returns dual feasibility error after dual feasibility correction. + +NOTE: this function expects that both nonbasic and basic components are + stored in XA[]. XB[] array is not referenced. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static double reviseddualsimplex_initialdualfeasibilitycorrection(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector dummy; + ae_int_t nn; + ae_int_t m; + ae_int_t ii; + ae_int_t i; + ae_int_t j; + ae_bool flipped; + double v; + double dj; + double xj; + ae_int_t bndt; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&dummy, 0, sizeof(dummy)); + ae_vector_init(&dummy, 0, DT_REAL, _state, ae_true); + + nn = s->ns; + m = s->m; + ae_assert(s->state>=reviseddualsimplex_ssvalidxn, "InitialDualFeasibilityCorrection: XN is invalid", _state); + + /* + * Prepare + */ + rvectorsetlengthatleast(&state->dfctmp0, m, _state); + rvectorsetlengthatleast(&state->dfctmp1, m, _state); + + /* + * Recompute D[] using fresh factorization + */ + reviseddualsimplex_basisfreshtrf(&state->basis, &state->at, settings, _state); + for(i=0; i<=m-1; i++) + { + state->dfctmp0.ptr.p_double[i] = s->effc.ptr.p_double[state->basis.idx.ptr.p_int[i]]; + } + reviseddualsimplex_basissolvet(&state->basis, &state->dfctmp0, &state->dfctmp1, &state->dfctmp2, _state); + reviseddualsimplex_computeantv(state, &state->dfctmp1, &s->d, _state); + for(i=0; i<=nn-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + s->d.ptr.p_double[j] = s->effc.ptr.p_double[j]-s->d.ptr.p_double[j]; + } + + /* + * Perform flips for dual-infeasible boxed variables + */ + result = (double)(0); + flipped = ae_false; + for(ii=0; ii<=nn-1; ii++) + { + j = state->basis.nidx.ptr.p_int[ii]; + bndt = s->bndt.ptr.p_int[j]; + + /* + * Boxed variables, perform DFC + */ + if( bndt==reviseddualsimplex_ccrange ) + { + dj = s->d.ptr.p_double[j]; + xj = s->xa.ptr.p_double[j]; + if( xj==s->bndl.ptr.p_double[j]&&dj<(double)0 ) + { + s->xa.ptr.p_double[j] = s->bndu.ptr.p_double[j]; + flipped = ae_true; + continue; + } + if( xj==s->bndu.ptr.p_double[j]&&dj>(double)0 ) + { + s->xa.ptr.p_double[j] = s->bndl.ptr.p_double[j]; + flipped = ae_true; + continue; + } + continue; + } + + /* + * Non-boxed variables, compute dual feasibility error + */ + if( bndt==reviseddualsimplex_ccfixed ) + { + continue; + } + if( bndt==reviseddualsimplex_cclower ) + { + v = -s->d.ptr.p_double[j]; + if( v>result ) + { + result = v; + } + continue; + } + if( bndt==reviseddualsimplex_ccupper ) + { + v = s->d.ptr.p_double[j]; + if( v>result ) + { + result = v; + } + continue; + } + if( bndt==reviseddualsimplex_ccfree ) + { + result = ae_maxreal(result, ae_fabs(s->d.ptr.p_double[j], _state), _state); + continue; + } + } + + /* + * Recompute basic components of X[] + */ + if( flipped||s->statexa, &state->dfctmp0, _state); + reviseddualsimplex_basissolve(&state->basis, &state->dfctmp0, &state->dfctmp1, &state->dfctmp2, _state); + for(i=0; i<=m-1; i++) + { + s->xa.ptr.p_double[state->basis.idx.ptr.p_int[i]] = -state->dfctmp1.ptr.p_double[i]; + } + } + + /* + * Update state validity/age + */ + s->state = reviseddualsimplex_ssvalid; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +This function performs shifting using current algorithm as specified by +settings.shifting. + +It accepts following parameters: +* AlphaR - pivot row +* Delta - delta from pricing step +* Q - variable selected by ratio test +* AlphaRPiv - pivot element, Q-th element of AlphaR (because alphaR is + stored in compressed format, we can't extract it easily) +* ThetaD - dual step length + +If no shifts are necessary, it silently returns. If shifts are necessary, +it modifies ThetaD, S.D, S.EffC according to shifting algorithm. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_shifting(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* alphar, + double delta, + ae_int_t q, + double alpharpiv, + double* thetad, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t dir; + double sft; + ae_int_t ii; + ae_int_t j; + ae_int_t bndt; + + + + /* + * No shifts + */ + if( settings->shifting==0 ) + { + return; + } + if( q<0 ) + { + return; + } + + /* + * EXPAND with ThetaD=0 + */ + if( settings->shifting==1 ) + { + dir = ae_sign(delta, _state); + if( ae_fp_greater_eq(*thetad*(double)dir,(double)(0)) ) + { + return; + } + s->effc.ptr.p_double[q] = s->effc.ptr.p_double[q]-s->d.ptr.p_double[q]; + s->d.ptr.p_double[q] = (double)(0); + *thetad = (double)(0); + return; + } + + /* + * EXPAND with ThetaD=ShiftLen + */ + if( settings->shifting==2 ) + { + dir = ae_sign(delta, _state); + if( ae_fp_greater(*thetad*(double)dir,(double)(0)) ) + { + return; + } + + /* + * Ensure that non-zero step is performed + */ + *thetad = (double)dir*reviseddualsimplex_shiftlen; + + /* + * Shift Q-th coefficient + */ + sft = *thetad*((double)dir*alpharpiv)-s->d.ptr.p_double[q]; + s->effc.ptr.p_double[q] = s->effc.ptr.p_double[q]+sft; + s->d.ptr.p_double[q] = s->d.ptr.p_double[q]+sft; + + /* + * Shift other coefficients + */ + for(ii=0; ii<=alphar->k-1; ii++) + { + j = alphar->idx.ptr.p_int[ii]; + bndt = s->bndt.ptr.p_int[j]; + if( (j==q||bndt==reviseddualsimplex_ccfixed)||bndt==reviseddualsimplex_ccfree ) + { + continue; + } + sft = *thetad*((double)dir*alphar->vals.ptr.p_double[ii])-s->d.ptr.p_double[j]; + + /* + * Handle variables at lower bound + */ + if( bndt==reviseddualsimplex_cclower||(bndt==reviseddualsimplex_ccrange&&s->xa.ptr.p_double[j]==s->bndl.ptr.p_double[j]) ) + { + sft = sft-settings->dtolabs; + if( sft>(double)0 ) + { + s->effc.ptr.p_double[j] = s->effc.ptr.p_double[j]+sft; + s->d.ptr.p_double[j] = s->d.ptr.p_double[j]+sft; + } + continue; + } + if( bndt==reviseddualsimplex_ccupper||(bndt==reviseddualsimplex_ccrange&&s->xa.ptr.p_double[j]==s->bndu.ptr.p_double[j]) ) + { + sft = sft+settings->dtolabs; + if( sft<(double)0 ) + { + s->effc.ptr.p_double[j] = s->effc.ptr.p_double[j]+sft; + s->d.ptr.p_double[j] = s->d.ptr.p_double[j]+sft; + } + continue; + } + } + + /* + * Done + */ + return; + } + ae_assert(ae_false, "Shifting: unexpected shifting type", _state); +} + + +/************************************************************************* +This function performs pricing step + +Additional parameters: +* Phase1Pricing - if True, then special Phase #1 restriction is applied to + leaving variables: only those are eligible which will move to zero bound + after basis change. + + This trick allows to accelerate and stabilize phase #1. See Robert Fourer, + 'Notes on the dual simplex method', draft report, 1994, for more info. + +Returns: +* leaving variable index P +* its index R in the basis, in [0,M) range +* Delta - difference between variable value and corresponding bound + +NOTE: this function expects that basic components are stored in XB[]; + corresponding entries of XA[] are ignored. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_pricingstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_bool phase1pricing, + ae_int_t* p, + ae_int_t* r, + double* delta, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t bi; + double v; + double vtarget; + double xbi; + double bndl; + double bndu; + double vdiff; + double vtest; + double invw; + ae_int_t bndt; + ae_bool hasboth; + ae_bool hasl; + ae_bool hasu; + ae_int_t t0; + + *p = 0; + *r = 0; + *delta = 0.0; + + m = s->m; + + /* + * Integrity checks + */ + ae_assert(s->state==reviseddualsimplex_ssvalid, "PricingStep: invalid X", _state); + ae_assert(m>0, "PricingStep: M<=0", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * Pricing + */ + if( settings->pricing==0 ) + { + + /* + * "Most infeasible" pricing + */ + *p = -1; + *r = -1; + *delta = (double)(0); + vtarget = (double)(0); + for(i=0; i<=m-1; i++) + { + bndt = s->bndtb.ptr.p_int[i]; + hasboth = bndt==3||bndt==0; + hasl = hasboth||bndt==1; + hasu = hasboth||bndt==2; + xbi = s->xb.ptr.p_double[i]; + if( hasl ) + { + bndl = s->bndlb.ptr.p_double[i]; + vdiff = xbi-bndl; + v = -vdiff; + if( v>s->bndtollb.ptr.p_double[i]&&v>vtarget ) + { + + /* + * Special phase 1 pricing: do not choose variables which move to non-zero bound + */ + if( phase1pricing&&!(bndl==0.0) ) + { + continue; + } + + /* + * Proceed as usual + */ + *p = state->basis.idx.ptr.p_int[i]; + *r = i; + *delta = vdiff; + vtarget = v; + continue; + } + } + if( hasu ) + { + bndu = s->bndub.ptr.p_double[i]; + vdiff = xbi-bndu; + v = vdiff; + if( v>s->bndtolub.ptr.p_double[i]&&v>vtarget ) + { + + /* + * Special phase 1 pricing: do not choose variables which move to non-zero bound + */ + if( phase1pricing&&!(bndu==0.0) ) + { + continue; + } + + /* + * Proceed as usual + */ + *p = state->basis.idx.ptr.p_int[i]; + *r = i; + *delta = vdiff; + vtarget = v; + continue; + } + } + } + + /* + * Trace/profile + */ + if( state->dotrace ) + { + ae_trace("> pricing: most infeasible variable removed\n"); + ae_trace("P = %12d (R=%0d)\n", + (int)(*p), + (int)(*r)); + ae_trace("Delta = %12.3e\n", + (double)(*delta)); + } + if( state->dotimers ) + { + state->repdualpricingtime = state->repdualpricingtime+(ae_tickcount()-t0); + } + + /* + * Done + */ + return; + } + if( settings->pricing==-1||settings->pricing==1 ) + { + + /* + * Dual steepest edge pricing + */ + reviseddualsimplex_basisrequestweights(&state->basis, settings, _state); + *p = -1; + *r = -1; + *delta = (double)(0); + vtarget = (double)(0); + for(i=0; i<=m-1; i++) + { + bi = state->basis.idx.ptr.p_int[i]; + bndt = s->bndtb.ptr.p_int[i]; + hasboth = bndt==3||bndt==0; + hasl = hasboth||bndt==1; + hasu = hasboth||bndt==2; + xbi = s->xb.ptr.p_double[i]; + invw = (double)1/state->basis.dseweights.ptr.p_double[i]; + if( hasl ) + { + bndl = s->bndlb.ptr.p_double[i]; + vdiff = xbi-bndl; + vtest = vdiff*vdiff*invw; + if( vdiff<-s->bndtollb.ptr.p_double[i]&&(*p<0||vtest>vtarget) ) + { + + /* + * Special phase 1 pricing: do not choose variables which move to non-zero bound + */ + if( phase1pricing&&!(bndl==0.0) ) + { + continue; + } + + /* + * Proceed as usual + */ + *p = bi; + *r = i; + *delta = vdiff; + vtarget = vtest; + continue; + } + } + if( hasu ) + { + bndu = s->bndub.ptr.p_double[i]; + vdiff = xbi-bndu; + vtest = vdiff*vdiff*invw; + if( vdiff>s->bndtolub.ptr.p_double[i]&&(*p<0||vtest>vtarget) ) + { + + /* + * Special phase 1 pricing: do not choose variables which move to non-zero bound + */ + if( phase1pricing&&!(bndu==0.0) ) + { + continue; + } + + /* + * Proceed as usual + */ + *p = bi; + *r = i; + *delta = vdiff; + vtarget = vtest; + continue; + } + } + } + + /* + * Trace/profile + */ + if( state->dotrace ) + { + ae_trace("> dual steepest edge pricing: leaving variable found\n"); + ae_trace("P = %12d (variable index)\n", + (int)(*p)); + ae_trace("R = %12d (variable index in basis)\n", + (int)(*r)); + ae_trace("Delta = %12.3e (primal infeasibility removed)\n", + (double)(*delta)); + } + if( state->dotimers ) + { + state->repdualpricingtime = state->repdualpricingtime+(ae_tickcount()-t0); + } + + /* + * Done + */ + return; + } + ae_assert(ae_false, "PricingStep: unknown pricing type", _state); +} + + +/************************************************************************* +This function performs BTran step + +Accepts: +* R, index of the leaving variable in the basis, in [0,M) range + +Returns: +* RhoR, array[M], BTran result + + -- ALGLIB -- + Copyright 19.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_btranstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_int_t r, + dssvector* rhor, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t t0; + + + m = s->m; + + /* + * Integrity checks + */ + ae_assert(m>0, "BTranStep: M<=0", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * BTran + */ + rvectorsetlengthatleast(&state->btrantmp0, m, _state); + rvectorsetlengthatleast(&state->btrantmp1, m, _state); + rvectorsetlengthatleast(&state->btrantmp2, m, _state); + for(i=0; i<=m-1; i++) + { + state->btrantmp0.ptr.p_double[i] = (double)(0); + } + state->btrantmp0.ptr.p_double[r] = (double)(1); + reviseddualsimplex_dvalloc(rhor, m, _state); + reviseddualsimplex_basissolvet(&state->basis, &state->btrantmp0, &rhor->dense, &state->btrantmp1, _state); + reviseddualsimplex_dvdensetosparse(rhor, _state); + + /* + * Timers + */ + if( state->dotimers ) + { + state->repdualbtrantime = state->repdualbtrantime+(ae_tickcount()-t0); + } +} + + +/************************************************************************* +This function performs PivotRow step + +Accepts: +* RhoR, BTRan result + +Returns: +* AlphaR, array[N+M], pivot row + + -- ALGLIB -- + Copyright 19.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_pivotrowstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* rhor, + dssvector* alphar, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t ns; + ae_int_t nx; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t alphark; + double v; + ae_int_t t0; + double avgcolwise; + double avgrowwise; + + + m = s->m; + ns = s->ns; + nx = s->ns+s->m; + + /* + * Integrity checks + */ + ae_assert(m>0, "BTranStep: M<=0", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * Determine operation counts for columnwise and rowwise approaches + */ + avgrowwise = (double)rhor->k*((double)state->at.ridx.ptr.p_int[nx]/(double)m); + avgcolwise = (double)ns*((double)state->at.ridx.ptr.p_int[nx]/(double)nx); + + /* + * Pivot row + */ + if( ae_fp_less(avgrowwise,avgcolwise) ) + { + + /* + * Use rowwise algorithm + */ + reviseddualsimplex_dvinit(alphar, nx, _state); + for(i=0; i<=rhor->k-1; i++) + { + k = rhor->idx.ptr.p_int[i]; + v = rhor->vals.ptr.p_double[i]; + j0 = state->a.ridx.ptr.p_int[k]; + j1 = state->a.ridx.ptr.p_int[k+1]-1; + for(j=j0; j<=j1; j++) + { + jj = state->a.idx.ptr.p_int[j]; + alphar->dense.ptr.p_double[jj] = alphar->dense.ptr.p_double[jj]+v*state->a.vals.ptr.p_double[j]; + } + } + alphark = 0; + for(i=0; i<=nx-1; i++) + { + if( !state->basis.isbasic.ptr.p_bool[i] ) + { + + /* + * Fetch nonbasic nonzeros to sparse part + */ + v = alphar->dense.ptr.p_double[i]; + if( v!=0.0 ) + { + alphar->idx.ptr.p_int[alphark] = i; + alphar->vals.ptr.p_double[alphark] = v; + alphark = alphark+1; + } + } + else + { + + /* + * Enforce condition that basic elements of AlphaR are exactly zero + */ + alphar->dense.ptr.p_double[i] = (double)(0); + } + } + alphar->k = alphark; + } + else + { + + /* + * Use colwise algorithm + */ + reviseddualsimplex_dvalloc(alphar, nx, _state); + alphark = 0; + for(i=0; i<=ns-1; i++) + { + k = state->basis.nidx.ptr.p_int[i]; + j0 = state->at.ridx.ptr.p_int[k]; + j1 = state->at.ridx.ptr.p_int[k+1]-1; + v = (double)(0); + for(j=j0; j<=j1; j++) + { + v = v+state->at.vals.ptr.p_double[j]*rhor->dense.ptr.p_double[state->at.idx.ptr.p_int[j]]; + } + if( v!=0.0 ) + { + alphar->idx.ptr.p_int[alphark] = k; + alphar->vals.ptr.p_double[alphark] = v; + alphark = alphark+1; + } + } + alphar->k = alphark; + reviseddualsimplex_dvsparsetodense(alphar, _state); + } + + /* + * Timers and tracing + */ + if( state->dodetailedtrace ) + { + reviseddualsimplex_updateavgcounter((double)rhor->k/coalesce((double)(rhor->n), (double)(1), _state), &state->repfillrhor, &state->repfillrhorcnt, _state); + reviseddualsimplex_updateavgcounter((double)alphar->k/coalesce((double)(alphar->n), (double)(1), _state), &state->repfillpivotrow, &state->repfillpivotrowcnt, _state); + } + if( state->dotimers ) + { + state->repdualpivotrowtime = state->repdualpivotrowtime+(ae_tickcount()-t0); + } +} + + +/************************************************************************* +This function performs FTran step + +Accepts: +* RhoR, array[M] +* Q, index of the entering variable, in [0,NX) range + +Returns: +* AlphaQ, array[M], FTran result +* AlphaQim, array[M], intermediate FTran result used by Forest-Tomlin update +* Tau, array[M], used to compute DSE temporaries + + -- ALGLIB -- + Copyright 19.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_ftranstep(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* rhor, + ae_int_t q, + /* Real */ ae_vector* alphaq, + /* Real */ ae_vector* alphaqim, + /* Real */ ae_vector* tau, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + ae_int_t t0; + + + m = s->m; + + /* + * Integrity checks + */ + ae_assert(m>0, "BTranStep: M<=0", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * FTran + */ + rvectorsetlengthatleast(&state->ftrantmp0, m, _state); + for(i=0; i<=m-1; i++) + { + state->ftrantmp0.ptr.p_double[i] = (double)(0); + } + j0 = state->at.ridx.ptr.p_int[q]; + j1 = state->at.ridx.ptr.p_int[q+1]-1; + for(j=j0; j<=j1; j++) + { + state->ftrantmp0.ptr.p_double[state->at.idx.ptr.p_int[j]] = state->at.vals.ptr.p_double[j]; + } + reviseddualsimplex_basissolvex(&state->basis, &state->ftrantmp0, alphaq, alphaqim, ae_true, &state->ftrantmp1, _state); + ae_assert((settings->pricing==-1||settings->pricing==0)||settings->pricing==1, "FTran: unexpected Settings.Pricing", _state); + if( settings->pricing==1 ) + { + reviseddualsimplex_basissolve(&state->basis, &rhor->dense, tau, &state->ftrantmp1, _state); + } + + /* + * Timers + */ + if( state->dotimers ) + { + state->repdualftrantime = state->repdualftrantime+(ae_tickcount()-t0); + } +} + + +/************************************************************************* +This function performs ratio test, either simple one or BFRT. + +It accepts following parameters: +* AlphaR - pivot row +* Delta - delta from pricing step +* P - index of leaving variable from pricing step + +It returns following results: +* Q - non-negative value for success, negative for primal infeasible problem +* AlphaRPiv - AlphaR[Q] (due to AlphaR being stored in sparse format this + value is difficult to extract by index Q). +* ThetaD - dual step length +* PossibleFlips[PossibleFlipsCnt] - for possible flip indexes (for BFRT + this set coincides with actual flips, but stabilizing BFRT is a bit more + complex - some variables in PossibleFlips[] may need flipping and some not) + +Internally it uses following fields of State for temporaries: +* EligibleAlphaR + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_ratiotest(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dssvector* alphar, + double delta, + ae_int_t p, + ae_int_t* q, + double* alpharpiv, + double* thetad, + /* Integer */ ae_vector* possibleflips, + ae_int_t* possibleflipscnt, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t j; + ae_int_t nj; + ae_int_t dir; + double vx; + double vp; + ae_int_t ej; + double alpharej; + double vtarget; + double vtest; + ae_int_t eligiblecnt; + ae_int_t originaleligiblecnt; + ae_int_t bndt; + double alphawaver; + double adelta; + ae_int_t idx; + double vtheta; + ae_int_t t0; + + *q = 0; + *alpharpiv = 0.0; + *thetad = 0.0; + + nx = s->ns+s->m; + ae_assert(ae_fp_neq(delta,(double)(0)), "RatioTest: zero delta", _state); + ae_assert(s->state==reviseddualsimplex_ssvalid, "RatioTest: invalid X", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * Clear output + */ + *q = -1; + *alpharpiv = (double)(0); + *thetad = (double)(0); + *possibleflipscnt = 0; + + /* + * Prepare temporaries + * + * Scaled tolerances are used to test AlphaWaveR for positivity/negativity, + * scale of I-th tolerance is calculated as ratio of ColScale[I] and ColScale[P]. + */ + dir = ae_sign(delta, _state); + ivectorsetlengthatleast(possibleflips, nx, _state); + + /* + * Prepare set of eligible variables + * + * NOTE: free variables are immediately chosen at this stage + */ + ivectorsetlengthatleast(&state->eligiblealphar, alphar->k, _state); + eligiblecnt = 0; + for(j=0; j<=alphar->k-1; j++) + { + nj = alphar->idx.ptr.p_int[j]; + bndt = s->bndt.ptr.p_int[nj]; + + /* + * Handle fixed and free variables: fixed ones are not eligible, + * free non-basic variables are always and immediately eligible + */ + if( bndt==reviseddualsimplex_ccfixed ) + { + continue; + } + if( bndt==reviseddualsimplex_ccfree ) + { + *q = nj; + *thetad = (double)(0); + *alpharpiv = alphar->vals.ptr.p_double[j]; + if( state->dotrace ) + { + ae_trace("> ratio test: quick exit, found free nonbasic variable\n"); + ae_trace("Q = %12d (variable selected)\n", + (int)(*q)); + ae_trace("ThetaD = %12.3e (dual step length)\n", + (double)(*thetad)); + } + if( state->dotimers ) + { + state->repdualratiotesttime = state->repdualratiotesttime+(ae_tickcount()-t0); + } + return; + } + + /* + * Handle lower/upper/range constraints + */ + vx = s->xa.ptr.p_double[nj]; + vp = settings->pivottol; + alphawaver = (double)dir*alphar->vals.ptr.p_double[j]; + if( bndt==reviseddualsimplex_cclower||(bndt==reviseddualsimplex_ccrange&&vx==s->bndl.ptr.p_double[nj]) ) + { + if( alphawaver>vp ) + { + state->eligiblealphar.ptr.p_int[eligiblecnt] = j; + eligiblecnt = eligiblecnt+1; + continue; + } + } + if( bndt==reviseddualsimplex_ccupper||(bndt==reviseddualsimplex_ccrange&&vx==s->bndu.ptr.p_double[nj]) ) + { + if( alphawaver<-vp ) + { + state->eligiblealphar.ptr.p_int[eligiblecnt] = j; + eligiblecnt = eligiblecnt+1; + continue; + } + } + } + originaleligiblecnt = eligiblecnt; + + /* + * Simple ratio test. + */ + if( settings->ratiotest==0 ) + { + + /* + * Ratio test + */ + vtarget = (double)(0); + for(j=0; j<=eligiblecnt-1; j++) + { + ej = state->eligiblealphar.ptr.p_int[j]; + nj = alphar->idx.ptr.p_int[ej]; + alpharej = alphar->vals.ptr.p_double[ej]; + + /* + * More general case + */ + alphawaver = (double)dir*alpharej; + vtest = s->d.ptr.p_double[nj]/alphawaver; + if( *q<0||vtestd.ptr.p_double[nj]/alpharej; + } + } + reviseddualsimplex_shifting(state, s, alphar, delta, *q, *alpharpiv, thetad, settings, _state); + + /* + * Trace + */ + if( state->dotrace ) + { + ae_trace("> dual ratio test:\n"); + ae_trace("|E| = %12d (eligible set size)\n", + (int)(originaleligiblecnt)); + ae_trace("Q = %12d (variable selected)\n", + (int)(*q)); + ae_trace("ThetaD = %12.3e (dual step length)\n", + (double)(*thetad)); + } + if( state->dotimers ) + { + state->repdualratiotesttime = state->repdualratiotesttime+(ae_tickcount()-t0); + } + + /* + * Done + */ + return; + } + + /* + * Bounds flipping ratio test + */ + if( settings->ratiotest==1 ) + { + adelta = ae_fabs(delta, _state); + + /* + * Quick exit + */ + if( eligiblecnt==0 ) + { + if( state->dotrace ) + { + ae_trace("> ratio test: quick exit, no eligible variables\n"); + } + return; + } + + /* + * BFRT + */ + while(eligiblecnt>0) + { + + /* + * Find Q satisfying BFRT criteria + */ + idx = -1; + *q = -1; + *alpharpiv = (double)(0); + vtarget = (double)(0); + for(j=0; j<=eligiblecnt-1; j++) + { + ej = state->eligiblealphar.ptr.p_int[j]; + nj = alphar->idx.ptr.p_int[ej]; + alpharej = alphar->vals.ptr.p_double[ej]; + vtheta = s->d.ptr.p_double[nj]/alpharej; + vtest = (double)dir*vtheta; + if( *q<0||vtest=0, "RatioTest: integrity check failed (BFRT)", _state); + + /* + * BFRT mini-iterations will be terminated upon discovery + * of non-boxed variable or upon exhausting of eligible set. + */ + if( s->bndt.ptr.p_int[*q]!=reviseddualsimplex_ccrange ) + { + break; + } + if( eligiblecnt==1 ) + { + break; + } + + /* + * Update and test ADelta. Break BFRT mini-iterations once + * we get negative slope. + */ + adelta = adelta-(s->bndu.ptr.p_double[*q]-s->bndl.ptr.p_double[*q])*ae_fabs(*alpharpiv, _state); + if( ae_fp_less_eq(adelta,(double)(0)) ) + { + break; + } + + /* + * Update eligible set, record flip + */ + possibleflips->ptr.p_int[*possibleflipscnt] = state->eligiblealphar.ptr.p_int[idx]; + *possibleflipscnt = *possibleflipscnt+1; + state->eligiblealphar.ptr.p_int[idx] = state->eligiblealphar.ptr.p_int[eligiblecnt-1]; + eligiblecnt = eligiblecnt-1; + } + ae_assert(*q>=0, "RatioTest: unexpected failure", _state); + *thetad = s->d.ptr.p_double[*q]/(*alpharpiv); + reviseddualsimplex_shifting(state, s, alphar, delta, *q, *alpharpiv, thetad, settings, _state); + + /* + * Trace + */ + if( state->dotrace ) + { + ae_trace("> dual bounds flipping ratio test:\n"); + ae_trace("|E| = %12d (eligible set size)\n", + (int)(originaleligiblecnt)); + ae_trace("Q = %12d (variable selected)\n", + (int)(*q)); + ae_trace("ThetaD = %12.3e (dual step length)\n", + (double)(*thetad)); + ae_trace("Flips = %12d (possible bound flips)\n", + (int)(state->possibleflipscnt)); + } + if( state->dotimers ) + { + state->repdualratiotesttime = state->repdualratiotesttime+(ae_tickcount()-t0); + } + + /* + * Done + */ + return; + } + + /* + * Unknown test type + */ + ae_assert(ae_false, "RatioTest: integrity check failed, unknown test type", _state); +} + + +/************************************************************************* +This function performs update of XB, XN, D and Z during final step of revised +dual simplex method. + +It also updates basis cache of the subproblem (s.bcache field). + +Depending on Settings.RatioTest, following operations are performed: +* Settings.RatioTest=0 -> simple update is performed +* Settings.RatioTest=1 -> bounds flipping ratio test update is performed +* Settings.RatioTest=2 -> stabilizing bounds flipping ratio test update is performed + +It accepts following parameters: +* P - index of leaving variable from pricing step +* Q - index of entering variable. +* R - index of leaving variable in AlphaQ +* Delta - delta from pricing step +* AlphaPiv - pivot element (in absence of numerical rounding it is AlphaR[Q]=AlphaQ[R]) +* ThetaP - primal step length +* ThetaD - dual step length +* AlphaQ - pivot column +* AlphaQim - intermediate result from Ftran for AlphaQ, used for + Forest-Tomlin update, not referenced when other update scheme is set +* AlphaR - pivot row +* Tau - tau-vector for DSE pricing (ignored if simple pricing is used) +* PossibleAlphaRFlips, PossibleAlphaRFlipsCnt - outputs of the RatioTest() + information about possible variable flips - indexes of AlphaR positions + which are considered for flipping due to BFRT (however, we have to check + residual costs before actually flipping variables - it is possible that some variables + in this set actually do not need flipping) + +It performs following operations: +* basis update +* update of XB/BndTB/BndLB/BndUB[] and XA[] (basic and nonbasic components), D +* update of pricing weights + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_updatestep(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_int_t p, + ae_int_t q, + ae_int_t r, + double delta, + double alphapiv, + double thetap, + double thetad, + /* Real */ const ae_vector* alphaq, + /* Real */ const ae_vector* alphaqim, + const dssvector* alphar, + /* Real */ const ae_vector* tau, + /* Integer */ const ae_vector* possiblealpharflips, + ae_int_t possiblealpharflipscnt, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t m; + ae_int_t ii; + ae_int_t j; + ae_int_t k; + ae_int_t aj; + ae_int_t k0; + ae_int_t k1; + double bndl; + double bndu; + ae_bool flipped; + double flip; + double dj; + ae_int_t dir; + ae_int_t idx; + ae_int_t actualflipscnt; + ae_int_t t0; + ae_int_t alpharlen; + + + nx = s->ns+s->m; + m = s->m; + + /* + * Integrity checks + */ + ae_assert((settings->ratiotest==0||settings->ratiotest==1)||settings->ratiotest==2, "UpdateStep: invalid X", _state); + ae_assert(s->state==reviseddualsimplex_ssvalid, "UpdateStep: invalid X", _state); + ae_assert(p>=0&&q>=0, "UpdateStep: invalid P/Q", _state); + ae_assert(ae_fp_neq(delta,(double)(0)), "UpdateStep: Delta=0", _state); + ae_assert(ae_fp_neq(alphapiv,(double)(0)), "UpdateStep: AlphaPiv=0", _state); + + /* + * Timers + */ + t0 = 0; + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + + /* + * Prepare + */ + dir = ae_sign(delta, _state); + alpharlen = alphar->k; + flip = (double)(0); + rvectorsetlengthatleast(&state->tmp0, m, _state); + for(k=0; k<=m-1; k++) + { + state->tmp0.ptr.p_double[k] = (double)(0); + } + ivectorsetlengthatleast(&state->ustmpi, nx, _state); + actualflipscnt = 0; + + /* + * Evaluate and update non-basic elements of D + */ + for(ii=0; ii<=alpharlen-1; ii++) + { + j = alphar->idx.ptr.p_int[ii]; + s->d.ptr.p_double[j] = s->d.ptr.p_double[j]-thetad*alphar->vals.ptr.p_double[ii]; + } + for(ii=0; ii<=possiblealpharflipscnt-1; ii++) + { + aj = possiblealpharflips->ptr.p_int[ii]; + j = alphar->idx.ptr.p_int[aj]; + dj = s->d.ptr.p_double[j]; + bndl = s->bndl.ptr.p_double[j]; + bndu = s->bndu.ptr.p_double[j]; + flipped = ae_false; + if( s->xa.ptr.p_double[j]==bndl&&dj<(double)0 ) + { + flip = bndu-bndl; + flipped = ae_true; + } + else + { + if( s->xa.ptr.p_double[j]==bndu&&dj>(double)0 ) + { + flip = bndl-bndu; + flipped = ae_true; + } + } + if( flipped ) + { + delta = delta-(double)dir*(bndu-bndl)*ae_fabs(alphar->vals.ptr.p_double[aj], _state); + state->ustmpi.ptr.p_int[actualflipscnt] = j; + actualflipscnt = actualflipscnt+1; + k0 = state->at.ridx.ptr.p_int[j]; + k1 = state->at.ridx.ptr.p_int[j+1]-1; + for(k=k0; k<=k1; k++) + { + idx = state->at.idx.ptr.p_int[k]; + state->tmp0.ptr.p_double[idx] = state->tmp0.ptr.p_double[idx]+flip*state->at.vals.ptr.p_double[k]; + } + } + } + s->d.ptr.p_double[p] = -thetad; + s->d.ptr.p_double[q] = 0.0; + + /* + * Apply BFRT update (aka long dual step) or simple ratio update + */ + if( actualflipscnt>0 ) + { + thetap = delta/alphapiv; + k0 = state->at.ridx.ptr.p_int[q]; + k1 = state->at.ridx.ptr.p_int[q+1]-1; + for(k=k0; k<=k1; k++) + { + idx = state->at.idx.ptr.p_int[k]; + state->tmp0.ptr.p_double[idx] = state->tmp0.ptr.p_double[idx]+thetap*state->at.vals.ptr.p_double[k]; + } + reviseddualsimplex_basissolve(&state->basis, &state->tmp0, &state->tmp1, &state->tmp2, _state); + for(j=0; j<=m-1; j++) + { + s->xb.ptr.p_double[j] = s->xb.ptr.p_double[j]-state->tmp1.ptr.p_double[j]; + } + for(ii=0; ii<=actualflipscnt-1; ii++) + { + j = state->ustmpi.ptr.p_int[ii]; + if( s->xa.ptr.p_double[j]==s->bndl.ptr.p_double[j] ) + { + s->xa.ptr.p_double[j] = s->bndu.ptr.p_double[j]; + } + else + { + s->xa.ptr.p_double[j] = s->bndl.ptr.p_double[j]; + } + } + s->xb.ptr.p_double[r] = s->xa.ptr.p_double[q]+thetap; + if( dir<0 ) + { + s->xa.ptr.p_double[p] = s->bndl.ptr.p_double[p]; + } + else + { + s->xa.ptr.p_double[p] = s->bndu.ptr.p_double[p]; + } + } + else + { + for(j=0; j<=m-1; j++) + { + s->xb.ptr.p_double[j] = s->xb.ptr.p_double[j]-thetap*alphaq->ptr.p_double[j]; + } + s->xb.ptr.p_double[r] = s->xa.ptr.p_double[q]+thetap; + if( dir<0 ) + { + s->xa.ptr.p_double[p] = s->bndl.ptr.p_double[p]; + } + else + { + s->xa.ptr.p_double[p] = s->bndu.ptr.p_double[p]; + } + } + + /* + * Update basis + */ + reviseddualsimplex_basisupdatetrf(&state->basis, &state->at, p, q, alphaq, alphaqim, r, tau, settings, _state); + + /* + * Update cached variables + */ + reviseddualsimplex_cacheboundinfo(s, r, q, settings, _state); + + /* + * Tracing and timers + */ + if( state->dodetailedtrace ) + { + if( state->basis.trftype==3 ) + { + reviseddualsimplex_updateavgcounter(reviseddualsimplex_sparsityof(&state->basis.densemu, state->basis.trfage*m, _state), &state->repfilldensemu, &state->repfilldensemucnt, _state); + } + } + if( state->dotimers ) + { + state->repdualupdatesteptime = state->repdualupdatesteptime+(ae_tickcount()-t0); + } +} + + +/************************************************************************* +This function performs several checks for accumulation of errors during +factorization update. It returns True if refactorization is advised. + + -- ALGLIB -- + Copyright 24.01.2019 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_refactorizationrequired(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + ae_int_t q, + double alpharpiv, + ae_int_t r, + double alphaqpiv, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + double mx; + double v; + ae_bool result; + + + m = s->m; + result = ae_false; + + /* + * Quick exit + */ + if( state->basis.trfage<=reviseddualsimplex_safetrfage ) + { + return result; + } + + /* + * Compare Q-th entry of the pivot row AlphaR with R-th entry of the AlphaQ; + * ideally, both should match exactly. The difference is a rough estimate + * of the magnitude of the numerical errors. + */ + mx = 0.0; + for(i=0; i<=m-1; i++) + { + v = state->alphaq.ptr.p_double[i]; + v = v*v; + if( v>mx ) + { + mx = v; + } + } + mx = ae_sqrt(mx, _state); + result = result||ae_fp_greater(ae_fabs(alphaqpiv-alpharpiv, _state),reviseddualsimplex_alphatrigger*(1.0+mx)); + result = result||ae_fp_greater(ae_fabs(alphaqpiv-alpharpiv, _state),reviseddualsimplex_alphatrigger2*ae_fabs(alpharpiv, _state)); + return result; +} + + +/************************************************************************* +This function caches information for I-th column of the basis, which is +assumed to store variable K: +* lower bound in S.BndLB[I]=S.BndL[K] +* upper bound in S.BndUB[I]=S.BndU[K] +* bound type in S.BndTB[I]=S.BndT[K] +* lower bound primal error tolerance in S.BndTolLB[I] (nonnegative) +* upper bound primal error tolerance in S.BndTolLB[I] (nonnegative). + + -- ALGLIB -- + Copyright 18.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_cacheboundinfo(dualsimplexsubproblem* s, + ae_int_t i, + ae_int_t k, + const dualsimplexsettings* settings, + ae_state *_state) +{ + + + s->bndlb.ptr.p_double[i] = s->bndl.ptr.p_double[k]; + s->bndub.ptr.p_double[i] = s->bndu.ptr.p_double[k]; + s->bndtb.ptr.p_int[i] = s->bndt.ptr.p_int[k]; + s->bndtollb.ptr.p_double[i] = settings->xtolabs+settings->xtolrelabs*settings->xtolabs*ae_fabs(s->bndlb.ptr.p_double[i], _state); + s->bndtolub.ptr.p_double[i] = settings->xtolabs+settings->xtolrelabs*settings->xtolabs*ae_fabs(s->bndub.ptr.p_double[i], _state); +} + + +/************************************************************************* +This function performs actual solution of dual simplex subproblem (either +primary one or phase 1 one). + +A problem with following properties is expected: +* M>0 +* feasible box constraints +* dual feasible initial basis +* actual initial point XC and target value Z +* actual reduced cost vector D +* pricing weights being set to 1.0 or copied from previous problem + +Returns: + * Info = +1 for success, -3 for infeasible + * IterationsCount is increased by amount of iterations performed + +NOTE: this function internally uses separate storage of basic and nonbasic + components; however, all inputs and outputs use single array S.XA[] + to store both basic and nonbasic variables. It transparently splits + variables on input and recombines them on output. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_solvesubproblemdual(dualsimplexstate* state, + dualsimplexsubproblem* s, + ae_bool isphase1, + const dualsimplexsettings* settings, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t nx; + ae_int_t m; + ae_int_t i; + ae_int_t p; + ae_int_t r; + ae_int_t q; + double alpharpiv; + double alphaqpiv; + double thetad; + double thetap; + double delta; + ae_int_t forcedrestarts; + + *info = 0; + + nx = s->ns+s->m; + m = s->m; + forcedrestarts = 0; + + /* + * Integrity checks + */ + ae_assert(s->state==reviseddualsimplex_ssvalid, "SolveSubproblemDual: X is not valid", _state); + ae_assert(m>0, "SolveSubproblemDual: M<=0", _state); + for(i=0; i<=nx-1; i++) + { + ae_assert(s->bndt.ptr.p_int[i]!=reviseddualsimplex_ccinfeasible, "SolveSubproblemDual: infeasible box constraints", _state); + } + ae_assert(reviseddualsimplex_isdualfeasible(state, s, settings, _state), "SolveSubproblemDual: dual infeasible initial basis", _state); + + /* + * Actual processing + */ + reviseddualsimplex_offloadbasiccomponents(s, &state->basis, settings, _state); + *info = 0; + rvectorsetlengthatleast(&state->tmp0, m, _state); + for(;;) + { + + /* + * Iteration report + */ + if( state->dotrace ) + { + i = state->repiterationscount2; + if( isphase1 ) + { + i = state->repiterationscount1; + } + ae_trace("=== ITERATION %5d STARTED ========================================================================\n", + (int)(i)); + if( state->dodetailedtrace ) + { + } + } + + /* + * Pricing + */ + reviseddualsimplex_pricingstep(state, s, isphase1, &p, &r, &delta, settings, _state); + if( ae_fp_eq(delta,(double)(0)) ) + { + + /* + * Solved! Feasible and bounded! + */ + if( state->dotrace ) + { + ae_trace("> pricing: feasible point found\n"); + } + reviseddualsimplex_recombinebasicnonbasicx(s, &state->basis, _state); + *info = 1; + return; + } + + /* + * BTran + */ + reviseddualsimplex_btranstep(state, s, r, &state->rhor, settings, _state); + + /* + * Pivot row + */ + reviseddualsimplex_pivotrowstep(state, s, &state->rhor, &state->alphar, settings, _state); + + /* + * Ratio test + */ + reviseddualsimplex_ratiotest(state, s, &state->alphar, delta, p, &q, &alpharpiv, &thetad, &state->possibleflips, &state->possibleflipscnt, settings, _state); + if( q<0 ) + { + + /* + * Do we have fresh factorization and state? If not, + * refresh them prior to declaring that we have no solution. + */ + if( state->basis.trfage>0&&forcedrestartsdotrace ) + { + ae_trace("> ratio test: failed, basis is old (age=%0d), forcing restart (%0d of %0d)\n", + (int)(state->basis.trfage), + (int)(forcedrestarts), + (int)(reviseddualsimplex_maxforcedrestarts-1)); + } + reviseddualsimplex_basisfreshtrf(&state->basis, &state->at, settings, _state); + reviseddualsimplex_subproblemhandlexnupdate(state, s, _state); + reviseddualsimplex_offloadbasiccomponents(s, &state->basis, settings, _state); + inc(&forcedrestarts, _state); + continue; + } + + /* + * Dual unbounded, primal infeasible + */ + if( state->dotrace ) + { + ae_trace("> ratio test: failed, results are accepted\n"); + } + reviseddualsimplex_recombinebasicnonbasicx(s, &state->basis, _state); + *info = -3; + return; + } + thetap = delta/alpharpiv; + + /* + * FTran, including additional FTran for DSE weights (if needed) + * + * NOTE: AlphaQim is filled by intermediate FTran result which is useful + * for Forest-Tomlin update scheme. If not Forest-Tomlin update is + * used, then it is not set. + */ + reviseddualsimplex_ftranstep(state, s, &state->rhor, q, &state->alphaq, &state->alphaqim, &state->tau, settings, _state); + alphaqpiv = state->alphaq.ptr.p_double[r]; + + /* + * Check numerical accuracy, trigger refactorization if needed + */ + if( reviseddualsimplex_refactorizationrequired(state, s, q, alpharpiv, r, alphaqpiv, _state) ) + { + if( state->dotrace ) + { + ae_trace("> refactorization test: numerical errors are too large, forcing refactorization and restart\n"); + } + reviseddualsimplex_basisfreshtrf(&state->basis, &state->at, settings, _state); + reviseddualsimplex_subproblemhandlexnupdate(state, s, _state); + reviseddualsimplex_offloadbasiccomponents(s, &state->basis, settings, _state); + continue; + } + + /* + * Basis change and update + */ + reviseddualsimplex_updatestep(state, s, p, q, r, delta, alpharpiv, thetap, thetad, &state->alphaq, &state->alphaqim, &state->alphar, &state->tau, &state->possibleflips, state->possibleflipscnt, settings, _state); + inc(&state->repiterationscount, _state); + if( isphase1 ) + { + inc(&state->repiterationscount1, _state); + } + else + { + inc(&state->repiterationscount2, _state); + } + } +} + + +/************************************************************************* +This function solves simplex subproblem using primal simplex method. + +A problem with following properties is expected: +* M>0 +* feasible box constraints +* primal feasible initial basis +* actual initial point XC and target value Z +* actual reduced cost vector D +* pricing weights being set to 1.0 or copied from previous problem + +Returns: + * Info = +1 for success, -3 for infeasible + * IterationsCount is increased by amount of iterations performed + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_solvesubproblemprimal(dualsimplexstate* state, + dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_int_t* info, + ae_state *_state) +{ + ae_int_t nn; + ae_int_t nx; + ae_int_t m; + ae_int_t i; + ae_int_t j; + double v; + double vmax; + ae_int_t bi; + double dj; + ae_int_t bndt; + ae_int_t q; + ae_int_t p; + ae_int_t r; + ae_int_t dir; + double lim; + ae_bool haslim; + double thetap; + double xbnd; + double flip; + ae_int_t canddir; + double candlim; + double candflip; + ae_int_t j0; + ae_int_t j1; + double alphawave; + double vp; + double vb; + double vx; + double vtest; + double vv; + + *info = 0; + + nn = s->ns; + nx = s->ns+s->m; + m = s->m; + + /* + * Integrity checks + */ + ae_assert(s->state==reviseddualsimplex_ssvalid, "SolveSubproblemPrimal: X is not valid", _state); + ae_assert(m>0, "SolveSubproblemPrimal: M<=0", _state); + for(i=0; i<=nx-1; i++) + { + ae_assert(s->bndt.ptr.p_int[i]!=reviseddualsimplex_ccinfeasible, "SolveSubproblemPrimal: infeasible box constraints", _state); + } + + /* + * Actual processing + */ + *info = 1; + rvectorsetlengthatleast(&state->tmp0, m, _state); + for(;;) + { + + /* + * Iteration report + */ + if( state->dotrace ) + { + i = state->repiterationscount3; + ae_trace("=== ITERATION %5d STARTED ========================================================================\n", + (int)(i)); + if( state->dodetailedtrace ) + { + } + } + + /* + * Primal simplex pricing step: we implement the very basic version + * of the pricing step because it is expected that primal simplex method + * is used just to apply quick correction after removal of the perturbation. + */ + q = -1; + vmax = (double)(0); + dir = 0; + lim = ae_maxrealnumber; + haslim = ae_false; + flip = (double)(0); + canddir = 0; + for(i=0; i<=nn-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + dj = s->d.ptr.p_double[j]; + bndt = s->bndt.ptr.p_int[j]; + if( bndt==reviseddualsimplex_ccfixed ) + { + continue; + } + if( bndt==reviseddualsimplex_ccrange ) + { + v = (double)(0); + candlim = s->bndu.ptr.p_double[j]-s->bndl.ptr.p_double[j]; + candflip = (double)(0); + if( s->xa.ptr.p_double[j]==s->bndl.ptr.p_double[j] ) + { + v = -dj; + canddir = 1; + candflip = s->bndu.ptr.p_double[j]; + } + if( s->xa.ptr.p_double[j]==s->bndu.ptr.p_double[j] ) + { + v = dj; + canddir = -1; + candflip = s->bndl.ptr.p_double[j]; + } + if( v>vmax ) + { + vmax = v; + dir = canddir; + lim = candlim; + haslim = ae_true; + flip = candflip; + q = j; + } + continue; + } + v = (double)(0); + canddir = 0; + if( bndt==reviseddualsimplex_cclower ) + { + v = -dj; + canddir = 1; + } + if( bndt==reviseddualsimplex_ccupper ) + { + v = dj; + canddir = -1; + } + if( bndt==reviseddualsimplex_ccfree ) + { + v = ae_fabs(dj, _state); + canddir = -ae_sign(dj, _state); + } + if( v>vmax ) + { + vmax = v; + dir = canddir; + lim = ae_maxrealnumber; + haslim = ae_false; + q = j; + } + continue; + } + if( vmax<=settings->dtolabs ) + { + + /* + * Solved: primal and dual feasible! + */ + if( state->dotrace ) + { + ae_trace("> primal pricing: feasible point found\n"); + } + return; + } + ae_assert(q>=0, "SolveSubproblemPrimal: integrity check failed", _state); + if( state->dotrace ) + { + ae_trace("> primal pricing: found entering variable\n"); + ae_trace("Q = %12d (variable selected)\n", + (int)(q)); + ae_trace("|D| = %12.3e (dual infeasibility)\n", + (double)(vmax)); + } + + /* + * FTran and textbook ratio test (again, we expect primal phase to terminate quickly) + * + * NOTE: AlphaQim is filled by intermediate FTran result which is useful + * for Forest-Tomlin update scheme. If not Forest-Tomlin update is + * used, then it is not set. + */ + for(i=0; i<=m-1; i++) + { + state->tmp0.ptr.p_double[i] = (double)(0); + } + j0 = state->at.ridx.ptr.p_int[q]; + j1 = state->at.ridx.ptr.p_int[q+1]-1; + for(j=j0; j<=j1; j++) + { + state->tmp0.ptr.p_double[state->at.idx.ptr.p_int[j]] = state->at.vals.ptr.p_double[j]; + } + reviseddualsimplex_basissolvex(&state->basis, &state->tmp0, &state->alphaq, &state->alphaqim, ae_true, &state->tmp2, _state); + vp = settings->pivottol; + p = -1; + r = -1; + thetap = (double)(0); + xbnd = (double)(0); + for(i=0; i<=m-1; i++) + { + bi = state->basis.idx.ptr.p_int[i]; + alphawave = -(double)dir*state->alphaq.ptr.p_double[i]; + vx = s->xa.ptr.p_double[bi]; + if( alphawave<-vp&&reviseddualsimplex_hasbndl(s, bi, _state) ) + { + vb = s->bndl.ptr.p_double[bi]; + if( vx<=vb ) + { + + /* + * X[Bi] is already out of bounds due to rounding errors, perform shifting + */ + vb = vx-reviseddualsimplex_shiftlen; + s->bndl.ptr.p_double[bi] = vx; + } + vtest = (vb-vx)/alphawave; + if( p<0||vtestvp&&reviseddualsimplex_hasbndu(s, bi, _state) ) + { + vb = s->bndu.ptr.p_double[bi]; + if( vx>=vb ) + { + + /* + * X[Bi] is already out of bounds due to rounding errors, perform shifting + */ + vb = vx+reviseddualsimplex_shiftlen; + s->bndu.ptr.p_double[bi] = vb; + } + vtest = (vb-vx)/alphawave; + if( p<0||vtestdotrace ) + { + ae_trace("> primal ratio test: dual infeasible, primal unbounded\n"); + } + return; + } + if( state->dotrace ) + { + ae_trace("> primal ratio test: found leaving variable\n"); + ae_trace("P = %12d (variable index)\n", + (int)(p)); + ae_trace("R = %12d (variable index in basis)\n", + (int)(r)); + ae_trace("ThetaP = %12.3e (primal step length)\n", + (double)(thetap)); + } + + /* + * Update step + */ + if( p>=0&&(!haslim||thetaptmp0, m, _state); + for(i=0; i<=m-1; i++) + { + bi = state->basis.idx.ptr.p_int[i]; + vv = thetap*((double)dir*state->alphaq.ptr.p_double[i]); + s->xa.ptr.p_double[bi] = s->xa.ptr.p_double[bi]-vv; + } + s->xa.ptr.p_double[p] = xbnd; + s->xa.ptr.p_double[q] = s->xa.ptr.p_double[q]+(double)dir*thetap; + for(i=0; i<=m-1; i++) + { + state->tmp0.ptr.p_double[i] = (double)(0); + } + reviseddualsimplex_basisupdatetrf(&state->basis, &state->at, p, q, &state->alphaq, &state->alphaqim, r, &state->tmp0, settings, _state); + for(i=0; i<=m-1; i++) + { + state->tmp0.ptr.p_double[i] = s->effc.ptr.p_double[state->basis.idx.ptr.p_int[i]]; + } + reviseddualsimplex_basissolvet(&state->basis, &state->tmp0, &state->tmp1, &state->tmp2, _state); + reviseddualsimplex_computeantv(state, &state->tmp1, &s->d, _state); + for(i=0; i<=nn-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + s->d.ptr.p_double[j] = s->effc.ptr.p_double[j]-s->d.ptr.p_double[j]; + } + } + else + { + + /* + * Basis does not change because Qth variable flips from one bound + * to another one long before we encounter the boundary + */ + s->xa.ptr.p_double[q] = flip; + for(i=0; i<=m-1; i++) + { + bi = state->basis.idx.ptr.p_int[i]; + vv = lim*((double)dir*state->alphaq.ptr.p_double[i]); + s->xa.ptr.p_double[bi] = s->xa.ptr.p_double[bi]-vv; + } + } + inc(&state->repiterationscount, _state); + inc(&state->repiterationscount3, _state); + } +} + + +/************************************************************************* +This function estimates feasibility properties of the current basis and +invokes phase 1 if necessary. + +A problem with following properties is expected: +* M>0 +* feasible box constraints +* some initial basis (can be dual infeasible) with actual factorization +* actual initial point XC and target value Z +* actual reduced cost vector D + +It returns: +* +1 if dual feasible basis was found +* -4 if problem is dual infeasible + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_invokephase1(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + double dualerr; + + + m = state->primary.m; + state->repterminationtype = 0; + + /* + * Integrity checks + */ + ae_assert(state->primary.state==reviseddualsimplex_ssvalid, "InvokePhase1: invalid primary X", _state); + ae_assert(m>0, "InvokePhase1: M<=0", _state); + + /* + * Is it dual feasible from the very beginning (or maybe after initial DFC)? + */ + if( state->dotrace ) + { + ae_trace("> performing initial dual feasibility correction...\n"); + } + dualerr = reviseddualsimplex_initialdualfeasibilitycorrection(state, &state->primary, settings, _state); + if( state->dotrace ) + { + ae_trace("> initial dual feasibility correction done\ndualErr = %0.3e\n", + (double)(dualerr)); + } + if( ae_fp_less_eq(dualerr,settings->dtolabs) ) + { + if( state->dotrace ) + { + ae_trace("> solution is dual feasible, phase 1 is done\n"); + } + state->repterminationtype = 1; + return; + } + if( state->dotrace ) + { + ae_trace("> solution is not dual feasible, proceeding to full-scale phase 1\n"); + ae_trace("\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("* PHASE 1 OF DUAL SIMPLEX SOLVER *\n"); + ae_trace("****************************************************************************************************\n"); + } + + /* + * Solve phase #1 subproblem + */ + reviseddualsimplex_subprobleminitphase1(&state->primary, &state->basis, &state->phase1, _state); + if( state->dotrace ) + { + ae_trace("> performing phase 1 dual feasibility correction...\n"); + } + dualerr = reviseddualsimplex_initialdualfeasibilitycorrection(state, &state->phase1, settings, _state); + if( state->dotrace ) + { + ae_trace("> phase 1 dual feasibility correction done\ndualErr = %0.3e\n", + (double)(dualerr)); + } + reviseddualsimplex_solvesubproblemdual(state, &state->phase1, ae_true, settings, &state->repterminationtype, _state); + ae_assert(state->repterminationtype>0, "DualSimplexSolver: unexpected failure of phase #1", _state); + state->repterminationtype = 1; + + /* + * Setup initial basis for phase #2 using solution of phase #1 + */ + if( state->dotrace ) + { + ae_trace("> setting up phase 2 initial solution\n"); + } + reviseddualsimplex_subprobleminferinitialxn(state, &state->primary, _state); + dualerr = reviseddualsimplex_initialdualfeasibilitycorrection(state, &state->primary, settings, _state); + if( ae_fp_greater(dualerr,settings->dtolabs) ) + { + if( state->dotrace ) + { + ae_trace("> initial dual feasibility correction failed! terminating...\n"); + } + state->repterminationtype = -4; + return; + } + state->repterminationtype = 1; +} + + +/************************************************************************* +This function performs actual solution. + +INPUT PARAMETERS: + State - state + +Solution results can be found in fields of State which are explicitly +declared as accessible by external code. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_dssoptimizewrk(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t nx; + ae_int_t m; + ae_int_t i; + ae_int_t j; + double v; + hqrndstate rs; + ae_int_t t0; + + ae_frame_make(_state, &_frame_block); + memset(&rs, 0, sizeof(rs)); + _hqrndstate_init(&rs, _state, ae_true); + + nx = state->primary.ns+state->primary.m; + m = state->primary.m; + t0 = 0; + + /* + * Handle case when M=0; after this block we assume that M>0. + */ + if( m==0 ) + { + + /* + * Trace + */ + if( state->dotrace ) + { + ae_trace("> box-only LP problem, quick solution\n"); + } + + /* + * Solve + */ + reviseddualsimplex_solveboxonly(state, _state); + ae_frame_leave(_state); + return; + } + + /* + * Most basic check for correctness of box and/or linear constraints + */ + for(j=0; j<=nx-1; j++) + { + if( state->primary.bndt.ptr.p_int[j]==reviseddualsimplex_ccinfeasible ) + { + + /* + * Set error flag and generate some point to return + */ + if( state->dotrace ) + { + ae_trace("[WARNING] infeasible box constraint (or range constraint with AL>AU) found, terminating\n"); + } + state->repterminationtype = -3; + reviseddualsimplex_setzeroxystats(state, _state); + ae_frame_leave(_state); + return; + } + } + + /* + * Initialization: + * * initial perturbed C[] + */ + hqrndseed(7456, 2355, &rs, _state); + for(i=0; i<=nx-1; i++) + { + if( !reviseddualsimplex_isfree(&state->primary, i, _state) ) + { + + /* + * apply perturbation + */ + v = settings->perturbmag*((double)1+ae_fabs(state->primary.rawc.ptr.p_double[i], _state))*((double)1+hqrnduniformr(&rs, _state)); + if( !reviseddualsimplex_hasbndl(&state->primary, i, _state) ) + { + v = -v; + } + state->primary.effc.ptr.p_double[i] = state->primary.rawc.ptr.p_double[i]+v; + } + } + + /* + * Solve phase 1 subproblem, then perturbed subproblem + */ + reviseddualsimplex_basisfreshtrf(&state->basis, &state->at, settings, _state); + if( state->primary.state==reviseddualsimplex_ssinvalid ) + { + reviseddualsimplex_subprobleminferinitialxn(state, &state->primary, _state); + } + if( state->primary.state==reviseddualsimplex_ssvalidxn ) + { + reviseddualsimplex_subproblemhandlexnupdate(state, &state->primary, _state); + } + ae_assert(state->primary.state==reviseddualsimplex_ssvalid, "DSS: integrity check failed (init)", _state); + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + reviseddualsimplex_invokephase1(state, settings, _state); + if( state->dotimers ) + { + state->repphase1time = ae_tickcount()-t0; + } + if( state->repterminationtype<=0 ) + { + + /* + * Primal unbounded, dual infeasible + */ + ae_assert(state->repterminationtype==-4, "DSS: integrity check for InvokePhase1() result failed", _state); + if( state->dotrace ) + { + ae_trace("> the problem is dual infeasible, primal unbounded\n> done\n"); + } + reviseddualsimplex_setxydstats(state, &state->primary, &state->basis, &state->xydsbuf, &state->repx, &state->replagbc, &state->replaglc, &state->repstats, _state); + ae_frame_leave(_state); + return; + } + if( state->dotrace ) + { + ae_trace("\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("* PHASE 2 OF DUAL SIMPLEX SOLVER *\n"); + ae_trace("****************************************************************************************************\n"); + } + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + reviseddualsimplex_solvesubproblemdual(state, &state->primary, ae_false, settings, &state->repterminationtype, _state); + if( state->dotimers ) + { + state->repphase2time = ae_tickcount()-t0; + } + if( state->repterminationtype<=0 ) + { + + /* + * Primal infeasible + */ + ae_assert(state->repterminationtype==-3, "DSS: integrity check for SolveSubproblemDual() result failed", _state); + if( state->dotrace ) + { + ae_trace("> the problem is primal infeasible\n> done\n"); + } + reviseddualsimplex_setxydstats(state, &state->primary, &state->basis, &state->xydsbuf, &state->repx, &state->replagbc, &state->replaglc, &state->repstats, _state); + ae_frame_leave(_state); + return; + } + + /* + * Remove perturbation from the cost vector, + * then use primal simplex to enforce dual feasibility + * after removal of the perturbation (if necessary). + */ + if( state->dotrace ) + { + ae_trace("\n"); + ae_trace("****************************************************************************************************\n"); + ae_trace("* PHASE 3 OF DUAL SIMPLEX SOLVER (perturbation removed from cost vector) *\n"); + ae_trace("****************************************************************************************************\n"); + } + if( state->dotimers ) + { + t0 = ae_tickcount(); + } + reviseddualsimplex_subprobleminitphase3(&state->primary, &state->phase3, _state); + for(i=0; i<=nx-1; i++) + { + state->phase3.effc.ptr.p_double[i] = state->primary.rawc.ptr.p_double[i]; + } + ae_assert(state->phase3.state>=reviseddualsimplex_ssvalidxn, "DSS: integrity check failed (remove perturbation)", _state); + reviseddualsimplex_subproblemhandlexnupdate(state, &state->phase3, _state); + reviseddualsimplex_solvesubproblemprimal(state, &state->phase3, settings, &state->repterminationtype, _state); + if( state->dotimers ) + { + state->repphase3time = ae_tickcount()-t0; + } + if( state->repterminationtype<=0 ) + { + + /* + * Dual infeasible, primal unbounded + */ + ae_assert(state->repterminationtype==-4, "DSS: integrity check for SolveSubproblemPrimal() result failed", _state); + if( state->dotrace ) + { + ae_trace("> the problem is primal unbounded\n> done\n"); + } + reviseddualsimplex_setxydstats(state, &state->phase3, &state->basis, &state->xydsbuf, &state->repx, &state->replagbc, &state->replaglc, &state->repstats, _state); + ae_frame_leave(_state); + return; + } + for(i=0; i<=nx-1; i++) + { + state->primary.xa.ptr.p_double[i] = state->phase3.xa.ptr.p_double[i]; + if( reviseddualsimplex_hasbndl(&state->primary, i, _state) ) + { + state->primary.xa.ptr.p_double[i] = ae_maxreal(state->primary.xa.ptr.p_double[i], state->primary.bndl.ptr.p_double[i], _state); + } + if( reviseddualsimplex_hasbndu(&state->primary, i, _state) ) + { + state->primary.xa.ptr.p_double[i] = ae_minreal(state->primary.xa.ptr.p_double[i], state->primary.bndu.ptr.p_double[i], _state); + } + } + + /* + * Primal and dual feasible, problem solved + */ + state->repterminationtype = 1; + reviseddualsimplex_setxydstats(state, &state->primary, &state->basis, &state->xydsbuf, &state->repx, &state->replagbc, &state->replaglc, &state->repstats, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Box-constrained solver; sets State.RepX, State.RepStats and State.RepTerminationType, +does not change other fields. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_solveboxonly(dualsimplexstate* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t ns; + + + ns = state->primary.ns; + ae_assert(state->primary.m==0, "SolveBoxOnly: integrity check failed", _state); + rsetv(ns, 0.0, &state->replagbc, _state); + for(i=0; i<=ns-1; i++) + { + + /* + * Handle infeasible variable + */ + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccinfeasible ) + { + state->repterminationtype = -3; + state->repx.ptr.p_double[i] = 0.5*(state->primary.bndl.ptr.p_double[i]+state->primary.bndu.ptr.p_double[i]); + state->repstats.ptr.p_int[i] = 0; + continue; + } + + /* + * Handle fixed variable + */ + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfixed ) + { + state->repx.ptr.p_double[i] = state->primary.bndl.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = -1; + state->replagbc.ptr.p_double[i] = -state->primary.rawc.ptr.p_double[i]; + continue; + } + + /* + * Handle non-zero cost component + */ + if( ae_fp_greater(state->primary.rawc.ptr.p_double[i],(double)(0)) ) + { + if( state->primary.bndt.ptr.p_int[i]!=reviseddualsimplex_ccrange&&state->primary.bndt.ptr.p_int[i]!=reviseddualsimplex_cclower ) + { + if( state->repterminationtype>0 ) + { + state->repterminationtype = -4; + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccupper ) + { + state->repx.ptr.p_double[i] = state->primary.bndu.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = 1; + } + else + { + state->repx.ptr.p_double[i] = (double)(0); + state->repstats.ptr.p_int[i] = 0; + } + state->replagbc.ptr.p_double[i] = (double)(0); + } + else + { + state->repx.ptr.p_double[i] = state->primary.bndl.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = -1; + state->replagbc.ptr.p_double[i] = -state->primary.rawc.ptr.p_double[i]; + } + continue; + } + if( ae_fp_less(state->primary.rawc.ptr.p_double[i],(double)(0)) ) + { + if( state->primary.bndt.ptr.p_int[i]!=reviseddualsimplex_ccrange&&state->primary.bndt.ptr.p_int[i]!=reviseddualsimplex_ccupper ) + { + if( state->repterminationtype>0 ) + { + state->repterminationtype = -4; + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_cclower ) + { + state->repx.ptr.p_double[i] = state->primary.bndl.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = -1; + } + else + { + state->repx.ptr.p_double[i] = (double)(0); + state->repstats.ptr.p_int[i] = 0; + } + state->replagbc.ptr.p_double[i] = (double)(0); + } + else + { + state->repx.ptr.p_double[i] = state->primary.bndu.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = 1; + state->replagbc.ptr.p_double[i] = -state->primary.rawc.ptr.p_double[i]; + } + continue; + } + + /* + * Handle non-free variable with zero cost component + */ + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccupper||state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccrange ) + { + state->repx.ptr.p_double[i] = state->primary.bndu.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = 1; + state->replagbc.ptr.p_double[i] = (double)(0); + continue; + } + if( state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_cclower ) + { + state->repx.ptr.p_double[i] = state->primary.bndl.ptr.p_double[i]; + state->repstats.ptr.p_int[i] = -1; + state->replagbc.ptr.p_double[i] = (double)(0); + continue; + } + + /* + * Free variable, zero cost component + */ + ae_assert(state->primary.bndt.ptr.p_int[i]==reviseddualsimplex_ccfree, "DSSOptimize: integrity check failed", _state); + state->repx.ptr.p_double[i] = (double)(0); + state->repstats.ptr.p_int[i] = 0; + state->replagbc.ptr.p_double[i] = (double)(0); + } +} + + +/************************************************************************* +Zero-fill RepX, RepLagBC, RepLagLC, RepStats. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_setzeroxystats(dualsimplexstate* state, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=state->primary.ns-1; i++) + { + state->repx.ptr.p_double[i] = (double)(0); + state->replagbc.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=state->primary.m-1; i++) + { + state->replaglc.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=state->primary.ns+state->primary.m-1; i++) + { + state->repstats.ptr.p_int[i] = 0; + } +} + + +/************************************************************************* +This function initializes basis structure; no triangular factorization is +prepared yet. Previously allocated memory is reused. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basisinit(ae_int_t ns, + ae_int_t m, + dualsimplexbasis* s, + ae_state *_state) +{ + ae_int_t i; + + + s->ns = ns; + s->m = m; + ivectorgrowto(&s->idx, m, _state); + ivectorgrowto(&s->nidx, ns, _state); + bvectorgrowto(&s->isbasic, ns+m, _state); + for(i=0; i<=ns-1; i++) + { + s->nidx.ptr.p_int[i] = i; + s->isbasic.ptr.p_bool[i] = ae_false; + } + for(i=0; i<=m-1; i++) + { + s->idx.ptr.p_int[i] = ns+i; + s->isbasic.ptr.p_bool[ns+i] = ae_true; + } + s->trftype = 3; + s->trfage = 0; + s->isvalidtrf = ae_false; + rvectorsetlengthatleast(&s->dseweights, m, _state); + for(i=0; i<=m-1; i++) + { + s->dseweights.ptr.p_double[i] = 1.0; + } + s->dsevalid = ae_false; + reviseddualsimplex_basisclearstats(s, _state); +} + + +/************************************************************************* +This function clears internal performance counters of the basis + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basisclearstats(dualsimplexbasis* s, + ae_state *_state) +{ + + + s->statfact = 0; + s->statupdt = 0; + s->statoffdiag = (double)(0); +} + + +/************************************************************************* +This function resizes basis. It is assumed that constraint matrix is +completely overwritten by new one, but both matrices are similar enough +so we can reuse previous basis. + +Dual steepest edge weights are invalidated by this function. + +This function: +* tries to resize basis +* if possible, returns True and valid basis with valid factorization +* if resize is impossible (or abandoned due to stability reasons), it + returns False and basis object is left in the invalid state (you have + to reinitialize it by all-logicals basis) + +Following types of resize are supported: +* new basis size is larger than previous one => logical elements are + added to the new basis +* basis sizes match => no operation is performed +* new basis size is zero => basis is set to zero + +This function: +* requires valid triangular factorization at S on entry +* replaces it by another, valid factorization +* checks that new factorization deviates from the previous one not too much + by comparing magnitudes of min[abs(u_ii)] in both factorization (sharp + decrease results in attempt to resize being abandoned + +IMPORTANT: if smooth resize is not possible, this function throws an + exception! It is responsibility of the caller to check that + smooth resize is possible + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_basistryresize(dualsimplexbasis* s, + ae_int_t newm, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t ns; + ae_int_t oldm; + ae_int_t i; + double oldminu; + double newminu; + ae_bool result; + + + ns = s->ns; + oldm = s->m; + result = ae_false; + + /* + * Quick exit strategies + */ + if( newm==0 ) + { + reviseddualsimplex_basisinit(ns, 0, s, _state); + result = ae_true; + return result; + } + + /* + * Same size or larger + */ + if( newm>=oldm ) + { + ae_assert(s->isvalidtrf||oldm==0, "BasisTryResize: needs valid TRF in S", _state); + + /* + * Save information about matrix conditioning + */ + oldminu = reviseddualsimplex_basisminimumdiagonalelement(s, _state); + + /* + * Growth if needed + */ + s->m = newm; + ivectorgrowto(&s->idx, newm, _state); + bvectorgrowto(&s->isbasic, ns+newm, _state); + for(i=oldm; i<=newm-1; i++) + { + s->idx.ptr.p_int[i] = ns+i; + s->isbasic.ptr.p_bool[ns+i] = ae_true; + } + + /* + * DSE weights are invalid and filled by 1.0 + */ + rvectorgrowto(&s->dseweights, newm, _state); + for(i=0; i<=newm-1; i++) + { + s->dseweights.ptr.p_double[i] = 1.0; + } + s->dsevalid = ae_false; + + /* + * Invalidate TRF. + * Try to refactorize. + */ + s->isvalidtrf = ae_false; + newminu = reviseddualsimplex_basisfreshtrfunsafe(s, at, settings, _state); + result = ae_fp_greater_eq(newminu,reviseddualsimplex_maxudecay*oldminu); + return result; + } + ae_assert(ae_false, "BasisTryResize: unexpected branch", _state); + return result; +} + + +/************************************************************************* +This function returns minimum diagonal element of S. Result=1 is returned +for M=0. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static double reviseddualsimplex_basisminimumdiagonalelement(const dualsimplexbasis* s, + ae_state *_state) +{ + double v; + double vv; + ae_int_t i; + ae_int_t m; + double result; + + + m = s->m; + if( m==0 ) + { + result = (double)(1); + return result; + } + ae_assert(((s->trftype==0||s->trftype==1)||s->trftype==2)||s->trftype==3, "BasisMinimumDiagonalElement: unexpected TRF type", _state); + ae_assert(s->isvalidtrf, "BasisMinimumDiagonalElement: TRF is invalid", _state); + v = ae_maxrealnumber; + for(i=0; i<=m-1; i++) + { + vv = (double)(0); + if( s->trftype==0||s->trftype==1 ) + { + vv = s->denselu.ptr.pp_double[i][i]; + } + if( s->trftype==2||s->trftype==3 ) + { + vv = sparsegetdiagonal(&s->sparseu, i, _state); + } + if( vv<(double)0 ) + { + vv = -vv; + } + if( vvns = s0->ns; + s1->m = s0->m; + copyintegerarray(&s0->idx, &s1->idx, _state); + copyintegerarray(&s0->nidx, &s1->nidx, _state); + copybooleanarray(&s0->isbasic, &s1->isbasic, _state); + s1->isvalidtrf = ae_false; + s1->trftype = -1; + s1->dsevalid = ae_false; + if( s0->m>0 ) + { + ae_assert(s0->isvalidtrf, "BasisExport: valid factorization is required for source basis", _state); + s1->eminu = reviseddualsimplex_basisminimumdiagonalelement(s0, _state); + } + else + { + s1->eminu = (double)(1); + } +} + + +/************************************************************************* +This function imports from S1 to S0 a division of variables into +basic/nonbasic ones; only basic/nonbasic sets are imported. + +Triangular factorization is not imported; however, this function checks +that new factorization deviates from the previous one not too much by +comparing magnitudes of min[abs(u_ii)] in both factorization (basis being +imported stores statistics about U). Sharp decrease of diagonal elements +means that we have too unstable situation which results in import being +abandoned. In this case False is returned, and the basis S0 is left in the +indeterminate invalid state (you have to reinitialize it by all-logicals). + +IMPORTANT: if metrics of S0 and S1 do not match, an exception will be generated. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_basistryimportfrom(dualsimplexbasis* s0, + const dualsimplexbasis* s1, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t i; + double newminu; + ae_bool result; + + + ae_assert(s0->ns==s1->ns, "BasisImportFrom: structural variable counts do not match", _state); + reviseddualsimplex_basisclearstats(s0, _state); + s0->m = s1->m; + for(i=0; i<=s0->m-1; i++) + { + s0->idx.ptr.p_int[i] = s1->idx.ptr.p_int[i]; + } + for(i=0; i<=s0->ns-1; i++) + { + s0->nidx.ptr.p_int[i] = s1->nidx.ptr.p_int[i]; + } + for(i=0; i<=s0->m+s0->ns-1; i++) + { + s0->isbasic.ptr.p_bool[i] = s1->isbasic.ptr.p_bool[i]; + } + s0->isvalidtrf = ae_false; + rvectorsetlengthatleast(&s0->dseweights, s1->m, _state); + for(i=0; i<=s1->m-1; i++) + { + s0->dseweights.ptr.p_double[i] = 1.0; + } + s0->dsevalid = ae_false; + newminu = reviseddualsimplex_basisfreshtrfunsafe(s0, at, settings, _state); + result = ae_fp_greater_eq(newminu,reviseddualsimplex_maxudecay*s1->eminu); + if( !result ) + { + s0->isvalidtrf = ae_false; + s0->trftype = -1; + } + return result; +} + + +/************************************************************************* +This function computes fresh triangular factorization. + +If TRF of age 0 (fresh) is already present, no new factorization is calculated. +If factorization has exactly zero element along diagonal, this function +generates exception. + + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basisfreshtrf(dualsimplexbasis* s, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state) +{ + double v; + + + v = reviseddualsimplex_basisfreshtrfunsafe(s, at, settings, _state); + ae_assert(ae_fp_greater(v,(double)(0)), "BasisFreshTrf: degeneracy of B is detected", _state); +} + + +/************************************************************************* +This function computes fresh triangular factorization. + +If TRF of age 0 (fresh) is already present, no new factorization is calculated. + +It returns min[abs(u[i,i])] which can be used to determine whether factorization +is degenerate or not (it will factorize anything, the question is whether +it is possible to use factorization) + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static double reviseddualsimplex_basisfreshtrfunsafe(dualsimplexbasis* s, + const sparsematrix* at, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t ns; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_int_t k1; + ae_int_t nzl; + ae_int_t nzu; + ae_int_t nlogical; + ae_int_t nstructural; + ae_int_t offs; + ae_int_t offs1; + ae_int_t offs2; + double result; + + + m = s->m; + ns = s->ns; + result = (double)(0); + + /* + * Compare TRF type with one required by settings, invalidation and refresh otherwise + */ + if( s->trftype!=settings->trftype ) + { + s->trftype = settings->trftype; + s->isvalidtrf = ae_false; + result = reviseddualsimplex_basisfreshtrfunsafe(s, at, settings, _state); + return result; + } + + /* + * Is it valid and fresh? + */ + if( s->isvalidtrf&&s->trfage==0 ) + { + result = reviseddualsimplex_basisminimumdiagonalelement(s, _state); + return result; + } + + /* + * Dense TRF + */ + if( s->trftype==0||s->trftype==1 ) + { + ivectorsetlengthatleast(&s->colpermbwd, m, _state); + for(i=0; i<=m-1; i++) + { + s->colpermbwd.ptr.p_int[i] = i; + } + rmatrixsetlengthatleast(&s->denselu, m, m, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=m-1; j++) + { + s->denselu.ptr.pp_double[i][j] = (double)(0); + } + } + for(i=0; i<=m-1; i++) + { + j0 = at->ridx.ptr.p_int[s->idx.ptr.p_int[i]]; + j1 = at->ridx.ptr.p_int[s->idx.ptr.p_int[i]+1]-1; + for(j=j0; j<=j1; j++) + { + s->denselu.ptr.pp_double[i][at->idx.ptr.p_int[j]] = at->vals.ptr.p_double[j]; + } + } + rmatrixlu(&s->denselu, m, m, &s->tmpi, _state); + reviseddualsimplex_pivottobwd(&s->tmpi, m, &s->rowpermbwd, _state); + s->isvalidtrf = ae_true; + s->trfage = 0; + s->statfact = s->statfact+1; + s->statoffdiag = s->statoffdiag+ae_sqr((double)(m-1), _state); + result = reviseddualsimplex_basisminimumdiagonalelement(s, _state); + return result; + } + + /* + * Sparse TRF (with either PFI or Forest-Tomlin) + */ + if( s->trftype==2||s->trftype==3 ) + { + + /* + * Determine permutation which moves logical variables + * to the beginning. + * + * NOTE: this reordering results in stable factorization + * because we prenormalized constraints with 2-norm, + * all elements in the logical columns are less than + * 1.0 in magnitude. + * + * After this block is done we have following arrays: + * * tCInvIdx[j], which is an inverse of ColPermBwf[] + */ + ivectorsetlengthatleast(&s->tcinvidx, m, _state); + ivectorsetlengthatleast(&s->rowpermbwd, m, _state); + ivectorsetlengthatleast(&s->colpermbwd, m, _state); + for(i=0; i<=m-1; i++) + { + s->tcinvidx.ptr.p_int[i] = i; + s->rowpermbwd.ptr.p_int[i] = i; + s->colpermbwd.ptr.p_int[i] = i; + } + nlogical = 0; + for(i=0; i<=m-1; i++) + { + if( s->idx.ptr.p_int[i]>=ns ) + { + j = s->rowpermbwd.ptr.p_int[nlogical]; + s->rowpermbwd.ptr.p_int[nlogical] = s->rowpermbwd.ptr.p_int[i]; + s->rowpermbwd.ptr.p_int[i] = j; + j1 = s->tcinvidx.ptr.p_int[s->idx.ptr.p_int[i]-ns]; + j = s->colpermbwd.ptr.p_int[j1]; + s->colpermbwd.ptr.p_int[j1] = s->colpermbwd.ptr.p_int[nlogical]; + s->colpermbwd.ptr.p_int[nlogical] = j; + s->tcinvidx.ptr.p_int[s->colpermbwd.ptr.p_int[nlogical]] = nlogical; + s->tcinvidx.ptr.p_int[s->colpermbwd.ptr.p_int[j1]] = j1; + nlogical = nlogical+1; + } + } + sortmiddlei(&s->colpermbwd, nlogical, m-nlogical, _state); + for(i=0; i<=m-1; i++) + { + s->tcinvidx.ptr.p_int[s->colpermbwd.ptr.p_int[i]] = i; + } + nstructural = m-nlogical; + + /* + * Prepare SparseLU1 to receive factored out logical part of the matrix + * and SparseLU2 to receive structural part of the matrix. + */ + ivectorsetlengthatleast(&s->sparselu1.ridx, nstructural+1, _state); + ivectorsetlengthatleast(&s->sparselu1.didx, nstructural, _state); + ivectorsetlengthatleast(&s->sparselu1.uidx, nstructural, _state); + s->sparselu1.matrixtype = 1; + s->sparselu1.m = nstructural; + s->sparselu1.n = nlogical; + s->sparselu1.ridx.ptr.p_int[0] = 0; + ivectorsetlengthatleast(&s->sparselu2.ridx, nstructural+1, _state); + ivectorsetlengthatleast(&s->sparselu2.didx, nstructural, _state); + ivectorsetlengthatleast(&s->sparselu2.uidx, nstructural, _state); + s->sparselu2.matrixtype = 1; + s->sparselu2.m = nstructural; + s->sparselu2.n = nstructural; + s->sparselu2.ridx.ptr.p_int[0] = 0; + + /* + * Reorder array, perform LU factorization + */ + for(k=0; k<=nstructural-1; k++) + { + + /* + * Make sure SparseLU1 and SparseLU2 have enough place. + */ + offs1 = s->sparselu1.ridx.ptr.p_int[k]; + offs2 = s->sparselu2.ridx.ptr.p_int[k]; + ivectorgrowto(&s->sparselu1.idx, offs1+m, _state); + rvectorgrowto(&s->sparselu1.vals, offs1+m, _state); + ivectorgrowto(&s->sparselu2.idx, offs2+m, _state); + rvectorgrowto(&s->sparselu2.vals, offs2+m, _state); + + /* + * Extract K-th row of the SparseLU1/2 (I-th row of the original matrix) + */ + i = s->rowpermbwd.ptr.p_int[k+nlogical]; + j0 = at->ridx.ptr.p_int[s->idx.ptr.p_int[i]]; + j1 = at->ridx.ptr.p_int[s->idx.ptr.p_int[i]+1]-1; + for(j=j0; j<=j1; j++) + { + k1 = s->tcinvidx.ptr.p_int[at->idx.ptr.p_int[j]]; + if( k1sparselu1.idx.ptr.p_int[offs1] = k1; + s->sparselu1.vals.ptr.p_double[offs1] = at->vals.ptr.p_double[j]; + offs1 = offs1+1; + } + else + { + + /* + * Append element to SparseLU2 + */ + s->sparselu2.idx.ptr.p_int[offs2] = k1-nlogical; + s->sparselu2.vals.ptr.p_double[offs2] = at->vals.ptr.p_double[j]; + offs2 = offs2+1; + } + } + + /* + * Elements added to the last row of LU1 can be unordered, + * so it needs resorting. + * + * LU2 does NOT need resorting because trailing NStructural + * elements of permutation were post-sorted to produce + * already sorted results. + */ + tagsortmiddleir(&s->sparselu1.idx, &s->sparselu1.vals, s->sparselu1.ridx.ptr.p_int[k], offs1-s->sparselu1.ridx.ptr.p_int[k], _state); + s->sparselu1.ridx.ptr.p_int[k+1] = offs1; + s->sparselu2.ridx.ptr.p_int[k+1] = offs2; + } + s->sparselu1.ninitialized = s->sparselu1.ridx.ptr.p_int[nstructural]; + s->sparselu2.ninitialized = s->sparselu2.ridx.ptr.p_int[nstructural]; + sparseinitduidx(&s->sparselu1, _state); + sparseinitduidx(&s->sparselu2, _state); + if( nstructural>0 ) + { + sptrflu(&s->sparselu2, 2, &s->densep2, &s->densep2c, &s->lubuf2, _state); + for(i=0; i<=nstructural-1; i++) + { + j = s->rowpermbwd.ptr.p_int[i+nlogical]; + s->rowpermbwd.ptr.p_int[i+nlogical] = s->rowpermbwd.ptr.p_int[s->densep2.ptr.p_int[i]+nlogical]; + s->rowpermbwd.ptr.p_int[s->densep2.ptr.p_int[i]+nlogical] = j; + j = s->colpermbwd.ptr.p_int[i+nlogical]; + s->colpermbwd.ptr.p_int[i+nlogical] = s->colpermbwd.ptr.p_int[s->densep2c.ptr.p_int[i]+nlogical]; + s->colpermbwd.ptr.p_int[s->densep2c.ptr.p_int[i]+nlogical] = j; + } + + /* + * Process L factor: + * + * 1. count number of non-zeros in the L factor, + * 2. fill NLogical*NLogical leading block + * 3. NStructural*M bottom block + */ + nzl = nlogical; + for(i=0; i<=nstructural-1; i++) + { + k = s->lubuf2.rowpermrawidx.ptr.p_int[i]; + nzl = nzl+(s->sparselu1.ridx.ptr.p_int[k+1]-s->sparselu1.ridx.ptr.p_int[k]); + nzl = nzl+1+(s->sparselu2.didx.ptr.p_int[i]-s->sparselu2.ridx.ptr.p_int[i]); + } + rvectorsetlengthatleast(&s->sparsel.vals, nzl, _state); + ivectorsetlengthatleast(&s->sparsel.idx, nzl, _state); + ivectorsetlengthatleast(&s->sparsel.ridx, m+1, _state); + ivectorsetlengthatleast(&s->sparsel.didx, m, _state); + ivectorsetlengthatleast(&s->sparsel.uidx, m, _state); + s->sparsel.matrixtype = 1; + s->sparsel.m = m; + s->sparsel.n = m; + s->sparsel.ninitialized = nzl; + s->sparsel.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nlogical-1; i++) + { + s->sparsel.idx.ptr.p_int[i] = i; + s->sparsel.vals.ptr.p_double[i] = 1.0; + s->sparsel.ridx.ptr.p_int[i+1] = i+1; + } + for(i=0; i<=nstructural-1; i++) + { + offs = s->sparsel.ridx.ptr.p_int[nlogical+i]; + k = s->lubuf2.rowpermrawidx.ptr.p_int[i]; + j0 = s->sparselu1.ridx.ptr.p_int[k]; + j1 = s->sparselu1.ridx.ptr.p_int[k+1]-1; + for(j=j0; j<=j1; j++) + { + s->sparsel.idx.ptr.p_int[offs] = s->sparselu1.idx.ptr.p_int[j]; + s->sparsel.vals.ptr.p_double[offs] = -s->sparselu1.vals.ptr.p_double[j]; + offs = offs+1; + } + j0 = s->sparselu2.ridx.ptr.p_int[i]; + j1 = s->sparselu2.didx.ptr.p_int[i]-1; + for(j=j0; j<=j1; j++) + { + s->sparsel.idx.ptr.p_int[offs] = nlogical+s->sparselu2.idx.ptr.p_int[j]; + s->sparsel.vals.ptr.p_double[offs] = s->sparselu2.vals.ptr.p_double[j]; + offs = offs+1; + } + s->sparsel.idx.ptr.p_int[offs] = nlogical+i; + s->sparsel.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + s->sparsel.ridx.ptr.p_int[nlogical+i+1] = offs; + } + ae_assert(s->sparsel.ninitialized==s->sparsel.ridx.ptr.p_int[m], "BasisFreshTrf: integrity check failed", _state); + sparseinitduidx(&s->sparsel, _state); + + /* + * Process U factor: + * + * 1. count number of non-zeros in the U factor, + * 2. fill NLogical*NLogical leading block + * 3. NStructural*NStructural bottom block + */ + nzu = nlogical; + for(i=0; i<=nstructural-1; i++) + { + nzu = nzu+1+(s->sparselu2.ridx.ptr.p_int[i+1]-s->sparselu2.uidx.ptr.p_int[i]); + } + rvectorsetlengthatleast(&s->sparseu.vals, nzu, _state); + ivectorsetlengthatleast(&s->sparseu.idx, nzu, _state); + ivectorsetlengthatleast(&s->sparseu.ridx, m+1, _state); + ivectorsetlengthatleast(&s->sparseu.didx, m, _state); + ivectorsetlengthatleast(&s->sparseu.uidx, m, _state); + s->sparseu.matrixtype = 1; + s->sparseu.m = m; + s->sparseu.n = m; + s->sparseu.ninitialized = nzu; + s->sparseu.ridx.ptr.p_int[0] = 0; + for(i=0; i<=nlogical-1; i++) + { + s->sparseu.idx.ptr.p_int[i] = i; + s->sparseu.vals.ptr.p_double[i] = -1.0; + s->sparseu.ridx.ptr.p_int[i+1] = i+1; + } + for(i=0; i<=nstructural-1; i++) + { + offs = s->sparseu.ridx.ptr.p_int[nlogical+i]; + s->sparseu.idx.ptr.p_int[offs] = nlogical+i; + j = s->sparselu2.didx.ptr.p_int[i]; + if( jsparselu2.uidx.ptr.p_int[i] ) + { + ae_assert(s->sparselu2.idx.ptr.p_int[j]==i, "BasisFreshTrf: integrity check failed", _state); + s->sparseu.vals.ptr.p_double[offs] = s->sparselu2.vals.ptr.p_double[j]; + } + else + { + s->sparseu.vals.ptr.p_double[offs] = (double)(0); + } + offs = offs+1; + j0 = s->sparselu2.uidx.ptr.p_int[i]; + j1 = s->sparselu2.ridx.ptr.p_int[i+1]-1; + for(j=j0; j<=j1; j++) + { + s->sparseu.idx.ptr.p_int[offs] = nlogical+s->sparselu2.idx.ptr.p_int[j]; + s->sparseu.vals.ptr.p_double[offs] = s->sparselu2.vals.ptr.p_double[j]; + offs = offs+1; + } + s->sparseu.ridx.ptr.p_int[nlogical+i+1] = offs; + } + ae_assert(s->sparseu.ninitialized==s->sparseu.ridx.ptr.p_int[m], "BasisFreshTrf: integrity check failed", _state); + sparseinitduidx(&s->sparseu, _state); + } + else + { + ivectorsetlengthatleast(&s->nrs, m, _state); + for(i=0; i<=m-1; i++) + { + s->nrs.ptr.p_int[i] = 1; + } + sparsecreatecrsbuf(m, m, &s->nrs, &s->sparsel, _state); + for(i=0; i<=nlogical-1; i++) + { + sparseset(&s->sparsel, i, i, 1.0, _state); + } + sparsecreatecrsbuf(m, m, &s->nrs, &s->sparseu, _state); + for(i=0; i<=nlogical-1; i++) + { + sparseset(&s->sparseu, i, i, -1.0, _state); + } + } + sparsecopytransposecrsbuf(&s->sparseu, &s->sparseut, _state); + s->isvalidtrf = ae_true; + s->trfage = 0; + s->statfact = s->statfact+1; + s->statoffdiag = s->statoffdiag+(double)(s->sparsel.ridx.ptr.p_int[m]-m)+(double)(s->sparseu.ridx.ptr.p_int[m]-m); + result = reviseddualsimplex_basisminimumdiagonalelement(s, _state); + return result; + } + + /* + * + */ + ae_assert(ae_false, "BasisFreshTrf: unexpected TRF type", _state); + return result; +} + + +/************************************************************************* +This function fills S.DSEWeights by actual weights according to current +settings and sets validity flag. + +Basis object MUST store valid triangular factorization, otherwise this +function throws an exception. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basisrequestweights(dualsimplexbasis* s, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t ns; + ae_int_t i; + ae_int_t j; + double v; + double vv; + + + m = s->m; + ns = s->ns; + ae_assert((settings->pricing==-1||settings->pricing==0)||settings->pricing==1, "BasisRequestWeights: unknown pricing type", _state); + ae_assert(s->isvalidtrf, "BasisRequestWeights: factorization is not computed prior to calling this function", _state); + + /* + * If weights are valid, return immediately + */ + if( s->dsevalid ) + { + return; + } + + /* + * Compute weights from scratch + */ + if( settings->pricing==-1||settings->pricing==1 ) + { + for(i=0; i<=m-1; i++) + { + if( s->idx.ptr.p_int[i]wtmp0, m, _state); + rvectorsetlengthatleast(&s->wtmp1, m, _state); + for(j=0; j<=m-1; j++) + { + s->wtmp0.ptr.p_double[j] = (double)(0); + } + s->wtmp0.ptr.p_double[i] = (double)(1); + reviseddualsimplex_basissolvet(s, &s->wtmp0, &s->wtmp1, &s->wtmp2, _state); + v = (double)(0); + for(j=0; j<=m-1; j++) + { + vv = s->wtmp1.ptr.p_double[j]; + v = v+vv*vv; + } + s->dseweights.ptr.p_double[i] = v; + } + else + { + + /* + * Logical variable, weight can be set to 1.0 + */ + s->dseweights.ptr.p_double[i] = 1.0; + } + } + s->dsevalid = ae_true; + return; + } + + /* + * Compute weights from scratch + */ + if( settings->pricing==0 ) + { + for(i=0; i<=m-1; i++) + { + s->dseweights.ptr.p_double[i] = 1.0; + } + s->dsevalid = ae_true; + return; + } + ae_assert(ae_false, "BasisRequestWeights: unexpected pricing type", _state); +} + + +/************************************************************************* +This function updates triangular factorization by adding Q to basis and +removing P from basis. It also updates index tables IsBasic[], BasicIdx[], +Basis.NIdx[]. + +AlphaQim contains intermediate result from Ftran for AlphaQ, it is used +by Forest-Tomlin update scheme. If other update is used, it is not referenced +at all. + +X[], D[], Z are NOT recomputed. + +Tau is used if Settings.Pricing=1, ignored otherwise. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basisupdatetrf(dualsimplexbasis* s, + const sparsematrix* at, + ae_int_t p, + ae_int_t q, + /* Real */ const ae_vector* alphaq, + /* Real */ const ae_vector* alphaqim, + ae_int_t r, + /* Real */ const ae_vector* tau, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t m; + ae_int_t nn; + ae_int_t i; + ae_int_t j; + ae_bool processed; + double invaq; + ae_int_t dstoffs; + ae_int_t srcoffs; + ae_int_t srcidx; + double srcval; + double vcorner; + ae_int_t idxd; + double v; + + + m = s->m; + nn = s->ns; + + /* + * Update index tables + * + * TODO: better code!!!!!!!!!!!!!!!!!!!!!!! + */ + s->isbasic.ptr.p_bool[p] = ae_false; + s->isbasic.ptr.p_bool[q] = ae_true; + for(i=0; i<=m-1; i++) + { + if( s->idx.ptr.p_int[i]==p ) + { + s->idx.ptr.p_int[i] = q; + break; + } + } + for(i=0; i<=nn-1; i++) + { + if( s->nidx.ptr.p_int[i]==q ) + { + s->nidx.ptr.p_int[i] = p; + break; + } + } + + /* + * Update dense factorization + */ + if( ((s->trftype!=settings->trftype||s->trftype==0)||!s->isvalidtrf)||s->trfage>=settings->maxtrfage ) + { + + /* + * Complete refresh is needed for factorization + */ + s->isvalidtrf = ae_false; + reviseddualsimplex_basisfreshtrf(s, at, settings, _state); + } + else + { + processed = ae_false; + if( (s->trftype==0||s->trftype==1)||s->trftype==2 ) + { + + /* + * Dense/sparse factorizations with dense PFI + */ + ae_assert(ae_fp_neq(alphaq->ptr.p_double[r],(double)(0)), "BasisUpdateTrf: integrity check failed, AlphaQ[R]=0", _state); + rvectorgrowto(&s->densepfieta, (s->trfage+1)*m, _state); + ivectorgrowto(&s->rk, s->trfage+1, _state); + s->rk.ptr.p_int[s->trfage] = r; + invaq = 1.0/alphaq->ptr.p_double[r]; + for(i=0; i<=m-1; i++) + { + if( i!=r ) + { + s->densepfieta.ptr.p_double[s->trfage*m+i] = -alphaq->ptr.p_double[i]*invaq; + } + else + { + s->densepfieta.ptr.p_double[s->trfage*m+i] = invaq; + } + } + inc(&s->trfage, _state); + s->statupdt = s->statupdt+1; + s->statoffdiag = s->statoffdiag+ae_sqr((double)(m-1), _state); + processed = ae_true; + } + if( s->trftype==3 ) + { + + /* + * Sparse factorization with Forest-Tomlin update + */ + ae_assert(ae_fp_neq(alphaq->ptr.p_double[r],(double)(0)), "BasisUpdateTrf: integrity check failed, AlphaQ[R]=0", _state); + rvectorgrowto(&s->densemu, (s->trfage+1)*m, _state); + ivectorgrowto(&s->rk, s->trfage+1, _state); + ivectorgrowto(&s->dk, s->trfage+1, _state); + rvectorsetlengthatleast(&s->utmp0, m, _state); + + /* + * Determine D - index of row being overwritten by Forest-Tomlin update + */ + idxd = -1; + for(i=0; i<=m-1; i++) + { + if( s->rowpermbwd.ptr.p_int[i]==r ) + { + idxd = i; + break; + } + } + ae_assert(idxd>=0, "BasisUpdateTrf: unexpected integrity check failure", _state); + s->rk.ptr.p_int[s->trfage] = r; + s->dk.ptr.p_int[s->trfage] = idxd; + + /* + * Modify L with permutation which moves D-th row/column to the end: + * * rows 0...D-1 are left intact + * * rows D+1...M-1 are moved one position up, with columns 0..D-1 + * retained as is, and columns D+1...M-1 being moved one position left. + * * last row is filled by permutation/modification of AlphaQim + * Determine FT update coefficients in the process. + */ + ivectorgrowto(&s->sparsel.idx, s->sparsel.ridx.ptr.p_int[m]+m, _state); + rvectorgrowto(&s->sparsel.vals, s->sparsel.ridx.ptr.p_int[m]+m, _state); + for(i=0; i<=m-1; i++) + { + s->utmp0.ptr.p_double[i] = (double)(0); + } + for(i=idxd+1; i<=m-1; i++) + { + j = s->sparsel.ridx.ptr.p_int[i+1]-1; + if( s->sparsel.idx.ptr.p_int[j]!=i||s->sparsel.vals.ptr.p_double[j]!=(double)1 ) + { + ae_assert(ae_false, "UpdateTrf: integrity check failed for sparse L", _state); + } + dstoffs = s->sparsel.ridx.ptr.p_int[i-1]; + srcoffs = s->sparsel.ridx.ptr.p_int[i]; + + /* + * Read first element in the row (it has at least one - unit diagonal) + */ + srcidx = s->sparsel.idx.ptr.p_int[srcoffs]; + srcval = s->sparsel.vals.ptr.p_double[srcoffs]; + + /* + * Read/write columns 0...D-1 + */ + while(srcidxsparsel.idx.ptr.p_int[dstoffs] = srcidx; + s->sparsel.vals.ptr.p_double[dstoffs] = srcval; + dstoffs = dstoffs+1; + srcoffs = srcoffs+1; + srcidx = s->sparsel.idx.ptr.p_int[srcoffs]; + srcval = s->sparsel.vals.ptr.p_double[srcoffs]; + } + + /* + * If we have non-zero element in column D, use it as + * right-hand side of intermediate linear system which + * is used to determine coefficients of update matrix. + */ + if( srcidx==idxd ) + { + s->utmp0.ptr.p_double[i-1] = srcval; + srcoffs = srcoffs+1; + srcidx = s->sparsel.idx.ptr.p_int[srcoffs]; + srcval = s->sparsel.vals.ptr.p_double[srcoffs]; + } + + /* + * Process columns D+1...I-1 + */ + v = s->utmp0.ptr.p_double[i-1]; + while(srcidxsparsel.idx.ptr.p_int[dstoffs] = srcidx-1; + s->sparsel.vals.ptr.p_double[dstoffs] = srcval; + v = v-srcval*s->utmp0.ptr.p_double[srcidx-1]; + dstoffs = dstoffs+1; + srcoffs = srcoffs+1; + srcidx = s->sparsel.idx.ptr.p_int[srcoffs]; + srcval = s->sparsel.vals.ptr.p_double[srcoffs]; + } + s->utmp0.ptr.p_double[i-1] = v; + + /* + * Write out unit diagonal, finalize row + */ + s->sparsel.idx.ptr.p_int[dstoffs] = i-1; + s->sparsel.vals.ptr.p_double[dstoffs] = (double)(1); + dstoffs = dstoffs+1; + s->sparsel.ridx.ptr.p_int[i] = dstoffs; + } + s->utmp0.ptr.p_double[m-1] = (double)(1); + dstoffs = s->sparsel.ridx.ptr.p_int[m-1]; + for(j=0; j<=idxd-1; j++) + { + v = alphaqim->ptr.p_double[j]; + if( v!=(double)0 ) + { + s->sparsel.idx.ptr.p_int[dstoffs] = j; + s->sparsel.vals.ptr.p_double[dstoffs] = v; + dstoffs = dstoffs+1; + } + } + vcorner = alphaqim->ptr.p_double[idxd]; + for(j=idxd+1; j<=m-1; j++) + { + v = alphaqim->ptr.p_double[j]; + if( v!=(double)0 ) + { + s->sparsel.idx.ptr.p_int[dstoffs] = j-1; + s->sparsel.vals.ptr.p_double[dstoffs] = v; + dstoffs = dstoffs+1; + vcorner = vcorner-v*s->utmp0.ptr.p_double[j-1]; + } + } + s->sparsel.idx.ptr.p_int[dstoffs] = m-1; + s->sparsel.vals.ptr.p_double[dstoffs] = (double)(1); + dstoffs = dstoffs+1; + s->sparsel.ridx.ptr.p_int[m] = dstoffs; + s->sparsel.ninitialized = s->sparsel.ridx.ptr.p_int[m]; + for(i=0; i<=m-1; i++) + { + j = s->sparsel.ridx.ptr.p_int[i+1]; + s->sparsel.didx.ptr.p_int[i] = j-1; + s->sparsel.uidx.ptr.p_int[i] = j; + } + ae_assert(vcorner!=(double)0, "UpdateTrf: corner element is zero, degeneracy detected", _state); + v = (double)1/vcorner; + for(i=0; i<=m-2; i++) + { + s->densemu.ptr.p_double[s->trfage*m+i] = -s->utmp0.ptr.p_double[i]*v; + } + s->densemu.ptr.p_double[s->trfage*m+m-1] = v; + + /* + * Multiply row permutation matrix by cyclic permutation applied to L + */ + reviseddualsimplex_inversecyclicpermutation(&s->rowpermbwd, m, idxd, &s->utmpi, _state); + + /* + * Done + */ + inc(&s->trfage, _state); + s->statupdt = s->statupdt+1; + s->statoffdiag = s->statoffdiag+(double)(s->sparsel.ridx.ptr.p_int[m]-m)+(double)(s->sparseu.ridx.ptr.p_int[m]-m); + processed = ae_true; + } + ae_assert(processed, "BasisUpdateTrf: unexpected TRF type", _state); + } + + /* + * Update pricing weights + */ + ae_assert((settings->pricing==-1||settings->pricing==0)||settings->pricing==1, "BasisUpdateTrf: unexpected Settings.Pricing", _state); + processed = ae_false; + if( settings->pricing==-1 ) + { + + /* + * Weights are recomputed from scratch at every step. + * VERY, VERY time consuming, used only for debug purposes. + */ + s->dsevalid = ae_false; + reviseddualsimplex_basisrequestweights(s, settings, _state); + processed = ae_true; + } + if( settings->pricing==0 ) + { + + /* + * Weights are filled by 1.0 + */ + if( !s->dsevalid ) + { + for(i=0; i<=m-1; i++) + { + s->dseweights.ptr.p_double[i] = 1.0; + } + s->dsevalid = ae_true; + } + processed = ae_true; + } + if( settings->pricing==1 ) + { + + /* + * Weights are computed using DSE update formula. + */ + if( s->dsevalid ) + { + + /* + * Compute using update formula + */ + for(i=0; i<=m-1; i++) + { + if( i!=r ) + { + s->dseweights.ptr.p_double[i] = s->dseweights.ptr.p_double[i]-(double)2*(alphaq->ptr.p_double[i]/alphaq->ptr.p_double[r])*tau->ptr.p_double[i]+s->dseweights.ptr.p_double[r]*ae_sqr(alphaq->ptr.p_double[i]/alphaq->ptr.p_double[r], _state); + s->dseweights.ptr.p_double[i] = ae_maxreal(s->dseweights.ptr.p_double[i], reviseddualsimplex_minbeta, _state); + } + } + s->dseweights.ptr.p_double[r] = s->dseweights.ptr.p_double[r]/(alphaq->ptr.p_double[r]*alphaq->ptr.p_double[r]); + } + else + { + + /* + * No prior values, compute from scratch (usually it is done only once) + */ + reviseddualsimplex_basisrequestweights(s, settings, _state); + } + processed = ae_true; + } + ae_assert(processed, "BasisUpdateTrf: unexpected pricing type", _state); +} + + +/************************************************************************* +This function computes solution to B*x=r. + +Output array is reallocated if needed. Temporary array TmpX[] is used and +reallocated if necessary. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basissolve(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tmpx, + ae_state *_state) +{ + + + reviseddualsimplex_basissolvex(s, r, x, x, ae_false, tmpx, _state); +} + + +/************************************************************************* +This function computes solution to B*x=r. It also additionally outputs +intermediate result of multiplication by inv(DS)*inv(U)*inv(colPerm), a +value essential for Forest-Tomlin update. + +Output arrays are reallocated if needed. Temporary array TX[] can be +used/reallocated. + +If NeedIntermediate is False or Forest-Tomlin updates are not used, +then Xim[] is not referenced at all. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basissolvex(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* xim, + ae_bool needintermediate, + /* Real */ ae_vector* tx, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t d; + ae_int_t k; + double v; + double vd; + double vv; + ae_bool processed; + + + ae_assert(s->isvalidtrf, "BasisSolve: integrity check failed", _state); + m = s->m; + processed = ae_false; + rvectorsetlengthatleast(tx, m, _state); + + /* + * Dense/sparse factorizations with dense PFI + * + * NOTE: although we solve B*x=r, internally we store factorization of B^T + */ + if( (s->trftype==0||s->trftype==1)||s->trftype==2 ) + { + ae_assert(s->trfage==0||s->trftype!=0, "BasisSolve: integrity check failed TrfAge vs TrfType", _state); + rvectorsetlengthatleast(x, m, _state); + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = r->ptr.p_double[s->colpermbwd.ptr.p_int[i]]; + } + if( s->trftype==0||s->trftype==1 ) + { + + /* + * Dense TRF + */ + rmatrixtrsv(m, &s->denselu, 0, 0, ae_true, ae_false, 1, x, 0, _state); + rmatrixtrsv(m, &s->denselu, 0, 0, ae_false, ae_true, 1, x, 0, _state); + } + else + { + + /* + * Sparse TRF + */ + sparsetrsv(&s->sparseu, ae_true, ae_false, 1, x, _state); + sparsetrsv(&s->sparsel, ae_false, ae_false, 1, x, _state); + } + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[s->rowpermbwd.ptr.p_int[i]] = x->ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + for(k=0; k<=s->trfage-1; k++) + { + v = x->ptr.p_double[s->rk.ptr.p_int[k]]; + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]+s->densepfieta.ptr.p_double[k*m+i]*v; + } + x->ptr.p_double[s->rk.ptr.p_int[k]] = x->ptr.p_double[s->rk.ptr.p_int[k]]-v; + } + processed = ae_true; + } + + /* + * Sparse factorization with Forest-Tomlin update + * + * NOTE: although we solve B*x=r, internally we store factorization of B^T + */ + if( s->trftype==3 ) + { + rvectorsetlengthatleast(x, m, _state); + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = r->ptr.p_double[s->colpermbwd.ptr.p_int[i]]; + } + sparsetrsv(&s->sparseu, ae_true, ae_false, 1, x, _state); + for(k=0; k<=s->trfage-1; k++) + { + + /* + * The code below is an amalgamation of two parts: + * + * cyclic permutation + * V:=X[D]; + * for I:=D to M-2 do + * X[I]:=X[I+1]; + * X[M-1]:=V; + * + * and triangular factor + * V:=0; + * for I:=D to M-1 do + * V:=V+X[I]*S.DenseMu[K*M+I]; + * X[M-1]:=V; + */ + d = s->dk.ptr.p_int[k]; + vv = (double)(0); + vd = x->ptr.p_double[d]; + for(i=d; i<=m-2; i++) + { + v = x->ptr.p_double[i+1]; + x->ptr.p_double[i] = v; + vv = vv+v*s->densemu.ptr.p_double[k*m+i]; + } + x->ptr.p_double[m-1] = vv+vd*s->densemu.ptr.p_double[k*m+m-1]; + } + if( needintermediate ) + { + rvectorsetlengthatleast(xim, m, _state); + for(i=0; i<=m-1; i++) + { + xim->ptr.p_double[i] = x->ptr.p_double[i]; + } + } + sparsetrsv(&s->sparsel, ae_false, ae_false, 1, x, _state); + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[s->rowpermbwd.ptr.p_int[i]] = x->ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + processed = ae_true; + } + + /* + * Integrity check + */ + ae_assert(processed, "BasisSolve: unsupported TRF type", _state); + v = (double)(0); + for(i=0; i<=m-1; i++) + { + v = v+x->ptr.p_double[i]; + } + ae_assert(ae_isfinite(v, _state), "BasisSolve: integrity check failed (degeneracy in B?)", _state); +} + + +/************************************************************************* +This function computes solution to (B^T)*x=r. + +Output array is reallocated if needed. TX[] temporary is reallocated if +needed + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_basissolvet(const dualsimplexbasis* s, + /* Real */ const ae_vector* r, + /* Real */ ae_vector* x, + /* Real */ ae_vector* tx, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + ae_int_t d; + ae_int_t k; + double v; + double vm; + ae_bool processed; + + + ae_assert(s->isvalidtrf, "BasisSolveT: integrity check failed", _state); + m = s->m; + processed = ae_false; + rvectorsetlengthatleast(tx, m, _state); + + /* + * Dense factorizations + */ + if( (s->trftype==0||s->trftype==1)||s->trftype==2 ) + { + ae_assert(s->trfage==0||s->trftype!=0, "BasisSolveT: integrity check failed TrfAge vs TrfType", _state); + rvectorsetlengthatleast(x, m, _state); + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = r->ptr.p_double[i]; + } + for(k=s->trfage-1; k>=0; k--) + { + v = (double)(0); + for(i=0; i<=m-1; i++) + { + v = v+s->densepfieta.ptr.p_double[k*m+i]*x->ptr.p_double[i]; + } + x->ptr.p_double[s->rk.ptr.p_int[k]] = v; + } + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[i] = x->ptr.p_double[s->rowpermbwd.ptr.p_int[i]]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + if( s->trftype==0||s->trftype==1 ) + { + + /* + * Dense TRF + */ + rmatrixtrsv(m, &s->denselu, 0, 0, ae_false, ae_true, 0, x, 0, _state); + rmatrixtrsv(m, &s->denselu, 0, 0, ae_true, ae_false, 0, x, 0, _state); + } + else + { + + /* + * Sparse TRF + */ + sparsetrsv(&s->sparsel, ae_false, ae_false, 0, x, _state); + sparsetrsv(&s->sparseu, ae_true, ae_false, 0, x, _state); + } + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[s->colpermbwd.ptr.p_int[i]] = x->ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + processed = ae_true; + } + + /* + * Sparse factorization with Forest-Tomlin update + */ + if( s->trftype==3 ) + { + rvectorsetlengthatleast(x, m, _state); + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = r->ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[i] = x->ptr.p_double[s->rowpermbwd.ptr.p_int[i]]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + sparsetrsv(&s->sparsel, ae_false, ae_false, 0, x, _state); + for(k=s->trfage-1; k>=0; k--) + { + + /* + * The code below is an amalgamation of two parts: + * + * triangular factor + * V:=X[M-1]; + * for I:=D to M-2 do + * X[I]:=X[I]+S.DenseMu[K*M+I]*V; + * X[M-1]:=S.DenseMu[K*M+(M-1)]*V; + * + * inverse of cyclic permutation + * V:=X[M-1]; + * for I:=M-1 downto D+1 do + * X[I]:=X[I-1]; + * X[D]:=V; + */ + d = s->dk.ptr.p_int[k]; + vm = x->ptr.p_double[m-1]; + v = s->densemu.ptr.p_double[k*m+(m-1)]*vm; + if( vm!=(double)0 ) + { + + /* + * X[M-1] is non-zero, apply update + */ + for(i=m-2; i>=d; i--) + { + x->ptr.p_double[i+1] = x->ptr.p_double[i]+s->densemu.ptr.p_double[k*m+i]*vm; + } + } + else + { + + /* + * X[M-1] is zero, just cyclic permutation + */ + for(i=m-2; i>=d; i--) + { + x->ptr.p_double[i+1] = x->ptr.p_double[i]; + } + } + x->ptr.p_double[d] = v; + } + sparsetrsv(&s->sparseut, ae_false, ae_false, 1, x, _state); + for(i=0; i<=m-1; i++) + { + tx->ptr.p_double[s->colpermbwd.ptr.p_int[i]] = x->ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + x->ptr.p_double[i] = tx->ptr.p_double[i]; + } + processed = ae_true; + } + + /* + * Integrity check + */ + ae_assert(processed, "BasisSolveT: unsupported TRF type", _state); + v = (double)(0); + for(i=0; i<=m-1; i++) + { + v = v+x->ptr.p_double[i]; + } + ae_assert(ae_isfinite(v, _state), "BasisSolveT: integrity check failed (degeneracy in B?)", _state); +} + + +/************************************************************************* +This function computes product AN*XN, where AN is a non-basic subset of +columns of A, and XN is a non-basic subset of columns of X. + +Output array is reallocated if its size is too small. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_computeanxn(const dualsimplexstate* state, + const dualsimplexsubproblem* subproblem, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state) +{ + ae_int_t nn; + ae_int_t nx; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + double v; + + + nx = subproblem->ns+subproblem->m; + m = subproblem->m; + nn = nx-m; + + /* + * Integrity check + */ + ae_assert(subproblem->state>=reviseddualsimplex_ssvalidxn, "ComputeANXN: XN is invalid", _state); + + /* + * Compute + */ + rvectorsetlengthatleast(y, m, _state); + for(i=0; i<=m-1; i++) + { + y->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nn-1; i++) + { + j0 = state->at.ridx.ptr.p_int[state->basis.nidx.ptr.p_int[i]]; + j1 = state->at.ridx.ptr.p_int[state->basis.nidx.ptr.p_int[i]+1]-1; + v = x->ptr.p_double[state->basis.nidx.ptr.p_int[i]]; + for(j=j0; j<=j1; j++) + { + k = state->at.idx.ptr.p_int[j]; + y->ptr.p_double[k] = y->ptr.p_double[k]+v*state->at.vals.ptr.p_double[j]; + } + } +} + + +/************************************************************************* +This function computes product (AN^T)*y, where AN is a non-basic subset of +columns of A, and y is some vector. + +Output array is set to full NX-sized length, with basic components of the +output being set to zeros. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_computeantv(const dualsimplexstate* state, + /* Real */ const ae_vector* y, + /* Real */ ae_vector* r, + ae_state *_state) +{ + ae_int_t nn; + ae_int_t nx; + ae_int_t m; + ae_int_t i; + ae_int_t j; + ae_int_t j0; + ae_int_t j1; + double v; + + + nx = state->ns+state->m; + m = state->m; + nn = nx-m; + + /* + * Allocate output, set to zero + */ + rvectorsetlengthatleast(r, nx, _state); + for(i=0; i<=nx-1; i++) + { + r->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nn-1; i++) + { + j0 = state->at.ridx.ptr.p_int[state->basis.nidx.ptr.p_int[i]]; + j1 = state->at.ridx.ptr.p_int[state->basis.nidx.ptr.p_int[i]+1]-1; + v = (double)(0); + for(j=j0; j<=j1; j++) + { + v = v+state->at.vals.ptr.p_double[j]*y->ptr.p_double[state->at.idx.ptr.p_int[j]]; + } + r->ptr.p_double[state->basis.nidx.ptr.p_int[i]] = v; + } +} + + +/************************************************************************* +Returns True if I-th lower bound is present + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_hasbndl(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state) +{ + ae_int_t k; + ae_bool result; + + + k = subproblem->bndt.ptr.p_int[i]; + result = ae_false; + if( (k==0||k==1)||k==3 ) + { + result = ae_true; + return result; + } + if( k==2||k==4 ) + { + result = ae_false; + return result; + } + ae_assert(ae_false, "HasBndL: integrity check failed", _state); + return result; +} + + +/************************************************************************* +Returns True if I-th upper bound is present + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_hasbndu(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state) +{ + ae_int_t k; + ae_bool result; + + + k = subproblem->bndt.ptr.p_int[i]; + result = ae_false; + if( (k==0||k==2)||k==3 ) + { + result = ae_true; + return result; + } + if( k==1||k==4 ) + { + result = ae_false; + return result; + } + ae_assert(ae_false, "HasBndL: integrity check failed", _state); + return result; +} + + +/************************************************************************* +Returns True if I-th variable if free + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_isfree(const dualsimplexsubproblem* subproblem, + ae_int_t i, + ae_state *_state) +{ + ae_int_t k; + ae_bool result; + + + k = subproblem->bndt.ptr.p_int[i]; + result = ae_false; + if( ((k==0||k==1)||k==2)||k==3 ) + { + result = ae_false; + return result; + } + if( k==4 ) + { + result = ae_true; + return result; + } + ae_assert(ae_false, "IsFree: integrity check failed", _state); + return result; +} + + +/************************************************************************* +Downgrades problem state to the specified one (if status is lower than one +specified by user, nothing is changed) + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_downgradestate(dualsimplexsubproblem* subproblem, + ae_int_t s, + ae_state *_state) +{ + + + subproblem->state = ae_minint(subproblem->state, s, _state); +} + + +/************************************************************************* +Returns maximum dual infeasibility (only non-basic variables are checked, +we assume that basic variables are good enough). + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static double reviseddualsimplex_dualfeasibilityerror(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nn; + ae_int_t bndt; + double result; + + + nn = s->ns; + ae_assert(s->state==reviseddualsimplex_ssvalid, "DualFeasibilityError: invalid X", _state); + result = (double)(0); + for(i=0; i<=nn-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + bndt = s->bndt.ptr.p_int[j]; + if( bndt==reviseddualsimplex_ccfixed ) + { + continue; + } + if( bndt==reviseddualsimplex_ccrange ) + { + if( s->xa.ptr.p_double[j]==s->bndl.ptr.p_double[j] ) + { + result = ae_maxreal(result, -s->d.ptr.p_double[j], _state); + continue; + } + if( s->xa.ptr.p_double[j]==s->bndu.ptr.p_double[j] ) + { + result = ae_maxreal(result, s->d.ptr.p_double[j], _state); + continue; + } + ae_assert(ae_false, "DualFeasibilityError: integrity check failed", _state); + } + if( bndt==reviseddualsimplex_cclower ) + { + ae_assert(s->xa.ptr.p_double[j]==s->bndl.ptr.p_double[j], "DualFeasibilityError: integrity check failed", _state); + result = ae_maxreal(result, -s->d.ptr.p_double[j], _state); + continue; + } + if( bndt==reviseddualsimplex_ccupper ) + { + ae_assert(s->xa.ptr.p_double[j]==s->bndu.ptr.p_double[j], "DualFeasibilityError: integrity check failed", _state); + result = ae_maxreal(result, s->d.ptr.p_double[j], _state); + continue; + } + if( bndt==reviseddualsimplex_ccfree ) + { + result = ae_maxreal(result, ae_fabs(s->d.ptr.p_double[j], _state), _state); + continue; + } + ae_assert(ae_false, "DSSOptimize: integrity check failed (infeasible constraint)", _state); + } + return result; +} + + +/************************************************************************* +Returns True for dual feasible basis (some minor dual feasibility error is +allowed), False otherwise + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +static ae_bool reviseddualsimplex_isdualfeasible(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_bool result; + + + result = ae_fp_less_eq(reviseddualsimplex_dualfeasibilityerror(state, s, _state),settings->dtolabs); + return result; +} + + +/************************************************************************* +Transforms sequence of pivot permutations P0*P1*...*Pm to forward/backward +permutation representation. + + -- ALGLIB -- + Copyright 12.09.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_pivottobwd(/* Integer */ const ae_vector* p, + ae_int_t m, + /* Integer */ ae_vector* bwd, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_int_t t; + + + ivectorsetlengthatleast(bwd, m, _state); + for(i=0; i<=m-1; i++) + { + bwd->ptr.p_int[i] = i; + } + for(i=0; i<=m-1; i++) + { + k = p->ptr.p_int[i]; + if( k!=i ) + { + t = bwd->ptr.p_int[i]; + bwd->ptr.p_int[i] = bwd->ptr.p_int[k]; + bwd->ptr.p_int[k] = t; + } + } +} + + +/************************************************************************* +Applies inverse cyclic permutation of [D,M-1) (element D is moved to the end, the +rest of elements is shifted one position backward) to the already existing +permutation. + + -- ALGLIB -- + Copyright 12.09.2018 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_inversecyclicpermutation(/* Integer */ ae_vector* bwd, + ae_int_t m, + ae_int_t d, + /* Integer */ ae_vector* tmpi, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + + + + /* + * update Bwd[] + */ + k = bwd->ptr.p_int[d]; + for(i=d; i<=m-2; i++) + { + bwd->ptr.p_int[i] = bwd->ptr.p_int[i+1]; + } + bwd->ptr.p_int[m-1] = k; +} + + +/************************************************************************* +Offloads basic components of X[], BndT[], BndL[], BndU[] to XB/BndTB/BndLB/BndUB. + + -- ALGLIB -- + Copyright 24.01.2019 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_offloadbasiccomponents(dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + const dualsimplexsettings* settings, + ae_state *_state) +{ + ae_int_t i; + ae_int_t m; + + + m = basis->m; + for(i=0; i<=m-1; i++) + { + s->xb.ptr.p_double[i] = s->xa.ptr.p_double[basis->idx.ptr.p_int[i]]; + reviseddualsimplex_cacheboundinfo(s, i, basis->idx.ptr.p_int[i], settings, _state); + } +} + + +/************************************************************************* +Recombines basic and non-basic components in X[] + + -- ALGLIB -- + Copyright 24.01.2019 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_recombinebasicnonbasicx(dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + ae_state *_state) +{ + ae_int_t m; + ae_int_t i; + + + m = basis->m; + for(i=0; i<=m-1; i++) + { + s->xa.ptr.p_double[basis->idx.ptr.p_int[i]] = s->xb.ptr.p_double[i]; + } +} + + +/************************************************************************* +Computes Stats array + +INPUT PARAMETERS: + S - problem, contains current solution at S.XA + Basis - basis + X - possibly preallocated output buffer + LagBC - possibly preallocated output buffer + LagLC - possibly preallocated output buffer + Stats - possibly preallocated output buffer + Buffers - temporary buffers + +OUTPUT PARAMETERS: + X - array[NS], solution + LagBC - array[NS], Lagrange multipliers for box constraints + LagLC - array[M], Lagrange multipliers for linear constraints + Stats - array[NS+M], primary/slack variable stats: + * -1 = variable at lower bound + * +1 = variable at upper bound + * 0 = basic or free (possibly nonbasic) variable + fixed variables may be set to +1 or -1 + + -- ALGLIB -- + Copyright 24.01.2019 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_setxydstats(const dualsimplexstate* state, + const dualsimplexsubproblem* s, + const dualsimplexbasis* basis, + apbuffers* buffers, + /* Real */ ae_vector* x, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Integer */ ae_vector* stats, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t m; + ae_int_t ns; + ae_int_t nx; + + + + /* + * Prepare + */ + m = s->m; + ns = s->ns; + nx = s->ns+s->m; + rvectorsetlengthatleast(x, ns, _state); + rvectorsetlengthatleast(laglc, m, _state); + ivectorsetlengthatleast(stats, nx, _state); + rsetallocv(ns, 0.0, lagbc, _state); + + /* + * Compute Y (in Buffers.RA1) and D (in Buffers.RA3) + */ + rvectorsetlengthatleast(&buffers->ra0, m, _state); + rvectorsetlengthatleast(&buffers->ra1, m, _state); + rvectorsetlengthatleast(&buffers->ra3, nx, _state); + for(i=0; i<=m-1; i++) + { + buffers->ra0.ptr.p_double[i] = s->rawc.ptr.p_double[basis->idx.ptr.p_int[i]]; + } + reviseddualsimplex_basissolvet(basis, &buffers->ra0, &buffers->ra1, &buffers->ra2, _state); + reviseddualsimplex_computeantv(state, &buffers->ra1, &buffers->ra3, _state); + for(i=0; i<=ns-1; i++) + { + j = state->basis.nidx.ptr.p_int[i]; + buffers->ra3.ptr.p_double[j] = state->primary.rawc.ptr.p_double[j]-buffers->ra3.ptr.p_double[j]; + if( jptr.p_double[j] = -buffers->ra3.ptr.p_double[j]; + } + } + for(i=0; i<=m-1; i++) + { + buffers->ra3.ptr.p_double[state->basis.idx.ptr.p_int[i]] = (double)(0); + } + + /* + * Compute X, Y, Stats + */ + for(i=0; i<=ns-1; i++) + { + x->ptr.p_double[i] = s->xa.ptr.p_double[i]; + if( ae_isfinite(state->rawbndl.ptr.p_double[i], _state) ) + { + x->ptr.p_double[i] = ae_maxreal(x->ptr.p_double[i], state->rawbndl.ptr.p_double[i], _state); + } + if( ae_isfinite(state->rawbndu.ptr.p_double[i], _state) ) + { + x->ptr.p_double[i] = ae_minreal(x->ptr.p_double[i], state->rawbndu.ptr.p_double[i], _state); + } + } + for(i=0; i<=ns-1; i++) + { + if( basis->isbasic.ptr.p_bool[i] ) + { + lagbc->ptr.p_double[i] = (double)(0); + continue; + } + if( s->bndt.ptr.p_int[i]==reviseddualsimplex_ccfixed ) + { + continue; + } + if( reviseddualsimplex_hasbndl(s, i, _state)&&ae_fp_eq(s->xa.ptr.p_double[i],s->bndl.ptr.p_double[i]) ) + { + lagbc->ptr.p_double[i] = ae_minreal(lagbc->ptr.p_double[i], 0.0, _state); + continue; + } + if( reviseddualsimplex_hasbndu(s, i, _state)&&ae_fp_eq(s->xa.ptr.p_double[i],s->bndu.ptr.p_double[i]) ) + { + lagbc->ptr.p_double[i] = ae_maxreal(lagbc->ptr.p_double[i], 0.0, _state); + continue; + } + ae_assert(!reviseddualsimplex_hasbndl(s, i, _state)&&!reviseddualsimplex_hasbndu(s, i, _state), "SetStats: integrity check failed (zetta5)", _state); + lagbc->ptr.p_double[i] = (double)(0); + } + for(i=0; i<=m-1; i++) + { + laglc->ptr.p_double[i] = -buffers->ra1.ptr.p_double[i]/state->rowscales.ptr.p_double[i]; + } + for(i=0; i<=nx-1; i++) + { + if( basis->isbasic.ptr.p_bool[i] ) + { + stats->ptr.p_int[i] = 0; + continue; + } + if( reviseddualsimplex_hasbndl(s, i, _state)&&ae_fp_eq(s->xa.ptr.p_double[i],s->bndl.ptr.p_double[i]) ) + { + stats->ptr.p_int[i] = -1; + continue; + } + if( reviseddualsimplex_hasbndu(s, i, _state)&&ae_fp_eq(s->xa.ptr.p_double[i],s->bndu.ptr.p_double[i]) ) + { + stats->ptr.p_int[i] = 1; + continue; + } + ae_assert(!reviseddualsimplex_hasbndl(s, i, _state)&&!reviseddualsimplex_hasbndu(s, i, _state), "SetStats: integrity check failed (zetta5)", _state); + stats->ptr.p_int[i] = 0; + } +} + + +/************************************************************************* +Initializes vector, sets all internal arrays to length N (so that we may +store any vector without reallocation). Previously allocated memory is +reused as much as possible. + +No zero-filling is performed, X.K is undefined. Only X.N is set. + +INPUT PARAMETERS: + X - temporary buffers + +OUTPUT PARAMETERS: + X - preallocated vector, X.N=N, contents undefined + + -- ALGLIB -- + Copyright 24.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_dvalloc(dssvector* x, + ae_int_t n, + ae_state *_state) +{ + + + ivectorsetlengthatleast(&x->idx, n, _state); + rvectorsetlengthatleast(&x->vals, n, _state); + rvectorsetlengthatleast(&x->dense, n, _state); + x->n = n; +} + + +/************************************************************************* +Initializes vector, sets all internal arrays to length N and zero-fills +them. Previously allocated memory is reused as much as possible. + +INPUT PARAMETERS: + X - temporary buffers + +OUTPUT PARAMETERS: + X - preallocated vector: + * X.N=N + * X.K=0 + * X.Dense is zero-filled. + + -- ALGLIB -- + Copyright 24.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_dvinit(dssvector* x, + ae_int_t n, + ae_state *_state) +{ + + + ivectorsetlengthatleast(&x->idx, n, _state); + rvectorsetlengthatleast(&x->vals, n, _state); + rvectorsetlengthatleast(&x->dense, n, _state); + rsetv(n, 0.0, &x->dense, _state); + x->n = n; + x->k = 0; +} + + +/************************************************************************* +Copies dense part to sparse one. + +INPUT PARAMETERS: + X - allocated vector; dense part must be valid + +OUTPUT PARAMETERS: + X - both dense and sparse parts are valid. + + -- ALGLIB -- + Copyright 24.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_dvdensetosparse(dssvector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t k; + double v; + + + n = x->n; + ivectorsetlengthatleast(&x->idx, n, _state); + rvectorsetlengthatleast(&x->vals, n, _state); + k = 0; + for(i=0; i<=n-1; i++) + { + v = x->dense.ptr.p_double[i]; + if( v!=0.0 ) + { + x->idx.ptr.p_int[k] = i; + x->vals.ptr.p_double[k] = v; + k = k+1; + } + } + x->k = k; +} + + +/************************************************************************* +Copies sparse part to dense one. + +INPUT PARAMETERS: + X - allocated vector; sparse part must be valid + +OUTPUT PARAMETERS: + X - both dense and sparse parts are valid. + + -- ALGLIB -- + Copyright 24.07.2020 by Bochkanov Sergey +*************************************************************************/ +static void reviseddualsimplex_dvsparsetodense(dssvector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t k; + + + n = x->n; + k = x->k; + rsetv(n, 0.0, &x->dense, _state); + for(i=0; i<=k-1; i++) + { + x->dense.ptr.p_double[x->idx.ptr.p_int[i]] = x->vals.ptr.p_double[i]; + } +} + + +static double reviseddualsimplex_sparsityof(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double mx; + double result; + + + if( n<=1 ) + { + result = (double)(0); + return result; + } + mx = 1.0; + for(i=0; i<=n-1; i++) + { + mx = ae_maxreal(mx, ae_fabs(x->ptr.p_double[i], _state), _state); + } + mx = 1.0E5*ae_machineepsilon*mx; + k = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(ae_fabs(x->ptr.p_double[i], _state),mx) ) + { + k = k+1; + } + } + result = (double)k/(double)n; + return result; +} + + +static void reviseddualsimplex_updateavgcounter(double v, + double* acc, + ae_int_t* cnt, + ae_state *_state) +{ + + + *acc = *acc+v; + *cnt = *cnt+1; +} + + +void _dualsimplexsettings_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexsettings *p = (dualsimplexsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _dualsimplexsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexsettings *dst = (dualsimplexsettings*)_dst; + const dualsimplexsettings *src = (const dualsimplexsettings*)_src; + dst->pivottol = src->pivottol; + dst->perturbmag = src->perturbmag; + dst->maxtrfage = src->maxtrfage; + dst->trftype = src->trftype; + dst->ratiotest = src->ratiotest; + dst->pricing = src->pricing; + dst->shifting = src->shifting; + dst->xtolabs = src->xtolabs; + dst->xtolrelabs = src->xtolrelabs; + dst->dtolabs = src->dtolabs; +} + + +void _dualsimplexsettings_clear(void* _p) +{ + dualsimplexsettings *p = (dualsimplexsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _dualsimplexsettings_destroy(void* _p) +{ + dualsimplexsettings *p = (dualsimplexsettings*)_p; + ae_touch_ptr((void*)p); +} + + +void _dssvector_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dssvector *p = (dssvector*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->vals, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dense, 0, DT_REAL, _state, make_automatic); +} + + +void _dssvector_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dssvector *dst = (dssvector*)_dst; + const dssvector *src = (const dssvector*)_src; + dst->n = src->n; + dst->k = src->k; + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->vals, &src->vals, _state, make_automatic); + ae_vector_init_copy(&dst->dense, &src->dense, _state, make_automatic); +} + + +void _dssvector_clear(void* _p) +{ + dssvector *p = (dssvector*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->vals); + ae_vector_clear(&p->dense); +} + + +void _dssvector_destroy(void* _p) +{ + dssvector *p = (dssvector*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->vals); + ae_vector_destroy(&p->dense); +} + + +void _dualsimplexbasis_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexbasis *p = (dualsimplexbasis*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->idx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->isbasic, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->denselu, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsel, _state, make_automatic); + _sparsematrix_init(&p->sparseu, _state, make_automatic); + _sparsematrix_init(&p->sparseut, _state, make_automatic); + ae_vector_init(&p->rowpermbwd, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->colpermbwd, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->densepfieta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->densemu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rk, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->dk, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->dseweights, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wtmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wtmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wtmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nrs, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tcinvidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->denselu2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->densep2, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->densep2c, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->sparselu1, _state, make_automatic); + _sparsematrix_init(&p->sparselu2, _state, make_automatic); + _sluv2buffer_init(&p->lubuf2, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->utmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->utmpi, 0, DT_INT, _state, make_automatic); + _sparsematrix_init(&p->sparseludbg, _state, make_automatic); +} + + +void _dualsimplexbasis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexbasis *dst = (dualsimplexbasis*)_dst; + const dualsimplexbasis *src = (const dualsimplexbasis*)_src; + dst->ns = src->ns; + dst->m = src->m; + ae_vector_init_copy(&dst->idx, &src->idx, _state, make_automatic); + ae_vector_init_copy(&dst->nidx, &src->nidx, _state, make_automatic); + ae_vector_init_copy(&dst->isbasic, &src->isbasic, _state, make_automatic); + dst->trftype = src->trftype; + dst->isvalidtrf = src->isvalidtrf; + dst->trfage = src->trfage; + ae_matrix_init_copy(&dst->denselu, &src->denselu, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsel, &src->sparsel, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseu, &src->sparseu, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseut, &src->sparseut, _state, make_automatic); + ae_vector_init_copy(&dst->rowpermbwd, &src->rowpermbwd, _state, make_automatic); + ae_vector_init_copy(&dst->colpermbwd, &src->colpermbwd, _state, make_automatic); + ae_vector_init_copy(&dst->densepfieta, &src->densepfieta, _state, make_automatic); + ae_vector_init_copy(&dst->densemu, &src->densemu, _state, make_automatic); + ae_vector_init_copy(&dst->rk, &src->rk, _state, make_automatic); + ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic); + ae_vector_init_copy(&dst->dseweights, &src->dseweights, _state, make_automatic); + dst->dsevalid = src->dsevalid; + dst->eminu = src->eminu; + dst->statfact = src->statfact; + dst->statupdt = src->statupdt; + dst->statoffdiag = src->statoffdiag; + ae_vector_init_copy(&dst->wtmp0, &src->wtmp0, _state, make_automatic); + ae_vector_init_copy(&dst->wtmp1, &src->wtmp1, _state, make_automatic); + ae_vector_init_copy(&dst->wtmp2, &src->wtmp2, _state, make_automatic); + ae_vector_init_copy(&dst->nrs, &src->nrs, _state, make_automatic); + ae_vector_init_copy(&dst->tcinvidx, &src->tcinvidx, _state, make_automatic); + ae_matrix_init_copy(&dst->denselu2, &src->denselu2, _state, make_automatic); + ae_vector_init_copy(&dst->densep2, &src->densep2, _state, make_automatic); + ae_vector_init_copy(&dst->densep2c, &src->densep2c, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparselu1, &src->sparselu1, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparselu2, &src->sparselu2, _state, make_automatic); + _sluv2buffer_init_copy(&dst->lubuf2, &src->lubuf2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); + ae_vector_init_copy(&dst->utmp0, &src->utmp0, _state, make_automatic); + ae_vector_init_copy(&dst->utmpi, &src->utmpi, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparseludbg, &src->sparseludbg, _state, make_automatic); +} + + +void _dualsimplexbasis_clear(void* _p) +{ + dualsimplexbasis *p = (dualsimplexbasis*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->idx); + ae_vector_clear(&p->nidx); + ae_vector_clear(&p->isbasic); + ae_matrix_clear(&p->denselu); + _sparsematrix_clear(&p->sparsel); + _sparsematrix_clear(&p->sparseu); + _sparsematrix_clear(&p->sparseut); + ae_vector_clear(&p->rowpermbwd); + ae_vector_clear(&p->colpermbwd); + ae_vector_clear(&p->densepfieta); + ae_vector_clear(&p->densemu); + ae_vector_clear(&p->rk); + ae_vector_clear(&p->dk); + ae_vector_clear(&p->dseweights); + ae_vector_clear(&p->wtmp0); + ae_vector_clear(&p->wtmp1); + ae_vector_clear(&p->wtmp2); + ae_vector_clear(&p->nrs); + ae_vector_clear(&p->tcinvidx); + ae_matrix_clear(&p->denselu2); + ae_vector_clear(&p->densep2); + ae_vector_clear(&p->densep2c); + _sparsematrix_clear(&p->sparselu1); + _sparsematrix_clear(&p->sparselu2); + _sluv2buffer_clear(&p->lubuf2); + ae_vector_clear(&p->tmpi); + ae_vector_clear(&p->utmp0); + ae_vector_clear(&p->utmpi); + _sparsematrix_clear(&p->sparseludbg); +} + + +void _dualsimplexbasis_destroy(void* _p) +{ + dualsimplexbasis *p = (dualsimplexbasis*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->idx); + ae_vector_destroy(&p->nidx); + ae_vector_destroy(&p->isbasic); + ae_matrix_destroy(&p->denselu); + _sparsematrix_destroy(&p->sparsel); + _sparsematrix_destroy(&p->sparseu); + _sparsematrix_destroy(&p->sparseut); + ae_vector_destroy(&p->rowpermbwd); + ae_vector_destroy(&p->colpermbwd); + ae_vector_destroy(&p->densepfieta); + ae_vector_destroy(&p->densemu); + ae_vector_destroy(&p->rk); + ae_vector_destroy(&p->dk); + ae_vector_destroy(&p->dseweights); + ae_vector_destroy(&p->wtmp0); + ae_vector_destroy(&p->wtmp1); + ae_vector_destroy(&p->wtmp2); + ae_vector_destroy(&p->nrs); + ae_vector_destroy(&p->tcinvidx); + ae_matrix_destroy(&p->denselu2); + ae_vector_destroy(&p->densep2); + ae_vector_destroy(&p->densep2c); + _sparsematrix_destroy(&p->sparselu1); + _sparsematrix_destroy(&p->sparselu2); + _sluv2buffer_destroy(&p->lubuf2); + ae_vector_destroy(&p->tmpi); + ae_vector_destroy(&p->utmp0); + ae_vector_destroy(&p->utmpi); + _sparsematrix_destroy(&p->sparseludbg); +} + + +void _dualsimplexsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexsubproblem *p = (dualsimplexsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rawc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndt, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xa, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndlb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndub, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndtb, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->bndtollb, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndtolub, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->effc, 0, DT_REAL, _state, make_automatic); +} + + +void _dualsimplexsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexsubproblem *dst = (dualsimplexsubproblem*)_dst; + const dualsimplexsubproblem *src = (const dualsimplexsubproblem*)_src; + dst->ns = src->ns; + dst->m = src->m; + ae_vector_init_copy(&dst->rawc, &src->rawc, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndt, &src->bndt, _state, make_automatic); + ae_vector_init_copy(&dst->xa, &src->xa, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->state = src->state; + ae_vector_init_copy(&dst->xb, &src->xb, _state, make_automatic); + ae_vector_init_copy(&dst->bndlb, &src->bndlb, _state, make_automatic); + ae_vector_init_copy(&dst->bndub, &src->bndub, _state, make_automatic); + ae_vector_init_copy(&dst->bndtb, &src->bndtb, _state, make_automatic); + ae_vector_init_copy(&dst->bndtollb, &src->bndtollb, _state, make_automatic); + ae_vector_init_copy(&dst->bndtolub, &src->bndtolub, _state, make_automatic); + ae_vector_init_copy(&dst->effc, &src->effc, _state, make_automatic); +} + + +void _dualsimplexsubproblem_clear(void* _p) +{ + dualsimplexsubproblem *p = (dualsimplexsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rawc); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->bndt); + ae_vector_clear(&p->xa); + ae_vector_clear(&p->d); + ae_vector_clear(&p->xb); + ae_vector_clear(&p->bndlb); + ae_vector_clear(&p->bndub); + ae_vector_clear(&p->bndtb); + ae_vector_clear(&p->bndtollb); + ae_vector_clear(&p->bndtolub); + ae_vector_clear(&p->effc); +} + + +void _dualsimplexsubproblem_destroy(void* _p) +{ + dualsimplexsubproblem *p = (dualsimplexsubproblem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rawc); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->bndt); + ae_vector_destroy(&p->xa); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->xb); + ae_vector_destroy(&p->bndlb); + ae_vector_destroy(&p->bndub); + ae_vector_destroy(&p->bndtb); + ae_vector_destroy(&p->bndtollb); + ae_vector_destroy(&p->bndtolub); + ae_vector_destroy(&p->effc); +} + + +void _dualsimplexstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexstate *p = (dualsimplexstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rowscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawbndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->a, _state, make_automatic); + _sparsematrix_init(&p->at, _state, make_automatic); + _dualsimplexbasis_init(&p->basis, _state, make_automatic); + _dualsimplexsubproblem_init(&p->primary, _state, make_automatic); + _dualsimplexsubproblem_init(&p->phase1, _state, make_automatic); + _dualsimplexsubproblem_init(&p->phase3, _state, make_automatic); + ae_vector_init(&p->repx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->repstats, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->btrantmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->btrantmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->btrantmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ftrantmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ftrantmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->possibleflips, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->dfctmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dfctmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dfctmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ustmpi, 0, DT_INT, _state, make_automatic); + _apbuffers_init(&p->xydsbuf, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + _dssvector_init(&p->alphar, _state, make_automatic); + _dssvector_init(&p->rhor, _state, make_automatic); + ae_vector_init(&p->tau, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alphaq, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->alphaqim, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eligiblealphar, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->harrisset, 0, DT_INT, _state, make_automatic); +} + + +void _dualsimplexstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + dualsimplexstate *dst = (dualsimplexstate*)_dst; + const dualsimplexstate *src = (const dualsimplexstate*)_src; + ae_vector_init_copy(&dst->rowscales, &src->rowscales, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndl, &src->rawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->rawbndu, &src->rawbndu, _state, make_automatic); + dst->ns = src->ns; + dst->m = src->m; + _sparsematrix_init_copy(&dst->a, &src->a, _state, make_automatic); + _sparsematrix_init_copy(&dst->at, &src->at, _state, make_automatic); + _dualsimplexbasis_init_copy(&dst->basis, &src->basis, _state, make_automatic); + _dualsimplexsubproblem_init_copy(&dst->primary, &src->primary, _state, make_automatic); + _dualsimplexsubproblem_init_copy(&dst->phase1, &src->phase1, _state, make_automatic); + _dualsimplexsubproblem_init_copy(&dst->phase3, &src->phase3, _state, make_automatic); + ae_vector_init_copy(&dst->repx, &src->repx, _state, make_automatic); + ae_vector_init_copy(&dst->replagbc, &src->replagbc, _state, make_automatic); + ae_vector_init_copy(&dst->replaglc, &src->replaglc, _state, make_automatic); + ae_vector_init_copy(&dst->repstats, &src->repstats, _state, make_automatic); + dst->repterminationtype = src->repterminationtype; + dst->repiterationscount = src->repiterationscount; + dst->repiterationscount1 = src->repiterationscount1; + dst->repiterationscount2 = src->repiterationscount2; + dst->repiterationscount3 = src->repiterationscount3; + dst->repphase1time = src->repphase1time; + dst->repphase2time = src->repphase2time; + dst->repphase3time = src->repphase3time; + dst->repdualpricingtime = src->repdualpricingtime; + dst->repdualbtrantime = src->repdualbtrantime; + dst->repdualpivotrowtime = src->repdualpivotrowtime; + dst->repdualratiotesttime = src->repdualratiotesttime; + dst->repdualftrantime = src->repdualftrantime; + dst->repdualupdatesteptime = src->repdualupdatesteptime; + dst->repfillpivotrow = src->repfillpivotrow; + dst->repfillpivotrowcnt = src->repfillpivotrowcnt; + dst->repfillrhor = src->repfillrhor; + dst->repfillrhorcnt = src->repfillrhorcnt; + dst->repfilldensemu = src->repfilldensemu; + dst->repfilldensemucnt = src->repfilldensemucnt; + dst->dotrace = src->dotrace; + dst->dodetailedtrace = src->dodetailedtrace; + dst->dotimers = src->dotimers; + ae_vector_init_copy(&dst->btrantmp0, &src->btrantmp0, _state, make_automatic); + ae_vector_init_copy(&dst->btrantmp1, &src->btrantmp1, _state, make_automatic); + ae_vector_init_copy(&dst->btrantmp2, &src->btrantmp2, _state, make_automatic); + ae_vector_init_copy(&dst->ftrantmp0, &src->ftrantmp0, _state, make_automatic); + ae_vector_init_copy(&dst->ftrantmp1, &src->ftrantmp1, _state, make_automatic); + ae_vector_init_copy(&dst->possibleflips, &src->possibleflips, _state, make_automatic); + dst->possibleflipscnt = src->possibleflipscnt; + ae_vector_init_copy(&dst->dfctmp0, &src->dfctmp0, _state, make_automatic); + ae_vector_init_copy(&dst->dfctmp1, &src->dfctmp1, _state, make_automatic); + ae_vector_init_copy(&dst->dfctmp2, &src->dfctmp2, _state, make_automatic); + ae_vector_init_copy(&dst->ustmpi, &src->ustmpi, _state, make_automatic); + _apbuffers_init_copy(&dst->xydsbuf, &src->xydsbuf, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + _dssvector_init_copy(&dst->alphar, &src->alphar, _state, make_automatic); + _dssvector_init_copy(&dst->rhor, &src->rhor, _state, make_automatic); + ae_vector_init_copy(&dst->tau, &src->tau, _state, make_automatic); + ae_vector_init_copy(&dst->alphaq, &src->alphaq, _state, make_automatic); + ae_vector_init_copy(&dst->alphaqim, &src->alphaqim, _state, make_automatic); + ae_vector_init_copy(&dst->eligiblealphar, &src->eligiblealphar, _state, make_automatic); + ae_vector_init_copy(&dst->harrisset, &src->harrisset, _state, make_automatic); +} + + +void _dualsimplexstate_clear(void* _p) +{ + dualsimplexstate *p = (dualsimplexstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rowscales); + ae_vector_clear(&p->rawbndl); + ae_vector_clear(&p->rawbndu); + _sparsematrix_clear(&p->a); + _sparsematrix_clear(&p->at); + _dualsimplexbasis_clear(&p->basis); + _dualsimplexsubproblem_clear(&p->primary); + _dualsimplexsubproblem_clear(&p->phase1); + _dualsimplexsubproblem_clear(&p->phase3); + ae_vector_clear(&p->repx); + ae_vector_clear(&p->replagbc); + ae_vector_clear(&p->replaglc); + ae_vector_clear(&p->repstats); + ae_vector_clear(&p->btrantmp0); + ae_vector_clear(&p->btrantmp1); + ae_vector_clear(&p->btrantmp2); + ae_vector_clear(&p->ftrantmp0); + ae_vector_clear(&p->ftrantmp1); + ae_vector_clear(&p->possibleflips); + ae_vector_clear(&p->dfctmp0); + ae_vector_clear(&p->dfctmp1); + ae_vector_clear(&p->dfctmp2); + ae_vector_clear(&p->ustmpi); + _apbuffers_clear(&p->xydsbuf); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + _dssvector_clear(&p->alphar); + _dssvector_clear(&p->rhor); + ae_vector_clear(&p->tau); + ae_vector_clear(&p->alphaq); + ae_vector_clear(&p->alphaqim); + ae_vector_clear(&p->eligiblealphar); + ae_vector_clear(&p->harrisset); +} + + +void _dualsimplexstate_destroy(void* _p) +{ + dualsimplexstate *p = (dualsimplexstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rowscales); + ae_vector_destroy(&p->rawbndl); + ae_vector_destroy(&p->rawbndu); + _sparsematrix_destroy(&p->a); + _sparsematrix_destroy(&p->at); + _dualsimplexbasis_destroy(&p->basis); + _dualsimplexsubproblem_destroy(&p->primary); + _dualsimplexsubproblem_destroy(&p->phase1); + _dualsimplexsubproblem_destroy(&p->phase3); + ae_vector_destroy(&p->repx); + ae_vector_destroy(&p->replagbc); + ae_vector_destroy(&p->replaglc); + ae_vector_destroy(&p->repstats); + ae_vector_destroy(&p->btrantmp0); + ae_vector_destroy(&p->btrantmp1); + ae_vector_destroy(&p->btrantmp2); + ae_vector_destroy(&p->ftrantmp0); + ae_vector_destroy(&p->ftrantmp1); + ae_vector_destroy(&p->possibleflips); + ae_vector_destroy(&p->dfctmp0); + ae_vector_destroy(&p->dfctmp1); + ae_vector_destroy(&p->dfctmp2); + ae_vector_destroy(&p->ustmpi); + _apbuffers_destroy(&p->xydsbuf); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + _dssvector_destroy(&p->alphar); + _dssvector_destroy(&p->rhor); + ae_vector_destroy(&p->tau); + ae_vector_destroy(&p->alphaq); + ae_vector_destroy(&p->alphaqim); + ae_vector_destroy(&p->eligiblealphar); + ae_vector_destroy(&p->harrisset); +} + + +#endif +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + LINEAR PROGRAMMING + +The subroutine creates LP solver. After initial creation it contains +default optimization problem with zero cost vector and all variables being +fixed to zero values and no constraints. + +In order to actually solve something you should: +* set cost vector with minlpsetcost() +* set variable bounds with minlpsetbc() or minlpsetbcall() +* specify constraint matrix with one of the following functions: + [*] minlpsetlc() for dense one-sided constraints + [*] minlpsetlc2dense() for dense two-sided constraints + [*] minlpsetlc2() for sparse two-sided constraints + [*] minlpaddlc2dense() to add one dense row to constraint matrix + [*] minlpaddlc2() to add one row to constraint matrix (compressed format) +* call minlpoptimize() to run the solver and minlpresults() to get the + solution vector and additional information. + +By default, LP solver uses best algorithm available. As of ALGLIB 3.17, +sparse interior point (barrier) solver is used. Future releases of ALGLIB +may introduce other solvers. + +User may choose specific LP algorithm by calling: +* minlpsetalgodss() for revised dual simplex method with DSE pricing and + bounds flipping ratio test (aka long dual step). Large-scale sparse LU + solverwith Forest-Tomlin update is used internally as linear algebra + driver. +* minlpsetalgoipm() for sparse interior point method + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer in the default state + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpcreate(ae_int_t n, minlpstate* state, ae_state *_state) +{ + ae_int_t i; + + _minlpstate_clear(state); + + ae_assert(n>=1, "MinLPCreate: N<1", _state); + + /* + * Initialize + */ + state->n = n; + state->m = 0; + minlpsetalgoipm(state, 0.0, _state); + state->ipmlambda = (double)(0); + ae_vector_set_length(&state->c, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->xs, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = (double)(0); + state->bndu.ptr.p_double[i] = (double)(0); + state->c.ptr.p_double[i] = 0.0; + state->s.ptr.p_double[i] = 1.0; + state->xs.ptr.p_double[i] = 1.0; + } + lpsolvers_clearreportfields(state, _state); + xqcinit(n, &state->dummyxqc, _state); + xccinit(n, &state->dummyxcc, _state); +} + + +/************************************************************************* +This function sets LP algorithm to revised dual simplex method. + +ALGLIB implementation of dual simplex method supports advanced performance +and stability improvements like DSE pricing , bounds flipping ratio test +(aka long dual step), Forest-Tomlin update, shifting. + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-7. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when relative error is less than Eps. + +===== TRACING DSS SOLVER ================================================= + +DSS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'DSS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'DSS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'DSS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("DSS,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgodss(minlpstate* state, double eps, ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinLPSetAlgoDSS: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinLPSetAlgoDSS: Eps<0", _state); + state->algokind = 1; + if( ae_fp_eq(eps,(double)(0)) ) + { + eps = 1.0E-6; + } + state->dsseps = eps; +} + + +/************************************************************************* +This function sets LP algorithm to sparse interior point method. + +ALGORITHM INFORMATION: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-8. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when primal error AND dual error AND + duality gap are less than Eps. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgoipm(minlpstate* state, double eps, ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinLPSetAlgoIPM: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinLPSetAlgoIPM: Eps<0", _state); + state->algokind = 2; + state->ipmeps = eps; + state->ipmlambda = 0.0; +} + + +/************************************************************************* +This function sets cost term for LP solver. + +By default, cost term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + C - cost term, array[N]. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetcost(minlpstate* state, + /* Real */ const ae_vector* c, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = state->n; + ae_assert(c->cnt>=n, "MinLPSetCost: Length(C)c.ptr.p_double[i] = c->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets scaling coefficients. + +ALGLIB optimizers use scaling matrices to test stopping conditions and as +preconditioner. + +Scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the + function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetscale(minlpstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinLPSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinLPSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinLPSetScale: S contains zero elements", _state); + } + for(i=0; i<=state->n-1; i++) + { + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +different constraints for different variables). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call, overwritten with minlpsetbcall(), or partially +overwritten with minlmsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + BndU - upper bounds, array[N]. + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minlpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbc(minlpstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "MinLPSetBC: Length(BndL)cnt>=n, "MinLPSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinLPSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinLPSetBC: BndU contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +same constraints for all variables) + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call or partially overwritten with minlpsetbcall(). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbcall(minlpstate* state, + double bndl, + double bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(ae_isfinite(bndl, _state)||ae_isneginf(bndl, _state), "MinLPSetBCAll: BndL is NAN or +INF", _state); + ae_assert(ae_isfinite(bndu, _state)||ae_isposinf(bndu, _state), "MinLPSetBCAll: BndU is NAN or -INF", _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = bndl; + state->bndu.ptr.p_double[i] = bndu; + } +} + + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + I - variable index, in [0,N) + BndL - lower bound for I-th variable + BndU - upper bound for I-th variable + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbci(minlpstate* state, + ae_int_t i, + double bndl, + double bndu, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(i>=0&&ibndl.ptr.p_double[i] = bndl; + state->bndu.ptr.p_double[i] = bndu; +} + + +/************************************************************************* +This function sets one-sided linear constraints A*x ~ AU, where "~" can be +a mix of "<=", "=" and ">=". + +IMPORTANT: this function is provided here for compatibility with the rest + of ALGLIB optimizers which accept constraints in format like + this one. Many real-life problems feature two-sided constraints + like a0 <= a*x <= a1. It is really inefficient to add them as a + pair of one-sided constraints. + + Use minlpsetlc2dense(), minlpsetlc2(), minlpaddlc2() (or its + sparse version) wherever possible. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N+1]. Each row of A represents + one constraint, with first N elements being linear coefficients, + and last element being right side. + CT - constraint types, array[K]: + * if CT[i]>0, then I-th constraint is A[i,*]*x >= A[i,n] + * if CT[i]=0, then I-th constraint is A[i,*]*x = A[i,n] + * if CT[i]<0, then I-th constraint is A[i,*]*x <= A[i,n] + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A and CT. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc(minlpstate* state, + /* Real */ const ae_matrix* a, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector al; + ae_vector au; + ae_int_t n; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&al, 0, sizeof(al)); + memset(&au, 0, sizeof(au)); + ae_vector_init(&al, 0, DT_REAL, _state, ae_true); + ae_vector_init(&au, 0, DT_REAL, _state, ae_true); + + n = state->n; + ae_assert(k>=0, "MinLPSetLC: K<0", _state); + ae_assert(k==0||a->cols>=n+1, "MinLPSetLC: Cols(A)rows>=k, "MinLPSetLC: Rows(A)cnt>=k, "MinLPSetLC: Length(CT)m = 0; + ae_frame_leave(_state); + return; + } + + /* + * Convert constraints to two-sided storage format, call another function + */ + ae_vector_set_length(&al, k, _state); + ae_vector_set_length(&au, k, _state); + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]>0 ) + { + al.ptr.p_double[i] = a->ptr.pp_double[i][n]; + au.ptr.p_double[i] = _state->v_posinf; + continue; + } + if( ct->ptr.p_int[i]<0 ) + { + al.ptr.p_double[i] = _state->v_neginf; + au.ptr.p_double[i] = a->ptr.pp_double[i][n]; + continue; + } + al.ptr.p_double[i] = a->ptr.pp_double[i][n]; + au.ptr.p_double[i] = a->ptr.pp_double[i][n]; + } + minlpsetlc2dense(state, a, &al, &au, k, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU. + +This version accepts dense matrix as input; internally LP solver uses +sparse storage anyway (most LP problems are sparse), but for your +convenience it may accept dense inputs. This function overwrites linear +constraints set by previous calls (if such calls were made). + +We recommend you to use sparse version of this function unless you solve +small-scale LP problem (less than few hundreds of variables). + +NOTE: there also exist several versions of this function: + * one-sided dense version which accepts constraints in the same + format as one used by QP and NLP solvers + * two-sided sparse version which accepts sparse matrix + * two-sided dense version which allows you to add constraints row by row + * two-sided sparse version which allows you to add constraints row by row + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2dense(minlpstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t nz; + ae_vector nrs; + + ae_frame_make(_state, &_frame_block); + memset(&nrs, 0, sizeof(nrs)); + ae_vector_init(&nrs, 0, DT_INT, _state, ae_true); + + n = state->n; + ae_assert(k>=0, "MinLPSetLC2Dense: K<0", _state); + ae_assert(k==0||a->cols>=n, "MinLPSetLC2Dense: Cols(A)rows>=k, "MinLPSetLC2Dense: Rows(A)cnt>=k, "MinLPSetLC2Dense: Length(AL)cnt>=k, "MinLPSetLC2Dense: Length(AU)m = k; + if( state->m==0 ) + { + ae_frame_leave(_state); + return; + } + for(i=0; i<=k-1; i++) + { + ae_assert(ae_isfinite(al->ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "MinLPSetLC2Dense: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "MinLPSetLC2Dense: AU contains NAN or -INF", _state); + nz = 0; + for(j=0; j<=n-1; j++) + { + if( ae_fp_neq(a->ptr.pp_double[i][j],(double)(0)) ) + { + inc(&nz, _state); + } + } + nrs.ptr.p_int[i] = nz; + } + + /* + * Allocate storage, copy + */ + rvectorsetlengthatleast(&state->al, state->m, _state); + rvectorsetlengthatleast(&state->au, state->m, _state); + sparsecreatecrsbuf(state->m, n, &nrs, &state->a, _state); + for(i=0; i<=k-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( ae_fp_neq(a->ptr.pp_double[i][j],(double)(0)) ) + { + sparseset(&state->a, i, j, a->ptr.pp_double[i][j], _state); + } + } + state->al.ptr.p_double[i] = al->ptr.p_double[i]; + state->au.ptr.p_double[i] = au->ptr.p_double[i]; + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2(minlpstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = state->n; + + /* + * Quick exit + */ + if( k==0 ) + { + state->m = 0; + return; + } + + /* + * Integrity checks + */ + ae_assert(k>0, "MinLPSetLC2: K<0", _state); + ae_assert(sparsegetncols(a, _state)==n, "MinLPSetLC2: Cols(A)<>N", _state); + ae_assert(sparsegetnrows(a, _state)==k, "MinLPSetLC2: Rows(A)<>K", _state); + ae_assert(al->cnt>=k, "MinLPSetLC2: Length(AL)cnt>=k, "MinLPSetLC2: Length(AU)ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "MinLPSetLC2: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "MinLPSetLC2: AU contains NAN or -INF", _state); + } + + /* + * Copy + */ + state->m = k; + sparsecopytocrsbuf(a, &state->a, _state); + rvectorsetlengthatleast(&state->al, k, _state); + rvectorsetlengthatleast(&state->au, k, _state); + for(i=0; i<=k-1; i++) + { + state->al.ptr.p_double[i] = al->ptr.p_double[i]; + state->au.ptr.p_double[i] = au->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +This version accepts dense constraint vector as input, but sparsifies it +for internal storage and processing. Thus, time to add one constraint in +is O(N) - we have to scan entire array of length N. Sparse version of this +function is order of magnitude faster for constraints with just a few +nonzeros per row. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2dense(minlpstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + ae_int_t nnz; + + + n = state->n; + ae_assert(a->cnt>=n, "MinLPAddLC2Dense: Length(A)adddtmpi, n, _state); + rvectorsetlengthatleast(&state->adddtmpr, n, _state); + nnz = 0; + for(i=0; i<=n-1; i++) + { + if( a->ptr.p_double[i]!=0.0 ) + { + state->adddtmpi.ptr.p_int[nnz] = i; + state->adddtmpr.ptr.p_double[nnz] = a->ptr.p_double[i]; + nnz = nnz+1; + } + } + minlpaddlc2(state, &state->adddtmpi, &state->adddtmpr, nnz, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2(minlpstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs; + ae_int_t offsdst; + ae_int_t m; + ae_int_t n; + ae_int_t didx; + ae_int_t uidx; + + + m = state->m; + n = state->n; + + /* + * Check inputs + */ + ae_assert(nnz>=0, "MinLPAddLC2: NNZ<0", _state); + ae_assert(idxa->cnt>=nnz, "MinLPAddLC2: Length(IdxA)cnt>=nnz, "MinLPAddLC2: Length(ValA)ptr.p_int[i]>=0&&idxa->ptr.p_int[i]a.matrixtype = 1; + state->a.m = 0; + state->a.n = n; + state->a.ninitialized = 0; + ivectorsetlengthatleast(&state->a.ridx, 1, _state); + state->a.ridx.ptr.p_int[0] = 0; + } + + /* + * Reallocate storage + */ + offs = state->a.ridx.ptr.p_int[m]; + ivectorgrowto(&state->a.idx, offs+nnz, _state); + rvectorgrowto(&state->a.vals, offs+nnz, _state); + ivectorgrowto(&state->a.didx, m+1, _state); + ivectorgrowto(&state->a.uidx, m+1, _state); + ivectorgrowto(&state->a.ridx, m+2, _state); + rvectorgrowto(&state->al, m+1, _state); + rvectorgrowto(&state->au, m+1, _state); + + /* + * If NNZ=0, perform quick and simple row append. + */ + if( nnz==0 ) + { + state->a.didx.ptr.p_int[m] = state->a.ridx.ptr.p_int[m]; + state->a.uidx.ptr.p_int[m] = state->a.ridx.ptr.p_int[m]; + state->a.ridx.ptr.p_int[m+1] = state->a.ridx.ptr.p_int[m]; + state->al.ptr.p_double[m] = al; + state->au.ptr.p_double[m] = au; + state->a.m = m+1; + state->m = m+1; + return; + } + + /* + * Now we are sure that A contains properly initialized sparse + * matrix (or some appropriate dummy for M=0) and we have NNZ>0 + * (no need to care about degenerate cases). + * + * Append rows to A: + * * append data + * * sort in place + * * merge duplicate indexes + * * compute DIdx and UIdx + * + */ + for(i=0; i<=nnz-1; i++) + { + state->a.idx.ptr.p_int[offs+i] = idxa->ptr.p_int[i]; + state->a.vals.ptr.p_double[offs+i] = vala->ptr.p_double[i]; + } + tagsortmiddleir(&state->a.idx, &state->a.vals, offs, nnz, _state); + offsdst = offs; + for(i=1; i<=nnz-1; i++) + { + if( state->a.idx.ptr.p_int[offsdst]!=state->a.idx.ptr.p_int[offs+i] ) + { + offsdst = offsdst+1; + state->a.idx.ptr.p_int[offsdst] = state->a.idx.ptr.p_int[offs+i]; + state->a.vals.ptr.p_double[offsdst] = state->a.vals.ptr.p_double[offs+i]; + } + else + { + state->a.vals.ptr.p_double[offsdst] = state->a.vals.ptr.p_double[offsdst]+state->a.vals.ptr.p_double[offs+i]; + } + } + nnz = offsdst-offs+1; + uidx = -1; + didx = -1; + for(j=offs; j<=offsdst; j++) + { + k = state->a.idx.ptr.p_int[j]; + if( k==m ) + { + didx = j; + } + else + { + if( k>m&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offsdst+1; + } + if( didx==-1 ) + { + didx = uidx; + } + state->a.didx.ptr.p_int[m] = didx; + state->a.uidx.ptr.p_int[m] = uidx; + state->a.ridx.ptr.p_int[m+1] = offsdst+1; + state->a.m = m+1; + state->a.ninitialized = state->a.ninitialized+nnz; + state->al.ptr.p_double[m] = al; + state->au.ptr.p_double[m] = au; + state->m = m+1; +} + + +/************************************************************************* +This function solves LP problem. + +INPUT PARAMETERS: + State - algorithm state + +You should use minlpresults() function to access results after calls to +this function. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey. +*************************************************************************/ +void minlpoptimize(minlpstate* state, ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + ae_int_t i; + double v; + dualsimplexsettings settings; + ae_vector dummy1; + ae_matrix dummy; + dualsimplexbasis dummybasis; + ae_bool dotracepresolve; + + ae_frame_make(_state, &_frame_block); + memset(&settings, 0, sizeof(settings)); + memset(&dummy1, 0, sizeof(dummy1)); + memset(&dummy, 0, sizeof(dummy)); + memset(&dummybasis, 0, sizeof(dummybasis)); + _dualsimplexsettings_init(&settings, _state, ae_true); + ae_vector_init(&dummy1, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&dummy, 0, 0, DT_REAL, _state, ae_true); + _dualsimplexbasis_init(&dummybasis, _state, ae_true); + + n = state->n; + m = state->m; + dotracepresolve = ae_is_trace_enabled("IPM")||ae_is_trace_enabled("DSS"); + lpsolvers_clearreportfields(state, _state); + + /* + * Run presolver + */ + presolvelp(&state->s, &state->c, &state->bndl, &state->bndu, n, &state->a, &state->al, &state->au, m, &state->dummyxqc, &state->dummyxcc, dotracepresolve, &state->presolver, _state); + if( state->presolver.problemstatus==-3||state->presolver.problemstatus==-2 ) + { + state->repterminationtype = state->presolver.problemstatus; + state->repn = n; + state->repm = m; + rsetallocv(n, 0.0, &state->xs, _state); + rsetallocv(n, 0.0, &state->lagbc, _state); + rsetallocv(m, 0.0, &state->laglc, _state); + isetallocv(n+m, 0, &state->cs, _state); + state->repf = (double)(0); + state->repprimalerror = (double)(0); + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, state->bndl.ptr.p_double[i]-(double)0, _state); + } + if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, (double)0-state->bndu.ptr.p_double[i], _state); + } + } + for(i=0; i<=m-1; i++) + { + if( ae_isfinite(state->al.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, state->al.ptr.p_double[i]-(double)0, _state); + } + if( ae_isfinite(state->au.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, (double)0-state->au.ptr.p_double[i], _state); + } + } + state->repdualerror = (double)(0); + for(i=0; i<=n-1; i++) + { + state->repdualerror = ae_maxreal(state->repdualerror, ae_fabs(state->c.ptr.p_double[i], _state), _state); + } + state->repslackerror = (double)(0); + ae_frame_leave(_state); + return; + } + ae_assert(state->presolver.problemstatus==0, "MINLP: integrity check 4432 failed", _state); + + /* + * Call current solver + */ + if( state->algokind==1||state->algokind==2 ) + { + + /* + * If presolver did NOT remove all variables (NewN>0), call the current solver + */ + if( state->presolver.newn>0 ) + { + if( state->algokind==1 ) + { + + /* + * Dual simplex method with presolve + */ + dsssettingsinit(&settings, _state); + settings.xtolabs = state->dsseps; + settings.dtolabs = state->dsseps; + dssinit(state->presolver.newn, &state->dss, _state); + dsssetproblem(&state->dss, &state->presolver.c, &state->presolver.bndl, &state->presolver.bndu, &dummy, &state->presolver.sparsea, 1, &state->presolver.al, &state->presolver.au, state->presolver.newm, &dummybasis, lpsolvers_alllogicalsbasis, &settings, _state); + dssoptimize(&state->dss, &settings, _state); + + /* + * Export results, convert from presolve + */ + rcopyallocv(state->presolver.newn, &state->dss.repx, &state->xs, _state); + rcopyallocv(state->presolver.newn, &state->dss.replagbc, &state->lagbc, _state); + rcopyallocv(state->presolver.newm, &state->dss.replaglc, &state->laglc, _state); + icopyallocv(state->presolver.newn+state->presolver.newm, &state->dss.repstats, &state->cs, _state); + state->repiterationscount = state->dss.repiterationscount; + state->repterminationtype = state->dss.repterminationtype; + } + if( state->algokind==2 ) + { + + /* + * Interior point method with presolve + */ + rsetallocv(state->presolver.newn, 1.0, &state->units, _state); + rsetallocv(state->presolver.newn, 0.0, &state->zeroorigin, _state); + sparsecreatesksbandbuf(state->presolver.newn, state->presolver.newn, 0, &state->ipmquadratic, _state); + for(i=0; i<=state->presolver.newn-1; i++) + { + sparseset(&state->ipmquadratic, i, i, state->ipmlambda, _state); + } + sparseconverttocrs(&state->ipmquadratic, _state); + ipm2init(&state->ipm2, &state->units, &state->zeroorigin, state->presolver.newn, &dummy, &state->ipmquadratic, 1, ae_false, &dummy, &dummy1, 0, &state->presolver.c, 0.0, &state->presolver.bndl, &state->presolver.bndu, &state->presolver.sparsea, state->presolver.newm, &dummy, 0, &state->presolver.al, &state->presolver.au, ae_false, ae_false, _state); + ipm2setcond(&state->ipm2, state->ipmeps, state->ipmeps, state->ipmeps, _state); + ipm2optimize(&state->ipm2, ae_true, &state->xs, &state->lagbc, &state->laglc, &state->repterminationtype, _state); + state->repiterationscount = state->ipm2.repiterationscount; + isetallocv(state->presolver.newn+state->presolver.newm, 0, &state->cs, _state); + } + } + else + { + + /* + * Presolver removed all variables, manually set up XS and Lagrange multipliers + */ + rsetallocv(state->presolver.newm, 0.0, &state->laglc, _state); + isetallocv(state->presolver.newn+state->presolver.newm, 0, &state->cs, _state); + state->repterminationtype = 1; + state->repiterationscount = 0; + } + + /* + * Convert back from presolved format + */ + presolvebwd(&state->presolver, &state->xs, &state->cs, ae_true, &state->lagbc, &state->laglc, &state->dummylagqc, _state); + state->repn = n; + state->repm = m; + + /* + * Compute F, primal and dual errors + */ + state->repf = rdotv(n, &state->xs, &state->c, _state); + state->repprimalerror = (double)(0); + state->repdualerror = (double)(0); + state->repslackerror = (double)(0); + rcopyallocv(n, &state->c, &state->tmpg, _state); + if( m>0 ) + { + sparsemv(&state->a, &state->xs, &state->tmpax, _state); + sparsegemv(&state->a, 1.0, 1, &state->laglc, 0, 1.0, &state->tmpg, 0, _state); + } + raddv(n, 1.0, &state->lagbc, &state->tmpg, _state); + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(state->bndl.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, state->bndl.ptr.p_double[i]-state->xs.ptr.p_double[i], _state); + state->repslackerror = ae_maxreal(state->repslackerror, ae_maxreal(state->xs.ptr.p_double[i]-state->bndl.ptr.p_double[i], 0.0, _state)*ae_maxreal(-state->lagbc.ptr.p_double[i], 0.0, _state), _state); + } + if( ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, state->xs.ptr.p_double[i]-state->bndu.ptr.p_double[i], _state); + state->repslackerror = ae_maxreal(state->repslackerror, ae_maxreal(state->bndu.ptr.p_double[i]-state->xs.ptr.p_double[i], 0.0, _state)*ae_maxreal(state->lagbc.ptr.p_double[i], 0.0, _state), _state); + } + state->repdualerror = ae_maxreal(state->repdualerror, ae_fabs(state->tmpg.ptr.p_double[i], _state), _state); + } + for(i=0; i<=m-1; i++) + { + v = state->tmpax.ptr.p_double[i]; + if( ae_isfinite(state->al.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, state->al.ptr.p_double[i]-v, _state); + state->repslackerror = ae_maxreal(state->repslackerror, ae_maxreal(v-state->al.ptr.p_double[i], 0.0, _state)*ae_maxreal(-state->laglc.ptr.p_double[i], 0.0, _state), _state); + } + if( ae_isfinite(state->au.ptr.p_double[i], _state) ) + { + state->repprimalerror = ae_maxreal(state->repprimalerror, v-state->au.ptr.p_double[i], _state); + state->repslackerror = ae_maxreal(state->repslackerror, ae_maxreal(state->au.ptr.p_double[i]-v, 0.0, _state)*ae_maxreal(state->laglc.ptr.p_double[i], 0.0, _state), _state); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Integrity check failed - unknown solver + */ + ae_assert(ae_false, "MinQPOptimize: integrity check failed - unknown solver", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +LP solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution (on failure: last trial point) + Rep - optimization report. You should check Rep.TerminationType, + which contains completion code, and you may check another + fields which contain another information about algorithm + functioning. + + Failure codes returned by algorithm are: + * -4 LP problem is primal unbounded (dual infeasible) + * -3 LP problem is primal infeasible (dual unbounded) + * -2 IPM solver detected that problem is either + infeasible or unbounded + + Success codes: + * 1..4 successful completion + * 5 MaxIts steps was taken + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresults(const minlpstate* state, + /* Real */ ae_vector* x, + minlpreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minlpreport_clear(rep); + + minlpresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +LP results + +Buffered implementation of MinLPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresultsbuf(const minlpstate* state, + /* Real */ ae_vector* x, + minlpreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t repn; + ae_int_t repm; + + + repn = state->repn; + repm = state->repm; + if( x->cnty, repm, _state); + ae_vector_set_length(&rep->stats, repn+repm, _state); + rep->f = state->repf; + rep->primalerror = state->repprimalerror; + rep->dualerror = state->repdualerror; + rep->slackerror = state->repslackerror; + rep->iterationscount = state->repiterationscount; + rep->terminationtype = state->repterminationtype; + rcopyallocv(repm, &state->laglc, &rep->laglc, _state); + rcopyallocv(repn, &state->lagbc, &rep->lagbc, _state); + for(i=0; i<=repn-1; i++) + { + x->ptr.p_double[i] = state->xs.ptr.p_double[i]; + } + for(i=0; i<=repm-1; i++) + { + rep->y.ptr.p_double[i] = -rep->laglc.ptr.p_double[i]; + } + for(i=0; i<=repn+repm-1; i++) + { + rep->stats.ptr.p_int[i] = state->cs.ptr.p_int[i]; + } +} + + +/************************************************************************* +Clear report fields prior to the optimization. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey. +*************************************************************************/ +static void lpsolvers_clearreportfields(minlpstate* state, + ae_state *_state) +{ + + + state->repf = 0.0; + state->repprimalerror = 0.0; + state->repdualerror = 0.0; + state->repiterationscount = 0; + state->repterminationtype = 0; + state->repn = 0; + state->repm = 0; +} + + +void _minlpstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlpstate *p = (minlpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->a, _state, make_automatic); + ae_vector_init(&p->al, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->au, 0, DT_REAL, _state, make_automatic); + _xquadraticconstraints_init(&p->dummyxqc, _state, make_automatic); + _xconicconstraints_init(&p->dummyxcc, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cs, 0, DT_INT, _state, make_automatic); + _dualsimplexstate_init(&p->dss, _state, make_automatic); + _vipmstate_init(&p->ipm, _state, make_automatic); + _ipm2state_init(&p->ipm2, _state, make_automatic); + ae_vector_init(&p->adddtmpi, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->adddtmpr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg, 0, DT_REAL, _state, make_automatic); + _presolveinfo_init(&p->presolver, _state, make_automatic); + ae_vector_init(&p->zeroorigin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->units, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->ipmquadratic, _state, make_automatic); + ae_vector_init(&p->dummylagqc, 0, DT_REAL, _state, make_automatic); +} + + +void _minlpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlpstate *dst = (minlpstate*)_dst; + const minlpstate *src = (const minlpstate*)_src; + dst->n = src->n; + dst->algokind = src->algokind; + dst->ipmlambda = src->ipmlambda; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->m = src->m; + _sparsematrix_init_copy(&dst->a, &src->a, _state, make_automatic); + ae_vector_init_copy(&dst->al, &src->al, _state, make_automatic); + ae_vector_init_copy(&dst->au, &src->au, _state, make_automatic); + _xquadraticconstraints_init_copy(&dst->dummyxqc, &src->dummyxqc, _state, make_automatic); + _xconicconstraints_init_copy(&dst->dummyxcc, &src->dummyxcc, _state, make_automatic); + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + ae_vector_init_copy(&dst->lagbc, &src->lagbc, _state, make_automatic); + ae_vector_init_copy(&dst->laglc, &src->laglc, _state, make_automatic); + ae_vector_init_copy(&dst->cs, &src->cs, _state, make_automatic); + dst->repf = src->repf; + dst->repprimalerror = src->repprimalerror; + dst->repdualerror = src->repdualerror; + dst->repslackerror = src->repslackerror; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repn = src->repn; + dst->repm = src->repm; + dst->dsseps = src->dsseps; + dst->ipmeps = src->ipmeps; + _dualsimplexstate_init_copy(&dst->dss, &src->dss, _state, make_automatic); + _vipmstate_init_copy(&dst->ipm, &src->ipm, _state, make_automatic); + _ipm2state_init_copy(&dst->ipm2, &src->ipm2, _state, make_automatic); + ae_vector_init_copy(&dst->adddtmpi, &src->adddtmpi, _state, make_automatic); + ae_vector_init_copy(&dst->adddtmpr, &src->adddtmpr, _state, make_automatic); + ae_vector_init_copy(&dst->tmpax, &src->tmpax, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg, &src->tmpg, _state, make_automatic); + _presolveinfo_init_copy(&dst->presolver, &src->presolver, _state, make_automatic); + ae_vector_init_copy(&dst->zeroorigin, &src->zeroorigin, _state, make_automatic); + ae_vector_init_copy(&dst->units, &src->units, _state, make_automatic); + _sparsematrix_init_copy(&dst->ipmquadratic, &src->ipmquadratic, _state, make_automatic); + ae_vector_init_copy(&dst->dummylagqc, &src->dummylagqc, _state, make_automatic); +} + + +void _minlpstate_clear(void* _p) +{ + minlpstate *p = (minlpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->c); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + _sparsematrix_clear(&p->a); + ae_vector_clear(&p->al); + ae_vector_clear(&p->au); + _xquadraticconstraints_clear(&p->dummyxqc); + _xconicconstraints_clear(&p->dummyxcc); + ae_vector_clear(&p->xs); + ae_vector_clear(&p->lagbc); + ae_vector_clear(&p->laglc); + ae_vector_clear(&p->cs); + _dualsimplexstate_clear(&p->dss); + _vipmstate_clear(&p->ipm); + _ipm2state_clear(&p->ipm2); + ae_vector_clear(&p->adddtmpi); + ae_vector_clear(&p->adddtmpr); + ae_vector_clear(&p->tmpax); + ae_vector_clear(&p->tmpg); + _presolveinfo_clear(&p->presolver); + ae_vector_clear(&p->zeroorigin); + ae_vector_clear(&p->units); + _sparsematrix_clear(&p->ipmquadratic); + ae_vector_clear(&p->dummylagqc); +} + + +void _minlpstate_destroy(void* _p) +{ + minlpstate *p = (minlpstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->c); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + _sparsematrix_destroy(&p->a); + ae_vector_destroy(&p->al); + ae_vector_destroy(&p->au); + _xquadraticconstraints_destroy(&p->dummyxqc); + _xconicconstraints_destroy(&p->dummyxcc); + ae_vector_destroy(&p->xs); + ae_vector_destroy(&p->lagbc); + ae_vector_destroy(&p->laglc); + ae_vector_destroy(&p->cs); + _dualsimplexstate_destroy(&p->dss); + _vipmstate_destroy(&p->ipm); + _ipm2state_destroy(&p->ipm2); + ae_vector_destroy(&p->adddtmpi); + ae_vector_destroy(&p->adddtmpr); + ae_vector_destroy(&p->tmpax); + ae_vector_destroy(&p->tmpg); + _presolveinfo_destroy(&p->presolver); + ae_vector_destroy(&p->zeroorigin); + ae_vector_destroy(&p->units); + _sparsematrix_destroy(&p->ipmquadratic); + ae_vector_destroy(&p->dummylagqc); +} + + +void _minlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minlpreport *p = (minlpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->lagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->stats, 0, DT_INT, _state, make_automatic); +} + + +void _minlpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minlpreport *dst = (minlpreport*)_dst; + const minlpreport *src = (const minlpreport*)_src; + dst->f = src->f; + ae_vector_init_copy(&dst->lagbc, &src->lagbc, _state, make_automatic); + ae_vector_init_copy(&dst->laglc, &src->laglc, _state, make_automatic); + ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic); + ae_vector_init_copy(&dst->stats, &src->stats, _state, make_automatic); + dst->primalerror = src->primalerror; + dst->dualerror = src->dualerror; + dst->slackerror = src->slackerror; + dst->iterationscount = src->iterationscount; + dst->terminationtype = src->terminationtype; +} + + +void _minlpreport_clear(void* _p) +{ + minlpreport *p = (minlpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->lagbc); + ae_vector_clear(&p->laglc); + ae_vector_clear(&p->y); + ae_vector_clear(&p->stats); +} + + +void _minlpreport_destroy(void* _p) +{ + minlpreport *p = (minlpreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->lagbc); + ae_vector_destroy(&p->laglc); + ae_vector_destroy(&p->y); + ae_vector_destroy(&p->stats); +} + + +#endif +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + DERIVATIVE-FREE NONLINEAR LEAST SQUARES + +DESCRIPTION: + +This function creates a NLS solver configured to solve a constrained +nonlinear least squares problem + + min F(x) = f[0]^2 + f[1]^2 + ... + f[m-1]^2 + +where f[i] are available, but not their derivatives. + +The functions f[i] are assumed to be smooth, but may have some +amount of numerical noise (either random noise or deterministic noise +arising from numerical simulations or other complex numerical processes). + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i], M>=1 + X - initial point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlscreatedfo(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + nlsstate* state, + ae_state *_state) +{ + + _nlsstate_clear(state); + + ae_assert(n>=1, "NLSCreateDFO: N<1!", _state); + ae_assert(m>=1, "NLSCreateDFO: M<1!", _state); + ae_assert(x->cnt>=n, "NLSCreateDFO: Length(X)protocolversion = 2; + state->n = n; + state->m = m; + state->problemtype = 0; + state->diffstep = (double)(0); + state->xrep = ae_false; + state->rad0 = (double)(0); + state->maxfev = 0; + critinitdefault(&state->criteria, _state); + bsetallocv(n, ae_false, &state->hasbndl, _state); + bsetallocv(n, ae_false, &state->hasbndu, _state); + rsetallocv(n, _state->v_neginf, &state->bndl, _state); + rsetallocv(n, _state->v_posinf, &state->bndu, _state); + state->nnlc = 0; + state->cntlc = 0; + rsetallocv(n, 1.0, &state->s, _state); + nlssetalgo2ps(state, 0, _state); + nlsrestartfrom(state, x, _state); +} + + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +2PS (2-Point Stencil) algorithm. + +This solver is recommended for the following cases: +* an expensive target function is minimized by the commercial ALGLIB with + callback parallelism activated (see ALGLIB Reference Manual for more + information about parallel callbacks) +* an inexpensive target function is minimized by any ALGLIB edition (free + or commercial) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The 2PS algorithm is a derivative-free model-based nonlinear least squares +solver which builds local models by evaluating the target at N additional +points around the current one, with geometry similar to the 2-point finite +difference stencil. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. + +When compared with the DFO-LSA solver, the 2PS algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by the DFO-LSA) +* 2PS requires several times less iterations than the DFO-LSA because each + iteration extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets 2PS provides better parallelism potential than + DFO-LSA because the former issues many simultaneous target evaluation + requests which can be easily parallelized. It is possible for 2PS to + outperform DFO-LSA by parallelism alone, despite the fact that the + latter needs 3-4 times less target function evaluations. +* for inexpensive targets 2PS may win because it needs many times less + iterations, and thus the overhead associated with the working set updates + is also many times less. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgo2ps(nlsstate* state, + ae_int_t nnoisyrestarts, + ae_state *_state) +{ + + + ae_assert(state->problemtype==0, "NLSSetAlgo2PS: the solver MUST be created in a derivative-free mode (i.e. with nlscreatedfo() function)", _state); + ae_assert(nnoisyrestarts>=0, "NLSSetAlgo2PS: negative NNoisyRestarts", _state); + state->algorithm = 0; + state->nnoisyrestarts = nnoisyrestarts; +} + + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +DFO-LSA algorithm, an ALGLIB implementation (with several modifications)of +the original DFO-LS algorithm by Cartis, C., Fiala, J., Marteau, B. and +Roberts, L. ('Improving the Flexibility and Robustness of Model-Based +Derivative-Free Optimization Solvers', 2019). The A in DFO-LSA stands for +ALGLIB, in order to distinguish our slightly modified implementation from +the original algorithm. + +This solver is recommended for the following case: an expensive target +function is minimized without parallelism being used (either free ALGLIB +is used or commercial one is used but the target callback is non-reentrant +i.e. it can not be simultaneously called from multiple threads) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The DFO-LSA algorithm is a derivative-free model-based NLS solver which +builds local models by remembering N+1 previously computed target values +and updating them as optimization progresses. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. Our +implementation generally follows the same lines as the original DFO-LSA, +with several modifications to trust radius update strategies, stability +fixes (unlike original DFO-LS, our implementation can handle and recover +from the target breaking down due to infeasible arguments) and other minor +implementation details. + +When compared with the 2PS solver, the DFO-LSA algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by DFO-LSA) +* 2PS requires several times less iterations than DFO-LSA because each + iterations extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets DFO-LSA is much more efficient than 2PS because + it reuses previously computed target values as much as possible. +* however, DFO-LSA has little parallelism potential because (unlike 2PS) + it does not evaluate the target in several points simultaneously and + independently +* additionally, because DFO-LSA performs many times more iterations than + 2PS, iteration overhead (working set updates and matrix inversions) is + an issue here. For inexpensive targets it is possible for DFO-LSA to be + outperformed by 2PS merely because of the linear algebra cost. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgodfolsa(nlsstate* state, + ae_int_t nnoisyrestarts, + ae_state *_state) +{ + + + ae_assert(state->problemtype==0, "NLSSetAlgoDFOLSA: the solver MUST be created in a derivative-free mode (i.e. with nlscreatedfo() function)", _state); + ae_assert(nnoisyrestarts>=0, "NLSSetAlgo2PS: negative NNoisyRestarts", _state); + state->algorithm = 1; + state->nnoisyrestarts = nnoisyrestarts; +} + + +/************************************************************************* +This function sets stopping conditions + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - stop when the scaled trust region radius is smaller than + EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetcond(nlsstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "NLSSetCond: EpsX is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "NLSSetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "NLSSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsx,(double)(0))&&maxits==0 ) + { + epsx = 1.0E-6; + } + critsetcondv1(&state->criteria, 0.0, epsx, maxits, _state); +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLSOptimize(). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetxrep(nlsstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets variable scales + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But +derivative-free optimizers often use scaling matrix both in the stopping +condition tests and as a preconditioner. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetscale(nlsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "NLSSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "NLSSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "NLSSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets box constraints + +Box constraints are inactive by default (after initial creation). They are +preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (the latter is recommended). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (the latter is recommended). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unless explicitly mentioned in the specific NLS algorithm + description, the following holds: + * box constraints are always satisfied exactly + * the target is NOT evaluated outside of the box-constrained area + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetbc(nlsstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "NLSSetBC: Length(BndL)cnt>=n, "NLSSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "NLSSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "NLSSetBC: BndU contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* + +CALLBACK PARALLELISM + +The NLS optimizer supports parallel model evaluation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates optimization when using a solver which +issues batch requests, i.e. multiple requests for target values, which +can be computed independently by different threads. + +Callback parallelism is usually beneficial when processing a batch +request requires more than several milliseconds. It also requires the +solver which issues requests in convenient batches, e.g. 2PS solver. + +See ALGLIB Reference Manual, 'Working with commercial version' section for +more information. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool nlsiteration(nlsstate* state, ae_state *_state) +{ + ae_int_t nraw; + ae_int_t nreduced; + ae_int_t m; + ae_int_t nnlc; + ae_int_t i; + ae_int_t originalrequest; + ae_bool b; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + nraw = state->rstate.ia.ptr.p_int[0]; + nreduced = state->rstate.ia.ptr.p_int[1]; + m = state->rstate.ia.ptr.p_int[2]; + nnlc = state->rstate.ia.ptr.p_int[3]; + i = state->rstate.ia.ptr.p_int[4]; + originalrequest = state->rstate.ia.ptr.p_int[5]; + b = state->rstate.ba.ptr.p_bool[0]; + } + else + { + nraw = 359; + nreduced = -58; + m = -919; + nnlc = -909; + i = 81; + originalrequest = 255; + b = ae_false; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + + /* + * Routine body + */ + + /* + * prepare + */ + nraw = state->n; + m = state->m; + nnlc = state->nnlc; + state->repiterationscount = 0; + state->repterminationtype = 0; + state->repnrequests = 0; + state->repnfunc = 0; + state->userterminationneeded = ae_false; + + /* + * Trace status + */ + state->dotrace = ae_false; + b = ae_false; + if( state->algorithm==0 ) + { + state->dotrace = ae_is_trace_enabled("2PS")||ae_is_trace_enabled("DFGM"); + b = ae_true; + } + if( state->algorithm==1 ) + { + state->dotrace = ae_is_trace_enabled("DFOLSA")||ae_is_trace_enabled("DFGM"); + b = ae_true; + } + ae_assert(b, "NLS: integrity check 8718 failed", _state); + if( state->dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// NLS SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d (original variables count)\n", + (int)(nraw)); + } + + /* + * Check correctness of box constraints, remove fixed variables (most derivative-free solvers do not allow + * fixed variables because it overcomplicates geometry improvement code). + */ + iallocv(nraw, &state->idxraw2red, _state); + rallocv(nraw, &state->redbl, _state); + rallocv(nraw, &state->redbu, _state); + rallocv(nraw, &state->reds, _state); + rallocv(nraw, &state->redx0, _state); + nreduced = 0; + for(i=0; i<=nraw-1; i++) + { + if( ae_isfinite(state->bndl.ptr.p_double[i], _state)&&ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + if( state->dotrace ) + { + ae_trace("> variable %0d has inconsistent box constraints, terminating with code -3\n", + (int)(i)); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + if( ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->idxraw2red.ptr.p_int[i] = -1; + continue; + } + } + state->redx0.ptr.p_double[nreduced] = state->x0.ptr.p_double[i]; + state->reds.ptr.p_double[nreduced] = state->s.ptr.p_double[i]; + state->redbl.ptr.p_double[nreduced] = state->bndl.ptr.p_double[i]; + state->redbu.ptr.p_double[nreduced] = state->bndu.ptr.p_double[i]; + state->idxraw2red.ptr.p_int[i] = nreduced; + nreduced = nreduced+1; + } + if( nreduced==0 ) + { + + /* + * All variables are fixed, quick exit + */ + if( state->dotrace ) + { + ae_trace("> all variables are fixed by their box constraints, no need to run the solver. Success!\n"); + } + state->repterminationtype = 2; + state->repiterationscount = 0; + rcopyv(nraw, &state->bndl, &state->xc, _state); + result = ae_false; + return result; + } + if( state->dotrace ) + { + ae_trace("N_reduced = %6d (variables after removing fixed ones)\n", + (int)(nreduced)); + ae_trace("M = %6d (nonlinear least squares target functions)\n", + (int)(m)); + ae_trace("cntLC = %6d (linear constraints)\n", + (int)(state->cntlc)); + ae_trace("cntNLC = %6d (nonlinear constraints)\n", + (int)(state->nnlc)); + } + + /* + * Allocate temporaries, as mandated by the V2 protocol + */ + ae_assert(state->protocolversion==2, "NLS: integrity check 5124 failed", _state); + b = ae_false; + if( state->problemtype==0 ) + { + rallocv(nraw, &state->reportx, _state); + rallocv(m+nnlc, &state->tmpf1, _state); + rallocv(nraw, &state->tmpg1, _state); + rallocv(nraw, &state->tmpx1, _state); + b = ae_true; + } + ae_assert(b, "NLS: integrity check 6628 failed", _state); + + /* + * Initialization phase + */ + b = ae_false; + if( state->algorithm==0||state->algorithm==1 ) + { + + /* + * Initialize 2PS solver + */ + i = -999999; + if( state->algorithm==0 ) + { + i = 0; + } + if( state->algorithm==1 ) + { + i = 1; + } + ae_assert(i>=0, "NLS: integrity check 7930 failed", _state); + dfgminitbuf(&state->redbl, &state->redbu, &state->reds, &state->redx0, nreduced, m, ae_true, i, &state->criteria, state->nnoisyrestarts, state->rad0, state->maxfev, &state->dfgmsolver, _state); + b = ae_true; + } + ae_assert(b, "NLS: integrity check 1620 failed", _state); + + /* + * Iteration phase + */ +lbl_2: + if( ae_false ) + { + goto lbl_3; + } + + /* + * Run iteration function and load evaluation point + */ + state->requesttype = 0; + b = ae_false; + if( state->algorithm==0||state->algorithm==1 ) + { + + /* + * 2PS solver + */ + if( !dfgmiteration(&state->dfgmsolver, state->userterminationneeded, _state) ) + { + goto lbl_3; + } + if( state->dfgmsolver.requesttype==4 ) + { + rallocv(nraw*state->dfgmsolver.querysize, &state->unscaled, _state); + state->batchsize = state->dfgmsolver.querysize; + nls_unscalebatch(state, &state->dfgmsolver.querydata, state->dfgmsolver.querysize, &state->idxraw2red, nreduced, &state->dfgmsolver.scaledbndl, &state->dfgmsolver.scaledbndu, &state->unscaled, _state); + originalrequest = 4; + b = ae_true; + } + if( state->dfgmsolver.requesttype==-1 ) + { + nls_unscalebatch(state, &state->dfgmsolver.reportx, 1, &state->idxraw2red, nreduced, &state->dfgmsolver.scaledbndl, &state->dfgmsolver.scaledbndu, &state->reportx, _state); + state->reportf = state->dfgmsolver.reportf; + state->requesttype = -1; + originalrequest = -1; + b = ae_true; + } + } + ae_assert(b, "NLS: integrity check 5510 failed", _state); + + /* + * Process evaluation request, perform numerical differentiation if necessary, offload results back to the optimizer + */ + b = ae_false; + if( originalrequest!=-1 ) + { + goto lbl_4; + } + + /* + * Report + */ + ae_assert(state->protocolversion==2, "NLS: integrity check 6811 failed", _state); + if( !state->xrep ) + { + goto lbl_6; + } + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: +lbl_6: + b = ae_true; +lbl_4: + if( originalrequest!=4 ) + { + goto lbl_8; + } + state->repnfunc = state->repnfunc+state->batchsize; + state->repnrequests = state->repnrequests+1; + rallocv(nraw, &state->querydata, _state); + rallocv(m+nnlc, &state->replyfi, _state); + rallocv((m+nnlc)*state->batchsize, &state->combined, _state); + i = 0; +lbl_10: + if( i>state->batchsize-1 ) + { + goto lbl_12; + } + state->requesttype = 4; + state->queryfuncs = m+nnlc; + state->queryvars = nraw; + state->querydim = 0; + state->querysize = 1; + rcopyvx(nraw, &state->unscaled, i*nraw, &state->querydata, 0, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rcopyvx(m+nnlc, &state->replyfi, 0, &state->combined, i*(m+nnlc), _state); + i = i+1; + goto lbl_10; +lbl_12: + b = ae_true; +lbl_8: + ae_assert(b, "NLS: integrity check 7814 failed", _state); + + /* + * Send results back to the optimizer + */ + ae_assert(originalrequest==-1||originalrequest==4, "NLS: integrity check 8314 failed", _state); + b = ae_false; + if( originalrequest==-1 ) + { + + /* + * Do nothing + */ + b = ae_true; + } + if( originalrequest==4&&(state->algorithm==0||state->algorithm==1) ) + { + + /* + * 2PS solver + */ + ae_assert(state->protocolversion==2, "NLS: integrity check 9915 failed", _state); + rcopyv((m+nnlc)*state->batchsize, &state->combined, &state->dfgmsolver.replyfi, _state); + b = ae_true; + } + ae_assert(b, "MINNLC: integrity check 0038 failed", _state); + goto lbl_2; +lbl_3: + + /* + * Results phase + */ + b = ae_false; + if( state->algorithm==0||state->algorithm==1 ) + { + + /* + * 2PS results + */ + state->repterminationtype = state->dfgmsolver.repterminationtype; + state->repiterationscount = state->dfgmsolver.repiterationscount; + nls_unscalebatch(state, &state->dfgmsolver.xk, 1, &state->idxraw2red, nreduced, &state->dfgmsolver.scaledbndl, &state->dfgmsolver.scaledbndu, &state->xc, _state); + b = ae_true; + } + ae_assert(b, "NLS: integrity check 1825 failed", _state); + if( state->dotrace ) + { + ae_trace("> analyzing callback parallelism potential:\n"); + ae_trace("best_speedup = %0.1f (assuming expensive target function and negligible iteration overhead)\n", + (double)((double)state->repnfunc/(double)state->repnrequests)); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = nraw; + state->rstate.ia.ptr.p_int[1] = nreduced; + state->rstate.ia.ptr.p_int[2] = m; + state->rstate.ia.ptr.p_int[3] = nnlc; + state->rstate.ia.ptr.p_int[4] = i; + state->rstate.ia.ptr.p_int[5] = originalrequest; + state->rstate.ba.ptr.p_bool[0] = b; + return result; +} + + +/************************************************************************* +Nonlinear least squares solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report; includes termination codes and + additional information. Termination codes are returned in + rep.terminationtype field, its possible values are listed + below, see comments for this structure for more info. + + The termination code is a sum of a basic code (success or + failure) and one/several additional codes. Additional + codes are returned only for successful termination. + + The following basic codes can be returned: + * -8 optimizer detected NAN/INF values in the target or + nonlinear constraints and failed to recover + * -3 box constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called nlsrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + + The following additional codes can be returned (added to + a basic code): + * +800 if during algorithm execution the solver + encountered NAN/INF values in the target or + constraints but managed to recover by reducing + trust region radius, the solver returns one + of SUCCESS codes but adds +800 to the code. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlsresults(const nlsstate* state, + /* Real */ ae_vector* x, + nlsreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _nlsreport_clear(rep); + + nlsresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +Buffered implementation of NLSResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void nlsresultsbuf(const nlsstate* state, + /* Real */ ae_vector* x, + nlsreport* rep, + ae_state *_state) +{ + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + rcopyv(state->n, &state->xc, x, _state); + rep->iterationscount = state->repiterationscount; + rep->terminationtype = state->repterminationtype; + rep->nfunc = state->repnfunc; +} + + +/************************************************************************* +This subroutine restarts solver from the new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - optimizer + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nlsrestartfrom(nlsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "NLSRestartFrom: Length(X)n, _state), "NLSRestartFrom: X contains infinite or NaN values!", _state); + rcopyallocv(state->n, x, &state->x0, _state); + rcopyallocv(state->n, x, &state->xc, _state); + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void nlsrequesttermination(nlsstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Set V2 reverse communication protocol +*************************************************************************/ +void nlssetprotocolv2(nlsstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + ae_vector_set_length(&state->rstate.ia, 5+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones), paying special +attention to box constraints (output is always feasible; active constraints +are mapped to active ones). + +Can handle batch requests. Can handle problems with some variables being +fixed and removed from consideration. + +Parameters: + State solver + XS array[NReduced*BatchSize] - variables after scaling and + removal of fixed vars + idxRaw2Red array[NRaw], maps original variable indexes to ones + after removal of fixed vars. Contains -1 for fixed vars. + scaledBndL, + ScaledBndU array[NReduced], lower/upper bounds after removal of + the fixed vars + +output: + XU array[NRaw*BatchSize], vars after unscaling and + substitution of the fixed vars +*************************************************************************/ +static void nls_unscalebatch(const nlsstate* state, + /* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Integer */ const ae_vector* idxraw2red, + ae_int_t nreduced, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jr; + ae_int_t nraw; + double vs; + + + nraw = state->n; + if( nreduced==nraw ) + { + + /* + * No fixed vars, simple code + */ + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=nraw-1; j++) + { + i = k*nraw+j; + vs = xs->ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[j]&&vs<=scaledbndl->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + if( state->hasbndu.ptr.p_bool[j]&&vs>=scaledbndu->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + continue; + } + xu->ptr.p_double[i] = vs*state->s.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j]&&xu->ptr.p_double[i]bndl.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + } + if( state->hasbndu.ptr.p_bool[j]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + } + } + } + } + else + { + + /* + * Some vars are fixed + */ + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=nraw-1; j++) + { + i = k*nraw+j; + jr = idxraw2red->ptr.p_int[j]; + if( jr<0 ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + vs = xs->ptr.p_double[k*nreduced+jr]; + if( state->hasbndl.ptr.p_bool[j]&&vs<=scaledbndl->ptr.p_double[jr] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + if( state->hasbndu.ptr.p_bool[j]&&vs>=scaledbndu->ptr.p_double[jr] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + continue; + } + xu->ptr.p_double[i] = vs*state->s.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j]&&xu->ptr.p_double[i]bndl.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + } + if( state->hasbndu.ptr.p_bool[j]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + } + } + } + } +} + + +void _nlsstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nlsstate *p = (nlsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->idxraw2red, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->redbl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->redbu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reds, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->redx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _dfgmstate_init(&p->dfgmsolver, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->unscaled, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->combined, 0, DT_REAL, _state, make_automatic); +} + + +void _nlsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nlsstate *dst = (nlsstate*)_dst; + const nlsstate *src = (const nlsstate*)_src; + dst->protocolversion = src->protocolversion; + dst->n = src->n; + dst->m = src->m; + dst->problemtype = src->problemtype; + dst->algorithm = src->algorithm; + dst->diffstep = src->diffstep; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->xrep = src->xrep; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->rad0 = src->rad0; + dst->maxfev = src->maxfev; + dst->nnoisyrestarts = src->nnoisyrestarts; + dst->nnlc = src->nnlc; + dst->cntlc = src->cntlc; + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->idxraw2red, &src->idxraw2red, _state, make_automatic); + ae_vector_init_copy(&dst->redbl, &src->redbl, _state, make_automatic); + ae_vector_init_copy(&dst->redbu, &src->redbu, _state, make_automatic); + ae_vector_init_copy(&dst->reds, &src->reds, _state, make_automatic); + ae_vector_init_copy(&dst->redx0, &src->redx0, _state, make_automatic); + dst->userterminationneeded = src->userterminationneeded; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _dfgmstate_init_copy(&dst->dfgmsolver, &src->dfgmsolver, _state, make_automatic); + dst->dotrace = src->dotrace; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + dst->repnfunc = src->repnfunc; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repnrequests = src->repnrequests; + ae_vector_init_copy(&dst->unscaled, &src->unscaled, _state, make_automatic); + ae_vector_init_copy(&dst->combined, &src->combined, _state, make_automatic); + dst->batchsize = src->batchsize; +} + + +void _nlsstate_clear(void* _p) +{ + nlsstate *p = (nlsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->s); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->idxraw2red); + ae_vector_clear(&p->redbl); + ae_vector_clear(&p->redbu); + ae_vector_clear(&p->reds); + ae_vector_clear(&p->redx0); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + _rcommstate_clear(&p->rstate); + _dfgmstate_clear(&p->dfgmsolver); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->unscaled); + ae_vector_clear(&p->combined); +} + + +void _nlsstate_destroy(void* _p) +{ + nlsstate *p = (nlsstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->idxraw2red); + ae_vector_destroy(&p->redbl); + ae_vector_destroy(&p->redbu); + ae_vector_destroy(&p->reds); + ae_vector_destroy(&p->redx0); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + _rcommstate_destroy(&p->rstate); + _dfgmstate_destroy(&p->dfgmsolver); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->unscaled); + ae_vector_destroy(&p->combined); +} + + +void _nlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nlsreport *p = (nlsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _nlsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nlsreport *dst = (nlsreport*)_dst; + const nlsreport *src = (const nlsreport*)_src; + dst->iterationscount = src->iterationscount; + dst->terminationtype = src->terminationtype; + dst->nfunc = src->nfunc; +} + + +void _nlsreport_clear(void* _p) +{ + nlsreport *p = (nlsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _nlsreport_destroy(void* _p) +{ + nlsreport *p = (nlsreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Get recommended initial value for mu. + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +double gipm2getinitprimdual(ae_state *_state) +{ + double result; + + + result = ae_sqrt(gipm2_initmu, _state); + return result; +} + + +/************************************************************************* +Initialize GIPM structure + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +void gipm2initbuf(/* Real */ const ae_vector* x0, + ae_int_t np, + double eps, + ae_int_t maxits, + gipm2state* state, + ae_state *_state) +{ + + + state->np = np; + state->mflex = 0; + state->meq = 0; + state->mrlxeq = 0; + state->m1 = 0; + state->mrlx1 = 0; + state->hashardbc = ae_false; + state->hassoftbc = ae_false; + state->mudependent = ae_false; + gipm2setprofilequasinewton(state, ae_true, _state); + + /* + * Save initial point for further processing + */ + rcopyallocv(np, x0, &state->x0, _state); + + /* + * Prepare RCOMM-V2 protocol + */ + ae_vector_set_length(&state->rstate.ia, 7+1, _state); + ae_vector_set_length(&state->rstate.ba, 4+1, _state); + ae_vector_set_length(&state->rstate.ra, 22+1, _state); + state->rstate.stage = -1; + + /* + * Stopping criteria and settings + */ + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "GIPM: integrity check 9756 failed", _state); + state->eps = coalesce(eps, (double)10*ae_sqrt(ae_machineepsilon, _state), _state); + state->maxits = maxits; + + /* + * Report fields + */ + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repbcerr = (double)(0); + state->repbcidx = 0; + state->repnlcerr = (double)(0); + state->repnlcidx = 0; + state->repsclerr = (double)(0); + + /* + * Trace status + */ + state->dotracelaconic = ae_is_trace_enabled("GIPM2.LACONIC"); + state->dotrace = ae_is_trace_enabled("GIPM2")&&!state->dotracelaconic; +} + + +/************************************************************************* +Set profile for a quasi-Newton version of the step (linear convergence) + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +void gipm2setprofilequasinewton(gipm2state* state, + ae_bool isprimal, + ae_state *_state) +{ + + + state->isprimal = isprimal; + state->muepsfactor = (double)(10); + state->mudecaylinear = 0.2; + state->mudecaypower = 1.0; + state->multupdatedelay = icase2(isprimal, 1, 0, _state); + state->maxcheckpointstagnationits = 100; +} + + +/************************************************************************* +Set profile for a Newton version of the step (superlinear convergence) + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +void gipm2setprofilenewton(gipm2state* state, ae_state *_state) +{ + + + state->isprimal = ae_true; + state->muepsfactor = 0.1; + state->mudecaylinear = 0.2; + state->mudecaypower = 1.2; + state->multupdatedelay = 1; + state->maxcheckpointstagnationits = 20; +} + + +/************************************************************************* +Set hard box constraints (do not support box equality constraints) + +For a general problem of the form + + min f(x) subject to ci(x)>=0, ce(x)=0 + +rewritten as a barrier-penalty problem with parameter mu + + min f(x) + SUM(-mu*ln(ci(x))) + SUM(1/2mu*ce(x)^2) + +Its primal step direction can be written as a solution of the following +nonsymmetric system: + + [ H+D0 -J' ] [ dx ] [ -grad(f) + J'z ] [ rp ] + [ ] [ ] = [ ] = [ ] + [ U*J W ] [ dz ] [ W*(z_prim-z) ] [ rz0 ] + + +or, alternatively, a solution of a symmetrized augmented system + + [ H+D0 J' ] [ dx ] [ rp ] + [ ] [ ] = [ ] + [ J D1 ] [-dz ] [ rz1 ] + +where + + rz1 = -rz0/U + x is a vector primal variables + z is a vector of dual multipliers, which is taken to be equal to z_prim for the primal algorithm + z_prim is a vector of primal multiplier estimates, which is -ci(x)/mu for ce-rows ; mu/ci(x) for ci-rows + J is a combined Jacobian of ci(x) and ce(x) + U = [ 1 for ce-rows ; z or z_prim for ci-rows ] + W = [ mu for ce-rows ; ci(x) for ci-rows ] + D0 = 0 (it will become non-zero in condensed formulations) + D1 = -W/U + +Due to linearity this form changes in a decomposable, linear way when moving +to more specialized formulations. + +-------------------------------------------------------------------------- + +For a case of box constraints XL <= x <= XU subject to additional relaxation +coefficients QL in {0,1}, QU in {0,1}, we have + + c = { x[i]+qxl[i]*sxl[i]-xl[i]>=0, -x[i]+qxu[i]*sxu[i]+xu[i]>=0, sxl[i]>=0, sxu[i]>=0, msxl[i]-sxl[i]>=0, msxu[i]-sxu[i]>= } + = { VXL[i], VXU[i], SXL[I], SXU[I], SXLCAP[I], SXUCAP[I] } (at current point) + +and also we have f modified by adding barrier and penalty terms for sxl[i], sxu[i] + + f~ = f - mu*ln(sxl[i]) - mu*ln(sxu[i]) - mu*ln(msxl[i]-sxl[i]) - mu*ln(msxu[i]-sxu[i]) + pxl[i]*sxl[i] + pxu[i]*sxu[i] + +and, assuming diagonal regularizer L, the nonsymmetric system is + + (H+D0+L)*dx[i] - dzxl[i] + dzxu[i] = rp[i] = -grad(f)+zxl[i]-zxu[i] + -qxl[i]*dzxl[i] + L*dsxl[i] - dzsxl[i] + dzsxlcap[i] = rpsxl[i] = -pxl[i]+zxl[i]*qxl[i]+zsxl[i]-zsxlcap[i] + -qxu[i]*dzxu[i] + L*dsxu[i] - dzsxu[i] + dzsxucap[i] = rpsxu[i] = -pxu[i]+zxu[i]*qxu[i]+zsxu[i]-zsxucap[i] + zxl[i]*dx[i] + zxl[i]*qxl[i]*dsxl[i] + vxl[i]*dzxl[i] = rdxl[i] = vxl[i]*(zxl-zxl_prim) + -zxu[i]*dx[i] + zxu[i]*qxu[i]*dsxu[i] + vxu[i]*dzxu[i] = rdxu[i] = vxu[i]*(zxu-zxu_prim) + zsxl[i]*dsxl[i] + sxl[i]*dzsxl[i] = rdsxl[i] = sxl[i]*(zsxl-zsxl_prim) + zsxu[i]*dsxu[i] + sxu[i]*dzsxu[i] = rdsxu[i] = sxu[i]*(zsxu-zsxu_prim) + -zsxlcap[i]*dsxl[i] + sxlcap[i]*dzsxlcap[i] = rdsxlcap[i] = sxlcap[i]*(zsxlcap-zsxlcap_prim) + -zsxucap[i]*dsxu[i] + sxucap[i]*dzsxucap[i] = rdsxucap[i] = sxucap[i]*(zsxucap-zsxucap_prim) + +with last 4 rows giving us substitutions + + TMPSX0[i] = 1/sxl[i] or 0 + TMPSX1[i] = 1/sxu[i] or 0 + TMPSX2[i] = 1/sxlcap[i] or 0 + TMPSX3[i] = 1/sxucap[i] or 0 + dzsxl[i] = rdsxl[i]*TMPSX0[i] - (zsxl[i]*TMPSX0[i])*dsxl[i] + dzsxu[i] = rdsxu[i]*TMPSX1[i] - (zsxu[i]*TMPSX1[i])*dsxu[i] + dzsxlcap[i] = rdsxlcap[i]*TMPSX2[i] + (zsxlcap[i]*TMPSX2[i])*dsxl[i] + dzsxucap[i] = rdsxucap[i]*TMPSX3[i] + (zsxucap[i]*TMPSX3[i])*dsxu[i] + +that transform original system into + + TMPSX4[i] = 1/(L+zsxl[i]*TMPSX0[i]+zsxlcap[i]*TMPSX2[i]) + TMPSX5[i] = 1/(L+zsxu[i]*TMPSX1[i]+zsxucap[i]*TMPSX3[i]) + TMPSX6[i] = rpsxl[i] + rdsxl[i]*TMPSX0[i] - rdsxlcap[i]*TMPSX2[i] + TMPSX7[i] = rpsxu[i] + rdsxu[i]*TMPSX1[i] - rdsxucap[i]*TMPSX3[i] + + (H+D0+L)*dx[i] - dzxl[i] + dzxu[i] = rp[i] + -qxl[i]*dzxl[i] + (1/TMPSX4[i])*dsxl[i] = TMPSX6[i] + -qxu[i]*dzxu[i] + (1/TMPSX5[i])*dsxu[i] = TMPSX7[i] + zxl[i]*dx[i] + zxl[i]*qxl[i]*dsxl[i] + vxl[i]*dzxl[i] = rdxl[i] + -zxu[i]*dx[i] + zxu[i]*qxu[i]*dsxu[i] + vxu[i]*dzxu[i] = rdxu[i] + +which gives us + + dsxl[i] = TMPSX4[i]*TMPSX6[i] + (TMPSX4[i]*qxl[i])*dzxl[i] + dsxu[i] = TMPSX5[i]*TMPSX7[i] + (TMPSX5[i]*qxu[i])*dzxu[i] + +which, in turn, transform the system to + + TMPSX8[i] = 1/(zxl[i]*qxl[i]*TMPSX4[i]*qxl[i]+vxl[i]) + TMPSX9[i] = 1/(zxu[i]*qxu[i]*TMPSX5[i]*qxu[i]+vxu[i]) + TMPSX10[i] = rdxl[i] - zxl[i]*qxl[i]*TMPSX4[i]*TMPSX6[i] + TMPSX11[i] = rdxu[i] - zxu[i]*qxu[i]*TMPSX5[i]*TMPSX7[i] + + (H+D0+L)*dx[i] - dzxl[i] + dzxu[i] = rp[i] + zxl[i]*dx[i] + (1/TMPSX8[i])*dzxl[i] = TMPSX10[i] + -zxu[i]*dx[i] + (1/TMPSX9[i])*dzxu[i] = TMPSX11[i] + +and, with the final pair of substitutions + + dzxl[i] = TMPSX8[i]*TMPSX10[i] - TMPSX8[i]*zxl[i]*dx[i] + dzxu[i] = TMPSX9[i]*TMPSX11[i] + TMPSX9[i]*zxu[i]*dx[i] + +we get + + (H+D0+L+TMPSX8[i]*zxl[i]+TMPSX9[i]*zxu[i])*dx[i] = rp[i] + TMPSX8[i]*TMPSX10[i] - TMPSX9[i]*TMPSX11[i] + +which results in the following condensed solution algorithm + + TMPSX0[i] = 1/sxl[i] or 0 + TMPSX1[i] = 1/sxu[i] or 0 + TMPSX2[i] = 1/sxlcap[i] or 0 + TMPSX3[i] = 1/sxucap[i] or 0 + TMPSX4[i] = 1/(L+zsxl[i]*TMPSX0[i]+zsxlcap[i]*TMPSX2[i]) + TMPSX5[i] = 1/(L+zsxu[i]*TMPSX1[i]+zsxucap[i]*TMPSX3[i]) + TMPSX6[i] = rpsxl[i] + rdsxl[i]*TMPSX0[i] - rdsxlcap[i]*TMPSX2[i] + TMPSX7[i] = rpsxu[i] + rdsxu[i]*TMPSX1[i] - rdsxucap[i]*TMPSX3[i] + TMPSX8[i] = 1/(zxl[i]*qxl[i]*TMPSX4[i]*qxl[i]+vxl[i]) + TMPSX9[i] = 1/(zxu[i]*qxu[i]*TMPSX5[i]*qxu[i]+vxu[i]) + TMPSX10[i] = rdxl[i] - zxl[i]*qxl[i]*TMPSX4[i]*TMPSX6[i] + TMPSX11[i] = rdxu[i] - zxu[i]*qxu[i]*TMPSX5[i]*TMPSX7[i] + + WX := rp[i] + TMPSX8[i]*TMPSX10[i] - TMPSX9[i]*TMPSX11[i] + D0 := D0 + TMPSX8[i]*zxl[i] + TMPSX9[i]*zxu[i] + + [ solve (H+L+D0)*dx = WX ] + + dzxl[i] = TMPSX8[i]*(TMPSX10[i] - zxl[i]*dx[i]) + dzxu[i] = TMPSX9[i]*(TMPSX11[i] + zxu[i]*dx[i]) + + dsxl[i] = TMPSX4[i]*(TMPSX6[i] + qxl[i]*dzxl[i]) + dsxu[i] = TMPSX5[i]*(TMPSX7[i] + qxu[i]*dzxu[i]) + + dzsxl[i] = TMPSX0[i]*(rdsxl[i] - zsxl[i]*dsxl[i]) + dzsxu[i] = TMPSX1[i]*(rdsxu[i] - zsxu[i]*dsxu[i]) + dzsxlcap[i] = TMPSX2[i]*(rdsxlcap[i] + zsxlcap[i]*dsxl[i]) + dzsxucap[i] = TMPSX3[i]*(rdsxucap[i] + zsxucap[i]*dsxu[i]) + +or, for hard-only box constraints + + TMPX8[i] = 1/vxl[i] + TMPX9[i] = 1/vxu[i] + + WX := RP + rdxl[i]*TMPX8[i] - rdxu[i]*TMPX9[i] + D0 := D0 + zxl[i]*TMPX8[i] + zxu[i]*TMPX9[i] + + [ solve (H+D0)*dx = WX ] + + dzxl[i] = (rdxl[i] - zxl[i]*dx[i])*TMPX8[i] + dzxu[i] = (rdxu[i] + zxu[i]*dx[i])*TMPX9[i] + +and, for primal-only problem (z=z_prim, rdxl=rdxu=0), even more simple formulation + + TMPX8[i] = 1/vxl[i] + TMPX9[i] = 1/vxu[i] + + RP := RP + zxl[i]-zxu[i] + WX := RP + D0 := D0 + zxl[i]*TMPX8[i] + zxu[i]*TMPX9[i] + + [ solve (H+D0)*dx = WX ] + + dzxl[i] = -zxl[i]*dx[i]*TMPX8[i] + dzxu[i] = +zxu[i]*dx[i]*TMPX9[i] + + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +void gipm2sethardbc(gipm2state* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + + + state->hashardbc = ae_true; + state->hassoftbc = ae_false; + rcopyallocv(state->np, bndl, &state->hardbndl, _state); + rcopyallocv(state->np, bndu, &state->hardbndu, _state); +} + + +void gipm2setsoftbc(gipm2state* state, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* issoftl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* issoftu, + ae_state *_state) +{ + ae_int_t i; + + + state->hashardbc = ae_false; + state->hassoftbc = ae_true; + rcopyallocv(state->np, bndl, &state->hardbndl, _state); + rcopyallocv(state->np, bndu, &state->hardbndu, _state); + rsetallocv(state->np, 0.0, &state->softbcql, _state); + rsetallocv(state->np, 0.0, &state->softbcqu, _state); + for(i=0; i<=state->np-1; i++) + { + if( ae_isfinite(bndl->ptr.p_double[i], _state)&&issoftl->ptr.p_bool[i] ) + { + state->softbcql.ptr.p_double[i] = 1.0; + } + if( ae_isfinite(bndu->ptr.p_double[i], _state)&&issoftu->ptr.p_bool[i] ) + { + state->softbcqu.ptr.p_double[i] = 1.0; + } + } +} + + +void gipm2setflexnlc(gipm2state* state, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t mflex, + ae_state *_state) +{ + ae_int_t i; + + + state->mflex = mflex; + rcopyallocv(mflex, cl, &state->flexcl, _state); + rcopyallocv(mflex, cu, &state->flexcu, _state); + rsetallocv(mflex, 0.0, &state->maskflexcl, _state); + rsetallocv(mflex, 0.0, &state->maskflexcu, _state); + bsetallocv(mflex, ae_false, &state->hasflexcl, _state); + bsetallocv(mflex, ae_false, &state->hasflexcu, _state); + for(i=0; i<=mflex-1; i++) + { + if( ae_isfinite(cl->ptr.p_double[i], _state) ) + { + state->maskflexcl.ptr.p_double[i] = 1.0; + state->hasflexcl.ptr.p_bool[i] = ae_true; + } + if( ae_isfinite(cu->ptr.p_double[i], _state) ) + { + state->maskflexcu.ptr.p_double[i] = 1.0; + state->hasflexcu.ptr.p_bool[i] = ae_true; + } + } +} + + +/************************************************************************* +This function performs actual processing for GIPM2 algorithm. + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool gipm2iteration(gipm2state* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + double gnrm; + double v; + double vv; + double v2; + ae_int_t rfsidx; + double alpha; + double eprim; + double edual; + double ecmpl; + double emax; + double eprim2; + double edual2; + double ecmpl2; + double rhs0; + double rhsk; + double merit0; + double merit1; + double cmpl0; + double cmpl1; + double initprimdual; + ae_bool accepted; + ae_bool worsethanbest; + double minedual; + ae_bool monotonicallyaccepted; + double lastcheckpointf; + double lastcheckpointd; + double lastcheckpointc; + ae_int_t lastcheckpointidx; + ae_bool violated; + ae_bool lambdafound; + ae_int_t smalltrials; + ae_int_t btits; + ae_int_t jj; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + np = state->rstate.ia.ptr.p_int[0]; + mtotal = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + rfsidx = state->rstate.ia.ptr.p_int[3]; + lastcheckpointidx = state->rstate.ia.ptr.p_int[4]; + smalltrials = state->rstate.ia.ptr.p_int[5]; + btits = state->rstate.ia.ptr.p_int[6]; + jj = state->rstate.ia.ptr.p_int[7]; + accepted = state->rstate.ba.ptr.p_bool[0]; + worsethanbest = state->rstate.ba.ptr.p_bool[1]; + monotonicallyaccepted = state->rstate.ba.ptr.p_bool[2]; + violated = state->rstate.ba.ptr.p_bool[3]; + lambdafound = state->rstate.ba.ptr.p_bool[4]; + gnrm = state->rstate.ra.ptr.p_double[0]; + v = state->rstate.ra.ptr.p_double[1]; + vv = state->rstate.ra.ptr.p_double[2]; + v2 = state->rstate.ra.ptr.p_double[3]; + alpha = state->rstate.ra.ptr.p_double[4]; + eprim = state->rstate.ra.ptr.p_double[5]; + edual = state->rstate.ra.ptr.p_double[6]; + ecmpl = state->rstate.ra.ptr.p_double[7]; + emax = state->rstate.ra.ptr.p_double[8]; + eprim2 = state->rstate.ra.ptr.p_double[9]; + edual2 = state->rstate.ra.ptr.p_double[10]; + ecmpl2 = state->rstate.ra.ptr.p_double[11]; + rhs0 = state->rstate.ra.ptr.p_double[12]; + rhsk = state->rstate.ra.ptr.p_double[13]; + merit0 = state->rstate.ra.ptr.p_double[14]; + merit1 = state->rstate.ra.ptr.p_double[15]; + cmpl0 = state->rstate.ra.ptr.p_double[16]; + cmpl1 = state->rstate.ra.ptr.p_double[17]; + initprimdual = state->rstate.ra.ptr.p_double[18]; + minedual = state->rstate.ra.ptr.p_double[19]; + lastcheckpointf = state->rstate.ra.ptr.p_double[20]; + lastcheckpointd = state->rstate.ra.ptr.p_double[21]; + lastcheckpointc = state->rstate.ra.ptr.p_double[22]; + } + else + { + np = 359; + mtotal = -58; + i = -919; + rfsidx = -909; + lastcheckpointidx = 81; + smalltrials = 255; + btits = 74; + jj = -788; + accepted = ae_true; + worsethanbest = ae_true; + monotonicallyaccepted = ae_false; + violated = ae_true; + lambdafound = ae_false; + gnrm = 763.0; + v = -541.0; + vv = -698.0; + v2 = -900.0; + alpha = -318.0; + eprim = -940.0; + edual = 1016.0; + ecmpl = -229.0; + emax = -536.0; + eprim2 = 487.0; + edual2 = -115.0; + ecmpl2 = 886.0; + rhs0 = 346.0; + rhsk = -722.0; + merit0 = -413.0; + merit1 = -461.0; + cmpl0 = 927.0; + cmpl1 = 201.0; + initprimdual = 922.0; + minedual = -154.0; + lastcheckpointf = 306.0; + lastcheckpointd = -1011.0; + lastcheckpointc = 951.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + + /* + * Routine body + */ + np = state->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + ae_nxpool_alloc(&state->mnx1pool, ae_maxint(np, mtotal, _state)+1, _state); + + /* + * Prepare rcomm interface + */ + rallocv(np, &state->reportx, _state); + rallocv(np+mtotal, &state->querydata, _state); + rallocv(1+mtotal, &state->replyfi, _state); + rallocv(1+mtotal, &state->replyv, _state); + + /* + * Choose initial mu and initial variable values + */ + initprimdual = gipm2getinitprimdual(_state); + state->currentmu = gipm2_initmu; + state->prevmu = state->currentmu; + state->mumin = ae_maxreal(0.0001*state->eps/((double)1+gipm2_relaxfactor), (double)100*ae_machineepsilon, _state); + + /* + * Prepare variable bounds + */ + rsetallocv(np, -ae_sqrt(ae_maxrealnumber, _state), &state->finitebndl, _state); + rsetallocv(np, ae_sqrt(ae_maxrealnumber, _state), &state->finitebndu, _state); + bsetallocv(np, ae_false, &state->hasbndl, _state); + bsetallocv(np, ae_false, &state->hasbndu, _state); + rsetallocv(np, 0.0, &state->elp, _state); + rsetallocv(np, 0.0, &state->eup, _state); + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 711152", _state); + for(i=0; i<=np-1; i++) + { + if( ae_isfinite(state->hardbndl.ptr.p_double[i], _state) ) + { + state->finitebndl.ptr.p_double[i] = state->hardbndl.ptr.p_double[i]; + state->elp.ptr.p_double[i] = (double)(1); + state->hasbndl.ptr.p_bool[i] = ae_true; + } + if( ae_isfinite(state->hardbndu.ptr.p_double[i], _state) ) + { + state->finitebndu.ptr.p_double[i] = state->hardbndu.ptr.p_double[i]; + state->eup.ptr.p_double[i] = (double)(1); + state->hasbndu.ptr.p_bool[i] = ae_true; + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 597212", _state); + for(i=0; i<=np-1; i++) + { + if( ae_isfinite(state->hardbndl.ptr.p_double[i], _state) ) + { + state->finitebndl.ptr.p_double[i] = state->hardbndl.ptr.p_double[i]; + state->elp.ptr.p_double[i] = (double)(1); + state->hasbndl.ptr.p_bool[i] = ae_true; + } + if( ae_isfinite(state->hardbndu.ptr.p_double[i], _state) ) + { + state->finitebndu.ptr.p_double[i] = state->hardbndu.ptr.p_double[i]; + state->eup.ptr.p_double[i] = (double)(1); + state->hasbndu.ptr.p_bool[i] = ae_true; + } + } + } + gipm2_safeboundsfromfinitetightened(state, _state); + + /* + * Initialize algorithm state + * * initial function scales (vector of 1's) + * * current approximation of the Hessian matrix H (unit matrix) + */ + state->fstagnationcnt = 0; + gipm2_varsinitbyzero(&state->best, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + rsetallocv(np, 0.0, &state->bestlagbc, _state); + rsetallocv(mtotal, 0.0, &state->bestlagnlc, _state); + gipm2_varsinitbyzero(&state->current, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_varsinitbyzero(&state->cand, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_varsinitbyzero(&state->corr, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_varsinitbyzero(&state->delta, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_multinitbyzero(&state->deltamult, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_multinitbyzero(&state->corrmult, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + rcopyv(np, &state->x0, &state->current.xp, _state); + ae_assert(mtotal-state->mflex==0, "GIPM2: 824204", _state); + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 823200", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + v = 0.5*(state->hardbndl.ptr.p_double[i]+state->hardbndu.ptr.p_double[i]); + ae_assert(ae_fp_greater(v,state->hardbndl.ptr.p_double[i])&&ae_fp_less(v,state->hardbndu.ptr.p_double[i]), "GIPM: check 833206 failed, bounds are too tight", _state); + state->current.xp.ptr.p_double[i] = boundval(state->current.xp.ptr.p_double[i], ae_minreal(state->hardbndl.ptr.p_double[i]+initprimdual, v, _state), ae_maxreal(state->hardbndu.ptr.p_double[i]-initprimdual, v, _state), _state); + continue; + } + if( state->hasbndl.ptr.p_bool[i] ) + { + state->current.xp.ptr.p_double[i] = ae_maxreal(state->current.xp.ptr.p_double[i], state->hardbndl.ptr.p_double[i]+initprimdual, _state); + continue; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->current.xp.ptr.p_double[i] = ae_minreal(state->current.xp.ptr.p_double[i], state->hardbndu.ptr.p_double[i]-initprimdual, _state); + continue; + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 672222", _state); + rsetallocv(np, gipm2_initrlxpenalty, &state->pxl, _state); + rsetallocv(np, gipm2_initrlxpenalty, &state->pxu, _state); + rsetallocv(np, 1.0, &state->softbcmsxl, _state); + rsetallocv(np, 1.0, &state->softbcmsxu, _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + + /* + * Both bounds are present + */ + state->current.sxl.ptr.p_double[i] = initprimdual; + state->current.sxu.ptr.p_double[i] = initprimdual; + if( ae_fp_eq(state->softbcql.ptr.p_double[i],(double)(0))&&ae_fp_eq(state->softbcqu.ptr.p_double[i],(double)(0)) ) + { + + /* + * Both bounds are hard + */ + v = 0.5*(state->hardbndl.ptr.p_double[i]+state->hardbndu.ptr.p_double[i]); + ae_assert(ae_fp_greater(v,state->hardbndl.ptr.p_double[i])&&ae_fp_less(v,state->hardbndu.ptr.p_double[i]), "GIPM: check 730238 failed, hard bounds are too tight", _state); + state->current.xp.ptr.p_double[i] = boundval(state->current.xp.ptr.p_double[i], ae_minreal(state->hardbndl.ptr.p_double[i]+initprimdual, v, _state), ae_maxreal(state->hardbndu.ptr.p_double[i]-initprimdual, v, _state), _state); + } + else + { + + /* + * At least one bound is soft + */ + if( ae_fp_eq(state->softbcql.ptr.p_double[i],(double)(0)) ) + { + state->current.xp.ptr.p_double[i] = ae_maxreal(state->current.xp.ptr.p_double[i], state->hardbndl.ptr.p_double[i]+initprimdual, _state); + } + else + { + state->current.sxl.ptr.p_double[i] = state->current.sxl.ptr.p_double[i]+ae_maxreal(state->hardbndl.ptr.p_double[i]-state->current.xp.ptr.p_double[i], (double)(0), _state)/state->softbcql.ptr.p_double[i]; + } + if( ae_fp_eq(state->softbcqu.ptr.p_double[i],(double)(0)) ) + { + state->current.xp.ptr.p_double[i] = ae_minreal(state->current.xp.ptr.p_double[i], state->hardbndu.ptr.p_double[i]-initprimdual, _state); + } + else + { + state->current.sxu.ptr.p_double[i] = state->current.sxu.ptr.p_double[i]+ae_maxreal(state->current.xp.ptr.p_double[i]-state->hardbndu.ptr.p_double[i], (double)(0), _state)/state->softbcqu.ptr.p_double[i]; + } + } + state->softbcmsxl.ptr.p_double[i] = (double)2*state->current.sxl.ptr.p_double[i]+(double)1; + state->softbcmsxu.ptr.p_double[i] = (double)2*state->current.sxu.ptr.p_double[i]+(double)1; + continue; + } + + /* + * At most one bound is present + */ + if( state->hasbndl.ptr.p_bool[i] ) + { + state->current.sxl.ptr.p_double[i] = initprimdual; + if( ae_fp_eq(state->softbcql.ptr.p_double[i],(double)(0)) ) + { + state->current.xp.ptr.p_double[i] = ae_maxreal(state->current.xp.ptr.p_double[i], state->hardbndl.ptr.p_double[i]+initprimdual, _state); + } + else + { + state->current.sxl.ptr.p_double[i] = state->current.sxl.ptr.p_double[i]+ae_maxreal(state->hardbndl.ptr.p_double[i]-state->current.xp.ptr.p_double[i], (double)(0), _state)/state->softbcql.ptr.p_double[i]; + } + state->softbcmsxl.ptr.p_double[i] = (double)2*state->current.sxl.ptr.p_double[i]+(double)1; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->current.sxu.ptr.p_double[i] = initprimdual; + if( ae_fp_eq(state->softbcqu.ptr.p_double[i],(double)(0)) ) + { + state->current.xp.ptr.p_double[i] = ae_minreal(state->current.xp.ptr.p_double[i], state->hardbndu.ptr.p_double[i]-initprimdual, _state); + } + else + { + state->current.sxu.ptr.p_double[i] = state->current.sxu.ptr.p_double[i]+ae_maxreal(state->current.xp.ptr.p_double[i]-state->hardbndu.ptr.p_double[i], (double)(0), _state)/state->softbcqu.ptr.p_double[i]; + } + state->softbcmsxu.ptr.p_double[i] = (double)2*state->current.sxu.ptr.p_double[i]+(double)1; + } + } + } + gipm2_sendx(state, &state->current.xp, _state); + state->requesttype = 1; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( !gipm2_retrievefij(state, &state->current, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + ae_assert(mtotal-state->mflex==0, "GIPM2: 824204", _state); + for(i=0; i<=state->mflex-1; i++) + { + state->current.sxf.ptr.p_double[i] = state->current.fi.ptr.p_double[1+i]; + if( state->hasflexcl.ptr.p_bool[i] ) + { + state->current.gl.ptr.p_double[i] = ae_maxreal(state->current.sxf.ptr.p_double[i]-state->flexcl.ptr.p_double[i], initprimdual, _state); + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + state->current.gu.ptr.p_double[i] = ae_maxreal(state->flexcu.ptr.p_double[i]-state->current.sxf.ptr.p_double[i], initprimdual, _state); + } + } + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->delayedmult, _state); + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->currentmult, _state); + state->requesttype = 1000; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->requesttype = 1004; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + if( state->replywasrescale ) + { + if( state->dotrace ) + { + ae_trace("> initial objective/constraints rescaling was performed\n"); + } + gipm2_rescalecurrentbest(state, &state->replyv, ae_false, _state); + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->delayedmult, _state); + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->currentmult, _state); + } + state->requesttype = 1005; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + rcopyallocv(1+mtotal, &state->replyv, &state->callerfscales, _state); + state->nrmx0 = rmaxabsv(np, &state->current.xp, _state); + state->absf0 = ae_fabs(state->current.fi.ptr.p_double[0], _state); + ae_assert(mtotal-state->mflex==0, "GIPM2: 042333", _state); + rcopyv(state->np, &state->current.xp, &state->reportx, _state); + state->reportf = state->current.fi.ptr.p_double[0]; + state->requesttype = -1; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + gipm2_updateerrorestimates(state, _state); + + /* + * Prepare best point. + * + * NOTE: BestErr is initialized by MaxRealNumber, which is intentional - it means that + * during the very first iteration any point is better than the best, and some + * code (in particular, one using SengLagrangianInfo() function) relies on the property. + */ + state->besterr = ae_maxrealnumber; + state->hasbest = ae_false; + gipm2_varscopy(&state->current, &state->best, _state); + gipm2_lagcoeffsfrommultipliers(&state->currentmult, &state->bestlagbc, &state->bestlagnlc, _state); + state->requesttype = 1006; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + + /* + * Outer iterations + */ + state->curbigval = gipm2_initbigval; + state->curbiggrowth = gipm2_initbiggrowth; + state->lambdav = state->currentmu; + state->lambdadecay = 1.0; + state->lambdafound = ae_false; + state->infinitiesdetected = ae_false; + state->failedtorecoverfrominfinities = ae_false; + state->subsequentfactfailures = 0; + state->firstouteriteration = ae_true; + state->linesearchalwayssuccessful = ae_true; + state->lastprim = ae_sqrt(ae_maxrealnumber, _state); + state->lastdual = state->lastprim; + state->lastcmpl = state->lastprim; + gnrm = (double)(1); +lbl_18: + if( ae_false ) + { + goto lbl_19; + } + + /* + * Reset parameters and flags at the beginning of inner iterations + */ + state->unboundednesssuspected = ae_false; + lastcheckpointf = ae_maxrealnumber; + lastcheckpointd = ae_maxrealnumber; + lastcheckpointc = ae_maxrealnumber; + lastcheckpointidx = state->repiterationscount; + state->rhsstagnationcounter = 0; + state->goodinnerits = 0; + state->lambdav = ae_maxreal(state->currentmu, state->lambdav, _state); + state->lambdadecay = 1.0; + state->rejectedwithineps = 0; + state->nonmonotonicmemlen = -1; + state->inneriterationidx = 0; + worsethanbest = ae_true; + minedual = ae_maxrealnumber; + state->hessiandecay = 1.0; + + /* + * If the problem formulation is mu-dependent, recompute target/objective using + * current value of Mu. + * + *if State.MuDependent then + *begin + * State.RequestType:=1; + * State.QueryMu:=State.Mu; + * rAllocV(NRaw+MTotal, State.QueryData); + * rCopyVX(NRaw, State.Current.XP, 0, State.QueryData, 0); + * rCopyVX(MFlex, State.Current.YP, 0, State.QueryData, NRaw); + * rCopyVX(MHard, State.Current.YV, 0, State.QueryData, NRaw+MFlex); + * rAllocV(1+MTotal, State.ReplyFi); + * RComm; + * vfjInitFromSparse(State.Current.XP, NRaw, State.ReplyFi, 1+MTotal, State.ReplySJ, State.CurrentFJ); + *end; + */ + ae_assert(!state->mudependent, "GIPM2: integrity check 646212 failed", _state); + + /* + * Inner iterations for fixed Mu. + * + * After this loop is done we have current point in State.Current and current residual + * in State.RHS. Additionally, the current point is remembered as the one where the + * Hessian should be calculated. + */ +lbl_20: + if( ae_false ) + { + goto lbl_21; + } + if( userterminationneeded ) + { + goto lbl_21; + } + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + if( state->dotrace ) + { + ae_trace("> maximum number of iterations performed, stopping\n"); + } + state->repterminationtype = 5; + goto lbl_21; + } + + /* + * Issue rescale request, recompute merit function at the initial point + */ + state->requesttype = 1004; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + if( !state->replywasrescale ) + { + goto lbl_22; + } + + /* + * Handle rescale request + */ + if( state->dotrace ) + { + ae_trace("> target/constraints were rescaled due to gradient norms deviating too much from 1.0, clearing nonmonotonic memory"); + } + if( state->dotrace ) + { + ae_trace("\n"); + } + state->nonmonotonicmemlen = -1; + state->absf0 = state->absf0*state->replyv.ptr.p_double[0]; + gipm2_rescalecurrentbest(state, &state->replyv, ae_true, _state); + ae_assert(mtotal-state->mflex==0, "GIPM: 177010", _state); + + /* + * Update callerFScales[] + */ + state->requesttype = 1005; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + rcopyallocv(1+mtotal, &state->replyv, &state->callerfscales, _state); + + /* + * Reset checkpoint information + */ + lastcheckpointf = ae_maxrealnumber; + lastcheckpointd = ae_maxrealnumber; + lastcheckpointidx = state->repiterationscount; +lbl_22: + if( state->isprimal ) + { + merit0 = gipm2_meritfunction(state, &state->current, state->currentmu, _state); + } + else + { + merit0 = gipm2_meritfunctionpd(state, &state->current, &state->currentmult, state->currentmu, _state); + } + + /* + * Trace iteration start + */ + if( state->dotrace ) + { + ae_trace("\n=== ITERATION %5d STARTED ========================================================================\n", + (int)(state->repiterationscount)); + ae_trace("mu = %11.3e\n", + (double)(state->currentmu)); + ae_trace("lambda = %11.3e (damping term for the Hessian)\n", + (double)(state->lambdav)); + ae_trace("lambda_decay = %7.4f (decay for the damping term)\n", + (double)(state->lambdadecay)); + ae_trace("|x|inf = %11.3e\n", + (double)(rmaxabsv(np, &state->current.xp, _state))); + if( state->hassoftbc ) + { + ae_trace("|sxl/u|inf = %11.3e (relaxation slacks for box constraints)\n", + (double)(ae_maxreal(rmaxabsv(np, &state->current.sxl, _state), rmaxabsv(np, &state->current.sxu, _state), _state))); + } + ae_assert(mtotal-state->mflex==0, "GIPM2: 154352", _state); + if( state->hassoftbc ) + { + ae_trace("|pxl/u|inf = %11.3e (relaxation penalties for box constraints)\n", + (double)(ae_maxreal(rmaxabsv(np, &state->pxl, _state), rmaxabsv(np, &state->pxu, _state), _state))); + } + ae_assert(mtotal-state->mflex==0, "GIPM2: 157352", _state); + ae_trace("err.bc = %11.3e\n", + (double)(state->repbcerr)); + ae_trace("err.nlc = %11.3e\n", + (double)(state->repnlcerr)); + ae_trace("\n"); + } + + /* + * Recompute vector of primal multipliers (for primal algorithm). + * + * We use PrevMu instead of CurrentMu in order to gracefully handle decrease of + * barrier parameter. + */ + if( state->isprimal ) + { + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->currentmult, _state); + if( state->inneriterationidx>=state->multupdatedelay ) + { + gipm2_computeprimalmult(state, &state->current, state->currentmu, &state->delayedmult, _state); + } + } + + /* + * Compute residual for the non-condensed unsymmetric primal-dual system. + * Compute errors, check stopping and stagnation criteria. + */ + gipm2_computerhs(state, &state->current, state->currentmu, &state->currentmult, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + minedual = ae_minreal(minedual, edual, _state); + gnrm = (double)(0); + gnrm = gnrm+rdotv2(np, &state->rhs.rp, _state); + if( state->hassoftbc ) + { + gnrm = gnrm+rdotv2(np, &state->rhs.rpsxl, _state); + gnrm = gnrm+rdotv2(np, &state->rhs.rpsxu, _state); + } + if( state->mflex>0 ) + { + gnrm = gnrm+rdotv2(state->mflex, &state->rhs.rpgl, _state); + gnrm = gnrm+rdotv2(state->mflex, &state->rhs.rpgu, _state); + gnrm = gnrm+rdotv2(state->mflex, &state->rhs.rpsxf, _state); + } + ae_assert(mtotal-state->mflex==0, "GIPM: 149243", _state); + gnrm = ae_sqrt(gnrm, _state); + rhs0 = ae_maxreal(eprim, edual, _state); + emax = rmax3(eprim, edual, ecmpl, _state); + if( state->dotrace ) + { + ae_trace("> computing absolute errors for the barrier problem:\n"); + ae_trace("primal = %0.3e\n", + (double)(eprim)); + ae_trace("dual = %0.3e\n", + (double)(edual)); + ae_trace("cmpl = %0.3e\n", + (double)(ecmpl)); + ae_trace("e.max = %0.3e\n", + (double)(emax)); + } + worsethanbest = ae_fp_greater(gipm2_aggregateerr(eprim, edual, state->currentmu+ecmpl, _state),state->besterr); + if( (ae_fp_less(merit0,lastcheckpointf-gipm2_checkpointacceptancef*ae_fabs(lastcheckpointf, _state))||ae_fp_less(edual,gipm2_checkpointacceptanced*lastcheckpointd))||ae_fp_less(ecmpl,gipm2_checkpointacceptancec*lastcheckpointc) ) + { + + /* + * Significant progress achieved for at least one parameter. Save checkpoint (used to detect stagnation). + * + * NOTE: it is important that the comparison is strict! Non-strict comparison is likely to cause inability to + * detect stagnation should any error become exactly zero. + */ + lastcheckpointf = ae_minreal(lastcheckpointf, merit0, _state); + lastcheckpointd = ae_minreal(lastcheckpointd, edual, _state); + lastcheckpointc = ae_minreal(lastcheckpointc, ecmpl, _state); + lastcheckpointidx = state->repiterationscount; + } + if( ae_fp_less_eq(rmaxabs3(eprim/v, edual/vv, ecmpl/v2, _state),state->muepsfactor*state->currentmu) ) + { + if( state->dotrace ) + { + ae_trace("> stopping criteria for inner iterations met (relative error is small enough), exit to outer iteration\n"); + } + goto lbl_21; + } + if( state->rejectedwithineps>=gipm2_maxrejectedwithineps ) + { + if( state->dotrace ) + { + ae_trace("> %0d short steps (within Eps) or more in a row were rejected, exit to outer iteration\n", + (int)(gipm2_maxrejectedwithineps)); + } + goto lbl_21; + } + if( ae_fp_greater_eq(state->lambdav,gipm2_lambdamax) ) + { + if( state->dotrace ) + { + ae_trace("> regularization is at maximum, stopping inner iterations\n"); + } + state->lambdav = (double)(1); + state->lambdadecay = (double)(1); + goto lbl_21; + } + if( state->repiterationscount>lastcheckpointidx+state->maxcheckpointstagnationits ) + { + if( state->dotrace ) + { + ae_trace("> iteration stagnated (no new checkpoints for %0d its)\n", + (int)(state->maxcheckpointstagnationits)); + } + state->repterminationtype = 7; + goto lbl_21; + } + + /* + * Condense LHS (system matrix) and perform modified RCOMM request to factorize it + */ + if( state->isprimal ) + { + gipm2_condenselhs(state, &state->current, &state->delayedmult, state->currentmu, state->lambdav, &state->condensed, _state); + } + else + { + gipm2_condenselhs(state, &state->current, &state->currentmult, state->currentmu, state->lambdav, &state->condensed, _state); + } + state->requesttype = 1001; + state->factsuccess = ae_false; + rallocv(np+mtotal, &state->querydata, _state); + rcopyvx(np, &state->condensed.d0, 0, &state->querydata, 0, _state); + rcopyvx(mtotal, &state->condensed.d1, 0, &state->querydata, np, _state); + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + if( !state->factsuccess ) + { + if( state->subsequentfactfailures<=gipm2_maxsubsequentfailuresforweakgrowth ) + { + + /* + * Slowly growing Lambda + */ + if( state->dotrace ) + { + ae_trace("> factorization failed, Hessian is not sufficiently positive definite, increasing damping factor\n"); + } + state->lambdav = rcase2(lambdafound, gipm2_lambdagrowth, (double)(10), _state)*ae_maxreal(state->lambdav, state->currentmu, _state); + state->lambdadecay = 1.0; + } + else + { + + /* + * Many subsequent failures, rapid growth + */ + if( state->dotrace ) + { + ae_trace("> factorization failed too many times in a row, rapid growth of LambdaV is activated\n"); + } + state->lambdav = ae_maxreal(gipm2_lambdarapidgrowth*state->lambdav, 0.001*state->currentmu, _state); + state->lambdadecay = 1.0; + } + state->subsequentfactfailures = state->subsequentfactfailures+1; + goto lbl_20; + } + state->subsequentfactfailures = 0; + lambdafound = lambdafound||ae_fp_neq(state->lambdav,(double)(0)); + + /* + * Run iterative refinement + */ + gipm2_copyrhs(state, &state->rhs, &state->tmprhs, _state); + rhsk = ae_maxrealnumber; + gipm2_varsinitbyzero(&state->delta, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + gipm2_multinitbyzero(&state->deltamult, np, state->mflex, state->meq, state->mrlxeq, state->m1, state->mrlx1, state->hashardbc, state->hassoftbc, _state); + rfsidx = 0; +lbl_24: + if( rfsidx>gipm2_maxrfsits-1 ) + { + goto lbl_26; + } + if( state->isprimal ) + { + gipm2_condenserhs(state, &state->current, &state->delayedmult, &state->tmprhs, state->currentmu, state->lambdav, &state->condensed, _state); + } + else + { + gipm2_condenserhs(state, &state->current, &state->currentmult, &state->tmprhs, state->currentmu, state->lambdav, &state->condensed, _state); + } + state->requesttype = 1002; + rallocv(np+mtotal, &state->querydata, _state); + rcopyvx(np, &state->condensed.wx, 0, &state->querydata, 0, _state); + rcopyvx(mtotal, &state->condensed.wy, 0, &state->querydata, np, _state); + rallocv(np+mtotal, &state->replysol, _state); + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + if( state->isprimal ) + { + gipm2_unpacksolution(state, &state->current, &state->delayedmult, state->currentmu, state->lambdav, &state->tmprhs, &state->condensed, &state->replysol, &state->corr, &state->corrmult, _state); + } + else + { + gipm2_unpacksolution(state, &state->current, &state->currentmult, state->currentmu, state->lambdav, &state->tmprhs, &state->condensed, &state->replysol, &state->corr, &state->corrmult, _state); + } + gipm2_varsapplystep(&state->delta, &state->corr, 1.0, _state); + gipm2_multapplystep(&state->deltamult, &state->corrmult, 1.0, _state); + state->requesttype = 1003; + ae_assert(mtotal==state->mflex, "GIPM2: 015342", _state); + rallocv(np+mtotal, &state->querydata, _state); + rallocv(np+mtotal+np, &state->replyprod, _state); + rcopyvx(np, &state->corr.xp, 0, &state->querydata, 0, _state); + rcopyvx(mtotal, &state->corrmult.zcf, 0, &state->querydata, np, _state); + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + rallocv(np, &state->tmphdxp, _state); + rallocv(mtotal, &state->tmpjdxp, _state); + rallocv(np, &state->tmpjtdy, _state); + rcopyvx(np, &state->replyprod, 0, &state->tmphdxp, 0, _state); + rcopyvx(mtotal, &state->replyprod, np, &state->tmpjdxp, 0, _state); + rcopyvx(np, &state->replyprod, np+mtotal, &state->tmpjtdy, 0, _state); + if( state->isprimal ) + { + rhsk = gipm2_computeupdateresidual(state, &state->current, &state->delayedmult, state->currentmu, state->lambdav, &state->corr, &state->corrmult, &state->tmphdxp, &state->tmpjdxp, &state->tmpjtdy, &state->tmprhs, _state); + } + else + { + rhsk = gipm2_computeupdateresidual(state, &state->current, &state->currentmult, state->currentmu, state->lambdav, &state->corr, &state->corrmult, &state->tmphdxp, &state->tmpjdxp, &state->tmpjtdy, &state->tmprhs, _state); + } + if( state->dotrace ) + { + ae_trace("> analyzing solution to the linear system, relative residual norm is %0.2e\n", + (double)(rhsk/coalesce(rhs0, (double)(1), _state))); + } + if( ae_fp_less(rhsk,gipm2_rhstol*rhs0) ) + { + if( state->dotrace ) + { + ae_trace("> residual norm is small enough, stopping refinement\n"); + } + goto lbl_26; + } + rfsidx = rfsidx+1; + goto lbl_24; +lbl_26: + if( ae_fp_greater(rhsk,ae_maxreal((double)2*gipm2_rhstol, 0.001, _state)*rhs0) ) + { + if( state->dotrace ) + { + ae_trace("> iterative refinement failed to sufficiently decrease residual, increasing Lambda and retrying\n"); + } + state->lambdav = ae_maxreal((double)10*state->lambdav, (double)1000*ae_machineepsilon*((double)1/state->currentmu), _state); + state->lambdadecay = 1.0; + state->repiterationscount = state->repiterationscount+1; + goto lbl_20; + } + state->dxpnrm = rmaxabsv(np, &state->delta.xp, _state); + + /* + * Perform line search + */ + cmpl0 = gipm2_computeecmpl2(state, &state->rhs, _state); + if( state->nonmonotonicmemlen<0 ) + { + gipm2_nonmonotonicinit(state, gipm2_maxnd, merit0, _state); + } + if( state->isprimal ) + { + alpha = gipm2_computesteplengthp(state, &state->current, &state->delta, _state); + } + else + { + alpha = gipm2_computesteplengthpd(state, &state->current, &state->delta, &state->currentmult, &state->deltamult, _state); + } + if( state->dotrace ) + { + ae_trace("> |dXP|=%0.2e, computed maximum step length: alpha=%0.6f\n", + (double)(state->dxpnrm), + (double)(alpha)); + } + smalltrials = 0; + btits = 0; + monotonicallyaccepted = ae_false; + accepted = ae_false; +lbl_27: + if( ae_false ) + { + goto lbl_28; + } + + /* + * Preliminary checks + */ + if( ae_fp_less(alpha,gipm2_smallstep) ) + { + smalltrials = smalltrials+1; + } + if( smalltrials>=gipm2_maxsmalltrials ) + { + alpha = (double)(0); + goto lbl_28; + } + + /* + * Evaluate objective/constraints at the trial point, update multipliers according to the step and method (primal or primal-dual) + */ + gipm2_varscopy(&state->current, &state->cand, _state); + gipm2_varsapplystep(&state->cand, &state->delta, alpha, _state); + gipm2_sendx(state, &state->cand.xp, _state); + state->requesttype = 1; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + if( !gipm2_retrievefij(state, &state->cand, _state) ) + { + + /* + * Failed to retrieve function/Jacobian, infinities detected! + */ + if( state->dotrace ) + { + ae_trace("> objective/constraints contain infinities or NANs, promoting shorter steps\n"); + } + state->infinitiesdetected = ae_true; + state->failedtorecoverfrominfinities = ae_true; + alpha = 0.5*alpha; + goto lbl_27; + } + if( !state->isprimal ) + { + gipm2_multcopy(&state->currentmult, &state->candmult, _state); + gipm2_multapplystep(&state->candmult, &state->deltamult, alpha, _state); + } + else + { + gipm2_computeprimalmult(state, &state->cand, state->currentmu, &state->candmult, _state); + } + state->failedtorecoverfrominfinities = ae_false; + + /* + * Control violation of hard constraints + */ + violated = ae_false; + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 240129", _state); + if( violated ) + { + btits = btits+1; + alpha = 0.5*alpha; + goto lbl_27; + } + + /* + * Compute merit function and report step + */ + gipm2_computerhs(state, &state->cand, state->currentmu, &state->candmult, &state->candrhs, &eprim2, &edual2, &ecmpl2, &v, &vv, &v2, _state); + if( state->isprimal ) + { + merit1 = gipm2_meritfunction(state, &state->cand, state->currentmu, _state); + } + else + { + merit1 = gipm2_meritfunctionpd(state, &state->cand, &state->candmult, state->currentmu, _state); + } + cmpl1 = gipm2_computeecmpl2(state, &state->candrhs, _state); + if( state->dotrace ) + { + ae_trace("> stp=%11.3e dMerit=%14.6e\n", + (double)(alpha), + (double)(merit1-merit0)); + } + + /* + * Decide + */ + monotonicallyaccepted = ae_fp_less(merit1,merit0); + accepted = monotonicallyaccepted||ae_fp_less(merit1,merit0+gipm2_nonmonotonicgetcorr(state, merit0, _state)); + if( accepted ) + { + goto lbl_28; + } + + /* + * The step is not accepted, decrease Alpha + */ + btits = btits+1; + alpha = 0.5*alpha; + goto lbl_27; +lbl_28: + + /* + * Handle line search end + */ + if( !accepted ) + { + if( state->dotrace ) + { + ae_trace("> line search failed to provide sufficient decrease, stopping optimizer with TerminationType=7\n"); + } + state->repterminationtype = 7; + goto lbl_21; + } + if( btits>=3 ) + { + state->lambdav = ae_maxreal((double)2*state->lambdav, 0.0001*ae_sqrt(gnrm, _state), _state); + state->lambdadecay = 1.0; + if( state->dotrace ) + { + ae_trace("> too many backtracking its performed, increasing regularization coeff LambdaV to %0.2e\n", + (double)(state->lambdav)); + } + } + else + { + if( monotonicallyaccepted ) + { + state->lambdav = ae_maxreal(state->lambdav*state->lambdadecay, ae_machineepsilon*ae_machineepsilon, _state); + state->lambdadecay = ae_maxreal(state->lambdadecay*gipm2_lambdadecayacc, ae_sqrt(ae_sqrt(ae_machineepsilon, _state), _state), _state); + } + else + { + state->lambdadecay = 1.0; + } + } + if( state->dotrace ) + { + ae_trace("> line search finished with alpha=%0.2e\n", + (double)(alpha)); + ae_trace("> f: %0.9e -> %0.9e (delta=%0.3e)\n", + (double)(state->current.fi.ptr.p_double[0]), + (double)(state->cand.fi.ptr.p_double[0]), + (double)(state->cand.fi.ptr.p_double[0]-state->current.fi.ptr.p_double[0])); + ae_trace("> meritf: %0.9e -> %0.9e (delta=%0.3e)\n", + (double)(merit0), + (double)(merit1), + (double)(merit1-merit0)); + } + if( state->dotrace ) + { + ae_trace("> evaluating proposed step:\n"); + ae_trace("targetF: %17.9e -> %17.9e (delta=%11.3e, raw)\n", + (double)(state->callerfscales.ptr.p_double[0]*state->current.fi.ptr.p_double[0]), + (double)(state->callerfscales.ptr.p_double[0]*state->cand.fi.ptr.p_double[0]), + (double)(state->callerfscales.ptr.p_double[0]*(state->cand.fi.ptr.p_double[0]-state->current.fi.ptr.p_double[0]))); + ae_trace("meritF: %17.9e -> %17.9e (delta=%11.3e, target + barrier + penalty, predicted=%11.3e)\n", + (double)(merit0), + (double)(merit1), + (double)(merit1-merit0), + (double)(alpha*gipm2_computedg(state, &state->delta, &state->rhs, _state))); + ae_trace("meritF+corr: %17.9e -> %17.9e (delta=%11.3e, step subject to nonmonotonic correction)\n", + (double)(merit0), + (double)(merit1-gipm2_nonmonotonicgetcorr(state, merit0, _state)), + (double)(merit1-merit0-gipm2_nonmonotonicgetcorr(state, merit0, _state))); + ae_trace("dualErr: %17.9e -> %17.9e (delta=%11.3e, gradient inf-norm)\n", + (double)(edual), + (double)(edual2), + (double)(edual2-edual)); + if( !state->isprimal ) + { + ae_trace("cmplErr: %17.9e -> %17.9e (delta=%11.3e, complementarity residual inf-norm)\n", + (double)(ecmpl), + (double)(ecmpl2), + (double)(ecmpl2-ecmpl)); + } + ae_trace("(D,G): %17.9e -> %17.9e\n", + (double)(gipm2_computedg(state, &state->delta, &state->rhs, _state)), + (double)(gipm2_computedg(state, &state->delta, &state->candrhs, _state))); + if( ae_fp_less(merit1,merit0) ) + { + ae_trace("> step is accepted\n"); + } + else + { + ae_trace("> step is nonmonotonically accepted\n"); + } + } + ae_assert(!state->isprimal, "GIPM2: 004122", _state); + gipm2_sendlagrangianinfo(state, &state->current, &state->candmult, &state->cand, &state->candmult, ae_false, _state); + state->requesttype = 1008; + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + gipm2_varscopy(&state->cand, &state->current, _state); + gipm2_multcopy(&state->candmult, &state->currentmult, _state); + rcopyv(state->np, &state->current.xp, &state->reportx, _state); + state->reportf = state->current.fi.ptr.p_double[0]; + state->requesttype = -1; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + + /* + * Next iteration + */ + state->requesttype = 1000; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->lastprim = eprim; + state->lastdual = edual; + state->lastcmpl = ecmpl; + ae_assert(ae_fp_neq(state->lambdav,(double)(0)), "GIPM2: 429219", _state); + state->inneriterationidx = state->inneriterationidx+1; + state->repiterationscount = state->repiterationscount+1; + state->rhsstagnationcounter = state->rhsstagnationcounter+1; + state->goodinnerits = state->goodinnerits+1; + state->prevmu = state->currentmu; + state->failedtorecoverfrominfinities = ae_false; + gipm2_updateerrorestimates(state, _state); + gipm2_nonmonotonicpush(state, merit1, _state); + goto lbl_20; +lbl_21: + state->firstouteriteration = ae_false; + if( state->dotrace ) + { + ae_trace("\n----- outer iteration ------------------------------------------------------------------------------\n"); + } + if( userterminationneeded ) + { + if( state->dotrace ) + { + ae_trace("> user requested immediate termination, stopping\n"); + } + state->repterminationtype = 8; + goto lbl_19; + } + if( state->repterminationtype!=0 ) + { + goto lbl_19; + } + if( state->unboundednesssuspected ) + { + if( (ae_fp_less_eq(state->currentmu,1.001*state->mumin)&&ae_fp_greater_eq(state->curbigval,0.999*gipm2_maxbigval))&&ae_fp_greater_eq(state->curbiggrowth,0.999*gipm2_maxbiggrowth) ) + { + if( state->dotrace ) + { + ae_trace("> unboundedness detected (mu at minimum, thresholds at maximum, the problem is still unbounded)\n"); + } + state->repterminationtype = -4; + goto lbl_19; + } + if( state->dotrace ) + { + ae_trace("> decreasing mu, increasing unboundedness detection thresholds, continuing iterations\n"); + } + state->currentmu = ae_maxreal(state->mumin, 0.01*state->currentmu, _state); + state->curbigval = ae_minreal(gipm2_vggrowth*state->curbigval, gipm2_maxbigval, _state); + state->curbiggrowth = ae_minreal(gipm2_vggrowth*state->curbiggrowth, gipm2_maxbiggrowth, _state); + goto lbl_18; + } + + /* + * Recompute RHS from scratch (less dependency on the internal loop). + * Check primal/dual/complementarity errors. + */ + gipm2_computerhs(state, &state->current, state->currentmu, &state->currentmult, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + emax = gipm2_aggregateerr(eprim, edual, state->currentmu+ecmpl, _state); + if( state->dotrace ) + { + ae_trace("> recomputing absolute errors, taking complementarity error in account:\n"); + ae_trace("primal = %0.3e\n", + (double)(eprim)); + ae_trace("dual = %0.3e\n", + (double)(edual)); + ae_trace("cmpl = %0.3e\n", + (double)(state->currentmu+ecmpl)); + } + if( ae_fp_less_eq(rmax3(eprim/v, edual/vv, state->currentmu+ecmpl/v2, _state),state->eps) ) + { + if( state->dotrace ) + { + ae_trace("> stopping criteria for outer iterations are met (relative error is below Eps=%0.2e), solved\n", + (double)(state->eps)); + } + state->repterminationtype = 2; + goto lbl_19; + } + if( ae_fp_less_eq(state->currentmu,1.001*state->mumin) ) + { + if( state->dotrace ) + { + ae_trace("> mu is at minimum, stagnation detected, stopping\n"); + } + state->repterminationtype = 7; + goto lbl_19; + } + + /* + * Stopping criteria are not met, continuing iteration, save the best point so far + */ + if( ae_fp_greater_eq(emax,state->besterr) ) + { + goto lbl_29; + } + gipm2_varscopy(&state->current, &state->best, _state); + gipm2_lagcoeffsfrommultipliers(&state->currentmult, &state->bestlagbc, &state->bestlagnlc, _state); + state->besterr = emax; + state->hasbest = ae_true; + state->requesttype = 1006; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + if( state->dotrace ) + { + ae_trace("> the point provides the best prim/dual errors so far, saving\n"); + } + goto lbl_30; +lbl_29: + if( state->dotrace ) + { + ae_trace("> the point does not improve over the best prim/dual errors so far, not saved\n"); + } +lbl_30: + + /* + * Inner iterations are over, tighten/relax bounds if necessary and decrease Mu + */ + gipm2_tunepenalties(state, &state->currentmult, _state); + gipm2_tightenrelaxbounds(state, _state); + state->currentmu = ae_maxreal(state->mumin, ae_minreal(state->mudecaylinear*state->currentmu, ae_pow(state->currentmu, state->mudecaypower, _state), _state), _state); + goto lbl_18; +lbl_19: + + /* + * Almost done: + * * compare error at State.Current with one at State.Best, restore from State.Best + * if optimizer went in wrong direction + * * set completion flags + */ + if( state->dotrace ) + { + ae_trace("\n=== STOPPED ========================================================================================\n"); + } + gipm2_computerhs(state, &state->current, state->currentmu, &state->currentmult, &state->rhs, &eprim, &edual, &ecmpl, &v, &vv, &v2, _state); + if( ae_fp_less_eq(gipm2_aggregateerr(eprim, edual, state->currentmu+ecmpl, _state),state->besterr) ) + { + goto lbl_31; + } + + /* + * Restore the best point so far. + * + * It is essential that Request=1007 is ussued prior to Request=-1 + */ + gipm2_varscopy(&state->best, &state->current, _state); + rcopyv(state->np, &state->current.xp, &state->reportx, _state); + state->requesttype = 1007; + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + state->reportf = state->current.fi.ptr.p_double[0]; + state->requesttype = -1; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + gipm2_updateerrorestimates(state, _state); + if( state->dotrace ) + { + ae_trace("> the last accepted point is worse than the best one seen so far (p/d/c err: %0.2e vs %0.2e), restoring the best one\n", + (double)(gipm2_aggregateerr(eprim, edual, state->currentmu+ecmpl, _state)), + (double)(state->besterr)); + } +lbl_31: + if( state->infinitiesdetected ) + { + state->repterminationtype = icase2(state->failedtorecoverfrominfinities, -8, state->repterminationtype+800, _state); + } + if( state->dotrace ) + { + if( state->infinitiesdetected&&state->failedtorecoverfrominfinities ) + { + ae_trace("> infinities were detected, but we failed to recover by decreasing trust radius; declaring failure with the code -8\n"); + } + ae_trace("raw target: %20.12e\n", + (double)(state->current.fi.ptr.p_double[0]*state->callerfscales.ptr.p_double[0])); + } + smoothnessmonitortracestatus(smonitor, state->dotrace, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = np; + state->rstate.ia.ptr.p_int[1] = mtotal; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = rfsidx; + state->rstate.ia.ptr.p_int[4] = lastcheckpointidx; + state->rstate.ia.ptr.p_int[5] = smalltrials; + state->rstate.ia.ptr.p_int[6] = btits; + state->rstate.ia.ptr.p_int[7] = jj; + state->rstate.ba.ptr.p_bool[0] = accepted; + state->rstate.ba.ptr.p_bool[1] = worsethanbest; + state->rstate.ba.ptr.p_bool[2] = monotonicallyaccepted; + state->rstate.ba.ptr.p_bool[3] = violated; + state->rstate.ba.ptr.p_bool[4] = lambdafound; + state->rstate.ra.ptr.p_double[0] = gnrm; + state->rstate.ra.ptr.p_double[1] = v; + state->rstate.ra.ptr.p_double[2] = vv; + state->rstate.ra.ptr.p_double[3] = v2; + state->rstate.ra.ptr.p_double[4] = alpha; + state->rstate.ra.ptr.p_double[5] = eprim; + state->rstate.ra.ptr.p_double[6] = edual; + state->rstate.ra.ptr.p_double[7] = ecmpl; + state->rstate.ra.ptr.p_double[8] = emax; + state->rstate.ra.ptr.p_double[9] = eprim2; + state->rstate.ra.ptr.p_double[10] = edual2; + state->rstate.ra.ptr.p_double[11] = ecmpl2; + state->rstate.ra.ptr.p_double[12] = rhs0; + state->rstate.ra.ptr.p_double[13] = rhsk; + state->rstate.ra.ptr.p_double[14] = merit0; + state->rstate.ra.ptr.p_double[15] = merit1; + state->rstate.ra.ptr.p_double[16] = cmpl0; + state->rstate.ra.ptr.p_double[17] = cmpl1; + state->rstate.ra.ptr.p_double[18] = initprimdual; + state->rstate.ra.ptr.p_double[19] = minedual; + state->rstate.ra.ptr.p_double[20] = lastcheckpointf; + state->rstate.ra.ptr.p_double[21] = lastcheckpointd; + state->rstate.ra.ptr.p_double[22] = lastcheckpointc; + return result; +} + + +/************************************************************************* +Extract solution + +INPUT PARAMETERS: + State - solver instance + +OUTPUT PARAMETERS: + XS - array[N], solution + LagBC - array[N], Lagrange multipliers for box constraints + LagXC - array[MTotal], Lagrange multipliers for a;; constraints + TerminationType - completion code, positive values for success, + negative for failures (XS constrains best point + found so far): + * -2 the task is either unbounded or infeasible; + the IPM solver has difficulty distinguishing between these two. + * +1 stopping criteria are met + * +7 stopping criteria are too stringent + +RESULT: + +This function ALWAYS returns something meaningful in XS, LagBC, LagLC - +either solution or the best point so far, even for negative TerminationType. + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +void gipm2results(gipm2state* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagxc, + ae_int_t* terminationtype, + ae_state *_state) +{ + + *terminationtype = 0; + + *terminationtype = state->repterminationtype; + rcopyallocv(state->np, &state->current.xp, xs, _state); + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 566358 failed", _state); + rcopyallocv(state->np, &state->bestlagbc, lagbc, _state); + rcopyallocv(state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1, &state->bestlagnlc, lagxc, _state); +} + + +/************************************************************************* +Allocates place for variables of IPM and fills by zeros. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_varsinitbyzero(gipm2vars* vstate, + ae_int_t np, + ae_int_t mflex, + ae_int_t meq, + ae_int_t mrlxeq, + ae_int_t m1, + ae_int_t mrlx1, + ae_bool hashardbc, + ae_bool hassoftbc, + ae_state *_state) +{ + ae_int_t i; + ae_int_t mtotal; + + + mtotal = mflex+meq+mrlxeq+m1+mrlx1; + ae_assert(np>=1, "VarsInitByZero: N<1", _state); + ae_assert(mtotal-mflex==0&&!(hashardbc&&hassoftbc), "VarsInitByZero: integrity check 471355 failed", _state); + vstate->hashardbc = hashardbc; + vstate->hassoftbc = hassoftbc; + vstate->np = np; + vstate->mflex = mflex; + vstate->meq = 0; + vstate->mrlxeq = 0; + vstate->m1 = 0; + vstate->mrlx1 = 0; + rsetallocv(np, 0.0, &vstate->xp, _state); + if( hassoftbc ) + { + rsetallocv(np, 0.0, &vstate->sxl, _state); + rsetallocv(np, 0.0, &vstate->sxu, _state); + } + if( mflex!=0 ) + { + rsetallocv(mflex, 0.0, &vstate->sxf, _state); + rsetallocv(mflex, 0.0, &vstate->gl, _state); + rsetallocv(mflex, 0.0, &vstate->gu, _state); + } + rsetallocv(1+mtotal, 0.0, &vstate->fi, _state); + sparsecreatecrsemptybuf(np, &vstate->jac, _state); + for(i=0; i<=mtotal-1; i++) + { + sparseappendemptyrow(&vstate->jac, _state); + } +} + + +/************************************************************************* +Allocates place for variables of IPM and fills by zeros. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_multinitbyzero(gipm2mult* vstate, + ae_int_t np, + ae_int_t mflex, + ae_int_t meq, + ae_int_t mrlxeq, + ae_int_t m1, + ae_int_t mrlx1, + ae_bool hashardbc, + ae_bool hassoftbc, + ae_state *_state) +{ + ae_int_t mtotal; + + + mtotal = mflex+meq+mrlxeq+m1+mrlx1; + ae_assert(np>=1, "MultInitByZero: N<1", _state); + ae_assert(mtotal-mflex==0&&!(hashardbc&&hassoftbc), "MultInitByZero: integrity check 496128 failed", _state); + vstate->hashardbc = hashardbc; + vstate->hassoftbc = hassoftbc; + vstate->np = np; + vstate->mflex = mflex; + vstate->meq = 0; + vstate->mrlxeq = 0; + vstate->m1 = 0; + vstate->mrlx1 = 0; + if( hashardbc ) + { + rsetallocv(np, 0.0, &vstate->zxl, _state); + rsetallocv(np, 0.0, &vstate->zxu, _state); + } + if( hassoftbc ) + { + rsetallocv(np, 0.0, &vstate->zxl, _state); + rsetallocv(np, 0.0, &vstate->zxu, _state); + rsetallocv(np, 0.0, &vstate->zsxl, _state); + rsetallocv(np, 0.0, &vstate->zsxu, _state); + rsetallocv(np, 0.0, &vstate->zsxlcap, _state); + rsetallocv(np, 0.0, &vstate->zsxucap, _state); + } + if( mflex>0 ) + { + rsetallocv(mflex, 0.0, &vstate->zcf, _state); + rsetallocv(mflex, 0.0, &vstate->zgl, _state); + rsetallocv(mflex, 0.0, &vstate->zgu, _state); + rsetallocv(mflex, 0.0, &vstate->zcfgl, _state); + rsetallocv(mflex, 0.0, &vstate->zcfgu, _state); + } +} + + +/************************************************************************* +Applies step to primal and slack vars. Invalidates all potential dual +information, function vector and Jacobian + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_varsapplystep(gipm2vars* vstate, + const gipm2vars* delta, + double alpha, + ae_state *_state) +{ + + + raddv(vstate->np, alpha, &delta->xp, &vstate->xp, _state); + if( vstate->hassoftbc ) + { + raddv(vstate->np, alpha, &delta->sxl, &vstate->sxl, _state); + raddv(vstate->np, alpha, &delta->sxu, &vstate->sxu, _state); + } + if( vstate->mflex!=0 ) + { + raddv(vstate->mflex, alpha, &delta->sxf, &vstate->sxf, _state); + raddv(vstate->mflex, alpha, &delta->gl, &vstate->gl, _state); + raddv(vstate->mflex, alpha, &delta->gu, &vstate->gu, _state); + } + ae_assert(vstate->meq+vstate->mrlxeq+vstate->m1+vstate->mrlx1==0, "GIPM2: 414056", _state); +} + + +/************************************************************************* +Applies step to multipliers + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_multapplystep(gipm2mult* vstate, + const gipm2mult* delta, + double alpha, + ae_state *_state) +{ + + + if( vstate->hashardbc ) + { + ae_assert(!vstate->hassoftbc, "GIPM2: 586955", _state); + raddv(vstate->np, alpha, &delta->zxl, &vstate->zxl, _state); + raddv(vstate->np, alpha, &delta->zxu, &vstate->zxu, _state); + } + if( vstate->hassoftbc ) + { + ae_assert(!vstate->hashardbc, "GIPM2: 592956", _state); + raddv(vstate->np, alpha, &delta->zxl, &vstate->zxl, _state); + raddv(vstate->np, alpha, &delta->zxu, &vstate->zxu, _state); + raddv(vstate->np, alpha, &delta->zsxl, &vstate->zsxl, _state); + raddv(vstate->np, alpha, &delta->zsxu, &vstate->zsxu, _state); + raddv(vstate->np, alpha, &delta->zsxlcap, &vstate->zsxlcap, _state); + raddv(vstate->np, alpha, &delta->zsxucap, &vstate->zsxucap, _state); + } + if( vstate->mflex>0 ) + { + raddv(vstate->mflex, alpha, &delta->zcf, &vstate->zcf, _state); + raddv(vstate->mflex, alpha, &delta->zgl, &vstate->zgl, _state); + raddv(vstate->mflex, alpha, &delta->zgu, &vstate->zgu, _state); + raddv(vstate->mflex, alpha, &delta->zcfgl, &vstate->zcfgl, _state); + raddv(vstate->mflex, alpha, &delta->zcfgu, &vstate->zcfgu, _state); + } + ae_assert(vstate->meq+vstate->mrlxeq+vstate->m1+vstate->mrlx1==0, "GIPM2: 547132", _state); +} + + +/************************************************************************* +Copy vars + + -- ALGLIB -- + Copyright 06.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_varscopy(const gipm2vars* src, + gipm2vars* dst, + ae_state *_state) +{ + ae_int_t mtotal; + + + mtotal = src->mflex+src->meq+src->mrlxeq+src->m1+src->mrlx1; + dst->hashardbc = src->hashardbc; + dst->hassoftbc = src->hassoftbc; + dst->np = src->np; + dst->mflex = src->mflex; + dst->meq = src->meq; + dst->mrlxeq = src->mrlxeq; + dst->m1 = src->m1; + dst->mrlx1 = src->mrlx1; + rcopyallocv(src->np, &src->xp, &dst->xp, _state); + if( src->hassoftbc ) + { + rcopyallocv(src->np, &src->sxl, &dst->sxl, _state); + rcopyallocv(src->np, &src->sxu, &dst->sxu, _state); + } + rcopyallocv(src->mflex, &src->sxf, &dst->sxf, _state); + rcopyallocv(src->mflex, &src->gl, &dst->gl, _state); + rcopyallocv(src->mflex, &src->gu, &dst->gu, _state); + ae_assert(mtotal-src->mflex==0, "GIPM2: integrity check 554157 failed", _state); + rcopyallocv(1+mtotal, &src->fi, &dst->fi, _state); + sparsecopybuf(&src->jac, &dst->jac, _state); +} + + +/************************************************************************* +Copy multipliers + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_multcopy(const gipm2mult* src, + gipm2mult* dst, + ae_state *_state) +{ + ae_int_t mtotal; + + + mtotal = src->mflex+src->meq+src->mrlxeq+src->m1+src->mrlx1; + dst->hashardbc = src->hashardbc; + dst->hassoftbc = src->hassoftbc; + dst->np = src->np; + dst->mflex = src->mflex; + dst->meq = src->meq; + dst->mrlxeq = src->mrlxeq; + dst->m1 = src->m1; + dst->mrlx1 = src->mrlx1; + if( src->hashardbc ) + { + rcopyallocv(src->np, &src->zxl, &dst->zxl, _state); + rcopyallocv(src->np, &src->zxu, &dst->zxu, _state); + } + if( src->hassoftbc ) + { + rcopyallocv(src->np, &src->zxl, &dst->zxl, _state); + rcopyallocv(src->np, &src->zxu, &dst->zxu, _state); + rcopyallocv(src->np, &src->zsxl, &dst->zsxl, _state); + rcopyallocv(src->np, &src->zsxu, &dst->zsxu, _state); + rcopyallocv(src->np, &src->zsxlcap, &dst->zsxlcap, _state); + rcopyallocv(src->np, &src->zsxucap, &dst->zsxucap, _state); + } + if( src->mflex>0 ) + { + rcopyallocv(src->mflex, &src->zcf, &dst->zcf, _state); + rcopyallocv(src->mflex, &src->zgl, &dst->zgl, _state); + rcopyallocv(src->mflex, &src->zgu, &dst->zgu, _state); + rcopyallocv(src->mflex, &src->zcfgl, &dst->zcfgl, _state); + rcopyallocv(src->mflex, &src->zcfgu, &dst->zcfgu, _state); + } + ae_assert(mtotal-src->mflex==0, "MultCopy: integrity check 825139 failed", _state); +} + + +/************************************************************************* +Computes step length + + -- ALGLIB -- + Copyright 11.02.2025 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_computesteplengthp(const gipm2state* state, + const gipm2vars* current, + const gipm2vars* delta, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + double eps2; + double result; + + + np = state->np; + eps2 = (double)1/ae_sqrt(ae_maxrealnumber, _state); + result = ae_maxrealnumber; + ae_assert(state->isprimal, "GIPM2: 828359 failed", _state); + + /* + * Analyze NP-sized components + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 585353", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&delta->xp.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i])/(eps2-delta->xp.ptr.p_double[i]), _state); + } + if( state->hasbndu.ptr.p_bool[i]&&delta->xp.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i])/(eps2+delta->xp.ptr.p_double[i]), _state); + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 026790", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + if( delta->xp.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*delta->sxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i])/(eps2-(delta->xp.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*delta->sxl.ptr.p_double[i])), _state); + } + if( delta->sxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->sxl.ptr.p_double[i]/(eps2-delta->sxl.ptr.p_double[i]), _state); + } + if( delta->sxl.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i])/(eps2+delta->sxl.ptr.p_double[i]), _state); + } + } + if( state->hasbndu.ptr.p_bool[i] ) + { + if( -delta->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*delta->sxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i])/(eps2-(-delta->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*delta->sxu.ptr.p_double[i])), _state); + } + if( delta->sxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->sxu.ptr.p_double[i]/(eps2-delta->sxu.ptr.p_double[i]), _state); + } + if( delta->sxu.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i])/(eps2+delta->sxu.ptr.p_double[i]), _state); + } + } + } + } + + /* + * analyze MFlex-sized components + */ + for(i=0; i<=state->mflex-1; i++) + { + if( delta->gl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gl.ptr.p_double[i]/(eps2-delta->gl.ptr.p_double[i]), _state); + } + if( delta->gu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gu.ptr.p_double[i]/(eps2-delta->gu.ptr.p_double[i]), _state); + } + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 585352", _state); + + /* + * Apply fraction to boundary + */ + result = ae_minreal(gipm2_fractobnd*result, 1.0, _state); + return result; +} + + +/************************************************************************* +Computes step length + + -- ALGLIB -- + Copyright 11.02.2025 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_computesteplengthpd(const gipm2state* state, + const gipm2vars* current, + const gipm2vars* delta, + const gipm2mult* currentmult, + const gipm2mult* deltamult, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + double eps2; + double result; + + + np = state->np; + eps2 = (double)1/ae_sqrt(ae_maxrealnumber, _state); + result = ae_maxrealnumber; + + /* + * Analyze NP-sized components + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 585353", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + if( delta->xp.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i])/(eps2-delta->xp.ptr.p_double[i]), _state); + } + if( deltamult->zxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zxl.ptr.p_double[i]/(eps2-deltamult->zxl.ptr.p_double[i]), _state); + } + } + if( state->hasbndu.ptr.p_bool[i] ) + { + if( delta->xp.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i])/(eps2+delta->xp.ptr.p_double[i]), _state); + } + if( deltamult->zxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zxu.ptr.p_double[i]/(eps2-deltamult->zxu.ptr.p_double[i]), _state); + } + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 026790", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + if( delta->xp.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*delta->sxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i])/(eps2-(delta->xp.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*delta->sxl.ptr.p_double[i])), _state); + } + if( delta->sxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->sxl.ptr.p_double[i]/(eps2-delta->sxl.ptr.p_double[i]), _state); + } + if( delta->sxl.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i])/(eps2+delta->sxl.ptr.p_double[i]), _state); + } + if( deltamult->zxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zxl.ptr.p_double[i]/(eps2-deltamult->zxl.ptr.p_double[i]), _state); + } + if( deltamult->zsxl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zsxl.ptr.p_double[i]/(eps2-deltamult->zsxl.ptr.p_double[i]), _state); + } + if( deltamult->zsxlcap.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zsxlcap.ptr.p_double[i]/(eps2-deltamult->zsxlcap.ptr.p_double[i]), _state); + } + } + if( state->hasbndu.ptr.p_bool[i] ) + { + if( -delta->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*delta->sxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, (state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i])/(eps2-(-delta->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*delta->sxu.ptr.p_double[i])), _state); + } + if( delta->sxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->sxu.ptr.p_double[i]/(eps2-delta->sxu.ptr.p_double[i]), _state); + } + if( delta->sxu.ptr.p_double[i]>0.0 ) + { + result = ae_minreal(result, (state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i])/(eps2+delta->sxu.ptr.p_double[i]), _state); + } + if( deltamult->zxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zxu.ptr.p_double[i]/(eps2-deltamult->zxu.ptr.p_double[i]), _state); + } + if( deltamult->zsxu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zsxu.ptr.p_double[i]/(eps2-deltamult->zsxu.ptr.p_double[i]), _state); + } + if( deltamult->zsxucap.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zsxucap.ptr.p_double[i]/(eps2-deltamult->zsxucap.ptr.p_double[i]), _state); + } + } + } + } + + /* + * analyze MFlex-sized components + */ + for(i=0; i<=state->mflex-1; i++) + { + if( delta->gl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gl.ptr.p_double[i]/(eps2-delta->gl.ptr.p_double[i]), _state); + } + if( deltamult->zgl.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zgl.ptr.p_double[i]/(eps2-deltamult->zgl.ptr.p_double[i]), _state); + } + if( delta->gu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, current->gu.ptr.p_double[i]/(eps2-delta->gu.ptr.p_double[i]), _state); + } + if( deltamult->zgu.ptr.p_double[i]<0.0 ) + { + result = ae_minreal(result, currentmult->zgu.ptr.p_double[i]/(eps2-deltamult->zgu.ptr.p_double[i]), _state); + } + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 585352", _state); + + /* + * Apply fraction to boundary + */ + result = ae_minreal(gipm2_fractobnd*result, 1.0, _state); + return result; +} + + +/************************************************************************* +Compute primal multiplier estimates + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_computeprimalmult(gipm2state* state, + const gipm2vars* current, + double currentmu, + gipm2mult* mult, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + ae_vector tmp; + ae_int_t rowoffs; + double invmu; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + np = current->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + invmu = (double)1/currentmu; + ae_nxpool_retrieve(&state->mnx1pool, &tmp, _state); + ae_assert(tmp.cnt>=ae_maxint(np, mtotal, _state), "GIPM2: integrity check 7328 failed", _state); + + /* + * Initialize fields + */ + mult->hashardbc = state->hashardbc; + mult->hassoftbc = state->hassoftbc; + mult->np = state->np; + mult->mflex = state->mflex; + mult->meq = state->meq; + mult->mrlxeq = state->mrlxeq; + mult->m1 = state->m1; + mult->mrlx1 = state->mrlx1; + + /* + * Compute primal multiplier estimates for box constraints + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 782132", _state); + rsetallocv(state->np, currentmu, &mult->zxl, _state); + rcopyv(state->np, ¤t->xp, &tmp, _state); + raddv(state->np, -1.0, &state->finitebndl, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zxl, _state); + rmergemulv(state->np, &state->elp, &mult->zxl, _state); + rsetallocv(state->np, currentmu, &mult->zxu, _state); + rcopyv(state->np, &state->finitebndu, &tmp, _state); + raddv(state->np, -1.0, ¤t->xp, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zxu, _state); + rmergemulv(state->np, &state->eup, &mult->zxu, _state); + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 782132", _state); + rsetallocv(state->np, currentmu, &mult->zxl, _state); + rcopyv(state->np, ¤t->xp, &tmp, _state); + raddv(state->np, -1.0, &state->finitebndl, &tmp, _state); + rmuladdv(state->np, &state->softbcql, ¤t->sxl, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zxl, _state); + rmergemulv(state->np, &state->elp, &mult->zxl, _state); + rsetallocv(state->np, currentmu, &mult->zxu, _state); + rcopyv(state->np, &state->finitebndu, &tmp, _state); + raddv(state->np, -1.0, ¤t->xp, &tmp, _state); + rmuladdv(state->np, &state->softbcqu, ¤t->sxu, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zxu, _state); + rmergemulv(state->np, &state->eup, &mult->zxu, _state); + rsetallocv(state->np, currentmu, &mult->zsxl, _state); + rsetv(state->np, ae_sqrt(ae_minrealnumber, _state), &tmp, _state); + raddv(state->np, 1.0, ¤t->sxl, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zsxl, _state); + rmergemulv(state->np, &state->elp, &mult->zsxl, _state); + rsetallocv(state->np, currentmu, &mult->zsxu, _state); + rsetv(state->np, ae_sqrt(ae_minrealnumber, _state), &tmp, _state); + raddv(state->np, 1.0, ¤t->sxu, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zsxu, _state); + rmergemulv(state->np, &state->eup, &mult->zsxu, _state); + rsetallocv(state->np, currentmu, &mult->zsxlcap, _state); + rsetv(state->np, ae_sqrt(ae_minrealnumber, _state), &tmp, _state); + raddv(state->np, 1.0, &state->softbcmsxl, &tmp, _state); + raddv(state->np, -1.0, ¤t->sxl, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zsxlcap, _state); + rmergemulv(state->np, &state->elp, &mult->zsxlcap, _state); + rsetallocv(state->np, currentmu, &mult->zsxucap, _state); + rsetv(state->np, ae_sqrt(ae_minrealnumber, _state), &tmp, _state); + raddv(state->np, 1.0, &state->softbcmsxu, &tmp, _state); + raddv(state->np, -1.0, ¤t->sxu, &tmp, _state); + rmergedivv(state->np, &tmp, &mult->zsxucap, _state); + rmergemulv(state->np, &state->eup, &mult->zsxucap, _state); + } + + /* + * Compute primal multiplier estimates for non-box constraints + */ + rowoffs = 1; + rsetallocv(state->mflex, 0.0, &mult->zcf, _state); + rsetallocv(state->mflex, 0.0, &mult->zcfgl, _state); + rsetallocv(state->mflex, 0.0, &mult->zcfgu, _state); + rsetallocv(state->mflex, 0.0, &mult->zgl, _state); + rsetallocv(state->mflex, 0.0, &mult->zgu, _state); + for(i=0; i<=state->mflex-1; i++) + { + mult->zcf.ptr.p_double[i] = -(current->fi.ptr.p_double[rowoffs]-current->sxf.ptr.p_double[i])*invmu; + if( state->hasflexcl.ptr.p_bool[i] ) + { + mult->zcfgl.ptr.p_double[i] = -(current->sxf.ptr.p_double[i]-current->gl.ptr.p_double[i]-state->flexcl.ptr.p_double[i])*invmu; + mult->zgl.ptr.p_double[i] = currentmu/current->gl.ptr.p_double[i]; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + mult->zcfgu.ptr.p_double[i] = -(current->sxf.ptr.p_double[i]+current->gu.ptr.p_double[i]-state->flexcu.ptr.p_double[i])*invmu; + mult->zgu.ptr.p_double[i] = currentmu/current->gu.ptr.p_double[i]; + } + rowoffs = rowoffs+1; + } + ae_assert(rowoffs==mtotal+1, "GIPM2: 801132", _state); + + /* + * Done + */ + ae_nxpool_recycle(&state->mnx1pool, &tmp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Compute RP part of right-hand side of the Newton system. Used as a part of +ComputeRHS() or to issue Lagrangian updates. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_computerp(gipm2state* state, + const gipm2vars* current, + double currentmu, + const gipm2mult* mult, + /* Real */ ae_vector* rp, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t rowidx; + double v; + + + np = current->np; + rsetallocv(np, 0.0, rp, _state); + j0 = current->jac.ridx.ptr.p_int[0]; + j1 = current->jac.ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + rp->ptr.p_double[current->jac.idx.ptr.p_int[jj]] = -current->jac.vals.ptr.p_double[jj]; + } + raddv(np, -gipm2_damptau*currentmu, ¤t->xp, rp, _state); + if( mult->hashardbc||mult->hassoftbc ) + { + raddv(np, 1.0, &mult->zxl, rp, _state); + raddv(np, -1.0, &mult->zxu, rp, _state); + } + rowidx = 1; + for(i=0; i<=state->mflex-1; i++) + { + v = mult->zcf.ptr.p_double[i]; + j0 = current->jac.ridx.ptr.p_int[rowidx+0]; + j1 = current->jac.ridx.ptr.p_int[rowidx+1]-1; + for(jj=j0; jj<=j1; jj++) + { + rp->ptr.p_double[current->jac.idx.ptr.p_int[jj]] = rp->ptr.p_double[current->jac.idx.ptr.p_int[jj]]+v*current->jac.vals.ptr.p_double[jj]; + } + rowidx = rowidx+1; + } + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 021021", _state); +} + + +/************************************************************************* +Compute RHS for a Newton system, additionally saving dual multiplier +estimates into RHS. + +Returns inf-norms of raw (unnormalized) primal, dual, complementarity errors. +Also returns normalizing coefficients for errors. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_computerhs(gipm2state* state, + const gipm2vars* current, + double currentmu, + const gipm2mult* currentmult, + gipm2rhs* rhs, + double* epriminf, + double* edualinf, + double* ecmplinf, + double* sprim, + double* sdual, + double* scmpl, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + ae_vector tmp; + ae_int_t rowidx; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + *epriminf = 0.0; + *edualinf = 0.0; + *ecmplinf = 0.0; + *sprim = 0.0; + *sdual = 0.0; + *scmpl = 0.0; + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + + np = current->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + ae_nxpool_retrieve(&state->mnx1pool, &tmp, _state); + ae_assert(tmp.cnt>=ae_maxint(np, mtotal, _state), "GIPM2: integrity check 7328 failed", _state); + *epriminf = (double)(0); + *edualinf = (double)(0); + *ecmplinf = (double)(0); + *sprim = (double)(1); + *sdual = (double)(1); + *scmpl = (double)(1); + + /* + * Compute RP = -gmod(xp) + J'*y + ZXL - ZXU + */ + gipm2_computerp(state, current, currentmu, currentmult, &rhs->rp, _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(np, &rhs->rp, _state), _state); + + /* + * Compute RPSXL, RPSXU for a problem with soft box constraints + */ + if( state->hassoftbc ) + { + rallocv(np, &rhs->rpsxl, _state); + rallocv(np, &rhs->rpsxu, _state); + rcopymuladdv(np, ¤tmult->zxl, &state->softbcql, ¤tmult->zsxl, &rhs->rpsxl, _state); + rcopymuladdv(np, ¤tmult->zxu, &state->softbcqu, ¤tmult->zsxu, &rhs->rpsxu, _state); + raddv(np, -1.0, ¤tmult->zsxlcap, &rhs->rpsxl, _state); + raddv(np, -1.0, ¤tmult->zsxucap, &rhs->rpsxu, _state); + raddv(np, -1.0, &state->pxl, &rhs->rpsxl, _state); + raddv(np, -1.0, &state->pxu, &rhs->rpsxu, _state); + rmergemulv(np, &state->elp, &rhs->rpsxl, _state); + rmergemulv(np, &state->eup, &rhs->rpsxu, _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(np, &rhs->rpsxl, _state), _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(np, &rhs->rpsxu, _state), _state); + } + + /* + * Compute RDXL/RDXU, RDSXL/RDSXU and RDSXLCAP/RDSXUCAP, which are zero for a primal-only problem with hard constraints + */ + rsetallocv(np, 0.0, &rhs->rdxl, _state); + rsetallocv(np, 0.0, &rhs->rdxu, _state); + if( state->isprimal ) + { + if( state->hassoftbc ) + { + rsetallocv(np, 0.0, &rhs->rdsxl, _state); + rsetallocv(np, 0.0, &rhs->rdsxu, _state); + rsetallocv(np, 0.0, &rhs->rdsxlcap, _state); + rsetallocv(np, 0.0, &rhs->rdsxucap, _state); + } + } + else + { + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 162459 failed", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + rhs->rdxl.ptr.p_double[i] = currentmu-(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i])*currentmult->zxl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + rhs->rdxu.ptr.p_double[i] = currentmu-(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i])*currentmult->zxu.ptr.p_double[i]; + } + } + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdxl, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdxu, _state), _state); + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 162459 failed", _state); + rsetallocv(np, 0.0, &rhs->rdsxl, _state); + rsetallocv(np, 0.0, &rhs->rdsxu, _state); + rsetallocv(np, 0.0, &rhs->rdsxlcap, _state); + rsetallocv(np, 0.0, &rhs->rdsxucap, _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + rhs->rdxl.ptr.p_double[i] = currentmu-(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i])*currentmult->zxl.ptr.p_double[i]; + rhs->rdsxl.ptr.p_double[i] = currentmu-current->sxl.ptr.p_double[i]*currentmult->zsxl.ptr.p_double[i]; + rhs->rdsxlcap.ptr.p_double[i] = currentmu-(state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i])*currentmult->zsxlcap.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + rhs->rdxu.ptr.p_double[i] = currentmu-(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i])*currentmult->zxu.ptr.p_double[i]; + rhs->rdsxu.ptr.p_double[i] = currentmu-current->sxu.ptr.p_double[i]*currentmult->zsxu.ptr.p_double[i]; + rhs->rdsxucap.ptr.p_double[i] = currentmu-(state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i])*currentmult->zsxucap.ptr.p_double[i]; + } + } + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdxl, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdxu, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdsxl, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdsxu, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdsxlcap, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(np, &rhs->rdsxucap, _state), _state); + } + } + + /* + * FLEX-type constraints: compute Rpsxf, Rpgl, Rpgu, Rdcf, Rdcfgl, Rdcfgu, Rdgl, Rdgu + */ + rowidx = 1; + if( state->mflex>0 ) + { + + /* + * P-type RHS + */ + rsetallocv(state->mflex, 0.0, &rhs->rpsxf, _state); + raddv(state->mflex, -1.0, ¤tmult->zcf, &rhs->rpsxf, _state); + raddv(state->mflex, 1.0, ¤tmult->zcfgl, &rhs->rpsxf, _state); + raddv(state->mflex, 1.0, ¤tmult->zcfgu, &rhs->rpsxf, _state); + rcopyallocv(state->mflex, ¤tmult->zgl, &rhs->rpgl, _state); + raddv(state->mflex, -1.0, ¤tmult->zcfgl, &rhs->rpgl, _state); + rcopyallocv(state->mflex, ¤tmult->zgu, &rhs->rpgu, _state); + raddv(state->mflex, 1.0, ¤tmult->zcfgu, &rhs->rpgu, _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(state->mflex, &rhs->rpsxf, _state), _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(state->mflex, &rhs->rpgl, _state), _state); + *edualinf = ae_maxreal(*edualinf, rmaxabsv(state->mflex, &rhs->rpgu, _state), _state); + + /* + * D-type RHS + */ + rsetallocv(state->mflex, 0.0, &rhs->rdcf, _state); + rsetallocv(state->mflex, 0.0, &rhs->rdcfgl, _state); + rsetallocv(state->mflex, 0.0, &rhs->rdcfgu, _state); + rsetallocv(state->mflex, 0.0, &rhs->rdgl, _state); + rsetallocv(state->mflex, 0.0, &rhs->rdgu, _state); + if( !state->isprimal ) + { + for(i=0; i<=state->mflex-1; i++) + { + rhs->rdcf.ptr.p_double[i] = -(current->fi.ptr.p_double[rowidx]-current->sxf.ptr.p_double[i])-currentmu*currentmult->zcf.ptr.p_double[i]; + if( state->hasflexcl.ptr.p_bool[i] ) + { + rhs->rdcfgl.ptr.p_double[i] = -(current->sxf.ptr.p_double[i]-current->gl.ptr.p_double[i]-state->flexcl.ptr.p_double[i])-currentmu*currentmult->zcfgl.ptr.p_double[i]; + rhs->rdgl.ptr.p_double[i] = currentmu-current->gl.ptr.p_double[i]*currentmult->zgl.ptr.p_double[i]; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + rhs->rdcfgu.ptr.p_double[i] = -(current->sxf.ptr.p_double[i]+current->gu.ptr.p_double[i]-state->flexcu.ptr.p_double[i])-currentmu*currentmult->zcfgu.ptr.p_double[i]; + rhs->rdgu.ptr.p_double[i] = currentmu-current->gu.ptr.p_double[i]*currentmult->zgu.ptr.p_double[i]; + } + rowidx = rowidx+1; + } + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(state->mflex, &rhs->rdcf, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(state->mflex, &rhs->rdcfgl, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(state->mflex, &rhs->rdcfgu, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(state->mflex, &rhs->rdgl, _state), _state); + *ecmplinf = ae_maxreal(*ecmplinf, rmaxabsv(state->mflex, &rhs->rdgu, _state), _state); + } + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 661231", _state); + ae_assert(rowidx==1+mtotal, "GIPM2: 355229", _state); + + /* + * Done + */ + ae_nxpool_recycle(&state->mnx1pool, &tmp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Compute ECmpl2 + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_computeecmpl2(const gipm2state* state, + const gipm2rhs* rhs, + ae_state *_state) +{ + ae_int_t np; + double result; + + + np = state->np; + result = (double)(0); + if( state->isprimal ) + { + return result; + } + result = result+rdotv2(np, &rhs->rdxl, _state); + result = result+rdotv2(np, &rhs->rdxu, _state); + if( state->hassoftbc ) + { + result = result+rdotv2(np, &rhs->rdsxl, _state); + result = result+rdotv2(np, &rhs->rdsxu, _state); + result = result+rdotv2(np, &rhs->rdsxlcap, _state); + result = result+rdotv2(np, &rhs->rdsxucap, _state); + } + if( state->mflex>0 ) + { + result = result+rdotv2(state->mflex, &rhs->rdcf, _state); + result = result+rdotv2(state->mflex, &rhs->rdcfgl, _state); + result = result+rdotv2(state->mflex, &rhs->rdcfgu, _state); + result = result+rdotv2(state->mflex, &rhs->rdgl, _state); + result = result+rdotv2(state->mflex, &rhs->rdgu, _state); + } + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 409119", _state); + return result; +} + + +/************************************************************************* +Compute RHS for a Newton system, additionally saving dual multiplier +estimates into RHS. + +Returns inf-norms of raw (unnormalized) primal, dual, complementarity errors. +Also returns normalizing coefficients for errors. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_copyrhs(const gipm2state* state, + const gipm2rhs* src, + gipm2rhs* dst, + ae_state *_state) +{ + ae_int_t mtotal; + + + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + rcopyallocv(state->np, &src->rp, &dst->rp, _state); + rcopyallocv(state->np, &src->rdxl, &dst->rdxl, _state); + rcopyallocv(state->np, &src->rdxu, &dst->rdxu, _state); + if( state->hassoftbc ) + { + rcopyallocv(state->np, &src->rpsxl, &dst->rpsxl, _state); + rcopyallocv(state->np, &src->rpsxu, &dst->rpsxu, _state); + rcopyallocv(state->np, &src->rdsxl, &dst->rdsxl, _state); + rcopyallocv(state->np, &src->rdsxu, &dst->rdsxu, _state); + rcopyallocv(state->np, &src->rdsxlcap, &dst->rdsxlcap, _state); + rcopyallocv(state->np, &src->rdsxucap, &dst->rdsxucap, _state); + } + if( state->mflex>0 ) + { + rcopyallocv(state->mflex, &src->rpsxf, &dst->rpsxf, _state); + rcopyallocv(state->mflex, &src->rpgl, &dst->rpgl, _state); + rcopyallocv(state->mflex, &src->rpgu, &dst->rpgu, _state); + rcopyallocv(state->mflex, &src->rdcf, &dst->rdcf, _state); + rcopyallocv(state->mflex, &src->rdcfgl, &dst->rdcfgl, _state); + rcopyallocv(state->mflex, &src->rdcfgu, &dst->rdcfgu, _state); + rcopyallocv(state->mflex, &src->rdgl, &dst->rdgl, _state); + rcopyallocv(state->mflex, &src->rdgu, &dst->rdgu, _state); + } + ae_assert(mtotal-state->mflex==0, "GIPM2: 372016 failed", _state); +} + + +/************************************************************************* +Compute product of DeltaX and gradient, (deltaX,gradBarr), computed +subject to all primal and primal slack variables present. + +Barrier function decrease corresponds to a negative value. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_computedg(const gipm2state* state, + const gipm2vars* delta, + const gipm2rhs* rhs, + ae_state *_state) +{ + ae_int_t mtotal; + double result; + + + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + result = (double)(0); + result = result-rdotv(state->np, &delta->xp, &rhs->rp, _state); + if( state->hassoftbc ) + { + result = result-rdotv(state->np, &delta->sxl, &rhs->rpsxl, _state); + result = result-rdotv(state->np, &delta->sxu, &rhs->rpsxu, _state); + } + if( state->mflex>0 ) + { + result = result-rdotv(state->mflex, &delta->sxf, &rhs->rpsxf, _state); + result = result-rdotv(state->mflex, &delta->gl, &rhs->rpgl, _state); + result = result-rdotv(state->mflex, &delta->gu, &rhs->rpgu, _state); + } + ae_assert(mtotal-state->mflex==0, "GIPM2: 262010 failed", _state); + return result; +} + + +/************************************************************************* +Compute residual from the candidate solution for the already compute RHS: + + RHS := RHS - [SYSTEM]*delta + +Inputs include current location, candidate solution Delta and precomputed +products H*Delta.XP, J*Delta.XP, J'*Delta.Y + +Returns inf-norm of the residual. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_computeupdateresidual(gipm2state* state, + const gipm2vars* current, + const gipm2mult* multlhs, + double currentmu, + double currentdiag, + const gipm2vars* delta, + const gipm2mult* deltamult, + /* Real */ const ae_vector* hdxp, + /* Real */ const ae_vector* jdxp, + /* Real */ const ae_vector* jtdy, + gipm2rhs* rhs, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + double lambdatau; + ae_int_t cidx; + double result; + + + np = state->np; + lambdatau = currentdiag+currentmu*gipm2_damptau; + result = (double)(0); + + /* + * Update RP := RP - (Hmod+L+TAU)*d_xp - (J'*d_yp + Jv'*d_yv) + d_zxl - d_zxu + * + */ + raddv(np, -1.0, hdxp, &rhs->rp, _state); + raddv(np, -lambdatau, &delta->xp, &rhs->rp, _state); + if( state->hashardbc||state->hassoftbc ) + { + raddv(np, 1.0, &deltamult->zxl, &rhs->rp, _state); + raddv(np, -1.0, &deltamult->zxu, &rhs->rp, _state); + } + raddv(np, 1.0, jtdy, &rhs->rp, _state); + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 266037", _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rp, _state), _state); + + /* + * Update + * + * RPSXL := RPSXL - L*dsxl + ql*dzxl + dzsxl + * RPSXU := RPSXU - L*dsxu + qu*dzxu + dzsxu + */ + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 089003", _state); + raddv(np, -currentdiag, &delta->sxl, &rhs->rpsxl, _state); + rmuladdv(np, &state->softbcql, &deltamult->zxl, &rhs->rpsxl, _state); + raddv(np, 1.0, &deltamult->zsxl, &rhs->rpsxl, _state); + raddv(np, -1.0, &deltamult->zsxlcap, &rhs->rpsxl, _state); + raddv(np, -currentdiag, &delta->sxu, &rhs->rpsxu, _state); + rmuladdv(np, &state->softbcqu, &deltamult->zxu, &rhs->rpsxu, _state); + raddv(np, 1.0, &deltamult->zsxu, &rhs->rpsxu, _state); + raddv(np, -1.0, &deltamult->zsxucap, &rhs->rpsxu, _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rpsxl, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rpsxu, _state), _state); + } + + /* + * Compute rdxl, rdxu, rpsxl, rpsxu, rdsxl, rdsxu + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 075050", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + rhs->rdxl.ptr.p_double[i] = rhs->rdxl.ptr.p_double[i]-multlhs->zxl.ptr.p_double[i]*delta->xp.ptr.p_double[i]-(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i])*deltamult->zxl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + rhs->rdxu.ptr.p_double[i] = rhs->rdxu.ptr.p_double[i]+multlhs->zxu.ptr.p_double[i]*delta->xp.ptr.p_double[i]-(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i])*deltamult->zxu.ptr.p_double[i]; + } + } + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdxl, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdxu, _state), _state); + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 116010", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + rhs->rdxl.ptr.p_double[i] = rhs->rdxl.ptr.p_double[i]-multlhs->zxl.ptr.p_double[i]*(delta->xp.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*delta->sxl.ptr.p_double[i])-(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i])*deltamult->zxl.ptr.p_double[i]; + rhs->rdsxl.ptr.p_double[i] = rhs->rdsxl.ptr.p_double[i]-multlhs->zsxl.ptr.p_double[i]*delta->sxl.ptr.p_double[i]-current->sxl.ptr.p_double[i]*deltamult->zsxl.ptr.p_double[i]; + rhs->rdsxlcap.ptr.p_double[i] = rhs->rdsxlcap.ptr.p_double[i]+multlhs->zsxlcap.ptr.p_double[i]*delta->sxl.ptr.p_double[i]-(state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i])*deltamult->zsxlcap.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + rhs->rdxu.ptr.p_double[i] = rhs->rdxu.ptr.p_double[i]-multlhs->zxu.ptr.p_double[i]*(-delta->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*delta->sxu.ptr.p_double[i])-(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i])*deltamult->zxu.ptr.p_double[i]; + rhs->rdsxu.ptr.p_double[i] = rhs->rdsxu.ptr.p_double[i]-multlhs->zsxu.ptr.p_double[i]*delta->sxu.ptr.p_double[i]-current->sxu.ptr.p_double[i]*deltamult->zsxu.ptr.p_double[i]; + rhs->rdsxucap.ptr.p_double[i] = rhs->rdsxucap.ptr.p_double[i]+multlhs->zsxucap.ptr.p_double[i]*delta->sxu.ptr.p_double[i]-(state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i])*deltamult->zsxucap.ptr.p_double[i]; + } + } + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdxl, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdxu, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdsxl, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdsxu, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdsxlcap, _state), _state); + result = ae_maxreal(result, rmaxabsv(np, &rhs->rdsxucap, _state), _state); + } + + /* + * FLEX-type constraints: update Rpsxf, Rpgl, Rpgu, Rdcf, Rdcfgl, Rdcfgu, Rdgl, Rdgu + */ + cidx = 0; + if( state->mflex>0 ) + { + raddv(state->mflex, -currentdiag, &delta->sxf, &rhs->rpsxf, _state); + raddv(state->mflex, -1.0, &deltamult->zcf, &rhs->rpsxf, _state); + raddv(state->mflex, 1.0, &deltamult->zcfgl, &rhs->rpsxf, _state); + raddv(state->mflex, 1.0, &deltamult->zcfgu, &rhs->rpsxf, _state); + raddv(state->mflex, -currentdiag, &delta->gl, &rhs->rpgl, _state); + raddv(state->mflex, -1.0, &deltamult->zcfgl, &rhs->rpgl, _state); + raddv(state->mflex, 1.0, &deltamult->zgl, &rhs->rpgl, _state); + raddv(state->mflex, -currentdiag, &delta->gu, &rhs->rpgu, _state); + raddv(state->mflex, 1.0, &deltamult->zcfgu, &rhs->rpgu, _state); + raddv(state->mflex, 1.0, &deltamult->zgu, &rhs->rpgu, _state); + for(i=0; i<=state->mflex-1; i++) + { + rhs->rdcf.ptr.p_double[i] = rhs->rdcf.ptr.p_double[i]-jdxp->ptr.p_double[cidx]+delta->sxf.ptr.p_double[i]-currentmu*deltamult->zcf.ptr.p_double[i]; + rhs->rdgl.ptr.p_double[i] = rhs->rdgl.ptr.p_double[i]-multlhs->zgl.ptr.p_double[i]*delta->gl.ptr.p_double[i]-current->gl.ptr.p_double[i]*deltamult->zgl.ptr.p_double[i]; + rhs->rdgu.ptr.p_double[i] = rhs->rdgu.ptr.p_double[i]-multlhs->zgu.ptr.p_double[i]*delta->gu.ptr.p_double[i]-current->gu.ptr.p_double[i]*deltamult->zgu.ptr.p_double[i]; + rhs->rdcfgl.ptr.p_double[i] = rhs->rdcfgl.ptr.p_double[i]-state->maskflexcl.ptr.p_double[i]*delta->sxf.ptr.p_double[i]+delta->gl.ptr.p_double[i]-currentmu*deltamult->zcfgl.ptr.p_double[i]; + rhs->rdcfgu.ptr.p_double[i] = rhs->rdcfgu.ptr.p_double[i]-state->maskflexcu.ptr.p_double[i]*delta->sxf.ptr.p_double[i]-delta->gu.ptr.p_double[i]-currentmu*deltamult->zcfgu.ptr.p_double[i]; + cidx = cidx+1; + } + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rpsxf, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rpgl, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rpgu, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rdcf, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rdcfgl, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rdcfgu, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rdgl, _state), _state); + result = ae_maxreal(result, rmaxabsv(state->mflex, &rhs->rdgu, _state), _state); + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 661231", _state); + return result; +} + + +/************************************************************************* +Transforms nonsymmetric primal Newton system into a symmetric condensed form + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_condenselhs(const gipm2state* state, + const gipm2vars* current, + const gipm2mult* currentmult, + double currentmu, + double currentdiag, + gipm2condensedsystem* c, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + double vxl; + double vxu; + double sxlcap; + double sxucap; + double tmpsx0; + double tmpsx1; + double tmpsx2; + double tmpsx3; + double tmpsx4; + double tmpsx5; + double tmpsx8; + double tmpsx9; + double tmpcf11; + double tmpcfl; + double tmpcf0; + double tmpcf4; + double tmpcfu; + double tmpcf1; + double tmpcf5; + ae_int_t fidx; + ae_int_t d1idx; + + + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + np = state->np; + fidx = 1; + d1idx = 0; + + /* + * Initial D0 and D1 + */ + rsetallocv(np, currentdiag+currentmu*gipm2_damptau, &c->d0, _state); + rsetallocv(mtotal, 0.0, &c->d1, _state); + + /* + * Condense box constraints + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 080041", _state); + for(i=0; i<=np-1; i++) + { + vxl = current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]; + vxu = state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]; + c->d0.ptr.p_double[i] = c->d0.ptr.p_double[i]+currentmult->zxl.ptr.p_double[i]/vxl+currentmult->zxu.ptr.p_double[i]/vxu; + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 080041", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + vxl = current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i]; + sxlcap = state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i]; + tmpsx0 = (double)1/current->sxl.ptr.p_double[i]; + tmpsx2 = (double)1/sxlcap; + tmpsx4 = (double)1/(currentdiag+currentmult->zsxl.ptr.p_double[i]*tmpsx0+currentmult->zsxlcap.ptr.p_double[i]*tmpsx2); + tmpsx8 = (double)1/(currentmult->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*tmpsx4+vxl); + c->d0.ptr.p_double[i] = c->d0.ptr.p_double[i]+currentmult->zxl.ptr.p_double[i]*tmpsx8; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + vxu = state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i]; + sxucap = state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i]; + tmpsx1 = (double)1/current->sxu.ptr.p_double[i]; + tmpsx3 = (double)1/sxucap; + tmpsx5 = (double)1/(currentdiag+currentmult->zsxu.ptr.p_double[i]*tmpsx1+currentmult->zsxucap.ptr.p_double[i]*tmpsx3); + tmpsx9 = (double)1/(currentmult->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*tmpsx5+vxu); + c->d0.ptr.p_double[i] = c->d0.ptr.p_double[i]+currentmult->zxu.ptr.p_double[i]*tmpsx9; + } + } + } + + /* + * Condense FLEX constraints + */ + ae_assert(fidx==1&&d1idx==0, "GIPM2: 388206", _state); + for(i=0; i<=state->mflex-1; i++) + { + tmpcf11 = currentdiag; + if( state->hasflexcl.ptr.p_bool[i] ) + { + tmpcfl = (double)1/current->gl.ptr.p_double[i]; + tmpcf0 = currentdiag+currentmult->zgl.ptr.p_double[i]*tmpcfl; + tmpcf4 = (double)1/((double)1+currentmu*tmpcf0); + tmpcf11 = tmpcf11+tmpcf0*tmpcf4; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + tmpcfu = (double)1/current->gu.ptr.p_double[i]; + tmpcf1 = currentdiag+currentmult->zgu.ptr.p_double[i]*tmpcfu; + tmpcf5 = (double)1/((double)1+currentmu*tmpcf1); + tmpcf11 = tmpcf11+tmpcf1*tmpcf5; + } + tmpcf11 = (double)1/tmpcf11; + c->d1.ptr.p_double[d1idx] = -(currentmu+tmpcf11); + fidx = fidx+1; + d1idx = d1idx+1; + } + + /* + * Other constraints + */ + ae_assert(mtotal-state->mflex==0, "GIPM2: 969325", _state); +} + + +/************************************************************************* +Condense only right-hand-side using already condensed left hand side. + + -- ALGLIB -- + Copyright 07.05.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_condenserhs(const gipm2state* state, + const gipm2vars* currentvars, + const gipm2mult* currentmult, + const gipm2rhs* rhs, + double currentmu, + double currentdiag, + gipm2condensedsystem* c, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + double vxl; + double vxu; + double sxlcap; + double sxucap; + double tmpsx0; + double tmpsx1; + double tmpsx2; + double tmpsx3; + double tmpsx4; + double tmpsx5; + double tmpsx6; + double tmpsx7; + double tmpsx8; + double tmpsx9; + double tmpsx10; + double tmpsx11; + double tmpcfl; + double tmpcfu; + double tmpcf0; + double tmpcf1; + double tmpcf2; + double tmpcf3; + double tmpcf4; + double tmpcf5; + double tmpcf6; + double tmpcf7; + double tmpcf8; + double tmpcf9; + double tmpcf10; + double tmpcf11; + ae_int_t fidx; + ae_int_t wyidx; + + + np = state->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + fidx = 1; + wyidx = 0; + + /* + * Initialize + */ + rcopyallocv(np, &rhs->rp, &c->wx, _state); + rsetallocv(mtotal, 0.0, &c->wy, _state); + + /* + * Box constraints + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 040045", _state); + for(i=0; i<=np-1; i++) + { + vxl = currentvars->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]; + vxu = state->finitebndu.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]; + c->wx.ptr.p_double[i] = c->wx.ptr.p_double[i]+rhs->rdxl.ptr.p_double[i]/vxl-rhs->rdxu.ptr.p_double[i]/vxu; + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 193353", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + vxl = currentvars->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*currentvars->sxl.ptr.p_double[i]; + sxlcap = state->softbcmsxl.ptr.p_double[i]-currentvars->sxl.ptr.p_double[i]; + tmpsx0 = (double)1/currentvars->sxl.ptr.p_double[i]; + tmpsx2 = (double)1/sxlcap; + tmpsx4 = (double)1/(currentdiag+currentmult->zsxl.ptr.p_double[i]*tmpsx0+currentmult->zsxlcap.ptr.p_double[i]*tmpsx2); + tmpsx6 = rhs->rpsxl.ptr.p_double[i]+rhs->rdsxl.ptr.p_double[i]*tmpsx0-rhs->rdsxlcap.ptr.p_double[i]*tmpsx2; + tmpsx8 = (double)1/(currentmult->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*tmpsx4*state->softbcql.ptr.p_double[i]+vxl); + tmpsx10 = rhs->rdxl.ptr.p_double[i]-currentmult->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*tmpsx4*tmpsx6; + c->wx.ptr.p_double[i] = c->wx.ptr.p_double[i]+tmpsx8*tmpsx10; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + vxu = state->finitebndu.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*currentvars->sxu.ptr.p_double[i]; + sxucap = state->softbcmsxu.ptr.p_double[i]-currentvars->sxu.ptr.p_double[i]; + tmpsx1 = (double)1/currentvars->sxu.ptr.p_double[i]; + tmpsx3 = (double)1/sxucap; + tmpsx5 = (double)1/(currentdiag+currentmult->zsxu.ptr.p_double[i]*tmpsx1+currentmult->zsxucap.ptr.p_double[i]*tmpsx3); + tmpsx7 = rhs->rpsxu.ptr.p_double[i]+rhs->rdsxu.ptr.p_double[i]*tmpsx1-rhs->rdsxucap.ptr.p_double[i]*tmpsx3; + tmpsx9 = (double)1/(currentmult->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*tmpsx5*state->softbcqu.ptr.p_double[i]+vxu); + tmpsx11 = rhs->rdxu.ptr.p_double[i]-currentmult->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*tmpsx5*tmpsx7; + c->wx.ptr.p_double[i] = c->wx.ptr.p_double[i]-tmpsx9*tmpsx11; + } + } + } + + /* + * Condense FLEX-type constraints + */ + if( state->mflex>0 ) + { + ae_assert(fidx==1&&wyidx==0, "GIPM2: 509247", _state); + for(i=0; i<=state->mflex-1; i++) + { + tmpcf10 = rhs->rpsxf.ptr.p_double[i]; + tmpcf11 = currentdiag; + if( state->hasflexcl.ptr.p_bool[i] ) + { + tmpcfl = (double)1/currentvars->gl.ptr.p_double[i]; + tmpcf0 = currentdiag+currentmult->zgl.ptr.p_double[i]*tmpcfl; + tmpcf2 = rhs->rpgl.ptr.p_double[i]+rhs->rdgl.ptr.p_double[i]*tmpcfl; + tmpcf4 = (double)1/((double)1+currentmu*tmpcf0); + tmpcf6 = rhs->rdcfgl.ptr.p_double[i]-currentmu*tmpcf2; + tmpcf8 = tmpcf6*tmpcf4; + tmpcf10 = tmpcf10+tmpcf2+tmpcf0*tmpcf8; + tmpcf11 = tmpcf11+tmpcf0*tmpcf4; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + tmpcfu = (double)1/currentvars->gu.ptr.p_double[i]; + tmpcf1 = currentdiag+currentmult->zgu.ptr.p_double[i]*tmpcfu; + tmpcf3 = rhs->rpgu.ptr.p_double[i]+rhs->rdgu.ptr.p_double[i]*tmpcfu; + tmpcf5 = (double)1/((double)1+currentmu*tmpcf1); + tmpcf7 = rhs->rdcfgu.ptr.p_double[i]+currentmu*tmpcf3; + tmpcf9 = tmpcf7*tmpcf5; + tmpcf10 = tmpcf10-tmpcf3+tmpcf1*tmpcf9; + tmpcf11 = tmpcf11+tmpcf1*tmpcf5; + } + tmpcf11 = (double)1/tmpcf11; + c->wy.ptr.p_double[wyidx] = rhs->rdcf.ptr.p_double[i]+tmpcf11*tmpcf10; + wyidx = wyidx+1; + fidx = fidx+1; + } + } + + /* + * Other constraints + */ + ae_assert(mtotal-state->mflex==0, "GIPM2: 226005", _state); +} + + +/************************************************************************* +Unpack reply to Request=1002 into a solution to the original primal-dual system. +Returns maximum over step components; + +Delta must be properly allocated GIPMVars; however, initial values of +its variables are ignored. + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_unpacksolution(const gipm2state* state, + const gipm2vars* currentvars, + const gipm2mult* multlhs, + double currentmu, + double currentdiag, + const gipm2rhs* rhs, + gipm2condensedsystem* c, + /* Real */ const ae_vector* replysol, + gipm2vars* delta, + gipm2mult* deltamult, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + double vxl; + double vxu; + double sxlcap; + double sxucap; + double tmpsx0; + double tmpsx1; + double tmpsx2; + double tmpsx3; + double tmpsx4; + double tmpsx5; + double tmpsx6; + double tmpsx7; + double tmpsx8; + double tmpsx9; + double tmpsx10; + double tmpsx11; + double tmpcfl; + double tmpcfu; + double tmpcf0; + double tmpcf1; + double tmpcf2; + double tmpcf3; + double tmpcf4; + double tmpcf5; + double tmpcf6; + double tmpcf7; + double tmpcf8; + double tmpcf9; + double tmpcf10; + double tmpcf11; + ae_int_t sidx; + + + np = state->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + sidx = np; + + /* + * Init XP + */ + rcopyvx(np, &state->replysol, 0, &delta->xp, 0, _state); + + /* + * Handle box constraints + */ + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 283018", _state); + for(i=0; i<=np-1; i++) + { + deltamult->zxl.ptr.p_double[i] = 0.0; + deltamult->zxu.ptr.p_double[i] = 0.0; + if( state->hasbndl.ptr.p_bool[i] ) + { + deltamult->zxl.ptr.p_double[i] = (rhs->rdxl.ptr.p_double[i]-multlhs->zxl.ptr.p_double[i]*delta->xp.ptr.p_double[i])/(currentvars->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + deltamult->zxu.ptr.p_double[i] = (rhs->rdxu.ptr.p_double[i]+multlhs->zxu.ptr.p_double[i]*delta->xp.ptr.p_double[i])/(state->finitebndu.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]); + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 297019", _state); + for(i=0; i<=np-1; i++) + { + delta->sxl.ptr.p_double[i] = (double)(0); + delta->sxu.ptr.p_double[i] = (double)(0); + deltamult->zxl.ptr.p_double[i] = (double)(0); + deltamult->zsxl.ptr.p_double[i] = (double)(0); + deltamult->zsxlcap.ptr.p_double[i] = (double)(0); + deltamult->zxu.ptr.p_double[i] = (double)(0); + deltamult->zsxu.ptr.p_double[i] = (double)(0); + deltamult->zsxucap.ptr.p_double[i] = (double)(0); + if( state->hasbndl.ptr.p_bool[i] ) + { + vxl = currentvars->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*currentvars->sxl.ptr.p_double[i]; + sxlcap = state->softbcmsxl.ptr.p_double[i]-currentvars->sxl.ptr.p_double[i]; + tmpsx0 = (double)1/currentvars->sxl.ptr.p_double[i]; + tmpsx2 = (double)1/sxlcap; + tmpsx4 = (double)1/(currentdiag+multlhs->zsxl.ptr.p_double[i]*tmpsx0+multlhs->zsxlcap.ptr.p_double[i]*tmpsx2); + tmpsx6 = rhs->rpsxl.ptr.p_double[i]+rhs->rdsxl.ptr.p_double[i]*tmpsx0-rhs->rdsxlcap.ptr.p_double[i]*tmpsx2; + tmpsx8 = (double)1/(multlhs->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*tmpsx4*state->softbcql.ptr.p_double[i]+vxl); + tmpsx10 = rhs->rdxl.ptr.p_double[i]-multlhs->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]*tmpsx4*tmpsx6; + deltamult->zxl.ptr.p_double[i] = tmpsx8*(tmpsx10-multlhs->zxl.ptr.p_double[i]*delta->xp.ptr.p_double[i]); + delta->sxl.ptr.p_double[i] = tmpsx4*(tmpsx6+state->softbcql.ptr.p_double[i]*deltamult->zxl.ptr.p_double[i]); + deltamult->zsxl.ptr.p_double[i] = tmpsx0*(rhs->rdsxl.ptr.p_double[i]-multlhs->zsxl.ptr.p_double[i]*delta->sxl.ptr.p_double[i]); + deltamult->zsxlcap.ptr.p_double[i] = tmpsx2*(rhs->rdsxlcap.ptr.p_double[i]+multlhs->zsxlcap.ptr.p_double[i]*delta->sxl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + vxu = state->finitebndu.ptr.p_double[i]-currentvars->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*currentvars->sxu.ptr.p_double[i]; + sxucap = state->softbcmsxu.ptr.p_double[i]-currentvars->sxu.ptr.p_double[i]; + tmpsx1 = (double)1/currentvars->sxu.ptr.p_double[i]; + tmpsx3 = (double)1/sxucap; + tmpsx5 = (double)1/(currentdiag+multlhs->zsxu.ptr.p_double[i]*tmpsx1+multlhs->zsxucap.ptr.p_double[i]*tmpsx3); + tmpsx7 = rhs->rpsxu.ptr.p_double[i]+rhs->rdsxu.ptr.p_double[i]*tmpsx1-rhs->rdsxucap.ptr.p_double[i]*tmpsx3; + tmpsx9 = (double)1/(multlhs->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*tmpsx5*state->softbcqu.ptr.p_double[i]+vxu); + tmpsx11 = rhs->rdxu.ptr.p_double[i]-multlhs->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]*tmpsx5*tmpsx7; + deltamult->zxu.ptr.p_double[i] = tmpsx9*(tmpsx11+multlhs->zxu.ptr.p_double[i]*delta->xp.ptr.p_double[i]); + delta->sxu.ptr.p_double[i] = tmpsx5*(tmpsx7+state->softbcqu.ptr.p_double[i]*deltamult->zxu.ptr.p_double[i]); + deltamult->zsxu.ptr.p_double[i] = tmpsx1*(rhs->rdsxu.ptr.p_double[i]-multlhs->zsxu.ptr.p_double[i]*delta->sxu.ptr.p_double[i]); + deltamult->zsxucap.ptr.p_double[i] = tmpsx3*(rhs->rdsxucap.ptr.p_double[i]+multlhs->zsxucap.ptr.p_double[i]*delta->sxu.ptr.p_double[i]); + } + } + } + + /* + * Handle FLEX-type constraints + */ + if( state->mflex>0 ) + { + ae_assert(sidx==np, "GIPM2: 657310", _state); + for(i=0; i<=state->mflex-1; i++) + { + deltamult->zcf.ptr.p_double[i] = (double)(0); + delta->sxf.ptr.p_double[i] = (double)(0); + delta->gl.ptr.p_double[i] = (double)(0); + deltamult->zgl.ptr.p_double[i] = (double)(0); + deltamult->zcfgl.ptr.p_double[i] = (double)(0); + delta->gu.ptr.p_double[i] = (double)(0); + deltamult->zgu.ptr.p_double[i] = (double)(0); + deltamult->zcfgu.ptr.p_double[i] = (double)(0); + tmpcf10 = rhs->rpsxf.ptr.p_double[i]; + tmpcf11 = currentdiag; + if( state->hasflexcl.ptr.p_bool[i] ) + { + tmpcfl = (double)1/currentvars->gl.ptr.p_double[i]; + tmpcf0 = currentdiag+multlhs->zgl.ptr.p_double[i]*tmpcfl; + tmpcf2 = rhs->rpgl.ptr.p_double[i]+rhs->rdgl.ptr.p_double[i]*tmpcfl; + tmpcf4 = (double)1/((double)1+currentmu*tmpcf0); + tmpcf6 = rhs->rdcfgl.ptr.p_double[i]-currentmu*tmpcf2; + tmpcf8 = tmpcf6*tmpcf4; + tmpcf10 = tmpcf10+tmpcf2+tmpcf0*tmpcf8; + tmpcf11 = tmpcf11+tmpcf0*tmpcf4; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + tmpcfu = (double)1/currentvars->gu.ptr.p_double[i]; + tmpcf1 = currentdiag+multlhs->zgu.ptr.p_double[i]*tmpcfu; + tmpcf3 = rhs->rpgu.ptr.p_double[i]+rhs->rdgu.ptr.p_double[i]*tmpcfu; + tmpcf5 = (double)1/((double)1+currentmu*tmpcf1); + tmpcf7 = rhs->rdcfgu.ptr.p_double[i]+currentmu*tmpcf3; + tmpcf9 = tmpcf7*tmpcf5; + tmpcf10 = tmpcf10-tmpcf3+tmpcf1*tmpcf9; + tmpcf11 = tmpcf11+tmpcf1*tmpcf5; + } + tmpcf11 = (double)1/tmpcf11; + deltamult->zcf.ptr.p_double[i] = -replysol->ptr.p_double[sidx]; + delta->sxf.ptr.p_double[i] = tmpcf11*tmpcf10-tmpcf11*deltamult->zcf.ptr.p_double[i]; + if( state->hasflexcl.ptr.p_bool[i] ) + { + delta->gl.ptr.p_double[i] = -tmpcf8+tmpcf4*delta->sxf.ptr.p_double[i]; + deltamult->zgl.ptr.p_double[i] = (rhs->rdgl.ptr.p_double[i]-multlhs->zgl.ptr.p_double[i]*delta->gl.ptr.p_double[i])*tmpcfl; + deltamult->zcfgl.ptr.p_double[i] = tmpcf2-tmpcf0*delta->gl.ptr.p_double[i]; + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + delta->gu.ptr.p_double[i] = tmpcf9-tmpcf5*delta->sxf.ptr.p_double[i]; + deltamult->zgu.ptr.p_double[i] = (rhs->rdgu.ptr.p_double[i]-multlhs->zgu.ptr.p_double[i]*delta->gu.ptr.p_double[i])*tmpcfu; + deltamult->zcfgu.ptr.p_double[i] = -tmpcf3+tmpcf1*delta->gu.ptr.p_double[i]; + } + sidx = sidx+1; + } + } + + /* + * Handle other constraints + */ + ae_assert(mtotal-state->mflex==0, "GIPM2: 102051", _state); +} + + +/************************************************************************* +Merit function V0 + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_meritfunction(const gipm2state* state, + const gipm2vars* current, + double currentmu, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + ae_int_t fidx; + double barrierf; + double penaltyf; + double result; + + + np = state->np; + barrierf = (double)(0); + penaltyf = (double)(0); + fidx = 1; + + /* + * Compute fmod(xp,mu) and barrier terms with respect to primal variables XP and slacks SXL/SXU + */ + result = current->fi.ptr.p_double[0]+0.5*currentmu*gipm2_damptau*rdotv2(np, ¤t->xp, _state); + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 264349", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + barrierf = barrierf-ae_log(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i], _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + barrierf = barrierf-ae_log(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i], _state); + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 429016", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + barrierf = barrierf-ae_log(current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i], _state); + barrierf = barrierf-ae_log(current->sxl.ptr.p_double[i], _state)-ae_log(state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i], _state); + result = result+state->pxl.ptr.p_double[i]*current->sxl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + barrierf = barrierf-ae_log(state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i], _state); + barrierf = barrierf-ae_log(current->sxu.ptr.p_double[i], _state)-ae_log(state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i], _state); + result = result+state->pxu.ptr.p_double[i]*current->sxu.ptr.p_double[i]; + } + } + } + + /* + * FLEX-type constraints + */ + ae_assert(fidx==1, "GIPM2: 828102 failed", _state); + for(i=0; i<=state->mflex-1; i++) + { + penaltyf = penaltyf+ae_sqr(current->fi.ptr.p_double[fidx]-current->sxf.ptr.p_double[i], _state); + if( state->hasflexcl.ptr.p_bool[i] ) + { + penaltyf = penaltyf+ae_sqr(current->sxf.ptr.p_double[i]-current->gl.ptr.p_double[i]-state->flexcl.ptr.p_double[i], _state); + barrierf = barrierf-ae_log(current->gl.ptr.p_double[i], _state); + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + penaltyf = penaltyf+ae_sqr(current->sxf.ptr.p_double[i]+current->gu.ptr.p_double[i]-state->flexcu.ptr.p_double[i], _state); + barrierf = barrierf-ae_log(current->gu.ptr.p_double[i], _state); + } + fidx = fidx+1; + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 263349", _state); + + /* + * Done + */ + result = result+barrierf*currentmu+penaltyf/((double)2*currentmu); + return result; +} + + +/************************************************************************* +Merit function V0 + + -- ALGLIB -- + Copyright 11.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_meritfunctionpd(const gipm2state* state, + const gipm2vars* current, + const gipm2mult* currentmult, + double currentmu, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + ae_int_t fidx; + double barrierf; + double penaltyf; + double v; + double vv; + double invmu; + double result; + + + ae_assert(!state->isprimal, "GIPM2: 151843 failed", _state); + np = state->np; + barrierf = (double)(0); + penaltyf = (double)(0); + fidx = 1; + invmu = (double)1/currentmu; + + /* + * Compute fmod(xp,mu) and barrier terms with respect to primal variables XP and slacks SXL/SXU + */ + result = current->fi.ptr.p_double[0]+0.5*currentmu*gipm2_damptau*rdotv2(np, ¤t->xp, _state); + if( state->hashardbc ) + { + ae_assert(!state->hassoftbc, "GIPM2: 264349", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + v = current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]; + vv = v*currentmult->zxl.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + v = state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]; + vv = v*currentmult->zxu.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + } + } + } + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 429016", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + v = current->xp.ptr.p_double[i]-state->finitebndl.ptr.p_double[i]+state->softbcql.ptr.p_double[i]*current->sxl.ptr.p_double[i]; + vv = v*currentmult->zxl.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + v = current->sxl.ptr.p_double[i]; + vv = v*currentmult->zsxl.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + v = state->softbcmsxl.ptr.p_double[i]-current->sxl.ptr.p_double[i]; + vv = v*currentmult->zsxlcap.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + result = result+state->pxl.ptr.p_double[i]*current->sxl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + v = state->finitebndu.ptr.p_double[i]-current->xp.ptr.p_double[i]+state->softbcqu.ptr.p_double[i]*current->sxu.ptr.p_double[i]; + vv = v*currentmult->zxu.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + v = current->sxu.ptr.p_double[i]; + vv = v*currentmult->zsxu.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + v = state->softbcmsxu.ptr.p_double[i]-current->sxu.ptr.p_double[i]; + vv = v*currentmult->zsxucap.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + result = result+state->pxu.ptr.p_double[i]*current->sxu.ptr.p_double[i]; + } + } + } + + /* + * FLEX-type constraints + */ + ae_assert(fidx==1, "GIPM2: 828102 failed", _state); + for(i=0; i<=state->mflex-1; i++) + { + v = current->fi.ptr.p_double[fidx]-current->sxf.ptr.p_double[i]; + vv = v+currentmu*currentmult->zcf.ptr.p_double[i]; + penaltyf = penaltyf+v*v+gipm2_dualmeritnu*vv*vv; + if( state->hasflexcl.ptr.p_bool[i] ) + { + v = current->sxf.ptr.p_double[i]-current->gl.ptr.p_double[i]-state->flexcl.ptr.p_double[i]; + vv = v+currentmu*currentmult->zcfgl.ptr.p_double[i]; + penaltyf = penaltyf+v*v+gipm2_dualmeritnu*vv*vv; + v = current->gl.ptr.p_double[i]; + vv = v*currentmult->zgl.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + v = current->sxf.ptr.p_double[i]+current->gu.ptr.p_double[i]-state->flexcu.ptr.p_double[i]; + vv = v+currentmu*currentmult->zcfgu.ptr.p_double[i]; + penaltyf = penaltyf+v*v+gipm2_dualmeritnu*vv*vv; + v = current->gu.ptr.p_double[i]; + vv = v*currentmult->zgu.ptr.p_double[i]*invmu; + barrierf = barrierf-ae_log(v, _state)-gipm2_dualmeritnu*(ae_log(vv, _state)+(double)1-vv); + } + fidx = fidx+1; + } + + /* + * Other constraints + */ + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 263349", _state); + + /* + * Done + */ + result = result+barrierf*currentmu+penaltyf/((double)2*currentmu); + return result; +} + + +/************************************************************************* +Compute safeguard BndLP/UP from FiniteBndLX/UX. + + -- ALGLIB -- + Copyright 11.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_safeboundsfromfinitetightened(gipm2state* state, + ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + double vmid; + double v; + + + if( !state->hashardbc ) + { + return; + } + np = state->np; + rallocv(np, &state->safeguardbndlp, _state); + rallocv(np, &state->safeguardbndup, _state); + v = (double)10*ae_machineepsilon; + for(i=0; i<=np-1; i++) + { + + /* + * Safeguard bounds on primal variables and check interval width + */ + vmid = 0.5*(state->finitebndl.ptr.p_double[i]+state->finitebndu.ptr.p_double[i]); + state->safeguardbndlp.ptr.p_double[i] = ae_minreal(state->finitebndl.ptr.p_double[i]+ae_maxreal(ae_fabs(state->finitebndl.ptr.p_double[i], _state), 1.0, _state)*v, vmid, _state); + state->safeguardbndup.ptr.p_double[i] = ae_maxreal(state->finitebndu.ptr.p_double[i]-ae_maxreal(ae_fabs(state->finitebndu.ptr.p_double[i], _state), 1.0, _state)*v, vmid, _state); + ae_assert(ae_fp_greater_eq(state->safeguardbndup.ptr.p_double[i],state->safeguardbndlp.ptr.p_double[i]), "GIPM2: hard bounds on primal variables are too tight, bad problem preprocessing", _state); + } +} + + +/************************************************************************* +Decrease or increase relaxation penalties + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_tunepenalties(gipm2state* state, + const gipm2mult* currentmult, + ae_state *_state) +{ + ae_int_t np; + ae_int_t mtotal; + ae_int_t i; + ae_int_t increased; + ae_int_t decreased; + double v; + double rlxsafetymed; + + + np = state->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + increased = 0; + decreased = 0; + rlxsafetymed = ae_sqrt(gipm2_rlxsafetylo*gipm2_rlxsafetyhi, _state); + + /* + * Handle box constraints + */ + if( state->hassoftbc ) + { + ae_assert(!state->hashardbc, "GIPM2: 197214", _state); + ae_assert(currentmult->hassoftbc, "GIPM2: 197215", _state); + for(i=0; i<=np-1; i++) + { + if( state->hasbndl.ptr.p_bool[i] ) + { + v = currentmult->zxl.ptr.p_double[i]*state->softbcql.ptr.p_double[i]; + if( ae_fp_greater(v,gipm2_rlxsafetyhi*state->pxl.ptr.p_double[i]) ) + { + state->pxl.ptr.p_double[i] = state->pxl.ptr.p_double[i]*(double)10; + increased = increased+1; + continue; + } + if( ae_fp_less(ae_maxreal(v, (double)(1), _state),gipm2_rlxsafetylo*state->pxl.ptr.p_double[i]) ) + { + state->pxl.ptr.p_double[i] = v/rlxsafetymed; + decreased = decreased+1; + continue; + } + } + if( state->hasbndu.ptr.p_bool[i] ) + { + v = currentmult->zxu.ptr.p_double[i]*state->softbcqu.ptr.p_double[i]; + if( ae_fp_greater(v,gipm2_rlxsafetyhi*state->pxu.ptr.p_double[i]) ) + { + state->pxu.ptr.p_double[i] = state->pxu.ptr.p_double[i]*(double)10; + increased = increased+1; + continue; + } + if( ae_fp_less(ae_maxreal(v, (double)(1), _state),gipm2_rlxsafetylo*state->pxu.ptr.p_double[i]) ) + { + state->pxu.ptr.p_double[i] = v/rlxsafetymed; + decreased = decreased+1; + continue; + } + } + } + } + + /* + * Handle non-box constraints + */ + ae_assert(mtotal-state->mflex==0, "199213", _state); + + /* + * Trace + */ + if( state->dotrace&&increased+decreased>0 ) + { + ae_trace("> updating penalties, %0d increased, %0d decreased\n", + (int)(increased), + (int)(decreased)); + } +} + + +/************************************************************************* +Logic for tightenting/relaxation of a lower bound. Returns new bound value +(can be the same as original one) + +PARAMETERS: + VX variable or constraint value; can be below lower + bound if allowed by soft constraints + VXNrm inf-norm of the variable/constraint vector + WrkBndL working version of lower bound, potentially tighter than + TrueBndL, but not lower + TrueBndL true (fixed) lower bound + NTightened, + NRelaxed counters, updated on change + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_tgtrlxbndl(double vx, + double vxnrm, + double wrkbndl, + double truebndl, + ae_int_t* ntightened, + ae_int_t* nrelaxed, + ae_state *_state) +{ + double vtgt; + double vrlx; + double vmid; + double result; + + + vtgt = ae_maxreal(vx-vxnrm*gipm2_tightendist, truebndl, _state); + vrlx = ae_maxreal(vx-vxnrm*gipm2_relaxdist, truebndl, _state); + vmid = ae_maxreal(vx-vxnrm*gipm2_middist, truebndl, _state); + result = wrkbndl; + if( ae_fp_less(result,vtgt) ) + { + result = vmid; + *ntightened = *ntightened+1; + } + if( ae_fp_greater(result,vrlx) ) + { + result = vmid; + *nrelaxed = *nrelaxed+1; + } + return result; +} + + +/************************************************************************* +Logic for tightenting/relaxation of an upper bound. Returns new bound value +(can be the same as original one) + +PARAMETERS: + VX variable or constraint value; can be above upper + bound if allowed by soft constraints + VXNrm inf-norm of the varible/constraint vector + WrkBndU working version of the bound, potentially tighter than + TrueBndU, but not above + TrueBndU true (fixed) upper bound + NTightened, + NRelaxed counters, updated on change + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_tgtrlxbndu(double vx, + double vxnrm, + double wrkbndu, + double truebndu, + ae_int_t* ntightened, + ae_int_t* nrelaxed, + ae_state *_state) +{ + double vtgt; + double vrlx; + double vmid; + double result; + + + vtgt = ae_minreal(vx+vxnrm*gipm2_tightendist, truebndu, _state); + vrlx = ae_minreal(vx+vxnrm*gipm2_relaxdist, truebndu, _state); + vmid = ae_minreal(vx+vxnrm*gipm2_middist, truebndu, _state); + result = wrkbndu; + if( ae_fp_greater(result,vtgt) ) + { + result = vmid; + *ntightened = *ntightened+1; + } + if( ae_fp_less(result,vrlx) ) + { + result = vmid; + *nrelaxed = *nrelaxed+1; + } + return result; +} + + +/************************************************************************* +Tightens/relaxes bounds, recomputes safeguarded BndLP/UP if necessary. + + -- ALGLIB -- + Copyright 25.05.2024 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_tightenrelaxbounds(gipm2state* state, ae_state *_state) +{ + ae_int_t np; + ae_int_t i; + ae_int_t ntightened; + ae_int_t nrelaxed; + double xpnrm; + double vx; + double vnrm; + + + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 510240", _state); + ae_assert(ae_fp_less(gipm2_relaxdist,gipm2_tightendist), "GIPM: integrity check 1821 failed", _state); + np = state->np; + xpnrm = ae_maxreal(rmaxabsv(np, &state->current.xp, _state), (double)(1), _state); + ntightened = 0; + nrelaxed = 0; + for(i=0; i<=np-1; i++) + { + + /* + * Variable value and distance scaling factor + */ + vx = state->current.xp.ptr.p_double[i]; + vnrm = xpnrm; + if( state->hasbndl.ptr.p_bool[i] ) + { + state->finitebndl.ptr.p_double[i] = gipm2_tgtrlxbndl(vx, vnrm, state->finitebndl.ptr.p_double[i], state->hardbndl.ptr.p_double[i], &ntightened, &nrelaxed, _state); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->finitebndu.ptr.p_double[i] = gipm2_tgtrlxbndu(vx, vnrm, state->finitebndu.ptr.p_double[i], state->hardbndu.ptr.p_double[i], &ntightened, &nrelaxed, _state); + } + } + gipm2_safeboundsfromfinitetightened(state, _state); + if( state->dotrace&&nrelaxed+ntightened>0 ) + { + ae_trace("> %0d bounds tightened, %0d bounds relaxed\n", + (int)(ntightened), + (int)(nrelaxed)); + } +} + + +/************************************************************************* +Update box/nonbox error estimates +*************************************************************************/ +static void gipm2_updateerrorestimates(gipm2state* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t fidx; + double vx; + double v; + + + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repsclerr = (double)(0); + if( state->hashardbc||state->hassoftbc ) + { + for(i=0; i<=state->np-1; i++) + { + vx = state->current.xp.ptr.p_double[i]; + v = state->finitebndl.ptr.p_double[i]-vx; + if( ae_fp_greater(v,state->repbcerr) ) + { + state->repbcerr = v; + state->repbcidx = i; + } + v = vx-state->finitebndu.ptr.p_double[i]; + if( ae_fp_greater(v,state->repbcerr) ) + { + state->repbcerr = v; + state->repbcidx = i; + } + } + } + + /* + * Other constraints + */ + fidx = 1; + for(i=0; i<=state->mflex-1; i++) + { + if( state->hasflexcl.ptr.p_bool[i] ) + { + v = ae_maxreal(state->flexcl.ptr.p_double[i]-state->current.fi.ptr.p_double[fidx], 0.0, _state); + if( ae_fp_greater(v,state->repnlcerr) ) + { + state->repnlcerr = v; + state->repnlcidx = fidx-1; + } + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + v = ae_maxreal(state->current.fi.ptr.p_double[fidx]-state->flexcu.ptr.p_double[i], 0.0, _state); + if( ae_fp_greater(v,state->repnlcerr) ) + { + state->repnlcerr = v; + state->repnlcidx = fidx-1; + } + } + fidx = fidx+1; + } + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 885251", _state); + + /* + * Done + */ + state->repsclerr = rmax3(state->repsclerr, state->repbcerr, state->repnlcerr, _state); +} + + +/************************************************************************* +Send X +*************************************************************************/ +static void gipm2_sendx(gipm2state* state, + /* Real */ const ae_vector* xs, + ae_state *_state) +{ + + + ae_assert(state->meq+state->mrlxeq+state->m1+state->mrlx1==0, "GIPM2: 866202", _state); + rcopyv(state->np, xs, &state->querydata, _state); + if( state->hashardbc ) + { + rmergemaxv(state->np, &state->safeguardbndlp, &state->querydata, _state); + rmergeminv(state->np, &state->safeguardbndup, &state->querydata, _state); + } +} + + +/************************************************************************* +Send Lagrangian with terms corresponding to box constraints omitted +*************************************************************************/ +static void gipm2_sendlagrangianinfo(gipm2state* state, + gipm2vars* current, + gipm2mult* curmult, + gipm2vars* cand, + gipm2mult* candmult, + ae_bool usebestmult, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t np; + ae_int_t mtotal; + ae_int_t rowoffs; + ae_int_t qdoffs; + ae_int_t lagnlcoffs; + ae_vector tmp; + ae_vector tmp2; + + ae_frame_make(_state, &_frame_block); + memset(&tmp, 0, sizeof(tmp)); + memset(&tmp2, 0, sizeof(tmp2)); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true); + + np = state->np; + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + rallocv(4*np+mtotal, &state->querydata, _state); + + /* + * Retrieve temporary array and fill with multipliers + */ + ae_nxpool_retrieve(&state->mnx1pool, &tmp, _state); + ae_nxpool_retrieve(&state->mnx1pool, &tmp2, _state); + ae_assert(tmp.cnt>=mtotal+1&&tmp2.cnt>=mtotal+1, "GIPM2: 167028 failed", _state); + tmp.ptr.p_double[0] = (double)(1); + tmp2.ptr.p_double[0] = (double)(1); + lagnlcoffs = 0; + rowoffs = 1; + qdoffs = np; + for(i=0; i<=state->mflex-1; i++) + { + if( usebestmult ) + { + tmp.ptr.p_double[rowoffs] = -state->bestlagnlc.ptr.p_double[lagnlcoffs]; + tmp2.ptr.p_double[rowoffs] = -state->bestlagnlc.ptr.p_double[lagnlcoffs]; + } + else + { + tmp.ptr.p_double[rowoffs] = -curmult->zcf.ptr.p_double[i]; + tmp2.ptr.p_double[rowoffs] = -candmult->zcf.ptr.p_double[i]; + } + rowoffs = rowoffs+1; + qdoffs = qdoffs+1; + lagnlcoffs = lagnlcoffs+1; + } + ae_assert(mtotal-state->mflex==0, "GIPM2: integrity check 734626 failed", _state); + + /* + * Generate QueryData + */ + rcopyvx(np, ¤t->xp, 0, &state->querydata, 0, _state); + rcopyvx(np, &cand->xp, 0, &state->querydata, np, _state); + sparsegemv(¤t->jac, 1.0, 1, &tmp, 0, 0.0, &state->querydata, 2*np, _state); + sparsegemv(&cand->jac, 1.0, 1, &tmp2, 0, 0.0, &state->querydata, 3*np, _state); + rcopyvx(mtotal, &tmp2, 1, &state->querydata, 4*np, _state); + + /* + * Recycle + */ + ae_nxpool_recycle(&state->mnx1pool, &tmp2, _state); + ae_nxpool_recycle(&state->mnx1pool, &tmp, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Fills preallocated LagBC and LagNLC with values computed from multipliers +*************************************************************************/ +static void gipm2_lagcoeffsfrommultipliers(const gipm2mult* mult, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagnlc, + ae_state *_state) +{ + ae_int_t mtotal; + ae_int_t offs; + + + mtotal = mult->mflex+mult->meq+mult->mrlxeq+mult->m1+mult->mrlx1; + ae_assert(lagbc->cnt>=mult->np&&lagnlc->cnt>=mtotal, "GIPM2: 990225 failed", _state); + + /* + * Box constraints + */ + if( mult->hashardbc||mult->hassoftbc ) + { + rcopyv(mult->np, &mult->zxu, lagbc, _state); + raddv(mult->np, -1.0, &mult->zxl, lagbc, _state); + } + else + { + rsetv(mult->np, 0.0, lagbc, _state); + } + + /* + * Nonlinear constraints + */ + offs = 0; + if( mult->mflex>0 ) + { + rcopyvx(mult->mflex, &mult->zcf, 0, lagnlc, offs, _state); + offs = offs+mult->mflex; + } + ae_assert(offs==mtotal, "GIPM2: 015228 failed", _state); +} + + +/************************************************************************* +Retrieves F-vector and scaled Jacobian, copies them to VFJ, +applying reordering permutation if needed. + +Returns True on success, False on failure (when F or J are not finite numbers). +*************************************************************************/ +static ae_bool gipm2_retrievefij(const gipm2state* state, + gipm2vars* vfj, + ae_state *_state) +{ + ae_int_t mtotal; + ae_bool result; + + + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + + /* + * Retrieve function vector and Jacobian + */ + rcopyv(1+mtotal, &state->replyfi, &vfj->fi, _state); + sparsecopybuf(&state->replysj, &vfj->jac, _state); + + /* + * Check finiteness + */ + result = ae_isfinite(rdotv2(1+mtotal, &vfj->fi, _state), _state)&&ae_isfinite(rdotv2(vfj->jac.ridx.ptr.p_int[1+mtotal], &vfj->jac.vals, _state), _state); + return result; +} + + +/************************************************************************* +Initialize memory for nonmonotonic merit function optimization + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_nonmonotonicinit(gipm2state* state, + ae_int_t memlen, + double merit0, + ae_state *_state) +{ + + + ae_assert(memlen>=0, "GIPM2: integrity check 157435 failed", _state); + state->nonmonotonicmemlen = memlen; + state->nonmonotonicpos = 0; + rsetallocv(memlen+1, merit0, &state->nonmonotonicmerit, _state); + state->nonmonotonicmerit.ptr.p_double[memlen] = merit0; +} + + +/************************************************************************* +Push new value to the nonmonotonic memory + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_nonmonotonicpush(gipm2state* state, + double meritv, + ae_state *_state) +{ + + + state->nonmonotonicmerit.ptr.p_double[state->nonmonotonicpos] = meritv; + state->nonmonotonicpos = (state->nonmonotonicpos+1)%(state->nonmonotonicmemlen+1); +} + + +/************************************************************************* +Returns nonmonotonic correction that should be added to MeritV + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_nonmonotonicgetcorr(gipm2state* state, + double meritv, + ae_state *_state) +{ + ae_int_t i; + double mx; + double result; + + + mx = meritv; + for(i=0; i<=state->nonmonotonicmemlen; i++) + { + mx = ae_maxreal(mx, state->nonmonotonicmerit.ptr.p_double[i], _state); + } + result = ae_maxreal(mx-meritv, 0.0, _state); + return result; +} + + +/************************************************************************* +Apply function rescaling to the current point + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void gipm2_rescalecurrentbest(gipm2state* state, + /* Real */ const ae_vector* rescaleby, + ae_bool rescalebest, + ae_state *_state) +{ + ae_int_t mtotal; + ae_int_t rescaleoffs; + ae_int_t i; + double v; + + + mtotal = state->mflex+state->meq+state->mrlxeq+state->m1+state->mrlx1; + + /* + * Rescale primal variables and function vector/Jacobian + */ + rmergemulv(1+mtotal, rescaleby, &state->current.fi, _state); + sparsemultiplyrowsby(&state->current.jac, rescaleby, _state); + if( rescalebest ) + { + rmergemulv(1+mtotal, rescaleby, &state->best.fi, _state); + sparsemultiplyrowsby(&state->best.jac, rescaleby, _state); + } + + /* + * Rescale best Lagrange multipliers + */ + if( rescalebest ) + { + rmulv(state->np, rescaleby->ptr.p_double[0], &state->bestlagbc, _state); + rmulv(mtotal, rescaleby->ptr.p_double[0], &state->bestlagnlc, _state); + for(i=0; i<=mtotal-1; i++) + { + state->bestlagnlc.ptr.p_double[i] = state->bestlagnlc.ptr.p_double[i]/rescaleby->ptr.p_double[1+i]; + } + } + + /* + * Rescale FLEX-type constraints + */ + rescaleoffs = 1; + for(i=0; i<=state->mflex-1; i++) + { + v = rescaleby->ptr.p_double[rescaleoffs]; + state->flexcl.ptr.p_double[i] = state->flexcl.ptr.p_double[i]*v; + state->flexcu.ptr.p_double[i] = state->flexcu.ptr.p_double[i]*v; + state->current.sxf.ptr.p_double[i] = state->current.sxf.ptr.p_double[i]*v; + if( rescalebest ) + { + state->best.sxf.ptr.p_double[i] = state->best.sxf.ptr.p_double[i]*v; + } + if( state->hasflexcl.ptr.p_bool[i] ) + { + state->current.gl.ptr.p_double[i] = state->current.gl.ptr.p_double[i]*v; + if( rescalebest ) + { + state->best.gl.ptr.p_double[i] = state->best.gl.ptr.p_double[i]*v; + } + } + if( state->hasflexcu.ptr.p_bool[i] ) + { + state->current.gu.ptr.p_double[i] = state->current.gu.ptr.p_double[i]*v; + if( rescalebest ) + { + state->best.gu.ptr.p_double[i] = state->best.gu.ptr.p_double[i]*v; + } + } + rescaleoffs = rescaleoffs+1; + } + ae_assert(rescaleoffs==mtotal+1, "GIPM: 780055", _state); +} + + +/************************************************************************* +Compute aggregate of primal, dual and complementarity errors (now it is max). + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static double gipm2_aggregateerr(double p, + double d, + double c, + ae_state *_state) +{ + double result; + + + result = rmax3(p, d, c, _state); + return result; +} + + +void _gipm2vars_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipm2vars *p = (gipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->sxf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->jac, _state, make_automatic); +} + + +void _gipm2vars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipm2vars *dst = (gipm2vars*)_dst; + const gipm2vars *src = (const gipm2vars*)_src; + dst->hashardbc = src->hashardbc; + dst->hassoftbc = src->hassoftbc; + dst->np = src->np; + dst->mflex = src->mflex; + dst->meq = src->meq; + dst->mrlxeq = src->mrlxeq; + dst->m1 = src->m1; + dst->mrlx1 = src->mrlx1; + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + ae_vector_init_copy(&dst->sxl, &src->sxl, _state, make_automatic); + ae_vector_init_copy(&dst->sxu, &src->sxu, _state, make_automatic); + ae_vector_init_copy(&dst->sxf, &src->sxf, _state, make_automatic); + ae_vector_init_copy(&dst->gl, &src->gl, _state, make_automatic); + ae_vector_init_copy(&dst->gu, &src->gu, _state, make_automatic); + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + _sparsematrix_init_copy(&dst->jac, &src->jac, _state, make_automatic); +} + + +void _gipm2vars_clear(void* _p) +{ + gipm2vars *p = (gipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->sxl); + ae_vector_clear(&p->sxu); + ae_vector_clear(&p->sxf); + ae_vector_clear(&p->gl); + ae_vector_clear(&p->gu); + ae_vector_clear(&p->fi); + _sparsematrix_clear(&p->jac); +} + + +void _gipm2vars_destroy(void* _p) +{ + gipm2vars *p = (gipm2vars*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->sxl); + ae_vector_destroy(&p->sxu); + ae_vector_destroy(&p->sxf); + ae_vector_destroy(&p->gl); + ae_vector_destroy(&p->gu); + ae_vector_destroy(&p->fi); + _sparsematrix_destroy(&p->jac); +} + + +void _gipm2mult_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipm2mult *p = (gipm2mult*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->zxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zsxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zsxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zsxlcap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zsxucap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zcf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zgu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zcfgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->zcfgu, 0, DT_REAL, _state, make_automatic); +} + + +void _gipm2mult_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipm2mult *dst = (gipm2mult*)_dst; + const gipm2mult *src = (const gipm2mult*)_src; + dst->hashardbc = src->hashardbc; + dst->hassoftbc = src->hassoftbc; + dst->np = src->np; + dst->mflex = src->mflex; + dst->meq = src->meq; + dst->mrlxeq = src->mrlxeq; + dst->m1 = src->m1; + dst->mrlx1 = src->mrlx1; + ae_vector_init_copy(&dst->zxl, &src->zxl, _state, make_automatic); + ae_vector_init_copy(&dst->zxu, &src->zxu, _state, make_automatic); + ae_vector_init_copy(&dst->zsxl, &src->zsxl, _state, make_automatic); + ae_vector_init_copy(&dst->zsxu, &src->zsxu, _state, make_automatic); + ae_vector_init_copy(&dst->zsxlcap, &src->zsxlcap, _state, make_automatic); + ae_vector_init_copy(&dst->zsxucap, &src->zsxucap, _state, make_automatic); + ae_vector_init_copy(&dst->zcf, &src->zcf, _state, make_automatic); + ae_vector_init_copy(&dst->zgl, &src->zgl, _state, make_automatic); + ae_vector_init_copy(&dst->zgu, &src->zgu, _state, make_automatic); + ae_vector_init_copy(&dst->zcfgl, &src->zcfgl, _state, make_automatic); + ae_vector_init_copy(&dst->zcfgu, &src->zcfgu, _state, make_automatic); +} + + +void _gipm2mult_clear(void* _p) +{ + gipm2mult *p = (gipm2mult*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->zxl); + ae_vector_clear(&p->zxu); + ae_vector_clear(&p->zsxl); + ae_vector_clear(&p->zsxu); + ae_vector_clear(&p->zsxlcap); + ae_vector_clear(&p->zsxucap); + ae_vector_clear(&p->zcf); + ae_vector_clear(&p->zgl); + ae_vector_clear(&p->zgu); + ae_vector_clear(&p->zcfgl); + ae_vector_clear(&p->zcfgu); +} + + +void _gipm2mult_destroy(void* _p) +{ + gipm2mult *p = (gipm2mult*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->zxl); + ae_vector_destroy(&p->zxu); + ae_vector_destroy(&p->zsxl); + ae_vector_destroy(&p->zsxu); + ae_vector_destroy(&p->zsxlcap); + ae_vector_destroy(&p->zsxucap); + ae_vector_destroy(&p->zcf); + ae_vector_destroy(&p->zgl); + ae_vector_destroy(&p->zgu); + ae_vector_destroy(&p->zcfgl); + ae_vector_destroy(&p->zcfgu); +} + + +void _gipm2rhs_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipm2rhs *p = (gipm2rhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rpsxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rpsxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdsxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdsxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdsxlcap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdsxucap, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rpsxf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rpgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rpgu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdcf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdcfgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdcfgu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdgl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rdgu, 0, DT_REAL, _state, make_automatic); +} + + +void _gipm2rhs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipm2rhs *dst = (gipm2rhs*)_dst; + const gipm2rhs *src = (const gipm2rhs*)_src; + ae_vector_init_copy(&dst->rp, &src->rp, _state, make_automatic); + ae_vector_init_copy(&dst->rpsxl, &src->rpsxl, _state, make_automatic); + ae_vector_init_copy(&dst->rpsxu, &src->rpsxu, _state, make_automatic); + ae_vector_init_copy(&dst->rdxl, &src->rdxl, _state, make_automatic); + ae_vector_init_copy(&dst->rdxu, &src->rdxu, _state, make_automatic); + ae_vector_init_copy(&dst->rdsxl, &src->rdsxl, _state, make_automatic); + ae_vector_init_copy(&dst->rdsxu, &src->rdsxu, _state, make_automatic); + ae_vector_init_copy(&dst->rdsxlcap, &src->rdsxlcap, _state, make_automatic); + ae_vector_init_copy(&dst->rdsxucap, &src->rdsxucap, _state, make_automatic); + ae_vector_init_copy(&dst->rpsxf, &src->rpsxf, _state, make_automatic); + ae_vector_init_copy(&dst->rpgl, &src->rpgl, _state, make_automatic); + ae_vector_init_copy(&dst->rpgu, &src->rpgu, _state, make_automatic); + ae_vector_init_copy(&dst->rdcf, &src->rdcf, _state, make_automatic); + ae_vector_init_copy(&dst->rdcfgl, &src->rdcfgl, _state, make_automatic); + ae_vector_init_copy(&dst->rdcfgu, &src->rdcfgu, _state, make_automatic); + ae_vector_init_copy(&dst->rdgl, &src->rdgl, _state, make_automatic); + ae_vector_init_copy(&dst->rdgu, &src->rdgu, _state, make_automatic); +} + + +void _gipm2rhs_clear(void* _p) +{ + gipm2rhs *p = (gipm2rhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rp); + ae_vector_clear(&p->rpsxl); + ae_vector_clear(&p->rpsxu); + ae_vector_clear(&p->rdxl); + ae_vector_clear(&p->rdxu); + ae_vector_clear(&p->rdsxl); + ae_vector_clear(&p->rdsxu); + ae_vector_clear(&p->rdsxlcap); + ae_vector_clear(&p->rdsxucap); + ae_vector_clear(&p->rpsxf); + ae_vector_clear(&p->rpgl); + ae_vector_clear(&p->rpgu); + ae_vector_clear(&p->rdcf); + ae_vector_clear(&p->rdcfgl); + ae_vector_clear(&p->rdcfgu); + ae_vector_clear(&p->rdgl); + ae_vector_clear(&p->rdgu); +} + + +void _gipm2rhs_destroy(void* _p) +{ + gipm2rhs *p = (gipm2rhs*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rp); + ae_vector_destroy(&p->rpsxl); + ae_vector_destroy(&p->rpsxu); + ae_vector_destroy(&p->rdxl); + ae_vector_destroy(&p->rdxu); + ae_vector_destroy(&p->rdsxl); + ae_vector_destroy(&p->rdsxu); + ae_vector_destroy(&p->rdsxlcap); + ae_vector_destroy(&p->rdsxucap); + ae_vector_destroy(&p->rpsxf); + ae_vector_destroy(&p->rpgl); + ae_vector_destroy(&p->rpgu); + ae_vector_destroy(&p->rdcf); + ae_vector_destroy(&p->rdcfgl); + ae_vector_destroy(&p->rdcfgu); + ae_vector_destroy(&p->rdgl); + ae_vector_destroy(&p->rdgu); +} + + +void _gipm2condensedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipm2condensedsystem *p = (gipm2condensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->wx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wy, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d1, 0, DT_REAL, _state, make_automatic); +} + + +void _gipm2condensedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipm2condensedsystem *dst = (gipm2condensedsystem*)_dst; + const gipm2condensedsystem *src = (const gipm2condensedsystem*)_src; + ae_vector_init_copy(&dst->wx, &src->wx, _state, make_automatic); + ae_vector_init_copy(&dst->wy, &src->wy, _state, make_automatic); + ae_vector_init_copy(&dst->d0, &src->d0, _state, make_automatic); + ae_vector_init_copy(&dst->d1, &src->d1, _state, make_automatic); +} + + +void _gipm2condensedsystem_clear(void* _p) +{ + gipm2condensedsystem *p = (gipm2condensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->wx); + ae_vector_clear(&p->wy); + ae_vector_clear(&p->d0); + ae_vector_clear(&p->d1); +} + + +void _gipm2condensedsystem_destroy(void* _p) +{ + gipm2condensedsystem *p = (gipm2condensedsystem*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->wx); + ae_vector_destroy(&p->wy); + ae_vector_destroy(&p->d0); + ae_vector_destroy(&p->d1); +} + + +void _gipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + gipm2state *p = (gipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hardbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hardbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->softbcql, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->softbcqu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->softbcmsxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->softbcmsxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->callerfscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitebndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->safeguardbndlp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->safeguardbndup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->elp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->eup, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->flexcl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->flexcu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->maskflexcl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->maskflexcu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasflexcl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasflexcu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->replysol, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyprod, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyv, 0, DT_REAL, _state, make_automatic); + _gipm2vars_init(&p->current, _state, make_automatic); + _gipm2mult_init(&p->currentmult, _state, make_automatic); + _gipm2mult_init(&p->delayedmult, _state, make_automatic); + _gipm2vars_init(&p->best, _state, make_automatic); + ae_vector_init(&p->bestlagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bestlagnlc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pxl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pxu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nonmonotonicmerit, 0, DT_REAL, _state, make_automatic); + _gipm2vars_init(&p->cand, _state, make_automatic); + _gipm2vars_init(&p->delta, _state, make_automatic); + _gipm2vars_init(&p->corr, _state, make_automatic); + _gipm2mult_init(&p->deltamult, _state, make_automatic); + _gipm2mult_init(&p->corrmult, _state, make_automatic); + _gipm2condensedsystem_init(&p->condensed, _state, make_automatic); + _gipm2rhs_init(&p->rhs, _state, make_automatic); + _gipm2rhs_init(&p->tmprhs, _state, make_automatic); + ae_vector_init(&p->tmphdxp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpjdxp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpjtdy, 0, DT_REAL, _state, make_automatic); + ae_nxpool_init(&p->mnx1pool, DT_REAL, _state, make_automatic); + _gipm2mult_init(&p->candmult, _state, make_automatic); + _gipm2rhs_init(&p->candrhs, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _gipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + gipm2state *dst = (gipm2state*)_dst; + const gipm2state *src = (const gipm2state*)_src; + dst->np = src->np; + dst->mflex = src->mflex; + dst->meq = src->meq; + dst->mrlxeq = src->mrlxeq; + dst->m1 = src->m1; + dst->mrlx1 = src->mrlx1; + dst->hashardbc = src->hashardbc; + dst->hassoftbc = src->hassoftbc; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->hardbndl, &src->hardbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hardbndu, &src->hardbndu, _state, make_automatic); + ae_vector_init_copy(&dst->softbcql, &src->softbcql, _state, make_automatic); + ae_vector_init_copy(&dst->softbcqu, &src->softbcqu, _state, make_automatic); + ae_vector_init_copy(&dst->softbcmsxl, &src->softbcmsxl, _state, make_automatic); + ae_vector_init_copy(&dst->softbcmsxu, &src->softbcmsxu, _state, make_automatic); + dst->mudependent = src->mudependent; + dst->isprimal = src->isprimal; + ae_vector_init_copy(&dst->callerfscales, &src->callerfscales, _state, make_automatic); + dst->multupdatedelay = src->multupdatedelay; + ae_vector_init_copy(&dst->finitebndl, &src->finitebndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitebndu, &src->finitebndu, _state, make_automatic); + ae_vector_init_copy(&dst->safeguardbndlp, &src->safeguardbndlp, _state, make_automatic); + ae_vector_init_copy(&dst->safeguardbndup, &src->safeguardbndup, _state, make_automatic); + ae_vector_init_copy(&dst->elp, &src->elp, _state, make_automatic); + ae_vector_init_copy(&dst->eup, &src->eup, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->flexcl, &src->flexcl, _state, make_automatic); + ae_vector_init_copy(&dst->flexcu, &src->flexcu, _state, make_automatic); + ae_vector_init_copy(&dst->maskflexcl, &src->maskflexcl, _state, make_automatic); + ae_vector_init_copy(&dst->maskflexcu, &src->maskflexcu, _state, make_automatic); + ae_vector_init_copy(&dst->hasflexcl, &src->hasflexcl, _state, make_automatic); + ae_vector_init_copy(&dst->hasflexcu, &src->hasflexcu, _state, make_automatic); + dst->muepsfactor = src->muepsfactor; + dst->mudecaylinear = src->mudecaylinear; + dst->mudecaypower = src->mudecaypower; + dst->eps = src->eps; + dst->maxits = src->maxits; + dst->maxcheckpointstagnationits = src->maxcheckpointstagnationits; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->replysol, &src->replysol, _state, make_automatic); + ae_vector_init_copy(&dst->replyprod, &src->replyprod, _state, make_automatic); + ae_vector_init_copy(&dst->replyv, &src->replyv, _state, make_automatic); + dst->replywasrescale = src->replywasrescale; + dst->hasjac = src->hasjac; + dst->factsuccess = src->factsuccess; + dst->dotrace = src->dotrace; + dst->dotracelaconic = src->dotracelaconic; + _gipm2vars_init_copy(&dst->current, &src->current, _state, make_automatic); + _gipm2mult_init_copy(&dst->currentmult, &src->currentmult, _state, make_automatic); + _gipm2mult_init_copy(&dst->delayedmult, &src->delayedmult, _state, make_automatic); + dst->hasbest = src->hasbest; + _gipm2vars_init_copy(&dst->best, &src->best, _state, make_automatic); + ae_vector_init_copy(&dst->bestlagbc, &src->bestlagbc, _state, make_automatic); + ae_vector_init_copy(&dst->bestlagnlc, &src->bestlagnlc, _state, make_automatic); + dst->besterr = src->besterr; + dst->fstagnationcnt = src->fstagnationcnt; + dst->rhsstagnationcounter = src->rhsstagnationcounter; + dst->goodinnerits = src->goodinnerits; + dst->currentmu = src->currentmu; + dst->prevmu = src->prevmu; + dst->mumin = src->mumin; + dst->curbigval = src->curbigval; + dst->curbiggrowth = src->curbiggrowth; + dst->lambdav = src->lambdav; + dst->lambdadecay = src->lambdadecay; + dst->lambdafound = src->lambdafound; + dst->subsequentfactfailures = src->subsequentfactfailures; + dst->firstouteriteration = src->firstouteriteration; + dst->infinitiesdetected = src->infinitiesdetected; + dst->linesearchalwayssuccessful = src->linesearchalwayssuccessful; + dst->failedtorecoverfrominfinities = src->failedtorecoverfrominfinities; + dst->unboundednesssuspected = src->unboundednesssuspected; + dst->rejectedwithineps = src->rejectedwithineps; + dst->lastprim = src->lastprim; + dst->lastdual = src->lastdual; + dst->lastcmpl = src->lastcmpl; + ae_vector_init_copy(&dst->pxl, &src->pxl, _state, make_automatic); + ae_vector_init_copy(&dst->pxu, &src->pxu, _state, make_automatic); + dst->inneriterationidx = src->inneriterationidx; + dst->hessiandecay = src->hessiandecay; + dst->nonmonotonicmemlen = src->nonmonotonicmemlen; + dst->nonmonotonicpos = src->nonmonotonicpos; + ae_vector_init_copy(&dst->nonmonotonicmerit, &src->nonmonotonicmerit, _state, make_automatic); + dst->nrmx0 = src->nrmx0; + dst->absf0 = src->absf0; + dst->dxpnrm = src->dxpnrm; + _gipm2vars_init_copy(&dst->cand, &src->cand, _state, make_automatic); + _gipm2vars_init_copy(&dst->delta, &src->delta, _state, make_automatic); + _gipm2vars_init_copy(&dst->corr, &src->corr, _state, make_automatic); + _gipm2mult_init_copy(&dst->deltamult, &src->deltamult, _state, make_automatic); + _gipm2mult_init_copy(&dst->corrmult, &src->corrmult, _state, make_automatic); + _gipm2condensedsystem_init_copy(&dst->condensed, &src->condensed, _state, make_automatic); + _gipm2rhs_init_copy(&dst->rhs, &src->rhs, _state, make_automatic); + _gipm2rhs_init_copy(&dst->tmprhs, &src->tmprhs, _state, make_automatic); + ae_vector_init_copy(&dst->tmphdxp, &src->tmphdxp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpjdxp, &src->tmpjdxp, _state, make_automatic); + ae_vector_init_copy(&dst->tmpjtdy, &src->tmpjtdy, _state, make_automatic); + ae_nxpool_init_copy(&dst->mnx1pool, &src->mnx1pool, _state, make_automatic); + _gipm2mult_init_copy(&dst->candmult, &src->candmult, _state, make_automatic); + _gipm2rhs_init_copy(&dst->candrhs, &src->candrhs, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->repsclerr = src->repsclerr; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _gipm2state_clear(void* _p) +{ + gipm2state *p = (gipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->hardbndl); + ae_vector_clear(&p->hardbndu); + ae_vector_clear(&p->softbcql); + ae_vector_clear(&p->softbcqu); + ae_vector_clear(&p->softbcmsxl); + ae_vector_clear(&p->softbcmsxu); + ae_vector_clear(&p->callerfscales); + ae_vector_clear(&p->finitebndl); + ae_vector_clear(&p->finitebndu); + ae_vector_clear(&p->safeguardbndlp); + ae_vector_clear(&p->safeguardbndup); + ae_vector_clear(&p->elp); + ae_vector_clear(&p->eup); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->flexcl); + ae_vector_clear(&p->flexcu); + ae_vector_clear(&p->maskflexcl); + ae_vector_clear(&p->maskflexcu); + ae_vector_clear(&p->hasflexcl); + ae_vector_clear(&p->hasflexcu); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->replysol); + ae_vector_clear(&p->replyprod); + ae_vector_clear(&p->replyv); + _gipm2vars_clear(&p->current); + _gipm2mult_clear(&p->currentmult); + _gipm2mult_clear(&p->delayedmult); + _gipm2vars_clear(&p->best); + ae_vector_clear(&p->bestlagbc); + ae_vector_clear(&p->bestlagnlc); + ae_vector_clear(&p->pxl); + ae_vector_clear(&p->pxu); + ae_vector_clear(&p->nonmonotonicmerit); + _gipm2vars_clear(&p->cand); + _gipm2vars_clear(&p->delta); + _gipm2vars_clear(&p->corr); + _gipm2mult_clear(&p->deltamult); + _gipm2mult_clear(&p->corrmult); + _gipm2condensedsystem_clear(&p->condensed); + _gipm2rhs_clear(&p->rhs); + _gipm2rhs_clear(&p->tmprhs); + ae_vector_clear(&p->tmphdxp); + ae_vector_clear(&p->tmpjdxp); + ae_vector_clear(&p->tmpjtdy); + ae_nxpool_clear(&p->mnx1pool); + _gipm2mult_clear(&p->candmult); + _gipm2rhs_clear(&p->candrhs); + _rcommstate_clear(&p->rstate); +} + + +void _gipm2state_destroy(void* _p) +{ + gipm2state *p = (gipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->hardbndl); + ae_vector_destroy(&p->hardbndu); + ae_vector_destroy(&p->softbcql); + ae_vector_destroy(&p->softbcqu); + ae_vector_destroy(&p->softbcmsxl); + ae_vector_destroy(&p->softbcmsxu); + ae_vector_destroy(&p->callerfscales); + ae_vector_destroy(&p->finitebndl); + ae_vector_destroy(&p->finitebndu); + ae_vector_destroy(&p->safeguardbndlp); + ae_vector_destroy(&p->safeguardbndup); + ae_vector_destroy(&p->elp); + ae_vector_destroy(&p->eup); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->flexcl); + ae_vector_destroy(&p->flexcu); + ae_vector_destroy(&p->maskflexcl); + ae_vector_destroy(&p->maskflexcu); + ae_vector_destroy(&p->hasflexcl); + ae_vector_destroy(&p->hasflexcu); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->replysol); + ae_vector_destroy(&p->replyprod); + ae_vector_destroy(&p->replyv); + _gipm2vars_destroy(&p->current); + _gipm2mult_destroy(&p->currentmult); + _gipm2mult_destroy(&p->delayedmult); + _gipm2vars_destroy(&p->best); + ae_vector_destroy(&p->bestlagbc); + ae_vector_destroy(&p->bestlagnlc); + ae_vector_destroy(&p->pxl); + ae_vector_destroy(&p->pxu); + ae_vector_destroy(&p->nonmonotonicmerit); + _gipm2vars_destroy(&p->cand); + _gipm2vars_destroy(&p->delta); + _gipm2vars_destroy(&p->corr); + _gipm2mult_destroy(&p->deltamult); + _gipm2mult_destroy(&p->corrmult); + _gipm2condensedsystem_destroy(&p->condensed); + _gipm2rhs_destroy(&p->rhs); + _gipm2rhs_destroy(&p->tmprhs); + ae_vector_destroy(&p->tmphdxp); + ae_vector_destroy(&p->tmpjdxp); + ae_vector_destroy(&p->tmpjtdy); + ae_nxpool_destroy(&p->mnx1pool); + _gipm2mult_destroy(&p->candmult); + _gipm2rhs_destroy(&p->candrhs); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initialize GQPIPM structure. + +X0 - initial point; must be: + * strictly feasible wrt non-equality box constraints + * non-strictly feasible wrt equality box constraints + * strictly feasible wrt conic constraints, if present + Failure to satisfy these properties will lead to an exception + generated either during initialization or during the very + first iteration. + + -- ALGLIB -- + Copyright 11.02.2025 by Bochkanov Sergey +*************************************************************************/ +void nlpgipm2initbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const nlpstoppingcriteria* criteria, + ae_bool isdense, + nlpgipm2state* state, + ae_state *_state) +{ + ae_int_t i; + double fixtol; + double v; + + + ae_assert(!isdense, "NLPGIPM2: 225301", _state); + fixtol = 0.01*ae_sqrt(ae_machineepsilon, _state); + state->isdense = isdense; + state->isconvex = ae_false; + state->n = n; + state->mlc = 0; + state->mnlc = 0; + state->mxx = 0; + state->hasbc = ae_false; + state->hasfixed = ae_false; + rcopyallocv(n, s, &state->s, _state); + rsetallocv(n, _state->v_neginf, &state->scaledbndl, _state); + rsetallocv(n, _state->v_posinf, &state->scaledbndu, _state); + rsetallocv(n, -ae_sqrt(ae_maxrealnumber, _state), &state->finitescaledbndl, _state); + rsetallocv(n, ae_sqrt(ae_maxrealnumber, _state), &state->finitescaledbndu, _state); + rsetallocv(n, -ae_sqrt(ae_maxrealnumber, _state), &state->finiterawbndl, _state); + rsetallocv(n, ae_sqrt(ae_maxrealnumber, _state), &state->finiterawbndu, _state); + bsetallocv(n, ae_false, &state->isfixed, _state); + rsetallocv(n, 1.0, &state->nonfixedmask, _state); + rallocv(n, &state->scaledx0, _state); + fixtol = ae_sqrt(ae_machineepsilon, _state); + for(i=0; i<=n-1; i++) + { + state->scaledx0.ptr.p_double[i] = x0->ptr.p_double[i]/s->ptr.p_double[i]; + if( (ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state))&&ae_fp_less(bndu->ptr.p_double[i]-bndl->ptr.p_double[i],fixtol*s->ptr.p_double[i]) ) + { + v = 0.5*(bndl->ptr.p_double[i]+bndu->ptr.p_double[i])/s->ptr.p_double[i]; + state->scaledbndl.ptr.p_double[i] = v; + state->scaledbndu.ptr.p_double[i] = v; + state->finitescaledbndl.ptr.p_double[i] = v; + state->finitescaledbndu.ptr.p_double[i] = v; + state->finiterawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->finiterawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbc = ae_true; + state->hasfixed = ae_true; + state->isfixed.ptr.p_bool[i] = ae_true; + state->nonfixedmask.ptr.p_double[i] = 0.0; + continue; + } + if( ae_isfinite(bndl->ptr.p_double[i], _state) ) + { + state->scaledbndl.ptr.p_double[i] = bndl->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitescaledbndl.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + state->finiterawbndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbc = ae_true; + } + if( ae_isfinite(bndu->ptr.p_double[i], _state) ) + { + state->scaledbndu.ptr.p_double[i] = bndu->ptr.p_double[i]/s->ptr.p_double[i]; + state->finitescaledbndu.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + state->finiterawbndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbc = ae_true; + } + } + state->maxits = critgetmaxits(criteria, _state); + state->eps = critgetepswithdefault(criteria, 1.0E-7, _state); + state->repterminationtype = 0; + state->repiterationscount = 0; + rcopyallocv(n, x0, &state->xs, _state); + state->dolaconictrace = ae_is_trace_enabled("GIPM2.LACONIC"); + state->dotrace = ae_is_trace_enabled("GIPM2")&&!state->dolaconictrace; + ae_vector_set_length(&state->rstate.ia, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set constraints + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + SparseA - sparse constraint matrix, CRS format + CL, CU - lower and upper bounds for constraints + -INF <= CL[I] <= CU[I] <= +INF. + M - constraints count + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +void nlpgipm2setlinearconstraints(nlpgipm2state* state, + const sparsematrix* sparsea, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t m, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = state->n; + ae_assert(m>=0, "NLPGIPM2SetLinearConstraints: M<0", _state); + ae_assert(m==0||((sparsea->matrixtype==1&&sparsea->m==m)&&sparsea->n==n), "NLPGIPM2SetLinearConstraints: constraint matrix has incorrect size", _state); + ae_assert(cl->cnt>=m, "NLPGIPM2SetLinearConstraints: CL is too short!", _state); + ae_assert(cu->cnt>=m, "NLPGIPM2SetLinearConstraints: CU is too short!", _state); + state->mlc = m; + if( m>0 ) + { + sparsecopytocrsbuf(sparsea, &state->sparselc, _state); + rallocv(m, &state->lcbndl, _state); + rallocv(m, &state->lcbndu, _state); + for(i=0; i<=m-1; i++) + { + ae_assert(ae_isfinite(cl->ptr.p_double[i], _state)||ae_isneginf(cl->ptr.p_double[i], _state), "NLPGIPM2SetLinearConstraints: CL is not finite number or -INF", _state); + ae_assert(ae_isfinite(cu->ptr.p_double[i], _state)||ae_isposinf(cu->ptr.p_double[i], _state), "NLPGIPM2SetLinearConstraints: CU is not finite number or +INF", _state); + state->lcbndl.ptr.p_double[i] = cl->ptr.p_double[i]; + state->lcbndu.ptr.p_double[i] = cu->ptr.p_double[i]; + } + icopyallocv(m, lcsrcidx, &state->lcsrcidx, _state); + rsetallocv(n, 0.0, &state->tmp0, _state); + scaleshiftsparselcinplace(&state->s, &state->tmp0, n, &state->sparselc, m, &state->lcbndl, &state->lcbndu, _state); + normalizesparselcinplace(&state->sparselc, m, &state->lcbndl, &state->lcbndu, n, ae_true, &state->lcscales, ae_true, _state); + } +} + + +/************************************************************************* +Set nonlinear constraints + +INPUT PARAMETERS: + State - instance initialized with one of the initialization + functions + NL, NU - lower and upper bounds for constraints + -INF <= NL[I] <= NU[I] <= +INF. + NNLC - constraints count + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +void nlpgipm2setnonlinearconstraints(nlpgipm2state* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nnlc>=0, "NLPGIPM2SetNonlinearConstraints: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "NLPGIPM2SetNonlinearConstraints: CL is too short!", _state); + ae_assert(nu->cnt>=nnlc, "NLPGIPM2SetNonlinearConstraints: CU is too short!", _state); + state->mnlc = nnlc; + if( nnlc>0 ) + { + rallocv(nnlc, &state->rawnl, _state); + rallocv(nnlc, &state->rawnu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "NLPGIPM2SetNonlinearConstraints: NL is not finite number or -INF", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "NLPGIPM2SetNonlinearConstraints: NU is not finite number or +INF", _state); + state->rawnl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->rawnu.ptr.p_double[i] = nu->ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function performs actual processing for GIPM2 algorithm. + + -- ALGLIB -- + Copyright 01.02.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool nlpgipm2iteration(nlpgipm2state* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state) +{ + ae_int_t i; + double v; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + v = state->rstate.ra.ptr.p_double[0]; + } + else + { + i = 359; + v = -58.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + state->needfisj = ae_false; + state->xupdated = ae_false; + rallocv(state->n, &state->x, _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 377132 failed", _state); + rallocv(1+state->mnlc+state->mlc, &state->replyfi, _state); + state->haslast = ae_false; + state->hasbase = ae_false; + state->hasprevbase = ae_false; + state->hasbest = ae_false; + state->hasbaseh = ae_false; + state->factorized = ae_false; + state->hassparsityanalyzed = ae_false; + stimerinit(&state->timertotal, _state); + stimerinit(&state->timerfactorize, _state); + stimerinit(&state->timersolve, _state); + stimerinit(&state->timercallback, _state); + stimerinit(&state->timerreport, _state); + stimerinit(&state->timeranalyze, _state); + stimerinit(&state->timermv, _state); + stimerinit(&state->timerrescale, _state); + stimerstart(&state->timertotal, _state); + nlcgipm2_autoscaleinit(state, _state); + gipm2initbuf(&state->scaledx0, state->n, state->eps, state->maxits, &state->solver, _state); + gipm2setprofilequasinewton(&state->solver, ae_false, _state); + if( state->hasbc ) + { + gipm2setsoftbc(&state->solver, &state->scaledbndl, &state->isfixed, &state->scaledbndu, &state->isfixed, _state); + } + ae_assert(state->mxx==0, "GIPM2: integrity check 342033 failed", _state); + if( state->mnlc+state->mlc>0 ) + { + rallocv(state->mnlc+state->mlc, &state->wrkccbndl, _state); + rallocv(state->mnlc+state->mlc, &state->wrkccbndu, _state); + rcopyvx(state->mnlc, &state->rawnl, 0, &state->wrkccbndl, 0, _state); + rcopyvx(state->mnlc, &state->rawnu, 0, &state->wrkccbndu, 0, _state); + rcopyvx(state->mlc, &state->lcbndl, 0, &state->wrkccbndl, state->mnlc, _state); + rcopyvx(state->mlc, &state->lcbndu, 0, &state->wrkccbndu, state->mnlc, _state); + gipm2setflexnlc(&state->solver, &state->wrkccbndl, &state->wrkccbndu, state->mnlc+state->mlc, _state); + } + ae_assert(!state->isdense, "NLCGIPM2: 455319", _state); + state->hessmemlen = ae_minint(state->n, nlcgipm2_xbfgsmemlen, _state); + hessianinitlowranksr1(&state->hess, state->n, state->hessmemlen, ae_maxreal(state->eps, ae_sqrt(ae_machineepsilon, _state), _state), nlcgipm2_xbfgsmaxhess, _state); + state->hess.mincrv = 0.0; + if( state->dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// NONLINEAR GIPM2 SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d\n", + (int)(state->n)); + ae_trace("MLC = %6d\n", + (int)(state->mlc)); + ae_trace("MNLC = %6d\n", + (int)(state->mnlc)); + } +lbl_4: + if( !gipm2iteration(&state->solver, smonitor, userterminationneeded, _state) ) + { + goto lbl_5; + } + if( state->solver.requesttype==-1 ) + { + goto lbl_4; + } + if( state->solver.requesttype!=1 ) + { + goto lbl_6; + } + ae_assert(state->mxx==0, "GIPM2: integrity check 395132 failed", _state); + rcopyv(state->n, &state->solver.querydata, &state->x, _state); + rmergemaxv(state->n, &state->finitescaledbndl, &state->x, _state); + rmergeminv(state->n, &state->finitescaledbndu, &state->x, _state); + rcopyallocv(state->n, &state->x, &state->xproj, _state); + state->needfisj = ae_true; + if( state->dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + if( state->dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfisj = ae_false; + if( state->mlc>0 ) + { + sparsegemv(&state->sparselc, 1.0, 0, &state->xproj, 0, 0.0, &state->replyfi, 1+state->mnlc+state->mxx, _state); + sparseappendmatrix(&state->replysj, &state->sparselc, _state); + } + v = state->replyfi.ptr.p_double[0]; + ae_assert(state->mxx==0, "GIPM2: integrity check 395133 failed", _state); + rmergemulv(1+state->mnlc+state->mxx+state->mlc, &state->invfscales, &state->replyfi, _state); + sparsemultiplyrowscolsby(&state->replysj, &state->invfscales, &state->nonfixedmask, _state); + rcopyv(1+state->mnlc+state->mxx+state->mlc, &state->replyfi, &state->solver.replyfi, _state); + sparsecopybuf(&state->replysj, &state->solver.replysj, _state); + nlcgipm2_savepointaslast(state, v, _state); + goto lbl_4; +lbl_6: + if( state->solver.requesttype==999 ) + { + hessianmultiplyby(&state->hess, state->solver.querydata.ptr.p_double[0], _state); + goto lbl_4; + } + if( state->solver.requesttype!=1000 ) + { + goto lbl_8; + } + ae_assert(state->mxx==0, "GIPM2: integrity check 480643 failed", _state); + nlcgipm2_lastpointasbase(state, &state->solver.querydata, _state); + ae_assert(state->mxx==0, "NLCGIPM2: integrity check 395132 failed", _state); + rcopyv(state->n, &state->basex, &state->x, _state); + rmergemaxv(state->n, &state->finitescaledbndl, &state->x, _state); + rmergeminv(state->n, &state->finitescaledbndu, &state->x, _state); + state->reportf = state->baserawf0; + state->xupdated = ae_true; + if( state->dotrace ) + { + stimerstart(&state->timerreport, _state); + } + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + if( state->dotrace ) + { + stimerstop(&state->timerreport, _state); + } + state->xupdated = ae_false; + goto lbl_4; + goto lbl_4; +lbl_8: + if( state->solver.requesttype==1001 ) + { + if( state->dotrace ) + { + stimerstart(&state->timeranalyze, _state); + } + nlcgipm2_generatesparsesys(state, &state->basesj, _state); + if( state->dotrace ) + { + stimerstop(&state->timeranalyze, _state); + } + if( state->dotrace ) + { + stimerstart(&state->timerfactorize, _state); + } + nlcgipm2_factorizematrix(state, _state); + if( state->dotrace ) + { + stimerstop(&state->timerfactorize, _state); + } + goto lbl_4; + } + if( state->solver.requesttype==1002 ) + { + if( state->dotrace ) + { + stimerstart(&state->timersolve, _state); + } + nlcgipm2_solvesystem(state, _state); + if( state->dotrace ) + { + stimerstop(&state->timersolve, _state); + } + goto lbl_4; + } + if( state->solver.requesttype==1003 ) + { + if( state->dotrace ) + { + stimerstart(&state->timermv, _state); + } + nlcgipm2_matrixvector(state, _state); + if( state->dotrace ) + { + stimerstop(&state->timermv, _state); + } + goto lbl_4; + } + if( state->solver.requesttype==1004 ) + { + if( state->dotrace ) + { + stimerstart(&state->timerrescale, _state); + } + nlcgipm2_autoscaletargetconstraints(state, _state); + if( state->dotrace ) + { + stimerstop(&state->timerrescale, _state); + } + goto lbl_4; + } + if( state->solver.requesttype==1005 ) + { + rcopyv(1+state->mnlc+state->mxx+state->mlc, &state->fscales, &state->solver.replyv, _state); + goto lbl_4; + } + if( state->solver.requesttype==1006 ) + { + nlcgipm2_basepointasbest(state, _state); + goto lbl_4; + } + if( state->solver.requesttype!=1007 ) + { + goto lbl_10; + } + nlcgipm2_restorebestpoint(state, _state); + ae_assert(state->mxx==0, "NLCGIPM2: integrity check 395132 failed", _state); + rcopyv(state->n, &state->basex, &state->x, _state); + rmergemaxv(state->n, &state->finitescaledbndl, &state->x, _state); + rmergeminv(state->n, &state->finitescaledbndu, &state->x, _state); + state->reportf = state->baserawf0; + state->xupdated = ae_true; + if( state->dotrace ) + { + stimerstart(&state->timerreport, _state); + } + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + if( state->dotrace ) + { + stimerstop(&state->timerreport, _state); + } + state->xupdated = ae_false; + goto lbl_4; +lbl_10: + if( state->solver.requesttype==1008 ) + { + ae_assert(state->mxx==0, "GIPM2: integrity check 760054 failed", _state); + if( state->dotrace ) + { + ae_trace("> updating Hessian model\n"); + } + rallocv(state->n, &state->tmp0, _state); + rallocv(state->n, &state->tmp1, _state); + rallocv(state->n, &state->tmp2, _state); + rallocv(state->n, &state->tmp3, _state); + rcopyvx(state->n, &state->solver.querydata, 0*state->n, &state->tmp0, 0, _state); + rcopyvx(state->n, &state->solver.querydata, 1*state->n, &state->tmp1, 0, _state); + rcopyvx(state->n, &state->solver.querydata, 2*state->n, &state->tmp2, 0, _state); + rcopyvx(state->n, &state->solver.querydata, 3*state->n, &state->tmp3, 0, _state); + hessianupdatev2(&state->hess, &state->tmp0, &state->tmp2, &state->tmp1, &state->tmp3, 2, ae_false, state->dotrace, 2, _state); + goto lbl_4; + } + ae_assert(ae_false, "NLPGIPM2: request not implemented", _state); + goto lbl_4; +lbl_5: + ae_assert(state->mxx==0, "GIPM2: integrity check 430320 failed", _state); + gipm2results(&state->solver, &state->xs, &state->replagbc, &state->tmp0, &state->repterminationtype, _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 395132 failed", _state); + rcopyv(state->n, &state->xs, &state->x, _state); + rmergemaxv(state->n, &state->finitescaledbndl, &state->x, _state); + rmergeminv(state->n, &state->finitescaledbndu, &state->x, _state); + rcopyallocv(state->n, &state->x, &state->xproj, _state); + state->needfisj = ae_true; + if( state->dotrace ) + { + stimerstart(&state->timercallback, _state); + } + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + if( state->dotrace ) + { + stimerstop(&state->timercallback, _state); + } + state->needfisj = ae_false; + if( state->mlc>0 ) + { + sparsegemv(&state->sparselc, 1.0, 0, &state->xproj, 0, 0.0, &state->replyfi, 1+state->mnlc+state->mxx, _state); + sparseappendmatrix(&state->replysj, &state->sparselc, _state); + } + ae_assert(state->mxx==0, "GIPM2: integrity check 395133 failed", _state); + rmergemulv(1+state->mnlc+state->mxx+state->mlc, &state->invfscales, &state->replyfi, _state); + sparsemultiplyrowsby(&state->replysj, &state->invfscales, _state); + if( state->hasfixed ) + { + rallocv(1+state->mnlc+state->mxx+state->mlc, &state->tmp1, _state); + state->tmp1.ptr.p_double[0] = (double)(1); + rcopyvx(state->mnlc+state->mxx+state->mlc, &state->tmp0, 0, &state->tmp1, 1, _state); + rmulvx(state->mnlc+state->mxx+state->mlc, -1.0, &state->tmp1, 1, _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 804136 failed", _state); + rcopyallocv(state->n, &state->replagbc, &state->tmp2, _state); + sparsegemv(&state->replysj, 1.0, 1, &state->tmp1, 0, 1.0, &state->tmp2, 0, _state); + for(i=0; i<=state->n-1; i++) + { + if( state->isfixed.ptr.p_bool[i] ) + { + state->replagbc.ptr.p_double[i] = state->replagbc.ptr.p_double[i]-state->tmp2.ptr.p_double[i]; + } + } + } + rmulv(state->n, state->fscales.ptr.p_double[0], &state->replagbc, _state); + rmergedivv(state->n, &state->s, &state->replagbc, _state); + rallocv(state->mlc, &state->replaglc, _state); + for(i=0; i<=state->mlc-1; i++) + { + state->replaglc.ptr.p_double[i] = state->tmp0.ptr.p_double[state->mnlc+state->mxx+i]*(-state->fscales.ptr.p_double[0])/(state->fscales.ptr.p_double[1+state->mnlc+state->mxx+i]*state->lcscales.ptr.p_double[i]); + } + rallocv(state->mnlc, &state->replagnlc, _state); + for(i=0; i<=state->mnlc-1; i++) + { + state->replagnlc.ptr.p_double[i] = state->tmp0.ptr.p_double[state->mxx+i]*(-state->fscales.ptr.p_double[0])/state->fscales.ptr.p_double[1+state->mxx+i]; + } + state->repbcerr = state->solver.repbcerr; + state->repbcidx = state->solver.repbcidx; + state->repsclerr = state->solver.repsclerr; + checklc2violation(&state->sparselc, &state->lcbndl, &state->lcbndu, &state->lcsrcidx, state->mlc, &state->xs, &state->replcerr, &state->replcidx, _state); + unscaleandchecknlc2violation(&state->replyfi, &state->fscales, &state->rawnl, &state->rawnu, state->mnlc, &state->repnlcerr, &state->repnlcidx, _state); + state->repiterationscount = state->solver.repiterationscount; + stimerstop(&state->timertotal, _state); + if( state->solver.dotrace ) + { + ae_trace("total time: %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("* callback: %10.1f ms\n", + (double)(stimergetms(&state->timercallback, _state))); + ae_trace("* report: %10.1f ms\n", + (double)(stimergetms(&state->timerreport, _state))); + ae_trace("* analyze: %10.1f ms\n", + (double)(stimergetms(&state->timeranalyze, _state))); + ae_trace("* factorize: %10.1f ms\n", + (double)(stimergetms(&state->timerfactorize, _state))); + ae_trace("* solve: %10.1f ms\n", + (double)(stimergetms(&state->timersolve, _state))); + ae_trace("* gemv: %10.1f ms\n", + (double)(stimergetms(&state->timermv, _state))); + ae_trace("* rescale: %10.1f ms\n", + (double)(stimergetms(&state->timerrescale, _state))); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ra.ptr.p_double[0] = v; + return result; +} + + +/************************************************************************* +Handle compute-and-remember request + + -- ALGLIB -- + Copyright 07.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_savepointaslast(nlpgipm2state* state, + double rawf0, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(state->mxx==0, "GIPM2: integrity check 403144 failed", _state); + rcopyallocv(n, &state->solver.querydata, &state->laztx, _state); + rcopyallocv(1+state->mnlc+state->mlc, &state->replyfi, &state->laztfi, _state); + sparsecopybuf(&state->replysj, &state->laztsj, _state); + state->laztrawf0 = rawf0; + state->haslast = ae_true; +} + + +/************************************************************************* +Handle compute-and-remember request + + -- ALGLIB -- + Copyright 07.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_lastpointasbase(nlpgipm2state* state, + /* Real */ const ae_vector* querydata, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(state->haslast, "NLPGIPM2: integrity check 468318 failed", _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 403144 failed", _state); + if( state->hasbase ) + { + rcopyallocv(n, &state->basex, &state->prevbasex, _state); + rcopyallocv(1+state->mnlc+state->mlc, &state->basefi, &state->prevbasefi, _state); + sparsecopybuf(&state->basesj, &state->prevbasesj, _state); + state->prevbaserawf0 = state->baserawf0; + state->hasprevbase = ae_true; + } + rcopyallocv(n, &state->laztx, &state->basex, _state); + rcopyallocv(1+state->mnlc+state->mlc, &state->laztfi, &state->basefi, _state); + sparsecopybuf(&state->laztsj, &state->basesj, _state); + state->baserawf0 = state->laztrawf0; + state->hasbase = ae_true; + state->hasbaseh = ae_false; +} + + +/************************************************************************* +Save base point as best + + -- ALGLIB -- + Copyright 07.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_basepointasbest(nlpgipm2state* state, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(state->hasbase, "NLPGIPM2: integrity check 141338 failed", _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 142338 failed", _state); + rcopyallocv(n, &state->basex, &state->bestx, _state); + rcopyallocv(1+state->mnlc+state->mlc, &state->basefi, &state->bestfi, _state); + sparsecopybuf(&state->basesj, &state->bestsj, _state); + state->bestrawf0 = state->baserawf0; + state->hasbest = ae_true; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 07.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_restorebestpoint(nlpgipm2state* state, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + ae_assert(state->hasbest, "NLPGIPM2: integrity check 141338 failed", _state); + ae_assert(state->mxx==0, "GIPM2: integrity check 142338 failed", _state); + rcopyallocv(n, &state->bestx, &state->basex, _state); + rcopyallocv(1+state->mnlc+state->mlc, &state->bestfi, &state->basefi, _state); + sparsecopybuf(&state->bestsj, &state->basesj, _state); + state->baserawf0 = state->bestrawf0; + state->hasbase = ae_true; +} + + +/************************************************************************* +Handle factorization request + + -- ALGLIB -- + Copyright 07.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_factorizematrix(nlpgipm2state* state, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t offs; + ae_int_t mtotal; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + + + ae_assert(state->hasbase, "NLPGIPM2: integrity check 453018 failed (no base point)", _state); + n = state->n; + mtotal = state->mnlc+state->mxx+state->mlc; + ae_assert(!state->isdense, "NLPGIPM2: integrity check 017312 failed", _state); + hessiangetlowrankstabilized(&state->hess, &state->basehsr1diag, &state->basehsr1corrc, &state->basehsr1corrd, &state->basehrank, _state); + state->hasbaseh = ae_true; + ae_assert(!state->isdense, "NLPGIPM2: integrity check 017313 failed", _state); + ae_assert(state->hassparsityanalyzed, "NLPGIPM2: integrity check 018312 failed (sparsity pattern was not analyzed)", _state); + rsetv(state->sparsesys.ridx.ptr.p_int[n+mtotal+state->hessmemlen], 0.0, &state->sparsesys.vals, _state); + for(i=0; i<=n-1; i++) + { + state->sparsesys.vals.ptr.p_double[i] = state->basehsr1diag.ptr.p_double[i]+state->solver.querydata.ptr.p_double[i]; + } + for(i=0; i<=mtotal-1; i++) + { + offs = state->sparsesys.ridx.ptr.p_int[n+i]; + j0 = state->lastanalyzedjac.ridx.ptr.p_int[1+i]; + j1 = state->lastanalyzedjac.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.vals.ptr.p_double[offs] = state->lastanalyzedjac.vals.ptr.p_double[jj]; + offs = offs+1; + } + state->sparsesys.vals.ptr.p_double[offs] = state->solver.querydata.ptr.p_double[n+i]; + offs = offs+1; + ae_assert(offs==state->sparsesys.ridx.ptr.p_int[n+i+1], "GIPM2: integrity check 066230 failed, LastAnalyzedJac sparsity pattern is inconsistent with the what was analyzed", _state); + } + for(i=0; i<=state->basehrank-1; i++) + { + ae_assert(state->sparsesys.uidx.ptr.p_int[n+mtotal+i]-state->sparsesys.ridx.ptr.p_int[n+mtotal+i]==n+1, "NLCGIPM2: 049020", _state); + offs = state->sparsesys.ridx.ptr.p_int[n+mtotal+i]; + for(j=0; j<=n-1; j++) + { + state->sparsesys.vals.ptr.p_double[offs+j] = state->basehsr1corrc.ptr.pp_double[i][j]; + } + state->sparsesys.vals.ptr.p_double[offs+n] = -state->basehsr1corrd.ptr.p_double[i]; + } + for(i=state->basehrank; i<=state->hessmemlen-1; i++) + { + ae_assert(state->sparsesys.didx.ptr.p_int[n+mtotal+i]sparsesys.uidx.ptr.p_int[n+mtotal+i], "NLCGIPM2: 065212", _state); + state->sparsesys.vals.ptr.p_double[state->sparsesys.didx.ptr.p_int[n+mtotal+i]] = 1.0; + } + ballocv(n+mtotal+state->hessmemlen, &state->tmpb, _state); + for(i=0; i<=n-1; i++) + { + state->tmpb.ptr.p_bool[i] = ae_true; + } + for(i=n; i<=mtotal+n-1; i++) + { + state->tmpb.ptr.p_bool[i] = ae_false; + } + for(i=mtotal+n; i<=state->hessmemlen+mtotal+n-1; i++) + { + state->tmpb.ptr.p_bool[i] = ae_fp_greater_eq(state->sparsesys.vals.ptr.p_double[state->sparsesys.didx.ptr.p_int[i]],0.0); + } + spsymmcontrolsign(&state->analysis, &state->tmpb, 0.0, _state); + spsymmreload(&state->analysis, &state->sparsesys, _state); + state->factorized = spsymmfactorize(&state->analysis, _state); + state->solver.factsuccess = state->factorized; + if( !state->factorized ) + { + return; + } + if( state->solver.dotrace ) + { + ae_trace("> Hessian factorized, |stabilized.diagonal|=%0.2e\n", + (double)(rmaxabsv(n, &state->basehsr1diag, _state))); + } + state->solver.factsuccess = state->factorized; +} + + +/************************************************************************* +Handle solve request + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_solvesystem(nlpgipm2state* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t mtotal; + + + n = state->n; + mtotal = state->mnlc+state->mxx+state->mlc; + ae_assert(state->factorized, "NLPGIPM2: integrity check 577120 failed", _state); + rsetallocv(n+mtotal+state->hessmemlen, 0.0, &state->tmp0, _state); + rcopyv(n+mtotal, &state->solver.querydata, &state->tmp0, _state); + spsymmsolve(&state->analysis, &state->tmp0, _state); + rcopyv(n+mtotal, &state->tmp0, &state->solver.replysol, _state); +} + + +/************************************************************************* +Handle matrix-vector product request + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_matrixvector(nlpgipm2state* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t mtotal; + + + n = state->n; + mtotal = state->mnlc+state->mxx+state->mlc; + ae_assert(state->hasbase&&state->hasbaseh, "NLPGIPM2: integrity check 4322 failed", _state); + ae_assert(!state->isdense, "NLCGIPM2: integrity check 217017 failed", _state); + rallocv(ae_maxint(n, mtotal+1, _state), &state->tmp0, _state); + rallocv(ae_maxint(n, mtotal+1, _state), &state->tmp1, _state); + rallocv(ae_maxint(n, mtotal+1, _state), &state->tmp2, _state); + rcopyvx(n, &state->solver.querydata, 0, &state->tmp0, 0, _state); + rcopyv(n, &state->tmp0, &state->tmp1, _state); + rmergemulv(n, &state->basehsr1diag, &state->tmp1, _state); + if( state->basehrank>0 ) + { + ae_assert(state->basehrank<=n, "NLCGIPM2: integrity check 235014 failed", _state); + rgemv(state->basehrank, n, 1.0, &state->basehsr1corrc, 0, &state->tmp0, 0.0, &state->tmp2, _state); + rmergemulv(state->basehrank, &state->basehsr1corrd, &state->tmp2, _state); + rgemv(n, state->basehrank, 1.0, &state->basehsr1corrc, 1, &state->tmp2, 1.0, &state->tmp1, _state); + } + rcopyvx(n, &state->tmp1, 0, &state->solver.replyprod, 0, _state); + rsetv(1+mtotal, 0.0, &state->tmp1, _state); + ae_assert(state->mxx==0, "NLPGIPM2: integrity check 272335 failed", _state); + sparsegemv(&state->basesj, 1.0, 0, &state->solver.querydata, 0, 0.0, &state->tmp1, 0, _state); + rcopyvx(mtotal, &state->tmp1, 1, &state->solver.replyprod, n, _state); + rsetv(n, 0.0, &state->tmp1, _state); + ae_assert(state->mxx==0, "NLPGIPM2: integrity check 277336 failed", _state); + state->tmp2.ptr.p_double[0] = (double)(0); + rcopyvx(mtotal, &state->solver.querydata, n, &state->tmp2, 1, _state); + sparsegemv(&state->basesj, 1.0, 1, &state->tmp2, 0, 1.0, &state->tmp1, 0, _state); + rcopyvx(n, &state->tmp1, 0, &state->solver.replyprod, n+mtotal, _state); +} + + +/************************************************************************* +Initialize autoscaler state + + -- ALGLIB -- + Copyright 23.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_autoscaleinit(nlpgipm2state* state, ae_state *_state) +{ + ae_int_t mtotal; + + + mtotal = state->mnlc+state->mxx+state->mlc; + rsetallocv(1+mtotal, 1.0, &state->fscales, _state); + rsetallocv(1+mtotal, 1.0, &state->invfscales, _state); + rsetallocv(1+mtotal, 0.0, &state->autoscalerhessnorms, _state); + state->firstscaling = ae_true; + state->fbigscale = 5.0; + state->fsmallscale = 0.1; +} + + +/************************************************************************* +Rescale target/constraints if gradients deviate from 1.0 too much. + +Sets State.Solver.ReplyWasRescale to False or True; if the latter, also +sets State.Solver.ReplyV to multipliers applied to objective/constraints. + + -- ALGLIB -- + Copyright 23.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_autoscaletargetconstraints(nlpgipm2state* state, + ae_state *_state) +{ + ae_int_t n; + ae_int_t mtotal; + ae_int_t i; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t k0; + ae_int_t k1; + ae_int_t kk; + double ss; + double sy; + double nrm; + double gnrm2; + double v; + double multiplyby; + double setscaleto; + double minss; + ae_bool bigscaletriggered; + ae_bool smallscaletriggered; + + + ae_assert(state->hasbase, "NLPGIPM2: autoscale request was issued before base point was marked", _state); + n = state->n; + mtotal = state->mnlc+state->mxx+state->mlc; + minss = ae_sqr(1.0E-4, _state); + ss = (double)(0); + if( state->hasprevbase ) + { + for(i=0; i<=n-1; i++) + { + ss = ss+ae_sqr(state->basex.ptr.p_double[i]-state->prevbasex.ptr.p_double[i], _state); + } + } + state->solver.replywasrescale = ae_false; + bigscaletriggered = ae_false; + smallscaletriggered = ae_false; + for(i=0; i<=mtotal; i++) + { + j0 = state->basesj.ridx.ptr.p_int[i]; + j1 = state->basesj.ridx.ptr.p_int[i+1]-1; + gnrm2 = (double)(0); + for(jj=j0; jj<=j1; jj++) + { + v = state->basesj.vals.ptr.p_double[jj]; + gnrm2 = gnrm2+v*v; + } + gnrm2 = ae_sqrt(gnrm2, _state); + nrm = gnrm2; + if( state->hasprevbase&&ae_fp_greater_eq(ss,minss) ) + { + k0 = state->prevbasesj.ridx.ptr.p_int[i]; + k1 = state->prevbasesj.ridx.ptr.p_int[i+1]-1; + jj = j0; + kk = k0; + sy = (double)(0); + while(jj<=j1&&kk<=k1) + { + if( state->basesj.idx.ptr.p_int[jj]==state->prevbasesj.idx.ptr.p_int[kk] ) + { + k = state->basesj.idx.ptr.p_int[jj]; + sy = sy+(state->basex.ptr.p_double[k]-state->prevbasex.ptr.p_double[k])*(state->basesj.vals.ptr.p_double[jj]-state->prevbasesj.vals.ptr.p_double[kk]); + jj = jj+1; + kk = kk+1; + continue; + } + if( state->basesj.idx.ptr.p_int[jj]prevbasesj.idx.ptr.p_int[kk] ) + { + k = state->basesj.idx.ptr.p_int[jj]; + sy = sy+(state->basex.ptr.p_double[k]-state->prevbasex.ptr.p_double[k])*(state->basesj.vals.ptr.p_double[jj]-(double)0); + jj = jj+1; + } + else + { + k = state->prevbasesj.idx.ptr.p_int[kk]; + sy = sy+(state->basex.ptr.p_double[k]-state->prevbasex.ptr.p_double[k])*((double)0-state->prevbasesj.vals.ptr.p_double[kk]); + kk = kk+1; + } + } + while(jj<=j1) + { + k = state->basesj.idx.ptr.p_int[jj]; + sy = sy+(state->basex.ptr.p_double[k]-state->prevbasex.ptr.p_double[k])*(state->basesj.vals.ptr.p_double[jj]-(double)0); + jj = jj+1; + } + while(kk<=k1) + { + k = state->prevbasesj.idx.ptr.p_int[kk]; + sy = sy+(state->basex.ptr.p_double[k]-state->prevbasex.ptr.p_double[k])*((double)0-state->prevbasesj.vals.ptr.p_double[kk]); + kk = kk+1; + } + state->autoscalerhessnorms.ptr.p_double[i] = nlcgipm2_autoscalerhessdecay*state->autoscalerhessnorms.ptr.p_double[i]+((double)1-nlcgipm2_autoscalerhessdecay)*ae_fabs(sy/ss, _state); + } + nrm = ae_maxreal(nrm, state->autoscalerhessnorms.ptr.p_double[i]/nlcgipm2_maxhessnrm, _state); + multiplyby = 1.0; + setscaleto = state->fscales.ptr.p_double[i]; + if( ae_fp_greater_eq(nrm,state->fbigscale) ) + { + v = nrm; + if( !state->firstscaling ) + { + v = ae_minreal(v, nlcgipm2_maxrescale, _state); + } + multiplyby = (double)1/v; + setscaleto = state->fscales.ptr.p_double[i]*v; + bigscaletriggered = ae_true; + } + if( ae_fp_less_eq(nrm,state->fsmallscale)&&ae_fp_greater(state->fscales.ptr.p_double[i],1.0) ) + { + v = nrm; + if( !state->firstscaling ) + { + v = ae_maxreal(v, nlcgipm2_minrescale, _state); + } + if( ae_fp_greater(state->fscales.ptr.p_double[i]*v,(double)(1)) ) + { + multiplyby = (double)1/v; + setscaleto = state->fscales.ptr.p_double[i]*v; + } + else + { + multiplyby = state->fscales.ptr.p_double[i]; + setscaleto = 1.0; + } + smallscaletriggered = ae_true; + } + state->solver.replyv.ptr.p_double[i] = multiplyby; + if( ae_fp_neq(multiplyby,1.0) ) + { + state->fscales.ptr.p_double[i] = setscaleto; + state->invfscales.ptr.p_double[i] = (double)1/setscaleto; + state->autoscalerhessnorms.ptr.p_double[i] = state->autoscalerhessnorms.ptr.p_double[i]*multiplyby; + if( state->haslast ) + { + nlcgipm2_applyrescale(&state->laztfi, &state->laztsj, i, multiplyby, _state); + } + if( state->hasbase ) + { + nlcgipm2_applyrescale(&state->basefi, &state->basesj, i, multiplyby, _state); + } + if( state->hasprevbase ) + { + nlcgipm2_applyrescale(&state->prevbasefi, &state->prevbasesj, i, multiplyby, _state); + } + if( i>=1 ) + { + ae_assert(state->mxx==0, "NLPGIPM2: 956327", _state); + if( ae_isfinite(state->wrkccbndl.ptr.p_double[i-1], _state) ) + { + state->wrkccbndl.ptr.p_double[i-1] = state->wrkccbndl.ptr.p_double[i-1]*multiplyby; + } + if( ae_isfinite(state->wrkccbndu.ptr.p_double[i-1], _state) ) + { + state->wrkccbndu.ptr.p_double[i-1] = state->wrkccbndu.ptr.p_double[i-1]*multiplyby; + } + } + state->solver.replywasrescale = ae_true; + } + } + if( smallscaletriggered ) + { + state->fsmallscale = state->fsmallscale*nlcgipm2_smallscaledecrease; + } + state->firstscaling = ae_false; + touchboolean(&bigscaletriggered, _state); +} + + +/************************************************************************* +Rescale specific component of a function vector and a corresponding Jacobian +row. + + -- ALGLIB -- + Copyright 23.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_applyrescale(/* Real */ ae_vector* fi, + sparsematrix* sj, + ae_int_t idx, + double multiplyby, + ae_state *_state) +{ + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + + + fi->ptr.p_double[idx] = fi->ptr.p_double[idx]*multiplyby; + j0 = sj->ridx.ptr.p_int[idx]; + j1 = sj->ridx.ptr.p_int[idx+1]-1; + for(jj=j0; jj<=j1; jj++) + { + sj->vals.ptr.p_double[jj] = sj->vals.ptr.p_double[jj]*multiplyby; + } +} + + +/************************************************************************* +Analyze sparsity pattern of KKT system and generate SparseSys; recompute +if anything has changed. + + -- ALGLIB -- + Copyright 23.02.2025 by Bochkanov Sergey +*************************************************************************/ +static void nlcgipm2_generatesparsesys(nlpgipm2state* state, + const sparsematrix* upcomingsj, + ae_state *_state) +{ + ae_int_t n; + ae_int_t mtotal; + ae_int_t i; + ae_int_t j; + ae_int_t offs; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t facttype; + + + n = state->n; + mtotal = state->mnlc+state->mxx+state->mlc; + ae_assert((sparseiscrs(upcomingsj, _state)&&upcomingsj->m==mtotal+1)&&upcomingsj->n==n, "NLCGIPM2: 484120", _state); + if( state->hassparsityanalyzed&&sparsetrygatherclear(&state->lastanalyzedjac, upcomingsj, _state) ) + { + return; + } + if( state->hassparsityanalyzed ) + { + sparsemergepatterns(&state->lastanalyzedjac, upcomingsj, &state->tmpsparse, _state); + sparsecopybuf(&state->tmpsparse, &state->lastanalyzedjac, _state); + if( !sparsetrygatherclear(&state->lastanalyzedjac, upcomingsj, _state) ) + { + ae_assert(ae_false, "NLCGIPM2: integrity check 765614 failed", _state); + } + } + else + { + sparsecopybuf(upcomingsj, &state->lastanalyzedjac, _state); + } + state->sparsesys.m = n+mtotal+state->hessmemlen; + state->sparsesys.n = n+mtotal+state->hessmemlen; + iallocv(n+state->hessmemlen+mtotal+1, &state->sparsesys.ridx, _state); + state->sparsesys.ridx.ptr.p_int[0] = 0; + offs = 0; + igrowv(offs+n, &state->sparsesys.idx, _state); + rgrowv(offs+n, &state->sparsesys.vals, _state); + for(i=0; i<=n-1; i++) + { + state->sparsesys.idx.ptr.p_int[offs] = i; + state->sparsesys.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[i+1] = offs; + } + for(i=0; i<=mtotal-1; i++) + { + igrowv(offs+n+1, &state->sparsesys.idx, _state); + rgrowv(offs+n+1, &state->sparsesys.vals, _state); + j0 = state->lastanalyzedjac.ridx.ptr.p_int[1+i]; + j1 = state->lastanalyzedjac.ridx.ptr.p_int[1+i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sparsesys.idx.ptr.p_int[offs] = state->lastanalyzedjac.idx.ptr.p_int[jj]; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + } + state->sparsesys.idx.ptr.p_int[offs] = n+i; + state->sparsesys.vals.ptr.p_double[offs] = 1.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[n+i+1] = offs; + } + igrowv(offs+state->hessmemlen*(n+1), &state->sparsesys.idx, _state); + rgrowv(offs+state->hessmemlen*(n+1), &state->sparsesys.vals, _state); + for(i=0; i<=state->hessmemlen-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->sparsesys.idx.ptr.p_int[offs] = j; + state->sparsesys.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + } + state->sparsesys.idx.ptr.p_int[offs] = n+mtotal+i; + state->sparsesys.vals.ptr.p_double[offs] = 0.0; + offs = offs+1; + state->sparsesys.ridx.ptr.p_int[n+mtotal+i+1] = offs; + } + sparsecreatecrsinplace(&state->sparsesys, _state); + facttype = 21; + iallocv(n+mtotal+state->hessmemlen, &state->priorities, _state); + for(i=0; i<=n-1; i++) + { + state->priorities.ptr.p_int[i] = 0; + } + for(i=n; i<=mtotal+n-1; i++) + { + state->priorities.ptr.p_int[i] = 0; + } + for(i=mtotal+n; i<=state->hessmemlen+mtotal+n-1; i++) + { + state->priorities.ptr.p_int[i] = 2; + } + if( !spsymmanalyze(&state->sparsesys, &state->priorities, nlcgipm2_mupromote, 0, facttype, 3, 1, &state->analysis, _state) ) + { + ae_assert(ae_false, "NLCGIPM2: critical integrity check failed, symbolically degenerate KKT system encountered", _state); + } + state->hassparsityanalyzed = ae_true; +} + + +void _nlpgipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nlpgipm2state *p = (nlpgipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitescaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finitescaledbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finiterawbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->finiterawbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->isfixed, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->nonfixedmask, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + _xbfgshessian_init(&p->hess, _state, make_automatic); + ae_vector_init(&p->laztx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laztfi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->laztsj, _state, make_automatic); + ae_vector_init(&p->basex, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->basefi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->basesj, _state, make_automatic); + ae_vector_init(&p->prevbasex, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->prevbasefi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->prevbasesj, _state, make_automatic); + ae_vector_init(&p->bestx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bestfi, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->bestsj, _state, make_automatic); + ae_vector_init(&p->basehsr1diag, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->basehsr1corrd, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->basehsr1corrc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xproj, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->deltaproj, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->priorities, 0, DT_INT, _state, make_automatic); + _spcholanalysis_init(&p->analysis, _state, make_automatic); + _sparsematrix_init(&p->sparsesys, _state, make_automatic); + _sparsematrix_init(&p->lastanalyzedjac, _state, make_automatic); + ae_vector_init(&p->fscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invfscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->autoscalerhessnorms, 0, DT_REAL, _state, make_automatic); + _gipm2state_init(&p->solver, _state, make_automatic); + _sparsematrix_init(&p->sparselc, _state, make_automatic); + ae_vector_init(&p->lcbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lcsrcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->lcscales, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawnu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkccbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkccbndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xs, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagnlc, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timerfactorize, _state, make_automatic); + _stimer_init(&p->timersolve, _state, make_automatic); + _stimer_init(&p->timercallback, _state, make_automatic); + _stimer_init(&p->timerreport, _state, make_automatic); + _stimer_init(&p->timeranalyze, _state, make_automatic); + _stimer_init(&p->timermv, _state, make_automatic); + _stimer_init(&p->timerrescale, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp3, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpb, 0, DT_BOOL, _state, make_automatic); + _sparsematrix_init(&p->tmpsparse, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _nlpgipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nlpgipm2state *dst = (nlpgipm2state*)_dst; + const nlpgipm2state *src = (const nlpgipm2state*)_src; + dst->isdense = src->isdense; + dst->isconvex = src->isconvex; + dst->n = src->n; + dst->mlc = src->mlc; + dst->mnlc = src->mnlc; + dst->mxx = src->mxx; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->scaledx0, &src->scaledx0, _state, make_automatic); + dst->hasbc = src->hasbc; + dst->hasfixed = src->hasfixed; + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finitescaledbndl, &src->finitescaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->finitescaledbndu, &src->finitescaledbndu, _state, make_automatic); + ae_vector_init_copy(&dst->finiterawbndl, &src->finiterawbndl, _state, make_automatic); + ae_vector_init_copy(&dst->finiterawbndu, &src->finiterawbndu, _state, make_automatic); + ae_vector_init_copy(&dst->isfixed, &src->isfixed, _state, make_automatic); + ae_vector_init_copy(&dst->nonfixedmask, &src->nonfixedmask, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + dst->reportf = src->reportf; + dst->needfisj = src->needfisj; + dst->xupdated = src->xupdated; + _xbfgshessian_init_copy(&dst->hess, &src->hess, _state, make_automatic); + ae_vector_init_copy(&dst->laztx, &src->laztx, _state, make_automatic); + ae_vector_init_copy(&dst->laztfi, &src->laztfi, _state, make_automatic); + _sparsematrix_init_copy(&dst->laztsj, &src->laztsj, _state, make_automatic); + dst->laztrawf0 = src->laztrawf0; + ae_vector_init_copy(&dst->basex, &src->basex, _state, make_automatic); + ae_vector_init_copy(&dst->basefi, &src->basefi, _state, make_automatic); + _sparsematrix_init_copy(&dst->basesj, &src->basesj, _state, make_automatic); + dst->baserawf0 = src->baserawf0; + ae_vector_init_copy(&dst->prevbasex, &src->prevbasex, _state, make_automatic); + ae_vector_init_copy(&dst->prevbasefi, &src->prevbasefi, _state, make_automatic); + _sparsematrix_init_copy(&dst->prevbasesj, &src->prevbasesj, _state, make_automatic); + dst->prevbaserawf0 = src->prevbaserawf0; + ae_vector_init_copy(&dst->bestx, &src->bestx, _state, make_automatic); + ae_vector_init_copy(&dst->bestfi, &src->bestfi, _state, make_automatic); + _sparsematrix_init_copy(&dst->bestsj, &src->bestsj, _state, make_automatic); + dst->bestrawf0 = src->bestrawf0; + dst->hessmemlen = src->hessmemlen; + ae_vector_init_copy(&dst->basehsr1diag, &src->basehsr1diag, _state, make_automatic); + ae_vector_init_copy(&dst->basehsr1corrd, &src->basehsr1corrd, _state, make_automatic); + ae_matrix_init_copy(&dst->basehsr1corrc, &src->basehsr1corrc, _state, make_automatic); + dst->basehrank = src->basehrank; + dst->hasbaseh = src->hasbaseh; + dst->haslast = src->haslast; + dst->hasbase = src->hasbase; + dst->hasprevbase = src->hasprevbase; + dst->hasbest = src->hasbest; + ae_vector_init_copy(&dst->xproj, &src->xproj, _state, make_automatic); + ae_vector_init_copy(&dst->deltaproj, &src->deltaproj, _state, make_automatic); + ae_vector_init_copy(&dst->priorities, &src->priorities, _state, make_automatic); + _spcholanalysis_init_copy(&dst->analysis, &src->analysis, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsesys, &src->sparsesys, _state, make_automatic); + _sparsematrix_init_copy(&dst->lastanalyzedjac, &src->lastanalyzedjac, _state, make_automatic); + dst->hassparsityanalyzed = src->hassparsityanalyzed; + dst->factorized = src->factorized; + ae_vector_init_copy(&dst->fscales, &src->fscales, _state, make_automatic); + ae_vector_init_copy(&dst->invfscales, &src->invfscales, _state, make_automatic); + dst->fbigscale = src->fbigscale; + dst->fsmallscale = src->fsmallscale; + dst->firstscaling = src->firstscaling; + ae_vector_init_copy(&dst->autoscalerhessnorms, &src->autoscalerhessnorms, _state, make_automatic); + _gipm2state_init_copy(&dst->solver, &src->solver, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparselc, &src->sparselc, _state, make_automatic); + ae_vector_init_copy(&dst->lcbndl, &src->lcbndl, _state, make_automatic); + ae_vector_init_copy(&dst->lcbndu, &src->lcbndu, _state, make_automatic); + ae_vector_init_copy(&dst->lcsrcidx, &src->lcsrcidx, _state, make_automatic); + ae_vector_init_copy(&dst->lcscales, &src->lcscales, _state, make_automatic); + ae_vector_init_copy(&dst->rawnl, &src->rawnl, _state, make_automatic); + ae_vector_init_copy(&dst->rawnu, &src->rawnu, _state, make_automatic); + ae_vector_init_copy(&dst->wrkccbndl, &src->wrkccbndl, _state, make_automatic); + ae_vector_init_copy(&dst->wrkccbndu, &src->wrkccbndu, _state, make_automatic); + dst->eps = src->eps; + dst->maxits = src->maxits; + dst->repiterationscount = src->repiterationscount; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->repsclerr = src->repsclerr; + ae_vector_init_copy(&dst->xs, &src->xs, _state, make_automatic); + ae_vector_init_copy(&dst->replagbc, &src->replagbc, _state, make_automatic); + ae_vector_init_copy(&dst->replaglc, &src->replaglc, _state, make_automatic); + ae_vector_init_copy(&dst->replagnlc, &src->replagnlc, _state, make_automatic); + dst->dotrace = src->dotrace; + dst->dolaconictrace = src->dolaconictrace; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timerfactorize, &src->timerfactorize, _state, make_automatic); + _stimer_init_copy(&dst->timersolve, &src->timersolve, _state, make_automatic); + _stimer_init_copy(&dst->timercallback, &src->timercallback, _state, make_automatic); + _stimer_init_copy(&dst->timerreport, &src->timerreport, _state, make_automatic); + _stimer_init_copy(&dst->timeranalyze, &src->timeranalyze, _state, make_automatic); + _stimer_init_copy(&dst->timermv, &src->timermv, _state, make_automatic); + _stimer_init_copy(&dst->timerrescale, &src->timerrescale, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state, make_automatic); + ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmpsparse, &src->tmpsparse, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _nlpgipm2state_clear(void* _p) +{ + nlpgipm2state *p = (nlpgipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->scaledx0); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_vector_clear(&p->finitescaledbndl); + ae_vector_clear(&p->finitescaledbndu); + ae_vector_clear(&p->finiterawbndl); + ae_vector_clear(&p->finiterawbndu); + ae_vector_clear(&p->isfixed); + ae_vector_clear(&p->nonfixedmask); + ae_vector_clear(&p->x); + ae_vector_clear(&p->replyfi); + _sparsematrix_clear(&p->replysj); + _xbfgshessian_clear(&p->hess); + ae_vector_clear(&p->laztx); + ae_vector_clear(&p->laztfi); + _sparsematrix_clear(&p->laztsj); + ae_vector_clear(&p->basex); + ae_vector_clear(&p->basefi); + _sparsematrix_clear(&p->basesj); + ae_vector_clear(&p->prevbasex); + ae_vector_clear(&p->prevbasefi); + _sparsematrix_clear(&p->prevbasesj); + ae_vector_clear(&p->bestx); + ae_vector_clear(&p->bestfi); + _sparsematrix_clear(&p->bestsj); + ae_vector_clear(&p->basehsr1diag); + ae_vector_clear(&p->basehsr1corrd); + ae_matrix_clear(&p->basehsr1corrc); + ae_vector_clear(&p->xproj); + ae_vector_clear(&p->deltaproj); + ae_vector_clear(&p->priorities); + _spcholanalysis_clear(&p->analysis); + _sparsematrix_clear(&p->sparsesys); + _sparsematrix_clear(&p->lastanalyzedjac); + ae_vector_clear(&p->fscales); + ae_vector_clear(&p->invfscales); + ae_vector_clear(&p->autoscalerhessnorms); + _gipm2state_clear(&p->solver); + _sparsematrix_clear(&p->sparselc); + ae_vector_clear(&p->lcbndl); + ae_vector_clear(&p->lcbndu); + ae_vector_clear(&p->lcsrcidx); + ae_vector_clear(&p->lcscales); + ae_vector_clear(&p->rawnl); + ae_vector_clear(&p->rawnu); + ae_vector_clear(&p->wrkccbndl); + ae_vector_clear(&p->wrkccbndu); + ae_vector_clear(&p->xs); + ae_vector_clear(&p->replagbc); + ae_vector_clear(&p->replaglc); + ae_vector_clear(&p->replagnlc); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timerfactorize); + _stimer_clear(&p->timersolve); + _stimer_clear(&p->timercallback); + _stimer_clear(&p->timerreport); + _stimer_clear(&p->timeranalyze); + _stimer_clear(&p->timermv); + _stimer_clear(&p->timerrescale); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmp3); + ae_vector_clear(&p->tmpb); + _sparsematrix_clear(&p->tmpsparse); + _rcommstate_clear(&p->rstate); +} + + +void _nlpgipm2state_destroy(void* _p) +{ + nlpgipm2state *p = (nlpgipm2state*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->scaledx0); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_vector_destroy(&p->finitescaledbndl); + ae_vector_destroy(&p->finitescaledbndu); + ae_vector_destroy(&p->finiterawbndl); + ae_vector_destroy(&p->finiterawbndu); + ae_vector_destroy(&p->isfixed); + ae_vector_destroy(&p->nonfixedmask); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->replyfi); + _sparsematrix_destroy(&p->replysj); + _xbfgshessian_destroy(&p->hess); + ae_vector_destroy(&p->laztx); + ae_vector_destroy(&p->laztfi); + _sparsematrix_destroy(&p->laztsj); + ae_vector_destroy(&p->basex); + ae_vector_destroy(&p->basefi); + _sparsematrix_destroy(&p->basesj); + ae_vector_destroy(&p->prevbasex); + ae_vector_destroy(&p->prevbasefi); + _sparsematrix_destroy(&p->prevbasesj); + ae_vector_destroy(&p->bestx); + ae_vector_destroy(&p->bestfi); + _sparsematrix_destroy(&p->bestsj); + ae_vector_destroy(&p->basehsr1diag); + ae_vector_destroy(&p->basehsr1corrd); + ae_matrix_destroy(&p->basehsr1corrc); + ae_vector_destroy(&p->xproj); + ae_vector_destroy(&p->deltaproj); + ae_vector_destroy(&p->priorities); + _spcholanalysis_destroy(&p->analysis); + _sparsematrix_destroy(&p->sparsesys); + _sparsematrix_destroy(&p->lastanalyzedjac); + ae_vector_destroy(&p->fscales); + ae_vector_destroy(&p->invfscales); + ae_vector_destroy(&p->autoscalerhessnorms); + _gipm2state_destroy(&p->solver); + _sparsematrix_destroy(&p->sparselc); + ae_vector_destroy(&p->lcbndl); + ae_vector_destroy(&p->lcbndu); + ae_vector_destroy(&p->lcsrcidx); + ae_vector_destroy(&p->lcscales); + ae_vector_destroy(&p->rawnl); + ae_vector_destroy(&p->rawnu); + ae_vector_destroy(&p->wrkccbndl); + ae_vector_destroy(&p->wrkccbndu); + ae_vector_destroy(&p->xs); + ae_vector_destroy(&p->replagbc); + ae_vector_destroy(&p->replaglc); + ae_vector_destroy(&p->replagnlc); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timerfactorize); + _stimer_destroy(&p->timersolve); + _stimer_destroy(&p->timercallback); + _stimer_destroy(&p->timerreport); + _stimer_destroy(&p->timeranalyze); + _stimer_destroy(&p->timermv); + _stimer_destroy(&p->timerrescale); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmp3); + ae_vector_destroy(&p->tmpb); + _sparsematrix_destroy(&p->tmpsparse); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + BOUND CONSTRAINED OPTIMIZATION + WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BLEIC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBLEICCreate() call + +2. USer adds boundary and/or linear constraints by calling + MinBLEICSetBC() and MinBLEICSetLC() functions. + +3. User sets stopping conditions with MinBLEICSetCond(). + +4. User calls MinBLEICOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBLEICResults() to get solution + +6. Optionally user may call MinBLEICRestartFrom() to solve another problem + with same N but another starting point. + MinBLEICRestartFrom() allows to reuse already initialized structure. + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minbleicstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + _minbleicstate_clear(state); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "MinBLEICCreate: N<1", _state); + ae_assert(x->cnt>=n, "MinBLEICCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBLEICSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbleicstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + _minbleicstate_clear(state); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "MinBLEICCreateF: N<1", _state); + ae_assert(x->cnt>=n, "MinBLEICCreateF: Length(X)nmain; + ae_assert(bndl->cnt>=n, "MinBLEICSetBC: Length(BndL)cnt>=n, "MinBLEICSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBLEICSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } + sassetbc(&state->sas, bndl, bndu, _state); +} + + +/************************************************************************* +This function sets linear constraints for BLEIC optimizer. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetlc(minbleicstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + double v; + + + n = state->nmain; + + /* + * First, check for errors in the inputs + */ + ae_assert(k>=0, "MinBLEICSetLC: K<0", _state); + ae_assert(c->cols>=n+1||k==0, "MinBLEICSetLC: Cols(C)rows>=k, "MinBLEICSetLC: Rows(C)cnt>=k, "MinBLEICSetLC: Length(CT)nec = 0; + state->nic = 0; + sassetlc(&state->sas, c, ct, 0, _state); + return; + } + + /* + * Equality constraints are stored first, in the upper + * NEC rows of State.CLEIC matrix. Inequality constraints + * are stored in the next NIC rows. + * + * NOTE: we convert inequality constraints to the form + * A*x<=b before copying them. + */ + rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); + state->nec = 0; + state->nic = 0; + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]==0 ) + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + state->nec = state->nec+1; + } + } + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]!=0 ) + { + if( ct->ptr.p_int[i]>0 ) + { + ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + else + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + state->nic = state->nic+1; + } + } + + /* + * Normalize rows of State.CLEIC: each row must have unit norm. + * Norm is calculated using first N elements (i.e. right part is + * not counted when we calculate norm). + */ + for(i=0; i<=k-1; i++) + { + v = (double)(0); + for(j=0; j<=n-1; j++) + { + v = v+ae_sqr(state->cleic.ptr.pp_double[i][j], _state); + } + if( ae_fp_eq(v,(double)(0)) ) + { + continue; + } + v = (double)1/ae_sqrt(v, _state); + ae_v_muld(&state->cleic.ptr.pp_double[i][0], 1, ae_v_len(0,n), v); + } + sassetlc(&state->sas, c, ct, k, _state); +} + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBLEICSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetcond(minbleicstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinBLEICSetCond: EpsG is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinBLEICSetCond: negative EpsG", _state); + ae_assert(ae_isfinite(epsf, _state), "MinBLEICSetCond: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinBLEICSetCond: negative EpsF", _state); + ae_assert(ae_isfinite(epsx, _state), "MinBLEICSetCond: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinBLEICSetCond: negative EpsX", _state); + ae_assert(maxits>=0, "MinBLEICSetCond: negative MaxIts!", _state); + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsg = epsg; + state->epsf = epsf; + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets scaling coefficients for BLEIC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BLEIC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBLEICSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetscale(minbleicstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->nmain, "MinBLEICSetScale: Length(S)nmain-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinBLEICSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinBLEICSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } + sassetscale(&state->sas, s, _state); +} + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdefault(minbleicstate* state, ae_state *_state) +{ + + + state->prectype = 0; +} + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdiag(minbleicstate* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(d->cnt>=state->nmain, "MinBLEICSetPrecDiag: D is too short", _state); + for(i=0; i<=state->nmain-1; i++) + { + ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinBLEICSetPrecDiag: D contains infinite or NAN elements", _state); + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinBLEICSetPrecDiag: D contains non-positive elements", _state); + } + rvectorsetlengthatleast(&state->diagh, state->nmain, _state); + state->prectype = 2; + for(i=0; i<=state->nmain-1; i++) + { + state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; + } +} + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBLEICSetScale() +call (before or after MinBLEICSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecscale(minbleicstate* state, ae_state *_state) +{ + + + state->prectype = 3; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBLEICOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetxrep(minbleicstate* state, + ae_bool needxrep, + ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function turns on/off line search reports. +These reports are described in more details in developer-only comments on +MinBLEICState object. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedDRep- whether line search reports are needed or not + +This function is intended for private use only. Turning it on artificially +may cause program failure. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetdrep(minbleicstate* state, + ae_bool needdrep, + ae_state *_state) +{ + + + state->drep = needdrep; +} + + +/************************************************************************* +This function sets maximum step length + +IMPORTANT: this feature is hard to combine with preconditioning. You can't +set upper limit on step length, when you solve optimization problem with +linear (non-boundary) constraints AND preconditioner turned on. + +When non-boundary constraints are present, you have to either a) use +preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! +In this case algorithm will terminate with appropriate error code. + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetstpmax(minbleicstate* state, + double stpmax, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinBLEICSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinBLEICSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() + for numerical differentiation) you should choose appropriate variant of + MinBLEICOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinBLEICOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinBLEICOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinBLEICOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinBLEICCreateF() | work FAIL + MinBLEICCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinBLEICOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinBLEICCreateF() + and to pass gradient information to MinBLEICOptimize()) will lead to + exception being thrown. Either you did not pass gradient when it WAS + needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool minbleiciteration(minbleicstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double v0; + ae_bool b; + ae_int_t mcinfo; + ae_int_t actstatus; + ae_int_t itidx; + double penalty; + double ginit; + double gdecay; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + j = state->rstate.ia.ptr.p_int[3]; + mcinfo = state->rstate.ia.ptr.p_int[4]; + actstatus = state->rstate.ia.ptr.p_int[5]; + itidx = state->rstate.ia.ptr.p_int[6]; + b = state->rstate.ba.ptr.p_bool[0]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + v0 = state->rstate.ra.ptr.p_double[2]; + penalty = state->rstate.ra.ptr.p_double[3]; + ginit = state->rstate.ra.ptr.p_double[4]; + gdecay = state->rstate.ra.ptr.p_double[5]; + } + else + { + n = 359; + m = -58; + i = -919; + j = -909; + mcinfo = 81; + actstatus = 255; + itidx = 74; + b = ae_false; + v = 809.0; + vv = 205.0; + v0 = -838.0; + penalty = 939.0; + ginit = -526.0; + gdecay = 763.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + if( state->rstate.stage==20 ) + { + goto lbl_20; + } + if( state->rstate.stage==21 ) + { + goto lbl_21; + } + + /* + * Routine body + */ + + /* + * Algorithm parameters: + * * M number of L-BFGS corrections. + * This coefficient remains fixed during iterations. + * * GDecay desired decrease of constrained gradient during L-BFGS iterations. + * This coefficient is decreased after each L-BFGS round until + * it reaches minimum decay. + */ + m = ae_minint(5, state->nmain, _state); + gdecay = minbleic_initialdecay; + + /* + * Init + */ + n = state->nmain; + state->steepestdescentstep = ae_false; + state->userterminationneeded = ae_false; + state->repterminationtype = 0; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repnfev = 0; + state->repvaridx = -1; + state->repdebugeqerr = 0.0; + state->repdebugfs = _state->v_nan; + state->repdebugff = _state->v_nan; + state->repdebugdx = _state->v_nan; + if( ae_fp_neq(state->stpmax,(double)(0))&&state->prectype!=0 ) + { + state->repterminationtype = -10; + result = ae_false; + return result; + } + rmatrixsetlengthatleast(&state->bufyk, m+1, n, _state); + rmatrixsetlengthatleast(&state->bufsk, m+1, n, _state); + rvectorsetlengthatleast(&state->bufrho, m, _state); + rvectorsetlengthatleast(&state->buftheta, m, _state); + rvectorsetlengthatleast(&state->tmp0, n, _state); + smoothnessmonitorinit(&state->smonitor, &state->s, n, 1, state->smoothnessguardlevel>0, _state); + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + state->invs.ptr.p_double[i] = (double)1/state->s.ptr.p_double[i]; + } + + /* + * Check analytic derivative + */ + minbleic_clearrequestfields(state, _state); + if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_22; + } +lbl_24: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xstart, &state->s, &state->bndl, &state->bndu, ae_true, state->teststep, _state) ) + { + goto lbl_25; + } + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->smonitor.x.ptr.p_double[i]; + } + state->needfg = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfg = ae_false; + state->smonitor.fi.ptr.p_double[0] = state->f; + for(i=0; i<=n-1; i++) + { + state->smonitor.j.ptr.pp_double[0][i] = state->g.ptr.p_double[i]; + } + goto lbl_24; +lbl_25: +lbl_22: + + /* + * Fill TmpPrec with current preconditioner + */ + rvectorsetlengthatleast(&state->tmpprec, n, _state); + for(i=0; i<=n-1; i++) + { + if( state->prectype==2 ) + { + state->tmpprec.ptr.p_double[i] = state->diagh.ptr.p_double[i]; + continue; + } + if( state->prectype==3 ) + { + state->tmpprec.ptr.p_double[i] = (double)1/ae_sqr(state->s.ptr.p_double[i], _state); + continue; + } + state->tmpprec.ptr.p_double[i] = (double)(1); + } + sassetprecdiag(&state->sas, &state->tmpprec, _state); + + /* + * Start optimization + */ + if( !sasstartoptimization(&state->sas, &state->xstart, _state) ) + { + state->repterminationtype = -3; + result = ae_false; + return result; + } + + /* + * Main cycle of BLEIC-PG algorithm + */ + state->repterminationtype = 0; + state->lastgoodstep = (double)(0); + state->lastscaledgoodstep = (double)(0); + state->maxscaledgrad = (double)(0); + state->nonmonotoniccnt = ae_round(1.5*(double)(n+state->nic), _state)+5; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbleic_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_26; + } + state->needfg = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfg = ae_false; + goto lbl_27; +lbl_26: + state->needf = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needf = ae_false; +lbl_27: + state->fc = state->f; + trimprepare(state->f, &state->trimthreshold, _state); + state->repnfev = state->repnfev+1; + if( !state->xrep ) + { + goto lbl_28; + } + + /* + * Report current point + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fc; + state->xupdated = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->xupdated = ae_false; +lbl_28: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + sasstopoptimization(&state->sas, _state); + state->repterminationtype = 8; + result = ae_false; + return result; + } +lbl_30: + if( ae_false ) + { + goto lbl_31; + } + + /* + * Preparations + * + * (a) calculate unconstrained gradient + * (b) determine initial active set + * (c) update MaxScaledGrad + * (d) check F/G for NAN/INF, abnormally terminate algorithm if needed + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbleic_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_32; + } + + /* + * Analytic gradient + */ + state->needfg = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfg = ae_false; + goto lbl_33; +lbl_32: + + /* + * Numerical differentiation + */ + state->needf = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->fbase = state->f; + i = 0; +lbl_34: + if( i>n-1 ) + { + goto lbl_36; + } + v = state->x.ptr.p_double[i]; + b = ae_false; + if( state->hasbndl.ptr.p_bool[i] ) + { + b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); + } + if( b ) + { + goto lbl_37; + } + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->fp2 = state->f; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + goto lbl_38; +lbl_37: + state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; + state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) + { + state->xm1 = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) + { + state->xp1 = state->bndu.ptr.p_double[i]; + } + state->x.ptr.p_double[i] = state->xm1; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->fm1 = state->f; + state->x.ptr.p_double[i] = state->xp1; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->fp1 = state->f; + if( ae_fp_neq(state->xm1,state->xp1) ) + { + state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); + } + else + { + state->g.ptr.p_double[i] = (double)(0); + } +lbl_38: + state->x.ptr.p_double[i] = v; + i = i+1; + goto lbl_34; +lbl_36: + state->f = state->fbase; + state->needf = ae_false; +lbl_33: + state->fc = state->f; + ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + sasreactivateconstraintsprec(&state->sas, &state->ugc, _state); + sasconstraineddirection(&state->sas, &state->cgc, _state); + ginit = 0.0; + for(i=0; i<=n-1; i++) + { + ginit = ginit+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + ginit = ae_sqrt(ginit, _state); + state->maxscaledgrad = ae_maxreal(state->maxscaledgrad, ginit, _state); + if( !ae_isfinite(ginit, _state)||!ae_isfinite(state->fc, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + sasstopoptimization(&state->sas, _state); + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + sasstopoptimization(&state->sas, _state); + state->repterminationtype = 8; + result = ae_false; + return result; + } + + /* + * LBFGS stage: + * * during LBFGS iterations we activate new constraints, but never + * deactivate already active ones. + * * we perform at most N iterations of LBFGS before re-evaluating + * active set and restarting LBFGS. + * * first iteration of LBFGS is a special - it is performed with + * minimum set of active constraints, algorithm termination can + * be performed only at this state. We call this iteration + * "steepest descent step". + * + * About termination: + * * LBFGS iterations can be terminated because of two reasons: + * * "termination" - non-zero termination code in RepTerminationType, + * which means that optimization is done + * * "restart" - zero RepTerminationType, which means that we + * have to re-evaluate active set and resume LBFGS stage. + * * one more option is "refresh" - to continue LBFGS iterations, + * but with all BFGS updates (Sk/Yk pairs) being dropped; + * it happens after changes in active set + */ + state->bufsize = 0; + state->steepestdescentstep = ae_true; + itidx = -1; +lbl_39: + if( itidx>=n-1 ) + { + goto lbl_40; + } + + /* + * Increment iterations counter + * + * NOTE: we have strong reasons to use such complex scheme + * instead of just for() loop - this counter may be + * decreased at some occasions to perform "restart" + * of an iteration. + */ + itidx = itidx+1; + + /* + * At the beginning of each iteration: + * * SAS.XC stores current point + * * FC stores current function value + * * UGC stores current unconstrained gradient + * * CGC stores current constrained gradient + * * D stores constrained step direction (calculated at this block) + * + * + * Check gradient-based stopping criteria + * + * This stopping condition is tested only for step which is the + * first step of LBFGS (subsequent steps may accumulate active + * constraints thus they should NOT be used for stopping - gradient + * may be small when constrained, but these constraints may be + * deactivated by the subsequent steps) + */ + if( state->steepestdescentstep&&ae_fp_less_eq(sasscaledconstrainednorm(&state->sas, &state->ugc, _state),state->epsg) ) + { + + /* + * Gradient is small enough. + * Optimization is terminated + */ + state->repterminationtype = 4; + goto lbl_40; + } + + /* + * 1. Calculate search direction D according to L-BFGS algorithm + * using constrained preconditioner to perform inner multiplication. + * 2. Evaluate scaled length of direction D; restart LBFGS if D is zero + * (it may be possible that we found minimum, but it is also possible + * that some constraints need deactivation) + * 3. If D is non-zero, try to use previous scaled step length as initial estimate for new step. + */ + ae_v_move(&state->work.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=state->bufsize-1; i>=0; i--) + { + v = ae_v_dotproduct(&state->bufsk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->buftheta.ptr.p_double[i] = v; + vv = v*state->bufrho.ptr.p_double[i]; + ae_v_subd(&state->work.ptr.p_double[0], 1, &state->bufyk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); + } + sasconstraineddirectionprec(&state->sas, &state->work, _state); + for(i=0; i<=state->bufsize-1; i++) + { + v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vv = state->bufrho.ptr.p_double[i]*(-v+state->buftheta.ptr.p_double[i]); + ae_v_addd(&state->work.ptr.p_double[0], 1, &state->bufsk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); + } + sasconstraineddirection(&state->sas, &state->work, _state); + ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + if( ae_fp_eq(v,(double)(0)) ) + { + + /* + * Search direction is zero. + * If we perform "steepest descent step", algorithm is terminated. + * Otherwise we just restart LBFGS. + */ + if( state->steepestdescentstep ) + { + state->repterminationtype = 4; + } + goto lbl_40; + } + ae_assert(ae_fp_greater(v,(double)(0)), "MinBLEIC: internal error", _state); + if( ae_fp_greater(state->lastscaledgoodstep,(double)(0))&&ae_fp_greater(v,(double)(0)) ) + { + state->stp = state->lastscaledgoodstep/v; + } + else + { + state->stp = 1.0/v; + } + + /* + * Calculate bound on step length. + * Step direction is stored + */ + sasexploredirection(&state->sas, &state->d, &state->curstpmax, &state->cidx, &state->cval, _state); + state->activationstep = state->curstpmax; + if( state->cidx>=0&&ae_fp_eq(state->activationstep,(double)(0)) ) + { + + /* + * We are exactly at the boundary, immediate activation + * of constraint is required. LBFGS stage is continued + * with "refreshed" model. + * + * ! IMPORTANT: we do not clear SteepestDescent flag here, + * ! it is very important for correct stopping + * ! of algorithm. + * + * ! IMPORTANT: we decrease iteration counter in order to + * preserve computational budget for iterations. + */ + sasimmediateactivation(&state->sas, state->cidx, state->cval, _state); + state->bufsize = 0; + itidx = itidx-1; + goto lbl_39; + } + if( ae_fp_greater(state->stpmax,(double)(0)) ) + { + v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = ae_sqrt(v, _state); + if( ae_fp_greater(v,(double)(0)) ) + { + state->curstpmax = ae_minreal(state->curstpmax, state->stpmax/v, _state); + } + } + + /* + * Report beginning of line search (if requested by caller). + * See description of the MinBLEICState for more information + * about fields accessible to caller. + * + * Caller may do following: + * * change State.Stp and load better initial estimate of + * the step length. + * Caller may not terminate algorithm. + */ + if( !state->drep ) + { + goto lbl_41; + } + minbleic_clearrequestfields(state, _state); + state->lsstart = ae_true; + state->boundedstep = state->cidx>=0; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->lsstart = ae_false; +lbl_41: + + /* + * Minimize F(x+alpha*d) + */ + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->ugc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fn = state->fc; + state->mcstage = 0; + smoothnessmonitorstartlinesearch1u(&state->smonitor, &state->s, &state->invs, &state->xn, state->fn, &state->ugn, state->repinneriterationscount, -1, _state); + mcsrch(n, &state->xn, &state->fn, &state->ugn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_43: + if( state->mcstage==0 ) + { + goto lbl_44; + } + + /* + * Perform correction (constraints are enforced) + * Copy XN to X + */ + sascorrection(&state->sas, &state->xn, &penalty, _state); + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; + } + + /* + * Gradient, either user-provided or numerical differentiation + */ + minbleic_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_45; + } + + /* + * Analytic gradient + */ + state->needfg = ae_true; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->needfg = ae_false; + state->repnfev = state->repnfev+1; + goto lbl_46; +lbl_45: + + /* + * Numerical differentiation + */ + state->needf = ae_true; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->fbase = state->f; + i = 0; +lbl_47: + if( i>n-1 ) + { + goto lbl_49; + } + v = state->x.ptr.p_double[i]; + b = ae_false; + if( state->hasbndl.ptr.p_bool[i] ) + { + b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); + } + if( b ) + { + goto lbl_50; + } + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + state->fp2 = state->f; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + state->repnfev = state->repnfev+4; + goto lbl_51; +lbl_50: + state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; + state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) + { + state->xm1 = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) + { + state->xp1 = state->bndu.ptr.p_double[i]; + } + state->x.ptr.p_double[i] = state->xm1; + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + state->fm1 = state->f; + state->x.ptr.p_double[i] = state->xp1; + state->rstate.stage = 20; + goto lbl_rcomm; +lbl_20: + state->fp1 = state->f; + if( ae_fp_neq(state->xm1,state->xp1) ) + { + state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); + } + else + { + state->g.ptr.p_double[i] = (double)(0); + } + state->repnfev = state->repnfev+2; +lbl_51: + state->x.ptr.p_double[i] = v; + i = i+1; + goto lbl_47; +lbl_49: + state->f = state->fbase; + state->needf = ae_false; +lbl_46: + + /* + * Back to MCSRCH + * + * NOTE: penalty term from correction is added to FN in order + * to penalize increase in infeasibility. + */ + smoothnessmonitorenqueuepoint1u(&state->smonitor, &state->s, &state->invs, &state->d, state->stp, &state->x, state->f, &state->g, _state); + state->fn = state->f+minbleic_penaltyfactor*state->maxscaledgrad*penalty; + ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + sasconstraineddirection(&state->sas, &state->cgn, _state); + trimfunction(&state->fn, &state->cgn, n, state->trimthreshold, _state); + mcsrch(n, &state->xn, &state->fn, &state->ugn, &state->d, &state->stp, state->curstpmax, minbleic_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_43; +lbl_44: + ae_v_moveneg(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_moveneg(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_add(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_add(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + smoothnessmonitorfinalizelinesearch(&state->smonitor, _state); + + /* + * Check for presence of NAN/INF in function/gradient + */ + v = state->fn; + for(i=0; i<=n-1; i++) + { + v = 0.1*v+state->ugn.ptr.p_double[i]; + } + if( !ae_isfinite(v, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + goto lbl_40; + } + + /* + * Handle possible failure of the line search or request for termination + */ + if( mcinfo!=1&&mcinfo!=5 ) + { + + /* + * We can not find step which decreases function value. We have + * two possibilities: + * (a) numerical properties of the function do not allow us to + * find good step. + * (b) we are close to activation of some constraint, and it is + * so close that step which activates it leads to change in + * target function which is smaller than numerical noise. + * + * Optimization algorithm must be able to handle case (b), because + * inability to handle it will cause failure when algorithm + * started very close to boundary of the feasible area. + * + * In order to correctly handle such cases we allow limited amount + * of small steps which increase function value. + */ + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->d.ptr.p_double[i]*state->curstpmax/state->s.ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + b = ae_false; + if( (state->cidx>=0&&ae_fp_less_eq(v,minbleic_maxnonmonotoniclen))&&state->nonmonotoniccnt>0 ) + { + + /* + * We try to enforce non-monotonic step: + * * Stp := CurStpMax + * * MCINFO := 5 + * * XN := XC+CurStpMax*D + * * non-monotonic counter is decreased + * + * NOTE: UGN/CGN are not updated because step is so short that we assume that + * GN is approximately equal to GC. + * + * NOTE: prior to enforcing such step we check that it does not increase infeasibility + * of constraints beyond tolerable level + */ + v = state->curstpmax; + ae_v_move(&state->tmp0.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->tmp0.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->stp = state->curstpmax; + mcinfo = 5; + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->tmp0.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->nonmonotoniccnt = state->nonmonotoniccnt-1; + b = ae_true; + } + if( !b ) + { + + /* + * Numerical properties of the function do not allow + * us to solve problem. Here we have two possibilities: + * * if it is "steepest descent" step, we can terminate + * algorithm because we are close to minimum + * * if it is NOT "steepest descent" step, we should restart + * LBFGS iterations. + */ + if( state->steepestdescentstep ) + { + + /* + * Algorithm is terminated + */ + state->repterminationtype = 7; + goto lbl_40; + } + else + { + + /* + * Re-evaluate active set and restart LBFGS + */ + goto lbl_40; + } + } + } + if( state->userterminationneeded ) + { + goto lbl_40; + } + + /* + * Current point is updated: + * * move XC/FC/GC to XP/FP/GP + * * change current point remembered by SAS structure + * * move XN/FN/GN to XC/FC/GC + * * report current point and update iterations counter + * * if MCINFO=1, push new pair SK/YK to LBFGS buffer + */ + state->fp = state->fc; + ae_v_move(&state->xp.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fc = state->fn; + ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->ugn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + actstatus = sasmoveto(&state->sas, &state->xn, state->cidx>=0&&ae_fp_greater_eq(state->stp,state->activationstep), state->cidx, state->cval, _state); + if( !state->xrep ) + { + goto lbl_52; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbleic_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 21; + goto lbl_rcomm; +lbl_21: + state->xupdated = ae_false; +lbl_52: + state->repinneriterationscount = state->repinneriterationscount+1; + if( mcinfo==1 ) + { + + /* + * Accept new LBFGS update given by Sk,Yk + */ + if( state->bufsize==m ) + { + + /* + * Buffer is full, shift contents by one row + */ + for(i=0; i<=state->bufsize-1; i++) + { + ae_v_move(&state->bufsk.ptr.pp_double[i][0], 1, &state->bufsk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->bufyk.ptr.pp_double[i][0], 1, &state->bufyk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); + } + for(i=0; i<=state->bufsize-2; i++) + { + state->bufrho.ptr.p_double[i] = state->bufrho.ptr.p_double[i+1]; + state->buftheta.ptr.p_double[i] = state->buftheta.ptr.p_double[i+1]; + } + } + else + { + + /* + * Buffer is not full, increase buffer size by 1 + */ + state->bufsize = state->bufsize+1; + } + v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufsk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); + vv = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); + if( ae_fp_eq(v,(double)(0))||ae_fp_eq(vv,(double)(0)) ) + { + + /* + * Strange internal error in LBFGS - either YK=0 + * (which should not have been) or (SK,YK)=0 (again, + * unexpected). It should not take place because + * MCINFO=1, which signals "good" step. But just + * to be sure we have special branch of code which + * restarts LBFGS + */ + goto lbl_40; + } + state->bufrho.ptr.p_double[state->bufsize-1] = (double)1/v; + ae_assert(state->bufsize<=m, "MinBLEIC: internal error", _state); + + /* + * Update length of the good step + */ + v = (double)(0); + vv = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); + vv = vv+ae_sqr(state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i], _state); + } + state->lastgoodstep = ae_sqrt(vv, _state); + minbleic_updateestimateofgoodstep(&state->lastscaledgoodstep, ae_sqrt(v, _state), _state); + } + + /* + * Check stopping criteria + * + * Step size and function-based stopping criteria are tested only + * for step which satisfies Wolfe conditions and is the first step of + * LBFGS (subsequent steps may accumulate active constraints thus + * they should NOT be used for stopping; step size or function change + * may be small when constrained, but these constraints may be + * deactivated by the subsequent steps). + * + * MaxIts-based stopping condition is checked for all kinds of steps. + */ + if( mcinfo==1&&state->steepestdescentstep ) + { + + /* + * Step is small enough + */ + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr((state->sas.xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + if( ae_fp_less_eq(v,state->epsx) ) + { + state->repterminationtype = 2; + goto lbl_40; + } + + /* + * Function change is small enough + */ + if( ae_fp_less_eq(ae_fabs(state->fp-state->fc, _state),state->epsf*ae_maxreal(ae_fabs(state->fc, _state), ae_maxreal(ae_fabs(state->fp, _state), 1.0, _state), _state)) ) + { + state->repterminationtype = 1; + goto lbl_40; + } + } + if( state->maxits>0&&state->repinneriterationscount>=state->maxits ) + { + state->repterminationtype = 5; + goto lbl_40; + } + + /* + * Clear "steepest descent" flag. + */ + state->steepestdescentstep = ae_false; + + /* + * Smooth reset (LBFGS memory model is refreshed) or hard restart: + * * LBFGS model is refreshed, if line search was performed with activation of constraints + * * algorithm is restarted if scaled gradient decreased below GDecay + */ + if( actstatus>=0 ) + { + state->bufsize = 0; + goto lbl_39; + } + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( ae_fp_less(ae_sqrt(v, _state),gdecay*ginit) ) + { + goto lbl_40; + } + goto lbl_39; +lbl_40: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + goto lbl_31; + } + if( state->repterminationtype!=0 ) + { + + /* + * Algorithm terminated + */ + goto lbl_31; + } + + /* + * Decrease decay coefficient. Subsequent L-BFGS stages will + * have more stringent stopping criteria. + */ + gdecay = ae_maxreal(gdecay*minbleic_decaycorrection, minbleic_mindecay, _state); + goto lbl_30; +lbl_31: + sasstopoptimization(&state->sas, _state); + state->repouteriterationscount = 1; + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ia.ptr.p_int[3] = j; + state->rstate.ia.ptr.p_int[4] = mcinfo; + state->rstate.ia.ptr.p_int[5] = actstatus; + state->rstate.ia.ptr.p_int[6] = itidx; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + state->rstate.ra.ptr.p_double[2] = v0; + state->rstate.ra.ptr.p_double[3] = penalty; + state->rstate.ra.ptr.p_double[4] = ginit; + state->rstate.ra.ptr.p_double[5] = gdecay; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbleicoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbleicsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardgradient(minbleicstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinBLEICOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinBLEICOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardsmoothness(minbleicstate* state, + ae_int_t level, + ae_state *_state) +{ + + + ae_assert(level==0||level==1, "MinBLEICOptGuardSmoothness: unexpected value of level parameter", _state); + state->smoothnessguardlevel = level; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbleicoptguardgradient() for gradient verification +* minbleicoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbleicoptguardnonc1test0results() +* minbleicoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardresults(minbleicstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test0results(const minbleicstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test0report_clear(strrep); + _optguardnonc1test0report_clear(lngrep); + + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test1results(minbleicstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test1report_clear(strrep); + _optguardnonc1test1report_clear(lngrep); + + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +BLEIC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. Feasible point is + either nonexistent or too hard to find. Try to + restart optimizer with better initial approximation + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbleicrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBLEICReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresults(const minbleicstate* state, + /* Real */ ae_vector* x, + minbleicreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minbleicreport_clear(rep); + + minbleicresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +BLEIC results + +Buffered implementation of MinBLEICResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresultsbuf(const minbleicstate* state, + /* Real */ ae_vector* x, + minbleicreport* rep, + ae_state *_state) +{ + ae_int_t i; + + + if( x->cntnmain ) + { + ae_vector_set_length(x, state->nmain, _state); + } + rep->iterationscount = state->repinneriterationscount; + rep->inneriterationscount = state->repinneriterationscount; + rep->outeriterationscount = state->repouteriterationscount; + rep->nfev = state->repnfev; + rep->varidx = state->repvaridx; + rep->terminationtype = state->repterminationtype; + if( state->repterminationtype>0 ) + { + ae_v_move(&x->ptr.p_double[0], 1, &state->sas.xc.ptr.p_double[0], 1, ae_v_len(0,state->nmain-1)); + } + else + { + for(i=0; i<=state->nmain-1; i++) + { + x->ptr.p_double[i] = _state->v_nan; + } + } + rep->debugeqerr = state->repdebugeqerr; + rep->debugfs = state->repdebugfs; + rep->debugff = state->repdebugff; + rep->debugdx = state->repdebugdx; + rep->debugfeasqpits = state->repdebugfeasqpits; + rep->debugfeasgpaits = state->repdebugfeasgpaits; +} + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicrestartfrom(minbleicstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->nmain; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MinBLEICRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; + minbleic_clearrequestfields(state, _state); + sasstopoptimization(&state->sas, _state); +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicrequesttermination(minbleicstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +This subroutine finalizes internal structures after emergency termination +from State.LSStart report (see comments on MinBLEICState for more information). + +INPUT PARAMETERS: + State - structure after exit from LSStart report + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicemergencytermination(minbleicstate* state, ae_state *_state) +{ + + + sasstopoptimization(&state->sas, _state); +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minbleicsetprotocolv1(minbleicstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void minbleic_clearrequestfields(minbleicstate* state, + ae_state *_state) +{ + + + state->needf = ae_false; + state->needfg = ae_false; + state->xupdated = ae_false; + state->lsstart = ae_false; +} + + +/************************************************************************* +Internal initialization subroutine +*************************************************************************/ +static void minbleic_minbleicinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbleicstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + + /* + * Initialize + */ + state->protocolversion = 1; + state->teststep = (double)(0); + state->smoothnessguardlevel = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + state->nmain = n; + state->diffstep = diffstep; + sasinit(n, &state->sas, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->hasbndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->hasbndu, n, _state); + ae_vector_set_length(&state->xstart, n, _state); + ae_vector_set_length(&state->cgc, n, _state); + ae_vector_set_length(&state->ugc, n, _state); + ae_vector_set_length(&state->xn, n, _state); + ae_vector_set_length(&state->cgn, n, _state); + ae_vector_set_length(&state->ugn, n, _state); + ae_vector_set_length(&state->xp, n, _state); + ae_vector_set_length(&state->d, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->invs, n, _state); + ae_vector_set_length(&state->lastscaleused, n, _state); + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->g, n, _state); + ae_vector_set_length(&state->work, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->invs.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + } + minbleicsetlc(state, &c, &ct, 0, _state); + minbleicsetcond(state, 0.0, 0.0, 0.0, 0, _state); + minbleicsetxrep(state, ae_false, _state); + minbleicsetdrep(state, ae_false, _state); + minbleicsetstpmax(state, 0.0, _state); + minbleicsetprecdefault(state, _state); + minbleicrestartfrom(state, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine updates estimate of the good step length given: +1) previous estimate +2) new length of the good step + +It makes sure that estimate does not change too rapidly - ratio of new and +old estimates will be at least 0.01, at most 100.0 + +In case previous estimate of good step is zero (no estimate), new estimate +is used unconditionally. + + -- ALGLIB -- + Copyright 16.01.2013 by Bochkanov Sergey +*************************************************************************/ +static void minbleic_updateestimateofgoodstep(double* estimate, + double newstep, + ae_state *_state) +{ + + + if( ae_fp_eq(*estimate,(double)(0)) ) + { + *estimate = newstep; + return; + } + if( ae_fp_less(newstep,*estimate*0.01) ) + { + *estimate = *estimate*0.01; + return; + } + if( ae_fp_greater(newstep,*estimate*(double)100) ) + { + *estimate = *estimate*(double)100; + return; + } + *estimate = newstep; +} + + +void _minbleicstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minbleicstate *p = (minbleicstate*)_p; + ae_touch_ptr((void*)p); + _sactiveset_init(&p->sas, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->ugc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ugn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + _snnlssolver_init(&p->solver, _state, make_automatic); + ae_vector_init(&p->tmpprec, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); + ae_matrix_init(&p->bufyk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bufsk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufrho, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->buftheta, 0, DT_REAL, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invs, 0, DT_REAL, _state, make_automatic); +} + + +void _minbleicstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minbleicstate *dst = (minbleicstate*)_dst; + const minbleicstate *src = (const minbleicstate*)_src; + dst->nmain = src->nmain; + dst->nslack = src->nslack; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->drep = src->drep; + dst->stpmax = src->stpmax; + dst->diffstep = src->diffstep; + _sactiveset_init_copy(&dst->sas, &src->sas, _state, make_automatic); + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->prectype = src->prectype; + ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic); + dst->protocolversion = src->protocolversion; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->xupdated = src->xupdated; + dst->lsstart = src->lsstart; + dst->steepestdescentstep = src->steepestdescentstep; + dst->boundedstep = src->boundedstep; + dst->userterminationneeded = src->userterminationneeded; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->ugc, &src->ugc, _state, make_automatic); + ae_vector_init_copy(&dst->cgc, &src->cgc, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->ugn, &src->ugn, _state, make_automatic); + ae_vector_init_copy(&dst->cgn, &src->cgn, _state, make_automatic); + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + dst->fc = src->fc; + dst->fn = src->fn; + dst->fp = src->fp; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + dst->lastgoodstep = src->lastgoodstep; + dst->lastscaledgoodstep = src->lastscaledgoodstep; + dst->maxscaledgrad = src->maxscaledgrad; + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repvaridx = src->repvaridx; + dst->repterminationtype = src->repterminationtype; + dst->repdebugeqerr = src->repdebugeqerr; + dst->repdebugfs = src->repdebugfs; + dst->repdebugff = src->repdebugff; + dst->repdebugdx = src->repdebugdx; + dst->repdebugfeasqpits = src->repdebugfeasqpits; + dst->repdebugfeasgpaits = src->repdebugfeasgpaits; + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + _snnlssolver_init_copy(&dst->solver, &src->solver, _state, make_automatic); + dst->fbase = src->fbase; + dst->fm2 = src->fm2; + dst->fm1 = src->fm1; + dst->fp1 = src->fp1; + dst->fp2 = src->fp2; + dst->xm1 = src->xm1; + dst->xp1 = src->xp1; + dst->gm1 = src->gm1; + dst->gp1 = src->gp1; + dst->cidx = src->cidx; + dst->cval = src->cval; + ae_vector_init_copy(&dst->tmpprec, &src->tmpprec, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + dst->nfev = src->nfev; + dst->mcstage = src->mcstage; + dst->stp = src->stp; + dst->curstpmax = src->curstpmax; + dst->activationstep = src->activationstep; + ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic); + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->trimthreshold = src->trimthreshold; + dst->nonmonotoniccnt = src->nonmonotoniccnt; + ae_matrix_init_copy(&dst->bufyk, &src->bufyk, _state, make_automatic); + ae_matrix_init_copy(&dst->bufsk, &src->bufsk, _state, make_automatic); + ae_vector_init_copy(&dst->bufrho, &src->bufrho, _state, make_automatic); + ae_vector_init_copy(&dst->buftheta, &src->buftheta, _state, make_automatic); + dst->bufsize = src->bufsize; + dst->teststep = src->teststep; + dst->smoothnessguardlevel = src->smoothnessguardlevel; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); + ae_vector_init_copy(&dst->invs, &src->invs, _state, make_automatic); +} + + +void _minbleicstate_clear(void* _p) +{ + minbleicstate *p = (minbleicstate*)_p; + ae_touch_ptr((void*)p); + _sactiveset_clear(&p->sas); + ae_vector_clear(&p->s); + ae_vector_clear(&p->diagh); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->ugc); + ae_vector_clear(&p->cgc); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->ugn); + ae_vector_clear(&p->cgn); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->d); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->xstart); + _snnlssolver_clear(&p->solver); + ae_vector_clear(&p->tmpprec); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->work); + _linminstate_clear(&p->lstate); + ae_matrix_clear(&p->bufyk); + ae_matrix_clear(&p->bufsk); + ae_vector_clear(&p->bufrho); + ae_vector_clear(&p->buftheta); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); + ae_vector_clear(&p->invs); +} + + +void _minbleicstate_destroy(void* _p) +{ + minbleicstate *p = (minbleicstate*)_p; + ae_touch_ptr((void*)p); + _sactiveset_destroy(&p->sas); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->diagh); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->ugc); + ae_vector_destroy(&p->cgc); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->ugn); + ae_vector_destroy(&p->cgn); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->d); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->xstart); + _snnlssolver_destroy(&p->solver); + ae_vector_destroy(&p->tmpprec); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->work); + _linminstate_destroy(&p->lstate); + ae_matrix_destroy(&p->bufyk); + ae_matrix_destroy(&p->bufsk); + ae_vector_destroy(&p->bufrho); + ae_vector_destroy(&p->buftheta); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); + ae_vector_destroy(&p->invs); +} + + +void _minbleicreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minbleicreport *p = (minbleicreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minbleicreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minbleicreport *dst = (minbleicreport*)_dst; + const minbleicreport *src = (const minbleicreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->varidx = src->varidx; + dst->terminationtype = src->terminationtype; + dst->debugeqerr = src->debugeqerr; + dst->debugfs = src->debugfs; + dst->debugff = src->debugff; + dst->debugdx = src->debugdx; + dst->debugfeasqpits = src->debugfeasqpits; + dst->debugfeasgpaits = src->debugfeasgpaits; + dst->inneriterationscount = src->inneriterationscount; + dst->outeriterationscount = src->outeriterationscount; +} + + +void _minbleicreport_clear(void* _p) +{ + minbleicreport *p = (minbleicreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minbleicreport_destroy(void* _p) +{ + minbleicreport *p = (minbleicreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + NONLINEARLY CONSTRAINED OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to the +any combination of the: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +USAGE: + +Here we give the very brief outline of the MinNLC optimizer. We strongly +recommend you to study examples in the ALGLIB Reference Manual and to read +ALGLIB User Guide: https://www.alglib.net/nonlinear-programming/ + +1. The user initializes the solver with minnlccreate() or minnlccreatef(), + depending on the specific solver chosen: + * minnlccreate() for solvers capable of handling the problem 'as is', + without relying on numerical differentiation (SQP/GIPM2 for problems + with analytic derivatives, ORBIT for derivative-free problems) + * minnlccreatef(), when a numerical differentiation is used to provide + derivatives to a smooth derivative-based solver (SQP or GIPM2). + + In the current release the following solvers can be used: + + * sparse large-scale filter-based SQP solver, recommended for problems + of any size (from several variables to hundreds of thousands of + variables). Good at warm-starts. Activated with the minnlcsetalgosqp() + function. + + * sparse large-scale nonlinear nonconvex interior point method (GIPM2), + recommended for problems of any size (from several variables to + hundreds of thousands of variables). Has lower iteration overhead + than SQP, but is worse at using good initial points (it will need + at least tens of iterations even when started from the solution). + Activated with minnlcsetalgogipm2() function. + + * dense SQP-BFGS solver, recommended for small-scale problems (up to + several hundreds of variables). Requires less function evaluations + than SQP, but has more expensive iteration. + Activated with minnlcsetalgosqpbfgs() function. + + * ORBIT, a model-based derivative free solver that uses local RBF + models to optimize expensive objectives. This solver is activated + with minnlcsetalgoorbit() function. + + * several other solvers, including legacy ones + +2. [optional] user activates OptGuard integrity checker which tries to + detect possible errors in the user-supplied callbacks: + * discontinuity/nonsmoothness of the target/nonlinear constraints + * errors in the analytic gradient provided by user + This feature is essential for early prototyping stages because it helps + to catch common coding and problem statement errors. + OptGuard can be activated with following functions (one per each check + performed): + * minnlcoptguardsmoothness() + * minnlcoptguardgradient() + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minnlcsetbc() for boundary constraints + b) minnlcsetlc2() for sparse two-sided linear constraints, + minnlcsetlc2dense() for dense two-sided linear constraints, + minnlcsetlc2mixed() for mixed sparse/dense two-sided linear constraints + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + c) minnlcsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minnlcsetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + Knowing variable scales helps to check stopping criteria and + precondition the solver. + +5. User sets stopping conditions with minnlcsetcond3() or minnlcsetcond(). + If NLC solver uses inner/outer iteration layout, this function sets + stopping conditions for INNER iterations. + +6. Finally, user calls minnlcoptimize() function which takes algorithm + state and pointer (delegate, etc.) to callback function which calculates + F/G/H. + +7. User calls minnlcresults() to get solution; additionally you can + retrieve OptGuard report with minnlcoptguardresults(), and get detailed + report about purported errors in the target function with: + * minnlcoptguardnonc1test0results() + * minnlcoptguardnonc1test1results() + +8. Optionally user may call minnlcrestartfrom() to solve another problem + with same N but another starting point. minnlcrestartfrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minnlcstate* state, + ae_state *_state) +{ + + _minnlcstate_clear(state); + + ae_assert(n>=1, "MinNLCCreate: N<1", _state); + ae_assert(x->cnt>=n, "MinNLCCreate: Length(X)=1, "MinNLCCreateBuf: N<1", _state); + ae_assert(x->cnt>=n, "MinNLCCreateBuf: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, >0. + By default, a 5-point formula is used (actually, only 4 + function values per variable are used because the central + one has zero coefficient due to symmetry; that's why this + formula is often called a 4-point one). It can be changed + with minnlcsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTES: + +1. the differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinNLCSetScale() call. + +2. we recommend you to use moderate values of differentiation step. Too + large step will result in too large TRUNCATION errors, while too small + step will result in too large NUMERICAL errors. 1.0E-4 can be good + value to start from. + +3. Numerical differentiation is very inefficient - one gradient + calculation needs ~N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems or near the + solution. + + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnlcstate* state, + ae_state *_state) +{ + + _minnlcstate_clear(state); + + ae_assert(n>=1, "MinNLCCreateF: N<1", _state); + ae_assert(x->cnt>=n, "MinNLCCreateF: Length(X)=1, "MinNLCCreateFBuf: N<1", _state); + ae_assert(x->cnt>=n, "MinNLCCreateFBuf: Length(X)n; + ae_assert(bndl->cnt>=n, "MinNLCSetBC: Length(BndL)cnt>=n, "MinNLCSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinNLCSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinNLCSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets linear constraints for MinNLC optimizer. + +Linear constraints are inactive by default (after initial creation). They +are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine linear constraints with boundary ones - and with nonlinear +ones! If your problem has mixed constraints, you may explicitly specify +some of them as linear. It may help optimizer to handle them more +efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: when you solve your problem with augmented Lagrangian solver, + linear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc(minnlcstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + + + ae_assert(k>=0, "MinNLCSetLC: K<0", _state); + ae_assert(c->cols>=state->n+1||k==0, "MinNLCSetLC: Cols(C)rows>=k, "MinNLCSetLC: Rows(C)cnt>=k, "MinNLCSetLC: Length(CT)n+1, _state), "MinNLCSetLC: C contains infinite or NaN values!", _state); + xlcsetlcmixed(&state->xlc, &state->tmps1, ct, 0, c, ct, k, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2dense(minnlcstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, &state->tmps1, 0, a, k, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2(minnlcstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, a, k, &state->tmpj1, 0, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2mixed(minnlcstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state) +{ + + + xlcsetlc2mixed(&state->xlc, sparsea, ksparse, densea, kdense, al, au, _state); +} + + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2dense(minnlcstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2dense(&state->xlc, a, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2(minnlcstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2(&state->xlc, idxa, vala, nnz, al, au, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2sparsefromdense(minnlcstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state) +{ + + + xlcaddlc2sparsefromdense(&state->xlc, da, al, au, _state); +} + + +/************************************************************************* +This function sets nonlinear constraints for MinNLC optimizer. + +It sets constraints of the form + + Ci(x)=0 for i=0..NLEC-1 + Ci(x)<=0 for i=NLEC..NLEC+NLIC-1 + +See MinNLCSetNLC2() for a modern function which allows greater flexibility +in the constraint specification. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc(minnlcstate* state, + ae_int_t nlec, + ae_int_t nlic, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nlec>=0, "MinNLCSetNLC: NLEC<0", _state); + ae_assert(nlic>=0, "MinNLCSetNLC: NLIC<0", _state); + state->nnlc = nlec+nlic; + rallocv(state->nnlc, &state->nl, _state); + rallocv(state->nnlc, &state->nu, _state); + for(i=0; i<=nlec-1; i++) + { + state->nl.ptr.p_double[i] = (double)(0); + state->nu.ptr.p_double[i] = (double)(0); + } + for(i=nlec; i<=nlec+nlic-1; i++) + { + state->nl.ptr.p_double[i] = _state->v_neginf; + state->nu.ptr.p_double[i] = (double)(0); + } +} + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinNLC optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinNLCOptimize() method as callbacks. + +MinNLCOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinNLCSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinNLCSetScale() function). + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc2(minnlcstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nnlc>=0, "MinNLCSetNLC2: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "MinNLCSetNLC2: Length(NL)cnt>=nnlc, "MinNLCSetNLC2: Length(NU)nnlc = nnlc; + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "MinNLCSetNLC2: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "MinNLCSetNLC2: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minnlccreatef() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreateF call. + FormulaType - formula type: + * 5 for a 5-point formula (actually, only 4 values per + variable are used, ones at x+h, x+h/2, x-h/2 and + x-h; the central one has zero multiplier due to + symmetry). The most precise and the most expensive + option, chosen by default + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good compromise for medium-accuracy + setups + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnumdiff(minnlcstate* state, + ae_int_t formulatype, + ae_state *_state) +{ + + + ae_assert((formulatype==2||formulatype==3)||formulatype==5, "MinNLCSetNumDiff: unexpected formula type", _state); + state->formulatype = formulatype; +} + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set iterations limit and step-based stopping +conditions. If you want the solver to stop upon having a small change in +the target, use minnlcsetcond3() function. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond(minnlcstate* state, + double eps, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(eps, _state), "MinNLCSetCond: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinNLCSetCond: negative Eps", _state); + ae_assert(maxits>=0, "MinNLCSetCond: negative MaxIts!", _state); + critsetcondv1(&state->criteria, 0.0, eps, maxits, _state); +} + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set three types of stopping conditions: +* iterations limit +* stopping upon performing a short step (depending on the specific solver + being used it may stop as soon as the first short step was made, or + only after performing several sequential short steps) +* stopping upon having a small change in the target (depending on the + specific solver being used it may stop as soon as the first step with + small change in the target was made, or only after performing several + sequential steps) + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The optimizer will stop as soon as the following condition + is met: + + |f_scl(k+1)-f_scl(k)| <= max(|f_scl(k+1)|,|f_scl(k)|,1) + + where f_scl is an internally used by the optimizer rescaled + target (ALGLIB optimizers usually apply rescaling in order + to normalize target and constraints). + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF, EpsX=0 and MaxIts=0 (simultaneously) will lead to the +automatic selection of the stopping condition. + + -- ALGLIB -- + Copyright 21.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond3(minnlcstate* state, + double epsf, + double eps, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "MinNLCSetCond3: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinNLCSetCond3: negative EpsF", _state); + ae_assert(ae_isfinite(eps, _state), "MinNLCSetCond3: Eps is not finite number", _state); + ae_assert(ae_fp_greater_eq(eps,(double)(0)), "MinNLCSetCond3: negative Eps", _state); + ae_assert(maxits>=0, "MinNLCSetCond3: negative MaxIts!", _state); + critsetcondv1(&state->criteria, epsf, eps, maxits, _state); +} + + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scales +are also used by the finite difference variant of the optimizer - the step +along I-th axis is equal to DiffStep*S[I]. Finally, variable scales are +used for preconditioning (i.e. to speed up the solver). + +The scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetscale(minnlcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinNLCSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinNLCSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinNLCSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets maximum step length (after scaling of step vector with +respect to variable scales specified by minnlcsetscale() call). + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: different solvers employed by MinNLC optimizer may use different + norms for the step. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetstpmax(minnlcstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinNLCSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinNLCSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +This function tells MinNLC unit to use the large-scale augmented Lagrangian +algorithm for nonlinearly constrained optimization. + +This algorithm is a significant refactoring of one described in "A +Modified Barrier-Augmented Lagrangian Method for Constrained Minimization +(1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH with the +following additions: +* improved sparsity support +* improved handling of large-scale problems with the low rank LBFGS-based + sparse preconditioner +* automatic selection of the penalty parameter Rho + +AUL solver can be significantly faster than SQP on easy problems due to +cheaper iterations, although it needs more function evaluations. On large- +scale sparse problems one iteration of the AUL solver usually costs tens +times less than one iteration of the SQP solver. + +However, the SQP solver is more robust than the AUL. In particular, it is +much better at constraint enforcement and will never escape feasible area +after constraints were successfully enforced. It also needs much less +target function evaluations. + +INPUT PARAMETERS: + State - structure which stores algorithm state + MaxOuterIts-upper limit on outer iterations count: + * MaxOuterIts=0 means that the solver will automatically + choose an upper limit. Recommended value. + * MaxOuterIts>1 means that the AUL solver will performs at + most specified number of outer iterations + + -- ALGLIB -- + Copyright 22.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoaul2(minnlcstate* state, + ae_int_t maxouterits, + ae_state *_state) +{ + + + ae_assert(maxouterits>=0, "MinNLCSetAlgoAUL2: negative MaxOuterIts", _state); + state->aulitscnt = maxouterits; + state->solvertype = 0; +} + + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the sparse l-BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. +> + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qp(minnlcstate* state, ae_state *_state) +{ + + + state->solvertype = 2; +} + + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the dense BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qpbfgs(minnlcstate* state, ae_state *_state) +{ + + + state->solvertype = 3; +} + + +/************************************************************************* +This function selects large-scale sparse filter-based SQP solver, the +most robust solver in ALGLIB, a recommended option. + +This algorithm is scalable to problems with millions of variables and can +efficiently handle sparsity of constraints. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqp(minnlcstate* state, ae_state *_state) +{ + + + state->solvertype = 4; +} + + +/************************************************************************* +This function selects ORBIT solver, a model-based derivative-free solver +for minimization of expensive derivative-free functions. + +The ORBIT algorithm by Wild and Shoemaker (2013) is an algorithm that uses +objective function values to build a smooth RBF model (f=r^3) that is +minimized over a trust region in order to identify step direction. The +algorithm saves and reuses function values at all previously known points. + +ALGLIB added to the original algorithm the following modifications: +* box, linear and nonlinear constraints +* improved tolerance to noise in the objective/constraints + +Its intended area of application is a low-accuracy minimization of +expensive objectives with no gradient available. It is expected that +additional overhead of building and minimizing an RBF model is negligible +when compared with the objective evaluation cost. Iteration overhead grows +as O(N^3), so this solver is recommended for problems with N below 100. + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear and nonlinear constraints are enforced, the algorithm will + try to respect them as much as possible. + +When compared with SQP solver, ORBIT: +* is much faster than the finite-difference based serial SQP at early + stages of optimization, being able to achieve 0.1-0.01 relative accuracy + about 4x-10x faster than SQP solver +* has slower asymptotic convergence on ill-conditioned problems, sometimes + being unable to reduce error in objective or constraints below 1E-5 in + a reasonable amount of time +* has no obvious benefits over SQP with analytic gradient or highly + parallelized (more than 10 cores) finite-difference SQP + +NOTE: whilst technically this algorithm supports callback parallelism, in + practice it can't efficiently utilize parallel resources because it + issues requests for objective/constraints in an inherently serial + manner. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Rad0 - initial sampling radius (multiplied by per-variable + scales), Rad0>=0, zero value means automatic radius + selection. + An ideal value is large enough to allow significant + progress by making a Rad0-sized step, but not too large + (so that initial linear model well approximates the + objective). + Recommended values: 0.1 or 1 (assuming properly chosen + variable scales. + The solver can tolerate inappropriately chosen Rad0, at + the expense of additional function evaluations needed to + adjust it. + + MaxNFEV - MaxNFEV>=0, with zero value meaning no limit. This + parameter allows to control computational budget (measured + in function evaluations). + + It provides somewhat finer control than MaxIts parameter + of minnlcsetcond(), which controls the maximum amount of + iterations performed by the algorithm, with one iteration + usually needing more than one function evaluation. + + The solver does not stop immediately after reaching + MaxNFEV evaluations, but will stop shortly after that + (usually within N+1 evaluations, often within 1-2). + + -- ALGLIB -- + Copyright 02.10.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoorbit(minnlcstate* state, + double rad0, + ae_int_t maxnfev, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(rad0, _state), "MinNLCSetAlgoORBIT: Rad0 is INF/NAN", _state); + ae_assert(ae_fp_greater_eq(rad0,(double)(0)), "MinNLCSetAlgoORBIT: Rad0<0", _state); + ae_assert(maxnfev>=0, "MinNLCSetAlgoORBIT: MaxNFEV<0", _state); + state->solvertype = 6; + state->orbitrad0 = rad0; + state->orbitmaxnfev = maxnfev; +} + + +/************************************************************************* +This function selects a SQP solver specialized on low-dimensional problems +- dense filter-based SQP-BFGS solver. + +This algorithm uses a dense quadratic model of the target and solves a +dense QP subproblem at each step. Thus, it has difficulties scaling beyond +several hundreds of variables. However, it usually needs the smallest +number of the target evaluations - sometimes up to 30% less than the +sparse large-scale filter-based SQP. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a well optimized implementation; + however, using a hardware vendor-provided performance library + usually results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqpbfgs(minnlcstate* state, ae_state *_state) +{ + + + state->solvertype = 5; +} + + +/************************************************************************* +This function selects large-scale sparse interior point solver (GIPM2). + +This algorithm is scalable to problems with hundreds of thousands of +variables and can efficiently handle sparsity of constraints. + +When compared to SQP, the following differences can be noted: +* GIPM2 has lower iteration overhead than SQP +* GIPM2 violates all non-box constraints (linear and nonlinear, equality + and inequality ones) until it finally converges. Contrary to that, SQP + respects linear constraints after initial enforcement, and tends to + closely follow nonlinear ones. +* as all interior point methods, GIPM2 is bad at hot starts. Even if + started from solution, it will perform at least 30-60 iterations (first, + it will move away from the solution to find a centered initial point, + then it will converge back along the central path). + +The shorty summary is that SQP wins when starting close to the solution, +and GIPM2 tends to win on large-scale sparse problems where constraint +factorization adds significant linear algebra overhead. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING GIPM2 SOLVER =============================================== + +GIPM2 solver supports advanced tracing capabilities. You can trace +algorithm output by specifying following trace symbols (case-insensitive) +by means of trace_file() call: +* 'GIPM2' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GIPM2,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.02.2025 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgogipm2(minnlcstate* state, ae_state *_state) +{ + + + state->solvertype = 8; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinNLCOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - current point + and penalized function value at current point. Important - function + value which is returned is NOT function being minimized. It is sum + of the value of the function being minimized - and penalty term. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetxrep(minnlcstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* + +CALLBACK PARALLELISM + +The MINNLC optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +NOTES: + +1. This function has two different implementations: + * one which accepts objective/constraints values and their gradients + * and one which accepts only objective/constraints values + + The former function should be called when using solvers relying on + analytic gradients (SQP, GIPM2, etc). The latter one is intended for + derivative-free NLP solvers like ORBIT and, additionally, for numerical + differentiation based versions of SQP/GIPM2/etc. + + Be careful to choose variant of MinNLCOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinNLCOptimize() and specific + function used to create optimizer. + + + | PASSED TO MinNLCOptimize() + | | + PROBLEM SETUP | values only | values + | | and gradients + ----------------------------------------------------------------------- + MinNLCCreate()+SQP/GIPM2/AUL | FAILS + + MinNLCCreate()+ORBIT | + FAILS + MinNLCCreateF()+SQP/GIPM2/AUL | + FAILS + MinNLCCreateF()+ORBIT | FAILS FAILS + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and MinNLCOptimize() version. Any attempts to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 06.05.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool minnlciteration(minnlcstate* state, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t j0; + ae_int_t j1; + ae_int_t jj; + ae_int_t n; + ae_int_t nnlc; + ae_int_t offs; + double vleft; + double vright; + double v; + ae_bool b; + ae_int_t originalrequest; + ae_int_t originalquerysize; + ae_bool densejac; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + j = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + j0 = state->rstate.ia.ptr.p_int[3]; + j1 = state->rstate.ia.ptr.p_int[4]; + jj = state->rstate.ia.ptr.p_int[5]; + n = state->rstate.ia.ptr.p_int[6]; + nnlc = state->rstate.ia.ptr.p_int[7]; + offs = state->rstate.ia.ptr.p_int[8]; + originalrequest = state->rstate.ia.ptr.p_int[9]; + originalquerysize = state->rstate.ia.ptr.p_int[10]; + b = state->rstate.ba.ptr.p_bool[0]; + densejac = state->rstate.ba.ptr.p_bool[1]; + vleft = state->rstate.ra.ptr.p_double[0]; + vright = state->rstate.ra.ptr.p_double[1]; + v = state->rstate.ra.ptr.p_double[2]; + } + else + { + i = 359; + j = -58; + k = -919; + j0 = -909; + j1 = 81; + jj = 255; + n = 74; + nnlc = -788; + offs = 809; + originalrequest = 205; + originalquerysize = -838; + b = ae_true; + densejac = ae_false; + vleft = 763.0; + vright = -541.0; + v = -698.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + + /* + * Routine body + */ + + /* + * Init + */ + state->userterminationneeded = ae_false; + state->repf = ae_maxrealnumber; + state->repterminationtype = 0; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repnfev = 0; + state->repdbgphase0its = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repsclfeaserr = 0.0; + rsetallocv(state->n, 0.0, &state->replagbc, _state); + rsetallocv(state->n, 0.0, &state->replagbcnz, _state); + rsetallocv(state->xlc.nsparse+state->xlc.ndense, 0.0, &state->replaglc, _state); + rsetallocv(state->nnlc, 0.0, &state->replagnlc, _state); + n = state->n; + nnlc = state->nnlc; + minnlc_clearrequestfields(state, _state); + ae_assert(state->smoothnessguardlevel==0||state->smoothnessguardlevel==1, "MinNLCIteration: integrity check failed", _state); + b = state->smoothnessguardlevel>0; + b = b||(state->solvertype==0&&(ae_is_trace_enabled("AUL.PROBING")||ae_is_trace_enabled("AUL.PROBINGONFAILURE"))); + b = b||((((state->solvertype==2||state->solvertype==3)||state->solvertype==4)||state->solvertype==5)&&(ae_is_trace_enabled("SQP.PROBING")||ae_is_trace_enabled("SQP.PROBINGONFAILURE"))); + smoothnessmonitorinit(&state->smonitor, &state->s, n, 1+nnlc, b, _state); + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + } + + /* + * Allocate buffers, as mandated by the V2 protocol + */ + if( state->protocolversion==1 ) + { + if( state->fi.cnt!=1+state->nnlc ) + { + ae_vector_set_length(&state->fi, 1+state->nnlc, _state); + } + if( state->j.rows!=1+state->nnlc||state->j.cols!=state->n ) + { + ae_matrix_set_length(&state->j, 1+state->nnlc, state->n, _state); + } + } + if( state->protocolversion==2 ) + { + if( ae_fp_eq(state->diffstep,(double)(0)) ) + { + rallocv(n, &state->querydata, _state); + } + else + { + rallocv(n+2*3*n, &state->querydata, _state); + } + rallocv(1+nnlc, &state->replyfi, _state); + rallocv(1+nnlc, &state->tmpf1, _state); + rallocv(n, &state->tmpg1, _state); + rallocv(n, &state->tmpx1, _state); + } + + /* + * Check correctness of box constraints + */ + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + if( ae_fp_greater(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->repterminationtype = -3; + state->repbcerr = state->bndl.ptr.p_double[i]-state->bndu.ptr.p_double[i]; + state->repbcidx = i; + result = ae_false; + return result; + } + } + } + + /* + * Test gradient + */ + if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_20; + } +lbl_22: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xstart, &state->s, &state->bndl, &state->bndu, ae_true, state->teststep, _state) ) + { + goto lbl_23; + } + if( state->protocolversion!=2 ) + { + goto lbl_24; + } + if( !state->issuesparserequests ) + { + goto lbl_26; + } + state->requesttype = 1; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + rcopyv(n, &state->smonitor.x, &state->querydata, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + ae_assert(sparsegetnrows(&state->replysj, _state)==state->querysize*state->queryfuncs, "MINNLC: integrity check 0106 failed", _state); + ae_assert(sparsegetncols(&state->replysj, _state)==state->queryvars, "MINNLC: integrity check 0107 failed", _state); + for(i=0; i<=nnlc; i++) + { + state->smonitor.fi.ptr.p_double[i] = state->replyfi.ptr.p_double[i]; + rsetr(n, 0.0, &state->smonitor.j, i, _state); + j0 = state->replysj.ridx.ptr.p_int[i]; + j1 = state->replysj.ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->smonitor.j.ptr.pp_double[i][state->replysj.idx.ptr.p_int[jj]] = state->replysj.vals.ptr.p_double[jj]; + } + } + goto lbl_27; +lbl_26: + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + rcopyv(n, &state->smonitor.x, &state->querydata, _state); + rallocv(n*(1+nnlc), &state->replydj, _state); + rallocm(1+nnlc, n, &state->tmpj1, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + for(i=0; i<=nnlc; i++) + { + state->smonitor.fi.ptr.p_double[i] = state->replyfi.ptr.p_double[i]; + for(k=0; k<=n-1; k++) + { + state->smonitor.j.ptr.pp_double[i][k] = state->replydj.ptr.p_double[i*n+k]; + } + } +lbl_27: + goto lbl_25; +lbl_24: + ae_assert(state->protocolversion==1, "MINNLC: integrity check 0748 failed", _state); + ae_assert(!state->issuesparserequests, "MINNLC: integrity check 0749 failed", _state); + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->smonitor.x.ptr.p_double[i]; + } + state->needfij = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfij = ae_false; + for(i=0; i<=nnlc; i++) + { + state->smonitor.fi.ptr.p_double[i] = state->fi.ptr.p_double[i]; + for(k=0; k<=n-1; k++) + { + state->smonitor.j.ptr.pp_double[i][k] = state->j.ptr.pp_double[i][k]; + } + } +lbl_25: + goto lbl_22; +lbl_23: +lbl_20: + + /* + * Initialization phase + */ + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + rvectorsetlengthatleast(&state->xbase, n, _state); + rvectorsetlengthatleast(&state->fbase, 1+nnlc, _state); + rvectorsetlengthatleast(&state->fm2, 1+nnlc, _state); + rvectorsetlengthatleast(&state->fm1, 1+nnlc, _state); + rvectorsetlengthatleast(&state->fp1, 1+nnlc, _state); + rvectorsetlengthatleast(&state->fp2, 1+nnlc, _state); + } + b = ae_false; + if( state->solvertype==0 ) + { + + /* + * Initialize AUL solver + */ + if( !(state->aulsolverstate!=NULL) ) + { + state->aulsolverstate = (minaulstate*)ae_malloc(sizeof(minaulstate), _state); /* note: using state->aulsolverstate as a temporary prior to assigning its value to _state->aulsolverstate */ + memset(state->aulsolverstate, 0, sizeof(minaulstate)); + _minaulstate_init(state->aulsolverstate, _state, ae_false); + ae_smart_ptr_assign(&state->_aulsolverstate, state->aulsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minaulstate), _minaulstate_init_copy, _minaulstate_destroy); + } + xlcconverttosparse(&state->xlc, _state); + minaulinitbuf(&state->bndl, &state->bndu, &state->s, &state->xstart, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->nl, &state->nu, nnlc, &state->criteria, state->aulitscnt, state->aulsolverstate, _state); + b = ae_true; + } + if( state->solvertype==2||state->solvertype==3 ) + { + + /* + * Initialize SQP solver + */ + if( !(state->sqpsolverstate!=NULL) ) + { + state->sqpsolverstate = (minsqpstate*)ae_malloc(sizeof(minsqpstate), _state); /* note: using state->sqpsolverstate as a temporary prior to assigning its value to _state->sqpsolverstate */ + memset(state->sqpsolverstate, 0, sizeof(minsqpstate)); + _minsqpstate_init(state->sqpsolverstate, _state, ae_false); + ae_smart_ptr_assign(&state->_sqpsolverstate, state->sqpsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minsqpstate), _minsqpstate_init_copy, _minsqpstate_destroy); + } + xlcconverttoold(&state->xlc, _state); + converttwosidednlctoonesidedold(&state->nl, &state->nu, nnlc, &state->nlcidx, &state->nlcmul, &state->nlcadd, &state->nlcnlec, &state->nlcnlic, _state); + minsqpinitbuf(&state->bndl, &state->bndu, &state->s, &state->xstart, n, &state->xlc.cleic, &state->xlc.lcsrcidx, state->xlc.nec, state->xlc.nic, state->nlcnlec, state->nlcnlic, &state->criteria, state->solvertype==3, state->sqpsolverstate, _state); + b = ae_true; + } + if( state->solvertype==4||state->solvertype==5 ) + { + + /* + * Initialize FSQP solver + */ + if( !(state->fsqpsolverstate!=NULL) ) + { + state->fsqpsolverstate = (minfsqpstate*)ae_malloc(sizeof(minfsqpstate), _state); /* note: using state->fsqpsolverstate as a temporary prior to assigning its value to _state->fsqpsolverstate */ + memset(state->fsqpsolverstate, 0, sizeof(minfsqpstate)); + _minfsqpstate_init(state->fsqpsolverstate, _state, ae_false); + ae_smart_ptr_assign(&state->_fsqpsolverstate, state->fsqpsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minfsqpstate), _minfsqpstate_init_copy, _minfsqpstate_destroy); + } + xlcconverttosparse(&state->xlc, _state); + minfsqpinitbuf(&state->bndl, &state->bndu, &state->s, &state->xstart, n, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->nl, &state->nu, nnlc, &state->criteria, state->solvertype==5, state->fsqpsolverstate, _state); + if( state->fsqpadditsforctol>0 ) + { + minfsqpsetadditsforctol(state->fsqpsolverstate, state->fsqpadditsforctol, state->fsqpctol, _state); + } + b = ae_true; + } + if( state->solvertype!=6 ) + { + goto lbl_28; + } + + /* + * Initialize ORBIT solver. + * + * Remove fixed variables (most derivative-free solvers do not allow fixed variables + * because it overcomplicates geometry improvement code). + */ + if( !(state->orbitsolver!=NULL) ) + { + state->orbitsolver = (dfgmstate*)ae_malloc(sizeof(dfgmstate), _state); /* note: using state->orbitsolver as a temporary prior to assigning its value to _state->orbitsolver */ + memset(state->orbitsolver, 0, sizeof(dfgmstate)); + _dfgmstate_init(state->orbitsolver, _state, ae_false); + ae_smart_ptr_assign(&state->_orbitsolver, state->orbitsolver, ae_true, ae_true, (ae_int_t)sizeof(dfgmstate), _dfgmstate_init_copy, _dfgmstate_destroy); + } + iallocv(n, &state->idxraw2red, _state); + rallocv(n, &state->redbl, _state); + rallocv(n, &state->redbu, _state); + rallocv(n, &state->reds, _state); + rallocv(n, &state->redx0, _state); + state->nreduced = 0; + for(i=0; i<=n-1; i++) + { + if( ae_isfinite(state->bndl.ptr.p_double[i], _state)&&ae_isfinite(state->bndu.ptr.p_double[i], _state) ) + { + if( ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->idxraw2red.ptr.p_int[i] = -1; + continue; + } + } + state->redx0.ptr.p_double[state->nreduced] = state->xstart.ptr.p_double[i]; + state->reds.ptr.p_double[state->nreduced] = state->s.ptr.p_double[i]; + state->redbl.ptr.p_double[state->nreduced] = state->bndl.ptr.p_double[i]; + state->redbu.ptr.p_double[state->nreduced] = state->bndu.ptr.p_double[i]; + state->idxraw2red.ptr.p_int[i] = state->nreduced; + state->nreduced = state->nreduced+1; + } + if( state->nreduced!=0 ) + { + goto lbl_30; + } + + /* + * All variables are fixed, quick exit + */ + state->repbcerr = 0.0; + state->repbcidx = -1; + state->replcerr = 0.0; + state->replcidx = -1; + if( state->xlc.nsparse+state->xlc.ndense>0 ) + { + xlcconverttosparse(&state->xlc, _state); + checklc2violation(&state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->bndl, &state->replcerr, &state->replcidx, _state); + } + if( state->protocolversion!=2 ) + { + goto lbl_32; + } + rallocv(1+nnlc, &state->replyfi, _state); + rcopyallocv(n, &state->bndl, &state->querydata, _state); + state->requesttype = 4; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + goto lbl_33; +lbl_32: + ae_assert(state->protocolversion==1, "MINNLC: integrity check 849631 failed", _state); + rcopyv(n, &state->bndl, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfi = ae_false; + rcopyallocv(1+nnlc, &state->fi, &state->replyfi, _state); +lbl_33: + state->repf = state->replyfi.ptr.p_double[0]; + checknlc2violation(&state->replyfi, &state->nl, &state->nu, nnlc, &state->repnlcerr, &state->repnlcidx, _state); + state->repsclfeaserr = rmaxabs3(state->repbcerr, state->replcerr, state->repnlcerr, _state); + rsetv(n, 0.0, &state->replagbc, _state); + rsetv(n, 0.0, &state->replagbcnz, _state); + rsetv(state->xlc.nsparse+state->xlc.ndense, 0.0, &state->replaglc, _state); + rsetv(nnlc, 0.0, &state->replagnlc, _state); + state->repterminationtype = 2; + rcopyv(n, &state->bndl, &state->xc, _state); + result = ae_false; + return result; +lbl_30: + if( state->xlc.nsparse+state->xlc.ndense>0 ) + { + xlcconverttosparse(&state->xlc, _state); + iallocv(state->xlc.nsparse+state->xlc.ndense+1, &state->tmpi, _state); + state->tmpi.ptr.p_int[0] = 0; + for(i=0; i<=state->xlc.nsparse+state->xlc.ndense-1; i++) + { + k = state->tmpi.ptr.p_int[i]; + v = 0.0; + for(j=state->xlc.effsparsea.ridx.ptr.p_int[i]; j<=state->xlc.effsparsea.ridx.ptr.p_int[i+1]-1; j++) + { + if( state->idxraw2red.ptr.p_int[state->xlc.effsparsea.idx.ptr.p_int[j]]<0 ) + { + v = v+state->bndl.ptr.p_double[state->xlc.effsparsea.idx.ptr.p_int[j]]*state->xlc.effsparsea.vals.ptr.p_double[j]; + continue; + } + state->xlc.effsparsea.idx.ptr.p_int[k] = state->idxraw2red.ptr.p_int[state->xlc.effsparsea.idx.ptr.p_int[j]]; + state->xlc.effsparsea.vals.ptr.p_double[k] = state->xlc.effsparsea.vals.ptr.p_double[j]; + k = k+1; + } + if( ae_isfinite(state->xlc.effal.ptr.p_double[i], _state) ) + { + state->xlc.effal.ptr.p_double[i] = state->xlc.effal.ptr.p_double[i]-v; + } + if( ae_isfinite(state->xlc.effau.ptr.p_double[i], _state) ) + { + state->xlc.effau.ptr.p_double[i] = state->xlc.effau.ptr.p_double[i]-v; + } + state->tmpi.ptr.p_int[i+1] = k; + } + icopyv(state->xlc.nsparse+state->xlc.ndense+1, &state->tmpi, &state->xlc.effsparsea.ridx, _state); + state->xlc.effsparsea.ninitialized = state->xlc.effsparsea.ridx.ptr.p_int[state->xlc.nsparse+state->xlc.ndense]; + sparseinitduidx(&state->xlc.effsparsea, _state); + state->xlc.effsparsea.n = state->nreduced; + } + dfgminitbuf(&state->redbl, &state->redbu, &state->reds, &state->redx0, state->nreduced, 1, ae_false, 2, &state->criteria, 0, state->orbitrad0, state->orbitmaxnfev, state->orbitsolver, _state); + dfgmsetlc2(state->orbitsolver, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, state->xlc.nsparse+state->xlc.ndense, _state); + dfgmsetnlc2(state->orbitsolver, &state->nl, &state->nu, nnlc, _state); + b = ae_true; +lbl_28: + if( state->solvertype==7||state->solvertype==8 ) + { + + /* + * Initialize GIPM2 solver + */ + if( !(state->gipm2solver!=NULL) ) + { + state->gipm2solver = (nlpgipm2state*)ae_malloc(sizeof(nlpgipm2state), _state); /* note: using state->gipm2solver as a temporary prior to assigning its value to _state->gipm2solver */ + memset(state->gipm2solver, 0, sizeof(nlpgipm2state)); + _nlpgipm2state_init(state->gipm2solver, _state, ae_false); + ae_smart_ptr_assign(&state->_gipm2solver, state->gipm2solver, ae_true, ae_true, (ae_int_t)sizeof(nlpgipm2state), _nlpgipm2state_init_copy, _nlpgipm2state_destroy); + } + xlcconverttosparse(&state->xlc, _state); + nlpgipm2initbuf(&state->bndl, &state->bndu, &state->s, &state->xstart, n, &state->criteria, state->solvertype==5, state->gipm2solver, _state); + nlpgipm2setlinearconstraints(state->gipm2solver, &state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, _state); + nlpgipm2setnonlinearconstraints(state->gipm2solver, &state->nl, &state->nu, state->nnlc, _state); + b = ae_true; + } + ae_assert(b, "MINNLC: integrity check 7046 failed", _state); + + /* + * Iteration phase + */ +lbl_34: + if( ae_false ) + { + goto lbl_35; + } + + /* + * Run iteration function and load evaluation point + */ + minnlc_clearrequestfields(state, _state); + originalrequest = 0; + originalquerysize = 0; + densejac = ae_true; + b = ae_false; + if( state->solvertype==0 ) + { + + /* + * AUL solver + */ + if( !minauliteration(state->aulsolverstate, &state->smonitor, state->userterminationneeded, _state) ) + { + goto lbl_35; + } + if( state->aulsolverstate->needsj ) + { + + /* + * Request dense analytic Jacobian + */ + if( state->protocolversion==2 ) + { + minnlc_unscale(state, &state->aulsolverstate->x, &state->aulsolverstate->scaledbndl, &state->aulsolverstate->scaledbndu, &state->querydata, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 0312 failed", _state); + minnlc_unscale(state, &state->aulsolverstate->x, &state->aulsolverstate->scaledbndl, &state->aulsolverstate->scaledbndu, &state->x, _state); + } + originalrequest = 2; + originalquerysize = 1; + b = ae_true; + } + if( state->aulsolverstate->xupdated ) + { + if( state->protocolversion==2 ) + { + rallocv(n, &state->reportx, _state); + minnlc_unscale(state, &state->aulsolverstate->x, &state->aulsolverstate->scaledbndl, &state->aulsolverstate->scaledbndu, &state->reportx, _state); + state->reportf = state->aulsolverstate->f; + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 0941 failed", _state); + minnlc_unscale(state, &state->aulsolverstate->x, &state->aulsolverstate->scaledbndl, &state->aulsolverstate->scaledbndu, &state->x, _state); + state->f = state->aulsolverstate->f; + } + state->repf = state->aulsolverstate->f; + originalrequest = -1; + b = ae_true; + } + } + if( state->solvertype==2||state->solvertype==3 ) + { + + /* + * SQP solver + */ + if( !minsqpiteration(state->sqpsolverstate, &state->smonitor, state->userterminationneeded, _state) ) + { + goto lbl_35; + } + if( state->sqpsolverstate->needfij ) + { + if( state->protocolversion==2 ) + { + minnlc_unscale(state, &state->sqpsolverstate->x, &state->sqpsolverstate->scaledbndl, &state->sqpsolverstate->scaledbndu, &state->querydata, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 7919 failed", _state); + minnlc_unscale(state, &state->sqpsolverstate->x, &state->sqpsolverstate->scaledbndl, &state->sqpsolverstate->scaledbndu, &state->x, _state); + } + originalrequest = 2; + originalquerysize = 1; + b = ae_true; + } + if( state->sqpsolverstate->xupdated ) + { + if( state->protocolversion==2 ) + { + rallocv(n, &state->reportx, _state); + minnlc_unscale(state, &state->sqpsolverstate->x, &state->sqpsolverstate->scaledbndl, &state->sqpsolverstate->scaledbndu, &state->reportx, _state); + state->reportf = state->sqpsolverstate->f; + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 9420 failed", _state); + minnlc_unscale(state, &state->sqpsolverstate->x, &state->sqpsolverstate->scaledbndl, &state->sqpsolverstate->scaledbndu, &state->x, _state); + state->f = state->sqpsolverstate->f; + } + state->repf = state->sqpsolverstate->f; + originalrequest = -1; + b = ae_true; + } + } + if( state->solvertype==4||state->solvertype==5 ) + { + + /* + * FSQP solver + */ + if( !minfsqpiteration(state->fsqpsolverstate, &state->smonitor, state->userterminationneeded, _state) ) + { + goto lbl_35; + } + if( state->fsqpsolverstate->needfisj ) + { + if( state->protocolversion==2 ) + { + minnlc_unscale(state, &state->fsqpsolverstate->x, &state->fsqpsolverstate->scaledbndl, &state->fsqpsolverstate->scaledbndu, &state->querydata, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 7919 failed", _state); + minnlc_unscale(state, &state->fsqpsolverstate->x, &state->fsqpsolverstate->scaledbndl, &state->fsqpsolverstate->scaledbndu, &state->x, _state); + } + originalrequest = 2; + originalquerysize = 1; + b = ae_true; + } + if( state->fsqpsolverstate->xupdated ) + { + if( state->protocolversion==2 ) + { + rallocv(n, &state->reportx, _state); + minnlc_unscale(state, &state->fsqpsolverstate->x, &state->fsqpsolverstate->scaledbndl, &state->fsqpsolverstate->scaledbndu, &state->reportx, _state); + state->reportf = state->fsqpsolverstate->f; + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 9420 failed", _state); + minnlc_unscale(state, &state->fsqpsolverstate->x, &state->fsqpsolverstate->scaledbndl, &state->fsqpsolverstate->scaledbndu, &state->x, _state); + state->f = state->fsqpsolverstate->f; + } + state->repf = state->fsqpsolverstate->f; + originalrequest = -1; + b = ae_true; + } + } + if( state->solvertype==6 ) + { + + /* + * ORBIT solver + */ + if( !dfgmiteration(state->orbitsolver, state->userterminationneeded, _state) ) + { + goto lbl_35; + } + if( state->orbitsolver->requesttype==4 ) + { + rallocv(state->orbitsolver->querysize*n, &state->batchquerydata, _state); + minnlc_unscalebatch(state, &state->orbitsolver->querydata, state->orbitsolver->querysize, &state->idxraw2red, state->nreduced, &state->orbitsolver->scaledbndl, &state->orbitsolver->scaledbndu, &state->batchquerydata, _state); + originalrequest = 4; + originalquerysize = state->orbitsolver->querysize; + b = ae_true; + } + if( state->orbitsolver->requesttype==-1 ) + { + if( state->protocolversion==2 ) + { + rallocv(n, &state->reportx, _state); + minnlc_unscalebatch(state, &state->orbitsolver->querydata, 1, &state->idxraw2red, state->nreduced, &state->orbitsolver->scaledbndl, &state->orbitsolver->scaledbndu, &state->reportx, _state); + state->reportf = state->orbitsolver->reportf; + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 9420 failed", _state); + minnlc_unscalebatch(state, &state->orbitsolver->querydata, 1, &state->idxraw2red, state->nreduced, &state->orbitsolver->scaledbndl, &state->orbitsolver->scaledbndu, &state->x, _state); + state->f = state->orbitsolver->reportf; + } + state->repf = state->orbitsolver->reportf; + originalrequest = -1; + b = ae_true; + } + } + if( state->solvertype==7||state->solvertype==8 ) + { + + /* + * GIPM2 solver + */ + if( !nlpgipm2iteration(state->gipm2solver, &state->smonitor, state->userterminationneeded, _state) ) + { + goto lbl_35; + } + if( state->gipm2solver->needfisj ) + { + if( state->protocolversion==2 ) + { + minnlc_unscale(state, &state->gipm2solver->x, &state->gipm2solver->scaledbndl, &state->gipm2solver->scaledbndu, &state->querydata, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 368137 failed", _state); + minnlc_unscale(state, &state->gipm2solver->x, &state->gipm2solver->scaledbndl, &state->gipm2solver->scaledbndu, &state->x, _state); + } + originalrequest = 2; + originalquerysize = 1; + b = ae_true; + } + if( state->gipm2solver->xupdated ) + { + if( state->protocolversion==2 ) + { + rallocv(n, &state->reportx, _state); + minnlc_unscale(state, &state->gipm2solver->x, &state->gipm2solver->scaledbndl, &state->gipm2solver->scaledbndu, &state->reportx, _state); + state->reportf = state->gipm2solver->reportf; + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 9420 failed", _state); + minnlc_unscale(state, &state->gipm2solver->x, &state->gipm2solver->scaledbndl, &state->gipm2solver->scaledbndu, &state->x, _state); + state->f = state->gipm2solver->reportf; + } + state->repf = state->gipm2solver->reportf; + originalrequest = -1; + b = ae_true; + } + } + ae_assert(b, "MINNLC: integrity check 1848 failed", _state); + + /* + * Process evaluation request, perform numerical differentiation if necessary, offload results back to the optimizer + */ + b = ae_false; + if( originalrequest!=-1 ) + { + goto lbl_36; + } + + /* + * Report + */ + if( !state->xrep ) + { + goto lbl_38; + } + if( state->protocolversion!=2 ) + { + goto lbl_40; + } + state->requesttype = -1; + state->queryvars = n; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + goto lbl_41; +lbl_40: + ae_assert(state->protocolversion==1, "MINNLC: integrity check 8214 failed", _state); + state->xupdated = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->xupdated = ae_false; +lbl_41: +lbl_38: + b = ae_true; +lbl_36: + if( !(originalrequest==2&&ae_fp_neq(state->diffstep,(double)(0))) ) + { + goto lbl_42; + } + + /* + * Jacobian evaluation with numerical differentiation + */ + ae_assert(originalquerysize==1, "MINNLC: integrity check 023105 failed", _state); + densejac = ae_true; + if( state->protocolversion!=2 ) + { + goto lbl_44; + } + + /* + * Issue V2 request + */ + state->requesttype = 5; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + state->queryformulasize = 2; + rallocv(n*(1+nnlc), &state->replydj, _state); + rallocm(1+nnlc, n, &state->tmpj1, _state); + ae_assert(state->querydata.cnt>=n+state->queryformulasize*3*n, "MINNLC: integrity check 1558 failed", _state); + rcopyv(n, &state->querydata, &state->xbase, _state); + rsetvx(state->queryformulasize*3*n, 0.0, &state->querydata, n, _state); + for(k=0; k<=n-1; k++) + { + vleft = state->xbase.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + vright = state->xbase.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + if( (state->hasbndl.ptr.p_bool[k]&&ae_fp_less(vleft,state->bndl.ptr.p_double[k]))||(state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(vright,state->bndu.ptr.p_double[k])) ) + { + + /* + * A full-step formula violates box constraints, use a reduced one + */ + if( state->hasbndl.ptr.p_bool[k]&&ae_fp_less(vleft,state->bndl.ptr.p_double[k]) ) + { + vleft = state->bndl.ptr.p_double[k]; + } + if( state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(vright,state->bndu.ptr.p_double[k]) ) + { + vright = state->bndu.ptr.p_double[k]; + } + ae_assert(ae_fp_less_eq(vleft,vright), "MinNLC: integrity check failed", _state); + if( ae_fp_eq(vleft,vright) ) + { + + /* + * Fixed variable + */ + continue; + } + if( state->formulatype==3||state->formulatype==5 ) + { + + /* + * 5-point and 3-point differences are converted into a nonsymmetric 2-point one + */ + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+0] = vright; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+1] = vleft; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+2] = (double)1/(vright-vleft); + state->repnfev = state->repnfev+2; + continue; + } + if( state->formulatype==2 ) + { + + /* + * 2-point forward difference is converted into a forward or a backward one (possibly with reduced step). + * The difference with longer step is chosen. + */ + if( ae_fp_greater(vright-state->xbase.ptr.p_double[k],state->xbase.ptr.p_double[k]-vleft) ) + { + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+0] = vright; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+1] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+2] = (double)1/(vright-state->xbase.ptr.p_double[k]); + } + else + { + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+0] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+1] = vleft; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+3+2] = (double)1/(state->xbase.ptr.p_double[k]-vleft); + } + state->repnfev = state->repnfev+1; + continue; + } + ae_assert(ae_false, "MINNLC: integrity check 214202 failed", _state); + } + + /* + * A full-step formula does not violate box constraints. + */ + if( state->formulatype==5 ) + { + + /* + * Use 4-point central formula, converted to a sparsity-friendly representation: + * + * f' = 4/3h*(f(x+0.5h)-f(x-0.5h))-1/6h*(f(x+h)-f(x-h)) + * + * [ ] + * = [ -8*(f(x+0.5h)-f(x-0.5h)) + (f(x+h)-f(x-h)) ]*(-1/6h) + * [ ] + */ + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+0] = state->xbase.ptr.p_double[k]+0.5*state->s.ptr.p_double[k]*state->diffstep; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+1] = state->xbase.ptr.p_double[k]-0.5*state->s.ptr.p_double[k]*state->diffstep; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+2] = (double)(-8); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+0] = vright; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+1] = vleft; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+2] = -(double)1/((double)6*state->diffstep*state->s.ptr.p_double[k]); + state->repnfev = state->repnfev+4; + continue; + } + if( state->formulatype==3 ) + { + + /* + * Use 2-point central formula, converted to a sparsity-friendly representation: + * + * f' = (f(x+h)-f(x-h))/2h + */ + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+0] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+1] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+2] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+0] = vright; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+1] = vleft; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+2] = (double)1/((double)2*state->diffstep*state->s.ptr.p_double[k]); + state->repnfev = state->repnfev+2; + continue; + } + if( state->formulatype==2 ) + { + + /* + * Use forward finite difference formula, converted to a sparsity-friendly representation: + * + * f' = (f(x+h)-f(x))/h + */ + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+0] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+1] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+0*3+2] = (double)(0); + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+0] = vright; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+1] = state->xbase.ptr.p_double[k]; + state->querydata.ptr.p_double[n+state->queryformulasize*3*k+1*3+2] = (double)1/(state->diffstep*state->s.ptr.p_double[k]); + state->repnfev = state->repnfev+1; + continue; + } + ae_assert(ae_false, "MINNLC: integrity check 234316 failed", _state); + } + state->repnfev = state->repnfev+1; + rcopyv(n, &state->xbase, &state->x, _state); + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->needfi = ae_false; + goto lbl_45; +lbl_44: + + /* + * Issue V1 request + */ + ae_assert(state->protocolversion==1, "MINNLC: integrity check 0252 failed", _state); + ae_assert(state->j.rows==1+nnlc&&state->j.cols==n, "MINNLC: integrity check 4236 failed", _state); + rsetallocv(n, 0.0, &state->tmpsptolj, _state); + state->needfi = ae_true; + rcopyv(n, &state->x, &state->xbase, _state); + k = 0; +lbl_46: + if( k>n-1 ) + { + goto lbl_48; + } + vleft = state->xbase.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + vright = state->xbase.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + if( !((state->hasbndl.ptr.p_bool[k]&&vleftbndl.ptr.p_double[k])||(state->hasbndu.ptr.p_bool[k]&&vright>state->bndu.ptr.p_double[k])) ) + { + goto lbl_49; + } + + /* + * 4-point formula violates box constraints, use 2-point uncentered one + */ + if( state->hasbndl.ptr.p_bool[k]&&ae_fp_less(vleft,state->bndl.ptr.p_double[k]) ) + { + vleft = state->bndl.ptr.p_double[k]; + } + if( state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(vright,state->bndu.ptr.p_double[k]) ) + { + vright = state->bndu.ptr.p_double[k]; + } + ae_assert(ae_fp_less_eq(vleft,vright), "MinNLC: integrity check failed", _state); + if( ae_fp_eq(vleft,vright) ) + { + + /* + * Fixed variable + */ + for(i=0; i<=nnlc; i++) + { + state->j.ptr.pp_double[i][k] = (double)(0); + } + goto lbl_47; + } + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = vleft; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + rcopyv(1+nnlc, &state->fi, &state->fm1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = vright; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + rcopyv(1+nnlc, &state->fi, &state->fp1, _state); + for(i=0; i<=nnlc; i++) + { + state->j.ptr.pp_double[i][k] = (state->fp1.ptr.p_double[i]-state->fm1.ptr.p_double[i])/(vright-vleft); + } + state->repnfev = state->repnfev+2; + state->tmpsptolj.ptr.p_double[k] = (double)10*ae_machineepsilon/(vright-vleft); + goto lbl_50; +lbl_49: + + /* + * Use 4-point central formula + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + rcopyv(1+nnlc, &state->fi, &state->fm2, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-0.5*state->s.ptr.p_double[k]*state->diffstep; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + rcopyv(1+nnlc, &state->fi, &state->fm1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+0.5*state->s.ptr.p_double[k]*state->diffstep; + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + rcopyv(1+nnlc, &state->fi, &state->fp1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + rcopyv(1+nnlc, &state->fi, &state->fp2, _state); + for(i=0; i<=nnlc; i++) + { + state->j.ptr.pp_double[i][k] = ((double)8*(state->fp1.ptr.p_double[i]-state->fm1.ptr.p_double[i])-(state->fp2.ptr.p_double[i]-state->fm2.ptr.p_double[i]))/((double)6*state->diffstep*state->s.ptr.p_double[k]); + } + state->repnfev = state->repnfev+4; + state->tmpsptolj.ptr.p_double[k] = ae_fabs((double)10*ae_machineepsilon*(double)4/((double)3*state->diffstep*state->s.ptr.p_double[k]), _state); +lbl_50: +lbl_47: + k = k+1; + goto lbl_46; +lbl_48: + rcopyv(n, &state->xbase, &state->x, _state); + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->needfi = ae_false; + state->repnfev = state->repnfev+1; + + /* + * Sparsify Jacobian by zeroing components whose deviation from zero can be + * explained by numerical rounding errors. + * + * This part is essential for the performance of sparse optimizers which can + * face severe performance breakdown on Jacobians which became dense due to + * numerical rounding errors. + */ + rallocv(1+nnlc, &state->tmpspaf, _state); + for(i=0; i<=nnlc; i++) + { + state->tmpspaf.ptr.p_double[i] = ae_fabs(state->fi.ptr.p_double[i], _state); + } + for(i=0; i<=nnlc; i++) + { + for(j=0; j<=n-1; j++) + { + if( ae_fabs(state->j.ptr.pp_double[i][j], _state)<=state->tmpspaf.ptr.p_double[i]*state->tmpsptolj.ptr.p_double[j] ) + { + state->j.ptr.pp_double[i][j] = (double)(0); + } + } + } +lbl_45: + b = ae_true; +lbl_42: + if( !(originalrequest==2&&ae_fp_eq(state->diffstep,(double)(0))) ) + { + goto lbl_51; + } + + /* + * Analytic Jacobian + */ + ae_assert(originalquerysize==1, "MINNLC: integrity check 198106 failed", _state); + if( !state->issuesparserequests ) + { + goto lbl_53; + } + + /* + * Request sparse Jacobian + */ + densejac = ae_false; + ae_assert(state->protocolversion==2, "MINNLC: integrity check 0559 failed", _state); + state->requesttype = 1; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + state->replysj.m = -1; + state->replysj.n = -1; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + ae_assert(sparsegetnrows(&state->replysj, _state)==state->querysize*state->queryfuncs, "MINNLC: integrity check 1639 failed", _state); + ae_assert(sparsegetncols(&state->replysj, _state)==state->queryvars, "MINNLC: integrity check 1639 failed", _state); + goto lbl_54; +lbl_53: + + /* + * Request dense Jacobian + */ + densejac = ae_true; + if( state->protocolversion!=2 ) + { + goto lbl_55; + } + state->requesttype = 2; + state->querysize = 1; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + rallocv(n*(1+nnlc), &state->replydj, _state); + rallocm(1+nnlc, n, &state->tmpj1, _state); + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + goto lbl_56; +lbl_55: + ae_assert(state->protocolversion==1, "MINNLC: integrity check 8659 failed", _state); + ae_assert(state->j.rows==1+nnlc&&state->j.cols==n, "MINNLC: integrity check 4236 failed", _state); + state->needfij = ae_true; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->needfij = ae_false; +lbl_56: +lbl_54: + state->repnfev = state->repnfev+1; + b = ae_true; +lbl_51: + if( originalrequest!=4 ) + { + goto lbl_57; + } + + /* + * Batch request for gradient-free objective/constraints + */ + rallocv(originalquerysize*(1+nnlc), &state->replyfi, _state); + if( state->protocolversion!=2 ) + { + goto lbl_59; + } + rcopyallocv(n*originalquerysize, &state->batchquerydata, &state->querydata, _state); + state->requesttype = 4; + state->querysize = originalquerysize; + state->queryfuncs = 1+nnlc; + state->queryvars = n; + state->querydim = 0; + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + goto lbl_60; +lbl_59: + ae_assert(state->protocolversion==1, "MINNLC: integrity check 8659 failed", _state); + i = 0; +lbl_61: + if( i>originalquerysize-1 ) + { + goto lbl_63; + } + rcopyvx(n, &state->batchquerydata, i*n, &state->x, 0, _state); + state->needfi = ae_true; + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + state->needfi = ae_false; + rcopyvx(1+nnlc, &state->fi, 0, &state->replyfi, i*(1+nnlc), _state); + i = i+1; + goto lbl_61; +lbl_63: +lbl_60: + state->repnfev = state->repnfev+originalquerysize; + b = ae_true; +lbl_57: + ae_assert(b, "MINNLC: integrity check 6323 failed", _state); + + /* + * Send results back to the optimizer + */ + ae_assert(((originalrequest==-1||originalrequest==1)||originalrequest==2)||originalrequest==4, "MINNLC: integrity check 6336 failed", _state); + b = ae_false; + if( originalrequest==-1 ) + { + + /* + * Do nothing + */ + b = ae_true; + } + if( originalrequest==2 ) + { + if( state->solvertype==0 ) + { + + /* + * AUL solver + */ + ae_assert(state->protocolversion==1||state->protocolversion==2, "MINNLC: integrity check 1435 failed", _state); + if( state->protocolversion==2 ) + { + rcopyv(1+nnlc, &state->replyfi, &state->aulsolverstate->fi, _state); + } + else + { + rcopyv(1+nnlc, &state->fi, &state->aulsolverstate->fi, _state); + } + if( densejac ) + { + + /* + * Convert dense Jacobian to sparse and scale + */ + state->aulsolverstate->sj.matrixtype = 1; + state->aulsolverstate->sj.m = 1+nnlc; + state->aulsolverstate->sj.n = n; + iallocv(state->aulsolverstate->sj.m+1, &state->aulsolverstate->sj.ridx, _state); + state->aulsolverstate->sj.ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=nnlc; i++) + { + igrowv(offs+n, &state->aulsolverstate->sj.idx, _state); + rgrowv(offs+n, &state->aulsolverstate->sj.vals, _state); + if( state->protocolversion==2 ) + { + for(j=0; j<=n-1; j++) + { + if( state->replydj.ptr.p_double[i*n+j]!=0.0 ) + { + state->aulsolverstate->sj.idx.ptr.p_int[offs] = j; + state->aulsolverstate->sj.vals.ptr.p_double[offs] = state->replydj.ptr.p_double[i*n+j]*state->s.ptr.p_double[j]; + offs = offs+1; + } + } + } + else + { + for(j=0; j<=n-1; j++) + { + if( state->j.ptr.pp_double[i][j]!=0.0 ) + { + state->aulsolverstate->sj.idx.ptr.p_int[offs] = j; + state->aulsolverstate->sj.vals.ptr.p_double[offs] = state->j.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; + offs = offs+1; + } + } + } + state->aulsolverstate->sj.ridx.ptr.p_int[i+1] = offs; + } + state->aulsolverstate->sj.ninitialized = offs; + sparseinitduidx(&state->aulsolverstate->sj, _state); + } + else + { + + /* + * Copy sparse Jacobian and scale + */ + sparsecopytocrsbuf(&state->replysj, &state->aulsolverstate->sj, _state); + sparsemultiplycolsby(&state->aulsolverstate->sj, &state->s, _state); + } + b = ae_true; + } + if( state->solvertype==2||state->solvertype==3 ) + { + + /* + * SQP solver + */ + if( state->protocolversion==2 ) + { + state->sqpsolverstate->fi.ptr.p_double[0] = state->replyfi.ptr.p_double[0]; + if( !densejac ) + { + rsetr(n, 0.0, &state->sqpsolverstate->j, 0, _state); + j0 = state->replysj.ridx.ptr.p_int[0]; + j1 = state->replysj.ridx.ptr.p_int[1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sqpsolverstate->j.ptr.pp_double[0][state->replysj.idx.ptr.p_int[jj]] = state->replysj.vals.ptr.p_double[jj]; + } + } + else + { + rcopyvr(n, &state->replydj, &state->sqpsolverstate->j, 0, _state); + } + rmergemulvr(n, &state->s, &state->sqpsolverstate->j, 0, _state); + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->sqpsolverstate->fi.ptr.p_double[i+1] = state->replyfi.ptr.p_double[1+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + k = 1+state->nlcidx.ptr.p_int[i]; + if( !densejac ) + { + rsetr(n, 0.0, &state->sqpsolverstate->j, i+1, _state); + j0 = state->replysj.ridx.ptr.p_int[k]; + j1 = state->replysj.ridx.ptr.p_int[k+1]-1; + for(jj=j0; jj<=j1; jj++) + { + state->sqpsolverstate->j.ptr.pp_double[i+1][state->replysj.idx.ptr.p_int[jj]] = state->replysj.vals.ptr.p_double[jj]; + } + } + else + { + for(j=0; j<=n-1; j++) + { + state->sqpsolverstate->j.ptr.pp_double[i+1][j] = state->replydj.ptr.p_double[k*n+j]; + } + } + rmergemulvr(n, &state->s, &state->sqpsolverstate->j, i+1, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->sqpsolverstate->j, i+1, _state); + } + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 2222 failed", _state); + state->sqpsolverstate->fi.ptr.p_double[0] = state->fi.ptr.p_double[0]; + rcopyrr(n, &state->j, 0, &state->sqpsolverstate->j, 0, _state); + rmergemulvr(n, &state->s, &state->sqpsolverstate->j, 0, _state); + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->sqpsolverstate->fi.ptr.p_double[i+1] = state->fi.ptr.p_double[1+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + rcopyrr(n, &state->j, 1+state->nlcidx.ptr.p_int[i], &state->sqpsolverstate->j, i+1, _state); + rmergemulvr(n, &state->s, &state->sqpsolverstate->j, i+1, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->sqpsolverstate->j, i+1, _state); + } + } + b = ae_true; + } + if( state->solvertype==4||state->solvertype==5 ) + { + + /* + * FSQP solver + */ + if( state->protocolversion==2 ) + { + rcopyv(nnlc+1, &state->replyfi, &state->fsqpsolverstate->fi, _state); + if( densejac ) + { + minnlc_crsfromdensev(&state->replydj, state->nnlc+1, n, &state->fsqpsolverstate->sj, _state); + } + else + { + sparsecopytocrsbuf(&state->replysj, &state->fsqpsolverstate->sj, _state); + } + sparsemultiplycolsby(&state->fsqpsolverstate->sj, &state->s, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 2222 failed", _state); + ae_assert(densejac, "MINNLC: integrity check 2223 failed", _state); + rcopyv(nnlc+1, &state->fi, &state->fsqpsolverstate->fi, _state); + minnlc_crsfromdense(&state->j, state->nnlc+1, n, &state->fsqpsolverstate->sj, _state); + sparsemultiplycolsby(&state->fsqpsolverstate->sj, &state->s, _state); + } + b = ae_true; + } + if( state->solvertype==7||state->solvertype==8 ) + { + + /* + * GIPM2 solver + */ + if( state->protocolversion==2 ) + { + rcopyv(nnlc+1, &state->replyfi, &state->gipm2solver->replyfi, _state); + if( densejac ) + { + minnlc_crsfromdensev(&state->replydj, state->nnlc+1, n, &state->gipm2solver->replysj, _state); + } + else + { + sparsecopytocrsbuf(&state->replysj, &state->gipm2solver->replysj, _state); + } + sparsemultiplycolsby(&state->gipm2solver->replysj, &state->s, _state); + } + else + { + ae_assert(state->protocolversion==1, "MINNLC: integrity check 2222 failed", _state); + ae_assert(densejac, "MINNLC: integrity check 2223 failed", _state); + rcopyv(nnlc+1, &state->fi, &state->gipm2solver->replyfi, _state); + minnlc_crsfromdense(&state->j, state->nnlc+1, n, &state->gipm2solver->replysj, _state); + sparsemultiplycolsby(&state->gipm2solver->replysj, &state->s, _state); + } + b = ae_true; + } + } + if( originalrequest==4 ) + { + if( state->solvertype==6 ) + { + + /* + * ORBIT solver + */ + rcopyv((nnlc+1)*originalquerysize, &state->replyfi, &state->orbitsolver->replyfi, _state); + b = ae_true; + } + } + ae_assert(b, "MINNLC: integrity check 0038 failed", _state); + goto lbl_34; +lbl_35: + + /* + * Results phase + */ + b = ae_false; + if( state->solvertype==0 ) + { + + /* + * AUL results + */ + state->repterminationtype = state->aulsolverstate->repterminationtype; + state->repouteriterationscount = 1; + state->repinneriterationscount = state->aulsolverstate->repiterationscount; + state->repbcerr = state->aulsolverstate->repbcerr; + state->repbcidx = state->aulsolverstate->repbcidx; + state->replcerr = state->aulsolverstate->replcerr; + state->replcidx = state->aulsolverstate->replcidx; + state->repnlcerr = state->aulsolverstate->repnlcerr; + state->repnlcidx = state->aulsolverstate->repnlcidx; + state->repsclfeaserr = rmaxabs3(state->repbcerr, state->replcerr, state->repnlcerr, _state); + minnlc_unscale(state, &state->aulsolverstate->xtruebest.x, &state->aulsolverstate->scaledbndl, &state->aulsolverstate->scaledbndu, &state->xc, _state); + b = ae_true; + } + if( state->solvertype==2||state->solvertype==3 ) + { + state->repterminationtype = state->sqpsolverstate->repterminationtype; + state->repouteriterationscount = state->sqpsolverstate->repiterationscount; + state->repinneriterationscount = state->sqpsolverstate->repiterationscount; + state->repbcerr = state->sqpsolverstate->repbcerr; + state->repbcidx = state->sqpsolverstate->repbcidx; + state->replcerr = state->sqpsolverstate->replcerr; + state->replcidx = state->sqpsolverstate->replcidx; + state->repnlcerr = state->sqpsolverstate->repnlcerr; + state->repnlcidx = state->sqpsolverstate->repnlcidx; + state->repsclfeaserr = rmaxabs3(state->repbcerr, state->replcerr, state->repnlcerr, _state); + minnlc_unscale(state, &state->sqpsolverstate->stepk.x, &state->sqpsolverstate->scaledbndl, &state->sqpsolverstate->scaledbndu, &state->xc, _state); + b = ae_true; + } + if( state->solvertype==4||state->solvertype==5 ) + { + state->repterminationtype = state->fsqpsolverstate->repterminationtype; + state->repouteriterationscount = state->fsqpsolverstate->repiterationscount; + state->repinneriterationscount = state->fsqpsolverstate->repiterationscount; + state->repbcerr = state->fsqpsolverstate->repbcerr; + state->repbcidx = state->fsqpsolverstate->repbcidx; + state->replcerr = state->fsqpsolverstate->replcerr; + state->replcidx = state->fsqpsolverstate->replcidx; + state->repnlcerr = state->fsqpsolverstate->repnlcerr; + state->repnlcidx = state->fsqpsolverstate->repnlcidx; + state->repsclfeaserr = state->fsqpsolverstate->repsclerr; + minnlc_unscale(state, &state->fsqpsolverstate->stepk.x, &state->fsqpsolverstate->scaledbndl, &state->fsqpsolverstate->scaledbndu, &state->xc, _state); + rcopyv(state->n, &state->fsqpsolverstate->replagbc, &state->replagbc, _state); + rcopyv(state->n, &state->fsqpsolverstate->replagbc, &state->replagbcnz, _state); + for(i=0; i<=state->n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&state->bndl.ptr.p_double[i]==state->bndu.ptr.p_double[i] ) + { + state->replagbc.ptr.p_double[i] = 0.0; + if( state->diffstep!=(double)0 ) + { + state->replagbcnz.ptr.p_double[i] = 0.0; + } + } + } + for(i=0; i<=state->xlc.nsparse+state->xlc.ndense-1; i++) + { + state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]] = state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]]+state->fsqpsolverstate->replaglc.ptr.p_double[i]; + } + for(i=0; i<=nnlc-1; i++) + { + state->replagnlc.ptr.p_double[i] = state->fsqpsolverstate->replagnlc.ptr.p_double[i]; + } + b = ae_true; + } + if( state->solvertype==6 ) + { + state->repterminationtype = state->orbitsolver->repterminationtype; + state->repouteriterationscount = state->orbitsolver->repiterationscount; + state->repinneriterationscount = state->orbitsolver->repiterationscount; + state->repbcerr = 0.0; + state->repbcidx = -1; + state->replcerr = 0.0; + state->replcidx = -1; + minnlc_unscalebatch(state, &state->orbitsolver->xk, 1, &state->idxraw2red, state->nreduced, &state->orbitsolver->scaledbndl, &state->orbitsolver->scaledbndu, &state->xc, _state); + if( state->xlc.nsparse+state->xlc.ndense>0 ) + { + xlcconverttosparse(&state->xlc, _state); + checklc2violation(&state->xlc.effsparsea, &state->xlc.effal, &state->xlc.effau, &state->xlc.lcsrcidx, state->xlc.nsparse+state->xlc.ndense, &state->xc, &state->replcerr, &state->replcidx, _state); + } + checknlc2violation(&state->orbitsolver->fkvec, &state->nl, &state->nu, nnlc, &state->repnlcerr, &state->repnlcidx, _state); + state->repsclfeaserr = rmaxabs3(state->repbcerr, state->replcerr, state->repnlcerr, _state); + rsetv(state->n, 0.0, &state->replagbc, _state); + rsetv(state->n, 0.0, &state->replagbcnz, _state); + rsetv(state->xlc.nsparse+state->xlc.ndense, 0.0, &state->replaglc, _state); + rsetv(nnlc, 0.0, &state->replagnlc, _state); + b = ae_true; + } + if( state->solvertype==7||state->solvertype==8 ) + { + state->repterminationtype = state->gipm2solver->repterminationtype; + state->repouteriterationscount = state->gipm2solver->repiterationscount; + state->repinneriterationscount = state->gipm2solver->repiterationscount; + state->repbcerr = state->gipm2solver->repbcerr; + state->repbcidx = state->gipm2solver->repbcidx; + state->replcerr = state->gipm2solver->replcerr; + state->replcidx = state->gipm2solver->replcidx; + state->repnlcerr = state->gipm2solver->repnlcerr; + state->repnlcidx = state->gipm2solver->repnlcidx; + state->repsclfeaserr = state->gipm2solver->repsclerr; + minnlc_unscale(state, &state->gipm2solver->xs, &state->gipm2solver->scaledbndl, &state->gipm2solver->scaledbndu, &state->xc, _state); + rcopyv(state->n, &state->gipm2solver->replagbc, &state->replagbc, _state); + rcopyv(state->n, &state->gipm2solver->replagbc, &state->replagbcnz, _state); + for(i=0; i<=state->n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&state->bndl.ptr.p_double[i]==state->bndu.ptr.p_double[i] ) + { + state->replagbc.ptr.p_double[i] = 0.0; + if( state->diffstep!=(double)0 ) + { + state->replagbcnz.ptr.p_double[i] = 0.0; + } + } + } + for(i=0; i<=state->xlc.nsparse+state->xlc.ndense-1; i++) + { + state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]] = state->replaglc.ptr.p_double[state->xlc.lcsrcidx.ptr.p_int[i]]+state->gipm2solver->replaglc.ptr.p_double[i]; + } + for(i=0; i<=nnlc-1; i++) + { + state->replagnlc.ptr.p_double[i] = state->gipm2solver->replagnlc.ptr.p_double[i]; + } + b = ae_true; + } + ae_assert(b, "MINNLC: integrity check 2219 failed", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = j; + state->rstate.ia.ptr.p_int[2] = k; + state->rstate.ia.ptr.p_int[3] = j0; + state->rstate.ia.ptr.p_int[4] = j1; + state->rstate.ia.ptr.p_int[5] = jj; + state->rstate.ia.ptr.p_int[6] = n; + state->rstate.ia.ptr.p_int[7] = nnlc; + state->rstate.ia.ptr.p_int[8] = offs; + state->rstate.ia.ptr.p_int[9] = originalrequest; + state->rstate.ia.ptr.p_int[10] = originalquerysize; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ba.ptr.p_bool[1] = densejac; + state->rstate.ra.ptr.p_double[0] = vleft; + state->rstate.ra.ptr.p_double[1] = vright; + state->rstate.ra.ptr.p_double[2] = v; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient/Jacobian. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function (constraints) at the +initial point (note: future versions may also perform check at the final +point) and compares numerical gradient/Jacobian with analytic one provided +by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients/Jacobians, and specific components highlighted +as suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minnlcoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minnlcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardgradient(minnlcstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinNLCOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinNLCOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) and/or constraints +b) nonsmooth target function (non-C1) and/or constraints + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + This kind of monitoring does not work well with SQP + because SQP solver needs just 1-2 function evaluations + per step, which is not enough for OptGuard to make + any conclusions. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardsmoothness(minnlcstate* state, + ae_int_t level, + ae_state *_state) +{ + + + ae_assert(level==0||level==1, "MinNLCOptGuardSmoothness: unexpected value of level parameter", _state); + state->smoothnessguardlevel = level; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minnlcoptguardgradient() for gradient verification +* minnlcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation +* rep.nonc0suspected, and additionally: + * rep.nonc0fidx - an index of specific function violating C0 continuity +* rep.nonc1suspected, and additionally + * rep.nonc1fidx - an index of specific function violating C1 continuity +Here function index 0 means target function, index 1 or higher denotes +nonlinear constraints. + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minnlcoptguardnonc1test0results() +* minnlcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardresults(minnlcstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test0results(const minnlcstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test0report_clear(strrep); + _optguardnonc1test0report_clear(lngrep); + + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test1results(minnlcstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test1report_clear(strrep); + _optguardnonc1test1report_clear(lngrep); + + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +MinNLC results: the solution found, completion codes and additional +information. + +If you activated OptGuard integrity checking functionality and want to get +OptGuard report, it can be retrieved with: +* minnlcoptguardresults() - for a primary report about (a) suspected C0/C1 + continuity violations and (b) errors in the analytic gradient. +* minnlcoptguardnonc1test0results() - for C1 continuity violation test #0, + detailed line search log +* minnlcoptguardnonc1test1results() - for C1 continuity violation test #1, + detailed line search log + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + rep.f contains objective value at the solution. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient, recovery was + impossible. Abnormal termination signalled. + * -3 box constraints are infeasible. + Note: infeasibility of non-box constraints does + NOT trigger emergency completion; you have + to examine rep.bcerr/rep.lcerr/rep.nlcerr to + detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 1 small objective decrease indicates convergence + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 7 stopping conditions are too stringent, returning + the best point so far + * 8 user requested algorithm termination via + minnlcrequesttermination(), last accepted point is + returned. + + === ADDITIONAL CODES === + * +800 if during algorithm execution the solver + encountered NAN/INF values in the target or + constraints but managed to recover by reducing + trust region radius, the solver returns one + of SUCCESS codes but adds +800 to the code. + + Some solvers (as of ALGLIB 4.05, SQP and GIPM2) return + Lagrange multipliers in rep.lagbc/lagbcnz, laglc, lagnlc + fields. + + More information about fields of this structure can be + found in the comments on the minnlcreport datatype. + + -- ALGLIB -- + Copyright 18.01.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcresults(const minnlcstate* state, + /* Real */ ae_vector* x, + minnlcreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minnlcreport_clear(rep); + + minnlcresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +NLC results + +Buffered implementation of MinNLCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcresultsbuf(const minnlcstate* state, + /* Real */ ae_vector* x, + minnlcreport* rep, + ae_state *_state) +{ + + + rep->f = state->repf; + rep->iterationscount = state->repinneriterationscount; + rep->nfev = state->repnfev; + rep->terminationtype = state->repterminationtype; + rep->bcerr = state->repbcerr; + rep->bcidx = state->repbcidx; + rep->lcerr = state->replcerr; + rep->lcidx = state->replcidx; + rep->nlcerr = state->repnlcerr; + rep->nlcidx = state->repnlcidx; + rep->sclfeaserr = state->repsclfeaserr; + rep->dbgphase0its = state->repdbgphase0its; + if( state->repterminationtype>0 ) + { + rcopyallocv(state->n, &state->replagbc, &rep->lagbc, _state); + rcopyallocv(state->n, &state->replagbcnz, &rep->lagbcnz, _state); + rcopyallocv(state->xlc.ndense+state->xlc.nsparse, &state->replaglc, &rep->laglc, _state); + rcopyallocv(state->nnlc, &state->replagnlc, &rep->lagnlc, _state); + rcopyallocv(state->n, &state->xc, x, _state); + } + else + { + rsetallocv(state->n, 0.0, &rep->lagbc, _state); + rsetallocv(state->n, 0.0, &rep->lagbcnz, _state); + rsetallocv(state->xlc.nec+state->xlc.nic, 0.0, &rep->laglc, _state); + rsetallocv(state->nnlc, 0.0, &rep->lagnlc, _state); + rsetallocv(state->n, _state->v_nan, x, _state); + } +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcrequesttermination(minnlcstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcrestartfrom(minnlcstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MinNLCRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + minnlc_clearrequestfields(state, _state); +} + + +/************************************************************************* +This function sets the number additional iterations that can be performed +after reaching MaxIts limit, if the current point is infeasible (scaled +constraint violation is above CTol), but there was a feasible point in the +optimization history. + +Up to AddIts iterations will be performed, with iterations being terminated +immediately after reaching CTol level of error. + +Only FSQP solver respects this function. + +INPUT PARAMETERS: + State - solver state + AddIts - additional iterations, zero to turn off + CTol - scaled constraint violation tolerance. Points with + violation below or at CTol are considered feasible + + Do not use zero value because it is likely to + reject points with even a tiny violation of + constraints. + + -- ALGLIB -- + Copyright 05.03.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetfsqpadditsforctol(minnlcstate* state, + ae_int_t addits, + double ctol, + ae_state *_state) +{ + + + state->fsqpadditsforctol = addits; + state->fsqpctol = ctol; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minnlcsetprotocolv1(minnlcstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + state->issuesparserequests = ae_false; + ae_vector_set_length(&state->fi, 1+state->nnlc, _state); + ae_matrix_set_length(&state->j, 1+state->nnlc, state->n, _state); + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol with dense requests +*************************************************************************/ +void minnlcsetprotocolv2(minnlcstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_false; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol with sparse requests +*************************************************************************/ +void minnlcsetprotocolv2s(minnlcstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_true; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void minnlc_clearrequestfields(minnlcstate* state, + ae_state *_state) +{ + + + state->needfi = ae_false; + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void minnlc_minnlcinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnlcstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + state->protocolversion = 1; + state->issuesparserequests = ae_false; + + /* + * Smoothness monitor, default init + */ + state->teststep = (double)(0); + state->smoothnessguardlevel = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + + /* + * Initialize other params + */ + critinitdefault(&state->criteria, _state); + state->n = n; + state->diffstep = diffstep; + state->userterminationneeded = ae_false; + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->hasbndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->hasbndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->lastscaleused, n, _state); + ae_vector_set_length(&state->xstart, n, _state); + ae_vector_set_length(&state->xc, n, _state); + ae_vector_set_length(&state->x, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + state->xstart.ptr.p_double[i] = x->ptr.p_double[i]; + state->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + xlcinit(n, &state->xlc, _state); + minnlcsetnlc(state, 0, 0, _state); + minnlcsetxrep(state, ae_false, _state); + minnlcsetalgosqp(state, _state); + minnlcsetstpmax(state, 0.0, _state); + minnlcsetnumdiff(state, 5, _state); + minnlcrestartfrom(state, x, _state); + + /* + * Default values of solver-specific params + */ + state->fsqpadditsforctol = 0; + state->fsqpctol = (double)(0); + ae_frame_leave(_state); +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones), paying special +attention to box constraints (output is always feasible; active constraints +are mapped to active ones). +*************************************************************************/ +static void minnlc_unscale(const minnlcstate* state, + /* Real */ const ae_vector* xs, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&xs->ptr.p_double[i]<=scaledbndl->ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&xs->ptr.p_double[i]>=scaledbndu->ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + continue; + } + xu->ptr.p_double[i] = xs->ptr.p_double[i]*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&xu->ptr.p_double[i]bndl.ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +Convert dense Jacobian to a sparse matrix without +checks for NAN/INF performed by the similar function from the SPARSE subpackage. +*************************************************************************/ +static void minnlc_crsfromdense(/* Real */ const ae_matrix* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nnz; + ae_int_t offs; + + + ae_assert(m>0, "CreateCRSFromDenseBuf: M<=0", _state); + ae_assert(n>0, "CreateCRSFromDenseBuf: N<=0", _state); + ae_assert(a->rows>=m, "CreateCRSFromDenseBuf: rows(A)cols>=n, "CreateCRSFromDenseBuf: cols(A)ptr.pp_double[i][j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + s->matrixtype = 1; + s->ninitialized = nnz; + s->m = m; + s->n = n; + iallocv(m+1, &s->ridx, _state); + iallocv(nnz, &s->idx, _state); + rallocv(nnz, &s->vals, _state); + s->ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( a->ptr.pp_double[i][j]!=0.0 ) + { + s->idx.ptr.p_int[offs] = j; + s->vals.ptr.p_double[offs] = a->ptr.pp_double[i][j]; + offs = offs+1; + } + } + s->ridx.ptr.p_int[i+1] = offs; + } + ae_assert(offs==nnz, "CreateCRSFromDenseBuf: integrity check 6447 failed", _state); + sparseinitduidx(s, _state); +} + + +/************************************************************************* +Convert dense Jacobian (packed into a vector) to a sparse matrix without +checks for NAN/INF performed by the similar function from the SPARSE subpackage. +*************************************************************************/ +static void minnlc_crsfromdensev(/* Real */ const ae_vector* a, + ae_int_t m, + ae_int_t n, + sparsematrix* s, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t nnz; + ae_int_t offs; + + + ae_assert(m>0, "CreateCRSFromDenseVBuf: M<=0", _state); + ae_assert(n>0, "CreateCRSFromDenseVBuf: N<=0", _state); + ae_assert(a->cnt>=m*n, "CreateCRSFromDenseVBuf: length(A)ptr.p_double[i*n+j]!=0.0 ) + { + nnz = nnz+1; + } + } + } + s->matrixtype = 1; + s->ninitialized = nnz; + s->m = m; + s->n = n; + iallocv(m+1, &s->ridx, _state); + iallocv(nnz, &s->idx, _state); + rallocv(nnz, &s->vals, _state); + s->ridx.ptr.p_int[0] = 0; + offs = 0; + for(i=0; i<=m-1; i++) + { + for(j=0; j<=n-1; j++) + { + if( a->ptr.p_double[i*n+j]!=0.0 ) + { + s->idx.ptr.p_int[offs] = j; + s->vals.ptr.p_double[offs] = a->ptr.p_double[i*n+j]; + offs = offs+1; + } + } + s->ridx.ptr.p_int[i+1] = offs; + } + ae_assert(offs==nnz, "CreateCRSFromDenseVBuf: integrity check 6447 failed", _state); + sparseinitduidx(s, _state); +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones), paying special +attention to box constraints (output is always feasible; active constraints +are mapped to active ones). + +Can handle batch requests. Can handle problems with some variables being +fixed and removed from consideration. + +Parameters: + State solver + XS array[NReduced*BatchSize] - variables after scaling and + removal of fixed vars + idxRaw2Red array[NRaw], maps original variable indexes to ones + after removal of fixed vars. Contains -1 for fixed vars. + scaledBndL, + ScaledBndU array[NReduced], lower/upper bounds after removal of + the fixed vars + +output: + XU array[NRaw*BatchSize], vars after unscaling and + substitution of the fixed vars +*************************************************************************/ +static void minnlc_unscalebatch(const minnlcstate* state, + /* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Integer */ const ae_vector* idxraw2red, + ae_int_t nreduced, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t jr; + ae_int_t nraw; + double vs; + + + nraw = state->n; + if( nreduced==nraw ) + { + + /* + * No fixed vars, simple code + */ + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=nraw-1; j++) + { + i = k*nraw+j; + vs = xs->ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[j]&&vs<=scaledbndl->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + if( state->hasbndu.ptr.p_bool[j]&&vs>=scaledbndu->ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + continue; + } + xu->ptr.p_double[i] = vs*state->s.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j]&&xu->ptr.p_double[i]bndl.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + } + if( state->hasbndu.ptr.p_bool[j]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + } + } + } + } + else + { + + /* + * Some vars are fixed + */ + for(k=0; k<=batchsize-1; k++) + { + for(j=0; j<=nraw-1; j++) + { + i = k*nraw+j; + jr = idxraw2red->ptr.p_int[j]; + if( jr<0 ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + vs = xs->ptr.p_double[k*nreduced+jr]; + if( state->hasbndl.ptr.p_bool[j]&&vs<=scaledbndl->ptr.p_double[jr] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + continue; + } + if( state->hasbndu.ptr.p_bool[j]&&vs>=scaledbndu->ptr.p_double[jr] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + continue; + } + xu->ptr.p_double[i] = vs*state->s.ptr.p_double[j]; + if( state->hasbndl.ptr.p_bool[j]&&xu->ptr.p_double[i]bndl.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[j]; + } + if( state->hasbndu.ptr.p_bool[j]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[j] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[j]; + } + } + } + } +} + + +void _minnlcstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minnlcstate *p = (minnlcstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_init(&p->criteria, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + _xlinearconstraints_init(&p->xlc, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _rcommstate_init(&p->rstateaul, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->scaledcleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dfbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->batchquerydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpspaf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpsptolj, 0, DT_REAL, _state, make_automatic); + ae_smart_ptr_init(&p->_aulsolverstate, (void**)&p->aulsolverstate, ae_true, _state, make_automatic); + ae_smart_ptr_init(&p->_sqpsolverstate, (void**)&p->sqpsolverstate, ae_true, _state, make_automatic); + ae_smart_ptr_init(&p->_fsqpsolverstate, (void**)&p->fsqpsolverstate, ae_true, _state, make_automatic); + ae_smart_ptr_init(&p->_orbitsolver, (void**)&p->orbitsolver, ae_true, _state, make_automatic); + ae_vector_init(&p->idxraw2red, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->redx0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->reds, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->redbl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->redbu, 0, DT_REAL, _state, make_automatic); + ae_smart_ptr_init(&p->_gipm2solver, (void**)&p->gipm2solver, ae_true, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagbcnz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replaglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replagnlc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nlcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nlcmul, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nlcadd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi, 0, DT_INT, _state, make_automatic); +} + + +void _minnlcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minnlcstate *dst = (minnlcstate*)_dst; + const minnlcstate *src = (const minnlcstate*)_src; + dst->solvertype = src->solvertype; + dst->n = src->n; + _nlpstoppingcriteria_init_copy(&dst->criteria, &src->criteria, _state, make_automatic); + dst->aulitscnt = src->aulitscnt; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + dst->diffstep = src->diffstep; + dst->teststep = src->teststep; + dst->formulatype = src->formulatype; + dst->orbitrad0 = src->orbitrad0; + dst->orbitmaxnfev = src->orbitmaxnfev; + dst->fsqpadditsforctol = src->fsqpadditsforctol; + dst->fsqpctol = src->fsqpctol; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + _xlinearconstraints_init_copy(&dst->xlc, &src->xlc, _state, make_automatic); + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->protocolversion = src->protocolversion; + dst->issuesparserequests = src->issuesparserequests; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->needfij = src->needfij; + dst->needfi = src->needfi; + dst->xupdated = src->xupdated; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _rcommstate_init_copy(&dst->rstateaul, &src->rstateaul, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_matrix_init_copy(&dst->scaledcleic, &src->scaledcleic, _state, make_automatic); + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->fbase, &src->fbase, _state, make_automatic); + ae_vector_init_copy(&dst->dfbase, &src->dfbase, _state, make_automatic); + ae_vector_init_copy(&dst->fm2, &src->fm2, _state, make_automatic); + ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic); + ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic); + ae_vector_init_copy(&dst->fp2, &src->fp2, _state, make_automatic); + ae_vector_init_copy(&dst->batchquerydata, &src->batchquerydata, _state, make_automatic); + ae_vector_init_copy(&dst->tmpspaf, &src->tmpspaf, _state, make_automatic); + ae_vector_init_copy(&dst->tmpsptolj, &src->tmpsptolj, _state, make_automatic); + ae_smart_ptr_init(&dst->_aulsolverstate, (void**)&dst->aulsolverstate, ae_true, _state, make_automatic); + if( src->aulsolverstate!=NULL ) + { + dst->aulsolverstate = (minaulstate*)ae_malloc(sizeof(minaulstate), _state); /* note: using aulsolverstate as a temporary prior to assigning its value to _aulsolverstate */ + memset(dst->aulsolverstate, 0, sizeof(minaulstate)); + _minaulstate_init_copy(dst->aulsolverstate, src->aulsolverstate, _state, ae_false); + ae_smart_ptr_assign(&dst->_aulsolverstate, dst->aulsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minaulstate), _minaulstate_init_copy, _minaulstate_destroy); + } + dst->userterminationneeded = src->userterminationneeded; + ae_smart_ptr_init(&dst->_sqpsolverstate, (void**)&dst->sqpsolverstate, ae_true, _state, make_automatic); + if( src->sqpsolverstate!=NULL ) + { + dst->sqpsolverstate = (minsqpstate*)ae_malloc(sizeof(minsqpstate), _state); /* note: using sqpsolverstate as a temporary prior to assigning its value to _sqpsolverstate */ + memset(dst->sqpsolverstate, 0, sizeof(minsqpstate)); + _minsqpstate_init_copy(dst->sqpsolverstate, src->sqpsolverstate, _state, ae_false); + ae_smart_ptr_assign(&dst->_sqpsolverstate, dst->sqpsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minsqpstate), _minsqpstate_init_copy, _minsqpstate_destroy); + } + ae_smart_ptr_init(&dst->_fsqpsolverstate, (void**)&dst->fsqpsolverstate, ae_true, _state, make_automatic); + if( src->fsqpsolverstate!=NULL ) + { + dst->fsqpsolverstate = (minfsqpstate*)ae_malloc(sizeof(minfsqpstate), _state); /* note: using fsqpsolverstate as a temporary prior to assigning its value to _fsqpsolverstate */ + memset(dst->fsqpsolverstate, 0, sizeof(minfsqpstate)); + _minfsqpstate_init_copy(dst->fsqpsolverstate, src->fsqpsolverstate, _state, ae_false); + ae_smart_ptr_assign(&dst->_fsqpsolverstate, dst->fsqpsolverstate, ae_true, ae_true, (ae_int_t)sizeof(minfsqpstate), _minfsqpstate_init_copy, _minfsqpstate_destroy); + } + ae_smart_ptr_init(&dst->_orbitsolver, (void**)&dst->orbitsolver, ae_true, _state, make_automatic); + if( src->orbitsolver!=NULL ) + { + dst->orbitsolver = (dfgmstate*)ae_malloc(sizeof(dfgmstate), _state); /* note: using orbitsolver as a temporary prior to assigning its value to _orbitsolver */ + memset(dst->orbitsolver, 0, sizeof(dfgmstate)); + _dfgmstate_init_copy(dst->orbitsolver, src->orbitsolver, _state, ae_false); + ae_smart_ptr_assign(&dst->_orbitsolver, dst->orbitsolver, ae_true, ae_true, (ae_int_t)sizeof(dfgmstate), _dfgmstate_init_copy, _dfgmstate_destroy); + } + dst->nreduced = src->nreduced; + ae_vector_init_copy(&dst->idxraw2red, &src->idxraw2red, _state, make_automatic); + ae_vector_init_copy(&dst->redx0, &src->redx0, _state, make_automatic); + ae_vector_init_copy(&dst->reds, &src->reds, _state, make_automatic); + ae_vector_init_copy(&dst->redbl, &src->redbl, _state, make_automatic); + ae_vector_init_copy(&dst->redbu, &src->redbu, _state, make_automatic); + ae_smart_ptr_init(&dst->_gipm2solver, (void**)&dst->gipm2solver, ae_true, _state, make_automatic); + if( src->gipm2solver!=NULL ) + { + dst->gipm2solver = (nlpgipm2state*)ae_malloc(sizeof(nlpgipm2state), _state); /* note: using gipm2solver as a temporary prior to assigning its value to _gipm2solver */ + memset(dst->gipm2solver, 0, sizeof(nlpgipm2state)); + _nlpgipm2state_init_copy(dst->gipm2solver, src->gipm2solver, _state, ae_false); + ae_smart_ptr_assign(&dst->_gipm2solver, dst->gipm2solver, ae_true, ae_true, (ae_int_t)sizeof(nlpgipm2state), _nlpgipm2state_init_copy, _nlpgipm2state_destroy); + } + dst->smoothnessguardlevel = src->smoothnessguardlevel; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); + dst->repf = src->repf; + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + dst->repsclfeaserr = src->repsclfeaserr; + dst->repdbgphase0its = src->repdbgphase0its; + ae_vector_init_copy(&dst->replagbc, &src->replagbc, _state, make_automatic); + ae_vector_init_copy(&dst->replagbcnz, &src->replagbcnz, _state, make_automatic); + ae_vector_init_copy(&dst->replaglc, &src->replaglc, _state, make_automatic); + ae_vector_init_copy(&dst->replagnlc, &src->replagnlc, _state, make_automatic); + ae_vector_init_copy(&dst->nlcidx, &src->nlcidx, _state, make_automatic); + ae_vector_init_copy(&dst->nlcmul, &src->nlcmul, _state, make_automatic); + ae_vector_init_copy(&dst->nlcadd, &src->nlcadd, _state, make_automatic); + dst->nlcnlec = src->nlcnlec; + dst->nlcnlic = src->nlcnlic; + ae_vector_init_copy(&dst->tmpi, &src->tmpi, _state, make_automatic); +} + + +void _minnlcstate_clear(void* _p) +{ + minnlcstate *p = (minnlcstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_clear(&p->criteria); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + _xlinearconstraints_clear(&p->xlc); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + _rcommstate_clear(&p->rstate); + _rcommstate_clear(&p->rstateaul); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_matrix_clear(&p->scaledcleic); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->xstart); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fbase); + ae_vector_clear(&p->dfbase); + ae_vector_clear(&p->fm2); + ae_vector_clear(&p->fm1); + ae_vector_clear(&p->fp1); + ae_vector_clear(&p->fp2); + ae_vector_clear(&p->batchquerydata); + ae_vector_clear(&p->tmpspaf); + ae_vector_clear(&p->tmpsptolj); + ae_smart_ptr_clear(&p->_aulsolverstate); + ae_smart_ptr_clear(&p->_sqpsolverstate); + ae_smart_ptr_clear(&p->_fsqpsolverstate); + ae_smart_ptr_clear(&p->_orbitsolver); + ae_vector_clear(&p->idxraw2red); + ae_vector_clear(&p->redx0); + ae_vector_clear(&p->reds); + ae_vector_clear(&p->redbl); + ae_vector_clear(&p->redbu); + ae_smart_ptr_clear(&p->_gipm2solver); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); + ae_vector_clear(&p->replagbc); + ae_vector_clear(&p->replagbcnz); + ae_vector_clear(&p->replaglc); + ae_vector_clear(&p->replagnlc); + ae_vector_clear(&p->nlcidx); + ae_vector_clear(&p->nlcmul); + ae_vector_clear(&p->nlcadd); + ae_vector_clear(&p->tmpi); +} + + +void _minnlcstate_destroy(void* _p) +{ + minnlcstate *p = (minnlcstate*)_p; + ae_touch_ptr((void*)p); + _nlpstoppingcriteria_destroy(&p->criteria); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + _xlinearconstraints_destroy(&p->xlc); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + _rcommstate_destroy(&p->rstate); + _rcommstate_destroy(&p->rstateaul); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_matrix_destroy(&p->scaledcleic); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->xstart); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fbase); + ae_vector_destroy(&p->dfbase); + ae_vector_destroy(&p->fm2); + ae_vector_destroy(&p->fm1); + ae_vector_destroy(&p->fp1); + ae_vector_destroy(&p->fp2); + ae_vector_destroy(&p->batchquerydata); + ae_vector_destroy(&p->tmpspaf); + ae_vector_destroy(&p->tmpsptolj); + ae_smart_ptr_destroy(&p->_aulsolverstate); + ae_smart_ptr_destroy(&p->_sqpsolverstate); + ae_smart_ptr_destroy(&p->_fsqpsolverstate); + ae_smart_ptr_destroy(&p->_orbitsolver); + ae_vector_destroy(&p->idxraw2red); + ae_vector_destroy(&p->redx0); + ae_vector_destroy(&p->reds); + ae_vector_destroy(&p->redbl); + ae_vector_destroy(&p->redbu); + ae_smart_ptr_destroy(&p->_gipm2solver); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); + ae_vector_destroy(&p->replagbc); + ae_vector_destroy(&p->replagbcnz); + ae_vector_destroy(&p->replaglc); + ae_vector_destroy(&p->replagnlc); + ae_vector_destroy(&p->nlcidx); + ae_vector_destroy(&p->nlcmul); + ae_vector_destroy(&p->nlcadd); + ae_vector_destroy(&p->tmpi); +} + + +void _minnlcreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minnlcreport *p = (minnlcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->lagbc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagbcnz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->laglc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lagnlc, 0, DT_REAL, _state, make_automatic); +} + + +void _minnlcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minnlcreport *dst = (minnlcreport*)_dst; + const minnlcreport *src = (const minnlcreport*)_src; + dst->f = src->f; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; + dst->bcerr = src->bcerr; + dst->bcidx = src->bcidx; + dst->lcerr = src->lcerr; + dst->lcidx = src->lcidx; + dst->nlcerr = src->nlcerr; + dst->nlcidx = src->nlcidx; + dst->sclfeaserr = src->sclfeaserr; + ae_vector_init_copy(&dst->lagbc, &src->lagbc, _state, make_automatic); + ae_vector_init_copy(&dst->lagbcnz, &src->lagbcnz, _state, make_automatic); + ae_vector_init_copy(&dst->laglc, &src->laglc, _state, make_automatic); + ae_vector_init_copy(&dst->lagnlc, &src->lagnlc, _state, make_automatic); + dst->dbgphase0its = src->dbgphase0its; +} + + +void _minnlcreport_clear(void* _p) +{ + minnlcreport *p = (minnlcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->lagbc); + ae_vector_clear(&p->lagbcnz); + ae_vector_clear(&p->laglc); + ae_vector_clear(&p->lagnlc); +} + + +void _minnlcreport_destroy(void* _p) +{ + minnlcreport *p = (minnlcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->lagbc); + ae_vector_destroy(&p->lagbcnz); + ae_vector_destroy(&p->laglc); + ae_vector_destroy(&p->lagnlc); +} + + +#endif +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Initialize NBI solver with the problem formulation + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void nbiscaleandinitbuf(/* Real */ const ae_vector* x0, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t m, + ae_int_t frontsize, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + /* Real */ const ae_matrix* densea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t ksparse, + ae_int_t kdense, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + double epsx, + ae_int_t maxits, + ae_bool polishsolutions, + nbistate* state, + ae_state *_state) +{ + + + ae_assert(frontsize>=m, "NBIScaleAndInitBuf: FrontSizen = n; + state->m = m; + state->epsx = epsx; + state->maxits = maxits; + state->xrep = ae_false; + state->frontsize = frontsize; + state->polishsolutions = polishsolutions; + rsetallocv(n, 0.0, &state->tmpzero, _state); + rsetallocv(n, 1.0, &state->tmpone, _state); + + /* + * Copy and scale initial point + */ + rcopyallocv(n, x0, &state->xstart, _state); + rmergedivv(n, s, &state->xstart, _state); + + /* + * Copy and scale box constraints + */ + rcopyallocv(n, bndl, &state->bndl, _state); + rcopyallocv(n, bndu, &state->bndu, _state); + scaleshiftbcinplace(s, &state->tmpzero, &state->bndl, &state->bndu, n, _state); + + /* + * Copy and scale linear constraints + */ + state->ksparse = ksparse; + state->kdense = kdense; + rcopyallocv(ksparse+kdense, al, &state->cl, _state); + rcopyallocv(ksparse+kdense, au, &state->cu, _state); + if( ksparse>0 ) + { + sparsecopybuf(sparsea, &state->sparsec, _state); + } + if( kdense>0 ) + { + rcopyallocm(kdense, n, densea, &state->densec, _state); + } + scaleshiftmixedlcinplace(s, &state->tmpzero, n, &state->sparsec, ksparse, &state->densec, kdense, &state->cl, &state->cu, _state); + + /* + * Copy nonlinear constraints + */ + rcopyallocv(nnlc, nl, &state->nl, _state); + rcopyallocv(nnlc, nu, &state->nu, _state); + state->nnlc = nnlc; + + /* + * Other fields + */ + state->userrequestedtermination = ae_false; + state->repterminationtype = 0; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repnfev = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repfrontsize = 0; + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 7+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; + monbi_clearrequestfields(state, _state); + rallocv(n, &state->x, _state); + rallocv(m+nnlc, &state->fi, _state); + rallocm(m+nnlc, n, &state->j, _state); +} + + +/************************************************************************* +RCOMM function + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool nbiiteration(nbistate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t objectiveidx; + ae_int_t frontsize; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t frontrow; + double v; + double vv; + ae_bool dotrace; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + objectiveidx = state->rstate.ia.ptr.p_int[2]; + frontsize = state->rstate.ia.ptr.p_int[3]; + i = state->rstate.ia.ptr.p_int[4]; + j = state->rstate.ia.ptr.p_int[5]; + k = state->rstate.ia.ptr.p_int[6]; + frontrow = state->rstate.ia.ptr.p_int[7]; + dotrace = state->rstate.ba.ptr.p_bool[0]; + v = state->rstate.ra.ptr.p_double[0]; + vv = state->rstate.ra.ptr.p_double[1]; + } + else + { + n = 359; + m = -58; + objectiveidx = -919; + frontsize = -909; + i = 81; + j = 255; + k = 74; + frontrow = -788; + dotrace = ae_true; + v = 205.0; + vv = -838.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + frontsize = state->frontsize; + hqrndseed(348546, 436734, &state->rs, _state); + ae_assert(m>1||frontsize==1, "NBI: integrity check 3309 failed", _state); + dotrace = ae_is_trace_enabled("NBI"); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// NBI SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %0d (variables)\n", + (int)(n)); + ae_trace("M = %0d (objectives)\n", + (int)(m)); + } + + /* + * Prepare rcomm interface + */ + monbi_clearrequestfields(state, _state); + + /* + * Prepare initial state of the output + */ + ae_assert(state->frontsize>=m, "NBI: integrity check 0503 failed", _state); + rsetallocm(frontsize, n+m+m, _state->v_nan, &state->repparetofront, _state); + state->repfrontsize = 0; + state->repterminationtype = 2; + state->userrequestedtermination = ae_false; + + /* + * Convert linear and nonlinear constraints to an old format + */ + converttwosidedlctoonesidedold(&state->sparsec, state->ksparse, &state->densec, state->kdense, n, &state->cl, &state->cu, &state->olddensec, &state->olddensect, &state->olddensek, _state); + converttwosidednlctoonesidedold(&state->nl, &state->nu, state->nnlc, &state->nlcidx, &state->nlcmul, &state->nlcadd, &state->nlcnlec, &state->nlcnlic, _state); + + /* + * Solve M initial single-objective problems that are used to find an ideal objectives vector + */ + minnlccreate(n, &state->xstart, &state->nlcsolver, _state); + minnlcsetcond(&state->nlcsolver, state->epsx, state->maxits, _state); + minnlcsetbc(&state->nlcsolver, &state->bndl, &state->bndu, _state); + minnlcsetlc(&state->nlcsolver, &state->olddensec, &state->olddensect, state->olddensek, _state); + monbi_setnlcalgo(&state->nlcsolver, _state); + objectiveidx = 0; +lbl_16: + if( objectiveidx>m-1 ) + { + goto lbl_18; + } + if( !dotrace ) + { + goto lbl_19; + } + ae_trace("===== OPTIMIZING FOR OBJECTIVE %2d ==================================================================\n", + (int)(objectiveidx)); + state->needfij = ae_true; + rcopyv(n, &state->xstart, &state->x, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (initial) = "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace("\n"); +lbl_19: + + /* + * Optimize with respect to one objective + */ + minnlcsetnlc(&state->nlcsolver, state->nlcnlec, state->nlcnlic, _state); + minnlcrestartfrom(&state->nlcsolver, &state->xstart, _state); +lbl_21: + if( !minnlciteration(&state->nlcsolver, _state) ) + { + goto lbl_22; + } + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->nlcsolver.needfij ) + { + goto lbl_23; + } + + /* + * Forward report to the caller + */ + state->needfij = ae_true; + rcopyv(n, &state->nlcsolver.x, &state->x, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfij = ae_false; + + /* + * Convert target and constraints to the format used by the subproblem + */ + state->nlcsolver.fi.ptr.p_double[0] = state->fi.ptr.p_double[objectiveidx]; + rcopyrr(n, &state->j, objectiveidx, &state->nlcsolver.j, 0, _state); + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->nlcsolver.fi.ptr.p_double[i+1] = state->fi.ptr.p_double[m+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + rcopyrr(n, &state->j, m+state->nlcidx.ptr.p_int[i], &state->nlcsolver.j, i+1, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->nlcsolver.j, i+1, _state); + } + goto lbl_21; +lbl_23: + ae_assert(ae_false, "NBI: integrity check 6034 failed", _state); + goto lbl_21; +lbl_22: + minnlcresultsbuf(&state->nlcsolver, &state->x1, &state->nlcrep, _state); + if( state->nlcrep.terminationtype==-8 ) + { + state->repterminationtype = -8; + state->repfrontsize = 0; + result = ae_false; + return result; + } + ae_assert(state->nlcrep.terminationtype>0, "NBI: integrity check 7144 failed", _state); + state->repinneriterationscount = state->repinneriterationscount+state->nlcrep.iterationscount; + state->repnfev = state->repnfev+state->nlcrep.nfev; + if( !dotrace ) + { + goto lbl_25; + } + state->needfij = ae_true; + rcopyv(n, &state->x1, &state->x, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (unpolished)= "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace(" (%0d its, feas.err=%0.2e)\n", + (int)(state->nlcrep.iterationscount), + (double)(rmax3(state->nlcrep.bcerr, state->nlcrep.lcerr, state->nlcrep.nlcerr, _state))); +lbl_25: + + /* + * Polish the solution: having solution X1 that minimizes f_objectiveIdx, + * now we want to minimize a sum of f[i] subject to constraint that f_i(x)<=f_i(X1). + * + * This stage is essential for polishing other components of the solution + * (even with moderate condition numbers it is possible to have f[i!=objectiveIdx] + * underoptimized due to purely numerical issues). + */ + if( !state->polishsolutions ) + { + goto lbl_27; + } + state->needfij = ae_true; + rcopyv(n, &state->x1, &state->x, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + rcopyallocv(m+state->nnlc, &state->fi, &state->fix1, _state); + minnlcsetnlc(&state->nlcsolver, state->nlcnlec, state->nlcnlic+1, _state); + minnlcrestartfrom(&state->nlcsolver, &state->x1, _state); +lbl_29: + if( !minnlciteration(&state->nlcsolver, _state) ) + { + goto lbl_30; + } + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->nlcsolver.needfij ) + { + goto lbl_31; + } + + /* + * Forward report to the caller + */ + state->needfij = ae_true; + rcopyv(n, &state->nlcsolver.x, &state->x, _state); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfij = ae_false; + + /* + * Target: sum of objectives + */ + state->nlcsolver.fi.ptr.p_double[0] = (double)(0); + rsetr(n, 0.0, &state->nlcsolver.j, 0, _state); + for(i=0; i<=m-1; i++) + { + state->nlcsolver.fi.ptr.p_double[0] = state->nlcsolver.fi.ptr.p_double[0]+state->fi.ptr.p_double[i]; + raddrr(n, 1.0, &state->j, i, &state->nlcsolver.j, 0, _state); + } + + /* + * Original nonlinear constraints + */ + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->nlcsolver.fi.ptr.p_double[i+1] = state->fi.ptr.p_double[m+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + rcopyrr(n, &state->j, m+state->nlcidx.ptr.p_int[i], &state->nlcsolver.j, i+1, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->nlcsolver.j, i+1, _state); + } + + /* + * Additional nonlinear constraint: f[objectiveidx] does not increase: f(x)-f(X1)<=0 + */ + state->nlcsolver.fi.ptr.p_double[1+state->nlcnlec+state->nlcnlic] = state->fi.ptr.p_double[objectiveidx]-state->fix1.ptr.p_double[objectiveidx]; + rcopyrr(n, &state->j, objectiveidx, &state->nlcsolver.j, 1+state->nlcnlec+state->nlcnlic, _state); + + /* + * Done + */ + goto lbl_29; +lbl_31: + ae_assert(ae_false, "NBI: integrity check 7056 failed", _state); + goto lbl_29; +lbl_30: + minnlcresultsbuf(&state->nlcsolver, &state->x2, &state->nlcrep, _state); + if( state->nlcrep.terminationtype==-8 ) + { + state->repterminationtype = -8; + state->repfrontsize = 0; + result = ae_false; + return result; + } + ae_assert(state->nlcrep.terminationtype>0, "NBI: integrity check 7144 failed", _state); + state->repinneriterationscount = state->repinneriterationscount+state->nlcrep.iterationscount; + state->repnfev = state->repnfev+state->nlcrep.nfev; + if( !dotrace ) + { + goto lbl_33; + } + state->needfij = ae_true; + rcopyv(n, &state->x2, &state->x, _state); + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (polished) = "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace(" (%0d its, feas.err=%0.2e)\n", + (int)(state->nlcrep.iterationscount), + (double)(rmax3(state->nlcrep.bcerr, state->nlcrep.lcerr, state->nlcrep.nlcerr, _state))); +lbl_33: + goto lbl_28; +lbl_27: + rcopyallocv(n, &state->x1, &state->x2, _state); +lbl_28: + + /* + * Save solution and objectives at the solution + */ + state->needfij = ae_true; + rcopyv(n, &state->x2, &state->x, _state); + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + rcopyvr(n, &state->x2, &state->repparetofront, state->repfrontsize, _state); + for(i=0; i<=m-1; i++) + { + state->repparetofront.ptr.pp_double[state->repfrontsize][n+i] = state->fi.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + state->repparetofront.ptr.pp_double[state->repfrontsize][n+m+i] = rcase2(i==objectiveidx, (double)(1), (double)(0), _state); + } + state->repfrontsize = state->repfrontsize+1; + state->repouteriterationscount = state->repouteriterationscount+1; + if( ae_fp_greater(state->nlcrep.bcerr,state->repbcerr) ) + { + state->repbcerr = state->nlcrep.bcerr; + state->repbcidx = state->nlcrep.bcidx; + } + if( ae_fp_greater(state->nlcrep.lcerr,state->replcerr) ) + { + state->replcerr = state->nlcrep.lcerr; + state->replcidx = state->nlcrep.lcidx; + } + if( ae_fp_greater(state->nlcrep.nlcerr,state->repnlcerr) ) + { + state->repnlcerr = state->nlcrep.nlcerr; + state->repnlcidx = state->nlcrep.nlcidx; + } + + /* + * Report last point found and check request for termination + */ + rcopyrv(n, &state->repparetofront, state->repfrontsize-1, &state->x, _state); + state->xupdated = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->xupdated = ae_false; + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + objectiveidx = objectiveidx+1; + goto lbl_16; +lbl_18: + + /* + * Compute ideal vector and payoff matrix + */ + rallocv(m, &state->fideal, _state); + for(i=0; i<=m-1; i++) + { + state->fideal.ptr.p_double[i] = state->repparetofront.ptr.pp_double[i][n+i]; + } + rallocm(m, m, &state->payoff, _state); + for(i=0; i<=m-1; i++) + { + for(j=0; j<=m-1; j++) + { + state->payoff.ptr.pp_double[i][j] = state->repparetofront.ptr.pp_double[j][n+i]-state->fideal.ptr.p_double[i]; + } + } + + /* + * Generate quasi-normal vector Delta[]. + * + * NOTE: if |Delta| is less than 1, we normalize it. Without normalization + * nonlinear optimizer may fail when Delta is very small because + * an extremely small scale of Delta implies an extremely large scale + * of the artificial variable t. + * + * Values of Delta larger than 1 are not normalized. + * + */ + rallocv(m, &state->delta, _state); + for(i=0; i<=m-1; i++) + { + state->delta.ptr.p_double[i] = (double)(0); + for(j=0; j<=m-1; j++) + { + state->delta.ptr.p_double[i] = state->delta.ptr.p_double[i]-state->payoff.ptr.pp_double[i][j]; + } + if( ae_fp_greater_eq(state->delta.ptr.p_double[i],(double)(0)) ) + { + + /* + * Something is wrong with payoff matrix, fix direction + */ + state->delta.ptr.p_double[i] = (double)(0); + for(j=0; j<=m-1; j++) + { + state->delta.ptr.p_double[i] = ae_minreal(state->delta.ptr.p_double[i], -state->payoff.ptr.pp_double[i][j], _state); + } + state->delta.ptr.p_double[i] = coalesce(state->delta.ptr.p_double[i], (double)(-1), _state); + } + } + v = ae_sqrt(rdotv2(m, &state->delta, _state), _state); + ae_assert(ae_fp_neq(v,(double)(0)), "NBI: integrity check 8546 failed", _state); + rmulv(m, ae_maxreal((double)1/v, 1.0, _state), &state->delta, _state); + + /* + * For each front row solve NBI subproblem + */ + frontrow = m; +lbl_35: + if( frontrow>frontsize-1 ) + { + goto lbl_37; + } + if( dotrace ) + { + ae_trace("===== OPTIMIZING FOR FRONT POINT %4d ==============================================================\n", + (int)(frontrow)); + } + + /* + * Generate convex hull coordinates vector Beta[] using the following + * algorithm to obtain uniformly sampled points on a simplex: + * + * * generate M random uniform numbers + * * take logarithms + * * normalize sum + * + * Without latter two steps we will obtain heavily non-uniform distribution + * with a sharp peak at the center. + */ + rallocv(m, &state->beta, _state); + v = (double)(0); + for(i=0; i<=m-1; i++) + { + state->beta.ptr.p_double[i] = ae_log(hqrnduniformr(&state->rs, _state)+ae_machineepsilon, _state); + v = v+state->beta.ptr.p_double[i]; + } + rmulv(m, (double)1/v, &state->beta, _state); + if( dotrace ) + { + ae_trace("Beta (normal) = "); + tracevectorautoprec(&state->beta, 0, m, _state); + ae_trace("\n"); + } + + /* + * Prepare initial point for a subproblem: + * * for N first variables, select point from the front with closest values of Beta[] + * * for last variable, set T to zero (numerical experience shows that it is good enough) + */ + rallocv(n+1, &state->subproblemstart, _state); + k = -1; + v = ae_maxrealnumber; + for(i=0; i<=frontrow-1; i++) + { + vv = (double)(0); + for(j=0; j<=m-1; j++) + { + vv = vv+ae_sqr(state->repparetofront.ptr.pp_double[i][n+m+j]-state->beta.ptr.p_double[j], _state); + } + if( ae_fp_less(vv,v) ) + { + k = i; + v = vv; + } + } + ae_assert(k>=0, "NBI: integrity check 0630 failed", _state); + rcopyrv(n, &state->repparetofront, k, &state->subproblemstart, _state); + state->subproblemstart.ptr.p_double[n] = 0.0; + if( dotrace ) + { + ae_trace("StartIdx = %0d (front point used as the initial one)\n", + (int)(k)); + } + + /* + * Reformulate box and linear constraints + */ + rallocv(n+1, &state->bndlx, _state); + rallocv(n+1, &state->bndux, _state); + rcopyv(n, &state->bndl, &state->bndlx, _state); + rcopyv(n, &state->bndu, &state->bndux, _state); + state->bndlx.ptr.p_double[n] = _state->v_neginf; + state->bndux.ptr.p_double[n] = _state->v_posinf; + if( state->olddensek>0 ) + { + rallocm(state->olddensek, n+2, &state->olddensecx, _state); + rcopym(state->olddensek, n, &state->olddensec, &state->olddensecx, _state); + for(i=0; i<=state->olddensek-1; i++) + { + state->olddensecx.ptr.pp_double[i][n] = 0.0; + state->olddensecx.ptr.pp_double[i][n+1] = state->olddensec.ptr.pp_double[i][n]; + } + } + + /* + * Report initial F-vector + */ + if( !dotrace ) + { + goto lbl_38; + } + state->needfij = ae_true; + rcopyv(n, &state->subproblemstart, &state->x, _state); + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (initial) = "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace("\n"); +lbl_38: + + /* + * Solve initial NBI subproblem + */ + minnlccreate(n+1, &state->subproblemstart, &state->nlcsolver, _state); + minnlcsetcond(&state->nlcsolver, state->epsx, state->maxits, _state); + minnlcsetbc(&state->nlcsolver, &state->bndlx, &state->bndux, _state); + minnlcsetlc(&state->nlcsolver, &state->olddensecx, &state->olddensect, state->olddensek, _state); + minnlcsetnlc(&state->nlcsolver, state->nlcnlec, state->nlcnlic+m, _state); + monbi_setnlcalgo(&state->nlcsolver, _state); +lbl_40: + if( !minnlciteration(&state->nlcsolver, _state) ) + { + goto lbl_41; + } + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->nlcsolver.needfij ) + { + goto lbl_42; + } + + /* + * Forward report to the caller + */ + state->needfij = ae_true; + rcopyv(n, &state->nlcsolver.x, &state->x, _state); + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->needfij = ae_false; + + /* + * Compute target + */ + state->nlcsolver.fi.ptr.p_double[0] = -state->nlcsolver.x.ptr.p_double[n]; + rsetr(n+1, 0.0, &state->nlcsolver.j, 0, _state); + state->nlcsolver.j.ptr.pp_double[0][n] = (double)(-1); + + /* + * Forward original nonlinear constraints + */ + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->nlcsolver.fi.ptr.p_double[1+i] = state->fi.ptr.p_double[m+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + rcopyrr(n, &state->j, m+state->nlcidx.ptr.p_int[i], &state->nlcsolver.j, 1+i, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->nlcsolver.j, 1+i, _state); + state->nlcsolver.j.ptr.pp_double[1+i][n] = (double)(0); + } + + /* + * Append NBI constraints + */ + for(i=0; i<=m-1; i++) + { + + /* + * PAYOFF*Beta + t*Delta >= F(x)-FIdeal + * + * F(x) - FIdeal - t*DELTA - PAYOFF*Beta <= 0 + */ + state->nlcsolver.fi.ptr.p_double[1+state->nlcnlec+state->nlcnlic+i] = state->fi.ptr.p_double[i]-state->fideal.ptr.p_double[i]-state->nlcsolver.x.ptr.p_double[n]*state->delta.ptr.p_double[i]-rdotvr(m, &state->beta, &state->payoff, i, _state); + rcopyrr(n, &state->j, i, &state->nlcsolver.j, 1+state->nlcnlec+state->nlcnlic+i, _state); + state->nlcsolver.j.ptr.pp_double[1+state->nlcnlec+state->nlcnlic+i][n] = -state->delta.ptr.p_double[i]; + } + goto lbl_40; +lbl_42: + ae_assert(ae_false, "NBI: integrity check 6034 failed", _state); + goto lbl_40; +lbl_41: + minnlcresultsbuf(&state->nlcsolver, &state->x1, &state->nlcrep, _state); + if( state->nlcrep.terminationtype==-8 ) + { + state->repterminationtype = -8; + state->repfrontsize = 0; + result = ae_false; + return result; + } + ae_assert(state->nlcrep.terminationtype>0, "NBI: integrity check 7144 failed", _state); + state->repinneriterationscount = state->repinneriterationscount+state->nlcrep.iterationscount; + state->repnfev = state->repnfev+state->nlcrep.nfev; + if( !dotrace ) + { + goto lbl_44; + } + state->needfij = ae_true; + rcopyv(n, &state->x1, &state->x, _state); + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (unpolished)= "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace(" (%0d its, feas.err=%0.2e)\n", + (int)(state->nlcrep.iterationscount), + (double)(rmax3(state->nlcrep.bcerr, state->nlcrep.lcerr, state->nlcrep.nlcerr, _state))); +lbl_44: + + /* + * Polish the solution: having solution X1 that minimizes f_objectiveIdx, + * now we want to minimize a sum of f[i] subject to constraint that f_i(x)<=f_i(X1). + * + * This stage is essential for polishing other components of the solution + * (even with moderate condition numbers it is possible to have f[i!=objectiveIdx] + * underoptimized due to purely numerical issues). + */ + if( !state->polishsolutions ) + { + goto lbl_46; + } + state->needfij = ae_true; + rcopyv(n, &state->x1, &state->x, _state); + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + rcopyallocv(m+state->nnlc, &state->fi, &state->fix1, _state); + minnlccreate(n, &state->x1, &state->nlcsolver, _state); + minnlcsetcond(&state->nlcsolver, state->epsx, state->maxits, _state); + minnlcsetbc(&state->nlcsolver, &state->bndlx, &state->bndux, _state); + minnlcsetlc(&state->nlcsolver, &state->olddensec, &state->olddensect, state->olddensek, _state); + minnlcsetnlc(&state->nlcsolver, state->nlcnlec, state->nlcnlic+m, _state); + monbi_setnlcalgo(&state->nlcsolver, _state); +lbl_48: + if( !minnlciteration(&state->nlcsolver, _state) ) + { + goto lbl_49; + } + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( !state->nlcsolver.needfij ) + { + goto lbl_50; + } + + /* + * Forward report to the caller + */ + state->needfij = ae_true; + rcopyv(n, &state->nlcsolver.x, &state->x, _state); + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->needfij = ae_false; + + /* + * Target: sum of objectives + */ + state->nlcsolver.fi.ptr.p_double[0] = (double)(0); + rsetr(n, 0.0, &state->nlcsolver.j, 0, _state); + for(i=0; i<=m-1; i++) + { + state->nlcsolver.fi.ptr.p_double[0] = state->nlcsolver.fi.ptr.p_double[0]+state->fi.ptr.p_double[i]; + raddrr(n, 1.0, &state->j, i, &state->nlcsolver.j, 0, _state); + } + + /* + * Original nonlinear constraints + */ + for(i=0; i<=state->nlcnlec+state->nlcnlic-1; i++) + { + state->nlcsolver.fi.ptr.p_double[i+1] = state->fi.ptr.p_double[m+state->nlcidx.ptr.p_int[i]]*state->nlcmul.ptr.p_double[i]+state->nlcadd.ptr.p_double[i]; + rcopyrr(n, &state->j, m+state->nlcidx.ptr.p_int[i], &state->nlcsolver.j, i+1, _state); + rmulr(n, state->nlcmul.ptr.p_double[i], &state->nlcsolver.j, i+1, _state); + } + + /* + * Additional nonlinear constraints: objectives do not increase: f(x)-f(X1)<=0 + */ + for(i=0; i<=m-1; i++) + { + state->nlcsolver.fi.ptr.p_double[1+state->nlcnlec+state->nlcnlic+i] = state->fi.ptr.p_double[i]-state->fix1.ptr.p_double[i]; + rcopyrr(n, &state->j, i, &state->nlcsolver.j, 1+state->nlcnlec+state->nlcnlic+i, _state); + } + + /* + * Done + */ + goto lbl_48; +lbl_50: + ae_assert(ae_false, "NBI: integrity check 6034 failed", _state); + goto lbl_48; +lbl_49: + minnlcresultsbuf(&state->nlcsolver, &state->x2, &state->nlcrep, _state); + if( state->nlcrep.terminationtype==-8 ) + { + state->repterminationtype = -8; + state->repfrontsize = 0; + result = ae_false; + return result; + } + ae_assert(state->nlcrep.terminationtype>0, "NBI: integrity check 7144 failed", _state); + state->repinneriterationscount = state->repinneriterationscount+state->nlcrep.iterationscount; + state->repnfev = state->repnfev+state->nlcrep.nfev; + if( !dotrace ) + { + goto lbl_52; + } + state->needfij = ae_true; + rcopyv(n, &state->x2, &state->x, _state); + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_trace("F (polished) = "); + tracevectorautoprec(&state->fi, 0, m, _state); + ae_trace(" (%0d its, feas.err=%0.2e)\n", + (int)(state->nlcrep.iterationscount), + (double)(rmax3(state->nlcrep.bcerr, state->nlcrep.lcerr, state->nlcrep.nlcerr, _state))); +lbl_52: + goto lbl_47; +lbl_46: + rcopyallocv(n, &state->x1, &state->x2, _state); +lbl_47: + + /* + * Save solution and objectives at the solution, update statistics + */ + state->needfij = ae_true; + rcopyv(n, &state->x2, &state->x, _state); + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->needfij = ae_false; + state->repnfev = state->repnfev+1; + ae_assert(state->repfrontsizex2, &state->repparetofront, state->repfrontsize, _state); + for(i=0; i<=m-1; i++) + { + state->repparetofront.ptr.pp_double[state->repfrontsize][n+i] = state->fi.ptr.p_double[i]; + } + for(i=0; i<=m-1; i++) + { + state->repparetofront.ptr.pp_double[state->repfrontsize][n+m+i] = state->beta.ptr.p_double[i]; + } + state->repfrontsize = state->repfrontsize+1; + state->repouteriterationscount = state->repouteriterationscount+1; + if( ae_fp_greater(state->nlcrep.bcerr,state->repbcerr) ) + { + state->repbcerr = state->nlcrep.bcerr; + state->repbcidx = state->nlcrep.bcidx; + } + if( ae_fp_greater(state->nlcrep.lcerr,state->replcerr) ) + { + state->replcerr = state->nlcrep.lcerr; + state->replcidx = state->nlcrep.lcidx; + } + if( ae_fp_greater(state->nlcrep.nlcerr,state->repnlcerr) ) + { + state->repnlcerr = state->nlcrep.nlcerr; + state->repnlcidx = state->nlcrep.nlcidx; + } + + /* + * Report last point found and check request for termination + */ + rcopyrv(n, &state->repparetofront, state->repfrontsize-1, &state->x, _state); + state->xupdated = ae_true; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->xupdated = ae_false; + if( state->userrequestedtermination ) + { + state->repterminationtype = 8; + result = ae_false; + return result; + } + frontrow = frontrow+1; + goto lbl_35; +lbl_37: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = objectiveidx; + state->rstate.ia.ptr.p_int[3] = frontsize; + state->rstate.ia.ptr.p_int[4] = i; + state->rstate.ia.ptr.p_int[5] = j; + state->rstate.ia.ptr.p_int[6] = k; + state->rstate.ia.ptr.p_int[7] = frontrow; + state->rstate.ba.ptr.p_bool[0] = dotrace; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = vv; + return result; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void monbi_clearrequestfields(nbistate* state, ae_state *_state) +{ + + + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Sets NLC solver +*************************************************************************/ +static void monbi_setnlcalgo(minnlcstate* s, ae_state *_state) +{ + + + minnlcsetalgosqp(s, _state); +} + + +void _nbistate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nbistate *p = (nbistate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->densec, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsec, _state, make_automatic); + ae_vector_init(&p->cl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_matrix_init(&p->repparetofront, 0, 0, DT_REAL, _state, make_automatic); + _minnlcstate_init(&p->nlcsolver, _state, make_automatic); + _minnlcreport_init(&p->nlcrep, _state, make_automatic); + ae_vector_init(&p->tmpzero, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpone, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->olddensec, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->olddensect, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nlcidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->nlcmul, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nlcadd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fideal, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->payoff, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->beta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->delta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->subproblemstart, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->rs, _state, make_automatic); + ae_vector_init(&p->bndlx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndux, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->olddensecx, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fix1, 0, DT_REAL, _state, make_automatic); +} + + +void _nbistate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nbistate *dst = (nbistate*)_dst; + const nbistate *src = (const nbistate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + dst->frontsize = src->frontsize; + dst->polishsolutions = src->polishsolutions; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->ksparse = src->ksparse; + dst->kdense = src->kdense; + ae_matrix_init_copy(&dst->densec, &src->densec, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsec, &src->sparsec, _state, make_automatic); + ae_vector_init_copy(&dst->cl, &src->cl, _state, make_automatic); + ae_vector_init_copy(&dst->cu, &src->cu, _state, make_automatic); + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->needfij = src->needfij; + dst->xupdated = src->xupdated; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->userrequestedtermination = src->userrequestedtermination; + ae_matrix_init_copy(&dst->repparetofront, &src->repparetofront, _state, make_automatic); + dst->repfrontsize = src->repfrontsize; + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + _minnlcstate_init_copy(&dst->nlcsolver, &src->nlcsolver, _state, make_automatic); + _minnlcreport_init_copy(&dst->nlcrep, &src->nlcrep, _state, make_automatic); + ae_vector_init_copy(&dst->tmpzero, &src->tmpzero, _state, make_automatic); + ae_vector_init_copy(&dst->tmpone, &src->tmpone, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_matrix_init_copy(&dst->olddensec, &src->olddensec, _state, make_automatic); + ae_vector_init_copy(&dst->olddensect, &src->olddensect, _state, make_automatic); + dst->olddensek = src->olddensek; + ae_vector_init_copy(&dst->nlcidx, &src->nlcidx, _state, make_automatic); + ae_vector_init_copy(&dst->nlcmul, &src->nlcmul, _state, make_automatic); + ae_vector_init_copy(&dst->nlcadd, &src->nlcadd, _state, make_automatic); + dst->nlcnlec = src->nlcnlec; + dst->nlcnlic = src->nlcnlic; + ae_vector_init_copy(&dst->fideal, &src->fideal, _state, make_automatic); + ae_matrix_init_copy(&dst->payoff, &src->payoff, _state, make_automatic); + ae_vector_init_copy(&dst->beta, &src->beta, _state, make_automatic); + ae_vector_init_copy(&dst->delta, &src->delta, _state, make_automatic); + ae_vector_init_copy(&dst->subproblemstart, &src->subproblemstart, _state, make_automatic); + _hqrndstate_init_copy(&dst->rs, &src->rs, _state, make_automatic); + ae_vector_init_copy(&dst->bndlx, &src->bndlx, _state, make_automatic); + ae_vector_init_copy(&dst->bndux, &src->bndux, _state, make_automatic); + ae_matrix_init_copy(&dst->olddensecx, &src->olddensecx, _state, make_automatic); + ae_vector_init_copy(&dst->x1, &src->x1, _state, make_automatic); + ae_vector_init_copy(&dst->x2, &src->x2, _state, make_automatic); + ae_vector_init_copy(&dst->fix1, &src->fix1, _state, make_automatic); +} + + +void _nbistate_clear(void* _p) +{ + nbistate *p = (nbistate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xstart); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_matrix_clear(&p->densec); + _sparsematrix_clear(&p->sparsec); + ae_vector_clear(&p->cl); + ae_vector_clear(&p->cu); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstate); + ae_matrix_clear(&p->repparetofront); + _minnlcstate_clear(&p->nlcsolver); + _minnlcreport_clear(&p->nlcrep); + ae_vector_clear(&p->tmpzero); + ae_vector_clear(&p->tmpone); + ae_vector_clear(&p->tmp0); + ae_matrix_clear(&p->olddensec); + ae_vector_clear(&p->olddensect); + ae_vector_clear(&p->nlcidx); + ae_vector_clear(&p->nlcmul); + ae_vector_clear(&p->nlcadd); + ae_vector_clear(&p->fideal); + ae_matrix_clear(&p->payoff); + ae_vector_clear(&p->beta); + ae_vector_clear(&p->delta); + ae_vector_clear(&p->subproblemstart); + _hqrndstate_clear(&p->rs); + ae_vector_clear(&p->bndlx); + ae_vector_clear(&p->bndux); + ae_matrix_clear(&p->olddensecx); + ae_vector_clear(&p->x1); + ae_vector_clear(&p->x2); + ae_vector_clear(&p->fix1); +} + + +void _nbistate_destroy(void* _p) +{ + nbistate *p = (nbistate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xstart); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_matrix_destroy(&p->densec); + _sparsematrix_destroy(&p->sparsec); + ae_vector_destroy(&p->cl); + ae_vector_destroy(&p->cu); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _rcommstate_destroy(&p->rstate); + ae_matrix_destroy(&p->repparetofront); + _minnlcstate_destroy(&p->nlcsolver); + _minnlcreport_destroy(&p->nlcrep); + ae_vector_destroy(&p->tmpzero); + ae_vector_destroy(&p->tmpone); + ae_vector_destroy(&p->tmp0); + ae_matrix_destroy(&p->olddensec); + ae_vector_destroy(&p->olddensect); + ae_vector_destroy(&p->nlcidx); + ae_vector_destroy(&p->nlcmul); + ae_vector_destroy(&p->nlcadd); + ae_vector_destroy(&p->fideal); + ae_matrix_destroy(&p->payoff); + ae_vector_destroy(&p->beta); + ae_vector_destroy(&p->delta); + ae_vector_destroy(&p->subproblemstart); + _hqrndstate_destroy(&p->rs); + ae_vector_destroy(&p->bndlx); + ae_vector_destroy(&p->bndux); + ae_matrix_destroy(&p->olddensecx); + ae_vector_destroy(&p->x1); + ae_vector_destroy(&p->x2); + ae_vector_destroy(&p->fix1); +} + + +#endif +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + MULTI-OBJECTIVE OPTIMIZATION + +DESCRIPTION: + +The solver minimizes an M-dimensional vector function F(x) of N arguments +subject to any combination of: +* box constraints +* two-sided linear equality/inequality constraints AL<=A*x<=AU, where some + of AL/AU can be infinite (i.e. missing) +* two-sided nonlinear equality/inequality constraints NL<=C(x)<=NU, where + some of NL/NU can be infinite (i.e. missing) + +REQUIREMENTS: +* F(), C() are continuously differentiable on the feasible set and on its + neighborhood + +USAGE: + +1. User initializes algorithm state using either: + * minmocreate() to perform optimization with user-supplied Jacobian + * minmocreatef() to perform optimization with numerical differentiation + +2. User chooses which multi-objective solver to use. At the present moment + only NBI (Normal Boundary Intersection) solver is implemented, which is + activated by calling minmosetalgonbi(). + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minmosetbc() for boundary constraints + b) minmosetlc2() for two-sided sparse linear constraints; + minmosetlc2dense() for two-sided dense linear constraints; + minmosetlc2mixed() for two-sided mixed sparse/dense constraints + c) minmosetnlc2() for two-sided nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minmosetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +5. User sets stopping conditions with minmosetcond(). + +6. Finally, user calls minmooptimize() function which takes algorithm + state and pointers (delegate, etc.) to the callback functions which + calculate F/C + +7. User calls minmoresults() to get the solution + +8. Optionally user may call minmorestartfrom() to solve another problem + with same M,N but another starting point. minmorestartfrom() allows to + reuse an already initialized optimizer structure. + + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreate(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minmostate* state, + ae_state *_state) +{ + + _minmostate_clear(state); + + ae_assert(n>=1, "MinMOCreate: N<1", _state); + ae_assert(m>=1, "MinMOCreate: M<1", _state); + ae_assert(x->cnt>=n, "MinMOCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is a scaling vector which can be set by minmosetscale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step means too large TRUNCATION errors, whilst too small step + means too large NUMERICAL errors. + 1.0E-4 can be good value to start from for a unit-scaled problem. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreatef(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minmostate* state, + ae_state *_state) +{ + + _minmostate_clear(state); + + ae_assert(n>=1, "MinMOCreateF: N<1", _state); + ae_assert(m>=1, "MinMOCreateF: M<1", _state); + ae_assert(x->cnt>=n, "MinMOCreateF: Length(X)=M, + where M is an objectives count + PolishSolutions-whether additional solution improving phase is needed + or not: + * if False, the original NBI as formulated by Das and + Dennis is used. It quickly produces good solutions, + but these solutions can be suboptimal (usually within + 0.1% of the optimal values). + The reason is that the original NBI formulation does + not account for degeneracies that allow significant + progress for one objective with no deterioration for + other objectives. + * if True, the original NBI is followed by the + additional solution polishing phase. This solver + mode is several times slower than the original NBI, + but produces better solutions. + + -- ALGLIB -- + Copyright 20.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetalgonbi(minmostate* state, + ae_int_t frontsize, + ae_bool polishsolutions, + ae_state *_state) +{ + + + ae_assert(frontsize>=state->m, "MinMOSetAlgoNBI: FrontSize<=M", _state); + state->solvertype = icase2(polishsolutions, 1, 0, _state); + state->frontsize = frontsize; +} + + +/************************************************************************* +This function sets boundary constraints for the MO optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinMORestartFrom(). + +You may combine boundary constraints with general linear ones - and with +nonlinear ones! Boundary constraints are handled more efficiently than +other types. Thus, if your problem has mixed constraints, you may +explicitly specify some of them as boundary and save some time/space. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetbc(minmostate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(bndl->cnt>=n, "MinMOSetBC: Length(BndL)cnt>=n, "MinMOSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinMOSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinMOSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense may help some MO solvers + to utilize efficient dense Level 3 BLAS for dense parts of the + problem. If your problem has both dense and sparse constraints, you + can use minmosetlc2mixed() function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2dense(minmostate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + minmosetlc2mixed(state, &state->dummysparse, 0, a, k, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2(minmostate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state) +{ + + + minmosetlc2mixed(state, a, k, &state->dummyr2, 0, al, au, _state); +} + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you can store them in the +sparse format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2mixed(minmostate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + + + n = state->n; + m = kdense+ksparse; + + /* + * Check input arguments + */ + ae_assert(ksparse>=0, "MinMOSetLC2Mixed: KSparse<0", _state); + ae_assert(ksparse==0||sparsegetncols(sparsea, _state)==n, "MinMOSetLC2: Cols(SparseA)<>N", _state); + ae_assert(ksparse==0||sparsegetnrows(sparsea, _state)==ksparse, "MinMOSetLC2: Rows(SparseA)<>K", _state); + ae_assert(kdense>=0, "MinMOSetLC2Mixed: KDense<0", _state); + ae_assert(kdense==0||densea->cols>=n, "MinMOSetLC2Mixed: Cols(DenseA)rows>=kdense, "MinMOSetLC2Mixed: Rows(DenseA)cnt>=kdense+ksparse, "MinMOSetLC2Mixed: Length(AL)cnt>=kdense+ksparse, "MinMOSetLC2Mixed: Length(AU)ptr.p_double[i], _state)||ae_isneginf(al->ptr.p_double[i], _state), "MinMOSetLC2Mixed: AL contains NAN or +INF", _state); + ae_assert(ae_isfinite(au->ptr.p_double[i], _state)||ae_isposinf(au->ptr.p_double[i], _state), "MinMOSetLC2Mixed: AU contains NAN or -INF", _state); + } + + /* + * Quick exit if needed + */ + if( m==0 ) + { + state->mdense = 0; + state->msparse = 0; + return; + } + + /* + * Prepare + */ + rvectorsetlengthatleast(&state->cl, m, _state); + rvectorsetlengthatleast(&state->cu, m, _state); + for(i=0; i<=m-1; i++) + { + state->cl.ptr.p_double[i] = al->ptr.p_double[i]; + state->cu.ptr.p_double[i] = au->ptr.p_double[i]; + } + state->mdense = kdense; + state->msparse = ksparse; + + /* + * Copy dense and sparse terms + */ + if( ksparse>0 ) + { + sparsecopytocrsbuf(sparsea, &state->sparsec, _state); + } + if( kdense>0 ) + { + rmatrixsetlengthatleast(&state->densec, kdense, n, _state); + rmatrixcopy(kdense, n, densea, 0, 0, &state->densec, 0, 0, _state); + } +} + + +/************************************************************************* +This function appends two-sided linear constraint AL<=A*x<=AU to dense +constraints list. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2dense(minmostate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + ae_assert(a->cnt>=n, "MinMOAddLC2Dense: Length(A)cl, state->msparse+state->mdense+1, _state); + rvectorgrowto(&state->cu, state->msparse+state->mdense+1, _state); + rmatrixgrowrowsto(&state->densec, state->mdense+1, n, _state); + for(i=0; i<=n-1; i++) + { + state->densec.ptr.pp_double[state->mdense][i] = a->ptr.p_double[i]; + } + state->cl.ptr.p_double[state->msparse+state->mdense] = al; + state->cu.ptr.p_double[state->msparse+state->mdense] = au; + inc(&state->mdense, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of sparse constraints. + +Constraint is passed in the compressed format: as a list of non-zero +entries of the coefficient vector A. Such approach is more efficient than +the dense storage for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2(minmostate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t offs; + ae_int_t offsdst; + ae_int_t n; + ae_int_t didx; + ae_int_t uidx; + + + n = state->n; + + /* + * Check inputs + */ + ae_assert(nnz>=0, "MinMOAddLC2: NNZ<0", _state); + ae_assert(idxa->cnt>=nnz, "MinMOAddLC2: Length(IdxA)cnt>=nnz, "MinMOAddLC2: Length(ValA)ptr.p_int[i]>=0&&idxa->ptr.p_int[i]msparse==0 ) + { + state->sparsec.matrixtype = 1; + state->sparsec.m = 0; + state->sparsec.n = n; + state->sparsec.ninitialized = 0; + ivectorsetlengthatleast(&state->sparsec.ridx, 1, _state); + state->sparsec.ridx.ptr.p_int[0] = 0; + } + ae_assert(state->sparsec.matrixtype==1&&state->sparsec.m==state->msparse, "MinMOAddLC2: integrity check failed!", _state); + + /* + * Reallocate inequality bounds + */ + rvectorgrowto(&state->cl, state->msparse+state->mdense+1, _state); + rvectorgrowto(&state->cu, state->msparse+state->mdense+1, _state); + for(i=state->msparse+state->mdense; i>=state->msparse+1; i--) + { + state->cl.ptr.p_double[i] = state->cl.ptr.p_double[i-1]; + state->cu.ptr.p_double[i] = state->cu.ptr.p_double[i-1]; + } + state->cl.ptr.p_double[state->msparse] = al; + state->cu.ptr.p_double[state->msparse] = au; + + /* + * Reallocate sparse storage + */ + offs = state->sparsec.ridx.ptr.p_int[state->msparse]; + ivectorgrowto(&state->sparsec.idx, offs+nnz, _state); + rvectorgrowto(&state->sparsec.vals, offs+nnz, _state); + ivectorgrowto(&state->sparsec.didx, state->msparse+1, _state); + ivectorgrowto(&state->sparsec.uidx, state->msparse+1, _state); + ivectorgrowto(&state->sparsec.ridx, state->msparse+2, _state); + + /* + * If NNZ=0, perform quick and simple row append. + */ + if( nnz==0 ) + { + state->sparsec.didx.ptr.p_int[state->msparse] = state->sparsec.ridx.ptr.p_int[state->msparse]; + state->sparsec.uidx.ptr.p_int[state->msparse] = state->sparsec.ridx.ptr.p_int[state->msparse]; + state->sparsec.ridx.ptr.p_int[state->msparse+1] = state->sparsec.ridx.ptr.p_int[state->msparse]; + inc(&state->sparsec.m, _state); + inc(&state->msparse, _state); + return; + } + + /* + * Now we are sure that SparseC contains properly initialized sparse + * matrix (or some appropriate dummy for M=0) and we have NNZ>0 + * (no need to care about degenerate cases). + * + * Append rows to SparseC: + * * append data + * * sort in place + * * merge duplicate indexes + * * compute DIdx and UIdx + * + */ + for(i=0; i<=nnz-1; i++) + { + state->sparsec.idx.ptr.p_int[offs+i] = idxa->ptr.p_int[i]; + state->sparsec.vals.ptr.p_double[offs+i] = vala->ptr.p_double[i]; + } + tagsortmiddleir(&state->sparsec.idx, &state->sparsec.vals, offs, nnz, _state); + offsdst = offs; + for(i=1; i<=nnz-1; i++) + { + if( state->sparsec.idx.ptr.p_int[offsdst]!=state->sparsec.idx.ptr.p_int[offs+i] ) + { + offsdst = offsdst+1; + state->sparsec.idx.ptr.p_int[offsdst] = state->sparsec.idx.ptr.p_int[offs+i]; + state->sparsec.vals.ptr.p_double[offsdst] = state->sparsec.vals.ptr.p_double[offs+i]; + } + else + { + state->sparsec.vals.ptr.p_double[offsdst] = state->sparsec.vals.ptr.p_double[offsdst]+state->sparsec.vals.ptr.p_double[offs+i]; + } + } + nnz = offsdst-offs+1; + uidx = -1; + didx = -1; + for(j=offs; j<=offsdst; j++) + { + k = state->sparsec.idx.ptr.p_int[j]; + if( k==state->msparse ) + { + didx = j; + } + else + { + if( k>state->msparse&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offsdst+1; + } + if( didx==-1 ) + { + didx = uidx; + } + state->sparsec.didx.ptr.p_int[state->msparse] = didx; + state->sparsec.uidx.ptr.p_int[state->msparse] = uidx; + state->sparsec.ridx.ptr.p_int[state->msparse+1] = offsdst+1; + state->sparsec.ninitialized = state->sparsec.ridx.ptr.p_int[state->msparse+1]; + inc(&state->sparsec.m, _state); + inc(&state->msparse, _state); +} + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2sparsefromdense(minmostate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t nzi; + ae_int_t offs; + ae_int_t n; + ae_int_t nnz; + ae_int_t didx; + ae_int_t uidx; + + + n = state->n; + + /* + * Check inputs + */ + ae_assert(da->cnt>=n, "MinMOAddLC2SparseFromDense: Length(DA)msparse==0 ) + { + state->sparsec.matrixtype = 1; + state->sparsec.m = 0; + state->sparsec.n = n; + state->sparsec.ninitialized = 0; + ivectorsetlengthatleast(&state->sparsec.ridx, 1, _state); + state->sparsec.ridx.ptr.p_int[0] = 0; + } + ae_assert(state->sparsec.matrixtype==1&&state->sparsec.m==state->msparse, "MinMOAddLC2SparseFromDense: integrity check failed!", _state); + + /* + * Reallocate inequality bounds + */ + rvectorgrowto(&state->cl, state->msparse+state->mdense+1, _state); + rvectorgrowto(&state->cu, state->msparse+state->mdense+1, _state); + for(i=state->msparse+state->mdense; i>=state->msparse+1; i--) + { + state->cl.ptr.p_double[i] = state->cl.ptr.p_double[i-1]; + state->cu.ptr.p_double[i] = state->cu.ptr.p_double[i-1]; + } + state->cl.ptr.p_double[state->msparse] = al; + state->cu.ptr.p_double[state->msparse] = au; + + /* + * Determine nonzeros count. + * Reallocate sparse storage. + */ + nnz = 0; + for(i=0; i<=n-1; i++) + { + if( !(da->ptr.p_double[i]==0.0) ) + { + nnz = nnz+1; + } + } + offs = state->sparsec.ridx.ptr.p_int[state->msparse]; + ivectorgrowto(&state->sparsec.idx, offs+nnz, _state); + rvectorgrowto(&state->sparsec.vals, offs+nnz, _state); + ivectorgrowto(&state->sparsec.didx, state->msparse+1, _state); + ivectorgrowto(&state->sparsec.uidx, state->msparse+1, _state); + ivectorgrowto(&state->sparsec.ridx, state->msparse+2, _state); + + /* + * If NNZ=0, perform quick and simple row append. + */ + if( nnz==0 ) + { + state->sparsec.didx.ptr.p_int[state->msparse] = state->sparsec.ridx.ptr.p_int[state->msparse]; + state->sparsec.uidx.ptr.p_int[state->msparse] = state->sparsec.ridx.ptr.p_int[state->msparse]; + state->sparsec.ridx.ptr.p_int[state->msparse+1] = state->sparsec.ridx.ptr.p_int[state->msparse]; + inc(&state->sparsec.m, _state); + inc(&state->msparse, _state); + return; + } + + /* + * Now we are sure that SparseC contains properly initialized sparse + * matrix (or some appropriate dummy for M=0) and we have NNZ>0 + * (no need to care about degenerate cases). + * + * Append rows to SparseC: + * * append data + * * compute DIdx and UIdx + * + */ + nzi = 0; + for(i=0; i<=n-1; i++) + { + if( !(da->ptr.p_double[i]==0.0) ) + { + state->sparsec.idx.ptr.p_int[offs+nzi] = i; + state->sparsec.vals.ptr.p_double[offs+nzi] = da->ptr.p_double[i]; + nzi = nzi+1; + } + } + uidx = -1; + didx = -1; + for(j=offs; j<=offs+nnz-1; j++) + { + k = state->sparsec.idx.ptr.p_int[j]; + if( k==state->msparse ) + { + didx = j; + } + else + { + if( k>state->msparse&&uidx==-1 ) + { + uidx = j; + break; + } + } + } + if( uidx==-1 ) + { + uidx = offs+nnz; + } + if( didx==-1 ) + { + didx = uidx; + } + state->sparsec.didx.ptr.p_int[state->msparse] = didx; + state->sparsec.uidx.ptr.p_int[state->msparse] = uidx; + state->sparsec.ridx.ptr.p_int[state->msparse+1] = offs+nnz; + state->sparsec.ninitialized = state->sparsec.ridx.ptr.p_int[state->msparse+1]; + inc(&state->sparsec.m, _state); + inc(&state->msparse, _state); +} + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinMO optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinMOOptimize() method as callbacks. + +MinMOOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first M components of F[] and first M rows of J[] correspond to + multiple objectives +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinMOSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinMOSetScale() function). + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetnlc2(minmostate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(nnlc>=0, "MinMOSetNLC2: NNLC<0", _state); + ae_assert(nl->cnt>=nnlc, "MinMOSetNLC2: Length(NL)cnt>=nnlc, "MinMOSetNLC2: Length(NU)nnlc = nnlc; + ae_vector_set_length(&state->fi, state->m+nnlc, _state); + ae_matrix_set_length(&state->j, state->m+nnlc, state->n, _state); + rallocv(nnlc, &state->nl, _state); + rallocv(nnlc, &state->nu, _state); + for(i=0; i<=nnlc-1; i++) + { + ae_assert(ae_isfinite(nl->ptr.p_double[i], _state)||ae_isneginf(nl->ptr.p_double[i], _state), "MinMOSetNLC2: NL[i] is +INF or NAN", _state); + ae_assert(ae_isfinite(nu->ptr.p_double[i], _state)||ae_isposinf(nu->ptr.p_double[i], _state), "MinMOSetNLC2: NU[i] is -INF or NAN", _state); + state->nl.ptr.p_double[i] = nl->ptr.p_double[i]; + state->nu.ptr.p_double[i] = nu->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets stopping conditions for inner iterations of the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinMOSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to an automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetcond(minmostate* state, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "MinMOSetCond: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinMOSetCond: negative EpsX", _state); + ae_assert(maxits>=0, "MinMOSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsx,(double)(0))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets scaling coefficients for the MO optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetscale(minmostate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinMOSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinMOSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinMOSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function turns on/off reporting of the Pareto front points. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function (if it +was provided to MinMOOptimize) every time we find a Pareto front point. + +NOTE: according to the communication protocol used by ALGLIB, the solver + passes two parameters to the rep() callback - a current point and a + target value at the current point. + However, because we solve a multi-objective problem, the target + parameter is not used and set to zero. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetxrep(minmostate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied Jacobian, and one which uses only function + vector and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + you should choose appropriate variant of MinMOOptimize() - one which + needs function vector AND Jacobian or one which needs ONLY function. + + Be careful to choose variant of MinMOOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinMOOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinMOOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinMOCreateF() | works FAILS + MinMOCreate() | FAILS works + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and MinMOOptimize() version. Attemps to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +ae_bool minmoiteration(minmostate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t nnlc; + ae_int_t i; + ae_int_t k; + double vleft; + double vright; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + nnlc = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + k = state->rstate.ia.ptr.p_int[4]; + vleft = state->rstate.ra.ptr.p_double[0]; + vright = state->rstate.ra.ptr.p_double[1]; + } + else + { + n = 359; + m = -58; + nnlc = -919; + i = -909; + k = 81; + vleft = 255.0; + vright = 74.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + + /* + * Routine body + */ + n = state->n; + m = state->m; + nnlc = state->nnlc; + + /* + * Initialize + */ + state->repterminationtype = 0; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repnfev = 0; + state->repbcerr = (double)(0); + state->repbcidx = -1; + state->replcerr = (double)(0); + state->replcidx = -1; + state->repnlcerr = (double)(0); + state->repnlcidx = -1; + state->repfrontsize = 0; + minmo_clearrequestfields(state, _state); + + /* + * Check correctness of constraint bounds + */ + for(i=0; i<=n-1; i++) + { + if( (ae_isfinite(state->bndl.ptr.p_double[i], _state)&&ae_isfinite(state->bndu.ptr.p_double[i], _state))&&ae_fp_greater(state->bndl.ptr.p_double[i]-state->bndu.ptr.p_double[i],state->repbcerr) ) + { + state->repterminationtype = -3; + state->repbcerr = state->bndl.ptr.p_double[i]-state->bndu.ptr.p_double[i]; + state->repbcidx = i; + } + } + for(i=0; i<=state->mdense+state->msparse-1; i++) + { + if( (ae_isfinite(state->cl.ptr.p_double[i], _state)&&ae_isfinite(state->cu.ptr.p_double[i], _state))&&ae_fp_greater(state->cl.ptr.p_double[i]-state->cu.ptr.p_double[i],state->replcerr) ) + { + state->repterminationtype = -3; + state->replcerr = state->cl.ptr.p_double[i]-state->cu.ptr.p_double[i]; + state->replcidx = i; + } + } + for(i=0; i<=state->nnlc-1; i++) + { + if( (ae_isfinite(state->nl.ptr.p_double[i], _state)&&ae_isfinite(state->nu.ptr.p_double[i], _state))&&ae_fp_greater(state->nl.ptr.p_double[i]-state->nu.ptr.p_double[i],state->repnlcerr) ) + { + state->repterminationtype = -3; + state->repnlcerr = state->nl.ptr.p_double[i]-state->nu.ptr.p_double[i]; + state->repnlcidx = i; + } + } + if( state->repterminationtype<0 ) + { + result = ae_false; + return result; + } + + /* + * NBI solver + */ + if( !(state->solvertype==0||state->solvertype==1) ) + { + goto lbl_9; + } + + /* + * Prepare NBI solver + */ + nbiscaleandinitbuf(&state->xstart, &state->s, n, m, state->frontsize, &state->bndl, &state->bndu, &state->sparsec, &state->densec, &state->cl, &state->cu, state->msparse, state->mdense, &state->nl, &state->nu, state->nnlc, state->epsx, state->maxits, state->solvertype==1, &state->nbi, _state); + + /* + * Perform iterations + */ +lbl_11: + if( !nbiiteration(&state->nbi, _state) ) + { + goto lbl_12; + } + + /* + * Forward request to caller + */ + if( !state->nbi.needfij ) + { + goto lbl_13; + } + + /* + * Evaluate target function/Jacobian + */ + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_15; + } + + /* + * Analytic Jacobian is provided. + * + * Unscale point and forward request. We use scaled NBI.BndL/NBI.U to make sure + * that points exactly at scaled bounds are mapped to points exactly at raw bounds. + */ + minmo_unscale(state, &state->nbi.x, &state->nbi.bndl, &state->nbi.bndu, &state->x, _state); + state->needfij = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfij = ae_false; + for(i=0; i<=m+nnlc-1; i++) + { + state->nbi.fi.ptr.p_double[i] = state->fi.ptr.p_double[i]; + rcopyrr(n, &state->j, i, &state->nbi.j, i, _state); + rmergemulvr(n, &state->s, &state->nbi.j, i, _state); + } + goto lbl_16; +lbl_15: + + /* + * Numerical differentiation + */ + rallocv(n, &state->xbase, _state); + rallocv(m+nnlc, &state->fm1, _state); + rallocv(m+nnlc, &state->fp1, _state); + rallocv(m+nnlc, &state->fm2, _state); + rallocv(m+nnlc, &state->fp2, _state); + minmo_unscale(state, &state->nbi.x, &state->nbi.bndl, &state->nbi.bndu, &state->xbase, _state); + k = 0; +lbl_17: + if( k>n-1 ) + { + goto lbl_19; + } + vleft = state->xbase.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + vright = state->xbase.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + if( !((state->hasbndl.ptr.p_bool[k]&&ae_fp_less(vleft,state->bndl.ptr.p_double[k]))||(state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(vright,state->bndu.ptr.p_double[k]))) ) + { + goto lbl_20; + } + + /* + * Box constraint is violated by the 4-point centered formula, use 2-point uncentered one + */ + if( state->hasbndl.ptr.p_bool[k]&&ae_fp_less(vleft,state->bndl.ptr.p_double[k]) ) + { + vleft = state->bndl.ptr.p_double[k]; + } + if( state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(vright,state->bndu.ptr.p_double[k]) ) + { + vright = state->bndu.ptr.p_double[k]; + } + ae_assert(ae_fp_less_eq(vleft,vright), "MinMO: integrity check 3445 failed", _state); + if( ae_fp_eq(vleft,vright) ) + { + + /* + * Fixed variable + */ + rsetc(m+nnlc, 0.0, &state->j, k, _state); + goto lbl_18; + } + + /* + * Compute target at VLeft and VRight + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = vleft; + state->needfi = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fm1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = vright; + state->needfi = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fp1, _state); + + /* + * Compute derivative + */ + raddv(m+nnlc, -1.0, &state->fm1, &state->fp1, _state); + rmulv(m+nnlc, (double)1/(vright-vleft), &state->fp1, _state); + rcopyvc(m+nnlc, &state->fp1, &state->j, k, _state); + goto lbl_21; +lbl_20: + + /* + * 4-point centered formula does not violate box constraints. + * Compute target values at grid points. + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-state->s.ptr.p_double[k]*state->diffstep; + state->needfi = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fm2, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]-0.5*state->s.ptr.p_double[k]*state->diffstep; + state->needfi = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fm1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+0.5*state->s.ptr.p_double[k]*state->diffstep; + state->needfi = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fp1, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = state->x.ptr.p_double[k]+state->s.ptr.p_double[k]*state->diffstep; + state->needfi = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->fp2, _state); + + /* + * Compute derivative + */ + raddv(m+nnlc, -1.0, &state->fm1, &state->fp1, _state); + raddv(m+nnlc, -1.0, &state->fm2, &state->fp2, _state); + rmulv(m+nnlc, 8.0, &state->fp1, _state); + raddv(m+nnlc, -1.0, &state->fp2, &state->fp1, _state); + rmulv(m+nnlc, (double)1/((double)6*state->diffstep*state->s.ptr.p_double[k]), &state->fp1, _state); + rcopyvc(m+nnlc, &state->fp1, &state->j, k, _state); +lbl_21: +lbl_18: + k = k+1; + goto lbl_17; +lbl_19: + rcopyv(n, &state->xbase, &state->x, _state); + state->needfi = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->needfi = ae_false; + rcopyv(m+nnlc, &state->fi, &state->nbi.fi, _state); + rcopym(m+nnlc, n, &state->j, &state->nbi.j, _state); +lbl_16: + inc(&state->repnfev, _state); + goto lbl_11; +lbl_13: + if( !state->nbi.xupdated ) + { + goto lbl_22; + } + + /* + * Report current point + */ + if( !state->xrep ) + { + goto lbl_24; + } + minmo_unscale(state, &state->nbi.x, &state->nbi.bndl, &state->nbi.bndu, &state->x, _state); + state->f = 0.0; + state->xupdated = ae_true; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->xupdated = ae_false; +lbl_24: + goto lbl_11; +lbl_22: + ae_assert(ae_false, "MINMO: unexpected callback request", _state); + goto lbl_11; +lbl_12: + + /* + * Done + */ + state->repfrontsize = state->nbi.repfrontsize; + rcopyallocm(state->repfrontsize, n+m, &state->nbi.repparetofront, &state->repparetofront, _state); + state->repinneriterationscount = state->nbi.repinneriterationscount; + state->repouteriterationscount = state->nbi.repouteriterationscount; + state->repterminationtype = state->nbi.repterminationtype; + state->repbcerr = state->nbi.repbcerr; + state->repbcidx = state->nbi.repbcidx; + state->replcerr = state->nbi.replcerr; + state->replcidx = state->nbi.replcidx; + state->repnlcerr = state->nbi.repnlcerr; + state->repnlcidx = state->nbi.repnlcidx; + result = ae_false; + return result; +lbl_9: + + /* + * Unexpected solver + */ + ae_assert(ae_false, "MINBO: unexpected solver type", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = nnlc; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = k; + state->rstate.ra.ptr.p_double[0] = vleft; + state->rstate.ra.ptr.p_double[1] = vright; + return result; +} + + +/************************************************************************* +MinMO results: the solution found, completion codes and additional +information. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + ParetoFront-array[FrontSize,N+M], approximate Pareto front. + Its columns have the following structure: + * first N columns are variable values + * next M columns are objectives at these points + Its rows have the following structure: + * first M rows contain solutions to single-objective tasks + with I-th row storing result for I-th objective being + minimized ignoring other ones. + Thus, ParetoFront[I,N+I] for 0<=I=0. + * no larger than the number passed to setalgo() + * for a single-objective task, FrontSize=1 is ALWAYS + returned, no matter what was specified during setalgo() + call. + * if the solver was prematurely terminated with + minnorequesttermination(), an incomplete Pareto front + will be returned (it may even have less than M rows) + * if a failure (negative completion code) was signaled, + FrontSize=0 will be returned + + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 constraint bounds are infeasible, i.e. we have + box/linear/nonlinear constraint with two bounds + present, and a lower one being greater than the + upper one. + Note: less obvious infeasibilities of constraints + do NOT trigger emergency completion; you + have to examine rep.bcerr/rep.lcerr/rep.nlcerr + to detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 8 user requested algorithm termination via + minmorequesttermination(), last accepted point is + returned. + + More information about fields of this structure can be + found in the comments on minmoreport datatype. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmoresults(const minmostate* state, + /* Real */ ae_matrix* paretofront, + ae_int_t* frontsize, + minmoreport* rep, + ae_state *_state) +{ + ae_int_t i; + + ae_matrix_clear(paretofront); + *frontsize = 0; + _minmoreport_clear(rep); + + rep->inneriterationscount = state->repinneriterationscount; + rep->outeriterationscount = state->repouteriterationscount; + rep->nfev = state->repnfev; + rep->terminationtype = state->repterminationtype; + rep->bcerr = state->repbcerr; + rep->bcidx = state->repbcidx; + rep->lcerr = state->replcerr; + rep->lcidx = state->replcidx; + rep->nlcerr = state->repnlcerr; + rep->nlcidx = state->repnlcidx; + if( rep->terminationtype>0 ) + { + *frontsize = state->repfrontsize; + ae_matrix_set_length(paretofront, *frontsize, state->n+state->m, _state); + rcopym(*frontsize, state->n+state->m, &state->repparetofront, paretofront, _state); + for(i=0; i<=*frontsize-1; i++) + { + rmergemulvr(state->n, &state->s, paretofront, i, _state); + } + } + else + { + *frontsize = 0; + ae_matrix_set_length(paretofront, 0, 0, _state); + } +} + + +/************************************************************************* +This subroutine submits request for the termination of the running +optimizer. + +It should be called from the user-supplied callback when user decides that +it is time to "smoothly" terminate optimization process, or from some other +thread. As a result, optimizer stops at the state which was "current +accepted" when termination request was submitted and returns error code 8 +(successful termination). + +Usually it results in an incomplete Pareto front being returned. + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorequesttermination(minmostate* state, ae_state *_state) +{ + + + state->nbi.userrequestedtermination = ae_true; +} + + +/************************************************************************* +This subroutine restarts algorithm from the new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorestartfrom(minmostate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MinMORestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; + minmo_clearrequestfields(state, _state); +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minmosetprotocolv1(minmostate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 4+1, _state); + ae_vector_set_length(&state->rstate.ra, 1+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void minmo_clearrequestfields(minmostate* state, ae_state *_state) +{ + + + state->needfi = ae_false; + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void minmo_minmoinitinternal(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minmostate* state, + ae_state *_state) +{ + + + + /* + * Initialize + */ + state->protocolversion = 1; + state->n = n; + state->m = m; + state->diffstep = diffstep; + rsetallocv(n, _state->v_neginf, &state->bndl, _state); + rsetallocv(n, _state->v_posinf, &state->bndu, _state); + bsetallocv(n, ae_false, &state->hasbndl, _state); + bsetallocv(n, ae_false, &state->hasbndu, _state); + rsetallocv(n, 1.0, &state->s, _state); + rcopyallocv(n, x, &state->xstart, _state); + minmosetlc2dense(state, &state->dummyr2, &state->dummyr1, &state->dummyr1, 0, _state); + minmosetnlc2(state, &state->dummyr1, &state->dummyr1, 0, _state); + minmosetcond(state, 0.0, 0, _state); + minmosetxrep(state, ae_false, _state); + minmosetalgonbi(state, 10, ae_true, _state); + minmorestartfrom(state, x, _state); + + /* + * Prepare RComm.X + */ + rallocv(n, &state->x, _state); +} + + +/************************************************************************* +Unscales X (converts from scaled variables to original ones), paying special +attention to box constraints (output is always feasible; active constraints +are mapped to active ones). +*************************************************************************/ +static void minmo_unscale(const minmostate* state, + /* Real */ const ae_vector* xs, + /* Real */ const ae_vector* scaledbndl, + /* Real */ const ae_vector* scaledbndu, + /* Real */ ae_vector* xu, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + + n = state->n; + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&xs->ptr.p_double[i]<=scaledbndl->ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&xs->ptr.p_double[i]>=scaledbndu->ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + continue; + } + xu->ptr.p_double[i] = xs->ptr.p_double[i]*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&xu->ptr.p_double[i]bndl.ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&xu->ptr.p_double[i]>state->bndu.ptr.p_double[i] ) + { + xu->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } +} + + +void _minmostate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minmostate *p = (minmostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->densec, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->sparsec, _state, make_automatic); + ae_vector_init(&p->cl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->nu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _nbistate_init(&p->nbi, _state, make_automatic); + ae_matrix_init(&p->repparetofront, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dummyr1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->dummyr2, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->dummysparse, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp2, 0, DT_REAL, _state, make_automatic); +} + + +void _minmostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minmostate *dst = (minmostate*)_dst; + const minmostate *src = (const minmostate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->diffstep = src->diffstep; + dst->solvertype = src->solvertype; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->xrep = src->xrep; + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + dst->frontsize = src->frontsize; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + dst->msparse = src->msparse; + dst->mdense = src->mdense; + ae_matrix_init_copy(&dst->densec, &src->densec, _state, make_automatic); + _sparsematrix_init_copy(&dst->sparsec, &src->sparsec, _state, make_automatic); + ae_vector_init_copy(&dst->cl, &src->cl, _state, make_automatic); + ae_vector_init_copy(&dst->cu, &src->cu, _state, make_automatic); + dst->nnlc = src->nnlc; + ae_vector_init_copy(&dst->nl, &src->nl, _state, make_automatic); + ae_vector_init_copy(&dst->nu, &src->nu, _state, make_automatic); + dst->protocolversion = src->protocolversion; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->needfij = src->needfij; + dst->needfi = src->needfi; + dst->xupdated = src->xupdated; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _nbistate_init_copy(&dst->nbi, &src->nbi, _state, make_automatic); + dst->repfrontsize = src->repfrontsize; + ae_matrix_init_copy(&dst->repparetofront, &src->repparetofront, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + dst->repbcerr = src->repbcerr; + dst->repbcidx = src->repbcidx; + dst->replcerr = src->replcerr; + dst->replcidx = src->replcidx; + dst->repnlcerr = src->repnlcerr; + dst->repnlcidx = src->repnlcidx; + ae_vector_init_copy(&dst->dummyr1, &src->dummyr1, _state, make_automatic); + ae_matrix_init_copy(&dst->dummyr2, &src->dummyr2, _state, make_automatic); + _sparsematrix_init_copy(&dst->dummysparse, &src->dummysparse, _state, make_automatic); + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->fm2, &src->fm2, _state, make_automatic); + ae_vector_init_copy(&dst->fm1, &src->fm1, _state, make_automatic); + ae_vector_init_copy(&dst->fp1, &src->fp1, _state, make_automatic); + ae_vector_init_copy(&dst->fp2, &src->fp2, _state, make_automatic); +} + + +void _minmostate_clear(void* _p) +{ + minmostate *p = (minmostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->xstart); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_matrix_clear(&p->densec); + _sparsematrix_clear(&p->sparsec); + ae_vector_clear(&p->cl); + ae_vector_clear(&p->cu); + ae_vector_clear(&p->nl); + ae_vector_clear(&p->nu); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstate); + _nbistate_clear(&p->nbi); + ae_matrix_clear(&p->repparetofront); + ae_vector_clear(&p->dummyr1); + ae_matrix_clear(&p->dummyr2); + _sparsematrix_clear(&p->dummysparse); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fm2); + ae_vector_clear(&p->fm1); + ae_vector_clear(&p->fp1); + ae_vector_clear(&p->fp2); +} + + +void _minmostate_destroy(void* _p) +{ + minmostate *p = (minmostate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->xstart); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_matrix_destroy(&p->densec); + _sparsematrix_destroy(&p->sparsec); + ae_vector_destroy(&p->cl); + ae_vector_destroy(&p->cu); + ae_vector_destroy(&p->nl); + ae_vector_destroy(&p->nu); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _rcommstate_destroy(&p->rstate); + _nbistate_destroy(&p->nbi); + ae_matrix_destroy(&p->repparetofront); + ae_vector_destroy(&p->dummyr1); + ae_matrix_destroy(&p->dummyr2); + _sparsematrix_destroy(&p->dummysparse); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fm2); + ae_vector_destroy(&p->fm1); + ae_vector_destroy(&p->fp1); + ae_vector_destroy(&p->fp2); +} + + +void _minmoreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minmoreport *p = (minmoreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minmoreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minmoreport *dst = (minmoreport*)_dst; + const minmoreport *src = (const minmoreport*)_src; + dst->inneriterationscount = src->inneriterationscount; + dst->outeriterationscount = src->outeriterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; + dst->bcerr = src->bcerr; + dst->bcidx = src->bcidx; + dst->lcerr = src->lcerr; + dst->lcidx = src->lcidx; + dst->nlcerr = src->nlcerr; + dst->nlcidx = src->nlcidx; +} + + +void _minmoreport_clear(void* _p) +{ + minmoreport *p = (minmoreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minmoreport_destroy(void* _p) +{ + minmoreport *p = (minmoreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + NONSMOOTH NONCONVEX OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS + +DESCRIPTION: + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear equality constraints Gi(x)=0 +* nonlinear inequality constraints Hi(x)<=0 + +IMPORTANT: see MinNSSetAlgoAGS for important information on performance + restrictions of AGS solver. + +REQUIREMENTS: +* starting point X0 must be feasible or not too far away from the feasible + set +* F(), G(), H() are continuous, locally Lipschitz and continuously (but + not necessarily twice) differentiable in an open dense subset of R^N. + Functions F(), G() and H() may be nonsmooth and non-convex. + Informally speaking, it means that functions are composed of large + differentiable "patches" with nonsmoothness having place only at the + boundaries between these "patches". + Most real-life nonsmooth functions satisfy these requirements. Say, + anything which involves finite number of abs(), min() and max() is very + likely to pass the test. + Say, it is possible to optimize anything of the following: + * f=abs(x0)+2*abs(x1) + * f=max(x0,x1) + * f=sin(max(x0,x1)+abs(x2)) +* for nonlinearly constrained problems: F() must be bounded from below + without nonlinear constraints (this requirement is due to the fact that, + contrary to box and linear constraints, nonlinear ones require special + handling). +* user must provide function value and gradient for F(), H(), G() at all + points where function/gradient can be calculated. If optimizer requires + value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), + where gradient is not defined, user may resolve tie arbitrarily (in our + case - return +1 or -1 at its discretion). +* NS solver supports numerical differentiation, i.e. it may differentiate + your function for you, but it results in 2N increase of function + evaluations. Not recommended unless you solve really small problems. See + minnscreatef() for more information on this functionality. + +USAGE: + +1. User initializes algorithm state with MinNSCreate() call and chooses + what NLC solver to use. There is some solver which is used by default, + with default settings, but you should NOT rely on default choice. It + may change in future releases of ALGLIB without notice, and no one can + guarantee that new solver will be able to solve your problem with + default settings. + + From the other side, if you choose solver explicitly, you can be pretty + sure that it will work with new ALGLIB releases. + + In the current release following solvers can be used: + * AGS solver (activated with MinNSSetAlgoAGS() function) + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) MinNSSetBC() for boundary constraints + b) MinNSSetLC() for linear constraints + c) MinNSSetNLC() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with MinNSSetScale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +4. User sets stopping conditions with MinNSSetCond(). + +5. Finally, user calls MinNSOptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F/G/H. + +7. User calls MinNSResults() to get solution + +8. Optionally user may call MinNSRestartFrom() to solve another problem + with same N but another starting point. MinNSRestartFrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTE: minnscreatef() function may be used if you do not have analytic + gradient. This function creates solver which uses numerical + differentiation with user-specified step. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreate(ae_int_t n, + /* Real */ const ae_vector* x, + minnsstate* state, + ae_state *_state) +{ + + _minnsstate_clear(state); + + ae_assert(n>=1, "MinNSCreate: N<1", _state); + ae_assert(x->cnt>=n, "MinNSCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, DiffStep>0. Algorithm performs + numerical differentiation with step for I-th variable + being equal to DiffStep*S[I] (here S[] is a scale vector, + set by minnssetscale() function). + Do not use too small steps, because it may lead to + catastrophic cancellation during intermediate calculations. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnsstate* state, + ae_state *_state) +{ + + _minnsstate_clear(state); + + ae_assert(n>=1, "MinNSCreateF: N<1", _state); + ae_assert(x->cnt>=n, "MinNSCreateF: Length(X)n; + ae_assert(bndl->cnt>=n, "MinNSSetBC: Length(BndL)cnt>=n, "MinNSSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinNSSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinNSSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets linear constraints. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE: linear (non-bound) constraints are satisfied only approximately: + +* there always exists some minor violation (about current sampling radius + in magnitude during optimization, about EpsX in the solution) due to use + of penalty method to handle constraints. +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. + +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetlc(minnsstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(k>=0, "MinNSSetLC: K<0", _state); + ae_assert(c->cols>=n+1||k==0, "MinNSSetLC: Cols(C)rows>=k, "MinNSSetLC: Rows(C)cnt>=k, "MinNSSetLC: Length(CT)nec = 0; + state->nic = 0; + return; + } + + /* + * Equality constraints are stored first, in the upper + * NEC rows of State.CLEIC matrix. Inequality constraints + * are stored in the next NIC rows. + * + * NOTE: we convert inequality constraints to the form + * A*x<=b before copying them. + */ + rmatrixsetlengthatleast(&state->cleic, k, n+1, _state); + state->nec = 0; + state->nic = 0; + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]==0 ) + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + state->nec = state->nec+1; + } + } + for(i=0; i<=k-1; i++) + { + if( ct->ptr.p_int[i]!=0 ) + { + if( ct->ptr.p_int[i]>0 ) + { + ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + else + { + ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n)); + } + state->nic = state->nic+1; + } + } +} + + +/************************************************************************* +This function sets nonlinear constraints. + +In fact, this function sets NUMBER of nonlinear constraints. Constraints +itself (constraint functions) are passed to minnsoptimize() method. This +method requires user-defined vector function F[] and its Jacobian J[], +where: +* first component of F[] and first row of Jacobian J[] correspond to + function being minimized +* next NLEC components of F[] (and rows of J) correspond to nonlinear + equality constraints G_i(x)=0 +* next NLIC components of F[] (and rows of J) correspond to nonlinear + inequality constraints H_i(x)<=0 + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear ones. It may help optimizer to handle them more + efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 + NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to scale specified by + minnssetscale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for correct + scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you + to scale nonlinear constraints in such way that I-th component of + dG/dX (or dH/dx) has approximately unit magnitude (for problems + with unit scale) or has magnitude approximately equal to 1/S[i] + (where S is a scale set by minnssetscale() function). + +NOTE 3: nonlinear constraints are always hard to handle, no matter what + algorithm you try to use. Even basic box/linear constraints modify + function curvature by adding valleys and ridges. However, + nonlinear constraints add valleys which are very hard to follow + due to their "curved" nature. + + It means that optimization with single nonlinear constraint may be + significantly slower than optimization with multiple linear ones. + It is normal situation, and we recommend you to carefully choose + Rho parameter of minnssetalgoags(), because too large value may + slow down convergence. + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetnlc(minnsstate* state, + ae_int_t nlec, + ae_int_t nlic, + ae_state *_state) +{ + + + ae_assert(nlec>=0, "MinNSSetNLC: NLEC<0", _state); + ae_assert(nlic>=0, "MinNSSetNLC: NLIC<0", _state); + state->ng = nlec; + state->nh = nlic; + ae_vector_set_length(&state->fi, 1+state->ng+state->nh, _state); + ae_matrix_set_length(&state->j, 1+state->ng+state->nh, state->n, _state); +} + + +/************************************************************************* +This function sets stopping conditions for iterations of optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The AGS solver finishes its work if on k+1-th iteration + sampling radius decreases below EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection. We do not recommend you to rely on default +choice in production code. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetcond(minnsstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsx, _state), "MinNSSetCond: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinNSSetCond: negative EpsX", _state); + ae_assert(maxits>=0, "MinNSSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsx,(double)(0))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetscale(minnsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MinNSSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinNSSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinNSSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function tells MinNS unit to use AGS (adaptive gradient sampling) +algorithm for nonsmooth constrained optimization. This algorithm is a +slight modification of one described in "An Adaptive Gradient Sampling +Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. + +This optimizer has following benefits and drawbacks: ++ robustness; it can be used with nonsmooth and nonconvex functions. ++ relatively easy tuning; most of the metaparameters are easy to select. +- it has convergence of steepest descent, slower than CG/LBFGS. +- each iteration involves evaluation of ~2N gradient values and solution + of 2Nx2N quadratic programming problem, which limits applicability of + algorithm by small-scale problems (up to 50-100). + +IMPORTANT: this algorithm has convergence guarantees, i.e. it will + steadily move towards some stationary point of the function. + + However, "stationary point" does not always mean "solution". + Nonsmooth problems often have "flat spots", i.e. areas where + function do not change at all. Such "flat spots" are stationary + points by definition, and algorithm may be caught here. + + Nonsmooth CONVEX tasks are not prone to this problem. Say, if + your function has form f()=MAX(f0,f1,...), and f_i are convex, + then f() is convex too and you have guaranteed convergence to + solution. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Radius - initial sampling radius, >=0. + + Internally multiplied by vector of per-variable scales + specified by minnssetscale()). + + You should select relatively large sampling radius, roughly + proportional to scaled length of the first steps of the + algorithm. Something close to 0.1 in magnitude should be + good for most problems. + + AGS solver can automatically decrease radius, so too large + radius is not a problem (assuming that you won't choose + so large radius that algorithm will sample function in + too far away points, where gradient value is irrelevant). + + Too small radius won't cause algorithm to fail, but it may + slow down algorithm (it may have to perform too short + steps). + Penalty - penalty coefficient for nonlinear constraints: + * for problem with nonlinear constraints should be some + problem-specific positive value, large enough that + penalty term changes shape of the function. + Starting from some problem-specific value penalty + coefficient becomes large enough to exactly enforce + nonlinear constraints; larger values do not improve + precision. + Increasing it too much may slow down convergence, so you + should choose it carefully. + * can be zero for problems WITHOUT nonlinear constraints + (i.e. for unconstrained ones or ones with just box or + linear constraints) + * if you specify zero value for problem with at least one + nonlinear constraint, algorithm will terminate with + error code -1. + +ALGORITHM OUTLINE + +The very basic outline of unconstrained AGS algorithm is given below: + +0. If sampling radius is below EpsX or we performed more then MaxIts + iterations - STOP. +1. sample O(N) gradient values at random locations around current point; + informally speaking, this sample is an implicit piecewise linear model + of the function, although algorithm formulation does not mention that + explicitly +2. solve quadratic programming problem in order to find descent direction +3. if QP solver tells us that we are near solution, decrease sampling + radius and move to (0) +4. perform backtracking line search +5. after moving to new point, goto (0) + +Constraint handling details: +* box constraints are handled exactly by algorithm +* linear/nonlinear constraints are handled by adding L1 penalty. Because + our solver can handle nonsmoothness, we can use L1 penalty function, + which is an exact one (i.e. exact solution is returned under such + penalty). +* penalty coefficient for linear constraints is chosen automatically; + however, penalty coefficient for nonlinear constraints must be specified + by user. + +===== TRACING AGS SOLVER ================================================= + +AGS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'AGS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'AGS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'AGS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'AGS.DETAILED.SAMPLE'- + for output of points being visited , search directions + and gradient sample. May take a LOT of space , do not + use it on problems with more that several tens of vars. + This symbol also implicitly defines 'AGS' and + 'AGS.DETAILED'. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("AGS,PREC.F6", "path/to/trace.log") +> + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetalgoags(minnsstate* state, + double radius, + double penalty, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(radius, _state), "MinNSSetAlgoAGS: Radius is not finite", _state); + ae_assert(ae_fp_greater(radius,(double)(0)), "MinNSSetAlgoAGS: Radius<=0", _state); + ae_assert(ae_isfinite(penalty, _state), "MinNSSetAlgoAGS: Penalty is not finite", _state); + ae_assert(ae_fp_greater_eq(penalty,0.0), "MinNSSetAlgoAGS: Penalty<0", _state); + state->agsrhononlinear = penalty; + state->agsradius = radius; + state->solvertype = 0; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to minnsoptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnssetxrep(minnsstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrequesttermination(minnsstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied Jacobian, and one which uses only function + vector and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + you should choose appropriate variant of minnsoptimize() - one which + accepts function AND Jacobian or one which accepts ONLY function. + + Be careful to choose variant of minnsoptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to minnsoptimize() and specific + function used to create optimizer. + + + | USER PASSED TO minnsoptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + minnscreatef() | works FAILS + minnscreate() | FAILS works + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and minnsoptimize() version. Attemps to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool minnsiteration(minnsstate* state, ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t ng; + ae_int_t nh; + double v; + double xp; + double xm; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + j = state->rstate.ia.ptr.p_int[1]; + k = state->rstate.ia.ptr.p_int[2]; + n = state->rstate.ia.ptr.p_int[3]; + nec = state->rstate.ia.ptr.p_int[4]; + nic = state->rstate.ia.ptr.p_int[5]; + ng = state->rstate.ia.ptr.p_int[6]; + nh = state->rstate.ia.ptr.p_int[7]; + v = state->rstate.ra.ptr.p_double[0]; + xp = state->rstate.ra.ptr.p_double[1]; + xm = state->rstate.ra.ptr.p_double[2]; + } + else + { + i = 359; + j = -58; + k = -919; + n = -909; + nec = 81; + nic = 255; + ng = 74; + nh = -788; + v = 809.0; + xp = 205.0; + xm = -838.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + + /* + * Init + */ + state->replcerr = 0.0; + state->repnlcerr = 0.0; + state->repterminationtype = 0; + state->repinneriterationscount = 0; + state->repouteriterationscount = 0; + state->repnfev = 0; + state->repvaridx = 0; + state->repfuncidx = 0; + state->userterminationneeded = ae_false; + state->dbgncholesky = 0; + n = state->n; + nec = state->nec; + nic = state->nic; + ng = state->ng; + nh = state->nh; + minns_clearrequestfields(state, _state); + + /* + * AGS solver + */ + if( state->solvertype!=0 ) + { + goto lbl_4; + } + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + rvectorsetlengthatleast(&state->xbase, n, _state); + rvectorsetlengthatleast(&state->fbase, 1+ng+nh, _state); + rvectorsetlengthatleast(&state->fm, 1+ng+nh, _state); + rvectorsetlengthatleast(&state->fp, 1+ng+nh, _state); + } + rvectorsetlengthatleast(&state->xscaled, n, _state); + rvectorsetlengthatleast(&state->rawg, n, _state); + rvectorsetlengthatleast(&state->meritg, n, _state); + ae_vector_set_length(&state->rstateags.ia, 13+1, _state); + ae_vector_set_length(&state->rstateags.ba, 5+1, _state); + ae_vector_set_length(&state->rstateags.ra, 10+1, _state); + state->rstateags.stage = -1; +lbl_6: + if( !minns_agsiteration(state, _state) ) + { + goto lbl_7; + } + rcopyv(n, &state->x, &state->xscaled, _state); + minns_unscalepointbc(state, &state->x, _state); + + /* + * Numerical differentiation (if needed) - intercept NeedFiJ + * request and replace it by sequence of NeedFi requests + */ + if( !(ae_fp_neq(state->diffstep,(double)(0))&&state->needfij) ) + { + goto lbl_8; + } + state->needfij = ae_false; + state->needfi = ae_true; + ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + ae_v_move(&state->fbase.ptr.p_double[0], 1, &state->fi.ptr.p_double[0], 1, ae_v_len(0,ng+nh)); + state->repnfev = state->repnfev+1; + k = 0; +lbl_10: + if( k>n-1 ) + { + goto lbl_12; + } + v = state->xbase.ptr.p_double[k]; + xm = v-state->diffstep*state->s.ptr.p_double[k]; + xp = v+state->diffstep*state->s.ptr.p_double[k]; + if( state->hasbndl.ptr.p_bool[k]&&ae_fp_less(xm,state->bndl.ptr.p_double[k]) ) + { + xm = state->bndl.ptr.p_double[k]; + } + if( state->hasbndu.ptr.p_bool[k]&&ae_fp_greater(xp,state->bndu.ptr.p_double[k]) ) + { + xp = state->bndu.ptr.p_double[k]; + } + ae_assert(ae_fp_less_eq(xm,xp), "MinNS: integrity check failed (3y634)", _state); + if( ae_fp_eq(xm,xp) ) + { + goto lbl_13; + } + + /* + * Compute F(XM) and F(XP) + */ + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = xm; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + rcopyv(1+ng+nh, &state->fi, &state->fm, _state); + rcopyv(n, &state->xbase, &state->x, _state); + state->x.ptr.p_double[k] = xp; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + rcopyv(1+ng+nh, &state->fi, &state->fp, _state); + + /* + * Compute subgradient at XBase + */ + rcopymulvc(1+ng+nh, (double)1/(xp-xm), &state->fp, &state->j, k, _state); + raddvc(1+ng+nh, -(double)1/(xp-xm), &state->fm, &state->j, k, _state); + state->repnfev = state->repnfev+2; + goto lbl_14; +lbl_13: + rsetc(1+ng+nh, 0.0, &state->j, k, _state); +lbl_14: + k = k+1; + goto lbl_10; +lbl_12: + + /* + * Restore previous values of fields and continue + */ + rcopyv(n, &state->xscaled, &state->x, _state); + rcopyv(1+ng+nh, &state->fbase, &state->fi, _state); + state->needfi = ae_false; + state->needfij = ae_true; + goto lbl_9; +lbl_8: + + /* + * Forward request to caller + */ + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + inc(&state->repnfev, _state); + rcopyv(n, &state->xscaled, &state->x, _state); +lbl_9: + + /* + * Postprocess Jacobian: scale and produce 'raw' and 'merit' functions + */ + for(i=0; i<=ng+nh; i++) + { + rmergemulvr(n, &state->s, &state->j, i, _state); + } + state->rawf = state->fi.ptr.p_double[0]; + state->meritf = state->fi.ptr.p_double[0]; + rcopyrv(n, &state->j, 0, &state->rawg, _state); + rcopyrv(n, &state->j, 0, &state->meritg, _state); + for(i=0; i<=nec+nic-1; i++) + { + v = rdotvr(n, &state->x, &state->scaledcleic, i, _state)-state->scaledcleic.ptr.pp_double[i][n]; + if( i>=nec&&ae_fp_less(v,(double)(0)) ) + { + continue; + } + state->meritf = state->meritf+state->rholinear*ae_fabs(v, _state); + raddrv(n, state->rholinear*(double)ae_sign(v, _state), &state->scaledcleic, i, &state->meritg, _state); + } + for(i=1; i<=ng+nh; i++) + { + v = state->fi.ptr.p_double[i]; + if( i<=ng&&ae_fp_eq(v,(double)(0)) ) + { + continue; + } + if( i>ng&&ae_fp_less_eq(v,(double)(0)) ) + { + continue; + } + state->meritf = state->meritf+state->agsrhononlinear*ae_fabs(v, _state); + raddrv(n, state->agsrhononlinear*(double)ae_sign(v, _state), &state->j, i, &state->meritg, _state); + } + + /* + * Done + */ + goto lbl_6; + goto lbl_6; +lbl_7: + result = ae_false; + return result; +lbl_4: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ia.ptr.p_int[1] = j; + state->rstate.ia.ptr.p_int[2] = k; + state->rstate.ia.ptr.p_int[3] = n; + state->rstate.ia.ptr.p_int[4] = nec; + state->rstate.ia.ptr.p_int[5] = nic; + state->rstate.ia.ptr.p_int[6] = ng; + state->rstate.ia.ptr.p_int[7] = nh; + state->rstate.ra.ptr.p_double[0] = v; + state->rstate.ra.ptr.p_double[1] = xp; + state->rstate.ra.ptr.p_double[2] = xm; + return result; +} + + +/************************************************************************* +MinNS results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 box constraints are inconsistent + * -1 inconsistent parameters were passed: + * penalty parameter for minnssetalgoags() is zero, + but we have nonlinear constraints set by minnssetnlc() + * 2 sampling radius decreased below epsx + * 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + * 8 User requested termination via minnsrequesttermination() + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresults(const minnsstate* state, + /* Real */ ae_vector* x, + minnsreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minnsreport_clear(rep); + + minnsresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* + +Buffered implementation of minnsresults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresultsbuf(const minnsstate* state, + /* Real */ ae_vector* x, + minnsreport* rep, + ae_state *_state) +{ + ae_int_t i; + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + rep->iterationscount = state->repinneriterationscount; + rep->nfev = state->repnfev; + rep->varidx = state->repvaridx; + rep->funcidx = state->repfuncidx; + rep->terminationtype = state->repterminationtype; + rep->cerr = ae_maxreal(state->replcerr, state->repnlcerr, _state); + rep->lcerr = state->replcerr; + rep->nlcerr = state->repnlcerr; + if( state->repterminationtype>0 ) + { + ae_v_move(&x->ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + } + else + { + for(i=0; i<=state->n-1; i++) + { + x->ptr.p_double[i] = _state->v_nan; + } + } +} + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + X - new starting point. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrestartfrom(minnsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MinNSRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 7+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + minns_clearrequestfields(state, _state); +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minnssetprotocolv1(minnsstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 7+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void minns_clearrequestfields(minnsstate* state, ae_state *_state) +{ + + + state->needfi = ae_false; + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Internal initialization subroutine. +Sets default NLC solver with default criteria. +*************************************************************************/ +static void minns_minnsinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnsstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + state->protocolversion = 1; + state->agsinitstp = 0.2; + state->agsstattold = ae_sqrt(ae_machineepsilon, _state); + state->agsshortstpabs = 1.0E-10; + state->agsshortstprel = 0.75; + state->agsshortf = (double)10*ae_machineepsilon; + state->agsrhononlinear = 0.0; + state->agsraddecay = 0.2; + state->agsalphadecay = 0.5; + state->agsdecrease = 0.1; + state->agsmaxraddecays = 50; + state->agsmaxbacktrack = 20; + state->agsmaxbacktracknonfull = 8; + state->agspenaltylevel = 50.0; + state->agspenaltyincrease = 100.0; + state->agsminupdate = ae_maxint(5, n/2, _state); + state->agssamplesize = ae_maxint(2*n+1, state->agsminupdate+1, _state); + state->agsshortlimit = 4+state->agssamplesize/state->agsminupdate; + + /* + * Initialize other params + */ + state->n = n; + state->diffstep = diffstep; + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->hasbndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->hasbndu, n, _state); + ae_vector_set_length(&state->s, n, _state); + ae_vector_set_length(&state->xstart, n, _state); + ae_vector_set_length(&state->xc, n, _state); + ae_vector_set_length(&state->xn, n, _state); + ae_vector_set_length(&state->d, n, _state); + ae_vector_set_length(&state->x, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->xstart.ptr.p_double[i] = x->ptr.p_double[i]; + state->xc.ptr.p_double[i] = x->ptr.p_double[i]; + } + minnssetlc(state, &c, &ct, 0, _state); + minnssetnlc(state, 0, 0, _state); + minnssetcond(state, 0.0, 0, _state); + minnssetxrep(state, ae_false, _state); + minnssetalgoags(state, 0.1, 1000.0, _state); + minnsrestartfrom(state, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function performs actual processing for AUL algorith. It expects that +caller redirects its reverse communication requests NeedFiJ/XUpdated to +external user who will provide analytic derivative (or handle reports about +progress). + +In case external user does not have analytic derivative, it is responsibility +of caller to intercept NeedFiJ request and replace it with appropriate +numerical differentiation scheme. + + -- ALGLIB -- + Copyright 06.06.2015 by Bochkanov Sergey +*************************************************************************/ +static ae_bool minns_agsiteration(minnsstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t ng; + ae_int_t nh; + ae_int_t i; + ae_int_t j; + ae_int_t k; + double radius0; + double radius; + ae_int_t radiusdecays; + double alpha; + double recommendedstep; + double dhd; + double dnrminf; + double v; + double vv; + ae_int_t maxsamplesize; + ae_int_t cursamplesize; + double v0; + double v1; + ae_bool b; + ae_bool alphadecreased; + ae_int_t shortstepscnt; + ae_int_t backtrackits; + ae_int_t maxbacktrackits; + ae_bool fullsample; + double currentf0; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_bool dotracesample; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstateags.stage>=0 ) + { + n = state->rstateags.ia.ptr.p_int[0]; + nec = state->rstateags.ia.ptr.p_int[1]; + nic = state->rstateags.ia.ptr.p_int[2]; + ng = state->rstateags.ia.ptr.p_int[3]; + nh = state->rstateags.ia.ptr.p_int[4]; + i = state->rstateags.ia.ptr.p_int[5]; + j = state->rstateags.ia.ptr.p_int[6]; + k = state->rstateags.ia.ptr.p_int[7]; + radiusdecays = state->rstateags.ia.ptr.p_int[8]; + maxsamplesize = state->rstateags.ia.ptr.p_int[9]; + cursamplesize = state->rstateags.ia.ptr.p_int[10]; + shortstepscnt = state->rstateags.ia.ptr.p_int[11]; + backtrackits = state->rstateags.ia.ptr.p_int[12]; + maxbacktrackits = state->rstateags.ia.ptr.p_int[13]; + b = state->rstateags.ba.ptr.p_bool[0]; + alphadecreased = state->rstateags.ba.ptr.p_bool[1]; + fullsample = state->rstateags.ba.ptr.p_bool[2]; + dotrace = state->rstateags.ba.ptr.p_bool[3]; + dodetailedtrace = state->rstateags.ba.ptr.p_bool[4]; + dotracesample = state->rstateags.ba.ptr.p_bool[5]; + radius0 = state->rstateags.ra.ptr.p_double[0]; + radius = state->rstateags.ra.ptr.p_double[1]; + alpha = state->rstateags.ra.ptr.p_double[2]; + recommendedstep = state->rstateags.ra.ptr.p_double[3]; + dhd = state->rstateags.ra.ptr.p_double[4]; + dnrminf = state->rstateags.ra.ptr.p_double[5]; + v = state->rstateags.ra.ptr.p_double[6]; + vv = state->rstateags.ra.ptr.p_double[7]; + v0 = state->rstateags.ra.ptr.p_double[8]; + v1 = state->rstateags.ra.ptr.p_double[9]; + currentf0 = state->rstateags.ra.ptr.p_double[10]; + } + else + { + n = 939; + nec = -526; + nic = 763; + ng = -541; + nh = -698; + i = -900; + j = -318; + k = -940; + radiusdecays = 1016; + maxsamplesize = -229; + cursamplesize = -536; + shortstepscnt = 487; + backtrackits = -115; + maxbacktrackits = 886; + b = ae_false; + alphadecreased = ae_false; + fullsample = ae_true; + dotrace = ae_true; + dodetailedtrace = ae_true; + dotracesample = ae_true; + radius0 = 922.0; + radius = -154.0; + alpha = 306.0; + recommendedstep = -1011.0; + dhd = 951.0; + dnrminf = -463.0; + v = 88.0; + vv = -861.0; + v0 = -678.0; + v1 = -731.0; + currentf0 = -675.0; + } + if( state->rstateags.stage==0 ) + { + goto lbl_0; + } + if( state->rstateags.stage==1 ) + { + goto lbl_1; + } + if( state->rstateags.stage==2 ) + { + goto lbl_2; + } + if( state->rstateags.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + ae_assert(state->solvertype==0, "MinNS: internal error", _state); + n = state->n; + nec = state->nec; + nic = state->nic; + ng = state->ng; + nh = state->nh; + dotrace = ae_is_trace_enabled("AGS"); + dodetailedtrace = dotrace&&ae_is_trace_enabled("AGS.DETAILED"); + dotracesample = dodetailedtrace&&ae_is_trace_enabled("AGS.DETAILED.SAMPLE"); + + /* + * Trace output (if needed) + */ + if( dotrace ) + { + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// AGS SOLVER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + } + + /* + * Check consistency of parameters + */ + if( ng+nh>0&&ae_fp_eq(state->agsrhononlinear,(double)(0)) ) + { + if( dotrace ) + { + ae_trace("> inconsistent parameters detected, stopping\n\n"); + } + state->repterminationtype = -1; + result = ae_false; + return result; + } + + /* + * Allocate arrays. + */ + rvectorsetlengthatleast(&state->colmax, n, _state); + rvectorsetlengthatleast(&state->diagh, n, _state); + rvectorsetlengthatleast(&state->signmin, n, _state); + rvectorsetlengthatleast(&state->signmax, n, _state); + maxsamplesize = state->agssamplesize; + rmatrixsetlengthatleast(&state->samplex, maxsamplesize+1, n, _state); + rmatrixsetlengthatleast(&state->samplegm, maxsamplesize+1, n, _state); + rmatrixsetlengthatleast(&state->samplegmbc, maxsamplesize+1, n, _state); + rvectorsetlengthatleast(&state->samplef, maxsamplesize+1, _state); + + /* + * Prepare optimizer + */ + rvectorsetlengthatleast(&state->tmp0, maxsamplesize, _state); + rvectorsetlengthatleast(&state->tmp1, maxsamplesize, _state); + ivectorsetlengthatleast(&state->tmp3, 1, _state); + rmatrixsetlengthatleast(&state->tmp2, 1, maxsamplesize+1, _state); + for(i=0; i<=maxsamplesize-1; i++) + { + state->tmp0.ptr.p_double[i] = 0.0; + state->tmp1.ptr.p_double[i] = _state->v_posinf; + } + + /* + * Prepare RNG, seed it with fixed values so + * that each run on same problem yeilds same results + */ + hqrndseed(7235, 98532, &state->agsrs, _state); + + /* + * Prepare initial point subject to current bound constraints and + * perform scaling of bound constraints, linear constraints, point itself + */ + rvectorsetlengthatleast(&state->scaledbndl, n, _state); + rvectorsetlengthatleast(&state->scaledbndu, n, _state); + for(i=0; i<=n-1; i++) + { + + /* + * Check and scale constraints + */ + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_less(state->bndu.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + if( dotrace ) + { + ae_trace("> inconsistent box constraints detected, stopping\n\n"); + } + state->repterminationtype = -3; + result = ae_false; + return result; + } + if( state->hasbndl.ptr.p_bool[i] ) + { + state->scaledbndl.ptr.p_double[i] = state->bndl.ptr.p_double[i]/state->s.ptr.p_double[i]; + } + else + { + state->scaledbndl.ptr.p_double[i] = _state->v_neginf; + } + if( state->hasbndu.ptr.p_bool[i] ) + { + state->scaledbndu.ptr.p_double[i] = state->bndu.ptr.p_double[i]/state->s.ptr.p_double[i]; + } + else + { + state->scaledbndu.ptr.p_double[i] = _state->v_posinf; + } + if( state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i] ) + { + ae_assert(ae_fp_less_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity check failed (dfdf)", _state); + } + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->bndl.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + ae_assert(ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity check failed (dsgh)", _state); + } + + /* + * Scale and constrain point + */ + state->xc.ptr.p_double[i] = state->xstart.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + continue; + } + state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]/state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->scaledbndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + state->xc.ptr.p_double[i] = state->scaledbndu.ptr.p_double[i]; + } + } + rmatrixsetlengthatleast(&state->scaledcleic, nec+nic, n+1, _state); + for(i=0; i<=nec+nic-1; i++) + { + + /* + * Scale and normalize linear constraints + */ + vv = 0.0; + for(j=0; j<=n-1; j++) + { + v = state->cleic.ptr.pp_double[i][j]*state->s.ptr.p_double[j]; + state->scaledcleic.ptr.pp_double[i][j] = v; + vv = vv+v*v; + } + vv = ae_sqrt(vv, _state); + state->scaledcleic.ptr.pp_double[i][n] = state->cleic.ptr.pp_double[i][n]; + if( ae_fp_greater(vv,(double)(0)) ) + { + for(j=0; j<=n; j++) + { + state->scaledcleic.ptr.pp_double[i][j] = state->scaledcleic.ptr.pp_double[i][j]/vv; + } + } + } + + /* + * Main cycle + * + * We maintain several variables during iteration: + * * RecommendedStep- current estimate of recommended step length; + * must be Radius0 on first entry + * * Radius - current sampling radius + * * CurSampleSize - current sample size (may change in future versions) + * * FullSample - whether we have full sample, or only partial one + * * RadiusDecays - total number of decreases performed for sampling radius + */ + radius = state->agsradius; + radius0 = radius; + recommendedstep = ae_minreal(radius0, state->agsinitstp, _state); + cursamplesize = 1; + radiusdecays = 0; + shortstepscnt = 0; + fullsample = ae_false; + state->rholinear = 0.0; +lbl_4: + if( ae_false ) + { + goto lbl_5; + } + if( dotrace ) + { + ae_trace("\n=== ITERATION %5d STARTED ========================================================================\n", + (int)(state->repinneriterationscount)); + } + + /* + * First phase of iteration - central point: + * + * 1. evaluate function at central point - first entry in sample. + * Its status is ignored, it is always recalculated. + * 2. report point and check gradient/function value for NAN/INF + * 3. check penalty coefficients for linear terms; increase them + * if directional derivative of function being optimized (not + * merit function!) is larger than derivative of penalty. + * 4. update report on constraint violation + */ + cursamplesize = ae_maxint(cursamplesize, 1, _state); + ae_v_move(&state->samplex.ptr.pp_double[0][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minns_clearrequestfields(state, _state); + state->needfij = ae_true; + state->rstateags.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfij = ae_false; + currentf0 = state->rawf; + state->replcerr = 0.0; + for(i=0; i<=nec+nic-1; i++) + { + v = -state->scaledcleic.ptr.pp_double[i][n]; + for(j=0; j<=n-1; j++) + { + v = v+state->scaledcleic.ptr.pp_double[i][j]*state->xc.ptr.p_double[j]; + } + if( i>=nec&&ae_fp_less_eq(v,(double)(0)) ) + { + continue; + } + state->replcerr = ae_maxreal(state->replcerr, ae_fabs(v, _state), _state); + } + state->repnlcerr = 0.0; + for(i=1; i<=ng+nh; i++) + { + v = state->fi.ptr.p_double[i]; + if( i>ng&&ae_fp_less_eq(v,(double)(0)) ) + { + continue; + } + state->repnlcerr = ae_maxreal(state->repnlcerr, ae_fabs(v, _state), _state); + } + state->samplef.ptr.p_double[0] = state->meritf; + rcopyvr(n, &state->meritg, &state->samplegm, 0, _state); + if( !state->xrep ) + { + goto lbl_6; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = currentf0; + minns_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstateags.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; +lbl_6: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + if( dotrace ) + { + ae_trace("> termination requested by user\n\n"); + } + state->repterminationtype = 8; + goto lbl_5; + } + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->samplegm.ptr.pp_double[0][i], _state); + } + if( !ae_isfinite(v, _state)||!ae_isfinite(state->samplef.ptr.p_double[0], _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + if( dotrace ) + { + ae_trace("> NAN/INF detected in function/gradient, termination\n\n"); + } + state->repterminationtype = -8; + goto lbl_5; + } + ae_assert(ae_fp_greater(state->agspenaltylevel,1.0), "MinNS: integrity error", _state); + ae_assert(ae_fp_greater(state->agspenaltyincrease,state->agspenaltylevel), "MinNS: integrity error", _state); + if( ae_fp_greater(ae_sqrt(rdotv2(n, &state->rawg, _state), _state)*state->agspenaltylevel,state->rholinear) ) + { + state->rholinear = ae_sqrt(rdotv2(n, &state->rawg, _state), _state)*state->agspenaltyincrease; + if( dotrace ) + { + ae_trace("> penalty parameter needs increase, iteration restarted\n\n"); + } + cursamplesize = 0; + goto lbl_4; + } + + /* + * Trace if needed + */ + if( dotrace ) + { + if( dodetailedtrace ) + { + ae_trace("> printing raw data (prior to applying variable and function scales)\n"); + ae_trace("X (raw) = "); + tracevectorunscaledunshiftedautoprec(&state->xc, n, &state->s, ae_true, &state->s, ae_false, _state); + ae_trace("\n"); + ae_trace("> printing scaled data (after applying variable and function scales)\n"); + ae_trace("X (scaled) = "); + tracevectorautoprec(&state->xc, 0, n, _state); + ae_trace("\n"); + } + ae_trace("sampleRad = %0.3e\n", + (double)(radius)); + ae_trace("lin.violation = %0.3e (scaled violation of linear constraints)\n", + (double)(state->replcerr)); + ae_trace("nlc.violation = %0.3e (scaled violation of nonlinear constraints)\n", + (double)(state->repnlcerr)); + ae_trace("targetF = %0.3e (target function)\n", + (double)(currentf0)); + ae_trace("meritF = %0.3e (merit function)\n", + (double)(state->samplef.ptr.p_double[0])); + ae_trace("Rho linear = %0.3e\n", + (double)(state->rholinear)); + ae_trace("Rho nonlinear = %0.3e\n", + (double)(state->agsrhononlinear)); + ae_trace("----------------------------------------------------------------------------------------------------\n"); + } + + /* + * Check stopping conditions. + */ + if( radiusdecays>=state->agsmaxraddecays ) + { + + /* + * Too many attempts to decrease radius + */ + if( dotrace ) + { + ae_trace("> stopping condition met: too many attempts to decrease radius\n\n"); + } + state->repterminationtype = 7; + goto lbl_5; + } + if( state->repinneriterationscount>=state->maxits&&state->maxits>0 ) + { + + /* + * Too many iterations + */ + if( dotrace ) + { + ae_trace("> stopping condition met: %0d iterations performed\n\n", + (int)(state->repinneriterationscount)); + } + state->repterminationtype = 5; + goto lbl_5; + } + if( ae_fp_less_eq(radius,state->epsx*state->agsraddecay) ) + { + + /* + * Radius is smaller than required step tolerance multiplied by radius decay. + * + * Additional decay is required in order to make sure that optimization session + * with radius equal to EpsX was successfully done. + */ + if( dotrace ) + { + ae_trace("> stopping condition met: sampling radius is smaller than %0.3e\n\n", + (double)(state->epsx)); + } + state->repterminationtype = 2; + goto lbl_5; + } + + /* + * Update sample: + * + * 1. invalidate entries which are too far away from XC + * and move all valid entries to beginning of the sample. + * 2. add new entries until we have AGSSampleSize + * items in our sample. We remove oldest entries from + * sample until we have enough place to add at least + * AGSMinUpdate items. + * 3. prepare "modified" gradient sample with respect to + * boundary constraints. + */ + ae_assert(cursamplesize>=1, "MinNS: integrity check failed (2367)", _state); + k = 1; + for(i=1; i<=cursamplesize-1; i++) + { + + /* + * If entry is outside of Radius-ball around XC, discard it. + */ + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = ae_maxreal(v, ae_fabs(state->samplex.ptr.pp_double[i][j]-state->xc.ptr.p_double[j], _state), _state); + } + if( ae_fp_greater(v,radius) ) + { + continue; + } + + /* + * Move to the beginning + */ + rcopyrr(n, &state->samplex, i, &state->samplex, k, _state); + rcopyrr(n, &state->samplegm, i, &state->samplegm, k, _state); + state->samplef.ptr.p_double[k] = state->samplef.ptr.p_double[i]; + k = k+1; + } + cursamplesize = k; + if( state->agssamplesize-cursamplesizeagsminupdate ) + { + + /* + * Remove oldest entries + */ + k = state->agsminupdate-(state->agssamplesize-cursamplesize); + ae_assert(k<=cursamplesize-1, "MinNS: integrity check failed (2662)", _state); + for(i=1; i<=cursamplesize-k-1; i++) + { + rcopyrr(n, &state->samplex, i+k, &state->samplex, i, _state); + rcopyrr(n, &state->samplegm, i+k, &state->samplegm, i, _state); + state->samplef.ptr.p_double[i] = state->samplef.ptr.p_double[i+k]; + } + cursamplesize = cursamplesize-k; + } + k = 0; + i = cursamplesize; +lbl_8: + if( i>ae_minint(cursamplesize+state->agsminupdate, state->agssamplesize, _state)-1 ) + { + goto lbl_10; + } + for(j=0; j<=n-1; j++) + { + + /* + * Undistorted position + */ + state->samplex.ptr.pp_double[i][j] = state->xc.ptr.p_double[j]; + + /* + * Do not apply distortion if the variable is fixed + */ + if( (state->hasbndl.ptr.p_bool[j]&&state->hasbndu.ptr.p_bool[j])&&ae_fp_eq(state->scaledbndl.ptr.p_double[j],state->scaledbndu.ptr.p_double[j]) ) + { + continue; + } + + /* + * Apply distortion + */ + if( ae_fp_greater_eq(hqrnduniformr(&state->agsrs, _state),0.5) ) + { + + /* + * Sample at the left side with 50% probability + */ + v0 = state->samplex.ptr.pp_double[i][j]-radius; + v1 = state->samplex.ptr.pp_double[i][j]; + if( state->hasbndl.ptr.p_bool[j] ) + { + v0 = ae_maxreal(state->scaledbndl.ptr.p_double[j], v0, _state); + } + } + else + { + + /* + * Sample at the right side with 50% probability + */ + v0 = state->samplex.ptr.pp_double[i][j]; + v1 = state->samplex.ptr.pp_double[i][j]+radius; + if( state->hasbndu.ptr.p_bool[j] ) + { + v1 = ae_minreal(state->scaledbndu.ptr.p_double[j], v1, _state); + } + } + ae_assert(ae_fp_greater_eq(v1,v0), "MinNS: integrity check failed (9743)", _state); + state->samplex.ptr.pp_double[i][j] = boundval(v0+(v1-v0)*hqrnduniformr(&state->agsrs, _state), v0, v1, _state); + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->samplex.ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + minns_clearrequestfields(state, _state); + state->needfij = ae_true; + state->rstateags.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfij = ae_false; + state->samplef.ptr.p_double[i] = state->meritf; + rcopyvr(n, &state->meritg, &state->samplegm, i, _state); + k = k+1; + i = i+1; + goto lbl_8; +lbl_10: + cursamplesize = cursamplesize+k; + fullsample = cursamplesize==state->agssamplesize; + for(j=0; j<=cursamplesize-1; j++) + { + + /* + * For J-th element in gradient sample, process all of its components + * and modify them according to status of box constraints + */ + for(i=0; i<=n-1; i++) + { + ae_assert(!state->hasbndl.ptr.p_bool[i]||ae_fp_greater_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]), "MinNS: integrity error", _state); + ae_assert(!state->hasbndu.ptr.p_bool[i]||ae_fp_less_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]), "MinNS: integrity error", _state); + state->samplegmbc.ptr.pp_double[j][i] = state->samplegm.ptr.pp_double[j][i]; + if( (state->hasbndl.ptr.p_bool[i]&&state->hasbndu.ptr.p_bool[i])&&ae_fp_eq(state->scaledbndl.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + + /* + * I-th box constraint is of equality type (lower bound matches upper one). + * Simplest case, always active. + */ + state->samplegmbc.ptr.pp_double[j][i] = 0.0; + continue; + } + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) + { + + /* + * We are at lower bound: activate/deactivate constraint depending on gradient at XC + */ + if( ae_fp_greater_eq(state->samplegm.ptr.pp_double[0][i],0.0) ) + { + state->samplegmbc.ptr.pp_double[j][i] = 0.0; + } + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + + /* + * We are at upper bound: activate/deactivate constraint depending on gradient at XC + */ + if( ae_fp_less_eq(state->samplegm.ptr.pp_double[0][i],0.0) ) + { + state->samplegmbc.ptr.pp_double[j][i] = 0.0; + } + continue; + } + } + } + if( dotracesample ) + { + ae_trace("> gradient sample\n"); + for(i=0; i<=cursamplesize-1; i++) + { + ae_trace("SampleGrad[] = "); + tracerowautoprec(&state->samplegmbc, i, 0, n, _state); + ae_trace("\n"); + } + } + + /* + * Calculate diagonal Hessian. + * + * This Hessian serves two purposes: + * * first, it improves performance of gradient descent step + * * second, it improves condition number of QP subproblem + * solved to determine step + * + * The idea is that for each variable we check whether sample + * includes entries with alternating sign of gradient: + * * if gradients with different signs are present, Hessian + * component is set to M/R, where M is a maximum magnitude + * of corresponding gradient component, R is a sampling radius. + * Note that sign=0 and sign=1 are treated as different ones + * * if all gradients have same sign, Hessian component is + * set to M/R0, where R0 is initial sampling radius. + */ + for(j=0; j<=n-1; j++) + { + state->colmax.ptr.p_double[j] = 0.0; + state->signmin.ptr.p_double[j] = (double)(1); + state->signmax.ptr.p_double[j] = (double)(-1); + } + for(i=0; i<=cursamplesize-1; i++) + { + for(j=0; j<=n-1; j++) + { + v = state->samplegmbc.ptr.pp_double[i][j]; + state->colmax.ptr.p_double[j] = ae_maxreal(state->colmax.ptr.p_double[j], ae_fabs(v, _state), _state); + state->signmin.ptr.p_double[j] = ae_minreal(state->signmin.ptr.p_double[j], (double)(ae_sign(v, _state)), _state); + state->signmax.ptr.p_double[j] = ae_maxreal(state->signmax.ptr.p_double[j], (double)(ae_sign(v, _state)), _state); + } + } + for(j=0; j<=n-1; j++) + { + if( ae_fp_neq(state->signmin.ptr.p_double[j],state->signmax.ptr.p_double[j]) ) + { + + /* + * Alternating signs of gradient - step is proportional to current sampling radius + */ + ae_assert(ae_fp_neq(state->colmax.ptr.p_double[j],(double)(0)), "MinNS: integrity check failed (2975)", _state); + ae_assert(ae_fp_neq(radius,(double)(0)), "MinNS: integrity check failed (8473)", _state); + state->diagh.ptr.p_double[j] = state->colmax.ptr.p_double[j]/radius; + continue; + } + if( ae_fp_neq(state->colmax.ptr.p_double[j],(double)(0)) ) + { + + /* + * Non-alternating sign of gradient, but non-zero. + * Step is proportional to recommended step + */ + ae_assert(ae_fp_neq(recommendedstep,(double)(0)), "MinNS: integrity check failed (3274)", _state); + state->diagh.ptr.p_double[j] = state->colmax.ptr.p_double[j]/recommendedstep; + continue; + } + state->diagh.ptr.p_double[j] = (double)(1); + } + if( dodetailedtrace ) + { + ae_trace("> diagonal quasi-Hessian\n"); + ae_trace("H = "); + tracevectorautoprec(&state->diagh, 0, n, _state); + ae_trace("\n"); + } + + /* + * PROJECTION PHASE + * + * We project zero vector on convex hull of gradient sample. + * If projection is small enough, we decrease radius and restart. + * Otherwise, this phase returns search direction in State.D. + * + * NOTE: because we use iterative solver, it may have trouble + * dealing with ill-conditioned problems. So we also employ + * second, backup test for stationarity - when too many + * subsequent backtracking searches resulted in short steps. + */ + minns_solveqp(&state->samplegmbc, &state->diagh, cursamplesize, n, &state->tmp0, &state->dbgncholesky, &state->nsqp, _state); + for(j=0; j<=n-1; j++) + { + state->d.ptr.p_double[j] = 0.0; + } + for(i=0; i<=cursamplesize-1; i++) + { + v = state->tmp0.ptr.p_double[i]; + ae_v_addd(&state->d.ptr.p_double[0], 1, &state->samplegmbc.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), v); + } + v = 0.0; + for(j=0; j<=n-1; j++) + { + v = ae_maxreal(v, ae_fabs(state->d.ptr.p_double[j]/coalesce(state->colmax.ptr.p_double[j], 1.0, _state), _state), _state); + } + if( dotrace ) + { + ae_trace("> stationarity test:\n|proj(0)| = %0.3e (projection of zero vector on convex hull of gradient sample)\n", + (double)(v)); + } + if( ae_fp_less_eq(v,state->agsstattold) ) + { + + /* + * Stationarity test succeeded. + * Decrease radius and restart. + * + * NOTE: we also clear ShortStepsCnt on restart + */ + if( dotrace ) + { + ae_trace("> stationarity test satisfied, decreasing radius\n"); + } + radius = radius*state->agsraddecay; + shortstepscnt = 0; + inc(&radiusdecays, _state); + inc(&state->repinneriterationscount, _state); + goto lbl_4; + } + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = -state->d.ptr.p_double[i]/state->diagh.ptr.p_double[i]; + } + + /* + * Perform backtracking line search. + * Update initial step length depending on search results. + * Here we assume that D is non-zero. + * + * NOTE: if AGSShortLimit subsequent line searches resulted + * in steps shorter than AGSStatTolStp, we decrease radius. + */ + dhd = (double)(0); + for(i=0; i<=n-1; i++) + { + dhd = dhd+state->d.ptr.p_double[i]*state->diagh.ptr.p_double[i]*state->d.ptr.p_double[i]; + } + dnrminf = rmaxabsv(n, &state->d, _state); + if( dotrace ) + { + ae_trace("> search direction is ready:\n|D| = %0.3e (inf-norm)\n(D,grad) = %0.3e\n", + (double)(dnrminf), + (double)(rdotvr(n, &state->d, &state->samplegmbc, 0, _state))); + if( dodetailedtrace ) + { + ae_trace("D = "); + tracevectorautoprec(&state->d, 0, n, _state); + ae_trace("\n"); + } + } + ae_assert(ae_fp_greater(dnrminf,(double)(0)), "MinNS: integrity error (2752)", _state); + alpha = recommendedstep/dnrminf; + alphadecreased = ae_false; + backtrackits = 0; + if( fullsample ) + { + maxbacktrackits = state->agsmaxbacktrack; + } + else + { + maxbacktrackits = state->agsmaxbacktracknonfull; + } +lbl_11: + if( ae_false ) + { + goto lbl_12; + } + + /* + * Prepare XN and evaluate merit function at XN + */ + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), alpha); + enforceboundaryconstraints(&state->xn, &state->scaledbndl, &state->hasbndl, &state->scaledbndu, &state->hasbndu, n, 0, _state); + ae_v_move(&state->samplex.ptr.pp_double[maxsamplesize][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minns_clearrequestfields(state, _state); + state->needfij = ae_true; + state->rstateags.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfij = ae_false; + state->samplef.ptr.p_double[maxsamplesize] = state->meritf; + rcopyvr(n, &state->meritg, &state->samplegm, maxsamplesize, _state); + + /* + * Check sufficient decrease condition + */ + ae_assert(ae_fp_greater(dnrminf,(double)(0)), "MinNS: integrity error (9642)", _state); + if( ae_fp_less_eq(state->samplef.ptr.p_double[maxsamplesize],state->samplef.ptr.p_double[0]-alpha*state->agsdecrease*dhd) ) + { + goto lbl_12; + } + + /* + * Decrease Alpha + */ + alpha = alpha*state->agsalphadecay; + alphadecreased = ae_true; + + /* + * Update and check iterations counter. + */ + inc(&backtrackits, _state); + if( backtrackits>=maxbacktrackits ) + { + + /* + * Too many backtracking searches performed without success. + * Terminate iterations. + */ + alpha = 0.0; + alphadecreased = ae_true; + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + goto lbl_12; + } + goto lbl_11; +lbl_12: + if( dotrace ) + { + ae_trace("> backtracking line search finished:\nstp = %0.3e\n", + (double)(alpha)); + } + if( (ae_fp_less_eq(alpha*dnrminf,state->agsshortstpabs)||ae_fp_less_eq(alpha*dnrminf,state->agsshortstprel*radius))||ae_fp_less_eq(ae_fabs(state->samplef.ptr.p_double[0]-state->samplef.ptr.p_double[maxsamplesize], _state),state->agsshortf) ) + { + inc(&shortstepscnt, _state); + } + else + { + shortstepscnt = 0; + } + if( shortstepscnt>=state->agsshortlimit ) + { + + /* + * Too many subsequent short steps. + * + * It may be possible that optimizer is unable to find out + * that we have to decrease radius because of ill-conditioned + * gradients. + * + * Decrease radius and restart. + */ + if( dotrace ) + { + ae_trace("> too many subsequent short steps, decreasing radius\n"); + } + radius = radius*state->agsraddecay; + shortstepscnt = 0; + inc(&radiusdecays, _state); + inc(&state->repinneriterationscount, _state); + goto lbl_4; + } + if( !alphadecreased ) + { + recommendedstep = recommendedstep*2.0; + } + if( alphadecreased&&fullsample ) + { + recommendedstep = recommendedstep*0.5; + } + + /* + * Next iteration + */ + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + inc(&state->repinneriterationscount, _state); + goto lbl_4; +lbl_5: + + /* + * Convert back from scaled to unscaled representation + */ + minns_unscalepointbc(state, &state->xc, _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstateags.ia.ptr.p_int[0] = n; + state->rstateags.ia.ptr.p_int[1] = nec; + state->rstateags.ia.ptr.p_int[2] = nic; + state->rstateags.ia.ptr.p_int[3] = ng; + state->rstateags.ia.ptr.p_int[4] = nh; + state->rstateags.ia.ptr.p_int[5] = i; + state->rstateags.ia.ptr.p_int[6] = j; + state->rstateags.ia.ptr.p_int[7] = k; + state->rstateags.ia.ptr.p_int[8] = radiusdecays; + state->rstateags.ia.ptr.p_int[9] = maxsamplesize; + state->rstateags.ia.ptr.p_int[10] = cursamplesize; + state->rstateags.ia.ptr.p_int[11] = shortstepscnt; + state->rstateags.ia.ptr.p_int[12] = backtrackits; + state->rstateags.ia.ptr.p_int[13] = maxbacktrackits; + state->rstateags.ba.ptr.p_bool[0] = b; + state->rstateags.ba.ptr.p_bool[1] = alphadecreased; + state->rstateags.ba.ptr.p_bool[2] = fullsample; + state->rstateags.ba.ptr.p_bool[3] = dotrace; + state->rstateags.ba.ptr.p_bool[4] = dodetailedtrace; + state->rstateags.ba.ptr.p_bool[5] = dotracesample; + state->rstateags.ra.ptr.p_double[0] = radius0; + state->rstateags.ra.ptr.p_double[1] = radius; + state->rstateags.ra.ptr.p_double[2] = alpha; + state->rstateags.ra.ptr.p_double[3] = recommendedstep; + state->rstateags.ra.ptr.p_double[4] = dhd; + state->rstateags.ra.ptr.p_double[5] = dnrminf; + state->rstateags.ra.ptr.p_double[6] = v; + state->rstateags.ra.ptr.p_double[7] = vv; + state->rstateags.ra.ptr.p_double[8] = v0; + state->rstateags.ra.ptr.p_double[9] = v1; + state->rstateags.ra.ptr.p_double[10] = currentf0; + return result; +} + + +/************************************************************************* +This function performs transformation of X from scaled coordinates to +unscaled ones, paying special attention to box constraints: +* points which were exactly at the boundary before scaling will be mapped + to corresponding boundary after scaling +* in any case, unscaled box constraints will be satisfied + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_unscalepointbc(const minnsstate* state, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + + + for(i=0; i<=state->n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],state->scaledbndl.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + continue; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],state->scaledbndu.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + continue; + } + x->ptr.p_double[i] = x->ptr.p_double[i]*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(x->ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(x->ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + x->ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } +} + + +/************************************************************************* +This function solves QP problem of the form + + [ ] + min [ 0.5*c'*(G*inv(H)*G')*c ] s.t. c[i]>=0, SUM(c[i])=1.0 + [ ] + +where G is stored in SampleG[] array, diagonal H is stored in DiagH[]. + +DbgNCholesky is incremented every time we perform Cholesky decomposition. + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_solveqp(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ ae_vector* coeffs, + ae_int_t* dbgncholesky, + minnsqp* state, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + double v; + double vv; + ae_int_t n; + ae_int_t idx0; + ae_int_t idx1; + ae_int_t ncandbnd; + ae_int_t innerits; + ae_int_t outerits; + double dnrm; + double stp; + double stpmax; + ae_int_t actidx; + double dtol; + ae_bool kickneeded; + double kicklength; + double lambdav; + double maxdiag; + ae_bool wasactivation; + ae_bool werechanges; + ae_int_t termcnt; + + + n = nsample; + + /* + * Allocate arrays, prepare data + */ + rvectorsetlengthatleast(coeffs, n, _state); + rvectorsetlengthatleast(&state->xc, n, _state); + rvectorsetlengthatleast(&state->xn, n, _state); + rvectorsetlengthatleast(&state->x0, n, _state); + rvectorsetlengthatleast(&state->gc, n, _state); + rvectorsetlengthatleast(&state->d, n, _state); + rmatrixsetlengthatleast(&state->uh, n, n, _state); + rmatrixsetlengthatleast(&state->ch, n, n, _state); + rmatrixsetlengthatleast(&state->rk, nsample, nvars, _state); + rvectorsetlengthatleast(&state->invutc, n, _state); + rvectorsetlengthatleast(&state->tmp0, n, _state); + bvectorsetlengthatleast(&state->tmpb, n, _state); + for(i=0; i<=n-1; i++) + { + state->xc.ptr.p_double[i] = 1.0/(double)n; + coeffs->ptr.p_double[i] = 1.0/(double)n; + } + for(i=0; i<=nsample-1; i++) + { + for(j=0; j<=nvars-1; j++) + { + state->rk.ptr.pp_double[i][j] = sampleg->ptr.pp_double[i][j]/ae_sqrt(diagh->ptr.p_double[j], _state); + } + } + rmatrixsyrk(nsample, nvars, 1.0, &state->rk, 0, 0, 0, 0.0, &state->uh, 0, 0, ae_true, _state); + maxdiag = 0.0; + for(i=0; i<=nsample-1; i++) + { + maxdiag = ae_maxreal(maxdiag, state->uh.ptr.pp_double[i][i], _state); + } + maxdiag = coalesce(maxdiag, 1.0, _state); + + /* + * Main cycle: + */ + innerits = 0; + outerits = 0; + dtol = 1.0E5*ae_machineepsilon; + kicklength = ae_machineepsilon; + lambdav = 1.0E5*ae_machineepsilon; + termcnt = 0; + for(;;) + { + + /* + * Save current point to X0 + */ + ae_v_move(&state->x0.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Calculate gradient at initial point, solve NNLS problem + * to determine descent direction D subject to constraints. + * + * In order to do so we solve following constrained + * minimization problem: + * ( )^2 + * min ( SUM(lambda[i]*A[i]) + G ) + * ( ) + * Here: + * * G is a gradient (column vector) + * * A[i] is a column vector of I-th constraint + * * lambda[i] is a Lagrange multiplier corresponding to I-th constraint + * + * NOTE: all A[i] except for last one have only one element being set, + * so we rely on sparse capabilities of NNLS solver. However, + * in order to use these capabilities we have to reorder variables + * in such way that sparse ones come first. + * + * After finding lambda[] coefficients, we can find constrained descent + * direction by subtracting lambda[i]*A[i] from D=-G. We make use of the + * fact that first NCandBnd columns are just columns of identity matrix, + * so we can perform exact projection by explicitly setting elements of D + * to zeros. + */ + minns_qpcalculategradfunc(sampleg, diagh, nsample, nvars, &state->xc, &state->gc, &state->fc, &state->tmp0, _state); + ivectorsetlengthatleast(&state->tmpidx, n, _state); + rvectorsetlengthatleast(&state->tmpd, n, _state); + rmatrixsetlengthatleast(&state->tmpc2, n, 1, _state); + idx0 = 0; + ncandbnd = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xc.ptr.p_double[i],0.0) ) + { + ncandbnd = ncandbnd+1; + } + } + idx1 = ncandbnd; + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xc.ptr.p_double[i],0.0) ) + { + + /* + * Candidate for activation of boundary constraint, + * comes first. + * + * NOTE: multiplication by -1 is due to the fact that + * it is lower bound, and has specific direction + * of constraint gradient. + */ + state->tmpidx.ptr.p_int[idx0] = i; + state->tmpd.ptr.p_double[idx0] = (-state->gc.ptr.p_double[i])*(double)(-1); + state->tmpc2.ptr.pp_double[idx0][0] = 1.0*(double)(-1); + idx0 = idx0+1; + } + else + { + + /* + * We are far away from boundary. + */ + state->tmpidx.ptr.p_int[idx1] = i; + state->tmpd.ptr.p_double[idx1] = -state->gc.ptr.p_double[i]; + state->tmpc2.ptr.pp_double[idx1][0] = 1.0; + idx1 = idx1+1; + } + } + ae_assert(idx0==ncandbnd, "MinNSQP: integrity check failed (2346)", _state); + ae_assert(idx1==n, "MinNSQP: integrity check failed (4535)", _state); + snnlsinit(n, 1, n, &state->nnls, _state); + snnlssetproblem(&state->nnls, &state->tmpc2, &state->tmpd, ncandbnd, 1, n, _state); + snnlsdropnnc(&state->nnls, ncandbnd, _state); + snnlssolve(&state->nnls, &state->tmplambdas, _state); + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = -state->gc.ptr.p_double[i]-state->tmplambdas.ptr.p_double[ncandbnd]; + } + for(i=0; i<=ncandbnd-1; i++) + { + if( ae_fp_greater(state->tmplambdas.ptr.p_double[i],(double)(0)) ) + { + state->d.ptr.p_double[state->tmpidx.ptr.p_int[i]] = 0.0; + } + } + + /* + * Additional stage to "polish" D (improve situation + * with sum-to-one constraint and boundary constraints) + * and to perform additional integrity check. + * + * After this stage we are pretty sure that: + * * if x[i]=0.0, then d[i]>=0.0 + * * if d[i]<0.0, then x[i]>0.0 + */ + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_less(state->d.ptr.p_double[i],0.0) ) + { + state->d.ptr.p_double[i] = 0.0; + } + } + + /* + * Decide whether we need "kick" stage: special stage + * that moves us away from boundary constraints which are + * not strictly active (i.e. such constraints that x[i]=0.0 and d[i]>0). + * + * If we need kick stage, we make a kick - and restart iteration. + * If not, after this block we can rely on the fact that + * for all x[i]=0.0 we have d[i]=0.0 + */ + kickneeded = ae_false; + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->d.ptr.p_double[i],0.0) ) + { + kickneeded = ae_true; + } + } + if( kickneeded ) + { + + /* + * Perform kick. + * Restart. + * Do not increase outer iterations counter. + */ + v = 0.0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->d.ptr.p_double[i],0.0) ) + { + state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]+kicklength; + } + v = v+state->xc.ptr.p_double[i]; + } + ae_assert(ae_fp_greater(v,0.0), "MinNSQP: integrity check failed (2572)", _state); + for(i=0; i<=n-1; i++) + { + state->xc.ptr.p_double[i] = state->xc.ptr.p_double[i]/v; + } + inc(&innerits, _state); + continue; + } + + /* + * Calculate Cholesky decomposition of constrained Hessian + * for Newton phase. + */ + for(;;) + { + for(i=0; i<=n-1; i++) + { + + /* + * Diagonal element + */ + if( ae_fp_greater(state->xc.ptr.p_double[i],0.0) ) + { + state->ch.ptr.pp_double[i][i] = state->uh.ptr.pp_double[i][i]+lambdav*maxdiag; + } + else + { + state->ch.ptr.pp_double[i][i] = 1.0; + } + + /* + * Offdiagonal elements + */ + for(j=i+1; j<=n-1; j++) + { + if( ae_fp_greater(state->xc.ptr.p_double[i],0.0)&&ae_fp_greater(state->xc.ptr.p_double[j],0.0) ) + { + state->ch.ptr.pp_double[i][j] = state->uh.ptr.pp_double[i][j]; + } + else + { + state->ch.ptr.pp_double[i][j] = 0.0; + } + } + } + inc(dbgncholesky, _state); + if( !spdmatrixcholeskyrec(&state->ch, 0, n, ae_true, &state->tmp0, _state) ) + { + + /* + * Cholesky decomposition failed. + * Increase LambdaV and repeat iteration. + * Do not increase outer iterations counter. + */ + lambdav = lambdav*(double)10; + continue; + } + break; + } + + /* + * Newton phase + */ + for(;;) + { + + /* + * Calculate constrained (equality and sum-to-one) descent direction D. + * + * Here we use Sherman-Morrison update to calculate direction subject to + * sum-to-one constraint. + */ + minns_qpcalculategradfunc(sampleg, diagh, nsample, nvars, &state->xc, &state->gc, &state->fc, &state->tmp0, _state); + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(state->xc.ptr.p_double[i],0.0) ) + { + state->invutc.ptr.p_double[i] = 1.0; + state->d.ptr.p_double[i] = -state->gc.ptr.p_double[i]; + } + else + { + state->invutc.ptr.p_double[i] = 0.0; + state->d.ptr.p_double[i] = 0.0; + } + } + minns_qpsolveut(&state->ch, n, &state->invutc, _state); + minns_qpsolveut(&state->ch, n, &state->d, _state); + v = 0.0; + vv = 0.0; + for(i=0; i<=n-1; i++) + { + vv = vv+ae_sqr(state->invutc.ptr.p_double[i], _state); + v = v+state->invutc.ptr.p_double[i]*state->d.ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = state->d.ptr.p_double[i]-v/vv*state->invutc.ptr.p_double[i]; + } + minns_qpsolveu(&state->ch, n, &state->d, _state); + v = 0.0; + k = 0; + for(i=0; i<=n-1; i++) + { + v = v+state->d.ptr.p_double[i]; + if( ae_fp_neq(state->d.ptr.p_double[i],0.0) ) + { + k = k+1; + } + } + if( k>0&&ae_fp_greater(v,0.0) ) + { + vv = v/(double)k; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->d.ptr.p_double[i],0.0) ) + { + state->d.ptr.p_double[i] = state->d.ptr.p_double[i]-vv; + } + } + } + + /* + * Calculate length of D, maximum step and component which is + * activated by this step. + * + * Break if D is exactly zero. We do not break here if DNrm is + * small - this check is performed later. It is important to + * perform last step with nearly-zero D, it allows us to have + * extra-precision in solution which is often needed for convergence + * of AGS algorithm. + */ + dnrm = 0.0; + for(i=0; i<=n-1; i++) + { + dnrm = dnrm+ae_sqr(state->d.ptr.p_double[i], _state); + } + dnrm = ae_sqrt(dnrm, _state); + actidx = -1; + stpmax = 1.0E50; + for(i=0; i<=n-1; i++) + { + if( ae_fp_less(state->d.ptr.p_double[i],0.0) ) + { + v = stpmax; + stpmax = safeminposrv(state->xc.ptr.p_double[i], -state->d.ptr.p_double[i], stpmax, _state); + if( ae_fp_less(stpmax,v) ) + { + actidx = i; + } + } + } + if( ae_fp_eq(dnrm,0.0) ) + { + break; + } + + /* + * Calculate trial function value at unconstrained full step. + * If trial value is greater or equal to FC, terminate iterations. + */ + for(i=0; i<=n-1; i++) + { + state->xn.ptr.p_double[i] = state->xc.ptr.p_double[i]+1.0*state->d.ptr.p_double[i]; + } + minns_qpcalculatefunc(sampleg, diagh, nsample, nvars, &state->xn, &state->fn, &state->tmp0, _state); + if( ae_fp_greater_eq(state->fn,state->fc) ) + { + break; + } + + /* + * Perform step + * Update Hessian + * Update XC + * + * Break if: + * a) no constraint was activated + * b) norm of D is small enough + */ + stp = ae_minreal(1.0, stpmax, _state); + for(i=0; i<=n-1; i++) + { + state->xn.ptr.p_double[i] = ae_maxreal(state->xc.ptr.p_double[i]+stp*state->d.ptr.p_double[i], 0.0, _state); + } + if( ae_fp_eq(stp,stpmax)&&actidx>=0 ) + { + state->xn.ptr.p_double[actidx] = 0.0; + } + wasactivation = ae_false; + for(i=0; i<=n-1; i++) + { + state->tmpb.ptr.p_bool[i] = ae_fp_eq(state->xn.ptr.p_double[i],0.0)&&ae_fp_neq(state->xc.ptr.p_double[i],0.0); + wasactivation = wasactivation||state->tmpb.ptr.p_bool[i]; + } + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( !wasactivation ) + { + break; + } + if( ae_fp_less_eq(dnrm,dtol) ) + { + break; + } + spdmatrixcholeskyupdatefixbuf(&state->ch, n, ae_true, &state->tmpb, &state->tmp0, _state); + } + + /* + * Compare status of boundary constraints - if nothing changed during + * last outer iteration, TermCnt is increased. Otherwise it is reset + * to zero. + * + * When TermCnt is large enough, we terminate algorithm. + */ + werechanges = ae_false; + for(i=0; i<=n-1; i++) + { + werechanges = werechanges||ae_sign(state->x0.ptr.p_double[i], _state)!=ae_sign(state->xc.ptr.p_double[i], _state); + } + if( !werechanges ) + { + inc(&termcnt, _state); + } + else + { + termcnt = 0; + } + if( termcnt>=2 ) + { + break; + } + + /* + * Increase number of outer iterations. + * Break if we performed too many. + */ + inc(&outerits, _state); + if( outerits==10 ) + { + break; + } + } + + /* + * Store result + */ + for(i=0; i<=n-1; i++) + { + coeffs->ptr.p_double[i] = state->xc.ptr.p_double[i]; + } +} + + +/************************************************************************* +Function/gradient calculation for QP solver. + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_qpcalculategradfunc(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ const ae_vector* coeffs, + /* Real */ ae_vector* g, + double* f, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + *f = 0.0; + + rvectorsetlengthatleast(g, nsample, _state); + rvectorsetlengthatleast(tmp, nvars, _state); + + /* + * Calculate GS*p + */ + for(j=0; j<=nvars-1; j++) + { + tmp->ptr.p_double[j] = 0.0; + } + for(i=0; i<=nsample-1; i++) + { + v = coeffs->ptr.p_double[i]; + ae_v_addd(&tmp->ptr.p_double[0], 1, &sampleg->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); + } + + /* + * Calculate F + */ + *f = 0.0; + for(i=0; i<=nvars-1; i++) + { + *f = *f+0.5*ae_sqr(tmp->ptr.p_double[i], _state)/diagh->ptr.p_double[i]; + } + + /* + * Multiply by inverse Hessian + */ + for(i=0; i<=nvars-1; i++) + { + tmp->ptr.p_double[i] = tmp->ptr.p_double[i]/diagh->ptr.p_double[i]; + } + + /* + * Function gradient + */ + for(i=0; i<=nsample-1; i++) + { + v = ae_v_dotproduct(&sampleg->ptr.pp_double[i][0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,nvars-1)); + g->ptr.p_double[i] = v; + } +} + + +/************************************************************************* +Function calculation for QP solver. + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_qpcalculatefunc(/* Real */ const ae_matrix* sampleg, + /* Real */ const ae_vector* diagh, + ae_int_t nsample, + ae_int_t nvars, + /* Real */ const ae_vector* coeffs, + double* f, + /* Real */ ae_vector* tmp, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + *f = 0.0; + + rvectorsetlengthatleast(tmp, nvars, _state); + + /* + * Calculate GS*p + */ + for(j=0; j<=nvars-1; j++) + { + tmp->ptr.p_double[j] = 0.0; + } + for(i=0; i<=nsample-1; i++) + { + v = coeffs->ptr.p_double[i]; + ae_v_addd(&tmp->ptr.p_double[0], 1, &sampleg->ptr.pp_double[i][0], 1, ae_v_len(0,nvars-1), v); + } + + /* + * Calculate F + */ + *f = 0.0; + for(i=0; i<=nvars-1; i++) + { + *f = *f+0.5*ae_sqr(tmp->ptr.p_double[i], _state)/diagh->ptr.p_double[i]; + } +} + + +/************************************************************************* +Triangular solver for QP solver. + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_qpsolveu(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * A^(-1)*X + */ + for(i=n-1; i>=0; i--) + { + v = x->ptr.p_double[i]; + for(j=i+1; j<=n-1; j++) + { + v = v-a->ptr.pp_double[i][j]*x->ptr.p_double[j]; + } + x->ptr.p_double[i] = v/a->ptr.pp_double[i][i]; + } +} + + +/************************************************************************* +Triangular solver for QP solver. + + -- ALGLIB -- + Copyright 02.06.2015 by Bochkanov Sergey +*************************************************************************/ +static void minns_qpsolveut(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ ae_vector* x, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + + + + /* + * A^(-T)*X + */ + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = x->ptr.p_double[i]/a->ptr.pp_double[i][i]; + v = x->ptr.p_double[i]; + for(j=i+1; j<=n-1; j++) + { + x->ptr.p_double[j] = x->ptr.p_double[j]-a->ptr.pp_double[i][j]*v; + } + } +} + + +void _minnsqp_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minnsqp *p = (minnsqp*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->uh, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->ch, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->rk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invutc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->tmpd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmplambdas, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpc2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpb, 0, DT_BOOL, _state, make_automatic); + _snnlssolver_init(&p->nnls, _state, make_automatic); +} + + +void _minnsqp_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minnsqp *dst = (minnsqp*)_dst; + const minnsqp *src = (const minnsqp*)_src; + dst->fc = src->fc; + dst->fn = src->fn; + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_matrix_init_copy(&dst->uh, &src->uh, _state, make_automatic); + ae_matrix_init_copy(&dst->ch, &src->ch, _state, make_automatic); + ae_matrix_init_copy(&dst->rk, &src->rk, _state, make_automatic); + ae_vector_init_copy(&dst->invutc, &src->invutc, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmpidx, &src->tmpidx, _state, make_automatic); + ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc, &src->tmpc, _state, make_automatic); + ae_vector_init_copy(&dst->tmplambdas, &src->tmplambdas, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpc2, &src->tmpc2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpb, &src->tmpb, _state, make_automatic); + _snnlssolver_init_copy(&dst->nnls, &src->nnls, _state, make_automatic); +} + + +void _minnsqp_clear(void* _p) +{ + minnsqp *p = (minnsqp*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->gc); + ae_vector_clear(&p->d); + ae_matrix_clear(&p->uh); + ae_matrix_clear(&p->ch); + ae_matrix_clear(&p->rk); + ae_vector_clear(&p->invutc); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmpidx); + ae_vector_clear(&p->tmpd); + ae_vector_clear(&p->tmpc); + ae_vector_clear(&p->tmplambdas); + ae_matrix_clear(&p->tmpc2); + ae_vector_clear(&p->tmpb); + _snnlssolver_clear(&p->nnls); +} + + +void _minnsqp_destroy(void* _p) +{ + minnsqp *p = (minnsqp*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->gc); + ae_vector_destroy(&p->d); + ae_matrix_destroy(&p->uh); + ae_matrix_destroy(&p->ch); + ae_matrix_destroy(&p->rk); + ae_vector_destroy(&p->invutc); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmpidx); + ae_vector_destroy(&p->tmpd); + ae_vector_destroy(&p->tmpc); + ae_vector_destroy(&p->tmplambdas); + ae_matrix_destroy(&p->tmpc2); + ae_vector_destroy(&p->tmpb); + _snnlssolver_destroy(&p->nnls); +} + + +void _minnsstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minnsstate *p = (minnsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _rcommstate_init(&p->rstateags, _state, make_automatic); + _hqrndstate_init(&p->agsrs, _state, make_automatic); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rawg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->meritg, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->colmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->signmin, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->signmax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->scaledbndu, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->scaledcleic, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->samplex, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->samplegm, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->samplegmbc, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->samplef, 0, DT_REAL, _state, make_automatic); + _minnsqp_init(&p->nsqp, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp3, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fm, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xscaled, 0, DT_REAL, _state, make_automatic); +} + + +void _minnsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minnsstate *dst = (minnsstate*)_dst; + const minnsstate *src = (const minnsstate*)_src; + dst->solvertype = src->solvertype; + dst->n = src->n; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->diffstep = src->diffstep; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + dst->nec = src->nec; + dst->nic = src->nic; + ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic); + dst->ng = src->ng; + dst->nh = src->nh; + dst->protocolversion = src->protocolversion; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->needfij = src->needfij; + dst->needfi = src->needfi; + dst->xupdated = src->xupdated; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + _rcommstate_init_copy(&dst->rstateags, &src->rstateags, _state, make_automatic); + _hqrndstate_init_copy(&dst->agsrs, &src->agsrs, _state, make_automatic); + dst->agsradius = src->agsradius; + dst->agssamplesize = src->agssamplesize; + dst->agsraddecay = src->agsraddecay; + dst->agsalphadecay = src->agsalphadecay; + dst->agsdecrease = src->agsdecrease; + dst->agsinitstp = src->agsinitstp; + dst->agsstattold = src->agsstattold; + dst->agsshortstpabs = src->agsshortstpabs; + dst->agsshortstprel = src->agsshortstprel; + dst->agsshortf = src->agsshortf; + dst->agsshortlimit = src->agsshortlimit; + dst->agsrhononlinear = src->agsrhononlinear; + dst->agsminupdate = src->agsminupdate; + dst->agsmaxraddecays = src->agsmaxraddecays; + dst->agsmaxbacktrack = src->agsmaxbacktrack; + dst->agsmaxbacktracknonfull = src->agsmaxbacktracknonfull; + dst->agspenaltylevel = src->agspenaltylevel; + dst->agspenaltyincrease = src->agspenaltyincrease; + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->rawg, &src->rawg, _state, make_automatic); + ae_vector_init_copy(&dst->meritg, &src->meritg, _state, make_automatic); + dst->rawf = src->rawf; + dst->meritf = src->meritf; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + ae_vector_init_copy(&dst->colmax, &src->colmax, _state, make_automatic); + ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic); + ae_vector_init_copy(&dst->signmin, &src->signmin, _state, make_automatic); + ae_vector_init_copy(&dst->signmax, &src->signmax, _state, make_automatic); + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->scaledbndl, &src->scaledbndl, _state, make_automatic); + ae_vector_init_copy(&dst->scaledbndu, &src->scaledbndu, _state, make_automatic); + ae_matrix_init_copy(&dst->scaledcleic, &src->scaledcleic, _state, make_automatic); + dst->rholinear = src->rholinear; + ae_matrix_init_copy(&dst->samplex, &src->samplex, _state, make_automatic); + ae_matrix_init_copy(&dst->samplegm, &src->samplegm, _state, make_automatic); + ae_matrix_init_copy(&dst->samplegmbc, &src->samplegmbc, _state, make_automatic); + ae_vector_init_copy(&dst->samplef, &src->samplef, _state, make_automatic); + _minnsqp_init_copy(&dst->nsqp, &src->nsqp, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmp3, &src->tmp3, _state, make_automatic); + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + ae_vector_init_copy(&dst->fbase, &src->fbase, _state, make_automatic); + ae_vector_init_copy(&dst->fp, &src->fp, _state, make_automatic); + ae_vector_init_copy(&dst->fm, &src->fm, _state, make_automatic); + ae_vector_init_copy(&dst->xscaled, &src->xscaled, _state, make_automatic); + dst->repinneriterationscount = src->repinneriterationscount; + dst->repouteriterationscount = src->repouteriterationscount; + dst->repnfev = src->repnfev; + dst->repvaridx = src->repvaridx; + dst->repfuncidx = src->repfuncidx; + dst->repterminationtype = src->repterminationtype; + dst->replcerr = src->replcerr; + dst->repnlcerr = src->repnlcerr; + dst->dbgncholesky = src->dbgncholesky; +} + + +void _minnsstate_clear(void* _p) +{ + minnsstate *p = (minnsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_matrix_clear(&p->cleic); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstate); + _rcommstate_clear(&p->rstateags); + _hqrndstate_clear(&p->agsrs); + ae_vector_clear(&p->xstart); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->rawg); + ae_vector_clear(&p->meritg); + ae_vector_clear(&p->d); + ae_vector_clear(&p->colmax); + ae_vector_clear(&p->diagh); + ae_vector_clear(&p->signmin); + ae_vector_clear(&p->signmax); + ae_vector_clear(&p->scaledbndl); + ae_vector_clear(&p->scaledbndu); + ae_matrix_clear(&p->scaledcleic); + ae_matrix_clear(&p->samplex); + ae_matrix_clear(&p->samplegm); + ae_matrix_clear(&p->samplegmbc); + ae_vector_clear(&p->samplef); + _minnsqp_clear(&p->nsqp); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_matrix_clear(&p->tmp2); + ae_vector_clear(&p->tmp3); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->fbase); + ae_vector_clear(&p->fp); + ae_vector_clear(&p->fm); + ae_vector_clear(&p->xscaled); +} + + +void _minnsstate_destroy(void* _p) +{ + minnsstate *p = (minnsstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_matrix_destroy(&p->cleic); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _rcommstate_destroy(&p->rstate); + _rcommstate_destroy(&p->rstateags); + _hqrndstate_destroy(&p->agsrs); + ae_vector_destroy(&p->xstart); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->rawg); + ae_vector_destroy(&p->meritg); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->colmax); + ae_vector_destroy(&p->diagh); + ae_vector_destroy(&p->signmin); + ae_vector_destroy(&p->signmax); + ae_vector_destroy(&p->scaledbndl); + ae_vector_destroy(&p->scaledbndu); + ae_matrix_destroy(&p->scaledcleic); + ae_matrix_destroy(&p->samplex); + ae_matrix_destroy(&p->samplegm); + ae_matrix_destroy(&p->samplegmbc); + ae_vector_destroy(&p->samplef); + _minnsqp_destroy(&p->nsqp); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_matrix_destroy(&p->tmp2); + ae_vector_destroy(&p->tmp3); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->fbase); + ae_vector_destroy(&p->fp); + ae_vector_destroy(&p->fm); + ae_vector_destroy(&p->xscaled); +} + + +void _minnsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minnsreport *p = (minnsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minnsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minnsreport *dst = (minnsreport*)_dst; + const minnsreport *src = (const minnsreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->cerr = src->cerr; + dst->lcerr = src->lcerr; + dst->nlcerr = src->nlcerr; + dst->terminationtype = src->terminationtype; + dst->varidx = src->varidx; + dst->funcidx = src->funcidx; +} + + +void _minnsreport_clear(void* _p) +{ + minnsreport *p = (minnsreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minnsreport_destroy(void* _p) +{ + minnsreport *p = (minnsreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Obsolete function, use MinLBFGSSetPrecDefault() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, + ae_state *_state) +{ + + + minlbfgssetprecdefault(state, _state); +} + + +/************************************************************************* +Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, + /* Real */ const ae_matrix* p, + ae_bool isupper, + ae_state *_state) +{ + + + minlbfgssetpreccholesky(state, p, isupper, _state); +} + + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierwidth(minbleicstate* state, + double mu, + ae_state *_state) +{ + + +} + + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierdecay(minbleicstate* state, + double mudecay, + ae_state *_state) +{ + + +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void minasacreate(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + minasastate* state, + ae_state *_state) +{ + ae_int_t i; + + _minasastate_clear(state); + + ae_assert(n>=1, "MinASA: N too small!", _state); + ae_assert(x->cnt>=n, "MinCGCreate: Length(X)cnt>=n, "MinCGCreate: Length(BndL)cnt>=n, "MinCGCreate: Length(BndU)ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: inconsistent bounds!", _state); + ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],x->ptr.p_double[i]), "MinASA: infeasible X!", _state); + ae_assert(ae_fp_less_eq(x->ptr.p_double[i],bndu->ptr.p_double[i]), "MinASA: infeasible X!", _state); + } + + /* + * Initialize + */ + state->n = n; + minasasetcond(state, (double)(0), (double)(0), (double)(0), 0, _state); + minasasetxrep(state, ae_false, _state); + minasasetstpmax(state, (double)(0), _state); + minasasetalgorithm(state, -1, _state); + ae_vector_set_length(&state->bndl, n, _state); + ae_vector_set_length(&state->bndu, n, _state); + ae_vector_set_length(&state->ak, n, _state); + ae_vector_set_length(&state->xk, n, _state); + ae_vector_set_length(&state->dk, n, _state); + ae_vector_set_length(&state->an, n, _state); + ae_vector_set_length(&state->xn, n, _state); + ae_vector_set_length(&state->dn, n, _state); + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->d, n, _state); + ae_vector_set_length(&state->g, n, _state); + ae_vector_set_length(&state->gc, n, _state); + ae_vector_set_length(&state->work, n, _state); + ae_vector_set_length(&state->yk, n, _state); + minasarestartfrom(state, x, bndl, bndu, _state); +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetcond(minasastate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinASASetCond: EpsG is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinASASetCond: negative EpsG!", _state); + ae_assert(ae_isfinite(epsf, _state), "MinASASetCond: EpsF is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinASASetCond: negative EpsF!", _state); + ae_assert(ae_isfinite(epsx, _state), "MinASASetCond: EpsX is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinASASetCond: negative EpsX!", _state); + ae_assert(maxits>=0, "MinASASetCond: negative MaxIts!", _state); + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsg = epsg; + state->epsf = epsf; + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetalgorithm(minasastate* state, + ae_int_t algotype, + ae_state *_state) +{ + + + ae_assert(algotype>=-1&&algotype<=1, "MinASASetAlgorithm: incorrect AlgoType!", _state); + if( algotype==-1 ) + { + algotype = 1; + } + state->cgtype = algotype; +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinASASetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinASASetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool minasaiteration(minasastate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double betak; + double v; + double vv; + ae_int_t mcinfo; + ae_bool b; + ae_bool stepfound; + ae_int_t diffcnt; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + mcinfo = state->rstate.ia.ptr.p_int[2]; + diffcnt = state->rstate.ia.ptr.p_int[3]; + b = state->rstate.ba.ptr.p_bool[0]; + stepfound = state->rstate.ba.ptr.p_bool[1]; + betak = state->rstate.ra.ptr.p_double[0]; + v = state->rstate.ra.ptr.p_double[1]; + vv = state->rstate.ra.ptr.p_double[2]; + } + else + { + n = 359; + i = -58; + mcinfo = -919; + diffcnt = -909; + b = ae_true; + stepfound = ae_true; + betak = 74.0; + v = -788.0; + vv = 809.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + + /* + * Routine body + */ + + /* + * Prepare + */ + n = state->n; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + state->debugrestartscount = 0; + state->cgtype = 1; + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xk.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xk.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->ak.ptr.p_double[i] = (double)(0); + } + else + { + state->ak.ptr.p_double[i] = (double)(1); + } + } + state->mu = 0.1; + state->curalgo = 0; + + /* + * Calculate F/G, initialize algorithm + */ + mincomp_clearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfg = ae_false; + if( !state->xrep ) + { + goto lbl_15; + } + + /* + * progress report + */ + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; +lbl_15: + if( ae_fp_less_eq(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) + { + state->repterminationtype = 4; + result = ae_false; + return result; + } + state->repnfev = state->repnfev+1; + + /* + * Main cycle + * + * At the beginning of new iteration: + * * CurAlgo stores current algorithm selector + * * State.XK, State.F and State.G store current X/F/G + * * State.AK stores current set of active constraints + */ +lbl_17: + if( ae_false ) + { + goto lbl_18; + } + + /* + * GPA algorithm + */ + if( state->curalgo!=0 ) + { + goto lbl_19; + } + state->k = 0; + state->acount = 0; +lbl_21: + if( ae_false ) + { + goto lbl_22; + } + + /* + * Determine Dk = proj(xk - gk)-xk + */ + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->xk.ptr.p_double[i]; + } + + /* + * Armijo line search. + * * exact search with alpha=1 is tried first, + * 'exact' means that we evaluate f() EXACTLY at + * bound(x-g,bndl,bndu), without intermediate floating + * point operations. + * * alpha<1 are tried if explicit search wasn't successful + * Result is placed into XN. + * + * Two types of search are needed because we can't + * just use second type with alpha=1 because in finite + * precision arithmetics (x1-x0)+x0 may differ from x1. + * So while x1 is correctly bounded (it lie EXACTLY on + * boundary, if it is active), (x1-x0)+x0 may be + * not bounded. + */ + v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->dginit = v; + state->finit = state->f; + if( !(ae_fp_less_eq(mincomp_asad1norm(state, _state),state->stpmax)||ae_fp_eq(state->stpmax,(double)(0))) ) + { + goto lbl_23; + } + + /* + * Try alpha=1 step first + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = boundval(state->xk.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + mincomp_clearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfg = ae_false; + state->repnfev = state->repnfev+1; + stepfound = ae_fp_less_eq(state->f,state->finit+mincomp_gpaftol*state->dginit); + goto lbl_24; +lbl_23: + stepfound = ae_false; +lbl_24: + if( !stepfound ) + { + goto lbl_25; + } + + /* + * we are at the boundary(ies) + */ + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->stp = (double)(1); + goto lbl_26; +lbl_25: + + /* + * alpha=1 is too large, try smaller values + */ + state->stp = (double)(1); + linminnormalized(&state->d, &state->stp, n, _state); + state->dginit = state->dginit/state->stp; + state->stp = mincomp_gpadecay*state->stp; + if( ae_fp_greater(state->stpmax,(double)(0)) ) + { + state->stp = ae_minreal(state->stp, state->stpmax, _state); + } +lbl_27: + if( ae_false ) + { + goto lbl_28; + } + v = state->stp; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + mincomp_clearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needfg = ae_false; + state->repnfev = state->repnfev+1; + if( ae_fp_less_eq(state->stp,mincomp_stpmin) ) + { + goto lbl_28; + } + if( ae_fp_less_eq(state->f,state->finit+state->stp*mincomp_gpaftol*state->dginit) ) + { + goto lbl_28; + } + state->stp = state->stp*mincomp_gpadecay; + goto lbl_27; +lbl_28: + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); +lbl_26: + state->repiterationscount = state->repiterationscount+1; + if( !state->xrep ) + { + goto lbl_29; + } + + /* + * progress report + */ + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->xupdated = ae_false; +lbl_29: + + /* + * Calculate new set of active constraints. + * Reset counter if active set was changed. + * Prepare for the new iteration + */ + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->an.ptr.p_double[i] = (double)(0); + } + else + { + state->an.ptr.p_double[i] = (double)(1); + } + } + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->ak.ptr.p_double[i],state->an.ptr.p_double[i]) ) + { + state->acount = -1; + break; + } + } + state->acount = state->acount+1; + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ak.ptr.p_double[0], 1, &state->an.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Stopping conditions + */ + if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) + { + goto lbl_31; + } + + /* + * Too many iterations + */ + state->repterminationtype = 5; + if( !state->xrep ) + { + goto lbl_33; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->xupdated = ae_false; +lbl_33: + result = ae_false; + return result; +lbl_31: + if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) + { + goto lbl_35; + } + + /* + * Gradient is small enough + */ + state->repterminationtype = 4; + if( !state->xrep ) + { + goto lbl_37; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->xupdated = ae_false; +lbl_37: + result = ae_false; + return result; +lbl_35: + v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( ae_fp_greater(ae_sqrt(v, _state)*state->stp,state->epsx) ) + { + goto lbl_39; + } + + /* + * Step size is too small, no further improvement is + * possible + */ + state->repterminationtype = 2; + if( !state->xrep ) + { + goto lbl_41; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->xupdated = ae_false; +lbl_41: + result = ae_false; + return result; +lbl_39: + if( ae_fp_greater(state->finit-state->f,state->epsf*ae_maxreal(ae_fabs(state->finit, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) + { + goto lbl_43; + } + + /* + * F(k+1)-F(k) is small enough + */ + state->repterminationtype = 1; + if( !state->xrep ) + { + goto lbl_45; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->xupdated = ae_false; +lbl_45: + result = ae_false; + return result; +lbl_43: + + /* + * Decide - should we switch algorithm or not + */ + if( mincomp_asauisempty(state, _state) ) + { + if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) + { + state->curalgo = 1; + goto lbl_22; + } + else + { + state->mu = state->mu*mincomp_asarho; + } + } + else + { + if( state->acount==mincomp_n1 ) + { + if( ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) + { + state->curalgo = 1; + goto lbl_22; + } + } + } + + /* + * Next iteration + */ + state->k = state->k+1; + goto lbl_21; +lbl_22: +lbl_19: + + /* + * CG algorithm + */ + if( state->curalgo!=1 ) + { + goto lbl_47; + } + + /* + * first, check that there are non-active constraints. + * move to GPA algorithm, if all constraints are active + */ + b = ae_true; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->ak.ptr.p_double[i],(double)(0)) ) + { + b = ae_false; + break; + } + } + if( b ) + { + state->curalgo = 0; + goto lbl_17; + } + + /* + * CG iterations + */ + state->fold = state->f; + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + state->dk.ptr.p_double[i] = -state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; + state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]*state->ak.ptr.p_double[i]; + } +lbl_49: + if( ae_false ) + { + goto lbl_50; + } + + /* + * Store G[k] for later calculation of Y[k] + */ + for(i=0; i<=n-1; i++) + { + state->yk.ptr.p_double[i] = -state->gc.ptr.p_double[i]; + } + + /* + * Make a CG step in direction given by DK[]: + * * calculate step. Step projection into feasible set + * is used. It has several benefits: a) step may be + * found with usual line search, b) multiple constraints + * may be activated with one step, c) activated constraints + * are detected in a natural way - just compare x[i] with + * bounds + * * update active set, set B to True, if there + * were changes in the set. + */ + ae_v_move(&state->d.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->mcstage = 0; + state->stp = (double)(1); + linminnormalized(&state->d, &state->stp, n, _state); + if( ae_fp_neq(state->laststep,(double)(0)) ) + { + state->stp = state->laststep; + } + mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_51: + if( state->mcstage==0 ) + { + goto lbl_52; + } + + /* + * preprocess data: bound State.XN so it belongs to the + * feasible set and store it in the State.X + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + } + + /* + * RComm + */ + mincomp_clearrequestfields(state, _state); + state->needfg = ae_true; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->needfg = ae_false; + + /* + * postprocess data: zero components of G corresponding to + * the active constraints + */ + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->gc.ptr.p_double[i] = (double)(0); + } + else + { + state->gc.ptr.p_double[i] = state->g.ptr.p_double[i]; + } + } + mcsrch(n, &state->xn, &state->f, &state->gc, &state->d, &state->stp, state->stpmax, mincomp_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_51; +lbl_52: + diffcnt = 0; + for(i=0; i<=n-1; i++) + { + + /* + * XN contains unprojected result, project it, + * save copy to X (will be used for progress reporting) + */ + state->xn.ptr.p_double[i] = boundval(state->xn.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state); + + /* + * update active set + */ + if( ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i])||ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->an.ptr.p_double[i] = (double)(0); + } + else + { + state->an.ptr.p_double[i] = (double)(1); + } + if( ae_fp_neq(state->an.ptr.p_double[i],state->ak.ptr.p_double[i]) ) + { + diffcnt = diffcnt+1; + } + state->ak.ptr.p_double[i] = state->an.ptr.p_double[i]; + } + ae_v_move(&state->xk.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->repnfev = state->repnfev+state->nfev; + state->repiterationscount = state->repiterationscount+1; + if( !state->xrep ) + { + goto lbl_53; + } + + /* + * progress report + */ + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->xupdated = ae_false; +lbl_53: + + /* + * Update info about step length + */ + v = ae_v_dotproduct(&state->d.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->laststep = ae_sqrt(v, _state)*state->stp; + + /* + * Check stopping conditions. + */ + if( ae_fp_greater(mincomp_asaboundedantigradnorm(state, _state),state->epsg) ) + { + goto lbl_55; + } + + /* + * Gradient is small enough + */ + state->repterminationtype = 4; + if( !state->xrep ) + { + goto lbl_57; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->xupdated = ae_false; +lbl_57: + result = ae_false; + return result; +lbl_55: + if( !(state->repiterationscount>=state->maxits&&state->maxits>0) ) + { + goto lbl_59; + } + + /* + * Too many iterations + */ + state->repterminationtype = 5; + if( !state->xrep ) + { + goto lbl_61; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->xupdated = ae_false; +lbl_61: + result = ae_false; + return result; +lbl_59: + if( !(ae_fp_greater_eq(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state))&&diffcnt==0) ) + { + goto lbl_63; + } + + /* + * These conditions (EpsF/EpsX) are explicitly or implicitly + * related to the current step size and influenced + * by changes in the active constraints. + * + * For these reasons they are checked only when we don't + * want to 'unstick' at the end of the iteration and there + * were no changes in the active set. + * + * NOTE: consition |G|>=Mu*|D1| must be exactly opposite + * to the condition used to switch back to GPA. At least + * one inequality must be strict, otherwise infinite cycle + * may occur when |G|=Mu*|D1| (we DON'T test stopping + * conditions and we DON'T switch to GPA, so we cycle + * indefinitely). + */ + if( ae_fp_greater(state->fold-state->f,state->epsf*ae_maxreal(ae_fabs(state->fold, _state), ae_maxreal(ae_fabs(state->f, _state), 1.0, _state), _state)) ) + { + goto lbl_65; + } + + /* + * F(k+1)-F(k) is small enough + */ + state->repterminationtype = 1; + if( !state->xrep ) + { + goto lbl_67; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->xupdated = ae_false; +lbl_67: + result = ae_false; + return result; +lbl_65: + if( ae_fp_greater(state->laststep,state->epsx) ) + { + goto lbl_69; + } + + /* + * X(k+1)-X(k) is small enough + */ + state->repterminationtype = 2; + if( !state->xrep ) + { + goto lbl_71; + } + mincomp_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->xupdated = ae_false; +lbl_71: + result = ae_false; + return result; +lbl_69: +lbl_63: + + /* + * Check conditions for switching + */ + if( ae_fp_less(mincomp_asaginorm(state, _state),state->mu*mincomp_asad1norm(state, _state)) ) + { + state->curalgo = 0; + goto lbl_50; + } + if( diffcnt>0 ) + { + if( mincomp_asauisempty(state, _state)||diffcnt>=mincomp_n2 ) + { + state->curalgo = 1; + } + else + { + state->curalgo = 0; + } + goto lbl_50; + } + + /* + * Calculate D(k+1) + * + * Line search may result in: + * * maximum feasible step being taken (already processed) + * * point satisfying Wolfe conditions + * * some kind of error (CG is restarted by assigning 0.0 to Beta) + */ + if( mcinfo==1 ) + { + + /* + * Standard Wolfe conditions are satisfied: + * * calculate Y[K] and BetaK + */ + ae_v_add(&state->yk.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vv = ae_v_dotproduct(&state->yk.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->betady = v/vv; + v = ae_v_dotproduct(&state->gc.ptr.p_double[0], 1, &state->yk.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->betahs = v/vv; + if( state->cgtype==0 ) + { + betak = state->betady; + } + if( state->cgtype==1 ) + { + betak = ae_maxreal((double)(0), ae_minreal(state->betady, state->betahs, _state), _state); + } + } + else + { + + /* + * Something is wrong (may be function is too wild or too flat). + * + * We'll set BetaK=0, which will restart CG algorithm. + * We can stop later (during normal checks) if stopping conditions are met. + */ + betak = (double)(0); + state->debugrestartscount = state->debugrestartscount+1; + } + ae_v_moveneg(&state->dn.ptr.p_double[0], 1, &state->gc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->dn.ptr.p_double[0], 1, &state->dk.ptr.p_double[0], 1, ae_v_len(0,n-1), betak); + ae_v_move(&state->dk.ptr.p_double[0], 1, &state->dn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * update other information + */ + state->fold = state->f; + state->k = state->k+1; + goto lbl_49; +lbl_50: +lbl_47: + goto lbl_17; +lbl_18: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ia.ptr.p_int[2] = mcinfo; + state->rstate.ia.ptr.p_int[3] = diffcnt; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ba.ptr.p_bool[1] = stepfound; + state->rstate.ra.ptr.p_double[0] = betak; + state->rstate.ra.ptr.p_double[1] = v; + state->rstate.ra.ptr.p_double[2] = vv; + return result; +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresults(const minasastate* state, + /* Real */ ae_vector* x, + minasareport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minasareport_clear(rep); + + minasaresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresultsbuf(const minasastate* state, + /* Real */ ae_vector* x, + minasareport* rep, + ae_state *_state) +{ + ae_int_t i; + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nfev = state->repnfev; + rep->terminationtype = state->repterminationtype; + rep->activeconstraints = 0; + for(i=0; i<=state->n-1; i++) + { + if( ae_fp_eq(state->ak.ptr.p_double[i],(double)(0)) ) + { + rep->activeconstraints = rep->activeconstraints+1; + } + } +} + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minasarestartfrom(minasastate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "MinASARestartFrom: Length(X)n, _state), "MinASARestartFrom: X contains infinite or NaN values!", _state); + ae_assert(bndl->cnt>=state->n, "MinASARestartFrom: Length(BndL)n, _state), "MinASARestartFrom: BndL contains infinite or NaN values!", _state); + ae_assert(bndu->cnt>=state->n, "MinASARestartFrom: Length(BndU)n, _state), "MinASARestartFrom: BndU contains infinite or NaN values!", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_v_move(&state->bndl.ptr.p_double[0], 1, &bndl->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_v_move(&state->bndu.ptr.p_double[0], 1, &bndu->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->laststep = (double)(0); + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + mincomp_clearrequestfields(state, _state); +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minasasetprotocolv1(minasastate* state, ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 3+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Returns norm of bounded anti-gradient. + +Bounded antigradient is a vector obtained from anti-gradient by zeroing +components which point outwards: + result = norm(v) + v[i]=0 if ((-g[i]<0)and(x[i]=bndl[i])) or + ((-g[i]>0)and(x[i]=bndu[i])) + v[i]=-g[i] otherwise + +This function may be used to check a stopping criterion. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +static double mincomp_asaboundedantigradnorm(const minasastate* state, + ae_state *_state) +{ + ae_int_t i; + double v; + double result; + + + result = (double)(0); + for(i=0; i<=state->n-1; i++) + { + v = -state->g.ptr.p_double[i]; + if( ae_fp_eq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_less(-state->g.ptr.p_double[i],(double)(0)) ) + { + v = (double)(0); + } + if( ae_fp_eq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i])&&ae_fp_greater(-state->g.ptr.p_double[i],(double)(0)) ) + { + v = (double)(0); + } + result = result+ae_sqr(v, _state); + } + result = ae_sqrt(result, _state); + return result; +} + + +/************************************************************************* +Returns norm of GI(x). + +GI(x) is a gradient vector whose components associated with active +constraints are zeroed. It differs from bounded anti-gradient because +components of GI(x) are zeroed independently of sign(g[i]), and +anti-gradient's components are zeroed with respect to both constraint and +sign. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +static double mincomp_asaginorm(const minasastate* state, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=0; i<=state->n-1; i++) + { + if( ae_fp_neq(state->x.ptr.p_double[i],state->bndl.ptr.p_double[i])&&ae_fp_neq(state->x.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + result = result+ae_sqr(state->g.ptr.p_double[i], _state); + } + } + result = ae_sqrt(result, _state); + return result; +} + + +/************************************************************************* +Returns norm(D1(State.X)) + +For a meaning of D1 see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED +OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +static double mincomp_asad1norm(const minasastate* state, + ae_state *_state) +{ + ae_int_t i; + double result; + + + result = (double)(0); + for(i=0; i<=state->n-1; i++) + { + result = result+ae_sqr(boundval(state->x.ptr.p_double[i]-state->g.ptr.p_double[i], state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i], _state)-state->x.ptr.p_double[i], _state); + } + result = ae_sqrt(result, _state); + return result; +} + + +/************************************************************************* +Returns True, if U set is empty. + +* State.X is used as point, +* State.G - as gradient, +* D is calculated within function (because State.D may have different + meaning depending on current optimization algorithm) + +For a meaning of U see 'NEW ACTIVE SET ALGORITHM FOR BOX CONSTRAINED +OPTIMIZATION' by WILLIAM W. HAGER AND HONGCHAO ZHANG. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +static ae_bool mincomp_asauisempty(const minasastate* state, + ae_state *_state) +{ + ae_int_t i; + double d; + double d2; + double d32; + ae_bool result; + + + d = mincomp_asad1norm(state, _state); + d2 = ae_sqrt(d, _state); + d32 = d*d2; + result = ae_true; + for(i=0; i<=state->n-1; i++) + { + if( ae_fp_greater_eq(ae_fabs(state->g.ptr.p_double[i], _state),d2)&&ae_fp_greater_eq(ae_minreal(state->x.ptr.p_double[i]-state->bndl.ptr.p_double[i], state->bndu.ptr.p_double[i]-state->x.ptr.p_double[i], _state),d32) ) + { + result = ae_false; + return result; + } + } + return result; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void mincomp_clearrequestfields(minasastate* state, + ae_state *_state) +{ + + + state->needfg = ae_false; + state->xupdated = ae_false; +} + + +void _minasastate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minasastate *p = (minasastate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ak, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->an, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->dn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->yk, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); +} + + +void _minasastate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minasastate *dst = (minasastate*)_dst; + const minasastate *src = (const minasastate*)_src; + dst->n = src->n; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + dst->cgtype = src->cgtype; + dst->k = src->k; + dst->nfev = src->nfev; + dst->mcstage = src->mcstage; + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->curalgo = src->curalgo; + dst->acount = src->acount; + dst->mu = src->mu; + dst->finit = src->finit; + dst->dginit = src->dginit; + ae_vector_init_copy(&dst->ak, &src->ak, _state, make_automatic); + ae_vector_init_copy(&dst->xk, &src->xk, _state, make_automatic); + ae_vector_init_copy(&dst->dk, &src->dk, _state, make_automatic); + ae_vector_init_copy(&dst->an, &src->an, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->dn, &src->dn, _state, make_automatic); + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->fold = src->fold; + dst->stp = src->stp; + ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic); + ae_vector_init_copy(&dst->yk, &src->yk, _state, make_automatic); + ae_vector_init_copy(&dst->gc, &src->gc, _state, make_automatic); + dst->laststep = src->laststep; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needfg = src->needfg; + dst->xupdated = src->xupdated; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + dst->repterminationtype = src->repterminationtype; + dst->debugrestartscount = src->debugrestartscount; + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->betahs = src->betahs; + dst->betady = src->betady; +} + + +void _minasastate_clear(void* _p) +{ + minasastate *p = (minasastate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->ak); + ae_vector_clear(&p->xk); + ae_vector_clear(&p->dk); + ae_vector_clear(&p->an); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->dn); + ae_vector_clear(&p->d); + ae_vector_clear(&p->work); + ae_vector_clear(&p->yk); + ae_vector_clear(&p->gc); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + _rcommstate_clear(&p->rstate); + _linminstate_clear(&p->lstate); +} + + +void _minasastate_destroy(void* _p) +{ + minasastate *p = (minasastate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->ak); + ae_vector_destroy(&p->xk); + ae_vector_destroy(&p->dk); + ae_vector_destroy(&p->an); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->dn); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->work); + ae_vector_destroy(&p->yk); + ae_vector_destroy(&p->gc); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + _rcommstate_destroy(&p->rstate); + _linminstate_destroy(&p->lstate); +} + + +void _minasareport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minasareport *p = (minasareport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minasareport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minasareport *dst = (minasareport*)_dst; + const minasareport *src = (const minasareport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->terminationtype = src->terminationtype; + dst->activeconstraints = src->activeconstraints; +} + + +void _minasareport_clear(void* _p) +{ + minasareport *p = (minasareport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minasareport_destroy(void* _p) +{ + minasareport *p = (minasareport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + BOX CONSTRAINED OPTIMIZATION + WITH FAST ACTIVATION OF MULTIPLE BOX CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to box +constraints (with some of box constraints actually being equality ones). + +This optimizer uses algorithm similar to that of MinBLEIC (optimizer with +general linear constraints), but presence of box-only constraints allows +us to use faster constraint activation strategies. On large-scale problems, +with multiple constraints active at the solution, this optimizer can be +several times faster than BLEIC. + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBCCreate() call + +2. USer adds box constraints by calling MinBCSetBC() function. + +3. User sets stopping conditions with MinBCSetCond(). + +4. User calls MinBCOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBCResults() to get solution + +6. Optionally user may call MinBCRestartFrom() to solve another problem + with same N but another starting point. + MinBCRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minbcstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + _minbcstate_clear(state); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "MinBCCreate: N<1", _state); + ae_assert(x->cnt>=n, "MinBCCreate: Length(X)0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBCSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbcstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + _minbcstate_clear(state); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + ae_assert(n>=1, "MinBCCreateF: N<1", _state); + ae_assert(x->cnt>=n, "MinBCCreateF: Length(X)nmain; + ae_assert(bndl->cnt>=n, "MinBCSetBC: Length(BndL)cnt>=n, "MinBCSetBC: Length(BndU)ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "MinBCSetBC: BndL contains NAN or +INF", _state); + ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "MinBCSetBC: BndL contains NAN or -INF", _state); + state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i]; + state->hasbndl.ptr.p_bool[i] = ae_isfinite(bndl->ptr.p_double[i], _state); + state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i]; + state->hasbndu.ptr.p_bool[i] = ae_isfinite(bndu->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBCSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetcond(minbcstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsg, _state), "MinBCSetCond: EpsG is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsg,(double)(0)), "MinBCSetCond: negative EpsG", _state); + ae_assert(ae_isfinite(epsf, _state), "MinBCSetCond: EpsF is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "MinBCSetCond: negative EpsF", _state); + ae_assert(ae_isfinite(epsx, _state), "MinBCSetCond: EpsX is not finite number", _state); + ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "MinBCSetCond: negative EpsX", _state); + ae_assert(maxits>=0, "MinBCSetCond: negative MaxIts!", _state); + if( ((ae_fp_eq(epsg,(double)(0))&&ae_fp_eq(epsf,(double)(0)))&&ae_fp_eq(epsx,(double)(0)))&&maxits==0 ) + { + epsx = 1.0E-6; + } + state->epsg = epsg; + state->epsf = epsf; + state->epsx = epsx; + state->maxits = maxits; +} + + +/************************************************************************* +This function sets scaling coefficients for BC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBCSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbcsetscale(minbcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->nmain, "MinBCSetScale: Length(S)nmain-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MinBCSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MinBCSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdefault(minbcstate* state, ae_state *_state) +{ + + + state->prectype = 0; +} + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdiag(minbcstate* state, + /* Real */ const ae_vector* d, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(d->cnt>=state->nmain, "MinBCSetPrecDiag: D is too short", _state); + for(i=0; i<=state->nmain-1; i++) + { + ae_assert(ae_isfinite(d->ptr.p_double[i], _state), "MinBCSetPrecDiag: D contains infinite or NAN elements", _state); + ae_assert(ae_fp_greater(d->ptr.p_double[i],(double)(0)), "MinBCSetPrecDiag: D contains non-positive elements", _state); + } + rvectorsetlengthatleast(&state->diagh, state->nmain, _state); + state->prectype = 2; + for(i=0; i<=state->nmain-1; i++) + { + state->diagh.ptr.p_double[i] = d->ptr.p_double[i]; + } +} + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBCSetScale() +call (before or after MinBCSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecscale(minbcstate* state, ae_state *_state) +{ + + + state->prectype = 3; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBCOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetxrep(minbcstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetstpmax(minbcstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "MinBCSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "MinBCSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinBCCreate() for analytical gradient or MinBCCreateF() + for numerical differentiation) you should choose appropriate variant of + MinBCOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinBCOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinBCOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinBCOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinBCCreateF() | works FAILS + MinBCCreate() | FAILS works + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinBCOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinBCCreateF() + and to pass gradient information to MinCGOptimize()) will lead to + exception being thrown. Either you did not pass gradient when it WAS + needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool minbciteration(minbcstate* state, ae_state *_state) +{ + ae_int_t freezeidx; + double freezeval; + double scaleddnorm; + ae_int_t n; + ae_int_t m; + ae_int_t i; + ae_int_t j; + double v; + double vv; + double v0; + ae_bool b; + ae_int_t mcinfo; + ae_int_t itidx; + double ginit; + double gdecay; + ae_bool activationstatus; + double activationstep; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + freezeidx = state->rstate.ia.ptr.p_int[0]; + n = state->rstate.ia.ptr.p_int[1]; + m = state->rstate.ia.ptr.p_int[2]; + i = state->rstate.ia.ptr.p_int[3]; + j = state->rstate.ia.ptr.p_int[4]; + mcinfo = state->rstate.ia.ptr.p_int[5]; + itidx = state->rstate.ia.ptr.p_int[6]; + b = state->rstate.ba.ptr.p_bool[0]; + activationstatus = state->rstate.ba.ptr.p_bool[1]; + freezeval = state->rstate.ra.ptr.p_double[0]; + scaleddnorm = state->rstate.ra.ptr.p_double[1]; + v = state->rstate.ra.ptr.p_double[2]; + vv = state->rstate.ra.ptr.p_double[3]; + v0 = state->rstate.ra.ptr.p_double[4]; + ginit = state->rstate.ra.ptr.p_double[5]; + gdecay = state->rstate.ra.ptr.p_double[6]; + activationstep = state->rstate.ra.ptr.p_double[7]; + } + else + { + freezeidx = 359; + n = -58; + m = -919; + i = -909; + j = 81; + mcinfo = 255; + itidx = 74; + b = ae_false; + activationstatus = ae_true; + freezeval = 205.0; + scaleddnorm = -838.0; + v = 939.0; + vv = -526.0; + v0 = 763.0; + ginit = -541.0; + gdecay = -698.0; + activationstep = -900.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + if( state->rstate.stage==8 ) + { + goto lbl_8; + } + if( state->rstate.stage==9 ) + { + goto lbl_9; + } + if( state->rstate.stage==10 ) + { + goto lbl_10; + } + if( state->rstate.stage==11 ) + { + goto lbl_11; + } + if( state->rstate.stage==12 ) + { + goto lbl_12; + } + if( state->rstate.stage==13 ) + { + goto lbl_13; + } + if( state->rstate.stage==14 ) + { + goto lbl_14; + } + if( state->rstate.stage==15 ) + { + goto lbl_15; + } + if( state->rstate.stage==16 ) + { + goto lbl_16; + } + if( state->rstate.stage==17 ) + { + goto lbl_17; + } + if( state->rstate.stage==18 ) + { + goto lbl_18; + } + if( state->rstate.stage==19 ) + { + goto lbl_19; + } + if( state->rstate.stage==20 ) + { + goto lbl_20; + } + if( state->rstate.stage==21 ) + { + goto lbl_21; + } + if( state->rstate.stage==22 ) + { + goto lbl_22; + } + if( state->rstate.stage==23 ) + { + goto lbl_23; + } + if( state->rstate.stage==24 ) + { + goto lbl_24; + } + if( state->rstate.stage==25 ) + { + goto lbl_25; + } + if( state->rstate.stage==26 ) + { + goto lbl_26; + } + if( state->rstate.stage==27 ) + { + goto lbl_27; + } + if( state->rstate.stage==28 ) + { + goto lbl_28; + } + if( state->rstate.stage==29 ) + { + goto lbl_29; + } + + /* + * Routine body + */ + + /* + * Algorithm parameters: + * * M number of L-BFGS corrections. + * This coefficient remains fixed during iterations. + * * GDecay desired decrease of constrained gradient during L-BFGS iterations. + * This coefficient is decreased after each L-BFGS round until + * it reaches minimum decay. + */ + m = ae_minint(5, state->nmain, _state); + gdecay = minbc_initialdecay; + + /* + * Init + */ + n = state->nmain; + for(i=0; i<=n-1; i++) + { + state->xc.ptr.p_double[i] = state->xstart.ptr.p_double[i]; + } + if( !enforceboundaryconstraints(&state->xc, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, 0, _state) ) + { + + /* + * Inconsistent constraints + */ + state->repterminationtype = -3; + result = ae_false; + return result; + } + state->userterminationneeded = ae_false; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfev = 0; + state->repvaridx = -1; + rmatrixsetlengthatleast(&state->bufyk, m+1, n, _state); + rmatrixsetlengthatleast(&state->bufsk, m+1, n, _state); + rvectorsetlengthatleast(&state->bufrho, m, _state); + rvectorsetlengthatleast(&state->buftheta, m, _state); + rvectorsetlengthatleast(&state->tmp0, n, _state); + smoothnessmonitorinit(&state->smonitor, &state->s, n, 1, state->smoothnessguardlevel>0, _state); + for(i=0; i<=n-1; i++) + { + state->lastscaleused.ptr.p_double[i] = state->s.ptr.p_double[i]; + state->invs.ptr.p_double[i] = (double)1/state->s.ptr.p_double[i]; + } + + /* + * Fill TmpPrec with current preconditioner + */ + rvectorsetlengthatleast(&state->tmpprec, n, _state); + for(i=0; i<=n-1; i++) + { + if( state->prectype==2 ) + { + state->tmpprec.ptr.p_double[i] = (double)1/state->diagh.ptr.p_double[i]; + continue; + } + if( state->prectype==3 ) + { + state->tmpprec.ptr.p_double[i] = ae_sqr(state->s.ptr.p_double[i], _state); + continue; + } + state->tmpprec.ptr.p_double[i] = (double)(1); + } + + /* + * Check correctness of user-supplied gradient + */ + minbc_clearrequestfields(state, _state); + if( !(ae_fp_eq(state->diffstep,(double)(0))&&ae_fp_greater(state->teststep,(double)(0))) ) + { + goto lbl_30; + } +lbl_32: + if( !smoothnessmonitorcheckgradientatx0(&state->smonitor, &state->xc, &state->s, &state->bndl, &state->bndu, ae_true, state->teststep, _state) ) + { + goto lbl_33; + } + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->smonitor.x.ptr.p_double[i]; + } + state->needfg = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needfg = ae_false; + state->smonitor.fi.ptr.p_double[0] = state->f; + for(i=0; i<=n-1; i++) + { + state->smonitor.j.ptr.pp_double[0][i] = state->g.ptr.p_double[i]; + } + goto lbl_32; +lbl_33: +lbl_30: + + /* + * Main cycle of BC-PG algorithm + */ + state->repterminationtype = 0; + state->lastscaledgoodstep = (double)(0); + state->nonmonotoniccnt = ae_round(1.5*(double)n, _state)+5; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbc_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_34; + } + state->needfg = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needfg = ae_false; + goto lbl_35; +lbl_34: + state->needf = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needf = ae_false; +lbl_35: + state->fc = state->f; + trimprepare(state->f, &state->trimthreshold, _state); + state->repnfev = state->repnfev+1; + if( !state->xrep ) + { + goto lbl_36; + } + + /* + * Report current point + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fc; + state->xupdated = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->xupdated = ae_false; +lbl_36: + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } +lbl_38: + if( ae_false ) + { + goto lbl_39; + } + + /* + * Steepest descent phase + * + * (a) calculate unconstrained gradient + * (b) check F/G for NAN/INF, abnormally terminate algorithm if needed + * (c) perform one steepest descent step, activating only those constraints + * which prevent us from moving outside of box-constrained area + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbc_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_40; + } + + /* + * Analytic gradient + */ + state->needfg = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needfg = ae_false; + goto lbl_41; +lbl_40: + + /* + * Numerical differentiation + */ + state->needf = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->fbase = state->f; + i = 0; +lbl_42: + if( i>n-1 ) + { + goto lbl_44; + } + v = state->x.ptr.p_double[i]; + b = ae_false; + if( state->hasbndl.ptr.p_bool[i] ) + { + b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); + } + if( b ) + { + goto lbl_45; + } + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 8; + goto lbl_rcomm; +lbl_8: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 9; + goto lbl_rcomm; +lbl_9: + state->fp2 = state->f; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + goto lbl_46; +lbl_45: + state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; + state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) + { + state->xm1 = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) + { + state->xp1 = state->bndu.ptr.p_double[i]; + } + state->x.ptr.p_double[i] = state->xm1; + state->rstate.stage = 10; + goto lbl_rcomm; +lbl_10: + state->fm1 = state->f; + state->x.ptr.p_double[i] = state->xp1; + state->rstate.stage = 11; + goto lbl_rcomm; +lbl_11: + state->fp1 = state->f; + if( ae_fp_neq(state->xm1,state->xp1) ) + { + state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); + } + else + { + state->g.ptr.p_double[i] = (double)(0); + } +lbl_46: + state->x.ptr.p_double[i] = v; + i = i+1; + goto lbl_42; +lbl_44: + state->f = state->fbase; + state->needf = ae_false; +lbl_41: + state->fc = state->f; + ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + projectgradientintobc(&state->xc, &state->cgc, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, 0, _state); + ginit = 0.0; + for(i=0; i<=n-1; i++) + { + ginit = ginit+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + ginit = ae_sqrt(ginit, _state); + if( !ae_isfinite(ginit, _state)||!ae_isfinite(state->fc, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( ae_fp_less_eq(ginit,state->epsg) ) + { + + /* + * Gradient is small enough. + * Optimization is terminated + */ + state->repterminationtype = 4; + result = ae_false; + return result; + } + for(i=0; i<=n-1; i++) + { + state->d.ptr.p_double[i] = -state->tmpprec.ptr.p_double[i]*state->cgc.ptr.p_double[i]; + } + scaleddnorm = (double)(0); + for(i=0; i<=n-1; i++) + { + scaleddnorm = scaleddnorm+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + scaleddnorm = ae_sqrt(scaleddnorm, _state); + ae_assert(ae_fp_greater(scaleddnorm,(double)(0)), "MinBC: integrity check failed", _state); + if( ae_fp_greater(state->lastscaledgoodstep,(double)(0)) ) + { + state->stp = state->lastscaledgoodstep/scaleddnorm; + } + else + { + state->stp = 1.0/scaleddnorm; + } + calculatestepbound(&state->xc, &state->d, 1.0, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, 0, &freezeidx, &freezeval, &state->curstpmax, _state); + activationstep = state->curstpmax; + if( freezeidx<0||ae_fp_greater(state->curstpmax,1.0E50) ) + { + state->curstpmax = 1.0E50; + } + if( ae_fp_greater(state->stpmax,(double)(0)) ) + { + state->curstpmax = ae_minreal(state->curstpmax, state->stpmax/scaleddnorm, _state); + } + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->ugc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fn = state->fc; + state->mcstage = 0; + smoothnessmonitorstartlinesearch1u(&state->smonitor, &state->s, &state->invs, &state->xn, state->fn, &state->ugn, state->repiterationscount, -1, _state); + mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbc_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_47: + if( state->mcstage==0 ) + { + goto lbl_48; + } + + /* + * Copy XN to X, perform on-the-fly correction w.r.t box + * constraints (projection onto feasible set). + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->x.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->x.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + + /* + * Gradient, either user-provided or numerical differentiation + */ + minbc_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_49; + } + + /* + * Analytic gradient + */ + state->needfg = ae_true; + state->rstate.stage = 12; + goto lbl_rcomm; +lbl_12: + state->needfg = ae_false; + state->repnfev = state->repnfev+1; + goto lbl_50; +lbl_49: + + /* + * Numerical differentiation + */ + state->needf = ae_true; + state->rstate.stage = 13; + goto lbl_rcomm; +lbl_13: + state->fbase = state->f; + i = 0; +lbl_51: + if( i>n-1 ) + { + goto lbl_53; + } + v = state->x.ptr.p_double[i]; + b = ae_false; + if( state->hasbndl.ptr.p_bool[i] ) + { + b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); + } + if( b ) + { + goto lbl_54; + } + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 14; + goto lbl_rcomm; +lbl_14: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 15; + goto lbl_rcomm; +lbl_15: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 16; + goto lbl_rcomm; +lbl_16: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 17; + goto lbl_rcomm; +lbl_17: + state->fp2 = state->f; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + state->repnfev = state->repnfev+4; + goto lbl_55; +lbl_54: + state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; + state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) + { + state->xm1 = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) + { + state->xp1 = state->bndu.ptr.p_double[i]; + } + state->x.ptr.p_double[i] = state->xm1; + state->rstate.stage = 18; + goto lbl_rcomm; +lbl_18: + state->fm1 = state->f; + state->x.ptr.p_double[i] = state->xp1; + state->rstate.stage = 19; + goto lbl_rcomm; +lbl_19: + state->fp1 = state->f; + if( ae_fp_neq(state->xm1,state->xp1) ) + { + state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); + } + else + { + state->g.ptr.p_double[i] = (double)(0); + } + state->repnfev = state->repnfev+2; +lbl_55: + state->x.ptr.p_double[i] = v; + i = i+1; + goto lbl_51; +lbl_53: + state->f = state->fbase; + state->needf = ae_false; +lbl_50: + + /* + * Back to MCSRCH + */ + smoothnessmonitorenqueuepoint1u(&state->smonitor, &state->s, &state->invs, &state->d, state->stp, &state->x, state->f, &state->g, _state); + trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); + state->fn = state->f; + ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(state->d.ptr.p_double[i],(double)(0)) ) + { + state->cgn.ptr.p_double[i] = (double)(0); + } + } + mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbc_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_47; +lbl_48: + smoothnessmonitorfinalizelinesearch(&state->smonitor, _state); + v = state->fn; + for(i=0; i<=n-1; i++) + { + v = 0.1*v+state->ugn.ptr.p_double[i]; + } + if( !ae_isfinite(v, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( mcinfo!=1&&mcinfo!=5 ) + { + + /* + * We can not find step which decreases function value. We have + * two possibilities: + * (a) numerical properties of the function do not allow us to + * find good step. + * (b) we are close to activation of some constraint, and it is + * so close that step which activates it leads to change in + * target function which is smaller than numerical noise. + * + * Optimization algorithm must be able to handle case (b), because + * inability to handle it will cause failure when algorithm + * started very close to boundary of the feasible area. + * + * In order to correctly handle such cases we allow limited amount + * of small steps which increase function value. + */ + if( (freezeidx>=0&&ae_fp_less_eq(scaleddnorm*state->curstpmax,minbc_maxnonmonotoniclen))&&state->nonmonotoniccnt>0 ) + { + + /* + * We enforce non-monotonic step: + * * Stp := CurStpMax + * * MCINFO := 5 + * * XN := XC+CurStpMax*D + * * non-monotonic counter is decreased + * + * NOTE: UGN/CGN are not updated because step is so short that we assume that + * GN is approximately equal to GC. + */ + state->stp = state->curstpmax; + mcinfo = 5; + v = state->curstpmax; + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->xn.ptr.p_double[0], 1, &state->d.ptr.p_double[0], 1, ae_v_len(0,n-1), v); + state->nonmonotoniccnt = state->nonmonotoniccnt-1; + } + else + { + + /* + * Numerical properties of the function does not allow + * us to solve problem. Algorithm is terminated + */ + state->repterminationtype = 7; + result = ae_false; + return result; + } + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + ae_assert(mcinfo!=5||ae_fp_eq(state->stp,state->curstpmax), "MinBC: integrity check failed", _state); + postprocessboundedstep(&state->xn, &state->xc, &state->bndl, &state->hasbndl, &state->bndu, &state->hasbndu, n, 0, freezeidx, freezeval, state->stp, activationstep, _state); + state->fp = state->fc; + state->fc = state->fn; + ae_v_move(&state->xp.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->ugn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( !state->xrep ) + { + goto lbl_56; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbc_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 20; + goto lbl_rcomm; +lbl_20: + state->xupdated = ae_false; +lbl_56: + state->repiterationscount = state->repiterationscount+1; + if( mcinfo==1 ) + { + v = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr((state->xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); + } + v = ae_sqrt(v, _state); + if( ae_fp_less_eq(v,state->epsx) ) + { + + /* + * Step is small enough + */ + state->repterminationtype = 2; + result = ae_false; + return result; + } + if( ae_fp_less_eq(ae_fabs(state->fp-state->fc, _state),state->epsf*ae_maxreal(ae_fabs(state->fc, _state), ae_maxreal(ae_fabs(state->fp, _state), 1.0, _state), _state)) ) + { + + /* + * Function change is small enough + */ + state->repterminationtype = 1; + result = ae_false; + return result; + } + } + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + + /* + * Iteration counter exceeded limit + */ + state->repterminationtype = 5; + result = ae_false; + return result; + } + + /* + * LBFGS stage: + * * during LBFGS iterations we activate new constraints, but never + * deactivate already active ones. + * * we perform at most N iterations of LBFGS before re-evaluating + * active set and restarting LBFGS. + * + * About termination: + * * LBFGS iterations can be terminated because of two reasons: + * * "termination" - non-zero termination code in RepTerminationType, + * which means that optimization is done + * * "restart" - zero RepTerminationType, which means that we + * have to re-evaluate active set and resume LBFGS stage. + * * one more option is "refresh" - to continue LBFGS iterations, + * but with all BFGS updates (Sk/Yk pairs) being dropped; + * it happens after changes in active set + */ + ginit = 0.0; + for(i=0; i<=n-1; i++) + { + state->cgc.ptr.p_double[i] = state->ugc.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->cgc.ptr.p_double[i] = (double)(0); + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cgc.ptr.p_double[i] = (double)(0); + } + ginit = ginit+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + ginit = ae_sqrt(ginit, _state); + state->bufsize = 0; + itidx = 0; +lbl_58: + if( itidx>n-1 ) + { + goto lbl_60; + } + + /* + * At the beginning of each iteration: + * * XC stores current point + * * FC stores current function value + * * UGC stores current unconstrained gradient + * * CGC stores current constrained gradient + * * D stores constrained step direction (calculated at this block) + * + * 1. Calculate search direction D according to L-BFGS algorithm + * using constrained preconditioner to perform inner multiplication. + * 2. Evaluate scaled length of direction D; restart LBFGS if D is zero + * (it may be possible that we found minimum, but it is also possible + * that some constraints need deactivation) + * 3. If D is non-zero, try to use previous scaled step length as initial estimate for new step. + * 4. Calculate bound on step length. + */ + ae_v_move(&state->work.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + for(i=state->bufsize-1; i>=0; i--) + { + v = ae_v_dotproduct(&state->bufsk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->buftheta.ptr.p_double[i] = v; + vv = v*state->bufrho.ptr.p_double[i]; + ae_v_subd(&state->work.ptr.p_double[0], 1, &state->bufyk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); + } + for(i=0; i<=n-1; i++) + { + state->work.ptr.p_double[i] = state->tmpprec.ptr.p_double[i]*state->work.ptr.p_double[i]; + } + for(i=0; i<=state->bufsize-1; i++) + { + v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[i][0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + vv = state->bufrho.ptr.p_double[i]*(-v+state->buftheta.ptr.p_double[i]); + ae_v_addd(&state->work.ptr.p_double[0], 1, &state->bufsk.ptr.pp_double[i][0], 1, ae_v_len(0,n-1), vv); + } + ae_v_moveneg(&state->d.ptr.p_double[0], 1, &state->work.ptr.p_double[0], 1, ae_v_len(0,n-1)); + b = ae_false; + for(i=0; i<=n-1; i++) + { + b = b||((state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_neq(state->d.ptr.p_double[i],(double)(0))); + b = b||((state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xc.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_neq(state->d.ptr.p_double[i],(double)(0))); + } + ae_assert(!b, "MinBC: integrity check failed (q)", _state); + scaleddnorm = (double)(0); + for(i=0; i<=n-1; i++) + { + scaleddnorm = scaleddnorm+ae_sqr(state->d.ptr.p_double[i]/state->s.ptr.p_double[i], _state); + } + scaleddnorm = ae_sqrt(scaleddnorm, _state); + if( ae_fp_eq(scaleddnorm,(double)(0)) ) + { + + /* + * Search direction is zero. + * Skip back to steepest descent phase. + */ + goto lbl_60; + } + if( ae_fp_greater(state->lastscaledgoodstep,(double)(0)) ) + { + state->stp = state->lastscaledgoodstep/scaleddnorm; + } + else + { + state->stp = 1.0/scaleddnorm; + } + state->curstpmax = 1.0E50; + if( ae_fp_greater(state->stpmax,(double)(0)) ) + { + state->curstpmax = ae_minreal(state->curstpmax, state->stpmax/scaleddnorm, _state); + } + + /* + * Minimize G(t) = F(CONSTRAIN(XC + t*D)), with t being scalar, XC and D being vectors. + */ + ae_v_move(&state->xn.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgn.ptr.p_double[0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugn.ptr.p_double[0], 1, &state->ugc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fn = state->fc; + state->mcstage = 0; + smoothnessmonitorstartlinesearch1u(&state->smonitor, &state->s, &state->invs, &state->xn, state->fn, &state->ugn, state->repiterationscount, -1, _state); + mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbc_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); +lbl_61: + if( state->mcstage==0 ) + { + goto lbl_62; + } + + /* + * Copy XN to X, perform on-the-fly correction w.r.t box + * constraints (projection onto feasible set). + */ + for(i=0; i<=n-1; i++) + { + state->x.ptr.p_double[i] = state->xn.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->x.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->x.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + + /* + * Gradient, either user-provided or numerical differentiation + */ + minbc_clearrequestfields(state, _state); + if( ae_fp_neq(state->diffstep,(double)(0)) ) + { + goto lbl_63; + } + + /* + * Analytic gradient + */ + state->needfg = ae_true; + state->rstate.stage = 21; + goto lbl_rcomm; +lbl_21: + state->needfg = ae_false; + state->repnfev = state->repnfev+1; + goto lbl_64; +lbl_63: + + /* + * Numerical differentiation + */ + state->needf = ae_true; + state->rstate.stage = 22; + goto lbl_rcomm; +lbl_22: + state->fbase = state->f; + i = 0; +lbl_65: + if( i>n-1 ) + { + goto lbl_67; + } + v = state->x.ptr.p_double[i]; + b = ae_false; + if( state->hasbndl.ptr.p_bool[i] ) + { + b = b||ae_fp_less(v-state->diffstep*state->s.ptr.p_double[i],state->bndl.ptr.p_double[i]); + } + if( state->hasbndu.ptr.p_bool[i] ) + { + b = b||ae_fp_greater(v+state->diffstep*state->s.ptr.p_double[i],state->bndu.ptr.p_double[i]); + } + if( b ) + { + goto lbl_68; + } + state->x.ptr.p_double[i] = v-state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 23; + goto lbl_rcomm; +lbl_23: + state->fm2 = state->f; + state->x.ptr.p_double[i] = v-0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 24; + goto lbl_rcomm; +lbl_24: + state->fm1 = state->f; + state->x.ptr.p_double[i] = v+0.5*state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 25; + goto lbl_rcomm; +lbl_25: + state->fp1 = state->f; + state->x.ptr.p_double[i] = v+state->diffstep*state->s.ptr.p_double[i]; + state->rstate.stage = 26; + goto lbl_rcomm; +lbl_26: + state->fp2 = state->f; + state->g.ptr.p_double[i] = ((double)8*(state->fp1-state->fm1)-(state->fp2-state->fm2))/((double)6*state->diffstep*state->s.ptr.p_double[i]); + state->repnfev = state->repnfev+4; + goto lbl_69; +lbl_68: + state->xm1 = v-state->diffstep*state->s.ptr.p_double[i]; + state->xp1 = v+state->diffstep*state->s.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less(state->xm1,state->bndl.ptr.p_double[i]) ) + { + state->xm1 = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater(state->xp1,state->bndu.ptr.p_double[i]) ) + { + state->xp1 = state->bndu.ptr.p_double[i]; + } + state->x.ptr.p_double[i] = state->xm1; + state->rstate.stage = 27; + goto lbl_rcomm; +lbl_27: + state->fm1 = state->f; + state->x.ptr.p_double[i] = state->xp1; + state->rstate.stage = 28; + goto lbl_rcomm; +lbl_28: + state->fp1 = state->f; + if( ae_fp_neq(state->xm1,state->xp1) ) + { + state->g.ptr.p_double[i] = (state->fp1-state->fm1)/(state->xp1-state->xm1); + } + else + { + state->g.ptr.p_double[i] = (double)(0); + } + state->repnfev = state->repnfev+2; +lbl_69: + state->x.ptr.p_double[i] = v; + i = i+1; + goto lbl_65; +lbl_67: + state->f = state->fbase; + state->needf = ae_false; +lbl_64: + + /* + * Back to MCSRCH + */ + smoothnessmonitorenqueuepoint1u(&state->smonitor, &state->s, &state->invs, &state->d, state->stp, &state->x, state->f, &state->g, _state); + trimfunction(&state->f, &state->g, n, state->trimthreshold, _state); + state->fn = state->f; + for(i=0; i<=n-1; i++) + { + state->ugn.ptr.p_double[i] = state->g.ptr.p_double[i]; + state->cgn.ptr.p_double[i] = state->g.ptr.p_double[i]; + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->cgn.ptr.p_double[i] = (double)(0); + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->cgn.ptr.p_double[i] = (double)(0); + } + } + mcsrch(n, &state->xn, &state->fn, &state->cgn, &state->d, &state->stp, state->curstpmax, minbc_gtol, &mcinfo, &state->nfev, &state->work, &state->lstate, &state->mcstage, _state); + goto lbl_61; +lbl_62: + smoothnessmonitorfinalizelinesearch(&state->smonitor, _state); + for(i=0; i<=n-1; i++) + { + if( state->hasbndl.ptr.p_bool[i]&&ae_fp_less_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i]) ) + { + state->xn.ptr.p_double[i] = state->bndl.ptr.p_double[i]; + } + if( state->hasbndu.ptr.p_bool[i]&&ae_fp_greater_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]) ) + { + state->xn.ptr.p_double[i] = state->bndu.ptr.p_double[i]; + } + } + ae_v_moveneg(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_moveneg(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_add(&state->bufsk.ptr.pp_double[state->bufsize][0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_add(&state->bufyk.ptr.pp_double[state->bufsize][0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * Handle special situations: + * * check for presence of NAN/INF in function/gradient + * * handle failure of line search + */ + v = state->fn; + for(i=0; i<=n-1; i++) + { + v = 0.1*v+state->ugn.ptr.p_double[i]; + } + if( !ae_isfinite(v, _state) ) + { + + /* + * Abnormal termination - infinities in function/gradient + */ + state->repterminationtype = -8; + result = ae_false; + return result; + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + if( mcinfo!=1 ) + { + + /* + * Terminate LBFGS phase + */ + goto lbl_60; + } + + /* + * Current point is updated: + * * move XC/FC/GC to XP/FP/GP + * * move XN/FN/GN to XC/FC/GC + * * report current point and update iterations counter + * * push new pair SK/YK to LBFGS buffer + * * update length of the good step + */ + activationstatus = ae_false; + for(i=0; i<=n-1; i++) + { + if( (state->hasbndl.ptr.p_bool[i]&&ae_fp_eq(state->xn.ptr.p_double[i],state->bndl.ptr.p_double[i]))&&ae_fp_neq(state->xn.ptr.p_double[i],state->xc.ptr.p_double[i]) ) + { + activationstatus = ae_true; + } + if( (state->hasbndu.ptr.p_bool[i]&&ae_fp_eq(state->xn.ptr.p_double[i],state->bndu.ptr.p_double[i]))&&ae_fp_neq(state->xn.ptr.p_double[i],state->xc.ptr.p_double[i]) ) + { + activationstatus = ae_true; + } + } + state->fp = state->fc; + state->fc = state->fn; + ae_v_move(&state->xp.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->xc.ptr.p_double[0], 1, &state->xn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->cgc.ptr.p_double[0], 1, &state->cgn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->ugc.ptr.p_double[0], 1, &state->ugn.ptr.p_double[0], 1, ae_v_len(0,n-1)); + if( !state->xrep ) + { + goto lbl_70; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); + minbc_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 29; + goto lbl_rcomm; +lbl_29: + state->xupdated = ae_false; +lbl_70: + state->repiterationscount = state->repiterationscount+1; + if( state->bufsize==m ) + { + + /* + * Buffer is full, shift contents by one row + */ + for(i=0; i<=state->bufsize-1; i++) + { + ae_v_move(&state->bufsk.ptr.pp_double[i][0], 1, &state->bufsk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); + ae_v_move(&state->bufyk.ptr.pp_double[i][0], 1, &state->bufyk.ptr.pp_double[i+1][0], 1, ae_v_len(0,n-1)); + } + for(i=0; i<=state->bufsize-2; i++) + { + state->bufrho.ptr.p_double[i] = state->bufrho.ptr.p_double[i+1]; + state->buftheta.ptr.p_double[i] = state->buftheta.ptr.p_double[i+1]; + } + } + else + { + + /* + * Buffer is not full, increase buffer size by 1 + */ + state->bufsize = state->bufsize+1; + } + v = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufsk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); + vv = ae_v_dotproduct(&state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, &state->bufyk.ptr.pp_double[state->bufsize-1][0], 1, ae_v_len(0,n-1)); + if( ae_fp_eq(v,(double)(0))||ae_fp_eq(vv,(double)(0)) ) + { + + /* + * Strange internal error in LBFGS - either YK=0 + * (which should not have been) or (SK,YK)=0 (again, + * unexpected). It should not take place because + * MCINFO=1, which signals "good" step. But just + * to be sure we have special branch of code which + * restarts LBFGS + */ + goto lbl_60; + } + state->bufrho.ptr.p_double[state->bufsize-1] = (double)1/v; + ae_assert(state->bufsize<=m, "MinBC: internal error", _state); + v = (double)(0); + vv = (double)(0); + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr((state->xc.ptr.p_double[i]-state->xp.ptr.p_double[i])/state->s.ptr.p_double[i], _state); + vv = vv+ae_sqr(state->xc.ptr.p_double[i]-state->xp.ptr.p_double[i], _state); + } + minbc_updateestimateofgoodstep(&state->lastscaledgoodstep, ae_sqrt(v, _state), _state); + + /* + * Check MaxIts-based stopping condition. + */ + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + state->repterminationtype = 5; + result = ae_false; + return result; + } + + /* + * Smooth reset (LBFGS memory model is refreshed) or hard restart: + * * LBFGS model is refreshed, if line search was performed with activation of constraints + * * algorithm is restarted if scaled gradient decreased below GDecay + */ + if( activationstatus ) + { + state->bufsize = 0; + goto lbl_59; + } + v = 0.0; + for(i=0; i<=n-1; i++) + { + v = v+ae_sqr(state->cgc.ptr.p_double[i]*state->s.ptr.p_double[i], _state); + } + if( ae_fp_less(ae_sqrt(v, _state),gdecay*ginit) ) + { + goto lbl_60; + } +lbl_59: + itidx = itidx+1; + goto lbl_58; +lbl_60: + + /* + * Decrease decay coefficient. Subsequent L-BFGS stages will + * have more stringent stopping criteria. + */ + gdecay = ae_maxreal(gdecay*minbc_decaycorrection, minbc_mindecay, _state); + goto lbl_38; +lbl_39: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = freezeidx; + state->rstate.ia.ptr.p_int[1] = n; + state->rstate.ia.ptr.p_int[2] = m; + state->rstate.ia.ptr.p_int[3] = i; + state->rstate.ia.ptr.p_int[4] = j; + state->rstate.ia.ptr.p_int[5] = mcinfo; + state->rstate.ia.ptr.p_int[6] = itidx; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ba.ptr.p_bool[1] = activationstatus; + state->rstate.ra.ptr.p_double[0] = freezeval; + state->rstate.ra.ptr.p_double[1] = scaleddnorm; + state->rstate.ra.ptr.p_double[2] = v; + state->rstate.ra.ptr.p_double[3] = vv; + state->rstate.ra.ptr.p_double[4] = v0; + state->rstate.ra.ptr.p_double[5] = ginit; + state->rstate.ra.ptr.p_double[6] = gdecay; + state->rstate.ra.ptr.p_double[7] = activationstep; + return result; +} + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbcoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardgradient(minbcstate* state, + double teststep, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(teststep, _state), "MinBCOptGuardGradient: TestStep contains NaN or INF", _state); + ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "MinBCOptGuardGradient: invalid argument TestStep(TestStep<0)", _state); + state->teststep = teststep; +} + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardsmoothness(minbcstate* state, + ae_int_t level, + ae_state *_state) +{ + + + ae_assert(level==0||level==1, "MinBCOptGuardSmoothness: unexpected value of level parameter", _state); + state->smoothnessguardlevel = level; +} + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbcoptguardgradient() for gradient verification +* minbcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbcoptguardnonc1test0results() +* minbcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardresults(minbcstate* state, + optguardreport* rep, + ae_state *_state) +{ + + _optguardreport_clear(rep); + + smoothnessmonitorexportreport(&state->smonitor, rep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test0results(const minbcstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test0report_clear(strrep); + _optguardnonc1test0report_clear(lngrep); + + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test0report(&state->smonitor.nonc1test0lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test1results(minbcstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state) +{ + + _optguardnonc1test1report_clear(strrep); + _optguardnonc1test1report_clear(lngrep); + + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1strrep, &state->lastscaleused, strrep, _state); + smoothnessmonitorexportc1test1report(&state->smonitor.nonc1test1lngrep, &state->lastscaleused, lngrep, _state); +} + + +/************************************************************************* +BC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbcrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBCReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresults(const minbcstate* state, + /* Real */ ae_vector* x, + minbcreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _minbcreport_clear(rep); + + minbcresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +BC results + +Buffered implementation of MinBCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresultsbuf(const minbcstate* state, + /* Real */ ae_vector* x, + minbcreport* rep, + ae_state *_state) +{ + ae_int_t i; + + + if( x->cntnmain ) + { + ae_vector_set_length(x, state->nmain, _state); + } + rep->iterationscount = state->repiterationscount; + rep->nfev = state->repnfev; + rep->varidx = state->repvaridx; + rep->terminationtype = state->repterminationtype; + if( state->repterminationtype>0 ) + { + ae_v_move(&x->ptr.p_double[0], 1, &state->xc.ptr.p_double[0], 1, ae_v_len(0,state->nmain-1)); + } + else + { + for(i=0; i<=state->nmain-1; i++) + { + x->ptr.p_double[i] = _state->v_nan; + } + } +} + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcrestartfrom(minbcstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + ae_int_t n; + + + n = state->nmain; + + /* + * First, check for errors in the inputs + */ + ae_assert(x->cnt>=n, "MinBCRestartFrom: Length(X)xstart.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1)); + + /* + * prepare RComm facilities + */ + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 7+1, _state); + state->rstate.stage = -1; + minbc_clearrequestfields(state, _state); +} + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcrequesttermination(minbcstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Set V1 reverse communication protocol +*************************************************************************/ +void minbcsetprotocolv1(minbcstate* state, ae_state *_state) +{ + + + state->protocolversion = 1; + ae_vector_set_length(&state->rstate.ia, 6+1, _state); + ae_vector_set_length(&state->rstate.ba, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 7+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forget to clear something) +*************************************************************************/ +static void minbc_clearrequestfields(minbcstate* state, ae_state *_state) +{ + + + state->needf = ae_false; + state->needfg = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Internal initialization subroutine. +*************************************************************************/ +static void minbc_minbcinitinternal(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbcstate* state, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_matrix c; + ae_vector ct; + + ae_frame_make(_state, &_frame_block); + memset(&c, 0, sizeof(c)); + memset(&ct, 0, sizeof(ct)); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ct, 0, DT_INT, _state, ae_true); + + + /* + * Initialize + */ + state->protocolversion = 1; + state->teststep = (double)(0); + state->smoothnessguardlevel = 0; + smoothnessmonitorinit(&state->smonitor, &state->s, 0, 0, ae_false, _state); + state->nmain = n; + state->diffstep = diffstep; + rvectorsetlengthatleast(&state->bndl, n, _state); + bvectorsetlengthatleast(&state->hasbndl, n, _state); + rvectorsetlengthatleast(&state->bndu, n, _state); + bvectorsetlengthatleast(&state->hasbndu, n, _state); + rvectorsetlengthatleast(&state->xstart, n, _state); + rvectorsetlengthatleast(&state->xc, n, _state); + rvectorsetlengthatleast(&state->cgc, n, _state); + rvectorsetlengthatleast(&state->ugc, n, _state); + rvectorsetlengthatleast(&state->xn, n, _state); + rvectorsetlengthatleast(&state->cgn, n, _state); + rvectorsetlengthatleast(&state->ugn, n, _state); + rvectorsetlengthatleast(&state->xp, n, _state); + rvectorsetlengthatleast(&state->d, n, _state); + rvectorsetlengthatleast(&state->s, n, _state); + rvectorsetlengthatleast(&state->invs, n, _state); + rvectorsetlengthatleast(&state->lastscaleused, n, _state); + rvectorsetlengthatleast(&state->x, n, _state); + rvectorsetlengthatleast(&state->g, n, _state); + rvectorsetlengthatleast(&state->work, n, _state); + for(i=0; i<=n-1; i++) + { + state->bndl.ptr.p_double[i] = _state->v_neginf; + state->hasbndl.ptr.p_bool[i] = ae_false; + state->bndu.ptr.p_double[i] = _state->v_posinf; + state->hasbndu.ptr.p_bool[i] = ae_false; + state->s.ptr.p_double[i] = 1.0; + state->invs.ptr.p_double[i] = 1.0; + state->lastscaleused.ptr.p_double[i] = 1.0; + } + minbcsetcond(state, 0.0, 0.0, 0.0, 0, _state); + minbcsetxrep(state, ae_false, _state); + minbcsetstpmax(state, 0.0, _state); + minbcsetprecdefault(state, _state); + minbcrestartfrom(state, x, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This subroutine updates estimate of the good step length given: +1) previous estimate +2) new length of the good step + +It makes sure that estimate does not change too rapidly - ratio of new and +old estimates will be at least 0.01, at most 100.0 + +In case previous estimate of good step is zero (no estimate), new estimate +is used unconditionally. + + -- ALGLIB -- + Copyright 16.01.2013 by Bochkanov Sergey +*************************************************************************/ +static void minbc_updateestimateofgoodstep(double* estimate, + double newstep, + ae_state *_state) +{ + + + if( ae_fp_eq(*estimate,(double)(0)) ) + { + *estimate = newstep; + return; + } + if( ae_fp_less(newstep,*estimate*0.01) ) + { + *estimate = *estimate*0.01; + return; + } + if( ae_fp_greater(newstep,*estimate*(double)100) ) + { + *estimate = *estimate*(double)100; + return; + } + *estimate = newstep; +} + + +void _minbcstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minbcstate *p = (minbcstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->diagh, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->xc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ugc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgc, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ugn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgn, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xp, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->hasbndl, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->hasbndu, 0, DT_BOOL, _state, make_automatic); + ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xstart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpprec, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->work, 0, DT_REAL, _state, make_automatic); + _linminstate_init(&p->lstate, _state, make_automatic); + ae_matrix_init(&p->bufyk, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->bufsk, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->bufrho, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->buftheta, 0, DT_REAL, _state, make_automatic); + _smoothnessmonitor_init(&p->smonitor, _state, make_automatic); + ae_vector_init(&p->lastscaleused, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->invs, 0, DT_REAL, _state, make_automatic); +} + + +void _minbcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minbcstate *dst = (minbcstate*)_dst; + const minbcstate *src = (const minbcstate*)_src; + dst->nmain = src->nmain; + dst->epsg = src->epsg; + dst->epsf = src->epsf; + dst->epsx = src->epsx; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + dst->diffstep = src->diffstep; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->prectype = src->prectype; + ae_vector_init_copy(&dst->diagh, &src->diagh, _state, make_automatic); + dst->protocolversion = src->protocolversion; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic); + dst->needf = src->needf; + dst->needfg = src->needfg; + dst->xupdated = src->xupdated; + dst->userterminationneeded = src->userterminationneeded; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + ae_vector_init_copy(&dst->xc, &src->xc, _state, make_automatic); + ae_vector_init_copy(&dst->ugc, &src->ugc, _state, make_automatic); + ae_vector_init_copy(&dst->cgc, &src->cgc, _state, make_automatic); + ae_vector_init_copy(&dst->xn, &src->xn, _state, make_automatic); + ae_vector_init_copy(&dst->ugn, &src->ugn, _state, make_automatic); + ae_vector_init_copy(&dst->cgn, &src->cgn, _state, make_automatic); + ae_vector_init_copy(&dst->xp, &src->xp, _state, make_automatic); + dst->fc = src->fc; + dst->fn = src->fn; + dst->fp = src->fp; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->lastscaledgoodstep = src->lastscaledgoodstep; + ae_vector_init_copy(&dst->hasbndl, &src->hasbndl, _state, make_automatic); + ae_vector_init_copy(&dst->hasbndu, &src->hasbndu, _state, make_automatic); + ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic); + ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnfev = src->repnfev; + dst->repvaridx = src->repvaridx; + dst->repterminationtype = src->repterminationtype; + ae_vector_init_copy(&dst->xstart, &src->xstart, _state, make_automatic); + dst->fbase = src->fbase; + dst->fm2 = src->fm2; + dst->fm1 = src->fm1; + dst->fp1 = src->fp1; + dst->fp2 = src->fp2; + dst->xm1 = src->xm1; + dst->xp1 = src->xp1; + dst->gm1 = src->gm1; + dst->gp1 = src->gp1; + ae_vector_init_copy(&dst->tmpprec, &src->tmpprec, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + dst->nfev = src->nfev; + dst->mcstage = src->mcstage; + dst->stp = src->stp; + dst->curstpmax = src->curstpmax; + ae_vector_init_copy(&dst->work, &src->work, _state, make_automatic); + _linminstate_init_copy(&dst->lstate, &src->lstate, _state, make_automatic); + dst->trimthreshold = src->trimthreshold; + dst->nonmonotoniccnt = src->nonmonotoniccnt; + ae_matrix_init_copy(&dst->bufyk, &src->bufyk, _state, make_automatic); + ae_matrix_init_copy(&dst->bufsk, &src->bufsk, _state, make_automatic); + ae_vector_init_copy(&dst->bufrho, &src->bufrho, _state, make_automatic); + ae_vector_init_copy(&dst->buftheta, &src->buftheta, _state, make_automatic); + dst->bufsize = src->bufsize; + dst->teststep = src->teststep; + dst->smoothnessguardlevel = src->smoothnessguardlevel; + _smoothnessmonitor_init_copy(&dst->smonitor, &src->smonitor, _state, make_automatic); + ae_vector_init_copy(&dst->lastscaleused, &src->lastscaleused, _state, make_automatic); + ae_vector_init_copy(&dst->invs, &src->invs, _state, make_automatic); +} + + +void _minbcstate_clear(void* _p) +{ + minbcstate *p = (minbcstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->s); + ae_vector_clear(&p->diagh); + ae_vector_clear(&p->x); + ae_vector_clear(&p->g); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->xc); + ae_vector_clear(&p->ugc); + ae_vector_clear(&p->cgc); + ae_vector_clear(&p->xn); + ae_vector_clear(&p->ugn); + ae_vector_clear(&p->cgn); + ae_vector_clear(&p->xp); + ae_vector_clear(&p->d); + ae_vector_clear(&p->hasbndl); + ae_vector_clear(&p->hasbndu); + ae_vector_clear(&p->bndl); + ae_vector_clear(&p->bndu); + ae_vector_clear(&p->xstart); + ae_vector_clear(&p->tmpprec); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->work); + _linminstate_clear(&p->lstate); + ae_matrix_clear(&p->bufyk); + ae_matrix_clear(&p->bufsk); + ae_vector_clear(&p->bufrho); + ae_vector_clear(&p->buftheta); + _smoothnessmonitor_clear(&p->smonitor); + ae_vector_clear(&p->lastscaleused); + ae_vector_clear(&p->invs); +} + + +void _minbcstate_destroy(void* _p) +{ + minbcstate *p = (minbcstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->s); + ae_vector_destroy(&p->diagh); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->g); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->xc); + ae_vector_destroy(&p->ugc); + ae_vector_destroy(&p->cgc); + ae_vector_destroy(&p->xn); + ae_vector_destroy(&p->ugn); + ae_vector_destroy(&p->cgn); + ae_vector_destroy(&p->xp); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->hasbndl); + ae_vector_destroy(&p->hasbndu); + ae_vector_destroy(&p->bndl); + ae_vector_destroy(&p->bndu); + ae_vector_destroy(&p->xstart); + ae_vector_destroy(&p->tmpprec); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->work); + _linminstate_destroy(&p->lstate); + ae_matrix_destroy(&p->bufyk); + ae_matrix_destroy(&p->bufsk); + ae_vector_destroy(&p->bufrho); + ae_vector_destroy(&p->buftheta); + _smoothnessmonitor_destroy(&p->smonitor); + ae_vector_destroy(&p->lastscaleused); + ae_vector_destroy(&p->invs); +} + + +void _minbcreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + minbcreport *p = (minbcreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minbcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + minbcreport *dst = (minbcreport*)_dst; + const minbcreport *src = (const minbcreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfev = src->nfev; + dst->varidx = src->varidx; + dst->terminationtype = src->terminationtype; +} + + +void _minbcreport_clear(void* _p) +{ + minbcreport *p = (minbcreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _minbcreport_destroy(void* _p) +{ + minbcreport *p = (minbcreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif + +} + diff --git a/core/alglib/optimization.h b/core/alglib/optimization.h index cc1dba1d..c79f74e8 100644 --- a/core/alglib/optimization.h +++ b/core/alglib/optimization.h @@ -1,4379 +1,20125 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _optimization_pkg_h -#define _optimization_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "linalg.h" -#include "alglibmisc.h" -#include "solvers.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - ae_int_t n; - ae_int_t k; - double alpha; - double tau; - double theta; - ae_matrix a; - ae_matrix q; - ae_vector b; - ae_vector r; - ae_vector xc; - ae_vector d; - ae_vector activeset; - ae_matrix tq2dense; - ae_matrix tk2; - ae_vector tq2diag; - ae_vector tq1; - ae_vector tk1; - double tq0; - double tk0; - ae_vector txc; - ae_vector tb; - ae_int_t nfree; - ae_int_t ecakind; - ae_matrix ecadense; - ae_matrix eq; - ae_matrix eccm; - ae_vector ecadiag; - ae_vector eb; - double ec; - ae_vector tmp0; - ae_vector tmp1; - ae_vector tmpg; - ae_matrix tmp2; - ae_bool ismaintermchanged; - ae_bool issecondarytermchanged; - ae_bool islineartermchanged; - ae_bool isactivesetchanged; -} convexquadraticmodel; -typedef struct -{ - ae_int_t ns; - ae_int_t nd; - ae_int_t nr; - ae_matrix densea; - ae_vector b; - ae_vector nnc; - ae_int_t refinementits; - double debugflops; - ae_int_t debugmaxnewton; - ae_vector xn; - ae_matrix tmpz; - ae_matrix tmpca; - ae_vector g; - ae_vector d; - ae_vector dx; - ae_vector diagaa; - ae_vector cb; - ae_vector cx; - ae_vector cborg; - ae_vector columnmap; - ae_vector rowmap; - ae_vector tmpcholesky; - ae_vector r; -} snnlssolver; -typedef struct -{ - ae_int_t n; - ae_int_t algostate; - ae_vector xc; - ae_bool hasxc; - ae_vector s; - ae_vector h; - ae_vector activeset; - ae_bool basisisready; - ae_matrix sbasis; - ae_matrix pbasis; - ae_matrix ibasis; - ae_int_t basissize; - ae_bool constraintschanged; - ae_vector hasbndl; - ae_vector hasbndu; - ae_vector bndl; - ae_vector bndu; - ae_matrix cleic; - ae_int_t nec; - ae_int_t nic; - ae_vector mtx; - ae_vector mtas; - ae_vector cdtmp; - ae_vector corrtmp; - ae_vector unitdiagonal; - snnlssolver solver; - ae_vector scntmp; - ae_vector tmp0; - ae_vector tmpfeas; - ae_matrix tmpm0; - ae_vector rctmps; - ae_vector rctmpg; - ae_vector rctmprightpart; - ae_matrix rctmpdense0; - ae_matrix rctmpdense1; - ae_vector rctmpisequality; - ae_vector rctmpconstraintidx; - ae_vector rctmplambdas; - ae_matrix tmpbasis; -} sactiveset; -typedef struct -{ - ae_int_t n; - double epsg; - double epsf; - double epsx; - ae_int_t maxits; - double stpmax; - double suggestedstep; - ae_bool xrep; - ae_bool drep; - ae_int_t cgtype; - ae_int_t prectype; - ae_vector diagh; - ae_vector diaghl2; - ae_matrix vcorr; - ae_int_t vcnt; - ae_vector s; - double diffstep; - ae_int_t nfev; - ae_int_t mcstage; - ae_int_t k; - ae_vector xk; - ae_vector dk; - ae_vector xn; - ae_vector dn; - ae_vector d; - double fold; - double stp; - double curstpmax; - ae_vector yk; - double lastgoodstep; - double lastscaledstep; - ae_int_t mcinfo; - ae_bool innerresetneeded; - ae_bool terminationneeded; - double trimthreshold; - ae_int_t rstimer; - ae_vector x; - double f; - ae_vector g; - ae_bool needf; - ae_bool needfg; - ae_bool xupdated; - ae_bool algpowerup; - ae_bool lsstart; - ae_bool lsend; - double teststep; - rcommstate rstate; - ae_int_t repiterationscount; - ae_int_t repnfev; - ae_int_t repvaridx; - ae_int_t repterminationtype; - ae_int_t debugrestartscount; - linminstate lstate; - double fbase; - double fm2; - double fm1; - double fp1; - double fp2; - double betahs; - double betady; - ae_vector work0; - ae_vector work1; -} mincgstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nfev; - ae_int_t varidx; - ae_int_t terminationtype; -} mincgreport; -typedef struct -{ - ae_int_t nmain; - ae_int_t nslack; - double epsg; - double epsf; - double epsx; - ae_int_t maxits; - ae_bool xrep; - ae_bool drep; - double stpmax; - double diffstep; - sactiveset sas; - ae_vector s; - ae_int_t prectype; - ae_vector diagh; - ae_vector x; - double f; - ae_vector g; - ae_bool needf; - ae_bool needfg; - ae_bool xupdated; - ae_bool lsstart; - ae_bool lbfgssearch; - ae_bool boundedstep; - double teststep; - rcommstate rstate; - ae_vector gc; - ae_vector xn; - ae_vector gn; - ae_vector xp; - ae_vector gp; - double fc; - double fn; - double fp; - ae_vector d; - ae_matrix cleic; - ae_int_t nec; - ae_int_t nic; - double lastgoodstep; - double lastscaledgoodstep; - double maxscaledgrad; - ae_vector hasbndl; - ae_vector hasbndu; - ae_vector bndl; - ae_vector bndu; - ae_int_t repinneriterationscount; - ae_int_t repouteriterationscount; - ae_int_t repnfev; - ae_int_t repvaridx; - ae_int_t repterminationtype; - double repdebugeqerr; - double repdebugfs; - double repdebugff; - double repdebugdx; - ae_int_t repdebugfeasqpits; - ae_int_t repdebugfeasgpaits; - ae_vector xstart; - snnlssolver solver; - double fbase; - double fm2; - double fm1; - double fp1; - double fp2; - double xm1; - double xp1; - double gm1; - double gp1; - ae_int_t cidx; - double cval; - ae_vector tmpprec; - ae_int_t nfev; - ae_int_t mcstage; - double stp; - double curstpmax; - double activationstep; - ae_vector work; - linminstate lstate; - double trimthreshold; - ae_int_t nonmonotoniccnt; - ae_int_t k; - ae_int_t q; - ae_int_t p; - ae_vector rho; - ae_matrix yk; - ae_matrix sk; - ae_vector theta; -} minbleicstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nfev; - ae_int_t varidx; - ae_int_t terminationtype; - double debugeqerr; - double debugfs; - double debugff; - double debugdx; - ae_int_t debugfeasqpits; - ae_int_t debugfeasgpaits; - ae_int_t inneriterationscount; - ae_int_t outeriterationscount; -} minbleicreport; -typedef struct -{ - ae_int_t n; - ae_int_t m; - double epsg; - double epsf; - double epsx; - ae_int_t maxits; - ae_bool xrep; - double stpmax; - ae_vector s; - double diffstep; - ae_int_t nfev; - ae_int_t mcstage; - ae_int_t k; - ae_int_t q; - ae_int_t p; - ae_vector rho; - ae_matrix yk; - ae_matrix sk; - ae_vector theta; - ae_vector d; - double stp; - ae_vector work; - double fold; - double trimthreshold; - ae_int_t prectype; - double gammak; - ae_matrix denseh; - ae_vector diagh; - double fbase; - double fm2; - double fm1; - double fp1; - double fp2; - ae_vector autobuf; - ae_vector x; - double f; - ae_vector g; - ae_bool needf; - ae_bool needfg; - ae_bool xupdated; - double teststep; - rcommstate rstate; - ae_int_t repiterationscount; - ae_int_t repnfev; - ae_int_t repvaridx; - ae_int_t repterminationtype; - linminstate lstate; -} minlbfgsstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nfev; - ae_int_t varidx; - ae_int_t terminationtype; -} minlbfgsreport; -typedef struct -{ - ae_int_t n; - ae_int_t algokind; - ae_int_t akind; - convexquadraticmodel a; - sparsematrix sparsea; - ae_bool sparseaupper; - double anorm; - ae_vector b; - ae_vector bndl; - ae_vector bndu; - ae_vector s; - ae_vector havebndl; - ae_vector havebndu; - ae_vector xorigin; - ae_vector startx; - ae_bool havex; - ae_matrix cleic; - ae_int_t nec; - ae_int_t nic; - double bleicepsg; - double bleicepsf; - double bleicepsx; - ae_int_t bleicmaxits; - sactiveset sas; - ae_vector gc; - ae_vector xn; - ae_vector pg; - ae_vector workbndl; - ae_vector workbndu; - ae_matrix workcleic; - ae_vector xs; - ae_int_t repinneriterationscount; - ae_int_t repouteriterationscount; - ae_int_t repncholesky; - ae_int_t repnmv; - ae_int_t repterminationtype; - double debugphase1flops; - double debugphase2flops; - double debugphase3flops; - ae_vector tmp0; - ae_vector tmp1; - ae_vector tmpb; - ae_vector rctmpg; - ae_vector tmpi; - normestimatorstate estimator; - minbleicstate solver; - minbleicreport solverrep; -} minqpstate; -typedef struct -{ - ae_int_t inneriterationscount; - ae_int_t outeriterationscount; - ae_int_t nmv; - ae_int_t ncholesky; - ae_int_t terminationtype; -} minqpreport; -typedef struct -{ - ae_int_t n; - ae_int_t m; - double diffstep; - double epsg; - double epsf; - double epsx; - ae_int_t maxits; - ae_bool xrep; - double stpmax; - ae_int_t maxmodelage; - ae_bool makeadditers; - ae_vector x; - double f; - ae_vector fi; - ae_matrix j; - ae_matrix h; - ae_vector g; - ae_bool needf; - ae_bool needfg; - ae_bool needfgh; - ae_bool needfij; - ae_bool needfi; - ae_bool xupdated; - ae_int_t algomode; - ae_bool hasf; - ae_bool hasfi; - ae_bool hasg; - ae_vector xbase; - double fbase; - ae_vector fibase; - ae_vector gbase; - ae_matrix quadraticmodel; - ae_vector bndl; - ae_vector bndu; - ae_vector havebndl; - ae_vector havebndu; - ae_vector s; - double lambdav; - double nu; - ae_int_t modelage; - ae_vector xdir; - ae_vector deltax; - ae_vector deltaf; - ae_bool deltaxready; - ae_bool deltafready; - double teststep; - ae_int_t repiterationscount; - ae_int_t repterminationtype; - ae_int_t repfuncidx; - ae_int_t repvaridx; - ae_int_t repnfunc; - ae_int_t repnjac; - ae_int_t repngrad; - ae_int_t repnhess; - ae_int_t repncholesky; - rcommstate rstate; - ae_vector choleskybuf; - ae_vector tmp0; - double actualdecrease; - double predicteddecrease; - double xm1; - double xp1; - ae_vector fm1; - ae_vector fp1; - ae_vector fc1; - ae_vector gm1; - ae_vector gp1; - ae_vector gc1; - minlbfgsstate internalstate; - minlbfgsreport internalrep; - minqpstate qpstate; - minqpreport qprep; -} minlmstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t terminationtype; - ae_int_t funcidx; - ae_int_t varidx; - ae_int_t nfunc; - ae_int_t njac; - ae_int_t ngrad; - ae_int_t nhess; - ae_int_t ncholesky; -} minlmreport; -typedef struct -{ - ae_int_t n; - double epsg; - double epsf; - double epsx; - ae_int_t maxits; - ae_bool xrep; - double stpmax; - ae_int_t cgtype; - ae_int_t k; - ae_int_t nfev; - ae_int_t mcstage; - ae_vector bndl; - ae_vector bndu; - ae_int_t curalgo; - ae_int_t acount; - double mu; - double finit; - double dginit; - ae_vector ak; - ae_vector xk; - ae_vector dk; - ae_vector an; - ae_vector xn; - ae_vector dn; - ae_vector d; - double fold; - double stp; - ae_vector work; - ae_vector yk; - ae_vector gc; - double laststep; - ae_vector x; - double f; - ae_vector g; - ae_bool needfg; - ae_bool xupdated; - rcommstate rstate; - ae_int_t repiterationscount; - ae_int_t repnfev; - ae_int_t repterminationtype; - ae_int_t debugrestartscount; - linminstate lstate; - double betahs; - double betady; -} minasastate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nfev; - ae_int_t terminationtype; - ae_int_t activeconstraints; -} minasareport; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - - - - - - - - -/************************************************************************* -This object stores state of the nonlinear CG optimizer. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -class _mincgstate_owner -{ -public: - _mincgstate_owner(); - _mincgstate_owner(const _mincgstate_owner &rhs); - _mincgstate_owner& operator=(const _mincgstate_owner &rhs); - virtual ~_mincgstate_owner(); - alglib_impl::mincgstate* c_ptr(); - alglib_impl::mincgstate* c_ptr() const; -protected: - alglib_impl::mincgstate *p_struct; -}; -class mincgstate : public _mincgstate_owner -{ -public: - mincgstate(); - mincgstate(const mincgstate &rhs); - mincgstate& operator=(const mincgstate &rhs); - virtual ~mincgstate(); - ae_bool &needf; - ae_bool &needfg; - ae_bool &xupdated; - double &f; - real_1d_array g; - real_1d_array x; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _mincgreport_owner -{ -public: - _mincgreport_owner(); - _mincgreport_owner(const _mincgreport_owner &rhs); - _mincgreport_owner& operator=(const _mincgreport_owner &rhs); - virtual ~_mincgreport_owner(); - alglib_impl::mincgreport* c_ptr(); - alglib_impl::mincgreport* c_ptr() const; -protected: - alglib_impl::mincgreport *p_struct; -}; -class mincgreport : public _mincgreport_owner -{ -public: - mincgreport(); - mincgreport(const mincgreport &rhs); - mincgreport& operator=(const mincgreport &rhs); - virtual ~mincgreport(); - ae_int_t &iterationscount; - ae_int_t &nfev; - ae_int_t &varidx; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -This object stores nonlinear optimizer state. -You should use functions provided by MinBLEIC subpackage to work with this -object -*************************************************************************/ -class _minbleicstate_owner -{ -public: - _minbleicstate_owner(); - _minbleicstate_owner(const _minbleicstate_owner &rhs); - _minbleicstate_owner& operator=(const _minbleicstate_owner &rhs); - virtual ~_minbleicstate_owner(); - alglib_impl::minbleicstate* c_ptr(); - alglib_impl::minbleicstate* c_ptr() const; -protected: - alglib_impl::minbleicstate *p_struct; -}; -class minbleicstate : public _minbleicstate_owner -{ -public: - minbleicstate(); - minbleicstate(const minbleicstate &rhs); - minbleicstate& operator=(const minbleicstate &rhs); - virtual ~minbleicstate(); - ae_bool &needf; - ae_bool &needfg; - ae_bool &xupdated; - double &f; - real_1d_array g; - real_1d_array x; - -}; - - -/************************************************************************* -This structure stores optimization report: -* IterationsCount number of iterations -* NFEV number of gradient evaluations -* TerminationType termination type (see below) - -TERMINATION CODES - -TerminationType field contains completion code, which can be: - -7 gradient verification failed. - See MinBLEICSetGradientCheck() for more information. - -3 inconsistent constraints. Feasible point is - either nonexistent or too hard to find. Try to - restart optimizer with better initial approximation - 1 relative function improvement is no more than EpsF. - 2 relative step is no more than EpsX. - 4 gradient norm is no more than EpsG - 5 MaxIts steps was taken - 7 stopping conditions are too stringent, - further improvement is impossible, - X contains best point found so far. - -ADDITIONAL FIELDS - -There are additional fields which can be used for debugging: -* DebugEqErr error in the equality constraints (2-norm) -* DebugFS f, calculated at projection of initial point - to the feasible set -* DebugFF f, calculated at the final point -* DebugDX |X_start-X_final| -*************************************************************************/ -class _minbleicreport_owner -{ -public: - _minbleicreport_owner(); - _minbleicreport_owner(const _minbleicreport_owner &rhs); - _minbleicreport_owner& operator=(const _minbleicreport_owner &rhs); - virtual ~_minbleicreport_owner(); - alglib_impl::minbleicreport* c_ptr(); - alglib_impl::minbleicreport* c_ptr() const; -protected: - alglib_impl::minbleicreport *p_struct; -}; -class minbleicreport : public _minbleicreport_owner -{ -public: - minbleicreport(); - minbleicreport(const minbleicreport &rhs); - minbleicreport& operator=(const minbleicreport &rhs); - virtual ~minbleicreport(); - ae_int_t &iterationscount; - ae_int_t &nfev; - ae_int_t &varidx; - ae_int_t &terminationtype; - double &debugeqerr; - double &debugfs; - double &debugff; - double &debugdx; - ae_int_t &debugfeasqpits; - ae_int_t &debugfeasgpaits; - ae_int_t &inneriterationscount; - ae_int_t &outeriterationscount; - -}; - -/************************************************************************* - -*************************************************************************/ -class _minlbfgsstate_owner -{ -public: - _minlbfgsstate_owner(); - _minlbfgsstate_owner(const _minlbfgsstate_owner &rhs); - _minlbfgsstate_owner& operator=(const _minlbfgsstate_owner &rhs); - virtual ~_minlbfgsstate_owner(); - alglib_impl::minlbfgsstate* c_ptr(); - alglib_impl::minlbfgsstate* c_ptr() const; -protected: - alglib_impl::minlbfgsstate *p_struct; -}; -class minlbfgsstate : public _minlbfgsstate_owner -{ -public: - minlbfgsstate(); - minlbfgsstate(const minlbfgsstate &rhs); - minlbfgsstate& operator=(const minlbfgsstate &rhs); - virtual ~minlbfgsstate(); - ae_bool &needf; - ae_bool &needfg; - ae_bool &xupdated; - double &f; - real_1d_array g; - real_1d_array x; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _minlbfgsreport_owner -{ -public: - _minlbfgsreport_owner(); - _minlbfgsreport_owner(const _minlbfgsreport_owner &rhs); - _minlbfgsreport_owner& operator=(const _minlbfgsreport_owner &rhs); - virtual ~_minlbfgsreport_owner(); - alglib_impl::minlbfgsreport* c_ptr(); - alglib_impl::minlbfgsreport* c_ptr() const; -protected: - alglib_impl::minlbfgsreport *p_struct; -}; -class minlbfgsreport : public _minlbfgsreport_owner -{ -public: - minlbfgsreport(); - minlbfgsreport(const minlbfgsreport &rhs); - minlbfgsreport& operator=(const minlbfgsreport &rhs); - virtual ~minlbfgsreport(); - ae_int_t &iterationscount; - ae_int_t &nfev; - ae_int_t &varidx; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -This object stores nonlinear optimizer state. -You should use functions provided by MinQP subpackage to work with this -object -*************************************************************************/ -class _minqpstate_owner -{ -public: - _minqpstate_owner(); - _minqpstate_owner(const _minqpstate_owner &rhs); - _minqpstate_owner& operator=(const _minqpstate_owner &rhs); - virtual ~_minqpstate_owner(); - alglib_impl::minqpstate* c_ptr(); - alglib_impl::minqpstate* c_ptr() const; -protected: - alglib_impl::minqpstate *p_struct; -}; -class minqpstate : public _minqpstate_owner -{ -public: - minqpstate(); - minqpstate(const minqpstate &rhs); - minqpstate& operator=(const minqpstate &rhs); - virtual ~minqpstate(); - -}; - - -/************************************************************************* -This structure stores optimization report: -* InnerIterationsCount number of inner iterations -* OuterIterationsCount number of outer iterations -* NCholesky number of Cholesky decomposition -* NMV number of matrix-vector products - (only products calculated as part of iterative - process are counted) -* TerminationType completion code (see below) - -Completion codes: -* -5 inappropriate solver was used: - * Cholesky solver for semidefinite or indefinite problems - * Cholesky solver for problems with non-boundary constraints -* -4 BLEIC-QP algorithm found unconstrained direction - of negative curvature (function is unbounded from - below even under constraints), no meaningful - minimum can be found. -* -3 inconsistent constraints (or, maybe, feasible point is - too hard to find). If you are sure that constraints are feasible, - try to restart optimizer with better initial approximation. -* -1 solver error -* 4 successful completion -* 5 MaxIts steps was taken -* 7 stopping conditions are too stringent, - further improvement is impossible, - X contains best point found so far. -*************************************************************************/ -class _minqpreport_owner -{ -public: - _minqpreport_owner(); - _minqpreport_owner(const _minqpreport_owner &rhs); - _minqpreport_owner& operator=(const _minqpreport_owner &rhs); - virtual ~_minqpreport_owner(); - alglib_impl::minqpreport* c_ptr(); - alglib_impl::minqpreport* c_ptr() const; -protected: - alglib_impl::minqpreport *p_struct; -}; -class minqpreport : public _minqpreport_owner -{ -public: - minqpreport(); - minqpreport(const minqpreport &rhs); - minqpreport& operator=(const minqpreport &rhs); - virtual ~minqpreport(); - ae_int_t &inneriterationscount; - ae_int_t &outeriterationscount; - ae_int_t &nmv; - ae_int_t &ncholesky; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -Levenberg-Marquardt optimizer. - -This structure should be created using one of the MinLMCreate???() -functions. You should not access its fields directly; use ALGLIB functions -to work with it. -*************************************************************************/ -class _minlmstate_owner -{ -public: - _minlmstate_owner(); - _minlmstate_owner(const _minlmstate_owner &rhs); - _minlmstate_owner& operator=(const _minlmstate_owner &rhs); - virtual ~_minlmstate_owner(); - alglib_impl::minlmstate* c_ptr(); - alglib_impl::minlmstate* c_ptr() const; -protected: - alglib_impl::minlmstate *p_struct; -}; -class minlmstate : public _minlmstate_owner -{ -public: - minlmstate(); - minlmstate(const minlmstate &rhs); - minlmstate& operator=(const minlmstate &rhs); - virtual ~minlmstate(); - ae_bool &needf; - ae_bool &needfg; - ae_bool &needfgh; - ae_bool &needfi; - ae_bool &needfij; - ae_bool &xupdated; - double &f; - real_1d_array fi; - real_1d_array g; - real_2d_array h; - real_2d_array j; - real_1d_array x; - -}; - - -/************************************************************************* -Optimization report, filled by MinLMResults() function - -FIELDS: -* TerminationType, completion code: - * -7 derivative correctness check failed; - see Rep.WrongNum, Rep.WrongI, Rep.WrongJ for - more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient is no more than EpsG. - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible -* IterationsCount, contains iterations count -* NFunc, number of function calculations -* NJac, number of Jacobi matrix calculations -* NGrad, number of gradient calculations -* NHess, number of Hessian calculations -* NCholesky, number of Cholesky decomposition calculations -*************************************************************************/ -class _minlmreport_owner -{ -public: - _minlmreport_owner(); - _minlmreport_owner(const _minlmreport_owner &rhs); - _minlmreport_owner& operator=(const _minlmreport_owner &rhs); - virtual ~_minlmreport_owner(); - alglib_impl::minlmreport* c_ptr(); - alglib_impl::minlmreport* c_ptr() const; -protected: - alglib_impl::minlmreport *p_struct; -}; -class minlmreport : public _minlmreport_owner -{ -public: - minlmreport(); - minlmreport(const minlmreport &rhs); - minlmreport& operator=(const minlmreport &rhs); - virtual ~minlmreport(); - ae_int_t &iterationscount; - ae_int_t &terminationtype; - ae_int_t &funcidx; - ae_int_t &varidx; - ae_int_t &nfunc; - ae_int_t &njac; - ae_int_t &ngrad; - ae_int_t &nhess; - ae_int_t &ncholesky; - -}; - -/************************************************************************* - -*************************************************************************/ -class _minasastate_owner -{ -public: - _minasastate_owner(); - _minasastate_owner(const _minasastate_owner &rhs); - _minasastate_owner& operator=(const _minasastate_owner &rhs); - virtual ~_minasastate_owner(); - alglib_impl::minasastate* c_ptr(); - alglib_impl::minasastate* c_ptr() const; -protected: - alglib_impl::minasastate *p_struct; -}; -class minasastate : public _minasastate_owner -{ -public: - minasastate(); - minasastate(const minasastate &rhs); - minasastate& operator=(const minasastate &rhs); - virtual ~minasastate(); - ae_bool &needfg; - ae_bool &xupdated; - double &f; - real_1d_array g; - real_1d_array x; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _minasareport_owner -{ -public: - _minasareport_owner(); - _minasareport_owner(const _minasareport_owner &rhs); - _minasareport_owner& operator=(const _minasareport_owner &rhs); - virtual ~_minasareport_owner(); - alglib_impl::minasareport* c_ptr(); - alglib_impl::minasareport* c_ptr() const; -protected: - alglib_impl::minasareport *p_struct; -}; -class minasareport : public _minasareport_owner -{ -public: - minasareport(); - minasareport(const minasareport &rhs); - minasareport& operator=(const minasareport &rhs); - virtual ~minasareport(); - ae_int_t &iterationscount; - ae_int_t &nfev; - ae_int_t &terminationtype; - ae_int_t &activeconstraints; - -}; - - - - - - - - - -/************************************************************************* - NONLINEAR CONJUGATE GRADIENT METHOD - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using one of the -nonlinear conjugate gradient methods. - -These CG methods are globally convergent (even on non-convex functions) as -long as grad(f) is Lipschitz continuous in a some neighborhood of the -L = { x : f(x)<=f(x0) }. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinCGCreate() call -2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and - other functions -3. User calls MinCGOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinCGResults() to get solution -5. Optionally, user may call MinCGRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinCGRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state); -void mincgcreate(const real_1d_array &x, mincgstate &state); - - -/************************************************************************* -The subroutine is finite difference variant of MinCGCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinCGCreate() in order to get more -information about creation of CG optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinCGSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. L-BFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state); -void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state); - - -/************************************************************************* -This function sets stopping conditions for CG optimization algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinCGSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcond(const mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function sets scaling coefficients for CG optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of CG optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the CG too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinCGSetPrec...() functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void mincgsetscale(const mincgstate &state, const real_1d_array &s); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetxrep(const mincgstate &state, const bool needxrep); - - -/************************************************************************* -This function sets CG algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - CGType - algorithm type: - * -1 automatic selection of the best algorithm - * 0 DY (Dai and Yuan) algorithm - * 1 Hybrid DY-HS algorithm - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetcgtype(const mincgstate &state, const ae_int_t cgtype); - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetstpmax(const mincgstate &state, const double stpmax); - - -/************************************************************************* -This function allows to suggest initial step length to the CG algorithm. - -Suggested step length is used as starting point for the line search. It -can be useful when you have badly scaled problem, i.e. when ||grad|| -(which is used as initial estimate for the first step) is many orders of -magnitude different from the desired step. - -Line search may fail on such problems without good estimate of initial -step length. Imagine, for example, problem with ||grad||=10^50 and desired -step equal to 0.1 Line search function will use 10^50 as initial step, -then it will decrease step length by 2 (up to 20 attempts) and will get -10^44, which is still too large. - -This function allows us to tell than line search should be started from -some moderate step length, like 1.0, so algorithm will be able to detect -desired step length in a several searches. - -Default behavior (when no step is suggested) is to use preconditioner, if -it is available, to generate initial estimate of step length. - -This function influences only first iteration of algorithm. It should be -called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. -Suggested step is ignored if you have preconditioner. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - Stp - initial estimate of the step length. - Can be zero (no estimate). - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsuggeststep(const mincgstate &state, const double stp); - - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdefault(const mincgstate &state); - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecdiag(const mincgstate &state, const real_1d_array &d); - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinCGSetScale() call -(before or after MinCGSetPrecScale() call). Without knowledge of the scale -of your variables scale-based preconditioner will be just unit matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgsetprecscale(const mincgstate &state); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool mincgiteration(const mincgstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear optimizer - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinCGCreate() for analytical gradient or MinCGCreateF() for - numerical differentiation) you should choose appropriate variant of - MinCGOptimize() - one which accepts function AND gradient or one which - accepts function ONLY. - - Be careful to choose variant of MinCGOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinCGOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinCGOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinCGCreateF() | work FAIL - MinCGCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinCGOptimize() version. Attemps to use such combination - (for example, to create optimizer with MinCGCreateF() and to pass - gradient information to MinCGOptimize()) will lead to exception being - thrown. Either you did not pass gradient when it WAS needed or you - passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey - -*************************************************************************/ -void mincgoptimize(mincgstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void mincgoptimize(mincgstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -Conjugate gradient results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinCGSetGradientCheck() for more information. - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible, - we return best X found so far - * 8 terminated by user - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep); - - -/************************************************************************* -Conjugate gradient results - -Buffered implementation of MinCGResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.04.2009 by Bochkanov Sergey -*************************************************************************/ -void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep); - - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void mincgrestartfrom(const mincgstate &state, const real_1d_array &x); - - -/************************************************************************* - -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinCGOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinCGSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 31.05.2012 by Bochkanov Sergey -*************************************************************************/ -void mincgsetgradientcheck(const mincgstate &state, const double teststep); - -/************************************************************************* - BOUND CONSTRAINED OPTIMIZATION - WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments subject to any -combination of: -* bound constraints -* linear inequality constraints -* linear equality constraints - -REQUIREMENTS: -* user must provide function value and gradient -* starting point X0 must be feasible or - not too far away from the feasible set -* grad(f) must be Lipschitz continuous on a level set: - L = { x : f(x)<=f(x0) } -* function must be defined everywhere on the feasible set F - -USAGE: - -Constrained optimization if far more complex than the unconstrained one. -Here we give very brief outline of the BLEIC optimizer. We strongly recommend -you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide -on optimization, which is available at http://www.alglib.net/optimization/ - -1. User initializes algorithm state with MinBLEICCreate() call - -2. USer adds boundary and/or linear constraints by calling - MinBLEICSetBC() and MinBLEICSetLC() functions. - -3. User sets stopping conditions with MinBLEICSetCond(). - -4. User calls MinBLEICOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. - -5. User calls MinBLEICResults() to get solution - -6. Optionally user may call MinBLEICRestartFrom() to solve another problem - with same N but another starting point. - MinBLEICRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size ofX - X - starting point, array[N]: - * it is better to set X to a feasible point - * but X can be infeasible, in which case algorithm will try - to find feasible point first, using X as initial - approximation. - -OUTPUT PARAMETERS: - State - structure stores algorithm state - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state); -void minbleiccreate(const real_1d_array &x, minbleicstate &state); - - -/************************************************************************* -The subroutine is finite difference variant of MinBLEICCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinBLEICCreate() in order to get -more information about creation of BLEIC optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinBLEICSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. CG needs exact gradient values. Imprecise - gradient may slow down convergence, especially on highly nonlinear - problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state); -void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state); - - -/************************************************************************* -This function sets boundary constraints for BLEIC optimizer. - -Boundary constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF. - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF. - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: this solver has following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints, - even when numerical differentiation is used (algorithm adjusts nodes - according to boundary constraints) - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbc(const minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu); - - -/************************************************************************* -This function sets linear constraints for BLEIC optimizer. - -Linear constraints are inactive by default (after initial creation). -They are preserved after algorithm restart with MinBLEICRestartFrom(). - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately: -* there always exists some minor violation (about Epsilon in magnitude) - due to rounding errors -* numerical differentiation, if used, may lead to function evaluations - outside of the feasible area, because algorithm does NOT change - numerical differentiation formula according to linear constraints. -If you want constraints to be satisfied exactly, try to reformulate your -problem in such manner that all constraints will become boundary ones -(this kind of constraints is always satisfied exactly, both in the final -solution and in all intermediate points). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); -void minbleicsetlc(const minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct); - - -/************************************************************************* -This function sets stopping conditions for the optimizer. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinBLEICSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection. - -NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform - slightly more than MaxIts iterations. I.e., MaxIts sets non-strict - limit on iterations count. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetcond(const minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function sets scaling coefficients for BLEIC optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the BLEIC too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinBLEICSetPrec...() -functions. - -There is a special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetscale(const minbleicstate &state, const real_1d_array &s); - - -/************************************************************************* -Modification of the preconditioner: preconditioning is turned off. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdefault(const minbleicstate &state); - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE 1: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecdiag(const minbleicstate &state, const real_1d_array &d); - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinBLEICSetScale() -call (before or after MinBLEICSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetprecscale(const minbleicstate &state); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinBLEICOptimize(). - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetxrep(const minbleicstate &state, const bool needxrep); - - -/************************************************************************* -This function sets maximum step length - -IMPORTANT: this feature is hard to combine with preconditioning. You can't -set upper limit on step length, when you solve optimization problem with -linear (non-boundary) constraints AND preconditioner turned on. - -When non-boundary constraints are present, you have to either a) use -preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! -In this case algorithm will terminate with appropriate error code. - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which lead to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetstpmax(const minbleicstate &state, const double stpmax); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minbleiciteration(const minbleicstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear optimizer - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() - for numerical differentiation) you should choose appropriate variant of - MinBLEICOptimize() - one which accepts function AND gradient or one - which accepts function ONLY. - - Be careful to choose variant of MinBLEICOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinBLEICOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinBLEICOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinBLEICCreateF() | work FAIL - MinBLEICCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinBLEICOptimize() version. Attemps to use such - combination (for example, to create optimizer with MinBLEICCreateF() - and to pass gradient information to MinCGOptimize()) will lead to - exception being thrown. Either you did not pass gradient when it WAS - needed or you passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey - -*************************************************************************/ -void minbleicoptimize(minbleicstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minbleicoptimize(minbleicstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -BLEIC results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report. You should check Rep.TerminationType - in order to distinguish successful termination from - unsuccessful one: - * -7 gradient verification failed. - See MinBLEICSetGradientCheck() for more information. - * -3 inconsistent constraints. Feasible point is - either nonexistent or too hard to find. Try to - restart optimizer with better initial approximation - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - More information about fields of this structure can be - found in the comments on MinBLEICReport datatype. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep); - - -/************************************************************************* -BLEIC results - -Buffered implementation of MinBLEICResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep); - - -/************************************************************************* -This subroutine restarts algorithm from new point. -All optimization parameters (including constraints) are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure previously allocated with MinBLEICCreate call. - X - new starting point. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicrestartfrom(const minbleicstate &state, const real_1d_array &x); - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinBLEICOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinBLEICSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetgradientcheck(const minbleicstate &state, const double teststep); - -/************************************************************************* - LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION - -DESCRIPTION: -The subroutine minimizes function F(x) of N arguments by using a quasi- -Newton method (LBFGS scheme) which is optimized to use a minimum amount -of memory. -The subroutine generates the approximation of an inverse Hessian matrix by -using information about the last M steps of the algorithm (instead of N). -It lessens a required amount of memory from a value of order N^2 to a -value of order 2*N*M. - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function value F and its gradient G (simultaneously) at given point X - - -USAGE: -1. User initializes algorithm state with MinLBFGSCreate() call -2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() - and other functions -3. User calls MinLBFGSOptimize() function which takes algorithm state and - pointer (delegate, etc.) to callback function which calculates F/G. -4. User calls MinLBFGSResults() to get solution -5. Optionally user may call MinLBFGSRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLBFGSRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - problem dimension. N>0 - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - initial solution approximation, array[0..N-1]. - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with MinLBFGSSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLBFGSSetStpMax() function to bound algorithm's steps. However, - L-BFGS rarely needs such a tuning. - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state); -void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state); - - -/************************************************************************* -The subroutine is finite difference variant of MinLBFGSCreate(). It uses -finite differences in order to differentiate target function. - -Description below contains information which is specific to this function -only. We recommend to read comments on MinLBFGSCreate() in order to get -more information about creation of LBFGS optimizer. - -INPUT PARAMETERS: - N - problem dimension, N>0: - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of corrections in the BFGS scheme of Hessian - approximation update. Recommended value: 3<=M<=7. The smaller - value causes worse convergence, the bigger will not cause a - considerably better convergence, but will cause a fall in the - performance. M<=N. - X - starting point, array[0..N-1]. - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. algorithm uses 4-point central formula for differentiation. -2. differentiation step along I-th axis is equal to DiffStep*S[I] where - S[] is scaling vector which can be set by MinLBFGSSetScale() call. -3. we recommend you to use moderate values of differentiation step. Too - large step will result in too large truncation errors, while too small - step will result in too large numerical errors. 1.0E-6 can be good - value to start with. -4. Numerical differentiation is very inefficient - one gradient - calculation needs 4*N function evaluations. This function will work for - any N - either small (1...10), moderate (10...100) or large (100...). - However, performance penalty will be too severe for any N's except for - small ones. - We should also say that code which relies on numerical differentiation - is less robust and precise. LBFGS needs exact gradient values. - Imprecise gradient may slow down convergence, especially on highly - nonlinear problems. - Thus we recommend to use this function for fast prototyping on small- - dimensional problems only, and to implement analytical gradient as soon - as possible. - - -- ALGLIB -- - Copyright 16.05.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state); -void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state); - - -/************************************************************************* -This function sets stopping conditions for L-BFGS optimization algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLBFGSSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcond(const minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLBFGSOptimize(). - - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetxrep(const minlbfgsstate &state, const bool needxrep); - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if - you don't want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetstpmax(const minlbfgsstate &state, const double stpmax); - - -/************************************************************************* -This function sets scaling coefficients for LBFGS optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Scaling is also used by finite difference variant of the optimizer - step -along I-th axis is equal to DiffStep*S[I]. - -In most optimizers (and in the LBFGS too) scaling is NOT a form of -preconditioning. It just affects stopping conditions. You should set -preconditioner by separate call to one of the MinLBFGSSetPrec...() -functions. - -There is special preconditioning mode, however, which uses scaling -coefficients to form diagonal preconditioning matrix. You can turn this -mode on, if you want. But you should understand that scaling is not the -same thing as preconditioning - these are two different, although related -forms of tuning solver. - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetscale(const minlbfgsstate &state, const real_1d_array &s); - - -/************************************************************************* -Modification of the preconditioner: default preconditioner (simple -scaling, same for all elements of X) is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdefault(const minlbfgsstate &state); - - -/************************************************************************* -Modification of the preconditioner: Cholesky factorization of approximate -Hessian is used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - P - triangular preconditioner, Cholesky factorization of - the approximate Hessian. array[0..N-1,0..N-1], - (if larger, only leading N elements are used). - IsUpper - whether upper or lower triangle of P is given - (other triangle is not referenced) - -After call to this function preconditioner is changed to P (P is copied -into the internal buffer). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: P should be nonsingular. Exception will be thrown otherwise. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetpreccholesky(const minlbfgsstate &state, const real_2d_array &p, const bool isupper); - - -/************************************************************************* -Modification of the preconditioner: diagonal of approximate Hessian is -used. - -INPUT PARAMETERS: - State - structure which stores algorithm state - D - diagonal of the approximate Hessian, array[0..N-1], - (if larger, only leading N elements are used). - -NOTE: you can change preconditioner "on the fly", during algorithm -iterations. - -NOTE 2: D[i] should be positive. Exception will be thrown otherwise. - -NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecdiag(const minlbfgsstate &state, const real_1d_array &d); - - -/************************************************************************* -Modification of the preconditioner: scale-based diagonal preconditioning. - -This preconditioning mode can be useful when you don't have approximate -diagonal of Hessian, but you know that your variables are badly scaled -(for example, one variable is in [1,10], and another in [1000,100000]), -and most part of the ill-conditioning comes from different scales of vars. - -In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), -can greatly improve convergence. - -IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() -call (before or after MinLBFGSSetPrecScale() call). Without knowledge of -the scale of your variables scale-based preconditioner will be just unit -matrix. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetprecscale(const minlbfgsstate &state); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minlbfgsiteration(const minlbfgsstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear optimizer - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - -NOTES: - -1. This function has two different implementations: one which uses exact - (analytical) user-supplied gradient, and one which uses function value - only and numerically differentiates function in order to obtain - gradient. - - Depending on the specific function used to create optimizer object - (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() - for numerical differentiation) you should choose appropriate variant of - MinLBFGSOptimize() - one which accepts function AND gradient or one - which accepts function ONLY. - - Be careful to choose variant of MinLBFGSOptimize() which corresponds to - your optimization scheme! Table below lists different combinations of - callback (function/gradient) passed to MinLBFGSOptimize() and specific - function used to create optimizer. - - - | USER PASSED TO MinLBFGSOptimize() - CREATED WITH | function only | function and gradient - ------------------------------------------------------------ - MinLBFGSCreateF() | work FAIL - MinLBFGSCreate() | FAIL work - - Here "FAIL" denotes inappropriate combinations of optimizer creation - function and MinLBFGSOptimize() version. Attemps to use such - combination (for example, to create optimizer with MinLBFGSCreateF() and - to pass gradient information to MinCGOptimize()) will lead to exception - being thrown. Either you did not pass gradient when it WAS needed or - you passed gradient when it was NOT needed. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey - -*************************************************************************/ -void minlbfgsoptimize(minlbfgsstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minlbfgsoptimize(minlbfgsstate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -L-BFGS algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -7 gradient verification failed. - See MinLBFGSSetGradientCheck() for more information. - * -2 rounding errors prevent further improvement. - X contains best point found. - * -1 incorrect parameters were specified - * 1 relative function improvement is no more than - EpsF. - * 2 relative step is no more than EpsX. - * 4 gradient norm is no more than EpsG - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep); - - -/************************************************************************* -L-BFGS algorithm results - -Buffered implementation of MinLBFGSResults which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep); - - -/************************************************************************* -This subroutine restarts LBFGS algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used to store algorithm state - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgsrestartfrom(const minlbfgsstate &state, const real_1d_array &x); - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLBFGSOptimize() is called -* prior to actual optimization, for each component of parameters being - optimized X[i] algorithm performs following steps: - * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], - where X[i] is i-th component of the initial point and S[i] is a scale - of i-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * F(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) gradient evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided by - some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLBFGSSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 24.05.2012 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetgradientcheck(const minlbfgsstate &state, const double teststep); - -/************************************************************************* - CONSTRAINED QUADRATIC PROGRAMMING - -The subroutine creates QP optimizer. After initial creation, it contains -default optimization problem with zero quadratic and linear terms and no -constraints. You should set quadratic/linear terms with calls to functions -provided by MinQP subpackage. - -INPUT PARAMETERS: - N - problem size - -OUTPUT PARAMETERS: - State - optimizer with zero quadratic/linear terms - and no constraints - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpcreate(const ae_int_t n, minqpstate &state); - - -/************************************************************************* -This function sets linear term for QP solver. - -By default, linear term is zero. - -INPUT PARAMETERS: - State - structure which stores algorithm state - B - linear term, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlinearterm(const minqpstate &state, const real_1d_array &b); - - -/************************************************************************* -This function sets dense quadratic term for QP solver. By default, -quadratic term is zero. - -SUPPORT BY ALGLIB QP ALGORITHMS: - -Dense quadratic term can be handled by any of the QP algorithms supported -by ALGLIB QP Solver. - -IMPORTANT: - -This solver minimizes following function: - f(x) = 0.5*x'*A*x + b'*x. -Note that quadratic term has 0.5 before it. So if you want to minimize - f(x) = x^2 + x -you should rewrite your problem as follows: - f(x) = 0.5*(2*x^2) + x -and your matrix A will be equal to [[2.0]], not to [[1.0]] - -INPUT PARAMETERS: - State - structure which stores algorithm state - A - matrix, array[N,N] - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used - * if not given, both lower and upper triangles must be - filled. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a, const bool isupper); -void minqpsetquadraticterm(const minqpstate &state, const real_2d_array &a); - - -/************************************************************************* -This function sets sparse quadratic term for QP solver. By default, -quadratic term is zero. - -SUPPORT BY ALGLIB QP ALGORITHMS: - -Sparse quadratic term is supported only by BLEIC-based QP algorithm (one -which is activated by MinQPSetAlgoBLEIC function). Cholesky-based QP algo -won't be able to deal with sparse quadratic term and will terminate -abnormally. - -IF YOU CALLED THIS FUNCTION, YOU MUST SWITCH TO BLEIC-BASED QP ALGORITHM -BEFORE CALLING MINQPOPTIMIZE() FUNCTION. - -IMPORTANT: - -This solver minimizes following function: - f(x) = 0.5*x'*A*x + b'*x. -Note that quadratic term has 0.5 before it. So if you want to minimize - f(x) = x^2 + x -you should rewrite your problem as follows: - f(x) = 0.5*(2*x^2) + x -and your matrix A will be equal to [[2.0]], not to [[1.0]] - -INPUT PARAMETERS: - State - structure which stores algorithm state - A - matrix, array[N,N] - IsUpper - (optional) storage type: - * if True, symmetric matrix A is given by its upper - triangle, and the lower triangle isn’t used - * if False, symmetric matrix A is given by its lower - triangle, and the upper triangle isn’t used - * if not given, both lower and upper triangles must be - filled. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetquadratictermsparse(const minqpstate &state, const sparsematrix &a, const bool isupper); - - -/************************************************************************* -This function sets starting point for QP solver. It is useful to have -good initial approximation to the solution, because it will increase -speed of convergence and identification of active constraints. - -INPUT PARAMETERS: - State - structure which stores algorithm state - X - starting point, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetstartingpoint(const minqpstate &state, const real_1d_array &x); - - -/************************************************************************* -This function sets origin for QP solver. By default, following QP program -is solved: - - min(0.5*x'*A*x+b'*x) - -This function allows to solve different problem: - - min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) - -INPUT PARAMETERS: - State - structure which stores algorithm state - XOrigin - origin, array[N]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetorigin(const minqpstate &state, const real_1d_array &xorigin); - - -/************************************************************************* -This function sets scaling coefficients. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -BLEIC-based QP solver uses scale for two purposes: -* to evaluate stopping conditions -* for preconditioning of the underlying BLEIC solver - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetscale(const minqpstate &state, const real_1d_array &s); - - -/************************************************************************* -This function tells solver to use Cholesky-based algorithm. This algorithm -is active by default. - -DESCRIPTION: - -Cholesky-based algorithm can be used only for problems which: -* have dense quadratic term, set by MinQPSetQuadraticTerm(), sparse or - structured problems are not supported. -* are strictly convex, i.e. quadratic term is symmetric positive definite, - indefinite or semidefinite problems are not supported by this algorithm. - -If anything of what listed above is violated, you may use BLEIC-based QP -algorithm which can be activated by MinQPSetAlgoBLEIC(). - -BENEFITS AND DRAWBACKS: - -This algorithm gives best precision amongst all QP solvers provided by -ALGLIB (Newton iterations have much higher precision than any other -optimization algorithm). This solver also gracefully handles problems with -very large amount of constraints. - -Performance of the algorithm is good because internally it uses Level 3 -Dense BLAS for its performance-critical parts. - - -From the other side, algorithm has O(N^3) complexity for unconstrained -problems and up to orders of magnitude slower on constrained problems -(these additional iterations are needed to identify active constraints). -So, its running time depends on number of constraints active at solution. - -Furthermore, this algorithm can not solve problems with sparse matrices or -problems with semidefinite/indefinite matrices of any kind (dense/sparse). - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgocholesky(const minqpstate &state); - - -/************************************************************************* -This function tells solver to use BLEIC-based algorithm and sets stopping -criteria for the algorithm. - -DESCRIPTION: - -BLEIC-based QP algorithm can be used for any kind of QP problems: -* problems with both dense and sparse quadratic terms -* problems with positive definite, semidefinite, indefinite terms - -BLEIC-based algorithm can solve even indefinite problems - as long as they -are bounded from below on the feasible set. Of course, global minimum is -found only for positive definite and semidefinite problems. As for -indefinite ones - only local minimum is found. - -BENEFITS AND DRAWBACKS: - -This algorithm can be used to solve both convex and indefinite QP problems -and it can utilize sparsity of the quadratic term (algorithm calculates -matrix-vector products, which can be performed efficiently in case of -sparse matrix). - -Algorithm has iteration cost, which (assuming fixed amount of non-boundary -linear constraints) linearly depends on problem size. Boundary constraints -does not significantly change iteration cost. - -Thus, it outperforms Cholesky-based QP algorithm (CQP) on high-dimensional -sparse problems with moderate amount of constraints. - - -From the other side, unlike CQP solver, this algorithm does NOT make use -of Level 3 Dense BLAS. Thus, its performance on dense problems is inferior -to that of CQP solver. - -Its precision is also inferior to that of CQP. CQP performs Newton steps -which are know to achieve very good precision. In many cases Newton step -leads us exactly to the solution. BLEIC-QP performs LBFGS steps, which are -good at detecting neighborhood of the solution, buy need many iterations -to find solution with 6 digits of precision. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - EpsX - >=0 - The subroutine finishes its work if exploratory steepest - descent step on k+1-th iteration satisfies following - condition: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - step vector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinQPSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead -to automatic stopping criterion selection (presently it is small step -length, but it may change in the future versions of ALGLIB). - -IT IS VERY IMPORTANT THAT YOU CALL MinQPSetScale() WHEN YOU USE THIS ALGO! - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetalgobleic(const minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function sets boundary constraints for QP solver - -Boundary constraints are inactive by default (after initial creation). -After being set, they are preserved until explicitly turned off with -another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpsetbc(const minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu); - - -/************************************************************************* -This function sets linear constraints for QP optimizer. - -Linear constraints are inactive by default (after initial creation). - -INPUT PARAMETERS: - State - structure previously allocated with MinQPCreate call. - C - linear constraints, array[K,N+1]. - Each row of C represents one constraint, either equality - or inequality (see below): - * first N elements correspond to coefficients, - * last element corresponds to the right part. - All elements of C (including right part) must be finite. - CT - type of constraints, array[K]: - * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] - * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] - * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] - K - number of equality/inequality constraints, K>=0: - * if given, only leading K elements of C/CT are used - * if not given, automatically determined from sizes of C/CT - -NOTE 1: linear (non-bound) constraints are satisfied only approximately - - there always exists some minor violation (about 10^-10...10^-13) - due to numerical errors. - - -- ALGLIB -- - Copyright 19.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k); -void minqpsetlc(const minqpstate &state, const real_2d_array &c, const integer_1d_array &ct); - - -/************************************************************************* -This function solves quadratic programming problem. -You should call it after setting solver options with MinQPSet...() calls. - -INPUT PARAMETERS: - State - algorithm state - -You should use MinQPResults() function to access results after calls -to this function. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey. - Special thanks to Elvira Illarionova for important suggestions on - the linearly constrained QP algorithm. -*************************************************************************/ -void minqpoptimize(const minqpstate &state); - - -/************************************************************************* -QP solver results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution. - This array is allocated and initialized only when - Rep.TerminationType parameter is positive (success). - Rep - optimization report. You should check Rep.TerminationType, - which contains completion code, and you may check another - fields which contain another information about algorithm - functioning. - - Failure codes returned by algorithm are: - * -5 inappropriate solver was used: - * Cholesky solver for (semi)indefinite problems - * Cholesky solver for problems with sparse matrix - * -4 BLEIC-QP algorithm found unconstrained direction - of negative curvature (function is unbounded from - below even under constraints), no meaningful - minimum can be found. - * -3 inconsistent constraints (or maybe feasible point - is too hard to find). If you are sure that - constraints are feasible, try to restart optimizer - with better initial approximation. - - Completion codes specific for Cholesky algorithm: - * 4 successful completion - - Completion codes specific for BLEIC-based algorithm: - * 1 relative function improvement is no more than EpsF. - * 2 scaled step is no more than EpsX. - * 4 scaled gradient norm is no more than EpsG. - * 5 MaxIts steps was taken - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep); - - -/************************************************************************* -QP results - -Buffered implementation of MinQPResults() which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 11.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep); - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] and Jacobian of f[]. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function vector f[] at given point X -* function vector f[] and Jacobian of f[] (simultaneously) at given point - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() and jac() callbacks. -First one is used to calculate f[] at given point, second one calculates -f[] and Jacobian df[i]/dx[j]. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not provide Jacobian), but it -will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateVJ() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); -void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state); - - -/************************************************************************* - IMPROVED LEVENBERG-MARQUARDT METHOD FOR - NON-LINEAR LEAST SQUARES OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of function which is represented as -sum of squares: - F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) -using value of function vector f[] only. Finite differences are used to -calculate Jacobian. - - -REQUIREMENTS: -This algorithm will request following information during its operation: -* function vector f[] at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts fvec() callback. - -You can try to initialize MinLMState structure with VJ function and then -use incorrect version of MinLMOptimize() (for example, version which -works with general form function and does not accept function vector), but -it will lead to exception being thrown after first attempt to calculate -Jacobian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateV() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N/M but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - M - number of functions f[i] - X - initial solution, array[0..N-1] - DiffStep- differentiation step, >0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -See also MinLMIteration, MinLMResults. - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state); -void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state); - - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE METHOD FOR NON-LINEAR OPTIMIZATION - -DESCRIPTION: -This function is used to find minimum of general form (not "sum-of- --squares") function - F = F(x[0], ..., x[n-1]) -using its gradient and Hessian. Levenberg-Marquardt modification with -L-BFGS pre-optimization and internal pre-conditioned L-BFGS optimization -after each Levenberg-Marquardt step is used. - - -REQUIREMENTS: -This algorithm will request following information during its operation: - -* function value F at given point X -* F and gradient G (simultaneously) at given point X -* F, G and Hessian H (simultaneously) at given point X - -There are several overloaded versions of MinLMOptimize() function which -correspond to different LM-like optimization algorithms provided by this -unit. You should choose version which accepts func(), grad() and hess() -function pointers. First pointer is used to calculate F at given point, -second one calculates F(x) and grad F(x), third one calculates F(x), -grad F(x), hess F(x). - -You can try to initialize MinLMState structure with FGH-function and then -use incorrect version of MinLMOptimize() (for example, version which does -not provide Hessian matrix), but it will lead to exception being thrown -after first attempt to calculate Hessian. - - -USAGE: -1. User initializes algorithm state with MinLMCreateFGH() call -2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and - other functions -3. User calls MinLMOptimize() function which takes algorithm state and - pointers (delegates, etc.) to callback functions. -4. User calls MinLMResults() to get solution -5. Optionally, user may call MinLMRestartFrom() to solve another problem - with same N but another starting point and/or another function. - MinLMRestartFrom() allows to reuse already initialized structure. - - -INPUT PARAMETERS: - N - dimension, N>1 - * if given, only leading N elements of X are used - * if not given, automatically determined from size of X - X - initial solution, array[0..N-1] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -1. you may tune stopping conditions with MinLMSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use MinLMSetStpMax() function to bound algorithm's steps. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgh(const ae_int_t n, const real_1d_array &x, minlmstate &state); -void minlmcreatefgh(const real_1d_array &x, minlmstate &state); - - -/************************************************************************* -This function sets stopping conditions for Levenberg-Marquardt optimization -algorithm. - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsG - >=0 - The subroutine finishes its work if the condition - |v|=0 - The subroutine finishes its work if on k+1-th iteration - the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} - is satisfied. - EpsX - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition |v|<=EpsX is fulfilled, where: - * |.| means Euclidian norm - * v - scaled step vector, v[i]=dx[i]/s[i] - * dx - ste pvector, dx=X(k+1)-X(k) - * s - scaling coefficients set by MinLMSetScale() - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. Only Levenberg-Marquardt - iterations are counted (L-BFGS/CG iterations are NOT - counted because their cost is very low compared to that of - LM). - -Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to -automatic stopping criterion selection (small EpsX). - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetcond(const minlmstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS -iterations are reported. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetxrep(const minlmstate &state, const bool needxrep); - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when you optimize target function which contains exp() -or other fast growing functions, and optimization algorithm makes too -large steps which leads to overflow. This function allows us to reject -steps that are too large (and therefore expose us to the possible -overflow) without actually calculating function value at the x+stp*d. - -NOTE: non-zero StpMax leads to moderate performance degradation because -intermediate step of preconditioned L-BFGS optimization is incompatible -with limits on step size. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetstpmax(const minlmstate &state, const double stpmax); - - -/************************************************************************* -This function sets scaling coefficients for LM optimizer. - -ALGLIB optimizers use scaling matrices to test stopping conditions (step -size and gradient are scaled before comparison with tolerances). Scale of -the I-th variable is a translation invariant measure of: -a) "how large" the variable is -b) how large the step should be to make significant changes in the function - -Generally, scale is NOT considered to be a form of preconditioner. But LM -optimizer is unique in that it uses scaling matrix both in the stopping -condition tests and as Marquardt damping factor. - -Proper scaling is very important for the algorithm performance. It is less -important for the quality of results, but still has some influence (it is -easier to converge when variables are properly scaled, so premature -stopping is possible when very badly scalled variables are combined with -relaxed stopping conditions). - -INPUT PARAMETERS: - State - structure stores algorithm state - S - array[N], non-zero scaling coefficients - S[i] may be negative, sign doesn't matter. - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetscale(const minlmstate &state, const real_1d_array &s); - - -/************************************************************************* -This function sets boundary constraints for LM optimizer - -Boundary constraints are inactive by default (after initial creation). -They are preserved until explicitly turned off with another SetBC() call. - -INPUT PARAMETERS: - State - structure stores algorithm state - BndL - lower bounds, array[N]. - If some (all) variables are unbounded, you may specify - very small number or -INF (latter is recommended because - it will allow solver to use better algorithm). - BndU - upper bounds, array[N]. - If some (all) variables are unbounded, you may specify - very large number or +INF (latter is recommended because - it will allow solver to use better algorithm). - -NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th -variable will be "frozen" at X[i]=BndL[i]=BndU[i]. - -NOTE 2: this solver has following useful properties: -* bound constraints are always satisfied exactly -* function is evaluated only INSIDE area specified by bound constraints - or at its boundary - - -- ALGLIB -- - Copyright 14.01.2011 by Bochkanov Sergey -*************************************************************************/ -void minlmsetbc(const minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu); - - -/************************************************************************* -This function is used to change acceleration settings - -You can choose between three acceleration strategies: -* AccType=0, no acceleration. -* AccType=1, secant updates are used to update quadratic model after each - iteration. After fixed number of iterations (or after model breakdown) - we recalculate quadratic model using analytic Jacobian or finite - differences. Number of secant-based iterations depends on optimization - settings: about 3 iterations - when we have analytic Jacobian, up to 2*N - iterations - when we use finite differences to calculate Jacobian. - -AccType=1 is recommended when Jacobian calculation cost is prohibitive -high (several Mx1 function vector calculations followed by several NxN -Cholesky factorizations are faster than calculation of one M*N Jacobian). -It should also be used when we have no Jacobian, because finite difference -approximation takes too much time to compute. - -Table below list optimization protocols (XYZ protocol corresponds to -MinLMCreateXYZ) and acceleration types they support (and use by default). - -ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: - -protocol 0 1 comment -V + + -VJ + + -FGH + - -DAFAULT VALUES: - -protocol 0 1 comment -V x without acceleration it is so slooooooooow -VJ x -FGH x - -NOTE: this function should be called before optimization. Attempt to call -it during algorithm iterations may result in unexpected behavior. - -NOTE: attempt to call this function with unsupported protocol/acceleration -combination will result in exception being thrown. - - -- ALGLIB -- - Copyright 14.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmsetacctype(const minlmstate &state, const ae_int_t acctype); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minlmiteration(const minlmstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear optimizer - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - hess - callback which calculates function (or merit function) - value func, gradient grad and Hessian hess at given point x - fvec - callback which calculates function vector fi[] - at given point x - jac - callback which calculates function vector fi[] - and Jacobian jac at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - -NOTES: - -1. Depending on function used to create state structure, this algorithm - may accept Jacobian and/or Hessian and/or gradient. According to the - said above, there ase several versions of this function, which accept - different sets of callbacks. - - This flexibility opens way to subtle errors - you may create state with - MinLMCreateFGH() (optimization using Hessian), but call function which - does not accept Hessian. So when algorithm will request Hessian, there - will be no callback to call. In this case exception will be thrown. - - Be careful to avoid such errors because there is no way to find them at - compile time - you can see them at runtime only. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey - -*************************************************************************/ -void minlmoptimize(minlmstate &state, - void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minlmoptimize(minlmstate &state, - void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*hess)(const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); -void minlmoptimize(minlmstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -Levenberg-Marquardt algorithm results - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report; - see comments for this structure for more info. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep); - - -/************************************************************************* -Levenberg-Marquardt algorithm results - -Buffered implementation of MinLMResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 10.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep); - - -/************************************************************************* -This subroutine restarts LM algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinLMCreateXXX call. - X - new starting point. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minlmrestartfrom(const minlmstate &state, const real_1d_array &x); - - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateVJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatevgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); -void minlmcreatevgj(const ae_int_t m, const real_1d_array &x, minlmstate &state); - - -/************************************************************************* -This is obsolete function. - -Since ALGLIB 3.3 it is equivalent to MinLMCreateFJ(). - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefgj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); -void minlmcreatefgj(const ae_int_t m, const real_1d_array &x, minlmstate &state); - - -/************************************************************************* -This function is considered obsolete since ALGLIB 3.1.0 and is present for -backward compatibility only. We recommend to use MinLMCreateVJ, which -provides similar, but more consistent and feature-rich interface. - - -- ALGLIB -- - Copyright 30.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minlmcreatefj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state); -void minlmcreatefj(const ae_int_t m, const real_1d_array &x, minlmstate &state); - - -/************************************************************************* -This subroutine turns on verification of the user-supplied analytic -gradient: -* user calls this subroutine before optimization begins -* MinLMOptimize() is called -* prior to actual optimization, for each function Fi and each component - of parameters being optimized X[j] algorithm performs following steps: - * two trial steps are made to X[j]-TestStep*S[j] and X[j]+TestStep*S[j], - where X[j] is j-th parameter and S[j] is a scale of j-th parameter - * if needed, steps are bounded with respect to constraints on X[] - * Fi(X) is evaluated at these trial points - * we perform one more evaluation in the middle point of the interval - * we build cubic model using function values and derivatives at trial - points and we compare its prediction with actual value in the middle - point - * in case difference between prediction and actual value is higher than - some predetermined threshold, algorithm stops with completion code -7; - Rep.VarIdx is set to index of the parameter with incorrect derivative, - Rep.FuncIdx is set to index of the function. -* after verification is over, algorithm proceeds to the actual optimization. - -NOTE 1: verification needs N (parameters count) Jacobian evaluations. It - is very costly and you should use it only for low dimensional - problems, when you want to be sure that you've correctly - calculated analytic derivatives. You should not use it in the - production code (unless you want to check derivatives provided - by some third party). - -NOTE 2: you should carefully choose TestStep. Value which is too large - (so large that function behaviour is significantly non-cubic) will - lead to false alarms. You may use different step for different - parameters by means of setting scale with MinLMSetScale(). - -NOTE 3: this function may lead to false positives. In case it reports that - I-th derivative was calculated incorrectly, you may decrease test - step and try one more time - maybe your function changes too - sharply and your step is too large for such rapidly chanding - function. - -INPUT PARAMETERS: - State - structure used to store algorithm state - TestStep - verification step: - * TestStep=0 turns verification off - * TestStep>0 activates verification - - -- ALGLIB -- - Copyright 15.06.2012 by Bochkanov Sergey -*************************************************************************/ -void minlmsetgradientcheck(const minlmstate &state, const double teststep); - -/************************************************************************* -Obsolete function, use MinLBFGSSetPrecDefault() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetdefaultpreconditioner(const minlbfgsstate &state); - - -/************************************************************************* -Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. - - -- ALGLIB -- - Copyright 13.10.2010 by Bochkanov Sergey -*************************************************************************/ -void minlbfgssetcholeskypreconditioner(const minlbfgsstate &state, const real_2d_array &p, const bool isupper); - - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierwidth(const minbleicstate &state, const double mu); - - -/************************************************************************* -This is obsolete function which was used by previous version of the BLEIC -optimizer. It does nothing in the current version of BLEIC. - - -- ALGLIB -- - Copyright 28.11.2010 by Bochkanov Sergey -*************************************************************************/ -void minbleicsetbarrierdecay(const minbleicstate &state, const double mudecay); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 25.03.2010 by Bochkanov Sergey -*************************************************************************/ -void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state); -void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetcond(const minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetxrep(const minasastate &state, const bool needxrep); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetalgorithm(const minasastate &state, const ae_int_t algotype); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 02.04.2010 by Bochkanov Sergey -*************************************************************************/ -void minasasetstpmax(const minasastate &state, const double stpmax); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool minasaiteration(const minasastate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear optimizer - -These functions accept following parameters: - state - algorithm state - grad - callback which calculates function (or merit function) - value func and gradient grad at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey - -*************************************************************************/ -void minasaoptimize(minasastate &state, - void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep); - - -/************************************************************************* -Obsolete optimization algorithm. -Was replaced by MinBLEIC subpackage. - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void minasarestartfrom(const minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void trimprepare(double f, double* threshold, ae_state *_state); -void trimfunction(double* f, - /* Real */ ae_vector* g, - ae_int_t n, - double threshold, - ae_state *_state); -ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, - /* Real */ ae_vector* bl, - /* Boolean */ ae_vector* havebl, - /* Real */ ae_vector* bu, - /* Boolean */ ae_vector* havebu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state); -void projectgradientintobc(/* Real */ ae_vector* x, - /* Real */ ae_vector* g, - /* Real */ ae_vector* bl, - /* Boolean */ ae_vector* havebl, - /* Real */ ae_vector* bu, - /* Boolean */ ae_vector* havebu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state); -void calculatestepbound(/* Real */ ae_vector* x, - /* Real */ ae_vector* d, - double alpha, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_int_t* variabletofreeze, - double* valuetofreeze, - double* maxsteplen, - ae_state *_state); -ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, - /* Real */ ae_vector* xprev, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_int_t variabletofreeze, - double valuetofreeze, - double steptaken, - double maxsteplen, - ae_state *_state); -void filterdirection(/* Real */ ae_vector* d, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - /* Real */ ae_vector* s, - ae_int_t nmain, - ae_int_t nslack, - double droptol, - ae_state *_state); -ae_int_t numberofchangedconstraints(/* Real */ ae_vector* x, - /* Real */ ae_vector* xprev, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - ae_state *_state); -ae_bool findfeasiblepoint(/* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Boolean */ ae_vector* havebndl, - /* Real */ ae_vector* bndu, - /* Boolean */ ae_vector* havebndu, - ae_int_t nmain, - ae_int_t nslack, - /* Real */ ae_matrix* ce, - ae_int_t k, - double epsi, - ae_int_t* qpits, - ae_int_t* gpaits, - ae_state *_state); -ae_bool derivativecheck(double f0, - double df0, - double f1, - double df1, - double f, - double df, - double width, - ae_state *_state); -void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state); -void cqmseta(convexquadraticmodel* s, - /* Real */ ae_matrix* a, - ae_bool isupper, - double alpha, - ae_state *_state); -void cqmrewritedensediagonal(convexquadraticmodel* s, - /* Real */ ae_vector* z, - ae_state *_state); -void cqmsetd(convexquadraticmodel* s, - /* Real */ ae_vector* d, - double tau, - ae_state *_state); -void cqmdropa(convexquadraticmodel* s, ae_state *_state); -void cqmsetb(convexquadraticmodel* s, - /* Real */ ae_vector* b, - ae_state *_state); -void cqmsetq(convexquadraticmodel* s, - /* Real */ ae_matrix* q, - /* Real */ ae_vector* r, - ae_int_t k, - double theta, - ae_state *_state); -void cqmsetactiveset(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Boolean */ ae_vector* activeset, - ae_state *_state); -double cqmeval(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -void cqmevalx(convexquadraticmodel* s, - /* Real */ ae_vector* x, - double* r, - double* noise, - ae_state *_state); -void cqmgradunconstrained(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* g, - ae_state *_state); -double cqmxtadx2(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -void cqmadx(convexquadraticmodel* s, - /* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_state *_state); -ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -void cqmscalevector(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -double cqmdebugconstrainedevalt(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -double cqmdebugconstrainedevale(convexquadraticmodel* s, - /* Real */ ae_vector* x, - ae_state *_state); -ae_bool _convexquadraticmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _convexquadraticmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _convexquadraticmodel_clear(void* _p); -void _convexquadraticmodel_destroy(void* _p); -void snnlsinit(ae_int_t nsmax, - ae_int_t ndmax, - ae_int_t nrmax, - snnlssolver* s, - ae_state *_state); -void snnlssetproblem(snnlssolver* s, - /* Real */ ae_matrix* a, - /* Real */ ae_vector* b, - ae_int_t ns, - ae_int_t nd, - ae_int_t nr, - ae_state *_state); -void snnlsdropnnc(snnlssolver* s, ae_int_t idx, ae_state *_state); -void snnlssolve(snnlssolver* s, - /* Real */ ae_vector* x, - ae_state *_state); -ae_bool _snnlssolver_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _snnlssolver_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _snnlssolver_clear(void* _p); -void _snnlssolver_destroy(void* _p); -void sasinit(ae_int_t n, sactiveset* s, ae_state *_state); -void sassetscale(sactiveset* state, - /* Real */ ae_vector* s, - ae_state *_state); -void sassetprecdiag(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state); -void sassetbc(sactiveset* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -void sassetlc(sactiveset* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state); -void sassetlcx(sactiveset* state, - /* Real */ ae_matrix* cleic, - ae_int_t nec, - ae_int_t nic, - ae_state *_state); -ae_bool sasstartoptimization(sactiveset* state, - /* Real */ ae_vector* x, - ae_state *_state); -void sasexploredirection(sactiveset* state, - /* Real */ ae_vector* d, - double* stpmax, - ae_int_t* cidx, - double* vval, - ae_state *_state); -ae_int_t sasmoveto(sactiveset* state, - /* Real */ ae_vector* xn, - ae_bool needact, - ae_int_t cidx, - double cval, - ae_state *_state); -void sasimmediateactivation(sactiveset* state, - ae_int_t cidx, - double cval, - ae_state *_state); -void sasconstraineddescent(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* d, - ae_state *_state); -void sasconstraineddescentprec(sactiveset* state, - /* Real */ ae_vector* g, - /* Real */ ae_vector* d, - ae_state *_state); -void sasconstraineddirection(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state); -void sasconstraineddirectionprec(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state); -void sascorrection(sactiveset* state, - /* Real */ ae_vector* x, - double* penalty, - ae_state *_state); -double sasactivelcpenalty1(sactiveset* state, - /* Real */ ae_vector* x, - ae_state *_state); -double sasscaledconstrainednorm(sactiveset* state, - /* Real */ ae_vector* d, - ae_state *_state); -void sasstopoptimization(sactiveset* state, ae_state *_state); -void sasreactivateconstraints(sactiveset* state, - /* Real */ ae_vector* gc, - ae_state *_state); -void sasreactivateconstraintsprec(sactiveset* state, - /* Real */ ae_vector* gc, - ae_state *_state); -void sasrebuildbasis(sactiveset* state, ae_state *_state); -ae_bool _sactiveset_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _sactiveset_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _sactiveset_clear(void* _p); -void _sactiveset_destroy(void* _p); -void mincgcreate(ae_int_t n, - /* Real */ ae_vector* x, - mincgstate* state, - ae_state *_state); -void mincgcreatef(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - mincgstate* state, - ae_state *_state); -void mincgsetcond(mincgstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void mincgsetscale(mincgstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state); -void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state); -void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state); -void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state); -void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state); -void mincgsetprecdefault(mincgstate* state, ae_state *_state); -void mincgsetprecdiag(mincgstate* state, - /* Real */ ae_vector* d, - ae_state *_state); -void mincgsetprecscale(mincgstate* state, ae_state *_state); -ae_bool mincgiteration(mincgstate* state, ae_state *_state); -void mincgresults(mincgstate* state, - /* Real */ ae_vector* x, - mincgreport* rep, - ae_state *_state); -void mincgresultsbuf(mincgstate* state, - /* Real */ ae_vector* x, - mincgreport* rep, - ae_state *_state); -void mincgrestartfrom(mincgstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void mincgsetprecdiagfast(mincgstate* state, - /* Real */ ae_vector* d, - ae_state *_state); -void mincgsetpreclowrankfast(mincgstate* state, - /* Real */ ae_vector* d1, - /* Real */ ae_vector* c, - /* Real */ ae_matrix* v, - ae_int_t vcnt, - ae_state *_state); -void mincgsetprecvarpart(mincgstate* state, - /* Real */ ae_vector* d2, - ae_state *_state); -void mincgsetgradientcheck(mincgstate* state, - double teststep, - ae_state *_state); -ae_bool _mincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mincgstate_clear(void* _p); -void _mincgstate_destroy(void* _p); -ae_bool _mincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _mincgreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _mincgreport_clear(void* _p); -void _mincgreport_destroy(void* _p); -void minbleiccreate(ae_int_t n, - /* Real */ ae_vector* x, - minbleicstate* state, - ae_state *_state); -void minbleiccreatef(ae_int_t n, - /* Real */ ae_vector* x, - double diffstep, - minbleicstate* state, - ae_state *_state); -void minbleicsetbc(minbleicstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -void minbleicsetlc(minbleicstate* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state); -void minbleicsetcond(minbleicstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void minbleicsetscale(minbleicstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void minbleicsetprecdefault(minbleicstate* state, ae_state *_state); -void minbleicsetprecdiag(minbleicstate* state, - /* Real */ ae_vector* d, - ae_state *_state); -void minbleicsetprecscale(minbleicstate* state, ae_state *_state); -void minbleicsetxrep(minbleicstate* state, - ae_bool needxrep, - ae_state *_state); -void minbleicsetdrep(minbleicstate* state, - ae_bool needdrep, - ae_state *_state); -void minbleicsetstpmax(minbleicstate* state, - double stpmax, - ae_state *_state); -ae_bool minbleiciteration(minbleicstate* state, ae_state *_state); -void minbleicresults(minbleicstate* state, - /* Real */ ae_vector* x, - minbleicreport* rep, - ae_state *_state); -void minbleicresultsbuf(minbleicstate* state, - /* Real */ ae_vector* x, - minbleicreport* rep, - ae_state *_state); -void minbleicrestartfrom(minbleicstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void minbleicemergencytermination(minbleicstate* state, ae_state *_state); -void minbleicsetgradientcheck(minbleicstate* state, - double teststep, - ae_state *_state); -ae_bool _minbleicstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minbleicstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minbleicstate_clear(void* _p); -void _minbleicstate_destroy(void* _p); -ae_bool _minbleicreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minbleicreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minbleicreport_clear(void* _p); -void _minbleicreport_destroy(void* _p); -void minlbfgscreate(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlbfgsstate* state, - ae_state *_state); -void minlbfgscreatef(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - double diffstep, - minlbfgsstate* state, - ae_state *_state); -void minlbfgssetcond(minlbfgsstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void minlbfgssetxrep(minlbfgsstate* state, - ae_bool needxrep, - ae_state *_state); -void minlbfgssetstpmax(minlbfgsstate* state, - double stpmax, - ae_state *_state); -void minlbfgssetscale(minlbfgsstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void minlbfgscreatex(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - ae_int_t flags, - double diffstep, - minlbfgsstate* state, - ae_state *_state); -void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state); -void minlbfgssetpreccholesky(minlbfgsstate* state, - /* Real */ ae_matrix* p, - ae_bool isupper, - ae_state *_state); -void minlbfgssetprecdiag(minlbfgsstate* state, - /* Real */ ae_vector* d, - ae_state *_state); -void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state); -ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state); -void minlbfgsresults(minlbfgsstate* state, - /* Real */ ae_vector* x, - minlbfgsreport* rep, - ae_state *_state); -void minlbfgsresultsbuf(minlbfgsstate* state, - /* Real */ ae_vector* x, - minlbfgsreport* rep, - ae_state *_state); -void minlbfgsrestartfrom(minlbfgsstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void minlbfgssetgradientcheck(minlbfgsstate* state, - double teststep, - ae_state *_state); -ae_bool _minlbfgsstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minlbfgsstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minlbfgsstate_clear(void* _p); -void _minlbfgsstate_destroy(void* _p); -ae_bool _minlbfgsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minlbfgsreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minlbfgsreport_clear(void* _p); -void _minlbfgsreport_destroy(void* _p); -void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state); -void minqpsetlinearterm(minqpstate* state, - /* Real */ ae_vector* b, - ae_state *_state); -void minqpsetquadraticterm(minqpstate* state, - /* Real */ ae_matrix* a, - ae_bool isupper, - ae_state *_state); -void minqpsetquadratictermsparse(minqpstate* state, - sparsematrix* a, - ae_bool isupper, - ae_state *_state); -void minqpsetstartingpoint(minqpstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void minqpsetorigin(minqpstate* state, - /* Real */ ae_vector* xorigin, - ae_state *_state); -void minqpsetscale(minqpstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void minqpsetalgocholesky(minqpstate* state, ae_state *_state); -void minqpsetalgobleic(minqpstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void minqpsetbc(minqpstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -void minqpsetlc(minqpstate* state, - /* Real */ ae_matrix* c, - /* Integer */ ae_vector* ct, - ae_int_t k, - ae_state *_state); -void minqpoptimize(minqpstate* state, ae_state *_state); -void minqpresults(minqpstate* state, - /* Real */ ae_vector* x, - minqpreport* rep, - ae_state *_state); -void minqpresultsbuf(minqpstate* state, - /* Real */ ae_vector* x, - minqpreport* rep, - ae_state *_state); -void minqpsetlineartermfast(minqpstate* state, - /* Real */ ae_vector* b, - ae_state *_state); -void minqpsetquadratictermfast(minqpstate* state, - /* Real */ ae_matrix* a, - ae_bool isupper, - double s, - ae_state *_state); -void minqprewritediagonal(minqpstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void minqpsetstartingpointfast(minqpstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void minqpsetoriginfast(minqpstate* state, - /* Real */ ae_vector* xorigin, - ae_state *_state); -ae_bool _minqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minqpstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minqpstate_clear(void* _p); -void _minqpstate_destroy(void* _p); -ae_bool _minqpreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minqpreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minqpreport_clear(void* _p); -void _minqpreport_destroy(void* _p); -void minlmcreatevj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state); -void minlmcreatev(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - double diffstep, - minlmstate* state, - ae_state *_state); -void minlmcreatefgh(ae_int_t n, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state); -void minlmsetcond(minlmstate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state); -void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state); -void minlmsetscale(minlmstate* state, - /* Real */ ae_vector* s, - ae_state *_state); -void minlmsetbc(minlmstate* state, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -void minlmsetacctype(minlmstate* state, - ae_int_t acctype, - ae_state *_state); -ae_bool minlmiteration(minlmstate* state, ae_state *_state); -void minlmresults(minlmstate* state, - /* Real */ ae_vector* x, - minlmreport* rep, - ae_state *_state); -void minlmresultsbuf(minlmstate* state, - /* Real */ ae_vector* x, - minlmreport* rep, - ae_state *_state); -void minlmrestartfrom(minlmstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void minlmcreatevgj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state); -void minlmcreatefgj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state); -void minlmcreatefj(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - minlmstate* state, - ae_state *_state); -void minlmsetgradientcheck(minlmstate* state, - double teststep, - ae_state *_state); -ae_bool _minlmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minlmstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minlmstate_clear(void* _p); -void _minlmstate_destroy(void* _p); -ae_bool _minlmreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minlmreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minlmreport_clear(void* _p); -void _minlmreport_destroy(void* _p); -void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, - ae_state *_state); -void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, - /* Real */ ae_matrix* p, - ae_bool isupper, - ae_state *_state); -void minbleicsetbarrierwidth(minbleicstate* state, - double mu, - ae_state *_state); -void minbleicsetbarrierdecay(minbleicstate* state, - double mudecay, - ae_state *_state); -void minasacreate(ae_int_t n, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - minasastate* state, - ae_state *_state); -void minasasetcond(minasastate* state, - double epsg, - double epsf, - double epsx, - ae_int_t maxits, - ae_state *_state); -void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state); -void minasasetalgorithm(minasastate* state, - ae_int_t algotype, - ae_state *_state); -void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state); -ae_bool minasaiteration(minasastate* state, ae_state *_state); -void minasaresults(minasastate* state, - /* Real */ ae_vector* x, - minasareport* rep, - ae_state *_state); -void minasaresultsbuf(minasastate* state, - /* Real */ ae_vector* x, - minasareport* rep, - ae_state *_state); -void minasarestartfrom(minasastate* state, - /* Real */ ae_vector* x, - /* Real */ ae_vector* bndl, - /* Real */ ae_vector* bndu, - ae_state *_state); -ae_bool _minasastate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minasastate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minasastate_clear(void* _p); -void _minasastate_destroy(void* _p); -ae_bool _minasareport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _minasareport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _minasareport_clear(void* _p); -void _minasareport_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _optimization_pkg_h +#define _optimization_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" +#include "solvers.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool nonc0suspected; + ae_bool nonc0test0positive; + ae_int_t nonc0fidx; + double nonc0lipschitzc; + ae_bool nonc1suspected; + ae_bool nonc1test0positive; + ae_bool nonc1test1positive; + ae_int_t nonc1fidx; + double nonc1lipschitzc; + ae_bool badgradsuspected; + ae_int_t badgradfidx; + ae_int_t badgradvidx; + ae_vector badgradxbase; + ae_matrix badgraduser; + ae_matrix badgradnum; +} optguardreport; +typedef struct +{ + ae_bool positive; + ae_int_t fidx; + ae_vector x0; + ae_vector d; + ae_int_t n; + ae_vector stp; + ae_vector f; + ae_int_t cnt; + ae_int_t stpidxa; + ae_int_t stpidxb; + ae_int_t inneriter; + ae_int_t outeriter; +} optguardnonc0report; +typedef struct +{ + ae_bool positive; + ae_int_t fidx; + ae_vector x0; + ae_vector d; + ae_int_t n; + ae_vector stp; + ae_vector f; + ae_int_t cnt; + ae_int_t stpidxa; + ae_int_t stpidxb; + ae_int_t inneriter; + ae_int_t outeriter; +} optguardnonc1test0report; +typedef struct +{ + ae_bool positive; + ae_int_t fidx; + ae_int_t vidx; + ae_vector x0; + ae_vector d; + ae_int_t n; + ae_vector stp; + ae_vector g; + ae_int_t cnt; + ae_int_t stpidxa; + ae_int_t stpidxb; + ae_int_t inneriter; + ae_int_t outeriter; +} optguardnonc1test1report; +#endif +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t ndense; + ae_int_t nsparse; + ae_matrix densec; + sparsematrix sparsec; + ae_vector dcl; + ae_vector dcu; + ae_vector scl; + ae_vector scu; + ae_int_t nec; + ae_int_t nic; + ae_matrix cleic; + ae_vector lcsrcidx; + ae_vector lcsrcmult; + sparsematrix effsparsea; + ae_vector effal; + ae_vector effau; + sparsematrix tmps; +} xlinearconstraints; +typedef struct +{ + ae_int_t n; + ae_bool hasknowntarget; + double targetf; + ae_vector s; + ae_vector c; + ae_vector bndl; + ae_vector bndu; + ae_int_t m; + sparsematrix a; + ae_vector al; + ae_vector au; +} lptestproblem; +#endif +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector norms; + ae_vector alpha; + ae_vector rho; + ae_matrix yk; + ae_vector idx; + ae_vector bufa; + ae_vector bufb; +} precbuflbfgs; +typedef struct +{ + ae_int_t n; + ae_int_t k; + ae_vector d; + ae_matrix v; + ae_vector bufc; + ae_matrix bufz; + ae_matrix bufw; + ae_vector tmp; +} precbuflowrank; +typedef struct +{ + ae_int_t htype; + ae_vector varscale; + ae_vector invscale; + ae_int_t n; + ae_int_t resetfreq; + double stpshort; + double gammasml; + double reg; + double smallreg; + double microreg; + double wolfeeps; + double maxhess; + ae_int_t m; + double mincostheta; + double mincrv; + ae_matrix hcurrent; + ae_int_t hage; + double sumy2; + double sums2; + double sumsy; + ae_int_t memlen; + double sigma; + ae_matrix s; + ae_matrix y; + ae_matrix lowranksst; + ae_matrix lowranksyt; + ae_bool lowrankmodelvalid; + ae_int_t lowrankk; + ae_matrix lowrankcp; + ae_matrix lowrankcm; + ae_bool lowrankeffdvalid; + ae_vector lowrankeffd; + ae_bool sr1modelvalid; + ae_int_t sr1k; + ae_matrix sr1c; + ae_vector sr1d; + ae_vector sr1z; + ae_matrix sr1stabc; + ae_vector sr1stabz; + ae_vector sr1stabd; + ae_bool sr1effdvalid; + ae_vector sr1effd; + double sr1nrm2; + double sr1nrm2stab; + ae_int_t updatestatus; + ae_matrix hincoming; + ae_vector sk; + ae_vector yk; + ae_vector rk; + ae_vector hsk; + ae_vector buf; + ae_vector buf2; + ae_matrix corr2; + ae_matrix tmps; + ae_matrix tmpy; + ae_matrix jk; + ae_matrix blk; + ae_matrix blk2; + ae_matrix blk3; + ae_matrix invsqrtdlk; + ae_vector bufvmv; + ae_vector bufupdhx; + ae_matrix tmpunstablec; + ae_vector tmpunstables; + ae_matrix tmpu; + ae_matrix tmpq; + ae_matrix tmpw; + ae_matrix tmpsl; + ae_matrix tmpl; + ae_vector tmpe; + ae_vector tmptau; +} xbfgshessian; +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_bool isdense; + ae_vector x; + ae_vector fi; + ae_matrix jac; + sparsematrix sj; +} varsfuncjac; +typedef struct +{ + double epsf; + double eps; + ae_int_t maxits; +} nlpstoppingcriteria; +typedef struct +{ + ae_int_t n; + ae_int_t k; + ae_bool checksmoothness; + ae_vector s; + ae_vector dcur; + ae_int_t enqueuedcnt; + ae_vector enqueuedstp; + ae_vector enqueuedx; + ae_vector enqueuedfunc; + ae_matrix enqueuedjac; + ae_vector sortedstp; + ae_vector sortedidx; + ae_int_t sortedcnt; + ae_int_t lagprobinneriter; + ae_int_t lagprobouteriter; + double lagprobstepmax; + ae_int_t lagprobnstepsstored; + ae_vector lagprobxs; + ae_vector lagprobd; + double lagprobstp; + ae_vector lagprobx; + ae_vector lagprobfi; + double lagprobrawlag; + ae_matrix lagprobj; + ae_matrix lagprobvalues; + ae_matrix lagprobjacobians; + ae_vector lagprobsteps; + ae_vector lagproblagrangians; + rcommstate lagrangianprobingrcomm; + ae_bool linesearchspoiled; + ae_bool linesearchstarted; + ae_int_t linesearchinneridx; + ae_int_t linesearchouteridx; + double nonc0currentrating; + double nonc1currentrating; + ae_bool badgradhasxj; + optguardreport rep; + double nonc0strrating; + double nonc0lngrating; + optguardnonc0report nonc0strrep; + optguardnonc0report nonc0lngrep; + double nonc1test0strrating; + double nonc1test0lngrating; + optguardnonc1test0report nonc1test0strrep; + optguardnonc1test0report nonc1test0lngrep; + double nonc1test1strrating; + double nonc1test1lngrating; + optguardnonc1test1report nonc1test1strrep; + optguardnonc1test1report nonc1test1lngrep; + ae_bool needfij; + ae_vector x; + ae_vector fi; + ae_matrix j; + rcommstate rstateg0; + ae_vector xbase; + ae_vector fbase; + ae_vector fm; + ae_vector fc; + ae_vector fp; + ae_vector jm; + ae_vector jc; + ae_vector jp; + ae_matrix jbaseusr; + ae_matrix jbasenum; + ae_vector stp; + ae_vector bufr; + ae_vector f; + ae_vector g; + ae_vector deltax; + ae_vector tmpidx; + ae_vector bufi; + ae_vector xu; + ae_vector du; + ae_vector f0; + ae_matrix j0; +} smoothnessmonitor; +typedef struct +{ + ae_int_t problemtype; + ae_int_t problemsubtype; + ae_int_t n; + ae_int_t m; + ae_matrix x0; + ae_int_t k0; + ae_matrix xsol; + ae_matrix fsol; + ae_int_t ksol; + ae_vector lagmultbc; + ae_vector lagmultlc; + ae_vector lagmultnlc; + ae_bool isrotated; + ae_matrix rotq; + ae_vector tgtc; + ae_matrix tgtb; + ae_matrix tgta; + ae_matrix tgtd; + ae_vector bndl; + ae_vector bndu; + ae_matrix densea; + ae_vector al; + ae_vector au; + ae_int_t nlinear; + ae_vector nlc; + ae_matrix nlb; + ae_matrix nla; + ae_matrix nld; + ae_vector hl; + ae_vector hu; + ae_int_t nnonlinear; +} multiobjectivetestfunction; +typedef struct +{ + double f0; + double g0; + double alpha1; + double alphamax; + double c1; + double c2; + ae_bool strongwolfecond; + ae_int_t maxits; + ae_bool dotrace; + ae_int_t tracelevel; + double bestalphasofar; + double bestfsofar; + double alphaprev; + double fprev; + double gprev; + double alphacur; + double fcur; + double gcur; + double alphalo; + double alphahi; + double flo; + double fhi; + double glo; + double ghi; + ae_int_t nfev; + double alphasol; + ae_int_t terminationtype; + double alphatrial; + double ftrial; + double gtrial; + rcommstate rstate; +} linesearchstate; +typedef struct +{ + double maxh; + ae_int_t filtersize; + ae_int_t maxdominating; + double gammaf; + double gammah; + ae_bool violationistoohigh; + ae_vector filterf; + ae_vector filterh; +} nlpfilter; +#endif +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double epsg; + double epsf; + double epsx; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + ae_vector s; + double diffstep; + ae_int_t nfev; + ae_int_t mcstage; + ae_int_t k; + ae_int_t q; + ae_int_t p; + ae_vector rho; + ae_matrix yk; + ae_matrix sk; + ae_vector xp; + ae_vector theta; + ae_vector d; + double stp; + double longeststp; + ae_vector work; + double fold; + double trimthreshold; + ae_vector xbase; + ae_int_t prectype; + double gammak; + ae_matrix denseh; + ae_vector diagh; + ae_vector precc; + ae_vector precd; + ae_matrix precw; + ae_int_t preck; + precbuflbfgs precbuf; + precbuflowrank lowrankbuf; + double fbase; + double fm2; + double fm1; + double fp1; + double fp2; + double stplimit; + ae_vector autobuf; + ae_vector invs; + ae_int_t protocolversion; + ae_bool userterminationneeded; + ae_vector x; + double f; + ae_vector g; + ae_bool needf; + ae_bool needfg; + ae_bool xupdated; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + double teststep; + rcommstate rstate; + ae_int_t repiterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + linminstate lstate; + ae_int_t smoothnessguardlevel; + smoothnessmonitor smonitor; + ae_vector lastscaleused; +} minlbfgsstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t terminationtype; +} minlbfgsreport; +#endif +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t k; + double alpha; + double tau; + double theta; + ae_matrix a; + ae_matrix q; + ae_vector b; + ae_vector r; + ae_vector xc; + ae_vector d; + ae_vector activeset; + ae_matrix tq2dense; + ae_matrix tk2; + ae_vector tq2diag; + ae_vector tq1; + ae_vector tk1; + double tq0; + double tk0; + ae_vector txc; + ae_vector tb; + ae_int_t nfree; + ae_int_t ecakind; + ae_matrix ecadense; + ae_matrix eq; + ae_matrix eccm; + ae_vector ecadiag; + ae_vector eb; + double ec; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmpg; + ae_matrix tmp2; + ae_bool ismaintermchanged; + ae_bool issecondarytermchanged; + ae_bool islineartermchanged; + ae_bool isactivesetchanged; +} convexquadraticmodel; +#endif +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t ns; + ae_int_t nd; + ae_int_t nr; + ae_matrix densea; + ae_vector b; + ae_vector nnc; + double debugflops; + ae_int_t debugmaxinnerits; + ae_vector xn; + ae_vector xp; + ae_matrix tmpca; + ae_matrix tmplq; + ae_matrix trda; + ae_vector trdd; + ae_vector crb; + ae_vector g; + ae_vector d; + ae_vector dx; + ae_vector diagaa; + ae_vector cb; + ae_vector cx; + ae_vector cborg; + ae_vector tmpcholesky; + ae_vector r; + ae_vector regdiag; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector rdtmprowmap; +} snnlssolver; +#endif +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t algostate; + ae_vector xc; + ae_bool hasxc; + ae_vector s; + ae_vector h; + ae_vector cstatus; + ae_bool basisisready; + ae_matrix sdensebatch; + ae_matrix pdensebatch; + ae_matrix idensebatch; + ae_int_t densebatchsize; + ae_vector sparsebatch; + ae_int_t sparsebatchsize; + ae_int_t basisage; + ae_bool feasinitpt; + ae_bool constraintschanged; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector bndl; + ae_vector bndu; + ae_matrix cleic; + ae_int_t nec; + ae_int_t nic; + ae_vector mtnew; + ae_vector mtx; + ae_vector mtas; + ae_vector cdtmp; + ae_vector corrtmp; + ae_vector unitdiagonal; + snnlssolver solver; + ae_vector scntmp; + ae_vector tmp0; + ae_vector tmpfeas; + ae_matrix tmpm0; + ae_vector rctmps; + ae_vector rctmpg; + ae_vector rctmprightpart; + ae_matrix rctmpdense0; + ae_matrix rctmpdense1; + ae_vector rctmpisequality; + ae_vector rctmpconstraintidx; + ae_vector rctmplambdas; + ae_matrix tmpbasis; + ae_vector tmpnormestimates; + ae_vector tmpreciph; + ae_vector tmpprodp; + ae_vector tmpprods; + ae_vector tmpcp; + ae_vector tmpcs; + ae_vector tmpci; +} sactiveset; +#endif +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double epsg; + double epsf; + double epsx; + ae_int_t maxouterits; + ae_bool cgphase; + ae_bool cnphase; + ae_int_t cgminits; + ae_int_t cgmaxits; + ae_int_t cnmaxupdates; + ae_int_t sparsesolver; +} qqpsettings; +typedef struct +{ + ae_int_t n; + ae_int_t akind; + ae_matrix densea; + sparsematrix sparsea; + ae_bool sparseupper; + double absamax; + double absasum; + double absasum2; + ae_vector b; + ae_vector bndl; + ae_vector bndu; + ae_vector havebndl; + ae_vector havebndu; + ae_vector xs; + ae_vector xf; + ae_vector gc; + ae_vector xp; + ae_vector dc; + ae_vector dp; + ae_vector cgc; + ae_vector cgp; + sactiveset sas; + ae_vector activated; + ae_int_t nfree; + ae_int_t cnmodelage; + ae_matrix densez; + sparsematrix sparsecca; + ae_vector yidx; + ae_vector regdiag; + ae_vector regx0; + ae_vector tmpcn; + ae_vector tmpcni; + ae_vector tmpcnb; + ae_vector tmp0; + ae_vector tmp1; + ae_vector stpbuf; + sparsebuffers sbuf; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repncholesky; + ae_int_t repncupdates; +} qqpbuffers; +#endif +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double epsx; + ae_int_t outerits; + double rho; +} qpdenseaulsettings; +typedef struct +{ + ae_vector nulc; + ae_matrix sclsfta; + ae_vector sclsftb; + ae_vector sclsfthasbndl; + ae_vector sclsfthasbndu; + ae_vector sclsftbndl; + ae_vector sclsftbndu; + ae_vector sclsftxc; + ae_matrix sclsftcleic; + ae_vector cidx; + ae_vector cscales; + ae_matrix exa; + ae_vector exb; + ae_vector exxc; + ae_vector exbndl; + ae_vector exbndu; + ae_vector exscale; + ae_vector exxorigin; + qqpsettings qqpsettingsuser; + qqpbuffers qqpbuf; + ae_vector nulcest; + ae_vector tmpg; + ae_vector tmp0; + ae_matrix tmp2; + ae_vector modelg; + ae_vector d; + ae_vector deltax; + convexquadraticmodel dummycqm; + sparsematrix dummysparse; + ae_matrix qrkkt; + ae_vector qrrightpart; + ae_vector qrtau; + ae_vector qrsv0; + ae_vector qrsvx1; + ae_vector nicerr; + ae_vector nicnact; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repncholesky; + ae_int_t repnwrkchanges; + ae_int_t repnwrk0; + ae_int_t repnwrk1; + ae_int_t repnwrkf; + ae_int_t repnmv; +} qpdenseaulbuffers; +#endif +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_vector x; + ae_vector g; + ae_vector w; + ae_vector t; + ae_vector p; + ae_vector y; + ae_vector z; + ae_vector v; + ae_vector s; + ae_vector q; +} vipmvars; +typedef struct +{ + sparsematrix rawsystem; + ae_vector effectivediag; + ae_vector isdiagonal; + ae_vector rowdegrees; + ae_vector coldegrees; + ae_int_t ntotal; + spcholanalysis analysis; + ae_vector priorities; + ae_vector diagterm; + ae_vector dampterm; + ae_vector tmpb; + ae_vector tmprhs; + ae_vector tmpcorr; +} vipmreducedsparsesystem; +typedef struct +{ + ae_vector sigma; + ae_vector beta; + ae_vector rho; + ae_vector nu; + ae_vector tau; + ae_vector alpha; + ae_vector gammaz; + ae_vector gammas; + ae_vector gammaw; + ae_vector gammaq; +} vipmrighthandside; +typedef struct +{ + ae_bool slacksforequalityconstraints; + ae_bool normalize; + ae_int_t n; + ae_int_t nmain; + double epsp; + double epsd; + double epsgap; + ae_bool islinear; + ae_vector scl; + ae_vector invscl; + ae_vector xorigin; + double targetscale; + ae_vector c; + ae_matrix denseh; + sparsematrix sparseh; + ae_vector diagr; + ae_int_t hkind; + ae_bool isdiagonalh; + ae_vector bndl; + ae_vector bndu; + ae_vector rawbndl; + ae_vector rawbndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_matrix denseafull; + ae_matrix denseamain; + sparsematrix sparseafull; + sparsematrix sparseamain; + sparsematrix combinedaslack; + ae_vector ascales; + ae_vector aflips; + ae_vector b; + ae_vector r; + ae_vector hasr; + ae_int_t mdense; + ae_int_t msparse; + vipmvars current; + vipmvars best; + vipmvars trial; + vipmvars deltaaff; + vipmvars deltacorr; + ae_vector isfrozen; + ae_vector hasgz; + ae_vector hasts; + ae_vector haswv; + ae_vector haspq; + ae_int_t cntgz; + ae_int_t cntts; + ae_int_t cntwv; + ae_int_t cntpq; + ae_int_t repiterationscount; + ae_int_t repncholesky; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_int_t factorizationtype; + ae_bool factorizationpoweredup; + ae_bool factorizationpresent; + ae_vector diagdz; + ae_vector diagdzi; + ae_vector diagdziri; + ae_vector diagds; + ae_vector diagdsi; + ae_vector diagdsiri; + ae_vector diagdw; + ae_vector diagdwi; + ae_vector diagdwir; + ae_vector diagdq; + ae_vector diagdqi; + ae_vector diagdqiri; + ae_vector diagddr; + ae_vector diagde; + ae_vector diagder; + ae_matrix factdensehaug; + ae_vector factregdhrh; + ae_vector factinvregdzrz; + ae_vector factregewave; + ae_vector facttmpdiag; + ae_vector facttmpdamp; + vipmreducedsparsesystem reducedsparsesystem; + vipmrighthandside rhs; + ae_vector rhsalphacap; + ae_vector rhsbetacap; + ae_vector rhsnucap; + ae_vector rhstaucap; + ae_vector deltaxy; + ae_vector tmphx; + ae_vector tmpax; + ae_vector tmpaty; + vipmvars zerovars; + ae_vector dummyr; + ae_vector tmpy; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_matrix tmpr2; + ae_vector tmplaggrad; + ae_vector tmpi; + sparsematrix tmpsparse0; +} vipmstate; +#endif +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t ntotal; + ae_int_t m; + ae_vector x; + ae_vector g; + ae_vector t; + ae_vector y; + ae_vector z; + ae_vector s; +} ipm2vars; +typedef struct +{ + sparsematrix compactkkt; + ae_vector compactpriorities; + spcholanalysis analysis; + ae_vector extendedrawdiagonal; + ae_vector extendedeffdiagonal; + ae_vector compacteffdiagonal; + ae_vector extendedrhs; + ae_vector compactrhs; + ae_vector u0; + ae_vector u1; + ae_vector v0; + ae_vector v1; + ae_vector vm0; + ae_vector vm1; + ae_vector um0; + ae_vector d0; + ae_vector d1; + ae_vector d2; + ae_vector d3; + ae_vector d4; + ae_vector d5; + ae_vector d6; + ae_vector d7; + ae_vector rowdegrees; + ae_vector coldegrees; + ae_vector tmpregrhs; +} ipm2reducedsystem; +typedef struct +{ + ae_vector gammagz; + ae_vector gammats; + ae_vector ed; + ae_vector ea; + ae_vector el; + ae_vector eu; +} ipm2righthandside; +typedef struct +{ + ae_int_t nuser; + ae_int_t naug; + ae_int_t ntotal; + ae_bool hasuserpermutation; + ae_vector userpermutation; + double epsp; + double epsd; + double epsgap; + ae_int_t maxipmits; + ae_bool islinear; + ae_vector sclx; + ae_vector invsclx; + ae_vector xoriginx; + double targetscale; + ae_vector ce; + sparsematrix sparsehe; + ae_vector diagr; + ae_bool isdiagonalh; + double greg; + ae_vector gregoriginxuser; + ae_vector gregoriginyuser; + ae_vector gregdiag; + ae_vector gregrhsx; + ae_vector gregrhsy; + ae_vector gregoriginx; + ae_vector gregoriginy; + ae_vector rawbndl; + ae_vector rawbndu; + ae_vector bndle; + ae_vector bndue; + ae_vector bndlef; + ae_vector bnduef; + ae_vector hasbndle; + ae_vector hasbndue; + sparsematrix rawae; + ae_vector ascales; + ae_int_t mraw; + ipm2vars current; + ipm2vars best; + ipm2vars delta; + ipm2vars corr; + ae_vector hasgz; + ae_vector hasts; + ae_vector maskgz; + ae_vector maskts; + ae_int_t cntgz; + ae_int_t cntts; + ae_vector currenthx; + ae_vector currentax; + ae_vector currentaty; + ipm2righthandside rhstarget; + ae_int_t repiterationscount; + ae_int_t repncholesky; + ae_bool dotrace; + ae_bool dotimers; + ae_bool dodetailedtrace; + stimer timertotal; + stimer timeranalyze; + stimer timerfactorize; + stimer timerspsymmsolve; + stimer timerothersolve; + ipm2reducedsystem reducedsystem; + ipm2righthandside rhsprogress; + ae_vector tmphx; + ae_vector tmpax; + ae_vector tmpaty; + ae_vector dummyr; + ae_vector tmp0; + ae_matrix tmpr2; + sparsematrix tmpa; + ae_vector tmpal; + ae_vector tmpau; + sparsematrix tmpsparse0; + sparsematrix tmplowerh; + ae_matrix tmpccorr; + ae_vector tmpdcorr; +} ipm2state; +#endif +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + sparsematrix haug; + ae_vector priorities; + spcholanalysis analysis; + ae_vector effdiagonal; + ae_vector dampdiagonal; + ae_vector dx; + ae_vector bx; + ae_vector dh; + fblsgmresstate gmressolver; + ae_int_t repiterationscount; + ae_int_t repncholesky; + ae_bool dotrace; + ae_bool dotimers; + stimer timertotal; + stimer timeranalyze; + stimer timerfactorize; + stimer timerspsymmsolve; + stimer timerothersolve; +} ecqpstate; +#endif +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t np; + ae_int_t nf; + ae_int_t mflex; + ae_int_t mhard; + ae_vector xp; + ae_vector zlp; + ae_vector zup; + ae_vector yp; + ae_vector yl; + ae_vector yu; + ae_vector yv; + ae_vector xs; + ae_vector gl; + ae_vector gu; + ae_vector zls; + ae_vector zus; +} gipmvars; +typedef struct +{ + ae_vector rp; + ae_vector rs; + ae_vector rgl; + ae_vector rgu; + ae_vector ry; + ae_vector rcl; + ae_vector rcu; + ae_vector rlp; + ae_vector rup; + ae_vector rls; + ae_vector rus; + ae_vector rv; +} gipmrhs; +typedef struct +{ + ae_vector tls; + ae_vector tus; + ae_vector tgl; + ae_vector tgu; + ae_vector ts; + ae_vector ta; + ae_vector t0; + ae_vector t1; + ae_vector t2; + ae_vector t3; + ae_vector t4; + ae_vector t5; + ae_vector wx; + ae_vector wy; + ae_vector wyv; + ae_vector d0; + ae_vector d1; + ae_vector d1v; +} gipmcondensedsystem; +typedef struct +{ + ae_int_t nraw; + ae_int_t mflex; + ae_int_t mhard; + ae_vector x0; + ae_vector bndlx; + ae_vector bndux; + ae_vector hasbndlx; + ae_vector hasbndux; + ae_vector isequality; + ae_vector fscales; + ae_bool isfirstorder; + ae_vector qnmask; + ae_bool isqnmasknonzero; + double trustradxp; + ae_bool mudependent; + double eps; + ae_int_t maxits; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_vector querydata; + double querymu; + ae_vector replyfi; + sparsematrix replysj; + ae_vector replysol; + ae_vector replyprod; + ae_bool hasjac; + ae_bool factsuccess; + ae_vector elp; + ae_vector eup; + ae_vector els; + ae_vector eus; + ae_vector finitebndlx; + ae_vector finitebndux; + ae_vector safeguardbndlp; + ae_vector safeguardbndup; + double nrmx0; + double absf0; + double mu; + double lambdav; + double lambdadecay; + ae_int_t subsequentfactfailures; + gipmvars current; + gipmvars best; + varsfuncjac currentfj; + varsfuncjac bestfj; + double besterr; + ae_int_t rhsstagnationcounter; + ae_bool filterready; + nlpfilter filter; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_bool dolaconictrace; + ae_int_t nonmonotonicmemlen; + ae_int_t nonmonotonicpos; + ae_vector nonmonotonicmerit; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + stimer timertotal; + ae_nxpool mnx1pool; + gipmrhs rhs; + gipmcondensedsystem condensed; + gipmvars delta; + gipmvars corr; + ae_vector tmphdxp; + ae_vector tmpjdxp; + ae_vector tmpjtdy; + gipmvars trial; + varsfuncjac trialfj; + rcommstate rstate; +} gipmstate; +#endif +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + sparsematrix lowerh; + ae_vector ordervaridx; + ae_vector injectionoffsets; +} gqpsparseconichessian; +typedef struct +{ + ae_bool hasdenseterm; + ae_int_t nvars; + ae_vector varidx; + ae_matrix q; +} gqpoptionaldense; +typedef struct +{ + ae_int_t algomode; + ae_int_t hessmemlen; + ae_int_t hessmaxoffdiag; + ae_int_t n; + ae_int_t mlc; + ae_int_t mqc; + ae_int_t msocc; + ae_vector x0; + ae_vector wrkbndl; + ae_vector wrkbndu; + ae_vector finiterawbndl; + ae_vector finiterawbndu; + ae_vector isfixed; + ae_vector fixedidx; + ae_int_t fixedvarscnt; + ae_vector c; + ae_vector iotac; + ae_matrix denseq; + sparsematrix sparseq1; + gqpoptionaldense optionaldenseq1; + ae_int_t nq; + ae_int_t cvxobjective; + sparsematrix sparselc; + ae_vector lcbndl; + ae_vector lcbndu; + xquadraticconstraints xqc; + xconicconstraints xcc; + ae_obj_array optionaldensexqc; + ae_obj_array xchsparse; + ae_int_t pctype; + ae_int_t cvxqc; + ae_int_t cvxcc; + double eps; + ae_int_t maxits; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_bool dotrace; + ae_bool dolaconictrace; + stimer timertotal; + gipmstate solver; + sparsematrix curjac; + ae_matrix currenth; + ae_vector tmpd1; + ae_vector tmpd2; + ae_matrix currentch; + ae_matrix tmpwj; + ae_vector currentx; + ae_vector currentlag; + sparsematrix sparseh; + sparsematrix sparsehdeps; + sparsematrix sparsesys; + ae_vector priorities; + spcholanalysis analysis; + xbfgshessian hess; + ae_vector basehsr1diag; + ae_vector basehsr1corrd; + ae_matrix basehsr1corrc; + ae_int_t basehrank; + ae_nxpool nrealpool; + ae_vector totalnl; + ae_vector totalnu; + sparsematrix wrklc; + ae_vector fscales; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmp3; + ae_vector tmpx; + ae_vector tmprhsy; + ae_vector tmpi; + ae_matrix dummy2; + ae_vector tmphr; + ae_vector tmphc; + ae_vector tmphk; + ae_vector tmphr2; + ae_vector tmphc2; + ae_vector tmphk2; + ae_vector tmphv; + ae_vector tmphv2; + ae_vector tmpb; + ae_vector doqnupdates; +} gqpipmstate; +#endif +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t m; + ae_int_t n; + ae_int_t maxallocated; + ae_vector rowbegin; + ae_vector rowend; + ae_vector idx; + ae_vector vals; +} dynamiccrs; +typedef struct +{ + ae_int_t nvars; + ae_vector varidx; + ae_vector b; + dynamiccrs fullq; + double cl; + double cu; + ae_bool applyorigin; +} dynamiccrsqconstraint; +typedef struct +{ + ae_obj_array constraints; +} dynamiccrsqconstraints; +typedef struct +{ + niset setn; + niset setn2; + niset setn3; + niset setm; + ae_vector sparseidx; + ae_vector sparsevals; + ae_vector fixedlocal; + ae_vector tmp0; + dynamiccrsqconstraint qc; +} presolvebuffers; +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_int_t mqc; + ae_int_t mcc; + ae_int_t ntrf; + ae_vector trftype; + ae_vector idata; + ae_vector rdata; + ae_vector idataridx; + ae_vector rdataridx; + ae_int_t sourceidx; + ae_int_t isrc; + ae_int_t rsrc; + ae_vector sparseidx0; + ae_vector sparseidx1; + ae_vector sparseidx2; + ae_vector sparseidx3; + ae_vector sparseval0; + ae_vector sparseval1; + ae_vector sparseval2; + ae_vector sparseval3; +} presolverstack; +typedef struct +{ + ae_vector isdroppedcol; + ae_vector isdroppedlc; + ae_vector isdroppedqc; + ae_vector isdroppedcc; + ae_vector cntdownwardaxial; + ae_vector cntupwardaxial; + ae_vector cntaxial; + ae_vector cntradial; + ae_vector nlcpervar; + kniset varbyqc; + kniset varbycc; +} presolvervcstats; +typedef struct +{ + double eps; + ae_int_t newn; + ae_int_t oldn; + ae_int_t oldmqc; + ae_int_t oldmcc; + ae_int_t newm; + ae_int_t oldm; + ae_int_t newmqc; + ae_int_t newmcc; + ae_vector rawc; + ae_vector rawbndl; + ae_vector rawbndu; + ae_bool hash; + sparsematrix rawh; + sparsematrix rawa; + xquadraticconstraints rawxqc; + xconicconstraints rawxcc; + ae_int_t problemstatus; + ae_vector lagrangefromresidual; + ae_vector c; + ae_vector bndl; + ae_vector bndu; + sparsematrix sparseh; + sparsematrix sparsea; + ae_vector al; + ae_vector au; + xquadraticconstraints xqc; + xconicconstraints xcc; + ae_vector packxperm; + ae_vector packyperm; + ae_vector packqcperm; + ae_vector packccperm; + ae_vector packstatperm; + ae_vector unpackxperm; + ae_vector unpackyperm; + ae_vector unpackqcperm; + ae_vector unpackccperm; + ae_vector unpackstatperm; + presolverstack trfstack; + ae_vector s1; + ae_vector bc1; + ae_vector x1; + ae_vector y1; + ae_vector yqc; + ae_vector d; + ae_vector tmpi; + presolvebuffers buf; +} presolveinfo; +#endif +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + qqpsettings qqpsettingsuser; + qpdenseaulsettings qpdenseaulsettingsuser; + double veps; + ae_int_t vmemlen; + ae_int_t vmaxoffdiag; + ae_int_t gmaxits; + ae_bool dbgskipconstraintnormalization; + ae_bool dbgdopresolve; + ae_int_t algokind; + ae_int_t akind; + convexquadraticmodel a; + ae_bool cqmready; + sparsematrix sparsea; + ae_bool sparseaupper; + double absamax; + double absasum; + double absasum2; + ae_vector b; + ae_vector bndl; + ae_vector bndu; + ae_int_t stype; + ae_vector s; + ae_vector havebndl; + ae_vector havebndu; + ae_vector xorigin; + ae_vector startx; + ae_bool havex; + xlinearconstraints xlc; + xquadraticconstraints xqc; + xconicconstraints xcc; + ae_vector xs; + double repf; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repncholesky; + ae_int_t repnmv; + ae_int_t repterminationtype; + ae_vector replagbc; + ae_vector replaglc; + ae_vector replagqc; + ae_int_t repn; + ae_int_t repm; + ae_int_t repmqc; + ae_int_t repmcc; + ae_vector effectives; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmpi; + ae_vector elaglc; + ae_vector dummyr; + ae_matrix dummyr2; + sparsematrix dummysparse; + ae_matrix tmpr2; + presolveinfo presolver; + ae_nxpool n1realpool; + ae_nxpool n1intpool; + qqpbuffers qqpbuf; + qpdenseaulbuffers qpdenseaulbuf; + vipmstate vsolver; + ipm2state ipm2; + ecqpstate ecqp; + gqpipmstate genipm; + sparsematrix modsparsea; + xconicconstraints modxcc; +} minqpstate; +typedef struct +{ + ae_int_t inneriterationscount; + ae_int_t outeriterationscount; + ae_int_t nmv; + ae_int_t ncholesky; + ae_int_t terminationtype; + double f; + ae_vector lagbc; + ae_vector laglc; + ae_vector lagqc; +} minqpreport; +#endif +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + vipmstate ipmsolver; + ipm2state ipm2; + ae_vector ordering; + ae_vector elasticordering; + sparsematrix pattern; + sparsematrix elasticpattern; + sparsematrix upcomingpattern; + ae_vector curb; + ae_vector curbndl; + ae_vector curbndu; + ae_vector cural; + ae_vector curau; + sparsematrix sparserawlc; + sparsematrix sparseefflc; + ae_vector lastlaglc; + double penalty0; + double penalty1; + ae_matrix denseh; + ae_vector dummy1; + ae_matrix densedummy; + sparsematrix sparsetmp; + sparsematrix sparsedummy; + ae_vector tmps; + ae_vector tmporigin; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector retainnegativebclm; + ae_vector retainpositivebclm; + ae_vector rescalelag; + ae_vector isinactive; + ae_matrix tmpcorrc; + ae_vector tmpdiag; + ae_vector isbounded; + ae_vector hessdiag; + ae_matrix hesscorrc; + ae_vector hesscorrd; + ae_int_t hessrank; + sparsematrix hesssparsediag; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector hasal; + ae_vector hasau; +} minfsqpsubsolver; +typedef struct +{ + ae_int_t n; + ae_int_t lccnt; + ae_int_t nnlc; + ae_bool usedensebfgs; + double inittrustrad; + ae_vector s; + sparsematrix scla; + ae_vector hasal; + ae_vector hasau; + ae_vector sclal; + ae_vector sclau; + ae_vector lcscales; + ae_vector lcsrcidx; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_vector hasnl; + ae_vector hasnu; + ae_vector rawnl; + ae_vector rawnu; + ae_vector scalednl; + ae_vector scalednu; + ae_vector fscaleszzz; + ae_vector invfscales; + double sqpbigscale; + double sqpsmallscale; + nlpstoppingcriteria criteria; + ae_int_t bfgsresetfreq; + ae_int_t additsforctol; + double ctol; + ae_vector x; + ae_vector fi; + sparsematrix sj; + double f; + ae_bool needfisj; + ae_bool xupdated; + ae_bool werepointsbelowctol; + double trustrad; + double trustradgrowth; + ae_int_t trustradstagnationcnt; + ae_int_t fstagnationcnt; + varsfuncjac stepk; + ae_vector x0; + ae_vector xprev; + minfsqpsubsolver subsolver; + xbfgshessian hess; + ae_vector lagbcmult; + ae_vector lagxcmult; + varsfuncjac cand; + varsfuncjac probe; + ae_vector dtrial; + ae_vector d0; + ae_vector dmu; + nlpfilter filter; + ae_vector replagbc; + ae_vector replaglc; + ae_vector replagnlc; + ae_vector varscales; + ae_vector tmppend; + ae_vector tmphd; + ae_vector dummylagbcmult; + ae_vector dummylagxcmult; + ae_vector tmplaggrad; + ae_vector tmpcandlaggrad; + ae_vector tmphdiag; + ae_vector sclagtmp0; + ae_vector sclagtmp1; + ae_vector mftmp0; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + double repsclerr; + stimer timertotal; + stimer timerqpgen; + stimer timeripminit; + stimer timeripmsolve; + stimer timercallback; + rcommstate rstate; +} minfsqpstate; +#endif +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double stpmax; + ae_int_t modelage; + ae_int_t maxmodelage; + double epsx; + ae_vector x; + double f; + ae_vector fi; + ae_bool needf; + ae_bool needfi; + double fbase; + ae_vector modeldiag; + ae_vector xbase; + ae_vector fibase; + ae_vector bndl; + ae_vector bndu; + ae_vector havebndl; + ae_vector havebndu; + ae_vector s; + rcommstate rstate; + ae_vector xdir; + ae_vector choleskybuf; + ae_vector tmp0; + ae_vector tmpct; + double actualdecrease; + double predicteddecrease; + minqpstate qpstate; + minqpreport qprep; + sparsematrix tmpsp; +} minlmstepfinder; +typedef struct +{ + ae_int_t protocolversion; + ae_int_t n; + ae_int_t m; + double diffstep; + double epsx; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + ae_int_t maxmodelage; + ae_bool makeadditers; + ae_int_t nonmonotoniccnt; + ae_int_t formulatype; + ae_bool userterminationneeded; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_matrix h; + ae_vector g; + ae_bool needf; + ae_bool needfg; + ae_bool needfgh; + ae_bool needfij; + ae_bool needfi; + ae_bool xupdated; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_int_t algomode; + ae_vector xbase; + double fbase; + ae_vector fibase; + ae_vector gbase; + ae_matrix quadraticmodel; + ae_vector bndl; + ae_vector bndu; + ae_vector havebndl; + ae_vector havebndu; + ae_vector s; + ae_matrix cleic; + ae_int_t nec; + ae_int_t nic; + double lambdav; + double nu; + ae_int_t modelage; + ae_int_t nonmonotonicpos; + ae_vector nonmonotonicbuf; + ae_vector xnew; + ae_vector xdir; + ae_vector deltax; + ae_vector deltaf; + ae_bool deltaxready; + ae_bool deltafready; + smoothnessmonitor smonitor; + double teststep; + ae_vector lastscaleused; + ae_int_t fstagnationcnt; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_int_t repnfunc; + ae_int_t repnjac; + ae_int_t repngrad; + ae_int_t repnhess; + ae_int_t repncholesky; + ae_bool dotimers; + ae_int_t tstart; + ae_int_t tqp; + rcommstate rstate; + ae_vector choleskybuf; + ae_vector tmp0; + double actualdecrease; + double predicteddecrease; + double xm1; + double xp1; + ae_vector fm1; + ae_vector fp1; + ae_vector fc1; + ae_vector gm1; + ae_vector gp1; + ae_vector gc1; + minlbfgsstate internalstate; + minlbfgsreport internalrep; + minqpstate qpstate; + minqpreport qprep; + minlmstepfinder finderstate; +} minlmstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t terminationtype; + double f; + ae_int_t nfunc; + ae_int_t njac; + ae_int_t ngrad; + ae_int_t nhess; + ae_int_t ncholesky; +} minlmreport; +#endif +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t refreshfreq; + ae_int_t modelage; + spcholanalysis analysis; + sparsematrix augsys; + ae_int_t naug; + ae_matrix s; + ae_matrix y; + ae_int_t updcnt; + ae_matrix tmpcorrc; + ae_vector tmpcorrd; + ae_vector tmpdiag; + ae_vector priorities; + ae_vector dx; + ae_matrix dummys; + ae_matrix dummyy; + ae_vector alphak; + ae_vector rhok; +} minaulpreconditioner; +typedef struct +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_vector s; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_vector finitebndl; + ae_vector finitebndu; + sparsematrix sparsea; + ae_vector al; + ae_vector au; + ae_vector hasal; + ae_vector hasau; + ae_vector rawnl; + ae_vector rawnu; + ae_vector hasnl; + ae_vector hasnu; + ae_vector lcsrcidx; + nlpstoppingcriteria criteria; + ae_int_t maxouterits; + ae_int_t restartfreq; + ae_vector x; + ae_vector fi; + sparsematrix sj; + double f; + ae_bool needsj; + ae_bool precrefreshupcoming; + ae_bool xupdated; + double rho; + varsfuncjac xvirt; + varsfuncjac xvirtprev; + varsfuncjac xvirtbest; + varsfuncjac xtrue; + varsfuncjac xtrueprev; + varsfuncjac xtruebest; + double besterr; + ae_int_t bestiteridx; + ae_int_t besterrnegligibleupdates; + ae_vector lagmultbc2; + ae_vector lagmultxc2; + ae_vector x0; + ae_vector d; + ae_vector du; + ae_vector fscales; + ae_vector tracegamma; + minaulpreconditioner preconditioner; + xbfgshessian hessaug; + xbfgshessian hesstgt; + ae_vector laggrad0; + ae_vector laggradcur; + ae_vector modtgtgrad0; + ae_vector modtgtgrad1; + ae_int_t inneriterationscount; + ae_int_t outeriterationscount; + ae_int_t fstagnationcnt; + double longeststp; + ae_int_t mcstage; + linminstate lstate; + double stp; + double stplimit; + ae_vector ascales; + ae_vector tmpzero; + ae_vector tmpy; + ae_matrix dummy2; + ae_vector tmpretrdelta; + ae_vector tmpg; + varsfuncjac xvirtprobe; + varsfuncjac xtrueprobe; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_int_t repnfev; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + ae_int_t nfev; + ae_vector work; + rcommstate rstate; +} minaulstate; +#endif +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + double epsg; + double epsf; + double epsx; + ae_int_t maxits; + double stpmax; + double suggestedstep; + ae_bool xrep; + ae_bool drep; + ae_int_t cgtype; + ae_int_t prectype; + ae_vector diagh; + ae_vector diaghl2; + ae_matrix vcorr; + ae_int_t vcnt; + ae_vector s; + double diffstep; + ae_int_t nfev; + ae_int_t mcstage; + ae_int_t k; + ae_vector xk; + ae_vector dk; + ae_vector xn; + ae_vector dn; + ae_vector d; + double fold; + double stp; + double curstpmax; + ae_vector yk; + double lastgoodstep; + double lastscaledstep; + ae_int_t mcinfo; + ae_bool innerresetneeded; + ae_bool terminationneeded; + double trimthreshold; + ae_vector xbase; + ae_int_t rstimer; + ae_int_t protocolversion; + ae_vector x; + double f; + ae_vector g; + ae_bool needf; + ae_bool needfg; + ae_bool xupdated; + ae_bool algpowerup; + ae_bool lsstart; + ae_bool lsend; + ae_bool userterminationneeded; + rcommstate rstate; + ae_int_t repiterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + ae_int_t debugrestartscount; + linminstate lstate; + double fbase; + double fm2; + double fm1; + double fp1; + double fp2; + double betahs; + double betady; + ae_vector work0; + ae_vector work1; + ae_vector invs; + double teststep; + ae_int_t smoothnessguardlevel; + smoothnessmonitor smonitor; + ae_vector lastscaleused; +} mincgstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t terminationtype; +} mincgreport; +#endif +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector deltas; + ae_matrix jac; + ae_vector g; + ae_matrix q; +} df2psmodel; +typedef struct +{ + ae_matrix w; + ae_matrix invw; + ae_matrix jac; + ae_vector g; + ae_matrix q; + ae_vector tmp0; + ae_matrix tmprhs; +} dfolsamodel; +typedef struct +{ + ae_int_t ncenters; + double modelbase; + double modelscale; + ae_vector multscale; + ae_matrix centers; + ae_vector x0; + ae_matrix crbf; + ae_matrix clinear; + minfsqpstate fsqpsolver; + ae_matrix currentcloud; + ae_int_t currentcloudsize; + ae_vector distfromcenter; + ae_vector distfromchosen; + ae_vector available; + ae_matrix curwrkset; + ae_int_t curwrksetsize; + ae_matrix residualdisplacements; + ae_matrix q; + ae_vector tmpcand; + ae_vector tmpdisp; + ae_vector tmpwinner; + ae_vector tmpbndl; + ae_vector tmpbndu; + ae_vector tmpx0; + ae_vector tmps; + double winnerrating; + sparsematrix cx; + ae_vector clx; + ae_vector cux; + nlpstoppingcriteria crit; + smoothnessmonitor smonitor; +} dforbfmodel; +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_bool isleastsquares; + ae_int_t modeltype; + double rad0; + ae_int_t nnoisyrestarts; + ae_vector x0; + ae_vector s; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_vector finitebndl; + ae_vector finitebndu; + sparsematrix c; + ae_vector cl; + ae_vector cu; + ae_vector nl; + ae_vector nu; + double epsx; + double epsf; + ae_int_t maxits; + ae_int_t maxfev; + double toosmalltrustrad; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_vector querydata; + ae_vector replyfi; + rcommstate rstate; + rcommstate rstateimprove; + rcommstate rstateupdate; + ae_bool dotrace; + ae_vector trustregion; + ae_vector invtrustregion; + double trustradfactor; + double trustradbnd; + ae_vector xp; + ae_vector fpvec; + double fp; + double hp; + ae_vector xk; + ae_vector sk; + ae_vector xn; + ae_vector fkvec; + ae_vector fnvec; + double fk; + double hk; + ae_matrix wrkset; + ae_int_t wrksetsize; + hqrndstate rs; + df2psmodel tpsmodel; + dfolsamodel lsamodel; + dforbfmodel rbfmodel; + ae_bool infinitiesencountered; + ae_bool recoveredfrominfinities; + nlpfilter filter; + ae_bool savepointstocloud; + ae_matrix clouddata; + ae_int_t cloudsize; + ae_matrix cloudpending; + ae_int_t cloudpendingcnt; + ae_int_t successhistorylen; + ae_int_t successhistorymax; + ae_int_t successhistorynext; + ae_vector successhistory; + ae_int_t restartstoperform; + double lasttrustrad; + ae_matrix lastjac; + ae_vector trustradhistory; + ae_vector jacdiffhistory; + ae_vector iteridxhistory; + ae_int_t historylen; + ae_int_t historynext; + ae_vector tmpi; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmpdeltas; + vipmstate ipmsolver; + ae_matrix densedummy; + sparsematrix sparsedummy; + matinvreport invrep; + ae_int_t repterminationtype; + ae_int_t repiterationscount; + ae_int_t repnfev; + ae_int_t repsubsolverits; +} dfgmstate; +#endif +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + vipmstate ipmsolver; + ipm2state ipm2; + ae_vector curb; + ae_vector curbndl; + ae_vector curbndu; + ae_vector cural; + ae_vector curau; + sparsematrix sparserawlc; + sparsematrix sparseefflc; + ae_vector d0; + ae_matrix denseh; + ae_vector dummy1; + ae_matrix densedummy; + sparsematrix sparsedummy; + ae_vector tmps; + ae_vector tmporigin; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector retainnegativebclm; + ae_vector retainpositivebclm; + ae_vector rescalelag; + ae_matrix tmpcorrc; + ae_vector tmpdiag; + ae_vector hessdiag; + ae_matrix hesscorrc; + ae_vector hesscorrd; + ae_int_t hessrank; + sparsematrix hesssparsediag; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector hasal; + ae_vector hasau; +} minsqpsubsolver; +typedef struct +{ + ae_int_t n; + ae_int_t nec; + ae_int_t nic; + ae_int_t nlec; + ae_int_t nlic; + ae_bool usedensebfgs; + ae_vector s; + ae_matrix scaledcleic; + ae_vector lcsrcidx; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector scaledbndl; + ae_vector scaledbndu; + nlpstoppingcriteria criteria; + ae_int_t bfgsresetfreq; + ae_vector x; + ae_vector fi; + ae_matrix j; + double f; + ae_bool needfij; + ae_bool xupdated; + double meritmu; + double trustrad; + double trustradgrowth; + ae_int_t trustradstagnationcnt; + ae_int_t fstagnationcnt; + varsfuncjac stepk; + ae_vector x0; + ae_vector xprev; + ae_vector fscales; + ae_vector tracegamma; + minsqpsubsolver subsolver; + xbfgshessian hess; + ae_obj_array nonmonotonicmem; + ae_int_t nonmonotoniccnt; + ae_vector lagbcmult; + ae_vector lagxcmult; + varsfuncjac cand; + varsfuncjac corr; + varsfuncjac probe; + varsfuncjac currentlinearization; + ae_vector dtrial; + ae_vector d0; + ae_vector d1; + ae_vector dmu; + ae_vector tmppend; + ae_vector tmphd; + ae_vector dummylagbcmult; + ae_vector dummylagxcmult; + ae_vector tmplaggrad; + ae_vector tmpcandlaggrad; + ae_vector tmphdiag; + ae_vector sclagtmp0; + ae_vector sclagtmp1; + ae_vector mftmp0; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + stimer timertotal; + stimer timerqp; + stimer timercallback; + rcommstate rstate; +} minsqpstate; +#endif +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_vector x0; + ae_vector s; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector finitebndl; + ae_vector finitebndu; + ae_matrix densea; + ae_vector al; + ae_vector au; + ae_vector hasal; + ae_vector hasau; + ae_vector rawnl; + ae_vector rawnu; + ae_vector hasnl; + ae_vector hasnu; + ae_vector ascales; + ae_int_t maxits; + double rate0; + double rate1; + double momentum; + double blur0; + double blur1; + ae_int_t outerits; + double rho; + ae_vector x; + double f; + ae_vector fi; + ae_bool needfi; + ae_bool xupdated; + ae_vector avgsqj; + ae_vector fscales; + hqrndstate rs; + ae_vector xbest; + ae_vector fibest; + ae_vector xcur; + ae_vector gcur; + ae_vector dcur; + double currate; + double curblur; + double zcursecantstep; + ae_int_t repiterationscount; + ae_int_t repnfev; + rcommstate rstate; + ae_vector sqj; + ae_vector xleft; + ae_vector xright; + ae_vector fileft; + ae_vector firight; + ae_vector xoffs0; + ae_vector xoffs1; + ae_vector tmpzero; + sparsematrix dummysparsea; +} ssgdstate; +#endif +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t cnt; + ae_matrix x; + ae_matrix rawreplies; + ae_matrix fitness; + ae_matrix deparams; +} gdemopopulation; +typedef struct +{ + ae_int_t n; + ae_int_t m; + ae_int_t cntlc; + ae_int_t cntnlc; + ae_vector s; + ae_bool hasx0; + ae_vector x0; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector finitebndl; + ae_vector finitebndu; + ae_matrix densea; + ae_vector al; + ae_vector au; + ae_vector hasal; + ae_vector hasau; + ae_vector rawnl; + ae_vector rawnu; + ae_vector hasnl; + ae_vector hasnu; + ae_vector ascales; + ae_int_t popsize; + ae_int_t epochscnt; + ae_int_t constrmode; + double rho1; + double rho2; + double eps; + double nsample; + ae_int_t profile; + ae_bool fixedparams; + ae_int_t fixedstrategy; + double fixedcrossoverprob; + double fixeddifferentialweight; + ae_bool stoponsmallf; + double smallf; + double condfxepsf; + double condfxepsx; + double mucr; + double muf; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_vector querydata; + ae_vector replyfi; + rcommstate rstate; + hqrndstate rs; + gdemopopulation population; + gdemopopulation offspring; + ae_matrix xbest; + ae_vector fitbest; + ae_vector rawfbest; + ae_int_t repterminationtype; + ae_int_t repiterationscount; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + ae_vector tmpzero; + sparsematrix dummysparsea; + ae_vector goodbndl; + ae_vector goodbndu; + ae_vector empiricalbndl; + ae_vector empiricalbndu; +} gdemostate; +#endif +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t solvertype; + ae_int_t n; + ae_vector bndl; + ae_vector bndu; + ae_vector finitebndl; + ae_vector finitebndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_matrix densea; + ae_vector al; + ae_vector au; + ae_int_t m; + ae_vector nl; + ae_vector nu; + ae_int_t nnlc; + ae_vector s; + ae_bool hasx0; + ae_vector x0; + double condfxepsf; + double condfxepsx; + ae_bool stoponsmallf; + ae_bool dotimers; + double smallf; + ae_int_t rngseed; + ae_bool xrep; + ae_vector xf; + ae_int_t protocolversion; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_bool userterminationneeded; + ae_int_t gdemoprofile; + ae_int_t gdemoepochscnt; + ae_int_t gdemopopsize; + double gdemorho1; + double gdemorho2; + gdemostate gdemosolver; + ae_bool gdemofixedparams; + ae_int_t gdemostrategy; + double gdemocrossoverprob; + double gdemodifferentialweight; + ae_int_t ssgdmaxits; + double ssgdrate0; + double ssgdrate1; + double ssgdblur0; + double ssgdblur1; + ae_int_t ssgdouterits; + double ssgdmomentum; + double ssgdrho; + ssgdstate ssgdsolver; + rcommstate rstate; + double repf; + ae_int_t repterminationtype; + ae_int_t repiterationscount; + ae_int_t repnfunc; + ae_int_t repnrequests; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + double reptimetotal; + double reptimecallback; + stimer timertotal; + stimer timercallback; + ae_vector unscaled; + ae_vector combined; + ae_int_t batchsize; + ae_vector tmp0; +} mindfstate; +typedef struct +{ + double f; + ae_int_t iterationscount; + ae_int_t nfev; + double bcerr; + double lcerr; + double nlcerr; + ae_int_t terminationtype; + double timetotal; + double timesolver; + double timecallback; +} mindfreport; +#endif +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double pivottol; + double perturbmag; + ae_int_t maxtrfage; + ae_int_t trftype; + ae_int_t ratiotest; + ae_int_t pricing; + ae_int_t shifting; + double xtolabs; + double xtolrelabs; + double dtolabs; +} dualsimplexsettings; +typedef struct +{ + ae_int_t n; + ae_int_t k; + ae_vector idx; + ae_vector vals; + ae_vector dense; +} dssvector; +typedef struct +{ + ae_int_t ns; + ae_int_t m; + ae_vector idx; + ae_vector nidx; + ae_vector isbasic; + ae_int_t trftype; + ae_bool isvalidtrf; + ae_int_t trfage; + ae_matrix denselu; + sparsematrix sparsel; + sparsematrix sparseu; + sparsematrix sparseut; + ae_vector rowpermbwd; + ae_vector colpermbwd; + ae_vector densepfieta; + ae_vector densemu; + ae_vector rk; + ae_vector dk; + ae_vector dseweights; + ae_bool dsevalid; + double eminu; + ae_int_t statfact; + ae_int_t statupdt; + double statoffdiag; + ae_vector wtmp0; + ae_vector wtmp1; + ae_vector wtmp2; + ae_vector nrs; + ae_vector tcinvidx; + ae_matrix denselu2; + ae_vector densep2; + ae_vector densep2c; + sparsematrix sparselu1; + sparsematrix sparselu2; + sluv2buffer lubuf2; + ae_vector tmpi; + ae_vector utmp0; + ae_vector utmpi; + sparsematrix sparseludbg; +} dualsimplexbasis; +typedef struct +{ + ae_int_t ns; + ae_int_t m; + ae_vector rawc; + ae_vector bndl; + ae_vector bndu; + ae_vector bndt; + ae_vector xa; + ae_vector d; + ae_int_t state; + ae_vector xb; + ae_vector bndlb; + ae_vector bndub; + ae_vector bndtb; + ae_vector bndtollb; + ae_vector bndtolub; + ae_vector effc; +} dualsimplexsubproblem; +typedef struct +{ + ae_vector rowscales; + ae_vector rawbndl; + ae_vector rawbndu; + ae_int_t ns; + ae_int_t m; + sparsematrix a; + sparsematrix at; + dualsimplexbasis basis; + dualsimplexsubproblem primary; + dualsimplexsubproblem phase1; + dualsimplexsubproblem phase3; + ae_vector repx; + ae_vector replagbc; + ae_vector replaglc; + ae_vector repstats; + ae_int_t repterminationtype; + ae_int_t repiterationscount; + ae_int_t repiterationscount1; + ae_int_t repiterationscount2; + ae_int_t repiterationscount3; + ae_int_t repphase1time; + ae_int_t repphase2time; + ae_int_t repphase3time; + ae_int_t repdualpricingtime; + ae_int_t repdualbtrantime; + ae_int_t repdualpivotrowtime; + ae_int_t repdualratiotesttime; + ae_int_t repdualftrantime; + ae_int_t repdualupdatesteptime; + double repfillpivotrow; + ae_int_t repfillpivotrowcnt; + double repfillrhor; + ae_int_t repfillrhorcnt; + double repfilldensemu; + ae_int_t repfilldensemucnt; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_bool dotimers; + ae_vector btrantmp0; + ae_vector btrantmp1; + ae_vector btrantmp2; + ae_vector ftrantmp0; + ae_vector ftrantmp1; + ae_vector possibleflips; + ae_int_t possibleflipscnt; + ae_vector dfctmp0; + ae_vector dfctmp1; + ae_vector dfctmp2; + ae_vector ustmpi; + apbuffers xydsbuf; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + dssvector alphar; + dssvector rhor; + ae_vector tau; + ae_vector alphaq; + ae_vector alphaqim; + ae_vector eligiblealphar; + ae_vector harrisset; +} dualsimplexstate; +#endif +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t algokind; + double ipmlambda; + ae_vector s; + ae_vector c; + ae_vector bndl; + ae_vector bndu; + ae_int_t m; + sparsematrix a; + ae_vector al; + ae_vector au; + xquadraticconstraints dummyxqc; + xconicconstraints dummyxcc; + ae_vector xs; + ae_vector lagbc; + ae_vector laglc; + ae_vector cs; + double repf; + double repprimalerror; + double repdualerror; + double repslackerror; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_int_t repn; + ae_int_t repm; + double dsseps; + double ipmeps; + dualsimplexstate dss; + vipmstate ipm; + ipm2state ipm2; + ae_vector adddtmpi; + ae_vector adddtmpr; + ae_vector tmpax; + ae_vector tmpg; + presolveinfo presolver; + ae_vector zeroorigin; + ae_vector units; + sparsematrix ipmquadratic; + ae_vector dummylagqc; +} minlpstate; +typedef struct +{ + double f; + ae_vector lagbc; + ae_vector laglc; + ae_vector y; + ae_vector stats; + double primalerror; + double dualerror; + double slackerror; + ae_int_t iterationscount; + ae_int_t terminationtype; +} minlpreport; +#endif +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t protocolversion; + ae_int_t n; + ae_int_t m; + ae_int_t problemtype; + ae_int_t algorithm; + double diffstep; + nlpstoppingcriteria criteria; + ae_bool xrep; + ae_vector s; + ae_vector x0; + double rad0; + ae_int_t maxfev; + ae_int_t nnoisyrestarts; + ae_int_t nnlc; + ae_int_t cntlc; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector bndl; + ae_vector bndu; + ae_vector idxraw2red; + ae_vector redbl; + ae_vector redbu; + ae_vector reds; + ae_vector redx0; + ae_bool userterminationneeded; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + rcommstate rstate; + dfgmstate dfgmsolver; + ae_bool dotrace; + ae_vector xc; + ae_int_t repnfunc; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + ae_int_t repnrequests; + ae_vector unscaled; + ae_vector combined; + ae_int_t batchsize; +} nlsstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t terminationtype; + ae_int_t nfunc; +} nlsreport; +#endif +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool hashardbc; + ae_bool hassoftbc; + ae_int_t np; + ae_int_t mflex; + ae_int_t meq; + ae_int_t mrlxeq; + ae_int_t m1; + ae_int_t mrlx1; + ae_vector xp; + ae_vector sxl; + ae_vector sxu; + ae_vector sxf; + ae_vector gl; + ae_vector gu; + ae_vector fi; + sparsematrix jac; +} gipm2vars; +typedef struct +{ + ae_bool hashardbc; + ae_bool hassoftbc; + ae_int_t np; + ae_int_t mflex; + ae_int_t meq; + ae_int_t mrlxeq; + ae_int_t m1; + ae_int_t mrlx1; + ae_vector zxl; + ae_vector zxu; + ae_vector zsxl; + ae_vector zsxu; + ae_vector zsxlcap; + ae_vector zsxucap; + ae_vector zcf; + ae_vector zgl; + ae_vector zgu; + ae_vector zcfgl; + ae_vector zcfgu; +} gipm2mult; +typedef struct +{ + ae_vector rp; + ae_vector rpsxl; + ae_vector rpsxu; + ae_vector rdxl; + ae_vector rdxu; + ae_vector rdsxl; + ae_vector rdsxu; + ae_vector rdsxlcap; + ae_vector rdsxucap; + ae_vector rpsxf; + ae_vector rpgl; + ae_vector rpgu; + ae_vector rdcf; + ae_vector rdcfgl; + ae_vector rdcfgu; + ae_vector rdgl; + ae_vector rdgu; +} gipm2rhs; +typedef struct +{ + ae_vector wx; + ae_vector wy; + ae_vector d0; + ae_vector d1; +} gipm2condensedsystem; +typedef struct +{ + ae_int_t np; + ae_int_t mflex; + ae_int_t meq; + ae_int_t mrlxeq; + ae_int_t m1; + ae_int_t mrlx1; + ae_bool hashardbc; + ae_bool hassoftbc; + ae_vector x0; + ae_vector hardbndl; + ae_vector hardbndu; + ae_vector softbcql; + ae_vector softbcqu; + ae_vector softbcmsxl; + ae_vector softbcmsxu; + ae_bool mudependent; + ae_bool isprimal; + ae_vector callerfscales; + ae_int_t multupdatedelay; + ae_vector finitebndl; + ae_vector finitebndu; + ae_vector safeguardbndlp; + ae_vector safeguardbndup; + ae_vector elp; + ae_vector eup; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector flexcl; + ae_vector flexcu; + ae_vector maskflexcl; + ae_vector maskflexcu; + ae_vector hasflexcl; + ae_vector hasflexcu; + double muepsfactor; + double mudecaylinear; + double mudecaypower; + double eps; + ae_int_t maxits; + ae_int_t maxcheckpointstagnationits; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_vector querydata; + ae_vector replyfi; + sparsematrix replysj; + ae_vector replysol; + ae_vector replyprod; + ae_vector replyv; + ae_bool replywasrescale; + ae_bool hasjac; + ae_bool factsuccess; + ae_bool dotrace; + ae_bool dotracelaconic; + gipm2vars current; + gipm2mult currentmult; + gipm2mult delayedmult; + ae_bool hasbest; + gipm2vars best; + ae_vector bestlagbc; + ae_vector bestlagnlc; + double besterr; + ae_int_t fstagnationcnt; + ae_int_t rhsstagnationcounter; + ae_int_t goodinnerits; + double currentmu; + double prevmu; + double mumin; + double curbigval; + double curbiggrowth; + double lambdav; + double lambdadecay; + ae_bool lambdafound; + ae_int_t subsequentfactfailures; + ae_bool firstouteriteration; + ae_bool infinitiesdetected; + ae_bool linesearchalwayssuccessful; + ae_bool failedtorecoverfrominfinities; + ae_bool unboundednesssuspected; + ae_int_t rejectedwithineps; + double lastprim; + double lastdual; + double lastcmpl; + ae_vector pxl; + ae_vector pxu; + ae_int_t inneriterationidx; + double hessiandecay; + ae_int_t nonmonotonicmemlen; + ae_int_t nonmonotonicpos; + ae_vector nonmonotonicmerit; + double nrmx0; + double absf0; + double dxpnrm; + gipm2vars cand; + gipm2vars delta; + gipm2vars corr; + gipm2mult deltamult; + gipm2mult corrmult; + gipm2condensedsystem condensed; + gipm2rhs rhs; + gipm2rhs tmprhs; + ae_vector tmphdxp; + ae_vector tmpjdxp; + ae_vector tmpjtdy; + ae_nxpool mnx1pool; + gipm2mult candmult; + gipm2rhs candrhs; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double repnlcerr; + ae_int_t repnlcidx; + double repsclerr; + rcommstate rstate; +} gipm2state; +#endif +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_bool isdense; + ae_bool isconvex; + ae_int_t n; + ae_int_t mlc; + ae_int_t mnlc; + ae_int_t mxx; + ae_vector s; + ae_vector scaledx0; + ae_bool hasbc; + ae_bool hasfixed; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_vector finitescaledbndl; + ae_vector finitescaledbndu; + ae_vector finiterawbndl; + ae_vector finiterawbndu; + ae_vector isfixed; + ae_vector nonfixedmask; + ae_vector x; + ae_vector replyfi; + sparsematrix replysj; + double reportf; + ae_bool needfisj; + ae_bool xupdated; + xbfgshessian hess; + ae_vector laztx; + ae_vector laztfi; + sparsematrix laztsj; + double laztrawf0; + ae_vector basex; + ae_vector basefi; + sparsematrix basesj; + double baserawf0; + ae_vector prevbasex; + ae_vector prevbasefi; + sparsematrix prevbasesj; + double prevbaserawf0; + ae_vector bestx; + ae_vector bestfi; + sparsematrix bestsj; + double bestrawf0; + ae_int_t hessmemlen; + ae_vector basehsr1diag; + ae_vector basehsr1corrd; + ae_matrix basehsr1corrc; + ae_int_t basehrank; + ae_bool hasbaseh; + ae_bool haslast; + ae_bool hasbase; + ae_bool hasprevbase; + ae_bool hasbest; + ae_vector xproj; + ae_vector deltaproj; + ae_vector priorities; + spcholanalysis analysis; + sparsematrix sparsesys; + sparsematrix lastanalyzedjac; + ae_bool hassparsityanalyzed; + ae_bool factorized; + ae_vector fscales; + ae_vector invfscales; + double fbigscale; + double fsmallscale; + ae_bool firstscaling; + ae_vector autoscalerhessnorms; + gipm2state solver; + sparsematrix sparselc; + ae_vector lcbndl; + ae_vector lcbndu; + ae_vector lcsrcidx; + ae_vector lcscales; + ae_vector rawnl; + ae_vector rawnu; + ae_vector wrkccbndl; + ae_vector wrkccbndu; + double eps; + ae_int_t maxits; + ae_int_t repiterationscount; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + double repsclerr; + ae_vector xs; + ae_vector replagbc; + ae_vector replaglc; + ae_vector replagnlc; + ae_bool dotrace; + ae_bool dolaconictrace; + stimer timertotal; + stimer timerfactorize; + stimer timersolve; + stimer timercallback; + stimer timerreport; + stimer timeranalyze; + stimer timermv; + stimer timerrescale; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmp3; + ae_vector tmpb; + sparsematrix tmpsparse; + rcommstate rstate; +} nlpgipm2state; +#endif +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t nmain; + ae_int_t nslack; + double epsg; + double epsf; + double epsx; + ae_int_t maxits; + ae_bool xrep; + ae_bool drep; + double stpmax; + double diffstep; + sactiveset sas; + ae_vector s; + ae_int_t prectype; + ae_vector diagh; + ae_int_t protocolversion; + ae_vector x; + double f; + ae_vector g; + ae_bool needf; + ae_bool needfg; + ae_bool xupdated; + ae_bool lsstart; + ae_bool steepestdescentstep; + ae_bool boundedstep; + ae_bool userterminationneeded; + rcommstate rstate; + ae_vector ugc; + ae_vector cgc; + ae_vector xn; + ae_vector ugn; + ae_vector cgn; + ae_vector xp; + double fc; + double fn; + double fp; + ae_vector d; + ae_matrix cleic; + ae_int_t nec; + ae_int_t nic; + double lastgoodstep; + double lastscaledgoodstep; + double maxscaledgrad; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector bndl; + ae_vector bndu; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repvaridx; + ae_int_t repterminationtype; + double repdebugeqerr; + double repdebugfs; + double repdebugff; + double repdebugdx; + ae_int_t repdebugfeasqpits; + ae_int_t repdebugfeasgpaits; + ae_vector xstart; + snnlssolver solver; + double fbase; + double fm2; + double fm1; + double fp1; + double fp2; + double xm1; + double xp1; + double gm1; + double gp1; + ae_int_t cidx; + double cval; + ae_vector tmpprec; + ae_vector tmp0; + ae_int_t nfev; + ae_int_t mcstage; + double stp; + double curstpmax; + double activationstep; + ae_vector work; + linminstate lstate; + double trimthreshold; + ae_int_t nonmonotoniccnt; + ae_matrix bufyk; + ae_matrix bufsk; + ae_vector bufrho; + ae_vector buftheta; + ae_int_t bufsize; + double teststep; + ae_int_t smoothnessguardlevel; + smoothnessmonitor smonitor; + ae_vector lastscaleused; + ae_vector invs; +} minbleicstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t varidx; + ae_int_t terminationtype; + double debugeqerr; + double debugfs; + double debugff; + double debugdx; + ae_int_t debugfeasqpits; + ae_int_t debugfeasgpaits; + ae_int_t inneriterationscount; + ae_int_t outeriterationscount; +} minbleicreport; +#endif +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t solvertype; + ae_int_t n; + nlpstoppingcriteria criteria; + ae_int_t aulitscnt; + ae_bool xrep; + double stpmax; + double diffstep; + double teststep; + ae_int_t formulatype; + double orbitrad0; + ae_int_t orbitmaxnfev; + ae_int_t fsqpadditsforctol; + double fsqpctol; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_vector hasbndl; + ae_vector hasbndu; + xlinearconstraints xlc; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_int_t protocolversion; + ae_bool issuesparserequests; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needfij; + ae_bool needfi; + ae_bool xupdated; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + rcommstate rstate; + rcommstate rstateaul; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_matrix scaledcleic; + ae_vector xc; + ae_vector xstart; + ae_vector xbase; + ae_vector fbase; + ae_vector dfbase; + ae_vector fm2; + ae_vector fm1; + ae_vector fp1; + ae_vector fp2; + ae_vector batchquerydata; + ae_vector tmpspaf; + ae_vector tmpsptolj; + ae_smart_ptr _aulsolverstate; + minaulstate *aulsolverstate; + ae_bool userterminationneeded; + ae_smart_ptr _sqpsolverstate; + minsqpstate *sqpsolverstate; + ae_smart_ptr _fsqpsolverstate; + minfsqpstate *fsqpsolverstate; + ae_smart_ptr _orbitsolver; + dfgmstate *orbitsolver; + ae_int_t nreduced; + ae_vector idxraw2red; + ae_vector redx0; + ae_vector reds; + ae_vector redbl; + ae_vector redbu; + ae_smart_ptr _gipm2solver; + nlpgipm2state *gipm2solver; + ae_int_t smoothnessguardlevel; + smoothnessmonitor smonitor; + ae_vector lastscaleused; + double repf; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + double repsclfeaserr; + ae_int_t repdbgphase0its; + ae_vector replagbc; + ae_vector replagbcnz; + ae_vector replaglc; + ae_vector replagnlc; + ae_vector nlcidx; + ae_vector nlcmul; + ae_vector nlcadd; + ae_int_t nlcnlec; + ae_int_t nlcnlic; + ae_vector tmpi; +} minnlcstate; +typedef struct +{ + double f; + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t terminationtype; + double bcerr; + ae_int_t bcidx; + double lcerr; + ae_int_t lcidx; + double nlcerr; + ae_int_t nlcidx; + double sclfeaserr; + ae_vector lagbc; + ae_vector lagbcnz; + ae_vector laglc; + ae_vector lagnlc; + ae_int_t dbgphase0its; +} minnlcreport; +#endif +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double epsx; + ae_int_t maxits; + ae_bool xrep; + ae_vector xstart; + ae_int_t frontsize; + ae_bool polishsolutions; + ae_vector bndl; + ae_vector bndu; + ae_int_t ksparse; + ae_int_t kdense; + ae_matrix densec; + sparsematrix sparsec; + ae_vector cl; + ae_vector cu; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needfij; + ae_bool xupdated; + rcommstate rstate; + ae_bool userrequestedtermination; + ae_matrix repparetofront; + ae_int_t repfrontsize; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + minnlcstate nlcsolver; + minnlcreport nlcrep; + ae_vector tmpzero; + ae_vector tmpone; + ae_vector tmp0; + ae_matrix olddensec; + ae_vector olddensect; + ae_int_t olddensek; + ae_vector nlcidx; + ae_vector nlcmul; + ae_vector nlcadd; + ae_int_t nlcnlec; + ae_int_t nlcnlic; + ae_vector fideal; + ae_matrix payoff; + ae_vector beta; + ae_vector delta; + ae_vector subproblemstart; + hqrndstate rs; + ae_vector bndlx; + ae_vector bndux; + ae_matrix olddensecx; + ae_vector x1; + ae_vector x2; + ae_vector fix1; +} nbistate; +#endif +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double diffstep; + ae_int_t solvertype; + double epsx; + ae_int_t maxits; + ae_vector s; + ae_bool xrep; + ae_vector xstart; + ae_int_t frontsize; + ae_vector bndl; + ae_vector bndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_int_t msparse; + ae_int_t mdense; + ae_matrix densec; + sparsematrix sparsec; + ae_vector cl; + ae_vector cu; + ae_int_t nnlc; + ae_vector nl; + ae_vector nu; + ae_int_t protocolversion; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needfij; + ae_bool needfi; + ae_bool xupdated; + rcommstate rstate; + nbistate nbi; + ae_int_t repfrontsize; + ae_matrix repparetofront; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + double repbcerr; + ae_int_t repbcidx; + double replcerr; + ae_int_t replcidx; + double repnlcerr; + ae_int_t repnlcidx; + ae_vector dummyr1; + ae_matrix dummyr2; + sparsematrix dummysparse; + ae_vector xbase; + ae_vector fm2; + ae_vector fm1; + ae_vector fp1; + ae_vector fp2; +} minmostate; +typedef struct +{ + ae_int_t inneriterationscount; + ae_int_t outeriterationscount; + ae_int_t nfev; + ae_int_t terminationtype; + double bcerr; + ae_int_t bcidx; + double lcerr; + ae_int_t lcidx; + double nlcerr; + ae_int_t nlcidx; +} minmoreport; +#endif +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double fc; + double fn; + ae_vector xc; + ae_vector xn; + ae_vector x0; + ae_vector gc; + ae_vector d; + ae_matrix uh; + ae_matrix ch; + ae_matrix rk; + ae_vector invutc; + ae_vector tmp0; + ae_vector tmpidx; + ae_vector tmpd; + ae_vector tmpc; + ae_vector tmplambdas; + ae_matrix tmpc2; + ae_vector tmpb; + snnlssolver nnls; +} minnsqp; +typedef struct +{ + ae_int_t solvertype; + ae_int_t n; + double epsx; + ae_int_t maxits; + ae_bool xrep; + double diffstep; + ae_vector s; + ae_vector bndl; + ae_vector bndu; + ae_vector hasbndl; + ae_vector hasbndu; + ae_int_t nec; + ae_int_t nic; + ae_matrix cleic; + ae_int_t ng; + ae_int_t nh; + ae_int_t protocolversion; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needfij; + ae_bool needfi; + ae_bool xupdated; + rcommstate rstate; + rcommstate rstateags; + hqrndstate agsrs; + double agsradius; + ae_int_t agssamplesize; + double agsraddecay; + double agsalphadecay; + double agsdecrease; + double agsinitstp; + double agsstattold; + double agsshortstpabs; + double agsshortstprel; + double agsshortf; + ae_int_t agsshortlimit; + double agsrhononlinear; + ae_int_t agsminupdate; + ae_int_t agsmaxraddecays; + ae_int_t agsmaxbacktrack; + ae_int_t agsmaxbacktracknonfull; + double agspenaltylevel; + double agspenaltyincrease; + ae_vector xstart; + ae_vector xc; + ae_vector xn; + ae_vector rawg; + ae_vector meritg; + double rawf; + double meritf; + ae_vector d; + ae_vector colmax; + ae_vector diagh; + ae_vector signmin; + ae_vector signmax; + ae_bool userterminationneeded; + ae_vector scaledbndl; + ae_vector scaledbndu; + ae_matrix scaledcleic; + double rholinear; + ae_matrix samplex; + ae_matrix samplegm; + ae_matrix samplegmbc; + ae_vector samplef; + minnsqp nsqp; + ae_vector tmp0; + ae_vector tmp1; + ae_matrix tmp2; + ae_vector tmp3; + ae_vector xbase; + ae_vector fbase; + ae_vector fp; + ae_vector fm; + ae_vector xscaled; + ae_int_t repinneriterationscount; + ae_int_t repouteriterationscount; + ae_int_t repnfev; + ae_int_t repvaridx; + ae_int_t repfuncidx; + ae_int_t repterminationtype; + double replcerr; + double repnlcerr; + ae_int_t dbgncholesky; +} minnsstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + double cerr; + double lcerr; + double nlcerr; + ae_int_t terminationtype; + ae_int_t varidx; + ae_int_t funcidx; +} minnsreport; +#endif +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + double epsg; + double epsf; + double epsx; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + ae_int_t cgtype; + ae_int_t k; + ae_int_t nfev; + ae_int_t mcstage; + ae_vector bndl; + ae_vector bndu; + ae_int_t curalgo; + ae_int_t acount; + double mu; + double finit; + double dginit; + ae_vector ak; + ae_vector xk; + ae_vector dk; + ae_vector an; + ae_vector xn; + ae_vector dn; + ae_vector d; + double fold; + double stp; + ae_vector work; + ae_vector yk; + ae_vector gc; + double laststep; + ae_vector x; + double f; + ae_vector g; + ae_bool needfg; + ae_bool xupdated; + rcommstate rstate; + ae_int_t repiterationscount; + ae_int_t repnfev; + ae_int_t repterminationtype; + ae_int_t debugrestartscount; + linminstate lstate; + double betahs; + double betady; +} minasastate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t terminationtype; + ae_int_t activeconstraints; +} minasareport; +#endif +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t nmain; + double epsg; + double epsf; + double epsx; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + double diffstep; + ae_vector s; + ae_int_t prectype; + ae_vector diagh; + ae_int_t protocolversion; + ae_vector x; + double f; + ae_vector g; + ae_bool needf; + ae_bool needfg; + ae_bool xupdated; + ae_bool userterminationneeded; + rcommstate rstate; + ae_vector xc; + ae_vector ugc; + ae_vector cgc; + ae_vector xn; + ae_vector ugn; + ae_vector cgn; + ae_vector xp; + double fc; + double fn; + double fp; + ae_vector d; + double lastscaledgoodstep; + ae_vector hasbndl; + ae_vector hasbndu; + ae_vector bndl; + ae_vector bndu; + ae_int_t repiterationscount; + ae_int_t repnfev; + ae_int_t repvaridx; + ae_int_t repterminationtype; + ae_vector xstart; + double fbase; + double fm2; + double fm1; + double fp1; + double fp2; + double xm1; + double xp1; + double gm1; + double gp1; + ae_vector tmpprec; + ae_vector tmp0; + ae_int_t nfev; + ae_int_t mcstage; + double stp; + double curstpmax; + ae_vector work; + linminstate lstate; + double trimthreshold; + ae_int_t nonmonotoniccnt; + ae_matrix bufyk; + ae_matrix bufsk; + ae_vector bufrho; + ae_vector buftheta; + ae_int_t bufsize; + double teststep; + ae_int_t smoothnessguardlevel; + smoothnessmonitor smonitor; + ae_vector lastscaleused; + ae_vector invs; +} minbcstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfev; + ae_int_t varidx; + ae_int_t terminationtype; +} minbcreport; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) +class _optguardreport_owner; +class optguardreport; +class _optguardnonc0report_owner; +class optguardnonc0report; +class _optguardnonc1test0report_owner; +class optguardnonc1test0report; +class _optguardnonc1test1report_owner; +class optguardnonc1test1report; + + +/************************************************************************* +This structure is used to store OptGuard report, i.e. report on the +properties of the nonlinear function being optimized with ALGLIB. + +After you tell your optimizer to activate OptGuard this technology starts +to silently monitor function values and gradients/Jacobians being passed +all around during your optimization session. Depending on specific set of +checks enabled OptGuard may perform additional function evaluations (say, +about 3*N evaluations if you want to check analytic gradient for errors). + +Upon discovering that something strange happens (function values and/or +gradient components change too sharply and/or unexpectedly) OptGuard sets +one of the "suspicion flags" (without interrupting optimization session). +After optimization is done, you can examine OptGuard report. + +Following report fields can be set: +* nonc0suspected +* nonc1suspected +* badgradsuspected + + +=== WHAT CAN BE DETECTED WITH OptGuard INTEGRITY CHECKER ================= + +Following types of errors in your target function (constraints) can be +caught: +a) discontinuous functions ("non-C0" part of the report) +b) functions with discontinuous derivative ("non-C1" part of the report) +c) errors in the analytic gradient provided by user + +These types of errors result in optimizer stopping well before reaching +solution (most often - right after encountering discontinuity). + +Type A errors are usually coding errors during implementation of the +target function. Most "normal" problems involve continuous functions, and +anyway you can't reliably optimize discontinuous function. + +Type B errors are either coding errors or (in case code itself is correct) +evidence of the fact that your problem is an "incorrect" one. Most +optimizers (except for ones provided by MINNS subpackage) do not support +nonsmooth problems. + +Type C errors are coding errors which often prevent optimizer from making +even one step or result in optimizing stopping too early, as soon as +actual descent direction becomes too different from one suggested by user- +supplied gradient. + + +=== WHAT IS REPORTED ===================================================== + +Following set of report fields deals with discontinuous target functions, +ones not belonging to C0 continuity class: + +* nonc0suspected - is a flag which is set upon discovering some indication + of the discontinuity. If this flag is false, the rest of "non-C0" fields + should be ignored +* nonc0fidx - is an index of the function (0 for target function, 1 or + higher for nonlinear constraints) which is suspected of being "non-C0" +* nonc0lipshitzc - a Lipchitz constant for a function which was suspected + of being non-continuous. +* nonc0test0positive - set to indicate specific test which detected + continuity violation (test #0) + +Following set of report fields deals with discontinuous gradient/Jacobian, +i.e. with functions violating C1 continuity: + +* nonc1suspected - is a flag which is set upon discovering some indication + of the discontinuity. If this flag is false, the rest of "non-C1" fields + should be ignored +* nonc1fidx - is an index of the function (0 for target function, 1 or + higher for nonlinear constraints) which is suspected of being "non-C1" +* nonc1lipshitzc - a Lipchitz constant for a function gradient which was + suspected of being non-smooth. +* nonc1test0positive - set to indicate specific test which detected + continuity violation (test #0) +* nonc1test1positive - set to indicate specific test which detected + continuity violation (test #1) + +Following set of report fields deals with errors in the gradient: +* badgradsuspected - is a flad which is set upon discovering an error in + the analytic gradient supplied by user +* badgradfidx - index of the function with bad gradient (0 for target + function, 1 or higher for nonlinear constraints) +* badgradvidx - index of the variable +* badgradxbase - location where Jacobian is tested +* following matrices store user-supplied Jacobian and its numerical + differentiation version (which is assumed to be free from the coding + errors), both of them computed near the initial point: + * badgraduser, an array[K,N], analytic Jacobian supplied by user + * badgradnum, an array[K,N], numeric Jacobian computed by ALGLIB + Here K is a total number of nonlinear functions (target + nonlinear + constraints), N is a variable number. + The element of badgraduser[] with index [badgradfidx,badgradvidx] is + assumed to be wrong. + +More detailed error log can be obtained from optimizer by explicitly +requesting reports for tests C0.0, C1.0, C1.1. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +class _optguardreport_owner +{ +public: + _optguardreport_owner(); + _optguardreport_owner(alglib_impl::optguardreport *attach_to); + _optguardreport_owner(const _optguardreport_owner &rhs); + _optguardreport_owner& operator=(const _optguardreport_owner &rhs); + virtual ~_optguardreport_owner(); + alglib_impl::optguardreport* c_ptr(); + const alglib_impl::optguardreport* c_ptr() const; +protected: + alglib_impl::optguardreport *p_struct; + bool is_attached; +}; +class optguardreport : public _optguardreport_owner +{ +public: + optguardreport(); + optguardreport(alglib_impl::optguardreport *attach_to); + optguardreport(const optguardreport &rhs); + optguardreport& operator=(const optguardreport &rhs); + virtual ~optguardreport(); + ae_bool &nonc0suspected; + ae_bool &nonc0test0positive; + ae_int_t &nonc0fidx; + double &nonc0lipschitzc; + ae_bool &nonc1suspected; + ae_bool &nonc1test0positive; + ae_bool &nonc1test1positive; + ae_int_t &nonc1fidx; + double &nonc1lipschitzc; + ae_bool &badgradsuspected; + ae_int_t &badgradfidx; + ae_int_t &badgradvidx; + real_1d_array badgradxbase; + real_2d_array badgraduser; + real_2d_array badgradnum; + + +}; + + +/************************************************************************* +This structure is used for detailed reporting about suspected C0 +continuity violation. + +=== WHAT IS TESTED ======================================================= + +C0 test studies function values (not gradient!) obtained during line +searches and monitors estimate of the Lipschitz constant. Sudden spikes +usually indicate that discontinuity was detected. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the function value), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #0 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and f[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +class _optguardnonc0report_owner +{ +public: + _optguardnonc0report_owner(); + _optguardnonc0report_owner(alglib_impl::optguardnonc0report *attach_to); + _optguardnonc0report_owner(const _optguardnonc0report_owner &rhs); + _optguardnonc0report_owner& operator=(const _optguardnonc0report_owner &rhs); + virtual ~_optguardnonc0report_owner(); + alglib_impl::optguardnonc0report* c_ptr(); + const alglib_impl::optguardnonc0report* c_ptr() const; +protected: + alglib_impl::optguardnonc0report *p_struct; + bool is_attached; +}; +class optguardnonc0report : public _optguardnonc0report_owner +{ +public: + optguardnonc0report(); + optguardnonc0report(alglib_impl::optguardnonc0report *attach_to); + optguardnonc0report(const optguardnonc0report &rhs); + optguardnonc0report& operator=(const optguardnonc0report &rhs); + virtual ~optguardnonc0report(); + ae_bool &positive; + ae_int_t &fidx; + real_1d_array x0; + real_1d_array d; + ae_int_t &n; + real_1d_array stp; + real_1d_array f; + ae_int_t &cnt; + ae_int_t &stpidxa; + ae_int_t &stpidxb; + ae_int_t &inneriter; + ae_int_t &outeriter; + + +}; + + +/************************************************************************* +This structure is used for detailed reporting about suspected C1 +continuity violation as flagged by C1 test #0 (OptGuard has several tests +for C1 continuity, this report is used by #0). + +=== WHAT IS TESTED ======================================================= + +C1 test #0 studies function values (not gradient!) obtained during line +searches and monitors behavior of directional derivative estimate. This +test is less powerful than test #1, but it does not depend on gradient +values and thus it is more robust against artifacts introduced by +numerical differentiation. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the directional derivative), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #0 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and f[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +class _optguardnonc1test0report_owner +{ +public: + _optguardnonc1test0report_owner(); + _optguardnonc1test0report_owner(alglib_impl::optguardnonc1test0report *attach_to); + _optguardnonc1test0report_owner(const _optguardnonc1test0report_owner &rhs); + _optguardnonc1test0report_owner& operator=(const _optguardnonc1test0report_owner &rhs); + virtual ~_optguardnonc1test0report_owner(); + alglib_impl::optguardnonc1test0report* c_ptr(); + const alglib_impl::optguardnonc1test0report* c_ptr() const; +protected: + alglib_impl::optguardnonc1test0report *p_struct; + bool is_attached; +}; +class optguardnonc1test0report : public _optguardnonc1test0report_owner +{ +public: + optguardnonc1test0report(); + optguardnonc1test0report(alglib_impl::optguardnonc1test0report *attach_to); + optguardnonc1test0report(const optguardnonc1test0report &rhs); + optguardnonc1test0report& operator=(const optguardnonc1test0report &rhs); + virtual ~optguardnonc1test0report(); + ae_bool &positive; + ae_int_t &fidx; + real_1d_array x0; + real_1d_array d; + ae_int_t &n; + real_1d_array stp; + real_1d_array f; + ae_int_t &cnt; + ae_int_t &stpidxa; + ae_int_t &stpidxb; + ae_int_t &inneriter; + ae_int_t &outeriter; + + +}; + + +/************************************************************************* +This structure is used for detailed reporting about suspected C1 +continuity violation as flagged by C1 test #1 (OptGuard has several tests +for C1 continuity, this report is used by #1). + +=== WHAT IS TESTED ======================================================= + +C1 test #1 studies individual components of the gradient as recorded +during line searches. Upon discovering discontinuity in the gradient this +test records specific component which was suspected (or one with highest +indication of discontinuity if multiple components are suspected). + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + + +=== WHAT IS REPORTED ===================================================== + +Actually, report retrieval function returns TWO report structures: + +* one for most suspicious point found so far (one with highest change in + the directional derivative), so called "strongest" report +* another one for most detailed line search (more function evaluations = + easier to understand what's going on) which triggered test #1 criteria, + so called "longest" report + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. +* inneriter, outeriter - inner and outer iteration indexes (can be -1 if no + iteration information was specified) + +You can plot function values stored in stp[] and g[] arrays and study +behavior of your function by your own eyes, just to be sure that test +correctly reported C1 violation. + + -- ALGLIB -- + Copyright 19.11.2018 by Bochkanov Sergey +*************************************************************************/ +class _optguardnonc1test1report_owner +{ +public: + _optguardnonc1test1report_owner(); + _optguardnonc1test1report_owner(alglib_impl::optguardnonc1test1report *attach_to); + _optguardnonc1test1report_owner(const _optguardnonc1test1report_owner &rhs); + _optguardnonc1test1report_owner& operator=(const _optguardnonc1test1report_owner &rhs); + virtual ~_optguardnonc1test1report_owner(); + alglib_impl::optguardnonc1test1report* c_ptr(); + const alglib_impl::optguardnonc1test1report* c_ptr() const; +protected: + alglib_impl::optguardnonc1test1report *p_struct; + bool is_attached; +}; +class optguardnonc1test1report : public _optguardnonc1test1report_owner +{ +public: + optguardnonc1test1report(); + optguardnonc1test1report(alglib_impl::optguardnonc1test1report *attach_to); + optguardnonc1test1report(const optguardnonc1test1report &rhs); + optguardnonc1test1report& operator=(const optguardnonc1test1report &rhs); + virtual ~optguardnonc1test1report(); + ae_bool &positive; + ae_int_t &fidx; + ae_int_t &vidx; + real_1d_array x0; + real_1d_array d; + ae_int_t &n; + real_1d_array stp; + real_1d_array g; + ae_int_t &cnt; + ae_int_t &stpidxa; + ae_int_t &stpidxb; + ae_int_t &inneriter; + ae_int_t &outeriter; + + +}; +#endif + +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) +class _lptestproblem_owner; +class lptestproblem; + + +/************************************************************************* +This is a test problem class intended for internal performance tests. +Never use it directly in your projects. +*************************************************************************/ +class _lptestproblem_owner +{ +public: + _lptestproblem_owner(); + _lptestproblem_owner(alglib_impl::lptestproblem *attach_to); + _lptestproblem_owner(const _lptestproblem_owner &rhs); + _lptestproblem_owner& operator=(const _lptestproblem_owner &rhs); + virtual ~_lptestproblem_owner(); + alglib_impl::lptestproblem* c_ptr(); + const alglib_impl::lptestproblem* c_ptr() const; +protected: + alglib_impl::lptestproblem *p_struct; + bool is_attached; +}; +class lptestproblem : public _lptestproblem_owner +{ +public: + lptestproblem(); + lptestproblem(alglib_impl::lptestproblem *attach_to); + lptestproblem(const lptestproblem &rhs); + lptestproblem& operator=(const lptestproblem &rhs); + virtual ~lptestproblem(); + + +}; +#endif + +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +class _minlbfgsstate_owner; +class minlbfgsstate; +class _minlbfgsreport_owner; +class minlbfgsreport; + + +/************************************************************************* + +*************************************************************************/ +class _minlbfgsstate_owner +{ +public: + _minlbfgsstate_owner(); + _minlbfgsstate_owner(alglib_impl::minlbfgsstate *attach_to); + _minlbfgsstate_owner(const _minlbfgsstate_owner &rhs); + _minlbfgsstate_owner& operator=(const _minlbfgsstate_owner &rhs); + virtual ~_minlbfgsstate_owner(); + alglib_impl::minlbfgsstate* c_ptr(); + const alglib_impl::minlbfgsstate* c_ptr() const; +protected: + alglib_impl::minlbfgsstate *p_struct; + bool is_attached; +}; +class minlbfgsstate : public _minlbfgsstate_owner +{ +public: + minlbfgsstate(); + minlbfgsstate(alglib_impl::minlbfgsstate *attach_to); + minlbfgsstate(const minlbfgsstate &rhs); + minlbfgsstate& operator=(const minlbfgsstate &rhs); + virtual ~minlbfgsstate(); + + +}; + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minlbfgsrequesttermination(). + X contains point which was "current accepted" when termination + request was submitted. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +class _minlbfgsreport_owner +{ +public: + _minlbfgsreport_owner(); + _minlbfgsreport_owner(alglib_impl::minlbfgsreport *attach_to); + _minlbfgsreport_owner(const _minlbfgsreport_owner &rhs); + _minlbfgsreport_owner& operator=(const _minlbfgsreport_owner &rhs); + virtual ~_minlbfgsreport_owner(); + alglib_impl::minlbfgsreport* c_ptr(); + const alglib_impl::minlbfgsreport* c_ptr() const; +protected: + alglib_impl::minlbfgsreport *p_struct; + bool is_attached; +}; +class minlbfgsreport : public _minlbfgsreport_owner +{ +public: + minlbfgsreport(); + minlbfgsreport(alglib_impl::minlbfgsreport *attach_to); + minlbfgsreport(const minlbfgsreport &rhs); + minlbfgsreport& operator=(const minlbfgsreport &rhs); + virtual ~minlbfgsreport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) +class _minqpstate_owner; +class minqpstate; +class _minqpreport_owner; +class minqpreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinQP subpackage to work with this +object +*************************************************************************/ +class _minqpstate_owner +{ +public: + _minqpstate_owner(); + _minqpstate_owner(alglib_impl::minqpstate *attach_to); + _minqpstate_owner(const _minqpstate_owner &rhs); + _minqpstate_owner& operator=(const _minqpstate_owner &rhs); + virtual ~_minqpstate_owner(); + alglib_impl::minqpstate* c_ptr(); + const alglib_impl::minqpstate* c_ptr() const; +protected: + alglib_impl::minqpstate *p_struct; + bool is_attached; +}; +class minqpstate : public _minqpstate_owner +{ +public: + minqpstate(); + minqpstate(alglib_impl::minqpstate *attach_to); + minqpstate(const minqpstate &rhs); + minqpstate& operator=(const minqpstate &rhs); + virtual ~minqpstate(); + + +}; + + +/************************************************************************* +This structure stores optimization report: +* InnerIterationsCount number of inner iterations +* OuterIterationsCount number of outer iterations +* NCholesky number of Cholesky decomposition +* NMV number of matrix-vector products + (only products calculated as part of iterative + process are counted) +* TerminationType completion code (see below) +* F for positive terminationtype stores quadratic + model value at the solution +* LagBC Lagrange multipliers for box constraints, + array[N] +* LagLC Lagrange multipliers for linear constraints, + array[MSparse+MDense] +* LagQC Lagrange multipliers for quadratic constraints + +=== COMPLETION CODES ===================================================== + +Completion codes: +* -9 failure of the automatic scale evaluation: one of the diagonal + elements of the quadratic term is non-positive. Specify variable + scales manually! +* -5 inappropriate solver was used: + * QuickQP solver for a problem with general linear constraints (dense/sparse) + * QuickQP/DENSE-AUL/DENSE-IPM/SPARSE-IPM for a problem with + quadratic/conic constraints + * ECQP for a problem with inequality or nonlinear equality constraints +* -4 the problem is highly likely to be unbounded; either one of the solvers + found an unconstrained direction of negative curvature, or objective + simply decreased for too much (more than 1E50). +* -3 inconsistent constraints (or, maybe, feasible point is + too hard to find). If you are sure that constraints are feasible, + try to restart optimizer with better initial approximation. +* -2 IPM solver has difficulty finding primal/dual feasible point. + It is likely that the problem is either infeasible or unbounded, + but it is difficult to determine exact reason for termination. + X contains best point found so far. +* 1..4 successful completion +* 5 MaxIts steps was taken +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +=== LAGRANGE MULTIPLIERS ================================================= + +Some optimizers report values of Lagrange multipliers on successful +completion (positive completion code): +* dense and sparse IPM/GENIPM return very precise Lagrange multipliers as + determined during solution process. +* DENSE-AUL-QP returns approximate Lagrange multipliers (which are very + close to "true" Lagrange multipliers except for overconstrained or + degenerate problems) + +Three arrays of multipliers are returned: +* LagBC is array[N] which is loaded with multipliers from box constraints; + LagBC[i]>0 means that I-th constraint is at the upper bound, LagBC[I]<0 + means that I-th constraint is at the lower bound, LagBC[I]=0 means that + I-th box constraint is inactive. +* LagLC is array[MSparse+MDense] which is loaded with multipliers from + general linear constraints (former MSparse elements corresponds to + sparse part of the constraint matrix, latter MDense are for the dense + constraints, as was specified by user). + LagLC[i]>0 means that I-th constraint at the upper bound, LagLC[i]<0 + means that I-th constraint is at the lower bound, LagLC[i]=0 means that + I-th linear constraint is inactive. +* LagQC is array[MQC] which stores multipliers for quadratic constraints. + LagQC[i]>0 means that I-th constraint at the upper bound, LagQC[i]<0 + means that I-th constraint is at the lower bound, LagQC[i]=0 means that + I-th linear constraint is inactive. + +On failure (or when optimizer does not support Lagrange multipliers) these +arrays are zero-filled. + +It is expected that at solution the dual feasibility condition holds: + + C+H*(Xs-X0) + SUM(Ei*LagBC[i],i=0..n-1) + SUM(Ai*LagLC[i],i=0..m-1) + ... ~ 0 + +where +* C is a linear term +* H is a quadratic term +* Xs is a solution, and X0 is an origin term (zero by default) +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix + +NOTE: methods from IPM family may also return meaningful Lagrange + multipliers on completion with code -2 (infeasibility or + unboundedness detected). +*************************************************************************/ +class _minqpreport_owner +{ +public: + _minqpreport_owner(); + _minqpreport_owner(alglib_impl::minqpreport *attach_to); + _minqpreport_owner(const _minqpreport_owner &rhs); + _minqpreport_owner& operator=(const _minqpreport_owner &rhs); + virtual ~_minqpreport_owner(); + alglib_impl::minqpreport* c_ptr(); + const alglib_impl::minqpreport* c_ptr() const; +protected: + alglib_impl::minqpreport *p_struct; + bool is_attached; +}; +class minqpreport : public _minqpreport_owner +{ +public: + minqpreport(); + minqpreport(alglib_impl::minqpreport *attach_to); + minqpreport(const minqpreport &rhs); + minqpreport& operator=(const minqpreport &rhs); + virtual ~minqpreport(); + ae_int_t &inneriterationscount; + ae_int_t &outeriterationscount; + ae_int_t &nmv; + ae_int_t &ncholesky; + ae_int_t &terminationtype; + double &f; + real_1d_array lagbc; + real_1d_array laglc; + real_1d_array lagqc; + + +}; +#endif + +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +class _minlmstate_owner; +class minlmstate; +class _minlmreport_owner; +class minlmreport; + + +/************************************************************************* +Levenberg-Marquardt optimizer. + +This structure should be created using one of the MinLMCreate???() +functions. You should not access its fields directly; use ALGLIB functions +to work with it. +*************************************************************************/ +class _minlmstate_owner +{ +public: + _minlmstate_owner(); + _minlmstate_owner(alglib_impl::minlmstate *attach_to); + _minlmstate_owner(const _minlmstate_owner &rhs); + _minlmstate_owner& operator=(const _minlmstate_owner &rhs); + virtual ~_minlmstate_owner(); + alglib_impl::minlmstate* c_ptr(); + const alglib_impl::minlmstate* c_ptr() const; +protected: + alglib_impl::minlmstate *p_struct; + bool is_attached; +}; +class minlmstate : public _minlmstate_owner +{ +public: + minlmstate(); + minlmstate(alglib_impl::minlmstate *attach_to); + minlmstate(const minlmstate &rhs); + minlmstate& operator=(const minlmstate &rhs); + virtual ~minlmstate(); + + +}; + + +/************************************************************************* +Optimization report, filled by MinLMResults() function + +FIELDS: +* TerminationType, completetion code: + * -8 optimizer detected NAN/INF values either in the function itself, + or in its Jacobian + * -5 inappropriate solver was used: + * solver created with minlmcreatefgh() used on problem with + general linear constraints (set with minlmsetlc() call). + * -3 constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called MinLMRequestTermination(). + X contains point which was "current accepted" when termination + request was submitted. +* F, objective value, SUM(f[i]^2) +* IterationsCount, contains iterations count +* NFunc, number of function calculations +* NJac, number of Jacobi matrix calculations +* NGrad, number of gradient calculations +* NHess, number of Hessian calculations +* NCholesky, number of Cholesky decomposition calculations +*************************************************************************/ +class _minlmreport_owner +{ +public: + _minlmreport_owner(); + _minlmreport_owner(alglib_impl::minlmreport *attach_to); + _minlmreport_owner(const _minlmreport_owner &rhs); + _minlmreport_owner& operator=(const _minlmreport_owner &rhs); + virtual ~_minlmreport_owner(); + alglib_impl::minlmreport* c_ptr(); + const alglib_impl::minlmreport* c_ptr() const; +protected: + alglib_impl::minlmreport *p_struct; + bool is_attached; +}; +class minlmreport : public _minlmreport_owner +{ +public: + minlmreport(); + minlmreport(alglib_impl::minlmreport *attach_to); + minlmreport(const minlmreport &rhs); + minlmreport& operator=(const minlmreport &rhs); + virtual ~minlmreport(); + ae_int_t &iterationscount; + ae_int_t &terminationtype; + double &f; + ae_int_t &nfunc; + ae_int_t &njac; + ae_int_t &ngrad; + ae_int_t &nhess; + ae_int_t &ncholesky; + + +}; +#endif + +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +class _mincgstate_owner; +class mincgstate; +class _mincgreport_owner; +class mincgreport; + + +/************************************************************************* +This object stores state of the nonlinear CG optimizer. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _mincgstate_owner +{ +public: + _mincgstate_owner(); + _mincgstate_owner(alglib_impl::mincgstate *attach_to); + _mincgstate_owner(const _mincgstate_owner &rhs); + _mincgstate_owner& operator=(const _mincgstate_owner &rhs); + virtual ~_mincgstate_owner(); + alglib_impl::mincgstate* c_ptr(); + const alglib_impl::mincgstate* c_ptr() const; +protected: + alglib_impl::mincgstate *p_struct; + bool is_attached; +}; +class mincgstate : public _mincgstate_owner +{ +public: + mincgstate(); + mincgstate(alglib_impl::mincgstate *attach_to); + mincgstate(const mincgstate &rhs); + mincgstate& operator=(const mincgstate &rhs); + virtual ~mincgstate(); + ae_bool &needf; + ae_bool &needfg; + ae_bool &xupdated; + double &f; + real_1d_array g; + real_1d_array x; + + +}; + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called mincgrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +class _mincgreport_owner +{ +public: + _mincgreport_owner(); + _mincgreport_owner(alglib_impl::mincgreport *attach_to); + _mincgreport_owner(const _mincgreport_owner &rhs); + _mincgreport_owner& operator=(const _mincgreport_owner &rhs); + virtual ~_mincgreport_owner(); + alglib_impl::mincgreport* c_ptr(); + const alglib_impl::mincgreport* c_ptr() const; +protected: + alglib_impl::mincgreport *p_struct; + bool is_attached; +}; +class mincgreport : public _mincgreport_owner +{ +public: + mincgreport(); + mincgreport(alglib_impl::mincgreport *attach_to); + mincgreport(const mincgreport &rhs); + mincgreport& operator=(const mincgreport &rhs); + virtual ~mincgreport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +class _mindfstate_owner; +class mindfstate; +class _mindfreport_owner; +class mindfreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinDF subpackage to work with this +object +*************************************************************************/ +class _mindfstate_owner +{ +public: + _mindfstate_owner(); + _mindfstate_owner(alglib_impl::mindfstate *attach_to); + _mindfstate_owner(const _mindfstate_owner &rhs); + _mindfstate_owner& operator=(const _mindfstate_owner &rhs); + virtual ~_mindfstate_owner(); + alglib_impl::mindfstate* c_ptr(); + const alglib_impl::mindfstate* c_ptr() const; +protected: + alglib_impl::mindfstate *p_struct; + bool is_attached; +}; +class mindfstate : public _mindfstate_owner +{ +public: + mindfstate(); + mindfstate(alglib_impl::mindfstate *attach_to); + mindfstate(const mindfstate &rhs); + mindfstate& operator=(const mindfstate &rhs); + virtual ~mindfstate(); + + +}; + + +/************************************************************************* +This structure stores optimization report: +* f objective value at the solution +* iterationscount total number of inner iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) +* bcerr maximum violation of box constraints +* lcerr maximum violation of linear constraints +* nlcerr maximum violation of nonlinear constraints + +If timers were activated, the structure also stores running times: +* timesolver time (in seconds, stored as a floating-point + value) spent in the solver itself. Time spent + in the user callback is not included. + See 'TIMERS' below for more information. +* timecallback time (in seconds, stored as a floating-point + value) spent in the user callback. + See 'TIMERS' below for more information. +* timetotal total time spent during the optimization, + including both the solver and callbacks. + See 'TIMERS' below for more information. +In order to activate timers, the caller has to call mindfusetimers() +function. + +Other fields of this structure are not documented and should not be used! + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 box constraints are inconsistent + -1 inconsistent parameters were passed: + * penalty parameter is zero, but we have nonlinear constraints + set by mindfsetnlc2() + 1 function value has converged within epsf + 2 sampling radius decreased below epsx + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 User requested termination via mindfrequesttermination() + +TIMERS + +Starting from ALGLIB 4.04, many optimizers report time spent in in the +solver itself and in user callbacks. The time is reported in seconds, +using floating-point (i.e. fractional-length intervals can be reported). + +In order to activate timers, the caller has to call mindfusetimers() +function. + +The accuracy of the reported value depends on the specific programming +language and OS being used: +* C++, no AE_OS is #defined - the accuracy is that of time() function, i.e. + one second. +* C++, AE_OS=AE_WINDOWS is #defined - the accuracy is that of GetTickCount(), + i.e. about 10-20ms +* C++, AE_OS=AE_POSIX is #defined - the accuracy is that of gettimeofday() +* C#, managed core, any OS - the accuracy is that of Environment.TickCount +* C#, HPC core, any OS - the accuracy is that of a corresponding C++ version +* any other language - the accuracy is that of a corresponding C++ version + +Whilst modern operating systems provide more accurate timers, these timers +often have significant overhead or backward compatibility issues. Thus, +ALGLIB stick to the most basic and efficient functions, even at the cost +of some accuracy being lost. +*************************************************************************/ +class _mindfreport_owner +{ +public: + _mindfreport_owner(); + _mindfreport_owner(alglib_impl::mindfreport *attach_to); + _mindfreport_owner(const _mindfreport_owner &rhs); + _mindfreport_owner& operator=(const _mindfreport_owner &rhs); + virtual ~_mindfreport_owner(); + alglib_impl::mindfreport* c_ptr(); + const alglib_impl::mindfreport* c_ptr() const; +protected: + alglib_impl::mindfreport *p_struct; + bool is_attached; +}; +class mindfreport : public _mindfreport_owner +{ +public: + mindfreport(); + mindfreport(alglib_impl::mindfreport *attach_to); + mindfreport(const mindfreport &rhs); + mindfreport& operator=(const mindfreport &rhs); + virtual ~mindfreport(); + double &f; + ae_int_t &iterationscount; + ae_int_t &nfev; + double &bcerr; + double &lcerr; + double &nlcerr; + ae_int_t &terminationtype; + double &timetotal; + double ×olver; + double &timecallback; + + +}; +#endif + +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +class _minlpstate_owner; +class minlpstate; +class _minlpreport_owner; +class minlpreport; + + +/************************************************************************* +This object stores linear solver state. +You should use functions provided by MinLP subpackage to work with this +object +*************************************************************************/ +class _minlpstate_owner +{ +public: + _minlpstate_owner(); + _minlpstate_owner(alglib_impl::minlpstate *attach_to); + _minlpstate_owner(const _minlpstate_owner &rhs); + _minlpstate_owner& operator=(const _minlpstate_owner &rhs); + virtual ~_minlpstate_owner(); + alglib_impl::minlpstate* c_ptr(); + const alglib_impl::minlpstate* c_ptr() const; +protected: + alglib_impl::minlpstate *p_struct; + bool is_attached; +}; +class minlpstate : public _minlpstate_owner +{ +public: + minlpstate(); + minlpstate(alglib_impl::minlpstate *attach_to); + minlpstate(const minlpstate &rhs); + minlpstate& operator=(const minlpstate &rhs); + virtual ~minlpstate(); + + +}; + + +/************************************************************************* +This structure stores optimization report: +* f target function value +* lagbc Lagrange coefficients for box constraints +* laglc Lagrange coefficients for linear constraints +* y dual variables +* stats array[N+M], statuses of box (N) and linear (M) + constraints. This array is filled only by DSS + algorithm because IPM always stops at INTERIOR + point: + * stats[i]>0 => constraint at upper bound + (also used for free non-basic + variables set to zero) + * stats[i]<0 => constraint at lower bound + * stats[i]=0 => constraint is inactive, basic + variable +* primalerror primal feasibility error +* dualerror dual feasibility error +* slackerror complementary slackness error +* iterationscount iteration count +* terminationtype completion code (see below) + +COMPLETION CODES + +Completion codes: +* -4 LP problem is primal unbounded (dual infeasible) +* -3 LP problem is primal infeasible (dual unbounded) +* 1..4 successful completion +* 5 MaxIts steps was taken +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +LAGRANGE COEFFICIENTS + +Positive Lagrange coefficient means that constraint is at its upper bound. +Negative coefficient means that constraint is at its lower bound. It is +expected that at the solution the dual feasibility condition holds: + + C + SUM(Ei*LagBC[i],i=0..n-1) + SUM(Ai*LagLC[i],i=0..m-1) ~ 0 + +where +* C is a cost vector (linear term) +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix +*************************************************************************/ +class _minlpreport_owner +{ +public: + _minlpreport_owner(); + _minlpreport_owner(alglib_impl::minlpreport *attach_to); + _minlpreport_owner(const _minlpreport_owner &rhs); + _minlpreport_owner& operator=(const _minlpreport_owner &rhs); + virtual ~_minlpreport_owner(); + alglib_impl::minlpreport* c_ptr(); + const alglib_impl::minlpreport* c_ptr() const; +protected: + alglib_impl::minlpreport *p_struct; + bool is_attached; +}; +class minlpreport : public _minlpreport_owner +{ +public: + minlpreport(); + minlpreport(alglib_impl::minlpreport *attach_to); + minlpreport(const minlpreport &rhs); + minlpreport& operator=(const minlpreport &rhs); + virtual ~minlpreport(); + double &f; + real_1d_array lagbc; + real_1d_array laglc; + real_1d_array y; + integer_1d_array stats; + double &primalerror; + double &dualerror; + double &slackerror; + ae_int_t &iterationscount; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +class _nlsstate_owner; +class nlsstate; +class _nlsreport_owner; +class nlsreport; + + +/************************************************************************* +Nonlinear least squares solver +*************************************************************************/ +class _nlsstate_owner +{ +public: + _nlsstate_owner(); + _nlsstate_owner(alglib_impl::nlsstate *attach_to); + _nlsstate_owner(const _nlsstate_owner &rhs); + _nlsstate_owner& operator=(const _nlsstate_owner &rhs); + virtual ~_nlsstate_owner(); + alglib_impl::nlsstate* c_ptr(); + const alglib_impl::nlsstate* c_ptr() const; +protected: + alglib_impl::nlsstate *p_struct; + bool is_attached; +}; +class nlsstate : public _nlsstate_owner +{ +public: + nlsstate(); + nlsstate(alglib_impl::nlsstate *attach_to); + nlsstate(const nlsstate &rhs); + nlsstate& operator=(const nlsstate &rhs); + virtual ~nlsstate(); + + +}; + + +/************************************************************************* +Optimization report, filled by NLSResults() function + +FIELDS: +* TerminationType, completion code, which is a sum of a BASIC code and an +ADDITIONAL code. + + The following basic codes denote failure: + * -8 optimizer detected NAN/INF either in the function itself, + or its Jacobian; recovery was impossible, abnormal termination + reported. + * -3 box constraints are inconsistent + + The following basic codes denote success: + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called NLSRequestTermination(). + X contains point which was "current accepted" when termination + request was submitted. + + Additional codes can be set on success, but not on failure: + * +800 if during algorithm execution the solver encountered + NAN/INF values in the target or constraints but managed to + recover by reducing trust region radius, the solver returns + one of SUCCESS codes but adds +800 to the code. + +* IterationsCount, contains iterations count +* NFunc, number of function calculations +*************************************************************************/ +class _nlsreport_owner +{ +public: + _nlsreport_owner(); + _nlsreport_owner(alglib_impl::nlsreport *attach_to); + _nlsreport_owner(const _nlsreport_owner &rhs); + _nlsreport_owner& operator=(const _nlsreport_owner &rhs); + virtual ~_nlsreport_owner(); + alglib_impl::nlsreport* c_ptr(); + const alglib_impl::nlsreport* c_ptr() const; +protected: + alglib_impl::nlsreport *p_struct; + bool is_attached; +}; +class nlsreport : public _nlsreport_owner +{ +public: + nlsreport(); + nlsreport(alglib_impl::nlsreport *attach_to); + nlsreport(const nlsreport &rhs); + nlsreport& operator=(const nlsreport &rhs); + virtual ~nlsreport(); + ae_int_t &iterationscount; + ae_int_t &terminationtype; + ae_int_t &nfunc; + + +}; +#endif + +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +class _minbleicstate_owner; +class minbleicstate; +class _minbleicreport_owner; +class minbleicreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinBLEIC subpackage to work with this +object +*************************************************************************/ +class _minbleicstate_owner +{ +public: + _minbleicstate_owner(); + _minbleicstate_owner(alglib_impl::minbleicstate *attach_to); + _minbleicstate_owner(const _minbleicstate_owner &rhs); + _minbleicstate_owner& operator=(const _minbleicstate_owner &rhs); + virtual ~_minbleicstate_owner(); + alglib_impl::minbleicstate* c_ptr(); + const alglib_impl::minbleicstate* c_ptr() const; +protected: + alglib_impl::minbleicstate *p_struct; + bool is_attached; +}; +class minbleicstate : public _minbleicstate_owner +{ +public: + minbleicstate(); + minbleicstate(alglib_impl::minbleicstate *attach_to); + minbleicstate(const minbleicstate &rhs); + minbleicstate& operator=(const minbleicstate &rhs); + virtual ~minbleicstate(); + ae_bool &needf; + ae_bool &needfg; + ae_bool &xupdated; + double &f; + real_1d_array g; + real_1d_array x; + + +}; + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount number of iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 inconsistent constraints. Feasible point is + either nonexistent or too hard to find. Try to + restart optimizer with better initial approximation + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minbleicrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. + +ADDITIONAL FIELDS + +There are additional fields which can be used for debugging: +* DebugEqErr error in the equality constraints (2-norm) +* DebugFS f, calculated at projection of initial point + to the feasible set +* DebugFF f, calculated at the final point +* DebugDX |X_start-X_final| +*************************************************************************/ +class _minbleicreport_owner +{ +public: + _minbleicreport_owner(); + _minbleicreport_owner(alglib_impl::minbleicreport *attach_to); + _minbleicreport_owner(const _minbleicreport_owner &rhs); + _minbleicreport_owner& operator=(const _minbleicreport_owner &rhs); + virtual ~_minbleicreport_owner(); + alglib_impl::minbleicreport* c_ptr(); + const alglib_impl::minbleicreport* c_ptr() const; +protected: + alglib_impl::minbleicreport *p_struct; + bool is_attached; +}; +class minbleicreport : public _minbleicreport_owner +{ +public: + minbleicreport(); + minbleicreport(alglib_impl::minbleicreport *attach_to); + minbleicreport(const minbleicreport &rhs); + minbleicreport& operator=(const minbleicreport &rhs); + virtual ~minbleicreport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &varidx; + ae_int_t &terminationtype; + double &debugeqerr; + double &debugfs; + double &debugff; + double &debugdx; + ae_int_t &debugfeasqpits; + ae_int_t &debugfeasgpaits; + ae_int_t &inneriterationscount; + ae_int_t &outeriterationscount; + + +}; +#endif + +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +class _minnlcstate_owner; +class minnlcstate; +class _minnlcreport_owner; +class minnlcreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinNLC subpackage to work with this +object +*************************************************************************/ +class _minnlcstate_owner +{ +public: + _minnlcstate_owner(); + _minnlcstate_owner(alglib_impl::minnlcstate *attach_to); + _minnlcstate_owner(const _minnlcstate_owner &rhs); + _minnlcstate_owner& operator=(const _minnlcstate_owner &rhs); + virtual ~_minnlcstate_owner(); + alglib_impl::minnlcstate* c_ptr(); + const alglib_impl::minnlcstate* c_ptr() const; +protected: + alglib_impl::minnlcstate *p_struct; + bool is_attached; +}; +class minnlcstate : public _minnlcstate_owner +{ +public: + minnlcstate(); + minnlcstate(alglib_impl::minnlcstate *attach_to); + minnlcstate(const minnlcstate &rhs); + minnlcstate& operator=(const minnlcstate &rhs); + virtual ~minnlcstate(); + + +}; + + +/************************************************************************* +These fields store optimization report: +* f objective value at the solution +* iterationscount total number of inner iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +Scaled constraint violations are reported: +* bcerr maximum violation of the box constraints +* bcidx index of the most violated box constraint (or + -1, if all box constraints are satisfied or + there is no box constraint) +* lcerr maximum violation of the linear constraints, + computed as maximum scaled distance between + final point and constraint boundary. +* lcidx index of the most violated linear constraint + (or -1, if all constraints are satisfied or + there is no general linear constraints) +* nlcerr maximum violation of the nonlinear constraints +* nlcidx index of the most violated nonlinear constraint + (or -1, if all constraints are satisfied or + there is no nonlinear constraints) +* sclfeaserr maximum violation over all constraints, + computed with scaling/renormalization applied. + +Violations of box constraints are scaled on per-component basis according +to the scale vector s[] as specified by minnlcsetscale(). Violations of +the general linear constraints are also computed using user-supplied +variable scaling. Violations of nonlinear constraints are computed "as is" + +LAGRANGE COEFFICIENTS + +GIPM2 and modern SQP (one activated by setalgosqp()/setalgosqpbfgs(), but +not with legacy functions) set the following fields (other solvers fill +them by zeros): + +* lagbc[] array[N], Lagrange multipliers for box + constraints. IMPORTANT: COEFFICIENTS FOR FIXED + VARIABLES ARE SET TO ZERO. See below for an + explanation. + This parameter stores the same results + independently of whether analytic gradient is + provided or numerical differentiation is used. + +* lagbcnz[] array[N], Lagrange multipliers for box + constraints, behaves differently depending on + whether analytic gradient is provided or + numerical differentiation is used: + * for analytic Jacobian, lagbcnz[] contains + correct coefficients for all kinds of + variables - fixed or not. + * for numerical Jacobian, it is the same as + lagbc[], i.e. components corresponding to + fixed vars are zero. + See below for an explanation. + +* laglc[] array[Mlin], coeffs for linear constraints + +* lagnlc[] array[Mnlc], coeffs for nonlinear constraints + + +Positive Lagrange coefficient means that constraint is at its upper bound. +Negative coefficient means that constraint is at its lower bound. It is +expected that at the solution the dual feasibility condition holds: + + grad + SUM(Ei*LagBC[i],i=0..n-1) + + SUM(Ai*LagLC[i],i=0..mlin-1) + + SUM(Ni*LagNLC[i],i=0..mnlc-1) ~ 0 + + (except for fixed variables which are handled specially) + +where +* grad is a gradient at the solution +* Ei is a vector with 1.0 at position I and 0 in other positions +* Ai is an I-th row of linear constraint matrix +* Ni is an gradient of I-th nonlinear constraint + +Fixed variables have two sets of Lagrange multipliers for the following +reasons: +* analytic gradient and numerical gradient behave differently for fixed + vars. Numerical differentiation does not violate box constraints, thus + gradient components corresponding to fixed vars are zero because we have + no way of differentiating for these vars without violating box + constraints. + Contrary to that, analytic gradient usually returns correct values even + for fixed vars. +* ideally, we would like numerical gradient to be an almost perfect + replacement for an analytic one. Thus, we need Lagrange multipliers + which do not change when we change the gradient type. +* on the other hand, we do not want to lose the possibility of having + a full set of Lagrange multipliers for problems with analytic gradient. + Thus, there is a special field lagbcnz[] whose contents depends on the + information available to us. + +TERMINATION CODES + +TerminationType field contains completion code, which can be either FAILURE +code, SUCCESS code, or SUCCESS code + ADDITIONAL code. The latter option +is used for more detailed reporting. + +=== FAILURE CODE === + -8 internal integrity control detected infinite or NAN values in + function/gradient, recovery was impossible. Abnormal termination + signaled. + -3 box constraints are infeasible. Note: infeasibility of non-box + constraints does NOT trigger emergency completion; you have to + examine bcerr/lcerr/nlcerr to detect possibly inconsistent + constraints. + +=== SUCCESS CODE === + 1 small objective decrease indicates convergence + 2 Eps-based condition (depending on the solver): + * relative step is no more than Eps (for SQP and similar) + * primal/dual/complementarity errors are less than Eps (for GIPM2) + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 user requested algorithm termination via minnlcrequesttermination(), + last accepted point is returned + +=== ADDITIONAL CODES === +* +800 if during algorithm execution the solver encountered + NAN/INF values in the target or constraints but managed to + recover by reducing trust region radius, the solver returns + one of SUCCESS codes but adds +800 to the code. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +class _minnlcreport_owner +{ +public: + _minnlcreport_owner(); + _minnlcreport_owner(alglib_impl::minnlcreport *attach_to); + _minnlcreport_owner(const _minnlcreport_owner &rhs); + _minnlcreport_owner& operator=(const _minnlcreport_owner &rhs); + virtual ~_minnlcreport_owner(); + alglib_impl::minnlcreport* c_ptr(); + const alglib_impl::minnlcreport* c_ptr() const; +protected: + alglib_impl::minnlcreport *p_struct; + bool is_attached; +}; +class minnlcreport : public _minnlcreport_owner +{ +public: + minnlcreport(); + minnlcreport(alglib_impl::minnlcreport *attach_to); + minnlcreport(const minnlcreport &rhs); + minnlcreport& operator=(const minnlcreport &rhs); + virtual ~minnlcreport(); + double &f; + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + double &bcerr; + ae_int_t &bcidx; + double &lcerr; + ae_int_t &lcidx; + double &nlcerr; + ae_int_t &nlcidx; + double &sclfeaserr; + real_1d_array lagbc; + real_1d_array lagbcnz; + real_1d_array laglc; + real_1d_array lagnlc; + ae_int_t &dbgphase0its; + + +}; +#endif + +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +class _minmostate_owner; +class minmostate; +class _minmoreport_owner; +class minmoreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinMO subpackage to work with this +object +*************************************************************************/ +class _minmostate_owner +{ +public: + _minmostate_owner(); + _minmostate_owner(alglib_impl::minmostate *attach_to); + _minmostate_owner(const _minmostate_owner &rhs); + _minmostate_owner& operator=(const _minmostate_owner &rhs); + virtual ~_minmostate_owner(); + alglib_impl::minmostate* c_ptr(); + const alglib_impl::minmostate* c_ptr() const; +protected: + alglib_impl::minmostate *p_struct; + bool is_attached; +}; +class minmostate : public _minmostate_owner +{ +public: + minmostate(); + minmostate(alglib_impl::minmostate *attach_to); + minmostate(const minmostate &rhs); + minmostate& operator=(const minmostate &rhs); + virtual ~minmostate(); + ae_bool &needfi; + ae_bool &needfij; + ae_bool &xupdated; + double &f; + real_1d_array fi; + real_2d_array j; + real_1d_array x; + + +}; + + +/************************************************************************* +These fields store optimization report: +* inneriterationscount total number of inner iterations +* outeriterationscount number of internal optimization sessions performed +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +Scaled constraint violations (maximum over all Pareto points) are reported: +* bcerr maximum violation of the box constraints +* bcidx index of the most violated box constraint (or + -1, if all box constraints are satisfied or + there are no box constraint) +* lcerr maximum violation of the linear constraints, + computed as maximum scaled distance between + final point and constraint boundary. +* lcidx index of the most violated linear constraint + (or -1, if all constraints are satisfied or + there are no general linear constraints) +* nlcerr maximum violation of the nonlinear constraints +* nlcidx index of the most violated nonlinear constraint + (or -1, if all constraints are satisfied or + there are no nonlinear constraints) + +Violations of the box constraints are scaled on per-component basis +according to the scale vector s[] as specified by the minmosetscale(). +Violations of the general linear constraints are also computed using +user-supplied variable scaling. Violations of the nonlinear constraints +are computed "as is" + +TERMINATION CODES + +TerminationType field contains completion code, which can be either: + +=== FAILURE CODE === + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signaled. + -3 box constraints are infeasible. Note: infeasibility of non-box + constraints does NOT trigger emergency completion; you have to + examine bcerr/lcerr/nlcerr to detect possibly inconsistent + constraints. + +=== SUCCESS CODE === + 2 relative step is no more than EpsX. + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + +NOTE: The solver internally performs many optimization sessions: one for + each Pareto point, and some amount of preparatory optimizations. + Different optimization sessions may return different completion + codes. If at least one of internal optimizations failed, its failure + code is returned. If none of them failed, the most frequent code is + returned. + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +class _minmoreport_owner +{ +public: + _minmoreport_owner(); + _minmoreport_owner(alglib_impl::minmoreport *attach_to); + _minmoreport_owner(const _minmoreport_owner &rhs); + _minmoreport_owner& operator=(const _minmoreport_owner &rhs); + virtual ~_minmoreport_owner(); + alglib_impl::minmoreport* c_ptr(); + const alglib_impl::minmoreport* c_ptr() const; +protected: + alglib_impl::minmoreport *p_struct; + bool is_attached; +}; +class minmoreport : public _minmoreport_owner +{ +public: + minmoreport(); + minmoreport(alglib_impl::minmoreport *attach_to); + minmoreport(const minmoreport &rhs); + minmoreport& operator=(const minmoreport &rhs); + virtual ~minmoreport(); + ae_int_t &inneriterationscount; + ae_int_t &outeriterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + double &bcerr; + ae_int_t &bcidx; + double &lcerr; + ae_int_t &lcidx; + double &nlcerr; + ae_int_t &nlcidx; + + +}; +#endif + +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +class _minnsstate_owner; +class minnsstate; +class _minnsreport_owner; +class minnsreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinNS subpackage to work with this +object +*************************************************************************/ +class _minnsstate_owner +{ +public: + _minnsstate_owner(); + _minnsstate_owner(alglib_impl::minnsstate *attach_to); + _minnsstate_owner(const _minnsstate_owner &rhs); + _minnsstate_owner& operator=(const _minnsstate_owner &rhs); + virtual ~_minnsstate_owner(); + alglib_impl::minnsstate* c_ptr(); + const alglib_impl::minnsstate* c_ptr() const; +protected: + alglib_impl::minnsstate *p_struct; + bool is_attached; +}; +class minnsstate : public _minnsstate_owner +{ +public: + minnsstate(); + minnsstate(alglib_impl::minnsstate *attach_to); + minnsstate(const minnsstate &rhs); + minnsstate& operator=(const minnsstate &rhs); + virtual ~minnsstate(); + ae_bool &needfi; + ae_bool &needfij; + ae_bool &xupdated; + double &f; + real_1d_array fi; + real_2d_array j; + real_1d_array x; + + +}; + + +/************************************************************************* +This structure stores optimization report: +* IterationsCount total number of inner iterations +* NFEV number of gradient evaluations +* TerminationType termination type (see below) +* CErr maximum violation of all types of constraints +* LCErr maximum violation of linear constraints +* NLCErr maximum violation of nonlinear constraints + +TERMINATION CODES + +TerminationType field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 box constraints are inconsistent + -1 inconsistent parameters were passed: + * penalty parameter for minnssetalgoags() is zero, + but we have nonlinear constraints set by minnssetnlc() + 2 sampling radius decreased below epsx + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 User requested termination via MinNSRequestTermination() + +Other fields of this structure are not documented and should not be used! +*************************************************************************/ +class _minnsreport_owner +{ +public: + _minnsreport_owner(); + _minnsreport_owner(alglib_impl::minnsreport *attach_to); + _minnsreport_owner(const _minnsreport_owner &rhs); + _minnsreport_owner& operator=(const _minnsreport_owner &rhs); + virtual ~_minnsreport_owner(); + alglib_impl::minnsreport* c_ptr(); + const alglib_impl::minnsreport* c_ptr() const; +protected: + alglib_impl::minnsreport *p_struct; + bool is_attached; +}; +class minnsreport : public _minnsreport_owner +{ +public: + minnsreport(); + minnsreport(alglib_impl::minnsreport *attach_to); + minnsreport(const minnsreport &rhs); + minnsreport& operator=(const minnsreport &rhs); + virtual ~minnsreport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + double &cerr; + double &lcerr; + double &nlcerr; + ae_int_t &terminationtype; + ae_int_t &varidx; + ae_int_t &funcidx; + + +}; +#endif + +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +class _minasastate_owner; +class minasastate; +class _minasareport_owner; +class minasareport; + + +/************************************************************************* + +*************************************************************************/ +class _minasastate_owner +{ +public: + _minasastate_owner(); + _minasastate_owner(alglib_impl::minasastate *attach_to); + _minasastate_owner(const _minasastate_owner &rhs); + _minasastate_owner& operator=(const _minasastate_owner &rhs); + virtual ~_minasastate_owner(); + alglib_impl::minasastate* c_ptr(); + const alglib_impl::minasastate* c_ptr() const; +protected: + alglib_impl::minasastate *p_struct; + bool is_attached; +}; +class minasastate : public _minasastate_owner +{ +public: + minasastate(); + minasastate(alglib_impl::minasastate *attach_to); + minasastate(const minasastate &rhs); + minasastate& operator=(const minasastate &rhs); + virtual ~minasastate(); + ae_bool &needfg; + ae_bool &xupdated; + double &f; + real_1d_array g; + real_1d_array x; + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _minasareport_owner +{ +public: + _minasareport_owner(); + _minasareport_owner(alglib_impl::minasareport *attach_to); + _minasareport_owner(const _minasareport_owner &rhs); + _minasareport_owner& operator=(const _minasareport_owner &rhs); + virtual ~_minasareport_owner(); + alglib_impl::minasareport* c_ptr(); + const alglib_impl::minasareport* c_ptr() const; +protected: + alglib_impl::minasareport *p_struct; + bool is_attached; +}; +class minasareport : public _minasareport_owner +{ +public: + minasareport(); + minasareport(alglib_impl::minasareport *attach_to); + minasareport(const minasareport &rhs); + minasareport& operator=(const minasareport &rhs); + virtual ~minasareport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &terminationtype; + ae_int_t &activeconstraints; + + +}; +#endif + +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +class _minbcstate_owner; +class minbcstate; +class _minbcreport_owner; +class minbcreport; + + +/************************************************************************* +This object stores nonlinear optimizer state. +You should use functions provided by MinBC subpackage to work with this +object +*************************************************************************/ +class _minbcstate_owner +{ +public: + _minbcstate_owner(); + _minbcstate_owner(alglib_impl::minbcstate *attach_to); + _minbcstate_owner(const _minbcstate_owner &rhs); + _minbcstate_owner& operator=(const _minbcstate_owner &rhs); + virtual ~_minbcstate_owner(); + alglib_impl::minbcstate* c_ptr(); + const alglib_impl::minbcstate* c_ptr() const; +protected: + alglib_impl::minbcstate *p_struct; + bool is_attached; +}; +class minbcstate : public _minbcstate_owner +{ +public: + minbcstate(); + minbcstate(alglib_impl::minbcstate *attach_to); + minbcstate(const minbcstate &rhs); + minbcstate& operator=(const minbcstate &rhs); + virtual ~minbcstate(); + ae_bool &needf; + ae_bool &needfg; + ae_bool &xupdated; + double &f; + real_1d_array g; + real_1d_array x; + + +}; + + +/************************************************************************* +This structure stores optimization report: +* iterationscount number of iterations +* nfev number of gradient evaluations +* terminationtype termination type (see below) + +TERMINATION CODES + +terminationtype field contains completion code, which can be: + -8 internal integrity control detected infinite or NAN values in + function/gradient. Abnormal termination signalled. + -3 inconsistent constraints. + 1 relative function improvement is no more than EpsF. + 2 relative step is no more than EpsX. + 4 gradient norm is no more than EpsG + 5 MaxIts steps was taken + 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + 8 terminated by user who called minbcrequesttermination(). X contains + point which was "current accepted" when termination request was + submitted. +*************************************************************************/ +class _minbcreport_owner +{ +public: + _minbcreport_owner(); + _minbcreport_owner(alglib_impl::minbcreport *attach_to); + _minbcreport_owner(const _minbcreport_owner &rhs); + _minbcreport_owner& operator=(const _minbcreport_owner &rhs); + virtual ~_minbcreport_owner(); + alglib_impl::minbcreport* c_ptr(); + const alglib_impl::minbcreport* c_ptr() const; +protected: + alglib_impl::minbcreport *p_struct; + bool is_attached; +}; +class minbcreport : public _minbcreport_owner +{ +public: + minbcreport(); + minbcreport(alglib_impl::minbcreport *attach_to); + minbcreport(const minbcreport &rhs); + minbcreport& operator=(const minbcreport &rhs); + virtual ~minbcreport(); + ae_int_t &iterationscount; + ae_int_t &nfev; + ae_int_t &varidx; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function serializes data structure to string. + +Important properties of s_out: +* it contains alphanumeric characters, dots, underscores, minus signs +* these symbols are grouped into words, which are separated by spaces + and Windows-style (CR+LF) newlines +* although serializer uses spaces and CR+LF as separators, you can + replace any separator character by arbitrary combination of spaces, + tabs, Windows or Unix newlines. It allows flexible reformatting of + the string in case you want to include it into a text or XML file. + But you should not insert separators into the middle of the "words" + nor should you change the case of letters. +* s_out can be freely moved between 32-bit and 64-bit systems, little + and big endian machines, and so on. You can serialize structure on + 32-bit machine and unserialize it on 64-bit one (or vice versa), or + serialize it on SPARC and unserialize on x86. You can also + serialize it in C++ version of ALGLIB and unserialize it in C# one, + and vice versa. +*************************************************************************/ +void lptestproblemserialize(const lptestproblem &obj, std::string &s_out); + + +/************************************************************************* +This function serializes data structure to C++ stream. + +Data stream generated by this function is same as string representation +generated by string version of serializer - alphanumeric characters, +dots, underscores, minus signs, which are grouped into words separated by +spaces and CR+LF. + +We recommend you to read comments on string version of serializer to find +out more about serialization of AlGLIB objects. +*************************************************************************/ +void lptestproblemserialize(const lptestproblem &obj, std::ostream &s_out); + + +/************************************************************************* +This function unserializes data structure from string. +*************************************************************************/ +void lptestproblemunserialize(const std::string &s_in, lptestproblem &obj); + + +/************************************************************************* +This function unserializes data structure from stream. +*************************************************************************/ +void lptestproblemunserialize(const std::istream &s_in, lptestproblem &obj); + + +/************************************************************************* +Initialize test LP problem. + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemcreate(const ae_int_t n, const bool hasknowntarget, const double targetf, lptestproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +bool lptestproblemhasknowntarget(lptestproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +double lptestproblemgettargetf(lptestproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetn(lptestproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Query test problem info + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +ae_int_t lptestproblemgetm(lptestproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Set scale for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetscale(lptestproblem &p, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Set cost for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetcost(lptestproblem &p, const real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetbc(lptestproblem &p, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Set box constraints for test LP problem + +This function is intended for internal use by ALGLIB. + + -- ALGLIB -- + Copyright 20.07.2021 by Bochkanov Sergey +*************************************************************************/ +void lptestproblemsetlc2(lptestproblem &p, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns objective type: True for zero/linear/constant. + +Present version does not return False. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemisquadraticobjective(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get variables count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetn(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get linear constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmlc(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get quadratic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmqc(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get conic constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgetmcc(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get total constraints count + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t qpxproblemgettotalconstraints(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get initial point + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetinitialpoint(qpxproblem &p, real_1d_array &x0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get initial point presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasinitialpoint(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get scale + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetscale(qpxproblem &p, real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get scale presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasscale(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get origin + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetorigin(qpxproblem &p, real_1d_array &xorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get origin presence + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasorigin(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get linear term + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlinearterm(qpxproblem &p, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get quadratic term, returns zero matrix if no quadratic term is present + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetquadraticterm(qpxproblem &p, sparsematrix &q, bool &isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Returns False if no quadratic term was specified, or quadratic term is +numerically zero. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +bool qpxproblemhasquadraticterm(qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get box constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetbc(qpxproblem &p, real_1d_array &bndl, real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get linear constraints + + -- ALGLIB -- + Copyright 20.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetlc2(qpxproblem &p, sparsematrix &a, real_1d_array &al, real_1d_array &au, ae_int_t &m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Get IDX-th two-sided quadratic constraint, same format as minqpaddqc2(), +except for the fact that it always returns isUpper=False, even if the +original matrix was an upper triangular one. + +NOTE: this function is not optimized for big matrices. Whilst still having + O(max(N,Nonzeros)) running time, it may be somewhat slow due to + dynamic structures being used internally. + + + -- ALGLIB -- + Copyright 19.08.2024 by Bochkanov Sergey +*************************************************************************/ +void qpxproblemgetqc2i(qpxproblem &p, const ae_int_t idx, sparsematrix &q, bool &isupper, real_1d_array &b, double &cl, double &cu, bool &applyorigin, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LIMITED MEMORY BFGS METHOD FOR LARGE SCALE OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using a quasi- +Newton method (LBFGS scheme) which is optimized to use a minimum amount +of memory. +The subroutine generates the approximation of an inverse Hessian matrix by +using information about the last M steps of the algorithm (instead of N). +It lessens a required amount of memory from a value of order N^2 to a +value of order 2*N*M. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinLBFGSCreate() call +2. User tunes solver parameters with MinLBFGSSetCond() MinLBFGSSetStpMax() + and other functions +3. User calls MinLBFGSOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinLBFGSResults() to get solution +5. Optionally user may call MinLBFGSRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLBFGSRestartFrom() allows to reuse already initialized structure. + +INPUT PARAMETERS: + N - problem dimension. N>0 + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - initial solution approximation, array[0..N-1]. + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. you may tune stopping conditions with MinLBFGSSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLBFGSSetStpMax() function to bound algorithm's steps. However, + L-BFGS rarely needs such a tuning. + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlbfgsstate &state, const xparams _xparams = alglib::xdefault); +void minlbfgscreate(const ae_int_t m, const real_1d_array &x, minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +The subroutine is finite difference variant of MinLBFGSCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinLBFGSCreate() in order to get +more information about creation of LBFGS optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of corrections in the BFGS scheme of Hessian + approximation update. Recommended value: 3<=M<=7. The smaller + value causes worse convergence, the bigger will not cause a + considerably better convergence, but will cause a fall in the + performance. M<=N. + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +IMPORTANT: the LBFGS optimizer supports parallel parallel numerical + differentiation ('callback parallelism'). This feature, + which is present in commercial ALGLIB editions greatly + accelerates optimization with numerical differentiation of + an expensive target functions. + + Callback parallelism is usually beneficial when computing a + numerical gradient requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on minlbfgsoptimize() function for + more information. + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinLBFGSSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. LBFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgscreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state, const xparams _xparams = alglib::xdefault); +void minlbfgscreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for L-BFGS optimization algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLBFGSSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcond(minlbfgsstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLBFGSOptimize(). + + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetxrep(minlbfgsstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetstpmax(minlbfgsstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for LBFGS optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the LBFGS too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinLBFGSSetPrec...() +functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetscale(minlbfgsstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: default preconditioner (simple +scaling, same for all elements of X) is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdefault(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: Cholesky factorization of approximate +Hessian is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + P - triangular preconditioner, Cholesky factorization of + the approximate Hessian. array[0..N-1,0..N-1], + (if larger, only leading N elements are used). + IsUpper - whether upper or lower triangle of P is given + (other triangle is not referenced) + +After call to this function preconditioner is changed to P (P is copied +into the internal buffer). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: P should be nonsingular. Exception will be thrown otherwise. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetpreccholesky(minlbfgsstate &state, const real_2d_array &p, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecdiag(minlbfgsstate &state, const real_1d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinLBFGSSetScale() +call (before or after MinLBFGSSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetprecscale(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlbfgsiteration(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM: + +The LBFGS optimizer supports parallel numerical differentiation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates numerical differentiation of expensive +targets. + +Callback parallelism is usually beneficial computing a numerical gradient +requires more than several milliseconds. In this case the job of computing +individual gradient components can be split between multiple threads. Even +inexpensive targets can benefit from parallelism, if you have many +variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +CALLBACKS ACCEPTED + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinLBFGSCreate() for analytical gradient or MinLBFGSCreateF() + for numerical differentiation) you should choose appropriate variant of + MinLBFGSOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinLBFGSOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinLBFGSOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinLBFGSOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinLBFGSCreateF() | work FAIL + MinLBFGSCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinLBFGSOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinLBFGSCreateF() and + to pass gradient information to MinCGOptimize()) will lead to exception + being thrown. Either you did not pass gradient when it WAS needed or + you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey + + +*************************************************************************/ +void minlbfgsoptimize(minlbfgsstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minlbfgsoptimize(minlbfgsstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minlbfgsoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlbfgssetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardgradient(minlbfgsstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardsmoothness(minlbfgsstate &state, const ae_int_t level, const xparams _xparams = alglib::xdefault); +void minlbfgsoptguardsmoothness(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minlbfgsoptguardgradient() for gradient verification +* minlbfgsoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minlbfgsoptguardnonc1test0results() +* minlbfgsoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardresults(minlbfgsstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test0results(const minlbfgsstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsoptguardnonc1test1results(minlbfgsstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +L-BFGS algorithm results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -2 rounding errors prevent further improvement. + X contains best point found. + * -1 incorrect parameters were specified + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlbfgsrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresults(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +L-BFGS algorithm results + +Buffered implementation of MinLBFGSResults which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsresultsbuf(const minlbfgsstate &state, real_1d_array &x, minlbfgsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts LBFGS algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrestartfrom(minlbfgsstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlbfgsrequesttermination(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + CONSTRAINED QUADRATIC PROGRAMMING + +The subroutine creates QP optimizer. After initial creation, it contains +default optimization problem with zero quadratic and linear terms and no +constraints. + +In order to actually solve something you should: + +specify objective: +* set linear term with minqpsetlinearterm() +* set quadratic term with minqpsetquadraticterm() or + minqpsetquadratictermsparse() + +specify constraints: +* set variable bounds with minqpsetbc() or minqpsetbcall() +* specify linear constraint matrix with one of the following functions: + * modern API: + * minqpsetlc2() for sparse two-sided constraints AL <= A*x <= AU + * minqpsetlc2dense() for dense two-sided constraints AL <= A*x <= AU + * minqpsetlc2mixed() for mixed two-sided constraints AL <= A*x <= AU + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + * legacy API: + * minqpsetlc() for dense one-sided equality/inequality constraints + * minqpsetlcsparse() for sparse one-sided equality/inequality constraints + * minqpsetlcmixed() for mixed dense/sparse one-sided equality/inequality constraints +* add two-sided quadratic constraint(s) of the form CL <= b'x+0.5*x'Qx <= CU + with one of the following functions: + * minqpaddqc2() for a quadratic constraint given by a sparse + matrix structure; has O(max(N,NNZ)) memory and + running time requirements. + * minqpaddqc2dense() for a quadratic constraint given by a dense + matrix; has O(N^2) memory and running time requirements. + * minqpaddqc2list() for a sparse quadratic constraint given by + a list of non-zero entries; has O(NNZ) memory + and O(NNZ*logNNZ) running time requirements, + ideal for constraints with much less than N + nonzero elements. +* add second order cone constraints with: + * minqpaddsoccprimitive() for a primitive second order cone constraint + * minqpaddsoccorthogonal() for an axis-orthogonal second order cone constraint +* add power cone constraints with: + * minqpaddpowccprimitive() for a primitive power cone constraint + * minqpaddpowccorthogonal() for an axis-orthogonal power cone constraint + +configure and run QP solver: +* choose appropriate QP solver and set it and its stopping criteria by + means of minqpsetalgo??????() function +* call minqpoptimize() to run the solver and minqpresults() to get the + solution vector and additional information. + +Following solvers are recommended for convex and semidefinite problems +with box and linear constraints: +* QuickQP for small dense problems with box-only constraints (or no + constraints at all) +* DENSE-IPM-QP for convex or semidefinite problems with medium (up + to several thousands) variable count, dense/sparse quadratic term and + any number (up to many thousands) of dense/sparse general linear + constraints +* SPARSE-IPM-QP for convex or semidefinite problems with large (many + thousands) variable count, sparse quadratic term AND linear constraints. +* SPARSE-ECQP for convex having only linear equality constraints. This + specialized solver can be orders of magnitude faster than IPM. + +If your problem happens to be nonconvex or has nonlinear constraints, then +you can use: +* DENSE-GENIPM or SPARSE-GENIPM solver which supports convex/nonconvex + QP problems with box, linear, quadratic equality/inequality and + conic constraints. +* HYBRID-GENIPM solver which is optimized for well-conditioned problems + with large dense quadratic term/constraints or for problems with large + sparse quadratic terms having prohibitively dense Cholesky factors. The + solver uses limited-memory SR1 quadratic model to accelerate Newton step. +* QuickQP for small dense nonconvex problems with box-only constraints + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer with zero quadratic/linear terms + and no constraints + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpcreate(const ae_int_t n, minqpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear term for QP solver. + +By default, linear term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + B - linear term, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlinearterm(minqpstate &state, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets dense quadratic term for QP solver. By default, +quadratic term is zero. + +IMPORTANT: + +This solver minimizes following function: + f(x) = 0.5*x'*A*x + b'*x. +Note that quadratic term has 0.5 before it. So if you want to minimize + f(x) = x^2 + x +you should rewrite your problem as follows: + f(x) = 0.5*(2*x^2) + x +and your matrix A will be equal to [[2.0]], not to [[1.0]] + +INPUT PARAMETERS: + State - structure which stores algorithm state + A - matrix, array[N,N] + IsUpper - storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetquadraticterm(minqpstate &state, const real_2d_array &a, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets sparse quadratic term for QP solver. By default, +quadratic term is zero. This function overrides previous calls to +minqpsetquadraticterm() or minqpsetquadratictermsparse(). + +NOTE: dense solvers like DENSE-AUL-QP or DENSE-IPM-QP will convert this + matrix to dense storage anyway. + +IMPORTANT: + +This solver minimizes following function: + f(x) = 0.5*x'*A*x + b'*x. +Note that quadratic term has 0.5 before it. So if you want to minimize + f(x) = x^2 + x +you should rewrite your problem as follows: + f(x) = 0.5*(2*x^2) + x +and your matrix A will be equal to [[2.0]], not to [[1.0]] + +INPUT PARAMETERS: + State - structure which stores algorithm state + A - matrix, array[N,N] + IsUpper - (optional) storage type: + * if True, symmetric matrix A is given by its upper + triangle, and the lower triangle isn't used + * if False, symmetric matrix A is given by its lower + triangle, and the upper triangle isn't used + * if not given, both lower and upper triangles must be + filled. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetquadratictermsparse(minqpstate &state, const sparsematrix &a, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets starting point for QP solver. It is useful to have good +initial approximation to the solution, because it will increase speed of +convergence and identification of active constraints. + +NOTE: interior point solvers ignore initial point provided by user. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetstartingpoint(minqpstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets origin for QP solver. By default, following QP program +is solved: + + min(0.5*x'*A*x+b'*x) + +This function allows to solve a different problem: + + min(0.5*(x-x_origin)'*A*(x-x_origin)+b'*(x-x_origin)) + +Specification of non-zero origin affects function being minimized and +quadratic/conic constraints, but not box and linear constraints which are +still calculated without origin. + +INPUT PARAMETERS: + State - structure which stores algorithm state + XOrigin - origin, array[N]. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetorigin(minqpstate &state, const real_1d_array &xorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and as +preconditioner. + +Scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the + function + +If you do not know how to choose scales of your variables, you can: +* read www.alglib.net/optimization/scaling.php article +* use minqpsetscaleautodiag(), which calculates scale using diagonal of + the quadratic term: S is set to 1/sqrt(diag(A)), which works well + sometimes. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetscale(minqpstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets automatic evaluation of variable scaling. + +IMPORTANT: this function works only for matrices with positive diagonal + elements! Zero or negative elements will result in -9 error + code being returned. Specify scale vector manually with + minqpsetscale() in such cases. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and as +preconditioner. + +The best way to set scaling is to manually specify variable scales. +However, sometimes you just need quick-and-dirty solution - either when +you perform fast prototyping, or when you know your problem well and you +are 100% sure that this quick solution is robust enough in your case. + +One such solution is to evaluate scale of I-th variable as 1/Sqrt(A[i,i]), +where A[i,i] is an I-th diagonal element of the quadratic term. + +Such approach works well sometimes, but you have to be careful here. + +INPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void minqpsetscaleautodiag(minqpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use DENSE-AUL algorithm and sets stopping +criteria for the algorithm. + +This algorithm is intended for non-convex problems with moderate (up +to several thousands) variable count and arbitrary number of constraints +which are either (a) effectively convexified under constraints or (b) have +unique solution even with nonconvex target. + +IMPORTANT: when DENSE-IPM solver is applicable, its performance is usually + much better than that of DENSE-AUL. + We recommend you to use DENSE-AUL only when other solvers can + not be used. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* convergence is theoretically proved for positive-definite (convex) QP + problems. Semidefinite and non-convex problems can be solved as long as + they are bounded from below under constraints, although without + theoretical guarantees. + +ALGORITHM OUTLINE: + +* this algorithm is an augmented Lagrangian method with dense + preconditioner (hence its name). +* it performs several outer iterations in order to refine values of the + Lagrange multipliers. Single outer iteration is a solution of some + unconstrained optimization problem: first it performs dense Cholesky + factorization of the Hessian in order to build preconditioner (adaptive + regularization is applied to enforce positive definiteness), and then + it uses L-BFGS optimizer to solve optimization problem. +* typically you need about 5-10 outer iterations to converge to solution + +ALGORITHM LIMITATIONS: + +* because dense Cholesky driver is used, this algorithm has O(N^2) memory + requirements and O(OuterIterations*N^3) minimum running time. From the + practical point of view, it limits its applicability by several + thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + constraint matrix is sparse, it may handle tens of thousands of general + linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0, stopping criteria for inner optimizer. + Inner iterations are stopped when step length (with + variable scaling being applied) is less than EpsX. + See minqpsetscale() for more information on variable + scaling. + Rho - penalty coefficient, Rho>0: + * large enough that algorithm converges with desired + precision. + * not TOO large to prevent ill-conditioning + * recommended values are 100, 1000 or 10000 + ItsCnt - number of outer iterations: + * recommended values: 10-15 (although in most cases it + converges within 5 iterations, you may need a few more + to be sure). + * ItsCnt=0 means that small number of outer iterations is + automatically chosen (10 iterations in current version). + * ItsCnt=1 means that AUL algorithm performs just as usual + penalty method. + * ItsCnt>1 means that AUL algorithm performs specified + number of outer iterations + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic step length selection + (specific step length chosen may change in the future versions of + ALGLIB, so it is better to specify step length explicitly). + + -- ALGLIB -- + Copyright 20.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseaul(minqpstate &state, const double epsx, const double rho, const ae_int_t itscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use DENSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with moderate (up to several thousands) variable count +and arbitrary number of linear constraints. Quadratic and conic constraints +are supported by another solver (DENSE-GENIPM). + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: this algorithm is likely to fail on nonconvex problems, + furthermore, sometimes it fails without a notice. If you try to + run DENSE-IPM on a problem with indefinite matrix (a matrix + having at least one negative eigenvalue) then depending on the + circumstances it may either (a) stall at some arbitrary point, + or (b) throw an exception due to the failure of the Cholesky + decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodenseipm(minqpstate &state, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use SPARSE-IPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex and semidefinite QP (but not QCQP +or conic) problems with large variable and constraint count and sparse +quadratic term and sparse linear constraints. It was successfully used for +problems with millions of variables and constraints. Quadratic and conic +constraints are supported by another solver (SPARSE-GENIPM). + +It is possible to have some limited set of dense linear constraints - they +will be handled separately by the dense BLAS - but the more dense +constraints you have, the more time solver needs. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +IMPORTANT: this algorithm won't work for nonconvex problems. If you try to + run SPARSE-IPM on a problem with indefinite quadratic term (a + matrix having at least one negative eigenvalue) then depending + on the circumstances it may either (a) stall at some arbitrary + point, or (b) throw an exception due to the failure of the + Cholesky decomposition. + + Use GENIPM algorithm if your problem is nonconvex or has a + potential of becoming nonconvex. The GENIPM solver can also + handle problems with quadratic and conic constraints. + +ALGORITHM FEATURES: + +* supports box and dense/sparse general linear equality/inequality + constraints +* specializes on large-scale sparse problems + +ALGORITHM OUTLINE: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseipm(minqpstate &state, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use DENSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically +constrained QP problems with moderate (up to several thousands) variables +count and arbitrary number of constraints. Use SPARSE-GENIPM if your +problem is sparse. + +The algorithm is a generalization of DENSE-IPM solver, capable of handling +more general constraints as well as nonconvexity of the target. In the +latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a good implementation; however, + using a hardware vendor-provided performance library usually + results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +ALGORITHM FEATURES: + +* supports box, linear equality/inequality and conic constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) + +ALGORITHM LIMITATIONS: + +* because a dense Cholesky driver is used, for N-dimensional problem with + M dense constaints this algorithm has O(N^2+N*M) memory requirements and + O(N^3+M*N^2) running time. + Having sparse constraints with Z nonzeros per row relaxes storage and + running time down to O(N^2+M*Z) and O(N^3+M*Z^2) + From the practical point of view, it limits its applicability by + several thousands of variables. + From the other side, variables count is the most limiting factor, + and dependence on constraint count is much more lower. Assuming that + the constraint matrix is sparse, it may handle tens of thousands of + general linear constraints. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'GENIPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgodensegenipm(minqpstate &state, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use SPARSE-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for convex/nonconvex box/linearly/conically/ +quadratically constrained QP problems with sparse quadratic term and +constraints. It can handle millions of variables and constraints, assuming +that the problem is sufficiently sparse. If your problem is small (several +thousands vars at most) and dense, consider using DENSE-GENIPM as a more +efficient alternative. + +The algorithm is a generalization of the SPARSE-IPM solver, capable of +handling more general constraints as well as nonconvexity of the target. +In the latter case, a local solution is found. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + + In many cases this algorithm outperforms DENSE-IPM by order of + magnitude. However, in some cases you may get better results + with DENSE-IPM even when solving sparse task. + +ALGORITHM FEATURES: + + +* supports box, linear equality/inequality constraints +* for convex problems returns the global (and the only) solution +* can handle non-convex problem (only a locally optimal solution is + returned in this case) +* specializes on large-scale sparse problems + +ALGORITHM LIMITATIONS: + +* this algorithm may handle moderate number of dense constraints, usually + no more than a thousand of dense ones without losing its efficiency. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + +===== TRACING GENIPM SOLVER ============================================== + +GENIPM solver supports advanced tracing capabilities. You can log algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'GENIPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'GENIPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GENIPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparsegenipm(minqpstate &state, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use HYBRID-GENIPM QP algorithm and sets +stopping criteria for the algorithm. + +This algorithm is intended for finding medium-accuracy solutions (say, no +more than 5 accurate digits) to large-scale convex/nonconvex box/linearly/ +conically/quadratically constrained QP problems with objective and/or +quadratic constraints being well-conditioned but having prohibitively +dense Cholesky factors. This includes both dense problems and problems +with sparse terms having too dense factorizations. + +Being well conditioned allows us to use low rank LBFGS/LSR1 approximations +to the objective (quadratic constraints) and use sparse linear algebra for +the rest of the problem, thus achieving significant speed-up on many +types of problems. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). Specific speed-up due to parallelism + heavily depends on the sparsity pattern of quadratic term and + constraints. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism support. + + This function does not use performance backends to accelerate + sparse factorization because external libraries typically do + not provide fine control over regularization, pivoting and + sparse orderings. + +IMPORTANT: performance of this function depends on both sparsity pattern + of the problem and on its conditioning properties. The running + time for a dense QP/QCQP problem grows with variables count as + O(N^2) while DENSE-GENIPM running time grows as O(N^3). + + On the other hand, DENSE/SPARSE-GENIPM running time shows only + moderate dependence on the condition number, while HYBRID-GENIPM + running time often explodes with condition number larger than + 10000. + + In practice, on a dense QCQP problem HYBRID algorithm starts to + singificantly outperform DENSE-GENIPM for N>=1000. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities as well as complementarity gap are + less than Eps. + + This solver is optimized for finding medium-accuracy + solutions, with eps being between 1E-3 and 1E-5. + + MemLen - >=0, memory length for the limited memory SR1 model. Zero + value means automatic selection of some small predefined + value which may change in future versions of ALGLIB. + Optimal value is problem-dependent, with 8...32 being a + good initial point for the experimentation. Values above + N are silently truncated down to N. + + MaxOffdiag- >=0, quadratic terms with more than MaxOffdiag offdiagonal + elements are handled via quasi-Newton approximation. Terms + with no more than MaxOffdiag elements are handled exactly, + including strictly diagonal terms that are always handled + exactly (because they have the minimum number off-diagonal + elements possible - zero). Symmetric terms appearing above + and below diagonal are counted as one term, not two. A + single quasi-Newton model is built, which approximates all + eligible quadratic terms together. + + The following values are possible: + * 0 - approximate every quadratic term having at least one + off-diagonal element with a quasi-Newton model. + * 0=N*(N-1)/2 - no quadratic term is eligible + for quasi-Newton approximation, algorithm performance is + roughly similar to that of SPARSE-GENIPM, with some + additional small overhead for quasi-Newton code checks. + + -- ALGLIB -- + Copyright 01.05.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgohybridgenipm(minqpstate &state, const double eps, const ae_int_t memlen, const ae_int_t maxoffdiag, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells QP solver to use an ECQP algorithm. + +This algorithm is intended for sparse convex problems with only linear +equality constraints. It can handle millions of variables and constraints, +assuming that the problem is sufficiently sparse. However, it can NOT +deal with nonlinear equality constraints or inequality constraints of any +type (including box ones), nor it can deal with nonconvex problems. + +When applicable, it outperforms SPARSE-IPM by tens of times. It is a +regularized direct linear algebra solver that performs several rounds of +iterative refinement in order to improve a solution. Thus, due to its +direct nature, it does not need stopping criteria and performs much faster +than interior point methods. + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel PARDISO or another platform-specific library) to + accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of quadratic term + and constraints. For some problem types performance backends + provide great speed-up. For other ones, ALGLIB's own sparse + factorization code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +IMPORTANT: internally this solver performs large and sparse (N+M)x(N+M) + triangular factorization. So it expects both quadratic term and + constraints to be highly sparse. However, its running time is + influenced by BOTH fill factor and sparsity pattern. + + Generally we expect that no more than few nonzero elements per + row are present. However different sparsity patterns may result + in completely different running times even given same fill + factor. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, stopping criteria. The algorithm stops when primal + and dual infeasiblities are less than Eps. + +IT IS VERY IMPORTANT TO CALL minqpsetscale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS CONVERGENCE PROPERTIES AND STOPPING CRITERIA ARE SCALE-DEPENDENT! + +NOTE: Passing EpsX=0 will lead to automatic selection of small epsilon. + + -- ALGLIB -- + Copyright 01.07.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgosparseecqp(minqpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells solver to use QuickQP algorithm: special extra-fast +algorithm for problems with box-only constrants. It may solve non-convex +problems as long as they are bounded from below under constraints. + +ALGORITHM FEATURES: +* several times faster than DENSE-IPM when running on box-only problem +* utilizes accelerated methods for activation of constraints. +* supports dense and sparse QP problems +* supports ONLY box constraints; general linear constraints are NOT + supported by this solver +* can solve all types of problems (convex, semidefinite, nonconvex) as + long as they are bounded from below under constraints. + Say, it is possible to solve "min{-x^2} subject to -1<=x<=+1". + In convex/semidefinite case global minimum is returned, in nonconvex + case - algorithm returns one of the local minimums. + +ALGORITHM OUTLINE: + +* algorithm performs two kinds of iterations: constrained CG iterations + and constrained Newton iterations +* initially it performs small number of constrained CG iterations, which + can efficiently activate/deactivate multiple constraints +* after CG phase algorithm tries to calculate Cholesky decomposition and + to perform several constrained Newton steps. If Cholesky decomposition + failed (matrix is indefinite even under constraints), we perform more + CG iterations until we converge to such set of constraints that system + matrix becomes positive definite. Constrained Newton steps greatly + increase convergence speed and precision. +* algorithm interleaves CG and Newton iterations which allows to handle + indefinite matrices (CG phase) and quickly converge after final set of + constraints is found (Newton phase). Combination of CG and Newton phases + is called "outer iteration". +* it is possible to turn off Newton phase (beneficial for semidefinite + problems - Cholesky decomposition will fail too often) + +ALGORITHM LIMITATIONS: + +* algorithm does not support general linear constraints; only box ones + are supported +* Cholesky decomposition for sparse problems is performed with Skyline + Cholesky solver, which is intended for low-profile matrices. No profile- + reducing reordering of variables is performed in this version of ALGLIB. +* problems with near-zero negative eigenvalues (or exacty zero ones) may + experience about 2-3x performance penalty. The reason is that Cholesky + decomposition can not be performed until we identify directions of zero + and negative curvature and activate corresponding boundary constraints - + but we need a lot of trial and errors because these directions are hard + to notice in the matrix spectrum. + In this case you may turn off Newton phase of algorithm. + Large negative eigenvalues are not an issue, so highly non-convex + problems can be solved very efficiently. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + EpsX - >=0 + The subroutine finishes its work if exploratory steepest + descent step on k+1-th iteration satisfies following + condition: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinQPSetScale() + MaxOuterIts-maximum number of OUTER iterations. One outer iteration + includes some amount of CG iterations (from 5 to ~N) and + one or several (usually small amount) Newton steps. Thus, + one outer iteration has high cost, but can greatly reduce + funcation value. + Use 0 if you do not want to limit number of outer iterations. + UseNewton- use Newton phase or not: + * Newton phase improves performance of positive definite + dense problems (about 2 times improvement can be observed) + * can result in some performance penalty on semidefinite + or slightly negative definite problems - each Newton + phase will bring no improvement (Cholesky failure), but + still will require computational time. + * if you doubt, you can turn off this phase - optimizer + will retain its most of its high speed. + +IT IS VERY IMPORTANT TO CALL MinQPSetScale() WHEN YOU USE THIS ALGORITHM +BECAUSE ITS STOPPING CRITERIA ARE SCALE-DEPENDENT! + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection (presently it is small step +length, but it may change in the future versions of ALGLIB). + + -- ALGLIB -- + Copyright 22.05.2014 by Bochkanov Sergey +*************************************************************************/ +void minqpsetalgoquickqp(minqpstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxouterits, const bool usenewton, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for QP solver + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minqpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbc(minqpstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for QP solver (all variables at once, +same constraints for all variables) + +Box constraints are inactive by default (after initial creation). After +being set, they are preserved until explicitly overwritten with another +minqpsetbc() or minqpsetbcall() call, or partially overwritten with +minqpsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbcall(minqpstate &state, const double bndl, const double bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd BndL=BndU + lower bound BndL<=x[i] BndU=+INF + upper bound x[i]<=BndU BndL=-INF + range BndL<=x[i]<=BndU ... + free variable - BndL=-INF, BndU+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound + BndU - upper bound + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: BndL>BndU will result in QP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpsetbci(minqpstate &state, const ae_int_t i, const double bndl, const double bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets dense linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 19.06.2012 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc(minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minqpsetlc(minqpstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets sparse linear constraints for QP optimizer. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). After call to this function +all non-box constraints are dropped, and you have only those constraints +which were specified in the present call. + +If you want to specify mixed (with dense and sparse terms) linear +constraints, you should call minqpsetlcmixed(). + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + C - linear constraints, sparse matrix with dimensions at + least [K,N+1]. If matrix has larger size, only leading + Kx(N+1) rectangle is used. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0 + +NOTE 1: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcsparse(minqpstate &state, const sparsematrix &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets mixed linear constraints, which include a set of dense +rows, and a set of sparse rows. + +This function overrides results of previous calls to minqpsetlc(), +minqpsetlcsparse() and minqpsetlcmixed(). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with MinQPCreate call. + SparseC - linear constraints, sparse matrix with dimensions EXACTLY + EQUAL TO [SparseK,N+1]. Each row of C represents one + constraint, either equality or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + SparseCT- type of sparse constraints, array[K]: + * if SparseCT[i]>0, then I-th constraint is SparseC[i,*]*x >= SparseC[i,n+1] + * if SparseCT[i]=0, then I-th constraint is SparseC[i,*]*x = SparseC[i,n+1] + * if SparseCT[i]<0, then I-th constraint is SparseC[i,*]*x <= SparseC[i,n+1] + SparseK - number of sparse equality/inequality constraints, K>=0 + DenseC - dense linear constraints, array[K,N+1]. + Each row of DenseC represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of DenseC (including right part) must be finite. + DenseCT - type of constraints, array[K]: + * if DenseCT[i]>0, then I-th constraint is DenseC[i,*]*x >= DenseC[i,n+1] + * if DenseCT[i]=0, then I-th constraint is DenseC[i,*]*x = DenseC[i,n+1] + * if DenseCT[i]<0, then I-th constraint is DenseC[i,*]*x <= DenseC[i,n+1] + DenseK - number of equality/inequality constraints, DenseK>=0 + +NOTE 1: linear (non-box) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE 2: due to backward compatibility reasons SparseC can be larger than + [SparseK,N+1]. In this case only leading [SparseK,N+1] submatrix + will be used. However, the rest of ALGLIB has more strict + requirements on the input size, so we recommend you to pass sparse + term whose size exactly matches algorithm expectations. + + -- ALGLIB -- + Copyright 22.08.2016 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixed(minqpstate &state, const sparsematrix &sparsec, const integer_1d_array &sparsect, const ae_int_t sparsek, const real_2d_array &densec, const integer_1d_array &densect, const ae_int_t densek, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides legacy API for specification of mixed dense/sparse +linear constraints. + +New conventions used by ALGLIB since release 3.16.0 state that set of +sparse constraints comes first, followed by set of dense ones. This +convention is essential when you talk about things like order of Lagrange +multipliers. + +However, legacy API accepted mixed constraints in reverse order. This +function is here to simplify situation with code relying on legacy API. It +simply accepts constraints in one order (old) and passes them to new API, +now in correct order. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlcmixedlegacy(minqpstate &state, const real_2d_array &densec, const integer_1d_array &densect, const ae_int_t densek, const sparsematrix &sparsec, const integer_1d_array &sparsect, const ae_int_t sparsek, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense helps some QP solvers + (especially modern IPM method) to utilize efficient dense Level 3 + BLAS for dense parts of the problem. If your problem has both dense + and sparse constraints, you can use minqpsetlc2mixed() function, + which will result in dense algebra being applied to dense terms, and + sparse sparse linear algebra applied to sparse terms. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2dense(minqpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minqpsetlc2dense(minqpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2(minqpstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minqpsetlc2mixed(minqpstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +matrix of currently present dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2dense(minqpstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2(minqpstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minqpaddlc2sparsefromdense(minqpstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function clears the list of quadratic constraints. Other constraints +are not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearqc(minqpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear term is given by +a dense array, the quadratic term is given by a sparse array. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function has O(max(N,NNZ)) memory and time requirements because a +dense array is used to store linear term and because most sparse matrix +storage formats supported by ALGLIB need at least O(N) memory even for an +empty quadratic constraint matrix. + +Use minqpaddqc2list() if you have to add many constraints with much less +than N nonzero elements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - symmetric matrix Q in a sparse matrix storage format: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * any sparse matrix storage format present in ALGLIB is + supported + * the matrix must be exactly NxN + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2(minqpstate &state, const sparsematrix &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. Both linear and quadratic +terms are given as lists of non-zero entries. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +The function needs O(NNZ) memory for temporaries and O(NNZ*logNNZ) time, +where NNZ is a total number of non-zeros in both lists. For small +constraints it can be orders of magnitude faster than minqpaddqc2() with +its O(max(N,NNZ)) temporary memory or minqpaddqc2dense() with its O(N^2) +temporaries. Thus, it is recommended if you have many small constraints. + +NOTE: in the end, all quadratic constraints are stored in the same + memory-efficient compressed format. However, you have to allocate an + NxN temporary dense matrix when you pass a constraint using + minqpaddqc2dense(). Similarly, data structures used as a part of the + API provided by minqpaddqc2() have O(N) temporary memory + requirements. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + QRIdx - array[QNNZ], stores row indexes of QNNZ nonzero elements + of a symmetric matrix Q + QCIdx - array[QNNZ], stores col indexes of QNNZ nonzero elements + of a symmetric matrix Q + QVals - array[QNNZ], stores values of QNNZ nonzero elements of a + symmetric matrix Q + QNNZ - number of non-zero elements in Q, QNNZ>=0 + IsUpper - whether upper or lower triangle of Q is used: + * if IsUpper=True, then only elements with QRIdx[I]<=QCIdx[I] + are used and the rest is ignored + * if IsUpper=False, then only elements with QRIdx[I]>=QCIdx[I] + are used and the rest is ignored + BIdx - array[BNNZ], indexes of BNNZ nonzero elements of a linear term + BVals - array[BNNZ], values of BNNZ nonzero elements of a linear term + BNNZ - number of nonzero elements in B, BNNZ>=0 + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.07.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2list(minqpstate &state, const integer_1d_array &qridx, const integer_1d_array &qcidx, const real_1d_array &qvals, const ae_int_t qnnz, const bool isupper, const integer_1d_array &bidx, const real_1d_array &bvals, const ae_int_t bnnz, const double cl, const double cu, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a two-sided quadratic constraint of the form + + CL <= b'x + 0.5*x'*Q*x <= CU + +or (depending on the ApplyOrigin parameter) + + CL <= b'(x-origin) + 0.5*(x-origin)'*Q*(x-origin) <= CU + +to the set of currently present constraints. The linear and quadratic terms +are given by dense arrays. + +Here CL can be finite or -INF (absense of constraint), CU can be finite or ++INF (absense of constraint), CL<=CU, with CL=CU denoting an equality +constraint. Q is an arbitrary (including indefinite) symmetric matrix. + +This function trades convenience of using dense arrays for the efficiency. +Because dense NxN storage is used, merely calling this function has O(N^2) +complexity, no matter how sparse the Q is. + +Use minqpaddqc2() or minqpaddqc2list() if you have sparse Q and/or many +constraints to handle. + +IMPORTANT: ALGLIB supports arbitrary quadratic constraints, including + nonconvex ones. However, only convex constraints (combined with + the convex objective) result in guaranteed convergence to the + global minimizer. In all other cases, only local convergence to + a local minimum is guaranteed. + + A convex constraint is a constraint of the following form: + b'*(x-origin) + 0.5(x-origin)'*Q*(x-origin) <=CU, with Q being + a semidefinite matrix. All other modifications are nonconvex: + * -x0^2<=1 is nonconvex + * x0^2>=1 is nonconvex (despite Q=1 being positive definite) + * x0^2 =1 is nonconvex + + The latter case is notable because it effectively converts a QP + problem into a mixed integer QP program. Smooth interior point + solver can not efficiently handle such programs, converging to + a randomly chosen x0 (either +1 or -1) and keeping its value + fixed during the optimization. + + It is also notable that larger equality constraints (e.g. + x0^2+x1^2=1) are much less difficult to handle because they + form large connected regions within the parameters space. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Q - array[N,N], symmetric matrix Q: + * if IsUpper=True, then the upper triangle is given, and + the lower triangle is ignored + * if IsUpper=False, then the lower triangle is given, and + the upper triangle is ignored + * if more than N rows/cols are present, only leading N + elements are used + IsUpper - whether upper or lower triangle of Q is used + B - array[N], linear term + CL, CU - lower and upper bounds: + * CL can be finite or -INF (absence of a bound) + * CU can be finite or +INF (absence of a bound) + * CL<=CU, with CL=CU meaning an equality constraint + * CL=-INF, CU=+INF => constraint is ignored + ApplyOrigin-whether origin (as specified by minqpsetorigin) is applied + to the constraint or not. If no origin was specified, this + parameter has no effect. + +RESULT: + constraint index, starting from 0 + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddqc2dense(minqpstate &state, const real_2d_array &q, const bool isupper, const real_1d_array &b, const double cl, const double cu, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function clears the list of conic constraints. Other constraints are +not modified. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + + -- ALGLIB -- + Copyright 19.06.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpclearcc(minqpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a primitive second-order conic constraint of the +form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx] + ( ) + +with 'primitive' meaning that there are no per-variable scales and that +variables under the square root have sequential indexes. More general form +of conic constraints can be specified with minqpaddsoccorthogonal(). + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB allows conic constraints to +overlap, i.e. it allows a variable to be a part of multiple conic +constraints. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Range0, + Range1 - 0<=range0<=range1<=N, variable range for the LHS; + * squared variables x[range0]...x[range1-1] are summed up + under the square root. + * range0=range1 means that the constraint is interpreted + as x[AxisIdx]>=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccprimitive(minqpstate &state, const ae_int_t range0, const ae_int_t range1, const ae_int_t axisidx, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends an axis-orthogonal second-order conic constraint of +the form + + ( k-2 ( )^2 ) + sqrt ( SUM ( a[i]*x[idx[i]]+c[i] ) + theta^2 ) <= a[k-1]*x[idx[k-1]]+c[k-1] + ( i=0 ( ) ) + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows a[] to have zero elements at arbitrary positions (e.g., |x|<=const +can be handled just as easy as |x|<=y). Furthermore, ALGLIB allows conic +constraints to overlap, i.e. it allows a variable to be a part of multiple +conic constraints, or to appear multiple times in the same constraint. + +NOTE: second-order conic constraints are always convex, so having them + preserves convexity of the QP problem. + +NOTE: A starting point that is strictly feasible with respect to both box + and conic constraints greatly helps the solver to power up; however, + it will work even without such a point, albeit at somewhat lower + performance. + +INPUT PARAMETERS: + State - structure previously allocated with minqpcreate() call. + Idx - array[K] (or larger, only leading K elements are used) + storing variable indexes. Indexes can be unsorted and/or + non-distinct. + A - array[K] (or larger, only leading K elements are used), + variable multipliers. Can contain zero values. + C - array[K] (or larger, only leading K elements are used), + variable shifts. + K - cone dimensionality, K>=1. It is possible to have K>N. + Theta - additional constant term, can be zero + +RESULT: + constraint index in a conic constraints list, starting from 0 + + -- ALGLIB -- + Copyright 09.09.2024 by Bochkanov Sergey +*************************************************************************/ +ae_int_t minqpaddsoccorthogonal(minqpstate &state, const integer_1d_array &idx, const real_1d_array &a, const real_1d_array &c, const ae_int_t k, const double theta, const bool applyorigin, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a primitive power cone constraint of the form + + ( ) + sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 ) <= x[axisidx]^alpha + ( ) + +or, written in another form, + + ( ( ))^(1/alpha) + (sqrt(x[range0]^2 + x[range0+1]^2 + ... + x[range1-1]^2 )) <= x[axisidx] + ( ( )) + +where + + 0=0. + AxisIdx - RHS variable index: + * 0<=AxisIdx=Range1. + Alpha - power parameter, 0=0 + + 0=|theta| + +Alternatively, if ApplyOrigin parameter is True, x[i] is replaced by +x[i]-origin[i] (applies to all variables). + +Unlike many other conic solvers, ALGLIB provides a flexible conic API that +allows alpha[] to sum up to any positive value less than or equal to 1 +(e.g. it is possible to formulate |x|=1. It is possible to have K>N. + Theta - additional constant term, can be zero + AlphaV - array[KPow], power coefficients: + * 00 success +* 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresults(const minqpstate &state, real_1d_array &x, minqpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +QP results + +Buffered implementation of MinQPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minqpresultsbuf(const minqpstate &state, real_1d_array &x, minqpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Export current QP problem stored in the solver into QPXProblem instance. +This instance can be serialized into ALGLIB-specific format and +unserialized from several widely acknowledged formats. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpexport(minqpstate &state, qpxproblem &p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Imports QP problem, as defined by QPXProblem instance, creating a QP solver +with objective/constraints/scales/origin set to that stored in the instance. + +INPUT PARAMETERS: + P - QPXProblem instance storing current objective and + constraints. + +OUTPUT PARAMETERS: + State - newly created solver + + -- ALGLIB -- + Copyright 25.08.2024 by Bochkanov Sergey +*************************************************************************/ +void minqpimport(qpxproblem &p, minqpstate &s, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] and Jacobian of f[]. + + +REQUIREMENTS: +This algorithm will request following information during its operation: + +* function vector f[] at given point X +* function vector f[] and Jacobian of f[] (simultaneously) at given point + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() and jac() callbacks. +First one is used to calculate f[] at given point, second one calculates +f[] and Jacobian df[i]/dx[j]. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not provide Jacobian), but it +will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateVJ() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatevj(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minlmstate &state, const xparams _xparams = alglib::xdefault); +void minlmcreatevj(const ae_int_t m, const real_1d_array &x, minlmstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + IMPROVED LEVENBERG-MARQUARDT METHOD FOR + NON-LINEAR LEAST SQUARES OPTIMIZATION + +DESCRIPTION: +This function is used to find minimum of function which is represented as +sum of squares: + F(x) = f[0]^2(x[0],...,x[n-1]) + ... + f[m-1]^2(x[0],...,x[n-1]) +using value of function vector f[] only. Finite differences are used to +calculate Jacobian. + + +REQUIREMENTS: +This algorithm will request following information during its operation: +* function vector f[] at given point X + +There are several overloaded versions of MinLMOptimize() function which +correspond to different LM-like optimization algorithms provided by this +unit. You should choose version which accepts fvec() callback. + +You can try to initialize MinLMState structure with VJ function and then +use incorrect version of MinLMOptimize() (for example, version which +works with general form function and does not accept function vector), but +it will lead to exception being thrown after first attempt to calculate +Jacobian. + + +USAGE: +1. User initializes algorithm state with MinLMCreateV() call +2. User tunes solver parameters with MinLMSetCond(), MinLMSetStpMax() and + other functions +3. User calls MinLMOptimize() function which takes algorithm state and + callback functions. +4. User calls MinLMResults() to get solution +5. Optionally, user may call MinLMRestartFrom() to solve another problem + with same N/M but another starting point and/or another function. + MinLMRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i] + X - initial solution, array[0..N-1] + DiffStep- differentiation step, >0. By default, symmetric 3-point + formula which provides good accuracy is used. It can be + changed to a faster but less precise 2-point one with + minlmsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +See also MinLMIteration, MinLMResults. + +NOTES: +1. you may tune stopping conditions with MinLMSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use MinLMSetStpMax() function to bound algorithm's steps. + + -- ALGLIB -- + Copyright 30.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmcreatev(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state, const xparams _xparams = alglib::xdefault); +void minlmcreatev(const ae_int_t m, const real_1d_array &x, const double diffstep, minlmstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for Levenberg-Marquardt optimization +algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinLMSetScale() + Recommended values: 1E-9 ... 1E-12. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. Only Levenberg-Marquardt + iterations are counted (L-BFGS/CG iterations are NOT + counted because their cost is very low compared to that of + LM). + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + +NOTE: it is not recommended to set large EpsX (say, 0.001). Because LM is + a second-order method, it performs very precise steps anyway. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetcond(minlmstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinLMOptimize(). Both Levenberg-Marquardt and internal L-BFGS +iterations are reported. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetxrep(minlmstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: non-zero StpMax leads to moderate performance degradation because +intermediate step of preconditioned L-BFGS optimization is incompatible +with limits on step size. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetstpmax(minlmstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for LM optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But LM +optimizer is unique in that it uses scaling matrix both in the stopping +condition tests and as Marquardt damping factor. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetscale(minlmstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for LM optimizer + +Boundary constraints are inactive by default (after initial creation). +They are preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (latter is recommended because + it will allow solver to use better algorithm). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (latter is recommended because + it will allow solver to use better algorithm). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints + or at its boundary + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetbc(minlmstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets general linear constraints for LM optimizer + +Linear constraints are inactive by default (after initial creation). They +are preserved until explicitly turned off with another minlmsetlc() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +IMPORTANT: if you have linear constraints, it is strongly recommended to + set scale of variables with minlmsetscale(). QP solver which is + used to calculate linearly constrained steps heavily relies on + good scaling of input problems. + +IMPORTANT: solvers created with minlmcreatefgh() do not support linear + constraints. + +NOTE: linear (non-bound) constraints are satisfied only approximately - + there always exists some violation due to numerical errors and + algorithmic limitations. + +NOTE: general linear constraints add significant overhead to solution + process. Although solver performs roughly same amount of iterations + (when compared with similar box-only constrained problem), each + iteration now involves solution of linearly constrained QP + subproblem, which requires ~3-5 times more Cholesky decompositions. + Thus, if you can reformulate your problem in such way this it has + only box constraints, it may be beneficial to do so. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlmsetlc(minlmstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minlmsetlc(minlmstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to change acceleration settings + +You can choose between three acceleration strategies: +* AccType=0, no acceleration. +* AccType=1, secant updates are used to update quadratic model after each + iteration. After fixed number of iterations (or after model breakdown) + we recalculate quadratic model using analytic Jacobian or finite + differences. Number of secant-based iterations depends on optimization + settings: about 3 iterations - when we have analytic Jacobian, up to 2*N + iterations - when we use finite differences to calculate Jacobian. + +AccType=1 is recommended when Jacobian calculation cost is prohibitively +high (several Mx1 function vector calculations followed by several NxN +Cholesky factorizations are faster than calculation of one M*N Jacobian). +It should also be used when we have no Jacobian, because finite difference +approximation takes too much time to compute. + +Table below list optimization protocols (XYZ protocol corresponds to +MinLMCreateXYZ) and acceleration types they support (and use by default). + +ACCELERATION TYPES SUPPORTED BY OPTIMIZATION PROTOCOLS: + +protocol 0 1 comment +V + + +VJ + + +FGH + + +DEFAULT VALUES: + +protocol 0 1 comment +V x without acceleration it is so slooooooooow +VJ x +FGH x + +NOTE: this function should be called before optimization. Attempt to call +it during algorithm iterations may result in unexpected behavior. + +NOTE: attempt to call this function with unsupported protocol/acceleration +combination will result in exception being thrown. + + -- ALGLIB -- + Copyright 14.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmsetacctype(minlmstate &state, const ae_int_t acctype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to activate/deactivate nonmonotonic steps. Such +steps may improve convergence on noisy problems or ones with minor +smoothness defects. + +In its standard mode, LM solver compares value at the trial point f[1] +with the value at the current point f[0]. Only steps that decrease f() are +accepted. + +When the nonmonotonic mode is activated, f[1] is compared with maximum +over several previous locations: max(f[0],f[-1],...,f[-CNT]). We still +accept only steps that decrease f(), however our reference value has +changed. The net results is that f[1]>f[0] are now allowed. + +Nonmonotonic steps can help to handle minor defects in the objective (e.g. +small noise, discontinuous jumps or nonsmoothness). However, it is +important that the overall shape of the problem is still smooth. +It may also help to minimize perfectly smooth targets with complex +geometries by allowing to jump through curved valleys. + +However, sometimes nonmonotonic steps degrade convergence by allowing an +optimizer to wander too far away from the solution, so this feature should +be used only after careful testing. + +INPUT PARAMETERS: + State - structure stores algorithm state + Cnt - nonmonotonic memory length, Cnt>=0: + * 0 for traditional monotonic steps + * 2..3 is recommended for the nonmonotonic optimization + + -- ALGLIB -- + Copyright 07.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnonmonotonicsteps(minlmstate &state, const ae_int_t cnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minlmcreatev() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinLMCreateV() call. + FormulaType - formula type: + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good choice for medium-accuracy setups, + a default option. + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minlmsetnumdiff(minlmstate &state, const ae_int_t formulatype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minlmiteration(minlmstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM + +The MINLM optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +If you solve a curve fitting problem, i.e. the function vector is actually +the same function computed at different points of a data points space, it +may be better to use an LSFIT curve fitting solver, which offers more +fine-grained parallelism due to knowledge of the problem structure. In +particular, it can accelerate both numerical differentiation and problems +with user-supplied gradients. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + + -- ALGLIB -- + Copyright 03.12.2023 by Bochkanov Sergey + + +*************************************************************************/ +void minlmoptimize(minlmstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minlmoptimize(minlmstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic Jacobian. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function vector at the initial +point (note: future versions may also perform check at the final point) +and compares numerical Jacobian with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both Jacobians, and specific components highlighted as +suspicious by the OptGuard. + +The OptGuard report can be retrieved with minlmoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minlmsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardgradient(minlmstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +OptGuard checks analytic Jacobian against reference value obtained by +numerical differentiation with user-specified step. + +NOTE: other optimizers perform additional OptGuard checks for things like + C0/C1-continuity violations. However, LM optimizer can check only + for incorrect Jacobian. + + The reason is that unlike line search methods LM optimizer does not + perform extensive evaluations along the line. Thus, we simply do not + have enough data to catch C0/C1-violations. + +This check is activated with minlmoptguardgradient() function. + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - OptGuard report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minlmoptguardresults(minlmstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Levenberg-Marquardt algorithm results + +NOTE: if you activated OptGuard integrity checking functionality and want + to get OptGuard report, it can be retrieved with the help of + minlmoptguardresults() function. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report; includes termination codes and + additional information. Termination codes are listed below, + see comments for this structure for more info. + + Termination code is stored in rep.terminationtype field: + * -8 optimizer detected NAN/INF values either in the + function itself, or in its Jacobian + * -3 constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called minlmrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + + rep.f contains SUM(f[i]^2) at X + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresults(const minlmstate &state, real_1d_array &x, minlmreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Levenberg-Marquardt algorithm results + +Buffered implementation of MinLMResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minlmresultsbuf(const minlmstate &state, real_1d_array &x, minlmreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts LM algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinLMCreateXXX call. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minlmrestartfrom(minlmstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minlmrequesttermination(minlmstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONLINEAR CONJUGATE GRADIENT METHOD + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments by using one of the +nonlinear conjugate gradient methods. + +These CG methods are globally convergent (even on non-convex functions) as +long as grad(f) is Lipschitz continuous in a some neighborhood of the +L = { x : f(x)<=f(x0) }. + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function value F and its gradient G (simultaneously) at given point X + + +USAGE: +1. User initializes algorithm state with MinCGCreate() call +2. User tunes solver parameters with MinCGSetCond(), MinCGSetStpMax() and + other functions +3. User calls MinCGOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. +4. User calls MinCGResults() to get solution +5. Optionally, user may call MinCGRestartFrom() to solve another problem + with same N but another starting point and/or another function. + MinCGRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgcreate(const ae_int_t n, const real_1d_array &x, mincgstate &state, const xparams _xparams = alglib::xdefault); +void mincgcreate(const real_1d_array &x, mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +The subroutine is finite difference variant of MinCGCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinCGCreate() in order to get more +information about creation of CG optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinCGSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. L-BFGS needs exact gradient values. + Imprecise gradient may slow down convergence, especially on highly + nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgcreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, mincgstate &state, const xparams _xparams = alglib::xdefault); +void mincgcreatef(const real_1d_array &x, const double diffstep, mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for CG optimization algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - ste pvector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinCGSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0, EpsX=0 and MaxIts=0 (simultaneously) will lead to +automatic stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcond(mincgstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for CG optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of CG optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the CG too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinCGSetPrec...() functions. + +There is special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void mincgsetscale(mincgstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetxrep(mincgstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets CG algorithm. + +INPUT PARAMETERS: + State - structure which stores algorithm state + CGType - algorithm type: + * -1 automatic selection of the best algorithm + * 0 DY (Dai and Yuan) algorithm + * 1 Hybrid DY-HS algorithm + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetcgtype(mincgstate &state, const ae_int_t cgtype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetstpmax(mincgstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function allows to suggest initial step length to the CG algorithm. + +Suggested step length is used as starting point for the line search. It +can be useful when you have badly scaled problem, i.e. when ||grad|| +(which is used as initial estimate for the first step) is many orders of +magnitude different from the desired step. + +Line search may fail on such problems without good estimate of initial +step length. Imagine, for example, problem with ||grad||=10^50 and desired +step equal to 0.1 Line search function will use 10^50 as initial step, +then it will decrease step length by 2 (up to 20 attempts) and will get +10^44, which is still too large. + +This function allows us to tell than line search should be started from +some moderate step length, like 1.0, so algorithm will be able to detect +desired step length in a several searches. + +Default behavior (when no step is suggested) is to use preconditioner, if +it is available, to generate initial estimate of step length. + +This function influences only first iteration of algorithm. It should be +called between MinCGCreate/MinCGRestartFrom() call and MinCGOptimize call. +Suggested step is ignored if you have preconditioner. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + Stp - initial estimate of the step length. + Can be zero (no estimate). + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsuggeststep(mincgstate &state, const double stp, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdefault(mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + +NOTE 2: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 3: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecdiag(mincgstate &state, const real_1d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinCGSetScale() call +(before or after MinCGSetPrecScale() call). Without knowledge of the scale +of your variables scale-based preconditioner will be just unit matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: you can change preconditioner "on the fly", during algorithm +iterations. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgsetprecscale(mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mincgiteration(mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinCGCreate() for analytical gradient or MinCGCreateF() for + numerical differentiation) you should choose appropriate variant of + MinCGOptimize() - one which accepts function AND gradient or one which + accepts function ONLY. + + Be careful to choose variant of MinCGOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinCGOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinCGOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinCGCreateF() | work FAIL + MinCGCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinCGOptimize() version. Attemps to use such combination + (for example, to create optimizer with MinCGCreateF() and to pass + gradient information to MinCGOptimize()) will lead to exception being + thrown. Either you did not pass gradient when it WAS needed or you + passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey + + +*************************************************************************/ +void mincgoptimize(mincgstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void mincgoptimize(mincgstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with mincgoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with mincgsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardgradient(mincgstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardsmoothness(mincgstate &state, const ae_int_t level, const xparams _xparams = alglib::xdefault); +void mincgoptguardsmoothness(mincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* mincgoptguardgradient() for gradient verification +* mincgoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* mincgoptguardnonc1test0results() +* mincgoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardresults(mincgstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test0results(const mincgstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void mincgoptguardnonc1test1results(mincgstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Conjugate gradient results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -8 internal integrity control detected infinite + or NAN values in function/gradient. Abnormal + termination signalled. + * -7 gradient verification failed. + See MinCGSetGradientCheck() for more information. + * 1 relative function improvement is no more than + EpsF. + * 2 relative step is no more than EpsX. + * 4 gradient norm is no more than EpsG + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible, + we return best X found so far + * 8 terminated by user + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresults(const mincgstate &state, real_1d_array &x, mincgreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Conjugate gradient results + +Buffered implementation of MinCGResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.04.2009 by Bochkanov Sergey +*************************************************************************/ +void mincgresultsbuf(const mincgstate &state, real_1d_array &x, mincgreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used to store algorithm state. + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void mincgrestartfrom(mincgstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void mincgrequesttermination(mincgstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + GLOBAL OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR CONSTRAINTS + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear generalized inequality constraints Li<=Ci(x)<=Ui, with one of + Li/Ui possibly being infinite + +REQUIREMENTS: +* F() and C() do NOT have to be differentiable, locally Lipschitz or + continuous. Most solvers in this subpackage can deal with nonsmoothness + or minor discontinuities, although obviously smoother problems are the + most easy ones. +* generally, F() and C() must be computable at any point which is feasible + subject to box constraints + +USAGE: + +1. User initializes algorithm state with mindfcreate() call and + chooses specific solver to be used. There is some solver which is used + by default, with default settings, but you should NOT rely on the + default choice. It may change in the future releases of ALGLIB without + notice, and no one can guarantee that the new solver will be able to + solve your problem with default settings. + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) mindfsetbc() for boundary constraints + b) mindfsetlc2dense() for linear constraints + c) mindfsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with mindfsetscale() function. It is + VERY important to set variable scales because many derivative-free + algorithms refuse to work when variables are badly scaled. + Scaling helps to seed initial population, control convergence and + enforce penalties for constraint violation. + +4. Finally, user calls mindfoptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F and G. + +5. User calls mindfresults() to get a solution + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]. Some solvers can utilize a good + initial point to seed computations. + + As of ALGLIB 4.04, the initial point is: + * used by GDEMO + + If the chosen solver does not need initial point, one can + supply zeros. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + +IMPORTANT: the MINDF optimizer supports parallel model evaluation + ('callback parallelism'). This feature, which is present in + commercial ALGLIB editions, greatly accelerates algorithms like + differential evolution which usually issue batch requests to + user callbacks which can be efficiently parallelized. + + Callback parallelism is usually beneficial when the batch + evalution requires more than several milliseconds. + + See ALGLIB Reference Manual, 'Working with commercial version' + section, and comments on mindfoptimize() function for more + information. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfcreate(const ae_int_t n, const real_1d_array &x, mindfstate &state, const xparams _xparams = alglib::xdefault); +void mindfcreate(const real_1d_array &x, mindfstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints. + +Box constraints are inactive by default (after initial creation). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + + -- ALGLIB -- + Copyright 24.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetbc(mindfstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetlc2dense(mindfstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void mindfsetlc2dense(mindfstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided nonlinear constraints. + +In fact, this function sets only NUMBER of the nonlinear constraints. +Constraints themselves (constraint functions) are passed to the +MinDFOptimize() method. + +This method accepts user-defined vector function F[] where: +* first component of F[] corresponds to the objective +* subsequent NNLC components of F[] correspond to the two-sided nonlinear + constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinDFCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + +NOTE 2: the algorithm scales variables according to the scale specified by + MinDFSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints. We recommend you to scale + nonlinear constraints in such a way that the derivatives (if + constraints are differentiable) have approximately unit magnitude + (for problems with unit variable scales) or have magnitudes + approximately equal to 1/S[i] (where S is a variable scale set by + MinDFSetScale() function). + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetnlc2(mindfstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams = alglib::xdefault); +void mindfsetnlc2(mindfstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function sets a combined stopping condition: stopping when two +criteria are met simultaneously: +* function values has converged to a neighborhood whose size is + proportional to epsF +* variable values has converged to a neighborhood whose size is + proportional to epsX +It is possible to use only one condition by setting another EPS to zero. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + EpsX - >=0: + * zero value means no condition for X + * EpsX>0 means stopping when the solver converged with + error in I-th variable less than EpsX*S[i], where S[i] + is a variable scale + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondfx(mindfstate &state, const double epsf, const double epsx, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates internal timers used to track time +spent in various parts of the solver (mostly, callbacks vs solver itself). + +When activated with this function, the following timings are stored in the +mindfreport structure fields: +* total time spend in the optimization +* time spent in the callback +* time spent in the solver itself + +See comments on mindfreport structure for more information about timers +and their accuracy. + +Timers are an essential part of reports that helps to find out where the +most time is spent and how to optimize the code. E.g., noticing that +significant amount of time is spent in numerical differentiation makes +obvious that ALGLIB-provided parallel numerical differentiation is needed. + +However, time measurements add noticeable overhead, about 50-100ns per +function call. In some applications it results in a significant slowdown, +that's why this option is inactive by default and should be manually +activated. + +INPUT PARAMETERS: + State - structure which stores algorithm state + UseTimers- true or false + +NOTE: when tracing is turned on with alglib::trace_file(), some derivative + free solvers may also perform internal, more detailed time + measurements, which are printed to the log file. + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfusetimers(mindfstate &state, const bool usetimers, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping condition for the optimizer: function values +has converged to a neighborhood whose size is proportional to epsF. + +Most derivarive-free solvers are heuristics, so the code used to implement +this stopping condition is an heuristic too. Usually 'proportional to EPS' +means that we are somewhere between Eps/10...Eps*10 away from the solution. +However, there are no warranties that the solver has actually converged +to something, although in practice it works well. + +The specific meaning of 'converging' is algorithm-dependent. It is +possible that some future ALGLIB optimizers will ignore this condition, +see comments on specific solvers for more info. This condition does not +work for multi-objective problems. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0: + * zero value means no condition for F + * EpsF>0 means stopping when the solver converged with + an error estimate less than EpsF*max(|F|,1) + + -- ALGLIB -- + Copyright 23.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetcondf(mindfstate &state, const double epsf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets variable scales. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances) and to +guide algorithm steps. + +The scale of a variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetscale(mindfstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinDFOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - the best point + so far and a function value at the point. For unconstrained problems + the function value is non-increasing (the most recent best point is + always at least not worse than the previous best one). However, it + can increase between iterations when solving constrained problems + (a better point may have higher objective value but smaller + constraint violation). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void mindfsetxrep(mindfstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of a running optimizer. It +should be called from a user-supplied callback when user decides that it +is time to "smoothly" terminate optimization process. As a result, the +optimizer stops at the point which was "current accepted" when the +termination request was submitted and returns error code 8 (successful +termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on an optimizer which is NOT running will have + no effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfrequesttermination(mindfstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets seed used by internal RNG. + +By default, a random seed is used, i.e. every time you run the solver, we +seed its generator with a new value obtained from the system-wide RNG. +Thus, the solver returns non-deterministic results. You can change such +a behavior by specifying a fixed positive seed value. + +INPUT PARAMETERS: + S - optimizer structure + SeedVal - seed value: + * positive values are used for seeding RNG with a + fixed seed, i.e. subsequent runs on the same + objective will return the same results + * non-positive seed means that a random seed is used + for every run, i.e. subsequent runs on the same + objective will return slightly different results + + -- ALGLIB -- + Copyright 26.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetseed(mindfstate &s, const ae_int_t seedval, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with an +automatic parameters selection. + +NOTE: a version with manually tuned parameters can be activated by calling + the mindfsetalgogdemofixed() function. + +The primary stopping condition for the solver is to stop after the specified +number of iterations. You can also specify additional criteria to stop +early: +* stop when subpopulation target values (2N+1 best individuals) are within + EPS from the best one so far (function values seem to converge) +* stop when both subpopulation target values AND subpopulation variable + values are within EPS from the best one so far + +The first condition is specified with mindfsetcondf(), the second one is +activated with mindfsetcondfx(). + +Both conditions are heuristics which may fail. Being 'within EPS from the +best value so far' in practice means that we are somewhere within +[0.1EPS,10EPS] from the true solution; however, on difficult problems +this condition may fire too early. + +Imposing an additional requirement that variable values have clustered too +may prevent us from premature stopping. However, on multi-extremal and/or +noisy problems too many individuals may be trapped away from the optimum, +preventing this condition from activation. + +ALGORITHM PROPERTIES: + +* the solver uses a variant of the adaptive parameter tuning strategy + called 'Success-History Based Parameter Adaptation for Differential + Evolution Ensemble' (SHADE) by Ryoji Tanabe and Alex Fukunaga. You do + not have to specify crossover probability and differential weight, the + solver will automatically choose the most appropriate strategy. + +* the solver can handle box, linear, nonlinear constraints. Linear and + nonlinear constraints are handled by means of an L1/L2 penalty. The + solver does not violate box constraints at any point, but may violate + linear and nonlinear ones. Penalty coefficient can be changed with the + mindfsetgdemopenalty() function. + +* the solver heavily depends on variable scales being available (specified + by means of mindfsetscale() call) and on box constraints with both lower + and upper bounds being available which are used to determine the search + region. It will work without box constraints and without scales, but + results are likely to be suboptimal. + +* the solver is SIMD-optimized and parallelized (in commercial ALGLIB + editions), with nearly linear scalability of parallel processing. + +* this solver is intended for finding solutions with up to several digits + of precision at best. Its primary purpose is to find at least some + solution to an otherwise intractable problem. + +IMPORTANT: derivative-free optimization is inherently less robust than the + smooth nonlinear programming, especially when nonsmoothness and + discontinuities are present. + + Derivative-free algorithms have less convergence guarantees + than their smooth counterparts. It is considered a normal + (although, obviously, undesirable) situation when a derivative- + -free algorithm fails to converge with desired precision. Having + 2 digits of accurasy is already a good result, on difficult + problems (high numerical noise, discontinuities) you may have + even less than that. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + PopSize - population size, >=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemo(mindfstate &state, const ae_int_t epochscnt, const ae_int_t popsize, const xparams _xparams = alglib::xdefault); +void mindfsetalgogdemo(mindfstate &state, const ae_int_t epochscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +ROBUST profile (the default option). + +The ROBUST profile is intended to facilitate explorative behavior and +robust convergence even on difficult multi-extremal problems. It comes at +the expense of increased running time even on easy problems. The QUICK +profile can be chosen if your problem is relatively easy to handle and you +prefer speed over robustness. In most cases, the QUICK profile is ~2x-3x +faster than the robust one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilerobust(mindfstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to use a +QUICK profile. + +The QUICK profile is intended to facilitate accelerated convergence on +medium-complexity problems at the cost of (sometimes) having premature +convergence on difficult and/or multi-extremal problems. The ROBUST +profile can be selected if you favor convergence warranties over speed. +In most cases, the ROBUST profile is ~2x-3x slower than the QUICK one. + +This function has effect only on adaptive GDEMO with automatic parameters +selection. It has no effect on fixed-parameters GDEMO or any other +solvers. + +IMPORTANT: this function does NOT change the optimization algorithm. If + you want to activate differential evolution solver, you still + have to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + + -- ALGLIB -- + Copyright 25.04.2024 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemoprofilequick(mindfstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine tells GDEMO differential evolution optimizer to handle +linear/nonlinear constraints by an L1/L2 penalty function. + +IMPORTANT: this function does NOT change the optimization algorithm. If + want to activate differential evolution solver, you still have + to call a proper mindfsetalgo???() function. + +INPUT PARAMETERS: + State - solver + Rho1, Rho2 - penalty parameters for constraint violations: + * Rho1 is a multiplier for L1 penalty + * Rho2 is a multiplier for L2 penalty + * Rho1,Rho2>=0 + * having both of them at zero means that some default + value will be chosen. + Ignored for problems with box-only constraints. + + L1 penalty is usually better at enforcing constraints, + but leads to slower convergence than L2 penalty. It is + possible to combine both kinds of penalties together. + + There is a compromise between constraint satisfaction + and optimality: high values of Rho mean that + constraints are satisfied with high accuracy but that + the target may be underoptimized due to numerical + difficulties. Small values of Rho mean that the + solution may grossly violate constraints. Choosing + good Rho is usually a matter of trial and error. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetgdemopenalty(mindfstate &state, const double rho1, const double rho2, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine sets optimization algorithm to the differential evolution +solver GDEMO (Generalized Differential Evolution Multiobjective) with the +manual parameters selection. + +Unlike DE with an automatic parameters selection this function requires +user to manually specify algorithm parameters. In the general case the +full-auto GDEMO is better. However, it has to spend some time finding out +properties of a problem being solved; furthermore, it is not allowed to +try potentially dangerous values of parameters that lead to premature +stopping. Manually tuning the solver to the specific problem at hand can +get 2x-3x better running time. + +Aside from that, the algorithm is fully equivalent to automatic GDEMO, and +we recommend you reading comments on mindfsetalgogdemo() for more +information about algorithm properties and stopping criteria. + +INPUT PARAMETERS: + State - solver + EpochsCnt - iterations count, >0. Usually the algorithm needs + hundreds of iterations to converge. + Strategy - specific DE strategy to use: + * 0 for DE/rand/1 + * 1 for DE/best/2 + * 2 for DE/current-to-best/1 + CrossoverProb- crossover probability, 0=0. Zero value means that the + default value (which is 10*N in the current version) + will be chosen. Good values are in 5*N...20*N, with + the smaller values being recommended for easy problems + and the larger values for difficult multi-extremal + and/or noisy tasks. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfsetalgogdemofixed(mindfstate &state, const ae_int_t epochscnt, const ae_int_t strategy, const double crossoverprob, const double differentialweight, const ae_int_t popsize, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mindfiteration(mindfstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM + +The MINDF optimizer supports parallel model evaluation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates optimization when using a solver which +issues batch requests, i.e. multiple requests for target values, which +can be computed independently by different threads. + +Callback parallelism is usually beneficial when processing a batch +request requires more than several milliseconds. It also requires the +solver which issues requests in convenient batches, e.g. the differential +evolution solver. + +See ALGLIB Reference Manual, 'Working with commercial version' section for +more information. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey + + +*************************************************************************/ +void mindfoptimize(mindfstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MinDF results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + + rep.f stores objective value at the solution + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 box constraints are inconsistent + * -1 inconsistent parameters were passed: + * penalty parameter is zero, but we have nonlinear + constraints set by MinDFsetnlc2() + * 1 successful termination according to a solver-specific + set of conditions + * 8 User requested termination via minnsrequesttermination() + + If you activated timers with mindfusetimers(), you can + also find out how much time was spent in various code parts: + * rep.timetotal - for a total time in seconds + * rep.timesolver - for a time spent in the solver itself + * rep.timecallback - for a time spent in user callbacks + See comments on mindfreport structure for more information + about timers and their accuracy. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfresults(const mindfstate &state, real_1d_array &x, mindfreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + +Buffered implementation of MinDFresults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 25.07.2023 by Bochkanov Sergey +*************************************************************************/ +void mindfresultsbuf(const mindfstate &state, real_1d_array &x, mindfreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LINEAR PROGRAMMING + +The subroutine creates LP solver. After initial creation it contains +default optimization problem with zero cost vector and all variables being +fixed to zero values and no constraints. + +In order to actually solve something you should: +* set cost vector with minlpsetcost() +* set variable bounds with minlpsetbc() or minlpsetbcall() +* specify constraint matrix with one of the following functions: + [*] minlpsetlc() for dense one-sided constraints + [*] minlpsetlc2dense() for dense two-sided constraints + [*] minlpsetlc2() for sparse two-sided constraints + [*] minlpaddlc2dense() to add one dense row to constraint matrix + [*] minlpaddlc2() to add one row to constraint matrix (compressed format) +* call minlpoptimize() to run the solver and minlpresults() to get the + solution vector and additional information. + +By default, LP solver uses best algorithm available. As of ALGLIB 3.17, +sparse interior point (barrier) solver is used. Future releases of ALGLIB +may introduce other solvers. + +User may choose specific LP algorithm by calling: +* minlpsetalgodss() for revised dual simplex method with DSE pricing and + bounds flipping ratio test (aka long dual step). Large-scale sparse LU + solverwith Forest-Tomlin update is used internally as linear algebra + driver. +* minlpsetalgoipm() for sparse interior point method + +INPUT PARAMETERS: + N - problem size + +OUTPUT PARAMETERS: + State - optimizer in the default state + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpcreate(const ae_int_t n, minlpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets LP algorithm to revised dual simplex method. + +ALGLIB implementation of dual simplex method supports advanced performance +and stability improvements like DSE pricing , bounds flipping ratio test +(aka long dual step), Forest-Tomlin update, shifting. + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-7. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when relative error is less than Eps. + +===== TRACING DSS SOLVER ================================================= + +DSS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'DSS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'DSS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'DSS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("DSS,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgodss(minlpstate &state, const double eps, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets LP algorithm to sparse interior point method. + +ALGORITHM INFORMATION: + +* this algorithm is our implementation of interior point method as + formulated by R.J.Vanderbei, with minor modifications to the algorithm + (damped Newton directions are extensively used) +* like all interior point methods, this algorithm tends to converge in + roughly same number of iterations (between 15 and 50) independently from + the problem dimensionality + +INPUT PARAMETERS: + State - optimizer + Eps - stopping condition, Eps>=0: + * should be small number about 1E-6 or 1E-8. + * zero value means that solver automatically selects good + value (can be different in different ALGLIB versions) + * default value is zero + Algorithm stops when primal error AND dual error AND + duality gap are less than Eps. + +===== TRACING IPM SOLVER ================================================= + +IPM solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'IPM' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'IPM.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'IPM'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("IPM,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 08.11.2020 by Bochkanov Sergey +*************************************************************************/ +void minlpsetalgoipm(minlpstate &state, const double eps, const xparams _xparams = alglib::xdefault); +void minlpsetalgoipm(minlpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets cost term for LP solver. + +By default, cost term is zero. + +INPUT PARAMETERS: + State - structure which stores algorithm state + C - cost term, array[N]. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetcost(minlpstate &state, const real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients. + +ALGLIB optimizers use scaling matrices to test stopping conditions and as +preconditioner. + +Scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the + function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetscale(minlpstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +different constraints for different variables). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call, overwritten with minlpsetbcall(), or partially +overwritten with minlmsetbci() call. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + BndU - upper bounds, array[N]. + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: if constraints for all variables are same you may use minlpsetbcall() + which allows to specify constraints without using arrays. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbc(minlpstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for LP solver (all variables at once, +same constraints for all variables) + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. Constraint status +is preserved until constraints are explicitly overwritten with another +minlpsetbc() call or partially overwritten with minlpsetbcall(). + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bound, same for all variables + BndU - upper bound, same for all variables + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbcall(minlpstate &state, const double bndl, const double bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints for I-th variable (other variables are +not modified). + +The default state of constraints is to have all variables fixed at zero. +You have to overwrite it by your own constraint vector. + +Following types of constraints are supported: + + DESCRIPTION CONSTRAINT HOW TO SPECIFY + fixed variable x[i]=Bnd[i] BndL[i]=BndU[i] + lower bound BndL[i]<=x[i] BndU[i]=+INF + upper bound x[i]<=BndU[i] BndL[i]=-INF + range BndL[i]<=x[i]<=BndU[i] ... + free variable - BndL[I]=-INF, BndU[I]+INF + +INPUT PARAMETERS: + State - structure stores algorithm state + I - variable index, in [0,N) + BndL - lower bound for I-th variable + BndU - upper bound for I-th variable + +NOTE: infinite values can be specified by means of Double.PositiveInfinity + and Double.NegativeInfinity (in C#) and alglib::fp_posinf and + alglib::fp_neginf (in C++). + +NOTE: you may replace infinities by very small/very large values, but it + is not recommended because large numbers may introduce large numerical + errors in the algorithm. + +NOTE: minlpsetbc() can be used to specify different constraints for + different variables. + +NOTE: BndL>BndU will result in LP problem being recognized as infeasible. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetbci(minlpstate &state, const ae_int_t i, const double bndl, const double bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets one-sided linear constraints A*x ~ AU, where "~" can be +a mix of "<=", "=" and ">=". + +IMPORTANT: this function is provided here for compatibility with the rest + of ALGLIB optimizers which accept constraints in format like + this one. Many real-life problems feature two-sided constraints + like a0 <= a*x <= a1. It is really inefficient to add them as a + pair of one-sided constraints. + + Use minlpsetlc2dense(), minlpsetlc2(), minlpaddlc2() (or its + sparse version) wherever possible. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N+1]. Each row of A represents + one constraint, with first N elements being linear coefficients, + and last element being right side. + CT - constraint types, array[K]: + * if CT[i]>0, then I-th constraint is A[i,*]*x >= A[i,n] + * if CT[i]=0, then I-th constraint is A[i,*]*x = A[i,n] + * if CT[i]<0, then I-th constraint is A[i,*]*x <= A[i,n] + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A and CT. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc(minlpstate &state, const real_2d_array &a, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minlpsetlc(minlpstate &state, const real_2d_array &a, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU. + +This version accepts dense matrix as input; internally LP solver uses +sparse storage anyway (most LP problems are sparse), but for your +convenience it may accept dense inputs. This function overwrites linear +constraints set by previous calls (if such calls were made). + +We recommend you to use sparse version of this function unless you solve +small-scale LP problem (less than few hundreds of variables). + +NOTE: there also exist several versions of this function: + * one-sided dense version which accepts constraints in the same + format as one used by QP and NLP solvers + * two-sided sparse version which accepts sparse matrix + * two-sided dense version which allows you to add constraints row by row + * two-sided sparse version which allows you to add constraints row by row + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2dense(minlpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minlpsetlc2dense(minlpstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpsetlc2(minlpstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +This version accepts dense constraint vector as input, but sparsifies it +for internal storage and processing. Thus, time to add one constraint in +is O(N) - we have to scan entire array of length N. Sparse version of this +function is order of magnitude faster for constraints with just a few +nonzeros per row. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2dense(minlpstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minlpcreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minlpaddlc2(minlpstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function solves LP problem. + +INPUT PARAMETERS: + State - algorithm state + +You should use minlpresults() function to access results after calls to +this function. + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey. +*************************************************************************/ +void minlpoptimize(minlpstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LP solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution (on failure: last trial point) + Rep - optimization report. You should check Rep.TerminationType, + which contains completion code, and you may check another + fields which contain another information about algorithm + functioning. + + Failure codes returned by algorithm are: + * -4 LP problem is primal unbounded (dual infeasible) + * -3 LP problem is primal infeasible (dual unbounded) + * -2 IPM solver detected that problem is either + infeasible or unbounded + + Success codes: + * 1..4 successful completion + * 5 MaxIts steps was taken + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresults(const minlpstate &state, real_1d_array &x, minlpreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LP results + +Buffered implementation of MinLPResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 11.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minlpresultsbuf(const minlpstate &state, real_1d_array &x, minlpreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + DERIVATIVE-FREE NONLINEAR LEAST SQUARES + +DESCRIPTION: + +This function creates a NLS solver configured to solve a constrained +nonlinear least squares problem + + min F(x) = f[0]^2 + f[1]^2 + ... + f[m-1]^2 + +where f[i] are available, but not their derivatives. + +The functions f[i] are assumed to be smooth, but may have some +amount of numerical noise (either random noise or deterministic noise +arising from numerical simulations or other complex numerical processes). + +INPUT PARAMETERS: + N - dimension, N>1 + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + M - number of functions f[i], M>=1 + X - initial point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlscreatedfo(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nlsstate &state, const xparams _xparams = alglib::xdefault); +void nlscreatedfo(const ae_int_t m, const real_1d_array &x, nlsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +2PS (2-Point Stencil) algorithm. + +This solver is recommended for the following cases: +* an expensive target function is minimized by the commercial ALGLIB with + callback parallelism activated (see ALGLIB Reference Manual for more + information about parallel callbacks) +* an inexpensive target function is minimized by any ALGLIB edition (free + or commercial) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The 2PS algorithm is a derivative-free model-based nonlinear least squares +solver which builds local models by evaluating the target at N additional +points around the current one, with geometry similar to the 2-point finite +difference stencil. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. + +When compared with the DFO-LSA solver, the 2PS algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by the DFO-LSA) +* 2PS requires several times less iterations than the DFO-LSA because each + iteration extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets 2PS provides better parallelism potential than + DFO-LSA because the former issues many simultaneous target evaluation + requests which can be easily parallelized. It is possible for 2PS to + outperform DFO-LSA by parallelism alone, despite the fact that the + latter needs 3-4 times less target function evaluations. +* for inexpensive targets 2PS may win because it needs many times less + iterations, and thus the overhead associated with the working set updates + is also many times less. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgo2ps(nlsstate &state, const ae_int_t nnoisyrestarts, const xparams _xparams = alglib::xdefault); +void nlssetalgo2ps(nlsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets the derivative-free NLS optimization algorithm to the +DFO-LSA algorithm, an ALGLIB implementation (with several modifications)of +the original DFO-LS algorithm by Cartis, C., Fiala, J., Marteau, B. and +Roberts, L. ('Improving the Flexibility and Robustness of Model-Based +Derivative-Free Optimization Solvers', 2019). The A in DFO-LSA stands for +ALGLIB, in order to distinguish our slightly modified implementation from +the original algorithm. + +This solver is recommended for the following case: an expensive target +function is minimized without parallelism being used (either free ALGLIB +is used or commercial one is used but the target callback is non-reentrant +i.e. it can not be simultaneously called from multiple threads) + +This function works only with solvers created with nlscreatedfo(), i.e. in +the derivative-free mode. + +See the end of this comment for more information about the algorithm. + +INPUT PARAMETERS: + State - solver; must be created with nlscreatedfo() call - + passing an object initialized with another + constructor function will result in an exception. + NNoisyRestarts - number of restarts performed to combat a noise in + the target. (see below, section 'RESTARTS', for a + detailed discussion): + * 0 means that no restarts is performed, the + solver stops as soon as stopping criteria + are met. Recommended for noise-free tasks. + * >0 means that when the stopping criteria are + met, the solver will perform a restart: + increase the trust radius and resample + points. It often helps to solve problems + with random or deterministic noise. + +ALGORITHM DESCRIPTION AND DISCUSSION + +The DFO-LSA algorithm is a derivative-free model-based NLS solver which +builds local models by remembering N+1 previously computed target values +and updating them as optimization progresses. + +Similarly to the Levenberg-Marquardt algorithm, the solver shows quadratic +convergence despite the fact that it builds linear models. Our +implementation generally follows the same lines as the original DFO-LSA, +with several modifications to trust radius update strategies, stability +fixes (unlike original DFO-LS, our implementation can handle and recover +from the target breaking down due to infeasible arguments) and other minor +implementation details. + +When compared with the 2PS solver, the DFO-LSA algorithm has the following +distinctive properties: +* the 2PS algorithm performs more target function evaluations per iteration + (at least N+1 instead of 1-2 usually performed by DFO-LSA) +* 2PS requires several times less iterations than DFO-LSA because each + iterations extracts and utilizes more information about the target. This + difference tends to exaggerate when N increases +* contrary to that, DFO-LSA is much better at reuse of previously computed + points. Thus, DFO-LSA needs several times less target evaluations than + 2PS, usually about 3-4 times less (this ratio seems to be more or less + constant independently of N). + +The summary is that: +* for expensive targets DFO-LSA is much more efficient than 2PS because + it reuses previously computed target values as much as possible. +* however, DFO-LSA has little parallelism potential because (unlike 2PS) + it does not evaluate the target in several points simultaneously and + independently +* additionally, because DFO-LSA performs many times more iterations than + 2PS, iteration overhead (working set updates and matrix inversions) is + an issue here. For inexpensive targets it is possible for DFO-LSA to be + outperformed by 2PS merely because of the linear algebra cost. + +RESTARTS + +Restarts is a strategy used to deal with random and deterministic noise in +the target/constraints. + +Noise in the objective function can be random, arising from measurement or +simulation uncertainty, or deterministic, resulting from complex +underlying phenomena like numerical errors or branches in the target. Its +influence is especially high at last stages of the optimization, when all +computations are performed with small values of a trust radius. + +Restarts allow the optimization algorithm to be robust against both types +of noise by temporarily increasing a trust radius in order to capture a +global structure of the target and avoid being trapped by noise-produced +local features. + +A restart is usually performed when the stopping criteria are triggered. +Instead of stopping, the solver increases trust radius to its initial +value and tries to rebuild a model. + +If you decide to optimize with restarts, it is recommended to perform +a small amount of restarts, up to 5. Generally, restarts do not allow one +to completely solve the problem of noise, but still it is possible to +achieve some additional progress. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetalgodfolsa(nlsstate &state, const ae_int_t nnoisyrestarts, const xparams _xparams = alglib::xdefault); +void nlssetalgodfolsa(nlsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - stop when the scaled trust region radius is smaller than + EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection (small EpsX). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetcond(nlsstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLSOptimize(). + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetxrep(nlsstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets variable scales + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Generally, scale is NOT considered to be a form of preconditioner. But +derivative-free optimizers often use scaling matrix both in the stopping +condition tests and as a preconditioner. + +Proper scaling is very important for the algorithm performance. It is less +important for the quality of results, but still has some influence (it is +easier to converge when variables are properly scaled, so premature +stopping is possible when very badly scalled variables are combined with +relaxed stopping conditions). + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetscale(nlsstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets box constraints + +Box constraints are inactive by default (after initial creation). They are +preserved until explicitly turned off with another SetBC() call. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF (the latter is recommended). + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF (the latter is recommended). + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: unless explicitly mentioned in the specific NLS algorithm + description, the following holds: + * box constraints are always satisfied exactly + * the target is NOT evaluated outside of the box-constrained area + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlssetbc(nlsstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool nlsiteration(nlsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM + +The NLS optimizer supports parallel model evaluation ('callback +parallelism'). This feature, which is present in commercial ALGLIB +editions, greatly accelerates optimization when using a solver which +issues batch requests, i.e. multiple requests for target values, which +can be computed independently by different threads. + +Callback parallelism is usually beneficial when processing a batch +request requires more than several milliseconds. It also requires the +solver which issues requests in convenient batches, e.g. 2PS solver. + +See ALGLIB Reference Manual, 'Working with commercial version' section for +more information. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey + + +*************************************************************************/ +void nlsoptimize(nlsstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void nlsoptimize(nlsstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Nonlinear least squares solver results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report; includes termination codes and + additional information. Termination codes are returned in + rep.terminationtype field, its possible values are listed + below, see comments for this structure for more info. + + The termination code is a sum of a basic code (success or + failure) and one/several additional codes. Additional + codes are returned only for successful termination. + + The following basic codes can be returned: + * -8 optimizer detected NAN/INF values in the target or + nonlinear constraints and failed to recover + * -3 box constraints are inconsistent + * 2 relative step is no more than EpsX. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * 8 terminated by user who called nlsrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + + The following additional codes can be returned (added to + a basic code): + * +800 if during algorithm execution the solver + encountered NAN/INF values in the target or + constraints but managed to recover by reducing + trust region radius, the solver returns one + of SUCCESS codes but adds +800 to the code. + + -- ALGLIB -- + Copyright 15.10.2023 by Bochkanov Sergey +*************************************************************************/ +void nlsresults(const nlsstate &state, real_1d_array &x, nlsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Buffered implementation of NLSResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 10.03.2009 by Bochkanov Sergey +*************************************************************************/ +void nlsresultsbuf(const nlsstate &state, real_1d_array &x, nlsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts solver from the new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - optimizer + X - new starting point. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nlsrestartfrom(nlsstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void nlsrequesttermination(nlsstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + BOUND CONSTRAINED OPTIMIZATION + WITH ADDITIONAL LINEAR EQUALITY AND INEQUALITY CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BLEIC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBLEICCreate() call + +2. USer adds boundary and/or linear constraints by calling + MinBLEICSetBC() and MinBLEICSetLC() functions. + +3. User sets stopping conditions with MinBLEICSetCond(). + +4. User calls MinBLEICOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBLEICResults() to get solution + +6. Optionally user may call MinBLEICRestartFrom() to solve another problem + with same N but another starting point. + MinBLEICRestartFrom() allows to reuse already initialized structure. + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreate(const ae_int_t n, const real_1d_array &x, minbleicstate &state, const xparams _xparams = alglib::xdefault); +void minbleiccreate(const real_1d_array &x, minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +The subroutine is finite difference variant of MinBLEICCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBLEICCreate() in order to get +more information about creation of BLEIC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBLEICSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleiccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbleicstate &state, const xparams _xparams = alglib::xdefault); +void minbleiccreatef(const real_1d_array &x, const double diffstep, minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for BLEIC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +NOTE: if you have box-only constraints (no general linear constraints), + then MinBC optimizer can be better option. It uses special, faster + constraint activation method, which performs better on problems with + multiple constraints active at the solution. + + On small-scale problems performance of MinBC is similar to that of + MinBLEIC, but on large-scale ones (hundreds and thousands of active + constraints) it can be several times faster than MinBLEIC. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbc(minbleicstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear constraints for BLEIC optimizer. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBLEICRestartFrom(). + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: linear (non-bound) constraints are satisfied only approximately: +* there always exists some minor violation (about Epsilon in magnitude) + due to rounding errors +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetlc(minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minbleicsetlc(minbleicstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBLEICSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BLEIC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetcond(minbleicstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for BLEIC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BLEIC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBLEICSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetscale(minbleicstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdefault(minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecdiag(minbleicstate &state, const real_1d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBLEICSetScale() +call (before or after MinBLEICSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetprecscale(minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBLEICOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetxrep(minbleicstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +IMPORTANT: this feature is hard to combine with preconditioning. You can't +set upper limit on step length, when you solve optimization problem with +linear (non-boundary) constraints AND preconditioner turned on. + +When non-boundary constraints are present, you have to either a) use +preconditioner, or b) use upper limit on step length. YOU CAN'T USE BOTH! +In this case algorithm will terminate with appropriate error code. + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetstpmax(minbleicstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minbleiciteration(minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinBLEICCreate() for analytical gradient or MinBLEICCreateF() + for numerical differentiation) you should choose appropriate variant of + MinBLEICOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinBLEICOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinBLEICOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinBLEICOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinBLEICCreateF() | work FAIL + MinBLEICCreate() | FAIL work + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinBLEICOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinBLEICCreateF() + and to pass gradient information to MinBLEICOptimize()) will lead to + exception being thrown. Either you did not pass gradient when it WAS + needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey + + +*************************************************************************/ +void minbleicoptimize(minbleicstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minbleicoptimize(minbleicstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbleicoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbleicsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardgradient(minbleicstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardsmoothness(minbleicstate &state, const ae_int_t level, const xparams _xparams = alglib::xdefault); +void minbleicoptguardsmoothness(minbleicstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbleicoptguardgradient() for gradient verification +* minbleicoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbleicoptguardnonc1test0results() +* minbleicoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardresults(minbleicstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test0results(const minbleicstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbleicoptguardnonc1test1results(minbleicstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +BLEIC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. Feasible point is + either nonexistent or too hard to find. Try to + restart optimizer with better initial approximation + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbleicrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBLEICReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresults(const minbleicstate &state, real_1d_array &x, minbleicreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +BLEIC results + +Buffered implementation of MinBLEICResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicresultsbuf(const minbleicstate &state, real_1d_array &x, minbleicreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBLEICCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicrestartfrom(minbleicstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbleicrequesttermination(minbleicstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONLINEARLY CONSTRAINED OPTIMIZATION + +DESCRIPTION: +The subroutine minimizes a function F(x) of N arguments subject to the +any combination of the: +* box constraints +* linear equality/inequality/range constraints CL<=Ax<=CU +* nonlinear equality/inequality/range constraints HL<=Hi(x)<=HU + +REQUIREMENTS: +* F(), H() are continuously differentiable on the feasible set and its + neighborhood +* starting point X0, which can be infeasible + +USAGE: + +Here we give the very brief outline of the MinNLC optimizer. We strongly +recommend you to study examples in the ALGLIB Reference Manual and to read +ALGLIB User Guide: https://www.alglib.net/nonlinear-programming/ + +1. The user initializes the solver with minnlccreate() or minnlccreatef(), + depending on the specific solver chosen: + * minnlccreate() for solvers capable of handling the problem 'as is', + without relying on numerical differentiation (SQP/GIPM2 for problems + with analytic derivatives, ORBIT for derivative-free problems) + * minnlccreatef(), when a numerical differentiation is used to provide + derivatives to a smooth derivative-based solver (SQP or GIPM2). + + In the current release the following solvers can be used: + + * sparse large-scale filter-based SQP solver, recommended for problems + of any size (from several variables to hundreds of thousands of + variables). Good at warm-starts. Activated with the minnlcsetalgosqp() + function. + + * sparse large-scale nonlinear nonconvex interior point method (GIPM2), + recommended for problems of any size (from several variables to + hundreds of thousands of variables). Has lower iteration overhead + than SQP, but is worse at using good initial points (it will need + at least tens of iterations even when started from the solution). + Activated with minnlcsetalgogipm2() function. + + * dense SQP-BFGS solver, recommended for small-scale problems (up to + several hundreds of variables). Requires less function evaluations + than SQP, but has more expensive iteration. + Activated with minnlcsetalgosqpbfgs() function. + + * ORBIT, a model-based derivative free solver that uses local RBF + models to optimize expensive objectives. This solver is activated + with minnlcsetalgoorbit() function. + + * several other solvers, including legacy ones + +2. [optional] user activates OptGuard integrity checker which tries to + detect possible errors in the user-supplied callbacks: + * discontinuity/nonsmoothness of the target/nonlinear constraints + * errors in the analytic gradient provided by user + This feature is essential for early prototyping stages because it helps + to catch common coding and problem statement errors. + OptGuard can be activated with following functions (one per each check + performed): + * minnlcoptguardsmoothness() + * minnlcoptguardgradient() + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minnlcsetbc() for boundary constraints + b) minnlcsetlc2() for sparse two-sided linear constraints, + minnlcsetlc2dense() for dense two-sided linear constraints, + minnlcsetlc2mixed() for mixed sparse/dense two-sided linear constraints + * minqpaddlc2dense() to add one dense row to the dense constraint submatrix + * minqpaddlc2() to add one sparse row to the sparse constraint submatrix + * minqpaddlc2sparsefromdense() to add one sparse row (passed as a dense array) to the sparse constraint submatrix + c) minnlcsetnlc2() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minnlcsetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + Knowing variable scales helps to check stopping criteria and + precondition the solver. + +5. User sets stopping conditions with minnlcsetcond3() or minnlcsetcond(). + If NLC solver uses inner/outer iteration layout, this function sets + stopping conditions for INNER iterations. + +6. Finally, user calls minnlcoptimize() function which takes algorithm + state and pointer (delegate, etc.) to callback function which calculates + F/G/H. + +7. User calls minnlcresults() to get solution; additionally you can + retrieve OptGuard report with minnlcoptguardresults(), and get detailed + report about purported errors in the target function with: + * minnlcoptguardnonc1test0results() + * minnlcoptguardnonc1test1results() + +8. Optionally user may call minnlcrestartfrom() to solve another problem + with same N but another starting point. minnlcrestartfrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreate(const ae_int_t n, const real_1d_array &x, minnlcstate &state, const xparams _xparams = alglib::xdefault); +void minnlccreate(const real_1d_array &x, minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Buffered version of minnlccreate() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.10.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatebuf(const ae_int_t n, const real_1d_array &x, minnlcstate &state, const xparams _xparams = alglib::xdefault); +void minnlccreatebuf(const real_1d_array &x, minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine is a finite difference variant of MinNLCCreate(). It uses +finite differences in order to differentiate target function. + +This function is relevant when you want to solve a derivative-free problem +using a solver that relies on gradient info being available (e.g. SQP or +GIPM2). Do not use it for derivative-free solvers like ORBIT, the algo +will generate an exception during optimization. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinNLCCreate() in order to get more +information about creation of the NLC optimizer. + +CALLBACK PARALLELISM + +The MINNLC optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, >0. + By default, a 5-point formula is used (actually, only 4 + function values per variable are used because the central + one has zero coefficient due to symmetry; that's why this + formula is often called a 4-point one). It can be changed + with minnlcsetnumdiff() function. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTES: + +1. the differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinNLCSetScale() call. + +2. we recommend you to use moderate values of differentiation step. Too + large step will result in too large TRUNCATION errors, while too small + step will result in too large NUMERICAL errors. 1.0E-4 can be good + value to start from. + +3. Numerical differentiation is very inefficient - one gradient + calculation needs ~N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems or near the + solution. + + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams = alglib::xdefault); +void minnlccreatef(const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Buffered version of minnlccreatef() which reuses already allocated memory +as much as possible. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlccreatefbuf(const ae_int_t n, const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams = alglib::xdefault); +void minnlccreatefbuf(const real_1d_array &x, const double diffstep, minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for NLC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine boundary constraints with general linear ones - and with +nonlinear ones! Boundary constraints are handled more efficiently than +other types. Thus, if your problem has mixed constraints, you may +explicitly specify some of them as boundary and save some time/space. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: when you solve your problem with augmented Lagrangian solver, + boundary constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetbc(minnlcstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear constraints for MinNLC optimizer. + +Linear constraints are inactive by default (after initial creation). They +are preserved after algorithm restart with MinNLCRestartFrom(). + +You may combine linear constraints with boundary ones - and with nonlinear +ones! If your problem has mixed constraints, you may explicitly specify +some of them as linear. It may help optimizer to handle them more +efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE 1: when you solve your problem with augmented Lagrangian solver, + linear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + feasible area! + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc(minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minnlcsetlc(minnlcstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2dense(minnlcstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minnlcsetlc2dense(minnlcstate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2(minnlcstate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +a mixed constraining matrix A including a sparse part (first SparseK rows) +and a dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you may store them in sparse +format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetlc2mixed(minnlcstate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends a two-sided linear constraint AL <= A*x <= AU to the +matrix of dense constraints. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 15.04.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2dense(minnlcstate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint is passed in compressed format: as list of non-zero entries of +coefficient vector A. Such approach is more efficient than dense storage +for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2(minnlcstate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minnlccreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcaddlc2sparsefromdense(minnlcstate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets nonlinear constraints for MinNLC optimizer. + +It sets constraints of the form + + Ci(x)=0 for i=0..NLEC-1 + Ci(x)<=0 for i=NLEC..NLEC+NLIC-1 + +See MinNLCSetNLC2() for a modern function which allows greater flexibility +in the constraint specification. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc(minnlcstate &state, const ae_int_t nlec, const ae_int_t nlic, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinNLC optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinNLCOptimize() method as callbacks. + +MinNLCOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first element of F[] and first row of J[] correspond to the target +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinNLCSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinNLCSetScale() function). + + -- ALGLIB -- + Copyright 23.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnlc2(minnlcstate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams = alglib::xdefault); +void minnlcsetnlc2(minnlcstate &state, const real_1d_array &nl, const real_1d_array &nu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets specific finite difference formula to be used for +numerical differentiation. + +It works only for optimizers created with minnlccreatef() function; in +other cases it has no effect. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreateF call. + FormulaType - formula type: + * 5 for a 5-point formula (actually, only 4 values per + variable are used, ones at x+h, x+h/2, x-h/2 and + x-h; the central one has zero multiplier due to + symmetry). The most precise and the most expensive + option, chosen by default + * 3 for a 3-point formula, which is also known as a + symmetric difference quotient (the formula actually + uses only two function values per variable: at x+h + and x-h). A good compromise for medium-accuracy + setups + * 2 for a forward (or backward, depending on variable + bounds) finite difference (f(x+h)-f(x))/h. This + formula has the lowest accuracy. However, it is 4x + faster than the 5-point formula and 2x faster than + the 3-point one because, in addition to the central + value f(x), it needs only one additional function + evaluation per variable. + + + -- ALGLIB -- + Copyright 03.12.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetnumdiff(minnlcstate &state, const ae_int_t formulatype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set iterations limit and step-based stopping +conditions. If you want the solver to stop upon having a small change in +the target, use minnlcsetcond3() function. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond(minnlcstate &state, const double eps, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +This function allows to set three types of stopping conditions: +* iterations limit +* stopping upon performing a short step (depending on the specific solver + being used it may stop as soon as the first short step was made, or + only after performing several sequential short steps) +* stopping upon having a small change in the target (depending on the + specific solver being used it may stop as soon as the first step with + small change in the target was made, or only after performing several + sequential steps) + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The optimizer will stop as soon as the following condition + is met: + + |f_scl(k+1)-f_scl(k)| <= max(|f_scl(k+1)|,|f_scl(k)|,1) + + where f_scl is an internally used by the optimizer rescaled + target (ALGLIB optimizers usually apply rescaling in order + to normalize target and constraints). + Eps - >=0, specific meaning depends on the algorithm: + * for GIPM2 - stop when primal/dual/compl errors are less + than Eps + * for SQP-based solvers - stop when the scaled trust region + radius is less than Eps + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF, EpsX=0 and MaxIts=0 (simultaneously) will lead to the +automatic selection of the stopping condition. + + -- ALGLIB -- + Copyright 21.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetcond3(minnlcstate &state, const double epsf, const double eps, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scales +are also used by the finite difference variant of the optimizer - the step +along I-th axis is equal to DiffStep*S[I]. Finally, variable scales are +used for preconditioning (i.e. to speed up the solver). + +The scale of the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 06.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetscale(minnlcstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length (after scaling of step vector with +respect to variable scales specified by minnlcsetscale() call). + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0 (default), if + you don't want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which leads to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + +NOTE: different solvers employed by MinNLC optimizer may use different + norms for the step. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetstpmax(minnlcstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells MinNLC unit to use the large-scale augmented Lagrangian +algorithm for nonlinearly constrained optimization. + +This algorithm is a significant refactoring of one described in "A +Modified Barrier-Augmented Lagrangian Method for Constrained Minimization +(1999)" by D.GOLDFARB, R.POLYAK, K. SCHEINBERG, I.YUZEFOVICH with the +following additions: +* improved sparsity support +* improved handling of large-scale problems with the low rank LBFGS-based + sparse preconditioner +* automatic selection of the penalty parameter Rho + +AUL solver can be significantly faster than SQP on easy problems due to +cheaper iterations, although it needs more function evaluations. On large- +scale sparse problems one iteration of the AUL solver usually costs tens +times less than one iteration of the SQP solver. + +However, the SQP solver is more robust than the AUL. In particular, it is +much better at constraint enforcement and will never escape feasible area +after constraints were successfully enforced. It also needs much less +target function evaluations. + +INPUT PARAMETERS: + State - structure which stores algorithm state + MaxOuterIts-upper limit on outer iterations count: + * MaxOuterIts=0 means that the solver will automatically + choose an upper limit. Recommended value. + * MaxOuterIts>1 means that the AUL solver will performs at + most specified number of outer iterations + + -- ALGLIB -- + Copyright 22.09.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoaul2(minnlcstate &state, const ae_int_t maxouterits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the sparse l-BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. +> + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qp(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects a legacy solver: an L1 merit function based SQP with +the dense BFGS update. + +It is recommended to use either SQP or SQP-BFGS solvers instead of this +one. These solvers use filters to provide much faster and robust +convergence. + + -- ALGLIB -- + Copyright 02.12.2019 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosl1qpbfgs(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects large-scale sparse filter-based SQP solver, the +most robust solver in ALGLIB, a recommended option. + +This algorithm is scalable to problems with millions of variables and can +efficiently handle sparsity of constraints. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqp(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects ORBIT solver, a model-based derivative-free solver +for minimization of expensive derivative-free functions. + +The ORBIT algorithm by Wild and Shoemaker (2013) is an algorithm that uses +objective function values to build a smooth RBF model (f=r^3) that is +minimized over a trust region in order to identify step direction. The +algorithm saves and reuses function values at all previously known points. + +ALGLIB added to the original algorithm the following modifications: +* box, linear and nonlinear constraints +* improved tolerance to noise in the objective/constraints + +Its intended area of application is a low-accuracy minimization of +expensive objectives with no gradient available. It is expected that +additional overhead of building and minimizing an RBF model is negligible +when compared with the objective evaluation cost. Iteration overhead grows +as O(N^3), so this solver is recommended for problems with N below 100. + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear and nonlinear constraints are enforced, the algorithm will + try to respect them as much as possible. + +When compared with SQP solver, ORBIT: +* is much faster than the finite-difference based serial SQP at early + stages of optimization, being able to achieve 0.1-0.01 relative accuracy + about 4x-10x faster than SQP solver +* has slower asymptotic convergence on ill-conditioned problems, sometimes + being unable to reduce error in objective or constraints below 1E-5 in + a reasonable amount of time +* has no obvious benefits over SQP with analytic gradient or highly + parallelized (more than 10 cores) finite-difference SQP + +NOTE: whilst technically this algorithm supports callback parallelism, in + practice it can't efficiently utilize parallel resources because it + issues requests for objective/constraints in an inherently serial + manner. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + Rad0 - initial sampling radius (multiplied by per-variable + scales), Rad0>=0, zero value means automatic radius + selection. + An ideal value is large enough to allow significant + progress by making a Rad0-sized step, but not too large + (so that initial linear model well approximates the + objective). + Recommended values: 0.1 or 1 (assuming properly chosen + variable scales. + The solver can tolerate inappropriately chosen Rad0, at + the expense of additional function evaluations needed to + adjust it. + + MaxNFEV - MaxNFEV>=0, with zero value meaning no limit. This + parameter allows to control computational budget (measured + in function evaluations). + + It provides somewhat finer control than MaxIts parameter + of minnlcsetcond(), which controls the maximum amount of + iterations performed by the algorithm, with one iteration + usually needing more than one function evaluation. + + The solver does not stop immediately after reaching + MaxNFEV evaluations, but will stop shortly after that + (usually within N+1 evaluations, often within 1-2). + + -- ALGLIB -- + Copyright 02.10.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgoorbit(minnlcstate &state, const double rad0, const ae_int_t maxnfev, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects a SQP solver specialized on low-dimensional problems +- dense filter-based SQP-BFGS solver. + +This algorithm uses a dense quadratic model of the target and solves a +dense QP subproblem at each step. Thus, it has difficulties scaling beyond +several hundreds of variables. However, it usually needs the smallest +number of the target evaluations - sometimes up to 30% less than the +sparse large-scale filter-based SQP. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* once linear constraints are enforced, the algorithm will not violate them +* no such guarantees can be provided for nonlinear constraints, but once + nonlinear constraints are enforced, the algorithm will try to respect + them as much as possible +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes most time when solving + large-scale problems). It can also use a performance backend + (e.g. Intel MKL or another platform-specific library) to + accelerate dense factorization. + + Dense Cholesky factorization is a well studied and optimized + algorithm. ALGLIB includes a well optimized implementation; + however, using a hardware vendor-provided performance library + usually results in a better performance. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING SQP SOLVER ================================================= + +SQP solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'SQP' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + It also prints OptGuard integrity checker report when + nonsmoothness of target/constraints is suspected. +* 'SQP.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'SQP'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'SQP.PROBING' - to let algorithm insert additional function evaluations + before line search in order to build human-readable + chart of the raw Lagrangian (~40 additional function + evaluations is performed for each line search). This + symbol also implicitly defines 'SQP' and activates + OptGuard integrity checker which detects continuity and + smoothness violations. An OptGuard log is printed at the + end of the file. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. Specifying 'SQP.PROBING' adds even larger +overhead due to additional function evaluations being performed. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("SQP,SQP.PROBING,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.12.2023 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgosqpbfgs(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function selects large-scale sparse interior point solver (GIPM2). + +This algorithm is scalable to problems with hundreds of thousands of +variables and can efficiently handle sparsity of constraints. + +When compared to SQP, the following differences can be noted: +* GIPM2 has lower iteration overhead than SQP +* GIPM2 violates all non-box constraints (linear and nonlinear, equality + and inequality ones) until it finally converges. Contrary to that, SQP + respects linear constraints after initial enforcement, and tends to + closely follow nonlinear ones. +* as all interior point methods, GIPM2 is bad at hot starts. Even if + started from solution, it will perform at least 30-60 iterations (first, + it will move away from the solution to find a centered initial point, + then it will converge back along the central path). + +The shorty summary is that SQP wins when starting close to the solution, +and GIPM2 tends to win on large-scale sparse problems where constraint +factorization adds significant linear algebra overhead. + +The convergence is proved for the following case: +* function and constraints are continuously differentiable (C1 class) + +This algorithm has the following nice properties: +* no parameters to tune +* no convexity requirements for target function or constraints +* the initial point can be infeasible +* the algorithm respects box constraints in all intermediate points (it + does not even evaluate the target outside of the box constrained area) +* numerical differentiation does not violate box constraints (although + general linear and nonlinear ones can be violated during differentiation) + + +IMPORTANT: the commercial edition of ALGLIB can parallelize factorization + phase of this function (this phase takes significant amounts of + time when solving large-scale problems). It can also use a + performance backend (e.g. Intel PARDISO or another platform- + specific library) to accelerate sparse factorization. + + Specific speed-up due to parallelism and performance backend + usage heavily depends on the sparsity pattern of constraints. + For some problem types performance backends provide great + speed-up. For other ones, ALGLIB's own sparse factorization + code is the preferred option. + + See the ALGLIB Reference Manual for more information on how to + activate parallelism and backend support. + + +INPUT PARAMETERS: + State - structure which stores algorithm state + +===== TRACING GIPM2 SOLVER =============================================== + +GIPM2 solver supports advanced tracing capabilities. You can trace +algorithm output by specifying following trace symbols (case-insensitive) +by means of trace_file() call: +* 'GIPM2' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("GIPM2,PREC.F6", "path/to/trace.log") +> + + -- ALGLIB -- + Copyright 02.02.2025 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetalgogipm2(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinNLCOptimize(). + +NOTE: algorithm passes two parameters to rep() callback - current point + and penalized function value at current point. Important - function + value which is returned is NOT function being minimized. It is sum + of the value of the function being minimized - and penalty term. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcsetxrep(minnlcstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minnlciteration(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + sjac - callback which calculates function vector fi[] + and sparse Jacobian sjac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +CALLBACK PARALLELISM + +The MINNLC optimizer supports parallel parallel numerical differentiation +('callback parallelism'). This feature, which is present in commercial +ALGLIB editions, greatly accelerates optimization with numerical +differentiation of an expensive target functions. + +Callback parallelism is usually beneficial when computing a numerical +gradient requires more than several milliseconds. In this case the job +of computing individual gradient components can be split between multiple +threads. Even inexpensive targets can benefit from parallelism, if you +have many variables. + +ALGLIB Reference Manual, 'Working with commercial version' section, tells +how to activate callback parallelism for your programming language. + +NOTES: + +1. This function has two different implementations: + * one which accepts objective/constraints values and their gradients + * and one which accepts only objective/constraints values + + The former function should be called when using solvers relying on + analytic gradients (SQP, GIPM2, etc). The latter one is intended for + derivative-free NLP solvers like ORBIT and, additionally, for numerical + differentiation based versions of SQP/GIPM2/etc. + + Be careful to choose variant of MinNLCOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinNLCOptimize() and specific + function used to create optimizer. + + + | PASSED TO MinNLCOptimize() + | | + PROBLEM SETUP | values only | values + | | and gradients + ----------------------------------------------------------------------- + MinNLCCreate()+SQP/GIPM2/AUL | FAILS + + MinNLCCreate()+ORBIT | + FAILS + MinNLCCreateF()+SQP/GIPM2/AUL | + FAILS + MinNLCCreateF()+ORBIT | FAILS FAILS + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and MinNLCOptimize() version. Any attempts to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 06.05.2025 by Bochkanov Sergey + + +*************************************************************************/ +void minnlcoptimize(minnlcstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minnlcoptimize(minnlcstate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minnlcoptimize(minnlcstate &state, + void (*sjac)(const real_1d_array &x, real_1d_array &fi, sparsematrix &s, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient/Jacobian. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function (constraints) at the +initial point (note: future versions may also perform check at the final +point) and compares numerical gradient/Jacobian with analytic one provided +by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients/Jacobians, and specific components highlighted +as suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minnlcoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minnlcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardgradient(minnlcstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) and/or constraints +b) nonsmooth target function (non-C1) and/or constraints + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + This kind of monitoring does not work well with SQP + because SQP solver needs just 1-2 function evaluations + per step, which is not enough for OptGuard to make + any conclusions. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardsmoothness(minnlcstate &state, const ae_int_t level, const xparams _xparams = alglib::xdefault); +void minnlcoptguardsmoothness(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minnlcoptguardgradient() for gradient verification +* minnlcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradfidx for specific function (Jacobian row) suspected + * rep.badgradvidx for specific variable (Jacobian column) suspected + * rep.badgradxbase, a point where gradient/Jacobian is tested + * rep.badgraduser, user-provided gradient/Jacobian + * rep.badgradnum, reference gradient/Jacobian obtained via numerical + differentiation +* rep.nonc0suspected, and additionally: + * rep.nonc0fidx - an index of specific function violating C0 continuity +* rep.nonc1suspected, and additionally + * rep.nonc1fidx - an index of specific function violating C1 continuity +Here function index 0 means target function, index 1 or higher denotes +nonlinear constraints. + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minnlcoptguardnonc1test0results() +* minnlcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardresults(minnlcstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test0results(const minnlcstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* fidx - is an index of the function (0 for target function, 1 or higher + for nonlinear constraints) which is suspected of being "non-C1" +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minnlcoptguardnonc1test1results(minnlcstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MinNLC results: the solution found, completion codes and additional +information. + +If you activated OptGuard integrity checking functionality and want to get +OptGuard report, it can be retrieved with: +* minnlcoptguardresults() - for a primary report about (a) suspected C0/C1 + continuity violations and (b) errors in the analytic gradient. +* minnlcoptguardnonc1test0results() - for C1 continuity violation test #0, + detailed line search log +* minnlcoptguardnonc1test1results() - for C1 continuity violation test #1, + detailed line search log + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + rep.f contains objective value at the solution. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient, recovery was + impossible. Abnormal termination signalled. + * -3 box constraints are infeasible. + Note: infeasibility of non-box constraints does + NOT trigger emergency completion; you have + to examine rep.bcerr/rep.lcerr/rep.nlcerr to + detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 1 small objective decrease indicates convergence + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 7 stopping conditions are too stringent, returning + the best point so far + * 8 user requested algorithm termination via + minnlcrequesttermination(), last accepted point is + returned. + + === ADDITIONAL CODES === + * +800 if during algorithm execution the solver + encountered NAN/INF values in the target or + constraints but managed to recover by reducing + trust region radius, the solver returns one + of SUCCESS codes but adds +800 to the code. + + Some solvers (as of ALGLIB 4.05, SQP and GIPM2) return + Lagrange multipliers in rep.lagbc/lagbcnz, laglc, lagnlc + fields. + + More information about fields of this structure can be + found in the comments on the minnlcreport datatype. + + -- ALGLIB -- + Copyright 18.01.2024 by Bochkanov Sergey +*************************************************************************/ +void minnlcresults(const minnlcstate &state, real_1d_array &x, minnlcreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +NLC results + +Buffered implementation of MinNLCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcresultsbuf(const minnlcstate &state, real_1d_array &x, minnlcreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minnlcrequesttermination(minnlcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinNLCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnlcrestartfrom(minnlcstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + MULTI-OBJECTIVE OPTIMIZATION + +DESCRIPTION: + +The solver minimizes an M-dimensional vector function F(x) of N arguments +subject to any combination of: +* box constraints +* two-sided linear equality/inequality constraints AL<=A*x<=AU, where some + of AL/AU can be infinite (i.e. missing) +* two-sided nonlinear equality/inequality constraints NL<=C(x)<=NU, where + some of NL/NU can be infinite (i.e. missing) + +REQUIREMENTS: +* F(), C() are continuously differentiable on the feasible set and on its + neighborhood + +USAGE: + +1. User initializes algorithm state using either: + * minmocreate() to perform optimization with user-supplied Jacobian + * minmocreatef() to perform optimization with numerical differentiation + +2. User chooses which multi-objective solver to use. At the present moment + only NBI (Normal Boundary Intersection) solver is implemented, which is + activated by calling minmosetalgonbi(). + +3. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) minmosetbc() for boundary constraints + b) minmosetlc2() for two-sided sparse linear constraints; + minmosetlc2dense() for two-sided dense linear constraints; + minmosetlc2mixed() for two-sided mixed sparse/dense constraints + c) minmosetnlc2() for two-sided nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +4. User sets scale of the variables with minmosetscale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +5. User sets stopping conditions with minmosetcond(). + +6. Finally, user calls minmooptimize() function which takes algorithm + state and pointers (delegate, etc.) to the callback functions which + calculate F/C + +7. User calls minmoresults() to get the solution + +8. Optionally user may call minmorestartfrom() to solve another problem + with same M,N but another starting point. minmorestartfrom() allows to + reuse an already initialized optimizer structure. + + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreate(const ae_int_t n, const ae_int_t m, const real_1d_array &x, minmostate &state, const xparams _xparams = alglib::xdefault); +void minmocreate(const ae_int_t m, const real_1d_array &x, minmostate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine is a finite difference variant of minmocreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on minmocreate() too. + +INPUT PARAMETERS: + N - variables count, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from the size of X + M - objectives count, M>0. + M=1 is possible, although makes little sense - it is better + to use MinNLC directly. + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to reinforce feasibility during initial stages of the + optimization + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure that stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is a scaling vector which can be set by minmosetscale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step means too large TRUNCATION errors, whilst too small step + means too large NUMERICAL errors. + 1.0E-4 can be good value to start from for a unit-scaled problem. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. Imprecise gradient may slow down + convergence, especially on highly nonlinear problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmocreatef(const ae_int_t n, const ae_int_t m, const real_1d_array &x, const double diffstep, minmostate &state, const xparams _xparams = alglib::xdefault); +void minmocreatef(const ae_int_t m, const real_1d_array &x, const double diffstep, minmostate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Use the NBI (Normal Boundary Intersection) algorithm for multiobjective +optimization. + +NBI is a simple yet powerful multiobjective optimization algorithm that +has the following attractive properties: +* it generates nearly uniformly distributed Pareto points +* it is applicable to problems with more than 2 objectives +* it naturally supports a mix of box, linear and nonlinear constraints +* it is less sensitive to the bad scaling of the targets + +The only drawback of the algorithm is that for more than 2 objectives it +can miss some small parts of the Pareto front that are located near its +boundaries. + +INPUT PARAMETERS: + State - structure which stores algorithm state + FrontSize - desired Pareto front size, FrontSize>=M, + where M is an objectives count + PolishSolutions-whether additional solution improving phase is needed + or not: + * if False, the original NBI as formulated by Das and + Dennis is used. It quickly produces good solutions, + but these solutions can be suboptimal (usually within + 0.1% of the optimal values). + The reason is that the original NBI formulation does + not account for degeneracies that allow significant + progress for one objective with no deterioration for + other objectives. + * if True, the original NBI is followed by the + additional solution polishing phase. This solver + mode is several times slower than the original NBI, + but produces better solutions. + + -- ALGLIB -- + Copyright 20.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetalgonbi(minmostate &state, const ae_int_t frontsize, const bool polishsolutions, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for the MO optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinMORestartFrom(). + +You may combine boundary constraints with general linear ones - and with +nonlinear ones! Boundary constraints are handled more efficiently than +other types. Thus, if your problem has mixed constraints, you may +explicitly specify some of them as boundary and save some time/space. + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + a very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetbc(minmostate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with dense +constraint matrix A. + +NOTE: knowing that constraint matrix is dense may help some MO solvers + to utilize efficient dense Level 3 BLAS for dense parts of the + problem. If your problem has both dense and sparse constraints, you + can use minmosetlc2mixed() function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraints, array[K,N]. Each row of A represents + one constraint. One-sided inequality constraints, two- + sided inequality constraints, equality constraints are + supported (see below) + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0; if not + given, inferred from sizes of A, AL, AU. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2dense(minmostate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minmosetlc2dense(minmostate &state, const real_2d_array &a, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +sparse constraining matrix A. Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + AL, AU - lower and upper bounds, array[K]; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2(minmostate &state, const sparsematrix &a, const real_1d_array &al, const real_1d_array &au, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided linear constraints AL <= A*x <= AU with +mixed constraining matrix A including sparse part (first SparseK rows) and +dense part (last DenseK rows). Recommended for large-scale problems. + +This function overwrites linear (non-box) constraints set by previous +calls (if such calls were made). + +This function may be useful if constraint matrix includes large number of +both types of rows - dense and sparse. If you have just a few sparse rows, +you may represent them in dense format without losing performance. +Similarly, if you have just a few dense rows, you can store them in the +sparse format with almost same performance. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + SparseA - sparse matrix with size [K,N] (exactly!). + Each row of A represents one general linear constraint. + A can be stored in any sparse storage format. + SparseK - number of sparse constraints, SparseK>=0 + DenseA - linear constraints, array[K,N], set of dense constraints. + Each row of A represents one general linear constraint. + DenseK - number of dense constraints, DenseK>=0 + AL, AU - lower and upper bounds, array[SparseK+DenseK], with former + SparseK elements corresponding to sparse constraints, and + latter DenseK elements corresponding to dense constraints; + * AL[i]=AU[i] => equality constraint Ai*x + * AL[i] two-sided constraint AL[i]<=Ai*x<=AU[i] + * AL[i]=-INF => one-sided constraint Ai*x<=AU[i] + * AU[i]=+INF => one-sided constraint AL[i]<=Ai*x + * AL[i]=-INF, AU[i]=+INF => constraint is ignored + K - number of equality/inequality constraints, K>=0. If K=0 + is specified, A, AL, AU are ignored. + + -- ALGLIB -- + Copyright 01.11.2019 by Bochkanov Sergey +*************************************************************************/ +void minmosetlc2mixed(minmostate &state, const sparsematrix &sparsea, const ae_int_t ksparse, const real_2d_array &densea, const ae_int_t kdense, const real_1d_array &al, const real_1d_array &au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL<=A*x<=AU to dense +constraints list. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + A - linear constraint coefficient, array[N], right side is NOT + included. + AL, AU - lower and upper bounds; + * AL=AU => equality constraint Ai*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint Ai*x<=AU + * AU=+INF => one-sided constraint AL<=Ai*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2dense(minmostate &state, const real_1d_array &a, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of sparse constraints. + +Constraint is passed in the compressed format: as a list of non-zero +entries of the coefficient vector A. Such approach is more efficient than +the dense storage for highly sparse constraint vectors. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + IdxA - array[NNZ], indexes of non-zero elements of A: + * can be unsorted + * can include duplicate indexes (corresponding entries of + ValA[] will be summed) + ValA - array[NNZ], values of non-zero elements of A + NNZ - number of non-zero coefficients in A + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2(minmostate &state, const integer_1d_array &idxa, const real_1d_array &vala, const ae_int_t nnz, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function appends two-sided linear constraint AL <= A*x <= AU to the +list of currently present sparse constraints. + +Constraint vector A is passed as a dense array which is internally +sparsified by this function. + +INPUT PARAMETERS: + State - structure previously allocated with minmocreate() call. + DA - array[N], constraint vector + AL, AU - lower and upper bounds; + * AL=AU => equality constraint A*x + * AL two-sided constraint AL<=A*x<=AU + * AL=-INF => one-sided constraint A*x<=AU + * AU=+INF => one-sided constraint AL<=A*x + * AL=-INF, AU=+INF => constraint is ignored + + -- ALGLIB -- + Copyright 19.07.2018 by Bochkanov Sergey +*************************************************************************/ +void minmoaddlc2sparsefromdense(minmostate &state, const real_1d_array &da, const double al, const double au, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets two-sided nonlinear constraints for MinMO optimizer. + +In fact, this function sets only constraints COUNT and their BOUNDS. +Constraints themselves (constraint functions) are passed to the +MinMOOptimize() method as callbacks. + +MinMOOptimize() method accepts a user-defined vector function F[] and its +Jacobian J[], where: +* first M components of F[] and first M rows of J[] correspond to + multiple objectives +* subsequent NNLC components of F[] (and rows of J[]) correspond to two- + sided nonlinear constraints NL<=C(x)<=NU, where + * NL[i]=NU[i] => I-th row is an equality constraint Ci(x)=NL + * NL[i] I-th tow is a two-sided constraint NL[i]<=Ci(x)<=NU[i] + * NL[i]=-INF => I-th row is an one-sided constraint Ci(x)<=NU[i] + * NU[i]=+INF => I-th row is an one-sided constraint NL[i]<=Ci(x) + * NL[i]=-INF, NU[i]=+INF => constraint is ignored + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear or box ones. + It helps optimizer to handle them more efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + NL - array[NNLC], lower bounds, can contain -INF + NU - array[NNLC], lower bounds, can contain +INF + NNLC - constraints count, NNLC>=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that the algorithm will evaluate the function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to the scale specified by + MinMOSetScale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints. Inappropriate scaling of nonlinear constraints may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT the same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for the correct + scaling of the nonlinear constraints Gi(x) and Hi(x). We recommend + you to scale nonlinear constraints in such a way that the Jacobian + rows have approximately unit magnitude (for problems with unit + scale) or have magnitude approximately equal to 1/S[i] (where S is + a scale set by MinMOSetScale() function). + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetnlc2(minmostate &state, const real_1d_array &nl, const real_1d_array &nu, const ae_int_t nnlc, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for inner iterations of the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinMOSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to an automatic +selection of the stopping condition. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetcond(minmostate &state, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for the MO optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetscale(minmostate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting of the Pareto front points. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function (if it +was provided to MinMOOptimize) every time we find a Pareto front point. + +NOTE: according to the communication protocol used by ALGLIB, the solver + passes two parameters to the rep() callback - a current point and a + target value at the current point. + However, because we solve a multi-objective problem, the target + parameter is not used and set to zero. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmosetxrep(minmostate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minmoiteration(minmostate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied Jacobian, and one which uses only function + vector and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + you should choose appropriate variant of MinMOOptimize() - one which + needs function vector AND Jacobian or one which needs ONLY function. + + Be careful to choose variant of MinMOOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinMOOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinMOOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinMOCreateF() | works FAILS + MinMOCreate() | FAILS works + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and MinMOOptimize() version. Attemps to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey + + +*************************************************************************/ +void minmooptimize(minmostate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minmooptimize(minmostate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MinMO results: the solution found, completion codes and additional +information. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + ParetoFront-array[FrontSize,N+M], approximate Pareto front. + Its columns have the following structure: + * first N columns are variable values + * next M columns are objectives at these points + Its rows have the following structure: + * first M rows contain solutions to single-objective tasks + with I-th row storing result for I-th objective being + minimized ignoring other ones. + Thus, ParetoFront[I,N+I] for 0<=I=0. + * no larger than the number passed to setalgo() + * for a single-objective task, FrontSize=1 is ALWAYS + returned, no matter what was specified during setalgo() + call. + * if the solver was prematurely terminated with + minnorequesttermination(), an incomplete Pareto front + will be returned (it may even have less than M rows) + * if a failure (negative completion code) was signaled, + FrontSize=0 will be returned + + Rep - optimization report, contains information about completion + code, constraint violation at the solution and so on. + + You should check rep.terminationtype in order to + distinguish successful termination from unsuccessful one: + + === FAILURE CODES === + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 constraint bounds are infeasible, i.e. we have + box/linear/nonlinear constraint with two bounds + present, and a lower one being greater than the + upper one. + Note: less obvious infeasibilities of constraints + do NOT trigger emergency completion; you + have to examine rep.bcerr/rep.lcerr/rep.nlcerr + to detect possibly inconsistent constraints. + + === SUCCESS CODES === + * 2 scaled step is no more than EpsX. + * 5 MaxIts steps were taken. + * 8 user requested algorithm termination via + minmorequesttermination(), last accepted point is + returned. + + More information about fields of this structure can be + found in the comments on minmoreport datatype. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmoresults(const minmostate &state, real_2d_array &paretofront, ae_int_t &frontsize, minmoreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for the termination of the running +optimizer. + +It should be called from the user-supplied callback when user decides that +it is time to "smoothly" terminate optimization process, or from some other +thread. As a result, optimizer stops at the state which was "current +accepted" when termination request was submitted and returns error code 8 +(successful termination). + +Usually it results in an incomplete Pareto front being returned. + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorequesttermination(minmostate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from the new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinMOCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 01.03.2023 by Bochkanov Sergey +*************************************************************************/ +void minmorestartfrom(minmostate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + NONSMOOTH NONCONVEX OPTIMIZATION + SUBJECT TO BOX/LINEAR/NONLINEAR-NONSMOOTH CONSTRAINTS + +DESCRIPTION: + +The subroutine minimizes function F(x) of N arguments subject to any +combination of: +* bound constraints +* linear inequality constraints +* linear equality constraints +* nonlinear equality constraints Gi(x)=0 +* nonlinear inequality constraints Hi(x)<=0 + +IMPORTANT: see MinNSSetAlgoAGS for important information on performance + restrictions of AGS solver. + +REQUIREMENTS: +* starting point X0 must be feasible or not too far away from the feasible + set +* F(), G(), H() are continuous, locally Lipschitz and continuously (but + not necessarily twice) differentiable in an open dense subset of R^N. + Functions F(), G() and H() may be nonsmooth and non-convex. + Informally speaking, it means that functions are composed of large + differentiable "patches" with nonsmoothness having place only at the + boundaries between these "patches". + Most real-life nonsmooth functions satisfy these requirements. Say, + anything which involves finite number of abs(), min() and max() is very + likely to pass the test. + Say, it is possible to optimize anything of the following: + * f=abs(x0)+2*abs(x1) + * f=max(x0,x1) + * f=sin(max(x0,x1)+abs(x2)) +* for nonlinearly constrained problems: F() must be bounded from below + without nonlinear constraints (this requirement is due to the fact that, + contrary to box and linear constraints, nonlinear ones require special + handling). +* user must provide function value and gradient for F(), H(), G() at all + points where function/gradient can be calculated. If optimizer requires + value exactly at the boundary between "patches" (say, at x=0 for f=abs(x)), + where gradient is not defined, user may resolve tie arbitrarily (in our + case - return +1 or -1 at its discretion). +* NS solver supports numerical differentiation, i.e. it may differentiate + your function for you, but it results in 2N increase of function + evaluations. Not recommended unless you solve really small problems. See + minnscreatef() for more information on this functionality. + +USAGE: + +1. User initializes algorithm state with MinNSCreate() call and chooses + what NLC solver to use. There is some solver which is used by default, + with default settings, but you should NOT rely on default choice. It + may change in future releases of ALGLIB without notice, and no one can + guarantee that new solver will be able to solve your problem with + default settings. + + From the other side, if you choose solver explicitly, you can be pretty + sure that it will work with new ALGLIB releases. + + In the current release following solvers can be used: + * AGS solver (activated with MinNSSetAlgoAGS() function) + +2. User adds boundary and/or linear and/or nonlinear constraints by means + of calling one of the following functions: + a) MinNSSetBC() for boundary constraints + b) MinNSSetLC() for linear constraints + c) MinNSSetNLC() for nonlinear constraints + You may combine (a), (b) and (c) in one optimization problem. + +3. User sets scale of the variables with MinNSSetScale() function. It is + VERY important to set scale of the variables, because nonlinearly + constrained problems are hard to solve when variables are badly scaled. + +4. User sets stopping conditions with MinNSSetCond(). + +5. Finally, user calls MinNSOptimize() function which takes algorithm + state and pointer (delegate, etc) to callback function which calculates + F/G/H. + +7. User calls MinNSResults() to get solution + +8. Optionally user may call MinNSRestartFrom() to solve another problem + with same N but another starting point. MinNSRestartFrom() allows to + reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + +NOTE: minnscreatef() function may be used if you do not have analytic + gradient. This function creates solver which uses numerical + differentiation with user-specified step. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreate(const ae_int_t n, const real_1d_array &x, minnsstate &state, const xparams _xparams = alglib::xdefault); +void minnscreate(const real_1d_array &x, minnsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Version of minnscreatef() which uses numerical differentiation. I.e., you +do not have to calculate derivatives yourself. However, this version needs +2N times more function evaluations. + +2-point differentiation formula is used, because more precise 4-point +formula is unstable when used on non-smooth functions. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + DiffStep- differentiation step, DiffStep>0. Algorithm performs + numerical differentiation with step for I-th variable + being equal to DiffStep*S[I] (here S[] is a scale vector, + set by minnssetscale() function). + Do not use too small steps, because it may lead to + catastrophic cancellation during intermediate calculations. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnscreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minnsstate &state, const xparams _xparams = alglib::xdefault); +void minnscreatef(const real_1d_array &x, const double diffstep, minnsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: AGS solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetbc(minnsstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets linear constraints. + +Linear constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with minnsrestartfrom(). + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + C - linear constraints, array[K,N+1]. + Each row of C represents one constraint, either equality + or inequality (see below): + * first N elements correspond to coefficients, + * last element corresponds to the right part. + All elements of C (including right part) must be finite. + CT - type of constraints, array[K]: + * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1] + * if CT[i]=0, then I-th constraint is C[i,*]*x = C[i,n+1] + * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1] + K - number of equality/inequality constraints, K>=0: + * if given, only leading K elements of C/CT are used + * if not given, automatically determined from sizes of C/CT + +NOTE: linear (non-bound) constraints are satisfied only approximately: + +* there always exists some minor violation (about current sampling radius + in magnitude during optimization, about EpsX in the solution) due to use + of penalty method to handle constraints. +* numerical differentiation, if used, may lead to function evaluations + outside of the feasible area, because algorithm does NOT change + numerical differentiation formula according to linear constraints. + +If you want constraints to be satisfied exactly, try to reformulate your +problem in such manner that all constraints will become boundary ones +(this kind of constraints is always satisfied exactly, both in the final +solution and in all intermediate points). + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetlc(minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams = alglib::xdefault); +void minnssetlc(minnsstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets nonlinear constraints. + +In fact, this function sets NUMBER of nonlinear constraints. Constraints +itself (constraint functions) are passed to minnsoptimize() method. This +method requires user-defined vector function F[] and its Jacobian J[], +where: +* first component of F[] and first row of Jacobian J[] correspond to + function being minimized +* next NLEC components of F[] (and rows of J) correspond to nonlinear + equality constraints G_i(x)=0 +* next NLIC components of F[] (and rows of J) correspond to nonlinear + inequality constraints H_i(x)<=0 + +NOTE: you may combine nonlinear constraints with linear/boundary ones. If + your problem has mixed constraints, you may explicitly specify some + of them as linear ones. It may help optimizer to handle them more + efficiently. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + NLEC - number of Non-Linear Equality Constraints (NLEC), >=0 + NLIC - number of Non-Linear Inquality Constraints (NLIC), >=0 + +NOTE 1: nonlinear constraints are satisfied only approximately! It is + possible that algorithm will evaluate function outside of + the feasible area! + +NOTE 2: algorithm scales variables according to scale specified by + minnssetscale() function, so it can handle problems with badly + scaled variables (as long as we KNOW their scales). + + However, there is no way to automatically scale nonlinear + constraints Gi(x) and Hi(x). Inappropriate scaling of Gi/Hi may + ruin convergence. Solving problem with constraint "1000*G0(x)=0" + is NOT same as solving it with constraint "0.001*G0(x)=0". + + It means that YOU are the one who is responsible for correct + scaling of nonlinear constraints Gi(x) and Hi(x). We recommend you + to scale nonlinear constraints in such way that I-th component of + dG/dX (or dH/dx) has approximately unit magnitude (for problems + with unit scale) or has magnitude approximately equal to 1/S[i] + (where S is a scale set by minnssetscale() function). + +NOTE 3: nonlinear constraints are always hard to handle, no matter what + algorithm you try to use. Even basic box/linear constraints modify + function curvature by adding valleys and ridges. However, + nonlinear constraints add valleys which are very hard to follow + due to their "curved" nature. + + It means that optimization with single nonlinear constraint may be + significantly slower than optimization with multiple linear ones. + It is normal situation, and we recommend you to carefully choose + Rho parameter of minnssetalgoags(), because too large value may + slow down convergence. + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetnlc(minnsstate &state, const ae_int_t nlec, const ae_int_t nlic, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for iterations of optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsX - >=0 + The AGS solver finishes its work if on k+1-th iteration + sampling radius decreases below EpsX. + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsX=0 and MaxIts=0 (simultaneously) will lead to automatic +stopping criterion selection. We do not recommend you to rely on default +choice in production code. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetcond(minnsstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for NLC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetscale(minnsstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function tells MinNS unit to use AGS (adaptive gradient sampling) +algorithm for nonsmooth constrained optimization. This algorithm is a +slight modification of one described in "An Adaptive Gradient Sampling +Algorithm for Nonsmooth Optimization" by Frank E. Curtisy and Xiaocun Quez. + +This optimizer has following benefits and drawbacks: ++ robustness; it can be used with nonsmooth and nonconvex functions. ++ relatively easy tuning; most of the metaparameters are easy to select. +- it has convergence of steepest descent, slower than CG/LBFGS. +- each iteration involves evaluation of ~2N gradient values and solution + of 2Nx2N quadratic programming problem, which limits applicability of + algorithm by small-scale problems (up to 50-100). + +IMPORTANT: this algorithm has convergence guarantees, i.e. it will + steadily move towards some stationary point of the function. + + However, "stationary point" does not always mean "solution". + Nonsmooth problems often have "flat spots", i.e. areas where + function do not change at all. Such "flat spots" are stationary + points by definition, and algorithm may be caught here. + + Nonsmooth CONVEX tasks are not prone to this problem. Say, if + your function has form f()=MAX(f0,f1,...), and f_i are convex, + then f() is convex too and you have guaranteed convergence to + solution. + +INPUT PARAMETERS: + State - structure which stores algorithm state + Radius - initial sampling radius, >=0. + + Internally multiplied by vector of per-variable scales + specified by minnssetscale()). + + You should select relatively large sampling radius, roughly + proportional to scaled length of the first steps of the + algorithm. Something close to 0.1 in magnitude should be + good for most problems. + + AGS solver can automatically decrease radius, so too large + radius is not a problem (assuming that you won't choose + so large radius that algorithm will sample function in + too far away points, where gradient value is irrelevant). + + Too small radius won't cause algorithm to fail, but it may + slow down algorithm (it may have to perform too short + steps). + Penalty - penalty coefficient for nonlinear constraints: + * for problem with nonlinear constraints should be some + problem-specific positive value, large enough that + penalty term changes shape of the function. + Starting from some problem-specific value penalty + coefficient becomes large enough to exactly enforce + nonlinear constraints; larger values do not improve + precision. + Increasing it too much may slow down convergence, so you + should choose it carefully. + * can be zero for problems WITHOUT nonlinear constraints + (i.e. for unconstrained ones or ones with just box or + linear constraints) + * if you specify zero value for problem with at least one + nonlinear constraint, algorithm will terminate with + error code -1. + +ALGORITHM OUTLINE + +The very basic outline of unconstrained AGS algorithm is given below: + +0. If sampling radius is below EpsX or we performed more then MaxIts + iterations - STOP. +1. sample O(N) gradient values at random locations around current point; + informally speaking, this sample is an implicit piecewise linear model + of the function, although algorithm formulation does not mention that + explicitly +2. solve quadratic programming problem in order to find descent direction +3. if QP solver tells us that we are near solution, decrease sampling + radius and move to (0) +4. perform backtracking line search +5. after moving to new point, goto (0) + +Constraint handling details: +* box constraints are handled exactly by algorithm +* linear/nonlinear constraints are handled by adding L1 penalty. Because + our solver can handle nonsmoothness, we can use L1 penalty function, + which is an exact one (i.e. exact solution is returned under such + penalty). +* penalty coefficient for linear constraints is chosen automatically; + however, penalty coefficient for nonlinear constraints must be specified + by user. + +===== TRACING AGS SOLVER ================================================= + +AGS solver supports advanced tracing capabilities. You can trace algorithm +output by specifying following trace symbols (case-insensitive) by means +of trace_file() call: +* 'AGS' - for basic trace of algorithm steps and decisions. Only + short scalars (function values and deltas) are printed. + N-dimensional quantities like search directions are NOT + printed. +* 'AGS.DETAILED'- for output of points being visited and search directions + This symbol also implicitly defines 'AGS'. You can + control output format by additionally specifying: + * nothing to output in 6-digit exponential format + * 'PREC.E15' to output in 15-digit exponential format + * 'PREC.F6' to output in 6-digit fixed-point format +* 'AGS.DETAILED.SAMPLE'- + for output of points being visited , search directions + and gradient sample. May take a LOT of space , do not + use it on problems with more that several tens of vars. + This symbol also implicitly defines 'AGS' and + 'AGS.DETAILED'. + +By default trace is disabled and adds no overhead to the optimization +process. However, specifying any of the symbols adds some formatting and +output-related overhead. + +You may specify multiple symbols by separating them with commas: +> +> alglib::trace_file("AGS,PREC.F6", "path/to/trace.log") +> + + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnssetalgoags(minnsstate &state, const double radius, const double penalty, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to minnsoptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minnssetxrep(minnsstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrequesttermination(minnsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minnsiteration(minnsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + fvec - callback which calculates function vector fi[] + at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied Jacobian, and one which uses only function + vector and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + you should choose appropriate variant of minnsoptimize() - one which + accepts function AND Jacobian or one which accepts ONLY function. + + Be careful to choose variant of minnsoptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to minnsoptimize() and specific + function used to create optimizer. + + + | USER PASSED TO minnsoptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + minnscreatef() | works FAILS + minnscreate() | FAILS works + + Here "FAILS" denotes inappropriate combinations of optimizer creation + function and minnsoptimize() version. Attemps to use such + combination will lead to exception. Either you did not pass gradient + when it WAS needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey + + +*************************************************************************/ +void minnsoptimize(minnsstate &state, + void (*fvec)(const real_1d_array &x, real_1d_array &fi, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minnsoptimize(minnsstate &state, + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +MinNS results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 box constraints are inconsistent + * -1 inconsistent parameters were passed: + * penalty parameter for minnssetalgoags() is zero, + but we have nonlinear constraints set by minnssetnlc() + * 2 sampling radius decreased below epsx + * 7 stopping conditions are too stringent, + further improvement is impossible, + X contains best point found so far. + * 8 User requested termination via minnsrequesttermination() + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresults(const minnsstate &state, real_1d_array &x, minnsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* + +Buffered implementation of minnsresults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsresultsbuf(const minnsstate &state, real_1d_array &x, minnsreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with minnscreate() call. + X - new starting point. + + -- ALGLIB -- + Copyright 18.05.2015 by Bochkanov Sergey +*************************************************************************/ +void minnsrestartfrom(minnsstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Obsolete function, use MinLBFGSSetPrecDefault() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetdefaultpreconditioner(minlbfgsstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete function, use MinLBFGSSetCholeskyPreconditioner() instead. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minlbfgssetcholeskypreconditioner(minlbfgsstate &state, const real_2d_array &p, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierwidth(minbleicstate &state, const double mu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This is obsolete function which was used by previous version of the BLEIC +optimizer. It does nothing in the current version of BLEIC. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbleicsetbarrierdecay(minbleicstate &state, const double mudecay, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 25.03.2010 by Bochkanov Sergey +*************************************************************************/ +void minasacreate(const ae_int_t n, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state, const xparams _xparams = alglib::xdefault); +void minasacreate(const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, minasastate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetcond(minasastate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetxrep(minasastate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetalgorithm(minasastate &state, const ae_int_t algotype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minasasetstpmax(minasastate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minasaiteration(minasastate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey + + +*************************************************************************/ +void minasaoptimize(minasastate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresults(const minasastate &state, real_1d_array &x, minasareport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +void minasaresultsbuf(const minasastate &state, real_1d_array &x, minasareport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete optimization algorithm. +Was replaced by MinBLEIC subpackage. + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void minasarestartfrom(minasastate &state, const real_1d_array &x, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + BOX CONSTRAINED OPTIMIZATION + WITH FAST ACTIVATION OF MULTIPLE BOX CONSTRAINTS + +DESCRIPTION: +The subroutine minimizes function F(x) of N arguments subject to box +constraints (with some of box constraints actually being equality ones). + +This optimizer uses algorithm similar to that of MinBLEIC (optimizer with +general linear constraints), but presence of box-only constraints allows +us to use faster constraint activation strategies. On large-scale problems, +with multiple constraints active at the solution, this optimizer can be +several times faster than BLEIC. + +REQUIREMENTS: +* user must provide function value and gradient +* starting point X0 must be feasible or + not too far away from the feasible set +* grad(f) must be Lipschitz continuous on a level set: + L = { x : f(x)<=f(x0) } +* function must be defined everywhere on the feasible set F + +USAGE: + +Constrained optimization if far more complex than the unconstrained one. +Here we give very brief outline of the BC optimizer. We strongly recommend +you to read examples in the ALGLIB Reference Manual and to read ALGLIB User Guide +on optimization, which is available at http://www.alglib.net/optimization/ + +1. User initializes algorithm state with MinBCCreate() call + +2. USer adds box constraints by calling MinBCSetBC() function. + +3. User sets stopping conditions with MinBCSetCond(). + +4. User calls MinBCOptimize() function which takes algorithm state and + pointer (delegate, etc.) to callback function which calculates F/G. + +5. User calls MinBCResults() to get solution + +6. Optionally user may call MinBCRestartFrom() to solve another problem + with same N but another starting point. + MinBCRestartFrom() allows to reuse already initialized structure. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size ofX + X - starting point, array[N]: + * it is better to set X to a feasible point + * but X can be infeasible, in which case algorithm will try + to find feasible point first, using X as initial + approximation. + +OUTPUT PARAMETERS: + State - structure stores algorithm state + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbccreate(const ae_int_t n, const real_1d_array &x, minbcstate &state, const xparams _xparams = alglib::xdefault); +void minbccreate(const real_1d_array &x, minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +The subroutine is finite difference variant of MinBCCreate(). It uses +finite differences in order to differentiate target function. + +Description below contains information which is specific to this function +only. We recommend to read comments on MinBCCreate() in order to get +more information about creation of BC optimizer. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point, array[0..N-1]. + DiffStep- differentiation step, >0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +1. algorithm uses 4-point central formula for differentiation. +2. differentiation step along I-th axis is equal to DiffStep*S[I] where + S[] is scaling vector which can be set by MinBCSetScale() call. +3. we recommend you to use moderate values of differentiation step. Too + large step will result in too large truncation errors, while too small + step will result in too large numerical errors. 1.0E-6 can be good + value to start with. +4. Numerical differentiation is very inefficient - one gradient + calculation needs 4*N function evaluations. This function will work for + any N - either small (1...10), moderate (10...100) or large (100...). + However, performance penalty will be too severe for any N's except for + small ones. + We should also say that code which relies on numerical differentiation + is less robust and precise. CG needs exact gradient values. Imprecise + gradient may slow down convergence, especially on highly nonlinear + problems. + Thus we recommend to use this function for fast prototyping on small- + dimensional problems only, and to implement analytical gradient as soon + as possible. + + -- ALGLIB -- + Copyright 16.05.2011 by Bochkanov Sergey +*************************************************************************/ +void minbccreatef(const ae_int_t n, const real_1d_array &x, const double diffstep, minbcstate &state, const xparams _xparams = alglib::xdefault); +void minbccreatef(const real_1d_array &x, const double diffstep, minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets boundary constraints for BC optimizer. + +Boundary constraints are inactive by default (after initial creation). +They are preserved after algorithm restart with MinBCRestartFrom(). + +INPUT PARAMETERS: + State - structure stores algorithm state + BndL - lower bounds, array[N]. + If some (all) variables are unbounded, you may specify + very small number or -INF. + BndU - upper bounds, array[N]. + If some (all) variables are unbounded, you may specify + very large number or +INF. + +NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th +variable will be "frozen" at X[i]=BndL[i]=BndU[i]. + +NOTE 2: this solver has following useful properties: +* bound constraints are always satisfied exactly +* function is evaluated only INSIDE area specified by bound constraints, + even when numerical differentiation is used (algorithm adjusts nodes + according to boundary constraints) + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetbc(minbcstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the optimizer. + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsG - >=0 + The subroutine finishes its work if the condition + |v|=0 + The subroutine finishes its work if on k+1-th iteration + the condition |F(k+1)-F(k)|<=EpsF*max{|F(k)|,|F(k+1)|,1} + is satisfied. + EpsX - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition |v|<=EpsX is fulfilled, where: + * |.| means Euclidian norm + * v - scaled step vector, v[i]=dx[i]/s[i] + * dx - step vector, dx=X(k+1)-X(k) + * s - scaling coefficients set by MinBCSetScale() + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsG=0, EpsF=0 and EpsX=0 and MaxIts=0 (simultaneously) will lead +to automatic stopping criterion selection. + +NOTE: when SetCond() called with non-zero MaxIts, BC solver may perform + slightly more than MaxIts iterations. I.e., MaxIts sets non-strict + limit on iterations count. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetcond(minbcstate &state, const double epsg, const double epsf, const double epsx, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets scaling coefficients for BC optimizer. + +ALGLIB optimizers use scaling matrices to test stopping conditions (step +size and gradient are scaled before comparison with tolerances). Scale of +the I-th variable is a translation invariant measure of: +a) "how large" the variable is +b) how large the step should be to make significant changes in the function + +Scaling is also used by finite difference variant of the optimizer - step +along I-th axis is equal to DiffStep*S[I]. + +In most optimizers (and in the BC too) scaling is NOT a form of +preconditioning. It just affects stopping conditions. You should set +preconditioner by separate call to one of the MinBCSetPrec...() +functions. + +There is a special preconditioning mode, however, which uses scaling +coefficients to form diagonal preconditioning matrix. You can turn this +mode on, if you want. But you should understand that scaling is not the +same thing as preconditioning - these are two different, although related +forms of tuning solver. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 14.01.2011 by Bochkanov Sergey +*************************************************************************/ +void minbcsetscale(minbcstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: preconditioning is turned off. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdefault(minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: diagonal of approximate Hessian is +used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + D - diagonal of the approximate Hessian, array[0..N-1], + (if larger, only leading N elements are used). + +NOTE 1: D[i] should be positive. Exception will be thrown otherwise. + +NOTE 2: you should pass diagonal of approximate Hessian - NOT ITS INVERSE. + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecdiag(minbcstate &state, const real_1d_array &d, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modification of the preconditioner: scale-based diagonal preconditioning. + +This preconditioning mode can be useful when you don't have approximate +diagonal of Hessian, but you know that your variables are badly scaled +(for example, one variable is in [1,10], and another in [1000,100000]), +and most part of the ill-conditioning comes from different scales of vars. + +In this case simple scale-based preconditioner, with H[i] = 1/(s[i]^2), +can greatly improve convergence. + +IMPRTANT: you should set scale of your variables with MinBCSetScale() +call (before or after MinBCSetPrecScale() call). Without knowledge of +the scale of your variables scale-based preconditioner will be just unit +matrix. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 13.10.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetprecscale(minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinBCOptimize(). + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetxrep(minbcstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when you optimize target function which contains exp() +or other fast growing functions, and optimization algorithm makes too +large steps which lead to overflow. This function allows us to reject +steps that are too large (and therefore expose us to the possible +overflow) without actually calculating function value at the x+stp*d. + + -- ALGLIB -- + Copyright 02.04.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcsetstpmax(minbcstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool minbciteration(minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear optimizer + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + grad - callback which calculates function (or merit function) + value func and gradient grad at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + +NOTES: + +1. This function has two different implementations: one which uses exact + (analytical) user-supplied gradient, and one which uses function value + only and numerically differentiates function in order to obtain + gradient. + + Depending on the specific function used to create optimizer object + (either MinBCCreate() for analytical gradient or MinBCCreateF() + for numerical differentiation) you should choose appropriate variant of + MinBCOptimize() - one which accepts function AND gradient or one + which accepts function ONLY. + + Be careful to choose variant of MinBCOptimize() which corresponds to + your optimization scheme! Table below lists different combinations of + callback (function/gradient) passed to MinBCOptimize() and specific + function used to create optimizer. + + + | USER PASSED TO MinBCOptimize() + CREATED WITH | function only | function and gradient + ------------------------------------------------------------ + MinBCCreateF() | works FAILS + MinBCCreate() | FAILS works + + Here "FAIL" denotes inappropriate combinations of optimizer creation + function and MinBCOptimize() version. Attemps to use such + combination (for example, to create optimizer with MinBCCreateF() + and to pass gradient information to MinCGOptimize()) will lead to + exception being thrown. Either you did not pass gradient when it WAS + needed or you passed gradient when it was NOT needed. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey + + +*************************************************************************/ +void minbcoptimize(minbcstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); +void minbcoptimize(minbcstate &state, + void (*grad)(const real_1d_array &x, double &func, real_1d_array &grad, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates verification of the user-supplied +analytic gradient. + +Upon activation of this option OptGuard integrity checker performs +numerical differentiation of your target function at the initial point +(note: future versions may also perform check at the final point) and +compares numerical gradient with analytic one provided by you. + +If difference is too large, an error flag is set and optimization session +continues. After optimization session is over, you can retrieve the report +which stores both gradients and specific components highlighted as +suspicious by the OptGuard. + +The primary OptGuard report can be retrieved with minbcoptguardresults(). + +IMPORTANT: gradient check is a high-overhead option which will cost you + about 3*N additional function evaluations. In many cases it may + cost as much as the rest of the optimization session. + + YOU SHOULD NOT USE IT IN THE PRODUCTION CODE UNLESS YOU WANT TO + CHECK DERIVATIVES PROVIDED BY SOME THIRD PARTY. + +NOTE: unlike previous incarnation of the gradient checking code, OptGuard + does NOT interrupt optimization even if it discovers bad gradient. + +INPUT PARAMETERS: + State - structure used to store algorithm state + TestStep - verification step used for numerical differentiation: + * TestStep=0 turns verification off + * TestStep>0 activates verification + You should carefully choose TestStep. Value which is + too large (so large that function behavior is non- + cubic at this scale) will lead to false alarms. Too + short step will result in rounding errors dominating + numerical derivative. + + You may use different step for different parameters by + means of setting scale with minbcsetscale(). + +=== EXPLANATION ========================================================== + +In order to verify gradient algorithm performs following steps: + * two trial steps are made to X[i]-TestStep*S[i] and X[i]+TestStep*S[i], + where X[i] is i-th component of the initial point and S[i] is a scale + of i-th parameter + * F(X) is evaluated at these trial points + * we perform one more evaluation in the middle point of the interval + * we build cubic model using function values and derivatives at trial + points and we compare its prediction with actual value in the middle + point + + -- ALGLIB -- + Copyright 15.06.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardgradient(minbcstate &state, const double teststep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates/deactivates nonsmoothness monitoring option of +the OptGuard integrity checker. Smoothness monitor silently observes +solution process and tries to detect ill-posed problems, i.e. ones with: +a) discontinuous target function (non-C0) +b) nonsmooth target function (non-C1) + +Smoothness monitoring does NOT interrupt optimization even if it suspects +that your problem is nonsmooth. It just sets corresponding flags in the +OptGuard report which can be retrieved after optimization is over. + +Smoothness monitoring is a moderate overhead option which often adds less +than 1% to the optimizer running time. Thus, you can use it even for large +scale problems. + +NOTE: OptGuard does NOT guarantee that it will always detect C0/C1 + continuity violations. + + First, minor errors are hard to catch - say, a 0.0001 difference in + the model values at two sides of the gap may be due to discontinuity + of the model - or simply because the model has changed. + + Second, C1-violations are especially difficult to detect in a + noninvasive way. The optimizer usually performs very short steps + near the nonsmoothness, and differentiation usually introduces a + lot of numerical noise. It is hard to tell whether some tiny + discontinuity in the slope is due to real nonsmoothness or just due + to numerical noise alone. + + Our top priority was to avoid false positives, so in some rare cases + minor errors may went unnoticed (however, in most cases they can be + spotted with restart from different initial point). + +INPUT PARAMETERS: + state - algorithm state + level - monitoring level: + * 0 - monitoring is disabled + * 1 - noninvasive low-overhead monitoring; function values + and/or gradients are recorded, but OptGuard does not + try to perform additional evaluations in order to + get more information about suspicious locations. + +=== EXPLANATION ========================================================== + +One major source of headache during optimization is the possibility of +the coding errors in the target function/constraints (or their gradients). +Such errors most often manifest themselves as discontinuity or +nonsmoothness of the target/constraints. + +Another frequent situation is when you try to optimize something involving +lots of min() and max() operations, i.e. nonsmooth target. Although not a +coding error, it is nonsmoothness anyway - and smooth optimizers usually +stop right after encountering nonsmoothness, well before reaching solution. + +OptGuard integrity checker helps you to catch such situations: it monitors +function values/gradients being passed to the optimizer and tries to +errors. Upon discovering suspicious pair of points it raises appropriate +flag (and allows you to continue optimization). When optimization is done, +you can study OptGuard result. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardsmoothness(minbcstate &state, const ae_int_t level, const xparams _xparams = alglib::xdefault); +void minbcoptguardsmoothness(minbcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Results of OptGuard integrity check, should be called after optimization +session is over. + +=== PRIMARY REPORT ======================================================= + +OptGuard performs several checks which are intended to catch common errors +in the implementation of nonlinear function/gradient: +* incorrect analytic gradient +* discontinuous (non-C0) target functions (constraints) +* nonsmooth (non-C1) target functions (constraints) + +Each of these checks is activated with appropriate function: +* minbcoptguardgradient() for gradient verification +* minbcoptguardsmoothness() for C0/C1 checks + +Following flags are set when these errors are suspected: +* rep.badgradsuspected, and additionally: + * rep.badgradvidx for specific variable (gradient element) suspected + * rep.badgradxbase, a point where gradient is tested + * rep.badgraduser, user-provided gradient (stored as 2D matrix with + single row in order to make report structure compatible with more + complex optimizers like MinNLC or MinLM) + * rep.badgradnum, reference gradient obtained via numerical + differentiation (stored as 2D matrix with single row in order to make + report structure compatible with more complex optimizers like MinNLC + or MinLM) +* rep.nonc0suspected +* rep.nonc1suspected + +=== ADDITIONAL REPORTS/LOGS ============================================== + +Several different tests are performed to catch C0/C1 errors, you can find +out specific test signaled error by looking to: +* rep.nonc0test0positive, for non-C0 test #0 +* rep.nonc1test0positive, for non-C1 test #0 +* rep.nonc1test1positive, for non-C1 test #1 + +Additional information (including line search logs) can be obtained by +means of: +* minbcoptguardnonc1test0results() +* minbcoptguardnonc1test1results() +which return detailed error reports, specific points where discontinuities +were found, and so on. + +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + rep - generic OptGuard report; more detailed reports can be + retrieved with other functions. + +NOTE: false negatives (nonsmooth problems are not identified as nonsmooth + ones) are possible although unlikely. + + The reason is that you need to make several evaluations around + nonsmoothness in order to accumulate enough information about + function curvature. Say, if you start right from the nonsmooth point, + optimizer simply won't get enough data to understand what is going + wrong before it terminates due to abrupt changes in the derivative. + It is also possible that "unlucky" step will move us to the + termination too quickly. + + Our current approach is to have less than 0.1% false negatives in + our test examples (measured with multiple restarts from random + points), and to have exactly 0% false positives. + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardresults(minbcstate &state, optguardreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #0 + +Nonsmoothness (non-C1) test #0 studies function values (not gradient!) +obtained during line searches and monitors behavior of the directional +derivative estimate. + +This test is less powerful than test #1, but it does not depend on the +gradient values and thus it is more robust against artifacts introduced by +numerical differentiation. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], f[] - arrays of length CNT which store step lengths and function + values at these points; f[i] is evaluated in x0+stp[i]*d. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #0 "strong" report + lngrep - C1 test #0 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test0results(const minbcstate &state, optguardnonc1test0report &strrep, optguardnonc1test0report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Detailed results of the OptGuard integrity check for nonsmoothness test #1 + +Nonsmoothness (non-C1) test #1 studies individual components of the +gradient computed during line search. + +When precise analytic gradient is provided this test is more powerful than +test #0 which works with function values and ignores user-provided +gradient. However, test #0 becomes more powerful when numerical +differentiation is employed (in such cases test #1 detects higher levels +of numerical noise and becomes too conservative). + +This test also tells specific components of the gradient which violate C1 +continuity, which makes it more informative than #0, which just tells that +continuity is violated. + +Two reports are returned: +* a "strongest" one, corresponding to line search which had highest + value of the nonsmoothness indicator +* a "longest" one, corresponding to line search which had more function + evaluations, and thus is more detailed + +In both cases following fields are returned: + +* positive - is TRUE when test flagged suspicious point; FALSE if test + did not notice anything (in the latter cases fields below are empty). +* vidx - is an index of the variable in [0,N) with nonsmooth derivative +* x0[], d[] - arrays of length N which store initial point and direction + for line search (d[] can be normalized, but does not have to) +* stp[], g[] - arrays of length CNT which store step lengths and gradient + values at these points; g[i] is evaluated in x0+stp[i]*d and contains + vidx-th component of the gradient. +* stpidxa, stpidxb - we suspect that function violates C1 continuity + between steps #stpidxa and #stpidxb (usually we have stpidxb=stpidxa+3, + with most likely position of the violation between stpidxa+1 and + stpidxa+2. + +========================================================================== += SHORTLY SPEAKING: build a 2D plot of (stp,f) and look at it - you will += see where C1 continuity is violated. +========================================================================== + +INPUT PARAMETERS: + state - algorithm state + +OUTPUT PARAMETERS: + strrep - C1 test #1 "strong" report + lngrep - C1 test #1 "long" report + + -- ALGLIB -- + Copyright 21.11.2018 by Bochkanov Sergey +*************************************************************************/ +void minbcoptguardnonc1test1results(minbcstate &state, optguardnonc1test1report &strrep, optguardnonc1test1report &lngrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +BC results + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report. You should check Rep.TerminationType + in order to distinguish successful termination from + unsuccessful one: + * -8 internal integrity control detected infinite or + NAN values in function/gradient. Abnormal + termination signalled. + * -3 inconsistent constraints. + * 1 relative function improvement is no more than EpsF. + * 2 scaled step is no more than EpsX. + * 4 scaled gradient norm is no more than EpsG. + * 5 MaxIts steps was taken + * 8 terminated by user who called minbcrequesttermination(). + X contains point which was "current accepted" when + termination request was submitted. + More information about fields of this structure can be + found in the comments on MinBCReport datatype. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresults(const minbcstate &state, real_1d_array &x, minbcreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +BC results + +Buffered implementation of MinBCResults() which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcresultsbuf(const minbcstate &state, real_1d_array &x, minbcreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts algorithm from new point. +All optimization parameters (including constraints) are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure previously allocated with MinBCCreate call. + X - new starting point. + + -- ALGLIB -- + Copyright 28.11.2010 by Bochkanov Sergey +*************************************************************************/ +void minbcrestartfrom(minbcstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of running optimizer. It +should be called from user-supplied callback when user decides that it is +time to "smoothly" terminate optimization process. As result, optimizer +stops at point which was "current accepted" when termination request was +submitted and returns error code 8 (successful termination). + +INPUT PARAMETERS: + State - optimizer structure + +NOTE: after request for termination optimizer may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on optimizer which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void minbcrequesttermination(minbcstate &state, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_OPTGUARDAPI) || !defined(AE_PARTIAL_BUILD) +void optguardinitinternal(optguardreport* rep, + ae_int_t n, + ae_int_t k, + ae_state *_state); +void optguardexportreport(const optguardreport* srcrep, + ae_int_t n, + ae_int_t k, + ae_bool badgradhasxj, + optguardreport* dstrep, + ae_state *_state); +void smoothnessmonitorexportc1test0report(const optguardnonc1test0report* srcrep, + /* Real */ const ae_vector* s, + optguardnonc1test0report* dstrep, + ae_state *_state); +void smoothnessmonitorexportc1test1report(const optguardnonc1test1report* srcrep, + /* Real */ const ae_vector* s, + optguardnonc1test1report* dstrep, + ae_state *_state); +ae_bool optguardallclear(const optguardreport* rep, ae_state *_state); +void _optguardreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _optguardreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _optguardreport_clear(void* _p); +void _optguardreport_destroy(void* _p); +void _optguardnonc0report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _optguardnonc0report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _optguardnonc0report_clear(void* _p); +void _optguardnonc0report_destroy(void* _p); +void _optguardnonc1test0report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _optguardnonc1test0report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _optguardnonc1test0report_clear(void* _p); +void _optguardnonc1test0report_destroy(void* _p); +void _optguardnonc1test1report_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _optguardnonc1test1report_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _optguardnonc1test1report_clear(void* _p); +void _optguardnonc1test1report_destroy(void* _p); +#endif +#if defined(AE_COMPILE_OPTS) || !defined(AE_PARTIAL_BUILD) +void lptestproblemcreate(ae_int_t n, + ae_bool hasknowntarget, + double targetf, + lptestproblem* p, + ae_state *_state); +ae_bool lptestproblemhasknowntarget(lptestproblem* p, ae_state *_state); +double lptestproblemgettargetf(lptestproblem* p, ae_state *_state); +ae_int_t lptestproblemgetn(lptestproblem* p, ae_state *_state); +ae_int_t lptestproblemgetm(lptestproblem* p, ae_state *_state); +void lptestproblemsetscale(lptestproblem* p, + /* Real */ const ae_vector* s, + ae_state *_state); +void lptestproblemsetcost(lptestproblem* p, + /* Real */ const ae_vector* c, + ae_state *_state); +void lptestproblemsetbc(lptestproblem* p, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void lptestproblemsetlc2(lptestproblem* p, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t m, + ae_state *_state); +void lptestproblemalloc(ae_serializer* s, + const lptestproblem* p, + ae_state *_state); +void lptestproblemserialize(ae_serializer* s, + const lptestproblem* p, + ae_state *_state); +void lptestproblemunserialize(ae_serializer* s, + lptestproblem* p, + ae_state *_state); +ae_bool qpxproblemisquadraticobjective(qpxproblem* p, ae_state *_state); +ae_int_t qpxproblemgetn(qpxproblem* p, ae_state *_state); +ae_int_t qpxproblemgetmlc(qpxproblem* p, ae_state *_state); +ae_int_t qpxproblemgetmqc(qpxproblem* p, ae_state *_state); +ae_int_t qpxproblemgetmcc(qpxproblem* p, ae_state *_state); +ae_int_t qpxproblemgettotalconstraints(qpxproblem* p, ae_state *_state); +void qpxproblemgetinitialpoint(qpxproblem* p, + /* Real */ ae_vector* x0, + ae_state *_state); +ae_bool qpxproblemhasinitialpoint(qpxproblem* p, ae_state *_state); +void qpxproblemgetscale(qpxproblem* p, + /* Real */ ae_vector* s, + ae_state *_state); +ae_bool qpxproblemhasscale(qpxproblem* p, ae_state *_state); +void qpxproblemgetorigin(qpxproblem* p, + /* Real */ ae_vector* xorigin, + ae_state *_state); +ae_bool qpxproblemhasorigin(qpxproblem* p, ae_state *_state); +void qpxproblemgetlinearterm(qpxproblem* p, + /* Real */ ae_vector* c, + ae_state *_state); +void qpxproblemgetquadraticterm(qpxproblem* p, + sparsematrix* q, + ae_bool* isupper, + ae_state *_state); +ae_bool qpxproblemhasquadraticterm(qpxproblem* p, ae_state *_state); +void qpxproblemgetbc(qpxproblem* p, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + ae_state *_state); +void qpxproblemgetlc2(qpxproblem* p, + sparsematrix* a, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t* m, + ae_state *_state); +void qpxproblemsetxqc(qpxproblem* p, + xquadraticconstraints* src, + ae_state *_state); +void qpxproblemgetqc2i(qpxproblem* p, + ae_int_t idx, + sparsematrix* q, + ae_bool* isupper, + /* Real */ ae_vector* b, + double* cl, + double* cu, + ae_bool* applyorigin, + ae_state *_state); +void xqccopy(xquadraticconstraints* src, + xquadraticconstraints* dst, + ae_state *_state); +ae_int_t xqcgetcount(const xquadraticconstraints* xqc, ae_state *_state); +void _xlinearconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xlinearconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xlinearconstraints_clear(void* _p); +void _xlinearconstraints_destroy(void* _p); +void _lptestproblem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lptestproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lptestproblem_clear(void* _p); +void _lptestproblem_destroy(void* _p); +#endif +#if defined(AE_COMPILE_OPTSERV) || !defined(AE_PARTIAL_BUILD) +void checkbcviolation(/* Boolean */ const ae_vector* hasbndl, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* hasbndu, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* s, + ae_bool nonunits, + double* bcerr, + ae_int_t* bcidx, + ae_state *_state); +void checklcviolation(/* Real */ const ae_matrix* cleic, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t nec, + ae_int_t nic, + /* Real */ const ae_vector* x, + ae_int_t n, + double* lcerr, + ae_int_t* lcidx, + ae_state *_state); +void checklc2violation(const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* x, + double* lcerr, + ae_int_t* lcidx, + ae_state *_state); +void unscaleandchecklc2violation(/* Real */ const ae_vector* s, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* x, + double* sumerr, + double* maxerr, + ae_int_t* maxidx, + ae_state *_state); +void checknlcviolation(/* Real */ const ae_vector* fi, + ae_int_t ng, + ae_int_t nh, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state); +void unscaleandchecknlcviolation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* fscales, + ae_int_t ng, + ae_int_t nh, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state); +void unscaleandchecknlc2violation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* fscales, + /* Real */ const ae_vector* rawnl, + /* Real */ const ae_vector* rawnu, + ae_int_t cntnlc, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state); +void checknlc2violation(/* Real */ const ae_vector* fi, + /* Real */ const ae_vector* rawnl, + /* Real */ const ae_vector* rawnu, + ae_int_t cntnlc, + double* nlcerr, + ae_int_t* nlcidx, + ae_state *_state); +void trimprepare(double f, double* threshold, ae_state *_state); +void trimfunction(double* f, + /* Real */ ae_vector* g, + ae_int_t n, + double threshold, + ae_state *_state); +ae_bool enforceboundaryconstraints(/* Real */ ae_vector* x, + /* Real */ const ae_vector* bl, + /* Boolean */ const ae_vector* havebl, + /* Real */ const ae_vector* bu, + /* Boolean */ const ae_vector* havebu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state); +void projectgradientintobc(/* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + /* Real */ const ae_vector* bl, + /* Boolean */ const ae_vector* havebl, + /* Real */ const ae_vector* bu, + /* Boolean */ const ae_vector* havebu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state); +void calculatestepbound(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double alpha, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t* variabletofreeze, + double* valuetofreeze, + double* maxsteplen, + ae_state *_state); +ae_int_t postprocessboundedstep(/* Real */ ae_vector* x, + /* Real */ const ae_vector* xprev, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_int_t variabletofreeze, + double valuetofreeze, + double steptaken, + double maxsteplen, + ae_state *_state); +void filterdirection(/* Real */ ae_vector* d, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + /* Real */ const ae_vector* s, + ae_int_t nmain, + ae_int_t nslack, + double droptol, + ae_state *_state); +ae_int_t numberofchangedconstraints(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* xprev, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + ae_state *_state); +ae_bool findfeasiblepoint(/* Real */ ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* havebndl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* havebndu, + ae_int_t nmain, + ae_int_t nslack, + /* Real */ const ae_matrix* _ce, + ae_int_t k, + double epsi, + ae_int_t* qpits, + ae_int_t* gpaits, + ae_state *_state); +ae_bool derivativecheck(double f0, + double df0, + double f1, + double df1, + double f, + double df, + double width, + ae_state *_state); +void estimateparabolicmodel(double absasum, + double absasum2, + double mx, + double mb, + double md, + double d1, + double d2, + ae_int_t* d1est, + ae_int_t* d2est, + ae_state *_state); +void inexactlbfgspreconditioner(/* Real */ ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t k, + precbuflbfgs* buf, + ae_state *_state); +void preparelowrankpreconditioner(/* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t n, + ae_int_t k, + precbuflowrank* buf, + ae_state *_state); +void applylowrankpreconditioner(/* Real */ ae_vector* s, + precbuflowrank* buf, + ae_state *_state); +void smoothnessmonitorinit(smoothnessmonitor* monitor, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t k, + ae_bool checksmoothness, + ae_state *_state); +void smoothnessmonitorstartlinesearch(smoothnessmonitor* monitor, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state); +void smoothnessmonitorstartlinesearch1u(smoothnessmonitor* monitor, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* invs, + /* Real */ const ae_vector* x, + double f0, + /* Real */ const ae_vector* j0, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state); +void smoothnessmonitorenqueuepoint(smoothnessmonitor* monitor, + /* Real */ const ae_vector* d, + double stp, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* fi, + /* Real */ const ae_matrix* jac, + ae_state *_state); +void smoothnessmonitorenqueuepoint1u(smoothnessmonitor* monitor, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* invs, + /* Real */ const ae_vector* d, + double stp, + /* Real */ const ae_vector* x, + double f0, + /* Real */ const ae_vector* j0, + ae_state *_state); +void smoothnessmonitorfinalizelinesearch(smoothnessmonitor* monitor, + ae_state *_state); +void smoothnessmonitorstartlagrangianprobing(smoothnessmonitor* monitor, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* d, + double stpmax, + ae_int_t inneriter, + ae_int_t outeriter, + ae_state *_state); +ae_bool smoothnessmonitorprobelagrangian(smoothnessmonitor* monitor, + ae_state *_state); +void smoothnessmonitortracelagrangianprobingresults(smoothnessmonitor* monitor, + ae_state *_state); +void smoothnessmonitortracestatus(const smoothnessmonitor* monitor, + ae_bool callersuggeststrace, + ae_state *_state); +void smoothnessmonitorexportreport(smoothnessmonitor* monitor, + optguardreport* rep, + ae_state *_state); +ae_bool smoothnessmonitorcheckgradientatx0(smoothnessmonitor* monitor, + /* Real */ const ae_vector* unscaledx0, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_bool hasboxconstraints, + double teststep, + ae_state *_state); +void hessianinitbfgs(xbfgshessian* hess, + ae_int_t n, + ae_int_t resetfreq, + double stpshort, + ae_state *_state); +void hessianinitlowrank(xbfgshessian* hess, + ae_int_t n, + ae_int_t m, + double stpshort, + double maxhess, + ae_state *_state); +void hessianinitlowranksr1(xbfgshessian* hess, + ae_int_t n, + ae_int_t m, + double stpshort, + double maxhess, + ae_state *_state); +void hessiansetmaxhess(xbfgshessian* hess, + double maxhess, + ae_state *_state); +void hessiansetscales(xbfgshessian* hess, + /* Real */ const ae_vector* s, + ae_state *_state); +void hessiansetscalesinertial(xbfgshessian* hess, + /* Real */ const ae_vector* s, + ae_state *_state); +void hessianupdate(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_bool dotrace, + ae_state *_state); +void hessianupdatev2(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_int_t strategy, + ae_bool tryreplacelast, + ae_bool dotrace, + ae_int_t tracelevel, + ae_state *_state); +void hessianupdatesr1(xbfgshessian* hess, + /* Real */ const ae_vector* x0, + /* Real */ const ae_vector* g0, + /* Real */ const ae_vector* x1, + /* Real */ const ae_vector* g1, + ae_bool dotrace, + ae_int_t tracelevel, + ae_state *_state); +void hessianpoplatestifpossible(xbfgshessian* hess, ae_state *_state); +void hessianmultiplyby(xbfgshessian* hess, double s, ae_state *_state); +void hessiangetdiagonal(xbfgshessian* hess, + /* Real */ ae_vector* d, + ae_state *_state); +void hessiangetmatrix(xbfgshessian* hess, + ae_bool isupper, + /* Real */ ae_matrix* h, + ae_state *_state); +double hessiangetnrm2(xbfgshessian* hess, ae_state *_state); +double hessiangetnrm2stab(xbfgshessian* hess, ae_state *_state); +void hessiangetlowrank(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state); +void hessiangetlowrankmemory(xbfgshessian* hess, + double* sigma, + /* Real */ ae_matrix* s, + /* Real */ ae_matrix* y, + ae_int_t* updcnt, + ae_state *_state); +void hessiangetlowrankstabilized(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state); +void hessiangetlowrankstabilizedlbfgs(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state); +void hessiangetlowrankstabilizedsr1(xbfgshessian* hess, + /* Real */ ae_vector* d, + /* Real */ ae_matrix* corrc, + /* Real */ ae_vector* corrs, + ae_int_t* corrk, + ae_state *_state); +ae_int_t hessiangetmaxrank(const xbfgshessian* hess, ae_state *_state); +void hessianmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + ae_state *_state); +double hessianvmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + ae_state *_state); +void hessianxmv(xbfgshessian* hess, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* hx, + double* xhx, + ae_state *_state); +void motfcreaterandomunknown(ae_int_t n, + ae_int_t m, + ae_int_t nequality, + ae_int_t ninequality, + ae_int_t taskkind, + double nlquadratic, + double nlquartic, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfcreate1knownanswer(ae_int_t n, + double nlquadratic, + double nlquartic, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +ae_int_t motfgetmetaheuristicu1size(ae_state *_state); +ae_int_t motfgetmetaheuristicu2size(ae_state *_state); +ae_int_t motfgetmetaheuristicu3size(ae_state *_state); +ae_int_t motfgetnls1size(ae_state *_state); +ae_int_t motfgetnls2size(ae_state *_state); +void motfcreatemetaheuristicu1(ae_int_t problemidx, + ae_bool isrotated, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfcreatemetaheuristicu2(ae_int_t problemidx, + ae_bool isrotated, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfcreatemetaheuristicu3(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfcreatenls1(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfcreatenls2(ae_int_t problemidx, + hqrndstate* rs, + multiobjectivetestfunction* problem, + ae_state *_state); +void motfeval(const multiobjectivetestfunction* problem, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* fi, + ae_bool needfi, + /* Real */ ae_matrix* jac, + ae_bool needjac, + ae_state *_state); +void converttwosidedlctoonesidedold(const sparsematrix* sparsec, + ae_int_t ksparse, + /* Real */ const ae_matrix* densec, + ae_int_t kdense, + ae_int_t n, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + /* Real */ ae_matrix* olddensec, + /* Integer */ ae_vector* olddensect, + ae_int_t* olddensek, + ae_state *_state); +void converttwosidednlctoonesidedold(/* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + /* Integer */ ae_vector* nlcidx, + /* Real */ ae_vector* nlcmul, + /* Real */ ae_vector* nlcadd, + ae_int_t* cntnlec, + ae_int_t* cntnlic, + ae_state *_state); +void trustradincreasemomentum(double* growthfactor, + double growthincrease, + double maxgrowthfactor, + ae_state *_state); +void trustradresetmomentum(double* growthfactor, + double mingrowthfactor, + ae_state *_state); +void vfjallocdense(ae_int_t n, + ae_int_t m, + varsfuncjac* s, + ae_state *_state); +void vfjallocsparse(ae_int_t n, + ae_int_t m, + varsfuncjac* s, + ae_state *_state); +void vfjinitfromdense(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* fi, + ae_int_t m, + /* Real */ const ae_matrix* jac, + varsfuncjac* s, + ae_state *_state); +void vfjinitfromsparse(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* fi, + ae_int_t m, + const sparsematrix* jac, + varsfuncjac* s, + ae_state *_state); +void vfjcopy(const varsfuncjac* src, varsfuncjac* dst, ae_state *_state); +void critinitdefault(nlpstoppingcriteria* crit, ae_state *_state); +void critcopy(const nlpstoppingcriteria* src, + nlpstoppingcriteria* dst, + ae_state *_state); +void critsetcondv1(nlpstoppingcriteria* crit, + double epsf, + double eps, + ae_int_t maxits, + ae_state *_state); +double critgetepsf(const nlpstoppingcriteria* crit, ae_state *_state); +double critgeteps(const nlpstoppingcriteria* crit, ae_state *_state); +double critgetepswithdefault(const nlpstoppingcriteria* crit, + double defval, + ae_state *_state); +ae_int_t critgetmaxits(const nlpstoppingcriteria* crit, ae_state *_state); +void linesearchinitbisect(double f0, + double g0, + double alpha1, + double alphamax, + double c1, + double c2, + ae_bool strongwolfecond, + ae_int_t maxits, + ae_bool dotrace, + ae_int_t tracelevel, + linesearchstate* state, + ae_state *_state); +ae_bool linesearchiteration(linesearchstate* state, ae_state *_state); +void nlpfinit(double maxh, nlpfilter* s, ae_state *_state); +void nlpfinitfrom(const nlpfilter* src, nlpfilter* dst, ae_state *_state); +void nlpfinitx(double maxh, ae_int_t md, nlpfilter* s, ae_state *_state); +ae_bool nlpfisacceptable(nlpfilter* s, + double f0, + double h0, + double f1, + double h1, + ae_state *_state); +ae_bool nlpfisacceptable1(nlpfilter* s, + double f, + double h, + ae_state *_state); +void nlpfappend(nlpfilter* s, double f, double h, ae_state *_state); +void nlpfclear(nlpfilter* s, ae_state *_state); +void nlpfsetmaxh(nlpfilter* s, double maxh, ae_state *_state); +void xlcinit(ae_int_t n, xlinearconstraints* state, ae_state *_state); +void xlcsetlcmixed(xlinearconstraints* state, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + ae_state *_state); +void xlcsetlc2mixed(xlinearconstraints* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state); +void xlcaddlc2dense(xlinearconstraints* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void xlcaddlc2(xlinearconstraints* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void xlcaddlc2sparsefromdense(xlinearconstraints* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state); +void xlcconverttoold(xlinearconstraints* state, ae_state *_state); +void xlcconverttosparse(xlinearconstraints* state, ae_state *_state); +void xqcaddqc2list(xquadraticconstraints* xqc, + /* Integer */ const ae_vector* qridx, + /* Integer */ const ae_vector* qcidx, + /* Real */ const ae_vector* qvals, + ae_int_t qnnz, + ae_bool isupper, + /* Integer */ const ae_vector* bidx, + /* Real */ const ae_vector* bvals, + ae_int_t bnnz, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +void xqcaddqc2dense(xquadraticconstraints* xqc, + /* Real */ const ae_matrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +ae_int_t xccdenormalizedprimitivepowerconetype(ae_state *_state); +ae_int_t xccgenericorthogonalpowerconetype(ae_state *_state); +ae_int_t xccdenormalizedprimitiveconetype(ae_state *_state); +ae_int_t xccgenericorthogonalconetype(ae_state *_state); +ae_int_t xccprimitiveconetype(ae_state *_state); +ae_int_t xccprimitivepowerconetype(ae_state *_state); +void xccclear(xconicconstraints* state, ae_state *_state); +void xcccopy(xconicconstraints* src, + xconicconstraints* dst, + ae_state *_state); +void xcccopywithskipandpack(xconicconstraints* src, + /* Boolean */ const ae_vector* skipflags, + /* Integer */ const ae_vector* packxperm, + xconicconstraints* dst, + ae_state *_state); +ae_int_t xccgetcount(const xconicconstraints* xcc, ae_state *_state); +void xccaddsoccorthogonalnoncanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + double theta, + ae_bool applyorigin, + ae_state *_state); +void xccaddsoccprimitivecanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + ae_bool applyorigin, + ae_state *_state); +void xccaddpowccprimitivecanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + /* Real */ const ae_vector* alphapow, + ae_int_t kpow, + ae_bool applyorigin, + ae_state *_state); +void xccaddpowccorthogonalnoncanonic(xconicconstraints* xcc, + /* Integer */ const ae_vector* varidx, + /* Real */ const ae_vector* diag, + /* Real */ const ae_vector* shft, + ae_int_t nvars, + double theta, + /* Real */ const ae_vector* alphapow, + ae_int_t kpow, + ae_bool applyorigin, + ae_state *_state); +void xccfactoroutnonaxial(xconicconstraint* c, + ae_int_t k0, + double alpha0, + double alpha1, + ae_int_t k1, + ae_bool* hadk0, + ae_bool* hadk1, + ae_state *_state); +void unscalexbatchfinitebnd(/* Real */ const ae_vector* xs, + ae_int_t batchsize, + /* Real */ const ae_vector* s, + ae_int_t n, + /* Real */ const ae_vector* sclfinitebndl, + /* Real */ const ae_vector* sclfinitebndu, + /* Real */ const ae_vector* rawfinitebndl, + /* Real */ const ae_vector* rawfinitebndu, + /* Real */ ae_vector* xu, + ae_state *_state); +void _precbuflbfgs_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _precbuflbfgs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _precbuflbfgs_clear(void* _p); +void _precbuflbfgs_destroy(void* _p); +void _precbuflowrank_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _precbuflowrank_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _precbuflowrank_clear(void* _p); +void _precbuflowrank_destroy(void* _p); +void _xbfgshessian_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _xbfgshessian_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _xbfgshessian_clear(void* _p); +void _xbfgshessian_destroy(void* _p); +void _varsfuncjac_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _varsfuncjac_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _varsfuncjac_clear(void* _p); +void _varsfuncjac_destroy(void* _p); +void _nlpstoppingcriteria_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nlpstoppingcriteria_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nlpstoppingcriteria_clear(void* _p); +void _nlpstoppingcriteria_destroy(void* _p); +void _smoothnessmonitor_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _smoothnessmonitor_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _smoothnessmonitor_clear(void* _p); +void _smoothnessmonitor_destroy(void* _p); +void _multiobjectivetestfunction_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _multiobjectivetestfunction_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _multiobjectivetestfunction_clear(void* _p); +void _multiobjectivetestfunction_destroy(void* _p); +void _linesearchstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _linesearchstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _linesearchstate_clear(void* _p); +void _linesearchstate_destroy(void* _p); +void _nlpfilter_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nlpfilter_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nlpfilter_clear(void* _p); +void _nlpfilter_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINLBFGS) || !defined(AE_PARTIAL_BUILD) +void minlbfgscreate(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minlbfgsstate* state, + ae_state *_state); +void minlbfgscreatef(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minlbfgsstate* state, + ae_state *_state); +void minlbfgssetcond(minlbfgsstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minlbfgssetxrep(minlbfgsstate* state, + ae_bool needxrep, + ae_state *_state); +void minlbfgssetstpmax(minlbfgsstate* state, + double stpmax, + ae_state *_state); +void minlbfgssetscale(minlbfgsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minlbfgscreatex(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + ae_int_t flags, + double diffstep, + minlbfgsstate* state, + ae_state *_state); +void minlbfgssetprecdefault(minlbfgsstate* state, ae_state *_state); +void minlbfgssetpreccholesky(minlbfgsstate* state, + /* Real */ const ae_matrix* p, + ae_bool isupper, + ae_state *_state); +void minlbfgssetprecdiag(minlbfgsstate* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void minlbfgssetprecscale(minlbfgsstate* state, ae_state *_state); +void minlbfgssetprecrankklbfgsfast(minlbfgsstate* state, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t cnt, + ae_state *_state); +void minlbfgssetpreclowrankexact(minlbfgsstate* state, + /* Real */ const ae_vector* d, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* w, + ae_int_t cnt, + ae_state *_state); +ae_bool minlbfgsiteration(minlbfgsstate* state, ae_state *_state); +void minlbfgsoptguardgradient(minlbfgsstate* state, + double teststep, + ae_state *_state); +void minlbfgsoptguardsmoothness(minlbfgsstate* state, + ae_int_t level, + ae_state *_state); +void minlbfgsoptguardresults(minlbfgsstate* state, + optguardreport* rep, + ae_state *_state); +void minlbfgsoptguardnonc1test0results(const minlbfgsstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state); +void minlbfgsoptguardnonc1test1results(minlbfgsstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state); +void minlbfgsresults(const minlbfgsstate* state, + /* Real */ ae_vector* x, + minlbfgsreport* rep, + ae_state *_state); +void minlbfgsresultsbuf(const minlbfgsstate* state, + /* Real */ ae_vector* x, + minlbfgsreport* rep, + ae_state *_state); +void minlbfgsrestartfrom(minlbfgsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minlbfgsrequesttermination(minlbfgsstate* state, ae_state *_state); +void minlbfgssetprotocolv1(minlbfgsstate* state, ae_state *_state); +void minlbfgssetprotocolv2(minlbfgsstate* state, ae_state *_state); +void _minlbfgsstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlbfgsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlbfgsstate_clear(void* _p); +void _minlbfgsstate_destroy(void* _p); +void _minlbfgsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlbfgsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlbfgsreport_clear(void* _p); +void _minlbfgsreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_CQMODELS) || !defined(AE_PARTIAL_BUILD) +void cqminit(ae_int_t n, convexquadraticmodel* s, ae_state *_state); +void cqmseta(convexquadraticmodel* s, + /* Real */ const ae_matrix* a, + ae_bool isupper, + double alpha, + ae_state *_state); +void cqmgeta(const convexquadraticmodel* s, + /* Real */ ae_matrix* a, + ae_state *_state); +void cqmrewritedensediagonal(convexquadraticmodel* s, + /* Real */ const ae_vector* z, + ae_state *_state); +void cqmsetd(convexquadraticmodel* s, + /* Real */ const ae_vector* d, + double tau, + ae_state *_state); +void cqmdropa(convexquadraticmodel* s, ae_state *_state); +void cqmsetb(convexquadraticmodel* s, + /* Real */ const ae_vector* b, + ae_state *_state); +void cqmsetq(convexquadraticmodel* s, + /* Real */ const ae_matrix* q, + /* Real */ const ae_vector* r, + ae_int_t k, + double theta, + ae_state *_state); +void cqmsetactiveset(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Boolean */ const ae_vector* activeset, + ae_state *_state); +double cqmeval(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state); +void cqmevalx(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + double* r, + double* noise, + ae_state *_state); +void cqmgradunconstrained(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* g, + ae_state *_state); +double cqmxtadx2(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* tmp, + ae_state *_state); +void cqmadx(const convexquadraticmodel* s, + /* Real */ const ae_vector* x, + /* Real */ ae_vector* y, + ae_state *_state); +ae_bool cqmconstrainedoptimum(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state); +void cqmscalevector(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state); +void cqmgetdiaga(convexquadraticmodel* s, + /* Real */ ae_vector* x, + ae_state *_state); +double cqmdebugconstrainedevalt(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state); +double cqmdebugconstrainedevale(convexquadraticmodel* s, + /* Real */ const ae_vector* x, + ae_state *_state); +void _convexquadraticmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _convexquadraticmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _convexquadraticmodel_clear(void* _p); +void _convexquadraticmodel_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LPQPSERV) || !defined(AE_PARTIAL_BUILD) +void scaleshiftmixedlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_state *_state); +void scaleshiftbcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + ae_int_t n, + ae_state *_state); +void scaleshiftdensebrlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + /* Real */ ae_matrix* densea, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t m, + ae_state *_state); +void scaleshiftmixedbrlcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_state *_state); +void scaleshiftsparselcinplace(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_state *_state); +void scaledenseqpinplace(/* Real */ ae_matrix* densea, + ae_bool isupper, + ae_int_t nmain, + /* Real */ ae_vector* denseb, + ae_int_t ntotal, + /* Real */ const ae_vector* s, + ae_state *_state); +void scalesparseqpinplace(/* Real */ const ae_vector* s, + ae_int_t n, + sparsematrix* sparsea, + /* Real */ ae_matrix* densecorrc, + /* Real */ ae_vector* densecorrd, + ae_int_t corrrank, + /* Real */ ae_vector* denseb, + ae_state *_state); +void normalizedensebrlcinplace(/* Real */ ae_matrix* densea, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t n, + ae_int_t m, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state); +void normalizemixedbrlcinplace(sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ ae_matrix* densea, + ae_int_t mdense, + /* Real */ ae_vector* ab, + /* Real */ ae_vector* ar, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state); +void normalizedenselcinplace(/* Real */ ae_matrix* densea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state); +void normalizesparselcinplace(sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + ae_bool limitedamplification, + /* Real */ ae_vector* rownorms, + ae_bool neednorms, + ae_state *_state); +void normalizesparselcinplaceuniform(sparsematrix* sparsea, + ae_int_t m, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t n, + /* Real */ ae_vector* ascales, + ae_bool needscales, + ae_state *_state); +double normalizedenseqpinplace(/* Real */ ae_matrix* densea, + ae_bool isupper, + ae_int_t nmain, + /* Real */ ae_vector* denseb, + ae_int_t ntotal, + ae_state *_state); +double normalizesparseqpinplace(sparsematrix* sparsea, + ae_bool isupper, + /* Real */ ae_matrix* densecorrc, + /* Real */ ae_vector* densecorrd, + ae_int_t corrrank, + /* Real */ ae_vector* denseb, + ae_int_t n, + ae_state *_state); +void unscaleunshiftpointbc(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + /* Real */ const ae_vector* sclsftbndl, + /* Real */ const ae_vector* sclsftbndu, + /* Boolean */ const ae_vector* hasbndl, + /* Boolean */ const ae_vector* hasbndu, + /* Real */ ae_vector* x, + ae_int_t n, + ae_state *_state); +void quadraticlinearconverttodenseltr(/* Real */ const ae_vector* rawc, + ae_int_t n, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ ae_vector* c, + /* Real */ ae_matrix* h, + ae_state *_state); +#endif +#if defined(AE_COMPILE_SNNLS) || !defined(AE_PARTIAL_BUILD) +void snnlsinit(ae_int_t nsmax, + ae_int_t ndmax, + ae_int_t nrmax, + snnlssolver* s, + ae_state *_state); +void snnlssetproblem(snnlssolver* s, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* b, + ae_int_t ns, + ae_int_t nd, + ae_int_t nr, + ae_state *_state); +void snnlsdropnnc(snnlssolver* s, ae_int_t idx, ae_state *_state); +void snnlssolve(snnlssolver* s, + /* Real */ ae_vector* x, + ae_state *_state); +void _snnlssolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _snnlssolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _snnlssolver_clear(void* _p); +void _snnlssolver_destroy(void* _p); +#endif +#if defined(AE_COMPILE_SACTIVESETS) || !defined(AE_PARTIAL_BUILD) +void sasinit(ae_int_t n, sactiveset* s, ae_state *_state); +void sassetscale(sactiveset* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void sassetprecdiag(sactiveset* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void sassetbc(sactiveset* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void sassetlc(sactiveset* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void sassetlcx(sactiveset* state, + /* Real */ const ae_matrix* cleic, + ae_int_t nec, + ae_int_t nic, + ae_state *_state); +ae_bool sasstartoptimization(sactiveset* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void sasexploredirection(const sactiveset* state, + /* Real */ const ae_vector* d, + double* stpmax, + ae_int_t* cidx, + double* vval, + ae_state *_state); +ae_int_t sasmoveto(sactiveset* state, + /* Real */ const ae_vector* xn, + ae_bool needact, + ae_int_t cidx, + double cval, + ae_state *_state); +void sasimmediateactivation(sactiveset* state, + ae_int_t cidx, + double cval, + ae_state *_state); +void sasconstraineddescent(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state); +void sasconstraineddescentprec(sactiveset* state, + /* Real */ const ae_vector* g, + /* Real */ ae_vector* d, + ae_state *_state); +void sasconstraineddirection(sactiveset* state, + /* Real */ ae_vector* d, + ae_state *_state); +void sasconstraineddirectionprec(sactiveset* state, + /* Real */ ae_vector* d, + ae_state *_state); +void sascorrection(sactiveset* state, + /* Real */ ae_vector* x, + double* penalty, + ae_state *_state); +double sasactivelcpenalty1(sactiveset* state, + /* Real */ const ae_vector* x, + ae_state *_state); +double sasscaledconstrainednorm(sactiveset* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void sasstopoptimization(sactiveset* state, ae_state *_state); +void sasreactivateconstraints(sactiveset* state, + /* Real */ const ae_vector* gc, + ae_state *_state); +void sasreactivateconstraintsprec(sactiveset* state, + /* Real */ const ae_vector* gc, + ae_state *_state); +void sasrebuildbasis(sactiveset* state, ae_state *_state); +void sasappendtobasis(sactiveset* state, + /* Boolean */ const ae_vector* newentries, + ae_state *_state); +void _sactiveset_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sactiveset_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sactiveset_clear(void* _p); +void _sactiveset_destroy(void* _p); +#endif +#if defined(AE_COMPILE_QQPSOLVER) || !defined(AE_PARTIAL_BUILD) +void qqploaddefaults(ae_int_t n, qqpsettings* s, ae_state *_state); +void qqpcopysettings(const qqpsettings* src, + qqpsettings* dst, + ae_state *_state); +void qqppreallocategrowdense(qqpbuffers* sstate, + ae_int_t nexpected, + ae_int_t ngrowto, + ae_state *_state); +void qqpoptimize(const convexquadraticmodel* cqmac, + const sparsematrix* sparseac, + /* Real */ const ae_matrix* denseac, + ae_int_t akind, + ae_bool isupper, + /* Real */ const ae_vector* bc, + /* Real */ const ae_vector* bndlc, + /* Real */ const ae_vector* bnduc, + /* Real */ const ae_vector* sc, + /* Real */ const ae_vector* xoriginc, + ae_int_t nc, + const qqpsettings* settings, + qqpbuffers* sstate, + /* Real */ ae_vector* xs, + ae_int_t* terminationtype, + ae_state *_state); +void _qqpsettings_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _qqpsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _qqpsettings_clear(void* _p); +void _qqpsettings_destroy(void* _p); +void _qqpbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _qqpbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _qqpbuffers_clear(void* _p); +void _qqpbuffers_destroy(void* _p); +#endif +#if defined(AE_COMPILE_QPDENSEAULSOLVER) || !defined(AE_PARTIAL_BUILD) +void qpdenseaulloaddefaults(ae_int_t nmain, + qpdenseaulsettings* s, + ae_state *_state); +void qpdenseauloptimize(const convexquadraticmodel* a, + const sparsematrix* sparsea, + ae_int_t akind, + ae_bool sparseaupper, + /* Real */ const ae_vector* b, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nn, + /* Real */ const ae_matrix* cleic, + ae_int_t dnec, + ae_int_t dnic, + const sparsematrix* scleic, + ae_int_t snec, + ae_int_t snic, + ae_bool renormlc, + const qpdenseaulsettings* settings, + qpdenseaulbuffers* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state); +void _qpdenseaulsettings_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _qpdenseaulsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _qpdenseaulsettings_clear(void* _p); +void _qpdenseaulsettings_destroy(void* _p); +void _qpdenseaulbuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _qpdenseaulbuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _qpdenseaulbuffers_clear(void* _p); +void _qpdenseaulbuffers_destroy(void* _p); +#endif +#if defined(AE_COMPILE_VIPMSOLVER) || !defined(AE_PARTIAL_BUILD) +void vipminitdense(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_bool normalize, + ae_state *_state); +void vipminitdensewithslacks(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nmain, + ae_int_t n, + ae_bool normalize, + ae_state *_state); +void vipminitsparse(vipmstate* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t n, + ae_bool normalize, + ae_state *_state); +void vipmsetquadraticlinear(vipmstate* state, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ const ae_vector* c, + ae_state *_state); +void vipmsetconstraints(vipmstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ const ae_matrix* densea, + ae_int_t mdense, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_state *_state); +void vipmsetcond(vipmstate* state, + double epsp, + double epsd, + double epsgap, + ae_state *_state); +void vipmoptimize(vipmstate* state, + ae_bool dropbigbounds, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state); +void _vipmvars_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _vipmvars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _vipmvars_clear(void* _p); +void _vipmvars_destroy(void* _p); +void _vipmreducedsparsesystem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _vipmreducedsparsesystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _vipmreducedsparsesystem_clear(void* _p); +void _vipmreducedsparsesystem_destroy(void* _p); +void _vipmrighthandside_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _vipmrighthandside_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _vipmrighthandside_clear(void* _p); +void _vipmrighthandside_destroy(void* _p); +void _vipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _vipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _vipmstate_clear(void* _p); +void _vipmstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_IPM2SOLVER) || !defined(AE_PARTIAL_BUILD) +void ipm2init(ipm2state* state, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + ae_int_t nuser, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + ae_bool isupper, + /* Real */ const ae_matrix* ccorr, + /* Real */ const ae_vector* dcorr, + ae_int_t kcorr, + /* Real */ const ae_vector* c, + double targetscale, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + ae_int_t msparse, + /* Real */ const ae_matrix* densea, + ae_int_t mdense, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_bool uniformlcscale, + ae_bool skipnormalization, + ae_state *_state); +void ipm2setreg(ipm2state* state, + double regxy, + /* Real */ const ae_vector* originx, + /* Real */ const ae_vector* originy, + ae_state *_state); +void ipm2setcond(ipm2state* state, + double epsp, + double epsd, + double epsgap, + ae_state *_state); +void ipm2setmaxits(ipm2state* state, ae_int_t maxits, ae_state *_state); +void ipm2proposeordering(ipm2state* state, + ae_int_t n, + ae_bool isdiagonalq, + /* Boolean */ const ae_vector* hasbndl, + /* Boolean */ const ae_vector* hasbndu, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + /* Integer */ ae_vector* p, + ae_state *_state); +void ipm2setordering(ipm2state* state, + /* Integer */ const ae_vector* p, + ae_state *_state); +void ipm2optimize(ipm2state* state, + ae_bool dropbigbounds, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state); +void _ipm2vars_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ipm2vars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ipm2vars_clear(void* _p); +void _ipm2vars_destroy(void* _p); +void _ipm2reducedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ipm2reducedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ipm2reducedsystem_clear(void* _p); +void _ipm2reducedsystem_destroy(void* _p); +void _ipm2righthandside_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ipm2righthandside_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ipm2righthandside_clear(void* _p); +void _ipm2righthandside_destroy(void* _p); +void _ipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ipm2state_clear(void* _p); +void _ipm2state_destroy(void* _p); +#endif +#if defined(AE_COMPILE_ECQPSOLVER) || !defined(AE_PARTIAL_BUILD) +void ecqpsolve(ecqpstate* state, + ae_int_t nuser, + const sparsematrix* lowerh, + /* Real */ const ae_vector* c, + const sparsematrix* sparsea, + /* Real */ const ae_vector* ae, + ae_int_t m, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* laglc, + ae_int_t* terminationtype, + ae_state *_state); +void _ecqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ecqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ecqpstate_clear(void* _p); +void _ecqpstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_GIPM) || !defined(AE_PARTIAL_BUILD) +double gipmgetinitprimdual(ae_state *_state); +void gipminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x0, + ae_int_t nraw, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t mflex, + ae_int_t mhard, + /* Real */ const ae_vector* fscales, + /* Boolean */ const ae_vector* doqnreport, + double eps, + ae_int_t maxits, + ae_bool isfirstorder, + gipmstate* state, + ae_state *_state); +ae_bool gipmiteration(gipmstate* state, + ae_bool userterminationneeded, + ae_state *_state); +void gipmresults(gipmstate* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagxc, + ae_int_t* terminationtype, + ae_state *_state); +void _gipmvars_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipmvars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipmvars_clear(void* _p); +void _gipmvars_destroy(void* _p); +void _gipmrhs_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipmrhs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipmrhs_clear(void* _p); +void _gipmrhs_destroy(void* _p); +void _gipmcondensedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipmcondensedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipmcondensedsystem_clear(void* _p); +void _gipmcondensedsystem_destroy(void* _p); +void _gipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipmstate_clear(void* _p); +void _gipmstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_GQPIPM) || !defined(AE_PARTIAL_BUILD) +void gqpipmcanonicalizeconicconstraints(/* Real */ ae_vector* s, + /* Real */ ae_vector* xorigin, + /* Real */ ae_vector* b, + /* Real */ ae_vector* bndl, + /* Real */ ae_vector* bndu, + /* Real */ ae_vector* xs, + sparsematrix* sparseh, + ae_bool hupper, + ae_bool hash, + ae_int_t* n, + sparsematrix* a, + /* Real */ ae_vector* al, + /* Real */ ae_vector* au, + ae_int_t* m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + /* Real */ ae_vector* lagbcmin, + /* Real */ ae_vector* lagbcmax, + ae_state *_state); +void gqpipminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* x0, + ae_int_t n, + ae_bool isdense, + ae_bool isfirstorder, + double eps, + ae_int_t maxits, + gqpipmstate* state, + ae_state *_state); +void gqpipmsetquadraticlinear(gqpipmstate* state, + /* Real */ const ae_matrix* denseh, + const sparsematrix* sparseh, + ae_int_t hkind, + /* Real */ const ae_vector* c, + ae_state *_state); +void gqpipmsetconstraints(gqpipmstate* state, + const sparsematrix* sparsea, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_state *_state); +void gqpipmsetquasinewtonparams(gqpipmstate* state, + ae_int_t memlen, + ae_int_t maxoffdiag, + ae_state *_state); +void gqpipmoptimize(gqpipmstate* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + ae_int_t* terminationtype, + ae_state *_state); +void _gqpsparseconichessian_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gqpsparseconichessian_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gqpsparseconichessian_clear(void* _p); +void _gqpsparseconichessian_destroy(void* _p); +void _gqpoptionaldense_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gqpoptionaldense_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gqpoptionaldense_clear(void* _p); +void _gqpoptionaldense_destroy(void* _p); +void _gqpipmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gqpipmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gqpipmstate_clear(void* _p); +void _gqpipmstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LPQPPRESOLVE) || !defined(AE_PARTIAL_BUILD) +void presolvenonescaleuser(/* Real */ const ae_vector* s, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparseh, + ae_bool isupper, + ae_bool hash, + ae_int_t n, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_bool dotrace, + presolveinfo* info, + ae_state *_state); +void presolvelp(/* Real */ const ae_vector* raws, + /* Real */ const ae_vector* rawc, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + ae_int_t n, + const sparsematrix* rawsparsea, + /* Real */ const ae_vector* rawal, + /* Real */ const ae_vector* rawau, + ae_int_t m, + xquadraticconstraints* xqc, + xconicconstraints* xcc, + ae_bool dotrace, + presolveinfo* presolved, + ae_state *_state); +void presolveqp(/* Real */ const ae_vector* raws, + /* Real */ const ae_vector* xorigin, + /* Real */ const ae_vector* rawc, + /* Real */ const ae_vector* rawbndl, + /* Real */ const ae_vector* rawbndu, + const sparsematrix* rawsparseh, + ae_bool isupper, + ae_bool hash, + ae_int_t n, + const sparsematrix* rawsparsea, + /* Real */ const ae_vector* rawal, + /* Real */ const ae_vector* rawau, + ae_int_t m, + xquadraticconstraints* rawxqc, + xconicconstraints* rawxcc, + ae_bool dotrace, + presolveinfo* presolved, + ae_state *_state); +void presolvefwd(presolveinfo* s, + /* Real */ ae_vector* xx, + ae_state *_state); +void presolvebwd(presolveinfo* info, + /* Real */ ae_vector* x, + /* Integer */ ae_vector* stats, + ae_bool needstats, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* laglc, + /* Real */ ae_vector* lagqc, + ae_state *_state); +void _dynamiccrs_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dynamiccrs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dynamiccrs_clear(void* _p); +void _dynamiccrs_destroy(void* _p); +void _dynamiccrsqconstraint_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dynamiccrsqconstraint_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dynamiccrsqconstraint_clear(void* _p); +void _dynamiccrsqconstraint_destroy(void* _p); +void _dynamiccrsqconstraints_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dynamiccrsqconstraints_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dynamiccrsqconstraints_clear(void* _p); +void _dynamiccrsqconstraints_destroy(void* _p); +void _presolvebuffers_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _presolvebuffers_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _presolvebuffers_clear(void* _p); +void _presolvebuffers_destroy(void* _p); +void _presolverstack_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _presolverstack_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _presolverstack_clear(void* _p); +void _presolverstack_destroy(void* _p); +void _presolvervcstats_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _presolvervcstats_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _presolvervcstats_clear(void* _p); +void _presolvervcstats_destroy(void* _p); +void _presolveinfo_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _presolveinfo_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _presolveinfo_clear(void* _p); +void _presolveinfo_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINQP) || !defined(AE_PARTIAL_BUILD) +void minqpcreate(ae_int_t n, minqpstate* state, ae_state *_state); +void minqpsetlinearterm(minqpstate* state, + /* Real */ const ae_vector* b, + ae_state *_state); +void minqpsetquadraticterm(minqpstate* state, + /* Real */ const ae_matrix* a, + ae_bool isupper, + ae_state *_state); +void minqpsetquadratictermsparse(minqpstate* state, + const sparsematrix* a, + ae_bool isupper, + ae_state *_state); +void minqpsetstartingpoint(minqpstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minqpsetorigin(minqpstate* state, + /* Real */ const ae_vector* xorigin, + ae_state *_state); +void minqpsetscale(minqpstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minqpsetscaleautodiag(minqpstate* state, ae_state *_state); +void minqpsetalgodenseaul(minqpstate* state, + double epsx, + double rho, + ae_int_t itscnt, + ae_state *_state); +void minqpsetalgodenseipm(minqpstate* state, double eps, ae_state *_state); +void minqpsetalgosparseipm(minqpstate* state, + double eps, + ae_state *_state); +void minqpsetalgodensegenipm(minqpstate* state, + double eps, + ae_state *_state); +void minqpsetalgosparsegenipm(minqpstate* state, + double eps, + ae_state *_state); +void minqpsetalgohybridgenipm(minqpstate* state, + double eps, + ae_int_t memlen, + ae_int_t maxoffdiag, + ae_state *_state); +void minqpsetalgosparseecqp(minqpstate* state, ae_state *_state); +void minqpsetalgoquickqp(minqpstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxouterits, + ae_bool usenewton, + ae_state *_state); +void minqpsetbc(minqpstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minqpsetbcall(minqpstate* state, + double bndl, + double bndu, + ae_state *_state); +void minqpsetbci(minqpstate* state, + ae_int_t i, + double bndl, + double bndu, + ae_state *_state); +void minqpsetlc(minqpstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minqpsetlcsparse(minqpstate* state, + const sparsematrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minqpsetlcmixed(minqpstate* state, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + ae_state *_state); +void minqpsetlcmixedlegacy(minqpstate* state, + /* Real */ const ae_matrix* densec, + /* Integer */ const ae_vector* densect, + ae_int_t densek, + const sparsematrix* sparsec, + /* Integer */ const ae_vector* sparsect, + ae_int_t sparsek, + ae_state *_state); +void minqpsetlc2dense(minqpstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minqpsetlc2(minqpstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minqpsetlc2mixed(minqpstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state); +void minqpaddlc2dense(minqpstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void minqpaddlc2(minqpstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void minqpaddlc2sparsefromdense(minqpstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state); +void minqpclearqc(minqpstate* state, ae_state *_state); +ae_int_t minqpaddqc2(minqpstate* state, + const sparsematrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +ae_int_t minqpaddqc2list(minqpstate* state, + /* Integer */ const ae_vector* qridx, + /* Integer */ const ae_vector* qcidx, + /* Real */ const ae_vector* qvals, + ae_int_t qnnz, + ae_bool isupper, + /* Integer */ const ae_vector* bidx, + /* Real */ const ae_vector* bvals, + ae_int_t bnnz, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +ae_int_t minqpaddqc2dense(minqpstate* state, + /* Real */ const ae_matrix* q, + ae_bool isupper, + /* Real */ const ae_vector* b, + double cl, + double cu, + ae_bool applyorigin, + ae_state *_state); +void minqpclearcc(minqpstate* state, ae_state *_state); +ae_int_t minqpaddsoccprimitive(minqpstate* state, + ae_int_t range0, + ae_int_t range1, + ae_int_t axisidx, + ae_bool applyorigin, + ae_state *_state); +ae_int_t minqpaddsoccorthogonal(minqpstate* state, + /* Integer */ const ae_vector* idx, + /* Real */ const ae_vector* a, + /* Real */ const ae_vector* c, + ae_int_t k, + double theta, + ae_bool applyorigin, + ae_state *_state); +ae_int_t minqpaddpowccprimitive(minqpstate* state, + ae_int_t range0, + ae_int_t range1, + ae_int_t axisidx, + double alpha, + ae_bool applyorigin, + ae_state *_state); +ae_int_t minqpaddpowccorthogonal(minqpstate* state, + /* Integer */ const ae_vector* idx, + /* Real */ const ae_vector* a, + /* Real */ const ae_vector* c, + ae_int_t k, + double theta, + /* Real */ const ae_vector* alphav, + ae_int_t kpow, + ae_bool applyorigin, + ae_state *_state); +void minqpoptimize(minqpstate* state, ae_state *_state); +void minqpresults(const minqpstate* state, + /* Real */ ae_vector* x, + minqpreport* rep, + ae_state *_state); +void minqpresultsbuf(const minqpstate* state, + /* Real */ ae_vector* x, + minqpreport* rep, + ae_state *_state); +void minqpexport(minqpstate* state, qpxproblem* p, ae_state *_state); +void minqpimport(qpxproblem* p, minqpstate* s, ae_state *_state); +void minqpsetlineartermfast(minqpstate* state, + /* Real */ const ae_vector* b, + ae_state *_state); +void minqpsetquadratictermfast(minqpstate* state, + /* Real */ const ae_matrix* a, + ae_bool isupper, + double s, + ae_state *_state); +void minqprewritediagonal(minqpstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minqpsetstartingpointfast(minqpstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minqpsetoriginfast(minqpstate* state, + /* Real */ const ae_vector* xorigin, + ae_state *_state); +void _minqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minqpstate_clear(void* _p); +void _minqpstate_destroy(void* _p); +void _minqpreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minqpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minqpreport_clear(void* _p); +void _minqpreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NLCFSQP) || !defined(AE_PARTIAL_BUILD) +void minfsqpinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const sparsematrix* sparsea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t lccnt, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + const nlpstoppingcriteria* criteria, + ae_bool usedensebfgs, + minfsqpstate* state, + ae_state *_state); +void minfsqpsetadditsforctol(minfsqpstate* state, + ae_int_t addits, + double ctol, + ae_state *_state); +void minfsqpsetinittrustrad(minfsqpstate* state, + double rad0, + ae_state *_state); +ae_bool minfsqpiteration(minfsqpstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state); +void _minfsqpsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minfsqpsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minfsqpsubsolver_clear(void* _p); +void _minfsqpsubsolver_destroy(void* _p); +void _minfsqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minfsqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minfsqpstate_clear(void* _p); +void _minfsqpstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINLM) || !defined(AE_PARTIAL_BUILD) +void minlmcreatevj(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minlmstate* state, + ae_state *_state); +void minlmcreatev(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minlmstate* state, + ae_state *_state); +void minlmsetcond(minlmstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minlmsetxrep(minlmstate* state, ae_bool needxrep, ae_state *_state); +void minlmsetstpmax(minlmstate* state, double stpmax, ae_state *_state); +void minlmsetscale(minlmstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minlmsetbc(minlmstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minlmsetlc(minlmstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minlmsetacctype(minlmstate* state, + ae_int_t acctype, + ae_state *_state); +void minlmsetnonmonotonicsteps(minlmstate* state, + ae_int_t cnt, + ae_state *_state); +void minlmsetnumdiff(minlmstate* state, + ae_int_t formulatype, + ae_state *_state); +ae_bool minlmiteration(minlmstate* state, ae_state *_state); +void minlmoptguardgradient(minlmstate* state, + double teststep, + ae_state *_state); +void minlmoptguardresults(minlmstate* state, + optguardreport* rep, + ae_state *_state); +void minlmresults(const minlmstate* state, + /* Real */ ae_vector* x, + minlmreport* rep, + ae_state *_state); +void minlmresultsbuf(const minlmstate* state, + /* Real */ ae_vector* x, + minlmreport* rep, + ae_state *_state); +void minlmrestartfrom(minlmstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minlmrequesttermination(minlmstate* state, ae_state *_state); +void minlmsetprotocolv1(minlmstate* state, ae_state *_state); +void minlmsetprotocolv2(minlmstate* state, ae_state *_state); +void unpackdj(ae_int_t m, + ae_int_t n, + /* Real */ const ae_vector* replydj, + /* Real */ ae_matrix* jac, + ae_state *_state); +void _minlmstepfinder_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlmstepfinder_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlmstepfinder_clear(void* _p); +void _minlmstepfinder_destroy(void* _p); +void _minlmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlmstate_clear(void* _p); +void _minlmstate_destroy(void* _p); +void _minlmreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlmreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlmreport_clear(void* _p); +void _minlmreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NLCAUL) || !defined(AE_PARTIAL_BUILD) +void minaulinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + const nlpstoppingcriteria* criteria, + ae_int_t maxouterits, + minaulstate* state, + ae_state *_state); +ae_bool minauliteration(minaulstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state); +void inequalityshiftedbarrierfunction(double alpha, + double* f, + double* df, + double* d2f, + ae_state *_state); +void _minaulpreconditioner_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minaulpreconditioner_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minaulpreconditioner_clear(void* _p); +void _minaulpreconditioner_destroy(void* _p); +void _minaulstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minaulstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minaulstate_clear(void* _p); +void _minaulstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINCG) || !defined(AE_PARTIAL_BUILD) +void mincgcreate(ae_int_t n, + /* Real */ const ae_vector* x, + mincgstate* state, + ae_state *_state); +void mincgcreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + mincgstate* state, + ae_state *_state); +void mincgsetcond(mincgstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state); +void mincgsetscale(mincgstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void mincgsetxrep(mincgstate* state, ae_bool needxrep, ae_state *_state); +void mincgsetdrep(mincgstate* state, ae_bool needdrep, ae_state *_state); +void mincgsetcgtype(mincgstate* state, ae_int_t cgtype, ae_state *_state); +void mincgsetstpmax(mincgstate* state, double stpmax, ae_state *_state); +void mincgsuggeststep(mincgstate* state, double stp, ae_state *_state); +double mincglastgoodstep(mincgstate* state, ae_state *_state); +void mincgsetprecdefault(mincgstate* state, ae_state *_state); +void mincgsetprecdiag(mincgstate* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void mincgsetprecscale(mincgstate* state, ae_state *_state); +ae_bool mincgiteration(mincgstate* state, ae_state *_state); +void mincgoptguardgradient(mincgstate* state, + double teststep, + ae_state *_state); +void mincgoptguardsmoothness(mincgstate* state, + ae_int_t level, + ae_state *_state); +void mincgoptguardresults(mincgstate* state, + optguardreport* rep, + ae_state *_state); +void mincgoptguardnonc1test0results(const mincgstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state); +void mincgoptguardnonc1test1results(mincgstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state); +void mincgresults(const mincgstate* state, + /* Real */ ae_vector* x, + mincgreport* rep, + ae_state *_state); +void mincgresultsbuf(const mincgstate* state, + /* Real */ ae_vector* x, + mincgreport* rep, + ae_state *_state); +void mincgrestartfrom(mincgstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void mincgrequesttermination(mincgstate* state, ae_state *_state); +void mincgsetprecdiagfast(mincgstate* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void mincgsetpreclowrankfast(mincgstate* state, + /* Real */ const ae_vector* d1, + /* Real */ const ae_vector* c, + /* Real */ const ae_matrix* v, + ae_int_t vcnt, + ae_state *_state); +void mincgsetprecvarpart(mincgstate* state, + /* Real */ const ae_vector* d2, + ae_state *_state); +void mincgsetprotocolv1(mincgstate* state, ae_state *_state); +void _mincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mincgstate_clear(void* _p); +void _mincgstate_destroy(void* _p); +void _mincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mincgreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mincgreport_clear(void* _p); +void _mincgreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DFGENMOD) || !defined(AE_PARTIAL_BUILD) +void dfgminitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + ae_int_t m, + ae_bool isls, + ae_int_t modeltype, + const nlpstoppingcriteria* criteria, + ae_int_t nnoisyrestarts, + double rad0, + ae_int_t maxfev, + dfgmstate* state, + ae_state *_state); +void dfgmsetlc2(dfgmstate* state, + const sparsematrix* c, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t m, + ae_state *_state); +void dfgmsetnlc2(dfgmstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t m, + ae_state *_state); +ae_bool dfgmiteration(dfgmstate* state, + ae_bool userterminationneeded, + ae_state *_state); +void linregline(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + double* a, + double* b, + double* corrxy, + ae_state *_state); +void _df2psmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _df2psmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _df2psmodel_clear(void* _p); +void _df2psmodel_destroy(void* _p); +void _dfolsamodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfolsamodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfolsamodel_clear(void* _p); +void _dfolsamodel_destroy(void* _p); +void _dforbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dforbfmodel_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dforbfmodel_clear(void* _p); +void _dforbfmodel_destroy(void* _p); +void _dfgmstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dfgmstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dfgmstate_clear(void* _p); +void _dfgmstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NLCSQP) || !defined(AE_PARTIAL_BUILD) +void minsqpinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + /* Real */ const ae_matrix* cleic, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t nec, + ae_int_t nic, + ae_int_t nlec, + ae_int_t nlic, + const nlpstoppingcriteria* criteria, + ae_bool usedensebfgs, + minsqpstate* state, + ae_state *_state); +ae_bool minsqpiteration(minsqpstate* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state); +void _minsqpsubsolver_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minsqpsubsolver_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minsqpsubsolver_clear(void* _p); +void _minsqpsubsolver_destroy(void* _p); +void _minsqpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minsqpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minsqpstate_clear(void* _p); +void _minsqpstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_SSGD) || !defined(AE_PARTIAL_BUILD) +void ssgdinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + double rad0, + double rad1, + ae_int_t outerits, + double rate0, + double rate1, + double momentum, + ae_int_t maxits, + double rho, + ssgdstate* state, + ae_state *_state); +ae_bool ssgditeration(ssgdstate* state, + ae_bool userterminationneeded, + ae_state *_state); +void _ssgdstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _ssgdstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _ssgdstate_clear(void* _p); +void _ssgdstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DIFFEVO) || !defined(AE_PARTIAL_BUILD) +void gdemoinitbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t m, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t cntlc, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t cntnlc, + ae_int_t popsize, + ae_int_t epochscnt, + ae_int_t seed, + gdemostate* state, + ae_state *_state); +void gdemosetprofile(gdemostate* state, + ae_int_t profile, + ae_state *_state); +void gdemosetfixedparams(gdemostate* state, + ae_int_t strategy, + double crossoverprob, + double differentialweight, + ae_state *_state); +void gdemosetsmallf(gdemostate* state, double f, ae_state *_state); +void gdemosetcondfx(gdemostate* state, + double epsf, + double epsx, + ae_state *_state); +void gdemosetmodepenalty(gdemostate* state, + double rhol1, + double rhol2, + ae_state *_state); +void gdemosetx0(gdemostate* state, + /* Real */ const ae_vector* x0, + ae_state *_state); +ae_bool gdemoiteration(gdemostate* state, + ae_bool userterminationneeded, + ae_state *_state); +void _gdemopopulation_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gdemopopulation_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gdemopopulation_clear(void* _p); +void _gdemopopulation_destroy(void* _p); +void _gdemostate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gdemostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gdemostate_clear(void* _p); +void _gdemostate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINDF) || !defined(AE_PARTIAL_BUILD) +void mindfcreate(ae_int_t n, + /* Real */ const ae_vector* x, + mindfstate* state, + ae_state *_state); +void mindfsetbc(mindfstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void mindfsetlc2dense(mindfstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void mindfsetnlc2(mindfstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state); +void mindfsetcondfx(mindfstate* state, + double epsf, + double epsx, + ae_state *_state); +void mindfusetimers(mindfstate* state, + ae_bool usetimers, + ae_state *_state); +void mindfsetcondf(mindfstate* state, double epsf, ae_state *_state); +void mindfsetscale(mindfstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void mindfsetxrep(mindfstate* state, ae_bool needxrep, ae_state *_state); +void mindfrequesttermination(mindfstate* state, ae_state *_state); +void mindfsetseed(mindfstate* s, ae_int_t seedval, ae_state *_state); +void mindfsetalgogdemo(mindfstate* state, + ae_int_t epochscnt, + ae_int_t popsize, + ae_state *_state); +void mindfsetgdemoprofilerobust(mindfstate* state, ae_state *_state); +void mindfsetgdemoprofilequick(mindfstate* state, ae_state *_state); +void mindfsetgdemopenalty(mindfstate* state, + double rho1, + double rho2, + ae_state *_state); +void mindfsetsmallf(mindfstate* state, double f, ae_state *_state); +void mindfsetalgogdemofixed(mindfstate* state, + ae_int_t epochscnt, + ae_int_t strategy, + double crossoverprob, + double differentialweight, + ae_int_t popsize, + ae_state *_state); +ae_bool mindfiteration(mindfstate* state, ae_state *_state); +void mindfresults(const mindfstate* state, + /* Real */ ae_vector* x, + mindfreport* rep, + ae_state *_state); +void mindfresultsbuf(const mindfstate* state, + /* Real */ ae_vector* x, + mindfreport* rep, + ae_state *_state); +void mindfsetprotocolv2(mindfstate* state, ae_state *_state); +void _mindfstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mindfstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mindfstate_clear(void* _p); +void _mindfstate_destroy(void* _p); +void _mindfreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mindfreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mindfreport_clear(void* _p); +void _mindfreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_REVISEDDUALSIMPLEX) || !defined(AE_PARTIAL_BUILD) +void dsssettingsinit(dualsimplexsettings* settings, ae_state *_state); +void dssinit(ae_int_t n, dualsimplexstate* s, ae_state *_state); +void dsssetproblem(dualsimplexstate* state, + /* Real */ const ae_vector* c, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_matrix* densea, + const sparsematrix* sparsea, + ae_int_t akind, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + const dualsimplexbasis* proposedbasis, + ae_int_t basisinittype, + const dualsimplexsettings* settings, + ae_state *_state); +void dssexportbasis(const dualsimplexstate* state, + dualsimplexbasis* basis, + ae_state *_state); +void dssoptimize(dualsimplexstate* state, + const dualsimplexsettings* settings, + ae_state *_state); +void _dualsimplexsettings_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dualsimplexsettings_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dualsimplexsettings_clear(void* _p); +void _dualsimplexsettings_destroy(void* _p); +void _dssvector_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dssvector_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dssvector_clear(void* _p); +void _dssvector_destroy(void* _p); +void _dualsimplexbasis_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dualsimplexbasis_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dualsimplexbasis_clear(void* _p); +void _dualsimplexbasis_destroy(void* _p); +void _dualsimplexsubproblem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dualsimplexsubproblem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dualsimplexsubproblem_clear(void* _p); +void _dualsimplexsubproblem_destroy(void* _p); +void _dualsimplexstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _dualsimplexstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _dualsimplexstate_clear(void* _p); +void _dualsimplexstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LPSOLVERS) || !defined(AE_PARTIAL_BUILD) +void minlpcreate(ae_int_t n, minlpstate* state, ae_state *_state); +void minlpsetalgodss(minlpstate* state, double eps, ae_state *_state); +void minlpsetalgoipm(minlpstate* state, double eps, ae_state *_state); +void minlpsetcost(minlpstate* state, + /* Real */ const ae_vector* c, + ae_state *_state); +void minlpsetscale(minlpstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minlpsetbc(minlpstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minlpsetbcall(minlpstate* state, + double bndl, + double bndu, + ae_state *_state); +void minlpsetbci(minlpstate* state, + ae_int_t i, + double bndl, + double bndu, + ae_state *_state); +void minlpsetlc(minlpstate* state, + /* Real */ const ae_matrix* a, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minlpsetlc2dense(minlpstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minlpsetlc2(minlpstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minlpaddlc2dense(minlpstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void minlpaddlc2(minlpstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void minlpoptimize(minlpstate* state, ae_state *_state); +void minlpresults(const minlpstate* state, + /* Real */ ae_vector* x, + minlpreport* rep, + ae_state *_state); +void minlpresultsbuf(const minlpstate* state, + /* Real */ ae_vector* x, + minlpreport* rep, + ae_state *_state); +void _minlpstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlpstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlpstate_clear(void* _p); +void _minlpstate_destroy(void* _p); +void _minlpreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minlpreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minlpreport_clear(void* _p); +void _minlpreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NLS) || !defined(AE_PARTIAL_BUILD) +void nlscreatedfo(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + nlsstate* state, + ae_state *_state); +void nlssetalgo2ps(nlsstate* state, + ae_int_t nnoisyrestarts, + ae_state *_state); +void nlssetalgodfolsa(nlsstate* state, + ae_int_t nnoisyrestarts, + ae_state *_state); +void nlssetcond(nlsstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state); +void nlssetxrep(nlsstate* state, ae_bool needxrep, ae_state *_state); +void nlssetscale(nlsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void nlssetbc(nlsstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +ae_bool nlsiteration(nlsstate* state, ae_state *_state); +void nlsresults(const nlsstate* state, + /* Real */ ae_vector* x, + nlsreport* rep, + ae_state *_state); +void nlsresultsbuf(const nlsstate* state, + /* Real */ ae_vector* x, + nlsreport* rep, + ae_state *_state); +void nlsrestartfrom(nlsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void nlsrequesttermination(nlsstate* state, ae_state *_state); +void nlssetprotocolv2(nlsstate* state, ae_state *_state); +void _nlsstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nlsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nlsstate_clear(void* _p); +void _nlsstate_destroy(void* _p); +void _nlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nlsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nlsreport_clear(void* _p); +void _nlsreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_GIPM2) || !defined(AE_PARTIAL_BUILD) +double gipm2getinitprimdual(ae_state *_state); +void gipm2initbuf(/* Real */ const ae_vector* x0, + ae_int_t np, + double eps, + ae_int_t maxits, + gipm2state* state, + ae_state *_state); +void gipm2setprofilequasinewton(gipm2state* state, + ae_bool isprimal, + ae_state *_state); +void gipm2setprofilenewton(gipm2state* state, ae_state *_state); +void gipm2sethardbc(gipm2state* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void gipm2setsoftbc(gipm2state* state, + /* Real */ const ae_vector* bndl, + /* Boolean */ const ae_vector* issoftl, + /* Real */ const ae_vector* bndu, + /* Boolean */ const ae_vector* issoftu, + ae_state *_state); +void gipm2setflexnlc(gipm2state* state, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + ae_int_t mflex, + ae_state *_state); +ae_bool gipm2iteration(gipm2state* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state); +void gipm2results(gipm2state* state, + /* Real */ ae_vector* xs, + /* Real */ ae_vector* lagbc, + /* Real */ ae_vector* lagxc, + ae_int_t* terminationtype, + ae_state *_state); +void _gipm2vars_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipm2vars_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipm2vars_clear(void* _p); +void _gipm2vars_destroy(void* _p); +void _gipm2mult_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipm2mult_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipm2mult_clear(void* _p); +void _gipm2mult_destroy(void* _p); +void _gipm2rhs_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipm2rhs_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipm2rhs_clear(void* _p); +void _gipm2rhs_destroy(void* _p); +void _gipm2condensedsystem_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipm2condensedsystem_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipm2condensedsystem_clear(void* _p); +void _gipm2condensedsystem_destroy(void* _p); +void _gipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _gipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _gipm2state_clear(void* _p); +void _gipm2state_destroy(void* _p); +#endif +#if defined(AE_COMPILE_NLCGIPM2) || !defined(AE_PARTIAL_BUILD) +void nlpgipm2initbuf(/* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + /* Real */ const ae_vector* s, + /* Real */ const ae_vector* x0, + ae_int_t n, + const nlpstoppingcriteria* criteria, + ae_bool isdense, + nlpgipm2state* state, + ae_state *_state); +void nlpgipm2setlinearconstraints(nlpgipm2state* state, + const sparsematrix* sparsea, + /* Real */ const ae_vector* cl, + /* Real */ const ae_vector* cu, + /* Integer */ const ae_vector* lcsrcidx, + ae_int_t m, + ae_state *_state); +void nlpgipm2setnonlinearconstraints(nlpgipm2state* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state); +ae_bool nlpgipm2iteration(nlpgipm2state* state, + smoothnessmonitor* smonitor, + ae_bool userterminationneeded, + ae_state *_state); +void _nlpgipm2state_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nlpgipm2state_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nlpgipm2state_clear(void* _p); +void _nlpgipm2state_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINBLEIC) || !defined(AE_PARTIAL_BUILD) +void minbleiccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minbleicstate* state, + ae_state *_state); +void minbleiccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbleicstate* state, + ae_state *_state); +void minbleicsetbc(minbleicstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minbleicsetlc(minbleicstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minbleicsetcond(minbleicstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minbleicsetscale(minbleicstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minbleicsetprecdefault(minbleicstate* state, ae_state *_state); +void minbleicsetprecdiag(minbleicstate* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void minbleicsetprecscale(minbleicstate* state, ae_state *_state); +void minbleicsetxrep(minbleicstate* state, + ae_bool needxrep, + ae_state *_state); +void minbleicsetdrep(minbleicstate* state, + ae_bool needdrep, + ae_state *_state); +void minbleicsetstpmax(minbleicstate* state, + double stpmax, + ae_state *_state); +ae_bool minbleiciteration(minbleicstate* state, ae_state *_state); +void minbleicoptguardgradient(minbleicstate* state, + double teststep, + ae_state *_state); +void minbleicoptguardsmoothness(minbleicstate* state, + ae_int_t level, + ae_state *_state); +void minbleicoptguardresults(minbleicstate* state, + optguardreport* rep, + ae_state *_state); +void minbleicoptguardnonc1test0results(const minbleicstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state); +void minbleicoptguardnonc1test1results(minbleicstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state); +void minbleicresults(const minbleicstate* state, + /* Real */ ae_vector* x, + minbleicreport* rep, + ae_state *_state); +void minbleicresultsbuf(const minbleicstate* state, + /* Real */ ae_vector* x, + minbleicreport* rep, + ae_state *_state); +void minbleicrestartfrom(minbleicstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minbleicrequesttermination(minbleicstate* state, ae_state *_state); +void minbleicemergencytermination(minbleicstate* state, ae_state *_state); +void minbleicsetprotocolv1(minbleicstate* state, ae_state *_state); +void _minbleicstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minbleicstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minbleicstate_clear(void* _p); +void _minbleicstate_destroy(void* _p); +void _minbleicreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minbleicreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minbleicreport_clear(void* _p); +void _minbleicreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINNLC) || !defined(AE_PARTIAL_BUILD) +void minnlccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minnlcstate* state, + ae_state *_state); +void minnlccreatebuf(ae_int_t n, + /* Real */ const ae_vector* x, + minnlcstate* state, + ae_state *_state); +void minnlccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnlcstate* state, + ae_state *_state); +void minnlccreatefbuf(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnlcstate* state, + ae_state *_state); +void minnlcsetbc(minnlcstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minnlcsetlc(minnlcstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minnlcsetlc2dense(minnlcstate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minnlcsetlc2(minnlcstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minnlcsetlc2mixed(minnlcstate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state); +void minnlcaddlc2dense(minnlcstate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void minnlcaddlc2(minnlcstate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void minnlcaddlc2sparsefromdense(minnlcstate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state); +void minnlcsetnlc(minnlcstate* state, + ae_int_t nlec, + ae_int_t nlic, + ae_state *_state); +void minnlcsetnlc2(minnlcstate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state); +void minnlcsetnumdiff(minnlcstate* state, + ae_int_t formulatype, + ae_state *_state); +void minnlcsetcond(minnlcstate* state, + double eps, + ae_int_t maxits, + ae_state *_state); +void minnlcsetcond3(minnlcstate* state, + double epsf, + double eps, + ae_int_t maxits, + ae_state *_state); +void minnlcsetscale(minnlcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minnlcsetstpmax(minnlcstate* state, double stpmax, ae_state *_state); +void minnlcsetalgoaul2(minnlcstate* state, + ae_int_t maxouterits, + ae_state *_state); +void minnlcsetalgosl1qp(minnlcstate* state, ae_state *_state); +void minnlcsetalgosl1qpbfgs(minnlcstate* state, ae_state *_state); +void minnlcsetalgosqp(minnlcstate* state, ae_state *_state); +void minnlcsetalgoorbit(minnlcstate* state, + double rad0, + ae_int_t maxnfev, + ae_state *_state); +void minnlcsetalgosqpbfgs(minnlcstate* state, ae_state *_state); +void minnlcsetalgogipm2(minnlcstate* state, ae_state *_state); +void minnlcsetxrep(minnlcstate* state, ae_bool needxrep, ae_state *_state); +ae_bool minnlciteration(minnlcstate* state, ae_state *_state); +void minnlcoptguardgradient(minnlcstate* state, + double teststep, + ae_state *_state); +void minnlcoptguardsmoothness(minnlcstate* state, + ae_int_t level, + ae_state *_state); +void minnlcoptguardresults(minnlcstate* state, + optguardreport* rep, + ae_state *_state); +void minnlcoptguardnonc1test0results(const minnlcstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state); +void minnlcoptguardnonc1test1results(minnlcstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state); +void minnlcresults(const minnlcstate* state, + /* Real */ ae_vector* x, + minnlcreport* rep, + ae_state *_state); +void minnlcresultsbuf(const minnlcstate* state, + /* Real */ ae_vector* x, + minnlcreport* rep, + ae_state *_state); +void minnlcrequesttermination(minnlcstate* state, ae_state *_state); +void minnlcrestartfrom(minnlcstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minnlcsetfsqpadditsforctol(minnlcstate* state, + ae_int_t addits, + double ctol, + ae_state *_state); +void minnlcsetprotocolv1(minnlcstate* state, ae_state *_state); +void minnlcsetprotocolv2(minnlcstate* state, ae_state *_state); +void minnlcsetprotocolv2s(minnlcstate* state, ae_state *_state); +void _minnlcstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minnlcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minnlcstate_clear(void* _p); +void _minnlcstate_destroy(void* _p); +void _minnlcreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minnlcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minnlcreport_clear(void* _p); +void _minnlcreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MONBI) || !defined(AE_PARTIAL_BUILD) +void nbiscaleandinitbuf(/* Real */ const ae_vector* x0, + /* Real */ const ae_vector* s, + ae_int_t n, + ae_int_t m, + ae_int_t frontsize, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + const sparsematrix* sparsea, + /* Real */ const ae_matrix* densea, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t ksparse, + ae_int_t kdense, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + double epsx, + ae_int_t maxits, + ae_bool polishsolutions, + nbistate* state, + ae_state *_state); +ae_bool nbiiteration(nbistate* state, ae_state *_state); +void _nbistate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nbistate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nbistate_clear(void* _p); +void _nbistate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINMO) || !defined(AE_PARTIAL_BUILD) +void minmocreate(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + minmostate* state, + ae_state *_state); +void minmocreatef(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + double diffstep, + minmostate* state, + ae_state *_state); +void minmosetalgonbi(minmostate* state, + ae_int_t frontsize, + ae_bool polishsolutions, + ae_state *_state); +void minmosetbc(minmostate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minmosetlc2dense(minmostate* state, + /* Real */ const ae_matrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minmosetlc2(minmostate* state, + const sparsematrix* a, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_int_t k, + ae_state *_state); +void minmosetlc2mixed(minmostate* state, + const sparsematrix* sparsea, + ae_int_t ksparse, + /* Real */ const ae_matrix* densea, + ae_int_t kdense, + /* Real */ const ae_vector* al, + /* Real */ const ae_vector* au, + ae_state *_state); +void minmoaddlc2dense(minmostate* state, + /* Real */ const ae_vector* a, + double al, + double au, + ae_state *_state); +void minmoaddlc2(minmostate* state, + /* Integer */ const ae_vector* idxa, + /* Real */ const ae_vector* vala, + ae_int_t nnz, + double al, + double au, + ae_state *_state); +void minmoaddlc2sparsefromdense(minmostate* state, + /* Real */ const ae_vector* da, + double al, + double au, + ae_state *_state); +void minmosetnlc2(minmostate* state, + /* Real */ const ae_vector* nl, + /* Real */ const ae_vector* nu, + ae_int_t nnlc, + ae_state *_state); +void minmosetcond(minmostate* state, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minmosetscale(minmostate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minmosetxrep(minmostate* state, ae_bool needxrep, ae_state *_state); +ae_bool minmoiteration(minmostate* state, ae_state *_state); +void minmoresults(const minmostate* state, + /* Real */ ae_matrix* paretofront, + ae_int_t* frontsize, + minmoreport* rep, + ae_state *_state); +void minmorequesttermination(minmostate* state, ae_state *_state); +void minmorestartfrom(minmostate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minmosetprotocolv1(minmostate* state, ae_state *_state); +void _minmostate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minmostate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minmostate_clear(void* _p); +void _minmostate_destroy(void* _p); +void _minmoreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minmoreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minmoreport_clear(void* _p); +void _minmoreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINNS) || !defined(AE_PARTIAL_BUILD) +void minnscreate(ae_int_t n, + /* Real */ const ae_vector* x, + minnsstate* state, + ae_state *_state); +void minnscreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minnsstate* state, + ae_state *_state); +void minnssetbc(minnsstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minnssetlc(minnsstate* state, + /* Real */ const ae_matrix* c, + /* Integer */ const ae_vector* ct, + ae_int_t k, + ae_state *_state); +void minnssetnlc(minnsstate* state, + ae_int_t nlec, + ae_int_t nlic, + ae_state *_state); +void minnssetcond(minnsstate* state, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minnssetscale(minnsstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minnssetalgoags(minnsstate* state, + double radius, + double penalty, + ae_state *_state); +void minnssetxrep(minnsstate* state, ae_bool needxrep, ae_state *_state); +void minnsrequesttermination(minnsstate* state, ae_state *_state); +ae_bool minnsiteration(minnsstate* state, ae_state *_state); +void minnsresults(const minnsstate* state, + /* Real */ ae_vector* x, + minnsreport* rep, + ae_state *_state); +void minnsresultsbuf(const minnsstate* state, + /* Real */ ae_vector* x, + minnsreport* rep, + ae_state *_state); +void minnsrestartfrom(minnsstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minnssetprotocolv1(minnsstate* state, ae_state *_state); +void _minnsqp_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minnsqp_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minnsqp_clear(void* _p); +void _minnsqp_destroy(void* _p); +void _minnsstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minnsstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minnsstate_clear(void* _p); +void _minnsstate_destroy(void* _p); +void _minnsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minnsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minnsreport_clear(void* _p); +void _minnsreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINCOMP) || !defined(AE_PARTIAL_BUILD) +void minlbfgssetdefaultpreconditioner(minlbfgsstate* state, + ae_state *_state); +void minlbfgssetcholeskypreconditioner(minlbfgsstate* state, + /* Real */ const ae_matrix* p, + ae_bool isupper, + ae_state *_state); +void minbleicsetbarrierwidth(minbleicstate* state, + double mu, + ae_state *_state); +void minbleicsetbarrierdecay(minbleicstate* state, + double mudecay, + ae_state *_state); +void minasacreate(ae_int_t n, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + minasastate* state, + ae_state *_state); +void minasasetcond(minasastate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minasasetxrep(minasastate* state, ae_bool needxrep, ae_state *_state); +void minasasetalgorithm(minasastate* state, + ae_int_t algotype, + ae_state *_state); +void minasasetstpmax(minasastate* state, double stpmax, ae_state *_state); +ae_bool minasaiteration(minasastate* state, ae_state *_state); +void minasaresults(const minasastate* state, + /* Real */ ae_vector* x, + minasareport* rep, + ae_state *_state); +void minasaresultsbuf(const minasastate* state, + /* Real */ ae_vector* x, + minasareport* rep, + ae_state *_state); +void minasarestartfrom(minasastate* state, + /* Real */ const ae_vector* x, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minasasetprotocolv1(minasastate* state, ae_state *_state); +void _minasastate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minasastate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minasastate_clear(void* _p); +void _minasastate_destroy(void* _p); +void _minasareport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minasareport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minasareport_clear(void* _p); +void _minasareport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MINBC) || !defined(AE_PARTIAL_BUILD) +void minbccreate(ae_int_t n, + /* Real */ const ae_vector* x, + minbcstate* state, + ae_state *_state); +void minbccreatef(ae_int_t n, + /* Real */ const ae_vector* x, + double diffstep, + minbcstate* state, + ae_state *_state); +void minbcsetbc(minbcstate* state, + /* Real */ const ae_vector* bndl, + /* Real */ const ae_vector* bndu, + ae_state *_state); +void minbcsetcond(minbcstate* state, + double epsg, + double epsf, + double epsx, + ae_int_t maxits, + ae_state *_state); +void minbcsetscale(minbcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void minbcsetprecdefault(minbcstate* state, ae_state *_state); +void minbcsetprecdiag(minbcstate* state, + /* Real */ const ae_vector* d, + ae_state *_state); +void minbcsetprecscale(minbcstate* state, ae_state *_state); +void minbcsetxrep(minbcstate* state, ae_bool needxrep, ae_state *_state); +void minbcsetstpmax(minbcstate* state, double stpmax, ae_state *_state); +ae_bool minbciteration(minbcstate* state, ae_state *_state); +void minbcoptguardgradient(minbcstate* state, + double teststep, + ae_state *_state); +void minbcoptguardsmoothness(minbcstate* state, + ae_int_t level, + ae_state *_state); +void minbcoptguardresults(minbcstate* state, + optguardreport* rep, + ae_state *_state); +void minbcoptguardnonc1test0results(const minbcstate* state, + optguardnonc1test0report* strrep, + optguardnonc1test0report* lngrep, + ae_state *_state); +void minbcoptguardnonc1test1results(minbcstate* state, + optguardnonc1test1report* strrep, + optguardnonc1test1report* lngrep, + ae_state *_state); +void minbcresults(const minbcstate* state, + /* Real */ ae_vector* x, + minbcreport* rep, + ae_state *_state); +void minbcresultsbuf(const minbcstate* state, + /* Real */ ae_vector* x, + minbcreport* rep, + ae_state *_state); +void minbcrestartfrom(minbcstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void minbcrequesttermination(minbcstate* state, ae_state *_state); +void minbcsetprotocolv1(minbcstate* state, ae_state *_state); +void _minbcstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minbcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minbcstate_clear(void* _p); +void _minbcstate_destroy(void* _p); +void _minbcreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _minbcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _minbcreport_clear(void* _p); +void _minbcreport_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/solvers.cpp b/core/alglib/solvers.cpp index 77f9ca0e..3d7962b8 100644 --- a/core/alglib/solvers.cpp +++ b/core/alglib/solvers.cpp @@ -1,8709 +1,20609 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "solvers.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* - -*************************************************************************/ -_densesolverreport_owner::_densesolverreport_owner() -{ - p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_densesolverreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_densesolverreport_owner::_densesolverreport_owner(const _densesolverreport_owner &rhs) -{ - p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_densesolverreport_owner& _densesolverreport_owner::operator=(const _densesolverreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_densesolverreport_clear(p_struct); - if( !alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_densesolverreport_owner::~_densesolverreport_owner() -{ - alglib_impl::_densesolverreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -densesolverreport::densesolverreport() : _densesolverreport_owner() ,r1(p_struct->r1),rinf(p_struct->rinf) -{ -} - -densesolverreport::densesolverreport(const densesolverreport &rhs):_densesolverreport_owner(rhs) ,r1(p_struct->r1),rinf(p_struct->rinf) -{ -} - -densesolverreport& densesolverreport::operator=(const densesolverreport &rhs) -{ - if( this==&rhs ) - return *this; - _densesolverreport_owner::operator=(rhs); - return *this; -} - -densesolverreport::~densesolverreport() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_densesolverlsreport_owner::_densesolverlsreport_owner() -{ - p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_densesolverlsreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_densesolverlsreport_owner::_densesolverlsreport_owner(const _densesolverlsreport_owner &rhs) -{ - p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_densesolverlsreport_owner& _densesolverlsreport_owner::operator=(const _densesolverlsreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_densesolverlsreport_clear(p_struct); - if( !alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_densesolverlsreport_owner::~_densesolverlsreport_owner() -{ - alglib_impl::_densesolverlsreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -densesolverlsreport::densesolverlsreport() : _densesolverlsreport_owner() ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) -{ -} - -densesolverlsreport::densesolverlsreport(const densesolverlsreport &rhs):_densesolverlsreport_owner(rhs) ,r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) -{ -} - -densesolverlsreport& densesolverlsreport::operator=(const densesolverlsreport &rhs) -{ - if( this==&rhs ) - return *this; - _densesolverlsreport_owner::operator=(rhs); - return *this; -} - -densesolverlsreport::~densesolverlsreport() -{ -} - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where A is NxN non-denegerate -real matrix, x and b are vectors. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - return code: - * -3 A is singular, or VERY close to singular. - X is filled by zeros in such cases. - * -1 N<=0 was passed - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - X - array[0..N-1], it contains: - * solution of A*x=b if A is non-singular (well-conditioned - or ill-conditioned, but not very close to singular) - * zeros, if A is singular or VERY close to singular - (in this case Info=-3). - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -Similar to RMatrixSolve() but solves task with multiple right parts (where -b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* optional iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*X=B, where A is NxN non-denegerate -real matrix given by its LU decomposition, X and B are NxM real matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlusolve(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -Similar to RMatrixLUSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS -LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have -both A and its LU decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixmixedsolve(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -Similar to RMatrixMixedSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixmixedsolvem(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixsolvem(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), m, rfs, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixsolve(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlusolvem(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixlusolve(const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixmixedsolvem(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::cmatrixmixedsolve(const_cast(a.c_ptr()), const_cast(lua.c_ptr()), const_cast(p.c_ptr()), n, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for SPD matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spdmatrixcholeskysolve(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixsolvem(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixsolve(const_cast(a.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - HPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixcholeskysolvem(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), m, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hpdmatrixcholeskysolve(const_cast(cha.c_ptr()), n, isupper, const_cast(b.c_ptr()), &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dense solver. - -This subroutine finds solution of the linear system A*X=B with non-square, -possibly degenerate A. System is solved in the least squares sense, and -general least squares solution X = X0 + CX*y which minimizes |A*X-B| is -returned. If A is non-degenerate, solution in the usual sense is returned. - -Algorithm features: -* automatic detection (and correct handling!) of degenerate cases -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..NRows-1,0..NCols-1], system matrix - NRows - vertical size of A - NCols - horizontal size of A - B - array[0..NCols-1], right part - Threshold- a number in [0,1]. Singular values beyond Threshold are - considered zero. Set it to 0.0, if you don't understand - what it means, so the solver will choose good value on its - own. - -OUTPUT PARAMETERS - Info - return code: - * -4 SVD subroutine failed - * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed - * 1 if task is solved - Rep - solver report, see below for more info - X - array[0..N-1,0..M-1], it contains: - * solution of A*X=B (even for singular A) - * zeros, if SVD subroutine failed - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R2 reciprocal of condition number: 1/cond(A), 2-norm. -* N = NCols -* K dim(Null(A)) -* CX array[0..N-1,0..K-1], kernel of A. - Columns of CX store such vectors that A*CX[i]=0. - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rmatrixsolvels(const_cast(a.c_ptr()), nrows, ncols, const_cast(b.c_ptr()), threshold, &info, const_cast(rep.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This object stores state of the LinLSQR method. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -_linlsqrstate_owner::_linlsqrstate_owner() -{ - p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linlsqrstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linlsqrstate_owner::_linlsqrstate_owner(const _linlsqrstate_owner &rhs) -{ - p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linlsqrstate_owner& _linlsqrstate_owner::operator=(const _linlsqrstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_linlsqrstate_clear(p_struct); - if( !alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_linlsqrstate_owner::~_linlsqrstate_owner() -{ - alglib_impl::_linlsqrstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -linlsqrstate::linlsqrstate() : _linlsqrstate_owner() -{ -} - -linlsqrstate::linlsqrstate(const linlsqrstate &rhs):_linlsqrstate_owner(rhs) -{ -} - -linlsqrstate& linlsqrstate::operator=(const linlsqrstate &rhs) -{ - if( this==&rhs ) - return *this; - _linlsqrstate_owner::operator=(rhs); - return *this; -} - -linlsqrstate::~linlsqrstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_linlsqrreport_owner::_linlsqrreport_owner() -{ - p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linlsqrreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linlsqrreport_owner::_linlsqrreport_owner(const _linlsqrreport_owner &rhs) -{ - p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_linlsqrreport_owner& _linlsqrreport_owner::operator=(const _linlsqrreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_linlsqrreport_clear(p_struct); - if( !alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_linlsqrreport_owner::~_linlsqrreport_owner() -{ - alglib_impl::_linlsqrreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -linlsqrreport::linlsqrreport() : _linlsqrreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) -{ -} - -linlsqrreport::linlsqrreport(const linlsqrreport &rhs):_linlsqrreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) -{ -} - -linlsqrreport& linlsqrreport::operator=(const linlsqrreport &rhs) -{ - if( this==&rhs ) - return *this; - _linlsqrreport_owner::operator=(rhs); - return *this; -} - -linlsqrreport::~linlsqrreport() -{ -} - -/************************************************************************* -This function initializes linear LSQR Solver. This solver is used to solve -non-symmetric (and, possibly, non-square) problems. Least squares solution -is returned for non-compatible systems. - -USAGE: -1. User initializes algorithm state with LinLSQRCreate() call -2. User tunes solver parameters with LinLSQRSetCond() and other functions -3. User calls LinLSQRSolveSparse() function which takes algorithm state - and SparseMatrix object. -4. User calls LinLSQRResults() to get solution -5. Optionally, user may call LinLSQRSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinLSQRState structure. - -INPUT PARAMETERS: - M - number of rows in A - N - number of variables, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrcreate(m, n, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function changes preconditioning settings of LinLSQQSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecunit(const linlsqrstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsetprecunit(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecdiag(const linlsqrstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsetprecdiag(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets optional Tikhonov regularization coefficient. -It is zero by default. - -INPUT PARAMETERS: - LambdaI - regularization factor, LambdaI>=0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetlambdai(const linlsqrstate &state, const double lambdai) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsetlambdai(const_cast(state.c_ptr()), lambdai, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse M*N matrix in the CRS format (you MUST contvert it - to CRS format by calling SparseConvertToCRS() function - BEFORE you pass it to this function). - B - right part, array[M] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinLSQRSetPrecUnit(). However, preconditioning cost is low - and preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsolvesparse(const linlsqrstate &state, const sparsematrix &a, const real_1d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsolvesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. - EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| - MaxIts - algorithm will be stopped if number of iterations - more than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will -be setted as default values. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetcond(const linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsetcond(const_cast(state.c_ptr()), epsa, epsb, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -LSQR solver: results. - -This function must be called after LinLSQRSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * 1 ||Rk||<=EpsB*||B|| - * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - X contains best point found so far. - (sometimes returned on singular systems) - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetxrep(const linlsqrstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::linlsqrsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This object stores state of the linear CG method. - -You should use ALGLIB functions to work with this object. -Never try to access its fields directly! -*************************************************************************/ -_lincgstate_owner::_lincgstate_owner() -{ - p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lincgstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lincgstate_owner::_lincgstate_owner(const _lincgstate_owner &rhs) -{ - p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lincgstate_owner& _lincgstate_owner::operator=(const _lincgstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_lincgstate_clear(p_struct); - if( !alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_lincgstate_owner::~_lincgstate_owner() -{ - alglib_impl::_lincgstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::lincgstate* _lincgstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::lincgstate* _lincgstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -lincgstate::lincgstate() : _lincgstate_owner() -{ -} - -lincgstate::lincgstate(const lincgstate &rhs):_lincgstate_owner(rhs) -{ -} - -lincgstate& lincgstate::operator=(const lincgstate &rhs) -{ - if( this==&rhs ) - return *this; - _lincgstate_owner::operator=(rhs); - return *this; -} - -lincgstate::~lincgstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_lincgreport_owner::_lincgreport_owner() -{ - p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lincgreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lincgreport_owner::_lincgreport_owner(const _lincgreport_owner &rhs) -{ - p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_lincgreport_owner& _lincgreport_owner::operator=(const _lincgreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_lincgreport_clear(p_struct); - if( !alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_lincgreport_owner::~_lincgreport_owner() -{ - alglib_impl::_lincgreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::lincgreport* _lincgreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::lincgreport* _lincgreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -lincgreport::lincgreport() : _lincgreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) -{ -} - -lincgreport::lincgreport(const lincgreport &rhs):_lincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) -{ -} - -lincgreport& lincgreport::operator=(const lincgreport &rhs) -{ - if( this==&rhs ) - return *this; - _lincgreport_owner::operator=(rhs); - return *this; -} - -lincgreport::~lincgreport() -{ -} - -/************************************************************************* -This function initializes linear CG Solver. This solver is used to solve -symmetric positive definite problems. If you want to solve nonsymmetric -(or non-positive definite) problem you may use LinLSQR solver provided by -ALGLIB. - -USAGE: -1. User initializes algorithm state with LinCGCreate() call -2. User tunes solver parameters with LinCGSetCond() and other functions -3. Optionally, user sets starting point with LinCGSetStartingPoint() -4. User calls LinCGSolveSparse() function which takes algorithm state and - SparseMatrix object. -5. User calls LinCGResults() to get solution -6. Optionally, user may call LinCGSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinCGState structure. - -INPUT PARAMETERS: - N - problem dimension, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgcreate(const ae_int_t n, lincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgcreate(n, const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets starting point. -By default, zero starting point is used. - -INPUT PARAMETERS: - X - starting point, array[N] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetstartingpoint(const lincgstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetstartingpoint(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecunit(const lincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetprecunit(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecdiag(const lincgstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetprecdiag(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsF - algorithm will be stopped if norm of residual is less than - EpsF*||b||. - MaxIts - algorithm will be stopped if number of iterations is more - than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -If both EpsF and MaxIts are zero then small EpsF will be set to small -value. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetcond(const lincgstate &state, const double epsf, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetcond(const_cast(state.c_ptr()), epsf, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse matrix in the CRS format (you MUST contvert it to - CRS format by calling SparseConvertToCRS() function). - IsUpper - whether upper or lower triangle of A is used: - * IsUpper=True => only upper triangle is used and lower - triangle is not referenced at all - * IsUpper=False => only lower triangle is used and upper - triangle is not referenced at all - B - right part, array[N] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinCGSetPrecUnit(). However, preconditioning cost is low and - preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsolvesparse(const lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsolvesparse(const_cast(state.c_ptr()), const_cast(a.c_ptr()), isupper, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -CG-solver: results. - -This function must be called after LinCGSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -5 input matrix is either not positive definite, - too large or too small - * -4 overflow/underflow during solution - (ill conditioned problem) - * 1 ||residual||<=EpsF*||b|| - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - best point found is returned - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets restart frequency. By default, algorithm is restarted -after N subsequent iterations. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrestartfreq(const lincgstate &state, const ae_int_t srf) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetrestartfreq(const_cast(state.c_ptr()), srf, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets frequency of residual recalculations. - -Algorithm updates residual r_k using iterative formula, but recalculates -it from scratch after each 10 iterations. It is done to avoid accumulation -of numerical errors and to stop algorithm when r_k starts to grow. - -Such low update frequence (1/10) gives very little overhead, but makes -algorithm a bit more robust against numerical errors. However, you may -change it - -INPUT PARAMETERS: - Freq - desired update frequency, Freq>=0. - Zero value means that no updates will be done. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrupdatefreq(const lincgstate &state, const ae_int_t freq) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetrupdatefreq(const_cast(state.c_ptr()), freq, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetxrep(const lincgstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::lincgsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -_nleqstate_owner::_nleqstate_owner() -{ - p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_nleqstate_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_nleqstate_owner::_nleqstate_owner(const _nleqstate_owner &rhs) -{ - p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_nleqstate_owner& _nleqstate_owner::operator=(const _nleqstate_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_nleqstate_clear(p_struct); - if( !alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_nleqstate_owner::~_nleqstate_owner() -{ - alglib_impl::_nleqstate_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::nleqstate* _nleqstate_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::nleqstate* _nleqstate_owner::c_ptr() const -{ - return const_cast(p_struct); -} -nleqstate::nleqstate() : _nleqstate_owner() ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) -{ -} - -nleqstate::nleqstate(const nleqstate &rhs):_nleqstate_owner(rhs) ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) -{ -} - -nleqstate& nleqstate::operator=(const nleqstate &rhs) -{ - if( this==&rhs ) - return *this; - _nleqstate_owner::operator=(rhs); - return *this; -} - -nleqstate::~nleqstate() -{ -} - - -/************************************************************************* - -*************************************************************************/ -_nleqreport_owner::_nleqreport_owner() -{ - p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_nleqreport_init(p_struct, NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_nleqreport_owner::_nleqreport_owner(const _nleqreport_owner &rhs) -{ - p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), NULL); - if( p_struct==NULL ) - throw ap_error("ALGLIB: malloc error"); - if( !alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); -} - -_nleqreport_owner& _nleqreport_owner::operator=(const _nleqreport_owner &rhs) -{ - if( this==&rhs ) - return *this; - alglib_impl::_nleqreport_clear(p_struct); - if( !alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), NULL, ae_false) ) - throw ap_error("ALGLIB: malloc error"); - return *this; -} - -_nleqreport_owner::~_nleqreport_owner() -{ - alglib_impl::_nleqreport_clear(p_struct); - ae_free(p_struct); -} - -alglib_impl::nleqreport* _nleqreport_owner::c_ptr() -{ - return p_struct; -} - -alglib_impl::nleqreport* _nleqreport_owner::c_ptr() const -{ - return const_cast(p_struct); -} -nleqreport::nleqreport() : _nleqreport_owner() ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) -{ -} - -nleqreport::nleqreport(const nleqreport &rhs):_nleqreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) -{ -} - -nleqreport& nleqreport::operator=(const nleqreport &rhs) -{ - if( this==&rhs ) - return *this; - _nleqreport_owner::operator=(rhs); - return *this; -} - -nleqreport::~nleqreport() -{ -} - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER - -DESCRIPTION: -This algorithm solves system of nonlinear equations - F[0](x[0], ..., x[n-1]) = 0 - F[1](x[0], ..., x[n-1]) = 0 - ... - F[M-1](x[0], ..., x[n-1]) = 0 -with M/N do not necessarily coincide. Algorithm converges quadratically -under following conditions: - * the solution set XS is nonempty - * for some xs in XS there exist such neighbourhood N(xs) that: - * vector function F(x) and its Jacobian J(x) are continuously - differentiable on N - * ||F(x)|| provides local error bound on N, i.e. there exists such - c1, that ||F(x)||>c1*distance(x,XS) -Note that these conditions are much more weaker than usual non-singularity -conditions. For example, algorithm will converge for any affine function -F (whether its Jacobian singular or not). - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function vector F[] and Jacobian matrix at given point X -* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X - - -USAGE: -1. User initializes algorithm state with NLEQCreateLM() call -2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and - other functions -3. User calls NLEQSolve() function which takes algorithm state and - pointers (delegates, etc.) to callback functions which calculate merit - function value and Jacobian. -4. User calls NLEQResults() to get solution -5. Optionally, user may call NLEQRestartFrom() to solve another problem - with same parameters (N/M) but another starting point and/or another - function vector. NLEQRestartFrom() allows to reuse already initialized - structure. - - -INPUT PARAMETERS: - N - space dimension, N>1: - * if provided, only leading N elements of X are used - * if not provided, determined automatically from size of X - M - system size - X - starting point - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with NLEQSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use NLEQSetStpMax() function to bound algorithm's steps. -3. this algorithm is a slightly modified implementation of the method - described in 'Levenberg-Marquardt method for constrained nonlinear - equations with strong local convergence properties' by Christian Kanzow - Nobuo Yamashita and Masao Fukushima and further developed in 'On the - convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and - Ya-Xiang Yuan. - - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqcreatelm(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER - -DESCRIPTION: -This algorithm solves system of nonlinear equations - F[0](x[0], ..., x[n-1]) = 0 - F[1](x[0], ..., x[n-1]) = 0 - ... - F[M-1](x[0], ..., x[n-1]) = 0 -with M/N do not necessarily coincide. Algorithm converges quadratically -under following conditions: - * the solution set XS is nonempty - * for some xs in XS there exist such neighbourhood N(xs) that: - * vector function F(x) and its Jacobian J(x) are continuously - differentiable on N - * ||F(x)|| provides local error bound on N, i.e. there exists such - c1, that ||F(x)||>c1*distance(x,XS) -Note that these conditions are much more weaker than usual non-singularity -conditions. For example, algorithm will converge for any affine function -F (whether its Jacobian singular or not). - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function vector F[] and Jacobian matrix at given point X -* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X - - -USAGE: -1. User initializes algorithm state with NLEQCreateLM() call -2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and - other functions -3. User calls NLEQSolve() function which takes algorithm state and - pointers (delegates, etc.) to callback functions which calculate merit - function value and Jacobian. -4. User calls NLEQResults() to get solution -5. Optionally, user may call NLEQRestartFrom() to solve another problem - with same parameters (N/M) but another starting point and/or another - function vector. NLEQRestartFrom() allows to reuse already initialized - structure. - - -INPUT PARAMETERS: - N - space dimension, N>1: - * if provided, only leading N elements of X are used - * if not provided, determined automatically from size of X - M - system size - X - starting point - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with NLEQSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use NLEQSetStpMax() function to bound algorithm's steps. -3. this algorithm is a slightly modified implementation of the method - described in 'Levenberg-Marquardt method for constrained nonlinear - equations with strong local convergence properties' by Christian Kanzow - Nobuo Yamashita and Masao Fukushima and further developed in 'On the - convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and - Ya-Xiang Yuan. - - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqcreatelm(n, m, const_cast(x.c_ptr()), const_cast(state.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets stopping conditions for the nonlinear solver - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition ||F||<=EpsF is satisfied - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic -stopping criterion selection (small EpsF). - -NOTES: - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetcond(const nleqstate &state, const double epsf, const ae_int_t maxits) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqsetcond(const_cast(state.c_ptr()), epsf, maxits, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to NLEQSolve(). - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetxrep(const nleqstate &state, const bool needxrep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqsetxrep(const_cast(state.c_ptr()), needxrep, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when target function contains exp() or other fast -growing functions, and algorithm makes too large steps which lead to -overflow. This function allows us to reject steps that are too large (and -therefore expose us to the possible overflow) without actually calculating -function value at the x+stp*d. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetstpmax(const nleqstate &state, const double stpmax) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqsetstpmax(const_cast(state.c_ptr()), stpmax, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool nleqiteration(const nleqstate &state) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - ae_bool result = alglib_impl::nleqiteration(const_cast(state.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void nleqsolve(nleqstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr), - void *ptr) -{ - alglib_impl::ae_state _alglib_env_state; - if( func==NULL ) - throw ap_error("ALGLIB: error in 'nleqsolve()' (func is NULL)"); - if( jac==NULL ) - throw ap_error("ALGLIB: error in 'nleqsolve()' (jac is NULL)"); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - while( alglib_impl::nleqiteration(state.c_ptr(), &_alglib_env_state) ) - { - if( state.needf ) - { - func(state.x, state.f, ptr); - continue; - } - if( state.needfij ) - { - jac(state.x, state.fi, state.j, ptr); - continue; - } - if( state.xupdated ) - { - if( rep!=NULL ) - rep(state.x, state.f, ptr); - continue; - } - throw ap_error("ALGLIB: error in 'nleqsolve' (some derivatives were not provided?)"); - } - alglib_impl::ae_state_clear(&_alglib_env_state); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - - -/************************************************************************* -NLEQ solver results - -INPUT PARAMETERS: - State - algorithm state. - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -4 ERROR: algorithm has converged to the - stationary point Xf which is local minimum of - f=F[0]^2+...+F[m-1]^2, but is not solution of - nonlinear system. - * 1 sqrt(f)<=EpsF. - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - * ActiveConstraints contains number of active constraints - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqresults(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -NLEQ solver results - -Buffered implementation of NLEQResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqresultsbuf(const_cast(state.c_ptr()), const_cast(x.c_ptr()), const_cast(rep.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinCGCreate call. - X - new starting point. - BndL - new lower bounds - BndU - new upper bounds - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqrestartfrom(const nleqstate &state, const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::nleqrestartfrom(const_cast(state.c_ptr()), const_cast(x.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_bool havea, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* a, - ae_bool havea, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_bool havea, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* a, - ae_bool havea, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, - double r1, - double rinf, - ae_state *_state); -static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, - double r2, - ae_state *_state); -static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state); -static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Complex */ ae_vector* xb, - /* Complex */ ae_vector* tmp, - ae_state *_state); -static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* xb, - /* Complex */ ae_vector* tmp, - ae_state *_state); - - -static double linlsqr_atol = 1.0E-6; -static double linlsqr_btol = 1.0E-6; -static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state); - - -static double lincg_defaultprecision = 1.0E-6; -static void lincg_clearrfields(lincgstate* state, ae_state *_state); -static void lincg_updateitersdata(lincgstate* state, ae_state *_state); - - -static void nleq_clearrequestfields(nleqstate* state, ae_state *_state); -static ae_bool nleq_increaselambda(double* lambdav, - double* nu, - double lambdaup, - ae_state *_state); -static void nleq_decreaselambda(double* lambdav, - double* nu, - double lambdadown, - ae_state *_state); - - - - - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where A is NxN non-denegerate -real matrix, x and b are vectors. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - return code: - * -3 A is singular, or VERY close to singular. - X is filled by zeros in such cases. - * -1 N<=0 was passed - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - X - array[0..N-1], it contains: - * solution of A*x=b if A is non-singular (well-conditioned - or ill-conditioned, but not very close to singular) - * zeros, if A is singular or VERY close to singular - (in this case Info=-3). - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolve(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - rmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -Similar to RMatrixSolve() but solves task with multiple right parts (where -b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* optional iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvem(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_bool rfs, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix da; - ae_matrix emptya; - ae_vector p; - double scalea; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&da, n, n, _state); - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - for(i=0; i<=n-1; i++) - { - ae_v_move(&da.ptr.pp_double[i][0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); - } - rmatrixlu(&da, n, n, &p, _state); - if( rfs ) - { - densesolver_rmatrixlusolveinternal(&da, &p, scalea, n, a, ae_true, b, m, info, rep, x, _state); - } - else - { - densesolver_rmatrixlusolveinternal(&da, &p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*X=B, where A is NxN non-denegerate -real matrix given by its LU decomposition, X and B are NxM real matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolve(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - rmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -Similar to RMatrixLUSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolvem(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix emptya; - ae_int_t i; - ae_int_t j; - double scalea; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - - /* - * 1. scale matrix, max(|U[i,j]|) - * we assume that LU is in its normal form, i.e. |L[i,j]|<=1 - * 2. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_fabs(lua->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - densesolver_rmatrixlusolveinternal(lua, p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS -LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have -both A and its LU decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolve(/* Real */ ae_matrix* a, - /* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - rmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -Similar to RMatrixMixedSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolvem(/* Real */ ae_matrix* a, - /* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - double scalea; - ae_int_t i; - ae_int_t j; - - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - return; - } - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - densesolver_rmatrixlusolveinternal(lua, p, scalea, n, a, ae_true, b, m, info, rep, x, _state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolvem(/* Complex */ ae_matrix* a, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_bool rfs, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix da; - ae_matrix emptya; - ae_vector p; - double scalea; - ae_int_t i; - ae_int_t j; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&p, 0, DT_INT, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&da, n, n, _state); - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - for(i=0; i<=n-1; i++) - { - ae_v_cmove(&da.ptr.pp_complex[i][0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); - } - cmatrixlu(&da, n, n, &p, _state); - if( rfs ) - { - densesolver_cmatrixlusolveinternal(&da, &p, scalea, n, a, ae_true, b, m, info, rep, x, _state); - } - else - { - densesolver_cmatrixlusolveinternal(&da, &p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolve(/* Complex */ ae_matrix* a, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - cmatrixsolvem(a, n, &bm, 1, ae_true, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolvem(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix emptya; - ae_int_t i; - ae_int_t j; - double scalea; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - - /* - * 1. scale matrix, max(|U[i,j]|) - * we assume that LU is in its normal form, i.e. |L[i,j]|<=1 - * 2. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=i; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_c_abs(lua->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - densesolver_cmatrixlusolveinternal(lua, p, scalea, n, &emptya, ae_false, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolve(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - cmatrixlusolvem(lua, p, n, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, - /* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - double scalea; - ae_int_t i; - ae_int_t j; - - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - return; - } - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - scalea = 0; - for(i=0; i<=n-1; i++) - { - for(j=0; j<=n-1; j++) - { - scalea = ae_maxreal(scalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(scalea,0) ) - { - scalea = 1; - } - scalea = 1/scalea; - densesolver_cmatrixlusolveinternal(lua, p, scalea, n, a, ae_true, b, m, info, rep, x, _state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolve(/* Complex */ ae_matrix* a, - /* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - cmatrixmixedsolvem(a, lua, p, n, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolvem(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix da; - double sqrtscalea; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&da, n, n, _state); - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - sqrtscalea = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - sqrtscalea = ae_maxreal(sqrtscalea, ae_fabs(a->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(sqrtscalea,0) ) - { - sqrtscalea = 1; - } - sqrtscalea = 1/sqrtscalea; - sqrtscalea = ae_sqrt(sqrtscalea, _state); - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - ae_v_move(&da.ptr.pp_double[i][j1], 1, &a->ptr.pp_double[i][j1], 1, ae_v_len(j1,j2)); - } - if( !spdmatrixcholesky(&da, n, isupper, _state) ) - { - ae_matrix_set_length(x, n, m, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_double[i][j] = 0; - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - densesolver_spdmatrixcholeskysolveinternal(&da, sqrtscalea, n, isupper, a, ae_true, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for SPD matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolve(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - spdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix emptya; - double sqrtscalea; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - - /* - * 1. scale matrix, max(|U[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - sqrtscalea = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - sqrtscalea = ae_maxreal(sqrtscalea, ae_fabs(cha->ptr.pp_double[i][j], _state), _state); - } - } - if( ae_fp_eq(sqrtscalea,0) ) - { - sqrtscalea = 1; - } - sqrtscalea = 1/sqrtscalea; - densesolver_spdmatrixcholeskysolveinternal(cha, sqrtscalea, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_move(&bm.ptr.pp_double[0][0], bm.stride, &b->ptr.p_double[0], 1, ae_v_len(0,n-1)); - spdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolvem(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix da; - double sqrtscalea; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&da, n, n, _state); - - /* - * 1. scale matrix, max(|A[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - sqrtscalea = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - sqrtscalea = ae_maxreal(sqrtscalea, ae_c_abs(a->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(sqrtscalea,0) ) - { - sqrtscalea = 1; - } - sqrtscalea = 1/sqrtscalea; - sqrtscalea = ae_sqrt(sqrtscalea, _state); - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - ae_v_cmove(&da.ptr.pp_complex[i][j1], 1, &a->ptr.pp_complex[i][j1], 1, "N", ae_v_len(j1,j2)); - } - if( !hpdmatrixcholesky(&da, n, isupper, _state) ) - { - ae_matrix_set_length(x, n, m, _state); - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - densesolver_hpdmatrixcholeskysolveinternal(&da, sqrtscalea, n, isupper, a, ae_true, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolve(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - hpdmatrixsolvem(a, n, isupper, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - HPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix emptya; - double sqrtscalea; - ae_int_t i; - ae_int_t j; - ae_int_t j1; - ae_int_t j2; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); - - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - - /* - * 1. scale matrix, max(|U[i,j]|) - * 2. factorize scaled matrix - * 3. solve - */ - sqrtscalea = 0; - for(i=0; i<=n-1; i++) - { - if( isupper ) - { - j1 = i; - j2 = n-1; - } - else - { - j1 = 0; - j2 = i; - } - for(j=j1; j<=j2; j++) - { - sqrtscalea = ae_maxreal(sqrtscalea, ae_c_abs(cha->ptr.pp_complex[i][j], _state), _state); - } - } - if( ae_fp_eq(sqrtscalea,0) ) - { - sqrtscalea = 1; - } - sqrtscalea = 1/sqrtscalea; - densesolver_hpdmatrixcholeskysolveinternal(cha, sqrtscalea, n, isupper, &emptya, ae_false, b, m, info, rep, x, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix bm; - ae_matrix xm; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_vector_clear(x); - ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); - ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); - - if( n<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(&bm, n, 1, _state); - ae_v_cmove(&bm.ptr.pp_complex[0][0], bm.stride, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - hpdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, info, rep, &xm, _state); - ae_vector_set_length(x, n, _state); - ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); - ae_frame_leave(_state); -} - - -/************************************************************************* -Dense solver. - -This subroutine finds solution of the linear system A*X=B with non-square, -possibly degenerate A. System is solved in the least squares sense, and -general least squares solution X = X0 + CX*y which minimizes |A*X-B| is -returned. If A is non-degenerate, solution in the usual sense is returned. - -Algorithm features: -* automatic detection (and correct handling!) of degenerate cases -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..NRows-1,0..NCols-1], system matrix - NRows - vertical size of A - NCols - horizontal size of A - B - array[0..NCols-1], right part - Threshold- a number in [0,1]. Singular values beyond Threshold are - considered zero. Set it to 0.0, if you don't understand - what it means, so the solver will choose good value on its - own. - -OUTPUT PARAMETERS - Info - return code: - * -4 SVD subroutine failed - * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed - * 1 if task is solved - Rep - solver report, see below for more info - X - array[0..N-1,0..M-1], it contains: - * solution of A*X=B (even for singular A) - * zeros, if SVD subroutine failed - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R2 reciprocal of condition number: 1/cond(A), 2-norm. -* N = NCols -* K dim(Null(A)) -* CX array[0..N-1,0..K-1], kernel of A. - Columns of CX store such vectors that A*CX[i]=0. - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvels(/* Real */ ae_matrix* a, - ae_int_t nrows, - ae_int_t ncols, - /* Real */ ae_vector* b, - double threshold, - ae_int_t* info, - densesolverlsreport* rep, - /* Real */ ae_vector* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector sv; - ae_matrix u; - ae_matrix vt; - ae_vector rp; - ae_vector utb; - ae_vector sutb; - ae_vector tmp; - ae_vector ta; - ae_vector tx; - ae_vector buf; - ae_vector w; - ae_int_t i; - ae_int_t j; - ae_int_t nsv; - ae_int_t kernelidx; - double v; - double verr; - ae_bool svdfailed; - ae_bool zeroa; - ae_int_t rfs; - ae_int_t nrfs; - ae_bool terminatenexttime; - ae_bool smallerr; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverlsreport_clear(rep); - ae_vector_clear(x); - ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&rp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&utb, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); - ae_vector_init(&ta, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); - ae_vector_init(&w, 0, DT_REAL, _state, ae_true); - - if( (nrows<=0||ncols<=0)||ae_fp_less(threshold,0) ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - if( ae_fp_eq(threshold,0) ) - { - threshold = 1000*ae_machineepsilon; - } - - /* - * Factorize A first - */ - svdfailed = !rmatrixsvd(a, nrows, ncols, 1, 2, 2, &sv, &u, &vt, _state); - zeroa = ae_fp_eq(sv.ptr.p_double[0],0); - if( svdfailed||zeroa ) - { - if( svdfailed ) - { - *info = -4; - } - else - { - *info = 1; - } - ae_vector_set_length(x, ncols, _state); - for(i=0; i<=ncols-1; i++) - { - x->ptr.p_double[i] = 0; - } - rep->n = ncols; - rep->k = ncols; - ae_matrix_set_length(&rep->cx, ncols, ncols, _state); - for(i=0; i<=ncols-1; i++) - { - for(j=0; j<=ncols-1; j++) - { - if( i==j ) - { - rep->cx.ptr.pp_double[i][j] = 1; - } - else - { - rep->cx.ptr.pp_double[i][j] = 0; - } - } - } - rep->r2 = 0; - ae_frame_leave(_state); - return; - } - nsv = ae_minint(ncols, nrows, _state); - if( nsv==ncols ) - { - rep->r2 = sv.ptr.p_double[nsv-1]/sv.ptr.p_double[0]; - } - else - { - rep->r2 = 0; - } - rep->n = ncols; - *info = 1; - - /* - * Iterative refinement of xc combined with solution: - * 1. xc = 0 - * 2. calculate r = bc-A*xc using extra-precise dot product - * 3. solve A*y = r - * 4. update x:=x+r - * 5. goto 2 - * - * This cycle is executed until one of two things happens: - * 1. maximum number of iterations reached - * 2. last iteration decreased error to the lower limit - */ - ae_vector_set_length(&utb, nsv, _state); - ae_vector_set_length(&sutb, nsv, _state); - ae_vector_set_length(x, ncols, _state); - ae_vector_set_length(&tmp, ncols, _state); - ae_vector_set_length(&ta, ncols+1, _state); - ae_vector_set_length(&tx, ncols+1, _state); - ae_vector_set_length(&buf, ncols+1, _state); - for(i=0; i<=ncols-1; i++) - { - x->ptr.p_double[i] = 0; - } - kernelidx = nsv; - for(i=0; i<=nsv-1; i++) - { - if( ae_fp_less_eq(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) - { - kernelidx = i; - break; - } - } - rep->k = ncols-kernelidx; - nrfs = densesolver_densesolverrfsmaxv2(ncols, rep->r2, _state); - terminatenexttime = ae_false; - ae_vector_set_length(&rp, nrows, _state); - for(rfs=0; rfs<=nrfs; rfs++) - { - if( terminatenexttime ) - { - break; - } - - /* - * calculate right part - */ - if( rfs==0 ) - { - ae_v_move(&rp.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nrows-1)); - } - else - { - smallerr = ae_true; - for(i=0; i<=nrows-1; i++) - { - ae_v_move(&ta.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,ncols-1)); - ta.ptr.p_double[ncols] = -1; - ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,ncols-1)); - tx.ptr.p_double[ncols] = b->ptr.p_double[i]; - xdot(&ta, &tx, ncols+1, &buf, &v, &verr, _state); - rp.ptr.p_double[i] = -v; - smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); - } - if( smallerr ) - { - terminatenexttime = ae_true; - } - } - - /* - * solve A*dx = rp - */ - for(i=0; i<=ncols-1; i++) - { - tmp.ptr.p_double[i] = 0; - } - for(i=0; i<=nsv-1; i++) - { - utb.ptr.p_double[i] = 0; - } - for(i=0; i<=nrows-1; i++) - { - v = rp.ptr.p_double[i]; - ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nsv-1), v); - } - for(i=0; i<=nsv-1; i++) - { - if( iptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,ncols-1)); - } - - /* - * fill CX - */ - if( rep->k>0 ) - { - ae_matrix_set_length(&rep->cx, ncols, rep->k, _state); - for(i=0; i<=rep->k-1; i++) - { - ae_v_move(&rep->cx.ptr.pp_double[0][i], rep->cx.stride, &vt.ptr.pp_double[kernelidx+i][0], 1, ae_v_len(0,ncols-1)); - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal LU solver - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_rmatrixlusolveinternal(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Real */ ae_matrix* a, - ae_bool havea, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t rfs; - ae_int_t nrfs; - ae_vector xc; - ae_vector y; - ae_vector bc; - ae_vector xa; - ae_vector xb; - ae_vector tx; - double v; - double verr; - double mxb; - double scaleright; - ae_bool smallerr; - ae_bool terminatenexttime; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xb, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_greater(scalea,0), "Assertion failed", _state); - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]r1 = rmatrixlurcond1(lua, n, _state); - rep->rinf = rmatrixlurcondinf(lua, n, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_double[i][j] = 0; - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * solve - */ - for(k=0; k<=m-1; k++) - { - - /* - * copy B to contiguous storage - */ - ae_v_move(&bc.ptr.p_double[0], 1, &b->ptr.pp_double[0][k], b->stride, ae_v_len(0,n-1)); - - /* - * Scale right part: - * * MX stores max(|Bi|) - * * ScaleRight stores actual scaling applied to B when solving systems - * it is chosen to make |scaleRight*b| close to 1. - */ - mxb = 0; - for(i=0; i<=n-1; i++) - { - mxb = ae_maxreal(mxb, ae_fabs(bc.ptr.p_double[i], _state), _state); - } - if( ae_fp_eq(mxb,0) ) - { - mxb = 1; - } - scaleright = 1/mxb; - - /* - * First, non-iterative part of solution process. - * We use separate code for this task because - * XDot is quite slow and we want to save time. - */ - ae_v_moved(&xc.ptr.p_double[0], 1, &bc.ptr.p_double[0], 1, ae_v_len(0,n-1), scaleright); - densesolver_rbasiclusolve(lua, p, scalea, n, &xc, &tx, _state); - - /* - * Iterative refinement of xc: - * * calculate r = bc-A*xc using extra-precise dot product - * * solve A*y = r - * * update x:=x+r - * - * This cycle is executed until one of two things happens: - * 1. maximum number of iterations reached - * 2. last iteration decreased error to the lower limit - */ - if( havea ) - { - nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); - terminatenexttime = ae_false; - for(rfs=0; rfs<=nrfs-1; rfs++) - { - if( terminatenexttime ) - { - break; - } - - /* - * generate right part - */ - smallerr = ae_true; - ae_v_move(&xb.ptr.p_double[0], 1, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - ae_v_moved(&xa.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1), scalea); - xa.ptr.p_double[n] = -1; - xb.ptr.p_double[n] = scaleright*bc.ptr.p_double[i]; - xdot(&xa, &xb, n+1, &tx, &v, &verr, _state); - y.ptr.p_double[i] = -v; - smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),4*verr); - } - if( smallerr ) - { - terminatenexttime = ae_true; - } - - /* - * solve and update - */ - densesolver_rbasiclusolve(lua, p, scalea, n, &y, &tx, _state); - ae_v_add(&xc.ptr.p_double[0], 1, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); - } - } - - /* - * Store xc. - * Post-scale result. - */ - v = scalea*mxb; - ae_v_moved(&x->ptr.pp_double[0][k], x->stride, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal Cholesky solver - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_spdmatrixcholeskysolveinternal(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* a, - ae_bool havea, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_vector xc; - ae_vector y; - ae_vector bc; - ae_vector xa; - ae_vector xb; - ae_vector tx; - double v; - double mxb; - double scaleright; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y, 0, DT_REAL, _state, ae_true); - ae_vector_init(&bc, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); - ae_vector_init(&xb, 0, DT_REAL, _state, ae_true); - ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_greater(sqrtscalea,0), "Assertion failed", _state); - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(x, n, m, _state); - ae_vector_set_length(&y, n, _state); - ae_vector_set_length(&xc, n, _state); - ae_vector_set_length(&bc, n, _state); - ae_vector_set_length(&tx, n+1, _state); - ae_vector_set_length(&xa, n+1, _state); - ae_vector_set_length(&xb, n+1, _state); - - /* - * estimate condition number, test for near singularity - */ - rep->r1 = spdmatrixcholeskyrcond(cha, n, isupper, _state); - rep->rinf = rep->r1; - if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_double[i][j] = 0; - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * solve - */ - for(k=0; k<=m-1; k++) - { - - /* - * copy B to contiguous storage - */ - ae_v_move(&bc.ptr.p_double[0], 1, &b->ptr.pp_double[0][k], b->stride, ae_v_len(0,n-1)); - - /* - * Scale right part: - * * MX stores max(|Bi|) - * * ScaleRight stores actual scaling applied to B when solving systems - * it is chosen to make |scaleRight*b| close to 1. - */ - mxb = 0; - for(i=0; i<=n-1; i++) - { - mxb = ae_maxreal(mxb, ae_fabs(bc.ptr.p_double[i], _state), _state); - } - if( ae_fp_eq(mxb,0) ) - { - mxb = 1; - } - scaleright = 1/mxb; - - /* - * First, non-iterative part of solution process. - * We use separate code for this task because - * XDot is quite slow and we want to save time. - */ - ae_v_moved(&xc.ptr.p_double[0], 1, &bc.ptr.p_double[0], 1, ae_v_len(0,n-1), scaleright); - densesolver_spdbasiccholeskysolve(cha, sqrtscalea, n, isupper, &xc, &tx, _state); - - /* - * Store xc. - * Post-scale result. - */ - v = ae_sqr(sqrtscalea, _state)*mxb; - ae_v_moved(&x->ptr.pp_double[0][k], x->stride, &xc.ptr.p_double[0], 1, ae_v_len(0,n-1), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal LU solver - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_cmatrixlusolveinternal(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Complex */ ae_matrix* a, - ae_bool havea, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t rfs; - ae_int_t nrfs; - ae_vector xc; - ae_vector y; - ae_vector bc; - ae_vector xa; - ae_vector xb; - ae_vector tx; - ae_vector tmpbuf; - ae_complex v; - double verr; - double mxb; - double scaleright; - ae_bool smallerr; - ae_bool terminatenexttime; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&tmpbuf, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_greater(scalea,0), "Assertion failed", _state); - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - for(i=0; i<=n-1; i++) - { - if( p->ptr.p_int[i]>n-1||p->ptr.p_int[i]r1 = cmatrixlurcond1(lua, n, _state); - rep->rinf = cmatrixlurcondinf(lua, n, _state); - if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * solve - */ - for(k=0; k<=m-1; k++) - { - - /* - * copy B to contiguous storage - */ - ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); - - /* - * Scale right part: - * * MX stores max(|Bi|) - * * ScaleRight stores actual scaling applied to B when solving systems - * it is chosen to make |scaleRight*b| close to 1. - */ - mxb = 0; - for(i=0; i<=n-1; i++) - { - mxb = ae_maxreal(mxb, ae_c_abs(bc.ptr.p_complex[i], _state), _state); - } - if( ae_fp_eq(mxb,0) ) - { - mxb = 1; - } - scaleright = 1/mxb; - - /* - * First, non-iterative part of solution process. - * We use separate code for this task because - * XDot is quite slow and we want to save time. - */ - ae_v_cmoved(&xc.ptr.p_complex[0], 1, &bc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), scaleright); - densesolver_cbasiclusolve(lua, p, scalea, n, &xc, &tx, _state); - - /* - * Iterative refinement of xc: - * * calculate r = bc-A*xc using extra-precise dot product - * * solve A*y = r - * * update x:=x+r - * - * This cycle is executed until one of two things happens: - * 1. maximum number of iterations reached - * 2. last iteration decreased error to the lower limit - */ - if( havea ) - { - nrfs = densesolver_densesolverrfsmax(n, rep->r1, rep->rinf, _state); - terminatenexttime = ae_false; - for(rfs=0; rfs<=nrfs-1; rfs++) - { - if( terminatenexttime ) - { - break; - } - - /* - * generate right part - */ - smallerr = ae_true; - ae_v_cmove(&xb.ptr.p_complex[0], 1, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - for(i=0; i<=n-1; i++) - { - ae_v_cmoved(&xa.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1), scalea); - xa.ptr.p_complex[n] = ae_complex_from_d(-1); - xb.ptr.p_complex[n] = ae_c_mul_d(bc.ptr.p_complex[i],scaleright); - xcdot(&xa, &xb, n+1, &tmpbuf, &v, &verr, _state); - y.ptr.p_complex[i] = ae_c_neg(v); - smallerr = smallerr&&ae_fp_less(ae_c_abs(v, _state),4*verr); - } - if( smallerr ) - { - terminatenexttime = ae_true; - } - - /* - * solve and update - */ - densesolver_cbasiclusolve(lua, p, scalea, n, &y, &tx, _state); - ae_v_cadd(&xc.ptr.p_complex[0], 1, &y.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); - } - } - - /* - * Store xc. - * Post-scale result. - */ - v = ae_complex_from_d(scalea*mxb); - ae_v_cmovec(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal Cholesky solver - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_hpdmatrixcholeskysolveinternal(/* Complex */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* a, - ae_bool havea, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_vector xc; - ae_vector y; - ae_vector bc; - ae_vector xa; - ae_vector xb; - ae_vector tx; - double v; - double mxb; - double scaleright; - - ae_frame_make(_state, &_frame_block); - *info = 0; - _densesolverreport_clear(rep); - ae_matrix_clear(x); - ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); - ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); - - ae_assert(ae_fp_greater(sqrtscalea,0), "Assertion failed", _state); - - /* - * prepare: check inputs, allocate space... - */ - if( n<=0||m<=0 ) - { - *info = -1; - ae_frame_leave(_state); - return; - } - ae_matrix_set_length(x, n, m, _state); - ae_vector_set_length(&y, n, _state); - ae_vector_set_length(&xc, n, _state); - ae_vector_set_length(&bc, n, _state); - ae_vector_set_length(&tx, n+1, _state); - ae_vector_set_length(&xa, n+1, _state); - ae_vector_set_length(&xb, n+1, _state); - - /* - * estimate condition number, test for near singularity - */ - rep->r1 = hpdmatrixcholeskyrcond(cha, n, isupper, _state); - rep->rinf = rep->r1; - if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) - { - for(i=0; i<=n-1; i++) - { - for(j=0; j<=m-1; j++) - { - x->ptr.pp_complex[i][j] = ae_complex_from_d(0); - } - } - rep->r1 = 0; - rep->rinf = 0; - *info = -3; - ae_frame_leave(_state); - return; - } - *info = 1; - - /* - * solve - */ - for(k=0; k<=m-1; k++) - { - - /* - * copy B to contiguous storage - */ - ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); - - /* - * Scale right part: - * * MX stores max(|Bi|) - * * ScaleRight stores actual scaling applied to B when solving systems - * it is chosen to make |scaleRight*b| close to 1. - */ - mxb = 0; - for(i=0; i<=n-1; i++) - { - mxb = ae_maxreal(mxb, ae_c_abs(bc.ptr.p_complex[i], _state), _state); - } - if( ae_fp_eq(mxb,0) ) - { - mxb = 1; - } - scaleright = 1/mxb; - - /* - * First, non-iterative part of solution process. - * We use separate code for this task because - * XDot is quite slow and we want to save time. - */ - ae_v_cmoved(&xc.ptr.p_complex[0], 1, &bc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), scaleright); - densesolver_hpdbasiccholeskysolve(cha, sqrtscalea, n, isupper, &xc, &tx, _state); - - /* - * Store xc. - * Post-scale result. - */ - v = ae_sqr(sqrtscalea, _state)*mxb; - ae_v_cmoved(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1), v); - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Internal subroutine. -Returns maximum count of RFS iterations as function of: -1. machine epsilon -2. task size. -3. condition number - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static ae_int_t densesolver_densesolverrfsmax(ae_int_t n, - double r1, - double rinf, - ae_state *_state) -{ - ae_int_t result; - - - result = 5; - return result; -} - - -/************************************************************************* -Internal subroutine. -Returns maximum count of RFS iterations as function of: -1. machine epsilon -2. task size. -3. norm-2 condition number - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static ae_int_t densesolver_densesolverrfsmaxv2(ae_int_t n, - double r2, - ae_state *_state) -{ - ae_int_t result; - - - result = densesolver_densesolverrfsmax(n, 0, 0, _state); - return result; -} - - -/************************************************************************* -Basic LU solver for ScaleA*PLU*x = y. - -This subroutine assumes that: -* L is well-scaled, and it is U which needs scaling by ScaleA. -* A=PLU is well-conditioned, so no zero divisions or overflow may occur - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_rbasiclusolve(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - double v; - - - for(i=0; i<=n-1; i++) - { - if( p->ptr.p_int[i]!=i ) - { - v = xb->ptr.p_double[i]; - xb->ptr.p_double[i] = xb->ptr.p_double[p->ptr.p_int[i]]; - xb->ptr.p_double[p->ptr.p_int[i]] = v; - } - } - for(i=1; i<=n-1; i++) - { - v = ae_v_dotproduct(&lua->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); - xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; - } - xb->ptr.p_double[n-1] = xb->ptr.p_double[n-1]/(scalea*lua->ptr.pp_double[n-1][n-1]); - for(i=n-2; i>=0; i--) - { - ae_v_moved(&tmp->ptr.p_double[i+1], 1, &lua->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), scalea); - v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); - xb->ptr.p_double[i] = (xb->ptr.p_double[i]-v)/(scalea*lua->ptr.pp_double[i][i]); - } -} - - -/************************************************************************* -Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. - -This subroutine assumes that: -* A*ScaleA is well scaled -* A is well-conditioned, so no zero divisions or overflow may occur - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_spdbasiccholeskysolve(/* Real */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* xb, - /* Real */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - double v; - - - - /* - * A = L*L' or A=U'*U - */ - if( isupper ) - { - - /* - * Solve U'*y=b first. - */ - for(i=0; i<=n-1; i++) - { - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - if( iptr.p_double[i]; - ae_v_moved(&tmp->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); - ae_v_subd(&xb->ptr.p_double[i+1], 1, &tmp->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1), v); - } - } - - /* - * Solve U*x=y then. - */ - for(i=n-1; i>=0; i--) - { - if( iptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), sqrtscalea); - v = ae_v_dotproduct(&tmp->ptr.p_double[i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); - xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; - } - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - } - } - else - { - - /* - * Solve L*y=b first - */ - for(i=0; i<=n-1; i++) - { - if( i>0 ) - { - ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); - v = ae_v_dotproduct(&tmp->ptr.p_double[0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); - xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; - } - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - } - - /* - * Solve L'*x=y then. - */ - for(i=n-1; i>=0; i--) - { - xb->ptr.p_double[i] = xb->ptr.p_double[i]/(sqrtscalea*cha->ptr.pp_double[i][i]); - if( i>0 ) - { - v = xb->ptr.p_double[i]; - ae_v_moved(&tmp->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), sqrtscalea); - ae_v_subd(&xb->ptr.p_double[0], 1, &tmp->ptr.p_double[0], 1, ae_v_len(0,i-1), v); - } - } - } -} - - -/************************************************************************* -Basic LU solver for ScaleA*PLU*x = y. - -This subroutine assumes that: -* L is well-scaled, and it is U which needs scaling by ScaleA. -* A=PLU is well-conditioned, so no zero divisions or overflow may occur - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_cbasiclusolve(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - double scalea, - ae_int_t n, - /* Complex */ ae_vector* xb, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_complex v; - - - for(i=0; i<=n-1; i++) - { - if( p->ptr.p_int[i]!=i ) - { - v = xb->ptr.p_complex[i]; - xb->ptr.p_complex[i] = xb->ptr.p_complex[p->ptr.p_int[i]]; - xb->ptr.p_complex[p->ptr.p_int[i]] = v; - } - } - for(i=1; i<=n-1; i++) - { - v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); - xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); - } - xb->ptr.p_complex[n-1] = ae_c_div(xb->ptr.p_complex[n-1],ae_c_mul_d(lua->ptr.pp_complex[n-1][n-1],scalea)); - for(i=n-2; i>=0; i--) - { - ae_v_cmoved(&tmp->ptr.p_complex[i+1], 1, &lua->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), scalea); - v = ae_v_cdotproduct(&tmp->ptr.p_complex[i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); - xb->ptr.p_complex[i] = ae_c_div(ae_c_sub(xb->ptr.p_complex[i],v),ae_c_mul_d(lua->ptr.pp_complex[i][i],scalea)); - } -} - - -/************************************************************************* -Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. - -This subroutine assumes that: -* A*ScaleA is well scaled -* A is well-conditioned, so no zero divisions or overflow may occur - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -static void densesolver_hpdbasiccholeskysolve(/* Complex */ ae_matrix* cha, - double sqrtscalea, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* xb, - /* Complex */ ae_vector* tmp, - ae_state *_state) -{ - ae_int_t i; - ae_complex v; - - - - /* - * A = L*L' or A=U'*U - */ - if( isupper ) - { - - /* - * Solve U'*y=b first. - */ - for(i=0; i<=n-1; i++) - { - xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(ae_c_conj(cha->ptr.pp_complex[i][i], _state),sqrtscalea)); - if( iptr.p_complex[i]; - ae_v_cmoved(&tmp->ptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), sqrtscalea); - ae_v_csubc(&xb->ptr.p_complex[i+1], 1, &tmp->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1), v); - } - } - - /* - * Solve U*x=y then. - */ - for(i=n-1; i>=0; i--) - { - if( iptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "N", ae_v_len(i+1,n-1), sqrtscalea); - v = ae_v_cdotproduct(&tmp->ptr.p_complex[i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); - xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); - } - xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(cha->ptr.pp_complex[i][i],sqrtscalea)); - } - } - else - { - - /* - * Solve L*y=b first - */ - for(i=0; i<=n-1; i++) - { - if( i>0 ) - { - ae_v_cmoved(&tmp->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,i-1), sqrtscalea); - v = ae_v_cdotproduct(&tmp->ptr.p_complex[0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); - xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); - } - xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(cha->ptr.pp_complex[i][i],sqrtscalea)); - } - - /* - * Solve L'*x=y then. - */ - for(i=n-1; i>=0; i--) - { - xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_mul_d(ae_c_conj(cha->ptr.pp_complex[i][i], _state),sqrtscalea)); - if( i>0 ) - { - v = xb->ptr.p_complex[i]; - ae_v_cmoved(&tmp->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), sqrtscalea); - ae_v_csubc(&xb->ptr.p_complex[0], 1, &tmp->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1), v); - } - } - } -} - - -ae_bool _densesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - densesolverreport *p = (densesolverreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _densesolverreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - densesolverreport *dst = (densesolverreport*)_dst; - densesolverreport *src = (densesolverreport*)_src; - dst->r1 = src->r1; - dst->rinf = src->rinf; - return ae_true; -} - - -void _densesolverreport_clear(void* _p) -{ - densesolverreport *p = (densesolverreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _densesolverreport_destroy(void* _p) -{ - densesolverreport *p = (densesolverreport*)_p; - ae_touch_ptr((void*)p); -} - - -ae_bool _densesolverlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - densesolverlsreport *p = (densesolverlsreport*)_p; - ae_touch_ptr((void*)p); - if( !ae_matrix_init(&p->cx, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _densesolverlsreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - densesolverlsreport *dst = (densesolverlsreport*)_dst; - densesolverlsreport *src = (densesolverlsreport*)_src; - dst->r2 = src->r2; - if( !ae_matrix_init_copy(&dst->cx, &src->cx, _state, make_automatic) ) - return ae_false; - dst->n = src->n; - dst->k = src->k; - return ae_true; -} - - -void _densesolverlsreport_clear(void* _p) -{ - densesolverlsreport *p = (densesolverlsreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_clear(&p->cx); -} - - -void _densesolverlsreport_destroy(void* _p) -{ - densesolverlsreport *p = (densesolverlsreport*)_p; - ae_touch_ptr((void*)p); - ae_matrix_destroy(&p->cx); -} - - - - -/************************************************************************* -This function initializes linear LSQR Solver. This solver is used to solve -non-symmetric (and, possibly, non-square) problems. Least squares solution -is returned for non-compatible systems. - -USAGE: -1. User initializes algorithm state with LinLSQRCreate() call -2. User tunes solver parameters with LinLSQRSetCond() and other functions -3. User calls LinLSQRSolveSparse() function which takes algorithm state - and SparseMatrix object. -4. User calls LinLSQRResults() to get solution -5. Optionally, user may call LinLSQRSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinLSQRState structure. - -INPUT PARAMETERS: - M - number of rows in A - N - number of variables, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrcreate(ae_int_t m, - ae_int_t n, - linlsqrstate* state, - ae_state *_state) -{ - ae_int_t i; - - _linlsqrstate_clear(state); - - ae_assert(m>0, "LinLSQRCreate: M<=0", _state); - ae_assert(n>0, "LinLSQRCreate: N<=0", _state); - state->m = m; - state->n = n; - state->prectype = 0; - state->epsa = linlsqr_atol; - state->epsb = linlsqr_btol; - state->epsc = 1/ae_sqrt(ae_machineepsilon, _state); - state->maxits = 0; - state->lambdai = 0; - state->xrep = ae_false; - state->running = ae_false; - - /* - * * allocate arrays - * * set RX to NAN (just for the case user calls Results() without - * calling SolveSparse() - * * set B to zero - */ - normestimatorcreate(m, n, 2, 2, &state->nes, _state); - ae_vector_set_length(&state->rx, state->n, _state); - ae_vector_set_length(&state->ui, state->m+state->n, _state); - ae_vector_set_length(&state->uip1, state->m+state->n, _state); - ae_vector_set_length(&state->vip1, state->n, _state); - ae_vector_set_length(&state->vi, state->n, _state); - ae_vector_set_length(&state->omegai, state->n, _state); - ae_vector_set_length(&state->omegaip1, state->n, _state); - ae_vector_set_length(&state->d, state->n, _state); - ae_vector_set_length(&state->x, state->m+state->n, _state); - ae_vector_set_length(&state->mv, state->m+state->n, _state); - ae_vector_set_length(&state->mtv, state->n, _state); - ae_vector_set_length(&state->b, state->m, _state); - for(i=0; i<=n-1; i++) - { - state->rx.ptr.p_double[i] = _state->v_nan; - } - for(i=0; i<=m-1; i++) - { - state->b.ptr.p_double[i] = 0; - } - ae_vector_set_length(&state->rstate.ia, 1+1, _state); - ae_vector_set_length(&state->rstate.ra, 0+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -This function sets right part. By default, right part is zero. - -INPUT PARAMETERS: - B - right part, array[N]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetb(linlsqrstate* state, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(!state->running, "LinLSQRSetB: you can not change B when LinLSQRIteration is running", _state); - ae_assert(state->m<=b->cnt, "LinLSQRSetB: Length(B)m, _state), "LinLSQRSetB: B contains infinite or NaN values", _state); - state->bnorm2 = 0; - for(i=0; i<=state->m-1; i++) - { - state->b.ptr.p_double[i] = b->ptr.p_double[i]; - state->bnorm2 = state->bnorm2+b->ptr.p_double[i]*b->ptr.p_double[i]; - } -} - - -/************************************************************************* -This function changes preconditioning settings of LinLSQQSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state) -{ - - - ae_assert(!state->running, "LinLSQRSetPrecUnit: you can not change preconditioner, because function LinLSQRIteration is running!", _state); - state->prectype = -1; -} - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state) -{ - - - ae_assert(!state->running, "LinLSQRSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); - state->prectype = 0; -} - - -/************************************************************************* -This function sets optional Tikhonov regularization coefficient. -It is zero by default. - -INPUT PARAMETERS: - LambdaI - regularization factor, LambdaI>=0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetlambdai(linlsqrstate* state, - double lambdai, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinLSQRSetLambdaI: you can not set LambdaI, because function LinLSQRIteration is running", _state); - ae_assert(ae_isfinite(lambdai, _state)&&ae_fp_greater_eq(lambdai,0), "LinLSQRSetLambdaI: LambdaI is infinite or NaN", _state); - state->lambdai = lambdai; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state) -{ - ae_int_t summn; - double bnorm; - ae_int_t i; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - summn = state->rstate.ia.ptr.p_int[0]; - i = state->rstate.ia.ptr.p_int[1]; - bnorm = state->rstate.ra.ptr.p_double[0]; - } - else - { - summn = -983; - i = -989; - bnorm = -834; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - - /* - * Routine body - */ - ae_assert(state->b.cnt>0, "LinLSQRIteration: using non-allocated array B", _state); - bnorm = ae_sqrt(state->bnorm2, _state); - state->running = ae_true; - state->repnmv = 0; - linlsqr_clearrfields(state, _state); - state->repiterationscount = 0; - summn = state->m+state->n; - state->r2 = state->bnorm2; - - /* - *estimate for ANorm - */ - normestimatorrestart(&state->nes, _state); -lbl_7: - if( !normestimatoriteration(&state->nes, _state) ) - { - goto lbl_8; - } - if( !state->nes.needmv ) - { - goto lbl_9; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - linlsqr_clearrfields(state, _state); - state->needmv = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needmv = ae_false; - ae_v_move(&state->nes.mv.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); - goto lbl_7; -lbl_9: - if( !state->nes.needmtv ) - { - goto lbl_11; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); - - /* - *matrix-vector multiplication - */ - state->repnmv = state->repnmv+1; - linlsqr_clearrfields(state, _state); - state->needmtv = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->needmtv = ae_false; - ae_v_move(&state->nes.mtv.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - goto lbl_7; -lbl_11: - goto lbl_7; -lbl_8: - normestimatorresults(&state->nes, &state->anorm, _state); - - /* - *initialize .RX by zeros - */ - for(i=0; i<=state->n-1; i++) - { - state->rx.ptr.p_double[i] = 0; - } - - /* - *output first report - */ - if( !state->xrep ) - { - goto lbl_13; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - linlsqr_clearrfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->xupdated = ae_false; -lbl_13: - - /* - * LSQR, Step 0. - * - * Algorithm outline corresponds to one which was described at p.50 of - * "LSQR - an algorithm for sparse linear equations and sparse least - * squares" by C.Paige and M.Saunders with one small addition - we - * explicitly extend system matrix by additional N lines in order - * to handle non-zero lambda, i.e. original A is replaced by - * [ A ] - * A_mod = [ ] - * [ lambda*I ]. - * - * Step 0: - * x[0] = 0 - * beta[1]*u[1] = b - * alpha[1]*v[1] = A_mod'*u[1] - * w[1] = v[1] - * phiBar[1] = beta[1] - * rhoBar[1] = alpha[1] - * d[0] = 0 - * - * NOTE: - * There are three criteria for stopping: - * (S0) maximum number of iterations - * (S1) ||Rk||<=EpsB*||B||; - * (S2) ||A^T*Rk||/(||A||*||Rk||)<=EpsA. - * It is very important that S2 always checked AFTER S1. It is necessary - * to avoid division by zero when Rk=0. - */ - state->betai = bnorm; - if( ae_fp_eq(state->betai,0) ) - { - - /* - * Zero right part - */ - state->running = ae_false; - state->repterminationtype = 1; - result = ae_false; - return result; - } - for(i=0; i<=summn-1; i++) - { - if( im ) - { - state->ui.ptr.p_double[i] = state->b.ptr.p_double[i]/state->betai; - } - else - { - state->ui.ptr.p_double[i] = 0; - } - state->x.ptr.p_double[i] = state->ui.ptr.p_double[i]; - } - state->repnmv = state->repnmv+1; - linlsqr_clearrfields(state, _state); - state->needmtv = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needmtv = ae_false; - for(i=0; i<=state->n-1; i++) - { - state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->ui.ptr.p_double[state->m+i]; - } - state->alphai = 0; - for(i=0; i<=state->n-1; i++) - { - state->alphai = state->alphai+state->mtv.ptr.p_double[i]*state->mtv.ptr.p_double[i]; - } - state->alphai = ae_sqrt(state->alphai, _state); - if( ae_fp_eq(state->alphai,0) ) - { - - /* - * Orthogonality stopping criterion is met - */ - state->running = ae_false; - state->repterminationtype = 4; - result = ae_false; - return result; - } - for(i=0; i<=state->n-1; i++) - { - state->vi.ptr.p_double[i] = state->mtv.ptr.p_double[i]/state->alphai; - state->omegai.ptr.p_double[i] = state->vi.ptr.p_double[i]; - } - state->phibari = state->betai; - state->rhobari = state->alphai; - for(i=0; i<=state->n-1; i++) - { - state->d.ptr.p_double[i] = 0; - } - state->dnorm = 0; - - /* - * Steps I=1, 2, ... - */ -lbl_15: - if( ae_false ) - { - goto lbl_16; - } - - /* - * At I-th step State.RepIterationsCount=I. - */ - state->repiterationscount = state->repiterationscount+1; - - /* - * Bidiagonalization part: - * beta[i+1]*u[i+1] = A_mod*v[i]-alpha[i]*u[i] - * alpha[i+1]*v[i+1] = A_mod'*u[i+1] - beta[i+1]*v[i] - * - * NOTE: beta[i+1]=0 or alpha[i+1]=0 will lead to successful termination - * in the end of the current iteration. In this case u/v are zero. - * NOTE2: algorithm won't fail on zero alpha or beta (there will be no - * division by zero because it will be stopped BEFORE division - * occurs). However, near-zero alpha and beta won't stop algorithm - * and, although no division by zero will happen, orthogonality - * in U and V will be lost. - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->vi.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - linlsqr_clearrfields(state, _state); - state->needmv = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->needmv = ae_false; - for(i=0; i<=state->n-1; i++) - { - state->mv.ptr.p_double[state->m+i] = state->lambdai*state->vi.ptr.p_double[i]; - } - state->betaip1 = 0; - for(i=0; i<=summn-1; i++) - { - state->uip1.ptr.p_double[i] = state->mv.ptr.p_double[i]-state->alphai*state->ui.ptr.p_double[i]; - state->betaip1 = state->betaip1+state->uip1.ptr.p_double[i]*state->uip1.ptr.p_double[i]; - } - if( ae_fp_neq(state->betaip1,0) ) - { - state->betaip1 = ae_sqrt(state->betaip1, _state); - for(i=0; i<=summn-1; i++) - { - state->uip1.ptr.p_double[i] = state->uip1.ptr.p_double[i]/state->betaip1; - } - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); - state->repnmv = state->repnmv+1; - linlsqr_clearrfields(state, _state); - state->needmtv = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->needmtv = ae_false; - for(i=0; i<=state->n-1; i++) - { - state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->uip1.ptr.p_double[state->m+i]; - } - state->alphaip1 = 0; - for(i=0; i<=state->n-1; i++) - { - state->vip1.ptr.p_double[i] = state->mtv.ptr.p_double[i]-state->betaip1*state->vi.ptr.p_double[i]; - state->alphaip1 = state->alphaip1+state->vip1.ptr.p_double[i]*state->vip1.ptr.p_double[i]; - } - if( ae_fp_neq(state->alphaip1,0) ) - { - state->alphaip1 = ae_sqrt(state->alphaip1, _state); - for(i=0; i<=state->n-1; i++) - { - state->vip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]/state->alphaip1; - } - } - - /* - * Build next orthogonal transformation - */ - state->rhoi = safepythag2(state->rhobari, state->betaip1, _state); - state->ci = state->rhobari/state->rhoi; - state->si = state->betaip1/state->rhoi; - state->theta = state->si*state->alphaip1; - state->rhobarip1 = -state->ci*state->alphaip1; - state->phii = state->ci*state->phibari; - state->phibarip1 = state->si*state->phibari; - - /* - * Update .RNorm - * - * This tricky formula is necessary because simply writing - * State.R2:=State.PhiBarIP1*State.PhiBarIP1 does NOT guarantees - * monotonic decrease of R2. Roundoff error combined with 80-bit - * precision used internally by Intel chips allows R2 to increase - * slightly in some rare, but possible cases. This property is - * undesirable, so we prefer to guard against R increase. - */ - state->r2 = ae_minreal(state->r2, state->phibarip1*state->phibarip1, _state); - - /* - * Update d and DNorm, check condition-related stopping criteria - */ - for(i=0; i<=state->n-1; i++) - { - state->d.ptr.p_double[i] = 1/state->rhoi*(state->vi.ptr.p_double[i]-state->theta*state->d.ptr.p_double[i]); - state->dnorm = state->dnorm+state->d.ptr.p_double[i]*state->d.ptr.p_double[i]; - } - if( ae_fp_greater_eq(ae_sqrt(state->dnorm, _state)*state->anorm,state->epsc) ) - { - state->running = ae_false; - state->repterminationtype = 7; - result = ae_false; - return result; - } - - /* - * Update x, output report - */ - for(i=0; i<=state->n-1; i++) - { - state->rx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->phii/state->rhoi*state->omegai.ptr.p_double[i]; - } - if( !state->xrep ) - { - goto lbl_17; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - linlsqr_clearrfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->xupdated = ae_false; -lbl_17: - - /* - * Check stopping criteria - * 1. achieved required number of iterations; - * 2. ||Rk||<=EpsB*||B||; - * 3. ||A^T*Rk||/(||A||*||Rk||)<=EpsA; - */ - if( state->maxits>0&&state->repiterationscount>=state->maxits ) - { - - /* - * Achieved required number of iterations - */ - state->running = ae_false; - state->repterminationtype = 5; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->phibarip1,state->epsb*bnorm) ) - { - - /* - * ||Rk||<=EpsB*||B||, here ||Rk||=PhiBar - */ - state->running = ae_false; - state->repterminationtype = 1; - result = ae_false; - return result; - } - if( ae_fp_less_eq(state->alphaip1*ae_fabs(state->ci, _state)/state->anorm,state->epsa) ) - { - - /* - * ||A^T*Rk||/(||A||*||Rk||)<=EpsA, here ||A^T*Rk||=PhiBar*Alpha[i+1]*|.C| - */ - state->running = ae_false; - state->repterminationtype = 4; - result = ae_false; - return result; - } - - /* - * Update omega - */ - for(i=0; i<=state->n-1; i++) - { - state->omegaip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]-state->theta/state->rhoi*state->omegai.ptr.p_double[i]; - } - - /* - * Prepare for the next iteration - rename variables: - * u[i] := u[i+1] - * v[i] := v[i+1] - * rho[i] := rho[i+1] - * ... - */ - ae_v_move(&state->ui.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,summn-1)); - ae_v_move(&state->vi.ptr.p_double[0], 1, &state->vip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_v_move(&state->omegai.ptr.p_double[0], 1, &state->omegaip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->alphai = state->alphaip1; - state->betai = state->betaip1; - state->phibari = state->phibarip1; - state->rhobari = state->rhobarip1; - goto lbl_15; -lbl_16: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = summn; - state->rstate.ia.ptr.p_int[1] = i; - state->rstate.ra.ptr.p_double[0] = bnorm; - return result; -} - - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse M*N matrix in the CRS format (you MUST contvert it - to CRS format by calling SparseConvertToCRS() function - BEFORE you pass it to this function). - B - right part, array[M] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinLSQRSetPrecUnit(). However, preconditioning cost is low - and preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsolvesparse(linlsqrstate* state, - sparsematrix* a, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - ae_int_t j; - ae_int_t t0; - ae_int_t t1; - double v; - - - n = state->n; - ae_assert(!state->running, "LinLSQRSolveSparse: you can not call this function when LinLSQRIteration is running", _state); - ae_assert(b->cnt>=state->m, "LinLSQRSolveSparse: Length(B)m, _state), "LinLSQRSolveSparse: B contains infinite or NaN values", _state); - - /* - * Allocate temporaries - */ - rvectorsetlengthatleast(&state->tmpd, n, _state); - rvectorsetlengthatleast(&state->tmpx, n, _state); - - /* - * Compute diagonal scaling matrix D - */ - if( state->prectype==0 ) - { - - /* - * Default preconditioner - inverse of column norms - */ - for(i=0; i<=n-1; i++) - { - state->tmpd.ptr.p_double[i] = 0; - } - t0 = 0; - t1 = 0; - while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) - { - state->tmpd.ptr.p_double[j] = state->tmpd.ptr.p_double[j]+ae_sqr(v, _state); - } - for(i=0; i<=n-1; i++) - { - if( ae_fp_greater(state->tmpd.ptr.p_double[i],0) ) - { - state->tmpd.ptr.p_double[i] = 1/ae_sqrt(state->tmpd.ptr.p_double[i], _state); - } - else - { - state->tmpd.ptr.p_double[i] = 1; - } - } - } - else - { - - /* - * No diagonal scaling - */ - for(i=0; i<=n-1; i++) - { - state->tmpd.ptr.p_double[i] = 1; - } - } - - /* - * Solve. - * - * Instead of solving A*x=b we solve preconditioned system (A*D)*(inv(D)*x)=b. - * Transformed A is not calculated explicitly, we just modify multiplication - * by A or A'. After solution we modify State.RX so it will store untransformed - * variables - */ - linlsqrsetb(state, b, _state); - linlsqrrestart(state, _state); - while(linlsqriteration(state, _state)) - { - if( state->needmv ) - { - for(i=0; i<=n-1; i++) - { - state->tmpx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->x.ptr.p_double[i]; - } - sparsemv(a, &state->tmpx, &state->mv, _state); - } - if( state->needmtv ) - { - sparsemtv(a, &state->x, &state->mtv, _state); - for(i=0; i<=n-1; i++) - { - state->mtv.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->mtv.ptr.p_double[i]; - } - } - } - for(i=0; i<=n-1; i++) - { - state->rx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->rx.ptr.p_double[i]; - } -} - - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. - EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| - MaxIts - algorithm will be stopped if number of iterations - more than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will -be setted as default values. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetcond(linlsqrstate* state, - double epsa, - double epsb, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinLSQRSetCond: you can not call this function when LinLSQRIteration is running", _state); - ae_assert(ae_isfinite(epsa, _state)&&ae_fp_greater_eq(epsa,0), "LinLSQRSetCond: EpsA is negative, INF or NAN", _state); - ae_assert(ae_isfinite(epsb, _state)&&ae_fp_greater_eq(epsb,0), "LinLSQRSetCond: EpsB is negative, INF or NAN", _state); - ae_assert(maxits>=0, "LinLSQRSetCond: MaxIts is negative", _state); - if( (ae_fp_eq(epsa,0)&&ae_fp_eq(epsb,0))&&maxits==0 ) - { - state->epsa = linlsqr_atol; - state->epsb = linlsqr_btol; - state->maxits = state->n; - } - else - { - state->epsa = epsa; - state->epsb = epsb; - state->maxits = maxits; - } -} - - -/************************************************************************* -LSQR solver: results. - -This function must be called after LinLSQRSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * 1 ||Rk||<=EpsB*||B|| - * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - X contains best point found so far. - (sometimes returned on singular systems) - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrresults(linlsqrstate* state, - /* Real */ ae_vector* x, - linlsqrreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _linlsqrreport_clear(rep); - - ae_assert(!state->running, "LinLSQRResult: you can not call this function when LinLSQRIteration is running", _state); - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nmv = state->repnmv; - rep->terminationtype = state->repterminationtype; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetxrep(linlsqrstate* state, - ae_bool needxrep, - ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function restarts LinLSQRIteration - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrrestart(linlsqrstate* state, ae_state *_state) -{ - - - ae_vector_set_length(&state->rstate.ia, 1+1, _state); - ae_vector_set_length(&state->rstate.ra, 0+1, _state); - state->rstate.stage = -1; - linlsqr_clearrfields(state, _state); -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state) -{ - - - state->xupdated = ae_false; - state->needmv = ae_false; - state->needmtv = ae_false; - state->needmv2 = ae_false; - state->needvmv = ae_false; - state->needprec = ae_false; -} - - -ae_bool _linlsqrstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - linlsqrstate *p = (linlsqrstate*)_p; - ae_touch_ptr((void*)p); - if( !_normestimatorstate_init(&p->nes, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->ui, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->uip1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->vi, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->vip1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->omegai, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->omegaip1, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mtv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpd, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _linlsqrstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - linlsqrstate *dst = (linlsqrstate*)_dst; - linlsqrstate *src = (linlsqrstate*)_src; - if( !_normestimatorstate_init_copy(&dst->nes, &src->nes, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - dst->n = src->n; - dst->m = src->m; - dst->prectype = src->prectype; - if( !ae_vector_init_copy(&dst->ui, &src->ui, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->uip1, &src->uip1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->vi, &src->vi, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->vip1, &src->vip1, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->omegai, &src->omegai, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->omegaip1, &src->omegaip1, _state, make_automatic) ) - return ae_false; - dst->alphai = src->alphai; - dst->alphaip1 = src->alphaip1; - dst->betai = src->betai; - dst->betaip1 = src->betaip1; - dst->phibari = src->phibari; - dst->phibarip1 = src->phibarip1; - dst->phii = src->phii; - dst->rhobari = src->rhobari; - dst->rhobarip1 = src->rhobarip1; - dst->rhoi = src->rhoi; - dst->ci = src->ci; - dst->si = src->si; - dst->theta = src->theta; - dst->lambdai = src->lambdai; - if( !ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic) ) - return ae_false; - dst->anorm = src->anorm; - dst->bnorm2 = src->bnorm2; - dst->dnorm = src->dnorm; - dst->r2 = src->r2; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mtv, &src->mtv, _state, make_automatic) ) - return ae_false; - dst->epsa = src->epsa; - dst->epsb = src->epsb; - dst->epsc = src->epsc; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->xupdated = src->xupdated; - dst->needmv = src->needmv; - dst->needmtv = src->needmtv; - dst->needmv2 = src->needmv2; - dst->needvmv = src->needvmv; - dst->needprec = src->needprec; - dst->repiterationscount = src->repiterationscount; - dst->repnmv = src->repnmv; - dst->repterminationtype = src->repterminationtype; - dst->running = src->running; - if( !ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _linlsqrstate_clear(void* _p) -{ - linlsqrstate *p = (linlsqrstate*)_p; - ae_touch_ptr((void*)p); - _normestimatorstate_clear(&p->nes); - ae_vector_clear(&p->rx); - ae_vector_clear(&p->b); - ae_vector_clear(&p->ui); - ae_vector_clear(&p->uip1); - ae_vector_clear(&p->vi); - ae_vector_clear(&p->vip1); - ae_vector_clear(&p->omegai); - ae_vector_clear(&p->omegaip1); - ae_vector_clear(&p->d); - ae_vector_clear(&p->x); - ae_vector_clear(&p->mv); - ae_vector_clear(&p->mtv); - ae_vector_clear(&p->tmpd); - ae_vector_clear(&p->tmpx); - _rcommstate_clear(&p->rstate); -} - - -void _linlsqrstate_destroy(void* _p) -{ - linlsqrstate *p = (linlsqrstate*)_p; - ae_touch_ptr((void*)p); - _normestimatorstate_destroy(&p->nes); - ae_vector_destroy(&p->rx); - ae_vector_destroy(&p->b); - ae_vector_destroy(&p->ui); - ae_vector_destroy(&p->uip1); - ae_vector_destroy(&p->vi); - ae_vector_destroy(&p->vip1); - ae_vector_destroy(&p->omegai); - ae_vector_destroy(&p->omegaip1); - ae_vector_destroy(&p->d); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->mv); - ae_vector_destroy(&p->mtv); - ae_vector_destroy(&p->tmpd); - ae_vector_destroy(&p->tmpx); - _rcommstate_destroy(&p->rstate); -} - - -ae_bool _linlsqrreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - linlsqrreport *p = (linlsqrreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _linlsqrreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - linlsqrreport *dst = (linlsqrreport*)_dst; - linlsqrreport *src = (linlsqrreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nmv = src->nmv; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _linlsqrreport_clear(void* _p) -{ - linlsqrreport *p = (linlsqrreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _linlsqrreport_destroy(void* _p) -{ - linlsqrreport *p = (linlsqrreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* -This function initializes linear CG Solver. This solver is used to solve -symmetric positive definite problems. If you want to solve nonsymmetric -(or non-positive definite) problem you may use LinLSQR solver provided by -ALGLIB. - -USAGE: -1. User initializes algorithm state with LinCGCreate() call -2. User tunes solver parameters with LinCGSetCond() and other functions -3. Optionally, user sets starting point with LinCGSetStartingPoint() -4. User calls LinCGSolveSparse() function which takes algorithm state and - SparseMatrix object. -5. User calls LinCGResults() to get solution -6. Optionally, user may call LinCGSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinCGState structure. - -INPUT PARAMETERS: - N - problem dimension, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state) -{ - ae_int_t i; - - _lincgstate_clear(state); - - ae_assert(n>0, "LinCGCreate: N<=0", _state); - state->n = n; - state->prectype = 0; - state->itsbeforerestart = n; - state->itsbeforerupdate = 10; - state->epsf = lincg_defaultprecision; - state->maxits = 0; - state->xrep = ae_false; - state->running = ae_false; - - /* - * * allocate arrays - * * set RX to NAN (just for the case user calls Results() without - * calling SolveSparse() - * * set starting point to zero - * * we do NOT initialize B here because we assume that user should - * initializate it using LinCGSetB() function. In case he forgets - * to do so, exception will be thrown in the LinCGIteration(). - */ - ae_vector_set_length(&state->rx, state->n, _state); - ae_vector_set_length(&state->startx, state->n, _state); - ae_vector_set_length(&state->b, state->n, _state); - for(i=0; i<=state->n-1; i++) - { - state->rx.ptr.p_double[i] = _state->v_nan; - state->startx.ptr.p_double[i] = 0.0; - state->b.ptr.p_double[i] = 0; - } - ae_vector_set_length(&state->cx, state->n, _state); - ae_vector_set_length(&state->p, state->n, _state); - ae_vector_set_length(&state->r, state->n, _state); - ae_vector_set_length(&state->cr, state->n, _state); - ae_vector_set_length(&state->z, state->n, _state); - ae_vector_set_length(&state->cz, state->n, _state); - ae_vector_set_length(&state->x, state->n, _state); - ae_vector_set_length(&state->mv, state->n, _state); - ae_vector_set_length(&state->pv, state->n, _state); - lincg_updateitersdata(state, _state); - ae_vector_set_length(&state->rstate.ia, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; -} - - -/************************************************************************* -This function sets starting point. -By default, zero starting point is used. - -INPUT PARAMETERS: - X - starting point, array[N] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetstartingpoint(lincgstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetStartingPoint: you can not change starting point because LinCGIteration() function is running", _state); - ae_assert(state->n<=x->cnt, "LinCGSetStartingPoint: Length(X)n, _state), "LinCGSetStartingPoint: X contains infinite or NaN values!", _state); - ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); -} - - -/************************************************************************* -This function sets right part. By default, right part is zero. - -INPUT PARAMETERS: - B - right part, array[N]. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetb(lincgstate* state, - /* Real */ ae_vector* b, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetB: you can not set B, because function LinCGIteration is running!", _state); - ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); - ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); -} - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecunit(lincgstate* state, ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetPrecUnit: you can not change preconditioner, because function LinCGIteration is running!", _state); - state->prectype = -1; -} - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecdiag(lincgstate* state, ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); - state->prectype = 0; -} - - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsF - algorithm will be stopped if norm of residual is less than - EpsF*||b||. - MaxIts - algorithm will be stopped if number of iterations is more - than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -If both EpsF and MaxIts are zero then small EpsF will be set to small -value. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetcond(lincgstate* state, - double epsf, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetCond: you can not change stopping criteria when LinCGIteration() is running", _state); - ae_assert(ae_isfinite(epsf, _state)&&ae_fp_greater_eq(epsf,0), "LinCGSetCond: EpsF is negative or contains infinite or NaN values", _state); - ae_assert(maxits>=0, "LinCGSetCond: MaxIts is negative", _state); - if( ae_fp_eq(epsf,0)&&maxits==0 ) - { - state->epsf = lincg_defaultprecision; - state->maxits = maxits; - } - else - { - state->epsf = epsf; - state->maxits = maxits; - } -} - - -/************************************************************************* -Reverse communication version of linear CG. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -ae_bool lincgiteration(lincgstate* state, ae_state *_state) -{ - ae_int_t i; - double uvar; - double bnorm; - double v; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - i = state->rstate.ia.ptr.p_int[0]; - uvar = state->rstate.ra.ptr.p_double[0]; - bnorm = state->rstate.ra.ptr.p_double[1]; - v = state->rstate.ra.ptr.p_double[2]; - } - else - { - i = -983; - uvar = -989; - bnorm = -834; - v = 900; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - if( state->rstate.stage==5 ) - { - goto lbl_5; - } - if( state->rstate.stage==6 ) - { - goto lbl_6; - } - if( state->rstate.stage==7 ) - { - goto lbl_7; - } - - /* - * Routine body - */ - ae_assert(state->b.cnt>0, "LinCGIteration: B is not initialized (you must initialize B by LinCGSetB() call", _state); - state->running = ae_true; - state->repnmv = 0; - lincg_clearrfields(state, _state); - lincg_updateitersdata(state, _state); - - /* - * Start 0-th iteration - */ - ae_v_move(&state->rx.ptr.p_double[0], 1, &state->startx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - lincg_clearrfields(state, _state); - state->needvmv = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needvmv = ae_false; - bnorm = 0; - state->r2 = 0; - state->meritfunction = 0; - for(i=0; i<=state->n-1; i++) - { - state->r.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; - state->r2 = state->r2+state->r.ptr.p_double[i]*state->r.ptr.p_double[i]; - state->meritfunction = state->meritfunction+state->mv.ptr.p_double[i]*state->rx.ptr.p_double[i]-2*state->b.ptr.p_double[i]*state->rx.ptr.p_double[i]; - bnorm = bnorm+state->b.ptr.p_double[i]*state->b.ptr.p_double[i]; - } - bnorm = ae_sqrt(bnorm, _state); - - /* - * Output first report - */ - if( !state->xrep ) - { - goto lbl_8; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - lincg_clearrfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->xupdated = ae_false; -lbl_8: - - /* - * Is x0 a solution? - */ - if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) - { - state->running = ae_false; - if( ae_isfinite(state->r2, _state) ) - { - state->repterminationtype = 1; - } - else - { - state->repterminationtype = -4; - } - result = ae_false; - return result; - } - - /* - * Calculate Z and P - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->r.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - lincg_clearrfields(state, _state); - state->needprec = ae_true; - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->needprec = ae_false; - for(i=0; i<=state->n-1; i++) - { - state->z.ptr.p_double[i] = state->pv.ptr.p_double[i]; - state->p.ptr.p_double[i] = state->z.ptr.p_double[i]; - } - - /* - * Other iterations(1..N) - */ - state->repiterationscount = 0; -lbl_10: - if( ae_false ) - { - goto lbl_11; - } - state->repiterationscount = state->repiterationscount+1; - - /* - * Calculate Alpha - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->p.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - lincg_clearrfields(state, _state); - state->needvmv = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needvmv = ae_false; - if( !ae_isfinite(state->vmv, _state)||ae_fp_less_eq(state->vmv,0) ) - { - - /* - * a) Overflow when calculating VMV - * b) non-positive VMV (non-SPD matrix) - */ - state->running = ae_false; - if( ae_isfinite(state->vmv, _state) ) - { - state->repterminationtype = -5; - } - else - { - state->repterminationtype = -4; - } - result = ae_false; - return result; - } - state->alpha = 0; - for(i=0; i<=state->n-1; i++) - { - state->alpha = state->alpha+state->r.ptr.p_double[i]*state->z.ptr.p_double[i]; - } - state->alpha = state->alpha/state->vmv; - if( !ae_isfinite(state->alpha, _state) ) - { - - /* - * Overflow when calculating Alpha - */ - state->running = ae_false; - state->repterminationtype = -4; - result = ae_false; - return result; - } - - /* - * Next step toward solution - */ - for(i=0; i<=state->n-1; i++) - { - state->cx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->alpha*state->p.ptr.p_double[i]; - } - - /* - * Calculate R: - * * use recurrent relation to update R - * * at every ItsBeforeRUpdate-th iteration recalculate it from scratch, using matrix-vector product - * in case R grows instead of decreasing, algorithm is terminated with positive completion code - */ - if( !(state->itsbeforerupdate==0||state->repiterationscount%state->itsbeforerupdate!=0) ) - { - goto lbl_12; - } - - /* - * Calculate R using recurrent formula - */ - for(i=0; i<=state->n-1; i++) - { - state->cr.ptr.p_double[i] = state->r.ptr.p_double[i]-state->alpha*state->mv.ptr.p_double[i]; - state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; - } - goto lbl_13; -lbl_12: - - /* - * Calculate R using matrix-vector multiplication - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->repnmv = state->repnmv+1; - lincg_clearrfields(state, _state); - state->needmv = ae_true; - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->needmv = ae_false; - for(i=0; i<=state->n-1; i++) - { - state->cr.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; - state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; - } - - /* - * Calculating merit function - * Check emergency stopping criterion - */ - v = 0; - for(i=0; i<=state->n-1; i++) - { - v = v+state->mv.ptr.p_double[i]*state->cx.ptr.p_double[i]-2*state->b.ptr.p_double[i]*state->cx.ptr.p_double[i]; - } - if( ae_fp_less(v,state->meritfunction) ) - { - goto lbl_14; - } - for(i=0; i<=state->n-1; i++) - { - if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) - { - state->running = ae_false; - state->repterminationtype = -4; - result = ae_false; - return result; - } - } - - /* - *output last report - */ - if( !state->xrep ) - { - goto lbl_16; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - lincg_clearrfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 5; - goto lbl_rcomm; -lbl_5: - state->xupdated = ae_false; -lbl_16: - state->running = ae_false; - state->repterminationtype = 7; - result = ae_false; - return result; -lbl_14: - state->meritfunction = v; -lbl_13: - ae_v_move(&state->rx.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - - /* - * calculating RNorm - * - * NOTE: monotonic decrease of R2 is not guaranteed by algorithm. - */ - state->r2 = 0; - for(i=0; i<=state->n-1; i++) - { - state->r2 = state->r2+state->cr.ptr.p_double[i]*state->cr.ptr.p_double[i]; - } - - /* - *output report - */ - if( !state->xrep ) - { - goto lbl_18; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - lincg_clearrfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 6; - goto lbl_rcomm; -lbl_6: - state->xupdated = ae_false; -lbl_18: - - /* - *stopping criterion - *achieved the required precision - */ - if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) - { - state->running = ae_false; - if( ae_isfinite(state->r2, _state) ) - { - state->repterminationtype = 1; - } - else - { - state->repterminationtype = -4; - } - result = ae_false; - return result; - } - if( state->repiterationscount>=state->maxits&&state->maxits>0 ) - { - for(i=0; i<=state->n-1; i++) - { - if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) - { - state->running = ae_false; - state->repterminationtype = -4; - result = ae_false; - return result; - } - } - - /* - *if X is finite number - */ - state->running = ae_false; - state->repterminationtype = 5; - result = ae_false; - return result; - } - ae_v_move(&state->x.ptr.p_double[0], 1, &state->cr.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - - /* - *prepere of parameters for next iteration - */ - state->repnmv = state->repnmv+1; - lincg_clearrfields(state, _state); - state->needprec = ae_true; - state->rstate.stage = 7; - goto lbl_rcomm; -lbl_7: - state->needprec = ae_false; - ae_v_move(&state->cz.ptr.p_double[0], 1, &state->pv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - if( state->repiterationscount%state->itsbeforerestart!=0 ) - { - state->beta = 0; - uvar = 0; - for(i=0; i<=state->n-1; i++) - { - state->beta = state->beta+state->cz.ptr.p_double[i]*state->cr.ptr.p_double[i]; - uvar = uvar+state->z.ptr.p_double[i]*state->r.ptr.p_double[i]; - } - - /* - *check that UVar is't INF or is't zero - */ - if( !ae_isfinite(uvar, _state)||ae_fp_eq(uvar,0) ) - { - state->running = ae_false; - state->repterminationtype = -4; - result = ae_false; - return result; - } - - /* - *calculate .BETA - */ - state->beta = state->beta/uvar; - - /* - *check that .BETA neither INF nor NaN - */ - if( !ae_isfinite(state->beta, _state) ) - { - state->running = ae_false; - state->repterminationtype = -1; - result = ae_false; - return result; - } - for(i=0; i<=state->n-1; i++) - { - state->p.ptr.p_double[i] = state->cz.ptr.p_double[i]+state->beta*state->p.ptr.p_double[i]; - } - } - else - { - ae_v_move(&state->p.ptr.p_double[0], 1, &state->cz.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - } - - /* - *prepere data for next iteration - */ - for(i=0; i<=state->n-1; i++) - { - - /* - *write (k+1)th iteration to (k )th iteration - */ - state->r.ptr.p_double[i] = state->cr.ptr.p_double[i]; - state->z.ptr.p_double[i] = state->cz.ptr.p_double[i]; - } - goto lbl_10; -lbl_11: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = i; - state->rstate.ra.ptr.p_double[0] = uvar; - state->rstate.ra.ptr.p_double[1] = bnorm; - state->rstate.ra.ptr.p_double[2] = v; - return result; -} - - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse matrix in the CRS format (you MUST contvert it to - CRS format by calling SparseConvertToCRS() function). - IsUpper - whether upper or lower triangle of A is used: - * IsUpper=True => only upper triangle is used and lower - triangle is not referenced at all - * IsUpper=False => only lower triangle is used and upper - triangle is not referenced at all - B - right part, array[N] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinCGSetPrecUnit(). However, preconditioning cost is low and - preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsolvesparse(lincgstate* state, - sparsematrix* a, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t n; - ae_int_t i; - double v; - double vmv; - - - n = state->n; - ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); - - /* - * Allocate temporaries - */ - rvectorsetlengthatleast(&state->tmpd, n, _state); - - /* - * Compute diagonal scaling matrix D - */ - if( state->prectype==0 ) - { - - /* - * Default preconditioner - inverse of matrix diagonal - */ - for(i=0; i<=n-1; i++) - { - v = sparsegetdiagonal(a, i, _state); - if( ae_fp_greater(v,0) ) - { - state->tmpd.ptr.p_double[i] = 1/ae_sqrt(v, _state); - } - else - { - state->tmpd.ptr.p_double[i] = 1; - } - } - } - else - { - - /* - * No diagonal scaling - */ - for(i=0; i<=n-1; i++) - { - state->tmpd.ptr.p_double[i] = 1; - } - } - - /* - * Solve - */ - lincgrestart(state, _state); - lincgsetb(state, b, _state); - while(lincgiteration(state, _state)) - { - - /* - * Process different requests from optimizer - */ - if( state->needmv ) - { - sparsesmv(a, isupper, &state->x, &state->mv, _state); - } - if( state->needvmv ) - { - sparsesmv(a, isupper, &state->x, &state->mv, _state); - vmv = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - state->vmv = vmv; - } - if( state->needprec ) - { - for(i=0; i<=n-1; i++) - { - state->pv.ptr.p_double[i] = state->x.ptr.p_double[i]*ae_sqr(state->tmpd.ptr.p_double[i], _state); - } - } - } -} - - -/************************************************************************* -CG-solver: results. - -This function must be called after LinCGSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -5 input matrix is either not positive definite, - too large or too small - * -4 overflow/underflow during solution - (ill conditioned problem) - * 1 ||residual||<=EpsF*||b|| - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - best point found is returned - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgresults(lincgstate* state, - /* Real */ ae_vector* x, - lincgreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _lincgreport_clear(rep); - - ae_assert(!state->running, "LinCGResult: you can not get result, because function LinCGIteration has been launched!", _state); - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nmv = state->repnmv; - rep->terminationtype = state->repterminationtype; - rep->r2 = state->r2; -} - - -/************************************************************************* -This function sets restart frequency. By default, algorithm is restarted -after N subsequent iterations. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrestartfreq(lincgstate* state, - ae_int_t srf, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetRestartFreq: you can not change restart frequency when LinCGIteration() is running", _state); - ae_assert(srf>0, "LinCGSetRestartFreq: non-positive SRF", _state); - state->itsbeforerestart = srf; -} - - -/************************************************************************* -This function sets frequency of residual recalculations. - -Algorithm updates residual r_k using iterative formula, but recalculates -it from scratch after each 10 iterations. It is done to avoid accumulation -of numerical errors and to stop algorithm when r_k starts to grow. - -Such low update frequence (1/10) gives very little overhead, but makes -algorithm a bit more robust against numerical errors. However, you may -change it - -INPUT PARAMETERS: - Freq - desired update frequency, Freq>=0. - Zero value means that no updates will be done. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrupdatefreq(lincgstate* state, - ae_int_t freq, - ae_state *_state) -{ - - - ae_assert(!state->running, "LinCGSetRUpdateFreq: you can not change update frequency when LinCGIteration() is running", _state); - ae_assert(freq>=0, "LinCGSetRUpdateFreq: non-positive Freq", _state); - state->itsbeforerupdate = freq; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -Procedure for restart function LinCGIteration - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgrestart(lincgstate* state, ae_state *_state) -{ - - - ae_vector_set_length(&state->rstate.ia, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 2+1, _state); - state->rstate.stage = -1; - lincg_clearrfields(state, _state); -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void lincg_clearrfields(lincgstate* state, ae_state *_state) -{ - - - state->xupdated = ae_false; - state->needmv = ae_false; - state->needmtv = ae_false; - state->needmv2 = ae_false; - state->needvmv = ae_false; - state->needprec = ae_false; -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void lincg_updateitersdata(lincgstate* state, ae_state *_state) -{ - - - state->repiterationscount = 0; - state->repnmv = 0; - state->repterminationtype = 0; -} - - -ae_bool _lincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - lincgstate *p = (lincgstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cr, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cz, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->pv, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->startx, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->tmpd, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _lincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - lincgstate *dst = (lincgstate*)_dst; - lincgstate *src = (lincgstate*)_src; - if( !ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic) ) - return ae_false; - dst->n = src->n; - dst->prectype = src->prectype; - if( !ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cr, &src->cr, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cz, &src->cz, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic) ) - return ae_false; - dst->alpha = src->alpha; - dst->beta = src->beta; - dst->r2 = src->r2; - dst->meritfunction = src->meritfunction; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->pv, &src->pv, _state, make_automatic) ) - return ae_false; - dst->vmv = src->vmv; - if( !ae_vector_init_copy(&dst->startx, &src->startx, _state, make_automatic) ) - return ae_false; - dst->epsf = src->epsf; - dst->maxits = src->maxits; - dst->itsbeforerestart = src->itsbeforerestart; - dst->itsbeforerupdate = src->itsbeforerupdate; - dst->xrep = src->xrep; - dst->xupdated = src->xupdated; - dst->needmv = src->needmv; - dst->needmtv = src->needmtv; - dst->needmv2 = src->needmv2; - dst->needvmv = src->needvmv; - dst->needprec = src->needprec; - dst->repiterationscount = src->repiterationscount; - dst->repnmv = src->repnmv; - dst->repterminationtype = src->repterminationtype; - dst->running = src->running; - if( !ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _lincgstate_clear(void* _p) -{ - lincgstate *p = (lincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->rx); - ae_vector_clear(&p->b); - ae_vector_clear(&p->cx); - ae_vector_clear(&p->cr); - ae_vector_clear(&p->cz); - ae_vector_clear(&p->p); - ae_vector_clear(&p->r); - ae_vector_clear(&p->z); - ae_vector_clear(&p->x); - ae_vector_clear(&p->mv); - ae_vector_clear(&p->pv); - ae_vector_clear(&p->startx); - ae_vector_clear(&p->tmpd); - _rcommstate_clear(&p->rstate); -} - - -void _lincgstate_destroy(void* _p) -{ - lincgstate *p = (lincgstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->rx); - ae_vector_destroy(&p->b); - ae_vector_destroy(&p->cx); - ae_vector_destroy(&p->cr); - ae_vector_destroy(&p->cz); - ae_vector_destroy(&p->p); - ae_vector_destroy(&p->r); - ae_vector_destroy(&p->z); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->mv); - ae_vector_destroy(&p->pv); - ae_vector_destroy(&p->startx); - ae_vector_destroy(&p->tmpd); - _rcommstate_destroy(&p->rstate); -} - - -ae_bool _lincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - lincgreport *p = (lincgreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _lincgreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - lincgreport *dst = (lincgreport*)_dst; - lincgreport *src = (lincgreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nmv = src->nmv; - dst->terminationtype = src->terminationtype; - dst->r2 = src->r2; - return ae_true; -} - - -void _lincgreport_clear(void* _p) -{ - lincgreport *p = (lincgreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _lincgreport_destroy(void* _p) -{ - lincgreport *p = (lincgreport*)_p; - ae_touch_ptr((void*)p); -} - - - - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER - -DESCRIPTION: -This algorithm solves system of nonlinear equations - F[0](x[0], ..., x[n-1]) = 0 - F[1](x[0], ..., x[n-1]) = 0 - ... - F[M-1](x[0], ..., x[n-1]) = 0 -with M/N do not necessarily coincide. Algorithm converges quadratically -under following conditions: - * the solution set XS is nonempty - * for some xs in XS there exist such neighbourhood N(xs) that: - * vector function F(x) and its Jacobian J(x) are continuously - differentiable on N - * ||F(x)|| provides local error bound on N, i.e. there exists such - c1, that ||F(x)||>c1*distance(x,XS) -Note that these conditions are much more weaker than usual non-singularity -conditions. For example, algorithm will converge for any affine function -F (whether its Jacobian singular or not). - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function vector F[] and Jacobian matrix at given point X -* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X - - -USAGE: -1. User initializes algorithm state with NLEQCreateLM() call -2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and - other functions -3. User calls NLEQSolve() function which takes algorithm state and - pointers (delegates, etc.) to callback functions which calculate merit - function value and Jacobian. -4. User calls NLEQResults() to get solution -5. Optionally, user may call NLEQRestartFrom() to solve another problem - with same parameters (N/M) but another starting point and/or another - function vector. NLEQRestartFrom() allows to reuse already initialized - structure. - - -INPUT PARAMETERS: - N - space dimension, N>1: - * if provided, only leading N elements of X are used - * if not provided, determined automatically from size of X - M - system size - X - starting point - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with NLEQSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use NLEQSetStpMax() function to bound algorithm's steps. -3. this algorithm is a slightly modified implementation of the method - described in 'Levenberg-Marquardt method for constrained nonlinear - equations with strong local convergence properties' by Christian Kanzow - Nobuo Yamashita and Masao Fukushima and further developed in 'On the - convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and - Ya-Xiang Yuan. - - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqcreatelm(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - nleqstate* state, - ae_state *_state) -{ - - _nleqstate_clear(state); - - ae_assert(n>=1, "NLEQCreateLM: N<1!", _state); - ae_assert(m>=1, "NLEQCreateLM: M<1!", _state); - ae_assert(x->cnt>=n, "NLEQCreateLM: Length(X)n = n; - state->m = m; - nleqsetcond(state, 0, 0, _state); - nleqsetxrep(state, ae_false, _state); - nleqsetstpmax(state, 0, _state); - ae_vector_set_length(&state->x, n, _state); - ae_vector_set_length(&state->xbase, n, _state); - ae_matrix_set_length(&state->j, m, n, _state); - ae_vector_set_length(&state->fi, m, _state); - ae_vector_set_length(&state->rightpart, n, _state); - ae_vector_set_length(&state->candstep, n, _state); - nleqrestartfrom(state, x, _state); -} - - -/************************************************************************* -This function sets stopping conditions for the nonlinear solver - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition ||F||<=EpsF is satisfied - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic -stopping criterion selection (small EpsF). - -NOTES: - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetcond(nleqstate* state, - double epsf, - ae_int_t maxits, - ae_state *_state) -{ - - - ae_assert(ae_isfinite(epsf, _state), "NLEQSetCond: EpsF is not finite number!", _state); - ae_assert(ae_fp_greater_eq(epsf,0), "NLEQSetCond: negative EpsF!", _state); - ae_assert(maxits>=0, "NLEQSetCond: negative MaxIts!", _state); - if( ae_fp_eq(epsf,0)&&maxits==0 ) - { - epsf = 1.0E-6; - } - state->epsf = epsf; - state->maxits = maxits; -} - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to NLEQSolve(). - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state) -{ - - - state->xrep = needxrep; -} - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when target function contains exp() or other fast -growing functions, and algorithm makes too large steps which lead to -overflow. This function allows us to reject steps that are too large (and -therefore expose us to the possible overflow) without actually calculating -function value at the x+stp*d. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state) -{ - - - ae_assert(ae_isfinite(stpmax, _state), "NLEQSetStpMax: StpMax is not finite!", _state); - ae_assert(ae_fp_greater_eq(stpmax,0), "NLEQSetStpMax: StpMax<0!", _state); - state->stpmax = stpmax; -} - - -/************************************************************************* - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey -*************************************************************************/ -ae_bool nleqiteration(nleqstate* state, ae_state *_state) -{ - ae_int_t n; - ae_int_t m; - ae_int_t i; - double lambdaup; - double lambdadown; - double lambdav; - double rho; - double mu; - double stepnorm; - ae_bool b; - ae_bool result; - - - - /* - * Reverse communication preparations - * I know it looks ugly, but it works the same way - * anywhere from C++ to Python. - * - * This code initializes locals by: - * * random values determined during code - * generation - on first subroutine call - * * values from previous call - on subsequent calls - */ - if( state->rstate.stage>=0 ) - { - n = state->rstate.ia.ptr.p_int[0]; - m = state->rstate.ia.ptr.p_int[1]; - i = state->rstate.ia.ptr.p_int[2]; - b = state->rstate.ba.ptr.p_bool[0]; - lambdaup = state->rstate.ra.ptr.p_double[0]; - lambdadown = state->rstate.ra.ptr.p_double[1]; - lambdav = state->rstate.ra.ptr.p_double[2]; - rho = state->rstate.ra.ptr.p_double[3]; - mu = state->rstate.ra.ptr.p_double[4]; - stepnorm = state->rstate.ra.ptr.p_double[5]; - } - else - { - n = -983; - m = -989; - i = -834; - b = ae_false; - lambdaup = -287; - lambdadown = 364; - lambdav = 214; - rho = -338; - mu = -686; - stepnorm = 912; - } - if( state->rstate.stage==0 ) - { - goto lbl_0; - } - if( state->rstate.stage==1 ) - { - goto lbl_1; - } - if( state->rstate.stage==2 ) - { - goto lbl_2; - } - if( state->rstate.stage==3 ) - { - goto lbl_3; - } - if( state->rstate.stage==4 ) - { - goto lbl_4; - } - - /* - * Routine body - */ - - /* - * Prepare - */ - n = state->n; - m = state->m; - state->repterminationtype = 0; - state->repiterationscount = 0; - state->repnfunc = 0; - state->repnjac = 0; - - /* - * Calculate F/G, initialize algorithm - */ - nleq_clearrequestfields(state, _state); - state->needf = ae_true; - state->rstate.stage = 0; - goto lbl_rcomm; -lbl_0: - state->needf = ae_false; - state->repnfunc = state->repnfunc+1; - ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->fbase = state->f; - state->fprev = ae_maxrealnumber; - if( !state->xrep ) - { - goto lbl_5; - } - - /* - * progress report - */ - nleq_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->rstate.stage = 1; - goto lbl_rcomm; -lbl_1: - state->xupdated = ae_false; -lbl_5: - if( ae_fp_less_eq(state->f,ae_sqr(state->epsf, _state)) ) - { - state->repterminationtype = 1; - result = ae_false; - return result; - } - - /* - * Main cycle - */ - lambdaup = 10; - lambdadown = 0.3; - lambdav = 0.001; - rho = 1; -lbl_7: - if( ae_false ) - { - goto lbl_8; - } - - /* - * Get Jacobian; - * before we get to this point we already have State.XBase filled - * with current point and State.FBase filled with function value - * at XBase - */ - nleq_clearrequestfields(state, _state); - state->needfij = ae_true; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 2; - goto lbl_rcomm; -lbl_2: - state->needfij = ae_false; - state->repnfunc = state->repnfunc+1; - state->repnjac = state->repnjac+1; - rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->rightpart, 0, _state); - ae_v_muld(&state->rightpart.ptr.p_double[0], 1, ae_v_len(0,n-1), -1); - - /* - * Inner cycle: find good lambda - */ -lbl_9: - if( ae_false ) - { - goto lbl_10; - } - - /* - * Solve (J^T*J + (Lambda+Mu)*I)*y = J^T*F - * to get step d=-y where: - * * Mu=||F|| - is damping parameter for nonlinear system - * * Lambda - is additional Levenberg-Marquardt parameter - * for better convergence when far away from minimum - */ - for(i=0; i<=n-1; i++) - { - state->candstep.ptr.p_double[i] = 0; - } - fblssolvecgx(&state->j, m, n, lambdav, &state->rightpart, &state->candstep, &state->cgbuf, _state); - - /* - * Normalize step (it must be no more than StpMax) - */ - stepnorm = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(state->candstep.ptr.p_double[i],0) ) - { - stepnorm = 1; - break; - } - } - linminnormalized(&state->candstep, &stepnorm, n, _state); - if( ae_fp_neq(state->stpmax,0) ) - { - stepnorm = ae_minreal(stepnorm, state->stpmax, _state); - } - - /* - * Test new step - is it good enough? - * * if not, Lambda is increased and we try again. - * * if step is good, we decrease Lambda and move on. - * - * We can break this cycle on two occasions: - * * step is so small that x+step==x (in floating point arithmetics) - * * lambda is so large - */ - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - ae_v_addd(&state->x.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); - b = ae_true; - for(i=0; i<=n-1; i++) - { - if( ae_fp_neq(state->x.ptr.p_double[i],state->xbase.ptr.p_double[i]) ) - { - b = ae_false; - break; - } - } - if( b ) - { - - /* - * Step is too small, force zero step and break - */ - stepnorm = 0; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - goto lbl_10; - } - nleq_clearrequestfields(state, _state); - state->needf = ae_true; - state->rstate.stage = 3; - goto lbl_rcomm; -lbl_3: - state->needf = ae_false; - state->repnfunc = state->repnfunc+1; - if( ae_fp_less(state->f,state->fbase) ) - { - - /* - * function value decreased, move on - */ - nleq_decreaselambda(&lambdav, &rho, lambdadown, _state); - goto lbl_10; - } - if( !nleq_increaselambda(&lambdav, &rho, lambdaup, _state) ) - { - - /* - * Lambda is too large (near overflow), force zero step and break - */ - stepnorm = 0; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->f = state->fbase; - goto lbl_10; - } - goto lbl_9; -lbl_10: - - /* - * Accept step: - * * new position - * * new function value - */ - state->fbase = state->f; - ae_v_addd(&state->xbase.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); - state->repiterationscount = state->repiterationscount+1; - - /* - * Report new iteration - */ - if( !state->xrep ) - { - goto lbl_11; - } - nleq_clearrequestfields(state, _state); - state->xupdated = ae_true; - state->f = state->fbase; - ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); - state->rstate.stage = 4; - goto lbl_rcomm; -lbl_4: - state->xupdated = ae_false; -lbl_11: - - /* - * Test stopping conditions on F, step (zero/non-zero) and MaxIts; - * If one of the conditions is met, RepTerminationType is changed. - */ - if( ae_fp_less_eq(ae_sqrt(state->f, _state),state->epsf) ) - { - state->repterminationtype = 1; - } - if( ae_fp_eq(stepnorm,0)&&state->repterminationtype==0 ) - { - state->repterminationtype = -4; - } - if( state->repiterationscount>=state->maxits&&state->maxits>0 ) - { - state->repterminationtype = 5; - } - if( state->repterminationtype!=0 ) - { - goto lbl_8; - } - - /* - * Now, iteration is finally over - */ - goto lbl_7; -lbl_8: - result = ae_false; - return result; - - /* - * Saving state - */ -lbl_rcomm: - result = ae_true; - state->rstate.ia.ptr.p_int[0] = n; - state->rstate.ia.ptr.p_int[1] = m; - state->rstate.ia.ptr.p_int[2] = i; - state->rstate.ba.ptr.p_bool[0] = b; - state->rstate.ra.ptr.p_double[0] = lambdaup; - state->rstate.ra.ptr.p_double[1] = lambdadown; - state->rstate.ra.ptr.p_double[2] = lambdav; - state->rstate.ra.ptr.p_double[3] = rho; - state->rstate.ra.ptr.p_double[4] = mu; - state->rstate.ra.ptr.p_double[5] = stepnorm; - return result; -} - - -/************************************************************************* -NLEQ solver results - -INPUT PARAMETERS: - State - algorithm state. - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -4 ERROR: algorithm has converged to the - stationary point Xf which is local minimum of - f=F[0]^2+...+F[m-1]^2, but is not solution of - nonlinear system. - * 1 sqrt(f)<=EpsF. - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - * ActiveConstraints contains number of active constraints - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresults(nleqstate* state, - /* Real */ ae_vector* x, - nleqreport* rep, - ae_state *_state) -{ - - ae_vector_clear(x); - _nleqreport_clear(rep); - - nleqresultsbuf(state, x, rep, _state); -} - - -/************************************************************************* -NLEQ solver results - -Buffered implementation of NLEQResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresultsbuf(nleqstate* state, - /* Real */ ae_vector* x, - nleqreport* rep, - ae_state *_state) -{ - - - if( x->cntn ) - { - ae_vector_set_length(x, state->n, _state); - } - ae_v_move(&x->ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - rep->iterationscount = state->repiterationscount; - rep->nfunc = state->repnfunc; - rep->njac = state->repnjac; - rep->terminationtype = state->repterminationtype; -} - - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinCGCreate call. - X - new starting point. - BndL - new lower bounds - BndU - new upper bounds - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqrestartfrom(nleqstate* state, - /* Real */ ae_vector* x, - ae_state *_state) -{ - - - ae_assert(x->cnt>=state->n, "NLEQRestartFrom: Length(X)n, _state), "NLEQRestartFrom: X contains infinite or NaN values!", _state); - ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); - ae_vector_set_length(&state->rstate.ia, 2+1, _state); - ae_vector_set_length(&state->rstate.ba, 0+1, _state); - ae_vector_set_length(&state->rstate.ra, 5+1, _state); - state->rstate.stage = -1; - nleq_clearrequestfields(state, _state); -} - - -/************************************************************************* -Clears request fileds (to be sure that we don't forgot to clear something) -*************************************************************************/ -static void nleq_clearrequestfields(nleqstate* state, ae_state *_state) -{ - - - state->needf = ae_false; - state->needfij = ae_false; - state->xupdated = ae_false; -} - - -/************************************************************************* -Increases lambda, returns False when there is a danger of overflow -*************************************************************************/ -static ae_bool nleq_increaselambda(double* lambdav, - double* nu, - double lambdaup, - ae_state *_state) -{ - double lnlambda; - double lnnu; - double lnlambdaup; - double lnmax; - ae_bool result; - - - result = ae_false; - lnlambda = ae_log(*lambdav, _state); - lnlambdaup = ae_log(lambdaup, _state); - lnnu = ae_log(*nu, _state); - lnmax = 0.5*ae_log(ae_maxrealnumber, _state); - if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,lnmax) ) - { - return result; - } - if( ae_fp_greater(lnnu+ae_log(2, _state),lnmax) ) - { - return result; - } - *lambdav = *lambdav*lambdaup*(*nu); - *nu = *nu*2; - result = ae_true; - return result; -} - - -/************************************************************************* -Decreases lambda, but leaves it unchanged when there is danger of underflow. -*************************************************************************/ -static void nleq_decreaselambda(double* lambdav, - double* nu, - double lambdadown, - ae_state *_state) -{ - - - *nu = 1; - if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) - { - *lambdav = ae_minrealnumber; - } - else - { - *lambdav = *lambdav*lambdadown; - } -} - - -ae_bool _nleqstate_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - nleqstate *p = (nleqstate*)_p; - ae_touch_ptr((void*)p); - if( !ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !_rcommstate_init(&p->rstate, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->candstep, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->rightpart, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init(&p->cgbuf, 0, DT_REAL, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -ae_bool _nleqstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - nleqstate *dst = (nleqstate*)_dst; - nleqstate *src = (nleqstate*)_src; - dst->n = src->n; - dst->m = src->m; - dst->epsf = src->epsf; - dst->maxits = src->maxits; - dst->xrep = src->xrep; - dst->stpmax = src->stpmax; - if( !ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic) ) - return ae_false; - dst->f = src->f; - if( !ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic) ) - return ae_false; - if( !ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic) ) - return ae_false; - dst->needf = src->needf; - dst->needfij = src->needfij; - dst->xupdated = src->xupdated; - if( !_rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic) ) - return ae_false; - dst->repiterationscount = src->repiterationscount; - dst->repnfunc = src->repnfunc; - dst->repnjac = src->repnjac; - dst->repterminationtype = src->repterminationtype; - if( !ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic) ) - return ae_false; - dst->fbase = src->fbase; - dst->fprev = src->fprev; - if( !ae_vector_init_copy(&dst->candstep, &src->candstep, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->rightpart, &src->rightpart, _state, make_automatic) ) - return ae_false; - if( !ae_vector_init_copy(&dst->cgbuf, &src->cgbuf, _state, make_automatic) ) - return ae_false; - return ae_true; -} - - -void _nleqstate_clear(void* _p) -{ - nleqstate *p = (nleqstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_clear(&p->x); - ae_vector_clear(&p->fi); - ae_matrix_clear(&p->j); - _rcommstate_clear(&p->rstate); - ae_vector_clear(&p->xbase); - ae_vector_clear(&p->candstep); - ae_vector_clear(&p->rightpart); - ae_vector_clear(&p->cgbuf); -} - - -void _nleqstate_destroy(void* _p) -{ - nleqstate *p = (nleqstate*)_p; - ae_touch_ptr((void*)p); - ae_vector_destroy(&p->x); - ae_vector_destroy(&p->fi); - ae_matrix_destroy(&p->j); - _rcommstate_destroy(&p->rstate); - ae_vector_destroy(&p->xbase); - ae_vector_destroy(&p->candstep); - ae_vector_destroy(&p->rightpart); - ae_vector_destroy(&p->cgbuf); -} - - -ae_bool _nleqreport_init(void* _p, ae_state *_state, ae_bool make_automatic) -{ - nleqreport *p = (nleqreport*)_p; - ae_touch_ptr((void*)p); - return ae_true; -} - - -ae_bool _nleqreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic) -{ - nleqreport *dst = (nleqreport*)_dst; - nleqreport *src = (nleqreport*)_src; - dst->iterationscount = src->iterationscount; - dst->nfunc = src->nfunc; - dst->njac = src->njac; - dst->terminationtype = src->terminationtype; - return ae_true; -} - - -void _nleqreport_clear(void* _p) -{ - nleqreport *p = (nleqreport*)_p; - ae_touch_ptr((void*)p); -} - - -void _nleqreport_destroy(void* _p) -{ - nleqreport *p = (nleqreport*)_p; - ae_touch_ptr((void*)p); -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "solvers.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Polynomial root finding. + +This function returns all roots of the polynomial + P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n +Both real and complex roots are returned (see below). + +INPUT PARAMETERS: + A - array[N+1], polynomial coefficients: + * A[0] is constant term + * A[N] is a coefficient of X^N + N - polynomial degree + +OUTPUT PARAMETERS: + X - array of complex roots: + * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 + * complex roots are always returned in pairs - roots occupy + positions I and I+1, with: + * X[I+1]=Conj(X[I]) + * IMAGE(X[I]) > 0 + * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 + * multiple real roots may have non-zero imaginary part due + to roundoff errors. There is no reliable way to distinguish + real root of multiplicity 2 from two complex roots in + the presence of roundoff errors. + Rep - report, additional information, following fields are set: + * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field + allows to quickly estimate "quality" of the roots being + returned. + +NOTE: this function uses companion matrix method to find roots. In case + internal EVD solver fails do find eigenvalues, exception is + generated. + +NOTE: roots are not "polished" and no matrix balancing is performed + for them. + + -- ALGLIB -- + Copyright 24.02.2014 by Bochkanov Sergey +*************************************************************************/ +void polynomialsolve(const real_1d_array &a, const ae_int_t n, complex_1d_array &x, polynomialsolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::polynomialsolve(a.c_ptr(), n, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* + +*************************************************************************/ +_polynomialsolverreport_owner::_polynomialsolverreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_polynomialsolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::polynomialsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialsolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::polynomialsolverreport)); + alglib_impl::_polynomialsolverreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_polynomialsolverreport_owner::_polynomialsolverreport_owner(alglib_impl::polynomialsolverreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_polynomialsolverreport_owner::_polynomialsolverreport_owner(const _polynomialsolverreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_polynomialsolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialsolverreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::polynomialsolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialsolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::polynomialsolverreport)); + alglib_impl::_polynomialsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_polynomialsolverreport_owner& _polynomialsolverreport_owner::operator=(const _polynomialsolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: polynomialsolverreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialsolverreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: polynomialsolverreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_polynomialsolverreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::polynomialsolverreport)); + alglib_impl::_polynomialsolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_polynomialsolverreport_owner::~_polynomialsolverreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_polynomialsolverreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::polynomialsolverreport* _polynomialsolverreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::polynomialsolverreport* _polynomialsolverreport_owner::c_ptr() const +{ + return p_struct; +} +polynomialsolverreport::polynomialsolverreport() : _polynomialsolverreport_owner() ,maxerr(p_struct->maxerr) +{ +} + +polynomialsolverreport::polynomialsolverreport(alglib_impl::polynomialsolverreport *attach_to):_polynomialsolverreport_owner(attach_to) ,maxerr(p_struct->maxerr) +{ +} + +polynomialsolverreport::polynomialsolverreport(const polynomialsolverreport &rhs):_polynomialsolverreport_owner(rhs) ,maxerr(p_struct->maxerr) +{ +} + +polynomialsolverreport& polynomialsolverreport::operator=(const polynomialsolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _polynomialsolverreport_owner::operator=(rhs); + return *this; +} + +polynomialsolverreport::~polynomialsolverreport() +{ +} +#endif + +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and +b. This is "slow-but-feature rich" version of the linear solver. Faster +version is RMatrixSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It is also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolve(a.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and +b. This is "slow-but-feature rich" version of the linear solver. Faster +version is RMatrixSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It is also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixsolve(const real_2d_array &a, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolve(a.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. This is a "fast" version of linear +solver which does NOT provide any additional functions like condition +number estimation or iterative refinement. + +Algorithm features: +* efficient algorithm O(N^3) complexity +* no performance overhead from additional functionality + +If you need condition number estimation or iterative refinement, use more +feature-rich version - RMatrixSolve(). + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixsolvefast(a.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. This is a "fast" version of linear +solver which does NOT provide any additional functions like condition +number estimation or iterative refinement. + +Algorithm features: +* efficient algorithm O(N^3) complexity +* no performance overhead from additional functionality + +If you need condition number estimation or iterative refinement, use more +feature-rich version - RMatrixSolve(). + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool rmatrixsolvefast(const real_2d_array &a, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixsolvefast': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixsolvefast(a.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "slow-but-robust" version of linear +solver with additional functionality like condition number estimation. +There also exists faster version - RMatrixSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolvem(a.c_ptr(), n, b.c_ptr(), m, rfs, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "slow-but-robust" version of linear +solver with additional functionality like condition number estimation. +There also exists faster version - RMatrixSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixsolvem(const real_2d_array &a, const real_2d_array &b, const bool rfs, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolvem(a.c_ptr(), n, b.c_ptr(), m, rfs, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "fast" version of linear solver which +does NOT offer additional functions like condition number estimation or +iterative refinement. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional functionality, highest performance + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True for well-conditioned matrix + False for extremely badly conditioned or exactly singular problem + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, real_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixsolvemfast(a.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "fast" version of linear solver which +does NOT offer additional functions like condition number estimation or +iterative refinement. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional functionality, highest performance + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True for well-conditioned matrix + False for extremely badly conditioned or exactly singular problem + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool rmatrixsolvemfast(const real_2d_array &a, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixsolvemfast': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixsolvemfast(a.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "slow-but-robust" version of the linear LU-based solver. Faster version +is RMatrixLUSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlusolve(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "slow-but-robust" version of the linear LU-based solver. Faster version +is RMatrixLUSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixlusolve': looks like one of arguments has wrong size"); + n = lua.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlusolve(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "fast-without-any-checks" version of the linear LU-based solver. Slower +but more robust version is RMatrixLUSolve() function. + +Algorithm features: +* O(N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixlusolvefast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "fast-without-any-checks" version of the linear LU-based solver. Slower +but more robust version is RMatrixLUSolve() function. + +Algorithm features: +* O(N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixlusolvefast': looks like one of arguments has wrong size"); + n = lua.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixlusolvefast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). This is "robust-but-slow" version of +LU-based solver which performs additional checks for non-degeneracy of +inputs (condition number estimation). If you need best performance, use +"fast-without-any-checks" version, RMatrixLUSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlusolvem(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). This is "robust-but-slow" version of +LU-based solver which performs additional checks for non-degeneracy of +inputs (condition number estimation). If you need best performance, use +"fast-without-any-checks" version, RMatrixLUSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixlusolvem': looks like one of arguments has wrong size"); + n = lua.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixlusolvem(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts, +where b and x are NxM matrices. This is "fast-without-any-checks" version +of LU-based solver. It does not estimate condition number of a system, +so it is extremely fast. If you need better detection of near-degenerate +cases, use RMatrixLUSolveM() function. + +Algorithm features: +* O(M*N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS: + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, real_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixlusolvemfast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts, +where b and x are NxM matrices. This is "fast-without-any-checks" version +of LU-based solver. It does not estimate condition number of a system, +so it is extremely fast. If you need better detection of near-degenerate +cases, use RMatrixLUSolveM() function. + +Algorithm features: +* O(M*N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS: + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixlusolvemfast': looks like one of arguments has wrong size"); + n = lua.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::rmatrixlusolvemfast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixmixedsolve(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=lua.rows()) || (a.rows()!=lua.cols()) || (a.rows()!=p.length()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixmixedsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixmixedsolve(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixmixedsolvem(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=lua.rows()) || (a.rows()!=lua.cols()) || (a.rows()!=p.length()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixmixedsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixmixedsolvem(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Slow-but-feature-rich" version which provides +additional functions, at the cost of slower performance. Faster version +may be invoked with CMatrixSolveMFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixsolvem(a.c_ptr(), n, b.c_ptr(), m, rfs, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Slow-but-feature-rich" version which provides +additional functions, at the cost of slower performance. Faster version +may be invoked with CMatrixSolveMFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixsolvem(const complex_2d_array &a, const complex_2d_array &b, const bool rfs, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixsolvem(a.c_ptr(), n, b.c_ptr(), m, rfs, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Fast-but-lightweight" version which provides just +triangular solver - and no additional functions like iterative refinement +or condition number estimation. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, complex_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixsolvemfast(a.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Fast-but-lightweight" version which provides just +triangular solver - and no additional functions like iterative refinement +or condition number estimation. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool cmatrixsolvemfast(const complex_2d_array &a, complex_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixsolvemfast': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixsolvemfast(a.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixsolve(a.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixsolve(const complex_2d_array &a, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixsolve(a.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3) complexity +* no additional time consuming features, just triangular solver + +INPUT PARAMETERS: + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixsolvefast(a.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3) complexity +* no additional time consuming features, just triangular solver + +INPUT PARAMETERS: + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool cmatrixsolvefast(const complex_2d_array &a, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixsolvefast': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixsolvefast(a.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" +version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlusolvem(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" +version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixlusolvem': looks like one of arguments has wrong size"); + n = lua.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlusolvem(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" +version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* no additional time-consuming features + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, complex_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixlusolvemfast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" +version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* no additional time-consuming features + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, complex_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixlusolvemfast': looks like one of arguments has wrong size"); + n = lua.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixlusolvemfast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Complex dense linear solver for A*x=b with complex N*N A given by its LU +decomposition and N*1 vectors x and b. This is "slow-but-robust" version +of the complex linear solver with additional features which add +significant performance overhead. Faster version is CMatrixLUSolveFast() +function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlusolve(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Complex dense linear solver for A*x=b with complex N*N A given by its LU +decomposition and N*1 vectors x and b. This is "slow-but-robust" version +of the complex linear solver with additional features which add +significant performance overhead. Faster version is CMatrixLUSolveFast() +function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length()) || (lua.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixlusolve': looks like one of arguments has wrong size"); + n = lua.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixlusolve(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Complex dense linear solver for A*x=b with N*N complex A given by its LU +decomposition and N*1 vectors x and b. This is fast lightweight version +of solver, which is significantly faster than CMatrixLUSolve(), but does +not provide additional information (like condition numbers). + +Algorithm features: +* O(N^2) complexity +* no additional time-consuming features, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +NOTE: unlike CMatrixLUSolve(), this function does NOT check for + near-degeneracy of input matrix. It checks for EXACT degeneracy, + because this check is easy to do. However, very badly conditioned + matrices may went unnoticed. + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixlusolvefast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Complex dense linear solver for A*x=b with N*N complex A given by its LU +decomposition and N*1 vectors x and b. This is fast lightweight version +of solver, which is significantly faster than CMatrixLUSolve(), but does +not provide additional information (like condition numbers). + +Algorithm features: +* O(N^2) complexity +* no additional time-consuming features, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +NOTE: unlike CMatrixLUSolve(), this function does NOT check for + near-degeneracy of input matrix. It checks for EXACT degeneracy, + because this check is easy to do. However, very badly conditioned + matrices may went unnoticed. + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (lua.rows()!=lua.cols()) || (lua.rows()!=p.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixlusolvefast': looks like one of arguments has wrong size"); + n = lua.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::cmatrixlusolvefast(lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixmixedsolvem(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=lua.rows()) || (a.rows()!=lua.cols()) || (a.rows()!=p.length()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixmixedsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixmixedsolvem(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixmixedsolve(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=lua.rows()) || (a.rows()!=lua.cols()) || (a.rows()!=p.length()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cmatrixmixedsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::cmatrixmixedsolve(a.c_ptr(), lua.c_ptr(), p.c_ptr(), n, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixsolvem(a.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixsolvem(const real_2d_array &a, const bool isupper, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixsolvem(a.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, real_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixsolvemfast(a.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool spdmatrixsolvemfast(const real_2d_array &a, const bool isupper, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixsolvemfast': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixsolvemfast(a.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixsolve(a.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixsolve(const real_2d_array &a, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixsolve(a.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the +solver. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixsolvefast(a.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the +solver. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool spdmatrixsolvefast(const real_2d_array &a, const bool isupper, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixsolvefast': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixsolvefast(a.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- +feature-rich" version of the solver which estimates condition number of +the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveMFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskysolvem(cha.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- +feature-rich" version of the solver which estimates condition number of +the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveMFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixcholeskysolvem(const real_2d_array &cha, const bool isupper, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskysolvem': looks like one of arguments has wrong size"); + n = cha.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskysolvem(cha.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- +lightweight" version of the solver which just solves linear system, +without any additional functions. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional functionality + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, real_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholeskysolvemfast(cha.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- +lightweight" version of the solver which just solves linear system, +without any additional functions. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional functionality + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool spdmatrixcholeskysolvemfast(const real_2d_array &cha, const bool isupper, real_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskysolvemfast': looks like one of arguments has wrong size"); + n = cha.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholeskysolvemfast(cha.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- +but-feature-rich" version of the solver which, in addition to the +solution, performs condition number estimation. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskysolve(cha.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- +but-feature-rich" version of the solver which, in addition to the +solution, performs condition number estimation. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spdmatrixcholeskysolve(const real_2d_array &cha, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskysolve': looks like one of arguments has wrong size"); + n = cha.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spdmatrixcholeskysolve(cha.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- +but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholeskysolvefast(const real_2d_array &cha, const ae_int_t n, const bool isupper, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholeskysolvefast(cha.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- +but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool spdmatrixcholeskysolvefast(const real_2d_array &cha, const bool isupper, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spdmatrixcholeskysolvefast': looks like one of arguments has wrong size"); + n = cha.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::spdmatrixcholeskysolvefast(cha.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems (N<100). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixsolvem(a.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems (N<100). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixsolvem(const complex_2d_array &a, const bool isupper, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixsolvem': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixsolvem(a.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, complex_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixsolvemfast(a.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool hpdmatrixsolvemfast(const complex_2d_array &a, const bool isupper, complex_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (a.rows()!=a.cols()) || (a.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixsolvemfast': looks like one of arguments has wrong size"); + n = a.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixsolvemfast(a.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, HPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixsolve(a.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, HPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixsolve(const complex_2d_array &a, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixsolve': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixsolve(a.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Fast-but-lightweight" version of the +solver without additional functions. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixsolvefast(a.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Fast-but-lightweight" version of the +solver without additional functions. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool hpdmatrixsolvefast(const complex_2d_array &a, const bool isupper, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (a.rows()!=a.cols()) || (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixsolvefast': looks like one of arguments has wrong size"); + n = a.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixsolvefast(a.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"slow-but-feature-rich" version of the solver which, in addition to the +solution, estimates condition number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large Cholesky decomposition. However, if you call + ! this function many times for the same left side, this + ! overhead BECOMES significant. It also becomes significant + ! for small-scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveMFast() function. + + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskysolvem(cha.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"slow-but-feature-rich" version of the solver which, in addition to the +solution, estimates condition number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large Cholesky decomposition. However, if you call + ! this function many times for the same left side, this + ! overhead BECOMES significant. It also becomes significant + ! for small-scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveMFast() function. + + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const bool isupper, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholeskysolvem': looks like one of arguments has wrong size"); + n = cha.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskysolvem(cha.c_ptr(), n, isupper, b.c_ptr(), m, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, complex_2d_array &b, const ae_int_t m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholeskysolvemfast(cha.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const bool isupper, complex_2d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholeskysolvemfast': looks like one of arguments has wrong size"); + n = cha.rows(); + m = b.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholeskysolvemfast(cha.c_ptr(), n, isupper, b.c_ptr(), m, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"slow-but-feature-rich" version of the solver which estimates condition +number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskysolve(cha.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"slow-but-feature-rich" version of the solver which estimates condition +number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholeskysolve': looks like one of arguments has wrong size"); + n = cha.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hpdmatrixcholeskysolve(cha.c_ptr(), n, isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholeskysolvefast(cha.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +bool hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const bool isupper, complex_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (cha.rows()!=cha.cols()) || (cha.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'hpdmatrixcholeskysolvefast': looks like one of arguments has wrong size"); + n = cha.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::hpdmatrixcholeskysolvefast(cha.c_ptr(), n, isupper, b.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned. + +Algorithm features: +* automatic detection (and correct handling!) of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold*Largest are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B (even for singular A) + * zeros, if SVD subroutine failed + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* TerminationType is set to: + * -4 for SVD failure + * >0 for success +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, real_1d_array &x, densesolverlsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolvels(a.c_ptr(), nrows, ncols, b.c_ptr(), threshold, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned. + +Algorithm features: +* automatic detection (and correct handling!) of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold*Largest are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B (even for singular A) + * zeros, if SVD subroutine failed + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* TerminationType is set to: + * -4 for SVD failure + * >0 for success +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rmatrixsolvels(const real_2d_array &a, const real_1d_array &b, const double threshold, real_1d_array &x, densesolverlsreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t nrows; + ae_int_t ncols; + if( (a.rows()!=b.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'rmatrixsolvels': looks like one of arguments has wrong size"); + nrows = a.rows(); + ncols = a.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rmatrixsolvels(a.c_ptr(), nrows, ncols, b.c_ptr(), threshold, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + + +/************************************************************************* + +*************************************************************************/ +_densesolverreport_owner::_densesolverreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_densesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::densesolverreport)); + alglib_impl::_densesolverreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_densesolverreport_owner::_densesolverreport_owner(alglib_impl::densesolverreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_densesolverreport_owner::_densesolverreport_owner(const _densesolverreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_densesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: densesolverreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::densesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::densesolverreport)); + alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_densesolverreport_owner& _densesolverreport_owner::operator=(const _densesolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: densesolverreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: densesolverreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: densesolverreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_densesolverreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::densesolverreport)); + alglib_impl::_densesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_densesolverreport_owner::~_densesolverreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_densesolverreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::densesolverreport* _densesolverreport_owner::c_ptr() const +{ + return p_struct; +} +densesolverreport::densesolverreport() : _densesolverreport_owner() ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +densesolverreport::densesolverreport(alglib_impl::densesolverreport *attach_to):_densesolverreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +densesolverreport::densesolverreport(const densesolverreport &rhs):_densesolverreport_owner(rhs) ,terminationtype(p_struct->terminationtype),r1(p_struct->r1),rinf(p_struct->rinf) +{ +} + +densesolverreport& densesolverreport::operator=(const densesolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _densesolverreport_owner::operator=(rhs); + return *this; +} + +densesolverreport::~densesolverreport() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_densesolverlsreport_owner::_densesolverlsreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_densesolverlsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::densesolverlsreport)); + alglib_impl::_densesolverlsreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_densesolverlsreport_owner::_densesolverlsreport_owner(alglib_impl::densesolverlsreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_densesolverlsreport_owner::_densesolverlsreport_owner(const _densesolverlsreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_densesolverlsreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: densesolverlsreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::densesolverlsreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::densesolverlsreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::densesolverlsreport)); + alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_densesolverlsreport_owner& _densesolverlsreport_owner::operator=(const _densesolverlsreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: densesolverlsreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: densesolverlsreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: densesolverlsreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_densesolverlsreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::densesolverlsreport)); + alglib_impl::_densesolverlsreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_densesolverlsreport_owner::~_densesolverlsreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_densesolverlsreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::densesolverlsreport* _densesolverlsreport_owner::c_ptr() const +{ + return p_struct; +} +densesolverlsreport::densesolverlsreport() : _densesolverlsreport_owner() ,terminationtype(p_struct->terminationtype),r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) +{ +} + +densesolverlsreport::densesolverlsreport(alglib_impl::densesolverlsreport *attach_to):_densesolverlsreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) +{ +} + +densesolverlsreport::densesolverlsreport(const densesolverlsreport &rhs):_densesolverlsreport_owner(rhs) ,terminationtype(p_struct->terminationtype),r2(p_struct->r2),cx(&p_struct->cx),n(p_struct->n),k(p_struct->k) +{ +} + +densesolverlsreport& densesolverlsreport::operator=(const densesolverlsreport &rhs) +{ + if( this==&rhs ) + return *this; + _densesolverlsreport_owner::operator=(rhs); + return *this; +} + +densesolverlsreport::~densesolverlsreport() +{ +} +#endif + +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Solving sparse symmetric linear system A*x=b using GMRES(k) method. Sparse +symmetric A is given by its lower or upper triangle. + +NOTE: use SparseSolveGMRES() to solve system with nonsymmetric A. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvesymmetricgmres(const sparsematrix &a, const bool isupper, const real_1d_array &b, const ae_int_t k, const double epsf, const ae_int_t maxits, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolvesymmetricgmres(a.c_ptr(), isupper, b.c_ptr(), k, epsf, maxits, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Solving sparse linear system A*x=b using GMRES(k) method. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse NxN matrix in any sparse storage format. Using CRS + format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvegmres(const sparsematrix &a, const real_1d_array &b, const ae_int_t k, const double epsf, const ae_int_t maxits, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolvegmres(a.c_ptr(), b.c_ptr(), k, epsf, maxits, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initializes sparse linear iterative solver object. + +This solver can be used to solve nonsymmetric and symmetric positive +definite NxN (square) linear systems. + +The solver provides 'expert' API which allows advanced control over +algorithms being used, including ability to get progress report, terminate +long-running solver from other thread, out-of-core solution and so on. + +NOTE: there are also convenience functions that allows quick one-line + access to the solvers: + * SparseSolveCG() to solve SPD linear systems + * SparseSolveGMRES() to solve unsymmetric linear systems. + +NOTE: if you want to solve MxN (rectangular) linear problem you may use + LinLSQR solver provided by ALGLIB. + +USAGE (A is given by the SparseMatrix structure): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. Depending on whether system is symmetric or not, user calls: + * SparseSolverSolveSymmetric() for a symmetric system given by its + lower or upper triangle + * SparseSolverSolve() for a nonsymmetric system or a symmetric one + given by the full matrix + 5. User calls SparseSolverResults() to get the solution + + It is possible to call SparseSolverSolve???() again to solve another + task with same dimensionality but different matrix and/or right part + without reinitializing SparseSolverState structure. + +USAGE (out-of-core mode): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. After that user should work with out-of-core interface in a loop + like one given below: + + > alglib.sparsesolveroocstart(state) + > while alglib.sparsesolverooccontinue(state) do + > alglib.sparsesolveroocgetrequestinfo(state, out RequestType) + > alglib.sparsesolveroocgetrequestdata(state, out X) + > if RequestType=0 then + > [calculate Y=A*X, with X=R^N] + > alglib.sparsesolveroocsendresult(state, in Y) + > alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + N - problem dimensionality (fixed at start-up) + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvercreate(const ae_int_t n, sparsesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolvercreate(n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets the solver algorithm to GMRES(k). + +NOTE: if you do not need advanced functionality of the SparseSolver API, + you may use convenience functions SparseSolveGMRES() and + SparseSolveSymmetricGMRES(). + +INPUT PARAMETERS: + State - structure which stores algorithm state + K - GMRES parameter, K>=0: + * recommended values are in 10..100 range + * larger values up to N are possible but have little sense + - the algorithm will be slower than any dense solver. + * values above N are truncated down to N + * zero value means that default value is chosen. This + value is 50 in the current version, but it may change + in future ALGLIB releases. + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetalgogmres(sparsesolverstate &state, const ae_int_t k, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversetalgogmres(state.c_ptr(), k, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - new starting point was set + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetstartingpoint(sparsesolverstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversetstartingpoint(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetcond(sparsesolverstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversetcond(state.c_ptr(), epsf, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Procedure for the solution of A*x=b with sparse symmetric A given by its +lower or upper triangle. + +This function will work with any solver algorithm being used, SPD one +(like CG) or not (like GMRES). Using unsymmetric solvers (like GMRES) on +SPD problems is suboptimal, but still possible. + +NOTE: the solver behavior is ill-defined for a situation when a SPD + solver is used on indefinite matrix. It may solve the problem up to + desired precision (sometimes, rarely) or return with error code + signalling violation of underlying assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolvesymmetric(sparsesolverstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversolvesymmetric(state.c_ptr(), a.c_ptr(), isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Procedure for the solution of A*x=b with sparse nonsymmetric A + +IMPORTANT: this function will work with any solver algorithm being used, + symmetric solver like CG, or not. However, using symmetric + solvers on nonsymmetric problems is dangerous. It may solve + the problem up to desired precision (sometimes, rarely) or + terminate with error code signalling violation of underlying + assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolve(sparsesolverstate &state, const sparsematrix &a, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversolve(state.c_ptr(), a.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse solver results. + +This function must be called after calling one of the SparseSolverSolve() +functions. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual +s + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverresults(sparsesolverstate &state, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolverresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting during out-of-core processing. + +When the solver works in the out-of-core mode, it can be configured to +report its progress by returning current location. These location reports +are implemented as a special kind of the out-of-core request: +* SparseSolverOOCGetRequestInfo() returns -1 +* SparseSolverOOCGetRequestData() returns current location +* SparseSolverOOCGetRequestData1() returns squared norm of the residual +* SparseSolverOOCSendResult() shall NOT be called + +This function has no effect when SparseSolverSolve() is used because this +function has no method of reporting its progress. + +NOTE: when used with GMRES(k), this function reports progress every k-th + iteration. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetxrep(sparsesolverstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolversetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initiates out-of-core mode of the sparse solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver object + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstart(sparsesolverstate &state, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocstart(state.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function performs iterative solution of the linear system in the +out-of-core mode. It should be used in conjunction with other out-of-core- +related functions of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +bool sparsesolverooccontinue(sparsesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::sparsesolverooccontinue(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by the solver: +* RequestType=0 means that matrix-vector products A*x is requested +* RequestType=-1 means that solver reports its progress; this request is + returned only when reports are activated wit SparseSolverSetXRep(). + +This function returns just request type; in order to get contents of the +trial vector, use sparsesolveroocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 for matrix-vector product A*x, with A being + NxN system matrix and X being N-dimensional + vector + *-1 for location and residual report + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestinfo(sparsesolverstate &state, ae_int_t &requesttype, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocgetrequestinfo(state.c_ptr(), &requesttype, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to retrieve vector associated with out-of-core +request sent by the solver to user code. Depending on the request type +(returned by the SparseSolverOOCGetRequestInfo()) this vector should be +multiplied by A or subjected to another processing. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N] or larger, leading N elements are filled + with vector X. + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata(sparsesolverstate &state, real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocgetrequestdata(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to retrieve scalar value associated with out-of-core +request sent by the solver to user code. In the current ALGLIB version +this function is used to retrieve squared residual norm during progress +reports. + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + V - scalar value associated with the current request + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata1(sparsesolverstate &state, double &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocgetrequestdata1(state.c_ptr(), &v, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +the solver. Usually it is product A*x for vector X returned by the solver. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N] or larger, leading N elements contain A*x + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocsendresult(sparsesolverstate &state, const real_1d_array &ax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocsendresult(state.c_ptr(), ax.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function finalizes out-of-core mode of the linear solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + X - array[N], the solution. + Zero-filled on the failure (Rep.TerminationType<0). + Rep - report with additional info: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstop(sparsesolverstate &state, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolveroocstop(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants the solver to terminate +or when processing an out-of-core request. + +As result, solver stops at point which was "current accepted" when +the termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverrequesttermination(sparsesolverstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolverrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This structure is a sparse solver report (both direct and iterative solvers +use this structure). + +Following fields can be accessed by users: +* TerminationType (specific error codes depend on the solver being used, + with positive values ALWAYS signaling that something useful is returned + in X, and negative values ALWAYS meaning critical failures. +* NMV - number of matrix-vector products performed (0 for direct solvers) +* IterationsCount - inner iterations count (0 for direct solvers) +* R2 - squared residual +*************************************************************************/ +_sparsesolverreport_owner::_sparsesolverreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::sparsesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverreport)); + alglib_impl::_sparsesolverreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsesolverreport_owner::_sparsesolverreport_owner(alglib_impl::sparsesolverreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_sparsesolverreport_owner::_sparsesolverreport_owner(const _sparsesolverreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsesolverreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsesolverreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::sparsesolverreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsesolverreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverreport)); + alglib_impl::_sparsesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsesolverreport_owner& _sparsesolverreport_owner::operator=(const _sparsesolverreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: sparsesolverreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsesolverreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: sparsesolverreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_sparsesolverreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverreport)); + alglib_impl::_sparsesolverreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_sparsesolverreport_owner::~_sparsesolverreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_sparsesolverreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::sparsesolverreport* _sparsesolverreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::sparsesolverreport* _sparsesolverreport_owner::c_ptr() const +{ + return p_struct; +} +sparsesolverreport::sparsesolverreport() : _sparsesolverreport_owner() ,terminationtype(p_struct->terminationtype),nmv(p_struct->nmv),iterationscount(p_struct->iterationscount),r2(p_struct->r2) +{ +} + +sparsesolverreport::sparsesolverreport(alglib_impl::sparsesolverreport *attach_to):_sparsesolverreport_owner(attach_to) ,terminationtype(p_struct->terminationtype),nmv(p_struct->nmv),iterationscount(p_struct->iterationscount),r2(p_struct->r2) +{ +} + +sparsesolverreport::sparsesolverreport(const sparsesolverreport &rhs):_sparsesolverreport_owner(rhs) ,terminationtype(p_struct->terminationtype),nmv(p_struct->nmv),iterationscount(p_struct->iterationscount),r2(p_struct->r2) +{ +} + +sparsesolverreport& sparsesolverreport::operator=(const sparsesolverreport &rhs) +{ + if( this==&rhs ) + return *this; + _sparsesolverreport_owner::operator=(rhs); + return *this; +} + +sparsesolverreport::~sparsesolverreport() +{ +} + + + + +/************************************************************************* +This object stores state of the sparse linear solver object. + +You should use ALGLIB functions to work with this object. +Never try to access its fields directly! +*************************************************************************/ +_sparsesolverstate_owner::_sparsesolverstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsesolverstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::sparsesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsesolverstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverstate)); + alglib_impl::_sparsesolverstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsesolverstate_owner::_sparsesolverstate_owner(alglib_impl::sparsesolverstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_sparsesolverstate_owner::_sparsesolverstate_owner(const _sparsesolverstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_sparsesolverstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsesolverstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::sparsesolverstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::sparsesolverstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverstate)); + alglib_impl::_sparsesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_sparsesolverstate_owner& _sparsesolverstate_owner::operator=(const _sparsesolverstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: sparsesolverstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: sparsesolverstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: sparsesolverstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_sparsesolverstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::sparsesolverstate)); + alglib_impl::_sparsesolverstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_sparsesolverstate_owner::~_sparsesolverstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_sparsesolverstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::sparsesolverstate* _sparsesolverstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::sparsesolverstate* _sparsesolverstate_owner::c_ptr() const +{ + return p_struct; +} +sparsesolverstate::sparsesolverstate() : _sparsesolverstate_owner() +{ +} + +sparsesolverstate::sparsesolverstate(alglib_impl::sparsesolverstate *attach_to):_sparsesolverstate_owner(attach_to) +{ +} + +sparsesolverstate::sparsesolverstate(const sparsesolverstate &rhs):_sparsesolverstate_owner(rhs) +{ +} + +sparsesolverstate& sparsesolverstate::operator=(const sparsesolverstate &rhs) +{ + if( this==&rhs ) + return *this; + _sparsesolverstate_owner::operator=(rhs); + return *this; +} + +sparsesolverstate::~sparsesolverstate() +{ +} +#endif + +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes linear CG Solver. This solver is used to solve +symmetric positive definite problems. If you want to solve nonsymmetric +(or non-positive definite) problem you may use LinLSQR solver provided by +ALGLIB. + +USAGE: +1. User initializes algorithm state with LinCGCreate() call +2. User tunes solver parameters with LinCGSetCond() and other functions +3. Optionally, user sets starting point with LinCGSetStartingPoint() +4. User calls LinCGSolveSparse() function which takes algorithm state and + SparseMatrix object. +5. User calls LinCGResults() to get solution +6. Optionally, user may call LinCGSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinCGState structure. + +INPUT PARAMETERS: + N - problem dimension, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgcreate(const ae_int_t n, lincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgcreate(n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetstartingpoint(lincgstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetstartingpoint(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecunit(lincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetprecunit(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecdiag(lincgstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetprecdiag(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetcond(lincgstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetcond(state.c_ptr(), epsf, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse matrix in the CRS format (you MUST contvert it to + CRS format by calling SparseConvertToCRS() function). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinCGSetPrecUnit(). However, preconditioning cost is low and + preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsolvesparse(lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsolvesparse(state.c_ptr(), a.c_ptr(), isupper, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +CG-solver: results. + +This function must be called after LinCGSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -5 input matrix is either not positive definite, + too large or too small + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets restart frequency. By default, algorithm is restarted +after N subsequent iterations. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrestartfreq(lincgstate &state, const ae_int_t srf, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetrestartfreq(state.c_ptr(), srf, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets frequency of residual recalculations. + +Algorithm updates residual r_k using iterative formula, but recalculates +it from scratch after each 10 iterations. It is done to avoid accumulation +of numerical errors and to stop algorithm when r_k starts to grow. + +Such low update frequence (1/10) gives very little overhead, but makes +algorithm a bit more robust against numerical errors. However, you may +change it + +INPUT PARAMETERS: + Freq - desired update frequency, Freq>=0. + Zero value means that no updates will be done. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrupdatefreq(lincgstate &state, const ae_int_t freq, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetrupdatefreq(state.c_ptr(), freq, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetxrep(lincgstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::lincgsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores state of the linear CG method. + +You should use ALGLIB functions to work with this object. +Never try to access its fields directly! +*************************************************************************/ +_lincgstate_owner::_lincgstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lincgstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lincgstate)); + alglib_impl::_lincgstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lincgstate_owner::_lincgstate_owner(alglib_impl::lincgstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lincgstate_owner::_lincgstate_owner(const _lincgstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lincgstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lincgstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lincgstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lincgstate)); + alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lincgstate_owner& _lincgstate_owner::operator=(const _lincgstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lincgstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lincgstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lincgstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lincgstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lincgstate)); + alglib_impl::_lincgstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lincgstate_owner::~_lincgstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lincgstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lincgstate* _lincgstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lincgstate* _lincgstate_owner::c_ptr() const +{ + return p_struct; +} +lincgstate::lincgstate() : _lincgstate_owner() +{ +} + +lincgstate::lincgstate(alglib_impl::lincgstate *attach_to):_lincgstate_owner(attach_to) +{ +} + +lincgstate::lincgstate(const lincgstate &rhs):_lincgstate_owner(rhs) +{ +} + +lincgstate& lincgstate::operator=(const lincgstate &rhs) +{ + if( this==&rhs ) + return *this; + _lincgstate_owner::operator=(rhs); + return *this; +} + +lincgstate::~lincgstate() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_lincgreport_owner::_lincgreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lincgreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lincgreport)); + alglib_impl::_lincgreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lincgreport_owner::_lincgreport_owner(alglib_impl::lincgreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_lincgreport_owner::_lincgreport_owner(const _lincgreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_lincgreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lincgreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::lincgreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lincgreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::lincgreport)); + alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_lincgreport_owner& _lincgreport_owner::operator=(const _lincgreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lincgreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lincgreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: lincgreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_lincgreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::lincgreport)); + alglib_impl::_lincgreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_lincgreport_owner::~_lincgreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_lincgreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::lincgreport* _lincgreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::lincgreport* _lincgreport_owner::c_ptr() const +{ + return p_struct; +} +lincgreport::lincgreport() : _lincgreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) +{ +} + +lincgreport::lincgreport(alglib_impl::lincgreport *attach_to):_lincgreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) +{ +} + +lincgreport::lincgreport(const lincgreport &rhs):_lincgreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype),r2(p_struct->r2) +{ +} + +lincgreport& lincgreport::operator=(const lincgreport &rhs) +{ + if( this==&rhs ) + return *this; + _lincgreport_owner::operator=(rhs); + return *this; +} + +lincgreport::~lincgreport() +{ +} +#endif + +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes linear LSQR Solver. This solver is used to solve +non-symmetric (and, possibly, non-square) problems. Least squares solution +is returned for non-compatible systems. + +USAGE: +1. User initializes algorithm state with LinLSQRCreate() call +2. User tunes solver parameters with LinLSQRSetCond() and other functions +3. User calls LinLSQRSolveSparse() function which takes algorithm state + and SparseMatrix object. +4. User calls LinLSQRResults() to get solution +5. Optionally, user may call LinLSQRSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinLSQRState structure. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: see also linlsqrcreatebuf() for version which reuses previously + allocated place as much as possible. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrcreate(m, n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initializes linear LSQR Solver. It provides exactly same +functionality as linlsqrcreate(), but reuses previously allocated space +as much as possible. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2018 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreatebuf(const ae_int_t m, const ae_int_t n, linlsqrstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrcreatebuf(m, n, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes preconditioning settings of LinLSQQSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecunit(linlsqrstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsetprecunit(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecdiag(linlsqrstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsetprecdiag(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets optional Tikhonov regularization coefficient. +It is zero by default. + +INPUT PARAMETERS: + LambdaI - regularization factor, LambdaI>=0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetlambdai(linlsqrstate &state, const double lambdai, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsetlambdai(state.c_ptr(), lambdai, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse M*N matrix in the CRS format (you MUST contvert it + to CRS format by calling SparseConvertToCRS() function + BEFORE you pass it to this function). + B - right part, array[M] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinLSQRSetPrecUnit(). However, preconditioning cost is low + and preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsolvesparse(linlsqrstate &state, const sparsematrix &a, const real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsolvesparse(state.c_ptr(), a.c_ptr(), b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. + EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| + MaxIts - algorithm will be stopped if number of iterations + more than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will +be setted as default values. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetcond(linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsetcond(state.c_ptr(), epsa, epsb, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +LSQR solver: results. + +This function must be called after LinLSQRSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * 1 ||Rk||<=EpsB*||B|| + * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + X contains best point found so far. + (sometimes returned on singular systems) + * 8 user requested termination via calling + linlsqrrequesttermination() + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetxrep(linlsqrstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function is used to peek into LSQR solver and get current iteration +counter. You can safely "peek" into the solver from another thread. + +INPUT PARAMETERS: + S - solver object + +RESULT: + iteration counter, in [0,INF) + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t linlsqrpeekiterationscount(const linlsqrstate &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_int_t result = alglib_impl::linlsqrpeekiterationscount(s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return ae_int_t(result); +} + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants LSQR solver to terminate +(obviously, the thread running LSQR solver can not request termination +because it is already busy working on LSQR). + +As result, solver stops at point which was "current accepted" when +termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void linlsqrrequesttermination(linlsqrstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::linlsqrrequesttermination(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* +This object stores state of the LinLSQR method. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +_linlsqrstate_owner::_linlsqrstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linlsqrstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrstate)); + alglib_impl::_linlsqrstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linlsqrstate_owner::_linlsqrstate_owner(alglib_impl::linlsqrstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_linlsqrstate_owner::_linlsqrstate_owner(const _linlsqrstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linlsqrstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linlsqrstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::linlsqrstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrstate)); + alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linlsqrstate_owner& _linlsqrstate_owner::operator=(const _linlsqrstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: linlsqrstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linlsqrstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: linlsqrstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_linlsqrstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrstate)); + alglib_impl::_linlsqrstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_linlsqrstate_owner::~_linlsqrstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_linlsqrstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::linlsqrstate* _linlsqrstate_owner::c_ptr() const +{ + return p_struct; +} +linlsqrstate::linlsqrstate() : _linlsqrstate_owner() +{ +} + +linlsqrstate::linlsqrstate(alglib_impl::linlsqrstate *attach_to):_linlsqrstate_owner(attach_to) +{ +} + +linlsqrstate::linlsqrstate(const linlsqrstate &rhs):_linlsqrstate_owner(rhs) +{ +} + +linlsqrstate& linlsqrstate::operator=(const linlsqrstate &rhs) +{ + if( this==&rhs ) + return *this; + _linlsqrstate_owner::operator=(rhs); + return *this; +} + +linlsqrstate::~linlsqrstate() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_linlsqrreport_owner::_linlsqrreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linlsqrreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrreport)); + alglib_impl::_linlsqrreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linlsqrreport_owner::_linlsqrreport_owner(alglib_impl::linlsqrreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_linlsqrreport_owner::_linlsqrreport_owner(const _linlsqrreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_linlsqrreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linlsqrreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::linlsqrreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::linlsqrreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrreport)); + alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_linlsqrreport_owner& _linlsqrreport_owner::operator=(const _linlsqrreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: linlsqrreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: linlsqrreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: linlsqrreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_linlsqrreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::linlsqrreport)); + alglib_impl::_linlsqrreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_linlsqrreport_owner::~_linlsqrreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_linlsqrreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::linlsqrreport* _linlsqrreport_owner::c_ptr() const +{ + return p_struct; +} +linlsqrreport::linlsqrreport() : _linlsqrreport_owner() ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +linlsqrreport::linlsqrreport(alglib_impl::linlsqrreport *attach_to):_linlsqrreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +linlsqrreport::linlsqrreport(const linlsqrreport &rhs):_linlsqrreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype) +{ +} + +linlsqrreport& linlsqrreport::operator=(const linlsqrreport &rhs) +{ + if( this==&rhs ) + return *this; + _linlsqrreport_owner::operator=(rhs); + return *this; +} + +linlsqrreport::~linlsqrreport() +{ +} +#endif + +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +This solver converts input matrix to SKS format, performs Cholesky +factorization using SKS Cholesky subroutine (works well for limited +bandwidth matrices) and uses sparse triangular solvers to get solution of +the original system. + +IMPORTANT: this function is intended for low profile (variable band) + linear systems with dense or nearly-dense bands. Only in such + cases it provides some performance improvement over more + general sparsrspdsolve(). If your system has high bandwidth + or sparse band, the general sparsrspdsolve() is likely to be + more efficient. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolvesks(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsespdsolvesks(a.c_ptr(), isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +Depending on the ALGLIB edition (Free or Commercial, C++, C# or other), +the following applies: + +* FREE EDITION: ALGLIB sparse solver can be used, a supernodal algorithm + with serial implementation in generic C or generic C#. + +* COMMERCIAL EDITION: a parallel and SIMD-capable version of the ALGLIB + sparse supernodal solver can be used. A C code with SIMD kernels callable + from C++ and C#. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library can outperform + ALGLIB; for other problem types, ALGLIB DSS solver can be superior. + +IMPORTANT: This function is preferred to one that works with explicitly + given Cholesky factorization (sparsespdcholeskysolve). Some + efficient linear solver backends do not return Cholesky factors, + so doing explicit Cholesky followed by sparsespdcholeskysolve() + means that these backends will never be activated. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly. + Can be stored in any sparse storage format, CRS is preferred. + IsUpper - which half of A is provided (another half is ignored). + It is better to store the lower triangle because it allows + us to avoid one transposition during internal conversion. + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolve(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsespdsolve(a.c_ptr(), isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse linear solver for A*x=b with N*N real symmetric positive definite +matrix A given by its Cholesky decomposition, and N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the SKS (Skyline) + or CRS (compressed row storage) format. An exception will be + generated if you pass matrix in some other format. + +INPUT PARAMETERS + A - sparse NxN matrix stored in CRs or SKS format, must be NxN + exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdcholeskysolve(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsespdcholeskysolve(a.c_ptr(), isupper, b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A, N*1 vectors x and b. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* sparse LU with dynamic pivoting for stability. Provides better accuracy + at the cost of a significantly lower performance. Recommended only for + extremely unstable problems. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly, any storage format + B - array[N], right part + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + * 20 use sparse LU with dynamic pivoting for stability. + Not intended for large-scale problems. + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolve(const sparsematrix &a, const real_1d_array &b, const ae_int_t solvertype, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolve(a.c_ptr(), b.c_ptr(), solvertype, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A, N*1 vectors x and b. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* sparse LU with dynamic pivoting for stability. Provides better accuracy + at the cost of a significantly lower performance. Recommended only for + extremely unstable problems. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly, any storage format + B - array[N], right part + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + * 20 use sparse LU with dynamic pivoting for stability. + Not intended for large-scale problems. + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsesolve(const sparsematrix &a, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t solvertype; + + solvertype = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolve(a.c_ptr(), b.c_ptr(), solvertype, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Sparse linear least squares solver for A*x=b with general (nonsymmetric) +N*N sparse real matrix A, N*1 vectors x and b. + +This function solves a regularized linear least squares problem of the form + + ( ) + min ( |Ax-b|^2 + reg*|x|^2 ), with reg>=sqrt(MachineAccuracy) + ( ) + +It can be used to solve both full rank and rank deficient systems. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse MxN matrix, any storage format + B - array[M], right part + Reg - regularization coefficient, Reg>=sqrt(MachineAccuracy), + lower values will be silently increased. + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + +OUTPUT PARAMETERS + X - array[N], least squares solution + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success. + + Present version of the solver does NOT returns negative + completion codes because it does not fail. However, + future ALGLIB versions may include solvers which return + negative completion codes. + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvelsreg(const sparsematrix &a, const real_1d_array &b, const double reg, const ae_int_t solvertype, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolvelsreg(a.c_ptr(), b.c_ptr(), reg, solvertype, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Sparse linear least squares solver for A*x=b with general (nonsymmetric) +N*N sparse real matrix A, N*1 vectors x and b. + +This function solves a regularized linear least squares problem of the form + + ( ) + min ( |Ax-b|^2 + reg*|x|^2 ), with reg>=sqrt(MachineAccuracy) + ( ) + +It can be used to solve both full rank and rank deficient systems. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse MxN matrix, any storage format + B - array[M], right part + Reg - regularization coefficient, Reg>=sqrt(MachineAccuracy), + lower values will be silently increased. + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + +OUTPUT PARAMETERS + X - array[N], least squares solution + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success. + + Present version of the solver does NOT returns negative + completion codes because it does not fail. However, + future ALGLIB versions may include solvers which return + negative completion codes. + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sparsesolvelsreg(const sparsematrix &a, const real_1d_array &b, const double reg, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t solvertype; + + solvertype = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparsesolvelsreg(a.c_ptr(), b.c_ptr(), reg, solvertype, x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A given by its LU factorization, N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the CRS sparse + storage format. An exception will be generated if you pass + matrix in some other format (HASH or SKS). + +INPUT PARAMETERS + A - LU factorization of the sparse matrix, must be NxN exactly + in CRS storage format + P, Q - pivot indexes from LU factorization + N - size of A, N>0 + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparselusolve(const sparsematrix &a, const integer_1d_array &p, const integer_1d_array &q, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sparselusolve(a.c_ptr(), p.c_ptr(), q.c_ptr(), b.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqcreatelm(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqcreatelm(n, m, x.c_ptr(), state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(nleqstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqsetcond(state.c_ptr(), epsf, maxits, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(nleqstate &state, const bool needxrep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqsetxrep(state.c_ptr(), needxrep, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when target function contains exp() or other fast +growing functions, and algorithm makes too large steps which lead to +overflow. This function allows us to reject steps that are too large (and +therefore expose us to the possible overflow) without actually calculating +function value at the x+stp*d. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(nleqstate &state, const double stpmax, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqsetstpmax(state.c_ptr(), stpmax, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool nleqiteration(nleqstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::nleqiteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void nleqsolve(nleqstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'nleqsolve()' (func is NULL)", &_alglib_env_state); + alglib_impl::ae_assert(jac!=NULL, "ALGLIB: error in 'nleqsolve()' (jac is NULL)", &_alglib_env_state); + alglib_impl::nleqsetprotocolv1(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::nleqiteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( state.needf ) + { + func(state.x, state.f, ptr); + continue; + } + if( state.needfij ) + { + jac(state.x, state.fi, state.j, ptr); + continue; + } + if( state.xupdated ) + { + if( rep!=NULL ) + rep(state.x, state.f, ptr); + continue; + } + goto lbl_no_callback; + _ALGLIB_CALLBACK_EXCEPTION_GUARD_END + lbl_no_callback: + alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'nleqsolve' (some derivatives were not provided?)", &_alglib_env_state); + } + alglib_impl::ae_state_clear(&_alglib_env_state); +} + + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + * ActiveConstraints contains number of active constraints + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqresults(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqresultsbuf(state.c_ptr(), x.c_ptr(), rep.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinCGCreate call. + X - new starting point. + BndL - new lower bounds + BndU - new upper bounds + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqrestartfrom(nleqstate &state, const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::nleqrestartfrom(state.c_ptr(), x.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + + +/************************************************************************* + +*************************************************************************/ +_nleqstate_owner::_nleqstate_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nleqstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nleqstate)); + alglib_impl::_nleqstate_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nleqstate_owner::_nleqstate_owner(alglib_impl::nleqstate *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_nleqstate_owner::_nleqstate_owner(const _nleqstate_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nleqstate_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nleqstate copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::nleqstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqstate), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nleqstate)); + alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nleqstate_owner& _nleqstate_owner::operator=(const _nleqstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: nleqstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nleqstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: nleqstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_nleqstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::nleqstate)); + alglib_impl::_nleqstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_nleqstate_owner::~_nleqstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_nleqstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::nleqstate* _nleqstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::nleqstate* _nleqstate_owner::c_ptr() const +{ + return p_struct; +} +nleqstate::nleqstate() : _nleqstate_owner() ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +nleqstate::nleqstate(alglib_impl::nleqstate *attach_to):_nleqstate_owner(attach_to) ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +nleqstate::nleqstate(const nleqstate &rhs):_nleqstate_owner(rhs) ,needf(p_struct->needf),needfij(p_struct->needfij),xupdated(p_struct->xupdated),f(p_struct->f),fi(&p_struct->fi),j(&p_struct->j),x(&p_struct->x) +{ +} + +nleqstate& nleqstate::operator=(const nleqstate &rhs) +{ + if( this==&rhs ) + return *this; + _nleqstate_owner::operator=(rhs); + return *this; +} + +nleqstate::~nleqstate() +{ +} + + + + +/************************************************************************* + +*************************************************************************/ +_nleqreport_owner::_nleqreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nleqreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nleqreport)); + alglib_impl::_nleqreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nleqreport_owner::_nleqreport_owner(alglib_impl::nleqreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_nleqreport_owner::_nleqreport_owner(const _nleqreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_nleqreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nleqreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::nleqreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::nleqreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::nleqreport)); + alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_nleqreport_owner& _nleqreport_owner::operator=(const _nleqreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: nleqreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: nleqreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: nleqreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_nleqreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::nleqreport)); + alglib_impl::_nleqreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_nleqreport_owner::~_nleqreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_nleqreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::nleqreport* _nleqreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::nleqreport* _nleqreport_owner::c_ptr() const +{ + return p_struct; +} +nleqreport::nleqreport() : _nleqreport_owner() ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) +{ +} + +nleqreport::nleqreport(alglib_impl::nleqreport *attach_to):_nleqreport_owner(attach_to) ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) +{ +} + +nleqreport::nleqreport(const nleqreport &rhs):_nleqreport_owner(rhs) ,iterationscount(p_struct->iterationscount),nfunc(p_struct->nfunc),njac(p_struct->njac),terminationtype(p_struct->terminationtype) +{ +} + +nleqreport& nleqreport::operator=(const nleqreport &rhs) +{ + if( this==&rhs ) + return *this; + _nleqreport_owner::operator=(rhs); + return *this; +} + +nleqreport::~nleqreport() +{ +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +static void directdensesolvers_rmatrixlusolveinternal(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_bool havea, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +static void directdensesolvers_spdmatrixcholeskysolveinternal(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* a, + ae_bool havea, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +static void directdensesolvers_cmatrixlusolveinternal(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_bool havea, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +static void directdensesolvers_hpdmatrixcholeskysolveinternal(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* a, + ae_bool havea, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +static ae_int_t directdensesolvers_densesolverrfsmax(ae_int_t n, + double r1, + double rinf, + ae_state *_state); +static ae_int_t directdensesolvers_densesolverrfsmaxv2(ae_int_t n, + double r2, + ae_state *_state); +static void directdensesolvers_rbasiclusolve(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* xb, + ae_state *_state); +static void directdensesolvers_spdbasiccholeskysolve(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + ae_state *_state); +static void directdensesolvers_cbasiclusolve(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* xb, + ae_state *_state); +static void directdensesolvers_hpdbasiccholeskysolve(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* xb, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +static ae_bool iterativesparse_sparsesolveriteration(sparsesolverstate* state, + ae_state *_state); +static void iterativesparse_clearrequestfields(sparsesolverstate* state, + ae_state *_state); +static void iterativesparse_clearreportfields(sparsesolverstate* state, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +static double lincg_defaultprecision = 1.0E-6; +static void lincg_clearrfields(lincgstate* state, ae_state *_state); +static void lincg_updateitersdata(lincgstate* state, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +static double linlsqr_atol = 1.0E-6; +static double linlsqr_btol = 1.0E-6; +static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) +static void directsparsesolvers_sparsesolveaug(const sparsematrix* a, + /* Real */ const ae_vector* b, + double reg1f, + double reg2f, + double reg1r, + double reg2r, + ae_int_t gmresk, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +static void nleq_clearrequestfields(nleqstate* state, ae_state *_state); +static ae_bool nleq_increaselambda(double* lambdav, + double* nu, + double lambdaup, + ae_state *_state); +static void nleq_decreaselambda(double* lambdav, + double* nu, + double lambdadown, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Polynomial root finding. + +This function returns all roots of the polynomial + P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n +Both real and complex roots are returned (see below). + +INPUT PARAMETERS: + A - array[N+1], polynomial coefficients: + * A[0] is constant term + * A[N] is a coefficient of X^N + N - polynomial degree + +OUTPUT PARAMETERS: + X - array of complex roots: + * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 + * complex roots are always returned in pairs - roots occupy + positions I and I+1, with: + * X[I+1]=Conj(X[I]) + * IMAGE(X[I]) > 0 + * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 + * multiple real roots may have non-zero imaginary part due + to roundoff errors. There is no reliable way to distinguish + real root of multiplicity 2 from two complex roots in + the presence of roundoff errors. + Rep - report, additional information, following fields are set: + * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field + allows to quickly estimate "quality" of the roots being + returned. + +NOTE: this function uses companion matrix method to find roots. In case + internal EVD solver fails do find eigenvalues, exception is + generated. + +NOTE: roots are not "polished" and no matrix balancing is performed + for them. + + -- ALGLIB -- + Copyright 24.02.2014 by Bochkanov Sergey +*************************************************************************/ +void polynomialsolve(/* Real */ const ae_vector* _a, + ae_int_t n, + /* Complex */ ae_vector* x, + polynomialsolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector a; + ae_matrix c; + ae_matrix vl; + ae_matrix vr; + ae_vector wr; + ae_vector wi; + ae_int_t i; + ae_int_t j; + ae_bool status; + ae_int_t nz; + ae_int_t ne; + ae_complex v; + ae_complex vv; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&c, 0, sizeof(c)); + memset(&vl, 0, sizeof(vl)); + memset(&vr, 0, sizeof(vr)); + memset(&wr, 0, sizeof(wr)); + memset(&wi, 0, sizeof(wi)); + ae_vector_init_copy(&a, _a, _state, ae_true); + ae_vector_clear(x); + _polynomialsolverreport_clear(rep); + ae_matrix_init(&c, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vl, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vr, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&wi, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "PolynomialSolve: N<=0", _state); + ae_assert(a.cnt>=n+1, "PolynomialSolve: Length(A)0 ) + { + ae_matrix_set_length(&c, ne, ne, _state); + for(i=0; i<=ne-1; i++) + { + for(j=0; j<=ne-1; j++) + { + c.ptr.pp_double[i][j] = (double)(0); + } + } + c.ptr.pp_double[0][ne-1] = -a.ptr.p_double[0]; + for(i=1; i<=ne-1; i++) + { + c.ptr.pp_double[i][i-1] = (double)(1); + c.ptr.pp_double[i][ne-1] = -a.ptr.p_double[i]; + } + status = rmatrixevd(&c, ne, 0, &wr, &wi, &vl, &vr, _state); + ae_assert(status, "PolynomialSolve: inernal error - EVD solver failed", _state); + for(i=0; i<=ne-1; i++) + { + x->ptr.p_complex[i].x = wr.ptr.p_double[i]; + x->ptr.p_complex[i].y = wi.ptr.p_double[i]; + } + } + + /* + * Remaining NZ zero roots + */ + for(i=ne; i<=n-1; i++) + { + x->ptr.p_complex[i] = ae_complex_from_i(0); + } + + /* + * Rep + */ + rep->maxerr = (double)(0); + for(i=0; i<=ne-1; i++) + { + v = ae_complex_from_i(0); + vv = ae_complex_from_i(1); + for(j=0; j<=ne; j++) + { + v = ae_c_add(v,ae_c_mul_d(vv,a.ptr.p_double[j])); + vv = ae_c_mul(vv,x->ptr.p_complex[i]); + } + rep->maxerr = ae_maxreal(rep->maxerr, ae_c_abs(v, _state), _state); + } + ae_frame_leave(_state); +} + + +void _polynomialsolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + polynomialsolverreport *p = (polynomialsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _polynomialsolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + polynomialsolverreport *dst = (polynomialsolverreport*)_dst; + const polynomialsolverreport *src = (const polynomialsolverreport*)_src; + dst->maxerr = src->maxerr; +} + + +void _polynomialsolverreport_clear(void* _p) +{ + polynomialsolverreport *p = (polynomialsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _polynomialsolverreport_destroy(void* _p) +{ + polynomialsolverreport *p = (polynomialsolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and +b. This is "slow-but-feature rich" version of the linear solver. Faster +version is RMatrixSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It is also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixSolve: N<=0", _state); + ae_assert(a->rows>=n, "RMatrixSolve: rows(A)cols>=n, "RMatrixSolve: cols(A)cnt>=n, "RMatrixSolve: length(B) overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsolvefast(/* Real */ const ae_matrix* _a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_vector p; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&p, 0, sizeof(p)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "RMatrixSolveFast: N<=0", _state); + ae_assert(a.rows>=n, "RMatrixSolveFast: rows(A)=n, "RMatrixSolveFast: cols(A)cnt>=n, "RMatrixSolveFast: length(B)ptr.p_double[j] = 0.0; + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + directdensesolvers_rbasiclusolve(&a, &p, n, b, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "slow-but-robust" version of linear +solver with additional functionality like condition number estimation. +There also exists faster version - RMatrixSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + ae_bool rfs, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_matrix emptya; + ae_vector p; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&da, 0, sizeof(da)); + memset(&emptya, 0, sizeof(emptya)); + memset(&p, 0, sizeof(p)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "RMatrixSolveM: N<=0", _state); + ae_assert(m>0, "RMatrixSolveM: M<=0", _state); + ae_assert(a->rows>=n, "RMatrixSolveM: rows(A)cols>=n, "RMatrixSolveM: cols(A)rows>=n, "RMatrixSolveM: rows(B)cols>=m, "RMatrixSolveM: cols(B)ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + } + rmatrixlu(&da, n, n, &p, _state); + if( rfs ) + { + directdensesolvers_rmatrixlusolveinternal(&da, &p, n, a, ae_true, b, m, x, rep, _state); + } + else + { + directdensesolvers_rmatrixlusolveinternal(&da, &p, n, &emptya, ae_false, b, m, x, rep, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "fast" version of linear solver which +does NOT offer additional functions like condition number estimation or +iterative refinement. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional functionality, highest performance + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True for well-conditioned matrix + False for extremely badly conditioned or exactly singular problem + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixsolvemfast(/* Real */ const ae_matrix* _a, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + double v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector p; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&p, 0, sizeof(p)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "RMatrixSolveMFast: N<=0", _state); + ae_assert(m>0, "RMatrixSolveMFast: M<=0", _state); + ae_assert(a.rows>=n, "RMatrixSolveMFast: rows(A)=n, "RMatrixSolveMFast: cols(A)rows>=n, "RMatrixSolveMFast: rows(B)cols>=m, "RMatrixSolveMFast: cols(B)ptr.pp_double[j][k] = 0.0; + } + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + + /* + * Solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + if( p.ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = b->ptr.pp_double[i][j]; + b->ptr.pp_double[i][j] = b->ptr.pp_double[p.ptr.p_int[i]][j]; + b->ptr.pp_double[p.ptr.p_int[i]][j] = v; + } + } + } + rmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); + rmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "slow-but-robust" version of the linear LU-based solver. Faster version +is RMatrixLUSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixLUSolve: N<=0", _state); + ae_assert(lua->rows>=n, "RMatrixLUSolve: rows(LUA)cols>=n, "RMatrixLUSolve: cols(LUA)cnt>=n, "RMatrixLUSolve: length(P)cnt>=n, "RMatrixLUSolve: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i] overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixlusolvefast(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>0, "RMatrixLUSolveFast: N<=0", _state); + ae_assert(lua->rows>=n, "RMatrixLUSolveFast: rows(LUA)cols>=n, "RMatrixLUSolveFast: cols(LUA)cnt>=n, "RMatrixLUSolveFast: length(P)cnt>=n, "RMatrixLUSolveFast: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.pp_double[i][i],(double)(0)) ) + { + for(j=0; j<=n-1; j++) + { + b->ptr.p_double[j] = 0.0; + } + result = ae_false; + return result; + } + } + result = ae_true; + directdensesolvers_rbasiclusolve(lua, p, n, b, _state); + return result; +} + + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). This is "robust-but-slow" version of +LU-based solver which performs additional checks for non-degeneracy of +inputs (condition number estimation). If you need best performance, use +"fast-without-any-checks" version, RMatrixLUSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&emptya, 0, sizeof(emptya)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixLUSolveM: N<=0", _state); + ae_assert(m>0, "RMatrixLUSolveM: M<=0", _state); + ae_assert(lua->rows>=n, "RMatrixLUSolveM: rows(LUA)cols>=n, "RMatrixLUSolveM: cols(LUA)cnt>=n, "RMatrixLUSolveM: length(P)rows>=n, "RMatrixLUSolveM: rows(B)cols>=m, "RMatrixLUSolveM: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i] overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool rmatrixlusolvemfast(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + double v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + + + /* + * Check for exact degeneracy + */ + ae_assert(n>0, "RMatrixLUSolveMFast: N<=0", _state); + ae_assert(m>0, "RMatrixLUSolveMFast: M<=0", _state); + ae_assert(lua->rows>=n, "RMatrixLUSolveMFast: rows(LUA)cols>=n, "RMatrixLUSolveMFast: cols(LUA)cnt>=n, "RMatrixLUSolveMFast: length(P)rows>=n, "RMatrixLUSolveMFast: rows(B)cols>=m, "RMatrixLUSolveMFast: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.pp_double[i][i],(double)(0)) ) + { + for(j=0; j<=n-1; j++) + { + for(k=0; k<=m-1; k++) + { + b->ptr.pp_double[j][k] = 0.0; + } + } + result = ae_false; + return result; + } + } + result = ae_true; + + /* + * Solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = b->ptr.pp_double[i][j]; + b->ptr.pp_double[i][j] = b->ptr.pp_double[p->ptr.p_int[i]][j]; + b->ptr.pp_double[p->ptr.p_int[i]][j] = v; + } + } + } + rmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); + rmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + return result; +} + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "RMatrixMixedSolve: N<=0", _state); + ae_assert(a->rows>=n, "RMatrixMixedSolve: rows(A)cols>=n, "RMatrixMixedSolve: cols(A)rows>=n, "RMatrixMixedSolve: rows(LUA)cols>=n, "RMatrixMixedSolve: cols(LUA)cnt>=n, "RMatrixMixedSolve: length(P)cnt>=n, "RMatrixMixedSolve: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_int_t i; + + ae_matrix_clear(x); + _densesolverreport_clear(rep); + + ae_assert(n>0, "RMatrixMixedSolveM: N<=0", _state); + ae_assert(m>0, "RMatrixMixedSolveM: M<=0", _state); + ae_assert(a->rows>=n, "RMatrixMixedSolve: rows(A)cols>=n, "RMatrixMixedSolve: cols(A)rows>=n, "RMatrixMixedSolve: rows(LUA)cols>=n, "RMatrixMixedSolve: cols(LUA)cnt>=n, "RMatrixMixedSolve: length(P)rows>=n, "RMatrixMixedSolve: rows(B)cols>=m, "RMatrixMixedSolve: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(/* Complex */ const ae_matrix* a, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + ae_bool rfs, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_matrix emptya; + ae_vector p; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&da, 0, sizeof(da)); + memset(&emptya, 0, sizeof(emptya)); + memset(&p, 0, sizeof(p)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "CMatrixSolveM: N<=0", _state); + ae_assert(m>0, "CMatrixSolveM: M<=0", _state); + ae_assert(a->rows>=n, "CMatrixSolveM: rows(A)cols>=n, "CMatrixSolveM: cols(A)rows>=n, "CMatrixSolveM: rows(B)cols>=m, "CMatrixSolveM: cols(B)ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); + } + cmatrixlu(&da, n, n, &p, _state); + if( rfs ) + { + directdensesolvers_cmatrixlusolveinternal(&da, &p, n, a, ae_true, b, m, x, rep, _state); + } + else + { + directdensesolvers_cmatrixlusolveinternal(&da, &p, n, &emptya, ae_false, b, m, x, rep, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Fast-but-lightweight" version which provides just +triangular solver - and no additional functions like iterative refinement +or condition number estimation. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixsolvemfast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_complex v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_vector p; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&p, 0, sizeof(p)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "CMatrixSolveMFast: N<=0", _state); + ae_assert(m>0, "CMatrixSolveMFast: M<=0", _state); + ae_assert(a.rows>=n, "CMatrixSolveMFast: rows(A)=n, "CMatrixSolveMFast: cols(A)rows>=n, "CMatrixSolveMFast: rows(B)cols>=m, "CMatrixSolveMFast: cols(B)ptr.pp_complex[j][k] = ae_complex_from_d(0.0); + } + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + result = ae_true; + + /* + * Solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + if( p.ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = b->ptr.pp_complex[i][j]; + b->ptr.pp_complex[i][j] = b->ptr.pp_complex[p.ptr.p_int[i]][j]; + b->ptr.pp_complex[p.ptr.p_int[i]][j] = v; + } + } + } + cmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); + cmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(/* Complex */ const ae_matrix* a, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixSolve: N<=0", _state); + ae_assert(a->rows>=n, "CMatrixSolve: rows(A)cols>=n, "CMatrixSolve: cols(A)cnt>=n, "CMatrixSolve: length(B)ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixsolvem(a, n, &bm, 1, ae_true, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3) complexity +* no additional time consuming features, just triangular solver + +INPUT PARAMETERS: + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixsolvefast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_vector p; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&p, 0, sizeof(p)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + + ae_assert(n>0, "CMatrixSolveFast: N<=0", _state); + ae_assert(a.rows>=n, "CMatrixSolveFast: rows(A)=n, "CMatrixSolveFast: cols(A)cnt>=n, "CMatrixSolveFast: length(B)ptr.p_complex[j] = ae_complex_from_d(0.0); + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + } + directdensesolvers_cbasiclusolve(&a, &p, n, b, _state); + result = ae_true; + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" +version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&emptya, 0, sizeof(emptya)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixLUSolveM: N<=0", _state); + ae_assert(m>0, "CMatrixLUSolveM: M<=0", _state); + ae_assert(lua->rows>=n, "CMatrixLUSolveM: rows(LUA)cols>=n, "CMatrixLUSolveM: cols(LUA)cnt>=n, "CMatrixLUSolveM: length(P)rows>=n, "CMatrixLUSolveM: rows(B)cols>=m, "CMatrixLUSolveM: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i] overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixlusolvemfast(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_complex v; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + + ae_assert(n>0, "CMatrixLUSolveMFast: N<=0", _state); + ae_assert(m>0, "CMatrixLUSolveMFast: M<=0", _state); + ae_assert(lua->rows>=n, "CMatrixLUSolveMFast: rows(LUA)cols>=n, "CMatrixLUSolveMFast: cols(LUA)cnt>=n, "CMatrixLUSolveMFast: length(P)rows>=n, "CMatrixLUSolveMFast: rows(B)cols>=m, "CMatrixLUSolveMFast: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.pp_complex[i][i],(double)(0)) ) + { + for(j=0; j<=n-1; j++) + { + for(k=0; k<=m-1; k++) + { + b->ptr.pp_complex[j][k] = ae_complex_from_d(0.0); + } + } + result = ae_false; + return result; + } + } + result = ae_true; + + /* + * Solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = b->ptr.pp_complex[i][j]; + b->ptr.pp_complex[i][j] = b->ptr.pp_complex[p->ptr.p_int[i]][j]; + b->ptr.pp_complex[p->ptr.p_int[i]][j] = v; + } + } + } + cmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, b, 0, 0, _state); + cmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + return result; +} + + +/************************************************************************* +Complex dense linear solver for A*x=b with complex N*N A given by its LU +decomposition and N*1 vectors x and b. This is "slow-but-robust" version +of the complex linear solver with additional features which add +significant performance overhead. Faster version is CMatrixLUSolveFast() +function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixLUSolve: N<=0", _state); + ae_assert(lua->rows>=n, "CMatrixLUSolve: rows(LUA)cols>=n, "CMatrixLUSolve: cols(LUA)cnt>=n, "CMatrixLUSolve: length(P)cnt>=n, "CMatrixLUSolve: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixlusolvem(lua, p, n, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Complex dense linear solver for A*x=b with N*N complex A given by its LU +decomposition and N*1 vectors x and b. This is fast lightweight version +of solver, which is significantly faster than CMatrixLUSolve(), but does +not provide additional information (like condition numbers). + +Algorithm features: +* O(N^2) complexity +* no additional time-consuming features, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +NOTE: unlike CMatrixLUSolve(), this function does NOT check for + near-degeneracy of input matrix. It checks for EXACT degeneracy, + because this check is easy to do. However, very badly conditioned + matrices may went unnoticed. + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool cmatrixlusolvefast(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_bool result; + + + ae_assert(n>0, "CMatrixLUSolveFast: N<=0", _state); + ae_assert(lua->rows>=n, "CMatrixLUSolveFast: rows(LUA)cols>=n, "CMatrixLUSolveFast: cols(LUA)cnt>=n, "CMatrixLUSolveFast: length(P)cnt>=n, "CMatrixLUSolveFast: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.pp_complex[i][i],(double)(0)) ) + { + for(j=0; j<=n-1; j++) + { + b->ptr.p_complex[j] = ae_complex_from_d(0.0); + } + result = ae_false; + return result; + } + } + directdensesolvers_cbasiclusolve(lua, p, n, b, _state); + result = ae_true; + return result; +} + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(/* Complex */ const ae_matrix* a, + /* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_int_t i; + + ae_matrix_clear(x); + _densesolverreport_clear(rep); + + ae_assert(n>0, "CMatrixMixedSolveM: N<=0", _state); + ae_assert(m>0, "CMatrixMixedSolveM: M<=0", _state); + ae_assert(a->rows>=n, "CMatrixMixedSolveM: rows(A)cols>=n, "CMatrixMixedSolveM: cols(A)rows>=n, "CMatrixMixedSolveM: rows(LUA)cols>=n, "CMatrixMixedSolveM: cols(LUA)cnt>=n, "CMatrixMixedSolveM: length(P)rows>=n, "CMatrixMixedSolveM: rows(B)cols>=m, "CMatrixMixedSolveM: cols(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(/* Complex */ const ae_matrix* a, + /* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "CMatrixMixedSolve: N<=0", _state); + ae_assert(a->rows>=n, "CMatrixMixedSolve: rows(A)cols>=n, "CMatrixMixedSolve: cols(A)rows>=n, "CMatrixMixedSolve: rows(LUA)cols>=n, "CMatrixMixedSolve: cols(LUA)cnt>=n, "CMatrixMixedSolve: length(P)cnt>=n, "CMatrixMixedSolve: length(B)ptr.p_int[i]>=0&&p->ptr.p_int[i]ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + cmatrixmixedsolvem(a, lua, p, n, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&da, 0, sizeof(da)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&da, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixSolveM: N<=0", _state); + ae_assert(m>0, "SPDMatrixSolveM: M<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixSolveM: rows(A)cols>=n, "SPDMatrixSolveM: cols(A)rows>=n, "SPDMatrixSolveM: rows(B)cols>=m, "SPDMatrixSolveM: cols(B)ptr.pp_double[i][j1], 1, ae_v_len(j1,j2)); + } + if( !spdmatrixcholesky(&da, n, isupper, _state) ) + { + ae_matrix_set_length(x, n, m, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = (double)(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + rep->terminationtype = 1; + directdensesolvers_spdmatrixcholeskysolveinternal(&da, n, isupper, a, ae_true, b, m, x, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixsolvemfast(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>0, "SPDMatrixSolveMFast: N<=0", _state); + ae_assert(a.rows>=n, "SPDMatrixSolveMFast: rows(A)=n, "SPDMatrixSolveMFast: cols(A)rows>=n, "SPDMatrixSolveMFast: rows(B)cols>=m, "SPDMatrixSolveMFast: cols(B)ptr.pp_double[i][j] = 0.0; + } + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( isupper ) + { + rmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 1, b, 0, 0, _state); + rmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + } + else + { + rmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); + rmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_false, 1, b, 0, 0, _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixSolve: N<=0", _state); + ae_assert(a->rows>=n, "SPDMatrixSolve: rows(A)cols>=n, "SPDMatrixSolve: cols(A)cnt>=n, "SPDMatrixSolve: length(B)ptr.p_double[0], 1, ae_v_len(0,n-1)); + spdmatrixsolvem(a, n, isupper, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the +solver. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixsolvefast(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>0, "SPDMatrixSolveFast: N<=0", _state); + ae_assert(a.rows>=n, "SPDMatrixSolveFast: rows(A)=n, "SPDMatrixSolveFast: cols(A)cnt>=n, "SPDMatrixSolveFast: length(B)ptr.p_double[i] = 0.0; + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + directdensesolvers_spdbasiccholeskysolve(&a, n, isupper, b, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- +feature-rich" version of the solver which estimates condition number of +the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveMFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + + ae_frame_make(_state, &_frame_block); + memset(&emptya, 0, sizeof(emptya)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&emptya, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixCholeskySolveM: N<=0", _state); + ae_assert(m>0, "SPDMatrixCholeskySolveM: M<=0", _state); + ae_assert(cha->rows>=n, "SPDMatrixCholeskySolveM: rows(CHA)cols>=n, "SPDMatrixCholeskySolveM: cols(CHA)rows>=n, "SPDMatrixCholeskySolveM: rows(B)cols>=m, "SPDMatrixCholeskySolveM: cols(B) overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixcholeskysolvemfast(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + + ae_assert(n>0, "SPDMatrixCholeskySolveMFast: N<=0", _state); + ae_assert(m>0, "SPDMatrixCholeskySolveMFast: M<=0", _state); + ae_assert(cha->rows>=n, "SPDMatrixCholeskySolveMFast: rows(CHA)cols>=n, "SPDMatrixCholeskySolveMFast: cols(CHA)rows>=n, "SPDMatrixCholeskySolveMFast: rows(B)cols>=m, "SPDMatrixCholeskySolveMFast: cols(B)ptr.pp_double[k][k],0.0) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + b->ptr.pp_double[i][j] = 0.0; + } + } + result = ae_false; + return result; + } + } + if( isupper ) + { + rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 1, b, 0, 0, _state); + rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + } + else + { + rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); + rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 1, b, 0, 0, _state); + } + return result; +} + + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- +but-feature-rich" version of the solver which, in addition to the +solution, performs condition number estimation. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_REAL, _state, ae_true); + + ae_assert(n>0, "SPDMatrixCholeskySolve: N<=0", _state); + ae_assert(cha->rows>=n, "SPDMatrixCholeskySolve: rows(CHA)cols>=n, "SPDMatrixCholeskySolve: cols(CHA)cnt>=n, "SPDMatrixCholeskySolve: length(B)ptr.p_double[0], 1, ae_v_len(0,n-1)); + spdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_move(&x->ptr.p_double[0], 1, &xm.ptr.pp_double[0][0], xm.stride, ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- +but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +ae_bool spdmatrixcholeskysolvefast(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_bool result; + + + ae_assert(n>0, "SPDMatrixCholeskySolveFast: N<=0", _state); + ae_assert(cha->rows>=n, "SPDMatrixCholeskySolveFast: rows(CHA)cols>=n, "SPDMatrixCholeskySolveFast: cols(CHA)cnt>=n, "SPDMatrixCholeskySolveFast: length(B)ptr.pp_double[k][k],0.0) ) + { + for(i=0; i<=n-1; i++) + { + b->ptr.p_double[i] = 0.0; + } + result = ae_false; + return result; + } + } + directdensesolvers_spdbasiccholeskysolve(cha, n, isupper, b, _state); + return result; +} + + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems (N<100). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix da; + ae_int_t i; + ae_int_t j; + ae_int_t j1; + ae_int_t j2; + + ae_frame_make(_state, &_frame_block); + memset(&da, 0, sizeof(da)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&da, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "HPDMatrixSolveM: N<=0", _state); + ae_assert(m>0, "HPDMatrixSolveM: M<=0", _state); + ae_assert(a->rows>=n, "HPDMatrixSolveM: rows(A)cols>=n, "HPDMatrixSolveM: cols(A)rows>=n, "HPDMatrixSolveM: rows(B)cols>=m, "HPDMatrixSolveM: cols(B)ptr.pp_complex[i][j1], 1, "N", ae_v_len(j1,j2)); + } + if( !hpdmatrixcholesky(&da, n, isupper, _state) ) + { + ae_matrix_set_length(x, n, m, _state); + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + rep->terminationtype = 1; + directdensesolvers_hpdmatrixcholeskysolveinternal(&da, n, isupper, a, ae_true, b, m, x, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool hpdmatrixsolvemfast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_int_t j; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>0, "HPDMatrixSolveMFast: N<=0", _state); + ae_assert(a.rows>=n, "HPDMatrixSolveMFast: rows(A)=n, "HPDMatrixSolveMFast: cols(A)rows>=n, "HPDMatrixSolveMFast: rows(B)cols>=m, "HPDMatrixSolveMFast: cols(B)ptr.pp_complex[i][j] = ae_complex_from_d(0.0); + } + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + if( isupper ) + { + cmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 2, b, 0, 0, _state); + cmatrixlefttrsm(n, m, &a, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + } + else + { + cmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); + cmatrixlefttrsm(n, m, &a, 0, 0, ae_false, ae_false, 2, b, 0, 0, _state); + } + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, HPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "HPDMatrixSolve: N<=0", _state); + ae_assert(a->rows>=n, "HPDMatrixSolve: rows(A)cols>=n, "HPDMatrixSolve: cols(A)cnt>=n, "HPDMatrixSolve: length(B)ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + hpdmatrixsolvem(a, n, isupper, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Fast-but-lightweight" version of the +solver without additional functions. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool hpdmatrixsolvefast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix a; + ae_int_t i; + ae_bool result; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + ae_matrix_init_copy(&a, _a, _state, ae_true); + + ae_assert(n>0, "HPDMatrixSolveFast: N<=0", _state); + ae_assert(a.rows>=n, "HPDMatrixSolveFast: rows(A)=n, "HPDMatrixSolveFast: cols(A)cnt>=n, "HPDMatrixSolveFast: length(B)ptr.p_complex[i] = ae_complex_from_d(0.0); + } + result = ae_false; + ae_frame_leave(_state); + return result; + } + directdensesolvers_hpdbasiccholeskysolve(&a, n, isupper, b, _state); + ae_frame_leave(_state); + return result; +} + + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"slow-but-feature-rich" version of the solver which, in addition to the +solution, estimates condition number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large Cholesky decomposition. However, if you call + ! this function many times for the same left side, this + ! overhead BECOMES significant. It also becomes significant + ! for small-scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveMFast() function. + + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix emptya; + + ae_frame_make(_state, &_frame_block); + memset(&emptya, 0, sizeof(emptya)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&emptya, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "HPDMatrixCholeskySolveM: N<=0", _state); + ae_assert(m>0, "HPDMatrixCholeskySolveM: M<=0", _state); + ae_assert(cha->rows>=n, "HPDMatrixCholeskySolveM: rows(CHA)cols>=n, "HPDMatrixCholeskySolveM: cols(CHA)rows>=n, "HPDMatrixCholeskySolveM: rows(B)cols>=m, "HPDMatrixCholeskySolveM: cols(B) overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool hpdmatrixcholeskysolvemfast(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_bool result; + + + ae_assert(n>0, "HPDMatrixCholeskySolveMFast: N<=0", _state); + ae_assert(m>0, "HPDMatrixCholeskySolveMFast: M<=0", _state); + ae_assert(cha->rows>=n, "HPDMatrixCholeskySolveMFast: rows(CHA)cols>=n, "HPDMatrixCholeskySolveMFast: cols(CHA)rows>=n, "HPDMatrixCholeskySolveMFast: rows(B)cols>=m, "HPDMatrixCholeskySolveMFast: cols(B)ptr.pp_complex[k][k].x,0.0)&&ae_fp_eq(cha->ptr.pp_complex[k][k].y,0.0) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + b->ptr.pp_complex[i][j] = ae_complex_from_d(0.0); + } + } + result = ae_false; + return result; + } + } + if( isupper ) + { + cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 2, b, 0, 0, _state); + cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, b, 0, 0, _state); + } + else + { + cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, b, 0, 0, _state); + cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 2, b, 0, 0, _state); + } + return result; +} + + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"slow-but-feature-rich" version of the solver which estimates condition +number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix bm; + ae_matrix xm; + + ae_frame_make(_state, &_frame_block); + memset(&bm, 0, sizeof(bm)); + memset(&xm, 0, sizeof(xm)); + ae_vector_clear(x); + _densesolverreport_clear(rep); + ae_matrix_init(&bm, 0, 0, DT_COMPLEX, _state, ae_true); + ae_matrix_init(&xm, 0, 0, DT_COMPLEX, _state, ae_true); + + ae_assert(n>0, "HPDMatrixCholeskySolve: N<=0", _state); + ae_assert(cha->rows>=n, "HPDMatrixCholeskySolve: rows(CHA)cols>=n, "HPDMatrixCholeskySolve: cols(CHA)cnt>=n, "HPDMatrixCholeskySolve: length(B)ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + hpdmatrixcholeskysolvem(cha, n, isupper, &bm, 1, &xm, rep, _state); + ae_vector_set_length(x, n, _state); + ae_v_cmove(&x->ptr.p_complex[0], 1, &xm.ptr.pp_complex[0][0], xm.stride, "N", ae_v_len(0,n-1)); + ae_frame_leave(_state); +} + + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +ae_bool hpdmatrixcholeskysolvefast(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + ae_bool result; + + + ae_assert(n>0, "HPDMatrixCholeskySolveFast: N<=0", _state); + ae_assert(cha->rows>=n, "HPDMatrixCholeskySolveFast: rows(CHA)cols>=n, "HPDMatrixCholeskySolveFast: cols(CHA)cnt>=n, "HPDMatrixCholeskySolveFast: length(B)ptr.pp_complex[k][k].x,0.0)&&ae_fp_eq(cha->ptr.pp_complex[k][k].y,0.0) ) + { + for(i=0; i<=n-1; i++) + { + b->ptr.p_complex[i] = ae_complex_from_d(0.0); + } + result = ae_false; + return result; + } + } + directdensesolvers_hpdbasiccholeskysolve(cha, n, isupper, b, _state); + return result; +} + + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned. + +Algorithm features: +* automatic detection (and correct handling!) of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold*Largest are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B (even for singular A) + * zeros, if SVD subroutine failed + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* TerminationType is set to: + * -4 for SVD failure + * >0 for success +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(/* Real */ const ae_matrix* a, + ae_int_t nrows, + ae_int_t ncols, + /* Real */ const ae_vector* b, + double threshold, + /* Real */ ae_vector* x, + densesolverlsreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector sv; + ae_matrix u; + ae_matrix vt; + ae_vector rp; + ae_vector utb; + ae_vector sutb; + ae_vector tmp; + ae_vector ta; + ae_vector tx; + ae_vector buf; + ae_vector w; + ae_int_t i; + ae_int_t j; + ae_int_t nsv; + ae_int_t kernelidx; + double v; + double verr; + ae_bool svdfailed; + ae_bool zeroa; + ae_int_t rfs; + ae_int_t nrfs; + ae_bool terminatenexttime; + ae_bool smallerr; + + ae_frame_make(_state, &_frame_block); + memset(&sv, 0, sizeof(sv)); + memset(&u, 0, sizeof(u)); + memset(&vt, 0, sizeof(vt)); + memset(&rp, 0, sizeof(rp)); + memset(&utb, 0, sizeof(utb)); + memset(&sutb, 0, sizeof(sutb)); + memset(&tmp, 0, sizeof(tmp)); + memset(&ta, 0, sizeof(ta)); + memset(&tx, 0, sizeof(tx)); + memset(&buf, 0, sizeof(buf)); + memset(&w, 0, sizeof(w)); + ae_vector_clear(x); + _densesolverlsreport_clear(rep); + ae_vector_init(&sv, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&rp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&utb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true); + ae_vector_init(&ta, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&buf, 0, DT_REAL, _state, ae_true); + ae_vector_init(&w, 0, DT_REAL, _state, ae_true); + + ae_assert(nrows>0, "RMatrixSolveLS: NRows<=0", _state); + ae_assert(ncols>0, "RMatrixSolveLS: NCols<=0", _state); + ae_assert(ae_isfinite(threshold, _state)&&ae_fp_greater_eq(threshold,(double)(0)), "RMatrixSolveLS: Threshold<0 or is infinite", _state); + ae_assert(a->rows>=nrows, "RMatrixSolveLS: rows(A)cols>=ncols, "RMatrixSolveLS: cols(A)cnt>=nrows, "RMatrixSolveLS: length(B)terminationtype = -4; + } + else + { + rep->terminationtype = 1; + } + ae_vector_set_length(x, ncols, _state); + for(i=0; i<=ncols-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + rep->n = ncols; + rep->k = ncols; + ae_matrix_set_length(&rep->cx, ncols, ncols, _state); + for(i=0; i<=ncols-1; i++) + { + for(j=0; j<=ncols-1; j++) + { + if( i==j ) + { + rep->cx.ptr.pp_double[i][j] = (double)(1); + } + else + { + rep->cx.ptr.pp_double[i][j] = (double)(0); + } + } + } + rep->r2 = (double)(0); + ae_frame_leave(_state); + return; + } + nsv = ae_minint(ncols, nrows, _state); + if( nsv==ncols ) + { + rep->r2 = sv.ptr.p_double[nsv-1]/sv.ptr.p_double[0]; + } + else + { + rep->r2 = (double)(0); + } + rep->n = ncols; + rep->terminationtype = 1; + + /* + * Iterative refinement of xc combined with solution: + * 1. xc = 0 + * 2. calculate r = bc-A*xc using extra-precise dot product + * 3. solve A*y = r + * 4. update x:=x+r + * 5. goto 2 + * + * This cycle is executed until one of two things happens: + * 1. maximum number of iterations reached + * 2. last iteration decreased error to the lower limit + */ + ae_vector_set_length(&utb, nsv, _state); + ae_vector_set_length(&sutb, nsv, _state); + ae_vector_set_length(x, ncols, _state); + ae_vector_set_length(&tmp, ncols, _state); + ae_vector_set_length(&ta, ncols+1, _state); + ae_vector_set_length(&tx, ncols+1, _state); + ae_vector_set_length(&buf, ncols+1, _state); + for(i=0; i<=ncols-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + kernelidx = nsv; + for(i=0; i<=nsv-1; i++) + { + if( ae_fp_less_eq(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) ) + { + kernelidx = i; + break; + } + } + rep->k = ncols-kernelidx; + nrfs = directdensesolvers_densesolverrfsmaxv2(ncols, rep->r2, _state); + terminatenexttime = ae_false; + ae_vector_set_length(&rp, nrows, _state); + for(rfs=0; rfs<=nrfs; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * calculate right part + */ + if( rfs==0 ) + { + ae_v_move(&rp.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,nrows-1)); + } + else + { + smallerr = ae_true; + for(i=0; i<=nrows-1; i++) + { + ae_v_move(&ta.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,ncols-1)); + ta.ptr.p_double[ncols] = (double)(-1); + ae_v_move(&tx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,ncols-1)); + tx.ptr.p_double[ncols] = b->ptr.p_double[i]; + xdot(&ta, &tx, ncols+1, &buf, &v, &verr, _state); + rp.ptr.p_double[i] = -v; + smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),(double)4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + } + + /* + * solve A*dx = rp + */ + for(i=0; i<=ncols-1; i++) + { + tmp.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nsv-1; i++) + { + utb.ptr.p_double[i] = (double)(0); + } + for(i=0; i<=nrows-1; i++) + { + v = rp.ptr.p_double[i]; + ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,nsv-1), v); + } + for(i=0; i<=nsv-1; i++) + { + if( iptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,ncols-1)); + } + + /* + * fill CX + */ + if( rep->k>0 ) + { + ae_matrix_set_length(&rep->cx, ncols, rep->k, _state); + for(i=0; i<=rep->k-1; i++) + { + ae_v_move(&rep->cx.ptr.pp_double[0][i], rep->cx.stride, &vt.ptr.pp_double[kernelidx+i][0], 1, ae_v_len(0,ncols-1)); + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal LU solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_rmatrixlusolveinternal(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* a, + ae_bool havea, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t rfs; + ae_int_t nrfs; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + double v; + double verr; + double mxb; + ae_bool smallerr; + ae_bool terminatenexttime; + + ae_frame_make(_state, &_frame_block); + memset(&xc, 0, sizeof(xc)); + memset(&y, 0, sizeof(y)); + memset(&bc, 0, sizeof(bc)); + memset(&xa, 0, sizeof(xa)); + memset(&xb, 0, sizeof(xb)); + memset(&tx, 0, sizeof(tx)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_vector_init(&xc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + ae_vector_init(&bc, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xa, 0, DT_REAL, _state, ae_true); + ae_vector_init(&xb, 0, DT_REAL, _state, ae_true); + ae_vector_init(&tx, 0, DT_REAL, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + ae_assert(n>0&&m>0, "RMatrixLUSolveInternal: integrity check 7656 failed", _state); + for(i=0; i<=n-1; i++) + { + ae_assert(p->ptr.p_int[i]<=n-1&&p->ptr.p_int[i]>=i, "RMatrixLUSolveInternal: incorrect pivot, P[i]=N", _state); + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n+1, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = rmatrixlurcond1(lua, n, _state); + rep->rinf = rmatrixlurcondinf(lua, n, _state); + rep->terminationtype = 1; + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = (double)(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * First stage of solution: rough solution with TRSM() + */ + mxb = 0.0; + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + v = b->ptr.pp_double[i][j]; + mxb = ae_maxreal(mxb, ae_fabs(v, _state), _state); + x->ptr.pp_double[i][j] = v; + } + } + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = x->ptr.pp_double[i][j]; + x->ptr.pp_double[i][j] = x->ptr.pp_double[p->ptr.p_int[i]][j]; + x->ptr.pp_double[p->ptr.p_int[i]][j] = v; + } + } + } + rmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, x, 0, 0, _state); + rmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); + + /* + * Second stage: iterative refinement + */ + if( havea ) + { + for(k=0; k<=m-1; k++) + { + nrfs = directdensesolvers_densesolverrfsmax(n, rep->r1, rep->rinf, _state); + terminatenexttime = ae_false; + for(rfs=0; rfs<=nrfs-1; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * generate right part + */ + smallerr = ae_true; + ae_v_move(&xb.ptr.p_double[0], 1, &x->ptr.pp_double[0][k], x->stride, ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_move(&xa.ptr.p_double[0], 1, &a->ptr.pp_double[i][0], 1, ae_v_len(0,n-1)); + xa.ptr.p_double[n] = (double)(-1); + xb.ptr.p_double[n] = b->ptr.pp_double[i][k]; + xdot(&xa, &xb, n+1, &tx, &v, &verr, _state); + y.ptr.p_double[i] = -v; + smallerr = smallerr&&ae_fp_less(ae_fabs(v, _state),(double)4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + + /* + * solve and update + */ + directdensesolvers_rbasiclusolve(lua, p, n, &y, _state); + ae_v_add(&x->ptr.pp_double[0][k], x->stride, &y.ptr.p_double[0], 1, ae_v_len(0,n-1)); + } + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal Cholesky solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_spdmatrixcholeskysolveinternal(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* a, + ae_bool havea, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + + ae_matrix_clear(x); + _densesolverreport_clear(rep); + + + /* + * prepare: check inputs, allocate space... + */ + ae_assert(n>0&&m>0, "SPDMatrixCholeskySolveInternal: integrity check 9858 failed", _state); + ae_matrix_set_length(x, n, m, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = spdmatrixcholeskyrcond(cha, n, isupper, _state); + rep->rinf = rep->r1; + rep->terminationtype = 1; + if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = (double)(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + return; + } + + /* + * Solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_double[i][j] = b->ptr.pp_double[i][j]; + } + } + if( isupper ) + { + rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 1, x, 0, 0, _state); + rmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); + } + else + { + rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, x, 0, 0, _state); + rmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 1, x, 0, 0, _state); + } +} + + +/************************************************************************* +Internal LU solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_cmatrixlusolveinternal(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* a, + ae_bool havea, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t rfs; + ae_int_t nrfs; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + ae_vector tmpbuf; + ae_complex v; + double verr; + ae_bool smallerr; + ae_bool terminatenexttime; + + ae_frame_make(_state, &_frame_block); + memset(&xc, 0, sizeof(xc)); + memset(&y, 0, sizeof(y)); + memset(&bc, 0, sizeof(bc)); + memset(&xa, 0, sizeof(xa)); + memset(&xb, 0, sizeof(xb)); + memset(&tx, 0, sizeof(tx)); + memset(&tmpbuf, 0, sizeof(tmpbuf)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tmpbuf, 0, DT_REAL, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + ae_assert(n>0&&m>0, "CMatrixLUSolveInternal: integrity check 9302 failed", _state); + for(i=0; i<=n-1; i++) + { + ae_assert(p->ptr.p_int[i]<=n-1&&p->ptr.p_int[i]>=i, "CMatrixLUSolveInternal: incorrect pivot P[i]=N", _state); + } + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + ae_vector_set_length(&tmpbuf, 2*n+2, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = cmatrixlurcond1(lua, n, _state); + rep->rinf = cmatrixlurcondinf(lua, n, _state); + rep->terminationtype = 1; + if( ae_fp_less(rep->r1,rcondthreshold(_state))||ae_fp_less(rep->rinf,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * First phase: solve with TRSM() + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = b->ptr.pp_complex[i][j]; + } + } + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + for(j=0; j<=m-1; j++) + { + v = x->ptr.pp_complex[i][j]; + x->ptr.pp_complex[i][j] = x->ptr.pp_complex[p->ptr.p_int[i]][j]; + x->ptr.pp_complex[p->ptr.p_int[i]][j] = v; + } + } + } + cmatrixlefttrsm(n, m, lua, 0, 0, ae_false, ae_true, 0, x, 0, 0, _state); + cmatrixlefttrsm(n, m, lua, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); + + /* + * solve + */ + for(k=0; k<=m-1; k++) + { + ae_v_cmove(&bc.ptr.p_complex[0], 1, &b->ptr.pp_complex[0][k], b->stride, "N", ae_v_len(0,n-1)); + ae_v_cmove(&xc.ptr.p_complex[0], 1, &x->ptr.pp_complex[0][k], x->stride, "N", ae_v_len(0,n-1)); + + /* + * Iterative refinement of xc: + * * calculate r = bc-A*xc using extra-precise dot product + * * solve A*y = r + * * update x:=x+r + * + * This cycle is executed until one of two things happens: + * 1. maximum number of iterations reached + * 2. last iteration decreased error to the lower limit + */ + if( havea ) + { + nrfs = directdensesolvers_densesolverrfsmax(n, rep->r1, rep->rinf, _state); + terminatenexttime = ae_false; + for(rfs=0; rfs<=nrfs-1; rfs++) + { + if( terminatenexttime ) + { + break; + } + + /* + * generate right part + */ + smallerr = ae_true; + ae_v_cmove(&xb.ptr.p_complex[0], 1, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + for(i=0; i<=n-1; i++) + { + ae_v_cmove(&xa.ptr.p_complex[0], 1, &a->ptr.pp_complex[i][0], 1, "N", ae_v_len(0,n-1)); + xa.ptr.p_complex[n] = ae_complex_from_i(-1); + xb.ptr.p_complex[n] = bc.ptr.p_complex[i]; + xcdot(&xa, &xb, n+1, &tmpbuf, &v, &verr, _state); + y.ptr.p_complex[i] = ae_c_neg(v); + smallerr = smallerr&&ae_fp_less(ae_c_abs(v, _state),(double)4*verr); + } + if( smallerr ) + { + terminatenexttime = ae_true; + } + + /* + * solve and update + */ + directdensesolvers_cbasiclusolve(lua, p, n, &y, _state); + ae_v_cadd(&xc.ptr.p_complex[0], 1, &y.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + } + } + + /* + * Store xc. + * Post-scale result. + */ + ae_v_cmove(&x->ptr.pp_complex[0][k], x->stride, &xc.ptr.p_complex[0], 1, "N", ae_v_len(0,n-1)); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal Cholesky solver + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_hpdmatrixcholeskysolveinternal(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* a, + ae_bool havea, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_vector xc; + ae_vector y; + ae_vector bc; + ae_vector xa; + ae_vector xb; + ae_vector tx; + + ae_frame_make(_state, &_frame_block); + memset(&xc, 0, sizeof(xc)); + memset(&y, 0, sizeof(y)); + memset(&bc, 0, sizeof(bc)); + memset(&xa, 0, sizeof(xa)); + memset(&xb, 0, sizeof(xb)); + memset(&tx, 0, sizeof(tx)); + ae_matrix_clear(x); + _densesolverreport_clear(rep); + ae_vector_init(&xc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&y, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&bc, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xa, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&xb, 0, DT_COMPLEX, _state, ae_true); + ae_vector_init(&tx, 0, DT_COMPLEX, _state, ae_true); + + + /* + * prepare: check inputs, allocate space... + */ + ae_matrix_set_length(x, n, m, _state); + ae_vector_set_length(&y, n, _state); + ae_vector_set_length(&xc, n, _state); + ae_vector_set_length(&bc, n, _state); + ae_vector_set_length(&tx, n+1, _state); + ae_vector_set_length(&xa, n+1, _state); + ae_vector_set_length(&xb, n+1, _state); + + /* + * estimate condition number, test for near singularity + */ + rep->r1 = hpdmatrixcholeskyrcond(cha, n, isupper, _state); + rep->rinf = rep->r1; + rep->terminationtype = 1; + if( ae_fp_less(rep->r1,rcondthreshold(_state)) ) + { + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = ae_complex_from_i(0); + } + } + rep->r1 = (double)(0); + rep->rinf = (double)(0); + rep->terminationtype = -3; + ae_frame_leave(_state); + return; + } + + /* + * solve + */ + for(i=0; i<=n-1; i++) + { + for(j=0; j<=m-1; j++) + { + x->ptr.pp_complex[i][j] = b->ptr.pp_complex[i][j]; + } + } + if( isupper ) + { + cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 2, x, 0, 0, _state); + cmatrixlefttrsm(n, m, cha, 0, 0, ae_true, ae_false, 0, x, 0, 0, _state); + } + else + { + cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 0, x, 0, 0, _state); + cmatrixlefttrsm(n, m, cha, 0, 0, ae_false, ae_false, 2, x, 0, 0, _state); + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Internal subroutine. +Returns maximum count of RFS iterations as function of: +1. machine epsilon +2. task size. +3. condition number + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t directdensesolvers_densesolverrfsmax(ae_int_t n, + double r1, + double rinf, + ae_state *_state) +{ + ae_int_t result; + + + result = 5; + return result; +} + + +/************************************************************************* +Internal subroutine. +Returns maximum count of RFS iterations as function of: +1. machine epsilon +2. task size. +3. norm-2 condition number + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static ae_int_t directdensesolvers_densesolverrfsmaxv2(ae_int_t n, + double r2, + ae_state *_state) +{ + ae_int_t result; + + + result = directdensesolvers_densesolverrfsmax(n, (double)(0), (double)(0), _state); + return result; +} + + +/************************************************************************* +Basic LU solver for PLU*x = y. + +This subroutine assumes that: +* A=PLU is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_rbasiclusolve(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* xb, + ae_state *_state) +{ + ae_int_t i; + double v; + + + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + v = xb->ptr.p_double[i]; + xb->ptr.p_double[i] = xb->ptr.p_double[p->ptr.p_int[i]]; + xb->ptr.p_double[p->ptr.p_int[i]] = v; + } + } + for(i=1; i<=n-1; i++) + { + v = ae_v_dotproduct(&lua->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[n-1] = xb->ptr.p_double[n-1]/lua->ptr.pp_double[n-1][n-1]; + for(i=n-2; i>=0; i--) + { + v = ae_v_dotproduct(&lua->ptr.pp_double[i][i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + xb->ptr.p_double[i] = (xb->ptr.p_double[i]-v)/lua->ptr.pp_double[i][i]; + } +} + + +/************************************************************************* +Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. + +This subroutine assumes that: +* A*ScaleA is well scaled +* A is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_spdbasiccholeskysolve(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* xb, + ae_state *_state) +{ + ae_int_t i; + double v; + + + + /* + * A = L*L' or A=U'*U + */ + if( isupper ) + { + + /* + * Solve U'*y=b first. + */ + for(i=0; i<=n-1; i++) + { + xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; + if( iptr.p_double[i]; + ae_v_subd(&xb->ptr.p_double[i+1], 1, &cha->ptr.pp_double[i][i+1], 1, ae_v_len(i+1,n-1), v); + } + } + + /* + * Solve U*x=y then. + */ + for(i=n-1; i>=0; i--) + { + if( iptr.pp_double[i][i+1], 1, &xb->ptr.p_double[i+1], 1, ae_v_len(i+1,n-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; + } + } + else + { + + /* + * Solve L*y=b first + */ + for(i=0; i<=n-1; i++) + { + if( i>0 ) + { + v = ae_v_dotproduct(&cha->ptr.pp_double[i][0], 1, &xb->ptr.p_double[0], 1, ae_v_len(0,i-1)); + xb->ptr.p_double[i] = xb->ptr.p_double[i]-v; + } + xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; + } + + /* + * Solve L'*x=y then. + */ + for(i=n-1; i>=0; i--) + { + xb->ptr.p_double[i] = xb->ptr.p_double[i]/cha->ptr.pp_double[i][i]; + if( i>0 ) + { + v = xb->ptr.p_double[i]; + ae_v_subd(&xb->ptr.p_double[0], 1, &cha->ptr.pp_double[i][0], 1, ae_v_len(0,i-1), v); + } + } + } +} + + +/************************************************************************* +Basic LU solver for ScaleA*PLU*x = y. + +This subroutine assumes that: +* L is well-scaled, and it is U which needs scaling by ScaleA. +* A=PLU is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_cbasiclusolve(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* xb, + ae_state *_state) +{ + ae_int_t i; + ae_complex v; + + + for(i=0; i<=n-1; i++) + { + if( p->ptr.p_int[i]!=i ) + { + v = xb->ptr.p_complex[i]; + xb->ptr.p_complex[i] = xb->ptr.p_complex[p->ptr.p_int[i]]; + xb->ptr.p_complex[p->ptr.p_int[i]] = v; + } + } + for(i=1; i<=n-1; i++) + { + v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[n-1] = ae_c_div(xb->ptr.p_complex[n-1],lua->ptr.pp_complex[n-1][n-1]); + for(i=n-2; i>=0; i--) + { + v = ae_v_cdotproduct(&lua->ptr.pp_complex[i][i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); + xb->ptr.p_complex[i] = ae_c_div(ae_c_sub(xb->ptr.p_complex[i],v),lua->ptr.pp_complex[i][i]); + } +} + + +/************************************************************************* +Basic Cholesky solver for ScaleA*Cholesky(A)'*x = y. + +This subroutine assumes that: +* A*ScaleA is well scaled +* A is well-conditioned, so no zero divisions or overflow may occur + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +static void directdensesolvers_hpdbasiccholeskysolve(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* xb, + ae_state *_state) +{ + ae_int_t i; + ae_complex v; + + + + /* + * A = L*L' or A=U'*U + */ + if( isupper ) + { + + /* + * Solve U'*y=b first. + */ + for(i=0; i<=n-1; i++) + { + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_conj(cha->ptr.pp_complex[i][i], _state)); + if( iptr.p_complex[i]; + ae_v_csubc(&xb->ptr.p_complex[i+1], 1, &cha->ptr.pp_complex[i][i+1], 1, "Conj", ae_v_len(i+1,n-1), v); + } + } + + /* + * Solve U*x=y then. + */ + for(i=n-1; i>=0; i--) + { + if( iptr.pp_complex[i][i+1], 1, "N", &xb->ptr.p_complex[i+1], 1, "N", ae_v_len(i+1,n-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],cha->ptr.pp_complex[i][i]); + } + } + else + { + + /* + * Solve L*y=b first + */ + for(i=0; i<=n-1; i++) + { + if( i>0 ) + { + v = ae_v_cdotproduct(&cha->ptr.pp_complex[i][0], 1, "N", &xb->ptr.p_complex[0], 1, "N", ae_v_len(0,i-1)); + xb->ptr.p_complex[i] = ae_c_sub(xb->ptr.p_complex[i],v); + } + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],cha->ptr.pp_complex[i][i]); + } + + /* + * Solve L'*x=y then. + */ + for(i=n-1; i>=0; i--) + { + xb->ptr.p_complex[i] = ae_c_div(xb->ptr.p_complex[i],ae_c_conj(cha->ptr.pp_complex[i][i], _state)); + if( i>0 ) + { + v = xb->ptr.p_complex[i]; + ae_v_csubc(&xb->ptr.p_complex[0], 1, &cha->ptr.pp_complex[i][0], 1, "Conj", ae_v_len(0,i-1), v); + } + } + } +} + + +void _densesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + densesolverreport *p = (densesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _densesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + densesolverreport *dst = (densesolverreport*)_dst; + const densesolverreport *src = (const densesolverreport*)_src; + dst->terminationtype = src->terminationtype; + dst->r1 = src->r1; + dst->rinf = src->rinf; +} + + +void _densesolverreport_clear(void* _p) +{ + densesolverreport *p = (densesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _densesolverreport_destroy(void* _p) +{ + densesolverreport *p = (densesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _densesolverlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + densesolverlsreport *p = (densesolverlsreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->cx, 0, 0, DT_REAL, _state, make_automatic); +} + + +void _densesolverlsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + densesolverlsreport *dst = (densesolverlsreport*)_dst; + const densesolverlsreport *src = (const densesolverlsreport*)_src; + dst->terminationtype = src->terminationtype; + dst->r2 = src->r2; + ae_matrix_init_copy(&dst->cx, &src->cx, _state, make_automatic); + dst->n = src->n; + dst->k = src->k; +} + + +void _densesolverlsreport_clear(void* _p) +{ + densesolverlsreport *p = (densesolverlsreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->cx); +} + + +void _densesolverlsreport_destroy(void* _p) +{ + densesolverlsreport *p = (densesolverlsreport*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->cx); +} + + +#endif +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Solving sparse symmetric linear system A*x=b using GMRES(k) method. Sparse +symmetric A is given by its lower or upper triangle. + +NOTE: use SparseSolveGMRES() to solve system with nonsymmetric A. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvesymmetricgmres(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_int_t k, + double epsf, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + sparsematrix convbuf; + sparsesolverstate solver; + + ae_frame_make(_state, &_frame_block); + memset(&convbuf, 0, sizeof(convbuf)); + memset(&solver, 0, sizeof(solver)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&convbuf, _state, ae_true); + _sparsesolverstate_init(&solver, _state, ae_true); + + n = sparsegetnrows(a, _state); + + /* + * Test inputs + */ + ae_assert(n>=1, "SparseSolveSymmetricGMRES: tried to automatically detect N from sizeof(A), got nonpositive size", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSolveSymmetricGMRES: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSolveSymmetricGMRES: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSolveSymmetricGMRES: length(B)=0, "SparseSolveSymmetricGMRES: MaxIts<0", _state); + if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) + { + epsf = 1.0E-6; + } + + /* + * If A is non-CRS, perform conversion + */ + if( !sparseiscrs(a, _state) ) + { + sparsecopytocrsbuf(a, &convbuf, _state); + sparsesolvesymmetricgmres(&convbuf, isupper, b, k, epsf, maxits, x, rep, _state); + ae_frame_leave(_state); + return; + } + + /* + * Solve using temporary solver object + */ + sparsesolvercreate(n, &solver, _state); + sparsesolversetalgogmres(&solver, k, _state); + sparsesolversetcond(&solver, epsf, maxits, _state); + sparsesolversolvesymmetric(&solver, a, isupper, b, _state); + sparsesolverresults(&solver, x, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Solving sparse linear system A*x=b using GMRES(k) method. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse NxN matrix in any sparse storage format. Using CRS + format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvegmres(const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_int_t k, + double epsf, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + sparsematrix convbuf; + sparsesolverstate solver; + + ae_frame_make(_state, &_frame_block); + memset(&convbuf, 0, sizeof(convbuf)); + memset(&solver, 0, sizeof(solver)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&convbuf, _state, ae_true); + _sparsesolverstate_init(&solver, _state, ae_true); + + n = sparsegetnrows(a, _state); + + /* + * Test inputs + */ + ae_assert(n>=1, "SparseSolveGMRES: tried to automatically detect N from sizeof(A), got nonpositive size", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSolveGMRES: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSolveGMRES: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSolveGMRES: length(B)=0, "SparseSolveGMRES: MaxIts<0", _state); + if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) + { + epsf = 1.0E-6; + } + + /* + * If A is non-CRS, perform conversion + */ + if( !sparseiscrs(a, _state) ) + { + sparsecopytocrsbuf(a, &convbuf, _state); + sparsesolvegmres(&convbuf, b, k, epsf, maxits, x, rep, _state); + ae_frame_leave(_state); + return; + } + + /* + * Solve using temporary solver object + */ + sparsesolvercreate(n, &solver, _state); + sparsesolversetalgogmres(&solver, k, _state); + sparsesolversetcond(&solver, epsf, maxits, _state); + sparsesolversolve(&solver, a, b, _state); + sparsesolverresults(&solver, x, rep, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +This function initializes sparse linear iterative solver object. + +This solver can be used to solve nonsymmetric and symmetric positive +definite NxN (square) linear systems. + +The solver provides 'expert' API which allows advanced control over +algorithms being used, including ability to get progress report, terminate +long-running solver from other thread, out-of-core solution and so on. + +NOTE: there are also convenience functions that allows quick one-line + access to the solvers: + * SparseSolveCG() to solve SPD linear systems + * SparseSolveGMRES() to solve unsymmetric linear systems. + +NOTE: if you want to solve MxN (rectangular) linear problem you may use + LinLSQR solver provided by ALGLIB. + +USAGE (A is given by the SparseMatrix structure): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. Depending on whether system is symmetric or not, user calls: + * SparseSolverSolveSymmetric() for a symmetric system given by its + lower or upper triangle + * SparseSolverSolve() for a nonsymmetric system or a symmetric one + given by the full matrix + 5. User calls SparseSolverResults() to get the solution + + It is possible to call SparseSolverSolve???() again to solve another + task with same dimensionality but different matrix and/or right part + without reinitializing SparseSolverState structure. + +USAGE (out-of-core mode): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. After that user should work with out-of-core interface in a loop + like one given below: + + > alglib.sparsesolveroocstart(state) + > while alglib.sparsesolverooccontinue(state) do + > alglib.sparsesolveroocgetrequestinfo(state, out RequestType) + > alglib.sparsesolveroocgetrequestdata(state, out X) + > if RequestType=0 then + > [calculate Y=A*X, with X=R^N] + > alglib.sparsesolveroocsendresult(state, in Y) + > alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + N - problem dimensionality (fixed at start-up) + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvercreate(ae_int_t n, + sparsesolverstate* state, + ae_state *_state) +{ + + _sparsesolverstate_clear(state); + + ae_assert(n>=1, "SparseSolverCreate: N<=0", _state); + state->n = n; + state->running = ae_false; + state->userterminationneeded = ae_false; + rsetallocv(state->n, 0.0, &state->x0, _state); + rsetallocv(state->n, 0.0, &state->x, _state); + rsetallocv(state->n, 0.0, &state->ax, _state); + rsetallocv(state->n, 0.0, &state->xf, _state); + rsetallocv(state->n, 0.0, &state->b, _state); + rsetallocv(state->n, 0.0, &state->wrkb, _state); + state->reply1 = 0.0; + sparsesolversetxrep(state, ae_false, _state); + sparsesolversetcond(state, 0.0, 0, _state); + sparsesolversetalgogmres(state, 0, _state); + iterativesparse_clearrequestfields(state, _state); + iterativesparse_clearreportfields(state, _state); +} + + +/************************************************************************* +This function sets the solver algorithm to GMRES(k). + +NOTE: if you do not need advanced functionality of the SparseSolver API, + you may use convenience functions SparseSolveGMRES() and + SparseSolveSymmetricGMRES(). + +INPUT PARAMETERS: + State - structure which stores algorithm state + K - GMRES parameter, K>=0: + * recommended values are in 10..100 range + * larger values up to N are possible but have little sense + - the algorithm will be slower than any dense solver. + * values above N are truncated down to N + * zero value means that default value is chosen. This + value is 50 in the current version, but it may change + in future ALGLIB releases. + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetalgogmres(sparsesolverstate* state, + ae_int_t k, + ae_state *_state) +{ + + + ae_assert(k>=0, "SparseSolverSetAlgoGMRESK: K<0", _state); + state->algotype = 0; + if( k==0 ) + { + k = 50; + } + state->gmresk = ae_minint(k, state->n, _state); +} + + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - new starting point was set + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetstartingpoint(sparsesolverstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(state->n<=x->cnt, "SparseSolverSetStartingPoint: Length(X)n, _state), "SparseSolverSetStartingPoint: X contains infinite or NaN values!", _state); + rcopyv(state->n, x, &state->x0, _state); +} + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetcond(sparsesolverstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state)&&ae_fp_greater_eq(epsf,(double)(0)), "SparseSolverSetCond: EpsF is negative or contains infinite or NaN values", _state); + ae_assert(maxits>=0, "SparseSolverSetCond: MaxIts is negative", _state); + if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) + { + state->epsf = 1.0E-6; + state->maxits = 0; + } + else + { + state->epsf = epsf; + state->maxits = maxits; + } +} + + +/************************************************************************* +Procedure for the solution of A*x=b with sparse symmetric A given by its +lower or upper triangle. + +This function will work with any solver algorithm being used, SPD one +(like CG) or not (like GMRES). Using unsymmetric solvers (like GMRES) on +SPD problems is suboptimal, but still possible. + +NOTE: the solver behavior is ill-defined for a situation when a SPD + solver is used on indefinite matrix. It may solve the problem up to + desired precision (sometimes, rarely) or return with error code + signalling violation of underlying assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolvesymmetric(sparsesolverstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * Test inputs + */ + ae_assert(sparsegetnrows(a, _state)==n, "SparseSolverSolveSymmetric: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSolverSolveSymmetric: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSolverSolveSymmetric: length(B)convbuf, _state); + sparsesolversolvesymmetric(state, &state->convbuf, isupper, b, _state); + return; + } + + /* + * Solve using out-of-core API + */ + sparsesolveroocstart(state, b, _state); + while(sparsesolverooccontinue(state, _state)) + { + if( state->requesttype==-1 ) + { + + /* + * Skip location reports + */ + continue; + } + ae_assert(state->requesttype==0, "SparseSolverSolveSymmetric: integrity check 7372 failed", _state); + sparsesmv(a, isupper, &state->x, &state->ax, _state); + } +} + + +/************************************************************************* +Procedure for the solution of A*x=b with sparse nonsymmetric A + +IMPORTANT: this function will work with any solver algorithm being used, + symmetric solver like CG, or not. However, using symmetric + solvers on nonsymmetric problems is dangerous. It may solve + the problem up to desired precision (sometimes, rarely) or + terminate with error code signalling violation of underlying + assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolve(sparsesolverstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + + + n = state->n; + + /* + * Test inputs + */ + ae_assert(sparsegetnrows(a, _state)==n, "SparseSolverSolve: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSolverSolve: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSolverSolve: length(B)convbuf, _state); + sparsesolversolve(state, &state->convbuf, b, _state); + return; + } + + /* + * Solve using out-of-core API + */ + sparsesolveroocstart(state, b, _state); + while(sparsesolverooccontinue(state, _state)) + { + if( state->requesttype==-1 ) + { + + /* + * Skip location reports + */ + continue; + } + ae_assert(state->requesttype==0, "SparseSolverSolve: integrity check 7372 failed", _state); + sparsemv(a, &state->x, &state->ax, _state); + } +} + + +/************************************************************************* +Sparse solver results. + +This function must be called after calling one of the SparseSolverSolve() +functions. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual +s + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverresults(sparsesolverstate* state, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + + sparsesolveroocstop(state, x, rep, _state); +} + + +/************************************************************************* +This function turns on/off reporting during out-of-core processing. + +When the solver works in the out-of-core mode, it can be configured to +report its progress by returning current location. These location reports +are implemented as a special kind of the out-of-core request: +* SparseSolverOOCGetRequestInfo() returns -1 +* SparseSolverOOCGetRequestData() returns current location +* SparseSolverOOCGetRequestData1() returns squared norm of the residual +* SparseSolverOOCSendResult() shall NOT be called + +This function has no effect when SparseSolverSolve() is used because this +function has no method of reporting its progress. + +NOTE: when used with GMRES(k), this function reports progress every k-th + iteration. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetxrep(sparsesolverstate* state, + ae_bool needxrep, + ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function initiates out-of-core mode of the sparse solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver object + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstart(sparsesolverstate* state, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + iterativesparse_clearrequestfields(state, _state); + iterativesparse_clearreportfields(state, _state); + state->running = ae_true; + state->userterminationneeded = ae_false; + rcopyv(state->n, b, &state->b, _state); +} + + +/************************************************************************* +This function performs iterative solution of the linear system in the +out-of-core mode. It should be used in conjunction with other out-of-core- +related functions of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +ae_bool sparsesolverooccontinue(sparsesolverstate* state, + ae_state *_state) +{ + ae_bool result; + + + ae_assert(state->running, "SparseSolverContinue: the solver is not running", _state); + result = iterativesparse_sparsesolveriteration(state, _state); + state->running = result; + return result; +} + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by the solver: +* RequestType=0 means that matrix-vector products A*x is requested +* RequestType=-1 means that solver reports its progress; this request is + returned only when reports are activated wit SparseSolverSetXRep(). + +This function returns just request type; in order to get contents of the +trial vector, use sparsesolveroocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 for matrix-vector product A*x, with A being + NxN system matrix and X being N-dimensional + vector + *-1 for location and residual report + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestinfo(sparsesolverstate* state, + ae_int_t* requesttype, + ae_state *_state) +{ + + *requesttype = 0; + + ae_assert(state->running, "SparseSolverOOCGetRequestInfo: the solver is not running", _state); + *requesttype = state->requesttype; +} + + +/************************************************************************* +This function is used to retrieve vector associated with out-of-core +request sent by the solver to user code. Depending on the request type +(returned by the SparseSolverOOCGetRequestInfo()) this vector should be +multiplied by A or subjected to another processing. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N] or larger, leading N elements are filled + with vector X. + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata(sparsesolverstate* state, + /* Real */ ae_vector* x, + ae_state *_state) +{ + + + ae_assert(state->running, "SparseSolverOOCGetRequestInfo: the solver is not running", _state); + rcopyallocv(state->n, &state->x, x, _state); +} + + +/************************************************************************* +This function is used to retrieve scalar value associated with out-of-core +request sent by the solver to user code. In the current ALGLIB version +this function is used to retrieve squared residual norm during progress +reports. + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + V - scalar value associated with the current request + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata1(sparsesolverstate* state, + double* v, + ae_state *_state) +{ + + *v = 0.0; + + ae_assert(state->running, "SparseSolverOOCGetRequestInfo: the solver is not running", _state); + *v = state->reply1; +} + + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +the solver. Usually it is product A*x for vector X returned by the solver. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N] or larger, leading N elements contain A*x + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocsendresult(sparsesolverstate* state, + /* Real */ const ae_vector* ax, + ae_state *_state) +{ + + + ae_assert(state->running, "SparseSolverOOCSendResult: the solver is not running", _state); + ae_assert(state->requesttype==0, "SparseSolverOOCSendResult: this request type does not accept replies", _state); + rcopyv(state->n, ax, &state->ax, _state); +} + + +/************************************************************************* +This function finalizes out-of-core mode of the linear solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + X - array[N], the solution. + Zero-filled on the failure (Rep.TerminationType<0). + Rep - report with additional info: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstop(sparsesolverstate* state, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + + ae_assert(!state->running, "SparseSolverOOCStop: the solver is still running", _state); + ae_vector_set_length(x, state->n, _state); + rcopyv(state->n, &state->xf, x, _state); + initsparsesolverreport(rep, _state); + rep->iterationscount = state->repiterationscount; + rep->nmv = state->repnmv; + rep->terminationtype = state->repterminationtype; + rep->r2 = state->repr2; +} + + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants the solver to terminate +or when processing an out-of-core request. + +As result, solver stops at point which was "current accepted" when +the termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverrequesttermination(sparsesolverstate* state, + ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Reset report fields + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void initsparsesolverreport(sparsesolverreport* rep, ae_state *_state) +{ + + + rep->terminationtype = 0; + rep->nmv = 0; + rep->iterationscount = 0; + rep->r2 = (double)(0); +} + + +/************************************************************************* +Reverse communication sparse iteration subroutine + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +static ae_bool iterativesparse_sparsesolveriteration(sparsesolverstate* state, + ae_state *_state) +{ + ae_int_t outeridx; + double res; + double prevres; + double res0; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + outeridx = state->rstate.ia.ptr.p_int[0]; + res = state->rstate.ra.ptr.p_double[0]; + prevres = state->rstate.ra.ptr.p_double[1]; + res0 = state->rstate.ra.ptr.p_double[2]; + } + else + { + outeridx = 359; + res = -58.0; + prevres = -919.0; + res0 = -909.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + + /* + * Routine body + */ + state->running = ae_true; + iterativesparse_clearrequestfields(state, _state); + iterativesparse_clearreportfields(state, _state); + + /* + * GMRES? + */ + if( state->algotype!=0 ) + { + goto lbl_5; + } + if( ae_fp_neq(rdotv2(state->n, &state->x0, _state),(double)(0)) ) + { + goto lbl_7; + } + + /* + * Starting point is default one (zero), quick initialization + */ + rsetv(state->n, 0.0, &state->xf, _state); + rcopyv(state->n, &state->b, &state->wrkb, _state); + goto lbl_8; +lbl_7: + + /* + * Non-zero starting point is provided, + */ + rcopyv(state->n, &state->x0, &state->xf, _state); + state->requesttype = 0; + rcopyv(state->n, &state->x0, &state->x, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->requesttype = -999; + state->repnmv = state->repnmv+1; + rcopyv(state->n, &state->b, &state->wrkb, _state); + raddv(state->n, -1.0, &state->ax, &state->wrkb, _state); +lbl_8: + outeridx = 0; + state->repterminationtype = 5; + state->repr2 = rdotv2(state->n, &state->wrkb, _state); + res0 = ae_sqrt(rdotv2(state->n, &state->b, _state), _state); + res = ae_sqrt(state->repr2, _state); + if( !state->xrep ) + { + goto lbl_9; + } + + /* + * Report initial point + */ + state->requesttype = -1; + state->reply1 = res*res; + rcopyv(state->n, &state->xf, &state->x, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->requesttype = -999; +lbl_9: +lbl_11: + if( !(ae_fp_greater(res,(double)(0))&&(state->maxits==0||state->repiterationscountmaxits)) ) + { + goto lbl_12; + } + + /* + * Solve with GMRES(k) for current residual. + * + * We set EpsF-based stopping condition for GMRES(k). It allows us + * to quickly detect sufficient decrease in the residual. We still + * have to recompute residual after the GMRES round because residuals + * computed by GMRES are different from the true one (due to restarts). + * + * However, checking residual decrease within GMRES still gives us + * an opportunity to stop early without waiting for GMRES round to + * complete. + */ + fblsgmrescreate(&state->wrkb, state->n, state->gmresk, &state->gmressolver, _state); + state->gmressolver.epsres = state->epsf*res0/res; +lbl_13: + if( !fblsgmresiteration(&state->gmressolver, _state) ) + { + goto lbl_14; + } + state->requesttype = 0; + rcopyv(state->n, &state->gmressolver.x, &state->x, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->requesttype = -999; + rcopyv(state->n, &state->ax, &state->gmressolver.ax, _state); + state->repnmv = state->repnmv+1; + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + goto lbl_13; +lbl_14: + state->repiterationscount = state->repiterationscount+state->gmressolver.itsperformed; + raddv(state->n, 1.0, &state->gmressolver.xs, &state->xf, _state); + + /* + * Update residual, evaluate residual decrease, terminate if needed + */ + state->requesttype = 0; + rcopyv(state->n, &state->xf, &state->x, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->requesttype = -999; + state->repnmv = state->repnmv+1; + rcopyv(state->n, &state->b, &state->wrkb, _state); + raddv(state->n, -1.0, &state->ax, &state->wrkb, _state); + state->repr2 = rdotv2(state->n, &state->wrkb, _state); + prevres = res; + res = ae_sqrt(state->repr2, _state); + if( !state->xrep ) + { + goto lbl_15; + } + + /* + * Report initial point + */ + state->requesttype = -1; + state->reply1 = res*res; + rcopyv(state->n, &state->xf, &state->x, _state); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->requesttype = -999; +lbl_15: + if( ae_fp_less_eq(res,state->epsf*res0) ) + { + + /* + * Residual decrease condition met, stopping + */ + state->repterminationtype = 1; + goto lbl_12; + } + if( ae_fp_greater_eq(res,prevres*((double)1-ae_sqrt(ae_machineepsilon, _state))) ) + { + + /* + * The algorithm stagnated + */ + state->repterminationtype = 7; + goto lbl_12; + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->repterminationtype = 8; + result = ae_false; + return result; + } + outeridx = outeridx+1; + goto lbl_11; +lbl_12: + result = ae_false; + return result; +lbl_5: + ae_assert(ae_false, "SparseSolverIteration: integrity check failed (unexpected algo)", _state); + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = outeridx; + state->rstate.ra.ptr.p_double[0] = res; + state->rstate.ra.ptr.p_double[1] = prevres; + state->rstate.ra.ptr.p_double[2] = res0; + return result; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void iterativesparse_clearrequestfields(sparsesolverstate* state, + ae_state *_state) +{ + + + state->requesttype = -999; +} + + +/************************************************************************* +Clears report fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void iterativesparse_clearreportfields(sparsesolverstate* state, + ae_state *_state) +{ + + + state->repiterationscount = 0; + state->repnmv = 0; + state->repterminationtype = 0; + state->repr2 = (double)(0); +} + + +void _sparsesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sparsesolverreport *p = (sparsesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _sparsesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sparsesolverreport *dst = (sparsesolverreport*)_dst; + const sparsesolverreport *src = (const sparsesolverreport*)_src; + dst->terminationtype = src->terminationtype; + dst->nmv = src->nmv; + dst->iterationscount = src->iterationscount; + dst->r2 = src->r2; +} + + +void _sparsesolverreport_clear(void* _p) +{ + sparsesolverreport *p = (sparsesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _sparsesolverreport_destroy(void* _p) +{ + sparsesolverreport *p = (sparsesolverreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _sparsesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + sparsesolverstate *p = (sparsesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->xf, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ax, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->wrkb, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->convbuf, _state, make_automatic); + _fblsgmresstate_init(&p->gmressolver, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _sparsesolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + sparsesolverstate *dst = (sparsesolverstate*)_dst; + const sparsesolverstate *src = (const sparsesolverstate*)_src; + dst->n = src->n; + ae_vector_init_copy(&dst->x0, &src->x0, _state, make_automatic); + dst->epsf = src->epsf; + dst->maxits = src->maxits; + dst->algotype = src->algotype; + dst->gmresk = src->gmresk; + dst->xrep = src->xrep; + dst->running = src->running; + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + ae_vector_init_copy(&dst->xf, &src->xf, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnmv = src->repnmv; + dst->repterminationtype = src->repterminationtype; + dst->repr2 = src->repr2; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->ax, &src->ax, _state, make_automatic); + dst->reply1 = src->reply1; + ae_vector_init_copy(&dst->wrkb, &src->wrkb, _state, make_automatic); + _sparsematrix_init_copy(&dst->convbuf, &src->convbuf, _state, make_automatic); + _fblsgmresstate_init_copy(&dst->gmressolver, &src->gmressolver, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _sparsesolverstate_clear(void* _p) +{ + sparsesolverstate *p = (sparsesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x0); + ae_vector_clear(&p->b); + ae_vector_clear(&p->xf); + ae_vector_clear(&p->x); + ae_vector_clear(&p->ax); + ae_vector_clear(&p->wrkb); + _sparsematrix_clear(&p->convbuf); + _fblsgmresstate_clear(&p->gmressolver); + _rcommstate_clear(&p->rstate); +} + + +void _sparsesolverstate_destroy(void* _p) +{ + sparsesolverstate *p = (sparsesolverstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x0); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->xf); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->ax); + ae_vector_destroy(&p->wrkb); + _sparsematrix_destroy(&p->convbuf); + _fblsgmresstate_destroy(&p->gmressolver); + _rcommstate_destroy(&p->rstate); +} + + +#endif +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes linear CG Solver. This solver is used to solve +symmetric positive definite problems. If you want to solve nonsymmetric +(or non-positive definite) problem you may use LinLSQR solver provided by +ALGLIB. + +USAGE: +1. User initializes algorithm state with LinCGCreate() call +2. User tunes solver parameters with LinCGSetCond() and other functions +3. Optionally, user sets starting point with LinCGSetStartingPoint() +4. User calls LinCGSolveSparse() function which takes algorithm state and + SparseMatrix object. +5. User calls LinCGResults() to get solution +6. Optionally, user may call LinCGSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinCGState structure. + +INPUT PARAMETERS: + N - problem dimension, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state) +{ + ae_int_t i; + + _lincgstate_clear(state); + + ae_assert(n>0, "LinCGCreate: N<=0", _state); + state->n = n; + state->prectype = 0; + state->itsbeforerestart = n; + state->itsbeforerupdate = 10; + state->epsf = lincg_defaultprecision; + state->maxits = 0; + state->xrep = ae_false; + state->running = ae_false; + + /* + * * allocate arrays + * * set RX to NAN (just for the case user calls Results() without + * calling SolveSparse() + * * set starting point to zero + * * we do NOT initialize B here because we assume that user should + * initializate it using LinCGSetB() function. In case he forgets + * to do so, exception will be thrown in the LinCGIteration(). + */ + ae_vector_set_length(&state->rx, state->n, _state); + ae_vector_set_length(&state->startx, state->n, _state); + ae_vector_set_length(&state->b, state->n, _state); + for(i=0; i<=state->n-1; i++) + { + state->rx.ptr.p_double[i] = _state->v_nan; + state->startx.ptr.p_double[i] = 0.0; + state->b.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&state->cx, state->n, _state); + ae_vector_set_length(&state->p, state->n, _state); + ae_vector_set_length(&state->r, state->n, _state); + ae_vector_set_length(&state->cr, state->n, _state); + ae_vector_set_length(&state->z, state->n, _state); + ae_vector_set_length(&state->cz, state->n, _state); + ae_vector_set_length(&state->x, state->n, _state); + ae_vector_set_length(&state->mv, state->n, _state); + ae_vector_set_length(&state->pv, state->n, _state); + lincg_updateitersdata(state, _state); + ae_vector_set_length(&state->rstate.ia, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetstartingpoint(lincgstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetStartingPoint: you can not change starting point because LinCGIteration() function is running", _state); + ae_assert(state->n<=x->cnt, "LinCGSetStartingPoint: Length(X)n, _state), "LinCGSetStartingPoint: X contains infinite or NaN values!", _state); + ae_v_move(&state->startx.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); +} + + +/************************************************************************* +This function sets right part. By default, right part is zero. + +INPUT PARAMETERS: + B - right part, array[N]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetb(lincgstate* state, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetB: you can not set B, because function LinCGIteration is running!", _state); + ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); + ae_v_move(&state->b.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); +} + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecunit(lincgstate* state, ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetPrecUnit: you can not change preconditioner, because function LinCGIteration is running!", _state); + state->prectype = -1; +} + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecdiag(lincgstate* state, ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); + state->prectype = 0; +} + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetcond(lincgstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetCond: you can not change stopping criteria when LinCGIteration() is running", _state); + ae_assert(ae_isfinite(epsf, _state)&&ae_fp_greater_eq(epsf,(double)(0)), "LinCGSetCond: EpsF is negative or contains infinite or NaN values", _state); + ae_assert(maxits>=0, "LinCGSetCond: MaxIts is negative", _state); + if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) + { + state->epsf = lincg_defaultprecision; + state->maxits = maxits; + } + else + { + state->epsf = epsf; + state->maxits = maxits; + } +} + + +/************************************************************************* +Reverse communication version of linear CG. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +ae_bool lincgiteration(lincgstate* state, ae_state *_state) +{ + ae_int_t i; + double uvar; + double bnorm; + double v; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + i = state->rstate.ia.ptr.p_int[0]; + uvar = state->rstate.ra.ptr.p_double[0]; + bnorm = state->rstate.ra.ptr.p_double[1]; + v = state->rstate.ra.ptr.p_double[2]; + } + else + { + i = 359; + uvar = -58.0; + bnorm = -919.0; + v = -909.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + if( state->rstate.stage==7 ) + { + goto lbl_7; + } + + /* + * Routine body + */ + ae_assert(state->b.cnt>0, "LinCGIteration: B is not initialized (you must initialize B by LinCGSetB() call", _state); + state->running = ae_true; + state->repnmv = 0; + lincg_clearrfields(state, _state); + lincg_updateitersdata(state, _state); + + /* + * Start 0-th iteration + */ + ae_v_move(&state->rx.ptr.p_double[0], 1, &state->startx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + lincg_clearrfields(state, _state); + state->needvmv = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needvmv = ae_false; + bnorm = (double)(0); + state->r2 = (double)(0); + state->meritfunction = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->r.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; + state->r2 = state->r2+state->r.ptr.p_double[i]*state->r.ptr.p_double[i]; + state->meritfunction = state->meritfunction+state->mv.ptr.p_double[i]*state->rx.ptr.p_double[i]-(double)2*state->b.ptr.p_double[i]*state->rx.ptr.p_double[i]; + bnorm = bnorm+state->b.ptr.p_double[i]*state->b.ptr.p_double[i]; + } + bnorm = ae_sqrt(bnorm, _state); + + /* + * Output first report + */ + if( !state->xrep ) + { + goto lbl_8; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + lincg_clearrfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; +lbl_8: + + /* + * Is x0 a solution? + */ + if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) + { + state->running = ae_false; + if( ae_isfinite(state->r2, _state) ) + { + state->repterminationtype = 1; + } + else + { + state->repterminationtype = -4; + } + result = ae_false; + return result; + } + + /* + * Calculate Z and P + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->r.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + lincg_clearrfields(state, _state); + state->needprec = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needprec = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->z.ptr.p_double[i] = state->pv.ptr.p_double[i]; + state->p.ptr.p_double[i] = state->z.ptr.p_double[i]; + } + + /* + * Other iterations(1..N) + */ + state->repiterationscount = 0; +lbl_10: + if( ae_false ) + { + goto lbl_11; + } + state->repiterationscount = state->repiterationscount+1; + + /* + * Calculate Alpha + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->p.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + lincg_clearrfields(state, _state); + state->needvmv = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needvmv = ae_false; + if( !ae_isfinite(state->vmv, _state)||ae_fp_less_eq(state->vmv,(double)(0)) ) + { + + /* + * a) Overflow when calculating VMV + * b) non-positive VMV (non-SPD matrix) + */ + state->running = ae_false; + if( ae_isfinite(state->vmv, _state) ) + { + state->repterminationtype = -5; + } + else + { + state->repterminationtype = -4; + } + result = ae_false; + return result; + } + state->alpha = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->alpha = state->alpha+state->r.ptr.p_double[i]*state->z.ptr.p_double[i]; + } + state->alpha = state->alpha/state->vmv; + if( !ae_isfinite(state->alpha, _state) ) + { + + /* + * Overflow when calculating Alpha + */ + state->running = ae_false; + state->repterminationtype = -4; + result = ae_false; + return result; + } + + /* + * Next step toward solution + */ + for(i=0; i<=state->n-1; i++) + { + state->cx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->alpha*state->p.ptr.p_double[i]; + } + + /* + * Calculate R: + * * use recurrent relation to update R + * * at every ItsBeforeRUpdate-th iteration recalculate it from scratch, using matrix-vector product + * in case R grows instead of decreasing, algorithm is terminated with positive completion code + */ + if( !(state->itsbeforerupdate==0||state->repiterationscount%state->itsbeforerupdate!=0) ) + { + goto lbl_12; + } + + /* + * Calculate R using recurrent formula + */ + for(i=0; i<=state->n-1; i++) + { + state->cr.ptr.p_double[i] = state->r.ptr.p_double[i]-state->alpha*state->mv.ptr.p_double[i]; + state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; + } + goto lbl_13; +lbl_12: + + /* + * Calculate R using matrix-vector multiplication + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + lincg_clearrfields(state, _state); + state->needmv = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needmv = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->cr.ptr.p_double[i] = state->b.ptr.p_double[i]-state->mv.ptr.p_double[i]; + state->x.ptr.p_double[i] = state->cr.ptr.p_double[i]; + } + + /* + * Calculating merit function + * Check emergency stopping criterion + */ + v = (double)(0); + for(i=0; i<=state->n-1; i++) + { + v = v+state->mv.ptr.p_double[i]*state->cx.ptr.p_double[i]-(double)2*state->b.ptr.p_double[i]*state->cx.ptr.p_double[i]; + } + if( ae_fp_less(v,state->meritfunction) ) + { + goto lbl_14; + } + for(i=0; i<=state->n-1; i++) + { + if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) + { + state->running = ae_false; + state->repterminationtype = -4; + result = ae_false; + return result; + } + } + + /* + *output last report + */ + if( !state->xrep ) + { + goto lbl_16; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + lincg_clearrfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->xupdated = ae_false; +lbl_16: + state->running = ae_false; + state->repterminationtype = 7; + result = ae_false; + return result; +lbl_14: + state->meritfunction = v; +lbl_13: + ae_v_move(&state->rx.ptr.p_double[0], 1, &state->cx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + + /* + * calculating RNorm + * + * NOTE: monotonic decrease of R2 is not guaranteed by algorithm. + */ + state->r2 = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->r2 = state->r2+state->cr.ptr.p_double[i]*state->cr.ptr.p_double[i]; + } + + /* + *output report + */ + if( !state->xrep ) + { + goto lbl_18; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + lincg_clearrfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->xupdated = ae_false; +lbl_18: + + /* + *stopping criterion + *achieved the required precision + */ + if( !ae_isfinite(state->r2, _state)||ae_fp_less_eq(ae_sqrt(state->r2, _state),state->epsf*bnorm) ) + { + state->running = ae_false; + if( ae_isfinite(state->r2, _state) ) + { + state->repterminationtype = 1; + } + else + { + state->repterminationtype = -4; + } + result = ae_false; + return result; + } + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + for(i=0; i<=state->n-1; i++) + { + if( !ae_isfinite(state->rx.ptr.p_double[i], _state) ) + { + state->running = ae_false; + state->repterminationtype = -4; + result = ae_false; + return result; + } + } + + /* + *if X is finite number + */ + state->running = ae_false; + state->repterminationtype = 5; + result = ae_false; + return result; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->cr.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + + /* + *prepere of parameters for next iteration + */ + state->repnmv = state->repnmv+1; + lincg_clearrfields(state, _state); + state->needprec = ae_true; + state->rstate.stage = 7; + goto lbl_rcomm; +lbl_7: + state->needprec = ae_false; + ae_v_move(&state->cz.ptr.p_double[0], 1, &state->pv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + if( state->repiterationscount%state->itsbeforerestart!=0 ) + { + state->beta = (double)(0); + uvar = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->beta = state->beta+state->cz.ptr.p_double[i]*state->cr.ptr.p_double[i]; + uvar = uvar+state->z.ptr.p_double[i]*state->r.ptr.p_double[i]; + } + + /* + *check that UVar is't INF or is't zero + */ + if( !ae_isfinite(uvar, _state)||ae_fp_eq(uvar,(double)(0)) ) + { + state->running = ae_false; + state->repterminationtype = -4; + result = ae_false; + return result; + } + + /* + *calculate .BETA + */ + state->beta = state->beta/uvar; + + /* + *check that .BETA neither INF nor NaN + */ + if( !ae_isfinite(state->beta, _state) ) + { + state->running = ae_false; + state->repterminationtype = -1; + result = ae_false; + return result; + } + for(i=0; i<=state->n-1; i++) + { + state->p.ptr.p_double[i] = state->cz.ptr.p_double[i]+state->beta*state->p.ptr.p_double[i]; + } + } + else + { + ae_v_move(&state->p.ptr.p_double[0], 1, &state->cz.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + } + + /* + *prepere data for next iteration + */ + for(i=0; i<=state->n-1; i++) + { + + /* + *write (k+1)th iteration to (k )th iteration + */ + state->r.ptr.p_double[i] = state->cr.ptr.p_double[i]; + state->z.ptr.p_double[i] = state->cz.ptr.p_double[i]; + } + goto lbl_10; +lbl_11: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = i; + state->rstate.ra.ptr.p_double[0] = uvar; + state->rstate.ra.ptr.p_double[1] = bnorm; + state->rstate.ra.ptr.p_double[2] = v; + return result; +} + + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse matrix in the CRS format (you MUST contvert it to + CRS format by calling SparseConvertToCRS() function). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinCGSetPrecUnit(). However, preconditioning cost is low and + preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsolvesparse(lincgstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + double v; + double vmv; + + + n = state->n; + ae_assert(b->cnt>=state->n, "LinCGSetB: Length(B)n, _state), "LinCGSetB: B contains infinite or NaN values!", _state); + + /* + * Allocate temporaries + */ + rvectorsetlengthatleast(&state->tmpd, n, _state); + + /* + * Compute diagonal scaling matrix D + */ + if( state->prectype==0 ) + { + + /* + * Default preconditioner - inverse of matrix diagonal + */ + for(i=0; i<=n-1; i++) + { + v = sparsegetdiagonal(a, i, _state); + if( ae_fp_greater(v,(double)(0)) ) + { + state->tmpd.ptr.p_double[i] = (double)1/ae_sqrt(v, _state); + } + else + { + state->tmpd.ptr.p_double[i] = (double)(1); + } + } + } + else + { + + /* + * No diagonal scaling + */ + for(i=0; i<=n-1; i++) + { + state->tmpd.ptr.p_double[i] = (double)(1); + } + } + + /* + * Solve + */ + lincgrestart(state, _state); + lincgsetb(state, b, _state); + while(lincgiteration(state, _state)) + { + + /* + * Process different requests from optimizer + */ + if( state->needmv ) + { + sparsesmv(a, isupper, &state->x, &state->mv, _state); + } + if( state->needvmv ) + { + sparsesmv(a, isupper, &state->x, &state->mv, _state); + vmv = ae_v_dotproduct(&state->x.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->vmv = vmv; + } + if( state->needprec ) + { + for(i=0; i<=n-1; i++) + { + state->pv.ptr.p_double[i] = state->x.ptr.p_double[i]*ae_sqr(state->tmpd.ptr.p_double[i], _state); + } + } + } +} + + +/************************************************************************* +CG-solver: results. + +This function must be called after LinCGSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -5 input matrix is either not positive definite, + too large or too small + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgresults(const lincgstate* state, + /* Real */ ae_vector* x, + lincgreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _lincgreport_clear(rep); + + ae_assert(!state->running, "LinCGResult: you can not get result, because function LinCGIteration has been launched!", _state); + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nmv = state->repnmv; + rep->terminationtype = state->repterminationtype; + rep->r2 = state->r2; +} + + +/************************************************************************* +This function sets restart frequency. By default, algorithm is restarted +after N subsequent iterations. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrestartfreq(lincgstate* state, + ae_int_t srf, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetRestartFreq: you can not change restart frequency when LinCGIteration() is running", _state); + ae_assert(srf>0, "LinCGSetRestartFreq: non-positive SRF", _state); + state->itsbeforerestart = srf; +} + + +/************************************************************************* +This function sets frequency of residual recalculations. + +Algorithm updates residual r_k using iterative formula, but recalculates +it from scratch after each 10 iterations. It is done to avoid accumulation +of numerical errors and to stop algorithm when r_k starts to grow. + +Such low update frequence (1/10) gives very little overhead, but makes +algorithm a bit more robust against numerical errors. However, you may +change it + +INPUT PARAMETERS: + Freq - desired update frequency, Freq>=0. + Zero value means that no updates will be done. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrupdatefreq(lincgstate* state, + ae_int_t freq, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinCGSetRUpdateFreq: you can not change update frequency when LinCGIteration() is running", _state); + ae_assert(freq>=0, "LinCGSetRUpdateFreq: non-positive Freq", _state); + state->itsbeforerupdate = freq; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +Procedure for restart function LinCGIteration + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgrestart(lincgstate* state, ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 2+1, _state); + state->rstate.stage = -1; + lincg_clearrfields(state, _state); +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void lincg_clearrfields(lincgstate* state, ae_state *_state) +{ + + + state->xupdated = ae_false; + state->needmv = ae_false; + state->needmtv = ae_false; + state->needmv2 = ae_false; + state->needvmv = ae_false; + state->needprec = ae_false; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void lincg_updateitersdata(lincgstate* state, ae_state *_state) +{ + + + state->repiterationscount = 0; + state->repnmv = 0; + state->repterminationtype = 0; +} + + +void _lincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lincgstate *p = (lincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cr, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->r, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->pv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->startx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpd, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _lincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lincgstate *dst = (lincgstate*)_dst; + const lincgstate *src = (const lincgstate*)_src; + ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + dst->n = src->n; + dst->prectype = src->prectype; + ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic); + ae_vector_init_copy(&dst->cr, &src->cr, _state, make_automatic); + ae_vector_init_copy(&dst->cz, &src->cz, _state, make_automatic); + ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic); + ae_vector_init_copy(&dst->r, &src->r, _state, make_automatic); + ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic); + dst->alpha = src->alpha; + dst->beta = src->beta; + dst->r2 = src->r2; + dst->meritfunction = src->meritfunction; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic); + ae_vector_init_copy(&dst->pv, &src->pv, _state, make_automatic); + dst->vmv = src->vmv; + ae_vector_init_copy(&dst->startx, &src->startx, _state, make_automatic); + dst->epsf = src->epsf; + dst->maxits = src->maxits; + dst->itsbeforerestart = src->itsbeforerestart; + dst->itsbeforerupdate = src->itsbeforerupdate; + dst->xrep = src->xrep; + dst->xupdated = src->xupdated; + dst->needmv = src->needmv; + dst->needmtv = src->needmtv; + dst->needmv2 = src->needmv2; + dst->needvmv = src->needvmv; + dst->needprec = src->needprec; + dst->repiterationscount = src->repiterationscount; + dst->repnmv = src->repnmv; + dst->repterminationtype = src->repterminationtype; + dst->running = src->running; + ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _lincgstate_clear(void* _p) +{ + lincgstate *p = (lincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->rx); + ae_vector_clear(&p->b); + ae_vector_clear(&p->cx); + ae_vector_clear(&p->cr); + ae_vector_clear(&p->cz); + ae_vector_clear(&p->p); + ae_vector_clear(&p->r); + ae_vector_clear(&p->z); + ae_vector_clear(&p->x); + ae_vector_clear(&p->mv); + ae_vector_clear(&p->pv); + ae_vector_clear(&p->startx); + ae_vector_clear(&p->tmpd); + _rcommstate_clear(&p->rstate); +} + + +void _lincgstate_destroy(void* _p) +{ + lincgstate *p = (lincgstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->rx); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->cx); + ae_vector_destroy(&p->cr); + ae_vector_destroy(&p->cz); + ae_vector_destroy(&p->p); + ae_vector_destroy(&p->r); + ae_vector_destroy(&p->z); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->mv); + ae_vector_destroy(&p->pv); + ae_vector_destroy(&p->startx); + ae_vector_destroy(&p->tmpd); + _rcommstate_destroy(&p->rstate); +} + + +void _lincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + lincgreport *p = (lincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _lincgreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + lincgreport *dst = (lincgreport*)_dst; + const lincgreport *src = (const lincgreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nmv = src->nmv; + dst->terminationtype = src->terminationtype; + dst->r2 = src->r2; +} + + +void _lincgreport_clear(void* _p) +{ + lincgreport *p = (lincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _lincgreport_destroy(void* _p) +{ + lincgreport *p = (lincgreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes linear LSQR Solver. This solver is used to solve +non-symmetric (and, possibly, non-square) problems. Least squares solution +is returned for non-compatible systems. + +USAGE: +1. User initializes algorithm state with LinLSQRCreate() call +2. User tunes solver parameters with LinLSQRSetCond() and other functions +3. User calls LinLSQRSolveSparse() function which takes algorithm state + and SparseMatrix object. +4. User calls LinLSQRResults() to get solution +5. Optionally, user may call LinLSQRSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinLSQRState structure. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: see also linlsqrcreatebuf() for version which reuses previously + allocated place as much as possible. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreate(ae_int_t m, + ae_int_t n, + linlsqrstate* state, + ae_state *_state) +{ + + _linlsqrstate_clear(state); + + ae_assert(m>0, "LinLSQRCreate: M<=0", _state); + ae_assert(n>0, "LinLSQRCreate: N<=0", _state); + linlsqrcreatebuf(m, n, state, _state); +} + + +/************************************************************************* +This function initializes linear LSQR Solver. It provides exactly same +functionality as linlsqrcreate(), but reuses previously allocated space +as much as possible. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2018 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreatebuf(ae_int_t m, + ae_int_t n, + linlsqrstate* state, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(m>0, "LinLSQRCreateBuf: M<=0", _state); + ae_assert(n>0, "LinLSQRCreateBuf: N<=0", _state); + state->m = m; + state->n = n; + state->prectype = 0; + state->epsa = linlsqr_atol; + state->epsb = linlsqr_btol; + state->epsc = (double)1/ae_sqrt(ae_machineepsilon, _state); + state->maxits = 0; + state->lambdai = (double)(0); + state->xrep = ae_false; + state->running = ae_false; + state->repiterationscount = 0; + + /* + * * allocate arrays + * * set RX to NAN (just for the case user calls Results() without + * calling SolveSparse() + * * set B to zero + */ + normestimatorcreate(m, n, 2, 2, &state->nes, _state); + ae_vector_set_length(&state->rx, state->n, _state); + ae_vector_set_length(&state->ui, state->m+state->n, _state); + ae_vector_set_length(&state->uip1, state->m+state->n, _state); + ae_vector_set_length(&state->vip1, state->n, _state); + ae_vector_set_length(&state->vi, state->n, _state); + ae_vector_set_length(&state->omegai, state->n, _state); + ae_vector_set_length(&state->omegaip1, state->n, _state); + ae_vector_set_length(&state->d, state->n, _state); + ae_vector_set_length(&state->x, state->m+state->n, _state); + ae_vector_set_length(&state->mv, state->m+state->n, _state); + ae_vector_set_length(&state->mtv, state->n, _state); + ae_vector_set_length(&state->b, state->m, _state); + for(i=0; i<=n-1; i++) + { + state->rx.ptr.p_double[i] = _state->v_nan; + } + for(i=0; i<=m-1; i++) + { + state->b.ptr.p_double[i] = (double)(0); + } + ae_vector_set_length(&state->rstate.ia, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +This function sets right part. By default, right part is zero. + +INPUT PARAMETERS: + B - right part, array[N]. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetb(linlsqrstate* state, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(!state->running, "LinLSQRSetB: you can not change B when LinLSQRIteration is running", _state); + ae_assert(state->m<=b->cnt, "LinLSQRSetB: Length(B)m, _state), "LinLSQRSetB: B contains infinite or NaN values", _state); + state->bnorm2 = (double)(0); + for(i=0; i<=state->m-1; i++) + { + state->b.ptr.p_double[i] = b->ptr.p_double[i]; + state->bnorm2 = state->bnorm2+b->ptr.p_double[i]*b->ptr.p_double[i]; + } +} + + +/************************************************************************* +This function changes preconditioning settings of LinLSQQSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state) +{ + + + ae_assert(!state->running, "LinLSQRSetPrecUnit: you can not change preconditioner, because function LinLSQRIteration is running!", _state); + state->prectype = -1; +} + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state) +{ + + + ae_assert(!state->running, "LinLSQRSetPrecDiag: you can not change preconditioner, because function LinCGIteration is running!", _state); + state->prectype = 0; +} + + +/************************************************************************* +This function sets optional Tikhonov regularization coefficient. +It is zero by default. + +INPUT PARAMETERS: + LambdaI - regularization factor, LambdaI>=0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetlambdai(linlsqrstate* state, + double lambdai, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinLSQRSetLambdaI: you can not set LambdaI, because function LinLSQRIteration is running", _state); + ae_assert(ae_isfinite(lambdai, _state)&&ae_fp_greater_eq(lambdai,(double)(0)), "LinLSQRSetLambdaI: LambdaI is infinite or NaN", _state); + state->lambdai = lambdai; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state) +{ + ae_int_t summn; + double bnorm; + ae_int_t i; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + summn = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + bnorm = state->rstate.ra.ptr.p_double[0]; + } + else + { + summn = 359; + i = -58; + bnorm = -919.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + if( state->rstate.stage==5 ) + { + goto lbl_5; + } + if( state->rstate.stage==6 ) + { + goto lbl_6; + } + + /* + * Routine body + */ + ae_assert(state->b.cnt>0, "LinLSQRIteration: using non-allocated array B", _state); + summn = state->m+state->n; + bnorm = ae_sqrt(state->bnorm2, _state); + state->userterminationneeded = ae_false; + state->running = ae_true; + state->repnmv = 0; + state->repiterationscount = 0; + state->r2 = state->bnorm2; + linlsqr_clearrfields(state, _state); + + /* + *estimate for ANorm + */ + normestimatorrestart(&state->nes, _state); +lbl_7: + if( !normestimatoriteration(&state->nes, _state) ) + { + goto lbl_8; + } + if( !state->nes.needmv ) + { + goto lbl_9; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + linlsqr_clearrfields(state, _state); + state->needmv = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needmv = ae_false; + ae_v_move(&state->nes.mv.ptr.p_double[0], 1, &state->mv.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); + goto lbl_7; +lbl_9: + if( !state->nes.needmtv ) + { + goto lbl_11; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->nes.x.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); + + /* + *matrix-vector multiplication + */ + state->repnmv = state->repnmv+1; + linlsqr_clearrfields(state, _state); + state->needmtv = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->needmtv = ae_false; + ae_v_move(&state->nes.mtv.ptr.p_double[0], 1, &state->mtv.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + goto lbl_7; +lbl_11: + goto lbl_7; +lbl_8: + normestimatorresults(&state->nes, &state->anorm, _state); + + /* + *initialize .RX by zeros + */ + for(i=0; i<=state->n-1; i++) + { + state->rx.ptr.p_double[i] = (double)(0); + } + + /* + *output first report + */ + if( !state->xrep ) + { + goto lbl_13; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + linlsqr_clearrfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->xupdated = ae_false; +lbl_13: + + /* + * LSQR, Step 0. + * + * Algorithm outline corresponds to one which was described at p.50 of + * "LSQR - an algorithm for sparse linear equations and sparse least + * squares" by C.Paige and M.Saunders with one small addition - we + * explicitly extend system matrix by additional N lines in order + * to handle non-zero lambda, i.e. original A is replaced by + * [ A ] + * A_mod = [ ] + * [ lambda*I ]. + * + * Step 0: + * x[0] = 0 + * beta[1]*u[1] = b + * alpha[1]*v[1] = A_mod'*u[1] + * w[1] = v[1] + * phiBar[1] = beta[1] + * rhoBar[1] = alpha[1] + * d[0] = 0 + * + * NOTE: + * There are three criteria for stopping: + * (S0) maximum number of iterations + * (S1) ||Rk||<=EpsB*||B||; + * (S2) ||A^T*Rk||/(||A||*||Rk||)<=EpsA. + * It is very important that S2 always checked AFTER S1. It is necessary + * to avoid division by zero when Rk=0. + */ + state->betai = bnorm; + if( ae_fp_eq(state->betai,(double)(0)) ) + { + + /* + * Zero right part + */ + state->running = ae_false; + state->repterminationtype = 1; + result = ae_false; + return result; + } + for(i=0; i<=summn-1; i++) + { + if( im ) + { + state->ui.ptr.p_double[i] = state->b.ptr.p_double[i]/state->betai; + } + else + { + state->ui.ptr.p_double[i] = (double)(0); + } + state->x.ptr.p_double[i] = state->ui.ptr.p_double[i]; + } + state->repnmv = state->repnmv+1; + linlsqr_clearrfields(state, _state); + state->needmtv = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needmtv = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->ui.ptr.p_double[state->m+i]; + } + state->alphai = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->alphai = state->alphai+state->mtv.ptr.p_double[i]*state->mtv.ptr.p_double[i]; + } + state->alphai = ae_sqrt(state->alphai, _state); + if( ae_fp_eq(state->alphai,(double)(0)) ) + { + + /* + * Orthogonality stopping criterion is met + */ + state->running = ae_false; + state->repterminationtype = 4; + result = ae_false; + return result; + } + for(i=0; i<=state->n-1; i++) + { + state->vi.ptr.p_double[i] = state->mtv.ptr.p_double[i]/state->alphai; + state->omegai.ptr.p_double[i] = state->vi.ptr.p_double[i]; + } + state->phibari = state->betai; + state->rhobari = state->alphai; + for(i=0; i<=state->n-1; i++) + { + state->d.ptr.p_double[i] = (double)(0); + } + state->dnorm = (double)(0); + + /* + * Steps I=1, 2, ... + */ +lbl_15: + if( ae_false ) + { + goto lbl_16; + } + + /* + * At I-th step State.RepIterationsCount=I. + */ + state->repiterationscount = state->repiterationscount+1; + + /* + * Bidiagonalization part: + * beta[i+1]*u[i+1] = A_mod*v[i]-alpha[i]*u[i] + * alpha[i+1]*v[i+1] = A_mod'*u[i+1] - beta[i+1]*v[i] + * + * NOTE: beta[i+1]=0 or alpha[i+1]=0 will lead to successful termination + * in the end of the current iteration. In this case u/v are zero. + * NOTE2: algorithm won't fail on zero alpha or beta (there will be no + * division by zero because it will be stopped BEFORE division + * occurs). However, near-zero alpha and beta won't stop algorithm + * and, although no division by zero will happen, orthogonality + * in U and V will be lost. + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->vi.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->repnmv = state->repnmv+1; + linlsqr_clearrfields(state, _state); + state->needmv = ae_true; + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->needmv = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->mv.ptr.p_double[state->m+i] = state->lambdai*state->vi.ptr.p_double[i]; + } + state->betaip1 = (double)(0); + for(i=0; i<=summn-1; i++) + { + state->uip1.ptr.p_double[i] = state->mv.ptr.p_double[i]-state->alphai*state->ui.ptr.p_double[i]; + state->betaip1 = state->betaip1+state->uip1.ptr.p_double[i]*state->uip1.ptr.p_double[i]; + } + if( ae_fp_neq(state->betaip1,(double)(0)) ) + { + state->betaip1 = ae_sqrt(state->betaip1, _state); + for(i=0; i<=summn-1; i++) + { + state->uip1.ptr.p_double[i] = state->uip1.ptr.p_double[i]/state->betaip1; + } + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,state->m-1)); + state->repnmv = state->repnmv+1; + linlsqr_clearrfields(state, _state); + state->needmtv = ae_true; + state->rstate.stage = 5; + goto lbl_rcomm; +lbl_5: + state->needmtv = ae_false; + for(i=0; i<=state->n-1; i++) + { + state->mtv.ptr.p_double[i] = state->mtv.ptr.p_double[i]+state->lambdai*state->uip1.ptr.p_double[state->m+i]; + } + state->alphaip1 = (double)(0); + for(i=0; i<=state->n-1; i++) + { + state->vip1.ptr.p_double[i] = state->mtv.ptr.p_double[i]-state->betaip1*state->vi.ptr.p_double[i]; + state->alphaip1 = state->alphaip1+state->vip1.ptr.p_double[i]*state->vip1.ptr.p_double[i]; + } + if( ae_fp_neq(state->alphaip1,(double)(0)) ) + { + state->alphaip1 = ae_sqrt(state->alphaip1, _state); + for(i=0; i<=state->n-1; i++) + { + state->vip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]/state->alphaip1; + } + } + + /* + * Build next orthogonal transformation + */ + state->rhoi = safepythag2(state->rhobari, state->betaip1, _state); + state->ci = state->rhobari/state->rhoi; + state->si = state->betaip1/state->rhoi; + state->theta = state->si*state->alphaip1; + state->rhobarip1 = -state->ci*state->alphaip1; + state->phii = state->ci*state->phibari; + state->phibarip1 = state->si*state->phibari; + + /* + * Update .RNorm + * + * This tricky formula is necessary because simply writing + * State.R2:=State.PhiBarIP1*State.PhiBarIP1 does NOT guarantees + * monotonic decrease of R2. Roundoff error combined with 80-bit + * precision used internally by Intel chips allows R2 to increase + * slightly in some rare, but possible cases. This property is + * undesirable, so we prefer to guard against R increase. + */ + state->r2 = ae_minreal(state->r2, state->phibarip1*state->phibarip1, _state); + + /* + * Update d and DNorm, check condition-related stopping criteria + */ + for(i=0; i<=state->n-1; i++) + { + state->d.ptr.p_double[i] = (double)1/state->rhoi*(state->vi.ptr.p_double[i]-state->theta*state->d.ptr.p_double[i]); + state->dnorm = state->dnorm+state->d.ptr.p_double[i]*state->d.ptr.p_double[i]; + } + if( ae_fp_greater_eq(ae_sqrt(state->dnorm, _state)*state->anorm,state->epsc) ) + { + state->running = ae_false; + state->repterminationtype = 7; + result = ae_false; + return result; + } + + /* + * Update x, output report + */ + for(i=0; i<=state->n-1; i++) + { + state->rx.ptr.p_double[i] = state->rx.ptr.p_double[i]+state->phii/state->rhoi*state->omegai.ptr.p_double[i]; + } + if( !state->xrep ) + { + goto lbl_17; + } + ae_v_move(&state->x.ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + linlsqr_clearrfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 6; + goto lbl_rcomm; +lbl_6: + state->xupdated = ae_false; +lbl_17: + + /* + * Check stopping criteria + * 1. achieved required number of iterations; + * 2. ||Rk||<=EpsB*||B||; + * 3. ||A^T*Rk||/(||A||*||Rk||)<=EpsA; + */ + if( state->maxits>0&&state->repiterationscount>=state->maxits ) + { + + /* + * Achieved required number of iterations + */ + state->running = ae_false; + state->repterminationtype = 5; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->phibarip1,state->epsb*bnorm) ) + { + + /* + * ||Rk||<=EpsB*||B||, here ||Rk||=PhiBar + */ + state->running = ae_false; + state->repterminationtype = 1; + result = ae_false; + return result; + } + if( ae_fp_less_eq(state->alphaip1*ae_fabs(state->ci, _state)/state->anorm,state->epsa) ) + { + + /* + * ||A^T*Rk||/(||A||*||Rk||)<=EpsA, here ||A^T*Rk||=PhiBar*Alpha[i+1]*|.C| + */ + state->running = ae_false; + state->repterminationtype = 4; + result = ae_false; + return result; + } + if( state->userterminationneeded ) + { + + /* + * User requested termination + */ + state->running = ae_false; + state->repterminationtype = 8; + result = ae_false; + return result; + } + + /* + * Update omega + */ + for(i=0; i<=state->n-1; i++) + { + state->omegaip1.ptr.p_double[i] = state->vip1.ptr.p_double[i]-state->theta/state->rhoi*state->omegai.ptr.p_double[i]; + } + + /* + * Prepare for the next iteration - rename variables: + * u[i] := u[i+1] + * v[i] := v[i+1] + * rho[i] := rho[i+1] + * ... + */ + ae_v_move(&state->ui.ptr.p_double[0], 1, &state->uip1.ptr.p_double[0], 1, ae_v_len(0,summn-1)); + ae_v_move(&state->vi.ptr.p_double[0], 1, &state->vip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_v_move(&state->omegai.ptr.p_double[0], 1, &state->omegaip1.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + state->alphai = state->alphaip1; + state->betai = state->betaip1; + state->phibari = state->phibarip1; + state->rhobari = state->rhobarip1; + goto lbl_15; +lbl_16: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = summn; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ra.ptr.p_double[0] = bnorm; + return result; +} + + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse M*N matrix in the CRS format (you MUST contvert it + to CRS format by calling SparseConvertToCRS() function + BEFORE you pass it to this function). + B - right part, array[M] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinLSQRSetPrecUnit(). However, preconditioning cost is low + and preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsolvesparse(linlsqrstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t t0; + ae_int_t t1; + double v; + + + n = state->n; + ae_assert(!state->running, "LinLSQRSolveSparse: you can not call this function when LinLSQRIteration is running", _state); + ae_assert(b->cnt>=state->m, "LinLSQRSolveSparse: Length(B)m, _state), "LinLSQRSolveSparse: B contains infinite or NaN values", _state); + + /* + * Allocate temporaries + */ + rvectorsetlengthatleast(&state->tmpd, n, _state); + rvectorsetlengthatleast(&state->tmpx, n, _state); + + /* + * Compute diagonal scaling matrix D + */ + if( state->prectype==0 ) + { + + /* + * Default preconditioner - inverse of column norms + */ + for(i=0; i<=n-1; i++) + { + state->tmpd.ptr.p_double[i] = (double)(0); + } + t0 = 0; + t1 = 0; + while(sparseenumerate(a, &t0, &t1, &i, &j, &v, _state)) + { + state->tmpd.ptr.p_double[j] = state->tmpd.ptr.p_double[j]+ae_sqr(v, _state); + } + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(state->tmpd.ptr.p_double[i],(double)(0)) ) + { + state->tmpd.ptr.p_double[i] = (double)1/ae_sqrt(state->tmpd.ptr.p_double[i], _state); + } + else + { + state->tmpd.ptr.p_double[i] = (double)(1); + } + } + } + else + { + + /* + * No diagonal scaling + */ + for(i=0; i<=n-1; i++) + { + state->tmpd.ptr.p_double[i] = (double)(1); + } + } + + /* + * Solve. + * + * Instead of solving A*x=b we solve preconditioned system (A*D)*(inv(D)*x)=b. + * Transformed A is not calculated explicitly, we just modify multiplication + * by A or A'. After solution we modify State.RX so it will store untransformed + * variables + */ + linlsqrsetb(state, b, _state); + linlsqrrestart(state, _state); + while(linlsqriteration(state, _state)) + { + if( state->needmv ) + { + for(i=0; i<=n-1; i++) + { + state->tmpx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->x.ptr.p_double[i]; + } + sparsemv(a, &state->tmpx, &state->mv, _state); + } + if( state->needmtv ) + { + sparsemtv(a, &state->x, &state->mtv, _state); + for(i=0; i<=n-1; i++) + { + state->mtv.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->mtv.ptr.p_double[i]; + } + } + } + for(i=0; i<=n-1; i++) + { + state->rx.ptr.p_double[i] = state->tmpd.ptr.p_double[i]*state->rx.ptr.p_double[i]; + } +} + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. + EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| + MaxIts - algorithm will be stopped if number of iterations + more than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will +be setted as default values. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetcond(linlsqrstate* state, + double epsa, + double epsb, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(!state->running, "LinLSQRSetCond: you can not call this function when LinLSQRIteration is running", _state); + ae_assert(ae_isfinite(epsa, _state)&&ae_fp_greater_eq(epsa,(double)(0)), "LinLSQRSetCond: EpsA is negative, INF or NAN", _state); + ae_assert(ae_isfinite(epsb, _state)&&ae_fp_greater_eq(epsb,(double)(0)), "LinLSQRSetCond: EpsB is negative, INF or NAN", _state); + ae_assert(maxits>=0, "LinLSQRSetCond: MaxIts is negative", _state); + if( (ae_fp_eq(epsa,(double)(0))&&ae_fp_eq(epsb,(double)(0)))&&maxits==0 ) + { + state->epsa = linlsqr_atol; + state->epsb = linlsqr_btol; + state->maxits = state->n; + } + else + { + state->epsa = epsa; + state->epsb = epsb; + state->maxits = maxits; + } +} + + +/************************************************************************* +LSQR solver: results. + +This function must be called after LinLSQRSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * 1 ||Rk||<=EpsB*||B|| + * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + X contains best point found so far. + (sometimes returned on singular systems) + * 8 user requested termination via calling + linlsqrrequesttermination() + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrresults(const linlsqrstate* state, + /* Real */ ae_vector* x, + linlsqrreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _linlsqrreport_clear(rep); + + ae_assert(!state->running, "LinLSQRResult: you can not call this function when LinLSQRIteration is running", _state); + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->rx.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nmv = state->repnmv; + rep->terminationtype = state->repterminationtype; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetxrep(linlsqrstate* state, + ae_bool needxrep, + ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function restarts LinLSQRIteration + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrrestart(linlsqrstate* state, ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 1+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; + linlsqr_clearrfields(state, _state); + state->repiterationscount = 0; +} + + +/************************************************************************* +This function is used to peek into LSQR solver and get current iteration +counter. You can safely "peek" into the solver from another thread. + +INPUT PARAMETERS: + S - solver object + +RESULT: + iteration counter, in [0,INF) + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t linlsqrpeekiterationscount(const linlsqrstate* s, + ae_state *_state) +{ + ae_int_t result; + + + result = s->repiterationscount; + return result; +} + + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants LSQR solver to terminate +(obviously, the thread running LSQR solver can not request termination +because it is already busy working on LSQR). + +As result, solver stops at point which was "current accepted" when +termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void linlsqrrequesttermination(linlsqrstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void linlsqr_clearrfields(linlsqrstate* state, ae_state *_state) +{ + + + state->xupdated = ae_false; + state->needmv = ae_false; + state->needmtv = ae_false; + state->needmv2 = ae_false; + state->needvmv = ae_false; + state->needprec = ae_false; +} + + +void _linlsqrstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + linlsqrstate *p = (linlsqrstate*)_p; + ae_touch_ptr((void*)p); + _normestimatorstate_init(&p->nes, _state, make_automatic); + ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->b, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->ui, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->uip1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->vi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->vip1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->omegai, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->omegaip1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->d, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->mtv, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpd, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _linlsqrstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + linlsqrstate *dst = (linlsqrstate*)_dst; + const linlsqrstate *src = (const linlsqrstate*)_src; + _normestimatorstate_init_copy(&dst->nes, &src->nes, _state, make_automatic); + ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic); + ae_vector_init_copy(&dst->b, &src->b, _state, make_automatic); + dst->n = src->n; + dst->m = src->m; + dst->prectype = src->prectype; + ae_vector_init_copy(&dst->ui, &src->ui, _state, make_automatic); + ae_vector_init_copy(&dst->uip1, &src->uip1, _state, make_automatic); + ae_vector_init_copy(&dst->vi, &src->vi, _state, make_automatic); + ae_vector_init_copy(&dst->vip1, &src->vip1, _state, make_automatic); + ae_vector_init_copy(&dst->omegai, &src->omegai, _state, make_automatic); + ae_vector_init_copy(&dst->omegaip1, &src->omegaip1, _state, make_automatic); + dst->alphai = src->alphai; + dst->alphaip1 = src->alphaip1; + dst->betai = src->betai; + dst->betaip1 = src->betaip1; + dst->phibari = src->phibari; + dst->phibarip1 = src->phibarip1; + dst->phii = src->phii; + dst->rhobari = src->rhobari; + dst->rhobarip1 = src->rhobarip1; + dst->rhoi = src->rhoi; + dst->ci = src->ci; + dst->si = src->si; + dst->theta = src->theta; + dst->lambdai = src->lambdai; + ae_vector_init_copy(&dst->d, &src->d, _state, make_automatic); + dst->anorm = src->anorm; + dst->bnorm2 = src->bnorm2; + dst->dnorm = src->dnorm; + dst->r2 = src->r2; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + ae_vector_init_copy(&dst->mv, &src->mv, _state, make_automatic); + ae_vector_init_copy(&dst->mtv, &src->mtv, _state, make_automatic); + dst->epsa = src->epsa; + dst->epsb = src->epsb; + dst->epsc = src->epsc; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->xupdated = src->xupdated; + dst->needmv = src->needmv; + dst->needmtv = src->needmtv; + dst->needmv2 = src->needmv2; + dst->needvmv = src->needvmv; + dst->needprec = src->needprec; + dst->repiterationscount = src->repiterationscount; + dst->repnmv = src->repnmv; + dst->repterminationtype = src->repterminationtype; + dst->running = src->running; + dst->userterminationneeded = src->userterminationneeded; + ae_vector_init_copy(&dst->tmpd, &src->tmpd, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _linlsqrstate_clear(void* _p) +{ + linlsqrstate *p = (linlsqrstate*)_p; + ae_touch_ptr((void*)p); + _normestimatorstate_clear(&p->nes); + ae_vector_clear(&p->rx); + ae_vector_clear(&p->b); + ae_vector_clear(&p->ui); + ae_vector_clear(&p->uip1); + ae_vector_clear(&p->vi); + ae_vector_clear(&p->vip1); + ae_vector_clear(&p->omegai); + ae_vector_clear(&p->omegaip1); + ae_vector_clear(&p->d); + ae_vector_clear(&p->x); + ae_vector_clear(&p->mv); + ae_vector_clear(&p->mtv); + ae_vector_clear(&p->tmpd); + ae_vector_clear(&p->tmpx); + _rcommstate_clear(&p->rstate); +} + + +void _linlsqrstate_destroy(void* _p) +{ + linlsqrstate *p = (linlsqrstate*)_p; + ae_touch_ptr((void*)p); + _normestimatorstate_destroy(&p->nes); + ae_vector_destroy(&p->rx); + ae_vector_destroy(&p->b); + ae_vector_destroy(&p->ui); + ae_vector_destroy(&p->uip1); + ae_vector_destroy(&p->vi); + ae_vector_destroy(&p->vip1); + ae_vector_destroy(&p->omegai); + ae_vector_destroy(&p->omegaip1); + ae_vector_destroy(&p->d); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->mv); + ae_vector_destroy(&p->mtv); + ae_vector_destroy(&p->tmpd); + ae_vector_destroy(&p->tmpx); + _rcommstate_destroy(&p->rstate); +} + + +void _linlsqrreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + linlsqrreport *p = (linlsqrreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _linlsqrreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + linlsqrreport *dst = (linlsqrreport*)_dst; + const linlsqrreport *src = (const linlsqrreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nmv = src->nmv; + dst->terminationtype = src->terminationtype; +} + + +void _linlsqrreport_clear(void* _p) +{ + linlsqrreport *p = (linlsqrreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _linlsqrreport_destroy(void* _p) +{ + linlsqrreport *p = (linlsqrreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +This solver converts input matrix to SKS format, performs Cholesky +factorization using SKS Cholesky subroutine (works well for limited +bandwidth matrices) and uses sparse triangular solvers to get solution of +the original system. + +IMPORTANT: this function is intended for low profile (variable band) + linear systems with dense or nearly-dense bands. Only in such + cases it provides some performance improvement over more + general sparsrspdsolve(). If your system has high bandwidth + or sparse band, the general sparsrspdsolve() is likely to be + more efficient. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolvesks(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + sparsematrix a2; + ae_int_t n; + + ae_frame_make(_state, &_frame_block); + memset(&a2, 0, sizeof(a2)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&a2, _state, ae_true); + + n = sparsegetnrows(a, _state); + ae_assert(n>0, "SparseSPDSolveSKS: N<=0", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSPDSolveSKS: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSPDSolveSKS: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSPDSolveSKS: length(B)terminationtype = -3; + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = b->ptr.p_double[i]; + } + if( isupper ) + { + sparsetrsv(&a2, isupper, ae_false, 1, x, _state); + sparsetrsv(&a2, isupper, ae_false, 0, x, _state); + } + else + { + sparsetrsv(&a2, isupper, ae_false, 0, x, _state); + sparsetrsv(&a2, isupper, ae_false, 1, x, _state); + } + rep->terminationtype = 1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +Depending on the ALGLIB edition (Free or Commercial, C++, C# or other), +the following applies: + +* FREE EDITION: ALGLIB sparse solver can be used, a supernodal algorithm + with serial implementation in generic C or generic C#. + +* COMMERCIAL EDITION: a parallel and SIMD-capable version of the ALGLIB + sparse supernodal solver can be used. A C code with SIMD kernels callable + from C++ and C#. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library can outperform + ALGLIB; for other problem types, ALGLIB DSS solver can be superior. + +IMPORTANT: This function is preferred to one that works with explicitly + given Cholesky factorization (sparsespdcholeskysolve). Some + efficient linear solver backends do not return Cholesky factors, + so doing explicit Cholesky followed by sparsespdcholeskysolve() + means that these backends will never be activated. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly. + Can be stored in any sparse storage format, CRS is preferred. + IsUpper - which half of A is provided (another half is ignored). + It is better to store the lower triangle because it allows + us to avoid one transposition during internal conversion. + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolve(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + sparsematrix a2; + sparsematrix a3; + ae_int_t n; + ae_vector p; + ae_vector idummy; + ae_int_t donotreusemem; + spcholanalysis analysis; + ae_bool flg; + ae_int_t facttype; + + ae_frame_make(_state, &_frame_block); + memset(&a2, 0, sizeof(a2)); + memset(&a3, 0, sizeof(a3)); + memset(&p, 0, sizeof(p)); + memset(&idummy, 0, sizeof(idummy)); + memset(&analysis, 0, sizeof(analysis)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&a2, _state, ae_true); + _sparsematrix_init(&a3, _state, ae_true); + ae_vector_init(&p, 0, DT_INT, _state, ae_true); + ae_vector_init(&idummy, 0, DT_INT, _state, ae_true); + _spcholanalysis_init(&analysis, _state, ae_true); + + n = sparsegetnrows(a, _state); + ae_assert(n>0, "SparseSPDSolve: N<=0", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSPDSolve: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSPDSolve: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSPDSolve: length(B)terminationtype = -3; + rsetallocv(n, 0.0, x, _state); + ae_frame_leave(_state); + return; + } + + /* + * Factorize + */ + if( !spsymmfactorize(&analysis, _state) ) + { + rep->terminationtype = -3; + rsetallocv(n, 0.0, x, _state); + ae_frame_leave(_state); + return; + } + + /* + * Solve + */ + rcopyallocv(n, b, x, _state); + spsymmsolve(&analysis, x, _state); + rep->terminationtype = 1; + ae_frame_leave(_state); +} + + +/************************************************************************* +Sparse linear solver for A*x=b with N*N real symmetric positive definite +matrix A given by its Cholesky decomposition, and N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the SKS (Skyline) + or CRS (compressed row storage) format. An exception will be + generated if you pass matrix in some other format. + +INPUT PARAMETERS + A - sparse NxN matrix stored in CRs or SKS format, must be NxN + exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdcholeskysolve(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t n; + + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + + n = sparsegetnrows(a, _state); + ae_assert(n>0, "SparseSPDCholeskySolve: N<=0", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSPDCholeskySolve: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSPDCholeskySolve: cols(A)!=N", _state); + ae_assert(sparseissks(a, _state)||sparseiscrs(a, _state), "SparseSPDCholeskySolve: A is not an SKS/CRS matrix", _state); + ae_assert(b->cnt>=n, "SparseSPDCholeskySolve: length(B)terminationtype = -3; + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + return; + } + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = b->ptr.p_double[i]; + } + if( isupper ) + { + sparsetrsv(a, isupper, ae_false, 1, x, _state); + sparsetrsv(a, isupper, ae_false, 0, x, _state); + } + else + { + sparsetrsv(a, isupper, ae_false, 0, x, _state); + sparsetrsv(a, isupper, ae_false, 1, x, _state); + } + rep->terminationtype = 1; +} + + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A, N*1 vectors x and b. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* sparse LU with dynamic pivoting for stability. Provides better accuracy + at the cost of a significantly lower performance. Recommended only for + extremely unstable problems. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly, any storage format + B - array[N], right part + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + * 20 use sparse LU with dynamic pivoting for stability. + Not intended for large-scale problems. + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolve(const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_int_t solvertype, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t n; + double v; + sparsematrix a2; + ae_vector pivp; + ae_vector pivq; + ae_vector b2; + ae_vector sr; + ae_vector sc; + double reg; + normestimatorstate e; + ae_int_t gmresk; + ae_int_t maxits; + + ae_frame_make(_state, &_frame_block); + memset(&a2, 0, sizeof(a2)); + memset(&pivp, 0, sizeof(pivp)); + memset(&pivq, 0, sizeof(pivq)); + memset(&b2, 0, sizeof(b2)); + memset(&sr, 0, sizeof(sr)); + memset(&sc, 0, sizeof(sc)); + memset(&e, 0, sizeof(e)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&a2, _state, ae_true); + ae_vector_init(&pivp, 0, DT_INT, _state, ae_true); + ae_vector_init(&pivq, 0, DT_INT, _state, ae_true); + ae_vector_init(&b2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sc, 0, DT_REAL, _state, ae_true); + _normestimatorstate_init(&e, _state, ae_true); + + n = sparsegetnrows(a, _state); + ae_assert(n>0, "SparseSolve: N<=0", _state); + ae_assert((((solvertype==0||solvertype==-19)||solvertype==10)||solvertype==11)||solvertype==20, "SparseSolve: unexpected SolverType", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseSolve: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseSolve: cols(A)!=N", _state); + ae_assert(b->cnt>=n, "SparseSolve: length(B)terminationtype = -3; + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + ae_frame_leave(_state); + return; + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = b->ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + j = pivp.ptr.p_int[i]; + v = x->ptr.p_double[i]; + x->ptr.p_double[i] = x->ptr.p_double[j]; + x->ptr.p_double[j] = v; + } + sparsetrsv(&a2, ae_false, ae_true, 0, x, _state); + sparsetrsv(&a2, ae_true, ae_false, 0, x, _state); + for(i=n-1; i>=0; i--) + { + j = pivq.ptr.p_int[i]; + v = x->ptr.p_double[i]; + x->ptr.p_double[i] = x->ptr.p_double[j]; + x->ptr.p_double[j] = v; + } + rep->terminationtype = 1; + ae_frame_leave(_state); + return; + } + + /* + * unexpected solver type + */ + ae_assert(ae_false, "DIRECTSPARSESOLVERS: integrity check 1038 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Sparse linear least squares solver for A*x=b with general (nonsymmetric) +N*N sparse real matrix A, N*1 vectors x and b. + +This function solves a regularized linear least squares problem of the form + + ( ) + min ( |Ax-b|^2 + reg*|x|^2 ), with reg>=sqrt(MachineAccuracy) + ( ) + +It can be used to solve both full rank and rank deficient systems. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse MxN matrix, any storage format + B - array[M], right part + Reg - regularization coefficient, Reg>=sqrt(MachineAccuracy), + lower values will be silently increased. + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + +OUTPUT PARAMETERS + X - array[N], least squares solution + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success. + + Present version of the solver does NOT returns negative + completion codes because it does not fail. However, + future ALGLIB versions may include solvers which return + negative completion codes. + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvelsreg(const sparsematrix* a, + /* Real */ const ae_vector* b, + double reg, + ae_int_t solvertype, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + double v; + sparsematrix a2; + ae_vector pivp; + ae_vector pivq; + ae_vector b2; + ae_vector sr; + ae_vector sc; + double augreg; + normestimatorstate e; + ae_int_t gmresk; + ae_int_t maxits; + + ae_frame_make(_state, &_frame_block); + memset(&a2, 0, sizeof(a2)); + memset(&pivp, 0, sizeof(pivp)); + memset(&pivq, 0, sizeof(pivq)); + memset(&b2, 0, sizeof(b2)); + memset(&sr, 0, sizeof(sr)); + memset(&sc, 0, sizeof(sc)); + memset(&e, 0, sizeof(e)); + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + _sparsematrix_init(&a2, _state, ae_true); + ae_vector_init(&pivp, 0, DT_INT, _state, ae_true); + ae_vector_init(&pivq, 0, DT_INT, _state, ae_true); + ae_vector_init(&b2, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sc, 0, DT_REAL, _state, ae_true); + _normestimatorstate_init(&e, _state, ae_true); + + m = sparsegetnrows(a, _state); + n = sparsegetncols(a, _state); + ae_assert(m>0, "SparseSolveLS: M<=0", _state); + ae_assert(n>0, "SparseSolveLS: N<=0", _state); + ae_assert(ae_isfinite(reg, _state)&&ae_fp_greater(reg,(double)(0)), "SparseSolveLS: Reg is not finite or non-positive", _state); + ae_assert(((solvertype==0||solvertype==-19)||solvertype==10)||solvertype==11, "SparseSolveLS: unexpected SolverType", _state); + ae_assert(b->cnt>=m, "SparseSolveLS: length(B)terminationtype = 1; + + /* + * Augmented system-based solver + */ + if( (solvertype==-19||solvertype==10)||solvertype==11 ) + { + reg = ae_maxreal(reg, ae_sqrt(ae_machineepsilon, _state), _state); + gmresk = 200; + maxits = 200; + if( solvertype==11 ) + { + + /* + * Limited memory profile + */ + gmresk = 25; + maxits = 200; + } + if( solvertype==-19 ) + { + + /* + * Debug profile - deliberately limited GMRES + */ + gmresk = 5; + maxits = 200; + } + sparsescale(&a2, 0, ae_false, ae_true, ae_true, &sr, &sc, _state); + rcopyallocv(m, b, &b2, _state); + rmergedivv(m, &sr, &b2, _state); + normestimatorcreate(m, n, 5, 5, &e, _state); + normestimatorsetseed(&e, 117, _state); + normestimatorestimatesparse(&e, &a2, _state); + normestimatorresults(&e, &v, _state); + augreg = (double)10*ae_sqrt(ae_machineepsilon, _state)*coalesce(v, (double)(1), _state); + directsparsesolvers_sparsesolveaug(&a2, &b2, (double)(1), ae_maxreal(ae_sqr(augreg, _state), ae_sqr(reg, _state), _state), (double)(1), ae_sqr(reg, _state), gmresk, maxits, x, rep, _state); + rmergedivv(n, &sc, x, _state); + ae_frame_leave(_state); + return; + } + + /* + * unexpected solver type + */ + ae_assert(ae_false, "DIRECTSPARSESOLVERS: integrity check 1622 failed", _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A given by its LU factorization, N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the CRS sparse + storage format. An exception will be generated if you pass + matrix in some other format (HASH or SKS). + +INPUT PARAMETERS + A - LU factorization of the sparse matrix, must be NxN exactly + in CRS storage format + P, Q - pivot indexes from LU factorization + N - size of A, N>0 + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparselusolve(const sparsematrix* a, + /* Integer */ const ae_vector* p, + /* Integer */ const ae_vector* q, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_int_t i; + ae_int_t j; + double v; + ae_int_t n; + + ae_vector_clear(x); + _sparsesolverreport_clear(rep); + + n = sparsegetnrows(a, _state); + ae_assert(n>0, "SparseLUSolve: N<=0", _state); + ae_assert(sparsegetnrows(a, _state)==n, "SparseLUSolve: rows(A)!=N", _state); + ae_assert(sparsegetncols(a, _state)==n, "SparseLUSolve: cols(A)!=N", _state); + ae_assert(sparseiscrs(a, _state), "SparseLUSolve: A is not an SKS matrix", _state); + ae_assert(b->cnt>=n, "SparseLUSolve: length(B)cnt>=n, "SparseLUSolve: length(P)cnt>=n, "SparseLUSolve: length(Q)ptr.p_int[i]>=i&&p->ptr.p_int[i]ptr.p_int[i]>=i&&q->ptr.p_int[i]didx.ptr.p_int[i]==a->uidx.ptr.p_int[i]||a->vals.ptr.p_double[a->didx.ptr.p_int[i]]==0.0 ) + { + rep->terminationtype = -3; + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = (double)(0); + } + return; + } + } + for(i=0; i<=n-1; i++) + { + x->ptr.p_double[i] = b->ptr.p_double[i]; + } + for(i=0; i<=n-1; i++) + { + j = p->ptr.p_int[i]; + v = x->ptr.p_double[i]; + x->ptr.p_double[i] = x->ptr.p_double[j]; + x->ptr.p_double[j] = v; + } + sparsetrsv(a, ae_false, ae_true, 0, x, _state); + sparsetrsv(a, ae_true, ae_false, 0, x, _state); + for(i=n-1; i>=0; i--) + { + j = q->ptr.p_int[i]; + v = x->ptr.p_double[i]; + x->ptr.p_double[i] = x->ptr.p_double[j]; + x->ptr.p_double[j] = v; + } + rep->terminationtype = 1; +} + + +/************************************************************************* +Internal function which creates and solves a sparse augmented system + + ( | ) + ( REG1*I | A ) + ( | ) + (-----------------) + ( | ) + ( A' | -REG2*I) + ( | ) + +This function uses supernodal LDLT to factorize the system, then applies +iterative refinement (actually, a preconditioned GMRES which acts as an +improved version of the iterative refinement). + +It can be used to solve square nonsymmetric systems, or to solve +rectangular systems in a least squares sense. Its performance somewhat +deteriorates for rank-deficient systems. + +INPUT PARAMETERS + A - sparse matrix, M*N, CRS format + B - array[N], right part + Reg1F,Reg2F-regularizing factors used during the factorization of the + system, Reg1F>0, Reg2F>0 + Reg1R,Reg2R-regularizing factors used during the refinement stage, + Reg1R>=0, Reg2R>=0 + X - preallocated buffer + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + * rep.iterationscount - set ot an amount of GMRES + iterations performed + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +static void directsparsesolvers_sparsesolveaug(const sparsematrix* a, + /* Real */ const ae_vector* b, + double reg1f, + double reg2f, + double reg1r, + double reg2r, + ae_int_t gmresk, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t k; + ae_int_t jj; + ae_int_t j0; + ae_int_t j1; + ae_int_t m; + ae_int_t n; + ae_int_t nzaug; + sparsematrix aug; + ae_vector priorities; + ae_vector bx; + spcholanalysis analysis; + sparsesolverstate solver; + sparsesolverreport innerrep; + ae_int_t requesttype; + ae_vector rr; + ae_vector q; + ae_vector y; + ae_int_t priorityordering; + ae_int_t donotreusememory; + ae_int_t facttype; + + ae_frame_make(_state, &_frame_block); + memset(&aug, 0, sizeof(aug)); + memset(&priorities, 0, sizeof(priorities)); + memset(&bx, 0, sizeof(bx)); + memset(&analysis, 0, sizeof(analysis)); + memset(&solver, 0, sizeof(solver)); + memset(&innerrep, 0, sizeof(innerrep)); + memset(&rr, 0, sizeof(rr)); + memset(&q, 0, sizeof(q)); + memset(&y, 0, sizeof(y)); + _sparsematrix_init(&aug, _state, ae_true); + ae_vector_init(&priorities, 0, DT_INT, _state, ae_true); + ae_vector_init(&bx, 0, DT_REAL, _state, ae_true); + _spcholanalysis_init(&analysis, _state, ae_true); + _sparsesolverstate_init(&solver, _state, ae_true); + _sparsesolverreport_init(&innerrep, _state, ae_true); + ae_vector_init(&rr, 0, DT_REAL, _state, ae_true); + ae_vector_init(&q, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y, 0, DT_REAL, _state, ae_true); + + ae_assert(sparseiscrs(a, _state), "SparseSolveAug: A is not stored in the CRS format", _state); + m = sparsegetnrows(a, _state); + n = sparsegetncols(a, _state); + ae_assert(ae_isfinite(reg1f, _state)&&ae_fp_greater(reg1f,(double)(0)), "SparseSolveAug: Reg1F is non-positive", _state); + ae_assert(ae_isfinite(reg2f, _state)&&ae_fp_greater(reg2f,(double)(0)), "SparseSolveAug: Reg2F is non-positive", _state); + ae_assert(ae_isfinite(reg1r, _state)&&ae_fp_greater_eq(reg1r,(double)(0)), "SparseSolveAug: Reg1R is non-positive", _state); + ae_assert(ae_isfinite(reg2r, _state)&&ae_fp_greater_eq(reg2r,(double)(0)), "SparseSolveAug: Reg2R is non-positive", _state); + ae_assert(b->cnt>=m, "SparseSolveAug: length(B)cnt>=n, "SparseSolveAug: length(X)ridx.ptr.p_int[a->m]+n+m; + aug.matrixtype = 1; + aug.m = m+n; + aug.n = m+n; + iallocv(aug.m+1, &aug.ridx, _state); + iallocv(nzaug, &aug.idx, _state); + rallocv(nzaug, &aug.vals, _state); + aug.ridx.ptr.p_int[0] = 0; + for(i=0; i<=n-1; i++) + { + rr.ptr.p_double[i] = -reg2f; + aug.idx.ptr.p_int[i] = i; + aug.vals.ptr.p_double[i] = rr.ptr.p_double[i]; + aug.ridx.ptr.p_int[i+1] = i+1; + } + for(i=0; i<=m-1; i++) + { + rr.ptr.p_double[n+i] = reg1f; + k = aug.ridx.ptr.p_int[n+i]; + j0 = a->ridx.ptr.p_int[i]; + j1 = a->ridx.ptr.p_int[i+1]-1; + for(jj=j0; jj<=j1; jj++) + { + aug.idx.ptr.p_int[k] = a->idx.ptr.p_int[jj]; + aug.vals.ptr.p_double[k] = a->vals.ptr.p_double[jj]; + k = k+1; + } + aug.idx.ptr.p_int[k] = n+i; + aug.vals.ptr.p_double[k] = rr.ptr.p_double[n+i]; + k = k+1; + aug.ridx.ptr.p_int[n+i+1] = k; + } + ae_assert(aug.ridx.ptr.p_int[n+m]==nzaug, "SparseSolveAug: integrity check 2141 failed", _state); + sparsecreatecrsinplace(&aug, _state); + + /* + * Factorize augmented system + */ + facttype = 21; + priorityordering = 3; + donotreusememory = -1; + isetallocv(n+m, 1, &priorities, _state); + isetv(n, 0, &priorities, _state); + if( !spsymmanalyze(&aug, &priorities, 0.0, 0, facttype, priorityordering, donotreusememory, &analysis, _state) ) + { + ae_assert(ae_false, "SparseSolveAug: integrity check 4141 failed", _state); + } + while(!spsymmfactorize(&analysis, _state)) + { + + /* + * Factorization failure. Extremely rare, almost unable to reproduce. + */ + rmulv(n+m, 10.0, &rr, _state); + spsymmreloaddiagonal(&analysis, &rr, _state); + } + + /* + * Solve using GMRES as an improved iterative refinement + */ + rsetallocv(n+m, reg1r, &rr, _state); + rsetv(n, -reg2r, &rr, _state); + rallocv(m+n, &q, _state); + rallocv(m+n, &y, _state); + rsetallocv(m+n, 0.0, &bx, _state); + rcopyvx(m, b, 0, &bx, n, _state); + sparsesolvercreate(m+n, &solver, _state); + sparsesolversetalgogmres(&solver, gmresk, _state); + sparsesolversetcond(&solver, (double)10*ae_machineepsilon, maxits, _state); + sparsesolveroocstart(&solver, &bx, _state); + while(sparsesolverooccontinue(&solver, _state)) + { + sparsesolveroocgetrequestinfo(&solver, &requesttype, _state); + ae_assert(requesttype==0, "SPARSESOLVE: integrity check 8618 failed", _state); + sparsesolveroocgetrequestdata(&solver, &q, _state); + spsymmsolve(&analysis, &q, _state); + sparsegemv(a, 1.0, 0, &q, 0, 0.0, &y, n, _state); + sparsegemv(a, 1.0, 1, &q, n, 0.0, &y, 0, _state); + rmuladdv(m+n, &q, &rr, &y, _state); + sparsesolveroocsendresult(&solver, &y, _state); + } + sparsesolveroocstop(&solver, &bx, &innerrep, _state); + if( innerrep.terminationtype<=0 ) + { + rep->terminationtype = innerrep.terminationtype; + ae_frame_leave(_state); + return; + } + spsymmsolve(&analysis, &bx, _state); + rcopyvx(n, &bx, 0, x, 0, _state); + rep->terminationtype = 1; + rep->iterationscount = innerrep.iterationscount; + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + nleqstate* state, + ae_state *_state) +{ + + _nleqstate_clear(state); + + ae_assert(n>=1, "NLEQCreateLM: N<1!", _state); + ae_assert(m>=1, "NLEQCreateLM: M<1!", _state); + ae_assert(x->cnt>=n, "NLEQCreateLM: Length(X)n = n; + state->m = m; + nleqsetcond(state, (double)(0), 0, _state); + nleqsetxrep(state, ae_false, _state); + nleqsetstpmax(state, (double)(0), _state); + ae_vector_set_length(&state->x, n, _state); + ae_vector_set_length(&state->xbase, n, _state); + ae_matrix_set_length(&state->j, m, n, _state); + ae_vector_set_length(&state->fi, m, _state); + ae_vector_set_length(&state->rightpart, n, _state); + ae_vector_set_length(&state->candstep, n, _state); + nleqrestartfrom(state, x, _state); +} + + +/************************************************************************* +This function sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(nleqstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(epsf, _state), "NLEQSetCond: EpsF is not finite number!", _state); + ae_assert(ae_fp_greater_eq(epsf,(double)(0)), "NLEQSetCond: negative EpsF!", _state); + ae_assert(maxits>=0, "NLEQSetCond: negative MaxIts!", _state); + if( ae_fp_eq(epsf,(double)(0))&&maxits==0 ) + { + epsf = 1.0E-6; + } + state->epsf = epsf; + state->maxits = maxits; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when target function contains exp() or other fast +growing functions, and algorithm makes too large steps which lead to +overflow. This function allows us to reject steps that are too large (and +therefore expose us to the possible overflow) without actually calculating +function value at the x+stp*d. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state) +{ + + + ae_assert(ae_isfinite(stpmax, _state), "NLEQSetStpMax: StpMax is not finite!", _state); + ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "NLEQSetStpMax: StpMax<0!", _state); + state->stpmax = stpmax; +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey +*************************************************************************/ +ae_bool nleqiteration(nleqstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t m; + ae_int_t i; + double lambdaup; + double lambdadown; + double lambdav; + double rho; + double mu; + double stepnorm; + ae_bool b; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + m = state->rstate.ia.ptr.p_int[1]; + i = state->rstate.ia.ptr.p_int[2]; + b = state->rstate.ba.ptr.p_bool[0]; + lambdaup = state->rstate.ra.ptr.p_double[0]; + lambdadown = state->rstate.ra.ptr.p_double[1]; + lambdav = state->rstate.ra.ptr.p_double[2]; + rho = state->rstate.ra.ptr.p_double[3]; + mu = state->rstate.ra.ptr.p_double[4]; + stepnorm = state->rstate.ra.ptr.p_double[5]; + } + else + { + n = 359; + m = -58; + i = -919; + b = ae_true; + lambdaup = 81.0; + lambdadown = 255.0; + lambdav = 74.0; + rho = -788.0; + mu = 809.0; + stepnorm = 205.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + if( state->rstate.stage==4 ) + { + goto lbl_4; + } + + /* + * Routine body + */ + + /* + * Prepare + */ + n = state->n; + m = state->m; + state->repterminationtype = 0; + state->repiterationscount = 0; + state->repnfunc = 0; + state->repnjac = 0; + + /* + * Calculate F/G, initialize algorithm + */ + nleq_clearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + state->needf = ae_false; + state->repnfunc = state->repnfunc+1; + ae_v_move(&state->xbase.ptr.p_double[0], 1, &state->x.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->fbase = state->f; + state->fprev = ae_maxrealnumber; + if( !state->xrep ) + { + goto lbl_5; + } + + /* + * progress report + */ + nleq_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + state->xupdated = ae_false; +lbl_5: + if( ae_fp_less_eq(state->f,ae_sqr(state->epsf, _state)) ) + { + state->repterminationtype = 1; + result = ae_false; + return result; + } + + /* + * Main cycle + */ + lambdaup = (double)(10); + lambdadown = 0.3; + lambdav = 0.001; + rho = (double)(1); +lbl_7: + if( ae_false ) + { + goto lbl_8; + } + + /* + * Get Jacobian; + * before we get to this point we already have State.XBase filled + * with current point and State.FBase filled with function value + * at XBase + */ + nleq_clearrequestfields(state, _state); + state->needfij = ae_true; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + state->needfij = ae_false; + state->repnfunc = state->repnfunc+1; + state->repnjac = state->repnjac+1; + rmatrixmv(n, m, &state->j, 0, 0, 1, &state->fi, 0, &state->rightpart, 0, _state); + ae_v_muld(&state->rightpart.ptr.p_double[0], 1, ae_v_len(0,n-1), -1.0); + + /* + * Inner cycle: find good lambda + */ +lbl_9: + if( ae_false ) + { + goto lbl_10; + } + + /* + * Solve (J^T*J + (Lambda+Mu)*I)*y = J^T*F + * to get step d=-y where: + * * Mu=||F|| - is damping parameter for nonlinear system + * * Lambda - is additional Levenberg-Marquardt parameter + * for better convergence when far away from minimum + */ + for(i=0; i<=n-1; i++) + { + state->candstep.ptr.p_double[i] = (double)(0); + } + fblssolvecgx(&state->j, m, n, lambdav, &state->rightpart, &state->candstep, &state->cgbuf, _state); + + /* + * Normalize step (it must be no more than StpMax) + */ + stepnorm = (double)(0); + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->candstep.ptr.p_double[i],(double)(0)) ) + { + stepnorm = (double)(1); + break; + } + } + linminnormalized(&state->candstep, &stepnorm, n, _state); + if( ae_fp_neq(state->stpmax,(double)(0)) ) + { + stepnorm = ae_minreal(stepnorm, state->stpmax, _state); + } + + /* + * Test new step - is it good enough? + * * if not, Lambda is increased and we try again. + * * if step is good, we decrease Lambda and move on. + * + * We can break this cycle on two occasions: + * * step is so small that x+step==x (in floating point arithmetics) + * * lambda is so large + */ + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + ae_v_addd(&state->x.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); + b = ae_true; + for(i=0; i<=n-1; i++) + { + if( ae_fp_neq(state->x.ptr.p_double[i],state->xbase.ptr.p_double[i]) ) + { + b = ae_false; + break; + } + } + if( b ) + { + + /* + * Step is too small, force zero step and break + */ + stepnorm = (double)(0); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fbase; + goto lbl_10; + } + nleq_clearrequestfields(state, _state); + state->needf = ae_true; + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + state->needf = ae_false; + state->repnfunc = state->repnfunc+1; + if( ae_fp_less(state->f,state->fbase) ) + { + + /* + * function value decreased, move on + */ + nleq_decreaselambda(&lambdav, &rho, lambdadown, _state); + goto lbl_10; + } + if( !nleq_increaselambda(&lambdav, &rho, lambdaup, _state) ) + { + + /* + * Lambda is too large (near overflow), force zero step and break + */ + stepnorm = (double)(0); + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->f = state->fbase; + goto lbl_10; + } + goto lbl_9; +lbl_10: + + /* + * Accept step: + * * new position + * * new function value + */ + state->fbase = state->f; + ae_v_addd(&state->xbase.ptr.p_double[0], 1, &state->candstep.ptr.p_double[0], 1, ae_v_len(0,n-1), stepnorm); + state->repiterationscount = state->repiterationscount+1; + + /* + * Report new iteration + */ + if( !state->xrep ) + { + goto lbl_11; + } + nleq_clearrequestfields(state, _state); + state->xupdated = ae_true; + state->f = state->fbase; + ae_v_move(&state->x.ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,n-1)); + state->rstate.stage = 4; + goto lbl_rcomm; +lbl_4: + state->xupdated = ae_false; +lbl_11: + + /* + * Test stopping conditions on F, step (zero/non-zero) and MaxIts; + * If one of the conditions is met, RepTerminationType is changed. + */ + if( ae_fp_less_eq(ae_sqrt(state->f, _state),state->epsf) ) + { + state->repterminationtype = 1; + } + if( ae_fp_eq(stepnorm,(double)(0))&&state->repterminationtype==0 ) + { + state->repterminationtype = -4; + } + if( state->repiterationscount>=state->maxits&&state->maxits>0 ) + { + state->repterminationtype = 5; + } + if( state->repterminationtype!=0 ) + { + goto lbl_8; + } + + /* + * Now, iteration is finally over + */ + goto lbl_7; +lbl_8: + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = m; + state->rstate.ia.ptr.p_int[2] = i; + state->rstate.ba.ptr.p_bool[0] = b; + state->rstate.ra.ptr.p_double[0] = lambdaup; + state->rstate.ra.ptr.p_double[1] = lambdadown; + state->rstate.ra.ptr.p_double[2] = lambdav; + state->rstate.ra.ptr.p_double[3] = rho; + state->rstate.ra.ptr.p_double[4] = mu; + state->rstate.ra.ptr.p_double[5] = stepnorm; + return result; +} + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + * ActiveConstraints contains number of active constraints + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(const nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state) +{ + + ae_vector_clear(x); + _nleqreport_clear(rep); + + nleqresultsbuf(state, x, rep, _state); +} + + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(const nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state) +{ + + + if( x->cntn ) + { + ae_vector_set_length(x, state->n, _state); + } + ae_v_move(&x->ptr.p_double[0], 1, &state->xbase.ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + rep->iterationscount = state->repiterationscount; + rep->nfunc = state->repnfunc; + rep->njac = state->repnjac; + rep->terminationtype = state->repterminationtype; +} + + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinCGCreate call. + X - new starting point. + BndL - new lower bounds + BndU - new upper bounds + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqrestartfrom(nleqstate* state, + /* Real */ const ae_vector* x, + ae_state *_state) +{ + + + ae_assert(x->cnt>=state->n, "NLEQRestartFrom: Length(X)n, _state), "NLEQRestartFrom: X contains infinite or NaN values!", _state); + ae_v_move(&state->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,state->n-1)); + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; + nleq_clearrequestfields(state, _state); +} + + +/************************************************************************* +Sets V1 reverse communication protocol +*************************************************************************/ +void nleqsetprotocolv1(nleqstate* state, ae_state *_state) +{ + + + ae_vector_set_length(&state->rstate.ia, 2+1, _state); + ae_vector_set_length(&state->rstate.ba, 0+1, _state); + ae_vector_set_length(&state->rstate.ra, 5+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Clears request fileds (to be sure that we don't forgot to clear something) +*************************************************************************/ +static void nleq_clearrequestfields(nleqstate* state, ae_state *_state) +{ + + + state->needf = ae_false; + state->needfij = ae_false; + state->xupdated = ae_false; +} + + +/************************************************************************* +Increases lambda, returns False when there is a danger of overflow +*************************************************************************/ +static ae_bool nleq_increaselambda(double* lambdav, + double* nu, + double lambdaup, + ae_state *_state) +{ + double lnlambda; + double lnnu; + double lnlambdaup; + double lnmax; + ae_bool result; + + + result = ae_false; + lnlambda = ae_log(*lambdav, _state); + lnlambdaup = ae_log(lambdaup, _state); + lnnu = ae_log(*nu, _state); + lnmax = 0.5*ae_log(ae_maxrealnumber, _state); + if( ae_fp_greater(lnlambda+lnlambdaup+lnnu,lnmax) ) + { + return result; + } + if( ae_fp_greater(lnnu+ae_log((double)(2), _state),lnmax) ) + { + return result; + } + *lambdav = *lambdav*lambdaup*(*nu); + *nu = *nu*(double)2; + result = ae_true; + return result; +} + + +/************************************************************************* +Decreases lambda, but leaves it unchanged when there is danger of underflow. +*************************************************************************/ +static void nleq_decreaselambda(double* lambdav, + double* nu, + double lambdadown, + ae_state *_state) +{ + + + *nu = (double)(1); + if( ae_fp_less(ae_log(*lambdav, _state)+ae_log(lambdadown, _state),ae_log(ae_minrealnumber, _state)) ) + { + *lambdav = ae_minrealnumber; + } + else + { + *lambdav = *lambdav*lambdadown; + } +} + + +void _nleqstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nleqstate *p = (nleqstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->fi, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->j, 0, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); + ae_vector_init(&p->xbase, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->candstep, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->rightpart, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->cgbuf, 0, DT_REAL, _state, make_automatic); +} + + +void _nleqstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nleqstate *dst = (nleqstate*)_dst; + const nleqstate *src = (const nleqstate*)_src; + dst->n = src->n; + dst->m = src->m; + dst->epsf = src->epsf; + dst->maxits = src->maxits; + dst->xrep = src->xrep; + dst->stpmax = src->stpmax; + ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic); + dst->f = src->f; + ae_vector_init_copy(&dst->fi, &src->fi, _state, make_automatic); + ae_matrix_init_copy(&dst->j, &src->j, _state, make_automatic); + dst->needf = src->needf; + dst->needfij = src->needfij; + dst->xupdated = src->xupdated; + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); + dst->repiterationscount = src->repiterationscount; + dst->repnfunc = src->repnfunc; + dst->repnjac = src->repnjac; + dst->repterminationtype = src->repterminationtype; + ae_vector_init_copy(&dst->xbase, &src->xbase, _state, make_automatic); + dst->fbase = src->fbase; + dst->fprev = src->fprev; + ae_vector_init_copy(&dst->candstep, &src->candstep, _state, make_automatic); + ae_vector_init_copy(&dst->rightpart, &src->rightpart, _state, make_automatic); + ae_vector_init_copy(&dst->cgbuf, &src->cgbuf, _state, make_automatic); +} + + +void _nleqstate_clear(void* _p) +{ + nleqstate *p = (nleqstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->x); + ae_vector_clear(&p->fi); + ae_matrix_clear(&p->j); + _rcommstate_clear(&p->rstate); + ae_vector_clear(&p->xbase); + ae_vector_clear(&p->candstep); + ae_vector_clear(&p->rightpart); + ae_vector_clear(&p->cgbuf); +} + + +void _nleqstate_destroy(void* _p) +{ + nleqstate *p = (nleqstate*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->x); + ae_vector_destroy(&p->fi); + ae_matrix_destroy(&p->j); + _rcommstate_destroy(&p->rstate); + ae_vector_destroy(&p->xbase); + ae_vector_destroy(&p->candstep); + ae_vector_destroy(&p->rightpart); + ae_vector_destroy(&p->cgbuf); +} + + +void _nleqreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + nleqreport *p = (nleqreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _nleqreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + nleqreport *dst = (nleqreport*)_dst; + const nleqreport *src = (const nleqreport*)_src; + dst->iterationscount = src->iterationscount; + dst->nfunc = src->nfunc; + dst->njac = src->njac; + dst->terminationtype = src->terminationtype; +} + + +void _nleqreport_clear(void* _p) +{ + nleqreport *p = (nleqreport*)_p; + ae_touch_ptr((void*)p); +} + + +void _nleqreport_destroy(void* _p) +{ + nleqreport *p = (nleqreport*)_p; + ae_touch_ptr((void*)p); +} + + +#endif + +} + diff --git a/core/alglib/solvers.h b/core/alglib/solvers.h index ab9fb14e..0fa2289c 100644 --- a/core/alglib/solvers.h +++ b/core/alglib/solvers.h @@ -1,2016 +1,4864 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _solvers_pkg_h -#define _solvers_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "linalg.h" -#include "alglibmisc.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -typedef struct -{ - double r1; - double rinf; -} densesolverreport; -typedef struct -{ - double r2; - ae_matrix cx; - ae_int_t n; - ae_int_t k; -} densesolverlsreport; -typedef struct -{ - normestimatorstate nes; - ae_vector rx; - ae_vector b; - ae_int_t n; - ae_int_t m; - ae_int_t prectype; - ae_vector ui; - ae_vector uip1; - ae_vector vi; - ae_vector vip1; - ae_vector omegai; - ae_vector omegaip1; - double alphai; - double alphaip1; - double betai; - double betaip1; - double phibari; - double phibarip1; - double phii; - double rhobari; - double rhobarip1; - double rhoi; - double ci; - double si; - double theta; - double lambdai; - ae_vector d; - double anorm; - double bnorm2; - double dnorm; - double r2; - ae_vector x; - ae_vector mv; - ae_vector mtv; - double epsa; - double epsb; - double epsc; - ae_int_t maxits; - ae_bool xrep; - ae_bool xupdated; - ae_bool needmv; - ae_bool needmtv; - ae_bool needmv2; - ae_bool needvmv; - ae_bool needprec; - ae_int_t repiterationscount; - ae_int_t repnmv; - ae_int_t repterminationtype; - ae_bool running; - ae_vector tmpd; - ae_vector tmpx; - rcommstate rstate; -} linlsqrstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nmv; - ae_int_t terminationtype; -} linlsqrreport; -typedef struct -{ - ae_vector rx; - ae_vector b; - ae_int_t n; - ae_int_t prectype; - ae_vector cx; - ae_vector cr; - ae_vector cz; - ae_vector p; - ae_vector r; - ae_vector z; - double alpha; - double beta; - double r2; - double meritfunction; - ae_vector x; - ae_vector mv; - ae_vector pv; - double vmv; - ae_vector startx; - double epsf; - ae_int_t maxits; - ae_int_t itsbeforerestart; - ae_int_t itsbeforerupdate; - ae_bool xrep; - ae_bool xupdated; - ae_bool needmv; - ae_bool needmtv; - ae_bool needmv2; - ae_bool needvmv; - ae_bool needprec; - ae_int_t repiterationscount; - ae_int_t repnmv; - ae_int_t repterminationtype; - ae_bool running; - ae_vector tmpd; - rcommstate rstate; -} lincgstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nmv; - ae_int_t terminationtype; - double r2; -} lincgreport; -typedef struct -{ - ae_int_t n; - ae_int_t m; - double epsf; - ae_int_t maxits; - ae_bool xrep; - double stpmax; - ae_vector x; - double f; - ae_vector fi; - ae_matrix j; - ae_bool needf; - ae_bool needfij; - ae_bool xupdated; - rcommstate rstate; - ae_int_t repiterationscount; - ae_int_t repnfunc; - ae_int_t repnjac; - ae_int_t repterminationtype; - ae_vector xbase; - double fbase; - double fprev; - ae_vector candstep; - ae_vector rightpart; - ae_vector cgbuf; -} nleqstate; -typedef struct -{ - ae_int_t iterationscount; - ae_int_t nfunc; - ae_int_t njac; - ae_int_t terminationtype; -} nleqreport; - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - -/************************************************************************* - -*************************************************************************/ -class _densesolverreport_owner -{ -public: - _densesolverreport_owner(); - _densesolverreport_owner(const _densesolverreport_owner &rhs); - _densesolverreport_owner& operator=(const _densesolverreport_owner &rhs); - virtual ~_densesolverreport_owner(); - alglib_impl::densesolverreport* c_ptr(); - alglib_impl::densesolverreport* c_ptr() const; -protected: - alglib_impl::densesolverreport *p_struct; -}; -class densesolverreport : public _densesolverreport_owner -{ -public: - densesolverreport(); - densesolverreport(const densesolverreport &rhs); - densesolverreport& operator=(const densesolverreport &rhs); - virtual ~densesolverreport(); - double &r1; - double &rinf; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _densesolverlsreport_owner -{ -public: - _densesolverlsreport_owner(); - _densesolverlsreport_owner(const _densesolverlsreport_owner &rhs); - _densesolverlsreport_owner& operator=(const _densesolverlsreport_owner &rhs); - virtual ~_densesolverlsreport_owner(); - alglib_impl::densesolverlsreport* c_ptr(); - alglib_impl::densesolverlsreport* c_ptr() const; -protected: - alglib_impl::densesolverlsreport *p_struct; -}; -class densesolverlsreport : public _densesolverlsreport_owner -{ -public: - densesolverlsreport(); - densesolverlsreport(const densesolverlsreport &rhs); - densesolverlsreport& operator=(const densesolverlsreport &rhs); - virtual ~densesolverlsreport(); - double &r2; - real_2d_array cx; - ae_int_t &n; - ae_int_t &k; - -}; - -/************************************************************************* -This object stores state of the LinLSQR method. - -You should use ALGLIB functions to work with this object. -*************************************************************************/ -class _linlsqrstate_owner -{ -public: - _linlsqrstate_owner(); - _linlsqrstate_owner(const _linlsqrstate_owner &rhs); - _linlsqrstate_owner& operator=(const _linlsqrstate_owner &rhs); - virtual ~_linlsqrstate_owner(); - alglib_impl::linlsqrstate* c_ptr(); - alglib_impl::linlsqrstate* c_ptr() const; -protected: - alglib_impl::linlsqrstate *p_struct; -}; -class linlsqrstate : public _linlsqrstate_owner -{ -public: - linlsqrstate(); - linlsqrstate(const linlsqrstate &rhs); - linlsqrstate& operator=(const linlsqrstate &rhs); - virtual ~linlsqrstate(); - -}; - - -/************************************************************************* - -*************************************************************************/ -class _linlsqrreport_owner -{ -public: - _linlsqrreport_owner(); - _linlsqrreport_owner(const _linlsqrreport_owner &rhs); - _linlsqrreport_owner& operator=(const _linlsqrreport_owner &rhs); - virtual ~_linlsqrreport_owner(); - alglib_impl::linlsqrreport* c_ptr(); - alglib_impl::linlsqrreport* c_ptr() const; -protected: - alglib_impl::linlsqrreport *p_struct; -}; -class linlsqrreport : public _linlsqrreport_owner -{ -public: - linlsqrreport(); - linlsqrreport(const linlsqrreport &rhs); - linlsqrreport& operator=(const linlsqrreport &rhs); - virtual ~linlsqrreport(); - ae_int_t &iterationscount; - ae_int_t &nmv; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -This object stores state of the linear CG method. - -You should use ALGLIB functions to work with this object. -Never try to access its fields directly! -*************************************************************************/ -class _lincgstate_owner -{ -public: - _lincgstate_owner(); - _lincgstate_owner(const _lincgstate_owner &rhs); - _lincgstate_owner& operator=(const _lincgstate_owner &rhs); - virtual ~_lincgstate_owner(); - alglib_impl::lincgstate* c_ptr(); - alglib_impl::lincgstate* c_ptr() const; -protected: - alglib_impl::lincgstate *p_struct; -}; -class lincgstate : public _lincgstate_owner -{ -public: - lincgstate(); - lincgstate(const lincgstate &rhs); - lincgstate& operator=(const lincgstate &rhs); - virtual ~lincgstate(); - -}; - - -/************************************************************************* - -*************************************************************************/ -class _lincgreport_owner -{ -public: - _lincgreport_owner(); - _lincgreport_owner(const _lincgreport_owner &rhs); - _lincgreport_owner& operator=(const _lincgreport_owner &rhs); - virtual ~_lincgreport_owner(); - alglib_impl::lincgreport* c_ptr(); - alglib_impl::lincgreport* c_ptr() const; -protected: - alglib_impl::lincgreport *p_struct; -}; -class lincgreport : public _lincgreport_owner -{ -public: - lincgreport(); - lincgreport(const lincgreport &rhs); - lincgreport& operator=(const lincgreport &rhs); - virtual ~lincgreport(); - ae_int_t &iterationscount; - ae_int_t &nmv; - ae_int_t &terminationtype; - double &r2; - -}; - -/************************************************************************* - -*************************************************************************/ -class _nleqstate_owner -{ -public: - _nleqstate_owner(); - _nleqstate_owner(const _nleqstate_owner &rhs); - _nleqstate_owner& operator=(const _nleqstate_owner &rhs); - virtual ~_nleqstate_owner(); - alglib_impl::nleqstate* c_ptr(); - alglib_impl::nleqstate* c_ptr() const; -protected: - alglib_impl::nleqstate *p_struct; -}; -class nleqstate : public _nleqstate_owner -{ -public: - nleqstate(); - nleqstate(const nleqstate &rhs); - nleqstate& operator=(const nleqstate &rhs); - virtual ~nleqstate(); - ae_bool &needf; - ae_bool &needfij; - ae_bool &xupdated; - double &f; - real_1d_array fi; - real_2d_array j; - real_1d_array x; - -}; - - -/************************************************************************* - -*************************************************************************/ -class _nleqreport_owner -{ -public: - _nleqreport_owner(); - _nleqreport_owner(const _nleqreport_owner &rhs); - _nleqreport_owner& operator=(const _nleqreport_owner &rhs); - virtual ~_nleqreport_owner(); - alglib_impl::nleqreport* c_ptr(); - alglib_impl::nleqreport* c_ptr() const; -protected: - alglib_impl::nleqreport *p_struct; -}; -class nleqreport : public _nleqreport_owner -{ -public: - nleqreport(); - nleqreport(const nleqreport &rhs); - nleqreport& operator=(const nleqreport &rhs); - virtual ~nleqreport(); - ae_int_t &iterationscount; - ae_int_t &nfunc; - ae_int_t &njac; - ae_int_t &terminationtype; - -}; - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where A is NxN non-denegerate -real matrix, x and b are vectors. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - return code: - * -3 A is singular, or VERY close to singular. - X is filled by zeros in such cases. - * -1 N<=0 was passed - * 1 task is solved (but matrix A may be ill-conditioned, - check R1/RInf parameters for condition numbers). - Rep - solver report, see below for more info - X - array[0..N-1], it contains: - * solution of A*x=b if A is non-singular (well-conditioned - or ill-conditioned, but not very close to singular) - * zeros, if A is singular or VERY close to singular - (in this case Info=-3). - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R1 reciprocal of condition number: 1/cond(A), 1-norm. -* RInf reciprocal of condition number: 1/cond(A), inf-norm. - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); - - -/************************************************************************* -Dense solver. - -Similar to RMatrixSolve() but solves task with multiple right parts (where -b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* optional iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, real_2d_array &x); - - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*X=B, where A is NxN non-denegerate -real matrix given by its LU decomposition, X and B are NxM real matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); - - -/************************************************************************* -Dense solver. - -Similar to RMatrixLUSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); - - -/************************************************************************* -Dense solver. - -This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS -LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have -both A and its LU decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); - - -/************************************************************************* -Dense solver. - -Similar to RMatrixMixedSolve() but solves task with multiple right parts -(where b and x are NxM matrices). - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3+M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - RFS - iterative refinement switch: - * True - refinement is used. - Less performance, more precision. - * False - refinement is not used. - More performance, less precision. - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result - P - array[0..N-1], pivots array, RMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation - -No iterative refinement is provided because exact form of original matrix -is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(M*N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* iterative refinement -* O(N^2) complexity - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result - P - array[0..N-1], pivots array, CMatrixLU result - N - size of A - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolveM - Rep - same as in RMatrixSolveM - X - same as in RMatrixSolveM - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for symmetric positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for SPD matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-SPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, real_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for SPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, ae_int_t &info, densesolverreport &rep, real_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolveM(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3+M*N^2) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve. - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixSolve(), but for Hermitian positive definite -matrices. - -Algorithm features: -* automatic detection of degenerate cases -* condition number estimation -* O(N^3) complexity -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - A - array[0..N-1,0..N-1], system matrix - N - size of A - IsUpper - what half of A is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Returns -3 for non-HPD matrices. - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolveM(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(M*N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - HPDMatrixCholesky result - N - size of CHA - IsUpper - what half of CHA is provided - B - array[0..N-1,0..M-1], right part - M - right part size - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, ae_int_t &info, densesolverreport &rep, complex_2d_array &x); - - -/************************************************************************* -Dense solver. Same as RMatrixLUSolve(), but for HPD matrices represented -by their Cholesky decomposition. - -Algorithm features: -* automatic detection of degenerate cases -* O(N^2) complexity -* condition number estimation -* matrix is represented by its upper or lower triangle - -No iterative refinement is provided because such partial representation of -matrix does not allow efficient calculation of extra-precise matrix-vector -products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you -need iterative refinement. - -INPUT PARAMETERS - CHA - array[0..N-1,0..N-1], Cholesky decomposition, - SPDMatrixCholesky result - N - size of A - IsUpper - what half of CHA is provided - B - array[0..N-1], right part - -OUTPUT PARAMETERS - Info - same as in RMatrixSolve - Rep - same as in RMatrixSolve - X - same as in RMatrixSolve - - -- ALGLIB -- - Copyright 27.01.2010 by Bochkanov Sergey -*************************************************************************/ -void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, ae_int_t &info, densesolverreport &rep, complex_1d_array &x); - - -/************************************************************************* -Dense solver. - -This subroutine finds solution of the linear system A*X=B with non-square, -possibly degenerate A. System is solved in the least squares sense, and -general least squares solution X = X0 + CX*y which minimizes |A*X-B| is -returned. If A is non-degenerate, solution in the usual sense is returned. - -Algorithm features: -* automatic detection (and correct handling!) of degenerate cases -* iterative refinement -* O(N^3) complexity - -INPUT PARAMETERS - A - array[0..NRows-1,0..NCols-1], system matrix - NRows - vertical size of A - NCols - horizontal size of A - B - array[0..NCols-1], right part - Threshold- a number in [0,1]. Singular values beyond Threshold are - considered zero. Set it to 0.0, if you don't understand - what it means, so the solver will choose good value on its - own. - -OUTPUT PARAMETERS - Info - return code: - * -4 SVD subroutine failed - * -1 if NRows<=0 or NCols<=0 or Threshold<0 was passed - * 1 if task is solved - Rep - solver report, see below for more info - X - array[0..N-1,0..M-1], it contains: - * solution of A*X=B (even for singular A) - * zeros, if SVD subroutine failed - -SOLVER REPORT - -Subroutine sets following fields of the Rep structure: -* R2 reciprocal of condition number: 1/cond(A), 2-norm. -* N = NCols -* K dim(Null(A)) -* CX array[0..N-1,0..K-1], kernel of A. - Columns of CX store such vectors that A*CX[i]=0. - - -- ALGLIB -- - Copyright 24.08.2009 by Bochkanov Sergey -*************************************************************************/ -void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, ae_int_t &info, densesolverlsreport &rep, real_1d_array &x); - -/************************************************************************* -This function initializes linear LSQR Solver. This solver is used to solve -non-symmetric (and, possibly, non-square) problems. Least squares solution -is returned for non-compatible systems. - -USAGE: -1. User initializes algorithm state with LinLSQRCreate() call -2. User tunes solver parameters with LinLSQRSetCond() and other functions -3. User calls LinLSQRSolveSparse() function which takes algorithm state - and SparseMatrix object. -4. User calls LinLSQRResults() to get solution -5. Optionally, user may call LinLSQRSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinLSQRState structure. - -INPUT PARAMETERS: - M - number of rows in A - N - number of variables, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state); - - -/************************************************************************* -This function changes preconditioning settings of LinLSQQSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecunit(const linlsqrstate &state); - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetprecdiag(const linlsqrstate &state); - - -/************************************************************************* -This function sets optional Tikhonov regularization coefficient. -It is zero by default. - -INPUT PARAMETERS: - LambdaI - regularization factor, LambdaI>=0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetlambdai(const linlsqrstate &state, const double lambdai); - - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse M*N matrix in the CRS format (you MUST contvert it - to CRS format by calling SparseConvertToCRS() function - BEFORE you pass it to this function). - B - right part, array[M] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinLSQRSetPrecUnit(). However, preconditioning cost is low - and preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsolvesparse(const linlsqrstate &state, const sparsematrix &a, const real_1d_array &b); - - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. - EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| - MaxIts - algorithm will be stopped if number of iterations - more than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will -be setted as default values. - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetcond(const linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits); - - -/************************************************************************* -LSQR solver: results. - -This function must be called after LinLSQRSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * 1 ||Rk||<=EpsB*||B|| - * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - X contains best point found so far. - (sometimes returned on singular systems) - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 30.11.2011 by Bochkanov Sergey -*************************************************************************/ -void linlsqrsetxrep(const linlsqrstate &state, const bool needxrep); - -/************************************************************************* -This function initializes linear CG Solver. This solver is used to solve -symmetric positive definite problems. If you want to solve nonsymmetric -(or non-positive definite) problem you may use LinLSQR solver provided by -ALGLIB. - -USAGE: -1. User initializes algorithm state with LinCGCreate() call -2. User tunes solver parameters with LinCGSetCond() and other functions -3. Optionally, user sets starting point with LinCGSetStartingPoint() -4. User calls LinCGSolveSparse() function which takes algorithm state and - SparseMatrix object. -5. User calls LinCGResults() to get solution -6. Optionally, user may call LinCGSolveSparse() again to solve another - problem with different matrix and/or right part without reinitializing - LinCGState structure. - -INPUT PARAMETERS: - N - problem dimension, N>0 - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgcreate(const ae_int_t n, lincgstate &state); - - -/************************************************************************* -This function sets starting point. -By default, zero starting point is used. - -INPUT PARAMETERS: - X - starting point, array[N] - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetstartingpoint(const lincgstate &state, const real_1d_array &x); - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. By default, SolveSparse() uses diagonal preconditioner, but if -you want to use solver without preconditioning, you can call this function -which forces solver to use unit matrix for preconditioning. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecunit(const lincgstate &state); - - -/************************************************************************* -This function changes preconditioning settings of LinCGSolveSparse() -function. LinCGSolveSparse() will use diagonal of the system matrix as -preconditioner. This preconditioning mode is active by default. - -INPUT PARAMETERS: - State - structure which stores algorithm state - - -- ALGLIB -- - Copyright 19.11.2012 by Bochkanov Sergey -*************************************************************************/ -void lincgsetprecdiag(const lincgstate &state); - - -/************************************************************************* -This function sets stopping criteria. - -INPUT PARAMETERS: - EpsF - algorithm will be stopped if norm of residual is less than - EpsF*||b||. - MaxIts - algorithm will be stopped if number of iterations is more - than MaxIts. - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - -NOTES: -If both EpsF and MaxIts are zero then small EpsF will be set to small -value. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetcond(const lincgstate &state, const double epsf, const ae_int_t maxits); - - -/************************************************************************* -Procedure for solution of A*x=b with sparse A. - -INPUT PARAMETERS: - State - algorithm state - A - sparse matrix in the CRS format (you MUST contvert it to - CRS format by calling SparseConvertToCRS() function). - IsUpper - whether upper or lower triangle of A is used: - * IsUpper=True => only upper triangle is used and lower - triangle is not referenced at all - * IsUpper=False => only lower triangle is used and upper - triangle is not referenced at all - B - right part, array[N] - -RESULT: - This function returns no result. - You can get solution by calling LinCGResults() - -NOTE: this function uses lightweight preconditioning - multiplication by - inverse of diag(A). If you want, you can turn preconditioning off by - calling LinCGSetPrecUnit(). However, preconditioning cost is low and - preconditioner is very important for solution of badly scaled - problems. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsolvesparse(const lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b); - - -/************************************************************************* -CG-solver: results. - -This function must be called after LinCGSolve - -INPUT PARAMETERS: - State - algorithm state - -OUTPUT PARAMETERS: - X - array[N], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -5 input matrix is either not positive definite, - too large or too small - * -4 overflow/underflow during solution - (ill conditioned problem) - * 1 ||residual||<=EpsF*||b|| - * 5 MaxIts steps was taken - * 7 rounding errors prevent further progress, - best point found is returned - * Rep.IterationsCount contains iterations count - * NMV contains number of matrix-vector calculations - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep); - - -/************************************************************************* -This function sets restart frequency. By default, algorithm is restarted -after N subsequent iterations. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrestartfreq(const lincgstate &state, const ae_int_t srf); - - -/************************************************************************* -This function sets frequency of residual recalculations. - -Algorithm updates residual r_k using iterative formula, but recalculates -it from scratch after each 10 iterations. It is done to avoid accumulation -of numerical errors and to stop algorithm when r_k starts to grow. - -Such low update frequence (1/10) gives very little overhead, but makes -algorithm a bit more robust against numerical errors. However, you may -change it - -INPUT PARAMETERS: - Freq - desired update frequency, Freq>=0. - Zero value means that no updates will be done. - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetrupdatefreq(const lincgstate &state, const ae_int_t freq); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to MinCGOptimize(). - - -- ALGLIB -- - Copyright 14.11.2011 by Bochkanov Sergey -*************************************************************************/ -void lincgsetxrep(const lincgstate &state, const bool needxrep); - -/************************************************************************* - LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER - -DESCRIPTION: -This algorithm solves system of nonlinear equations - F[0](x[0], ..., x[n-1]) = 0 - F[1](x[0], ..., x[n-1]) = 0 - ... - F[M-1](x[0], ..., x[n-1]) = 0 -with M/N do not necessarily coincide. Algorithm converges quadratically -under following conditions: - * the solution set XS is nonempty - * for some xs in XS there exist such neighbourhood N(xs) that: - * vector function F(x) and its Jacobian J(x) are continuously - differentiable on N - * ||F(x)|| provides local error bound on N, i.e. there exists such - c1, that ||F(x)||>c1*distance(x,XS) -Note that these conditions are much more weaker than usual non-singularity -conditions. For example, algorithm will converge for any affine function -F (whether its Jacobian singular or not). - - -REQUIREMENTS: -Algorithm will request following information during its operation: -* function vector F[] and Jacobian matrix at given point X -* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X - - -USAGE: -1. User initializes algorithm state with NLEQCreateLM() call -2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and - other functions -3. User calls NLEQSolve() function which takes algorithm state and - pointers (delegates, etc.) to callback functions which calculate merit - function value and Jacobian. -4. User calls NLEQResults() to get solution -5. Optionally, user may call NLEQRestartFrom() to solve another problem - with same parameters (N/M) but another starting point and/or another - function vector. NLEQRestartFrom() allows to reuse already initialized - structure. - - -INPUT PARAMETERS: - N - space dimension, N>1: - * if provided, only leading N elements of X are used - * if not provided, determined automatically from size of X - M - system size - X - starting point - - -OUTPUT PARAMETERS: - State - structure which stores algorithm state - - -NOTES: -1. you may tune stopping conditions with NLEQSetCond() function -2. if target function contains exp() or other fast growing functions, and - optimization algorithm makes too large steps which leads to overflow, - use NLEQSetStpMax() function to bound algorithm's steps. -3. this algorithm is a slightly modified implementation of the method - described in 'Levenberg-Marquardt method for constrained nonlinear - equations with strong local convergence properties' by Christian Kanzow - Nobuo Yamashita and Masao Fukushima and further developed in 'On the - convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and - Ya-Xiang Yuan. - - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state); -void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state); - - -/************************************************************************* -This function sets stopping conditions for the nonlinear solver - -INPUT PARAMETERS: - State - structure which stores algorithm state - EpsF - >=0 - The subroutine finishes its work if on k+1-th iteration - the condition ||F||<=EpsF is satisfied - MaxIts - maximum number of iterations. If MaxIts=0, the number of - iterations is unlimited. - -Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic -stopping criterion selection (small EpsF). - -NOTES: - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetcond(const nleqstate &state, const double epsf, const ae_int_t maxits); - - -/************************************************************************* -This function turns on/off reporting. - -INPUT PARAMETERS: - State - structure which stores algorithm state - NeedXRep- whether iteration reports are needed or not - -If NeedXRep is True, algorithm will call rep() callback function if it is -provided to NLEQSolve(). - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetxrep(const nleqstate &state, const bool needxrep); - - -/************************************************************************* -This function sets maximum step length - -INPUT PARAMETERS: - State - structure which stores algorithm state - StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't - want to limit step length. - -Use this subroutine when target function contains exp() or other fast -growing functions, and algorithm makes too large steps which lead to -overflow. This function allows us to reject steps that are too large (and -therefore expose us to the possible overflow) without actually calculating -function value at the x+stp*d. - - -- ALGLIB -- - Copyright 20.08.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqsetstpmax(const nleqstate &state, const double stpmax); - - -/************************************************************************* -This function provides reverse communication interface -Reverse communication interface is not documented or recommended to use. -See below for functions which provide better documented API -*************************************************************************/ -bool nleqiteration(const nleqstate &state); - - -/************************************************************************* -This family of functions is used to launcn iterations of nonlinear solver - -These functions accept following parameters: - state - algorithm state - func - callback which calculates function (or merit function) - value func at given point x - jac - callback which calculates function vector fi[] - and Jacobian jac at given point x - rep - optional callback which is called after each iteration - can be NULL - ptr - optional pointer which is passed to func/grad/hess/jac/rep - can be NULL - - - -- ALGLIB -- - Copyright 20.03.2009 by Bochkanov Sergey - -*************************************************************************/ -void nleqsolve(nleqstate &state, - void (*func)(const real_1d_array &x, double &func, void *ptr), - void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), - void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, - void *ptr = NULL); - - -/************************************************************************* -NLEQ solver results - -INPUT PARAMETERS: - State - algorithm state. - -OUTPUT PARAMETERS: - X - array[0..N-1], solution - Rep - optimization report: - * Rep.TerminationType completion code: - * -4 ERROR: algorithm has converged to the - stationary point Xf which is local minimum of - f=F[0]^2+...+F[m-1]^2, but is not solution of - nonlinear system. - * 1 sqrt(f)<=EpsF. - * 5 MaxIts steps was taken - * 7 stopping conditions are too stringent, - further improvement is impossible - * Rep.IterationsCount contains iterations count - * NFEV contains number of function calculations - * ActiveConstraints contains number of active constraints - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep); - - -/************************************************************************* -NLEQ solver results - -Buffered implementation of NLEQResults(), which uses pre-allocated buffer -to store X[]. If buffer size is too small, it resizes buffer. It is -intended to be used in the inner cycles of performance critical algorithms -where array reallocation penalty is too large to be ignored. - - -- ALGLIB -- - Copyright 20.08.2009 by Bochkanov Sergey -*************************************************************************/ -void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep); - - -/************************************************************************* -This subroutine restarts CG algorithm from new point. All optimization -parameters are left unchanged. - -This function allows to solve multiple optimization problems (which -must have same number of dimensions) without object reallocation penalty. - -INPUT PARAMETERS: - State - structure used for reverse communication previously - allocated with MinCGCreate call. - X - new starting point. - BndL - new lower bounds - BndU - new upper bounds - - -- ALGLIB -- - Copyright 30.07.2010 by Bochkanov Sergey -*************************************************************************/ -void nleqrestartfrom(const nleqstate &state, const real_1d_array &x); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void rmatrixsolve(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -void rmatrixsolvem(/* Real */ ae_matrix* a, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_bool rfs, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -void rmatrixlusolve(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -void rmatrixlusolvem(/* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -void rmatrixmixedsolve(/* Real */ ae_matrix* a, - /* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -void rmatrixmixedsolvem(/* Real */ ae_matrix* a, - /* Real */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -void cmatrixsolvem(/* Complex */ ae_matrix* a, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_bool rfs, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -void cmatrixsolve(/* Complex */ ae_matrix* a, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state); -void cmatrixlusolvem(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -void cmatrixlusolve(/* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state); -void cmatrixmixedsolvem(/* Complex */ ae_matrix* a, - /* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -void cmatrixmixedsolve(/* Complex */ ae_matrix* a, - /* Complex */ ae_matrix* lua, - /* Integer */ ae_vector* p, - ae_int_t n, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state); -void spdmatrixsolvem(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -void spdmatrixsolve(/* Real */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -void spdmatrixcholeskysolvem(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_matrix* x, - ae_state *_state); -void spdmatrixcholeskysolve(/* Real */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -void hpdmatrixsolvem(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -void hpdmatrixsolve(/* Complex */ ae_matrix* a, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state); -void hpdmatrixcholeskysolvem(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_matrix* b, - ae_int_t m, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_matrix* x, - ae_state *_state); -void hpdmatrixcholeskysolve(/* Complex */ ae_matrix* cha, - ae_int_t n, - ae_bool isupper, - /* Complex */ ae_vector* b, - ae_int_t* info, - densesolverreport* rep, - /* Complex */ ae_vector* x, - ae_state *_state); -void rmatrixsolvels(/* Real */ ae_matrix* a, - ae_int_t nrows, - ae_int_t ncols, - /* Real */ ae_vector* b, - double threshold, - ae_int_t* info, - densesolverlsreport* rep, - /* Real */ ae_vector* x, - ae_state *_state); -ae_bool _densesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _densesolverreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _densesolverreport_clear(void* _p); -void _densesolverreport_destroy(void* _p); -ae_bool _densesolverlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _densesolverlsreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _densesolverlsreport_clear(void* _p); -void _densesolverlsreport_destroy(void* _p); -void linlsqrcreate(ae_int_t m, - ae_int_t n, - linlsqrstate* state, - ae_state *_state); -void linlsqrsetb(linlsqrstate* state, - /* Real */ ae_vector* b, - ae_state *_state); -void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state); -void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state); -void linlsqrsetlambdai(linlsqrstate* state, - double lambdai, - ae_state *_state); -ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state); -void linlsqrsolvesparse(linlsqrstate* state, - sparsematrix* a, - /* Real */ ae_vector* b, - ae_state *_state); -void linlsqrsetcond(linlsqrstate* state, - double epsa, - double epsb, - ae_int_t maxits, - ae_state *_state); -void linlsqrresults(linlsqrstate* state, - /* Real */ ae_vector* x, - linlsqrreport* rep, - ae_state *_state); -void linlsqrsetxrep(linlsqrstate* state, - ae_bool needxrep, - ae_state *_state); -void linlsqrrestart(linlsqrstate* state, ae_state *_state); -ae_bool _linlsqrstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _linlsqrstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _linlsqrstate_clear(void* _p); -void _linlsqrstate_destroy(void* _p); -ae_bool _linlsqrreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _linlsqrreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _linlsqrreport_clear(void* _p); -void _linlsqrreport_destroy(void* _p); -void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state); -void lincgsetstartingpoint(lincgstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -void lincgsetb(lincgstate* state, - /* Real */ ae_vector* b, - ae_state *_state); -void lincgsetprecunit(lincgstate* state, ae_state *_state); -void lincgsetprecdiag(lincgstate* state, ae_state *_state); -void lincgsetcond(lincgstate* state, - double epsf, - ae_int_t maxits, - ae_state *_state); -ae_bool lincgiteration(lincgstate* state, ae_state *_state); -void lincgsolvesparse(lincgstate* state, - sparsematrix* a, - ae_bool isupper, - /* Real */ ae_vector* b, - ae_state *_state); -void lincgresults(lincgstate* state, - /* Real */ ae_vector* x, - lincgreport* rep, - ae_state *_state); -void lincgsetrestartfreq(lincgstate* state, - ae_int_t srf, - ae_state *_state); -void lincgsetrupdatefreq(lincgstate* state, - ae_int_t freq, - ae_state *_state); -void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state); -void lincgrestart(lincgstate* state, ae_state *_state); -ae_bool _lincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _lincgstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _lincgstate_clear(void* _p); -void _lincgstate_destroy(void* _p); -ae_bool _lincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _lincgreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _lincgreport_clear(void* _p); -void _lincgreport_destroy(void* _p); -void nleqcreatelm(ae_int_t n, - ae_int_t m, - /* Real */ ae_vector* x, - nleqstate* state, - ae_state *_state); -void nleqsetcond(nleqstate* state, - double epsf, - ae_int_t maxits, - ae_state *_state); -void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state); -void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state); -ae_bool nleqiteration(nleqstate* state, ae_state *_state); -void nleqresults(nleqstate* state, - /* Real */ ae_vector* x, - nleqreport* rep, - ae_state *_state); -void nleqresultsbuf(nleqstate* state, - /* Real */ ae_vector* x, - nleqreport* rep, - ae_state *_state); -void nleqrestartfrom(nleqstate* state, - /* Real */ ae_vector* x, - ae_state *_state); -ae_bool _nleqstate_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _nleqstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _nleqstate_clear(void* _p); -void _nleqstate_destroy(void* _p); -ae_bool _nleqreport_init(void* _p, ae_state *_state, ae_bool make_automatic); -ae_bool _nleqreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic); -void _nleqreport_clear(void* _p); -void _nleqreport_destroy(void* _p); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _solvers_pkg_h +#define _solvers_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" +#include "linalg.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + double maxerr; +} polynomialsolverreport; +#endif +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t terminationtype; + double r1; + double rinf; +} densesolverreport; +typedef struct +{ + ae_int_t terminationtype; + double r2; + ae_matrix cx; + ae_int_t n; + ae_int_t k; +} densesolverlsreport; +#endif +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t terminationtype; + ae_int_t nmv; + ae_int_t iterationscount; + double r2; +} sparsesolverreport; +typedef struct +{ + ae_int_t n; + ae_vector x0; + double epsf; + ae_int_t maxits; + ae_int_t algotype; + ae_int_t gmresk; + ae_bool xrep; + ae_bool running; + ae_bool userterminationneeded; + ae_vector b; + ae_vector xf; + ae_int_t repiterationscount; + ae_int_t repnmv; + ae_int_t repterminationtype; + double repr2; + ae_int_t requesttype; + ae_vector x; + ae_vector ax; + double reply1; + ae_vector wrkb; + sparsematrix convbuf; + fblsgmresstate gmressolver; + rcommstate rstate; +} sparsesolverstate; +#endif +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_vector rx; + ae_vector b; + ae_int_t n; + ae_int_t prectype; + ae_vector cx; + ae_vector cr; + ae_vector cz; + ae_vector p; + ae_vector r; + ae_vector z; + double alpha; + double beta; + double r2; + double meritfunction; + ae_vector x; + ae_vector mv; + ae_vector pv; + double vmv; + ae_vector startx; + double epsf; + ae_int_t maxits; + ae_int_t itsbeforerestart; + ae_int_t itsbeforerupdate; + ae_bool xrep; + ae_bool xupdated; + ae_bool needmv; + ae_bool needmtv; + ae_bool needmv2; + ae_bool needvmv; + ae_bool needprec; + ae_int_t repiterationscount; + ae_int_t repnmv; + ae_int_t repterminationtype; + ae_bool running; + ae_vector tmpd; + rcommstate rstate; +} lincgstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nmv; + ae_int_t terminationtype; + double r2; +} lincgreport; +#endif +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + normestimatorstate nes; + ae_vector rx; + ae_vector b; + ae_int_t n; + ae_int_t m; + ae_int_t prectype; + ae_vector ui; + ae_vector uip1; + ae_vector vi; + ae_vector vip1; + ae_vector omegai; + ae_vector omegaip1; + double alphai; + double alphaip1; + double betai; + double betaip1; + double phibari; + double phibarip1; + double phii; + double rhobari; + double rhobarip1; + double rhoi; + double ci; + double si; + double theta; + double lambdai; + ae_vector d; + double anorm; + double bnorm2; + double dnorm; + double r2; + ae_vector x; + ae_vector mv; + ae_vector mtv; + double epsa; + double epsb; + double epsc; + ae_int_t maxits; + ae_bool xrep; + ae_bool xupdated; + ae_bool needmv; + ae_bool needmtv; + ae_bool needmv2; + ae_bool needvmv; + ae_bool needprec; + ae_int_t repiterationscount; + ae_int_t repnmv; + ae_int_t repterminationtype; + ae_bool running; + ae_bool userterminationneeded; + ae_vector tmpd; + ae_vector tmpx; + rcommstate rstate; +} linlsqrstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nmv; + ae_int_t terminationtype; +} linlsqrreport; +#endif +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t m; + double epsf; + ae_int_t maxits; + ae_bool xrep; + double stpmax; + ae_vector x; + double f; + ae_vector fi; + ae_matrix j; + ae_bool needf; + ae_bool needfij; + ae_bool xupdated; + rcommstate rstate; + ae_int_t repiterationscount; + ae_int_t repnfunc; + ae_int_t repnjac; + ae_int_t repterminationtype; + ae_vector xbase; + double fbase; + double fprev; + ae_vector candstep; + ae_vector rightpart; + ae_vector cgbuf; +} nleqstate; +typedef struct +{ + ae_int_t iterationscount; + ae_int_t nfunc; + ae_int_t njac; + ae_int_t terminationtype; +} nleqreport; +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) +class _polynomialsolverreport_owner; +class polynomialsolverreport; + + +/************************************************************************* + +*************************************************************************/ +class _polynomialsolverreport_owner +{ +public: + _polynomialsolverreport_owner(); + _polynomialsolverreport_owner(alglib_impl::polynomialsolverreport *attach_to); + _polynomialsolverreport_owner(const _polynomialsolverreport_owner &rhs); + _polynomialsolverreport_owner& operator=(const _polynomialsolverreport_owner &rhs); + virtual ~_polynomialsolverreport_owner(); + alglib_impl::polynomialsolverreport* c_ptr(); + const alglib_impl::polynomialsolverreport* c_ptr() const; +protected: + alglib_impl::polynomialsolverreport *p_struct; + bool is_attached; +}; +class polynomialsolverreport : public _polynomialsolverreport_owner +{ +public: + polynomialsolverreport(); + polynomialsolverreport(alglib_impl::polynomialsolverreport *attach_to); + polynomialsolverreport(const polynomialsolverreport &rhs); + polynomialsolverreport& operator=(const polynomialsolverreport &rhs); + virtual ~polynomialsolverreport(); + double &maxerr; + + +}; +#endif + +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +class _densesolverreport_owner; +class densesolverreport; +class _densesolverlsreport_owner; +class densesolverlsreport; + + +/************************************************************************* + +*************************************************************************/ +class _densesolverreport_owner +{ +public: + _densesolverreport_owner(); + _densesolverreport_owner(alglib_impl::densesolverreport *attach_to); + _densesolverreport_owner(const _densesolverreport_owner &rhs); + _densesolverreport_owner& operator=(const _densesolverreport_owner &rhs); + virtual ~_densesolverreport_owner(); + alglib_impl::densesolverreport* c_ptr(); + const alglib_impl::densesolverreport* c_ptr() const; +protected: + alglib_impl::densesolverreport *p_struct; + bool is_attached; +}; +class densesolverreport : public _densesolverreport_owner +{ +public: + densesolverreport(); + densesolverreport(alglib_impl::densesolverreport *attach_to); + densesolverreport(const densesolverreport &rhs); + densesolverreport& operator=(const densesolverreport &rhs); + virtual ~densesolverreport(); + ae_int_t &terminationtype; + double &r1; + double &rinf; + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _densesolverlsreport_owner +{ +public: + _densesolverlsreport_owner(); + _densesolverlsreport_owner(alglib_impl::densesolverlsreport *attach_to); + _densesolverlsreport_owner(const _densesolverlsreport_owner &rhs); + _densesolverlsreport_owner& operator=(const _densesolverlsreport_owner &rhs); + virtual ~_densesolverlsreport_owner(); + alglib_impl::densesolverlsreport* c_ptr(); + const alglib_impl::densesolverlsreport* c_ptr() const; +protected: + alglib_impl::densesolverlsreport *p_struct; + bool is_attached; +}; +class densesolverlsreport : public _densesolverlsreport_owner +{ +public: + densesolverlsreport(); + densesolverlsreport(alglib_impl::densesolverlsreport *attach_to); + densesolverlsreport(const densesolverlsreport &rhs); + densesolverlsreport& operator=(const densesolverlsreport &rhs); + virtual ~densesolverlsreport(); + ae_int_t &terminationtype; + double &r2; + real_2d_array cx; + ae_int_t &n; + ae_int_t &k; + + +}; +#endif + +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +class _sparsesolverreport_owner; +class sparsesolverreport; +class _sparsesolverstate_owner; +class sparsesolverstate; + + +/************************************************************************* +This structure is a sparse solver report (both direct and iterative solvers +use this structure). + +Following fields can be accessed by users: +* TerminationType (specific error codes depend on the solver being used, + with positive values ALWAYS signaling that something useful is returned + in X, and negative values ALWAYS meaning critical failures. +* NMV - number of matrix-vector products performed (0 for direct solvers) +* IterationsCount - inner iterations count (0 for direct solvers) +* R2 - squared residual +*************************************************************************/ +class _sparsesolverreport_owner +{ +public: + _sparsesolverreport_owner(); + _sparsesolverreport_owner(alglib_impl::sparsesolverreport *attach_to); + _sparsesolverreport_owner(const _sparsesolverreport_owner &rhs); + _sparsesolverreport_owner& operator=(const _sparsesolverreport_owner &rhs); + virtual ~_sparsesolverreport_owner(); + alglib_impl::sparsesolverreport* c_ptr(); + const alglib_impl::sparsesolverreport* c_ptr() const; +protected: + alglib_impl::sparsesolverreport *p_struct; + bool is_attached; +}; +class sparsesolverreport : public _sparsesolverreport_owner +{ +public: + sparsesolverreport(); + sparsesolverreport(alglib_impl::sparsesolverreport *attach_to); + sparsesolverreport(const sparsesolverreport &rhs); + sparsesolverreport& operator=(const sparsesolverreport &rhs); + virtual ~sparsesolverreport(); + ae_int_t &terminationtype; + ae_int_t &nmv; + ae_int_t &iterationscount; + double &r2; + + +}; + + +/************************************************************************* +This object stores state of the sparse linear solver object. + +You should use ALGLIB functions to work with this object. +Never try to access its fields directly! +*************************************************************************/ +class _sparsesolverstate_owner +{ +public: + _sparsesolverstate_owner(); + _sparsesolverstate_owner(alglib_impl::sparsesolverstate *attach_to); + _sparsesolverstate_owner(const _sparsesolverstate_owner &rhs); + _sparsesolverstate_owner& operator=(const _sparsesolverstate_owner &rhs); + virtual ~_sparsesolverstate_owner(); + alglib_impl::sparsesolverstate* c_ptr(); + const alglib_impl::sparsesolverstate* c_ptr() const; +protected: + alglib_impl::sparsesolverstate *p_struct; + bool is_attached; +}; +class sparsesolverstate : public _sparsesolverstate_owner +{ +public: + sparsesolverstate(); + sparsesolverstate(alglib_impl::sparsesolverstate *attach_to); + sparsesolverstate(const sparsesolverstate &rhs); + sparsesolverstate& operator=(const sparsesolverstate &rhs); + virtual ~sparsesolverstate(); + + +}; +#endif + +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +class _lincgstate_owner; +class lincgstate; +class _lincgreport_owner; +class lincgreport; + + +/************************************************************************* +This object stores state of the linear CG method. + +You should use ALGLIB functions to work with this object. +Never try to access its fields directly! +*************************************************************************/ +class _lincgstate_owner +{ +public: + _lincgstate_owner(); + _lincgstate_owner(alglib_impl::lincgstate *attach_to); + _lincgstate_owner(const _lincgstate_owner &rhs); + _lincgstate_owner& operator=(const _lincgstate_owner &rhs); + virtual ~_lincgstate_owner(); + alglib_impl::lincgstate* c_ptr(); + const alglib_impl::lincgstate* c_ptr() const; +protected: + alglib_impl::lincgstate *p_struct; + bool is_attached; +}; +class lincgstate : public _lincgstate_owner +{ +public: + lincgstate(); + lincgstate(alglib_impl::lincgstate *attach_to); + lincgstate(const lincgstate &rhs); + lincgstate& operator=(const lincgstate &rhs); + virtual ~lincgstate(); + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _lincgreport_owner +{ +public: + _lincgreport_owner(); + _lincgreport_owner(alglib_impl::lincgreport *attach_to); + _lincgreport_owner(const _lincgreport_owner &rhs); + _lincgreport_owner& operator=(const _lincgreport_owner &rhs); + virtual ~_lincgreport_owner(); + alglib_impl::lincgreport* c_ptr(); + const alglib_impl::lincgreport* c_ptr() const; +protected: + alglib_impl::lincgreport *p_struct; + bool is_attached; +}; +class lincgreport : public _lincgreport_owner +{ +public: + lincgreport(); + lincgreport(alglib_impl::lincgreport *attach_to); + lincgreport(const lincgreport &rhs); + lincgreport& operator=(const lincgreport &rhs); + virtual ~lincgreport(); + ae_int_t &iterationscount; + ae_int_t &nmv; + ae_int_t &terminationtype; + double &r2; + + +}; +#endif + +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +class _linlsqrstate_owner; +class linlsqrstate; +class _linlsqrreport_owner; +class linlsqrreport; + + +/************************************************************************* +This object stores state of the LinLSQR method. + +You should use ALGLIB functions to work with this object. +*************************************************************************/ +class _linlsqrstate_owner +{ +public: + _linlsqrstate_owner(); + _linlsqrstate_owner(alglib_impl::linlsqrstate *attach_to); + _linlsqrstate_owner(const _linlsqrstate_owner &rhs); + _linlsqrstate_owner& operator=(const _linlsqrstate_owner &rhs); + virtual ~_linlsqrstate_owner(); + alglib_impl::linlsqrstate* c_ptr(); + const alglib_impl::linlsqrstate* c_ptr() const; +protected: + alglib_impl::linlsqrstate *p_struct; + bool is_attached; +}; +class linlsqrstate : public _linlsqrstate_owner +{ +public: + linlsqrstate(); + linlsqrstate(alglib_impl::linlsqrstate *attach_to); + linlsqrstate(const linlsqrstate &rhs); + linlsqrstate& operator=(const linlsqrstate &rhs); + virtual ~linlsqrstate(); + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _linlsqrreport_owner +{ +public: + _linlsqrreport_owner(); + _linlsqrreport_owner(alglib_impl::linlsqrreport *attach_to); + _linlsqrreport_owner(const _linlsqrreport_owner &rhs); + _linlsqrreport_owner& operator=(const _linlsqrreport_owner &rhs); + virtual ~_linlsqrreport_owner(); + alglib_impl::linlsqrreport* c_ptr(); + const alglib_impl::linlsqrreport* c_ptr() const; +protected: + alglib_impl::linlsqrreport *p_struct; + bool is_attached; +}; +class linlsqrreport : public _linlsqrreport_owner +{ +public: + linlsqrreport(); + linlsqrreport(alglib_impl::linlsqrreport *attach_to); + linlsqrreport(const linlsqrreport &rhs); + linlsqrreport& operator=(const linlsqrreport &rhs); + virtual ~linlsqrreport(); + ae_int_t &iterationscount; + ae_int_t &nmv; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +class _nleqstate_owner; +class nleqstate; +class _nleqreport_owner; +class nleqreport; + + +/************************************************************************* + +*************************************************************************/ +class _nleqstate_owner +{ +public: + _nleqstate_owner(); + _nleqstate_owner(alglib_impl::nleqstate *attach_to); + _nleqstate_owner(const _nleqstate_owner &rhs); + _nleqstate_owner& operator=(const _nleqstate_owner &rhs); + virtual ~_nleqstate_owner(); + alglib_impl::nleqstate* c_ptr(); + const alglib_impl::nleqstate* c_ptr() const; +protected: + alglib_impl::nleqstate *p_struct; + bool is_attached; +}; +class nleqstate : public _nleqstate_owner +{ +public: + nleqstate(); + nleqstate(alglib_impl::nleqstate *attach_to); + nleqstate(const nleqstate &rhs); + nleqstate& operator=(const nleqstate &rhs); + virtual ~nleqstate(); + ae_bool &needf; + ae_bool &needfij; + ae_bool &xupdated; + double &f; + real_1d_array fi; + real_2d_array j; + real_1d_array x; + + +}; + + +/************************************************************************* + +*************************************************************************/ +class _nleqreport_owner +{ +public: + _nleqreport_owner(); + _nleqreport_owner(alglib_impl::nleqreport *attach_to); + _nleqreport_owner(const _nleqreport_owner &rhs); + _nleqreport_owner& operator=(const _nleqreport_owner &rhs); + virtual ~_nleqreport_owner(); + alglib_impl::nleqreport* c_ptr(); + const alglib_impl::nleqreport* c_ptr() const; +protected: + alglib_impl::nleqreport *p_struct; + bool is_attached; +}; +class nleqreport : public _nleqreport_owner +{ +public: + nleqreport(); + nleqreport(alglib_impl::nleqreport *attach_to); + nleqreport(const nleqreport &rhs); + nleqreport& operator=(const nleqreport &rhs); + virtual ~nleqreport(); + ae_int_t &iterationscount; + ae_int_t &nfunc; + ae_int_t &njac; + ae_int_t &terminationtype; + + +}; +#endif + +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Polynomial root finding. + +This function returns all roots of the polynomial + P(x) = a0 + a1*x + a2*x^2 + ... + an*x^n +Both real and complex roots are returned (see below). + +INPUT PARAMETERS: + A - array[N+1], polynomial coefficients: + * A[0] is constant term + * A[N] is a coefficient of X^N + N - polynomial degree + +OUTPUT PARAMETERS: + X - array of complex roots: + * for isolated real root, X[I] is strictly real: IMAGE(X[I])=0 + * complex roots are always returned in pairs - roots occupy + positions I and I+1, with: + * X[I+1]=Conj(X[I]) + * IMAGE(X[I]) > 0 + * IMAGE(X[I+1]) = -IMAGE(X[I]) < 0 + * multiple real roots may have non-zero imaginary part due + to roundoff errors. There is no reliable way to distinguish + real root of multiplicity 2 from two complex roots in + the presence of roundoff errors. + Rep - report, additional information, following fields are set: + * Rep.MaxErr - max( |P(xi)| ) for i=0..N-1. This field + allows to quickly estimate "quality" of the roots being + returned. + +NOTE: this function uses companion matrix method to find roots. In case + internal EVD solver fails do find eigenvalues, exception is + generated. + +NOTE: roots are not "polished" and no matrix balancing is performed + for them. + + -- ALGLIB -- + Copyright 24.02.2014 by Bochkanov Sergey +*************************************************************************/ +void polynomialsolve(const real_1d_array &a, const ae_int_t n, complex_1d_array &x, polynomialsolverreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Dense solver for A*x=b with N*N real matrix A and N*1 real vectorx x and +b. This is "slow-but-feature rich" version of the linear solver. Faster +version is RMatrixSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It is also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolve(const real_2d_array &a, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixsolve(const real_2d_array &a, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix, x and b are vectors. This is a "fast" version of linear +solver which does NOT provide any additional functions like condition +number estimation or iterative refinement. + +Algorithm features: +* efficient algorithm O(N^3) complexity +* no performance overhead from additional functionality + +If you need condition number estimation or iterative refinement, use more +feature-rich version - RMatrixSolve(). + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsolvefast(const real_2d_array &a, const ae_int_t n, real_1d_array &b, const xparams _xparams = alglib::xdefault); +bool rmatrixsolvefast(const real_2d_array &a, real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "slow-but-robust" version of linear +solver with additional functionality like condition number estimation. +There also exists faster version - RMatrixSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* optional iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. It also very significant on small matrices. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, RMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvem(const real_2d_array &a, const ae_int_t n, const real_2d_array &b, const ae_int_t m, const bool rfs, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixsolvem(const real_2d_array &a, const real_2d_array &b, const bool rfs, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixSolve() but solves task with multiple right parts (where +b and x are NxM matrices). This is "fast" version of linear solver which +does NOT offer additional functions like condition number estimation or +iterative refinement. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional functionality, highest performance + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True for well-conditioned matrix + False for extremely badly conditioned or exactly singular problem + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, real_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool rmatrixsolvemfast(const real_2d_array &a, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "slow-but-robust" version of the linear LU-based solver. Faster version +is RMatrixLUSolveFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, the following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixlusolve(const real_2d_array &lua, const integer_1d_array &p, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where A is NxN non-denegerate +real matrix given by its LU decomposition, x and b are real vectors. This +is "fast-without-any-checks" version of the linear LU-based solver. Slower +but more robust version is RMatrixLUSolve() function. + +Algorithm features: +* O(N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, real_1d_array &b, const xparams _xparams = alglib::xdefault); +bool rmatrixlusolvefast(const real_2d_array &lua, const integer_1d_array &p, real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts +(where b and x are NxM matrices). This is "robust-but-slow" version of +LU-based solver which performs additional checks for non-degeneracy of +inputs (condition number estimation). If you need best performance, use +"fast-without-any-checks" version, RMatrixLUSolveMFast(). + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! RMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[N,N], LU decomposition, RMatrixLU result + P - array[N], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixlusolvem(const real_2d_array &lua, const integer_1d_array &p, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixLUSolve() but solves task with multiple right parts, +where b and x are NxM matrices. This is "fast-without-any-checks" version +of LU-based solver. It does not estimate condition number of a system, +so it is extremely fast. If you need better detection of near-degenerate +cases, use RMatrixLUSolveM() function. + +Algorithm features: +* O(M*N^2) complexity +* fast algorithm without ANY additional checks, just triangular solver + +INPUT PARAMETERS: + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, real_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool rmatrixlusolvemfast(const real_2d_array &lua, const integer_1d_array &p, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +This subroutine solves a system A*x=b, where BOTH ORIGINAL A AND ITS +LU DECOMPOSITION ARE KNOWN. You can use it if for some reasons you have +both A and its LU decomposition. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixmixedsolve(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +Similar to RMatrixMixedSolve() but solves task with multiple right parts +(where b and x are NxM matrices). + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixmixedsolvem(const real_2d_array &a, const real_2d_array &lua, const integer_1d_array &p, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Slow-but-feature-rich" version which provides +additional functions, at the cost of slower performance. Faster version +may be invoked with CMatrixSolveMFast() function. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3+M*N^2) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + RFS - iterative refinement switch: + * True - refinement is used. + Less performance, more precision. + * False - refinement is not used. + More performance, less precision. + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, const bool rfs, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixsolvem(const complex_2d_array &a, const complex_2d_array &b, const bool rfs, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense solver for A*X=B with N*N complex matrix A, N*M complex +matrices X and B. "Fast-but-lightweight" version which provides just +triangular solver - and no additional functions like iterative refinement +or condition number estimation. + +Algorithm features: +* O(N^3+M*N^2) complexity +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 16.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, complex_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool cmatrixsolvemfast(const complex_2d_array &a, complex_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^3) complexity + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system + ! and performs iterative refinement, which results in + ! significant performance penalty when compared with "fast" + ! version which just performs LU decomposition and calls + ! triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, CMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixsolve(const complex_2d_array &a, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixsolve(const complex_2d_array &a, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense solver for A*x=B with N*N complex matrix A and N*1 complex +vectors x and b. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3) complexity +* no additional time consuming features, just triangular solver + +INPUT PARAMETERS: + A - array[0..N-1,0..N-1], system matrix + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, complex_1d_array &b, const xparams _xparams = alglib::xdefault); +bool cmatrixsolvefast(const complex_2d_array &a, complex_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Slow-but-feature-rich" +version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveMFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixlusolvem(const complex_2d_array &lua, const integer_1d_array &p, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N complex A given by its LU decomposition, +and N*M matrices X and B (multiple right sides). "Fast-but-lightweight" +version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* no additional time-consuming features + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, RMatrixLU result + P - array[0..N-1], pivots array, RMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, complex_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool cmatrixlusolvemfast(const complex_2d_array &lua, const integer_1d_array &p, complex_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense linear solver for A*x=b with complex N*N A given by its LU +decomposition and N*1 vectors x and b. This is "slow-but-robust" version +of the complex linear solver with additional features which add +significant performance overhead. Faster version is CMatrixLUSolveFast() +function. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation + +No iterative refinement is provided because exact form of original matrix +is not known to subroutine. Use CMatrixSolve or CMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems. + ! + ! In such cases we strongly recommend you to use faster solver, + ! CMatrixLUSolveFast() function. + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixlusolve(const complex_2d_array &lua, const integer_1d_array &p, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complex dense linear solver for A*x=b with N*N complex A given by its LU +decomposition and N*1 vectors x and b. This is fast lightweight version +of solver, which is significantly faster than CMatrixLUSolve(), but does +not provide additional information (like condition numbers). + +Algorithm features: +* O(N^2) complexity +* no additional time-consuming features, just triangular solver + +INPUT PARAMETERS + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +NOTE: unlike CMatrixLUSolve(), this function does NOT check for + near-degeneracy of input matrix. It checks for EXACT degeneracy, + because this check is easy to do. However, very badly conditioned + matrices may went unnoticed. + + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, complex_1d_array &b, const xparams _xparams = alglib::xdefault); +bool cmatrixlusolvefast(const complex_2d_array &lua, const integer_1d_array &p, complex_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolveM(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(M*N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixmixedsolvem(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. Same as RMatrixMixedSolve(), but for complex matrices. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* iterative refinement +* O(N^2) complexity + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + LUA - array[0..N-1,0..N-1], LU decomposition, CMatrixLU result + P - array[0..N-1], pivots array, CMatrixLU result + N - size of A + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or exactly singular matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const ae_int_t n, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void cmatrixmixedsolve(const complex_2d_array &a, const complex_2d_array &lua, const integer_1d_array &p, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "slow-but-feature-rich" version of the solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N,M], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolvem(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixsolvem(const real_2d_array &a, const bool isupper, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A, and +N*M vectors X and B. It is "fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N,M], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixsolvemfast(const real_2d_array &a, const ae_int_t n, const bool isupper, real_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool spdmatrixsolvemfast(const real_2d_array &a, const bool isupper, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, SPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixsolve(const real_2d_array &a, const ae_int_t n, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixsolve(const real_2d_array &a, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense linear solver for A*x=b with N*N real symmetric positive definite +matrix A, N*1 vectors x and b. "Fast-but-lightweight" version of the +solver. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N], it contains: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixsolvefast(const real_2d_array &a, const ae_int_t n, const bool isupper, real_1d_array &b, const xparams _xparams = alglib::xdefault); +bool spdmatrixsolvefast(const real_2d_array &a, const bool isupper, real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "slow-but- +feature-rich" version of the solver which estimates condition number of +the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveMFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolvem(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_2d_array &b, const ae_int_t m, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixcholeskysolvem(const real_2d_array &cha, const bool isupper, const real_2d_array &b, real_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*M vectors X and B. It is "fast-but- +lightweight" version of the solver which just solves linear system, +without any additional functions. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional functionality + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholeskysolvemfast(const real_2d_array &cha, const ae_int_t n, const bool isupper, real_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool spdmatrixcholeskysolvemfast(const real_2d_array &cha, const bool isupper, real_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "slow- +but-feature-rich" version of the solver which, in addition to the +solution, performs condition number estimation. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! SPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N]: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void spdmatrixcholeskysolve(const real_2d_array &cha, const ae_int_t n, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void spdmatrixcholeskysolve(const real_2d_array &cha, const bool isupper, const real_1d_array &b, real_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b with N*N symmetric positive definite matrix A given +by its Cholesky decomposition, and N*1 real vectors x and b. This is "fast- +but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[N], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or exactly singular system + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +bool spdmatrixcholeskysolvefast(const real_2d_array &cha, const ae_int_t n, const bool isupper, real_1d_array &b, const xparams _xparams = alglib::xdefault); +bool spdmatrixcholeskysolvefast(const real_2d_array &cha, const bool isupper, real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. + ! + ! This performance penalty is especially apparent when you use + ! ALGLIB parallel capabilities (condition number estimation is + ! inherently sequential). It also becomes significant for + ! small-scale problems (N<100). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixSolveMFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolvem(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixsolvem(const complex_2d_array &a, const bool isupper, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B, with N*N Hermitian positive definite matrix A and +N*M complex matrices X and B. "Fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^3+M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming features like condition number estimation + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1,0..M-1], right part + M - right part size + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixsolvemfast(const complex_2d_array &a, const ae_int_t n, const bool isupper, complex_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool hpdmatrixsolvemfast(const complex_2d_array &a, const bool isupper, complex_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Slow-but-feature-rich" version of the +solver. + +Algorithm features: +* automatic detection of degenerate cases +* condition number estimation +* O(N^3) complexity +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just performs Cholesky + ! decomposition and calls triangular solver. + ! + ! This performance penalty is especially visible in the + ! multithreaded mode, because both condition number estimation + ! and iterative refinement are inherently sequential + ! calculations. + ! + ! Thus, if you need high performance and if you are pretty sure + ! that your system is well conditioned, we strongly recommend + ! you to use faster solver, HPDMatrixSolveFast() function. + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - same as in RMatrixSolve + X - same as in RMatrixSolve + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixsolve(const complex_2d_array &a, const ae_int_t n, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixsolve(const complex_2d_array &a, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b, with N*N Hermitian positive definite matrix A, and +N*1 complex vectors x and b. "Fast-but-lightweight" version of the +solver without additional functions. + +Algorithm features: +* O(N^3) complexity +* matrix is represented by its upper or lower triangle +* no additional time consuming functions + +INPUT PARAMETERS + A - array[0..N-1,0..N-1], system matrix + N - size of A + IsUpper - what half of A is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[0..N-1]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 17.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixsolvefast(const complex_2d_array &a, const ae_int_t n, const bool isupper, complex_1d_array &b, const xparams _xparams = alglib::xdefault); +bool hpdmatrixsolvefast(const complex_2d_array &a, const bool isupper, complex_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"slow-but-feature-rich" version of the solver which, in addition to the +solution, estimates condition number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(M*N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in significant performance penalty when + ! compared with "fast" version which just calls triangular + ! solver. Amount of overhead introduced depends on M (the + ! larger - the more efficient). + ! + ! This performance penalty is insignificant when compared with + ! cost of large Cholesky decomposition. However, if you call + ! this function many times for the same left side, this + ! overhead BECOMES significant. It also becomes significant + ! for small-scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveMFast() function. + + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_2d_array &b, const ae_int_t m, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixcholeskysolvem(const complex_2d_array &cha, const bool isupper, const complex_2d_array &b, complex_2d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*X=B with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition and N*M complex matrices X and B. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(M*N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[N,N], Cholesky decomposition, + HPDMatrixCholesky result + N - size of CHA + IsUpper - what half of CHA is provided + B - array[N,M], right part + M - right part size + +OUTPUT PARAMETERS: + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, complex_2d_array &b, const ae_int_t m, const xparams _xparams = alglib::xdefault); +bool hpdmatrixcholeskysolvemfast(const complex_2d_array &cha, const bool isupper, complex_2d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"slow-but-feature-rich" version of the solver which estimates condition +number of the system. + +Algorithm features: +* automatic detection of degenerate cases +* O(N^2) complexity +* condition number estimation +* matrix is represented by its upper or lower triangle + +No iterative refinement is provided because such partial representation of +matrix does not allow efficient calculation of extra-precise matrix-vector +products for large matrices. Use RMatrixSolve or RMatrixMixedSolve if you +need iterative refinement. + +IMPORTANT: ! this function is NOT the most efficient linear solver provided + ! by ALGLIB. It estimates condition number of linear system, + ! which results in 10-15x performance penalty when compared + ! with "fast" version which just calls triangular solver. + ! + ! This performance penalty is insignificant when compared with + ! cost of large LU decomposition. However, if you call this + ! function many times for the same left side, this overhead + ! BECOMES significant. It also becomes significant for small- + ! scale problems (N<50). + ! + ! In such cases we strongly recommend you to use faster solver, + ! HPDMatrixCholeskySolveFast() function. + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + Rep - additional report, following fields are set: + * rep.terminationtype >0 for success + -3 for badly conditioned or indefinite matrix + * rep.r1 condition number in 1-norm + * rep.rinf condition number in inf-norm + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + + -- ALGLIB -- + Copyright 27.01.2010 by Bochkanov Sergey +*************************************************************************/ +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const ae_int_t n, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); +void hpdmatrixcholeskysolve(const complex_2d_array &cha, const bool isupper, const complex_1d_array &b, complex_1d_array &x, densesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver for A*x=b with N*N Hermitian positive definite matrix A given +by its Cholesky decomposition, and N*1 complex vectors x and b. This is +"fast-but-lightweight" version of the solver. + +Algorithm features: +* O(N^2) complexity +* matrix is represented by its upper or lower triangle +* no additional time-consuming features + +INPUT PARAMETERS + CHA - array[0..N-1,0..N-1], Cholesky decomposition, + SPDMatrixCholesky result + N - size of A + IsUpper - what half of CHA is provided + B - array[0..N-1], right part + +OUTPUT PARAMETERS + B - array[N]: + * result=true => overwritten by solution + * result=false => filled by zeros + +RETURNS: + True, if the system was solved + False, for an extremely badly conditioned or indefinite system + + -- ALGLIB -- + Copyright 18.03.2015 by Bochkanov Sergey +*************************************************************************/ +bool hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const ae_int_t n, const bool isupper, complex_1d_array &b, const xparams _xparams = alglib::xdefault); +bool hpdmatrixcholeskysolvefast(const complex_2d_array &cha, const bool isupper, complex_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Dense solver. + +This subroutine finds solution of the linear system A*X=B with non-square, +possibly degenerate A. System is solved in the least squares sense, and +general least squares solution X = X0 + CX*y which minimizes |A*X-B| is +returned. If A is non-degenerate, solution in the usual sense is returned. + +Algorithm features: +* automatic detection (and correct handling!) of degenerate cases +* iterative refinement +* O(N^3) complexity + +INPUT PARAMETERS + A - array[0..NRows-1,0..NCols-1], system matrix + NRows - vertical size of A + NCols - horizontal size of A + B - array[0..NCols-1], right part + Threshold- a number in [0,1]. Singular values beyond Threshold*Largest are + considered zero. Set it to 0.0, if you don't understand + what it means, so the solver will choose good value on its + own. + +OUTPUT PARAMETERS + Rep - solver report, see below for more info + X - array[0..N-1,0..M-1], it contains: + * solution of A*X=B (even for singular A) + * zeros, if SVD subroutine failed + +SOLVER REPORT + +Subroutine sets following fields of the Rep structure: +* TerminationType is set to: + * -4 for SVD failure + * >0 for success +* R2 reciprocal of condition number: 1/cond(A), 2-norm. +* N = NCols +* K dim(Null(A)) +* CX array[0..N-1,0..K-1], kernel of A. + Columns of CX store such vectors that A*CX[i]=0. + + ! FREE EDITION OF ALGLIB: + ! + ! Free Edition of ALGLIB supports following important features for this + ! function: + ! * C++ version: x64 SIMD support using C++ intrinsics + ! * C# version: x64 SIMD support using NET5/NetCore hardware intrinsics + ! + ! We recommend you to read 'Compiling ALGLIB' section of the ALGLIB + ! Reference Manual in order to find out how to activate SIMD support + ! in ALGLIB. + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + + -- ALGLIB -- + Copyright 24.08.2009 by Bochkanov Sergey +*************************************************************************/ +void rmatrixsolvels(const real_2d_array &a, const ae_int_t nrows, const ae_int_t ncols, const real_1d_array &b, const double threshold, real_1d_array &x, densesolverlsreport &rep, const xparams _xparams = alglib::xdefault); +void rmatrixsolvels(const real_2d_array &a, const real_1d_array &b, const double threshold, real_1d_array &x, densesolverlsreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Solving sparse symmetric linear system A*x=b using GMRES(k) method. Sparse +symmetric A is given by its lower or upper triangle. + +NOTE: use SparseSolveGMRES() to solve system with nonsymmetric A. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvesymmetricgmres(const sparsematrix &a, const bool isupper, const real_1d_array &b, const ae_int_t k, const double epsf, const ae_int_t maxits, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Solving sparse linear system A*x=b using GMRES(k) method. + +This function provides convenience API for an 'expert' interface provided +by SparseSolverState class. Use SparseSolver API if you need advanced +functions like providing initial point, using out-of-core API and so on. + +INPUT PARAMETERS: + A - sparse NxN matrix in any sparse storage format. Using CRS + format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + K - k parameter for GMRES(k), k>=0. Zero value means that + algorithm will choose it automatically. + EpsF - stopping condition, EpsF>=0. The algorithm will stop when + residual will decrease below EpsF*|B|. Having EpsF=0 means + that this stopping condition is ignored. + MaxIts - stopping condition, MaxIts>=0. The algorithm will stop + after performing MaxIts iterations. Zero value means no + limit. + +NOTE: having both EpsF=0 and MaxIts=0 means that stopping criteria will be + chosen automatically. + +OUTPUT PARAMETERS: + X - array[N], the solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvegmres(const sparsematrix &a, const real_1d_array &b, const ae_int_t k, const double epsf, const ae_int_t maxits, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function initializes sparse linear iterative solver object. + +This solver can be used to solve nonsymmetric and symmetric positive +definite NxN (square) linear systems. + +The solver provides 'expert' API which allows advanced control over +algorithms being used, including ability to get progress report, terminate +long-running solver from other thread, out-of-core solution and so on. + +NOTE: there are also convenience functions that allows quick one-line + access to the solvers: + * SparseSolveCG() to solve SPD linear systems + * SparseSolveGMRES() to solve unsymmetric linear systems. + +NOTE: if you want to solve MxN (rectangular) linear problem you may use + LinLSQR solver provided by ALGLIB. + +USAGE (A is given by the SparseMatrix structure): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. Depending on whether system is symmetric or not, user calls: + * SparseSolverSolveSymmetric() for a symmetric system given by its + lower or upper triangle + * SparseSolverSolve() for a nonsymmetric system or a symmetric one + given by the full matrix + 5. User calls SparseSolverResults() to get the solution + + It is possible to call SparseSolverSolve???() again to solve another + task with same dimensionality but different matrix and/or right part + without reinitializing SparseSolverState structure. + +USAGE (out-of-core mode): + + 1. User initializes algorithm state with SparseSolverCreate() call + 2. User selects algorithm with one of the SparseSolverSetAlgo???() + functions. By default, GMRES(k) is used with automatically chosen k + 3. Optionally, user tunes solver parameters, sets starting point, etc. + 4. After that user should work with out-of-core interface in a loop + like one given below: + + > alglib.sparsesolveroocstart(state) + > while alglib.sparsesolverooccontinue(state) do + > alglib.sparsesolveroocgetrequestinfo(state, out RequestType) + > alglib.sparsesolveroocgetrequestdata(state, out X) + > if RequestType=0 then + > [calculate Y=A*X, with X=R^N] + > alglib.sparsesolveroocsendresult(state, in Y) + > alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + N - problem dimensionality (fixed at start-up) + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvercreate(const ae_int_t n, sparsesolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets the solver algorithm to GMRES(k). + +NOTE: if you do not need advanced functionality of the SparseSolver API, + you may use convenience functions SparseSolveGMRES() and + SparseSolveSymmetricGMRES(). + +INPUT PARAMETERS: + State - structure which stores algorithm state + K - GMRES parameter, K>=0: + * recommended values are in 10..100 range + * larger values up to N are possible but have little sense + - the algorithm will be slower than any dense solver. + * values above N are truncated down to N + * zero value means that default value is chosen. This + value is 50 in the current version, but it may change + in future ALGLIB releases. + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetalgogmres(sparsesolverstate &state, const ae_int_t k, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + State - structure which stores algorithm state + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - new starting point was set + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetstartingpoint(sparsesolverstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetcond(sparsesolverstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procedure for the solution of A*x=b with sparse symmetric A given by its +lower or upper triangle. + +This function will work with any solver algorithm being used, SPD one +(like CG) or not (like GMRES). Using unsymmetric solvers (like GMRES) on +SPD problems is suboptimal, but still possible. + +NOTE: the solver behavior is ill-defined for a situation when a SPD + solver is used on indefinite matrix. It may solve the problem up to + desired precision (sometimes, rarely) or return with error code + signalling violation of underlying assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse symmetric NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolvesymmetric(sparsesolverstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procedure for the solution of A*x=b with sparse nonsymmetric A + +IMPORTANT: this function will work with any solver algorithm being used, + symmetric solver like CG, or not. However, using symmetric + solvers on nonsymmetric problems is dangerous. It may solve + the problem up to desired precision (sometimes, rarely) or + terminate with error code signalling violation of underlying + assumptions. + +INPUT PARAMETERS: + State - algorithm state + A - sparse NxN matrix in any sparse storage format. + Using CRS format is recommended because it avoids internal + conversion. + An exception will be generated if A is not NxN matrix + (where N is a size specified during solver object + creation). + B - right part, array[N] + +RESULT: + This function returns no result. + You can get the solution by calling SparseSolverResults() + + -- ALGLIB -- + Copyright 25.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversolve(sparsesolverstate &state, const sparsematrix &a, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse solver results. + +This function must be called after calling one of the SparseSolverSolve() +functions. + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - solution report: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual +s + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverresults(sparsesolverstate &state, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting during out-of-core processing. + +When the solver works in the out-of-core mode, it can be configured to +report its progress by returning current location. These location reports +are implemented as a special kind of the out-of-core request: +* SparseSolverOOCGetRequestInfo() returns -1 +* SparseSolverOOCGetRequestData() returns current location +* SparseSolverOOCGetRequestData1() returns squared norm of the residual +* SparseSolverOOCSendResult() shall NOT be called + +This function has no effect when SparseSolverSolve() is used because this +function has no method of reporting its progress. + +NOTE: when used with GMRES(k), this function reports progress every k-th + iteration. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolversetxrep(sparsesolverstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function initiates out-of-core mode of the sparse solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver object + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstart(sparsesolverstate &state, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function performs iterative solution of the linear system in the +out-of-core mode. It should be used in conjunction with other out-of-core- +related functions of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +bool sparsesolverooccontinue(sparsesolverstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to retrieve information about out-of-core request +sent by the solver: +* RequestType=0 means that matrix-vector products A*x is requested +* RequestType=-1 means that solver reports its progress; this request is + returned only when reports are activated wit SparseSolverSetXRep(). + +This function returns just request type; in order to get contents of the +trial vector, use sparsesolveroocgetrequestdata(). + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + RequestType - type of the request to process: + * 0 for matrix-vector product A*x, with A being + NxN system matrix and X being N-dimensional + vector + *-1 for location and residual report + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestinfo(sparsesolverstate &state, ae_int_t &requesttype, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to retrieve vector associated with out-of-core +request sent by the solver to user code. Depending on the request type +(returned by the SparseSolverOOCGetRequestInfo()) this vector should be +multiplied by A or subjected to another processing. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + X - possibly preallocated storage; reallocated if + needed, left unchanged, if large enough to store + request data. + +OUTPUT PARAMETERS: + X - array[N] or larger, leading N elements are filled + with vector X. + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata(sparsesolverstate &state, real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to retrieve scalar value associated with out-of-core +request sent by the solver to user code. In the current ALGLIB version +this function is used to retrieve squared residual norm during progress +reports. + +INPUT PARAMETERS: + State - solver running in out-of-core mode + +OUTPUT PARAMETERS: + V - scalar value associated with the current request + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocgetrequestdata1(sparsesolverstate &state, double &v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to send user reply to out-of-core request sent by +the solver. Usually it is product A*x for vector X returned by the solver. + +It should be used in conjunction with other out-of-core-related functions +of this subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver running in out-of-core mode + AX - array[N] or larger, leading N elements contain A*x + + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocsendresult(sparsesolverstate &state, const real_1d_array &ax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function finalizes out-of-core mode of the linear solver. It should +be used in conjunction with other out-of-core-related functions of this +subspackage in a loop like one given below: + +> alglib.sparsesolveroocstart(state) +> while alglib.sparsesolverooccontinue(state) do +> alglib.sparsesolveroocgetrequestinfo(state, out RequestType) +> alglib.sparsesolveroocgetrequestdata(state, out X) +> if RequestType=0 then +> [calculate Y=A*X, with X=R^N] +> alglib.sparsesolveroocsendresult(state, in Y) +> alglib.sparsesolveroocstop(state, out X, out Report) + +INPUT PARAMETERS: + State - solver state + +OUTPUT PARAMETERS: + X - array[N], the solution. + Zero-filled on the failure (Rep.TerminationType<0). + Rep - report with additional info: + * Rep.TerminationType completion code: + * -5 CG method was used for a matrix which is not + positive definite + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * 8 the algorithm was terminated early with + SparseSolverRequestTermination() being called + from other thread. + * Rep.IterationsCount contains iterations count + * Rep.NMV contains number of matrix-vector calculations + * Rep.R2 contains squared residual + + -- ALGLIB -- + Copyright 24.09.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolveroocstop(sparsesolverstate &state, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants the solver to terminate +or when processing an out-of-core request. + +As result, solver stops at point which was "current accepted" when +the termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 01.10.2021 by Bochkanov Sergey +*************************************************************************/ +void sparsesolverrequesttermination(sparsesolverstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes linear CG Solver. This solver is used to solve +symmetric positive definite problems. If you want to solve nonsymmetric +(or non-positive definite) problem you may use LinLSQR solver provided by +ALGLIB. + +USAGE: +1. User initializes algorithm state with LinCGCreate() call +2. User tunes solver parameters with LinCGSetCond() and other functions +3. Optionally, user sets starting point with LinCGSetStartingPoint() +4. User calls LinCGSolveSparse() function which takes algorithm state and + SparseMatrix object. +5. User calls LinCGResults() to get solution +6. Optionally, user may call LinCGSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinCGState structure. + +INPUT PARAMETERS: + N - problem dimension, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgcreate(const ae_int_t n, lincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets starting point. +By default, zero starting point is used. + +INPUT PARAMETERS: + X - starting point, array[N] + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetstartingpoint(lincgstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecunit(lincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void lincgsetprecdiag(lincgstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsF - algorithm will be stopped if norm of residual is less than + EpsF*||b||. + MaxIts - algorithm will be stopped if number of iterations is more + than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTES: +If both EpsF and MaxIts are zero then small EpsF will be set to small +value. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetcond(lincgstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse matrix in the CRS format (you MUST contvert it to + CRS format by calling SparseConvertToCRS() function). + IsUpper - whether upper or lower triangle of A is used: + * IsUpper=True => only upper triangle is used and lower + triangle is not referenced at all + * IsUpper=False => only lower triangle is used and upper + triangle is not referenced at all + B - right part, array[N] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinCGSetPrecUnit(). However, preconditioning cost is low and + preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsolvesparse(lincgstate &state, const sparsematrix &a, const bool isupper, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +CG-solver: results. + +This function must be called after LinCGSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -5 input matrix is either not positive definite, + too large or too small + * -4 overflow/underflow during solution + (ill conditioned problem) + * 1 ||residual||<=EpsF*||b|| + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + best point found is returned + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgresults(const lincgstate &state, real_1d_array &x, lincgreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets restart frequency. By default, algorithm is restarted +after N subsequent iterations. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrestartfreq(lincgstate &state, const ae_int_t srf, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets frequency of residual recalculations. + +Algorithm updates residual r_k using iterative formula, but recalculates +it from scratch after each 10 iterations. It is done to avoid accumulation +of numerical errors and to stop algorithm when r_k starts to grow. + +Such low update frequence (1/10) gives very little overhead, but makes +algorithm a bit more robust against numerical errors. However, you may +change it + +INPUT PARAMETERS: + Freq - desired update frequency, Freq>=0. + Zero value means that no updates will be done. + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetrupdatefreq(lincgstate &state, const ae_int_t freq, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 14.11.2011 by Bochkanov Sergey +*************************************************************************/ +void lincgsetxrep(lincgstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes linear LSQR Solver. This solver is used to solve +non-symmetric (and, possibly, non-square) problems. Least squares solution +is returned for non-compatible systems. + +USAGE: +1. User initializes algorithm state with LinLSQRCreate() call +2. User tunes solver parameters with LinLSQRSetCond() and other functions +3. User calls LinLSQRSolveSparse() function which takes algorithm state + and SparseMatrix object. +4. User calls LinLSQRResults() to get solution +5. Optionally, user may call LinLSQRSolveSparse() again to solve another + problem with different matrix and/or right part without reinitializing + LinLSQRState structure. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: see also linlsqrcreatebuf() for version which reuses previously + allocated place as much as possible. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreate(const ae_int_t m, const ae_int_t n, linlsqrstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function initializes linear LSQR Solver. It provides exactly same +functionality as linlsqrcreate(), but reuses previously allocated space +as much as possible. + +INPUT PARAMETERS: + M - number of rows in A + N - number of variables, N>0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 14.11.2018 by Bochkanov Sergey +*************************************************************************/ +void linlsqrcreatebuf(const ae_int_t m, const ae_int_t n, linlsqrstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes preconditioning settings of LinLSQQSolveSparse() +function. By default, SolveSparse() uses diagonal preconditioner, but if +you want to use solver without preconditioning, you can call this function +which forces solver to use unit matrix for preconditioning. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecunit(linlsqrstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function changes preconditioning settings of LinCGSolveSparse() +function. LinCGSolveSparse() will use diagonal of the system matrix as +preconditioner. This preconditioning mode is active by default. + +INPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 19.11.2012 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetprecdiag(linlsqrstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets optional Tikhonov regularization coefficient. +It is zero by default. + +INPUT PARAMETERS: + LambdaI - regularization factor, LambdaI>=0 + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetlambdai(linlsqrstate &state, const double lambdai, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Procedure for solution of A*x=b with sparse A. + +INPUT PARAMETERS: + State - algorithm state + A - sparse M*N matrix in the CRS format (you MUST contvert it + to CRS format by calling SparseConvertToCRS() function + BEFORE you pass it to this function). + B - right part, array[M] + +RESULT: + This function returns no result. + You can get solution by calling LinCGResults() + +NOTE: this function uses lightweight preconditioning - multiplication by + inverse of diag(A). If you want, you can turn preconditioning off by + calling LinLSQRSetPrecUnit(). However, preconditioning cost is low + and preconditioner is very important for solution of badly scaled + problems. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsolvesparse(linlsqrstate &state, const sparsematrix &a, const real_1d_array &b, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping criteria. + +INPUT PARAMETERS: + EpsA - algorithm will be stopped if ||A^T*Rk||/(||A||*||Rk||)<=EpsA. + EpsB - algorithm will be stopped if ||Rk||<=EpsB*||B|| + MaxIts - algorithm will be stopped if number of iterations + more than MaxIts. + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + +NOTE: if EpsA,EpsB,EpsC and MaxIts are zero then these variables will +be setted as default values. + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetcond(linlsqrstate &state, const double epsa, const double epsb, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +LSQR solver: results. + +This function must be called after LinLSQRSolve + +INPUT PARAMETERS: + State - algorithm state + +OUTPUT PARAMETERS: + X - array[N], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * 1 ||Rk||<=EpsB*||B|| + * 4 ||A^T*Rk||/(||A||*||Rk||)<=EpsA + * 5 MaxIts steps was taken + * 7 rounding errors prevent further progress, + X contains best point found so far. + (sometimes returned on singular systems) + * 8 user requested termination via calling + linlsqrrequesttermination() + * Rep.IterationsCount contains iterations count + * NMV countains number of matrix-vector calculations + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrresults(const linlsqrstate &state, real_1d_array &x, linlsqrreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to MinCGOptimize(). + + -- ALGLIB -- + Copyright 30.11.2011 by Bochkanov Sergey +*************************************************************************/ +void linlsqrsetxrep(linlsqrstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function is used to peek into LSQR solver and get current iteration +counter. You can safely "peek" into the solver from another thread. + +INPUT PARAMETERS: + S - solver object + +RESULT: + iteration counter, in [0,INF) + + -- ALGLIB -- + Copyright 21.05.2018 by Bochkanov Sergey +*************************************************************************/ +ae_int_t linlsqrpeekiterationscount(const linlsqrstate &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine submits request for termination of the running solver. It +can be called from some other thread which wants LSQR solver to terminate +(obviously, the thread running LSQR solver can not request termination +because it is already busy working on LSQR). + +As result, solver stops at point which was "current accepted" when +termination request was submitted and returns error code 8 (successful +termination). Such termination is a smooth process which properly +deallocates all temporaries. + +INPUT PARAMETERS: + State - solver structure + +NOTE: calling this function on solver which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + +NOTE: solver clears termination flag on its start, it means that if some + other thread will request termination too soon, its request will went + unnoticed. + + -- ALGLIB -- + Copyright 08.10.2014 by Bochkanov Sergey +*************************************************************************/ +void linlsqrrequesttermination(linlsqrstate &state, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +This solver converts input matrix to SKS format, performs Cholesky +factorization using SKS Cholesky subroutine (works well for limited +bandwidth matrices) and uses sparse triangular solvers to get solution of +the original system. + +IMPORTANT: this function is intended for low profile (variable band) + linear systems with dense or nearly-dense bands. Only in such + cases it provides some performance improvement over more + general sparsrspdsolve(). If your system has high bandwidth + or sparse band, the general sparsrspdsolve() is likely to be + more efficient. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolvesks(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse linear solver for A*x=b with N*N sparse real symmetric positive +definite matrix A, N*1 vectors x and b. + +Depending on the ALGLIB edition (Free or Commercial, C++, C# or other), +the following applies: + +* FREE EDITION: ALGLIB sparse solver can be used, a supernodal algorithm + with serial implementation in generic C or generic C#. + +* COMMERCIAL EDITION: a parallel and SIMD-capable version of the ALGLIB + sparse supernodal solver can be used. A C code with SIMD kernels callable + from C++ and C#. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library can outperform + ALGLIB; for other problem types, ALGLIB DSS solver can be superior. + +IMPORTANT: This function is preferred to one that works with explicitly + given Cholesky factorization (sparsespdcholeskysolve). Some + efficient linear solver backends do not return Cholesky factors, + so doing explicit Cholesky followed by sparsespdcholeskysolve() + means that these backends will never be activated. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly. + Can be stored in any sparse storage format, CRS is preferred. + IsUpper - which half of A is provided (another half is ignored). + It is better to store the lower triangle because it allows + us to avoid one transposition during internal conversion. + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdsolve(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse linear solver for A*x=b with N*N real symmetric positive definite +matrix A given by its Cholesky decomposition, and N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the SKS (Skyline) + or CRS (compressed row storage) format. An exception will be + generated if you pass matrix in some other format. + +INPUT PARAMETERS + A - sparse NxN matrix stored in CRs or SKS format, must be NxN + exactly + IsUpper - which half of A is provided (another half is ignored) + B - array[N], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate or non-SPD system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparsespdcholeskysolve(const sparsematrix &a, const bool isupper, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A, N*1 vectors x and b. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* sparse LU with dynamic pivoting for stability. Provides better accuracy + at the cost of a significantly lower performance. Recommended only for + extremely unstable problems. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse matrix, must be NxN exactly, any storage format + B - array[N], right part + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + * 20 use sparse LU with dynamic pivoting for stability. + Not intended for large-scale problems. + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolve(const sparsematrix &a, const real_1d_array &b, const ae_int_t solvertype, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); +void sparsesolve(const sparsematrix &a, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse linear least squares solver for A*x=b with general (nonsymmetric) +N*N sparse real matrix A, N*1 vectors x and b. + +This function solves a regularized linear least squares problem of the form + + ( ) + min ( |Ax-b|^2 + reg*|x|^2 ), with reg>=sqrt(MachineAccuracy) + ( ) + +It can be used to solve both full rank and rank deficient systems. + +Depending on ALGLIB edition (Free or Commercial, C++, C# or other), one +of the following approaches can be used: + +* ALGLIB supernodal solver with static pivoting applied to a 2N*2N + regularized augmented system, followed by iterative refinement. This + solver is a recommended option because it provides the best speed and + has the lowest memory requirements. Depending on the programming + language and library edition (Free or Commercial), it can be a generic C + implementation, generic C# code, C code with SIMD kernels. + +* COMMERCIAL EDITION: Performance Backend Library can be used, if linked/ + loaded. See ALGLIB Reference Manual for the most actual information + about supported backends. Different backends are optimized for different + problem classes; for some problems, a backend library may outperform + ALGLIB; for other problem types, ALGLIB DSS solver is superior. + +INPUT PARAMETERS + A - sparse MxN matrix, any storage format + B - array[M], right part + Reg - regularization coefficient, Reg>=sqrt(MachineAccuracy), + lower values will be silently increased. + SolverType- solver type to use: + * 0 use the best solver. It is augmented system in the + current version, but may change in future releases + * 10 use 'default profile' of the supernodal solver with + static pivoting. The 'default' profile is + intended for systems with plenty of memory; it is + optimized for the best convergence at the cost of + increased RAM usage. Recommended option. + * 11 use 'limited memory' profile of the supernodal + solver with static pivoting. The limited-memory + profile is intended for problems with millions of + variables. On most systems it has the same + convergence as the default profile, having somewhat + worse results only for ill-conditioned systems. + +OUTPUT PARAMETERS + X - array[N], least squares solution + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success. + + Present version of the solver does NOT returns negative + completion codes because it does not fail. However, + future ALGLIB versions may include solvers which return + negative completion codes. + + -- ALGLIB -- + Copyright 18.11.2023 by Bochkanov Sergey +*************************************************************************/ +void sparsesolvelsreg(const sparsematrix &a, const real_1d_array &b, const double reg, const ae_int_t solvertype, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); +void sparsesolvelsreg(const sparsematrix &a, const real_1d_array &b, const double reg, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Sparse linear solver for A*x=b with general (nonsymmetric) N*N sparse real +matrix A given by its LU factorization, N*1 vectors x and b. + +IMPORTANT: this solver requires input matrix to be in the CRS sparse + storage format. An exception will be generated if you pass + matrix in some other format (HASH or SKS). + +INPUT PARAMETERS + A - LU factorization of the sparse matrix, must be NxN exactly + in CRS storage format + P, Q - pivot indexes from LU factorization + N - size of A, N>0 + B - array[0..N-1], right part + +OUTPUT PARAMETERS + X - array[N], it contains: + * rep.terminationtype>0 => solution + * rep.terminationtype=-3 => filled by zeros + Rep - solver report, following fields are set: + * rep.terminationtype - solver status; >0 for success, + set to -3 on failure (degenerate system). + + -- ALGLIB -- + Copyright 26.12.2017 by Bochkanov Sergey +*************************************************************************/ +void sparselusolve(const sparsematrix &a, const integer_1d_array &p, const integer_1d_array &q, const real_1d_array &b, real_1d_array &x, sparsesolverreport &rep, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* + LEVENBERG-MARQUARDT-LIKE NONLINEAR SOLVER + +DESCRIPTION: +This algorithm solves system of nonlinear equations + F[0](x[0], ..., x[n-1]) = 0 + F[1](x[0], ..., x[n-1]) = 0 + ... + F[M-1](x[0], ..., x[n-1]) = 0 +with M/N do not necessarily coincide. Algorithm converges quadratically +under following conditions: + * the solution set XS is nonempty + * for some xs in XS there exist such neighbourhood N(xs) that: + * vector function F(x) and its Jacobian J(x) are continuously + differentiable on N + * ||F(x)|| provides local error bound on N, i.e. there exists such + c1, that ||F(x)||>c1*distance(x,XS) +Note that these conditions are much more weaker than usual non-singularity +conditions. For example, algorithm will converge for any affine function +F (whether its Jacobian singular or not). + + +REQUIREMENTS: +Algorithm will request following information during its operation: +* function vector F[] and Jacobian matrix at given point X +* value of merit function f(x)=F[0]^2(x)+...+F[M-1]^2(x) at given point X + + +USAGE: +1. User initializes algorithm state with NLEQCreateLM() call +2. User tunes solver parameters with NLEQSetCond(), NLEQSetStpMax() and + other functions +3. User calls NLEQSolve() function which takes algorithm state and + pointers (delegates, etc.) to callback functions which calculate merit + function value and Jacobian. +4. User calls NLEQResults() to get solution +5. Optionally, user may call NLEQRestartFrom() to solve another problem + with same parameters (N/M) but another starting point and/or another + function vector. NLEQRestartFrom() allows to reuse already initialized + structure. + + +INPUT PARAMETERS: + N - space dimension, N>1: + * if provided, only leading N elements of X are used + * if not provided, determined automatically from size of X + M - system size + X - starting point + + +OUTPUT PARAMETERS: + State - structure which stores algorithm state + + +NOTES: +1. you may tune stopping conditions with NLEQSetCond() function +2. if target function contains exp() or other fast growing functions, and + optimization algorithm makes too large steps which leads to overflow, + use NLEQSetStpMax() function to bound algorithm's steps. +3. this algorithm is a slightly modified implementation of the method + described in 'Levenberg-Marquardt method for constrained nonlinear + equations with strong local convergence properties' by Christian Kanzow + Nobuo Yamashita and Masao Fukushima and further developed in 'On the + convergence of a New Levenberg-Marquardt Method' by Jin-yan Fan and + Ya-Xiang Yuan. + + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqcreatelm(const ae_int_t n, const ae_int_t m, const real_1d_array &x, nleqstate &state, const xparams _xparams = alglib::xdefault); +void nleqcreatelm(const ae_int_t m, const real_1d_array &x, nleqstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets stopping conditions for the nonlinear solver + +INPUT PARAMETERS: + State - structure which stores algorithm state + EpsF - >=0 + The subroutine finishes its work if on k+1-th iteration + the condition ||F||<=EpsF is satisfied + MaxIts - maximum number of iterations. If MaxIts=0, the number of + iterations is unlimited. + +Passing EpsF=0 and MaxIts=0 simultaneously will lead to automatic +stopping criterion selection (small EpsF). + +NOTES: + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetcond(nleqstate &state, const double epsf, const ae_int_t maxits, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores algorithm state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, algorithm will call rep() callback function if it is +provided to NLEQSolve(). + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetxrep(nleqstate &state, const bool needxrep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets maximum step length + +INPUT PARAMETERS: + State - structure which stores algorithm state + StpMax - maximum step length, >=0. Set StpMax to 0.0, if you don't + want to limit step length. + +Use this subroutine when target function contains exp() or other fast +growing functions, and algorithm makes too large steps which lead to +overflow. This function allows us to reject steps that are too large (and +therefore expose us to the possible overflow) without actually calculating +function value at the x+stp*d. + + -- ALGLIB -- + Copyright 20.08.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqsetstpmax(nleqstate &state, const double stpmax, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool nleqiteration(nleqstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This family of functions is used to start iterations of nonlinear solver + +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + jac - callback which calculates function vector fi[] + and Jacobian jac at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + + -- ALGLIB -- + Copyright 20.03.2009 by Bochkanov Sergey + + +*************************************************************************/ +void nleqsolve(nleqstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*jac)(const real_1d_array &x, real_1d_array &fi, real_2d_array &jac, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +NLEQ solver results + +INPUT PARAMETERS: + State - algorithm state. + +OUTPUT PARAMETERS: + X - array[0..N-1], solution + Rep - optimization report: + * Rep.TerminationType completetion code: + * -4 ERROR: algorithm has converged to the + stationary point Xf which is local minimum of + f=F[0]^2+...+F[m-1]^2, but is not solution of + nonlinear system. + * 1 sqrt(f)<=EpsF. + * 5 MaxIts steps was taken + * 7 stopping conditions are too stringent, + further improvement is impossible + * Rep.IterationsCount contains iterations count + * NFEV countains number of function calculations + * ActiveConstraints contains number of active constraints + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresults(const nleqstate &state, real_1d_array &x, nleqreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +NLEQ solver results + +Buffered implementation of NLEQResults(), which uses pre-allocated buffer +to store X[]. If buffer size is too small, it resizes buffer. It is +intended to be used in the inner cycles of performance critical algorithms +where array reallocation penalty is too large to be ignored. + + -- ALGLIB -- + Copyright 20.08.2009 by Bochkanov Sergey +*************************************************************************/ +void nleqresultsbuf(const nleqstate &state, real_1d_array &x, nleqreport &rep, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This subroutine restarts CG algorithm from new point. All optimization +parameters are left unchanged. + +This function allows to solve multiple optimization problems (which +must have same number of dimensions) without object reallocation penalty. + +INPUT PARAMETERS: + State - structure used for reverse communication previously + allocated with MinCGCreate call. + X - new starting point. + BndL - new lower bounds + BndU - new upper bounds + + -- ALGLIB -- + Copyright 30.07.2010 by Bochkanov Sergey +*************************************************************************/ +void nleqrestartfrom(nleqstate &state, const real_1d_array &x, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_POLYNOMIALSOLVER) || !defined(AE_PARTIAL_BUILD) +void polynomialsolve(/* Real */ const ae_vector* _a, + ae_int_t n, + /* Complex */ ae_vector* x, + polynomialsolverreport* rep, + ae_state *_state); +void _polynomialsolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _polynomialsolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _polynomialsolverreport_clear(void* _p); +void _polynomialsolverreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DIRECTDENSESOLVERS) || !defined(AE_PARTIAL_BUILD) +void rmatrixsolve(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool rmatrixsolvefast(/* Real */ const ae_matrix* _a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state); +void rmatrixsolvem(/* Real */ const ae_matrix* a, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + ae_bool rfs, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool rmatrixsolvemfast(/* Real */ const ae_matrix* _a, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void rmatrixlusolve(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool rmatrixlusolvefast(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state); +void rmatrixlusolvem(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool rmatrixlusolvemfast(/* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void rmatrixmixedsolve(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +void rmatrixmixedsolvem(/* Real */ const ae_matrix* a, + /* Real */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +void cmatrixsolvem(/* Complex */ const ae_matrix* a, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + ae_bool rfs, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool cmatrixsolvemfast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void cmatrixsolve(/* Complex */ const ae_matrix* a, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool cmatrixsolvefast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_state *_state); +void cmatrixlusolvem(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool cmatrixlusolvemfast(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void cmatrixlusolve(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool cmatrixlusolvefast(/* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ ae_vector* b, + ae_state *_state); +void cmatrixmixedsolvem(/* Complex */ const ae_matrix* a, + /* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +void cmatrixmixedsolve(/* Complex */ const ae_matrix* a, + /* Complex */ const ae_matrix* lua, + /* Integer */ const ae_vector* p, + ae_int_t n, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +void spdmatrixsolvem(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool spdmatrixsolvemfast(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void spdmatrixsolve(/* Real */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool spdmatrixsolvefast(/* Real */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_state *_state); +void spdmatrixcholeskysolvem(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_matrix* b, + ae_int_t m, + /* Real */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool spdmatrixcholeskysolvemfast(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void spdmatrixcholeskysolve(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool spdmatrixcholeskysolvefast(/* Real */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Real */ ae_vector* b, + ae_state *_state); +void hpdmatrixsolvem(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool hpdmatrixsolvemfast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void hpdmatrixsolve(/* Complex */ const ae_matrix* a, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool hpdmatrixsolvefast(/* Complex */ const ae_matrix* _a, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_state *_state); +void hpdmatrixcholeskysolvem(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_matrix* b, + ae_int_t m, + /* Complex */ ae_matrix* x, + densesolverreport* rep, + ae_state *_state); +ae_bool hpdmatrixcholeskysolvemfast(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_matrix* b, + ae_int_t m, + ae_state *_state); +void hpdmatrixcholeskysolve(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ const ae_vector* b, + /* Complex */ ae_vector* x, + densesolverreport* rep, + ae_state *_state); +ae_bool hpdmatrixcholeskysolvefast(/* Complex */ const ae_matrix* cha, + ae_int_t n, + ae_bool isupper, + /* Complex */ ae_vector* b, + ae_state *_state); +void rmatrixsolvels(/* Real */ const ae_matrix* a, + ae_int_t nrows, + ae_int_t ncols, + /* Real */ const ae_vector* b, + double threshold, + /* Real */ ae_vector* x, + densesolverlsreport* rep, + ae_state *_state); +void _densesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _densesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _densesolverreport_clear(void* _p); +void _densesolverreport_destroy(void* _p); +void _densesolverlsreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _densesolverlsreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _densesolverlsreport_clear(void* _p); +void _densesolverlsreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_ITERATIVESPARSE) || !defined(AE_PARTIAL_BUILD) +void sparsesolvesymmetricgmres(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_int_t k, + double epsf, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolvegmres(const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_int_t k, + double epsf, + ae_int_t maxits, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolvercreate(ae_int_t n, + sparsesolverstate* state, + ae_state *_state); +void sparsesolversetalgogmres(sparsesolverstate* state, + ae_int_t k, + ae_state *_state); +void sparsesolversetstartingpoint(sparsesolverstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void sparsesolversetcond(sparsesolverstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state); +void sparsesolversolvesymmetric(sparsesolverstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_state *_state); +void sparsesolversolve(sparsesolverstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_state *_state); +void sparsesolverresults(sparsesolverstate* state, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolversetxrep(sparsesolverstate* state, + ae_bool needxrep, + ae_state *_state); +void sparsesolveroocstart(sparsesolverstate* state, + /* Real */ const ae_vector* b, + ae_state *_state); +ae_bool sparsesolverooccontinue(sparsesolverstate* state, + ae_state *_state); +void sparsesolveroocgetrequestinfo(sparsesolverstate* state, + ae_int_t* requesttype, + ae_state *_state); +void sparsesolveroocgetrequestdata(sparsesolverstate* state, + /* Real */ ae_vector* x, + ae_state *_state); +void sparsesolveroocgetrequestdata1(sparsesolverstate* state, + double* v, + ae_state *_state); +void sparsesolveroocsendresult(sparsesolverstate* state, + /* Real */ const ae_vector* ax, + ae_state *_state); +void sparsesolveroocstop(sparsesolverstate* state, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolverrequesttermination(sparsesolverstate* state, + ae_state *_state); +void initsparsesolverreport(sparsesolverreport* rep, ae_state *_state); +void _sparsesolverreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sparsesolverreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sparsesolverreport_clear(void* _p); +void _sparsesolverreport_destroy(void* _p); +void _sparsesolverstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _sparsesolverstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _sparsesolverstate_clear(void* _p); +void _sparsesolverstate_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LINCG) || !defined(AE_PARTIAL_BUILD) +void lincgcreate(ae_int_t n, lincgstate* state, ae_state *_state); +void lincgsetstartingpoint(lincgstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void lincgsetb(lincgstate* state, + /* Real */ const ae_vector* b, + ae_state *_state); +void lincgsetprecunit(lincgstate* state, ae_state *_state); +void lincgsetprecdiag(lincgstate* state, ae_state *_state); +void lincgsetcond(lincgstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state); +ae_bool lincgiteration(lincgstate* state, ae_state *_state); +void lincgsolvesparse(lincgstate* state, + const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + ae_state *_state); +void lincgresults(const lincgstate* state, + /* Real */ ae_vector* x, + lincgreport* rep, + ae_state *_state); +void lincgsetrestartfreq(lincgstate* state, + ae_int_t srf, + ae_state *_state); +void lincgsetrupdatefreq(lincgstate* state, + ae_int_t freq, + ae_state *_state); +void lincgsetxrep(lincgstate* state, ae_bool needxrep, ae_state *_state); +void lincgrestart(lincgstate* state, ae_state *_state); +void _lincgstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lincgstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lincgstate_clear(void* _p); +void _lincgstate_destroy(void* _p); +void _lincgreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _lincgreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _lincgreport_clear(void* _p); +void _lincgreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_LINLSQR) || !defined(AE_PARTIAL_BUILD) +void linlsqrcreate(ae_int_t m, + ae_int_t n, + linlsqrstate* state, + ae_state *_state); +void linlsqrcreatebuf(ae_int_t m, + ae_int_t n, + linlsqrstate* state, + ae_state *_state); +void linlsqrsetb(linlsqrstate* state, + /* Real */ const ae_vector* b, + ae_state *_state); +void linlsqrsetprecunit(linlsqrstate* state, ae_state *_state); +void linlsqrsetprecdiag(linlsqrstate* state, ae_state *_state); +void linlsqrsetlambdai(linlsqrstate* state, + double lambdai, + ae_state *_state); +ae_bool linlsqriteration(linlsqrstate* state, ae_state *_state); +void linlsqrsolvesparse(linlsqrstate* state, + const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_state *_state); +void linlsqrsetcond(linlsqrstate* state, + double epsa, + double epsb, + ae_int_t maxits, + ae_state *_state); +void linlsqrresults(const linlsqrstate* state, + /* Real */ ae_vector* x, + linlsqrreport* rep, + ae_state *_state); +void linlsqrsetxrep(linlsqrstate* state, + ae_bool needxrep, + ae_state *_state); +void linlsqrrestart(linlsqrstate* state, ae_state *_state); +ae_int_t linlsqrpeekiterationscount(const linlsqrstate* s, + ae_state *_state); +void linlsqrrequesttermination(linlsqrstate* state, ae_state *_state); +void _linlsqrstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _linlsqrstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _linlsqrstate_clear(void* _p); +void _linlsqrstate_destroy(void* _p); +void _linlsqrreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _linlsqrreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _linlsqrreport_clear(void* _p); +void _linlsqrreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_DIRECTSPARSESOLVERS) || !defined(AE_PARTIAL_BUILD) +void sparsespdsolvesks(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsespdsolve(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsespdcholeskysolve(const sparsematrix* a, + ae_bool isupper, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolve(const sparsematrix* a, + /* Real */ const ae_vector* b, + ae_int_t solvertype, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparsesolvelsreg(const sparsematrix* a, + /* Real */ const ae_vector* b, + double reg, + ae_int_t solvertype, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +void sparselusolve(const sparsematrix* a, + /* Integer */ const ae_vector* p, + /* Integer */ const ae_vector* q, + /* Real */ const ae_vector* b, + /* Real */ ae_vector* x, + sparsesolverreport* rep, + ae_state *_state); +#endif +#if defined(AE_COMPILE_NLEQ) || !defined(AE_PARTIAL_BUILD) +void nleqcreatelm(ae_int_t n, + ae_int_t m, + /* Real */ const ae_vector* x, + nleqstate* state, + ae_state *_state); +void nleqsetcond(nleqstate* state, + double epsf, + ae_int_t maxits, + ae_state *_state); +void nleqsetxrep(nleqstate* state, ae_bool needxrep, ae_state *_state); +void nleqsetstpmax(nleqstate* state, double stpmax, ae_state *_state); +ae_bool nleqiteration(nleqstate* state, ae_state *_state); +void nleqresults(const nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state); +void nleqresultsbuf(const nleqstate* state, + /* Real */ ae_vector* x, + nleqreport* rep, + ae_state *_state); +void nleqrestartfrom(nleqstate* state, + /* Real */ const ae_vector* x, + ae_state *_state); +void nleqsetprotocolv1(nleqstate* state, ae_state *_state); +void _nleqstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nleqstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nleqstate_clear(void* _p); +void _nleqstate_destroy(void* _p); +void _nleqreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _nleqreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _nleqreport_clear(void* _p); +void _nleqreport_destroy(void* _p); +#endif + +} +#endif + diff --git a/core/alglib/specialfunctions.cpp b/core/alglib/specialfunctions.cpp index f88f8a86..91024043 100644 --- a/core/alglib/specialfunctions.cpp +++ b/core/alglib/specialfunctions.cpp @@ -1,9637 +1,10672 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "specialfunctions.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Gamma function - -Input parameters: - X - argument - -Domain: - 0 < X < 171.6 - -170 < X < 0, X is not an integer. - -Relative error: - arithmetic domain # trials peak rms - IEEE -170,-33 20000 2.3e-15 3.3e-16 - IEEE -33, 33 20000 9.4e-16 2.2e-16 - IEEE 33, 171.6 20000 2.3e-15 3.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double gammafunction(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::gammafunction(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Natural logarithm of gamma function - -Input parameters: - X - argument - -Result: - logarithm of the absolute value of the Gamma(X). - -Output parameters: - SgnGam - sign(Gamma(X)) - -Domain: - 0 < X < 2.55e305 - -2.55e305 < X < 0, X is not an integer. - -ACCURACY: -arithmetic domain # trials peak rms - IEEE 0, 3 28000 5.4e-16 1.1e-16 - IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 -The error criterion was relative when the function magnitude -was greater than one but absolute when it was less than one. - -The following test used the relative error criterion, though -at certain points the relative error could be much higher than -indicated. - IEEE -200, -4 10000 4.8e-16 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double lngamma(const double x, double &sgngam) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::lngamma(x, &sgngam, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Error function - -The integral is - - x - - - 2 | | 2 - erf(x) = -------- | exp( - t ) dt. - sqrt(pi) | | - - - 0 - -For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise -erf(x) = 1 - erfc(x). - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 3.7e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunction(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::errorfunction(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complementary error function - - 1 - erf(x) = - - inf. - - - 2 | | 2 - erfc(x) = -------- | exp( - t ) dt - sqrt(pi) | | - - - x - - -For small x, erfc(x) = 1 - erf(x); otherwise rational -approximations are computed. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,26.6417 30000 5.7e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunctionc(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::errorfunctionc(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Normal distribution function - -Returns the area under the Gaussian probability density -function, integrated from minus infinity to x: - - x - - - 1 | | 2 - ndtr(x) = --------- | exp( - t /2 ) dt - sqrt(2pi) | | - - - -inf. - - = ( 1 + erf(z) ) / 2 - = erfc(z) / 2 - -where z = x/sqrt(2). Computation is via the functions -erf and erfc. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE -13,0 30000 3.4e-14 6.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double normaldistribution(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::normaldistribution(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of the error function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double inverf(const double e) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::inverf(e, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of Normal distribution function - -Returns the argument, x, for which the area under the -Gaussian probability density function (integrated from -minus infinity to x) is equal to y. - - -For small arguments 0 < y < exp(-2), the program computes -z = sqrt( -2.0 * log(y) ); then the approximation is -x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). -There are two rational functions P/Q, one for 0 < y < exp(-32) -and the other for y up to exp(-2). For larger arguments, -w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0.125, 1 20000 7.2e-16 1.3e-16 - IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double invnormaldistribution(const double y0) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invnormaldistribution(y0, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Incomplete gamma integral - -The function is defined by - - x - - - 1 | | -t a-1 - igam(a,x) = ----- | e t dt. - - | | - | (a) - - 0 - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 200000 3.6e-14 2.9e-15 - IEEE 0,100 300000 9.9e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegamma(const double a, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::incompletegamma(a, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complemented incomplete gamma integral - -The function is defined by - - - igamc(a,x) = 1 - igam(a,x) - - inf. - - - 1 | | -t a-1 - = ----- | e t dt. - - | | - | (a) - - x - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - -Tested at random a, x. - a x Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 - IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegammac(const double a, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::incompletegammac(a, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of complemented incomplete gamma integral - -Given p, the function finds x such that - - igamc( a, x ) = p. - -Starting with the approximate value - - 3 - x = a t - - where - - t = 1 - d - ndtri(p) sqrt(d) - -and - - d = 1/9a, - -the routine performs up to 10 Newton iterations to find the -root of igamc(a,x) - p = 0. - -ACCURACY: - -Tested at random a, p in the intervals indicated. - - a p Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 - IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 - IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletegammac(const double a, const double y0) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invincompletegammac(a, y0, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Airy function - -Solution of the differential equation - -y"(x) = xy. - -The function returns the two independent solutions Ai, Bi -and their first derivatives Ai'(x), Bi'(x). - -Evaluation is by power series summation for small x, -by rational minimax approximations for large x. - - - -ACCURACY: -Error criterion is absolute when function <= 1, relative -when function > 1, except * denotes relative error criterion. -For large negative x, the absolute error increases as x^1.5. -For large positive x, the relative error increases as x^1.5. - -Arithmetic domain function # trials peak rms -IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 -IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* -IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 -IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* -IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 -IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void airy(const double x, double &ai, double &aip, double &bi, double &bip) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::airy(x, &ai, &aip, &bi, &bip, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of order zero - -Returns Bessel function of order zero of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval the following rational -approximation is used: - - - 2 2 -(w - r ) (w - r ) P (w) / Q (w) - 1 2 3 8 - - 2 -where w = x and the two r's are zeros of the function. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 60000 4.2e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj0(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselj0(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of order one - -Returns Bessel function of order one of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 24 term Chebyshev -expansion is used. In the second, the asymptotic -trigonometric representation is employed using two -rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 2.6e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj1(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselj1(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The ratio of jn(x) to j0(x) is computed by backward -recurrence. First the ratio jn/jn-1 is found by a -continued fraction expansion. Then the recurrence -relating successive orders is applied until j0 or j1 is -reached. - -If n = 0 or 1 the routine for j0 or j1 is called -directly. - -ACCURACY: - - Absolute error: -arithmetic range # trials peak rms - IEEE 0, 30 5000 4.4e-16 7.9e-17 - - -Not suitable for large n or x. Use jv() (fractional order) instead. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseljn(const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besseljn(n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of the second kind, order zero - -Returns Bessel function of the second kind, of order -zero, of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval a rational approximation -R(x) is employed to compute - y0(x) = R(x) + 2 * log(x) * j0(x) / PI. -Thus a call to j0() is required. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - - - -ACCURACY: - - Absolute error, when y0(x) < 1; else relative error: - -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.3e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely0(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::bessely0(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of second kind of order one - -Returns Bessel function of the second kind of order one -of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 25 term Chebyshev -expansion is used, and a call to j1() is required. -In the second, the asymptotic trigonometric representation -is employed using two rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.0e-15 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely1(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::bessely1(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Bessel function of second kind of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The function is evaluated by forward recurrence on -n, starting with values computed by the routines -y0() and y1(). - -If n = 0 or 1 the routine for y0 or y1 is called -directly. - -ACCURACY: - Absolute error, except relative - when y > 1: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 3.4e-15 4.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselyn(const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselyn(n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modified Bessel function of order zero - -Returns modified Bessel function of order zero of the -argument. - -The function is defined as i0(x) = j0( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 5.8e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli0(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besseli0(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modified Bessel function of order one - -Returns modified Bessel function of order one of the -argument. - -The function is defined as i1(x) = -i j1( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.9e-15 2.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli1(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besseli1(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modified Bessel function, second kind, order zero - -Returns modified Bessel function of the second kind -of order zero of the argument. - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - -Tested at 2000 random points between 0 and 8. Peak absolute -error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk0(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselk0(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modified Bessel function, second kind, order one - -Computes the modified Bessel function of the second kind -of order one of the argument. - -The range is partitioned into the two intervals [0,2] and -(2, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk1(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselk1(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Modified Bessel function, second kind, integer order - -Returns modified Bessel function of the second kind -of order n of the argument. - -The range is partitioned into the two intervals [0,9.55] and -(9.55, infinity). An ascending power series is used in the -low range, and an asymptotic expansion in the high range. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 90000 1.8e-8 3.0e-10 - -Error is high only near the crossover point x = 9.55 -between the two expansions used. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselkn(const ae_int_t nn, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::besselkn(nn, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Beta function - - - - - - | (a) | (b) -beta( a, b ) = -----------. - - - | (a+b) - -For large arguments the logarithm of the function is -evaluated using lgam(), then exponentiated. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 8.1e-14 1.1e-14 - -Cephes Math Library Release 2.0: April, 1987 -Copyright 1984, 1987 by Stephen L. Moshier -*************************************************************************/ -double beta(const double a, const double b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::beta(a, b, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Incomplete beta integral - -Returns incomplete beta integral of the arguments, evaluated -from zero to x. The function is defined as - - x - - - - | (a+b) | | a-1 b-1 - ----------- | t (1-t) dt. - - - | | - | (a) | (b) - - 0 - -The domain of definition is 0 <= x <= 1. In this -implementation a and b are restricted to positive values. -The integral from x to 1 may be obtained by the symmetry -relation - - 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). - -The integral is evaluated by a continued fraction expansion -or, when b*x is small, by a power series. - -ACCURACY: - -Tested at uniformly distributed random points (a,b,x) with a and b -in "domain" and x between 0 and 1. - Relative error -arithmetic domain # trials peak rms - IEEE 0,5 10000 6.9e-15 4.5e-16 - IEEE 0,85 250000 2.2e-13 1.7e-14 - IEEE 0,1000 30000 5.3e-12 6.3e-13 - IEEE 0,10000 250000 9.3e-11 7.1e-12 - IEEE 0,100000 10000 8.7e-10 4.8e-11 -Outputs smaller than the IEEE gradual underflow threshold -were excluded from these statistics. - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletebeta(const double a, const double b, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::incompletebeta(a, b, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of incomplete beta integral - -Given y, the function finds x such that - - incbet( a, b, x ) = y . - -The routine performs interval halving or Newton iterations to find the -root of incbet(a,b,x) - y = 0. - - -ACCURACY: - - Relative error: - x a,b -arithmetic domain domain # trials peak rms - IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 - IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 - IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 -With a and b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 - IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 -With a = .5, b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1996, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletebeta(const double a, const double b, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invincompletebeta(a, b, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Binomial distribution - -Returns the sum of the terms 0 through k of the Binomial -probability density: - - k - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=0 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p), with p between 0 and 1. - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 4.3e-15 2.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::binomialdistribution(k, n, p, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complemented binomial distribution - -Returns the sum of the terms k+1 through n of the Binomial -probability density: - - n - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=k+1 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 6.7e-15 8.2e-16 - For p between 0 and .001: - IEEE 0,100 100000 1.5e-13 2.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::binomialcdistribution(k, n, p, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse binomial distribution - -Finds the event probability p such that the sum of the -terms 0 through k of the Binomial probability density -is equal to the given cumulative probability y. - -This is accomplished using the inverse beta integral -function and the relation - -1 - p = incbi( n-k, k+1, y ). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 2.3e-14 6.4e-16 - IEEE 0,10000 100000 6.6e-12 1.2e-13 - For p between 10^-6 and 0.001: - IEEE 0,100 100000 2.0e-12 1.3e-14 - IEEE 0,10000 100000 1.5e-12 3.2e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invbinomialdistribution(k, n, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the value of the Chebyshev polynomials of the -first and second kinds. - -Parameters: - r - polynomial kind, either 1 or 2. - n - degree, n>=0 - x - argument, -1 <= x <= 1 - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::chebyshevcalculate(r, n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Summation of Chebyshev polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) -or - c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) -depending on the R. - -Parameters: - r - polynomial kind, either 1 or 2. - n - degree, n>=0 - x - argument - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::chebyshevsum(const_cast(c.c_ptr()), r, n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void chebyshevcoefficients(const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::chebyshevcoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Conversion of a series of Chebyshev polynomials to a power series. - -Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as -B[0] + B[1]*X + ... + B[N]*X^N. - -Input parameters: - A - Chebyshev series coefficients - N - degree, N>=0 - -Output parameters - B - power series coefficients -*************************************************************************/ -void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fromchebyshev(const_cast(a.c_ptr()), n, const_cast(b.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Chi-square distribution - -Returns the area under the left hand tail (from 0 to x) -of the Chi square probability density function with -v degrees of freedom. - - - x - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - 0 - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquaredistribution(const double v, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::chisquaredistribution(v, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complemented Chi-square distribution - -Returns the area under the right hand tail (from x to -infinity) of the Chi square probability density function -with v degrees of freedom: - - inf. - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - x - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquarecdistribution(const double v, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::chisquarecdistribution(v, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of complemented Chi-square distribution - -Finds the Chi-square argument x such that the integral -from x to infinity of the Chi-square density is equal -to the given cumulative probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - x/2 = igami( df/2, y ); - -ACCURACY: - -See inverse incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double invchisquaredistribution(const double v, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invchisquaredistribution(v, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Dawson's Integral - -Approximates the integral - - x - - - 2 | | 2 - dawsn(x) = exp( -x ) | exp( t ) dt - | | - - - 0 - -Three different rational approximations are employed, for -the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,10 10000 6.9e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double dawsonintegral(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::dawsonintegral(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -using the approximation - - P(x) - log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegralk(const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::ellipticintegralk(m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -where m = 1 - m1, using the approximation - - P(x) - log x Q(x). - -The argument m1 is used rather than m so that the logarithmic -singularity at m = 1 will be shifted to the origin; this -preserves maximum accuracy. - -K(0) = pi/2. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Àëãîðèòì âçÿò èç áèáëèîòåêè Cephes -*************************************************************************/ -double ellipticintegralkhighprecision(const double m1) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::ellipticintegralkhighprecision(m1, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Incomplete elliptic integral of the first kind F(phi|m) - -Approximates the integral - - - - phi - - - | | - | dt -F(phi_\m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - - - - -ACCURACY: - -Tested at random points with m in [0, 1] and phi as indicated. - - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 200000 7.4e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegralk(const double phi, const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::incompleteellipticintegralk(phi, m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complete elliptic integral of the second kind - -Approximates the integral - - - pi/2 - - - | | 2 -E(m) = | sqrt( 1 - m sin t ) dt - | | - - - 0 - -using the approximation - - P(x) - x log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 1 10000 2.1e-16 7.3e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegrale(const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::ellipticintegrale(m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Incomplete elliptic integral of the second kind - -Approximates the integral - - - phi - - - | | - | 2 -E(phi_\m) = | sqrt( 1 - m sin t ) dt - | - | | - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - -ACCURACY: - -Tested at random arguments with phi in [-10, 10] and m in -[0, 1]. - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 150000 3.3e-15 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegrale(const double phi, const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::incompleteellipticintegrale(phi, m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Exponential integral Ei(x) - - x - - t - | | e - Ei(x) = -|- --- dt . - | | t - - - -inf - -Not defined for x <= 0. -See also expn.c. - - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,100 50000 8.6e-16 1.3e-16 - -Cephes Math Library Release 2.8: May, 1999 -Copyright 1999 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralei(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::exponentialintegralei(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Exponential integral En(x) - -Evaluates the exponential integral - - inf. - - - | | -xt - | e - E (x) = | ---- dt. - n | n - | | t - - - 1 - - -Both n and x must be nonnegative. - -The routine employs either a power series, a continued -fraction, or an asymptotic formula depending on the -relative values of n and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 10000 1.7e-15 3.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 2000 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralen(const double x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::exponentialintegralen(x, n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -F distribution - -Returns the area from zero to x under the F density -function (also known as Snedcor's density or the -variance ratio density). This is the density -of x = (u1/df1)/(u2/df2), where u1 and u2 are random -variables having Chi square distributions with df1 -and df2 degrees of freedom, respectively. -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). - - -The arguments a and b are greater than zero, and x is -nonnegative. - -ACCURACY: - -Tested at random points (a,b,x). - - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 - IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 - IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 - IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fdistribution(const ae_int_t a, const ae_int_t b, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::fdistribution(a, b, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complemented F distribution - -Returns the area from x to infinity under the F density -function (also known as Snedcor's density or the -variance ratio density). - - - inf. - - - 1 | | a-1 b-1 -1-P(x) = ------ | t (1-t) dt - B(a,b) | | - - - x - - -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). - - -ACCURACY: - -Tested at random points (a,b,x) in the indicated intervals. - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 - IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 - IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 - IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fcdistribution(const ae_int_t a, const ae_int_t b, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::fcdistribution(a, b, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse of complemented F distribution - -Finds the F density argument x such that the integral -from x to infinity of the F density is equal to the -given probability p. - -This is accomplished using the inverse beta integral -function and the relations - - z = incbi( df2/2, df1/2, p ) - x = df2 (1-z) / (df1 z). - -Note: the following relations hold for the inverse of -the uncomplemented F distribution: - - z = incbi( df1/2, df2/2, p ) - x = df2 z / (df1 (1-z)). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between .001 and 1: - IEEE 1,100 100000 8.3e-15 4.7e-16 - IEEE 1,10000 100000 2.1e-11 1.4e-13 - For p between 10^-6 and 10^-3: - IEEE 1,100 50000 1.3e-12 8.4e-15 - IEEE 1,10000 50000 3.0e-12 4.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invfdistribution(const ae_int_t a, const ae_int_t b, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invfdistribution(a, b, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Fresnel integral - -Evaluates the Fresnel integrals - - x - - - | | -C(x) = | cos(pi/2 t**2) dt, - | | - - - 0 - - x - - - | | -S(x) = | sin(pi/2 t**2) dt. - | | - - - 0 - - -The integrals are evaluated by a power series for x < 1. -For x >= 1 auxiliary functions f(x) and g(x) are employed -such that - -C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) -S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) - - - -ACCURACY: - - Relative error. - -Arithmetic function domain # trials peak rms - IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 - IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void fresnelintegral(const double x, double &c, double &s) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::fresnelintegral(x, &c, &s, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the value of the Hermite polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial Hn at x -*************************************************************************/ -double hermitecalculate(const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hermitecalculate(n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Summation of Hermite polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial at x -*************************************************************************/ -double hermitesum(const real_1d_array &c, const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::hermitesum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void hermitecoefficients(const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hermitecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Jacobian Elliptic Functions - -Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), -and dn(u|m) of parameter m between 0 and 1, and real -argument u. - -These functions are periodic, with quarter-period on the -real axis equal to the complete elliptic integral -ellpk(1.0-m). - -Relation to incomplete elliptic integral: -If u = ellik(phi,m), then sn(u|m) = sin(phi), -and cn(u|m) = cos(phi). Phi is called the amplitude of u. - -Computation is by means of the arithmetic-geometric mean -algorithm, except when m is within 1e-9 of 0 or 1. In the -latter case with m close to 1, the approximation applies -only for phi < pi/2. - -ACCURACY: - -Tested at random points with u between 0 and 10, m between -0 and 1. - - Absolute error (* = relative error): -arithmetic function # trials peak rms - IEEE phi 10000 9.2e-16* 1.4e-16* - IEEE sn 50000 4.1e-15 4.6e-16 - IEEE cn 40000 3.6e-15 4.4e-16 - IEEE dn 10000 1.3e-12 1.8e-14 - - Peak error observed in consistency check using addition -theorem for sn(u+v) was 4e-16 (absolute). Also tested by -the above relation to the incomplete elliptic integral. -Accuracy deteriorates when u is large. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::jacobianellipticfunctions(u, m, &sn, &cn, &dn, &ph, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the value of the Laguerre polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial Ln at x -*************************************************************************/ -double laguerrecalculate(const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::laguerrecalculate(n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Summation of Laguerre polynomials using Clenshaw’s recurrence formula. - -This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial at x -*************************************************************************/ -double laguerresum(const real_1d_array &c, const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::laguerresum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void laguerrecoefficients(const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::laguerrecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the value of the Legendre polynomial Pn. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial Pn at x -*************************************************************************/ -double legendrecalculate(const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::legendrecalculate(n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Summation of Legendre polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial at x -*************************************************************************/ -double legendresum(const real_1d_array &c, const ae_int_t n, const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::legendresum(const_cast(c.c_ptr()), n, x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void legendrecoefficients(const ae_int_t n, real_1d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::legendrecoefficients(n, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Poisson distribution - -Returns the sum of the first k+1 terms of the Poisson -distribution: - - k j - -- -m m - > e -- - -- j! - j=0 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the relation - -y = pdtr( k, m ) = igamc( k+1, m ). - -The arguments must both be positive. -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissondistribution(const ae_int_t k, const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::poissondistribution(k, m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Complemented Poisson distribution - -Returns the sum of the terms k+1 to infinity of the Poisson -distribution: - - inf. j - -- -m m - > e -- - -- j! - j=k+1 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the formula - -y = pdtrc( k, m ) = igam( k+1, m ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissoncdistribution(const ae_int_t k, const double m) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::poissoncdistribution(k, m, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Inverse Poisson distribution - -Finds the Poisson variable x such that the integral -from 0 to x of the Poisson density is equal to the -given probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - m = igami( k+1, y ). - -ACCURACY: - -See inverse incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invpoissondistribution(const ae_int_t k, const double y) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invpoissondistribution(k, y, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Psi (digamma) function - - d - - psi(x) = -- ln | (x) - dx - -is the logarithmic derivative of the gamma function. -For integer x, - n-1 - - -psi(n) = -EUL + > 1/k. - - - k=1 - -This formula is used for 0 < n <= 10. If x is negative, it -is transformed to a positive argument by the reflection -formula psi(1-x) = psi(x) + pi cot(pi x). -For general positive x, the argument is made greater than 10 -using the recurrence psi(x+1) = psi(x) + 1/x. -Then the following asymptotic expansion is applied: - - inf. B - - 2k -psi(x) = log(x) - 1/2x - > ------- - - 2k - k=1 2k x - -where the B2k are Bernoulli numbers. - -ACCURACY: - Relative error (except absolute when |psi| < 1): -arithmetic domain # trials peak rms - IEEE 0,30 30000 1.3e-15 1.4e-16 - IEEE -30,0 40000 1.5e-15 2.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double psi(const double x) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::psi(x, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Student's t distribution - -Computes the integral from minus infinity to t of the Student -t distribution with integer k > 0 degrees of freedom: - - t - - - | | - - | 2 -(k+1)/2 - | ( (k+1)/2 ) | ( x ) - ---------------------- | ( 1 + --- ) dx - - | ( k ) - sqrt( k pi ) | ( k/2 ) | - | | - - - -inf. - -Relation to incomplete beta integral: - - 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) -where - z = k/(k + t**2). - -For t < -2, this is the method of computation. For higher t, -a direct method is derived from integration by parts. -Since the function is symmetric about t=0, the area under the -right tail of the density is found by calling the function -with -t instead of t. - -ACCURACY: - -Tested at random 1 <= k <= 25. The "domain" refers to t. - Relative error: -arithmetic domain # trials peak rms - IEEE -100,-2 50000 5.9e-15 1.4e-15 - IEEE -2,100 500000 2.7e-15 4.9e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double studenttdistribution(const ae_int_t k, const double t) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::studenttdistribution(k, t, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Functional inverse of Student's t distribution - -Given probability p, finds the argument t such that stdtr(k,t) -is equal to p. - -ACCURACY: - -Tested at random 1 <= k <= 100. The "domain" refers to p: - Relative error: -arithmetic domain # trials peak rms - IEEE .001,.999 25000 5.7e-15 8.0e-16 - IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invstudenttdistribution(const ae_int_t k, const double p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::invstudenttdistribution(k, p, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Sine and cosine integrals - -Evaluates the integrals - - x - - - | cos t - 1 - Ci(x) = eul + ln x + | --------- dt, - | t - - - 0 - x - - - | sin t - Si(x) = | ----- dt - | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are approximated by rational functions. -For x > 8 auxiliary functions f(x) and g(x) are employed -such that - -Ci(x) = f(x) sin(x) - g(x) cos(x) -Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) - - -ACCURACY: - Test interval = [0,50]. -Absolute error, except relative when > 1: -arithmetic function # trials peak rms - IEEE Si 30000 4.4e-16 7.3e-17 - IEEE Ci 30000 6.9e-16 5.1e-17 - -Cephes Math Library Release 2.1: January, 1989 -Copyright 1984, 1987, 1989 by Stephen L. Moshier -*************************************************************************/ -void sinecosineintegrals(const double x, double &si, double &ci) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sinecosineintegrals(x, &si, &ci, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Hyperbolic sine and cosine integrals - -Approximates the integrals - - x - - - | | cosh t - 1 - Chi(x) = eul + ln x + | ----------- dt, - | | t - - - 0 - - x - - - | | sinh t - Shi(x) = | ------ dt - | | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are evaluated by power series for x < 8 -and by Chebyshev expansions for x between 8 and 88. -For large x, both functions approach exp(x)/2x. -Arguments greater than 88 in magnitude return MAXNUM. - - -ACCURACY: - -Test interval 0 to 88. - Relative error: -arithmetic function # trials peak rms - IEEE Shi 30000 6.9e-16 1.6e-16 - Absolute error, except relative when |Chi| > 1: - IEEE Chi 30000 8.4e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::hyperbolicsinecosineintegrals(x, &shi, &chi, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static double gammafunc_gammastirf(double x, ae_state *_state); - - - - - - - - -static void bessel_besselmfirstcheb(double c, - double* b0, - double* b1, - double* b2, - ae_state *_state); -static void bessel_besselmnextcheb(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state); -static void bessel_besselm1firstcheb(double c, - double* b0, - double* b1, - double* b2, - ae_state *_state); -static void bessel_besselm1nextcheb(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state); -static void bessel_besselasympt0(double x, - double* pzero, - double* qzero, - ae_state *_state); -static void bessel_besselasympt1(double x, - double* pzero, - double* qzero, - ae_state *_state); - - - - -static double ibetaf_incompletebetafe(double a, - double b, - double x, - double big, - double biginv, - ae_state *_state); -static double ibetaf_incompletebetafe2(double a, - double b, - double x, - double big, - double biginv, - ae_state *_state); -static double ibetaf_incompletebetaps(double a, - double b, - double x, - double maxgam, - ae_state *_state); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static void trigintegrals_chebiterationshichi(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state); - - - - - -/************************************************************************* -Gamma function - -Input parameters: - X - argument - -Domain: - 0 < X < 171.6 - -170 < X < 0, X is not an integer. - -Relative error: - arithmetic domain # trials peak rms - IEEE -170,-33 20000 2.3e-15 3.3e-16 - IEEE -33, 33 20000 9.4e-16 2.2e-16 - IEEE 33, 171.6 20000 2.3e-15 3.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double gammafunction(double x, ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SPECFUNCS - double p; - double pp; - double q; - double qq; - double z; - ae_int_t i; - double sgngam; - double result; - - - sgngam = 1; - q = ae_fabs(x, _state); - if( ae_fp_greater(q,33.0) ) - { - if( ae_fp_less(x,0.0) ) - { - p = ae_ifloor(q, _state); - i = ae_round(p, _state); - if( i%2==0 ) - { - sgngam = -1; - } - z = q-p; - if( ae_fp_greater(z,0.5) ) - { - p = p+1; - z = q-p; - } - z = q*ae_sin(ae_pi*z, _state); - z = ae_fabs(z, _state); - z = ae_pi/(z*gammafunc_gammastirf(q, _state)); - } - else - { - z = gammafunc_gammastirf(x, _state); - } - result = sgngam*z; - return result; - } - z = 1; - while(ae_fp_greater_eq(x,3)) - { - x = x-1; - z = z*x; - } - while(ae_fp_less(x,0)) - { - if( ae_fp_greater(x,-0.000000001) ) - { - result = z/((1+0.5772156649015329*x)*x); - return result; - } - z = z/x; - x = x+1; - } - while(ae_fp_less(x,2)) - { - if( ae_fp_less(x,0.000000001) ) - { - result = z/((1+0.5772156649015329*x)*x); - return result; - } - z = z/x; - x = x+1.0; - } - if( ae_fp_eq(x,2) ) - { - result = z; - return result; - } - x = x-2.0; - pp = 1.60119522476751861407E-4; - pp = 1.19135147006586384913E-3+x*pp; - pp = 1.04213797561761569935E-2+x*pp; - pp = 4.76367800457137231464E-2+x*pp; - pp = 2.07448227648435975150E-1+x*pp; - pp = 4.94214826801497100753E-1+x*pp; - pp = 9.99999999999999996796E-1+x*pp; - qq = -2.31581873324120129819E-5; - qq = 5.39605580493303397842E-4+x*qq; - qq = -4.45641913851797240494E-3+x*qq; - qq = 1.18139785222060435552E-2+x*qq; - qq = 3.58236398605498653373E-2+x*qq; - qq = -2.34591795718243348568E-1+x*qq; - qq = 7.14304917030273074085E-2+x*qq; - qq = 1.00000000000000000320+x*qq; - result = z*pp/qq; - return result; -#else - return _ialglib_i_gammafunction(x); -#endif -} - - -/************************************************************************* -Natural logarithm of gamma function - -Input parameters: - X - argument - -Result: - logarithm of the absolute value of the Gamma(X). - -Output parameters: - SgnGam - sign(Gamma(X)) - -Domain: - 0 < X < 2.55e305 - -2.55e305 < X < 0, X is not an integer. - -ACCURACY: -arithmetic domain # trials peak rms - IEEE 0, 3 28000 5.4e-16 1.1e-16 - IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 -The error criterion was relative when the function magnitude -was greater than one but absolute when it was less than one. - -The following test used the relative error criterion, though -at certain points the relative error could be much higher than -indicated. - IEEE -200, -4 10000 4.8e-16 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double lngamma(double x, double* sgngam, ae_state *_state) -{ -#ifndef ALGLIB_INTERCEPTS_SPECFUNCS - double a; - double b; - double c; - double p; - double q; - double u; - double w; - double z; - ae_int_t i; - double logpi; - double ls2pi; - double tmp; - double result; - - *sgngam = 0; - - *sgngam = 1; - logpi = 1.14472988584940017414; - ls2pi = 0.91893853320467274178; - if( ae_fp_less(x,-34.0) ) - { - q = -x; - w = lngamma(q, &tmp, _state); - p = ae_ifloor(q, _state); - i = ae_round(p, _state); - if( i%2==0 ) - { - *sgngam = -1; - } - else - { - *sgngam = 1; - } - z = q-p; - if( ae_fp_greater(z,0.5) ) - { - p = p+1; - z = p-q; - } - z = q*ae_sin(ae_pi*z, _state); - result = logpi-ae_log(z, _state)-w; - return result; - } - if( ae_fp_less(x,13) ) - { - z = 1; - p = 0; - u = x; - while(ae_fp_greater_eq(u,3)) - { - p = p-1; - u = x+p; - z = z*u; - } - while(ae_fp_less(u,2)) - { - z = z/u; - p = p+1; - u = x+p; - } - if( ae_fp_less(z,0) ) - { - *sgngam = -1; - z = -z; - } - else - { - *sgngam = 1; - } - if( ae_fp_eq(u,2) ) - { - result = ae_log(z, _state); - return result; - } - p = p-2; - x = x+p; - b = -1378.25152569120859100; - b = -38801.6315134637840924+x*b; - b = -331612.992738871184744+x*b; - b = -1162370.97492762307383+x*b; - b = -1721737.00820839662146+x*b; - b = -853555.664245765465627+x*b; - c = 1; - c = -351.815701436523470549+x*c; - c = -17064.2106651881159223+x*c; - c = -220528.590553854454839+x*c; - c = -1139334.44367982507207+x*c; - c = -2532523.07177582951285+x*c; - c = -2018891.41433532773231+x*c; - p = x*b/c; - result = ae_log(z, _state)+p; - return result; - } - q = (x-0.5)*ae_log(x, _state)-x+ls2pi; - if( ae_fp_greater(x,100000000) ) - { - result = q; - return result; - } - p = 1/(x*x); - if( ae_fp_greater_eq(x,1000.0) ) - { - q = q+((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x; - } - else - { - a = 8.11614167470508450300*0.0001; - a = -5.95061904284301438324*0.0001+p*a; - a = 7.93650340457716943945*0.0001+p*a; - a = -2.77777777730099687205*0.001+p*a; - a = 8.33333333333331927722*0.01+p*a; - q = q+a/x; - } - result = q; - return result; -#else - return _ialglib_i_lngamma(x, sgngam); -#endif -} - - -static double gammafunc_gammastirf(double x, ae_state *_state) -{ - double y; - double w; - double v; - double stir; - double result; - - - w = 1/x; - stir = 7.87311395793093628397E-4; - stir = -2.29549961613378126380E-4+w*stir; - stir = -2.68132617805781232825E-3+w*stir; - stir = 3.47222221605458667310E-3+w*stir; - stir = 8.33333333333482257126E-2+w*stir; - w = 1+w*stir; - y = ae_exp(x, _state); - if( ae_fp_greater(x,143.01608) ) - { - v = ae_pow(x, 0.5*x-0.25, _state); - y = v*(v/y); - } - else - { - y = ae_pow(x, x-0.5, _state)/y; - } - result = 2.50662827463100050242*y*w; - return result; -} - - - - -/************************************************************************* -Error function - -The integral is - - x - - - 2 | | 2 - erf(x) = -------- | exp( - t ) dt. - sqrt(pi) | | - - - 0 - -For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise -erf(x) = 1 - erfc(x). - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 3.7e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunction(double x, ae_state *_state) -{ - double xsq; - double s; - double p; - double q; - double result; - - - s = ae_sign(x, _state); - x = ae_fabs(x, _state); - if( ae_fp_less(x,0.5) ) - { - xsq = x*x; - p = 0.007547728033418631287834; - p = -0.288805137207594084924010+xsq*p; - p = 14.3383842191748205576712+xsq*p; - p = 38.0140318123903008244444+xsq*p; - p = 3017.82788536507577809226+xsq*p; - p = 7404.07142710151470082064+xsq*p; - p = 80437.3630960840172832162+xsq*p; - q = 0.0; - q = 1.00000000000000000000000+xsq*q; - q = 38.0190713951939403753468+xsq*q; - q = 658.070155459240506326937+xsq*q; - q = 6379.60017324428279487120+xsq*q; - q = 34216.5257924628539769006+xsq*q; - q = 80437.3630960840172826266+xsq*q; - result = s*1.1283791670955125738961589031*x*p/q; - return result; - } - if( ae_fp_greater_eq(x,10) ) - { - result = s; - return result; - } - result = s*(1-errorfunctionc(x, _state)); - return result; -} - - -/************************************************************************* -Complementary error function - - 1 - erf(x) = - - inf. - - - 2 | | 2 - erfc(x) = -------- | exp( - t ) dt - sqrt(pi) | | - - - x - - -For small x, erfc(x) = 1 - erf(x); otherwise rational -approximations are computed. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,26.6417 30000 5.7e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunctionc(double x, ae_state *_state) -{ - double p; - double q; - double result; - - - if( ae_fp_less(x,0) ) - { - result = 2-errorfunctionc(-x, _state); - return result; - } - if( ae_fp_less(x,0.5) ) - { - result = 1.0-errorfunction(x, _state); - return result; - } - if( ae_fp_greater_eq(x,10) ) - { - result = 0; - return result; - } - p = 0.0; - p = 0.5641877825507397413087057563+x*p; - p = 9.675807882987265400604202961+x*p; - p = 77.08161730368428609781633646+x*p; - p = 368.5196154710010637133875746+x*p; - p = 1143.262070703886173606073338+x*p; - p = 2320.439590251635247384768711+x*p; - p = 2898.0293292167655611275846+x*p; - p = 1826.3348842295112592168999+x*p; - q = 1.0; - q = 17.14980943627607849376131193+x*q; - q = 137.1255960500622202878443578+x*q; - q = 661.7361207107653469211984771+x*q; - q = 2094.384367789539593790281779+x*q; - q = 4429.612803883682726711528526+x*q; - q = 6089.5424232724435504633068+x*q; - q = 4958.82756472114071495438422+x*q; - q = 1826.3348842295112595576438+x*q; - result = ae_exp(-ae_sqr(x, _state), _state)*p/q; - return result; -} - - -/************************************************************************* -Normal distribution function - -Returns the area under the Gaussian probability density -function, integrated from minus infinity to x: - - x - - - 1 | | 2 - ndtr(x) = --------- | exp( - t /2 ) dt - sqrt(2pi) | | - - - -inf. - - = ( 1 + erf(z) ) / 2 - = erfc(z) / 2 - -where z = x/sqrt(2). Computation is via the functions -erf and erfc. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE -13,0 30000 3.4e-14 6.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double normaldistribution(double x, ae_state *_state) -{ - double result; - - - result = 0.5*(errorfunction(x/1.41421356237309504880, _state)+1); - return result; -} - - -/************************************************************************* -Inverse of the error function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double inverf(double e, ae_state *_state) -{ - double result; - - - result = invnormaldistribution(0.5*(e+1), _state)/ae_sqrt(2, _state); - return result; -} - - -/************************************************************************* -Inverse of Normal distribution function - -Returns the argument, x, for which the area under the -Gaussian probability density function (integrated from -minus infinity to x) is equal to y. - - -For small arguments 0 < y < exp(-2), the program computes -z = sqrt( -2.0 * log(y) ); then the approximation is -x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). -There are two rational functions P/Q, one for 0 < y < exp(-32) -and the other for y up to exp(-2). For larger arguments, -w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0.125, 1 20000 7.2e-16 1.3e-16 - IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double invnormaldistribution(double y0, ae_state *_state) -{ - double expm2; - double s2pi; - double x; - double y; - double z; - double y2; - double x0; - double x1; - ae_int_t code; - double p0; - double q0; - double p1; - double q1; - double p2; - double q2; - double result; - - - expm2 = 0.13533528323661269189; - s2pi = 2.50662827463100050242; - if( ae_fp_less_eq(y0,0) ) - { - result = -ae_maxrealnumber; - return result; - } - if( ae_fp_greater_eq(y0,1) ) - { - result = ae_maxrealnumber; - return result; - } - code = 1; - y = y0; - if( ae_fp_greater(y,1.0-expm2) ) - { - y = 1.0-y; - code = 0; - } - if( ae_fp_greater(y,expm2) ) - { - y = y-0.5; - y2 = y*y; - p0 = -59.9633501014107895267; - p0 = 98.0010754185999661536+y2*p0; - p0 = -56.6762857469070293439+y2*p0; - p0 = 13.9312609387279679503+y2*p0; - p0 = -1.23916583867381258016+y2*p0; - q0 = 1; - q0 = 1.95448858338141759834+y2*q0; - q0 = 4.67627912898881538453+y2*q0; - q0 = 86.3602421390890590575+y2*q0; - q0 = -225.462687854119370527+y2*q0; - q0 = 200.260212380060660359+y2*q0; - q0 = -82.0372256168333339912+y2*q0; - q0 = 15.9056225126211695515+y2*q0; - q0 = -1.18331621121330003142+y2*q0; - x = y+y*y2*p0/q0; - x = x*s2pi; - result = x; - return result; - } - x = ae_sqrt(-2.0*ae_log(y, _state), _state); - x0 = x-ae_log(x, _state)/x; - z = 1.0/x; - if( ae_fp_less(x,8.0) ) - { - p1 = 4.05544892305962419923; - p1 = 31.5251094599893866154+z*p1; - p1 = 57.1628192246421288162+z*p1; - p1 = 44.0805073893200834700+z*p1; - p1 = 14.6849561928858024014+z*p1; - p1 = 2.18663306850790267539+z*p1; - p1 = -1.40256079171354495875*0.1+z*p1; - p1 = -3.50424626827848203418*0.01+z*p1; - p1 = -8.57456785154685413611*0.0001+z*p1; - q1 = 1; - q1 = 15.7799883256466749731+z*q1; - q1 = 45.3907635128879210584+z*q1; - q1 = 41.3172038254672030440+z*q1; - q1 = 15.0425385692907503408+z*q1; - q1 = 2.50464946208309415979+z*q1; - q1 = -1.42182922854787788574*0.1+z*q1; - q1 = -3.80806407691578277194*0.01+z*q1; - q1 = -9.33259480895457427372*0.0001+z*q1; - x1 = z*p1/q1; - } - else - { - p2 = 3.23774891776946035970; - p2 = 6.91522889068984211695+z*p2; - p2 = 3.93881025292474443415+z*p2; - p2 = 1.33303460815807542389+z*p2; - p2 = 2.01485389549179081538*0.1+z*p2; - p2 = 1.23716634817820021358*0.01+z*p2; - p2 = 3.01581553508235416007*0.0001+z*p2; - p2 = 2.65806974686737550832*0.000001+z*p2; - p2 = 6.23974539184983293730*0.000000001+z*p2; - q2 = 1; - q2 = 6.02427039364742014255+z*q2; - q2 = 3.67983563856160859403+z*q2; - q2 = 1.37702099489081330271+z*q2; - q2 = 2.16236993594496635890*0.1+z*q2; - q2 = 1.34204006088543189037*0.01+z*q2; - q2 = 3.28014464682127739104*0.0001+z*q2; - q2 = 2.89247864745380683936*0.000001+z*q2; - q2 = 6.79019408009981274425*0.000000001+z*q2; - x1 = z*p2/q2; - } - x = x0-x1; - if( code!=0 ) - { - x = -x; - } - result = x; - return result; -} - - - - -/************************************************************************* -Incomplete gamma integral - -The function is defined by - - x - - - 1 | | -t a-1 - igam(a,x) = ----- | e t dt. - - | | - | (a) - - 0 - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 200000 3.6e-14 2.9e-15 - IEEE 0,100 300000 9.9e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegamma(double a, double x, ae_state *_state) -{ - double igammaepsilon; - double ans; - double ax; - double c; - double r; - double tmp; - double result; - - - igammaepsilon = 0.000000000000001; - if( ae_fp_less_eq(x,0)||ae_fp_less_eq(a,0) ) - { - result = 0; - return result; - } - if( ae_fp_greater(x,1)&&ae_fp_greater(x,a) ) - { - result = 1-incompletegammac(a, x, _state); - return result; - } - ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); - if( ae_fp_less(ax,-709.78271289338399) ) - { - result = 0; - return result; - } - ax = ae_exp(ax, _state); - r = a; - c = 1; - ans = 1; - do - { - r = r+1; - c = c*x/r; - ans = ans+c; - } - while(ae_fp_greater(c/ans,igammaepsilon)); - result = ans*ax/a; - return result; -} - - -/************************************************************************* -Complemented incomplete gamma integral - -The function is defined by - - - igamc(a,x) = 1 - igam(a,x) - - inf. - - - 1 | | -t a-1 - = ----- | e t dt. - - | | - | (a) - - x - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - -Tested at random a, x. - a x Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 - IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegammac(double a, double x, ae_state *_state) -{ - double igammaepsilon; - double igammabignumber; - double igammabignumberinv; - double ans; - double ax; - double c; - double yc; - double r; - double t; - double y; - double z; - double pk; - double pkm1; - double pkm2; - double qk; - double qkm1; - double qkm2; - double tmp; - double result; - - - igammaepsilon = 0.000000000000001; - igammabignumber = 4503599627370496.0; - igammabignumberinv = 2.22044604925031308085*0.0000000000000001; - if( ae_fp_less_eq(x,0)||ae_fp_less_eq(a,0) ) - { - result = 1; - return result; - } - if( ae_fp_less(x,1)||ae_fp_less(x,a) ) - { - result = 1-incompletegamma(a, x, _state); - return result; - } - ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); - if( ae_fp_less(ax,-709.78271289338399) ) - { - result = 0; - return result; - } - ax = ae_exp(ax, _state); - y = 1-a; - z = x+y+1; - c = 0; - pkm2 = 1; - qkm2 = x; - pkm1 = x+1; - qkm1 = z*x; - ans = pkm1/qkm1; - do - { - c = c+1; - y = y+1; - z = z+2; - yc = y*c; - pk = pkm1*z-pkm2*yc; - qk = qkm1*z-qkm2*yc; - if( ae_fp_neq(qk,0) ) - { - r = pk/qk; - t = ae_fabs((ans-r)/r, _state); - ans = r; - } - else - { - t = 1; - } - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - if( ae_fp_greater(ae_fabs(pk, _state),igammabignumber) ) - { - pkm2 = pkm2*igammabignumberinv; - pkm1 = pkm1*igammabignumberinv; - qkm2 = qkm2*igammabignumberinv; - qkm1 = qkm1*igammabignumberinv; - } - } - while(ae_fp_greater(t,igammaepsilon)); - result = ans*ax; - return result; -} - - -/************************************************************************* -Inverse of complemented incomplete gamma integral - -Given p, the function finds x such that - - igamc( a, x ) = p. - -Starting with the approximate value - - 3 - x = a t - - where - - t = 1 - d - ndtri(p) sqrt(d) - -and - - d = 1/9a, - -the routine performs up to 10 Newton iterations to find the -root of igamc(a,x) - p = 0. - -ACCURACY: - -Tested at random a, p in the intervals indicated. - - a p Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 - IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 - IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletegammac(double a, double y0, ae_state *_state) -{ - double igammaepsilon; - double iinvgammabignumber; - double x0; - double x1; - double x; - double yl; - double yh; - double y; - double d; - double lgm; - double dithresh; - ae_int_t i; - ae_int_t dir; - double tmp; - double result; - - - igammaepsilon = 0.000000000000001; - iinvgammabignumber = 4503599627370496.0; - x0 = iinvgammabignumber; - yl = 0; - x1 = 0; - yh = 1; - dithresh = 5*igammaepsilon; - d = 1/(9*a); - y = 1-d-invnormaldistribution(y0, _state)*ae_sqrt(d, _state); - x = a*y*y*y; - lgm = lngamma(a, &tmp, _state); - i = 0; - while(i<10) - { - if( ae_fp_greater(x,x0)||ae_fp_less(x,x1) ) - { - d = 0.0625; - break; - } - y = incompletegammac(a, x, _state); - if( ae_fp_less(y,yl)||ae_fp_greater(y,yh) ) - { - d = 0.0625; - break; - } - if( ae_fp_less(y,y0) ) - { - x0 = x; - yl = y; - } - else - { - x1 = x; - yh = y; - } - d = (a-1)*ae_log(x, _state)-x-lgm; - if( ae_fp_less(d,-709.78271289338399) ) - { - d = 0.0625; - break; - } - d = -ae_exp(d, _state); - d = (y-y0)/d; - if( ae_fp_less(ae_fabs(d/x, _state),igammaepsilon) ) - { - result = x; - return result; - } - x = x-d; - i = i+1; - } - if( ae_fp_eq(x0,iinvgammabignumber) ) - { - if( ae_fp_less_eq(x,0) ) - { - x = 1; - } - while(ae_fp_eq(x0,iinvgammabignumber)) - { - x = (1+d)*x; - y = incompletegammac(a, x, _state); - if( ae_fp_less(y,y0) ) - { - x0 = x; - yl = y; - break; - } - d = d+d; - } - } - d = 0.5; - dir = 0; - i = 0; - while(i<400) - { - x = x1+d*(x0-x1); - y = incompletegammac(a, x, _state); - lgm = (x0-x1)/(x1+x0); - if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) - { - break; - } - lgm = (y-y0)/y0; - if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) - { - break; - } - if( ae_fp_less_eq(x,0.0) ) - { - break; - } - if( ae_fp_greater_eq(y,y0) ) - { - x1 = x; - yh = y; - if( dir<0 ) - { - dir = 0; - d = 0.5; - } - else - { - if( dir>1 ) - { - d = 0.5*d+0.5; - } - else - { - d = (y0-yl)/(yh-yl); - } - } - dir = dir+1; - } - else - { - x0 = x; - yl = y; - if( dir>0 ) - { - dir = 0; - d = 0.5; - } - else - { - if( dir<-1 ) - { - d = 0.5*d; - } - else - { - d = (y0-yl)/(yh-yl); - } - } - dir = dir-1; - } - i = i+1; - } - result = x; - return result; -} - - - - -/************************************************************************* -Airy function - -Solution of the differential equation - -y"(x) = xy. - -The function returns the two independent solutions Ai, Bi -and their first derivatives Ai'(x), Bi'(x). - -Evaluation is by power series summation for small x, -by rational minimax approximations for large x. - - - -ACCURACY: -Error criterion is absolute when function <= 1, relative -when function > 1, except * denotes relative error criterion. -For large negative x, the absolute error increases as x^1.5. -For large positive x, the relative error increases as x^1.5. - -Arithmetic domain function # trials peak rms -IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 -IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* -IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 -IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* -IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 -IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void airy(double x, - double* ai, - double* aip, - double* bi, - double* bip, - ae_state *_state) -{ - double z; - double zz; - double t; - double f; - double g; - double uf; - double ug; - double k; - double zeta; - double theta; - ae_int_t domflg; - double c1; - double c2; - double sqrt3; - double sqpii; - double afn; - double afd; - double agn; - double agd; - double apfn; - double apfd; - double apgn; - double apgd; - double an; - double ad; - double apn; - double apd; - double bn16; - double bd16; - double bppn; - double bppd; - - *ai = 0; - *aip = 0; - *bi = 0; - *bip = 0; - - sqpii = 5.64189583547756286948E-1; - c1 = 0.35502805388781723926; - c2 = 0.258819403792806798405; - sqrt3 = 1.732050807568877293527; - domflg = 0; - if( ae_fp_greater(x,25.77) ) - { - *ai = 0; - *aip = 0; - *bi = ae_maxrealnumber; - *bip = ae_maxrealnumber; - return; - } - if( ae_fp_less(x,-2.09) ) - { - domflg = 15; - t = ae_sqrt(-x, _state); - zeta = -2.0*x*t/3.0; - t = ae_sqrt(t, _state); - k = sqpii/t; - z = 1.0/zeta; - zz = z*z; - afn = -1.31696323418331795333E-1; - afn = afn*zz-6.26456544431912369773E-1; - afn = afn*zz-6.93158036036933542233E-1; - afn = afn*zz-2.79779981545119124951E-1; - afn = afn*zz-4.91900132609500318020E-2; - afn = afn*zz-4.06265923594885404393E-3; - afn = afn*zz-1.59276496239262096340E-4; - afn = afn*zz-2.77649108155232920844E-6; - afn = afn*zz-1.67787698489114633780E-8; - afd = 1.00000000000000000000E0; - afd = afd*zz+1.33560420706553243746E1; - afd = afd*zz+3.26825032795224613948E1; - afd = afd*zz+2.67367040941499554804E1; - afd = afd*zz+9.18707402907259625840E0; - afd = afd*zz+1.47529146771666414581E0; - afd = afd*zz+1.15687173795188044134E-1; - afd = afd*zz+4.40291641615211203805E-3; - afd = afd*zz+7.54720348287414296618E-5; - afd = afd*zz+4.51850092970580378464E-7; - uf = 1.0+zz*afn/afd; - agn = 1.97339932091685679179E-2; - agn = agn*zz+3.91103029615688277255E-1; - agn = agn*zz+1.06579897599595591108E0; - agn = agn*zz+9.39169229816650230044E-1; - agn = agn*zz+3.51465656105547619242E-1; - agn = agn*zz+6.33888919628925490927E-2; - agn = agn*zz+5.85804113048388458567E-3; - agn = agn*zz+2.82851600836737019778E-4; - agn = agn*zz+6.98793669997260967291E-6; - agn = agn*zz+8.11789239554389293311E-8; - agn = agn*zz+3.41551784765923618484E-10; - agd = 1.00000000000000000000E0; - agd = agd*zz+9.30892908077441974853E0; - agd = agd*zz+1.98352928718312140417E1; - agd = agd*zz+1.55646628932864612953E1; - agd = agd*zz+5.47686069422975497931E0; - agd = agd*zz+9.54293611618961883998E-1; - agd = agd*zz+8.64580826352392193095E-2; - agd = agd*zz+4.12656523824222607191E-3; - agd = agd*zz+1.01259085116509135510E-4; - agd = agd*zz+1.17166733214413521882E-6; - agd = agd*zz+4.91834570062930015649E-9; - ug = z*agn/agd; - theta = zeta+0.25*ae_pi; - f = ae_sin(theta, _state); - g = ae_cos(theta, _state); - *ai = k*(f*uf-g*ug); - *bi = k*(g*uf+f*ug); - apfn = 1.85365624022535566142E-1; - apfn = apfn*zz+8.86712188052584095637E-1; - apfn = apfn*zz+9.87391981747398547272E-1; - apfn = apfn*zz+4.01241082318003734092E-1; - apfn = apfn*zz+7.10304926289631174579E-2; - apfn = apfn*zz+5.90618657995661810071E-3; - apfn = apfn*zz+2.33051409401776799569E-4; - apfn = apfn*zz+4.08718778289035454598E-6; - apfn = apfn*zz+2.48379932900442457853E-8; - apfd = 1.00000000000000000000E0; - apfd = apfd*zz+1.47345854687502542552E1; - apfd = apfd*zz+3.75423933435489594466E1; - apfd = apfd*zz+3.14657751203046424330E1; - apfd = apfd*zz+1.09969125207298778536E1; - apfd = apfd*zz+1.78885054766999417817E0; - apfd = apfd*zz+1.41733275753662636873E-1; - apfd = apfd*zz+5.44066067017226003627E-3; - apfd = apfd*zz+9.39421290654511171663E-5; - apfd = apfd*zz+5.65978713036027009243E-7; - uf = 1.0+zz*apfn/apfd; - apgn = -3.55615429033082288335E-2; - apgn = apgn*zz-6.37311518129435504426E-1; - apgn = apgn*zz-1.70856738884312371053E0; - apgn = apgn*zz-1.50221872117316635393E0; - apgn = apgn*zz-5.63606665822102676611E-1; - apgn = apgn*zz-1.02101031120216891789E-1; - apgn = apgn*zz-9.48396695961445269093E-3; - apgn = apgn*zz-4.60325307486780994357E-4; - apgn = apgn*zz-1.14300836484517375919E-5; - apgn = apgn*zz-1.33415518685547420648E-7; - apgn = apgn*zz-5.63803833958893494476E-10; - apgd = 1.00000000000000000000E0; - apgd = apgd*zz+9.85865801696130355144E0; - apgd = apgd*zz+2.16401867356585941885E1; - apgd = apgd*zz+1.73130776389749389525E1; - apgd = apgd*zz+6.17872175280828766327E0; - apgd = apgd*zz+1.08848694396321495475E0; - apgd = apgd*zz+9.95005543440888479402E-2; - apgd = apgd*zz+4.78468199683886610842E-3; - apgd = apgd*zz+1.18159633322838625562E-4; - apgd = apgd*zz+1.37480673554219441465E-6; - apgd = apgd*zz+5.79912514929147598821E-9; - ug = z*apgn/apgd; - k = sqpii*t; - *aip = -k*(g*uf+f*ug); - *bip = k*(f*uf-g*ug); - return; - } - if( ae_fp_greater_eq(x,2.09) ) - { - domflg = 5; - t = ae_sqrt(x, _state); - zeta = 2.0*x*t/3.0; - g = ae_exp(zeta, _state); - t = ae_sqrt(t, _state); - k = 2.0*t*g; - z = 1.0/zeta; - an = 3.46538101525629032477E-1; - an = an*z+1.20075952739645805542E1; - an = an*z+7.62796053615234516538E1; - an = an*z+1.68089224934630576269E2; - an = an*z+1.59756391350164413639E2; - an = an*z+7.05360906840444183113E1; - an = an*z+1.40264691163389668864E1; - an = an*z+9.99999999999999995305E-1; - ad = 5.67594532638770212846E-1; - ad = ad*z+1.47562562584847203173E1; - ad = ad*z+8.45138970141474626562E1; - ad = ad*z+1.77318088145400459522E2; - ad = ad*z+1.64234692871529701831E2; - ad = ad*z+7.14778400825575695274E1; - ad = ad*z+1.40959135607834029598E1; - ad = ad*z+1.00000000000000000470E0; - f = an/ad; - *ai = sqpii*f/k; - k = -0.5*sqpii*t/g; - apn = 6.13759184814035759225E-1; - apn = apn*z+1.47454670787755323881E1; - apn = apn*z+8.20584123476060982430E1; - apn = apn*z+1.71184781360976385540E2; - apn = apn*z+1.59317847137141783523E2; - apn = apn*z+6.99778599330103016170E1; - apn = apn*z+1.39470856980481566958E1; - apn = apn*z+1.00000000000000000550E0; - apd = 3.34203677749736953049E-1; - apd = apd*z+1.11810297306158156705E1; - apd = apd*z+7.11727352147859965283E1; - apd = apd*z+1.58778084372838313640E2; - apd = apd*z+1.53206427475809220834E2; - apd = apd*z+6.86752304592780337944E1; - apd = apd*z+1.38498634758259442477E1; - apd = apd*z+9.99999999999999994502E-1; - f = apn/apd; - *aip = f*k; - if( ae_fp_greater(x,8.3203353) ) - { - bn16 = -2.53240795869364152689E-1; - bn16 = bn16*z+5.75285167332467384228E-1; - bn16 = bn16*z-3.29907036873225371650E-1; - bn16 = bn16*z+6.44404068948199951727E-2; - bn16 = bn16*z-3.82519546641336734394E-3; - bd16 = 1.00000000000000000000E0; - bd16 = bd16*z-7.15685095054035237902E0; - bd16 = bd16*z+1.06039580715664694291E1; - bd16 = bd16*z-5.23246636471251500874E0; - bd16 = bd16*z+9.57395864378383833152E-1; - bd16 = bd16*z-5.50828147163549611107E-2; - f = z*bn16/bd16; - k = sqpii*g; - *bi = k*(1.0+f)/t; - bppn = 4.65461162774651610328E-1; - bppn = bppn*z-1.08992173800493920734E0; - bppn = bppn*z+6.38800117371827987759E-1; - bppn = bppn*z-1.26844349553102907034E-1; - bppn = bppn*z+7.62487844342109852105E-3; - bppd = 1.00000000000000000000E0; - bppd = bppd*z-8.70622787633159124240E0; - bppd = bppd*z+1.38993162704553213172E1; - bppd = bppd*z-7.14116144616431159572E0; - bppd = bppd*z+1.34008595960680518666E0; - bppd = bppd*z-7.84273211323341930448E-2; - f = z*bppn/bppd; - *bip = k*t*(1.0+f); - return; - } - } - f = 1.0; - g = x; - t = 1.0; - uf = 1.0; - ug = x; - k = 1.0; - z = x*x*x; - while(ae_fp_greater(t,ae_machineepsilon)) - { - uf = uf*z; - k = k+1.0; - uf = uf/k; - ug = ug*z; - k = k+1.0; - ug = ug/k; - uf = uf/k; - f = f+uf; - k = k+1.0; - ug = ug/k; - g = g+ug; - t = ae_fabs(uf/f, _state); - } - uf = c1*f; - ug = c2*g; - if( domflg%2==0 ) - { - *ai = uf-ug; - } - if( domflg/2%2==0 ) - { - *bi = sqrt3*(uf+ug); - } - k = 4.0; - uf = x*x/2.0; - ug = z/3.0; - f = uf; - g = 1.0+ug; - uf = uf/3.0; - t = 1.0; - while(ae_fp_greater(t,ae_machineepsilon)) - { - uf = uf*z; - ug = ug/k; - k = k+1.0; - ug = ug*z; - uf = uf/k; - f = f+uf; - k = k+1.0; - ug = ug/k; - uf = uf/k; - g = g+ug; - k = k+1.0; - t = ae_fabs(ug/g, _state); - } - uf = c1*f; - ug = c2*g; - if( domflg/4%2==0 ) - { - *aip = uf-ug; - } - if( domflg/8%2==0 ) - { - *bip = sqrt3*(uf+ug); - } -} - - - - -/************************************************************************* -Bessel function of order zero - -Returns Bessel function of order zero of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval the following rational -approximation is used: - - - 2 2 -(w - r ) (w - r ) P (w) / Q (w) - 1 2 3 8 - - 2 -where w = x and the two r's are zeros of the function. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 60000 4.2e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj0(double x, ae_state *_state) -{ - double xsq; - double nn; - double pzero; - double qzero; - double p1; - double q1; - double result; - - - if( ae_fp_less(x,0) ) - { - x = -x; - } - if( ae_fp_greater(x,8.0) ) - { - bessel_besselasympt0(x, &pzero, &qzero, _state); - nn = x-ae_pi/4; - result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); - return result; - } - xsq = ae_sqr(x, _state); - p1 = 26857.86856980014981415848441; - p1 = -40504123.71833132706360663322+xsq*p1; - p1 = 25071582855.36881945555156435+xsq*p1; - p1 = -8085222034853.793871199468171+xsq*p1; - p1 = 1434354939140344.111664316553+xsq*p1; - p1 = -136762035308817138.6865416609+xsq*p1; - p1 = 6382059341072356562.289432465+xsq*p1; - p1 = -117915762910761053603.8440800+xsq*p1; - p1 = 493378725179413356181.6813446+xsq*p1; - q1 = 1.0; - q1 = 1363.063652328970604442810507+xsq*q1; - q1 = 1114636.098462985378182402543+xsq*q1; - q1 = 669998767.2982239671814028660+xsq*q1; - q1 = 312304311494.1213172572469442+xsq*q1; - q1 = 112775673967979.8507056031594+xsq*q1; - q1 = 30246356167094626.98627330784+xsq*q1; - q1 = 5428918384092285160.200195092+xsq*q1; - q1 = 493378725179413356211.3278438+xsq*q1; - result = p1/q1; - return result; -} - - -/************************************************************************* -Bessel function of order one - -Returns Bessel function of order one of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 24 term Chebyshev -expansion is used. In the second, the asymptotic -trigonometric representation is employed using two -rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 2.6e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj1(double x, ae_state *_state) -{ - double s; - double xsq; - double nn; - double pzero; - double qzero; - double p1; - double q1; - double result; - - - s = ae_sign(x, _state); - if( ae_fp_less(x,0) ) - { - x = -x; - } - if( ae_fp_greater(x,8.0) ) - { - bessel_besselasympt1(x, &pzero, &qzero, _state); - nn = x-3*ae_pi/4; - result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); - if( ae_fp_less(s,0) ) - { - result = -result; - } - return result; - } - xsq = ae_sqr(x, _state); - p1 = 2701.122710892323414856790990; - p1 = -4695753.530642995859767162166+xsq*p1; - p1 = 3413234182.301700539091292655+xsq*p1; - p1 = -1322983480332.126453125473247+xsq*p1; - p1 = 290879526383477.5409737601689+xsq*p1; - p1 = -35888175699101060.50743641413+xsq*p1; - p1 = 2316433580634002297.931815435+xsq*p1; - p1 = -66721065689249162980.20941484+xsq*p1; - p1 = 581199354001606143928.050809+xsq*p1; - q1 = 1.0; - q1 = 1606.931573481487801970916749+xsq*q1; - q1 = 1501793.594998585505921097578+xsq*q1; - q1 = 1013863514.358673989967045588+xsq*q1; - q1 = 524371026216.7649715406728642+xsq*q1; - q1 = 208166122130760.7351240184229+xsq*q1; - q1 = 60920613989175217.46105196863+xsq*q1; - q1 = 11857707121903209998.37113348+xsq*q1; - q1 = 1162398708003212287858.529400+xsq*q1; - result = s*x*p1/q1; - return result; -} - - -/************************************************************************* -Bessel function of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The ratio of jn(x) to j0(x) is computed by backward -recurrence. First the ratio jn/jn-1 is found by a -continued fraction expansion. Then the recurrence -relating successive orders is applied until j0 or j1 is -reached. - -If n = 0 or 1 the routine for j0 or j1 is called -directly. - -ACCURACY: - - Absolute error: -arithmetic range # trials peak rms - IEEE 0, 30 5000 4.4e-16 7.9e-17 - - -Not suitable for large n or x. Use jv() (fractional order) instead. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseljn(ae_int_t n, double x, ae_state *_state) -{ - double pkm2; - double pkm1; - double pk; - double xk; - double r; - double ans; - ae_int_t k; - ae_int_t sg; - double result; - - - if( n<0 ) - { - n = -n; - if( n%2==0 ) - { - sg = 1; - } - else - { - sg = -1; - } - } - else - { - sg = 1; - } - if( ae_fp_less(x,0) ) - { - if( n%2!=0 ) - { - sg = -sg; - } - x = -x; - } - if( n==0 ) - { - result = sg*besselj0(x, _state); - return result; - } - if( n==1 ) - { - result = sg*besselj1(x, _state); - return result; - } - if( n==2 ) - { - if( ae_fp_eq(x,0) ) - { - result = 0; - } - else - { - result = sg*(2.0*besselj1(x, _state)/x-besselj0(x, _state)); - } - return result; - } - if( ae_fp_less(x,ae_machineepsilon) ) - { - result = 0; - return result; - } - k = 53; - pk = 2*(n+k); - ans = pk; - xk = x*x; - do - { - pk = pk-2.0; - ans = pk-xk/ans; - k = k-1; - } - while(k!=0); - ans = x/ans; - pk = 1.0; - pkm1 = 1.0/ans; - k = n-1; - r = 2*k; - do - { - pkm2 = (pkm1*r-pk*x)/x; - pk = pkm1; - pkm1 = pkm2; - r = r-2.0; - k = k-1; - } - while(k!=0); - if( ae_fp_greater(ae_fabs(pk, _state),ae_fabs(pkm1, _state)) ) - { - ans = besselj1(x, _state)/pk; - } - else - { - ans = besselj0(x, _state)/pkm1; - } - result = sg*ans; - return result; -} - - -/************************************************************************* -Bessel function of the second kind, order zero - -Returns Bessel function of the second kind, of order -zero, of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval a rational approximation -R(x) is employed to compute - y0(x) = R(x) + 2 * log(x) * j0(x) / PI. -Thus a call to j0() is required. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - - - -ACCURACY: - - Absolute error, when y0(x) < 1; else relative error: - -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.3e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely0(double x, ae_state *_state) -{ - double nn; - double xsq; - double pzero; - double qzero; - double p4; - double q4; - double result; - - - if( ae_fp_greater(x,8.0) ) - { - bessel_besselasympt0(x, &pzero, &qzero, _state); - nn = x-ae_pi/4; - result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); - return result; - } - xsq = ae_sqr(x, _state); - p4 = -41370.35497933148554125235152; - p4 = 59152134.65686889654273830069+xsq*p4; - p4 = -34363712229.79040378171030138+xsq*p4; - p4 = 10255208596863.94284509167421+xsq*p4; - p4 = -1648605817185729.473122082537+xsq*p4; - p4 = 137562431639934407.8571335453+xsq*p4; - p4 = -5247065581112764941.297350814+xsq*p4; - p4 = 65874732757195549259.99402049+xsq*p4; - p4 = -27502866786291095837.01933175+xsq*p4; - q4 = 1.0; - q4 = 1282.452772478993804176329391+xsq*q4; - q4 = 1001702.641288906265666651753+xsq*q4; - q4 = 579512264.0700729537480087915+xsq*q4; - q4 = 261306575504.1081249568482092+xsq*q4; - q4 = 91620380340751.85262489147968+xsq*q4; - q4 = 23928830434997818.57439356652+xsq*q4; - q4 = 4192417043410839973.904769661+xsq*q4; - q4 = 372645883898616588198.9980+xsq*q4; - result = p4/q4+2/ae_pi*besselj0(x, _state)*ae_log(x, _state); - return result; -} - - -/************************************************************************* -Bessel function of second kind of order one - -Returns Bessel function of the second kind of order one -of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 25 term Chebyshev -expansion is used, and a call to j1() is required. -In the second, the asymptotic trigonometric representation -is employed using two rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.0e-15 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely1(double x, ae_state *_state) -{ - double nn; - double xsq; - double pzero; - double qzero; - double p4; - double q4; - double result; - - - if( ae_fp_greater(x,8.0) ) - { - bessel_besselasympt1(x, &pzero, &qzero, _state); - nn = x-3*ae_pi/4; - result = ae_sqrt(2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); - return result; - } - xsq = ae_sqr(x, _state); - p4 = -2108847.540133123652824139923; - p4 = 3639488548.124002058278999428+xsq*p4; - p4 = -2580681702194.450950541426399+xsq*p4; - p4 = 956993023992168.3481121552788+xsq*p4; - p4 = -196588746272214065.8820322248+xsq*p4; - p4 = 21931073399177975921.11427556+xsq*p4; - p4 = -1212297555414509577913.561535+xsq*p4; - p4 = 26554738314348543268942.48968+xsq*p4; - p4 = -99637534243069222259967.44354+xsq*p4; - q4 = 1.0; - q4 = 1612.361029677000859332072312+xsq*q4; - q4 = 1563282.754899580604737366452+xsq*q4; - q4 = 1128686837.169442121732366891+xsq*q4; - q4 = 646534088126.5275571961681500+xsq*q4; - q4 = 297663212564727.6729292742282+xsq*q4; - q4 = 108225825940881955.2553850180+xsq*q4; - q4 = 29549879358971486742.90758119+xsq*q4; - q4 = 5435310377188854170800.653097+xsq*q4; - q4 = 508206736694124324531442.4152+xsq*q4; - result = x*p4/q4+2/ae_pi*(besselj1(x, _state)*ae_log(x, _state)-1/x); - return result; -} - - -/************************************************************************* -Bessel function of second kind of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The function is evaluated by forward recurrence on -n, starting with values computed by the routines -y0() and y1(). - -If n = 0 or 1 the routine for y0 or y1 is called -directly. - -ACCURACY: - Absolute error, except relative - when y > 1: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 3.4e-15 4.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselyn(ae_int_t n, double x, ae_state *_state) -{ - ae_int_t i; - double a; - double b; - double tmp; - double s; - double result; - - - s = 1; - if( n<0 ) - { - n = -n; - if( n%2!=0 ) - { - s = -1; - } - } - if( n==0 ) - { - result = bessely0(x, _state); - return result; - } - if( n==1 ) - { - result = s*bessely1(x, _state); - return result; - } - a = bessely0(x, _state); - b = bessely1(x, _state); - for(i=1; i<=n-1; i++) - { - tmp = b; - b = 2*i/x*b-a; - a = tmp; - } - result = s*b; - return result; -} - - -/************************************************************************* -Modified Bessel function of order zero - -Returns modified Bessel function of order zero of the -argument. - -The function is defined as i0(x) = j0( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 5.8e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli0(double x, ae_state *_state) -{ - double y; - double v; - double z; - double b0; - double b1; - double b2; - double result; - - - if( ae_fp_less(x,0) ) - { - x = -x; - } - if( ae_fp_less_eq(x,8.0) ) - { - y = x/2.0-2.0; - bessel_besselmfirstcheb(-4.41534164647933937950E-18, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 3.33079451882223809783E-17, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -2.43127984654795469359E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.71539128555513303061E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -1.16853328779934516808E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 7.67618549860493561688E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -4.85644678311192946090E-13, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 2.95505266312963983461E-12, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -1.72682629144155570723E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 9.67580903537323691224E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -5.18979560163526290666E-10, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 2.65982372468238665035E-9, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -1.30002500998624804212E-8, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 6.04699502254191894932E-8, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -2.67079385394061173391E-7, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.11738753912010371815E-6, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -4.41673835845875056359E-6, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.64484480707288970893E-5, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -5.75419501008210370398E-5, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.88502885095841655729E-4, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -5.76375574538582365885E-4, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.63947561694133579842E-3, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -4.32430999505057594430E-3, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.05464603945949983183E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -2.37374148058994688156E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 4.93052842396707084878E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -9.49010970480476444210E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.71620901522208775349E-1, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -3.04682672343198398683E-1, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 6.76795274409476084995E-1, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - result = ae_exp(x, _state)*v; - return result; - } - z = 32.0/x-2.0; - bessel_besselmfirstcheb(-7.23318048787475395456E-18, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -4.83050448594418207126E-18, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 4.46562142029675999901E-17, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.46122286769746109310E-17, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -2.82762398051658348494E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -3.42548561967721913462E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.77256013305652638360E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.81168066935262242075E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -9.55484669882830764870E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -4.15056934728722208663E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.54008621752140982691E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.85277838274214270114E-13, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 7.18012445138366623367E-13, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.79417853150680611778E-12, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.32158118404477131188E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -3.14991652796324136454E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.18891471078464383424E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 4.94060238822496958910E-10, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.39623202570838634515E-9, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 2.26666899049817806459E-8, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 2.04891858946906374183E-7, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 2.89137052083475648297E-6, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 6.88975834691682398426E-5, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.36911647825569408990E-3, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 8.04490411014108831608E-1, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - result = ae_exp(x, _state)*v/ae_sqrt(x, _state); - return result; -} - - -/************************************************************************* -Modified Bessel function of order one - -Returns modified Bessel function of order one of the -argument. - -The function is defined as i1(x) = -i j1( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.9e-15 2.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli1(double x, ae_state *_state) -{ - double y; - double z; - double v; - double b0; - double b1; - double b2; - double result; - - - z = ae_fabs(x, _state); - if( ae_fp_less_eq(z,8.0) ) - { - y = z/2.0-2.0; - bessel_besselm1firstcheb(2.77791411276104639959E-18, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.11142121435816608115E-17, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.55363195773620046921E-16, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.10559694773538630805E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 7.60068429473540693410E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -5.04218550472791168711E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.22379336594557470981E-13, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.98397439776494371520E-12, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.17361862988909016308E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -6.66348972350202774223E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.62559028155211703701E-10, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.88724975172282928790E-9, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 9.38153738649577178388E-9, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -4.44505912879632808065E-8, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.00329475355213526229E-7, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -8.56872026469545474066E-7, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.47025130813767847674E-6, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.32731636560394358279E-5, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 4.78156510755005422638E-5, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.61760815825896745588E-4, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 5.12285956168575772895E-4, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.51357245063125314899E-3, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 4.15642294431288815669E-3, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.05640848946261981558E-2, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.47264490306265168283E-2, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -5.29459812080949914269E-2, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.02643658689847095384E-1, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.76416518357834055153E-1, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.52587186443633654823E-1, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - z = v*z*ae_exp(z, _state); - } - else - { - y = 32.0/z-2.0; - bessel_besselm1firstcheb(7.51729631084210481353E-18, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 4.41434832307170791151E-18, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -4.65030536848935832153E-17, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.20952592199342395980E-17, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.96262899764595013876E-16, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.30820231092092828324E-16, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.88035477551078244854E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.81440307243700780478E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.04202769841288027642E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 4.27244001671195135429E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.10154184277266431302E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -4.08355111109219731823E-13, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -7.19855177624590851209E-13, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.03562854414708950722E-12, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.41258074366137813316E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.25260358301548823856E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.89749581235054123450E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -5.58974346219658380687E-10, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.83538038596423702205E-9, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.63146884688951950684E-8, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.51223623787020892529E-7, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.88256480887769039346E-6, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.10588938762623716291E-4, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -9.76109749136146840777E-3, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 7.78576235018280120474E-1, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - z = v*ae_exp(z, _state)/ae_sqrt(z, _state); - } - if( ae_fp_less(x,0) ) - { - z = -z; - } - result = z; - return result; -} - - -/************************************************************************* -Modified Bessel function, second kind, order zero - -Returns modified Bessel function of the second kind -of order zero of the argument. - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - -Tested at 2000 random points between 0 and 8. Peak absolute -error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk0(double x, ae_state *_state) -{ - double y; - double z; - double v; - double b0; - double b1; - double b2; - double result; - - - ae_assert(ae_fp_greater(x,0), "Domain error in BesselK0: x<=0", _state); - if( ae_fp_less_eq(x,2) ) - { - y = x*x-2.0; - bessel_besselmfirstcheb(1.37446543561352307156E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 4.25981614279661018399E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.03496952576338420167E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.90451637722020886025E-9, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 2.53479107902614945675E-7, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 2.28621210311945178607E-5, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 1.26461541144692592338E-3, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 3.59799365153615016266E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, 3.44289899924628486886E-1, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(y, -5.35327393233902768720E-1, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - v = v-ae_log(0.5*x, _state)*besseli0(x, _state); - } - else - { - z = 8.0/x-2.0; - bessel_besselmfirstcheb(5.30043377268626276149E-18, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.64758043015242134646E-17, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 5.21039150503902756861E-17, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.67823109680541210385E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 5.51205597852431940784E-16, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.84859337734377901440E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 6.34007647740507060557E-15, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -2.22751332699166985548E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 8.03289077536357521100E-14, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -2.98009692317273043925E-13, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.14034058820847496303E-12, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -4.51459788337394416547E-12, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.85594911495471785253E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -7.95748924447710747776E-11, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 3.57739728140030116597E-10, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.69753450938905987466E-9, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 8.57403401741422608519E-9, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -4.66048989768794782956E-8, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 2.76681363944501510342E-7, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.83175552271911948767E-6, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.39498137188764993662E-5, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -1.28495495816278026384E-4, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 1.56988388573005337491E-3, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, -3.14481013119645005427E-2, &b0, &b1, &b2, _state); - bessel_besselmnextcheb(z, 2.44030308206595545468E0, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - v = v*ae_exp(-x, _state)/ae_sqrt(x, _state); - } - result = v; - return result; -} - - -/************************************************************************* -Modified Bessel function, second kind, order one - -Computes the modified Bessel function of the second kind -of order one of the argument. - -The range is partitioned into the two intervals [0,2] and -(2, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk1(double x, ae_state *_state) -{ - double y; - double z; - double v; - double b0; - double b1; - double b2; - double result; - - - z = 0.5*x; - ae_assert(ae_fp_greater(z,0), "Domain error in K1", _state); - if( ae_fp_less_eq(x,2) ) - { - y = x*x-2.0; - bessel_besselm1firstcheb(-7.02386347938628759343E-18, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.42744985051936593393E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -6.66690169419932900609E-13, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.41148839263352776110E-10, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.21338763073472585583E-8, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.43340614156596823496E-6, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.73028895751305206302E-4, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -6.97572385963986435018E-3, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.22611180822657148235E-1, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.53155960776544875667E-1, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.52530022733894777053E0, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - result = ae_log(z, _state)*besseli1(x, _state)+v/x; - } - else - { - y = 8.0/x-2.0; - bessel_besselm1firstcheb(-5.75674448366501715755E-18, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.79405087314755922667E-17, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -5.68946255844285935196E-17, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.83809354436663880070E-16, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -6.05704724837331885336E-16, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.03870316562433424052E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -7.01983709041831346144E-15, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.47715442448130437068E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -8.97670518232499435011E-14, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 3.34841966607842919884E-13, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.28917396095102890680E-12, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 5.13963967348173025100E-12, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.12996783842756842877E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 9.21831518760500529508E-11, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -4.19035475934189648750E-10, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.01504975519703286596E-9, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.03457624656780970260E-8, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 5.74108412545004946722E-8, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -3.50196060308781257119E-7, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.40648494783721712015E-6, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -1.93619797416608296024E-5, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.95215518471351631108E-4, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, -2.85781685962277938680E-3, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 1.03923736576817238437E-1, &b0, &b1, &b2, _state); - bessel_besselm1nextcheb(y, 2.72062619048444266945E0, &b0, &b1, &b2, _state); - v = 0.5*(b0-b2); - result = ae_exp(-x, _state)*v/ae_sqrt(x, _state); - } - return result; -} - - -/************************************************************************* -Modified Bessel function, second kind, integer order - -Returns modified Bessel function of the second kind -of order n of the argument. - -The range is partitioned into the two intervals [0,9.55] and -(9.55, infinity). An ascending power series is used in the -low range, and an asymptotic expansion in the high range. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 90000 1.8e-8 3.0e-10 - -Error is high only near the crossover point x = 9.55 -between the two expansions used. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselkn(ae_int_t nn, double x, ae_state *_state) -{ - double k; - double kf; - double nk1f; - double nkf; - double zn; - double t; - double s; - double z0; - double z; - double ans; - double fn; - double pn; - double pk; - double zmn; - double tlg; - double tox; - ae_int_t i; - ae_int_t n; - double eul; - double result; - - - eul = 5.772156649015328606065e-1; - if( nn<0 ) - { - n = -nn; - } - else - { - n = nn; - } - ae_assert(n<=31, "Overflow in BesselKN", _state); - ae_assert(ae_fp_greater(x,0), "Domain error in BesselKN", _state); - if( ae_fp_less_eq(x,9.55) ) - { - ans = 0.0; - z0 = 0.25*x*x; - fn = 1.0; - pn = 0.0; - zmn = 1.0; - tox = 2.0/x; - if( n>0 ) - { - pn = -eul; - k = 1.0; - for(i=1; i<=n-1; i++) - { - pn = pn+1.0/k; - k = k+1.0; - fn = fn*k; - } - zmn = tox; - if( n==1 ) - { - ans = 1.0/x; - } - else - { - nk1f = fn/n; - kf = 1.0; - s = nk1f; - z = -z0; - zn = 1.0; - for(i=1; i<=n-1; i++) - { - nk1f = nk1f/(n-i); - kf = kf*i; - zn = zn*z; - t = nk1f*zn/kf; - s = s+t; - ae_assert(ae_fp_greater(ae_maxrealnumber-ae_fabs(t, _state),ae_fabs(s, _state)), "Overflow in BesselKN", _state); - ae_assert(!(ae_fp_greater(tox,1.0)&&ae_fp_less(ae_maxrealnumber/tox,zmn)), "Overflow in BesselKN", _state); - zmn = zmn*tox; - } - s = s*0.5; - t = ae_fabs(s, _state); - ae_assert(!(ae_fp_greater(zmn,1.0)&&ae_fp_less(ae_maxrealnumber/zmn,t)), "Overflow in BesselKN", _state); - ae_assert(!(ae_fp_greater(t,1.0)&&ae_fp_less(ae_maxrealnumber/t,zmn)), "Overflow in BesselKN", _state); - ans = s*zmn; - } - } - tlg = 2.0*ae_log(0.5*x, _state); - pk = -eul; - if( n==0 ) - { - pn = pk; - t = 1.0; - } - else - { - pn = pn+1.0/n; - t = 1.0/fn; - } - s = (pk+pn-tlg)*t; - k = 1.0; - do - { - t = t*(z0/(k*(k+n))); - pk = pk+1.0/k; - pn = pn+1.0/(k+n); - s = s+(pk+pn-tlg)*t; - k = k+1.0; - } - while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); - s = 0.5*s/zmn; - if( n%2!=0 ) - { - s = -s; - } - ans = ans+s; - result = ans; - return result; - } - if( ae_fp_greater(x,ae_log(ae_maxrealnumber, _state)) ) - { - result = 0; - return result; - } - k = n; - pn = 4.0*k*k; - pk = 1.0; - z0 = 8.0*x; - fn = 1.0; - t = 1.0; - s = t; - nkf = ae_maxrealnumber; - i = 0; - do - { - z = pn-pk*pk; - t = t*z/(fn*z0); - nk1f = ae_fabs(t, _state); - if( i>=n&&ae_fp_greater(nk1f,nkf) ) - { - break; - } - nkf = nk1f; - s = s+t; - fn = fn+1.0; - pk = pk+2.0; - i = i+1; - } - while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); - result = ae_exp(-x, _state)*ae_sqrt(ae_pi/(2.0*x), _state)*s; - return result; -} - - -/************************************************************************* -Internal subroutine - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -static void bessel_besselmfirstcheb(double c, - double* b0, - double* b1, - double* b2, - ae_state *_state) -{ - - - *b0 = c; - *b1 = 0.0; - *b2 = 0.0; -} - - -/************************************************************************* -Internal subroutine - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -static void bessel_besselmnextcheb(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state) -{ - - - *b2 = *b1; - *b1 = *b0; - *b0 = x*(*b1)-(*b2)+c; -} - - -/************************************************************************* -Internal subroutine - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -static void bessel_besselm1firstcheb(double c, - double* b0, - double* b1, - double* b2, - ae_state *_state) -{ - - - *b0 = c; - *b1 = 0.0; - *b2 = 0.0; -} - - -/************************************************************************* -Internal subroutine - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -static void bessel_besselm1nextcheb(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state) -{ - - - *b2 = *b1; - *b1 = *b0; - *b0 = x*(*b1)-(*b2)+c; -} - - -static void bessel_besselasympt0(double x, - double* pzero, - double* qzero, - ae_state *_state) -{ - double xsq; - double p2; - double q2; - double p3; - double q3; - - *pzero = 0; - *qzero = 0; - - xsq = 64.0/(x*x); - p2 = 0.0; - p2 = 2485.271928957404011288128951+xsq*p2; - p2 = 153982.6532623911470917825993+xsq*p2; - p2 = 2016135.283049983642487182349+xsq*p2; - p2 = 8413041.456550439208464315611+xsq*p2; - p2 = 12332384.76817638145232406055+xsq*p2; - p2 = 5393485.083869438325262122897+xsq*p2; - q2 = 1.0; - q2 = 2615.700736920839685159081813+xsq*q2; - q2 = 156001.7276940030940592769933+xsq*q2; - q2 = 2025066.801570134013891035236+xsq*q2; - q2 = 8426449.050629797331554404810+xsq*q2; - q2 = 12338310.22786324960844856182+xsq*q2; - q2 = 5393485.083869438325560444960+xsq*q2; - p3 = -0.0; - p3 = -4.887199395841261531199129300+xsq*p3; - p3 = -226.2630641933704113967255053+xsq*p3; - p3 = -2365.956170779108192723612816+xsq*p3; - p3 = -8239.066313485606568803548860+xsq*p3; - p3 = -10381.41698748464093880530341+xsq*p3; - p3 = -3984.617357595222463506790588+xsq*p3; - q3 = 1.0; - q3 = 408.7714673983499223402830260+xsq*q3; - q3 = 15704.89191515395519392882766+xsq*q3; - q3 = 156021.3206679291652539287109+xsq*q3; - q3 = 533291.3634216897168722255057+xsq*q3; - q3 = 666745.4239319826986004038103+xsq*q3; - q3 = 255015.5108860942382983170882+xsq*q3; - *pzero = p2/q2; - *qzero = 8*p3/q3/x; -} - - -static void bessel_besselasympt1(double x, - double* pzero, - double* qzero, - ae_state *_state) -{ - double xsq; - double p2; - double q2; - double p3; - double q3; - - *pzero = 0; - *qzero = 0; - - xsq = 64.0/(x*x); - p2 = -1611.616644324610116477412898; - p2 = -109824.0554345934672737413139+xsq*p2; - p2 = -1523529.351181137383255105722+xsq*p2; - p2 = -6603373.248364939109255245434+xsq*p2; - p2 = -9942246.505077641195658377899+xsq*p2; - p2 = -4435757.816794127857114720794+xsq*p2; - q2 = 1.0; - q2 = -1455.009440190496182453565068+xsq*q2; - q2 = -107263.8599110382011903063867+xsq*q2; - q2 = -1511809.506634160881644546358+xsq*q2; - q2 = -6585339.479723087072826915069+xsq*q2; - q2 = -9934124.389934585658967556309+xsq*q2; - q2 = -4435757.816794127856828016962+xsq*q2; - p3 = 35.26513384663603218592175580; - p3 = 1706.375429020768002061283546+xsq*p3; - p3 = 18494.26287322386679652009819+xsq*p3; - p3 = 66178.83658127083517939992166+xsq*p3; - p3 = 85145.16067533570196555001171+xsq*p3; - p3 = 33220.91340985722351859704442+xsq*p3; - q3 = 1.0; - q3 = 863.8367769604990967475517183+xsq*q3; - q3 = 37890.22974577220264142952256+xsq*q3; - q3 = 400294.4358226697511708610813+xsq*q3; - q3 = 1419460.669603720892855755253+xsq*q3; - q3 = 1819458.042243997298924553839+xsq*q3; - q3 = 708712.8194102874357377502472+xsq*q3; - *pzero = p2/q2; - *qzero = 8*p3/q3/x; -} - - - - -/************************************************************************* -Beta function - - - - - - | (a) | (b) -beta( a, b ) = -----------. - - - | (a+b) - -For large arguments the logarithm of the function is -evaluated using lgam(), then exponentiated. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 8.1e-14 1.1e-14 - -Cephes Math Library Release 2.0: April, 1987 -Copyright 1984, 1987 by Stephen L. Moshier -*************************************************************************/ -double beta(double a, double b, ae_state *_state) -{ - double y; - double sg; - double s; - double result; - - - sg = 1; - ae_assert(ae_fp_greater(a,0)||ae_fp_neq(a,ae_ifloor(a, _state)), "Overflow in Beta", _state); - ae_assert(ae_fp_greater(b,0)||ae_fp_neq(b,ae_ifloor(b, _state)), "Overflow in Beta", _state); - y = a+b; - if( ae_fp_greater(ae_fabs(y, _state),171.624376956302725) ) - { - y = lngamma(y, &s, _state); - sg = sg*s; - y = lngamma(b, &s, _state)-y; - sg = sg*s; - y = lngamma(a, &s, _state)+y; - sg = sg*s; - ae_assert(ae_fp_less_eq(y,ae_log(ae_maxrealnumber, _state)), "Overflow in Beta", _state); - result = sg*ae_exp(y, _state); - return result; - } - y = gammafunction(y, _state); - ae_assert(ae_fp_neq(y,0), "Overflow in Beta", _state); - if( ae_fp_greater(a,b) ) - { - y = gammafunction(a, _state)/y; - y = y*gammafunction(b, _state); - } - else - { - y = gammafunction(b, _state)/y; - y = y*gammafunction(a, _state); - } - result = y; - return result; -} - - - - -/************************************************************************* -Incomplete beta integral - -Returns incomplete beta integral of the arguments, evaluated -from zero to x. The function is defined as - - x - - - - | (a+b) | | a-1 b-1 - ----------- | t (1-t) dt. - - - | | - | (a) | (b) - - 0 - -The domain of definition is 0 <= x <= 1. In this -implementation a and b are restricted to positive values. -The integral from x to 1 may be obtained by the symmetry -relation - - 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). - -The integral is evaluated by a continued fraction expansion -or, when b*x is small, by a power series. - -ACCURACY: - -Tested at uniformly distributed random points (a,b,x) with a and b -in "domain" and x between 0 and 1. - Relative error -arithmetic domain # trials peak rms - IEEE 0,5 10000 6.9e-15 4.5e-16 - IEEE 0,85 250000 2.2e-13 1.7e-14 - IEEE 0,1000 30000 5.3e-12 6.3e-13 - IEEE 0,10000 250000 9.3e-11 7.1e-12 - IEEE 0,100000 10000 8.7e-10 4.8e-11 -Outputs smaller than the IEEE gradual underflow threshold -were excluded from these statistics. - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletebeta(double a, double b, double x, ae_state *_state) -{ - double t; - double xc; - double w; - double y; - ae_int_t flag; - double sg; - double big; - double biginv; - double maxgam; - double minlog; - double maxlog; - double result; - - - big = 4.503599627370496e15; - biginv = 2.22044604925031308085e-16; - maxgam = 171.624376956302725; - minlog = ae_log(ae_minrealnumber, _state); - maxlog = ae_log(ae_maxrealnumber, _state); - ae_assert(ae_fp_greater(a,0)&&ae_fp_greater(b,0), "Domain error in IncompleteBeta", _state); - ae_assert(ae_fp_greater_eq(x,0)&&ae_fp_less_eq(x,1), "Domain error in IncompleteBeta", _state); - if( ae_fp_eq(x,0) ) - { - result = 0; - return result; - } - if( ae_fp_eq(x,1) ) - { - result = 1; - return result; - } - flag = 0; - if( ae_fp_less_eq(b*x,1.0)&&ae_fp_less_eq(x,0.95) ) - { - result = ibetaf_incompletebetaps(a, b, x, maxgam, _state); - return result; - } - w = 1.0-x; - if( ae_fp_greater(x,a/(a+b)) ) - { - flag = 1; - t = a; - a = b; - b = t; - xc = x; - x = w; - } - else - { - xc = w; - } - if( (flag==1&&ae_fp_less_eq(b*x,1.0))&&ae_fp_less_eq(x,0.95) ) - { - t = ibetaf_incompletebetaps(a, b, x, maxgam, _state); - if( ae_fp_less_eq(t,ae_machineepsilon) ) - { - result = 1.0-ae_machineepsilon; - } - else - { - result = 1.0-t; - } - return result; - } - y = x*(a+b-2.0)-(a-1.0); - if( ae_fp_less(y,0.0) ) - { - w = ibetaf_incompletebetafe(a, b, x, big, biginv, _state); - } - else - { - w = ibetaf_incompletebetafe2(a, b, x, big, biginv, _state)/xc; - } - y = a*ae_log(x, _state); - t = b*ae_log(xc, _state); - if( (ae_fp_less(a+b,maxgam)&&ae_fp_less(ae_fabs(y, _state),maxlog))&&ae_fp_less(ae_fabs(t, _state),maxlog) ) - { - t = ae_pow(xc, b, _state); - t = t*ae_pow(x, a, _state); - t = t/a; - t = t*w; - t = t*(gammafunction(a+b, _state)/(gammafunction(a, _state)*gammafunction(b, _state))); - if( flag==1 ) - { - if( ae_fp_less_eq(t,ae_machineepsilon) ) - { - result = 1.0-ae_machineepsilon; - } - else - { - result = 1.0-t; - } - } - else - { - result = t; - } - return result; - } - y = y+t+lngamma(a+b, &sg, _state)-lngamma(a, &sg, _state)-lngamma(b, &sg, _state); - y = y+ae_log(w/a, _state); - if( ae_fp_less(y,minlog) ) - { - t = 0.0; - } - else - { - t = ae_exp(y, _state); - } - if( flag==1 ) - { - if( ae_fp_less_eq(t,ae_machineepsilon) ) - { - t = 1.0-ae_machineepsilon; - } - else - { - t = 1.0-t; - } - } - result = t; - return result; -} - - -/************************************************************************* -Inverse of incomplete beta integral - -Given y, the function finds x such that - - incbet( a, b, x ) = y . - -The routine performs interval halving or Newton iterations to find the -root of incbet(a,b,x) - y = 0. - - -ACCURACY: - - Relative error: - x a,b -arithmetic domain domain # trials peak rms - IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 - IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 - IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 -With a and b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 - IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 -With a = .5, b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1996, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletebeta(double a, double b, double y, ae_state *_state) -{ - double aaa; - double bbb; - double y0; - double d; - double yyy; - double x; - double x0; - double x1; - double lgm; - double yp; - double di; - double dithresh; - double yl; - double yh; - double xt; - ae_int_t i; - ae_int_t rflg; - ae_int_t dir; - ae_int_t nflg; - double s; - ae_int_t mainlooppos; - ae_int_t ihalve; - ae_int_t ihalvecycle; - ae_int_t newt; - ae_int_t newtcycle; - ae_int_t breaknewtcycle; - ae_int_t breakihalvecycle; - double result; - - - i = 0; - ae_assert(ae_fp_greater_eq(y,0)&&ae_fp_less_eq(y,1), "Domain error in InvIncompleteBeta", _state); - - /* - * special cases - */ - if( ae_fp_eq(y,0) ) - { - result = 0; - return result; - } - if( ae_fp_eq(y,1.0) ) - { - result = 1; - return result; - } - - /* - * these initializations are not really necessary, - * but without them compiler complains about 'possibly uninitialized variables'. - */ - dithresh = 0; - rflg = 0; - aaa = 0; - bbb = 0; - y0 = 0; - x = 0; - yyy = 0; - lgm = 0; - dir = 0; - di = 0; - - /* - * normal initializations - */ - x0 = 0.0; - yl = 0.0; - x1 = 1.0; - yh = 1.0; - nflg = 0; - mainlooppos = 0; - ihalve = 1; - ihalvecycle = 2; - newt = 3; - newtcycle = 4; - breaknewtcycle = 5; - breakihalvecycle = 6; - - /* - * main loop - */ - for(;;) - { - - /* - * start - */ - if( mainlooppos==0 ) - { - if( ae_fp_less_eq(a,1.0)||ae_fp_less_eq(b,1.0) ) - { - dithresh = 1.0e-6; - rflg = 0; - aaa = a; - bbb = b; - y0 = y; - x = aaa/(aaa+bbb); - yyy = incompletebeta(aaa, bbb, x, _state); - mainlooppos = ihalve; - continue; - } - else - { - dithresh = 1.0e-4; - } - yp = -invnormaldistribution(y, _state); - if( ae_fp_greater(y,0.5) ) - { - rflg = 1; - aaa = b; - bbb = a; - y0 = 1.0-y; - yp = -yp; - } - else - { - rflg = 0; - aaa = a; - bbb = b; - y0 = y; - } - lgm = (yp*yp-3.0)/6.0; - x = 2.0/(1.0/(2.0*aaa-1.0)+1.0/(2.0*bbb-1.0)); - d = yp*ae_sqrt(x+lgm, _state)/x-(1.0/(2.0*bbb-1.0)-1.0/(2.0*aaa-1.0))*(lgm+5.0/6.0-2.0/(3.0*x)); - d = 2.0*d; - if( ae_fp_less(d,ae_log(ae_minrealnumber, _state)) ) - { - x = 0; - break; - } - x = aaa/(aaa+bbb*ae_exp(d, _state)); - yyy = incompletebeta(aaa, bbb, x, _state); - yp = (yyy-y0)/y0; - if( ae_fp_less(ae_fabs(yp, _state),0.2) ) - { - mainlooppos = newt; - continue; - } - mainlooppos = ihalve; - continue; - } - - /* - * ihalve - */ - if( mainlooppos==ihalve ) - { - dir = 0; - di = 0.5; - i = 0; - mainlooppos = ihalvecycle; - continue; - } - - /* - * ihalvecycle - */ - if( mainlooppos==ihalvecycle ) - { - if( i<=99 ) - { - if( i!=0 ) - { - x = x0+di*(x1-x0); - if( ae_fp_eq(x,1.0) ) - { - x = 1.0-ae_machineepsilon; - } - if( ae_fp_eq(x,0.0) ) - { - di = 0.5; - x = x0+di*(x1-x0); - if( ae_fp_eq(x,0.0) ) - { - break; - } - } - yyy = incompletebeta(aaa, bbb, x, _state); - yp = (x1-x0)/(x1+x0); - if( ae_fp_less(ae_fabs(yp, _state),dithresh) ) - { - mainlooppos = newt; - continue; - } - yp = (yyy-y0)/y0; - if( ae_fp_less(ae_fabs(yp, _state),dithresh) ) - { - mainlooppos = newt; - continue; - } - } - if( ae_fp_less(yyy,y0) ) - { - x0 = x; - yl = yyy; - if( dir<0 ) - { - dir = 0; - di = 0.5; - } - else - { - if( dir>3 ) - { - di = 1.0-(1.0-di)*(1.0-di); - } - else - { - if( dir>1 ) - { - di = 0.5*di+0.5; - } - else - { - di = (y0-yyy)/(yh-yl); - } - } - } - dir = dir+1; - if( ae_fp_greater(x0,0.75) ) - { - if( rflg==1 ) - { - rflg = 0; - aaa = a; - bbb = b; - y0 = y; - } - else - { - rflg = 1; - aaa = b; - bbb = a; - y0 = 1.0-y; - } - x = 1.0-x; - yyy = incompletebeta(aaa, bbb, x, _state); - x0 = 0.0; - yl = 0.0; - x1 = 1.0; - yh = 1.0; - mainlooppos = ihalve; - continue; - } - } - else - { - x1 = x; - if( rflg==1&&ae_fp_less(x1,ae_machineepsilon) ) - { - x = 0.0; - break; - } - yh = yyy; - if( dir>0 ) - { - dir = 0; - di = 0.5; - } - else - { - if( dir<-3 ) - { - di = di*di; - } - else - { - if( dir<-1 ) - { - di = 0.5*di; - } - else - { - di = (yyy-y0)/(yh-yl); - } - } - } - dir = dir-1; - } - i = i+1; - mainlooppos = ihalvecycle; - continue; - } - else - { - mainlooppos = breakihalvecycle; - continue; - } - } - - /* - * breakihalvecycle - */ - if( mainlooppos==breakihalvecycle ) - { - if( ae_fp_greater_eq(x0,1.0) ) - { - x = 1.0-ae_machineepsilon; - break; - } - if( ae_fp_less_eq(x,0.0) ) - { - x = 0.0; - break; - } - mainlooppos = newt; - continue; - } - - /* - * newt - */ - if( mainlooppos==newt ) - { - if( nflg!=0 ) - { - break; - } - nflg = 1; - lgm = lngamma(aaa+bbb, &s, _state)-lngamma(aaa, &s, _state)-lngamma(bbb, &s, _state); - i = 0; - mainlooppos = newtcycle; - continue; - } - - /* - * newtcycle - */ - if( mainlooppos==newtcycle ) - { - if( i<=7 ) - { - if( i!=0 ) - { - yyy = incompletebeta(aaa, bbb, x, _state); - } - if( ae_fp_less(yyy,yl) ) - { - x = x0; - yyy = yl; - } - else - { - if( ae_fp_greater(yyy,yh) ) - { - x = x1; - yyy = yh; - } - else - { - if( ae_fp_less(yyy,y0) ) - { - x0 = x; - yl = yyy; - } - else - { - x1 = x; - yh = yyy; - } - } - } - if( ae_fp_eq(x,1.0)||ae_fp_eq(x,0.0) ) - { - mainlooppos = breaknewtcycle; - continue; - } - d = (aaa-1.0)*ae_log(x, _state)+(bbb-1.0)*ae_log(1.0-x, _state)+lgm; - if( ae_fp_less(d,ae_log(ae_minrealnumber, _state)) ) - { - break; - } - if( ae_fp_greater(d,ae_log(ae_maxrealnumber, _state)) ) - { - mainlooppos = breaknewtcycle; - continue; - } - d = ae_exp(d, _state); - d = (yyy-y0)/d; - xt = x-d; - if( ae_fp_less_eq(xt,x0) ) - { - yyy = (x-x0)/(x1-x0); - xt = x0+0.5*yyy*(x-x0); - if( ae_fp_less_eq(xt,0.0) ) - { - mainlooppos = breaknewtcycle; - continue; - } - } - if( ae_fp_greater_eq(xt,x1) ) - { - yyy = (x1-x)/(x1-x0); - xt = x1-0.5*yyy*(x1-x); - if( ae_fp_greater_eq(xt,1.0) ) - { - mainlooppos = breaknewtcycle; - continue; - } - } - x = xt; - if( ae_fp_less(ae_fabs(d/x, _state),128.0*ae_machineepsilon) ) - { - break; - } - i = i+1; - mainlooppos = newtcycle; - continue; - } - else - { - mainlooppos = breaknewtcycle; - continue; - } - } - - /* - * breaknewtcycle - */ - if( mainlooppos==breaknewtcycle ) - { - dithresh = 256.0*ae_machineepsilon; - mainlooppos = ihalve; - continue; - } - } - - /* - * done - */ - if( rflg!=0 ) - { - if( ae_fp_less_eq(x,ae_machineepsilon) ) - { - x = 1.0-ae_machineepsilon; - } - else - { - x = 1.0-x; - } - } - result = x; - return result; -} - - -/************************************************************************* -Continued fraction expansion #1 for incomplete beta integral - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -static double ibetaf_incompletebetafe(double a, - double b, - double x, - double big, - double biginv, - ae_state *_state) -{ - double xk; - double pk; - double pkm1; - double pkm2; - double qk; - double qkm1; - double qkm2; - double k1; - double k2; - double k3; - double k4; - double k5; - double k6; - double k7; - double k8; - double r; - double t; - double ans; - double thresh; - ae_int_t n; - double result; - - - k1 = a; - k2 = a+b; - k3 = a; - k4 = a+1.0; - k5 = 1.0; - k6 = b-1.0; - k7 = k4; - k8 = a+2.0; - pkm2 = 0.0; - qkm2 = 1.0; - pkm1 = 1.0; - qkm1 = 1.0; - ans = 1.0; - r = 1.0; - n = 0; - thresh = 3.0*ae_machineepsilon; - do - { - xk = -x*k1*k2/(k3*k4); - pk = pkm1+pkm2*xk; - qk = qkm1+qkm2*xk; - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - xk = x*k5*k6/(k7*k8); - pk = pkm1+pkm2*xk; - qk = qkm1+qkm2*xk; - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - if( ae_fp_neq(qk,0) ) - { - r = pk/qk; - } - if( ae_fp_neq(r,0) ) - { - t = ae_fabs((ans-r)/r, _state); - ans = r; - } - else - { - t = 1.0; - } - if( ae_fp_less(t,thresh) ) - { - break; - } - k1 = k1+1.0; - k2 = k2+1.0; - k3 = k3+2.0; - k4 = k4+2.0; - k5 = k5+1.0; - k6 = k6-1.0; - k7 = k7+2.0; - k8 = k8+2.0; - if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) - { - pkm2 = pkm2*biginv; - pkm1 = pkm1*biginv; - qkm2 = qkm2*biginv; - qkm1 = qkm1*biginv; - } - if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) - { - pkm2 = pkm2*big; - pkm1 = pkm1*big; - qkm2 = qkm2*big; - qkm1 = qkm1*big; - } - n = n+1; - } - while(n!=300); - result = ans; - return result; -} - - -/************************************************************************* -Continued fraction expansion #2 -for incomplete beta integral - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -static double ibetaf_incompletebetafe2(double a, - double b, - double x, - double big, - double biginv, - ae_state *_state) -{ - double xk; - double pk; - double pkm1; - double pkm2; - double qk; - double qkm1; - double qkm2; - double k1; - double k2; - double k3; - double k4; - double k5; - double k6; - double k7; - double k8; - double r; - double t; - double ans; - double z; - double thresh; - ae_int_t n; - double result; - - - k1 = a; - k2 = b-1.0; - k3 = a; - k4 = a+1.0; - k5 = 1.0; - k6 = a+b; - k7 = a+1.0; - k8 = a+2.0; - pkm2 = 0.0; - qkm2 = 1.0; - pkm1 = 1.0; - qkm1 = 1.0; - z = x/(1.0-x); - ans = 1.0; - r = 1.0; - n = 0; - thresh = 3.0*ae_machineepsilon; - do - { - xk = -z*k1*k2/(k3*k4); - pk = pkm1+pkm2*xk; - qk = qkm1+qkm2*xk; - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - xk = z*k5*k6/(k7*k8); - pk = pkm1+pkm2*xk; - qk = qkm1+qkm2*xk; - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - if( ae_fp_neq(qk,0) ) - { - r = pk/qk; - } - if( ae_fp_neq(r,0) ) - { - t = ae_fabs((ans-r)/r, _state); - ans = r; - } - else - { - t = 1.0; - } - if( ae_fp_less(t,thresh) ) - { - break; - } - k1 = k1+1.0; - k2 = k2-1.0; - k3 = k3+2.0; - k4 = k4+2.0; - k5 = k5+1.0; - k6 = k6+1.0; - k7 = k7+2.0; - k8 = k8+2.0; - if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) - { - pkm2 = pkm2*biginv; - pkm1 = pkm1*biginv; - qkm2 = qkm2*biginv; - qkm1 = qkm1*biginv; - } - if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) - { - pkm2 = pkm2*big; - pkm1 = pkm1*big; - qkm2 = qkm2*big; - qkm1 = qkm1*big; - } - n = n+1; - } - while(n!=300); - result = ans; - return result; -} - - -/************************************************************************* -Power series for incomplete beta integral. -Use when b*x is small and x not too close to 1. - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -static double ibetaf_incompletebetaps(double a, - double b, - double x, - double maxgam, - ae_state *_state) -{ - double s; - double t; - double u; - double v; - double n; - double t1; - double z; - double ai; - double sg; - double result; - - - ai = 1.0/a; - u = (1.0-b)*x; - v = u/(a+1.0); - t1 = v; - t = u; - n = 2.0; - s = 0.0; - z = ae_machineepsilon*ai; - while(ae_fp_greater(ae_fabs(v, _state),z)) - { - u = (n-b)*x/n; - t = t*u; - v = t/(a+n); - s = s+v; - n = n+1.0; - } - s = s+t1; - s = s+ai; - u = a*ae_log(x, _state); - if( ae_fp_less(a+b,maxgam)&&ae_fp_less(ae_fabs(u, _state),ae_log(ae_maxrealnumber, _state)) ) - { - t = gammafunction(a+b, _state)/(gammafunction(a, _state)*gammafunction(b, _state)); - s = s*t*ae_pow(x, a, _state); - } - else - { - t = lngamma(a+b, &sg, _state)-lngamma(a, &sg, _state)-lngamma(b, &sg, _state)+u+ae_log(s, _state); - if( ae_fp_less(t,ae_log(ae_minrealnumber, _state)) ) - { - s = 0.0; - } - else - { - s = ae_exp(t, _state); - } - } - result = s; - return result; -} - - - - -/************************************************************************* -Binomial distribution - -Returns the sum of the terms 0 through k of the Binomial -probability density: - - k - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=0 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p), with p between 0 and 1. - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 4.3e-15 2.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialdistribution(ae_int_t k, - ae_int_t n, - double p, - ae_state *_state) -{ - double dk; - double dn; - double result; - - - ae_assert(ae_fp_greater_eq(p,0)&&ae_fp_less_eq(p,1), "Domain error in BinomialDistribution", _state); - ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistribution", _state); - if( k==-1 ) - { - result = 0; - return result; - } - if( k==n ) - { - result = 1; - return result; - } - dn = n-k; - if( k==0 ) - { - dk = ae_pow(1.0-p, dn, _state); - } - else - { - dk = k+1; - dk = incompletebeta(dn, dk, 1.0-p, _state); - } - result = dk; - return result; -} - - -/************************************************************************* -Complemented binomial distribution - -Returns the sum of the terms k+1 through n of the Binomial -probability density: - - n - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=k+1 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 6.7e-15 8.2e-16 - For p between 0 and .001: - IEEE 0,100 100000 1.5e-13 2.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialcdistribution(ae_int_t k, - ae_int_t n, - double p, - ae_state *_state) -{ - double dk; - double dn; - double result; - - - ae_assert(ae_fp_greater_eq(p,0)&&ae_fp_less_eq(p,1), "Domain error in BinomialDistributionC", _state); - ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistributionC", _state); - if( k==-1 ) - { - result = 1; - return result; - } - if( k==n ) - { - result = 0; - return result; - } - dn = n-k; - if( k==0 ) - { - if( ae_fp_less(p,0.01) ) - { - dk = -nuexpm1(dn*nulog1p(-p, _state), _state); - } - else - { - dk = 1.0-ae_pow(1.0-p, dn, _state); - } - } - else - { - dk = k+1; - dk = incompletebeta(dk, dn, p, _state); - } - result = dk; - return result; -} - - -/************************************************************************* -Inverse binomial distribution - -Finds the event probability p such that the sum of the -terms 0 through k of the Binomial probability density -is equal to the given cumulative probability y. - -This is accomplished using the inverse beta integral -function and the relation - -1 - p = incbi( n-k, k+1, y ). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 2.3e-14 6.4e-16 - IEEE 0,10000 100000 6.6e-12 1.2e-13 - For p between 10^-6 and 0.001: - IEEE 0,100 100000 2.0e-12 1.3e-14 - IEEE 0,10000 100000 1.5e-12 3.2e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invbinomialdistribution(ae_int_t k, - ae_int_t n, - double y, - ae_state *_state) -{ - double dk; - double dn; - double p; - double result; - - - ae_assert(k>=0&&k=0 - x - argument, -1 <= x <= 1 - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevcalculate(ae_int_t r, - ae_int_t n, - double x, - ae_state *_state) -{ - ae_int_t i; - double a; - double b; - double result; - - - result = 0; - - /* - * Prepare A and B - */ - if( r==1 ) - { - a = 1; - b = x; - } - else - { - a = 1; - b = 2*x; - } - - /* - * Special cases: N=0 or N=1 - */ - if( n==0 ) - { - result = a; - return result; - } - if( n==1 ) - { - result = b; - return result; - } - - /* - * General case: N>=2 - */ - for(i=2; i<=n; i++) - { - result = 2*x*b-a; - a = b; - b = result; - } - return result; -} - - -/************************************************************************* -Summation of Chebyshev polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) -or - c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) -depending on the R. - -Parameters: - r - polynomial kind, either 1 or 2. - n - degree, n>=0 - x - argument - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevsum(/* Real */ ae_vector* c, - ae_int_t r, - ae_int_t n, - double x, - ae_state *_state) -{ - double b1; - double b2; - ae_int_t i; - double result; - - - b1 = 0; - b2 = 0; - for(i=n; i>=1; i--) - { - result = 2*x*b1-b2+c->ptr.p_double[i]; - b2 = b1; - b1 = result; - } - if( r==1 ) - { - result = -b2+x*b1+c->ptr.p_double[0]; - } - else - { - result = -b2+2*x*b1+c->ptr.p_double[0]; - } - return result; -} - - -/************************************************************************* -Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void chebyshevcoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(c); - - ae_vector_set_length(c, n+1, _state); - for(i=0; i<=n; i++) - { - c->ptr.p_double[i] = 0; - } - if( n==0||n==1 ) - { - c->ptr.p_double[n] = 1; - } - else - { - c->ptr.p_double[n] = ae_exp((n-1)*ae_log(2, _state), _state); - for(i=0; i<=n/2-1; i++) - { - c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1)/(n-i-1); - } - } -} - - -/************************************************************************* -Conversion of a series of Chebyshev polynomials to a power series. - -Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as -B[0] + B[1]*X + ... + B[N]*X^N. - -Input parameters: - A - Chebyshev series coefficients - N - degree, N>=0 - -Output parameters - B - power series coefficients -*************************************************************************/ -void fromchebyshev(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* b, - ae_state *_state) -{ - ae_int_t i; - ae_int_t k; - double e; - double d; - - ae_vector_clear(b); - - ae_vector_set_length(b, n+1, _state); - for(i=0; i<=n; i++) - { - b->ptr.p_double[i] = 0; - } - d = 0; - i = 0; - do - { - k = i; - do - { - e = b->ptr.p_double[k]; - b->ptr.p_double[k] = 0; - if( i<=1&&k==i ) - { - b->ptr.p_double[k] = 1; - } - else - { - if( i!=0 ) - { - b->ptr.p_double[k] = 2*d; - } - if( k>i+1 ) - { - b->ptr.p_double[k] = b->ptr.p_double[k]-b->ptr.p_double[k-2]; - } - } - d = e; - k = k+1; - } - while(k<=n); - d = b->ptr.p_double[i]; - e = 0; - k = i; - while(k<=n) - { - e = e+b->ptr.p_double[k]*a->ptr.p_double[k]; - k = k+2; - } - b->ptr.p_double[i] = e; - i = i+1; - } - while(i<=n); -} - - - - -/************************************************************************* -Chi-square distribution - -Returns the area under the left hand tail (from 0 to x) -of the Chi square probability density function with -v degrees of freedom. - - - x - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - 0 - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquaredistribution(double v, double x, ae_state *_state) -{ - double result; - - - ae_assert(ae_fp_greater_eq(x,0)&&ae_fp_greater_eq(v,1), "Domain error in ChiSquareDistribution", _state); - result = incompletegamma(v/2.0, x/2.0, _state); - return result; -} - - -/************************************************************************* -Complemented Chi-square distribution - -Returns the area under the right hand tail (from x to -infinity) of the Chi square probability density function -with v degrees of freedom: - - inf. - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - x - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquarecdistribution(double v, double x, ae_state *_state) -{ - double result; - - - ae_assert(ae_fp_greater_eq(x,0)&&ae_fp_greater_eq(v,1), "Domain error in ChiSquareDistributionC", _state); - result = incompletegammac(v/2.0, x/2.0, _state); - return result; -} - - -/************************************************************************* -Inverse of complemented Chi-square distribution - -Finds the Chi-square argument x such that the integral -from x to infinity of the Chi-square density is equal -to the given cumulative probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - x/2 = igami( df/2, y ); - -ACCURACY: - -See inverse incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double invchisquaredistribution(double v, double y, ae_state *_state) -{ - double result; - - - ae_assert((ae_fp_greater_eq(y,0)&&ae_fp_less_eq(y,1))&&ae_fp_greater_eq(v,1), "Domain error in InvChiSquareDistribution", _state); - result = 2*invincompletegammac(0.5*v, y, _state); - return result; -} - - - - -/************************************************************************* -Dawson's Integral - -Approximates the integral - - x - - - 2 | | 2 - dawsn(x) = exp( -x ) | exp( t ) dt - | | - - - 0 - -Three different rational approximations are employed, for -the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,10 10000 6.9e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double dawsonintegral(double x, ae_state *_state) -{ - double x2; - double y; - ae_int_t sg; - double an; - double ad; - double bn; - double bd; - double cn; - double cd; - double result; - - - sg = 1; - if( ae_fp_less(x,0) ) - { - sg = -1; - x = -x; - } - if( ae_fp_less(x,3.25) ) - { - x2 = x*x; - an = 1.13681498971755972054E-11; - an = an*x2+8.49262267667473811108E-10; - an = an*x2+1.94434204175553054283E-8; - an = an*x2+9.53151741254484363489E-7; - an = an*x2+3.07828309874913200438E-6; - an = an*x2+3.52513368520288738649E-4; - an = an*x2+(-8.50149846724410912031E-4); - an = an*x2+4.22618223005546594270E-2; - an = an*x2+(-9.17480371773452345351E-2); - an = an*x2+9.99999999999999994612E-1; - ad = 2.40372073066762605484E-11; - ad = ad*x2+1.48864681368493396752E-9; - ad = ad*x2+5.21265281010541664570E-8; - ad = ad*x2+1.27258478273186970203E-6; - ad = ad*x2+2.32490249820789513991E-5; - ad = ad*x2+3.25524741826057911661E-4; - ad = ad*x2+3.48805814657162590916E-3; - ad = ad*x2+2.79448531198828973716E-2; - ad = ad*x2+1.58874241960120565368E-1; - ad = ad*x2+5.74918629489320327824E-1; - ad = ad*x2+1.00000000000000000539E0; - y = x*an/ad; - result = sg*y; - return result; - } - x2 = 1.0/(x*x); - if( ae_fp_less(x,6.25) ) - { - bn = 5.08955156417900903354E-1; - bn = bn*x2-2.44754418142697847934E-1; - bn = bn*x2+9.41512335303534411857E-2; - bn = bn*x2-2.18711255142039025206E-2; - bn = bn*x2+3.66207612329569181322E-3; - bn = bn*x2-4.23209114460388756528E-4; - bn = bn*x2+3.59641304793896631888E-5; - bn = bn*x2-2.14640351719968974225E-6; - bn = bn*x2+9.10010780076391431042E-8; - bn = bn*x2-2.40274520828250956942E-9; - bn = bn*x2+3.59233385440928410398E-11; - bd = 1.00000000000000000000E0; - bd = bd*x2-6.31839869873368190192E-1; - bd = bd*x2+2.36706788228248691528E-1; - bd = bd*x2-5.31806367003223277662E-2; - bd = bd*x2+8.48041718586295374409E-3; - bd = bd*x2-9.47996768486665330168E-4; - bd = bd*x2+7.81025592944552338085E-5; - bd = bd*x2-4.55875153252442634831E-6; - bd = bd*x2+1.89100358111421846170E-7; - bd = bd*x2-4.91324691331920606875E-9; - bd = bd*x2+7.18466403235734541950E-11; - y = 1.0/x+x2*bn/(bd*x); - result = sg*0.5*y; - return result; - } - if( ae_fp_greater(x,1.0E9) ) - { - result = sg*0.5/x; - return result; - } - cn = -5.90592860534773254987E-1; - cn = cn*x2+6.29235242724368800674E-1; - cn = cn*x2-1.72858975380388136411E-1; - cn = cn*x2+1.64837047825189632310E-2; - cn = cn*x2-4.86827613020462700845E-4; - cd = 1.00000000000000000000E0; - cd = cd*x2-2.69820057197544900361E0; - cd = cd*x2+1.73270799045947845857E0; - cd = cd*x2-3.93708582281939493482E-1; - cd = cd*x2+3.44278924041233391079E-2; - cd = cd*x2-9.73655226040941223894E-4; - y = 1.0/x+x2*cn/(cd*x); - result = sg*0.5*y; - return result; -} - - - - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -using the approximation - - P(x) - log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegralk(double m, ae_state *_state) -{ - double result; - - - result = ellipticintegralkhighprecision(1.0-m, _state); - return result; -} - - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -where m = 1 - m1, using the approximation - - P(x) - log x Q(x). - -The argument m1 is used rather than m so that the logarithmic -singularity at m = 1 will be shifted to the origin; this -preserves maximum accuracy. - -K(0) = pi/2. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Àëãîðèòì âçÿò èç áèáëèîòåêè Cephes -*************************************************************************/ -double ellipticintegralkhighprecision(double m1, ae_state *_state) -{ - double p; - double q; - double result; - - - if( ae_fp_less_eq(m1,ae_machineepsilon) ) - { - result = 1.3862943611198906188E0-0.5*ae_log(m1, _state); - } - else - { - p = 1.37982864606273237150E-4; - p = p*m1+2.28025724005875567385E-3; - p = p*m1+7.97404013220415179367E-3; - p = p*m1+9.85821379021226008714E-3; - p = p*m1+6.87489687449949877925E-3; - p = p*m1+6.18901033637687613229E-3; - p = p*m1+8.79078273952743772254E-3; - p = p*m1+1.49380448916805252718E-2; - p = p*m1+3.08851465246711995998E-2; - p = p*m1+9.65735902811690126535E-2; - p = p*m1+1.38629436111989062502E0; - q = 2.94078955048598507511E-5; - q = q*m1+9.14184723865917226571E-4; - q = q*m1+5.94058303753167793257E-3; - q = q*m1+1.54850516649762399335E-2; - q = q*m1+2.39089602715924892727E-2; - q = q*m1+3.01204715227604046988E-2; - q = q*m1+3.73774314173823228969E-2; - q = q*m1+4.88280347570998239232E-2; - q = q*m1+7.03124996963957469739E-2; - q = q*m1+1.24999999999870820058E-1; - q = q*m1+4.99999999999999999821E-1; - result = p-q*ae_log(m1, _state); - } - return result; -} - - -/************************************************************************* -Incomplete elliptic integral of the first kind F(phi|m) - -Approximates the integral - - - - phi - - - | | - | dt -F(phi_\m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - - - - -ACCURACY: - -Tested at random points with m in [0, 1] and phi as indicated. - - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 200000 7.4e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegralk(double phi, double m, ae_state *_state) -{ - double a; - double b; - double c; - double e; - double temp; - double pio2; - double t; - double k; - ae_int_t d; - ae_int_t md; - ae_int_t s; - ae_int_t npio2; - double result; - - - pio2 = 1.57079632679489661923; - if( ae_fp_eq(m,0) ) - { - result = phi; - return result; - } - a = 1-m; - if( ae_fp_eq(a,0) ) - { - result = ae_log(ae_tan(0.5*(pio2+phi), _state), _state); - return result; - } - npio2 = ae_ifloor(phi/pio2, _state); - if( npio2%2!=0 ) - { - npio2 = npio2+1; - } - if( npio2!=0 ) - { - k = ellipticintegralk(1-a, _state); - phi = phi-npio2*pio2; - } - else - { - k = 0; - } - if( ae_fp_less(phi,0) ) - { - phi = -phi; - s = -1; - } - else - { - s = 0; - } - b = ae_sqrt(a, _state); - t = ae_tan(phi, _state); - if( ae_fp_greater(ae_fabs(t, _state),10) ) - { - e = 1.0/(b*t); - if( ae_fp_less(ae_fabs(e, _state),10) ) - { - e = ae_atan(e, _state); - if( npio2==0 ) - { - k = ellipticintegralk(1-a, _state); - } - temp = k-incompleteellipticintegralk(e, m, _state); - if( s<0 ) - { - temp = -temp; - } - result = temp+npio2*k; - return result; - } - } - a = 1.0; - c = ae_sqrt(m, _state); - d = 1; - md = 0; - while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) - { - temp = b/a; - phi = phi+ae_atan(t*temp, _state)+md*ae_pi; - md = ae_trunc((phi+pio2)/ae_pi, _state); - t = t*(1.0+temp)/(1.0-temp*t*t); - c = 0.5*(a-b); - temp = ae_sqrt(a*b, _state); - a = 0.5*(a+b); - b = temp; - d = d+d; - } - temp = (ae_atan(t, _state)+md*ae_pi)/(d*a); - if( s<0 ) - { - temp = -temp; - } - result = temp+npio2*k; - return result; -} - - -/************************************************************************* -Complete elliptic integral of the second kind - -Approximates the integral - - - pi/2 - - - | | 2 -E(m) = | sqrt( 1 - m sin t ) dt - | | - - - 0 - -using the approximation - - P(x) - x log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 1 10000 2.1e-16 7.3e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegrale(double m, ae_state *_state) -{ - double p; - double q; - double result; - - - ae_assert(ae_fp_greater_eq(m,0)&&ae_fp_less_eq(m,1), "Domain error in EllipticIntegralE: m<0 or m>1", _state); - m = 1-m; - if( ae_fp_eq(m,0) ) - { - result = 1; - return result; - } - p = 1.53552577301013293365E-4; - p = p*m+2.50888492163602060990E-3; - p = p*m+8.68786816565889628429E-3; - p = p*m+1.07350949056076193403E-2; - p = p*m+7.77395492516787092951E-3; - p = p*m+7.58395289413514708519E-3; - p = p*m+1.15688436810574127319E-2; - p = p*m+2.18317996015557253103E-2; - p = p*m+5.68051945617860553470E-2; - p = p*m+4.43147180560990850618E-1; - p = p*m+1.00000000000000000299E0; - q = 3.27954898576485872656E-5; - q = q*m+1.00962792679356715133E-3; - q = q*m+6.50609489976927491433E-3; - q = q*m+1.68862163993311317300E-2; - q = q*m+2.61769742454493659583E-2; - q = q*m+3.34833904888224918614E-2; - q = q*m+4.27180926518931511717E-2; - q = q*m+5.85936634471101055642E-2; - q = q*m+9.37499997197644278445E-2; - q = q*m+2.49999999999888314361E-1; - result = p-q*m*ae_log(m, _state); - return result; -} - - -/************************************************************************* -Incomplete elliptic integral of the second kind - -Approximates the integral - - - phi - - - | | - | 2 -E(phi_\m) = | sqrt( 1 - m sin t ) dt - | - | | - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - -ACCURACY: - -Tested at random arguments with phi in [-10, 10] and m in -[0, 1]. - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 150000 3.3e-15 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegrale(double phi, double m, ae_state *_state) -{ - double pio2; - double a; - double b; - double c; - double e; - double temp; - double lphi; - double t; - double ebig; - ae_int_t d; - ae_int_t md; - ae_int_t npio2; - ae_int_t s; - double result; - - - pio2 = 1.57079632679489661923; - if( ae_fp_eq(m,0) ) - { - result = phi; - return result; - } - lphi = phi; - npio2 = ae_ifloor(lphi/pio2, _state); - if( npio2%2!=0 ) - { - npio2 = npio2+1; - } - lphi = lphi-npio2*pio2; - if( ae_fp_less(lphi,0) ) - { - lphi = -lphi; - s = -1; - } - else - { - s = 1; - } - a = 1.0-m; - ebig = ellipticintegrale(m, _state); - if( ae_fp_eq(a,0) ) - { - temp = ae_sin(lphi, _state); - if( s<0 ) - { - temp = -temp; - } - result = temp+npio2*ebig; - return result; - } - t = ae_tan(lphi, _state); - b = ae_sqrt(a, _state); - - /* - * Thanks to Brian Fitzgerald - * for pointing out an instability near odd multiples of pi/2 - */ - if( ae_fp_greater(ae_fabs(t, _state),10) ) - { - - /* - * Transform the amplitude - */ - e = 1.0/(b*t); - - /* - * ... but avoid multiple recursions. - */ - if( ae_fp_less(ae_fabs(e, _state),10) ) - { - e = ae_atan(e, _state); - temp = ebig+m*ae_sin(lphi, _state)*ae_sin(e, _state)-incompleteellipticintegrale(e, m, _state); - if( s<0 ) - { - temp = -temp; - } - result = temp+npio2*ebig; - return result; - } - } - c = ae_sqrt(m, _state); - a = 1.0; - d = 1; - e = 0.0; - md = 0; - while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) - { - temp = b/a; - lphi = lphi+ae_atan(t*temp, _state)+md*ae_pi; - md = ae_trunc((lphi+pio2)/ae_pi, _state); - t = t*(1.0+temp)/(1.0-temp*t*t); - c = 0.5*(a-b); - temp = ae_sqrt(a*b, _state); - a = 0.5*(a+b); - b = temp; - d = d+d; - e = e+c*ae_sin(lphi, _state); - } - temp = ebig/ellipticintegralk(m, _state); - temp = temp*((ae_atan(t, _state)+md*ae_pi)/(d*a)); - temp = temp+e; - if( s<0 ) - { - temp = -temp; - } - result = temp+npio2*ebig; - return result; -} - - - - -/************************************************************************* -Exponential integral Ei(x) - - x - - t - | | e - Ei(x) = -|- --- dt . - | | t - - - -inf - -Not defined for x <= 0. -See also expn.c. - - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,100 50000 8.6e-16 1.3e-16 - -Cephes Math Library Release 2.8: May, 1999 -Copyright 1999 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralei(double x, ae_state *_state) -{ - double eul; - double f; - double f1; - double f2; - double w; - double result; - - - eul = 0.5772156649015328606065; - if( ae_fp_less_eq(x,0) ) - { - result = 0; - return result; - } - if( ae_fp_less(x,2) ) - { - f1 = -5.350447357812542947283; - f1 = f1*x+218.5049168816613393830; - f1 = f1*x-4176.572384826693777058; - f1 = f1*x+55411.76756393557601232; - f1 = f1*x-331338.1331178144034309; - f1 = f1*x+1592627.163384945414220; - f2 = 1.000000000000000000000; - f2 = f2*x-52.50547959112862969197; - f2 = f2*x+1259.616186786790571525; - f2 = f2*x-17565.49581973534652631; - f2 = f2*x+149306.2117002725991967; - f2 = f2*x-729494.9239640527645655; - f2 = f2*x+1592627.163384945429726; - f = f1/f2; - result = eul+ae_log(x, _state)+x*f; - return result; - } - if( ae_fp_less(x,4) ) - { - w = 1/x; - f1 = 1.981808503259689673238E-2; - f1 = f1*w-1.271645625984917501326; - f1 = f1*w-2.088160335681228318920; - f1 = f1*w+2.755544509187936721172; - f1 = f1*w-4.409507048701600257171E-1; - f1 = f1*w+4.665623805935891391017E-2; - f1 = f1*w-1.545042679673485262580E-3; - f1 = f1*w+7.059980605299617478514E-5; - f2 = 1.000000000000000000000; - f2 = f2*w+1.476498670914921440652; - f2 = f2*w+5.629177174822436244827E-1; - f2 = f2*w+1.699017897879307263248E-1; - f2 = f2*w+2.291647179034212017463E-2; - f2 = f2*w+4.450150439728752875043E-3; - f2 = f2*w+1.727439612206521482874E-4; - f2 = f2*w+3.953167195549672482304E-5; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; - } - if( ae_fp_less(x,8) ) - { - w = 1/x; - f1 = -1.373215375871208729803; - f1 = f1*w-7.084559133740838761406E-1; - f1 = f1*w+1.580806855547941010501; - f1 = f1*w-2.601500427425622944234E-1; - f1 = f1*w+2.994674694113713763365E-2; - f1 = f1*w-1.038086040188744005513E-3; - f1 = f1*w+4.371064420753005429514E-5; - f1 = f1*w+2.141783679522602903795E-6; - f2 = 1.000000000000000000000; - f2 = f2*w+8.585231423622028380768E-1; - f2 = f2*w+4.483285822873995129957E-1; - f2 = f2*w+7.687932158124475434091E-2; - f2 = f2*w+2.449868241021887685904E-2; - f2 = f2*w+8.832165941927796567926E-4; - f2 = f2*w+4.590952299511353531215E-4; - f2 = f2*w+(-4.729848351866523044863E-6); - f2 = f2*w+2.665195537390710170105E-6; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; - } - if( ae_fp_less(x,16) ) - { - w = 1/x; - f1 = -2.106934601691916512584; - f1 = f1*w+1.732733869664688041885; - f1 = f1*w-2.423619178935841904839E-1; - f1 = f1*w+2.322724180937565842585E-2; - f1 = f1*w+2.372880440493179832059E-4; - f1 = f1*w-8.343219561192552752335E-5; - f1 = f1*w+1.363408795605250394881E-5; - f1 = f1*w-3.655412321999253963714E-7; - f1 = f1*w+1.464941733975961318456E-8; - f1 = f1*w+6.176407863710360207074E-10; - f2 = 1.000000000000000000000; - f2 = f2*w-2.298062239901678075778E-1; - f2 = f2*w+1.105077041474037862347E-1; - f2 = f2*w-1.566542966630792353556E-2; - f2 = f2*w+2.761106850817352773874E-3; - f2 = f2*w-2.089148012284048449115E-4; - f2 = f2*w+1.708528938807675304186E-5; - f2 = f2*w-4.459311796356686423199E-7; - f2 = f2*w+1.394634930353847498145E-8; - f2 = f2*w+6.150865933977338354138E-10; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; - } - if( ae_fp_less(x,32) ) - { - w = 1/x; - f1 = -2.458119367674020323359E-1; - f1 = f1*w-1.483382253322077687183E-1; - f1 = f1*w+7.248291795735551591813E-2; - f1 = f1*w-1.348315687380940523823E-2; - f1 = f1*w+1.342775069788636972294E-3; - f1 = f1*w-7.942465637159712264564E-5; - f1 = f1*w+2.644179518984235952241E-6; - f1 = f1*w-4.239473659313765177195E-8; - f2 = 1.000000000000000000000; - f2 = f2*w-1.044225908443871106315E-1; - f2 = f2*w-2.676453128101402655055E-1; - f2 = f2*w+9.695000254621984627876E-2; - f2 = f2*w-1.601745692712991078208E-2; - f2 = f2*w+1.496414899205908021882E-3; - f2 = f2*w-8.462452563778485013756E-5; - f2 = f2*w+2.728938403476726394024E-6; - f2 = f2*w-4.239462431819542051337E-8; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; - } - if( ae_fp_less(x,64) ) - { - w = 1/x; - f1 = 1.212561118105456670844E-1; - f1 = f1*w-5.823133179043894485122E-1; - f1 = f1*w+2.348887314557016779211E-1; - f1 = f1*w-3.040034318113248237280E-2; - f1 = f1*w+1.510082146865190661777E-3; - f1 = f1*w-2.523137095499571377122E-5; - f2 = 1.000000000000000000000; - f2 = f2*w-1.002252150365854016662; - f2 = f2*w+2.928709694872224144953E-1; - f2 = f2*w-3.337004338674007801307E-2; - f2 = f2*w+1.560544881127388842819E-3; - f2 = f2*w-2.523137093603234562648E-5; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; - } - w = 1/x; - f1 = -7.657847078286127362028E-1; - f1 = f1*w+6.886192415566705051750E-1; - f1 = f1*w-2.132598113545206124553E-1; - f1 = f1*w+3.346107552384193813594E-2; - f1 = f1*w-3.076541477344756050249E-3; - f1 = f1*w+1.747119316454907477380E-4; - f1 = f1*w-6.103711682274170530369E-6; - f1 = f1*w+1.218032765428652199087E-7; - f1 = f1*w-1.086076102793290233007E-9; - f2 = 1.000000000000000000000; - f2 = f2*w-1.888802868662308731041; - f2 = f2*w+1.066691687211408896850; - f2 = f2*w-2.751915982306380647738E-1; - f2 = f2*w+3.930852688233823569726E-2; - f2 = f2*w-3.414684558602365085394E-3; - f2 = f2*w+1.866844370703555398195E-4; - f2 = f2*w-6.345146083130515357861E-6; - f2 = f2*w+1.239754287483206878024E-7; - f2 = f2*w-1.086076102793126632978E-9; - f = f1/f2; - result = ae_exp(x, _state)*w*(1+w*f); - return result; -} - - -/************************************************************************* -Exponential integral En(x) - -Evaluates the exponential integral - - inf. - - - | | -xt - | e - E (x) = | ---- dt. - n | n - | | t - - - 1 - - -Both n and x must be nonnegative. - -The routine employs either a power series, a continued -fraction, or an asymptotic formula depending on the -relative values of n and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 10000 1.7e-15 3.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 2000 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralen(double x, ae_int_t n, ae_state *_state) -{ - double r; - double t; - double yk; - double xk; - double pk; - double pkm1; - double pkm2; - double qk; - double qkm1; - double qkm2; - double psi; - double z; - ae_int_t i; - ae_int_t k; - double big; - double eul; - double result; - - - eul = 0.57721566490153286060; - big = 1.44115188075855872*ae_pow(10, 17, _state); - if( ((n<0||ae_fp_less(x,0))||ae_fp_greater(x,170))||(ae_fp_eq(x,0)&&n<2) ) - { - result = -1; - return result; - } - if( ae_fp_eq(x,0) ) - { - result = (double)1/(double)(n-1); - return result; - } - if( n==0 ) - { - result = ae_exp(-x, _state)/x; - return result; - } - if( n>5000 ) - { - xk = x+n; - yk = 1/(xk*xk); - t = n; - result = yk*t*(6*x*x-8*t*x+t*t); - result = yk*(result+t*(t-2.0*x)); - result = yk*(result+t); - result = (result+1)*ae_exp(-x, _state)/xk; - return result; - } - if( ae_fp_less_eq(x,1) ) - { - psi = -eul-ae_log(x, _state); - for(i=1; i<=n-1; i++) - { - psi = psi+(double)1/(double)i; - } - z = -x; - xk = 0; - yk = 1; - pk = 1-n; - if( n==1 ) - { - result = 0.0; - } - else - { - result = 1.0/pk; - } - do - { - xk = xk+1; - yk = yk*z/xk; - pk = pk+1; - if( ae_fp_neq(pk,0) ) - { - result = result+yk/pk; - } - if( ae_fp_neq(result,0) ) - { - t = ae_fabs(yk/result, _state); - } - else - { - t = 1; - } - } - while(ae_fp_greater_eq(t,ae_machineepsilon)); - t = 1; - for(i=1; i<=n-1; i++) - { - t = t*z/i; - } - result = psi*t-result; - return result; - } - else - { - k = 1; - pkm2 = 1; - qkm2 = x; - pkm1 = 1.0; - qkm1 = x+n; - result = pkm1/qkm1; - do - { - k = k+1; - if( k%2==1 ) - { - yk = 1; - xk = n+(double)(k-1)/(double)2; - } - else - { - yk = x; - xk = (double)k/(double)2; - } - pk = pkm1*yk+pkm2*xk; - qk = qkm1*yk+qkm2*xk; - if( ae_fp_neq(qk,0) ) - { - r = pk/qk; - t = ae_fabs((result-r)/r, _state); - result = r; - } - else - { - t = 1; - } - pkm2 = pkm1; - pkm1 = pk; - qkm2 = qkm1; - qkm1 = qk; - if( ae_fp_greater(ae_fabs(pk, _state),big) ) - { - pkm2 = pkm2/big; - pkm1 = pkm1/big; - qkm2 = qkm2/big; - qkm1 = qkm1/big; - } - } - while(ae_fp_greater_eq(t,ae_machineepsilon)); - result = result*ae_exp(-x, _state); - } - return result; -} - - - - -/************************************************************************* -F distribution - -Returns the area from zero to x under the F density -function (also known as Snedcor's density or the -variance ratio density). This is the density -of x = (u1/df1)/(u2/df2), where u1 and u2 are random -variables having Chi square distributions with df1 -and df2 degrees of freedom, respectively. -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). - - -The arguments a and b are greater than zero, and x is -nonnegative. - -ACCURACY: - -Tested at random points (a,b,x). - - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 - IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 - IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 - IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) -{ - double w; - double result; - - - ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,0), "Domain error in FDistribution", _state); - w = a*x; - w = w/(b+w); - result = incompletebeta(0.5*a, 0.5*b, w, _state); - return result; -} - - -/************************************************************************* -Complemented F distribution - -Returns the area from x to infinity under the F density -function (also known as Snedcor's density or the -variance ratio density). - - - inf. - - - 1 | | a-1 b-1 -1-P(x) = ------ | t (1-t) dt - B(a,b) | | - - - x - - -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). - - -ACCURACY: - -Tested at random points (a,b,x) in the indicated intervals. - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 - IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 - IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 - IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) -{ - double w; - double result; - - - ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,0), "Domain error in FCDistribution", _state); - w = b/(b+a*x); - result = incompletebeta(0.5*b, 0.5*a, w, _state); - return result; -} - - -/************************************************************************* -Inverse of complemented F distribution - -Finds the F density argument x such that the integral -from x to infinity of the F density is equal to the -given probability p. - -This is accomplished using the inverse beta integral -function and the relations - - z = incbi( df2/2, df1/2, p ) - x = df2 (1-z) / (df1 z). - -Note: the following relations hold for the inverse of -the uncomplemented F distribution: - - z = incbi( df1/2, df2/2, p ) - x = df2 z / (df1 (1-z)). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between .001 and 1: - IEEE 1,100 100000 8.3e-15 4.7e-16 - IEEE 1,10000 100000 2.1e-11 1.4e-13 - For p between 10^-6 and 10^-3: - IEEE 1,100 50000 1.3e-12 8.4e-15 - IEEE 1,10000 50000 3.0e-12 4.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invfdistribution(ae_int_t a, - ae_int_t b, - double y, - ae_state *_state) -{ - double w; - double result; - - - ae_assert(((a>=1&&b>=1)&&ae_fp_greater(y,0))&&ae_fp_less_eq(y,1), "Domain error in InvFDistribution", _state); - - /* - * Compute probability for x = 0.5 - */ - w = incompletebeta(0.5*b, 0.5*a, 0.5, _state); - - /* - * If that is greater than y, then the solution w < .5 - * Otherwise, solve at 1-y to remove cancellation in (b - b*w) - */ - if( ae_fp_greater(w,y)||ae_fp_less(y,0.001) ) - { - w = invincompletebeta(0.5*b, 0.5*a, y, _state); - result = (b-b*w)/(a*w); - } - else - { - w = invincompletebeta(0.5*a, 0.5*b, 1.0-y, _state); - result = b*w/(a*(1.0-w)); - } - return result; -} - - - - -/************************************************************************* -Fresnel integral - -Evaluates the Fresnel integrals - - x - - - | | -C(x) = | cos(pi/2 t**2) dt, - | | - - - 0 - - x - - - | | -S(x) = | sin(pi/2 t**2) dt. - | | - - - 0 - - -The integrals are evaluated by a power series for x < 1. -For x >= 1 auxiliary functions f(x) and g(x) are employed -such that - -C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) -S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) - - - -ACCURACY: - - Relative error. - -Arithmetic function domain # trials peak rms - IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 - IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void fresnelintegral(double x, double* c, double* s, ae_state *_state) -{ - double xxa; - double f; - double g; - double cc; - double ss; - double t; - double u; - double x2; - double sn; - double sd; - double cn; - double cd; - double fn; - double fd; - double gn; - double gd; - double mpi; - double mpio2; - - - mpi = 3.14159265358979323846; - mpio2 = 1.57079632679489661923; - xxa = x; - x = ae_fabs(xxa, _state); - x2 = x*x; - if( ae_fp_less(x2,2.5625) ) - { - t = x2*x2; - sn = -2.99181919401019853726E3; - sn = sn*t+7.08840045257738576863E5; - sn = sn*t-6.29741486205862506537E7; - sn = sn*t+2.54890880573376359104E9; - sn = sn*t-4.42979518059697779103E10; - sn = sn*t+3.18016297876567817986E11; - sd = 1.00000000000000000000E0; - sd = sd*t+2.81376268889994315696E2; - sd = sd*t+4.55847810806532581675E4; - sd = sd*t+5.17343888770096400730E6; - sd = sd*t+4.19320245898111231129E8; - sd = sd*t+2.24411795645340920940E10; - sd = sd*t+6.07366389490084639049E11; - cn = -4.98843114573573548651E-8; - cn = cn*t+9.50428062829859605134E-6; - cn = cn*t-6.45191435683965050962E-4; - cn = cn*t+1.88843319396703850064E-2; - cn = cn*t-2.05525900955013891793E-1; - cn = cn*t+9.99999999999999998822E-1; - cd = 3.99982968972495980367E-12; - cd = cd*t+9.15439215774657478799E-10; - cd = cd*t+1.25001862479598821474E-7; - cd = cd*t+1.22262789024179030997E-5; - cd = cd*t+8.68029542941784300606E-4; - cd = cd*t+4.12142090722199792936E-2; - cd = cd*t+1.00000000000000000118E0; - *s = ae_sign(xxa, _state)*x*x2*sn/sd; - *c = ae_sign(xxa, _state)*x*cn/cd; - return; - } - if( ae_fp_greater(x,36974.0) ) - { - *c = ae_sign(xxa, _state)*0.5; - *s = ae_sign(xxa, _state)*0.5; - return; - } - x2 = x*x; - t = mpi*x2; - u = 1/(t*t); - t = 1/t; - fn = 4.21543555043677546506E-1; - fn = fn*u+1.43407919780758885261E-1; - fn = fn*u+1.15220955073585758835E-2; - fn = fn*u+3.45017939782574027900E-4; - fn = fn*u+4.63613749287867322088E-6; - fn = fn*u+3.05568983790257605827E-8; - fn = fn*u+1.02304514164907233465E-10; - fn = fn*u+1.72010743268161828879E-13; - fn = fn*u+1.34283276233062758925E-16; - fn = fn*u+3.76329711269987889006E-20; - fd = 1.00000000000000000000E0; - fd = fd*u+7.51586398353378947175E-1; - fd = fd*u+1.16888925859191382142E-1; - fd = fd*u+6.44051526508858611005E-3; - fd = fd*u+1.55934409164153020873E-4; - fd = fd*u+1.84627567348930545870E-6; - fd = fd*u+1.12699224763999035261E-8; - fd = fd*u+3.60140029589371370404E-11; - fd = fd*u+5.88754533621578410010E-14; - fd = fd*u+4.52001434074129701496E-17; - fd = fd*u+1.25443237090011264384E-20; - gn = 5.04442073643383265887E-1; - gn = gn*u+1.97102833525523411709E-1; - gn = gn*u+1.87648584092575249293E-2; - gn = gn*u+6.84079380915393090172E-4; - gn = gn*u+1.15138826111884280931E-5; - gn = gn*u+9.82852443688422223854E-8; - gn = gn*u+4.45344415861750144738E-10; - gn = gn*u+1.08268041139020870318E-12; - gn = gn*u+1.37555460633261799868E-15; - gn = gn*u+8.36354435630677421531E-19; - gn = gn*u+1.86958710162783235106E-22; - gd = 1.00000000000000000000E0; - gd = gd*u+1.47495759925128324529E0; - gd = gd*u+3.37748989120019970451E-1; - gd = gd*u+2.53603741420338795122E-2; - gd = gd*u+8.14679107184306179049E-4; - gd = gd*u+1.27545075667729118702E-5; - gd = gd*u+1.04314589657571990585E-7; - gd = gd*u+4.60680728146520428211E-10; - gd = gd*u+1.10273215066240270757E-12; - gd = gd*u+1.38796531259578871258E-15; - gd = gd*u+8.39158816283118707363E-19; - gd = gd*u+1.86958710162783236342E-22; - f = 1-u*fn/fd; - g = t*gn/gd; - t = mpio2*x2; - cc = ae_cos(t, _state); - ss = ae_sin(t, _state); - t = mpi*x; - *c = 0.5+(f*ss-g*cc)/t; - *s = 0.5-(f*cc+g*ss)/t; - *c = *c*ae_sign(xxa, _state); - *s = *s*ae_sign(xxa, _state); -} - - - - -/************************************************************************* -Calculation of the value of the Hermite polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial Hn at x -*************************************************************************/ -double hermitecalculate(ae_int_t n, double x, ae_state *_state) -{ - ae_int_t i; - double a; - double b; - double result; - - - result = 0; - - /* - * Prepare A and B - */ - a = 1; - b = 2*x; - - /* - * Special cases: N=0 or N=1 - */ - if( n==0 ) - { - result = a; - return result; - } - if( n==1 ) - { - result = b; - return result; - } - - /* - * General case: N>=2 - */ - for(i=2; i<=n; i++) - { - result = 2*x*b-2*(i-1)*a; - a = b; - b = result; - } - return result; -} - - -/************************************************************************* -Summation of Hermite polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial at x -*************************************************************************/ -double hermitesum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state) -{ - double b1; - double b2; - ae_int_t i; - double result; - - - b1 = 0; - b2 = 0; - result = 0; - for(i=n; i>=0; i--) - { - result = 2*(x*b1-(i+1)*b2)+c->ptr.p_double[i]; - b2 = b1; - b1 = result; - } - return result; -} - - -/************************************************************************* -Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void hermitecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(c); - - ae_vector_set_length(c, n+1, _state); - for(i=0; i<=n; i++) - { - c->ptr.p_double[i] = 0; - } - c->ptr.p_double[n] = ae_exp(n*ae_log(2, _state), _state); - for(i=0; i<=n/2-1; i++) - { - c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/4/(i+1); - } -} - - - - -/************************************************************************* -Jacobian Elliptic Functions - -Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), -and dn(u|m) of parameter m between 0 and 1, and real -argument u. - -These functions are periodic, with quarter-period on the -real axis equal to the complete elliptic integral -ellpk(1.0-m). - -Relation to incomplete elliptic integral: -If u = ellik(phi,m), then sn(u|m) = sin(phi), -and cn(u|m) = cos(phi). Phi is called the amplitude of u. - -Computation is by means of the arithmetic-geometric mean -algorithm, except when m is within 1e-9 of 0 or 1. In the -latter case with m close to 1, the approximation applies -only for phi < pi/2. - -ACCURACY: - -Tested at random points with u between 0 and 10, m between -0 and 1. - - Absolute error (* = relative error): -arithmetic function # trials peak rms - IEEE phi 10000 9.2e-16* 1.4e-16* - IEEE sn 50000 4.1e-15 4.6e-16 - IEEE cn 40000 3.6e-15 4.4e-16 - IEEE dn 10000 1.3e-12 1.8e-14 - - Peak error observed in consistency check using addition -theorem for sn(u+v) was 4e-16 (absolute). Also tested by -the above relation to the incomplete elliptic integral. -Accuracy deteriorates when u is large. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void jacobianellipticfunctions(double u, - double m, - double* sn, - double* cn, - double* dn, - double* ph, - ae_state *_state) -{ - ae_frame _frame_block; - double ai; - double b; - double phi; - double t; - double twon; - ae_vector a; - ae_vector c; - ae_int_t i; - - ae_frame_make(_state, &_frame_block); - *sn = 0; - *cn = 0; - *dn = 0; - *ph = 0; - ae_vector_init(&a, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_REAL, _state, ae_true); - - ae_assert(ae_fp_greater_eq(m,0)&&ae_fp_less_eq(m,1), "Domain error in JacobianEllipticFunctions: m<0 or m>1", _state); - ae_vector_set_length(&a, 8+1, _state); - ae_vector_set_length(&c, 8+1, _state); - if( ae_fp_less(m,1.0e-9) ) - { - t = ae_sin(u, _state); - b = ae_cos(u, _state); - ai = 0.25*m*(u-t*b); - *sn = t-ai*b; - *cn = b+ai*t; - *ph = u-ai; - *dn = 1.0-0.5*m*t*t; - ae_frame_leave(_state); - return; - } - if( ae_fp_greater_eq(m,0.9999999999) ) - { - ai = 0.25*(1.0-m); - b = ae_cosh(u, _state); - t = ae_tanh(u, _state); - phi = 1.0/b; - twon = b*ae_sinh(u, _state); - *sn = t+ai*(twon-u)/(b*b); - *ph = 2.0*ae_atan(ae_exp(u, _state), _state)-1.57079632679489661923+ai*(twon-u)/b; - ai = ai*t*phi; - *cn = phi-ai*(twon-u); - *dn = phi+ai*(twon+u); - ae_frame_leave(_state); - return; - } - a.ptr.p_double[0] = 1.0; - b = ae_sqrt(1.0-m, _state); - c.ptr.p_double[0] = ae_sqrt(m, _state); - twon = 1.0; - i = 0; - while(ae_fp_greater(ae_fabs(c.ptr.p_double[i]/a.ptr.p_double[i], _state),ae_machineepsilon)) - { - if( i>7 ) - { - ae_assert(ae_false, "Overflow in JacobianEllipticFunctions", _state); - break; - } - ai = a.ptr.p_double[i]; - i = i+1; - c.ptr.p_double[i] = 0.5*(ai-b); - t = ae_sqrt(ai*b, _state); - a.ptr.p_double[i] = 0.5*(ai+b); - b = t; - twon = twon*2.0; - } - phi = twon*a.ptr.p_double[i]*u; - do - { - t = c.ptr.p_double[i]*ae_sin(phi, _state)/a.ptr.p_double[i]; - b = phi; - phi = (ae_asin(t, _state)+phi)/2.0; - i = i-1; - } - while(i!=0); - *sn = ae_sin(phi, _state); - t = ae_cos(phi, _state); - *cn = t; - *dn = t/ae_cos(phi-b, _state); - *ph = phi; - ae_frame_leave(_state); -} - - - - -/************************************************************************* -Calculation of the value of the Laguerre polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial Ln at x -*************************************************************************/ -double laguerrecalculate(ae_int_t n, double x, ae_state *_state) -{ - double a; - double b; - double i; - double result; - - - result = 1; - a = 1; - b = 1-x; - if( n==1 ) - { - result = b; - } - i = 2; - while(ae_fp_less_eq(i,n)) - { - result = ((2*i-1-x)*b-(i-1)*a)/i; - a = b; - b = result; - i = i+1; - } - return result; -} - - -/************************************************************************* -Summation of Laguerre polynomials using Clenshaw’s recurrence formula. - -This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial at x -*************************************************************************/ -double laguerresum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state) -{ - double b1; - double b2; - ae_int_t i; - double result; - - - b1 = 0; - b2 = 0; - result = 0; - for(i=n; i>=0; i--) - { - result = (2*i+1-x)*b1/(i+1)-(i+1)*b2/(i+2)+c->ptr.p_double[i]; - b2 = b1; - b1 = result; - } - return result; -} - - -/************************************************************************* -Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void laguerrecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(c); - - ae_vector_set_length(c, n+1, _state); - c->ptr.p_double[0] = 1; - for(i=0; i<=n-1; i++) - { - c->ptr.p_double[i+1] = -c->ptr.p_double[i]*(n-i)/(i+1)/(i+1); - } -} - - - - -/************************************************************************* -Calculation of the value of the Legendre polynomial Pn. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial Pn at x -*************************************************************************/ -double legendrecalculate(ae_int_t n, double x, ae_state *_state) -{ - double a; - double b; - ae_int_t i; - double result; - - - result = 1; - a = 1; - b = x; - if( n==0 ) - { - result = a; - return result; - } - if( n==1 ) - { - result = b; - return result; - } - for(i=2; i<=n; i++) - { - result = ((2*i-1)*x*b-(i-1)*a)/i; - a = b; - b = result; - } - return result; -} - - -/************************************************************************* -Summation of Legendre polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial at x -*************************************************************************/ -double legendresum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state) -{ - double b1; - double b2; - ae_int_t i; - double result; - - - b1 = 0; - b2 = 0; - result = 0; - for(i=n; i>=0; i--) - { - result = (2*i+1)*x*b1/(i+1)-(i+1)*b2/(i+2)+c->ptr.p_double[i]; - b2 = b1; - b1 = result; - } - return result; -} - - -/************************************************************************* -Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void legendrecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state) -{ - ae_int_t i; - - ae_vector_clear(c); - - ae_vector_set_length(c, n+1, _state); - for(i=0; i<=n; i++) - { - c->ptr.p_double[i] = 0; - } - c->ptr.p_double[n] = 1; - for(i=1; i<=n; i++) - { - c->ptr.p_double[n] = c->ptr.p_double[n]*(n+i)/2/i; - } - for(i=0; i<=n/2-1; i++) - { - c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(n-2*i)*(n-2*i-1)/2/(i+1)/(2*(n-i)-1); - } -} - - - - -/************************************************************************* -Poisson distribution - -Returns the sum of the first k+1 terms of the Poisson -distribution: - - k j - -- -m m - > e -- - -- j! - j=0 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the relation - -y = pdtr( k, m ) = igamc( k+1, m ). - -The arguments must both be positive. -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissondistribution(ae_int_t k, double m, ae_state *_state) -{ - double result; - - - ae_assert(k>=0&&ae_fp_greater(m,0), "Domain error in PoissonDistribution", _state); - result = incompletegammac(k+1, m, _state); - return result; -} - - -/************************************************************************* -Complemented Poisson distribution - -Returns the sum of the terms k+1 to infinity of the Poisson -distribution: - - inf. j - -- -m m - > e -- - -- j! - j=k+1 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the formula - -y = pdtrc( k, m ) = igam( k+1, m ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissoncdistribution(ae_int_t k, double m, ae_state *_state) -{ - double result; - - - ae_assert(k>=0&&ae_fp_greater(m,0), "Domain error in PoissonDistributionC", _state); - result = incompletegamma(k+1, m, _state); - return result; -} - - -/************************************************************************* -Inverse Poisson distribution - -Finds the Poisson variable x such that the integral -from 0 to x of the Poisson density is equal to the -given probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - m = igami( k+1, y ). - -ACCURACY: - -See inverse incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invpoissondistribution(ae_int_t k, double y, ae_state *_state) -{ - double result; - - - ae_assert((k>=0&&ae_fp_greater_eq(y,0))&&ae_fp_less(y,1), "Domain error in InvPoissonDistribution", _state); - result = invincompletegammac(k+1, y, _state); - return result; -} - - - - -/************************************************************************* -Psi (digamma) function - - d - - psi(x) = -- ln | (x) - dx - -is the logarithmic derivative of the gamma function. -For integer x, - n-1 - - -psi(n) = -EUL + > 1/k. - - - k=1 - -This formula is used for 0 < n <= 10. If x is negative, it -is transformed to a positive argument by the reflection -formula psi(1-x) = psi(x) + pi cot(pi x). -For general positive x, the argument is made greater than 10 -using the recurrence psi(x+1) = psi(x) + 1/x. -Then the following asymptotic expansion is applied: - - inf. B - - 2k -psi(x) = log(x) - 1/2x - > ------- - - 2k - k=1 2k x - -where the B2k are Bernoulli numbers. - -ACCURACY: - Relative error (except absolute when |psi| < 1): -arithmetic domain # trials peak rms - IEEE 0,30 30000 1.3e-15 1.4e-16 - IEEE -30,0 40000 1.5e-15 2.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double psi(double x, ae_state *_state) -{ - double p; - double q; - double nz; - double s; - double w; - double y; - double z; - double polv; - ae_int_t i; - ae_int_t n; - ae_int_t negative; - double result; - - - negative = 0; - nz = 0.0; - if( ae_fp_less_eq(x,0) ) - { - negative = 1; - q = x; - p = ae_ifloor(q, _state); - if( ae_fp_eq(p,q) ) - { - ae_assert(ae_false, "Singularity in Psi(x)", _state); - result = ae_maxrealnumber; - return result; - } - nz = q-p; - if( ae_fp_neq(nz,0.5) ) - { - if( ae_fp_greater(nz,0.5) ) - { - p = p+1.0; - nz = q-p; - } - nz = ae_pi/ae_tan(ae_pi*nz, _state); - } - else - { - nz = 0.0; - } - x = 1.0-x; - } - if( ae_fp_less_eq(x,10.0)&&ae_fp_eq(x,ae_ifloor(x, _state)) ) - { - y = 0.0; - n = ae_ifloor(x, _state); - for(i=1; i<=n-1; i++) - { - w = i; - y = y+1.0/w; - } - y = y-0.57721566490153286061; - } - else - { - s = x; - w = 0.0; - while(ae_fp_less(s,10.0)) - { - w = w+1.0/s; - s = s+1.0; - } - if( ae_fp_less(s,1.0E17) ) - { - z = 1.0/(s*s); - polv = 8.33333333333333333333E-2; - polv = polv*z-2.10927960927960927961E-2; - polv = polv*z+7.57575757575757575758E-3; - polv = polv*z-4.16666666666666666667E-3; - polv = polv*z+3.96825396825396825397E-3; - polv = polv*z-8.33333333333333333333E-3; - polv = polv*z+8.33333333333333333333E-2; - y = z*polv; - } - else - { - y = 0.0; - } - y = ae_log(s, _state)-0.5/s-y-w; - } - if( negative!=0 ) - { - y = y-nz; - } - result = y; - return result; -} - - - - -/************************************************************************* -Student's t distribution - -Computes the integral from minus infinity to t of the Student -t distribution with integer k > 0 degrees of freedom: - - t - - - | | - - | 2 -(k+1)/2 - | ( (k+1)/2 ) | ( x ) - ---------------------- | ( 1 + --- ) dx - - | ( k ) - sqrt( k pi ) | ( k/2 ) | - | | - - - -inf. - -Relation to incomplete beta integral: - - 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) -where - z = k/(k + t**2). - -For t < -2, this is the method of computation. For higher t, -a direct method is derived from integration by parts. -Since the function is symmetric about t=0, the area under the -right tail of the density is found by calling the function -with -t instead of t. - -ACCURACY: - -Tested at random 1 <= k <= 25. The "domain" refers to t. - Relative error: -arithmetic domain # trials peak rms - IEEE -100,-2 50000 5.9e-15 1.4e-15 - IEEE -2,100 500000 2.7e-15 4.9e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double studenttdistribution(ae_int_t k, double t, ae_state *_state) -{ - double x; - double rk; - double z; - double f; - double tz; - double p; - double xsqk; - ae_int_t j; - double result; - - - ae_assert(k>0, "Domain error in StudentTDistribution", _state); - if( ae_fp_eq(t,0) ) - { - result = 0.5; - return result; - } - if( ae_fp_less(t,-2.0) ) - { - rk = k; - z = rk/(rk+t*t); - result = 0.5*incompletebeta(0.5*rk, 0.5, z, _state); - return result; - } - if( ae_fp_less(t,0) ) - { - x = -t; - } - else - { - x = t; - } - rk = k; - z = 1.0+x*x/rk; - if( k%2!=0 ) - { - xsqk = x/ae_sqrt(rk, _state); - p = ae_atan(xsqk, _state); - if( k>1 ) - { - f = 1.0; - tz = 1.0; - j = 3; - while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) - { - tz = tz*((j-1)/(z*j)); - f = f+tz; - j = j+2; - } - p = p+f*xsqk/z; - } - p = p*2.0/ae_pi; - } - else - { - f = 1.0; - tz = 1.0; - j = 2; - while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) - { - tz = tz*((j-1)/(z*j)); - f = f+tz; - j = j+2; - } - p = f*x/ae_sqrt(z*rk, _state); - } - if( ae_fp_less(t,0) ) - { - p = -p; - } - result = 0.5+0.5*p; - return result; -} - - -/************************************************************************* -Functional inverse of Student's t distribution - -Given probability p, finds the argument t such that stdtr(k,t) -is equal to p. - -ACCURACY: - -Tested at random 1 <= k <= 100. The "domain" refers to p: - Relative error: -arithmetic domain # trials peak rms - IEEE .001,.999 25000 5.7e-15 8.0e-16 - IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invstudenttdistribution(ae_int_t k, double p, ae_state *_state) -{ - double t; - double rk; - double z; - ae_int_t rflg; - double result; - - - ae_assert((k>0&&ae_fp_greater(p,0))&&ae_fp_less(p,1), "Domain error in InvStudentTDistribution", _state); - rk = k; - if( ae_fp_greater(p,0.25)&&ae_fp_less(p,0.75) ) - { - if( ae_fp_eq(p,0.5) ) - { - result = 0; - return result; - } - z = 1.0-2.0*p; - z = invincompletebeta(0.5, 0.5*rk, ae_fabs(z, _state), _state); - t = ae_sqrt(rk*z/(1.0-z), _state); - if( ae_fp_less(p,0.5) ) - { - t = -t; - } - result = t; - return result; - } - rflg = -1; - if( ae_fp_greater_eq(p,0.5) ) - { - p = 1.0-p; - rflg = 1; - } - z = invincompletebeta(0.5*rk, 0.5, 2.0*p, _state); - if( ae_fp_less(ae_maxrealnumber*z,rk) ) - { - result = rflg*ae_maxrealnumber; - return result; - } - t = ae_sqrt(rk/z-rk, _state); - result = rflg*t; - return result; -} - - - - -/************************************************************************* -Sine and cosine integrals - -Evaluates the integrals - - x - - - | cos t - 1 - Ci(x) = eul + ln x + | --------- dt, - | t - - - 0 - x - - - | sin t - Si(x) = | ----- dt - | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are approximated by rational functions. -For x > 8 auxiliary functions f(x) and g(x) are employed -such that - -Ci(x) = f(x) sin(x) - g(x) cos(x) -Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) - - -ACCURACY: - Test interval = [0,50]. -Absolute error, except relative when > 1: -arithmetic function # trials peak rms - IEEE Si 30000 4.4e-16 7.3e-17 - IEEE Ci 30000 6.9e-16 5.1e-17 - -Cephes Math Library Release 2.1: January, 1989 -Copyright 1984, 1987, 1989 by Stephen L. Moshier -*************************************************************************/ -void sinecosineintegrals(double x, - double* si, - double* ci, - ae_state *_state) -{ - double z; - double c; - double s; - double f; - double g; - ae_int_t sg; - double sn; - double sd; - double cn; - double cd; - double fn; - double fd; - double gn; - double gd; - - *si = 0; - *ci = 0; - - if( ae_fp_less(x,0) ) - { - sg = -1; - x = -x; - } - else - { - sg = 0; - } - if( ae_fp_eq(x,0) ) - { - *si = 0; - *ci = -ae_maxrealnumber; - return; - } - if( ae_fp_greater(x,1.0E9) ) - { - *si = 1.570796326794896619-ae_cos(x, _state)/x; - *ci = ae_sin(x, _state)/x; - return; - } - if( ae_fp_less_eq(x,4) ) - { - z = x*x; - sn = -8.39167827910303881427E-11; - sn = sn*z+4.62591714427012837309E-8; - sn = sn*z-9.75759303843632795789E-6; - sn = sn*z+9.76945438170435310816E-4; - sn = sn*z-4.13470316229406538752E-2; - sn = sn*z+1.00000000000000000302E0; - sd = 2.03269266195951942049E-12; - sd = sd*z+1.27997891179943299903E-9; - sd = sd*z+4.41827842801218905784E-7; - sd = sd*z+9.96412122043875552487E-5; - sd = sd*z+1.42085239326149893930E-2; - sd = sd*z+9.99999999999999996984E-1; - s = x*sn/sd; - cn = 2.02524002389102268789E-11; - cn = cn*z-1.35249504915790756375E-8; - cn = cn*z+3.59325051419993077021E-6; - cn = cn*z-4.74007206873407909465E-4; - cn = cn*z+2.89159652607555242092E-2; - cn = cn*z-1.00000000000000000080E0; - cd = 4.07746040061880559506E-12; - cd = cd*z+3.06780997581887812692E-9; - cd = cd*z+1.23210355685883423679E-6; - cd = cd*z+3.17442024775032769882E-4; - cd = cd*z+5.10028056236446052392E-2; - cd = cd*z+4.00000000000000000080E0; - c = z*cn/cd; - if( sg!=0 ) - { - s = -s; - } - *si = s; - *ci = 0.57721566490153286061+ae_log(x, _state)+c; - return; - } - s = ae_sin(x, _state); - c = ae_cos(x, _state); - z = 1.0/(x*x); - if( ae_fp_less(x,8) ) - { - fn = 4.23612862892216586994E0; - fn = fn*z+5.45937717161812843388E0; - fn = fn*z+1.62083287701538329132E0; - fn = fn*z+1.67006611831323023771E-1; - fn = fn*z+6.81020132472518137426E-3; - fn = fn*z+1.08936580650328664411E-4; - fn = fn*z+5.48900223421373614008E-7; - fd = 1.00000000000000000000E0; - fd = fd*z+8.16496634205391016773E0; - fd = fd*z+7.30828822505564552187E0; - fd = fd*z+1.86792257950184183883E0; - fd = fd*z+1.78792052963149907262E-1; - fd = fd*z+7.01710668322789753610E-3; - fd = fd*z+1.10034357153915731354E-4; - fd = fd*z+5.48900252756255700982E-7; - f = fn/(x*fd); - gn = 8.71001698973114191777E-2; - gn = gn*z+6.11379109952219284151E-1; - gn = gn*z+3.97180296392337498885E-1; - gn = gn*z+7.48527737628469092119E-2; - gn = gn*z+5.38868681462177273157E-3; - gn = gn*z+1.61999794598934024525E-4; - gn = gn*z+1.97963874140963632189E-6; - gn = gn*z+7.82579040744090311069E-9; - gd = 1.00000000000000000000E0; - gd = gd*z+1.64402202413355338886E0; - gd = gd*z+6.66296701268987968381E-1; - gd = gd*z+9.88771761277688796203E-2; - gd = gd*z+6.22396345441768420760E-3; - gd = gd*z+1.73221081474177119497E-4; - gd = gd*z+2.02659182086343991969E-6; - gd = gd*z+7.82579218933534490868E-9; - g = z*gn/gd; - } - else - { - fn = 4.55880873470465315206E-1; - fn = fn*z+7.13715274100146711374E-1; - fn = fn*z+1.60300158222319456320E-1; - fn = fn*z+1.16064229408124407915E-2; - fn = fn*z+3.49556442447859055605E-4; - fn = fn*z+4.86215430826454749482E-6; - fn = fn*z+3.20092790091004902806E-8; - fn = fn*z+9.41779576128512936592E-11; - fn = fn*z+9.70507110881952024631E-14; - fd = 1.00000000000000000000E0; - fd = fd*z+9.17463611873684053703E-1; - fd = fd*z+1.78685545332074536321E-1; - fd = fd*z+1.22253594771971293032E-2; - fd = fd*z+3.58696481881851580297E-4; - fd = fd*z+4.92435064317881464393E-6; - fd = fd*z+3.21956939101046018377E-8; - fd = fd*z+9.43720590350276732376E-11; - fd = fd*z+9.70507110881952025725E-14; - f = fn/(x*fd); - gn = 6.97359953443276214934E-1; - gn = gn*z+3.30410979305632063225E-1; - gn = gn*z+3.84878767649974295920E-2; - gn = gn*z+1.71718239052347903558E-3; - gn = gn*z+3.48941165502279436777E-5; - gn = gn*z+3.47131167084116673800E-7; - gn = gn*z+1.70404452782044526189E-9; - gn = gn*z+3.85945925430276600453E-12; - gn = gn*z+3.14040098946363334640E-15; - gd = 1.00000000000000000000E0; - gd = gd*z+1.68548898811011640017E0; - gd = gd*z+4.87852258695304967486E-1; - gd = gd*z+4.67913194259625806320E-2; - gd = gd*z+1.90284426674399523638E-3; - gd = gd*z+3.68475504442561108162E-5; - gd = gd*z+3.57043223443740838771E-7; - gd = gd*z+1.72693748966316146736E-9; - gd = gd*z+3.87830166023954706752E-12; - gd = gd*z+3.14040098946363335242E-15; - g = z*gn/gd; - } - *si = 1.570796326794896619-f*c-g*s; - if( sg!=0 ) - { - *si = -*si; - } - *ci = f*s-g*c; -} - - -/************************************************************************* -Hyperbolic sine and cosine integrals - -Approximates the integrals - - x - - - | | cosh t - 1 - Chi(x) = eul + ln x + | ----------- dt, - | | t - - - 0 - - x - - - | | sinh t - Shi(x) = | ------ dt - | | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are evaluated by power series for x < 8 -and by Chebyshev expansions for x between 8 and 88. -For large x, both functions approach exp(x)/2x. -Arguments greater than 88 in magnitude return MAXNUM. - - -ACCURACY: - -Test interval 0 to 88. - Relative error: -arithmetic function # trials peak rms - IEEE Shi 30000 6.9e-16 1.6e-16 - Absolute error, except relative when |Chi| > 1: - IEEE Chi 30000 8.4e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void hyperbolicsinecosineintegrals(double x, - double* shi, - double* chi, - ae_state *_state) -{ - double k; - double z; - double c; - double s; - double a; - ae_int_t sg; - double b0; - double b1; - double b2; - - *shi = 0; - *chi = 0; - - if( ae_fp_less(x,0) ) - { - sg = -1; - x = -x; - } - else - { - sg = 0; - } - if( ae_fp_eq(x,0) ) - { - *shi = 0; - *chi = -ae_maxrealnumber; - return; - } - if( ae_fp_less(x,8.0) ) - { - z = x*x; - a = 1.0; - s = 1.0; - c = 0.0; - k = 2.0; - do - { - a = a*z/k; - c = c+a/k; - k = k+1.0; - a = a/k; - s = s+a/k; - k = k+1.0; - } - while(ae_fp_greater_eq(ae_fabs(a/s, _state),ae_machineepsilon)); - s = s*x; - } - else - { - if( ae_fp_less(x,18.0) ) - { - a = (576.0/x-52.0)/10.0; - k = ae_exp(x, _state)/x; - b0 = 1.83889230173399459482E-17; - b1 = 0.0; - trigintegrals_chebiterationshichi(a, -9.55485532279655569575E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.04326105980879882648E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.09896949074905343022E-15, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.31313534344092599234E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 5.93976226264314278932E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.47197010497749154755E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.40059764613117131000E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 9.49044626224223543299E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.61596181145435454033E-11, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.77899784436430310321E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.35455469767246947469E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.03257121792819495123E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.56699611114982536845E-8, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.44818877384267342057E-7, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 7.82018215184051295296E-7, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -5.39919118403805073710E-6, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.12458202168959833422E-5, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 8.90136741950727517826E-5, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.02558474743846862168E-3, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.96064440855633256972E-2, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.11847751047257036625E0, &b0, &b1, &b2, _state); - s = k*0.5*(b0-b2); - b0 = -8.12435385225864036372E-18; - b1 = 0.0; - trigintegrals_chebiterationshichi(a, 2.17586413290339214377E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 5.22624394924072204667E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -9.48812110591690559363E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 5.35546311647465209166E-15, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.21009970113732918701E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -6.00865178553447437951E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 7.16339649156028587775E-13, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -2.93496072607599856104E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.40359438136491256904E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 8.76302288609054966081E-11, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -4.40092476213282340617E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.87992075640569295479E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.31458150989474594064E-8, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -4.75513930924765465590E-8, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -2.21775018801848880741E-7, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.94635531373272490962E-6, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 4.33505889257316408893E-6, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -6.13387001076494349496E-5, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.13085477492997465138E-4, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 4.97164789823116062801E-4, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.64347496031374526641E-2, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.11446150876699213025E0, &b0, &b1, &b2, _state); - c = k*0.5*(b0-b2); - } - else - { - if( ae_fp_less_eq(x,88.0) ) - { - a = (6336.0/x-212.0)/70.0; - k = ae_exp(x, _state)/x; - b0 = -1.05311574154850938805E-17; - b1 = 0.0; - trigintegrals_chebiterationshichi(a, 2.62446095596355225821E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 8.82090135625368160657E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.38459811878103047136E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -8.30608026366935789136E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 3.93397875437050071776E-15, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.01765565969729044505E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -4.21128170307640802703E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.60818204519802480035E-13, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 3.34714954175994481761E-13, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.72600352129153073807E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.66894954752839083608E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.49278141024730899554E-11, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.58580661666482709598E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.79289437183355633342E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.76281629144264523277E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.69050228879421288846E-8, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.25391771228487041649E-7, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.16229947068677338732E-6, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.61038260117376323993E-5, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 3.49810375601053973070E-4, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.28478065259647610779E-2, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.03665722588798326712E0, &b0, &b1, &b2, _state); - s = k*0.5*(b0-b2); - b0 = 8.06913408255155572081E-18; - b1 = 0.0; - trigintegrals_chebiterationshichi(a, -2.08074168180148170312E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -5.98111329658272336816E-17, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.68533951085945765591E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 4.52313941698904694774E-16, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.10734917335299464535E-15, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -4.42823207332531972288E-15, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 3.49639695410806959872E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 6.63406731718911586609E-14, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.71902448093119218395E-13, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.27135418132338309016E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.74851141935315395333E-12, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.33781843985453438400E-11, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 2.71436006377612442764E-11, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -2.56600180000355990529E-10, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -1.61021375163803438552E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -4.72543064876271773512E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, -3.00095178028681682282E-9, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 7.79387474390914922337E-8, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.06942765566401507066E-6, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.59503164802313196374E-5, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 3.49592575153777996871E-4, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.28475387530065247392E-2, &b0, &b1, &b2, _state); - trigintegrals_chebiterationshichi(a, 1.03665693917934275131E0, &b0, &b1, &b2, _state); - c = k*0.5*(b0-b2); - } - else - { - if( sg!=0 ) - { - *shi = -ae_maxrealnumber; - } - else - { - *shi = ae_maxrealnumber; - } - *chi = ae_maxrealnumber; - return; - } - } - } - if( sg!=0 ) - { - s = -s; - } - *shi = s; - *chi = 0.57721566490153286061+ae_log(x, _state)+c; -} - - -static void trigintegrals_chebiterationshichi(double x, - double c, - double* b0, - double* b1, - double* b2, - ae_state *_state) -{ - - - *b2 = *b1; - *b1 = *b0; - *b0 = x*(*b1)-(*b2)+c; -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "specialfunctions.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Gamma function + +Input parameters: + X - argument + +Domain: + 0 < X < 171.6 + -170 < X < 0, X is not an integer. + +Relative error: + arithmetic domain # trials peak rms + IEEE -170,-33 20000 2.3e-15 3.3e-16 + IEEE -33, 33 20000 9.4e-16 2.2e-16 + IEEE 33, 171.6 20000 2.3e-15 3.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double gammafunction(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::gammafunction(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Natural logarithm of gamma function + +Input parameters: + X - argument + +Result: + logarithm of the absolute value of the Gamma(X). + +Output parameters: + SgnGam - sign(Gamma(X)) + +Domain: + 0 < X < 2.55e305 + -2.55e305 < X < 0, X is not an integer. + +ACCURACY: +arithmetic domain # trials peak rms + IEEE 0, 3 28000 5.4e-16 1.1e-16 + IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 +The error criterion was relative when the function magnitude +was greater than one but absolute when it was less than one. + +The following test used the relative error criterion, though +at certain points the relative error could be much higher than +indicated. + IEEE -200, -4 10000 4.8e-16 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double lngamma(const double x, double &sgngam, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::lngamma(x, &sgngam, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Error function + +The integral is + + x + - + 2 | | 2 + erf(x) = -------- | exp( - t ) dt. + sqrt(pi) | | + - + 0 + +For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise +erf(x) = 1 - erfc(x). + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 3.7e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunction(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::errorfunction(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complementary error function + + 1 - erf(x) = + + inf. + - + 2 | | 2 + erfc(x) = -------- | exp( - t ) dt + sqrt(pi) | | + - + x + + +For small x, erfc(x) = 1 - erf(x); otherwise rational +approximations are computed. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,26.6417 30000 5.7e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunctionc(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::errorfunctionc(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Same as normalcdf(), obsolete name. +*************************************************************************/ +double normaldistribution(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::normaldistribution(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Normal distribution PDF + +Returns Gaussian probability density function: + + 1 + f(x) = --------- * exp(-x^2/2) + sqrt(2pi) + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalpdf(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::normalpdf(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Normal distribution CDF + +Returns the area under the Gaussian probability density +function, integrated from minus infinity to x: + + x + - + 1 | | 2 + ndtr(x) = --------- | exp( - t /2 ) dt + sqrt(2pi) | | + - + -inf. + + = ( 1 + erf(z) ) / 2 + = erfc(z) / 2 + +where z = x/sqrt(2). Computation is via the functions +erf and erfc. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE -13,0 30000 3.4e-14 6.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalcdf(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::normalcdf(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse of the error function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double inverf(const double e, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::inverf(e, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Same as invnormalcdf(), deprecated name +*************************************************************************/ +double invnormaldistribution(const double y0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invnormaldistribution(y0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse of Normal CDF + +Returns the argument, x, for which the area under the +Gaussian probability density function (integrated from +minus infinity to x) is equal to y. + + +For small arguments 0 < y < exp(-2), the program computes +z = sqrt( -2.0 * log(y) ); then the approximation is +x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). +There are two rational functions P/Q, one for 0 < y < exp(-32) +and the other for y up to exp(-2). For larger arguments, +w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0.125, 1 20000 7.2e-16 1.3e-16 + IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double invnormalcdf(const double y0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invnormalcdf(y0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bivariate normal PDF + +Returns probability density function of the bivariate Gaussian with +correlation parameter equal to Rho: + + 1 ( x^2 - 2*rho*x*y + y^2 ) + f(x,y,rho) = ----------------- * exp( - ----------------------- ) + 2pi*sqrt(1-rho^2) ( 2*(1-rho^2) ) + + +with -1 0 degrees of freedom: + + t + - + | | + - | 2 -(k+1)/2 + | ( (k+1)/2 ) | ( x ) + ---------------------- | ( 1 + --- ) dx + - | ( k ) + sqrt( k pi ) | ( k/2 ) | + | | + - + -inf. + +Relation to incomplete beta integral: + + 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) +where + z = k/(k + t**2). + +For t < -2, this is the method of computation. For higher t, +a direct method is derived from integration by parts. +Since the function is symmetric about t=0, the area under the +right tail of the density is found by calling the function +with -t instead of t. + +ACCURACY: + +Tested at random 1 <= k <= 25. The "domain" refers to t. + Relative error: +arithmetic domain # trials peak rms + IEEE -100,-2 50000 5.9e-15 1.4e-15 + IEEE -2,100 500000 2.7e-15 4.9e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double studenttdistribution(const ae_int_t k, const double t, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::studenttdistribution(k, t, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Functional inverse of Student's t distribution + +Given probability p, finds the argument t such that stdtr(k,t) +is equal to p. + +ACCURACY: + +Tested at random 1 <= k <= 100. The "domain" refers to p: + Relative error: +arithmetic domain # trials peak rms + IEEE .001,.999 25000 5.7e-15 8.0e-16 + IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invstudenttdistribution(const ae_int_t k, const double p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invstudenttdistribution(k, p, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +F distribution + +Returns the area from zero to x under the F density +function (also known as Snedcor's density or the +variance ratio density). This is the density +of x = (u1/df1)/(u2/df2), where u1 and u2 are random +variables having Chi square distributions with df1 +and df2 degrees of freedom, respectively. +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). + + +The arguments a and b are greater than zero, and x is +nonnegative. + +ACCURACY: + +Tested at random points (a,b,x). + + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 + IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 + IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 + IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fdistribution(const ae_int_t a, const ae_int_t b, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::fdistribution(a, b, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complemented F distribution + +Returns the area from x to infinity under the F density +function (also known as Snedcor's density or the +variance ratio density). + + + inf. + - + 1 | | a-1 b-1 +1-P(x) = ------ | t (1-t) dt + B(a,b) | | + - + x + + +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). + + +ACCURACY: + +Tested at random points (a,b,x) in the indicated intervals. + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 + IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 + IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 + IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fcdistribution(const ae_int_t a, const ae_int_t b, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::fcdistribution(a, b, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse of complemented F distribution + +Finds the F density argument x such that the integral +from x to infinity of the F density is equal to the +given probability p. + +This is accomplished using the inverse beta integral +function and the relations + + z = incbi( df2/2, df1/2, p ) + x = df2 (1-z) / (df1 z). + +Note: the following relations hold for the inverse of +the uncomplemented F distribution: + + z = incbi( df1/2, df2/2, p ) + x = df2 z / (df1 (1-z)). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between .001 and 1: + IEEE 1,100 100000 8.3e-15 4.7e-16 + IEEE 1,10000 100000 2.1e-11 1.4e-13 + For p between 10^-6 and 10^-3: + IEEE 1,100 50000 1.3e-12 8.4e-15 + IEEE 1,10000 50000 3.0e-12 4.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invfdistribution(const ae_int_t a, const ae_int_t b, const double y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invfdistribution(a, b, y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Incomplete gamma integral + +The function is defined by + + x + - + 1 | | -t a-1 + igam(a,x) = ----- | e t dt. + - | | + | (a) - + 0 + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 200000 3.6e-14 2.9e-15 + IEEE 0,100 300000 9.9e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegamma(const double a, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::incompletegamma(a, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complemented incomplete gamma integral + +The function is defined by + + + igamc(a,x) = 1 - igam(a,x) + + inf. + - + 1 | | -t a-1 + = ----- | e t dt. + - | | + | (a) - + x + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + +Tested at random a, x. + a x Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 + IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegammac(const double a, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::incompletegammac(a, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse of complemented imcomplete gamma integral + +Given p, the function finds x such that + + igamc( a, x ) = p. + +Starting with the approximate value + + 3 + x = a t + + where + + t = 1 - d - ndtri(p) sqrt(d) + +and + + d = 1/9a, + +the routine performs up to 10 Newton iterations to find the +root of igamc(a,x) - p = 0. + +ACCURACY: + +Tested at random a, p in the intervals indicated. + + a p Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 + IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 + IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invincompletegammac(const double a, const double y0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invincompletegammac(a, y0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Chi-square distribution + +Returns the area under the left hand tail (from 0 to x) +of the Chi square probability density function with +v degrees of freedom. + + + x + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + 0 + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquaredistribution(const double v, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::chisquaredistribution(v, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complemented Chi-square distribution + +Returns the area under the right hand tail (from x to +infinity) of the Chi square probability density function +with v degrees of freedom: + + inf. + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + x + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquarecdistribution(const double v, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::chisquarecdistribution(v, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse of complemented Chi-square distribution + +Finds the Chi-square argument x such that the integral +from x to infinity of the Chi-square density is equal +to the given cumulative probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + x/2 = igami( df/2, y ); + +ACCURACY: + +See inverse incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double invchisquaredistribution(const double v, const double y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invchisquaredistribution(v, y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Binomial distribution + +Returns the sum of the terms 0 through k of the Binomial +probability density: + + k + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=0 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p), with p between 0 and 1. + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 4.3e-15 2.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::binomialdistribution(k, n, p, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complemented binomial distribution + +Returns the sum of the terms k+1 through n of the Binomial +probability density: + + n + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=k+1 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 6.7e-15 8.2e-16 + For p between 0 and .001: + IEEE 0,100 100000 1.5e-13 2.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::binomialcdistribution(k, n, p, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse binomial distribution + +Finds the event probability p such that the sum of the +terms 0 through k of the Binomial probability density +is equal to the given cumulative probability y. + +This is accomplished using the inverse beta integral +function and the relation + +1 - p = incbi( n-k, k+1, y ). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 2.3e-14 6.4e-16 + IEEE 0,10000 100000 6.6e-12 1.2e-13 + For p between 10^-6 and 0.001: + IEEE 0,100 100000 2.0e-12 1.3e-14 + IEEE 0,10000 100000 1.5e-12 3.2e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invbinomialdistribution(k, n, y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Exponential integral Ei(x) + + x + - t + | | e + Ei(x) = -|- --- dt . + | | t + - + -inf + +Not defined for x <= 0. +See also expn.c. + + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,100 50000 8.6e-16 1.3e-16 + +Cephes Math Library Release 2.8: May, 1999 +Copyright 1999 by Stephen L. Moshier +*************************************************************************/ +double exponentialintegralei(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::exponentialintegralei(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Exponential integral En(x) + +Evaluates the exponential integral + + inf. + - + | | -xt + | e + E (x) = | ---- dt. + n | n + | | t + - + 1 + + +Both n and x must be nonnegative. + +The routine employs either a power series, a continued +fraction, or an asymptotic formula depending on the +relative values of n and x. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 10000 1.7e-15 3.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 2000 by Stephen L. Moshier +*************************************************************************/ +double exponentialintegralen(const double x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::exponentialintegralen(x, n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Jacobian Elliptic Functions + +Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), +and dn(u|m) of parameter m between 0 and 1, and real +argument u. + +These functions are periodic, with quarter-period on the +real axis equal to the complete elliptic integral +ellpk(1.0-m). + +Relation to incomplete elliptic integral: +If u = ellik(phi,m), then sn(u|m) = sin(phi), +and cn(u|m) = cos(phi). Phi is called the amplitude of u. + +Computation is by means of the arithmetic-geometric mean +algorithm, except when m is within 1e-9 of 0 or 1. In the +latter case with m close to 1, the approximation applies +only for phi < pi/2. + +ACCURACY: + +Tested at random points with u between 0 and 10, m between +0 and 1. + + Absolute error (* = relative error): +arithmetic function # trials peak rms + IEEE phi 10000 9.2e-16* 1.4e-16* + IEEE sn 50000 4.1e-15 4.6e-16 + IEEE cn 40000 3.6e-15 4.4e-16 + IEEE dn 10000 1.3e-12 1.8e-14 + + Peak error observed in consistency check using addition +theorem for sn(u+v) was 4e-16 (absolute). Also tested by +the above relation to the incomplete elliptic integral. +Accuracy deteriorates when u is large. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::jacobianellipticfunctions(u, m, &sn, &cn, &dn, &ph, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sine and cosine integrals + +Evaluates the integrals + + x + - + | cos t - 1 + Ci(x) = eul + ln x + | --------- dt, + | t + - + 0 + x + - + | sin t + Si(x) = | ----- dt + | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are approximated by rational functions. +For x > 8 auxiliary functions f(x) and g(x) are employed +such that + +Ci(x) = f(x) sin(x) - g(x) cos(x) +Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) + + +ACCURACY: + Test interval = [0,50]. +Absolute error, except relative when > 1: +arithmetic function # trials peak rms + IEEE Si 30000 4.4e-16 7.3e-17 + IEEE Ci 30000 6.9e-16 5.1e-17 + +Cephes Math Library Release 2.1: January, 1989 +Copyright 1984, 1987, 1989 by Stephen L. Moshier +*************************************************************************/ +void sinecosineintegrals(const double x, double &si, double &ci, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sinecosineintegrals(x, &si, &ci, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Hyperbolic sine and cosine integrals + +Approximates the integrals + + x + - + | | cosh t - 1 + Chi(x) = eul + ln x + | ----------- dt, + | | t + - + 0 + + x + - + | | sinh t + Shi(x) = | ------ dt + | | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are evaluated by power series for x < 8 +and by Chebyshev expansions for x between 8 and 88. +For large x, both functions approach exp(x)/2x. +Arguments greater than 88 in magnitude return MAXNUM. + + +ACCURACY: + +Test interval 0 to 88. + Relative error: +arithmetic function # trials peak rms + IEEE Shi 30000 6.9e-16 1.6e-16 + Absolute error, except relative when |Chi| > 1: + IEEE Chi 30000 8.4e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hyperbolicsinecosineintegrals(x, &shi, &chi, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Chebyshev polynomials of the +first and second kinds. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument, -1 <= x <= 1 + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::chebyshevcalculate(r, n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Summation of Chebyshev polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) +or + c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) +depending on the R. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::chebyshevsum(c.c_ptr(), r, n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void chebyshevcoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::chebyshevcoefficients(n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Conversion of a series of Chebyshev polynomials to a power series. + +Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as +B[0] + B[1]*X + ... + B[N]*X^N. + +Input parameters: + A - Chebyshev series coefficients + N - degree, N>=0 + +Output parameters + B - power series coefficients +*************************************************************************/ +void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fromchebyshev(a.c_ptr(), n, b.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Poisson distribution + +Returns the sum of the first k+1 terms of the Poisson +distribution: + + k j + -- -m m + > e -- + -- j! + j=0 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the relation + +y = pdtr( k, m ) = igamc( k+1, m ). + +The arguments must both be positive. +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissondistribution(const ae_int_t k, const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::poissondistribution(k, m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complemented Poisson distribution + +Returns the sum of the terms k+1 to infinity of the Poisson +distribution: + + inf. j + -- -m m + > e -- + -- j! + j=k+1 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the formula + +y = pdtrc( k, m ) = igam( k+1, m ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissoncdistribution(const ae_int_t k, const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::poissoncdistribution(k, m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Inverse Poisson distribution + +Finds the Poisson variable x such that the integral +from 0 to x of the Poisson density is equal to the +given probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + m = igami( k+1, y ). + +ACCURACY: + +See inverse incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invpoissondistribution(const ae_int_t k, const double y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::invpoissondistribution(k, y, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Beta function + + + - - + | (a) | (b) +beta( a, b ) = -----------. + - + | (a+b) + +For large arguments the logarithm of the function is +evaluated using lgam(), then exponentiated. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 8.1e-14 1.1e-14 + +Cephes Math Library Release 2.0: April, 1987 +Copyright 1984, 1987 by Stephen L. Moshier +*************************************************************************/ +double beta(const double a, const double b, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::beta(a, b, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Fresnel integral + +Evaluates the Fresnel integrals + + x + - + | | +C(x) = | cos(pi/2 t**2) dt, + | | + - + 0 + + x + - + | | +S(x) = | sin(pi/2 t**2) dt. + | | + - + 0 + + +The integrals are evaluated by a power series for x < 1. +For x >= 1 auxiliary functions f(x) and g(x) are employed +such that + +C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) +S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) + + + +ACCURACY: + + Relative error. + +Arithmetic function domain # trials peak rms + IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 + IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void fresnelintegral(const double x, double &c, double &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::fresnelintegral(x, &c, &s, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Psi (digamma) function + + d - + psi(x) = -- ln | (x) + dx + +is the logarithmic derivative of the gamma function. +For integer x, + n-1 + - +psi(n) = -EUL + > 1/k. + - + k=1 + +This formula is used for 0 < n <= 10. If x is negative, it +is transformed to a positive argument by the reflection +formula psi(1-x) = psi(x) + pi cot(pi x). +For general positive x, the argument is made greater than 10 +using the recurrence psi(x+1) = psi(x) + 1/x. +Then the following asymptotic expansion is applied: + + inf. B + - 2k +psi(x) = log(x) - 1/2x - > ------- + - 2k + k=1 2k x + +where the B2k are Bernoulli numbers. + +ACCURACY: + Relative error (except absolute when |psi| < 1): +arithmetic domain # trials peak rms + IEEE 0,30 30000 1.3e-15 1.4e-16 + IEEE -30,0 40000 1.5e-15 2.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double psi(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::psi(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Airy function + +Solution of the differential equation + +y"(x) = xy. + +The function returns the two independent solutions Ai, Bi +and their first derivatives Ai'(x), Bi'(x). + +Evaluation is by power series summation for small x, +by rational minimax approximations for large x. + + + +ACCURACY: +Error criterion is absolute when function <= 1, relative +when function > 1, except * denotes relative error criterion. +For large negative x, the absolute error increases as x^1.5. +For large positive x, the relative error increases as x^1.5. + +Arithmetic domain function # trials peak rms +IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 +IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* +IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 +IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* +IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 +IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void airy(const double x, double &ai, double &aip, double &bi, double &bip, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::airy(x, &ai, &aip, &bi, &bip, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Dawson's Integral + +Approximates the integral + + x + - + 2 | | 2 + dawsn(x) = exp( -x ) | exp( t ) dt + | | + - + 0 + +Three different rational approximations are employed, for +the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,10 10000 6.9e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double dawsonintegral(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::dawsonintegral(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Hermite polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial Hn at x +*************************************************************************/ +double hermitecalculate(const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hermitecalculate(n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Summation of Hermite polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial at x +*************************************************************************/ +double hermitesum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::hermitesum(c.c_ptr(), n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void hermitecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::hermitecoefficients(n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Legendre polynomial Pn. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial Pn at x +*************************************************************************/ +double legendrecalculate(const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::legendrecalculate(n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Summation of Legendre polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial at x +*************************************************************************/ +double legendresum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::legendresum(c.c_ptr(), n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void legendrecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::legendrecoefficients(n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Bessel function of order zero + +Returns Bessel function of order zero of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval the following rational +approximation is used: + + + 2 2 +(w - r ) (w - r ) P (w) / Q (w) + 1 2 3 8 + + 2 +where w = x and the two r's are zeros of the function. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 60000 4.2e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj0(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselj0(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bessel function of order one + +Returns Bessel function of order one of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 24 term Chebyshev +expansion is used. In the second, the asymptotic +trigonometric representation is employed using two +rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 2.6e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj1(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselj1(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bessel function of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The ratio of jn(x) to j0(x) is computed by backward +recurrence. First the ratio jn/jn-1 is found by a +continued fraction expansion. Then the recurrence +relating successive orders is applied until j0 or j1 is +reached. + +If n = 0 or 1 the routine for j0 or j1 is called +directly. + +ACCURACY: + + Absolute error: +arithmetic range # trials peak rms + IEEE 0, 30 5000 4.4e-16 7.9e-17 + + +Not suitable for large n or x. Use jv() (fractional order) instead. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseljn(const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besseljn(n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bessel function of the second kind, order zero + +Returns Bessel function of the second kind, of order +zero, of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval a rational approximation +R(x) is employed to compute + y0(x) = R(x) + 2 * log(x) * j0(x) / PI. +Thus a call to j0() is required. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + + + +ACCURACY: + + Absolute error, when y0(x) < 1; else relative error: + +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.3e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely0(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::bessely0(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bessel function of second kind of order one + +Returns Bessel function of the second kind of order one +of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 25 term Chebyshev +expansion is used, and a call to j1() is required. +In the second, the asymptotic trigonometric representation +is employed using two rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.0e-15 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely1(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::bessely1(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Bessel function of second kind of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The function is evaluated by forward recurrence on +n, starting with values computed by the routines +y0() and y1(). + +If n = 0 or 1 the routine for y0 or y1 is called +directly. + +ACCURACY: + Absolute error, except relative + when y > 1: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 3.4e-15 4.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselyn(const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselyn(n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Modified Bessel function of order zero + +Returns modified Bessel function of order zero of the +argument. + +The function is defined as i0(x) = j0( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 5.8e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli0(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besseli0(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Modified Bessel function of order one + +Returns modified Bessel function of order one of the +argument. + +The function is defined as i1(x) = -i j1( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.9e-15 2.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli1(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besseli1(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Modified Bessel function, second kind, order zero + +Returns modified Bessel function of the second kind +of order zero of the argument. + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + +Tested at 2000 random points between 0 and 8. Peak absolute +error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk0(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselk0(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Modified Bessel function, second kind, order one + +Computes the modified Bessel function of the second kind +of order one of the argument. + +The range is partitioned into the two intervals [0,2] and +(2, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk1(const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselk1(x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Modified Bessel function, second kind, integer order + +Returns modified Bessel function of the second kind +of order n of the argument. + +The range is partitioned into the two intervals [0,9.55] and +(9.55, infinity). An ascending power series is used in the +low range, and an asymptotic expansion in the high range. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 90000 1.8e-8 3.0e-10 + +Error is high only near the crossover point x = 9.55 +between the two expansions used. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselkn(const ae_int_t nn, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::besselkn(nn, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Laguerre polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial Ln at x +*************************************************************************/ +double laguerrecalculate(const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::laguerrecalculate(n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Summation of Laguerre polynomials using Clenshaw's recurrence formula. + +This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial at x +*************************************************************************/ +double laguerresum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::laguerresum(c.c_ptr(), n, x, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void laguerrecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::laguerrecoefficients(n, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +using the approximation + + P(x) - log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralk(const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::ellipticintegralk(m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +where m = 1 - m1, using the approximation + + P(x) - log x Q(x). + +The argument m1 is used rather than m so that the logarithmic +singularity at m = 1 will be shifted to the origin; this +preserves maximum accuracy. + +K(0) = pi/2. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralkhighprecision(const double m1, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::ellipticintegralkhighprecision(m1, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Incomplete elliptic integral of the first kind F(phi|m) + +Approximates the integral + + + + phi + - + | | + | dt +F(phi_\m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + + + + +ACCURACY: + +Tested at random points with m in [0, 1] and phi as indicated. + + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 200000 7.4e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegralk(const double phi, const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::incompleteellipticintegralk(phi, m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Complete elliptic integral of the second kind + +Approximates the integral + + + pi/2 + - + | | 2 +E(m) = | sqrt( 1 - m sin t ) dt + | | + - + 0 + +using the approximation + + P(x) - x log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 1 10000 2.1e-16 7.3e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegrale(const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::ellipticintegrale(m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Incomplete elliptic integral of the second kind + +Approximates the integral + + + phi + - + | | + | 2 +E(phi_\m) = | sqrt( 1 - m sin t ) dt + | + | | + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + +ACCURACY: + +Tested at random arguments with phi in [-10, 10] and m in +[0, 1]. + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 150000 3.3e-15 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegrale(const double phi, const double m, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::incompleteellipticintegrale(phi, m, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) +static double gammafunc_gammastirf(double x, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) +static double normaldistr_bvnintegrate3(double rangea, + double rangeb, + double x, + double y, + double gw, + double gx, + ae_state *_state); +static double normaldistr_bvnintegrate6(double rangea, + double rangeb, + double x, + double y, + double s, + double gw, + double gx, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_IBETAF) || !defined(AE_PARTIAL_BUILD) +static double ibetaf_incompletebetafe(double a, + double b, + double x, + double big, + double biginv, + ae_state *_state); +static double ibetaf_incompletebetafe2(double a, + double b, + double x, + double big, + double biginv, + ae_state *_state); +static double ibetaf_incompletebetaps(double a, + double b, + double x, + double maxgam, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_STUDENTTDISTR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) +static void trigintegrals_chebiterationshichi(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) +static void bessel_besselmfirstcheb(double c, + double* b0, + double* b1, + double* b2, + ae_state *_state); +static void bessel_besselmnextcheb(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state); +static void bessel_besselm1firstcheb(double c, + double* b0, + double* b1, + double* b2, + ae_state *_state); +static void bessel_besselm1nextcheb(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state); +static void bessel_besselasympt0(double x, + double* pzero, + double* qzero, + ae_state *_state); +static void bessel_besselasympt1(double x, + double* pzero, + double* qzero, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) + + +#endif + +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Gamma function + +Input parameters: + X - argument + +Domain: + 0 < X < 171.6 + -170 < X < 0, X is not an integer. + +Relative error: + arithmetic domain # trials peak rms + IEEE -170,-33 20000 2.3e-15 3.3e-16 + IEEE -33, 33 20000 9.4e-16 2.2e-16 + IEEE 33, 171.6 20000 2.3e-15 3.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double gammafunction(double x, ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SPECFUNCS + double p; + double pp; + double q; + double qq; + double z; + ae_int_t i; + double sgngam; + double result; + + + sgngam = (double)(1); + q = ae_fabs(x, _state); + if( ae_fp_greater(q,33.0) ) + { + if( ae_fp_less(x,0.0) ) + { + p = (double)(ae_ifloor(q, _state)); + i = ae_round(p, _state); + if( i%2==0 ) + { + sgngam = (double)(-1); + } + z = q-p; + if( ae_fp_greater(z,0.5) ) + { + p = p+(double)1; + z = q-p; + } + z = q*ae_sin(ae_pi*z, _state); + z = ae_fabs(z, _state); + z = ae_pi/(z*gammafunc_gammastirf(q, _state)); + } + else + { + z = gammafunc_gammastirf(x, _state); + } + result = sgngam*z; + return result; + } + z = (double)(1); + while(ae_fp_greater_eq(x,(double)(3))) + { + x = x-(double)1; + z = z*x; + } + while(ae_fp_less(x,(double)(0))) + { + if( ae_fp_greater(x,-0.000000001) ) + { + result = z/(((double)1+0.5772156649015329*x)*x); + return result; + } + z = z/x; + x = x+(double)1; + } + while(ae_fp_less(x,(double)(2))) + { + if( ae_fp_less(x,0.000000001) ) + { + result = z/(((double)1+0.5772156649015329*x)*x); + return result; + } + z = z/x; + x = x+1.0; + } + if( ae_fp_eq(x,(double)(2)) ) + { + result = z; + return result; + } + x = x-2.0; + pp = 1.60119522476751861407E-4; + pp = 1.19135147006586384913E-3+x*pp; + pp = 1.04213797561761569935E-2+x*pp; + pp = 4.76367800457137231464E-2+x*pp; + pp = 2.07448227648435975150E-1+x*pp; + pp = 4.94214826801497100753E-1+x*pp; + pp = 9.99999999999999996796E-1+x*pp; + qq = -2.31581873324120129819E-5; + qq = 5.39605580493303397842E-4+x*qq; + qq = -4.45641913851797240494E-3+x*qq; + qq = 1.18139785222060435552E-2+x*qq; + qq = 3.58236398605498653373E-2+x*qq; + qq = -2.34591795718243348568E-1+x*qq; + qq = 7.14304917030273074085E-2+x*qq; + qq = 1.00000000000000000320+x*qq; + result = z*pp/qq; + return result; +#else + return _ialglib_i_gammafunction(x); +#endif +} + + +/************************************************************************* +Natural logarithm of gamma function + +Input parameters: + X - argument + +Result: + logarithm of the absolute value of the Gamma(X). + +Output parameters: + SgnGam - sign(Gamma(X)) + +Domain: + 0 < X < 2.55e305 + -2.55e305 < X < 0, X is not an integer. + +ACCURACY: +arithmetic domain # trials peak rms + IEEE 0, 3 28000 5.4e-16 1.1e-16 + IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 +The error criterion was relative when the function magnitude +was greater than one but absolute when it was less than one. + +The following test used the relative error criterion, though +at certain points the relative error could be much higher than +indicated. + IEEE -200, -4 10000 4.8e-16 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double lngamma(double x, double* sgngam, ae_state *_state) +{ +#ifndef ALGLIB_INTERCEPTS_SPECFUNCS + double a; + double b; + double c; + double p; + double q; + double u; + double w; + double z; + ae_int_t i; + double logpi; + double ls2pi; + double tmp; + double result; + + *sgngam = 0.0; + + *sgngam = (double)(1); + logpi = 1.14472988584940017414; + ls2pi = 0.91893853320467274178; + if( ae_fp_less(x,-34.0) ) + { + q = -x; + w = lngamma(q, &tmp, _state); + p = (double)(ae_ifloor(q, _state)); + i = ae_round(p, _state); + if( i%2==0 ) + { + *sgngam = (double)(-1); + } + else + { + *sgngam = (double)(1); + } + z = q-p; + if( ae_fp_greater(z,0.5) ) + { + p = p+(double)1; + z = p-q; + } + z = q*ae_sin(ae_pi*z, _state); + result = logpi-ae_log(z, _state)-w; + return result; + } + if( ae_fp_less(x,(double)(13)) ) + { + z = (double)(1); + p = (double)(0); + u = x; + while(ae_fp_greater_eq(u,(double)(3))) + { + p = p-(double)1; + u = x+p; + z = z*u; + } + while(ae_fp_less(u,(double)(2))) + { + z = z/u; + p = p+(double)1; + u = x+p; + } + if( ae_fp_less(z,(double)(0)) ) + { + *sgngam = (double)(-1); + z = -z; + } + else + { + *sgngam = (double)(1); + } + if( ae_fp_eq(u,(double)(2)) ) + { + result = ae_log(z, _state); + return result; + } + p = p-(double)2; + x = x+p; + b = -1378.25152569120859100; + b = -38801.6315134637840924+x*b; + b = -331612.992738871184744+x*b; + b = -1162370.97492762307383+x*b; + b = -1721737.00820839662146+x*b; + b = -853555.664245765465627+x*b; + c = (double)(1); + c = -351.815701436523470549+x*c; + c = -17064.2106651881159223+x*c; + c = -220528.590553854454839+x*c; + c = -1139334.44367982507207+x*c; + c = -2532523.07177582951285+x*c; + c = -2018891.41433532773231+x*c; + p = x*b/c; + result = ae_log(z, _state)+p; + return result; + } + q = (x-0.5)*ae_log(x, _state)-x+ls2pi; + if( ae_fp_greater(x,(double)(100000000)) ) + { + result = q; + return result; + } + p = (double)1/(x*x); + if( ae_fp_greater_eq(x,1000.0) ) + { + q = q+((7.9365079365079365079365*0.0001*p-2.7777777777777777777778*0.001)*p+0.0833333333333333333333)/x; + } + else + { + a = 8.11614167470508450300*0.0001; + a = -5.95061904284301438324*0.0001+p*a; + a = 7.93650340457716943945*0.0001+p*a; + a = -2.77777777730099687205*0.001+p*a; + a = 8.33333333333331927722*0.01+p*a; + q = q+a/x; + } + result = q; + return result; +#else + return _ialglib_i_lngamma(x, sgngam); +#endif +} + + +static double gammafunc_gammastirf(double x, ae_state *_state) +{ + double y; + double w; + double v; + double stir; + double result; + + + w = (double)1/x; + stir = 7.87311395793093628397E-4; + stir = -2.29549961613378126380E-4+w*stir; + stir = -2.68132617805781232825E-3+w*stir; + stir = 3.47222221605458667310E-3+w*stir; + stir = 8.33333333333482257126E-2+w*stir; + w = (double)1+w*stir; + y = ae_exp(x, _state); + if( ae_fp_greater(x,143.01608) ) + { + v = ae_pow(x, 0.5*x-0.25, _state); + y = v*(v/y); + } + else + { + y = ae_pow(x, x-0.5, _state)/y; + } + result = 2.50662827463100050242*y*w; + return result; +} + + +#endif +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Error function + +The integral is + + x + - + 2 | | 2 + erf(x) = -------- | exp( - t ) dt. + sqrt(pi) | | + - + 0 + +For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise +erf(x) = 1 - erfc(x). + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 3.7e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunction(double x, ae_state *_state) +{ + double xsq; + double s; + double p; + double q; + double result; + + + s = (double)(ae_sign(x, _state)); + x = ae_fabs(x, _state); + if( ae_fp_less(x,0.5) ) + { + xsq = x*x; + p = 0.007547728033418631287834; + p = -0.288805137207594084924010+xsq*p; + p = 14.3383842191748205576712+xsq*p; + p = 38.0140318123903008244444+xsq*p; + p = 3017.82788536507577809226+xsq*p; + p = 7404.07142710151470082064+xsq*p; + p = 80437.3630960840172832162+xsq*p; + q = 0.0; + q = 1.00000000000000000000000+xsq*q; + q = 38.0190713951939403753468+xsq*q; + q = 658.070155459240506326937+xsq*q; + q = 6379.60017324428279487120+xsq*q; + q = 34216.5257924628539769006+xsq*q; + q = 80437.3630960840172826266+xsq*q; + result = s*1.1283791670955125738961589031*x*p/q; + return result; + } + if( ae_fp_greater_eq(x,(double)(10)) ) + { + result = s; + return result; + } + result = s*((double)1-errorfunctionc(x, _state)); + return result; +} + + +/************************************************************************* +Complementary error function + + 1 - erf(x) = + + inf. + - + 2 | | 2 + erfc(x) = -------- | exp( - t ) dt + sqrt(pi) | | + - + x + + +For small x, erfc(x) = 1 - erf(x); otherwise rational +approximations are computed. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,26.6417 30000 5.7e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunctionc(double x, ae_state *_state) +{ + double p; + double q; + double result; + + + if( ae_fp_less(x,(double)(0)) ) + { + result = (double)2-errorfunctionc(-x, _state); + return result; + } + if( ae_fp_less(x,0.5) ) + { + result = 1.0-errorfunction(x, _state); + return result; + } + if( ae_fp_greater_eq(x,(double)(10)) ) + { + result = (double)(0); + return result; + } + p = 0.0; + p = 0.5641877825507397413087057563+x*p; + p = 9.675807882987265400604202961+x*p; + p = 77.08161730368428609781633646+x*p; + p = 368.5196154710010637133875746+x*p; + p = 1143.262070703886173606073338+x*p; + p = 2320.439590251635247384768711+x*p; + p = 2898.0293292167655611275846+x*p; + p = 1826.3348842295112592168999+x*p; + q = 1.0; + q = 17.14980943627607849376131193+x*q; + q = 137.1255960500622202878443578+x*q; + q = 661.7361207107653469211984771+x*q; + q = 2094.384367789539593790281779+x*q; + q = 4429.612803883682726711528526+x*q; + q = 6089.5424232724435504633068+x*q; + q = 4958.82756472114071495438422+x*q; + q = 1826.3348842295112595576438+x*q; + result = ae_exp(-ae_sqr(x, _state), _state)*p/q; + return result; +} + + +/************************************************************************* +Same as normalcdf(), obsolete name. +*************************************************************************/ +double normaldistribution(double x, ae_state *_state) +{ + double result; + + + result = 0.5*(errorfunction(x/1.41421356237309504880, _state)+(double)1); + return result; +} + + +/************************************************************************* +Normal distribution PDF + +Returns Gaussian probability density function: + + 1 + f(x) = --------- * exp(-x^2/2) + sqrt(2pi) + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalpdf(double x, ae_state *_state) +{ + double result; + + + ae_assert(ae_isfinite(x, _state), "NormalPDF: X is infinite", _state); + result = ae_exp(-x*x/(double)2, _state)/ae_sqrt((double)2*ae_pi, _state); + return result; +} + + +/************************************************************************* +Normal distribution CDF + +Returns the area under the Gaussian probability density +function, integrated from minus infinity to x: + + x + - + 1 | | 2 + ndtr(x) = --------- | exp( - t /2 ) dt + sqrt(2pi) | | + - + -inf. + + = ( 1 + erf(z) ) / 2 + = erfc(z) / 2 + +where z = x/sqrt(2). Computation is via the functions +erf and erfc. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE -13,0 30000 3.4e-14 6.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalcdf(double x, ae_state *_state) +{ + double result; + + + result = 0.5*(errorfunction(x/1.41421356237309504880, _state)+(double)1); + return result; +} + + +/************************************************************************* +Inverse of the error function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double inverf(double e, ae_state *_state) +{ + double result; + + + result = invnormaldistribution(0.5*(e+(double)1), _state)/ae_sqrt((double)(2), _state); + return result; +} + + +/************************************************************************* +Same as invnormalcdf(), deprecated name +*************************************************************************/ +double invnormaldistribution(double y0, ae_state *_state) +{ + double result; + + + result = invnormalcdf(y0, _state); + return result; +} + + +/************************************************************************* +Inverse of Normal CDF + +Returns the argument, x, for which the area under the +Gaussian probability density function (integrated from +minus infinity to x) is equal to y. + + +For small arguments 0 < y < exp(-2), the program computes +z = sqrt( -2.0 * log(y) ); then the approximation is +x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). +There are two rational functions P/Q, one for 0 < y < exp(-32) +and the other for y up to exp(-2). For larger arguments, +w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0.125, 1 20000 7.2e-16 1.3e-16 + IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double invnormalcdf(double y0, ae_state *_state) +{ + double expm2; + double s2pi; + double x; + double y; + double z; + double y2; + double x0; + double x1; + ae_int_t code; + double p0; + double q0; + double p1; + double q1; + double p2; + double q2; + double result; + + + expm2 = 0.13533528323661269189; + s2pi = 2.50662827463100050242; + if( ae_fp_less_eq(y0,(double)(0)) ) + { + result = -ae_maxrealnumber; + return result; + } + if( ae_fp_greater_eq(y0,(double)(1)) ) + { + result = ae_maxrealnumber; + return result; + } + code = 1; + y = y0; + if( ae_fp_greater(y,1.0-expm2) ) + { + y = 1.0-y; + code = 0; + } + if( ae_fp_greater(y,expm2) ) + { + y = y-0.5; + y2 = y*y; + p0 = -59.9633501014107895267; + p0 = 98.0010754185999661536+y2*p0; + p0 = -56.6762857469070293439+y2*p0; + p0 = 13.9312609387279679503+y2*p0; + p0 = -1.23916583867381258016+y2*p0; + q0 = (double)(1); + q0 = 1.95448858338141759834+y2*q0; + q0 = 4.67627912898881538453+y2*q0; + q0 = 86.3602421390890590575+y2*q0; + q0 = -225.462687854119370527+y2*q0; + q0 = 200.260212380060660359+y2*q0; + q0 = -82.0372256168333339912+y2*q0; + q0 = 15.9056225126211695515+y2*q0; + q0 = -1.18331621121330003142+y2*q0; + x = y+y*y2*p0/q0; + x = x*s2pi; + result = x; + return result; + } + x = ae_sqrt(-2.0*ae_log(y, _state), _state); + x0 = x-ae_log(x, _state)/x; + z = 1.0/x; + if( ae_fp_less(x,8.0) ) + { + p1 = 4.05544892305962419923; + p1 = 31.5251094599893866154+z*p1; + p1 = 57.1628192246421288162+z*p1; + p1 = 44.0805073893200834700+z*p1; + p1 = 14.6849561928858024014+z*p1; + p1 = 2.18663306850790267539+z*p1; + p1 = -1.40256079171354495875*0.1+z*p1; + p1 = -3.50424626827848203418*0.01+z*p1; + p1 = -8.57456785154685413611*0.0001+z*p1; + q1 = (double)(1); + q1 = 15.7799883256466749731+z*q1; + q1 = 45.3907635128879210584+z*q1; + q1 = 41.3172038254672030440+z*q1; + q1 = 15.0425385692907503408+z*q1; + q1 = 2.50464946208309415979+z*q1; + q1 = -1.42182922854787788574*0.1+z*q1; + q1 = -3.80806407691578277194*0.01+z*q1; + q1 = -9.33259480895457427372*0.0001+z*q1; + x1 = z*p1/q1; + } + else + { + p2 = 3.23774891776946035970; + p2 = 6.91522889068984211695+z*p2; + p2 = 3.93881025292474443415+z*p2; + p2 = 1.33303460815807542389+z*p2; + p2 = 2.01485389549179081538*0.1+z*p2; + p2 = 1.23716634817820021358*0.01+z*p2; + p2 = 3.01581553508235416007*0.0001+z*p2; + p2 = 2.65806974686737550832*0.000001+z*p2; + p2 = 6.23974539184983293730*0.000000001+z*p2; + q2 = (double)(1); + q2 = 6.02427039364742014255+z*q2; + q2 = 3.67983563856160859403+z*q2; + q2 = 1.37702099489081330271+z*q2; + q2 = 2.16236993594496635890*0.1+z*q2; + q2 = 1.34204006088543189037*0.01+z*q2; + q2 = 3.28014464682127739104*0.0001+z*q2; + q2 = 2.89247864745380683936*0.000001+z*q2; + q2 = 6.79019408009981274425*0.000000001+z*q2; + x1 = z*p2/q2; + } + x = x0-x1; + if( code!=0 ) + { + x = -x; + } + result = x; + return result; +} + + +/************************************************************************* +Bivariate normal PDF + +Returns probability density function of the bivariate Gaussian with +correlation parameter equal to Rho: + + 1 ( x^2 - 2*rho*x*y + y^2 ) + f(x,y,rho) = ----------------- * exp( - ----------------------- ) + 2pi*sqrt(1-rho^2) ( 2*(1-rho^2) ) + + +with -13 ) + { + di = 1.0-(1.0-di)*(1.0-di); + } + else + { + if( dir>1 ) + { + di = 0.5*di+0.5; + } + else + { + di = (y0-yyy)/(yh-yl); + } + } + } + dir = dir+1; + if( ae_fp_greater(x0,0.75) ) + { + if( rflg==1 ) + { + rflg = 0; + aaa = a; + bbb = b; + y0 = y; + } + else + { + rflg = 1; + aaa = b; + bbb = a; + y0 = 1.0-y; + } + x = 1.0-x; + yyy = incompletebeta(aaa, bbb, x, _state); + x0 = 0.0; + yl = 0.0; + x1 = 1.0; + yh = 1.0; + mainlooppos = ihalve; + continue; + } + } + else + { + x1 = x; + if( rflg==1&&ae_fp_less(x1,ae_machineepsilon) ) + { + x = 0.0; + break; + } + yh = yyy; + if( dir>0 ) + { + dir = 0; + di = 0.5; + } + else + { + if( dir<-3 ) + { + di = di*di; + } + else + { + if( dir<-1 ) + { + di = 0.5*di; + } + else + { + di = (yyy-y0)/(yh-yl); + } + } + } + dir = dir-1; + } + i = i+1; + mainlooppos = ihalvecycle; + continue; + } + else + { + mainlooppos = breakihalvecycle; + continue; + } + } + + /* + * breakihalvecycle + */ + if( mainlooppos==breakihalvecycle ) + { + if( ae_fp_greater_eq(x0,1.0) ) + { + x = 1.0-ae_machineepsilon; + break; + } + if( ae_fp_less_eq(x,0.0) ) + { + x = 0.0; + break; + } + mainlooppos = newt; + continue; + } + + /* + * newt + */ + if( mainlooppos==newt ) + { + if( nflg!=0 ) + { + break; + } + nflg = 1; + lgm = lngamma(aaa+bbb, &s, _state)-lngamma(aaa, &s, _state)-lngamma(bbb, &s, _state); + i = 0; + mainlooppos = newtcycle; + continue; + } + + /* + * newtcycle + */ + if( mainlooppos==newtcycle ) + { + if( i<=7 ) + { + if( i!=0 ) + { + yyy = incompletebeta(aaa, bbb, x, _state); + } + if( ae_fp_less(yyy,yl) ) + { + x = x0; + yyy = yl; + } + else + { + if( ae_fp_greater(yyy,yh) ) + { + x = x1; + yyy = yh; + } + else + { + if( ae_fp_less(yyy,y0) ) + { + x0 = x; + yl = yyy; + } + else + { + x1 = x; + yh = yyy; + } + } + } + if( ae_fp_eq(x,1.0)||ae_fp_eq(x,0.0) ) + { + mainlooppos = breaknewtcycle; + continue; + } + d = (aaa-1.0)*ae_log(x, _state)+(bbb-1.0)*ae_log(1.0-x, _state)+lgm; + if( ae_fp_less(d,ae_log(ae_minrealnumber, _state)) ) + { + break; + } + if( ae_fp_greater(d,ae_log(ae_maxrealnumber, _state)) ) + { + mainlooppos = breaknewtcycle; + continue; + } + d = ae_exp(d, _state); + d = (yyy-y0)/d; + xt = x-d; + if( ae_fp_less_eq(xt,x0) ) + { + yyy = (x-x0)/(x1-x0); + xt = x0+0.5*yyy*(x-x0); + if( ae_fp_less_eq(xt,0.0) ) + { + mainlooppos = breaknewtcycle; + continue; + } + } + if( ae_fp_greater_eq(xt,x1) ) + { + yyy = (x1-x)/(x1-x0); + xt = x1-0.5*yyy*(x1-x); + if( ae_fp_greater_eq(xt,1.0) ) + { + mainlooppos = breaknewtcycle; + continue; + } + } + x = xt; + if( ae_fp_less(ae_fabs(d/x, _state),128.0*ae_machineepsilon) ) + { + break; + } + i = i+1; + mainlooppos = newtcycle; + continue; + } + else + { + mainlooppos = breaknewtcycle; + continue; + } + } + + /* + * breaknewtcycle + */ + if( mainlooppos==breaknewtcycle ) + { + dithresh = 256.0*ae_machineepsilon; + mainlooppos = ihalve; + continue; + } + } + + /* + * done + */ + if( rflg!=0 ) + { + if( ae_fp_less_eq(x,ae_machineepsilon) ) + { + x = 1.0-ae_machineepsilon; + } + else + { + x = 1.0-x; + } + } + result = x; + return result; +} + + +/************************************************************************* +Continued fraction expansion #1 for incomplete beta integral + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +static double ibetaf_incompletebetafe(double a, + double b, + double x, + double big, + double biginv, + ae_state *_state) +{ + double xk; + double pk; + double pkm1; + double pkm2; + double qk; + double qkm1; + double qkm2; + double k1; + double k2; + double k3; + double k4; + double k5; + double k6; + double k7; + double k8; + double r; + double t; + double ans; + double thresh; + ae_int_t n; + double result; + + + k1 = a; + k2 = a+b; + k3 = a; + k4 = a+1.0; + k5 = 1.0; + k6 = b-1.0; + k7 = k4; + k8 = a+2.0; + pkm2 = 0.0; + qkm2 = 1.0; + pkm1 = 1.0; + qkm1 = 1.0; + ans = 1.0; + r = 1.0; + n = 0; + thresh = 3.0*ae_machineepsilon; + do + { + xk = -x*k1*k2/(k3*k4); + pk = pkm1+pkm2*xk; + qk = qkm1+qkm2*xk; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + xk = x*k5*k6/(k7*k8); + pk = pkm1+pkm2*xk; + qk = qkm1+qkm2*xk; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if( ae_fp_neq(qk,(double)(0)) ) + { + r = pk/qk; + } + if( ae_fp_neq(r,(double)(0)) ) + { + t = ae_fabs((ans-r)/r, _state); + ans = r; + } + else + { + t = 1.0; + } + if( ae_fp_less(t,thresh) ) + { + break; + } + k1 = k1+1.0; + k2 = k2+1.0; + k3 = k3+2.0; + k4 = k4+2.0; + k5 = k5+1.0; + k6 = k6-1.0; + k7 = k7+2.0; + k8 = k8+2.0; + if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) + { + pkm2 = pkm2*biginv; + pkm1 = pkm1*biginv; + qkm2 = qkm2*biginv; + qkm1 = qkm1*biginv; + } + if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) + { + pkm2 = pkm2*big; + pkm1 = pkm1*big; + qkm2 = qkm2*big; + qkm1 = qkm1*big; + } + n = n+1; + } + while(n!=300); + result = ans; + return result; +} + + +/************************************************************************* +Continued fraction expansion #2 +for incomplete beta integral + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +static double ibetaf_incompletebetafe2(double a, + double b, + double x, + double big, + double biginv, + ae_state *_state) +{ + double xk; + double pk; + double pkm1; + double pkm2; + double qk; + double qkm1; + double qkm2; + double k1; + double k2; + double k3; + double k4; + double k5; + double k6; + double k7; + double k8; + double r; + double t; + double ans; + double z; + double thresh; + ae_int_t n; + double result; + + + k1 = a; + k2 = b-1.0; + k3 = a; + k4 = a+1.0; + k5 = 1.0; + k6 = a+b; + k7 = a+1.0; + k8 = a+2.0; + pkm2 = 0.0; + qkm2 = 1.0; + pkm1 = 1.0; + qkm1 = 1.0; + z = x/(1.0-x); + ans = 1.0; + r = 1.0; + n = 0; + thresh = 3.0*ae_machineepsilon; + do + { + xk = -z*k1*k2/(k3*k4); + pk = pkm1+pkm2*xk; + qk = qkm1+qkm2*xk; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + xk = z*k5*k6/(k7*k8); + pk = pkm1+pkm2*xk; + qk = qkm1+qkm2*xk; + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if( ae_fp_neq(qk,(double)(0)) ) + { + r = pk/qk; + } + if( ae_fp_neq(r,(double)(0)) ) + { + t = ae_fabs((ans-r)/r, _state); + ans = r; + } + else + { + t = 1.0; + } + if( ae_fp_less(t,thresh) ) + { + break; + } + k1 = k1+1.0; + k2 = k2-1.0; + k3 = k3+2.0; + k4 = k4+2.0; + k5 = k5+1.0; + k6 = k6+1.0; + k7 = k7+2.0; + k8 = k8+2.0; + if( ae_fp_greater(ae_fabs(qk, _state)+ae_fabs(pk, _state),big) ) + { + pkm2 = pkm2*biginv; + pkm1 = pkm1*biginv; + qkm2 = qkm2*biginv; + qkm1 = qkm1*biginv; + } + if( ae_fp_less(ae_fabs(qk, _state),biginv)||ae_fp_less(ae_fabs(pk, _state),biginv) ) + { + pkm2 = pkm2*big; + pkm1 = pkm1*big; + qkm2 = qkm2*big; + qkm1 = qkm1*big; + } + n = n+1; + } + while(n!=300); + result = ans; + return result; +} + + +/************************************************************************* +Power series for incomplete beta integral. +Use when b*x is small and x not too close to 1. + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +static double ibetaf_incompletebetaps(double a, + double b, + double x, + double maxgam, + ae_state *_state) +{ + double s; + double t; + double u; + double v; + double n; + double t1; + double z; + double ai; + double sg; + double result; + + + ai = 1.0/a; + u = (1.0-b)*x; + v = u/(a+1.0); + t1 = v; + t = u; + n = 2.0; + s = 0.0; + z = ae_machineepsilon*ai; + while(ae_fp_greater(ae_fabs(v, _state),z)) + { + u = (n-b)*x/n; + t = t*u; + v = t/(a+n); + s = s+v; + n = n+1.0; + } + s = s+t1; + s = s+ai; + u = a*ae_log(x, _state); + if( ae_fp_less(a+b,maxgam)&&ae_fp_less(ae_fabs(u, _state),ae_log(ae_maxrealnumber, _state)) ) + { + t = gammafunction(a+b, _state)/(gammafunction(a, _state)*gammafunction(b, _state)); + s = s*t*ae_pow(x, a, _state); + } + else + { + t = lngamma(a+b, &sg, _state)-lngamma(a, &sg, _state)-lngamma(b, &sg, _state)+u+ae_log(s, _state); + if( ae_fp_less(t,ae_log(ae_minrealnumber, _state)) ) + { + s = 0.0; + } + else + { + s = ae_exp(t, _state); + } + } + result = s; + return result; +} + + +#endif +#if defined(AE_COMPILE_STUDENTTDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Student's t distribution + +Computes the integral from minus infinity to t of the Student +t distribution with integer k > 0 degrees of freedom: + + t + - + | | + - | 2 -(k+1)/2 + | ( (k+1)/2 ) | ( x ) + ---------------------- | ( 1 + --- ) dx + - | ( k ) + sqrt( k pi ) | ( k/2 ) | + | | + - + -inf. + +Relation to incomplete beta integral: + + 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) +where + z = k/(k + t**2). + +For t < -2, this is the method of computation. For higher t, +a direct method is derived from integration by parts. +Since the function is symmetric about t=0, the area under the +right tail of the density is found by calling the function +with -t instead of t. + +ACCURACY: + +Tested at random 1 <= k <= 25. The "domain" refers to t. + Relative error: +arithmetic domain # trials peak rms + IEEE -100,-2 50000 5.9e-15 1.4e-15 + IEEE -2,100 500000 2.7e-15 4.9e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double studenttdistribution(ae_int_t k, double t, ae_state *_state) +{ + double x; + double rk; + double z; + double f; + double tz; + double p; + double xsqk; + ae_int_t j; + double result; + + + ae_assert(k>0, "Domain error in StudentTDistribution", _state); + if( ae_fp_eq(t,(double)(0)) ) + { + result = 0.5; + return result; + } + if( ae_fp_less(t,-2.0) ) + { + rk = (double)(k); + z = rk/(rk+t*t); + result = 0.5*incompletebeta(0.5*rk, 0.5, z, _state); + return result; + } + if( ae_fp_less(t,(double)(0)) ) + { + x = -t; + } + else + { + x = t; + } + rk = (double)(k); + z = 1.0+x*x/rk; + if( k%2!=0 ) + { + xsqk = x/ae_sqrt(rk, _state); + p = ae_atan(xsqk, _state); + if( k>1 ) + { + f = 1.0; + tz = 1.0; + j = 3; + while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) + { + tz = tz*((double)(j-1)/(z*(double)j)); + f = f+tz; + j = j+2; + } + p = p+f*xsqk/z; + } + p = p*2.0/ae_pi; + } + else + { + f = 1.0; + tz = 1.0; + j = 2; + while(j<=k-2&&ae_fp_greater(tz/f,ae_machineepsilon)) + { + tz = tz*((double)(j-1)/(z*(double)j)); + f = f+tz; + j = j+2; + } + p = f*x/ae_sqrt(z*rk, _state); + } + if( ae_fp_less(t,(double)(0)) ) + { + p = -p; + } + result = 0.5+0.5*p; + return result; +} + + +/************************************************************************* +Functional inverse of Student's t distribution + +Given probability p, finds the argument t such that stdtr(k,t) +is equal to p. + +ACCURACY: + +Tested at random 1 <= k <= 100. The "domain" refers to p: + Relative error: +arithmetic domain # trials peak rms + IEEE .001,.999 25000 5.7e-15 8.0e-16 + IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invstudenttdistribution(ae_int_t k, double p, ae_state *_state) +{ + double t; + double rk; + double z; + ae_int_t rflg; + double result; + + + ae_assert((k>0&&ae_fp_greater(p,(double)(0)))&&ae_fp_less(p,(double)(1)), "Domain error in InvStudentTDistribution", _state); + rk = (double)(k); + if( ae_fp_greater(p,0.25)&&ae_fp_less(p,0.75) ) + { + if( ae_fp_eq(p,0.5) ) + { + result = (double)(0); + return result; + } + z = 1.0-2.0*p; + z = invincompletebeta(0.5, 0.5*rk, ae_fabs(z, _state), _state); + t = ae_sqrt(rk*z/(1.0-z), _state); + if( ae_fp_less(p,0.5) ) + { + t = -t; + } + result = t; + return result; + } + rflg = -1; + if( ae_fp_greater_eq(p,0.5) ) + { + p = 1.0-p; + rflg = 1; + } + z = invincompletebeta(0.5*rk, 0.5, 2.0*p, _state); + if( ae_fp_less(ae_maxrealnumber*z,rk) ) + { + result = (double)rflg*ae_maxrealnumber; + return result; + } + t = ae_sqrt(rk/z-rk, _state); + result = (double)rflg*t; + return result; +} + + +#endif +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +F distribution + +Returns the area from zero to x under the F density +function (also known as Snedcor's density or the +variance ratio density). This is the density +of x = (u1/df1)/(u2/df2), where u1 and u2 are random +variables having Chi square distributions with df1 +and df2 degrees of freedom, respectively. +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). + + +The arguments a and b are greater than zero, and x is +nonnegative. + +ACCURACY: + +Tested at random points (a,b,x). + + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 + IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 + IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 + IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) +{ + double w; + double result; + + + ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,(double)(0)), "Domain error in FDistribution", _state); + w = (double)a*x; + w = w/((double)b+w); + result = incompletebeta(0.5*(double)a, 0.5*(double)b, w, _state); + return result; +} + + +/************************************************************************* +Complemented F distribution + +Returns the area from x to infinity under the F density +function (also known as Snedcor's density or the +variance ratio density). + + + inf. + - + 1 | | a-1 b-1 +1-P(x) = ------ | t (1-t) dt + B(a,b) | | + - + x + + +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). + + +ACCURACY: + +Tested at random points (a,b,x) in the indicated intervals. + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 + IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 + IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 + IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state) +{ + double w; + double result; + + + ae_assert((a>=1&&b>=1)&&ae_fp_greater_eq(x,(double)(0)), "Domain error in FCDistribution", _state); + w = (double)b/((double)b+(double)a*x); + result = incompletebeta(0.5*(double)b, 0.5*(double)a, w, _state); + return result; +} + + +/************************************************************************* +Inverse of complemented F distribution + +Finds the F density argument x such that the integral +from x to infinity of the F density is equal to the +given probability p. + +This is accomplished using the inverse beta integral +function and the relations + + z = incbi( df2/2, df1/2, p ) + x = df2 (1-z) / (df1 z). + +Note: the following relations hold for the inverse of +the uncomplemented F distribution: + + z = incbi( df1/2, df2/2, p ) + x = df2 z / (df1 (1-z)). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between .001 and 1: + IEEE 1,100 100000 8.3e-15 4.7e-16 + IEEE 1,10000 100000 2.1e-11 1.4e-13 + For p between 10^-6 and 10^-3: + IEEE 1,100 50000 1.3e-12 8.4e-15 + IEEE 1,10000 50000 3.0e-12 4.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invfdistribution(ae_int_t a, + ae_int_t b, + double y, + ae_state *_state) +{ + double w; + double result; + + + ae_assert(((a>=1&&b>=1)&&ae_fp_greater(y,(double)(0)))&&ae_fp_less_eq(y,(double)(1)), "Domain error in InvFDistribution", _state); + + /* + * Compute probability for x = 0.5 + */ + w = incompletebeta(0.5*(double)b, 0.5*(double)a, 0.5, _state); + + /* + * If that is greater than y, then the solution w < .5 + * Otherwise, solve at 1-y to remove cancellation in (b - b*w) + */ + if( ae_fp_greater(w,y)||ae_fp_less(y,0.001) ) + { + w = invincompletebeta(0.5*(double)b, 0.5*(double)a, y, _state); + result = ((double)b-(double)b*w)/((double)a*w); + } + else + { + w = invincompletebeta(0.5*(double)a, 0.5*(double)b, 1.0-y, _state); + result = (double)b*w/((double)a*(1.0-w)); + } + return result; +} + + +#endif +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Incomplete gamma integral + +The function is defined by + + x + - + 1 | | -t a-1 + igam(a,x) = ----- | e t dt. + - | | + | (a) - + 0 + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 200000 3.6e-14 2.9e-15 + IEEE 0,100 300000 9.9e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegamma(double a, double x, ae_state *_state) +{ + double igammaepsilon; + double ans; + double ax; + double c; + double r; + double tmp; + double result; + + + igammaepsilon = 0.000000000000001; + if( ae_fp_less_eq(x,(double)(0))||ae_fp_less_eq(a,(double)(0)) ) + { + result = (double)(0); + return result; + } + if( ae_fp_greater(x,(double)(1))&&ae_fp_greater(x,a) ) + { + result = (double)1-incompletegammac(a, x, _state); + return result; + } + ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); + if( ae_fp_less(ax,-709.78271289338399) ) + { + result = (double)(0); + return result; + } + ax = ae_exp(ax, _state); + r = a; + c = (double)(1); + ans = (double)(1); + do + { + r = r+(double)1; + c = c*x/r; + ans = ans+c; + } + while(ae_fp_greater(c/ans,igammaepsilon)); + result = ans*ax/a; + return result; +} + + +/************************************************************************* +Complemented incomplete gamma integral + +The function is defined by + + + igamc(a,x) = 1 - igam(a,x) + + inf. + - + 1 | | -t a-1 + = ----- | e t dt. + - | | + | (a) - + x + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + +Tested at random a, x. + a x Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 + IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegammac(double a, double x, ae_state *_state) +{ + double igammaepsilon; + double igammabignumber; + double igammabignumberinv; + double ans; + double ax; + double c; + double yc; + double r; + double t; + double y; + double z; + double pk; + double pkm1; + double pkm2; + double qk; + double qkm1; + double qkm2; + double tmp; + double result; + + + igammaepsilon = 0.000000000000001; + igammabignumber = 4503599627370496.0; + igammabignumberinv = 2.22044604925031308085*0.0000000000000001; + if( ae_fp_less_eq(x,(double)(0))||ae_fp_less_eq(a,(double)(0)) ) + { + result = (double)(1); + return result; + } + if( ae_fp_less(x,(double)(1))||ae_fp_less(x,a) ) + { + result = (double)1-incompletegamma(a, x, _state); + return result; + } + ax = a*ae_log(x, _state)-x-lngamma(a, &tmp, _state); + if( ae_fp_less(ax,-709.78271289338399) ) + { + result = (double)(0); + return result; + } + ax = ae_exp(ax, _state); + y = (double)1-a; + z = x+y+(double)1; + c = (double)(0); + pkm2 = (double)(1); + qkm2 = x; + pkm1 = x+(double)1; + qkm1 = z*x; + ans = pkm1/qkm1; + do + { + c = c+(double)1; + y = y+(double)1; + z = z+(double)2; + yc = y*c; + pk = pkm1*z-pkm2*yc; + qk = qkm1*z-qkm2*yc; + if( ae_fp_neq(qk,(double)(0)) ) + { + r = pk/qk; + t = ae_fabs((ans-r)/r, _state); + ans = r; + } + else + { + t = (double)(1); + } + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if( ae_fp_greater(ae_fabs(pk, _state),igammabignumber) ) + { + pkm2 = pkm2*igammabignumberinv; + pkm1 = pkm1*igammabignumberinv; + qkm2 = qkm2*igammabignumberinv; + qkm1 = qkm1*igammabignumberinv; + } + } + while(ae_fp_greater(t,igammaepsilon)); + result = ans*ax; + return result; +} + + +/************************************************************************* +Inverse of complemented imcomplete gamma integral + +Given p, the function finds x such that + + igamc( a, x ) = p. + +Starting with the approximate value + + 3 + x = a t + + where + + t = 1 - d - ndtri(p) sqrt(d) + +and + + d = 1/9a, + +the routine performs up to 10 Newton iterations to find the +root of igamc(a,x) - p = 0. + +ACCURACY: + +Tested at random a, p in the intervals indicated. + + a p Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 + IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 + IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invincompletegammac(double a, double y0, ae_state *_state) +{ + double igammaepsilon; + double iinvgammabignumber; + double x0; + double x1; + double x; + double yl; + double yh; + double y; + double d; + double lgm; + double dithresh; + ae_int_t i; + ae_int_t dir; + double tmp; + double result; + + + igammaepsilon = 0.000000000000001; + iinvgammabignumber = 4503599627370496.0; + x0 = iinvgammabignumber; + yl = (double)(0); + x1 = (double)(0); + yh = (double)(1); + dithresh = (double)5*igammaepsilon; + d = (double)1/((double)9*a); + y = (double)1-d-invnormaldistribution(y0, _state)*ae_sqrt(d, _state); + x = a*y*y*y; + lgm = lngamma(a, &tmp, _state); + i = 0; + while(i<10) + { + if( ae_fp_greater(x,x0)||ae_fp_less(x,x1) ) + { + d = 0.0625; + break; + } + y = incompletegammac(a, x, _state); + if( ae_fp_less(y,yl)||ae_fp_greater(y,yh) ) + { + d = 0.0625; + break; + } + if( ae_fp_less(y,y0) ) + { + x0 = x; + yl = y; + } + else + { + x1 = x; + yh = y; + } + d = (a-(double)1)*ae_log(x, _state)-x-lgm; + if( ae_fp_less(d,-709.78271289338399) ) + { + d = 0.0625; + break; + } + d = -ae_exp(d, _state); + d = (y-y0)/d; + if( ae_fp_less(ae_fabs(d/x, _state),igammaepsilon) ) + { + result = x; + return result; + } + x = x-d; + i = i+1; + } + if( ae_fp_eq(x0,iinvgammabignumber) ) + { + if( ae_fp_less_eq(x,(double)(0)) ) + { + x = (double)(1); + } + while(ae_fp_eq(x0,iinvgammabignumber)) + { + x = ((double)1+d)*x; + y = incompletegammac(a, x, _state); + if( ae_fp_less(y,y0) ) + { + x0 = x; + yl = y; + break; + } + d = d+d; + } + } + d = 0.5; + dir = 0; + i = 0; + while(i<400) + { + x = x1+d*(x0-x1); + y = incompletegammac(a, x, _state); + lgm = (x0-x1)/(x1+x0); + if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) + { + break; + } + lgm = (y-y0)/y0; + if( ae_fp_less(ae_fabs(lgm, _state),dithresh) ) + { + break; + } + if( ae_fp_less_eq(x,0.0) ) + { + break; + } + if( ae_fp_greater_eq(y,y0) ) + { + x1 = x; + yh = y; + if( dir<0 ) + { + dir = 0; + d = 0.5; + } + else + { + if( dir>1 ) + { + d = 0.5*d+0.5; + } + else + { + d = (y0-yl)/(yh-yl); + } + } + dir = dir+1; + } + else + { + x0 = x; + yl = y; + if( dir>0 ) + { + dir = 0; + d = 0.5; + } + else + { + if( dir<-1 ) + { + d = 0.5*d; + } + else + { + d = (y0-yl)/(yh-yl); + } + } + dir = dir-1; + } + i = i+1; + } + result = x; + return result; +} + + +#endif +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Chi-square distribution + +Returns the area under the left hand tail (from 0 to x) +of the Chi square probability density function with +v degrees of freedom. + + + x + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + 0 + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquaredistribution(double v, double x, ae_state *_state) +{ + double result; + + + ae_assert(ae_fp_greater_eq(x,(double)(0))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in ChiSquareDistribution", _state); + result = incompletegamma(v/2.0, x/2.0, _state); + return result; +} + + +/************************************************************************* +Complemented Chi-square distribution + +Returns the area under the right hand tail (from x to +infinity) of the Chi square probability density function +with v degrees of freedom: + + inf. + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + x + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquarecdistribution(double v, double x, ae_state *_state) +{ + double result; + + + ae_assert(ae_fp_greater_eq(x,(double)(0))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in ChiSquareDistributionC", _state); + result = incompletegammac(v/2.0, x/2.0, _state); + return result; +} + + +/************************************************************************* +Inverse of complemented Chi-square distribution + +Finds the Chi-square argument x such that the integral +from x to infinity of the Chi-square density is equal +to the given cumulative probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + x/2 = igami( df/2, y ); + +ACCURACY: + +See inverse incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double invchisquaredistribution(double v, double y, ae_state *_state) +{ + double result; + + + ae_assert((ae_fp_greater_eq(y,(double)(0))&&ae_fp_less_eq(y,(double)(1)))&&ae_fp_greater_eq(v,(double)(1)), "Domain error in InvChiSquareDistribution", _state); + result = (double)2*invincompletegammac(0.5*v, y, _state); + return result; +} + + +#endif +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Binomial distribution + +Returns the sum of the terms 0 through k of the Binomial +probability density: + + k + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=0 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p), with p between 0 and 1. + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 4.3e-15 2.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialdistribution(ae_int_t k, + ae_int_t n, + double p, + ae_state *_state) +{ + double dk; + double dn; + double result; + + + ae_assert(ae_fp_greater_eq(p,(double)(0))&&ae_fp_less_eq(p,(double)(1)), "Domain error in BinomialDistribution", _state); + ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistribution", _state); + if( k==-1 ) + { + result = (double)(0); + return result; + } + if( k==n ) + { + result = (double)(1); + return result; + } + dn = (double)(n-k); + if( k==0 ) + { + dk = ae_pow(1.0-p, dn, _state); + } + else + { + dk = (double)(k+1); + dk = incompletebeta(dn, dk, 1.0-p, _state); + } + result = dk; + return result; +} + + +/************************************************************************* +Complemented binomial distribution + +Returns the sum of the terms k+1 through n of the Binomial +probability density: + + n + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=k+1 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 6.7e-15 8.2e-16 + For p between 0 and .001: + IEEE 0,100 100000 1.5e-13 2.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialcdistribution(ae_int_t k, + ae_int_t n, + double p, + ae_state *_state) +{ + double dk; + double dn; + double result; + + + ae_assert(ae_fp_greater_eq(p,(double)(0))&&ae_fp_less_eq(p,(double)(1)), "Domain error in BinomialDistributionC", _state); + ae_assert(k>=-1&&k<=n, "Domain error in BinomialDistributionC", _state); + if( k==-1 ) + { + result = (double)(1); + return result; + } + if( k==n ) + { + result = (double)(0); + return result; + } + dn = (double)(n-k); + if( k==0 ) + { + if( ae_fp_less(p,0.01) ) + { + dk = -nuexpm1(dn*nulog1p(-p, _state), _state); + } + else + { + dk = 1.0-ae_pow(1.0-p, dn, _state); + } + } + else + { + dk = (double)(k+1); + dk = incompletebeta(dk, dn, p, _state); + } + result = dk; + return result; +} + + +/************************************************************************* +Inverse binomial distribution + +Finds the event probability p such that the sum of the +terms 0 through k of the Binomial probability density +is equal to the given cumulative probability y. + +This is accomplished using the inverse beta integral +function and the relation + +1 - p = incbi( n-k, k+1, y ). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 2.3e-14 6.4e-16 + IEEE 0,10000 100000 6.6e-12 1.2e-13 + For p between 10^-6 and 0.001: + IEEE 0,100 100000 2.0e-12 1.3e-14 + IEEE 0,10000 100000 1.5e-12 3.2e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invbinomialdistribution(ae_int_t k, + ae_int_t n, + double y, + ae_state *_state) +{ + double dk; + double dn; + double p; + double result; + + + ae_assert(k>=0&&k5000 ) + { + xk = x+(double)n; + yk = (double)1/(xk*xk); + t = (double)(n); + result = yk*t*((double)6*x*x-(double)8*t*x+t*t); + result = yk*(result+t*(t-2.0*x)); + result = yk*(result+t); + result = (result+(double)1)*ae_exp(-x, _state)/xk; + return result; + } + if( ae_fp_less_eq(x,(double)(1)) ) + { + psi = -eul-ae_log(x, _state); + for(i=1; i<=n-1; i++) + { + psi = psi+(double)1/(double)i; + } + z = -x; + xk = (double)(0); + yk = (double)(1); + pk = (double)(1-n); + if( n==1 ) + { + result = 0.0; + } + else + { + result = 1.0/pk; + } + do + { + xk = xk+(double)1; + yk = yk*z/xk; + pk = pk+(double)1; + if( ae_fp_neq(pk,(double)(0)) ) + { + result = result+yk/pk; + } + if( ae_fp_neq(result,(double)(0)) ) + { + t = ae_fabs(yk/result, _state); + } + else + { + t = (double)(1); + } + } + while(ae_fp_greater_eq(t,ae_machineepsilon)); + t = (double)(1); + for(i=1; i<=n-1; i++) + { + t = t*z/(double)i; + } + result = psi*t-result; + return result; + } + else + { + k = 1; + pkm2 = (double)(1); + qkm2 = x; + pkm1 = 1.0; + qkm1 = x+(double)n; + result = pkm1/qkm1; + do + { + k = k+1; + if( k%2==1 ) + { + yk = (double)(1); + xk = (double)n+(double)(k-1)/(double)2; + } + else + { + yk = x; + xk = (double)k/(double)2; + } + pk = pkm1*yk+pkm2*xk; + qk = qkm1*yk+qkm2*xk; + if( ae_fp_neq(qk,(double)(0)) ) + { + r = pk/qk; + t = ae_fabs((result-r)/r, _state); + result = r; + } + else + { + t = (double)(1); + } + pkm2 = pkm1; + pkm1 = pk; + qkm2 = qkm1; + qkm1 = qk; + if( ae_fp_greater(ae_fabs(pk, _state),big) ) + { + pkm2 = pkm2/big; + pkm1 = pkm1/big; + qkm2 = qkm2/big; + qkm1 = qkm1/big; + } + } + while(ae_fp_greater_eq(t,ae_machineepsilon)); + result = result*ae_exp(-x, _state); + } + return result; +} + + +#endif +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Jacobian Elliptic Functions + +Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), +and dn(u|m) of parameter m between 0 and 1, and real +argument u. + +These functions are periodic, with quarter-period on the +real axis equal to the complete elliptic integral +ellpk(1.0-m). + +Relation to incomplete elliptic integral: +If u = ellik(phi,m), then sn(u|m) = sin(phi), +and cn(u|m) = cos(phi). Phi is called the amplitude of u. + +Computation is by means of the arithmetic-geometric mean +algorithm, except when m is within 1e-9 of 0 or 1. In the +latter case with m close to 1, the approximation applies +only for phi < pi/2. + +ACCURACY: + +Tested at random points with u between 0 and 10, m between +0 and 1. + + Absolute error (* = relative error): +arithmetic function # trials peak rms + IEEE phi 10000 9.2e-16* 1.4e-16* + IEEE sn 50000 4.1e-15 4.6e-16 + IEEE cn 40000 3.6e-15 4.4e-16 + IEEE dn 10000 1.3e-12 1.8e-14 + + Peak error observed in consistency check using addition +theorem for sn(u+v) was 4e-16 (absolute). Also tested by +the above relation to the incomplete elliptic integral. +Accuracy deteriorates when u is large. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void jacobianellipticfunctions(double u, + double m, + double* sn, + double* cn, + double* dn, + double* ph, + ae_state *_state) +{ + ae_frame _frame_block; + double ai; + double b; + double phi; + double t; + double twon; + ae_vector a; + ae_vector c; + ae_int_t i; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&c, 0, sizeof(c)); + *sn = 0.0; + *cn = 0.0; + *dn = 0.0; + *ph = 0.0; + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_REAL, _state, ae_true); + + ae_assert(ae_fp_greater_eq(m,(double)(0))&&ae_fp_less_eq(m,(double)(1)), "Domain error in JacobianEllipticFunctions: m<0 or m>1", _state); + ae_vector_set_length(&a, 8+1, _state); + ae_vector_set_length(&c, 8+1, _state); + if( ae_fp_less(m,1.0e-9) ) + { + t = ae_sin(u, _state); + b = ae_cos(u, _state); + ai = 0.25*m*(u-t*b); + *sn = t-ai*b; + *cn = b+ai*t; + *ph = u-ai; + *dn = 1.0-0.5*m*t*t; + ae_frame_leave(_state); + return; + } + if( ae_fp_greater_eq(m,0.9999999999) ) + { + ai = 0.25*(1.0-m); + b = ae_cosh(u, _state); + t = ae_tanh(u, _state); + phi = 1.0/b; + twon = b*ae_sinh(u, _state); + *sn = t+ai*(twon-u)/(b*b); + *ph = 2.0*ae_atan(ae_exp(u, _state), _state)-1.57079632679489661923+ai*(twon-u)/b; + ai = ai*t*phi; + *cn = phi-ai*(twon-u); + *dn = phi+ai*(twon+u); + ae_frame_leave(_state); + return; + } + a.ptr.p_double[0] = 1.0; + b = ae_sqrt(1.0-m, _state); + c.ptr.p_double[0] = ae_sqrt(m, _state); + twon = 1.0; + i = 0; + while(ae_fp_greater(ae_fabs(c.ptr.p_double[i]/a.ptr.p_double[i], _state),ae_machineepsilon)) + { + if( i>7 ) + { + ae_assert(ae_false, "Overflow in JacobianEllipticFunctions", _state); + break; + } + ai = a.ptr.p_double[i]; + i = i+1; + c.ptr.p_double[i] = 0.5*(ai-b); + t = ae_sqrt(ai*b, _state); + a.ptr.p_double[i] = 0.5*(ai+b); + b = t; + twon = twon*2.0; + } + phi = twon*a.ptr.p_double[i]*u; + do + { + t = c.ptr.p_double[i]*ae_sin(phi, _state)/a.ptr.p_double[i]; + b = phi; + phi = (ae_asin(t, _state)+phi)/2.0; + i = i-1; + } + while(i!=0); + *sn = ae_sin(phi, _state); + t = ae_cos(phi, _state); + *cn = t; + *dn = t/ae_cos(phi-b, _state); + *ph = phi; + ae_frame_leave(_state); +} + + +#endif +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Sine and cosine integrals + +Evaluates the integrals + + x + - + | cos t - 1 + Ci(x) = eul + ln x + | --------- dt, + | t + - + 0 + x + - + | sin t + Si(x) = | ----- dt + | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are approximated by rational functions. +For x > 8 auxiliary functions f(x) and g(x) are employed +such that + +Ci(x) = f(x) sin(x) - g(x) cos(x) +Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) + + +ACCURACY: + Test interval = [0,50]. +Absolute error, except relative when > 1: +arithmetic function # trials peak rms + IEEE Si 30000 4.4e-16 7.3e-17 + IEEE Ci 30000 6.9e-16 5.1e-17 + +Cephes Math Library Release 2.1: January, 1989 +Copyright 1984, 1987, 1989 by Stephen L. Moshier +*************************************************************************/ +void sinecosineintegrals(double x, + double* si, + double* ci, + ae_state *_state) +{ + double z; + double c; + double s; + double f; + double g; + ae_int_t sg; + double sn; + double sd; + double cn; + double cd; + double fn; + double fd; + double gn; + double gd; + + *si = 0.0; + *ci = 0.0; + + if( ae_fp_less(x,(double)(0)) ) + { + sg = -1; + x = -x; + } + else + { + sg = 0; + } + if( ae_fp_eq(x,(double)(0)) ) + { + *si = (double)(0); + *ci = -ae_maxrealnumber; + return; + } + if( ae_fp_greater(x,1.0E9) ) + { + *si = 1.570796326794896619-ae_cos(x, _state)/x; + *ci = ae_sin(x, _state)/x; + return; + } + if( ae_fp_less_eq(x,(double)(4)) ) + { + z = x*x; + sn = -8.39167827910303881427E-11; + sn = sn*z+4.62591714427012837309E-8; + sn = sn*z-9.75759303843632795789E-6; + sn = sn*z+9.76945438170435310816E-4; + sn = sn*z-4.13470316229406538752E-2; + sn = sn*z+1.00000000000000000302E0; + sd = 2.03269266195951942049E-12; + sd = sd*z+1.27997891179943299903E-9; + sd = sd*z+4.41827842801218905784E-7; + sd = sd*z+9.96412122043875552487E-5; + sd = sd*z+1.42085239326149893930E-2; + sd = sd*z+9.99999999999999996984E-1; + s = x*sn/sd; + cn = 2.02524002389102268789E-11; + cn = cn*z-1.35249504915790756375E-8; + cn = cn*z+3.59325051419993077021E-6; + cn = cn*z-4.74007206873407909465E-4; + cn = cn*z+2.89159652607555242092E-2; + cn = cn*z-1.00000000000000000080E0; + cd = 4.07746040061880559506E-12; + cd = cd*z+3.06780997581887812692E-9; + cd = cd*z+1.23210355685883423679E-6; + cd = cd*z+3.17442024775032769882E-4; + cd = cd*z+5.10028056236446052392E-2; + cd = cd*z+4.00000000000000000080E0; + c = z*cn/cd; + if( sg!=0 ) + { + s = -s; + } + *si = s; + *ci = 0.57721566490153286061+ae_log(x, _state)+c; + return; + } + s = ae_sin(x, _state); + c = ae_cos(x, _state); + z = 1.0/(x*x); + if( ae_fp_less(x,(double)(8)) ) + { + fn = 4.23612862892216586994E0; + fn = fn*z+5.45937717161812843388E0; + fn = fn*z+1.62083287701538329132E0; + fn = fn*z+1.67006611831323023771E-1; + fn = fn*z+6.81020132472518137426E-3; + fn = fn*z+1.08936580650328664411E-4; + fn = fn*z+5.48900223421373614008E-7; + fd = 1.00000000000000000000E0; + fd = fd*z+8.16496634205391016773E0; + fd = fd*z+7.30828822505564552187E0; + fd = fd*z+1.86792257950184183883E0; + fd = fd*z+1.78792052963149907262E-1; + fd = fd*z+7.01710668322789753610E-3; + fd = fd*z+1.10034357153915731354E-4; + fd = fd*z+5.48900252756255700982E-7; + f = fn/(x*fd); + gn = 8.71001698973114191777E-2; + gn = gn*z+6.11379109952219284151E-1; + gn = gn*z+3.97180296392337498885E-1; + gn = gn*z+7.48527737628469092119E-2; + gn = gn*z+5.38868681462177273157E-3; + gn = gn*z+1.61999794598934024525E-4; + gn = gn*z+1.97963874140963632189E-6; + gn = gn*z+7.82579040744090311069E-9; + gd = 1.00000000000000000000E0; + gd = gd*z+1.64402202413355338886E0; + gd = gd*z+6.66296701268987968381E-1; + gd = gd*z+9.88771761277688796203E-2; + gd = gd*z+6.22396345441768420760E-3; + gd = gd*z+1.73221081474177119497E-4; + gd = gd*z+2.02659182086343991969E-6; + gd = gd*z+7.82579218933534490868E-9; + g = z*gn/gd; + } + else + { + fn = 4.55880873470465315206E-1; + fn = fn*z+7.13715274100146711374E-1; + fn = fn*z+1.60300158222319456320E-1; + fn = fn*z+1.16064229408124407915E-2; + fn = fn*z+3.49556442447859055605E-4; + fn = fn*z+4.86215430826454749482E-6; + fn = fn*z+3.20092790091004902806E-8; + fn = fn*z+9.41779576128512936592E-11; + fn = fn*z+9.70507110881952024631E-14; + fd = 1.00000000000000000000E0; + fd = fd*z+9.17463611873684053703E-1; + fd = fd*z+1.78685545332074536321E-1; + fd = fd*z+1.22253594771971293032E-2; + fd = fd*z+3.58696481881851580297E-4; + fd = fd*z+4.92435064317881464393E-6; + fd = fd*z+3.21956939101046018377E-8; + fd = fd*z+9.43720590350276732376E-11; + fd = fd*z+9.70507110881952025725E-14; + f = fn/(x*fd); + gn = 6.97359953443276214934E-1; + gn = gn*z+3.30410979305632063225E-1; + gn = gn*z+3.84878767649974295920E-2; + gn = gn*z+1.71718239052347903558E-3; + gn = gn*z+3.48941165502279436777E-5; + gn = gn*z+3.47131167084116673800E-7; + gn = gn*z+1.70404452782044526189E-9; + gn = gn*z+3.85945925430276600453E-12; + gn = gn*z+3.14040098946363334640E-15; + gd = 1.00000000000000000000E0; + gd = gd*z+1.68548898811011640017E0; + gd = gd*z+4.87852258695304967486E-1; + gd = gd*z+4.67913194259625806320E-2; + gd = gd*z+1.90284426674399523638E-3; + gd = gd*z+3.68475504442561108162E-5; + gd = gd*z+3.57043223443740838771E-7; + gd = gd*z+1.72693748966316146736E-9; + gd = gd*z+3.87830166023954706752E-12; + gd = gd*z+3.14040098946363335242E-15; + g = z*gn/gd; + } + *si = 1.570796326794896619-f*c-g*s; + if( sg!=0 ) + { + *si = -*si; + } + *ci = f*s-g*c; +} + + +/************************************************************************* +Hyperbolic sine and cosine integrals + +Approximates the integrals + + x + - + | | cosh t - 1 + Chi(x) = eul + ln x + | ----------- dt, + | | t + - + 0 + + x + - + | | sinh t + Shi(x) = | ------ dt + | | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are evaluated by power series for x < 8 +and by Chebyshev expansions for x between 8 and 88. +For large x, both functions approach exp(x)/2x. +Arguments greater than 88 in magnitude return MAXNUM. + + +ACCURACY: + +Test interval 0 to 88. + Relative error: +arithmetic function # trials peak rms + IEEE Shi 30000 6.9e-16 1.6e-16 + Absolute error, except relative when |Chi| > 1: + IEEE Chi 30000 8.4e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void hyperbolicsinecosineintegrals(double x, + double* shi, + double* chi, + ae_state *_state) +{ + double k; + double z; + double c; + double s; + double a; + ae_int_t sg; + double b0; + double b1; + double b2; + + *shi = 0.0; + *chi = 0.0; + + if( ae_fp_less(x,(double)(0)) ) + { + sg = -1; + x = -x; + } + else + { + sg = 0; + } + if( ae_fp_eq(x,(double)(0)) ) + { + *shi = (double)(0); + *chi = -ae_maxrealnumber; + return; + } + if( ae_fp_less(x,8.0) ) + { + z = x*x; + a = 1.0; + s = 1.0; + c = 0.0; + k = 2.0; + do + { + a = a*z/k; + c = c+a/k; + k = k+1.0; + a = a/k; + s = s+a/k; + k = k+1.0; + } + while(ae_fp_greater_eq(ae_fabs(a/s, _state),ae_machineepsilon)); + s = s*x; + } + else + { + if( ae_fp_less(x,18.0) ) + { + a = (576.0/x-52.0)/10.0; + k = ae_exp(x, _state)/x; + b0 = 1.83889230173399459482E-17; + b1 = 0.0; + trigintegrals_chebiterationshichi(a, -9.55485532279655569575E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.04326105980879882648E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.09896949074905343022E-15, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.31313534344092599234E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 5.93976226264314278932E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.47197010497749154755E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.40059764613117131000E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 9.49044626224223543299E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.61596181145435454033E-11, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.77899784436430310321E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.35455469767246947469E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.03257121792819495123E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.56699611114982536845E-8, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.44818877384267342057E-7, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 7.82018215184051295296E-7, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -5.39919118403805073710E-6, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.12458202168959833422E-5, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 8.90136741950727517826E-5, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.02558474743846862168E-3, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.96064440855633256972E-2, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.11847751047257036625E0, &b0, &b1, &b2, _state); + s = k*0.5*(b0-b2); + b0 = -8.12435385225864036372E-18; + b1 = 0.0; + trigintegrals_chebiterationshichi(a, 2.17586413290339214377E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 5.22624394924072204667E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -9.48812110591690559363E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 5.35546311647465209166E-15, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.21009970113732918701E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -6.00865178553447437951E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 7.16339649156028587775E-13, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -2.93496072607599856104E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.40359438136491256904E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 8.76302288609054966081E-11, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -4.40092476213282340617E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.87992075640569295479E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.31458150989474594064E-8, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -4.75513930924765465590E-8, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -2.21775018801848880741E-7, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.94635531373272490962E-6, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 4.33505889257316408893E-6, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -6.13387001076494349496E-5, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.13085477492997465138E-4, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 4.97164789823116062801E-4, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.64347496031374526641E-2, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.11446150876699213025E0, &b0, &b1, &b2, _state); + c = k*0.5*(b0-b2); + } + else + { + if( ae_fp_less_eq(x,88.0) ) + { + a = (6336.0/x-212.0)/70.0; + k = ae_exp(x, _state)/x; + b0 = -1.05311574154850938805E-17; + b1 = 0.0; + trigintegrals_chebiterationshichi(a, 2.62446095596355225821E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 8.82090135625368160657E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.38459811878103047136E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -8.30608026366935789136E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 3.93397875437050071776E-15, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.01765565969729044505E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -4.21128170307640802703E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.60818204519802480035E-13, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 3.34714954175994481761E-13, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.72600352129153073807E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.66894954752839083608E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.49278141024730899554E-11, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.58580661666482709598E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.79289437183355633342E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.76281629144264523277E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.69050228879421288846E-8, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.25391771228487041649E-7, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.16229947068677338732E-6, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.61038260117376323993E-5, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 3.49810375601053973070E-4, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.28478065259647610779E-2, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.03665722588798326712E0, &b0, &b1, &b2, _state); + s = k*0.5*(b0-b2); + b0 = 8.06913408255155572081E-18; + b1 = 0.0; + trigintegrals_chebiterationshichi(a, -2.08074168180148170312E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -5.98111329658272336816E-17, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.68533951085945765591E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 4.52313941698904694774E-16, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.10734917335299464535E-15, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -4.42823207332531972288E-15, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 3.49639695410806959872E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 6.63406731718911586609E-14, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.71902448093119218395E-13, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.27135418132338309016E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.74851141935315395333E-12, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.33781843985453438400E-11, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 2.71436006377612442764E-11, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -2.56600180000355990529E-10, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -1.61021375163803438552E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -4.72543064876271773512E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, -3.00095178028681682282E-9, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 7.79387474390914922337E-8, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.06942765566401507066E-6, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.59503164802313196374E-5, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 3.49592575153777996871E-4, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.28475387530065247392E-2, &b0, &b1, &b2, _state); + trigintegrals_chebiterationshichi(a, 1.03665693917934275131E0, &b0, &b1, &b2, _state); + c = k*0.5*(b0-b2); + } + else + { + if( sg!=0 ) + { + *shi = -ae_maxrealnumber; + } + else + { + *shi = ae_maxrealnumber; + } + *chi = ae_maxrealnumber; + return; + } + } + } + if( sg!=0 ) + { + s = -s; + } + *shi = s; + *chi = 0.57721566490153286061+ae_log(x, _state)+c; +} + + +static void trigintegrals_chebiterationshichi(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state) +{ + + + *b2 = *b1; + *b1 = *b0; + *b0 = x*(*b1)-(*b2)+c; +} + + +#endif +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Calculation of the value of the Chebyshev polynomials of the +first and second kinds. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument, -1 <= x <= 1 + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevcalculate(ae_int_t r, + ae_int_t n, + double x, + ae_state *_state) +{ + ae_int_t i; + double a; + double b; + double result; + + + result = (double)(0); + + /* + * Prepare A and B + */ + if( r==1 ) + { + a = (double)(1); + b = x; + } + else + { + a = (double)(1); + b = (double)2*x; + } + + /* + * Special cases: N=0 or N=1 + */ + if( n==0 ) + { + result = a; + return result; + } + if( n==1 ) + { + result = b; + return result; + } + + /* + * General case: N>=2 + */ + for(i=2; i<=n; i++) + { + result = (double)2*x*b-a; + a = b; + b = result; + } + return result; +} + + +/************************************************************************* +Summation of Chebyshev polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) +or + c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) +depending on the R. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevsum(/* Real */ const ae_vector* c, + ae_int_t r, + ae_int_t n, + double x, + ae_state *_state) +{ + double b1; + double b2; + ae_int_t i; + double result; + + + b1 = (double)(0); + b2 = (double)(0); + for(i=n; i>=1; i--) + { + result = (double)2*x*b1-b2+c->ptr.p_double[i]; + b2 = b1; + b1 = result; + } + if( r==1 ) + { + result = -b2+x*b1+c->ptr.p_double[0]; + } + else + { + result = -b2+(double)2*x*b1+c->ptr.p_double[0]; + } + return result; +} + + +/************************************************************************* +Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void chebyshevcoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(c); + + ae_vector_set_length(c, n+1, _state); + for(i=0; i<=n; i++) + { + c->ptr.p_double[i] = (double)(0); + } + if( n==0||n==1 ) + { + c->ptr.p_double[n] = (double)(1); + } + else + { + c->ptr.p_double[n] = ae_exp((double)(n-1)*ae_log((double)(2), _state), _state); + for(i=0; i<=n/2-1; i++) + { + c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(double)(n-2*i)*(double)(n-2*i-1)/(double)4/(double)(i+1)/(double)(n-i-1); + } + } +} + + +/************************************************************************* +Conversion of a series of Chebyshev polynomials to a power series. + +Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as +B[0] + B[1]*X + ... + B[N]*X^N. + +Input parameters: + A - Chebyshev series coefficients + N - degree, N>=0 + +Output parameters + B - power series coefficients +*************************************************************************/ +void fromchebyshev(/* Real */ const ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state) +{ + ae_int_t i; + ae_int_t k; + double e; + double d; + + ae_vector_clear(b); + + ae_vector_set_length(b, n+1, _state); + for(i=0; i<=n; i++) + { + b->ptr.p_double[i] = (double)(0); + } + d = (double)(0); + i = 0; + do + { + k = i; + do + { + e = b->ptr.p_double[k]; + b->ptr.p_double[k] = (double)(0); + if( i<=1&&k==i ) + { + b->ptr.p_double[k] = (double)(1); + } + else + { + if( i!=0 ) + { + b->ptr.p_double[k] = (double)2*d; + } + if( k>i+1 ) + { + b->ptr.p_double[k] = b->ptr.p_double[k]-b->ptr.p_double[k-2]; + } + } + d = e; + k = k+1; + } + while(k<=n); + d = b->ptr.p_double[i]; + e = (double)(0); + k = i; + while(k<=n) + { + e = e+b->ptr.p_double[k]*a->ptr.p_double[k]; + k = k+2; + } + b->ptr.p_double[i] = e; + i = i+1; + } + while(i<=n); +} + + +#endif +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Poisson distribution + +Returns the sum of the first k+1 terms of the Poisson +distribution: + + k j + -- -m m + > e -- + -- j! + j=0 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the relation + +y = pdtr( k, m ) = igamc( k+1, m ). + +The arguments must both be positive. +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissondistribution(ae_int_t k, double m, ae_state *_state) +{ + double result; + + + ae_assert(k>=0&&ae_fp_greater(m,(double)(0)), "Domain error in PoissonDistribution", _state); + result = incompletegammac((double)(k+1), m, _state); + return result; +} + + +/************************************************************************* +Complemented Poisson distribution + +Returns the sum of the terms k+1 to infinity of the Poisson +distribution: + + inf. j + -- -m m + > e -- + -- j! + j=k+1 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the formula + +y = pdtrc( k, m ) = igam( k+1, m ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissoncdistribution(ae_int_t k, double m, ae_state *_state) +{ + double result; + + + ae_assert(k>=0&&ae_fp_greater(m,(double)(0)), "Domain error in PoissonDistributionC", _state); + result = incompletegamma((double)(k+1), m, _state); + return result; +} + + +/************************************************************************* +Inverse Poisson distribution + +Finds the Poisson variable x such that the integral +from 0 to x of the Poisson density is equal to the +given probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + m = igami( k+1, y ). + +ACCURACY: + +See inverse incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invpoissondistribution(ae_int_t k, double y, ae_state *_state) +{ + double result; + + + ae_assert((k>=0&&ae_fp_greater_eq(y,(double)(0)))&&ae_fp_less(y,(double)(1)), "Domain error in InvPoissonDistribution", _state); + result = invincompletegammac((double)(k+1), y, _state); + return result; +} + + +#endif +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Beta function + + + - - + | (a) | (b) +beta( a, b ) = -----------. + - + | (a+b) + +For large arguments the logarithm of the function is +evaluated using lgam(), then exponentiated. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 8.1e-14 1.1e-14 + +Cephes Math Library Release 2.0: April, 1987 +Copyright 1984, 1987 by Stephen L. Moshier +*************************************************************************/ +double beta(double a, double b, ae_state *_state) +{ + double y; + double sg; + double s; + double result; + + + sg = (double)(1); + ae_assert(ae_fp_greater(a,(double)(0))||ae_fp_neq(a,(double)(ae_ifloor(a, _state))), "Overflow in Beta", _state); + ae_assert(ae_fp_greater(b,(double)(0))||ae_fp_neq(b,(double)(ae_ifloor(b, _state))), "Overflow in Beta", _state); + y = a+b; + if( ae_fp_greater(ae_fabs(y, _state),171.624376956302725) ) + { + y = lngamma(y, &s, _state); + sg = sg*s; + y = lngamma(b, &s, _state)-y; + sg = sg*s; + y = lngamma(a, &s, _state)+y; + sg = sg*s; + ae_assert(ae_fp_less_eq(y,ae_log(ae_maxrealnumber, _state)), "Overflow in Beta", _state); + result = sg*ae_exp(y, _state); + return result; + } + y = gammafunction(y, _state); + ae_assert(ae_fp_neq(y,(double)(0)), "Overflow in Beta", _state); + if( ae_fp_greater(a,b) ) + { + y = gammafunction(a, _state)/y; + y = y*gammafunction(b, _state); + } + else + { + y = gammafunction(b, _state)/y; + y = y*gammafunction(a, _state); + } + result = y; + return result; +} + + +#endif +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Fresnel integral + +Evaluates the Fresnel integrals + + x + - + | | +C(x) = | cos(pi/2 t**2) dt, + | | + - + 0 + + x + - + | | +S(x) = | sin(pi/2 t**2) dt. + | | + - + 0 + + +The integrals are evaluated by a power series for x < 1. +For x >= 1 auxiliary functions f(x) and g(x) are employed +such that + +C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) +S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) + + + +ACCURACY: + + Relative error. + +Arithmetic function domain # trials peak rms + IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 + IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void fresnelintegral(double x, double* c, double* s, ae_state *_state) +{ + double xxa; + double f; + double g; + double cc; + double ss; + double t; + double u; + double x2; + double sn; + double sd; + double cn; + double cd; + double fn; + double fd; + double gn; + double gd; + double mpi; + double mpio2; + + + mpi = 3.14159265358979323846; + mpio2 = 1.57079632679489661923; + xxa = x; + x = ae_fabs(xxa, _state); + x2 = x*x; + if( ae_fp_less(x2,2.5625) ) + { + t = x2*x2; + sn = -2.99181919401019853726E3; + sn = sn*t+7.08840045257738576863E5; + sn = sn*t-6.29741486205862506537E7; + sn = sn*t+2.54890880573376359104E9; + sn = sn*t-4.42979518059697779103E10; + sn = sn*t+3.18016297876567817986E11; + sd = 1.00000000000000000000E0; + sd = sd*t+2.81376268889994315696E2; + sd = sd*t+4.55847810806532581675E4; + sd = sd*t+5.17343888770096400730E6; + sd = sd*t+4.19320245898111231129E8; + sd = sd*t+2.24411795645340920940E10; + sd = sd*t+6.07366389490084639049E11; + cn = -4.98843114573573548651E-8; + cn = cn*t+9.50428062829859605134E-6; + cn = cn*t-6.45191435683965050962E-4; + cn = cn*t+1.88843319396703850064E-2; + cn = cn*t-2.05525900955013891793E-1; + cn = cn*t+9.99999999999999998822E-1; + cd = 3.99982968972495980367E-12; + cd = cd*t+9.15439215774657478799E-10; + cd = cd*t+1.25001862479598821474E-7; + cd = cd*t+1.22262789024179030997E-5; + cd = cd*t+8.68029542941784300606E-4; + cd = cd*t+4.12142090722199792936E-2; + cd = cd*t+1.00000000000000000118E0; + *s = (double)ae_sign(xxa, _state)*x*x2*sn/sd; + *c = (double)ae_sign(xxa, _state)*x*cn/cd; + return; + } + if( ae_fp_greater(x,36974.0) ) + { + *c = (double)ae_sign(xxa, _state)*0.5; + *s = (double)ae_sign(xxa, _state)*0.5; + return; + } + x2 = x*x; + t = mpi*x2; + u = (double)1/(t*t); + t = (double)1/t; + fn = 4.21543555043677546506E-1; + fn = fn*u+1.43407919780758885261E-1; + fn = fn*u+1.15220955073585758835E-2; + fn = fn*u+3.45017939782574027900E-4; + fn = fn*u+4.63613749287867322088E-6; + fn = fn*u+3.05568983790257605827E-8; + fn = fn*u+1.02304514164907233465E-10; + fn = fn*u+1.72010743268161828879E-13; + fn = fn*u+1.34283276233062758925E-16; + fn = fn*u+3.76329711269987889006E-20; + fd = 1.00000000000000000000E0; + fd = fd*u+7.51586398353378947175E-1; + fd = fd*u+1.16888925859191382142E-1; + fd = fd*u+6.44051526508858611005E-3; + fd = fd*u+1.55934409164153020873E-4; + fd = fd*u+1.84627567348930545870E-6; + fd = fd*u+1.12699224763999035261E-8; + fd = fd*u+3.60140029589371370404E-11; + fd = fd*u+5.88754533621578410010E-14; + fd = fd*u+4.52001434074129701496E-17; + fd = fd*u+1.25443237090011264384E-20; + gn = 5.04442073643383265887E-1; + gn = gn*u+1.97102833525523411709E-1; + gn = gn*u+1.87648584092575249293E-2; + gn = gn*u+6.84079380915393090172E-4; + gn = gn*u+1.15138826111884280931E-5; + gn = gn*u+9.82852443688422223854E-8; + gn = gn*u+4.45344415861750144738E-10; + gn = gn*u+1.08268041139020870318E-12; + gn = gn*u+1.37555460633261799868E-15; + gn = gn*u+8.36354435630677421531E-19; + gn = gn*u+1.86958710162783235106E-22; + gd = 1.00000000000000000000E0; + gd = gd*u+1.47495759925128324529E0; + gd = gd*u+3.37748989120019970451E-1; + gd = gd*u+2.53603741420338795122E-2; + gd = gd*u+8.14679107184306179049E-4; + gd = gd*u+1.27545075667729118702E-5; + gd = gd*u+1.04314589657571990585E-7; + gd = gd*u+4.60680728146520428211E-10; + gd = gd*u+1.10273215066240270757E-12; + gd = gd*u+1.38796531259578871258E-15; + gd = gd*u+8.39158816283118707363E-19; + gd = gd*u+1.86958710162783236342E-22; + f = (double)1-u*fn/fd; + g = t*gn/gd; + t = mpio2*x2; + cc = ae_cos(t, _state); + ss = ae_sin(t, _state); + t = mpi*x; + *c = 0.5+(f*ss-g*cc)/t; + *s = 0.5-(f*cc+g*ss)/t; + *c = *c*(double)ae_sign(xxa, _state); + *s = *s*(double)ae_sign(xxa, _state); +} + + +#endif +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Psi (digamma) function + + d - + psi(x) = -- ln | (x) + dx + +is the logarithmic derivative of the gamma function. +For integer x, + n-1 + - +psi(n) = -EUL + > 1/k. + - + k=1 + +This formula is used for 0 < n <= 10. If x is negative, it +is transformed to a positive argument by the reflection +formula psi(1-x) = psi(x) + pi cot(pi x). +For general positive x, the argument is made greater than 10 +using the recurrence psi(x+1) = psi(x) + 1/x. +Then the following asymptotic expansion is applied: + + inf. B + - 2k +psi(x) = log(x) - 1/2x - > ------- + - 2k + k=1 2k x + +where the B2k are Bernoulli numbers. + +ACCURACY: + Relative error (except absolute when |psi| < 1): +arithmetic domain # trials peak rms + IEEE 0,30 30000 1.3e-15 1.4e-16 + IEEE -30,0 40000 1.5e-15 2.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double psi(double x, ae_state *_state) +{ + double p; + double q; + double nz; + double s; + double w; + double y; + double z; + double polv; + ae_int_t i; + ae_int_t n; + ae_int_t negative; + double result; + + + negative = 0; + nz = 0.0; + if( ae_fp_less_eq(x,(double)(0)) ) + { + negative = 1; + q = x; + p = (double)(ae_ifloor(q, _state)); + if( ae_fp_eq(p,q) ) + { + ae_assert(ae_false, "Singularity in Psi(x)", _state); + result = ae_maxrealnumber; + return result; + } + nz = q-p; + if( ae_fp_neq(nz,0.5) ) + { + if( ae_fp_greater(nz,0.5) ) + { + p = p+1.0; + nz = q-p; + } + nz = ae_pi/ae_tan(ae_pi*nz, _state); + } + else + { + nz = 0.0; + } + x = 1.0-x; + } + if( ae_fp_less_eq(x,10.0)&&ae_fp_eq(x,(double)(ae_ifloor(x, _state))) ) + { + y = 0.0; + n = ae_ifloor(x, _state); + for(i=1; i<=n-1; i++) + { + w = (double)(i); + y = y+1.0/w; + } + y = y-0.57721566490153286061; + } + else + { + s = x; + w = 0.0; + while(ae_fp_less(s,10.0)) + { + w = w+1.0/s; + s = s+1.0; + } + if( ae_fp_less(s,1.0E17) ) + { + z = 1.0/(s*s); + polv = 8.33333333333333333333E-2; + polv = polv*z-2.10927960927960927961E-2; + polv = polv*z+7.57575757575757575758E-3; + polv = polv*z-4.16666666666666666667E-3; + polv = polv*z+3.96825396825396825397E-3; + polv = polv*z-8.33333333333333333333E-3; + polv = polv*z+8.33333333333333333333E-2; + y = z*polv; + } + else + { + y = 0.0; + } + y = ae_log(s, _state)-0.5/s-y-w; + } + if( negative!=0 ) + { + y = y-nz; + } + result = y; + return result; +} + + +#endif +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Airy function + +Solution of the differential equation + +y"(x) = xy. + +The function returns the two independent solutions Ai, Bi +and their first derivatives Ai'(x), Bi'(x). + +Evaluation is by power series summation for small x, +by rational minimax approximations for large x. + + + +ACCURACY: +Error criterion is absolute when function <= 1, relative +when function > 1, except * denotes relative error criterion. +For large negative x, the absolute error increases as x^1.5. +For large positive x, the relative error increases as x^1.5. + +Arithmetic domain function # trials peak rms +IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 +IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* +IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 +IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* +IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 +IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void airy(double x, + double* ai, + double* aip, + double* bi, + double* bip, + ae_state *_state) +{ + double z; + double zz; + double t; + double f; + double g; + double uf; + double ug; + double k; + double zeta; + double theta; + ae_int_t domflg; + double c1; + double c2; + double sqrt3; + double sqpii; + double afn; + double afd; + double agn; + double agd; + double apfn; + double apfd; + double apgn; + double apgd; + double an; + double ad; + double apn; + double apd; + double bn16; + double bd16; + double bppn; + double bppd; + + *ai = 0.0; + *aip = 0.0; + *bi = 0.0; + *bip = 0.0; + + sqpii = 5.64189583547756286948E-1; + c1 = 0.35502805388781723926; + c2 = 0.258819403792806798405; + sqrt3 = 1.732050807568877293527; + domflg = 0; + if( ae_fp_greater(x,25.77) ) + { + *ai = (double)(0); + *aip = (double)(0); + *bi = ae_maxrealnumber; + *bip = ae_maxrealnumber; + return; + } + if( ae_fp_less(x,-2.09) ) + { + domflg = 15; + t = ae_sqrt(-x, _state); + zeta = -2.0*x*t/3.0; + t = ae_sqrt(t, _state); + k = sqpii/t; + z = 1.0/zeta; + zz = z*z; + afn = -1.31696323418331795333E-1; + afn = afn*zz-6.26456544431912369773E-1; + afn = afn*zz-6.93158036036933542233E-1; + afn = afn*zz-2.79779981545119124951E-1; + afn = afn*zz-4.91900132609500318020E-2; + afn = afn*zz-4.06265923594885404393E-3; + afn = afn*zz-1.59276496239262096340E-4; + afn = afn*zz-2.77649108155232920844E-6; + afn = afn*zz-1.67787698489114633780E-8; + afd = 1.00000000000000000000E0; + afd = afd*zz+1.33560420706553243746E1; + afd = afd*zz+3.26825032795224613948E1; + afd = afd*zz+2.67367040941499554804E1; + afd = afd*zz+9.18707402907259625840E0; + afd = afd*zz+1.47529146771666414581E0; + afd = afd*zz+1.15687173795188044134E-1; + afd = afd*zz+4.40291641615211203805E-3; + afd = afd*zz+7.54720348287414296618E-5; + afd = afd*zz+4.51850092970580378464E-7; + uf = 1.0+zz*afn/afd; + agn = 1.97339932091685679179E-2; + agn = agn*zz+3.91103029615688277255E-1; + agn = agn*zz+1.06579897599595591108E0; + agn = agn*zz+9.39169229816650230044E-1; + agn = agn*zz+3.51465656105547619242E-1; + agn = agn*zz+6.33888919628925490927E-2; + agn = agn*zz+5.85804113048388458567E-3; + agn = agn*zz+2.82851600836737019778E-4; + agn = agn*zz+6.98793669997260967291E-6; + agn = agn*zz+8.11789239554389293311E-8; + agn = agn*zz+3.41551784765923618484E-10; + agd = 1.00000000000000000000E0; + agd = agd*zz+9.30892908077441974853E0; + agd = agd*zz+1.98352928718312140417E1; + agd = agd*zz+1.55646628932864612953E1; + agd = agd*zz+5.47686069422975497931E0; + agd = agd*zz+9.54293611618961883998E-1; + agd = agd*zz+8.64580826352392193095E-2; + agd = agd*zz+4.12656523824222607191E-3; + agd = agd*zz+1.01259085116509135510E-4; + agd = agd*zz+1.17166733214413521882E-6; + agd = agd*zz+4.91834570062930015649E-9; + ug = z*agn/agd; + theta = zeta+0.25*ae_pi; + f = ae_sin(theta, _state); + g = ae_cos(theta, _state); + *ai = k*(f*uf-g*ug); + *bi = k*(g*uf+f*ug); + apfn = 1.85365624022535566142E-1; + apfn = apfn*zz+8.86712188052584095637E-1; + apfn = apfn*zz+9.87391981747398547272E-1; + apfn = apfn*zz+4.01241082318003734092E-1; + apfn = apfn*zz+7.10304926289631174579E-2; + apfn = apfn*zz+5.90618657995661810071E-3; + apfn = apfn*zz+2.33051409401776799569E-4; + apfn = apfn*zz+4.08718778289035454598E-6; + apfn = apfn*zz+2.48379932900442457853E-8; + apfd = 1.00000000000000000000E0; + apfd = apfd*zz+1.47345854687502542552E1; + apfd = apfd*zz+3.75423933435489594466E1; + apfd = apfd*zz+3.14657751203046424330E1; + apfd = apfd*zz+1.09969125207298778536E1; + apfd = apfd*zz+1.78885054766999417817E0; + apfd = apfd*zz+1.41733275753662636873E-1; + apfd = apfd*zz+5.44066067017226003627E-3; + apfd = apfd*zz+9.39421290654511171663E-5; + apfd = apfd*zz+5.65978713036027009243E-7; + uf = 1.0+zz*apfn/apfd; + apgn = -3.55615429033082288335E-2; + apgn = apgn*zz-6.37311518129435504426E-1; + apgn = apgn*zz-1.70856738884312371053E0; + apgn = apgn*zz-1.50221872117316635393E0; + apgn = apgn*zz-5.63606665822102676611E-1; + apgn = apgn*zz-1.02101031120216891789E-1; + apgn = apgn*zz-9.48396695961445269093E-3; + apgn = apgn*zz-4.60325307486780994357E-4; + apgn = apgn*zz-1.14300836484517375919E-5; + apgn = apgn*zz-1.33415518685547420648E-7; + apgn = apgn*zz-5.63803833958893494476E-10; + apgd = 1.00000000000000000000E0; + apgd = apgd*zz+9.85865801696130355144E0; + apgd = apgd*zz+2.16401867356585941885E1; + apgd = apgd*zz+1.73130776389749389525E1; + apgd = apgd*zz+6.17872175280828766327E0; + apgd = apgd*zz+1.08848694396321495475E0; + apgd = apgd*zz+9.95005543440888479402E-2; + apgd = apgd*zz+4.78468199683886610842E-3; + apgd = apgd*zz+1.18159633322838625562E-4; + apgd = apgd*zz+1.37480673554219441465E-6; + apgd = apgd*zz+5.79912514929147598821E-9; + ug = z*apgn/apgd; + k = sqpii*t; + *aip = -k*(g*uf+f*ug); + *bip = k*(f*uf-g*ug); + return; + } + if( ae_fp_greater_eq(x,2.09) ) + { + domflg = 5; + t = ae_sqrt(x, _state); + zeta = 2.0*x*t/3.0; + g = ae_exp(zeta, _state); + t = ae_sqrt(t, _state); + k = 2.0*t*g; + z = 1.0/zeta; + an = 3.46538101525629032477E-1; + an = an*z+1.20075952739645805542E1; + an = an*z+7.62796053615234516538E1; + an = an*z+1.68089224934630576269E2; + an = an*z+1.59756391350164413639E2; + an = an*z+7.05360906840444183113E1; + an = an*z+1.40264691163389668864E1; + an = an*z+9.99999999999999995305E-1; + ad = 5.67594532638770212846E-1; + ad = ad*z+1.47562562584847203173E1; + ad = ad*z+8.45138970141474626562E1; + ad = ad*z+1.77318088145400459522E2; + ad = ad*z+1.64234692871529701831E2; + ad = ad*z+7.14778400825575695274E1; + ad = ad*z+1.40959135607834029598E1; + ad = ad*z+1.00000000000000000470E0; + f = an/ad; + *ai = sqpii*f/k; + k = -0.5*sqpii*t/g; + apn = 6.13759184814035759225E-1; + apn = apn*z+1.47454670787755323881E1; + apn = apn*z+8.20584123476060982430E1; + apn = apn*z+1.71184781360976385540E2; + apn = apn*z+1.59317847137141783523E2; + apn = apn*z+6.99778599330103016170E1; + apn = apn*z+1.39470856980481566958E1; + apn = apn*z+1.00000000000000000550E0; + apd = 3.34203677749736953049E-1; + apd = apd*z+1.11810297306158156705E1; + apd = apd*z+7.11727352147859965283E1; + apd = apd*z+1.58778084372838313640E2; + apd = apd*z+1.53206427475809220834E2; + apd = apd*z+6.86752304592780337944E1; + apd = apd*z+1.38498634758259442477E1; + apd = apd*z+9.99999999999999994502E-1; + f = apn/apd; + *aip = f*k; + if( ae_fp_greater(x,8.3203353) ) + { + bn16 = -2.53240795869364152689E-1; + bn16 = bn16*z+5.75285167332467384228E-1; + bn16 = bn16*z-3.29907036873225371650E-1; + bn16 = bn16*z+6.44404068948199951727E-2; + bn16 = bn16*z-3.82519546641336734394E-3; + bd16 = 1.00000000000000000000E0; + bd16 = bd16*z-7.15685095054035237902E0; + bd16 = bd16*z+1.06039580715664694291E1; + bd16 = bd16*z-5.23246636471251500874E0; + bd16 = bd16*z+9.57395864378383833152E-1; + bd16 = bd16*z-5.50828147163549611107E-2; + f = z*bn16/bd16; + k = sqpii*g; + *bi = k*(1.0+f)/t; + bppn = 4.65461162774651610328E-1; + bppn = bppn*z-1.08992173800493920734E0; + bppn = bppn*z+6.38800117371827987759E-1; + bppn = bppn*z-1.26844349553102907034E-1; + bppn = bppn*z+7.62487844342109852105E-3; + bppd = 1.00000000000000000000E0; + bppd = bppd*z-8.70622787633159124240E0; + bppd = bppd*z+1.38993162704553213172E1; + bppd = bppd*z-7.14116144616431159572E0; + bppd = bppd*z+1.34008595960680518666E0; + bppd = bppd*z-7.84273211323341930448E-2; + f = z*bppn/bppd; + *bip = k*t*(1.0+f); + return; + } + } + f = 1.0; + g = x; + t = 1.0; + uf = 1.0; + ug = x; + k = 1.0; + z = x*x*x; + while(ae_fp_greater(t,ae_machineepsilon)) + { + uf = uf*z; + k = k+1.0; + uf = uf/k; + ug = ug*z; + k = k+1.0; + ug = ug/k; + uf = uf/k; + f = f+uf; + k = k+1.0; + ug = ug/k; + g = g+ug; + t = ae_fabs(uf/f, _state); + } + uf = c1*f; + ug = c2*g; + if( domflg%2==0 ) + { + *ai = uf-ug; + } + if( domflg/2%2==0 ) + { + *bi = sqrt3*(uf+ug); + } + k = 4.0; + uf = x*x/2.0; + ug = z/3.0; + f = uf; + g = 1.0+ug; + uf = uf/3.0; + t = 1.0; + while(ae_fp_greater(t,ae_machineepsilon)) + { + uf = uf*z; + ug = ug/k; + k = k+1.0; + ug = ug*z; + uf = uf/k; + f = f+uf; + k = k+1.0; + ug = ug/k; + uf = uf/k; + g = g+ug; + k = k+1.0; + t = ae_fabs(ug/g, _state); + } + uf = c1*f; + ug = c2*g; + if( domflg/4%2==0 ) + { + *aip = uf-ug; + } + if( domflg/8%2==0 ) + { + *bip = sqrt3*(uf+ug); + } +} + + +#endif +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Dawson's Integral + +Approximates the integral + + x + - + 2 | | 2 + dawsn(x) = exp( -x ) | exp( t ) dt + | | + - + 0 + +Three different rational approximations are employed, for +the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,10 10000 6.9e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double dawsonintegral(double x, ae_state *_state) +{ + double x2; + double y; + ae_int_t sg; + double an; + double ad; + double bn; + double bd; + double cn; + double cd; + double result; + + + sg = 1; + if( ae_fp_less(x,(double)(0)) ) + { + sg = -1; + x = -x; + } + if( ae_fp_less(x,3.25) ) + { + x2 = x*x; + an = 1.13681498971755972054E-11; + an = an*x2+8.49262267667473811108E-10; + an = an*x2+1.94434204175553054283E-8; + an = an*x2+9.53151741254484363489E-7; + an = an*x2+3.07828309874913200438E-6; + an = an*x2+3.52513368520288738649E-4; + an = an*x2+(-8.50149846724410912031E-4); + an = an*x2+4.22618223005546594270E-2; + an = an*x2+(-9.17480371773452345351E-2); + an = an*x2+9.99999999999999994612E-1; + ad = 2.40372073066762605484E-11; + ad = ad*x2+1.48864681368493396752E-9; + ad = ad*x2+5.21265281010541664570E-8; + ad = ad*x2+1.27258478273186970203E-6; + ad = ad*x2+2.32490249820789513991E-5; + ad = ad*x2+3.25524741826057911661E-4; + ad = ad*x2+3.48805814657162590916E-3; + ad = ad*x2+2.79448531198828973716E-2; + ad = ad*x2+1.58874241960120565368E-1; + ad = ad*x2+5.74918629489320327824E-1; + ad = ad*x2+1.00000000000000000539E0; + y = x*an/ad; + result = (double)sg*y; + return result; + } + x2 = 1.0/(x*x); + if( ae_fp_less(x,6.25) ) + { + bn = 5.08955156417900903354E-1; + bn = bn*x2-2.44754418142697847934E-1; + bn = bn*x2+9.41512335303534411857E-2; + bn = bn*x2-2.18711255142039025206E-2; + bn = bn*x2+3.66207612329569181322E-3; + bn = bn*x2-4.23209114460388756528E-4; + bn = bn*x2+3.59641304793896631888E-5; + bn = bn*x2-2.14640351719968974225E-6; + bn = bn*x2+9.10010780076391431042E-8; + bn = bn*x2-2.40274520828250956942E-9; + bn = bn*x2+3.59233385440928410398E-11; + bd = 1.00000000000000000000E0; + bd = bd*x2-6.31839869873368190192E-1; + bd = bd*x2+2.36706788228248691528E-1; + bd = bd*x2-5.31806367003223277662E-2; + bd = bd*x2+8.48041718586295374409E-3; + bd = bd*x2-9.47996768486665330168E-4; + bd = bd*x2+7.81025592944552338085E-5; + bd = bd*x2-4.55875153252442634831E-6; + bd = bd*x2+1.89100358111421846170E-7; + bd = bd*x2-4.91324691331920606875E-9; + bd = bd*x2+7.18466403235734541950E-11; + y = 1.0/x+x2*bn/(bd*x); + result = (double)sg*0.5*y; + return result; + } + if( ae_fp_greater(x,1.0E9) ) + { + result = (double)sg*0.5/x; + return result; + } + cn = -5.90592860534773254987E-1; + cn = cn*x2+6.29235242724368800674E-1; + cn = cn*x2-1.72858975380388136411E-1; + cn = cn*x2+1.64837047825189632310E-2; + cn = cn*x2-4.86827613020462700845E-4; + cd = 1.00000000000000000000E0; + cd = cd*x2-2.69820057197544900361E0; + cd = cd*x2+1.73270799045947845857E0; + cd = cd*x2-3.93708582281939493482E-1; + cd = cd*x2+3.44278924041233391079E-2; + cd = cd*x2-9.73655226040941223894E-4; + y = 1.0/x+x2*cn/(cd*x); + result = (double)sg*0.5*y; + return result; +} + + +#endif +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Calculation of the value of the Hermite polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial Hn at x +*************************************************************************/ +double hermitecalculate(ae_int_t n, double x, ae_state *_state) +{ + ae_int_t i; + double a; + double b; + double result; + + + result = (double)(0); + + /* + * Prepare A and B + */ + a = (double)(1); + b = (double)2*x; + + /* + * Special cases: N=0 or N=1 + */ + if( n==0 ) + { + result = a; + return result; + } + if( n==1 ) + { + result = b; + return result; + } + + /* + * General case: N>=2 + */ + for(i=2; i<=n; i++) + { + result = (double)2*x*b-(double)(2*(i-1))*a; + a = b; + b = result; + } + return result; +} + + +/************************************************************************* +Summation of Hermite polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial at x +*************************************************************************/ +double hermitesum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state) +{ + double b1; + double b2; + ae_int_t i; + double result; + + + b1 = (double)(0); + b2 = (double)(0); + result = (double)(0); + for(i=n; i>=0; i--) + { + result = (double)2*(x*b1-(double)(i+1)*b2)+c->ptr.p_double[i]; + b2 = b1; + b1 = result; + } + return result; +} + + +/************************************************************************* +Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void hermitecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(c); + + ae_vector_set_length(c, n+1, _state); + for(i=0; i<=n; i++) + { + c->ptr.p_double[i] = (double)(0); + } + c->ptr.p_double[n] = ae_exp((double)n*ae_log((double)(2), _state), _state); + for(i=0; i<=n/2-1; i++) + { + c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(double)(n-2*i)*(double)(n-2*i-1)/(double)4/(double)(i+1); + } +} + + +#endif +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Calculation of the value of the Legendre polynomial Pn. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial Pn at x +*************************************************************************/ +double legendrecalculate(ae_int_t n, double x, ae_state *_state) +{ + double a; + double b; + ae_int_t i; + double result; + + + result = (double)(1); + a = (double)(1); + b = x; + if( n==0 ) + { + result = a; + return result; + } + if( n==1 ) + { + result = b; + return result; + } + for(i=2; i<=n; i++) + { + result = ((double)(2*i-1)*x*b-(double)(i-1)*a)/(double)i; + a = b; + b = result; + } + return result; +} + + +/************************************************************************* +Summation of Legendre polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial at x +*************************************************************************/ +double legendresum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state) +{ + double b1; + double b2; + ae_int_t i; + double result; + + + b1 = (double)(0); + b2 = (double)(0); + result = (double)(0); + for(i=n; i>=0; i--) + { + result = (double)(2*i+1)*x*b1/(double)(i+1)-(double)(i+1)*b2/(double)(i+2)+c->ptr.p_double[i]; + b2 = b1; + b1 = result; + } + return result; +} + + +/************************************************************************* +Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void legendrecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(c); + + ae_vector_set_length(c, n+1, _state); + for(i=0; i<=n; i++) + { + c->ptr.p_double[i] = (double)(0); + } + c->ptr.p_double[n] = (double)(1); + for(i=1; i<=n; i++) + { + c->ptr.p_double[n] = c->ptr.p_double[n]*(double)(n+i)/(double)2/(double)i; + } + for(i=0; i<=n/2-1; i++) + { + c->ptr.p_double[n-2*(i+1)] = -c->ptr.p_double[n-2*i]*(double)(n-2*i)*(double)(n-2*i-1)/(double)2/(double)(i+1)/(double)(2*(n-i)-1); + } +} + + +#endif +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Bessel function of order zero + +Returns Bessel function of order zero of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval the following rational +approximation is used: + + + 2 2 +(w - r ) (w - r ) P (w) / Q (w) + 1 2 3 8 + + 2 +where w = x and the two r's are zeros of the function. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 60000 4.2e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj0(double x, ae_state *_state) +{ + double xsq; + double nn; + double pzero; + double qzero; + double p1; + double q1; + double result; + + + if( ae_fp_less(x,(double)(0)) ) + { + x = -x; + } + if( ae_fp_greater(x,8.0) ) + { + bessel_besselasympt0(x, &pzero, &qzero, _state); + nn = x-ae_pi/(double)4; + result = ae_sqrt((double)2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); + return result; + } + xsq = ae_sqr(x, _state); + p1 = 26857.86856980014981415848441; + p1 = -40504123.71833132706360663322+xsq*p1; + p1 = 25071582855.36881945555156435+xsq*p1; + p1 = -8085222034853.793871199468171+xsq*p1; + p1 = 1434354939140344.111664316553+xsq*p1; + p1 = -136762035308817138.6865416609+xsq*p1; + p1 = 6382059341072356562.289432465+xsq*p1; + p1 = -117915762910761053603.8440800+xsq*p1; + p1 = 493378725179413356181.6813446+xsq*p1; + q1 = 1.0; + q1 = 1363.063652328970604442810507+xsq*q1; + q1 = 1114636.098462985378182402543+xsq*q1; + q1 = 669998767.2982239671814028660+xsq*q1; + q1 = 312304311494.1213172572469442+xsq*q1; + q1 = 112775673967979.8507056031594+xsq*q1; + q1 = 30246356167094626.98627330784+xsq*q1; + q1 = 5428918384092285160.200195092+xsq*q1; + q1 = 493378725179413356211.3278438+xsq*q1; + result = p1/q1; + return result; +} + + +/************************************************************************* +Bessel function of order one + +Returns Bessel function of order one of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 24 term Chebyshev +expansion is used. In the second, the asymptotic +trigonometric representation is employed using two +rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 2.6e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj1(double x, ae_state *_state) +{ + double s; + double xsq; + double nn; + double pzero; + double qzero; + double p1; + double q1; + double result; + + + s = (double)(ae_sign(x, _state)); + if( ae_fp_less(x,(double)(0)) ) + { + x = -x; + } + if( ae_fp_greater(x,8.0) ) + { + bessel_besselasympt1(x, &pzero, &qzero, _state); + nn = x-(double)3*ae_pi/(double)4; + result = ae_sqrt((double)2/ae_pi/x, _state)*(pzero*ae_cos(nn, _state)-qzero*ae_sin(nn, _state)); + if( ae_fp_less(s,(double)(0)) ) + { + result = -result; + } + return result; + } + xsq = ae_sqr(x, _state); + p1 = 2701.122710892323414856790990; + p1 = -4695753.530642995859767162166+xsq*p1; + p1 = 3413234182.301700539091292655+xsq*p1; + p1 = -1322983480332.126453125473247+xsq*p1; + p1 = 290879526383477.5409737601689+xsq*p1; + p1 = -35888175699101060.50743641413+xsq*p1; + p1 = 2316433580634002297.931815435+xsq*p1; + p1 = -66721065689249162980.20941484+xsq*p1; + p1 = 581199354001606143928.050809+xsq*p1; + q1 = 1.0; + q1 = 1606.931573481487801970916749+xsq*q1; + q1 = 1501793.594998585505921097578+xsq*q1; + q1 = 1013863514.358673989967045588+xsq*q1; + q1 = 524371026216.7649715406728642+xsq*q1; + q1 = 208166122130760.7351240184229+xsq*q1; + q1 = 60920613989175217.46105196863+xsq*q1; + q1 = 11857707121903209998.37113348+xsq*q1; + q1 = 1162398708003212287858.529400+xsq*q1; + result = s*x*p1/q1; + return result; +} + + +/************************************************************************* +Bessel function of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The ratio of jn(x) to j0(x) is computed by backward +recurrence. First the ratio jn/jn-1 is found by a +continued fraction expansion. Then the recurrence +relating successive orders is applied until j0 or j1 is +reached. + +If n = 0 or 1 the routine for j0 or j1 is called +directly. + +ACCURACY: + + Absolute error: +arithmetic range # trials peak rms + IEEE 0, 30 5000 4.4e-16 7.9e-17 + + +Not suitable for large n or x. Use jv() (fractional order) instead. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseljn(ae_int_t n, double x, ae_state *_state) +{ + double pkm2; + double pkm1; + double pk; + double xk; + double r; + double ans; + ae_int_t k; + ae_int_t sg; + double result; + + + if( n<0 ) + { + n = -n; + if( n%2==0 ) + { + sg = 1; + } + else + { + sg = -1; + } + } + else + { + sg = 1; + } + if( ae_fp_less(x,(double)(0)) ) + { + if( n%2!=0 ) + { + sg = -sg; + } + x = -x; + } + if( n==0 ) + { + result = (double)sg*besselj0(x, _state); + return result; + } + if( n==1 ) + { + result = (double)sg*besselj1(x, _state); + return result; + } + if( n==2 ) + { + if( ae_fp_eq(x,(double)(0)) ) + { + result = (double)(0); + } + else + { + result = (double)sg*(2.0*besselj1(x, _state)/x-besselj0(x, _state)); + } + return result; + } + if( ae_fp_less(x,ae_machineepsilon) ) + { + result = (double)(0); + return result; + } + k = 53; + pk = (double)(2*(n+k)); + ans = pk; + xk = x*x; + do + { + pk = pk-2.0; + ans = pk-xk/ans; + k = k-1; + } + while(k!=0); + ans = x/ans; + pk = 1.0; + pkm1 = 1.0/ans; + k = n-1; + r = (double)(2*k); + do + { + pkm2 = (pkm1*r-pk*x)/x; + pk = pkm1; + pkm1 = pkm2; + r = r-2.0; + k = k-1; + } + while(k!=0); + if( ae_fp_greater(ae_fabs(pk, _state),ae_fabs(pkm1, _state)) ) + { + ans = besselj1(x, _state)/pk; + } + else + { + ans = besselj0(x, _state)/pkm1; + } + result = (double)sg*ans; + return result; +} + + +/************************************************************************* +Bessel function of the second kind, order zero + +Returns Bessel function of the second kind, of order +zero, of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval a rational approximation +R(x) is employed to compute + y0(x) = R(x) + 2 * log(x) * j0(x) / PI. +Thus a call to j0() is required. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + + + +ACCURACY: + + Absolute error, when y0(x) < 1; else relative error: + +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.3e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely0(double x, ae_state *_state) +{ + double nn; + double xsq; + double pzero; + double qzero; + double p4; + double q4; + double result; + + + if( ae_fp_greater(x,8.0) ) + { + bessel_besselasympt0(x, &pzero, &qzero, _state); + nn = x-ae_pi/(double)4; + result = ae_sqrt((double)2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); + return result; + } + xsq = ae_sqr(x, _state); + p4 = -41370.35497933148554125235152; + p4 = 59152134.65686889654273830069+xsq*p4; + p4 = -34363712229.79040378171030138+xsq*p4; + p4 = 10255208596863.94284509167421+xsq*p4; + p4 = -1648605817185729.473122082537+xsq*p4; + p4 = 137562431639934407.8571335453+xsq*p4; + p4 = -5247065581112764941.297350814+xsq*p4; + p4 = 65874732757195549259.99402049+xsq*p4; + p4 = -27502866786291095837.01933175+xsq*p4; + q4 = 1.0; + q4 = 1282.452772478993804176329391+xsq*q4; + q4 = 1001702.641288906265666651753+xsq*q4; + q4 = 579512264.0700729537480087915+xsq*q4; + q4 = 261306575504.1081249568482092+xsq*q4; + q4 = 91620380340751.85262489147968+xsq*q4; + q4 = 23928830434997818.57439356652+xsq*q4; + q4 = 4192417043410839973.904769661+xsq*q4; + q4 = 372645883898616588198.9980+xsq*q4; + result = p4/q4+(double)2/ae_pi*besselj0(x, _state)*ae_log(x, _state); + return result; +} + + +/************************************************************************* +Bessel function of second kind of order one + +Returns Bessel function of the second kind of order one +of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 25 term Chebyshev +expansion is used, and a call to j1() is required. +In the second, the asymptotic trigonometric representation +is employed using two rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.0e-15 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely1(double x, ae_state *_state) +{ + double nn; + double xsq; + double pzero; + double qzero; + double p4; + double q4; + double result; + + + if( ae_fp_greater(x,8.0) ) + { + bessel_besselasympt1(x, &pzero, &qzero, _state); + nn = x-(double)3*ae_pi/(double)4; + result = ae_sqrt((double)2/ae_pi/x, _state)*(pzero*ae_sin(nn, _state)+qzero*ae_cos(nn, _state)); + return result; + } + xsq = ae_sqr(x, _state); + p4 = -2108847.540133123652824139923; + p4 = 3639488548.124002058278999428+xsq*p4; + p4 = -2580681702194.450950541426399+xsq*p4; + p4 = 956993023992168.3481121552788+xsq*p4; + p4 = -196588746272214065.8820322248+xsq*p4; + p4 = 21931073399177975921.11427556+xsq*p4; + p4 = -1212297555414509577913.561535+xsq*p4; + p4 = 26554738314348543268942.48968+xsq*p4; + p4 = -99637534243069222259967.44354+xsq*p4; + q4 = 1.0; + q4 = 1612.361029677000859332072312+xsq*q4; + q4 = 1563282.754899580604737366452+xsq*q4; + q4 = 1128686837.169442121732366891+xsq*q4; + q4 = 646534088126.5275571961681500+xsq*q4; + q4 = 297663212564727.6729292742282+xsq*q4; + q4 = 108225825940881955.2553850180+xsq*q4; + q4 = 29549879358971486742.90758119+xsq*q4; + q4 = 5435310377188854170800.653097+xsq*q4; + q4 = 508206736694124324531442.4152+xsq*q4; + result = x*p4/q4+(double)2/ae_pi*(besselj1(x, _state)*ae_log(x, _state)-(double)1/x); + return result; +} + + +/************************************************************************* +Bessel function of second kind of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The function is evaluated by forward recurrence on +n, starting with values computed by the routines +y0() and y1(). + +If n = 0 or 1 the routine for y0 or y1 is called +directly. + +ACCURACY: + Absolute error, except relative + when y > 1: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 3.4e-15 4.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselyn(ae_int_t n, double x, ae_state *_state) +{ + ae_int_t i; + double a; + double b; + double tmp; + double s; + double result; + + + s = (double)(1); + if( n<0 ) + { + n = -n; + if( n%2!=0 ) + { + s = (double)(-1); + } + } + if( n==0 ) + { + result = bessely0(x, _state); + return result; + } + if( n==1 ) + { + result = s*bessely1(x, _state); + return result; + } + a = bessely0(x, _state); + b = bessely1(x, _state); + for(i=1; i<=n-1; i++) + { + tmp = b; + b = (double)(2*i)/x*b-a; + a = tmp; + } + result = s*b; + return result; +} + + +/************************************************************************* +Modified Bessel function of order zero + +Returns modified Bessel function of order zero of the +argument. + +The function is defined as i0(x) = j0( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 5.8e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli0(double x, ae_state *_state) +{ + double y; + double v; + double z; + double b0; + double b1; + double b2; + double result; + + + if( ae_fp_less(x,(double)(0)) ) + { + x = -x; + } + if( ae_fp_less_eq(x,8.0) ) + { + y = x/2.0-2.0; + bessel_besselmfirstcheb(-4.41534164647933937950E-18, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 3.33079451882223809783E-17, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -2.43127984654795469359E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.71539128555513303061E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -1.16853328779934516808E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 7.67618549860493561688E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -4.85644678311192946090E-13, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 2.95505266312963983461E-12, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -1.72682629144155570723E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 9.67580903537323691224E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -5.18979560163526290666E-10, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 2.65982372468238665035E-9, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -1.30002500998624804212E-8, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 6.04699502254191894932E-8, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -2.67079385394061173391E-7, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.11738753912010371815E-6, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -4.41673835845875056359E-6, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.64484480707288970893E-5, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -5.75419501008210370398E-5, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.88502885095841655729E-4, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -5.76375574538582365885E-4, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.63947561694133579842E-3, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -4.32430999505057594430E-3, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.05464603945949983183E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -2.37374148058994688156E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 4.93052842396707084878E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -9.49010970480476444210E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.71620901522208775349E-1, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -3.04682672343198398683E-1, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 6.76795274409476084995E-1, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + result = ae_exp(x, _state)*v; + return result; + } + z = 32.0/x-2.0; + bessel_besselmfirstcheb(-7.23318048787475395456E-18, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -4.83050448594418207126E-18, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 4.46562142029675999901E-17, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.46122286769746109310E-17, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -2.82762398051658348494E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -3.42548561967721913462E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.77256013305652638360E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.81168066935262242075E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -9.55484669882830764870E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -4.15056934728722208663E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.54008621752140982691E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.85277838274214270114E-13, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 7.18012445138366623367E-13, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.79417853150680611778E-12, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.32158118404477131188E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -3.14991652796324136454E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.18891471078464383424E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 4.94060238822496958910E-10, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.39623202570838634515E-9, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 2.26666899049817806459E-8, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 2.04891858946906374183E-7, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 2.89137052083475648297E-6, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 6.88975834691682398426E-5, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.36911647825569408990E-3, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 8.04490411014108831608E-1, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + result = ae_exp(x, _state)*v/ae_sqrt(x, _state); + return result; +} + + +/************************************************************************* +Modified Bessel function of order one + +Returns modified Bessel function of order one of the +argument. + +The function is defined as i1(x) = -i j1( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.9e-15 2.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli1(double x, ae_state *_state) +{ + double y; + double z; + double v; + double b0; + double b1; + double b2; + double result; + + + z = ae_fabs(x, _state); + if( ae_fp_less_eq(z,8.0) ) + { + y = z/2.0-2.0; + bessel_besselm1firstcheb(2.77791411276104639959E-18, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.11142121435816608115E-17, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.55363195773620046921E-16, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.10559694773538630805E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 7.60068429473540693410E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -5.04218550472791168711E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.22379336594557470981E-13, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.98397439776494371520E-12, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.17361862988909016308E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -6.66348972350202774223E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.62559028155211703701E-10, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.88724975172282928790E-9, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 9.38153738649577178388E-9, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -4.44505912879632808065E-8, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.00329475355213526229E-7, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -8.56872026469545474066E-7, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.47025130813767847674E-6, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.32731636560394358279E-5, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 4.78156510755005422638E-5, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.61760815825896745588E-4, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 5.12285956168575772895E-4, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.51357245063125314899E-3, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 4.15642294431288815669E-3, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.05640848946261981558E-2, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.47264490306265168283E-2, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -5.29459812080949914269E-2, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.02643658689847095384E-1, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.76416518357834055153E-1, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.52587186443633654823E-1, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + z = v*z*ae_exp(z, _state); + } + else + { + y = 32.0/z-2.0; + bessel_besselm1firstcheb(7.51729631084210481353E-18, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 4.41434832307170791151E-18, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -4.65030536848935832153E-17, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.20952592199342395980E-17, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.96262899764595013876E-16, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.30820231092092828324E-16, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.88035477551078244854E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.81440307243700780478E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.04202769841288027642E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 4.27244001671195135429E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.10154184277266431302E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -4.08355111109219731823E-13, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -7.19855177624590851209E-13, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.03562854414708950722E-12, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.41258074366137813316E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.25260358301548823856E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.89749581235054123450E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -5.58974346219658380687E-10, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.83538038596423702205E-9, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.63146884688951950684E-8, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.51223623787020892529E-7, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.88256480887769039346E-6, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.10588938762623716291E-4, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -9.76109749136146840777E-3, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 7.78576235018280120474E-1, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + z = v*ae_exp(z, _state)/ae_sqrt(z, _state); + } + if( ae_fp_less(x,(double)(0)) ) + { + z = -z; + } + result = z; + return result; +} + + +/************************************************************************* +Modified Bessel function, second kind, order zero + +Returns modified Bessel function of the second kind +of order zero of the argument. + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + +Tested at 2000 random points between 0 and 8. Peak absolute +error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk0(double x, ae_state *_state) +{ + double y; + double z; + double v; + double b0; + double b1; + double b2; + double result; + + + ae_assert(ae_fp_greater(x,(double)(0)), "Domain error in BesselK0: x<=0", _state); + if( ae_fp_less_eq(x,(double)(2)) ) + { + y = x*x-2.0; + bessel_besselmfirstcheb(1.37446543561352307156E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 4.25981614279661018399E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.03496952576338420167E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.90451637722020886025E-9, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 2.53479107902614945675E-7, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 2.28621210311945178607E-5, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 1.26461541144692592338E-3, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 3.59799365153615016266E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, 3.44289899924628486886E-1, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(y, -5.35327393233902768720E-1, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + v = v-ae_log(0.5*x, _state)*besseli0(x, _state); + } + else + { + z = 8.0/x-2.0; + bessel_besselmfirstcheb(5.30043377268626276149E-18, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.64758043015242134646E-17, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 5.21039150503902756861E-17, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.67823109680541210385E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 5.51205597852431940784E-16, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.84859337734377901440E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 6.34007647740507060557E-15, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -2.22751332699166985548E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 8.03289077536357521100E-14, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -2.98009692317273043925E-13, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.14034058820847496303E-12, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -4.51459788337394416547E-12, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.85594911495471785253E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -7.95748924447710747776E-11, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 3.57739728140030116597E-10, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.69753450938905987466E-9, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 8.57403401741422608519E-9, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -4.66048989768794782956E-8, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 2.76681363944501510342E-7, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.83175552271911948767E-6, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.39498137188764993662E-5, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -1.28495495816278026384E-4, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 1.56988388573005337491E-3, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, -3.14481013119645005427E-2, &b0, &b1, &b2, _state); + bessel_besselmnextcheb(z, 2.44030308206595545468E0, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + v = v*ae_exp(-x, _state)/ae_sqrt(x, _state); + } + result = v; + return result; +} + + +/************************************************************************* +Modified Bessel function, second kind, order one + +Computes the modified Bessel function of the second kind +of order one of the argument. + +The range is partitioned into the two intervals [0,2] and +(2, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk1(double x, ae_state *_state) +{ + double y; + double z; + double v; + double b0; + double b1; + double b2; + double result; + + + z = 0.5*x; + ae_assert(ae_fp_greater(z,(double)(0)), "Domain error in K1", _state); + if( ae_fp_less_eq(x,(double)(2)) ) + { + y = x*x-2.0; + bessel_besselm1firstcheb(-7.02386347938628759343E-18, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.42744985051936593393E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -6.66690169419932900609E-13, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.41148839263352776110E-10, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.21338763073472585583E-8, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.43340614156596823496E-6, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.73028895751305206302E-4, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -6.97572385963986435018E-3, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.22611180822657148235E-1, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.53155960776544875667E-1, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.52530022733894777053E0, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + result = ae_log(z, _state)*besseli1(x, _state)+v/x; + } + else + { + y = 8.0/x-2.0; + bessel_besselm1firstcheb(-5.75674448366501715755E-18, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.79405087314755922667E-17, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -5.68946255844285935196E-17, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.83809354436663880070E-16, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -6.05704724837331885336E-16, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.03870316562433424052E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -7.01983709041831346144E-15, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.47715442448130437068E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -8.97670518232499435011E-14, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 3.34841966607842919884E-13, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.28917396095102890680E-12, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 5.13963967348173025100E-12, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.12996783842756842877E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 9.21831518760500529508E-11, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -4.19035475934189648750E-10, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.01504975519703286596E-9, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.03457624656780970260E-8, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 5.74108412545004946722E-8, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -3.50196060308781257119E-7, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.40648494783721712015E-6, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -1.93619797416608296024E-5, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.95215518471351631108E-4, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, -2.85781685962277938680E-3, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 1.03923736576817238437E-1, &b0, &b1, &b2, _state); + bessel_besselm1nextcheb(y, 2.72062619048444266945E0, &b0, &b1, &b2, _state); + v = 0.5*(b0-b2); + result = ae_exp(-x, _state)*v/ae_sqrt(x, _state); + } + return result; +} + + +/************************************************************************* +Modified Bessel function, second kind, integer order + +Returns modified Bessel function of the second kind +of order n of the argument. + +The range is partitioned into the two intervals [0,9.55] and +(9.55, infinity). An ascending power series is used in the +low range, and an asymptotic expansion in the high range. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 90000 1.8e-8 3.0e-10 + +Error is high only near the crossover point x = 9.55 +between the two expansions used. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselkn(ae_int_t nn, double x, ae_state *_state) +{ + double k; + double kf; + double nk1f; + double nkf; + double zn; + double t; + double s; + double z0; + double z; + double ans; + double fn; + double pn; + double pk; + double zmn; + double tlg; + double tox; + ae_int_t i; + ae_int_t n; + double eul; + double result; + + + eul = 5.772156649015328606065e-1; + if( nn<0 ) + { + n = -nn; + } + else + { + n = nn; + } + ae_assert(n<=31, "Overflow in BesselKN", _state); + ae_assert(ae_fp_greater(x,(double)(0)), "Domain error in BesselKN", _state); + if( ae_fp_less_eq(x,9.55) ) + { + ans = 0.0; + z0 = 0.25*x*x; + fn = 1.0; + pn = 0.0; + zmn = 1.0; + tox = 2.0/x; + if( n>0 ) + { + pn = -eul; + k = 1.0; + for(i=1; i<=n-1; i++) + { + pn = pn+1.0/k; + k = k+1.0; + fn = fn*k; + } + zmn = tox; + if( n==1 ) + { + ans = 1.0/x; + } + else + { + nk1f = fn/(double)n; + kf = 1.0; + s = nk1f; + z = -z0; + zn = 1.0; + for(i=1; i<=n-1; i++) + { + nk1f = nk1f/(double)(n-i); + kf = kf*(double)i; + zn = zn*z; + t = nk1f*zn/kf; + s = s+t; + ae_assert(ae_fp_greater(ae_maxrealnumber-ae_fabs(t, _state),ae_fabs(s, _state)), "Overflow in BesselKN", _state); + ae_assert(!(ae_fp_greater(tox,1.0)&&ae_fp_less(ae_maxrealnumber/tox,zmn)), "Overflow in BesselKN", _state); + zmn = zmn*tox; + } + s = s*0.5; + t = ae_fabs(s, _state); + ae_assert(!(ae_fp_greater(zmn,1.0)&&ae_fp_less(ae_maxrealnumber/zmn,t)), "Overflow in BesselKN", _state); + ae_assert(!(ae_fp_greater(t,1.0)&&ae_fp_less(ae_maxrealnumber/t,zmn)), "Overflow in BesselKN", _state); + ans = s*zmn; + } + } + tlg = 2.0*ae_log(0.5*x, _state); + pk = -eul; + if( n==0 ) + { + pn = pk; + t = 1.0; + } + else + { + pn = pn+1.0/(double)n; + t = 1.0/fn; + } + s = (pk+pn-tlg)*t; + k = 1.0; + do + { + t = t*(z0/(k*(k+(double)n))); + pk = pk+1.0/k; + pn = pn+1.0/(k+(double)n); + s = s+(pk+pn-tlg)*t; + k = k+1.0; + } + while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); + s = 0.5*s/zmn; + if( n%2!=0 ) + { + s = -s; + } + ans = ans+s; + result = ans; + return result; + } + if( ae_fp_greater(x,ae_log(ae_maxrealnumber, _state)) ) + { + result = (double)(0); + return result; + } + k = (double)(n); + pn = 4.0*k*k; + pk = 1.0; + z0 = 8.0*x; + fn = 1.0; + t = 1.0; + s = t; + nkf = ae_maxrealnumber; + i = 0; + do + { + z = pn-pk*pk; + t = t*z/(fn*z0); + nk1f = ae_fabs(t, _state); + if( i>=n&&ae_fp_greater(nk1f,nkf) ) + { + break; + } + nkf = nk1f; + s = s+t; + fn = fn+1.0; + pk = pk+2.0; + i = i+1; + } + while(ae_fp_greater(ae_fabs(t/s, _state),ae_machineepsilon)); + result = ae_exp(-x, _state)*ae_sqrt(ae_pi/(2.0*x), _state)*s; + return result; +} + + +/************************************************************************* +Internal subroutine + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +static void bessel_besselmfirstcheb(double c, + double* b0, + double* b1, + double* b2, + ae_state *_state) +{ + + + *b0 = c; + *b1 = 0.0; + *b2 = 0.0; +} + + +/************************************************************************* +Internal subroutine + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +static void bessel_besselmnextcheb(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state) +{ + + + *b2 = *b1; + *b1 = *b0; + *b0 = x*(*b1)-(*b2)+c; +} + + +/************************************************************************* +Internal subroutine + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +static void bessel_besselm1firstcheb(double c, + double* b0, + double* b1, + double* b2, + ae_state *_state) +{ + + + *b0 = c; + *b1 = 0.0; + *b2 = 0.0; +} + + +/************************************************************************* +Internal subroutine + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +static void bessel_besselm1nextcheb(double x, + double c, + double* b0, + double* b1, + double* b2, + ae_state *_state) +{ + + + *b2 = *b1; + *b1 = *b0; + *b0 = x*(*b1)-(*b2)+c; +} + + +static void bessel_besselasympt0(double x, + double* pzero, + double* qzero, + ae_state *_state) +{ + double xsq; + double p2; + double q2; + double p3; + double q3; + + *pzero = 0.0; + *qzero = 0.0; + + xsq = 64.0/(x*x); + p2 = 0.0; + p2 = 2485.271928957404011288128951+xsq*p2; + p2 = 153982.6532623911470917825993+xsq*p2; + p2 = 2016135.283049983642487182349+xsq*p2; + p2 = 8413041.456550439208464315611+xsq*p2; + p2 = 12332384.76817638145232406055+xsq*p2; + p2 = 5393485.083869438325262122897+xsq*p2; + q2 = 1.0; + q2 = 2615.700736920839685159081813+xsq*q2; + q2 = 156001.7276940030940592769933+xsq*q2; + q2 = 2025066.801570134013891035236+xsq*q2; + q2 = 8426449.050629797331554404810+xsq*q2; + q2 = 12338310.22786324960844856182+xsq*q2; + q2 = 5393485.083869438325560444960+xsq*q2; + p3 = -0.0; + p3 = -4.887199395841261531199129300+xsq*p3; + p3 = -226.2630641933704113967255053+xsq*p3; + p3 = -2365.956170779108192723612816+xsq*p3; + p3 = -8239.066313485606568803548860+xsq*p3; + p3 = -10381.41698748464093880530341+xsq*p3; + p3 = -3984.617357595222463506790588+xsq*p3; + q3 = 1.0; + q3 = 408.7714673983499223402830260+xsq*q3; + q3 = 15704.89191515395519392882766+xsq*q3; + q3 = 156021.3206679291652539287109+xsq*q3; + q3 = 533291.3634216897168722255057+xsq*q3; + q3 = 666745.4239319826986004038103+xsq*q3; + q3 = 255015.5108860942382983170882+xsq*q3; + *pzero = p2/q2; + *qzero = (double)8*p3/q3/x; +} + + +static void bessel_besselasympt1(double x, + double* pzero, + double* qzero, + ae_state *_state) +{ + double xsq; + double p2; + double q2; + double p3; + double q3; + + *pzero = 0.0; + *qzero = 0.0; + + xsq = 64.0/(x*x); + p2 = -1611.616644324610116477412898; + p2 = -109824.0554345934672737413139+xsq*p2; + p2 = -1523529.351181137383255105722+xsq*p2; + p2 = -6603373.248364939109255245434+xsq*p2; + p2 = -9942246.505077641195658377899+xsq*p2; + p2 = -4435757.816794127857114720794+xsq*p2; + q2 = 1.0; + q2 = -1455.009440190496182453565068+xsq*q2; + q2 = -107263.8599110382011903063867+xsq*q2; + q2 = -1511809.506634160881644546358+xsq*q2; + q2 = -6585339.479723087072826915069+xsq*q2; + q2 = -9934124.389934585658967556309+xsq*q2; + q2 = -4435757.816794127856828016962+xsq*q2; + p3 = 35.26513384663603218592175580; + p3 = 1706.375429020768002061283546+xsq*p3; + p3 = 18494.26287322386679652009819+xsq*p3; + p3 = 66178.83658127083517939992166+xsq*p3; + p3 = 85145.16067533570196555001171+xsq*p3; + p3 = 33220.91340985722351859704442+xsq*p3; + q3 = 1.0; + q3 = 863.8367769604990967475517183+xsq*q3; + q3 = 37890.22974577220264142952256+xsq*q3; + q3 = 400294.4358226697511708610813+xsq*q3; + q3 = 1419460.669603720892855755253+xsq*q3; + q3 = 1819458.042243997298924553839+xsq*q3; + q3 = 708712.8194102874357377502472+xsq*q3; + *pzero = p2/q2; + *qzero = (double)8*p3/q3/x; +} + + +#endif +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Calculation of the value of the Laguerre polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial Ln at x +*************************************************************************/ +double laguerrecalculate(ae_int_t n, double x, ae_state *_state) +{ + double a; + double b; + double i; + double result; + + + result = (double)(1); + a = (double)(1); + b = (double)1-x; + if( n==1 ) + { + result = b; + } + i = (double)(2); + while(ae_fp_less_eq(i,(double)(n))) + { + result = (((double)2*i-(double)1-x)*b-(i-(double)1)*a)/i; + a = b; + b = result; + i = i+(double)1; + } + return result; +} + + +/************************************************************************* +Summation of Laguerre polynomials using Clenshaw's recurrence formula. + +This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial at x +*************************************************************************/ +double laguerresum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state) +{ + double b1; + double b2; + ae_int_t i; + double result; + + + b1 = (double)(0); + b2 = (double)(0); + result = (double)(0); + for(i=n; i>=0; i--) + { + result = ((double)(2*i+1)-x)*b1/(double)(i+1)-(double)(i+1)*b2/(double)(i+2)+c->ptr.p_double[i]; + b2 = b1; + b1 = result; + } + return result; +} + + +/************************************************************************* +Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void laguerrecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state) +{ + ae_int_t i; + + ae_vector_clear(c); + + ae_vector_set_length(c, n+1, _state); + c->ptr.p_double[0] = (double)(1); + for(i=0; i<=n-1; i++) + { + c->ptr.p_double[i+1] = -c->ptr.p_double[i]*(double)(n-i)/(double)(i+1)/(double)(i+1); + } +} + + +#endif +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +using the approximation + + P(x) - log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralk(double m, ae_state *_state) +{ + double result; + + + result = ellipticintegralkhighprecision(1.0-m, _state); + return result; +} + + +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +where m = 1 - m1, using the approximation + + P(x) - log x Q(x). + +The argument m1 is used rather than m so that the logarithmic +singularity at m = 1 will be shifted to the origin; this +preserves maximum accuracy. + +K(0) = pi/2. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralkhighprecision(double m1, ae_state *_state) +{ + double p; + double q; + double result; + + + if( ae_fp_less_eq(m1,ae_machineepsilon) ) + { + result = 1.3862943611198906188E0-0.5*ae_log(m1, _state); + } + else + { + p = 1.37982864606273237150E-4; + p = p*m1+2.28025724005875567385E-3; + p = p*m1+7.97404013220415179367E-3; + p = p*m1+9.85821379021226008714E-3; + p = p*m1+6.87489687449949877925E-3; + p = p*m1+6.18901033637687613229E-3; + p = p*m1+8.79078273952743772254E-3; + p = p*m1+1.49380448916805252718E-2; + p = p*m1+3.08851465246711995998E-2; + p = p*m1+9.65735902811690126535E-2; + p = p*m1+1.38629436111989062502E0; + q = 2.94078955048598507511E-5; + q = q*m1+9.14184723865917226571E-4; + q = q*m1+5.94058303753167793257E-3; + q = q*m1+1.54850516649762399335E-2; + q = q*m1+2.39089602715924892727E-2; + q = q*m1+3.01204715227604046988E-2; + q = q*m1+3.73774314173823228969E-2; + q = q*m1+4.88280347570998239232E-2; + q = q*m1+7.03124996963957469739E-2; + q = q*m1+1.24999999999870820058E-1; + q = q*m1+4.99999999999999999821E-1; + result = p-q*ae_log(m1, _state); + } + return result; +} + + +/************************************************************************* +Incomplete elliptic integral of the first kind F(phi|m) + +Approximates the integral + + + + phi + - + | | + | dt +F(phi_\m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + + + + +ACCURACY: + +Tested at random points with m in [0, 1] and phi as indicated. + + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 200000 7.4e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegralk(double phi, double m, ae_state *_state) +{ + double a; + double b; + double c; + double e; + double temp; + double pio2; + double t; + double k; + ae_int_t d; + ae_int_t md; + ae_int_t s; + ae_int_t npio2; + double result; + + + pio2 = 1.57079632679489661923; + if( ae_fp_eq(m,(double)(0)) ) + { + result = phi; + return result; + } + a = (double)1-m; + if( ae_fp_eq(a,(double)(0)) ) + { + result = ae_log(ae_tan(0.5*(pio2+phi), _state), _state); + return result; + } + npio2 = ae_ifloor(phi/pio2, _state); + if( npio2%2!=0 ) + { + npio2 = npio2+1; + } + if( npio2!=0 ) + { + k = ellipticintegralk((double)1-a, _state); + phi = phi-(double)npio2*pio2; + } + else + { + k = (double)(0); + } + if( ae_fp_less(phi,(double)(0)) ) + { + phi = -phi; + s = -1; + } + else + { + s = 0; + } + b = ae_sqrt(a, _state); + t = ae_tan(phi, _state); + if( ae_fp_greater(ae_fabs(t, _state),(double)(10)) ) + { + e = 1.0/(b*t); + if( ae_fp_less(ae_fabs(e, _state),(double)(10)) ) + { + e = ae_atan(e, _state); + if( npio2==0 ) + { + k = ellipticintegralk((double)1-a, _state); + } + temp = k-incompleteellipticintegralk(e, m, _state); + if( s<0 ) + { + temp = -temp; + } + result = temp+(double)npio2*k; + return result; + } + } + a = 1.0; + c = ae_sqrt(m, _state); + d = 1; + md = 0; + while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) + { + temp = b/a; + phi = phi+ae_atan(t*temp, _state)+(double)md*ae_pi; + md = ae_trunc((phi+pio2)/ae_pi, _state); + t = t*(1.0+temp)/(1.0-temp*t*t); + c = 0.5*(a-b); + temp = ae_sqrt(a*b, _state); + a = 0.5*(a+b); + b = temp; + d = d+d; + } + temp = (ae_atan(t, _state)+(double)md*ae_pi)/((double)d*a); + if( s<0 ) + { + temp = -temp; + } + result = temp+(double)npio2*k; + return result; +} + + +/************************************************************************* +Complete elliptic integral of the second kind + +Approximates the integral + + + pi/2 + - + | | 2 +E(m) = | sqrt( 1 - m sin t ) dt + | | + - + 0 + +using the approximation + + P(x) - x log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 1 10000 2.1e-16 7.3e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegrale(double m, ae_state *_state) +{ + double p; + double q; + double result; + + + ae_assert(ae_fp_greater_eq(m,(double)(0))&&ae_fp_less_eq(m,(double)(1)), "Domain error in EllipticIntegralE: m<0 or m>1", _state); + m = (double)1-m; + if( ae_fp_eq(m,(double)(0)) ) + { + result = (double)(1); + return result; + } + p = 1.53552577301013293365E-4; + p = p*m+2.50888492163602060990E-3; + p = p*m+8.68786816565889628429E-3; + p = p*m+1.07350949056076193403E-2; + p = p*m+7.77395492516787092951E-3; + p = p*m+7.58395289413514708519E-3; + p = p*m+1.15688436810574127319E-2; + p = p*m+2.18317996015557253103E-2; + p = p*m+5.68051945617860553470E-2; + p = p*m+4.43147180560990850618E-1; + p = p*m+1.00000000000000000299E0; + q = 3.27954898576485872656E-5; + q = q*m+1.00962792679356715133E-3; + q = q*m+6.50609489976927491433E-3; + q = q*m+1.68862163993311317300E-2; + q = q*m+2.61769742454493659583E-2; + q = q*m+3.34833904888224918614E-2; + q = q*m+4.27180926518931511717E-2; + q = q*m+5.85936634471101055642E-2; + q = q*m+9.37499997197644278445E-2; + q = q*m+2.49999999999888314361E-1; + result = p-q*m*ae_log(m, _state); + return result; +} + + +/************************************************************************* +Incomplete elliptic integral of the second kind + +Approximates the integral + + + phi + - + | | + | 2 +E(phi_\m) = | sqrt( 1 - m sin t ) dt + | + | | + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + +ACCURACY: + +Tested at random arguments with phi in [-10, 10] and m in +[0, 1]. + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 150000 3.3e-15 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegrale(double phi, double m, ae_state *_state) +{ + double pio2; + double a; + double b; + double c; + double e; + double temp; + double lphi; + double t; + double ebig; + ae_int_t d; + ae_int_t md; + ae_int_t npio2; + ae_int_t s; + double result; + + + pio2 = 1.57079632679489661923; + if( ae_fp_eq(m,(double)(0)) ) + { + result = phi; + return result; + } + lphi = phi; + npio2 = ae_ifloor(lphi/pio2, _state); + if( npio2%2!=0 ) + { + npio2 = npio2+1; + } + lphi = lphi-(double)npio2*pio2; + if( ae_fp_less(lphi,(double)(0)) ) + { + lphi = -lphi; + s = -1; + } + else + { + s = 1; + } + a = 1.0-m; + ebig = ellipticintegrale(m, _state); + if( ae_fp_eq(a,(double)(0)) ) + { + temp = ae_sin(lphi, _state); + if( s<0 ) + { + temp = -temp; + } + result = temp+(double)npio2*ebig; + return result; + } + t = ae_tan(lphi, _state); + b = ae_sqrt(a, _state); + + /* + * Thanks to Brian Fitzgerald + * for pointing out an instability near odd multiples of pi/2 + */ + if( ae_fp_greater(ae_fabs(t, _state),(double)(10)) ) + { + + /* + * Transform the amplitude + */ + e = 1.0/(b*t); + + /* + * ... but avoid multiple recursions. + */ + if( ae_fp_less(ae_fabs(e, _state),(double)(10)) ) + { + e = ae_atan(e, _state); + temp = ebig+m*ae_sin(lphi, _state)*ae_sin(e, _state)-incompleteellipticintegrale(e, m, _state); + if( s<0 ) + { + temp = -temp; + } + result = temp+(double)npio2*ebig; + return result; + } + } + c = ae_sqrt(m, _state); + a = 1.0; + d = 1; + e = 0.0; + md = 0; + while(ae_fp_greater(ae_fabs(c/a, _state),ae_machineepsilon)) + { + temp = b/a; + lphi = lphi+ae_atan(t*temp, _state)+(double)md*ae_pi; + md = ae_trunc((lphi+pio2)/ae_pi, _state); + t = t*(1.0+temp)/(1.0-temp*t*t); + c = 0.5*(a-b); + temp = ae_sqrt(a*b, _state); + a = 0.5*(a+b); + b = temp; + d = d+d; + e = e+c*ae_sin(lphi, _state); + } + temp = ebig/ellipticintegralk(m, _state); + temp = temp*((ae_atan(t, _state)+(double)md*ae_pi)/((double)d*a)); + temp = temp+e; + if( s<0 ) + { + temp = -temp; + } + result = temp+(double)npio2*ebig; + return result; +} + + +#endif + +} + diff --git a/core/alglib/specialfunctions.h b/core/alglib/specialfunctions.h index f09393bd..3fe2c519 100644 --- a/core/alglib/specialfunctions.h +++ b/core/alglib/specialfunctions.h @@ -1,1976 +1,2305 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _specialfunctions_pkg_h -#define _specialfunctions_pkg_h -#include "ap.h" -#include "alglibinternal.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Gamma function - -Input parameters: - X - argument - -Domain: - 0 < X < 171.6 - -170 < X < 0, X is not an integer. - -Relative error: - arithmetic domain # trials peak rms - IEEE -170,-33 20000 2.3e-15 3.3e-16 - IEEE -33, 33 20000 9.4e-16 2.2e-16 - IEEE 33, 171.6 20000 2.3e-15 3.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double gammafunction(const double x); - - -/************************************************************************* -Natural logarithm of gamma function - -Input parameters: - X - argument - -Result: - logarithm of the absolute value of the Gamma(X). - -Output parameters: - SgnGam - sign(Gamma(X)) - -Domain: - 0 < X < 2.55e305 - -2.55e305 < X < 0, X is not an integer. - -ACCURACY: -arithmetic domain # trials peak rms - IEEE 0, 3 28000 5.4e-16 1.1e-16 - IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 -The error criterion was relative when the function magnitude -was greater than one but absolute when it was less than one. - -The following test used the relative error criterion, though -at certain points the relative error could be much higher than -indicated. - IEEE -200, -4 10000 4.8e-16 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier -Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). -*************************************************************************/ -double lngamma(const double x, double &sgngam); - -/************************************************************************* -Error function - -The integral is - - x - - - 2 | | 2 - erf(x) = -------- | exp( - t ) dt. - sqrt(pi) | | - - - 0 - -For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise -erf(x) = 1 - erfc(x). - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 3.7e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunction(const double x); - - -/************************************************************************* -Complementary error function - - 1 - erf(x) = - - inf. - - - 2 | | 2 - erfc(x) = -------- | exp( - t ) dt - sqrt(pi) | | - - - x - - -For small x, erfc(x) = 1 - erf(x); otherwise rational -approximations are computed. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,26.6417 30000 5.7e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double errorfunctionc(const double x); - - -/************************************************************************* -Normal distribution function - -Returns the area under the Gaussian probability density -function, integrated from minus infinity to x: - - x - - - 1 | | 2 - ndtr(x) = --------- | exp( - t /2 ) dt - sqrt(2pi) | | - - - -inf. - - = ( 1 + erf(z) ) / 2 - = erfc(z) / 2 - -where z = x/sqrt(2). Computation is via the functions -erf and erfc. - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE -13,0 30000 3.4e-14 6.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double normaldistribution(const double x); - - -/************************************************************************* -Inverse of the error function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double inverf(const double e); - - -/************************************************************************* -Inverse of Normal distribution function - -Returns the argument, x, for which the area under the -Gaussian probability density function (integrated from -minus infinity to x) is equal to y. - - -For small arguments 0 < y < exp(-2), the program computes -z = sqrt( -2.0 * log(y) ); then the approximation is -x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). -There are two rational functions P/Q, one for 0 < y < exp(-32) -and the other for y up to exp(-2). For larger arguments, -w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0.125, 1 20000 7.2e-16 1.3e-16 - IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double invnormaldistribution(const double y0); - -/************************************************************************* -Incomplete gamma integral - -The function is defined by - - x - - - 1 | | -t a-1 - igam(a,x) = ----- | e t dt. - - | | - | (a) - - 0 - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 200000 3.6e-14 2.9e-15 - IEEE 0,100 300000 9.9e-14 1.5e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegamma(const double a, const double x); - - -/************************************************************************* -Complemented incomplete gamma integral - -The function is defined by - - - igamc(a,x) = 1 - igam(a,x) - - inf. - - - 1 | | -t a-1 - = ----- | e t dt. - - | | - | (a) - - x - - -In this implementation both arguments must be positive. -The integral is evaluated by either a power series or -continued fraction expansion, depending on the relative -values of a and x. - -ACCURACY: - -Tested at random a, x. - a x Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 - IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletegammac(const double a, const double x); - - -/************************************************************************* -Inverse of complemented incomplete gamma integral - -Given p, the function finds x such that - - igamc( a, x ) = p. - -Starting with the approximate value - - 3 - x = a t - - where - - t = 1 - d - ndtri(p) sqrt(d) - -and - - d = 1/9a, - -the routine performs up to 10 Newton iterations to find the -root of igamc(a,x) - p = 0. - -ACCURACY: - -Tested at random a, p in the intervals indicated. - - a p Relative error: -arithmetic domain domain # trials peak rms - IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 - IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 - IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletegammac(const double a, const double y0); - -/************************************************************************* -Airy function - -Solution of the differential equation - -y"(x) = xy. - -The function returns the two independent solutions Ai, Bi -and their first derivatives Ai'(x), Bi'(x). - -Evaluation is by power series summation for small x, -by rational minimax approximations for large x. - - - -ACCURACY: -Error criterion is absolute when function <= 1, relative -when function > 1, except * denotes relative error criterion. -For large negative x, the absolute error increases as x^1.5. -For large positive x, the relative error increases as x^1.5. - -Arithmetic domain function # trials peak rms -IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 -IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* -IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 -IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* -IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 -IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void airy(const double x, double &ai, double &aip, double &bi, double &bip); - -/************************************************************************* -Bessel function of order zero - -Returns Bessel function of order zero of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval the following rational -approximation is used: - - - 2 2 -(w - r ) (w - r ) P (w) / Q (w) - 1 2 3 8 - - 2 -where w = x and the two r's are zeros of the function. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 60000 4.2e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj0(const double x); - - -/************************************************************************* -Bessel function of order one - -Returns Bessel function of order one of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 24 term Chebyshev -expansion is used. In the second, the asymptotic -trigonometric representation is employed using two -rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 2.6e-16 1.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselj1(const double x); - - -/************************************************************************* -Bessel function of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The ratio of jn(x) to j0(x) is computed by backward -recurrence. First the ratio jn/jn-1 is found by a -continued fraction expansion. Then the recurrence -relating successive orders is applied until j0 or j1 is -reached. - -If n = 0 or 1 the routine for j0 or j1 is called -directly. - -ACCURACY: - - Absolute error: -arithmetic range # trials peak rms - IEEE 0, 30 5000 4.4e-16 7.9e-17 - - -Not suitable for large n or x. Use jv() (fractional order) instead. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseljn(const ae_int_t n, const double x); - - -/************************************************************************* -Bessel function of the second kind, order zero - -Returns Bessel function of the second kind, of order -zero, of the argument. - -The domain is divided into the intervals [0, 5] and -(5, infinity). In the first interval a rational approximation -R(x) is employed to compute - y0(x) = R(x) + 2 * log(x) * j0(x) / PI. -Thus a call to j0() is required. - -In the second interval, the Hankel asymptotic expansion -is employed with two rational functions of degree 6/6 -and 7/7. - - - -ACCURACY: - - Absolute error, when y0(x) < 1; else relative error: - -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.3e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely0(const double x); - - -/************************************************************************* -Bessel function of second kind of order one - -Returns Bessel function of the second kind of order one -of the argument. - -The domain is divided into the intervals [0, 8] and -(8, infinity). In the first interval a 25 term Chebyshev -expansion is used, and a call to j1() is required. -In the second, the asymptotic trigonometric representation -is employed using two rational functions of degree 5/5. - -ACCURACY: - - Absolute error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.0e-15 1.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double bessely1(const double x); - - -/************************************************************************* -Bessel function of second kind of integer order - -Returns Bessel function of order n, where n is a -(possibly negative) integer. - -The function is evaluated by forward recurrence on -n, starting with values computed by the routines -y0() and y1(). - -If n = 0 or 1 the routine for y0 or y1 is called -directly. - -ACCURACY: - Absolute error, except relative - when y > 1: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 3.4e-15 4.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselyn(const ae_int_t n, const double x); - - -/************************************************************************* -Modified Bessel function of order zero - -Returns modified Bessel function of order zero of the -argument. - -The function is defined as i0(x) = j0( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 5.8e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli0(const double x); - - -/************************************************************************* -Modified Bessel function of order one - -Returns modified Bessel function of order one of the -argument. - -The function is defined as i1(x) = -i j1( ix ). - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.9e-15 2.1e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besseli1(const double x); - - -/************************************************************************* -Modified Bessel function, second kind, order zero - -Returns modified Bessel function of the second kind -of order zero of the argument. - -The range is partitioned into the two intervals [0,8] and -(8, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - -Tested at 2000 random points between 0 and 8. Peak absolute -error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk0(const double x); - - -/************************************************************************* -Modified Bessel function, second kind, order one - -Computes the modified Bessel function of the second kind -of order one of the argument. - -The range is partitioned into the two intervals [0,2] and -(2, infinity). Chebyshev polynomial expansions are employed -in each interval. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 30000 1.2e-15 1.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselk1(const double x); - - -/************************************************************************* -Modified Bessel function, second kind, integer order - -Returns modified Bessel function of the second kind -of order n of the argument. - -The range is partitioned into the two intervals [0,9.55] and -(9.55, infinity). An ascending power series is used in the -low range, and an asymptotic expansion in the high range. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 90000 1.8e-8 3.0e-10 - -Error is high only near the crossover point x = 9.55 -between the two expansions used. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier -*************************************************************************/ -double besselkn(const ae_int_t nn, const double x); - -/************************************************************************* -Beta function - - - - - - | (a) | (b) -beta( a, b ) = -----------. - - - | (a+b) - -For large arguments the logarithm of the function is -evaluated using lgam(), then exponentiated. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,30 30000 8.1e-14 1.1e-14 - -Cephes Math Library Release 2.0: April, 1987 -Copyright 1984, 1987 by Stephen L. Moshier -*************************************************************************/ -double beta(const double a, const double b); - -/************************************************************************* -Incomplete beta integral - -Returns incomplete beta integral of the arguments, evaluated -from zero to x. The function is defined as - - x - - - - | (a+b) | | a-1 b-1 - ----------- | t (1-t) dt. - - - | | - | (a) | (b) - - 0 - -The domain of definition is 0 <= x <= 1. In this -implementation a and b are restricted to positive values. -The integral from x to 1 may be obtained by the symmetry -relation - - 1 - incbet( a, b, x ) = incbet( b, a, 1-x ). - -The integral is evaluated by a continued fraction expansion -or, when b*x is small, by a power series. - -ACCURACY: - -Tested at uniformly distributed random points (a,b,x) with a and b -in "domain" and x between 0 and 1. - Relative error -arithmetic domain # trials peak rms - IEEE 0,5 10000 6.9e-15 4.5e-16 - IEEE 0,85 250000 2.2e-13 1.7e-14 - IEEE 0,1000 30000 5.3e-12 6.3e-13 - IEEE 0,10000 250000 9.3e-11 7.1e-12 - IEEE 0,100000 10000 8.7e-10 4.8e-11 -Outputs smaller than the IEEE gradual underflow threshold -were excluded from these statistics. - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompletebeta(const double a, const double b, const double x); - - -/************************************************************************* -Inverse of incomplete beta integral - -Given y, the function finds x such that - - incbet( a, b, x ) = y . - -The routine performs interval halving or Newton iterations to find the -root of incbet(a,b,x) - y = 0. - - -ACCURACY: - - Relative error: - x a,b -arithmetic domain domain # trials peak rms - IEEE 0,1 .5,10000 50000 5.8e-12 1.3e-13 - IEEE 0,1 .25,100 100000 1.8e-13 3.9e-15 - IEEE 0,1 0,5 50000 1.1e-12 5.5e-15 -With a and b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 50000 5.8e-12 1.1e-13 - IEEE 0,1 .5,100 100000 1.7e-14 7.9e-16 -With a = .5, b constrained to half-integer or integer values: - IEEE 0,1 .5,10000 10000 8.3e-11 1.0e-11 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1996, 2000 by Stephen L. Moshier -*************************************************************************/ -double invincompletebeta(const double a, const double b, const double y); - -/************************************************************************* -Binomial distribution - -Returns the sum of the terms 0 through k of the Binomial -probability density: - - k - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=0 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p), with p between 0 and 1. - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 4.3e-15 2.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p); - - -/************************************************************************* -Complemented binomial distribution - -Returns the sum of the terms k+1 through n of the Binomial -probability density: - - n - -- ( n ) j n-j - > ( ) p (1-p) - -- ( j ) - j=k+1 - -The terms are not summed directly; instead the incomplete -beta integral is employed, according to the formula - -y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). - -The arguments must be positive, with p ranging from 0 to 1. - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 6.7e-15 8.2e-16 - For p between 0 and .001: - IEEE 0,100 100000 1.5e-13 2.7e-15 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p); - - -/************************************************************************* -Inverse binomial distribution - -Finds the event probability p such that the sum of the -terms 0 through k of the Binomial probability density -is equal to the given cumulative probability y. - -This is accomplished using the inverse beta integral -function and the relation - -1 - p = incbi( n-k, k+1, y ). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between 0.001 and 1: - IEEE 0,100 100000 2.3e-14 6.4e-16 - IEEE 0,10000 100000 6.6e-12 1.2e-13 - For p between 10^-6 and 0.001: - IEEE 0,100 100000 2.0e-12 1.3e-14 - IEEE 0,10000 100000 1.5e-12 3.2e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y); - -/************************************************************************* -Calculation of the value of the Chebyshev polynomials of the -first and second kinds. - -Parameters: - r - polynomial kind, either 1 or 2. - n - degree, n>=0 - x - argument, -1 <= x <= 1 - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x); - - -/************************************************************************* -Summation of Chebyshev polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) -or - c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) -depending on the R. - -Parameters: - r - polynomial kind, either 1 or 2. - n - degree, n>=0 - x - argument - -Result: - the value of the Chebyshev polynomial at x -*************************************************************************/ -double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x); - - -/************************************************************************* -Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void chebyshevcoefficients(const ae_int_t n, real_1d_array &c); - - -/************************************************************************* -Conversion of a series of Chebyshev polynomials to a power series. - -Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as -B[0] + B[1]*X + ... + B[N]*X^N. - -Input parameters: - A - Chebyshev series coefficients - N - degree, N>=0 - -Output parameters - B - power series coefficients -*************************************************************************/ -void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b); - -/************************************************************************* -Chi-square distribution - -Returns the area under the left hand tail (from 0 to x) -of the Chi square probability density function with -v degrees of freedom. - - - x - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - 0 - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquaredistribution(const double v, const double x); - - -/************************************************************************* -Complemented Chi-square distribution - -Returns the area under the right hand tail (from x to -infinity) of the Chi square probability density function -with v degrees of freedom: - - inf. - - - 1 | | v/2-1 -t/2 - P( x | v ) = ----------- | t e dt - v/2 - | | - 2 | (v/2) - - x - -where x is the Chi-square variable. - -The incomplete gamma integral is used, according to the -formula - -y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double chisquarecdistribution(const double v, const double x); - - -/************************************************************************* -Inverse of complemented Chi-square distribution - -Finds the Chi-square argument x such that the integral -from x to infinity of the Chi-square density is equal -to the given cumulative probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - x/2 = igami( df/2, y ); - -ACCURACY: - -See inverse incomplete gamma function - - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double invchisquaredistribution(const double v, const double y); - -/************************************************************************* -Dawson's Integral - -Approximates the integral - - x - - - 2 | | 2 - dawsn(x) = exp( -x ) | exp( t ) dt - | | - - - 0 - -Three different rational approximations are employed, for -the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,10 10000 6.9e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double dawsonintegral(const double x); - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -using the approximation - - P(x) - log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegralk(const double m); - - -/************************************************************************* -Complete elliptic integral of the first kind - -Approximates the integral - - - - pi/2 - - - | | - | dt -K(m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -where m = 1 - m1, using the approximation - - P(x) - log x Q(x). - -The argument m1 is used rather than m so that the logarithmic -singularity at m = 1 will be shifted to the origin; this -preserves maximum accuracy. - -K(0) = pi/2. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,1 30000 2.5e-16 6.8e-17 - -Àëãîðèòì âçÿò èç áèáëèîòåêè Cephes -*************************************************************************/ -double ellipticintegralkhighprecision(const double m1); - - -/************************************************************************* -Incomplete elliptic integral of the first kind F(phi|m) - -Approximates the integral - - - - phi - - - | | - | dt -F(phi_\m) = | ------------------ - | 2 - | | sqrt( 1 - m sin t ) - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - - - - -ACCURACY: - -Tested at random points with m in [0, 1] and phi as indicated. - - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 200000 7.4e-16 1.0e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegralk(const double phi, const double m); - - -/************************************************************************* -Complete elliptic integral of the second kind - -Approximates the integral - - - pi/2 - - - | | 2 -E(m) = | sqrt( 1 - m sin t ) dt - | | - - - 0 - -using the approximation - - P(x) - x log x Q(x). - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 1 10000 2.1e-16 7.3e-17 - -Cephes Math Library, Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -double ellipticintegrale(const double m); - - -/************************************************************************* -Incomplete elliptic integral of the second kind - -Approximates the integral - - - phi - - - | | - | 2 -E(phi_\m) = | sqrt( 1 - m sin t ) dt - | - | | - - - 0 - -of amplitude phi and modulus m, using the arithmetic - -geometric mean algorithm. - -ACCURACY: - -Tested at random arguments with phi in [-10, 10] and m in -[0, 1]. - Relative error: -arithmetic domain # trials peak rms - IEEE -10,10 150000 3.3e-15 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier -*************************************************************************/ -double incompleteellipticintegrale(const double phi, const double m); - -/************************************************************************* -Exponential integral Ei(x) - - x - - t - | | e - Ei(x) = -|- --- dt . - | | t - - - -inf - -Not defined for x <= 0. -See also expn.c. - - - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0,100 50000 8.6e-16 1.3e-16 - -Cephes Math Library Release 2.8: May, 1999 -Copyright 1999 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralei(const double x); - - -/************************************************************************* -Exponential integral En(x) - -Evaluates the exponential integral - - inf. - - - | | -xt - | e - E (x) = | ---- dt. - n | n - | | t - - - 1 - - -Both n and x must be nonnegative. - -The routine employs either a power series, a continued -fraction, or an asymptotic formula depending on the -relative values of n and x. - -ACCURACY: - - Relative error: -arithmetic domain # trials peak rms - IEEE 0, 30 10000 1.7e-15 3.6e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1985, 2000 by Stephen L. Moshier -*************************************************************************/ -double exponentialintegralen(const double x, const ae_int_t n); - -/************************************************************************* -F distribution - -Returns the area from zero to x under the F density -function (also known as Snedcor's density or the -variance ratio density). This is the density -of x = (u1/df1)/(u2/df2), where u1 and u2 are random -variables having Chi square distributions with df1 -and df2 degrees of freedom, respectively. -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). - - -The arguments a and b are greater than zero, and x is -nonnegative. - -ACCURACY: - -Tested at random points (a,b,x). - - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 - IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 - IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 - IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fdistribution(const ae_int_t a, const ae_int_t b, const double x); - - -/************************************************************************* -Complemented F distribution - -Returns the area from x to infinity under the F density -function (also known as Snedcor's density or the -variance ratio density). - - - inf. - - - 1 | | a-1 b-1 -1-P(x) = ------ | t (1-t) dt - B(a,b) | | - - - x - - -The incomplete beta integral is used, according to the -formula - -P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). - - -ACCURACY: - -Tested at random points (a,b,x) in the indicated intervals. - x a,b Relative error: -arithmetic domain domain # trials peak rms - IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 - IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 - IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 - IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double fcdistribution(const ae_int_t a, const ae_int_t b, const double x); - - -/************************************************************************* -Inverse of complemented F distribution - -Finds the F density argument x such that the integral -from x to infinity of the F density is equal to the -given probability p. - -This is accomplished using the inverse beta integral -function and the relations - - z = incbi( df2/2, df1/2, p ) - x = df2 (1-z) / (df1 z). - -Note: the following relations hold for the inverse of -the uncomplemented F distribution: - - z = incbi( df1/2, df2/2, p ) - x = df2 z / (df1 (1-z)). - -ACCURACY: - -Tested at random points (a,b,p). - - a,b Relative error: -arithmetic domain # trials peak rms - For p between .001 and 1: - IEEE 1,100 100000 8.3e-15 4.7e-16 - IEEE 1,10000 100000 2.1e-11 1.4e-13 - For p between 10^-6 and 10^-3: - IEEE 1,100 50000 1.3e-12 8.4e-15 - IEEE 1,10000 50000 3.0e-12 4.8e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invfdistribution(const ae_int_t a, const ae_int_t b, const double y); - -/************************************************************************* -Fresnel integral - -Evaluates the Fresnel integrals - - x - - - | | -C(x) = | cos(pi/2 t**2) dt, - | | - - - 0 - - x - - - | | -S(x) = | sin(pi/2 t**2) dt. - | | - - - 0 - - -The integrals are evaluated by a power series for x < 1. -For x >= 1 auxiliary functions f(x) and g(x) are employed -such that - -C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) -S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) - - - -ACCURACY: - - Relative error. - -Arithmetic function domain # trials peak rms - IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 - IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier -*************************************************************************/ -void fresnelintegral(const double x, double &c, double &s); - -/************************************************************************* -Calculation of the value of the Hermite polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial Hn at x -*************************************************************************/ -double hermitecalculate(const ae_int_t n, const double x); - - -/************************************************************************* -Summation of Hermite polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Hermite polynomial at x -*************************************************************************/ -double hermitesum(const real_1d_array &c, const ae_int_t n, const double x); - - -/************************************************************************* -Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void hermitecoefficients(const ae_int_t n, real_1d_array &c); - -/************************************************************************* -Jacobian Elliptic Functions - -Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), -and dn(u|m) of parameter m between 0 and 1, and real -argument u. - -These functions are periodic, with quarter-period on the -real axis equal to the complete elliptic integral -ellpk(1.0-m). - -Relation to incomplete elliptic integral: -If u = ellik(phi,m), then sn(u|m) = sin(phi), -and cn(u|m) = cos(phi). Phi is called the amplitude of u. - -Computation is by means of the arithmetic-geometric mean -algorithm, except when m is within 1e-9 of 0 or 1. In the -latter case with m close to 1, the approximation applies -only for phi < pi/2. - -ACCURACY: - -Tested at random points with u between 0 and 10, m between -0 and 1. - - Absolute error (* = relative error): -arithmetic function # trials peak rms - IEEE phi 10000 9.2e-16* 1.4e-16* - IEEE sn 50000 4.1e-15 4.6e-16 - IEEE cn 40000 3.6e-15 4.4e-16 - IEEE dn 10000 1.3e-12 1.8e-14 - - Peak error observed in consistency check using addition -theorem for sn(u+v) was 4e-16 (absolute). Also tested by -the above relation to the incomplete elliptic integral. -Accuracy deteriorates when u is large. - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph); - -/************************************************************************* -Calculation of the value of the Laguerre polynomial. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial Ln at x -*************************************************************************/ -double laguerrecalculate(const ae_int_t n, const double x); - - -/************************************************************************* -Summation of Laguerre polynomials using Clenshaw’s recurrence formula. - -This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Laguerre polynomial at x -*************************************************************************/ -double laguerresum(const real_1d_array &c, const ae_int_t n, const double x); - - -/************************************************************************* -Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void laguerrecoefficients(const ae_int_t n, real_1d_array &c); - -/************************************************************************* -Calculation of the value of the Legendre polynomial Pn. - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial Pn at x -*************************************************************************/ -double legendrecalculate(const ae_int_t n, const double x); - - -/************************************************************************* -Summation of Legendre polynomials using Clenshaw’s recurrence formula. - -This routine calculates - c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) - -Parameters: - n - degree, n>=0 - x - argument - -Result: - the value of the Legendre polynomial at x -*************************************************************************/ -double legendresum(const real_1d_array &c, const ae_int_t n, const double x); - - -/************************************************************************* -Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N - -Input parameters: - N - polynomial degree, n>=0 - -Output parameters: - C - coefficients -*************************************************************************/ -void legendrecoefficients(const ae_int_t n, real_1d_array &c); - -/************************************************************************* -Poisson distribution - -Returns the sum of the first k+1 terms of the Poisson -distribution: - - k j - -- -m m - > e -- - -- j! - j=0 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the relation - -y = pdtr( k, m ) = igamc( k+1, m ). - -The arguments must both be positive. -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissondistribution(const ae_int_t k, const double m); - - -/************************************************************************* -Complemented Poisson distribution - -Returns the sum of the terms k+1 to infinity of the Poisson -distribution: - - inf. j - -- -m m - > e -- - -- j! - j=k+1 - -The terms are not summed directly; instead the incomplete -gamma integral is employed, according to the formula - -y = pdtrc( k, m ) = igam( k+1, m ). - -The arguments must both be positive. - -ACCURACY: - -See incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double poissoncdistribution(const ae_int_t k, const double m); - - -/************************************************************************* -Inverse Poisson distribution - -Finds the Poisson variable x such that the integral -from 0 to x of the Poisson density is equal to the -given probability y. - -This is accomplished using the inverse gamma integral -function and the relation - - m = igami( k+1, y ). - -ACCURACY: - -See inverse incomplete gamma function - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invpoissondistribution(const ae_int_t k, const double y); - -/************************************************************************* -Psi (digamma) function - - d - - psi(x) = -- ln | (x) - dx - -is the logarithmic derivative of the gamma function. -For integer x, - n-1 - - -psi(n) = -EUL + > 1/k. - - - k=1 - -This formula is used for 0 < n <= 10. If x is negative, it -is transformed to a positive argument by the reflection -formula psi(1-x) = psi(x) + pi cot(pi x). -For general positive x, the argument is made greater than 10 -using the recurrence psi(x+1) = psi(x) + 1/x. -Then the following asymptotic expansion is applied: - - inf. B - - 2k -psi(x) = log(x) - 1/2x - > ------- - - 2k - k=1 2k x - -where the B2k are Bernoulli numbers. - -ACCURACY: - Relative error (except absolute when |psi| < 1): -arithmetic domain # trials peak rms - IEEE 0,30 30000 1.3e-15 1.4e-16 - IEEE -30,0 40000 1.5e-15 2.2e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier -*************************************************************************/ -double psi(const double x); - -/************************************************************************* -Student's t distribution - -Computes the integral from minus infinity to t of the Student -t distribution with integer k > 0 degrees of freedom: - - t - - - | | - - | 2 -(k+1)/2 - | ( (k+1)/2 ) | ( x ) - ---------------------- | ( 1 + --- ) dx - - | ( k ) - sqrt( k pi ) | ( k/2 ) | - | | - - - -inf. - -Relation to incomplete beta integral: - - 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) -where - z = k/(k + t**2). - -For t < -2, this is the method of computation. For higher t, -a direct method is derived from integration by parts. -Since the function is symmetric about t=0, the area under the -right tail of the density is found by calling the function -with -t instead of t. - -ACCURACY: - -Tested at random 1 <= k <= 25. The "domain" refers to t. - Relative error: -arithmetic domain # trials peak rms - IEEE -100,-2 50000 5.9e-15 1.4e-15 - IEEE -2,100 500000 2.7e-15 4.9e-17 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double studenttdistribution(const ae_int_t k, const double t); - - -/************************************************************************* -Functional inverse of Student's t distribution - -Given probability p, finds the argument t such that stdtr(k,t) -is equal to p. - -ACCURACY: - -Tested at random 1 <= k <= 100. The "domain" refers to p: - Relative error: -arithmetic domain # trials peak rms - IEEE .001,.999 25000 5.7e-15 8.0e-16 - IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier -*************************************************************************/ -double invstudenttdistribution(const ae_int_t k, const double p); - -/************************************************************************* -Sine and cosine integrals - -Evaluates the integrals - - x - - - | cos t - 1 - Ci(x) = eul + ln x + | --------- dt, - | t - - - 0 - x - - - | sin t - Si(x) = | ----- dt - | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are approximated by rational functions. -For x > 8 auxiliary functions f(x) and g(x) are employed -such that - -Ci(x) = f(x) sin(x) - g(x) cos(x) -Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) - - -ACCURACY: - Test interval = [0,50]. -Absolute error, except relative when > 1: -arithmetic function # trials peak rms - IEEE Si 30000 4.4e-16 7.3e-17 - IEEE Ci 30000 6.9e-16 5.1e-17 - -Cephes Math Library Release 2.1: January, 1989 -Copyright 1984, 1987, 1989 by Stephen L. Moshier -*************************************************************************/ -void sinecosineintegrals(const double x, double &si, double &ci); - - -/************************************************************************* -Hyperbolic sine and cosine integrals - -Approximates the integrals - - x - - - | | cosh t - 1 - Chi(x) = eul + ln x + | ----------- dt, - | | t - - - 0 - - x - - - | | sinh t - Shi(x) = | ------ dt - | | t - - - 0 - -where eul = 0.57721566490153286061 is Euler's constant. -The integrals are evaluated by power series for x < 8 -and by Chebyshev expansions for x between 8 and 88. -For large x, both functions approach exp(x)/2x. -Arguments greater than 88 in magnitude return MAXNUM. - - -ACCURACY: - -Test interval 0 to 88. - Relative error: -arithmetic function # trials peak rms - IEEE Shi 30000 6.9e-16 1.6e-16 - Absolute error, except relative when |Chi| > 1: - IEEE Chi 30000 8.4e-16 1.4e-16 - -Cephes Math Library Release 2.8: June, 2000 -Copyright 1984, 1987, 2000 by Stephen L. Moshier -*************************************************************************/ -void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -double gammafunction(double x, ae_state *_state); -double lngamma(double x, double* sgngam, ae_state *_state); -double errorfunction(double x, ae_state *_state); -double errorfunctionc(double x, ae_state *_state); -double normaldistribution(double x, ae_state *_state); -double inverf(double e, ae_state *_state); -double invnormaldistribution(double y0, ae_state *_state); -double incompletegamma(double a, double x, ae_state *_state); -double incompletegammac(double a, double x, ae_state *_state); -double invincompletegammac(double a, double y0, ae_state *_state); -void airy(double x, - double* ai, - double* aip, - double* bi, - double* bip, - ae_state *_state); -double besselj0(double x, ae_state *_state); -double besselj1(double x, ae_state *_state); -double besseljn(ae_int_t n, double x, ae_state *_state); -double bessely0(double x, ae_state *_state); -double bessely1(double x, ae_state *_state); -double besselyn(ae_int_t n, double x, ae_state *_state); -double besseli0(double x, ae_state *_state); -double besseli1(double x, ae_state *_state); -double besselk0(double x, ae_state *_state); -double besselk1(double x, ae_state *_state); -double besselkn(ae_int_t nn, double x, ae_state *_state); -double beta(double a, double b, ae_state *_state); -double incompletebeta(double a, double b, double x, ae_state *_state); -double invincompletebeta(double a, double b, double y, ae_state *_state); -double binomialdistribution(ae_int_t k, - ae_int_t n, - double p, - ae_state *_state); -double binomialcdistribution(ae_int_t k, - ae_int_t n, - double p, - ae_state *_state); -double invbinomialdistribution(ae_int_t k, - ae_int_t n, - double y, - ae_state *_state); -double chebyshevcalculate(ae_int_t r, - ae_int_t n, - double x, - ae_state *_state); -double chebyshevsum(/* Real */ ae_vector* c, - ae_int_t r, - ae_int_t n, - double x, - ae_state *_state); -void chebyshevcoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -void fromchebyshev(/* Real */ ae_vector* a, - ae_int_t n, - /* Real */ ae_vector* b, - ae_state *_state); -double chisquaredistribution(double v, double x, ae_state *_state); -double chisquarecdistribution(double v, double x, ae_state *_state); -double invchisquaredistribution(double v, double y, ae_state *_state); -double dawsonintegral(double x, ae_state *_state); -double ellipticintegralk(double m, ae_state *_state); -double ellipticintegralkhighprecision(double m1, ae_state *_state); -double incompleteellipticintegralk(double phi, double m, ae_state *_state); -double ellipticintegrale(double m, ae_state *_state); -double incompleteellipticintegrale(double phi, double m, ae_state *_state); -double exponentialintegralei(double x, ae_state *_state); -double exponentialintegralen(double x, ae_int_t n, ae_state *_state); -double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); -double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); -double invfdistribution(ae_int_t a, - ae_int_t b, - double y, - ae_state *_state); -void fresnelintegral(double x, double* c, double* s, ae_state *_state); -double hermitecalculate(ae_int_t n, double x, ae_state *_state); -double hermitesum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state); -void hermitecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -void jacobianellipticfunctions(double u, - double m, - double* sn, - double* cn, - double* dn, - double* ph, - ae_state *_state); -double laguerrecalculate(ae_int_t n, double x, ae_state *_state); -double laguerresum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state); -void laguerrecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -double legendrecalculate(ae_int_t n, double x, ae_state *_state); -double legendresum(/* Real */ ae_vector* c, - ae_int_t n, - double x, - ae_state *_state); -void legendrecoefficients(ae_int_t n, - /* Real */ ae_vector* c, - ae_state *_state); -double poissondistribution(ae_int_t k, double m, ae_state *_state); -double poissoncdistribution(ae_int_t k, double m, ae_state *_state); -double invpoissondistribution(ae_int_t k, double y, ae_state *_state); -double psi(double x, ae_state *_state); -double studenttdistribution(ae_int_t k, double t, ae_state *_state); -double invstudenttdistribution(ae_int_t k, double p, ae_state *_state); -void sinecosineintegrals(double x, - double* si, - double* ci, - ae_state *_state); -void hyperbolicsinecosineintegrals(double x, - double* shi, - double* chi, - ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _specialfunctions_pkg_h +#define _specialfunctions_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "alglibmisc.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_IBETAF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_STUDENTTDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_IBETAF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_STUDENTTDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Gamma function + +Input parameters: + X - argument + +Domain: + 0 < X < 171.6 + -170 < X < 0, X is not an integer. + +Relative error: + arithmetic domain # trials peak rms + IEEE -170,-33 20000 2.3e-15 3.3e-16 + IEEE -33, 33 20000 9.4e-16 2.2e-16 + IEEE 33, 171.6 20000 2.3e-15 3.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Original copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double gammafunction(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Natural logarithm of gamma function + +Input parameters: + X - argument + +Result: + logarithm of the absolute value of the Gamma(X). + +Output parameters: + SgnGam - sign(Gamma(X)) + +Domain: + 0 < X < 2.55e305 + -2.55e305 < X < 0, X is not an integer. + +ACCURACY: +arithmetic domain # trials peak rms + IEEE 0, 3 28000 5.4e-16 1.1e-16 + IEEE 2.718, 2.556e305 40000 3.5e-16 8.3e-17 +The error criterion was relative when the function magnitude +was greater than one but absolute when it was less than one. + +The following test used the relative error criterion, though +at certain points the relative error could be much higher than +indicated. + IEEE -200, -4 10000 4.8e-16 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +Translated to AlgoPascal by Bochkanov Sergey (2005, 2006, 2007). +*************************************************************************/ +double lngamma(const double x, double &sgngam, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Error function + +The integral is + + x + - + 2 | | 2 + erf(x) = -------- | exp( - t ) dt. + sqrt(pi) | | + - + 0 + +For 0 <= |x| < 1, erf(x) = x * P4(x**2)/Q5(x**2); otherwise +erf(x) = 1 - erfc(x). + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 3.7e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunction(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complementary error function + + 1 - erf(x) = + + inf. + - + 2 | | 2 + erfc(x) = -------- | exp( - t ) dt + sqrt(pi) | | + - + x + + +For small x, erfc(x) = 1 - erf(x); otherwise rational +approximations are computed. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,26.6417 30000 5.7e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double errorfunctionc(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as normalcdf(), obsolete name. +*************************************************************************/ +double normaldistribution(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Normal distribution PDF + +Returns Gaussian probability density function: + + 1 + f(x) = --------- * exp(-x^2/2) + sqrt(2pi) + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalpdf(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Normal distribution CDF + +Returns the area under the Gaussian probability density +function, integrated from minus infinity to x: + + x + - + 1 | | 2 + ndtr(x) = --------- | exp( - t /2 ) dt + sqrt(2pi) | | + - + -inf. + + = ( 1 + erf(z) ) / 2 + = erfc(z) / 2 + +where z = x/sqrt(2). Computation is via the functions +erf and erfc. + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE -13,0 30000 3.4e-14 6.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double normalcdf(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse of the error function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double inverf(const double e, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as invnormalcdf(), deprecated name +*************************************************************************/ +double invnormaldistribution(const double y0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse of Normal CDF + +Returns the argument, x, for which the area under the +Gaussian probability density function (integrated from +minus infinity to x) is equal to y. + + +For small arguments 0 < y < exp(-2), the program computes +z = sqrt( -2.0 * log(y) ); then the approximation is +x = z - log(z)/z - (1/z) P(1/z) / Q(1/z). +There are two rational functions P/Q, one for 0 < y < exp(-32) +and the other for y up to exp(-2). For larger arguments, +w = y - 0.5, and x/sqrt(2pi) = w + w**3 R(w**2)/S(w**2)). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0.125, 1 20000 7.2e-16 1.3e-16 + IEEE 3e-308, 0.135 50000 4.6e-16 9.8e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double invnormalcdf(const double y0, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bivariate normal PDF + +Returns probability density function of the bivariate Gaussian with +correlation parameter equal to Rho: + + 1 ( x^2 - 2*rho*x*y + y^2 ) + f(x,y,rho) = ----------------- * exp( - ----------------------- ) + 2pi*sqrt(1-rho^2) ( 2*(1-rho^2) ) + + +with -1 0 degrees of freedom: + + t + - + | | + - | 2 -(k+1)/2 + | ( (k+1)/2 ) | ( x ) + ---------------------- | ( 1 + --- ) dx + - | ( k ) + sqrt( k pi ) | ( k/2 ) | + | | + - + -inf. + +Relation to incomplete beta integral: + + 1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z ) +where + z = k/(k + t**2). + +For t < -2, this is the method of computation. For higher t, +a direct method is derived from integration by parts. +Since the function is symmetric about t=0, the area under the +right tail of the density is found by calling the function +with -t instead of t. + +ACCURACY: + +Tested at random 1 <= k <= 25. The "domain" refers to t. + Relative error: +arithmetic domain # trials peak rms + IEEE -100,-2 50000 5.9e-15 1.4e-15 + IEEE -2,100 500000 2.7e-15 4.9e-17 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double studenttdistribution(const ae_int_t k, const double t, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Functional inverse of Student's t distribution + +Given probability p, finds the argument t such that stdtr(k,t) +is equal to p. + +ACCURACY: + +Tested at random 1 <= k <= 100. The "domain" refers to p: + Relative error: +arithmetic domain # trials peak rms + IEEE .001,.999 25000 5.7e-15 8.0e-16 + IEEE 10^-6,.001 25000 2.0e-12 2.9e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invstudenttdistribution(const ae_int_t k, const double p, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +F distribution + +Returns the area from zero to x under the F density +function (also known as Snedcor's density or the +variance ratio density). This is the density +of x = (u1/df1)/(u2/df2), where u1 and u2 are random +variables having Chi square distributions with df1 +and df2 degrees of freedom, respectively. +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df1/2, df2/2, (df1*x/(df2 + df1*x) ). + + +The arguments a and b are greater than zero, and x is +nonnegative. + +ACCURACY: + +Tested at random points (a,b,x). + + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 0,100 100000 9.8e-15 1.7e-15 + IEEE 1,5 0,100 100000 6.5e-15 3.5e-16 + IEEE 0,1 1,10000 100000 2.2e-11 3.3e-12 + IEEE 1,5 1,10000 100000 1.1e-11 1.7e-13 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fdistribution(const ae_int_t a, const ae_int_t b, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complemented F distribution + +Returns the area from x to infinity under the F density +function (also known as Snedcor's density or the +variance ratio density). + + + inf. + - + 1 | | a-1 b-1 +1-P(x) = ------ | t (1-t) dt + B(a,b) | | + - + x + + +The incomplete beta integral is used, according to the +formula + +P(x) = incbet( df2/2, df1/2, (df2/(df2 + df1*x) ). + + +ACCURACY: + +Tested at random points (a,b,x) in the indicated intervals. + x a,b Relative error: +arithmetic domain domain # trials peak rms + IEEE 0,1 1,100 100000 3.7e-14 5.9e-16 + IEEE 1,5 1,100 100000 8.0e-15 1.6e-15 + IEEE 0,1 1,10000 100000 1.8e-11 3.5e-13 + IEEE 1,5 1,10000 100000 2.0e-11 3.0e-12 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double fcdistribution(const ae_int_t a, const ae_int_t b, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse of complemented F distribution + +Finds the F density argument x such that the integral +from x to infinity of the F density is equal to the +given probability p. + +This is accomplished using the inverse beta integral +function and the relations + + z = incbi( df2/2, df1/2, p ) + x = df2 (1-z) / (df1 z). + +Note: the following relations hold for the inverse of +the uncomplemented F distribution: + + z = incbi( df1/2, df2/2, p ) + x = df2 z / (df1 (1-z)). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between .001 and 1: + IEEE 1,100 100000 8.3e-15 4.7e-16 + IEEE 1,10000 100000 2.1e-11 1.4e-13 + For p between 10^-6 and 10^-3: + IEEE 1,100 50000 1.3e-12 8.4e-15 + IEEE 1,10000 50000 3.0e-12 4.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invfdistribution(const ae_int_t a, const ae_int_t b, const double y, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Incomplete gamma integral + +The function is defined by + + x + - + 1 | | -t a-1 + igam(a,x) = ----- | e t dt. + - | | + | (a) - + 0 + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 200000 3.6e-14 2.9e-15 + IEEE 0,100 300000 9.9e-14 1.5e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegamma(const double a, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complemented incomplete gamma integral + +The function is defined by + + + igamc(a,x) = 1 - igam(a,x) + + inf. + - + 1 | | -t a-1 + = ----- | e t dt. + - | | + | (a) - + x + + +In this implementation both arguments must be positive. +The integral is evaluated by either a power series or +continued fraction expansion, depending on the relative +values of a and x. + +ACCURACY: + +Tested at random a, x. + a x Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,100 200000 1.9e-14 1.7e-15 + IEEE 0.01,0.5 0,100 200000 1.4e-13 1.6e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompletegammac(const double a, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse of complemented imcomplete gamma integral + +Given p, the function finds x such that + + igamc( a, x ) = p. + +Starting with the approximate value + + 3 + x = a t + + where + + t = 1 - d - ndtri(p) sqrt(d) + +and + + d = 1/9a, + +the routine performs up to 10 Newton iterations to find the +root of igamc(a,x) - p = 0. + +ACCURACY: + +Tested at random a, p in the intervals indicated. + + a p Relative error: +arithmetic domain domain # trials peak rms + IEEE 0.5,100 0,0.5 100000 1.0e-14 1.7e-15 + IEEE 0.01,0.5 0,0.5 100000 9.0e-14 3.4e-15 + IEEE 0.5,10000 0,0.5 20000 2.3e-13 3.8e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invincompletegammac(const double a, const double y0, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Chi-square distribution + +Returns the area under the left hand tail (from 0 to x) +of the Chi square probability density function with +v degrees of freedom. + + + x + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + 0 + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igam( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquaredistribution(const double v, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complemented Chi-square distribution + +Returns the area under the right hand tail (from x to +infinity) of the Chi square probability density function +with v degrees of freedom: + + inf. + - + 1 | | v/2-1 -t/2 + P( x | v ) = ----------- | t e dt + v/2 - | | + 2 | (v/2) - + x + +where x is the Chi-square variable. + +The incomplete gamma integral is used, according to the +formula + +y = chdtr( v, x ) = igamc( v/2.0, x/2.0 ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double chisquarecdistribution(const double v, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse of complemented Chi-square distribution + +Finds the Chi-square argument x such that the integral +from x to infinity of the Chi-square density is equal +to the given cumulative probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + x/2 = igami( df/2, y ); + +ACCURACY: + +See inverse incomplete gamma function + + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double invchisquaredistribution(const double v, const double y, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Binomial distribution + +Returns the sum of the terms 0 through k of the Binomial +probability density: + + k + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=0 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtr( k, n, p ) = incbet( n-k, k+1, 1-p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p), with p between 0 and 1. + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 4.3e-15 2.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialdistribution(const ae_int_t k, const ae_int_t n, const double p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complemented binomial distribution + +Returns the sum of the terms k+1 through n of the Binomial +probability density: + + n + -- ( n ) j n-j + > ( ) p (1-p) + -- ( j ) + j=k+1 + +The terms are not summed directly; instead the incomplete +beta integral is employed, according to the formula + +y = bdtrc( k, n, p ) = incbet( k+1, n-k, p ). + +The arguments must be positive, with p ranging from 0 to 1. + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 6.7e-15 8.2e-16 + For p between 0 and .001: + IEEE 0,100 100000 1.5e-13 2.7e-15 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double binomialcdistribution(const ae_int_t k, const ae_int_t n, const double p, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse binomial distribution + +Finds the event probability p such that the sum of the +terms 0 through k of the Binomial probability density +is equal to the given cumulative probability y. + +This is accomplished using the inverse beta integral +function and the relation + +1 - p = incbi( n-k, k+1, y ). + +ACCURACY: + +Tested at random points (a,b,p). + + a,b Relative error: +arithmetic domain # trials peak rms + For p between 0.001 and 1: + IEEE 0,100 100000 2.3e-14 6.4e-16 + IEEE 0,10000 100000 6.6e-12 1.2e-13 + For p between 10^-6 and 0.001: + IEEE 0,100 100000 2.0e-12 1.3e-14 + IEEE 0,10000 100000 1.5e-12 3.2e-14 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invbinomialdistribution(const ae_int_t k, const ae_int_t n, const double y, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Exponential integral Ei(x) + + x + - t + | | e + Ei(x) = -|- --- dt . + | | t + - + -inf + +Not defined for x <= 0. +See also expn.c. + + + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,100 50000 8.6e-16 1.3e-16 + +Cephes Math Library Release 2.8: May, 1999 +Copyright 1999 by Stephen L. Moshier +*************************************************************************/ +double exponentialintegralei(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Exponential integral En(x) + +Evaluates the exponential integral + + inf. + - + | | -xt + | e + E (x) = | ---- dt. + n | n + | | t + - + 1 + + +Both n and x must be nonnegative. + +The routine employs either a power series, a continued +fraction, or an asymptotic formula depending on the +relative values of n and x. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 10000 1.7e-15 3.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 2000 by Stephen L. Moshier +*************************************************************************/ +double exponentialintegralen(const double x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Jacobian Elliptic Functions + +Evaluates the Jacobian elliptic functions sn(u|m), cn(u|m), +and dn(u|m) of parameter m between 0 and 1, and real +argument u. + +These functions are periodic, with quarter-period on the +real axis equal to the complete elliptic integral +ellpk(1.0-m). + +Relation to incomplete elliptic integral: +If u = ellik(phi,m), then sn(u|m) = sin(phi), +and cn(u|m) = cos(phi). Phi is called the amplitude of u. + +Computation is by means of the arithmetic-geometric mean +algorithm, except when m is within 1e-9 of 0 or 1. In the +latter case with m close to 1, the approximation applies +only for phi < pi/2. + +ACCURACY: + +Tested at random points with u between 0 and 10, m between +0 and 1. + + Absolute error (* = relative error): +arithmetic function # trials peak rms + IEEE phi 10000 9.2e-16* 1.4e-16* + IEEE sn 50000 4.1e-15 4.6e-16 + IEEE cn 40000 3.6e-15 4.4e-16 + IEEE dn 10000 1.3e-12 1.8e-14 + + Peak error observed in consistency check using addition +theorem for sn(u+v) was 4e-16 (absolute). Also tested by +the above relation to the incomplete elliptic integral. +Accuracy deteriorates when u is large. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void jacobianellipticfunctions(const double u, const double m, double &sn, double &cn, double &dn, double &ph, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sine and cosine integrals + +Evaluates the integrals + + x + - + | cos t - 1 + Ci(x) = eul + ln x + | --------- dt, + | t + - + 0 + x + - + | sin t + Si(x) = | ----- dt + | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are approximated by rational functions. +For x > 8 auxiliary functions f(x) and g(x) are employed +such that + +Ci(x) = f(x) sin(x) - g(x) cos(x) +Si(x) = pi/2 - f(x) cos(x) - g(x) sin(x) + + +ACCURACY: + Test interval = [0,50]. +Absolute error, except relative when > 1: +arithmetic function # trials peak rms + IEEE Si 30000 4.4e-16 7.3e-17 + IEEE Ci 30000 6.9e-16 5.1e-17 + +Cephes Math Library Release 2.1: January, 1989 +Copyright 1984, 1987, 1989 by Stephen L. Moshier +*************************************************************************/ +void sinecosineintegrals(const double x, double &si, double &ci, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Hyperbolic sine and cosine integrals + +Approximates the integrals + + x + - + | | cosh t - 1 + Chi(x) = eul + ln x + | ----------- dt, + | | t + - + 0 + + x + - + | | sinh t + Shi(x) = | ------ dt + | | t + - + 0 + +where eul = 0.57721566490153286061 is Euler's constant. +The integrals are evaluated by power series for x < 8 +and by Chebyshev expansions for x between 8 and 88. +For large x, both functions approach exp(x)/2x. +Arguments greater than 88 in magnitude return MAXNUM. + + +ACCURACY: + +Test interval 0 to 88. + Relative error: +arithmetic function # trials peak rms + IEEE Shi 30000 6.9e-16 1.6e-16 + Absolute error, except relative when |Chi| > 1: + IEEE Chi 30000 8.4e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +void hyperbolicsinecosineintegrals(const double x, double &shi, double &chi, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Chebyshev polynomials of the +first and second kinds. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument, -1 <= x <= 1 + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevcalculate(const ae_int_t r, const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Summation of Chebyshev polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*T0(x) + c[1]*T1(x) + ... + c[N]*TN(x) +or + c[0]*U0(x) + c[1]*U1(x) + ... + c[N]*UN(x) +depending on the R. + +Parameters: + r - polynomial kind, either 1 or 2. + n - degree, n>=0 + x - argument + +Result: + the value of the Chebyshev polynomial at x +*************************************************************************/ +double chebyshevsum(const real_1d_array &c, const ae_int_t r, const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Representation of Tn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void chebyshevcoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Conversion of a series of Chebyshev polynomials to a power series. + +Represents A[0]*T0(x) + A[1]*T1(x) + ... + A[N]*Tn(x) as +B[0] + B[1]*X + ... + B[N]*X^N. + +Input parameters: + A - Chebyshev series coefficients + N - degree, N>=0 + +Output parameters + B - power series coefficients +*************************************************************************/ +void fromchebyshev(const real_1d_array &a, const ae_int_t n, real_1d_array &b, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Poisson distribution + +Returns the sum of the first k+1 terms of the Poisson +distribution: + + k j + -- -m m + > e -- + -- j! + j=0 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the relation + +y = pdtr( k, m ) = igamc( k+1, m ). + +The arguments must both be positive. +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissondistribution(const ae_int_t k, const double m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complemented Poisson distribution + +Returns the sum of the terms k+1 to infinity of the Poisson +distribution: + + inf. j + -- -m m + > e -- + -- j! + j=k+1 + +The terms are not summed directly; instead the incomplete +gamma integral is employed, according to the formula + +y = pdtrc( k, m ) = igam( k+1, m ). + +The arguments must both be positive. + +ACCURACY: + +See incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double poissoncdistribution(const ae_int_t k, const double m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Inverse Poisson distribution + +Finds the Poisson variable x such that the integral +from 0 to x of the Poisson density is equal to the +given probability y. + +This is accomplished using the inverse gamma integral +function and the relation + + m = igami( k+1, y ). + +ACCURACY: + +See inverse incomplete gamma function + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier +*************************************************************************/ +double invpoissondistribution(const ae_int_t k, const double y, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Beta function + + + - - + | (a) | (b) +beta( a, b ) = -----------. + - + | (a+b) + +For large arguments the logarithm of the function is +evaluated using lgam(), then exponentiated. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 8.1e-14 1.1e-14 + +Cephes Math Library Release 2.0: April, 1987 +Copyright 1984, 1987 by Stephen L. Moshier +*************************************************************************/ +double beta(const double a, const double b, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Fresnel integral + +Evaluates the Fresnel integrals + + x + - + | | +C(x) = | cos(pi/2 t**2) dt, + | | + - + 0 + + x + - + | | +S(x) = | sin(pi/2 t**2) dt. + | | + - + 0 + + +The integrals are evaluated by a power series for x < 1. +For x >= 1 auxiliary functions f(x) and g(x) are employed +such that + +C(x) = 0.5 + f(x) sin( pi/2 x**2 ) - g(x) cos( pi/2 x**2 ) +S(x) = 0.5 - f(x) cos( pi/2 x**2 ) - g(x) sin( pi/2 x**2 ) + + + +ACCURACY: + + Relative error. + +Arithmetic function domain # trials peak rms + IEEE S(x) 0, 10 10000 2.0e-15 3.2e-16 + IEEE C(x) 0, 10 10000 1.8e-15 3.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void fresnelintegral(const double x, double &c, double &s, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Psi (digamma) function + + d - + psi(x) = -- ln | (x) + dx + +is the logarithmic derivative of the gamma function. +For integer x, + n-1 + - +psi(n) = -EUL + > 1/k. + - + k=1 + +This formula is used for 0 < n <= 10. If x is negative, it +is transformed to a positive argument by the reflection +formula psi(1-x) = psi(x) + pi cot(pi x). +For general positive x, the argument is made greater than 10 +using the recurrence psi(x+1) = psi(x) + 1/x. +Then the following asymptotic expansion is applied: + + inf. B + - 2k +psi(x) = log(x) - 1/2x - > ------- + - 2k + k=1 2k x + +where the B2k are Bernoulli numbers. + +ACCURACY: + Relative error (except absolute when |psi| < 1): +arithmetic domain # trials peak rms + IEEE 0,30 30000 1.3e-15 1.4e-16 + IEEE -30,0 40000 1.5e-15 2.2e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1992, 2000 by Stephen L. Moshier +*************************************************************************/ +double psi(const double x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Airy function + +Solution of the differential equation + +y"(x) = xy. + +The function returns the two independent solutions Ai, Bi +and their first derivatives Ai'(x), Bi'(x). + +Evaluation is by power series summation for small x, +by rational minimax approximations for large x. + + + +ACCURACY: +Error criterion is absolute when function <= 1, relative +when function > 1, except * denotes relative error criterion. +For large negative x, the absolute error increases as x^1.5. +For large positive x, the relative error increases as x^1.5. + +Arithmetic domain function # trials peak rms +IEEE -10, 0 Ai 10000 1.6e-15 2.7e-16 +IEEE 0, 10 Ai 10000 2.3e-14* 1.8e-15* +IEEE -10, 0 Ai' 10000 4.6e-15 7.6e-16 +IEEE 0, 10 Ai' 10000 1.8e-14* 1.5e-15* +IEEE -10, 10 Bi 30000 4.2e-15 5.3e-16 +IEEE -10, 10 Bi' 30000 4.9e-15 7.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +void airy(const double x, double &ai, double &aip, double &bi, double &bip, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Dawson's Integral + +Approximates the integral + + x + - + 2 | | 2 + dawsn(x) = exp( -x ) | exp( t ) dt + | | + - + 0 + +Three different rational approximations are employed, for +the intervals 0 to 3.25; 3.25 to 6.25; and 6.25 up. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,10 10000 6.9e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double dawsonintegral(const double x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Hermite polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial Hn at x +*************************************************************************/ +double hermitecalculate(const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Summation of Hermite polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*H0(x) + c[1]*H1(x) + ... + c[N]*HN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Hermite polynomial at x +*************************************************************************/ +double hermitesum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Representation of Hn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void hermitecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Legendre polynomial Pn. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial Pn at x +*************************************************************************/ +double legendrecalculate(const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Summation of Legendre polynomials using Clenshaw's recurrence formula. + +This routine calculates + c[0]*P0(x) + c[1]*P1(x) + ... + c[N]*PN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Legendre polynomial at x +*************************************************************************/ +double legendresum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Representation of Pn as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void legendrecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Bessel function of order zero + +Returns Bessel function of order zero of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval the following rational +approximation is used: + + + 2 2 +(w - r ) (w - r ) P (w) / Q (w) + 1 2 3 8 + + 2 +where w = x and the two r's are zeros of the function. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 60000 4.2e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj0(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bessel function of order one + +Returns Bessel function of order one of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 24 term Chebyshev +expansion is used. In the second, the asymptotic +trigonometric representation is employed using two +rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 2.6e-16 1.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselj1(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bessel function of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The ratio of jn(x) to j0(x) is computed by backward +recurrence. First the ratio jn/jn-1 is found by a +continued fraction expansion. Then the recurrence +relating successive orders is applied until j0 or j1 is +reached. + +If n = 0 or 1 the routine for j0 or j1 is called +directly. + +ACCURACY: + + Absolute error: +arithmetic range # trials peak rms + IEEE 0, 30 5000 4.4e-16 7.9e-17 + + +Not suitable for large n or x. Use jv() (fractional order) instead. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseljn(const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bessel function of the second kind, order zero + +Returns Bessel function of the second kind, of order +zero, of the argument. + +The domain is divided into the intervals [0, 5] and +(5, infinity). In the first interval a rational approximation +R(x) is employed to compute + y0(x) = R(x) + 2 * log(x) * j0(x) / PI. +Thus a call to j0() is required. + +In the second interval, the Hankel asymptotic expansion +is employed with two rational functions of degree 6/6 +and 7/7. + + + +ACCURACY: + + Absolute error, when y0(x) < 1; else relative error: + +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.3e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely0(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bessel function of second kind of order one + +Returns Bessel function of the second kind of order one +of the argument. + +The domain is divided into the intervals [0, 8] and +(8, infinity). In the first interval a 25 term Chebyshev +expansion is used, and a call to j1() is required. +In the second, the asymptotic trigonometric representation +is employed using two rational functions of degree 5/5. + +ACCURACY: + + Absolute error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.0e-15 1.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double bessely1(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Bessel function of second kind of integer order + +Returns Bessel function of order n, where n is a +(possibly negative) integer. + +The function is evaluated by forward recurrence on +n, starting with values computed by the routines +y0() and y1(). + +If n = 0 or 1 the routine for y0 or y1 is called +directly. + +ACCURACY: + Absolute error, except relative + when y > 1: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 3.4e-15 4.3e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselyn(const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modified Bessel function of order zero + +Returns modified Bessel function of order zero of the +argument. + +The function is defined as i0(x) = j0( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 30000 5.8e-16 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli0(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modified Bessel function of order one + +Returns modified Bessel function of order one of the +argument. + +The function is defined as i1(x) = -i j1( ix ). + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.9e-15 2.1e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1985, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besseli1(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modified Bessel function, second kind, order zero + +Returns modified Bessel function of the second kind +of order zero of the argument. + +The range is partitioned into the two intervals [0,8] and +(8, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + +Tested at 2000 random points between 0 and 8. Peak absolute +error (relative when K0 > 1) was 1.46e-14; rms, 4.26e-15. + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk0(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modified Bessel function, second kind, order one + +Computes the modified Bessel function of the second kind +of order one of the argument. + +The range is partitioned into the two intervals [0,2] and +(2, infinity). Chebyshev polynomial expansions are employed +in each interval. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 30 30000 1.2e-15 1.6e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselk1(const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Modified Bessel function, second kind, integer order + +Returns modified Bessel function of the second kind +of order n of the argument. + +The range is partitioned into the two intervals [0,9.55] and +(9.55, infinity). An ascending power series is used in the +low range, and an asymptotic expansion in the high range. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,30 90000 1.8e-8 3.0e-10 + +Error is high only near the crossover point x = 9.55 +between the two expansions used. + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1988, 2000 by Stephen L. Moshier +*************************************************************************/ +double besselkn(const ae_int_t nn, const double x, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the value of the Laguerre polynomial. + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial Ln at x +*************************************************************************/ +double laguerrecalculate(const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Summation of Laguerre polynomials using Clenshaw's recurrence formula. + +This routine calculates c[0]*L0(x) + c[1]*L1(x) + ... + c[N]*LN(x) + +Parameters: + n - degree, n>=0 + x - argument + +Result: + the value of the Laguerre polynomial at x +*************************************************************************/ +double laguerresum(const real_1d_array &c, const ae_int_t n, const double x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Representation of Ln as C[0] + C[1]*X + ... + C[N]*X^N + +Input parameters: + N - polynomial degree, n>=0 + +Output parameters: + C - coefficients +*************************************************************************/ +void laguerrecoefficients(const ae_int_t n, real_1d_array &c, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +using the approximation + + P(x) - log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralk(const double m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complete elliptic integral of the first kind + +Approximates the integral + + + + pi/2 + - + | | + | dt +K(m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +where m = 1 - m1, using the approximation + + P(x) - log x Q(x). + +The argument m1 is used rather than m so that the logarithmic +singularity at m = 1 will be shifted to the origin; this +preserves maximum accuracy. + +K(0) = pi/2. + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0,1 30000 2.5e-16 6.8e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegralkhighprecision(const double m1, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Incomplete elliptic integral of the first kind F(phi|m) + +Approximates the integral + + + + phi + - + | | + | dt +F(phi_\m) = | ------------------ + | 2 + | | sqrt( 1 - m sin t ) + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + + + + +ACCURACY: + +Tested at random points with m in [0, 1] and phi as indicated. + + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 200000 7.4e-16 1.0e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegralk(const double phi, const double m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Complete elliptic integral of the second kind + +Approximates the integral + + + pi/2 + - + | | 2 +E(m) = | sqrt( 1 - m sin t ) dt + | | + - + 0 + +using the approximation + + P(x) - x log x Q(x). + +ACCURACY: + + Relative error: +arithmetic domain # trials peak rms + IEEE 0, 1 10000 2.1e-16 7.3e-17 + +Cephes Math Library, Release 2.8: June, 2000 +Copyright 1984, 1987, 1989, 2000 by Stephen L. Moshier +*************************************************************************/ +double ellipticintegrale(const double m, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Incomplete elliptic integral of the second kind + +Approximates the integral + + + phi + - + | | + | 2 +E(phi_\m) = | sqrt( 1 - m sin t ) dt + | + | | + - + 0 + +of amplitude phi and modulus m, using the arithmetic - +geometric mean algorithm. + +ACCURACY: + +Tested at random arguments with phi in [-10, 10] and m in +[0, 1]. + Relative error: +arithmetic domain # trials peak rms + IEEE -10,10 150000 3.3e-15 1.4e-16 + +Cephes Math Library Release 2.8: June, 2000 +Copyright 1984, 1987, 1993, 2000 by Stephen L. Moshier +*************************************************************************/ +double incompleteellipticintegrale(const double phi, const double m, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_GAMMAFUNC) || !defined(AE_PARTIAL_BUILD) +double gammafunction(double x, ae_state *_state); +double lngamma(double x, double* sgngam, ae_state *_state); +#endif +#if defined(AE_COMPILE_NORMALDISTR) || !defined(AE_PARTIAL_BUILD) +double errorfunction(double x, ae_state *_state); +double errorfunctionc(double x, ae_state *_state); +double normaldistribution(double x, ae_state *_state); +double normalpdf(double x, ae_state *_state); +double normalcdf(double x, ae_state *_state); +double inverf(double e, ae_state *_state); +double invnormaldistribution(double y0, ae_state *_state); +double invnormalcdf(double y0, ae_state *_state); +double bivariatenormalpdf(double x, + double y, + double rho, + ae_state *_state); +double bivariatenormalcdf(double x, + double y, + double rho, + ae_state *_state); +#endif +#if defined(AE_COMPILE_IBETAF) || !defined(AE_PARTIAL_BUILD) +double incompletebeta(double a, double b, double x, ae_state *_state); +double invincompletebeta(double a, double b, double y, ae_state *_state); +#endif +#if defined(AE_COMPILE_STUDENTTDISTR) || !defined(AE_PARTIAL_BUILD) +double studenttdistribution(ae_int_t k, double t, ae_state *_state); +double invstudenttdistribution(ae_int_t k, double p, ae_state *_state); +#endif +#if defined(AE_COMPILE_FDISTR) || !defined(AE_PARTIAL_BUILD) +double fdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); +double fcdistribution(ae_int_t a, ae_int_t b, double x, ae_state *_state); +double invfdistribution(ae_int_t a, + ae_int_t b, + double y, + ae_state *_state); +#endif +#if defined(AE_COMPILE_IGAMMAF) || !defined(AE_PARTIAL_BUILD) +double incompletegamma(double a, double x, ae_state *_state); +double incompletegammac(double a, double x, ae_state *_state); +double invincompletegammac(double a, double y0, ae_state *_state); +#endif +#if defined(AE_COMPILE_CHISQUAREDISTR) || !defined(AE_PARTIAL_BUILD) +double chisquaredistribution(double v, double x, ae_state *_state); +double chisquarecdistribution(double v, double x, ae_state *_state); +double invchisquaredistribution(double v, double y, ae_state *_state); +#endif +#if defined(AE_COMPILE_BINOMIALDISTR) || !defined(AE_PARTIAL_BUILD) +double binomialdistribution(ae_int_t k, + ae_int_t n, + double p, + ae_state *_state); +double binomialcdistribution(ae_int_t k, + ae_int_t n, + double p, + ae_state *_state); +double invbinomialdistribution(ae_int_t k, + ae_int_t n, + double y, + ae_state *_state); +#endif +#if defined(AE_COMPILE_EXPINTEGRALS) || !defined(AE_PARTIAL_BUILD) +double exponentialintegralei(double x, ae_state *_state); +double exponentialintegralen(double x, ae_int_t n, ae_state *_state); +#endif +#if defined(AE_COMPILE_JACOBIANELLIPTIC) || !defined(AE_PARTIAL_BUILD) +void jacobianellipticfunctions(double u, + double m, + double* sn, + double* cn, + double* dn, + double* ph, + ae_state *_state); +#endif +#if defined(AE_COMPILE_TRIGINTEGRALS) || !defined(AE_PARTIAL_BUILD) +void sinecosineintegrals(double x, + double* si, + double* ci, + ae_state *_state); +void hyperbolicsinecosineintegrals(double x, + double* shi, + double* chi, + ae_state *_state); +#endif +#if defined(AE_COMPILE_CHEBYSHEV) || !defined(AE_PARTIAL_BUILD) +double chebyshevcalculate(ae_int_t r, + ae_int_t n, + double x, + ae_state *_state); +double chebyshevsum(/* Real */ const ae_vector* c, + ae_int_t r, + ae_int_t n, + double x, + ae_state *_state); +void chebyshevcoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +void fromchebyshev(/* Real */ const ae_vector* a, + ae_int_t n, + /* Real */ ae_vector* b, + ae_state *_state); +#endif +#if defined(AE_COMPILE_POISSONDISTR) || !defined(AE_PARTIAL_BUILD) +double poissondistribution(ae_int_t k, double m, ae_state *_state); +double poissoncdistribution(ae_int_t k, double m, ae_state *_state); +double invpoissondistribution(ae_int_t k, double y, ae_state *_state); +#endif +#if defined(AE_COMPILE_BETAF) || !defined(AE_PARTIAL_BUILD) +double beta(double a, double b, ae_state *_state); +#endif +#if defined(AE_COMPILE_FRESNEL) || !defined(AE_PARTIAL_BUILD) +void fresnelintegral(double x, double* c, double* s, ae_state *_state); +#endif +#if defined(AE_COMPILE_PSIF) || !defined(AE_PARTIAL_BUILD) +double psi(double x, ae_state *_state); +#endif +#if defined(AE_COMPILE_AIRYF) || !defined(AE_PARTIAL_BUILD) +void airy(double x, + double* ai, + double* aip, + double* bi, + double* bip, + ae_state *_state); +#endif +#if defined(AE_COMPILE_DAWSON) || !defined(AE_PARTIAL_BUILD) +double dawsonintegral(double x, ae_state *_state); +#endif +#if defined(AE_COMPILE_HERMITE) || !defined(AE_PARTIAL_BUILD) +double hermitecalculate(ae_int_t n, double x, ae_state *_state); +double hermitesum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state); +void hermitecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +#endif +#if defined(AE_COMPILE_LEGENDRE) || !defined(AE_PARTIAL_BUILD) +double legendrecalculate(ae_int_t n, double x, ae_state *_state); +double legendresum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state); +void legendrecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +#endif +#if defined(AE_COMPILE_BESSEL) || !defined(AE_PARTIAL_BUILD) +double besselj0(double x, ae_state *_state); +double besselj1(double x, ae_state *_state); +double besseljn(ae_int_t n, double x, ae_state *_state); +double bessely0(double x, ae_state *_state); +double bessely1(double x, ae_state *_state); +double besselyn(ae_int_t n, double x, ae_state *_state); +double besseli0(double x, ae_state *_state); +double besseli1(double x, ae_state *_state); +double besselk0(double x, ae_state *_state); +double besselk1(double x, ae_state *_state); +double besselkn(ae_int_t nn, double x, ae_state *_state); +#endif +#if defined(AE_COMPILE_LAGUERRE) || !defined(AE_PARTIAL_BUILD) +double laguerrecalculate(ae_int_t n, double x, ae_state *_state); +double laguerresum(/* Real */ const ae_vector* c, + ae_int_t n, + double x, + ae_state *_state); +void laguerrecoefficients(ae_int_t n, + /* Real */ ae_vector* c, + ae_state *_state); +#endif +#if defined(AE_COMPILE_ELLIPTIC) || !defined(AE_PARTIAL_BUILD) +double ellipticintegralk(double m, ae_state *_state); +double ellipticintegralkhighprecision(double m1, ae_state *_state); +double incompleteellipticintegralk(double phi, double m, ae_state *_state); +double ellipticintegrale(double m, ae_state *_state); +double incompleteellipticintegrale(double phi, double m, ae_state *_state); +#endif + +} +#endif + diff --git a/core/alglib/statistics.cpp b/core/alglib/statistics.cpp index d59d0a2e..7a644029 100644 --- a/core/alglib/statistics.cpp +++ b/core/alglib/statistics.cpp @@ -1,19718 +1,24013 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#include "stdafx.h" -#include "statistics.h" - -// disable some irrelevant warnings -#if (AE_COMPILER==AE_MSVC) -#pragma warning(disable:4100) -#pragma warning(disable:4127) -#pragma warning(disable:4702) -#pragma warning(disable:4996) -#endif -using namespace std; - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Calculation of the distribution moments: mean, variance, skewness, kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -OUTPUT PARAMETERS - Mean - mean. - Variance- variance. - Skewness- skewness (if variance<>0; zero otherwise). - Kurtosis- kurtosis (if variance<>0; zero otherwise). - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplemoments(const_cast(x.c_ptr()), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the distribution moments: mean, variance, skewness, kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -OUTPUT PARAMETERS - Mean - mean. - Variance- variance. - Skewness- skewness (if variance<>0; zero otherwise). - Kurtosis- kurtosis (if variance<>0; zero otherwise). - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplemoments(const_cast(x.c_ptr()), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the mean. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Mean' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplemean(const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplemean(const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the mean. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Mean' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplemean(const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplemean(const_cast(x.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the variance. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Variance' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplevariance(const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplevariance(const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the variance. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Variance' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplevariance(const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplevariance(const_cast(x.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the skewness. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Skewness' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double sampleskewness(const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::sampleskewness(const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the skewness. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Skewness' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double sampleskewness(const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::sampleskewness(const_cast(x.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Kurtosis' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplekurtosis(const real_1d_array &x, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplekurtosis(const_cast(x.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Calculation of the kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Kurtosis' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplekurtosis(const real_1d_array &x) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::samplekurtosis(const_cast(x.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -ADev - -Input parameters: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - ADev- ADev - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sampleadev(const_cast(x.c_ptr()), n, &adev, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -ADev - -Input parameters: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - ADev- ADev - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void sampleadev(const real_1d_array &x, double &adev) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::sampleadev(const_cast(x.c_ptr()), n, &adev, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Median calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - Median - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemedian(const real_1d_array &x, const ae_int_t n, double &median) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplemedian(const_cast(x.c_ptr()), n, &median, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Median calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - Median - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemedian(const real_1d_array &x, double &median) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplemedian(const_cast(x.c_ptr()), n, &median, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Percentile calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - P - percentile (0<=P<=1) - -Output parameters: - V - percentile - - -- ALGLIB -- - Copyright 01.03.2008 by Bochkanov Sergey -*************************************************************************/ -void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplepercentile(const_cast(x.c_ptr()), n, p, &v, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Percentile calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - P - percentile (0<=P<=1) - -Output parameters: - V - percentile - - -- ALGLIB -- - Copyright 01.03.2008 by Bochkanov Sergey -*************************************************************************/ -void samplepercentile(const real_1d_array &x, const double p, double &v) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::samplepercentile(const_cast(x.c_ptr()), n, p, &v, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -2-sample covariance - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - covariance (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cov2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -2-sample covariance - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - covariance (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double cov2(const real_1d_array &x, const real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'cov2': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::cov2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Pearson product-moment correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::pearsoncorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Pearson product-moment correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorr2(const real_1d_array &x, const real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'pearsoncorr2': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::pearsoncorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Spearman's rank correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spearmancorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Spearman's rank correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmancorr2(const real_1d_array &x, const real_1d_array &y) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - if( (x.length()!=y.length())) - throw ap_error("Error while calling 'spearmancorr2': looks like one of arguments has wrong size"); - n = x.length(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spearmancorr2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_covm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_covm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_pearsoncorrm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_pearsoncorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_spearmancorrm(const real_2d_array &x, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m; - - n = x.rows(); - m = x.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_spearmancorrm(const_cast(x.c_ptr()), n, m, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cross-covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Cross-covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'covm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'covm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_covm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson product-moment cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'pearsoncorrm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'pearsoncorrm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_pearsoncorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'spearmancorrm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t n; - ae_int_t m1; - ae_int_t m2; - if( (x.rows()!=y.rows())) - throw ap_error("Error while calling 'spearmancorrm2': looks like one of arguments has wrong size"); - n = x.rows(); - m1 = x.cols(); - m2 = y.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_spearmancorrm2(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, m1, m2, const_cast(c.c_ptr()), &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rankdata(real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - ae_int_t nfeatures; - - npoints = xy.rows(); - nfeatures = xy.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rankdata(real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - ae_int_t nfeatures; - - npoints = xy.rows(); - nfeatures = xy.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rankdata(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* - -*************************************************************************/ -void rankdatacentered(real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - ae_int_t nfeatures; - - npoints = xy.rows(); - nfeatures = xy.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - - -void smp_rankdatacentered(real_2d_array &xy) -{ - alglib_impl::ae_state _alglib_env_state; - ae_int_t npoints; - ae_int_t nfeatures; - - npoints = xy.rows(); - nfeatures = xy.cols(); - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::_pexec_rankdatacentered(const_cast(xy.c_ptr()), npoints, nfeatures, &_alglib_env_state); - - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete function, we recommend to use PearsonCorr2(). - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::pearsoncorrelation(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Obsolete function, we recommend to use SpearmanCorr2(). - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - double result = alglib_impl::spearmanrankcorrelation(const_cast(x.c_ptr()), const_cast(y.c_ptr()), n, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return *(reinterpret_cast(&result)); - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Pearson's correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5 - * normality of distributions of X and Y. - -Input parameters: - R - Pearson's correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::pearsoncorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Spearman's rank correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5. - -The test is non-parametric and doesn't require distributions X and Y to be -normal. - -Input parameters: - R - Spearman's rank correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::spearmanrankcorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Jarque-Bera test - -This test checks hypotheses about the fact that a given sample X is a -sample of normal random variable. - -Requirements: - * the number of elements in the sample is not less than 5. - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -Accuracy of the approximation used (5<=N<=1951): - -p-value relative error (5<=N<=1951) -[1, 0.1] < 1% -[0.1, 0.01] < 2% -[0.01, 0.001] < 6% -[0.001, 0] wasn't measured - -For N>1951 accuracy wasn't measured but it shouldn't be sharply different -from table values. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::jarqueberatest(const_cast(x.c_ptr()), n, &p, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Mann-Whitney U-test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions of the same shape and same median or whether -their medians are different. - -The following tests are performed: - * two-tailed test (null hypothesis - the medians are equal) - * left-tailed test (null hypothesis - the median of the first sample - is greater than or equal to the median of the second sample) - * right-tailed test (null hypothesis - the median of the first sample - is less than or equal to the median of the second sample). - -Requirements: - * the samples are independent - * X and Y are continuous distributions (or discrete distributions well- - approximating continuous distributions) - * distributions of X and Y have the same shape. The only possible - difference is their position (i.e. the value of the median) - * the number of elements in each sample is not less than 5 - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distributions to be normal. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. M>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with satisfactory accuracy in interval [0.0001, 1]. -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - -Relative precision of approximation of p-value: - -N M Max.err. Rms.err. -5..10 N..10 1.4e-02 6.0e-04 -5..10 N..100 2.2e-02 5.3e-06 -10..15 N..15 1.0e-02 3.2e-04 -10..15 N..100 1.0e-02 2.2e-05 -15..100 N..100 6.1e-03 2.7e-06 - -For N,M>100 accuracy checks weren't put into practice, but taking into -account characteristics of asymptotic approximation used, precision should -not be sharply different from the values for interval [5, 100]. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::mannwhitneyutest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Sign test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -While calculating p-values high-precision binomial distribution -approximation is used, so significance levels have about 15 exact digits. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::onesamplesigntest(const_cast(x.c_ptr()), n, median, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -One-sample t-test - -This test checks three hypotheses about the mean of the given sample. The -following tests are performed: - * two-tailed test (null hypothesis - the mean is equal to the given - value) - * left-tailed test (null hypothesis - the mean is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the mean is less than or equal - to the given value). - -The test is based on the assumption that a given sample has a normal -distribution and an unknown dispersion. If the distribution sharply -differs from normal, the test will work incorrectly. - -INPUT PARAMETERS: - X - sample. Array whose index goes from 0 to N-1. - N - size of sample, N>=0 - Mean - assumed value of the mean. - -OUTPUT PARAMETERS: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0, all p-values are set to 1.0 - * when variance of X[] is exactly zero, p-values are set - to 1.0 or 0.0, depending on difference between sample mean and - value of mean being tested. - - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::studentttest1(const_cast(x.c_ptr()), n, mean, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Two-sample pooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * dispersions are equal - * samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has exactly zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::studentttest2(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Two-sample unpooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * samples are independent. -Equality of variances is NOT required. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - * when only one sample has zero variance, test reduces to 1-sample - version. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::unequalvariancettest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Two-sample F-test - -This test checks three hypotheses about dispersions of the given samples. -The following tests are performed: - * two-tailed test (null hypothesis - the dispersions are equal) - * left-tailed test (null hypothesis - the dispersion of the first - sample is greater than or equal to the dispersion of the second - sample). - * right-tailed test (null hypothesis - the dispersion of the first - sample is less than or equal to the dispersion of the second sample) - -The test is based on the following assumptions: - * the given samples have normal distributions - * the samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - sample size. - Y - sample 2. Array whose index goes from 0 to M-1. - M - sample size. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::ftest(const_cast(x.c_ptr()), n, const_cast(y.c_ptr()), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -One-sample chi-square test - -This test checks three hypotheses about the dispersion of the given sample -The following tests are performed: - * two-tailed test (null hypothesis - the dispersion equals the given - number) - * left-tailed test (null hypothesis - the dispersion is greater than - or equal to the given number) - * right-tailed test (null hypothesis - dispersion is less than or - equal to the given number). - -Test is based on the following assumptions: - * the given sample has a normal distribution. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Variance - dispersion value to compare with. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::onesamplevariancetest(const_cast(x.c_ptr()), n, variance, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} - -/************************************************************************* -Wilcoxon signed-rank test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - * the distribution should be continuous and symmetric relative to its - median. - * number of distinct values in the X array should be greater than 4 - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with two decimal places in interval [0.0001, 1]. - -"Two decimal places" does not sound very impressive, but in practice the -relative error of less than 1% is enough to make a decision. - -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail) -{ - alglib_impl::ae_state _alglib_env_state; - alglib_impl::ae_state_init(&_alglib_env_state); - try - { - alglib_impl::wilcoxonsignedranktest(const_cast(x.c_ptr()), n, e, &bothtails, &lefttail, &righttail, &_alglib_env_state); - alglib_impl::ae_state_clear(&_alglib_env_state); - return; - } - catch(alglib_impl::ae_error_type) - { - throw ap_error(_alglib_env_state.error_msg); - } -} -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -static void basestat_rankdatarec(/* Real */ ae_matrix* xy, - ae_int_t i0, - ae_int_t i1, - ae_int_t nfeatures, - ae_bool iscentered, - ae_shared_pool* pool, - ae_int_t basecasecost, - ae_state *_state); -static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, - ae_int_t i0, - ae_int_t i1, - ae_int_t nfeatures, - ae_bool iscentered, - apbuffers* buf0, - apbuffers* buf1, - ae_state *_state); - - -static double correlationtests_spearmantail5(double s, ae_state *_state); -static double correlationtests_spearmantail6(double s, ae_state *_state); -static double correlationtests_spearmantail7(double s, ae_state *_state); -static double correlationtests_spearmantail8(double s, ae_state *_state); -static double correlationtests_spearmantail9(double s, ae_state *_state); -static double correlationtests_spearmantail(double t, - ae_int_t n, - ae_state *_state); - - -static void jarquebera_jarqueberastatistic(/* Real */ ae_vector* x, - ae_int_t n, - double* s, - ae_state *_state); -static double jarquebera_jarqueberaapprox(ae_int_t n, - double s, - ae_state *_state); -static double jarquebera_jbtbl5(double s, ae_state *_state); -static double jarquebera_jbtbl6(double s, ae_state *_state); -static double jarquebera_jbtbl7(double s, ae_state *_state); -static double jarquebera_jbtbl8(double s, ae_state *_state); -static double jarquebera_jbtbl9(double s, ae_state *_state); -static double jarquebera_jbtbl10(double s, ae_state *_state); -static double jarquebera_jbtbl11(double s, ae_state *_state); -static double jarquebera_jbtbl12(double s, ae_state *_state); -static double jarquebera_jbtbl13(double s, ae_state *_state); -static double jarquebera_jbtbl14(double s, ae_state *_state); -static double jarquebera_jbtbl15(double s, ae_state *_state); -static double jarquebera_jbtbl16(double s, ae_state *_state); -static double jarquebera_jbtbl17(double s, ae_state *_state); -static double jarquebera_jbtbl18(double s, ae_state *_state); -static double jarquebera_jbtbl19(double s, ae_state *_state); -static double jarquebera_jbtbl20(double s, ae_state *_state); -static double jarquebera_jbtbl30(double s, ae_state *_state); -static double jarquebera_jbtbl50(double s, ae_state *_state); -static double jarquebera_jbtbl65(double s, ae_state *_state); -static double jarquebera_jbtbl100(double s, ae_state *_state); -static double jarquebera_jbtbl130(double s, ae_state *_state); -static double jarquebera_jbtbl200(double s, ae_state *_state); -static double jarquebera_jbtbl301(double s, ae_state *_state); -static double jarquebera_jbtbl501(double s, ae_state *_state); -static double jarquebera_jbtbl701(double s, ae_state *_state); -static double jarquebera_jbtbl1401(double s, ae_state *_state); -static void jarquebera_jbcheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state); - - -static void mannwhitneyu_ucheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state); -static double mannwhitneyu_uninterpolate(double p1, - double p2, - double p3, - ae_int_t n, - ae_state *_state); -static double mannwhitneyu_usigma000(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma075(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma150(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma225(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma300(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma333(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma367(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_usigma400(ae_int_t n1, - ae_int_t n2, - ae_state *_state); -static double mannwhitneyu_utbln5n5(double s, ae_state *_state); -static double mannwhitneyu_utbln5n6(double s, ae_state *_state); -static double mannwhitneyu_utbln5n7(double s, ae_state *_state); -static double mannwhitneyu_utbln5n8(double s, ae_state *_state); -static double mannwhitneyu_utbln5n9(double s, ae_state *_state); -static double mannwhitneyu_utbln5n10(double s, ae_state *_state); -static double mannwhitneyu_utbln5n11(double s, ae_state *_state); -static double mannwhitneyu_utbln5n12(double s, ae_state *_state); -static double mannwhitneyu_utbln5n13(double s, ae_state *_state); -static double mannwhitneyu_utbln5n14(double s, ae_state *_state); -static double mannwhitneyu_utbln5n15(double s, ae_state *_state); -static double mannwhitneyu_utbln5n16(double s, ae_state *_state); -static double mannwhitneyu_utbln5n17(double s, ae_state *_state); -static double mannwhitneyu_utbln5n18(double s, ae_state *_state); -static double mannwhitneyu_utbln5n19(double s, ae_state *_state); -static double mannwhitneyu_utbln5n20(double s, ae_state *_state); -static double mannwhitneyu_utbln5n21(double s, ae_state *_state); -static double mannwhitneyu_utbln5n22(double s, ae_state *_state); -static double mannwhitneyu_utbln5n23(double s, ae_state *_state); -static double mannwhitneyu_utbln5n24(double s, ae_state *_state); -static double mannwhitneyu_utbln5n25(double s, ae_state *_state); -static double mannwhitneyu_utbln5n26(double s, ae_state *_state); -static double mannwhitneyu_utbln5n27(double s, ae_state *_state); -static double mannwhitneyu_utbln5n28(double s, ae_state *_state); -static double mannwhitneyu_utbln5n29(double s, ae_state *_state); -static double mannwhitneyu_utbln5n30(double s, ae_state *_state); -static double mannwhitneyu_utbln5n100(double s, ae_state *_state); -static double mannwhitneyu_utbln6n6(double s, ae_state *_state); -static double mannwhitneyu_utbln6n7(double s, ae_state *_state); -static double mannwhitneyu_utbln6n8(double s, ae_state *_state); -static double mannwhitneyu_utbln6n9(double s, ae_state *_state); -static double mannwhitneyu_utbln6n10(double s, ae_state *_state); -static double mannwhitneyu_utbln6n11(double s, ae_state *_state); -static double mannwhitneyu_utbln6n12(double s, ae_state *_state); -static double mannwhitneyu_utbln6n13(double s, ae_state *_state); -static double mannwhitneyu_utbln6n14(double s, ae_state *_state); -static double mannwhitneyu_utbln6n15(double s, ae_state *_state); -static double mannwhitneyu_utbln6n30(double s, ae_state *_state); -static double mannwhitneyu_utbln6n100(double s, ae_state *_state); -static double mannwhitneyu_utbln7n7(double s, ae_state *_state); -static double mannwhitneyu_utbln7n8(double s, ae_state *_state); -static double mannwhitneyu_utbln7n9(double s, ae_state *_state); -static double mannwhitneyu_utbln7n10(double s, ae_state *_state); -static double mannwhitneyu_utbln7n11(double s, ae_state *_state); -static double mannwhitneyu_utbln7n12(double s, ae_state *_state); -static double mannwhitneyu_utbln7n13(double s, ae_state *_state); -static double mannwhitneyu_utbln7n14(double s, ae_state *_state); -static double mannwhitneyu_utbln7n15(double s, ae_state *_state); -static double mannwhitneyu_utbln7n30(double s, ae_state *_state); -static double mannwhitneyu_utbln7n100(double s, ae_state *_state); -static double mannwhitneyu_utbln8n8(double s, ae_state *_state); -static double mannwhitneyu_utbln8n9(double s, ae_state *_state); -static double mannwhitneyu_utbln8n10(double s, ae_state *_state); -static double mannwhitneyu_utbln8n11(double s, ae_state *_state); -static double mannwhitneyu_utbln8n12(double s, ae_state *_state); -static double mannwhitneyu_utbln8n13(double s, ae_state *_state); -static double mannwhitneyu_utbln8n14(double s, ae_state *_state); -static double mannwhitneyu_utbln8n15(double s, ae_state *_state); -static double mannwhitneyu_utbln8n30(double s, ae_state *_state); -static double mannwhitneyu_utbln8n100(double s, ae_state *_state); -static double mannwhitneyu_utbln9n9(double s, ae_state *_state); -static double mannwhitneyu_utbln9n10(double s, ae_state *_state); -static double mannwhitneyu_utbln9n11(double s, ae_state *_state); -static double mannwhitneyu_utbln9n12(double s, ae_state *_state); -static double mannwhitneyu_utbln9n13(double s, ae_state *_state); -static double mannwhitneyu_utbln9n14(double s, ae_state *_state); -static double mannwhitneyu_utbln9n15(double s, ae_state *_state); -static double mannwhitneyu_utbln9n30(double s, ae_state *_state); -static double mannwhitneyu_utbln9n100(double s, ae_state *_state); -static double mannwhitneyu_utbln10n10(double s, ae_state *_state); -static double mannwhitneyu_utbln10n11(double s, ae_state *_state); -static double mannwhitneyu_utbln10n12(double s, ae_state *_state); -static double mannwhitneyu_utbln10n13(double s, ae_state *_state); -static double mannwhitneyu_utbln10n14(double s, ae_state *_state); -static double mannwhitneyu_utbln10n15(double s, ae_state *_state); -static double mannwhitneyu_utbln10n30(double s, ae_state *_state); -static double mannwhitneyu_utbln10n100(double s, ae_state *_state); -static double mannwhitneyu_utbln11n11(double s, ae_state *_state); -static double mannwhitneyu_utbln11n12(double s, ae_state *_state); -static double mannwhitneyu_utbln11n13(double s, ae_state *_state); -static double mannwhitneyu_utbln11n14(double s, ae_state *_state); -static double mannwhitneyu_utbln11n15(double s, ae_state *_state); -static double mannwhitneyu_utbln11n30(double s, ae_state *_state); -static double mannwhitneyu_utbln11n100(double s, ae_state *_state); -static double mannwhitneyu_utbln12n12(double s, ae_state *_state); -static double mannwhitneyu_utbln12n13(double s, ae_state *_state); -static double mannwhitneyu_utbln12n14(double s, ae_state *_state); -static double mannwhitneyu_utbln12n15(double s, ae_state *_state); -static double mannwhitneyu_utbln12n30(double s, ae_state *_state); -static double mannwhitneyu_utbln12n100(double s, ae_state *_state); -static double mannwhitneyu_utbln13n13(double s, ae_state *_state); -static double mannwhitneyu_utbln13n14(double s, ae_state *_state); -static double mannwhitneyu_utbln13n15(double s, ae_state *_state); -static double mannwhitneyu_utbln13n30(double s, ae_state *_state); -static double mannwhitneyu_utbln13n100(double s, ae_state *_state); -static double mannwhitneyu_utbln14n14(double s, ae_state *_state); -static double mannwhitneyu_utbln14n15(double s, ae_state *_state); -static double mannwhitneyu_utbln14n30(double s, ae_state *_state); -static double mannwhitneyu_utbln14n100(double s, ae_state *_state); -static double mannwhitneyu_usigma(double s, - ae_int_t n1, - ae_int_t n2, - ae_state *_state); - - - - - - - - -static void wsr_wcheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state); -static double wsr_w5(double s, ae_state *_state); -static double wsr_w6(double s, ae_state *_state); -static double wsr_w7(double s, ae_state *_state); -static double wsr_w8(double s, ae_state *_state); -static double wsr_w9(double s, ae_state *_state); -static double wsr_w10(double s, ae_state *_state); -static double wsr_w11(double s, ae_state *_state); -static double wsr_w12(double s, ae_state *_state); -static double wsr_w13(double s, ae_state *_state); -static double wsr_w14(double s, ae_state *_state); -static double wsr_w15(double s, ae_state *_state); -static double wsr_w16(double s, ae_state *_state); -static double wsr_w17(double s, ae_state *_state); -static double wsr_w18(double s, ae_state *_state); -static double wsr_w19(double s, ae_state *_state); -static double wsr_w20(double s, ae_state *_state); -static double wsr_w21(double s, ae_state *_state); -static double wsr_w22(double s, ae_state *_state); -static double wsr_w23(double s, ae_state *_state); -static double wsr_w24(double s, ae_state *_state); -static double wsr_w25(double s, ae_state *_state); -static double wsr_w26(double s, ae_state *_state); -static double wsr_w27(double s, ae_state *_state); -static double wsr_w28(double s, ae_state *_state); -static double wsr_w29(double s, ae_state *_state); -static double wsr_w30(double s, ae_state *_state); -static double wsr_w40(double s, ae_state *_state); -static double wsr_w60(double s, ae_state *_state); -static double wsr_w120(double s, ae_state *_state); -static double wsr_w200(double s, ae_state *_state); -static double wsr_wsigma(double s, ae_int_t n, ae_state *_state); - - - - - -/************************************************************************* -Calculation of the distribution moments: mean, variance, skewness, kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -OUTPUT PARAMETERS - Mean - mean. - Variance- variance. - Skewness- skewness (if variance<>0; zero otherwise). - Kurtosis- kurtosis (if variance<>0; zero otherwise). - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemoments(/* Real */ ae_vector* x, - ae_int_t n, - double* mean, - double* variance, - double* skewness, - double* kurtosis, - ae_state *_state) -{ - ae_int_t i; - double v; - double v1; - double v2; - double stddev; - - *mean = 0; - *variance = 0; - *skewness = 0; - *kurtosis = 0; - - ae_assert(n>=0, "SampleMoments: N<0", _state); - ae_assert(x->cnt>=n, "SampleMoments: Length(X)ptr.p_double[i]; - } - *mean = *mean/n; - - /* - * Variance (using corrected two-pass algorithm) - */ - if( n!=1 ) - { - v1 = 0; - for(i=0; i<=n-1; i++) - { - v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); - } - v2 = 0; - for(i=0; i<=n-1; i++) - { - v2 = v2+(x->ptr.p_double[i]-(*mean)); - } - v2 = ae_sqr(v2, _state)/n; - *variance = (v1-v2)/(n-1); - if( ae_fp_less(*variance,0) ) - { - *variance = 0; - } - stddev = ae_sqrt(*variance, _state); - } - - /* - * Skewness and kurtosis - */ - if( ae_fp_neq(stddev,0) ) - { - for(i=0; i<=n-1; i++) - { - v = (x->ptr.p_double[i]-(*mean))/stddev; - v2 = ae_sqr(v, _state); - *skewness = *skewness+v2*v; - *kurtosis = *kurtosis+ae_sqr(v2, _state); - } - *skewness = *skewness/n; - *kurtosis = *kurtosis/n-3; - } -} - - -/************************************************************************* -Calculation of the mean. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Mean' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplemean(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double mean; - double tmp0; - double tmp1; - double tmp2; - double result; - - - samplemoments(x, n, &mean, &tmp0, &tmp1, &tmp2, _state); - result = mean; - return result; -} - - -/************************************************************************* -Calculation of the variance. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Variance' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplevariance(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double variance; - double tmp0; - double tmp1; - double tmp2; - double result; - - - samplemoments(x, n, &tmp0, &variance, &tmp1, &tmp2, _state); - result = variance; - return result; -} - - -/************************************************************************* -Calculation of the skewness. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Skewness' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double sampleskewness(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double skewness; - double tmp0; - double tmp1; - double tmp2; - double result; - - - samplemoments(x, n, &tmp0, &tmp1, &skewness, &tmp2, _state); - result = skewness; - return result; -} - - -/************************************************************************* -Calculation of the kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Kurtosis' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplekurtosis(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state) -{ - double kurtosis; - double tmp0; - double tmp1; - double tmp2; - double result; - - - samplemoments(x, n, &tmp0, &tmp1, &tmp2, &kurtosis, _state); - result = kurtosis; - return result; -} - - -/************************************************************************* -ADev - -Input parameters: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - ADev- ADev - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void sampleadev(/* Real */ ae_vector* x, - ae_int_t n, - double* adev, - ae_state *_state) -{ - ae_int_t i; - double mean; - - *adev = 0; - - ae_assert(n>=0, "SampleADev: N<0", _state); - ae_assert(x->cnt>=n, "SampleADev: Length(X)ptr.p_double[i]; - } - mean = mean/n; - - /* - * ADev - */ - for(i=0; i<=n-1; i++) - { - *adev = *adev+ae_fabs(x->ptr.p_double[i]-mean, _state); - } - *adev = *adev/n; -} - - -/************************************************************************* -Median calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - Median - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemedian(/* Real */ ae_vector* x, - ae_int_t n, - double* median, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_int_t i; - ae_int_t ir; - ae_int_t j; - ae_int_t l; - ae_int_t midp; - ae_int_t k; - double a; - double tval; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - *median = 0; - - ae_assert(n>=0, "SampleMedian: N<0", _state); - ae_assert(x->cnt>=n, "SampleMedian: Length(X)ptr.p_double[0]; - ae_frame_leave(_state); - return; - } - if( n==2 ) - { - *median = 0.5*(x->ptr.p_double[0]+x->ptr.p_double[1]); - ae_frame_leave(_state); - return; - } - - /* - * Common case, N>=3. - * Choose X[(N-1)/2] - */ - l = 0; - ir = n-1; - k = (n-1)/2; - for(;;) - { - if( ir<=l+1 ) - { - - /* - * 1 or 2 elements in partition - */ - if( ir==l+1&&ae_fp_less(x->ptr.p_double[ir],x->ptr.p_double[l]) ) - { - tval = x->ptr.p_double[l]; - x->ptr.p_double[l] = x->ptr.p_double[ir]; - x->ptr.p_double[ir] = tval; - } - break; - } - else - { - midp = (l+ir)/2; - tval = x->ptr.p_double[midp]; - x->ptr.p_double[midp] = x->ptr.p_double[l+1]; - x->ptr.p_double[l+1] = tval; - if( ae_fp_greater(x->ptr.p_double[l],x->ptr.p_double[ir]) ) - { - tval = x->ptr.p_double[l]; - x->ptr.p_double[l] = x->ptr.p_double[ir]; - x->ptr.p_double[ir] = tval; - } - if( ae_fp_greater(x->ptr.p_double[l+1],x->ptr.p_double[ir]) ) - { - tval = x->ptr.p_double[l+1]; - x->ptr.p_double[l+1] = x->ptr.p_double[ir]; - x->ptr.p_double[ir] = tval; - } - if( ae_fp_greater(x->ptr.p_double[l],x->ptr.p_double[l+1]) ) - { - tval = x->ptr.p_double[l]; - x->ptr.p_double[l] = x->ptr.p_double[l+1]; - x->ptr.p_double[l+1] = tval; - } - i = l+1; - j = ir; - a = x->ptr.p_double[l+1]; - for(;;) - { - do - { - i = i+1; - } - while(ae_fp_less(x->ptr.p_double[i],a)); - do - { - j = j-1; - } - while(ae_fp_greater(x->ptr.p_double[j],a)); - if( jptr.p_double[i]; - x->ptr.p_double[i] = x->ptr.p_double[j]; - x->ptr.p_double[j] = tval; - } - x->ptr.p_double[l+1] = x->ptr.p_double[j]; - x->ptr.p_double[j] = a; - if( j>=k ) - { - ir = j-1; - } - if( j<=k ) - { - l = i; - } - } - } - - /* - * If N is odd, return result - */ - if( n%2==1 ) - { - *median = x->ptr.p_double[k]; - ae_frame_leave(_state); - return; - } - a = x->ptr.p_double[n-1]; - for(i=k+1; i<=n-1; i++) - { - if( ae_fp_less(x->ptr.p_double[i],a) ) - { - a = x->ptr.p_double[i]; - } - } - *median = 0.5*(x->ptr.p_double[k]+a); - ae_frame_leave(_state); -} - - -/************************************************************************* -Percentile calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - P - percentile (0<=P<=1) - -Output parameters: - V - percentile - - -- ALGLIB -- - Copyright 01.03.2008 by Bochkanov Sergey -*************************************************************************/ -void samplepercentile(/* Real */ ae_vector* x, - ae_int_t n, - double p, - double* v, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_int_t i1; - double t; - ae_vector rbuf; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - *v = 0; - ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "SamplePercentile: N<0", _state); - ae_assert(x->cnt>=n, "SamplePercentile: Length(X)ptr.p_double[0]; - ae_frame_leave(_state); - return; - } - if( ae_fp_eq(p,1) ) - { - *v = x->ptr.p_double[n-1]; - ae_frame_leave(_state); - return; - } - t = p*(n-1); - i1 = ae_ifloor(t, _state); - t = t-ae_ifloor(t, _state); - *v = x->ptr.p_double[i1]*(1-t)+x->ptr.p_double[i1+1]*t; - ae_frame_leave(_state); -} - - -/************************************************************************* -2-sample covariance - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - covariance (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double cov2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - double xmean; - double ymean; - double v; - double x0; - double y0; - double s; - ae_bool samex; - ae_bool samey; - double result; - - - ae_assert(n>=0, "Cov2: N<0", _state); - ae_assert(x->cnt>=n, "Cov2: Length(X)cnt>=n, "Cov2: Length(Y)ptr.p_double[0]; - y0 = y->ptr.p_double[0]; - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - s = x->ptr.p_double[i]; - samex = samex&&ae_fp_eq(s,x0); - xmean = xmean+s*v; - s = y->ptr.p_double[i]; - samey = samey&&ae_fp_eq(s,y0); - ymean = ymean+s*v; - } - if( samex||samey ) - { - result = 0; - return result; - } - - /* - * covariance - */ - v = (double)1/(double)(n-1); - result = 0; - for(i=0; i<=n-1; i++) - { - result = result+v*(x->ptr.p_double[i]-xmean)*(y->ptr.p_double[i]-ymean); - } - return result; -} - - -/************************************************************************* -Pearson product-moment correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Pearson product-moment correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorr2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state) -{ - ae_int_t i; - double xmean; - double ymean; - double v; - double x0; - double y0; - double s; - ae_bool samex; - ae_bool samey; - double xv; - double yv; - double t1; - double t2; - double result; - - - ae_assert(n>=0, "PearsonCorr2: N<0", _state); - ae_assert(x->cnt>=n, "PearsonCorr2: Length(X)cnt>=n, "PearsonCorr2: Length(Y)ptr.p_double[0]; - y0 = y->ptr.p_double[0]; - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - s = x->ptr.p_double[i]; - samex = samex&&ae_fp_eq(s,x0); - xmean = xmean+s*v; - s = y->ptr.p_double[i]; - samey = samey&&ae_fp_eq(s,y0); - ymean = ymean+s*v; - } - if( samex||samey ) - { - result = 0; - return result; - } - - /* - * numerator and denominator - */ - s = 0; - xv = 0; - yv = 0; - for(i=0; i<=n-1; i++) - { - t1 = x->ptr.p_double[i]-xmean; - t2 = y->ptr.p_double[i]-ymean; - xv = xv+ae_sqr(t1, _state); - yv = yv+ae_sqr(t2, _state); - s = s+t1*t2; - } - if( ae_fp_eq(xv,0)||ae_fp_eq(yv,0) ) - { - result = 0; - } - else - { - result = s/(ae_sqrt(xv, _state)*ae_sqrt(yv, _state)); - } - return result; -} - - -/************************************************************************* -Spearman's rank correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Spearman's rank correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmancorr2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_vector _y; - apbuffers buf; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_vector_init_copy(&_y, y, _state, ae_true); - y = &_y; - _apbuffers_init(&buf, _state, ae_true); - - ae_assert(n>=0, "SpearmanCorr2: N<0", _state); - ae_assert(x->cnt>=n, "SpearmanCorr2: Length(X)cnt>=n, "SpearmanCorr2: Length(Y)=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _x; - ae_int_t i; - ae_int_t j; - double v; - ae_vector t; - ae_vector x0; - ae_vector same; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_matrix_clear(c); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&same, 0, DT_BOOL, _state, ae_true); - - ae_assert(n>=0, "CovM: N<0", _state); - ae_assert(m>=1, "CovM: M<1", _state); - ae_assert(x->rows>=n, "CovM: Rows(X)cols>=m||n==0, "CovM: Cols(X)ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Calculate means, - * check for constant columns - */ - ae_vector_set_length(&t, m, _state); - ae_vector_set_length(&x0, m, _state); - ae_vector_set_length(&same, m, _state); - ae_matrix_set_length(c, m, m, _state); - for(i=0; i<=m-1; i++) - { - t.ptr.p_double[i] = 0; - same.ptr.p_bool[i] = ae_true; - } - ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m-1)); - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); - for(j=0; j<=m-1; j++) - { - same.ptr.p_bool[j] = same.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); - } - } - - /* - * * center variables; - * * if we have constant columns, these columns are - * artificially zeroed (they must be zero in exact arithmetics, - * but unfortunately floating point ops are not exact). - * * calculate upper half of symmetric covariance matrix - */ - for(i=0; i<=n-1; i++) - { - ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m-1)); - for(j=0; j<=m-1; j++) - { - if( same.ptr.p_bool[j] ) - { - x->ptr.pp_double[i][j] = 0; - } - } - } - rmatrixsyrk(m, n, (double)1/(double)(n-1), x, 0, 0, 1, 0.0, c, 0, 0, ae_true, _state); - rmatrixenforcesymmetricity(c, m, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_covm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state) -{ - covm(x,n,m,c, _state); -} - - -/************************************************************************* -Pearson product-moment correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector t; - ae_int_t i; - ae_int_t j; - double v; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(c); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "PearsonCorrM: N<0", _state); - ae_assert(m>=1, "PearsonCorrM: M<1", _state); - ae_assert(x->rows>=n, "PearsonCorrM: Rows(X)cols>=m||n==0, "PearsonCorrM: Cols(X)ptr.pp_double[i][i],0) ) - { - t.ptr.p_double[i] = 1/ae_sqrt(c->ptr.pp_double[i][i], _state); - } - else - { - t.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m-1; i++) - { - v = t.ptr.p_double[i]; - for(j=0; j<=m-1; j++) - { - c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_pearsoncorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state) -{ - pearsoncorrm(x,n,m,c, _state); -} - - -/************************************************************************* -Spearman's rank correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - apbuffers buf; - ae_matrix xc; - ae_vector t; - double v; - double vv; - double x0; - ae_bool b; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(c); - _apbuffers_init(&buf, _state, ae_true); - ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - - ae_assert(n>=0, "SpearmanCorrM: N<0", _state); - ae_assert(m>=1, "SpearmanCorrM: M<1", _state); - ae_assert(x->rows>=n, "SpearmanCorrM: Rows(X)cols>=m||n==0, "SpearmanCorrM: Cols(X)ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Allocate - */ - ae_vector_set_length(&t, ae_maxint(n, m, _state), _state); - ae_matrix_set_length(c, m, m, _state); - - /* - * Replace data with ranks - */ - ae_matrix_set_length(&xc, m, n, _state); - rmatrixtranspose(n, m, x, 0, 0, &xc, 0, 0, _state); - rankdata(&xc, m, n, _state); - - /* - * 1. Calculate means, check for constant columns - * 2. Center variables, constant columns are - * artificialy zeroed (they must be zero in exact arithmetics, - * but unfortunately floating point is not exact). - */ - for(i=0; i<=m-1; i++) - { - - /* - * Calculate: - * * V - mean value of I-th variable - * * B - True in case all variable values are same - */ - v = 0; - b = ae_true; - x0 = xc.ptr.pp_double[i][0]; - for(j=0; j<=n-1; j++) - { - vv = xc.ptr.pp_double[i][j]; - v = v+vv; - b = b&&ae_fp_eq(vv,x0); - } - v = v/n; - - /* - * Center/zero I-th variable - */ - if( b ) - { - - /* - * Zero - */ - for(j=0; j<=n-1; j++) - { - xc.ptr.pp_double[i][j] = 0.0; - } - } - else - { - - /* - * Center - */ - for(j=0; j<=n-1; j++) - { - xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]-v; - } - } - } - - /* - * Calculate upper half of symmetric covariance matrix - */ - rmatrixsyrk(m, n, (double)1/(double)(n-1), &xc, 0, 0, 0, 0.0, c, 0, 0, ae_true, _state); - - /* - * Calculate Pearson coefficients (upper triangle) - */ - for(i=0; i<=m-1; i++) - { - if( ae_fp_greater(c->ptr.pp_double[i][i],0) ) - { - t.ptr.p_double[i] = 1/ae_sqrt(c->ptr.pp_double[i][i], _state); - } - else - { - t.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m-1; i++) - { - v = t.ptr.p_double[i]; - for(j=i; j<=m-1; j++) - { - c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; - } - } - - /* - * force symmetricity - */ - rmatrixenforcesymmetricity(c, m, ae_true, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_spearmancorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state) -{ - spearmancorrm(x,n,m,c, _state); -} - - -/************************************************************************* -Cross-covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _x; - ae_matrix _y; - ae_int_t i; - ae_int_t j; - double v; - ae_vector t; - ae_vector x0; - ae_vector y0; - ae_vector samex; - ae_vector samey; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_matrix_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_matrix_clear(c); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&samex, 0, DT_BOOL, _state, ae_true); - ae_vector_init(&samey, 0, DT_BOOL, _state, ae_true); - - ae_assert(n>=0, "CovM2: N<0", _state); - ae_assert(m1>=1, "CovM2: M1<1", _state); - ae_assert(m2>=1, "CovM2: M2<1", _state); - ae_assert(x->rows>=n, "CovM2: Rows(X)cols>=m1||n==0, "CovM2: Cols(X)rows>=n, "CovM2: Rows(Y)cols>=m2||n==0, "CovM2: Cols(Y)ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Allocate - */ - ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); - ae_vector_set_length(&x0, m1, _state); - ae_vector_set_length(&y0, m2, _state); - ae_vector_set_length(&samex, m1, _state); - ae_vector_set_length(&samey, m2, _state); - ae_matrix_set_length(c, m1, m2, _state); - - /* - * * calculate means of X - * * center X - * * if we have constant columns, these columns are - * artificially zeroed (they must be zero in exact arithmetics, - * but unfortunately floating point ops are not exact). - */ - for(i=0; i<=m1-1; i++) - { - t.ptr.p_double[i] = 0; - samex.ptr.p_bool[i] = ae_true; - } - ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); - for(j=0; j<=m1-1; j++) - { - samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); - } - } - for(i=0; i<=n-1; i++) - { - ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); - for(j=0; j<=m1-1; j++) - { - if( samex.ptr.p_bool[j] ) - { - x->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * Repeat same steps for Y - */ - for(i=0; i<=m2-1; i++) - { - t.ptr.p_double[i] = 0; - samey.ptr.p_bool[i] = ae_true; - } - ae_v_move(&y0.ptr.p_double[0], 1, &y->ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - ae_v_addd(&t.ptr.p_double[0], 1, &y->ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); - for(j=0; j<=m2-1; j++) - { - samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y->ptr.pp_double[i][j],y0.ptr.p_double[j]); - } - } - for(i=0; i<=n-1; i++) - { - ae_v_sub(&y->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); - for(j=0; j<=m2-1; j++) - { - if( samey.ptr.p_bool[j] ) - { - y->ptr.pp_double[i][j] = 0; - } - } - } - - /* - * calculate cross-covariance matrix - */ - rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), x, 0, 0, 1, y, 0, 0, 0, 0.0, c, 0, 0, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_covm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state) -{ - covm2(x,y,n,m1,m2,c, _state); -} - - -/************************************************************************* -Pearson product-moment cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_matrix _x; - ae_matrix _y; - ae_int_t i; - ae_int_t j; - double v; - ae_vector t; - ae_vector x0; - ae_vector y0; - ae_vector sx; - ae_vector sy; - ae_vector samex; - ae_vector samey; - - ae_frame_make(_state, &_frame_block); - ae_matrix_init_copy(&_x, x, _state, ae_true); - x = &_x; - ae_matrix_init_copy(&_y, y, _state, ae_true); - y = &_y; - ae_matrix_clear(c); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&y0, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); - ae_vector_init(&samex, 0, DT_BOOL, _state, ae_true); - ae_vector_init(&samey, 0, DT_BOOL, _state, ae_true); - - ae_assert(n>=0, "PearsonCorrM2: N<0", _state); - ae_assert(m1>=1, "PearsonCorrM2: M1<1", _state); - ae_assert(m2>=1, "PearsonCorrM2: M2<1", _state); - ae_assert(x->rows>=n, "PearsonCorrM2: Rows(X)cols>=m1||n==0, "PearsonCorrM2: Cols(X)rows>=n, "PearsonCorrM2: Rows(Y)cols>=m2||n==0, "PearsonCorrM2: Cols(Y)ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Allocate - */ - ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); - ae_vector_set_length(&x0, m1, _state); - ae_vector_set_length(&y0, m2, _state); - ae_vector_set_length(&sx, m1, _state); - ae_vector_set_length(&sy, m2, _state); - ae_vector_set_length(&samex, m1, _state); - ae_vector_set_length(&samey, m2, _state); - ae_matrix_set_length(c, m1, m2, _state); - - /* - * * calculate means of X - * * center X - * * if we have constant columns, these columns are - * artificially zeroed (they must be zero in exact arithmetics, - * but unfortunately floating point ops are not exact). - * * calculate column variances - */ - for(i=0; i<=m1-1; i++) - { - t.ptr.p_double[i] = 0; - samex.ptr.p_bool[i] = ae_true; - sx.ptr.p_double[i] = 0; - } - ae_v_move(&x0.ptr.p_double[0], 1, &x->ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - ae_v_addd(&t.ptr.p_double[0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); - for(j=0; j<=m1-1; j++) - { - samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x->ptr.pp_double[i][j],x0.ptr.p_double[j]); - } - } - for(i=0; i<=n-1; i++) - { - ae_v_sub(&x->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); - for(j=0; j<=m1-1; j++) - { - if( samex.ptr.p_bool[j] ) - { - x->ptr.pp_double[i][j] = 0; - } - sx.ptr.p_double[j] = sx.ptr.p_double[j]+x->ptr.pp_double[i][j]*x->ptr.pp_double[i][j]; - } - } - for(j=0; j<=m1-1; j++) - { - sx.ptr.p_double[j] = ae_sqrt(sx.ptr.p_double[j]/(n-1), _state); - } - - /* - * Repeat same steps for Y - */ - for(i=0; i<=m2-1; i++) - { - t.ptr.p_double[i] = 0; - samey.ptr.p_bool[i] = ae_true; - sy.ptr.p_double[i] = 0; - } - ae_v_move(&y0.ptr.p_double[0], 1, &y->ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); - v = (double)1/(double)n; - for(i=0; i<=n-1; i++) - { - ae_v_addd(&t.ptr.p_double[0], 1, &y->ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); - for(j=0; j<=m2-1; j++) - { - samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y->ptr.pp_double[i][j],y0.ptr.p_double[j]); - } - } - for(i=0; i<=n-1; i++) - { - ae_v_sub(&y->ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); - for(j=0; j<=m2-1; j++) - { - if( samey.ptr.p_bool[j] ) - { - y->ptr.pp_double[i][j] = 0; - } - sy.ptr.p_double[j] = sy.ptr.p_double[j]+y->ptr.pp_double[i][j]*y->ptr.pp_double[i][j]; - } - } - for(j=0; j<=m2-1; j++) - { - sy.ptr.p_double[j] = ae_sqrt(sy.ptr.p_double[j]/(n-1), _state); - } - - /* - * calculate cross-covariance matrix - */ - rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), x, 0, 0, 1, y, 0, 0, 0, 0.0, c, 0, 0, _state); - - /* - * Divide by standard deviations - */ - for(i=0; i<=m1-1; i++) - { - if( ae_fp_neq(sx.ptr.p_double[i],0) ) - { - sx.ptr.p_double[i] = 1/sx.ptr.p_double[i]; - } - else - { - sx.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m2-1; i++) - { - if( ae_fp_neq(sy.ptr.p_double[i],0) ) - { - sy.ptr.p_double[i] = 1/sy.ptr.p_double[i]; - } - else - { - sy.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m1-1; i++) - { - v = sx.ptr.p_double[i]; - for(j=0; j<=m2-1; j++) - { - c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_pearsoncorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state) -{ - pearsoncorrm2(x,y,n,m1,m2,c, _state); -} - - -/************************************************************************* -Spearman's rank cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - double v; - double v2; - double vv; - ae_bool b; - ae_vector t; - double x0; - double y0; - ae_vector sx; - ae_vector sy; - ae_matrix xc; - ae_matrix yc; - apbuffers buf; - - ae_frame_make(_state, &_frame_block); - ae_matrix_clear(c); - ae_vector_init(&t, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&yc, 0, 0, DT_REAL, _state, ae_true); - _apbuffers_init(&buf, _state, ae_true); - - ae_assert(n>=0, "SpearmanCorrM2: N<0", _state); - ae_assert(m1>=1, "SpearmanCorrM2: M1<1", _state); - ae_assert(m2>=1, "SpearmanCorrM2: M2<1", _state); - ae_assert(x->rows>=n, "SpearmanCorrM2: Rows(X)cols>=m1||n==0, "SpearmanCorrM2: Cols(X)rows>=n, "SpearmanCorrM2: Rows(Y)cols>=m2||n==0, "SpearmanCorrM2: Cols(Y)ptr.pp_double[i][j] = 0; - } - } - ae_frame_leave(_state); - return; - } - - /* - * Allocate - */ - ae_vector_set_length(&t, ae_maxint(ae_maxint(m1, m2, _state), n, _state), _state); - ae_vector_set_length(&sx, m1, _state); - ae_vector_set_length(&sy, m2, _state); - ae_matrix_set_length(c, m1, m2, _state); - - /* - * Replace data with ranks - */ - ae_matrix_set_length(&xc, m1, n, _state); - ae_matrix_set_length(&yc, m2, n, _state); - rmatrixtranspose(n, m1, x, 0, 0, &xc, 0, 0, _state); - rmatrixtranspose(n, m2, y, 0, 0, &yc, 0, 0, _state); - rankdata(&xc, m1, n, _state); - rankdata(&yc, m2, n, _state); - - /* - * 1. Calculate means, variances, check for constant columns - * 2. Center variables, constant columns are - * artificialy zeroed (they must be zero in exact arithmetics, - * but unfortunately floating point is not exact). - * - * Description of variables: - * * V - mean value of I-th variable - * * V2- variance - * * VV-temporary - * * B - True in case all variable values are same - */ - for(i=0; i<=m1-1; i++) - { - v = 0; - v2 = 0.0; - b = ae_true; - x0 = xc.ptr.pp_double[i][0]; - for(j=0; j<=n-1; j++) - { - vv = xc.ptr.pp_double[i][j]; - v = v+vv; - b = b&&ae_fp_eq(vv,x0); - } - v = v/n; - if( b ) - { - for(j=0; j<=n-1; j++) - { - xc.ptr.pp_double[i][j] = 0.0; - } - } - else - { - for(j=0; j<=n-1; j++) - { - vv = xc.ptr.pp_double[i][j]; - xc.ptr.pp_double[i][j] = vv-v; - v2 = v2+(vv-v)*(vv-v); - } - } - sx.ptr.p_double[i] = ae_sqrt(v2/(n-1), _state); - } - for(i=0; i<=m2-1; i++) - { - v = 0; - v2 = 0.0; - b = ae_true; - y0 = yc.ptr.pp_double[i][0]; - for(j=0; j<=n-1; j++) - { - vv = yc.ptr.pp_double[i][j]; - v = v+vv; - b = b&&ae_fp_eq(vv,y0); - } - v = v/n; - if( b ) - { - for(j=0; j<=n-1; j++) - { - yc.ptr.pp_double[i][j] = 0.0; - } - } - else - { - for(j=0; j<=n-1; j++) - { - vv = yc.ptr.pp_double[i][j]; - yc.ptr.pp_double[i][j] = vv-v; - v2 = v2+(vv-v)*(vv-v); - } - } - sy.ptr.p_double[i] = ae_sqrt(v2/(n-1), _state); - } - - /* - * calculate cross-covariance matrix - */ - rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), &xc, 0, 0, 0, &yc, 0, 0, 1, 0.0, c, 0, 0, _state); - - /* - * Divide by standard deviations - */ - for(i=0; i<=m1-1; i++) - { - if( ae_fp_neq(sx.ptr.p_double[i],0) ) - { - sx.ptr.p_double[i] = 1/sx.ptr.p_double[i]; - } - else - { - sx.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m2-1; i++) - { - if( ae_fp_neq(sy.ptr.p_double[i],0) ) - { - sy.ptr.p_double[i] = 1/sy.ptr.p_double[i]; - } - else - { - sy.ptr.p_double[i] = 0.0; - } - } - for(i=0; i<=m1-1; i++) - { - v = sx.ptr.p_double[i]; - for(j=0; j<=m2-1; j++) - { - c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; - } - } - ae_frame_leave(_state); -} - - -/************************************************************************* -Single-threaded stub. HPC ALGLIB replaces it by multithreaded code. -*************************************************************************/ -void _pexec_spearmancorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state) -{ - spearmancorrm2(x,y,n,m1,m2,c, _state); -} - - -void rankdata(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_state *_state) -{ - ae_frame _frame_block; - apbuffers buf0; - apbuffers buf1; - ae_int_t basecasecost; - ae_shared_pool pool; - - ae_frame_make(_state, &_frame_block); - _apbuffers_init(&buf0, _state, ae_true); - _apbuffers_init(&buf1, _state, ae_true); - ae_shared_pool_init(&pool, _state, ae_true); - - ae_assert(npoints>=0, "RankData: NPoints<0", _state); - ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); - ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=0, "RankData: NPoints<0", _state); - ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); - ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=i0, "RankDataRec: internal error", _state); - - /* - * Recursively split problem, if it is too large - */ - problemcost = inttoreal(i1-i0, _state)*inttoreal(nfeatures, _state)*log2(nfeatures, _state); - if( i1-i0>=2&&ae_fp_greater(problemcost,basecasecost) ) - { - im = (i1+i0)/2; - basestat_rankdatarec(xy, i0, im, nfeatures, iscentered, pool, basecasecost, _state); - basestat_rankdatarec(xy, im, i1, nfeatures, iscentered, pool, basecasecost, _state); - ae_frame_leave(_state); - return; - } - - /* - * Retrieve buffers from pool, call serial code, return buffers to pool - */ - ae_shared_pool_retrieve(pool, &_buf0, _state); - ae_shared_pool_retrieve(pool, &_buf1, _state); - basestat_rankdatabasecase(xy, i0, i1, nfeatures, iscentered, buf0, buf1, _state); - ae_shared_pool_recycle(pool, &_buf0, _state); - ae_shared_pool_recycle(pool, &_buf1, _state); - ae_frame_leave(_state); -} - - -static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, - ae_int_t i0, - ae_int_t i1, - ae_int_t nfeatures, - ae_bool iscentered, - apbuffers* buf0, - apbuffers* buf1, - ae_state *_state) -{ - ae_int_t i; - - - ae_assert(i1>=i0, "RankDataBasecase: internal error", _state); - if( buf1->ra0.cntra0, nfeatures, _state); - } - for(i=i0; i<=i1-1; i++) - { - ae_v_move(&buf1->ra0.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); - rankx(&buf1->ra0, nfeatures, iscentered, buf0, _state); - ae_v_move(&xy->ptr.pp_double[i][0], 1, &buf1->ra0.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); - } -} - - - - -/************************************************************************* -Pearson's correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5 - * normality of distributions of X and Y. - -Input parameters: - R - Pearson's correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrelationsignificance(double r, - ae_int_t n, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - double t; - double p; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - - /* - * Some special cases - */ - if( ae_fp_greater_eq(r,1) ) - { - *bothtails = 0.0; - *lefttail = 1.0; - *righttail = 0.0; - return; - } - if( ae_fp_less_eq(r,-1) ) - { - *bothtails = 0.0; - *lefttail = 0.0; - *righttail = 1.0; - return; - } - if( n<5 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * General case - */ - t = r*ae_sqrt((n-2)/(1-ae_sqr(r, _state)), _state); - p = studenttdistribution(n-2, t, _state); - *bothtails = 2*ae_minreal(p, 1-p, _state); - *lefttail = p; - *righttail = 1-p; -} - - -/************************************************************************* -Spearman's rank correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5. - -The test is non-parametric and doesn't require distributions X and Y to be -normal. - -Input parameters: - R - Spearman's rank correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void spearmanrankcorrelationsignificance(double r, - ae_int_t n, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - double t; - double p; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - - /* - * Special case - */ - if( n<5 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * General case - */ - if( ae_fp_greater_eq(r,1) ) - { - t = 1.0E10; - } - else - { - if( ae_fp_less_eq(r,-1) ) - { - t = -1.0E10; - } - else - { - t = r*ae_sqrt((n-2)/(1-ae_sqr(r, _state)), _state); - } - } - if( ae_fp_less(t,0) ) - { - p = correlationtests_spearmantail(t, n, _state); - *bothtails = 2*p; - *lefttail = p; - *righttail = 1-p; - } - else - { - p = correlationtests_spearmantail(-t, n, _state); - *bothtails = 2*p; - *lefttail = 1-p; - *righttail = p; - } -} - - -/************************************************************************* -Tail(S, 5) -*************************************************************************/ -static double correlationtests_spearmantail5(double s, ae_state *_state) -{ - double result; - - - if( ae_fp_less(s,0.000e+00) ) - { - result = studenttdistribution(3, -s, _state); - return result; - } - if( ae_fp_greater_eq(s,3.580e+00) ) - { - result = 8.304e-03; - return result; - } - if( ae_fp_greater_eq(s,2.322e+00) ) - { - result = 4.163e-02; - return result; - } - if( ae_fp_greater_eq(s,1.704e+00) ) - { - result = 6.641e-02; - return result; - } - if( ae_fp_greater_eq(s,1.303e+00) ) - { - result = 1.164e-01; - return result; - } - if( ae_fp_greater_eq(s,1.003e+00) ) - { - result = 1.748e-01; - return result; - } - if( ae_fp_greater_eq(s,7.584e-01) ) - { - result = 2.249e-01; - return result; - } - if( ae_fp_greater_eq(s,5.468e-01) ) - { - result = 2.581e-01; - return result; - } - if( ae_fp_greater_eq(s,3.555e-01) ) - { - result = 3.413e-01; - return result; - } - if( ae_fp_greater_eq(s,1.759e-01) ) - { - result = 3.911e-01; - return result; - } - if( ae_fp_greater_eq(s,1.741e-03) ) - { - result = 4.747e-01; - return result; - } - if( ae_fp_greater_eq(s,0.000e+00) ) - { - result = 5.248e-01; - return result; - } - result = 0; - return result; -} - - -/************************************************************************* -Tail(S, 6) -*************************************************************************/ -static double correlationtests_spearmantail6(double s, ae_state *_state) -{ - double result; - - - if( ae_fp_less(s,1.001e+00) ) - { - result = studenttdistribution(4, -s, _state); - return result; - } - if( ae_fp_greater_eq(s,5.663e+00) ) - { - result = 1.366e-03; - return result; - } - if( ae_fp_greater_eq(s,3.834e+00) ) - { - result = 8.350e-03; - return result; - } - if( ae_fp_greater_eq(s,2.968e+00) ) - { - result = 1.668e-02; - return result; - } - if( ae_fp_greater_eq(s,2.430e+00) ) - { - result = 2.921e-02; - return result; - } - if( ae_fp_greater_eq(s,2.045e+00) ) - { - result = 5.144e-02; - return result; - } - if( ae_fp_greater_eq(s,1.747e+00) ) - { - result = 6.797e-02; - return result; - } - if( ae_fp_greater_eq(s,1.502e+00) ) - { - result = 8.752e-02; - return result; - } - if( ae_fp_greater_eq(s,1.295e+00) ) - { - result = 1.210e-01; - return result; - } - if( ae_fp_greater_eq(s,1.113e+00) ) - { - result = 1.487e-01; - return result; - } - if( ae_fp_greater_eq(s,1.001e+00) ) - { - result = 1.780e-01; - return result; - } - result = 0; - return result; -} - - -/************************************************************************* -Tail(S, 7) -*************************************************************************/ -static double correlationtests_spearmantail7(double s, ae_state *_state) -{ - double result; - - - if( ae_fp_less(s,1.001e+00) ) - { - result = studenttdistribution(5, -s, _state); - return result; - } - if( ae_fp_greater_eq(s,8.159e+00) ) - { - result = 2.081e-04; - return result; - } - if( ae_fp_greater_eq(s,5.620e+00) ) - { - result = 1.393e-03; - return result; - } - if( ae_fp_greater_eq(s,4.445e+00) ) - { - result = 3.398e-03; - return result; - } - if( ae_fp_greater_eq(s,3.728e+00) ) - { - result = 6.187e-03; - return result; - } - if( ae_fp_greater_eq(s,3.226e+00) ) - { - result = 1.200e-02; - return result; - } - if( ae_fp_greater_eq(s,2.844e+00) ) - { - result = 1.712e-02; - return result; - } - if( ae_fp_greater_eq(s,2.539e+00) ) - { - result = 2.408e-02; - return result; - } - if( ae_fp_greater_eq(s,2.285e+00) ) - { - result = 3.320e-02; - return result; - } - if( ae_fp_greater_eq(s,2.068e+00) ) - { - result = 4.406e-02; - return result; - } - if( ae_fp_greater_eq(s,1.879e+00) ) - { - result = 5.478e-02; - return result; - } - if( ae_fp_greater_eq(s,1.710e+00) ) - { - result = 6.946e-02; - return result; - } - if( ae_fp_greater_eq(s,1.559e+00) ) - { - result = 8.331e-02; - return result; - } - if( ae_fp_greater_eq(s,1.420e+00) ) - { - result = 1.001e-01; - return result; - } - if( ae_fp_greater_eq(s,1.292e+00) ) - { - result = 1.180e-01; - return result; - } - if( ae_fp_greater_eq(s,1.173e+00) ) - { - result = 1.335e-01; - return result; - } - if( ae_fp_greater_eq(s,1.062e+00) ) - { - result = 1.513e-01; - return result; - } - if( ae_fp_greater_eq(s,1.001e+00) ) - { - result = 1.770e-01; - return result; - } - result = 0; - return result; -} - - -/************************************************************************* -Tail(S, 8) -*************************************************************************/ -static double correlationtests_spearmantail8(double s, ae_state *_state) -{ - double result; - - - if( ae_fp_less(s,2.001e+00) ) - { - result = studenttdistribution(6, -s, _state); - return result; - } - if( ae_fp_greater_eq(s,1.103e+01) ) - { - result = 2.194e-05; - return result; - } - if( ae_fp_greater_eq(s,7.685e+00) ) - { - result = 2.008e-04; - return result; - } - if( ae_fp_greater_eq(s,6.143e+00) ) - { - result = 5.686e-04; - return result; - } - if( ae_fp_greater_eq(s,5.213e+00) ) - { - result = 1.138e-03; - return result; - } - if( ae_fp_greater_eq(s,4.567e+00) ) - { - result = 2.310e-03; - return result; - } - if( ae_fp_greater_eq(s,4.081e+00) ) - { - result = 3.634e-03; - return result; - } - if( ae_fp_greater_eq(s,3.697e+00) ) - { - result = 5.369e-03; - return result; - } - if( ae_fp_greater_eq(s,3.381e+00) ) - { - result = 7.708e-03; - return result; - } - if( ae_fp_greater_eq(s,3.114e+00) ) - { - result = 1.087e-02; - return result; - } - if( ae_fp_greater_eq(s,2.884e+00) ) - { - result = 1.397e-02; - return result; - } - if( ae_fp_greater_eq(s,2.682e+00) ) - { - result = 1.838e-02; - return result; - } - if( ae_fp_greater_eq(s,2.502e+00) ) - { - result = 2.288e-02; - return result; - } - if( ae_fp_greater_eq(s,2.340e+00) ) - { - result = 2.883e-02; - return result; - } - if( ae_fp_greater_eq(s,2.192e+00) ) - { - result = 3.469e-02; - return result; - } - if( ae_fp_greater_eq(s,2.057e+00) ) - { - result = 4.144e-02; - return result; - } - if( ae_fp_greater_eq(s,2.001e+00) ) - { - result = 4.804e-02; - return result; - } - result = 0; - return result; -} - - -/************************************************************************* -Tail(S, 9) -*************************************************************************/ -static double correlationtests_spearmantail9(double s, ae_state *_state) -{ - double result; - - - if( ae_fp_less(s,2.001e+00) ) - { - result = studenttdistribution(7, -s, _state); - return result; - } - if( ae_fp_greater_eq(s,9.989e+00) ) - { - result = 2.306e-05; - return result; - } - if( ae_fp_greater_eq(s,8.069e+00) ) - { - result = 8.167e-05; - return result; - } - if( ae_fp_greater_eq(s,6.890e+00) ) - { - result = 1.744e-04; - return result; - } - if( ae_fp_greater_eq(s,6.077e+00) ) - { - result = 3.625e-04; - return result; - } - if( ae_fp_greater_eq(s,5.469e+00) ) - { - result = 6.450e-04; - return result; - } - if( ae_fp_greater_eq(s,4.991e+00) ) - { - result = 1.001e-03; - return result; - } - if( ae_fp_greater_eq(s,4.600e+00) ) - { - result = 1.514e-03; - return result; - } - if( ae_fp_greater_eq(s,4.272e+00) ) - { - result = 2.213e-03; - return result; - } - if( ae_fp_greater_eq(s,3.991e+00) ) - { - result = 2.990e-03; - return result; - } - if( ae_fp_greater_eq(s,3.746e+00) ) - { - result = 4.101e-03; - return result; - } - if( ae_fp_greater_eq(s,3.530e+00) ) - { - result = 5.355e-03; - return result; - } - if( ae_fp_greater_eq(s,3.336e+00) ) - { - result = 6.887e-03; - return result; - } - if( ae_fp_greater_eq(s,3.161e+00) ) - { - result = 8.598e-03; - return result; - } - if( ae_fp_greater_eq(s,3.002e+00) ) - { - result = 1.065e-02; - return result; - } - if( ae_fp_greater_eq(s,2.855e+00) ) - { - result = 1.268e-02; - return result; - } - if( ae_fp_greater_eq(s,2.720e+00) ) - { - result = 1.552e-02; - return result; - } - if( ae_fp_greater_eq(s,2.595e+00) ) - { - result = 1.836e-02; - return result; - } - if( ae_fp_greater_eq(s,2.477e+00) ) - { - result = 2.158e-02; - return result; - } - if( ae_fp_greater_eq(s,2.368e+00) ) - { - result = 2.512e-02; - return result; - } - if( ae_fp_greater_eq(s,2.264e+00) ) - { - result = 2.942e-02; - return result; - } - if( ae_fp_greater_eq(s,2.166e+00) ) - { - result = 3.325e-02; - return result; - } - if( ae_fp_greater_eq(s,2.073e+00) ) - { - result = 3.800e-02; - return result; - } - if( ae_fp_greater_eq(s,2.001e+00) ) - { - result = 4.285e-02; - return result; - } - result = 0; - return result; -} - - -/************************************************************************* -Tail(T,N), accepts T<0 -*************************************************************************/ -static double correlationtests_spearmantail(double t, - ae_int_t n, - ae_state *_state) -{ - double result; - - - if( n==5 ) - { - result = correlationtests_spearmantail5(-t, _state); - return result; - } - if( n==6 ) - { - result = correlationtests_spearmantail6(-t, _state); - return result; - } - if( n==7 ) - { - result = correlationtests_spearmantail7(-t, _state); - return result; - } - if( n==8 ) - { - result = correlationtests_spearmantail8(-t, _state); - return result; - } - if( n==9 ) - { - result = correlationtests_spearmantail9(-t, _state); - return result; - } - result = studenttdistribution(n-2, t, _state); - return result; -} - - - - -/************************************************************************* -Jarque-Bera test - -This test checks hypotheses about the fact that a given sample X is a -sample of normal random variable. - -Requirements: - * the number of elements in the sample is not less than 5. - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -Accuracy of the approximation used (5<=N<=1951): - -p-value relative error (5<=N<=1951) -[1, 0.1] < 1% -[0.1, 0.01] < 2% -[0.01, 0.001] < 6% -[0.001, 0] wasn't measured - -For N>1951 accuracy wasn't measured but it shouldn't be sharply different -from table values. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void jarqueberatest(/* Real */ ae_vector* x, - ae_int_t n, - double* p, - ae_state *_state) -{ - double s; - - *p = 0; - - - /* - * N is too small - */ - if( n<5 ) - { - *p = 1.0; - return; - } - - /* - * N is large enough - */ - jarquebera_jarqueberastatistic(x, n, &s, _state); - *p = jarquebera_jarqueberaapprox(n, s, _state); -} - - -static void jarquebera_jarqueberastatistic(/* Real */ ae_vector* x, - ae_int_t n, - double* s, - ae_state *_state) -{ - ae_int_t i; - double v; - double v1; - double v2; - double stddev; - double mean; - double variance; - double skewness; - double kurtosis; - - *s = 0; - - mean = 0; - variance = 0; - skewness = 0; - kurtosis = 0; - stddev = 0; - ae_assert(n>1, "Assertion failed", _state); - - /* - * Mean - */ - for(i=0; i<=n-1; i++) - { - mean = mean+x->ptr.p_double[i]; - } - mean = mean/n; - - /* - * Variance (using corrected two-pass algorithm) - */ - if( n!=1 ) - { - v1 = 0; - for(i=0; i<=n-1; i++) - { - v1 = v1+ae_sqr(x->ptr.p_double[i]-mean, _state); - } - v2 = 0; - for(i=0; i<=n-1; i++) - { - v2 = v2+(x->ptr.p_double[i]-mean); - } - v2 = ae_sqr(v2, _state)/n; - variance = (v1-v2)/(n-1); - if( ae_fp_less(variance,0) ) - { - variance = 0; - } - stddev = ae_sqrt(variance, _state); - } - - /* - * Skewness and kurtosis - */ - if( ae_fp_neq(stddev,0) ) - { - for(i=0; i<=n-1; i++) - { - v = (x->ptr.p_double[i]-mean)/stddev; - v2 = ae_sqr(v, _state); - skewness = skewness+v2*v; - kurtosis = kurtosis+ae_sqr(v2, _state); - } - skewness = skewness/n; - kurtosis = kurtosis/n-3; - } - - /* - * Statistic - */ - *s = (double)n/(double)6*(ae_sqr(skewness, _state)+ae_sqr(kurtosis, _state)/4); -} - - -static double jarquebera_jarqueberaapprox(ae_int_t n, - double s, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector vx; - ae_vector vy; - ae_matrix ctbl; - double t1; - double t2; - double t3; - double t; - double f1; - double f2; - double f3; - double f12; - double f23; - double x; - double result; - - ae_frame_make(_state, &_frame_block); - ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); - ae_vector_init(&vy, 0, DT_REAL, _state, ae_true); - ae_matrix_init(&ctbl, 0, 0, DT_REAL, _state, ae_true); - - result = 1; - x = s; - if( n<5 ) - { - ae_frame_leave(_state); - return result; - } - - /* - * N = 5..20 are tabulated - */ - if( n>=5&&n<=20 ) - { - if( n==5 ) - { - result = ae_exp(jarquebera_jbtbl5(x, _state), _state); - } - if( n==6 ) - { - result = ae_exp(jarquebera_jbtbl6(x, _state), _state); - } - if( n==7 ) - { - result = ae_exp(jarquebera_jbtbl7(x, _state), _state); - } - if( n==8 ) - { - result = ae_exp(jarquebera_jbtbl8(x, _state), _state); - } - if( n==9 ) - { - result = ae_exp(jarquebera_jbtbl9(x, _state), _state); - } - if( n==10 ) - { - result = ae_exp(jarquebera_jbtbl10(x, _state), _state); - } - if( n==11 ) - { - result = ae_exp(jarquebera_jbtbl11(x, _state), _state); - } - if( n==12 ) - { - result = ae_exp(jarquebera_jbtbl12(x, _state), _state); - } - if( n==13 ) - { - result = ae_exp(jarquebera_jbtbl13(x, _state), _state); - } - if( n==14 ) - { - result = ae_exp(jarquebera_jbtbl14(x, _state), _state); - } - if( n==15 ) - { - result = ae_exp(jarquebera_jbtbl15(x, _state), _state); - } - if( n==16 ) - { - result = ae_exp(jarquebera_jbtbl16(x, _state), _state); - } - if( n==17 ) - { - result = ae_exp(jarquebera_jbtbl17(x, _state), _state); - } - if( n==18 ) - { - result = ae_exp(jarquebera_jbtbl18(x, _state), _state); - } - if( n==19 ) - { - result = ae_exp(jarquebera_jbtbl19(x, _state), _state); - } - if( n==20 ) - { - result = ae_exp(jarquebera_jbtbl20(x, _state), _state); - } - ae_frame_leave(_state); - return result; - } - - /* - * N = 20, 30, 50 are tabulated. - * In-between values are interpolated - * using interpolating polynomial of the second degree. - */ - if( n>20&&n<=50 ) - { - t1 = -1.0/20.0; - t2 = -1.0/30.0; - t3 = -1.0/50.0; - t = -1.0/n; - f1 = jarquebera_jbtbl20(x, _state); - f2 = jarquebera_jbtbl30(x, _state); - f3 = jarquebera_jbtbl50(x, _state); - f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - - /* - * N = 50, 65, 100 are tabulated. - * In-between values are interpolated - * using interpolating polynomial of the second degree. - */ - if( n>50&&n<=100 ) - { - t1 = -1.0/50.0; - t2 = -1.0/65.0; - t3 = -1.0/100.0; - t = -1.0/n; - f1 = jarquebera_jbtbl50(x, _state); - f2 = jarquebera_jbtbl65(x, _state); - f3 = jarquebera_jbtbl100(x, _state); - f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - - /* - * N = 100, 130, 200 are tabulated. - * In-between values are interpolated - * using interpolating polynomial of the second degree. - */ - if( n>100&&n<=200 ) - { - t1 = -1.0/100.0; - t2 = -1.0/130.0; - t3 = -1.0/200.0; - t = -1.0/n; - f1 = jarquebera_jbtbl100(x, _state); - f2 = jarquebera_jbtbl130(x, _state); - f3 = jarquebera_jbtbl200(x, _state); - f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - - /* - * N = 200, 301, 501 are tabulated. - * In-between values are interpolated - * using interpolating polynomial of the second degree. - */ - if( n>200&&n<=501 ) - { - t1 = -1.0/200.0; - t2 = -1.0/301.0; - t3 = -1.0/501.0; - t = -1.0/n; - f1 = jarquebera_jbtbl200(x, _state); - f2 = jarquebera_jbtbl301(x, _state); - f3 = jarquebera_jbtbl501(x, _state); - f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - - /* - * N = 501, 701, 1401 are tabulated. - * In-between values are interpolated - * using interpolating polynomial of the second degree. - */ - if( n>501&&n<=1401 ) - { - t1 = -1.0/501.0; - t2 = -1.0/701.0; - t3 = -1.0/1401.0; - t = -1.0/n; - f1 = jarquebera_jbtbl501(x, _state); - f2 = jarquebera_jbtbl701(x, _state); - f3 = jarquebera_jbtbl1401(x, _state); - f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); - f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); - result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - - /* - * Asymptotic expansion - */ - if( n>1401 ) - { - result = -0.5*x+(jarquebera_jbtbl1401(x, _state)+0.5*x)*ae_sqrt((double)1401/(double)n, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - result = ae_exp(result, _state); - ae_frame_leave(_state); - return result; - } - ae_frame_leave(_state); - return result; -} - - -static double jarquebera_jbtbl5(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,0.4000) ) - { - x = 2*(s-0.000000)/0.400000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.097885e-20, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.854501e-20, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.756616e-20, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,1.1000) ) - { - x = 2*(s-0.400000)/0.700000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.324545e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.075941e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.772272e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.175686e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.576162e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.126861e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.434425e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.790359e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.809178e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.479704e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.717040e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.294170e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.880632e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.023344e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.601531e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.920403e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -5.188419e+02*(s-1.100000e+00)-4.767297e+00; - return result; -} - - -static double jarquebera_jbtbl6(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,0.2500) ) - { - x = 2*(s-0.000000)/0.250000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.274707e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.700471e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.425764e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,1.3000) ) - { - x = 2*(s-0.250000)/1.050000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.339000e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.011104e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.168177e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.085666e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.738606e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.022876e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.462402e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.908270e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.230772e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.006996e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.410222e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.893768e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.114564e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,1.8500) ) - { - x = 2*(s-1.300000)/0.550000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.794311e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.578700e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.394664e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.928290e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.813273e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.076063e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.835380e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.013013e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.058903e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.856915e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.710887e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.770029e+02*(s-1.850000e+00)-1.371015e+01; - return result; -} - - -static double jarquebera_jbtbl7(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.4000) ) - { - x = 2*(s-0.000000)/1.400000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.093681e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.695911e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.473192e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.203236e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.590379e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.291876e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.132007e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.411147e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.180067e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.487610e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.436561e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-1.400000)/1.600000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.947854e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.772675e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.707912e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.691171e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.132795e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.481310e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.867536e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.772327e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.033387e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.378277e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.497964e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.636814e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.581640e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,3.2000) ) - { - x = 2*(s-3.000000)/0.200000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -7.511008e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.895025e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.824116e+03*(s-3.200000e+00)-1.440330e+01; - return result; -} - - -static double jarquebera_jbtbl8(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.3000) ) - { - x = 2*(s-0.000000)/1.300000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -7.199015e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.095921e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.736828e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.047438e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.484320e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.937923e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.810470e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.139780e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.708443e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,2.0000) ) - { - x = 2*(s-1.300000)/0.700000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.378966e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.802461e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.547593e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.241042e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.203274e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.201990e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.125597e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.584426e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.546069e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,5.0000) ) - { - x = 2*(s-2.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.828366e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.137533e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.016671e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.745637e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.189801e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.621610e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.741122e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.516368e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.552085e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.787029e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.359774e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -5.087028e+00*(s-5.000000e+00)-1.071300e+01; - return result; -} - - -static double jarquebera_jbtbl9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.3000) ) - { - x = 2*(s-0.000000)/1.300000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.279320e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.277151e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.669339e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.086149e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.333816e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.871249e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.007048e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.482245e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.355615e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,2.0000) ) - { - x = 2*(s-1.300000)/0.700000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.981430e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.972248e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.747737e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.808530e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.888305e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.001302e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.378767e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.108510e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.915372e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,7.0000) ) - { - x = 2*(s-2.000000)/5.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.387463e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.845231e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.809956e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.543461e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.880397e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.160074e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.356527e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.394428e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.619892e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.758763e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.790977e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.020952e+00*(s-7.000000e+00)-9.516623e+00; - return result; -} - - -static double jarquebera_jbtbl10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.2000) ) - { - x = 2*(s-0.000000)/1.200000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.590993e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.562730e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.353934e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.069933e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.849151e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.931406e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.636295e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.178340e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.917749e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,2.0000) ) - { - x = 2*(s-1.200000)/0.800000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.537658e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.962401e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.838715e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.055792e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.580316e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.781701e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.770362e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.838983e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.999052e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,7.0000) ) - { - x = 2*(s-2.000000)/5.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.337524e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.877029e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.734650e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.249254e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.320250e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.432266e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -8.711035e-01*(s-7.000000e+00)-7.212811e+00; - return result; -} - - -static double jarquebera_jbtbl11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.2000) ) - { - x = 2*(s-0.000000)/1.200000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.339517e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.051558e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.000992e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.022547e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.808401e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.592870e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.575081e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.086173e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.089011e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,2.2500) ) - { - x = 2*(s-1.200000)/1.050000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.523221e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.068388e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.179661e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.555524e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.238964e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.364320e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.895771e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.762774e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.201340e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,8.0000) ) - { - x = 2*(s-2.250000)/5.750000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.212179e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.684579e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.299519e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.606261e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.310869e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.320115e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -5.715445e-01*(s-8.000000e+00)-6.845834e+00; - return result; -} - - -static double jarquebera_jbtbl12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.0000) ) - { - x = 2*(s-0.000000)/1.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.736742e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.657836e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.047209e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.319599e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.545631e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.280445e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.815679e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.213519e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.256838e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-1.000000)/2.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.573947e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.515287e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.611880e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.271311e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.495815e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.141186e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.180886e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.388211e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.890761e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.233175e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.946156e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,12.0000) ) - { - x = 2*(s-3.000000)/9.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.947819e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.034157e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.878986e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.078603e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.990977e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.866215e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.897866e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.512252e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.073743e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.022621e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.501343e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.877243e-01*(s-1.200000e+01)-7.936839e+00; - return result; -} - - -static double jarquebera_jbtbl13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.0000) ) - { - x = 2*(s-0.000000)/1.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.713276e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.557541e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.459092e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.044145e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.546132e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.002374e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.349456e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.025669e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.590242e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-1.000000)/2.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.454383e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.467539e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.270774e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.075763e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.611647e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.990785e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.109212e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.135031e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.915919e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.522390e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.144701e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,13.0000) ) - { - x = 2*(s-3.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.736127e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.920809e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.175858e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.002049e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.158966e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.157781e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.762172e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.780347e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.193310e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.442421e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.547756e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.799944e-01*(s-1.300000e+01)-7.566269e+00; - return result; -} - - -static double jarquebera_jbtbl14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,1.0000) ) - { - x = 2*(s-0.000000)/1.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.698527e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.479081e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.640733e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.466899e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.469485e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.150009e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.965975e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.710210e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.327808e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-1.000000)/2.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -2.350359e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.421365e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.960468e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.149167e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.361109e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.976022e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.082700e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.563328e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.453123e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.917559e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.151067e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-3.000000)/12.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.746892e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.010441e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.566146e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.129690e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.929724e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.524227e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.192933e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.254730e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.620685e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.289618e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.112350e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.590621e-01*(s-1.500000e+01)-7.632238e+00; - return result; -} - - -static double jarquebera_jbtbl15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,2.0000) ) - { - x = 2*(s-0.000000)/2.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.043660e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.361653e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.009497e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.951784e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.377903e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.003253e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.271309e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,5.0000) ) - { - x = 2*(s-2.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.582778e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.349578e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.476514e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.717385e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.222591e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.635124e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.815993e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,17.0000) ) - { - x = 2*(s-5.000000)/12.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.115476e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.655936e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.404310e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.663794e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.868618e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.381447e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.444801e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.581503e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.468696e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.728509e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.206470e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.927937e-01*(s-1.700000e+01)-7.700983e+00; - return result; -} - - -static double jarquebera_jbtbl16(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,2.0000) ) - { - x = 2*(s-0.000000)/2.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.002570e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.298141e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.832803e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.877026e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.539436e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.439658e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.756911e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,5.0000) ) - { - x = 2*(s-2.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.486198e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.242944e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.020002e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.130531e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.512373e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.054876e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.556839e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,20.0000) ) - { - x = 2*(s-5.000000)/15.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.241608e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.832655e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.340545e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.361143e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.283219e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.484549e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.805968e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.057243e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.454439e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.177513e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.819209e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.391580e-01*(s-2.000000e+01)-7.963205e+00; - return result; -} - - -static double jarquebera_jbtbl17(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-0.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.566973e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.810330e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.840039e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.337294e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.383549e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.556515e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.656965e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.404569e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.447867e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,6.0000) ) - { - x = 2*(s-3.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.905684e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.222920e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.146667e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.809176e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.057028e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.211838e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.099683e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.161105e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.225465e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,24.0000) ) - { - x = 2*(s-6.000000)/18.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.594282e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.917838e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.455980e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.999589e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.604263e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.484445e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.819937e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.930390e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.771761e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.232581e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.029083e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.127771e-01*(s-2.400000e+01)-8.400197e+00; - return result; -} - - -static double jarquebera_jbtbl18(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-0.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.526802e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.762373e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.598890e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.189437e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.971721e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.823067e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.064501e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.014932e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.953513e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,6.0000) ) - { - x = 2*(s-3.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.818669e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.070918e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.277196e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.879817e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.887357e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.638451e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.502800e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.165796e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.034960e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,20.0000) ) - { - x = 2*(s-6.000000)/14.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.010656e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.496296e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.002227e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.338250e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.137036e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.586202e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.736384e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.332251e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.877982e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.160963e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.547247e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.684623e-01*(s-2.000000e+01)-7.428883e+00; - return result; -} - - -static double jarquebera_jbtbl19(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,3.0000) ) - { - x = 2*(s-0.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.490213e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.719633e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.459123e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.034878e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.113868e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.030922e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.054022e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.525623e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.277360e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,6.0000) ) - { - x = 2*(s-3.000000)/3.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -3.744750e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.977749e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.223716e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.363889e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.711774e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.557257e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.254794e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.034207e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.498107e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,20.0000) ) - { - x = 2*(s-6.000000)/14.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.872768e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.430689e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.136575e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.726627e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.421110e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.581510e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.559520e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.838208e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.428839e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.170682e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.006647e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.539373e-01*(s-2.000000e+01)-7.206941e+00; - return result; -} - - -static double jarquebera_jbtbl20(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.854794e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.948947e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.632184e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.139397e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.006237e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.810031e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.573620e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.951242e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.274092e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.464196e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.882139e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.575144e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.822804e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.061348e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.908404e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.978353e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.030989e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.327151e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.346404e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.840051e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.578551e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.813886e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.905973e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.358489e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.450795e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.941157e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.432418e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.070537e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.375654e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.367378e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.890859e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.679782e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -7.015854e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.487737e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.244254e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.318007e-01*(s-2.500000e+01)-7.742185e+00; - return result; -} - - -static double jarquebera_jbtbl30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.630822e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.724298e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.872756e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.658268e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.573597e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.994157e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.994825e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.394303e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.785029e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.990264e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.037838e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.755546e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.774473e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.821395e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.392603e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.353313e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.539322e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.197018e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.396848e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.804293e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.867928e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.768758e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.211792e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.925799e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.046235e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.536469e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.489642e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.263462e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.177316e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.590637e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.028212e-01*(s-2.500000e+01)-6.855288e+00; - return result; -} - - -static double jarquebera_jbtbl50(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.436279e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.519711e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.148699e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.001204e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.207620e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.034778e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.220322e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.033260e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.588280e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.851653e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.287733e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.234645e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.189127e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.429738e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.058822e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 9.086776e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.445783e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.311671e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.261298e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.496987e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.605249e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.162282e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.921095e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.888603e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.080113e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -9.313116e-02*(s-2.500000e+01)-6.479154e+00; - return result; -} - - -static double jarquebera_jbtbl65(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.360024e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.434631e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.514580e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 7.332038e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.158197e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.121233e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.051056e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.148601e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.214233e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.487977e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.424720e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.116715e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.043152e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.718149e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.313701e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.097305e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.181031e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.256975e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.858951e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.895179e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.933237e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -9.443768e-02*(s-2.500000e+01)-6.419137e+00; - return result; -} - - -static double jarquebera_jbtbl100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.257021e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.313418e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.628931e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.264287e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.518487e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.499826e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.836044e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.056508e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.279690e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.665746e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.290012e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.487632e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.704465e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.211669e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.866099e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.399767e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.498208e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.080097e-01*(s-2.500000e+01)-6.481094e+00; - return result; -} - - -static double jarquebera_jbtbl130(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.207999e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.253864e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.618032e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.112729e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.210546e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.732602e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.410527e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.026324e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.331990e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.779129e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.674749e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.669077e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.679136e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 8.833221e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -5.893951e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.475304e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.116734e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.045722e-01*(s-2.500000e+01)-6.510314e+00; - return result; -} - - -static double jarquebera_jbtbl200(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.146155e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.177398e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.297970e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.869745e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.717288e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.982108e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.427636e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.034235e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.455006e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.942996e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.973795e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.418812e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.156778e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.896705e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.086071e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.152176e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.725393e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.132404e-01*(s-2.500000e+01)-6.764034e+00; - return result; -} - - -static double jarquebera_jbtbl301(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.104290e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.125800e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.595847e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.219666e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.502210e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.414543e-05, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.754115e-05, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.065955e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.582060e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.004472e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -4.709092e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.105779e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.197391e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.386780e-04, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.311384e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.918763e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.626584e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.293626e-01*(s-2.500000e+01)-7.066995e+00; - return result; -} - - -static double jarquebera_jbtbl501(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.067426e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.079765e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -5.463005e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 6.875659e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.127574e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.740694e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.044502e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.746714e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 3.810594e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.197111e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.628194e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -8.846221e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.386405e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.418332e-01*(s-2.500000e+01)-7.468952e+00; - return result; -} - - -static double jarquebera_jbtbl701(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.050999e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.059769e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -3.922680e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 4.847054e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.192182e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.860007e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.963942e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.838711e-02, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.893112e-04, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.159788e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -6.917851e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -9.817020e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.383727e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -1.532706e-01*(s-2.500000e+01)-7.845715e+00; - return result; -} - - -static double jarquebera_jbtbl1401(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - if( ae_fp_less_eq(s,4.0000) ) - { - x = 2*(s-0.000000)/4.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -1.026266e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.030061e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.259222e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 2.536254e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,15.0000) ) - { - x = 2*(s-4.000000)/11.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -4.329849e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -2.095443e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 1.759363e-01, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -7.751359e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -6.124368e-03, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.793114e-03, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - if( ae_fp_less_eq(s,25.0000) ) - { - x = 2*(s-15.000000)/10.000000-1; - tj = 1; - tj1 = x; - jarquebera_jbcheb(x, -7.544330e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, -1.225382e+00, &tj, &tj1, &result, _state); - jarquebera_jbcheb(x, 5.392349e-02, &tj, &tj1, &result, _state); - if( ae_fp_greater(result,0) ) - { - result = 0; - } - return result; - } - result = -2.019375e-01*(s-2.500000e+01)-8.715788e+00; - return result; -} - - -static void jarquebera_jbcheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state) -{ - double t; - - - *r = *r+c*(*tj); - t = 2*x*(*tj1)-(*tj); - *tj = *tj1; - *tj1 = t; -} - - - - -/************************************************************************* -Mann-Whitney U-test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions of the same shape and same median or whether -their medians are different. - -The following tests are performed: - * two-tailed test (null hypothesis - the medians are equal) - * left-tailed test (null hypothesis - the median of the first sample - is greater than or equal to the median of the second sample) - * right-tailed test (null hypothesis - the median of the first sample - is less than or equal to the median of the second sample). - -Requirements: - * the samples are independent - * X and Y are continuous distributions (or discrete distributions well- - approximating continuous distributions) - * distributions of X and Y have the same shape. The only possible - difference is their position (i.e. the value of the median) - * the number of elements in each sample is not less than 5 - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distributions to be normal. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. M>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with satisfactory accuracy in interval [0.0001, 1]. -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - -Relative precision of approximation of p-value: - -N M Max.err. Rms.err. -5..10 N..10 1.4e-02 6.0e-04 -5..10 N..100 2.2e-02 5.3e-06 -10..15 N..15 1.0e-02 3.2e-04 -10..15 N..100 1.0e-02 2.2e-05 -15..100 N..100 6.1e-03 2.7e-06 - -For N,M>100 accuracy checks weren't put into practice, but taking into -account characteristics of asymptotic approximation used, precision should -not be sharply different from the values for interval [5, 100]. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void mannwhitneyutest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_frame _frame_block; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t t; - double tmp; - ae_int_t tmpi; - ae_int_t ns; - ae_vector r; - ae_vector c; - double u; - double p; - double mp; - double s; - double sigma; - double mu; - ae_int_t tiecount; - ae_vector tiesize; - - ae_frame_make(_state, &_frame_block); - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - ae_vector_init(&r, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_INT, _state, ae_true); - ae_vector_init(&tiesize, 0, DT_INT, _state, ae_true); - - - /* - * Prepare - */ - if( n<=4||m<=4 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - ae_frame_leave(_state); - return; - } - ns = n+m; - ae_vector_set_length(&r, ns-1+1, _state); - ae_vector_set_length(&c, ns-1+1, _state); - for(i=0; i<=n-1; i++) - { - r.ptr.p_double[i] = x->ptr.p_double[i]; - c.ptr.p_int[i] = 0; - } - for(i=0; i<=m-1; i++) - { - r.ptr.p_double[n+i] = y->ptr.p_double[i]; - c.ptr.p_int[n+i] = 1; - } - - /* - * sort {R, C} - */ - if( ns!=1 ) - { - i = 2; - do - { - t = i; - while(t!=1) - { - k = t/2; - if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) - { - t = 1; - } - else - { - tmp = r.ptr.p_double[k-1]; - r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; - r.ptr.p_double[t-1] = tmp; - tmpi = c.ptr.p_int[k-1]; - c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; - c.ptr.p_int[t-1] = tmpi; - t = k; - } - } - i = i+1; - } - while(i<=ns); - i = ns-1; - do - { - tmp = r.ptr.p_double[i]; - r.ptr.p_double[i] = r.ptr.p_double[0]; - r.ptr.p_double[0] = tmp; - tmpi = c.ptr.p_int[i]; - c.ptr.p_int[i] = c.ptr.p_int[0]; - c.ptr.p_int[0] = tmpi; - t = 1; - while(t!=0) - { - k = 2*t; - if( k>i ) - { - t = 0; - } - else - { - if( k=1); - } - - /* - * compute tied ranks - */ - i = 0; - tiecount = 0; - ae_vector_set_length(&tiesize, ns-1+1, _state); - while(i<=ns-1) - { - j = i+1; - while(j<=ns-1) - { - if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) - { - break; - } - j = j+1; - } - for(k=i; k<=j-1; k++) - { - r.ptr.p_double[k] = 1+(double)(i+j-1)/(double)2; - } - tiesize.ptr.p_int[tiecount] = j-i; - tiecount = tiecount+1; - i = j; - } - - /* - * Compute U - */ - u = 0; - for(i=0; i<=ns-1; i++) - { - if( c.ptr.p_int[i]==0 ) - { - u = u+r.ptr.p_double[i]; - } - } - u = n*m+n*(n+1)/2-u; - - /* - * Result - */ - mu = (double)(n*m)/(double)2; - tmp = ns*(ae_sqr(ns, _state)-1)/12; - for(i=0; i<=tiecount-1; i++) - { - tmp = tmp-tiesize.ptr.p_int[i]*(ae_sqr(tiesize.ptr.p_int[i], _state)-1)/12; - } - sigma = ae_sqrt((double)(m*n)/(double)ns/(ns-1)*tmp, _state); - s = (u-mu)/sigma; - if( ae_fp_less_eq(s,0) ) - { - p = ae_exp(mannwhitneyu_usigma(-(u-mu)/sigma, n, m, _state), _state); - mp = 1-ae_exp(mannwhitneyu_usigma(-(u-1-mu)/sigma, n, m, _state), _state); - } - else - { - mp = ae_exp(mannwhitneyu_usigma((u-mu)/sigma, n, m, _state), _state); - p = 1-ae_exp(mannwhitneyu_usigma((u+1-mu)/sigma, n, m, _state), _state); - } - *bothtails = ae_maxreal(2*ae_minreal(p, mp, _state), 1.0E-4, _state); - *lefttail = ae_maxreal(mp, 1.0E-4, _state); - *righttail = ae_maxreal(p, 1.0E-4, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Sequential Chebyshev interpolation. -*************************************************************************/ -static void mannwhitneyu_ucheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state) -{ - double t; - - - *r = *r+c*(*tj); - t = 2*x*(*tj1)-(*tj); - *tj = *tj1; - *tj1 = t; -} - - -/************************************************************************* -Three-point polynomial interpolation. -*************************************************************************/ -static double mannwhitneyu_uninterpolate(double p1, - double p2, - double p3, - ae_int_t n, - ae_state *_state) -{ - double t1; - double t2; - double t3; - double t; - double p12; - double p23; - double result; - - - t1 = 1.0/15.0; - t2 = 1.0/30.0; - t3 = 1.0/100.0; - t = 1.0/n; - p12 = ((t-t2)*p1+(t1-t)*p2)/(t1-t2); - p23 = ((t-t3)*p2+(t2-t)*p3)/(t2-t3); - result = ((t-t3)*p12+(t1-t)*p23)/(t1-t3); - return result; -} - - -/************************************************************************* -Tail(0, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma000(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-6.76984e-01, -6.83700e-01, -6.89873e-01, n2, _state); - p2 = mannwhitneyu_uninterpolate(-6.83700e-01, -6.87311e-01, -6.90957e-01, n2, _state); - p3 = mannwhitneyu_uninterpolate(-6.89873e-01, -6.90957e-01, -6.92175e-01, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(0.75, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma075(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-1.44500e+00, -1.45906e+00, -1.47063e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-1.45906e+00, -1.46856e+00, -1.47644e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-1.47063e+00, -1.47644e+00, -1.48100e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(1.5, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma150(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-2.65380e+00, -2.67352e+00, -2.69011e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-2.67352e+00, -2.68591e+00, -2.69659e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-2.69011e+00, -2.69659e+00, -2.70192e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(2.25, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma225(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-4.41465e+00, -4.42260e+00, -4.43702e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-4.42260e+00, -4.41639e+00, -4.41928e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-4.43702e+00, -4.41928e+00, -4.41030e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(3.0, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma300(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-6.89839e+00, -6.83477e+00, -6.82340e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-6.83477e+00, -6.74559e+00, -6.71117e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-6.82340e+00, -6.71117e+00, -6.64929e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(3.33, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma333(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-8.31272e+00, -8.17096e+00, -8.13125e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-8.17096e+00, -8.00156e+00, -7.93245e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-8.13125e+00, -7.93245e+00, -7.82502e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(3.66, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma367(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-9.98837e+00, -9.70844e+00, -9.62087e+00, n2, _state); - p2 = mannwhitneyu_uninterpolate(-9.70844e+00, -9.41156e+00, -9.28998e+00, n2, _state); - p3 = mannwhitneyu_uninterpolate(-9.62087e+00, -9.28998e+00, -9.11686e+00, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(4.0, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma400(ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double p1; - double p2; - double p3; - double result; - - - p1 = mannwhitneyu_uninterpolate(-1.20250e+01, -1.14911e+01, -1.13231e+01, n2, _state); - p2 = mannwhitneyu_uninterpolate(-1.14911e+01, -1.09927e+01, -1.07937e+01, n2, _state); - p3 = mannwhitneyu_uninterpolate(-1.13231e+01, -1.07937e+01, -1.05285e+01, n2, _state); - result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 5) -*************************************************************************/ -static double mannwhitneyu_utbln5n5(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/2.611165e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -2.596264e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.412086e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.858542e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.614282e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.372686e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.524731e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.435331e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.284665e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.184141e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.298360e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 7.447272e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.938769e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.276205e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.138481e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.684625e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.558104e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 6) -*************************************************************************/ -static double mannwhitneyu_utbln5n6(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/2.738613e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -2.810459e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.684429e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.712858e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.009324e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.644391e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.034173e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.953498e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.279293e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.563485e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.971952e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.506309e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.541406e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.283205e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.016347e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.221626e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.286752e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 7) -*************************************************************************/ -static double mannwhitneyu_utbln5n7(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/2.841993e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -2.994677e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.923264e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.506190e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.054280e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.794587e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.726290e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.534180e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.517845e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.904428e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.882443e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.482988e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.114875e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.515082e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.996056e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.293581e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.349444e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 8) -*************************************************************************/ -static double mannwhitneyu_utbln5n8(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/2.927700e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.155727e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.135078e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.247203e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.309697e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.993725e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.567219e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.383704e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.002188e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.487322e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.443899e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.688270e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.600339e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.874948e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.811593e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.072353e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.659457e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 9) -*************************************************************************/ -static double mannwhitneyu_utbln5n9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.298162e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.325016e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.939852e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.563029e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.222652e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.195200e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.445665e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.204792e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.775217e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.527781e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.221948e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.242968e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.607959e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.771285e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.694026e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.481190e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 10) -*************************************************************************/ -static double mannwhitneyu_utbln5n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.061862e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.425360e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.496710e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.587658e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.812005e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.427637e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.515702e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.406867e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.796295e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.237591e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.654249e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.181165e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.011665e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.417927e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.534880e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.791255e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.871512e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 11) -*************************************************************************/ -static double mannwhitneyu_utbln5n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.115427e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.539959e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.652998e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.196503e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.054363e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.618848e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.109411e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.786668e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.215648e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.484220e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.935991e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.396191e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.894177e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.206979e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.519055e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.210326e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.189679e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 12) -*************************************************************************/ -static double mannwhitneyu_utbln5n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.162278e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.644007e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.796173e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.771177e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.290043e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.794686e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.702110e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.185959e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.416259e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.592056e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.201530e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.754365e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.978945e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.012032e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.304579e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.100378e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.728269e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 13) -*************************************************************************/ -static double mannwhitneyu_utbln5n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.203616e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.739120e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.928117e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.031605e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.519403e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.962648e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.292183e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.809293e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.465156e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.456278e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.446055e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.109490e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.218256e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.941479e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.058603e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.824402e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.830947e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 14) -*************************************************************************/ -static double mannwhitneyu_utbln5n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.240370e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.826559e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.050370e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.083408e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.743164e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.012030e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.884686e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.059656e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.327521e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.134026e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.584201e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.440618e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.524133e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.990007e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.887334e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.534977e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.705395e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 15) -*************************************************************************/ -static double mannwhitneyu_utbln5n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.851572e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.082033e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.095983e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.814595e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.073148e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.420213e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.517175e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.344180e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.371393e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.711443e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.228569e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.683483e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.267112e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.156044e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.131316e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.301023e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 16) -*************************************************************************/ -static double mannwhitneyu_utbln5n16(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.852210e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.077482e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.091186e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.797282e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.084994e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.667054e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.843909e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.456732e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.039830e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.723508e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.940608e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.478285e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.649144e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.237703e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.707410e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.874293e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 17) -*************************************************************************/ -static double mannwhitneyu_utbln5n17(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.851752e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.071259e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.084700e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.758898e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.073846e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.684838e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.964936e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.782442e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.956362e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.984727e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.196936e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.558262e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.690746e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.364855e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.401006e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.546748e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 18) -*************************************************************************/ -static double mannwhitneyu_utbln5n18(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.850840e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.064799e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.077651e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.712659e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.049217e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.571333e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.929809e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.752044e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.949464e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.896101e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.614460e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.384357e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.489113e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.445725e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.945636e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.424653e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 19) -*************************************************************************/ -static double mannwhitneyu_utbln5n19(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.850027e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.059159e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.071106e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.669960e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.022780e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.442555e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.851335e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.433865e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.514465e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.332989e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.606099e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.341945e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.402164e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.039761e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.512831e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.284427e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 20) -*************************************************************************/ -static double mannwhitneyu_utbln5n20(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.849651e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.054729e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.065747e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.636243e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.003234e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.372789e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.831551e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.763090e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.830626e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.122384e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.108328e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.557983e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.945666e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.965696e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.493236e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.162591e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 21) -*************************************************************************/ -static double mannwhitneyu_utbln5n21(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.849649e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.051155e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.061430e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.608869e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.902788e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.346562e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.874709e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.682887e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.026206e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.534551e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.990575e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.713334e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.737011e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.304571e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.133110e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.123457e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 22) -*************************************************************************/ -static double mannwhitneyu_utbln5n22(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.849598e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.047605e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.057264e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.579513e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.749602e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.275137e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.881768e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.177374e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.981056e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.696290e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.886803e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.085378e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.675242e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.426367e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.039613e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.662378e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 23) -*************************************************************************/ -static double mannwhitneyu_utbln5n23(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.849269e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.043761e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.052735e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.544683e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.517503e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.112082e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.782070e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.549483e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.747329e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.694263e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.147141e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.526209e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.039173e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.235615e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.656546e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.014423e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 24) -*************************************************************************/ -static double mannwhitneyu_utbln5n24(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.848925e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.040178e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.048355e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.510198e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.261134e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.915864e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.627423e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.307345e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.732992e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.869652e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.494176e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.047533e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.178439e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.424171e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.829195e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.840810e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 25) -*************************************************************************/ -static double mannwhitneyu_utbln5n25(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.848937e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.037512e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.044866e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.483269e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.063682e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.767778e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.508540e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.332756e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.881511e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.124041e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.368456e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.930499e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.779630e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.029528e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.658678e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.289695e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 26) -*************************************************************************/ -static double mannwhitneyu_utbln5n26(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.849416e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.035915e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.042493e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.466021e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.956432e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.698914e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.465689e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.035254e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.674614e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.492734e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.014021e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.944953e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.255750e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.075841e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.989330e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.134862e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 27) -*************************************************************************/ -static double mannwhitneyu_utbln5n27(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.850070e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.034815e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.040650e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.453117e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.886426e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.661702e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.452346e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.002476e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.720126e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.001400e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.729826e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.740640e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.206333e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.366093e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.193471e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.804091e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 28) -*************************************************************************/ -static double mannwhitneyu_utbln5n28(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.850668e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.033786e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.038853e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.440281e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.806020e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.612883e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.420436e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.787982e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.535230e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.263121e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.849609e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.863967e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.391610e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.720294e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.952273e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.901413e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 29) -*************************************************************************/ -static double mannwhitneyu_utbln5n29(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.851217e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.032834e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.037113e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.427762e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.719146e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.557172e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.375498e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.452033e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.187516e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.916936e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.065533e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.067301e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.615824e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.432244e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.417795e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.710038e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 30) -*************************************************************************/ -static double mannwhitneyu_utbln5n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.851845e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.032148e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.035679e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.417758e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.655330e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.522132e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.352106e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.326911e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.064969e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.813321e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.683881e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.813346e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.627085e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.832107e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.519336e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.888530e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 5, 100) -*************************************************************************/ -static double mannwhitneyu_utbln5n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.250000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.877940e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.039324e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.022243e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.305825e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.960119e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.112000e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.138868e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.418164e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.174520e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.489617e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.878301e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.302233e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.054113e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.458862e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.186591e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.623412e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 6) -*************************************************************************/ -static double mannwhitneyu_utbln6n6(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/2.882307e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.054075e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.998804e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.681518e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.067578e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.709435e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.952661e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.641700e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.304572e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.336275e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.770385e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.401891e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.246148e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.442663e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.502866e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.105855e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.739371e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 7) -*************************************************************************/ -static double mannwhitneyu_utbln6n7(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.265287e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.274613e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.582352e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.334293e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.915502e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.108091e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.546701e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.298827e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.891501e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.313717e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.989501e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.914594e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.062372e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.158841e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.596443e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.185662e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 8) -*************************************************************************/ -static double mannwhitneyu_utbln6n8(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.098387e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.450954e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.520462e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.420299e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.604853e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.165840e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.008756e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.723402e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.843521e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.883405e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.720980e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.301709e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.948034e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.776243e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.623736e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.742068e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.796927e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 9) -*************************************************************************/ -static double mannwhitneyu_utbln6n9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.181981e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.616113e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.741650e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.204487e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.873068e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.446794e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.632286e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.266481e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.280067e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.780687e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.480242e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.592200e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.581019e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.264231e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.347174e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.167535e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.092185e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 10) -*************************************************************************/ -static double mannwhitneyu_utbln6n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.253957e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.764382e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.942366e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.939896e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.137812e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.720270e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.281070e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.901060e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.824937e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.802812e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.258132e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.233536e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.085530e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.212151e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.001329e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.226048e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.035298e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 11) -*************************************************************************/ -static double mannwhitneyu_utbln6n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.316625e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.898597e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.125710e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.063297e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.396852e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.990126e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.927977e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.726500e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.858745e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.654590e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.217736e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.989770e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.768493e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.924364e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.140215e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.647914e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.924802e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 12) -*************************************************************************/ -static double mannwhitneyu_utbln6n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.371709e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.020941e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.294250e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.128842e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.650389e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.248611e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.578510e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.162852e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.746982e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.454209e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.128042e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.936650e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.530794e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.665192e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.994144e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.662249e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.368541e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 13) -*************************************************************************/ -static double mannwhitneyu_utbln6n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.420526e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.133167e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.450016e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.191088e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.898220e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.050249e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.226901e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.471113e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.007470e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.049420e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.059074e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.881249e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.452780e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.441805e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.787493e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.483957e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.481590e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 14) -*************************************************************************/ -static double mannwhitneyu_utbln6n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.201268e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.542568e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.226965e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.046029e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.136657e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.786757e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.843748e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.588022e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.253029e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.667188e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.788330e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.474545e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.540494e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.951188e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.863323e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.220904e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 15) -*************************************************************************/ -static double mannwhitneyu_utbln6n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.195689e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.526567e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.213617e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.975035e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.118480e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.859142e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.083312e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.298720e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.766708e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.026356e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.093113e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.135168e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.136376e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.190870e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.435972e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.413129e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 30) -*************************************************************************/ -static double mannwhitneyu_utbln6n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.166269e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.427399e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.118239e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.360847e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.745885e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.025041e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.187179e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.432089e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.408451e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.388774e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.795560e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.304136e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.258516e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.180236e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.388679e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.836027e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 6, 100) -*************************************************************************/ -static double mannwhitneyu_utbln6n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.450000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.181350e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.417919e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.094201e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.195883e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.818937e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.514202e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.125047e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.022148e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.284181e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.157766e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.023752e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.127985e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.221690e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.516179e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.501398e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.380220e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 7) -*************************************************************************/ -static double mannwhitneyu_utbln7n7(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.130495e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.501264e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.584790e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.577311e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.617002e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.145186e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.023462e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.408251e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.626515e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.072492e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.722926e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.095445e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.842602e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.751427e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.008927e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.892431e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.772386e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 8) -*************************************************************************/ -static double mannwhitneyu_utbln7n8(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.240370e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.709965e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.862154e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.504541e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.900195e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.439995e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.678028e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.485540e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.437047e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.440092e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.114227e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.516569e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.829457e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.787550e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.761866e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.991911e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.533481e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 9) -*************************************************************************/ -static double mannwhitneyu_utbln7n9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.334314e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.896550e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.112671e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.037277e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.181695e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.765190e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.360116e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.695960e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.780578e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.963843e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.616148e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.852104e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.390744e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.014041e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.888101e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.467474e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.004611e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 10) -*************************************************************************/ -static double mannwhitneyu_utbln7n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.415650e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.064844e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.340749e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.118888e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.459730e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.097781e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.057688e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.097406e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.209262e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.065641e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.196677e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.313994e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.827157e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.822284e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.389090e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.340850e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.395172e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 11) -*************************************************************************/ -static double mannwhitneyu_utbln7n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.486817e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.217795e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.549783e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.195905e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.733093e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.428447e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.760093e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.431676e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.717152e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.032199e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.832423e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.905979e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.302799e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.464371e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.456211e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.736244e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.140712e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 12) -*************************************************************************/ -static double mannwhitneyu_utbln7n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.235822e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.564100e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.190813e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.686546e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.395083e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.967359e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.747096e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.304144e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.903198e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.134906e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.175035e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.266224e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.892931e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.604706e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.070459e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.427010e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 13) -*************************************************************************/ -static double mannwhitneyu_utbln7n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.222204e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.532300e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.164642e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.523768e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.531984e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.467857e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.483804e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.524136e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.077740e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.745218e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.602085e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.828831e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.994070e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.873879e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.341937e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.706444e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 14) -*************************************************************************/ -static double mannwhitneyu_utbln7n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.211763e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.507542e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.143640e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.395755e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.808020e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.044259e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.182308e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.057325e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.724255e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.303900e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.113148e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.102514e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.559442e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.634986e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.776476e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.054489e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 15) -*************************************************************************/ -static double mannwhitneyu_utbln7n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.204898e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.489960e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.129172e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.316741e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.506107e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.983676e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.258013e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.262515e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.984156e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.912108e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.974023e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.056195e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.090842e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.232620e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.816339e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.020421e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 30) -*************************************************************************/ -static double mannwhitneyu_utbln7n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.176536e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.398705e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.045481e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.821982e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.962304e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.698132e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.062667e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.282353e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.014836e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.035683e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.004137e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.801453e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.920705e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.518735e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.821501e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.801008e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 7, 100) -*************************************************************************/ -static double mannwhitneyu_utbln7n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.500000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.188337e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.386949e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.022834e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.686517e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.323516e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.399392e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.644333e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.617044e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.031396e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.792066e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.675457e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.673416e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.258552e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.174214e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.073644e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.349958e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 8) -*************************************************************************/ -static double mannwhitneyu_utbln8n8(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.360672e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -3.940217e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.168913e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.051485e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.195325e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.775196e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.385506e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.244902e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.525632e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.771275e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.332874e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.079599e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.882551e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.407944e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.769844e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.062433e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.872535e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 9) -*************************************************************************/ -static double mannwhitneyu_utbln8n9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.464102e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.147004e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.446939e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.146155e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.488561e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.144561e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.116917e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.205667e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.515661e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.618616e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.599011e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.457324e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.482917e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.488267e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.469823e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.957591e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.058326e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 10) -*************************************************************************/ -static double mannwhitneyu_utbln8n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.554093e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.334282e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.700860e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.235253e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.778489e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.527324e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.862885e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.589781e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.507355e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.717526e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.215726e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.848696e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.918854e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.219614e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.753761e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.573688e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.602177e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 11) -*************************************************************************/ -static double mannwhitneyu_utbln8n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.421882e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.812457e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.266153e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.849344e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.971527e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.258944e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.944820e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.894685e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.031836e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.514330e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.351660e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.206748e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.492600e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.005338e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.780099e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.673599e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 12) -*************************************************************************/ -static double mannwhitneyu_utbln8n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.398211e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.762214e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.226296e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.603837e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.643223e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.502438e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.544574e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.647734e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.442259e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.011484e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.384758e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.998259e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.659985e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.331046e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.638478e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.056785e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 13) -*************************************************************************/ -static double mannwhitneyu_utbln8n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.380670e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.724511e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.195851e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.420511e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.609928e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.893999e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.115919e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.291410e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.339664e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.801548e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.534710e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.793250e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.806718e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.384624e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.120582e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.936453e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 14) -*************************************************************************/ -static double mannwhitneyu_utbln8n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.368494e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.697171e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.174440e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.300621e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.087393e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.685826e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.085254e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.525658e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.966647e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.453388e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.826066e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.501958e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.336297e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.251972e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.118456e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.415959e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 15) -*************************************************************************/ -static double mannwhitneyu_utbln8n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.358397e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.674485e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.155941e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.195780e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.544830e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.426183e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.309902e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.650956e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.068874e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.538544e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.192525e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.073905e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.079673e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.423572e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.579647e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.765904e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 30) -*************************************************************************/ -static double mannwhitneyu_utbln8n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.318823e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.567159e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.064864e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.688413e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.153712e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.309389e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.226861e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.523815e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.780987e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.166866e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.922431e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.466397e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.690036e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.008185e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.271903e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.534751e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 8, 100) -*************************************************************************/ -static double mannwhitneyu_utbln8n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.600000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.324531e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.547071e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.038129e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.541549e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.525605e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.044992e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.085713e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.017871e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.459226e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.092064e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.024349e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 7.366347e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.385637e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.321722e-08, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.439286e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.058079e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 9) -*************************************************************************/ -static double mannwhitneyu_utbln9n9(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.576237e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.372857e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.750859e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.248233e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.792868e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.559372e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.894941e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.643256e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.091370e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.285034e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.112997e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.806229e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.150741e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.509825e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.891051e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.485013e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.343653e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 10) -*************************************************************************/ -static double mannwhitneyu_utbln9n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.516726e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.939333e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.305046e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.935326e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.029141e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.420592e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.053140e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.065930e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.523581e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.544888e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.813741e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.510631e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.536057e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.833815e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.189692e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.615050e-03, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 11) -*************************************************************************/ -static double mannwhitneyu_utbln9n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.481308e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.867483e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.249072e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.591790e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.400128e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.341992e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.463680e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.487211e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.671196e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.343472e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.544146e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.802335e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.117084e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.217443e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.858766e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.193687e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 12) -*************************************************************************/ -static double mannwhitneyu_utbln9n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.456776e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.817037e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.209788e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.362108e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.171356e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.661557e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.026141e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.361908e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.093885e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.298389e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.663603e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.768522e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.579015e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.868677e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.440652e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.523037e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 13) -*************************************************************************/ -static double mannwhitneyu_utbln9n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.438840e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.779308e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.180614e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.196489e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.346621e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.234857e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.796211e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.575715e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.525647e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.964651e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.275235e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.299124e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.397416e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.295781e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.237619e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 7.269692e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 14) -*************************************************************************/ -static double mannwhitneyu_utbln9n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.425981e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.751545e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.159543e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.086570e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.917446e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.120112e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.175519e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.515473e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.727772e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.070629e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.677569e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.876953e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.233502e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.508182e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.120389e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.847212e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 15) -*************************************************************************/ -static double mannwhitneyu_utbln9n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.414952e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.727612e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.140634e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.981231e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.382635e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.853575e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.571051e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.567625e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.214197e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.448700e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.712669e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.015050e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.438610e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.301363e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.309386e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.164772e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 30) -*************************************************************************/ -static double mannwhitneyu_utbln9n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.370720e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.615712e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.050023e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.504775e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.318265e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.646826e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.741492e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.735360e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.966911e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.100738e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.348991e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.527687e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.917286e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.397466e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.360175e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.892252e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 9, 100) -*************************************************************************/ -static double mannwhitneyu_utbln9n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.372506e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.590966e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.021758e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.359849e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.755519e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.533166e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.936659e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.634913e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.730053e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.791845e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.030682e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.228663e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.631175e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.636749e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.404599e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.789872e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 10) -*************************************************************************/ -static double mannwhitneyu_utbln10n10(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.468831e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.844398e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.231728e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.486073e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.781321e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.971425e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.215371e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.828451e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.419872e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.430165e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.740363e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.049211e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.269371e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.211393e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.232314e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.016081e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 11) -*************************************************************************/ -static double mannwhitneyu_utbln10n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.437998e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.782296e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.184732e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.219585e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.457012e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.296008e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.481501e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.527940e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.953426e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.563840e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.574403e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.535775e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.338037e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.002654e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.852676e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.318132e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 12) -*************************************************************************/ -static double mannwhitneyu_utbln10n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.416082e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.737458e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.150952e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.036884e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.609030e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.908684e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.439666e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.162647e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.451601e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.148757e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.803981e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.731621e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.346903e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.013151e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.956148e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.438381e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 13) -*************************************************************************/ -static double mannwhitneyu_utbln10n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.399480e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.702863e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.124829e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.897428e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.979802e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.634368e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.180461e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.484926e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.864376e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.186576e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.886925e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.836828e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.074756e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.209547e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.883266e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.380143e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 14) -*************************************************************************/ -static double mannwhitneyu_utbln10n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.386924e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.676124e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.104740e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.793826e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.558886e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.492462e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.052903e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.917782e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.878696e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.576046e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.764551e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.288778e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.757658e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.299101e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.265197e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.384503e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 15) -*************************************************************************/ -static double mannwhitneyu_utbln10n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.376846e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.654247e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.088083e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.705945e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.169677e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.317213e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.264836e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.548024e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.633910e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.505621e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.658588e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.320254e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.175277e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.122317e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.675688e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.661363e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 30) -*************************************************************************/ -static double mannwhitneyu_utbln10n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.333977e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.548099e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.004444e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.291014e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.523674e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.828211e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.716917e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.894256e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.433371e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.522675e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.764192e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.140235e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.629230e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.541895e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.944946e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.726360e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 10, 100) -*************************************************************************/ -static double mannwhitneyu_utbln10n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.650000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.334008e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.522316e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.769627e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.158110e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.053650e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.242235e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.173571e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.033661e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.824732e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.084420e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.610036e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.728155e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.217130e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.340966e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.001235e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.694052e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 11) -*************************************************************************/ -static double mannwhitneyu_utbln11n11(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.519760e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.880694e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.200698e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.174092e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.072304e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.054773e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.506613e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.813942e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.223644e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.417416e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.499166e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.194332e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 7.369096e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.968590e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.630532e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.061000e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 12) -*************************************************************************/ -static double mannwhitneyu_utbln11n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.495790e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.832622e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.165420e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.987306e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.265621e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.723537e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.347406e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.353464e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.613369e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.102522e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.237709e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.665652e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.626903e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.167518e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.564455e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.047320e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 13) -*************************************************************************/ -static double mannwhitneyu_utbln11n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.477880e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.796242e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.138769e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.851739e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.722104e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.548304e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.176683e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.817895e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.842451e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.935870e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.421777e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.238831e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.867026e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.458255e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.306259e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.961487e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 14) -*************************************************************************/ -static double mannwhitneyu_utbln11n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.463683e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.766969e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.117082e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.739574e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.238865e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.350306e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.425871e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.640172e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.660633e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.879883e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.349658e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.271795e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.304544e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.024201e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.816867e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.596787e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 15) -*************************************************************************/ -static double mannwhitneyu_utbln11n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.452526e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.743570e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.099705e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.650612e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.858285e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.187036e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.689241e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.294360e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.072623e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.278008e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.322382e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.131558e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.305669e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.825627e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.332689e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.120973e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 30) -*************************************************************************/ -static double mannwhitneyu_utbln11n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.402621e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.627440e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.011333e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.224126e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.232856e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.859347e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.377381e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.756709e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.033230e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.875472e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.608399e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.102943e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.740693e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.343139e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.196878e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.658062e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 11, 100) -*************************************************************************/ -static double mannwhitneyu_utbln11n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.398795e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.596486e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.814761e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.085187e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.766529e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.379425e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.986351e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.214705e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.360075e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.260869e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.033307e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.727087e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.393883e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.242989e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.111928e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.898823e-09, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 12) -*************************************************************************/ -static double mannwhitneyu_utbln12n12(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.472616e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.786627e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.132099e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.817523e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.570179e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.479511e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.799492e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.565350e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.530139e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.380132e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.242761e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.576269e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.018771e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.933911e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.002799e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.022048e-06, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 13) -*************************************************************************/ -static double mannwhitneyu_utbln12n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.454800e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.750794e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.105988e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.684754e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.011826e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.262579e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.044492e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.478741e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.322165e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.621104e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.068753e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.468396e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.056235e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.327375e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.914877e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.784191e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 14) -*************************************************************************/ -static double mannwhitneyu_utbln12n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.440910e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.722404e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.085254e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.579439e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.563738e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.066730e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.129346e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.014531e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.129679e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.000909e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.996174e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.377924e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.936304e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.051098e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.025820e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 8.730585e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 15) -*************************************************************************/ -static double mannwhitneyu_utbln12n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.430123e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.700008e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.068971e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.499725e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.250897e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.473145e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.680008e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.483350e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.766992e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.891081e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.015140e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.977756e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.707414e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.114786e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.238865e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.381445e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 30) -*************************************************************************/ -static double mannwhitneyu_utbln12n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.380023e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.585782e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.838583e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.103394e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.834015e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.635212e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.948212e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.574169e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.747980e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.833672e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.722433e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.181038e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.206473e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.716003e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.476434e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.217700e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 12, 100) -*************************************************************************/ -static double mannwhitneyu_utbln12n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.700000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.374567e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.553481e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.541334e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.701907e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.414757e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.404103e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.234388e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.453762e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.311060e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.317501e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.713888e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.309583e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.019804e-08, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.224829e-09, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.349019e-08, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.893302e-08, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 13, 13) -*************************************************************************/ -static double mannwhitneyu_utbln13n13(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.541046e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.859047e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.130164e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.689719e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.950693e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.231455e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.976550e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.538455e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.245603e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.142647e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.831434e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.032483e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.488405e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.156927e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.949279e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.532700e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 13, 14) -*************************************************************************/ -static double mannwhitneyu_utbln13n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.525655e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.828341e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.108110e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.579552e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.488307e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.032328e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.988741e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.766394e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.388950e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.338179e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.133440e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.023518e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.110570e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.202332e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.056132e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.536323e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 13, 15) -*************************************************************************/ -static double mannwhitneyu_utbln13n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.513585e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.803952e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.090686e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.495310e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.160314e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.073124e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.480313e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.478239e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.140914e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.311541e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.677105e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.115464e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.578563e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.044604e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.888939e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 2.395644e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 13, 30) -*************************************************************************/ -static double mannwhitneyu_utbln13n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.455999e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.678434e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.995491e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.078100e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.705220e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.258739e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.671526e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.185458e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.507764e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.411446e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.044355e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.285765e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.345282e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.066940e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.962037e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.723644e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 13, 100) -*************************************************************************/ -static double mannwhitneyu_utbln13n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.446787e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.640804e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.671552e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.364990e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.274444e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.047440e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.161439e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.171729e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.562171e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.359762e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.275494e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.747635e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.700292e-08, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.565559e-09, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 5.005396e-09, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 3.335794e-09, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 14, 14) -*************************************************************************/ -static double mannwhitneyu_utbln14n14(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.510624e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.798584e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.087107e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.478532e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.098050e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.855986e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.409083e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.299536e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.176177e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.479417e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.812761e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -5.225872e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 4.516521e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 6.730551e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 9.237563e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.611820e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 14, 15) -*************************************************************************/ -static double mannwhitneyu_utbln14n15(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.498681e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.774668e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.070267e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.399348e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.807239e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.845763e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.071773e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.261698e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.011695e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.305946e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.879295e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.999439e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.904438e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.944986e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.373908e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.140794e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 14, 30) -*************************************************************************/ -static double mannwhitneyu_utbln14n30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.440378e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.649587e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.807829e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.989753e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.463646e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.586580e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -6.745917e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.635398e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.923172e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.446699e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.613892e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.214073e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.651683e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.272777e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.464988e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.109803e-07, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 14, 100) -*************************************************************************/ -static double mannwhitneyu_utbln14n100(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/3.750000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - mannwhitneyu_ucheb(x, -4.429701e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -4.610577e+00, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -9.482675e-01, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.605550e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.062151e-02, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.525154e-03, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.835983e-04, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -8.411440e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.744901e-05, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.318850e-06, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.692100e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -1.536270e-07, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -3.705888e-08, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -7.999599e-09, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, -2.908395e-09, &tj, &tj1, &result, _state); - mannwhitneyu_ucheb(x, 1.546923e-09, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, N1, N2) -*************************************************************************/ -static double mannwhitneyu_usigma(double s, - ae_int_t n1, - ae_int_t n2, - ae_state *_state) -{ - double f0; - double f1; - double f2; - double f3; - double f4; - double s0; - double s1; - double s2; - double s3; - double s4; - double result; - - - result = 0; - - /* - * N1=5, N2 = 5, 6, 7, ... - */ - if( ae_minint(n1, n2, _state)==5 ) - { - if( ae_maxint(n1, n2, _state)==5 ) - { - result = mannwhitneyu_utbln5n5(s, _state); - } - if( ae_maxint(n1, n2, _state)==6 ) - { - result = mannwhitneyu_utbln5n6(s, _state); - } - if( ae_maxint(n1, n2, _state)==7 ) - { - result = mannwhitneyu_utbln5n7(s, _state); - } - if( ae_maxint(n1, n2, _state)==8 ) - { - result = mannwhitneyu_utbln5n8(s, _state); - } - if( ae_maxint(n1, n2, _state)==9 ) - { - result = mannwhitneyu_utbln5n9(s, _state); - } - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln5n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln5n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln5n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln5n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln5n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln5n15(s, _state); - } - if( ae_maxint(n1, n2, _state)==16 ) - { - result = mannwhitneyu_utbln5n16(s, _state); - } - if( ae_maxint(n1, n2, _state)==17 ) - { - result = mannwhitneyu_utbln5n17(s, _state); - } - if( ae_maxint(n1, n2, _state)==18 ) - { - result = mannwhitneyu_utbln5n18(s, _state); - } - if( ae_maxint(n1, n2, _state)==19 ) - { - result = mannwhitneyu_utbln5n19(s, _state); - } - if( ae_maxint(n1, n2, _state)==20 ) - { - result = mannwhitneyu_utbln5n20(s, _state); - } - if( ae_maxint(n1, n2, _state)==21 ) - { - result = mannwhitneyu_utbln5n21(s, _state); - } - if( ae_maxint(n1, n2, _state)==22 ) - { - result = mannwhitneyu_utbln5n22(s, _state); - } - if( ae_maxint(n1, n2, _state)==23 ) - { - result = mannwhitneyu_utbln5n23(s, _state); - } - if( ae_maxint(n1, n2, _state)==24 ) - { - result = mannwhitneyu_utbln5n24(s, _state); - } - if( ae_maxint(n1, n2, _state)==25 ) - { - result = mannwhitneyu_utbln5n25(s, _state); - } - if( ae_maxint(n1, n2, _state)==26 ) - { - result = mannwhitneyu_utbln5n26(s, _state); - } - if( ae_maxint(n1, n2, _state)==27 ) - { - result = mannwhitneyu_utbln5n27(s, _state); - } - if( ae_maxint(n1, n2, _state)==28 ) - { - result = mannwhitneyu_utbln5n28(s, _state); - } - if( ae_maxint(n1, n2, _state)==29 ) - { - result = mannwhitneyu_utbln5n29(s, _state); - } - if( ae_maxint(n1, n2, _state)>29 ) - { - f0 = mannwhitneyu_utbln5n15(s, _state); - f1 = mannwhitneyu_utbln5n30(s, _state); - f2 = mannwhitneyu_utbln5n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=6, N2 = 6, 7, 8, ... - */ - if( ae_minint(n1, n2, _state)==6 ) - { - if( ae_maxint(n1, n2, _state)==6 ) - { - result = mannwhitneyu_utbln6n6(s, _state); - } - if( ae_maxint(n1, n2, _state)==7 ) - { - result = mannwhitneyu_utbln6n7(s, _state); - } - if( ae_maxint(n1, n2, _state)==8 ) - { - result = mannwhitneyu_utbln6n8(s, _state); - } - if( ae_maxint(n1, n2, _state)==9 ) - { - result = mannwhitneyu_utbln6n9(s, _state); - } - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln6n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln6n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln6n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln6n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln6n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln6n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln6n15(s, _state); - f1 = mannwhitneyu_utbln6n30(s, _state); - f2 = mannwhitneyu_utbln6n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=7, N2 = 7, 8, ... - */ - if( ae_minint(n1, n2, _state)==7 ) - { - if( ae_maxint(n1, n2, _state)==7 ) - { - result = mannwhitneyu_utbln7n7(s, _state); - } - if( ae_maxint(n1, n2, _state)==8 ) - { - result = mannwhitneyu_utbln7n8(s, _state); - } - if( ae_maxint(n1, n2, _state)==9 ) - { - result = mannwhitneyu_utbln7n9(s, _state); - } - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln7n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln7n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln7n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln7n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln7n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln7n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln7n15(s, _state); - f1 = mannwhitneyu_utbln7n30(s, _state); - f2 = mannwhitneyu_utbln7n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=8, N2 = 8, 9, 10, ... - */ - if( ae_minint(n1, n2, _state)==8 ) - { - if( ae_maxint(n1, n2, _state)==8 ) - { - result = mannwhitneyu_utbln8n8(s, _state); - } - if( ae_maxint(n1, n2, _state)==9 ) - { - result = mannwhitneyu_utbln8n9(s, _state); - } - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln8n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln8n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln8n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln8n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln8n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln8n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln8n15(s, _state); - f1 = mannwhitneyu_utbln8n30(s, _state); - f2 = mannwhitneyu_utbln8n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=9, N2 = 9, 10, ... - */ - if( ae_minint(n1, n2, _state)==9 ) - { - if( ae_maxint(n1, n2, _state)==9 ) - { - result = mannwhitneyu_utbln9n9(s, _state); - } - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln9n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln9n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln9n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln9n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln9n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln9n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln9n15(s, _state); - f1 = mannwhitneyu_utbln9n30(s, _state); - f2 = mannwhitneyu_utbln9n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=10, N2 = 10, 11, ... - */ - if( ae_minint(n1, n2, _state)==10 ) - { - if( ae_maxint(n1, n2, _state)==10 ) - { - result = mannwhitneyu_utbln10n10(s, _state); - } - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln10n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln10n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln10n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln10n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln10n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln10n15(s, _state); - f1 = mannwhitneyu_utbln10n30(s, _state); - f2 = mannwhitneyu_utbln10n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=11, N2 = 11, 12, ... - */ - if( ae_minint(n1, n2, _state)==11 ) - { - if( ae_maxint(n1, n2, _state)==11 ) - { - result = mannwhitneyu_utbln11n11(s, _state); - } - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln11n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln11n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln11n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln11n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln11n15(s, _state); - f1 = mannwhitneyu_utbln11n30(s, _state); - f2 = mannwhitneyu_utbln11n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=12, N2 = 12, 13, ... - */ - if( ae_minint(n1, n2, _state)==12 ) - { - if( ae_maxint(n1, n2, _state)==12 ) - { - result = mannwhitneyu_utbln12n12(s, _state); - } - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln12n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln12n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln12n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln12n15(s, _state); - f1 = mannwhitneyu_utbln12n30(s, _state); - f2 = mannwhitneyu_utbln12n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=13, N2 = 13, 14, ... - */ - if( ae_minint(n1, n2, _state)==13 ) - { - if( ae_maxint(n1, n2, _state)==13 ) - { - result = mannwhitneyu_utbln13n13(s, _state); - } - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln13n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln13n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln13n15(s, _state); - f1 = mannwhitneyu_utbln13n30(s, _state); - f2 = mannwhitneyu_utbln13n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1=14, N2 = 14, 15, ... - */ - if( ae_minint(n1, n2, _state)==14 ) - { - if( ae_maxint(n1, n2, _state)==14 ) - { - result = mannwhitneyu_utbln14n14(s, _state); - } - if( ae_maxint(n1, n2, _state)==15 ) - { - result = mannwhitneyu_utbln14n15(s, _state); - } - if( ae_maxint(n1, n2, _state)>15 ) - { - f0 = mannwhitneyu_utbln14n15(s, _state); - f1 = mannwhitneyu_utbln14n30(s, _state); - f2 = mannwhitneyu_utbln14n100(s, _state); - result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); - } - return result; - } - - /* - * N1 >= 15, N2 >= 15 - */ - if( ae_fp_greater(s,4) ) - { - s = 4; - } - if( ae_fp_less(s,3) ) - { - s0 = 0.000000e+00; - f0 = mannwhitneyu_usigma000(n1, n2, _state); - s1 = 7.500000e-01; - f1 = mannwhitneyu_usigma075(n1, n2, _state); - s2 = 1.500000e+00; - f2 = mannwhitneyu_usigma150(n1, n2, _state); - s3 = 2.250000e+00; - f3 = mannwhitneyu_usigma225(n1, n2, _state); - s4 = 3.000000e+00; - f4 = mannwhitneyu_usigma300(n1, n2, _state); - f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); - f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); - f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); - f4 = ((s-s0)*f4-(s-s4)*f0)/(s4-s0); - f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); - f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); - f4 = ((s-s1)*f4-(s-s4)*f1)/(s4-s1); - f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); - f4 = ((s-s2)*f4-(s-s4)*f2)/(s4-s2); - f4 = ((s-s3)*f4-(s-s4)*f3)/(s4-s3); - result = f4; - } - else - { - s0 = 3.000000e+00; - f0 = mannwhitneyu_usigma300(n1, n2, _state); - s1 = 3.333333e+00; - f1 = mannwhitneyu_usigma333(n1, n2, _state); - s2 = 3.666667e+00; - f2 = mannwhitneyu_usigma367(n1, n2, _state); - s3 = 4.000000e+00; - f3 = mannwhitneyu_usigma400(n1, n2, _state); - f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); - f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); - f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); - f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); - f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); - f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); - result = f3; - } - return result; -} - - - - -/************************************************************************* -Sign test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -While calculating p-values high-precision binomial distribution -approximation is used, so significance levels have about 15 exact digits. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplesigntest(/* Real */ ae_vector* x, - ae_int_t n, - double median, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - ae_int_t gtcnt; - ae_int_t necnt; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=1 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Calculate: - * GTCnt - count of x[i]>Median - * NECnt - count of x[i]<>Median - */ - gtcnt = 0; - necnt = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_greater(x->ptr.p_double[i],median) ) - { - gtcnt = gtcnt+1; - } - if( ae_fp_neq(x->ptr.p_double[i],median) ) - { - necnt = necnt+1; - } - } - if( necnt==0 ) - { - - /* - * all x[i] are equal to Median. - * So we can conclude that Median is a true median :) - */ - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - *bothtails = ae_minreal(2*binomialdistribution(ae_minint(gtcnt, necnt-gtcnt, _state), necnt, 0.5, _state), 1.0, _state); - *lefttail = binomialdistribution(gtcnt, necnt, 0.5, _state); - *righttail = binomialcdistribution(gtcnt-1, necnt, 0.5, _state); -} - - - - -/************************************************************************* -One-sample t-test - -This test checks three hypotheses about the mean of the given sample. The -following tests are performed: - * two-tailed test (null hypothesis - the mean is equal to the given - value) - * left-tailed test (null hypothesis - the mean is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the mean is less than or equal - to the given value). - -The test is based on the assumption that a given sample has a normal -distribution and an unknown dispersion. If the distribution sharply -differs from normal, the test will work incorrectly. - -INPUT PARAMETERS: - X - sample. Array whose index goes from 0 to N-1. - N - size of sample, N>=0 - Mean - assumed value of the mean. - -OUTPUT PARAMETERS: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0, all p-values are set to 1.0 - * when variance of X[] is exactly zero, p-values are set - to 1.0 or 0.0, depending on difference between sample mean and - value of mean being tested. - - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest1(/* Real */ ae_vector* x, - ae_int_t n, - double mean, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - double xmean; - double x0; - double v; - ae_bool samex; - double xvariance; - double xstddev; - double v1; - double v2; - double stat; - double s; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=0 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Mean - */ - xmean = 0; - x0 = x->ptr.p_double[0]; - samex = ae_true; - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_double[i]; - xmean = xmean+v; - samex = samex&&ae_fp_eq(v,x0); - } - if( samex ) - { - xmean = x0; - } - else - { - xmean = xmean/n; - } - - /* - * Variance (using corrected two-pass algorithm) - */ - xvariance = 0; - xstddev = 0; - if( n!=1&&!samex ) - { - v1 = 0; - for(i=0; i<=n-1; i++) - { - v1 = v1+ae_sqr(x->ptr.p_double[i]-xmean, _state); - } - v2 = 0; - for(i=0; i<=n-1; i++) - { - v2 = v2+(x->ptr.p_double[i]-xmean); - } - v2 = ae_sqr(v2, _state)/n; - xvariance = (v1-v2)/(n-1); - if( ae_fp_less(xvariance,0) ) - { - xvariance = 0; - } - xstddev = ae_sqrt(xvariance, _state); - } - if( ae_fp_eq(xstddev,0) ) - { - if( ae_fp_eq(xmean,mean) ) - { - *bothtails = 1.0; - } - else - { - *bothtails = 0.0; - } - if( ae_fp_greater_eq(xmean,mean) ) - { - *lefttail = 1.0; - } - else - { - *lefttail = 0.0; - } - if( ae_fp_less_eq(xmean,mean) ) - { - *righttail = 1.0; - } - else - { - *righttail = 0.0; - } - return; - } - - /* - * Statistic - */ - stat = (xmean-mean)/(xstddev/ae_sqrt(n, _state)); - s = studenttdistribution(n-1, stat, _state); - *bothtails = 2*ae_minreal(s, 1-s, _state); - *lefttail = s; - *righttail = 1-s; -} - - -/************************************************************************* -Two-sample pooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * dispersions are equal - * samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has exactly zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest2(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - ae_bool samex; - ae_bool samey; - double x0; - double y0; - double xmean; - double ymean; - double v; - double stat; - double s; - double p; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=0||m<=0 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Mean - */ - xmean = 0; - x0 = x->ptr.p_double[0]; - samex = ae_true; - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_double[i]; - xmean = xmean+v; - samex = samex&&ae_fp_eq(v,x0); - } - if( samex ) - { - xmean = x0; - } - else - { - xmean = xmean/n; - } - ymean = 0; - y0 = y->ptr.p_double[0]; - samey = ae_true; - for(i=0; i<=m-1; i++) - { - v = y->ptr.p_double[i]; - ymean = ymean+v; - samey = samey&&ae_fp_eq(v,y0); - } - if( samey ) - { - ymean = y0; - } - else - { - ymean = ymean/m; - } - - /* - * S - */ - s = 0; - if( n+m>2 ) - { - for(i=0; i<=n-1; i++) - { - s = s+ae_sqr(x->ptr.p_double[i]-xmean, _state); - } - for(i=0; i<=m-1; i++) - { - s = s+ae_sqr(y->ptr.p_double[i]-ymean, _state); - } - s = ae_sqrt(s*((double)1/(double)n+(double)1/(double)m)/(n+m-2), _state); - } - if( ae_fp_eq(s,0) ) - { - if( ae_fp_eq(xmean,ymean) ) - { - *bothtails = 1.0; - } - else - { - *bothtails = 0.0; - } - if( ae_fp_greater_eq(xmean,ymean) ) - { - *lefttail = 1.0; - } - else - { - *lefttail = 0.0; - } - if( ae_fp_less_eq(xmean,ymean) ) - { - *righttail = 1.0; - } - else - { - *righttail = 0.0; - } - return; - } - - /* - * Statistic - */ - stat = (xmean-ymean)/s; - p = studenttdistribution(n+m-2, stat, _state); - *bothtails = 2*ae_minreal(p, 1-p, _state); - *lefttail = p; - *righttail = 1-p; -} - - -/************************************************************************* -Two-sample unpooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * samples are independent. -Equality of variances is NOT required. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - * when only one sample has zero variance, test reduces to 1-sample - version. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void unequalvariancettest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - ae_bool samex; - ae_bool samey; - double x0; - double y0; - double xmean; - double ymean; - double xvar; - double yvar; - double v; - double df; - double p; - double stat; - double c; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=0||m<=0 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Mean - */ - xmean = 0; - x0 = x->ptr.p_double[0]; - samex = ae_true; - for(i=0; i<=n-1; i++) - { - v = x->ptr.p_double[i]; - xmean = xmean+v; - samex = samex&&ae_fp_eq(v,x0); - } - if( samex ) - { - xmean = x0; - } - else - { - xmean = xmean/n; - } - ymean = 0; - y0 = y->ptr.p_double[0]; - samey = ae_true; - for(i=0; i<=m-1; i++) - { - v = y->ptr.p_double[i]; - ymean = ymean+v; - samey = samey&&ae_fp_eq(v,y0); - } - if( samey ) - { - ymean = y0; - } - else - { - ymean = ymean/m; - } - - /* - * Variance (using corrected two-pass algorithm) - */ - xvar = 0; - if( n>=2&&!samex ) - { - for(i=0; i<=n-1; i++) - { - xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); - } - xvar = xvar/(n-1); - } - yvar = 0; - if( m>=2&&!samey ) - { - for(i=0; i<=m-1; i++) - { - yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); - } - yvar = yvar/(m-1); - } - - /* - * Handle different special cases - * (one or both variances are zero). - */ - if( ae_fp_eq(xvar,0)&&ae_fp_eq(yvar,0) ) - { - if( ae_fp_eq(xmean,ymean) ) - { - *bothtails = 1.0; - } - else - { - *bothtails = 0.0; - } - if( ae_fp_greater_eq(xmean,ymean) ) - { - *lefttail = 1.0; - } - else - { - *lefttail = 0.0; - } - if( ae_fp_less_eq(xmean,ymean) ) - { - *righttail = 1.0; - } - else - { - *righttail = 0.0; - } - return; - } - if( ae_fp_eq(xvar,0) ) - { - - /* - * X is constant, unpooled 2-sample test reduces to 1-sample test. - * - * NOTE: right-tail and left-tail must be passed to 1-sample - * t-test in reverse order because we reverse order of - * of samples. - */ - studentttest1(y, m, xmean, bothtails, righttail, lefttail, _state); - return; - } - if( ae_fp_eq(yvar,0) ) - { - - /* - * Y is constant, unpooled 2-sample test reduces to 1-sample test. - */ - studentttest1(x, n, ymean, bothtails, lefttail, righttail, _state); - return; - } - - /* - * Statistic - */ - stat = (xmean-ymean)/ae_sqrt(xvar/n+yvar/m, _state); - c = xvar/n/(xvar/n+yvar/m); - df = (n-1)*(m-1)/((m-1)*ae_sqr(c, _state)+(n-1)*ae_sqr(1-c, _state)); - if( ae_fp_greater(stat,0) ) - { - p = 1-0.5*incompletebeta(df/2, 0.5, df/(df+ae_sqr(stat, _state)), _state); - } - else - { - p = 0.5*incompletebeta(df/2, 0.5, df/(df+ae_sqr(stat, _state)), _state); - } - *bothtails = 2*ae_minreal(p, 1-p, _state); - *lefttail = p; - *righttail = 1-p; -} - - - - -/************************************************************************* -Two-sample F-test - -This test checks three hypotheses about dispersions of the given samples. -The following tests are performed: - * two-tailed test (null hypothesis - the dispersions are equal) - * left-tailed test (null hypothesis - the dispersion of the first - sample is greater than or equal to the dispersion of the second - sample). - * right-tailed test (null hypothesis - the dispersion of the first - sample is less than or equal to the dispersion of the second sample) - -The test is based on the following assumptions: - * the given samples have normal distributions - * the samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - sample size. - Y - sample 2. Array whose index goes from 0 to M-1. - M - sample size. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void ftest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - double xmean; - double ymean; - double xvar; - double yvar; - ae_int_t df1; - ae_int_t df2; - double stat; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=2||m<=2 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Mean - */ - xmean = 0; - for(i=0; i<=n-1; i++) - { - xmean = xmean+x->ptr.p_double[i]; - } - xmean = xmean/n; - ymean = 0; - for(i=0; i<=m-1; i++) - { - ymean = ymean+y->ptr.p_double[i]; - } - ymean = ymean/m; - - /* - * Variance (using corrected two-pass algorithm) - */ - xvar = 0; - for(i=0; i<=n-1; i++) - { - xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); - } - xvar = xvar/(n-1); - yvar = 0; - for(i=0; i<=m-1; i++) - { - yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); - } - yvar = yvar/(m-1); - if( ae_fp_eq(xvar,0)||ae_fp_eq(yvar,0) ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Statistic - */ - df1 = n-1; - df2 = m-1; - stat = ae_minreal(xvar/yvar, yvar/xvar, _state); - *bothtails = 1-(fdistribution(df1, df2, 1/stat, _state)-fdistribution(df1, df2, stat, _state)); - *lefttail = fdistribution(df1, df2, xvar/yvar, _state); - *righttail = 1-(*lefttail); -} - - -/************************************************************************* -One-sample chi-square test - -This test checks three hypotheses about the dispersion of the given sample -The following tests are performed: - * two-tailed test (null hypothesis - the dispersion equals the given - number) - * left-tailed test (null hypothesis - the dispersion is greater than - or equal to the given number) - * right-tailed test (null hypothesis - dispersion is less than or - equal to the given number). - -Test is based on the following assumptions: - * the given sample has a normal distribution. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Variance - dispersion value to compare with. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplevariancetest(/* Real */ ae_vector* x, - ae_int_t n, - double variance, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_int_t i; - double xmean; - double xvar; - double s; - double stat; - - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - - if( n<=1 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Mean - */ - xmean = 0; - for(i=0; i<=n-1; i++) - { - xmean = xmean+x->ptr.p_double[i]; - } - xmean = xmean/n; - - /* - * Variance - */ - xvar = 0; - for(i=0; i<=n-1; i++) - { - xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); - } - xvar = xvar/(n-1); - if( ae_fp_eq(xvar,0) ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - return; - } - - /* - * Statistic - */ - stat = (n-1)*xvar/variance; - s = chisquaredistribution(n-1, stat, _state); - *bothtails = 2*ae_minreal(s, 1-s, _state); - *lefttail = s; - *righttail = 1-(*lefttail); -} - - - - -/************************************************************************* -Wilcoxon signed-rank test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - * the distribution should be continuous and symmetric relative to its - median. - * number of distinct values in the X array should be greater than 4 - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with two decimal places in interval [0.0001, 1]. - -"Two decimal places" does not sound very impressive, but in practice the -relative error of less than 1% is enough to make a decision. - -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void wilcoxonsignedranktest(/* Real */ ae_vector* x, - ae_int_t n, - double e, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state) -{ - ae_frame _frame_block; - ae_vector _x; - ae_int_t i; - ae_int_t j; - ae_int_t k; - ae_int_t t; - double tmp; - ae_int_t tmpi; - ae_int_t ns; - ae_vector r; - ae_vector c; - double w; - double p; - double mp; - double s; - double sigma; - double mu; - - ae_frame_make(_state, &_frame_block); - ae_vector_init_copy(&_x, x, _state, ae_true); - x = &_x; - *bothtails = 0; - *lefttail = 0; - *righttail = 0; - ae_vector_init(&r, 0, DT_REAL, _state, ae_true); - ae_vector_init(&c, 0, DT_INT, _state, ae_true); - - - /* - * Prepare - */ - if( n<5 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - ae_frame_leave(_state); - return; - } - ns = 0; - for(i=0; i<=n-1; i++) - { - if( ae_fp_eq(x->ptr.p_double[i],e) ) - { - continue; - } - x->ptr.p_double[ns] = x->ptr.p_double[i]; - ns = ns+1; - } - if( ns<5 ) - { - *bothtails = 1.0; - *lefttail = 1.0; - *righttail = 1.0; - ae_frame_leave(_state); - return; - } - ae_vector_set_length(&r, ns-1+1, _state); - ae_vector_set_length(&c, ns-1+1, _state); - for(i=0; i<=ns-1; i++) - { - r.ptr.p_double[i] = ae_fabs(x->ptr.p_double[i]-e, _state); - c.ptr.p_int[i] = i; - } - - /* - * sort {R, C} - */ - if( ns!=1 ) - { - i = 2; - do - { - t = i; - while(t!=1) - { - k = t/2; - if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) - { - t = 1; - } - else - { - tmp = r.ptr.p_double[k-1]; - r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; - r.ptr.p_double[t-1] = tmp; - tmpi = c.ptr.p_int[k-1]; - c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; - c.ptr.p_int[t-1] = tmpi; - t = k; - } - } - i = i+1; - } - while(i<=ns); - i = ns-1; - do - { - tmp = r.ptr.p_double[i]; - r.ptr.p_double[i] = r.ptr.p_double[0]; - r.ptr.p_double[0] = tmp; - tmpi = c.ptr.p_int[i]; - c.ptr.p_int[i] = c.ptr.p_int[0]; - c.ptr.p_int[0] = tmpi; - t = 1; - while(t!=0) - { - k = 2*t; - if( k>i ) - { - t = 0; - } - else - { - if( k=1); - } - - /* - * compute tied ranks - */ - i = 0; - while(i<=ns-1) - { - j = i+1; - while(j<=ns-1) - { - if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) - { - break; - } - j = j+1; - } - for(k=i; k<=j-1; k++) - { - r.ptr.p_double[k] = 1+(double)(i+j-1)/(double)2; - } - i = j; - } - - /* - * Compute W+ - */ - w = 0; - for(i=0; i<=ns-1; i++) - { - if( ae_fp_greater(x->ptr.p_double[c.ptr.p_int[i]],e) ) - { - w = w+r.ptr.p_double[i]; - } - } - - /* - * Result - */ - mu = (double)(ns*(ns+1))/(double)4; - sigma = ae_sqrt((double)(ns*(ns+1)*(2*ns+1))/(double)24, _state); - s = (w-mu)/sigma; - if( ae_fp_less_eq(s,0) ) - { - p = ae_exp(wsr_wsigma(-(w-mu)/sigma, ns, _state), _state); - mp = 1-ae_exp(wsr_wsigma(-(w-1-mu)/sigma, ns, _state), _state); - } - else - { - mp = ae_exp(wsr_wsigma((w-mu)/sigma, ns, _state), _state); - p = 1-ae_exp(wsr_wsigma((w+1-mu)/sigma, ns, _state), _state); - } - *bothtails = ae_maxreal(2*ae_minreal(p, mp, _state), 1.0E-4, _state); - *lefttail = ae_maxreal(p, 1.0E-4, _state); - *righttail = ae_maxreal(mp, 1.0E-4, _state); - ae_frame_leave(_state); -} - - -/************************************************************************* -Sequential Chebyshev interpolation. -*************************************************************************/ -static void wsr_wcheb(double x, - double c, - double* tj, - double* tj1, - double* r, - ae_state *_state) -{ - double t; - - - *r = *r+c*(*tj); - t = 2*x*(*tj1)-(*tj); - *tj = *tj1; - *tj1 = t; -} - - -/************************************************************************* -Tail(S, 5) -*************************************************************************/ -static double wsr_w5(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-3.708099e+00*s+7.500000e+00, _state); - if( w>=7 ) - { - r = -6.931e-01; - } - if( w==6 ) - { - r = -9.008e-01; - } - if( w==5 ) - { - r = -1.163e+00; - } - if( w==4 ) - { - r = -1.520e+00; - } - if( w==3 ) - { - r = -1.856e+00; - } - if( w==2 ) - { - r = -2.367e+00; - } - if( w==1 ) - { - r = -2.773e+00; - } - if( w<=0 ) - { - r = -3.466e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 6) -*************************************************************************/ -static double wsr_w6(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-4.769696e+00*s+1.050000e+01, _state); - if( w>=10 ) - { - r = -6.931e-01; - } - if( w==9 ) - { - r = -8.630e-01; - } - if( w==8 ) - { - r = -1.068e+00; - } - if( w==7 ) - { - r = -1.269e+00; - } - if( w==6 ) - { - r = -1.520e+00; - } - if( w==5 ) - { - r = -1.856e+00; - } - if( w==4 ) - { - r = -2.213e+00; - } - if( w==3 ) - { - r = -2.549e+00; - } - if( w==2 ) - { - r = -3.060e+00; - } - if( w==1 ) - { - r = -3.466e+00; - } - if( w<=0 ) - { - r = -4.159e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 7) -*************************************************************************/ -static double wsr_w7(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-5.916080e+00*s+1.400000e+01, _state); - if( w>=14 ) - { - r = -6.325e-01; - } - if( w==13 ) - { - r = -7.577e-01; - } - if( w==12 ) - { - r = -9.008e-01; - } - if( w==11 ) - { - r = -1.068e+00; - } - if( w==10 ) - { - r = -1.241e+00; - } - if( w==9 ) - { - r = -1.451e+00; - } - if( w==8 ) - { - r = -1.674e+00; - } - if( w==7 ) - { - r = -1.908e+00; - } - if( w==6 ) - { - r = -2.213e+00; - } - if( w==5 ) - { - r = -2.549e+00; - } - if( w==4 ) - { - r = -2.906e+00; - } - if( w==3 ) - { - r = -3.243e+00; - } - if( w==2 ) - { - r = -3.753e+00; - } - if( w==1 ) - { - r = -4.159e+00; - } - if( w<=0 ) - { - r = -4.852e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 8) -*************************************************************************/ -static double wsr_w8(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-7.141428e+00*s+1.800000e+01, _state); - if( w>=18 ) - { - r = -6.399e-01; - } - if( w==17 ) - { - r = -7.494e-01; - } - if( w==16 ) - { - r = -8.630e-01; - } - if( w==15 ) - { - r = -9.913e-01; - } - if( w==14 ) - { - r = -1.138e+00; - } - if( w==13 ) - { - r = -1.297e+00; - } - if( w==12 ) - { - r = -1.468e+00; - } - if( w==11 ) - { - r = -1.653e+00; - } - if( w==10 ) - { - r = -1.856e+00; - } - if( w==9 ) - { - r = -2.079e+00; - } - if( w==8 ) - { - r = -2.326e+00; - } - if( w==7 ) - { - r = -2.601e+00; - } - if( w==6 ) - { - r = -2.906e+00; - } - if( w==5 ) - { - r = -3.243e+00; - } - if( w==4 ) - { - r = -3.599e+00; - } - if( w==3 ) - { - r = -3.936e+00; - } - if( w==2 ) - { - r = -4.447e+00; - } - if( w==1 ) - { - r = -4.852e+00; - } - if( w<=0 ) - { - r = -5.545e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 9) -*************************************************************************/ -static double wsr_w9(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-8.440972e+00*s+2.250000e+01, _state); - if( w>=22 ) - { - r = -6.931e-01; - } - if( w==21 ) - { - r = -7.873e-01; - } - if( w==20 ) - { - r = -8.912e-01; - } - if( w==19 ) - { - r = -1.002e+00; - } - if( w==18 ) - { - r = -1.120e+00; - } - if( w==17 ) - { - r = -1.255e+00; - } - if( w==16 ) - { - r = -1.394e+00; - } - if( w==15 ) - { - r = -1.547e+00; - } - if( w==14 ) - { - r = -1.717e+00; - } - if( w==13 ) - { - r = -1.895e+00; - } - if( w==12 ) - { - r = -2.079e+00; - } - if( w==11 ) - { - r = -2.287e+00; - } - if( w==10 ) - { - r = -2.501e+00; - } - if( w==9 ) - { - r = -2.742e+00; - } - if( w==8 ) - { - r = -3.019e+00; - } - if( w==7 ) - { - r = -3.294e+00; - } - if( w==6 ) - { - r = -3.599e+00; - } - if( w==5 ) - { - r = -3.936e+00; - } - if( w==4 ) - { - r = -4.292e+00; - } - if( w==3 ) - { - r = -4.629e+00; - } - if( w==2 ) - { - r = -5.140e+00; - } - if( w==1 ) - { - r = -5.545e+00; - } - if( w<=0 ) - { - r = -6.238e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 10) -*************************************************************************/ -static double wsr_w10(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-9.810708e+00*s+2.750000e+01, _state); - if( w>=27 ) - { - r = -6.931e-01; - } - if( w==26 ) - { - r = -7.745e-01; - } - if( w==25 ) - { - r = -8.607e-01; - } - if( w==24 ) - { - r = -9.551e-01; - } - if( w==23 ) - { - r = -1.057e+00; - } - if( w==22 ) - { - r = -1.163e+00; - } - if( w==21 ) - { - r = -1.279e+00; - } - if( w==20 ) - { - r = -1.402e+00; - } - if( w==19 ) - { - r = -1.533e+00; - } - if( w==18 ) - { - r = -1.674e+00; - } - if( w==17 ) - { - r = -1.826e+00; - } - if( w==16 ) - { - r = -1.983e+00; - } - if( w==15 ) - { - r = -2.152e+00; - } - if( w==14 ) - { - r = -2.336e+00; - } - if( w==13 ) - { - r = -2.525e+00; - } - if( w==12 ) - { - r = -2.727e+00; - } - if( w==11 ) - { - r = -2.942e+00; - } - if( w==10 ) - { - r = -3.170e+00; - } - if( w==9 ) - { - r = -3.435e+00; - } - if( w==8 ) - { - r = -3.713e+00; - } - if( w==7 ) - { - r = -3.987e+00; - } - if( w==6 ) - { - r = -4.292e+00; - } - if( w==5 ) - { - r = -4.629e+00; - } - if( w==4 ) - { - r = -4.986e+00; - } - if( w==3 ) - { - r = -5.322e+00; - } - if( w==2 ) - { - r = -5.833e+00; - } - if( w==1 ) - { - r = -6.238e+00; - } - if( w<=0 ) - { - r = -6.931e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 11) -*************************************************************************/ -static double wsr_w11(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.124722e+01*s+3.300000e+01, _state); - if( w>=33 ) - { - r = -6.595e-01; - } - if( w==32 ) - { - r = -7.279e-01; - } - if( w==31 ) - { - r = -8.002e-01; - } - if( w==30 ) - { - r = -8.782e-01; - } - if( w==29 ) - { - r = -9.615e-01; - } - if( w==28 ) - { - r = -1.050e+00; - } - if( w==27 ) - { - r = -1.143e+00; - } - if( w==26 ) - { - r = -1.243e+00; - } - if( w==25 ) - { - r = -1.348e+00; - } - if( w==24 ) - { - r = -1.459e+00; - } - if( w==23 ) - { - r = -1.577e+00; - } - if( w==22 ) - { - r = -1.700e+00; - } - if( w==21 ) - { - r = -1.832e+00; - } - if( w==20 ) - { - r = -1.972e+00; - } - if( w==19 ) - { - r = -2.119e+00; - } - if( w==18 ) - { - r = -2.273e+00; - } - if( w==17 ) - { - r = -2.437e+00; - } - if( w==16 ) - { - r = -2.607e+00; - } - if( w==15 ) - { - r = -2.788e+00; - } - if( w==14 ) - { - r = -2.980e+00; - } - if( w==13 ) - { - r = -3.182e+00; - } - if( w==12 ) - { - r = -3.391e+00; - } - if( w==11 ) - { - r = -3.617e+00; - } - if( w==10 ) - { - r = -3.863e+00; - } - if( w==9 ) - { - r = -4.128e+00; - } - if( w==8 ) - { - r = -4.406e+00; - } - if( w==7 ) - { - r = -4.680e+00; - } - if( w==6 ) - { - r = -4.986e+00; - } - if( w==5 ) - { - r = -5.322e+00; - } - if( w==4 ) - { - r = -5.679e+00; - } - if( w==3 ) - { - r = -6.015e+00; - } - if( w==2 ) - { - r = -6.526e+00; - } - if( w==1 ) - { - r = -6.931e+00; - } - if( w<=0 ) - { - r = -7.625e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 12) -*************************************************************************/ -static double wsr_w12(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.274755e+01*s+3.900000e+01, _state); - if( w>=39 ) - { - r = -6.633e-01; - } - if( w==38 ) - { - r = -7.239e-01; - } - if( w==37 ) - { - r = -7.878e-01; - } - if( w==36 ) - { - r = -8.556e-01; - } - if( w==35 ) - { - r = -9.276e-01; - } - if( w==34 ) - { - r = -1.003e+00; - } - if( w==33 ) - { - r = -1.083e+00; - } - if( w==32 ) - { - r = -1.168e+00; - } - if( w==31 ) - { - r = -1.256e+00; - } - if( w==30 ) - { - r = -1.350e+00; - } - if( w==29 ) - { - r = -1.449e+00; - } - if( w==28 ) - { - r = -1.552e+00; - } - if( w==27 ) - { - r = -1.660e+00; - } - if( w==26 ) - { - r = -1.774e+00; - } - if( w==25 ) - { - r = -1.893e+00; - } - if( w==24 ) - { - r = -2.017e+00; - } - if( w==23 ) - { - r = -2.148e+00; - } - if( w==22 ) - { - r = -2.285e+00; - } - if( w==21 ) - { - r = -2.429e+00; - } - if( w==20 ) - { - r = -2.581e+00; - } - if( w==19 ) - { - r = -2.738e+00; - } - if( w==18 ) - { - r = -2.902e+00; - } - if( w==17 ) - { - r = -3.076e+00; - } - if( w==16 ) - { - r = -3.255e+00; - } - if( w==15 ) - { - r = -3.443e+00; - } - if( w==14 ) - { - r = -3.645e+00; - } - if( w==13 ) - { - r = -3.852e+00; - } - if( w==12 ) - { - r = -4.069e+00; - } - if( w==11 ) - { - r = -4.310e+00; - } - if( w==10 ) - { - r = -4.557e+00; - } - if( w==9 ) - { - r = -4.821e+00; - } - if( w==8 ) - { - r = -5.099e+00; - } - if( w==7 ) - { - r = -5.373e+00; - } - if( w==6 ) - { - r = -5.679e+00; - } - if( w==5 ) - { - r = -6.015e+00; - } - if( w==4 ) - { - r = -6.372e+00; - } - if( w==3 ) - { - r = -6.708e+00; - } - if( w==2 ) - { - r = -7.219e+00; - } - if( w==1 ) - { - r = -7.625e+00; - } - if( w<=0 ) - { - r = -8.318e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 13) -*************************************************************************/ -static double wsr_w13(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.430909e+01*s+4.550000e+01, _state); - if( w>=45 ) - { - r = -6.931e-01; - } - if( w==44 ) - { - r = -7.486e-01; - } - if( w==43 ) - { - r = -8.068e-01; - } - if( w==42 ) - { - r = -8.683e-01; - } - if( w==41 ) - { - r = -9.328e-01; - } - if( w==40 ) - { - r = -1.001e+00; - } - if( w==39 ) - { - r = -1.072e+00; - } - if( w==38 ) - { - r = -1.146e+00; - } - if( w==37 ) - { - r = -1.224e+00; - } - if( w==36 ) - { - r = -1.306e+00; - } - if( w==35 ) - { - r = -1.392e+00; - } - if( w==34 ) - { - r = -1.481e+00; - } - if( w==33 ) - { - r = -1.574e+00; - } - if( w==32 ) - { - r = -1.672e+00; - } - if( w==31 ) - { - r = -1.773e+00; - } - if( w==30 ) - { - r = -1.879e+00; - } - if( w==29 ) - { - r = -1.990e+00; - } - if( w==28 ) - { - r = -2.104e+00; - } - if( w==27 ) - { - r = -2.224e+00; - } - if( w==26 ) - { - r = -2.349e+00; - } - if( w==25 ) - { - r = -2.479e+00; - } - if( w==24 ) - { - r = -2.614e+00; - } - if( w==23 ) - { - r = -2.755e+00; - } - if( w==22 ) - { - r = -2.902e+00; - } - if( w==21 ) - { - r = -3.055e+00; - } - if( w==20 ) - { - r = -3.215e+00; - } - if( w==19 ) - { - r = -3.380e+00; - } - if( w==18 ) - { - r = -3.551e+00; - } - if( w==17 ) - { - r = -3.733e+00; - } - if( w==16 ) - { - r = -3.917e+00; - } - if( w==15 ) - { - r = -4.113e+00; - } - if( w==14 ) - { - r = -4.320e+00; - } - if( w==13 ) - { - r = -4.534e+00; - } - if( w==12 ) - { - r = -4.762e+00; - } - if( w==11 ) - { - r = -5.004e+00; - } - if( w==10 ) - { - r = -5.250e+00; - } - if( w==9 ) - { - r = -5.514e+00; - } - if( w==8 ) - { - r = -5.792e+00; - } - if( w==7 ) - { - r = -6.066e+00; - } - if( w==6 ) - { - r = -6.372e+00; - } - if( w==5 ) - { - r = -6.708e+00; - } - if( w==4 ) - { - r = -7.065e+00; - } - if( w==3 ) - { - r = -7.401e+00; - } - if( w==2 ) - { - r = -7.912e+00; - } - if( w==1 ) - { - r = -8.318e+00; - } - if( w<=0 ) - { - r = -9.011e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 14) -*************************************************************************/ -static double wsr_w14(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.592953e+01*s+5.250000e+01, _state); - if( w>=52 ) - { - r = -6.931e-01; - } - if( w==51 ) - { - r = -7.428e-01; - } - if( w==50 ) - { - r = -7.950e-01; - } - if( w==49 ) - { - r = -8.495e-01; - } - if( w==48 ) - { - r = -9.067e-01; - } - if( w==47 ) - { - r = -9.664e-01; - } - if( w==46 ) - { - r = -1.029e+00; - } - if( w==45 ) - { - r = -1.094e+00; - } - if( w==44 ) - { - r = -1.162e+00; - } - if( w==43 ) - { - r = -1.233e+00; - } - if( w==42 ) - { - r = -1.306e+00; - } - if( w==41 ) - { - r = -1.383e+00; - } - if( w==40 ) - { - r = -1.463e+00; - } - if( w==39 ) - { - r = -1.546e+00; - } - if( w==38 ) - { - r = -1.632e+00; - } - if( w==37 ) - { - r = -1.722e+00; - } - if( w==36 ) - { - r = -1.815e+00; - } - if( w==35 ) - { - r = -1.911e+00; - } - if( w==34 ) - { - r = -2.011e+00; - } - if( w==33 ) - { - r = -2.115e+00; - } - if( w==32 ) - { - r = -2.223e+00; - } - if( w==31 ) - { - r = -2.334e+00; - } - if( w==30 ) - { - r = -2.450e+00; - } - if( w==29 ) - { - r = -2.570e+00; - } - if( w==28 ) - { - r = -2.694e+00; - } - if( w==27 ) - { - r = -2.823e+00; - } - if( w==26 ) - { - r = -2.956e+00; - } - if( w==25 ) - { - r = -3.095e+00; - } - if( w==24 ) - { - r = -3.238e+00; - } - if( w==23 ) - { - r = -3.387e+00; - } - if( w==22 ) - { - r = -3.541e+00; - } - if( w==21 ) - { - r = -3.700e+00; - } - if( w==20 ) - { - r = -3.866e+00; - } - if( w==19 ) - { - r = -4.038e+00; - } - if( w==18 ) - { - r = -4.215e+00; - } - if( w==17 ) - { - r = -4.401e+00; - } - if( w==16 ) - { - r = -4.592e+00; - } - if( w==15 ) - { - r = -4.791e+00; - } - if( w==14 ) - { - r = -5.004e+00; - } - if( w==13 ) - { - r = -5.227e+00; - } - if( w==12 ) - { - r = -5.456e+00; - } - if( w==11 ) - { - r = -5.697e+00; - } - if( w==10 ) - { - r = -5.943e+00; - } - if( w==9 ) - { - r = -6.208e+00; - } - if( w==8 ) - { - r = -6.485e+00; - } - if( w==7 ) - { - r = -6.760e+00; - } - if( w==6 ) - { - r = -7.065e+00; - } - if( w==5 ) - { - r = -7.401e+00; - } - if( w==4 ) - { - r = -7.758e+00; - } - if( w==3 ) - { - r = -8.095e+00; - } - if( w==2 ) - { - r = -8.605e+00; - } - if( w==1 ) - { - r = -9.011e+00; - } - if( w<=0 ) - { - r = -9.704e+00; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 15) -*************************************************************************/ -static double wsr_w15(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.760682e+01*s+6.000000e+01, _state); - if( w>=60 ) - { - r = -6.714e-01; - } - if( w==59 ) - { - r = -7.154e-01; - } - if( w==58 ) - { - r = -7.613e-01; - } - if( w==57 ) - { - r = -8.093e-01; - } - if( w==56 ) - { - r = -8.593e-01; - } - if( w==55 ) - { - r = -9.114e-01; - } - if( w==54 ) - { - r = -9.656e-01; - } - if( w==53 ) - { - r = -1.022e+00; - } - if( w==52 ) - { - r = -1.081e+00; - } - if( w==51 ) - { - r = -1.142e+00; - } - if( w==50 ) - { - r = -1.205e+00; - } - if( w==49 ) - { - r = -1.270e+00; - } - if( w==48 ) - { - r = -1.339e+00; - } - if( w==47 ) - { - r = -1.409e+00; - } - if( w==46 ) - { - r = -1.482e+00; - } - if( w==45 ) - { - r = -1.558e+00; - } - if( w==44 ) - { - r = -1.636e+00; - } - if( w==43 ) - { - r = -1.717e+00; - } - if( w==42 ) - { - r = -1.801e+00; - } - if( w==41 ) - { - r = -1.888e+00; - } - if( w==40 ) - { - r = -1.977e+00; - } - if( w==39 ) - { - r = -2.070e+00; - } - if( w==38 ) - { - r = -2.166e+00; - } - if( w==37 ) - { - r = -2.265e+00; - } - if( w==36 ) - { - r = -2.366e+00; - } - if( w==35 ) - { - r = -2.472e+00; - } - if( w==34 ) - { - r = -2.581e+00; - } - if( w==33 ) - { - r = -2.693e+00; - } - if( w==32 ) - { - r = -2.809e+00; - } - if( w==31 ) - { - r = -2.928e+00; - } - if( w==30 ) - { - r = -3.051e+00; - } - if( w==29 ) - { - r = -3.179e+00; - } - if( w==28 ) - { - r = -3.310e+00; - } - if( w==27 ) - { - r = -3.446e+00; - } - if( w==26 ) - { - r = -3.587e+00; - } - if( w==25 ) - { - r = -3.732e+00; - } - if( w==24 ) - { - r = -3.881e+00; - } - if( w==23 ) - { - r = -4.036e+00; - } - if( w==22 ) - { - r = -4.195e+00; - } - if( w==21 ) - { - r = -4.359e+00; - } - if( w==20 ) - { - r = -4.531e+00; - } - if( w==19 ) - { - r = -4.707e+00; - } - if( w==18 ) - { - r = -4.888e+00; - } - if( w==17 ) - { - r = -5.079e+00; - } - if( w==16 ) - { - r = -5.273e+00; - } - if( w==15 ) - { - r = -5.477e+00; - } - if( w==14 ) - { - r = -5.697e+00; - } - if( w==13 ) - { - r = -5.920e+00; - } - if( w==12 ) - { - r = -6.149e+00; - } - if( w==11 ) - { - r = -6.390e+00; - } - if( w==10 ) - { - r = -6.636e+00; - } - if( w==9 ) - { - r = -6.901e+00; - } - if( w==8 ) - { - r = -7.178e+00; - } - if( w==7 ) - { - r = -7.453e+00; - } - if( w==6 ) - { - r = -7.758e+00; - } - if( w==5 ) - { - r = -8.095e+00; - } - if( w==4 ) - { - r = -8.451e+00; - } - if( w==3 ) - { - r = -8.788e+00; - } - if( w==2 ) - { - r = -9.299e+00; - } - if( w==1 ) - { - r = -9.704e+00; - } - if( w<=0 ) - { - r = -1.040e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 16) -*************************************************************************/ -static double wsr_w16(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-1.933908e+01*s+6.800000e+01, _state); - if( w>=68 ) - { - r = -6.733e-01; - } - if( w==67 ) - { - r = -7.134e-01; - } - if( w==66 ) - { - r = -7.551e-01; - } - if( w==65 ) - { - r = -7.986e-01; - } - if( w==64 ) - { - r = -8.437e-01; - } - if( w==63 ) - { - r = -8.905e-01; - } - if( w==62 ) - { - r = -9.391e-01; - } - if( w==61 ) - { - r = -9.895e-01; - } - if( w==60 ) - { - r = -1.042e+00; - } - if( w==59 ) - { - r = -1.096e+00; - } - if( w==58 ) - { - r = -1.152e+00; - } - if( w==57 ) - { - r = -1.210e+00; - } - if( w==56 ) - { - r = -1.270e+00; - } - if( w==55 ) - { - r = -1.331e+00; - } - if( w==54 ) - { - r = -1.395e+00; - } - if( w==53 ) - { - r = -1.462e+00; - } - if( w==52 ) - { - r = -1.530e+00; - } - if( w==51 ) - { - r = -1.600e+00; - } - if( w==50 ) - { - r = -1.673e+00; - } - if( w==49 ) - { - r = -1.748e+00; - } - if( w==48 ) - { - r = -1.825e+00; - } - if( w==47 ) - { - r = -1.904e+00; - } - if( w==46 ) - { - r = -1.986e+00; - } - if( w==45 ) - { - r = -2.071e+00; - } - if( w==44 ) - { - r = -2.158e+00; - } - if( w==43 ) - { - r = -2.247e+00; - } - if( w==42 ) - { - r = -2.339e+00; - } - if( w==41 ) - { - r = -2.434e+00; - } - if( w==40 ) - { - r = -2.532e+00; - } - if( w==39 ) - { - r = -2.632e+00; - } - if( w==38 ) - { - r = -2.735e+00; - } - if( w==37 ) - { - r = -2.842e+00; - } - if( w==36 ) - { - r = -2.951e+00; - } - if( w==35 ) - { - r = -3.064e+00; - } - if( w==34 ) - { - r = -3.179e+00; - } - if( w==33 ) - { - r = -3.298e+00; - } - if( w==32 ) - { - r = -3.420e+00; - } - if( w==31 ) - { - r = -3.546e+00; - } - if( w==30 ) - { - r = -3.676e+00; - } - if( w==29 ) - { - r = -3.810e+00; - } - if( w==28 ) - { - r = -3.947e+00; - } - if( w==27 ) - { - r = -4.088e+00; - } - if( w==26 ) - { - r = -4.234e+00; - } - if( w==25 ) - { - r = -4.383e+00; - } - if( w==24 ) - { - r = -4.538e+00; - } - if( w==23 ) - { - r = -4.697e+00; - } - if( w==22 ) - { - r = -4.860e+00; - } - if( w==21 ) - { - r = -5.029e+00; - } - if( w==20 ) - { - r = -5.204e+00; - } - if( w==19 ) - { - r = -5.383e+00; - } - if( w==18 ) - { - r = -5.569e+00; - } - if( w==17 ) - { - r = -5.762e+00; - } - if( w==16 ) - { - r = -5.960e+00; - } - if( w==15 ) - { - r = -6.170e+00; - } - if( w==14 ) - { - r = -6.390e+00; - } - if( w==13 ) - { - r = -6.613e+00; - } - if( w==12 ) - { - r = -6.842e+00; - } - if( w==11 ) - { - r = -7.083e+00; - } - if( w==10 ) - { - r = -7.329e+00; - } - if( w==9 ) - { - r = -7.594e+00; - } - if( w==8 ) - { - r = -7.871e+00; - } - if( w==7 ) - { - r = -8.146e+00; - } - if( w==6 ) - { - r = -8.451e+00; - } - if( w==5 ) - { - r = -8.788e+00; - } - if( w==4 ) - { - r = -9.144e+00; - } - if( w==3 ) - { - r = -9.481e+00; - } - if( w==2 ) - { - r = -9.992e+00; - } - if( w==1 ) - { - r = -1.040e+01; - } - if( w<=0 ) - { - r = -1.109e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 17) -*************************************************************************/ -static double wsr_w17(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-2.112463e+01*s+7.650000e+01, _state); - if( w>=76 ) - { - r = -6.931e-01; - } - if( w==75 ) - { - r = -7.306e-01; - } - if( w==74 ) - { - r = -7.695e-01; - } - if( w==73 ) - { - r = -8.097e-01; - } - if( w==72 ) - { - r = -8.514e-01; - } - if( w==71 ) - { - r = -8.946e-01; - } - if( w==70 ) - { - r = -9.392e-01; - } - if( w==69 ) - { - r = -9.853e-01; - } - if( w==68 ) - { - r = -1.033e+00; - } - if( w==67 ) - { - r = -1.082e+00; - } - if( w==66 ) - { - r = -1.133e+00; - } - if( w==65 ) - { - r = -1.185e+00; - } - if( w==64 ) - { - r = -1.240e+00; - } - if( w==63 ) - { - r = -1.295e+00; - } - if( w==62 ) - { - r = -1.353e+00; - } - if( w==61 ) - { - r = -1.412e+00; - } - if( w==60 ) - { - r = -1.473e+00; - } - if( w==59 ) - { - r = -1.536e+00; - } - if( w==58 ) - { - r = -1.600e+00; - } - if( w==57 ) - { - r = -1.666e+00; - } - if( w==56 ) - { - r = -1.735e+00; - } - if( w==55 ) - { - r = -1.805e+00; - } - if( w==54 ) - { - r = -1.877e+00; - } - if( w==53 ) - { - r = -1.951e+00; - } - if( w==52 ) - { - r = -2.028e+00; - } - if( w==51 ) - { - r = -2.106e+00; - } - if( w==50 ) - { - r = -2.186e+00; - } - if( w==49 ) - { - r = -2.269e+00; - } - if( w==48 ) - { - r = -2.353e+00; - } - if( w==47 ) - { - r = -2.440e+00; - } - if( w==46 ) - { - r = -2.530e+00; - } - if( w==45 ) - { - r = -2.621e+00; - } - if( w==44 ) - { - r = -2.715e+00; - } - if( w==43 ) - { - r = -2.812e+00; - } - if( w==42 ) - { - r = -2.911e+00; - } - if( w==41 ) - { - r = -3.012e+00; - } - if( w==40 ) - { - r = -3.116e+00; - } - if( w==39 ) - { - r = -3.223e+00; - } - if( w==38 ) - { - r = -3.332e+00; - } - if( w==37 ) - { - r = -3.445e+00; - } - if( w==36 ) - { - r = -3.560e+00; - } - if( w==35 ) - { - r = -3.678e+00; - } - if( w==34 ) - { - r = -3.799e+00; - } - if( w==33 ) - { - r = -3.924e+00; - } - if( w==32 ) - { - r = -4.052e+00; - } - if( w==31 ) - { - r = -4.183e+00; - } - if( w==30 ) - { - r = -4.317e+00; - } - if( w==29 ) - { - r = -4.456e+00; - } - if( w==28 ) - { - r = -4.597e+00; - } - if( w==27 ) - { - r = -4.743e+00; - } - if( w==26 ) - { - r = -4.893e+00; - } - if( w==25 ) - { - r = -5.047e+00; - } - if( w==24 ) - { - r = -5.204e+00; - } - if( w==23 ) - { - r = -5.367e+00; - } - if( w==22 ) - { - r = -5.534e+00; - } - if( w==21 ) - { - r = -5.706e+00; - } - if( w==20 ) - { - r = -5.884e+00; - } - if( w==19 ) - { - r = -6.066e+00; - } - if( w==18 ) - { - r = -6.254e+00; - } - if( w==17 ) - { - r = -6.451e+00; - } - if( w==16 ) - { - r = -6.654e+00; - } - if( w==15 ) - { - r = -6.864e+00; - } - if( w==14 ) - { - r = -7.083e+00; - } - if( w==13 ) - { - r = -7.306e+00; - } - if( w==12 ) - { - r = -7.535e+00; - } - if( w==11 ) - { - r = -7.776e+00; - } - if( w==10 ) - { - r = -8.022e+00; - } - if( w==9 ) - { - r = -8.287e+00; - } - if( w==8 ) - { - r = -8.565e+00; - } - if( w==7 ) - { - r = -8.839e+00; - } - if( w==6 ) - { - r = -9.144e+00; - } - if( w==5 ) - { - r = -9.481e+00; - } - if( w==4 ) - { - r = -9.838e+00; - } - if( w==3 ) - { - r = -1.017e+01; - } - if( w==2 ) - { - r = -1.068e+01; - } - if( w==1 ) - { - r = -1.109e+01; - } - if( w<=0 ) - { - r = -1.178e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 18) -*************************************************************************/ -static double wsr_w18(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-2.296193e+01*s+8.550000e+01, _state); - if( w>=85 ) - { - r = -6.931e-01; - } - if( w==84 ) - { - r = -7.276e-01; - } - if( w==83 ) - { - r = -7.633e-01; - } - if( w==82 ) - { - r = -8.001e-01; - } - if( w==81 ) - { - r = -8.381e-01; - } - if( w==80 ) - { - r = -8.774e-01; - } - if( w==79 ) - { - r = -9.179e-01; - } - if( w==78 ) - { - r = -9.597e-01; - } - if( w==77 ) - { - r = -1.003e+00; - } - if( w==76 ) - { - r = -1.047e+00; - } - if( w==75 ) - { - r = -1.093e+00; - } - if( w==74 ) - { - r = -1.140e+00; - } - if( w==73 ) - { - r = -1.188e+00; - } - if( w==72 ) - { - r = -1.238e+00; - } - if( w==71 ) - { - r = -1.289e+00; - } - if( w==70 ) - { - r = -1.342e+00; - } - if( w==69 ) - { - r = -1.396e+00; - } - if( w==68 ) - { - r = -1.452e+00; - } - if( w==67 ) - { - r = -1.509e+00; - } - if( w==66 ) - { - r = -1.568e+00; - } - if( w==65 ) - { - r = -1.628e+00; - } - if( w==64 ) - { - r = -1.690e+00; - } - if( w==63 ) - { - r = -1.753e+00; - } - if( w==62 ) - { - r = -1.818e+00; - } - if( w==61 ) - { - r = -1.885e+00; - } - if( w==60 ) - { - r = -1.953e+00; - } - if( w==59 ) - { - r = -2.023e+00; - } - if( w==58 ) - { - r = -2.095e+00; - } - if( w==57 ) - { - r = -2.168e+00; - } - if( w==56 ) - { - r = -2.244e+00; - } - if( w==55 ) - { - r = -2.321e+00; - } - if( w==54 ) - { - r = -2.400e+00; - } - if( w==53 ) - { - r = -2.481e+00; - } - if( w==52 ) - { - r = -2.564e+00; - } - if( w==51 ) - { - r = -2.648e+00; - } - if( w==50 ) - { - r = -2.735e+00; - } - if( w==49 ) - { - r = -2.824e+00; - } - if( w==48 ) - { - r = -2.915e+00; - } - if( w==47 ) - { - r = -3.008e+00; - } - if( w==46 ) - { - r = -3.104e+00; - } - if( w==45 ) - { - r = -3.201e+00; - } - if( w==44 ) - { - r = -3.301e+00; - } - if( w==43 ) - { - r = -3.403e+00; - } - if( w==42 ) - { - r = -3.508e+00; - } - if( w==41 ) - { - r = -3.615e+00; - } - if( w==40 ) - { - r = -3.724e+00; - } - if( w==39 ) - { - r = -3.836e+00; - } - if( w==38 ) - { - r = -3.950e+00; - } - if( w==37 ) - { - r = -4.068e+00; - } - if( w==36 ) - { - r = -4.188e+00; - } - if( w==35 ) - { - r = -4.311e+00; - } - if( w==34 ) - { - r = -4.437e+00; - } - if( w==33 ) - { - r = -4.565e+00; - } - if( w==32 ) - { - r = -4.698e+00; - } - if( w==31 ) - { - r = -4.833e+00; - } - if( w==30 ) - { - r = -4.971e+00; - } - if( w==29 ) - { - r = -5.113e+00; - } - if( w==28 ) - { - r = -5.258e+00; - } - if( w==27 ) - { - r = -5.408e+00; - } - if( w==26 ) - { - r = -5.561e+00; - } - if( w==25 ) - { - r = -5.717e+00; - } - if( w==24 ) - { - r = -5.878e+00; - } - if( w==23 ) - { - r = -6.044e+00; - } - if( w==22 ) - { - r = -6.213e+00; - } - if( w==21 ) - { - r = -6.388e+00; - } - if( w==20 ) - { - r = -6.569e+00; - } - if( w==19 ) - { - r = -6.753e+00; - } - if( w==18 ) - { - r = -6.943e+00; - } - if( w==17 ) - { - r = -7.144e+00; - } - if( w==16 ) - { - r = -7.347e+00; - } - if( w==15 ) - { - r = -7.557e+00; - } - if( w==14 ) - { - r = -7.776e+00; - } - if( w==13 ) - { - r = -7.999e+00; - } - if( w==12 ) - { - r = -8.228e+00; - } - if( w==11 ) - { - r = -8.469e+00; - } - if( w==10 ) - { - r = -8.715e+00; - } - if( w==9 ) - { - r = -8.980e+00; - } - if( w==8 ) - { - r = -9.258e+00; - } - if( w==7 ) - { - r = -9.532e+00; - } - if( w==6 ) - { - r = -9.838e+00; - } - if( w==5 ) - { - r = -1.017e+01; - } - if( w==4 ) - { - r = -1.053e+01; - } - if( w==3 ) - { - r = -1.087e+01; - } - if( w==2 ) - { - r = -1.138e+01; - } - if( w==1 ) - { - r = -1.178e+01; - } - if( w<=0 ) - { - r = -1.248e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 19) -*************************************************************************/ -static double wsr_w19(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-2.484955e+01*s+9.500000e+01, _state); - if( w>=95 ) - { - r = -6.776e-01; - } - if( w==94 ) - { - r = -7.089e-01; - } - if( w==93 ) - { - r = -7.413e-01; - } - if( w==92 ) - { - r = -7.747e-01; - } - if( w==91 ) - { - r = -8.090e-01; - } - if( w==90 ) - { - r = -8.445e-01; - } - if( w==89 ) - { - r = -8.809e-01; - } - if( w==88 ) - { - r = -9.185e-01; - } - if( w==87 ) - { - r = -9.571e-01; - } - if( w==86 ) - { - r = -9.968e-01; - } - if( w==85 ) - { - r = -1.038e+00; - } - if( w==84 ) - { - r = -1.080e+00; - } - if( w==83 ) - { - r = -1.123e+00; - } - if( w==82 ) - { - r = -1.167e+00; - } - if( w==81 ) - { - r = -1.213e+00; - } - if( w==80 ) - { - r = -1.259e+00; - } - if( w==79 ) - { - r = -1.307e+00; - } - if( w==78 ) - { - r = -1.356e+00; - } - if( w==77 ) - { - r = -1.407e+00; - } - if( w==76 ) - { - r = -1.458e+00; - } - if( w==75 ) - { - r = -1.511e+00; - } - if( w==74 ) - { - r = -1.565e+00; - } - if( w==73 ) - { - r = -1.621e+00; - } - if( w==72 ) - { - r = -1.678e+00; - } - if( w==71 ) - { - r = -1.736e+00; - } - if( w==70 ) - { - r = -1.796e+00; - } - if( w==69 ) - { - r = -1.857e+00; - } - if( w==68 ) - { - r = -1.919e+00; - } - if( w==67 ) - { - r = -1.983e+00; - } - if( w==66 ) - { - r = -2.048e+00; - } - if( w==65 ) - { - r = -2.115e+00; - } - if( w==64 ) - { - r = -2.183e+00; - } - if( w==63 ) - { - r = -2.253e+00; - } - if( w==62 ) - { - r = -2.325e+00; - } - if( w==61 ) - { - r = -2.398e+00; - } - if( w==60 ) - { - r = -2.472e+00; - } - if( w==59 ) - { - r = -2.548e+00; - } - if( w==58 ) - { - r = -2.626e+00; - } - if( w==57 ) - { - r = -2.706e+00; - } - if( w==56 ) - { - r = -2.787e+00; - } - if( w==55 ) - { - r = -2.870e+00; - } - if( w==54 ) - { - r = -2.955e+00; - } - if( w==53 ) - { - r = -3.042e+00; - } - if( w==52 ) - { - r = -3.130e+00; - } - if( w==51 ) - { - r = -3.220e+00; - } - if( w==50 ) - { - r = -3.313e+00; - } - if( w==49 ) - { - r = -3.407e+00; - } - if( w==48 ) - { - r = -3.503e+00; - } - if( w==47 ) - { - r = -3.601e+00; - } - if( w==46 ) - { - r = -3.702e+00; - } - if( w==45 ) - { - r = -3.804e+00; - } - if( w==44 ) - { - r = -3.909e+00; - } - if( w==43 ) - { - r = -4.015e+00; - } - if( w==42 ) - { - r = -4.125e+00; - } - if( w==41 ) - { - r = -4.236e+00; - } - if( w==40 ) - { - r = -4.350e+00; - } - if( w==39 ) - { - r = -4.466e+00; - } - if( w==38 ) - { - r = -4.585e+00; - } - if( w==37 ) - { - r = -4.706e+00; - } - if( w==36 ) - { - r = -4.830e+00; - } - if( w==35 ) - { - r = -4.957e+00; - } - if( w==34 ) - { - r = -5.086e+00; - } - if( w==33 ) - { - r = -5.219e+00; - } - if( w==32 ) - { - r = -5.355e+00; - } - if( w==31 ) - { - r = -5.493e+00; - } - if( w==30 ) - { - r = -5.634e+00; - } - if( w==29 ) - { - r = -5.780e+00; - } - if( w==28 ) - { - r = -5.928e+00; - } - if( w==27 ) - { - r = -6.080e+00; - } - if( w==26 ) - { - r = -6.235e+00; - } - if( w==25 ) - { - r = -6.394e+00; - } - if( w==24 ) - { - r = -6.558e+00; - } - if( w==23 ) - { - r = -6.726e+00; - } - if( w==22 ) - { - r = -6.897e+00; - } - if( w==21 ) - { - r = -7.074e+00; - } - if( w==20 ) - { - r = -7.256e+00; - } - if( w==19 ) - { - r = -7.443e+00; - } - if( w==18 ) - { - r = -7.636e+00; - } - if( w==17 ) - { - r = -7.837e+00; - } - if( w==16 ) - { - r = -8.040e+00; - } - if( w==15 ) - { - r = -8.250e+00; - } - if( w==14 ) - { - r = -8.469e+00; - } - if( w==13 ) - { - r = -8.692e+00; - } - if( w==12 ) - { - r = -8.921e+00; - } - if( w==11 ) - { - r = -9.162e+00; - } - if( w==10 ) - { - r = -9.409e+00; - } - if( w==9 ) - { - r = -9.673e+00; - } - if( w==8 ) - { - r = -9.951e+00; - } - if( w==7 ) - { - r = -1.023e+01; - } - if( w==6 ) - { - r = -1.053e+01; - } - if( w==5 ) - { - r = -1.087e+01; - } - if( w==4 ) - { - r = -1.122e+01; - } - if( w==3 ) - { - r = -1.156e+01; - } - if( w==2 ) - { - r = -1.207e+01; - } - if( w==1 ) - { - r = -1.248e+01; - } - if( w<=0 ) - { - r = -1.317e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 20) -*************************************************************************/ -static double wsr_w20(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-2.678619e+01*s+1.050000e+02, _state); - if( w>=105 ) - { - r = -6.787e-01; - } - if( w==104 ) - { - r = -7.078e-01; - } - if( w==103 ) - { - r = -7.378e-01; - } - if( w==102 ) - { - r = -7.686e-01; - } - if( w==101 ) - { - r = -8.004e-01; - } - if( w==100 ) - { - r = -8.330e-01; - } - if( w==99 ) - { - r = -8.665e-01; - } - if( w==98 ) - { - r = -9.010e-01; - } - if( w==97 ) - { - r = -9.363e-01; - } - if( w==96 ) - { - r = -9.726e-01; - } - if( w==95 ) - { - r = -1.010e+00; - } - if( w==94 ) - { - r = -1.048e+00; - } - if( w==93 ) - { - r = -1.087e+00; - } - if( w==92 ) - { - r = -1.128e+00; - } - if( w==91 ) - { - r = -1.169e+00; - } - if( w==90 ) - { - r = -1.211e+00; - } - if( w==89 ) - { - r = -1.254e+00; - } - if( w==88 ) - { - r = -1.299e+00; - } - if( w==87 ) - { - r = -1.344e+00; - } - if( w==86 ) - { - r = -1.390e+00; - } - if( w==85 ) - { - r = -1.438e+00; - } - if( w==84 ) - { - r = -1.486e+00; - } - if( w==83 ) - { - r = -1.536e+00; - } - if( w==82 ) - { - r = -1.587e+00; - } - if( w==81 ) - { - r = -1.639e+00; - } - if( w==80 ) - { - r = -1.692e+00; - } - if( w==79 ) - { - r = -1.746e+00; - } - if( w==78 ) - { - r = -1.802e+00; - } - if( w==77 ) - { - r = -1.859e+00; - } - if( w==76 ) - { - r = -1.916e+00; - } - if( w==75 ) - { - r = -1.976e+00; - } - if( w==74 ) - { - r = -2.036e+00; - } - if( w==73 ) - { - r = -2.098e+00; - } - if( w==72 ) - { - r = -2.161e+00; - } - if( w==71 ) - { - r = -2.225e+00; - } - if( w==70 ) - { - r = -2.290e+00; - } - if( w==69 ) - { - r = -2.357e+00; - } - if( w==68 ) - { - r = -2.426e+00; - } - if( w==67 ) - { - r = -2.495e+00; - } - if( w==66 ) - { - r = -2.566e+00; - } - if( w==65 ) - { - r = -2.639e+00; - } - if( w==64 ) - { - r = -2.713e+00; - } - if( w==63 ) - { - r = -2.788e+00; - } - if( w==62 ) - { - r = -2.865e+00; - } - if( w==61 ) - { - r = -2.943e+00; - } - if( w==60 ) - { - r = -3.023e+00; - } - if( w==59 ) - { - r = -3.104e+00; - } - if( w==58 ) - { - r = -3.187e+00; - } - if( w==57 ) - { - r = -3.272e+00; - } - if( w==56 ) - { - r = -3.358e+00; - } - if( w==55 ) - { - r = -3.446e+00; - } - if( w==54 ) - { - r = -3.536e+00; - } - if( w==53 ) - { - r = -3.627e+00; - } - if( w==52 ) - { - r = -3.721e+00; - } - if( w==51 ) - { - r = -3.815e+00; - } - if( w==50 ) - { - r = -3.912e+00; - } - if( w==49 ) - { - r = -4.011e+00; - } - if( w==48 ) - { - r = -4.111e+00; - } - if( w==47 ) - { - r = -4.214e+00; - } - if( w==46 ) - { - r = -4.318e+00; - } - if( w==45 ) - { - r = -4.425e+00; - } - if( w==44 ) - { - r = -4.534e+00; - } - if( w==43 ) - { - r = -4.644e+00; - } - if( w==42 ) - { - r = -4.757e+00; - } - if( w==41 ) - { - r = -4.872e+00; - } - if( w==40 ) - { - r = -4.990e+00; - } - if( w==39 ) - { - r = -5.109e+00; - } - if( w==38 ) - { - r = -5.232e+00; - } - if( w==37 ) - { - r = -5.356e+00; - } - if( w==36 ) - { - r = -5.484e+00; - } - if( w==35 ) - { - r = -5.614e+00; - } - if( w==34 ) - { - r = -5.746e+00; - } - if( w==33 ) - { - r = -5.882e+00; - } - if( w==32 ) - { - r = -6.020e+00; - } - if( w==31 ) - { - r = -6.161e+00; - } - if( w==30 ) - { - r = -6.305e+00; - } - if( w==29 ) - { - r = -6.453e+00; - } - if( w==28 ) - { - r = -6.603e+00; - } - if( w==27 ) - { - r = -6.757e+00; - } - if( w==26 ) - { - r = -6.915e+00; - } - if( w==25 ) - { - r = -7.076e+00; - } - if( w==24 ) - { - r = -7.242e+00; - } - if( w==23 ) - { - r = -7.411e+00; - } - if( w==22 ) - { - r = -7.584e+00; - } - if( w==21 ) - { - r = -7.763e+00; - } - if( w==20 ) - { - r = -7.947e+00; - } - if( w==19 ) - { - r = -8.136e+00; - } - if( w==18 ) - { - r = -8.330e+00; - } - if( w==17 ) - { - r = -8.530e+00; - } - if( w==16 ) - { - r = -8.733e+00; - } - if( w==15 ) - { - r = -8.943e+00; - } - if( w==14 ) - { - r = -9.162e+00; - } - if( w==13 ) - { - r = -9.386e+00; - } - if( w==12 ) - { - r = -9.614e+00; - } - if( w==11 ) - { - r = -9.856e+00; - } - if( w==10 ) - { - r = -1.010e+01; - } - if( w==9 ) - { - r = -1.037e+01; - } - if( w==8 ) - { - r = -1.064e+01; - } - if( w==7 ) - { - r = -1.092e+01; - } - if( w==6 ) - { - r = -1.122e+01; - } - if( w==5 ) - { - r = -1.156e+01; - } - if( w==4 ) - { - r = -1.192e+01; - } - if( w==3 ) - { - r = -1.225e+01; - } - if( w==2 ) - { - r = -1.276e+01; - } - if( w==1 ) - { - r = -1.317e+01; - } - if( w<=0 ) - { - r = -1.386e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 21) -*************************************************************************/ -static double wsr_w21(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-2.877064e+01*s+1.155000e+02, _state); - if( w>=115 ) - { - r = -6.931e-01; - } - if( w==114 ) - { - r = -7.207e-01; - } - if( w==113 ) - { - r = -7.489e-01; - } - if( w==112 ) - { - r = -7.779e-01; - } - if( w==111 ) - { - r = -8.077e-01; - } - if( w==110 ) - { - r = -8.383e-01; - } - if( w==109 ) - { - r = -8.697e-01; - } - if( w==108 ) - { - r = -9.018e-01; - } - if( w==107 ) - { - r = -9.348e-01; - } - if( w==106 ) - { - r = -9.685e-01; - } - if( w==105 ) - { - r = -1.003e+00; - } - if( w==104 ) - { - r = -1.039e+00; - } - if( w==103 ) - { - r = -1.075e+00; - } - if( w==102 ) - { - r = -1.112e+00; - } - if( w==101 ) - { - r = -1.150e+00; - } - if( w==100 ) - { - r = -1.189e+00; - } - if( w==99 ) - { - r = -1.229e+00; - } - if( w==98 ) - { - r = -1.269e+00; - } - if( w==97 ) - { - r = -1.311e+00; - } - if( w==96 ) - { - r = -1.353e+00; - } - if( w==95 ) - { - r = -1.397e+00; - } - if( w==94 ) - { - r = -1.441e+00; - } - if( w==93 ) - { - r = -1.486e+00; - } - if( w==92 ) - { - r = -1.533e+00; - } - if( w==91 ) - { - r = -1.580e+00; - } - if( w==90 ) - { - r = -1.628e+00; - } - if( w==89 ) - { - r = -1.677e+00; - } - if( w==88 ) - { - r = -1.728e+00; - } - if( w==87 ) - { - r = -1.779e+00; - } - if( w==86 ) - { - r = -1.831e+00; - } - if( w==85 ) - { - r = -1.884e+00; - } - if( w==84 ) - { - r = -1.939e+00; - } - if( w==83 ) - { - r = -1.994e+00; - } - if( w==82 ) - { - r = -2.051e+00; - } - if( w==81 ) - { - r = -2.108e+00; - } - if( w==80 ) - { - r = -2.167e+00; - } - if( w==79 ) - { - r = -2.227e+00; - } - if( w==78 ) - { - r = -2.288e+00; - } - if( w==77 ) - { - r = -2.350e+00; - } - if( w==76 ) - { - r = -2.414e+00; - } - if( w==75 ) - { - r = -2.478e+00; - } - if( w==74 ) - { - r = -2.544e+00; - } - if( w==73 ) - { - r = -2.611e+00; - } - if( w==72 ) - { - r = -2.679e+00; - } - if( w==71 ) - { - r = -2.748e+00; - } - if( w==70 ) - { - r = -2.819e+00; - } - if( w==69 ) - { - r = -2.891e+00; - } - if( w==68 ) - { - r = -2.964e+00; - } - if( w==67 ) - { - r = -3.039e+00; - } - if( w==66 ) - { - r = -3.115e+00; - } - if( w==65 ) - { - r = -3.192e+00; - } - if( w==64 ) - { - r = -3.270e+00; - } - if( w==63 ) - { - r = -3.350e+00; - } - if( w==62 ) - { - r = -3.432e+00; - } - if( w==61 ) - { - r = -3.515e+00; - } - if( w==60 ) - { - r = -3.599e+00; - } - if( w==59 ) - { - r = -3.685e+00; - } - if( w==58 ) - { - r = -3.772e+00; - } - if( w==57 ) - { - r = -3.861e+00; - } - if( w==56 ) - { - r = -3.952e+00; - } - if( w==55 ) - { - r = -4.044e+00; - } - if( w==54 ) - { - r = -4.138e+00; - } - if( w==53 ) - { - r = -4.233e+00; - } - if( w==52 ) - { - r = -4.330e+00; - } - if( w==51 ) - { - r = -4.429e+00; - } - if( w==50 ) - { - r = -4.530e+00; - } - if( w==49 ) - { - r = -4.632e+00; - } - if( w==48 ) - { - r = -4.736e+00; - } - if( w==47 ) - { - r = -4.842e+00; - } - if( w==46 ) - { - r = -4.950e+00; - } - if( w==45 ) - { - r = -5.060e+00; - } - if( w==44 ) - { - r = -5.172e+00; - } - if( w==43 ) - { - r = -5.286e+00; - } - if( w==42 ) - { - r = -5.402e+00; - } - if( w==41 ) - { - r = -5.520e+00; - } - if( w==40 ) - { - r = -5.641e+00; - } - if( w==39 ) - { - r = -5.763e+00; - } - if( w==38 ) - { - r = -5.889e+00; - } - if( w==37 ) - { - r = -6.016e+00; - } - if( w==36 ) - { - r = -6.146e+00; - } - if( w==35 ) - { - r = -6.278e+00; - } - if( w==34 ) - { - r = -6.413e+00; - } - if( w==33 ) - { - r = -6.551e+00; - } - if( w==32 ) - { - r = -6.692e+00; - } - if( w==31 ) - { - r = -6.835e+00; - } - if( w==30 ) - { - r = -6.981e+00; - } - if( w==29 ) - { - r = -7.131e+00; - } - if( w==28 ) - { - r = -7.283e+00; - } - if( w==27 ) - { - r = -7.439e+00; - } - if( w==26 ) - { - r = -7.599e+00; - } - if( w==25 ) - { - r = -7.762e+00; - } - if( w==24 ) - { - r = -7.928e+00; - } - if( w==23 ) - { - r = -8.099e+00; - } - if( w==22 ) - { - r = -8.274e+00; - } - if( w==21 ) - { - r = -8.454e+00; - } - if( w==20 ) - { - r = -8.640e+00; - } - if( w==19 ) - { - r = -8.829e+00; - } - if( w==18 ) - { - r = -9.023e+00; - } - if( w==17 ) - { - r = -9.223e+00; - } - if( w==16 ) - { - r = -9.426e+00; - } - if( w==15 ) - { - r = -9.636e+00; - } - if( w==14 ) - { - r = -9.856e+00; - } - if( w==13 ) - { - r = -1.008e+01; - } - if( w==12 ) - { - r = -1.031e+01; - } - if( w==11 ) - { - r = -1.055e+01; - } - if( w==10 ) - { - r = -1.079e+01; - } - if( w==9 ) - { - r = -1.106e+01; - } - if( w==8 ) - { - r = -1.134e+01; - } - if( w==7 ) - { - r = -1.161e+01; - } - if( w==6 ) - { - r = -1.192e+01; - } - if( w==5 ) - { - r = -1.225e+01; - } - if( w==4 ) - { - r = -1.261e+01; - } - if( w==3 ) - { - r = -1.295e+01; - } - if( w==2 ) - { - r = -1.346e+01; - } - if( w==1 ) - { - r = -1.386e+01; - } - if( w<=0 ) - { - r = -1.456e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 22) -*************************************************************************/ -static double wsr_w22(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-3.080179e+01*s+1.265000e+02, _state); - if( w>=126 ) - { - r = -6.931e-01; - } - if( w==125 ) - { - r = -7.189e-01; - } - if( w==124 ) - { - r = -7.452e-01; - } - if( w==123 ) - { - r = -7.722e-01; - } - if( w==122 ) - { - r = -7.999e-01; - } - if( w==121 ) - { - r = -8.283e-01; - } - if( w==120 ) - { - r = -8.573e-01; - } - if( w==119 ) - { - r = -8.871e-01; - } - if( w==118 ) - { - r = -9.175e-01; - } - if( w==117 ) - { - r = -9.486e-01; - } - if( w==116 ) - { - r = -9.805e-01; - } - if( w==115 ) - { - r = -1.013e+00; - } - if( w==114 ) - { - r = -1.046e+00; - } - if( w==113 ) - { - r = -1.080e+00; - } - if( w==112 ) - { - r = -1.115e+00; - } - if( w==111 ) - { - r = -1.151e+00; - } - if( w==110 ) - { - r = -1.187e+00; - } - if( w==109 ) - { - r = -1.224e+00; - } - if( w==108 ) - { - r = -1.262e+00; - } - if( w==107 ) - { - r = -1.301e+00; - } - if( w==106 ) - { - r = -1.340e+00; - } - if( w==105 ) - { - r = -1.381e+00; - } - if( w==104 ) - { - r = -1.422e+00; - } - if( w==103 ) - { - r = -1.464e+00; - } - if( w==102 ) - { - r = -1.506e+00; - } - if( w==101 ) - { - r = -1.550e+00; - } - if( w==100 ) - { - r = -1.594e+00; - } - if( w==99 ) - { - r = -1.640e+00; - } - if( w==98 ) - { - r = -1.686e+00; - } - if( w==97 ) - { - r = -1.733e+00; - } - if( w==96 ) - { - r = -1.781e+00; - } - if( w==95 ) - { - r = -1.830e+00; - } - if( w==94 ) - { - r = -1.880e+00; - } - if( w==93 ) - { - r = -1.930e+00; - } - if( w==92 ) - { - r = -1.982e+00; - } - if( w==91 ) - { - r = -2.034e+00; - } - if( w==90 ) - { - r = -2.088e+00; - } - if( w==89 ) - { - r = -2.142e+00; - } - if( w==88 ) - { - r = -2.198e+00; - } - if( w==87 ) - { - r = -2.254e+00; - } - if( w==86 ) - { - r = -2.312e+00; - } - if( w==85 ) - { - r = -2.370e+00; - } - if( w==84 ) - { - r = -2.429e+00; - } - if( w==83 ) - { - r = -2.490e+00; - } - if( w==82 ) - { - r = -2.551e+00; - } - if( w==81 ) - { - r = -2.614e+00; - } - if( w==80 ) - { - r = -2.677e+00; - } - if( w==79 ) - { - r = -2.742e+00; - } - if( w==78 ) - { - r = -2.808e+00; - } - if( w==77 ) - { - r = -2.875e+00; - } - if( w==76 ) - { - r = -2.943e+00; - } - if( w==75 ) - { - r = -3.012e+00; - } - if( w==74 ) - { - r = -3.082e+00; - } - if( w==73 ) - { - r = -3.153e+00; - } - if( w==72 ) - { - r = -3.226e+00; - } - if( w==71 ) - { - r = -3.300e+00; - } - if( w==70 ) - { - r = -3.375e+00; - } - if( w==69 ) - { - r = -3.451e+00; - } - if( w==68 ) - { - r = -3.529e+00; - } - if( w==67 ) - { - r = -3.607e+00; - } - if( w==66 ) - { - r = -3.687e+00; - } - if( w==65 ) - { - r = -3.769e+00; - } - if( w==64 ) - { - r = -3.851e+00; - } - if( w==63 ) - { - r = -3.935e+00; - } - if( w==62 ) - { - r = -4.021e+00; - } - if( w==61 ) - { - r = -4.108e+00; - } - if( w==60 ) - { - r = -4.196e+00; - } - if( w==59 ) - { - r = -4.285e+00; - } - if( w==58 ) - { - r = -4.376e+00; - } - if( w==57 ) - { - r = -4.469e+00; - } - if( w==56 ) - { - r = -4.563e+00; - } - if( w==55 ) - { - r = -4.659e+00; - } - if( w==54 ) - { - r = -4.756e+00; - } - if( w==53 ) - { - r = -4.855e+00; - } - if( w==52 ) - { - r = -4.955e+00; - } - if( w==51 ) - { - r = -5.057e+00; - } - if( w==50 ) - { - r = -5.161e+00; - } - if( w==49 ) - { - r = -5.266e+00; - } - if( w==48 ) - { - r = -5.374e+00; - } - if( w==47 ) - { - r = -5.483e+00; - } - if( w==46 ) - { - r = -5.594e+00; - } - if( w==45 ) - { - r = -5.706e+00; - } - if( w==44 ) - { - r = -5.821e+00; - } - if( w==43 ) - { - r = -5.938e+00; - } - if( w==42 ) - { - r = -6.057e+00; - } - if( w==41 ) - { - r = -6.177e+00; - } - if( w==40 ) - { - r = -6.300e+00; - } - if( w==39 ) - { - r = -6.426e+00; - } - if( w==38 ) - { - r = -6.553e+00; - } - if( w==37 ) - { - r = -6.683e+00; - } - if( w==36 ) - { - r = -6.815e+00; - } - if( w==35 ) - { - r = -6.949e+00; - } - if( w==34 ) - { - r = -7.086e+00; - } - if( w==33 ) - { - r = -7.226e+00; - } - if( w==32 ) - { - r = -7.368e+00; - } - if( w==31 ) - { - r = -7.513e+00; - } - if( w==30 ) - { - r = -7.661e+00; - } - if( w==29 ) - { - r = -7.813e+00; - } - if( w==28 ) - { - r = -7.966e+00; - } - if( w==27 ) - { - r = -8.124e+00; - } - if( w==26 ) - { - r = -8.285e+00; - } - if( w==25 ) - { - r = -8.449e+00; - } - if( w==24 ) - { - r = -8.617e+00; - } - if( w==23 ) - { - r = -8.789e+00; - } - if( w==22 ) - { - r = -8.965e+00; - } - if( w==21 ) - { - r = -9.147e+00; - } - if( w==20 ) - { - r = -9.333e+00; - } - if( w==19 ) - { - r = -9.522e+00; - } - if( w==18 ) - { - r = -9.716e+00; - } - if( w==17 ) - { - r = -9.917e+00; - } - if( w==16 ) - { - r = -1.012e+01; - } - if( w==15 ) - { - r = -1.033e+01; - } - if( w==14 ) - { - r = -1.055e+01; - } - if( w==13 ) - { - r = -1.077e+01; - } - if( w==12 ) - { - r = -1.100e+01; - } - if( w==11 ) - { - r = -1.124e+01; - } - if( w==10 ) - { - r = -1.149e+01; - } - if( w==9 ) - { - r = -1.175e+01; - } - if( w==8 ) - { - r = -1.203e+01; - } - if( w==7 ) - { - r = -1.230e+01; - } - if( w==6 ) - { - r = -1.261e+01; - } - if( w==5 ) - { - r = -1.295e+01; - } - if( w==4 ) - { - r = -1.330e+01; - } - if( w==3 ) - { - r = -1.364e+01; - } - if( w==2 ) - { - r = -1.415e+01; - } - if( w==1 ) - { - r = -1.456e+01; - } - if( w<=0 ) - { - r = -1.525e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 23) -*************************************************************************/ -static double wsr_w23(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-3.287856e+01*s+1.380000e+02, _state); - if( w>=138 ) - { - r = -6.813e-01; - } - if( w==137 ) - { - r = -7.051e-01; - } - if( w==136 ) - { - r = -7.295e-01; - } - if( w==135 ) - { - r = -7.544e-01; - } - if( w==134 ) - { - r = -7.800e-01; - } - if( w==133 ) - { - r = -8.061e-01; - } - if( w==132 ) - { - r = -8.328e-01; - } - if( w==131 ) - { - r = -8.601e-01; - } - if( w==130 ) - { - r = -8.880e-01; - } - if( w==129 ) - { - r = -9.166e-01; - } - if( w==128 ) - { - r = -9.457e-01; - } - if( w==127 ) - { - r = -9.755e-01; - } - if( w==126 ) - { - r = -1.006e+00; - } - if( w==125 ) - { - r = -1.037e+00; - } - if( w==124 ) - { - r = -1.069e+00; - } - if( w==123 ) - { - r = -1.101e+00; - } - if( w==122 ) - { - r = -1.134e+00; - } - if( w==121 ) - { - r = -1.168e+00; - } - if( w==120 ) - { - r = -1.202e+00; - } - if( w==119 ) - { - r = -1.237e+00; - } - if( w==118 ) - { - r = -1.273e+00; - } - if( w==117 ) - { - r = -1.309e+00; - } - if( w==116 ) - { - r = -1.347e+00; - } - if( w==115 ) - { - r = -1.384e+00; - } - if( w==114 ) - { - r = -1.423e+00; - } - if( w==113 ) - { - r = -1.462e+00; - } - if( w==112 ) - { - r = -1.502e+00; - } - if( w==111 ) - { - r = -1.543e+00; - } - if( w==110 ) - { - r = -1.585e+00; - } - if( w==109 ) - { - r = -1.627e+00; - } - if( w==108 ) - { - r = -1.670e+00; - } - if( w==107 ) - { - r = -1.714e+00; - } - if( w==106 ) - { - r = -1.758e+00; - } - if( w==105 ) - { - r = -1.804e+00; - } - if( w==104 ) - { - r = -1.850e+00; - } - if( w==103 ) - { - r = -1.897e+00; - } - if( w==102 ) - { - r = -1.944e+00; - } - if( w==101 ) - { - r = -1.993e+00; - } - if( w==100 ) - { - r = -2.042e+00; - } - if( w==99 ) - { - r = -2.093e+00; - } - if( w==98 ) - { - r = -2.144e+00; - } - if( w==97 ) - { - r = -2.195e+00; - } - if( w==96 ) - { - r = -2.248e+00; - } - if( w==95 ) - { - r = -2.302e+00; - } - if( w==94 ) - { - r = -2.356e+00; - } - if( w==93 ) - { - r = -2.412e+00; - } - if( w==92 ) - { - r = -2.468e+00; - } - if( w==91 ) - { - r = -2.525e+00; - } - if( w==90 ) - { - r = -2.583e+00; - } - if( w==89 ) - { - r = -2.642e+00; - } - if( w==88 ) - { - r = -2.702e+00; - } - if( w==87 ) - { - r = -2.763e+00; - } - if( w==86 ) - { - r = -2.825e+00; - } - if( w==85 ) - { - r = -2.888e+00; - } - if( w==84 ) - { - r = -2.951e+00; - } - if( w==83 ) - { - r = -3.016e+00; - } - if( w==82 ) - { - r = -3.082e+00; - } - if( w==81 ) - { - r = -3.149e+00; - } - if( w==80 ) - { - r = -3.216e+00; - } - if( w==79 ) - { - r = -3.285e+00; - } - if( w==78 ) - { - r = -3.355e+00; - } - if( w==77 ) - { - r = -3.426e+00; - } - if( w==76 ) - { - r = -3.498e+00; - } - if( w==75 ) - { - r = -3.571e+00; - } - if( w==74 ) - { - r = -3.645e+00; - } - if( w==73 ) - { - r = -3.721e+00; - } - if( w==72 ) - { - r = -3.797e+00; - } - if( w==71 ) - { - r = -3.875e+00; - } - if( w==70 ) - { - r = -3.953e+00; - } - if( w==69 ) - { - r = -4.033e+00; - } - if( w==68 ) - { - r = -4.114e+00; - } - if( w==67 ) - { - r = -4.197e+00; - } - if( w==66 ) - { - r = -4.280e+00; - } - if( w==65 ) - { - r = -4.365e+00; - } - if( w==64 ) - { - r = -4.451e+00; - } - if( w==63 ) - { - r = -4.539e+00; - } - if( w==62 ) - { - r = -4.628e+00; - } - if( w==61 ) - { - r = -4.718e+00; - } - if( w==60 ) - { - r = -4.809e+00; - } - if( w==59 ) - { - r = -4.902e+00; - } - if( w==58 ) - { - r = -4.996e+00; - } - if( w==57 ) - { - r = -5.092e+00; - } - if( w==56 ) - { - r = -5.189e+00; - } - if( w==55 ) - { - r = -5.287e+00; - } - if( w==54 ) - { - r = -5.388e+00; - } - if( w==53 ) - { - r = -5.489e+00; - } - if( w==52 ) - { - r = -5.592e+00; - } - if( w==51 ) - { - r = -5.697e+00; - } - if( w==50 ) - { - r = -5.804e+00; - } - if( w==49 ) - { - r = -5.912e+00; - } - if( w==48 ) - { - r = -6.022e+00; - } - if( w==47 ) - { - r = -6.133e+00; - } - if( w==46 ) - { - r = -6.247e+00; - } - if( w==45 ) - { - r = -6.362e+00; - } - if( w==44 ) - { - r = -6.479e+00; - } - if( w==43 ) - { - r = -6.598e+00; - } - if( w==42 ) - { - r = -6.719e+00; - } - if( w==41 ) - { - r = -6.842e+00; - } - if( w==40 ) - { - r = -6.967e+00; - } - if( w==39 ) - { - r = -7.094e+00; - } - if( w==38 ) - { - r = -7.224e+00; - } - if( w==37 ) - { - r = -7.355e+00; - } - if( w==36 ) - { - r = -7.489e+00; - } - if( w==35 ) - { - r = -7.625e+00; - } - if( w==34 ) - { - r = -7.764e+00; - } - if( w==33 ) - { - r = -7.905e+00; - } - if( w==32 ) - { - r = -8.049e+00; - } - if( w==31 ) - { - r = -8.196e+00; - } - if( w==30 ) - { - r = -8.345e+00; - } - if( w==29 ) - { - r = -8.498e+00; - } - if( w==28 ) - { - r = -8.653e+00; - } - if( w==27 ) - { - r = -8.811e+00; - } - if( w==26 ) - { - r = -8.974e+00; - } - if( w==25 ) - { - r = -9.139e+00; - } - if( w==24 ) - { - r = -9.308e+00; - } - if( w==23 ) - { - r = -9.481e+00; - } - if( w==22 ) - { - r = -9.658e+00; - } - if( w==21 ) - { - r = -9.840e+00; - } - if( w==20 ) - { - r = -1.003e+01; - } - if( w==19 ) - { - r = -1.022e+01; - } - if( w==18 ) - { - r = -1.041e+01; - } - if( w==17 ) - { - r = -1.061e+01; - } - if( w==16 ) - { - r = -1.081e+01; - } - if( w==15 ) - { - r = -1.102e+01; - } - if( w==14 ) - { - r = -1.124e+01; - } - if( w==13 ) - { - r = -1.147e+01; - } - if( w==12 ) - { - r = -1.169e+01; - } - if( w==11 ) - { - r = -1.194e+01; - } - if( w==10 ) - { - r = -1.218e+01; - } - if( w==9 ) - { - r = -1.245e+01; - } - if( w==8 ) - { - r = -1.272e+01; - } - if( w==7 ) - { - r = -1.300e+01; - } - if( w==6 ) - { - r = -1.330e+01; - } - if( w==5 ) - { - r = -1.364e+01; - } - if( w==4 ) - { - r = -1.400e+01; - } - if( w==3 ) - { - r = -1.433e+01; - } - if( w==2 ) - { - r = -1.484e+01; - } - if( w==1 ) - { - r = -1.525e+01; - } - if( w<=0 ) - { - r = -1.594e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 24) -*************************************************************************/ -static double wsr_w24(double s, ae_state *_state) -{ - ae_int_t w; - double r; - double result; - - - r = 0; - w = ae_round(-3.500000e+01*s+1.500000e+02, _state); - if( w>=150 ) - { - r = -6.820e-01; - } - if( w==149 ) - { - r = -7.044e-01; - } - if( w==148 ) - { - r = -7.273e-01; - } - if( w==147 ) - { - r = -7.507e-01; - } - if( w==146 ) - { - r = -7.746e-01; - } - if( w==145 ) - { - r = -7.990e-01; - } - if( w==144 ) - { - r = -8.239e-01; - } - if( w==143 ) - { - r = -8.494e-01; - } - if( w==142 ) - { - r = -8.754e-01; - } - if( w==141 ) - { - r = -9.020e-01; - } - if( w==140 ) - { - r = -9.291e-01; - } - if( w==139 ) - { - r = -9.567e-01; - } - if( w==138 ) - { - r = -9.849e-01; - } - if( w==137 ) - { - r = -1.014e+00; - } - if( w==136 ) - { - r = -1.043e+00; - } - if( w==135 ) - { - r = -1.073e+00; - } - if( w==134 ) - { - r = -1.103e+00; - } - if( w==133 ) - { - r = -1.135e+00; - } - if( w==132 ) - { - r = -1.166e+00; - } - if( w==131 ) - { - r = -1.198e+00; - } - if( w==130 ) - { - r = -1.231e+00; - } - if( w==129 ) - { - r = -1.265e+00; - } - if( w==128 ) - { - r = -1.299e+00; - } - if( w==127 ) - { - r = -1.334e+00; - } - if( w==126 ) - { - r = -1.369e+00; - } - if( w==125 ) - { - r = -1.405e+00; - } - if( w==124 ) - { - r = -1.441e+00; - } - if( w==123 ) - { - r = -1.479e+00; - } - if( w==122 ) - { - r = -1.517e+00; - } - if( w==121 ) - { - r = -1.555e+00; - } - if( w==120 ) - { - r = -1.594e+00; - } - if( w==119 ) - { - r = -1.634e+00; - } - if( w==118 ) - { - r = -1.675e+00; - } - if( w==117 ) - { - r = -1.716e+00; - } - if( w==116 ) - { - r = -1.758e+00; - } - if( w==115 ) - { - r = -1.800e+00; - } - if( w==114 ) - { - r = -1.844e+00; - } - if( w==113 ) - { - r = -1.888e+00; - } - if( w==112 ) - { - r = -1.932e+00; - } - if( w==111 ) - { - r = -1.978e+00; - } - if( w==110 ) - { - r = -2.024e+00; - } - if( w==109 ) - { - r = -2.070e+00; - } - if( w==108 ) - { - r = -2.118e+00; - } - if( w==107 ) - { - r = -2.166e+00; - } - if( w==106 ) - { - r = -2.215e+00; - } - if( w==105 ) - { - r = -2.265e+00; - } - if( w==104 ) - { - r = -2.316e+00; - } - if( w==103 ) - { - r = -2.367e+00; - } - if( w==102 ) - { - r = -2.419e+00; - } - if( w==101 ) - { - r = -2.472e+00; - } - if( w==100 ) - { - r = -2.526e+00; - } - if( w==99 ) - { - r = -2.580e+00; - } - if( w==98 ) - { - r = -2.636e+00; - } - if( w==97 ) - { - r = -2.692e+00; - } - if( w==96 ) - { - r = -2.749e+00; - } - if( w==95 ) - { - r = -2.806e+00; - } - if( w==94 ) - { - r = -2.865e+00; - } - if( w==93 ) - { - r = -2.925e+00; - } - if( w==92 ) - { - r = -2.985e+00; - } - if( w==91 ) - { - r = -3.046e+00; - } - if( w==90 ) - { - r = -3.108e+00; - } - if( w==89 ) - { - r = -3.171e+00; - } - if( w==88 ) - { - r = -3.235e+00; - } - if( w==87 ) - { - r = -3.300e+00; - } - if( w==86 ) - { - r = -3.365e+00; - } - if( w==85 ) - { - r = -3.432e+00; - } - if( w==84 ) - { - r = -3.499e+00; - } - if( w==83 ) - { - r = -3.568e+00; - } - if( w==82 ) - { - r = -3.637e+00; - } - if( w==81 ) - { - r = -3.708e+00; - } - if( w==80 ) - { - r = -3.779e+00; - } - if( w==79 ) - { - r = -3.852e+00; - } - if( w==78 ) - { - r = -3.925e+00; - } - if( w==77 ) - { - r = -4.000e+00; - } - if( w==76 ) - { - r = -4.075e+00; - } - if( w==75 ) - { - r = -4.151e+00; - } - if( w==74 ) - { - r = -4.229e+00; - } - if( w==73 ) - { - r = -4.308e+00; - } - if( w==72 ) - { - r = -4.387e+00; - } - if( w==71 ) - { - r = -4.468e+00; - } - if( w==70 ) - { - r = -4.550e+00; - } - if( w==69 ) - { - r = -4.633e+00; - } - if( w==68 ) - { - r = -4.718e+00; - } - if( w==67 ) - { - r = -4.803e+00; - } - if( w==66 ) - { - r = -4.890e+00; - } - if( w==65 ) - { - r = -4.978e+00; - } - if( w==64 ) - { - r = -5.067e+00; - } - if( w==63 ) - { - r = -5.157e+00; - } - if( w==62 ) - { - r = -5.249e+00; - } - if( w==61 ) - { - r = -5.342e+00; - } - if( w==60 ) - { - r = -5.436e+00; - } - if( w==59 ) - { - r = -5.531e+00; - } - if( w==58 ) - { - r = -5.628e+00; - } - if( w==57 ) - { - r = -5.727e+00; - } - if( w==56 ) - { - r = -5.826e+00; - } - if( w==55 ) - { - r = -5.927e+00; - } - if( w==54 ) - { - r = -6.030e+00; - } - if( w==53 ) - { - r = -6.134e+00; - } - if( w==52 ) - { - r = -6.240e+00; - } - if( w==51 ) - { - r = -6.347e+00; - } - if( w==50 ) - { - r = -6.456e+00; - } - if( w==49 ) - { - r = -6.566e+00; - } - if( w==48 ) - { - r = -6.678e+00; - } - if( w==47 ) - { - r = -6.792e+00; - } - if( w==46 ) - { - r = -6.907e+00; - } - if( w==45 ) - { - r = -7.025e+00; - } - if( w==44 ) - { - r = -7.144e+00; - } - if( w==43 ) - { - r = -7.265e+00; - } - if( w==42 ) - { - r = -7.387e+00; - } - if( w==41 ) - { - r = -7.512e+00; - } - if( w==40 ) - { - r = -7.639e+00; - } - if( w==39 ) - { - r = -7.768e+00; - } - if( w==38 ) - { - r = -7.899e+00; - } - if( w==37 ) - { - r = -8.032e+00; - } - if( w==36 ) - { - r = -8.167e+00; - } - if( w==35 ) - { - r = -8.305e+00; - } - if( w==34 ) - { - r = -8.445e+00; - } - if( w==33 ) - { - r = -8.588e+00; - } - if( w==32 ) - { - r = -8.733e+00; - } - if( w==31 ) - { - r = -8.881e+00; - } - if( w==30 ) - { - r = -9.031e+00; - } - if( w==29 ) - { - r = -9.185e+00; - } - if( w==28 ) - { - r = -9.341e+00; - } - if( w==27 ) - { - r = -9.501e+00; - } - if( w==26 ) - { - r = -9.664e+00; - } - if( w==25 ) - { - r = -9.830e+00; - } - if( w==24 ) - { - r = -1.000e+01; - } - if( w==23 ) - { - r = -1.017e+01; - } - if( w==22 ) - { - r = -1.035e+01; - } - if( w==21 ) - { - r = -1.053e+01; - } - if( w==20 ) - { - r = -1.072e+01; - } - if( w==19 ) - { - r = -1.091e+01; - } - if( w==18 ) - { - r = -1.110e+01; - } - if( w==17 ) - { - r = -1.130e+01; - } - if( w==16 ) - { - r = -1.151e+01; - } - if( w==15 ) - { - r = -1.172e+01; - } - if( w==14 ) - { - r = -1.194e+01; - } - if( w==13 ) - { - r = -1.216e+01; - } - if( w==12 ) - { - r = -1.239e+01; - } - if( w==11 ) - { - r = -1.263e+01; - } - if( w==10 ) - { - r = -1.287e+01; - } - if( w==9 ) - { - r = -1.314e+01; - } - if( w==8 ) - { - r = -1.342e+01; - } - if( w==7 ) - { - r = -1.369e+01; - } - if( w==6 ) - { - r = -1.400e+01; - } - if( w==5 ) - { - r = -1.433e+01; - } - if( w==4 ) - { - r = -1.469e+01; - } - if( w==3 ) - { - r = -1.503e+01; - } - if( w==2 ) - { - r = -1.554e+01; - } - if( w==1 ) - { - r = -1.594e+01; - } - if( w<=0 ) - { - r = -1.664e+01; - } - result = r; - return result; -} - - -/************************************************************************* -Tail(S, 25) -*************************************************************************/ -static double wsr_w25(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.150509e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.695528e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.437637e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.611906e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -7.625722e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.579892e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.086876e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.906543e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.354881e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 1.007195e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -8.437327e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 26) -*************************************************************************/ -static double wsr_w26(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.117622e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.635159e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.395167e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.382823e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -6.531987e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.060112e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -8.203697e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.516523e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.431364e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 6.384553e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -3.238369e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 27) -*************************************************************************/ -static double wsr_w27(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.089731e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.584248e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.359966e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.203696e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.753344e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.761891e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -7.096897e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.419108e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.581214e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 3.033766e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.901441e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 28) -*************************************************************************/ -static double wsr_w28(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.065046e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.539163e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.328939e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.046376e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.061515e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.469271e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.711578e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -8.389153e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.250575e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 4.047245e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.128555e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 29) -*************************************************************************/ -static double wsr_w29(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.043413e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.499756e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.302137e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.915129e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.516329e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.260064e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.817269e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.478130e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.111668e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 4.093451e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.135860e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 30) -*************************************************************************/ -static double wsr_w30(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -5.024071e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.464515e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.278342e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.800030e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.046294e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.076162e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -3.968677e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.911679e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -8.619185e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, 5.125362e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -3.984370e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 40) -*************************************************************************/ -static double wsr_w40(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -4.904809e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.248327e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.136698e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.170982e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.824427e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -3.888648e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.344929e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, 2.790407e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.619858e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, 3.359121e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.883026e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 60) -*************************************************************************/ -static double wsr_w60(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -4.809656e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.077191e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.029402e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -7.507931e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, -6.506226e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.391278e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.263635e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, 2.302271e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.384348e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, 1.865587e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.622355e-04, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 120) -*************************************************************************/ -static double wsr_w120(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -4.729426e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.934426e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -9.433231e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.492504e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, 1.673948e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, -6.077014e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -7.215768e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, 9.086734e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, -8.447980e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, 6.705028e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.828507e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S, 200) -*************************************************************************/ -static double wsr_w200(double s, ae_state *_state) -{ - double x; - double tj; - double tj1; - double result; - - - result = 0; - x = ae_minreal(2*(s-0.000000e+00)/4.000000e+00-1, 1.0, _state); - tj = 1; - tj1 = x; - wsr_wcheb(x, -4.700240e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.883080e+00, &tj, &tj1, &result, _state); - wsr_wcheb(x, -9.132168e-01, &tj, &tj1, &result, _state); - wsr_wcheb(x, -3.512684e-02, &tj, &tj1, &result, _state); - wsr_wcheb(x, 1.726342e-03, &tj, &tj1, &result, _state); - wsr_wcheb(x, -5.189796e-04, &tj, &tj1, &result, _state); - wsr_wcheb(x, -1.628659e-06, &tj, &tj1, &result, _state); - wsr_wcheb(x, 4.261786e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, -4.002498e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, 3.146287e-05, &tj, &tj1, &result, _state); - wsr_wcheb(x, -2.727576e-05, &tj, &tj1, &result, _state); - return result; -} - - -/************************************************************************* -Tail(S,N), S>=0 -*************************************************************************/ -static double wsr_wsigma(double s, ae_int_t n, ae_state *_state) -{ - double f0; - double f1; - double f2; - double f3; - double f4; - double x0; - double x1; - double x2; - double x3; - double x4; - double x; - double result; - - - result = 0; - if( n==5 ) - { - result = wsr_w5(s, _state); - } - if( n==6 ) - { - result = wsr_w6(s, _state); - } - if( n==7 ) - { - result = wsr_w7(s, _state); - } - if( n==8 ) - { - result = wsr_w8(s, _state); - } - if( n==9 ) - { - result = wsr_w9(s, _state); - } - if( n==10 ) - { - result = wsr_w10(s, _state); - } - if( n==11 ) - { - result = wsr_w11(s, _state); - } - if( n==12 ) - { - result = wsr_w12(s, _state); - } - if( n==13 ) - { - result = wsr_w13(s, _state); - } - if( n==14 ) - { - result = wsr_w14(s, _state); - } - if( n==15 ) - { - result = wsr_w15(s, _state); - } - if( n==16 ) - { - result = wsr_w16(s, _state); - } - if( n==17 ) - { - result = wsr_w17(s, _state); - } - if( n==18 ) - { - result = wsr_w18(s, _state); - } - if( n==19 ) - { - result = wsr_w19(s, _state); - } - if( n==20 ) - { - result = wsr_w20(s, _state); - } - if( n==21 ) - { - result = wsr_w21(s, _state); - } - if( n==22 ) - { - result = wsr_w22(s, _state); - } - if( n==23 ) - { - result = wsr_w23(s, _state); - } - if( n==24 ) - { - result = wsr_w24(s, _state); - } - if( n==25 ) - { - result = wsr_w25(s, _state); - } - if( n==26 ) - { - result = wsr_w26(s, _state); - } - if( n==27 ) - { - result = wsr_w27(s, _state); - } - if( n==28 ) - { - result = wsr_w28(s, _state); - } - if( n==29 ) - { - result = wsr_w29(s, _state); - } - if( n==30 ) - { - result = wsr_w30(s, _state); - } - if( n>30 ) - { - x = 1.0/n; - x0 = 1.0/30; - f0 = wsr_w30(s, _state); - x1 = 1.0/40; - f1 = wsr_w40(s, _state); - x2 = 1.0/60; - f2 = wsr_w60(s, _state); - x3 = 1.0/120; - f3 = wsr_w120(s, _state); - x4 = 1.0/200; - f4 = wsr_w200(s, _state); - f1 = ((x-x0)*f1-(x-x1)*f0)/(x1-x0); - f2 = ((x-x0)*f2-(x-x2)*f0)/(x2-x0); - f3 = ((x-x0)*f3-(x-x3)*f0)/(x3-x0); - f4 = ((x-x0)*f4-(x-x4)*f0)/(x4-x0); - f2 = ((x-x1)*f2-(x-x2)*f1)/(x2-x1); - f3 = ((x-x1)*f3-(x-x3)*f1)/(x3-x1); - f4 = ((x-x1)*f4-(x-x4)*f1)/(x4-x1); - f3 = ((x-x2)*f3-(x-x3)*f2)/(x3-x2); - f4 = ((x-x2)*f4-(x-x4)*f2)/(x4-x2); - f4 = ((x-x3)*f4-(x-x4)*f3)/(x4-x3); - result = f4; - } - return result; -} - - - -} - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif +#include "stdafx.h" +#include "statistics.h" + +// disable some irrelevant warnings +#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS) +#pragma warning(disable:4100) +#pragma warning(disable:4127) +#pragma warning(disable:4611) +#pragma warning(disable:4702) +#pragma warning(disable:4996) +#endif + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + + +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the distribution moments: mean, variance, skewness, kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +OUTPUT PARAMETERS + Mean - mean. + Variance- variance. + Skewness- skewness (if variance<>0; zero otherwise). + Kurtosis- kurtosis (if variance<>0; zero otherwise). + +NOTE: variance is calculated by dividing sum of squares by N-1, not N. + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplemoments(x.c_ptr(), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Calculation of the distribution moments: mean, variance, skewness, kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +OUTPUT PARAMETERS + Mean - mean. + Variance- variance. + Skewness- skewness (if variance<>0; zero otherwise). + Kurtosis- kurtosis (if variance<>0; zero otherwise). + +NOTE: variance is calculated by dividing sum of squares by N-1, not N. + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplemoments(x.c_ptr(), n, &mean, &variance, &skewness, &kurtosis, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Calculation of the mean. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Mean' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplemean(const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplemean(x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculation of the mean. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Mean' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double samplemean(const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplemean(x.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Calculation of the variance. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Variance' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplevariance(const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplevariance(x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculation of the variance. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Variance' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double samplevariance(const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplevariance(x.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Calculation of the skewness. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Skewness' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double sampleskewness(const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::sampleskewness(x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculation of the skewness. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Skewness' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double sampleskewness(const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::sampleskewness(x.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Calculation of the kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Kurtosis' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplekurtosis(const real_1d_array &x, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplekurtosis(x.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Calculation of the kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Kurtosis' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double samplekurtosis(const real_1d_array &x, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::samplekurtosis(x.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +ADev + +Input parameters: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + ADev- ADev + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sampleadev(x.c_ptr(), n, &adev, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +ADev + +Input parameters: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + ADev- ADev + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void sampleadev(const real_1d_array &x, double &adev, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::sampleadev(x.c_ptr(), n, &adev, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Median calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + Median + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemedian(const real_1d_array &x, const ae_int_t n, double &median, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplemedian(x.c_ptr(), n, &median, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Median calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + Median + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void samplemedian(const real_1d_array &x, double &median, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplemedian(x.c_ptr(), n, &median, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Percentile calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + P - percentile (0<=P<=1) + +Output parameters: + V - percentile + + -- ALGLIB -- + Copyright 01.03.2008 by Bochkanov Sergey +*************************************************************************/ +void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplepercentile(x.c_ptr(), n, p, &v, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Percentile calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + P - percentile (0<=P<=1) + +Output parameters: + V - percentile + + -- ALGLIB -- + Copyright 01.03.2008 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void samplepercentile(const real_1d_array &x, const double p, double &v, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::samplepercentile(x.c_ptr(), n, p, &v, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +2-sample covariance + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + covariance (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cov2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +2-sample covariance + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + covariance (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double cov2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'cov2': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::cov2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Pearson product-moment correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Pearson product-moment correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::pearsoncorr2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Pearson product-moment correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Pearson product-moment correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'pearsoncorr2': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::pearsoncorr2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Spearman's rank correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Spearman's rank correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spearmancorr2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Spearman's rank correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Spearman's rank correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + if( (x.length()!=y.length())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spearmancorr2': looks like one of arguments has wrong size"); + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spearmancorr2(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return *(reinterpret_cast(&result)); +} +#endif + +/************************************************************************* +Covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::covm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void covm(const real_2d_array &x, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.rows(); + m = x.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::covm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Pearson product-moment correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pearsoncorrm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Pearson product-moment correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void pearsoncorrm(const real_2d_array &x, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.rows(); + m = x.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pearsoncorrm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Spearman's rank correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spearmancorrm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Spearman's rank correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spearmancorrm(const real_2d_array &x, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m; + + n = x.rows(); + m = x.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spearmancorrm(x.c_ptr(), n, m, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Cross-covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::covm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Cross-covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m1; + ae_int_t m2; + if( (x.rows()!=y.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'covm2': looks like one of arguments has wrong size"); + n = x.rows(); + m1 = x.cols(); + m2 = y.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::covm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Pearson product-moment cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pearsoncorrm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Pearson product-moment cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m1; + ae_int_t m2; + if( (x.rows()!=y.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'pearsoncorrm2': looks like one of arguments has wrong size"); + n = x.rows(); + m1 = x.cols(); + m2 = y.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pearsoncorrm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Spearman's rank cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spearmancorrm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Spearman's rank cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t m1; + ae_int_t m2; + if( (x.rows()!=y.rows())) + _ALGLIB_CPP_EXCEPTION("Error while calling 'spearmancorrm2': looks like one of arguments has wrong size"); + n = x.rows(); + m1 = x.cols(); + m2 = y.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spearmancorrm2(x.c_ptr(), y.c_ptr(), n, m1, m2, c.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function replaces data in XY by their ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* ranking starts from 0, ends at NFeatures-1 +* sum of within-row values is equal to (NFeatures-1)*NFeatures/2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +void rankdata(real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rankdata(xy.c_ptr(), npoints, nfeatures, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function replaces data in XY by their ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* ranking starts from 0, ends at NFeatures-1 +* sum of within-row values is equal to (NFeatures-1)*NFeatures/2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rankdata(real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nfeatures; + + npoints = xy.rows(); + nfeatures = xy.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rankdata(xy.c_ptr(), npoints, nfeatures, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function replaces data in XY by their CENTERED ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* centered ranks are just usual ranks, but centered in such way that sum + of within-row values is equal to 0.0. +* centering is performed by subtracting mean from each row, i.e it changes + mean value, but does NOT change higher moments + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +void rankdatacentered(real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rankdatacentered(xy.c_ptr(), npoints, nfeatures, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function replaces data in XY by their CENTERED ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* centered ranks are just usual ranks, but centered in such way that sum + of within-row values is equal to 0.0. +* centering is performed by subtracting mean from each row, i.e it changes + mean value, but does NOT change higher moments + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void rankdatacentered(real_2d_array &xy, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t npoints; + ae_int_t nfeatures; + + npoints = xy.rows(); + nfeatures = xy.cols(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::rankdatacentered(xy.c_ptr(), npoints, nfeatures, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +Obsolete function, we recommend to use PearsonCorr2(). + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::pearsoncorrelation(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} + +/************************************************************************* +Obsolete function, we recommend to use SpearmanCorr2(). + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + double result = alglib_impl::spearmanrankcorrelation(x.c_ptr(), y.c_ptr(), n, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return double(result); +} +#endif + +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Pearson's correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5 + * normality of distributions of X and Y. + +Input parameters: + R - Pearson's correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::pearsoncorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Spearman's rank correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5. + +The test is non-parametric and doesn't require distributions X and Y to be +normal. + +Input parameters: + R - Spearman's rank correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::spearmanrankcorrelationsignificance(r, n, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Jarque-Bera test + +This test checks hypotheses about the fact that a given sample X is a +sample of normal random variable. + +Requirements: + * the number of elements in the sample is not less than 5. + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. N>=5 + +Output parameters: + P - p-value for the test + +Accuracy of the approximation used (5<=N<=1951): + +p-value relative error (5<=N<=1951) +[1, 0.1] < 1% +[0.1, 0.01] < 2% +[0.01, 0.001] < 6% +[0.001, 0] wasn't measured + +For N>1951 accuracy wasn't measured but it shouldn't be sharply different +from table values. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::jarqueberatest(x.c_ptr(), n, &p, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Two-sample F-test + +This test checks three hypotheses about dispersions of the given samples. +The following tests are performed: + * two-tailed test (null hypothesis - the dispersions are equal) + * left-tailed test (null hypothesis - the dispersion of the first + sample is greater than or equal to the dispersion of the second + sample). + * right-tailed test (null hypothesis - the dispersion of the first + sample is less than or equal to the dispersion of the second sample) + +The test is based on the following assumptions: + * the given samples have normal distributions + * the samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - sample size. + Y - sample 2. Array whose index goes from 0 to M-1. + M - sample size. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ftest(x.c_ptr(), n, y.c_ptr(), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +One-sample chi-square test + +This test checks three hypotheses about the dispersion of the given sample +The following tests are performed: + * two-tailed test (null hypothesis - the dispersion equals the given + number) + * left-tailed test (null hypothesis - the dispersion is greater than + or equal to the given number) + * right-tailed test (null hypothesis - dispersion is less than or + equal to the given number). + +Test is based on the following assumptions: + * the given sample has a normal distribution. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Variance - dispersion value to compare with. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::onesamplevariancetest(x.c_ptr(), n, variance, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Wilcoxon signed-rank test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + * the distribution should be continuous and symmetric relative to its + median. + * number of distinct values in the X array should be greater than 4 + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with two decimal places in interval [0.0001, 1]. + +"Two decimal places" does not sound very impressive, but in practice the +relative error of less than 1% is enough to make a decision. + +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::wilcoxonsignedranktest(x.c_ptr(), n, e, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +One-sample t-test + +This test checks three hypotheses about the mean of the given sample. The +following tests are performed: + * two-tailed test (null hypothesis - the mean is equal to the given + value) + * left-tailed test (null hypothesis - the mean is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the mean is less than or equal + to the given value). + +The test is based on the assumption that a given sample has a normal +distribution and an unknown dispersion. If the distribution sharply +differs from normal, the test will work incorrectly. + +INPUT PARAMETERS: + X - sample. Array whose index goes from 0 to N-1. + N - size of sample, N>=0 + Mean - assumed value of the mean. + +OUTPUT PARAMETERS: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0, all p-values are set to 1.0 + * when variance of X[] is exactly zero, p-values are set + to 1.0 or 0.0, depending on difference between sample mean and + value of mean being tested. + + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::studentttest1(x.c_ptr(), n, mean, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Two-sample pooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * dispersions are equal + * samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has exactly zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::studentttest2(x.c_ptr(), n, y.c_ptr(), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Two-sample unpooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * samples are independent. +Equality of variances is NOT required. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + * when only one sample has zero variance, test reduces to 1-sample + version. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::unequalvariancettest(x.c_ptr(), n, y.c_ptr(), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sign test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +While calculating p-values high-precision binomial distribution +approximation is used, so significance levels have about 15 exact digits. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::onesamplesigntest(x.c_ptr(), n, median, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes MCMC sampler using single initial point to seed +the population. + +The population is generated around the initial point with random Gaussian +noise being added, having per-variable magnitude equal to XStdDev or (if +MCMCSetScale() was called) equal to XStdDev*S[I]. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point used to seed a MCMC algo, array[N]: + * it is better to have X not too far away from the maximum + of log-likelihood + * any point will do, if no maximum location is unknown + XStdDev - standard deviation of a population generated around X: + * strictly greater than zero + * nearly zero values are likely to cause population to + stagnate, whilst too large values are likely to cause + population to spend excessive time converging + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreate1(const ae_int_t n, const real_1d_array &x, const double xstddev, mcmcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmccreate1(n, x.c_ptr(), xstddev, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initializes MCMC sampler using single initial point to seed +the population. + +The population is generated around the initial point with random Gaussian +noise being added, having per-variable magnitude equal to XStdDev or (if +MCMCSetScale() was called) equal to XStdDev*S[I]. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point used to seed a MCMC algo, array[N]: + * it is better to have X not too far away from the maximum + of log-likelihood + * any point will do, if no maximum location is unknown + XStdDev - standard deviation of a population generated around X: + * strictly greater than zero + * nearly zero values are likely to cause population to + stagnate, whilst too large values are likely to cause + population to spend excessive time converging + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcmccreate1(const real_1d_array &x, const double xstddev, mcmcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + + n = x.length(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmccreate1(n, x.c_ptr(), xstddev, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function initializes MCMC sampler using a population of user-specified +points. + +A specific sampling algorithm that needs an initial population will use +user-provided points. If an algorithm needs more initial points than was +specified, additional points will be randomly generated using population +as a distribution reference. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of P are used + * if not given, automatically determined from size of P + P - initial points, array[PopSize,N] + PopSize - population size, PopSize>0: + * if given, only leading PopSize elements of P are used + * if not given, automatically determined from size of P + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreatefrompopulation(const ae_int_t n, const real_2d_array &p, const ae_int_t popsize, mcmcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmccreatefrompopulation(n, p.c_ptr(), popsize, state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function initializes MCMC sampler using a population of user-specified +points. + +A specific sampling algorithm that needs an initial population will use +user-provided points. If an algorithm needs more initial points than was +specified, additional points will be randomly generated using population +as a distribution reference. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of P are used + * if not given, automatically determined from size of P + P - initial points, array[PopSize,N] + PopSize - population size, PopSize>0: + * if given, only leading PopSize elements of P are used + * if not given, automatically determined from size of P + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.05.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcmccreatefrompopulation(const real_2d_array &p, mcmcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + ae_int_t n; + ae_int_t popsize; + + n = p.cols(); + popsize = p.rows(); + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmccreatefrompopulation(n, p.c_ptr(), popsize, state.c_ptr(), &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets per-variable scaling coefficients for MCMC sampler. + +Present version of the MCMC sampler uses per-variable scales during initial +popilation generation: an initial point X0 is perturbed with random noise, +whose per-variable magnitude is XStdDev*S[I]. + +Future versions of the sampler may use scales for other purposes too, but +are likely to do so in a backward-compatible manner. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetscale(mcmcstate &state, const real_1d_array &s, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetscale(state.c_ptr(), s.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function controls adaptation rate of the temperature ladder used by +adaptive parallel tempering algorithms. + +The sampler changes the logarithmic difference between temperatures in the +ladder ln(T[i+1]-T[i]) as a product of different between swap accept rates +A[i]-A[i+1] and current adaptation rate, which is nu0/(1+iteridx/tau). + +Here nu0 is an initial adaptation rate that similar to stochastic gradient +descent learning rate. Recommended values 0.01-0.1. And tau is a learning +rate decay time, depending on the problem it can be 100 or 1000. + +The MCMC sampler uses some default values for these parameters, but they +can change in future versions without notice. + +This function has no effect when adaptive tempering is not active. + +INPUT PARAMETERS: + State - structure stores algorithm state + Nu0 - initial learning rate, >=0. + Zero value effectively turns off adaptation. + Tau - characteristic decay time, >=0. + Zero value effectively turns off adaptation. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetladderadaptationrate(mcmcstate &state, const double nu0, const double tau, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetladderadaptationrate(state.c_ptr(), nu0, tau, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates parallel tempering with the fixed temperature +ladder. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +INPUT PARAMETERS: + State - structure stores algorithm state + T - array[NTemp], T[0]=1, T[I+1]>T[I], sampling temperatures. + If the first element of T is different from 1, or + temperatures are not strictly increasing, an exception is + raised + NTemp - >=1, temperature ladder height + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetfixedtemperatureladder(mcmcstate &state, const real_1d_array &t, const ae_int_t ntemp, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetfixedtemperatureladder(state.c_ptr(), t.c_ptr(), ntemp, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function activates parallel tempering with the adaptive temperature +ladder using uniform Swap Acceptance Rate (SAR) proposal. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +The function accepts the hottest temperature in the ladder TMax, as well +as ladder height NTemp>=1. + +You can control adaptation rate wuth mcmcsetladderadaptationrate() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + TMax - initial value of the maximum temperature in the ladder, + TMax>1 (strictly) + NTemp - >=1, temperature ladder height: + * NTemp=1 means that no temperature ladder is actually used + * NTemp=2 means that we have a ladder with temperatures + [1,TMax] and no adaptation + * NTemp>2 means that we have a ladder with T[0]=1 and + T[NTemp-1]=TMax, and adaptive temperatures between them. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetsartemperatureladder(mcmcstate &state, const double tmax, const ae_int_t ntemp, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetsartemperatureladder(state.c_ptr(), tmax, ntemp, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +Same as mcmcsetalgostretch(). +*************************************************************************/ +void mcmcsetalgogoodmanweare(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgogoodmanweare(state.c_ptr(), popsize, epochscnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses stretch move, as defined in 'Ensemble samplers with affine +invariance', Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + EpochsCnt- iterations count to be reported, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgostretch(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgostretch(state.c_ptr(), popsize, epochscnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses walk move, as defined in 'Ensemble samplers with affine invariance', +Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + helpers, and that we can use parallel moves. + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + HelpersCnt- helpers count, >=2. Number of helpers used to generate + proposal. Recommended values: some small number like 3-5. + It is possible to specify HelpersCnt=PopSize, but for + large populations it will result in proposal generation + overhead growing as O(N*PopSize^2). + Values larger than PopSize will be silently truncated to + PopSize. + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgowalk(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const ae_int_t helperscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgowalk(state.c_ptr(), popsize, epochscnt, helperscnt, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move, as defined in 'RUN DMC: an efficient, parallel code for +analyzing radial velocity observations using n-body integrations and +differential evolution Markov chain Monte Carlo' by Benjamin Nelson, Eric +B. Ford, and Matthew J. Payne. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Sigma - non-negative, standard deviation of a Gaussian used to + randomly modify the proposal vector. Recommended values: + about 1E-5. Zero value (or omitted) means that a default + one is used. + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2N), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgode(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const double sigma, const double gamma0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgode(state.c_ptr(), popsize, epochscnt, sigma, gamma0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move, as defined in 'RUN DMC: an efficient, parallel code for +analyzing radial velocity observations using n-body integrations and +differential evolution Markov chain Monte Carlo' by Benjamin Nelson, Eric +B. Ford, and Matthew J. Payne. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Sigma - non-negative, standard deviation of a Gaussian used to + randomly modify the proposal vector. Recommended values: + about 1E-5. Zero value (or omitted) means that a default + one is used. + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2N), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcmcsetalgode(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double sigma; + double gamma0; + + sigma = 0; + gamma0 = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgode(state.c_ptr(), popsize, epochscnt, sigma, gamma0, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move with snooker update, as defined in 'Differential Evolution +Markov Chain with snooker updater and fewer chains' by Cajo J.F. ter Braak +and Jasper A. Vrugt. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=6 + that follows from the fact that each update needs at least three + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + In order to simplify the algorithm, if N+1<=PopSize<6, we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgodesnooker(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const double gamma0, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgodesnooker(state.c_ptr(), popsize, epochscnt, gamma0, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move with snooker update, as defined in 'Differential Evolution +Markov Chain with snooker updater and fewer chains' by Cajo J.F. ter Braak +and Jasper A. Vrugt. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=6 + that follows from the fact that each update needs at least three + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + In order to simplify the algorithm, if N+1<=PopSize<6, we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +#if !defined(AE_NO_EXCEPTIONS) +void mcmcsetalgodesnooker(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + double gamma0; + + gamma0 = 0; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgodesnooker(state.c_ptr(), popsize, epochscnt, gamma0, &_alglib_env_state); + + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses Gaussian random walk, an ensemble of PopSize completely independent +walkers. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: this move is special because it can work with any ensemble size, + including PopSize=1 (most other moves need at least 4, 5 or 6 + walkers in the ensemble). Other moves will throw an exception if + called with PopSize=1. + + EpochsCnt- iterations count to be reported, >=1 + + C - array[N,N], a positive definite covariance matrix. Walker + position is perturbed with Gaussian perturbation with + covariance C. + + IsUpper - if IsUpper=True, only upper triangle of C is used (the + lower one is ignored). Otherwise, only lower triangle is + used. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgogaussian(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const real_2d_array &c, const bool isupper, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetalgogaussian(state.c_ptr(), popsize, epochscnt, c.c_ptr(), isupper, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets number of additional initial iterations (in addition to +EpochsCnt) that will be performed and discarded (not stored into the +report sample), so called 'burn-in length'. + +In total, BurnInLen+EpochsCnt iterations will be performed, with initial +BurnInLen ones being used solely to help MCMC spread walkers according to +the density of the function being sampled. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + BurnInLen - burn-in length, >=0 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetburninlength(mcmcstate &state, const ae_int_t burninlen, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetburninlength(state.c_ptr(), burninlen, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets thinning factor: ThinBy*EpochsCnt iterations will be +performed (after the optional burn-in phase), with every ThinBy-th +iteration being saved and the rest being discarded. + +This option helps to avoid storing highly correlated samples. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + ThinBy - thinning factor, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetthinningfactor(mcmcstate &state, const ae_int_t thinby, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetthinningfactor(state.c_ptr(), thinby, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function sets the seed which is used to initialize internal RNG. By +default, a deterministic seed is used - same for each run of the sampler. +It means that the same sampling decisions are taken every time. + +If you specify a non-deterministic seed value, then the sampler may return +slightly different results after each run. + +INPUT PARAMETERS: + S - sampler state + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetseed(mcmcstate &s, const ae_int_t seed, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mcmcsetseed(s.c_ptr(), seed, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mcmciteration(mcmcstate &state, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return 0; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + ae_bool result = alglib_impl::mcmciteration(state.c_ptr(), &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return bool(result); +} + + +void mcmcrun(mcmcstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr), + void *ptr, + const xparams _xparams) +{ + alglib_impl::mcmcstate &optimizer = *(state.c_ptr()); + alglib_impl::rcommv2_request request( + optimizer.requesttype, + optimizer.querysize, optimizer.queryfuncs, optimizer.queryvars, optimizer.querydim, optimizer.queryformulasize, + optimizer.querydata.ptr.p_double, optimizer.replyfi.ptr.p_double, optimizer.replydj.ptr.p_double, optimizer.replysj, ptr, + "mcmc"); + alglib_impl::rcommv2_callbacks callbacks; + alglib_impl::rcommv2_buffers buffers(&state.c_ptr()->tmpx1, &state.c_ptr()->tmpc1, &state.c_ptr()->tmpf1, &state.c_ptr()->tmpg1, &state.c_ptr()->tmpj1, &state.c_ptr()->tmps1); + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'mcmcrun()' (func is NULL)", &_alglib_env_state); +callbacks.func = func; + + alglib_impl::mcmcsetprotocolv2(state.c_ptr(), &_alglib_env_state); + while( alglib_impl::mcmciteration(state.c_ptr(), &_alglib_env_state) ) + { + _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN + if( optimizer.requesttype==3 ) + { + const ae_int_t njobs = request.size*request.vars+request.size; + for(alglib_impl::ae_int_t job_idx=0; job_idx(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcmcstate_owner& _mcmcstate_owner::operator=(const _mcmcstate_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mcmcstate assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcmcstate assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mcmcstate assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mcmcstate_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mcmcstate)); + alglib_impl::_mcmcstate_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mcmcstate_owner::~_mcmcstate_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mcmcstate_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mcmcstate* _mcmcstate_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mcmcstate* _mcmcstate_owner::c_ptr() const +{ + return p_struct; +} +mcmcstate::mcmcstate() : _mcmcstate_owner() +{ +} + +mcmcstate::mcmcstate(alglib_impl::mcmcstate *attach_to):_mcmcstate_owner(attach_to) +{ +} + +mcmcstate::mcmcstate(const mcmcstate &rhs):_mcmcstate_owner(rhs) +{ +} + +mcmcstate& mcmcstate::operator=(const mcmcstate &rhs) +{ + if( this==&rhs ) + return *this; + _mcmcstate_owner::operator=(rhs); + return *this; +} + +mcmcstate::~mcmcstate() +{ +} + + + + +/************************************************************************* +These fields store MCMC report: +* nfev number of function evaluations +* acceptrate acceptance rate of a MCMC algo; when parallel + tempering is used, this field stores acceptance + rate for the lowest level (T=1). +* swapacceptrate acceptance rate for swaps between levels of the + temperature ladder. When no parallel tempering + is used, stores zero. +* autocorrtimes array[N], per-variable autocorrelation times +*************************************************************************/ +_mcmcreport_owner::_mcmcreport_owner() +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcmcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + p_struct = (alglib_impl::mcmcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcmcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcmcreport)); + alglib_impl::_mcmcreport_init(p_struct, &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcmcreport_owner::_mcmcreport_owner(alglib_impl::mcmcreport *attach_to) +{ + p_struct = attach_to; + is_attached = true; +} + +_mcmcreport_owner::_mcmcreport_owner(const _mcmcreport_owner &rhs) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { + if( p_struct!=NULL ) + { + alglib_impl::_mcmcreport_destroy(p_struct); + alglib_impl::ae_free(p_struct); + } + p_struct = NULL; +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + p_struct = NULL; + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcmcreport copy constructor failure (source is not initialized)", &_state); + p_struct = (alglib_impl::mcmcreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::mcmcreport), &_state); + memset(p_struct, 0, sizeof(alglib_impl::mcmcreport)); + alglib_impl::_mcmcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + is_attached = false; +} + +_mcmcreport_owner& _mcmcreport_owner::operator=(const _mcmcreport_owner &rhs) +{ + if( this==&rhs ) + return *this; + jmp_buf _break_jump; + alglib_impl::ae_state _state; + + alglib_impl::ae_state_init(&_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_state.error_msg); + return *this; +#endif + } + alglib_impl::ae_state_set_break_jump(&_state, &_break_jump); + alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: mcmcreport assignment constructor failure (destination is not initialized)", &_state); + alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: mcmcreport assignment constructor failure (source is not initialized)", &_state); + alglib_impl::ae_assert(!is_attached, "ALGLIB: mcmcreport assignment constructor failure (can not assign to the structure which is attached to something else)", &_state); + alglib_impl::_mcmcreport_destroy(p_struct); + memset(p_struct, 0, sizeof(alglib_impl::mcmcreport)); + alglib_impl::_mcmcreport_init_copy(p_struct, const_cast(rhs.p_struct), &_state, ae_false); + ae_state_clear(&_state); + return *this; +} + +_mcmcreport_owner::~_mcmcreport_owner() +{ + if( p_struct!=NULL && !is_attached ) + { + alglib_impl::_mcmcreport_destroy(p_struct); + ae_free(p_struct); + } +} + +alglib_impl::mcmcreport* _mcmcreport_owner::c_ptr() +{ + return p_struct; +} + +const alglib_impl::mcmcreport* _mcmcreport_owner::c_ptr() const +{ + return p_struct; +} +mcmcreport::mcmcreport() : _mcmcreport_owner() ,nfev(p_struct->nfev),acceptrate(p_struct->acceptrate),swapacceptrate(p_struct->swapacceptrate),autocorrtimes(&p_struct->autocorrtimes) +{ +} + +mcmcreport::mcmcreport(alglib_impl::mcmcreport *attach_to):_mcmcreport_owner(attach_to) ,nfev(p_struct->nfev),acceptrate(p_struct->acceptrate),swapacceptrate(p_struct->swapacceptrate),autocorrtimes(&p_struct->autocorrtimes) +{ +} + +mcmcreport::mcmcreport(const mcmcreport &rhs):_mcmcreport_owner(rhs) ,nfev(p_struct->nfev),acceptrate(p_struct->acceptrate),swapacceptrate(p_struct->swapacceptrate),autocorrtimes(&p_struct->autocorrtimes) +{ +} + +mcmcreport& mcmcreport::operator=(const mcmcreport &rhs) +{ + if( this==&rhs ) + return *this; + _mcmcreport_owner::operator=(rhs); + return *this; +} + +mcmcreport::~mcmcreport() +{ +} +#endif + +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Mann-Whitney U-test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions of the same shape and same median or whether +their medians are different. + +The following tests are performed: + * two-tailed test (null hypothesis - the medians are equal) + * left-tailed test (null hypothesis - the median of the first sample + is greater than or equal to the median of the second sample) + * right-tailed test (null hypothesis - the median of the first sample + is less than or equal to the median of the second sample). + +Requirements: + * the samples are independent + * X and Y are continuous distributions (or discrete distributions well- + approximating continuous distributions) + * distributions of X and Y have the same shape. The only possible + difference is their position (i.e. the value of the median) + * the number of elements in each sample is not less than 5 + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + +The test is non-parametric and doesn't require distributions to be normal. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. N>=5 + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. M>=5 + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with satisfactory accuracy in interval [0.0001, 1]. +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + +Relative precision of approximation of p-value: + +N M Max.err. Rms.err. +5..10 N..10 1.4e-02 6.0e-04 +5..10 N..100 2.2e-02 5.3e-06 +10..15 N..15 1.0e-02 3.2e-04 +10..15 N..100 1.0e-02 2.2e-05 +15..100 N..100 6.1e-03 2.7e-06 + +For N,M>100 accuracy checks weren't put into practice, but taking into +account characteristics of asymptotic approximation used, precision should +not be sharply different from the values for interval [5, 100]. + +NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, + P's outside of this interval are enforced to these bounds. Say, you + may quite often get P equal to exactly 0.25 or 0.0001. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams) +{ + jmp_buf _break_jump; + alglib_impl::ae_state _alglib_env_state; + alglib_impl::ae_state_init(&_alglib_env_state); + if( setjmp(_break_jump) ) + { +#if !defined(AE_NO_EXCEPTIONS) + _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg); +#else + _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg); + return; +#endif + } + ae_state_set_break_jump(&_alglib_env_state, &_break_jump); + if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 ) + ae_state_set_flags(&_alglib_env_state, _xparams.flags); + alglib_impl::mannwhitneyutest(x.c_ptr(), n, y.c_ptr(), m, &bothtails, &lefttail, &righttail, &_alglib_env_state); + alglib_impl::ae_state_clear(&_alglib_env_state); + return; +} +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) +static void basestat_rankdatarec(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + ae_shared_pool* pool, + ae_int_t basecasecost, + ae_state *_state); +ae_bool _trypexec_basestat_rankdatarec(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + ae_shared_pool* pool, + ae_int_t basecasecost, ae_state *_state); +static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + apbuffers* buf0, + apbuffers* buf1, + ae_state *_state); +ae_bool _trypexec_basestat_rankdatabasecase(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + apbuffers* buf0, + apbuffers* buf1, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) +static double correlationtests_spearmantail5(double s, ae_state *_state); +static double correlationtests_spearmantail6(double s, ae_state *_state); +static double correlationtests_spearmantail7(double s, ae_state *_state); +static double correlationtests_spearmantail8(double s, ae_state *_state); +static double correlationtests_spearmantail9(double s, ae_state *_state); +static double correlationtests_spearmantail(double t, + ae_int_t n, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) +static void jarquebera_jarqueberastatistic(/* Real */ const ae_vector* x, + ae_int_t n, + double* s, + ae_state *_state); +static double jarquebera_jarqueberaapprox(ae_int_t n, + double s, + ae_state *_state); +static double jarquebera_jbtbl5(double s, ae_state *_state); +static double jarquebera_jbtbl6(double s, ae_state *_state); +static double jarquebera_jbtbl7(double s, ae_state *_state); +static double jarquebera_jbtbl8(double s, ae_state *_state); +static double jarquebera_jbtbl9(double s, ae_state *_state); +static double jarquebera_jbtbl10(double s, ae_state *_state); +static double jarquebera_jbtbl11(double s, ae_state *_state); +static double jarquebera_jbtbl12(double s, ae_state *_state); +static double jarquebera_jbtbl13(double s, ae_state *_state); +static double jarquebera_jbtbl14(double s, ae_state *_state); +static double jarquebera_jbtbl15(double s, ae_state *_state); +static double jarquebera_jbtbl16(double s, ae_state *_state); +static double jarquebera_jbtbl17(double s, ae_state *_state); +static double jarquebera_jbtbl18(double s, ae_state *_state); +static double jarquebera_jbtbl19(double s, ae_state *_state); +static double jarquebera_jbtbl20(double s, ae_state *_state); +static double jarquebera_jbtbl30(double s, ae_state *_state); +static double jarquebera_jbtbl50(double s, ae_state *_state); +static double jarquebera_jbtbl65(double s, ae_state *_state); +static double jarquebera_jbtbl100(double s, ae_state *_state); +static double jarquebera_jbtbl130(double s, ae_state *_state); +static double jarquebera_jbtbl200(double s, ae_state *_state); +static double jarquebera_jbtbl301(double s, ae_state *_state); +static double jarquebera_jbtbl501(double s, ae_state *_state); +static double jarquebera_jbtbl701(double s, ae_state *_state); +static double jarquebera_jbtbl1401(double s, ae_state *_state); +static void jarquebera_jbcheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) +static void wsr_wcheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state); +static double wsr_w5(double s, ae_state *_state); +static double wsr_w6(double s, ae_state *_state); +static double wsr_w7(double s, ae_state *_state); +static double wsr_w8(double s, ae_state *_state); +static double wsr_w9(double s, ae_state *_state); +static double wsr_w10(double s, ae_state *_state); +static double wsr_w11(double s, ae_state *_state); +static double wsr_w12(double s, ae_state *_state); +static double wsr_w13(double s, ae_state *_state); +static double wsr_w14(double s, ae_state *_state); +static double wsr_w15(double s, ae_state *_state); +static double wsr_w16(double s, ae_state *_state); +static double wsr_w17(double s, ae_state *_state); +static double wsr_w18(double s, ae_state *_state); +static double wsr_w19(double s, ae_state *_state); +static double wsr_w20(double s, ae_state *_state); +static double wsr_w21(double s, ae_state *_state); +static double wsr_w22(double s, ae_state *_state); +static double wsr_w23(double s, ae_state *_state); +static double wsr_w24(double s, ae_state *_state); +static double wsr_w25(double s, ae_state *_state); +static double wsr_w26(double s, ae_state *_state); +static double wsr_w27(double s, ae_state *_state); +static double wsr_w28(double s, ae_state *_state); +static double wsr_w29(double s, ae_state *_state); +static double wsr_w30(double s, ae_state *_state); +static double wsr_w40(double s, ae_state *_state); +static double wsr_w60(double s, ae_state *_state); +static double wsr_w120(double s, ae_state *_state); +static double wsr_w200(double s, ae_state *_state); +static double wsr_wsigma(double s, ae_int_t n, ae_state *_state); + + +#endif +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) + + +#endif +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +static double mcmc_goodmanwearea = 2.0; +static double mcmc_cautocorr = 5.0; +static void mcmc_initinternal(mcmcstate* state, + ae_int_t n, + ae_state *_state); +static void mcmc_dologging(mcmcstate* state, + ae_int_t iteridx, + ae_int_t accept1cnt, + ae_int_t accepthcnt, + ae_state *_state); +static void mcmc_applyswapsandadapt(mcmcstate* state, + ae_int_t rawitidx, + ae_bool burninover, + hqrndstate* rs, + ae_state *_state); +static void mcmc_savepopulation(mcmcstate* state, ae_state *_state); +static void mcmc_generateproposals(mcmcstate* state, + hqrndstate* rs, + /* Integer */ const ae_vector* grpidx, + ae_int_t dstgrpsize, + /* Integer */ ae_vector* propidx, + /* Real */ ae_vector* propz, + /* Real */ ae_vector* propt, + /* Real */ ae_matrix* propxf, + ae_state *_state); +static void mcmc_computeautocorrtimes(const mcmcstate* state, + /* Real */ ae_vector* autocorrtimes, + ae_state *_state); +static void mcmc_autocorrij(const mcmcstate* state, + ae_int_t idxw, + ae_int_t idxv, + /* Real */ ae_vector* a, + ae_state *_state); + + +#endif +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) +static void mannwhitneyu_ucheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state); +static double mannwhitneyu_uninterpolate(double p1, + double p2, + double p3, + ae_int_t n, + ae_state *_state); +static double mannwhitneyu_usigma000(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma075(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma150(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma225(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma300(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma333(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma367(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_usigma400(ae_int_t n1, + ae_int_t n2, + ae_state *_state); +static double mannwhitneyu_utbln5n5(double s, ae_state *_state); +static double mannwhitneyu_utbln5n6(double s, ae_state *_state); +static double mannwhitneyu_utbln5n7(double s, ae_state *_state); +static double mannwhitneyu_utbln5n8(double s, ae_state *_state); +static double mannwhitneyu_utbln5n9(double s, ae_state *_state); +static double mannwhitneyu_utbln5n10(double s, ae_state *_state); +static double mannwhitneyu_utbln5n11(double s, ae_state *_state); +static double mannwhitneyu_utbln5n12(double s, ae_state *_state); +static double mannwhitneyu_utbln5n13(double s, ae_state *_state); +static double mannwhitneyu_utbln5n14(double s, ae_state *_state); +static double mannwhitneyu_utbln5n15(double s, ae_state *_state); +static double mannwhitneyu_utbln5n16(double s, ae_state *_state); +static double mannwhitneyu_utbln5n17(double s, ae_state *_state); +static double mannwhitneyu_utbln5n18(double s, ae_state *_state); +static double mannwhitneyu_utbln5n19(double s, ae_state *_state); +static double mannwhitneyu_utbln5n20(double s, ae_state *_state); +static double mannwhitneyu_utbln5n21(double s, ae_state *_state); +static double mannwhitneyu_utbln5n22(double s, ae_state *_state); +static double mannwhitneyu_utbln5n23(double s, ae_state *_state); +static double mannwhitneyu_utbln5n24(double s, ae_state *_state); +static double mannwhitneyu_utbln5n25(double s, ae_state *_state); +static double mannwhitneyu_utbln5n26(double s, ae_state *_state); +static double mannwhitneyu_utbln5n27(double s, ae_state *_state); +static double mannwhitneyu_utbln5n28(double s, ae_state *_state); +static double mannwhitneyu_utbln5n29(double s, ae_state *_state); +static double mannwhitneyu_utbln5n30(double s, ae_state *_state); +static double mannwhitneyu_utbln5n100(double s, ae_state *_state); +static double mannwhitneyu_utbln6n6(double s, ae_state *_state); +static double mannwhitneyu_utbln6n7(double s, ae_state *_state); +static double mannwhitneyu_utbln6n8(double s, ae_state *_state); +static double mannwhitneyu_utbln6n9(double s, ae_state *_state); +static double mannwhitneyu_utbln6n10(double s, ae_state *_state); +static double mannwhitneyu_utbln6n11(double s, ae_state *_state); +static double mannwhitneyu_utbln6n12(double s, ae_state *_state); +static double mannwhitneyu_utbln6n13(double s, ae_state *_state); +static double mannwhitneyu_utbln6n14(double s, ae_state *_state); +static double mannwhitneyu_utbln6n15(double s, ae_state *_state); +static double mannwhitneyu_utbln6n30(double s, ae_state *_state); +static double mannwhitneyu_utbln6n100(double s, ae_state *_state); +static double mannwhitneyu_utbln7n7(double s, ae_state *_state); +static double mannwhitneyu_utbln7n8(double s, ae_state *_state); +static double mannwhitneyu_utbln7n9(double s, ae_state *_state); +static double mannwhitneyu_utbln7n10(double s, ae_state *_state); +static double mannwhitneyu_utbln7n11(double s, ae_state *_state); +static double mannwhitneyu_utbln7n12(double s, ae_state *_state); +static double mannwhitneyu_utbln7n13(double s, ae_state *_state); +static double mannwhitneyu_utbln7n14(double s, ae_state *_state); +static double mannwhitneyu_utbln7n15(double s, ae_state *_state); +static double mannwhitneyu_utbln7n30(double s, ae_state *_state); +static double mannwhitneyu_utbln7n100(double s, ae_state *_state); +static double mannwhitneyu_utbln8n8(double s, ae_state *_state); +static double mannwhitneyu_utbln8n9(double s, ae_state *_state); +static double mannwhitneyu_utbln8n10(double s, ae_state *_state); +static double mannwhitneyu_utbln8n11(double s, ae_state *_state); +static double mannwhitneyu_utbln8n12(double s, ae_state *_state); +static double mannwhitneyu_utbln8n13(double s, ae_state *_state); +static double mannwhitneyu_utbln8n14(double s, ae_state *_state); +static double mannwhitneyu_utbln8n15(double s, ae_state *_state); +static double mannwhitneyu_utbln8n30(double s, ae_state *_state); +static double mannwhitneyu_utbln8n100(double s, ae_state *_state); +static double mannwhitneyu_utbln9n9(double s, ae_state *_state); +static double mannwhitneyu_utbln9n10(double s, ae_state *_state); +static double mannwhitneyu_utbln9n11(double s, ae_state *_state); +static double mannwhitneyu_utbln9n12(double s, ae_state *_state); +static double mannwhitneyu_utbln9n13(double s, ae_state *_state); +static double mannwhitneyu_utbln9n14(double s, ae_state *_state); +static double mannwhitneyu_utbln9n15(double s, ae_state *_state); +static double mannwhitneyu_utbln9n30(double s, ae_state *_state); +static double mannwhitneyu_utbln9n100(double s, ae_state *_state); +static double mannwhitneyu_utbln10n10(double s, ae_state *_state); +static double mannwhitneyu_utbln10n11(double s, ae_state *_state); +static double mannwhitneyu_utbln10n12(double s, ae_state *_state); +static double mannwhitneyu_utbln10n13(double s, ae_state *_state); +static double mannwhitneyu_utbln10n14(double s, ae_state *_state); +static double mannwhitneyu_utbln10n15(double s, ae_state *_state); +static double mannwhitneyu_utbln10n30(double s, ae_state *_state); +static double mannwhitneyu_utbln10n100(double s, ae_state *_state); +static double mannwhitneyu_utbln11n11(double s, ae_state *_state); +static double mannwhitneyu_utbln11n12(double s, ae_state *_state); +static double mannwhitneyu_utbln11n13(double s, ae_state *_state); +static double mannwhitneyu_utbln11n14(double s, ae_state *_state); +static double mannwhitneyu_utbln11n15(double s, ae_state *_state); +static double mannwhitneyu_utbln11n30(double s, ae_state *_state); +static double mannwhitneyu_utbln11n100(double s, ae_state *_state); +static double mannwhitneyu_utbln12n12(double s, ae_state *_state); +static double mannwhitneyu_utbln12n13(double s, ae_state *_state); +static double mannwhitneyu_utbln12n14(double s, ae_state *_state); +static double mannwhitneyu_utbln12n15(double s, ae_state *_state); +static double mannwhitneyu_utbln12n30(double s, ae_state *_state); +static double mannwhitneyu_utbln12n100(double s, ae_state *_state); +static double mannwhitneyu_utbln13n13(double s, ae_state *_state); +static double mannwhitneyu_utbln13n14(double s, ae_state *_state); +static double mannwhitneyu_utbln13n15(double s, ae_state *_state); +static double mannwhitneyu_utbln13n30(double s, ae_state *_state); +static double mannwhitneyu_utbln13n100(double s, ae_state *_state); +static double mannwhitneyu_utbln14n14(double s, ae_state *_state); +static double mannwhitneyu_utbln14n15(double s, ae_state *_state); +static double mannwhitneyu_utbln14n30(double s, ae_state *_state); +static double mannwhitneyu_utbln14n100(double s, ae_state *_state); +static double mannwhitneyu_usigma(double s, + ae_int_t n1, + ae_int_t n2, + ae_state *_state); + + +#endif + +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Calculation of the distribution moments: mean, variance, skewness, kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +OUTPUT PARAMETERS + Mean - mean. + Variance- variance. + Skewness- skewness (if variance<>0; zero otherwise). + Kurtosis- kurtosis (if variance<>0; zero otherwise). + +NOTE: variance is calculated by dividing sum of squares by N-1, not N. + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemoments(/* Real */ const ae_vector* x, + ae_int_t n, + double* mean, + double* variance, + double* skewness, + double* kurtosis, + ae_state *_state) +{ + ae_int_t i; + double v; + double v1; + double v2; + double stddev; + + *mean = 0.0; + *variance = 0.0; + *skewness = 0.0; + *kurtosis = 0.0; + + ae_assert(n>=0, "SampleMoments: N<0", _state); + ae_assert(x->cnt>=n, "SampleMoments: Length(X)ptr.p_double[i]; + } + *mean = *mean/(double)n; + + /* + * Variance (using corrected two-pass algorithm) + */ + if( n!=1 ) + { + v1 = (double)(0); + for(i=0; i<=n-1; i++) + { + v1 = v1+ae_sqr(x->ptr.p_double[i]-(*mean), _state); + } + v2 = (double)(0); + for(i=0; i<=n-1; i++) + { + v2 = v2+(x->ptr.p_double[i]-(*mean)); + } + v2 = ae_sqr(v2, _state)/(double)n; + *variance = (v1-v2)/(double)(n-1); + if( ae_fp_less(*variance,(double)(0)) ) + { + *variance = (double)(0); + } + stddev = ae_sqrt(*variance, _state); + } + + /* + * Skewness and kurtosis + */ + if( ae_fp_neq(stddev,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + v = (x->ptr.p_double[i]-(*mean))/stddev; + v2 = ae_sqr(v, _state); + *skewness = *skewness+v2*v; + *kurtosis = *kurtosis+ae_sqr(v2, _state); + } + *skewness = *skewness/(double)n; + *kurtosis = *kurtosis/(double)n-(double)3; + } +} + + +/************************************************************************* +Calculation of the mean. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Mean' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplemean(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double mean; + double tmp0; + double tmp1; + double tmp2; + double result; + + + samplemoments(x, n, &mean, &tmp0, &tmp1, &tmp2, _state); + result = mean; + return result; +} + + +/************************************************************************* +Calculation of the variance. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Variance' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplevariance(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double variance; + double tmp0; + double tmp1; + double tmp2; + double result; + + + samplemoments(x, n, &tmp0, &variance, &tmp1, &tmp2, _state); + result = variance; + return result; +} + + +/************************************************************************* +Calculation of the skewness. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Skewness' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double sampleskewness(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double skewness; + double tmp0; + double tmp1; + double tmp2; + double result; + + + samplemoments(x, n, &tmp0, &tmp1, &skewness, &tmp2, _state); + result = skewness; + return result; +} + + +/************************************************************************* +Calculation of the kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Kurtosis' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplekurtosis(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state) +{ + double kurtosis; + double tmp0; + double tmp1; + double tmp2; + double result; + + + samplemoments(x, n, &tmp0, &tmp1, &tmp2, &kurtosis, _state); + result = kurtosis; + return result; +} + + +/************************************************************************* +ADev + +Input parameters: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + ADev- ADev + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void sampleadev(/* Real */ const ae_vector* x, + ae_int_t n, + double* adev, + ae_state *_state) +{ + ae_int_t i; + double mean; + + *adev = 0.0; + + ae_assert(n>=0, "SampleADev: N<0", _state); + ae_assert(x->cnt>=n, "SampleADev: Length(X)ptr.p_double[i]; + } + mean = mean/(double)n; + + /* + * ADev + */ + for(i=0; i<=n-1; i++) + { + *adev = *adev+ae_fabs(x->ptr.p_double[i]-mean, _state); + } + *adev = *adev/(double)n; +} + + +/************************************************************************* +Median calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + Median + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemedian(/* Real */ const ae_vector* _x, + ae_int_t n, + double* median, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_int_t i; + ae_int_t ir; + ae_int_t j; + ae_int_t l; + ae_int_t midp; + ae_int_t k; + double a; + double tval; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + ae_vector_init_copy(&x, _x, _state, ae_true); + *median = 0.0; + + ae_assert(n>=0, "SampleMedian: N<0", _state); + ae_assert(x.cnt>=n, "SampleMedian: Length(X)=3. + * Choose X[(N-1)/2] + */ + l = 0; + ir = n-1; + k = (n-1)/2; + for(;;) + { + if( ir<=l+1 ) + { + + /* + * 1 or 2 elements in partition + */ + if( ir==l+1&&ae_fp_less(x.ptr.p_double[ir],x.ptr.p_double[l]) ) + { + tval = x.ptr.p_double[l]; + x.ptr.p_double[l] = x.ptr.p_double[ir]; + x.ptr.p_double[ir] = tval; + } + break; + } + else + { + midp = (l+ir)/2; + tval = x.ptr.p_double[midp]; + x.ptr.p_double[midp] = x.ptr.p_double[l+1]; + x.ptr.p_double[l+1] = tval; + if( ae_fp_greater(x.ptr.p_double[l],x.ptr.p_double[ir]) ) + { + tval = x.ptr.p_double[l]; + x.ptr.p_double[l] = x.ptr.p_double[ir]; + x.ptr.p_double[ir] = tval; + } + if( ae_fp_greater(x.ptr.p_double[l+1],x.ptr.p_double[ir]) ) + { + tval = x.ptr.p_double[l+1]; + x.ptr.p_double[l+1] = x.ptr.p_double[ir]; + x.ptr.p_double[ir] = tval; + } + if( ae_fp_greater(x.ptr.p_double[l],x.ptr.p_double[l+1]) ) + { + tval = x.ptr.p_double[l]; + x.ptr.p_double[l] = x.ptr.p_double[l+1]; + x.ptr.p_double[l+1] = tval; + } + i = l+1; + j = ir; + a = x.ptr.p_double[l+1]; + for(;;) + { + do + { + i = i+1; + } + while(ae_fp_less(x.ptr.p_double[i],a)); + do + { + j = j-1; + } + while(ae_fp_greater(x.ptr.p_double[j],a)); + if( j=k ) + { + ir = j-1; + } + if( j<=k ) + { + l = i; + } + } + } + + /* + * If N is odd, return result + */ + if( n%2==1 ) + { + *median = x.ptr.p_double[k]; + ae_frame_leave(_state); + return; + } + a = x.ptr.p_double[n-1]; + for(i=k+1; i<=n-1; i++) + { + if( ae_fp_less(x.ptr.p_double[i],a) ) + { + a = x.ptr.p_double[i]; + } + } + *median = 0.5*(x.ptr.p_double[k]+a); + ae_frame_leave(_state); +} + + +/************************************************************************* +Percentile calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + P - percentile (0<=P<=1) + +Output parameters: + V - percentile + + -- ALGLIB -- + Copyright 01.03.2008 by Bochkanov Sergey +*************************************************************************/ +void samplepercentile(/* Real */ const ae_vector* _x, + ae_int_t n, + double p, + double* v, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_int_t i1; + double t; + ae_vector rbuf; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&rbuf, 0, sizeof(rbuf)); + ae_vector_init_copy(&x, _x, _state, ae_true); + *v = 0.0; + ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "SamplePercentile: N<0", _state); + ae_assert(x.cnt>=n, "SamplePercentile: Length(X)=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + covariance (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double cov2(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double xmean; + double ymean; + double v; + double x0; + double y0; + double s; + ae_bool samex; + ae_bool samey; + double result; + + + ae_assert(n>=0, "Cov2: N<0", _state); + ae_assert(x->cnt>=n, "Cov2: Length(X)cnt>=n, "Cov2: Length(Y)ptr.p_double[0]; + y0 = y->ptr.p_double[0]; + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + s = x->ptr.p_double[i]; + samex = samex&&ae_fp_eq(s,x0); + xmean = xmean+s*v; + s = y->ptr.p_double[i]; + samey = samey&&ae_fp_eq(s,y0); + ymean = ymean+s*v; + } + if( samex||samey ) + { + result = (double)(0); + return result; + } + + /* + * covariance + */ + v = (double)1/(double)(n-1); + result = (double)(0); + for(i=0; i<=n-1; i++) + { + result = result+v*(x->ptr.p_double[i]-xmean)*(y->ptr.p_double[i]-ymean); + } + return result; +} + + +/************************************************************************* +Pearson product-moment correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Pearson product-moment correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double pearsoncorr2(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state) +{ + ae_int_t i; + double xmean; + double ymean; + double v; + double x0; + double y0; + double s; + ae_bool samex; + ae_bool samey; + double xv; + double yv; + double t1; + double t2; + double result; + + + ae_assert(n>=0, "PearsonCorr2: N<0", _state); + ae_assert(x->cnt>=n, "PearsonCorr2: Length(X)cnt>=n, "PearsonCorr2: Length(Y)ptr.p_double[0]; + y0 = y->ptr.p_double[0]; + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + s = x->ptr.p_double[i]; + samex = samex&&ae_fp_eq(s,x0); + xmean = xmean+s*v; + s = y->ptr.p_double[i]; + samey = samey&&ae_fp_eq(s,y0); + ymean = ymean+s*v; + } + if( samex||samey ) + { + result = (double)(0); + return result; + } + + /* + * numerator and denominator + */ + s = (double)(0); + xv = (double)(0); + yv = (double)(0); + for(i=0; i<=n-1; i++) + { + t1 = x->ptr.p_double[i]-xmean; + t2 = y->ptr.p_double[i]-ymean; + xv = xv+ae_sqr(t1, _state); + yv = yv+ae_sqr(t2, _state); + s = s+t1*t2; + } + if( ae_fp_eq(xv,(double)(0))||ae_fp_eq(yv,(double)(0)) ) + { + result = (double)(0); + } + else + { + result = s/(ae_sqrt(xv, _state)*ae_sqrt(yv, _state)); + } + return result; +} + + +/************************************************************************* +Spearman's rank correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Spearman's rank correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double spearmancorr2(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_vector y; + apbuffers buf; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&buf, 0, sizeof(buf)); + ae_vector_init_copy(&x, _x, _state, ae_true); + ae_vector_init_copy(&y, _y, _state, ae_true); + _apbuffers_init(&buf, _state, ae_true); + + ae_assert(n>=0, "SpearmanCorr2: N<0", _state); + ae_assert(x.cnt>=n, "SpearmanCorr2: Length(X)=n, "SpearmanCorr2: Length(Y)=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm(/* Real */ const ae_matrix* _x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix x; + ae_int_t i; + ae_int_t j; + double v; + ae_vector t; + ae_vector x0; + ae_vector same; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&t, 0, sizeof(t)); + memset(&x0, 0, sizeof(x0)); + memset(&same, 0, sizeof(same)); + ae_matrix_init_copy(&x, _x, _state, ae_true); + ae_matrix_clear(c); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&same, 0, DT_BOOL, _state, ae_true); + + ae_assert(n>=0, "CovM: N<0", _state); + ae_assert(m>=1, "CovM: M<1", _state); + ae_assert(x.rows>=n, "CovM: Rows(X)=m||n==0, "CovM: Cols(X)ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Calculate means, + * check for constant columns + */ + ae_vector_set_length(&t, m, _state); + ae_vector_set_length(&x0, m, _state); + ae_vector_set_length(&same, m, _state); + ae_matrix_set_length(c, m, m, _state); + for(i=0; i<=m-1; i++) + { + t.ptr.p_double[i] = (double)(0); + same.ptr.p_bool[i] = ae_true; + } + ae_v_move(&x0.ptr.p_double[0], 1, &x.ptr.pp_double[0][0], 1, ae_v_len(0,m-1)); + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + ae_v_addd(&t.ptr.p_double[0], 1, &x.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v); + for(j=0; j<=m-1; j++) + { + same.ptr.p_bool[j] = same.ptr.p_bool[j]&&ae_fp_eq(x.ptr.pp_double[i][j],x0.ptr.p_double[j]); + } + } + + /* + * * center variables; + * * if we have constant columns, these columns are + * artificially zeroed (they must be zero in exact arithmetics, + * but unfortunately floating point ops are not exact). + * * calculate upper half of symmetric covariance matrix + */ + for(i=0; i<=n-1; i++) + { + ae_v_sub(&x.ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m-1)); + for(j=0; j<=m-1; j++) + { + if( same.ptr.p_bool[j] ) + { + x.ptr.pp_double[i][j] = (double)(0); + } + } + } + rmatrixsyrk(m, n, (double)1/(double)(n-1), &x, 0, 0, 1, 0.0, c, 0, 0, ae_true, _state); + rmatrixenforcesymmetricity(c, m, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Pearson product-moment correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector t; + ae_int_t i; + ae_int_t j; + double v; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + ae_matrix_clear(c); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "PearsonCorrM: N<0", _state); + ae_assert(m>=1, "PearsonCorrM: M<1", _state); + ae_assert(x->rows>=n, "PearsonCorrM: Rows(X)cols>=m||n==0, "PearsonCorrM: Cols(X)ptr.pp_double[i][i],(double)(0)) ) + { + t.ptr.p_double[i] = (double)1/ae_sqrt(c->ptr.pp_double[i][i], _state); + } + else + { + t.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m-1; i++) + { + v = t.ptr.p_double[i]; + for(j=0; j<=m-1; j++) + { + c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Spearman's rank correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + apbuffers buf; + ae_matrix xc; + ae_vector t; + double v; + double vv; + double x0; + ae_bool b; + + ae_frame_make(_state, &_frame_block); + memset(&buf, 0, sizeof(buf)); + memset(&xc, 0, sizeof(xc)); + memset(&t, 0, sizeof(t)); + ae_matrix_clear(c); + _apbuffers_init(&buf, _state, ae_true); + ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + + ae_assert(n>=0, "SpearmanCorrM: N<0", _state); + ae_assert(m>=1, "SpearmanCorrM: M<1", _state); + ae_assert(x->rows>=n, "SpearmanCorrM: Rows(X)cols>=m||n==0, "SpearmanCorrM: Cols(X)ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Allocate + */ + ae_vector_set_length(&t, ae_maxint(n, m, _state), _state); + ae_matrix_set_length(c, m, m, _state); + + /* + * Replace data with ranks + */ + ae_matrix_set_length(&xc, m, n, _state); + rmatrixtranspose(n, m, x, 0, 0, &xc, 0, 0, _state); + rankdata(&xc, m, n, _state); + + /* + * 1. Calculate means, check for constant columns + * 2. Center variables, constant columns are + * artificialy zeroed (they must be zero in exact arithmetics, + * but unfortunately floating point is not exact). + */ + for(i=0; i<=m-1; i++) + { + + /* + * Calculate: + * * V - mean value of I-th variable + * * B - True in case all variable values are same + */ + v = (double)(0); + b = ae_true; + x0 = xc.ptr.pp_double[i][0]; + for(j=0; j<=n-1; j++) + { + vv = xc.ptr.pp_double[i][j]; + v = v+vv; + b = b&&ae_fp_eq(vv,x0); + } + v = v/(double)n; + + /* + * Center/zero I-th variable + */ + if( b ) + { + + /* + * Zero + */ + for(j=0; j<=n-1; j++) + { + xc.ptr.pp_double[i][j] = 0.0; + } + } + else + { + + /* + * Center + */ + for(j=0; j<=n-1; j++) + { + xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j]-v; + } + } + } + + /* + * Calculate upper half of symmetric covariance matrix + */ + rmatrixsyrk(m, n, (double)1/(double)(n-1), &xc, 0, 0, 0, 0.0, c, 0, 0, ae_true, _state); + + /* + * Calculate Pearson coefficients (upper triangle) + */ + for(i=0; i<=m-1; i++) + { + if( ae_fp_greater(c->ptr.pp_double[i][i],(double)(0)) ) + { + t.ptr.p_double[i] = (double)1/ae_sqrt(c->ptr.pp_double[i][i], _state); + } + else + { + t.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m-1; i++) + { + v = t.ptr.p_double[i]; + for(j=i; j<=m-1; j++) + { + c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*t.ptr.p_double[j]; + } + } + + /* + * force symmetricity + */ + rmatrixenforcesymmetricity(c, m, ae_true, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Cross-covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm2(/* Real */ const ae_matrix* _x, + /* Real */ const ae_matrix* _y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix x; + ae_matrix y; + ae_int_t i; + ae_int_t j; + double v; + ae_vector t; + ae_vector x0; + ae_vector y0; + ae_vector samex; + ae_vector samey; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&t, 0, sizeof(t)); + memset(&x0, 0, sizeof(x0)); + memset(&y0, 0, sizeof(y0)); + memset(&samex, 0, sizeof(samex)); + memset(&samey, 0, sizeof(samey)); + ae_matrix_init_copy(&x, _x, _state, ae_true); + ae_matrix_init_copy(&y, _y, _state, ae_true); + ae_matrix_clear(c); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&samex, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&samey, 0, DT_BOOL, _state, ae_true); + + ae_assert(n>=0, "CovM2: N<0", _state); + ae_assert(m1>=1, "CovM2: M1<1", _state); + ae_assert(m2>=1, "CovM2: M2<1", _state); + ae_assert(x.rows>=n, "CovM2: Rows(X)=m1||n==0, "CovM2: Cols(X)=n, "CovM2: Rows(Y)=m2||n==0, "CovM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Allocate + */ + ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); + ae_vector_set_length(&x0, m1, _state); + ae_vector_set_length(&y0, m2, _state); + ae_vector_set_length(&samex, m1, _state); + ae_vector_set_length(&samey, m2, _state); + ae_matrix_set_length(c, m1, m2, _state); + + /* + * * calculate means of X + * * center X + * * if we have constant columns, these columns are + * artificially zeroed (they must be zero in exact arithmetics, + * but unfortunately floating point ops are not exact). + */ + for(i=0; i<=m1-1; i++) + { + t.ptr.p_double[i] = (double)(0); + samex.ptr.p_bool[i] = ae_true; + } + ae_v_move(&x0.ptr.p_double[0], 1, &x.ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + ae_v_addd(&t.ptr.p_double[0], 1, &x.ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); + for(j=0; j<=m1-1; j++) + { + samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x.ptr.pp_double[i][j],x0.ptr.p_double[j]); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_sub(&x.ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); + for(j=0; j<=m1-1; j++) + { + if( samex.ptr.p_bool[j] ) + { + x.ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * Repeat same steps for Y + */ + for(i=0; i<=m2-1; i++) + { + t.ptr.p_double[i] = (double)(0); + samey.ptr.p_bool[i] = ae_true; + } + ae_v_move(&y0.ptr.p_double[0], 1, &y.ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + ae_v_addd(&t.ptr.p_double[0], 1, &y.ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); + for(j=0; j<=m2-1; j++) + { + samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y.ptr.pp_double[i][j],y0.ptr.p_double[j]); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_sub(&y.ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); + for(j=0; j<=m2-1; j++) + { + if( samey.ptr.p_bool[j] ) + { + y.ptr.pp_double[i][j] = (double)(0); + } + } + } + + /* + * calculate cross-covariance matrix + */ + rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), &x, 0, 0, 1, &y, 0, 0, 0, 0.0, c, 0, 0, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Pearson product-moment cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm2(/* Real */ const ae_matrix* _x, + /* Real */ const ae_matrix* _y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_matrix x; + ae_matrix y; + ae_int_t i; + ae_int_t j; + double v; + ae_vector t; + ae_vector x0; + ae_vector y0; + ae_vector sx; + ae_vector sy; + ae_vector samex; + ae_vector samey; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&y, 0, sizeof(y)); + memset(&t, 0, sizeof(t)); + memset(&x0, 0, sizeof(x0)); + memset(&y0, 0, sizeof(y0)); + memset(&sx, 0, sizeof(sx)); + memset(&sy, 0, sizeof(sy)); + memset(&samex, 0, sizeof(samex)); + memset(&samey, 0, sizeof(samey)); + ae_matrix_init_copy(&x, _x, _state, ae_true); + ae_matrix_init_copy(&y, _y, _state, ae_true); + ae_matrix_clear(c); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&x0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&y0, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); + ae_vector_init(&samex, 0, DT_BOOL, _state, ae_true); + ae_vector_init(&samey, 0, DT_BOOL, _state, ae_true); + + ae_assert(n>=0, "PearsonCorrM2: N<0", _state); + ae_assert(m1>=1, "PearsonCorrM2: M1<1", _state); + ae_assert(m2>=1, "PearsonCorrM2: M2<1", _state); + ae_assert(x.rows>=n, "PearsonCorrM2: Rows(X)=m1||n==0, "PearsonCorrM2: Cols(X)=n, "PearsonCorrM2: Rows(Y)=m2||n==0, "PearsonCorrM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Allocate + */ + ae_vector_set_length(&t, ae_maxint(m1, m2, _state), _state); + ae_vector_set_length(&x0, m1, _state); + ae_vector_set_length(&y0, m2, _state); + ae_vector_set_length(&sx, m1, _state); + ae_vector_set_length(&sy, m2, _state); + ae_vector_set_length(&samex, m1, _state); + ae_vector_set_length(&samey, m2, _state); + ae_matrix_set_length(c, m1, m2, _state); + + /* + * * calculate means of X + * * center X + * * if we have constant columns, these columns are + * artificially zeroed (they must be zero in exact arithmetics, + * but unfortunately floating point ops are not exact). + * * calculate column variances + */ + for(i=0; i<=m1-1; i++) + { + t.ptr.p_double[i] = (double)(0); + samex.ptr.p_bool[i] = ae_true; + sx.ptr.p_double[i] = (double)(0); + } + ae_v_move(&x0.ptr.p_double[0], 1, &x.ptr.pp_double[0][0], 1, ae_v_len(0,m1-1)); + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + ae_v_addd(&t.ptr.p_double[0], 1, &x.ptr.pp_double[i][0], 1, ae_v_len(0,m1-1), v); + for(j=0; j<=m1-1; j++) + { + samex.ptr.p_bool[j] = samex.ptr.p_bool[j]&&ae_fp_eq(x.ptr.pp_double[i][j],x0.ptr.p_double[j]); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_sub(&x.ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m1-1)); + for(j=0; j<=m1-1; j++) + { + if( samex.ptr.p_bool[j] ) + { + x.ptr.pp_double[i][j] = (double)(0); + } + sx.ptr.p_double[j] = sx.ptr.p_double[j]+x.ptr.pp_double[i][j]*x.ptr.pp_double[i][j]; + } + } + for(j=0; j<=m1-1; j++) + { + sx.ptr.p_double[j] = ae_sqrt(sx.ptr.p_double[j]/(double)(n-1), _state); + } + + /* + * Repeat same steps for Y + */ + for(i=0; i<=m2-1; i++) + { + t.ptr.p_double[i] = (double)(0); + samey.ptr.p_bool[i] = ae_true; + sy.ptr.p_double[i] = (double)(0); + } + ae_v_move(&y0.ptr.p_double[0], 1, &y.ptr.pp_double[0][0], 1, ae_v_len(0,m2-1)); + v = (double)1/(double)n; + for(i=0; i<=n-1; i++) + { + ae_v_addd(&t.ptr.p_double[0], 1, &y.ptr.pp_double[i][0], 1, ae_v_len(0,m2-1), v); + for(j=0; j<=m2-1; j++) + { + samey.ptr.p_bool[j] = samey.ptr.p_bool[j]&&ae_fp_eq(y.ptr.pp_double[i][j],y0.ptr.p_double[j]); + } + } + for(i=0; i<=n-1; i++) + { + ae_v_sub(&y.ptr.pp_double[i][0], 1, &t.ptr.p_double[0], 1, ae_v_len(0,m2-1)); + for(j=0; j<=m2-1; j++) + { + if( samey.ptr.p_bool[j] ) + { + y.ptr.pp_double[i][j] = (double)(0); + } + sy.ptr.p_double[j] = sy.ptr.p_double[j]+y.ptr.pp_double[i][j]*y.ptr.pp_double[i][j]; + } + } + for(j=0; j<=m2-1; j++) + { + sy.ptr.p_double[j] = ae_sqrt(sy.ptr.p_double[j]/(double)(n-1), _state); + } + + /* + * calculate cross-covariance matrix + */ + rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), &x, 0, 0, 1, &y, 0, 0, 0, 0.0, c, 0, 0, _state); + + /* + * Divide by standard deviations + */ + for(i=0; i<=m1-1; i++) + { + if( ae_fp_neq(sx.ptr.p_double[i],(double)(0)) ) + { + sx.ptr.p_double[i] = (double)1/sx.ptr.p_double[i]; + } + else + { + sx.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m2-1; i++) + { + if( ae_fp_neq(sy.ptr.p_double[i],(double)(0)) ) + { + sy.ptr.p_double[i] = (double)1/sy.ptr.p_double[i]; + } + else + { + sy.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m1-1; i++) + { + v = sx.ptr.p_double[i]; + for(j=0; j<=m2-1; j++) + { + c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Spearman's rank cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm2(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + double v; + double v2; + double vv; + ae_bool b; + ae_vector t; + double x0; + double y0; + ae_vector sx; + ae_vector sy; + ae_matrix xc; + ae_matrix yc; + apbuffers buf; + + ae_frame_make(_state, &_frame_block); + memset(&t, 0, sizeof(t)); + memset(&sx, 0, sizeof(sx)); + memset(&sy, 0, sizeof(sy)); + memset(&xc, 0, sizeof(xc)); + memset(&yc, 0, sizeof(yc)); + memset(&buf, 0, sizeof(buf)); + ae_matrix_clear(c); + ae_vector_init(&t, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&sy, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&yc, 0, 0, DT_REAL, _state, ae_true); + _apbuffers_init(&buf, _state, ae_true); + + ae_assert(n>=0, "SpearmanCorrM2: N<0", _state); + ae_assert(m1>=1, "SpearmanCorrM2: M1<1", _state); + ae_assert(m2>=1, "SpearmanCorrM2: M2<1", _state); + ae_assert(x->rows>=n, "SpearmanCorrM2: Rows(X)cols>=m1||n==0, "SpearmanCorrM2: Cols(X)rows>=n, "SpearmanCorrM2: Rows(Y)cols>=m2||n==0, "SpearmanCorrM2: Cols(Y)ptr.pp_double[i][j] = (double)(0); + } + } + ae_frame_leave(_state); + return; + } + + /* + * Allocate + */ + ae_vector_set_length(&t, ae_maxint(ae_maxint(m1, m2, _state), n, _state), _state); + ae_vector_set_length(&sx, m1, _state); + ae_vector_set_length(&sy, m2, _state); + ae_matrix_set_length(c, m1, m2, _state); + + /* + * Replace data with ranks + */ + ae_matrix_set_length(&xc, m1, n, _state); + ae_matrix_set_length(&yc, m2, n, _state); + rmatrixtranspose(n, m1, x, 0, 0, &xc, 0, 0, _state); + rmatrixtranspose(n, m2, y, 0, 0, &yc, 0, 0, _state); + rankdata(&xc, m1, n, _state); + rankdata(&yc, m2, n, _state); + + /* + * 1. Calculate means, variances, check for constant columns + * 2. Center variables, constant columns are + * artificialy zeroed (they must be zero in exact arithmetics, + * but unfortunately floating point is not exact). + * + * Description of variables: + * * V - mean value of I-th variable + * * V2- variance + * * VV-temporary + * * B - True in case all variable values are same + */ + for(i=0; i<=m1-1; i++) + { + v = (double)(0); + v2 = 0.0; + b = ae_true; + x0 = xc.ptr.pp_double[i][0]; + for(j=0; j<=n-1; j++) + { + vv = xc.ptr.pp_double[i][j]; + v = v+vv; + b = b&&ae_fp_eq(vv,x0); + } + v = v/(double)n; + if( b ) + { + for(j=0; j<=n-1; j++) + { + xc.ptr.pp_double[i][j] = 0.0; + } + } + else + { + for(j=0; j<=n-1; j++) + { + vv = xc.ptr.pp_double[i][j]; + xc.ptr.pp_double[i][j] = vv-v; + v2 = v2+(vv-v)*(vv-v); + } + } + sx.ptr.p_double[i] = ae_sqrt(v2/(double)(n-1), _state); + } + for(i=0; i<=m2-1; i++) + { + v = (double)(0); + v2 = 0.0; + b = ae_true; + y0 = yc.ptr.pp_double[i][0]; + for(j=0; j<=n-1; j++) + { + vv = yc.ptr.pp_double[i][j]; + v = v+vv; + b = b&&ae_fp_eq(vv,y0); + } + v = v/(double)n; + if( b ) + { + for(j=0; j<=n-1; j++) + { + yc.ptr.pp_double[i][j] = 0.0; + } + } + else + { + for(j=0; j<=n-1; j++) + { + vv = yc.ptr.pp_double[i][j]; + yc.ptr.pp_double[i][j] = vv-v; + v2 = v2+(vv-v)*(vv-v); + } + } + sy.ptr.p_double[i] = ae_sqrt(v2/(double)(n-1), _state); + } + + /* + * calculate cross-covariance matrix + */ + rmatrixgemm(m1, m2, n, (double)1/(double)(n-1), &xc, 0, 0, 0, &yc, 0, 0, 1, 0.0, c, 0, 0, _state); + + /* + * Divide by standard deviations + */ + for(i=0; i<=m1-1; i++) + { + if( ae_fp_neq(sx.ptr.p_double[i],(double)(0)) ) + { + sx.ptr.p_double[i] = (double)1/sx.ptr.p_double[i]; + } + else + { + sx.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m2-1; i++) + { + if( ae_fp_neq(sy.ptr.p_double[i],(double)(0)) ) + { + sy.ptr.p_double[i] = (double)1/sy.ptr.p_double[i]; + } + else + { + sy.ptr.p_double[i] = 0.0; + } + } + for(i=0; i<=m1-1; i++) + { + v = sx.ptr.p_double[i]; + for(j=0; j<=m2-1; j++) + { + c->ptr.pp_double[i][j] = c->ptr.pp_double[i][j]*v*sy.ptr.p_double[j]; + } + } + ae_frame_leave(_state); +} + + +/************************************************************************* +This function replaces data in XY by their ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* ranking starts from 0, ends at NFeatures-1 +* sum of within-row values is equal to (NFeatures-1)*NFeatures/2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +void rankdata(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_state *_state) +{ + ae_frame _frame_block; + apbuffers buf0; + apbuffers buf1; + ae_int_t basecasecost; + ae_shared_pool pool; + + ae_frame_make(_state, &_frame_block); + memset(&buf0, 0, sizeof(buf0)); + memset(&buf1, 0, sizeof(buf1)); + memset(&pool, 0, sizeof(pool)); + _apbuffers_init(&buf0, _state, ae_true); + _apbuffers_init(&buf1, _state, ae_true); + ae_shared_pool_init(&pool, _state, ae_true); + + ae_assert(npoints>=0, "RankData: NPoints<0", _state); + ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); + ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=0, "RankData: NPoints<0", _state); + ae_assert(nfeatures>=1, "RankData: NFeatures<1", _state); + ae_assert(xy->rows>=npoints, "RankData: Rows(XY)cols>=nfeatures||npoints==0, "RankData: Cols(XY)=i0, "RankDataRec: internal error", _state); + + /* + * Try to activate parallelism + */ + if( i1-i0>=4&&ae_fp_greater_eq(rmul3((double)(i1-i0), (double)(nfeatures), logbase2((double)(nfeatures), _state), _state),smpactivationlevel(_state)) ) + { + if( _trypexec_basestat_rankdatarec(xy,i0,i1,nfeatures,iscentered,pool,basecasecost, _state) ) + { + ae_frame_leave(_state); + return; + } + } + + /* + * Recursively split problem, if it is too large + */ + problemcost = rmul3((double)(i1-i0), (double)(nfeatures), logbase2((double)(nfeatures), _state), _state); + if( i1-i0>=2&&ae_fp_greater(problemcost,spawnlevel(_state)) ) + { + im = (i1+i0)/2; + basestat_rankdatarec(xy, i0, im, nfeatures, iscentered, pool, basecasecost, _state); + basestat_rankdatarec(xy, im, i1, nfeatures, iscentered, pool, basecasecost, _state); + ae_frame_leave(_state); + return; + } + + /* + * Retrieve buffers from pool, call serial code, return buffers to pool + */ + ae_shared_pool_retrieve(pool, &_buf0, _state); + ae_shared_pool_retrieve(pool, &_buf1, _state); + basestat_rankdatabasecase(xy, i0, i1, nfeatures, iscentered, buf0, buf1, _state); + ae_shared_pool_recycle(pool, &_buf0, _state); + ae_shared_pool_recycle(pool, &_buf1, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_basestat_rankdatarec(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + ae_shared_pool* pool, + ae_int_t basecasecost, + ae_state *_state) +{ + return ae_false; +} + + +/************************************************************************* +Basecase code for RankData(), performs actual work on subset of data using +temporary buffer passed as parameter. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + I0 - index of first row to process + I1 - index of past-the-last row to process; + this function processes half-interval [I0,I1). + NFeatures- number of features + IsCentered- whether ranks are centered or not: + * True - ranks are centered in such way that their + within-row sum is zero + * False - ranks are not centered + Buf0 - temporary buffers, may be empty (this function automatically + allocates/reuses buffers). + Buf1 - temporary buffers, may be empty (this function automatically + allocates/reuses buffers). + +OUTPUT PARAMETERS: + XY - data in [I0,I1) are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +static void basestat_rankdatabasecase(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + apbuffers* buf0, + apbuffers* buf1, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(i1>=i0, "RankDataBasecase: internal error", _state); + if( buf1->ra0.cntra0, nfeatures, _state); + } + for(i=i0; i<=i1-1; i++) + { + ae_v_move(&buf1->ra0.ptr.p_double[0], 1, &xy->ptr.pp_double[i][0], 1, ae_v_len(0,nfeatures-1)); + rankx(&buf1->ra0, nfeatures, iscentered, buf0, _state); + ae_v_move(&xy->ptr.pp_double[i][0], 1, &buf1->ra0.ptr.p_double[0], 1, ae_v_len(0,nfeatures-1)); + } +} + + +/************************************************************************* +Serial stub for GPL edition. +*************************************************************************/ +ae_bool _trypexec_basestat_rankdatabasecase(/* Real */ ae_matrix* xy, + ae_int_t i0, + ae_int_t i1, + ae_int_t nfeatures, + ae_bool iscentered, + apbuffers* buf0, + apbuffers* buf1, + ae_state *_state) +{ + return ae_false; +} + + +#endif +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Pearson's correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5 + * normality of distributions of X and Y. + +Input parameters: + R - Pearson's correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrelationsignificance(double r, + ae_int_t n, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + double t; + double p; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + + /* + * Some special cases + */ + if( ae_fp_greater_eq(r,(double)(1)) ) + { + *bothtails = 0.0; + *lefttail = 1.0; + *righttail = 0.0; + return; + } + if( ae_fp_less_eq(r,(double)(-1)) ) + { + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 1.0; + return; + } + if( n<5 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * General case + */ + t = r*ae_sqrt((double)(n-2)/((double)1-ae_sqr(r, _state)), _state); + p = studenttdistribution(n-2, t, _state); + *bothtails = (double)2*ae_minreal(p, (double)1-p, _state); + *lefttail = p; + *righttail = (double)1-p; +} + + +/************************************************************************* +Spearman's rank correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5. + +The test is non-parametric and doesn't require distributions X and Y to be +normal. + +Input parameters: + R - Spearman's rank correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void spearmanrankcorrelationsignificance(double r, + ae_int_t n, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + double t; + double p; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + + /* + * Special case + */ + if( n<5 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * General case + */ + if( ae_fp_greater_eq(r,(double)(1)) ) + { + t = 1.0E10; + } + else + { + if( ae_fp_less_eq(r,(double)(-1)) ) + { + t = -1.0E10; + } + else + { + t = r*ae_sqrt((double)(n-2)/((double)1-ae_sqr(r, _state)), _state); + } + } + if( ae_fp_less(t,(double)(0)) ) + { + p = correlationtests_spearmantail(t, n, _state); + *bothtails = (double)2*p; + *lefttail = p; + *righttail = (double)1-p; + } + else + { + p = correlationtests_spearmantail(-t, n, _state); + *bothtails = (double)2*p; + *lefttail = (double)1-p; + *righttail = p; + } +} + + +/************************************************************************* +Tail(S, 5) +*************************************************************************/ +static double correlationtests_spearmantail5(double s, ae_state *_state) +{ + double result; + + + if( ae_fp_less(s,0.000e+00) ) + { + result = studenttdistribution(3, -s, _state); + return result; + } + if( ae_fp_greater_eq(s,3.580e+00) ) + { + result = 8.304e-03; + return result; + } + if( ae_fp_greater_eq(s,2.322e+00) ) + { + result = 4.163e-02; + return result; + } + if( ae_fp_greater_eq(s,1.704e+00) ) + { + result = 6.641e-02; + return result; + } + if( ae_fp_greater_eq(s,1.303e+00) ) + { + result = 1.164e-01; + return result; + } + if( ae_fp_greater_eq(s,1.003e+00) ) + { + result = 1.748e-01; + return result; + } + if( ae_fp_greater_eq(s,7.584e-01) ) + { + result = 2.249e-01; + return result; + } + if( ae_fp_greater_eq(s,5.468e-01) ) + { + result = 2.581e-01; + return result; + } + if( ae_fp_greater_eq(s,3.555e-01) ) + { + result = 3.413e-01; + return result; + } + if( ae_fp_greater_eq(s,1.759e-01) ) + { + result = 3.911e-01; + return result; + } + if( ae_fp_greater_eq(s,1.741e-03) ) + { + result = 4.747e-01; + return result; + } + if( ae_fp_greater_eq(s,0.000e+00) ) + { + result = 5.248e-01; + return result; + } + result = (double)(0); + return result; +} + + +/************************************************************************* +Tail(S, 6) +*************************************************************************/ +static double correlationtests_spearmantail6(double s, ae_state *_state) +{ + double result; + + + if( ae_fp_less(s,1.001e+00) ) + { + result = studenttdistribution(4, -s, _state); + return result; + } + if( ae_fp_greater_eq(s,5.663e+00) ) + { + result = 1.366e-03; + return result; + } + if( ae_fp_greater_eq(s,3.834e+00) ) + { + result = 8.350e-03; + return result; + } + if( ae_fp_greater_eq(s,2.968e+00) ) + { + result = 1.668e-02; + return result; + } + if( ae_fp_greater_eq(s,2.430e+00) ) + { + result = 2.921e-02; + return result; + } + if( ae_fp_greater_eq(s,2.045e+00) ) + { + result = 5.144e-02; + return result; + } + if( ae_fp_greater_eq(s,1.747e+00) ) + { + result = 6.797e-02; + return result; + } + if( ae_fp_greater_eq(s,1.502e+00) ) + { + result = 8.752e-02; + return result; + } + if( ae_fp_greater_eq(s,1.295e+00) ) + { + result = 1.210e-01; + return result; + } + if( ae_fp_greater_eq(s,1.113e+00) ) + { + result = 1.487e-01; + return result; + } + if( ae_fp_greater_eq(s,1.001e+00) ) + { + result = 1.780e-01; + return result; + } + result = (double)(0); + return result; +} + + +/************************************************************************* +Tail(S, 7) +*************************************************************************/ +static double correlationtests_spearmantail7(double s, ae_state *_state) +{ + double result; + + + if( ae_fp_less(s,1.001e+00) ) + { + result = studenttdistribution(5, -s, _state); + return result; + } + if( ae_fp_greater_eq(s,8.159e+00) ) + { + result = 2.081e-04; + return result; + } + if( ae_fp_greater_eq(s,5.620e+00) ) + { + result = 1.393e-03; + return result; + } + if( ae_fp_greater_eq(s,4.445e+00) ) + { + result = 3.398e-03; + return result; + } + if( ae_fp_greater_eq(s,3.728e+00) ) + { + result = 6.187e-03; + return result; + } + if( ae_fp_greater_eq(s,3.226e+00) ) + { + result = 1.200e-02; + return result; + } + if( ae_fp_greater_eq(s,2.844e+00) ) + { + result = 1.712e-02; + return result; + } + if( ae_fp_greater_eq(s,2.539e+00) ) + { + result = 2.408e-02; + return result; + } + if( ae_fp_greater_eq(s,2.285e+00) ) + { + result = 3.320e-02; + return result; + } + if( ae_fp_greater_eq(s,2.068e+00) ) + { + result = 4.406e-02; + return result; + } + if( ae_fp_greater_eq(s,1.879e+00) ) + { + result = 5.478e-02; + return result; + } + if( ae_fp_greater_eq(s,1.710e+00) ) + { + result = 6.946e-02; + return result; + } + if( ae_fp_greater_eq(s,1.559e+00) ) + { + result = 8.331e-02; + return result; + } + if( ae_fp_greater_eq(s,1.420e+00) ) + { + result = 1.001e-01; + return result; + } + if( ae_fp_greater_eq(s,1.292e+00) ) + { + result = 1.180e-01; + return result; + } + if( ae_fp_greater_eq(s,1.173e+00) ) + { + result = 1.335e-01; + return result; + } + if( ae_fp_greater_eq(s,1.062e+00) ) + { + result = 1.513e-01; + return result; + } + if( ae_fp_greater_eq(s,1.001e+00) ) + { + result = 1.770e-01; + return result; + } + result = (double)(0); + return result; +} + + +/************************************************************************* +Tail(S, 8) +*************************************************************************/ +static double correlationtests_spearmantail8(double s, ae_state *_state) +{ + double result; + + + if( ae_fp_less(s,2.001e+00) ) + { + result = studenttdistribution(6, -s, _state); + return result; + } + if( ae_fp_greater_eq(s,1.103e+01) ) + { + result = 2.194e-05; + return result; + } + if( ae_fp_greater_eq(s,7.685e+00) ) + { + result = 2.008e-04; + return result; + } + if( ae_fp_greater_eq(s,6.143e+00) ) + { + result = 5.686e-04; + return result; + } + if( ae_fp_greater_eq(s,5.213e+00) ) + { + result = 1.138e-03; + return result; + } + if( ae_fp_greater_eq(s,4.567e+00) ) + { + result = 2.310e-03; + return result; + } + if( ae_fp_greater_eq(s,4.081e+00) ) + { + result = 3.634e-03; + return result; + } + if( ae_fp_greater_eq(s,3.697e+00) ) + { + result = 5.369e-03; + return result; + } + if( ae_fp_greater_eq(s,3.381e+00) ) + { + result = 7.708e-03; + return result; + } + if( ae_fp_greater_eq(s,3.114e+00) ) + { + result = 1.087e-02; + return result; + } + if( ae_fp_greater_eq(s,2.884e+00) ) + { + result = 1.397e-02; + return result; + } + if( ae_fp_greater_eq(s,2.682e+00) ) + { + result = 1.838e-02; + return result; + } + if( ae_fp_greater_eq(s,2.502e+00) ) + { + result = 2.288e-02; + return result; + } + if( ae_fp_greater_eq(s,2.340e+00) ) + { + result = 2.883e-02; + return result; + } + if( ae_fp_greater_eq(s,2.192e+00) ) + { + result = 3.469e-02; + return result; + } + if( ae_fp_greater_eq(s,2.057e+00) ) + { + result = 4.144e-02; + return result; + } + if( ae_fp_greater_eq(s,2.001e+00) ) + { + result = 4.804e-02; + return result; + } + result = (double)(0); + return result; +} + + +/************************************************************************* +Tail(S, 9) +*************************************************************************/ +static double correlationtests_spearmantail9(double s, ae_state *_state) +{ + double result; + + + if( ae_fp_less(s,2.001e+00) ) + { + result = studenttdistribution(7, -s, _state); + return result; + } + if( ae_fp_greater_eq(s,9.989e+00) ) + { + result = 2.306e-05; + return result; + } + if( ae_fp_greater_eq(s,8.069e+00) ) + { + result = 8.167e-05; + return result; + } + if( ae_fp_greater_eq(s,6.890e+00) ) + { + result = 1.744e-04; + return result; + } + if( ae_fp_greater_eq(s,6.077e+00) ) + { + result = 3.625e-04; + return result; + } + if( ae_fp_greater_eq(s,5.469e+00) ) + { + result = 6.450e-04; + return result; + } + if( ae_fp_greater_eq(s,4.991e+00) ) + { + result = 1.001e-03; + return result; + } + if( ae_fp_greater_eq(s,4.600e+00) ) + { + result = 1.514e-03; + return result; + } + if( ae_fp_greater_eq(s,4.272e+00) ) + { + result = 2.213e-03; + return result; + } + if( ae_fp_greater_eq(s,3.991e+00) ) + { + result = 2.990e-03; + return result; + } + if( ae_fp_greater_eq(s,3.746e+00) ) + { + result = 4.101e-03; + return result; + } + if( ae_fp_greater_eq(s,3.530e+00) ) + { + result = 5.355e-03; + return result; + } + if( ae_fp_greater_eq(s,3.336e+00) ) + { + result = 6.887e-03; + return result; + } + if( ae_fp_greater_eq(s,3.161e+00) ) + { + result = 8.598e-03; + return result; + } + if( ae_fp_greater_eq(s,3.002e+00) ) + { + result = 1.065e-02; + return result; + } + if( ae_fp_greater_eq(s,2.855e+00) ) + { + result = 1.268e-02; + return result; + } + if( ae_fp_greater_eq(s,2.720e+00) ) + { + result = 1.552e-02; + return result; + } + if( ae_fp_greater_eq(s,2.595e+00) ) + { + result = 1.836e-02; + return result; + } + if( ae_fp_greater_eq(s,2.477e+00) ) + { + result = 2.158e-02; + return result; + } + if( ae_fp_greater_eq(s,2.368e+00) ) + { + result = 2.512e-02; + return result; + } + if( ae_fp_greater_eq(s,2.264e+00) ) + { + result = 2.942e-02; + return result; + } + if( ae_fp_greater_eq(s,2.166e+00) ) + { + result = 3.325e-02; + return result; + } + if( ae_fp_greater_eq(s,2.073e+00) ) + { + result = 3.800e-02; + return result; + } + if( ae_fp_greater_eq(s,2.001e+00) ) + { + result = 4.285e-02; + return result; + } + result = (double)(0); + return result; +} + + +/************************************************************************* +Tail(T,N), accepts T<0 +*************************************************************************/ +static double correlationtests_spearmantail(double t, + ae_int_t n, + ae_state *_state) +{ + double result; + + + if( n==5 ) + { + result = correlationtests_spearmantail5(-t, _state); + return result; + } + if( n==6 ) + { + result = correlationtests_spearmantail6(-t, _state); + return result; + } + if( n==7 ) + { + result = correlationtests_spearmantail7(-t, _state); + return result; + } + if( n==8 ) + { + result = correlationtests_spearmantail8(-t, _state); + return result; + } + if( n==9 ) + { + result = correlationtests_spearmantail9(-t, _state); + return result; + } + result = studenttdistribution(n-2, t, _state); + return result; +} + + +#endif +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Jarque-Bera test + +This test checks hypotheses about the fact that a given sample X is a +sample of normal random variable. + +Requirements: + * the number of elements in the sample is not less than 5. + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. N>=5 + +Output parameters: + P - p-value for the test + +Accuracy of the approximation used (5<=N<=1951): + +p-value relative error (5<=N<=1951) +[1, 0.1] < 1% +[0.1, 0.01] < 2% +[0.01, 0.001] < 6% +[0.001, 0] wasn't measured + +For N>1951 accuracy wasn't measured but it shouldn't be sharply different +from table values. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void jarqueberatest(/* Real */ const ae_vector* x, + ae_int_t n, + double* p, + ae_state *_state) +{ + double s; + + *p = 0.0; + + + /* + * N is too small + */ + if( n<5 ) + { + *p = 1.0; + return; + } + + /* + * N is large enough + */ + jarquebera_jarqueberastatistic(x, n, &s, _state); + *p = jarquebera_jarqueberaapprox(n, s, _state); +} + + +static void jarquebera_jarqueberastatistic(/* Real */ const ae_vector* x, + ae_int_t n, + double* s, + ae_state *_state) +{ + ae_int_t i; + double v; + double v1; + double v2; + double stddev; + double mean; + double variance; + double skewness; + double kurtosis; + + *s = 0.0; + + mean = (double)(0); + variance = (double)(0); + skewness = (double)(0); + kurtosis = (double)(0); + stddev = (double)(0); + ae_assert(n>1, "Assertion failed", _state); + + /* + * Mean + */ + for(i=0; i<=n-1; i++) + { + mean = mean+x->ptr.p_double[i]; + } + mean = mean/(double)n; + + /* + * Variance (using corrected two-pass algorithm) + */ + if( n!=1 ) + { + v1 = (double)(0); + for(i=0; i<=n-1; i++) + { + v1 = v1+ae_sqr(x->ptr.p_double[i]-mean, _state); + } + v2 = (double)(0); + for(i=0; i<=n-1; i++) + { + v2 = v2+(x->ptr.p_double[i]-mean); + } + v2 = ae_sqr(v2, _state)/(double)n; + variance = (v1-v2)/(double)(n-1); + if( ae_fp_less(variance,(double)(0)) ) + { + variance = (double)(0); + } + stddev = ae_sqrt(variance, _state); + } + + /* + * Skewness and kurtosis + */ + if( ae_fp_neq(stddev,(double)(0)) ) + { + for(i=0; i<=n-1; i++) + { + v = (x->ptr.p_double[i]-mean)/stddev; + v2 = ae_sqr(v, _state); + skewness = skewness+v2*v; + kurtosis = kurtosis+ae_sqr(v2, _state); + } + skewness = skewness/(double)n; + kurtosis = kurtosis/(double)n-(double)3; + } + + /* + * Statistic + */ + *s = (double)n/(double)6*(ae_sqr(skewness, _state)+ae_sqr(kurtosis, _state)/(double)4); +} + + +static double jarquebera_jarqueberaapprox(ae_int_t n, + double s, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector vx; + ae_vector vy; + ae_matrix ctbl; + double t1; + double t2; + double t3; + double t; + double f1; + double f2; + double f3; + double f12; + double f23; + double x; + double result; + + ae_frame_make(_state, &_frame_block); + memset(&vx, 0, sizeof(vx)); + memset(&vy, 0, sizeof(vy)); + memset(&ctbl, 0, sizeof(ctbl)); + ae_vector_init(&vx, 0, DT_REAL, _state, ae_true); + ae_vector_init(&vy, 0, DT_REAL, _state, ae_true); + ae_matrix_init(&ctbl, 0, 0, DT_REAL, _state, ae_true); + + result = (double)(1); + x = s; + if( n<5 ) + { + ae_frame_leave(_state); + return result; + } + + /* + * N = 5..20 are tabulated + */ + if( n>=5&&n<=20 ) + { + if( n==5 ) + { + result = ae_exp(jarquebera_jbtbl5(x, _state), _state); + } + if( n==6 ) + { + result = ae_exp(jarquebera_jbtbl6(x, _state), _state); + } + if( n==7 ) + { + result = ae_exp(jarquebera_jbtbl7(x, _state), _state); + } + if( n==8 ) + { + result = ae_exp(jarquebera_jbtbl8(x, _state), _state); + } + if( n==9 ) + { + result = ae_exp(jarquebera_jbtbl9(x, _state), _state); + } + if( n==10 ) + { + result = ae_exp(jarquebera_jbtbl10(x, _state), _state); + } + if( n==11 ) + { + result = ae_exp(jarquebera_jbtbl11(x, _state), _state); + } + if( n==12 ) + { + result = ae_exp(jarquebera_jbtbl12(x, _state), _state); + } + if( n==13 ) + { + result = ae_exp(jarquebera_jbtbl13(x, _state), _state); + } + if( n==14 ) + { + result = ae_exp(jarquebera_jbtbl14(x, _state), _state); + } + if( n==15 ) + { + result = ae_exp(jarquebera_jbtbl15(x, _state), _state); + } + if( n==16 ) + { + result = ae_exp(jarquebera_jbtbl16(x, _state), _state); + } + if( n==17 ) + { + result = ae_exp(jarquebera_jbtbl17(x, _state), _state); + } + if( n==18 ) + { + result = ae_exp(jarquebera_jbtbl18(x, _state), _state); + } + if( n==19 ) + { + result = ae_exp(jarquebera_jbtbl19(x, _state), _state); + } + if( n==20 ) + { + result = ae_exp(jarquebera_jbtbl20(x, _state), _state); + } + ae_frame_leave(_state); + return result; + } + + /* + * N = 20, 30, 50 are tabulated. + * In-between values are interpolated + * using interpolating polynomial of the second degree. + */ + if( n>20&&n<=50 ) + { + t1 = -1.0/20.0; + t2 = -1.0/30.0; + t3 = -1.0/50.0; + t = -1.0/(double)n; + f1 = jarquebera_jbtbl20(x, _state); + f2 = jarquebera_jbtbl30(x, _state); + f3 = jarquebera_jbtbl50(x, _state); + f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); + f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); + result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + + /* + * N = 50, 65, 100 are tabulated. + * In-between values are interpolated + * using interpolating polynomial of the second degree. + */ + if( n>50&&n<=100 ) + { + t1 = -1.0/50.0; + t2 = -1.0/65.0; + t3 = -1.0/100.0; + t = -1.0/(double)n; + f1 = jarquebera_jbtbl50(x, _state); + f2 = jarquebera_jbtbl65(x, _state); + f3 = jarquebera_jbtbl100(x, _state); + f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); + f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); + result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + + /* + * N = 100, 130, 200 are tabulated. + * In-between values are interpolated + * using interpolating polynomial of the second degree. + */ + if( n>100&&n<=200 ) + { + t1 = -1.0/100.0; + t2 = -1.0/130.0; + t3 = -1.0/200.0; + t = -1.0/(double)n; + f1 = jarquebera_jbtbl100(x, _state); + f2 = jarquebera_jbtbl130(x, _state); + f3 = jarquebera_jbtbl200(x, _state); + f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); + f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); + result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + + /* + * N = 200, 301, 501 are tabulated. + * In-between values are interpolated + * using interpolating polynomial of the second degree. + */ + if( n>200&&n<=501 ) + { + t1 = -1.0/200.0; + t2 = -1.0/301.0; + t3 = -1.0/501.0; + t = -1.0/(double)n; + f1 = jarquebera_jbtbl200(x, _state); + f2 = jarquebera_jbtbl301(x, _state); + f3 = jarquebera_jbtbl501(x, _state); + f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); + f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); + result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + + /* + * N = 501, 701, 1401 are tabulated. + * In-between values are interpolated + * using interpolating polynomial of the second degree. + */ + if( n>501&&n<=1401 ) + { + t1 = -1.0/501.0; + t2 = -1.0/701.0; + t3 = -1.0/1401.0; + t = -1.0/(double)n; + f1 = jarquebera_jbtbl501(x, _state); + f2 = jarquebera_jbtbl701(x, _state); + f3 = jarquebera_jbtbl1401(x, _state); + f12 = ((t-t2)*f1+(t1-t)*f2)/(t1-t2); + f23 = ((t-t3)*f2+(t2-t)*f3)/(t2-t3); + result = ((t-t3)*f12+(t1-t)*f23)/(t1-t3); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + + /* + * Asymptotic expansion + */ + if( n>1401 ) + { + result = -0.5*x+(jarquebera_jbtbl1401(x, _state)+0.5*x)*ae_sqrt((double)1401/(double)n, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + result = ae_exp(result, _state); + ae_frame_leave(_state); + return result; + } + ae_frame_leave(_state); + return result; +} + + +static double jarquebera_jbtbl5(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,0.4000) ) + { + x = (double)2*(s-0.000000)/0.400000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.097885e-20, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.854501e-20, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.756616e-20, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,1.1000) ) + { + x = (double)2*(s-0.400000)/0.700000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.324545e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.075941e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.772272e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.175686e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.576162e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.126861e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.434425e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.790359e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.809178e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.479704e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.717040e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.294170e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.880632e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.023344e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.601531e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.920403e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -5.188419e+02*(s-1.100000e+00)-4.767297e+00; + return result; +} + + +static double jarquebera_jbtbl6(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,0.2500) ) + { + x = (double)2*(s-0.000000)/0.250000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.274707e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.700471e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.425764e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,1.3000) ) + { + x = (double)2*(s-0.250000)/1.050000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.339000e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.011104e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.168177e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.085666e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.738606e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.022876e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.462402e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.908270e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.230772e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.006996e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.410222e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.893768e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.114564e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,1.8500) ) + { + x = (double)2*(s-1.300000)/0.550000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.794311e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.578700e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.394664e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.928290e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.813273e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.076063e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.835380e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.013013e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.058903e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.856915e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.710887e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.770029e+02*(s-1.850000e+00)-1.371015e+01; + return result; +} + + +static double jarquebera_jbtbl7(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.4000) ) + { + x = (double)2*(s-0.000000)/1.400000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.093681e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.695911e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.473192e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.203236e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.590379e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.291876e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.132007e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.411147e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.180067e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.487610e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.436561e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-1.400000)/1.600000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.947854e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.772675e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.707912e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.691171e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.132795e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.481310e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.867536e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.772327e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.033387e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.378277e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.497964e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.636814e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.581640e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,3.2000) ) + { + x = (double)2*(s-3.000000)/0.200000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -7.511008e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.895025e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.140472e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.933930e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.568561e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.682053e+00, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.824116e+03*(s-3.200000e+00)-1.440330e+01; + return result; +} + + +static double jarquebera_jbtbl8(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.3000) ) + { + x = (double)2*(s-0.000000)/1.300000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -7.199015e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.095921e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.736828e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.047438e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.484320e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.937923e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.810470e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.139780e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.708443e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,2.0000) ) + { + x = (double)2*(s-1.300000)/0.700000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.378966e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.802461e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.547593e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.241042e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.203274e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.201990e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.125597e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.584426e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.546069e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,5.0000) ) + { + x = (double)2*(s-2.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.828366e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.137533e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.016671e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.745637e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.189801e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.621610e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.741122e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.516368e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.552085e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.787029e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.359774e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -5.087028e+00*(s-5.000000e+00)-1.071300e+01; + return result; +} + + +static double jarquebera_jbtbl9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.3000) ) + { + x = (double)2*(s-0.000000)/1.300000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.279320e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.277151e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.669339e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.086149e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.333816e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.871249e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.007048e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.482245e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.355615e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,2.0000) ) + { + x = (double)2*(s-1.300000)/0.700000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.981430e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.972248e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.747737e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.808530e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.888305e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.001302e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.378767e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.108510e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.915372e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,7.0000) ) + { + x = (double)2*(s-2.000000)/5.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.387463e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.845231e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.809956e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.543461e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.880397e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.160074e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.356527e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.394428e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.619892e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.758763e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.790977e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.020952e+00*(s-7.000000e+00)-9.516623e+00; + return result; +} + + +static double jarquebera_jbtbl10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.2000) ) + { + x = (double)2*(s-0.000000)/1.200000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.590993e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.562730e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.353934e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.069933e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.849151e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.931406e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.636295e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.178340e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.917749e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,2.0000) ) + { + x = (double)2*(s-1.200000)/0.800000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.537658e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.962401e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.838715e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.055792e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.580316e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.781701e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.770362e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.838983e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.999052e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,7.0000) ) + { + x = (double)2*(s-2.000000)/5.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.337524e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.877029e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.734650e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.249254e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.320250e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.432266e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -8.711035e-01*(s-7.000000e+00)-7.212811e+00; + return result; +} + + +static double jarquebera_jbtbl11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.2000) ) + { + x = (double)2*(s-0.000000)/1.200000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.339517e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.051558e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.000992e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.022547e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.808401e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.592870e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.575081e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.086173e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.089011e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,2.2500) ) + { + x = (double)2*(s-1.200000)/1.050000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.523221e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.068388e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.179661e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.555524e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.238964e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.364320e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.895771e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.762774e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.201340e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,8.0000) ) + { + x = (double)2*(s-2.250000)/5.750000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.212179e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.684579e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.299519e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.606261e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.310869e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.320115e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -5.715445e-01*(s-8.000000e+00)-6.845834e+00; + return result; +} + + +static double jarquebera_jbtbl12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.0000) ) + { + x = (double)2*(s-0.000000)/1.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.736742e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.657836e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.047209e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.319599e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.545631e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.280445e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.815679e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.213519e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.256838e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-1.000000)/2.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.573947e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.515287e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.611880e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.271311e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.495815e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.141186e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.180886e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.388211e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.890761e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.233175e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.946156e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,12.0000) ) + { + x = (double)2*(s-3.000000)/9.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.947819e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.034157e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.878986e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.078603e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.990977e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.866215e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.897866e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.512252e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.073743e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.022621e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.501343e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.877243e-01*(s-1.200000e+01)-7.936839e+00; + return result; +} + + +static double jarquebera_jbtbl13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.0000) ) + { + x = (double)2*(s-0.000000)/1.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.713276e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.557541e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.459092e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.044145e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.546132e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.002374e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.349456e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.025669e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.590242e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-1.000000)/2.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.454383e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.467539e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.270774e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.075763e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.611647e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.990785e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.109212e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.135031e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.915919e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.522390e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.144701e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,13.0000) ) + { + x = (double)2*(s-3.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.736127e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.920809e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.175858e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.002049e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.158966e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.157781e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.762172e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.780347e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.193310e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.442421e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.547756e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.799944e-01*(s-1.300000e+01)-7.566269e+00; + return result; +} + + +static double jarquebera_jbtbl14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,1.0000) ) + { + x = (double)2*(s-0.000000)/1.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.698527e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.479081e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.640733e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.466899e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.469485e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.150009e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.965975e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.710210e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.327808e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-1.000000)/2.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -2.350359e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.421365e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.960468e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.149167e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.361109e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.976022e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.082700e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.563328e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.453123e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.917559e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.151067e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-3.000000)/12.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.746892e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.010441e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.566146e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.129690e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.929724e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.524227e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.192933e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.254730e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.620685e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.289618e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.112350e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.590621e-01*(s-1.500000e+01)-7.632238e+00; + return result; +} + + +static double jarquebera_jbtbl15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,2.0000) ) + { + x = (double)2*(s-0.000000)/2.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.043660e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.361653e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.009497e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.951784e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.377903e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.003253e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.271309e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,5.0000) ) + { + x = (double)2*(s-2.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.582778e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.349578e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.476514e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.717385e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.222591e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.635124e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.815993e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,17.0000) ) + { + x = (double)2*(s-5.000000)/12.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.115476e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.655936e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.404310e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.663794e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.868618e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.381447e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.444801e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.581503e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.468696e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.728509e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.206470e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.927937e-01*(s-1.700000e+01)-7.700983e+00; + return result; +} + + +static double jarquebera_jbtbl16(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,2.0000) ) + { + x = (double)2*(s-0.000000)/2.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.002570e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.298141e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.832803e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.877026e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.539436e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.439658e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.756911e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,5.0000) ) + { + x = (double)2*(s-2.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.486198e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.242944e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.020002e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.130531e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.512373e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.054876e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.556839e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,20.0000) ) + { + x = (double)2*(s-5.000000)/15.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.241608e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.832655e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.340545e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.361143e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.283219e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.484549e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.805968e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.057243e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.454439e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.177513e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.819209e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.391580e-01*(s-2.000000e+01)-7.963205e+00; + return result; +} + + +static double jarquebera_jbtbl17(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-0.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.566973e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.810330e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.840039e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.337294e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.383549e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.556515e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.656965e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.404569e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.447867e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,6.0000) ) + { + x = (double)2*(s-3.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.905684e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.222920e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.146667e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.809176e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.057028e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.211838e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.099683e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.161105e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.225465e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,24.0000) ) + { + x = (double)2*(s-6.000000)/18.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.594282e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.917838e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.455980e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.999589e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.604263e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.484445e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.819937e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.930390e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.771761e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.232581e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.029083e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.127771e-01*(s-2.400000e+01)-8.400197e+00; + return result; +} + + +static double jarquebera_jbtbl18(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-0.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.526802e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.762373e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.598890e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.189437e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.971721e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.823067e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.064501e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.014932e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.953513e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,6.0000) ) + { + x = (double)2*(s-3.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.818669e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.070918e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.277196e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.879817e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.887357e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.638451e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.502800e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.165796e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.034960e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,20.0000) ) + { + x = (double)2*(s-6.000000)/14.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.010656e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.496296e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.002227e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.338250e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.137036e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.586202e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.736384e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.332251e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.877982e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.160963e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.547247e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.684623e-01*(s-2.000000e+01)-7.428883e+00; + return result; +} + + +static double jarquebera_jbtbl19(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,3.0000) ) + { + x = (double)2*(s-0.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.490213e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.719633e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.459123e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.034878e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.113868e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.030922e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.054022e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.525623e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.277360e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,6.0000) ) + { + x = (double)2*(s-3.000000)/3.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -3.744750e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.977749e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.223716e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.363889e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.711774e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.557257e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.254794e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.034207e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.498107e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,20.0000) ) + { + x = (double)2*(s-6.000000)/14.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.872768e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.430689e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.136575e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.726627e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.421110e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.581510e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.559520e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.838208e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.428839e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.170682e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.006647e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.539373e-01*(s-2.000000e+01)-7.206941e+00; + return result; +} + + +static double jarquebera_jbtbl20(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.854794e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.948947e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.632184e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.139397e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.006237e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.810031e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.573620e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.951242e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.274092e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.464196e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.882139e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.575144e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.822804e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.061348e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.908404e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.978353e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.030989e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.327151e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.346404e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.840051e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.578551e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.813886e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.905973e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.358489e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.450795e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.941157e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.432418e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.070537e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.375654e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.367378e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.890859e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.679782e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -7.015854e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.487737e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.244254e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.318007e-01*(s-2.500000e+01)-7.742185e+00; + return result; +} + + +static double jarquebera_jbtbl30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.630822e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.724298e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.872756e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.658268e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.573597e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.994157e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.994825e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.394303e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.785029e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.990264e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.037838e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.755546e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.774473e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.821395e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.392603e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.353313e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.539322e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.197018e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.396848e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.804293e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.867928e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.768758e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.211792e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.925799e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.046235e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.536469e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.489642e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.263462e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.177316e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.590637e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.028212e-01*(s-2.500000e+01)-6.855288e+00; + return result; +} + + +static double jarquebera_jbtbl50(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.436279e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.519711e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.148699e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.001204e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.207620e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.034778e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.220322e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.033260e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.588280e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.851653e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.287733e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.234645e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.189127e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.429738e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.058822e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 9.086776e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.445783e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.311671e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.261298e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.496987e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.605249e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.162282e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.921095e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.888603e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.080113e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -9.313116e-02*(s-2.500000e+01)-6.479154e+00; + return result; +} + + +static double jarquebera_jbtbl65(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.360024e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.434631e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.514580e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 7.332038e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.158197e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.121233e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.051056e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.148601e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.214233e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.487977e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.424720e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.116715e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.043152e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.718149e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.313701e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.097305e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.181031e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.256975e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.858951e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.895179e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.933237e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -9.443768e-02*(s-2.500000e+01)-6.419137e+00; + return result; +} + + +static double jarquebera_jbtbl100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.257021e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.313418e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.628931e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.264287e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.518487e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.499826e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.836044e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.056508e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.279690e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.665746e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.290012e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.487632e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.704465e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.211669e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.866099e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.399767e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.498208e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.080097e-01*(s-2.500000e+01)-6.481094e+00; + return result; +} + + +static double jarquebera_jbtbl130(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.207999e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.253864e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.618032e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.112729e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.210546e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.732602e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.410527e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.026324e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.331990e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.779129e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.674749e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.669077e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.679136e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 8.833221e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -5.893951e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.475304e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.116734e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.045722e-01*(s-2.500000e+01)-6.510314e+00; + return result; +} + + +static double jarquebera_jbtbl200(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.146155e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.177398e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.297970e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.869745e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.717288e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.982108e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.427636e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.034235e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.455006e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.942996e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.973795e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.418812e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.156778e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.896705e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.086071e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.152176e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.725393e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.132404e-01*(s-2.500000e+01)-6.764034e+00; + return result; +} + + +static double jarquebera_jbtbl301(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.104290e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.125800e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.595847e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.219666e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.502210e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.414543e-05, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.754115e-05, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.065955e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.582060e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.004472e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -4.709092e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.105779e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.197391e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.386780e-04, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.311384e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.918763e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.626584e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.293626e-01*(s-2.500000e+01)-7.066995e+00; + return result; +} + + +static double jarquebera_jbtbl501(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.067426e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.079765e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -5.463005e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 6.875659e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.127574e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.740694e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.044502e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.746714e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 3.810594e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.197111e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.628194e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -8.846221e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.386405e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.418332e-01*(s-2.500000e+01)-7.468952e+00; + return result; +} + + +static double jarquebera_jbtbl701(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.050999e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.059769e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -3.922680e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 4.847054e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.192182e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.860007e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.963942e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.838711e-02, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.893112e-04, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.159788e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -6.917851e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -9.817020e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.383727e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -1.532706e-01*(s-2.500000e+01)-7.845715e+00; + return result; +} + + +static double jarquebera_jbtbl1401(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + if( ae_fp_less_eq(s,4.0000) ) + { + x = (double)2*(s-0.000000)/4.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -1.026266e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.030061e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.259222e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 2.536254e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,15.0000) ) + { + x = (double)2*(s-4.000000)/11.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -4.329849e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -2.095443e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 1.759363e-01, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -7.751359e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -6.124368e-03, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.793114e-03, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + if( ae_fp_less_eq(s,25.0000) ) + { + x = (double)2*(s-15.000000)/10.000000-(double)1; + tj = (double)(1); + tj1 = x; + jarquebera_jbcheb(x, -7.544330e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, -1.225382e+00, &tj, &tj1, &result, _state); + jarquebera_jbcheb(x, 5.392349e-02, &tj, &tj1, &result, _state); + if( ae_fp_greater(result,(double)(0)) ) + { + result = (double)(0); + } + return result; + } + result = -2.019375e-01*(s-2.500000e+01)-8.715788e+00; + return result; +} + + +static void jarquebera_jbcheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state) +{ + double t; + + + *r = *r+c*(*tj); + t = (double)2*x*(*tj1)-(*tj); + *tj = *tj1; + *tj1 = t; +} + + +#endif +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Two-sample F-test + +This test checks three hypotheses about dispersions of the given samples. +The following tests are performed: + * two-tailed test (null hypothesis - the dispersions are equal) + * left-tailed test (null hypothesis - the dispersion of the first + sample is greater than or equal to the dispersion of the second + sample). + * right-tailed test (null hypothesis - the dispersion of the first + sample is less than or equal to the dispersion of the second sample) + +The test is based on the following assumptions: + * the given samples have normal distributions + * the samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - sample size. + Y - sample 2. Array whose index goes from 0 to M-1. + M - sample size. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void ftest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + double xmean; + double ymean; + double xvar; + double yvar; + ae_int_t df1; + ae_int_t df2; + double stat; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=2||m<=2 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Mean + */ + xmean = (double)(0); + for(i=0; i<=n-1; i++) + { + xmean = xmean+x->ptr.p_double[i]; + } + xmean = xmean/(double)n; + ymean = (double)(0); + for(i=0; i<=m-1; i++) + { + ymean = ymean+y->ptr.p_double[i]; + } + ymean = ymean/(double)m; + + /* + * Variance (using corrected two-pass algorithm) + */ + xvar = (double)(0); + for(i=0; i<=n-1; i++) + { + xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); + } + xvar = xvar/(double)(n-1); + yvar = (double)(0); + for(i=0; i<=m-1; i++) + { + yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); + } + yvar = yvar/(double)(m-1); + if( ae_fp_eq(xvar,(double)(0))||ae_fp_eq(yvar,(double)(0)) ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Statistic + */ + df1 = n-1; + df2 = m-1; + stat = ae_minreal(xvar/yvar, yvar/xvar, _state); + *bothtails = (double)1-(fdistribution(df1, df2, (double)1/stat, _state)-fdistribution(df1, df2, stat, _state)); + *lefttail = fdistribution(df1, df2, xvar/yvar, _state); + *righttail = (double)1-(*lefttail); +} + + +/************************************************************************* +One-sample chi-square test + +This test checks three hypotheses about the dispersion of the given sample +The following tests are performed: + * two-tailed test (null hypothesis - the dispersion equals the given + number) + * left-tailed test (null hypothesis - the dispersion is greater than + or equal to the given number) + * right-tailed test (null hypothesis - dispersion is less than or + equal to the given number). + +Test is based on the following assumptions: + * the given sample has a normal distribution. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Variance - dispersion value to compare with. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplevariancetest(/* Real */ const ae_vector* x, + ae_int_t n, + double variance, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + double xmean; + double xvar; + double s; + double stat; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=1 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Mean + */ + xmean = (double)(0); + for(i=0; i<=n-1; i++) + { + xmean = xmean+x->ptr.p_double[i]; + } + xmean = xmean/(double)n; + + /* + * Variance + */ + xvar = (double)(0); + for(i=0; i<=n-1; i++) + { + xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); + } + xvar = xvar/(double)(n-1); + if( ae_fp_eq(xvar,(double)(0)) ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Statistic + */ + stat = (double)(n-1)*xvar/variance; + s = chisquaredistribution((double)(n-1), stat, _state); + *bothtails = (double)2*ae_minreal(s, (double)1-s, _state); + *lefttail = s; + *righttail = (double)1-(*lefttail); +} + + +#endif +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Wilcoxon signed-rank test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + * the distribution should be continuous and symmetric relative to its + median. + * number of distinct values in the X array should be greater than 4 + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with two decimal places in interval [0.0001, 1]. + +"Two decimal places" does not sound very impressive, but in practice the +relative error of less than 1% is enough to make a decision. + +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void wilcoxonsignedranktest(/* Real */ const ae_vector* _x, + ae_int_t n, + double e, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector x; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t t; + double tmp; + ae_int_t tmpi; + ae_int_t ns; + ae_vector r; + ae_vector c; + double w; + double p; + double mp; + double s; + double sigma; + double mu; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&r, 0, sizeof(r)); + memset(&c, 0, sizeof(c)); + ae_vector_init_copy(&x, _x, _state, ae_true); + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + ae_vector_init(&r, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_INT, _state, ae_true); + + + /* + * Prepare + */ + if( n<5 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + ae_frame_leave(_state); + return; + } + ns = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_eq(x.ptr.p_double[i],e) ) + { + continue; + } + x.ptr.p_double[ns] = x.ptr.p_double[i]; + ns = ns+1; + } + if( ns<5 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + ae_frame_leave(_state); + return; + } + ae_vector_set_length(&r, ns-1+1, _state); + ae_vector_set_length(&c, ns-1+1, _state); + for(i=0; i<=ns-1; i++) + { + r.ptr.p_double[i] = ae_fabs(x.ptr.p_double[i]-e, _state); + c.ptr.p_int[i] = i; + } + + /* + * sort {R, C} + */ + if( ns!=1 ) + { + i = 2; + do + { + t = i; + while(t!=1) + { + k = t/2; + if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) + { + t = 1; + } + else + { + tmp = r.ptr.p_double[k-1]; + r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; + r.ptr.p_double[t-1] = tmp; + tmpi = c.ptr.p_int[k-1]; + c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; + c.ptr.p_int[t-1] = tmpi; + t = k; + } + } + i = i+1; + } + while(i<=ns); + i = ns-1; + do + { + tmp = r.ptr.p_double[i]; + r.ptr.p_double[i] = r.ptr.p_double[0]; + r.ptr.p_double[0] = tmp; + tmpi = c.ptr.p_int[i]; + c.ptr.p_int[i] = c.ptr.p_int[0]; + c.ptr.p_int[0] = tmpi; + t = 1; + while(t!=0) + { + k = 2*t; + if( k>i ) + { + t = 0; + } + else + { + if( k=1); + } + + /* + * compute tied ranks + */ + i = 0; + while(i<=ns-1) + { + j = i+1; + while(j<=ns-1) + { + if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) + { + break; + } + j = j+1; + } + for(k=i; k<=j-1; k++) + { + r.ptr.p_double[k] = (double)1+(double)(i+j-1)/(double)2; + } + i = j; + } + + /* + * Compute W+ + */ + w = (double)(0); + for(i=0; i<=ns-1; i++) + { + if( ae_fp_greater(x.ptr.p_double[c.ptr.p_int[i]],e) ) + { + w = w+r.ptr.p_double[i]; + } + } + + /* + * Result + */ + mu = rmul2((double)(ns), (double)(ns+1), _state)/(double)4; + sigma = ae_sqrt(mu*(double)(2*ns+1)/(double)6, _state); + s = (w-mu)/sigma; + if( ae_fp_less_eq(s,(double)(0)) ) + { + p = ae_exp(wsr_wsigma(-(w-mu)/sigma, ns, _state), _state); + mp = (double)1-ae_exp(wsr_wsigma(-(w-(double)1-mu)/sigma, ns, _state), _state); + } + else + { + mp = ae_exp(wsr_wsigma((w-mu)/sigma, ns, _state), _state); + p = (double)1-ae_exp(wsr_wsigma((w+(double)1-mu)/sigma, ns, _state), _state); + } + *lefttail = ae_maxreal(p, 1.0E-4, _state); + *righttail = ae_maxreal(mp, 1.0E-4, _state); + *bothtails = (double)2*ae_minreal(*lefttail, *righttail, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Sequential Chebyshev interpolation. +*************************************************************************/ +static void wsr_wcheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state) +{ + double t; + + + *r = *r+c*(*tj); + t = (double)2*x*(*tj1)-(*tj); + *tj = *tj1; + *tj1 = t; +} + + +/************************************************************************* +Tail(S, 5) +*************************************************************************/ +static double wsr_w5(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-3.708099e+00*s+7.500000e+00, _state); + if( w>=7 ) + { + r = -6.931e-01; + } + if( w==6 ) + { + r = -9.008e-01; + } + if( w==5 ) + { + r = -1.163e+00; + } + if( w==4 ) + { + r = -1.520e+00; + } + if( w==3 ) + { + r = -1.856e+00; + } + if( w==2 ) + { + r = -2.367e+00; + } + if( w==1 ) + { + r = -2.773e+00; + } + if( w<=0 ) + { + r = -3.466e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 6) +*************************************************************************/ +static double wsr_w6(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-4.769696e+00*s+1.050000e+01, _state); + if( w>=10 ) + { + r = -6.931e-01; + } + if( w==9 ) + { + r = -8.630e-01; + } + if( w==8 ) + { + r = -1.068e+00; + } + if( w==7 ) + { + r = -1.269e+00; + } + if( w==6 ) + { + r = -1.520e+00; + } + if( w==5 ) + { + r = -1.856e+00; + } + if( w==4 ) + { + r = -2.213e+00; + } + if( w==3 ) + { + r = -2.549e+00; + } + if( w==2 ) + { + r = -3.060e+00; + } + if( w==1 ) + { + r = -3.466e+00; + } + if( w<=0 ) + { + r = -4.159e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 7) +*************************************************************************/ +static double wsr_w7(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-5.916080e+00*s+1.400000e+01, _state); + if( w>=14 ) + { + r = -6.325e-01; + } + if( w==13 ) + { + r = -7.577e-01; + } + if( w==12 ) + { + r = -9.008e-01; + } + if( w==11 ) + { + r = -1.068e+00; + } + if( w==10 ) + { + r = -1.241e+00; + } + if( w==9 ) + { + r = -1.451e+00; + } + if( w==8 ) + { + r = -1.674e+00; + } + if( w==7 ) + { + r = -1.908e+00; + } + if( w==6 ) + { + r = -2.213e+00; + } + if( w==5 ) + { + r = -2.549e+00; + } + if( w==4 ) + { + r = -2.906e+00; + } + if( w==3 ) + { + r = -3.243e+00; + } + if( w==2 ) + { + r = -3.753e+00; + } + if( w==1 ) + { + r = -4.159e+00; + } + if( w<=0 ) + { + r = -4.852e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 8) +*************************************************************************/ +static double wsr_w8(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-7.141428e+00*s+1.800000e+01, _state); + if( w>=18 ) + { + r = -6.399e-01; + } + if( w==17 ) + { + r = -7.494e-01; + } + if( w==16 ) + { + r = -8.630e-01; + } + if( w==15 ) + { + r = -9.913e-01; + } + if( w==14 ) + { + r = -1.138e+00; + } + if( w==13 ) + { + r = -1.297e+00; + } + if( w==12 ) + { + r = -1.468e+00; + } + if( w==11 ) + { + r = -1.653e+00; + } + if( w==10 ) + { + r = -1.856e+00; + } + if( w==9 ) + { + r = -2.079e+00; + } + if( w==8 ) + { + r = -2.326e+00; + } + if( w==7 ) + { + r = -2.601e+00; + } + if( w==6 ) + { + r = -2.906e+00; + } + if( w==5 ) + { + r = -3.243e+00; + } + if( w==4 ) + { + r = -3.599e+00; + } + if( w==3 ) + { + r = -3.936e+00; + } + if( w==2 ) + { + r = -4.447e+00; + } + if( w==1 ) + { + r = -4.852e+00; + } + if( w<=0 ) + { + r = -5.545e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 9) +*************************************************************************/ +static double wsr_w9(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-8.440972e+00*s+2.250000e+01, _state); + if( w>=22 ) + { + r = -6.931e-01; + } + if( w==21 ) + { + r = -7.873e-01; + } + if( w==20 ) + { + r = -8.912e-01; + } + if( w==19 ) + { + r = -1.002e+00; + } + if( w==18 ) + { + r = -1.120e+00; + } + if( w==17 ) + { + r = -1.255e+00; + } + if( w==16 ) + { + r = -1.394e+00; + } + if( w==15 ) + { + r = -1.547e+00; + } + if( w==14 ) + { + r = -1.717e+00; + } + if( w==13 ) + { + r = -1.895e+00; + } + if( w==12 ) + { + r = -2.079e+00; + } + if( w==11 ) + { + r = -2.287e+00; + } + if( w==10 ) + { + r = -2.501e+00; + } + if( w==9 ) + { + r = -2.742e+00; + } + if( w==8 ) + { + r = -3.019e+00; + } + if( w==7 ) + { + r = -3.294e+00; + } + if( w==6 ) + { + r = -3.599e+00; + } + if( w==5 ) + { + r = -3.936e+00; + } + if( w==4 ) + { + r = -4.292e+00; + } + if( w==3 ) + { + r = -4.629e+00; + } + if( w==2 ) + { + r = -5.140e+00; + } + if( w==1 ) + { + r = -5.545e+00; + } + if( w<=0 ) + { + r = -6.238e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 10) +*************************************************************************/ +static double wsr_w10(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-9.810708e+00*s+2.750000e+01, _state); + if( w>=27 ) + { + r = -6.931e-01; + } + if( w==26 ) + { + r = -7.745e-01; + } + if( w==25 ) + { + r = -8.607e-01; + } + if( w==24 ) + { + r = -9.551e-01; + } + if( w==23 ) + { + r = -1.057e+00; + } + if( w==22 ) + { + r = -1.163e+00; + } + if( w==21 ) + { + r = -1.279e+00; + } + if( w==20 ) + { + r = -1.402e+00; + } + if( w==19 ) + { + r = -1.533e+00; + } + if( w==18 ) + { + r = -1.674e+00; + } + if( w==17 ) + { + r = -1.826e+00; + } + if( w==16 ) + { + r = -1.983e+00; + } + if( w==15 ) + { + r = -2.152e+00; + } + if( w==14 ) + { + r = -2.336e+00; + } + if( w==13 ) + { + r = -2.525e+00; + } + if( w==12 ) + { + r = -2.727e+00; + } + if( w==11 ) + { + r = -2.942e+00; + } + if( w==10 ) + { + r = -3.170e+00; + } + if( w==9 ) + { + r = -3.435e+00; + } + if( w==8 ) + { + r = -3.713e+00; + } + if( w==7 ) + { + r = -3.987e+00; + } + if( w==6 ) + { + r = -4.292e+00; + } + if( w==5 ) + { + r = -4.629e+00; + } + if( w==4 ) + { + r = -4.986e+00; + } + if( w==3 ) + { + r = -5.322e+00; + } + if( w==2 ) + { + r = -5.833e+00; + } + if( w==1 ) + { + r = -6.238e+00; + } + if( w<=0 ) + { + r = -6.931e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 11) +*************************************************************************/ +static double wsr_w11(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.124722e+01*s+3.300000e+01, _state); + if( w>=33 ) + { + r = -6.595e-01; + } + if( w==32 ) + { + r = -7.279e-01; + } + if( w==31 ) + { + r = -8.002e-01; + } + if( w==30 ) + { + r = -8.782e-01; + } + if( w==29 ) + { + r = -9.615e-01; + } + if( w==28 ) + { + r = -1.050e+00; + } + if( w==27 ) + { + r = -1.143e+00; + } + if( w==26 ) + { + r = -1.243e+00; + } + if( w==25 ) + { + r = -1.348e+00; + } + if( w==24 ) + { + r = -1.459e+00; + } + if( w==23 ) + { + r = -1.577e+00; + } + if( w==22 ) + { + r = -1.700e+00; + } + if( w==21 ) + { + r = -1.832e+00; + } + if( w==20 ) + { + r = -1.972e+00; + } + if( w==19 ) + { + r = -2.119e+00; + } + if( w==18 ) + { + r = -2.273e+00; + } + if( w==17 ) + { + r = -2.437e+00; + } + if( w==16 ) + { + r = -2.607e+00; + } + if( w==15 ) + { + r = -2.788e+00; + } + if( w==14 ) + { + r = -2.980e+00; + } + if( w==13 ) + { + r = -3.182e+00; + } + if( w==12 ) + { + r = -3.391e+00; + } + if( w==11 ) + { + r = -3.617e+00; + } + if( w==10 ) + { + r = -3.863e+00; + } + if( w==9 ) + { + r = -4.128e+00; + } + if( w==8 ) + { + r = -4.406e+00; + } + if( w==7 ) + { + r = -4.680e+00; + } + if( w==6 ) + { + r = -4.986e+00; + } + if( w==5 ) + { + r = -5.322e+00; + } + if( w==4 ) + { + r = -5.679e+00; + } + if( w==3 ) + { + r = -6.015e+00; + } + if( w==2 ) + { + r = -6.526e+00; + } + if( w==1 ) + { + r = -6.931e+00; + } + if( w<=0 ) + { + r = -7.625e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 12) +*************************************************************************/ +static double wsr_w12(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.274755e+01*s+3.900000e+01, _state); + if( w>=39 ) + { + r = -6.633e-01; + } + if( w==38 ) + { + r = -7.239e-01; + } + if( w==37 ) + { + r = -7.878e-01; + } + if( w==36 ) + { + r = -8.556e-01; + } + if( w==35 ) + { + r = -9.276e-01; + } + if( w==34 ) + { + r = -1.003e+00; + } + if( w==33 ) + { + r = -1.083e+00; + } + if( w==32 ) + { + r = -1.168e+00; + } + if( w==31 ) + { + r = -1.256e+00; + } + if( w==30 ) + { + r = -1.350e+00; + } + if( w==29 ) + { + r = -1.449e+00; + } + if( w==28 ) + { + r = -1.552e+00; + } + if( w==27 ) + { + r = -1.660e+00; + } + if( w==26 ) + { + r = -1.774e+00; + } + if( w==25 ) + { + r = -1.893e+00; + } + if( w==24 ) + { + r = -2.017e+00; + } + if( w==23 ) + { + r = -2.148e+00; + } + if( w==22 ) + { + r = -2.285e+00; + } + if( w==21 ) + { + r = -2.429e+00; + } + if( w==20 ) + { + r = -2.581e+00; + } + if( w==19 ) + { + r = -2.738e+00; + } + if( w==18 ) + { + r = -2.902e+00; + } + if( w==17 ) + { + r = -3.076e+00; + } + if( w==16 ) + { + r = -3.255e+00; + } + if( w==15 ) + { + r = -3.443e+00; + } + if( w==14 ) + { + r = -3.645e+00; + } + if( w==13 ) + { + r = -3.852e+00; + } + if( w==12 ) + { + r = -4.069e+00; + } + if( w==11 ) + { + r = -4.310e+00; + } + if( w==10 ) + { + r = -4.557e+00; + } + if( w==9 ) + { + r = -4.821e+00; + } + if( w==8 ) + { + r = -5.099e+00; + } + if( w==7 ) + { + r = -5.373e+00; + } + if( w==6 ) + { + r = -5.679e+00; + } + if( w==5 ) + { + r = -6.015e+00; + } + if( w==4 ) + { + r = -6.372e+00; + } + if( w==3 ) + { + r = -6.708e+00; + } + if( w==2 ) + { + r = -7.219e+00; + } + if( w==1 ) + { + r = -7.625e+00; + } + if( w<=0 ) + { + r = -8.318e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 13) +*************************************************************************/ +static double wsr_w13(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.430909e+01*s+4.550000e+01, _state); + if( w>=45 ) + { + r = -6.931e-01; + } + if( w==44 ) + { + r = -7.486e-01; + } + if( w==43 ) + { + r = -8.068e-01; + } + if( w==42 ) + { + r = -8.683e-01; + } + if( w==41 ) + { + r = -9.328e-01; + } + if( w==40 ) + { + r = -1.001e+00; + } + if( w==39 ) + { + r = -1.072e+00; + } + if( w==38 ) + { + r = -1.146e+00; + } + if( w==37 ) + { + r = -1.224e+00; + } + if( w==36 ) + { + r = -1.306e+00; + } + if( w==35 ) + { + r = -1.392e+00; + } + if( w==34 ) + { + r = -1.481e+00; + } + if( w==33 ) + { + r = -1.574e+00; + } + if( w==32 ) + { + r = -1.672e+00; + } + if( w==31 ) + { + r = -1.773e+00; + } + if( w==30 ) + { + r = -1.879e+00; + } + if( w==29 ) + { + r = -1.990e+00; + } + if( w==28 ) + { + r = -2.104e+00; + } + if( w==27 ) + { + r = -2.224e+00; + } + if( w==26 ) + { + r = -2.349e+00; + } + if( w==25 ) + { + r = -2.479e+00; + } + if( w==24 ) + { + r = -2.614e+00; + } + if( w==23 ) + { + r = -2.755e+00; + } + if( w==22 ) + { + r = -2.902e+00; + } + if( w==21 ) + { + r = -3.055e+00; + } + if( w==20 ) + { + r = -3.215e+00; + } + if( w==19 ) + { + r = -3.380e+00; + } + if( w==18 ) + { + r = -3.551e+00; + } + if( w==17 ) + { + r = -3.733e+00; + } + if( w==16 ) + { + r = -3.917e+00; + } + if( w==15 ) + { + r = -4.113e+00; + } + if( w==14 ) + { + r = -4.320e+00; + } + if( w==13 ) + { + r = -4.534e+00; + } + if( w==12 ) + { + r = -4.762e+00; + } + if( w==11 ) + { + r = -5.004e+00; + } + if( w==10 ) + { + r = -5.250e+00; + } + if( w==9 ) + { + r = -5.514e+00; + } + if( w==8 ) + { + r = -5.792e+00; + } + if( w==7 ) + { + r = -6.066e+00; + } + if( w==6 ) + { + r = -6.372e+00; + } + if( w==5 ) + { + r = -6.708e+00; + } + if( w==4 ) + { + r = -7.065e+00; + } + if( w==3 ) + { + r = -7.401e+00; + } + if( w==2 ) + { + r = -7.912e+00; + } + if( w==1 ) + { + r = -8.318e+00; + } + if( w<=0 ) + { + r = -9.011e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 14) +*************************************************************************/ +static double wsr_w14(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.592953e+01*s+5.250000e+01, _state); + if( w>=52 ) + { + r = -6.931e-01; + } + if( w==51 ) + { + r = -7.428e-01; + } + if( w==50 ) + { + r = -7.950e-01; + } + if( w==49 ) + { + r = -8.495e-01; + } + if( w==48 ) + { + r = -9.067e-01; + } + if( w==47 ) + { + r = -9.664e-01; + } + if( w==46 ) + { + r = -1.029e+00; + } + if( w==45 ) + { + r = -1.094e+00; + } + if( w==44 ) + { + r = -1.162e+00; + } + if( w==43 ) + { + r = -1.233e+00; + } + if( w==42 ) + { + r = -1.306e+00; + } + if( w==41 ) + { + r = -1.383e+00; + } + if( w==40 ) + { + r = -1.463e+00; + } + if( w==39 ) + { + r = -1.546e+00; + } + if( w==38 ) + { + r = -1.632e+00; + } + if( w==37 ) + { + r = -1.722e+00; + } + if( w==36 ) + { + r = -1.815e+00; + } + if( w==35 ) + { + r = -1.911e+00; + } + if( w==34 ) + { + r = -2.011e+00; + } + if( w==33 ) + { + r = -2.115e+00; + } + if( w==32 ) + { + r = -2.223e+00; + } + if( w==31 ) + { + r = -2.334e+00; + } + if( w==30 ) + { + r = -2.450e+00; + } + if( w==29 ) + { + r = -2.570e+00; + } + if( w==28 ) + { + r = -2.694e+00; + } + if( w==27 ) + { + r = -2.823e+00; + } + if( w==26 ) + { + r = -2.956e+00; + } + if( w==25 ) + { + r = -3.095e+00; + } + if( w==24 ) + { + r = -3.238e+00; + } + if( w==23 ) + { + r = -3.387e+00; + } + if( w==22 ) + { + r = -3.541e+00; + } + if( w==21 ) + { + r = -3.700e+00; + } + if( w==20 ) + { + r = -3.866e+00; + } + if( w==19 ) + { + r = -4.038e+00; + } + if( w==18 ) + { + r = -4.215e+00; + } + if( w==17 ) + { + r = -4.401e+00; + } + if( w==16 ) + { + r = -4.592e+00; + } + if( w==15 ) + { + r = -4.791e+00; + } + if( w==14 ) + { + r = -5.004e+00; + } + if( w==13 ) + { + r = -5.227e+00; + } + if( w==12 ) + { + r = -5.456e+00; + } + if( w==11 ) + { + r = -5.697e+00; + } + if( w==10 ) + { + r = -5.943e+00; + } + if( w==9 ) + { + r = -6.208e+00; + } + if( w==8 ) + { + r = -6.485e+00; + } + if( w==7 ) + { + r = -6.760e+00; + } + if( w==6 ) + { + r = -7.065e+00; + } + if( w==5 ) + { + r = -7.401e+00; + } + if( w==4 ) + { + r = -7.758e+00; + } + if( w==3 ) + { + r = -8.095e+00; + } + if( w==2 ) + { + r = -8.605e+00; + } + if( w==1 ) + { + r = -9.011e+00; + } + if( w<=0 ) + { + r = -9.704e+00; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 15) +*************************************************************************/ +static double wsr_w15(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.760682e+01*s+6.000000e+01, _state); + if( w>=60 ) + { + r = -6.714e-01; + } + if( w==59 ) + { + r = -7.154e-01; + } + if( w==58 ) + { + r = -7.613e-01; + } + if( w==57 ) + { + r = -8.093e-01; + } + if( w==56 ) + { + r = -8.593e-01; + } + if( w==55 ) + { + r = -9.114e-01; + } + if( w==54 ) + { + r = -9.656e-01; + } + if( w==53 ) + { + r = -1.022e+00; + } + if( w==52 ) + { + r = -1.081e+00; + } + if( w==51 ) + { + r = -1.142e+00; + } + if( w==50 ) + { + r = -1.205e+00; + } + if( w==49 ) + { + r = -1.270e+00; + } + if( w==48 ) + { + r = -1.339e+00; + } + if( w==47 ) + { + r = -1.409e+00; + } + if( w==46 ) + { + r = -1.482e+00; + } + if( w==45 ) + { + r = -1.558e+00; + } + if( w==44 ) + { + r = -1.636e+00; + } + if( w==43 ) + { + r = -1.717e+00; + } + if( w==42 ) + { + r = -1.801e+00; + } + if( w==41 ) + { + r = -1.888e+00; + } + if( w==40 ) + { + r = -1.977e+00; + } + if( w==39 ) + { + r = -2.070e+00; + } + if( w==38 ) + { + r = -2.166e+00; + } + if( w==37 ) + { + r = -2.265e+00; + } + if( w==36 ) + { + r = -2.366e+00; + } + if( w==35 ) + { + r = -2.472e+00; + } + if( w==34 ) + { + r = -2.581e+00; + } + if( w==33 ) + { + r = -2.693e+00; + } + if( w==32 ) + { + r = -2.809e+00; + } + if( w==31 ) + { + r = -2.928e+00; + } + if( w==30 ) + { + r = -3.051e+00; + } + if( w==29 ) + { + r = -3.179e+00; + } + if( w==28 ) + { + r = -3.310e+00; + } + if( w==27 ) + { + r = -3.446e+00; + } + if( w==26 ) + { + r = -3.587e+00; + } + if( w==25 ) + { + r = -3.732e+00; + } + if( w==24 ) + { + r = -3.881e+00; + } + if( w==23 ) + { + r = -4.036e+00; + } + if( w==22 ) + { + r = -4.195e+00; + } + if( w==21 ) + { + r = -4.359e+00; + } + if( w==20 ) + { + r = -4.531e+00; + } + if( w==19 ) + { + r = -4.707e+00; + } + if( w==18 ) + { + r = -4.888e+00; + } + if( w==17 ) + { + r = -5.079e+00; + } + if( w==16 ) + { + r = -5.273e+00; + } + if( w==15 ) + { + r = -5.477e+00; + } + if( w==14 ) + { + r = -5.697e+00; + } + if( w==13 ) + { + r = -5.920e+00; + } + if( w==12 ) + { + r = -6.149e+00; + } + if( w==11 ) + { + r = -6.390e+00; + } + if( w==10 ) + { + r = -6.636e+00; + } + if( w==9 ) + { + r = -6.901e+00; + } + if( w==8 ) + { + r = -7.178e+00; + } + if( w==7 ) + { + r = -7.453e+00; + } + if( w==6 ) + { + r = -7.758e+00; + } + if( w==5 ) + { + r = -8.095e+00; + } + if( w==4 ) + { + r = -8.451e+00; + } + if( w==3 ) + { + r = -8.788e+00; + } + if( w==2 ) + { + r = -9.299e+00; + } + if( w==1 ) + { + r = -9.704e+00; + } + if( w<=0 ) + { + r = -1.040e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 16) +*************************************************************************/ +static double wsr_w16(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-1.933908e+01*s+6.800000e+01, _state); + if( w>=68 ) + { + r = -6.733e-01; + } + if( w==67 ) + { + r = -7.134e-01; + } + if( w==66 ) + { + r = -7.551e-01; + } + if( w==65 ) + { + r = -7.986e-01; + } + if( w==64 ) + { + r = -8.437e-01; + } + if( w==63 ) + { + r = -8.905e-01; + } + if( w==62 ) + { + r = -9.391e-01; + } + if( w==61 ) + { + r = -9.895e-01; + } + if( w==60 ) + { + r = -1.042e+00; + } + if( w==59 ) + { + r = -1.096e+00; + } + if( w==58 ) + { + r = -1.152e+00; + } + if( w==57 ) + { + r = -1.210e+00; + } + if( w==56 ) + { + r = -1.270e+00; + } + if( w==55 ) + { + r = -1.331e+00; + } + if( w==54 ) + { + r = -1.395e+00; + } + if( w==53 ) + { + r = -1.462e+00; + } + if( w==52 ) + { + r = -1.530e+00; + } + if( w==51 ) + { + r = -1.600e+00; + } + if( w==50 ) + { + r = -1.673e+00; + } + if( w==49 ) + { + r = -1.748e+00; + } + if( w==48 ) + { + r = -1.825e+00; + } + if( w==47 ) + { + r = -1.904e+00; + } + if( w==46 ) + { + r = -1.986e+00; + } + if( w==45 ) + { + r = -2.071e+00; + } + if( w==44 ) + { + r = -2.158e+00; + } + if( w==43 ) + { + r = -2.247e+00; + } + if( w==42 ) + { + r = -2.339e+00; + } + if( w==41 ) + { + r = -2.434e+00; + } + if( w==40 ) + { + r = -2.532e+00; + } + if( w==39 ) + { + r = -2.632e+00; + } + if( w==38 ) + { + r = -2.735e+00; + } + if( w==37 ) + { + r = -2.842e+00; + } + if( w==36 ) + { + r = -2.951e+00; + } + if( w==35 ) + { + r = -3.064e+00; + } + if( w==34 ) + { + r = -3.179e+00; + } + if( w==33 ) + { + r = -3.298e+00; + } + if( w==32 ) + { + r = -3.420e+00; + } + if( w==31 ) + { + r = -3.546e+00; + } + if( w==30 ) + { + r = -3.676e+00; + } + if( w==29 ) + { + r = -3.810e+00; + } + if( w==28 ) + { + r = -3.947e+00; + } + if( w==27 ) + { + r = -4.088e+00; + } + if( w==26 ) + { + r = -4.234e+00; + } + if( w==25 ) + { + r = -4.383e+00; + } + if( w==24 ) + { + r = -4.538e+00; + } + if( w==23 ) + { + r = -4.697e+00; + } + if( w==22 ) + { + r = -4.860e+00; + } + if( w==21 ) + { + r = -5.029e+00; + } + if( w==20 ) + { + r = -5.204e+00; + } + if( w==19 ) + { + r = -5.383e+00; + } + if( w==18 ) + { + r = -5.569e+00; + } + if( w==17 ) + { + r = -5.762e+00; + } + if( w==16 ) + { + r = -5.960e+00; + } + if( w==15 ) + { + r = -6.170e+00; + } + if( w==14 ) + { + r = -6.390e+00; + } + if( w==13 ) + { + r = -6.613e+00; + } + if( w==12 ) + { + r = -6.842e+00; + } + if( w==11 ) + { + r = -7.083e+00; + } + if( w==10 ) + { + r = -7.329e+00; + } + if( w==9 ) + { + r = -7.594e+00; + } + if( w==8 ) + { + r = -7.871e+00; + } + if( w==7 ) + { + r = -8.146e+00; + } + if( w==6 ) + { + r = -8.451e+00; + } + if( w==5 ) + { + r = -8.788e+00; + } + if( w==4 ) + { + r = -9.144e+00; + } + if( w==3 ) + { + r = -9.481e+00; + } + if( w==2 ) + { + r = -9.992e+00; + } + if( w==1 ) + { + r = -1.040e+01; + } + if( w<=0 ) + { + r = -1.109e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 17) +*************************************************************************/ +static double wsr_w17(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-2.112463e+01*s+7.650000e+01, _state); + if( w>=76 ) + { + r = -6.931e-01; + } + if( w==75 ) + { + r = -7.306e-01; + } + if( w==74 ) + { + r = -7.695e-01; + } + if( w==73 ) + { + r = -8.097e-01; + } + if( w==72 ) + { + r = -8.514e-01; + } + if( w==71 ) + { + r = -8.946e-01; + } + if( w==70 ) + { + r = -9.392e-01; + } + if( w==69 ) + { + r = -9.853e-01; + } + if( w==68 ) + { + r = -1.033e+00; + } + if( w==67 ) + { + r = -1.082e+00; + } + if( w==66 ) + { + r = -1.133e+00; + } + if( w==65 ) + { + r = -1.185e+00; + } + if( w==64 ) + { + r = -1.240e+00; + } + if( w==63 ) + { + r = -1.295e+00; + } + if( w==62 ) + { + r = -1.353e+00; + } + if( w==61 ) + { + r = -1.412e+00; + } + if( w==60 ) + { + r = -1.473e+00; + } + if( w==59 ) + { + r = -1.536e+00; + } + if( w==58 ) + { + r = -1.600e+00; + } + if( w==57 ) + { + r = -1.666e+00; + } + if( w==56 ) + { + r = -1.735e+00; + } + if( w==55 ) + { + r = -1.805e+00; + } + if( w==54 ) + { + r = -1.877e+00; + } + if( w==53 ) + { + r = -1.951e+00; + } + if( w==52 ) + { + r = -2.028e+00; + } + if( w==51 ) + { + r = -2.106e+00; + } + if( w==50 ) + { + r = -2.186e+00; + } + if( w==49 ) + { + r = -2.269e+00; + } + if( w==48 ) + { + r = -2.353e+00; + } + if( w==47 ) + { + r = -2.440e+00; + } + if( w==46 ) + { + r = -2.530e+00; + } + if( w==45 ) + { + r = -2.621e+00; + } + if( w==44 ) + { + r = -2.715e+00; + } + if( w==43 ) + { + r = -2.812e+00; + } + if( w==42 ) + { + r = -2.911e+00; + } + if( w==41 ) + { + r = -3.012e+00; + } + if( w==40 ) + { + r = -3.116e+00; + } + if( w==39 ) + { + r = -3.223e+00; + } + if( w==38 ) + { + r = -3.332e+00; + } + if( w==37 ) + { + r = -3.445e+00; + } + if( w==36 ) + { + r = -3.560e+00; + } + if( w==35 ) + { + r = -3.678e+00; + } + if( w==34 ) + { + r = -3.799e+00; + } + if( w==33 ) + { + r = -3.924e+00; + } + if( w==32 ) + { + r = -4.052e+00; + } + if( w==31 ) + { + r = -4.183e+00; + } + if( w==30 ) + { + r = -4.317e+00; + } + if( w==29 ) + { + r = -4.456e+00; + } + if( w==28 ) + { + r = -4.597e+00; + } + if( w==27 ) + { + r = -4.743e+00; + } + if( w==26 ) + { + r = -4.893e+00; + } + if( w==25 ) + { + r = -5.047e+00; + } + if( w==24 ) + { + r = -5.204e+00; + } + if( w==23 ) + { + r = -5.367e+00; + } + if( w==22 ) + { + r = -5.534e+00; + } + if( w==21 ) + { + r = -5.706e+00; + } + if( w==20 ) + { + r = -5.884e+00; + } + if( w==19 ) + { + r = -6.066e+00; + } + if( w==18 ) + { + r = -6.254e+00; + } + if( w==17 ) + { + r = -6.451e+00; + } + if( w==16 ) + { + r = -6.654e+00; + } + if( w==15 ) + { + r = -6.864e+00; + } + if( w==14 ) + { + r = -7.083e+00; + } + if( w==13 ) + { + r = -7.306e+00; + } + if( w==12 ) + { + r = -7.535e+00; + } + if( w==11 ) + { + r = -7.776e+00; + } + if( w==10 ) + { + r = -8.022e+00; + } + if( w==9 ) + { + r = -8.287e+00; + } + if( w==8 ) + { + r = -8.565e+00; + } + if( w==7 ) + { + r = -8.839e+00; + } + if( w==6 ) + { + r = -9.144e+00; + } + if( w==5 ) + { + r = -9.481e+00; + } + if( w==4 ) + { + r = -9.838e+00; + } + if( w==3 ) + { + r = -1.017e+01; + } + if( w==2 ) + { + r = -1.068e+01; + } + if( w==1 ) + { + r = -1.109e+01; + } + if( w<=0 ) + { + r = -1.178e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 18) +*************************************************************************/ +static double wsr_w18(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-2.296193e+01*s+8.550000e+01, _state); + if( w>=85 ) + { + r = -6.931e-01; + } + if( w==84 ) + { + r = -7.276e-01; + } + if( w==83 ) + { + r = -7.633e-01; + } + if( w==82 ) + { + r = -8.001e-01; + } + if( w==81 ) + { + r = -8.381e-01; + } + if( w==80 ) + { + r = -8.774e-01; + } + if( w==79 ) + { + r = -9.179e-01; + } + if( w==78 ) + { + r = -9.597e-01; + } + if( w==77 ) + { + r = -1.003e+00; + } + if( w==76 ) + { + r = -1.047e+00; + } + if( w==75 ) + { + r = -1.093e+00; + } + if( w==74 ) + { + r = -1.140e+00; + } + if( w==73 ) + { + r = -1.188e+00; + } + if( w==72 ) + { + r = -1.238e+00; + } + if( w==71 ) + { + r = -1.289e+00; + } + if( w==70 ) + { + r = -1.342e+00; + } + if( w==69 ) + { + r = -1.396e+00; + } + if( w==68 ) + { + r = -1.452e+00; + } + if( w==67 ) + { + r = -1.509e+00; + } + if( w==66 ) + { + r = -1.568e+00; + } + if( w==65 ) + { + r = -1.628e+00; + } + if( w==64 ) + { + r = -1.690e+00; + } + if( w==63 ) + { + r = -1.753e+00; + } + if( w==62 ) + { + r = -1.818e+00; + } + if( w==61 ) + { + r = -1.885e+00; + } + if( w==60 ) + { + r = -1.953e+00; + } + if( w==59 ) + { + r = -2.023e+00; + } + if( w==58 ) + { + r = -2.095e+00; + } + if( w==57 ) + { + r = -2.168e+00; + } + if( w==56 ) + { + r = -2.244e+00; + } + if( w==55 ) + { + r = -2.321e+00; + } + if( w==54 ) + { + r = -2.400e+00; + } + if( w==53 ) + { + r = -2.481e+00; + } + if( w==52 ) + { + r = -2.564e+00; + } + if( w==51 ) + { + r = -2.648e+00; + } + if( w==50 ) + { + r = -2.735e+00; + } + if( w==49 ) + { + r = -2.824e+00; + } + if( w==48 ) + { + r = -2.915e+00; + } + if( w==47 ) + { + r = -3.008e+00; + } + if( w==46 ) + { + r = -3.104e+00; + } + if( w==45 ) + { + r = -3.201e+00; + } + if( w==44 ) + { + r = -3.301e+00; + } + if( w==43 ) + { + r = -3.403e+00; + } + if( w==42 ) + { + r = -3.508e+00; + } + if( w==41 ) + { + r = -3.615e+00; + } + if( w==40 ) + { + r = -3.724e+00; + } + if( w==39 ) + { + r = -3.836e+00; + } + if( w==38 ) + { + r = -3.950e+00; + } + if( w==37 ) + { + r = -4.068e+00; + } + if( w==36 ) + { + r = -4.188e+00; + } + if( w==35 ) + { + r = -4.311e+00; + } + if( w==34 ) + { + r = -4.437e+00; + } + if( w==33 ) + { + r = -4.565e+00; + } + if( w==32 ) + { + r = -4.698e+00; + } + if( w==31 ) + { + r = -4.833e+00; + } + if( w==30 ) + { + r = -4.971e+00; + } + if( w==29 ) + { + r = -5.113e+00; + } + if( w==28 ) + { + r = -5.258e+00; + } + if( w==27 ) + { + r = -5.408e+00; + } + if( w==26 ) + { + r = -5.561e+00; + } + if( w==25 ) + { + r = -5.717e+00; + } + if( w==24 ) + { + r = -5.878e+00; + } + if( w==23 ) + { + r = -6.044e+00; + } + if( w==22 ) + { + r = -6.213e+00; + } + if( w==21 ) + { + r = -6.388e+00; + } + if( w==20 ) + { + r = -6.569e+00; + } + if( w==19 ) + { + r = -6.753e+00; + } + if( w==18 ) + { + r = -6.943e+00; + } + if( w==17 ) + { + r = -7.144e+00; + } + if( w==16 ) + { + r = -7.347e+00; + } + if( w==15 ) + { + r = -7.557e+00; + } + if( w==14 ) + { + r = -7.776e+00; + } + if( w==13 ) + { + r = -7.999e+00; + } + if( w==12 ) + { + r = -8.228e+00; + } + if( w==11 ) + { + r = -8.469e+00; + } + if( w==10 ) + { + r = -8.715e+00; + } + if( w==9 ) + { + r = -8.980e+00; + } + if( w==8 ) + { + r = -9.258e+00; + } + if( w==7 ) + { + r = -9.532e+00; + } + if( w==6 ) + { + r = -9.838e+00; + } + if( w==5 ) + { + r = -1.017e+01; + } + if( w==4 ) + { + r = -1.053e+01; + } + if( w==3 ) + { + r = -1.087e+01; + } + if( w==2 ) + { + r = -1.138e+01; + } + if( w==1 ) + { + r = -1.178e+01; + } + if( w<=0 ) + { + r = -1.248e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 19) +*************************************************************************/ +static double wsr_w19(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-2.484955e+01*s+9.500000e+01, _state); + if( w>=95 ) + { + r = -6.776e-01; + } + if( w==94 ) + { + r = -7.089e-01; + } + if( w==93 ) + { + r = -7.413e-01; + } + if( w==92 ) + { + r = -7.747e-01; + } + if( w==91 ) + { + r = -8.090e-01; + } + if( w==90 ) + { + r = -8.445e-01; + } + if( w==89 ) + { + r = -8.809e-01; + } + if( w==88 ) + { + r = -9.185e-01; + } + if( w==87 ) + { + r = -9.571e-01; + } + if( w==86 ) + { + r = -9.968e-01; + } + if( w==85 ) + { + r = -1.038e+00; + } + if( w==84 ) + { + r = -1.080e+00; + } + if( w==83 ) + { + r = -1.123e+00; + } + if( w==82 ) + { + r = -1.167e+00; + } + if( w==81 ) + { + r = -1.213e+00; + } + if( w==80 ) + { + r = -1.259e+00; + } + if( w==79 ) + { + r = -1.307e+00; + } + if( w==78 ) + { + r = -1.356e+00; + } + if( w==77 ) + { + r = -1.407e+00; + } + if( w==76 ) + { + r = -1.458e+00; + } + if( w==75 ) + { + r = -1.511e+00; + } + if( w==74 ) + { + r = -1.565e+00; + } + if( w==73 ) + { + r = -1.621e+00; + } + if( w==72 ) + { + r = -1.678e+00; + } + if( w==71 ) + { + r = -1.736e+00; + } + if( w==70 ) + { + r = -1.796e+00; + } + if( w==69 ) + { + r = -1.857e+00; + } + if( w==68 ) + { + r = -1.919e+00; + } + if( w==67 ) + { + r = -1.983e+00; + } + if( w==66 ) + { + r = -2.048e+00; + } + if( w==65 ) + { + r = -2.115e+00; + } + if( w==64 ) + { + r = -2.183e+00; + } + if( w==63 ) + { + r = -2.253e+00; + } + if( w==62 ) + { + r = -2.325e+00; + } + if( w==61 ) + { + r = -2.398e+00; + } + if( w==60 ) + { + r = -2.472e+00; + } + if( w==59 ) + { + r = -2.548e+00; + } + if( w==58 ) + { + r = -2.626e+00; + } + if( w==57 ) + { + r = -2.706e+00; + } + if( w==56 ) + { + r = -2.787e+00; + } + if( w==55 ) + { + r = -2.870e+00; + } + if( w==54 ) + { + r = -2.955e+00; + } + if( w==53 ) + { + r = -3.042e+00; + } + if( w==52 ) + { + r = -3.130e+00; + } + if( w==51 ) + { + r = -3.220e+00; + } + if( w==50 ) + { + r = -3.313e+00; + } + if( w==49 ) + { + r = -3.407e+00; + } + if( w==48 ) + { + r = -3.503e+00; + } + if( w==47 ) + { + r = -3.601e+00; + } + if( w==46 ) + { + r = -3.702e+00; + } + if( w==45 ) + { + r = -3.804e+00; + } + if( w==44 ) + { + r = -3.909e+00; + } + if( w==43 ) + { + r = -4.015e+00; + } + if( w==42 ) + { + r = -4.125e+00; + } + if( w==41 ) + { + r = -4.236e+00; + } + if( w==40 ) + { + r = -4.350e+00; + } + if( w==39 ) + { + r = -4.466e+00; + } + if( w==38 ) + { + r = -4.585e+00; + } + if( w==37 ) + { + r = -4.706e+00; + } + if( w==36 ) + { + r = -4.830e+00; + } + if( w==35 ) + { + r = -4.957e+00; + } + if( w==34 ) + { + r = -5.086e+00; + } + if( w==33 ) + { + r = -5.219e+00; + } + if( w==32 ) + { + r = -5.355e+00; + } + if( w==31 ) + { + r = -5.493e+00; + } + if( w==30 ) + { + r = -5.634e+00; + } + if( w==29 ) + { + r = -5.780e+00; + } + if( w==28 ) + { + r = -5.928e+00; + } + if( w==27 ) + { + r = -6.080e+00; + } + if( w==26 ) + { + r = -6.235e+00; + } + if( w==25 ) + { + r = -6.394e+00; + } + if( w==24 ) + { + r = -6.558e+00; + } + if( w==23 ) + { + r = -6.726e+00; + } + if( w==22 ) + { + r = -6.897e+00; + } + if( w==21 ) + { + r = -7.074e+00; + } + if( w==20 ) + { + r = -7.256e+00; + } + if( w==19 ) + { + r = -7.443e+00; + } + if( w==18 ) + { + r = -7.636e+00; + } + if( w==17 ) + { + r = -7.837e+00; + } + if( w==16 ) + { + r = -8.040e+00; + } + if( w==15 ) + { + r = -8.250e+00; + } + if( w==14 ) + { + r = -8.469e+00; + } + if( w==13 ) + { + r = -8.692e+00; + } + if( w==12 ) + { + r = -8.921e+00; + } + if( w==11 ) + { + r = -9.162e+00; + } + if( w==10 ) + { + r = -9.409e+00; + } + if( w==9 ) + { + r = -9.673e+00; + } + if( w==8 ) + { + r = -9.951e+00; + } + if( w==7 ) + { + r = -1.023e+01; + } + if( w==6 ) + { + r = -1.053e+01; + } + if( w==5 ) + { + r = -1.087e+01; + } + if( w==4 ) + { + r = -1.122e+01; + } + if( w==3 ) + { + r = -1.156e+01; + } + if( w==2 ) + { + r = -1.207e+01; + } + if( w==1 ) + { + r = -1.248e+01; + } + if( w<=0 ) + { + r = -1.317e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 20) +*************************************************************************/ +static double wsr_w20(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-2.678619e+01*s+1.050000e+02, _state); + if( w>=105 ) + { + r = -6.787e-01; + } + if( w==104 ) + { + r = -7.078e-01; + } + if( w==103 ) + { + r = -7.378e-01; + } + if( w==102 ) + { + r = -7.686e-01; + } + if( w==101 ) + { + r = -8.004e-01; + } + if( w==100 ) + { + r = -8.330e-01; + } + if( w==99 ) + { + r = -8.665e-01; + } + if( w==98 ) + { + r = -9.010e-01; + } + if( w==97 ) + { + r = -9.363e-01; + } + if( w==96 ) + { + r = -9.726e-01; + } + if( w==95 ) + { + r = -1.010e+00; + } + if( w==94 ) + { + r = -1.048e+00; + } + if( w==93 ) + { + r = -1.087e+00; + } + if( w==92 ) + { + r = -1.128e+00; + } + if( w==91 ) + { + r = -1.169e+00; + } + if( w==90 ) + { + r = -1.211e+00; + } + if( w==89 ) + { + r = -1.254e+00; + } + if( w==88 ) + { + r = -1.299e+00; + } + if( w==87 ) + { + r = -1.344e+00; + } + if( w==86 ) + { + r = -1.390e+00; + } + if( w==85 ) + { + r = -1.438e+00; + } + if( w==84 ) + { + r = -1.486e+00; + } + if( w==83 ) + { + r = -1.536e+00; + } + if( w==82 ) + { + r = -1.587e+00; + } + if( w==81 ) + { + r = -1.639e+00; + } + if( w==80 ) + { + r = -1.692e+00; + } + if( w==79 ) + { + r = -1.746e+00; + } + if( w==78 ) + { + r = -1.802e+00; + } + if( w==77 ) + { + r = -1.859e+00; + } + if( w==76 ) + { + r = -1.916e+00; + } + if( w==75 ) + { + r = -1.976e+00; + } + if( w==74 ) + { + r = -2.036e+00; + } + if( w==73 ) + { + r = -2.098e+00; + } + if( w==72 ) + { + r = -2.161e+00; + } + if( w==71 ) + { + r = -2.225e+00; + } + if( w==70 ) + { + r = -2.290e+00; + } + if( w==69 ) + { + r = -2.357e+00; + } + if( w==68 ) + { + r = -2.426e+00; + } + if( w==67 ) + { + r = -2.495e+00; + } + if( w==66 ) + { + r = -2.566e+00; + } + if( w==65 ) + { + r = -2.639e+00; + } + if( w==64 ) + { + r = -2.713e+00; + } + if( w==63 ) + { + r = -2.788e+00; + } + if( w==62 ) + { + r = -2.865e+00; + } + if( w==61 ) + { + r = -2.943e+00; + } + if( w==60 ) + { + r = -3.023e+00; + } + if( w==59 ) + { + r = -3.104e+00; + } + if( w==58 ) + { + r = -3.187e+00; + } + if( w==57 ) + { + r = -3.272e+00; + } + if( w==56 ) + { + r = -3.358e+00; + } + if( w==55 ) + { + r = -3.446e+00; + } + if( w==54 ) + { + r = -3.536e+00; + } + if( w==53 ) + { + r = -3.627e+00; + } + if( w==52 ) + { + r = -3.721e+00; + } + if( w==51 ) + { + r = -3.815e+00; + } + if( w==50 ) + { + r = -3.912e+00; + } + if( w==49 ) + { + r = -4.011e+00; + } + if( w==48 ) + { + r = -4.111e+00; + } + if( w==47 ) + { + r = -4.214e+00; + } + if( w==46 ) + { + r = -4.318e+00; + } + if( w==45 ) + { + r = -4.425e+00; + } + if( w==44 ) + { + r = -4.534e+00; + } + if( w==43 ) + { + r = -4.644e+00; + } + if( w==42 ) + { + r = -4.757e+00; + } + if( w==41 ) + { + r = -4.872e+00; + } + if( w==40 ) + { + r = -4.990e+00; + } + if( w==39 ) + { + r = -5.109e+00; + } + if( w==38 ) + { + r = -5.232e+00; + } + if( w==37 ) + { + r = -5.356e+00; + } + if( w==36 ) + { + r = -5.484e+00; + } + if( w==35 ) + { + r = -5.614e+00; + } + if( w==34 ) + { + r = -5.746e+00; + } + if( w==33 ) + { + r = -5.882e+00; + } + if( w==32 ) + { + r = -6.020e+00; + } + if( w==31 ) + { + r = -6.161e+00; + } + if( w==30 ) + { + r = -6.305e+00; + } + if( w==29 ) + { + r = -6.453e+00; + } + if( w==28 ) + { + r = -6.603e+00; + } + if( w==27 ) + { + r = -6.757e+00; + } + if( w==26 ) + { + r = -6.915e+00; + } + if( w==25 ) + { + r = -7.076e+00; + } + if( w==24 ) + { + r = -7.242e+00; + } + if( w==23 ) + { + r = -7.411e+00; + } + if( w==22 ) + { + r = -7.584e+00; + } + if( w==21 ) + { + r = -7.763e+00; + } + if( w==20 ) + { + r = -7.947e+00; + } + if( w==19 ) + { + r = -8.136e+00; + } + if( w==18 ) + { + r = -8.330e+00; + } + if( w==17 ) + { + r = -8.530e+00; + } + if( w==16 ) + { + r = -8.733e+00; + } + if( w==15 ) + { + r = -8.943e+00; + } + if( w==14 ) + { + r = -9.162e+00; + } + if( w==13 ) + { + r = -9.386e+00; + } + if( w==12 ) + { + r = -9.614e+00; + } + if( w==11 ) + { + r = -9.856e+00; + } + if( w==10 ) + { + r = -1.010e+01; + } + if( w==9 ) + { + r = -1.037e+01; + } + if( w==8 ) + { + r = -1.064e+01; + } + if( w==7 ) + { + r = -1.092e+01; + } + if( w==6 ) + { + r = -1.122e+01; + } + if( w==5 ) + { + r = -1.156e+01; + } + if( w==4 ) + { + r = -1.192e+01; + } + if( w==3 ) + { + r = -1.225e+01; + } + if( w==2 ) + { + r = -1.276e+01; + } + if( w==1 ) + { + r = -1.317e+01; + } + if( w<=0 ) + { + r = -1.386e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 21) +*************************************************************************/ +static double wsr_w21(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-2.877064e+01*s+1.155000e+02, _state); + if( w>=115 ) + { + r = -6.931e-01; + } + if( w==114 ) + { + r = -7.207e-01; + } + if( w==113 ) + { + r = -7.489e-01; + } + if( w==112 ) + { + r = -7.779e-01; + } + if( w==111 ) + { + r = -8.077e-01; + } + if( w==110 ) + { + r = -8.383e-01; + } + if( w==109 ) + { + r = -8.697e-01; + } + if( w==108 ) + { + r = -9.018e-01; + } + if( w==107 ) + { + r = -9.348e-01; + } + if( w==106 ) + { + r = -9.685e-01; + } + if( w==105 ) + { + r = -1.003e+00; + } + if( w==104 ) + { + r = -1.039e+00; + } + if( w==103 ) + { + r = -1.075e+00; + } + if( w==102 ) + { + r = -1.112e+00; + } + if( w==101 ) + { + r = -1.150e+00; + } + if( w==100 ) + { + r = -1.189e+00; + } + if( w==99 ) + { + r = -1.229e+00; + } + if( w==98 ) + { + r = -1.269e+00; + } + if( w==97 ) + { + r = -1.311e+00; + } + if( w==96 ) + { + r = -1.353e+00; + } + if( w==95 ) + { + r = -1.397e+00; + } + if( w==94 ) + { + r = -1.441e+00; + } + if( w==93 ) + { + r = -1.486e+00; + } + if( w==92 ) + { + r = -1.533e+00; + } + if( w==91 ) + { + r = -1.580e+00; + } + if( w==90 ) + { + r = -1.628e+00; + } + if( w==89 ) + { + r = -1.677e+00; + } + if( w==88 ) + { + r = -1.728e+00; + } + if( w==87 ) + { + r = -1.779e+00; + } + if( w==86 ) + { + r = -1.831e+00; + } + if( w==85 ) + { + r = -1.884e+00; + } + if( w==84 ) + { + r = -1.939e+00; + } + if( w==83 ) + { + r = -1.994e+00; + } + if( w==82 ) + { + r = -2.051e+00; + } + if( w==81 ) + { + r = -2.108e+00; + } + if( w==80 ) + { + r = -2.167e+00; + } + if( w==79 ) + { + r = -2.227e+00; + } + if( w==78 ) + { + r = -2.288e+00; + } + if( w==77 ) + { + r = -2.350e+00; + } + if( w==76 ) + { + r = -2.414e+00; + } + if( w==75 ) + { + r = -2.478e+00; + } + if( w==74 ) + { + r = -2.544e+00; + } + if( w==73 ) + { + r = -2.611e+00; + } + if( w==72 ) + { + r = -2.679e+00; + } + if( w==71 ) + { + r = -2.748e+00; + } + if( w==70 ) + { + r = -2.819e+00; + } + if( w==69 ) + { + r = -2.891e+00; + } + if( w==68 ) + { + r = -2.964e+00; + } + if( w==67 ) + { + r = -3.039e+00; + } + if( w==66 ) + { + r = -3.115e+00; + } + if( w==65 ) + { + r = -3.192e+00; + } + if( w==64 ) + { + r = -3.270e+00; + } + if( w==63 ) + { + r = -3.350e+00; + } + if( w==62 ) + { + r = -3.432e+00; + } + if( w==61 ) + { + r = -3.515e+00; + } + if( w==60 ) + { + r = -3.599e+00; + } + if( w==59 ) + { + r = -3.685e+00; + } + if( w==58 ) + { + r = -3.772e+00; + } + if( w==57 ) + { + r = -3.861e+00; + } + if( w==56 ) + { + r = -3.952e+00; + } + if( w==55 ) + { + r = -4.044e+00; + } + if( w==54 ) + { + r = -4.138e+00; + } + if( w==53 ) + { + r = -4.233e+00; + } + if( w==52 ) + { + r = -4.330e+00; + } + if( w==51 ) + { + r = -4.429e+00; + } + if( w==50 ) + { + r = -4.530e+00; + } + if( w==49 ) + { + r = -4.632e+00; + } + if( w==48 ) + { + r = -4.736e+00; + } + if( w==47 ) + { + r = -4.842e+00; + } + if( w==46 ) + { + r = -4.950e+00; + } + if( w==45 ) + { + r = -5.060e+00; + } + if( w==44 ) + { + r = -5.172e+00; + } + if( w==43 ) + { + r = -5.286e+00; + } + if( w==42 ) + { + r = -5.402e+00; + } + if( w==41 ) + { + r = -5.520e+00; + } + if( w==40 ) + { + r = -5.641e+00; + } + if( w==39 ) + { + r = -5.763e+00; + } + if( w==38 ) + { + r = -5.889e+00; + } + if( w==37 ) + { + r = -6.016e+00; + } + if( w==36 ) + { + r = -6.146e+00; + } + if( w==35 ) + { + r = -6.278e+00; + } + if( w==34 ) + { + r = -6.413e+00; + } + if( w==33 ) + { + r = -6.551e+00; + } + if( w==32 ) + { + r = -6.692e+00; + } + if( w==31 ) + { + r = -6.835e+00; + } + if( w==30 ) + { + r = -6.981e+00; + } + if( w==29 ) + { + r = -7.131e+00; + } + if( w==28 ) + { + r = -7.283e+00; + } + if( w==27 ) + { + r = -7.439e+00; + } + if( w==26 ) + { + r = -7.599e+00; + } + if( w==25 ) + { + r = -7.762e+00; + } + if( w==24 ) + { + r = -7.928e+00; + } + if( w==23 ) + { + r = -8.099e+00; + } + if( w==22 ) + { + r = -8.274e+00; + } + if( w==21 ) + { + r = -8.454e+00; + } + if( w==20 ) + { + r = -8.640e+00; + } + if( w==19 ) + { + r = -8.829e+00; + } + if( w==18 ) + { + r = -9.023e+00; + } + if( w==17 ) + { + r = -9.223e+00; + } + if( w==16 ) + { + r = -9.426e+00; + } + if( w==15 ) + { + r = -9.636e+00; + } + if( w==14 ) + { + r = -9.856e+00; + } + if( w==13 ) + { + r = -1.008e+01; + } + if( w==12 ) + { + r = -1.031e+01; + } + if( w==11 ) + { + r = -1.055e+01; + } + if( w==10 ) + { + r = -1.079e+01; + } + if( w==9 ) + { + r = -1.106e+01; + } + if( w==8 ) + { + r = -1.134e+01; + } + if( w==7 ) + { + r = -1.161e+01; + } + if( w==6 ) + { + r = -1.192e+01; + } + if( w==5 ) + { + r = -1.225e+01; + } + if( w==4 ) + { + r = -1.261e+01; + } + if( w==3 ) + { + r = -1.295e+01; + } + if( w==2 ) + { + r = -1.346e+01; + } + if( w==1 ) + { + r = -1.386e+01; + } + if( w<=0 ) + { + r = -1.456e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 22) +*************************************************************************/ +static double wsr_w22(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-3.080179e+01*s+1.265000e+02, _state); + if( w>=126 ) + { + r = -6.931e-01; + } + if( w==125 ) + { + r = -7.189e-01; + } + if( w==124 ) + { + r = -7.452e-01; + } + if( w==123 ) + { + r = -7.722e-01; + } + if( w==122 ) + { + r = -7.999e-01; + } + if( w==121 ) + { + r = -8.283e-01; + } + if( w==120 ) + { + r = -8.573e-01; + } + if( w==119 ) + { + r = -8.871e-01; + } + if( w==118 ) + { + r = -9.175e-01; + } + if( w==117 ) + { + r = -9.486e-01; + } + if( w==116 ) + { + r = -9.805e-01; + } + if( w==115 ) + { + r = -1.013e+00; + } + if( w==114 ) + { + r = -1.046e+00; + } + if( w==113 ) + { + r = -1.080e+00; + } + if( w==112 ) + { + r = -1.115e+00; + } + if( w==111 ) + { + r = -1.151e+00; + } + if( w==110 ) + { + r = -1.187e+00; + } + if( w==109 ) + { + r = -1.224e+00; + } + if( w==108 ) + { + r = -1.262e+00; + } + if( w==107 ) + { + r = -1.301e+00; + } + if( w==106 ) + { + r = -1.340e+00; + } + if( w==105 ) + { + r = -1.381e+00; + } + if( w==104 ) + { + r = -1.422e+00; + } + if( w==103 ) + { + r = -1.464e+00; + } + if( w==102 ) + { + r = -1.506e+00; + } + if( w==101 ) + { + r = -1.550e+00; + } + if( w==100 ) + { + r = -1.594e+00; + } + if( w==99 ) + { + r = -1.640e+00; + } + if( w==98 ) + { + r = -1.686e+00; + } + if( w==97 ) + { + r = -1.733e+00; + } + if( w==96 ) + { + r = -1.781e+00; + } + if( w==95 ) + { + r = -1.830e+00; + } + if( w==94 ) + { + r = -1.880e+00; + } + if( w==93 ) + { + r = -1.930e+00; + } + if( w==92 ) + { + r = -1.982e+00; + } + if( w==91 ) + { + r = -2.034e+00; + } + if( w==90 ) + { + r = -2.088e+00; + } + if( w==89 ) + { + r = -2.142e+00; + } + if( w==88 ) + { + r = -2.198e+00; + } + if( w==87 ) + { + r = -2.254e+00; + } + if( w==86 ) + { + r = -2.312e+00; + } + if( w==85 ) + { + r = -2.370e+00; + } + if( w==84 ) + { + r = -2.429e+00; + } + if( w==83 ) + { + r = -2.490e+00; + } + if( w==82 ) + { + r = -2.551e+00; + } + if( w==81 ) + { + r = -2.614e+00; + } + if( w==80 ) + { + r = -2.677e+00; + } + if( w==79 ) + { + r = -2.742e+00; + } + if( w==78 ) + { + r = -2.808e+00; + } + if( w==77 ) + { + r = -2.875e+00; + } + if( w==76 ) + { + r = -2.943e+00; + } + if( w==75 ) + { + r = -3.012e+00; + } + if( w==74 ) + { + r = -3.082e+00; + } + if( w==73 ) + { + r = -3.153e+00; + } + if( w==72 ) + { + r = -3.226e+00; + } + if( w==71 ) + { + r = -3.300e+00; + } + if( w==70 ) + { + r = -3.375e+00; + } + if( w==69 ) + { + r = -3.451e+00; + } + if( w==68 ) + { + r = -3.529e+00; + } + if( w==67 ) + { + r = -3.607e+00; + } + if( w==66 ) + { + r = -3.687e+00; + } + if( w==65 ) + { + r = -3.769e+00; + } + if( w==64 ) + { + r = -3.851e+00; + } + if( w==63 ) + { + r = -3.935e+00; + } + if( w==62 ) + { + r = -4.021e+00; + } + if( w==61 ) + { + r = -4.108e+00; + } + if( w==60 ) + { + r = -4.196e+00; + } + if( w==59 ) + { + r = -4.285e+00; + } + if( w==58 ) + { + r = -4.376e+00; + } + if( w==57 ) + { + r = -4.469e+00; + } + if( w==56 ) + { + r = -4.563e+00; + } + if( w==55 ) + { + r = -4.659e+00; + } + if( w==54 ) + { + r = -4.756e+00; + } + if( w==53 ) + { + r = -4.855e+00; + } + if( w==52 ) + { + r = -4.955e+00; + } + if( w==51 ) + { + r = -5.057e+00; + } + if( w==50 ) + { + r = -5.161e+00; + } + if( w==49 ) + { + r = -5.266e+00; + } + if( w==48 ) + { + r = -5.374e+00; + } + if( w==47 ) + { + r = -5.483e+00; + } + if( w==46 ) + { + r = -5.594e+00; + } + if( w==45 ) + { + r = -5.706e+00; + } + if( w==44 ) + { + r = -5.821e+00; + } + if( w==43 ) + { + r = -5.938e+00; + } + if( w==42 ) + { + r = -6.057e+00; + } + if( w==41 ) + { + r = -6.177e+00; + } + if( w==40 ) + { + r = -6.300e+00; + } + if( w==39 ) + { + r = -6.426e+00; + } + if( w==38 ) + { + r = -6.553e+00; + } + if( w==37 ) + { + r = -6.683e+00; + } + if( w==36 ) + { + r = -6.815e+00; + } + if( w==35 ) + { + r = -6.949e+00; + } + if( w==34 ) + { + r = -7.086e+00; + } + if( w==33 ) + { + r = -7.226e+00; + } + if( w==32 ) + { + r = -7.368e+00; + } + if( w==31 ) + { + r = -7.513e+00; + } + if( w==30 ) + { + r = -7.661e+00; + } + if( w==29 ) + { + r = -7.813e+00; + } + if( w==28 ) + { + r = -7.966e+00; + } + if( w==27 ) + { + r = -8.124e+00; + } + if( w==26 ) + { + r = -8.285e+00; + } + if( w==25 ) + { + r = -8.449e+00; + } + if( w==24 ) + { + r = -8.617e+00; + } + if( w==23 ) + { + r = -8.789e+00; + } + if( w==22 ) + { + r = -8.965e+00; + } + if( w==21 ) + { + r = -9.147e+00; + } + if( w==20 ) + { + r = -9.333e+00; + } + if( w==19 ) + { + r = -9.522e+00; + } + if( w==18 ) + { + r = -9.716e+00; + } + if( w==17 ) + { + r = -9.917e+00; + } + if( w==16 ) + { + r = -1.012e+01; + } + if( w==15 ) + { + r = -1.033e+01; + } + if( w==14 ) + { + r = -1.055e+01; + } + if( w==13 ) + { + r = -1.077e+01; + } + if( w==12 ) + { + r = -1.100e+01; + } + if( w==11 ) + { + r = -1.124e+01; + } + if( w==10 ) + { + r = -1.149e+01; + } + if( w==9 ) + { + r = -1.175e+01; + } + if( w==8 ) + { + r = -1.203e+01; + } + if( w==7 ) + { + r = -1.230e+01; + } + if( w==6 ) + { + r = -1.261e+01; + } + if( w==5 ) + { + r = -1.295e+01; + } + if( w==4 ) + { + r = -1.330e+01; + } + if( w==3 ) + { + r = -1.364e+01; + } + if( w==2 ) + { + r = -1.415e+01; + } + if( w==1 ) + { + r = -1.456e+01; + } + if( w<=0 ) + { + r = -1.525e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 23) +*************************************************************************/ +static double wsr_w23(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-3.287856e+01*s+1.380000e+02, _state); + if( w>=138 ) + { + r = -6.813e-01; + } + if( w==137 ) + { + r = -7.051e-01; + } + if( w==136 ) + { + r = -7.295e-01; + } + if( w==135 ) + { + r = -7.544e-01; + } + if( w==134 ) + { + r = -7.800e-01; + } + if( w==133 ) + { + r = -8.061e-01; + } + if( w==132 ) + { + r = -8.328e-01; + } + if( w==131 ) + { + r = -8.601e-01; + } + if( w==130 ) + { + r = -8.880e-01; + } + if( w==129 ) + { + r = -9.166e-01; + } + if( w==128 ) + { + r = -9.457e-01; + } + if( w==127 ) + { + r = -9.755e-01; + } + if( w==126 ) + { + r = -1.006e+00; + } + if( w==125 ) + { + r = -1.037e+00; + } + if( w==124 ) + { + r = -1.069e+00; + } + if( w==123 ) + { + r = -1.101e+00; + } + if( w==122 ) + { + r = -1.134e+00; + } + if( w==121 ) + { + r = -1.168e+00; + } + if( w==120 ) + { + r = -1.202e+00; + } + if( w==119 ) + { + r = -1.237e+00; + } + if( w==118 ) + { + r = -1.273e+00; + } + if( w==117 ) + { + r = -1.309e+00; + } + if( w==116 ) + { + r = -1.347e+00; + } + if( w==115 ) + { + r = -1.384e+00; + } + if( w==114 ) + { + r = -1.423e+00; + } + if( w==113 ) + { + r = -1.462e+00; + } + if( w==112 ) + { + r = -1.502e+00; + } + if( w==111 ) + { + r = -1.543e+00; + } + if( w==110 ) + { + r = -1.585e+00; + } + if( w==109 ) + { + r = -1.627e+00; + } + if( w==108 ) + { + r = -1.670e+00; + } + if( w==107 ) + { + r = -1.714e+00; + } + if( w==106 ) + { + r = -1.758e+00; + } + if( w==105 ) + { + r = -1.804e+00; + } + if( w==104 ) + { + r = -1.850e+00; + } + if( w==103 ) + { + r = -1.897e+00; + } + if( w==102 ) + { + r = -1.944e+00; + } + if( w==101 ) + { + r = -1.993e+00; + } + if( w==100 ) + { + r = -2.042e+00; + } + if( w==99 ) + { + r = -2.093e+00; + } + if( w==98 ) + { + r = -2.144e+00; + } + if( w==97 ) + { + r = -2.195e+00; + } + if( w==96 ) + { + r = -2.248e+00; + } + if( w==95 ) + { + r = -2.302e+00; + } + if( w==94 ) + { + r = -2.356e+00; + } + if( w==93 ) + { + r = -2.412e+00; + } + if( w==92 ) + { + r = -2.468e+00; + } + if( w==91 ) + { + r = -2.525e+00; + } + if( w==90 ) + { + r = -2.583e+00; + } + if( w==89 ) + { + r = -2.642e+00; + } + if( w==88 ) + { + r = -2.702e+00; + } + if( w==87 ) + { + r = -2.763e+00; + } + if( w==86 ) + { + r = -2.825e+00; + } + if( w==85 ) + { + r = -2.888e+00; + } + if( w==84 ) + { + r = -2.951e+00; + } + if( w==83 ) + { + r = -3.016e+00; + } + if( w==82 ) + { + r = -3.082e+00; + } + if( w==81 ) + { + r = -3.149e+00; + } + if( w==80 ) + { + r = -3.216e+00; + } + if( w==79 ) + { + r = -3.285e+00; + } + if( w==78 ) + { + r = -3.355e+00; + } + if( w==77 ) + { + r = -3.426e+00; + } + if( w==76 ) + { + r = -3.498e+00; + } + if( w==75 ) + { + r = -3.571e+00; + } + if( w==74 ) + { + r = -3.645e+00; + } + if( w==73 ) + { + r = -3.721e+00; + } + if( w==72 ) + { + r = -3.797e+00; + } + if( w==71 ) + { + r = -3.875e+00; + } + if( w==70 ) + { + r = -3.953e+00; + } + if( w==69 ) + { + r = -4.033e+00; + } + if( w==68 ) + { + r = -4.114e+00; + } + if( w==67 ) + { + r = -4.197e+00; + } + if( w==66 ) + { + r = -4.280e+00; + } + if( w==65 ) + { + r = -4.365e+00; + } + if( w==64 ) + { + r = -4.451e+00; + } + if( w==63 ) + { + r = -4.539e+00; + } + if( w==62 ) + { + r = -4.628e+00; + } + if( w==61 ) + { + r = -4.718e+00; + } + if( w==60 ) + { + r = -4.809e+00; + } + if( w==59 ) + { + r = -4.902e+00; + } + if( w==58 ) + { + r = -4.996e+00; + } + if( w==57 ) + { + r = -5.092e+00; + } + if( w==56 ) + { + r = -5.189e+00; + } + if( w==55 ) + { + r = -5.287e+00; + } + if( w==54 ) + { + r = -5.388e+00; + } + if( w==53 ) + { + r = -5.489e+00; + } + if( w==52 ) + { + r = -5.592e+00; + } + if( w==51 ) + { + r = -5.697e+00; + } + if( w==50 ) + { + r = -5.804e+00; + } + if( w==49 ) + { + r = -5.912e+00; + } + if( w==48 ) + { + r = -6.022e+00; + } + if( w==47 ) + { + r = -6.133e+00; + } + if( w==46 ) + { + r = -6.247e+00; + } + if( w==45 ) + { + r = -6.362e+00; + } + if( w==44 ) + { + r = -6.479e+00; + } + if( w==43 ) + { + r = -6.598e+00; + } + if( w==42 ) + { + r = -6.719e+00; + } + if( w==41 ) + { + r = -6.842e+00; + } + if( w==40 ) + { + r = -6.967e+00; + } + if( w==39 ) + { + r = -7.094e+00; + } + if( w==38 ) + { + r = -7.224e+00; + } + if( w==37 ) + { + r = -7.355e+00; + } + if( w==36 ) + { + r = -7.489e+00; + } + if( w==35 ) + { + r = -7.625e+00; + } + if( w==34 ) + { + r = -7.764e+00; + } + if( w==33 ) + { + r = -7.905e+00; + } + if( w==32 ) + { + r = -8.049e+00; + } + if( w==31 ) + { + r = -8.196e+00; + } + if( w==30 ) + { + r = -8.345e+00; + } + if( w==29 ) + { + r = -8.498e+00; + } + if( w==28 ) + { + r = -8.653e+00; + } + if( w==27 ) + { + r = -8.811e+00; + } + if( w==26 ) + { + r = -8.974e+00; + } + if( w==25 ) + { + r = -9.139e+00; + } + if( w==24 ) + { + r = -9.308e+00; + } + if( w==23 ) + { + r = -9.481e+00; + } + if( w==22 ) + { + r = -9.658e+00; + } + if( w==21 ) + { + r = -9.840e+00; + } + if( w==20 ) + { + r = -1.003e+01; + } + if( w==19 ) + { + r = -1.022e+01; + } + if( w==18 ) + { + r = -1.041e+01; + } + if( w==17 ) + { + r = -1.061e+01; + } + if( w==16 ) + { + r = -1.081e+01; + } + if( w==15 ) + { + r = -1.102e+01; + } + if( w==14 ) + { + r = -1.124e+01; + } + if( w==13 ) + { + r = -1.147e+01; + } + if( w==12 ) + { + r = -1.169e+01; + } + if( w==11 ) + { + r = -1.194e+01; + } + if( w==10 ) + { + r = -1.218e+01; + } + if( w==9 ) + { + r = -1.245e+01; + } + if( w==8 ) + { + r = -1.272e+01; + } + if( w==7 ) + { + r = -1.300e+01; + } + if( w==6 ) + { + r = -1.330e+01; + } + if( w==5 ) + { + r = -1.364e+01; + } + if( w==4 ) + { + r = -1.400e+01; + } + if( w==3 ) + { + r = -1.433e+01; + } + if( w==2 ) + { + r = -1.484e+01; + } + if( w==1 ) + { + r = -1.525e+01; + } + if( w<=0 ) + { + r = -1.594e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 24) +*************************************************************************/ +static double wsr_w24(double s, ae_state *_state) +{ + ae_int_t w; + double r; + double result; + + + r = (double)(0); + w = ae_round(-3.500000e+01*s+1.500000e+02, _state); + if( w>=150 ) + { + r = -6.820e-01; + } + if( w==149 ) + { + r = -7.044e-01; + } + if( w==148 ) + { + r = -7.273e-01; + } + if( w==147 ) + { + r = -7.507e-01; + } + if( w==146 ) + { + r = -7.746e-01; + } + if( w==145 ) + { + r = -7.990e-01; + } + if( w==144 ) + { + r = -8.239e-01; + } + if( w==143 ) + { + r = -8.494e-01; + } + if( w==142 ) + { + r = -8.754e-01; + } + if( w==141 ) + { + r = -9.020e-01; + } + if( w==140 ) + { + r = -9.291e-01; + } + if( w==139 ) + { + r = -9.567e-01; + } + if( w==138 ) + { + r = -9.849e-01; + } + if( w==137 ) + { + r = -1.014e+00; + } + if( w==136 ) + { + r = -1.043e+00; + } + if( w==135 ) + { + r = -1.073e+00; + } + if( w==134 ) + { + r = -1.103e+00; + } + if( w==133 ) + { + r = -1.135e+00; + } + if( w==132 ) + { + r = -1.166e+00; + } + if( w==131 ) + { + r = -1.198e+00; + } + if( w==130 ) + { + r = -1.231e+00; + } + if( w==129 ) + { + r = -1.265e+00; + } + if( w==128 ) + { + r = -1.299e+00; + } + if( w==127 ) + { + r = -1.334e+00; + } + if( w==126 ) + { + r = -1.369e+00; + } + if( w==125 ) + { + r = -1.405e+00; + } + if( w==124 ) + { + r = -1.441e+00; + } + if( w==123 ) + { + r = -1.479e+00; + } + if( w==122 ) + { + r = -1.517e+00; + } + if( w==121 ) + { + r = -1.555e+00; + } + if( w==120 ) + { + r = -1.594e+00; + } + if( w==119 ) + { + r = -1.634e+00; + } + if( w==118 ) + { + r = -1.675e+00; + } + if( w==117 ) + { + r = -1.716e+00; + } + if( w==116 ) + { + r = -1.758e+00; + } + if( w==115 ) + { + r = -1.800e+00; + } + if( w==114 ) + { + r = -1.844e+00; + } + if( w==113 ) + { + r = -1.888e+00; + } + if( w==112 ) + { + r = -1.932e+00; + } + if( w==111 ) + { + r = -1.978e+00; + } + if( w==110 ) + { + r = -2.024e+00; + } + if( w==109 ) + { + r = -2.070e+00; + } + if( w==108 ) + { + r = -2.118e+00; + } + if( w==107 ) + { + r = -2.166e+00; + } + if( w==106 ) + { + r = -2.215e+00; + } + if( w==105 ) + { + r = -2.265e+00; + } + if( w==104 ) + { + r = -2.316e+00; + } + if( w==103 ) + { + r = -2.367e+00; + } + if( w==102 ) + { + r = -2.419e+00; + } + if( w==101 ) + { + r = -2.472e+00; + } + if( w==100 ) + { + r = -2.526e+00; + } + if( w==99 ) + { + r = -2.580e+00; + } + if( w==98 ) + { + r = -2.636e+00; + } + if( w==97 ) + { + r = -2.692e+00; + } + if( w==96 ) + { + r = -2.749e+00; + } + if( w==95 ) + { + r = -2.806e+00; + } + if( w==94 ) + { + r = -2.865e+00; + } + if( w==93 ) + { + r = -2.925e+00; + } + if( w==92 ) + { + r = -2.985e+00; + } + if( w==91 ) + { + r = -3.046e+00; + } + if( w==90 ) + { + r = -3.108e+00; + } + if( w==89 ) + { + r = -3.171e+00; + } + if( w==88 ) + { + r = -3.235e+00; + } + if( w==87 ) + { + r = -3.300e+00; + } + if( w==86 ) + { + r = -3.365e+00; + } + if( w==85 ) + { + r = -3.432e+00; + } + if( w==84 ) + { + r = -3.499e+00; + } + if( w==83 ) + { + r = -3.568e+00; + } + if( w==82 ) + { + r = -3.637e+00; + } + if( w==81 ) + { + r = -3.708e+00; + } + if( w==80 ) + { + r = -3.779e+00; + } + if( w==79 ) + { + r = -3.852e+00; + } + if( w==78 ) + { + r = -3.925e+00; + } + if( w==77 ) + { + r = -4.000e+00; + } + if( w==76 ) + { + r = -4.075e+00; + } + if( w==75 ) + { + r = -4.151e+00; + } + if( w==74 ) + { + r = -4.229e+00; + } + if( w==73 ) + { + r = -4.308e+00; + } + if( w==72 ) + { + r = -4.387e+00; + } + if( w==71 ) + { + r = -4.468e+00; + } + if( w==70 ) + { + r = -4.550e+00; + } + if( w==69 ) + { + r = -4.633e+00; + } + if( w==68 ) + { + r = -4.718e+00; + } + if( w==67 ) + { + r = -4.803e+00; + } + if( w==66 ) + { + r = -4.890e+00; + } + if( w==65 ) + { + r = -4.978e+00; + } + if( w==64 ) + { + r = -5.067e+00; + } + if( w==63 ) + { + r = -5.157e+00; + } + if( w==62 ) + { + r = -5.249e+00; + } + if( w==61 ) + { + r = -5.342e+00; + } + if( w==60 ) + { + r = -5.436e+00; + } + if( w==59 ) + { + r = -5.531e+00; + } + if( w==58 ) + { + r = -5.628e+00; + } + if( w==57 ) + { + r = -5.727e+00; + } + if( w==56 ) + { + r = -5.826e+00; + } + if( w==55 ) + { + r = -5.927e+00; + } + if( w==54 ) + { + r = -6.030e+00; + } + if( w==53 ) + { + r = -6.134e+00; + } + if( w==52 ) + { + r = -6.240e+00; + } + if( w==51 ) + { + r = -6.347e+00; + } + if( w==50 ) + { + r = -6.456e+00; + } + if( w==49 ) + { + r = -6.566e+00; + } + if( w==48 ) + { + r = -6.678e+00; + } + if( w==47 ) + { + r = -6.792e+00; + } + if( w==46 ) + { + r = -6.907e+00; + } + if( w==45 ) + { + r = -7.025e+00; + } + if( w==44 ) + { + r = -7.144e+00; + } + if( w==43 ) + { + r = -7.265e+00; + } + if( w==42 ) + { + r = -7.387e+00; + } + if( w==41 ) + { + r = -7.512e+00; + } + if( w==40 ) + { + r = -7.639e+00; + } + if( w==39 ) + { + r = -7.768e+00; + } + if( w==38 ) + { + r = -7.899e+00; + } + if( w==37 ) + { + r = -8.032e+00; + } + if( w==36 ) + { + r = -8.167e+00; + } + if( w==35 ) + { + r = -8.305e+00; + } + if( w==34 ) + { + r = -8.445e+00; + } + if( w==33 ) + { + r = -8.588e+00; + } + if( w==32 ) + { + r = -8.733e+00; + } + if( w==31 ) + { + r = -8.881e+00; + } + if( w==30 ) + { + r = -9.031e+00; + } + if( w==29 ) + { + r = -9.185e+00; + } + if( w==28 ) + { + r = -9.341e+00; + } + if( w==27 ) + { + r = -9.501e+00; + } + if( w==26 ) + { + r = -9.664e+00; + } + if( w==25 ) + { + r = -9.830e+00; + } + if( w==24 ) + { + r = -1.000e+01; + } + if( w==23 ) + { + r = -1.017e+01; + } + if( w==22 ) + { + r = -1.035e+01; + } + if( w==21 ) + { + r = -1.053e+01; + } + if( w==20 ) + { + r = -1.072e+01; + } + if( w==19 ) + { + r = -1.091e+01; + } + if( w==18 ) + { + r = -1.110e+01; + } + if( w==17 ) + { + r = -1.130e+01; + } + if( w==16 ) + { + r = -1.151e+01; + } + if( w==15 ) + { + r = -1.172e+01; + } + if( w==14 ) + { + r = -1.194e+01; + } + if( w==13 ) + { + r = -1.216e+01; + } + if( w==12 ) + { + r = -1.239e+01; + } + if( w==11 ) + { + r = -1.263e+01; + } + if( w==10 ) + { + r = -1.287e+01; + } + if( w==9 ) + { + r = -1.314e+01; + } + if( w==8 ) + { + r = -1.342e+01; + } + if( w==7 ) + { + r = -1.369e+01; + } + if( w==6 ) + { + r = -1.400e+01; + } + if( w==5 ) + { + r = -1.433e+01; + } + if( w==4 ) + { + r = -1.469e+01; + } + if( w==3 ) + { + r = -1.503e+01; + } + if( w==2 ) + { + r = -1.554e+01; + } + if( w==1 ) + { + r = -1.594e+01; + } + if( w<=0 ) + { + r = -1.664e+01; + } + result = r; + return result; +} + + +/************************************************************************* +Tail(S, 25) +*************************************************************************/ +static double wsr_w25(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.150509e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.695528e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.437637e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.611906e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -7.625722e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.579892e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.086876e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.906543e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.354881e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 1.007195e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -8.437327e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 26) +*************************************************************************/ +static double wsr_w26(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.117622e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.635159e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.395167e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.382823e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -6.531987e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.060112e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -8.203697e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.516523e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.431364e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 6.384553e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -3.238369e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 27) +*************************************************************************/ +static double wsr_w27(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.089731e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.584248e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.359966e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.203696e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.753344e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.761891e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -7.096897e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.419108e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.581214e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 3.033766e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.901441e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 28) +*************************************************************************/ +static double wsr_w28(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.065046e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.539163e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.328939e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.046376e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.061515e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.469271e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.711578e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -8.389153e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.250575e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 4.047245e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.128555e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 29) +*************************************************************************/ +static double wsr_w29(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.043413e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.499756e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.302137e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.915129e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.516329e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.260064e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.817269e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.478130e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.111668e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 4.093451e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.135860e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 30) +*************************************************************************/ +static double wsr_w30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -5.024071e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.464515e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.278342e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.800030e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.046294e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.076162e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -3.968677e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.911679e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -8.619185e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, 5.125362e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -3.984370e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 40) +*************************************************************************/ +static double wsr_w40(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -4.904809e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.248327e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.136698e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.170982e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.824427e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -3.888648e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.344929e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, 2.790407e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.619858e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, 3.359121e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.883026e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 60) +*************************************************************************/ +static double wsr_w60(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -4.809656e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.077191e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.029402e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -7.507931e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, -6.506226e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.391278e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.263635e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, 2.302271e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.384348e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, 1.865587e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.622355e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 120) +*************************************************************************/ +static double wsr_w120(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -4.729426e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.934426e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -9.433231e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.492504e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, 1.673948e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, -6.077014e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -7.215768e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, 9.086734e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, -8.447980e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, 6.705028e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.828507e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 200) +*************************************************************************/ +static double wsr_w200(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/4.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + wsr_wcheb(x, -4.700240e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.883080e+00, &tj, &tj1, &result, _state); + wsr_wcheb(x, -9.132168e-01, &tj, &tj1, &result, _state); + wsr_wcheb(x, -3.512684e-02, &tj, &tj1, &result, _state); + wsr_wcheb(x, 1.726342e-03, &tj, &tj1, &result, _state); + wsr_wcheb(x, -5.189796e-04, &tj, &tj1, &result, _state); + wsr_wcheb(x, -1.628659e-06, &tj, &tj1, &result, _state); + wsr_wcheb(x, 4.261786e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, -4.002498e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, 3.146287e-05, &tj, &tj1, &result, _state); + wsr_wcheb(x, -2.727576e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S,N), S>=0 +*************************************************************************/ +static double wsr_wsigma(double s, ae_int_t n, ae_state *_state) +{ + double f0; + double f1; + double f2; + double f3; + double f4; + double x0; + double x1; + double x2; + double x3; + double x4; + double x; + double result; + + + result = (double)(0); + if( n==5 ) + { + result = wsr_w5(s, _state); + } + if( n==6 ) + { + result = wsr_w6(s, _state); + } + if( n==7 ) + { + result = wsr_w7(s, _state); + } + if( n==8 ) + { + result = wsr_w8(s, _state); + } + if( n==9 ) + { + result = wsr_w9(s, _state); + } + if( n==10 ) + { + result = wsr_w10(s, _state); + } + if( n==11 ) + { + result = wsr_w11(s, _state); + } + if( n==12 ) + { + result = wsr_w12(s, _state); + } + if( n==13 ) + { + result = wsr_w13(s, _state); + } + if( n==14 ) + { + result = wsr_w14(s, _state); + } + if( n==15 ) + { + result = wsr_w15(s, _state); + } + if( n==16 ) + { + result = wsr_w16(s, _state); + } + if( n==17 ) + { + result = wsr_w17(s, _state); + } + if( n==18 ) + { + result = wsr_w18(s, _state); + } + if( n==19 ) + { + result = wsr_w19(s, _state); + } + if( n==20 ) + { + result = wsr_w20(s, _state); + } + if( n==21 ) + { + result = wsr_w21(s, _state); + } + if( n==22 ) + { + result = wsr_w22(s, _state); + } + if( n==23 ) + { + result = wsr_w23(s, _state); + } + if( n==24 ) + { + result = wsr_w24(s, _state); + } + if( n==25 ) + { + result = wsr_w25(s, _state); + } + if( n==26 ) + { + result = wsr_w26(s, _state); + } + if( n==27 ) + { + result = wsr_w27(s, _state); + } + if( n==28 ) + { + result = wsr_w28(s, _state); + } + if( n==29 ) + { + result = wsr_w29(s, _state); + } + if( n==30 ) + { + result = wsr_w30(s, _state); + } + if( n>30 ) + { + x = 1.0/(double)n; + x0 = 1.0/(double)30; + f0 = wsr_w30(s, _state); + x1 = 1.0/(double)40; + f1 = wsr_w40(s, _state); + x2 = 1.0/(double)60; + f2 = wsr_w60(s, _state); + x3 = 1.0/(double)120; + f3 = wsr_w120(s, _state); + x4 = 1.0/(double)200; + f4 = wsr_w200(s, _state); + f1 = ((x-x0)*f1-(x-x1)*f0)/(x1-x0); + f2 = ((x-x0)*f2-(x-x2)*f0)/(x2-x0); + f3 = ((x-x0)*f3-(x-x3)*f0)/(x3-x0); + f4 = ((x-x0)*f4-(x-x4)*f0)/(x4-x0); + f2 = ((x-x1)*f2-(x-x2)*f1)/(x2-x1); + f3 = ((x-x1)*f3-(x-x3)*f1)/(x3-x1); + f4 = ((x-x1)*f4-(x-x4)*f1)/(x4-x1); + f3 = ((x-x2)*f3-(x-x3)*f2)/(x3-x2); + f4 = ((x-x2)*f4-(x-x4)*f2)/(x4-x2); + f4 = ((x-x3)*f4-(x-x4)*f3)/(x4-x3); + result = f4; + } + return result; +} + + +#endif +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +One-sample t-test + +This test checks three hypotheses about the mean of the given sample. The +following tests are performed: + * two-tailed test (null hypothesis - the mean is equal to the given + value) + * left-tailed test (null hypothesis - the mean is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the mean is less than or equal + to the given value). + +The test is based on the assumption that a given sample has a normal +distribution and an unknown dispersion. If the distribution sharply +differs from normal, the test will work incorrectly. + +INPUT PARAMETERS: + X - sample. Array whose index goes from 0 to N-1. + N - size of sample, N>=0 + Mean - assumed value of the mean. + +OUTPUT PARAMETERS: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0, all p-values are set to 1.0 + * when variance of X[] is exactly zero, p-values are set + to 1.0 or 0.0, depending on difference between sample mean and + value of mean being tested. + + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest1(/* Real */ const ae_vector* x, + ae_int_t n, + double mean, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + double xmean; + double x0; + double v; + ae_bool samex; + double xvariance; + double xstddev; + double v1; + double v2; + double stat; + double s; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=0 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Mean + */ + xmean = (double)(0); + x0 = x->ptr.p_double[0]; + samex = ae_true; + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + xmean = xmean+v; + samex = samex&&ae_fp_eq(v,x0); + } + if( samex ) + { + xmean = x0; + } + else + { + xmean = xmean/(double)n; + } + + /* + * Variance (using corrected two-pass algorithm) + */ + xvariance = (double)(0); + xstddev = (double)(0); + if( n!=1&&!samex ) + { + v1 = (double)(0); + for(i=0; i<=n-1; i++) + { + v1 = v1+ae_sqr(x->ptr.p_double[i]-xmean, _state); + } + v2 = (double)(0); + for(i=0; i<=n-1; i++) + { + v2 = v2+(x->ptr.p_double[i]-xmean); + } + v2 = ae_sqr(v2, _state)/(double)n; + xvariance = (v1-v2)/(double)(n-1); + if( ae_fp_less(xvariance,(double)(0)) ) + { + xvariance = (double)(0); + } + xstddev = ae_sqrt(xvariance, _state); + } + if( ae_fp_eq(xstddev,(double)(0)) ) + { + if( ae_fp_eq(xmean,mean) ) + { + *bothtails = 1.0; + } + else + { + *bothtails = 0.0; + } + if( ae_fp_greater_eq(xmean,mean) ) + { + *lefttail = 1.0; + } + else + { + *lefttail = 0.0; + } + if( ae_fp_less_eq(xmean,mean) ) + { + *righttail = 1.0; + } + else + { + *righttail = 0.0; + } + return; + } + + /* + * Statistic + */ + stat = (xmean-mean)/(xstddev/ae_sqrt((double)(n), _state)); + s = studenttdistribution(n-1, stat, _state); + *bothtails = (double)2*ae_minreal(s, (double)1-s, _state); + *lefttail = s; + *righttail = (double)1-s; +} + + +/************************************************************************* +Two-sample pooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * dispersions are equal + * samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has exactly zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest2(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + ae_bool samex; + ae_bool samey; + double x0; + double y0; + double xmean; + double ymean; + double v; + double stat; + double s; + double p; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=0||m<=0 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Mean + */ + xmean = (double)(0); + x0 = x->ptr.p_double[0]; + samex = ae_true; + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + xmean = xmean+v; + samex = samex&&ae_fp_eq(v,x0); + } + if( samex ) + { + xmean = x0; + } + else + { + xmean = xmean/(double)n; + } + ymean = (double)(0); + y0 = y->ptr.p_double[0]; + samey = ae_true; + for(i=0; i<=m-1; i++) + { + v = y->ptr.p_double[i]; + ymean = ymean+v; + samey = samey&&ae_fp_eq(v,y0); + } + if( samey ) + { + ymean = y0; + } + else + { + ymean = ymean/(double)m; + } + + /* + * S + */ + s = (double)(0); + if( n+m>2 ) + { + for(i=0; i<=n-1; i++) + { + s = s+ae_sqr(x->ptr.p_double[i]-xmean, _state); + } + for(i=0; i<=m-1; i++) + { + s = s+ae_sqr(y->ptr.p_double[i]-ymean, _state); + } + s = ae_sqrt(s*((double)1/(double)n+(double)1/(double)m)/(double)(n+m-2), _state); + } + if( ae_fp_eq(s,(double)(0)) ) + { + if( ae_fp_eq(xmean,ymean) ) + { + *bothtails = 1.0; + } + else + { + *bothtails = 0.0; + } + if( ae_fp_greater_eq(xmean,ymean) ) + { + *lefttail = 1.0; + } + else + { + *lefttail = 0.0; + } + if( ae_fp_less_eq(xmean,ymean) ) + { + *righttail = 1.0; + } + else + { + *righttail = 0.0; + } + return; + } + + /* + * Statistic + */ + stat = (xmean-ymean)/s; + p = studenttdistribution(n+m-2, stat, _state); + *bothtails = (double)2*ae_minreal(p, (double)1-p, _state); + *lefttail = p; + *righttail = (double)1-p; +} + + +/************************************************************************* +Two-sample unpooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * samples are independent. +Equality of variances is NOT required. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + * when only one sample has zero variance, test reduces to 1-sample + version. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void unequalvariancettest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + ae_bool samex; + ae_bool samey; + double x0; + double y0; + double xmean; + double ymean; + double xvar; + double yvar; + double v; + double df; + double p; + double stat; + double c; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=0||m<=0 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Mean + */ + xmean = (double)(0); + x0 = x->ptr.p_double[0]; + samex = ae_true; + for(i=0; i<=n-1; i++) + { + v = x->ptr.p_double[i]; + xmean = xmean+v; + samex = samex&&ae_fp_eq(v,x0); + } + if( samex ) + { + xmean = x0; + } + else + { + xmean = xmean/(double)n; + } + ymean = (double)(0); + y0 = y->ptr.p_double[0]; + samey = ae_true; + for(i=0; i<=m-1; i++) + { + v = y->ptr.p_double[i]; + ymean = ymean+v; + samey = samey&&ae_fp_eq(v,y0); + } + if( samey ) + { + ymean = y0; + } + else + { + ymean = ymean/(double)m; + } + + /* + * Variance (using corrected two-pass algorithm) + */ + xvar = (double)(0); + if( n>=2&&!samex ) + { + for(i=0; i<=n-1; i++) + { + xvar = xvar+ae_sqr(x->ptr.p_double[i]-xmean, _state); + } + xvar = xvar/(double)(n-1); + } + yvar = (double)(0); + if( m>=2&&!samey ) + { + for(i=0; i<=m-1; i++) + { + yvar = yvar+ae_sqr(y->ptr.p_double[i]-ymean, _state); + } + yvar = yvar/(double)(m-1); + } + + /* + * Handle different special cases + * (one or both variances are zero). + */ + if( ae_fp_eq(xvar,(double)(0))&&ae_fp_eq(yvar,(double)(0)) ) + { + if( ae_fp_eq(xmean,ymean) ) + { + *bothtails = 1.0; + } + else + { + *bothtails = 0.0; + } + if( ae_fp_greater_eq(xmean,ymean) ) + { + *lefttail = 1.0; + } + else + { + *lefttail = 0.0; + } + if( ae_fp_less_eq(xmean,ymean) ) + { + *righttail = 1.0; + } + else + { + *righttail = 0.0; + } + return; + } + if( ae_fp_eq(xvar,(double)(0)) ) + { + + /* + * X is constant, unpooled 2-sample test reduces to 1-sample test. + * + * NOTE: right-tail and left-tail must be passed to 1-sample + * t-test in reverse order because we reverse order of + * of samples. + */ + studentttest1(y, m, xmean, bothtails, righttail, lefttail, _state); + return; + } + if( ae_fp_eq(yvar,(double)(0)) ) + { + + /* + * Y is constant, unpooled 2-sample test reduces to 1-sample test. + */ + studentttest1(x, n, ymean, bothtails, lefttail, righttail, _state); + return; + } + + /* + * Statistic + */ + stat = (xmean-ymean)/ae_sqrt(xvar/(double)n+yvar/(double)m, _state); + c = xvar/(double)n/(xvar/(double)n+yvar/(double)m); + df = rmul2((double)(n-1), (double)(m-1), _state)/((double)(m-1)*ae_sqr(c, _state)+(double)(n-1)*ae_sqr((double)1-c, _state)); + if( ae_fp_greater(stat,(double)(0)) ) + { + p = (double)1-0.5*incompletebeta(df/(double)2, 0.5, df/(df+ae_sqr(stat, _state)), _state); + } + else + { + p = 0.5*incompletebeta(df/(double)2, 0.5, df/(df+ae_sqr(stat, _state)), _state); + } + *bothtails = (double)2*ae_minreal(p, (double)1-p, _state); + *lefttail = p; + *righttail = (double)1-p; +} + + +#endif +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Sign test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +While calculating p-values high-precision binomial distribution +approximation is used, so significance levels have about 15 exact digits. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplesigntest(/* Real */ const ae_vector* x, + ae_int_t n, + double median, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_int_t i; + ae_int_t gtcnt; + ae_int_t necnt; + + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + + if( n<=1 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + + /* + * Calculate: + * GTCnt - count of x[i]>Median + * NECnt - count of x[i]<>Median + */ + gtcnt = 0; + necnt = 0; + for(i=0; i<=n-1; i++) + { + if( ae_fp_greater(x->ptr.p_double[i],median) ) + { + gtcnt = gtcnt+1; + } + if( ae_fp_neq(x->ptr.p_double[i],median) ) + { + necnt = necnt+1; + } + } + if( necnt==0 ) + { + + /* + * all x[i] are equal to Median. + * So we can conclude that Median is a true median :) + */ + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + return; + } + *bothtails = ae_minreal((double)2*binomialdistribution(ae_minint(gtcnt, necnt-gtcnt, _state), necnt, 0.5, _state), 1.0, _state); + *lefttail = binomialdistribution(gtcnt, necnt, 0.5, _state); + *righttail = binomialcdistribution(gtcnt-1, necnt, 0.5, _state); +} + + +#endif +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +This function initializes MCMC sampler using single initial point to seed +the population. + +The population is generated around the initial point with random Gaussian +noise being added, having per-variable magnitude equal to XStdDev or (if +MCMCSetScale() was called) equal to XStdDev*S[I]. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point used to seed a MCMC algo, array[N]: + * it is better to have X not too far away from the maximum + of log-likelihood + * any point will do, if no maximum location is unknown + XStdDev - standard deviation of a population generated around X: + * strictly greater than zero + * nearly zero values are likely to cause population to + stagnate, whilst too large values are likely to cause + population to spend excessive time converging + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreate1(ae_int_t n, + /* Real */ const ae_vector* x, + double xstddev, + mcmcstate* state, + ae_state *_state) +{ + + _mcmcstate_clear(state); + + ae_assert(n>=1, "MCMCCreate1: N<1", _state); + ae_assert(x->cnt>=n, "MCMCCreate1: Length(X)x0width = 1; + state->x0height = 1; + rallocm(1, n, &state->x0m, _state); + rcopyvr(n, x, &state->x0m, 0, _state); + state->x0stddev = xstddev; + state->x0type = 0; +} + + +/************************************************************************* +This function initializes MCMC sampler using a population of user-specified +points. + +A specific sampling algorithm that needs an initial population will use +user-provided points. If an algorithm needs more initial points than was +specified, additional points will be randomly generated using population +as a distribution reference. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of P are used + * if not given, automatically determined from size of P + P - initial points, array[PopSize,N] + PopSize - population size, PopSize>0: + * if given, only leading PopSize elements of P are used + * if not given, automatically determined from size of P + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreatefrompopulation(ae_int_t n, + /* Real */ const ae_matrix* p, + ae_int_t popsize, + mcmcstate* state, + ae_state *_state) +{ + + _mcmcstate_clear(state); + + ae_assert(n>=1, "MCMCCreateFromPopulation: N<1", _state); + ae_assert(popsize>=1, "MCMCCreateFromPopulation: PopSize<1", _state); + ae_assert(p->cols>=n, "MCMCCreateFromPopulation: Cols(P)rows>=popsize, "MCMCCreateFromPopulation: Rows(P)x0width = popsize; + state->x0height = 1; + rcopyallocm(popsize, n, p, &state->x0m, _state); + state->x0type = 1; +} + + +/************************************************************************* +This function sets per-variable scaling coefficients for MCMC sampler. + +Present version of the MCMC sampler uses per-variable scales during initial +popilation generation: an initial point X0 is perturbed with random noise, +whose per-variable magnitude is XStdDev*S[I]. + +Future versions of the sampler may use scales for other purposes too, but +are likely to do so in a backward-compatible manner. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetscale(mcmcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(s->cnt>=state->n, "MCMCSetScale: Length(S)n-1; i++) + { + ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "MCMCSetScale: S contains infinite or NAN elements", _state); + ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "MCMCSetScale: S contains zero elements", _state); + state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state); + } +} + + +/************************************************************************* +This function controls adaptation rate of the temperature ladder used by +adaptive parallel tempering algorithms. + +The sampler changes the logarithmic difference between temperatures in the +ladder ln(T[i+1]-T[i]) as a product of different between swap accept rates +A[i]-A[i+1] and current adaptation rate, which is nu0/(1+iteridx/tau). + +Here nu0 is an initial adaptation rate that similar to stochastic gradient +descent learning rate. Recommended values 0.01-0.1. And tau is a learning +rate decay time, depending on the problem it can be 100 or 1000. + +The MCMC sampler uses some default values for these parameters, but they +can change in future versions without notice. + +This function has no effect when adaptive tempering is not active. + +INPUT PARAMETERS: + State - structure stores algorithm state + Nu0 - initial learning rate, >=0. + Zero value effectively turns off adaptation. + Tau - characteristic decay time, >=0. + Zero value effectively turns off adaptation. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetladderadaptationrate(mcmcstate* state, + double nu0, + double tau, + ae_state *_state) +{ + + + ae_assert(ae_isfinite(nu0, _state), "MCMCSetLadderAdaptationRate: Nu0 is not finite", _state); + ae_assert(ae_isfinite(tau, _state), "MCMCSetLadderAdaptationRate: Tau is not finite", _state); + ae_assert(ae_fp_greater_eq(nu0,(double)(0)), "MCMCSetLadderAdaptationRate: Nu0<0", _state); + ae_assert(ae_fp_greater_eq(tau,(double)(0)), "MCMCSetLadderAdaptationRate: Tau<0", _state); + state->laddernu0 = nu0; + state->laddertau = tau; +} + + +/************************************************************************* +This function activates parallel tempering with the fixed temperature +ladder. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +INPUT PARAMETERS: + State - structure stores algorithm state + T - array[NTemp], T[0]=1, T[I+1]>T[I], sampling temperatures. + If the first element of T is different from 1, or + temperatures are not strictly increasing, an exception is + raised + NTemp - >=1, temperature ladder height + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetfixedtemperatureladder(mcmcstate* state, + /* Real */ const ae_vector* t, + ae_int_t ntemp, + ae_state *_state) +{ + ae_int_t i; + + + ae_assert(ntemp>=1, "MCMCSetFixedTemperatureLadder: NTemp<1", _state); + ae_assert(t->cnt>=ntemp, "MCMCSetFixedTemperatureLadder: Length(T)ptr.p_double[0],(double)(1)), "MCMCSetFixedTemperatureLadder: T[0]<>1", _state); + for(i=0; i<=ntemp-2; i++) + { + ae_assert(ae_fp_greater(t->ptr.p_double[i+1],t->ptr.p_double[i]), "MCMCSetFixedTemperatureLadder: T[I+1]<=T[I]", _state); + } + state->ladderkind = 0; + state->popheight = ntemp; + rcopyallocv(ntemp, t, &state->initialladder, _state); +} + + +/************************************************************************* +This function activates parallel tempering with the adaptive temperature +ladder using uniform Swap Acceptance Rate (SAR) proposal. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +The function accepts the hottest temperature in the ladder TMax, as well +as ladder height NTemp>=1. + +You can control adaptation rate wuth mcmcsetladderadaptationrate() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + TMax - initial value of the maximum temperature in the ladder, + TMax>1 (strictly) + NTemp - >=1, temperature ladder height: + * NTemp=1 means that no temperature ladder is actually used + * NTemp=2 means that we have a ladder with temperatures + [1,TMax] and no adaptation + * NTemp>2 means that we have a ladder with T[0]=1 and + T[NTemp-1]=TMax, and adaptive temperatures between them. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetsartemperatureladder(mcmcstate* state, + double tmax, + ae_int_t ntemp, + ae_state *_state) +{ + ae_int_t i; + double growth; + + + ae_assert(ntemp>=1, "MCMCSetSARTemperatureLadder: NTemp<1", _state); + ae_assert(ae_isfinite(tmax, _state), "MCMCSetSARTemperatureLadder: TMax is INF/NAN", _state); + ae_assert(ae_fp_greater(tmax,(double)(1)), "MCMCSetSARTemperatureLadder: TMax<=1", _state); + state->ladderkind = 1; + state->popheight = ntemp; + rallocv(ntemp, &state->initialladder, _state); + state->initialladder.ptr.p_double[0] = 1.0; + if( ntemp>1 ) + { + growth = ae_pow(tmax, (double)1/(double)(ntemp-1), _state); + for(i=1; i<=ntemp-1; i++) + { + state->initialladder.ptr.p_double[i] = state->initialladder.ptr.p_double[i-1]*growth; + } + } +} + + +/************************************************************************* +Same as mcmcsetalgostretch(). +*************************************************************************/ +void mcmcsetalgogoodmanweare(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_state *_state) +{ + + + mcmcsetalgostretch(state, popsize, epochscnt, _state); +} + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses stretch move, as defined in 'Ensemble samplers with affine +invariance', Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + EpochsCnt- iterations count to be reported, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgostretch(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_state *_state) +{ + + + ae_assert(popsize>=state->n+1, "MCMCSetAlgoStretch: PopSize=1, "MCMCSetAlgoStretch: EpochsCnt<1", _state); + state->popwidth = popsize; + state->epochscnt = epochscnt; + state->algokind = 0; + state->proposalkind = 0; +} + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses walk move, as defined in 'Ensemble samplers with affine invariance', +Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + helpers, and that we can use parallel moves. + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + HelpersCnt- helpers count, >=2. Number of helpers used to generate + proposal. Recommended values: some small number like 3-5. + It is possible to specify HelpersCnt=PopSize, but for + large populations it will result in proposal generation + overhead growing as O(N*PopSize^2). + Values larger than PopSize will be silently truncated to + PopSize. + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgowalk(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_int_t helperscnt, + ae_state *_state) +{ + + + ae_assert(popsize>=state->n+1, "MCMCSetAlgoWalk: PopSize=1, "MCMCSetAlgoWalk: EpochsCnt<1", _state); + ae_assert(helperscnt>=2, "MCMCSetAlgoWalk: HelpersCnt<2", _state); + if( popsize<4 ) + { + mcmcsetalgostretch(state, popsize, epochscnt, _state); + return; + } + state->popwidth = popsize; + state->epochscnt = epochscnt; + state->algokind = 0; + state->proposalkind = 1; + state->helperscnt = helperscnt; +} + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move, as defined in 'RUN DMC: an efficient, parallel code for +analyzing radial velocity observations using n-body integrations and +differential evolution Markov chain Monte Carlo' by Benjamin Nelson, Eric +B. Ford, and Matthew J. Payne. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Sigma - non-negative, standard deviation of a Gaussian used to + randomly modify the proposal vector. Recommended values: + about 1E-5. Zero value (or omitted) means that a default + one is used. + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2N), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgode(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + double sigma, + double gamma0, + ae_state *_state) +{ + + + ae_assert(popsize>=state->n+1, "MCMCSetAlgoDE: PopSize=1, "MCMCSetAlgoDE: EpochsCnt<1", _state); + ae_assert(ae_isfinite(sigma, _state), "MCMCSetAlgoDE: Sigma is not finite value", _state); + ae_assert(ae_isfinite(gamma0, _state), "MCMCSetAlgoDE: Gamma0 is not finite value", _state); + ae_assert(ae_fp_greater_eq(sigma,(double)(0)), "MCMCSetAlgoDE: Sigma<0", _state); + ae_assert(ae_fp_greater_eq(gamma0,(double)(0)), "MCMCSetAlgoDE: Gamma0<0", _state); + if( popsize<4 ) + { + mcmcsetalgostretch(state, popsize, epochscnt, _state); + return; + } + state->popwidth = popsize; + state->epochscnt = epochscnt; + state->algokind = 0; + state->proposalkind = 2; + state->desigma = rcase2(ae_fp_greater(sigma,(double)(0)), sigma, 1.0E-5, _state); + state->degamma0 = rcase2(ae_fp_greater(gamma0,(double)(0)), gamma0, 2.38/ae_sqrt((double)(2*state->n), _state), _state); +} + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move with snooker update, as defined in 'Differential Evolution +Markov Chain with snooker updater and fewer chains' by Cajo J.F. ter Braak +and Jasper A. Vrugt. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=6 + that follows from the fact that each update needs at least three + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + In order to simplify the algorithm, if N+1<=PopSize<6, we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgodesnooker(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + double gamma0, + ae_state *_state) +{ + + + ae_assert(popsize>=state->n+1, "MCMCSetAlgoDESnooker: PopSize=1, "MCMCSetAlgoDESnooker: EpochsCnt<1", _state); + ae_assert(ae_isfinite(gamma0, _state), "MCMCSetAlgoDESnooker: Gamma0 is not finite value", _state); + ae_assert(ae_fp_greater_eq(gamma0,(double)(0)), "MCMCSetAlgoDESnooker: Gamma0<0", _state); + if( popsize<6 ) + { + mcmcsetalgostretch(state, popsize, epochscnt, _state); + return; + } + state->popwidth = popsize; + state->epochscnt = epochscnt; + state->algokind = 0; + state->proposalkind = 3; + state->degamma0 = rcase2(ae_fp_greater(gamma0,(double)(0)), gamma0, 2.38/ae_sqrt((double)(2), _state), _state); +} + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses Gaussian random walk, an ensemble of PopSize completely independent +walkers. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: this move is special because it can work with any ensemble size, + including PopSize=1 (most other moves need at least 4, 5 or 6 + walkers in the ensemble). Other moves will throw an exception if + called with PopSize=1. + + EpochsCnt- iterations count to be reported, >=1 + + C - array[N,N], a positive definite covariance matrix. Walker + position is perturbed with Gaussian perturbation with + covariance C. + + IsUpper - if IsUpper=True, only upper triangle of C is used (the + lower one is ignored). Otherwise, only lower triangle is + used. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgogaussian(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + /* Real */ const ae_matrix* c, + ae_bool isupper, + ae_state *_state) +{ + + + ae_assert(popsize>=1, "MCMCSetAlgoGaussian: PopSize=1, "MCMCSetAlgoGaussian: EpochsCnt<1", _state); + ae_assert(c->rows>=state->n, "MCMCSetAlgoGaussian: rows(C)cols>=state->n, "MCMCSetAlgoGaussian: cols(C)n, isupper, _state), "MCMCSetAlgoGaussian: C contains infinite or NaN values!", _state); + state->popwidth = popsize; + state->epochscnt = epochscnt; + state->algokind = 0; + state->proposalkind = 4; + rallocm(state->n, state->n, &state->gausslowerc, _state); + if( isupper ) + { + rmatrixtranspose(state->n, state->n, c, 0, 0, &state->gausslowerc, 0, 0, _state); + } + else + { + rcopym(state->n, state->n, c, &state->gausslowerc, _state); + } +} + + +/************************************************************************* +This function sets number of additional initial iterations (in addition to +EpochsCnt) that will be performed and discarded (not stored into the +report sample), so called 'burn-in length'. + +In total, BurnInLen+EpochsCnt iterations will be performed, with initial +BurnInLen ones being used solely to help MCMC spread walkers according to +the density of the function being sampled. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + BurnInLen - burn-in length, >=0 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetburninlength(mcmcstate* state, + ae_int_t burninlen, + ae_state *_state) +{ + + + ae_assert(burninlen>=0, "MCMCSetBurnInLength: BurnInLen<0", _state); + state->burninlen = burninlen; +} + + +/************************************************************************* +This function sets thinning factor: ThinBy*EpochsCnt iterations will be +performed (after the optional burn-in phase), with every ThinBy-th +iteration being saved and the rest being discarded. + +This option helps to avoid storing highly correlated samples. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + ThinBy - thinning factor, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetthinningfactor(mcmcstate* state, + ae_int_t thinby, + ae_state *_state) +{ + + + ae_assert(thinby>=1, "MCMCSetThinningFactor: ThinBy<1", _state); + state->thinby = thinby; +} + + +/************************************************************************* +This function sets the seed which is used to initialize internal RNG. By +default, a deterministic seed is used - same for each run of the sampler. +It means that the same sampling decisions are taken every time. + +If you specify a non-deterministic seed value, then the sampler may return +slightly different results after each run. + +INPUT PARAMETERS: + S - sampler state + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetseed(mcmcstate* s, ae_int_t seed, ae_state *_state) +{ + + + s->rngseed = ae_maxint(seed, 0, _state); +} + + +/************************************************************************* + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool mcmciteration(mcmcstate* state, ae_state *_state) +{ + ae_int_t n; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t itidx; + ae_int_t itmax; + ae_int_t groupscnt; + ae_int_t grpdstsize; + ae_int_t dst; + ae_int_t accept1cnt; + ae_int_t accepthcnt; + double v; + ae_bool result; + + + + /* + * Reverse communication preparations + * I know it looks ugly, but it works the same way + * anywhere from C++ to Python. + * + * This code initializes locals by: + * * random values determined during code + * generation - on first subroutine call + * * values from previous call - on subsequent calls + */ + if( state->rstate.stage>=0 ) + { + n = state->rstate.ia.ptr.p_int[0]; + i = state->rstate.ia.ptr.p_int[1]; + j = state->rstate.ia.ptr.p_int[2]; + k = state->rstate.ia.ptr.p_int[3]; + itidx = state->rstate.ia.ptr.p_int[4]; + itmax = state->rstate.ia.ptr.p_int[5]; + groupscnt = state->rstate.ia.ptr.p_int[6]; + grpdstsize = state->rstate.ia.ptr.p_int[7]; + dst = state->rstate.ia.ptr.p_int[8]; + accept1cnt = state->rstate.ia.ptr.p_int[9]; + accepthcnt = state->rstate.ia.ptr.p_int[10]; + v = state->rstate.ra.ptr.p_double[0]; + } + else + { + n = 359; + i = -58; + j = -919; + k = -909; + itidx = 81; + itmax = 255; + groupscnt = 74; + grpdstsize = -788; + dst = 809; + accept1cnt = 205; + accepthcnt = -838; + v = 939.0; + } + if( state->rstate.stage==0 ) + { + goto lbl_0; + } + if( state->rstate.stage==1 ) + { + goto lbl_1; + } + if( state->rstate.stage==2 ) + { + goto lbl_2; + } + if( state->rstate.stage==3 ) + { + goto lbl_3; + } + + /* + * Routine body + */ + + /* + * Init + */ + state->dotrace = ae_is_trace_enabled("MCMC"); + state->dodetailedtrace = state->dotrace&&ae_is_trace_enabled("MCMC.DETAILED"); + state->dotimers = state->dotrace; + if( state->dotrace ) + { + ae_trace("\n\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("// MCMC SAMPLER STARTED //\n"); + ae_trace("////////////////////////////////////////////////////////////////////////////////////////////////////\n"); + ae_trace("N = %6d (variables)\n", + (int)(state->n)); + ae_trace("PopSize = %6d (walkers)\n", + (int)(state->popwidth)); + if( state->popheight>1 ) + { + ae_trace("TemperLvls = %6d (tempering levels)\n", + (int)(state->popheight)); + } + if( state->burninlen>0 ) + { + ae_trace("BurnIn = %6d (burn-in phase, not reported)\n", + (int)(state->burninlen)); + } + ae_trace("EpochsCnt = %6d (sampling rounds count)\n", + (int)(state->epochscnt)); + } + stimerinit(&state->timertotal, _state); + stimerinit(&state->timercallback, _state); + stimerinit(&state->timerreport, _state); + stimerstartcond(&state->timertotal, state->dotimers, _state); + state->userterminationneeded = ae_false; + state->repnfev = 0; + state->repaccept1cnt = 0; + state->repaccepthcnt = 0; + state->repepochscnt = 0; + state->repswapacceptcnt = 0; + state->repswapattemptcnt = 0; + rsetallocv(state->popheight-1, 0.0, &state->repavgswaprates, _state); + state->reppopwidth = state->popwidth; + state->reppopheight = state->popheight; + state->repsamplesize = 0; + n = state->n; + if( state->reseedglobalrs ) + { + if( state->rngseed==0 ) + { + hqrndrandomize(&state->globalrs, _state); + } + else + { + hqrndseed(state->rngseed, 856446, &state->globalrs, _state); + } + } + if( state->repsample.cols>n+1 ) + { + ae_matrix_set_length(&state->repsample, 0, 0, _state); + } + if( state->useparallelmoves ) + { + iallocv(state->popwidth*state->popheight, &state->propidx, _state); + rallocv(state->popwidth*state->popheight, &state->propz, _state); + rallocv(state->popwidth*state->popheight, &state->propt, _state); + rallocm(state->popwidth*state->popheight, n+1, &state->propxf, _state); + iallocv(state->popwidth, &state->grpabidx, _state); + } + else + { + iallocv(state->popheight, &state->propidx, _state); + rallocv(state->popheight, &state->propz, _state); + rallocv(state->popheight, &state->propt, _state); + rallocm(state->popheight, n+1, &state->propxf, _state); + } + iallocv(state->popwidth, &state->grpdsidx, _state); + + /* + * Initialize proposal generators + */ + ae_assert((state->algokind==0&&state->proposalkind>=0)&&state->proposalkind<=4, "MCMC: integrity check 795613 failed", _state); + if( state->proposalkind==4 ) + { + v = (double)(0); + for(;;) + { + rcopyallocm(n, n, &state->gausslowerc, &state->gaussl, _state); + for(i=0; i<=n-1; i++) + { + state->gaussl.ptr.pp_double[i][i] = state->gaussl.ptr.pp_double[i][i]+v; + for(j=i+1; j<=n-1; j++) + { + state->gaussl.ptr.pp_double[i][j] = 0.0; + } + } + if( spdmatrixcholesky(&state->gaussl, n, ae_false, _state) ) + { + break; + } + v = coalesce((double)2*v, ae_machineepsilon, _state); + } + } + + /* + * Initial temperature ladder + */ + ae_assert(state->ladderkind>=0&&state->ladderkind<=1, "MCMC: 915033 failed", _state); + rcopyallocv(state->popheight, &state->initialladder, &state->currentladder, _state); + + /* + * Allocate buffers, as mandated by the V2 protocol + */ + ae_assert(state->protocolversion==2, "MCMC: integrity check 206333 failed", _state); + ae_assert(state->algokind==0, "MCMC: integrity check 207333 failed", _state); + rallocv(n, &state->querydata, _state); + rallocv(1, &state->replyfi, _state); + rallocv(1, &state->tmpf1, _state); + rallocv(n, &state->tmpx1, _state); + rallocv(n, &state->tmpg1, _state); + ae_vector_set_length(&state->reportx, 1, _state); + state->reportx.ptr.p_double[0] = (double)(0); + state->reportf = (double)(0); + + /* + * Initial population and subdivision into groups + */ + ae_assert((state->x0type==0||state->x0type==1)||state->x0type==2, "MCMC: integrity check 221342 failed", _state); + if( state->useparallelmoves ) + { + for(i=0; i<=state->popwidth-1; i++) + { + state->grpabidx.ptr.p_int[i] = i; + } + if( state->proposalkind!=4 ) + { + ae_assert(state->popwidth>=2, "MCMC: integrity check 294008 failed", _state); + state->grpasize = state->popwidth/2; + } + else + { + state->grpasize = state->popwidth; + } + } + if( state->x0type==0 ) + { + ae_assert(state->x0width>=1, "MCMC: integrity check 426148 failed", _state); + ae_assert(state->x0height>=1, "MCMC: integrity check 884204 failed", _state); + rallocm(state->popwidth*state->popheight, n+1, &state->population2d, _state); + for(i=0; i<=state->popwidth*state->popheight-1; i++) + { + for(j=0; j<=n-1; j++) + { + state->population2d.ptr.pp_double[i][j] = state->x0m.ptr.pp_double[0][j]+state->x0stddev*state->s.ptr.p_double[j]*hqrndnormal(&state->globalrs, _state); + } + } + } + if( state->x0type==1 ) + { + ae_assert(state->x0width>=1, "MCMC: integrity check 487508 failed", _state); + + /* + * Prepare for the case when we do not have enough points to seed the algorithm. + * + * Compute a bounding box for the user-provided set of points, with center at + * tmp0[] and per-variable scaled radii in tmp2[] + * + * Make sure that the box has no zero radius and that his aspect ratio is well-normalized + */ + rallocv(n, &state->tmp0, _state); + rallocv(n, &state->tmp1, _state); + rcopyrv(n, &state->x0m, 0, &state->tmp0, _state); + rcopyrv(n, &state->x0m, 0, &state->tmp1, _state); + for(i=1; i<=state->x0width-1; i++) + { + rmergeminrv(n, &state->x0m, i, &state->tmp0, _state); + rmergemaxrv(n, &state->x0m, i, &state->tmp1, _state); + } + rcopyallocv(n, &state->tmp1, &state->tmp2, _state); + raddv(n, -1.0, &state->tmp0, &state->tmp2, _state); + rmulv(n, 0.5, &state->tmp2, _state); + rmergedivv(n, &state->s, &state->tmp2, _state); + raddv(n, 1.0, &state->tmp1, &state->tmp0, _state); + rmulv(n, 0.5, &state->tmp0, _state); + v = rmaxabsv(n, &state->tmp2, _state); + for(j=0; j<=n-1; j++) + { + state->tmp2.ptr.p_double[j] = coalesce(ae_maxreal(state->tmp2.ptr.p_double[j], 1.0E-6*v, _state), (double)(1), _state); + } + + /* + * Seed the algorithm using population in X0, when present; fill with random values when not present. + * The same population is used for all levels of the temperature ladder. + */ + ae_assert(state->x0height==1, "MCMC: integrity check 894205 failed", _state); + k = ae_minint(state->x0width, state->popwidth, _state); + rallocm(state->popwidth*state->popheight, n+1, &state->population2d, _state); + for(i=0; i<=state->popwidth*state->popheight-1; i++) + { + if( ix0width ) + { + for(j=0; j<=n-1; j++) + { + state->population2d.ptr.pp_double[i][j] = state->x0m.ptr.pp_double[i][j]; + } + } + else + { + for(j=0; j<=n-1; j++) + { + state->population2d.ptr.pp_double[i][j] = hqrndnormal(&state->globalrs, _state)*(0.33*state->tmp2.ptr.p_double[j]*state->s.ptr.p_double[j])+state->tmp0.ptr.p_double[j]; + } + } + } + } + if( state->x0type==2 ) + { + ae_assert(state->haslastpopulation, "MCMC: integrity check 434149 failed", _state); + + /* + * Reuse last population + */ + rallocm(state->popwidth*state->popheight, n+1, &state->population2d, _state); + for(i=0; i<=state->popheight-1; i++) + { + for(j=0; j<=state->popwidth-1; j++) + { + if( ilastpopulationheight&&jlastpopulationwidth ) + { + rcopyrr(n, &state->lastpopulation2d, i*state->lastpopulationwidth+j, &state->population2d, i*state->popwidth+j, _state); + } + else + { + for(k=0; k<=n-1; k++) + { + state->population2d.ptr.pp_double[i*state->popwidth+j][k] = state->lastpopulation2d.ptr.pp_double[ae_minint(i, state->lastpopulationheight-1, _state)*state->lastpopulationwidth+hqrnduniformi(&state->globalrs, state->lastpopulationwidth, _state)][k]; + } + } + } + } + + /* + * If parallel moves are used AND new population size matches its old size, reuse previous subdivision + * into groups (it is important for smooth restarts) + */ + if( (state->useparallelmoves&&state->lastpopulationwidth==state->popwidth)&&state->lastpopulationheight==state->popheight ) + { + icopyv(state->popwidth, &state->lastgrpabidx, &state->grpabidx, _state); + } + } + i = 0; +lbl_4: + if( i>state->popwidth*state->popheight-1 ) + { + goto lbl_6; + } + state->repnfev = state->repnfev+1; + state->requesttype = 4; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + state->querysize = 1; + for(j=0; j<=n-1; j++) + { + state->querydata.ptr.p_double[j] = state->population2d.ptr.pp_double[i][j]; + } + stimerstartcond(&state->timercallback, state->dotimers, _state); + state->rstate.stage = 0; + goto lbl_rcomm; +lbl_0: + stimerstopcond(&state->timercallback, state->dotimers, _state); + state->population2d.ptr.pp_double[i][n] = state->replyfi.ptr.p_double[0]; + i = i+1; + goto lbl_4; +lbl_6: + if( !state->xrep ) + { + goto lbl_7; + } + state->requesttype = -1; + stimerstartcond(&state->timerreport, state->dotimers, _state); + state->rstate.stage = 1; + goto lbl_rcomm; +lbl_1: + stimerstopcond(&state->timerreport, state->dotimers, _state); +lbl_7: + mcmc_savepopulation(state, _state); + + /* + * Subsequent moves + */ + ae_assert(state->algokind==0, "MCMC: integrity check 238038 failed", _state); + ae_assert(state->popwidth>=2, "MCMC: integrity check 238039 failed", _state); + itmax = icase2(state->initialstart, state->burninlen, 0, _state)+state->epochscnt*state->thinby; + rallocm(state->epochscnt*state->popwidth*icase2(state->reportalllevels, state->popheight, 1, _state), n+1, &state->repsample, _state); + itidx = 0; +lbl_9: + if( itidx>itmax-1 ) + { + goto lbl_11; + } + + /* + * Perform moves + */ + accept1cnt = 0; + accepthcnt = 0; + groupscnt = icase2(state->useparallelmoves, 2, state->popwidth, _state); + if( state->useparallelmoves ) + { + icopyv(state->popwidth, &state->grpabidx, &state->grpdsidx, _state); + grpdstsize = state->grpasize; + } + else + { + for(i=0; i<=state->popwidth-1; i++) + { + state->grpdsidx.ptr.p_int[i] = i; + } + grpdstsize = 1; + } + i = 0; +lbl_12: + if( i>groupscnt-1 ) + { + goto lbl_14; + } + + /* + * Handle degenerate cases (walk move with group size = pop size) + */ + if( grpdstsize==0 ) + { + ae_assert(i==groupscnt-1, "MCMC: 018015 failed", _state); + goto lbl_14; + } + + /* + * Generate proposals + */ + mcmc_generateproposals(state, &state->globalrs, &state->grpdsidx, grpdstsize, &state->propidx, &state->propz, &state->propt, &state->propxf, _state); + + /* + * Issue RCOMM-V2 request + */ + j = 0; +lbl_15: + if( j>grpdstsize-1 ) + { + goto lbl_17; + } + rcopyrv(n, &state->propxf, j, &state->querydata, _state); + state->repnfev = state->repnfev+1; + state->requesttype = 4; + state->queryfuncs = 1; + state->queryvars = n; + state->querydim = 0; + state->querysize = 1; + stimerstartcond(&state->timercallback, state->dotimers, _state); + state->rstate.stage = 2; + goto lbl_rcomm; +lbl_2: + stimerstopcond(&state->timercallback, state->dotimers, _state); + state->propxf.ptr.pp_double[j][n] = state->replyfi.ptr.p_double[0]; + j = j+1; + goto lbl_15; +lbl_17: + + /* + * Acceptance test + */ + for(j=0; j<=grpdstsize-1; j++) + { + if( ae_fp_less(hqrnduniformr(&state->globalrs, _state),ae_minreal(1.0, ae_exp(state->propz.ptr.p_double[j]+(state->propxf.ptr.pp_double[j][n]-state->population2d.ptr.pp_double[state->propidx.ptr.p_int[j]][n])/state->propt.ptr.p_double[j], _state), _state)) ) + { + rcopyrr(n+1, &state->propxf, j, &state->population2d, state->propidx.ptr.p_int[j], _state); + accept1cnt = accept1cnt+1; + if( state->propidx.ptr.p_int[j]>state->popwidth ) + { + accepthcnt = accepthcnt+1; + } + } + } + + /* + * Update split into A and B groups + */ + if( state->useparallelmoves ) + { + ae_assert(i<=1, "MCMC: 071013 failed", _state); + if( i==0 ) + { + iallocv(state->popwidth, &state->tmpi0, _state); + icopyvx(state->grpasize, &state->grpdsidx, 0, &state->tmpi0, state->popwidth-state->grpasize, _state); + icopyvx(state->popwidth-state->grpasize, &state->grpdsidx, state->grpasize, &state->tmpi0, 0, _state); + icopyv(state->popwidth, &state->tmpi0, &state->grpdsidx, _state); + grpdstsize = state->popwidth-state->grpasize; + } + } + else + { + ae_assert(grpdstsize==1, "MCMC: 092019 failed", _state); + if( ipopwidth-1 ) + { + k = state->grpdsidx.ptr.p_int[0]; + state->grpdsidx.ptr.p_int[0] = state->grpdsidx.ptr.p_int[i+1]; + state->grpdsidx.ptr.p_int[i+1] = k; + } + } + i = i+1; + goto lbl_12; +lbl_14: + + /* + * Apply swaps between temperature ladder levels and perform adaptation, if needed + */ + mcmc_applyswapsandadapt(state, itidx, itidx>=icase2(state->initialstart, state->burninlen, 0, _state), &state->globalrs, _state); + + /* + * If parallel moves are used, update splits into groups + */ + if( state->useparallelmoves ) + { + for(i=0; i<=state->popwidth-1; i++) + { + j = i+hqrnduniformi(&state->globalrs, state->popwidth-i, _state); + k = state->grpabidx.ptr.p_int[i]; + state->grpabidx.ptr.p_int[i] = state->grpabidx.ptr.p_int[j]; + state->grpabidx.ptr.p_int[j] = k; + } + } + + /* + * Save report, check for termination request. The check is done twice: + * prior to reporting progress and after returning from the callback. + * + * This way we can: + * * stop immediately after progress is reported, if request was submitted + * in the callback + * * stop before iteration is accepted, if request was submitted prior to + * invoking the callback + */ + if( state->dotrace ) + { + mcmc_dologging(state, itidx, accept1cnt, accepthcnt, _state); + } + if( state->userterminationneeded ) + { + goto lbl_11; + } + k = itidx; + if( state->initialstart ) + { + k = k-state->burninlen; + } + if( !(k>=0&&k%state->thinby==0) ) + { + goto lbl_18; + } + ae_assert(state->repsample.rows>=state->repsamplesize+state->popwidth*icase2(state->reportalllevels, state->popheight, 1, _state)&&state->repsample.cols>=n+1, "MCMC: integrity check 497055 failed", _state); + ae_assert(!state->reportalllevels, "$rep-all-lvl", _state); + for(i=0; i<=state->popwidth-1; i++) + { + rcopyrr(n+1, &state->population2d, i, &state->repsample, state->repsamplesize, _state); + state->repsamplesize = state->repsamplesize+1; + } + state->repaccept1cnt = state->repaccept1cnt+accept1cnt; + state->repaccepthcnt = state->repaccepthcnt+accepthcnt; + state->repepochscnt = state->repepochscnt+1; + if( !state->xrep ) + { + goto lbl_20; + } + state->requesttype = -1; + stimerstartcond(&state->timerreport, state->dotimers, _state); + state->rstate.stage = 3; + goto lbl_rcomm; +lbl_3: + stimerstopcond(&state->timerreport, state->dotimers, _state); +lbl_20: +lbl_18: + if( state->userterminationneeded ) + { + goto lbl_11; + } + itidx = itidx+1; + goto lbl_9; +lbl_11: + + /* + * Finalize + */ + state->reseedglobalrs = ae_true; + mcmc_savepopulation(state, _state); + stimerstopcond(&state->timertotal, state->dotimers, _state); + if( state->dotrace ) + { + ae_trace("\n=== STOPPED ========================================================================================\n"); + ae_trace("total time: %10.1f ms, including\n", + (double)(stimergetms(&state->timertotal, _state))); + ae_trace("* sampler %10.1f ms\n", + (double)(stimergetms(&state->timertotal, _state)-stimergetms(&state->timercallback, _state)-stimergetms(&state->timerreport, _state))); + ae_trace("* callbacks %10.1f ms (computing log-likelihood)\n", + (double)(stimergetms(&state->timercallback, _state))); + ae_trace("* reports %10.1f ms (reporting progress)\n", + (double)(stimergetms(&state->timerreport, _state))); + } + result = ae_false; + return result; + + /* + * Saving state + */ +lbl_rcomm: + result = ae_true; + state->rstate.ia.ptr.p_int[0] = n; + state->rstate.ia.ptr.p_int[1] = i; + state->rstate.ia.ptr.p_int[2] = j; + state->rstate.ia.ptr.p_int[3] = k; + state->rstate.ia.ptr.p_int[4] = itidx; + state->rstate.ia.ptr.p_int[5] = itmax; + state->rstate.ia.ptr.p_int[6] = groupscnt; + state->rstate.ia.ptr.p_int[7] = grpdstsize; + state->rstate.ia.ptr.p_int[8] = dst; + state->rstate.ia.ptr.p_int[9] = accept1cnt; + state->rstate.ia.ptr.p_int[10] = accepthcnt; + state->rstate.ra.ptr.p_double[0] = v; + return result; +} + + +/************************************************************************* +Extract MCMC sampler results from the sampler. This function has significant +overhead coming from two sources: +* overhead of copying PopSize*EpochsCnt*N-sized array from internal memory +* overhead of computing per-variable integrated autocorrelating time + +INPUT PARAMETERS: + State - MCMC sampler, either after return from mcmcrun() + or still running (in the latter case, this + function can be safely called only from the rep() + callback). + +OUTPUT PARAMETERS: + Sample - array[SampleSize,N+1], current sample: + * first N columns store variable values, the last + one stores log-likelihood value as computed by + the callback + * first PopSize rows store population snapshot + after the iteration #0, subsequent PopSize rows + correspond to iteration #1 and so on. + * each snapshot (a set of PopSize rows) stores + positions of PopSize walkers, each walker having + the same position in each of SampleSize snapshots. + Thus, walker #I at the iteration #J is stored + at the row PopSize*J+I. + + SampleSize - current sample size: + * for a sampler that stopped it is equal to PopSize*EpochsCnt + * for a sampler that is still running, we have + 0<=SampleSizenfev = state->repnfev; + rep->acceptrate = (double)state->repaccept1cnt/coalesce((double)(state->repepochscnt*state->reppopwidth), (double)(1), _state); + rep->swapacceptrate = (double)state->repswapacceptcnt/coalesce((double)(state->repswapattemptcnt), (double)(1), _state); + rsetallocv(state->n, 0.0, &rep->autocorrtimes, _state); + *samplesize = state->repsamplesize; + + /* + * RepSampleSize>0 + */ + if( state->repsamplesize>0 ) + { + rcopyallocm(state->repsamplesize, state->n+1, &state->repsample, sample, _state); + mcmc_computeautocorrtimes(state, &rep->autocorrtimes, _state); + } +} + + +/************************************************************************* +This subroutine submits request for termination of a running MCMC +sampler. It should be called from user-supplied callback when user decides +that it is time to "smoothly" terminate optimization process. As a result, +sampler stops at the point which was "current accepted" when termination +request was submitted. + +Alternatively, this function can be called from some other thread +(different from one where the sampler is running). + +INPUT PARAMETERS: + State - sampler structure + +NOTE: after request for termination sampler may perform several + additional calls to user-supplied callbacks. It does NOT guarantee + to stop immediately - it just guarantees that these additional calls + will be discarded later. + +NOTE: calling this function on sampler which is NOT running will have no + effect. + +NOTE: multiple calls to this function are possible. First call is counted, + subsequent calls are silently ignored. + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcrequesttermination(mcmcstate* state, ae_state *_state) +{ + + + state->userterminationneeded = ae_true; +} + + +/************************************************************************* +This function turns on/off reporting. + +INPUT PARAMETERS: + State - structure which stores sampler state + NeedXRep- whether iteration reports are needed or not + +If NeedXRep is True, the algorithm will call rep() callback function if it +was provided to mcmcrun(). + +NOTE: due to ALGLIB conventions regarding report callbacks, the sampler + passes two parameters to the rep() callback - an 1D floating point + array, and a scalar floating-point value. + + In nonlinear optimizers these parameters are used to report current + point/objective, but it makes little sense in the context of MCMC. + Because of that, MCMC sampler sets the first parameter to be a + zero-initialized single-element array, and the second (scalar) + parameter is set to zero. + + -- ALGLIB -- + Copyright 25.02.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetxrep(mcmcstate* state, ae_bool needxrep, ae_state *_state) +{ + + + state->xrep = needxrep; +} + + +/************************************************************************* +This function tells the sampler to restart the next sampling session using +the most recent population as an initial state. + +The new sampling session is still considered an independent one. It uses +sampling distribution of the previous session to provide a smooth restart, +but its results do not include samples collected during the previous +session. + +It is possible to specify different sampling algorithm or change +parameters of the algorithm. If population size has changed, then we have +two options: +* the new population size is less than the previous one; the population is + truncated (only leading NewPopSize elements are retained) +* the new population size is greater than the previous one; in this case, + leading OldPopSize elements are retained from the previous population, + and the rest (NewPopSize-OldPopSize) is randomly initialized using the + previous population as a reference distribution. + +INPUT PARAMETERS: + State - structure which stores sampler state + +RESULT: + * False, if no previous population was stored in the sampler (the + restart was requested prior to running anything, so we have nothing + to restart from). In this case, the sampler will silently reuse + previous initial population generation strategy. + * True, if a request was successfully accepted. + +NOTE: this function also tells the sampler not to re-seed internal RNG, + so the new session will produce the same sequence of sampling + decisions. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +ae_bool mcmcrestart(mcmcstate* state, ae_state *_state) +{ + ae_bool result; + + + result = state->haslastpopulation; + if( !result ) + { + return result; + } + state->x0type = 2; + state->reseedglobalrs = ae_false; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; + return result; +} + + +/************************************************************************* +Set V2 reverse communication protocol with dense requests +*************************************************************************/ +void mcmcsetprotocolv2(mcmcstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_false; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Set V2 reverse communication protocol with sparse requests +*************************************************************************/ +void mcmcsetprotocolv2s(mcmcstate* state, ae_state *_state) +{ + + + state->protocolversion = 2; + state->issuesparserequests = ae_true; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Internal initialization to the default state + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_initinternal(mcmcstate* state, + ae_int_t n, + ae_state *_state) +{ + + + state->n = n; + state->x0width = 0; + state->x0height = 0; + state->x0type = -1; + state->algokind = 0; + state->proposalkind = 0; + state->popwidth = 10*n; + state->ladderkind = 0; + state->popheight = 1; + rsetallocv(1, 1.0, &state->initialladder, _state); + state->laddernu0 = 0.05; + state->laddertau = 1000.0; + state->noladderadaptationafterburnin = ae_false; + state->epochscnt = 100; + state->burninlen = 0; + state->thinby = 1; + state->reportalllevels = ae_false; + state->initialstart = ae_true; + state->protocolversion = 2; + state->haslastpopulation = ae_false; + state->rngseed = 6435533; + state->xrep = ae_false; + rsetallocv(n, 1.0, &state->s, _state); + hqrndseed(state->rngseed, 856446, &state->globalrs, _state); + state->reseedglobalrs = ae_true; + state->useparallelmoves = ae_true; + ae_vector_set_length(&state->rstate.ia, 10+1, _state); + ae_vector_set_length(&state->rstate.ra, 0+1, _state); + state->rstate.stage = -1; +} + + +/************************************************************************* +Logging + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_dologging(mcmcstate* state, + ae_int_t iteridx, + ae_int_t accept1cnt, + ae_int_t accepthcnt, + ae_state *_state) +{ + ae_frame _frame_block; + ae_vector popmean; + ae_vector popstddev; + ae_int_t i; + ae_int_t j; + ae_int_t n; + ae_int_t popwidth; + double llmean; + double llstddev; + + ae_frame_make(_state, &_frame_block); + memset(&popmean, 0, sizeof(popmean)); + memset(&popstddev, 0, sizeof(popstddev)); + ae_vector_init(&popmean, 0, DT_REAL, _state, ae_true); + ae_vector_init(&popstddev, 0, DT_REAL, _state, ae_true); + + ae_assert(state->dotrace, "MCMC: DoLogging() is called with tracing disable; this function shall not be called when logging is turned off", _state); + n = state->n; + popwidth = state->popwidth; + if( state->dodetailedtrace ) + { + ae_trace("=== ITERATION %5d ================================================================================\n", + (int)(iteridx)); + rsetallocv(n, 0.0, &popmean, _state); + rsetallocv(n, 0.0, &popstddev, _state); + for(i=0; i<=popwidth-1; i++) + { + for(j=0; j<=n-1; j++) + { + popmean.ptr.p_double[j] = popmean.ptr.p_double[j]+state->population2d.ptr.pp_double[i][j]; + } + } + for(j=0; j<=n-1; j++) + { + popmean.ptr.p_double[j] = popmean.ptr.p_double[j]/(double)popwidth; + } + for(i=0; i<=popwidth-1; i++) + { + for(j=0; j<=n-1; j++) + { + popstddev.ptr.p_double[j] = popstddev.ptr.p_double[j]+(state->population2d.ptr.pp_double[i][j]-popmean.ptr.p_double[j])*(state->population2d.ptr.pp_double[i][j]-popmean.ptr.p_double[j]); + } + } + for(j=0; j<=n-1; j++) + { + popstddev.ptr.p_double[j] = ae_sqrt(popstddev.ptr.p_double[j]/(double)popwidth, _state); + } + ae_trace("pop.mean = "); + tracevectore3(&popmean, 0, n, _state); + ae_trace("\n"); + ae_trace("pop.stddev = "); + tracevectore3(&popstddev, 0, n, _state); + ae_trace("\n"); + llmean = (double)(0); + for(i=0; i<=popwidth-1; i++) + { + llmean = llmean+state->population2d.ptr.pp_double[i][n]; + } + llmean = llmean/(double)popwidth; + llstddev = (double)(0); + for(i=0; i<=popwidth-1; i++) + { + llstddev = llstddev+ae_sqr(state->population2d.ptr.pp_double[i][n]-llmean, _state); + } + llstddev = ae_sqrt(llstddev/(double)popwidth, _state); + ae_trace("loglik.mean = %0.3f\n", + (double)(llmean)); + ae_trace("loglik.stddev = %0.3f\n", + (double)(llstddev)); + ae_trace("accept.rate = %0.3f\n", + (double)((double)accept1cnt/(double)popwidth)); + if( state->popheight>1 ) + { + ae_trace("> Temperature ladder:\n"); + ae_trace("temperatures = ["); + tracevectore3(&state->currentladder, 0, state->popheight, _state); + ae_trace("]\n"); + ae_trace("accept rates = ["); + tracevectore3(&state->repavgswaprates, 0, state->popheight-1, _state); + ae_trace("]\n"); + } + } + else + { + } + ae_frame_leave(_state); +} + + +/************************************************************************* +Apply temperature ladder swaps and perform adaptation; +does nothing for popheight=1. + +INPUT PARAMETERS: + RawItIdx iteration index, starts from the very beginning, + is NOT thinned (counts all iterations) + BurnInOver if True, burn-in phase is completed + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_applyswapsandadapt(mcmcstate* state, + ae_int_t rawitidx, + ae_bool burninover, + hqrndstate* rs, + ae_state *_state) +{ + ae_int_t n; + ae_int_t popheight; + ae_int_t popwidth; + ae_int_t i; + ae_int_t widx; + ae_int_t hidx; + ae_int_t idx0; + ae_int_t idx1; + double deltabeta; + double logprob; + ae_bool adaptationdone; + double decay; + double v; + + + n = state->n; + popheight = state->popheight; + popwidth = state->popwidth; + if( popheight==1 ) + { + return; + } + + /* + * Apply swaps + */ + rsetallocv(popheight-1, 0.0, &state->saacceptrates, _state); + for(hidx=popheight-1; hidx>=1; hidx--) + { + deltabeta = (double)1/state->currentladder.ptr.p_double[hidx]-(double)1/state->currentladder.ptr.p_double[hidx-1]; + for(widx=0; widx<=popwidth-1; widx++) + { + idx0 = hidx*popwidth+widx; + idx1 = (hidx-1)*popwidth+widx; + logprob = -deltabeta*(state->population2d.ptr.pp_double[idx0][n]-state->population2d.ptr.pp_double[idx1][n]); + if( ae_fp_less(hqrnduniformr(rs, _state),ae_minreal(ae_exp(logprob, _state), (double)(1), _state)) ) + { + swaprows(&state->population2d, idx0, idx1, n+1, _state); + state->repswapacceptcnt = state->repswapacceptcnt+1; + state->saacceptrates.ptr.p_double[hidx-1] = state->saacceptrates.ptr.p_double[hidx-1]+(double)1/(double)popwidth; + } + state->repswapattemptcnt = state->repswapattemptcnt+1; + } + } + if( popheight>1 ) + { + if( ae_fp_greater(rmaxabsv(popheight-1, &state->repavgswaprates, _state),(double)(0)) ) + { + v = 0.01; + rmulv(popheight-1, (double)1-v, &state->repavgswaprates, _state); + raddv(popheight-1, v, &state->saacceptrates, &state->repavgswaprates, _state); + } + else + { + rcopyv(popheight-1, &state->saacceptrates, &state->repavgswaprates, _state); + } + } + + /* + * Perform adaptation + */ + if( !burninover||!state->noladderadaptationafterburnin ) + { + decay = state->laddernu0*state->laddertau/((double)rawitidx+state->laddertau+ae_machineepsilon); + adaptationdone = ae_false; + if( state->ladderkind==0 ) + { + adaptationdone = ae_true; + } + if( state->ladderkind==1 ) + { + if( popheight>=3 ) + { + rallocv(popheight-2, &state->savecsi, _state); + rallocv(popheight-1, &state->saproposedladder, _state); + for(i=0; i<=popheight-3; i++) + { + state->savecsi.ptr.p_double[i] = ae_log(state->currentladder.ptr.p_double[i+1]-state->currentladder.ptr.p_double[i], _state)+decay*(state->saacceptrates.ptr.p_double[i]-state->saacceptrates.ptr.p_double[i+1]); + } + state->saproposedladder.ptr.p_double[0] = state->currentladder.ptr.p_double[0]; + for(i=1; i<=popheight-2; i++) + { + state->saproposedladder.ptr.p_double[i] = state->saproposedladder.ptr.p_double[i-1]+ae_exp(state->savecsi.ptr.p_double[i-1], _state); + } + if( ae_fp_less(state->saproposedladder.ptr.p_double[popheight-2],state->currentladder.ptr.p_double[popheight-1]) ) + { + rcopyv(popheight-1, &state->saproposedladder, &state->currentladder, _state); + } + } + adaptationdone = ae_true; + } + ae_assert(adaptationdone, "MCMC: 728137", _state); + } +} + + +/************************************************************************* +Save current population + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_savepopulation(mcmcstate* state, ae_state *_state) +{ + + + state->haslastpopulation = ae_true; + state->lastpopulationwidth = state->popwidth; + state->lastpopulationheight = state->popheight; + rcopyallocm(state->popwidth*state->popheight, state->n+1, &state->population2d, &state->lastpopulation2d, _state); + if( state->useparallelmoves ) + { + icopyallocv(state->popwidth, &state->grpabidx, &state->lastgrpabidx, _state); + } +} + + +/************************************************************************* +Generates proposals for walkers + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_generateproposals(mcmcstate* state, + hqrndstate* rs, + /* Integer */ const ae_vector* grpidx, + ae_int_t dstgrpsize, + /* Integer */ ae_vector* propidx, + /* Real */ ae_vector* propz, + /* Real */ ae_vector* propt, + /* Real */ ae_matrix* propxf, + ae_state *_state) +{ + ae_int_t n; + ae_int_t popwidth; + ae_int_t popheight; + ae_int_t helperscnt; + ae_int_t widx; + ae_int_t hidx; + ae_int_t offs; + ae_int_t j; + ae_int_t jj; + ae_int_t itmp; + ae_int_t k; + ae_int_t src; + ae_int_t srca; + ae_int_t srcb; + ae_int_t srcc; + ae_int_t dst; + double v; + double vs; + double vnrm; + + + n = state->n; + popwidth = state->popwidth; + popheight = state->popheight; + ae_assert(state->algokind==0, "MCMC 188955 failed", _state); + ae_assert((((state->proposalkind==0||state->proposalkind==1)||state->proposalkind==2)||state->proposalkind==3)||state->proposalkind==4, "MCMC 250131 failed", _state); + + /* + * Prepare group structure + */ + ae_assert(state->proposalkind!=0||popwidth-dstgrpsize>=1, "MCMC 564025 failed", _state); + ae_assert(state->proposalkind!=1||(popwidth-dstgrpsize>=2&&state->helperscnt>=2), "MCMC 272113 failed", _state); + ae_assert(state->proposalkind!=2||popwidth-dstgrpsize>=2, "MCMC 367147 failed", _state); + ae_assert(state->proposalkind!=3||popwidth-dstgrpsize>=3, "MCMC 432520 failed", _state); + + /* + * Generate proposals + */ + ae_assert((((propidx->cnt>=dstgrpsize*popheight&&propz->cnt>=dstgrpsize*popheight)&&propt->cnt>=dstgrpsize*popheight)&&propxf->rows>=dstgrpsize*popheight)&&propxf->cols>=n+1, "MCMC 188955 failed", _state); + if( state->proposalkind==0 ) + { + + /* + * Stretch move + */ + offs = 0; + for(widx=0; widx<=dstgrpsize-1; widx++) + { + for(hidx=0; hidx<=popheight-1; hidx++) + { + dst = grpidx->ptr.p_int[widx]; + src = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + dst = hidx*popwidth+dst; + src = hidx*popwidth+src; + propidx->ptr.p_int[offs] = dst; + v = ae_sqr((mcmc_goodmanwearea-(double)1)*hqrnduniformr(rs, _state)+(double)1, _state)/mcmc_goodmanwearea; + propz->ptr.p_double[offs] = (double)(n-1)*ae_log(v, _state); + propt->ptr.p_double[offs] = state->currentladder.ptr.p_double[hidx]; + for(k=0; k<=n-1; k++) + { + propxf->ptr.pp_double[offs][k] = state->population2d.ptr.pp_double[src][k]+v*(state->population2d.ptr.pp_double[dst][k]-state->population2d.ptr.pp_double[src][k]); + } + offs = offs+1; + } + } + return; + } + if( state->proposalkind==1 ) + { + + /* + * Walk move + */ + helperscnt = ae_minint(state->helperscnt, popwidth-dstgrpsize, _state); + iallocv(popwidth, &state->gphelperidx, _state); + rallocv(n, &state->gpmeanhelper, _state); + rallocv(n, &state->gpproposal, _state); + icopyvx(popwidth-dstgrpsize, grpidx, dstgrpsize, &state->gphelperidx, 0, _state); + offs = 0; + for(widx=0; widx<=dstgrpsize-1; widx++) + { + for(hidx=0; hidx<=popheight-1; hidx++) + { + + /* + * Determine Dst and Helper indexes + */ + dst = grpidx->ptr.p_int[widx]; + for(jj=0; jj<=helperscnt-1; jj++) + { + swapelementsi(&state->gphelperidx, jj, jj+hqrnduniformi(rs, popwidth-dstgrpsize-jj, _state), _state); + } + dst = hidx*popwidth+dst; + + /* + * Generate proposal + */ + propidx->ptr.p_int[offs] = dst; + rsetv(n, 0.0, &state->gpmeanhelper, _state); + rsetv(n, 0.0, &state->gpproposal, _state); + vs = (double)(0); + for(jj=0; jj<=helperscnt-1; jj++) + { + v = hqrndnormal(rs, _state); + raddrv(n, v, &state->population2d, hidx*popwidth+state->gphelperidx.ptr.p_int[jj], &state->gpproposal, _state); + raddrv(n, 1.0/(double)helperscnt, &state->population2d, hidx*popwidth+state->gphelperidx.ptr.p_int[jj], &state->gpmeanhelper, _state); + vs = vs+v; + } + raddv(n, -vs, &state->gpmeanhelper, &state->gpproposal, _state); + propz->ptr.p_double[offs] = 0.0; + propt->ptr.p_double[offs] = state->currentladder.ptr.p_double[hidx]; + rcopyrr(n, &state->population2d, dst, propxf, offs, _state); + raddvr(n, 1.0, &state->gpproposal, propxf, offs, _state); + offs = offs+1; + } + } + return; + } + if( state->proposalkind==2 ) + { + + /* + * DE move + */ + offs = 0; + for(widx=0; widx<=dstgrpsize-1; widx++) + { + for(hidx=0; hidx<=popheight-1; hidx++) + { + + /* + * Determine Dst and SrcA/SrcB indexes + */ + dst = grpidx->ptr.p_int[widx]; + do + { + srca = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + srcb = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + } + while(srca==srcb); + dst = hidx*popwidth+dst; + srca = hidx*popwidth+srca; + srcb = hidx*popwidth+srcb; + + /* + * Generate proposal + */ + propidx->ptr.p_int[offs] = dst; + propz->ptr.p_double[offs] = 0.0; + propt->ptr.p_double[offs] = state->currentladder.ptr.p_double[hidx]; + v = state->degamma0+state->desigma*hqrndnormal(rs, _state); + for(k=0; k<=n-1; k++) + { + propxf->ptr.pp_double[offs][k] = state->population2d.ptr.pp_double[dst][k]+v*(state->population2d.ptr.pp_double[srca][k]-state->population2d.ptr.pp_double[srcb][k]); + } + offs = offs+1; + } + } + return; + } + if( state->proposalkind==3 ) + { + + /* + * DE move with snooker update + */ + rallocv(n, &state->gpdelta, _state); + rallocv(n, &state->gptmp0, _state); + offs = 0; + for(widx=0; widx<=dstgrpsize-1; widx++) + { + for(hidx=0; hidx<=popheight-1; hidx++) + { + + /* + * Determine Dst and SrcA/SrcB/SrcC indexes + */ + dst = grpidx->ptr.p_int[widx]; + srca = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + do + { + srcb = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + } + while(srcb==srca); + do + { + srcc = grpidx->ptr.p_int[dstgrpsize+hqrnduniformi(rs, popwidth-dstgrpsize, _state)]; + } + while(!(srcc!=srcb&&srcc!=srca)); + dst = hidx*popwidth+dst; + srca = hidx*popwidth+srca; + srcb = hidx*popwidth+srcb; + srcc = hidx*popwidth+srcc; + + /* + * Generate proposal + */ + propidx->ptr.p_int[offs] = dst; + rcopyrv(n, &state->population2d, dst, &state->gpdelta, _state); + raddrv(n, -1.0, &state->population2d, srca, &state->gpdelta, _state); + vnrm = ae_sqrt(rdotv2(n, &state->gpdelta, _state), _state); + rmulv(n, (double)1/(vnrm+ae_minrealnumber), &state->gpdelta, _state); + rcopyrr(n, &state->population2d, dst, propxf, offs, _state); + raddvr(n, state->degamma0*(rdotvr(n, &state->gpdelta, &state->population2d, srcb, _state)-rdotvr(n, &state->gpdelta, &state->population2d, srcc, _state)), &state->gpdelta, propxf, offs, _state); + rcopyrv(n, propxf, offs, &state->gptmp0, _state); + raddrv(n, -1.0, &state->population2d, srca, &state->gptmp0, _state); + v = ae_sqrt(rdotv2(n, &state->gptmp0, _state), _state); + propz->ptr.p_double[offs] = (double)(n-1)*ae_log((v+ae_minrealnumber)/(vnrm+ae_minrealnumber), _state); + propt->ptr.p_double[offs] = state->currentladder.ptr.p_double[hidx]; + offs = offs+1; + } + } + return; + } + if( state->proposalkind==4 ) + { + + /* + * Gaussian move + */ + rallocv(n, &state->gpdelta, _state); + rallocv(n, &state->gptmp0, _state); + offs = 0; + for(widx=0; widx<=dstgrpsize-1; widx++) + { + for(hidx=0; hidx<=popheight-1; hidx++) + { + + /* + * Determine Dst to update + */ + dst = hidx*popwidth+grpidx->ptr.p_int[widx]; + + /* + * Generate proposal + */ + for(k=0; k<=n-1; k++) + { + state->gptmp0.ptr.p_double[k] = hqrndnormal(rs, _state); + } + rgemv(n, n, 1.0, &state->gaussl, 0, &state->gptmp0, 0.0, &state->gpdelta, _state); + propidx->ptr.p_int[offs] = dst; + propz->ptr.p_double[offs] = 0.0; + propt->ptr.p_double[offs] = state->currentladder.ptr.p_double[hidx]; + rcopyrr(n, &state->population2d, dst, propxf, offs, _state); + raddvr(n, 1.0, &state->gpdelta, propxf, offs, _state); + offs = offs+1; + } + } + return; + } + ae_assert(ae_false, "MCMC: 319132 failed", _state); +} + + +/************************************************************************* +Compute per-variable integrated autocorrelation times + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +static void mcmc_computeautocorrtimes(const mcmcstate* state, + /* Real */ ae_vector* autocorrtimes, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t n; + ae_int_t m; + ae_int_t epochscnt; + ae_int_t popwidth; + ae_int_t idxv; + ae_int_t idxw; + ae_vector a; + ae_vector a2; + + ae_frame_make(_state, &_frame_block); + memset(&a, 0, sizeof(a)); + memset(&a2, 0, sizeof(a2)); + ae_vector_init(&a, 0, DT_REAL, _state, ae_true); + ae_vector_init(&a2, 0, DT_REAL, _state, ae_true); + + n = state->n; + epochscnt = state->repepochscnt; + popwidth = state->reppopwidth; + ae_assert(!state->reportalllevels, "MCMC: 778552 failed", _state); + ae_assert(epochscnt*popwidth==state->repsamplesize, "MCMC: integrity check 657126 failed", _state); + rsetallocv(n, 0.0, autocorrtimes, _state); + + /* + * + */ + for(idxv=0; idxv<=n-1; idxv++) + { + + /* + * Compute averaged autocorrelation function + */ + rsetallocv(epochscnt, 0.0, &a, _state); + for(idxw=0; idxw<=popwidth-1; idxw++) + { + mcmc_autocorrij(state, idxw, idxv, &a2, _state); + raddv(epochscnt, (double)1/(double)popwidth, &a2, &a, _state); + } + rmulv(epochscnt, (double)1/(a.ptr.p_double[0]+ae_sqrt(ae_minrealnumber, _state)*possign(a.ptr.p_double[0], _state)), &a, _state); + + /* + * Compute integrated autocorrelation time using finite window M, such that time(M)*C<=M for C~5. + * Having finite window size helps to reduce influence of random noise. + */ + autocorrtimes->ptr.p_double[idxv] = a.ptr.p_double[0]; + for(m=1; m<=epochscnt-1; m++) + { + autocorrtimes->ptr.p_double[idxv] = autocorrtimes->ptr.p_double[idxv]+(double)2*a.ptr.p_double[m]; + if( ae_fp_less_eq(autocorrtimes->ptr.p_double[idxv]*mcmc_cautocorr,(double)(m)) ) + { + break; + } + } + } + ae_frame_leave(_state); +} + + +static void mcmc_autocorrij(const mcmcstate* state, + ae_int_t idxw, + ae_int_t idxv, + /* Real */ ae_vector* a, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t epochscnt; + ae_int_t ex2; + ae_int_t popwidth; + ae_vector x; + double meanx; + ae_int_t i; + ae_vector f; + + ae_frame_make(_state, &_frame_block); + memset(&x, 0, sizeof(x)); + memset(&f, 0, sizeof(f)); + ae_vector_init(&x, 0, DT_REAL, _state, ae_true); + ae_vector_init(&f, 0, DT_COMPLEX, _state, ae_true); + + epochscnt = state->repepochscnt; + popwidth = state->reppopwidth; + ae_assert(!state->reportalllevels, "MCMC: 778552 failed", _state); + ae_assert(epochscnt*popwidth==state->repsamplesize, "MCMC: integrity check 678132 failed", _state); + ex2 = 1; + while(ex2repsample.ptr.pp_double[popwidth*i+idxw][idxv]; + meanx = meanx+x.ptr.p_double[i]; + } + meanx = meanx/(double)epochscnt; + for(i=0; i<=epochscnt-1; i++) + { + x.ptr.p_double[i] = x.ptr.p_double[i]-meanx; + } + fftr1dbuf(&x, ex2, &f, _state); + for(i=0; i<=ex2-1; i++) + { + f.ptr.p_complex[i] = ae_c_mul(f.ptr.p_complex[i],ae_c_conj(f.ptr.p_complex[i], _state)); + } + fftr1dinvbuf(&f, ex2, &x, _state); + rallocv(epochscnt, a, _state); + rcopymulv(epochscnt, (double)1/(double)epochscnt, &x, a, _state); + ae_frame_leave(_state); +} + + +void _mcmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mcmcstate *p = (mcmcstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_init(&p->x0m, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->initialladder, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->gausslowerc, 0, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->gaussl, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->population2d, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->currentladder, 0, DT_REAL, _state, make_automatic); + _hqrndstate_init(&p->globalrs, _state, make_automatic); + ae_vector_init(&p->propidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->propz, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->propt, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->propxf, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->grpabidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->grpdsidx, 0, DT_INT, _state, make_automatic); + ae_matrix_init(&p->lastpopulation2d, 0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->lastgrpabidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->reportx, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->querydata, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replyfi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->replydj, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->replysj, _state, make_automatic); + ae_vector_init(&p->tmpx1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpc1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpf1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpg1, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->tmpj1, 0, 0, DT_REAL, _state, make_automatic); + _sparsematrix_init(&p->tmps1, _state, make_automatic); + ae_vector_init(&p->repavgswaprates, 0, DT_REAL, _state, make_automatic); + ae_matrix_init(&p->repsample, 0, 0, DT_REAL, _state, make_automatic); + _stimer_init(&p->timertotal, _state, make_automatic); + _stimer_init(&p->timercallback, _state, make_automatic); + _stimer_init(&p->timerreport, _state, make_automatic); + ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmp2, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->tmpi0, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->gphelperidx, 0, DT_INT, _state, make_automatic); + ae_vector_init(&p->gpmeanhelper, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gpproposal, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gpdelta, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->gptmp0, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->saacceptrates, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->savecsi, 0, DT_REAL, _state, make_automatic); + ae_vector_init(&p->saproposedladder, 0, DT_REAL, _state, make_automatic); + _rcommstate_init(&p->rstate, _state, make_automatic); +} + + +void _mcmcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mcmcstate *dst = (mcmcstate*)_dst; + const mcmcstate *src = (const mcmcstate*)_src; + dst->n = src->n; + dst->x0width = src->x0width; + dst->x0height = src->x0height; + ae_matrix_init_copy(&dst->x0m, &src->x0m, _state, make_automatic); + dst->x0type = src->x0type; + dst->x0stddev = src->x0stddev; + dst->algokind = src->algokind; + dst->ladderkind = src->ladderkind; + dst->proposalkind = src->proposalkind; + dst->helperscnt = src->helperscnt; + dst->desigma = src->desigma; + dst->degamma0 = src->degamma0; + ae_vector_init_copy(&dst->initialladder, &src->initialladder, _state, make_automatic); + dst->laddernu0 = src->laddernu0; + dst->laddertau = src->laddertau; + dst->noladderadaptationafterburnin = src->noladderadaptationafterburnin; + ae_matrix_init_copy(&dst->gausslowerc, &src->gausslowerc, _state, make_automatic); + ae_matrix_init_copy(&dst->gaussl, &src->gaussl, _state, make_automatic); + dst->useparallelmoves = src->useparallelmoves; + dst->epochscnt = src->epochscnt; + dst->popwidth = src->popwidth; + dst->popheight = src->popheight; + dst->burninlen = src->burninlen; + dst->thinby = src->thinby; + dst->reportalllevels = src->reportalllevels; + dst->rngseed = src->rngseed; + ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic); + dst->initialstart = src->initialstart; + dst->xrep = src->xrep; + ae_matrix_init_copy(&dst->population2d, &src->population2d, _state, make_automatic); + ae_vector_init_copy(&dst->currentladder, &src->currentladder, _state, make_automatic); + _hqrndstate_init_copy(&dst->globalrs, &src->globalrs, _state, make_automatic); + dst->reseedglobalrs = src->reseedglobalrs; + ae_vector_init_copy(&dst->propidx, &src->propidx, _state, make_automatic); + ae_vector_init_copy(&dst->propz, &src->propz, _state, make_automatic); + ae_vector_init_copy(&dst->propt, &src->propt, _state, make_automatic); + ae_matrix_init_copy(&dst->propxf, &src->propxf, _state, make_automatic); + ae_vector_init_copy(&dst->grpabidx, &src->grpabidx, _state, make_automatic); + dst->grpasize = src->grpasize; + ae_vector_init_copy(&dst->grpdsidx, &src->grpdsidx, _state, make_automatic); + dst->haslastpopulation = src->haslastpopulation; + ae_matrix_init_copy(&dst->lastpopulation2d, &src->lastpopulation2d, _state, make_automatic); + ae_vector_init_copy(&dst->lastgrpabidx, &src->lastgrpabidx, _state, make_automatic); + dst->lastpopulationwidth = src->lastpopulationwidth; + dst->lastpopulationheight = src->lastpopulationheight; + dst->userterminationneeded = src->userterminationneeded; + dst->protocolversion = src->protocolversion; + dst->issuesparserequests = src->issuesparserequests; + dst->requesttype = src->requesttype; + ae_vector_init_copy(&dst->reportx, &src->reportx, _state, make_automatic); + dst->reportf = src->reportf; + dst->querysize = src->querysize; + dst->queryfuncs = src->queryfuncs; + dst->queryvars = src->queryvars; + dst->querydim = src->querydim; + dst->queryformulasize = src->queryformulasize; + ae_vector_init_copy(&dst->querydata, &src->querydata, _state, make_automatic); + ae_vector_init_copy(&dst->replyfi, &src->replyfi, _state, make_automatic); + ae_vector_init_copy(&dst->replydj, &src->replydj, _state, make_automatic); + _sparsematrix_init_copy(&dst->replysj, &src->replysj, _state, make_automatic); + ae_vector_init_copy(&dst->tmpx1, &src->tmpx1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpc1, &src->tmpc1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpf1, &src->tmpf1, _state, make_automatic); + ae_vector_init_copy(&dst->tmpg1, &src->tmpg1, _state, make_automatic); + ae_matrix_init_copy(&dst->tmpj1, &src->tmpj1, _state, make_automatic); + _sparsematrix_init_copy(&dst->tmps1, &src->tmps1, _state, make_automatic); + dst->repnfev = src->repnfev; + dst->repaccept1cnt = src->repaccept1cnt; + dst->repaccepthcnt = src->repaccepthcnt; + dst->repepochscnt = src->repepochscnt; + dst->reppopwidth = src->reppopwidth; + dst->reppopheight = src->reppopheight; + dst->repswapacceptcnt = src->repswapacceptcnt; + dst->repswapattemptcnt = src->repswapattemptcnt; + ae_vector_init_copy(&dst->repavgswaprates, &src->repavgswaprates, _state, make_automatic); + ae_matrix_init_copy(&dst->repsample, &src->repsample, _state, make_automatic); + dst->repsamplesize = src->repsamplesize; + dst->dotrace = src->dotrace; + dst->dodetailedtrace = src->dodetailedtrace; + dst->dotimers = src->dotimers; + _stimer_init_copy(&dst->timertotal, &src->timertotal, _state, make_automatic); + _stimer_init_copy(&dst->timercallback, &src->timercallback, _state, make_automatic); + _stimer_init_copy(&dst->timerreport, &src->timerreport, _state, make_automatic); + ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic); + ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic); + ae_vector_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic); + ae_vector_init_copy(&dst->tmpi0, &src->tmpi0, _state, make_automatic); + ae_vector_init_copy(&dst->gphelperidx, &src->gphelperidx, _state, make_automatic); + ae_vector_init_copy(&dst->gpmeanhelper, &src->gpmeanhelper, _state, make_automatic); + ae_vector_init_copy(&dst->gpproposal, &src->gpproposal, _state, make_automatic); + ae_vector_init_copy(&dst->gpdelta, &src->gpdelta, _state, make_automatic); + ae_vector_init_copy(&dst->gptmp0, &src->gptmp0, _state, make_automatic); + ae_vector_init_copy(&dst->saacceptrates, &src->saacceptrates, _state, make_automatic); + ae_vector_init_copy(&dst->savecsi, &src->savecsi, _state, make_automatic); + ae_vector_init_copy(&dst->saproposedladder, &src->saproposedladder, _state, make_automatic); + _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic); +} + + +void _mcmcstate_clear(void* _p) +{ + mcmcstate *p = (mcmcstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_clear(&p->x0m); + ae_vector_clear(&p->initialladder); + ae_matrix_clear(&p->gausslowerc); + ae_matrix_clear(&p->gaussl); + ae_vector_clear(&p->s); + ae_matrix_clear(&p->population2d); + ae_vector_clear(&p->currentladder); + _hqrndstate_clear(&p->globalrs); + ae_vector_clear(&p->propidx); + ae_vector_clear(&p->propz); + ae_vector_clear(&p->propt); + ae_matrix_clear(&p->propxf); + ae_vector_clear(&p->grpabidx); + ae_vector_clear(&p->grpdsidx); + ae_matrix_clear(&p->lastpopulation2d); + ae_vector_clear(&p->lastgrpabidx); + ae_vector_clear(&p->reportx); + ae_vector_clear(&p->querydata); + ae_vector_clear(&p->replyfi); + ae_vector_clear(&p->replydj); + _sparsematrix_clear(&p->replysj); + ae_vector_clear(&p->tmpx1); + ae_vector_clear(&p->tmpc1); + ae_vector_clear(&p->tmpf1); + ae_vector_clear(&p->tmpg1); + ae_matrix_clear(&p->tmpj1); + _sparsematrix_clear(&p->tmps1); + ae_vector_clear(&p->repavgswaprates); + ae_matrix_clear(&p->repsample); + _stimer_clear(&p->timertotal); + _stimer_clear(&p->timercallback); + _stimer_clear(&p->timerreport); + ae_vector_clear(&p->tmp0); + ae_vector_clear(&p->tmp1); + ae_vector_clear(&p->tmp2); + ae_vector_clear(&p->tmpi0); + ae_vector_clear(&p->gphelperidx); + ae_vector_clear(&p->gpmeanhelper); + ae_vector_clear(&p->gpproposal); + ae_vector_clear(&p->gpdelta); + ae_vector_clear(&p->gptmp0); + ae_vector_clear(&p->saacceptrates); + ae_vector_clear(&p->savecsi); + ae_vector_clear(&p->saproposedladder); + _rcommstate_clear(&p->rstate); +} + + +void _mcmcstate_destroy(void* _p) +{ + mcmcstate *p = (mcmcstate*)_p; + ae_touch_ptr((void*)p); + ae_matrix_destroy(&p->x0m); + ae_vector_destroy(&p->initialladder); + ae_matrix_destroy(&p->gausslowerc); + ae_matrix_destroy(&p->gaussl); + ae_vector_destroy(&p->s); + ae_matrix_destroy(&p->population2d); + ae_vector_destroy(&p->currentladder); + _hqrndstate_destroy(&p->globalrs); + ae_vector_destroy(&p->propidx); + ae_vector_destroy(&p->propz); + ae_vector_destroy(&p->propt); + ae_matrix_destroy(&p->propxf); + ae_vector_destroy(&p->grpabidx); + ae_vector_destroy(&p->grpdsidx); + ae_matrix_destroy(&p->lastpopulation2d); + ae_vector_destroy(&p->lastgrpabidx); + ae_vector_destroy(&p->reportx); + ae_vector_destroy(&p->querydata); + ae_vector_destroy(&p->replyfi); + ae_vector_destroy(&p->replydj); + _sparsematrix_destroy(&p->replysj); + ae_vector_destroy(&p->tmpx1); + ae_vector_destroy(&p->tmpc1); + ae_vector_destroy(&p->tmpf1); + ae_vector_destroy(&p->tmpg1); + ae_matrix_destroy(&p->tmpj1); + _sparsematrix_destroy(&p->tmps1); + ae_vector_destroy(&p->repavgswaprates); + ae_matrix_destroy(&p->repsample); + _stimer_destroy(&p->timertotal); + _stimer_destroy(&p->timercallback); + _stimer_destroy(&p->timerreport); + ae_vector_destroy(&p->tmp0); + ae_vector_destroy(&p->tmp1); + ae_vector_destroy(&p->tmp2); + ae_vector_destroy(&p->tmpi0); + ae_vector_destroy(&p->gphelperidx); + ae_vector_destroy(&p->gpmeanhelper); + ae_vector_destroy(&p->gpproposal); + ae_vector_destroy(&p->gpdelta); + ae_vector_destroy(&p->gptmp0); + ae_vector_destroy(&p->saacceptrates); + ae_vector_destroy(&p->savecsi); + ae_vector_destroy(&p->saproposedladder); + _rcommstate_destroy(&p->rstate); +} + + +void _mcmcreport_init(void* _p, ae_state *_state, ae_bool make_automatic) +{ + mcmcreport *p = (mcmcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_init(&p->autocorrtimes, 0, DT_REAL, _state, make_automatic); +} + + +void _mcmcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic) +{ + mcmcreport *dst = (mcmcreport*)_dst; + const mcmcreport *src = (const mcmcreport*)_src; + dst->nfev = src->nfev; + dst->acceptrate = src->acceptrate; + dst->swapacceptrate = src->swapacceptrate; + ae_vector_init_copy(&dst->autocorrtimes, &src->autocorrtimes, _state, make_automatic); +} + + +void _mcmcreport_clear(void* _p) +{ + mcmcreport *p = (mcmcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_clear(&p->autocorrtimes); +} + + +void _mcmcreport_destroy(void* _p) +{ + mcmcreport *p = (mcmcreport*)_p; + ae_touch_ptr((void*)p); + ae_vector_destroy(&p->autocorrtimes); +} + + +#endif +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) + + +/************************************************************************* +Mann-Whitney U-test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions of the same shape and same median or whether +their medians are different. + +The following tests are performed: + * two-tailed test (null hypothesis - the medians are equal) + * left-tailed test (null hypothesis - the median of the first sample + is greater than or equal to the median of the second sample) + * right-tailed test (null hypothesis - the median of the first sample + is less than or equal to the median of the second sample). + +Requirements: + * the samples are independent + * X and Y are continuous distributions (or discrete distributions well- + approximating continuous distributions) + * distributions of X and Y have the same shape. The only possible + difference is their position (i.e. the value of the median) + * the number of elements in each sample is not less than 5 + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + +The test is non-parametric and doesn't require distributions to be normal. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. N>=5 + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. M>=5 + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with satisfactory accuracy in interval [0.0001, 1]. +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + +Relative precision of approximation of p-value: + +N M Max.err. Rms.err. +5..10 N..10 1.4e-02 6.0e-04 +5..10 N..100 2.2e-02 5.3e-06 +10..15 N..15 1.0e-02 3.2e-04 +10..15 N..100 1.0e-02 2.2e-05 +15..100 N..100 6.1e-03 2.7e-06 + +For N,M>100 accuracy checks weren't put into practice, but taking into +account characteristics of asymptotic approximation used, precision should +not be sharply different from the values for interval [5, 100]. + +NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, + P's outside of this interval are enforced to these bounds. Say, you + may quite often get P equal to exactly 0.25 or 0.0001. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void mannwhitneyutest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state) +{ + ae_frame _frame_block; + ae_int_t i; + ae_int_t j; + ae_int_t k; + ae_int_t t; + double tmp; + ae_int_t tmpi; + ae_int_t ns; + ae_vector r; + ae_vector c; + double u; + double p; + double mp; + double s; + double sigma; + double mu; + ae_int_t tiecount; + ae_vector tiesize; + + ae_frame_make(_state, &_frame_block); + memset(&r, 0, sizeof(r)); + memset(&c, 0, sizeof(c)); + memset(&tiesize, 0, sizeof(tiesize)); + *bothtails = 0.0; + *lefttail = 0.0; + *righttail = 0.0; + ae_vector_init(&r, 0, DT_REAL, _state, ae_true); + ae_vector_init(&c, 0, DT_INT, _state, ae_true); + ae_vector_init(&tiesize, 0, DT_INT, _state, ae_true); + + + /* + * Prepare + */ + if( n<=4||m<=4 ) + { + *bothtails = 1.0; + *lefttail = 1.0; + *righttail = 1.0; + ae_frame_leave(_state); + return; + } + ns = n+m; + ae_vector_set_length(&r, ns-1+1, _state); + ae_vector_set_length(&c, ns-1+1, _state); + for(i=0; i<=n-1; i++) + { + r.ptr.p_double[i] = x->ptr.p_double[i]; + c.ptr.p_int[i] = 0; + } + for(i=0; i<=m-1; i++) + { + r.ptr.p_double[n+i] = y->ptr.p_double[i]; + c.ptr.p_int[n+i] = 1; + } + + /* + * sort {R, C} + */ + if( ns!=1 ) + { + i = 2; + do + { + t = i; + while(t!=1) + { + k = t/2; + if( ae_fp_greater_eq(r.ptr.p_double[k-1],r.ptr.p_double[t-1]) ) + { + t = 1; + } + else + { + tmp = r.ptr.p_double[k-1]; + r.ptr.p_double[k-1] = r.ptr.p_double[t-1]; + r.ptr.p_double[t-1] = tmp; + tmpi = c.ptr.p_int[k-1]; + c.ptr.p_int[k-1] = c.ptr.p_int[t-1]; + c.ptr.p_int[t-1] = tmpi; + t = k; + } + } + i = i+1; + } + while(i<=ns); + i = ns-1; + do + { + tmp = r.ptr.p_double[i]; + r.ptr.p_double[i] = r.ptr.p_double[0]; + r.ptr.p_double[0] = tmp; + tmpi = c.ptr.p_int[i]; + c.ptr.p_int[i] = c.ptr.p_int[0]; + c.ptr.p_int[0] = tmpi; + t = 1; + while(t!=0) + { + k = 2*t; + if( k>i ) + { + t = 0; + } + else + { + if( k=1); + } + + /* + * compute tied ranks + */ + i = 0; + tiecount = 0; + ae_vector_set_length(&tiesize, ns-1+1, _state); + while(i<=ns-1) + { + j = i+1; + while(j<=ns-1) + { + if( ae_fp_neq(r.ptr.p_double[j],r.ptr.p_double[i]) ) + { + break; + } + j = j+1; + } + for(k=i; k<=j-1; k++) + { + r.ptr.p_double[k] = (double)1+(double)(i+j-1)/(double)2; + } + tiesize.ptr.p_int[tiecount] = j-i; + tiecount = tiecount+1; + i = j; + } + + /* + * Compute U + */ + u = (double)(0); + for(i=0; i<=ns-1; i++) + { + if( c.ptr.p_int[i]==0 ) + { + u = u+r.ptr.p_double[i]; + } + } + u = rmul2((double)(n), (double)(m), _state)+rmul2((double)(n), (double)(n+1), _state)*0.5-u; + + /* + * Result + */ + mu = rmul2((double)(n), (double)(m), _state)/(double)2; + tmp = (double)ns*(ae_sqr((double)(ns), _state)-(double)1)/(double)12; + for(i=0; i<=tiecount-1; i++) + { + tmp = tmp-(double)tiesize.ptr.p_int[i]*(ae_sqr((double)(tiesize.ptr.p_int[i]), _state)-(double)1)/(double)12; + } + sigma = ae_sqrt(rmul2((double)(n), (double)(m), _state)/(double)ns/(double)(ns-1)*tmp, _state); + s = (u-mu)/sigma; + if( ae_fp_less_eq(s,(double)(0)) ) + { + p = ae_exp(mannwhitneyu_usigma(-(u-mu)/sigma, n, m, _state), _state); + mp = (double)1-ae_exp(mannwhitneyu_usigma(-(u-(double)1-mu)/sigma, n, m, _state), _state); + } + else + { + mp = ae_exp(mannwhitneyu_usigma((u-mu)/sigma, n, m, _state), _state); + p = (double)1-ae_exp(mannwhitneyu_usigma((u+(double)1-mu)/sigma, n, m, _state), _state); + } + *lefttail = boundval(ae_maxreal(mp, 1.0E-4, _state), 0.0001, 0.2500, _state); + *righttail = boundval(ae_maxreal(p, 1.0E-4, _state), 0.0001, 0.2500, _state); + *bothtails = (double)2*ae_minreal(*lefttail, *righttail, _state); + ae_frame_leave(_state); +} + + +/************************************************************************* +Sequential Chebyshev interpolation. +*************************************************************************/ +static void mannwhitneyu_ucheb(double x, + double c, + double* tj, + double* tj1, + double* r, + ae_state *_state) +{ + double t; + + + *r = *r+c*(*tj); + t = (double)2*x*(*tj1)-(*tj); + *tj = *tj1; + *tj1 = t; +} + + +/************************************************************************* +Three-point polynomial interpolation. +*************************************************************************/ +static double mannwhitneyu_uninterpolate(double p1, + double p2, + double p3, + ae_int_t n, + ae_state *_state) +{ + double t1; + double t2; + double t3; + double t; + double p12; + double p23; + double result; + + + t1 = 1.0/15.0; + t2 = 1.0/30.0; + t3 = 1.0/100.0; + t = 1.0/(double)n; + p12 = ((t-t2)*p1+(t1-t)*p2)/(t1-t2); + p23 = ((t-t3)*p2+(t2-t)*p3)/(t2-t3); + result = ((t-t3)*p12+(t1-t)*p23)/(t1-t3); + return result; +} + + +/************************************************************************* +Tail(0, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma000(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-6.76984e-01, -6.83700e-01, -6.89873e-01, n2, _state); + p2 = mannwhitneyu_uninterpolate(-6.83700e-01, -6.87311e-01, -6.90957e-01, n2, _state); + p3 = mannwhitneyu_uninterpolate(-6.89873e-01, -6.90957e-01, -6.92175e-01, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(0.75, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma075(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-1.44500e+00, -1.45906e+00, -1.47063e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-1.45906e+00, -1.46856e+00, -1.47644e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-1.47063e+00, -1.47644e+00, -1.48100e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(1.5, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma150(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-2.65380e+00, -2.67352e+00, -2.69011e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-2.67352e+00, -2.68591e+00, -2.69659e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-2.69011e+00, -2.69659e+00, -2.70192e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(2.25, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma225(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-4.41465e+00, -4.42260e+00, -4.43702e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-4.42260e+00, -4.41639e+00, -4.41928e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-4.43702e+00, -4.41928e+00, -4.41030e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(3.0, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma300(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-6.89839e+00, -6.83477e+00, -6.82340e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-6.83477e+00, -6.74559e+00, -6.71117e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-6.82340e+00, -6.71117e+00, -6.64929e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(3.33, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma333(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-8.31272e+00, -8.17096e+00, -8.13125e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-8.17096e+00, -8.00156e+00, -7.93245e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-8.13125e+00, -7.93245e+00, -7.82502e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(3.66, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma367(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-9.98837e+00, -9.70844e+00, -9.62087e+00, n2, _state); + p2 = mannwhitneyu_uninterpolate(-9.70844e+00, -9.41156e+00, -9.28998e+00, n2, _state); + p3 = mannwhitneyu_uninterpolate(-9.62087e+00, -9.28998e+00, -9.11686e+00, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(4.0, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma400(ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double p1; + double p2; + double p3; + double result; + + + p1 = mannwhitneyu_uninterpolate(-1.20250e+01, -1.14911e+01, -1.13231e+01, n2, _state); + p2 = mannwhitneyu_uninterpolate(-1.14911e+01, -1.09927e+01, -1.07937e+01, n2, _state); + p3 = mannwhitneyu_uninterpolate(-1.13231e+01, -1.07937e+01, -1.05285e+01, n2, _state); + result = mannwhitneyu_uninterpolate(p1, p2, p3, n1, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 5) +*************************************************************************/ +static double mannwhitneyu_utbln5n5(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/2.611165e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -2.596264e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.412086e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.858542e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.614282e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.372686e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.524731e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.435331e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.284665e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.184141e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.298360e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 7.447272e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.938769e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.276205e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.138481e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.684625e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.558104e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 6) +*************************************************************************/ +static double mannwhitneyu_utbln5n6(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/2.738613e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -2.810459e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.684429e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.712858e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.009324e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.644391e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.034173e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.953498e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.279293e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.563485e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.971952e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.506309e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.541406e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.283205e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.016347e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.221626e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.286752e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 7) +*************************************************************************/ +static double mannwhitneyu_utbln5n7(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/2.841993e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -2.994677e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.923264e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.506190e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.054280e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.794587e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.726290e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.534180e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.517845e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.904428e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.882443e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.482988e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.114875e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.515082e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.996056e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.293581e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.349444e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 8) +*************************************************************************/ +static double mannwhitneyu_utbln5n8(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/2.927700e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.155727e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.135078e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.247203e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.309697e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.993725e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.567219e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.383704e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.002188e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.487322e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.443899e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.688270e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.600339e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.874948e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.811593e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.072353e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.659457e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 9) +*************************************************************************/ +static double mannwhitneyu_utbln5n9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.298162e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.325016e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.939852e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.563029e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.222652e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.195200e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.445665e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.204792e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.775217e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.527781e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.221948e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.242968e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.607959e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.771285e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.694026e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.481190e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 10) +*************************************************************************/ +static double mannwhitneyu_utbln5n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.061862e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.425360e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.496710e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.587658e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.812005e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.427637e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.515702e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.406867e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.796295e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.237591e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.654249e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.181165e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.011665e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.417927e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.534880e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.791255e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.871512e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 11) +*************************************************************************/ +static double mannwhitneyu_utbln5n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.115427e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.539959e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.652998e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.196503e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.054363e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.618848e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.109411e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.786668e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.215648e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.484220e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.935991e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.396191e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.894177e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.206979e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.519055e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.210326e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.189679e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 12) +*************************************************************************/ +static double mannwhitneyu_utbln5n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.162278e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.644007e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.796173e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.771177e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.290043e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.794686e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.702110e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.185959e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.416259e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.592056e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.201530e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.754365e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.978945e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.012032e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.304579e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.100378e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.728269e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 13) +*************************************************************************/ +static double mannwhitneyu_utbln5n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.203616e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.739120e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.928117e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.031605e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.519403e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.962648e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.292183e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.809293e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.465156e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.456278e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.446055e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.109490e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.218256e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.941479e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.058603e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.824402e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.830947e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 14) +*************************************************************************/ +static double mannwhitneyu_utbln5n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.240370e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.826559e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.050370e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.083408e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.743164e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.012030e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.884686e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.059656e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.327521e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.134026e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.584201e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.440618e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.524133e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.990007e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.887334e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.534977e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.705395e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 15) +*************************************************************************/ +static double mannwhitneyu_utbln5n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.851572e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.082033e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.095983e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.814595e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.073148e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.420213e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.517175e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.344180e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.371393e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.711443e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.228569e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.683483e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.267112e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.156044e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.131316e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.301023e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 16) +*************************************************************************/ +static double mannwhitneyu_utbln5n16(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.852210e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.077482e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.091186e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.797282e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.084994e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.667054e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.843909e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.456732e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.039830e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.723508e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.940608e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.478285e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.649144e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.237703e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.707410e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.874293e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 17) +*************************************************************************/ +static double mannwhitneyu_utbln5n17(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.851752e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.071259e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.084700e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.758898e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.073846e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.684838e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.964936e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.782442e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.956362e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.984727e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.196936e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.558262e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.690746e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.364855e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.401006e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.546748e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 18) +*************************************************************************/ +static double mannwhitneyu_utbln5n18(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.850840e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.064799e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.077651e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.712659e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.049217e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.571333e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.929809e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.752044e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.949464e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.896101e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.614460e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.384357e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.489113e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.445725e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.945636e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.424653e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 19) +*************************************************************************/ +static double mannwhitneyu_utbln5n19(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.850027e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.059159e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.071106e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.669960e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.022780e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.442555e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.851335e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.433865e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.514465e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.332989e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.606099e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.341945e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.402164e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.039761e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.512831e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.284427e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 20) +*************************************************************************/ +static double mannwhitneyu_utbln5n20(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.849651e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.054729e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.065747e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.636243e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.003234e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.372789e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.831551e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.763090e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.830626e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.122384e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.108328e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.557983e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.945666e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.965696e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.493236e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.162591e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 21) +*************************************************************************/ +static double mannwhitneyu_utbln5n21(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.849649e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.051155e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.061430e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.608869e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.902788e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.346562e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.874709e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.682887e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.026206e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.534551e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.990575e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.713334e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.737011e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.304571e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.133110e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.123457e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 22) +*************************************************************************/ +static double mannwhitneyu_utbln5n22(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.849598e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.047605e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.057264e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.579513e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.749602e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.275137e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.881768e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.177374e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.981056e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.696290e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.886803e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.085378e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.675242e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.426367e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.039613e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.662378e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 23) +*************************************************************************/ +static double mannwhitneyu_utbln5n23(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.849269e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.043761e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.052735e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.544683e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.517503e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.112082e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.782070e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.549483e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.747329e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.694263e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.147141e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.526209e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.039173e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.235615e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.656546e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.014423e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 24) +*************************************************************************/ +static double mannwhitneyu_utbln5n24(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.848925e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.040178e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.048355e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.510198e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.261134e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.915864e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.627423e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.307345e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.732992e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.869652e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.494176e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.047533e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.178439e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.424171e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.829195e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.840810e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 25) +*************************************************************************/ +static double mannwhitneyu_utbln5n25(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.848937e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.037512e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.044866e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.483269e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.063682e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.767778e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.508540e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.332756e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.881511e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.124041e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.368456e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.930499e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.779630e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.029528e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.658678e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.289695e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 26) +*************************************************************************/ +static double mannwhitneyu_utbln5n26(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.849416e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.035915e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.042493e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.466021e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.956432e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.698914e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.465689e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.035254e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.674614e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.492734e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.014021e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.944953e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.255750e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.075841e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.989330e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.134862e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 27) +*************************************************************************/ +static double mannwhitneyu_utbln5n27(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.850070e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.034815e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.040650e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.453117e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.886426e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.661702e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.452346e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.002476e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.720126e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.001400e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.729826e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.740640e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.206333e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.366093e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.193471e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.804091e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 28) +*************************************************************************/ +static double mannwhitneyu_utbln5n28(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.850668e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.033786e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.038853e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.440281e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.806020e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.612883e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.420436e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.787982e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.535230e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.263121e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.849609e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.863967e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.391610e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.720294e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.952273e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.901413e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 29) +*************************************************************************/ +static double mannwhitneyu_utbln5n29(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.851217e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.032834e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.037113e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.427762e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.719146e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.557172e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.375498e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.452033e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.187516e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.916936e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.065533e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.067301e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.615824e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.432244e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.417795e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.710038e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 30) +*************************************************************************/ +static double mannwhitneyu_utbln5n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.851845e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.032148e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.035679e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.417758e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.655330e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.522132e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.352106e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.326911e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.064969e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.813321e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.683881e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.813346e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.627085e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.832107e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.519336e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.888530e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 5, 100) +*************************************************************************/ +static double mannwhitneyu_utbln5n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.250000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.877940e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.039324e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.022243e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.305825e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.960119e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.112000e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.138868e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.418164e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.174520e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.489617e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.878301e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.302233e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.054113e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.458862e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.186591e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.623412e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 6) +*************************************************************************/ +static double mannwhitneyu_utbln6n6(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/2.882307e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.054075e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.998804e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.681518e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.067578e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.709435e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.952661e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.641700e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.304572e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.336275e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.770385e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.401891e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.246148e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.442663e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.502866e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.105855e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.739371e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 7) +*************************************************************************/ +static double mannwhitneyu_utbln6n7(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.000000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.265287e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.274613e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.582352e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.334293e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.915502e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.108091e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.546701e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.298827e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.891501e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.313717e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.989501e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.914594e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.062372e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.158841e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.596443e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.185662e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 8) +*************************************************************************/ +static double mannwhitneyu_utbln6n8(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.098387e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.450954e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.520462e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.420299e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.604853e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.165840e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.008756e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.723402e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.843521e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.883405e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.720980e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.301709e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.948034e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.776243e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.623736e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.742068e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.796927e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 9) +*************************************************************************/ +static double mannwhitneyu_utbln6n9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.181981e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.616113e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.741650e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.204487e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.873068e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.446794e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.632286e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.266481e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.280067e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.780687e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.480242e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.592200e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.581019e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.264231e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.347174e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.167535e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.092185e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 10) +*************************************************************************/ +static double mannwhitneyu_utbln6n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.253957e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.764382e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.942366e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.939896e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.137812e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.720270e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.281070e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.901060e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.824937e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.802812e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.258132e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.233536e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.085530e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.212151e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.001329e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.226048e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.035298e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 11) +*************************************************************************/ +static double mannwhitneyu_utbln6n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.316625e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.898597e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.125710e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.063297e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.396852e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.990126e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.927977e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.726500e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.858745e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.654590e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.217736e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.989770e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.768493e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.924364e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.140215e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.647914e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.924802e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 12) +*************************************************************************/ +static double mannwhitneyu_utbln6n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.371709e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.020941e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.294250e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.128842e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.650389e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.248611e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.578510e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.162852e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.746982e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.454209e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.128042e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.936650e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.530794e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.665192e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.994144e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.662249e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.368541e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 13) +*************************************************************************/ +static double mannwhitneyu_utbln6n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.420526e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.133167e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.450016e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.191088e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.898220e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.050249e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.226901e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.471113e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.007470e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.049420e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.059074e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.881249e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.452780e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.441805e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.787493e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.483957e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.481590e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 14) +*************************************************************************/ +static double mannwhitneyu_utbln6n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.450000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.201268e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.542568e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.226965e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.046029e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.136657e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.786757e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.843748e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.588022e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.253029e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.667188e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.788330e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.474545e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.540494e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.951188e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.863323e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.220904e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 15) +*************************************************************************/ +static double mannwhitneyu_utbln6n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.450000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.195689e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.526567e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.213617e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.975035e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.118480e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.859142e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.083312e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.298720e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.766708e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.026356e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.093113e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.135168e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.136376e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.190870e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.435972e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.413129e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 30) +*************************************************************************/ +static double mannwhitneyu_utbln6n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.450000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.166269e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.427399e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.118239e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.360847e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.745885e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.025041e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.187179e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.432089e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.408451e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.388774e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.795560e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.304136e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.258516e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.180236e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.388679e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.836027e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 6, 100) +*************************************************************************/ +static double mannwhitneyu_utbln6n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.450000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.181350e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.417919e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.094201e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.195883e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.818937e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.514202e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.125047e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.022148e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.284181e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.157766e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.023752e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.127985e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.221690e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.516179e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.501398e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.380220e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 7) +*************************************************************************/ +static double mannwhitneyu_utbln7n7(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.130495e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.501264e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.584790e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.577311e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.617002e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.145186e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.023462e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.408251e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.626515e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.072492e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.722926e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.095445e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.842602e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.751427e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.008927e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.892431e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.772386e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 8) +*************************************************************************/ +static double mannwhitneyu_utbln7n8(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.240370e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.709965e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.862154e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.504541e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.900195e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.439995e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.678028e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.485540e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.437047e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.440092e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.114227e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.516569e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.829457e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.787550e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.761866e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.991911e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.533481e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 9) +*************************************************************************/ +static double mannwhitneyu_utbln7n9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.334314e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.896550e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.112671e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.037277e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.181695e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.765190e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.360116e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.695960e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.780578e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.963843e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.616148e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.852104e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.390744e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.014041e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.888101e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.467474e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.004611e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 10) +*************************************************************************/ +static double mannwhitneyu_utbln7n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.415650e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.064844e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.340749e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.118888e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.459730e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.097781e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.057688e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.097406e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.209262e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.065641e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.196677e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.313994e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.827157e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.822284e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.389090e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.340850e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.395172e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 11) +*************************************************************************/ +static double mannwhitneyu_utbln7n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.486817e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.217795e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.549783e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.195905e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.733093e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.428447e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.760093e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.431676e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.717152e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.032199e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.832423e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.905979e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.302799e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.464371e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.456211e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.736244e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.140712e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 12) +*************************************************************************/ +static double mannwhitneyu_utbln7n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.235822e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.564100e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.190813e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.686546e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.395083e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.967359e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.747096e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.304144e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.903198e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.134906e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.175035e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.266224e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.892931e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.604706e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.070459e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.427010e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 13) +*************************************************************************/ +static double mannwhitneyu_utbln7n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.222204e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.532300e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.164642e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.523768e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.531984e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.467857e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.483804e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.524136e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.077740e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.745218e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.602085e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.828831e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.994070e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.873879e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.341937e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.706444e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 14) +*************************************************************************/ +static double mannwhitneyu_utbln7n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.211763e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.507542e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.143640e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.395755e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.808020e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.044259e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.182308e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.057325e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.724255e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.303900e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.113148e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.102514e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.559442e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.634986e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.776476e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.054489e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 15) +*************************************************************************/ +static double mannwhitneyu_utbln7n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.204898e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.489960e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.129172e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.316741e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.506107e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.983676e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.258013e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.262515e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.984156e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.912108e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.974023e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.056195e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.090842e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.232620e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.816339e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.020421e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 30) +*************************************************************************/ +static double mannwhitneyu_utbln7n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.176536e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.398705e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.045481e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.821982e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.962304e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.698132e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.062667e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.282353e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.014836e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.035683e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.004137e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.801453e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.920705e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.518735e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.821501e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.801008e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 7, 100) +*************************************************************************/ +static double mannwhitneyu_utbln7n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.500000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.188337e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.386949e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.022834e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.686517e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.323516e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.399392e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.644333e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.617044e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.031396e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.792066e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.675457e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.673416e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.258552e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.174214e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.073644e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.349958e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 8) +*************************************************************************/ +static double mannwhitneyu_utbln8n8(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.360672e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -3.940217e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.168913e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.051485e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.195325e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.775196e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.385506e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.244902e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.525632e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.771275e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.332874e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.079599e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.882551e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.407944e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.769844e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.062433e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.872535e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 9) +*************************************************************************/ +static double mannwhitneyu_utbln8n9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.464102e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.147004e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.446939e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.146155e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.488561e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.144561e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.116917e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.205667e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.515661e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.618616e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.599011e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.457324e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.482917e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.488267e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.469823e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.957591e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.058326e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 10) +*************************************************************************/ +static double mannwhitneyu_utbln8n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.554093e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.334282e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.700860e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.235253e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.778489e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.527324e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.862885e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.589781e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.507355e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.717526e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.215726e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.848696e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.918854e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.219614e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.753761e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.573688e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.602177e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 11) +*************************************************************************/ +static double mannwhitneyu_utbln8n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.421882e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.812457e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.266153e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.849344e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.971527e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.258944e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.944820e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.894685e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.031836e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.514330e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.351660e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.206748e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.492600e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.005338e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.780099e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.673599e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 12) +*************************************************************************/ +static double mannwhitneyu_utbln8n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.398211e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.762214e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.226296e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.603837e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.643223e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.502438e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.544574e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.647734e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.442259e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.011484e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.384758e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.998259e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.659985e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.331046e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.638478e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.056785e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 13) +*************************************************************************/ +static double mannwhitneyu_utbln8n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.380670e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.724511e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.195851e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.420511e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.609928e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.893999e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.115919e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.291410e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.339664e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.801548e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.534710e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.793250e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.806718e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.384624e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.120582e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.936453e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 14) +*************************************************************************/ +static double mannwhitneyu_utbln8n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.368494e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.697171e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.174440e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.300621e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.087393e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.685826e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.085254e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.525658e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.966647e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.453388e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.826066e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.501958e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.336297e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.251972e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.118456e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.415959e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 15) +*************************************************************************/ +static double mannwhitneyu_utbln8n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.358397e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.674485e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.155941e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.195780e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.544830e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.426183e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.309902e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.650956e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.068874e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.538544e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.192525e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.073905e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.079673e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.423572e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.579647e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.765904e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 30) +*************************************************************************/ +static double mannwhitneyu_utbln8n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.318823e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.567159e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.064864e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.688413e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.153712e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.309389e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.226861e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.523815e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.780987e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.166866e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.922431e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.466397e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.690036e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.008185e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.271903e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.534751e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 8, 100) +*************************************************************************/ +static double mannwhitneyu_utbln8n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.600000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.324531e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.547071e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.038129e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.541549e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.525605e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.044992e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.085713e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.017871e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.459226e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.092064e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.024349e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 7.366347e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.385637e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.321722e-08, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.439286e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.058079e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 9) +*************************************************************************/ +static double mannwhitneyu_utbln9n9(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.576237e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.372857e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.750859e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.248233e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.792868e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.559372e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.894941e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.643256e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.091370e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.285034e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.112997e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.806229e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.150741e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.509825e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.891051e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.485013e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.343653e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 10) +*************************************************************************/ +static double mannwhitneyu_utbln9n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.516726e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.939333e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.305046e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.935326e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.029141e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.420592e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.053140e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.065930e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.523581e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.544888e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.813741e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.510631e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.536057e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.833815e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.189692e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.615050e-03, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 11) +*************************************************************************/ +static double mannwhitneyu_utbln9n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.481308e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.867483e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.249072e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.591790e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.400128e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.341992e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.463680e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.487211e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.671196e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.343472e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.544146e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.802335e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.117084e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.217443e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.858766e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.193687e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 12) +*************************************************************************/ +static double mannwhitneyu_utbln9n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.456776e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.817037e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.209788e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.362108e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.171356e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.661557e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.026141e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.361908e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.093885e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.298389e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.663603e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.768522e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.579015e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.868677e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.440652e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.523037e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 13) +*************************************************************************/ +static double mannwhitneyu_utbln9n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.438840e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.779308e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.180614e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.196489e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.346621e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.234857e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.796211e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.575715e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.525647e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.964651e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.275235e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.299124e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.397416e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.295781e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.237619e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 7.269692e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 14) +*************************************************************************/ +static double mannwhitneyu_utbln9n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.425981e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.751545e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.159543e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.086570e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.917446e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.120112e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.175519e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.515473e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.727772e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.070629e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.677569e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.876953e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.233502e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.508182e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.120389e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.847212e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 15) +*************************************************************************/ +static double mannwhitneyu_utbln9n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.414952e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.727612e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.140634e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.981231e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.382635e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.853575e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.571051e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.567625e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.214197e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.448700e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.712669e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.015050e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.438610e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.301363e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.309386e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.164772e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 30) +*************************************************************************/ +static double mannwhitneyu_utbln9n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.370720e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.615712e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.050023e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.504775e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.318265e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.646826e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.741492e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.735360e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.966911e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.100738e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.348991e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.527687e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.917286e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.397466e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.360175e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.892252e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 9, 100) +*************************************************************************/ +static double mannwhitneyu_utbln9n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.372506e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.590966e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.021758e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.359849e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.755519e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.533166e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.936659e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.634913e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.730053e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.791845e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.030682e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.228663e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.631175e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.636749e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.404599e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.789872e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 10) +*************************************************************************/ +static double mannwhitneyu_utbln10n10(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.468831e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.844398e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.231728e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.486073e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.781321e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.971425e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.215371e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.828451e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.419872e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.430165e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.740363e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.049211e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.269371e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.211393e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.232314e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.016081e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 11) +*************************************************************************/ +static double mannwhitneyu_utbln10n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.437998e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.782296e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.184732e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.219585e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.457012e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.296008e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.481501e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.527940e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.953426e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.563840e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.574403e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.535775e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.338037e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.002654e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.852676e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.318132e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 12) +*************************************************************************/ +static double mannwhitneyu_utbln10n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.416082e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.737458e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.150952e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.036884e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.609030e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.908684e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.439666e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.162647e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.451601e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.148757e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.803981e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.731621e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.346903e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.013151e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.956148e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.438381e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 13) +*************************************************************************/ +static double mannwhitneyu_utbln10n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.399480e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.702863e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.124829e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.897428e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.979802e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.634368e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.180461e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.484926e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.864376e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.186576e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.886925e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.836828e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.074756e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.209547e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.883266e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.380143e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 14) +*************************************************************************/ +static double mannwhitneyu_utbln10n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.386924e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.676124e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.104740e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.793826e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.558886e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.492462e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.052903e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.917782e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.878696e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.576046e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.764551e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.288778e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.757658e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.299101e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.265197e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.384503e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 15) +*************************************************************************/ +static double mannwhitneyu_utbln10n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.376846e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.654247e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.088083e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.705945e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.169677e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.317213e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.264836e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.548024e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.633910e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.505621e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.658588e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.320254e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.175277e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.122317e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.675688e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.661363e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 30) +*************************************************************************/ +static double mannwhitneyu_utbln10n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.333977e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.548099e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.004444e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.291014e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.523674e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.828211e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.716917e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.894256e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.433371e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.522675e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.764192e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.140235e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.629230e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.541895e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.944946e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.726360e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 10, 100) +*************************************************************************/ +static double mannwhitneyu_utbln10n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.650000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.334008e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.522316e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.769627e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.158110e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.053650e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.242235e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.173571e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.033661e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.824732e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.084420e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.610036e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.728155e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.217130e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.340966e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.001235e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.694052e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 11) +*************************************************************************/ +static double mannwhitneyu_utbln11n11(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.519760e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.880694e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.200698e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.174092e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.072304e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.054773e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.506613e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.813942e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.223644e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.417416e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.499166e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.194332e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 7.369096e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.968590e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.630532e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.061000e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 12) +*************************************************************************/ +static double mannwhitneyu_utbln11n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.495790e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.832622e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.165420e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.987306e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.265621e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.723537e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.347406e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.353464e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.613369e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.102522e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.237709e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.665652e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.626903e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.167518e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.564455e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.047320e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 13) +*************************************************************************/ +static double mannwhitneyu_utbln11n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.477880e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.796242e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.138769e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.851739e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.722104e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.548304e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.176683e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.817895e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.842451e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.935870e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.421777e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.238831e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.867026e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.458255e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.306259e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.961487e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 14) +*************************************************************************/ +static double mannwhitneyu_utbln11n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.463683e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.766969e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.117082e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.739574e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.238865e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.350306e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.425871e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.640172e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.660633e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.879883e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.349658e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.271795e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.304544e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.024201e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.816867e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.596787e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 15) +*************************************************************************/ +static double mannwhitneyu_utbln11n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.452526e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.743570e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.099705e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.650612e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.858285e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.187036e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.689241e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.294360e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.072623e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.278008e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.322382e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.131558e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.305669e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.825627e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.332689e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.120973e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 30) +*************************************************************************/ +static double mannwhitneyu_utbln11n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.402621e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.627440e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.011333e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.224126e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.232856e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.859347e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.377381e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.756709e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.033230e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.875472e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.608399e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.102943e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.740693e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.343139e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.196878e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.658062e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 11, 100) +*************************************************************************/ +static double mannwhitneyu_utbln11n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.398795e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.596486e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.814761e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.085187e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.766529e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.379425e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.986351e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.214705e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.360075e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.260869e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.033307e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.727087e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.393883e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.242989e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.111928e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.898823e-09, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 12) +*************************************************************************/ +static double mannwhitneyu_utbln12n12(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.472616e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.786627e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.132099e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.817523e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.570179e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.479511e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.799492e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.565350e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.530139e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.380132e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.242761e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.576269e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.018771e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.933911e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.002799e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.022048e-06, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 13) +*************************************************************************/ +static double mannwhitneyu_utbln12n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.454800e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.750794e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.105988e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.684754e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.011826e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.262579e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.044492e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.478741e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.322165e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.621104e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.068753e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.468396e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.056235e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.327375e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.914877e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.784191e-04, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 14) +*************************************************************************/ +static double mannwhitneyu_utbln12n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.440910e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.722404e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.085254e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.579439e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.563738e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.066730e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.129346e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.014531e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.129679e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.000909e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.996174e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.377924e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.936304e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.051098e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.025820e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 8.730585e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 15) +*************************************************************************/ +static double mannwhitneyu_utbln12n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.430123e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.700008e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.068971e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.499725e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.250897e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.473145e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.680008e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.483350e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.766992e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.891081e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.015140e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.977756e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.707414e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.114786e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.238865e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.381445e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 30) +*************************************************************************/ +static double mannwhitneyu_utbln12n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.380023e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.585782e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.838583e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.103394e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.834015e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.635212e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.948212e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.574169e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.747980e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.833672e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.722433e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.181038e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.206473e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.716003e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.476434e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.217700e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 12, 100) +*************************************************************************/ +static double mannwhitneyu_utbln12n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.700000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.374567e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.553481e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.541334e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.701907e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.414757e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.404103e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.234388e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.453762e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.311060e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.317501e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.713888e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.309583e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.019804e-08, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.224829e-09, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.349019e-08, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.893302e-08, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 13, 13) +*************************************************************************/ +static double mannwhitneyu_utbln13n13(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.541046e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.859047e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.130164e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.689719e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.950693e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.231455e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.976550e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.538455e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.245603e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.142647e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.831434e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.032483e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.488405e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.156927e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.949279e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.532700e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 13, 14) +*************************************************************************/ +static double mannwhitneyu_utbln13n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.525655e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.828341e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.108110e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.579552e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.488307e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.032328e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.988741e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.766394e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.388950e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.338179e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.133440e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.023518e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.110570e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.202332e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.056132e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.536323e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 13, 15) +*************************************************************************/ +static double mannwhitneyu_utbln13n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.513585e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.803952e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.090686e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.495310e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.160314e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.073124e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.480313e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.478239e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.140914e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.311541e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.677105e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.115464e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.578563e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.044604e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.888939e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 2.395644e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 13, 30) +*************************************************************************/ +static double mannwhitneyu_utbln13n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.455999e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.678434e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.995491e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.078100e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.705220e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.258739e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.671526e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.185458e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.507764e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.411446e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.044355e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.285765e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.345282e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.066940e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.962037e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.723644e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 13, 100) +*************************************************************************/ +static double mannwhitneyu_utbln13n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.446787e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.640804e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.671552e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.364990e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.274444e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.047440e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.161439e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.171729e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.562171e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.359762e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.275494e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.747635e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.700292e-08, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.565559e-09, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 5.005396e-09, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 3.335794e-09, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 14, 14) +*************************************************************************/ +static double mannwhitneyu_utbln14n14(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.510624e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.798584e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.087107e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.478532e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.098050e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.855986e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.409083e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.299536e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.176177e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.479417e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.812761e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -5.225872e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 4.516521e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 6.730551e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 9.237563e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.611820e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 14, 15) +*************************************************************************/ +static double mannwhitneyu_utbln14n15(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.498681e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.774668e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.070267e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.399348e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.807239e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.845763e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.071773e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.261698e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.011695e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.305946e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.879295e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.999439e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.904438e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.944986e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.373908e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.140794e-05, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 14, 30) +*************************************************************************/ +static double mannwhitneyu_utbln14n30(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.440378e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.649587e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.807829e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.989753e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.463646e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.586580e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -6.745917e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.635398e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.923172e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.446699e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.613892e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.214073e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.651683e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.272777e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.464988e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.109803e-07, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, 14, 100) +*************************************************************************/ +static double mannwhitneyu_utbln14n100(double s, ae_state *_state) +{ + double x; + double tj; + double tj1; + double result; + + + result = (double)(0); + x = ae_minreal((double)2*(s-0.000000e+00)/3.750000e+00-(double)1, 1.0, _state); + tj = (double)(1); + tj1 = x; + mannwhitneyu_ucheb(x, -4.429701e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -4.610577e+00, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -9.482675e-01, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.605550e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.062151e-02, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.525154e-03, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.835983e-04, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -8.411440e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.744901e-05, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.318850e-06, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.692100e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -1.536270e-07, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -3.705888e-08, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -7.999599e-09, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, -2.908395e-09, &tj, &tj1, &result, _state); + mannwhitneyu_ucheb(x, 1.546923e-09, &tj, &tj1, &result, _state); + return result; +} + + +/************************************************************************* +Tail(S, N1, N2) +*************************************************************************/ +static double mannwhitneyu_usigma(double s, + ae_int_t n1, + ae_int_t n2, + ae_state *_state) +{ + double f0; + double f1; + double f2; + double f3; + double f4; + double s0; + double s1; + double s2; + double s3; + double s4; + double result; + + + result = (double)(0); + + /* + * N1=5, N2 = 5, 6, 7, ... + */ + if( ae_minint(n1, n2, _state)==5 ) + { + if( ae_maxint(n1, n2, _state)==5 ) + { + result = mannwhitneyu_utbln5n5(s, _state); + } + if( ae_maxint(n1, n2, _state)==6 ) + { + result = mannwhitneyu_utbln5n6(s, _state); + } + if( ae_maxint(n1, n2, _state)==7 ) + { + result = mannwhitneyu_utbln5n7(s, _state); + } + if( ae_maxint(n1, n2, _state)==8 ) + { + result = mannwhitneyu_utbln5n8(s, _state); + } + if( ae_maxint(n1, n2, _state)==9 ) + { + result = mannwhitneyu_utbln5n9(s, _state); + } + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln5n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln5n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln5n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln5n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln5n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln5n15(s, _state); + } + if( ae_maxint(n1, n2, _state)==16 ) + { + result = mannwhitneyu_utbln5n16(s, _state); + } + if( ae_maxint(n1, n2, _state)==17 ) + { + result = mannwhitneyu_utbln5n17(s, _state); + } + if( ae_maxint(n1, n2, _state)==18 ) + { + result = mannwhitneyu_utbln5n18(s, _state); + } + if( ae_maxint(n1, n2, _state)==19 ) + { + result = mannwhitneyu_utbln5n19(s, _state); + } + if( ae_maxint(n1, n2, _state)==20 ) + { + result = mannwhitneyu_utbln5n20(s, _state); + } + if( ae_maxint(n1, n2, _state)==21 ) + { + result = mannwhitneyu_utbln5n21(s, _state); + } + if( ae_maxint(n1, n2, _state)==22 ) + { + result = mannwhitneyu_utbln5n22(s, _state); + } + if( ae_maxint(n1, n2, _state)==23 ) + { + result = mannwhitneyu_utbln5n23(s, _state); + } + if( ae_maxint(n1, n2, _state)==24 ) + { + result = mannwhitneyu_utbln5n24(s, _state); + } + if( ae_maxint(n1, n2, _state)==25 ) + { + result = mannwhitneyu_utbln5n25(s, _state); + } + if( ae_maxint(n1, n2, _state)==26 ) + { + result = mannwhitneyu_utbln5n26(s, _state); + } + if( ae_maxint(n1, n2, _state)==27 ) + { + result = mannwhitneyu_utbln5n27(s, _state); + } + if( ae_maxint(n1, n2, _state)==28 ) + { + result = mannwhitneyu_utbln5n28(s, _state); + } + if( ae_maxint(n1, n2, _state)==29 ) + { + result = mannwhitneyu_utbln5n29(s, _state); + } + if( ae_maxint(n1, n2, _state)>29 ) + { + f0 = mannwhitneyu_utbln5n15(s, _state); + f1 = mannwhitneyu_utbln5n30(s, _state); + f2 = mannwhitneyu_utbln5n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=6, N2 = 6, 7, 8, ... + */ + if( ae_minint(n1, n2, _state)==6 ) + { + if( ae_maxint(n1, n2, _state)==6 ) + { + result = mannwhitneyu_utbln6n6(s, _state); + } + if( ae_maxint(n1, n2, _state)==7 ) + { + result = mannwhitneyu_utbln6n7(s, _state); + } + if( ae_maxint(n1, n2, _state)==8 ) + { + result = mannwhitneyu_utbln6n8(s, _state); + } + if( ae_maxint(n1, n2, _state)==9 ) + { + result = mannwhitneyu_utbln6n9(s, _state); + } + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln6n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln6n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln6n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln6n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln6n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln6n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln6n15(s, _state); + f1 = mannwhitneyu_utbln6n30(s, _state); + f2 = mannwhitneyu_utbln6n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=7, N2 = 7, 8, ... + */ + if( ae_minint(n1, n2, _state)==7 ) + { + if( ae_maxint(n1, n2, _state)==7 ) + { + result = mannwhitneyu_utbln7n7(s, _state); + } + if( ae_maxint(n1, n2, _state)==8 ) + { + result = mannwhitneyu_utbln7n8(s, _state); + } + if( ae_maxint(n1, n2, _state)==9 ) + { + result = mannwhitneyu_utbln7n9(s, _state); + } + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln7n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln7n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln7n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln7n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln7n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln7n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln7n15(s, _state); + f1 = mannwhitneyu_utbln7n30(s, _state); + f2 = mannwhitneyu_utbln7n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=8, N2 = 8, 9, 10, ... + */ + if( ae_minint(n1, n2, _state)==8 ) + { + if( ae_maxint(n1, n2, _state)==8 ) + { + result = mannwhitneyu_utbln8n8(s, _state); + } + if( ae_maxint(n1, n2, _state)==9 ) + { + result = mannwhitneyu_utbln8n9(s, _state); + } + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln8n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln8n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln8n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln8n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln8n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln8n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln8n15(s, _state); + f1 = mannwhitneyu_utbln8n30(s, _state); + f2 = mannwhitneyu_utbln8n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=9, N2 = 9, 10, ... + */ + if( ae_minint(n1, n2, _state)==9 ) + { + if( ae_maxint(n1, n2, _state)==9 ) + { + result = mannwhitneyu_utbln9n9(s, _state); + } + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln9n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln9n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln9n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln9n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln9n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln9n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln9n15(s, _state); + f1 = mannwhitneyu_utbln9n30(s, _state); + f2 = mannwhitneyu_utbln9n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=10, N2 = 10, 11, ... + */ + if( ae_minint(n1, n2, _state)==10 ) + { + if( ae_maxint(n1, n2, _state)==10 ) + { + result = mannwhitneyu_utbln10n10(s, _state); + } + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln10n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln10n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln10n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln10n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln10n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln10n15(s, _state); + f1 = mannwhitneyu_utbln10n30(s, _state); + f2 = mannwhitneyu_utbln10n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=11, N2 = 11, 12, ... + */ + if( ae_minint(n1, n2, _state)==11 ) + { + if( ae_maxint(n1, n2, _state)==11 ) + { + result = mannwhitneyu_utbln11n11(s, _state); + } + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln11n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln11n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln11n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln11n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln11n15(s, _state); + f1 = mannwhitneyu_utbln11n30(s, _state); + f2 = mannwhitneyu_utbln11n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=12, N2 = 12, 13, ... + */ + if( ae_minint(n1, n2, _state)==12 ) + { + if( ae_maxint(n1, n2, _state)==12 ) + { + result = mannwhitneyu_utbln12n12(s, _state); + } + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln12n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln12n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln12n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln12n15(s, _state); + f1 = mannwhitneyu_utbln12n30(s, _state); + f2 = mannwhitneyu_utbln12n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=13, N2 = 13, 14, ... + */ + if( ae_minint(n1, n2, _state)==13 ) + { + if( ae_maxint(n1, n2, _state)==13 ) + { + result = mannwhitneyu_utbln13n13(s, _state); + } + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln13n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln13n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln13n15(s, _state); + f1 = mannwhitneyu_utbln13n30(s, _state); + f2 = mannwhitneyu_utbln13n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1=14, N2 = 14, 15, ... + */ + if( ae_minint(n1, n2, _state)==14 ) + { + if( ae_maxint(n1, n2, _state)==14 ) + { + result = mannwhitneyu_utbln14n14(s, _state); + } + if( ae_maxint(n1, n2, _state)==15 ) + { + result = mannwhitneyu_utbln14n15(s, _state); + } + if( ae_maxint(n1, n2, _state)>15 ) + { + f0 = mannwhitneyu_utbln14n15(s, _state); + f1 = mannwhitneyu_utbln14n30(s, _state); + f2 = mannwhitneyu_utbln14n100(s, _state); + result = mannwhitneyu_uninterpolate(f0, f1, f2, ae_maxint(n1, n2, _state), _state); + } + return result; + } + + /* + * N1 >= 15, N2 >= 15 + */ + if( ae_fp_greater(s,(double)(4)) ) + { + s = (double)(4); + } + if( ae_fp_less(s,(double)(3)) ) + { + s0 = 0.000000e+00; + f0 = mannwhitneyu_usigma000(n1, n2, _state); + s1 = 7.500000e-01; + f1 = mannwhitneyu_usigma075(n1, n2, _state); + s2 = 1.500000e+00; + f2 = mannwhitneyu_usigma150(n1, n2, _state); + s3 = 2.250000e+00; + f3 = mannwhitneyu_usigma225(n1, n2, _state); + s4 = 3.000000e+00; + f4 = mannwhitneyu_usigma300(n1, n2, _state); + f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); + f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); + f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); + f4 = ((s-s0)*f4-(s-s4)*f0)/(s4-s0); + f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); + f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); + f4 = ((s-s1)*f4-(s-s4)*f1)/(s4-s1); + f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); + f4 = ((s-s2)*f4-(s-s4)*f2)/(s4-s2); + f4 = ((s-s3)*f4-(s-s4)*f3)/(s4-s3); + result = f4; + } + else + { + s0 = 3.000000e+00; + f0 = mannwhitneyu_usigma300(n1, n2, _state); + s1 = 3.333333e+00; + f1 = mannwhitneyu_usigma333(n1, n2, _state); + s2 = 3.666667e+00; + f2 = mannwhitneyu_usigma367(n1, n2, _state); + s3 = 4.000000e+00; + f3 = mannwhitneyu_usigma400(n1, n2, _state); + f1 = ((s-s0)*f1-(s-s1)*f0)/(s1-s0); + f2 = ((s-s0)*f2-(s-s2)*f0)/(s2-s0); + f3 = ((s-s0)*f3-(s-s3)*f0)/(s3-s0); + f2 = ((s-s1)*f2-(s-s2)*f1)/(s2-s1); + f3 = ((s-s1)*f3-(s-s3)*f1)/(s3-s1); + f3 = ((s-s2)*f3-(s-s3)*f2)/(s3-s2); + result = f3; + } + return result; +} + + +#endif + +} + diff --git a/core/alglib/statistics.h b/core/alglib/statistics.h index d3249461..a815043b 100644 --- a/core/alglib/statistics.h +++ b/core/alglib/statistics.h @@ -1,1305 +1,2293 @@ -/************************************************************************* -Copyright (c) Sergey Bochkanov (ALGLIB project). - ->>> SOURCE LICENSE >>> -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation (www.fsf.org); either version 2 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -A copy of the GNU General Public License is available at -http://www.fsf.org/licensing/licenses ->>> END OF LICENSE >>> -*************************************************************************/ -#ifndef _statistics_pkg_h -#define _statistics_pkg_h -#include "ap.h" -#include "alglibinternal.h" -#include "linalg.h" -#include "specialfunctions.h" - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ - -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS C++ INTERFACE -// -///////////////////////////////////////////////////////////////////////// -namespace alglib -{ - - -/************************************************************************* -Calculation of the distribution moments: mean, variance, skewness, kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -OUTPUT PARAMETERS - Mean - mean. - Variance- variance. - Skewness- skewness (if variance<>0; zero otherwise). - Kurtosis- kurtosis (if variance<>0; zero otherwise). - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis); -void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis); - - -/************************************************************************* -Calculation of the mean. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Mean' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplemean(const real_1d_array &x, const ae_int_t n); -double samplemean(const real_1d_array &x); - - -/************************************************************************* -Calculation of the variance. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Variance' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplevariance(const real_1d_array &x, const ae_int_t n); -double samplevariance(const real_1d_array &x); - - -/************************************************************************* -Calculation of the skewness. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Skewness' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double sampleskewness(const real_1d_array &x, const ae_int_t n); -double sampleskewness(const real_1d_array &x); - - -/************************************************************************* -Calculation of the kurtosis. - -INPUT PARAMETERS: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -NOTE: - -This function return result which calculated by 'SampleMoments' function -and stored at 'Kurtosis' variable. - - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -double samplekurtosis(const real_1d_array &x, const ae_int_t n); -double samplekurtosis(const real_1d_array &x); - - -/************************************************************************* -ADev - -Input parameters: - X - sample - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - ADev- ADev - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev); -void sampleadev(const real_1d_array &x, double &adev); - - -/************************************************************************* -Median calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - -Output parameters: - Median - - -- ALGLIB -- - Copyright 06.09.2006 by Bochkanov Sergey -*************************************************************************/ -void samplemedian(const real_1d_array &x, const ae_int_t n, double &median); -void samplemedian(const real_1d_array &x, double &median); - - -/************************************************************************* -Percentile calculation. - -Input parameters: - X - sample (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only leading N elements of X are processed - * if not given, automatically determined from size of X - P - percentile (0<=P<=1) - -Output parameters: - V - percentile - - -- ALGLIB -- - Copyright 01.03.2008 by Bochkanov Sergey -*************************************************************************/ -void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v); -void samplepercentile(const real_1d_array &x, const double p, double &v); - - -/************************************************************************* -2-sample covariance - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - covariance (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); -double cov2(const real_1d_array &x, const real_1d_array &y); - - -/************************************************************************* -Pearson product-moment correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Pearson product-moment correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); -double pearsoncorr2(const real_1d_array &x, const real_1d_array &y); - - -/************************************************************************* -Spearman's rank correlation coefficient - -Input parameters: - X - sample 1 (array indexes: [0..N-1]) - Y - sample 2 (array indexes: [0..N-1]) - N - N>=0, sample size: - * if given, only N leading elements of X/Y are processed - * if not given, automatically determined from input sizes - -Result: - Spearman's rank correlation coefficient - (zero for N=0 or N=1) - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); -double spearmancorr2(const real_1d_array &x, const real_1d_array &y); - - -/************************************************************************* -Covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void smp_covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void covm(const real_2d_array &x, real_2d_array &c); -void smp_covm(const real_2d_array &x, real_2d_array &c); - - -/************************************************************************* -Pearson product-moment correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void smp_pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void pearsoncorrm(const real_2d_array &x, real_2d_array &c); -void smp_pearsoncorrm(const real_2d_array &x, real_2d_array &c); - - -/************************************************************************* -Spearman's rank correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X are used - * if not given, automatically determined from input size - M - M>0, number of variables: - * if given, only leading M columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M,M], correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void smp_spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c); -void spearmancorrm(const real_2d_array &x, real_2d_array &c); -void smp_spearmancorrm(const real_2d_array &x, real_2d_array &c); - - -/************************************************************************* -Cross-covariance matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with covariance matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void smp_covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); -void smp_covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); - - -/************************************************************************* -Pearson product-moment cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); -void smp_pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); - - -/************************************************************************* -Spearman's rank cross-correlation matrix - -SMP EDITION OF ALGLIB: - - ! This function can utilize multicore capabilities of your system. In - ! order to do this you have to call version with "smp_" prefix, which - ! indicates that multicore code will be used. - ! - ! This note is given for users of SMP edition; if you use GPL edition, - ! or commercial edition of ALGLIB without SMP support, you still will - ! be able to call smp-version of this function, but all computations - ! will be done serially. - ! - ! We recommend you to carefully read ALGLIB Reference Manual, section - ! called 'SMP support', before using parallel version of this function. - ! - ! You should remember that starting/stopping worker thread always have - ! non-zero cost. Although multicore version is pretty efficient on - ! large problems, we do not recommend you to use it on small problems - - ! with correlation matrices smaller than 128*128. - -INPUT PARAMETERS: - X - array[N,M1], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - Y - array[N,M2], sample matrix: - * J-th column corresponds to J-th variable - * I-th row corresponds to I-th observation - N - N>=0, number of observations: - * if given, only leading N rows of X/Y are used - * if not given, automatically determined from input sizes - M1 - M1>0, number of variables in X: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - M2 - M2>0, number of variables in Y: - * if given, only leading M1 columns of X are used - * if not given, automatically determined from input size - -OUTPUT PARAMETERS: - C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) - - -- ALGLIB -- - Copyright 28.10.2010 by Bochkanov Sergey -*************************************************************************/ -void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c); -void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); -void smp_spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c); - - -/************************************************************************* - -*************************************************************************/ -void rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); -void smp_rankdata(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); -void rankdata(real_2d_array &xy); -void smp_rankdata(real_2d_array &xy); - - -/************************************************************************* - -*************************************************************************/ -void rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); -void smp_rankdatacentered(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures); -void rankdatacentered(real_2d_array &xy); -void smp_rankdatacentered(real_2d_array &xy); - - -/************************************************************************* -Obsolete function, we recommend to use PearsonCorr2(). - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); - - -/************************************************************************* -Obsolete function, we recommend to use SpearmanCorr2(). - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n); - -/************************************************************************* -Pearson's correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5 - * normality of distributions of X and Y. - -Input parameters: - R - Pearson's correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail); - - -/************************************************************************* -Spearman's rank correlation coefficient significance test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions having zero correlation or whether their -correlation is non-zero. - -The following tests are performed: - * two-tailed test (null hypothesis - X and Y have zero correlation) - * left-tailed test (null hypothesis - the correlation coefficient is - greater than or equal to 0) - * right-tailed test (null hypothesis - the correlation coefficient is - less than or equal to 0). - -Requirements: - * the number of elements in each sample is not less than 5. - -The test is non-parametric and doesn't require distributions X and Y to be -normal. - -Input parameters: - R - Spearman's rank correlation coefficient for X and Y - N - number of elements in samples, N>=5. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail); - -/************************************************************************* -Jarque-Bera test - -This test checks hypotheses about the fact that a given sample X is a -sample of normal random variable. - -Requirements: - * the number of elements in the sample is not less than 5. - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -Accuracy of the approximation used (5<=N<=1951): - -p-value relative error (5<=N<=1951) -[1, 0.1] < 1% -[0.1, 0.01] < 2% -[0.01, 0.001] < 6% -[0.001, 0] wasn't measured - -For N>1951 accuracy wasn't measured but it shouldn't be sharply different -from table values. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p); - -/************************************************************************* -Mann-Whitney U-test - -This test checks hypotheses about whether X and Y are samples of two -continuous distributions of the same shape and same median or whether -their medians are different. - -The following tests are performed: - * two-tailed test (null hypothesis - the medians are equal) - * left-tailed test (null hypothesis - the median of the first sample - is greater than or equal to the median of the second sample) - * right-tailed test (null hypothesis - the median of the first sample - is less than or equal to the median of the second sample). - -Requirements: - * the samples are independent - * X and Y are continuous distributions (or discrete distributions well- - approximating continuous distributions) - * distributions of X and Y have the same shape. The only possible - difference is their position (i.e. the value of the median) - * the number of elements in each sample is not less than 5 - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distributions to be normal. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. N>=5 - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. M>=5 - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with satisfactory accuracy in interval [0.0001, 1]. -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - -Relative precision of approximation of p-value: - -N M Max.err. Rms.err. -5..10 N..10 1.4e-02 6.0e-04 -5..10 N..100 2.2e-02 5.3e-06 -10..15 N..15 1.0e-02 3.2e-04 -10..15 N..100 1.0e-02 2.2e-05 -15..100 N..100 6.1e-03 2.7e-06 - -For N,M>100 accuracy checks weren't put into practice, but taking into -account characteristics of asymptotic approximation used, precision should -not be sharply different from the values for interval [5, 100]. - - -- ALGLIB -- - Copyright 09.04.2007 by Bochkanov Sergey -*************************************************************************/ -void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); - -/************************************************************************* -Sign test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -While calculating p-values high-precision binomial distribution -approximation is used, so significance levels have about 15 exact digits. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail); - -/************************************************************************* -One-sample t-test - -This test checks three hypotheses about the mean of the given sample. The -following tests are performed: - * two-tailed test (null hypothesis - the mean is equal to the given - value) - * left-tailed test (null hypothesis - the mean is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the mean is less than or equal - to the given value). - -The test is based on the assumption that a given sample has a normal -distribution and an unknown dispersion. If the distribution sharply -differs from normal, the test will work incorrectly. - -INPUT PARAMETERS: - X - sample. Array whose index goes from 0 to N-1. - N - size of sample, N>=0 - Mean - assumed value of the mean. - -OUTPUT PARAMETERS: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0, all p-values are set to 1.0 - * when variance of X[] is exactly zero, p-values are set - to 1.0 or 0.0, depending on difference between sample mean and - value of mean being tested. - - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail); - - -/************************************************************************* -Two-sample pooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * dispersions are equal - * samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has exactly zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); - - -/************************************************************************* -Two-sample unpooled test - -This test checks three hypotheses about the mean of the given samples. The -following tests are performed: - * two-tailed test (null hypothesis - the means are equal) - * left-tailed test (null hypothesis - the mean of the first sample is - greater than or equal to the mean of the second sample) - * right-tailed test (null hypothesis - the mean of the first sample is - less than or equal to the mean of the second sample). - -Test is based on the following assumptions: - * given samples have normal distributions - * samples are independent. -Equality of variances is NOT required. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Y - sample 2. Array whose index goes from 0 to M-1. - M - size of the sample. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -NOTE: this function correctly handles degenerate cases: - * when N=0 or M=0, all p-values are set to 1.0 - * when both samples has zero variance, p-values are set - to 1.0 or 0.0, depending on difference between means. - * when only one sample has zero variance, test reduces to 1-sample - version. - - -- ALGLIB -- - Copyright 18.09.2006 by Bochkanov Sergey -*************************************************************************/ -void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); - -/************************************************************************* -Two-sample F-test - -This test checks three hypotheses about dispersions of the given samples. -The following tests are performed: - * two-tailed test (null hypothesis - the dispersions are equal) - * left-tailed test (null hypothesis - the dispersion of the first - sample is greater than or equal to the dispersion of the second - sample). - * right-tailed test (null hypothesis - the dispersion of the first - sample is less than or equal to the dispersion of the second sample) - -The test is based on the following assumptions: - * the given samples have normal distributions - * the samples are independent. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - sample size. - Y - sample 2. Array whose index goes from 0 to M-1. - M - sample size. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail); - - -/************************************************************************* -One-sample chi-square test - -This test checks three hypotheses about the dispersion of the given sample -The following tests are performed: - * two-tailed test (null hypothesis - the dispersion equals the given - number) - * left-tailed test (null hypothesis - the dispersion is greater than - or equal to the given number) - * right-tailed test (null hypothesis - dispersion is less than or - equal to the given number). - -Test is based on the following assumptions: - * the given sample has a normal distribution. - -Input parameters: - X - sample 1. Array whose index goes from 0 to N-1. - N - size of the sample. - Variance - dispersion value to compare with. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - - -- ALGLIB -- - Copyright 19.09.2006 by Bochkanov Sergey -*************************************************************************/ -void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail); - -/************************************************************************* -Wilcoxon signed-rank test - -This test checks three hypotheses about the median of the given sample. -The following tests are performed: - * two-tailed test (null hypothesis - the median is equal to the given - value) - * left-tailed test (null hypothesis - the median is greater than or - equal to the given value) - * right-tailed test (null hypothesis - the median is less than or - equal to the given value) - -Requirements: - * the scale of measurement should be ordinal, interval or ratio (i.e. - the test could not be applied to nominal variables). - * the distribution should be continuous and symmetric relative to its - median. - * number of distinct values in the X array should be greater than 4 - -The test is non-parametric and doesn't require distribution X to be normal - -Input parameters: - X - sample. Array whose index goes from 0 to N-1. - N - size of the sample. - Median - assumed median value. - -Output parameters: - BothTails - p-value for two-tailed test. - If BothTails is less than the given significance level - the null hypothesis is rejected. - LeftTail - p-value for left-tailed test. - If LeftTail is less than the given significance level, - the null hypothesis is rejected. - RightTail - p-value for right-tailed test. - If RightTail is less than the given significance level - the null hypothesis is rejected. - -To calculate p-values, special approximation is used. This method lets us -calculate p-values with two decimal places in interval [0.0001, 1]. - -"Two decimal places" does not sound very impressive, but in practice the -relative error of less than 1% is enough to make a decision. - -There is no approximation outside the [0.0001, 1] interval. Therefore, if -the significance level outlies this interval, the test returns 0.0001. - - -- ALGLIB -- - Copyright 08.09.2006 by Bochkanov Sergey -*************************************************************************/ -void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail); -} - -///////////////////////////////////////////////////////////////////////// -// -// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) -// -///////////////////////////////////////////////////////////////////////// -namespace alglib_impl -{ -void samplemoments(/* Real */ ae_vector* x, - ae_int_t n, - double* mean, - double* variance, - double* skewness, - double* kurtosis, - ae_state *_state); -double samplemean(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -double samplevariance(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -double sampleskewness(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -double samplekurtosis(/* Real */ ae_vector* x, - ae_int_t n, - ae_state *_state); -void sampleadev(/* Real */ ae_vector* x, - ae_int_t n, - double* adev, - ae_state *_state); -void samplemedian(/* Real */ ae_vector* x, - ae_int_t n, - double* median, - ae_state *_state); -void samplepercentile(/* Real */ ae_vector* x, - ae_int_t n, - double p, - double* v, - ae_state *_state); -double cov2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -double pearsoncorr2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -double spearmancorr2(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -void covm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_covm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state); -void pearsoncorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_pearsoncorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state); -void spearmancorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_spearmancorrm(/* Real */ ae_matrix* x, - ae_int_t n, - ae_int_t m, - /* Real */ ae_matrix* c, ae_state *_state); -void covm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_covm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state); -void pearsoncorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_pearsoncorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state); -void spearmancorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, - ae_state *_state); -void _pexec_spearmancorrm2(/* Real */ ae_matrix* x, - /* Real */ ae_matrix* y, - ae_int_t n, - ae_int_t m1, - ae_int_t m2, - /* Real */ ae_matrix* c, ae_state *_state); -void rankdata(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_state *_state); -void _pexec_rankdata(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, ae_state *_state); -void rankdatacentered(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, - ae_state *_state); -void _pexec_rankdatacentered(/* Real */ ae_matrix* xy, - ae_int_t npoints, - ae_int_t nfeatures, ae_state *_state); -double pearsoncorrelation(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -double spearmanrankcorrelation(/* Real */ ae_vector* x, - /* Real */ ae_vector* y, - ae_int_t n, - ae_state *_state); -void pearsoncorrelationsignificance(double r, - ae_int_t n, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void spearmanrankcorrelationsignificance(double r, - ae_int_t n, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void jarqueberatest(/* Real */ ae_vector* x, - ae_int_t n, - double* p, - ae_state *_state); -void mannwhitneyutest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void onesamplesigntest(/* Real */ ae_vector* x, - ae_int_t n, - double median, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void studentttest1(/* Real */ ae_vector* x, - ae_int_t n, - double mean, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void studentttest2(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void unequalvariancettest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void ftest(/* Real */ ae_vector* x, - ae_int_t n, - /* Real */ ae_vector* y, - ae_int_t m, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void onesamplevariancetest(/* Real */ ae_vector* x, - ae_int_t n, - double variance, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); -void wilcoxonsignedranktest(/* Real */ ae_vector* x, - ae_int_t n, - double e, - double* bothtails, - double* lefttail, - double* righttail, - ae_state *_state); - -} -#endif - +/************************************************************************* +ALGLIB 4.07.0 (source code generated 2025-12-29) +Copyright (c) Sergey Bochkanov (ALGLIB project). + +>>> SOURCE LICENSE >>> +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (www.fsf.org); either version 2 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available at +http://www.fsf.org/licensing/licenses +>>> END OF LICENSE >>> +*************************************************************************/ +#ifndef _statistics_pkg_h +#define _statistics_pkg_h +#include "ap.h" +#include "alglibinternal.h" +#include "linalg.h" +#include "specialfunctions.h" +#include "alglibmisc.h" +#include "fasttransforms.h" + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (DATATYPES) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) +#endif +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +typedef struct +{ + ae_int_t n; + ae_int_t x0width; + ae_int_t x0height; + ae_matrix x0m; + ae_int_t x0type; + double x0stddev; + ae_int_t algokind; + ae_int_t ladderkind; + ae_int_t proposalkind; + ae_int_t helperscnt; + double desigma; + double degamma0; + ae_vector initialladder; + double laddernu0; + double laddertau; + ae_bool noladderadaptationafterburnin; + ae_matrix gausslowerc; + ae_matrix gaussl; + ae_bool useparallelmoves; + ae_int_t epochscnt; + ae_int_t popwidth; + ae_int_t popheight; + ae_int_t burninlen; + ae_int_t thinby; + ae_bool reportalllevels; + ae_int_t rngseed; + ae_vector s; + ae_bool initialstart; + ae_bool xrep; + ae_matrix population2d; + ae_vector currentladder; + hqrndstate globalrs; + ae_bool reseedglobalrs; + ae_vector propidx; + ae_vector propz; + ae_vector propt; + ae_matrix propxf; + ae_vector grpabidx; + ae_int_t grpasize; + ae_vector grpdsidx; + ae_bool haslastpopulation; + ae_matrix lastpopulation2d; + ae_vector lastgrpabidx; + ae_int_t lastpopulationwidth; + ae_int_t lastpopulationheight; + ae_bool userterminationneeded; + ae_int_t protocolversion; + ae_bool issuesparserequests; + ae_int_t requesttype; + ae_vector reportx; + double reportf; + ae_int_t querysize; + ae_int_t queryfuncs; + ae_int_t queryvars; + ae_int_t querydim; + ae_int_t queryformulasize; + ae_vector querydata; + ae_vector replyfi; + ae_vector replydj; + sparsematrix replysj; + ae_vector tmpx1; + ae_vector tmpc1; + ae_vector tmpf1; + ae_vector tmpg1; + ae_matrix tmpj1; + sparsematrix tmps1; + ae_int_t repnfev; + ae_int_t repaccept1cnt; + ae_int_t repaccepthcnt; + ae_int_t repepochscnt; + ae_int_t reppopwidth; + ae_int_t reppopheight; + ae_int_t repswapacceptcnt; + ae_int_t repswapattemptcnt; + ae_vector repavgswaprates; + ae_matrix repsample; + ae_int_t repsamplesize; + ae_bool dotrace; + ae_bool dodetailedtrace; + ae_bool dotimers; + stimer timertotal; + stimer timercallback; + stimer timerreport; + ae_vector tmp0; + ae_vector tmp1; + ae_vector tmp2; + ae_vector tmpi0; + ae_vector gphelperidx; + ae_vector gpmeanhelper; + ae_vector gpproposal; + ae_vector gpdelta; + ae_vector gptmp0; + ae_vector saacceptrates; + ae_vector savecsi; + ae_vector saproposedladder; + rcommstate rstate; +} mcmcstate; +typedef struct +{ + ae_int_t nfev; + double acceptrate; + double swapacceptrate; + ae_vector autocorrtimes; +} mcmcreport; +#endif +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) +#endif + +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS C++ INTERFACE +// +///////////////////////////////////////////////////////////////////////// +namespace alglib +{ + +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +class _mcmcstate_owner; +class mcmcstate; +class _mcmcreport_owner; +class mcmcreport; + + +/************************************************************************* +This object stores MCMC sampler. + +You should use functions provided by the MCMC subpackage to work with this +object. +*************************************************************************/ +class _mcmcstate_owner +{ +public: + _mcmcstate_owner(); + _mcmcstate_owner(alglib_impl::mcmcstate *attach_to); + _mcmcstate_owner(const _mcmcstate_owner &rhs); + _mcmcstate_owner& operator=(const _mcmcstate_owner &rhs); + virtual ~_mcmcstate_owner(); + alglib_impl::mcmcstate* c_ptr(); + const alglib_impl::mcmcstate* c_ptr() const; +protected: + alglib_impl::mcmcstate *p_struct; + bool is_attached; +}; +class mcmcstate : public _mcmcstate_owner +{ +public: + mcmcstate(); + mcmcstate(alglib_impl::mcmcstate *attach_to); + mcmcstate(const mcmcstate &rhs); + mcmcstate& operator=(const mcmcstate &rhs); + virtual ~mcmcstate(); + + +}; + + +/************************************************************************* +These fields store MCMC report: +* nfev number of function evaluations +* acceptrate acceptance rate of a MCMC algo; when parallel + tempering is used, this field stores acceptance + rate for the lowest level (T=1). +* swapacceptrate acceptance rate for swaps between levels of the + temperature ladder. When no parallel tempering + is used, stores zero. +* autocorrtimes array[N], per-variable autocorrelation times +*************************************************************************/ +class _mcmcreport_owner +{ +public: + _mcmcreport_owner(); + _mcmcreport_owner(alglib_impl::mcmcreport *attach_to); + _mcmcreport_owner(const _mcmcreport_owner &rhs); + _mcmcreport_owner& operator=(const _mcmcreport_owner &rhs); + virtual ~_mcmcreport_owner(); + alglib_impl::mcmcreport* c_ptr(); + const alglib_impl::mcmcreport* c_ptr() const; +protected: + alglib_impl::mcmcreport *p_struct; + bool is_attached; +}; +class mcmcreport : public _mcmcreport_owner +{ +public: + mcmcreport(); + mcmcreport(alglib_impl::mcmcreport *attach_to); + mcmcreport(const mcmcreport &rhs); + mcmcreport& operator=(const mcmcreport &rhs); + virtual ~mcmcreport(); + ae_int_t &nfev; + double &acceptrate; + double &swapacceptrate; + real_1d_array autocorrtimes; + + +}; +#endif + +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) + +#endif + +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Calculation of the distribution moments: mean, variance, skewness, kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +OUTPUT PARAMETERS + Mean - mean. + Variance- variance. + Skewness- skewness (if variance<>0; zero otherwise). + Kurtosis- kurtosis (if variance<>0; zero otherwise). + +NOTE: variance is calculated by dividing sum of squares by N-1, not N. + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemoments(const real_1d_array &x, const ae_int_t n, double &mean, double &variance, double &skewness, double &kurtosis, const xparams _xparams = alglib::xdefault); +void samplemoments(const real_1d_array &x, double &mean, double &variance, double &skewness, double &kurtosis, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the mean. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Mean' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplemean(const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double samplemean(const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the variance. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Variance' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplevariance(const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double samplevariance(const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the skewness. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Skewness' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double sampleskewness(const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double sampleskewness(const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Calculation of the kurtosis. + +INPUT PARAMETERS: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +NOTE: + +This function return result which calculated by 'SampleMoments' function +and stored at 'Kurtosis' variable. + + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +double samplekurtosis(const real_1d_array &x, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double samplekurtosis(const real_1d_array &x, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +ADev + +Input parameters: + X - sample + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + ADev- ADev + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void sampleadev(const real_1d_array &x, const ae_int_t n, double &adev, const xparams _xparams = alglib::xdefault); +void sampleadev(const real_1d_array &x, double &adev, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Median calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + +Output parameters: + Median + + -- ALGLIB -- + Copyright 06.09.2006 by Bochkanov Sergey +*************************************************************************/ +void samplemedian(const real_1d_array &x, const ae_int_t n, double &median, const xparams _xparams = alglib::xdefault); +void samplemedian(const real_1d_array &x, double &median, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Percentile calculation. + +Input parameters: + X - sample (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only leading N elements of X are processed + * if not given, automatically determined from size of X + P - percentile (0<=P<=1) + +Output parameters: + V - percentile + + -- ALGLIB -- + Copyright 01.03.2008 by Bochkanov Sergey +*************************************************************************/ +void samplepercentile(const real_1d_array &x, const ae_int_t n, const double p, double &v, const xparams _xparams = alglib::xdefault); +void samplepercentile(const real_1d_array &x, const double p, double &v, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +2-sample covariance + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + covariance (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double cov2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double cov2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Pearson product-moment correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Pearson product-moment correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double pearsoncorr2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Spearman's rank correlation coefficient + +Input parameters: + X - sample 1 (array indexes: [0..N-1]) + Y - sample 2 (array indexes: [0..N-1]) + N - N>=0, sample size: + * if given, only N leading elements of X/Y are processed + * if not given, automatically determined from input sizes + +Result: + Spearman's rank correlation coefficient + (zero for N=0 or N=1) + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams = alglib::xdefault); +double spearmancorr2(const real_1d_array &x, const real_1d_array &y, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void covm(const real_2d_array &x, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Pearson product-moment correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void pearsoncorrm(const real_2d_array &x, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Spearman's rank correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X are used + * if not given, automatically determined from input size + M - M>0, number of variables: + * if given, only leading M columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M,M], correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm(const real_2d_array &x, const ae_int_t n, const ae_int_t m, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void spearmancorrm(const real_2d_array &x, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Cross-covariance matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-covariance matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void covm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void covm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Pearson product-moment cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void pearsoncorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Spearman's rank cross-correlation matrix + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! * hardware vendor (Intel, ARM) implementations of linear algebra and + ! other primitives (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + X - array[N,M1], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + Y - array[N,M2], sample matrix: + * J-th column corresponds to J-th variable + * I-th row corresponds to I-th observation + N - N>=0, number of observations: + * if given, only leading N rows of X/Y are used + * if not given, automatically determined from input sizes + M1 - M1>0, number of variables in X: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + M2 - M2>0, number of variables in Y: + * if given, only leading M1 columns of X are used + * if not given, automatically determined from input size + +OUTPUT PARAMETERS: + C - array[M1,M2], cross-correlation matrix (zero if N=0 or N=1) + + -- ALGLIB -- + Copyright 28.10.2010 by Bochkanov Sergey +*************************************************************************/ +void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, const ae_int_t n, const ae_int_t m1, const ae_int_t m2, real_2d_array &c, const xparams _xparams = alglib::xdefault); +void spearmancorrm2(const real_2d_array &x, const real_2d_array &y, real_2d_array &c, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function replaces data in XY by their ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* ranking starts from 0, ends at NFeatures-1 +* sum of within-row values is equal to (NFeatures-1)*NFeatures/2 + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +void rankdata(real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const xparams _xparams = alglib::xdefault); +void rankdata(real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function replaces data in XY by their CENTERED ranks: +* XY is processed row-by-row +* rows are processed separately +* tied data are correctly handled (tied ranks are calculated) +* centered ranks are just usual ranks, but centered in such way that sum + of within-row values is equal to 0.0. +* centering is performed by subtracting mean from each row, i.e it changes + mean value, but does NOT change higher moments + + ! COMMERCIAL EDITION OF ALGLIB: + ! + ! Commercial Edition of ALGLIB includes following important improvements + ! of this function: + ! * high-performance native backend with same C# interface (C# version) + ! * multithreading support (C++ and C# versions) + ! + ! We recommend you to read 'Working with commercial version' section of + ! ALGLIB Reference Manual in order to find out how to use performance- + ! related features provided by commercial edition of ALGLIB. + +INPUT PARAMETERS: + XY - array[NPoints,NFeatures], dataset + NPoints - number of points + NFeatures- number of features + +OUTPUT PARAMETERS: + XY - data are replaced by their within-row ranks; + ranking starts from 0, ends at NFeatures-1 + + -- ALGLIB -- + Copyright 18.04.2013 by Bochkanov Sergey +*************************************************************************/ +void rankdatacentered(real_2d_array &xy, const ae_int_t npoints, const ae_int_t nfeatures, const xparams _xparams = alglib::xdefault); +void rankdatacentered(real_2d_array &xy, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete function, we recommend to use PearsonCorr2(). + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double pearsoncorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Obsolete function, we recommend to use SpearmanCorr2(). + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +double spearmanrankcorrelation(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Pearson's correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5 + * normality of distributions of X and Y. + +Input parameters: + R - Pearson's correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void pearsoncorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Spearman's rank correlation coefficient significance test + +This test checks hypotheses about whether X and Y are samples of two +continuous distributions having zero correlation or whether their +correlation is non-zero. + +The following tests are performed: + * two-tailed test (null hypothesis - X and Y have zero correlation) + * left-tailed test (null hypothesis - the correlation coefficient is + greater than or equal to 0) + * right-tailed test (null hypothesis - the correlation coefficient is + less than or equal to 0). + +Requirements: + * the number of elements in each sample is not less than 5. + +The test is non-parametric and doesn't require distributions X and Y to be +normal. + +Input parameters: + R - Spearman's rank correlation coefficient for X and Y + N - number of elements in samples, N>=5. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void spearmanrankcorrelationsignificance(const double r, const ae_int_t n, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Jarque-Bera test + +This test checks hypotheses about the fact that a given sample X is a +sample of normal random variable. + +Requirements: + * the number of elements in the sample is not less than 5. + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. N>=5 + +Output parameters: + P - p-value for the test + +Accuracy of the approximation used (5<=N<=1951): + +p-value relative error (5<=N<=1951) +[1, 0.1] < 1% +[0.1, 0.01] < 2% +[0.01, 0.001] < 6% +[0.001, 0] wasn't measured + +For N>1951 accuracy wasn't measured but it shouldn't be sharply different +from table values. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void jarqueberatest(const real_1d_array &x, const ae_int_t n, double &p, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Two-sample F-test + +This test checks three hypotheses about dispersions of the given samples. +The following tests are performed: + * two-tailed test (null hypothesis - the dispersions are equal) + * left-tailed test (null hypothesis - the dispersion of the first + sample is greater than or equal to the dispersion of the second + sample). + * right-tailed test (null hypothesis - the dispersion of the first + sample is less than or equal to the dispersion of the second sample) + +The test is based on the following assumptions: + * the given samples have normal distributions + * the samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - sample size. + Y - sample 2. Array whose index goes from 0 to M-1. + M - sample size. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void ftest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +One-sample chi-square test + +This test checks three hypotheses about the dispersion of the given sample +The following tests are performed: + * two-tailed test (null hypothesis - the dispersion equals the given + number) + * left-tailed test (null hypothesis - the dispersion is greater than + or equal to the given number) + * right-tailed test (null hypothesis - dispersion is less than or + equal to the given number). + +Test is based on the following assumptions: + * the given sample has a normal distribution. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Variance - dispersion value to compare with. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + + -- ALGLIB -- + Copyright 19.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplevariancetest(const real_1d_array &x, const ae_int_t n, const double variance, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Wilcoxon signed-rank test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + * the distribution should be continuous and symmetric relative to its + median. + * number of distinct values in the X array should be greater than 4 + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with two decimal places in interval [0.0001, 1]. + +"Two decimal places" does not sound very impressive, but in practice the +relative error of less than 1% is enough to make a decision. + +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void wilcoxonsignedranktest(const real_1d_array &x, const ae_int_t n, const double e, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +One-sample t-test + +This test checks three hypotheses about the mean of the given sample. The +following tests are performed: + * two-tailed test (null hypothesis - the mean is equal to the given + value) + * left-tailed test (null hypothesis - the mean is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the mean is less than or equal + to the given value). + +The test is based on the assumption that a given sample has a normal +distribution and an unknown dispersion. If the distribution sharply +differs from normal, the test will work incorrectly. + +INPUT PARAMETERS: + X - sample. Array whose index goes from 0 to N-1. + N - size of sample, N>=0 + Mean - assumed value of the mean. + +OUTPUT PARAMETERS: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0, all p-values are set to 1.0 + * when variance of X[] is exactly zero, p-values are set + to 1.0 or 0.0, depending on difference between sample mean and + value of mean being tested. + + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest1(const real_1d_array &x, const ae_int_t n, const double mean, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Two-sample pooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * dispersions are equal + * samples are independent. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has exactly zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void studentttest2(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Two-sample unpooled test + +This test checks three hypotheses about the mean of the given samples. The +following tests are performed: + * two-tailed test (null hypothesis - the means are equal) + * left-tailed test (null hypothesis - the mean of the first sample is + greater than or equal to the mean of the second sample) + * right-tailed test (null hypothesis - the mean of the first sample is + less than or equal to the mean of the second sample). + +Test is based on the following assumptions: + * given samples have normal distributions + * samples are independent. +Equality of variances is NOT required. + +Input parameters: + X - sample 1. Array whose index goes from 0 to N-1. + N - size of the sample. + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +NOTE: this function correctly handles degenerate cases: + * when N=0 or M=0, all p-values are set to 1.0 + * when both samples has zero variance, p-values are set + to 1.0 or 0.0, depending on difference between means. + * when only one sample has zero variance, test reduces to 1-sample + version. + + -- ALGLIB -- + Copyright 18.09.2006 by Bochkanov Sergey +*************************************************************************/ +void unequalvariancettest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +Sign test + +This test checks three hypotheses about the median of the given sample. +The following tests are performed: + * two-tailed test (null hypothesis - the median is equal to the given + value) + * left-tailed test (null hypothesis - the median is greater than or + equal to the given value) + * right-tailed test (null hypothesis - the median is less than or + equal to the given value) + +Requirements: + * the scale of measurement should be ordinal, interval or ratio (i.e. + the test could not be applied to nominal variables). + +The test is non-parametric and doesn't require distribution X to be normal + +Input parameters: + X - sample. Array whose index goes from 0 to N-1. + N - size of the sample. + Median - assumed median value. + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +While calculating p-values high-precision binomial distribution +approximation is used, so significance levels have about 15 exact digits. + + -- ALGLIB -- + Copyright 08.09.2006 by Bochkanov Sergey +*************************************************************************/ +void onesamplesigntest(const real_1d_array &x, const ae_int_t n, const double median, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif + +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +/************************************************************************* +This function initializes MCMC sampler using single initial point to seed +the population. + +The population is generated around the initial point with random Gaussian +noise being added, having per-variable magnitude equal to XStdDev or (if +MCMCSetScale() was called) equal to XStdDev*S[I]. + + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of X are used + * if not given, automatically determined from size of X + X - starting point used to seed a MCMC algo, array[N]: + * it is better to have X not too far away from the maximum + of log-likelihood + * any point will do, if no maximum location is unknown + XStdDev - standard deviation of a population generated around X: + * strictly greater than zero + * nearly zero values are likely to cause population to + stagnate, whilst too large values are likely to cause + population to spend excessive time converging + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreate1(const ae_int_t n, const real_1d_array &x, const double xstddev, mcmcstate &state, const xparams _xparams = alglib::xdefault); +void mcmccreate1(const real_1d_array &x, const double xstddev, mcmcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function initializes MCMC sampler using a population of user-specified +points. + +A specific sampling algorithm that needs an initial population will use +user-provided points. If an algorithm needs more initial points than was +specified, additional points will be randomly generated using population +as a distribution reference. + +INPUT PARAMETERS: + N - problem dimension, N>0: + * if given, only leading N elements of P are used + * if not given, automatically determined from size of P + P - initial points, array[PopSize,N] + PopSize - population size, PopSize>0: + * if given, only leading PopSize elements of P are used + * if not given, automatically determined from size of P + +OUTPUT PARAMETERS: + State - structure stores MCMC sampler state + + -- ALGLIB -- + Copyright 20.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmccreatefrompopulation(const ae_int_t n, const real_2d_array &p, const ae_int_t popsize, mcmcstate &state, const xparams _xparams = alglib::xdefault); +void mcmccreatefrompopulation(const real_2d_array &p, mcmcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets per-variable scaling coefficients for MCMC sampler. + +Present version of the MCMC sampler uses per-variable scales during initial +popilation generation: an initial point X0 is perturbed with random noise, +whose per-variable magnitude is XStdDev*S[I]. + +Future versions of the sampler may use scales for other purposes too, but +are likely to do so in a backward-compatible manner. + +INPUT PARAMETERS: + State - structure stores algorithm state + S - array[N], non-zero scaling coefficients + S[i] may be negative, sign doesn't matter. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetscale(mcmcstate &state, const real_1d_array &s, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function controls adaptation rate of the temperature ladder used by +adaptive parallel tempering algorithms. + +The sampler changes the logarithmic difference between temperatures in the +ladder ln(T[i+1]-T[i]) as a product of different between swap accept rates +A[i]-A[i+1] and current adaptation rate, which is nu0/(1+iteridx/tau). + +Here nu0 is an initial adaptation rate that similar to stochastic gradient +descent learning rate. Recommended values 0.01-0.1. And tau is a learning +rate decay time, depending on the problem it can be 100 or 1000. + +The MCMC sampler uses some default values for these parameters, but they +can change in future versions without notice. + +This function has no effect when adaptive tempering is not active. + +INPUT PARAMETERS: + State - structure stores algorithm state + Nu0 - initial learning rate, >=0. + Zero value effectively turns off adaptation. + Tau - characteristic decay time, >=0. + Zero value effectively turns off adaptation. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetladderadaptationrate(mcmcstate &state, const double nu0, const double tau, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates parallel tempering with the fixed temperature +ladder. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +INPUT PARAMETERS: + State - structure stores algorithm state + T - array[NTemp], T[0]=1, T[I+1]>T[I], sampling temperatures. + If the first element of T is different from 1, or + temperatures are not strictly increasing, an exception is + raised + NTemp - >=1, temperature ladder height + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetfixedtemperatureladder(mcmcstate &state, const real_1d_array &t, const ae_int_t ntemp, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function activates parallel tempering with the adaptive temperature +ladder using uniform Swap Acceptance Rate (SAR) proposal. + +Parallel tempering is intended for sampling of multimodal distributions, +with the T=1 corresponding to sampling of the original distribution (what +you get as result), and higher temperatures corresponding to smoothed +versions of the distribution, helping the sampler to reach otherwise +unreachable remote peaks. + +The function accepts the hottest temperature in the ladder TMax, as well +as ladder height NTemp>=1. + +You can control adaptation rate wuth mcmcsetladderadaptationrate() function. + +INPUT PARAMETERS: + State - structure stores algorithm state + TMax - initial value of the maximum temperature in the ladder, + TMax>1 (strictly) + NTemp - >=1, temperature ladder height: + * NTemp=1 means that no temperature ladder is actually used + * NTemp=2 means that we have a ladder with temperatures + [1,TMax] and no adaptation + * NTemp>2 means that we have a ladder with T[0]=1 and + T[NTemp-1]=TMax, and adaptive temperatures between them. + + -- ALGLIB -- + Copyright 15.05.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetsartemperatureladder(mcmcstate &state, const double tmax, const ae_int_t ntemp, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Same as mcmcsetalgostretch(). +*************************************************************************/ +void mcmcsetalgogoodmanweare(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses stretch move, as defined in 'Ensemble samplers with affine +invariance', Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + EpochsCnt- iterations count to be reported, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgostretch(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses walk move, as defined in 'Ensemble samplers with affine invariance', +Goodman and Weare, 2010. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + helpers, and that we can use parallel moves. + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + HelpersCnt- helpers count, >=2. Number of helpers used to generate + proposal. Recommended values: some small number like 3-5. + It is possible to specify HelpersCnt=PopSize, but for + large populations it will result in proposal generation + overhead growing as O(N*PopSize^2). + Values larger than PopSize will be silently truncated to + PopSize. + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgowalk(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const ae_int_t helperscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare ( ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move, as defined in 'RUN DMC: an efficient, parallel code for +analyzing radial velocity observations using n-body integrations and +differential evolution Markov chain Monte Carlo' by Benjamin Nelson, Eric +B. Ford, and Matthew J. Payne. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=4 + that follows from the fact that each walker needs at least two + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + For N=1 or N=2 it is possible to specify PopSize=N+1 that is less + than 4. In order to simplify the algorithm, in this case we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Sigma - non-negative, standard deviation of a Gaussian used to + randomly modify the proposal vector. Recommended values: + about 1E-5. Zero value (or omitted) means that a default + one is used. + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2N), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgode(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const double sigma, const double gamma0, const xparams _xparams = alglib::xdefault); +void mcmcsetalgode(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses DE move with snooker update, as defined in 'Differential Evolution +Markov Chain with snooker updater and fewer chains' by Cajo J.F. ter Braak +and Jasper A. Vrugt. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: for consistency with the rest of the library this move type requires + PopSize>=N+1. However, it also has a special requirement PopSize>=6 + that follows from the fact that each update needs at least three + other walkers to produce a DE proposal, and that we can use parallel + moves (that need larger ensembles). + + In order to simplify the algorithm, if N+1<=PopSize<6, we silently + override selection with the stretch move. + +NOTE: it is recommended to specify PopSize and EpochsCnt and leave other + parameters to their default values. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + + PopSize - ensemble size, PopSize>=N+1, recommended: >=2*N + + EpochsCnt- iterations count to be reported, >=1 + + Gamma0 - the mean stretch factor for the proposal vector, >=0. Zero + value means that a default value is used which is + 2.38/sqrt(2), as recommended by the original paper. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgodesnooker(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const double gamma0, const xparams _xparams = alglib::xdefault); +void mcmcsetalgodesnooker(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets MCMC algorithm to Goodman-Weare (ensemble MCMC) with +the specified ensemble size and number of iterations being reported. + +Uses Gaussian random walk, an ensemble of PopSize completely independent +walkers. + +NOTE: the sampler always reports PopSize*EpochsCnt samples which corresponds + to EpochsCnt iterations being reported. + + By default, it performs exactly the same number of iterations as it + reports. However, it will perform more iterations than it reports if + using a burn-in phase (discards initial samples that are too + influenced by the initial state) and by specifying a thinning factor + greater than 1 (helps to combat autocorrelations). + +NOTE: this move is special because it can work with any ensemble size, + including PopSize=1 (most other moves need at least 4, 5 or 6 + walkers in the ensemble). Other moves will throw an exception if + called with PopSize=1. + + EpochsCnt- iterations count to be reported, >=1 + + C - array[N,N], a positive definite covariance matrix. Walker + position is perturbed with Gaussian perturbation with + covariance C. + + IsUpper - if IsUpper=True, only upper triangle of C is used (the + lower one is ignored). Otherwise, only lower triangle is + used. + + + -- ALGLIB -- + Copyright 20.11.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetalgogaussian(mcmcstate &state, const ae_int_t popsize, const ae_int_t epochscnt, const real_2d_array &c, const bool isupper, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets number of additional initial iterations (in addition to +EpochsCnt) that will be performed and discarded (not stored into the +report sample), so called 'burn-in length'. + +In total, BurnInLen+EpochsCnt iterations will be performed, with initial +BurnInLen ones being used solely to help MCMC spread walkers according to +the density of the function being sampled. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + BurnInLen - burn-in length, >=0 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetburninlength(mcmcstate &state, const ae_int_t burninlen, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets thinning factor: ThinBy*EpochsCnt iterations will be +performed (after the optional burn-in phase), with every ThinBy-th +iteration being saved and the rest being discarded. + +This option helps to avoid storing highly correlated samples. + +INPUT PARAMETERS: + State - structure that stores MCMC sampler state + ThinBy - thinning factor, >=1 + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetthinningfactor(mcmcstate &state, const ae_int_t thinby, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function sets the seed which is used to initialize internal RNG. By +default, a deterministic seed is used - same for each run of the sampler. +It means that the same sampling decisions are taken every time. + +If you specify a non-deterministic seed value, then the sampler may return +slightly different results after each run. + +INPUT PARAMETERS: + S - sampler state + Seed - seed: + * positive values = use deterministic seed for each run of + algorithms which depend on random initialization + * zero or negative values = use non-deterministic seed + + -- ALGLIB -- + Copyright 08.06.2017 by Bochkanov Sergey +*************************************************************************/ +void mcmcsetseed(mcmcstate &s, const ae_int_t seed, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +This function provides reverse communication interface +Reverse communication interface is not documented or recommended to use. +See below for functions which provide better documented API +*************************************************************************/ +bool mcmciteration(mcmcstate &state, const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +These functions accept following parameters: + state - algorithm state + func - callback which calculates function (or merit function) + value func at given point x + rep - optional callback which is called after each iteration + can be NULL + ptr - optional pointer which is passed to func/grad/hess/jac/rep + can be NULL + + + -- ALGLIB -- + Copyright 20.01.2025 by Bochkanov Sergey + + +*************************************************************************/ +void mcmcrun(mcmcstate &state, + void (*func)(const real_1d_array &x, double &func, void *ptr), + void (*rep)(const real_1d_array &x, double func, void *ptr) = NULL, + void *ptr = NULL, + const xparams _xparams = alglib::xdefault); + + +/************************************************************************* +Extract MCMC sampler results from the sampler. This function has significant +overhead coming from two sources: +* overhead of copying PopSize*EpochsCnt*N-sized array from internal memory +* overhead of computing per-variable integrated autocorrelating time + +INPUT PARAMETERS: + State - MCMC sampler, either after return from mcmcrun() + or still running (in the latter case, this + function can be safely called only from the rep() + callback). + +OUTPUT PARAMETERS: + Sample - array[SampleSize,N+1], current sample: + * first N columns store variable values, the last + one stores log-likelihood value as computed by + the callback + * first PopSize rows store population snapshot + after the iteration #0, subsequent PopSize rows + correspond to iteration #1 and so on. + * each snapshot (a set of PopSize rows) stores + positions of PopSize walkers, each walker having + the same position in each of SampleSize snapshots. + Thus, walker #I at the iteration #J is stored + at the row PopSize*J+I. + + SampleSize - current sample size: + * for a sampler that stopped it is equal to PopSize*EpochsCnt + * for a sampler that is still running, we have + 0<=SampleSize=5 + Y - sample 2. Array whose index goes from 0 to M-1. + M - size of the sample. M>=5 + +Output parameters: + BothTails - p-value for two-tailed test. + If BothTails is less than the given significance level + the null hypothesis is rejected. + LeftTail - p-value for left-tailed test. + If LeftTail is less than the given significance level, + the null hypothesis is rejected. + RightTail - p-value for right-tailed test. + If RightTail is less than the given significance level + the null hypothesis is rejected. + +To calculate p-values, special approximation is used. This method lets us +calculate p-values with satisfactory accuracy in interval [0.0001, 1]. +There is no approximation outside the [0.0001, 1] interval. Therefore, if +the significance level outlies this interval, the test returns 0.0001. + +Relative precision of approximation of p-value: + +N M Max.err. Rms.err. +5..10 N..10 1.4e-02 6.0e-04 +5..10 N..100 2.2e-02 5.3e-06 +10..15 N..15 1.0e-02 3.2e-04 +10..15 N..100 1.0e-02 2.2e-05 +15..100 N..100 6.1e-03 2.7e-06 + +For N,M>100 accuracy checks weren't put into practice, but taking into +account characteristics of asymptotic approximation used, precision should +not be sharply different from the values for interval [5, 100]. + +NOTE: P-value approximation was optimized for 0.0001<=p<=0.2500. Thus, + P's outside of this interval are enforced to these bounds. Say, you + may quite often get P equal to exactly 0.25 or 0.0001. + + -- ALGLIB -- + Copyright 09.04.2007 by Bochkanov Sergey +*************************************************************************/ +void mannwhitneyutest(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, double &bothtails, double &lefttail, double &righttail, const xparams _xparams = alglib::xdefault); +#endif +} + +///////////////////////////////////////////////////////////////////////// +// +// THIS SECTION CONTAINS COMPUTATIONAL CORE DECLARATIONS (FUNCTIONS) +// +///////////////////////////////////////////////////////////////////////// +namespace alglib_impl +{ +#if defined(AE_COMPILE_BASESTAT) || !defined(AE_PARTIAL_BUILD) +void samplemoments(/* Real */ const ae_vector* x, + ae_int_t n, + double* mean, + double* variance, + double* skewness, + double* kurtosis, + ae_state *_state); +double samplemean(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +double samplevariance(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +double sampleskewness(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +double samplekurtosis(/* Real */ const ae_vector* x, + ae_int_t n, + ae_state *_state); +void sampleadev(/* Real */ const ae_vector* x, + ae_int_t n, + double* adev, + ae_state *_state); +void samplemedian(/* Real */ const ae_vector* _x, + ae_int_t n, + double* median, + ae_state *_state); +void samplepercentile(/* Real */ const ae_vector* _x, + ae_int_t n, + double p, + double* v, + ae_state *_state); +double cov2(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); +double pearsoncorr2(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); +double spearmancorr2(/* Real */ const ae_vector* _x, + /* Real */ const ae_vector* _y, + ae_int_t n, + ae_state *_state); +void covm(/* Real */ const ae_matrix* _x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state); +void pearsoncorrm(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state); +void spearmancorrm(/* Real */ const ae_matrix* x, + ae_int_t n, + ae_int_t m, + /* Real */ ae_matrix* c, + ae_state *_state); +void covm2(/* Real */ const ae_matrix* _x, + /* Real */ const ae_matrix* _y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state); +void pearsoncorrm2(/* Real */ const ae_matrix* _x, + /* Real */ const ae_matrix* _y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state); +void spearmancorrm2(/* Real */ const ae_matrix* x, + /* Real */ const ae_matrix* y, + ae_int_t n, + ae_int_t m1, + ae_int_t m2, + /* Real */ ae_matrix* c, + ae_state *_state); +void rankdata(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_state *_state); +ae_bool _trypexec_rankdata(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, ae_state *_state); +void rankdatacentered(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, + ae_state *_state); +ae_bool _trypexec_rankdatacentered(/* Real */ ae_matrix* xy, + ae_int_t npoints, + ae_int_t nfeatures, ae_state *_state); +double pearsoncorrelation(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); +double spearmanrankcorrelation(/* Real */ const ae_vector* x, + /* Real */ const ae_vector* y, + ae_int_t n, + ae_state *_state); +#endif +#if defined(AE_COMPILE_CORRELATIONTESTS) || !defined(AE_PARTIAL_BUILD) +void pearsoncorrelationsignificance(double r, + ae_int_t n, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +void spearmanrankcorrelationsignificance(double r, + ae_int_t n, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif +#if defined(AE_COMPILE_JARQUEBERA) || !defined(AE_PARTIAL_BUILD) +void jarqueberatest(/* Real */ const ae_vector* x, + ae_int_t n, + double* p, + ae_state *_state); +#endif +#if defined(AE_COMPILE_VARIANCETESTS) || !defined(AE_PARTIAL_BUILD) +void ftest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +void onesamplevariancetest(/* Real */ const ae_vector* x, + ae_int_t n, + double variance, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif +#if defined(AE_COMPILE_WSR) || !defined(AE_PARTIAL_BUILD) +void wilcoxonsignedranktest(/* Real */ const ae_vector* _x, + ae_int_t n, + double e, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif +#if defined(AE_COMPILE_STUDENTTTESTS) || !defined(AE_PARTIAL_BUILD) +void studentttest1(/* Real */ const ae_vector* x, + ae_int_t n, + double mean, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +void studentttest2(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +void unequalvariancettest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif +#if defined(AE_COMPILE_STEST) || !defined(AE_PARTIAL_BUILD) +void onesamplesigntest(/* Real */ const ae_vector* x, + ae_int_t n, + double median, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif +#if defined(AE_COMPILE_MCMC) || !defined(AE_PARTIAL_BUILD) +void mcmccreate1(ae_int_t n, + /* Real */ const ae_vector* x, + double xstddev, + mcmcstate* state, + ae_state *_state); +void mcmccreatefrompopulation(ae_int_t n, + /* Real */ const ae_matrix* p, + ae_int_t popsize, + mcmcstate* state, + ae_state *_state); +void mcmcsetscale(mcmcstate* state, + /* Real */ const ae_vector* s, + ae_state *_state); +void mcmcsetladderadaptationrate(mcmcstate* state, + double nu0, + double tau, + ae_state *_state); +void mcmcsetfixedtemperatureladder(mcmcstate* state, + /* Real */ const ae_vector* t, + ae_int_t ntemp, + ae_state *_state); +void mcmcsetsartemperatureladder(mcmcstate* state, + double tmax, + ae_int_t ntemp, + ae_state *_state); +void mcmcsetalgogoodmanweare(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_state *_state); +void mcmcsetalgostretch(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_state *_state); +void mcmcsetalgowalk(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + ae_int_t helperscnt, + ae_state *_state); +void mcmcsetalgode(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + double sigma, + double gamma0, + ae_state *_state); +void mcmcsetalgodesnooker(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + double gamma0, + ae_state *_state); +void mcmcsetalgogaussian(mcmcstate* state, + ae_int_t popsize, + ae_int_t epochscnt, + /* Real */ const ae_matrix* c, + ae_bool isupper, + ae_state *_state); +void mcmcsetburninlength(mcmcstate* state, + ae_int_t burninlen, + ae_state *_state); +void mcmcsetthinningfactor(mcmcstate* state, + ae_int_t thinby, + ae_state *_state); +void mcmcsetseed(mcmcstate* s, ae_int_t seed, ae_state *_state); +ae_bool mcmciteration(mcmcstate* state, ae_state *_state); +void mcmcresults(const mcmcstate* state, + /* Real */ ae_matrix* sample, + ae_int_t* samplesize, + mcmcreport* rep, + ae_state *_state); +void mcmcresultsbuf(const mcmcstate* state, + /* Real */ ae_matrix* sample, + ae_int_t* samplesize, + mcmcreport* rep, + ae_state *_state); +void mcmcrequesttermination(mcmcstate* state, ae_state *_state); +void mcmcsetxrep(mcmcstate* state, ae_bool needxrep, ae_state *_state); +ae_bool mcmcrestart(mcmcstate* state, ae_state *_state); +void mcmcsetprotocolv2(mcmcstate* state, ae_state *_state); +void mcmcsetprotocolv2s(mcmcstate* state, ae_state *_state); +void _mcmcstate_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mcmcstate_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mcmcstate_clear(void* _p); +void _mcmcstate_destroy(void* _p); +void _mcmcreport_init(void* _p, ae_state *_state, ae_bool make_automatic); +void _mcmcreport_init_copy(void* _dst, const void* _src, ae_state *_state, ae_bool make_automatic); +void _mcmcreport_clear(void* _p); +void _mcmcreport_destroy(void* _p); +#endif +#if defined(AE_COMPILE_MANNWHITNEYU) || !defined(AE_PARTIAL_BUILD) +void mannwhitneyutest(/* Real */ const ae_vector* x, + ae_int_t n, + /* Real */ const ae_vector* y, + ae_int_t m, + double* bothtails, + double* lefttail, + double* righttail, + ae_state *_state); +#endif + +} +#endif + diff --git a/core/alglib/stdafx.h b/core/alglib/stdafx.h index 99a80913..139597f9 100644 --- a/core/alglib/stdafx.h +++ b/core/alglib/stdafx.h @@ -1,2 +1,2 @@ - - + + From 535d43f7a263726871b3d6a2710f6ab8cbf51659 Mon Sep 17 00:00:00 2001 From: albertmena <12760268+albertmena@users.noreply.github.com> Date: Thu, 7 May 2026 12:18:44 +0200 Subject: [PATCH 02/15] added README --- core/alglib/README.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 core/alglib/README.txt diff --git a/core/alglib/README.txt b/core/alglib/README.txt new file mode 100644 index 00000000..f01c7423 --- /dev/null +++ b/core/alglib/README.txt @@ -0,0 +1,4 @@ +Donwloaded from:https://www.alglib.net/download.php +Version 4.07.0 for C++ + +https://www.alglib.net/ \ No newline at end of file From c402b90140f6e1c78e605d7a1bfb68b7a7345f6f Mon Sep 17 00:00:00 2001 From: alberto Date: Thu, 7 May 2026 13:47:43 +0200 Subject: [PATCH 03/15] Update README.txt with correct formatting and links --- core/alglib/README.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index f01c7423..493b6273 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,4 +1,4 @@ -Donwloaded from:https://www.alglib.net/download.php +ALGLIB +https://www.alglib.net/ +Donwloaded from: https://www.alglib.net/download.php Version 4.07.0 for C++ - -https://www.alglib.net/ \ No newline at end of file From 8d79d9300392f1de5cf621c29274295d705f4799 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 07:22:28 +0200 Subject: [PATCH 04/15] Update README.txt --- core/alglib/README.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index 493b6273..a61bd279 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,4 +1,6 @@ ALGLIB +Version 4.07.0 for C++ + https://www.alglib.net/ Donwloaded from: https://www.alglib.net/download.php -Version 4.07.0 for C++ + From 44b4485089675a1a7c178fec960f44ef4d7b101c Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 07:59:10 +0200 Subject: [PATCH 05/15] Update README.txt --- core/alglib/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index a61bd279..71db457b 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,4 +1,4 @@ -ALGLIB +-ALGLIB- Version 4.07.0 for C++ https://www.alglib.net/ From 278627383bbdab02164489458b301a121fdeb3f0 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 10:12:40 +0200 Subject: [PATCH 06/15] Update README.txt --- core/alglib/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index 71db457b..38de14d0 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,4 +1,4 @@ --ALGLIB- +#ALGLIB Version 4.07.0 for C++ https://www.alglib.net/ From fcbe7bef6011fafa81cd59f70c0d2dc7d8aec852 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 10:32:28 +0200 Subject: [PATCH 07/15] Update README.txt --- core/alglib/README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index 38de14d0..ed1f1d35 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,4 +1,4 @@ -#ALGLIB +# ALGLIB Version 4.07.0 for C++ https://www.alglib.net/ From 6b7fb0c7dcbfb6d673c20c4f296ad577df6e42a2 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 11:26:20 +0200 Subject: [PATCH 08/15] Update README.txt --- core/alglib/README.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index ed1f1d35..dca44424 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -1,6 +1,6 @@ # ALGLIB Version 4.07.0 for C++ -https://www.alglib.net/ -Donwloaded from: https://www.alglib.net/download.php +- web: https://www.alglib.net/ +- Donwloaded from: https://www.alglib.net/download.php From 1e9feb1f090227159fe3ef817576c960d01418cd Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 12:05:59 +0200 Subject: [PATCH 09/15] Update README.txt --- core/alglib/README.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/alglib/README.txt b/core/alglib/README.txt index dca44424..995dc086 100644 --- a/core/alglib/README.txt +++ b/core/alglib/README.txt @@ -4,3 +4,4 @@ Version 4.07.0 for C++ - web: https://www.alglib.net/ - Donwloaded from: https://www.alglib.net/download.php + From 98837dd50313daeccc854f7c65d92eb4a2b98bb9 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 12:30:52 +0200 Subject: [PATCH 10/15] Refactor sonar.exclusions formatting Removed spaces in sonar.exclusions for consistency. --- sonar-project.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 9fa939ea..e19e2d4d 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,7 +7,6 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 -sonar.exclusions=**/alglib**, **/bilib/** , **/${env.BUILD_DIR}/**, **/legacy/** - +sonar.exclusions=**/alglib/**,**/bilib/**,**/${env.BUILD_DIR}/**,**/legacy/** # Python version to analyze Python code sonar.python.version=3 From d8a1e61a784242463e27c78165483fbf4e4ae927 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 12:41:38 +0200 Subject: [PATCH 11/15] Update sonar-project.properties --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index e19e2d4d..266fef26 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,6 +7,6 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 -sonar.exclusions=**/alglib/**,**/bilib/**,**/${env.BUILD_DIR}/**,**/legacy/** +sonar.exclusions=**/alglib/**,**/bilib/**,**/CIBuild/**,**/legacy/** # Python version to analyze Python code sonar.python.version=3 From 43a3fc42c12abebb4305485f7f2457045774bb6b Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 13:06:07 +0200 Subject: [PATCH 12/15] Update sonar-project.properties --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index 266fef26..af4d69c9 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,6 +7,6 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 -sonar.exclusions=**/alglib/**,**/bilib/**,**/CIBuild/**,**/legacy/** +sonar.exclusions=core/alglib/**,core/bilib/**,**/CIBuild/**,core/legacy/** # Python version to analyze Python code sonar.python.version=3 From 20e69d717357a91f4554fc387e0d361232d30e35 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 13:19:49 +0200 Subject: [PATCH 13/15] Update sonar-project.properties --- sonar-project.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/sonar-project.properties b/sonar-project.properties index af4d69c9..98d4e30f 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,6 +7,7 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 +sonar.sources=core sonar.exclusions=core/alglib/**,core/bilib/**,**/CIBuild/**,core/legacy/** # Python version to analyze Python code sonar.python.version=3 From 53db5d1a9e3d6b7913f74d2e24e6d0ee13246bf7 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 13:27:40 +0200 Subject: [PATCH 14/15] Update sonar-project.properties --- sonar-project.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/sonar-project.properties b/sonar-project.properties index 98d4e30f..39863f18 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,6 +7,7 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 +sonar.inclusions=core/**/*.cpp,core/**/*.h sonar.sources=core sonar.exclusions=core/alglib/**,core/bilib/**,**/CIBuild/**,core/legacy/** # Python version to analyze Python code From 18f2dfb3a9c363a2b5223260a6fa75bfd244e760 Mon Sep 17 00:00:00 2001 From: alberto Date: Fri, 8 May 2026 13:32:51 +0200 Subject: [PATCH 15/15] Update sonar-project.properties --- sonar-project.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 39863f18..908c1cff 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -7,8 +7,6 @@ sonar.projectVersion=3.0 # NOTE - be careful with excusion rules. If you include formerly excluded folder, all files that include # headers from it will be analyzed again! https://community.sonarsource.com/t/sonarscanner-cache-not-working-properly/29451 -sonar.inclusions=core/**/*.cpp,core/**/*.h -sonar.sources=core -sonar.exclusions=core/alglib/**,core/bilib/**,**/CIBuild/**,core/legacy/** +sonar.exclusions=core/alglib/*,core/bilib/*,**/CIBuild/**,core/legacy/** # Python version to analyze Python code sonar.python.version=3